From fffad7c20e284dca83953ab9860eeba4866e0291 Mon Sep 17 00:00:00 2001 From: Mark Pizzolato Date: Mon, 19 Mar 2012 16:05:24 -0700 Subject: [PATCH] Merge changes from v3.9-0 rc1 --- 0readme_38.txt | 80 - 0readme_39.txt | 184 + AltairZ80/altairz80_cpu.c | 37 +- AltairZ80/altairz80_cpu_nommu.c | 2 +- AltairZ80/altairz80_defs.h | 4 +- AltairZ80/altairz80_doc.pdf | Bin 416146 -> 507457 bytes AltairZ80/altairz80_dsk.c | 135 +- AltairZ80/altairz80_hdsk.c | 65 +- AltairZ80/altairz80_net.c | 17 +- AltairZ80/altairz80_sio.c | 420 ++- AltairZ80/altairz80_sys.c | 2 +- AltairZ80/i8272.c | 226 +- AltairZ80/insnsa.c | 4443 ----------------------- AltairZ80/mfdc.c | 46 +- AltairZ80/n8vem.c | 60 +- AltairZ80/s100_64fdc.c | 101 +- AltairZ80/s100_adcs6.c | 129 +- AltairZ80/s100_disk1a.c | 35 +- AltairZ80/s100_disk2.c | 122 +- AltairZ80/s100_disk3.c | 115 +- AltairZ80/s100_fif.c | 2 +- AltairZ80/s100_hdc1001.c | 90 +- AltairZ80/s100_if3.c | 58 +- AltairZ80/s100_mdriveh.c | 22 +- AltairZ80/s100_mdsad.c | 172 +- AltairZ80/s100_scp300f.c | 48 +- AltairZ80/s100_selchan.c | 18 +- AltairZ80/s100_ss1.c | 118 +- AltairZ80/sim_imd.c | 16 +- AltairZ80/vfdhd.c | 55 +- AltairZ80/wd179x.c | 251 +- HP2100/hp2100_baci.c | 421 +-- HP2100/hp2100_bugfixes.txt | 618 +++- HP2100/hp2100_cpu.c | 1650 +++++---- HP2100/hp2100_cpu.h | 37 +- HP2100/hp2100_cpu0.c | 16 +- HP2100/hp2100_cpu6.c | 15 +- HP2100/hp2100_defs.h | 339 +- HP2100/hp2100_dp.c | 494 +-- HP2100/hp2100_dq.c | 407 ++- HP2100/hp2100_dr.c | 264 +- HP2100/hp2100_ds.c | 314 +- HP2100/hp2100_fp1.c | 57 +- HP2100/hp2100_ipl.c | 533 +-- HP2100/hp2100_lps.c | 338 +- HP2100/hp2100_lpt.c | 171 +- HP2100/hp2100_mpx.c | 283 +- HP2100/hp2100_ms.c | 490 +-- HP2100/hp2100_mt.c | 326 +- HP2100/hp2100_mux.c | 654 ++-- HP2100/hp2100_pif.c | 190 +- HP2100/hp2100_stddev.c | 603 +-- HP2100/hp2100_sys.c | 27 +- I1401/i1401_cpu.c | 1 + I1401/i1401_iq.c | 4 +- I7094/i7094_clk.c | 13 +- I7094/i7094_com_old.c | 1179 ------ I7094/i7094_cpu.c | 135 +- I7094/i7094_cpu1.c | 51 +- I7094/i7094_cpu1_old.c | 887 ----- I7094/i7094_cpu_old.c | 2439 ------------- I7094/i7094_defs.h | 5 +- I7094/i7094_drm.c | 88 +- I7094/i7094_mt_old.c | 861 ----- I7094/i7094_sys.c | 9 +- I7094/i7094_sys_old.c | 748 ---- LGP/lgp_defs.h | 1 - PDP10/pdp10_sys.c | 5 +- PDP11/pdp11_dc.c | 5 +- PDP11/pdp11_dl.c | 5 +- PDP11/pdp11_io.c | 2 +- PDP11/pdp11_rl.c | 856 ++++- PDP11/pdp11_rq.c | 4 +- PDP11/pdp11_rx.c | 13 +- PDP11/pdp11_ry.c | 13 +- PDP11/pdp11_tq.c | 13 +- VAX/vax780_bug_history.txt | 5 + VAX/vax780_syslist.c | 2 +- VAX/vax_cpu.c | 6 +- VAX/vax_cpu1.c | 7 +- VAX/vax_defs.h | 3 +- VAX/vax_fpa.c | 45 +- VAX/vax_octa.c | 24 +- VAX/vax_syslist.c | 2 +- Visual Studio Projects/AltairZ80.vcproj | 4 - alpha/alpha_500au_syslist.c | 49 + alpha/alpha_cpu.c | 1865 ++++++++++ alpha/alpha_defs.h | 457 +++ 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 | 814 +++++ 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 +++++++++ doc/gri_doc.doc | Bin 0 -> 54784 bytes doc/h316_doc.doc | Bin 0 -> 82432 bytes doc/hp2100_doc.doc | Bin 0 -> 166400 bytes doc/i1401_doc.doc | Bin 0 -> 65024 bytes doc/i1620_doc.doc | Bin 0 -> 68096 bytes doc/i7094_doc.doc | Bin 0 -> 89600 bytes doc/id_doc.doc | Bin 0 -> 116224 bytes doc/lgp_doc.doc | Bin 0 -> 58880 bytes doc/nova_doc.doc | Bin 0 -> 86528 bytes doc/pdp10_doc.doc | Bin 0 -> 84480 bytes doc/pdp11_doc.doc | Bin 0 -> 231424 bytes doc/pdp18b_doc.doc | Bin 0 -> 118784 bytes doc/pdp1_doc.doc | Bin 0 -> 83456 bytes doc/pdp8_doc.doc | Bin 0 -> 109056 bytes doc/sds_doc.doc | Bin 0 -> 74240 bytes doc/simh_doc.doc | Bin 0 -> 198144 bytes doc/simh_faq.doc | Bin 0 -> 85504 bytes doc/simh_swre.doc | Bin 0 -> 101376 bytes doc/vax780_doc.doc | Bin 0 -> 125440 bytes doc/vax_doc.doc | Bin 0 -> 123392 bytes makefile | 88 +- scp.c | 18 +- sigma/Design Notes on the Sigma 7.doc | Bin 0 -> 25088 bytes sigma/sigma_bugs.txt | 149 + sigma/sigma_cis.c | 990 +++++ sigma/sigma_coc.c | 620 ++++ sigma/sigma_cpu.c | 2848 +++++++++++++++ sigma/sigma_defs.h | 478 +++ sigma/sigma_dk.c | 470 +++ sigma/sigma_doc.doc | Bin 0 -> 90624 bytes sigma/sigma_dp.c | 1278 +++++++ sigma/sigma_fp.c | 421 +++ sigma/sigma_io.c | 1497 ++++++++ sigma/sigma_io_defs.h | 276 ++ sigma/sigma_lp.c | 529 +++ sigma/sigma_map.c | 591 +++ sigma/sigma_mt.c | 645 ++++ sigma/sigma_pt.c | 297 ++ sigma/sigma_rad.c | 532 +++ sigma/sigma_rtc.c | 267 ++ sigma/sigma_sys.c | 613 ++++ sigma/sigma_tt.c | 331 ++ sim_rev.h | 94 +- sim_timer.c | 8 +- 145 files changed, 29917 insertions(+), 15649 deletions(-) delete mode 100644 0readme_38.txt create mode 100644 0readme_39.txt delete mode 100644 AltairZ80/insnsa.c delete mode 100644 I7094/i7094_com_old.c delete mode 100644 I7094/i7094_cpu1_old.c delete mode 100644 I7094/i7094_cpu_old.c delete mode 100644 I7094/i7094_mt_old.c delete mode 100644 I7094/i7094_sys_old.c create mode 100644 alpha/alpha_500au_syslist.c create mode 100644 alpha/alpha_cpu.c create mode 100644 alpha/alpha_defs.h create mode 100644 alpha/alpha_ev5_cons.c create mode 100644 alpha/alpha_ev5_defs.h create mode 100644 alpha/alpha_ev5_pal.c create mode 100644 alpha/alpha_ev5_tlb.c create mode 100644 alpha/alpha_fpi.c create mode 100644 alpha/alpha_fpv.c create mode 100644 alpha/alpha_io.c create mode 100644 alpha/alpha_mmu.c create mode 100644 alpha/alpha_sys.c create mode 100644 alpha/alpha_sys_defs.h create mode 100644 alpha/old_pal/alpha_pal_defs.h create mode 100644 alpha/old_pal/alpha_pal_unix.c create mode 100644 alpha/old_pal/alpha_pal_vms.c create mode 100644 doc/gri_doc.doc create mode 100644 doc/h316_doc.doc create mode 100644 doc/hp2100_doc.doc create mode 100644 doc/i1401_doc.doc create mode 100644 doc/i1620_doc.doc create mode 100644 doc/i7094_doc.doc create mode 100644 doc/id_doc.doc create mode 100644 doc/lgp_doc.doc create mode 100644 doc/nova_doc.doc create mode 100644 doc/pdp10_doc.doc create mode 100644 doc/pdp11_doc.doc create mode 100644 doc/pdp18b_doc.doc create mode 100644 doc/pdp1_doc.doc create mode 100644 doc/pdp8_doc.doc create mode 100644 doc/sds_doc.doc create mode 100644 doc/simh_doc.doc create mode 100644 doc/simh_faq.doc create mode 100644 doc/simh_swre.doc create mode 100644 doc/vax780_doc.doc create mode 100644 doc/vax_doc.doc create mode 100644 sigma/Design Notes on the Sigma 7.doc create mode 100644 sigma/sigma_bugs.txt create mode 100644 sigma/sigma_cis.c create mode 100644 sigma/sigma_coc.c create mode 100644 sigma/sigma_cpu.c create mode 100644 sigma/sigma_defs.h create mode 100644 sigma/sigma_dk.c create mode 100644 sigma/sigma_doc.doc create mode 100644 sigma/sigma_dp.c create mode 100644 sigma/sigma_fp.c create mode 100644 sigma/sigma_io.c create mode 100644 sigma/sigma_io_defs.h create mode 100644 sigma/sigma_lp.c create mode 100644 sigma/sigma_map.c create mode 100644 sigma/sigma_mt.c create mode 100644 sigma/sigma_pt.c create mode 100644 sigma/sigma_rad.c create mode 100644 sigma/sigma_rtc.c create mode 100644 sigma/sigma_sys.c create mode 100644 sigma/sigma_tt.c diff --git a/0readme_38.txt b/0readme_38.txt deleted file mode 100644 index 5ed20e65..00000000 --- a/0readme_38.txt +++ /dev/null @@ -1,80 +0,0 @@ -Notes For V3.8 - - -The makefile now works for Linux and most Unix's. However, for Solaris -and MacOS, you must first export the OSTYPE environment variable: - -> export OSTYPE -> make - -Otherwise, you will get build errors. - - -1. New Features - -1.1 3.8-0 - -1.1.1 SCP and Libraries - -- BREAK, NOBREAK, and SHOW BREAK with no argument will set, clear, and - show (respectively) a breakpoint at the current PC. - -1.1.2 GRI - -- Added support for the GRI-99 processor. - -1.1.3 HP2100 - -- Added support for the BACI terminal interface. -- Added support for RTE OS/VMA/EMA, SIGNAL, VIS firmware extensions. - -1.1.4 Nova - -- Added support for 64KW memory (implemented in third-party CPU's). - -1.1.5 PDP-11 - -- Added support for DC11, RC11, KE11A, KG11A. -- Added modem control support for DL11. -- Added ASCII character support for all 8b devices. - -1.2 3.8-1 - -1.2.1 SCP and libraries - -- Added capability to set line connection order for terminal multiplexers. - -1.2.2 HP2100 - -- Added support for 12620A/12936A privileged interrupt fence. -- Added support for 12792C eight-channel asynchronous multiplexer. - -1.3 3.8-2 - -1.3.1 SCP and libraries - -- Added line history capability for *nix hosts. -- Added "SHOW SHOW" and "SHOW SHOW" commands. - -1.3.2 1401 - -- Added "no rewind" option to magtape boot. - -1.3.3 PDP-11 - -- Added RD32 support to RQ -- Added debug support to RL - -1.3.4 PDP-8 - -- Added FPP support (many thanks to Rick Murphy for debugging the code) - -1.3.5 VAX-11/780 - -- Added AUTORESTART switch support, and VMS REBOOT command support - - -2. Bugs Fixed - -Please see the revision history on http://simh.trailing-edge.com or -in the source module sim_rev.h. diff --git a/0readme_39.txt b/0readme_39.txt new file mode 100644 index 00000000..d3c8fbc0 --- /dev/null +++ b/0readme_39.txt @@ -0,0 +1,184 @@ +Notes For V3.9 + + +The makefile now works for Linux and most Unix's. However, for Solaris +and MacOS, you must first export the OSTYPE environment variable: + +> export OSTYPE +> make + +Otherwise, you will get build errors. + + +1. New Features + +1.1 3.9-0 + +1.1.1 SCP and libraries + + - added *nix READLINE support (Mark Pizzolato) + - added "SHOW SHOW" and "SHOW SHOW" commands (Mark Pizzolato) + - added support for BREAK key on Windows (Mark Pizzolato) + + +1.1.2 PDP-8 + + - floating point processor is now enabled + +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 + +This is the last release of SimH for which I will be sole editor. After this +release, the source is moving to a public repository: + + + +under the general editorship of Dave Hittner and Mark Pizzolato. The status +of the individual simulators is as follows: + +3.1 PDP-1 + +Stable and working; runs available software. + +3.2 PDP-4/7/9/15 + +Stable and working; runs available software. + +3.3 PDP-8 + +Stable and working; runs available software. + +3.4 PDP-10 [KS-10 only] + +Stable and working; runs available software. + +3.5 PDP-11 + +Stable and working; runs available system software. The emulation of individual +models has numerous errors of detail, which prevents many diagnostics from +running correctly. + +3.6 VAX-11/780 + +Stable and working; runs available software. + +3.7 MicroVAX 3900 (VAX) + +Stable and working; runs available software. Thanks to the kind generosity of +Camiel Vanderhoeven, this simulator has been verified with AXE, the VAX +architectural exerciser. + +3.8 Nova + +Stable and working; runs available software. + +3.9 Eclipse + +Stable and working, but not really supported. There is no Eclipse-specific +software available under a hobbyist license. + +3.10 Interdata 16b + +Stable and working, but no software for it has been found, other than +diagnostics. + +3.11 Interdata 32b + +Stable and working; runs 32b UNIX and diagnostics. + +3.12 IBM 1401 + +Stable and working; runs available software. + +3.13 IBM 1620 + +Hand debug only. No software for it has been found or tested. + +3.14 IBM 7094 + +Stable and working as a stock system; runs IBSYS. The CTSS extensions +have not been debugged. + +3.15 IBM S/3 + +Stable and working, but not really supported. Runs available software. + +3.16 IBM 1130 + +Stable and working; runs available software. Supported and edited by +Brian Knittel. + +3.17 HP 2100/1000 + +Stable and working; runs available software. Supported and edited by +Dave Bryan. + +3.18 Honeywell 316/516 + +Stable and working; runs available software. + +3.19 GRI-909/99 + +Hand debug only. No software for it has been found or tested. + +3.20 SDS-940 + +Hand debug only, and a few diagnostics. + +3.21 LGP-30 + +Unfinished; hand debug only. Does not run available software, probably +due to my misunderstanding of the LGP-30 operational procedures. + +3.22 Altair (original 8080 version) + +Stable and working, but not really supported. Runs available software. + +3.23 AltairZ80 (Z80 version) + +Stable and working; runs available software. Supported and edited by +Peter Schorn. + +3.24 SWTP 6800 + +Stable and working; runs available software. Supported and edited by +Bill Beech + +3.25 Sigma 32b + +Incomplete; more work is needed on the peripherals for accuracy. + +3.26 Alpha + +Incomplete; essentially just an EV-5 (21164) chip emulator. + +4. Suggestions for Future Work + +4.1 General Structure + + - Multi-threading, to allow true concurrency between SCP and the simulator + - Graphics device support, particularly for the PDP-1 and PDP-11 + +4.2 Current Simulators + + - PDP-1 graphics, to run Space War + - PDP-11 GT40 graphics, to run Lunar Lander + - PDP-15 MUMPS-15 + - Interdata native OS debug, both 16b and 32b + - SDS 940 timesharing operating system debug + - IBM 7094 CTSS feature debug and operating system debug + - IBM 1620 debug and software + - GRI-909 software + - Sigma 32b completion and debug + - LGP-30 debug + +4.3 Possible Future Simulators + + - Data General MV8000 (if a hobbyist license can be obtained for AOS) + - Alpha simulator + - HP 3000 (16b) simulator with MPE + diff --git a/AltairZ80/altairz80_cpu.c b/AltairZ80/altairz80_cpu.c index 5c19ed64..7b4e7a5c 100644 --- a/AltairZ80/altairz80_cpu.c +++ b/AltairZ80/altairz80_cpu.c @@ -1,6 +1,6 @@ /* altairz80_cpu.c: MITS Altair CPU (8080 and Z80) - Copyright (c) 2002-2010, Peter Schorn + Copyright (c) 2002-2011, Peter Schorn Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), @@ -191,6 +191,8 @@ uint8 GetByteDMA(const uint32 Addr); void PutByteDMA(const uint32 Addr, const uint32 Value); int32 getBankSelect(void); void setBankSelect(const int32 b); +uint32 getClockFrequency(void); +void setClockFrequency(const uint32 Value); uint32 getCommon(void); t_stat sim_load(FILE *fileref, char *cptr, char *fnam, int32 flag); uint32 sim_map_resource(uint32 baseaddr, uint32 size, uint32 resource_type, @@ -1867,6 +1869,17 @@ t_stat sim_instr (void) { return result; } +static int32 clockHasChanged = FALSE; + +uint32 getClockFrequency(void) { + return clockFrequency; +} + +void setClockFrequency(const uint32 Value) { + clockFrequency = Value; + clockHasChanged = TRUE; +} + static t_stat sim_instr_mmu (void) { extern int32 sim_interval; extern t_bool sim_brk_pend[SIM_BKPT_N_SPC]; @@ -1916,22 +1929,29 @@ static t_stat sim_instr_mmu (void) { startTime = sim_os_msec(); tStatesInSlice = sliceLength*clockFrequency; } - else { /* make sure that sim_os_msec() is not called later */ + else /* make sure that sim_os_msec() is not called later */ clockFrequency = startTime = tStatesInSlice = 0; - } /* main instruction fetch/decode loop */ while (switch_cpu_now == TRUE) { /* loop until halted */ if (sim_interval <= 0) { /* check clock queue */ #if !UNIX_PLATFORM - if ((reason = sim_os_poll_kbd()) == SCPE_STOP) { /* poll on platforms without reliable signalling */ + if ((reason = sim_os_poll_kbd()) == SCPE_STOP) /* poll on platforms without reliable signalling */ break; - } #endif - if ( (reason = sim_process_event()) ) + if ((reason = sim_process_event())) break; - else - specialProcessing = clockFrequency | timerInterrupt | keyboardInterrupt | sim_brk_summ; + if (clockHasChanged) { + clockHasChanged = FALSE; + tStates = 0; + if (rtc_avail) { + startTime = sim_os_msec(); + tStatesInSlice = sliceLength*clockFrequency; + } + else /* make sure that sim_os_msec() is not called later */ + clockFrequency = startTime = tStatesInSlice = 0; + } + specialProcessing = clockFrequency | timerInterrupt | keyboardInterrupt | sim_brk_summ; } if (specialProcessing) { /* quick check for special processing */ @@ -6442,6 +6462,7 @@ static void cpu_clear(void) { mmu_table[i] = EMPTY_PAGE; if (cpu_unit.flags & UNIT_CPU_ALTAIRROM) install_ALTAIRbootROM(); + clockHasChanged = FALSE; } static t_stat cpu_clear_command(UNIT *uptr, int32 value, char *cptr, void *desc) { diff --git a/AltairZ80/altairz80_cpu_nommu.c b/AltairZ80/altairz80_cpu_nommu.c index fa1a9221..a390ca4b 100644 --- a/AltairZ80/altairz80_cpu_nommu.c +++ b/AltairZ80/altairz80_cpu_nommu.c @@ -1,6 +1,6 @@ /* altairz80_cpu_opt.c: MITS Altair CPU (8080 and Z80) - Copyright (c) 2002-2010, Peter Schorn + Copyright (c) 2002-2011, Peter Schorn Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), diff --git a/AltairZ80/altairz80_defs.h b/AltairZ80/altairz80_defs.h index c16f7121..162fd7c9 100644 --- a/AltairZ80/altairz80_defs.h +++ b/AltairZ80/altairz80_defs.h @@ -1,6 +1,6 @@ /* altairz80_defs.h: MITS Altair simulator definitions - Copyright (c) 2002-2010, Peter Schorn + Copyright (c) 2002-2011, Peter Schorn Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), @@ -43,7 +43,7 @@ #define RESOURCE_TYPE_MEMORY 1 #define RESOURCE_TYPE_IO 2 -#define NUM_OF_DSK 8 /* NUM_OF_DSK must be power of two */ +#define NUM_OF_DSK 16 /* NUM_OF_DSK must be power of two */ #define LDA_INSTRUCTION 0x3e /* op-code for LD A,<8-bit value> instruction */ #define UNIT_NO_OFFSET_1 0x37 /* LD A, */ #define UNIT_NO_OFFSET_2 0xb4 /* LD a,80h | */ diff --git a/AltairZ80/altairz80_doc.pdf b/AltairZ80/altairz80_doc.pdf index 1d9f22d9814301a3fed9d345b8d1bd1d78f5718b..a09c74bd4789a93d959b385203c8eeb2d6055f09 100644 GIT binary patch literal 507457 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℘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

(|5V%n*3>;& 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%0DV?Ock#pV(vQ%OB~6R2}mJ| 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 literal 416146 zcmce;cU%-p&^BsDf?yyAK_zF25+zBNuz;{2AX&*GIVw@IWJ!|4E+AQwfC>nLWEKzv zL_l)RAaHvY;i%_)_j|v4fA{{e_EgtXPgPHM_0;rm4vmt8B+E@!PAr=GiIs`jtkvX> z`j1##RP0n%`leWdf>dnsMwTYF52?687mSKc@{zf%kqv0g^=yqKj0~&{ji`i$v7Xr4 z80lGHIiAdm({dR6NZ>QF%w)X%s66`a>9@sJk=TuvY0@{N0#!DzrR4P^Xz0?zd-m2T zY>YiH>Ys9G^Ek14^ToJrRD3@1&1%7HGd{=IQgx#R4sZMF$p5%|wBR;n`8wHVVwGKJ zk~w49K)KE4fiVGo^ZtX9-Pz6s#wo?DGexZ)OMKd=Sk!|D`%-Y` z>e5L0`JdV&a?yc?cWJ|NmlkaaUDf?_PTnVQPaz)3N?wffo-5aqOAjRK)S8osc~(Ev z5NzwN$ZL3Y)`7AM>qk_YRb*;#Q1aT7E~nL4%t!3XQ4>AENM&ZSv=7_QzWS)v7hGlW zN^{&cW0TxEk5IyY>>rrC2{+brla9n`5i4HKPocmrO-raIz>+4Ynf2z4lt|}NZ5h5Z z3g1zYTbs>W@Sb_DSyUx9tIpzfzgETR8ZLY5nP~$OfpFSz zrNt}9CuVs{s4c@asS{_TIq-m$%aHn!MF-`ZnF+d27ir}$4(%9d1=4uywuC%*OSt(C z{%q3Mu|vH{qxXWf9!6sA&qV@3@)%2w1i~-AHep+sr4dbO_T{HfyemS{J2Oc=zh?Z& zFs~ql$wz(8ZFMU-zMNiNqncuK0B6N-a)T zWJh+C%MTX0FG{Sg42;A-=535#Xxt;n+`s#U!PPgw`Zm@i4Z{49KoX1?mo}#iemd7{ ze#}1Db=(r$UNg$+eUVuQCAFQviNQPao(r(Y^x5j}>&UFz$z+xl4-m2bT%H&CU-~Pm zsLy4~75GmZ&KTDv@SiTOd4_29m3v!en!5Dd8-7($bV=4Cx1yQpd2G?XvYKaTZst_7 zJ>2YRlgj901`Tg2IE(j+Jh|4a*G#ZTsSp;Ku@UYKZ_zUEF;#N@r&@!AKIJ%iBwgd2 z6%Sv8a!h~2O=)61VRu7*%DZLfj@i?P#k9;XVg!kV$sZ^_n*YL1aXvnaAx-Aic+xXT z4dh9e{by{_DKGHp2FRY2ddlCMh$?Erd3^duNdFvmlG8h0`x9)RQ%`l4U~>l~WxCqc zE9^Y*XN&E9_%?I`Bi~tyM`~2h50`4`%y5yU2K<}Yoq4^xJ+^l)XQ>E;f3TXJNcT)^ zb0VGG3METbnm$2V#HS!lEqN)d;aOp4_`Ctr(1+9Ku6-*q=QWAN0bfHcBOH;z_lnIH18AgU1rb%YULar&H9F{$ZW1?^SUDH)zWO<%2;R zXL&&F8h{6S3P?RZ6R@U6(1Ev&gMK`yD<62t{ru_%#G zR+JaMyX$=rbUEqQ8!_RfcOy2nw4(OfzP*71*Ecq?v)%;`^Pz=a7fY;PqGk=TB)CY4 zn8T#Do)wy#skrdF;QHeAoDC%_uSCraBy3q`GD;Qyd^SJxtuDGqwwB}kl{X&_M6Xku zzvl=PUTz}avNceOKlzd?Yrjvj<5`(3}Ti?>6l;i?e zFD*O!sqOW!J}XVm%ae4`M3v=SJQHx-SLaE6L|@&-6gWRR3mcBP=5s0L=B1gHbY}07 zi{tR8SWZ8D^}qWP%Ra=Hd2)A(cO-5b7y$nA6*iDZ^D zn{W3LK3}|_z$R_hXl*GZ5XgDyuBOe$lh<%saTSfZ$&FZNtuNeKy`fwsUL9b}_j%>f zPdVF@CPidX7Cgq1k=mt!@_I6-WQvzK?h1|TP`=W@OIy-PpL@Yrd&>Ku`~gcWCOs`n z6HKyFj_xWMVGDnK5pRYC2jfjSZIRcqN-E0Zr{L0J*A}(f^<3N>=&=+6^JYHvFT-?iICjy{mNTE<-kd+-s)X^#wKLb8SbuW&G?Kef?z0+ax_74joD|)K(B+b` zMvaTXx-R~Wcu`Lu-2VEsIElbhpF^iu;JPn4wb+N8(%VKKU5(6TDDZ4Vc=NU!p1G}s z_liET;4*!#v{A6CvsBQA36i$gumBRG{Ppj%4spk9wN)&VD;^TS+%Lt%2|sgQ^l^;AXs zG1rYhuB6eo*=ef?Wetmmo^iu15Qh8aDvva>NTdP2o>*dcCZ zX$$mEsGy=6RM2;g3?J!qG=uS&CaVk=!xPgS@;7s#c6a$CvO%B2o%+%cLWA*vw8(BY?sy@Ap zp&d^lg}0Hs<$4uVr8FEzGny83CguK1nr|j)t{6tusxomWCN}B2ySEbLPq5?1>VBT2 zO)>Z9xPwo!;J&x387pgs>Am&9{oabCL#b5&JM~K978U9^U)o;dbqpk*n@1dqPdlyK2j{ zbM3E0gI>W$%;$31stHeQP;16h6xT$lohY$5Co(abtGGyYV&&|KlHr8atG?zs;q~8f z=&%Fl=FFd*Ofq9-n&RC}^0aEM_2t`)ZCTj8Cy+^W``HZ{0#2hl6Pa0=auT0E8ket}_|jK%egmHia+gA3$OIjv6*Q=RaBDt+;E^l4V< zQ;$T>6p0G=pTH8m*?-dB%hdWr&ok$aGYXzO*5~e@QGa*A8XM=Sln9pZdpY)#!_OX_ z_guP2kSdCNL70vgE7p6FO!K^xxTw-C{L>BM{x2?ui)?q$W)m}dAydSagw}4@l2)GA z_S#9t=%C^{w|COb`_ju(-Fg@LPrP~hr9goEywr!5ZxW6K2^d8021jMf359XXJ`jzP zEuCQY(ftr{UZm;#=}t+F^JL2sVlOnPPhPra7Ir=T6yi?Y3*2Jy)4UCT7G8E)5g{^N&_$DRjZ~~V!>OyhtagW2?TNZv2jf5eW(q3( zoy&Jj*Xw44W+F)ANNY$*NYzMVxIS`|#979Dikpa=-j8}PT};S9HBge>|za*G=<`}E85|#TD+oV_sdiq#1!S&G}v_Wl^0Wl zm6P(4(rcw^wLF^Nbx;jF2o#NfpPdqrQmgk$FKyJ|1~M$ClQB&*P2l4#gEx-@mW9W( zXbb!kWx{2GKiyU7?-^EoP}yG6j$`)YAuU%9cU5C*!B;puSF$&muTHSZHO(o0n+aPe zP$MvraEMTsd7fE?WtN!|&Hz8FVNo(uuv0fsA7`d*;MVACI%ZJZmO1pJG!MZtVqZJ& zCJ?7xFhp3TP}RPHyK#M&cK0TRke{PpHST7=tv!8}w;Srx?9^y^+j7tt2AvCCVYf`y zNFuzAq3uFj8a58m5>XEeu}$aW(QAYDi6lpeLgs4>miozHjsf+y|kE$WB* zg}&^S?=s=Z;e|;BHb!PeOp>-^>pYLiR}WLqFALw)Uo>6J66P277Y-J_Qe$6}CmRGCaJ(+LODVQ$xl)Z zcTiGy@3`EFxg!^&!3-}RmkiPjqRJE^q$DG7p|-a{Y<3OF`Hjte#~NE;<-8wVJU3ud zI)P|ufBi!DJ^V4_RWeG7k&6fZS3V#n5HiH+YO)m$TS(eti5IQGwe)^ zcae9eL`=Q5zk$qa83LKHQ;MRc-|UKXSDuX{B40$NF>oR}5v`BBOSVe7#c1>b3YfGx zh3Kl;>bTO_#Vea1p%&Dxq>6Ng$=S_TGNnI(c zQlG22r>FJ!0p6of!_X3r?4oMfd{Ze@)=c`$Gt$twAJsE1W%G#xje~u)BNiUrCxcHn zUw?$AEze@|b(Sk^5QEjbKh&e*)>>e44a-)+)|863cl^&iurTJk=DZa$H=Dl z>h8abaC8}puDn5&d{iAnWiHeQDq}RjlL+Ok!6DI=K(KMU!0IRu}b?1rZp37q}UmEKJ@3eOlGZU*&=wjd3#^`*_AoB zq8AK=(z#c<18}>j%N<{eggI^MIIU6+EmnHi?!B(k(ay8aLA|c}GHgHC`opw#;p+a^ zy~Tyyg=)N!wV}OuOS_+ot!}%XDAdl*R;|v}5i{M|AsyYkdpYip4=Q)Ry&g38RV*u; zMIi@sU-u0S%`Q}j?&hfVIXLJ#9As(L?2I=&>tVUQyB@e8G83)sI=;84!|WUSlbCWl z;_6E9u+x^ft7%qfu8yt8+=B4DaHYV$#$rOz-sc=Ovbp_vC##Jor`h_3@N^w`cZr6E zMtm2oUEJ)R3=ZYy^URx=`&pOO49pKG+Ex#h9aOEaVdX)|* zlIIv5=%-li^uJG9;qmkGXx1VRsm2?dO|spp=@t;~<=?tJ#fj(aDJ*<-x1o#JV>xNP zpLbH2tgb(>Q?I<*GCwnZBQEyyFiZXlrsJGOJ@#Xq>MsN$WwWQI7NY$u)#oP^D7!6m zmn1Cu&MNk7RDSax7*-Wj9t@x}RbQ5v$9|Qq4V3e}K)J9a6|qlLTE*a)YF|d6sJiRY zc(AqWNoP7jB&fV=_x?)h2tK&55AeLLy!#tLP2w^IE~B$=SAK7!36`&ANIO1GHJ`8w zdr6}5YNM^zp&NI#C5iP}PdX$-vIp2uBliyD0RHpTf&WT2$JE|<;LlAP^jI;y$`*GQ zJK%#aV!g_4MS{TB0LWMc48`}M=U!bINh&5Wzr+=G+vl_zQ|lM+zU#Oa_cTSE>!i5f z!&APvoo8?;en+(a-yoRR?4Q#QWInuQDK=~Rd)u^vj0i}AF{2Wla0cE~4?FLZR0Hr$hm0eH6)QT&v9ECar)K_NJ zL^(QBg@wg5^RdGH*O64Q8qkGZj?^-HR;{jTa2!gNDWRUY=x@9hC!Wgt0@e(!hl5G<9P+M^qYhj%kSbDF%|3UDTE2q z*=Ol4o4)t=);tz3#{HK8WdE!KKS3#5UjiRVe94DVQX(bblJcP#2JFTD5r5YLcFaG) zM_L)+``=WMmKsF%FGpwS@EHM>EILr7>|;?Z@;m~`J znZO02)_ftK4jKH`NGL!9C8WN>a4RL^S9A4D7Q@mH!E29@-^kBo&Ca$W+=`u87pZRD zb-HW4^R7x}$YYo2iyR(d+}qvA*35igw=}}VuMK89;zKyK&3%3{k~6)j^Sm3b`BTQ{ zV?#T->+F6Qt9Hv+VW<=M;?_3nOljt%!$F*0{qF3D~!z?}U6`QC{ zQQAg}SW$n7|7$IE&pz2-;9p{x(ykRV7tENDbe{}6I5O79_u!-04I|@}QM8x;?^Sgk z2EbQg$I^&W_D^1P7#9wL(P8}0RbYmjJPe>29jPMpxNG$7GSq=~m zD^D!Q3d;Q^zFV8M>DKs7*m}p0hK}v9H#WJOISk$x9Py|m(RUFgO4D-GIYF_1>uO3? z`@7<(%J^$<{8BiuvfAg*-mVD}yKI_v(WjYS0(2>72Z`Y`0uk4P{7c_-UXYj#jLe5# zRq`5El=5>iBm7h)lHbK}rT>*yTFl~a@R2QMsdAIpjWUxIJ^Z4Mrg`{7VjpHM8y7-S zw3q)MR6$~pFYF8GVH={uV8=QPDa$@)~*_q+Lt|_X!&;6+`?YXsK{u zeSy{iiO*Cz2cQQ_CG7=zsVFx=J4X{eH63&(u){IQeCE=@ItT`QU>!(a<41rvprt}@ z2rU(Jz{itjeQt{@tzhWtn<4x1sw%7Og{6^}4f~<}gCE8Yrf;-$*V{`8w7znSo7<22 zah&(qbqVwu;`{zhpUW!1i?^z*;eBygtJc@r1>tfsN^g7&nd}D9%chTCcx#e_-4jFf zVSpEP&vz=!(p%DEEV$uHfk)zbF%>l8FN0s=MeoeN4UX)oxc>0)oBf#-2HaGohE;mi z?^IZ7f}vtG$0G3mT#TSSP08PjUUgXzE9zK;qWcT{ON4^`3;aujLiv{?h#62tq2o?P zJ3@=k(P12F(P2PQ9fOaw=rF(}GvlU0lT3)w2~BdK*LXT1hBBCBy~h`!NiMkc9Q}A8 z2a^njfQF!-APu7E$HRB3TaN;~=)txi4H^8_yhwls3Z@-KE&f?rnO{)xZ0%P6YnoWd-%^tH)a3 zsx`kXhiQ}uU1qCbDbV_IPKaA5soGDkHlP#_JNRC-&&L5jA4#SbF@yO!v9zc=DW*p7 zhq-PV4@-)exq5|}xisN~q-Kga2R- z6hj@u{$YmTdCVXHLLX$55t`{Ca11&9pQ}LXYQoW}o5u{LZpuBvL{-2FX0@joow}w* z=+rGOno5Vp1wo>rSyf_cfo3&3iiXY(3<{)fSrIyQwE!PT-8^P~1c(EqZh2I-W7oE6 zQLPSTTzxk(M>kRZ?#KD&A7Anc-VRwRboQyo(-kV3wPP*^4HRotI{p0YV5xFr$DuUB z>VEKkI^Omx%iB{oOu6?+JUZJ)-fG}*PrB`Dd|jB&)zO6&RbsyXEN$bAAI(FtwrbEg6=075FL09f7oM!Dy`9d0%(S; z53m&C05?b+a5JF%Ic~t50T0;W{&Tu)iMBO2gf{Y3Y(0Ktq%6+pmc_dd)avMV)hhU# ztmg}?XSq*K?}FIKL*xDACqo|yK!JrSt3*OsLAPWXOD?Z&)+<)gf< zH4HcRoQgh$c6wC-p){rWwIDInqckPE0eaO$9!$HeRxyK#Cb6_``Am&O6aDK@9&7RM7IzYDF*qZewUBdLE@kAOR~#Cw>cbIwkU; z(@B9W5eyrhPLGPAO>(9LolbTG2iAX40E zN!-98oh@;wdX(k%L^(_7+AGwf+U0Z2`EKu*9FWP?*NOtnbm``p{808T#l{}NJjy!E z>%<;mwUhByN%w5nB#B^)+7yfSS%a`7r?AK7jzYeb{In^rLu9gZ3@*>i5PKWj1&Ni4 zh^HV!l(PvR(yO9wVxdl5@Ij(ce|1TwXeOs9sWnpf9HWl9=vA?~@R2hwy({_u>LT_r zeda5sMiHT;-uMee4Cp1%9+3vX2oj-~l(Ub;-?WF6P5C^zcum-kOxBQ zD{u;3{^=X2W&EL}3Zu2Eg%4F#uPU$?=bcc?B}?W`FkYHh$`owTtEk6cY5KUAs&d8_ z)p)D4d;5N>5Gm|BPx}>Pk4=YG_NjGtCvASsNi|8XWF+-L4uEmK0Rsce*pv*2;4Zv@ zKV+tYKU5uL<|2H-%!LH&6I+^)6vcz3Rti@5$xmWw10Z*v8m1^)fTR#9>c~bj9Ko=I z&r)Ltn}Xaq749Qh8Z4%E4EviII6Z=aqyVfCV>So?a*mD(tnIa|9Z1lrb@>t1(amqq*)R@0LG4 z{c5lhwjG5%nQzdtAVXs@TsO!otCRb>w{Hl!=TIKHV%N7=IX~(!X^Lu;oJ?y8w(=vl z5OTnIt;4*q-|J?(IbOwPrCzwZx%G~9XJKJ>;p;0G{%L#1(yMer)i&VhE6*fZJmj3X zANd7eTs~493L7qB{_%(GwoRQHQ?GULs(Q-$7&gKOF7S~GPQOTd-*HXKE9Ex>?9%Vz zHR-Nnr|}sZFnnZ}MN?p|O4<07K=kw0T-HmulwR1O$-Ae%s4oY5_EBYOgK^VPI z@F{I!48qVtdGWmtN?z$@Jt%q8w_Zd*cLKZ{5Ky8E42VyZL$3iNQ5A#;7E12ceZgrq zCSlI0eR&!>>QEPf$r&cz4f+*DVmJ=y$sb_q1KAbz?j8s(pOJb<~3P zstpGAuJCY>7@lrm4|5Fdnr+L*v)lF#Nw184FbkK@N>;Y_k~Ua$Kh|+rbo;8CS4kJk zr!v97jdj^H*wb4xjVh&=UOM|&JduJ>exWoU*|q;(pUr*b%o!g5p(~XX70UztX82TG z+*tU?f>S=SX(B0DOiI~YMGq#52sOie%VY5B@iczQ|Q^m5ITF1$7OxQk`-PC)sU=Mn+- zyAh+EJ5LuEmRpx%8({IdKiAh%4)X9E`=S=t!>sb2xMtwlvEjxS*tYcT_n7Tc;2pSo z)^xgAml02s?eTML#){i5v@v!YjO33glF0}6P-K3jP2>PZ#pYE-f zq@x1z!L^UsxxYI^BY%RvB)*rVn1b@b=dWf;p2JhQ;q8YA`%u^Od=!qfaePTC3RKiU zg%4DLeuzsS>w2We;K=VlC266c`~`!HnUd^yDs?2@ zh)bQ6UPP(+}Fl=>wKgk ziR?@#oB~zX6Tn=jCnRWgCwjE}>Z{W0E!Gd(+mQ8FGw&Iaw9T<4*$Hdh_TG3h=f0W# z!0oEL{Cru2i^Ir$q4}C`X@btu^K?zo10FopbITFsu8$q7H1=UwBSJTPbeT<5wnm*l zwZOJw-?~n$e*YBeE{avV;&fAX{qQG)n&8^Q%Gh~J{2#xU=`%>uji}NMrCwJ@xpqSBuV&g`snj+|yzpj54Dk2jdMnUO(U#=)C7jq=r%8vCp=%Q$PCH!g&SQjFm9 zxfr!s*`E9?<-kU0vZy@3YD2Q9?94e{l6RiMqfgF?(zPnUrTS`i7TG)D-Tn7vb&GHG z?uGD=mvGr_4N0o_B}8Z9)($?LdC~nrb!48@&1l=ckJ+y2(ew>=2-EcF5m0sYT+7Np z4CIlxU2v>2jz;dq!I3=X#)yH!*bLJa&><8LIxHj+!=<2O&^Q|KFV*%}^H>_2pxRoQ z)wFnvRp*C-VAW2X@@h(QudZw`oh@Zn6J?Q$vi%4n=qXZ_F`-9wk;thjwZLc+3soWQ zv6!MNXYv>Lm*@*)`5Sy>D_eTZjHZGdLCi9Ms*41z{YONHaVVn0_!Im~iw>idx~0Rn z-F%@4BoT9BVIz>+Yzw18QM+@3Tc|l6}iUcQ8$6 zQ&~D^i*Zup$IJO`LmEz%8Ffv3gHJZkUF9>O=1$}ck82~5xjPw@p7}%)*3EYVF`e+N zCk$Ns=~`gWdH&WN)??cyZOV_fdckjVeEk>0X~c~`*#0(CLO#)qG@ZoB;Lo~)uy6Y% zLjHYWiQTEH0$_UiSY%6&MJUS1nFPX&0X}g=+aqPbZk7^^4wNnU$%^!^yP_YpuiM<A6#4Fa|Y?=Q|)IG?uJ?MnJoI4Zp2#ZtYzsn z7B{Rc4(xnhbj=ENO>vZzF;W2|D^kbJOFeWF*ZgTKO^>S8Ch}FKq+r6xskNtkP zYct-lkWN)!=E|wsgSoAv zVdOK5&SnM=!zRe!w}v1Q@&I<{B8h6p-tAYbj%C>-(5#w$uEV35F}8CVNFKUx(axlt z#qxdGQdz~2N%{6JwP{P0H>4L$qJy$GhLgsZJM#Zv^UtA8ghEQy|zKE_Fm;z+$g5G zKrQ90mTtOa?(!i{vaiAJH;Pp=TA0;p!{Ep+qiEzv6SLYhhpb)YXV^MfYzCvYF+w)x zP-S~0DkHlA@>u*$D~V9}8~jU4lEMFr>J6D5no^z*&Cwhweq_X`5`uQfF`)s)!l;6K zY;+7ZfNW>zTW;MAf0f8@SSjCDsiS5{63bd#4C;^LCaoB9M*x@1Y$0mrr#wN~JptYI zlS_g>U$Tx^DtOR+y+8jd{toW+%9$@+6Ps?O!LLJ>@7!#&r^KJ&x84^lGLq_4{OrA3 z#yQ$xv);STt5^x6vPEMkBi}8BLEOgQu!O9c~v0Wm?S&G?41i z-)6b<-|L&KH(yRfG08>FL;+}Xc=`@0^V*l0>LLk9li_RxNQxv7I>0`kSq7Q^UQ8Em zme1S?|EE_OkkJE*@HiGeKyf*vl12(`P&N*AN6thiq#MhHpm{7mDI>LPKo>b0bts|@ z?EqpZJWUlc0z8LeM34D@85~oBRj%vh^IFe!)i4??e)B{5>NE3CpVWI_Q@1Q}Ys_7u z|HR>Xfl$B5QV2fUbuP8YrlGNSK6p;YoA271EfzrSumQ9AyO$*dxk)xx1ip+yl`xBdf!=612__A;{?;b}Qkb5e%sL_5p~jbc_~@`z>(eDTKZoTUH0S;L51=~4{AK~P zJH8M9u>Q@@1$~ND;4ggL%X<%; z1uBTfTGd8a{XK?1rZoocWyz}=6r^@EZ;xfZwitMCM&CpHhR%V-h|Bi|K_79ZB16i} z7d<`1A~VtkREXgqy`7>Okr3(NX9?Wg=fdMiPs`j5ewLp3@dQkY^t9}H7iET~fe1op zCr#B1%$J-;q$yhc6jr?^h3F+#LdNXVqmGeO2n3ijwmoGe_qoWKjN7uMACHjIrlv;( zCo`O3t-MA_z@2kYe=Fj48eujNbZ)%SYn549&m6N4Ai&Kfy<$67n}k5EXC)F++YYo1(S< zh`(tM!}tUIOM4gw*x7tY(K#b_0onugQqCoUAwm@ea}PRa2u;x`hs`~e3q}Mg3cVCx zsG=xPszVq0+1E_&f+-<#xOXrLguu(*lZcb+S8*6G}yKS#Z~R98dAyW2Wl z%|1{=HSc>Z<~;Y6A1Xd^WoxnBgYlo|u~!-w7P=SGsumnV1Gocs`-U(aw0A4;4yw(q zq_94_uWnqBuYA%FM`FszPR&g~93F>-BXjrcx%3eHqif&vo!(pXl&l-hty*KrJ*p3y z;405fB5s@ob9qV}rt<6>0`cwz=$HP*@q!=rKnZDZBhvKjxeR_DF~q$i5wh@tQIMsm zGO^R63NOi)9*dCk$eI508Jf>T5h1}!$YT+rPgZS|q(@=l$l95E!}5+rDAHpOzyNXx z*+UKw$Ab0%89)w!J>)PC9WC0!p9aAGFhY=3st?dvb=*LM7KJK%Ms{>%f831cg7Bcq zo`4u#*&jEcvIowf#5?7MuI%vv095wr??CDvX`W2yu0}UMR*a3+*|~p~b}h(hOY~Vq z^|WIATIM_RHkAjND~-#&w^V+>u|Df>C%X*(lyzwab^LJ2kdZIhsOwrju-Ba?ejQ03dq;>^49Q$jyO4`wO9Y_ z&>CUB%4=KcpVDo$wrFo7&sNT>SgU-FPbt=Ab*+txY+W_Sd868C$84|42+>Rhj)J74 zkvQQQj9!Mn#K@UH#NV{aNY1~(zqAsFwnHk$qyRM43PJ;7W=z7$;Qz(!%7_LxXX&FI zxiTI*ItCxvN}C$LU{)icmWxtsfJKQGscx$>+eI2Z*cLHFQ)m)sS_*Sa1>u>3dUJRL^+ip7d1&hFh zqsfxTi(I3PM5{iN%qPh~^qc(G^4_G#=~01A&v$&t{qzFWJsGg*Y~jDI^$Vt0uq1$eBOH-?YlevA@B;v{Hx*_T_h* z=EA>k6Rh1^z9o?J|AH25M1^dhIC7`LrKo^I@F-7D1x3MeV<;HX2E_depY3om`xq7O3ioxkv`lc{P8eY~;ba#wYC%X9EV}?>b`6u zo~mz&ar4KnxFP3-SEtH|GPqTY<;>jkCDOEY1trMxUB8rwg^ch|I6hf)s8xwekz)AK zG1wa^+)ACGgHb~v7Gl>|_C=A6-RkF))EoxxvUgGl@g~uBes6LvyYqYxXD-@w^jsTH z2AwBWo?yGKM3qvC;X3yoc8RL^z3|G!y@qj@LJari!2XtGvuI7xP819`8X4)8!8q{% zAA3T}%@ zY2kaQcC~s2O3`p5M{HO0gIMcZS~0{19?fO%OrXN*?O9>;`^l^sC|`jFDqnTM(-)Ml z>)hz_RY%vW4e|q4yOUchRKJ>kE@PW6`7Q7j8cRZ&tM?ZkdztD zPC+p3^)ywsP-SF}d*sZ-O<6m%8oUHvO;c6hqerzEM9v%|BYJXol#wxw^eDC4vg<3v z8I?0fNXW-8f>2nspd{k;F%r1_#}&j0jO|dNXwT~C;Lt80F31St0S1*bbO<~RxOYz&CO(>8af6FNsbZa%?_0X=xy-rGYzZI7F8xzLROQv(|4XoXk} z00`h8vuEf`pt#YRgDyB_&Q8|c-NEYR1d7w&hs8mibT4kVbzDKEOkHs>t5^>gDuA?b zxc$sa4@_85y1NU@cn9~Y7CH9!heKVi#H+JLALPxG7sYN8xtb-u(-=H6+z8VYxq(~u ze8;BZO7T#USwEBhPT1xLk}dJKLT>f?i0!@VJ(hXepSvwYZ_ZaXF52Hl(XZgH%sYMH z32qW-Dps9vW>%}XDyR0k5f(LD_)C5XarsZtl3-#HZ!ZHPoaTzA1C5ltS!Rhrsq+C^B|7`DND^?ILGJX6aG2eKN=)m9;3l z`H|VFTnLh=oTh5hLyscimbH@%24Y0d=WI}lm`2V7k!J9xNg~>g#JF^0G~zDLS1Pyz-$E+n%s)|St>aPQd>1X}vGna>za(Pg zDXjPBM=jxMcZ-xYstnxlZ1Er6`KtyjPCFDS4O+|xnezSR7(!F~`8x^zA%!N36T+V} zyaz>=*DwwCB4#h`huhmKSSc@#O^^tp#v5HmC`oE2^`{$2$0%13S`G~l@Fq=*yZhj^ z!3`fin~ix2G|!50za$Mj3;m*z4X5OT|NAG0(m$E`@xOl=&V?sb48SjK%NtRs@$~qo z>ktYdoJ>OhF^>?TPWpYu}u?)}vIGHvGdb>|n+S3hp$?hI3MY@6Wi zEg8uFfbUVUF|V-*?|!RYif7Px+Ru>WcAXd1Z z2}hf!T;tW}FRiUk3yk`VLhA!_dP6!~SsW;oQ~n1MWP1u6+4i45@b&RO`ysrH=_~PK z)x`h&rKu(z_v^~Ljgve3R(}!PG#n!?-z%E<@Fuk3CRtW~LTu7Ff^M8^J#GuruhHzKmq&mY01=N=qYuA>wkTugoXd|4gMe zLBCV>Zh~G;jSrm2hotu4*f-S{3SbD(qu%4n+7*B|$GK$HLs6#n0Y(OYzbFFNUJ2<% z5jk@#g4*oAx*=3}+%eC6SvThX*dkuu$qDwtk5h|x=d6HFeSVi%h2C#M!WRS-H#6NE%GJ z;J~UM`%We5sMUSDHK6T>mr{!&DrK&_oN+#s^bnfi;A@JE1~QtOSxxS8Br=}5C_lF} zntCqxPYpyUi<0D?V=_yl!4$|j#G~Dy!o4$0WjtY}$`^KMhK)j9656&-a)+nUHnZ;kWmT1pw6-kZ`x;B zD$PQl2EPFv)lO^Y%a3(6MfPaW`F2pIP0{+#<-S($RPU_;A4uOuE0uP>Lj;T24$8bx(w1m^d;M_a^-zV|_Ba-N=5xYAxm_(6#f|C;!PY zZTrmQf|LT0tQ~FuY~B`piqr<*KIwmn;8SEJ_&TZ-X_|$d!H)qxmL7?L>6zU=utYEL zvGmZO^jHKROIiPI0NK+Zrhx}-W3fy_mdwb>&^Cy6U|I}Ki#9r>J&FT_1<@Xg$FzSK zK=#)mTJ%RwR_G|CPRlsigamX!XaCY!fe9$k(FlS%`~rH^*z|(2fmhHl1tNZMYW7ca zYqkl51SZ}}*mvOSjVx@TQ{Y(&`k+-HsX)YM#;;9J(86)`NoD4hq*+^^bS}Kxx3uGD zKfPMWyP%U)#_~?}nJHfnc`=`M-@t6~Q2Dos$D8d3J;p>9w}bnM*TeR>gm>#!?eg>P z#Kcl=erCCtd3&}u665`o4$djHHIN^!MKc0X))pL0`a$-;i5f@=qG+V`bD)LTkHLS~LcSqeG#H}# zM++i5Vm{VFjv&7hP~3;wL-E+}W%Mw96MwTshXEZ-cKV7EGs;y5Z(0GYbC*E!*}>Bb+|Z}?N%k*D#RPA?!@ekZ`9tk<$Ge5j`(@=IqMbUE7}9C=I3fB z?k)cGxTH;+mgrIzG2PC8SzFpP06jn9ajDqS6#mE8(CtspoDzen*g})^v?uKN`b7`^ zzs%@SqZiRLPJx>OX8e~3S%aqwdd4DWtiieDu?YE-wY%kwULt`?t z^!Ad3ZADFmP<5Kx7427bdS?Bk)z39iZT=s}J_jYoGIp;1GYwT-M zZbc0{Z9f+5rR=oipq#mOdn$2py)BfDurbl(>QBVt8bj^aV4#qoM{R74`UHoNb$g%n zj!qT>vsx6m*%KdNc5xqIY83^liJ1keYOKs^{~J{n13fAVTTbmaOUUY1ms&-#s`~HZ zAtzev3DX8{{s13|=s=(#rqj?=QNo~5L5s)EGD3?WTW~tjA7x1L`hLfaZ_Pf?nZ@h- z=(B%yR`iht6Om1C?tSz(vM7)-;DqwH;Ww*Nn6y@0v}}bAkL^N@NJ3RvIU7&r+_&6m zm7iEC5t}TriRI9mSRq3Zu(GShN>~(X)F|V9_bcD;Fwv>7cG`=0x^R0xJv5v7@wJsG z;Ts`ZBp$6^lw&q@!etu5Tpg5ERf<)i3zZ{w2UD6?o(Pr5H*W4|mkIs+p_8|>uy42d zUYnQy`kpLZ>U;t7!qMNV+Ru9CS3SXw;zKG(C?oR?^b!1*jQ;gwL@6QVxTBF*l%tWb z;EWlG$PA>a0UGu{RQ_SH6?_w~T^H3W(1Kj)pJ`xWD`BMvujxBy# z+j}vl&=f7%$)jfj3*fbr($#&)ZTYbIk{$}TQl_?$)Nps!fLV2`a`Gqkf`uf6&oU z-_k#90ZIrW(xC_v(%mU3-616$Qb4*(I3NPj-5}lFjevA_NF&`HzkRUKuikr~`##V6 z$GG;)XJ*Z84`;1ev)5i{B}DaUqp*73D~1^}@rxZt3|f!Xk(3M8DaxBk$Br1p0|#wf zY1L}b!h2^l66qVE+){wfKcp^F4mI#W%O@be{z^6I=dxOLQV$e!W%y9ZWc{JOv2ikX z3s=}HsEgEEc)_pA-%;Troz8!D1wn}iVwit8vH^Mq*kC|;9_Y$u;S&AHUO^Kt!}vw{ z8~R=IfgE}y{L*T7%?b;dBWWbDCRKANY!EN-rb7eMN3`|Ul7-z;L7FQ?F!YF5P(mO$Z5S$QZbh1XtMX} z`s`A;c(`coA=|Un*sSNAr>{8c@eHttq8A0oo>UM_+^u05Y>xe6&YMnq_7>wZJN_-9 zhLtX9s5S=nkPZN~>0h(s@7ZvDzkgp*#P5g-%SxrC#kf=ovsB9a-ZC+HLE)WE*S?~vm`T5!8l_krZ_x*-iGB2- zn4+}Km&_$;Vy|wci(1&1u$`y}u00dCn(oKt7}b|f?aSgCTS%IO-Q_jh*lF+@9!Obh zqJ6cIxN-2AoVBVVWhyUme={V}a=3K&l=Z00BMi68lBnk6{o?mHYqtG4dnI-vDlcrE zYKv^&^0Qmq>N1zsF2+(>F=l)&i&!VMR}z_&?!lF|{zxJH+_FGs4~b0HsX{T`_I5~m z%>LMA8P7p%YYgL!hHi+L0E}&yQ}OK^lP8LD1Sq5B$Z#vGz_eFOPeUL$gMMzG(y-1g_84*AyQ ze{Z;SAfW@_y46P%F&5RNO#4W*t7dj@1vWG+hu=DtL`*iUwxhnp#KtSxk44tmP~VSZ zn_@(e=G+vH^&E2{4?#Tc&yj^Ly=na#Z_DY7S|0kCX5yZDp8Z+i?R9wjK57T$`^~kB zs$10uMY?OHQN=stbv6uofJZlckJD_(F`o~VdnV~mG)fg2y-ZVL%#+EAR7f8b zB_0?`_jjr;Eb5nHS(x@q>t$zPm;LV|MW8b>SsW^1iyvBw z=@7%aVM*yXwbPcJA#Bj{FYFccYnOjQ`P0^&FSlhH^jxM^YF?Myr4N(0Of2Ot(;iDFrM`4H$wvy=&O0_0~n zo4})>-s@etIb-DAU1jKBqK6XJj4V?+v}!o4oVN6sZ7NX>TkQ|dXG}g0jhuLi!!3=g zRXRAeiaF_+r_SU@fe zF&H@UN|f246q7P@G6@381)D1ti)SB!-GG0>m(M;*rXQdQTy~$_2NeVCBfcCI1#y`F zlM(FKArms1{-{IzGGzXzb%vyUyQo#ZZl?a; zd>zCfyQsg{5WZCu{yI{AFC|>59$apXGA#$50$vsw0HoY}usJH5#BSC6Z2jW;inQ5t+e;n*ZbLC*K|Kto_>Tf?=@#7HQ%cH@roWcwH%PG8&pR)LN3h$-m z_cO%)*N))@j_1AN;`>=PccxyuBo#aiu~$11+&@4azSDVx{Ihorz}eGoXj&f(zrs@lNu zReAhK;m}%lF>k@dM#Pz|gTqp!M-9Wp_&9xRmF*OL&J^R?R?R_98)MK0}+9}zg=d`TsOl4<&ZA<@bnWW9aXv{Qs z$hWJ4oebwte`35wuh;{vV{K}dXq91TOr>BgXK0=!B=YrAjz|29#Ex@`^AeTdv5gMO zNd?hyg+A(H6Ra9Cr~TQBgZbp%tYVf)eR&n932~ysBs-qX`*X?T_o2#YXg1z*9zs_h zz#vwSTr|XPv7622EZtR9VLyCsLn#(kS#ZwCX>~xdMdUPN96PyKfOp4di0`j<8BX^zrz$90EM zL-*~*hIkJb52H3sG|n%@Q?kzQbKG|g%O~VY6N@V_tz>K-&E}lP*W(nekd8}MR09{v z@}-HE^HaE|??>14$0d1vSeGTH-;b6&SWk6O11@r&j!T{xf?4&|9Hr~=QcfJcDqxPn zTJ?7Ww(b@HHY@{NsQ3U%v+r4e>$`x#az=RNKe0KSp_I+uz5<-p<-bpwR&RHN@mK)0C0tA)erbz2D+CS0y-$iEl+HH5c0tszj9Z_zhOJO8?TD%;a2FKhY|6 zRS43l5s$EX{FooILTaTMD(OZPxRq5Pe!o-kC#w^`{hh@IkFs82A|w6_*rAR!#CuwNpuVLx3N8OZIe zw%s}ZiK4(ux&qfSw!CWMxSXkf5q-z3!73^*?6H^Kxd1|j{b>gKhKKJLwMA?0aIp0| zr->+qjtc8CV#dMT6FP*=)vY%wx5KIER4LSTzqgeya=RTMjGG8LCMDX}mgfmP!lV1{ z?tXW8d0VvNdEu|ubtBPeTpB_2zTw(Uu&0drtqT6#?SCYfZW2u}PnK4KgifYJYOn~( zviAenq5w}o6abjS|5KbG@id%(j#iGiALA*CKH+^Z%eM}mhC@Wi5xdP4&O06B># z$$)7uY-?js9=0fV?p`d?^mA4qmm}MfrUvl z;-!QYQiG5I7I-!LDti@0(f_90`Z`yFgpf=IP89nXTwY+yM_^50PeRSiD`=E?dUv*-tOmlC#S`aO%#=_!( z6N5Y-57T}b2i?>$);nb6*ln1N-8*W7g@<+{7`x{;j^dTAhR!T22U_PQmkV-|mDfhh zj6hVTj~7x78ll?PVst{h#a>u#M)BI@;uwqjDL%UqF;W5(qd3_$z4*e|M*C<0i*vEF z>+!ndMw_wFAv4Umjf|@0mRWW)n&F{MA;l4ORM|qTzzV+l^y2tdSE5A^=B63$;bKp6 ze@gG-xcTXhuC$|Tb644PtUx4k*vGE2*;s*DWTDe2pr=A|!ns}M67~zWQB)jw&P8`8 zTthD{msqndPT%7B2|~xtn*ikFB{l8jWd&$q9^9B&9N+FrRJnJ)Www5_*psbWxXXM% z4rrkcf!S~B0r2Gyyea5 zdt5w>bjZwjxRXlYytODfwZ6G1`RQV&D-oY)wkuI;>@A>@4cw**_0E@Oof3?Y%uKkd zyevyBF^aApEIUiv!zG`NxKhUbBJ5n`X>#B3h1U0B7e)f@?-fta(2v+v&(GKKy+kYr zS8Y|1y4SRH;zdRjiKQ)3TZ5wcXbi8iU>eX5_ETZ>RTfab%KqP=1bvrLU3GND?|+NB zv=S*}OdvIRZx!(Z3HUI^y&U!&V_d`;2`<3w(!kGm~(e!kjIVkGB>cRu4g zLz9sfwYV*XWig_aa#u>f&p_AO@v-XXaGzPKk1y3qbtqi)bL>u5c+^2HIaq;u8B+_FdMj9RcT{IZx7tZf_t7c`xH%Bz@cyHGMf*siOr8BQHjPov2O z1~pm3ws~)%gka2)5KGUJkkK|tD`Cn)W^|OBqxjJV_`ypR+?OE%odOE!Ac8-&b$X z*@n71&Jv^;g3(IW1`k3735SEi@?AS}gkj?pebS z6}8R22i*Q>g~v-r;};KcjR$z^c>YN)JQIJELv;U_F~3hhpWHkJ9&fP_ zYr)g;&h5fcBvWOWS27!Il9#$Bivo$Jd?{W%yoa}rCeh;!h#wKE%^Mds1cM!gSehM$ zjMkP|L3>vsxBWMzR+*oQKa~Vo3);U@qDWG-qV|Wsl4NpkCmHSEiC9`sCj{fq6qHs- z+vfduYLyuc2l4-vFhHbh?KF@7NFp@RmfGR|emo^dX1x}T)7y^E8a?1 z_Q?hDT4fc%8k+z|{-&v@{>Vp6Jq-`Hi=d3>w3?^qPV3mv`$?Ep zH`SPK4&Y~Jb4)~yvN@S8FAqDKL?{nZQ?!uhEQszKgdfgZBEXrHXJmI(#D>JtY$>LS z*rP1dhmy%W;eZSF?BXd}2mtGM5W)>aJV#B3$PFkYQ=8!wQk(ur68}GAg1Ya~awU9z zQa5btvngP1GwmR>-D6j+g)C&t7Pe;sDOTRjTG!nGjvz9n5cipd@=#G6O6~9wePu)@ z*}Yaa3uU%69L(y$(fef4fMO_bp;t;xa{qlo>_z)Mmxb{y;2{1PYi_fVh&IzIx!7?9 z9evm58MK-mgutMF1DLj;fB_v2n6l7-DT`7)oLbeHhF-OnMzhixnA@)Zt`sK%g#1nM zk4nHq^Gk34Py!~Jf4KZb37Ba97#Bq88c6@oaea^JUj`3R;tI#Syvtu)e*bR}Oa}fy zuKZX0L+RJxX;gEsu?>|+RtO|o3>8JQ^yA688d8p#m2t6mRl>EcPfsSRoZ4hQ^}Thm zv~_mz!o2KtH09D^Z}M|=%w;lo1e*}Ba4b0fQFnc}gsz6JU?CM9of0}GJ~=!>Fsi$| zNE=U5Uwt={zJ@Mw5f$AB08#>=JOEOH*51It*~AH)oS3CyPi4vTp^Y04O1!qb!B}g^ zy6rl(-RRxU@zn9xc{QKibZ_#8hWB}dfSOK%fR3q&Nkz9nr>+aHU)vql4=AMrN^-7X zeFZ?V5KuG$ly(3mXa;p%kyo`6k#7o|hA9sj^$n%{+>%M&@)*J<07Bya~I>HC{QB$n_$MfoSE zxT1B;Tb{|EP2t9M=PXu^SUfw-vg&4uKSe2I*2z!qP?4)y%cl>&ywg}Qba38n@UZpX zj6rPG+b1QRu`NFLVn01>7oR(@Ps%xMno5kVE~nubk{v(7ciMuf7K~xyEVWUL8fF@3 zVx`!oJ#wkJSiIXa_sFP_UDIN3-L($XOX$cGv)MT1oik@B+j+iNptQ8mVLKt`vpsv( zwU#=ZE`^(%E)9?jK(aAO<#IqP50C;tiU27Aqzupt08;^4Re;n0QU^!_pqBt?0+<%i zf&kJ6NCzNYfb;;;2QUMmeFcyqKt=!=1N0go6Wk>2c{UN*MSy_Q&16>qS_5cGUHliQ~*iz&>O@Zaw{$ zIJ$3&BIGqOh_ha(Cw6i}$#-GT+a`+ATod~Hxh3_NE((mad zt<*M@g5m1|dvUakUeWh49MNq^~ z3Sa>N`+~LqNP^2jz*9TfLT`r$AD!afaWCxT+9M8CIG$*m|U{FZA_ocU3@dEv*JO!h6v<|Ep89Y>wj>@2D%t$L0|Ck z6jcChgNj^}+44bn_R-pFqhteI2bRu&y~rb_gn&5~#y0vC+_tBS{U$tXCjkrZ?qnFB za)(d9>k4%!$D(9UH zYi=L;991sV^nVh{@;_x)^?u+=jvZLffhvOS_1{S{)$Sj%OC4RCr*Ak9N|vFXiT?{P zmmZWppr2wC$x}YGliItHFYzlSNF4k_mfww!Hq&*+UFEzgGywOOX9BK;XW)+{$Wwsk z2TlhFRVdPN9WCcW#x+^M(cVw>U(K6UYoTVqj&0@9lyF#QAv!q^S&zxhNH>lE&PAut*g5R2ZVb!}8$c@&)x%>llEhNJ-6Xhvcr26c zK)0He)20(S#@JCN*IxN9ZcLC>GrqS|A+?YeMSsm3Ec}B-CH;l{J1UV{MEjfa752YH zAIGOf=Sk@4kjacfBBHBs1^l^ReuTy5DtEq*G>;L-g_ zduaDYbi4mNn03B=v^^=1G{2qafueT&JF)@^z7WM!{5Il#e-LVV3k{sCRyg=SfDJ4B zE}}lHz2Pyeh?5wjAfPiuL(w0D0*_j9#}}(er2fJR>W)$n_ZP##7X2{z#`5s={mI~) zJ=iVzcZ2T^A@+Af|K^ZuN$WDK|G=qjp~^zz+JcZ*S;&b_(*u=A$Lf896M}uuBhy0j zg~pfF_AwdtoC^W#FCL$>lsL{ORU)ymYP~Z=hVD>y@{7$Yz~9VMctT+yZ1lK`{xc#c zI;{gKqPBXT>6^gNPmd$*1E06tS1|3~QbDAw%B(Cq-r&#s@j7GBVUjzv3v!+pTA^sAAjNd$Ka!+=@nukuz|=%k zvshWh2r{6Fv@+yuzqf26!&m$w#ew?BDT?5OZ<^`+qN6SFke^xLdW44wFlS5d*M`L6 z?db)*~kSFr~=dAwA%$$_=$hE%zQOKvB-zMd6 zvp1|XqRJ7YQ$;+W_xrpJsGuZ=sC9V^4-22i3;>h%o0=*M!=H2Zw;5Vks+q0P#EJR1 zg>=V_J{6d9OSpbf3i=R&*$nIJ^7q->0W2`c@|U@tTuBK)pL|E#fh~i-l7Bx5@IDaj zABj&YMFdT_OwiR|S&?vxZGZZIPTHvnpi9UCxWEP` zau2`+nBGkwtiCP=Q8>k>|3C?Sp*Li@MhVY-BR2e<+l5T!u{0`kk25lWi5({yMAn>* z-$!4A)7fF(ktp8W)3|0^EUP7A8XY+wA?<4z2rOJSmq==()a@;1#n&RR#8Dl$(rwmz zPo9KM=ETs#EAZd)1&&Y^ud%I94z?-GGH6RQd@&^zN1aPQU>k!$sr+XD1hzZDXp?9n z`zco&tHk+-lO;sZM(Q@jbxyq@BS23bu?z4y6L_A z?uJKfzfa{7ZL3cunamX`tQ`Bi;XuEgKxFZl5>EE-1p6H)-*~&Vc+T%r3Cy=GZ9GM{ z{lV$}p#Y(Q%P(8V^{<3F0PVDHJka751H|x)`zxUkL$Jcs!9!a89DddP5BhVU_+N=H z-sm4PQ2a;5y4Vv}Oq-Fwe-#1{lAHFoyCYx6I~%7grpbvxlMf#{K9&RS#W0;;6%`eKI?e&rD#ogjoqvR7$`}f zRCJ@i&JMdjh(@IfU5%J>Y9RM1P9%PfoiNA5#&jF5O-&R!U*$ zkifxl+2ea(8+A+|@Y&$gY5aCh_9XkUof#;vX0?}f^!j;)ipvRW+C@!utr3S|=qzYn z_?g|2d0!N>YVoZBYYezQ5bWNc<==HLadJX7O+R44U+H~Gts>g-G=Yk#?OG`MwBg{N zEGp?Q?EeiancAWCo1-i2e~Uhe*LzYR5&nrxMw3dN{=7cLS1Y{f}7j?60uAGN`p;L6GVB_QfndtrR<%~Rnv=TNcR(lEy>ey!dp#UX65ePt-mEo^0yyIjCo$_LqFbR}K~RhPK>uU|6uGdh zHFJoDtO2)EY-nTeeU_6VKQq(wSi7$PAMHd}Qee7xB=}dt0+(Nrg*f5uL9&+U z<3eBx{{j4}^ivM$>|bI39gd2CcyVT)!C|=nVHxPr8nWGcNqiar7!SgAoEe()+w z6rVPoC}D6&+>gltTjcJ`lXaC9=aK&1;EH{$Tk`J)-|Y$L{^k&3FQlvg7l#o0!0x{W z>?Zc7DF5hG0KrMDQlfz~v#9*FgNkrjic9VuALe<~F*d@5fsb7Q(mt2IY${cKXfH752YI-ICARct98V5+gNaGW(Qp!N0Ju zML${dLMODhW7BMja;kHtBTJ>eN3X-yzN~bPBv?RL0hYX{8599}Y_ zoJokC(?XqNLCsTNyG5_Vr;O**Q>W5Qy%}G(1jP=@l<#XN_bKns+{-T-^M<2e#*D2@ zGvUA+&Z-LcOe*gPOR}ZCFWk`~LN;L7L^co^u8_`1nwj5NJk}xksD9T)kM_RZAf{4NVYnx|0Rp+^XuDesJ#Zuam$EN2 z1r%OM%^e~@Eo7RFQ10ajjr|zI{B&|Oci>%l9?yxuB{1#zLH?*h2gsugNQUsWg_S-qwE1An__aFn z^Wnpl^a7m5J0x#ic^610bbda&_?}*9EXQYT30vRB2;wmKhdHctTh3x$yyNM_y%Y8f z5iUG6*paEpayb@ad$})hRI)6@BEffIrITFq`>8Eyt4}=Adbu^y%_YJ}aZr+lVZh(m zkkOJzSl~zI|6x`y^CgbVVq);n%77dPg(HJT<+4xNWVlP~R`Wa=opNga&>3x|Ba>Ddl=xj6ZSTyhr&t@*rDz83R(pxB*B%TkR zEkZm>ijsDSj%BH!E^8c?QyXU>;x16pj$R;QwZfV{O<$*3ag(B5c_x*T34EviPD0W7 zV#M?Xe*V0=cg| z;N#}kjvg+M>!G1pX^a7?U;c_jyP4sDAK)Vf6m+r@Kw5*q_xJ(%;{vfIMM(HSZ46N8 zQsQfC$ppUXmtC|Jhyh+83yXZQRY=}QIGg|hfv6>iKfC2F0+Rr!HAa9TTM{lx0EdSTvWTWJ# zrJ#C9Lv^ac1VG zAPqxU>+5Su%D&@t=ne-tn~4Gm1!Y7#!yyzZ>0mk5LS*=KVc;yA-VmXjQ`@NF#o@>{ zktejle%ElHSlBb4cOFq#?o%E;J11=5c~VD1{3gy%FXj{5`_K$QBehnY?IN}cHIMvE zQ1`i7s4Z8ncfh`y)hH1=M^_*S=~g`PQyXLQ+2P8;8cC!UCPDnN?70z}Qg|)mp`mS} zv}_904iPC8ju$Q3PtraZmYpo}goRiY&qI}uf7UojbdZfBRA`BvKUO|cpD;3@6s}r) z*j?K?X5BY{q#oSDI7FjDK6i{*z!O5&Cz9MlGicZUge(Chxr9S_BzzGHYgn@q-4xKI zAf)S^tlDu$LDL|xsy?LKF1LrnjwnS98yuyJ#Zycc zs5>3Af(#f7nYWPk{}}>Y>_miCO>0&_ha!{(Y<*==QeoJ%Euv(D{0~Jr`WAhudAnvmke?c zh*~k-c9mt|;^CwVQq@JOc)6I{UQeZrkZI<+J7dm3$YAY%4?D;!5u3)lGC?>l6%)D9 z(U)yd#zc1~PHjq$xcIGEa`_q>zt{N;>k6Ur3(GyEmGm~gWHB~$OZd+(o#U8@Truv6 z20-=U?>lRXs8$%iO-8@dXI_hxNErI;6JftPi6LngEf$pma&CG(^r5@C@x{9QEBMwx zngPiq-Y|qD()#hD>&mL@!_E>E-MLH)3#y4P)H^fG+4XfS9H){w^A5sj@bfAoFCu!E zo*U)dw7)oNy@sYD(BYB4Nbq@3&1w^WqAqz51wa3*ND}p;Pit^@*Ef+qWr%dc|357lE}wIbVYif|`>yGbghmynsKk zNP=SmPf{(qP~ecvia=ulIb6F{aeWeY@jVuc)pAbDT{Gq69lM()v2%>eB%x%FxTVr5 zkwvD@d=OyP8Qhu$*WcNZ)Z|y0^j7I!kfZRay%b+EF%nqKAEi}S54okf?u>?~&6l?6 zWuc#p?4?F*)VPMZ^Rk~ZZiZF~Hv#O*ks$SWN*S8ayL{Csvagg|+i(NBQqh|4uydxf zwSVH1MZN$Ecp|a9oFsuwNnbq7l(+Z5RZihd&w^osSl4~k&#{>4EHt+VEQ`(R3V%0& zpUN!>S>*}i?(L7LyJwh<6QAQ9!Bz)7&!pIqnh=Za`B3a1a;3kPVdOEvZMs3^;%e?% zIZ4|mGI84>bgWObhrK{~LU$@QA=2L&WiNRm18X&8)ux;p%1an3@Bs?l70 zd0wudK4Rme@_YI+jN9rH=p#JSiCayq%Hl(!v4ab5h~5<}gd|CC%eHu-Fq&}%y6dQZ zD4bs0x827FB~nE5N9~=|#iXlSsW!!qNi>GlUAu0#-|LAjPV^>L`+dq#E(?3Kci&h$ zouku`{o7?|*Jn=tmo1m@DbQ7v6@$IVN@LNMLoZK zCe)oR#@!U1`^(XG-rcSvgMwkIot+OFpxXreI?KX$DPQH;X?JW_ok3|G==pn_4RUCq zd^USVXqSMjpPi~LJ(lc7hgS|WICaD_g@3boUSh8J;to8 zRdl1>iQjl6*T!RVXOOVbOkMF6TWBBC1~g9sQ+eg5UKdSsQD_nk4vDsB^90I)AEo(v zxUI1)LJb@r!uKjvyIGFF;U{Y=;!;=VLopQJhvQqP_9A*Tjwr43VSIvIod?=#|B+UE zrWOC&7odXLm8b55CByi^xmAe;9^jojH<_Ae@iy<~oX)w7PZbPBF`aD)o!iWD@K7IZ z3>MQrMBok_%vrimsea5meS&dB#q33+ zwDQi}wMt5RuoRZbW*t-$dWaYh?3Q`U_)!k-JsKH$zx-0!-FP+(M50N>@SP4PA$7j> z3s0XjU0PP>kAl}zki!r++HQOMJ&L)2O1?09%ZxV=>!~h&em(x&d-R`4&EllG9vT{vYHtG(b-CHPQMtrMa4|eNSn=8S9U zh%udoXSS=?psNSYfu&HDLz(NF6476w75>?Ri5Hqvd)517*-f?~W6(+*V5H(~VlVz@pQPU@$U!7yE5ZCv0*Nu7Zn-u!=i;gQdN|SA+1ab8Xpl$SaD}rczxMw{Ycd zH5%WT^6_wcZS8Q^?}At~mIc3I`fymQ zBwoyKY~>EWk0$egDt+i=xB99Zk?G^xPwAsslrBU?6>T-hq`4bP+)&!!0B}qk!TSo! z!%y2E%XGx(waBP)h})rW;FP4c)xQy-;zWCfO1k=iLS800?fI|?Um85c+SqX3yH7~E zJ<(P(yGj~5Qt$<-V(Yc6#g+=l)4X7#M=3XoN*}^!xJ;a;!-trs^y!dMw{ej*kpdv^Bv+|p zx^D2tVA$uKT8Hf1AMS;$=C?Qd=pu*a$Shl^S3j(TLR#RdU$JZq!%2Gt4%iUYi7ymDal&jZWqt^wyu`bho!p(=17&s^4W zkr=Mfn?g?J%w$kYrU`esLO+cy!Ro!Ga65Gz=}a5&sz6>M^)kh7SgF#!Pb`E{7mZ>D zI@8GtzCrR@rAG1t|@him2(13BP-B?;(>xZ>^%jcD!k9FvqVqk)tAtEe9b{j z&FqcA@uaaTWp>nr!4@9iDR6Bt)n{e!WRqIbo7ao@Cbr7)@OF3E(AEnXHM*ibx1+l^ zko9wm7SW0rvGlVaG-C9N!IFHM!3p?sgZ40uKwF|<%(elaI7P-%I>pa=?N$j1W0`B= z!|X`meGI7Uq=};AFWv}UtOu*>-J%v4(rZw>mm-NyX z4(Zp_K1Ykg2K6xIo!{xb=+PC1HW>prDU3*z%dmV5=Bgwc+I#Mx!_vh zhUjx{SYFJg;Nkb(CQ50ttmIIE^EZ0~o)Vqbl@HR$GRKqlYp=$&WcHSLR7VycC8;cP#}9@Q`qM zGAI1|^?X_NA0Ex8&faJqt~GJn^}MMgcU&e*Y4sV(sk&`rBC1|qnTIHC6IZRM^qfh} zfh8bPB;sbzzOhAWTvXTi;0RYr^A2~8+dbGq7-Q)h+MJD;i83wQzLe2E4brBT!t6i4v$s z>scsp9NFD+G0?$s$0bqXVai2DLzGH84ji^Jmo>sY-44S?J()tePi)qG`H+ehE9I6P z-V60?dNq*iawZHXOd(K7R5c@zwt_irZv+q1E@v@S?_fcH(5FCZ#nEV)XgSTMNJ5x< zo|nKsIvbDvLFrslKd(63B);5jGpTv#?%-hU!Dk1vl@KdW4EiM2cgeahicKD`@z2W? zAHeycE70$@`73uK?G`+a_vP~H*S@nMxWss);6$xA7gemz>Kv&tC(w^b4!ih0xN_jB zstpU_9MrRSV~At^)z@8~YMb9c$r{{3yY4JX*%!_mn`7r@!D^qFsLj+{OYJ5LAdlDbQ+DJTl3()UzfrIo#=(ld$Adl7~cQY0XY;aodvHL$2DV5&jvcXqGT zkG*xrqY>$gAsSI<(D3{DXBksYq4&=wJuVt=4d3yg%n?lYt+os|)!SnHxmO zcN+*y-o&sbU@5?zw1gQgP3QT$ndwow>^j>`H&9|<&w$~S_xT`*sia{}zivLL{8AUe z1tz8T$PbNW{^a_@H*esfrv&43Fm*tVM2GVO77_v2#Wd8IzG4+LF13@`6;S1QwY#m2 z_d`KjPi>J3Vnh zpPntArtbs)5@=AqsLso~pUDoToZ;g2!T@ti&;i*KJyNmZnT_zqOSGDj;pjV>F#Q7y z*2|Xl;%B`mKqMoiVFhRi2}tm++cQKwj!^Qnhu z_jA{=6)1;X$Tr~kPznR1$(f!}_Zs@?

Y@89G7#ML&X&)5gyGvw_ElF$Jq>7&nhM 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

YYkpg#1uI%td7gULc%H~@Hj|=Eq3DIA1 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%0AW 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 D*h)3a diff --git a/AltairZ80/altairz80_dsk.c b/AltairZ80/altairz80_dsk.c index 070b8b6f..4c7e9742 100644 --- a/AltairZ80/altairz80_dsk.c +++ b/AltairZ80/altairz80_dsk.c @@ -1,6 +1,6 @@ /* altairz80_dsk.c: MITS Altair 88-DISK Simulator - Copyright (c) 2002-2010, Peter Schorn + Copyright (c) 2002-2011, Peter Schorn Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), @@ -152,18 +152,20 @@ void install_ALTAIRbootROM(void); /* currently selected drive (values are 0 .. NUM_OF_DSK) current_disk < NUM_OF_DSK implies that the corresponding disk is attached to a file */ static int32 current_disk = NUM_OF_DSK; -static int32 current_track [NUM_OF_DSK] = {0, 0, 0, 0, 0, 0, 0, 0}; -static int32 current_sector [NUM_OF_DSK] = {0, 0, 0, 0, 0, 0, 0, 0}; -static int32 current_byte [NUM_OF_DSK] = {0, 0, 0, 0, 0, 0, 0, 0}; -static int32 current_flag [NUM_OF_DSK] = {0, 0, 0, 0, 0, 0, 0, 0}; +static int32 current_track [NUM_OF_DSK] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static int32 current_sector [NUM_OF_DSK] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static int32 current_byte [NUM_OF_DSK] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static int32 current_flag [NUM_OF_DSK] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; static uint8 tracks [NUM_OF_DSK] = { MAX_TRACKS, MAX_TRACKS, MAX_TRACKS, MAX_TRACKS, + MAX_TRACKS, MAX_TRACKS, MAX_TRACKS, MAX_TRACKS, + MAX_TRACKS, MAX_TRACKS, MAX_TRACKS, MAX_TRACKS, MAX_TRACKS, MAX_TRACKS, MAX_TRACKS, MAX_TRACKS }; static int32 in9_count = 0; static int32 in9_message = FALSE; static int32 dirty = FALSE; /* TRUE when buffer has unwritten data in it */ static int32 warnLevelDSK = 3; -static int32 warnLock [NUM_OF_DSK] = {0, 0, 0, 0, 0, 0, 0, 0}; -static int32 warnAttached [NUM_OF_DSK] = {0, 0, 0, 0, 0, 0, 0, 0}; +static int32 warnLock [NUM_OF_DSK] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static int32 warnAttached [NUM_OF_DSK] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; static int32 warnDSK10 = 0; static int32 warnDSK11 = 0; static int32 warnDSK12 = 0; @@ -215,7 +217,15 @@ static UNIT dsk_unit[] = { { UDATA (NULL, UNIT_FIX + UNIT_ATTABLE + UNIT_DISABLE + UNIT_ROABLE, MAX_DSK_SIZE) }, { UDATA (NULL, UNIT_FIX + UNIT_ATTABLE + UNIT_DISABLE + UNIT_ROABLE, MAX_DSK_SIZE) }, { UDATA (NULL, UNIT_FIX + UNIT_ATTABLE + UNIT_DISABLE + UNIT_ROABLE, MAX_DSK_SIZE) }, - { UDATA (NULL, UNIT_FIX + UNIT_ATTABLE + UNIT_DISABLE + UNIT_ROABLE, MAX_DSK_SIZE) } + { UDATA (NULL, UNIT_FIX + UNIT_ATTABLE + UNIT_DISABLE + UNIT_ROABLE, MAX_DSK_SIZE) }, + { UDATA (NULL, UNIT_FIX + UNIT_ATTABLE + UNIT_DISABLE + UNIT_ROABLE, MAX_DSK_SIZE) }, + { UDATA (NULL, UNIT_FIX + UNIT_ATTABLE + UNIT_DISABLE + UNIT_ROABLE, MAX_DSK_SIZE) }, + { UDATA (NULL, UNIT_FIX + UNIT_ATTABLE + UNIT_DISABLE + UNIT_ROABLE, MAX_DSK_SIZE) }, + { UDATA (NULL, UNIT_FIX + UNIT_ATTABLE + UNIT_DISABLE + UNIT_ROABLE, MAX_DSK_SIZE) }, + { UDATA (NULL, UNIT_FIX + UNIT_ATTABLE + UNIT_DISABLE + UNIT_ROABLE, MAX_DSK_SIZE) }, + { UDATA (NULL, UNIT_FIX + UNIT_ATTABLE + UNIT_DISABLE + UNIT_ROABLE, MAX_DSK_SIZE) }, + { UDATA (NULL, UNIT_FIX + UNIT_ATTABLE + UNIT_DISABLE + UNIT_ROABLE, MAX_DSK_SIZE) }, + { UDATA (NULL, UNIT_FIX + UNIT_ATTABLE + UNIT_DISABLE + UNIT_ROABLE, MAX_DSK_SIZE) }, }; static REG dsk_reg[] = { @@ -244,10 +254,6 @@ static MTAB dsk_mod[] = { { 0 } }; -#define TRACE_PRINT(level, args) if (dsk_dev.dctrl & level) { \ - printf args; \ - } - /* Debug Flags */ static DEBTAB dsk_dt[] = { { "IN", IN_MSG }, @@ -262,7 +268,7 @@ static DEBTAB dsk_dt[] = { DEVICE dsk_dev = { "DSK", dsk_unit, dsk_reg, dsk_mod, - 8, 10, 31, 1, 8, 8, + NUM_OF_DSK, 10, 31, 1, 8, 8, NULL, NULL, &dsk_reset, &dsk_boot, NULL, NULL, NULL, (DEV_DISABLE | DEV_DEBUG), 0, @@ -281,6 +287,11 @@ static t_stat dsk_reset(DEVICE *dptr) { for (i = 0; i < NUM_OF_DSK; i++) { warnLock[i] = 0; warnAttached[i] = 0; + current_track[i] = 0; + current_sector[i] = 0; + current_byte[i] = 0; + current_flag[i] = 0; + tracks[i] = MAX_TRACKS; } warnDSK10 = 0; warnDSK11 = 0; @@ -332,23 +343,30 @@ static void writebuf(void) { dskbuf[i++] = 0; uptr = dsk_dev.units + current_disk; if (((uptr -> flags) & UNIT_DSK_WLK) == 0) { /* write enabled */ - TRACE_PRINT(WRITE_MSG, ("DSK%i: " ADDRESS_FORMAT " OUT 0x0a (WRITE) D%d T%d S%d" NLP, current_disk, PCX, - current_disk, current_track[current_disk], current_sector[current_disk])); + sim_debug(WRITE_MSG, &dsk_dev, + "DSK%i: " ADDRESS_FORMAT " OUT 0x0a (WRITE) D%d T%d S%d\n", + current_disk, PCX, current_disk, + current_track[current_disk], current_sector[current_disk]); if (dskseek(uptr)) { - printf("DSK%i: " ADDRESS_FORMAT " fseek failed D%d T%d S%d" NLP, current_disk, - PCX, current_disk, current_track[current_disk], current_sector[current_disk]); + sim_debug(VERBOSE_MSG, &dsk_dev, + "DSK%i: " ADDRESS_FORMAT " fseek failed D%d T%d S%d\n", + current_disk, PCX, current_disk, + current_track[current_disk], current_sector[current_disk]); } rtn = sim_fwrite(dskbuf, 1, DSK_SECTSIZE, uptr -> fileref); if (rtn != DSK_SECTSIZE) { - printf("DSK%i: " ADDRESS_FORMAT " sim_fwrite failed T%d S%d Return=%d" NLP, current_disk, - PCX, current_track[current_disk], current_sector[current_disk], rtn); + sim_debug(VERBOSE_MSG, &dsk_dev, + "DSK%i: " ADDRESS_FORMAT " sim_fwrite failed T%d S%d Return=%d\n", + current_disk, PCX, current_track[current_disk], + current_sector[current_disk], rtn); } } else if ( (dsk_dev.dctrl & VERBOSE_MSG) && (warnLock[current_disk] < warnLevelDSK) ) { /* write locked - print warning message if required */ warnLock[current_disk]++; -/*05*/ printf("DSK%i: " ADDRESS_FORMAT " Attempt to write to locked DSK%d - ignored." NLP, - current_disk, PCX, current_disk); + sim_debug(VERBOSE_MSG, &dsk_dev, + "DSK%i: " ADDRESS_FORMAT " Attempt to write to locked DSK%d - ignored.\n", + current_disk, PCX, current_disk); } current_flag[current_disk] &= 0xfe; /* ENWD off */ current_byte[current_disk] = 0xff; @@ -381,8 +399,10 @@ int32 dsk10(const int32 port, const int32 io, const int32 data) { if (current_disk >= NUM_OF_DSK) { if ((dsk_dev.dctrl & VERBOSE_MSG) && (warnDSK10 < warnLevelDSK)) { warnDSK10++; -/*01*/ printf("DSK%i: " ADDRESS_FORMAT " Attempt of IN 0x08 on unattached disk - ignored." NLP, - current_disk, PCX); + sim_debug(VERBOSE_MSG, &dsk_dev, + "DSK%i: " ADDRESS_FORMAT + " Attempt of IN 0x08 on unattached disk - ignored.\n", + current_disk, PCX); } return 0xff; /* no drive selected - can do nothing */ } @@ -392,14 +412,16 @@ int32 dsk10(const int32 port, const int32 io, const int32 data) { /* OUT: Controller set/reset/enable/disable */ if (dirty) /* implies that current_disk < NUM_OF_DSK */ writebuf(); - TRACE_PRINT(OUT_MSG, ("DSK%i: " ADDRESS_FORMAT " OUT 0x08: %x" NLP, current_disk, PCX, data)); + sim_debug(OUT_MSG, &dsk_dev, "DSK%i: " ADDRESS_FORMAT " OUT 0x08: %x\n", current_disk, PCX, data); current_disk = data & NUM_OF_DSK_MASK; /* 0 <= current_disk < NUM_OF_DSK */ current_disk_flags = (dsk_dev.units + current_disk) -> flags; if ((current_disk_flags & UNIT_ATT) == 0) { /* nothing attached? */ if ( (dsk_dev.dctrl & VERBOSE_MSG) && (warnAttached[current_disk] < warnLevelDSK) ) { warnAttached[current_disk]++; -/*02*/ printf("DSK%i: " ADDRESS_FORMAT " Attempt to select unattached DSK%d - ignored." NLP, - current_disk, PCX, current_disk); + sim_debug(VERBOSE_MSG, &dsk_dev, + "DSK%i: " ADDRESS_FORMAT + " Attempt to select unattached DSK%d - ignored.\n", + current_disk, PCX, current_disk); } current_disk = NUM_OF_DSK; } @@ -407,8 +429,8 @@ int32 dsk10(const int32 port, const int32 io, const int32 data) { current_sector[current_disk] = 0xff; /* reset internal counters */ current_byte[current_disk] = 0xff; current_flag[current_disk] = data & 0x80 ? 0 /* disable drive */ : - (current_track[current_disk] == 0 ? 0x5a /* enable: head move true, track 0 if there */ : - 0x1a); /* enable: head move true */ + (current_track[current_disk] == 0 ? 0x5a /* enable: head move true, track 0 if there */ : + 0x1a); /* enable: head move true */ } return 0; /* ignored since OUT */ } @@ -419,8 +441,10 @@ int32 dsk11(const int32 port, const int32 io, const int32 data) { if (current_disk >= NUM_OF_DSK) { if ((dsk_dev.dctrl & VERBOSE_MSG) && (warnDSK11 < warnLevelDSK)) { warnDSK11++; -/*03*/ printf("DSK%i: " ADDRESS_FORMAT " Attempt of %s 0x09 on unattached disk - ignored." NLP, - current_disk, PCX, selectInOut(io)); + sim_debug(VERBOSE_MSG, &dsk_dev, + "DSK%i: " ADDRESS_FORMAT + " Attempt of %s 0x09 on unattached disk - ignored.\n", + current_disk, PCX, selectInOut(io)); } return 0; /* no drive selected - can do nothing */ } @@ -430,10 +454,11 @@ int32 dsk11(const int32 port, const int32 io, const int32 data) { in9_count++; if ((dsk_dev.dctrl & SECTOR_STUCK_MSG) && (in9_count > 2 * DSK_SECT) && (!in9_message)) { in9_message = TRUE; - printf("DSK%i: " ADDRESS_FORMAT " Looping on sector find." NLP, - current_disk, PCX); + sim_debug(SECTOR_STUCK_MSG, &dsk_dev, + "DSK%i: " ADDRESS_FORMAT " Looping on sector find.\n", + current_disk, PCX); } - TRACE_PRINT(IN_MSG, ("DSK%i: " ADDRESS_FORMAT " IN 0x09" NLP, current_disk, PCX)); + sim_debug(IN_MSG, &dsk_dev, "DSK%i: " ADDRESS_FORMAT " IN 0x09\n", current_disk, PCX); if (dirty) /* implies that current_disk < NUM_OF_DSK */ writebuf(); if (current_flag[current_disk] & 0x04) { /* head loaded? */ @@ -442,7 +467,7 @@ int32 dsk11(const int32 port, const int32 io, const int32 data) { current_sector[current_disk] = 0; current_byte[current_disk] = 0xff; return (((current_sector[current_disk] << 1) & 0x3e) /* return 'sector true' bit = 0 (true) */ - | 0xc0); /* set on 'unused' bits */ + | 0xc0); /* set on 'unused' bits */ } else return 0; /* head not loaded - return 0 */ } @@ -450,12 +475,12 @@ int32 dsk11(const int32 port, const int32 io, const int32 data) { in9_count = 0; /* drive functions */ - TRACE_PRINT(OUT_MSG, ("DSK%i: " ADDRESS_FORMAT " OUT 0x09: %x" NLP, current_disk, PCX, data)); + sim_debug(OUT_MSG, &dsk_dev, "DSK%i: " ADDRESS_FORMAT " OUT 0x09: %x\n", current_disk, PCX, data); if (data & 0x01) { /* step head in */ - if ((dsk_dev.dctrl & TRACK_STUCK_MSG) && (current_track[current_disk] == (tracks[current_disk] - 1))) { - printf("DSK%i: " ADDRESS_FORMAT " Unnecessary step in." NLP, - current_disk, PCX); - } + if (current_track[current_disk] == (tracks[current_disk] - 1)) + sim_debug(TRACK_STUCK_MSG, &dsk_dev, + "DSK%i: " ADDRESS_FORMAT " Unnecessary step in.\n", + current_disk, PCX); current_track[current_disk]++; if (current_track[current_disk] > (tracks[current_disk] - 1)) current_track[current_disk] = (tracks[current_disk] - 1); @@ -466,9 +491,10 @@ int32 dsk11(const int32 port, const int32 io, const int32 data) { } if (data & 0x02) { /* step head out */ - if ((dsk_dev.dctrl & TRACK_STUCK_MSG) && (current_track[current_disk] == 0)) { - printf("DSK%i: " ADDRESS_FORMAT " Unnecessary step out." NLP, current_disk, PCX); - } + if (current_track[current_disk] == 0) + sim_debug(TRACK_STUCK_MSG, &dsk_dev, + "DSK%i: " ADDRESS_FORMAT " Unnecessary step out.\n", + current_disk, PCX); current_track[current_disk]--; if (current_track[current_disk] < 0) { current_track[current_disk] = 0; @@ -513,8 +539,10 @@ int32 dsk12(const int32 port, const int32 io, const int32 data) { if (current_disk >= NUM_OF_DSK) { if ((dsk_dev.dctrl & VERBOSE_MSG) && (warnDSK12 < warnLevelDSK)) { warnDSK12++; -/*04*/ printf("DSK%i: " ADDRESS_FORMAT " Attempt of %s 0x0a on unattached disk - ignored." NLP, - current_disk, PCX, selectInOut(io)); + sim_debug(VERBOSE_MSG, &dsk_dev, + "DSK%i: " ADDRESS_FORMAT + " Attempt of %s 0x0a on unattached disk - ignored.\n", + current_disk, PCX, selectInOut(io)); } return 0; } @@ -525,24 +553,29 @@ int32 dsk12(const int32 port, const int32 io, const int32 data) { if (io == 0) { if (current_byte[current_disk] >= DSK_SECTSIZE) { /* physically read the sector */ - TRACE_PRINT(READ_MSG, - ("DSK%i: " ADDRESS_FORMAT " IN 0x0a (READ) D%d T%d S%d" NLP, current_disk, - PCX, current_disk, current_track[current_disk], current_sector[current_disk])); + sim_debug(READ_MSG, &dsk_dev, + "DSK%i: " ADDRESS_FORMAT " IN 0x0a (READ) D%d T%d S%d\n", + current_disk, PCX, current_disk, + current_track[current_disk], current_sector[current_disk]); for (i = 0; i < DSK_SECTSIZE; i++) dskbuf[i] = 0; if (dskseek(uptr)) { if ((dsk_dev.dctrl & VERBOSE_MSG) && (warnDSK12 < warnLevelDSK)) { warnDSK12++; - printf("DSK%i: " ADDRESS_FORMAT " fseek error D%d T%d S%d" NLP, current_disk, - PCX, current_disk, current_track[current_disk], current_sector[current_disk]); + sim_debug(VERBOSE_MSG, &dsk_dev, + "DSK%i: " ADDRESS_FORMAT " fseek error D%d T%d S%d\n", + current_disk, PCX, current_disk, + current_track[current_disk], current_sector[current_disk]); } } rtn = sim_fread(dskbuf, 1, DSK_SECTSIZE, uptr -> fileref); if (rtn != DSK_SECTSIZE) { if ((dsk_dev.dctrl & VERBOSE_MSG) && (warnDSK12 < warnLevelDSK)) { warnDSK12++; - printf("DSK%i: " ADDRESS_FORMAT " sim_fread error D%d T%d S%d" NLP, current_disk, - PCX, current_disk, current_track[current_disk], current_sector[current_disk]); + sim_debug(VERBOSE_MSG, &dsk_dev, + "DSK%i: " ADDRESS_FORMAT " sim_fread error D%d T%d S%d\n", + current_disk, PCX, current_disk, + current_track[current_disk], current_sector[current_disk]); } } current_byte[current_disk] = 0; diff --git a/AltairZ80/altairz80_hdsk.c b/AltairZ80/altairz80_hdsk.c index e90bc90e..085b17e5 100644 --- a/AltairZ80/altairz80_hdsk.c +++ b/AltairZ80/altairz80_hdsk.c @@ -1,6 +1,6 @@ /* altairz80_hdsk.c: simulated hard disk device to increase capacity - Copyright (c) 2002-2010, Peter Schorn + Copyright (c) 2002-2011, Peter Schorn Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), @@ -248,10 +248,6 @@ static MTAB hdsk_mod[] = { { 0 } }; -#define TRACE_PRINT(level, args) if (hdsk_dev.dctrl & level) { \ - printf args; \ - } - /* Debug Flags */ static DEBTAB hdsk_dt[] = { { "READ", READ_MSG }, @@ -552,32 +548,37 @@ static t_stat hdsk_boot(int32 unitno, DEVICE *dptr) { static int32 checkParameters(void) { UNIT *uptr; if ((selectedDisk < 0) || (selectedDisk >= HDSK_NUMBER)) { - TRACE_PRINT(VERBOSE_MSG, ("HDSK%d: " ADDRESS_FORMAT " Disk %i does not exist, will use HDSK0 instead." NLP, - selectedDisk, PCX, selectedDisk)); + sim_debug(VERBOSE_MSG, &hdsk_dev, "HDSK%d: " ADDRESS_FORMAT + " Disk %i does not exist, will use HDSK0 instead.\n", + selectedDisk, PCX, selectedDisk); selectedDisk = 0; } uptr = &hdsk_dev.units[selectedDisk]; if ((hdsk_dev.units[selectedDisk].flags & UNIT_ATT) == 0) { - TRACE_PRINT(VERBOSE_MSG, ("HDSK%d: " ADDRESS_FORMAT " Disk %i is not attached." NLP, - selectedDisk, PCX, selectedDisk)); + sim_debug(VERBOSE_MSG, &hdsk_dev, "HDSK%d: " ADDRESS_FORMAT + " Disk %i is not attached.\n", selectedDisk, PCX, selectedDisk); return FALSE; /* cannot read or write */ } if ((selectedSector < 0) || (selectedSector >= uptr -> HDSK_SECTORS_PER_TRACK)) { - TRACE_PRINT(VERBOSE_MSG, ("HDSK%d: " ADDRESS_FORMAT " Constraint violation 0 <= Sector=%02d < %d, will use sector 0 instead." NLP, - selectedDisk, PCX, selectedSector, uptr -> HDSK_SECTORS_PER_TRACK)); + sim_debug(VERBOSE_MSG, &hdsk_dev, "HDSK%d: " ADDRESS_FORMAT + " Constraint violation 0 <= Sector=%02d < %d, will use sector 0 instead.\n", + selectedDisk, PCX, selectedSector, uptr -> HDSK_SECTORS_PER_TRACK); selectedSector = 0; } if ((selectedTrack < 0) || (selectedTrack >= uptr -> HDSK_NUMBER_OF_TRACKS)) { - TRACE_PRINT(VERBOSE_MSG, ("HDSK%d: " ADDRESS_FORMAT " Constraint violation 0 <= Track=%04d < %04d, will use track 0 instead." NLP, - selectedDisk, PCX, selectedTrack, uptr -> HDSK_NUMBER_OF_TRACKS)); + sim_debug(VERBOSE_MSG, &hdsk_dev, "HDSK%d: " ADDRESS_FORMAT + " Constraint violation 0 <= Track=%04d < %04d, will use track 0 instead.\n", + selectedDisk, PCX, selectedTrack, uptr -> HDSK_NUMBER_OF_TRACKS); selectedTrack = 0; } selectedDMA &= ADDRMASK; - if ((hdsk_dev.dctrl & READ_MSG) && (hdskLastCommand == HDSK_READ)) - printf("HDSK%d " ADDRESS_FORMAT " Read Track=%04d Sector=%02d Len=%04d DMA=%04x" NLP, + if (hdskLastCommand == HDSK_READ) + sim_debug(READ_MSG, &hdsk_dev, "HDSK%d " ADDRESS_FORMAT + " Read Track=%04d Sector=%02d Len=%04d DMA=%04x\n", selectedDisk, PCX, selectedTrack, selectedSector, uptr -> HDSK_SECTOR_SIZE, selectedDMA); - if ((hdsk_dev.dctrl & WRITE_MSG) && (hdskLastCommand == HDSK_WRITE)) - printf("HDSK%d " ADDRESS_FORMAT " Write Track=%04d Sector=%02d Len=%04d DMA=%04x" NLP, + if (hdskLastCommand == HDSK_WRITE) + sim_debug(WRITE_MSG, &hdsk_dev, "HDSK%d " ADDRESS_FORMAT + " Write Track=%04d Sector=%02d Len=%04d DMA=%04x\n", selectedDisk, PCX, selectedTrack, selectedSector, uptr -> HDSK_SECTOR_SIZE, selectedDMA); return TRUE; } @@ -592,8 +593,9 @@ static int32 doSeek(void) { if (sim_fseek(uptr -> fileref, sectorSize * (uptr -> HDSK_SECTORS_PER_TRACK * selectedTrack + hostSector) + dpb[uptr -> HDSK_FORMAT_TYPE].offset, SEEK_SET)) { - TRACE_PRINT(VERBOSE_MSG, ("HDSK%d: " ADDRESS_FORMAT " Could not access Sector=%02d[=%02d] Track=%04d." NLP, - selectedDisk, PCX, selectedSector, hostSector, selectedTrack)); + sim_debug(VERBOSE_MSG, &hdsk_dev, "HDSK%d: " ADDRESS_FORMAT + " Could not access Sector=%02d[=%02d] Track=%04d.\n", + selectedDisk, PCX, selectedSector, hostSector, selectedTrack); return CPM_ERROR; } return CPM_OK; @@ -611,8 +613,9 @@ static int32 doRead(void) { if (sim_fread(hdskbuf, 1, uptr -> HDSK_SECTOR_SIZE, uptr -> fileref) != (size_t)(uptr -> HDSK_SECTOR_SIZE)) { for (i = 0; i < uptr -> HDSK_SECTOR_SIZE; i++) hdskbuf[i] = CPM_EMPTY; - TRACE_PRINT(VERBOSE_MSG, ("HDSK%d: " ADDRESS_FORMAT " Could not read Sector=%02d Track=%04d." NLP, - selectedDisk, PCX, selectedSector, selectedTrack)); + sim_debug(VERBOSE_MSG, &hdsk_dev, "HDSK%d: " ADDRESS_FORMAT + " Could not read Sector=%02d Track=%04d.\n", + selectedDisk, PCX, selectedSector, selectedTrack); return CPM_OK; /* allows the creation of empty hard disks */ } for (i = 0; i < uptr -> HDSK_SECTOR_SIZE; i++) @@ -632,14 +635,16 @@ static int32 doWrite(void) { hdskbuf[i] = GetBYTEWrapper(selectedDMA + i); rtn = sim_fwrite(hdskbuf, 1, uptr -> HDSK_SECTOR_SIZE, uptr -> fileref); if (rtn != (size_t)(uptr -> HDSK_SECTOR_SIZE)) { - TRACE_PRINT(VERBOSE_MSG, ("HDSK%d: " ADDRESS_FORMAT " Could not write Sector=%02d Track=%04d Result=%d." NLP, - selectedDisk, PCX, selectedSector, selectedTrack, (int)rtn)); + sim_debug(VERBOSE_MSG, &hdsk_dev, "HDSK%d: " ADDRESS_FORMAT + " Could not write Sector=%02d Track=%04d Result=%zd.\n", + selectedDisk, PCX, selectedSector, selectedTrack, rtn); return CPM_ERROR; } } else { - TRACE_PRINT(VERBOSE_MSG, ("HDSK%d: " ADDRESS_FORMAT " Could not write to locked disk Sector=%02d Track=%04d." NLP, - selectedDisk, PCX, selectedSector, selectedTrack)); + sim_debug(VERBOSE_MSG, &hdsk_dev, "HDSK%d: " ADDRESS_FORMAT + " Could not write to locked disk Sector=%02d Track=%04d.\n", + selectedDisk, PCX, selectedSector, selectedTrack); return CPM_ERROR; } return CPM_OK; @@ -660,8 +665,9 @@ static int32 hdsk_in(const int32 port) { hdskLastCommand = HDSK_NONE; return parameterBlock[parameterCount - 1]; } - TRACE_PRINT(VERBOSE_MSG, ("HDSK%d: " ADDRESS_FORMAT " Illegal IN command detected (port=%03xh, cmd=%d, pos=%d)." NLP, - selectedDisk, PCX, port, hdskLastCommand, hdskCommandPosition)); + sim_debug(VERBOSE_MSG, &hdsk_dev, "HDSK%d: " ADDRESS_FORMAT + " Illegal IN command detected (port=%03xh, cmd=%d, pos=%d).\n", + selectedDisk, PCX, port, hdskLastCommand, hdskCommandPosition); return CPM_OK; } @@ -745,8 +751,9 @@ static int32 hdsk_out(const int32 port, const int32 data) { if ((HDSK_RESET <= data) && (data <= HDSK_PARAM)) hdskLastCommand = data; else { - TRACE_PRINT(VERBOSE_MSG, ("HDSK%d: " ADDRESS_FORMAT " Illegal OUT command detected (port=%03xh, cmd=%d)." NLP, - selectedDisk, PCX, port, data)); + sim_debug(VERBOSE_MSG, &hdsk_dev, "HDSK%d: " ADDRESS_FORMAT + " Illegal OUT command detected (port=%03xh, cmd=%d).\n", + selectedDisk, PCX, port, data); hdskLastCommand = HDSK_RESET; } hdskCommandPosition = 0; diff --git a/AltairZ80/altairz80_net.c b/AltairZ80/altairz80_net.c index c4fa016c..fa5e5103 100644 --- a/AltairZ80/altairz80_net.c +++ b/AltairZ80/altairz80_net.c @@ -1,6 +1,6 @@ /* altairz80_net.c: networking capability - Copyright (c) 2002-2010, Peter Schorn + Copyright (c) 2002-2011, Peter Schorn Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), @@ -96,10 +96,6 @@ static MTAB net_mod[] = { { 0 } }; -#define TRACE_PRINT(level, args) if (net_dev.dctrl & level) { \ - printf args; \ - } - /* Debug Flags */ static DEBTAB net_dt[] = { { "ACCEPT", ACCEPT_MSG }, @@ -215,7 +211,7 @@ static t_stat net_svc(UNIT *uptr) { s = sim_accept_conn(serviceDescriptor[1].masterSocket, NULL); if (s != INVALID_SOCKET) { serviceDescriptor[i].ioSocket = s; - TRACE_PRINT(ACCEPT_MSG, ("NET: " ADDRESS_FORMAT " Accepted connection %i with socket %i." NLP, PCX, i, s)); + sim_debug(ACCEPT_MSG, &net_dev, "NET: " ADDRESS_FORMAT " Accepted connection %i with socket %i.\n", PCX, i, s); } } } @@ -232,8 +228,7 @@ static t_stat net_svc(UNIT *uptr) { r = sim_read_sock(serviceDescriptor[i].ioSocket, svcBuffer, BUFFER_LENGTH - serviceDescriptor[i].inputSize); if (r == -1) { - TRACE_PRINT(DROP_MSG, ("NET: " ADDRESS_FORMAT " Drop connection %i with socket %i." NLP, - PCX, i, serviceDescriptor[i].ioSocket)); + sim_debug(DROP_MSG, &net_dev, "NET: " ADDRESS_FORMAT " Drop connection %i with socket %i.\n", PCX, i, serviceDescriptor[i].ioSocket); sim_close_sock(serviceDescriptor[i].ioSocket, FALSE); serviceDescriptor[i].ioSocket = 0; serviceDescriptor_reset(i); @@ -303,8 +298,7 @@ int32 netData(const int32 port, const int32 io, const int32 data) { serviceDescriptor[i].inputPosRead = 0; serviceDescriptor[i].inputSize--; } - TRACE_PRINT(IN_MSG, ("NET: " ADDRESS_FORMAT " IN(%i)=%03xh (%c)" NLP, PCX, port, (result & 0xff), - (32 <= (result & 0xff)) && ((result & 0xff) <= 127) ? (result & 0xff) : '?')); + sim_debug(IN_MSG, &net_dev, "NET: " ADDRESS_FORMAT " IN(%i)=%03xh (%c)\n", PCX, port, (result & 0xff), (32 <= (result & 0xff)) && ((result & 0xff) <= 127) ? (result & 0xff) : '?'); return result; } else { /* OUT */ @@ -319,8 +313,7 @@ int32 netData(const int32 port, const int32 io, const int32 data) { serviceDescriptor[i].outputPosWrite = 0; serviceDescriptor[i].outputSize++; } - TRACE_PRINT(OUT_MSG, ("NET: " ADDRESS_FORMAT " OUT(%i)=%03xh (%c)" NLP, PCX, port, data, - (32 <= data) && (data <= 127) ? data : '?')); + sim_debug(OUT_MSG, &net_dev, "NET: " ADDRESS_FORMAT " OUT(%i)=%03xh (%c)\n", PCX, port, data, (32 <= data) && (data <= 127) ? data : '?'); return 0; } } diff --git a/AltairZ80/altairz80_sio.c b/AltairZ80/altairz80_sio.c index 6249546d..94a35f81 100644 --- a/AltairZ80/altairz80_sio.c +++ b/AltairZ80/altairz80_sio.c @@ -1,6 +1,6 @@ /* altairz80_sio.c: MITS Altair serial I/O card - Copyright (c) 2002-2010, Peter Schorn + Copyright (c) 2002-2011, Peter Schorn Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), @@ -62,6 +62,23 @@ #include #endif +uint8 *URLContents(const char *URL, uint32 *length); +#ifndef URL_READER_SUPPORT +#define RESULT_BUFFER_LENGTH 1024 +#define RESULT_LEAD_IN "URL is not supported on this platform. START URL \"" +#define RESULT_LEAD_OUT "\" URL END." +uint8 *URLContents(const char *URL, uint32 *length) { + char str[RESULT_BUFFER_LENGTH] = RESULT_LEAD_IN; + char *result; + strncat(str, URL, RESULT_BUFFER_LENGTH - strlen(RESULT_LEAD_IN) - strlen(RESULT_LEAD_OUT) - 1); + strcat(str, RESULT_LEAD_OUT); + result = malloc(strlen(str)); + strcpy(result, str); + *length = strlen(str); + return (uint8*)result; +} +#endif + /* Debug flags */ #define IN_MSG (1 << 0) #define OUT_MSG (1 << 1) @@ -143,6 +160,8 @@ extern uint32 getCommon(void); extern uint8 GetBYTEWrapper(const uint32 Addr); extern uint32 sim_map_resource(uint32 baseaddr, uint32 size, uint32 resource_type, int32 (*routine)(const int32, const int32, const int32), uint8 unmap); +extern uint32 getClockFrequency(void); +extern void setClockFrequency(const uint32 Value); extern int32 chiptype; extern const t_bool rtc_avail; @@ -154,10 +173,6 @@ extern UNIT cpu_unit; extern volatile int32 stop_cpu; extern int32 sim_interval; -#define TRACE_PRINT(device, level, args) if (device.dctrl & level) { \ - printf args; \ - } - /* Debug Flags */ static DEBTAB generic_dt[] = { { "IN", IN_MSG }, @@ -213,6 +228,11 @@ static int32 lastCPMStatus = 0; /* result of last attachCPM comm static int32 lastCommand = 0; /* most recent command processed on port 0xfeh */ static int32 getCommonPos = 0; /* determines state for sending the 'common' register */ +/* CPU Clock Frequency related */ +static uint32 newClockFrequency; +static int32 setClockFrequencyPos = 0; /* determines state for sending the clock frequency */ +static int32 getClockFrequencyPos = 0; /* determines state for receiving the clock frequency */ + /* support for wild card expansion */ #if UNIX_PLATFORM static glob_t globS; @@ -437,7 +457,7 @@ static void pollConnection(void) { /* reset routines */ static t_stat sio_reset(DEVICE *dptr) { int32 i; - TRACE_PRINT(sio_dev, VERBOSE_MSG, ("SIO: " ADDRESS_FORMAT " Reset" NLP, PCX)); + sim_debug(VERBOSE_MSG, &sio_dev, "SIO: " ADDRESS_FORMAT " Reset\n", PCX); sio_unit.u3 = FALSE; /* no character in terminal input buffer */ sio_unit.buf = 0; resetSIOWarningFlags(); @@ -452,7 +472,7 @@ static t_stat sio_reset(DEVICE *dptr) { } static t_stat ptr_reset(DEVICE *dptr) { - TRACE_PRINT(ptr_dev, VERBOSE_MSG, ("PTR: " ADDRESS_FORMAT " Reset" NLP, PCX)); + sim_debug(VERBOSE_MSG, &ptr_dev, "PTR: " ADDRESS_FORMAT " Reset\n", PCX); resetSIOWarningFlags(); ptr_unit.u3 = FALSE; /* End Of File not yet reached */ ptr_unit.buf = 0; @@ -464,7 +484,7 @@ static t_stat ptr_reset(DEVICE *dptr) { } static t_stat ptp_reset(DEVICE *dptr) { - TRACE_PRINT(ptp_dev, VERBOSE_MSG, ("PTP: " ADDRESS_FORMAT " Reset" NLP, PCX)); + sim_debug(VERBOSE_MSG, &ptp_dev, "PTP: " ADDRESS_FORMAT " Reset\n", PCX); resetSIOWarningFlags(); sim_map_resource(0x12, 1, RESOURCE_TYPE_IO, &sio1s, dptr->flags & DEV_DIS); sim_map_resource(0x13, 1, RESOURCE_TYPE_IO, &sio1d, dptr->flags & DEV_DIS); @@ -506,10 +526,10 @@ typedef struct { int32 sio_can_read; /* bit mask to indicate that one can read from this port */ int32 sio_cannot_read; /* bit mask to indicate that one cannot read from this port */ int32 sio_can_write; /* bit mask to indicate that one can write to this port */ - t_bool hasReset; /* TRUE iff SIO has reset command */ + int32 hasReset; /* TRUE iff SIO has reset command */ int32 sio_reset; /* reset command */ - t_bool hasOUT; /* TRUE iff port supports OUT command */ - t_bool isBuiltin; /* TRUE iff mapping is built in */ + int32 hasOUT; /* TRUE iff port supports OUT command */ + int32 isBuiltin; /* TRUE iff mapping is built in */ } SIO_PORT_INFO; static SIO_PORT_INFO port_table[PORT_TABLE_SIZE] = { @@ -677,18 +697,20 @@ static int32 sio0sCore(const int32 port, const int32 io, const int32 data) { if (spi.hasReset && (data == spi.sio_reset)) { /* reset command */ if (!sio_unit.u4) /* only reset for regular console I/O */ sio_unit.u3 = FALSE; /* indicate that no character is available */ - TRACE_PRINT(sio_dev, CMD_MSG, - ("\tSIO_S: " ADDRESS_FORMAT " Command OUT(0x%03x) = 0x%02x" NLP, PCX, port, data)); + sim_debug(CMD_MSG, &sio_dev, "\tSIO_S: " ADDRESS_FORMAT + " Command OUT(0x%03x) = 0x%02x\n", PCX, port, data); } return 0x00; /* ignored since OUT */ } int32 sio0s(const int32 port, const int32 io, const int32 data) { const int32 result = sio0sCore(port, io, data); - if ((io == 0) && (sio_dev.dctrl & IN_MSG)) - printf("\tSIO_S: " ADDRESS_FORMAT " IN(0x%03x) = 0x%02x" NLP, PCX, port, result); - else if ((io) && (sio_dev.dctrl & OUT_MSG)) - printf("\tSIO_S: " ADDRESS_FORMAT " OUT(0x%03x) = 0x%02x" NLP, PCX, port, data); + if (io == 0) + sim_debug(IN_MSG, &sio_dev, "\tSIO_S: " ADDRESS_FORMAT + " IN(0x%03x) = 0x%02x\n", PCX, port, result); + else if (io) + sim_debug(OUT_MSG, &sio_dev, "\tSIO_S: " ADDRESS_FORMAT + " OUT(0x%03x) = 0x%02x\n", PCX, port, data); return result; } @@ -701,8 +723,9 @@ static int32 sio0dCore(const int32 port, const int32 io, const int32 data) { if (io == 0) { /* IN */ if ((sio_unit.flags & UNIT_ATT) && (!sio_unit.u4)) return mapCharacter(tmxr_getc_ln(&TerminalLines[spi.terminalLine])); - if ((!sio_unit.u3) && (sio_dev.dctrl & BUFFER_EMPTY_MSG)) - printf("\tSIO_D: " ADDRESS_FORMAT " IN(0x%03x) for empty character buffer" NLP, PCX, port); + if (!sio_unit.u3) + sim_debug(BUFFER_EMPTY_MSG, &sio_dev, "\tSIO_D: " ADDRESS_FORMAT + " IN(0x%03x) for empty character buffer\n", PCX, port); sio_unit.u3 = FALSE; /* no character is available any more */ return mapCharacter(sio_unit.buf); /* return previous character */ } /* OUT follows, no fall-through from IN */ @@ -730,10 +753,12 @@ static char* printable(char* result, int32 data, const int32 isIn) { int32 sio0d(const int32 port, const int32 io, const int32 data) { char buffer[8]; const int32 result = sio0dCore(port, io, data); - if ((io == 0) && (sio_dev.dctrl & IN_MSG)) - printf("\tSIO_D: " ADDRESS_FORMAT " IN(0x%03x) = 0x%02x%s" NLP, PCX, port, result, printable(buffer, result, TRUE)); - else if ((io) && (sio_dev.dctrl & OUT_MSG)) - printf("\tSIO_D: " ADDRESS_FORMAT " OUT(0x%03x) = 0x%02x%s" NLP, PCX, port, data, printable(buffer, data, FALSE)); + if (io == 0) + sim_debug(IN_MSG, &sio_dev, "\tSIO_D: " ADDRESS_FORMAT + " IN(0x%03x) = 0x%02x%s\n", PCX, port, result, printable(buffer, result, TRUE)); + else if (io) + sim_debug(OUT_MSG, &sio_dev, "\tSIO_D: " ADDRESS_FORMAT + " OUT(0x%03x) = 0x%02x%s\n", PCX, port, data, printable(buffer, data, FALSE)); return result; } @@ -746,7 +771,8 @@ static int32 sio1sCore(const int32 port, const int32 io, const int32 data) { if ((ptr_unit.flags & UNIT_ATT) == 0) { /* PTR is not attached */ if ((ptr_dev.dctrl & VERBOSE_MSG) && (warnUnattachedPTR < warnLevelSIO)) { warnUnattachedPTR++; -/*06*/ printf("PTR: " ADDRESS_FORMAT " Attempt to test status of unattached PTR[0x%02x]. 0x02 returned." NLP, PCX, port); +/*06*/ sim_debug(VERBOSE_MSG, &ptr_dev, "PTR: " ADDRESS_FORMAT + " Attempt to test status of unattached PTR[0x%02x]. 0x02 returned.\n", PCX, port); } return SIO_CAN_WRITE; } @@ -756,18 +782,26 @@ static int32 sio1sCore(const int32 port, const int32 io, const int32 data) { } /* OUT follows */ if (data == SIO_RESET) { ptr_unit.u3 = FALSE; /* reset EOF indicator */ - TRACE_PRINT(ptr_dev, CMD_MSG, - ("PTR: " ADDRESS_FORMAT " Command OUT(0x%03x) = 0x%02x" NLP, PCX, port, data)); + sim_debug(CMD_MSG, &ptr_dev, "PTR: " ADDRESS_FORMAT + " Command OUT(0x%03x) = 0x%02x\n", PCX, port, data); } return 0x00; /* ignored since OUT */ } int32 sio1s(const int32 port, const int32 io, const int32 data) { const int32 result = sio1sCore(port, io, data); - if ((io == 0) && ((ptr_dev.dctrl & IN_MSG) || (ptp_dev.dctrl & IN_MSG))) - printf("PTP/PTR_S: " ADDRESS_FORMAT " IN(0x%02x) = 0x%02x" NLP, PCX, port, result); - else if ((io) && ((ptr_dev.dctrl & OUT_MSG) || (ptp_dev.dctrl & OUT_MSG))) - printf("PTP/PTR_S: " ADDRESS_FORMAT " OUT(0x%02x) = 0x%02x" NLP, PCX, port, data); + if (io == 0) { + sim_debug(IN_MSG, &ptr_dev, "PTR_S: " ADDRESS_FORMAT + " IN(0x%02x) = 0x%02x\n", PCX, port, result); + sim_debug(IN_MSG, &ptp_dev, "PTP_S: " ADDRESS_FORMAT + " IN(0x%02x) = 0x%02x\n", PCX, port, result); + } + else if (io) { + sim_debug(OUT_MSG, &ptr_dev, "PTR_S: " ADDRESS_FORMAT + " OUT(0x%02x) = 0x%02x\n", PCX, port, data); + sim_debug(OUT_MSG, &ptp_dev, "PTP_S: " ADDRESS_FORMAT + " OUT(0x%02x) = 0x%02x\n", PCX, port, data); + } return result; } @@ -778,14 +812,16 @@ static int32 sio1dCore(const int32 port, const int32 io, const int32 data) { if (ptr_unit.u3) { /* EOF reached, no more data available */ if ((ptr_dev.dctrl & VERBOSE_MSG) && (warnPTREOF < warnLevelSIO)) { warnPTREOF++; -/*07*/ printf("PTR: " ADDRESS_FORMAT " PTR[0x%02x] attempted to read past EOF. 0x00 returned." NLP, PCX, port); +/*07*/ sim_debug(VERBOSE_MSG, &ptr_dev, "PTR: " ADDRESS_FORMAT + " PTR[0x%02x] attempted to read past EOF. 0x00 returned.\n", PCX, port); } return 0x00; } if ((ptr_unit.flags & UNIT_ATT) == 0) { /* not attached */ if ((ptr_dev.dctrl & VERBOSE_MSG) && (warnUnattachedPTR < warnLevelSIO)) { warnUnattachedPTR++; -/*08*/ printf("PTR: " ADDRESS_FORMAT " Attempt to read from unattached PTR[0x%02x]. 0x00 returned." NLP, PCX, port); +/*08*/ sim_debug(VERBOSE_MSG, &ptr_dev, "PTR: " ADDRESS_FORMAT + " Attempt to read from unattached PTR[0x%02x]. 0x00 returned.\n", PCX, port); } return 0x00; } @@ -800,17 +836,26 @@ static int32 sio1dCore(const int32 port, const int32 io, const int32 data) { /* else ignore data */ else if ((ptp_dev.dctrl & VERBOSE_MSG) && (warnUnattachedPTP < warnLevelSIO)) { warnUnattachedPTP++; -/*09*/ printf("PTP: " ADDRESS_FORMAT " Attempt to output '0x%02x' to unattached PTP[0x%02x] - ignored." NLP, PCX, data, port); +/*09*/ sim_debug(VERBOSE_MSG, &ptp_dev, "PTP: " ADDRESS_FORMAT + " Attempt to output '0x%02x' to unattached PTP[0x%02x] - ignored.\n", PCX, data, port); } return 0x00; /* ignored since OUT */ } int32 sio1d(const int32 port, const int32 io, const int32 data) { const int32 result = sio1dCore(port, io, data); - if ((io == 0) && ((ptr_dev.dctrl & IN_MSG) || (ptp_dev.dctrl & IN_MSG))) - printf("PTP/PTR_D: " ADDRESS_FORMAT " IN(0x%02x) = 0x%02x" NLP, PCX, port, result); - else if ((io) && ((ptr_dev.dctrl & OUT_MSG) || (ptp_dev.dctrl & OUT_MSG))) - printf("PTP/PTR_D: " ADDRESS_FORMAT " OUT(0x%02x) = 0x%02x" NLP, PCX, port, data); + if (io == 0) { + sim_debug(IN_MSG, &ptr_dev, "PTR_D: " ADDRESS_FORMAT + " IN(0x%02x) = 0x%02x\n", PCX, port, result); + sim_debug(IN_MSG, &ptp_dev, "PTP_D: " ADDRESS_FORMAT + " IN(0x%02x) = 0x%02x\n", PCX, port, result); + } + else if (io) { + sim_debug(OUT_MSG, &ptr_dev, "PTR_D: " ADDRESS_FORMAT + " OUT(0x%02x) = 0x%02x\n", PCX, port, data); + sim_debug(OUT_MSG, &ptp_dev, "PTP_D: " ADDRESS_FORMAT + " OUT(0x%02x) = 0x%02x\n", PCX, port, data); + } return result; } @@ -962,9 +1007,13 @@ int32 nulldev(const int32 port, const int32 io, const int32 data) { if ((sio_unit.flags & UNIT_SIO_VERBOSE) && (warnUnassignedPort < warnLevelSIO)) { warnUnassignedPort++; if (io == 0) - printf("SIO: " ADDRESS_FORMAT " Attempt to input from unassigned port 0x%04x - ignored." NLP, PCX, port); + sim_debug(VERBOSE_MSG, &sio_dev, "SIO: " ADDRESS_FORMAT + " Attempt to input from unassigned port 0x%04x - ignored.\n", + PCX, port); else - printf("SIO: " ADDRESS_FORMAT " Attempt to output 0x%02x to unassigned port 0x%04x - ignored." NLP, PCX, data, port); + sim_debug(VERBOSE_MSG, &sio_dev, "SIO: " ADDRESS_FORMAT + " Attempt to output 0x%02x to unassigned port 0x%04x - ignored.\n", + PCX, data, port); } return io == 0 ? 0xff : 0; } @@ -1010,7 +1059,17 @@ static int32 fromBCD(const int32 x) { Note: The calling program must request all bytes of the result. Otherwise the pseudo device is left in an undefined state. - 4) Commands requiring parameters and returning results do not exist currently. + 4) For commands that do require parameters and return results + ld a, + out (0feh),a + ld a, + out (0feh),a + ld a, + out (0feh),a + ... ; send all parameters + in a,(0feh) ; contains first byte of result + in a,(0feh) ; contains second byte of result + ... */ @@ -1044,12 +1103,14 @@ enum simhPseudoDeviceCommands { /* do not change order or remove commands, add o readStopWatchCmd, /* 26 read the millisecond stop watch */ SIMHSleepCmd, /* 27 let SIMH sleep for SIMHSleep microseconds */ getHostOSPathSeparatorCmd, /* 28 obtain the file path separator of the OS under which SIMH runs */ - getHostFilenamesCmd /* 29 perform wildcard expansion and obtain list of file names */ + getHostFilenamesCmd, /* 29 perform wildcard expansion and obtain list of file names */ + readURLCmd, /* 30 read the contents of an URL */ + getCPUClockFrequency, /* 31 get the clock frequency of the CPU */ + setCPUClockFrequency, /* 32 set the clock frequency of the CPU */ + kSimhPseudoDeviceCommands }; -static int32 lastSIMHCommand = getHostFilenamesCmd; - -static char *cmdNames[] = { +static char *cmdNames[kSimhPseudoDeviceCommands] = { "printTime", "startTimer", "stopTimer", @@ -1079,7 +1140,10 @@ static char *cmdNames[] = { "readStopWatch", "SIMHSleep", "getHostOSPathSeparator", - "getHostFilenames" + "getHostFilenames", + "readURL", + "getCPUClockFrequency", + "setCPUClockFrequency", }; #define CPM_COMMAND_LINE_LENGTH 128 @@ -1087,7 +1151,16 @@ static char *cmdNames[] = { static uint32 markTime[TIMER_STACK_LIMIT]; /* timer stack */ static struct tm currentTime; static int32 currentTimeValid = FALSE; -static char version[] = "SIMH003"; +static char version[] = "SIMH004"; + +#define URL_MAX_LENGTH 1024 +static uint32 urlPointer; +static char urlStore[URL_MAX_LENGTH]; +static uint8 *urlResult = NULL; +static uint32 resultLength; +static uint32 resultPointer; +static int32 showAvailability; +static int32 isInReadPhase; static t_stat simh_dev_reset(DEVICE *dptr) { sim_map_resource(0xfe, 1, RESOURCE_TYPE_IO, &simh_dev, dptr->flags & DEV_DIS); @@ -1107,14 +1180,21 @@ static t_stat simh_dev_reset(DEVICE *dptr) { lastCommand = 0; lastCPMStatus = SCPE_OK; timerInterrupt = FALSE; + urlPointer = 0; + getClockFrequencyPos = 0; + setClockFrequencyPos = 0; + if (urlResult != NULL) { + free(urlResult); + urlResult = NULL; + } if (simh_unit.flags & UNIT_SIMH_TIMERON) simh_dev_set_timeron(NULL, 0, NULL, NULL); return SCPE_OK; } static void warnNoRealTimeClock(void) { - TRACE_PRINT(simh_device, VERBOSE_MSG, - ("SIMH: " ADDRESS_FORMAT " Sorry - no real time clock available." NLP, PCX)); + sim_debug(VERBOSE_MSG, &simh_device, "SIMH: " ADDRESS_FORMAT + " Sorry - no real time clock available.\n", PCX); } static t_stat simh_dev_set_timeron(UNIT *uptr, int32 value, char *cptr, void *desc) { @@ -1142,11 +1222,11 @@ static t_stat simh_svc(UNIT *uptr) { else { uint32 newTimeOfNextInterrupt = now + timerDelta - (now - timeOfNextInterrupt) % timerDelta; if (newTimeOfNextInterrupt != timeOfNextInterrupt + timerDelta) { - TRACE_PRINT(simh_device, VERBOSE_MSG, - ("SIMH: " ADDRESS_FORMAT " Timer interrupts skipped %i. Delta %i. Expect %i. Got %i." NLP, PCX, - (newTimeOfNextInterrupt - timeOfNextInterrupt) / timerDelta - 1, - timerDelta, - timeOfNextInterrupt + timerDelta - now, newTimeOfNextInterrupt - now)); + sim_debug(VERBOSE_MSG, &simh_device, "SIMH: " ADDRESS_FORMAT + " Timer interrupts skipped %i. Delta %i. Expect %i. Got %i.\n", + PCX, (newTimeOfNextInterrupt - timeOfNextInterrupt) / timerDelta - 1, + timerDelta, timeOfNextInterrupt + timerDelta - now, + newTimeOfNextInterrupt - now); } timeOfNextInterrupt = newTimeOfNextInterrupt; } @@ -1187,8 +1267,10 @@ static void attachCPM(UNIT *uptr) { /* 'C' option makes sure that file is properly truncated if it had existed before */ sim_quiet = sim_switches & SWMASK ('Q'); /* -q means quiet */ lastCPMStatus = attach_unit(uptr, cpmCommandLine); - if ((lastCPMStatus != SCPE_OK) && (simh_device.dctrl & VERBOSE_MSG)) - printf("SIMH: " ADDRESS_FORMAT " Cannot open '%s' (%s)." NLP, PCX, cpmCommandLine, sim_error_text(lastCPMStatus)); + if (lastCPMStatus != SCPE_OK) + sim_debug(VERBOSE_MSG, &simh_device, "SIMH: " ADDRESS_FORMAT + " Cannot open '%s' (%s).\n", PCX, cpmCommandLine, + sim_error_text(lastCPMStatus)); } /* setClockZSDOSAdr points to 6 byte block in M: YY MM DD HH MM SS in BCD notation */ @@ -1234,6 +1316,25 @@ static void setClockCPM3(void) { static int32 simh_in(const int32 port) { int32 result = 0; switch(lastCommand) { + case readURLCmd: + if (isInReadPhase) { + if (showAvailability) { + if (resultPointer < resultLength) + result = 1; + else { + if (urlResult != NULL) + free(urlResult); + urlResult = NULL; + lastCommand = 0; + } + } + else if (resultPointer < resultLength) + result = urlResult[resultPointer++]; + showAvailability = 1 - showAvailability; + } + else + lastCommand = 0; + break; case getHostFilenamesCmd: #if UNIX_PLATFORM @@ -1358,8 +1459,8 @@ static int32 simh_in(const int32 port) { result = getBankSelect(); else { result = 0; - TRACE_PRINT(simh_device, VERBOSE_MSG, - ("SIMH: " ADDRESS_FORMAT " Get selected bank ignored for non-banked memory." NLP, PCX)); + sim_debug(VERBOSE_MSG, &simh_device, "SIMH: " ADDRESS_FORMAT + " Get selected bank ignored for non-banked memory.\n", PCX); } lastCommand = 0; break; @@ -1375,6 +1476,17 @@ static int32 simh_in(const int32 port) { } break; + case getCPUClockFrequency: + if (getClockFrequencyPos == 0) { + result = getClockFrequency() & 0xff; + getClockFrequencyPos = 1; + } + else { + result = (getClockFrequency() >> 8) & 0xff; + getClockFrequencyPos = lastCommand = 0; + } + break; + case hasBankedMemoryCmd: result = cpu_unit.flags & UNIT_CPU_BANKED ? MAXBANKS : 0; lastCommand = 0; @@ -1402,9 +1514,9 @@ static int32 simh_in(const int32 port) { break; default: - TRACE_PRINT(simh_device, VERBOSE_MSG, - ("SIMH: " ADDRESS_FORMAT " Undefined IN from SIMH pseudo device on port %03xh ignored." NLP, - PCX, port)); + sim_debug(VERBOSE_MSG, &simh_device, "SIMH: " ADDRESS_FORMAT + " Undefined IN from SIMH pseudo device on port %03xh ignored.\n", + PCX, port); result = lastCommand = 0; } return result; @@ -1427,7 +1539,26 @@ void do_SIMH_sleep(void) { static int32 simh_out(const int32 port, const int32 data) { time_t now; switch(lastCommand) { - + case readURLCmd: + if (isInReadPhase) + lastCommand = 0; + else { + if (data) { + if (urlPointer < URL_MAX_LENGTH - 1) + urlStore[urlPointer++] = data & 0xff; + } + else { + if (urlResult != NULL) + free(urlResult); + urlStore[urlPointer] = 0; + urlResult = URLContents(urlStore, &resultLength); + urlPointer = resultPointer = 0; + showAvailability = 1; + isInReadPhase = TRUE; + } + } + break; + case setClockZSDOSCmd: if (setClockZSDOSPos == 0) { setClockZSDOSAdr = data; @@ -1439,7 +1570,7 @@ static int32 simh_out(const int32 port, const int32 data) { setClockZSDOSPos = lastCommand = 0; } break; - + case setClockCPM3Cmd: if (setClockCPM3Pos == 0) { setClockCPM3Adr = data; @@ -1451,18 +1582,28 @@ static int32 simh_out(const int32 port, const int32 data) { setClockCPM3Pos = lastCommand = 0; } break; - + + case setCPUClockFrequency: + if (setClockFrequencyPos == 0) { + newClockFrequency = data; + setClockFrequencyPos = 1; + } + else { + setClockFrequency((data << 8) | newClockFrequency); + setClockFrequencyPos = lastCommand = 0; + } + break; + case setBankSelectCmd: if (cpu_unit.flags & UNIT_CPU_BANKED) setBankSelect(data & BANKMASK); - else { - TRACE_PRINT(simh_device, VERBOSE_MSG, - ("SIMH: " ADDRESS_FORMAT " Set selected bank to %i ignored for non-banked memory." - NLP, PCX, data & 3)); - } + else + sim_debug(VERBOSE_MSG, &simh_device, "SIMH: " ADDRESS_FORMAT + " Set selected bank to %i ignored for non-banked memory.\n", + PCX, data & 3); lastCommand = 0; break; - + case setTimerDeltaCmd: if (setTimerDeltaPos == 0) { timerDelta = data; @@ -1473,13 +1614,13 @@ static int32 simh_out(const int32 port, const int32 data) { setTimerDeltaPos = lastCommand = 0; if (timerDelta == 0) { timerDelta = DEFAULT_TIMER_DELTA; - TRACE_PRINT(simh_device, VERBOSE_MSG, - ("SIMH: " ADDRESS_FORMAT " Timer delta set to 0 ms ignored. Using %i ms instead." - NLP, PCX, DEFAULT_TIMER_DELTA)); + sim_debug(VERBOSE_MSG, &simh_device, "SIMH: " ADDRESS_FORMAT + " Timer delta set to 0 ms ignored. Using %i ms instead.\n", + PCX, DEFAULT_TIMER_DELTA); } } break; - + case setTimerInterruptAdrCmd: if (setTimerInterruptAdrPos == 0) { timerInterruptHandler = data; @@ -1490,15 +1631,21 @@ static int32 simh_out(const int32 port, const int32 data) { setTimerInterruptAdrPos = lastCommand = 0; } break; - - default: - TRACE_PRINT(simh_device, CMD_MSG, - ("SIMH: " ADDRESS_FORMAT " CMD(0x%02x) <- %i (0x%02x, '%s')" NLP, PCX, port, data, data, - (0 <= data) && (data <= lastSIMHCommand) ? cmdNames[data] : "Unknown command")); - + + default: /* lastCommand not yet set */ + sim_debug(CMD_MSG, &simh_device, "SIMH: " ADDRESS_FORMAT + " CMD(0x%02x) <- %i (0x%02x, '%s')\n", + PCX, port, data, data, + (0 <= data) && (data < kSimhPseudoDeviceCommands) ? + cmdNames[data] : "Unknown command"); + lastCommand = data; switch(data) { - + case readURLCmd: + urlPointer = 0; + isInReadPhase = FALSE; + break; + case getHostFilenamesCmd: #if UNIX_PLATFORM if (!globValid) { @@ -1507,9 +1654,10 @@ static int32 simh_out(const int32 port, const int32 data) { createCPMCommandLine(); globError = glob(cpmCommandLine, GLOB_ERR, NULL, &globS); if (globError) { - TRACE_PRINT(simh_device, VERBOSE_MSG, - ("SIMH: " ADDRESS_FORMAT " Cannot expand '%s'. Error is %i." - NLP, PCX, cpmCommandLine, globError)); + sim_debug(VERBOSE_MSG, &simh_device, + "SIMH: " ADDRESS_FORMAT + " Cannot expand '%s'. Error is %i.\n", + PCX, cpmCommandLine, globError); globfree(&globS); globValid = FALSE; } @@ -1523,36 +1671,37 @@ static int32 simh_out(const int32 port, const int32 data) { setLastPathSeparator(); hFind = FindFirstFile(cpmCommandLine, &FindFileData); if (hFind == INVALID_HANDLE_VALUE) { - TRACE_PRINT(simh_device, VERBOSE_MSG, - ("SIMH: " ADDRESS_FORMAT " Cannot expand '%s'. Error is %lu." - NLP, PCX, cpmCommandLine, GetLastError())); + sim_debug(VERBOSE_MSG, &simh_device, + "SIMH: " ADDRESS_FORMAT + " Cannot expand '%s'. Error is %lu.\n", + PCX, cpmCommandLine, GetLastError()); globValid = FALSE; } } #endif break; - + case SIMHSleepCmd: do_SIMH_sleep(); break; - + case printTimeCmd: /* print time */ if (rtc_avail) printf("SIMH: " ADDRESS_FORMAT " Current time in milliseconds = %d." NLP, PCX, sim_os_msec()); else warnNoRealTimeClock(); break; - + case startTimerCmd: /* create a new timer on top of stack */ if (rtc_avail) if (markTimeSP < TIMER_STACK_LIMIT) markTime[markTimeSP++] = sim_os_msec(); else printf("SIMH: " ADDRESS_FORMAT " Timer stack overflow." NLP, PCX); - else - warnNoRealTimeClock(); + else + warnNoRealTimeClock(); break; - + case stopTimerCmd: /* stop timer on top of stack and show time difference */ if (rtc_avail) if (markTimeSP > 0) { @@ -1561,26 +1710,26 @@ static int32 simh_out(const int32 port, const int32 data) { } else printf("SIMH: " ADDRESS_FORMAT " No timer active." NLP, PCX); - else - warnNoRealTimeClock(); + else + warnNoRealTimeClock(); break; - + case resetPTRCmd: /* reset ptr device */ ptr_reset(&ptr_dev); break; - + case attachPTRCmd: /* attach ptr to the file with name at beginning of CP/M command line */ attachCPM(&ptr_unit); break; - + case detachPTRCmd: /* detach ptr */ detach_unit(&ptr_unit); break; - + case getSIMHVersionCmd: versionPos = 0; break; - + case getClockZSDOSCmd: time(&now); now += ClockZSDOSDelta; @@ -1588,11 +1737,11 @@ static int32 simh_out(const int32 port, const int32 data) { currentTimeValid = TRUE; getClockZSDOSPos = 0; break; - + case setClockZSDOSCmd: setClockZSDOSPos = 0; break; - + case getClockCPM3Cmd: time(&now); now += ClockCPM3Delta; @@ -1601,18 +1750,29 @@ static int32 simh_out(const int32 port, const int32 data) { daysCPM3SinceOrg = (int32) ((now - mkCPM3Origin()) / SECONDS_PER_DAY); getClockCPM3Pos = 0; break; - + case setClockCPM3Cmd: setClockCPM3Pos = 0; break; - + + case getCommonCmd: + getCommonPos = 0; + break; + + case getCPUClockFrequency: + getClockFrequencyPos = 0; + break; + + case setCPUClockFrequency: + setClockFrequencyPos = 0; + break; + case getBankSelectCmd: case setBankSelectCmd: - case getCommonCmd: case hasBankedMemoryCmd: case getHostOSPathSeparatorCmd: break; - + case resetSIMHInterfaceCmd: markTimeSP = 0; lastCommand = 0; @@ -1630,7 +1790,7 @@ static int32 simh_out(const int32 port, const int32 data) { } #endif break; - + case showTimerCmd: /* show time difference to timer on top of stack */ if (rtc_avail) if (markTimeSP > 0) { @@ -1639,60 +1799,60 @@ static int32 simh_out(const int32 port, const int32 data) { } else printf("SIMH: " ADDRESS_FORMAT " No timer active." NLP, PCX); - else - warnNoRealTimeClock(); + else + warnNoRealTimeClock(); break; - + case attachPTPCmd: /* attach ptp to the file with name at beginning of CP/M command line */ attachCPM(&ptp_unit); break; - + case detachPTPCmd: /* detach ptp */ detach_unit(&ptp_unit); break; - + case setZ80CPUCmd: chiptype = CHIP_TYPE_Z80; break; - + case set8080CPUCmd: chiptype = CHIP_TYPE_8080; break; - + case startTimerInterruptsCmd: if (simh_dev_set_timeron(NULL, 0, NULL, NULL) == SCPE_OK) { timerInterrupt = FALSE; simh_unit.flags |= UNIT_SIMH_TIMERON; } break; - + case stopTimerInterruptsCmd: simh_unit.flags &= ~UNIT_SIMH_TIMERON; simh_dev_set_timeroff(NULL, 0, NULL, NULL); break; - + case setTimerDeltaCmd: setTimerDeltaPos = 0; break; - + case setTimerInterruptAdrCmd: setTimerInterruptAdrPos = 0; break; - + case resetStopWatchCmd: stopWatchNow = rtc_avail ? sim_os_msec() : 0; break; - + case readStopWatchCmd: getStopWatchDeltaPos = 0; stopWatchDelta = rtc_avail ? sim_os_msec() - stopWatchNow : 0; break; - + default: - TRACE_PRINT(simh_device, CMD_MSG, - ("SIMH: " ADDRESS_FORMAT " Unknown command (%i) to SIMH pseudo device on port %03xh ignored." - NLP, PCX, data, port)); - } + sim_debug(CMD_MSG, &simh_device, "SIMH: " ADDRESS_FORMAT + " Unknown command (%i) to SIMH pseudo device on port %03xh ignored.\n", + PCX, data, port); + } } return 0x00; /* ignored, since OUT */ } @@ -1702,15 +1862,17 @@ int32 simh_dev(const int32 port, const int32 io, const int32 data) { int32 result = 0; if (io == 0) { result = simh_in(port); - TRACE_PRINT(simh_device, IN_MSG, - ("SIMH: " ADDRESS_FORMAT " IN(0x%02x) -> %i (0x%02x, '%c')" NLP, PCX, port, result, result, - (32 <= (result & 0xff)) && ((result & 0xff) <= 127) ? (result & 0xff) : '?')); + sim_debug(IN_MSG, &simh_device, "SIMH: " ADDRESS_FORMAT + " IN(0x%02x) -> %i (0x%02x, '%c')\n", PCX, + port, result, result, + (32 <= (result & 0xff)) && ((result & 0xff) <= 127) ? (result & 0xff) : '?'); } else { - TRACE_PRINT(simh_device, OUT_MSG, - ("SIMH: " ADDRESS_FORMAT " OUT(0x%02x) <- %i (0x%02x, '%c')" NLP, PCX, port, data, data, - (32 <= (data & 0xff)) && ((data & 0xff) <= 127) ? (data & 0xff) : '?')); + sim_debug(OUT_MSG, &simh_device, "SIMH: " ADDRESS_FORMAT + " OUT(0x%02x) <- %i (0x%02x, '%c')\n", PCX, + port, data, data, + (32 <= (data & 0xff)) && ((data & 0xff) <= 127) ? (data & 0xff) : '?'); simh_out(port, data); } return result; diff --git a/AltairZ80/altairz80_sys.c b/AltairZ80/altairz80_sys.c index f02b826f..6a4f8985 100644 --- a/AltairZ80/altairz80_sys.c +++ b/AltairZ80/altairz80_sys.c @@ -1,6 +1,6 @@ /* altairz80_sys.c: MITS Altair system interface - Copyright (c) 2002-2010, Peter Schorn + Copyright (c) 2002-2011, Peter Schorn Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), diff --git a/AltairZ80/i8272.c b/AltairZ80/i8272.c index 0d21de52..b02fa450 100644 --- a/AltairZ80/i8272.c +++ b/AltairZ80/i8272.c @@ -202,11 +202,6 @@ static MTAB i8272_mod[] = { { 0 } }; -#define TRACE_PRINT(level, args) if(i8272_dev.dctrl & level) { \ - printf args; \ - } - - /* Debug Flags */ static DEBTAB i8272_dt[] = { { "ERROR", ERROR_MSG }, @@ -427,26 +422,32 @@ uint8 I8272_Read(const uint32 Addr) cData |= ~I8272_MSR_FDC_BUSY; } #endif /* 0 hharte */ - TRACE_PRINT(STATUS_MSG, ("I8272: " ADDRESS_FORMAT " RD FDC MSR = 0x%02x" NLP, PCX, cData)); + sim_debug(STATUS_MSG, &i8272_dev, "I8272: " ADDRESS_FORMAT + " RD FDC MSR = 0x%02x\n", PCX, cData); break; case I8272_FDC_DATA: if(i8272_info->fdc_phase == DATA_PHASE) { cData = i8272_info->result[i8272_info->result_index]; - TRACE_PRINT(VERBOSE_MSG, ("I8272: " ADDRESS_FORMAT " RD Data, phase=%d, [%d]=0x%02x" NLP, PCX, i8272_info->fdc_phase, i8272_info->result_index, cData)); + sim_debug(VERBOSE_MSG, &i8272_dev, "I8272: " ADDRESS_FORMAT + " RD Data, phase=%d, [%d]=0x%02x\n", + PCX, i8272_info->fdc_phase, i8272_info->result_index, cData); i8272_irq = 0; i8272_info->result_index ++; if(i8272_info->result_index == i8272_info->result_len) { - TRACE_PRINT(VERBOSE_MSG, ("I8272: " ADDRESS_FORMAT " result phase complete." NLP, PCX)); + sim_debug(VERBOSE_MSG, &i8272_dev, "I8272: " ADDRESS_FORMAT + " result phase complete.\n", PCX); i8272_info->fdc_phase = CMD_PHASE; } } else { cData = i8272_info->result[0]; /* hack, in theory any value should be ok but this makes "format" work */ - TRACE_PRINT(VERBOSE_MSG, ("I8272: " ADDRESS_FORMAT " error, reading data register when not in data phase. " - "Returning 0x%02x" NLP, PCX, cData)); + sim_debug(VERBOSE_MSG, &i8272_dev, "I8272: " ADDRESS_FORMAT + " error, reading data register when not in data phase. " + "Returning 0x%02x\n", PCX, cData); } break; default: - TRACE_PRINT(VERBOSE_MSG, ("I8272: " ADDRESS_FORMAT " Cannot read register %x" NLP, PCX, Addr)); + sim_debug(VERBOSE_MSG, &i8272_dev, "I8272: " ADDRESS_FORMAT + " Cannot read register %x\n", PCX, Addr); cData = 0xFF; } @@ -475,8 +476,8 @@ static char *messages[0x20] = { uint8 I8272_Write(const uint32 Addr, uint8 cData) { I8272_DRIVE_INFO *pDrive; - uint32 flags = 0; - uint32 readlen; + unsigned int flags = 0; + unsigned int readlen; uint8 disk_read = 0; int32 i; @@ -488,19 +489,20 @@ uint8 I8272_Write(const uint32 Addr, uint8 cData) switch(Addr & 0x3) { case I8272_FDC_MSR: - TRACE_PRINT(WR_DATA_MSG, ("I8272: " ADDRESS_FORMAT " WR Drive Select Reg=%02x" NLP, - PCX, cData)); + sim_debug(WR_DATA_MSG, &i8272_dev, "I8272: " ADDRESS_FORMAT + " WR Drive Select Reg=%02x\n", PCX, cData); break; case I8272_FDC_DATA: i8272_info->fdc_msr &= 0xF0; - TRACE_PRINT(VERBOSE_MSG, ("I8272: " ADDRESS_FORMAT " WR Data, phase=%d, index=%d" NLP, - PCX, i8272_info->fdc_phase, i8272_info->cmd_index)); + sim_debug(VERBOSE_MSG, &i8272_dev, "I8272: " ADDRESS_FORMAT + " WR Data, phase=%d, index=%d\n", + PCX, i8272_info->fdc_phase, i8272_info->cmd_index); if(i8272_info->fdc_phase == CMD_PHASE) { i8272_info->cmd[i8272_info->cmd_index] = cData; if(i8272_info->cmd_index == 0) { - TRACE_PRINT(CMD_MSG, ("I8272: " ADDRESS_FORMAT " CMD=0x%02x[%s]" NLP, - PCX, cData & 0x1F, messages[cData & 0x1F])); + sim_debug(CMD_MSG, &i8272_dev, "I8272: " ADDRESS_FORMAT + " CMD=0x%02x[%s]\n", PCX, cData & 0x1F, messages[cData & 0x1F]); I8272_Setup_Cmd(cData & 0x1F); } i8272_info->cmd_index ++; @@ -537,14 +539,12 @@ uint8 I8272_Write(const uint32 Addr, uint8 cData) i8272_info->fdc_seek_end = 0; } if(pDrive->track != i8272_info->cmd[2]) { - TRACE_PRINT(CMD_MSG, ("I8272: " ADDRESS_FORMAT - " ERROR: CMD=0x%02x[%s]: Drive: %d, Command wants track %d, but positioner is on track %d." NLP, - PCX, - i8272_info->cmd[0] & 0x1F, - messages[i8272_info->cmd[0] & 0x1F], - i8272_info->sel_drive, - i8272_info->cmd[2], - pDrive->track)); + sim_debug(CMD_MSG, &i8272_dev, "I8272: " ADDRESS_FORMAT + " ERROR: CMD=0x%02x[%s]: Drive: %d, Command wants track %d, " + "but positioner is on track %d.\n", + PCX, i8272_info->cmd[0] & 0x1F, + messages[i8272_info->cmd[0] & 0x1F], + i8272_info->sel_drive, i8272_info->cmd[2], pDrive->track); } pDrive->track = i8272_info->cmd[2]; @@ -552,30 +552,31 @@ uint8 I8272_Write(const uint32 Addr, uint8 cData) i8272_info->fdc_sector = i8272_info->cmd[4]; i8272_info->fdc_sec_len = i8272_info->cmd[5]; if(i8272_info->fdc_sec_len > I8272_MAX_N) { - TRACE_PRINT(ERROR_MSG, ("I8272: " ADDRESS_FORMAT " Illegal sector size %d [N=%d]. Reset to %d [N=%d]." NLP, - PCX, 128 << i8272_info->fdc_sec_len, i8272_info->fdc_sec_len, - 128 << I8272_MAX_N, I8272_MAX_N)); + sim_debug(ERROR_MSG, &i8272_dev, "I8272: " ADDRESS_FORMAT + " Illegal sector size %d [N=%d]. Reset to %d [N=%d].\n", + PCX, 128 << i8272_info->fdc_sec_len, + i8272_info->fdc_sec_len, 128 << I8272_MAX_N, I8272_MAX_N); i8272_info->fdc_sec_len = I8272_MAX_N; } i8272_info->fdc_eot = i8272_info->cmd[6]; i8272_info->fdc_gpl = i8272_info->cmd[7]; i8272_info->fdc_dtl = i8272_info->cmd[8]; - TRACE_PRINT(CMD_MSG, ("I8272: " ADDRESS_FORMAT - " CMD=0x%02x[%s]: Drive: %d, %s %s, C=%d. H=%d. S=%d, N=%d, EOT=%02x, GPL=%02x, DTL=%02x" NLP, - PCX, - i8272_info->cmd[0] & 0x1F, - messages[i8272_info->cmd[0] & 0x1F], - i8272_info->sel_drive, - i8272_info->fdc_mt ? "Multi" : "Single", - i8272_info->fdc_mfm ? "MFM" : "FM", - pDrive->track, - i8272_info->fdc_head, - i8272_info->fdc_sector, - i8272_info->fdc_sec_len, - i8272_info->fdc_eot, - i8272_info->fdc_gpl, - i8272_info->fdc_dtl)); + sim_debug(CMD_MSG, &i8272_dev, "I8272: " ADDRESS_FORMAT + " CMD=0x%02x[%s]: Drive: %d, %s %s, C=%d. H=%d. S=%d, N=%d, " + "EOT=%02x, GPL=%02x, DTL=%02x\n", PCX, + i8272_info->cmd[0] & 0x1F, + messages[i8272_info->cmd[0] & 0x1F], + i8272_info->sel_drive, + i8272_info->fdc_mt ? "Multi" : "Single", + i8272_info->fdc_mfm ? "MFM" : "FM", + pDrive->track, + i8272_info->fdc_head, + i8272_info->fdc_sector, + i8272_info->fdc_sec_len, + i8272_info->fdc_eot, + i8272_info->fdc_gpl, + i8272_info->fdc_dtl); i8272_info->fdc_status[0] = (i8272_info->fdc_hds & 1) << 2; i8272_info->fdc_status[0] |= (i8272_info->sel_drive & 0x03); @@ -613,8 +614,9 @@ uint8 I8272_Write(const uint32 Addr, uint8 cData) /* READID to detect non-standard disk formats. */ i8272_info->fdc_sector = pDrive->imd->track[pDrive->track][i8272_info->fdc_hds].start_sector; if((i8272_info->fdc_sec_len == 0xF8) || (i8272_info->fdc_sec_len > I8272_MAX_N)) { /* Error calculating N or N too large */ - TRACE_PRINT(ERROR_MSG, ("I8272: " ADDRESS_FORMAT " Illegal sector size N=%d. Reset to 0." NLP, - PCX, i8272_info->fdc_sec_len)); + sim_debug(ERROR_MSG, &i8272_dev, "I8272: " ADDRESS_FORMAT + " Illegal sector size N=%d. Reset to 0.\n", + PCX, i8272_info->fdc_sec_len); i8272_info->fdc_sec_len = 0; return 0xFF; } @@ -642,8 +644,9 @@ uint8 I8272_Write(const uint32 Addr, uint8 cData) pDrive->track = 0; i8272_info->fdc_phase = CMD_PHASE; /* No result phase */ i8272_info->fdc_seek_end = 1; - TRACE_PRINT(SEEK_MSG, ("I8272: " ADDRESS_FORMAT " Recalibrate: Drive 0x%02x" NLP, - PCX, i8272_info->sel_drive)); + sim_debug(SEEK_MSG, &i8272_dev, "I8272: " ADDRESS_FORMAT + " Recalibrate: Drive 0x%02x\n", + PCX, i8272_info->sel_drive); break; case I8272_FORMAT_TRACK: /* FORMAT A TRACK */ i8272_info->fdc_mfm = (i8272_info->cmd[0] & 0x40) >> 6; @@ -662,25 +665,27 @@ uint8 I8272_Write(const uint32 Addr, uint8 cData) } i8272_info->fdc_sec_len = i8272_info->cmd[2]; if(i8272_info->fdc_sec_len > I8272_MAX_N) { - TRACE_PRINT(ERROR_MSG, ("I8272: " ADDRESS_FORMAT " Illegal sector size %d [N=%d]. Reset to %d [N=%d]." NLP, - PCX, 128 << i8272_info->fdc_sec_len, i8272_info->fdc_sec_len, - 128 << I8272_MAX_N, I8272_MAX_N)); + sim_debug(ERROR_MSG, &i8272_dev, "I8272: " ADDRESS_FORMAT + " Illegal sector size %d [N=%d]. Reset to %d [N=%d].\n", + PCX, 128 << i8272_info->fdc_sec_len, + i8272_info->fdc_sec_len, 128 << I8272_MAX_N, I8272_MAX_N); i8272_info->fdc_sec_len = I8272_MAX_N; } i8272_info->fdc_sc = i8272_info->cmd[3]; i8272_info->fdc_gpl = i8272_info->cmd[4]; i8272_info->fdc_fillbyte = i8272_info->cmd[5]; - TRACE_PRINT(FMT_MSG, ("I8272: " ADDRESS_FORMAT " Format Drive: %d, %s, C=%d. H=%d. N=%d, SC=%d, GPL=%02x, FILL=%02x" NLP, - PCX, - i8272_info->sel_drive, - i8272_info->fdc_mfm ? "MFM" : "FM", - pDrive->track, - i8272_info->fdc_head, - i8272_info->fdc_sec_len, - i8272_info->fdc_sc, - i8272_info->fdc_gpl, - i8272_info->fdc_fillbyte)); + sim_debug(FMT_MSG, &i8272_dev, "I8272: " ADDRESS_FORMAT + " Format Drive: %d, %s, C=%d. H=%d. N=%d, SC=%d, GPL=%02x, FILL=%02x\n", + PCX, + i8272_info->sel_drive, + i8272_info->fdc_mfm ? "MFM" : "FM", + pDrive->track, + i8272_info->fdc_head, + i8272_info->fdc_sec_len, + i8272_info->fdc_sc, + i8272_info->fdc_gpl, + i8272_info->fdc_fillbyte); i8272_info->fdc_status[0] = (i8272_info->fdc_hds & 1) << 2; i8272_info->fdc_status[0] |= (i8272_info->sel_drive & 0x03); @@ -698,7 +703,8 @@ uint8 I8272_Write(const uint32 Addr, uint8 cData) i8272_info->result[6] = i8272_info->fdc_sec_len; break; case I8272_SENSE_INTR_STATUS: /* SENSE INTERRUPT STATUS */ - TRACE_PRINT(CMD_MSG, ("I8272: " ADDRESS_FORMAT " Sense Interrupt Status" NLP, PCX)); + sim_debug(CMD_MSG, &i8272_dev, "I8272: " ADDRESS_FORMAT + " Sense Interrupt Status\n", PCX); i8272_info->result[0] = i8272_info->fdc_seek_end ? 0x20 : 0x00; /* SEEK_END */ i8272_info->result[0] |= i8272_info->sel_drive; i8272_info->result[1] = pDrive->track; @@ -710,12 +716,12 @@ uint8 I8272_Write(const uint32 Addr, uint8 cData) i8272_info->fdc_hlt = ((i8272_info->cmd[2] & 0xFE) >> 1) * 2; i8272_info->fdc_nd = (i8272_info->cmd[2] & 0x01); i8272_info->fdc_phase = CMD_PHASE; /* No result phase */ - TRACE_PRINT(CMD_MSG, ("I8272: " ADDRESS_FORMAT " Specify: SRT=%d, HUT=%d, HLT=%d, ND=%s" NLP, - PCX, - i8272_info->fdc_srt, - i8272_info->fdc_hut, - i8272_info->fdc_hlt, - i8272_info->fdc_nd ? "NON-DMA" : "DMA")); + sim_debug(CMD_MSG, &i8272_dev, "I8272: " ADDRESS_FORMAT + " Specify: SRT=%d, HUT=%d, HLT=%d, ND=%s\n", + PCX, i8272_info->fdc_srt, + i8272_info->fdc_hut, + i8272_info->fdc_hlt, + i8272_info->fdc_nd ? "NON-DMA" : "DMA"); break; case I8272_SENSE_DRIVE_STATUS: /* Setup Status3 Byte */ i8272_info->fdc_hds = (i8272_info->cmd[1] & 0x04) >> 2; @@ -735,8 +741,8 @@ uint8 I8272_Write(const uint32 Addr, uint8 cData) i8272_info->result[0] |= (i8272_info->fdc_hds & 1) << 2; i8272_info->result[0] |= (i8272_info->sel_drive & 0x03); i8272_info->result[0] |= (pDrive->track == 0) ? DRIVE_STATUS_TRACK0 : 0x00; /* Track 0 */ - TRACE_PRINT(CMD_MSG, ("I8272: " ADDRESS_FORMAT " Sense Drive Status = 0x%02x" NLP, - PCX, i8272_info->result[0])); + sim_debug(CMD_MSG, &i8272_dev, "I8272: " ADDRESS_FORMAT + " Sense Drive Status = 0x%02x\n", PCX, i8272_info->result[0]); break; case I8272_SEEK: /* SEEK */ i8272_info->fdc_mt = (i8272_info->cmd[0] & 0x80) >> 7; @@ -752,15 +758,15 @@ uint8 I8272_Write(const uint32 Addr, uint8 cData) pDrive->track = i8272_info->cmd[2]; i8272_info->fdc_head = i8272_info->fdc_hds; /*AGN seek should save the head */ i8272_info->fdc_seek_end = 1; - TRACE_PRINT(SEEK_MSG, ("I8272: " ADDRESS_FORMAT - " Seek Drive: %d, %s %s, C=%d. Skip Deleted Data=%s Head Select=%s" NLP, - PCX, - i8272_info->sel_drive, - i8272_info->fdc_mt ? "Multi" : "Single", - i8272_info->fdc_mfm ? "MFM" : "FM", - i8272_info->cmd[2], - i8272_info->fdc_sk ? "True" : "False", - i8272_info->fdc_hds ? "True" : "False")); + sim_debug(SEEK_MSG, &i8272_dev, "I8272: " ADDRESS_FORMAT + " Seek Drive: %d, %s %s, C=%d. Skip Deleted Data=%s Head Select=%s\n", + PCX, + i8272_info->sel_drive, + i8272_info->fdc_mt ? "Multi" : "Single", + i8272_info->fdc_mfm ? "MFM" : "FM", + i8272_info->cmd[2], + i8272_info->fdc_sk ? "True" : "False", + i8272_info->fdc_hds ? "True" : "False"); break; default: /* INVALID */ break; @@ -777,10 +783,11 @@ uint8 I8272_Write(const uint32 Addr, uint8 cData) case I8272_WRITE_DATA: case I8272_WRITE_DELETED_DATA: for(;i8272_info->fdc_sector<=i8272_info->fdc_eot;i8272_info->fdc_sector++) { - TRACE_PRINT(RD_DATA_MSG, ("I8272: " ADDRESS_FORMAT " %s Data, sector: %d sector len=%d" NLP, - PCX, disk_read ? "RD" : "WR", - i8272_info->fdc_sector, - 128 << i8272_info->fdc_sec_len)); + sim_debug(RD_DATA_MSG, &i8272_dev, "I8272: " ADDRESS_FORMAT + " %s Data, sector: %d sector len=%d\n", + PCX, disk_read ? "RD" : "WR", + i8272_info->fdc_sector, + 128 << i8272_info->fdc_sec_len); if(pDrive->imd == NULL) { printf(".imd is NULL!" NLP); @@ -799,20 +806,21 @@ uint8 I8272_Write(const uint32 Addr, uint8 cData) PutByteDMA(i8272_info->fdc_dma_addr, sdata.raw[i]); i8272_info->fdc_dma_addr++; } - TRACE_PRINT(RD_DATA_MSG, ("I8272: " ADDRESS_FORMAT " T:%d/H:%d/S:%d/L:%4d: Data transferred to RAM at 0x%06x" NLP, - PCX, - pDrive->track, - i8272_info->fdc_head, - i8272_info->fdc_sector, - 128 << i8272_info->fdc_sec_len, - i8272_info->fdc_dma_addr - i)); + sim_debug(RD_DATA_MSG, &i8272_dev, "I8272: " ADDRESS_FORMAT + " T:%d/H:%d/S:%d/L:%4d: Data transferred to RAM at 0x%06x\n", + PCX, pDrive->track, + i8272_info->fdc_head, + i8272_info->fdc_sector, + 128 << i8272_info->fdc_sec_len, + i8272_info->fdc_dma_addr - i); } else { /* Write */ for(i=0;i<(128 << i8272_info->fdc_sec_len);i++) { sdata.raw[i] = GetByteDMA(i8272_info->fdc_dma_addr); i8272_info->fdc_dma_addr++; } - TRACE_PRINT(WR_DATA_MSG, ("I8272: " ADDRESS_FORMAT " Data transferred from RAM at 0x%06x" NLP, - PCX, i8272_info->fdc_dma_addr)); + sim_debug(WR_DATA_MSG, &i8272_dev, "I8272: " ADDRESS_FORMAT + " Data transferred from RAM at 0x%06x\n", + PCX, i8272_info->fdc_dma_addr); sectWrite(pDrive->imd, pDrive->track, i8272_info->fdc_head, @@ -829,14 +837,12 @@ uint8 I8272_Write(const uint32 Addr, uint8 cData) break; case I8272_FORMAT_TRACK: /* FORMAT A TRACK */ for(i8272_info->fdc_sector = 1;i8272_info->fdc_sector<=i8272_info->fdc_sc;i8272_info->fdc_sector++) { - TRACE_PRINT(CMD_MSG, ("I8272: " ADDRESS_FORMAT " Format Track %d, Sector=%d, len=%d" NLP, - PCX, - pDrive->track, - i8272_info->fdc_sector, - 128 << i8272_info->fdc_sec_len)); + sim_debug(CMD_MSG, &i8272_dev, "I8272: " ADDRESS_FORMAT + " Format Track %d, Sector=%d, len=%d\n", PCX, pDrive->track, i8272_info->fdc_sector, 128 << i8272_info->fdc_sec_len); if(i8272_info->fdc_sectorcount >= I8272_MAX_SECTOR) { - TRACE_PRINT(ERROR_MSG, ("I8272: " ADDRESS_FORMAT " Illegal sector count" NLP, PCX)); + sim_debug(ERROR_MSG, &i8272_dev, "I8272: " ADDRESS_FORMAT + " Illegal sector count\n", PCX); i8272_info->fdc_sectorcount = 0; } i8272_info->fdc_sectormap[i8272_info->fdc_sectorcount] = i8272_info->fdc_sector; @@ -862,16 +868,20 @@ uint8 I8272_Write(const uint32 Addr, uint8 cData) case I8272_SCAN_LOW_EQUAL: /* SCAN LOW OR EQUAL */ case I8272_SCAN_HIGH_EQUAL: /* SCAN HIGH OR EQUAL */ case I8272_SCAN_EQUAL: /* SCAN EQUAL */ - TRACE_PRINT(CMD_MSG, ("I8272: " ADDRESS_FORMAT " Scan Data" NLP, - PCX)); - TRACE_PRINT(ERROR_MSG, ("I8272: " ADDRESS_FORMAT " ERROR: Scan not implemented." NLP, PCX)); + sim_debug(CMD_MSG, &i8272_dev, "I8272: " ADDRESS_FORMAT + " Scan Data\n", PCX); + sim_debug(ERROR_MSG, &i8272_dev, "I8272: " ADDRESS_FORMAT + " ERROR: Scan not implemented.\n", PCX); break; case I8272_READ_ID: /* READ ID */ - TRACE_PRINT(CMD_MSG, ("I8272: " ADDRESS_FORMAT - " READ ID Drive %d result ST0=%02x ST1=%02x ST2=%02x C=%d H=%d R=%02x N=%d" - NLP, PCX, i8272_info->sel_drive, i8272_info->result[0], - i8272_info->result[1],i8272_info->result[2],i8272_info->result[3], - i8272_info->result[4],i8272_info->result[5],i8272_info->result[6])); + sim_debug(CMD_MSG, &i8272_dev, "I8272: " ADDRESS_FORMAT + " READ ID Drive %d result ST0=%02x ST1=%02x ST2=%02x " + "C=%d H=%d R=%02x N=%d\n", PCX, + i8272_info->sel_drive, + i8272_info->result[0], i8272_info->result[1], + i8272_info->result[2], i8272_info->result[3], + i8272_info->result[4], i8272_info->result[5], + i8272_info->result[6]); break; default: @@ -956,7 +966,7 @@ extern void raise_disk1a_interrupt(void); static void raise_i8272_interrupt(void) { - TRACE_PRINT(IRQ_MSG, ("I8272: " ADDRESS_FORMAT " FDC Interrupt" NLP, PCX)); + sim_debug(IRQ_MSG, &i8272_dev, "I8272: " ADDRESS_FORMAT " FDC Interrupt\n", PCX); i8272_irq = 1; raise_disk1a_interrupt(); } diff --git a/AltairZ80/insnsa.c b/AltairZ80/insnsa.c deleted file mode 100644 index ba4d70d7..00000000 --- a/AltairZ80/insnsa.c +++ /dev/null @@ -1,4443 +0,0 @@ -/* This file auto-generated from insns.dat by insns.pl - don't edit it */ - -#include "nasm.h" -#include "insns.h" - -static struct itemplate instrux_AAA[] = { - {I_AAA, 0, {0,0,0}, "\1\x37", IF_8086}, - ITEMPLATE_END -}; - -static struct itemplate instrux_AAD[] = { - {I_AAD, 0, {0,0,0}, "\2\xD5\x0A", IF_8086}, - {I_AAD, 1, {IMMEDIATE,0,0}, "\1\xD5\24", IF_8086|IF_SB}, - ITEMPLATE_END -}; - -static struct itemplate instrux_AAM[] = { - {I_AAM, 0, {0,0,0}, "\2\xD4\x0A", IF_8086}, - {I_AAM, 1, {IMMEDIATE,0,0}, "\1\xD4\24", IF_8086|IF_SB}, - ITEMPLATE_END -}; - -static struct itemplate instrux_AAS[] = { - {I_AAS, 0, {0,0,0}, "\1\x3F", IF_8086}, - ITEMPLATE_END -}; - -static struct itemplate instrux_ADC[] = { - {I_ADC, 2, {MEMORY,REG8,0}, "\300\1\x10\101", IF_8086|IF_SM}, - {I_ADC, 2, {REG8,REG8,0}, "\1\x10\101", IF_8086}, - {I_ADC, 2, {MEMORY,REG16,0}, "\320\300\1\x11\101", IF_8086|IF_SM}, - {I_ADC, 2, {REG16,REG16,0}, "\320\1\x11\101", IF_8086}, - {I_ADC, 2, {MEMORY,REG32,0}, "\321\300\1\x11\101", IF_386|IF_SM}, - {I_ADC, 2, {REG32,REG32,0}, "\321\1\x11\101", IF_386}, - {I_ADC, 2, {REG8,MEMORY,0}, "\301\1\x12\110", IF_8086|IF_SM}, - {I_ADC, 2, {REG8,REG8,0}, "\1\x12\110", IF_8086}, - {I_ADC, 2, {REG16,MEMORY,0}, "\320\301\1\x13\110", IF_8086|IF_SM}, - {I_ADC, 2, {REG16,REG16,0}, "\320\1\x13\110", IF_8086}, - {I_ADC, 2, {REG32,MEMORY,0}, "\321\301\1\x13\110", IF_386|IF_SM}, - {I_ADC, 2, {REG32,REG32,0}, "\321\1\x13\110", IF_386}, - {I_ADC, 2, {REGMEM|BITS16,IMMEDIATE|BITS8,0}, "\320\300\1\x83\202\15", IF_8086}, - {I_ADC, 2, {REGMEM|BITS32,IMMEDIATE|BITS8,0}, "\321\300\1\x83\202\15", IF_386}, - {I_ADC, 2, {REG_AL,IMMEDIATE,0}, "\1\x14\21", IF_8086|IF_SM}, - {I_ADC, 2, {REG_AX,SBYTE,0}, "\320\1\x83\202\15", IF_8086|IF_SM}, - {I_ADC, 2, {REG_AX,IMMEDIATE,0}, "\320\1\x15\31", IF_8086|IF_SM}, - {I_ADC, 2, {REG_EAX,SBYTE,0}, "\321\1\x83\202\15", IF_386|IF_SM}, - {I_ADC, 2, {REG_EAX,IMMEDIATE,0}, "\321\1\x15\41", IF_386|IF_SM}, - {I_ADC, 2, {REGMEM|BITS8,IMMEDIATE,0}, "\300\1\x80\202\21", IF_8086|IF_SM}, - {I_ADC, 2, {REGMEM|BITS16,IMMEDIATE,0}, "\320\300\134\1\x81\202\131", IF_8086|IF_SM}, - {I_ADC, 2, {REGMEM|BITS32,IMMEDIATE,0}, "\321\300\144\1\x81\202\141", IF_386|IF_SM}, - {I_ADC, 2, {MEMORY,IMMEDIATE|BITS8,0}, "\300\1\x80\202\21", IF_8086|IF_SM}, - {I_ADC, 2, {MEMORY,IMMEDIATE|BITS16,0}, "\320\300\134\1\x81\202\131", IF_8086|IF_SM}, - {I_ADC, 2, {MEMORY,IMMEDIATE|BITS32,0}, "\321\300\144\1\x81\202\141", IF_386|IF_SM}, - ITEMPLATE_END -}; - -static struct itemplate instrux_ADD[] = { - {I_ADD, 2, {MEMORY,REG8,0}, "\300\17\101", IF_8086|IF_SM}, - {I_ADD, 2, {REG8,REG8,0}, "\17\101", IF_8086}, - {I_ADD, 2, {MEMORY,REG16,0}, "\320\300\1\x01\101", IF_8086|IF_SM}, - {I_ADD, 2, {REG16,REG16,0}, "\320\1\x01\101", IF_8086}, - {I_ADD, 2, {MEMORY,REG32,0}, "\321\300\1\x01\101", IF_386|IF_SM}, - {I_ADD, 2, {REG32,REG32,0}, "\321\1\x01\101", IF_386}, - {I_ADD, 2, {REG8,MEMORY,0}, "\301\1\x02\110", IF_8086|IF_SM}, - {I_ADD, 2, {REG8,REG8,0}, "\1\x02\110", IF_8086}, - {I_ADD, 2, {REG16,MEMORY,0}, "\320\301\1\x03\110", IF_8086|IF_SM}, - {I_ADD, 2, {REG16,REG16,0}, "\320\1\x03\110", IF_8086}, - {I_ADD, 2, {REG32,MEMORY,0}, "\321\301\1\x03\110", IF_386|IF_SM}, - {I_ADD, 2, {REG32,REG32,0}, "\321\1\x03\110", IF_386}, - {I_ADD, 2, {REGMEM|BITS16,IMMEDIATE|BITS8,0}, "\320\300\1\x83\200\15", IF_8086}, - {I_ADD, 2, {REGMEM|BITS32,IMMEDIATE|BITS8,0}, "\321\300\1\x83\200\15", IF_386}, - {I_ADD, 2, {REG_AL,IMMEDIATE,0}, "\1\x04\21", IF_8086|IF_SM}, - {I_ADD, 2, {REG_AX,SBYTE,0}, "\320\1\x83\200\15", IF_8086|IF_SM}, - {I_ADD, 2, {REG_AX,IMMEDIATE,0}, "\320\1\x05\31", IF_8086|IF_SM}, - {I_ADD, 2, {REG_EAX,SBYTE,0}, "\321\1\x83\200\15", IF_386|IF_SM}, - {I_ADD, 2, {REG_EAX,IMMEDIATE,0}, "\321\1\x05\41", IF_386|IF_SM}, - {I_ADD, 2, {REGMEM|BITS8,IMMEDIATE,0}, "\300\1\x80\200\21", IF_8086|IF_SM}, - {I_ADD, 2, {REGMEM|BITS16,IMMEDIATE,0}, "\320\300\134\1\x81\200\131", IF_8086|IF_SM}, - {I_ADD, 2, {REGMEM|BITS32,IMMEDIATE,0}, "\321\300\144\1\x81\200\141", IF_386|IF_SM}, - {I_ADD, 2, {MEMORY,IMMEDIATE|BITS8,0}, "\300\1\x80\200\21", IF_8086|IF_SM}, - {I_ADD, 2, {MEMORY,IMMEDIATE|BITS16,0}, "\320\300\134\1\x81\200\131", IF_8086|IF_SM}, - {I_ADD, 2, {MEMORY,IMMEDIATE|BITS32,0}, "\321\300\144\1\x81\200\141", IF_386|IF_SM}, - ITEMPLATE_END -}; - -static struct itemplate instrux_ADDPD[] = { - {I_ADDPD, 2, {XMMREG,XMMREG,0}, "\331\3\x66\x0F\x58\110", IF_WILLAMETTE|IF_SSE2}, - {I_ADDPD, 2, {XMMREG,MEMORY,0}, "\301\331\3\x66\x0F\x58\110", IF_WILLAMETTE|IF_SSE2|IF_SM}, - ITEMPLATE_END -}; - -static struct itemplate instrux_ADDPS[] = { - {I_ADDPS, 2, {XMMREG,MEMORY,0}, "\301\331\2\x0F\x58\110", IF_KATMAI|IF_SSE}, - {I_ADDPS, 2, {XMMREG,XMMREG,0}, "\331\2\x0F\x58\110", IF_KATMAI|IF_SSE}, - ITEMPLATE_END -}; - -static struct itemplate instrux_ADDSD[] = { - {I_ADDSD, 2, {XMMREG,XMMREG,0}, "\331\3\xF2\x0F\x58\110", IF_WILLAMETTE|IF_SSE2}, - {I_ADDSD, 2, {XMMREG,MEMORY,0}, "\301\331\3\xF2\x0F\x58\110", IF_WILLAMETTE|IF_SSE2}, - ITEMPLATE_END -}; - -static struct itemplate instrux_ADDSS[] = { - {I_ADDSS, 2, {XMMREG,MEMORY,0}, "\301\333\2\x0F\x58\110", IF_KATMAI|IF_SSE}, - {I_ADDSS, 2, {XMMREG,XMMREG,0}, "\333\2\x0F\x58\110", IF_KATMAI|IF_SSE}, - ITEMPLATE_END -}; - -static struct itemplate instrux_ADDSUBPD[] = { - {I_ADDSUBPD, 2, {XMMREG,MEMORY,0}, "\301\3\x66\x0F\xD0\110", IF_PRESCOTT|IF_SSE3|IF_SM}, - {I_ADDSUBPD, 2, {XMMREG,XMMREG,0}, "\3\x66\x0F\xD0\110", IF_PRESCOTT|IF_SSE3}, - ITEMPLATE_END -}; - -static struct itemplate instrux_ADDSUBPS[] = { - {I_ADDSUBPS, 2, {XMMREG,MEMORY,0}, "\301\3\xF2\x0F\xD0\110", IF_PRESCOTT|IF_SSE3|IF_SM}, - {I_ADDSUBPS, 2, {XMMREG,XMMREG,0}, "\3\xF2\x0F\xD0\110", IF_PRESCOTT|IF_SSE3}, - ITEMPLATE_END -}; - -static struct itemplate instrux_AND[] = { - {I_AND, 2, {MEMORY,REG8,0}, "\300\1\x20\101", IF_8086|IF_SM}, - {I_AND, 2, {REG8,REG8,0}, "\1\x20\101", IF_8086}, - {I_AND, 2, {MEMORY,REG16,0}, "\320\300\1\x21\101", IF_8086|IF_SM}, - {I_AND, 2, {REG16,REG16,0}, "\320\1\x21\101", IF_8086}, - {I_AND, 2, {MEMORY,REG32,0}, "\321\300\1\x21\101", IF_386|IF_SM}, - {I_AND, 2, {REG32,REG32,0}, "\321\1\x21\101", IF_386}, - {I_AND, 2, {REG8,MEMORY,0}, "\301\1\x22\110", IF_8086|IF_SM}, - {I_AND, 2, {REG8,REG8,0}, "\1\x22\110", IF_8086}, - {I_AND, 2, {REG16,MEMORY,0}, "\320\301\1\x23\110", IF_8086|IF_SM}, - {I_AND, 2, {REG16,REG16,0}, "\320\1\x23\110", IF_8086}, - {I_AND, 2, {REG32,MEMORY,0}, "\321\301\1\x23\110", IF_386|IF_SM}, - {I_AND, 2, {REG32,REG32,0}, "\321\1\x23\110", IF_386}, - {I_AND, 2, {REGMEM|BITS16,IMMEDIATE|BITS8,0}, "\320\300\1\x83\204\15", IF_8086}, - {I_AND, 2, {REGMEM|BITS32,IMMEDIATE|BITS8,0}, "\321\300\1\x83\204\15", IF_386}, - {I_AND, 2, {REG_AL,IMMEDIATE,0}, "\1\x24\21", IF_8086|IF_SM}, - {I_AND, 2, {REG_AX,SBYTE,0}, "\320\1\x83\204\15", IF_8086|IF_SM}, - {I_AND, 2, {REG_AX,IMMEDIATE,0}, "\320\1\x25\31", IF_8086|IF_SM}, - {I_AND, 2, {REG_EAX,SBYTE,0}, "\321\1\x83\204\15", IF_386|IF_SM}, - {I_AND, 2, {REG_EAX,IMMEDIATE,0}, "\321\1\x25\41", IF_386|IF_SM}, - {I_AND, 2, {REGMEM|BITS8,IMMEDIATE,0}, "\300\1\x80\204\21", IF_8086|IF_SM}, - {I_AND, 2, {REGMEM|BITS16,IMMEDIATE,0}, "\320\300\134\1\x81\204\131", IF_8086|IF_SM}, - {I_AND, 2, {REGMEM|BITS32,IMMEDIATE,0}, "\321\300\144\1\x81\204\141", IF_386|IF_SM}, - {I_AND, 2, {MEMORY,IMMEDIATE|BITS8,0}, "\300\1\x80\204\21", IF_8086|IF_SM}, - {I_AND, 2, {MEMORY,IMMEDIATE|BITS16,0}, "\320\300\134\1\x81\204\131", IF_8086|IF_SM}, - {I_AND, 2, {MEMORY,IMMEDIATE|BITS32,0}, "\321\300\144\1\x81\204\141", IF_386|IF_SM}, - ITEMPLATE_END -}; - -static struct itemplate instrux_ANDNPD[] = { - {I_ANDNPD, 2, {XMMREG,XMMREG,0}, "\331\3\x66\x0F\x55\110", IF_WILLAMETTE|IF_SSE2}, - {I_ANDNPD, 2, {XMMREG,MEMORY,0}, "\301\331\3\x66\x0F\x55\110", IF_WILLAMETTE|IF_SSE2|IF_SM}, - ITEMPLATE_END -}; - -static struct itemplate instrux_ANDNPS[] = { - {I_ANDNPS, 2, {XMMREG,MEMORY,0}, "\301\2\x0F\x55\110", IF_KATMAI|IF_SSE}, - {I_ANDNPS, 2, {XMMREG,XMMREG,0}, "\2\x0F\x55\110", IF_KATMAI|IF_SSE}, - ITEMPLATE_END -}; - -static struct itemplate instrux_ANDPD[] = { - {I_ANDPD, 2, {XMMREG,XMMREG,0}, "\331\3\x66\x0F\x54\110", IF_WILLAMETTE|IF_SSE2}, - {I_ANDPD, 2, {XMMREG,MEMORY,0}, "\301\331\3\x66\x0F\x54\110", IF_WILLAMETTE|IF_SSE2|IF_SM}, - ITEMPLATE_END -}; - -static struct itemplate instrux_ANDPS[] = { - {I_ANDPS, 2, {XMMREG,MEMORY,0}, "\301\2\x0F\x54\110", IF_KATMAI|IF_SSE}, - {I_ANDPS, 2, {XMMREG,XMMREG,0}, "\2\x0F\x54\110", IF_KATMAI|IF_SSE}, - ITEMPLATE_END -}; - -static struct itemplate instrux_ARPL[] = { - {I_ARPL, 2, {MEMORY,REG16,0}, "\300\1\x63\101", IF_286|IF_PROT|IF_SM}, - {I_ARPL, 2, {REG16,REG16,0}, "\1\x63\101", IF_286|IF_PROT}, - ITEMPLATE_END -}; - -static struct itemplate instrux_BOUND[] = { - {I_BOUND, 2, {REG16,MEMORY,0}, "\320\301\1\x62\110", IF_186}, - {I_BOUND, 2, {REG32,MEMORY,0}, "\321\301\1\x62\110", IF_386}, - ITEMPLATE_END -}; - -static struct itemplate instrux_BSF[] = { - {I_BSF, 2, {REG16,MEMORY,0}, "\320\301\2\x0F\xBC\110", IF_386|IF_SM}, - {I_BSF, 2, {REG16,REG16,0}, "\320\2\x0F\xBC\110", IF_386}, - {I_BSF, 2, {REG32,MEMORY,0}, "\321\301\2\x0F\xBC\110", IF_386|IF_SM}, - {I_BSF, 2, {REG32,REG32,0}, "\321\2\x0F\xBC\110", IF_386}, - ITEMPLATE_END -}; - -static struct itemplate instrux_BSR[] = { - {I_BSR, 2, {REG16,MEMORY,0}, "\320\301\2\x0F\xBD\110", IF_386|IF_SM}, - {I_BSR, 2, {REG16,REG16,0}, "\320\2\x0F\xBD\110", IF_386}, - {I_BSR, 2, {REG32,MEMORY,0}, "\321\301\2\x0F\xBD\110", IF_386|IF_SM}, - {I_BSR, 2, {REG32,REG32,0}, "\321\2\x0F\xBD\110", IF_386}, - ITEMPLATE_END -}; - -static struct itemplate instrux_BSWAP[] = { - {I_BSWAP, 1, {REG32,0,0}, "\321\1\x0F\10\xC8", IF_486}, - ITEMPLATE_END -}; - -static struct itemplate instrux_BT[] = { - {I_BT, 2, {MEMORY,REG16,0}, "\320\300\2\x0F\xA3\101", IF_386|IF_SM}, - {I_BT, 2, {REG16,REG16,0}, "\320\2\x0F\xA3\101", IF_386}, - {I_BT, 2, {MEMORY,REG32,0}, "\321\300\2\x0F\xA3\101", IF_386|IF_SM}, - {I_BT, 2, {REG32,REG32,0}, "\321\2\x0F\xA3\101", IF_386}, - {I_BT, 2, {REGMEM|BITS16,IMMEDIATE,0}, "\320\300\2\x0F\xBA\204\25", IF_386|IF_SB}, - {I_BT, 2, {REGMEM|BITS32,IMMEDIATE,0}, "\321\300\2\x0F\xBA\204\25", IF_386|IF_SB}, - ITEMPLATE_END -}; - -static struct itemplate instrux_BTC[] = { - {I_BTC, 2, {MEMORY,REG16,0}, "\320\300\2\x0F\xBB\101", IF_386|IF_SM}, - {I_BTC, 2, {REG16,REG16,0}, "\320\2\x0F\xBB\101", IF_386}, - {I_BTC, 2, {MEMORY,REG32,0}, "\321\300\2\x0F\xBB\101", IF_386|IF_SM}, - {I_BTC, 2, {REG32,REG32,0}, "\321\2\x0F\xBB\101", IF_386}, - {I_BTC, 2, {REGMEM|BITS16,IMMEDIATE,0}, "\320\300\2\x0F\xBA\207\25", IF_386|IF_SB}, - {I_BTC, 2, {REGMEM|BITS32,IMMEDIATE,0}, "\321\300\2\x0F\xBA\207\25", IF_386|IF_SB}, - ITEMPLATE_END -}; - -static struct itemplate instrux_BTR[] = { - {I_BTR, 2, {MEMORY,REG16,0}, "\320\300\2\x0F\xB3\101", IF_386|IF_SM}, - {I_BTR, 2, {REG16,REG16,0}, "\320\2\x0F\xB3\101", IF_386}, - {I_BTR, 2, {MEMORY,REG32,0}, "\321\300\2\x0F\xB3\101", IF_386|IF_SM}, - {I_BTR, 2, {REG32,REG32,0}, "\321\2\x0F\xB3\101", IF_386}, - {I_BTR, 2, {REGMEM|BITS16,IMMEDIATE,0}, "\320\300\2\x0F\xBA\206\25", IF_386|IF_SB}, - {I_BTR, 2, {REGMEM|BITS32,IMMEDIATE,0}, "\321\300\2\x0F\xBA\206\25", IF_386|IF_SB}, - ITEMPLATE_END -}; - -static struct itemplate instrux_BTS[] = { - {I_BTS, 2, {MEMORY,REG16,0}, "\320\300\2\x0F\xAB\101", IF_386|IF_SM}, - {I_BTS, 2, {REG16,REG16,0}, "\320\2\x0F\xAB\101", IF_386}, - {I_BTS, 2, {MEMORY,REG32,0}, "\321\300\2\x0F\xAB\101", IF_386|IF_SM}, - {I_BTS, 2, {REG32,REG32,0}, "\321\2\x0F\xAB\101", IF_386}, - {I_BTS, 2, {REGMEM|BITS16,IMMEDIATE,0}, "\320\300\2\x0F\xBA\205\25", IF_386|IF_SB}, - {I_BTS, 2, {REGMEM|BITS32,IMMEDIATE,0}, "\321\300\2\x0F\xBA\205\25", IF_386|IF_SB}, - ITEMPLATE_END -}; - -static struct itemplate instrux_CALL[] = { - {I_CALL, 1, {IMMEDIATE,0,0}, "\322\1\xE8\64", IF_8086}, - {I_CALL, 1, {IMMEDIATE|NEAR,0,0}, "\322\1\xE8\64", IF_8086}, - {I_CALL, 1, {IMMEDIATE|FAR,0,0}, "\322\1\x9A\34\37", IF_8086}, - {I_CALL, 1, {IMMEDIATE|BITS16,0,0}, "\320\1\xE8\64", IF_8086}, - {I_CALL, 1, {IMMEDIATE|BITS16|NEAR,0,0}, "\320\1\xE8\64", IF_8086}, - {I_CALL, 1, {IMMEDIATE|BITS16|FAR,0,0}, "\320\1\x9A\34\37", IF_8086}, - {I_CALL, 1, {IMMEDIATE|BITS32,0,0}, "\321\1\xE8\64", IF_386}, - {I_CALL, 1, {IMMEDIATE|BITS32|NEAR,0,0}, "\321\1\xE8\64", IF_386}, - {I_CALL, 1, {IMMEDIATE|BITS32|FAR,0,0}, "\321\1\x9A\34\37", IF_386}, - {I_CALL, 2, {IMMEDIATE|COLON,IMMEDIATE,0}, "\322\1\x9A\35\30", IF_8086}, - {I_CALL, 2, {IMMEDIATE|BITS16|COLON,IMMEDIATE,0}, "\320\1\x9A\31\30", IF_8086}, - {I_CALL, 2, {IMMEDIATE|COLON,IMMEDIATE|BITS16,0}, "\320\1\x9A\31\30", IF_8086}, - {I_CALL, 2, {IMMEDIATE|BITS32|COLON,IMMEDIATE,0}, "\321\1\x9A\41\30", IF_386}, - {I_CALL, 2, {IMMEDIATE|COLON,IMMEDIATE|BITS32,0}, "\321\1\x9A\41\30", IF_386}, - {I_CALL, 1, {MEMORY|FAR,0,0}, "\322\300\1\xFF\203", IF_8086}, - {I_CALL, 1, {MEMORY|BITS16|FAR,0,0}, "\320\300\1\xFF\203", IF_8086}, - {I_CALL, 1, {MEMORY|BITS32|FAR,0,0}, "\321\300\1\xFF\203", IF_386}, - {I_CALL, 1, {MEMORY|NEAR,0,0}, "\322\300\1\xFF\202", IF_8086}, - {I_CALL, 1, {MEMORY|BITS16|NEAR,0,0}, "\320\300\1\xFF\202", IF_8086}, - {I_CALL, 1, {MEMORY|BITS32|NEAR,0,0}, "\321\300\1\xFF\202", IF_386}, - {I_CALL, 1, {REG16,0,0}, "\320\300\1\xFF\202", IF_8086}, - {I_CALL, 1, {REG32,0,0}, "\321\300\1\xFF\202", IF_386}, - {I_CALL, 1, {MEMORY,0,0}, "\322\300\1\xFF\202", IF_8086}, - {I_CALL, 1, {MEMORY|BITS16,0,0}, "\320\300\1\xFF\202", IF_8086}, - {I_CALL, 1, {MEMORY|BITS32,0,0}, "\321\300\1\xFF\202", IF_386}, - ITEMPLATE_END -}; - -static struct itemplate instrux_CBW[] = { - {I_CBW, 0, {0,0,0}, "\320\1\x98", IF_8086}, - ITEMPLATE_END -}; - -static struct itemplate instrux_CDQ[] = { - {I_CDQ, 0, {0,0,0}, "\321\1\x99", IF_386}, - ITEMPLATE_END -}; - -static struct itemplate instrux_CLC[] = { - {I_CLC, 0, {0,0,0}, "\1\xF8", IF_8086}, - ITEMPLATE_END -}; - -static struct itemplate instrux_CLD[] = { - {I_CLD, 0, {0,0,0}, "\1\xFC", IF_8086}, - ITEMPLATE_END -}; - -static struct itemplate instrux_CLFLUSH[] = { - {I_CLFLUSH, 1, {MEMORY,0,0}, "\300\2\x0F\xAE\207", IF_WILLAMETTE|IF_SSE2}, - ITEMPLATE_END -}; - -static struct itemplate instrux_CLI[] = { - {I_CLI, 0, {0,0,0}, "\1\xFA", IF_8086}, - ITEMPLATE_END -}; - -static struct itemplate instrux_CLTS[] = { - {I_CLTS, 0, {0,0,0}, "\2\x0F\x06", IF_286|IF_PRIV}, - ITEMPLATE_END -}; - -static struct itemplate instrux_CMC[] = { - {I_CMC, 0, {0,0,0}, "\1\xF5", IF_8086}, - ITEMPLATE_END -}; - -static struct itemplate instrux_CMP[] = { - {I_CMP, 2, {MEMORY,REG8,0}, "\300\1\x38\101", IF_8086|IF_SM}, - {I_CMP, 2, {REG8,REG8,0}, "\1\x38\101", IF_8086}, - {I_CMP, 2, {MEMORY,REG16,0}, "\320\300\1\x39\101", IF_8086|IF_SM}, - {I_CMP, 2, {REG16,REG16,0}, "\320\1\x39\101", IF_8086}, - {I_CMP, 2, {MEMORY,REG32,0}, "\321\300\1\x39\101", IF_386|IF_SM}, - {I_CMP, 2, {REG32,REG32,0}, "\321\1\x39\101", IF_386}, - {I_CMP, 2, {REG8,MEMORY,0}, "\301\1\x3A\110", IF_8086|IF_SM}, - {I_CMP, 2, {REG8,REG8,0}, "\1\x3A\110", IF_8086}, - {I_CMP, 2, {REG16,MEMORY,0}, "\320\301\1\x3B\110", IF_8086|IF_SM}, - {I_CMP, 2, {REG16,REG16,0}, "\320\1\x3B\110", IF_8086}, - {I_CMP, 2, {REG32,MEMORY,0}, "\321\301\1\x3B\110", IF_386|IF_SM}, - {I_CMP, 2, {REG32,REG32,0}, "\321\1\x3B\110", IF_386}, - {I_CMP, 2, {REGMEM|BITS16,IMMEDIATE|BITS8,0}, "\320\300\1\x83\207\15", IF_8086}, - {I_CMP, 2, {REGMEM|BITS32,IMMEDIATE|BITS8,0}, "\321\300\1\x83\207\15", IF_386}, - {I_CMP, 2, {REG_AL,IMMEDIATE,0}, "\1\x3C\21", IF_8086|IF_SM}, - {I_CMP, 2, {REG_AX,SBYTE,0}, "\320\1\x83\207\15", IF_8086|IF_SM}, - {I_CMP, 2, {REG_AX,IMMEDIATE,0}, "\320\1\x3D\31", IF_8086|IF_SM}, - {I_CMP, 2, {REG_EAX,SBYTE,0}, "\321\1\x83\207\15", IF_386|IF_SM}, - {I_CMP, 2, {REG_EAX,IMMEDIATE,0}, "\321\1\x3D\41", IF_386|IF_SM}, - {I_CMP, 2, {REGMEM|BITS8,IMMEDIATE,0}, "\300\1\x80\207\21", IF_8086|IF_SM}, - {I_CMP, 2, {REGMEM|BITS16,IMMEDIATE,0}, "\320\300\134\1\x81\207\131", IF_8086|IF_SM}, - {I_CMP, 2, {REGMEM|BITS32,IMMEDIATE,0}, "\321\300\144\1\x81\207\141", IF_386|IF_SM}, - {I_CMP, 2, {MEMORY,IMMEDIATE|BITS8,0}, "\300\1\x80\207\21", IF_8086|IF_SM}, - {I_CMP, 2, {MEMORY,IMMEDIATE|BITS16,0}, "\320\300\134\1\x81\207\131", IF_8086|IF_SM}, - {I_CMP, 2, {MEMORY,IMMEDIATE|BITS32,0}, "\321\300\144\1\x81\207\141", IF_386|IF_SM}, - ITEMPLATE_END -}; - -static struct itemplate instrux_CMPEQPD[] = { - {I_CMPEQPD, 2, {XMMREG,MEMORY,0}, "\301\331\3\x66\x0F\xC2\110\1\x00", IF_WILLAMETTE|IF_SSE2|IF_SM}, - {I_CMPEQPD, 2, {XMMREG,XMMREG,0}, "\331\3\x66\x0F\xC2\110\1\x00", IF_WILLAMETTE|IF_SSE2}, - ITEMPLATE_END -}; - -static struct itemplate instrux_CMPEQPS[] = { - {I_CMPEQPS, 2, {XMMREG,MEMORY,0}, "\301\331\2\x0F\xC2\110\1\x00", IF_KATMAI|IF_SSE}, - {I_CMPEQPS, 2, {XMMREG,XMMREG,0}, "\331\2\x0F\xC2\110\1\x00", IF_KATMAI|IF_SSE}, - ITEMPLATE_END -}; - -static struct itemplate instrux_CMPEQSD[] = { - {I_CMPEQSD, 2, {XMMREG,MEMORY,0}, "\301\331\3\xF2\x0F\xC2\110\1\x00", IF_WILLAMETTE|IF_SSE2}, - {I_CMPEQSD, 2, {XMMREG,XMMREG,0}, "\331\3\xF2\x0F\xC2\110\1\x00", IF_WILLAMETTE|IF_SSE2}, - ITEMPLATE_END -}; - -static struct itemplate instrux_CMPEQSS[] = { - {I_CMPEQSS, 2, {XMMREG,MEMORY,0}, "\301\333\2\x0F\xC2\110\1\x00", IF_KATMAI|IF_SSE}, - {I_CMPEQSS, 2, {XMMREG,XMMREG,0}, "\333\2\x0F\xC2\110\1\x00", IF_KATMAI|IF_SSE}, - ITEMPLATE_END -}; - -static struct itemplate instrux_CMPLEPD[] = { - {I_CMPLEPD, 2, {XMMREG,MEMORY,0}, "\301\331\3\x66\x0F\xC2\110\1\x02", IF_WILLAMETTE|IF_SSE2|IF_SM}, - {I_CMPLEPD, 2, {XMMREG,XMMREG,0}, "\331\3\x66\x0F\xC2\110\1\x02", IF_WILLAMETTE|IF_SSE2}, - ITEMPLATE_END -}; - -static struct itemplate instrux_CMPLEPS[] = { - {I_CMPLEPS, 2, {XMMREG,MEMORY,0}, "\301\331\2\x0F\xC2\110\1\x02", IF_KATMAI|IF_SSE}, - {I_CMPLEPS, 2, {XMMREG,XMMREG,0}, "\331\2\x0F\xC2\110\1\x02", IF_KATMAI|IF_SSE}, - ITEMPLATE_END -}; - -static struct itemplate instrux_CMPLESD[] = { - {I_CMPLESD, 2, {XMMREG,MEMORY,0}, "\301\331\3\xF2\x0F\xC2\110\1\x02", IF_WILLAMETTE|IF_SSE2}, - {I_CMPLESD, 2, {XMMREG,XMMREG,0}, "\331\3\xF2\x0F\xC2\110\1\x02", IF_WILLAMETTE|IF_SSE2}, - ITEMPLATE_END -}; - -static struct itemplate instrux_CMPLESS[] = { - {I_CMPLESS, 2, {XMMREG,MEMORY,0}, "\301\333\2\x0F\xC2\110\1\x02", IF_KATMAI|IF_SSE}, - {I_CMPLESS, 2, {XMMREG,XMMREG,0}, "\333\2\x0F\xC2\110\1\x02", IF_KATMAI|IF_SSE}, - ITEMPLATE_END -}; - -static struct itemplate instrux_CMPLTPD[] = { - {I_CMPLTPD, 2, {XMMREG,MEMORY,0}, "\301\331\3\x66\x0F\xC2\110\1\x01", IF_WILLAMETTE|IF_SSE2|IF_SM}, - {I_CMPLTPD, 2, {XMMREG,XMMREG,0}, "\331\3\x66\x0F\xC2\110\1\x01", IF_WILLAMETTE|IF_SSE2}, - ITEMPLATE_END -}; - -static struct itemplate instrux_CMPLTPS[] = { - {I_CMPLTPS, 2, {XMMREG,MEMORY,0}, "\301\331\2\x0F\xC2\110\1\x01", IF_KATMAI|IF_SSE}, - {I_CMPLTPS, 2, {XMMREG,XMMREG,0}, "\331\2\x0F\xC2\110\1\x01", IF_KATMAI|IF_SSE}, - ITEMPLATE_END -}; - -static struct itemplate instrux_CMPLTSD[] = { - {I_CMPLTSD, 2, {XMMREG,MEMORY,0}, "\301\331\3\xF2\x0F\xC2\110\1\x01", IF_WILLAMETTE|IF_SSE2}, - {I_CMPLTSD, 2, {XMMREG,XMMREG,0}, "\331\3\xF2\x0F\xC2\110\1\x01", IF_WILLAMETTE|IF_SSE2}, - ITEMPLATE_END -}; - -static struct itemplate instrux_CMPLTSS[] = { - {I_CMPLTSS, 2, {XMMREG,MEMORY,0}, "\301\333\2\x0F\xC2\110\1\x01", IF_KATMAI|IF_SSE}, - {I_CMPLTSS, 2, {XMMREG,XMMREG,0}, "\333\2\x0F\xC2\110\1\x01", IF_KATMAI|IF_SSE}, - ITEMPLATE_END -}; - -static struct itemplate instrux_CMPNEQPD[] = { - {I_CMPNEQPD, 2, {XMMREG,MEMORY,0}, "\301\331\3\x66\x0F\xC2\110\1\x04", IF_WILLAMETTE|IF_SSE2|IF_SM}, - {I_CMPNEQPD, 2, {XMMREG,XMMREG,0}, "\331\3\x66\x0F\xC2\110\1\x04", IF_WILLAMETTE|IF_SSE2}, - ITEMPLATE_END -}; - -static struct itemplate instrux_CMPNEQPS[] = { - {I_CMPNEQPS, 2, {XMMREG,MEMORY,0}, "\301\331\2\x0F\xC2\110\1\x04", IF_KATMAI|IF_SSE}, - {I_CMPNEQPS, 2, {XMMREG,XMMREG,0}, "\331\2\x0F\xC2\110\1\x04", IF_KATMAI|IF_SSE}, - ITEMPLATE_END -}; - -static struct itemplate instrux_CMPNEQSD[] = { - {I_CMPNEQSD, 2, {XMMREG,MEMORY,0}, "\301\331\3\xF2\x0F\xC2\110\1\x04", IF_WILLAMETTE|IF_SSE2}, - {I_CMPNEQSD, 2, {XMMREG,XMMREG,0}, "\331\3\xF2\x0F\xC2\110\1\x04", IF_WILLAMETTE|IF_SSE2}, - ITEMPLATE_END -}; - -static struct itemplate instrux_CMPNEQSS[] = { - {I_CMPNEQSS, 2, {XMMREG,MEMORY,0}, "\301\333\2\x0F\xC2\110\1\x04", IF_KATMAI|IF_SSE}, - {I_CMPNEQSS, 2, {XMMREG,XMMREG,0}, "\333\2\x0F\xC2\110\1\x04", IF_KATMAI|IF_SSE}, - ITEMPLATE_END -}; - -static struct itemplate instrux_CMPNLEPD[] = { - {I_CMPNLEPD, 2, {XMMREG,MEMORY,0}, "\301\331\3\x66\x0F\xC2\110\1\x06", IF_WILLAMETTE|IF_SSE2|IF_SM}, - {I_CMPNLEPD, 2, {XMMREG,XMMREG,0}, "\331\3\x66\x0F\xC2\110\1\x06", IF_WILLAMETTE|IF_SSE2}, - ITEMPLATE_END -}; - -static struct itemplate instrux_CMPNLEPS[] = { - {I_CMPNLEPS, 2, {XMMREG,MEMORY,0}, "\301\331\2\x0F\xC2\110\1\x06", IF_KATMAI|IF_SSE}, - {I_CMPNLEPS, 2, {XMMREG,XMMREG,0}, "\331\2\x0F\xC2\110\1\x06", IF_KATMAI|IF_SSE}, - ITEMPLATE_END -}; - -static struct itemplate instrux_CMPNLESD[] = { - {I_CMPNLESD, 2, {XMMREG,MEMORY,0}, "\301\331\3\xF2\x0F\xC2\110\1\x06", IF_WILLAMETTE|IF_SSE2}, - {I_CMPNLESD, 2, {XMMREG,XMMREG,0}, "\331\3\xF2\x0F\xC2\110\1\x06", IF_WILLAMETTE|IF_SSE2}, - ITEMPLATE_END -}; - -static struct itemplate instrux_CMPNLESS[] = { - {I_CMPNLESS, 2, {XMMREG,MEMORY,0}, "\301\333\2\x0F\xC2\110\1\x06", IF_KATMAI|IF_SSE}, - {I_CMPNLESS, 2, {XMMREG,XMMREG,0}, "\333\2\x0F\xC2\110\1\x06", IF_KATMAI|IF_SSE}, - ITEMPLATE_END -}; - -static struct itemplate instrux_CMPNLTPD[] = { - {I_CMPNLTPD, 2, {XMMREG,MEMORY,0}, "\301\331\3\x66\x0F\xC2\110\1\x05", IF_WILLAMETTE|IF_SSE2|IF_SM}, - {I_CMPNLTPD, 2, {XMMREG,XMMREG,0}, "\331\3\x66\x0F\xC2\110\1\x05", IF_WILLAMETTE|IF_SSE2}, - ITEMPLATE_END -}; - -static struct itemplate instrux_CMPNLTPS[] = { - {I_CMPNLTPS, 2, {XMMREG,MEMORY,0}, "\301\331\2\x0F\xC2\110\1\x05", IF_KATMAI|IF_SSE}, - {I_CMPNLTPS, 2, {XMMREG,XMMREG,0}, "\331\2\x0F\xC2\110\1\x05", IF_KATMAI|IF_SSE}, - ITEMPLATE_END -}; - -static struct itemplate instrux_CMPNLTSD[] = { - {I_CMPNLTSD, 2, {XMMREG,MEMORY,0}, "\301\331\3\xF2\x0F\xC2\110\1\x05", IF_WILLAMETTE|IF_SSE2}, - {I_CMPNLTSD, 2, {XMMREG,XMMREG,0}, "\331\3\xF2\x0F\xC2\110\1\x05", IF_WILLAMETTE|IF_SSE2}, - ITEMPLATE_END -}; - -static struct itemplate instrux_CMPNLTSS[] = { - {I_CMPNLTSS, 2, {XMMREG,MEMORY,0}, "\301\333\2\x0F\xC2\110\1\x05", IF_KATMAI|IF_SSE}, - {I_CMPNLTSS, 2, {XMMREG,XMMREG,0}, "\333\2\x0F\xC2\110\1\x05", IF_KATMAI|IF_SSE}, - ITEMPLATE_END -}; - -static struct itemplate instrux_CMPORDPD[] = { - {I_CMPORDPD, 2, {XMMREG,MEMORY,0}, "\301\331\3\x66\x0F\xC2\110\1\x07", IF_WILLAMETTE|IF_SSE2|IF_SM}, - {I_CMPORDPD, 2, {XMMREG,XMMREG,0}, "\331\3\x66\x0F\xC2\110\1\x07", IF_WILLAMETTE|IF_SSE2}, - ITEMPLATE_END -}; - -static struct itemplate instrux_CMPORDPS[] = { - {I_CMPORDPS, 2, {XMMREG,MEMORY,0}, "\301\331\2\x0F\xC2\110\1\x07", IF_KATMAI|IF_SSE}, - {I_CMPORDPS, 2, {XMMREG,XMMREG,0}, "\331\2\x0F\xC2\110\1\x07", IF_KATMAI|IF_SSE}, - ITEMPLATE_END -}; - -static struct itemplate instrux_CMPORDSD[] = { - {I_CMPORDSD, 2, {XMMREG,MEMORY,0}, "\301\331\3\xF2\x0F\xC2\110\1\x07", IF_WILLAMETTE|IF_SSE2}, - {I_CMPORDSD, 2, {XMMREG,XMMREG,0}, "\331\3\xF2\x0F\xC2\110\1\x07", IF_WILLAMETTE|IF_SSE2}, - ITEMPLATE_END -}; - -static struct itemplate instrux_CMPORDSS[] = { - {I_CMPORDSS, 2, {XMMREG,MEMORY,0}, "\301\333\2\x0F\xC2\110\1\x07", IF_KATMAI|IF_SSE}, - {I_CMPORDSS, 2, {XMMREG,XMMREG,0}, "\333\2\x0F\xC2\110\1\x07", IF_KATMAI|IF_SSE}, - ITEMPLATE_END -}; - -static struct itemplate instrux_CMPPD[] = { - {I_CMPPD, 3, {XMMREG,XMMREG,IMMEDIATE}, "\331\3\x66\x0F\xC2\110\26", IF_WILLAMETTE|IF_SSE2|IF_SB|IF_AR2}, - {I_CMPPD, 3, {XMMREG,MEMORY,IMMEDIATE}, "\301\331\3\x66\x0F\xC2\110\26", IF_WILLAMETTE|IF_SSE2|IF_SM2|IF_SB|IF_AR2}, - ITEMPLATE_END -}; - -static struct itemplate instrux_CMPPS[] = { - {I_CMPPS, 3, {XMMREG,MEMORY,IMMEDIATE}, "\301\331\2\x0F\xC2\110\26", IF_KATMAI|IF_SSE|IF_SB|IF_AR2}, - {I_CMPPS, 3, {XMMREG,XMMREG,IMMEDIATE}, "\331\2\x0F\xC2\110\26", IF_KATMAI|IF_SSE|IF_SB|IF_AR2}, - ITEMPLATE_END -}; - -static struct itemplate instrux_CMPSB[] = { - {I_CMPSB, 0, {0,0,0}, "\332\1\xA6", IF_8086}, - ITEMPLATE_END -}; - -static struct itemplate instrux_CMPSD[] = { - {I_CMPSD, 0, {0,0,0}, "\332\321\1\xA7", IF_386}, - {I_CMPSD, 3, {XMMREG,XMMREG,IMMEDIATE}, "\331\3\xF2\x0F\xC2\110\26", IF_WILLAMETTE|IF_SSE2|IF_SB|IF_AR2}, - {I_CMPSD, 3, {XMMREG,MEMORY,IMMEDIATE}, "\301\331\3\xF2\x0F\xC2\110\26", IF_WILLAMETTE|IF_SSE2|IF_SB|IF_AR2}, - ITEMPLATE_END -}; - -static struct itemplate instrux_CMPSS[] = { - {I_CMPSS, 3, {XMMREG,MEMORY,IMMEDIATE}, "\301\333\2\x0F\xC2\110\26", IF_KATMAI|IF_SSE|IF_SB|IF_AR2}, - {I_CMPSS, 3, {XMMREG,XMMREG,IMMEDIATE}, "\333\2\x0F\xC2\110\26", IF_KATMAI|IF_SSE|IF_SB|IF_AR2}, - ITEMPLATE_END -}; - -static struct itemplate instrux_CMPSW[] = { - {I_CMPSW, 0, {0,0,0}, "\332\320\1\xA7", IF_8086}, - ITEMPLATE_END -}; - -static struct itemplate instrux_CMPUNORDPD[] = { - {I_CMPUNORDPD, 2, {XMMREG,MEMORY,0}, "\301\331\3\x66\x0F\xC2\110\1\x03", IF_WILLAMETTE|IF_SSE2|IF_SM}, - {I_CMPUNORDPD, 2, {XMMREG,XMMREG,0}, "\331\3\x66\x0F\xC2\110\1\x03", IF_WILLAMETTE|IF_SSE2}, - ITEMPLATE_END -}; - -static struct itemplate instrux_CMPUNORDPS[] = { - {I_CMPUNORDPS, 2, {XMMREG,MEMORY,0}, "\301\331\2\x0F\xC2\110\1\x03", IF_KATMAI|IF_SSE}, - {I_CMPUNORDPS, 2, {XMMREG,XMMREG,0}, "\331\2\x0F\xC2\110\1\x03", IF_KATMAI|IF_SSE}, - ITEMPLATE_END -}; - -static struct itemplate instrux_CMPUNORDSD[] = { - {I_CMPUNORDSD, 2, {XMMREG,MEMORY,0}, "\301\331\3\xF2\x0F\xC2\110\1\x03", IF_WILLAMETTE|IF_SSE2}, - {I_CMPUNORDSD, 2, {XMMREG,XMMREG,0}, "\331\3\xF2\x0F\xC2\110\1\x03", IF_WILLAMETTE|IF_SSE2}, - ITEMPLATE_END -}; - -static struct itemplate instrux_CMPUNORDSS[] = { - {I_CMPUNORDSS, 2, {XMMREG,MEMORY,0}, "\301\333\2\x0F\xC2\110\1\x03", IF_KATMAI|IF_SSE}, - {I_CMPUNORDSS, 2, {XMMREG,XMMREG,0}, "\333\2\x0F\xC2\110\1\x03", IF_KATMAI|IF_SSE}, - ITEMPLATE_END -}; - -static struct itemplate instrux_CMPXCHG[] = { - {I_CMPXCHG, 2, {MEMORY,REG8,0}, "\300\2\x0F\xB0\101", IF_PENT|IF_SM}, - {I_CMPXCHG, 2, {REG8,REG8,0}, "\2\x0F\xB0\101", IF_PENT}, - {I_CMPXCHG, 2, {MEMORY,REG16,0}, "\320\300\2\x0F\xB1\101", IF_PENT|IF_SM}, - {I_CMPXCHG, 2, {REG16,REG16,0}, "\320\2\x0F\xB1\101", IF_PENT}, - {I_CMPXCHG, 2, {MEMORY,REG32,0}, "\321\300\2\x0F\xB1\101", IF_PENT|IF_SM}, - {I_CMPXCHG, 2, {REG32,REG32,0}, "\321\2\x0F\xB1\101", IF_PENT}, - ITEMPLATE_END -}; - -static struct itemplate instrux_CMPXCHG486[] = { - {I_CMPXCHG486, 2, {MEMORY,REG8,0}, "\300\2\x0F\xA6\101", IF_486|IF_SM|IF_UNDOC}, - {I_CMPXCHG486, 2, {REG8,REG8,0}, "\2\x0F\xA6\101", IF_486|IF_UNDOC}, - {I_CMPXCHG486, 2, {MEMORY,REG16,0}, "\320\300\2\x0F\xA7\101", IF_486|IF_SM|IF_UNDOC}, - {I_CMPXCHG486, 2, {REG16,REG16,0}, "\320\2\x0F\xA7\101", IF_486|IF_UNDOC}, - {I_CMPXCHG486, 2, {MEMORY,REG32,0}, "\321\300\2\x0F\xA7\101", IF_486|IF_SM|IF_UNDOC}, - {I_CMPXCHG486, 2, {REG32,REG32,0}, "\321\2\x0F\xA7\101", IF_486|IF_UNDOC}, - ITEMPLATE_END -}; - -static struct itemplate instrux_CMPXCHG8B[] = { - {I_CMPXCHG8B, 1, {MEMORY,0,0}, "\300\2\x0F\xC7\201", IF_PENT}, - ITEMPLATE_END -}; - -static struct itemplate instrux_COMISD[] = { - {I_COMISD, 2, {XMMREG,XMMREG,0}, "\331\3\x66\x0F\x2F\110", IF_WILLAMETTE|IF_SSE2}, - {I_COMISD, 2, {XMMREG,MEMORY,0}, "\301\331\3\x66\x0F\x2F\110", IF_WILLAMETTE|IF_SSE2}, - ITEMPLATE_END -}; - -static struct itemplate instrux_COMISS[] = { - {I_COMISS, 2, {XMMREG,MEMORY,0}, "\301\2\x0F\x2F\110", IF_KATMAI|IF_SSE}, - {I_COMISS, 2, {XMMREG,XMMREG,0}, "\2\x0F\x2F\110", IF_KATMAI|IF_SSE}, - ITEMPLATE_END -}; - -static struct itemplate instrux_CPUID[] = { - {I_CPUID, 0, {0,0,0}, "\2\x0F\xA2", IF_PENT}, - ITEMPLATE_END -}; - -static struct itemplate instrux_CVTDQ2PD[] = { - {I_CVTDQ2PD, 2, {XMMREG,XMMREG,0}, "\333\2\x0F\xE6\110", IF_WILLAMETTE|IF_SSE2}, - {I_CVTDQ2PD, 2, {XMMREG,MEMORY,0}, "\301\333\2\x0F\xE6\110", IF_WILLAMETTE|IF_SSE2}, - ITEMPLATE_END -}; - -static struct itemplate instrux_CVTDQ2PS[] = { - {I_CVTDQ2PS, 2, {XMMREG,XMMREG,0}, "\2\x0F\x5B\110", IF_WILLAMETTE|IF_SSE2}, - {I_CVTDQ2PS, 2, {XMMREG,MEMORY,0}, "\301\2\x0F\x5B\110", IF_WILLAMETTE|IF_SSE2|IF_SM}, - ITEMPLATE_END -}; - -static struct itemplate instrux_CVTPD2DQ[] = { - {I_CVTPD2DQ, 2, {XMMREG,XMMREG,0}, "\3\xF2\x0F\xE6\110", IF_WILLAMETTE|IF_SSE2}, - {I_CVTPD2DQ, 2, {XMMREG,MEMORY,0}, "\301\3\xF2\x0F\xE6\110", IF_WILLAMETTE|IF_SSE2|IF_SM}, - ITEMPLATE_END -}; - -static struct itemplate instrux_CVTPD2PI[] = { - {I_CVTPD2PI, 2, {MMXREG,XMMREG,0}, "\3\x66\x0F\x2D\110", IF_WILLAMETTE|IF_SSE2}, - {I_CVTPD2PI, 2, {MMXREG,MEMORY,0}, "\301\3\x66\x0F\x2D\110", IF_WILLAMETTE|IF_SSE2}, - ITEMPLATE_END -}; - -static struct itemplate instrux_CVTPD2PS[] = { - {I_CVTPD2PS, 2, {XMMREG,XMMREG,0}, "\3\x66\x0F\x5A\110", IF_WILLAMETTE|IF_SSE2}, - {I_CVTPD2PS, 2, {XMMREG,MEMORY,0}, "\301\3\x66\x0F\x5A\110", IF_WILLAMETTE|IF_SSE2|IF_SM}, - ITEMPLATE_END -}; - -static struct itemplate instrux_CVTPI2PD[] = { - {I_CVTPI2PD, 2, {XMMREG,MMXREG,0}, "\3\x66\x0F\x2A\110", IF_WILLAMETTE|IF_SSE2}, - {I_CVTPI2PD, 2, {XMMREG,MEMORY,0}, "\301\3\x66\x0F\x2A\110", IF_WILLAMETTE|IF_SSE2}, - ITEMPLATE_END -}; - -static struct itemplate instrux_CVTPI2PS[] = { - {I_CVTPI2PS, 2, {XMMREG,MEMORY,0}, "\301\331\2\x0F\x2A\110", IF_KATMAI|IF_SSE|IF_MMX}, - {I_CVTPI2PS, 2, {XMMREG,MMXREG,0}, "\331\2\x0F\x2A\110", IF_KATMAI|IF_SSE|IF_MMX}, - ITEMPLATE_END -}; - -static struct itemplate instrux_CVTPS2DQ[] = { - {I_CVTPS2DQ, 2, {XMMREG,XMMREG,0}, "\3\x66\x0F\x5B\110", IF_WILLAMETTE|IF_SSE2}, - {I_CVTPS2DQ, 2, {XMMREG,MEMORY,0}, "\301\3\x66\x0F\x5B\110", IF_WILLAMETTE|IF_SSE2|IF_SM}, - ITEMPLATE_END -}; - -static struct itemplate instrux_CVTPS2PD[] = { - {I_CVTPS2PD, 2, {XMMREG,XMMREG,0}, "\2\x0F\x5A\110", IF_WILLAMETTE|IF_SSE2}, - {I_CVTPS2PD, 2, {XMMREG,MEMORY,0}, "\301\2\x0F\x5A\110", IF_WILLAMETTE|IF_SSE2}, - ITEMPLATE_END -}; - -static struct itemplate instrux_CVTPS2PI[] = { - {I_CVTPS2PI, 2, {MMXREG,MEMORY,0}, "\301\331\2\x0F\x2D\110", IF_KATMAI|IF_SSE|IF_MMX}, - {I_CVTPS2PI, 2, {MMXREG,XMMREG,0}, "\331\2\x0F\x2D\110", IF_KATMAI|IF_SSE|IF_MMX}, - ITEMPLATE_END -}; - -static struct itemplate instrux_CVTSD2SI[] = { - {I_CVTSD2SI, 2, {REG32,XMMREG,0}, "\3\xF2\x0F\x2D\110", IF_WILLAMETTE|IF_SSE2}, - {I_CVTSD2SI, 2, {REG32,MEMORY,0}, "\301\3\xF2\x0F\x2D\110", IF_WILLAMETTE|IF_SSE2}, - ITEMPLATE_END -}; - -static struct itemplate instrux_CVTSD2SS[] = { - {I_CVTSD2SS, 2, {XMMREG,XMMREG,0}, "\3\xF2\x0F\x5A\110", IF_WILLAMETTE|IF_SSE2}, - {I_CVTSD2SS, 2, {XMMREG,MEMORY,0}, "\301\3\xF2\x0F\x5A\110", IF_WILLAMETTE|IF_SSE2}, - ITEMPLATE_END -}; - -static struct itemplate instrux_CVTSI2SD[] = { - {I_CVTSI2SD, 2, {XMMREG,REG32,0}, "\3\xF2\x0F\x2A\110", IF_WILLAMETTE|IF_SSE2}, - {I_CVTSI2SD, 2, {XMMREG,MEMORY,0}, "\301\3\xF2\x0F\x2A\110", IF_WILLAMETTE|IF_SSE2}, - ITEMPLATE_END -}; - -static struct itemplate instrux_CVTSI2SS[] = { - {I_CVTSI2SS, 2, {XMMREG,MEMORY,0}, "\301\333\2\x0F\x2A\110", IF_KATMAI|IF_SSE|IF_SD|IF_AR1}, - {I_CVTSI2SS, 2, {XMMREG,REG32,0}, "\333\2\x0F\x2A\110", IF_KATMAI|IF_SSE}, - ITEMPLATE_END -}; - -static struct itemplate instrux_CVTSS2SD[] = { - {I_CVTSS2SD, 2, {XMMREG,XMMREG,0}, "\333\2\x0F\x5A\110", IF_WILLAMETTE|IF_SSE2}, - {I_CVTSS2SD, 2, {XMMREG,MEMORY,0}, "\301\333\2\x0F\x5A\110", IF_WILLAMETTE|IF_SSE2}, - ITEMPLATE_END -}; - -static struct itemplate instrux_CVTSS2SI[] = { - {I_CVTSS2SI, 2, {REG32,MEMORY,0}, "\301\333\2\x0F\x2D\110", IF_KATMAI|IF_SSE}, - {I_CVTSS2SI, 2, {REG32,XMMREG,0}, "\333\2\x0F\x2D\110", IF_KATMAI|IF_SSE}, - ITEMPLATE_END -}; - -static struct itemplate instrux_CVTTPD2DQ[] = { - {I_CVTTPD2DQ, 2, {XMMREG,XMMREG,0}, "\3\x66\x0F\xE6\110", IF_WILLAMETTE|IF_SSE2}, - {I_CVTTPD2DQ, 2, {XMMREG,MEMORY,0}, "\301\3\x66\x0F\xE6\110", IF_WILLAMETTE|IF_SSE2|IF_SM}, - ITEMPLATE_END -}; - -static struct itemplate instrux_CVTTPD2PI[] = { - {I_CVTTPD2PI, 2, {MMXREG,XMMREG,0}, "\3\x66\x0F\x2C\110", IF_WILLAMETTE|IF_SSE2}, - {I_CVTTPD2PI, 2, {MMXREG,MEMORY,0}, "\301\3\x66\x0F\x2C\110", IF_WILLAMETTE|IF_SSE2}, - ITEMPLATE_END -}; - -static struct itemplate instrux_CVTTPS2DQ[] = { - {I_CVTTPS2DQ, 2, {XMMREG,XMMREG,0}, "\333\2\x0F\x5B\110", IF_WILLAMETTE|IF_SSE2}, - {I_CVTTPS2DQ, 2, {XMMREG,MEMORY,0}, "\301\333\2\x0F\x5B\110", IF_WILLAMETTE|IF_SSE2|IF_SM}, - ITEMPLATE_END -}; - -static struct itemplate instrux_CVTTPS2PI[] = { - {I_CVTTPS2PI, 2, {MMXREG,MEMORY,0}, "\301\331\2\x0F\x2C\110", IF_KATMAI|IF_SSE|IF_MMX}, - {I_CVTTPS2PI, 2, {MMXREG,XMMREG,0}, "\331\2\x0F\x2C\110", IF_KATMAI|IF_SSE|IF_MMX}, - ITEMPLATE_END -}; - -static struct itemplate instrux_CVTTSD2SI[] = { - {I_CVTTSD2SI, 2, {REG32,XMMREG,0}, "\3\xF2\x0F\x2C\110", IF_WILLAMETTE|IF_SSE2}, - {I_CVTTSD2SI, 2, {REG32,MEMORY,0}, "\301\3\xF2\x0F\x2C\110", IF_WILLAMETTE|IF_SSE2}, - ITEMPLATE_END -}; - -static struct itemplate instrux_CVTTSS2SI[] = { - {I_CVTTSS2SI, 2, {REG32,MEMORY,0}, "\301\333\2\x0F\x2C\110", IF_KATMAI|IF_SSE}, - {I_CVTTSS2SI, 2, {REG32,XMMREG,0}, "\333\2\x0F\x2C\110", IF_KATMAI|IF_SSE}, - ITEMPLATE_END -}; - -static struct itemplate instrux_CWD[] = { - {I_CWD, 0, {0,0,0}, "\320\1\x99", IF_8086}, - ITEMPLATE_END -}; - -static struct itemplate instrux_CWDE[] = { - {I_CWDE, 0, {0,0,0}, "\321\1\x98", IF_386}, - ITEMPLATE_END -}; - -static struct itemplate instrux_DAA[] = { - {I_DAA, 0, {0,0,0}, "\1\x27", IF_8086}, - ITEMPLATE_END -}; - -static struct itemplate instrux_DAS[] = { - {I_DAS, 0, {0,0,0}, "\1\x2F", IF_8086}, - ITEMPLATE_END -}; - -static struct itemplate instrux_DB[] = { - ITEMPLATE_END -}; - -static struct itemplate instrux_DD[] = { - ITEMPLATE_END -}; - -static struct itemplate instrux_DEC[] = { - {I_DEC, 1, {REG16,0,0}, "\320\10\x48", IF_8086}, - {I_DEC, 1, {REG32,0,0}, "\321\10\x48", IF_386}, - {I_DEC, 1, {REGMEM|BITS8,0,0}, "\300\1\xFE\201", IF_8086}, - {I_DEC, 1, {REGMEM|BITS16,0,0}, "\320\300\1\xFF\201", IF_8086}, - {I_DEC, 1, {REGMEM|BITS32,0,0}, "\321\300\1\xFF\201", IF_386}, - ITEMPLATE_END -}; - -static struct itemplate instrux_DIV[] = { - {I_DIV, 1, {REGMEM|BITS8,0,0}, "\300\1\xF6\206", IF_8086}, - {I_DIV, 1, {REGMEM|BITS16,0,0}, "\320\300\1\xF7\206", IF_8086}, - {I_DIV, 1, {REGMEM|BITS32,0,0}, "\321\300\1\xF7\206", IF_386}, - ITEMPLATE_END -}; - -static struct itemplate instrux_DIVPD[] = { - {I_DIVPD, 2, {XMMREG,XMMREG,0}, "\3\x66\x0F\x5E\110", IF_WILLAMETTE|IF_SSE2}, - {I_DIVPD, 2, {XMMREG,MEMORY,0}, "\301\3\x66\x0F\x5E\110", IF_WILLAMETTE|IF_SSE2|IF_SM}, - ITEMPLATE_END -}; - -static struct itemplate instrux_DIVPS[] = { - {I_DIVPS, 2, {XMMREG,MEMORY,0}, "\301\331\2\x0F\x5E\110", IF_KATMAI|IF_SSE}, - {I_DIVPS, 2, {XMMREG,XMMREG,0}, "\331\2\x0F\x5E\110", IF_KATMAI|IF_SSE}, - ITEMPLATE_END -}; - -static struct itemplate instrux_DIVSD[] = { - {I_DIVSD, 2, {XMMREG,XMMREG,0}, "\3\xF2\x0F\x5E\110", IF_WILLAMETTE|IF_SSE2}, - {I_DIVSD, 2, {XMMREG,MEMORY,0}, "\301\3\xF2\x0F\x5E\110", IF_WILLAMETTE|IF_SSE2}, - ITEMPLATE_END -}; - -static struct itemplate instrux_DIVSS[] = { - {I_DIVSS, 2, {XMMREG,MEMORY,0}, "\301\333\2\x0F\x5E\110", IF_KATMAI|IF_SSE}, - {I_DIVSS, 2, {XMMREG,XMMREG,0}, "\333\2\x0F\x5E\110", IF_KATMAI|IF_SSE}, - ITEMPLATE_END -}; - -static struct itemplate instrux_DQ[] = { - ITEMPLATE_END -}; - -static struct itemplate instrux_DT[] = { - ITEMPLATE_END -}; - -static struct itemplate instrux_DW[] = { - ITEMPLATE_END -}; - -static struct itemplate instrux_EMMS[] = { - {I_EMMS, 0, {0,0,0}, "\2\x0F\x77", IF_PENT|IF_MMX}, - ITEMPLATE_END -}; - -static struct itemplate instrux_ENTER[] = { - {I_ENTER, 2, {IMMEDIATE,IMMEDIATE,0}, "\1\xC8\30\25", IF_186}, - ITEMPLATE_END -}; - -static struct itemplate instrux_EQU[] = { - {I_EQU, 1, {IMMEDIATE,0,0}, "\0", IF_8086}, - {I_EQU, 2, {IMMEDIATE|COLON,IMMEDIATE,0}, "\0", IF_8086}, - ITEMPLATE_END -}; - -static struct itemplate instrux_F2XM1[] = { - {I_F2XM1, 0, {0,0,0}, "\2\xD9\xF0", IF_8086|IF_FPU}, - ITEMPLATE_END -}; - -static struct itemplate instrux_FABS[] = { - {I_FABS, 0, {0,0,0}, "\2\xD9\xE1", IF_8086|IF_FPU}, - ITEMPLATE_END -}; - -static struct itemplate instrux_FADD[] = { - {I_FADD, 1, {MEMORY|BITS32,0,0}, "\300\1\xD8\200", IF_8086|IF_FPU}, - {I_FADD, 1, {MEMORY|BITS64,0,0}, "\300\1\xDC\200", IF_8086|IF_FPU}, - {I_FADD, 1, {FPUREG|TO,0,0}, "\1\xDC\10\xC0", IF_8086|IF_FPU}, - {I_FADD, 1, {FPUREG,0,0}, "\1\xD8\10\xC0", IF_8086|IF_FPU}, - {I_FADD, 2, {FPUREG,FPU0,0}, "\1\xDC\10\xC0", IF_8086|IF_FPU}, - {I_FADD, 2, {FPU0,FPUREG,0}, "\1\xD8\11\xC0", IF_8086|IF_FPU}, - ITEMPLATE_END -}; - -static struct itemplate instrux_FADDP[] = { - {I_FADDP, 1, {FPUREG,0,0}, "\1\xDE\10\xC0", IF_8086|IF_FPU}, - {I_FADDP, 2, {FPUREG,FPU0,0}, "\1\xDE\10\xC0", IF_8086|IF_FPU}, - ITEMPLATE_END -}; - -static struct itemplate instrux_FBLD[] = { - {I_FBLD, 1, {MEMORY|BITS80,0,0}, "\300\1\xDF\204", IF_8086|IF_FPU}, - {I_FBLD, 1, {MEMORY,0,0}, "\300\1\xDF\204", IF_8086|IF_FPU}, - ITEMPLATE_END -}; - -static struct itemplate instrux_FBSTP[] = { - {I_FBSTP, 1, {MEMORY|BITS80,0,0}, "\300\1\xDF\206", IF_8086|IF_FPU}, - {I_FBSTP, 1, {MEMORY,0,0}, "\300\1\xDF\206", IF_8086|IF_FPU}, - ITEMPLATE_END -}; - -static struct itemplate instrux_FCHS[] = { - {I_FCHS, 0, {0,0,0}, "\2\xD9\xE0", IF_8086|IF_FPU}, - ITEMPLATE_END -}; - -static struct itemplate instrux_FCLEX[] = { - {I_FCLEX, 0, {0,0,0}, "\3\x9B\xDB\xE2", IF_8086|IF_FPU}, - ITEMPLATE_END -}; - -static struct itemplate instrux_FCMOVB[] = { - {I_FCMOVB, 1, {FPUREG,0,0}, "\1\xDA\10\xC0", IF_P6|IF_FPU}, - {I_FCMOVB, 2, {FPU0,FPUREG,0}, "\1\xDA\11\xC0", IF_P6|IF_FPU}, - ITEMPLATE_END -}; - -static struct itemplate instrux_FCMOVBE[] = { - {I_FCMOVBE, 1, {FPUREG,0,0}, "\1\xDA\10\xD0", IF_P6|IF_FPU}, - {I_FCMOVBE, 2, {FPU0,FPUREG,0}, "\1\xDA\11\xD0", IF_P6|IF_FPU}, - ITEMPLATE_END -}; - -static struct itemplate instrux_FCMOVE[] = { - {I_FCMOVE, 1, {FPUREG,0,0}, "\1\xDA\10\xC8", IF_P6|IF_FPU}, - {I_FCMOVE, 2, {FPU0,FPUREG,0}, "\1\xDA\11\xC8", IF_P6|IF_FPU}, - ITEMPLATE_END -}; - -static struct itemplate instrux_FCMOVNB[] = { - {I_FCMOVNB, 1, {FPUREG,0,0}, "\1\xDB\10\xC0", IF_P6|IF_FPU}, - {I_FCMOVNB, 2, {FPU0,FPUREG,0}, "\1\xDB\11\xC0", IF_P6|IF_FPU}, - ITEMPLATE_END -}; - -static struct itemplate instrux_FCMOVNBE[] = { - {I_FCMOVNBE, 1, {FPUREG,0,0}, "\1\xDB\10\xD0", IF_P6|IF_FPU}, - {I_FCMOVNBE, 2, {FPU0,FPUREG,0}, "\1\xDB\11\xD0", IF_P6|IF_FPU}, - ITEMPLATE_END -}; - -static struct itemplate instrux_FCMOVNE[] = { - {I_FCMOVNE, 1, {FPUREG,0,0}, "\1\xDB\10\xC8", IF_P6|IF_FPU}, - {I_FCMOVNE, 2, {FPU0,FPUREG,0}, "\1\xDB\11\xC8", IF_P6|IF_FPU}, - ITEMPLATE_END -}; - -static struct itemplate instrux_FCMOVNU[] = { - {I_FCMOVNU, 1, {FPUREG,0,0}, "\1\xDB\10\xD8", IF_P6|IF_FPU}, - {I_FCMOVNU, 2, {FPU0,FPUREG,0}, "\1\xDB\11\xD8", IF_P6|IF_FPU}, - ITEMPLATE_END -}; - -static struct itemplate instrux_FCMOVU[] = { - {I_FCMOVU, 1, {FPUREG,0,0}, "\1\xDA\10\xD8", IF_P6|IF_FPU}, - {I_FCMOVU, 2, {FPU0,FPUREG,0}, "\1\xDA\11\xD8", IF_P6|IF_FPU}, - ITEMPLATE_END -}; - -static struct itemplate instrux_FCOM[] = { - {I_FCOM, 1, {MEMORY|BITS32,0,0}, "\300\1\xD8\202", IF_8086|IF_FPU}, - {I_FCOM, 1, {MEMORY|BITS64,0,0}, "\300\1\xDC\202", IF_8086|IF_FPU}, - {I_FCOM, 1, {FPUREG,0,0}, "\1\xD8\10\xD0", IF_8086|IF_FPU}, - {I_FCOM, 2, {FPU0,FPUREG,0}, "\1\xD8\11\xD0", IF_8086|IF_FPU}, - ITEMPLATE_END -}; - -static struct itemplate instrux_FCOMI[] = { - {I_FCOMI, 1, {FPUREG,0,0}, "\1\xDB\10\xF0", IF_P6|IF_FPU}, - {I_FCOMI, 2, {FPU0,FPUREG,0}, "\1\xDB\11\xF0", IF_P6|IF_FPU}, - ITEMPLATE_END -}; - -static struct itemplate instrux_FCOMIP[] = { - {I_FCOMIP, 1, {FPUREG,0,0}, "\1\xDF\10\xF0", IF_P6|IF_FPU}, - {I_FCOMIP, 2, {FPU0,FPUREG,0}, "\1\xDF\11\xF0", IF_P6|IF_FPU}, - ITEMPLATE_END -}; - -static struct itemplate instrux_FCOMP[] = { - {I_FCOMP, 1, {MEMORY|BITS32,0,0}, "\300\1\xD8\203", IF_8086|IF_FPU}, - {I_FCOMP, 1, {MEMORY|BITS64,0,0}, "\300\1\xDC\203", IF_8086|IF_FPU}, - {I_FCOMP, 1, {FPUREG,0,0}, "\1\xD8\10\xD8", IF_8086|IF_FPU}, - {I_FCOMP, 2, {FPU0,FPUREG,0}, "\1\xD8\11\xD8", IF_8086|IF_FPU}, - ITEMPLATE_END -}; - -static struct itemplate instrux_FCOMPP[] = { - {I_FCOMPP, 0, {0,0,0}, "\2\xDE\xD9", IF_8086|IF_FPU}, - ITEMPLATE_END -}; - -static struct itemplate instrux_FCOS[] = { - {I_FCOS, 0, {0,0,0}, "\2\xD9\xFF", IF_386|IF_FPU}, - ITEMPLATE_END -}; - -static struct itemplate instrux_FDECSTP[] = { - {I_FDECSTP, 0, {0,0,0}, "\2\xD9\xF6", IF_8086|IF_FPU}, - ITEMPLATE_END -}; - -static struct itemplate instrux_FDISI[] = { - {I_FDISI, 0, {0,0,0}, "\3\x9B\xDB\xE1", IF_8086|IF_FPU}, - ITEMPLATE_END -}; - -static struct itemplate instrux_FDIV[] = { - {I_FDIV, 1, {MEMORY|BITS32,0,0}, "\300\1\xD8\206", IF_8086|IF_FPU}, - {I_FDIV, 1, {MEMORY|BITS64,0,0}, "\300\1\xDC\206", IF_8086|IF_FPU}, - {I_FDIV, 1, {FPUREG|TO,0,0}, "\1\xDC\10\xF8", IF_8086|IF_FPU}, - {I_FDIV, 2, {FPUREG,FPU0,0}, "\1\xDC\10\xF8", IF_8086|IF_FPU}, - {I_FDIV, 1, {FPUREG,0,0}, "\1\xD8\10\xF0", IF_8086|IF_FPU}, - {I_FDIV, 2, {FPU0,FPUREG,0}, "\1\xD8\11\xF0", IF_8086|IF_FPU}, - ITEMPLATE_END -}; - -static struct itemplate instrux_FDIVP[] = { - {I_FDIVP, 2, {FPUREG,FPU0,0}, "\1\xDE\10\xF8", IF_8086|IF_FPU}, - {I_FDIVP, 1, {FPUREG,0,0}, "\1\xDE\10\xF8", IF_8086|IF_FPU}, - ITEMPLATE_END -}; - -static struct itemplate instrux_FDIVR[] = { - {I_FDIVR, 1, {MEMORY|BITS32,0,0}, "\300\1\xD8\207", IF_8086|IF_FPU}, - {I_FDIVR, 1, {MEMORY|BITS64,0,0}, "\300\1\xDC\207", IF_8086|IF_FPU}, - {I_FDIVR, 1, {FPUREG|TO,0,0}, "\1\xDC\10\xF0", IF_8086|IF_FPU}, - {I_FDIVR, 2, {FPUREG,FPU0,0}, "\1\xDC\10\xF0", IF_8086|IF_FPU}, - {I_FDIVR, 1, {FPUREG,0,0}, "\1\xD8\10\xF8", IF_8086|IF_FPU}, - {I_FDIVR, 2, {FPU0,FPUREG,0}, "\1\xD8\11\xF8", IF_8086|IF_FPU}, - ITEMPLATE_END -}; - -static struct itemplate instrux_FDIVRP[] = { - {I_FDIVRP, 1, {FPUREG,0,0}, "\1\xDE\10\xF0", IF_8086|IF_FPU}, - {I_FDIVRP, 2, {FPUREG,FPU0,0}, "\1\xDE\10\xF0", IF_8086|IF_FPU}, - ITEMPLATE_END -}; - -static struct itemplate instrux_FEMMS[] = { - {I_FEMMS, 0, {0,0,0}, "\2\x0F\x0E", IF_PENT|IF_3DNOW}, - ITEMPLATE_END -}; - -static struct itemplate instrux_FENI[] = { - {I_FENI, 0, {0,0,0}, "\3\x9B\xDB\xE0", IF_8086|IF_FPU}, - ITEMPLATE_END -}; - -static struct itemplate instrux_FFREE[] = { - {I_FFREE, 1, {FPUREG,0,0}, "\1\xDD\10\xC0", IF_8086|IF_FPU}, - ITEMPLATE_END -}; - -static struct itemplate instrux_FFREEP[] = { - {I_FFREEP, 1, {FPUREG,0,0}, "\1\xDF\10\xC0", IF_286|IF_FPU|IF_UNDOC}, - ITEMPLATE_END -}; - -static struct itemplate instrux_FIADD[] = { - {I_FIADD, 1, {MEMORY|BITS32,0,0}, "\300\1\xDA\200", IF_8086|IF_FPU}, - {I_FIADD, 1, {MEMORY|BITS16,0,0}, "\300\1\xDE\200", IF_8086|IF_FPU}, - ITEMPLATE_END -}; - -static struct itemplate instrux_FICOM[] = { - {I_FICOM, 1, {MEMORY|BITS32,0,0}, "\300\1\xDA\202", IF_8086|IF_FPU}, - {I_FICOM, 1, {MEMORY|BITS16,0,0}, "\300\1\xDE\202", IF_8086|IF_FPU}, - ITEMPLATE_END -}; - -static struct itemplate instrux_FICOMP[] = { - {I_FICOMP, 1, {MEMORY|BITS32,0,0}, "\300\1\xDA\203", IF_8086|IF_FPU}, - {I_FICOMP, 1, {MEMORY|BITS16,0,0}, "\300\1\xDE\203", IF_8086|IF_FPU}, - ITEMPLATE_END -}; - -static struct itemplate instrux_FIDIV[] = { - {I_FIDIV, 1, {MEMORY|BITS32,0,0}, "\300\1\xDA\206", IF_8086|IF_FPU}, - {I_FIDIV, 1, {MEMORY|BITS16,0,0}, "\300\1\xDE\206", IF_8086|IF_FPU}, - ITEMPLATE_END -}; - -static struct itemplate instrux_FIDIVR[] = { - {I_FIDIVR, 1, {MEMORY|BITS32,0,0}, "\300\1\xDA\207", IF_8086|IF_FPU}, - {I_FIDIVR, 1, {MEMORY|BITS16,0,0}, "\300\1\xDE\207", IF_8086|IF_FPU}, - ITEMPLATE_END -}; - -static struct itemplate instrux_FILD[] = { - {I_FILD, 1, {MEMORY|BITS32,0,0}, "\300\1\xDB\200", IF_8086|IF_FPU}, - {I_FILD, 1, {MEMORY|BITS16,0,0}, "\300\1\xDF\200", IF_8086|IF_FPU}, - {I_FILD, 1, {MEMORY|BITS64,0,0}, "\300\1\xDF\205", IF_8086|IF_FPU}, - ITEMPLATE_END -}; - -static struct itemplate instrux_FIMUL[] = { - {I_FIMUL, 1, {MEMORY|BITS32,0,0}, "\300\1\xDA\201", IF_8086|IF_FPU}, - {I_FIMUL, 1, {MEMORY|BITS16,0,0}, "\300\1\xDE\201", IF_8086|IF_FPU}, - ITEMPLATE_END -}; - -static struct itemplate instrux_FINCSTP[] = { - {I_FINCSTP, 0, {0,0,0}, "\2\xD9\xF7", IF_8086|IF_FPU}, - ITEMPLATE_END -}; - -static struct itemplate instrux_FINIT[] = { - {I_FINIT, 0, {0,0,0}, "\3\x9B\xDB\xE3", IF_8086|IF_FPU}, - ITEMPLATE_END -}; - -static struct itemplate instrux_FIST[] = { - {I_FIST, 1, {MEMORY|BITS32,0,0}, "\300\1\xDB\202", IF_8086|IF_FPU}, - {I_FIST, 1, {MEMORY|BITS16,0,0}, "\300\1\xDF\202", IF_8086|IF_FPU}, - ITEMPLATE_END -}; - -static struct itemplate instrux_FISTP[] = { - {I_FISTP, 1, {MEMORY|BITS32,0,0}, "\300\1\xDB\203", IF_8086|IF_FPU}, - {I_FISTP, 1, {MEMORY|BITS16,0,0}, "\300\1\xDF\203", IF_8086|IF_FPU}, - {I_FISTP, 1, {MEMORY|BITS64,0,0}, "\300\1\xDF\207", IF_8086|IF_FPU}, - ITEMPLATE_END -}; - -static struct itemplate instrux_FISTTP[] = { - {I_FISTTP, 1, {MEMORY|BITS32,0,0}, "\300\1\xDD\201", IF_PRESCOTT|IF_FPU}, - {I_FISTTP, 1, {MEMORY|BITS16,0,0}, "\300\1\xDB\201", IF_PRESCOTT|IF_FPU}, - {I_FISTTP, 1, {MEMORY|BITS64,0,0}, "\300\1\xDF\201", IF_PRESCOTT|IF_FPU}, - ITEMPLATE_END -}; - -static struct itemplate instrux_FISUB[] = { - {I_FISUB, 1, {MEMORY|BITS32,0,0}, "\300\1\xDA\204", IF_8086|IF_FPU}, - {I_FISUB, 1, {MEMORY|BITS16,0,0}, "\300\1\xDE\204", IF_8086|IF_FPU}, - ITEMPLATE_END -}; - -static struct itemplate instrux_FISUBR[] = { - {I_FISUBR, 1, {MEMORY|BITS32,0,0}, "\300\1\xDA\205", IF_8086|IF_FPU}, - {I_FISUBR, 1, {MEMORY|BITS16,0,0}, "\300\1\xDE\205", IF_8086|IF_FPU}, - ITEMPLATE_END -}; - -static struct itemplate instrux_FLD[] = { - {I_FLD, 1, {MEMORY|BITS32,0,0}, "\300\1\xD9\200", IF_8086|IF_FPU}, - {I_FLD, 1, {MEMORY|BITS64,0,0}, "\300\1\xDD\200", IF_8086|IF_FPU}, - {I_FLD, 1, {MEMORY|BITS80,0,0}, "\300\1\xDB\205", IF_8086|IF_FPU}, - {I_FLD, 1, {FPUREG,0,0}, "\1\xD9\10\xC0", IF_8086|IF_FPU}, - ITEMPLATE_END -}; - -static struct itemplate instrux_FLD1[] = { - {I_FLD1, 0, {0,0,0}, "\2\xD9\xE8", IF_8086|IF_FPU}, - ITEMPLATE_END -}; - -static struct itemplate instrux_FLDCW[] = { - {I_FLDCW, 1, {MEMORY,0,0}, "\300\1\xD9\205", IF_8086|IF_FPU|IF_SW}, - ITEMPLATE_END -}; - -static struct itemplate instrux_FLDENV[] = { - {I_FLDENV, 1, {MEMORY,0,0}, "\300\1\xD9\204", IF_8086|IF_FPU}, - ITEMPLATE_END -}; - -static struct itemplate instrux_FLDL2E[] = { - {I_FLDL2E, 0, {0,0,0}, "\2\xD9\xEA", IF_8086|IF_FPU}, - ITEMPLATE_END -}; - -static struct itemplate instrux_FLDL2T[] = { - {I_FLDL2T, 0, {0,0,0}, "\2\xD9\xE9", IF_8086|IF_FPU}, - ITEMPLATE_END -}; - -static struct itemplate instrux_FLDLG2[] = { - {I_FLDLG2, 0, {0,0,0}, "\2\xD9\xEC", IF_8086|IF_FPU}, - ITEMPLATE_END -}; - -static struct itemplate instrux_FLDLN2[] = { - {I_FLDLN2, 0, {0,0,0}, "\2\xD9\xED", IF_8086|IF_FPU}, - ITEMPLATE_END -}; - -static struct itemplate instrux_FLDPI[] = { - {I_FLDPI, 0, {0,0,0}, "\2\xD9\xEB", IF_8086|IF_FPU}, - ITEMPLATE_END -}; - -static struct itemplate instrux_FLDZ[] = { - {I_FLDZ, 0, {0,0,0}, "\2\xD9\xEE", IF_8086|IF_FPU}, - ITEMPLATE_END -}; - -static struct itemplate instrux_FMUL[] = { - {I_FMUL, 1, {MEMORY|BITS32,0,0}, "\300\1\xD8\201", IF_8086|IF_FPU}, - {I_FMUL, 1, {MEMORY|BITS64,0,0}, "\300\1\xDC\201", IF_8086|IF_FPU}, - {I_FMUL, 1, {FPUREG|TO,0,0}, "\1\xDC\10\xC8", IF_8086|IF_FPU}, - {I_FMUL, 2, {FPUREG,FPU0,0}, "\1\xDC\10\xC8", IF_8086|IF_FPU}, - {I_FMUL, 1, {FPUREG,0,0}, "\1\xD8\10\xC8", IF_8086|IF_FPU}, - {I_FMUL, 2, {FPU0,FPUREG,0}, "\1\xD8\11\xC8", IF_8086|IF_FPU}, - ITEMPLATE_END -}; - -static struct itemplate instrux_FMULP[] = { - {I_FMULP, 1, {FPUREG,0,0}, "\1\xDE\10\xC8", IF_8086|IF_FPU}, - {I_FMULP, 2, {FPUREG,FPU0,0}, "\1\xDE\10\xC8", IF_8086|IF_FPU}, - ITEMPLATE_END -}; - -static struct itemplate instrux_FNCLEX[] = { - {I_FNCLEX, 0, {0,0,0}, "\2\xDB\xE2", IF_8086|IF_FPU}, - ITEMPLATE_END -}; - -static struct itemplate instrux_FNDISI[] = { - {I_FNDISI, 0, {0,0,0}, "\2\xDB\xE1", IF_8086|IF_FPU}, - ITEMPLATE_END -}; - -static struct itemplate instrux_FNENI[] = { - {I_FNENI, 0, {0,0,0}, "\2\xDB\xE0", IF_8086|IF_FPU}, - ITEMPLATE_END -}; - -static struct itemplate instrux_FNINIT[] = { - {I_FNINIT, 0, {0,0,0}, "\2\xDB\xE3", IF_8086|IF_FPU}, - ITEMPLATE_END -}; - -static struct itemplate instrux_FNOP[] = { - {I_FNOP, 0, {0,0,0}, "\2\xD9\xD0", IF_8086|IF_FPU}, - ITEMPLATE_END -}; - -static struct itemplate instrux_FNSAVE[] = { - {I_FNSAVE, 1, {MEMORY,0,0}, "\300\1\xDD\206", IF_8086|IF_FPU}, - ITEMPLATE_END -}; - -static struct itemplate instrux_FNSTCW[] = { - {I_FNSTCW, 1, {MEMORY,0,0}, "\300\1\xD9\207", IF_8086|IF_FPU|IF_SW}, - ITEMPLATE_END -}; - -static struct itemplate instrux_FNSTENV[] = { - {I_FNSTENV, 1, {MEMORY,0,0}, "\300\1\xD9\206", IF_8086|IF_FPU}, - ITEMPLATE_END -}; - -static struct itemplate instrux_FNSTSW[] = { - {I_FNSTSW, 1, {MEMORY,0,0}, "\300\1\xDD\207", IF_8086|IF_FPU|IF_SW}, - {I_FNSTSW, 1, {REG_AX,0,0}, "\2\xDF\xE0", IF_286|IF_FPU}, - ITEMPLATE_END -}; - -static struct itemplate instrux_FPATAN[] = { - {I_FPATAN, 0, {0,0,0}, "\2\xD9\xF3", IF_8086|IF_FPU}, - ITEMPLATE_END -}; - -static struct itemplate instrux_FPREM[] = { - {I_FPREM, 0, {0,0,0}, "\2\xD9\xF8", IF_8086|IF_FPU}, - ITEMPLATE_END -}; - -static struct itemplate instrux_FPREM1[] = { - {I_FPREM1, 0, {0,0,0}, "\2\xD9\xF5", IF_386|IF_FPU}, - ITEMPLATE_END -}; - -static struct itemplate instrux_FPTAN[] = { - {I_FPTAN, 0, {0,0,0}, "\2\xD9\xF2", IF_8086|IF_FPU}, - ITEMPLATE_END -}; - -static struct itemplate instrux_FRNDINT[] = { - {I_FRNDINT, 0, {0,0,0}, "\2\xD9\xFC", IF_8086|IF_FPU}, - ITEMPLATE_END -}; - -static struct itemplate instrux_FRSTOR[] = { - {I_FRSTOR, 1, {MEMORY,0,0}, "\300\1\xDD\204", IF_8086|IF_FPU}, - ITEMPLATE_END -}; - -static struct itemplate instrux_FSAVE[] = { - {I_FSAVE, 1, {MEMORY,0,0}, "\300\2\x9B\xDD\206", IF_8086|IF_FPU}, - ITEMPLATE_END -}; - -static struct itemplate instrux_FSCALE[] = { - {I_FSCALE, 0, {0,0,0}, "\2\xD9\xFD", IF_8086|IF_FPU}, - ITEMPLATE_END -}; - -static struct itemplate instrux_FSETPM[] = { - {I_FSETPM, 0, {0,0,0}, "\2\xDB\xE4", IF_286|IF_FPU}, - ITEMPLATE_END -}; - -static struct itemplate instrux_FSIN[] = { - {I_FSIN, 0, {0,0,0}, "\2\xD9\xFE", IF_386|IF_FPU}, - ITEMPLATE_END -}; - -static struct itemplate instrux_FSINCOS[] = { - {I_FSINCOS, 0, {0,0,0}, "\2\xD9\xFB", IF_386|IF_FPU}, - ITEMPLATE_END -}; - -static struct itemplate instrux_FSQRT[] = { - {I_FSQRT, 0, {0,0,0}, "\2\xD9\xFA", IF_8086|IF_FPU}, - ITEMPLATE_END -}; - -static struct itemplate instrux_FST[] = { - {I_FST, 1, {MEMORY|BITS32,0,0}, "\300\1\xD9\202", IF_8086|IF_FPU}, - {I_FST, 1, {MEMORY|BITS64,0,0}, "\300\1\xDD\202", IF_8086|IF_FPU}, - {I_FST, 1, {FPUREG,0,0}, "\1\xDD\10\xD0", IF_8086|IF_FPU}, - ITEMPLATE_END -}; - -static struct itemplate instrux_FSTCW[] = { - {I_FSTCW, 1, {MEMORY,0,0}, "\300\2\x9B\xD9\207", IF_8086|IF_FPU|IF_SW}, - ITEMPLATE_END -}; - -static struct itemplate instrux_FSTENV[] = { - {I_FSTENV, 1, {MEMORY,0,0}, "\300\2\x9B\xD9\206", IF_8086|IF_FPU}, - ITEMPLATE_END -}; - -static struct itemplate instrux_FSTP[] = { - {I_FSTP, 1, {MEMORY|BITS32,0,0}, "\300\1\xD9\203", IF_8086|IF_FPU}, - {I_FSTP, 1, {MEMORY|BITS64,0,0}, "\300\1\xDD\203", IF_8086|IF_FPU}, - {I_FSTP, 1, {MEMORY|BITS80,0,0}, "\300\1\xDB\207", IF_8086|IF_FPU}, - {I_FSTP, 1, {FPUREG,0,0}, "\1\xDD\10\xD8", IF_8086|IF_FPU}, - ITEMPLATE_END -}; - -static struct itemplate instrux_FSTSW[] = { - {I_FSTSW, 1, {MEMORY,0,0}, "\300\2\x9B\xDD\207", IF_8086|IF_FPU|IF_SW}, - {I_FSTSW, 1, {REG_AX,0,0}, "\3\x9B\xDF\xE0", IF_286|IF_FPU}, - ITEMPLATE_END -}; - -static struct itemplate instrux_FSUB[] = { - {I_FSUB, 1, {MEMORY|BITS32,0,0}, "\300\1\xD8\204", IF_8086|IF_FPU}, - {I_FSUB, 1, {MEMORY|BITS64,0,0}, "\300\1\xDC\204", IF_8086|IF_FPU}, - {I_FSUB, 1, {FPUREG|TO,0,0}, "\1\xDC\10\xE8", IF_8086|IF_FPU}, - {I_FSUB, 2, {FPUREG,FPU0,0}, "\1\xDC\10\xE8", IF_8086|IF_FPU}, - {I_FSUB, 1, {FPUREG,0,0}, "\1\xD8\10\xE0", IF_8086|IF_FPU}, - {I_FSUB, 2, {FPU0,FPUREG,0}, "\1\xD8\11\xE0", IF_8086|IF_FPU}, - ITEMPLATE_END -}; - -static struct itemplate instrux_FSUBP[] = { - {I_FSUBP, 1, {FPUREG,0,0}, "\1\xDE\10\xE8", IF_8086|IF_FPU}, - {I_FSUBP, 2, {FPUREG,FPU0,0}, "\1\xDE\10\xE8", IF_8086|IF_FPU}, - ITEMPLATE_END -}; - -static struct itemplate instrux_FSUBR[] = { - {I_FSUBR, 1, {MEMORY|BITS32,0,0}, "\300\1\xD8\205", IF_8086|IF_FPU}, - {I_FSUBR, 1, {MEMORY|BITS64,0,0}, "\300\1\xDC\205", IF_8086|IF_FPU}, - {I_FSUBR, 1, {FPUREG|TO,0,0}, "\1\xDC\10\xE0", IF_8086|IF_FPU}, - {I_FSUBR, 2, {FPUREG,FPU0,0}, "\1\xDC\10\xE0", IF_8086|IF_FPU}, - {I_FSUBR, 1, {FPUREG,0,0}, "\1\xD8\10\xE8", IF_8086|IF_FPU}, - {I_FSUBR, 2, {FPU0,FPUREG,0}, "\1\xD8\11\xE8", IF_8086|IF_FPU}, - ITEMPLATE_END -}; - -static struct itemplate instrux_FSUBRP[] = { - {I_FSUBRP, 1, {FPUREG,0,0}, "\1\xDE\10\xE0", IF_8086|IF_FPU}, - {I_FSUBRP, 2, {FPUREG,FPU0,0}, "\1\xDE\10\xE0", IF_8086|IF_FPU}, - ITEMPLATE_END -}; - -static struct itemplate instrux_FTST[] = { - {I_FTST, 0, {0,0,0}, "\2\xD9\xE4", IF_8086|IF_FPU}, - ITEMPLATE_END -}; - -static struct itemplate instrux_FUCOM[] = { - {I_FUCOM, 1, {FPUREG,0,0}, "\1\xDD\10\xE0", IF_386|IF_FPU}, - {I_FUCOM, 2, {FPU0,FPUREG,0}, "\1\xDD\11\xE0", IF_386|IF_FPU}, - ITEMPLATE_END -}; - -static struct itemplate instrux_FUCOMI[] = { - {I_FUCOMI, 1, {FPUREG,0,0}, "\1\xDB\10\xE8", IF_P6|IF_FPU}, - {I_FUCOMI, 2, {FPU0,FPUREG,0}, "\1\xDB\11\xE8", IF_P6|IF_FPU}, - ITEMPLATE_END -}; - -static struct itemplate instrux_FUCOMIP[] = { - {I_FUCOMIP, 1, {FPUREG,0,0}, "\1\xDF\10\xE8", IF_P6|IF_FPU}, - {I_FUCOMIP, 2, {FPU0,FPUREG,0}, "\1\xDF\11\xE8", IF_P6|IF_FPU}, - ITEMPLATE_END -}; - -static struct itemplate instrux_FUCOMP[] = { - {I_FUCOMP, 1, {FPUREG,0,0}, "\1\xDD\10\xE8", IF_386|IF_FPU}, - {I_FUCOMP, 2, {FPU0,FPUREG,0}, "\1\xDD\11\xE8", IF_386|IF_FPU}, - ITEMPLATE_END -}; - -static struct itemplate instrux_FUCOMPP[] = { - {I_FUCOMPP, 0, {0,0,0}, "\2\xDA\xE9", IF_386|IF_FPU}, - ITEMPLATE_END -}; - -static struct itemplate instrux_FWAIT[] = { - {I_FWAIT, 0, {0,0,0}, "\1\x9B", IF_8086}, - ITEMPLATE_END -}; - -static struct itemplate instrux_FXAM[] = { - {I_FXAM, 0, {0,0,0}, "\2\xD9\xE5", IF_8086|IF_FPU}, - ITEMPLATE_END -}; - -static struct itemplate instrux_FXCH[] = { - {I_FXCH, 0, {0,0,0}, "\2\xD9\xC9", IF_8086|IF_FPU}, - {I_FXCH, 1, {FPUREG,0,0}, "\1\xD9\10\xC8", IF_8086|IF_FPU}, - {I_FXCH, 2, {FPUREG,FPU0,0}, "\1\xD9\10\xC8", IF_8086|IF_FPU}, - {I_FXCH, 2, {FPU0,FPUREG,0}, "\1\xD9\11\xC8", IF_8086|IF_FPU}, - ITEMPLATE_END -}; - -static struct itemplate instrux_FXRSTOR[] = { - {I_FXRSTOR, 1, {MEMORY,0,0}, "\300\2\x0F\xAE\201", IF_P6|IF_SSE|IF_FPU}, - ITEMPLATE_END -}; - -static struct itemplate instrux_FXSAVE[] = { - {I_FXSAVE, 1, {MEMORY,0,0}, "\300\2\x0F\xAE\200", IF_P6|IF_SSE|IF_FPU}, - ITEMPLATE_END -}; - -static struct itemplate instrux_FXTRACT[] = { - {I_FXTRACT, 0, {0,0,0}, "\2\xD9\xF4", IF_8086|IF_FPU}, - ITEMPLATE_END -}; - -static struct itemplate instrux_FYL2X[] = { - {I_FYL2X, 0, {0,0,0}, "\2\xD9\xF1", IF_8086|IF_FPU}, - ITEMPLATE_END -}; - -static struct itemplate instrux_FYL2XP1[] = { - {I_FYL2XP1, 0, {0,0,0}, "\2\xD9\xF9", IF_8086|IF_FPU}, - ITEMPLATE_END -}; - -static struct itemplate instrux_HADDPD[] = { - {I_HADDPD, 2, {XMMREG,MEMORY,0}, "\301\3\x66\x0F\x7C\110", IF_PRESCOTT|IF_SSE3|IF_SM}, - {I_HADDPD, 2, {XMMREG,XMMREG,0}, "\3\x66\x0F\x7C\110", IF_PRESCOTT|IF_SSE3}, - ITEMPLATE_END -}; - -static struct itemplate instrux_HADDPS[] = { - {I_HADDPS, 2, {XMMREG,MEMORY,0}, "\301\3\xF2\x0F\x7C\110", IF_PRESCOTT|IF_SSE3|IF_SM}, - {I_HADDPS, 2, {XMMREG,XMMREG,0}, "\3\xF2\x0F\x7C\110", IF_PRESCOTT|IF_SSE3}, - ITEMPLATE_END -}; - -static struct itemplate instrux_HLT[] = { - {I_HLT, 0, {0,0,0}, "\1\xF4", IF_8086|IF_PRIV}, - ITEMPLATE_END -}; - -static struct itemplate instrux_HSUBPD[] = { - {I_HSUBPD, 2, {XMMREG,MEMORY,0}, "\301\3\x66\x0F\x7D\110", IF_PRESCOTT|IF_SSE3|IF_SM}, - {I_HSUBPD, 2, {XMMREG,XMMREG,0}, "\3\x66\x0F\x7D\110", IF_PRESCOTT|IF_SSE3}, - ITEMPLATE_END -}; - -static struct itemplate instrux_HSUBPS[] = { - {I_HSUBPS, 2, {XMMREG,MEMORY,0}, "\301\3\xF2\x0F\x7D\110", IF_PRESCOTT|IF_SSE3|IF_SM}, - {I_HSUBPS, 2, {XMMREG,XMMREG,0}, "\3\xF2\x0F\x7D\110", IF_PRESCOTT|IF_SSE3}, - ITEMPLATE_END -}; - -static struct itemplate instrux_IBTS[] = { - {I_IBTS, 2, {MEMORY,REG16,0}, "\320\300\2\x0F\xA7\101", IF_386|IF_SW|IF_UNDOC}, - {I_IBTS, 2, {REG16,REG16,0}, "\320\2\x0F\xA7\101", IF_386|IF_UNDOC}, - {I_IBTS, 2, {MEMORY,REG32,0}, "\321\300\2\x0F\xA7\101", IF_386|IF_SD|IF_UNDOC}, - {I_IBTS, 2, {REG32,REG32,0}, "\321\2\x0F\xA7\101", IF_386|IF_UNDOC}, - ITEMPLATE_END -}; - -static struct itemplate instrux_ICEBP[] = { - {I_ICEBP, 0, {0,0,0}, "\1\xF1", IF_386}, - ITEMPLATE_END -}; - -static struct itemplate instrux_IDIV[] = { - {I_IDIV, 1, {REGMEM|BITS8,0,0}, "\300\1\xF6\207", IF_8086}, - {I_IDIV, 1, {REGMEM|BITS16,0,0}, "\320\300\1\xF7\207", IF_8086}, - {I_IDIV, 1, {REGMEM|BITS32,0,0}, "\321\300\1\xF7\207", IF_386}, - ITEMPLATE_END -}; - -static struct itemplate instrux_IMUL[] = { - {I_IMUL, 1, {REGMEM|BITS8,0,0}, "\300\1\xF6\205", IF_8086}, - {I_IMUL, 1, {REGMEM|BITS16,0,0}, "\320\300\1\xF7\205", IF_8086}, - {I_IMUL, 1, {REGMEM|BITS32,0,0}, "\321\300\1\xF7\205", IF_386}, - {I_IMUL, 2, {REG16,MEMORY,0}, "\320\301\2\x0F\xAF\110", IF_386|IF_SM}, - {I_IMUL, 2, {REG16,REG16,0}, "\320\2\x0F\xAF\110", IF_386}, - {I_IMUL, 2, {REG32,MEMORY,0}, "\321\301\2\x0F\xAF\110", IF_386|IF_SM}, - {I_IMUL, 2, {REG32,REG32,0}, "\321\2\x0F\xAF\110", IF_386}, - {I_IMUL, 3, {REG16,MEMORY,IMMEDIATE|BITS8}, "\320\301\1\x6B\110\16", IF_186|IF_SM}, - {I_IMUL, 3, {REG16,MEMORY,SBYTE}, "\320\301\1\x6B\110\16", IF_186|IF_SM}, - {I_IMUL, 3, {REG16,MEMORY,IMMEDIATE|BITS16}, "\320\301\1\x69\110\32", IF_186|IF_SM}, - {I_IMUL, 3, {REG16,MEMORY,IMMEDIATE}, "\320\301\135\1\x69\110\132", IF_186|IF_SM}, - {I_IMUL, 3, {REG16,REG16,IMMEDIATE|BITS8}, "\320\1\x6B\110\16", IF_186}, - {I_IMUL, 3, {REG16,REG16,SBYTE}, "\320\1\x6B\110\16", IF_186|IF_SM}, - {I_IMUL, 3, {REG16,REG16,IMMEDIATE|BITS16}, "\320\1\x69\110\32", IF_186}, - {I_IMUL, 3, {REG16,REG16,IMMEDIATE}, "\320\135\1\x69\110\132", IF_186|IF_SM}, - {I_IMUL, 3, {REG32,MEMORY,IMMEDIATE|BITS8}, "\321\301\1\x6B\110\16", IF_386|IF_SM}, - {I_IMUL, 3, {REG32,MEMORY,SBYTE}, "\321\301\1\x6B\110\16", IF_386|IF_SM}, - {I_IMUL, 3, {REG32,MEMORY,IMMEDIATE|BITS32}, "\321\301\1\x69\110\42", IF_386|IF_SM}, - {I_IMUL, 3, {REG32,MEMORY,IMMEDIATE}, "\321\301\145\1\x69\110\142", IF_386|IF_SM}, - {I_IMUL, 3, {REG32,REG32,IMMEDIATE|BITS8}, "\321\1\x6B\110\16", IF_386}, - {I_IMUL, 3, {REG32,REG32,SBYTE}, "\321\1\x6B\110\16", IF_386|IF_SM}, - {I_IMUL, 3, {REG32,REG32,IMMEDIATE|BITS32}, "\321\1\x69\110\42", IF_386}, - {I_IMUL, 3, {REG32,REG32,IMMEDIATE}, "\321\145\1\x69\110\142", IF_386|IF_SM}, - {I_IMUL, 2, {REG16,IMMEDIATE|BITS8,0}, "\320\1\x6B\100\15", IF_186}, - {I_IMUL, 2, {REG16,SBYTE,0}, "\320\1\x6B\100\15", IF_186|IF_SM}, - {I_IMUL, 2, {REG16,IMMEDIATE|BITS16,0}, "\320\1\x69\100\31", IF_186}, - {I_IMUL, 2, {REG16,IMMEDIATE,0}, "\320\134\1\x69\100\131", IF_186|IF_SM}, - {I_IMUL, 2, {REG32,IMMEDIATE|BITS8,0}, "\321\1\x6B\100\15", IF_386}, - {I_IMUL, 2, {REG32,SBYTE,0}, "\321\1\x6B\100\15", IF_386|IF_SM}, - {I_IMUL, 2, {REG32,IMMEDIATE|BITS32,0}, "\321\1\x69\100\41", IF_386}, - {I_IMUL, 2, {REG32,IMMEDIATE,0}, "\321\144\1\x69\100\141", IF_386|IF_SM}, - ITEMPLATE_END -}; - -static struct itemplate instrux_IN[] = { - {I_IN, 2, {REG_AL,IMMEDIATE,0}, "\1\xE4\25", IF_8086|IF_SB}, - {I_IN, 2, {REG_AX,IMMEDIATE,0}, "\320\1\xE5\25", IF_8086|IF_SB}, - {I_IN, 2, {REG_EAX,IMMEDIATE,0}, "\321\1\xE5\25", IF_386|IF_SB}, - {I_IN, 2, {REG_AL,REG_DX,0}, "\1\xEC", IF_8086}, - {I_IN, 2, {REG_AX,REG_DX,0}, "\320\1\xED", IF_8086}, - {I_IN, 2, {REG_EAX,REG_DX,0}, "\321\1\xED", IF_386}, - ITEMPLATE_END -}; - -static struct itemplate instrux_INC[] = { - {I_INC, 1, {REG16,0,0}, "\320\10\x40", IF_8086}, - {I_INC, 1, {REG32,0,0}, "\321\10\x40", IF_386}, - {I_INC, 1, {REGMEM|BITS8,0,0}, "\300\1\xFE\200", IF_8086}, - {I_INC, 1, {REGMEM|BITS16,0,0}, "\320\300\1\xFF\200", IF_8086}, - {I_INC, 1, {REGMEM|BITS32,0,0}, "\321\300\1\xFF\200", IF_386}, - ITEMPLATE_END -}; - -static struct itemplate instrux_INCBIN[] = { - ITEMPLATE_END -}; - -static struct itemplate instrux_INSB[] = { - {I_INSB, 0, {0,0,0}, "\1\x6C", IF_186}, - ITEMPLATE_END -}; - -static struct itemplate instrux_INSD[] = { - {I_INSD, 0, {0,0,0}, "\321\1\x6D", IF_386}, - ITEMPLATE_END -}; - -static struct itemplate instrux_INSW[] = { - {I_INSW, 0, {0,0,0}, "\320\1\x6D", IF_186}, - ITEMPLATE_END -}; - -static struct itemplate instrux_INT[] = { - {I_INT, 1, {IMMEDIATE,0,0}, "\1\xCD\24", IF_8086|IF_SB}, - ITEMPLATE_END -}; - -static struct itemplate instrux_INT01[] = { - {I_INT01, 0, {0,0,0}, "\1\xF1", IF_386}, - ITEMPLATE_END -}; - -static struct itemplate instrux_INT03[] = { - {I_INT03, 0, {0,0,0}, "\1\xCC", IF_8086}, - ITEMPLATE_END -}; - -static struct itemplate instrux_INT1[] = { - {I_INT1, 0, {0,0,0}, "\1\xF1", IF_386}, - ITEMPLATE_END -}; - -static struct itemplate instrux_INT3[] = { - {I_INT3, 0, {0,0,0}, "\1\xCC", IF_8086}, - ITEMPLATE_END -}; - -static struct itemplate instrux_INTO[] = { - {I_INTO, 0, {0,0,0}, "\1\xCE", IF_8086}, - ITEMPLATE_END -}; - -static struct itemplate instrux_INVD[] = { - {I_INVD, 0, {0,0,0}, "\2\x0F\x08", IF_486|IF_PRIV}, - ITEMPLATE_END -}; - -static struct itemplate instrux_INVLPG[] = { - {I_INVLPG, 1, {MEMORY,0,0}, "\300\2\x0F\x01\207", IF_486|IF_PRIV}, - ITEMPLATE_END -}; - -static struct itemplate instrux_IRET[] = { - {I_IRET, 0, {0,0,0}, "\322\1\xCF", IF_8086}, - ITEMPLATE_END -}; - -static struct itemplate instrux_IRETD[] = { - {I_IRETD, 0, {0,0,0}, "\321\1\xCF", IF_386}, - ITEMPLATE_END -}; - -static struct itemplate instrux_IRETW[] = { - {I_IRETW, 0, {0,0,0}, "\320\1\xCF", IF_8086}, - ITEMPLATE_END -}; - -static struct itemplate instrux_JCXZ[] = { - {I_JCXZ, 1, {IMMEDIATE,0,0}, "\310\1\xE3\50", IF_8086}, - ITEMPLATE_END -}; - -static struct itemplate instrux_JECXZ[] = { - {I_JECXZ, 1, {IMMEDIATE,0,0}, "\311\1\xE3\50", IF_386}, - ITEMPLATE_END -}; - -static struct itemplate instrux_JMP[] = { - {I_JMP, 1, {IMMEDIATE|SHORT,0,0}, "\1\xEB\50", IF_8086}, - {I_JMP, 1, {IMMEDIATE,0,0}, "\371\1\xEB\50", IF_8086}, - {I_JMP, 1, {IMMEDIATE,0,0}, "\322\1\xE9\64", IF_8086}, - {I_JMP, 1, {IMMEDIATE|NEAR,0,0}, "\322\1\xE9\64", IF_8086}, - {I_JMP, 1, {IMMEDIATE|FAR,0,0}, "\322\1\xEA\34\37", IF_8086}, - {I_JMP, 1, {IMMEDIATE|BITS16,0,0}, "\320\1\xE9\64", IF_8086}, - {I_JMP, 1, {IMMEDIATE|BITS16|NEAR,0,0}, "\320\1\xE9\64", IF_8086}, - {I_JMP, 1, {IMMEDIATE|BITS16|FAR,0,0}, "\320\1\xEA\34\37", IF_8086}, - {I_JMP, 1, {IMMEDIATE|BITS32,0,0}, "\321\1\xE9\64", IF_386}, - {I_JMP, 1, {IMMEDIATE|BITS32|NEAR,0,0}, "\321\1\xE9\64", IF_386}, - {I_JMP, 1, {IMMEDIATE|BITS32|FAR,0,0}, "\321\1\xEA\34\37", IF_386}, - {I_JMP, 2, {IMMEDIATE|COLON,IMMEDIATE,0}, "\322\1\xEA\35\30", IF_8086}, - {I_JMP, 2, {IMMEDIATE|BITS16|COLON,IMMEDIATE,0}, "\320\1\xEA\31\30", IF_8086}, - {I_JMP, 2, {IMMEDIATE|COLON,IMMEDIATE|BITS16,0}, "\320\1\xEA\31\30", IF_8086}, - {I_JMP, 2, {IMMEDIATE|BITS32|COLON,IMMEDIATE,0}, "\321\1\xEA\41\30", IF_386}, - {I_JMP, 2, {IMMEDIATE|COLON,IMMEDIATE|BITS32,0}, "\321\1\xEA\41\30", IF_386}, - {I_JMP, 1, {MEMORY|FAR,0,0}, "\322\300\1\xFF\205", IF_8086}, - {I_JMP, 1, {MEMORY|BITS16|FAR,0,0}, "\320\300\1\xFF\205", IF_8086}, - {I_JMP, 1, {MEMORY|BITS32|FAR,0,0}, "\321\300\1\xFF\205", IF_386}, - {I_JMP, 1, {MEMORY|NEAR,0,0}, "\322\300\1\xFF\204", IF_8086}, - {I_JMP, 1, {MEMORY|BITS16|NEAR,0,0}, "\320\300\1\xFF\204", IF_8086}, - {I_JMP, 1, {MEMORY|BITS32|NEAR,0,0}, "\321\300\1\xFF\204", IF_386}, - {I_JMP, 1, {REG16,0,0}, "\320\300\1\xFF\204", IF_8086}, - {I_JMP, 1, {REG32,0,0}, "\321\300\1\xFF\204", IF_386}, - {I_JMP, 1, {MEMORY,0,0}, "\322\300\1\xFF\204", IF_8086}, - {I_JMP, 1, {MEMORY|BITS16,0,0}, "\320\300\1\xFF\204", IF_8086}, - {I_JMP, 1, {MEMORY|BITS32,0,0}, "\321\300\1\xFF\204", IF_386}, - ITEMPLATE_END -}; - -static struct itemplate instrux_JMPE[] = { - {I_JMPE, 1, {IMMEDIATE,0,0}, "\322\2\x0F\xB8\64", IF_IA64}, - {I_JMPE, 1, {IMMEDIATE|BITS16,0,0}, "\320\2\x0F\xB8\64", IF_IA64}, - {I_JMPE, 1, {IMMEDIATE|BITS32,0,0}, "\321\2\x0F\xB8\64", IF_IA64}, - {I_JMPE, 1, {REGMEM|BITS16,0,0}, "\320\2\x0F\x00\206", IF_IA64}, - {I_JMPE, 1, {REGMEM|BITS32,0,0}, "\321\2\x0F\x00\206", IF_IA64}, - ITEMPLATE_END -}; - -static struct itemplate instrux_LAHF[] = { - {I_LAHF, 0, {0,0,0}, "\1\x9F", IF_8086}, - ITEMPLATE_END -}; - -static struct itemplate instrux_LAR[] = { - {I_LAR, 2, {REG16,MEMORY,0}, "\320\301\2\x0F\x02\110", IF_286|IF_PROT|IF_SM}, - {I_LAR, 2, {REG16,REG16,0}, "\320\2\x0F\x02\110", IF_286|IF_PROT}, - {I_LAR, 2, {REG32,MEMORY,0}, "\321\301\2\x0F\x02\110", IF_386|IF_PROT|IF_SM}, - {I_LAR, 2, {REG32,REG32,0}, "\321\2\x0F\x02\110", IF_386|IF_PROT}, - ITEMPLATE_END -}; - -static struct itemplate instrux_LDDQU[] = { - {I_LDDQU, 2, {XMMREG,MEMORY,0}, "\3\xF2\x0F\xF0\110", IF_PRESCOTT|IF_SSE3}, - ITEMPLATE_END -}; - -static struct itemplate instrux_LDMXCSR[] = { - {I_LDMXCSR, 1, {MEMORY,0,0}, "\300\2\x0F\xAE\202", IF_KATMAI|IF_SSE|IF_SD}, - ITEMPLATE_END -}; - -static struct itemplate instrux_LDS[] = { - {I_LDS, 2, {REG16,MEMORY,0}, "\320\301\1\xC5\110", IF_8086}, - {I_LDS, 2, {REG32,MEMORY,0}, "\321\301\1\xC5\110", IF_386}, - ITEMPLATE_END -}; - -static struct itemplate instrux_LEA[] = { - {I_LEA, 2, {REG16,MEMORY,0}, "\320\301\1\x8D\110", IF_8086}, - {I_LEA, 2, {REG32,MEMORY,0}, "\321\301\1\x8D\110", IF_386}, - ITEMPLATE_END -}; - -static struct itemplate instrux_LEAVE[] = { - {I_LEAVE, 0, {0,0,0}, "\1\xC9", IF_186}, - ITEMPLATE_END -}; - -static struct itemplate instrux_LES[] = { - {I_LES, 2, {REG16,MEMORY,0}, "\320\301\1\xC4\110", IF_8086}, - {I_LES, 2, {REG32,MEMORY,0}, "\321\301\1\xC4\110", IF_386}, - ITEMPLATE_END -}; - -static struct itemplate instrux_LFENCE[] = { - {I_LFENCE, 0, {0,0,0}, "\3\x0F\xAE\xE8", IF_WILLAMETTE|IF_SSE2}, - ITEMPLATE_END -}; - -static struct itemplate instrux_LFS[] = { - {I_LFS, 2, {REG16,MEMORY,0}, "\320\301\2\x0F\xB4\110", IF_386}, - {I_LFS, 2, {REG32,MEMORY,0}, "\321\301\2\x0F\xB4\110", IF_386}, - ITEMPLATE_END -}; - -static struct itemplate instrux_LGDT[] = { - {I_LGDT, 1, {MEMORY,0,0}, "\300\2\x0F\x01\202", IF_286|IF_PRIV}, - ITEMPLATE_END -}; - -static struct itemplate instrux_LGS[] = { - {I_LGS, 2, {REG16,MEMORY,0}, "\320\301\2\x0F\xB5\110", IF_386}, - {I_LGS, 2, {REG32,MEMORY,0}, "\321\301\2\x0F\xB5\110", IF_386}, - ITEMPLATE_END -}; - -static struct itemplate instrux_LIDT[] = { - {I_LIDT, 1, {MEMORY,0,0}, "\300\2\x0F\x01\203", IF_286|IF_PRIV}, - ITEMPLATE_END -}; - -static struct itemplate instrux_LLDT[] = { - {I_LLDT, 1, {MEMORY,0,0}, "\300\1\x0F\17\202", IF_286|IF_PROT|IF_PRIV}, - {I_LLDT, 1, {MEMORY|BITS16,0,0}, "\300\1\x0F\17\202", IF_286|IF_PROT|IF_PRIV}, - {I_LLDT, 1, {REG16,0,0}, "\1\x0F\17\202", IF_286|IF_PROT|IF_PRIV}, - ITEMPLATE_END -}; - -static struct itemplate instrux_LMSW[] = { - {I_LMSW, 1, {MEMORY,0,0}, "\300\2\x0F\x01\206", IF_286|IF_PRIV}, - {I_LMSW, 1, {MEMORY|BITS16,0,0}, "\300\2\x0F\x01\206", IF_286|IF_PRIV}, - {I_LMSW, 1, {REG16,0,0}, "\2\x0F\x01\206", IF_286|IF_PRIV}, - ITEMPLATE_END -}; - -static struct itemplate instrux_LOADALL[] = { - {I_LOADALL, 0, {0,0,0}, "\2\x0F\x07", IF_386|IF_UNDOC}, - ITEMPLATE_END -}; - -static struct itemplate instrux_LOADALL286[] = { - {I_LOADALL286, 0, {0,0,0}, "\2\x0F\x05", IF_286|IF_UNDOC}, - ITEMPLATE_END -}; - -static struct itemplate instrux_LODSB[] = { - {I_LODSB, 0, {0,0,0}, "\1\xAC", IF_8086}, - ITEMPLATE_END -}; - -static struct itemplate instrux_LODSD[] = { - {I_LODSD, 0, {0,0,0}, "\321\1\xAD", IF_386}, - ITEMPLATE_END -}; - -static struct itemplate instrux_LODSW[] = { - {I_LODSW, 0, {0,0,0}, "\320\1\xAD", IF_8086}, - ITEMPLATE_END -}; - -static struct itemplate instrux_LOOP[] = { - {I_LOOP, 1, {IMMEDIATE,0,0}, "\312\1\xE2\50", IF_8086}, - {I_LOOP, 2, {IMMEDIATE,REG_CX,0}, "\310\1\xE2\50", IF_8086}, - {I_LOOP, 2, {IMMEDIATE,REG_ECX,0}, "\311\1\xE2\50", IF_386}, - ITEMPLATE_END -}; - -static struct itemplate instrux_LOOPE[] = { - {I_LOOPE, 1, {IMMEDIATE,0,0}, "\312\1\xE1\50", IF_8086}, - {I_LOOPE, 2, {IMMEDIATE,REG_CX,0}, "\310\1\xE1\50", IF_8086}, - {I_LOOPE, 2, {IMMEDIATE,REG_ECX,0}, "\311\1\xE1\50", IF_386}, - ITEMPLATE_END -}; - -static struct itemplate instrux_LOOPNE[] = { - {I_LOOPNE, 1, {IMMEDIATE,0,0}, "\312\1\xE0\50", IF_8086}, - {I_LOOPNE, 2, {IMMEDIATE,REG_CX,0}, "\310\1\xE0\50", IF_8086}, - {I_LOOPNE, 2, {IMMEDIATE,REG_ECX,0}, "\311\1\xE0\50", IF_386}, - ITEMPLATE_END -}; - -static struct itemplate instrux_LOOPNZ[] = { - {I_LOOPNZ, 1, {IMMEDIATE,0,0}, "\312\1\xE0\50", IF_8086}, - {I_LOOPNZ, 2, {IMMEDIATE,REG_CX,0}, "\310\1\xE0\50", IF_8086}, - {I_LOOPNZ, 2, {IMMEDIATE,REG_ECX,0}, "\311\1\xE0\50", IF_386}, - ITEMPLATE_END -}; - -static struct itemplate instrux_LOOPZ[] = { - {I_LOOPZ, 1, {IMMEDIATE,0,0}, "\312\1\xE1\50", IF_8086}, - {I_LOOPZ, 2, {IMMEDIATE,REG_CX,0}, "\310\1\xE1\50", IF_8086}, - {I_LOOPZ, 2, {IMMEDIATE,REG_ECX,0}, "\311\1\xE1\50", IF_386}, - ITEMPLATE_END -}; - -static struct itemplate instrux_LSL[] = { - {I_LSL, 2, {REG16,MEMORY,0}, "\320\301\2\x0F\x03\110", IF_286|IF_PROT|IF_SM}, - {I_LSL, 2, {REG16,REG16,0}, "\320\2\x0F\x03\110", IF_286|IF_PROT}, - {I_LSL, 2, {REG32,MEMORY,0}, "\321\301\2\x0F\x03\110", IF_386|IF_PROT|IF_SM}, - {I_LSL, 2, {REG32,REG32,0}, "\321\2\x0F\x03\110", IF_386|IF_PROT}, - ITEMPLATE_END -}; - -static struct itemplate instrux_LSS[] = { - {I_LSS, 2, {REG16,MEMORY,0}, "\320\301\2\x0F\xB2\110", IF_386}, - {I_LSS, 2, {REG32,MEMORY,0}, "\321\301\2\x0F\xB2\110", IF_386}, - ITEMPLATE_END -}; - -static struct itemplate instrux_LTR[] = { - {I_LTR, 1, {MEMORY,0,0}, "\300\1\x0F\17\203", IF_286|IF_PROT|IF_PRIV}, - {I_LTR, 1, {MEMORY|BITS16,0,0}, "\300\1\x0F\17\203", IF_286|IF_PROT|IF_PRIV}, - {I_LTR, 1, {REG16,0,0}, "\1\x0F\17\203", IF_286|IF_PROT|IF_PRIV}, - ITEMPLATE_END -}; - -static struct itemplate instrux_MASKMOVDQU[] = { - {I_MASKMOVDQU, 2, {XMMREG,XMMREG,0}, "\3\x66\x0F\xF7\110", IF_WILLAMETTE|IF_SSE2}, - ITEMPLATE_END -}; - -static struct itemplate instrux_MASKMOVQ[] = { - {I_MASKMOVQ, 2, {MMXREG,MMXREG,0}, "\2\x0F\xF7\110", IF_KATMAI|IF_MMX}, - ITEMPLATE_END -}; - -static struct itemplate instrux_MAXPD[] = { - {I_MAXPD, 2, {XMMREG,XMMREG,0}, "\3\x66\x0F\x5F\110", IF_WILLAMETTE|IF_SSE2}, - {I_MAXPD, 2, {XMMREG,MEMORY,0}, "\301\3\x66\x0F\x5F\110", IF_WILLAMETTE|IF_SSE2|IF_SM}, - ITEMPLATE_END -}; - -static struct itemplate instrux_MAXPS[] = { - {I_MAXPS, 2, {XMMREG,MEMORY,0}, "\301\331\2\x0F\x5F\110", IF_KATMAI|IF_SSE}, - {I_MAXPS, 2, {XMMREG,XMMREG,0}, "\331\2\x0F\x5F\110", IF_KATMAI|IF_SSE}, - ITEMPLATE_END -}; - -static struct itemplate instrux_MAXSD[] = { - {I_MAXSD, 2, {XMMREG,XMMREG,0}, "\3\xF2\x0F\x5F\110", IF_WILLAMETTE|IF_SSE2}, - {I_MAXSD, 2, {XMMREG,MEMORY,0}, "\301\3\xF2\x0F\x5F\110", IF_WILLAMETTE|IF_SSE2}, - ITEMPLATE_END -}; - -static struct itemplate instrux_MAXSS[] = { - {I_MAXSS, 2, {XMMREG,MEMORY,0}, "\301\333\2\x0F\x5F\110", IF_KATMAI|IF_SSE}, - {I_MAXSS, 2, {XMMREG,XMMREG,0}, "\333\2\x0F\x5F\110", IF_KATMAI|IF_SSE}, - ITEMPLATE_END -}; - -static struct itemplate instrux_MFENCE[] = { - {I_MFENCE, 0, {0,0,0}, "\3\x0F\xAE\xF0", IF_WILLAMETTE|IF_SSE2}, - ITEMPLATE_END -}; - -static struct itemplate instrux_MINPD[] = { - {I_MINPD, 2, {XMMREG,XMMREG,0}, "\3\x66\x0F\x5D\110", IF_WILLAMETTE|IF_SSE2}, - {I_MINPD, 2, {XMMREG,MEMORY,0}, "\301\3\x66\x0F\x5D\110", IF_WILLAMETTE|IF_SSE2|IF_SM}, - ITEMPLATE_END -}; - -static struct itemplate instrux_MINPS[] = { - {I_MINPS, 2, {XMMREG,MEMORY,0}, "\301\331\2\x0F\x5D\110", IF_KATMAI|IF_SSE}, - {I_MINPS, 2, {XMMREG,XMMREG,0}, "\331\2\x0F\x5D\110", IF_KATMAI|IF_SSE}, - ITEMPLATE_END -}; - -static struct itemplate instrux_MINSD[] = { - {I_MINSD, 2, {XMMREG,XMMREG,0}, "\3\xF2\x0F\x5D\110", IF_WILLAMETTE|IF_SSE2}, - {I_MINSD, 2, {XMMREG,MEMORY,0}, "\301\3\xF2\x0F\x5D\110", IF_WILLAMETTE|IF_SSE2}, - ITEMPLATE_END -}; - -static struct itemplate instrux_MINSS[] = { - {I_MINSS, 2, {XMMREG,MEMORY,0}, "\301\333\2\x0F\x5D\110", IF_KATMAI|IF_SSE}, - {I_MINSS, 2, {XMMREG,XMMREG,0}, "\333\2\x0F\x5D\110", IF_KATMAI|IF_SSE}, - ITEMPLATE_END -}; - -static struct itemplate instrux_MONITOR[] = { - {I_MONITOR, 0, {0,0,0}, "\3\x0F\x01\xC8", IF_PRESCOTT}, - {I_MONITOR, 3, {REG_EAX,REG_ECX,REG_EDX}, "\3\x0F\x01\xC8", IF_PRESCOTT}, - ITEMPLATE_END -}; - -static struct itemplate instrux_MOV[] = { - {I_MOV, 2, {MEMORY,REG_SREG,0}, "\300\1\x8C\101", IF_8086|IF_SM}, - {I_MOV, 2, {REG16,REG_SREG,0}, "\320\1\x8C\101", IF_8086}, - {I_MOV, 2, {REG32,REG_SREG,0}, "\321\1\x8C\101", IF_386}, - {I_MOV, 2, {REG_SREG,MEMORY,0}, "\301\1\x8E\110", IF_8086|IF_SM}, - {I_MOV, 2, {REG_SREG,REG16,0}, "\1\x8E\110", IF_8086}, - {I_MOV, 2, {REG_SREG,REG32,0}, "\1\x8E\110", IF_386}, - {I_MOV, 2, {REG_AL,MEM_OFFS,0}, "\301\1\xA0\45", IF_8086|IF_SM}, - {I_MOV, 2, {REG_AX,MEM_OFFS,0}, "\301\320\1\xA1\45", IF_8086|IF_SM}, - {I_MOV, 2, {REG_EAX,MEM_OFFS,0}, "\301\321\1\xA1\45", IF_386|IF_SM}, - {I_MOV, 2, {MEM_OFFS,REG_AL,0}, "\300\1\xA2\44", IF_8086|IF_SM}, - {I_MOV, 2, {MEM_OFFS,REG_AX,0}, "\300\320\1\xA3\44", IF_8086|IF_SM}, - {I_MOV, 2, {MEM_OFFS,REG_EAX,0}, "\300\321\1\xA3\44", IF_386|IF_SM}, - {I_MOV, 2, {REG32,REG_CREG,0}, "\2\x0F\x20\101", IF_386|IF_PRIV}, - {I_MOV, 2, {REG32,REG_DREG,0}, "\2\x0F\x21\101", IF_386|IF_PRIV}, - {I_MOV, 2, {REG32,REG_TREG,0}, "\2\x0F\x24\101", IF_386|IF_PRIV}, - {I_MOV, 2, {REG_CREG,REG32,0}, "\2\x0F\x22\110", IF_386|IF_PRIV}, - {I_MOV, 2, {REG_DREG,REG32,0}, "\2\x0F\x23\110", IF_386|IF_PRIV}, - {I_MOV, 2, {REG_TREG,REG32,0}, "\2\x0F\x26\110", IF_386|IF_PRIV}, - {I_MOV, 2, {MEMORY,REG8,0}, "\300\1\x88\101", IF_8086|IF_SM}, - {I_MOV, 2, {REG8,REG8,0}, "\1\x88\101", IF_8086}, - {I_MOV, 2, {MEMORY,REG16,0}, "\320\300\1\x89\101", IF_8086|IF_SM}, - {I_MOV, 2, {REG16,REG16,0}, "\320\1\x89\101", IF_8086}, - {I_MOV, 2, {MEMORY,REG32,0}, "\321\300\1\x89\101", IF_386|IF_SM}, - {I_MOV, 2, {REG32,REG32,0}, "\321\1\x89\101", IF_386}, - {I_MOV, 2, {REG8,MEMORY,0}, "\301\1\x8A\110", IF_8086|IF_SM}, - {I_MOV, 2, {REG8,REG8,0}, "\1\x8A\110", IF_8086}, - {I_MOV, 2, {REG16,MEMORY,0}, "\320\301\1\x8B\110", IF_8086|IF_SM}, - {I_MOV, 2, {REG16,REG16,0}, "\320\1\x8B\110", IF_8086}, - {I_MOV, 2, {REG32,MEMORY,0}, "\321\301\1\x8B\110", IF_386|IF_SM}, - {I_MOV, 2, {REG32,REG32,0}, "\321\1\x8B\110", IF_386}, - {I_MOV, 2, {REG8,IMMEDIATE,0}, "\10\xB0\21", IF_8086|IF_SM}, - {I_MOV, 2, {REG16,IMMEDIATE,0}, "\320\10\xB8\31", IF_8086|IF_SM}, - {I_MOV, 2, {REG32,IMMEDIATE,0}, "\321\10\xB8\41", IF_386|IF_SM}, - {I_MOV, 2, {REGMEM|BITS8,IMMEDIATE,0}, "\300\1\xC6\200\21", IF_8086|IF_SM}, - {I_MOV, 2, {REGMEM|BITS16,IMMEDIATE,0}, "\320\300\1\xC7\200\31", IF_8086|IF_SM}, - {I_MOV, 2, {REGMEM|BITS32,IMMEDIATE,0}, "\321\300\1\xC7\200\41", IF_386|IF_SM}, - {I_MOV, 2, {MEMORY,IMMEDIATE|BITS8,0}, "\300\1\xC6\200\21", IF_8086|IF_SM}, - {I_MOV, 2, {MEMORY,IMMEDIATE|BITS16,0}, "\320\300\1\xC7\200\31", IF_8086|IF_SM}, - {I_MOV, 2, {MEMORY,IMMEDIATE|BITS32,0}, "\321\300\1\xC7\200\41", IF_386|IF_SM}, - ITEMPLATE_END -}; - -static struct itemplate instrux_MOVAPD[] = { - {I_MOVAPD, 2, {XMMREG,XMMREG,0}, "\3\x66\x0F\x28\110", IF_WILLAMETTE|IF_SSE2}, - {I_MOVAPD, 2, {XMMREG,XMMREG,0}, "\3\x66\x0F\x29\110", IF_WILLAMETTE|IF_SSE2}, - {I_MOVAPD, 2, {MEMORY,XMMREG,0}, "\300\3\x66\x0F\x29\101", IF_WILLAMETTE|IF_SSE2|IF_SM}, - {I_MOVAPD, 2, {XMMREG,MEMORY,0}, "\301\3\x66\x0F\x28\110", IF_WILLAMETTE|IF_SSE2|IF_SM}, - ITEMPLATE_END -}; - -static struct itemplate instrux_MOVAPS[] = { - {I_MOVAPS, 2, {XMMREG,MEMORY,0}, "\301\2\x0F\x28\110", IF_KATMAI|IF_SSE}, - {I_MOVAPS, 2, {MEMORY,XMMREG,0}, "\300\2\x0F\x29\101", IF_KATMAI|IF_SSE}, - {I_MOVAPS, 2, {XMMREG,XMMREG,0}, "\2\x0F\x28\110", IF_KATMAI|IF_SSE}, - {I_MOVAPS, 2, {XMMREG,XMMREG,0}, "\2\x0F\x29\101", IF_KATMAI|IF_SSE}, - ITEMPLATE_END -}; - -static struct itemplate instrux_MOVD[] = { - {I_MOVD, 2, {MMXREG,MEMORY,0}, "\301\2\x0F\x6E\110", IF_PENT|IF_MMX|IF_SD}, - {I_MOVD, 2, {MMXREG,REG32,0}, "\2\x0F\x6E\110", IF_PENT|IF_MMX}, - {I_MOVD, 2, {MEMORY,MMXREG,0}, "\300\2\x0F\x7E\101", IF_PENT|IF_MMX|IF_SD}, - {I_MOVD, 2, {REG32,MMXREG,0}, "\2\x0F\x7E\101", IF_PENT|IF_MMX}, - {I_MOVD, 2, {XMMREG,REG32,0}, "\3\x66\x0F\x6E\110", IF_WILLAMETTE|IF_SSE2}, - {I_MOVD, 2, {REG32,XMMREG,0}, "\3\x66\x0F\x7E\101", IF_WILLAMETTE|IF_SSE2}, - {I_MOVD, 2, {MEMORY,XMMREG,0}, "\300\3\x66\x0F\x7E\101", IF_WILLAMETTE|IF_SSE2}, - {I_MOVD, 2, {XMMREG,MEMORY,0}, "\301\3\x66\x0F\x6E\110", IF_WILLAMETTE|IF_SSE2}, - ITEMPLATE_END -}; - -static struct itemplate instrux_MOVDDUP[] = { - {I_MOVDDUP, 2, {XMMREG,MEMORY,0}, "\301\3\xF2\x0F\x12\110", IF_PRESCOTT|IF_SSE3}, - {I_MOVDDUP, 2, {XMMREG,XMMREG,0}, "\3\xF2\x0F\x12\110", IF_PRESCOTT|IF_SSE3}, - ITEMPLATE_END -}; - -static struct itemplate instrux_MOVDQ2Q[] = { - {I_MOVDQ2Q, 2, {MMXREG,XMMREG,0}, "\3\xF2\x0F\xD6\110", IF_WILLAMETTE|IF_SSE2}, - ITEMPLATE_END -}; - -static struct itemplate instrux_MOVDQA[] = { - {I_MOVDQA, 2, {XMMREG,XMMREG,0}, "\3\x66\x0F\x6F\110", IF_WILLAMETTE|IF_SSE2}, - {I_MOVDQA, 2, {MEMORY,XMMREG,0}, "\300\3\x66\x0F\x7F\101", IF_WILLAMETTE|IF_SSE2|IF_SM}, - {I_MOVDQA, 2, {XMMREG,MEMORY,0}, "\301\3\x66\x0F\x6F\110", IF_WILLAMETTE|IF_SSE2|IF_SM}, - {I_MOVDQA, 2, {XMMREG,XMMREG,0}, "\3\x66\x0F\x7F\110", IF_WILLAMETTE|IF_SSE2}, - ITEMPLATE_END -}; - -static struct itemplate instrux_MOVDQU[] = { - {I_MOVDQU, 2, {XMMREG,XMMREG,0}, "\333\2\x0F\x6F\110", IF_WILLAMETTE|IF_SSE2}, - {I_MOVDQU, 2, {MEMORY,XMMREG,0}, "\333\300\2\x0F\x7F\101", IF_WILLAMETTE|IF_SSE2|IF_SM}, - {I_MOVDQU, 2, {XMMREG,MEMORY,0}, "\301\333\2\x0F\x6F\110", IF_WILLAMETTE|IF_SSE2|IF_SM}, - {I_MOVDQU, 2, {XMMREG,XMMREG,0}, "\333\2\x0F\x7F\110", IF_WILLAMETTE|IF_SSE2}, - ITEMPLATE_END -}; - -static struct itemplate instrux_MOVHLPS[] = { - {I_MOVHLPS, 2, {XMMREG,XMMREG,0}, "\2\x0F\x12\110", IF_KATMAI|IF_SSE}, - ITEMPLATE_END -}; - -static struct itemplate instrux_MOVHPD[] = { - {I_MOVHPD, 2, {MEMORY,XMMREG,0}, "\300\3\x66\x0F\x17\101", IF_WILLAMETTE|IF_SSE2}, - {I_MOVHPD, 2, {XMMREG,MEMORY,0}, "\301\3\x66\x0F\x16\110", IF_WILLAMETTE|IF_SSE2}, - ITEMPLATE_END -}; - -static struct itemplate instrux_MOVHPS[] = { - {I_MOVHPS, 2, {XMMREG,MEMORY,0}, "\301\2\x0F\x16\110", IF_KATMAI|IF_SSE}, - {I_MOVHPS, 2, {MEMORY,XMMREG,0}, "\300\2\x0F\x17\101", IF_KATMAI|IF_SSE}, - ITEMPLATE_END -}; - -static struct itemplate instrux_MOVLHPS[] = { - {I_MOVLHPS, 2, {XMMREG,XMMREG,0}, "\2\x0F\x16\110", IF_KATMAI|IF_SSE}, - ITEMPLATE_END -}; - -static struct itemplate instrux_MOVLPD[] = { - {I_MOVLPD, 2, {MEMORY,XMMREG,0}, "\300\3\x66\x0F\x13\101", IF_WILLAMETTE|IF_SSE2}, - {I_MOVLPD, 2, {XMMREG,MEMORY,0}, "\301\3\x66\x0F\x12\110", IF_WILLAMETTE|IF_SSE2}, - ITEMPLATE_END -}; - -static struct itemplate instrux_MOVLPS[] = { - {I_MOVLPS, 2, {XMMREG,MEMORY,0}, "\301\2\x0F\x12\110", IF_KATMAI|IF_SSE}, - {I_MOVLPS, 2, {MEMORY,XMMREG,0}, "\300\2\x0F\x13\101", IF_KATMAI|IF_SSE}, - ITEMPLATE_END -}; - -static struct itemplate instrux_MOVMSKPD[] = { - {I_MOVMSKPD, 2, {REG32,XMMREG,0}, "\3\x66\x0F\x50\110", IF_WILLAMETTE|IF_SSE2}, - ITEMPLATE_END -}; - -static struct itemplate instrux_MOVMSKPS[] = { - {I_MOVMSKPS, 2, {REG32,XMMREG,0}, "\2\x0F\x50\110", IF_KATMAI|IF_SSE}, - ITEMPLATE_END -}; - -static struct itemplate instrux_MOVNTDQ[] = { - {I_MOVNTDQ, 2, {MEMORY,XMMREG,0}, "\300\3\x66\x0F\xE7\101", IF_WILLAMETTE|IF_SSE2|IF_SM}, - ITEMPLATE_END -}; - -static struct itemplate instrux_MOVNTI[] = { - {I_MOVNTI, 2, {MEMORY,REG32,0}, "\300\2\x0F\xC3\101", IF_WILLAMETTE|IF_SSE2|IF_SM}, - ITEMPLATE_END -}; - -static struct itemplate instrux_MOVNTPD[] = { - {I_MOVNTPD, 2, {MEMORY,XMMREG,0}, "\300\3\x66\x0F\x2B\101", IF_WILLAMETTE|IF_SSE2|IF_SM}, - ITEMPLATE_END -}; - -static struct itemplate instrux_MOVNTPS[] = { - {I_MOVNTPS, 2, {MEMORY,XMMREG,0}, "\300\2\x0F\x2B\101", IF_KATMAI|IF_SSE}, - ITEMPLATE_END -}; - -static struct itemplate instrux_MOVNTQ[] = { - {I_MOVNTQ, 2, {MEMORY,MMXREG,0}, "\300\2\x0F\xE7\101", IF_KATMAI|IF_MMX|IF_SM}, - ITEMPLATE_END -}; - -static struct itemplate instrux_MOVQ[] = { - {I_MOVQ, 2, {MMXREG,MEMORY,0}, "\301\2\x0F\x6F\110", IF_PENT|IF_MMX|IF_SM}, - {I_MOVQ, 2, {MMXREG,MMXREG,0}, "\2\x0F\x6F\110", IF_PENT|IF_MMX}, - {I_MOVQ, 2, {MEMORY,MMXREG,0}, "\300\2\x0F\x7F\101", IF_PENT|IF_MMX|IF_SM}, - {I_MOVQ, 2, {MMXREG,MMXREG,0}, "\2\x0F\x7F\101", IF_PENT|IF_MMX}, - {I_MOVQ, 2, {XMMREG,XMMREG,0}, "\333\2\x0F\x7E\110", IF_WILLAMETTE|IF_SSE2}, - {I_MOVQ, 2, {XMMREG,XMMREG,0}, "\3\x66\x0F\xD6\110", IF_WILLAMETTE|IF_SSE2}, - {I_MOVQ, 2, {MEMORY,XMMREG,0}, "\300\3\x66\x0F\xD6\101", IF_WILLAMETTE|IF_SSE2}, - {I_MOVQ, 2, {XMMREG,MEMORY,0}, "\301\333\2\x0F\x7E\110", IF_WILLAMETTE|IF_SSE2}, - ITEMPLATE_END -}; - -static struct itemplate instrux_MOVQ2DQ[] = { - {I_MOVQ2DQ, 2, {XMMREG,MMXREG,0}, "\333\2\x0F\xD6\110", IF_WILLAMETTE|IF_SSE2}, - ITEMPLATE_END -}; - -static struct itemplate instrux_MOVSB[] = { - {I_MOVSB, 0, {0,0,0}, "\1\xA4", IF_8086}, - ITEMPLATE_END -}; - -static struct itemplate instrux_MOVSD[] = { - {I_MOVSD, 0, {0,0,0}, "\321\1\xA5", IF_386}, - {I_MOVSD, 2, {XMMREG,XMMREG,0}, "\3\xF2\x0F\x10\110", IF_WILLAMETTE|IF_SSE2}, - {I_MOVSD, 2, {XMMREG,XMMREG,0}, "\3\xF2\x0F\x11\110", IF_WILLAMETTE|IF_SSE2}, - {I_MOVSD, 2, {MEMORY,XMMREG,0}, "\300\3\xF2\x0F\x11\101", IF_WILLAMETTE|IF_SSE2}, - {I_MOVSD, 2, {XMMREG,MEMORY,0}, "\301\3\xF2\x0F\x10\110", IF_WILLAMETTE|IF_SSE2}, - ITEMPLATE_END -}; - -static struct itemplate instrux_MOVSHDUP[] = { - {I_MOVSHDUP, 2, {XMMREG,MEMORY,0}, "\301\3\xF3\x0F\x16\110", IF_PRESCOTT|IF_SSE3}, - {I_MOVSHDUP, 2, {XMMREG,XMMREG,0}, "\3\xF3\x0F\x16\110", IF_PRESCOTT|IF_SSE3}, - ITEMPLATE_END -}; - -static struct itemplate instrux_MOVSLDUP[] = { - {I_MOVSLDUP, 2, {XMMREG,MEMORY,0}, "\301\3\xF3\x0F\x12\110", IF_PRESCOTT|IF_SSE3}, - {I_MOVSLDUP, 2, {XMMREG,XMMREG,0}, "\3\xF3\x0F\x12\110", IF_PRESCOTT|IF_SSE3}, - ITEMPLATE_END -}; - -static struct itemplate instrux_MOVSS[] = { - {I_MOVSS, 2, {XMMREG,MEMORY,0}, "\301\333\2\x0F\x10\110", IF_KATMAI|IF_SSE}, - {I_MOVSS, 2, {MEMORY,XMMREG,0}, "\300\333\2\x0F\x11\101", IF_KATMAI|IF_SSE}, - {I_MOVSS, 2, {XMMREG,XMMREG,0}, "\333\2\x0F\x10\110", IF_KATMAI|IF_SSE}, - {I_MOVSS, 2, {XMMREG,XMMREG,0}, "\333\2\x0F\x11\101", IF_KATMAI|IF_SSE}, - ITEMPLATE_END -}; - -static struct itemplate instrux_MOVSW[] = { - {I_MOVSW, 0, {0,0,0}, "\320\1\xA5", IF_8086}, - ITEMPLATE_END -}; - -static struct itemplate instrux_MOVSX[] = { - {I_MOVSX, 2, {REG16,MEMORY,0}, "\320\301\2\x0F\xBE\110", IF_386|IF_SB}, - {I_MOVSX, 2, {REG16,REG8,0}, "\320\2\x0F\xBE\110", IF_386}, - {I_MOVSX, 2, {REG32,REGMEM|BITS8,0}, "\321\301\2\x0F\xBE\110", IF_386}, - {I_MOVSX, 2, {REG32,REGMEM|BITS16,0}, "\321\301\2\x0F\xBF\110", IF_386}, - ITEMPLATE_END -}; - -static struct itemplate instrux_MOVUPD[] = { - {I_MOVUPD, 2, {XMMREG,XMMREG,0}, "\3\x66\x0F\x10\110", IF_WILLAMETTE|IF_SSE2}, - {I_MOVUPD, 2, {XMMREG,XMMREG,0}, "\3\x66\x0F\x11\110", IF_WILLAMETTE|IF_SSE2}, - {I_MOVUPD, 2, {MEMORY,XMMREG,0}, "\300\3\x66\x0F\x11\101", IF_WILLAMETTE|IF_SSE2|IF_SM}, - {I_MOVUPD, 2, {XMMREG,MEMORY,0}, "\301\3\x66\x0F\x10\110", IF_WILLAMETTE|IF_SSE2|IF_SM}, - ITEMPLATE_END -}; - -static struct itemplate instrux_MOVUPS[] = { - {I_MOVUPS, 2, {XMMREG,MEMORY,0}, "\301\331\2\x0F\x10\110", IF_KATMAI|IF_SSE}, - {I_MOVUPS, 2, {MEMORY,XMMREG,0}, "\300\331\2\x0F\x11\101", IF_KATMAI|IF_SSE}, - {I_MOVUPS, 2, {XMMREG,XMMREG,0}, "\331\2\x0F\x10\110", IF_KATMAI|IF_SSE}, - {I_MOVUPS, 2, {XMMREG,XMMREG,0}, "\331\2\x0F\x11\101", IF_KATMAI|IF_SSE}, - ITEMPLATE_END -}; - -static struct itemplate instrux_MOVZX[] = { - {I_MOVZX, 2, {REG16,MEMORY,0}, "\320\301\2\x0F\xB6\110", IF_386|IF_SB}, - {I_MOVZX, 2, {REG16,REG8,0}, "\320\2\x0F\xB6\110", IF_386}, - {I_MOVZX, 2, {REG32,REGMEM|BITS8,0}, "\321\301\2\x0F\xB6\110", IF_386}, - {I_MOVZX, 2, {REG32,REGMEM|BITS16,0}, "\321\301\2\x0F\xB7\110", IF_386}, - ITEMPLATE_END -}; - -static struct itemplate instrux_MUL[] = { - {I_MUL, 1, {REGMEM|BITS8,0,0}, "\300\1\xF6\204", IF_8086}, - {I_MUL, 1, {REGMEM|BITS16,0,0}, "\320\300\1\xF7\204", IF_8086}, - {I_MUL, 1, {REGMEM|BITS32,0,0}, "\321\300\1\xF7\204", IF_386}, - ITEMPLATE_END -}; - -static struct itemplate instrux_MULPD[] = { - {I_MULPD, 2, {XMMREG,XMMREG,0}, "\3\x66\x0F\x59\110", IF_WILLAMETTE|IF_SSE2}, - {I_MULPD, 2, {XMMREG,MEMORY,0}, "\301\3\x66\x0F\x59\110", IF_WILLAMETTE|IF_SSE2|IF_SM}, - ITEMPLATE_END -}; - -static struct itemplate instrux_MULPS[] = { - {I_MULPS, 2, {XMMREG,MEMORY,0}, "\301\2\x0F\x59\110", IF_KATMAI|IF_SSE}, - {I_MULPS, 2, {XMMREG,XMMREG,0}, "\2\x0F\x59\110", IF_KATMAI|IF_SSE}, - ITEMPLATE_END -}; - -static struct itemplate instrux_MULSD[] = { - {I_MULSD, 2, {XMMREG,XMMREG,0}, "\3\xF2\x0F\x59\110", IF_WILLAMETTE|IF_SSE2}, - {I_MULSD, 2, {XMMREG,MEMORY,0}, "\301\3\xF2\x0F\x59\110", IF_WILLAMETTE|IF_SSE2}, - ITEMPLATE_END -}; - -static struct itemplate instrux_MULSS[] = { - {I_MULSS, 2, {XMMREG,MEMORY,0}, "\301\333\2\x0F\x59\110", IF_KATMAI|IF_SSE}, - {I_MULSS, 2, {XMMREG,XMMREG,0}, "\333\2\x0F\x59\110", IF_KATMAI|IF_SSE}, - ITEMPLATE_END -}; - -static struct itemplate instrux_MWAIT[] = { - {I_MWAIT, 0, {0,0,0}, "\3\x0F\x01\xC9", IF_PRESCOTT}, - {I_MWAIT, 2, {REG_EAX,REG_ECX,0}, "\3\x0F\x01\xC9", IF_PRESCOTT}, - ITEMPLATE_END -}; - -static struct itemplate instrux_NEG[] = { - {I_NEG, 1, {REGMEM|BITS8,0,0}, "\300\1\xF6\203", IF_8086}, - {I_NEG, 1, {REGMEM|BITS16,0,0}, "\320\300\1\xF7\203", IF_8086}, - {I_NEG, 1, {REGMEM|BITS32,0,0}, "\321\300\1\xF7\203", IF_386}, - ITEMPLATE_END -}; - -static struct itemplate instrux_NOP[] = { - {I_NOP, 0, {0,0,0}, "\1\x90", IF_8086}, - ITEMPLATE_END -}; - -static struct itemplate instrux_NOT[] = { - {I_NOT, 1, {REGMEM|BITS8,0,0}, "\300\1\xF6\202", IF_8086}, - {I_NOT, 1, {REGMEM|BITS16,0,0}, "\320\300\1\xF7\202", IF_8086}, - {I_NOT, 1, {REGMEM|BITS32,0,0}, "\321\300\1\xF7\202", IF_386}, - ITEMPLATE_END -}; - -static struct itemplate instrux_OR[] = { - {I_OR, 2, {MEMORY,REG8,0}, "\300\1\x08\101", IF_8086|IF_SM}, - {I_OR, 2, {REG8,REG8,0}, "\1\x08\101", IF_8086}, - {I_OR, 2, {MEMORY,REG16,0}, "\320\300\1\x09\101", IF_8086|IF_SM}, - {I_OR, 2, {REG16,REG16,0}, "\320\1\x09\101", IF_8086}, - {I_OR, 2, {MEMORY,REG32,0}, "\321\300\1\x09\101", IF_386|IF_SM}, - {I_OR, 2, {REG32,REG32,0}, "\321\1\x09\101", IF_386}, - {I_OR, 2, {REG8,MEMORY,0}, "\301\1\x0A\110", IF_8086|IF_SM}, - {I_OR, 2, {REG8,REG8,0}, "\1\x0A\110", IF_8086}, - {I_OR, 2, {REG16,MEMORY,0}, "\320\301\1\x0B\110", IF_8086|IF_SM}, - {I_OR, 2, {REG16,REG16,0}, "\320\1\x0B\110", IF_8086}, - {I_OR, 2, {REG32,MEMORY,0}, "\321\301\1\x0B\110", IF_386|IF_SM}, - {I_OR, 2, {REG32,REG32,0}, "\321\1\x0B\110", IF_386}, - {I_OR, 2, {REGMEM|BITS16,IMMEDIATE|BITS8,0}, "\320\300\1\x83\201\15", IF_8086}, - {I_OR, 2, {REGMEM|BITS32,IMMEDIATE|BITS8,0}, "\321\300\1\x83\201\15", IF_386}, - {I_OR, 2, {REG_AL,IMMEDIATE,0}, "\1\x0C\21", IF_8086|IF_SM}, - {I_OR, 2, {REG_AX,SBYTE,0}, "\320\1\x83\201\15", IF_8086|IF_SM}, - {I_OR, 2, {REG_AX,IMMEDIATE,0}, "\320\1\x0D\31", IF_8086|IF_SM}, - {I_OR, 2, {REG_EAX,SBYTE,0}, "\321\1\x83\201\15", IF_386|IF_SM}, - {I_OR, 2, {REG_EAX,IMMEDIATE,0}, "\321\1\x0D\41", IF_386|IF_SM}, - {I_OR, 2, {REGMEM|BITS8,IMMEDIATE,0}, "\300\1\x80\201\21", IF_8086|IF_SM}, - {I_OR, 2, {REGMEM|BITS16,IMMEDIATE,0}, "\320\300\134\1\x81\201\131", IF_8086|IF_SM}, - {I_OR, 2, {REGMEM|BITS32,IMMEDIATE,0}, "\321\300\144\1\x81\201\141", IF_386|IF_SM}, - {I_OR, 2, {MEMORY,IMMEDIATE|BITS8,0}, "\300\1\x80\201\21", IF_8086|IF_SM}, - {I_OR, 2, {MEMORY,IMMEDIATE|BITS16,0}, "\320\300\134\1\x81\201\131", IF_8086|IF_SM}, - {I_OR, 2, {MEMORY,IMMEDIATE|BITS32,0}, "\321\300\144\1\x81\201\141", IF_386|IF_SM}, - ITEMPLATE_END -}; - -static struct itemplate instrux_ORPD[] = { - {I_ORPD, 2, {XMMREG,MEMORY,0}, "\301\3\x66\x0F\x56\110", IF_WILLAMETTE|IF_SSE2|IF_SM}, - {I_ORPD, 2, {XMMREG,XMMREG,0}, "\3\x66\x0F\x56\110", IF_WILLAMETTE|IF_SSE2}, - ITEMPLATE_END -}; - -static struct itemplate instrux_ORPS[] = { - {I_ORPS, 2, {XMMREG,MEMORY,0}, "\301\2\x0F\x56\110", IF_KATMAI|IF_SSE}, - {I_ORPS, 2, {XMMREG,XMMREG,0}, "\2\x0F\x56\110", IF_KATMAI|IF_SSE}, - ITEMPLATE_END -}; - -static struct itemplate instrux_OUT[] = { - {I_OUT, 2, {IMMEDIATE,REG_AL,0}, "\1\xE6\24", IF_8086|IF_SB}, - {I_OUT, 2, {IMMEDIATE,REG_AX,0}, "\320\1\xE7\24", IF_8086|IF_SB}, - {I_OUT, 2, {IMMEDIATE,REG_EAX,0}, "\321\1\xE7\24", IF_386|IF_SB}, - {I_OUT, 2, {REG_DX,REG_AL,0}, "\1\xEE", IF_8086}, - {I_OUT, 2, {REG_DX,REG_AX,0}, "\320\1\xEF", IF_8086}, - {I_OUT, 2, {REG_DX,REG_EAX,0}, "\321\1\xEF", IF_386}, - ITEMPLATE_END -}; - -static struct itemplate instrux_OUTSB[] = { - {I_OUTSB, 0, {0,0,0}, "\1\x6E", IF_186}, - ITEMPLATE_END -}; - -static struct itemplate instrux_OUTSD[] = { - {I_OUTSD, 0, {0,0,0}, "\321\1\x6F", IF_386}, - ITEMPLATE_END -}; - -static struct itemplate instrux_OUTSW[] = { - {I_OUTSW, 0, {0,0,0}, "\320\1\x6F", IF_186}, - ITEMPLATE_END -}; - -static struct itemplate instrux_PACKSSDW[] = { - {I_PACKSSDW, 2, {MMXREG,MEMORY,0}, "\301\2\x0F\x6B\110", IF_PENT|IF_MMX|IF_SM}, - {I_PACKSSDW, 2, {MMXREG,MMXREG,0}, "\2\x0F\x6B\110", IF_PENT|IF_MMX}, - {I_PACKSSDW, 2, {XMMREG,XMMREG,0}, "\3\x66\x0F\x6B\110", IF_WILLAMETTE|IF_SSE2}, - {I_PACKSSDW, 2, {XMMREG,MEMORY,0}, "\301\3\x66\x0F\x6B\110", IF_WILLAMETTE|IF_SSE2|IF_SM}, - ITEMPLATE_END -}; - -static struct itemplate instrux_PACKSSWB[] = { - {I_PACKSSWB, 2, {MMXREG,MEMORY,0}, "\301\2\x0F\x63\110", IF_PENT|IF_MMX|IF_SM}, - {I_PACKSSWB, 2, {MMXREG,MMXREG,0}, "\2\x0F\x63\110", IF_PENT|IF_MMX}, - {I_PACKSSWB, 2, {XMMREG,XMMREG,0}, "\3\x66\x0F\x63\110", IF_WILLAMETTE|IF_SSE2}, - {I_PACKSSWB, 2, {XMMREG,MEMORY,0}, "\301\3\x66\x0F\x63\110", IF_WILLAMETTE|IF_SSE2|IF_SM}, - ITEMPLATE_END -}; - -static struct itemplate instrux_PACKUSWB[] = { - {I_PACKUSWB, 2, {MMXREG,MEMORY,0}, "\301\2\x0F\x67\110", IF_PENT|IF_MMX|IF_SM}, - {I_PACKUSWB, 2, {MMXREG,MMXREG,0}, "\2\x0F\x67\110", IF_PENT|IF_MMX}, - {I_PACKUSWB, 2, {XMMREG,XMMREG,0}, "\3\x66\x0F\x67\110", IF_WILLAMETTE|IF_SSE2}, - {I_PACKUSWB, 2, {XMMREG,MEMORY,0}, "\301\3\x66\x0F\x67\110", IF_WILLAMETTE|IF_SSE2|IF_SM}, - ITEMPLATE_END -}; - -static struct itemplate instrux_PADDB[] = { - {I_PADDB, 2, {MMXREG,MEMORY,0}, "\301\2\x0F\xFC\110", IF_PENT|IF_MMX|IF_SM}, - {I_PADDB, 2, {MMXREG,MMXREG,0}, "\2\x0F\xFC\110", IF_PENT|IF_MMX}, - {I_PADDB, 2, {XMMREG,XMMREG,0}, "\3\x66\x0F\xFC\110", IF_WILLAMETTE|IF_SSE2}, - {I_PADDB, 2, {XMMREG,MEMORY,0}, "\301\3\x66\x0F\xFC\110", IF_WILLAMETTE|IF_SSE2|IF_SM}, - ITEMPLATE_END -}; - -static struct itemplate instrux_PADDD[] = { - {I_PADDD, 2, {MMXREG,MEMORY,0}, "\301\2\x0F\xFE\110", IF_PENT|IF_MMX|IF_SM}, - {I_PADDD, 2, {MMXREG,MMXREG,0}, "\2\x0F\xFE\110", IF_PENT|IF_MMX}, - {I_PADDD, 2, {XMMREG,XMMREG,0}, "\3\x66\x0F\xFE\110", IF_WILLAMETTE|IF_SSE2}, - {I_PADDD, 2, {XMMREG,MEMORY,0}, "\301\3\x66\x0F\xFE\110", IF_WILLAMETTE|IF_SSE2|IF_SM}, - ITEMPLATE_END -}; - -static struct itemplate instrux_PADDQ[] = { - {I_PADDQ, 2, {MMXREG,MMXREG,0}, "\2\x0F\xD4\110", IF_WILLAMETTE|IF_SSE2}, - {I_PADDQ, 2, {MMXREG,MEMORY,0}, "\301\2\x0F\xD4\110", IF_WILLAMETTE|IF_SSE2|IF_SM}, - {I_PADDQ, 2, {XMMREG,XMMREG,0}, "\3\x66\x0F\xD4\110", IF_WILLAMETTE|IF_SSE2}, - {I_PADDQ, 2, {XMMREG,MEMORY,0}, "\301\3\x66\x0F\xD4\110", IF_WILLAMETTE|IF_SSE2|IF_SM}, - ITEMPLATE_END -}; - -static struct itemplate instrux_PADDSB[] = { - {I_PADDSB, 2, {MMXREG,MEMORY,0}, "\301\2\x0F\xEC\110", IF_PENT|IF_MMX|IF_SM}, - {I_PADDSB, 2, {MMXREG,MMXREG,0}, "\2\x0F\xEC\110", IF_PENT|IF_MMX}, - {I_PADDSB, 2, {XMMREG,MEMORY,0}, "\301\3\x66\x0F\xEC\110", IF_WILLAMETTE|IF_SSE2|IF_SM}, - {I_PADDSB, 2, {XMMREG,XMMREG,0}, "\3\x66\x0F\xEC\110", IF_WILLAMETTE|IF_SSE2}, - ITEMPLATE_END -}; - -static struct itemplate instrux_PADDSIW[] = { - {I_PADDSIW, 2, {MMXREG,MEMORY,0}, "\301\2\x0F\x51\110", IF_PENT|IF_MMX|IF_SM|IF_CYRIX}, - {I_PADDSIW, 2, {MMXREG,MMXREG,0}, "\2\x0F\x51\110", IF_PENT|IF_MMX|IF_CYRIX}, - ITEMPLATE_END -}; - -static struct itemplate instrux_PADDSW[] = { - {I_PADDSW, 2, {MMXREG,MEMORY,0}, "\301\2\x0F\xED\110", IF_PENT|IF_MMX|IF_SM}, - {I_PADDSW, 2, {MMXREG,MMXREG,0}, "\2\x0F\xED\110", IF_PENT|IF_MMX}, - {I_PADDSW, 2, {XMMREG,MEMORY,0}, "\301\3\x66\x0F\xED\110", IF_WILLAMETTE|IF_SSE2|IF_SM}, - {I_PADDSW, 2, {XMMREG,XMMREG,0}, "\3\x66\x0F\xED\110", IF_WILLAMETTE|IF_SSE2}, - ITEMPLATE_END -}; - -static struct itemplate instrux_PADDUSB[] = { - {I_PADDUSB, 2, {MMXREG,MEMORY,0}, "\301\2\x0F\xDC\110", IF_PENT|IF_MMX|IF_SM}, - {I_PADDUSB, 2, {MMXREG,MMXREG,0}, "\2\x0F\xDC\110", IF_PENT|IF_MMX}, - {I_PADDUSB, 2, {XMMREG,MEMORY,0}, "\301\3\x66\x0F\xDC\110", IF_WILLAMETTE|IF_SSE2|IF_SM}, - {I_PADDUSB, 2, {XMMREG,XMMREG,0}, "\3\x66\x0F\xDC\110", IF_WILLAMETTE|IF_SSE2}, - ITEMPLATE_END -}; - -static struct itemplate instrux_PADDUSW[] = { - {I_PADDUSW, 2, {MMXREG,MEMORY,0}, "\301\2\x0F\xDD\110", IF_PENT|IF_MMX|IF_SM}, - {I_PADDUSW, 2, {MMXREG,MMXREG,0}, "\2\x0F\xDD\110", IF_PENT|IF_MMX}, - {I_PADDUSW, 2, {XMMREG,MEMORY,0}, "\301\3\x66\x0F\xDD\110", IF_WILLAMETTE|IF_SSE2|IF_SM}, - {I_PADDUSW, 2, {XMMREG,XMMREG,0}, "\3\x66\x0F\xDD\110", IF_WILLAMETTE|IF_SSE2}, - ITEMPLATE_END -}; - -static struct itemplate instrux_PADDW[] = { - {I_PADDW, 2, {MMXREG,MEMORY,0}, "\301\2\x0F\xFD\110", IF_PENT|IF_MMX|IF_SM}, - {I_PADDW, 2, {MMXREG,MMXREG,0}, "\2\x0F\xFD\110", IF_PENT|IF_MMX}, - {I_PADDW, 2, {XMMREG,XMMREG,0}, "\3\x66\x0F\xFD\110", IF_WILLAMETTE|IF_SSE2}, - {I_PADDW, 2, {XMMREG,MEMORY,0}, "\301\3\x66\x0F\xFD\110", IF_WILLAMETTE|IF_SSE2|IF_SM}, - ITEMPLATE_END -}; - -static struct itemplate instrux_PAND[] = { - {I_PAND, 2, {MMXREG,MEMORY,0}, "\301\2\x0F\xDB\110", IF_PENT|IF_MMX|IF_SM}, - {I_PAND, 2, {MMXREG,MMXREG,0}, "\2\x0F\xDB\110", IF_PENT|IF_MMX}, - {I_PAND, 2, {XMMREG,XMMREG,0}, "\3\x66\x0F\xDB\110", IF_WILLAMETTE|IF_SSE2}, - {I_PAND, 2, {XMMREG,MEMORY,0}, "\301\3\x66\x0F\xDB\110", IF_WILLAMETTE|IF_SSE2|IF_SM}, - ITEMPLATE_END -}; - -static struct itemplate instrux_PANDN[] = { - {I_PANDN, 2, {MMXREG,MEMORY,0}, "\301\2\x0F\xDF\110", IF_PENT|IF_MMX|IF_SM}, - {I_PANDN, 2, {MMXREG,MMXREG,0}, "\2\x0F\xDF\110", IF_PENT|IF_MMX}, - {I_PANDN, 2, {XMMREG,XMMREG,0}, "\3\x66\x0F\xDF\110", IF_WILLAMETTE|IF_SSE2}, - {I_PANDN, 2, {XMMREG,MEMORY,0}, "\301\3\x66\x0F\xDF\110", IF_WILLAMETTE|IF_SSE2|IF_SM}, - ITEMPLATE_END -}; - -static struct itemplate instrux_PAUSE[] = { - {I_PAUSE, 0, {0,0,0}, "\333\1\x90", IF_WILLAMETTE|IF_SSE2}, - ITEMPLATE_END -}; - -static struct itemplate instrux_PAVEB[] = { - {I_PAVEB, 2, {MMXREG,MEMORY,0}, "\301\2\x0F\x50\110", IF_PENT|IF_MMX|IF_SM|IF_CYRIX}, - {I_PAVEB, 2, {MMXREG,MMXREG,0}, "\2\x0F\x50\110", IF_PENT|IF_MMX|IF_CYRIX}, - ITEMPLATE_END -}; - -static struct itemplate instrux_PAVGB[] = { - {I_PAVGB, 2, {MMXREG,MMXREG,0}, "\2\x0F\xE0\110", IF_KATMAI|IF_MMX}, - {I_PAVGB, 2, {MMXREG,MEMORY,0}, "\301\2\x0F\xE0\110", IF_KATMAI|IF_MMX|IF_SM}, - {I_PAVGB, 2, {XMMREG,XMMREG,0}, "\3\x66\x0F\xE0\110", IF_WILLAMETTE|IF_SSE2}, - {I_PAVGB, 2, {XMMREG,MEMORY,0}, "\301\3\x66\x0F\xE0\110", IF_WILLAMETTE|IF_SSE2|IF_SM}, - ITEMPLATE_END -}; - -static struct itemplate instrux_PAVGUSB[] = { - {I_PAVGUSB, 2, {MMXREG,MEMORY,0}, "\301\2\x0F\x0F\110\01\xBF", IF_PENT|IF_3DNOW|IF_SM}, - {I_PAVGUSB, 2, {MMXREG,MMXREG,0}, "\2\x0F\x0F\110\01\xBF", IF_PENT|IF_3DNOW}, - ITEMPLATE_END -}; - -static struct itemplate instrux_PAVGW[] = { - {I_PAVGW, 2, {MMXREG,MMXREG,0}, "\2\x0F\xE3\110", IF_KATMAI|IF_MMX}, - {I_PAVGW, 2, {MMXREG,MEMORY,0}, "\301\2\x0F\xE3\110", IF_KATMAI|IF_MMX|IF_SM}, - {I_PAVGW, 2, {XMMREG,XMMREG,0}, "\3\x66\x0F\xE3\110", IF_WILLAMETTE|IF_SSE2}, - {I_PAVGW, 2, {XMMREG,MEMORY,0}, "\301\3\x66\x0F\xE3\110", IF_WILLAMETTE|IF_SSE2|IF_SM}, - ITEMPLATE_END -}; - -static struct itemplate instrux_PCMPEQB[] = { - {I_PCMPEQB, 2, {MMXREG,MEMORY,0}, "\301\2\x0F\x74\110", IF_PENT|IF_MMX|IF_SM}, - {I_PCMPEQB, 2, {MMXREG,MMXREG,0}, "\2\x0F\x74\110", IF_PENT|IF_MMX}, - {I_PCMPEQB, 2, {XMMREG,XMMREG,0}, "\3\x66\x0F\x74\110", IF_WILLAMETTE|IF_SSE2}, - {I_PCMPEQB, 2, {XMMREG,MEMORY,0}, "\301\3\x66\x0F\x74\110", IF_WILLAMETTE|IF_SSE2|IF_SM}, - ITEMPLATE_END -}; - -static struct itemplate instrux_PCMPEQD[] = { - {I_PCMPEQD, 2, {MMXREG,MEMORY,0}, "\301\2\x0F\x76\110", IF_PENT|IF_MMX|IF_SM}, - {I_PCMPEQD, 2, {MMXREG,MMXREG,0}, "\2\x0F\x76\110", IF_PENT|IF_MMX}, - {I_PCMPEQD, 2, {XMMREG,XMMREG,0}, "\3\x66\x0F\x76\110", IF_WILLAMETTE|IF_SSE2}, - {I_PCMPEQD, 2, {XMMREG,MEMORY,0}, "\301\3\x66\x0F\x76\110", IF_WILLAMETTE|IF_SSE2|IF_SM}, - ITEMPLATE_END -}; - -static struct itemplate instrux_PCMPEQW[] = { - {I_PCMPEQW, 2, {MMXREG,MEMORY,0}, "\301\2\x0F\x75\110", IF_PENT|IF_MMX|IF_SM}, - {I_PCMPEQW, 2, {MMXREG,MMXREG,0}, "\2\x0F\x75\110", IF_PENT|IF_MMX}, - {I_PCMPEQW, 2, {XMMREG,XMMREG,0}, "\3\x66\x0F\x75\110", IF_WILLAMETTE|IF_SSE2}, - {I_PCMPEQW, 2, {XMMREG,MEMORY,0}, "\301\3\x66\x0F\x75\110", IF_WILLAMETTE|IF_SSE2|IF_SM}, - ITEMPLATE_END -}; - -static struct itemplate instrux_PCMPGTB[] = { - {I_PCMPGTB, 2, {MMXREG,MEMORY,0}, "\301\2\x0F\x64\110", IF_PENT|IF_MMX|IF_SM}, - {I_PCMPGTB, 2, {MMXREG,MMXREG,0}, "\2\x0F\x64\110", IF_PENT|IF_MMX}, - {I_PCMPGTB, 2, {XMMREG,XMMREG,0}, "\3\x66\x0F\x64\110", IF_WILLAMETTE|IF_SSE2}, - {I_PCMPGTB, 2, {XMMREG,MEMORY,0}, "\301\3\x66\x0F\x64\110", IF_WILLAMETTE|IF_SSE2|IF_SM}, - ITEMPLATE_END -}; - -static struct itemplate instrux_PCMPGTD[] = { - {I_PCMPGTD, 2, {MMXREG,MEMORY,0}, "\301\2\x0F\x66\110", IF_PENT|IF_MMX|IF_SM}, - {I_PCMPGTD, 2, {MMXREG,MMXREG,0}, "\2\x0F\x66\110", IF_PENT|IF_MMX}, - {I_PCMPGTD, 2, {XMMREG,XMMREG,0}, "\3\x66\x0F\x66\110", IF_WILLAMETTE|IF_SSE2}, - {I_PCMPGTD, 2, {XMMREG,MEMORY,0}, "\301\3\x66\x0F\x66\110", IF_WILLAMETTE|IF_SSE2|IF_SM}, - ITEMPLATE_END -}; - -static struct itemplate instrux_PCMPGTW[] = { - {I_PCMPGTW, 2, {MMXREG,MEMORY,0}, "\301\2\x0F\x65\110", IF_PENT|IF_MMX|IF_SM}, - {I_PCMPGTW, 2, {MMXREG,MMXREG,0}, "\2\x0F\x65\110", IF_PENT|IF_MMX}, - {I_PCMPGTW, 2, {XMMREG,XMMREG,0}, "\3\x66\x0F\x65\110", IF_WILLAMETTE|IF_SSE2}, - {I_PCMPGTW, 2, {XMMREG,MEMORY,0}, "\301\3\x66\x0F\x65\110", IF_WILLAMETTE|IF_SSE2|IF_SM}, - ITEMPLATE_END -}; - -static struct itemplate instrux_PDISTIB[] = { - {I_PDISTIB, 2, {MMXREG,MEMORY,0}, "\301\2\x0F\x54\110", IF_PENT|IF_MMX|IF_SM|IF_CYRIX}, - ITEMPLATE_END -}; - -static struct itemplate instrux_PEXTRW[] = { - {I_PEXTRW, 3, {REG32,MMXREG,IMMEDIATE}, "\2\x0F\xC5\110\26", IF_KATMAI|IF_MMX|IF_SB|IF_AR2}, - {I_PEXTRW, 3, {REG32,XMMREG,IMMEDIATE}, "\3\x66\x0F\xC5\110\26", IF_WILLAMETTE|IF_SSE2|IF_SB|IF_AR2}, - ITEMPLATE_END -}; - -static struct itemplate instrux_PF2ID[] = { - {I_PF2ID, 2, {MMXREG,MEMORY,0}, "\301\2\x0F\x0F\110\01\x1D", IF_PENT|IF_3DNOW|IF_SM}, - {I_PF2ID, 2, {MMXREG,MMXREG,0}, "\2\x0F\x0F\110\01\x1D", IF_PENT|IF_3DNOW}, - ITEMPLATE_END -}; - -static struct itemplate instrux_PF2IW[] = { - {I_PF2IW, 2, {MMXREG,MEMORY,0}, "\301\2\x0F\x0F\110\01\x1C", IF_PENT|IF_3DNOW|IF_SM}, - {I_PF2IW, 2, {MMXREG,MMXREG,0}, "\2\x0F\x0F\110\01\x1C", IF_PENT|IF_3DNOW}, - ITEMPLATE_END -}; - -static struct itemplate instrux_PFACC[] = { - {I_PFACC, 2, {MMXREG,MEMORY,0}, "\301\2\x0F\x0F\110\01\xAE", IF_PENT|IF_3DNOW|IF_SM}, - {I_PFACC, 2, {MMXREG,MMXREG,0}, "\2\x0F\x0F\110\01\xAE", IF_PENT|IF_3DNOW}, - ITEMPLATE_END -}; - -static struct itemplate instrux_PFADD[] = { - {I_PFADD, 2, {MMXREG,MEMORY,0}, "\301\2\x0F\x0F\110\01\x9E", IF_PENT|IF_3DNOW|IF_SM}, - {I_PFADD, 2, {MMXREG,MMXREG,0}, "\2\x0F\x0F\110\01\x9E", IF_PENT|IF_3DNOW}, - ITEMPLATE_END -}; - -static struct itemplate instrux_PFCMPEQ[] = { - {I_PFCMPEQ, 2, {MMXREG,MEMORY,0}, "\301\2\x0F\x0F\110\01\xB0", IF_PENT|IF_3DNOW|IF_SM}, - {I_PFCMPEQ, 2, {MMXREG,MMXREG,0}, "\2\x0F\x0F\110\01\xB0", IF_PENT|IF_3DNOW}, - ITEMPLATE_END -}; - -static struct itemplate instrux_PFCMPGE[] = { - {I_PFCMPGE, 2, {MMXREG,MEMORY,0}, "\301\2\x0F\x0F\110\01\x90", IF_PENT|IF_3DNOW|IF_SM}, - {I_PFCMPGE, 2, {MMXREG,MMXREG,0}, "\2\x0F\x0F\110\01\x90", IF_PENT|IF_3DNOW}, - ITEMPLATE_END -}; - -static struct itemplate instrux_PFCMPGT[] = { - {I_PFCMPGT, 2, {MMXREG,MEMORY,0}, "\301\2\x0F\x0F\110\01\xA0", IF_PENT|IF_3DNOW|IF_SM}, - {I_PFCMPGT, 2, {MMXREG,MMXREG,0}, "\2\x0F\x0F\110\01\xA0", IF_PENT|IF_3DNOW}, - ITEMPLATE_END -}; - -static struct itemplate instrux_PFMAX[] = { - {I_PFMAX, 2, {MMXREG,MEMORY,0}, "\301\2\x0F\x0F\110\01\xA4", IF_PENT|IF_3DNOW|IF_SM}, - {I_PFMAX, 2, {MMXREG,MMXREG,0}, "\2\x0F\x0F\110\01\xA4", IF_PENT|IF_3DNOW}, - ITEMPLATE_END -}; - -static struct itemplate instrux_PFMIN[] = { - {I_PFMIN, 2, {MMXREG,MEMORY,0}, "\301\2\x0F\x0F\110\01\x94", IF_PENT|IF_3DNOW|IF_SM}, - {I_PFMIN, 2, {MMXREG,MMXREG,0}, "\2\x0F\x0F\110\01\x94", IF_PENT|IF_3DNOW}, - ITEMPLATE_END -}; - -static struct itemplate instrux_PFMUL[] = { - {I_PFMUL, 2, {MMXREG,MEMORY,0}, "\301\2\x0F\x0F\110\01\xB4", IF_PENT|IF_3DNOW|IF_SM}, - {I_PFMUL, 2, {MMXREG,MMXREG,0}, "\2\x0F\x0F\110\01\xB4", IF_PENT|IF_3DNOW}, - ITEMPLATE_END -}; - -static struct itemplate instrux_PFNACC[] = { - {I_PFNACC, 2, {MMXREG,MEMORY,0}, "\301\2\x0F\x0F\110\01\x8A", IF_PENT|IF_3DNOW|IF_SM}, - {I_PFNACC, 2, {MMXREG,MMXREG,0}, "\2\x0F\x0F\110\01\x8A", IF_PENT|IF_3DNOW}, - ITEMPLATE_END -}; - -static struct itemplate instrux_PFPNACC[] = { - {I_PFPNACC, 2, {MMXREG,MEMORY,0}, "\301\2\x0F\x0F\110\01\x8E", IF_PENT|IF_3DNOW|IF_SM}, - {I_PFPNACC, 2, {MMXREG,MMXREG,0}, "\2\x0F\x0F\110\01\x8E", IF_PENT|IF_3DNOW}, - ITEMPLATE_END -}; - -static struct itemplate instrux_PFRCP[] = { - {I_PFRCP, 2, {MMXREG,MEMORY,0}, "\301\2\x0F\x0F\110\01\x96", IF_PENT|IF_3DNOW|IF_SM}, - {I_PFRCP, 2, {MMXREG,MMXREG,0}, "\2\x0F\x0F\110\01\x96", IF_PENT|IF_3DNOW}, - ITEMPLATE_END -}; - -static struct itemplate instrux_PFRCPIT1[] = { - {I_PFRCPIT1, 2, {MMXREG,MEMORY,0}, "\301\2\x0F\x0F\110\01\xA6", IF_PENT|IF_3DNOW|IF_SM}, - {I_PFRCPIT1, 2, {MMXREG,MMXREG,0}, "\2\x0F\x0F\110\01\xA6", IF_PENT|IF_3DNOW}, - ITEMPLATE_END -}; - -static struct itemplate instrux_PFRCPIT2[] = { - {I_PFRCPIT2, 2, {MMXREG,MEMORY,0}, "\301\2\x0F\x0F\110\01\xB6", IF_PENT|IF_3DNOW|IF_SM}, - {I_PFRCPIT2, 2, {MMXREG,MMXREG,0}, "\2\x0F\x0F\110\01\xB6", IF_PENT|IF_3DNOW}, - ITEMPLATE_END -}; - -static struct itemplate instrux_PFRSQIT1[] = { - {I_PFRSQIT1, 2, {MMXREG,MEMORY,0}, "\301\2\x0F\x0F\110\01\xA7", IF_PENT|IF_3DNOW|IF_SM}, - {I_PFRSQIT1, 2, {MMXREG,MMXREG,0}, "\2\x0F\x0F\110\01\xA7", IF_PENT|IF_3DNOW}, - ITEMPLATE_END -}; - -static struct itemplate instrux_PFRSQRT[] = { - {I_PFRSQRT, 2, {MMXREG,MEMORY,0}, "\301\2\x0F\x0F\110\01\x97", IF_PENT|IF_3DNOW|IF_SM}, - {I_PFRSQRT, 2, {MMXREG,MMXREG,0}, "\2\x0F\x0F\110\01\x97", IF_PENT|IF_3DNOW}, - ITEMPLATE_END -}; - -static struct itemplate instrux_PFSUB[] = { - {I_PFSUB, 2, {MMXREG,MEMORY,0}, "\301\2\x0F\x0F\110\01\x9A", IF_PENT|IF_3DNOW|IF_SM}, - {I_PFSUB, 2, {MMXREG,MMXREG,0}, "\2\x0F\x0F\110\01\x9A", IF_PENT|IF_3DNOW}, - ITEMPLATE_END -}; - -static struct itemplate instrux_PFSUBR[] = { - {I_PFSUBR, 2, {MMXREG,MEMORY,0}, "\301\2\x0F\x0F\110\01\xAA", IF_PENT|IF_3DNOW|IF_SM}, - {I_PFSUBR, 2, {MMXREG,MMXREG,0}, "\2\x0F\x0F\110\01\xAA", IF_PENT|IF_3DNOW}, - ITEMPLATE_END -}; - -static struct itemplate instrux_PI2FD[] = { - {I_PI2FD, 2, {MMXREG,MEMORY,0}, "\301\2\x0F\x0F\110\01\x0D", IF_PENT|IF_3DNOW|IF_SM}, - {I_PI2FD, 2, {MMXREG,MMXREG,0}, "\2\x0F\x0F\110\01\x0D", IF_PENT|IF_3DNOW}, - ITEMPLATE_END -}; - -static struct itemplate instrux_PI2FW[] = { - {I_PI2FW, 2, {MMXREG,MEMORY,0}, "\301\2\x0F\x0F\110\01\x0C", IF_PENT|IF_3DNOW|IF_SM}, - {I_PI2FW, 2, {MMXREG,MMXREG,0}, "\2\x0F\x0F\110\01\x0C", IF_PENT|IF_3DNOW}, - ITEMPLATE_END -}; - -static struct itemplate instrux_PINSRW[] = { - {I_PINSRW, 3, {MMXREG,REG16,IMMEDIATE}, "\2\x0F\xC4\110\26", IF_KATMAI|IF_MMX|IF_SB|IF_AR2}, - {I_PINSRW, 3, {MMXREG,REG32,IMMEDIATE}, "\2\x0F\xC4\110\26", IF_KATMAI|IF_MMX|IF_SB|IF_AR2}, - {I_PINSRW, 3, {MMXREG,MEMORY,IMMEDIATE}, "\301\2\x0F\xC4\110\26", IF_KATMAI|IF_MMX|IF_SB|IF_AR2}, - {I_PINSRW, 3, {MMXREG,MEMORY|BITS16,IMMEDIATE}, "\301\2\x0F\xC4\110\26", IF_KATMAI|IF_MMX|IF_SB|IF_AR2}, - {I_PINSRW, 3, {XMMREG,REG16,IMMEDIATE}, "\3\x66\x0F\xC4\110\26", IF_WILLAMETTE|IF_SSE2|IF_SB|IF_AR2}, - {I_PINSRW, 3, {XMMREG,REG32,IMMEDIATE}, "\3\x66\x0F\xC4\110\26", IF_WILLAMETTE|IF_SSE2|IF_SB|IF_AR2}, - {I_PINSRW, 3, {XMMREG,MEMORY,IMMEDIATE}, "\301\3\x66\x0F\xC4\110\26", IF_WILLAMETTE|IF_SSE2|IF_SB|IF_AR2}, - {I_PINSRW, 3, {XMMREG,MEMORY|BITS16,IMMEDIATE}, "\301\3\x66\x0F\xC4\110\26", IF_WILLAMETTE|IF_SSE2|IF_SB|IF_AR2}, - ITEMPLATE_END -}; - -static struct itemplate instrux_PMACHRIW[] = { - {I_PMACHRIW, 2, {MMXREG,MEMORY,0}, "\301\2\x0F\x5E\110", IF_PENT|IF_MMX|IF_SM|IF_CYRIX}, - ITEMPLATE_END -}; - -static struct itemplate instrux_PMADDWD[] = { - {I_PMADDWD, 2, {MMXREG,MEMORY,0}, "\301\2\x0F\xF5\110", IF_PENT|IF_MMX|IF_SM}, - {I_PMADDWD, 2, {MMXREG,MMXREG,0}, "\2\x0F\xF5\110", IF_PENT|IF_MMX}, - {I_PMADDWD, 2, {XMMREG,MEMORY,0}, "\301\3\x66\x0F\xF5\110", IF_WILLAMETTE|IF_SSE2|IF_SM}, - {I_PMADDWD, 2, {XMMREG,XMMREG,0}, "\3\x66\x0F\xF5\110", IF_WILLAMETTE|IF_SSE2}, - ITEMPLATE_END -}; - -static struct itemplate instrux_PMAGW[] = { - {I_PMAGW, 2, {MMXREG,MEMORY,0}, "\301\2\x0F\x52\110", IF_PENT|IF_MMX|IF_SM|IF_CYRIX}, - {I_PMAGW, 2, {MMXREG,MMXREG,0}, "\2\x0F\x52\110", IF_PENT|IF_MMX|IF_CYRIX}, - ITEMPLATE_END -}; - -static struct itemplate instrux_PMAXSW[] = { - {I_PMAXSW, 2, {MMXREG,MMXREG,0}, "\2\x0F\xEE\110", IF_KATMAI|IF_MMX}, - {I_PMAXSW, 2, {MMXREG,MEMORY,0}, "\301\2\x0F\xEE\110", IF_KATMAI|IF_MMX|IF_SM}, - {I_PMAXSW, 2, {XMMREG,XMMREG,0}, "\3\x66\x0F\xEE\110", IF_WILLAMETTE|IF_SSE2}, - {I_PMAXSW, 2, {XMMREG,MEMORY,0}, "\301\3\x66\x0F\xEE\110", IF_WILLAMETTE|IF_SSE2|IF_SM}, - ITEMPLATE_END -}; - -static struct itemplate instrux_PMAXUB[] = { - {I_PMAXUB, 2, {MMXREG,MMXREG,0}, "\2\x0F\xDE\110", IF_KATMAI|IF_MMX}, - {I_PMAXUB, 2, {MMXREG,MEMORY,0}, "\301\2\x0F\xDE\110", IF_KATMAI|IF_MMX|IF_SM}, - {I_PMAXUB, 2, {XMMREG,XMMREG,0}, "\3\x66\x0F\xDE\110", IF_WILLAMETTE|IF_SSE2}, - {I_PMAXUB, 2, {XMMREG,MEMORY,0}, "\301\3\x66\x0F\xDE\110", IF_WILLAMETTE|IF_SSE2|IF_SM}, - ITEMPLATE_END -}; - -static struct itemplate instrux_PMINSW[] = { - {I_PMINSW, 2, {MMXREG,MMXREG,0}, "\2\x0F\xEA\110", IF_KATMAI|IF_MMX}, - {I_PMINSW, 2, {MMXREG,MEMORY,0}, "\301\2\x0F\xEA\110", IF_KATMAI|IF_MMX|IF_SM}, - {I_PMINSW, 2, {XMMREG,XMMREG,0}, "\3\x66\x0F\xEA\110", IF_WILLAMETTE|IF_SSE2}, - {I_PMINSW, 2, {XMMREG,MEMORY,0}, "\301\3\x66\x0F\xEA\110", IF_WILLAMETTE|IF_SSE2|IF_SM}, - ITEMPLATE_END -}; - -static struct itemplate instrux_PMINUB[] = { - {I_PMINUB, 2, {MMXREG,MMXREG,0}, "\2\x0F\xDA\110", IF_KATMAI|IF_MMX}, - {I_PMINUB, 2, {MMXREG,MEMORY,0}, "\301\2\x0F\xDA\110", IF_KATMAI|IF_MMX|IF_SM}, - {I_PMINUB, 2, {XMMREG,XMMREG,0}, "\3\x66\x0F\xDA\110", IF_WILLAMETTE|IF_SSE2}, - {I_PMINUB, 2, {XMMREG,MEMORY,0}, "\301\3\x66\x0F\xDA\110", IF_WILLAMETTE|IF_SSE2|IF_SM}, - ITEMPLATE_END -}; - -static struct itemplate instrux_PMOVMSKB[] = { - {I_PMOVMSKB, 2, {REG32,MMXREG,0}, "\2\x0F\xD7\110", IF_KATMAI|IF_MMX}, - {I_PMOVMSKB, 2, {REG32,XMMREG,0}, "\3\x66\x0F\xD7\110", IF_WILLAMETTE|IF_SSE2}, - ITEMPLATE_END -}; - -static struct itemplate instrux_PMULHRIW[] = { - {I_PMULHRIW, 2, {MMXREG,MEMORY,0}, "\301\2\x0F\x5D\110", IF_PENT|IF_MMX|IF_SM|IF_CYRIX}, - {I_PMULHRIW, 2, {MMXREG,MMXREG,0}, "\2\x0F\x5D\110", IF_PENT|IF_MMX|IF_CYRIX}, - ITEMPLATE_END -}; - -static struct itemplate instrux_PMULHRWA[] = { - {I_PMULHRWA, 2, {MMXREG,MEMORY,0}, "\301\2\x0F\x0F\110\1\xB7", IF_PENT|IF_3DNOW|IF_SM}, - {I_PMULHRWA, 2, {MMXREG,MMXREG,0}, "\2\x0F\x0F\110\1\xB7", IF_PENT|IF_3DNOW}, - ITEMPLATE_END -}; - -static struct itemplate instrux_PMULHRWC[] = { - {I_PMULHRWC, 2, {MMXREG,MEMORY,0}, "\301\2\x0F\x59\110", IF_PENT|IF_MMX|IF_SM|IF_CYRIX}, - {I_PMULHRWC, 2, {MMXREG,MMXREG,0}, "\2\x0F\x59\110", IF_PENT|IF_MMX|IF_CYRIX}, - ITEMPLATE_END -}; - -static struct itemplate instrux_PMULHUW[] = { - {I_PMULHUW, 2, {MMXREG,MMXREG,0}, "\2\x0F\xE4\110", IF_KATMAI|IF_MMX}, - {I_PMULHUW, 2, {MMXREG,MEMORY,0}, "\301\2\x0F\xE4\110", IF_KATMAI|IF_MMX|IF_SM}, - {I_PMULHUW, 2, {XMMREG,XMMREG,0}, "\3\x66\x0F\xE4\110", IF_WILLAMETTE|IF_SSE2}, - {I_PMULHUW, 2, {XMMREG,MEMORY,0}, "\301\3\x66\x0F\xE4\110", IF_WILLAMETTE|IF_SSE2|IF_SM}, - ITEMPLATE_END -}; - -static struct itemplate instrux_PMULHW[] = { - {I_PMULHW, 2, {MMXREG,MEMORY,0}, "\301\2\x0F\xE5\110", IF_PENT|IF_MMX|IF_SM}, - {I_PMULHW, 2, {MMXREG,MMXREG,0}, "\2\x0F\xE5\110", IF_PENT|IF_MMX}, - {I_PMULHW, 2, {XMMREG,MEMORY,0}, "\301\3\x66\x0F\xE5\110", IF_WILLAMETTE|IF_SSE2|IF_SM}, - {I_PMULHW, 2, {XMMREG,XMMREG,0}, "\3\x66\x0F\xE5\110", IF_WILLAMETTE|IF_SSE2}, - ITEMPLATE_END -}; - -static struct itemplate instrux_PMULLW[] = { - {I_PMULLW, 2, {MMXREG,MEMORY,0}, "\301\2\x0F\xD5\110", IF_PENT|IF_MMX|IF_SM}, - {I_PMULLW, 2, {MMXREG,MMXREG,0}, "\2\x0F\xD5\110", IF_PENT|IF_MMX}, - {I_PMULLW, 2, {XMMREG,MEMORY,0}, "\301\3\x66\x0F\xD5\110", IF_WILLAMETTE|IF_SSE2|IF_SM}, - {I_PMULLW, 2, {XMMREG,XMMREG,0}, "\3\x66\x0F\xD5\110", IF_WILLAMETTE|IF_SSE2}, - ITEMPLATE_END -}; - -static struct itemplate instrux_PMULUDQ[] = { - {I_PMULUDQ, 2, {MMXREG,MMXREG,0}, "\2\x0F\xF4\110", IF_WILLAMETTE|IF_SSE2}, - {I_PMULUDQ, 2, {MMXREG,MEMORY,0}, "\301\2\x0F\xF4\110", IF_WILLAMETTE|IF_SSE2|IF_SM}, - {I_PMULUDQ, 2, {XMMREG,XMMREG,0}, "\3\x66\x0F\xF4\110", IF_WILLAMETTE|IF_SSE2}, - {I_PMULUDQ, 2, {XMMREG,MEMORY,0}, "\301\3\x66\x0F\xF4\110", IF_WILLAMETTE|IF_SSE2|IF_SM}, - ITEMPLATE_END -}; - -static struct itemplate instrux_PMVGEZB[] = { - {I_PMVGEZB, 2, {MMXREG,MEMORY,0}, "\301\2\x0F\x5C\110", IF_PENT|IF_MMX|IF_SM|IF_CYRIX}, - ITEMPLATE_END -}; - -static struct itemplate instrux_PMVLZB[] = { - {I_PMVLZB, 2, {MMXREG,MEMORY,0}, "\301\2\x0F\x5B\110", IF_PENT|IF_MMX|IF_SM|IF_CYRIX}, - ITEMPLATE_END -}; - -static struct itemplate instrux_PMVNZB[] = { - {I_PMVNZB, 2, {MMXREG,MEMORY,0}, "\301\2\x0F\x5A\110", IF_PENT|IF_MMX|IF_SM|IF_CYRIX}, - ITEMPLATE_END -}; - -static struct itemplate instrux_PMVZB[] = { - {I_PMVZB, 2, {MMXREG,MEMORY,0}, "\301\2\x0F\x58\110", IF_PENT|IF_MMX|IF_SM|IF_CYRIX}, - ITEMPLATE_END -}; - -static struct itemplate instrux_POP[] = { - {I_POP, 1, {REG16,0,0}, "\320\10\x58", IF_8086}, - {I_POP, 1, {REG32,0,0}, "\321\10\x58", IF_386}, - {I_POP, 1, {REGMEM|BITS16,0,0}, "\320\300\1\x8F\200", IF_8086}, - {I_POP, 1, {REGMEM|BITS32,0,0}, "\321\300\1\x8F\200", IF_386}, - {I_POP, 1, {REG_CS,0,0}, "\1\x0F", IF_8086|IF_UNDOC}, - {I_POP, 1, {REG_DESS,0,0}, "\4", IF_8086}, - {I_POP, 1, {REG_FSGS,0,0}, "\1\x0F\5", IF_386}, - ITEMPLATE_END -}; - -static struct itemplate instrux_POPA[] = { - {I_POPA, 0, {0,0,0}, "\322\1\x61", IF_186}, - ITEMPLATE_END -}; - -static struct itemplate instrux_POPAD[] = { - {I_POPAD, 0, {0,0,0}, "\321\1\x61", IF_386}, - ITEMPLATE_END -}; - -static struct itemplate instrux_POPAW[] = { - {I_POPAW, 0, {0,0,0}, "\320\1\x61", IF_186}, - ITEMPLATE_END -}; - -static struct itemplate instrux_POPF[] = { - {I_POPF, 0, {0,0,0}, "\322\1\x9D", IF_8086}, - ITEMPLATE_END -}; - -static struct itemplate instrux_POPFD[] = { - {I_POPFD, 0, {0,0,0}, "\321\1\x9D", IF_386}, - ITEMPLATE_END -}; - -static struct itemplate instrux_POPFW[] = { - {I_POPFW, 0, {0,0,0}, "\320\1\x9D", IF_8086}, - ITEMPLATE_END -}; - -static struct itemplate instrux_POR[] = { - {I_POR, 2, {MMXREG,MEMORY,0}, "\301\2\x0F\xEB\110", IF_PENT|IF_MMX|IF_SM}, - {I_POR, 2, {MMXREG,MMXREG,0}, "\2\x0F\xEB\110", IF_PENT|IF_MMX}, - {I_POR, 2, {XMMREG,MEMORY,0}, "\301\3\x66\x0F\xEB\110", IF_WILLAMETTE|IF_SSE2|IF_SM}, - {I_POR, 2, {XMMREG,XMMREG,0}, "\3\x66\x0F\xEB\110", IF_WILLAMETTE|IF_SSE2}, - ITEMPLATE_END -}; - -static struct itemplate instrux_PREFETCH[] = { - {I_PREFETCH, 1, {MEMORY,0,0}, "\2\x0F\x0D\200", IF_PENT|IF_3DNOW|IF_SM}, - ITEMPLATE_END -}; - -static struct itemplate instrux_PREFETCHNTA[] = { - {I_PREFETCHNTA, 1, {MEMORY,0,0}, "\300\2\x0F\x18\200", IF_KATMAI}, - ITEMPLATE_END -}; - -static struct itemplate instrux_PREFETCHT0[] = { - {I_PREFETCHT0, 1, {MEMORY,0,0}, "\300\2\x0F\x18\201", IF_KATMAI}, - ITEMPLATE_END -}; - -static struct itemplate instrux_PREFETCHT1[] = { - {I_PREFETCHT1, 1, {MEMORY,0,0}, "\300\2\x0F\x18\202", IF_KATMAI}, - ITEMPLATE_END -}; - -static struct itemplate instrux_PREFETCHT2[] = { - {I_PREFETCHT2, 1, {MEMORY,0,0}, "\300\2\x0F\x18\203", IF_KATMAI}, - ITEMPLATE_END -}; - -static struct itemplate instrux_PREFETCHW[] = { - {I_PREFETCHW, 1, {MEMORY,0,0}, "\2\x0F\x0D\201", IF_PENT|IF_3DNOW|IF_SM}, - ITEMPLATE_END -}; - -static struct itemplate instrux_PSADBW[] = { - {I_PSADBW, 2, {MMXREG,MMXREG,0}, "\2\x0F\xF6\110", IF_KATMAI|IF_MMX}, - {I_PSADBW, 2, {MMXREG,MEMORY,0}, "\301\2\x0F\xF6\110", IF_KATMAI|IF_MMX|IF_SM}, - {I_PSADBW, 2, {XMMREG,XMMREG,0}, "\3\x66\x0F\xF6\110", IF_WILLAMETTE|IF_SSE2}, - {I_PSADBW, 2, {XMMREG,MEMORY,0}, "\301\3\x66\x0F\xF6\110", IF_WILLAMETTE|IF_SSE2|IF_SM}, - ITEMPLATE_END -}; - -static struct itemplate instrux_PSHUFD[] = { - {I_PSHUFD, 3, {XMMREG,XMMREG,IMMEDIATE}, "\3\x66\x0F\x70\110\22", IF_WILLAMETTE|IF_SSE2|IF_SB|IF_AR2}, - {I_PSHUFD, 3, {XMMREG,MEMORY,IMMEDIATE}, "\301\3\x66\x0F\x70\110\22", IF_WILLAMETTE|IF_SSE2|IF_SM2|IF_SB|IF_AR2}, - ITEMPLATE_END -}; - -static struct itemplate instrux_PSHUFHW[] = { - {I_PSHUFHW, 3, {XMMREG,XMMREG,IMMEDIATE}, "\333\2\x0F\x70\110\22", IF_WILLAMETTE|IF_SSE2|IF_SB|IF_AR2}, - {I_PSHUFHW, 3, {XMMREG,MEMORY,IMMEDIATE}, "\301\333\2\x0F\x70\110\22", IF_WILLAMETTE|IF_SSE2|IF_SM2|IF_SB|IF_AR2}, - ITEMPLATE_END -}; - -static struct itemplate instrux_PSHUFLW[] = { - {I_PSHUFLW, 3, {XMMREG,XMMREG,IMMEDIATE}, "\3\xF2\x0F\x70\110\22", IF_WILLAMETTE|IF_SSE2|IF_SB|IF_AR2}, - {I_PSHUFLW, 3, {XMMREG,MEMORY,IMMEDIATE}, "\301\3\xF2\x0F\x70\110\22", IF_WILLAMETTE|IF_SSE2|IF_SM2|IF_SB|IF_AR2}, - ITEMPLATE_END -}; - -static struct itemplate instrux_PSHUFW[] = { - {I_PSHUFW, 3, {MMXREG,MMXREG,IMMEDIATE}, "\2\x0F\x70\110\22", IF_KATMAI|IF_MMX|IF_SB|IF_AR2}, - {I_PSHUFW, 3, {MMXREG,MEMORY,IMMEDIATE}, "\301\2\x0F\x70\110\22", IF_KATMAI|IF_MMX|IF_SM2|IF_SB|IF_AR2}, - ITEMPLATE_END -}; - -static struct itemplate instrux_PSLLD[] = { - {I_PSLLD, 2, {MMXREG,MEMORY,0}, "\301\2\x0F\xF2\110", IF_PENT|IF_MMX|IF_SM}, - {I_PSLLD, 2, {MMXREG,MMXREG,0}, "\2\x0F\xF2\110", IF_PENT|IF_MMX}, - {I_PSLLD, 2, {MMXREG,IMMEDIATE,0}, "\2\x0F\x72\206\25", IF_PENT|IF_MMX}, - {I_PSLLD, 2, {XMMREG,MEMORY,0}, "\301\3\x66\x0F\xF2\110", IF_WILLAMETTE|IF_SSE2|IF_SM}, - {I_PSLLD, 2, {XMMREG,XMMREG,0}, "\3\x66\x0F\xF2\110", IF_WILLAMETTE|IF_SSE2}, - {I_PSLLD, 2, {XMMREG,IMMEDIATE,0}, "\3\x66\x0F\x72\206\25", IF_WILLAMETTE|IF_SSE2|IF_SB|IF_AR1}, - ITEMPLATE_END -}; - -static struct itemplate instrux_PSLLDQ[] = { - {I_PSLLDQ, 2, {XMMREG,IMMEDIATE,0}, "\3\x66\x0F\x73\207\25", IF_WILLAMETTE|IF_SSE2|IF_SB|IF_AR1}, - ITEMPLATE_END -}; - -static struct itemplate instrux_PSLLQ[] = { - {I_PSLLQ, 2, {MMXREG,MEMORY,0}, "\301\2\x0F\xF3\110", IF_PENT|IF_MMX|IF_SM}, - {I_PSLLQ, 2, {MMXREG,MMXREG,0}, "\2\x0F\xF3\110", IF_PENT|IF_MMX}, - {I_PSLLQ, 2, {MMXREG,IMMEDIATE,0}, "\2\x0F\x73\206\25", IF_PENT|IF_MMX}, - {I_PSLLQ, 2, {XMMREG,MEMORY,0}, "\301\3\x66\x0F\xF3\110", IF_WILLAMETTE|IF_SSE2|IF_SM}, - {I_PSLLQ, 2, {XMMREG,XMMREG,0}, "\3\x66\x0F\xF3\110", IF_WILLAMETTE|IF_SSE2}, - {I_PSLLQ, 2, {XMMREG,IMMEDIATE,0}, "\3\x66\x0F\x73\206\25", IF_WILLAMETTE|IF_SSE2|IF_SB|IF_AR1}, - ITEMPLATE_END -}; - -static struct itemplate instrux_PSLLW[] = { - {I_PSLLW, 2, {MMXREG,MEMORY,0}, "\301\2\x0F\xF1\110", IF_PENT|IF_MMX|IF_SM}, - {I_PSLLW, 2, {MMXREG,MMXREG,0}, "\2\x0F\xF1\110", IF_PENT|IF_MMX}, - {I_PSLLW, 2, {MMXREG,IMMEDIATE,0}, "\2\x0F\x71\206\25", IF_PENT|IF_MMX}, - {I_PSLLW, 2, {XMMREG,MEMORY,0}, "\301\3\x66\x0F\xF1\110", IF_WILLAMETTE|IF_SSE2|IF_SM}, - {I_PSLLW, 2, {XMMREG,XMMREG,0}, "\3\x66\x0F\xF1\110", IF_WILLAMETTE|IF_SSE2}, - {I_PSLLW, 2, {XMMREG,IMMEDIATE,0}, "\3\x66\x0F\x71\206\25", IF_WILLAMETTE|IF_SSE2|IF_SB|IF_AR1}, - ITEMPLATE_END -}; - -static struct itemplate instrux_PSRAD[] = { - {I_PSRAD, 2, {MMXREG,MEMORY,0}, "\301\2\x0F\xE2\110", IF_PENT|IF_MMX|IF_SM}, - {I_PSRAD, 2, {MMXREG,MMXREG,0}, "\2\x0F\xE2\110", IF_PENT|IF_MMX}, - {I_PSRAD, 2, {MMXREG,IMMEDIATE,0}, "\2\x0F\x72\204\25", IF_PENT|IF_MMX}, - {I_PSRAD, 2, {XMMREG,MEMORY,0}, "\301\3\x66\x0F\xE2\110", IF_WILLAMETTE|IF_SSE2|IF_SM}, - {I_PSRAD, 2, {XMMREG,XMMREG,0}, "\3\x66\x0F\xE2\110", IF_WILLAMETTE|IF_SSE2}, - {I_PSRAD, 2, {XMMREG,IMMEDIATE,0}, "\3\x66\x0F\x72\204\25", IF_WILLAMETTE|IF_SSE2|IF_SB|IF_AR1}, - ITEMPLATE_END -}; - -static struct itemplate instrux_PSRAW[] = { - {I_PSRAW, 2, {MMXREG,MEMORY,0}, "\301\2\x0F\xE1\110", IF_PENT|IF_MMX|IF_SM}, - {I_PSRAW, 2, {MMXREG,MMXREG,0}, "\2\x0F\xE1\110", IF_PENT|IF_MMX}, - {I_PSRAW, 2, {MMXREG,IMMEDIATE,0}, "\2\x0F\x71\204\25", IF_PENT|IF_MMX}, - {I_PSRAW, 2, {XMMREG,MEMORY,0}, "\301\3\x66\x0F\xE1\110", IF_WILLAMETTE|IF_SSE2|IF_SM}, - {I_PSRAW, 2, {XMMREG,XMMREG,0}, "\3\x66\x0F\xE1\110", IF_WILLAMETTE|IF_SSE2}, - {I_PSRAW, 2, {XMMREG,IMMEDIATE,0}, "\3\x66\x0F\x71\204\25", IF_WILLAMETTE|IF_SSE2|IF_SB|IF_AR1}, - ITEMPLATE_END -}; - -static struct itemplate instrux_PSRLD[] = { - {I_PSRLD, 2, {MMXREG,MEMORY,0}, "\301\2\x0F\xD2\110", IF_PENT|IF_MMX|IF_SM}, - {I_PSRLD, 2, {MMXREG,MMXREG,0}, "\2\x0F\xD2\110", IF_PENT|IF_MMX}, - {I_PSRLD, 2, {MMXREG,IMMEDIATE,0}, "\2\x0F\x72\202\25", IF_PENT|IF_MMX}, - {I_PSRLD, 2, {XMMREG,MEMORY,0}, "\301\3\x66\x0F\xD2\110", IF_WILLAMETTE|IF_SSE2|IF_SM}, - {I_PSRLD, 2, {XMMREG,XMMREG,0}, "\3\x66\x0F\xD2\110", IF_WILLAMETTE|IF_SSE2}, - {I_PSRLD, 2, {XMMREG,IMMEDIATE,0}, "\3\x66\x0F\x72\202\25", IF_WILLAMETTE|IF_SSE2|IF_SB|IF_AR1}, - ITEMPLATE_END -}; - -static struct itemplate instrux_PSRLDQ[] = { - {I_PSRLDQ, 2, {XMMREG,IMMEDIATE,0}, "\3\x66\x0F\x73\203\25", IF_WILLAMETTE|IF_SSE2|IF_SB|IF_AR1}, - ITEMPLATE_END -}; - -static struct itemplate instrux_PSRLQ[] = { - {I_PSRLQ, 2, {MMXREG,MEMORY,0}, "\301\2\x0F\xD3\110", IF_PENT|IF_MMX|IF_SM}, - {I_PSRLQ, 2, {MMXREG,MMXREG,0}, "\2\x0F\xD3\110", IF_PENT|IF_MMX}, - {I_PSRLQ, 2, {MMXREG,IMMEDIATE,0}, "\2\x0F\x73\202\25", IF_PENT|IF_MMX}, - {I_PSRLQ, 2, {XMMREG,MEMORY,0}, "\301\3\x66\x0F\xD3\110", IF_WILLAMETTE|IF_SSE2|IF_SM}, - {I_PSRLQ, 2, {XMMREG,XMMREG,0}, "\3\x66\x0F\xD3\110", IF_WILLAMETTE|IF_SSE2}, - {I_PSRLQ, 2, {XMMREG,IMMEDIATE,0}, "\3\x66\x0F\x73\202\25", IF_WILLAMETTE|IF_SSE2|IF_SB|IF_AR1}, - ITEMPLATE_END -}; - -static struct itemplate instrux_PSRLW[] = { - {I_PSRLW, 2, {MMXREG,MEMORY,0}, "\301\2\x0F\xD1\110", IF_PENT|IF_MMX|IF_SM}, - {I_PSRLW, 2, {MMXREG,MMXREG,0}, "\2\x0F\xD1\110", IF_PENT|IF_MMX}, - {I_PSRLW, 2, {MMXREG,IMMEDIATE,0}, "\2\x0F\x71\202\25", IF_PENT|IF_MMX}, - {I_PSRLW, 2, {XMMREG,MEMORY,0}, "\301\3\x66\x0F\xD1\110", IF_WILLAMETTE|IF_SSE2|IF_SM}, - {I_PSRLW, 2, {XMMREG,XMMREG,0}, "\3\x66\x0F\xD1\110", IF_WILLAMETTE|IF_SSE2}, - {I_PSRLW, 2, {XMMREG,IMMEDIATE,0}, "\3\x66\x0F\x71\202\25", IF_WILLAMETTE|IF_SSE2|IF_SB|IF_AR1}, - ITEMPLATE_END -}; - -static struct itemplate instrux_PSUBB[] = { - {I_PSUBB, 2, {MMXREG,MEMORY,0}, "\301\2\x0F\xF8\110", IF_PENT|IF_MMX|IF_SM}, - {I_PSUBB, 2, {MMXREG,MMXREG,0}, "\2\x0F\xF8\110", IF_PENT|IF_MMX}, - {I_PSUBB, 2, {XMMREG,MEMORY,0}, "\301\3\x66\x0F\xF8\110", IF_WILLAMETTE|IF_SSE2|IF_SM}, - {I_PSUBB, 2, {XMMREG,XMMREG,0}, "\3\x66\x0F\xF8\110", IF_WILLAMETTE|IF_SSE2}, - ITEMPLATE_END -}; - -static struct itemplate instrux_PSUBD[] = { - {I_PSUBD, 2, {MMXREG,MEMORY,0}, "\301\2\x0F\xFA\110", IF_PENT|IF_MMX|IF_SM}, - {I_PSUBD, 2, {MMXREG,MMXREG,0}, "\2\x0F\xFA\110", IF_PENT|IF_MMX}, - {I_PSUBD, 2, {XMMREG,MEMORY,0}, "\301\3\x66\x0F\xFA\110", IF_WILLAMETTE|IF_SSE2|IF_SM}, - {I_PSUBD, 2, {XMMREG,XMMREG,0}, "\3\x66\x0F\xFA\110", IF_WILLAMETTE|IF_SSE2}, - ITEMPLATE_END -}; - -static struct itemplate instrux_PSUBQ[] = { - {I_PSUBQ, 2, {MMXREG,MMXREG,0}, "\2\x0F\xFB\110", IF_WILLAMETTE|IF_SSE2}, - {I_PSUBQ, 2, {MMXREG,MEMORY,0}, "\301\2\x0F\xFB\110", IF_WILLAMETTE|IF_SSE2|IF_SM}, - {I_PSUBQ, 2, {XMMREG,XMMREG,0}, "\3\x66\x0F\xFB\110", IF_WILLAMETTE|IF_SSE2}, - {I_PSUBQ, 2, {XMMREG,MEMORY,0}, "\301\3\x66\x0F\xFB\110", IF_WILLAMETTE|IF_SSE2|IF_SM}, - ITEMPLATE_END -}; - -static struct itemplate instrux_PSUBSB[] = { - {I_PSUBSB, 2, {MMXREG,MEMORY,0}, "\301\2\x0F\xE8\110", IF_PENT|IF_MMX|IF_SM}, - {I_PSUBSB, 2, {MMXREG,MMXREG,0}, "\2\x0F\xE8\110", IF_PENT|IF_MMX}, - {I_PSUBSB, 2, {XMMREG,MEMORY,0}, "\301\3\x66\x0F\xE8\110", IF_WILLAMETTE|IF_SSE2|IF_SM}, - {I_PSUBSB, 2, {XMMREG,XMMREG,0}, "\3\x66\x0F\xE8\110", IF_WILLAMETTE|IF_SSE2}, - ITEMPLATE_END -}; - -static struct itemplate instrux_PSUBSIW[] = { - {I_PSUBSIW, 2, {MMXREG,MEMORY,0}, "\301\2\x0F\x55\110", IF_PENT|IF_MMX|IF_SM|IF_CYRIX}, - {I_PSUBSIW, 2, {MMXREG,MMXREG,0}, "\2\x0F\x55\110", IF_PENT|IF_MMX|IF_CYRIX}, - ITEMPLATE_END -}; - -static struct itemplate instrux_PSUBSW[] = { - {I_PSUBSW, 2, {MMXREG,MEMORY,0}, "\301\2\x0F\xE9\110", IF_PENT|IF_MMX|IF_SM}, - {I_PSUBSW, 2, {MMXREG,MMXREG,0}, "\2\x0F\xE9\110", IF_PENT|IF_MMX}, - {I_PSUBSW, 2, {XMMREG,MEMORY,0}, "\301\3\x66\x0F\xE9\110", IF_WILLAMETTE|IF_SSE2|IF_SM}, - {I_PSUBSW, 2, {XMMREG,XMMREG,0}, "\3\x66\x0F\xE9\110", IF_WILLAMETTE|IF_SSE2}, - ITEMPLATE_END -}; - -static struct itemplate instrux_PSUBUSB[] = { - {I_PSUBUSB, 2, {MMXREG,MEMORY,0}, "\301\2\x0F\xD8\110", IF_PENT|IF_MMX|IF_SM}, - {I_PSUBUSB, 2, {MMXREG,MMXREG,0}, "\2\x0F\xD8\110", IF_PENT|IF_MMX}, - {I_PSUBUSB, 2, {XMMREG,MEMORY,0}, "\301\3\x66\x0F\xD8\110", IF_WILLAMETTE|IF_SSE2|IF_SM}, - {I_PSUBUSB, 2, {XMMREG,XMMREG,0}, "\3\x66\x0F\xD8\110", IF_WILLAMETTE|IF_SSE2}, - ITEMPLATE_END -}; - -static struct itemplate instrux_PSUBUSW[] = { - {I_PSUBUSW, 2, {MMXREG,MEMORY,0}, "\301\2\x0F\xD9\110", IF_PENT|IF_MMX|IF_SM}, - {I_PSUBUSW, 2, {MMXREG,MMXREG,0}, "\2\x0F\xD9\110", IF_PENT|IF_MMX}, - {I_PSUBUSW, 2, {XMMREG,MEMORY,0}, "\301\3\x66\x0F\xD9\110", IF_WILLAMETTE|IF_SSE2|IF_SM}, - {I_PSUBUSW, 2, {XMMREG,XMMREG,0}, "\3\x66\x0F\xD9\110", IF_WILLAMETTE|IF_SSE2}, - ITEMPLATE_END -}; - -static struct itemplate instrux_PSUBW[] = { - {I_PSUBW, 2, {MMXREG,MEMORY,0}, "\301\2\x0F\xF9\110", IF_PENT|IF_MMX|IF_SM}, - {I_PSUBW, 2, {MMXREG,MMXREG,0}, "\2\x0F\xF9\110", IF_PENT|IF_MMX}, - {I_PSUBW, 2, {XMMREG,MEMORY,0}, "\301\3\x66\x0F\xF9\110", IF_WILLAMETTE|IF_SSE2|IF_SM}, - {I_PSUBW, 2, {XMMREG,XMMREG,0}, "\3\x66\x0F\xF9\110", IF_WILLAMETTE|IF_SSE2}, - ITEMPLATE_END -}; - -static struct itemplate instrux_PSWAPD[] = { - {I_PSWAPD, 2, {MMXREG,MEMORY,0}, "\301\2\x0F\x0F\110\01\xBB", IF_PENT|IF_3DNOW|IF_SM}, - {I_PSWAPD, 2, {MMXREG,MMXREG,0}, "\2\x0F\x0F\110\01\xBB", IF_PENT|IF_3DNOW}, - ITEMPLATE_END -}; - -static struct itemplate instrux_PUNPCKHBW[] = { - {I_PUNPCKHBW, 2, {MMXREG,MEMORY,0}, "\301\2\x0F\x68\110", IF_PENT|IF_MMX|IF_SM}, - {I_PUNPCKHBW, 2, {MMXREG,MMXREG,0}, "\2\x0F\x68\110", IF_PENT|IF_MMX}, - {I_PUNPCKHBW, 2, {XMMREG,MEMORY,0}, "\301\3\x66\x0F\x68\110", IF_WILLAMETTE|IF_SSE2|IF_SM}, - {I_PUNPCKHBW, 2, {XMMREG,XMMREG,0}, "\3\x66\x0F\x68\110", IF_WILLAMETTE|IF_SSE2}, - ITEMPLATE_END -}; - -static struct itemplate instrux_PUNPCKHDQ[] = { - {I_PUNPCKHDQ, 2, {MMXREG,MEMORY,0}, "\301\2\x0F\x6A\110", IF_PENT|IF_MMX|IF_SM}, - {I_PUNPCKHDQ, 2, {MMXREG,MMXREG,0}, "\2\x0F\x6A\110", IF_PENT|IF_MMX}, - {I_PUNPCKHDQ, 2, {XMMREG,MEMORY,0}, "\301\3\x66\x0F\x6A\110", IF_WILLAMETTE|IF_SSE2|IF_SM}, - {I_PUNPCKHDQ, 2, {XMMREG,XMMREG,0}, "\3\x66\x0F\x6A\110", IF_WILLAMETTE|IF_SSE2}, - ITEMPLATE_END -}; - -static struct itemplate instrux_PUNPCKHQDQ[] = { - {I_PUNPCKHQDQ, 2, {XMMREG,XMMREG,0}, "\3\x66\x0F\x6D\110", IF_WILLAMETTE|IF_SSE2}, - {I_PUNPCKHQDQ, 2, {XMMREG,MEMORY,0}, "\301\3\x66\x0F\x6D\110", IF_WILLAMETTE|IF_SSE2|IF_SM}, - ITEMPLATE_END -}; - -static struct itemplate instrux_PUNPCKHWD[] = { - {I_PUNPCKHWD, 2, {MMXREG,MEMORY,0}, "\301\2\x0F\x69\110", IF_PENT|IF_MMX|IF_SM}, - {I_PUNPCKHWD, 2, {MMXREG,MMXREG,0}, "\2\x0F\x69\110", IF_PENT|IF_MMX}, - {I_PUNPCKHWD, 2, {XMMREG,MEMORY,0}, "\301\3\x66\x0F\x69\110", IF_WILLAMETTE|IF_SSE2|IF_SM}, - {I_PUNPCKHWD, 2, {XMMREG,XMMREG,0}, "\3\x66\x0F\x69\110", IF_WILLAMETTE|IF_SSE2}, - ITEMPLATE_END -}; - -static struct itemplate instrux_PUNPCKLBW[] = { - {I_PUNPCKLBW, 2, {MMXREG,MEMORY,0}, "\301\2\x0F\x60\110", IF_PENT|IF_MMX|IF_SM}, - {I_PUNPCKLBW, 2, {MMXREG,MMXREG,0}, "\2\x0F\x60\110", IF_PENT|IF_MMX}, - {I_PUNPCKLBW, 2, {XMMREG,MEMORY,0}, "\301\3\x66\x0F\x60\110", IF_WILLAMETTE|IF_SSE2|IF_SM}, - {I_PUNPCKLBW, 2, {XMMREG,XMMREG,0}, "\3\x66\x0F\x60\110", IF_WILLAMETTE|IF_SSE2}, - ITEMPLATE_END -}; - -static struct itemplate instrux_PUNPCKLDQ[] = { - {I_PUNPCKLDQ, 2, {MMXREG,MEMORY,0}, "\301\2\x0F\x62\110", IF_PENT|IF_MMX|IF_SM}, - {I_PUNPCKLDQ, 2, {MMXREG,MMXREG,0}, "\2\x0F\x62\110", IF_PENT|IF_MMX}, - {I_PUNPCKLDQ, 2, {XMMREG,MEMORY,0}, "\301\3\x66\x0F\x62\110", IF_WILLAMETTE|IF_SSE2|IF_SM}, - {I_PUNPCKLDQ, 2, {XMMREG,XMMREG,0}, "\3\x66\x0F\x62\110", IF_WILLAMETTE|IF_SSE2}, - ITEMPLATE_END -}; - -static struct itemplate instrux_PUNPCKLQDQ[] = { - {I_PUNPCKLQDQ, 2, {XMMREG,XMMREG,0}, "\3\x66\x0F\x6C\110", IF_WILLAMETTE|IF_SSE2}, - {I_PUNPCKLQDQ, 2, {XMMREG,MEMORY,0}, "\301\3\x66\x0F\x6C\110", IF_WILLAMETTE|IF_SSE2|IF_SM}, - ITEMPLATE_END -}; - -static struct itemplate instrux_PUNPCKLWD[] = { - {I_PUNPCKLWD, 2, {MMXREG,MEMORY,0}, "\301\2\x0F\x61\110", IF_PENT|IF_MMX|IF_SM}, - {I_PUNPCKLWD, 2, {MMXREG,MMXREG,0}, "\2\x0F\x61\110", IF_PENT|IF_MMX}, - {I_PUNPCKLWD, 2, {XMMREG,MEMORY,0}, "\301\3\x66\x0F\x61\110", IF_WILLAMETTE|IF_SSE2|IF_SM}, - {I_PUNPCKLWD, 2, {XMMREG,XMMREG,0}, "\3\x66\x0F\x61\110", IF_WILLAMETTE|IF_SSE2}, - ITEMPLATE_END -}; - -static struct itemplate instrux_PUSH[] = { - {I_PUSH, 1, {REG16,0,0}, "\320\10\x50", IF_8086}, - {I_PUSH, 1, {REG32,0,0}, "\321\10\x50", IF_386}, - {I_PUSH, 1, {REGMEM|BITS16,0,0}, "\320\300\1\xFF\206", IF_8086}, - {I_PUSH, 1, {REGMEM|BITS32,0,0}, "\321\300\1\xFF\206", IF_386}, - {I_PUSH, 1, {REG_CS,0,0}, "\6", IF_8086}, - {I_PUSH, 1, {REG_DESS,0,0}, "\6", IF_8086}, - {I_PUSH, 1, {REG_FSGS,0,0}, "\1\x0F\7", IF_386}, - {I_PUSH, 1, {IMMEDIATE|BITS8,0,0}, "\1\x6A\14", IF_186}, - {I_PUSH, 1, {SBYTE,0,0}, "\1\x6A\14", IF_186}, - {I_PUSH, 1, {IMMEDIATE|BITS16,0,0}, "\320\133\1\x68\130", IF_186}, - {I_PUSH, 1, {IMMEDIATE|BITS32,0,0}, "\321\143\1\x68\140", IF_386}, - {I_PUSH, 1, {IMMEDIATE,0,0}, "\1\x68\34", IF_186}, - ITEMPLATE_END -}; - -static struct itemplate instrux_PUSHA[] = { - {I_PUSHA, 0, {0,0,0}, "\322\1\x60", IF_186}, - ITEMPLATE_END -}; - -static struct itemplate instrux_PUSHAD[] = { - {I_PUSHAD, 0, {0,0,0}, "\321\1\x60", IF_386}, - ITEMPLATE_END -}; - -static struct itemplate instrux_PUSHAW[] = { - {I_PUSHAW, 0, {0,0,0}, "\320\1\x60", IF_186}, - ITEMPLATE_END -}; - -static struct itemplate instrux_PUSHF[] = { - {I_PUSHF, 0, {0,0,0}, "\322\1\x9C", IF_8086}, - ITEMPLATE_END -}; - -static struct itemplate instrux_PUSHFD[] = { - {I_PUSHFD, 0, {0,0,0}, "\321\1\x9C", IF_386}, - ITEMPLATE_END -}; - -static struct itemplate instrux_PUSHFW[] = { - {I_PUSHFW, 0, {0,0,0}, "\320\1\x9C", IF_8086}, - ITEMPLATE_END -}; - -static struct itemplate instrux_PXOR[] = { - {I_PXOR, 2, {MMXREG,MEMORY,0}, "\301\2\x0F\xEF\110", IF_PENT|IF_MMX|IF_SM}, - {I_PXOR, 2, {MMXREG,MMXREG,0}, "\2\x0F\xEF\110", IF_PENT|IF_MMX}, - {I_PXOR, 2, {XMMREG,MEMORY,0}, "\301\3\x66\x0F\xEF\110", IF_WILLAMETTE|IF_SSE2|IF_SM}, - {I_PXOR, 2, {XMMREG,XMMREG,0}, "\3\x66\x0F\xEF\110", IF_WILLAMETTE|IF_SSE2}, - ITEMPLATE_END -}; - -static struct itemplate instrux_RCL[] = { - {I_RCL, 2, {REGMEM|BITS8,UNITY,0}, "\300\1\xD0\202", IF_8086}, - {I_RCL, 2, {REGMEM|BITS8,REG_CL,0}, "\300\1\xD2\202", IF_8086}, - {I_RCL, 2, {REGMEM|BITS8,IMMEDIATE,0}, "\300\1\xC0\202\25", IF_186|IF_SB}, - {I_RCL, 2, {REGMEM|BITS16,UNITY,0}, "\320\300\1\xD1\202", IF_8086}, - {I_RCL, 2, {REGMEM|BITS16,REG_CL,0}, "\320\300\1\xD3\202", IF_8086}, - {I_RCL, 2, {REGMEM|BITS16,IMMEDIATE,0}, "\320\300\1\xC1\202\25", IF_186|IF_SB}, - {I_RCL, 2, {REGMEM|BITS32,UNITY,0}, "\321\300\1\xD1\202", IF_386}, - {I_RCL, 2, {REGMEM|BITS32,REG_CL,0}, "\321\300\1\xD3\202", IF_386}, - {I_RCL, 2, {REGMEM|BITS32,IMMEDIATE,0}, "\321\300\1\xC1\202\25", IF_386|IF_SB}, - ITEMPLATE_END -}; - -static struct itemplate instrux_RCPPS[] = { - {I_RCPPS, 2, {XMMREG,MEMORY,0}, "\301\331\2\x0F\x53\110", IF_KATMAI|IF_SSE}, - {I_RCPPS, 2, {XMMREG,XMMREG,0}, "\331\2\x0F\x53\110", IF_KATMAI|IF_SSE}, - ITEMPLATE_END -}; - -static struct itemplate instrux_RCPSS[] = { - {I_RCPSS, 2, {XMMREG,MEMORY,0}, "\301\333\2\x0F\x53\110", IF_KATMAI|IF_SSE}, - {I_RCPSS, 2, {XMMREG,XMMREG,0}, "\333\2\x0F\x53\110", IF_KATMAI|IF_SSE}, - ITEMPLATE_END -}; - -static struct itemplate instrux_RCR[] = { - {I_RCR, 2, {REGMEM|BITS8,UNITY,0}, "\300\1\xD0\203", IF_8086}, - {I_RCR, 2, {REGMEM|BITS8,REG_CL,0}, "\300\1\xD2\203", IF_8086}, - {I_RCR, 2, {REGMEM|BITS8,IMMEDIATE,0}, "\300\1\xC0\203\25", IF_186|IF_SB}, - {I_RCR, 2, {REGMEM|BITS16,UNITY,0}, "\320\300\1\xD1\203", IF_8086}, - {I_RCR, 2, {REGMEM|BITS16,REG_CL,0}, "\320\300\1\xD3\203", IF_8086}, - {I_RCR, 2, {REGMEM|BITS16,IMMEDIATE,0}, "\320\300\1\xC1\203\25", IF_186|IF_SB}, - {I_RCR, 2, {REGMEM|BITS32,UNITY,0}, "\321\300\1\xD1\203", IF_386}, - {I_RCR, 2, {REGMEM|BITS32,REG_CL,0}, "\321\300\1\xD3\203", IF_386}, - {I_RCR, 2, {REGMEM|BITS32,IMMEDIATE,0}, "\321\300\1\xC1\203\25", IF_386|IF_SB}, - ITEMPLATE_END -}; - -static struct itemplate instrux_RDMSR[] = { - {I_RDMSR, 0, {0,0,0}, "\2\x0F\x32", IF_PENT|IF_PRIV}, - ITEMPLATE_END -}; - -static struct itemplate instrux_RDPMC[] = { - {I_RDPMC, 0, {0,0,0}, "\2\x0F\x33", IF_P6}, - ITEMPLATE_END -}; - -static struct itemplate instrux_RDSHR[] = { - {I_RDSHR, 1, {REGMEM|BITS32,0,0}, "\321\300\2\x0F\x36\200", IF_P6|IF_CYRIX|IF_SMM}, - ITEMPLATE_END -}; - -static struct itemplate instrux_RDTSC[] = { - {I_RDTSC, 0, {0,0,0}, "\2\x0F\x31", IF_PENT}, - ITEMPLATE_END -}; - -static struct itemplate instrux_RESB[] = { - {I_RESB, 1, {IMMEDIATE,0,0}, "\340", IF_8086}, - ITEMPLATE_END -}; - -static struct itemplate instrux_RESD[] = { - ITEMPLATE_END -}; - -static struct itemplate instrux_RESQ[] = { - ITEMPLATE_END -}; - -static struct itemplate instrux_REST[] = { - ITEMPLATE_END -}; - -static struct itemplate instrux_RESW[] = { - ITEMPLATE_END -}; - -static struct itemplate instrux_RET[] = { - {I_RET, 0, {0,0,0}, "\1\xC3", IF_8086}, - {I_RET, 1, {IMMEDIATE,0,0}, "\1\xC2\30", IF_8086|IF_SW}, - ITEMPLATE_END -}; - -static struct itemplate instrux_RETF[] = { - {I_RETF, 0, {0,0,0}, "\1\xCB", IF_8086}, - {I_RETF, 1, {IMMEDIATE,0,0}, "\1\xCA\30", IF_8086|IF_SW}, - ITEMPLATE_END -}; - -static struct itemplate instrux_RETN[] = { - {I_RETN, 0, {0,0,0}, "\1\xC3", IF_8086}, - {I_RETN, 1, {IMMEDIATE,0,0}, "\1\xC2\30", IF_8086|IF_SW}, - ITEMPLATE_END -}; - -static struct itemplate instrux_ROL[] = { - {I_ROL, 2, {REGMEM|BITS8,UNITY,0}, "\300\1\xD0\200", IF_8086}, - {I_ROL, 2, {REGMEM|BITS8,REG_CL,0}, "\300\1\xD2\200", IF_8086}, - {I_ROL, 2, {REGMEM|BITS8,IMMEDIATE,0}, "\300\1\xC0\200\25", IF_186|IF_SB}, - {I_ROL, 2, {REGMEM|BITS16,UNITY,0}, "\320\300\1\xD1\200", IF_8086}, - {I_ROL, 2, {REGMEM|BITS16,REG_CL,0}, "\320\300\1\xD3\200", IF_8086}, - {I_ROL, 2, {REGMEM|BITS16,IMMEDIATE,0}, "\320\300\1\xC1\200\25", IF_186|IF_SB}, - {I_ROL, 2, {REGMEM|BITS32,UNITY,0}, "\321\300\1\xD1\200", IF_386}, - {I_ROL, 2, {REGMEM|BITS32,REG_CL,0}, "\321\300\1\xD3\200", IF_386}, - {I_ROL, 2, {REGMEM|BITS32,IMMEDIATE,0}, "\321\300\1\xC1\200\25", IF_386|IF_SB}, - ITEMPLATE_END -}; - -static struct itemplate instrux_ROR[] = { - {I_ROR, 2, {REGMEM|BITS8,UNITY,0}, "\300\1\xD0\201", IF_8086}, - {I_ROR, 2, {REGMEM|BITS8,REG_CL,0}, "\300\1\xD2\201", IF_8086}, - {I_ROR, 2, {REGMEM|BITS8,IMMEDIATE,0}, "\300\1\xC0\201\25", IF_186|IF_SB}, - {I_ROR, 2, {REGMEM|BITS16,UNITY,0}, "\320\300\1\xD1\201", IF_8086}, - {I_ROR, 2, {REGMEM|BITS16,REG_CL,0}, "\320\300\1\xD3\201", IF_8086}, - {I_ROR, 2, {REGMEM|BITS16,IMMEDIATE,0}, "\320\300\1\xC1\201\25", IF_186|IF_SB}, - {I_ROR, 2, {REGMEM|BITS32,UNITY,0}, "\321\300\1\xD1\201", IF_386}, - {I_ROR, 2, {REGMEM|BITS32,REG_CL,0}, "\321\300\1\xD3\201", IF_386}, - {I_ROR, 2, {REGMEM|BITS32,IMMEDIATE,0}, "\321\300\1\xC1\201\25", IF_386|IF_SB}, - ITEMPLATE_END -}; - -static struct itemplate instrux_RSDC[] = { - {I_RSDC, 2, {REG_SREG,MEMORY|BITS80,0}, "\301\2\x0F\x79\110", IF_486|IF_CYRIX|IF_SMM}, - ITEMPLATE_END -}; - -static struct itemplate instrux_RSLDT[] = { - {I_RSLDT, 1, {MEMORY|BITS80,0,0}, "\300\2\x0F\x7B\200", IF_486|IF_CYRIX|IF_SMM}, - ITEMPLATE_END -}; - -static struct itemplate instrux_RSM[] = { - {I_RSM, 0, {0,0,0}, "\2\x0F\xAA", IF_PENT|IF_SMM}, - ITEMPLATE_END -}; - -static struct itemplate instrux_RSQRTPS[] = { - {I_RSQRTPS, 2, {XMMREG,MEMORY,0}, "\301\331\2\x0F\x52\110", IF_KATMAI|IF_SSE}, - {I_RSQRTPS, 2, {XMMREG,XMMREG,0}, "\331\2\x0F\x52\110", IF_KATMAI|IF_SSE}, - ITEMPLATE_END -}; - -static struct itemplate instrux_RSQRTSS[] = { - {I_RSQRTSS, 2, {XMMREG,MEMORY,0}, "\301\333\2\x0F\x52\110", IF_KATMAI|IF_SSE}, - {I_RSQRTSS, 2, {XMMREG,XMMREG,0}, "\333\2\x0F\x52\110", IF_KATMAI|IF_SSE}, - ITEMPLATE_END -}; - -static struct itemplate instrux_RSTS[] = { - {I_RSTS, 1, {MEMORY|BITS80,0,0}, "\300\2\x0F\x7D\200", IF_486|IF_CYRIX|IF_SMM}, - ITEMPLATE_END -}; - -static struct itemplate instrux_SAHF[] = { - {I_SAHF, 0, {0,0,0}, "\1\x9E", IF_8086}, - ITEMPLATE_END -}; - -static struct itemplate instrux_SAL[] = { - {I_SAL, 2, {REGMEM|BITS8,UNITY,0}, "\300\1\xD0\204", IF_8086}, - {I_SAL, 2, {REGMEM|BITS8,REG_CL,0}, "\300\1\xD2\204", IF_8086}, - {I_SAL, 2, {REGMEM|BITS8,IMMEDIATE,0}, "\300\1\xC0\204\25", IF_186|IF_SB}, - {I_SAL, 2, {REGMEM|BITS16,UNITY,0}, "\320\300\1\xD1\204", IF_8086}, - {I_SAL, 2, {REGMEM|BITS16,REG_CL,0}, "\320\300\1\xD3\204", IF_8086}, - {I_SAL, 2, {REGMEM|BITS16,IMMEDIATE,0}, "\320\300\1\xC1\204\25", IF_186|IF_SB}, - {I_SAL, 2, {REGMEM|BITS32,UNITY,0}, "\321\300\1\xD1\204", IF_386}, - {I_SAL, 2, {REGMEM|BITS32,REG_CL,0}, "\321\300\1\xD3\204", IF_386}, - {I_SAL, 2, {REGMEM|BITS32,IMMEDIATE,0}, "\321\300\1\xC1\204\25", IF_386|IF_SB}, - ITEMPLATE_END -}; - -static struct itemplate instrux_SALC[] = { - {I_SALC, 0, {0,0,0}, "\1\xD6", IF_8086|IF_UNDOC}, - ITEMPLATE_END -}; - -static struct itemplate instrux_SAR[] = { - {I_SAR, 2, {REGMEM|BITS8,UNITY,0}, "\300\1\xD0\207", IF_8086}, - {I_SAR, 2, {REGMEM|BITS8,REG_CL,0}, "\300\1\xD2\207", IF_8086}, - {I_SAR, 2, {REGMEM|BITS8,IMMEDIATE,0}, "\300\1\xC0\207\25", IF_186|IF_SB}, - {I_SAR, 2, {REGMEM|BITS16,UNITY,0}, "\320\300\1\xD1\207", IF_8086}, - {I_SAR, 2, {REGMEM|BITS16,REG_CL,0}, "\320\300\1\xD3\207", IF_8086}, - {I_SAR, 2, {REGMEM|BITS16,IMMEDIATE,0}, "\320\300\1\xC1\207\25", IF_186|IF_SB}, - {I_SAR, 2, {REGMEM|BITS32,UNITY,0}, "\321\300\1\xD1\207", IF_386}, - {I_SAR, 2, {REGMEM|BITS32,REG_CL,0}, "\321\300\1\xD3\207", IF_386}, - {I_SAR, 2, {REGMEM|BITS32,IMMEDIATE,0}, "\321\300\1\xC1\207\25", IF_386|IF_SB}, - ITEMPLATE_END -}; - -static struct itemplate instrux_SBB[] = { - {I_SBB, 2, {MEMORY,REG8,0}, "\300\1\x18\101", IF_8086|IF_SM}, - {I_SBB, 2, {REG8,REG8,0}, "\1\x18\101", IF_8086}, - {I_SBB, 2, {MEMORY,REG16,0}, "\320\300\1\x19\101", IF_8086|IF_SM}, - {I_SBB, 2, {REG16,REG16,0}, "\320\1\x19\101", IF_8086}, - {I_SBB, 2, {MEMORY,REG32,0}, "\321\300\1\x19\101", IF_386|IF_SM}, - {I_SBB, 2, {REG32,REG32,0}, "\321\1\x19\101", IF_386}, - {I_SBB, 2, {REG8,MEMORY,0}, "\301\1\x1A\110", IF_8086|IF_SM}, - {I_SBB, 2, {REG8,REG8,0}, "\1\x1A\110", IF_8086}, - {I_SBB, 2, {REG16,MEMORY,0}, "\320\301\1\x1B\110", IF_8086|IF_SM}, - {I_SBB, 2, {REG16,REG16,0}, "\320\1\x1B\110", IF_8086}, - {I_SBB, 2, {REG32,MEMORY,0}, "\321\301\1\x1B\110", IF_386|IF_SM}, - {I_SBB, 2, {REG32,REG32,0}, "\321\1\x1B\110", IF_386}, - {I_SBB, 2, {REGMEM|BITS16,IMMEDIATE|BITS8,0}, "\320\300\1\x83\203\15", IF_8086}, - {I_SBB, 2, {REGMEM|BITS32,IMMEDIATE|BITS8,0}, "\321\300\1\x83\203\15", IF_386}, - {I_SBB, 2, {REG_AL,IMMEDIATE,0}, "\1\x1C\21", IF_8086|IF_SM}, - {I_SBB, 2, {REG_AX,SBYTE,0}, "\320\1\x83\203\15", IF_8086|IF_SM}, - {I_SBB, 2, {REG_AX,IMMEDIATE,0}, "\320\1\x1D\31", IF_8086|IF_SM}, - {I_SBB, 2, {REG_EAX,SBYTE,0}, "\321\1\x83\203\15", IF_386|IF_SM}, - {I_SBB, 2, {REG_EAX,IMMEDIATE,0}, "\321\1\x1D\41", IF_386|IF_SM}, - {I_SBB, 2, {REGMEM|BITS8,IMMEDIATE,0}, "\300\1\x80\203\21", IF_8086|IF_SM}, - {I_SBB, 2, {REGMEM|BITS16,IMMEDIATE,0}, "\320\300\134\1\x81\203\131", IF_8086|IF_SM}, - {I_SBB, 2, {REGMEM|BITS32,IMMEDIATE,0}, "\321\300\144\1\x81\203\141", IF_386|IF_SM}, - {I_SBB, 2, {MEMORY,IMMEDIATE|BITS8,0}, "\300\1\x80\203\21", IF_8086|IF_SM}, - {I_SBB, 2, {MEMORY,IMMEDIATE|BITS16,0}, "\320\300\134\1\x81\203\131", IF_8086|IF_SM}, - {I_SBB, 2, {MEMORY,IMMEDIATE|BITS32,0}, "\321\300\144\1\x81\203\141", IF_386|IF_SM}, - ITEMPLATE_END -}; - -static struct itemplate instrux_SCASB[] = { - {I_SCASB, 0, {0,0,0}, "\332\1\xAE", IF_8086}, - ITEMPLATE_END -}; - -static struct itemplate instrux_SCASD[] = { - {I_SCASD, 0, {0,0,0}, "\332\321\1\xAF", IF_386}, - ITEMPLATE_END -}; - -static struct itemplate instrux_SCASW[] = { - {I_SCASW, 0, {0,0,0}, "\332\320\1\xAF", IF_8086}, - ITEMPLATE_END -}; - -static struct itemplate instrux_SFENCE[] = { - {I_SFENCE, 0, {0,0,0}, "\3\x0F\xAE\xF8", IF_KATMAI}, - ITEMPLATE_END -}; - -static struct itemplate instrux_SGDT[] = { - {I_SGDT, 1, {MEMORY,0,0}, "\300\2\x0F\x01\200", IF_286}, - ITEMPLATE_END -}; - -static struct itemplate instrux_SHL[] = { - {I_SHL, 2, {REGMEM|BITS8,UNITY,0}, "\300\1\xD0\204", IF_8086}, - {I_SHL, 2, {REGMEM|BITS8,REG_CL,0}, "\300\1\xD2\204", IF_8086}, - {I_SHL, 2, {REGMEM|BITS8,IMMEDIATE,0}, "\300\1\xC0\204\25", IF_186|IF_SB}, - {I_SHL, 2, {REGMEM|BITS16,UNITY,0}, "\320\300\1\xD1\204", IF_8086}, - {I_SHL, 2, {REGMEM|BITS16,REG_CL,0}, "\320\300\1\xD3\204", IF_8086}, - {I_SHL, 2, {REGMEM|BITS16,IMMEDIATE,0}, "\320\300\1\xC1\204\25", IF_186|IF_SB}, - {I_SHL, 2, {REGMEM|BITS32,UNITY,0}, "\321\300\1\xD1\204", IF_386}, - {I_SHL, 2, {REGMEM|BITS32,REG_CL,0}, "\321\300\1\xD3\204", IF_386}, - {I_SHL, 2, {REGMEM|BITS32,IMMEDIATE,0}, "\321\300\1\xC1\204\25", IF_386|IF_SB}, - ITEMPLATE_END -}; - -static struct itemplate instrux_SHLD[] = { - {I_SHLD, 3, {MEMORY,REG16,IMMEDIATE}, "\300\320\2\x0F\xA4\101\26", IF_386|IF_SM2|IF_SB|IF_AR2}, - {I_SHLD, 3, {REG16,REG16,IMMEDIATE}, "\320\2\x0F\xA4\101\26", IF_386|IF_SM2|IF_SB|IF_AR2}, - {I_SHLD, 3, {MEMORY,REG32,IMMEDIATE}, "\300\321\2\x0F\xA4\101\26", IF_386|IF_SM2|IF_SB|IF_AR2}, - {I_SHLD, 3, {REG32,REG32,IMMEDIATE}, "\321\2\x0F\xA4\101\26", IF_386|IF_SM2|IF_SB|IF_AR2}, - {I_SHLD, 3, {MEMORY,REG16,REG_CL}, "\300\320\2\x0F\xA5\101", IF_386|IF_SM}, - {I_SHLD, 3, {REG16,REG16,REG_CL}, "\320\2\x0F\xA5\101", IF_386}, - {I_SHLD, 3, {MEMORY,REG32,REG_CL}, "\300\321\2\x0F\xA5\101", IF_386|IF_SM}, - {I_SHLD, 3, {REG32,REG32,REG_CL}, "\321\2\x0F\xA5\101", IF_386}, - ITEMPLATE_END -}; - -static struct itemplate instrux_SHR[] = { - {I_SHR, 2, {REGMEM|BITS8,UNITY,0}, "\300\1\xD0\205", IF_8086}, - {I_SHR, 2, {REGMEM|BITS8,REG_CL,0}, "\300\1\xD2\205", IF_8086}, - {I_SHR, 2, {REGMEM|BITS8,IMMEDIATE,0}, "\300\1\xC0\205\25", IF_186|IF_SB}, - {I_SHR, 2, {REGMEM|BITS16,UNITY,0}, "\320\300\1\xD1\205", IF_8086}, - {I_SHR, 2, {REGMEM|BITS16,REG_CL,0}, "\320\300\1\xD3\205", IF_8086}, - {I_SHR, 2, {REGMEM|BITS16,IMMEDIATE,0}, "\320\300\1\xC1\205\25", IF_186|IF_SB}, - {I_SHR, 2, {REGMEM|BITS32,UNITY,0}, "\321\300\1\xD1\205", IF_386}, - {I_SHR, 2, {REGMEM|BITS32,REG_CL,0}, "\321\300\1\xD3\205", IF_386}, - {I_SHR, 2, {REGMEM|BITS32,IMMEDIATE,0}, "\321\300\1\xC1\205\25", IF_386|IF_SB}, - ITEMPLATE_END -}; - -static struct itemplate instrux_SHRD[] = { - {I_SHRD, 3, {MEMORY,REG16,IMMEDIATE}, "\300\320\2\x0F\xAC\101\26", IF_386|IF_SM2|IF_SB|IF_AR2}, - {I_SHRD, 3, {REG16,REG16,IMMEDIATE}, "\320\2\x0F\xAC\101\26", IF_386|IF_SM2|IF_SB|IF_AR2}, - {I_SHRD, 3, {MEMORY,REG32,IMMEDIATE}, "\300\321\2\x0F\xAC\101\26", IF_386|IF_SM2|IF_SB|IF_AR2}, - {I_SHRD, 3, {REG32,REG32,IMMEDIATE}, "\321\2\x0F\xAC\101\26", IF_386|IF_SM2|IF_SB|IF_AR2}, - {I_SHRD, 3, {MEMORY,REG16,REG_CL}, "\300\320\2\x0F\xAD\101", IF_386|IF_SM}, - {I_SHRD, 3, {REG16,REG16,REG_CL}, "\320\2\x0F\xAD\101", IF_386}, - {I_SHRD, 3, {MEMORY,REG32,REG_CL}, "\300\321\2\x0F\xAD\101", IF_386|IF_SM}, - {I_SHRD, 3, {REG32,REG32,REG_CL}, "\321\2\x0F\xAD\101", IF_386}, - ITEMPLATE_END -}; - -static struct itemplate instrux_SHUFPD[] = { - {I_SHUFPD, 3, {XMMREG,XMMREG,IMMEDIATE}, "\3\x66\x0F\xC6\110\26", IF_WILLAMETTE|IF_SSE2|IF_SB|IF_AR2}, - {I_SHUFPD, 3, {XMMREG,MEMORY,IMMEDIATE}, "\301\3\x66\x0F\xC6\110\26", IF_WILLAMETTE|IF_SSE2|IF_SM|IF_SB|IF_AR2}, - ITEMPLATE_END -}; - -static struct itemplate instrux_SHUFPS[] = { - {I_SHUFPS, 3, {XMMREG,MEMORY,IMMEDIATE}, "\301\2\x0F\xC6\110\26", IF_KATMAI|IF_SSE|IF_SB|IF_AR2}, - {I_SHUFPS, 3, {XMMREG,XMMREG,IMMEDIATE}, "\2\x0F\xC6\110\26", IF_KATMAI|IF_SSE|IF_SB|IF_AR2}, - ITEMPLATE_END -}; - -static struct itemplate instrux_SIDT[] = { - {I_SIDT, 1, {MEMORY,0,0}, "\300\2\x0F\x01\201", IF_286}, - ITEMPLATE_END -}; - -static struct itemplate instrux_SLDT[] = { - {I_SLDT, 1, {MEMORY,0,0}, "\300\1\x0F\17\200", IF_286}, - {I_SLDT, 1, {MEMORY|BITS16,0,0}, "\300\1\x0F\17\200", IF_286}, - {I_SLDT, 1, {REG16,0,0}, "\320\1\x0F\17\200", IF_286}, - {I_SLDT, 1, {REG32,0,0}, "\321\1\x0F\17\200", IF_386}, - ITEMPLATE_END -}; - -static struct itemplate instrux_SMI[] = { - {I_SMI, 0, {0,0,0}, "\1\xF1", IF_386|IF_UNDOC}, - ITEMPLATE_END -}; - -static struct itemplate instrux_SMINT[] = { - {I_SMINT, 0, {0,0,0}, "\2\x0F\x38", IF_P6|IF_CYRIX}, - ITEMPLATE_END -}; - -static struct itemplate instrux_SMINTOLD[] = { - {I_SMINTOLD, 0, {0,0,0}, "\2\x0F\x7E", IF_486|IF_CYRIX}, - ITEMPLATE_END -}; - -static struct itemplate instrux_SMSW[] = { - {I_SMSW, 1, {MEMORY,0,0}, "\300\2\x0F\x01\204", IF_286}, - {I_SMSW, 1, {MEMORY|BITS16,0,0}, "\300\2\x0F\x01\204", IF_286}, - {I_SMSW, 1, {REG16,0,0}, "\320\2\x0F\x01\204", IF_286}, - {I_SMSW, 1, {REG32,0,0}, "\321\2\x0F\x01\204", IF_386}, - ITEMPLATE_END -}; - -static struct itemplate instrux_SQRTPD[] = { - {I_SQRTPD, 2, {XMMREG,XMMREG,0}, "\3\x66\x0F\x51\110", IF_WILLAMETTE|IF_SSE2}, - {I_SQRTPD, 2, {XMMREG,MEMORY,0}, "\301\3\x66\x0F\x51\110", IF_WILLAMETTE|IF_SSE2|IF_SM}, - ITEMPLATE_END -}; - -static struct itemplate instrux_SQRTPS[] = { - {I_SQRTPS, 2, {XMMREG,MEMORY,0}, "\301\331\2\x0F\x51\110", IF_KATMAI|IF_SSE}, - {I_SQRTPS, 2, {XMMREG,XMMREG,0}, "\331\2\x0F\x51\110", IF_KATMAI|IF_SSE}, - ITEMPLATE_END -}; - -static struct itemplate instrux_SQRTSD[] = { - {I_SQRTSD, 2, {XMMREG,XMMREG,0}, "\3\xF2\x0F\x51\110", IF_WILLAMETTE|IF_SSE2}, - {I_SQRTSD, 2, {XMMREG,MEMORY,0}, "\301\3\xF2\x0F\x51\110", IF_WILLAMETTE|IF_SSE2}, - ITEMPLATE_END -}; - -static struct itemplate instrux_SQRTSS[] = { - {I_SQRTSS, 2, {XMMREG,MEMORY,0}, "\301\333\2\x0F\x51\110", IF_KATMAI|IF_SSE}, - {I_SQRTSS, 2, {XMMREG,XMMREG,0}, "\333\2\x0F\x51\110", IF_KATMAI|IF_SSE}, - ITEMPLATE_END -}; - -static struct itemplate instrux_STC[] = { - {I_STC, 0, {0,0,0}, "\1\xF9", IF_8086}, - ITEMPLATE_END -}; - -static struct itemplate instrux_STD[] = { - {I_STD, 0, {0,0,0}, "\1\xFD", IF_8086}, - ITEMPLATE_END -}; - -static struct itemplate instrux_STI[] = { - {I_STI, 0, {0,0,0}, "\1\xFB", IF_8086}, - ITEMPLATE_END -}; - -static struct itemplate instrux_STMXCSR[] = { - {I_STMXCSR, 1, {MEMORY,0,0}, "\300\2\x0F\xAE\203", IF_KATMAI|IF_SSE|IF_SD}, - ITEMPLATE_END -}; - -static struct itemplate instrux_STOSB[] = { - {I_STOSB, 0, {0,0,0}, "\1\xAA", IF_8086}, - ITEMPLATE_END -}; - -static struct itemplate instrux_STOSD[] = { - {I_STOSD, 0, {0,0,0}, "\321\1\xAB", IF_386}, - ITEMPLATE_END -}; - -static struct itemplate instrux_STOSW[] = { - {I_STOSW, 0, {0,0,0}, "\320\1\xAB", IF_8086}, - ITEMPLATE_END -}; - -static struct itemplate instrux_STR[] = { - {I_STR, 1, {MEMORY,0,0}, "\300\1\x0F\17\201", IF_286|IF_PROT}, - {I_STR, 1, {MEMORY|BITS16,0,0}, "\300\1\x0F\17\201", IF_286|IF_PROT}, - {I_STR, 1, {REG16,0,0}, "\320\1\x0F\17\201", IF_286|IF_PROT}, - {I_STR, 1, {REG32,0,0}, "\321\1\x0F\17\201", IF_386|IF_PROT}, - ITEMPLATE_END -}; - -static struct itemplate instrux_SUB[] = { - {I_SUB, 2, {MEMORY,REG8,0}, "\300\1\x28\101", IF_8086|IF_SM}, - {I_SUB, 2, {REG8,REG8,0}, "\1\x28\101", IF_8086}, - {I_SUB, 2, {MEMORY,REG16,0}, "\320\300\1\x29\101", IF_8086|IF_SM}, - {I_SUB, 2, {REG16,REG16,0}, "\320\1\x29\101", IF_8086}, - {I_SUB, 2, {MEMORY,REG32,0}, "\321\300\1\x29\101", IF_386|IF_SM}, - {I_SUB, 2, {REG32,REG32,0}, "\321\1\x29\101", IF_386}, - {I_SUB, 2, {REG8,MEMORY,0}, "\301\1\x2A\110", IF_8086|IF_SM}, - {I_SUB, 2, {REG8,REG8,0}, "\1\x2A\110", IF_8086}, - {I_SUB, 2, {REG16,MEMORY,0}, "\320\301\1\x2B\110", IF_8086|IF_SM}, - {I_SUB, 2, {REG16,REG16,0}, "\320\1\x2B\110", IF_8086}, - {I_SUB, 2, {REG32,MEMORY,0}, "\321\301\1\x2B\110", IF_386|IF_SM}, - {I_SUB, 2, {REG32,REG32,0}, "\321\1\x2B\110", IF_386}, - {I_SUB, 2, {REGMEM|BITS16,IMMEDIATE|BITS8,0}, "\320\300\1\x83\205\15", IF_8086}, - {I_SUB, 2, {REGMEM|BITS32,IMMEDIATE|BITS8,0}, "\321\300\1\x83\205\15", IF_386}, - {I_SUB, 2, {REG_AL,IMMEDIATE,0}, "\1\x2C\21", IF_8086|IF_SM}, - {I_SUB, 2, {REG_AX,SBYTE,0}, "\320\1\x83\205\15", IF_8086|IF_SM}, - {I_SUB, 2, {REG_AX,IMMEDIATE,0}, "\320\1\x2D\31", IF_8086|IF_SM}, - {I_SUB, 2, {REG_EAX,SBYTE,0}, "\321\1\x83\205\15", IF_386|IF_SM}, - {I_SUB, 2, {REG_EAX,IMMEDIATE,0}, "\321\1\x2D\41", IF_386|IF_SM}, - {I_SUB, 2, {REGMEM|BITS8,IMMEDIATE,0}, "\300\1\x80\205\21", IF_8086|IF_SM}, - {I_SUB, 2, {REGMEM|BITS16,IMMEDIATE,0}, "\320\300\134\1\x81\205\131", IF_8086|IF_SM}, - {I_SUB, 2, {REGMEM|BITS32,IMMEDIATE,0}, "\321\300\144\1\x81\205\141", IF_386|IF_SM}, - {I_SUB, 2, {MEMORY,IMMEDIATE|BITS8,0}, "\300\1\x80\205\21", IF_8086|IF_SM}, - {I_SUB, 2, {MEMORY,IMMEDIATE|BITS16,0}, "\320\300\134\1\x81\205\131", IF_8086|IF_SM}, - {I_SUB, 2, {MEMORY,IMMEDIATE|BITS32,0}, "\321\300\144\1\x81\205\141", IF_386|IF_SM}, - ITEMPLATE_END -}; - -static struct itemplate instrux_SUBPD[] = { - {I_SUBPD, 2, {XMMREG,XMMREG,0}, "\3\x66\x0F\x5C\110", IF_WILLAMETTE|IF_SSE2}, - {I_SUBPD, 2, {XMMREG,MEMORY,0}, "\301\3\x66\x0F\x5C\110", IF_WILLAMETTE|IF_SSE2|IF_SM}, - ITEMPLATE_END -}; - -static struct itemplate instrux_SUBPS[] = { - {I_SUBPS, 2, {XMMREG,MEMORY,0}, "\301\331\2\x0F\x5C\110", IF_KATMAI|IF_SSE}, - {I_SUBPS, 2, {XMMREG,XMMREG,0}, "\331\2\x0F\x5C\110", IF_KATMAI|IF_SSE}, - ITEMPLATE_END -}; - -static struct itemplate instrux_SUBSD[] = { - {I_SUBSD, 2, {XMMREG,XMMREG,0}, "\3\xF2\x0F\x5C\110", IF_WILLAMETTE|IF_SSE2}, - {I_SUBSD, 2, {XMMREG,MEMORY,0}, "\301\3\xF2\x0F\x5C\110", IF_WILLAMETTE|IF_SSE2}, - ITEMPLATE_END -}; - -static struct itemplate instrux_SUBSS[] = { - {I_SUBSS, 2, {XMMREG,MEMORY,0}, "\301\333\2\x0F\x5C\110", IF_KATMAI|IF_SSE}, - {I_SUBSS, 2, {XMMREG,XMMREG,0}, "\333\2\x0F\x5C\110", IF_KATMAI|IF_SSE}, - ITEMPLATE_END -}; - -static struct itemplate instrux_SVDC[] = { - {I_SVDC, 2, {MEMORY|BITS80,REG_SREG,0}, "\300\2\x0F\x78\101", IF_486|IF_CYRIX|IF_SMM}, - ITEMPLATE_END -}; - -static struct itemplate instrux_SVLDT[] = { - {I_SVLDT, 1, {MEMORY|BITS80,0,0}, "\300\2\x0F\x7A\200", IF_486|IF_CYRIX|IF_SMM}, - ITEMPLATE_END -}; - -static struct itemplate instrux_SVTS[] = { - {I_SVTS, 1, {MEMORY|BITS80,0,0}, "\300\2\x0F\x7C\200", IF_486|IF_CYRIX|IF_SMM}, - ITEMPLATE_END -}; - -static struct itemplate instrux_SYSCALL[] = { - {I_SYSCALL, 0, {0,0,0}, "\2\x0F\x05", IF_P6|IF_AMD}, - ITEMPLATE_END -}; - -static struct itemplate instrux_SYSENTER[] = { - {I_SYSENTER, 0, {0,0,0}, "\2\x0F\x34", IF_P6}, - ITEMPLATE_END -}; - -static struct itemplate instrux_SYSEXIT[] = { - {I_SYSEXIT, 0, {0,0,0}, "\2\x0F\x35", IF_P6|IF_PRIV}, - ITEMPLATE_END -}; - -static struct itemplate instrux_SYSRET[] = { - {I_SYSRET, 0, {0,0,0}, "\2\x0F\x07", IF_P6|IF_PRIV|IF_AMD}, - ITEMPLATE_END -}; - -static struct itemplate instrux_TEST[] = { - {I_TEST, 2, {MEMORY,REG8,0}, "\300\1\x84\101", IF_8086|IF_SM}, - {I_TEST, 2, {REG8,REG8,0}, "\1\x84\101", IF_8086}, - {I_TEST, 2, {MEMORY,REG16,0}, "\320\300\1\x85\101", IF_8086|IF_SM}, - {I_TEST, 2, {REG16,REG16,0}, "\320\1\x85\101", IF_8086}, - {I_TEST, 2, {MEMORY,REG32,0}, "\321\300\1\x85\101", IF_386|IF_SM}, - {I_TEST, 2, {REG32,REG32,0}, "\321\1\x85\101", IF_386}, - {I_TEST, 2, {REG8,MEMORY,0}, "\301\1\x84\110", IF_8086|IF_SM}, - {I_TEST, 2, {REG16,MEMORY,0}, "\320\301\1\x85\110", IF_8086|IF_SM}, - {I_TEST, 2, {REG32,MEMORY,0}, "\321\301\1\x85\110", IF_386|IF_SM}, - {I_TEST, 2, {REG_AL,IMMEDIATE,0}, "\1\xA8\21", IF_8086|IF_SM}, - {I_TEST, 2, {REG_AX,IMMEDIATE,0}, "\320\1\xA9\31", IF_8086|IF_SM}, - {I_TEST, 2, {REG_EAX,IMMEDIATE,0}, "\321\1\xA9\41", IF_386|IF_SM}, - {I_TEST, 2, {REGMEM|BITS8,IMMEDIATE,0}, "\300\1\xF6\200\21", IF_8086|IF_SM}, - {I_TEST, 2, {REGMEM|BITS16,IMMEDIATE,0}, "\320\300\1\xF7\200\31", IF_8086|IF_SM}, - {I_TEST, 2, {REGMEM|BITS32,IMMEDIATE,0}, "\321\300\1\xF7\200\41", IF_386|IF_SM}, - {I_TEST, 2, {MEMORY,IMMEDIATE|BITS8,0}, "\300\1\xF6\200\21", IF_8086|IF_SM}, - {I_TEST, 2, {MEMORY,IMMEDIATE|BITS16,0}, "\320\300\1\xF7\200\31", IF_8086|IF_SM}, - {I_TEST, 2, {MEMORY,IMMEDIATE|BITS32,0}, "\321\300\1\xF7\200\41", IF_386|IF_SM}, - ITEMPLATE_END -}; - -static struct itemplate instrux_UCOMISD[] = { - {I_UCOMISD, 2, {XMMREG,XMMREG,0}, "\3\x66\x0F\x2E\110", IF_WILLAMETTE|IF_SSE2}, - {I_UCOMISD, 2, {XMMREG,MEMORY,0}, "\301\3\x66\x0F\x2E\110", IF_WILLAMETTE|IF_SSE2}, - ITEMPLATE_END -}; - -static struct itemplate instrux_UCOMISS[] = { - {I_UCOMISS, 2, {XMMREG,MEMORY,0}, "\301\2\x0F\x2E\110", IF_KATMAI|IF_SSE}, - {I_UCOMISS, 2, {XMMREG,XMMREG,0}, "\2\x0F\x2E\110", IF_KATMAI|IF_SSE}, - ITEMPLATE_END -}; - -static struct itemplate instrux_UD0[] = { - {I_UD0, 0, {0,0,0}, "\2\x0F\xFF", IF_286|IF_UNDOC}, - ITEMPLATE_END -}; - -static struct itemplate instrux_UD1[] = { - {I_UD1, 0, {0,0,0}, "\2\x0F\xB9", IF_286|IF_UNDOC}, - ITEMPLATE_END -}; - -static struct itemplate instrux_UD2[] = { - {I_UD2, 0, {0,0,0}, "\2\x0F\x0B", IF_286}, - ITEMPLATE_END -}; - -static struct itemplate instrux_UMOV[] = { - {I_UMOV, 2, {MEMORY,REG8,0}, "\300\2\x0F\x10\101", IF_386|IF_UNDOC|IF_SM}, - {I_UMOV, 2, {REG8,REG8,0}, "\2\x0F\x10\101", IF_386|IF_UNDOC}, - {I_UMOV, 2, {MEMORY,REG16,0}, "\320\300\2\x0F\x11\101", IF_386|IF_UNDOC|IF_SM}, - {I_UMOV, 2, {REG16,REG16,0}, "\320\2\x0F\x11\101", IF_386|IF_UNDOC}, - {I_UMOV, 2, {MEMORY,REG32,0}, "\321\300\2\x0F\x11\101", IF_386|IF_UNDOC|IF_SM}, - {I_UMOV, 2, {REG32,REG32,0}, "\321\2\x0F\x11\101", IF_386|IF_UNDOC}, - {I_UMOV, 2, {REG8,MEMORY,0}, "\301\2\x0F\x12\110", IF_386|IF_UNDOC|IF_SM}, - {I_UMOV, 2, {REG8,REG8,0}, "\2\x0F\x12\110", IF_386|IF_UNDOC}, - {I_UMOV, 2, {REG16,MEMORY,0}, "\320\301\2\x0F\x13\110", IF_386|IF_UNDOC|IF_SM}, - {I_UMOV, 2, {REG16,REG16,0}, "\320\2\x0F\x13\110", IF_386|IF_UNDOC}, - {I_UMOV, 2, {REG32,MEMORY,0}, "\321\301\2\x0F\x13\110", IF_386|IF_UNDOC|IF_SM}, - {I_UMOV, 2, {REG32,REG32,0}, "\321\2\x0F\x13\110", IF_386|IF_UNDOC}, - ITEMPLATE_END -}; - -static struct itemplate instrux_UNPCKHPD[] = { - {I_UNPCKHPD, 2, {XMMREG,XMMREG,0}, "\3\x66\x0F\x15\110", IF_WILLAMETTE|IF_SSE2}, - {I_UNPCKHPD, 2, {XMMREG,MEMORY,0}, "\301\3\x66\x0F\x15\110", IF_WILLAMETTE|IF_SSE2|IF_SM}, - ITEMPLATE_END -}; - -static struct itemplate instrux_UNPCKHPS[] = { - {I_UNPCKHPS, 2, {XMMREG,MEMORY,0}, "\301\2\x0F\x15\110", IF_KATMAI|IF_SSE}, - {I_UNPCKHPS, 2, {XMMREG,XMMREG,0}, "\2\x0F\x15\110", IF_KATMAI|IF_SSE}, - ITEMPLATE_END -}; - -static struct itemplate instrux_UNPCKLPD[] = { - {I_UNPCKLPD, 2, {XMMREG,XMMREG,0}, "\3\x66\x0F\x14\110", IF_WILLAMETTE|IF_SSE2}, - {I_UNPCKLPD, 2, {XMMREG,MEMORY,0}, "\301\3\x66\x0F\x14\110", IF_WILLAMETTE|IF_SSE2|IF_SM}, - ITEMPLATE_END -}; - -static struct itemplate instrux_UNPCKLPS[] = { - {I_UNPCKLPS, 2, {XMMREG,MEMORY,0}, "\301\2\x0F\x14\110", IF_KATMAI|IF_SSE}, - {I_UNPCKLPS, 2, {XMMREG,XMMREG,0}, "\2\x0F\x14\110", IF_KATMAI|IF_SSE}, - ITEMPLATE_END -}; - -static struct itemplate instrux_VERR[] = { - {I_VERR, 1, {MEMORY,0,0}, "\300\1\x0F\17\204", IF_286|IF_PROT}, - {I_VERR, 1, {MEMORY|BITS16,0,0}, "\300\1\x0F\17\204", IF_286|IF_PROT}, - {I_VERR, 1, {REG16,0,0}, "\1\x0F\17\204", IF_286|IF_PROT}, - ITEMPLATE_END -}; - -static struct itemplate instrux_VERW[] = { - {I_VERW, 1, {MEMORY,0,0}, "\300\1\x0F\17\205", IF_286|IF_PROT}, - {I_VERW, 1, {MEMORY|BITS16,0,0}, "\300\1\x0F\17\205", IF_286|IF_PROT}, - {I_VERW, 1, {REG16,0,0}, "\1\x0F\17\205", IF_286|IF_PROT}, - ITEMPLATE_END -}; - -static struct itemplate instrux_WAIT[] = { - {I_WAIT, 0, {0,0,0}, "\1\x9B", IF_8086}, - ITEMPLATE_END -}; - -static struct itemplate instrux_WBINVD[] = { - {I_WBINVD, 0, {0,0,0}, "\2\x0F\x09", IF_486|IF_PRIV}, - ITEMPLATE_END -}; - -static struct itemplate instrux_WRMSR[] = { - {I_WRMSR, 0, {0,0,0}, "\2\x0F\x30", IF_PENT|IF_PRIV}, - ITEMPLATE_END -}; - -static struct itemplate instrux_WRSHR[] = { - {I_WRSHR, 1, {REGMEM|BITS32,0,0}, "\321\300\2\x0F\x37\200", IF_P6|IF_CYRIX|IF_SMM}, - ITEMPLATE_END -}; - -static struct itemplate instrux_XADD[] = { - {I_XADD, 2, {MEMORY,REG8,0}, "\300\2\x0F\xC0\101", IF_486|IF_SM}, - {I_XADD, 2, {REG8,REG8,0}, "\2\x0F\xC0\101", IF_486}, - {I_XADD, 2, {MEMORY,REG16,0}, "\320\300\2\x0F\xC1\101", IF_486|IF_SM}, - {I_XADD, 2, {REG16,REG16,0}, "\320\2\x0F\xC1\101", IF_486}, - {I_XADD, 2, {MEMORY,REG32,0}, "\321\300\2\x0F\xC1\101", IF_486|IF_SM}, - {I_XADD, 2, {REG32,REG32,0}, "\321\2\x0F\xC1\101", IF_486}, - ITEMPLATE_END -}; - -static struct itemplate instrux_XBTS[] = { - {I_XBTS, 2, {REG16,MEMORY,0}, "\320\301\2\x0F\xA6\110", IF_386|IF_SW|IF_UNDOC}, - {I_XBTS, 2, {REG16,REG16,0}, "\320\2\x0F\xA6\110", IF_386|IF_UNDOC}, - {I_XBTS, 2, {REG32,MEMORY,0}, "\321\301\2\x0F\xA6\110", IF_386|IF_SD|IF_UNDOC}, - {I_XBTS, 2, {REG32,REG32,0}, "\321\2\x0F\xA6\110", IF_386|IF_UNDOC}, - ITEMPLATE_END -}; - -static struct itemplate instrux_XCHG[] = { - {I_XCHG, 2, {REG_AX,REG16,0}, "\320\11\x90", IF_8086}, - {I_XCHG, 2, {REG_EAX,REG32,0}, "\321\11\x90", IF_386}, - {I_XCHG, 2, {REG16,REG_AX,0}, "\320\10\x90", IF_8086}, - {I_XCHG, 2, {REG32,REG_EAX,0}, "\321\10\x90", IF_386}, - {I_XCHG, 2, {REG8,MEMORY,0}, "\301\1\x86\110", IF_8086|IF_SM}, - {I_XCHG, 2, {REG8,REG8,0}, "\1\x86\110", IF_8086}, - {I_XCHG, 2, {REG16,MEMORY,0}, "\320\301\1\x87\110", IF_8086|IF_SM}, - {I_XCHG, 2, {REG16,REG16,0}, "\320\1\x87\110", IF_8086}, - {I_XCHG, 2, {REG32,MEMORY,0}, "\321\301\1\x87\110", IF_386|IF_SM}, - {I_XCHG, 2, {REG32,REG32,0}, "\321\1\x87\110", IF_386}, - {I_XCHG, 2, {MEMORY,REG8,0}, "\300\1\x86\101", IF_8086|IF_SM}, - {I_XCHG, 2, {REG8,REG8,0}, "\1\x86\101", IF_8086}, - {I_XCHG, 2, {MEMORY,REG16,0}, "\320\300\1\x87\101", IF_8086|IF_SM}, - {I_XCHG, 2, {REG16,REG16,0}, "\320\1\x87\101", IF_8086}, - {I_XCHG, 2, {MEMORY,REG32,0}, "\321\300\1\x87\101", IF_386|IF_SM}, - {I_XCHG, 2, {REG32,REG32,0}, "\321\1\x87\101", IF_386}, - ITEMPLATE_END -}; - -static struct itemplate instrux_XLAT[] = { - {I_XLAT, 0, {0,0,0}, "\1\xD7", IF_8086}, - ITEMPLATE_END -}; - -static struct itemplate instrux_XLATB[] = { - {I_XLATB, 0, {0,0,0}, "\1\xD7", IF_8086}, - ITEMPLATE_END -}; - -static struct itemplate instrux_XOR[] = { - {I_XOR, 2, {MEMORY,REG8,0}, "\300\1\x30\101", IF_8086|IF_SM}, - {I_XOR, 2, {REG8,REG8,0}, "\1\x30\101", IF_8086}, - {I_XOR, 2, {MEMORY,REG16,0}, "\320\300\1\x31\101", IF_8086|IF_SM}, - {I_XOR, 2, {REG16,REG16,0}, "\320\1\x31\101", IF_8086}, - {I_XOR, 2, {MEMORY,REG32,0}, "\321\300\1\x31\101", IF_386|IF_SM}, - {I_XOR, 2, {REG32,REG32,0}, "\321\1\x31\101", IF_386}, - {I_XOR, 2, {REG8,MEMORY,0}, "\301\1\x32\110", IF_8086|IF_SM}, - {I_XOR, 2, {REG8,REG8,0}, "\1\x32\110", IF_8086}, - {I_XOR, 2, {REG16,MEMORY,0}, "\320\301\1\x33\110", IF_8086|IF_SM}, - {I_XOR, 2, {REG16,REG16,0}, "\320\1\x33\110", IF_8086}, - {I_XOR, 2, {REG32,MEMORY,0}, "\321\301\1\x33\110", IF_386|IF_SM}, - {I_XOR, 2, {REG32,REG32,0}, "\321\1\x33\110", IF_386}, - {I_XOR, 2, {REGMEM|BITS16,IMMEDIATE|BITS8,0}, "\320\300\1\x83\206\15", IF_8086}, - {I_XOR, 2, {REGMEM|BITS32,IMMEDIATE|BITS8,0}, "\321\300\1\x83\206\15", IF_386}, - {I_XOR, 2, {REG_AL,IMMEDIATE,0}, "\1\x34\21", IF_8086|IF_SM}, - {I_XOR, 2, {REG_AX,SBYTE,0}, "\320\1\x83\206\15", IF_8086|IF_SM}, - {I_XOR, 2, {REG_AX,IMMEDIATE,0}, "\320\1\x35\31", IF_8086|IF_SM}, - {I_XOR, 2, {REG_EAX,SBYTE,0}, "\321\1\x83\206\15", IF_386|IF_SM}, - {I_XOR, 2, {REG_EAX,IMMEDIATE,0}, "\321\1\x35\41", IF_386|IF_SM}, - {I_XOR, 2, {REGMEM|BITS8,IMMEDIATE,0}, "\300\1\x80\206\21", IF_8086|IF_SM}, - {I_XOR, 2, {REGMEM|BITS16,IMMEDIATE,0}, "\320\300\134\1\x81\206\131", IF_8086|IF_SM}, - {I_XOR, 2, {REGMEM|BITS32,IMMEDIATE,0}, "\321\300\144\1\x81\206\141", IF_386|IF_SM}, - {I_XOR, 2, {MEMORY,IMMEDIATE|BITS8,0}, "\300\1\x80\206\21", IF_8086|IF_SM}, - {I_XOR, 2, {MEMORY,IMMEDIATE|BITS16,0}, "\320\300\134\1\x81\206\131", IF_8086|IF_SM}, - {I_XOR, 2, {MEMORY,IMMEDIATE|BITS32,0}, "\321\300\144\1\x81\206\141", IF_386|IF_SM}, - ITEMPLATE_END -}; - -static struct itemplate instrux_XORPD[] = { - {I_XORPD, 2, {XMMREG,XMMREG,0}, "\3\x66\x0F\x57\110", IF_WILLAMETTE|IF_SSE2}, - {I_XORPD, 2, {XMMREG,MEMORY,0}, "\301\3\x66\x0F\x57\110", IF_WILLAMETTE|IF_SSE2|IF_SM}, - ITEMPLATE_END -}; - -static struct itemplate instrux_XORPS[] = { - {I_XORPS, 2, {XMMREG,MEMORY,0}, "\301\2\x0F\x57\110", IF_KATMAI|IF_SSE}, - {I_XORPS, 2, {XMMREG,XMMREG,0}, "\2\x0F\x57\110", IF_KATMAI|IF_SSE}, - ITEMPLATE_END -}; - -static struct itemplate instrux_XSTORE[] = { - {I_XSTORE, 0, {0,0,0}, "\3\x0F\xA7\xC0", IF_P6|IF_CYRIX}, - ITEMPLATE_END -}; - -static struct itemplate instrux_CMOVcc[] = { - {I_CMOVcc, 2, {REG16,MEMORY,0}, "\320\301\1\x0F\330\x40\110", IF_P6|IF_SM}, - {I_CMOVcc, 2, {REG16,REG16,0}, "\320\1\x0F\330\x40\110", IF_P6}, - {I_CMOVcc, 2, {REG32,MEMORY,0}, "\321\301\1\x0F\330\x40\110", IF_P6|IF_SM}, - {I_CMOVcc, 2, {REG32,REG32,0}, "\321\1\x0F\330\x40\110", IF_P6}, - ITEMPLATE_END -}; - -static struct itemplate instrux_Jcc[] = { - {I_Jcc, 1, {IMMEDIATE|NEAR,0,0}, "\322\1\x0F\330\x80\64", IF_386}, - {I_Jcc, 1, {IMMEDIATE|BITS16|NEAR,0,0}, "\320\1\x0F\330\x80\64", IF_386}, - {I_Jcc, 1, {IMMEDIATE|BITS32|NEAR,0,0}, "\321\1\x0F\330\x80\64", IF_386}, - {I_Jcc, 1, {IMMEDIATE|SHORT,0,0}, "\330\x70\50", IF_8086}, - {I_Jcc, 1, {IMMEDIATE,0,0}, "\370\330\x70\50", IF_8086}, - {I_Jcc, 1, {IMMEDIATE,0,0}, "\1\x0F\330\x80\64", IF_386}, - {I_Jcc, 1, {IMMEDIATE,0,0}, "\330\x71\373\1\xE9\64", IF_8086}, - {I_Jcc, 1, {IMMEDIATE,0,0}, "\330\x70\50", IF_8086}, - ITEMPLATE_END -}; - -static struct itemplate instrux_SETcc[] = { - {I_SETcc, 1, {MEMORY,0,0}, "\300\1\x0F\330\x90\200", IF_386|IF_SB}, - {I_SETcc, 1, {REG8,0,0}, "\300\1\x0F\330\x90\200", IF_386}, - ITEMPLATE_END -}; - -struct itemplate *nasm_instructions[] = { - instrux_AAA, - instrux_AAD, - instrux_AAM, - instrux_AAS, - instrux_ADC, - instrux_ADD, - instrux_ADDPD, - instrux_ADDPS, - instrux_ADDSD, - instrux_ADDSS, - instrux_ADDSUBPD, - instrux_ADDSUBPS, - instrux_AND, - instrux_ANDNPD, - instrux_ANDNPS, - instrux_ANDPD, - instrux_ANDPS, - instrux_ARPL, - instrux_BOUND, - instrux_BSF, - instrux_BSR, - instrux_BSWAP, - instrux_BT, - instrux_BTC, - instrux_BTR, - instrux_BTS, - instrux_CALL, - instrux_CBW, - instrux_CDQ, - instrux_CLC, - instrux_CLD, - instrux_CLFLUSH, - instrux_CLI, - instrux_CLTS, - instrux_CMC, - instrux_CMP, - instrux_CMPEQPD, - instrux_CMPEQPS, - instrux_CMPEQSD, - instrux_CMPEQSS, - instrux_CMPLEPD, - instrux_CMPLEPS, - instrux_CMPLESD, - instrux_CMPLESS, - instrux_CMPLTPD, - instrux_CMPLTPS, - instrux_CMPLTSD, - instrux_CMPLTSS, - instrux_CMPNEQPD, - instrux_CMPNEQPS, - instrux_CMPNEQSD, - instrux_CMPNEQSS, - instrux_CMPNLEPD, - instrux_CMPNLEPS, - instrux_CMPNLESD, - instrux_CMPNLESS, - instrux_CMPNLTPD, - instrux_CMPNLTPS, - instrux_CMPNLTSD, - instrux_CMPNLTSS, - instrux_CMPORDPD, - instrux_CMPORDPS, - instrux_CMPORDSD, - instrux_CMPORDSS, - instrux_CMPPD, - instrux_CMPPS, - instrux_CMPSB, - instrux_CMPSD, - instrux_CMPSS, - instrux_CMPSW, - instrux_CMPUNORDPD, - instrux_CMPUNORDPS, - instrux_CMPUNORDSD, - instrux_CMPUNORDSS, - instrux_CMPXCHG, - instrux_CMPXCHG486, - instrux_CMPXCHG8B, - instrux_COMISD, - instrux_COMISS, - instrux_CPUID, - instrux_CVTDQ2PD, - instrux_CVTDQ2PS, - instrux_CVTPD2DQ, - instrux_CVTPD2PI, - instrux_CVTPD2PS, - instrux_CVTPI2PD, - instrux_CVTPI2PS, - instrux_CVTPS2DQ, - instrux_CVTPS2PD, - instrux_CVTPS2PI, - instrux_CVTSD2SI, - instrux_CVTSD2SS, - instrux_CVTSI2SD, - instrux_CVTSI2SS, - instrux_CVTSS2SD, - instrux_CVTSS2SI, - instrux_CVTTPD2DQ, - instrux_CVTTPD2PI, - instrux_CVTTPS2DQ, - instrux_CVTTPS2PI, - instrux_CVTTSD2SI, - instrux_CVTTSS2SI, - instrux_CWD, - instrux_CWDE, - instrux_DAA, - instrux_DAS, - instrux_DB, - instrux_DD, - instrux_DEC, - instrux_DIV, - instrux_DIVPD, - instrux_DIVPS, - instrux_DIVSD, - instrux_DIVSS, - instrux_DQ, - instrux_DT, - instrux_DW, - instrux_EMMS, - instrux_ENTER, - instrux_EQU, - instrux_F2XM1, - instrux_FABS, - instrux_FADD, - instrux_FADDP, - instrux_FBLD, - instrux_FBSTP, - instrux_FCHS, - instrux_FCLEX, - instrux_FCMOVB, - instrux_FCMOVBE, - instrux_FCMOVE, - instrux_FCMOVNB, - instrux_FCMOVNBE, - instrux_FCMOVNE, - instrux_FCMOVNU, - instrux_FCMOVU, - instrux_FCOM, - instrux_FCOMI, - instrux_FCOMIP, - instrux_FCOMP, - instrux_FCOMPP, - instrux_FCOS, - instrux_FDECSTP, - instrux_FDISI, - instrux_FDIV, - instrux_FDIVP, - instrux_FDIVR, - instrux_FDIVRP, - instrux_FEMMS, - instrux_FENI, - instrux_FFREE, - instrux_FFREEP, - instrux_FIADD, - instrux_FICOM, - instrux_FICOMP, - instrux_FIDIV, - instrux_FIDIVR, - instrux_FILD, - instrux_FIMUL, - instrux_FINCSTP, - instrux_FINIT, - instrux_FIST, - instrux_FISTP, - instrux_FISTTP, - instrux_FISUB, - instrux_FISUBR, - instrux_FLD, - instrux_FLD1, - instrux_FLDCW, - instrux_FLDENV, - instrux_FLDL2E, - instrux_FLDL2T, - instrux_FLDLG2, - instrux_FLDLN2, - instrux_FLDPI, - instrux_FLDZ, - instrux_FMUL, - instrux_FMULP, - instrux_FNCLEX, - instrux_FNDISI, - instrux_FNENI, - instrux_FNINIT, - instrux_FNOP, - instrux_FNSAVE, - instrux_FNSTCW, - instrux_FNSTENV, - instrux_FNSTSW, - instrux_FPATAN, - instrux_FPREM, - instrux_FPREM1, - instrux_FPTAN, - instrux_FRNDINT, - instrux_FRSTOR, - instrux_FSAVE, - instrux_FSCALE, - instrux_FSETPM, - instrux_FSIN, - instrux_FSINCOS, - instrux_FSQRT, - instrux_FST, - instrux_FSTCW, - instrux_FSTENV, - instrux_FSTP, - instrux_FSTSW, - instrux_FSUB, - instrux_FSUBP, - instrux_FSUBR, - instrux_FSUBRP, - instrux_FTST, - instrux_FUCOM, - instrux_FUCOMI, - instrux_FUCOMIP, - instrux_FUCOMP, - instrux_FUCOMPP, - instrux_FWAIT, - instrux_FXAM, - instrux_FXCH, - instrux_FXRSTOR, - instrux_FXSAVE, - instrux_FXTRACT, - instrux_FYL2X, - instrux_FYL2XP1, - instrux_HADDPD, - instrux_HADDPS, - instrux_HLT, - instrux_HSUBPD, - instrux_HSUBPS, - instrux_IBTS, - instrux_ICEBP, - instrux_IDIV, - instrux_IMUL, - instrux_IN, - instrux_INC, - instrux_INCBIN, - instrux_INSB, - instrux_INSD, - instrux_INSW, - instrux_INT, - instrux_INT01, - instrux_INT03, - instrux_INT1, - instrux_INT3, - instrux_INTO, - instrux_INVD, - instrux_INVLPG, - instrux_IRET, - instrux_IRETD, - instrux_IRETW, - instrux_JCXZ, - instrux_JECXZ, - instrux_JMP, - instrux_JMPE, - instrux_LAHF, - instrux_LAR, - instrux_LDDQU, - instrux_LDMXCSR, - instrux_LDS, - instrux_LEA, - instrux_LEAVE, - instrux_LES, - instrux_LFENCE, - instrux_LFS, - instrux_LGDT, - instrux_LGS, - instrux_LIDT, - instrux_LLDT, - instrux_LMSW, - instrux_LOADALL, - instrux_LOADALL286, - instrux_LODSB, - instrux_LODSD, - instrux_LODSW, - instrux_LOOP, - instrux_LOOPE, - instrux_LOOPNE, - instrux_LOOPNZ, - instrux_LOOPZ, - instrux_LSL, - instrux_LSS, - instrux_LTR, - instrux_MASKMOVDQU, - instrux_MASKMOVQ, - instrux_MAXPD, - instrux_MAXPS, - instrux_MAXSD, - instrux_MAXSS, - instrux_MFENCE, - instrux_MINPD, - instrux_MINPS, - instrux_MINSD, - instrux_MINSS, - instrux_MONITOR, - instrux_MOV, - instrux_MOVAPD, - instrux_MOVAPS, - instrux_MOVD, - instrux_MOVDDUP, - instrux_MOVDQ2Q, - instrux_MOVDQA, - instrux_MOVDQU, - instrux_MOVHLPS, - instrux_MOVHPD, - instrux_MOVHPS, - instrux_MOVLHPS, - instrux_MOVLPD, - instrux_MOVLPS, - instrux_MOVMSKPD, - instrux_MOVMSKPS, - instrux_MOVNTDQ, - instrux_MOVNTI, - instrux_MOVNTPD, - instrux_MOVNTPS, - instrux_MOVNTQ, - instrux_MOVQ, - instrux_MOVQ2DQ, - instrux_MOVSB, - instrux_MOVSD, - instrux_MOVSHDUP, - instrux_MOVSLDUP, - instrux_MOVSS, - instrux_MOVSW, - instrux_MOVSX, - instrux_MOVUPD, - instrux_MOVUPS, - instrux_MOVZX, - instrux_MUL, - instrux_MULPD, - instrux_MULPS, - instrux_MULSD, - instrux_MULSS, - instrux_MWAIT, - instrux_NEG, - instrux_NOP, - instrux_NOT, - instrux_OR, - instrux_ORPD, - instrux_ORPS, - instrux_OUT, - instrux_OUTSB, - instrux_OUTSD, - instrux_OUTSW, - instrux_PACKSSDW, - instrux_PACKSSWB, - instrux_PACKUSWB, - instrux_PADDB, - instrux_PADDD, - instrux_PADDQ, - instrux_PADDSB, - instrux_PADDSIW, - instrux_PADDSW, - instrux_PADDUSB, - instrux_PADDUSW, - instrux_PADDW, - instrux_PAND, - instrux_PANDN, - instrux_PAUSE, - instrux_PAVEB, - instrux_PAVGB, - instrux_PAVGUSB, - instrux_PAVGW, - instrux_PCMPEQB, - instrux_PCMPEQD, - instrux_PCMPEQW, - instrux_PCMPGTB, - instrux_PCMPGTD, - instrux_PCMPGTW, - instrux_PDISTIB, - instrux_PEXTRW, - instrux_PF2ID, - instrux_PF2IW, - instrux_PFACC, - instrux_PFADD, - instrux_PFCMPEQ, - instrux_PFCMPGE, - instrux_PFCMPGT, - instrux_PFMAX, - instrux_PFMIN, - instrux_PFMUL, - instrux_PFNACC, - instrux_PFPNACC, - instrux_PFRCP, - instrux_PFRCPIT1, - instrux_PFRCPIT2, - instrux_PFRSQIT1, - instrux_PFRSQRT, - instrux_PFSUB, - instrux_PFSUBR, - instrux_PI2FD, - instrux_PI2FW, - instrux_PINSRW, - instrux_PMACHRIW, - instrux_PMADDWD, - instrux_PMAGW, - instrux_PMAXSW, - instrux_PMAXUB, - instrux_PMINSW, - instrux_PMINUB, - instrux_PMOVMSKB, - instrux_PMULHRIW, - instrux_PMULHRWA, - instrux_PMULHRWC, - instrux_PMULHUW, - instrux_PMULHW, - instrux_PMULLW, - instrux_PMULUDQ, - instrux_PMVGEZB, - instrux_PMVLZB, - instrux_PMVNZB, - instrux_PMVZB, - instrux_POP, - instrux_POPA, - instrux_POPAD, - instrux_POPAW, - instrux_POPF, - instrux_POPFD, - instrux_POPFW, - instrux_POR, - instrux_PREFETCH, - instrux_PREFETCHNTA, - instrux_PREFETCHT0, - instrux_PREFETCHT1, - instrux_PREFETCHT2, - instrux_PREFETCHW, - instrux_PSADBW, - instrux_PSHUFD, - instrux_PSHUFHW, - instrux_PSHUFLW, - instrux_PSHUFW, - instrux_PSLLD, - instrux_PSLLDQ, - instrux_PSLLQ, - instrux_PSLLW, - instrux_PSRAD, - instrux_PSRAW, - instrux_PSRLD, - instrux_PSRLDQ, - instrux_PSRLQ, - instrux_PSRLW, - instrux_PSUBB, - instrux_PSUBD, - instrux_PSUBQ, - instrux_PSUBSB, - instrux_PSUBSIW, - instrux_PSUBSW, - instrux_PSUBUSB, - instrux_PSUBUSW, - instrux_PSUBW, - instrux_PSWAPD, - instrux_PUNPCKHBW, - instrux_PUNPCKHDQ, - instrux_PUNPCKHQDQ, - instrux_PUNPCKHWD, - instrux_PUNPCKLBW, - instrux_PUNPCKLDQ, - instrux_PUNPCKLQDQ, - instrux_PUNPCKLWD, - instrux_PUSH, - instrux_PUSHA, - instrux_PUSHAD, - instrux_PUSHAW, - instrux_PUSHF, - instrux_PUSHFD, - instrux_PUSHFW, - instrux_PXOR, - instrux_RCL, - instrux_RCPPS, - instrux_RCPSS, - instrux_RCR, - instrux_RDMSR, - instrux_RDPMC, - instrux_RDSHR, - instrux_RDTSC, - instrux_RESB, - instrux_RESD, - instrux_RESQ, - instrux_REST, - instrux_RESW, - instrux_RET, - instrux_RETF, - instrux_RETN, - instrux_ROL, - instrux_ROR, - instrux_RSDC, - instrux_RSLDT, - instrux_RSM, - instrux_RSQRTPS, - instrux_RSQRTSS, - instrux_RSTS, - instrux_SAHF, - instrux_SAL, - instrux_SALC, - instrux_SAR, - instrux_SBB, - instrux_SCASB, - instrux_SCASD, - instrux_SCASW, - instrux_SFENCE, - instrux_SGDT, - instrux_SHL, - instrux_SHLD, - instrux_SHR, - instrux_SHRD, - instrux_SHUFPD, - instrux_SHUFPS, - instrux_SIDT, - instrux_SLDT, - instrux_SMI, - instrux_SMINT, - instrux_SMINTOLD, - instrux_SMSW, - instrux_SQRTPD, - instrux_SQRTPS, - instrux_SQRTSD, - instrux_SQRTSS, - instrux_STC, - instrux_STD, - instrux_STI, - instrux_STMXCSR, - instrux_STOSB, - instrux_STOSD, - instrux_STOSW, - instrux_STR, - instrux_SUB, - instrux_SUBPD, - instrux_SUBPS, - instrux_SUBSD, - instrux_SUBSS, - instrux_SVDC, - instrux_SVLDT, - instrux_SVTS, - instrux_SYSCALL, - instrux_SYSENTER, - instrux_SYSEXIT, - instrux_SYSRET, - instrux_TEST, - instrux_UCOMISD, - instrux_UCOMISS, - instrux_UD0, - instrux_UD1, - instrux_UD2, - instrux_UMOV, - instrux_UNPCKHPD, - instrux_UNPCKHPS, - instrux_UNPCKLPD, - instrux_UNPCKLPS, - instrux_VERR, - instrux_VERW, - instrux_WAIT, - instrux_WBINVD, - instrux_WRMSR, - instrux_WRSHR, - instrux_XADD, - instrux_XBTS, - instrux_XCHG, - instrux_XLAT, - instrux_XLATB, - instrux_XOR, - instrux_XORPD, - instrux_XORPS, - instrux_XSTORE, - instrux_CMOVcc, - instrux_Jcc, - instrux_SETcc, -}; diff --git a/AltairZ80/mfdc.c b/AltairZ80/mfdc.c index 5ac79053..e697660d 100644 --- a/AltairZ80/mfdc.c +++ b/AltairZ80/mfdc.c @@ -161,10 +161,6 @@ static MTAB mfdc_mod[] = { { 0 } }; -#define TRACE_PRINT(level, args) if(mfdc_dev.dctrl & level) { \ - printf args; \ - } - /* Debug Flags */ static DEBTAB mfdc_dt[] = { { "ERROR", ERROR_MSG }, @@ -402,7 +398,7 @@ static uint8 MFDC_Read(const uint32 Addr) cData |= (1 << 7); /* Sector Flag */ mfdc_info->xfr_flag = 1; /* Drive has data */ mfdc_info->datacount = 0; - TRACE_PRINT(STATUS_MSG, ("MFDC: " ADDRESS_FORMAT " RD Sector Register = 0x%02x" NLP, PCX, cData)); + sim_debug(STATUS_MSG, &mfdc_dev, "MFDC: " ADDRESS_FORMAT " RD Sector Register = 0x%02x\n", PCX, cData); break; case 1: cData = (mfdc_info->sel_drive & 0x3); /* [1:0] selected drive */ @@ -414,15 +410,15 @@ static uint8 MFDC_Read(const uint32 Addr) cData |= (0 << 6); /* [6] PINTE from S-100 Bus */ cData |= (mfdc_info->xfr_flag << 7); /* [7] Transfer Flag */ - TRACE_PRINT(STATUS_MSG, ("MFDC: " ADDRESS_FORMAT " RD Status = 0x%02x" NLP, PCX, cData)); + sim_debug(STATUS_MSG, &mfdc_dev, "MFDC: " ADDRESS_FORMAT " RD Status = 0x%02x\n", PCX, cData); break; case 2: case 3: if(mfdc_info->datacount == 0) { unsigned int i, checksum; unsigned long sec_offset; - uint32 flags; - uint32 readlen; + unsigned int flags; + unsigned int readlen; /* Clear out unused portion of sector. */ memset(&sdata.u.unused[0], 0x00, 10); @@ -431,10 +427,7 @@ static uint8 MFDC_Read(const uint32 Addr) sdata.u.header[0] = pDrive->track; sdata.u.header[1] = pDrive->sector; - TRACE_PRINT(RD_DATA_MSG, ("MFDC: " ADDRESS_FORMAT " RD Data T:%d S:[%d]" NLP, - PCX, - pDrive->track, - pDrive->sector)); + sim_debug(RD_DATA_MSG, &mfdc_dev, "MFDC: " ADDRESS_FORMAT " RD Data T:%d S:[%d]\n", PCX, pDrive->track, pDrive->sector); #ifdef USE_VGI sec_offset = (pDrive->track * MFDC_SECTOR_LEN * 16) + \ @@ -509,8 +502,7 @@ static uint8 MFDC_Read(const uint32 Addr) mfdc_info->datacount++; if(mfdc_info->datacount == 270) { - TRACE_PRINT(RD_DATA_MSG, ("MFDC: " ADDRESS_FORMAT " Read sector [%d] complete" NLP, - PCX, pDrive->sector)); + sim_debug(RD_DATA_MSG, &mfdc_dev, "MFDC: " ADDRESS_FORMAT " Read sector [%d] complete\n", PCX, pDrive->sector); mfdc_info->read_in_progress = FALSE; } @@ -524,8 +516,8 @@ static uint8 MFDC_Read(const uint32 Addr) static uint8 MFDC_Write(const uint32 Addr, uint8 cData) { unsigned int sec_offset; - uint32 flags = 0; - uint32 writelen; + unsigned int flags = 0; + unsigned int writelen; MFDC_DRIVE_INFO *pDrive; pDrive = &mfdc_info->drive[mfdc_info->sel_drive]; @@ -564,10 +556,7 @@ static uint8 MFDC_Write(const uint32 Addr, uint8 cData) mfdc_info->datacount ++; if(mfdc_info->datacount == 270) { - TRACE_PRINT(WR_DATA_MSG, ("MFDC: " ADDRESS_FORMAT " WR Data T:%d S:[%d]" NLP, - PCX, - pDrive->track, - pDrive->sector)); + sim_debug(WR_DATA_MSG, &mfdc_dev, "MFDC: " ADDRESS_FORMAT " WR Data T:%d S:[%d]\n", PCX, pDrive->track, pDrive->sector); if (!(pDrive->uptr->flags & UNIT_ATT)) { if (pDrive->uptr->flags & UNIT_MFDC_VERBOSE) @@ -641,7 +630,7 @@ static void MFDC_Command(uint8 cData) switch(cCommand) { case MFDC_CMD_NOP: - TRACE_PRINT(CMD_MSG, ("MFDC: " ADDRESS_FORMAT " No Op." NLP, PCX)); + sim_debug(CMD_MSG, &mfdc_dev, "MFDC: " ADDRESS_FORMAT " No Op.\n", PCX); break; case MFDC_CMD_SELECT: mfdc_info->sel_drive = cModifier & 0x03; @@ -654,13 +643,11 @@ static void MFDC_Command(uint8 cData) pDrive->ready = 0; } - TRACE_PRINT(CMD_MSG, ("MFDC: " ADDRESS_FORMAT " Select Drive: %d, Head: %s" NLP, - PCX, mfdc_info->sel_drive, (mfdc_info->head) ? "Upper" : "Lower")); + sim_debug(CMD_MSG, &mfdc_dev, "MFDC: " ADDRESS_FORMAT " Select Drive: %d, Head: %s\n", PCX, mfdc_info->sel_drive, (mfdc_info->head) ? "Upper" : "Lower"); break; case MFDC_CMD_INTR: mfdc_info->int_enable = cModifier & 1; /* 0=int disable, 1=enable */ - TRACE_PRINT(CMD_MSG, ("MFDC: " ADDRESS_FORMAT " Interrupts %s." NLP, - PCX, mfdc_info->int_enable ? "Enabled" : "Disabled")); + sim_debug(CMD_MSG, &mfdc_dev, "MFDC: " ADDRESS_FORMAT " Interrupts %s.\n", PCX, mfdc_info->int_enable ? "Enabled" : "Disabled"); break; case MFDC_CMD_STEP: if(cModifier & 1) { /* Step IN */ @@ -672,23 +659,22 @@ static void MFDC_Command(uint8 cData) } } - TRACE_PRINT(SEEK_MSG, ("MFDC: " ADDRESS_FORMAT " Step %s, Track=%d." NLP, - PCX, (cModifier & 1) ? "IN" : "OUT", pDrive->track)); + sim_debug(SEEK_MSG, &mfdc_dev, "MFDC: " ADDRESS_FORMAT " Step %s, Track=%d.\n", PCX, (cModifier & 1) ? "IN" : "OUT", pDrive->track); break; case MFDC_CMD_SET_WRITE: - TRACE_PRINT(CMD_MSG, ("MFDC: " ADDRESS_FORMAT " Set WRITE." NLP, PCX)); + sim_debug(CMD_MSG, &mfdc_dev, "MFDC: " ADDRESS_FORMAT " Set WRITE.\n", PCX); mfdc_info->wr_latch = 1; /* Allow writes for the current sector */ mfdc_info->datacount = 0; /* reset the byte counter */ break; case MFDC_CMD_RESET: - TRACE_PRINT(CMD_MSG, ("MFDC: " ADDRESS_FORMAT " Reset Controller." NLP, PCX)); + sim_debug(CMD_MSG, &mfdc_dev, "MFDC: " ADDRESS_FORMAT " Reset Controller.\n", PCX); mfdc_info->selected = 0; /* de-select the drive */ mfdc_info->wr_latch = 0; /* Disable the write latch */ mfdc_info->datacount = 0; /* reset the byte counter */ break; default: - TRACE_PRINT(CMD_MSG, ("MFDC: " ADDRESS_FORMAT " Unsupported command." NLP, PCX)); + sim_debug(CMD_MSG, &mfdc_dev, "MFDC: " ADDRESS_FORMAT " Unsupported command.\n", PCX); break; } } diff --git a/AltairZ80/n8vem.c b/AltairZ80/n8vem.c index c1dbdbe2..99bfb446 100644 --- a/AltairZ80/n8vem.c +++ b/AltairZ80/n8vem.c @@ -136,10 +136,6 @@ static MTAB n8vem_mod[] = { { 0 } }; -#define TRACE_PRINT(level, args) if(n8vem_dev.dctrl & level) { \ - printf args; \ - } - /* Debug Flags */ static DEBTAB n8vem_dt[] = { { "ERROR", ERROR_MSG }, @@ -165,7 +161,7 @@ static t_stat n8vem_reset(DEVICE *dptr) { PNP_INFO *pnp = (PNP_INFO *)dptr->ctxt; - TRACE_PRINT(VERBOSE_MSG, ("N8VEM: Reset.\n")); + sim_debug(VERBOSE_MSG, &n8vem_dev, "N8VEM: Reset.\n"); if(dptr->flags & DEV_DIS) { /* Disconnect I/O Ports */ sim_map_resource(pnp->io_base, pnp->io_size, RESOURCE_TYPE_IO, &n8vemdev, TRUE); @@ -196,7 +192,7 @@ static t_stat n8vem_reset(DEVICE *dptr) static t_stat n8vem_boot(int32 unitno, DEVICE *dptr) { - TRACE_PRINT(VERBOSE_MSG, ("N8VEM: Boot.\n")); + sim_debug(VERBOSE_MSG, &n8vem_dev, "N8VEM: Boot.\n"); /* Clear the RAM and ROM mapping registers */ n8vem_info->mpcl_ram = 0; @@ -226,7 +222,7 @@ static t_stat n8vem_attach(UNIT *uptr, char *cptr) /* Determine length of this disk */ uptr->capac = sim_fsize(uptr->fileref); - TRACE_PRINT(VERBOSE_MSG, ("N8VEM: Attach %s.\n", i == 0 ? "ROM" : "RAM")); + sim_debug(VERBOSE_MSG, &n8vem_dev, "N8VEM: Attach %s.\n", i == 0 ? "ROM" : "RAM"); if(i == 0) { /* Attaching ROM */ n8vem_info->rom_attached = TRUE; @@ -240,9 +236,7 @@ static t_stat n8vem_attach(UNIT *uptr, char *cptr) uptr->capac = N8VEM_ROM_SIZE; rtn = fread((void *)(n8vem_info->rom), uptr->capac, 1, uptr->fileref); - TRACE_PRINT(VERBOSE_MSG, ("N8VEM: Reading %d bytes into ROM." - " Result = %ssuccessful.\n", - uptr->capac, rtn == 1 ? "" : "not ")); + sim_debug(VERBOSE_MSG, &n8vem_dev, "N8VEM: Reading %d bytes into ROM." " Result = %ssuccessful.\n", uptr->capac, rtn == 1 ? "" : "not "); } } else { /* attaching RAM */ /* Erase RAM */ @@ -254,9 +248,7 @@ static t_stat n8vem_attach(UNIT *uptr, char *cptr) uptr->capac = N8VEM_RAM_SIZE; rtn = fread((void *)(n8vem_info->ram), uptr->capac, 1, uptr->fileref); - TRACE_PRINT(VERBOSE_MSG, ("N8VEM: Reading %d bytes into RAM." - " Result = %ssuccessful.\n", - uptr->capac, rtn == 1 ? "" : "not ")); + sim_debug(VERBOSE_MSG, &n8vem_dev, "N8VEM: Reading %d bytes into RAM." " Result = %ssuccessful.\n", uptr->capac, rtn == 1 ? "" : "not "); } } return r; @@ -274,7 +266,7 @@ static t_stat n8vem_detach(UNIT *uptr) return (SCPE_IERR); } - TRACE_PRINT(VERBOSE_MSG, ("N8VEM: Detach %s.\n", i == 0 ? "ROM" : "RAM")); + sim_debug(VERBOSE_MSG, &n8vem_dev, "N8VEM: Detach %s.\n", i == 0 ? "ROM" : "RAM"); /* rewind to the beginning of the file. */ sim_fseek(uptr->fileref, 0, SEEK_SET); @@ -282,13 +274,13 @@ static t_stat n8vem_detach(UNIT *uptr) if(i == 0) { /* ROM */ /* Save the ROM back to disk if SAVEROM is set. */ if(save_rom == 1) { - TRACE_PRINT(VERBOSE_MSG, ("N8VEM: Writing %d bytes into ROM image.\n", N8VEM_ROM_SIZE)); + sim_debug(VERBOSE_MSG, &n8vem_dev, "N8VEM: Writing %d bytes into ROM image.\n", N8VEM_ROM_SIZE); fwrite((void *)(n8vem_info->rom), N8VEM_ROM_SIZE, 1, uptr->fileref); } } else { /* RAM */ /* Save the RAM back to disk if SAVERAM is set. */ if(save_ram == 1) { - TRACE_PRINT(VERBOSE_MSG, ("N8VEM: Writing %d bytes into RAM image.\n", N8VEM_RAM_SIZE)); + sim_debug(VERBOSE_MSG, &n8vem_dev, "N8VEM: Writing %d bytes into RAM image.\n", N8VEM_RAM_SIZE); fwrite((void *)(n8vem_info->ram), N8VEM_RAM_SIZE, 1, uptr->fileref); } } @@ -334,7 +326,7 @@ static t_stat n8vem_detach(UNIT *uptr) if(save_rom == 1) { n8vem_info->rom[((n8vem_info->mpcl_rom & N8VEM_ROM_MASK) << 15) | (Addr & N8VEM_ADDR_MASK)] = data; } else { - TRACE_PRINT(ROM_MSG, ("N8VEM: " ADDRESS_FORMAT " WR ROM[0x%05x]: Cannot write to ROM." NLP, PCX, ((n8vem_info->mpcl_rom & N8VEM_ROM_MASK) << 15) | (Addr & N8VEM_ADDR_MASK))); + sim_debug(ROM_MSG, &n8vem_dev, "N8VEM: " ADDRESS_FORMAT " WR ROM[0x%05x]: Cannot write to ROM.\n", PCX, ((n8vem_info->mpcl_rom & N8VEM_ROM_MASK) << 15) | (Addr & N8VEM_ADDR_MASK)); } } return 0; @@ -391,19 +383,19 @@ static uint8 N8VEM_Read(const uint32 Addr) switch(Addr & 0x1F) { case N8VEM_PIO1A: - TRACE_PRINT(PIO_MSG, ("N8VEM: " ADDRESS_FORMAT " RD: PIO1A" NLP, PCX)); + sim_debug(PIO_MSG, &n8vem_dev, "N8VEM: " ADDRESS_FORMAT " RD: PIO1A\n", PCX); cData = n8vem_pio1a; break; case N8VEM_PIO1B: - TRACE_PRINT(PIO_MSG, ("N8VEM: " ADDRESS_FORMAT " RD: PIO1B" NLP, PCX)); + sim_debug(PIO_MSG, &n8vem_dev, "N8VEM: " ADDRESS_FORMAT " RD: PIO1B\n", PCX); cData = n8vem_pio1b; break; case N8VEM_PIO1C: - TRACE_PRINT(PIO_MSG, ("N8VEM: " ADDRESS_FORMAT " RD: PIO1C" NLP, PCX)); + sim_debug(PIO_MSG, &n8vem_dev, "N8VEM: " ADDRESS_FORMAT " RD: PIO1C\n", PCX); cData = n8vem_pio1c; break; case N8VEM_PIO1CONT: - TRACE_PRINT(PIO_MSG, ("N8VEM: " ADDRESS_FORMAT " RD: PIO1CTRL" NLP, PCX)); + sim_debug(PIO_MSG, &n8vem_dev, "N8VEM: " ADDRESS_FORMAT " RD: PIO1CTRL\n", PCX); cData = n8vem_pio1ctrl; break; case N8VEM_UART_LCR: @@ -415,7 +407,7 @@ static uint8 N8VEM_Read(const uint32 Addr) case N8VEM_UART_INTR: case N8VEM_UART_MCR: case N8VEM_UART_MSR: - TRACE_PRINT(UART_MSG, ("N8VEM: " ADDRESS_FORMAT " RD[%02x]: UART not Implemented." NLP, PCX, Addr)); + sim_debug(UART_MSG, &n8vem_dev, "N8VEM: " ADDRESS_FORMAT " RD[%02x]: UART not Implemented.\n", PCX, Addr); break; case N8VEM_UART_SCR: /* 16550 Scratchpad, implemented so software can detect UART is present */ cData = n8vem_info->uart_scr; @@ -424,16 +416,16 @@ static uint8 N8VEM_Read(const uint32 Addr) case N8VEM_MPCL_RAM1: case N8VEM_MPCL_RAM2: case N8VEM_MPCL_RAM3: - TRACE_PRINT(MPCL_MSG, ("N8VEM: " ADDRESS_FORMAT " RD: MPCL_RAM not Implemented." NLP, PCX)); + sim_debug(MPCL_MSG, &n8vem_dev, "N8VEM: " ADDRESS_FORMAT " RD: MPCL_RAM not Implemented.\n", PCX); break; case N8VEM_MPCL_ROM: case N8VEM_MPCL_ROM1: case N8VEM_MPCL_ROM2: case N8VEM_MPCL_ROM3: - TRACE_PRINT(MPCL_MSG, ("N8VEM: " ADDRESS_FORMAT " RD: MPCL_ROM not Implemented." NLP, PCX)); + sim_debug(MPCL_MSG, &n8vem_dev, "N8VEM: " ADDRESS_FORMAT " RD: MPCL_ROM not Implemented.\n", PCX); break; default: - TRACE_PRINT(VERBOSE_MSG, ("N8VEM: " ADDRESS_FORMAT " RD[%02x]: not Implemented." NLP, PCX, Addr)); + sim_debug(VERBOSE_MSG, &n8vem_dev, "N8VEM: " ADDRESS_FORMAT " RD[%02x]: not Implemented.\n", PCX, Addr); break; } @@ -446,23 +438,23 @@ static uint8 N8VEM_Write(const uint32 Addr, uint8 cData) switch(Addr & 0x1F) { case N8VEM_PIO1A: - TRACE_PRINT(PIO_MSG, ("N8VEM: " ADDRESS_FORMAT " WR: PIO1A=0x%02x" NLP, PCX, cData)); + sim_debug(PIO_MSG, &n8vem_dev, "N8VEM: " ADDRESS_FORMAT " WR: PIO1A=0x%02x\n", PCX, cData); n8vem_pio1a = cData; break; case N8VEM_PIO1B: - TRACE_PRINT(PIO_MSG, ("N8VEM: " ADDRESS_FORMAT " WR: PIO1B=0x%02x" NLP, PCX, cData)); + sim_debug(PIO_MSG, &n8vem_dev, "N8VEM: " ADDRESS_FORMAT " WR: PIO1B=0x%02x\n", PCX, cData); n8vem_pio1b = cData; break; case N8VEM_PIO1C: - TRACE_PRINT(PIO_MSG, ("N8VEM: " ADDRESS_FORMAT " WR: PIO1C=0x%02x" NLP, PCX, cData)); + sim_debug(PIO_MSG, &n8vem_dev, "N8VEM: " ADDRESS_FORMAT " WR: PIO1C=0x%02x\n", PCX, cData); n8vem_pio1c = cData; break; case N8VEM_PIO1CONT: - TRACE_PRINT(PIO_MSG, ("N8VEM: " ADDRESS_FORMAT " WR: PIO1_CTRL=0x%02x" NLP, PCX, cData)); + sim_debug(PIO_MSG, &n8vem_dev, "N8VEM: " ADDRESS_FORMAT " WR: PIO1_CTRL=0x%02x\n", PCX, cData); n8vem_pio1ctrl = cData; break; case N8VEM_UART_LCR: - TRACE_PRINT(UART_MSG, ("N8VEM: " ADDRESS_FORMAT " WR: UART LCR=%02x." NLP, PCX, cData)); + sim_debug(UART_MSG, &n8vem_dev, "N8VEM: " ADDRESS_FORMAT " WR: UART LCR=%02x.\n", PCX, cData); n8vem_info->uart_lcr = cData; break; case N8VEM_UART_DATA: @@ -471,7 +463,7 @@ static uint8 N8VEM_Write(const uint32 Addr, uint8 cData) case N8VEM_UART_MCR: case N8VEM_UART_LSR: case N8VEM_UART_MSR: - TRACE_PRINT(UART_MSG, ("N8VEM: " ADDRESS_FORMAT " WR[%02x]: UART not Implemented." NLP, PCX, Addr)); + sim_debug(UART_MSG, &n8vem_dev, "N8VEM: " ADDRESS_FORMAT " WR[%02x]: UART not Implemented.\n", PCX, Addr); break; case N8VEM_UART_SCR: /* 16550 Scratchpad, implemented so software can detect UART is present */ n8vem_info->uart_scr = cData; @@ -480,18 +472,18 @@ static uint8 N8VEM_Write(const uint32 Addr, uint8 cData) case N8VEM_MPCL_RAM1: case N8VEM_MPCL_RAM2: case N8VEM_MPCL_RAM3: - TRACE_PRINT(MPCL_MSG, ("N8VEM: " ADDRESS_FORMAT " WR: MPCL_RAM=0x%02x" NLP, PCX, cData)); + sim_debug(MPCL_MSG, &n8vem_dev, "N8VEM: " ADDRESS_FORMAT " WR: MPCL_RAM=0x%02x\n", PCX, cData); n8vem_info->mpcl_ram = cData; break; case N8VEM_MPCL_ROM: case N8VEM_MPCL_ROM1: case N8VEM_MPCL_ROM2: case N8VEM_MPCL_ROM3: - TRACE_PRINT(MPCL_MSG, ("N8VEM: " ADDRESS_FORMAT " WR: MPCL_ROM=0x%02x" NLP, PCX, cData)); + sim_debug(MPCL_MSG, &n8vem_dev, "N8VEM: " ADDRESS_FORMAT " WR: MPCL_ROM=0x%02x\n", PCX, cData); n8vem_info->mpcl_rom = cData; break; default: - TRACE_PRINT(VERBOSE_MSG, ("N8VEM: " ADDRESS_FORMAT " WR[0x%02x]=0x%02x: not Implemented." NLP, PCX, Addr, cData)); + sim_debug(VERBOSE_MSG, &n8vem_dev, "N8VEM: " ADDRESS_FORMAT " WR[0x%02x]=0x%02x: not Implemented.\n", PCX, Addr, cData); break; } diff --git a/AltairZ80/s100_64fdc.c b/AltairZ80/s100_64fdc.c index 86b7d0e7..03c4f395 100644 --- a/AltairZ80/s100_64fdc.c +++ b/AltairZ80/s100_64fdc.c @@ -86,7 +86,7 @@ typedef struct { uint8 ipend; /* Interrupt Pending Register */ } CROMFDC_INFO; -extern WD179X_INFO_PUB *wd179x_info; +extern WD179X_INFO_PUB *wd179x_infop; static CROMFDC_INFO cromfdc_info_data = { { 0xC000, CROMFDC_ROM_SIZE, 0x3, 2 } }; static CROMFDC_INFO *cromfdc_info = &cromfdc_info_data; @@ -248,10 +248,6 @@ static MTAB cromfdc_mod[] = { { 0 } }; -#define TRACE_PRINT(level, args) if(cromfdc_dev.dctrl & level) { \ - printf args; \ - } - /* Debug Flags */ static DEBTAB cromfdc_dt[] = { { "ERROR", ERROR_MSG }, @@ -1463,13 +1459,13 @@ static t_stat cromfdc_svc (UNIT *uptr) motor_timeout ++; if(motor_timeout == MOTOR_TO_LIMIT) { cromfdc_info->motor_on = 0; - TRACE_PRINT(DRIVE_MSG, ("CROMFDC: Motor OFF" NLP)) + sim_debug(DRIVE_MSG, &cromfdc_dev, "CROMFDC: Motor OFF\n"); } } cromfdc_info->rtc ++; - TRACE_PRINT(VERBOSE_MSG, ("CROMFDC: " ADDRESS_FORMAT " Timer IRQ" NLP, PCX)); + sim_debug(VERBOSE_MSG, &cromfdc_dev, "CROMFDC: " ADDRESS_FORMAT " Timer IRQ\n", PCX); cromfdc_info->ipend |= CROMFDC_IRQ_TIMER3; /* sim_activate (cromfdc_unit, cromfdc_unit->wait); */ /* requeue! */ @@ -1498,14 +1494,13 @@ static t_stat cromfdc_reset(DEVICE *dptr) } else { /* Connect CROMFDC ROM at base address */ if (cromfdc_hasProperty(UNIT_CROMFDC_ROM)) { - TRACE_PRINT(VERBOSE_MSG, ("CROMFDC: ROM Enabled." NLP)); + sim_debug(VERBOSE_MSG, &cromfdc_dev, "CROMFDC: ROM Enabled.\n"); if(sim_map_resource(pnp->mem_base, pnp->mem_size, RESOURCE_TYPE_MEMORY, &cromfdcrom, FALSE) != 0) { printf("%s: error mapping MEM resource at 0x%04x" NLP, __FUNCTION__, pnp->io_base); return SCPE_ARG; } - } else { - TRACE_PRINT(VERBOSE_MSG, ("CROMFDC: ROM Disabled." NLP)) - } + } else + sim_debug(VERBOSE_MSG, &cromfdc_dev, "CROMFDC: ROM Disabled.\n"); /* Connect CROMFDC Interrupt, and Aux Disk Registers */ if(sim_map_resource(0x03, 0x02, RESOURCE_TYPE_IO, &cromfdc_ext, FALSE) != 0) { printf("%s: error mapping I/O resource at 0x%04x" NLP, __FUNCTION__, pnp->io_base); @@ -1535,7 +1530,7 @@ static t_stat cromfdc_reset(DEVICE *dptr) printf("%s: error mapping I/O resource at 0x%04x" NLP, __FUNCTION__, pnp->io_base); return SCPE_ARG; } else { - TRACE_PRINT(VERBOSE_MSG, ("Mapped CCS2810 UART Status at 0x26" NLP)); + sim_debug(VERBOSE_MSG, &cromfdc_dev, "Mapped CCS2810 UART Status at 0x26\n"); } } @@ -1585,29 +1580,28 @@ static int32 cromfdc_control(const int32 port, const int32 io, const int32 data) if(io) { /* I/O Write */ switch(data & 0x0F) { case 0: - wd179x_info->sel_drive = 0xFF; + wd179x_infop->sel_drive = 0xFF; break; case CROMFDC_CTRL_DS1: - wd179x_info->sel_drive = 0; + wd179x_infop->sel_drive = 0; break; case CROMFDC_CTRL_DS2: - wd179x_info->sel_drive = 1; + wd179x_infop->sel_drive = 1; break; case CROMFDC_CTRL_DS3: - wd179x_info->sel_drive = 2; + wd179x_infop->sel_drive = 2; break; case CROMFDC_CTRL_DS4: - wd179x_info->sel_drive = 3; + wd179x_infop->sel_drive = 3; break; default: - TRACE_PRINT(STATUS_MSG, - ("CROMFDC: " ADDRESS_FORMAT " WR CTRL = 0x%02x: Invalid drive selected." NLP, PCX, data & 0xFF)); + sim_debug(STATUS_MSG, &cromfdc_dev, "CROMFDC: " ADDRESS_FORMAT " WR CTRL = 0x%02x: Invalid drive selected.\n", PCX, data & 0xFF); break; } if(data & CROMFDC_CTRL_MAXI) { - wd179x_info->drivetype = 8; + wd179x_infop->drivetype = 8; } else { - wd179x_info->drivetype = 5; + wd179x_infop->drivetype = 5; } if(data & CROMFDC_CTRL_MTRON) { @@ -1617,13 +1611,12 @@ static int32 cromfdc_control(const int32 port, const int32 io, const int32 data) if(data & CROMFDC_CTRL_DDENS) { if(crofdc_type == 4) { /* 4FDC */ - TRACE_PRINT(DRIVE_MSG, - ("CROMFDC: " ADDRESS_FORMAT " WR CTRL: Cannot set double density on 4FDC" NLP, PCX)); + sim_debug(DRIVE_MSG, &cromfdc_dev, "CROMFDC: " ADDRESS_FORMAT " WR CTRL: Cannot set double density on 4FDC\n", PCX); } else { - wd179x_info->ddens = 1; + wd179x_infop->ddens = 1; } } else { - wd179x_info->ddens = 0; + wd179x_infop->ddens = 0; } if(data & CROMFDC_CTRL_AUTOWAIT) { cromfdc_info->autowait = 1; @@ -1631,13 +1624,11 @@ static int32 cromfdc_control(const int32 port, const int32 io, const int32 data) cromfdc_info->autowait = 0; } - TRACE_PRINT(DRIVE_MSG, - ("CROMFDC: " ADDRESS_FORMAT " WR CTRL: sel_drive=%d, drivetype=%d, motor=%d, dens=%d, aw=%d" NLP, PCX, - wd179x_info->sel_drive, wd179x_info->drivetype, cromfdc_info->motor_on, wd179x_info->ddens, cromfdc_info->autowait)); + sim_debug(DRIVE_MSG, &cromfdc_dev, "CROMFDC: " ADDRESS_FORMAT " WR CTRL: sel_drive=%d, drivetype=%d, motor=%d, dens=%d, aw=%d\n", PCX, wd179x_infop->sel_drive, wd179x_infop->drivetype, cromfdc_info->motor_on, wd179x_infop->ddens, cromfdc_info->autowait); } else { /* I/O Read */ result = (crofdc_boot) ? 0 : CROMFDC_FLAG_BOOT; - result |= (wd179x_info->intrq) ? CROMFDC_FLAG_EOJ : 0; - result |= (wd179x_info->drq) ? CROMFDC_FLAG_DRQ : 0; + result |= (wd179x_infop->intrq) ? CROMFDC_FLAG_EOJ : 0; + result |= (wd179x_infop->drq) ? CROMFDC_FLAG_DRQ : 0; if(crofdc_type != 50) { /* Cromemco Controller */ result |= (motor_timeout < MOTOR_TO_LIMIT) ? CROMFDC_FLAG_SEL_REQ : 0; if(crofdc_type > 4) { /* 16, 64FDC */ @@ -1648,7 +1639,7 @@ static int32 cromfdc_control(const int32 port, const int32 io, const int32 data) result |= 0x1E; /* Make unused bits '1' on 4FDC */ } } else { /* CCS 2422 Controller */ - switch(wd179x_info->sel_drive) { + switch(wd179x_infop->sel_drive) { case 1: result |= 0x02; break; @@ -1665,8 +1656,8 @@ static int32 cromfdc_control(const int32 port, const int32 io, const int32 data) /* printf("CCS2422FDC: " ADDRESS_FORMAT " Read STATUS1=0x%02x" NLP, PCX, result); */ } - TRACE_PRINT(STATUS_MSG, - ("CROMFDC: " ADDRESS_FORMAT " Read DISK FLAGS, Port 0x%02x Result 0x%02x" NLP, PCX, port, result)) + sim_debug(STATUS_MSG, &cromfdc_dev, "CROMFDC: " ADDRESS_FORMAT + " Read DISK FLAGS, Port 0x%02x Result 0x%02x\n", PCX, port, result); } return result; @@ -1684,13 +1675,12 @@ static int32 cromfdc_ext(const int32 port, const int32 io, const int32 data) if(crofdc_type != 50) { /* Cromemco Controller */ if((data & CROMFDC_AUX_CMD_SIDE) == 0) { if(crofdc_type == 4) { /* 4FDC */ - TRACE_PRINT(DRIVE_MSG, - ("CROMFDC: " ADDRESS_FORMAT " WR CTRL: Cannot set side 1 on 4FDC" NLP, PCX)); + sim_debug(DRIVE_MSG, &cromfdc_dev, "CROMFDC: " ADDRESS_FORMAT " WR CTRL: Cannot set side 1 on 4FDC\n", PCX); } else { - wd179x_info->fdc_head = 1; + wd179x_infop->fdc_head = 1; } } else { - wd179x_info->fdc_head = 0; + wd179x_infop->fdc_head = 0; } #if 0 /* hharte - nothing implemented for these */ if((data & CROMFDC_AUX_EJECT) == 0) { @@ -1710,21 +1700,20 @@ static int32 cromfdc_ext(const int32 port, const int32 io, const int32 data) } } else { /* CCS 2422 Controller */ if((data & CCSFDC_CMD_SIDE) == 0) { - wd179x_info->fdc_head = 1; + wd179x_infop->fdc_head = 1; } else { - wd179x_info->fdc_head = 0; + wd179x_infop->fdc_head = 0; } } } else if (port == 0x3) { /* Interrupt Address */ - TRACE_PRINT(IRQ_MSG, - ("CROMFDC: " ADDRESS_FORMAT " IRQ Mask=0x%02x" NLP, PCX, data)); + sim_debug(IRQ_MSG, &cromfdc_dev, "CROMFDC: " ADDRESS_FORMAT " IRQ Mask=0x%02x\n", PCX, data); cromfdc_info->imask = data; } else { } - TRACE_PRINT(DRIVE_MSG, - ("CROMFDC: " ADDRESS_FORMAT " AUX OUT, Port 0x%02x Data 0x%02x" NLP, PCX, port, data)) + sim_debug(DRIVE_MSG, &cromfdc_dev, "CROMFDC: " ADDRESS_FORMAT + " AUX OUT, Port 0x%02x Data 0x%02x\n", PCX, port, data); result = 0; } else { /* I/O Read */ if(port == 0x4) { @@ -1732,20 +1721,18 @@ static int32 cromfdc_ext(const int32 port, const int32 io, const int32 data) result |= 0x00; /* Bit 6 is Seek in Progress for Persci drives. */ result |= (cromfdc_info->rtc & 1) ? 0x80 : 0; if(crofdc_type == 50) { - TRACE_PRINT(STATUS_MSG, - ("CCS2422FDC: " ADDRESS_FORMAT " Read STATUS2=0x%02x" NLP, PCX, result)); + sim_debug(STATUS_MSG, &cromfdc_dev, "CCS2422FDC: " ADDRESS_FORMAT " Read STATUS2=0x%02x\n", PCX, result); } } else if (port == 0x3) { /* Interrupt Address */ result = ipend_to_rst_opcode(cromfdc_info->ipend); if(result != 0) { - TRACE_PRINT(IRQ_MSG, - ("CROMFDC: " ADDRESS_FORMAT " RST Opcode=%x, Vector=%04x" NLP, PCX, result, RST_OPCODE_TO_VECTOR(result))); + sim_debug(IRQ_MSG, &cromfdc_dev, "CROMFDC: " ADDRESS_FORMAT " RST Opcode=%x, Vector=%04x\n", PCX, result, RST_OPCODE_TO_VECTOR(result)); } } else { result = 0xFF; } - TRACE_PRINT(STATUS_MSG, - ("CROMFDC: " ADDRESS_FORMAT " AUX IN, Port 0x%02x Result 0x%02x" NLP, PCX, port, result)) + sim_debug(STATUS_MSG, &cromfdc_dev, "CROMFDC: " ADDRESS_FORMAT + " AUX IN, Port 0x%02x Result 0x%02x\n", PCX, port, result); } return result; } @@ -1755,14 +1742,14 @@ static int32 cromfdc_timer(const int32 port, const int32 io, const int32 data) { static int32 result = 0; if(io) { - TRACE_PRINT(VERBOSE_MSG, - ("CROMFDC: " ADDRESS_FORMAT " TIMER%d OUT, Port 0x%02x Data 0x%02x" NLP, PCX, (port-4), port, data)) + sim_debug(VERBOSE_MSG, &cromfdc_dev, "CROMFDC: " ADDRESS_FORMAT + " TIMER%d OUT, Port 0x%02x Data 0x%02x\n", PCX, (port-4), port, data); result = 0; sim_activate(cromfdc_unit, (CROMFDC_SIM_64US * data)); } else { result++; - TRACE_PRINT(VERBOSE_MSG, - ("CROMFDC: " ADDRESS_FORMAT " TIMER%d IN, Port 0x%02x Result 0x%02x" NLP, PCX, (port-4), port, result)) + sim_debug(VERBOSE_MSG, &cromfdc_dev, "CROMFDC: " ADDRESS_FORMAT + " TIMER%d IN, Port 0x%02x Result 0x%02x\n", PCX, (port-4), port, result); } return result; } @@ -1772,15 +1759,15 @@ static int32 cromfdc_banksel(const int32 port, const int32 io, const int32 data) { int32 result; if(io) { - TRACE_PRINT(VERBOSE_MSG, - ("CROMFDC: " ADDRESS_FORMAT " BANKSEL OUT, Port 0x%02x Data 0x%02x" NLP, PCX, port, data)) + sim_debug(VERBOSE_MSG, &cromfdc_dev, "CROMFDC: " ADDRESS_FORMAT + " BANKSEL OUT, Port 0x%02x Data 0x%02x\n", PCX, port, data); /* Unmap Boot ROM */ cromfdc_info->rom_disabled = TRUE; result = 0; } else { result = 0xFF; - TRACE_PRINT(VERBOSE_MSG, - ("CROMFDC: " ADDRESS_FORMAT " BANKSEL IN, Port 0x%02x Result 0x%02x" NLP, PCX, port, result)) + sim_debug(VERBOSE_MSG, &cromfdc_dev, "CROMFDC: " ADDRESS_FORMAT + " BANKSEL IN, Port 0x%02x Result 0x%02x\n", PCX, port, result); } return result; } diff --git a/AltairZ80/s100_adcs6.c b/AltairZ80/s100_adcs6.c index 7c6b14bd..353b92e6 100644 --- a/AltairZ80/s100_adcs6.c +++ b/AltairZ80/s100_adcs6.c @@ -88,7 +88,7 @@ typedef struct { uint8 s100_addr_u; /* A23:16 of S-100 bus */ } ADCS6_INFO; -extern WD179X_INFO_PUB *wd179x_info; +extern WD179X_INFO_PUB *wd179x_infop; static ADCS6_INFO adcs6_info_data = { { 0xF000, ADCS6_ROM_SIZE, 0x3, 2 } }; static ADCS6_INFO *adcs6_info = &adcs6_info_data; @@ -207,10 +207,6 @@ static MTAB adcs6_mod[] = { { 0 } }; -#define TRACE_PRINT(level, args) if(adcs6_dev.dctrl & level) { \ - printf args; \ - } - /* Debug Flags */ static DEBTAB adcs6_dt[] = { { "ERROR", ERROR_MSG }, @@ -398,7 +394,7 @@ static t_stat adcs6_svc (UNIT *uptr) motor_timeout ++; if(motor_timeout == MOTOR_TO_LIMIT) { adcs6_info->head_sel = 0; - TRACE_PRINT(DRIVE_MSG, ("ADCS6: Motor OFF" NLP)) + sim_debug(DRIVE_MSG, &adcs6_dev, "ADCS6: Motor OFF\n"); } } @@ -430,14 +426,14 @@ static t_stat adcs6_reset(DEVICE *dptr) } else { /* Connect ADCS6 ROM at base address */ if (adcs6_hasProperty(UNIT_ADCS6_ROM)) { - TRACE_PRINT(VERBOSE_MSG, ("ADCS6: ROM Enabled." NLP)) + sim_debug(VERBOSE_MSG, &adcs6_dev, "ADCS6: ROM Enabled.\n"); if(sim_map_resource(pnp->mem_base, pnp->mem_size, RESOURCE_TYPE_MEMORY, &adcs6rom, FALSE) != 0) { printf("%s: error mapping MEM resource at 0x%04x\n", __FUNCTION__, pnp->io_base); return SCPE_ARG; } adcs6_info->rom_disabled = FALSE; } else { - TRACE_PRINT(VERBOSE_MSG, ("ADCS6: ROM Disabled." NLP)) + sim_debug(VERBOSE_MSG, &adcs6_dev, "ADCS6: ROM Disabled.\n"); adcs6_info->rom_disabled = TRUE; } @@ -508,8 +504,8 @@ static int32 adcs6rom(const int32 Addr, const int32 write, const int32 data) /* DBG_PRINT(("ADCS6: ROM %s, Addr %04x" NLP, write ? "WR" : "RD", Addr)); */ if(write) { if(adcs6_info->rom_disabled == FALSE) { - TRACE_PRINT(ERROR_MSG, - ("ADCS6: " ADDRESS_FORMAT " Cannot write to ROM." NLP, PCX)); + sim_debug(ERROR_MSG, &adcs6_dev, "ADCS6: " ADDRESS_FORMAT + " Cannot write to ROM.\n", PCX); } else { adcs6ram[Addr & ADCS6_ADDR_MASK] = data; } @@ -528,26 +524,26 @@ static int32 adcs6_control(const int32 port, const int32 io, const int32 data) { int32 result = 0; if(io) { /* I/O Write */ - wd179x_info->sel_drive = data & 0x03; + wd179x_infop->sel_drive = data & 0x03; if(data & ADCS6_CTRL_MINI) { - wd179x_info->drivetype = 5; + wd179x_infop->drivetype = 5; } else { - wd179x_info->drivetype = 8; + wd179x_infop->drivetype = 8; } if(data & ADCS6_CTRL_HDS) { adcs6_info->head_sel = 1; - wd179x_info->fdc_head = 1; + wd179x_infop->fdc_head = 1; } else { adcs6_info->head_sel = 0; - wd179x_info->fdc_head = 0; + wd179x_infop->fdc_head = 0; } if(data & ADCS6_CTRL_DDENS) { - wd179x_info->ddens = 1; + wd179x_infop->ddens = 1; } else { - wd179x_info->ddens = 0; + wd179x_infop->ddens = 0; } if(data & ADCS6_CTRL_AUTOWAIT) { adcs6_info->autowait = 1; @@ -555,16 +551,15 @@ static int32 adcs6_control(const int32 port, const int32 io, const int32 data) adcs6_info->autowait = 0; } - TRACE_PRINT(DRIVE_MSG, - ("ADCS6: " ADDRESS_FORMAT " WR CTRL: sel_drive=%d, drivetype=%d, head_sel=%d, dens=%d, aw=%d" NLP, PCX, - wd179x_info->sel_drive, wd179x_info->drivetype, adcs6_info->head_sel, wd179x_info->ddens, adcs6_info->autowait)); + sim_debug(DRIVE_MSG, &adcs6_dev, "ADCS6: " ADDRESS_FORMAT + " WR CTRL: sel_drive=%d, drivetype=%d, head_sel=%d, dens=%d, aw=%d\n", + PCX, wd179x_infop->sel_drive, + wd179x_infop->drivetype, adcs6_info->head_sel, + wd179x_infop->ddens, adcs6_info->autowait); } else { /* I/O Read */ - result = wd179x_info->drq ? 0xFF : 0; - if (wd179x_info->intrq) + result = wd179x_infop->drq ? 0xFF : 0; + if (wd179x_infop->intrq) result &= 0x7F; - -/* TRACE_PRINT(VERBOSE_MSG, */ -/* ("ADCS6: " ADDRESS_FORMAT " Read DISK FLAGS, Port 0x%02x Result 0x%02x" NLP, PCX, port, result)) */ } return result; @@ -575,12 +570,12 @@ static int32 adcs6_dma(const int32 port, const int32 io, const int32 data) { int32 result = 0xff; if(io) { /* I/O Write */ - TRACE_PRINT(DMA_MSG, - ("ADCS6: " ADDRESS_FORMAT " WR DMA: 0x%02x" NLP, PCX, data & 0xFF)); + sim_debug(DMA_MSG, &adcs6_dev, "ADCS6: " ADDRESS_FORMAT + " WR DMA: 0x%02x\n", PCX, data & 0xFF); } else { /* I/O Read */ result = 0xFF; - TRACE_PRINT(DMA_MSG, - ("ADCS6: " ADDRESS_FORMAT " RD DMA: 0x%02x" NLP, PCX, result)); + sim_debug(DMA_MSG, &adcs6_dev, "ADCS6: " ADDRESS_FORMAT + " RD DMA: 0x%02x\n", PCX, result); } return result; } @@ -592,62 +587,62 @@ static int32 adcs6_timer(const int32 port, const int32 io, const int32 data) if(io) { /* Write */ switch(port) { case 0x04: - TRACE_PRINT(VERBOSE_MSG, - ("ADCS6: " ADDRESS_FORMAT " WR PIOA DATA=0x%02x" NLP, PCX, data)); + sim_debug(VERBOSE_MSG, &adcs6_dev, "ADCS6: " ADDRESS_FORMAT + " WR PIOA DATA=0x%02x\n", PCX, data); break; case 0x05: - TRACE_PRINT(VERBOSE_MSG, - ("ADCS6: " ADDRESS_FORMAT " WR PIOB DATA=0x%02x" NLP, PCX, data)); + sim_debug(VERBOSE_MSG, &adcs6_dev, "ADCS6: " ADDRESS_FORMAT + " WR PIOB DATA=0x%02x\n", PCX, data); break; case 0x06: - TRACE_PRINT(VERBOSE_MSG, - ("ADCS6: " ADDRESS_FORMAT " WR PIOA CTRL=0x%02x" NLP, PCX, data)); + sim_debug(VERBOSE_MSG, &adcs6_dev, "ADCS6: " ADDRESS_FORMAT + " WR PIOA CTRL=0x%02x\n", PCX, data); break; case 0x07: - TRACE_PRINT(VERBOSE_MSG, - ("ADCS6: " ADDRESS_FORMAT " WR PIOB CTRL=0x%02x" NLP, PCX, data)); + sim_debug(VERBOSE_MSG, &adcs6_dev, "ADCS6: " ADDRESS_FORMAT + " WR PIOB CTRL=0x%02x\n", PCX, data); break; case 0x08: case 0x09: case 0x0A: case 0x0B: - TRACE_PRINT(VERBOSE_MSG, - ("ADCS6: " ADDRESS_FORMAT " WR CTC%d: 0x%02x" NLP, PCX, port - 8, data)); + sim_debug(VERBOSE_MSG, &adcs6_dev, "ADCS6: " ADDRESS_FORMAT + " WR CTC%d: 0x%02x\n", PCX, port - 8, data); break; default: - TRACE_PRINT(ERROR_MSG, - ("ADCS6: " ADDRESS_FORMAT " WR Unhandled Port: 0x%02x=0x%02x" NLP, PCX, port, data)); + sim_debug(ERROR_MSG, &adcs6_dev, "ADCS6: " ADDRESS_FORMAT + " WR Unhandled Port: 0x%02x=0x%02x\n", PCX, port, data); break; } } else { /* Read */ result = 0xFF; switch(port) { case 0x04: - TRACE_PRINT(VERBOSE_MSG, - ("ADCS6: " ADDRESS_FORMAT " RD PIOA DATA=0x%02x" NLP, PCX, result)); + sim_debug(VERBOSE_MSG, &adcs6_dev, "ADCS6: " ADDRESS_FORMAT + " RD PIOA DATA=0x%02x\n", PCX, result); break; case 0x05: - TRACE_PRINT(VERBOSE_MSG, - ("ADCS6: " ADDRESS_FORMAT " RD PIOB DATA=0x%02x" NLP, PCX, result)); + sim_debug(VERBOSE_MSG, &adcs6_dev, "ADCS6: " ADDRESS_FORMAT + " RD PIOB DATA=0x%02x\n", PCX, result); break; case 0x06: - TRACE_PRINT(VERBOSE_MSG, - ("ADCS6: " ADDRESS_FORMAT " RD PIOA CTRL=0x%02x" NLP, PCX, result)); + sim_debug(VERBOSE_MSG, &adcs6_dev, "ADCS6: " ADDRESS_FORMAT + " RD PIOA CTRL=0x%02x\n", PCX, result); break; case 0x07: - TRACE_PRINT(VERBOSE_MSG, - ("ADCS6: " ADDRESS_FORMAT " RD PIOB CTRL=0x%02x" NLP, PCX, result)); + sim_debug(VERBOSE_MSG, &adcs6_dev, "ADCS6: " ADDRESS_FORMAT + " RD PIOB CTRL=0x%02x\n", PCX, result); break; case 0x08: case 0x09: case 0x0A: case 0x0B: - TRACE_PRINT(VERBOSE_MSG, - ("ADCS6: " ADDRESS_FORMAT " RD CTC%d: 0x%02x" NLP, PCX, port - 8, data)); + sim_debug(VERBOSE_MSG, &adcs6_dev, "ADCS6: " ADDRESS_FORMAT + " RD CTC%d: 0x%02x\n", PCX, port - 8, data); break; default: - TRACE_PRINT(ERROR_MSG, - ("ADCS6: " ADDRESS_FORMAT " RD Unhandled Port: 0x%02x=0x%02x" NLP, PCX, port, data)); + sim_debug(ERROR_MSG, &adcs6_dev, "ADCS6: " ADDRESS_FORMAT + " RD Unhandled Port: 0x%02x=0x%02x\n", PCX, port, data); break; } } @@ -662,28 +657,28 @@ static int32 adcs6_banksel(const int32 port, const int32 io, const int32 data) switch(port) { case 0x15: adcs6_info->s100_addr_u = data & 0xFF; - TRACE_PRINT(VERBOSE_MSG, - ("ADCS6: " ADDRESS_FORMAT " WR S100 A[23:16]=0x%02x" NLP, PCX, data)); + sim_debug(VERBOSE_MSG, &adcs6_dev, "ADCS6: " ADDRESS_FORMAT + " WR S100 A[23:16]=0x%02x\n", PCX, data); break; case 0x16: - TRACE_PRINT(VERBOSE_MSG, - ("ADCS6: " ADDRESS_FORMAT " WR MCTRL0: 0x%02x" NLP, PCX, data)); + sim_debug(VERBOSE_MSG, &adcs6_dev, "ADCS6: " ADDRESS_FORMAT + " WR MCTRL0: 0x%02x\n", PCX, data); adcs6_info->rom_disabled = (data & 0x20) ? TRUE : FALSE; /* Unmap Boot ROM */ break; case 0x17: - TRACE_PRINT(VERBOSE_MSG, - ("ADCS6: " ADDRESS_FORMAT " WR MCTRL1: 0x%02x" NLP, PCX, data)); + sim_debug(VERBOSE_MSG, &adcs6_dev, "ADCS6: " ADDRESS_FORMAT + " WR MCTRL1: 0x%02x\n", PCX, data); break; case 0x18: case 0x19: case 0x1A: case 0x1B: - TRACE_PRINT(VERBOSE_MSG, - ("ADCS6: " ADDRESS_FORMAT " WR BAUD RATE=0x%02x" NLP, PCX, data)); + sim_debug(VERBOSE_MSG, &adcs6_dev, "ADCS6: " ADDRESS_FORMAT + " WR BAUD RATE=0x%02x\n", PCX, data); break; default: - TRACE_PRINT(ERROR_MSG, - ("ADCS6: " ADDRESS_FORMAT " WR Unhandled Port: 0x%02x=0x%02x" NLP, PCX, port, data)); + sim_debug(ERROR_MSG, &adcs6_dev, "ADCS6: " ADDRESS_FORMAT + " WR Unhandled Port: 0x%02x=0x%02x\n", PCX, port, data); break; } result = 0; @@ -697,8 +692,8 @@ static int32 adcs6_banksel(const int32 port, const int32 io, const int32 data) * Bit 5:0 = "Baud Rate" */ result = dipswitch; - TRACE_PRINT(VERBOSE_MSG, - ("ADCS6: " ADDRESS_FORMAT " RD BAUD RATE=0x%02x" NLP, PCX, result)); + sim_debug(VERBOSE_MSG, &adcs6_dev, "ADCS6: " ADDRESS_FORMAT + " RD BAUD RATE=0x%02x\n", PCX, result); break; case 0x16: case 0x17: @@ -707,8 +702,8 @@ static int32 adcs6_banksel(const int32 port, const int32 io, const int32 data) case 0x1A: case 0x1B: default: - TRACE_PRINT(ERROR_MSG, - ("ADCS6: " ADDRESS_FORMAT " RD attempt from write-only 0x%02x=0x%02x" NLP, PCX, port, result)); + sim_debug(ERROR_MSG, &adcs6_dev, "ADCS6: " ADDRESS_FORMAT + " RD attempt from write-only 0x%02x=0x%02x\n", PCX, port, result); break; } } diff --git a/AltairZ80/s100_disk1a.c b/AltairZ80/s100_disk1a.c index 814d910c..5a71aa94 100644 --- a/AltairZ80/s100_disk1a.c +++ b/AltairZ80/s100_disk1a.c @@ -145,10 +145,6 @@ static MTAB disk1a_mod[] = { { 0 } }; -#define TRACE_PRINT(level, args) if(disk1a_dev.dctrl & level) { \ - printf args; \ - } - /* Debug Flags */ static DEBTAB disk1a_dt[] = { { "ERROR", ERROR_MSG }, @@ -805,14 +801,13 @@ static int32 disk1adev(const int32 port, const int32 io, const int32 data) { int32 result; if(io) { - TRACE_PRINT(VERBOSE_MSG, - ("DISK1A: " ADDRESS_FORMAT " OUT, Port 0x%02x Data 0x%02x" NLP, PCX, port, data)) + sim_debug(VERBOSE_MSG, &disk1a_dev, "DISK1A: " ADDRESS_FORMAT + " OUT, Port 0x%02x Data 0x%02x\n", PCX, port, data); DISK1A_Write(port, data); result = 0; } else { result = DISK1A_Read(port); - TRACE_PRINT(VERBOSE_MSG, - ("DISK1A: " ADDRESS_FORMAT " IN, Port 0x%02x Result 0x%02x" NLP, PCX, port, result)) + sim_debug(VERBOSE_MSG, &disk1a_dev, "DISK1A: " ADDRESS_FORMAT " IN, Port 0x%02x Result 0x%02x\n", PCX, port, result); } return result; } @@ -835,12 +830,10 @@ static uint8 DISK1A_Read(const uint32 Addr) break; case DISK1A_DRIVE_STATUS: cData = i8272_irq ? 0x81 : 0x01; /* Ready */ - TRACE_PRINT(STATUS_MSG, - ("DISK1A: " ADDRESS_FORMAT " RD STATUS = 0x%02x" NLP, PCX, cData)) + sim_debug(STATUS_MSG, &disk1a_dev, "DISK1A: " ADDRESS_FORMAT " RD STATUS = 0x%02x\n", PCX, cData); break; case DISK1A_MOTOR: - TRACE_PRINT(VERBOSE_MSG, - ("DISK1A: " ADDRESS_FORMAT " Error, can't read from MOTOR register." NLP, PCX)) + sim_debug(VERBOSE_MSG, &disk1a_dev, "DISK1A: " ADDRESS_FORMAT " Error, can't read from MOTOR register.\n", PCX); cData = 0xFF; /* Return High-Z data */ break; } @@ -862,24 +855,24 @@ static uint8 DISK1A_Write(const uint32 Addr, uint8 cData) disk1a_info->dma_addr <<= 8; disk1a_info->dma_addr &= 0x00FFFF00; disk1a_info->dma_addr |= cData; - TRACE_PRINT(RD_DATA_MSG, ("DISK1A: " ADDRESS_FORMAT " DMA Address=%06x" NLP, - PCX, disk1a_info->dma_addr)) + sim_debug(RD_DATA_MSG, &disk1a_dev, "DISK1A: " ADDRESS_FORMAT + " DMA Address=%06x\n", PCX, disk1a_info->dma_addr); I8272_Set_DMA(disk1a_info->dma_addr); break; case DISK1A_MOTOR: - TRACE_PRINT(CMD_MSG, - ("DISK1A: " ADDRESS_FORMAT " write Motor Reg=0x%02x" NLP, PCX, cData)) + sim_debug(CMD_MSG, &disk1a_dev, "DISK1A: " ADDRESS_FORMAT + " write Motor Reg=0x%02x\n", PCX, cData); if((cData & BOOT_PROM_DISABLE) == 0) { - TRACE_PRINT(CMD_MSG, - ("DISK1A: " ADDRESS_FORMAT " Boot ROM disabled" NLP, PCX)) + sim_debug(CMD_MSG, &disk1a_dev, "DISK1A: " ADDRESS_FORMAT + " Boot ROM disabled\n", PCX); /* Unmap Boot ROM */ disk1a_info->rom_disabled = TRUE; } - TRACE_PRINT(CMD_MSG, ("DISK1A: " ADDRESS_FORMAT " Motors = %x" NLP, - PCX, (cData & FLOPPY_MOTORS) >> 4)) + sim_debug(CMD_MSG, &disk1a_dev, "DISK1A: " ADDRESS_FORMAT + " Motors = %x\n", PCX, (cData & FLOPPY_MOTORS) >> 4); break; } @@ -890,7 +883,7 @@ static uint8 DISK1A_Write(const uint32 Addr, uint8 cData) void raise_disk1a_interrupt(void) { - TRACE_PRINT(IRQ_MSG, ("DISK1A: " ADDRESS_FORMAT " Interrupt" NLP, PCX)); + sim_debug(IRQ_MSG, &disk1a_dev, "DISK1A: " ADDRESS_FORMAT " Interrupt\n", PCX); raise_ss1_interrupt(SS1_VI4_INT); diff --git a/AltairZ80/s100_disk2.c b/AltairZ80/s100_disk2.c index 1af9a918..597294df 100644 --- a/AltairZ80/s100_disk2.c +++ b/AltairZ80/s100_disk2.c @@ -174,10 +174,6 @@ static MTAB disk2_mod[] = { { 0 } }; -#define TRACE_PRINT(level, args) if(disk2_dev.dctrl & level) { \ - printf args; \ - } - /* Debug Flags */ static DEBTAB disk2_dt[] = { { "ERROR", ERROR_MSG }, @@ -313,7 +309,7 @@ t_stat disk2_detach(UNIT *uptr) static int32 disk2dev(const int32 port, const int32 io, const int32 data) { -/* TRACE_PRINT(VERBOSE_MSG, ("DISK2: " ADDRESS_FORMAT " IO %s, Port %02x" NLP, PCX, io ? "WR" : "RD", port)); */ +/* sim_debug(VERBOSE_MSG, &disk2_dev, "DISK2: " ADDRESS_FORMAT " IO %s, Port %02x\n", PCX, io ? "WR" : "RD", port); */ if(io) { DISK2_Write(port, data); return 0; @@ -343,7 +339,8 @@ static uint8 DISK2_Read(const uint32 Addr) cData |= (disk2_info->seek_complete == 0) ? 0x04 : 0x00; cData |= (disk2_info->write_fault) << 1; cData |= ((pDrive->track != 0) || (disk2_info->seek_complete == 0)) ? 0x01 : 0x00; - TRACE_PRINT(STATUS_MSG, ("DISK2: " ADDRESS_FORMAT " RD STATUS = 0x%02x" NLP, PCX, cData)); + sim_debug(STATUS_MSG, &disk2_dev, "DISK2: " ADDRESS_FORMAT + " RD STATUS = 0x%02x\n", PCX, cData); disk2_info->seek_complete = 1; break; @@ -357,8 +354,9 @@ static uint8 DISK2_Read(const uint32 Addr) pDrive->track --; } } - TRACE_PRINT(SEEK_MSG, ("DISK2: " ADDRESS_FORMAT " Step %s, Track=%d" NLP, - PCX, disk2_info->ctl_op & 0x04 ? "IN" : "OUT", pDrive->track)); + sim_debug(SEEK_MSG, &disk2_dev, "DISK2: " ADDRESS_FORMAT + " Step %s, Track=%d\n", PCX, + disk2_info->ctl_op & 0x04 ? "IN" : "OUT", pDrive->track); disk2_info->seek_complete = 0; cData = 0xFF; /* Return High-Z data */ break; @@ -399,13 +397,11 @@ static uint8 DISK2_Write(const uint32 Addr, uint8 cData) disk2_info->timeout = 0; } disk2_info->ctl_us = (cData & 0x03); - TRACE_PRINT(VERBOSE_MSG, ("DISK2: " ADDRESS_FORMAT " ATTN*=%d, RUN=%d, OP=%d, FAULT_CLR=%d, US=%d" NLP, - PCX, - disk2_info->ctl_attn, - disk2_info->ctl_run, - disk2_info->ctl_op, - disk2_info->ctl_fault_clr, - disk2_info->ctl_us)); + sim_debug(VERBOSE_MSG, &disk2_dev, "DISK2: " ADDRESS_FORMAT + " ATTN*=%d, RUN=%d, OP=%d, FAULT_CLR=%d, US=%d\n", + PCX, disk2_info->ctl_attn, disk2_info->ctl_run, + disk2_info->ctl_op, disk2_info->ctl_fault_clr, + disk2_info->ctl_us); /* FIXME: seek_complete = 1 is needed by CP/M, but why? Also, maybe related, * there appears to be a bug in the seeking logic. For some reason, the @@ -428,21 +424,20 @@ static uint8 DISK2_Write(const uint32 Addr, uint8 cData) switch(disk2_info->ctl_op) { case DISK2_CMD_NULL: - TRACE_PRINT(CMD_MSG, ("DISK2: " ADDRESS_FORMAT " NULL Command" NLP, PCX)); + sim_debug(CMD_MSG, &disk2_dev, "DISK2: " ADDRESS_FORMAT + " NULL Command\n", PCX); break; case DISK2_CMD_READ_DATA: - TRACE_PRINT(RD_DATA_MSG, ("DISK2: " ADDRESS_FORMAT " READ_DATA: (C:%d/H:%d/S:%d)" NLP, - PCX, - disk2_info->cyl, - disk2_info->head, - disk2_info->sector)); + sim_debug(RD_DATA_MSG, &disk2_dev, "DISK2: " ADDRESS_FORMAT + " READ_DATA: (C:%d/H:%d/S:%d)\n", PCX, disk2_info->cyl, disk2_info->head, disk2_info->sector); if(disk2_info->head_sel != disk2_info->head) { - printf("DISK2: " ADDRESS_FORMAT " READ_DATA: head_sel != head" NLP, PCX); + printf("DISK2: " ADDRESS_FORMAT + " READ_DATA: head_sel != head" NLP, PCX); } /* See FIXME above... that might be why this does not work properly... */ if(disk2_info->cyl != pDrive->track) { /* problem, should not happen, see above */ - TRACE_PRINT(ERROR_MSG, ("DISK2: " ADDRESS_FORMAT " READ_DATA: cyl=%d, track=%d" NLP, - PCX, disk2_info->cyl, pDrive->track)); + sim_debug(ERROR_MSG, &disk2_dev, "DISK2: " ADDRESS_FORMAT + " READ_DATA: cyl=%d, track=%d\n", PCX, disk2_info->cyl, pDrive->track); pDrive->track = disk2_info->cyl; /* update track */ } sim_fseek((pDrive->uptr)->fileref, track_offset + (disk2_info->head_sel * pDrive->nsectors * (pDrive->sectsize + 3)), SEEK_SET); @@ -450,15 +445,18 @@ static uint8 DISK2_Write(const uint32 Addr, uint8 cData) /* Read sector */ rtn = sim_fread(sdata.raw, 1, (pDrive->sectsize + 3), (pDrive->uptr)->fileref); if (rtn != (size_t)(pDrive->sectsize + 3)) { - TRACE_PRINT(ERROR_MSG, ("DISK2: " ADDRESS_FORMAT " READ_DATA: sim_fread error." NLP, PCX)); + sim_debug(ERROR_MSG, &disk2_dev, "DISK2: " ADDRESS_FORMAT + " READ_DATA: sim_fread error.\n", PCX); } if(sdata.u.header[2] == disk2_info->sector) { if(sdata.u.header[0] != disk2_info->cyl) { /*pDrive->track) { */ - printf("DISK2: " ADDRESS_FORMAT " READ_DATA Incorrect header: track" NLP, PCX); + printf("DISK2: " ADDRESS_FORMAT + " READ_DATA Incorrect header: track" NLP, PCX); disk2_info->timeout = 1; } if(sdata.u.header[1] != disk2_info->head) { - printf("DISK2: " ADDRESS_FORMAT " READ_DATA Incorrect header: head" NLP, PCX); + printf("DISK2: " ADDRESS_FORMAT + " READ_DATA Incorrect header: head" NLP, PCX); disk2_info->timeout = 1; } @@ -466,24 +464,22 @@ static uint8 DISK2_Write(const uint32 Addr, uint8 cData) break; } if(i == pDrive->nsectors) { - printf("DISK2: " ADDRESS_FORMAT " Sector not found" NLP, PCX); + printf("DISK2: " ADDRESS_FORMAT + " Sector not found" NLP, PCX); disk2_info->timeout = 1; } } break; case DISK2_CMD_WRITE_DATA: - TRACE_PRINT(WR_DATA_MSG, ("DISK2: " ADDRESS_FORMAT " WRITE_DATA: (C:%d/H:%d/S:%d)" NLP, - PCX, - disk2_info->cyl, - disk2_info->head, - disk2_info->sector)); + sim_debug(WR_DATA_MSG, &disk2_dev, "DISK2: " ADDRESS_FORMAT + " WRITE_DATA: (C:%d/H:%d/S:%d)\n", PCX, disk2_info->cyl, disk2_info->head, disk2_info->sector); if(disk2_info->head_sel != disk2_info->head) { printf("DISK2: " ADDRESS_FORMAT " WRITE_DATA: head_sel != head" NLP, PCX); } if(disk2_info->cyl != pDrive->track) { /* problem, should not happen, see above */ - TRACE_PRINT(ERROR_MSG, ("DISK2: " ADDRESS_FORMAT " WRITE_DATA = 0x%02x, cyl=%d, track=%d" NLP, - PCX, cData, disk2_info->cyl, pDrive->track)); + sim_debug(ERROR_MSG, &disk2_dev, "DISK2: " ADDRESS_FORMAT + " WRITE_DATA = 0x%02x, cyl=%d, track=%d\n", PCX, cData, disk2_info->cyl, pDrive->track); pDrive->track = disk2_info->cyl; /* update track */ } @@ -493,15 +489,18 @@ static uint8 DISK2_Write(const uint32 Addr, uint8 cData) file_offset = ftell((pDrive->uptr)->fileref); rtn = sim_fread(sdata.raw, 1, 3, (pDrive->uptr)->fileref); if (rtn != 3) { - TRACE_PRINT(ERROR_MSG, ("DISK2: " ADDRESS_FORMAT " WRITE_DATA: sim_fread error." NLP, PCX)); + sim_debug(ERROR_MSG, &disk2_dev, "DISK2: " ADDRESS_FORMAT + " WRITE_DATA: sim_fread error.\n", PCX); } if(sdata.u.header[2] == disk2_info->sector) { if(sdata.u.header[0] != disk2_info->cyl) { - printf("DISK2: " ADDRESS_FORMAT " WRITE_DATA Incorrect header: track" NLP, PCX); + printf("DISK2: " ADDRESS_FORMAT + " WRITE_DATA Incorrect header: track" NLP, PCX); disk2_info->timeout = 1; } if(sdata.u.header[1] != disk2_info->head) { - printf("DISK2: " ADDRESS_FORMAT " WRITE_DATA Incorrect header: head" NLP, PCX); + printf("DISK2: " ADDRESS_FORMAT + " WRITE_DATA Incorrect header: head" NLP, PCX); disk2_info->timeout = 1; } @@ -512,7 +511,8 @@ static uint8 DISK2_Write(const uint32 Addr, uint8 cData) } rtn = sim_fread(sdata.raw, 1, pDrive->sectsize, (pDrive->uptr)->fileref); if (rtn != (size_t)(pDrive->sectsize)) { - TRACE_PRINT(ERROR_MSG, ("DISK2: " ADDRESS_FORMAT " WRITE_DATA: sim_fread error." NLP, PCX)); + sim_debug(ERROR_MSG, &disk2_dev, "DISK2: " ADDRESS_FORMAT + " WRITE_DATA: sim_fread error.\n", PCX); } if(i == pDrive->nsectors) { printf("DISK2: " ADDRESS_FORMAT " Sector not found" NLP, PCX); @@ -522,12 +522,10 @@ static uint8 DISK2_Write(const uint32 Addr, uint8 cData) break; case DISK2_CMD_WRITE_HEADER: track_offset = pDrive->track * pDrive->nheads * pDrive->nsectors * (pDrive->sectsize + 3); - TRACE_PRINT(CMD_MSG, ("DISK2: " ADDRESS_FORMAT " WRITE_HEADER Command: track=%d (%d), Head=%d, Sector=%d" NLP, - PCX, - pDrive->track, - disk2_info->cyl, - disk2_info->head_sel, - disk2_info->hdr_sector)); + sim_debug(CMD_MSG, &disk2_dev, "DISK2: " ADDRESS_FORMAT + " WRITE_HEADER Command: track=%d (%d), Head=%d, Sector=%d\n", + PCX, pDrive->track, disk2_info->cyl, + disk2_info->head_sel, disk2_info->hdr_sector); i = disk2_info->hdr_sector; selchan_dma(sdata.raw, 3); @@ -542,11 +540,13 @@ static uint8 DISK2_Write(const uint32 Addr, uint8 cData) break; case DISK2_CMD_READ_HEADER: track_offset = pDrive->track * pDrive->nheads * pDrive->nsectors * (pDrive->sectsize + 3); - TRACE_PRINT(CMD_MSG, ("DISK2: " ADDRESS_FORMAT " READ_HEADER Command" NLP, PCX)); + sim_debug(CMD_MSG, &disk2_dev, "DISK2: " ADDRESS_FORMAT + " READ_HEADER Command\n", PCX); sim_fseek((pDrive->uptr)->fileref, track_offset + (disk2_info->head_sel * pDrive->nsectors * (pDrive->sectsize + 3)), SEEK_SET); rtn = sim_fread(sdata.raw, 1, 3, (pDrive->uptr)->fileref); if (rtn != 3) { - TRACE_PRINT(ERROR_MSG, ("DISK2: " ADDRESS_FORMAT " READ_HEADER: sim_fread error." NLP, PCX)); + sim_debug(ERROR_MSG, &disk2_dev, "DISK2: " ADDRESS_FORMAT + " READ_HEADER: sim_fread error.\n", PCX); } selchan_dma(sdata.raw, 3); @@ -578,33 +578,36 @@ static uint8 DISK2_Write(const uint32 Addr, uint8 cData) disk2_info->sel_drive = 3; break; default: - printf("DISK2: " ADDRESS_FORMAT " Error, invalid drive select=0x%x" NLP, PCX, cData >> 4); + printf("DISK2: " ADDRESS_FORMAT + " Error, invalid drive select=0x%x" NLP, PCX, cData >> 4); break; } disk2_info->head_sel = cData & 0x0F; - TRACE_PRINT(VERBOSE_MSG, ("DISK2: " ADDRESS_FORMAT " Write DATA [DRIVE]=%d, Head=%d" NLP, - PCX, disk2_info->sel_drive, disk2_info->head)); + sim_debug(VERBOSE_MSG, &disk2_dev, "DISK2: " ADDRESS_FORMAT + " Write DATA [DRIVE]=%d, Head=%d\n", + PCX, disk2_info->sel_drive, disk2_info->head); break; case DISK2_OP_CYL: disk2_info->cyl = cData; - TRACE_PRINT(VERBOSE_MSG, ("DISK2: " ADDRESS_FORMAT " Write DATA [CYL] = %02x" NLP, - PCX, cData)); + sim_debug(VERBOSE_MSG, &disk2_dev, "DISK2: " ADDRESS_FORMAT + " Write DATA [CYL] = %02x\n", PCX, cData); break; case DISK2_OP_HEAD: disk2_info->head = cData; - TRACE_PRINT(VERBOSE_MSG, ("DISK2: " ADDRESS_FORMAT " Write DATA [HEAD] = %02x" NLP, - PCX, cData)); + sim_debug(VERBOSE_MSG, &disk2_dev, "DISK2: " ADDRESS_FORMAT + " Write DATA [HEAD] = %02x\n", PCX, cData); break; case DISK2_OP_SECTOR: disk2_info->sector = cData; - TRACE_PRINT(VERBOSE_MSG, ("DISK2: " ADDRESS_FORMAT " Write Register [SECTOR] = %02x" NLP, - PCX, cData)); + sim_debug(VERBOSE_MSG, &disk2_dev, "DISK2: " ADDRESS_FORMAT + " Write Register [SECTOR] = %02x\n", PCX, cData); break; default: - TRACE_PRINT(VERBOSE_MSG, ("DISK2: " ADDRESS_FORMAT " Write Register unknown op [%d] = %02x" NLP, - PCX, disk2_info->ctl_op, cData)); + sim_debug(VERBOSE_MSG, &disk2_dev, "DISK2: " ADDRESS_FORMAT + " Write Register unknown op [%d] = %02x\n", + PCX, disk2_info->ctl_op, cData); break; } } @@ -616,7 +619,8 @@ static uint8 DISK2_Write(const uint32 Addr, uint8 cData) static void raise_disk2_interrupt(void) { - TRACE_PRINT(IRQ_MSG, ("DISK2: " ADDRESS_FORMAT " Interrupt" NLP, PCX)); + sim_debug(IRQ_MSG, &disk2_dev, "DISK2: " ADDRESS_FORMAT + " Interrupt\n", PCX); raise_ss1_interrupt(SS1_VI1_INT); diff --git a/AltairZ80/s100_disk3.c b/AltairZ80/s100_disk3.c index 9d578a83..6cb00874 100644 --- a/AltairZ80/s100_disk3.c +++ b/AltairZ80/s100_disk3.c @@ -237,10 +237,6 @@ static MTAB disk3_mod[] = { { 0 } }; -#define TRACE_PRINT(level, args) if(disk3_dev.dctrl & level) { \ - printf args; \ - } - /* Debug Flags */ static DEBTAB disk3_dt[] = { { "ERROR", ERROR_MSG }, @@ -384,7 +380,8 @@ t_stat disk3_detach(UNIT *uptr) static int32 disk3dev(const int32 port, const int32 io, const int32 data) { - TRACE_PRINT(VERBOSE_MSG, ("DISK3: " ADDRESS_FORMAT " IO %s, Port %02x" NLP, PCX, io ? "WR" : "RD", port)); + sim_debug(VERBOSE_MSG, &disk3_dev, "DISK3: " ADDRESS_FORMAT + " IO %s, Port %02x\n", PCX, io ? "WR" : "RD", port); if(io) { DISK3_Write(port, data); return 0; @@ -417,13 +414,13 @@ static uint8 DISK3_Write(const uint32 Addr, uint8 cData) next_link |= disk3_info->iopb[DISK3_IOPB_LINK+1] << 8; next_link |= disk3_info->iopb[DISK3_IOPB_LINK+2] << 16; - TRACE_PRINT(VERBOSE_MSG, ("DISK3[%d]: LINK=0x%05x, NEXT=0x%05x, CMD=%x, %s DMA@0x%05x\n", - disk3_info->sel_drive, - disk3_info->link_addr, - next_link, - disk3_info->iopb[DISK3_IOPB_CMD] & DISK3_CMD_MASK, - (disk3_info->iopb[DISK3_IOPB_CMD] & DISK3_REQUEST_IRQ) ? "IRQ" : "POLL", - disk3_info->dma_addr)); + sim_debug(VERBOSE_MSG, &disk3_dev, "DISK3[%d]: LINK=0x%05x, NEXT=0x%05x, CMD=%x, %s DMA@0x%05x\n", + disk3_info->sel_drive, + disk3_info->link_addr, + next_link, + disk3_info->iopb[DISK3_IOPB_CMD] & DISK3_CMD_MASK, + (disk3_info->iopb[DISK3_IOPB_CMD] & DISK3_REQUEST_IRQ) ? "IRQ" : "POLL", + disk3_info->dma_addr); pDrive = &disk3_info->drive[disk3_info->sel_drive]; @@ -432,30 +429,33 @@ static uint8 DISK3_Write(const uint32 Addr, uint8 cData) /* Perform command */ switch(cmd & DISK3_CMD_MASK) { case DISK3_CODE_NOOP: - TRACE_PRINT(VERBOSE_MSG, ("DISK3[%d]: " ADDRESS_FORMAT " NOOP" NLP, disk3_info->sel_drive, PCX)); + sim_debug(VERBOSE_MSG, &disk3_dev, "DISK3[%d]: " ADDRESS_FORMAT + " NOOP\n", disk3_info->sel_drive, PCX); break; case DISK3_CODE_VERSION: break; case DISK3_CODE_GLOBAL: - TRACE_PRINT(CMD_MSG, ("DISK3[%d]: " ADDRESS_FORMAT " GLOBAL" NLP, disk3_info->sel_drive, PCX)); + sim_debug(CMD_MSG, &disk3_dev, "DISK3[%d]: " ADDRESS_FORMAT + " GLOBAL\n", disk3_info->sel_drive, PCX); disk3_info->mode = disk3_info->iopb[DISK3_IOPB_ARG1]; disk3_info->retries = disk3_info->iopb[DISK3_IOPB_ARG2]; disk3_info->ndrives = disk3_info->iopb[DISK3_IOPB_ARG3]; - TRACE_PRINT(SPECIFY_MSG, (" Mode: 0x%02x" NLP, disk3_info->mode)); - TRACE_PRINT(SPECIFY_MSG, (" # Retries: 0x%02x" NLP, disk3_info->retries)); - TRACE_PRINT(SPECIFY_MSG, (" # Drives: 0x%02x" NLP, disk3_info->ndrives)); + sim_debug(SPECIFY_MSG, &disk3_dev, " Mode: 0x%02x\n", disk3_info->mode); + sim_debug(SPECIFY_MSG, &disk3_dev, " # Retries: 0x%02x\n", disk3_info->retries); + sim_debug(SPECIFY_MSG, &disk3_dev, " # Drives: 0x%02x\n", disk3_info->ndrives); if(disk3_info->mode == DISK3_MODE_ABS) { - TRACE_PRINT(ERROR_MSG, ("DISK3: Absolute addressing not supported." NLP)); + sim_debug(ERROR_MSG, &disk3_dev, "DISK3: Absolute addressing not supported.\n"); } break; case DISK3_CODE_SPECIFY: { uint8 specify_data[22]; - TRACE_PRINT(CMD_MSG, ("DISK3[%d]: " ADDRESS_FORMAT " SPECIFY" NLP, disk3_info->sel_drive, PCX)); + sim_debug(CMD_MSG, &disk3_dev, "DISK3[%d]: " ADDRESS_FORMAT + " SPECIFY\n", disk3_info->sel_drive, PCX); for(i = 0; i < 22; i++) { specify_data[i] = GetByteDMA(disk3_info->dma_addr + i); @@ -467,32 +467,36 @@ static uint8 DISK3_Write(const uint32 Addr, uint8 cData) pDrive->ntracks = specify_data[10] | (specify_data[11] << 8); pDrive->res_tracks = specify_data[18] | (specify_data[19] << 8); - TRACE_PRINT(SPECIFY_MSG, (" Sectsize: %d" NLP, pDrive->sectsize)); - TRACE_PRINT(SPECIFY_MSG, (" Sectors: %d" NLP, pDrive->nsectors)); - TRACE_PRINT(SPECIFY_MSG, (" Heads: %d" NLP, pDrive->nheads)); - TRACE_PRINT(SPECIFY_MSG, (" Tracks: %d" NLP, pDrive->ntracks)); - TRACE_PRINT(SPECIFY_MSG, (" Reserved: %d" NLP, pDrive->res_tracks)); + sim_debug(SPECIFY_MSG, &disk3_dev, " Sectsize: %d\n", pDrive->sectsize); + sim_debug(SPECIFY_MSG, &disk3_dev, " Sectors: %d\n", pDrive->nsectors); + sim_debug(SPECIFY_MSG, &disk3_dev, " Heads: %d\n", pDrive->nheads); + sim_debug(SPECIFY_MSG, &disk3_dev, " Tracks: %d\n", pDrive->ntracks); + sim_debug(SPECIFY_MSG, &disk3_dev, " Reserved: %d\n", pDrive->res_tracks); break; } case DISK3_CODE_HOME: pDrive->track = 0; - TRACE_PRINT(SEEK_MSG, ("DISK3[%d]: " ADDRESS_FORMAT " HOME" NLP, disk3_info->sel_drive, PCX)); + sim_debug(SEEK_MSG, &disk3_dev, "DISK3[%d]: " ADDRESS_FORMAT + " HOME\n", disk3_info->sel_drive, PCX); break; case DISK3_CODE_SEEK: pDrive->track = disk3_info->iopb[DISK3_IOPB_ARG1]; pDrive->track |= (disk3_info->iopb[DISK3_IOPB_ARG2] << 8); if(pDrive->track > pDrive->ntracks) { - TRACE_PRINT(ERROR_MSG, ("DISK3[%d]: " ADDRESS_FORMAT " SEEK ERROR %d not found" NLP, disk3_info->sel_drive, PCX, pDrive->track)); + sim_debug(ERROR_MSG, &disk3_dev, "DISK3[%d]: " ADDRESS_FORMAT + " SEEK ERROR %d not found\n", disk3_info->sel_drive, PCX, pDrive->track); pDrive->track = pDrive->ntracks - 1; result = DISK3_STATUS_TIMEOUT; } else { - TRACE_PRINT(SEEK_MSG, ("DISK3[%d]: " ADDRESS_FORMAT " SEEK %d" NLP, disk3_info->sel_drive, PCX, pDrive->track)); + sim_debug(SEEK_MSG, &disk3_dev, "DISK3[%d]: " ADDRESS_FORMAT + " SEEK %d\n", disk3_info->sel_drive, PCX, pDrive->track); } break; case DISK3_CODE_READ_HDR: { - TRACE_PRINT(CMD_MSG, ("DISK3[%d]: " ADDRESS_FORMAT " READ HEADER: %d" NLP, pDrive->track, PCX, pDrive->track >> 8)); + sim_debug(CMD_MSG, &disk3_dev, "DISK3[%d]: " ADDRESS_FORMAT + " READ HEADER: %d\n", pDrive->track, PCX, pDrive->track >> 8); PutByteDMA(disk3_info->dma_addr + 0, pDrive->track & 0xFF); PutByteDMA(disk3_info->dma_addr + 1, (pDrive->track >> 8) & 0xFF); PutByteDMA(disk3_info->dma_addr + 2, 0); @@ -510,7 +514,7 @@ static uint8 DISK3_Write(const uint32 Addr, uint8 cData) size_t rtn; if(disk3_info->mode == DISK3_MODE_ABS) { - TRACE_PRINT(ERROR_MSG, ("DISK3: Absolute addressing not supported." NLP)); + sim_debug(ERROR_MSG, &disk3_dev, "DISK3: Absolute addressing not supported.\n"); break; } @@ -532,16 +536,15 @@ static uint8 DISK3_Write(const uint32 Addr, uint8 cData) if(disk3_info->iopb[DISK3_IOPB_ARG1] == 1) { /* Read */ rtn = sim_fread(dataBuffer, 1, xfr_len, (pDrive->uptr)->fileref); - TRACE_PRINT(RD_DATA_MSG, - ("DISK3[%d]: " ADDRESS_FORMAT " READ @0x%05x T:%04d/S:%04d/#:%d %s" NLP, - disk3_info->sel_drive, - PCX, - disk3_info->dma_addr, - pDrive->cur_track, - pDrive->cur_sect, - pDrive->xfr_nsects, - rtn == (size_t)xfr_len ? "OK" : "NOK" - )); + sim_debug(RD_DATA_MSG, &disk3_dev, "DISK3[%d]: " ADDRESS_FORMAT + " READ @0x%05x T:%04d/S:%04d/#:%d %s\n", + disk3_info->sel_drive, + PCX, + disk3_info->dma_addr, + pDrive->cur_track, + pDrive->cur_sect, + pDrive->xfr_nsects, + rtn == (size_t)xfr_len ? "OK" : "NOK" ); /* Perform DMA Transfer */ @@ -549,14 +552,8 @@ static uint8 DISK3_Write(const uint32 Addr, uint8 cData) PutByteDMA(disk3_info->dma_addr + xfr_count, dataBuffer[xfr_count]); } } else { /* Write */ - TRACE_PRINT(WR_DATA_MSG, ("DISK3[%d]: " ADDRESS_FORMAT " WRITE @0x%05x T:%04d/S:%04d/#:%d" NLP, - disk3_info->sel_drive, - PCX, - disk3_info->dma_addr, - pDrive->cur_track, - pDrive->cur_sect, - pDrive->xfr_nsects - )); + sim_debug(WR_DATA_MSG, &disk3_dev, "DISK3[%d]: " ADDRESS_FORMAT + " WRITE @0x%05x T:%04d/S:%04d/#:%d\n", disk3_info->sel_drive, PCX, disk3_info->dma_addr, pDrive->cur_track, pDrive->cur_sect, pDrive->xfr_nsects ); /* Perform DMA Transfer */ for(xfr_count = 0;xfr_count < xfr_len; xfr_count++) { @@ -596,14 +593,14 @@ static uint8 DISK3_Write(const uint32 Addr, uint8 cData) data_len = pDrive->nsectors * pDrive->sectsize; - TRACE_PRINT(WR_DATA_MSG, ("DISK3[%d]: " ADDRESS_FORMAT " FORMAT T:%d/H:%d/Fill=0x%02x/Len=%d" NLP, - disk3_info->sel_drive, - PCX, - pDrive->track, - disk3_info->iopb[DISK3_IOPB_ARG3], - disk3_info->iopb[DISK3_IOPB_ARG2], - data_len - )); + sim_debug(WR_DATA_MSG, &disk3_dev, "DISK3[%d]: " ADDRESS_FORMAT + " FORMAT T:%d/H:%d/Fill=0x%02x/Len=%d\n", + disk3_info->sel_drive, + PCX, + pDrive->track, + disk3_info->iopb[DISK3_IOPB_ARG3], + disk3_info->iopb[DISK3_IOPB_ARG2], + data_len); file_offset = (pDrive->track * (pDrive->nheads) * data_len); /* Calculate offset based on current track */ file_offset += (disk3_info->iopb[DISK3_IOPB_ARG3] * data_len); @@ -627,7 +624,11 @@ static uint8 DISK3_Write(const uint32 Addr, uint8 cData) case DISK3_CODE_EXAMINE: case DISK3_CODE_MODIFY: default: - TRACE_PRINT(ERROR_MSG, ("DISK3[%d]: " ADDRESS_FORMAT " CMD=%x Unsupported" NLP, disk3_info->sel_drive, PCX, cmd & DISK3_CMD_MASK)); + sim_debug(ERROR_MSG, &disk3_dev, "DISK3[%d]: " ADDRESS_FORMAT + " CMD=%x Unsupported\n", + disk3_info->sel_drive, + PCX, + cmd & DISK3_CMD_MASK); break; } } else { /* Drive not ready */ @@ -654,7 +655,7 @@ static uint8 DISK3_Write(const uint32 Addr, uint8 cData) static void raise_disk3_interrupt(void) { - TRACE_PRINT(IRQ_MSG, ("DISK3: " ADDRESS_FORMAT " Interrupt" NLP, PCX)); + sim_debug(IRQ_MSG, &disk3_dev, "DISK3: " ADDRESS_FORMAT " Interrupt\n", PCX); raise_ss1_interrupt(SS1_VI1_INT); diff --git a/AltairZ80/s100_fif.c b/AltairZ80/s100_fif.c index 913de8e0..ca5481c4 100644 --- a/AltairZ80/s100_fif.c +++ b/AltairZ80/s100_fif.c @@ -2,7 +2,7 @@ IMSAI FIF Disk Controller by Ernie Price - Based on altairz80_dsk.c, Copyright (c) 2002-2010, Peter Schorn + Based on altairz80_dsk.c, Copyright (c) 2002-2011, Peter Schorn Plug-n-Play added by Howard M. Harte diff --git a/AltairZ80/s100_hdc1001.c b/AltairZ80/s100_hdc1001.c index a5afa7fb..d23db1da 100644 --- a/AltairZ80/s100_hdc1001.c +++ b/AltairZ80/s100_hdc1001.c @@ -144,10 +144,6 @@ static MTAB hdc1001_mod[] = { { 0 } }; -#define TRACE_PRINT(level, args) if(hdc1001_dev.dctrl & level) { \ - printf args; \ - } - /* Debug Flags */ static DEBTAB hdc1001_dt[] = { { "ERROR", ERROR_MSG }, @@ -289,7 +285,7 @@ t_stat hdc1001_detach(UNIT *uptr) static int32 hdc1001dev(const int32 port, const int32 io, const int32 data) { -/* TRACE_PRINT(VERBOSE_MSG, ("HDC1001: " ADDRESS_FORMAT " IO %s, Port %02x" NLP, PCX, io ? "WR" : "RD", port)); */ +/* sim_debug(VERBOSE_MSG, &hdc1001_dev, "HDC1001: " ADDRESS_FORMAT " IO %s, Port %02x\n", PCX, io ? "WR" : "RD", port); */ if(io) { HDC1001_Write(port, data); return 0; @@ -369,19 +365,18 @@ static uint8 HDC1001_Write(const uint32 Addr, uint8 cData) case TF_CYLLO: case TF_CYLHI: hdc1001_info->taskfile[Addr & 0x07] = cData; - TRACE_PRINT(VERBOSE_MSG, ("HDC1001: " ADDRESS_FORMAT " WR TF[%d]=0x%02x" NLP, PCX, Addr & 7, cData)); + sim_debug(VERBOSE_MSG, &hdc1001_dev, "HDC1001: " ADDRESS_FORMAT + " WR TF[%d]=0x%02x\n", PCX, Addr & 7, cData); break; case TF_CMD: pDrive->track = hdc1001_info->taskfile[TF_CYLLO] | (hdc1001_info->taskfile[TF_CYLHI] << 8); pDrive->xfr_nsects = hdc1001_info->taskfile[TF_SECNT]; - TRACE_PRINT(CMD_MSG, ("HDC1001[%d]: Command=%d, T:%d/H:%d/S:%d N=%d" NLP, - hdc1001_info->sel_drive, - hdc1001_info->taskfile[TF_CMD], - pDrive->track, - hdc1001_info->taskfile[TF_SDH] & 0x07, - hdc1001_info->taskfile[TF_SECNO], - pDrive->xfr_nsects)); + sim_debug(CMD_MSG, &hdc1001_dev, "HDC1001[%d]: Command=%d, T:%d/H:%d/S:%d N=%d\n", + hdc1001_info->sel_drive, + hdc1001_info->taskfile[TF_CMD], + pDrive->track, hdc1001_info->taskfile[TF_SDH] & 0x07, + hdc1001_info->taskfile[TF_SECNO], pDrive->xfr_nsects); break; default: break; @@ -394,7 +389,8 @@ static uint8 HDC1001_Read(const uint32 Addr) uint8 cData; cData = hdc1001_info->taskfile[Addr & 0x07]; - TRACE_PRINT(VERBOSE_MSG, ("HDC1001: " ADDRESS_FORMAT " RD TF[%d]=0x%02x" NLP, PCX, Addr & 7, cData)); + sim_debug(VERBOSE_MSG, &hdc1001_dev, "HDC1001: " ADDRESS_FORMAT + " RD TF[%d]=0x%02x\n", PCX, Addr & 7, cData); return (cData); } @@ -415,12 +411,7 @@ static uint8 HDC1001_Read(const uint32 Addr) next_link |= hdc1001_info->iopb[0x0E] << 8; next_link |= hdc1001_info->iopb[0x0F] << 16; - TRACE_PRINT(VERBOSE_MSG, ("HDC1001[%d]: LINK=0x%05x, NEXT=0x%05x, CMD=%x, DMA@0x%05x\n", - hdc1001_info->sel_drive, - hdc1001_info->link_addr, - next_link, - hdc1001_info->iopb[0], - hdc1001_info->dma_addr)); + sim_debug(VERBOSE_MSG, &hdc1001_dev, "HDC1001[%d]: LINK=0x%05x, NEXT=0x%05x, CMD=%x, DMA@0x%05x\n", hdc1001_info->sel_drive, hdc1001_info->link_addr, next_link, hdc1001_info->iopb[0], hdc1001_info->dma_addr); @@ -429,26 +420,26 @@ static uint8 HDC1001_Read(const uint32 Addr) /* Perform command */ switch(cmd) { case HDC1001_CODE_NOOP: - TRACE_PRINT(VERBOSE_MSG, ("HDC1001[%d]: " ADDRESS_FORMAT " NOOP" NLP, hdc1001_info->sel_drive, PCX)); + sim_debug(VERBOSE_MSG, &hdc1001_dev, "HDC1001[%d]: " ADDRESS_FORMAT " NOOP\n", hdc1001_info->sel_drive, PCX); break; case HDC1001_CODE_VERSION: break; case HDC1001_CODE_GLOBAL: - TRACE_PRINT(CMD_MSG, ("HDC1001[%d]: " ADDRESS_FORMAT " GLOBAL" NLP, hdc1001_info->sel_drive, PCX)); + sim_debug(CMD_MSG, &hdc1001_dev, "HDC1001[%d]: " ADDRESS_FORMAT " GLOBAL\n", hdc1001_info->sel_drive, PCX); hdc1001_info->mode = hdc1001_info->iopb[3]; hdc1001_info->retries = hdc1001_info->iopb[4]; hdc1001_info->ndrives = hdc1001_info->iopb[5]; - TRACE_PRINT(VERBOSE_MSG, (" Mode: 0x%02x" NLP, hdc1001_info->mode)); - TRACE_PRINT(VERBOSE_MSG, (" # Retries: 0x%02x" NLP, hdc1001_info->retries)); - TRACE_PRINT(VERBOSE_MSG, (" # Drives: 0x%02x" NLP, hdc1001_info->ndrives)); + sim_debug(VERBOSE_MSG, &hdc1001_dev, " Mode: 0x%02x\n", hdc1001_info->mode); + sim_debug(VERBOSE_MSG, &hdc1001_dev, " # Retries: 0x%02x\n", hdc1001_info->retries); + sim_debug(VERBOSE_MSG, &hdc1001_dev, " # Drives: 0x%02x\n", hdc1001_info->ndrives); break; case HDC1001_CODE_SPECIFY: { uint8 specify_data[22]; - TRACE_PRINT(CMD_MSG, ("HDC1001[%d]: " ADDRESS_FORMAT " SPECIFY" NLP, hdc1001_info->sel_drive, PCX)); + sim_debug(CMD_MSG, &hdc1001_dev, "HDC1001[%d]: " ADDRESS_FORMAT " SPECIFY\n", hdc1001_info->sel_drive, PCX); for(i = 0; i < 22; i++) { specify_data[i] = GetBYTEWrapper(hdc1001_info->dma_addr + i); @@ -460,32 +451,32 @@ static uint8 HDC1001_Read(const uint32 Addr) pDrive->ntracks = specify_data[10] | (specify_data[11] << 8); pDrive->res_tracks = specify_data[18] | (specify_data[19] << 8); - TRACE_PRINT(VERBOSE_MSG, (" Sectsize: %d" NLP, pDrive->sectsize)); - TRACE_PRINT(VERBOSE_MSG, (" Sectors: %d" NLP, pDrive->nsectors)); - TRACE_PRINT(VERBOSE_MSG, (" Heads: %d" NLP, pDrive->nheads)); - TRACE_PRINT(VERBOSE_MSG, (" Tracks: %d" NLP, pDrive->ntracks)); - TRACE_PRINT(VERBOSE_MSG, (" Reserved: %d" NLP, pDrive->res_tracks)); + sim_debug(VERBOSE_MSG, &hdc1001_dev, " Sectsize: %d\n", pDrive->sectsize); + sim_debug(VERBOSE_MSG, &hdc1001_dev, " Sectors: %d\n", pDrive->nsectors); + sim_debug(VERBOSE_MSG, &hdc1001_dev, " Heads: %d\n", pDrive->nheads); + sim_debug(VERBOSE_MSG, &hdc1001_dev, " Tracks: %d\n", pDrive->ntracks); + sim_debug(VERBOSE_MSG, &hdc1001_dev, " Reserved: %d\n", pDrive->res_tracks); break; } case HDC1001_CODE_HOME: pDrive->track = 0; - TRACE_PRINT(SEEK_MSG, ("HDC1001[%d]: " ADDRESS_FORMAT " HOME" NLP, hdc1001_info->sel_drive, PCX)); + sim_debug(SEEK_MSG, &hdc1001_dev, "HDC1001[%d]: " ADDRESS_FORMAT " HOME\n", hdc1001_info->sel_drive, PCX); break; case HDC1001_CODE_SEEK: pDrive->track = hdc1001_info->iopb[3]; pDrive->track |= (hdc1001_info->iopb[4] << 8); if(pDrive->track > pDrive->ntracks) { - TRACE_PRINT(ERROR_MSG, ("HDC1001[%d]: " ADDRESS_FORMAT " SEEK ERROR %d not found" NLP, hdc1001_info->sel_drive, PCX, pDrive->track)); + sim_debug(ERROR_MSG, &hdc1001_dev, "HDC1001[%d]: " ADDRESS_FORMAT " SEEK ERROR %d not found\n", hdc1001_info->sel_drive, PCX, pDrive->track); pDrive->track = pDrive->ntracks - 1; result = HDC1001_STATUS_TIMEOUT; } else { - TRACE_PRINT(SEEK_MSG, ("HDC1001[%d]: " ADDRESS_FORMAT " SEEK %d" NLP, hdc1001_info->sel_drive, PCX, pDrive->track)); + sim_debug(SEEK_MSG, &hdc1001_dev, "HDC1001[%d]: " ADDRESS_FORMAT " SEEK %d\n", hdc1001_info->sel_drive, PCX, pDrive->track); } break; case HDC1001_CODE_READ_HDR: { - TRACE_PRINT(CMD_MSG, ("HDC1001[%d]: " ADDRESS_FORMAT " READ HEADER: %d" NLP, pDrive->track, PCX)); + sim_debug(CMD_MSG, &hdc1001_dev, "HDC1001[%d]: " ADDRESS_FORMAT " READ HEADER: %d\n", pDrive->track, PCX); PutBYTEWrapper(hdc1001_info->dma_addr + 0, pDrive->track & 0xFF); PutBYTEWrapper(hdc1001_info->dma_addr + 1, (pDrive->track >> 8) & 0xFF); PutBYTEWrapper(hdc1001_info->dma_addr + 2, 0); @@ -517,14 +508,7 @@ static uint8 HDC1001_Read(const uint32 Addr) sim_fseek((pDrive->uptr)->fileref, file_offset, SEEK_SET); if(hdc1001_info->iopb[3] == 1) { /* Read */ - TRACE_PRINT(RD_DATA_MSG, ("HDC1001[%d]: " ADDRESS_FORMAT " READ @0x%05x T:%04d/S:%04d/#:%d" NLP, - hdc1001_info->sel_drive, - PCX, - hdc1001_info->dma_addr, - pDrive->cur_track, - pDrive->cur_sect, - pDrive->xfr_nsects - )); + sim_debug(RD_DATA_MSG, &hdc1001_dev, "HDC1001[%d]: " ADDRESS_FORMAT " READ @0x%05x T:%04d/S:%04d/#:%d\n", hdc1001_info->sel_drive, PCX, hdc1001_info->dma_addr, pDrive->cur_track, pDrive->cur_sect, pDrive->xfr_nsects ); sim_fread(dataBuffer, 1, xfr_len, (pDrive->uptr)->fileref); @@ -533,14 +517,7 @@ static uint8 HDC1001_Read(const uint32 Addr) PutBYTEWrapper(hdc1001_info->dma_addr + xfr_count, dataBuffer[xfr_count]); } } else { /* Write */ - TRACE_PRINT(WR_DATA_MSG, ("HDC1001[%d]: " ADDRESS_FORMAT " WRITE @0x%05x T:%04d/S:%04d/#:%d" NLP, - hdc1001_info->sel_drive, - PCX, - hdc1001_info->dma_addr, - pDrive->cur_track, - pDrive->cur_sect, - pDrive->xfr_nsects - )); + sim_debug(WR_DATA_MSG, &hdc1001_dev, "HDC1001[%d]: " ADDRESS_FORMAT " WRITE @0x%05x T:%04d/S:%04d/#:%d\n", hdc1001_info->sel_drive, PCX, hdc1001_info->dma_addr, pDrive->cur_track, pDrive->cur_sect, pDrive->xfr_nsects ); /* Perform DMA Transfer */ for(xfr_count = 0;xfr_count < xfr_len; xfr_count++) { @@ -562,14 +539,7 @@ static uint8 HDC1001_Read(const uint32 Addr) data_len = pDrive->nsectors * pDrive->sectsize; - TRACE_PRINT(WR_DATA_MSG, ("HDC1001[%d]: " ADDRESS_FORMAT " FORMAT T:%d/H:%d/Fill=0x%02x/Len=%d" NLP, - hdc1001_info->sel_drive, - PCX, - pDrive->track, - hdc1001_info->iopb[5], - hdc1001_info->iopb[4], - data_len - )); + sim_debug(WR_DATA_MSG, &hdc1001_dev, "HDC1001[%d]: " ADDRESS_FORMAT " FORMAT T:%d/H:%d/Fill=0x%02x/Len=%d\n", hdc1001_info->sel_drive, PCX, pDrive->track, hdc1001_info->iopb[5], hdc1001_info->iopb[4], data_len ); file_offset = (pDrive->track * (pDrive->nheads) * data_len); /* Calculate offset based on current track */ file_offset += (hdc1001_info->iopb[5] * data_len); @@ -592,7 +562,7 @@ static uint8 HDC1001_Read(const uint32 Addr) case HDC1001_CODE_EXAMINE: case HDC1001_CODE_MODIFY: default: - TRACE_PRINT(ERROR_MSG, ("HDC1001[%d]: " ADDRESS_FORMAT " CMD=%x Unsupported" NLP, hdc1001_info->sel_drive, PCX, cmd)); + sim_debug(ERROR_MSG, &hdc1001_dev, "HDC1001[%d]: " ADDRESS_FORMAT " CMD=%x Unsupported\n", hdc1001_info->sel_drive, PCX, cmd); break; } } else { /* Drive not ready */ diff --git a/AltairZ80/s100_if3.c b/AltairZ80/s100_if3.c index 3ca1f9e6..8c844512 100644 --- a/AltairZ80/s100_if3.c +++ b/AltairZ80/s100_if3.c @@ -126,10 +126,6 @@ static MTAB if3_mod[] = { { 0 } }; -#define TRACE_PRINT(level, args) if(if3_dev.dctrl & level) { \ - printf args; \ - } - /* Debug Flags */ static DEBTAB if3_dt[] = { { "ERROR", ERROR_MSG }, @@ -153,15 +149,15 @@ DEVICE if3_dev = { static t_stat set_if3_connect(UNIT *uptr, int32 val, char *cptr, void *desc) { if(uptr->flags & UNIT_DISABLE) { - TRACE_PRINT(ERROR_MSG, ("IF3[%d]: not enabled." NLP, uptr->u3)); + sim_debug(ERROR_MSG, &if3_dev, "IF3[%d]: not enabled.\n", uptr->u3); return SCPE_OK; } if(val & UNIT_IF3_CONNECT) { - TRACE_PRINT((RXIRQ_MSG|TXIRQ_MSG), ("IF3[%d]: IRQ polling started..." NLP, uptr->u3)); + sim_debug((RXIRQ_MSG|TXIRQ_MSG), &if3_dev, "IF3[%d]: IRQ polling started...\n", uptr->u3); sim_activate(uptr, 100000); } else { - TRACE_PRINT((RXIRQ_MSG|TXIRQ_MSG), ("IF3[%d]: IRQ polling stopped." NLP, uptr->u3)); + sim_debug((RXIRQ_MSG|TXIRQ_MSG), &if3_dev, "IF3[%d]: IRQ polling stopped.\n", uptr->u3); sim_cancel(uptr); } return (SCPE_OK); @@ -189,7 +185,7 @@ static t_stat if3_reset(DEVICE *dptr) for(i=0;i> 3; /* guarantees that if3_board < IF3_MAX_BOARDS */ if3_user = cData & 0x7; - TRACE_PRINT(USER_MSG, ("IF3[%d]: " ADDRESS_FORMAT " WR UART_SEL=0x%02x (Board=%d, Rel_User=%d, User=%d)" NLP, - if3_board, PCX, cData, if3_board, if3_user, cData)); + sim_debug(USER_MSG, &if3_dev, "IF3[%d]: " ADDRESS_FORMAT " WR UART_SEL=0x%02x (Board=%d, Rel_User=%d, User=%d)\n", if3_board, PCX, cData, if3_board, if3_user, cData); break; } @@ -334,13 +324,13 @@ static t_stat if3_svc (UNIT *uptr) pending_rx_irqs = if3_risr[board] & if3_rimr[board]; if(pending_rx_irqs) { - TRACE_PRINT(RXIRQ_MSG, ("IF3[%d]: " ADDRESS_FORMAT " Rx IRQ Pending: 0x%02x" NLP, board, PCX, pending_rx_irqs)); + sim_debug(RXIRQ_MSG, &if3_dev, "IF3[%d]: " ADDRESS_FORMAT " Rx IRQ Pending: 0x%02x\n", board, PCX, pending_rx_irqs); raise_ss1_interrupt(SS1_VI2_INT); } pending_tx_irqs = if3_tisr[board] & if3_timr[board]; if(pending_tx_irqs) { - TRACE_PRINT(TXIRQ_MSG, ("IF3[%d]: " ADDRESS_FORMAT " Tx IRQ Pending: 0x%02x" NLP, board, PCX, pending_tx_irqs)); + sim_debug(TXIRQ_MSG, &if3_dev, "IF3[%d]: " ADDRESS_FORMAT " Tx IRQ Pending: 0x%02x\n", board, PCX, pending_tx_irqs); raise_ss1_interrupt(SS1_VI3_INT); } diff --git a/AltairZ80/s100_mdriveh.c b/AltairZ80/s100_mdriveh.c index eaa8791a..ca20262b 100644 --- a/AltairZ80/s100_mdriveh.c +++ b/AltairZ80/s100_mdriveh.c @@ -118,10 +118,6 @@ static MTAB mdriveh_mod[] = { { 0 } }; -#define TRACE_PRINT(level, args) if(mdriveh_dev.dctrl & level) { \ - printf args; \ - } - /* Debug Flags */ static DEBTAB mdriveh_dt[] = { { "ERROR", ERROR_MSG }, @@ -207,8 +203,7 @@ static uint8 MDRIVEH_Read(const uint32 Addr) switch(Addr & 0x1) { case MDRIVEH_ADDR: - TRACE_PRINT(VERBOSE_MSG, ("MDRIVEH: " ADDRESS_FORMAT " RD Addr = 0x%02x" NLP, - PCX, cData)); + sim_debug(VERBOSE_MSG, &mdriveh_dev, "MDRIVEH: " ADDRESS_FORMAT " RD Addr = 0x%02x\n", PCX, cData); break; case MDRIVEH_DATA: unit = (mdriveh_info->dma_addr & 0x380000) >> 19; @@ -218,8 +213,7 @@ static uint8 MDRIVEH_Read(const uint32 Addr) cData = mdriveh_info->storage[unit][offset]; } - TRACE_PRINT(RD_DATA_MSG, ("MDRIVEH: " ADDRESS_FORMAT " RD Data [%x:%05x] = 0x%02x" NLP, - PCX, unit, offset, cData)); + sim_debug(RD_DATA_MSG, &mdriveh_dev, "MDRIVEH: " ADDRESS_FORMAT " RD Data [%x:%05x] = 0x%02x\n", PCX, unit, offset, cData); /* Increment M-DRIVE/H Data Address */ mdriveh_info->dma_addr++; @@ -241,8 +235,7 @@ static uint8 MDRIVEH_Write(const uint32 Addr, uint8 cData) mdriveh_info->dma_addr <<= 8; mdriveh_info->dma_addr &= 0x003FFF00; mdriveh_info->dma_addr |= cData; - TRACE_PRINT(SEEK_MSG, ("MDRIVEH: " ADDRESS_FORMAT " DMA Address=%06x" NLP, - PCX, mdriveh_info->dma_addr)); + sim_debug(SEEK_MSG, &mdriveh_dev, "MDRIVEH: " ADDRESS_FORMAT " DMA Address=%06x\n", PCX, mdriveh_info->dma_addr); break; case MDRIVEH_DATA: unit = (mdriveh_info->dma_addr & 0x380000) >> 19; @@ -250,16 +243,13 @@ static uint8 MDRIVEH_Write(const uint32 Addr, uint8 cData) if(mdriveh_info->storage[unit] != NULL) { if(mdriveh_info->uptr[unit].flags & UNIT_MDRIVEH_WLK) { - TRACE_PRINT(WR_DATA_MSG, ("MDRIVEH: " ADDRESS_FORMAT " WR Data [%x:%05x] = Unit Write Locked" NLP, - PCX, unit, offset)); + sim_debug(WR_DATA_MSG, &mdriveh_dev, "MDRIVEH: " ADDRESS_FORMAT " WR Data [%x:%05x] = Unit Write Locked\n", PCX, unit, offset); } else { - TRACE_PRINT(WR_DATA_MSG, ("MDRIVEH: " ADDRESS_FORMAT " WR Data [%x:%05x] = 0x%02x" NLP, - PCX, unit, offset, cData)); + sim_debug(WR_DATA_MSG, &mdriveh_dev, "MDRIVEH: " ADDRESS_FORMAT " WR Data [%x:%05x] = 0x%02x\n", PCX, unit, offset, cData); mdriveh_info->storage[unit][offset] = cData; } } else { - TRACE_PRINT(WR_DATA_MSG, ("MDRIVEH: " ADDRESS_FORMAT " WR Data [%x:%05x] = Unit OFFLINE" NLP, - PCX, unit, offset)); + sim_debug(WR_DATA_MSG, &mdriveh_dev, "MDRIVEH: " ADDRESS_FORMAT " WR Data [%x:%05x] = Unit OFFLINE\n", PCX, unit, offset); } /* Increment M-DRIVE/H Data Address */ diff --git a/AltairZ80/s100_mdsad.c b/AltairZ80/s100_mdsad.c index 639df98c..fe3c5d65 100644 --- a/AltairZ80/s100_mdsad.c +++ b/AltairZ80/s100_mdsad.c @@ -243,10 +243,6 @@ static MTAB mdsad_mod[] = { { 0 } }; -#define TRACE_PRINT(level, args) if(mdsad_dev.dctrl & level) { \ - printf args; \ - } - /* Debug Flags */ static DEBTAB mdsad_dt[] = { { "ERROR", ERROR_MSG }, @@ -462,13 +458,10 @@ static uint8 MDSAD_Read(const uint32 Addr) case MDSAD_WRITE_DATA: { if(mdsad_info->datacount == 0) { - TRACE_PRINT(WR_DATA_MSG, ("MDSAD: " ADDRESS_FORMAT - " WRITE Start: Drive: %d, Track=%d, Head=%d, Sector=%d" NLP, - PCX, - mdsad_info->orders.ds, - pDrive->track, - mdsad_info->orders.ss, - pDrive->sector)); + sim_debug(WR_DATA_MSG, &mdsad_dev, "MDSAD: " ADDRESS_FORMAT + " WRITE Start: Drive: %d, Track=%d, Head=%d, Sector=%d\n", + PCX, mdsad_info->orders.ds, pDrive->track, + mdsad_info->orders.ss, pDrive->sector); sec_offset = calculate_mdsad_sec_offset(pDrive->track, mdsad_info->orders.ss, @@ -484,13 +477,12 @@ static uint8 MDSAD_Read(const uint32 Addr) sdata.raw[mdsad_info->datacount] = Addr & 0xFF; if(mdsad_info->datacount == (MDSAD_RAW_LEN - 1)) { - TRACE_PRINT(WR_DATA_MSG, ("MDSAD: " ADDRESS_FORMAT - " Write Complete" NLP, PCX)); + sim_debug(WR_DATA_MSG, &mdsad_dev, "MDSAD: " ADDRESS_FORMAT + " Write Complete\n", PCX); if ((pDrive->uptr == NULL) || (pDrive->uptr->fileref == NULL)) { - TRACE_PRINT(WR_DATA_MSG, ("MDSAD: " ADDRESS_FORMAT - " Drive: %d not attached - write ignored." NLP, - PCX, mdsad_info->orders.ds)); + sim_debug(WR_DATA_MSG, &mdsad_dev, "MDSAD: " ADDRESS_FORMAT + " Drive: %d not attached - write ignored.\n", PCX, mdsad_info->orders.ds); return 0x00; } if(mdsad_dev.dctrl & WR_DATA_DETAIL_MSG) @@ -541,34 +533,29 @@ static uint8 MDSAD_Read(const uint32 Addr) } if(mdsad_info->orders.ds != (mdsad_info->orders.ds & 0x03)) { - TRACE_PRINT(ERROR_MSG, ("MDSAD: " ADDRESS_FORMAT - " Controller Orders update drive %x" NLP, PCX, mdsad_info->orders.ds)); + sim_debug(ERROR_MSG, &mdsad_dev, "MDSAD: " ADDRESS_FORMAT + " Controller Orders update drive %x\n", PCX, mdsad_info->orders.ds); mdsad_info->orders.ds &= 0x03; } - TRACE_PRINT(ORDERS_MSG, ("MDSAD: " ADDRESS_FORMAT - " Controller Orders: Drive=%x[%x], DD=%d, SS=%d, DP=%d, ST=%d" NLP, - PCX, - mdsad_info->orders.ds, ds, - mdsad_info->orders.dd, - mdsad_info->orders.ss, - mdsad_info->orders.dp, - mdsad_info->orders.st)); + sim_debug(ORDERS_MSG, &mdsad_dev, "MDSAD: " ADDRESS_FORMAT + " Controller Orders: Drive=%x[%x], DD=%d, SS=%d, DP=%d, ST=%d\n", + PCX, mdsad_info->orders.ds, ds, mdsad_info->orders.dd, + mdsad_info->orders.ss, mdsad_info->orders.dp, mdsad_info->orders.st); /* use latest selected drive */ pDrive = &mdsad_info->drive[mdsad_info->orders.ds]; if(mdsad_info->orders.st == 1) { if(mdsad_info->orders.dp == 0) { - TRACE_PRINT(SEEK_MSG, ("MDSAD: " ADDRESS_FORMAT - " Step out: Track=%d%s" NLP, PCX, pDrive->track, - pDrive->track == 0 ? "[Warn: already at 0]" : "")); + sim_debug(SEEK_MSG, &mdsad_dev, "MDSAD: " ADDRESS_FORMAT + " Step out: Track=%d%s\n", PCX, pDrive->track, + pDrive->track == 0 ? "[Warn: already at 0]" : ""); if(pDrive->track > 0) /* anything to do? */ pDrive->track--; } else { - TRACE_PRINT(SEEK_MSG, ("MDSAD: " ADDRESS_FORMAT - " Step in: Track=%d%s" NLP, PCX, pDrive->track, - pDrive->track == (MDSAD_TRACKS - 1) ? - "[Warn: already at highest track]" : "")); + sim_debug(SEEK_MSG, &mdsad_dev, "MDSAD: " ADDRESS_FORMAT + " Step in: Track=%d%s\n", PCX, pDrive->track, + pDrive->track == (MDSAD_TRACKS - 1) ? "[Warn: already at highest track]" : ""); if(pDrive->track < (MDSAD_TRACKS - 1)) /* anything to do? */ pDrive->track++; } @@ -577,11 +564,11 @@ static uint8 MDSAD_Read(const uint32 Addr) mdsad_info->b_status.t0 = (pDrive->track == 0); break; case MDSAD_CTLR_COMMAND: -/* TRACE_PRINT(CMD_MSG, ("MDSAD: " ADDRESS_FORMAT " DM=%x" NLP, PCX, (Addr & 0xF0) >> 4)); */ +/* sim_debug(CMD_MSG, &mdsad_dev, "MDSAD: " ADDRESS_FORMAT " DM=%x\n", PCX, (Addr & 0xF0) >> 4); */ switch(Addr & 0x0F) { case MDSAD_CMD_MOTORS_ON: - TRACE_PRINT(CMD_MSG, ("MDSAD: " ADDRESS_FORMAT - " CMD=Motors On" NLP, PCX)); + sim_debug(CMD_MSG, &mdsad_dev, "MDSAD: " ADDRESS_FORMAT + " CMD=Motors On\n", PCX); mdsad_info->com_status.mo = 1; /* Turn motors on */ break; @@ -616,37 +603,37 @@ static uint8 MDSAD_Read(const uint32 Addr) } break; case MDSAD_CMD_RESET_SF: - TRACE_PRINT(CMD_MSG, ("MDSAD: " ADDRESS_FORMAT - " CMD=Reset Sector Flag" NLP, PCX)); + sim_debug(CMD_MSG, &mdsad_dev, "MDSAD: " ADDRESS_FORMAT + " CMD=Reset Sector Flag\n", PCX); mdsad_info->com_status.sf = 0; mdsad_info->datacount = 0; break; case MDSAD_CMD_INTR_DIS: - TRACE_PRINT(CMD_MSG, ("MDSAD: " ADDRESS_FORMAT - " CMD=Disarm Interrupt" NLP, PCX)); + sim_debug(CMD_MSG, &mdsad_dev, "MDSAD: " ADDRESS_FORMAT + " CMD=Disarm Interrupt\n", PCX); mdsad_info->int_enable = 0; break; case MDSAD_CMD_INTR_ARM: - TRACE_PRINT(CMD_MSG, ("MDSAD: " ADDRESS_FORMAT - " CMD=Arm Interrupt" NLP, PCX)); + sim_debug(CMD_MSG, &mdsad_dev, "MDSAD: " ADDRESS_FORMAT + " CMD=Arm Interrupt\n", PCX); mdsad_info->int_enable = 1; break; case MDSAD_CMD_SET_BODY: - TRACE_PRINT(CMD_MSG, ("MDSAD: " ADDRESS_FORMAT - " CMD=Set Body (Diagnostic)" NLP, PCX)); + sim_debug(CMD_MSG, &mdsad_dev, "MDSAD: " ADDRESS_FORMAT + " CMD=Set Body (Diagnostic)\n", PCX); break; case MDSAD_CMD_BEGIN_WR: - TRACE_PRINT(CMD_MSG, ("MDSAD: " ADDRESS_FORMAT - " CMD=Begin Write" NLP, PCX)); + sim_debug(CMD_MSG, &mdsad_dev, "MDSAD: " ADDRESS_FORMAT + " CMD=Begin Write\n", PCX); break; case MDSAD_CMD_RESET: - TRACE_PRINT(CMD_MSG, ("MDSAD: " ADDRESS_FORMAT - " CMD=Reset Controller" NLP, PCX)); + sim_debug(CMD_MSG, &mdsad_dev, "MDSAD: " ADDRESS_FORMAT + " CMD=Reset Controller\n", PCX); mdsad_info->com_status.mo = 0; /* Turn motors off */ break; default: - TRACE_PRINT(CMD_MSG, ("MDSAD: " ADDRESS_FORMAT - " Unsupported CMD=0x%x" NLP, PCX, Addr & 0x0F)); + sim_debug(CMD_MSG, &mdsad_dev, "MDSAD: " ADDRESS_FORMAT + " Unsupported CMD=0x%x\n", PCX, Addr & 0x0F); break; } @@ -666,52 +653,56 @@ static uint8 MDSAD_Read(const uint32 Addr) cData |= (mdsad_info->a_status.re & 1) << 2; cData |= (mdsad_info->a_status.sp & 1) << 1; cData |= (mdsad_info->a_status.bd & 1); - TRACE_PRINT(STATUS_MSG, ("MDSAD: " ADDRESS_FORMAT - " A-Status = <%s %s %s %s %s %s %s %s>" NLP, PCX, - cData & MDSAD_A_SF ? "SF" : " ", - cData & MDSAD_A_IX ? "IX" : " ", - cData & MDSAD_A_DD ? "DD" : " ", - cData & MDSAD_A_MO ? "MO" : " ", - cData & MDSAD_A_WI ? "WI" : " ", - cData & MDSAD_A_RE ? "RE" : " ", - cData & MDSAD_A_SP ? "SP" : " ", - cData & MDSAD_A_BD ? "BD" : " ")); + sim_debug(STATUS_MSG, &mdsad_dev, "MDSAD: " ADDRESS_FORMAT + " A-Status = <%s %s %s %s %s %s %s %s>\n", + PCX, + cData & MDSAD_A_SF ? "SF" : " ", + cData & MDSAD_A_IX ? "IX" : " ", + cData & MDSAD_A_DD ? "DD" : " ", + cData & MDSAD_A_MO ? "MO" : " ", + cData & MDSAD_A_WI ? "WI" : " ", + cData & MDSAD_A_RE ? "RE" : " ", + cData & MDSAD_A_SP ? "SP" : " ", + cData & MDSAD_A_BD ? "BD" : " "); break; case MDSAD_B_STATUS: /* B-STATUS */ cData |= (mdsad_info->b_status.wr & 1) << 3; cData |= (mdsad_info->b_status.sp & 1) << 2; cData |= (mdsad_info->b_status.wp & 1) << 1; cData |= (mdsad_info->b_status.t0 & 1); - TRACE_PRINT(STATUS_MSG, ("MDSAD: " ADDRESS_FORMAT - " B-Status = <%s %s %s %s %s %s %s %s>" NLP, PCX, - cData & MDSAD_B_SF ? "SF" : " ", - cData & MDSAD_B_IX ? "IX" : " ", - cData & MDSAD_B_DD ? "DD" : " ", - cData & MDSAD_B_MO ? "MO" : " ", - cData & MDSAD_B_WR ? "WR" : " ", - cData & MDSAD_B_SP ? "SP" : " ", - cData & MDSAD_B_WP ? "WP" : " ", - cData & MDSAD_B_T0 ? "T0" : " ")); + sim_debug(STATUS_MSG, &mdsad_dev, "MDSAD: " ADDRESS_FORMAT + " B-Status = <%s %s %s %s %s %s %s %s>\n", + PCX, + cData & MDSAD_B_SF ? "SF" : " ", + cData & MDSAD_B_IX ? "IX" : " ", + cData & MDSAD_B_DD ? "DD" : " ", + cData & MDSAD_B_MO ? "MO" : " ", + cData & MDSAD_B_WR ? "WR" : " ", + cData & MDSAD_B_SP ? "SP" : " ", + cData & MDSAD_B_WP ? "WP" : " ", + cData & MDSAD_B_T0 ? "T0" : " "); break; case MDSAD_C_STATUS: /* C-STATUS */ cData |= (mdsad_info->c_status.sc & 0xF); - TRACE_PRINT(STATUS_MSG, ("MDSAD: " ADDRESS_FORMAT - " C-Status = <%s %s %s %s %i>" NLP, PCX, - cData & MDSAD_C_SF ? "SF" : " ", - cData & MDSAD_C_IX ? "IX" : " ", - cData & MDSAD_C_DD ? "DD" : " ", - cData & MDSAD_C_MO ? "MO" : " ", cData & MDSAD_C_SC)); + sim_debug(STATUS_MSG, &mdsad_dev, "MDSAD: " ADDRESS_FORMAT + " C-Status = <%s %s %s %s %i>\n", + PCX, + cData & MDSAD_C_SF ? "SF" : " ", + cData & MDSAD_C_IX ? "IX" : " ", + cData & MDSAD_C_DD ? "DD" : " ", + cData & MDSAD_C_MO ? "MO" : " ", + cData & MDSAD_C_SC); break; case MDSAD_READ_DATA: /* READ DATA */ { if(mdsad_info->datacount == 0) { - TRACE_PRINT(RD_DATA_MSG, ("MDSAD: " ADDRESS_FORMAT - " READ Start: Drive: %d, Track=%d, Head=%d, Sector=%d" NLP, - PCX, - mdsad_info->orders.ds, - pDrive->track, - mdsad_info->orders.ss, - pDrive->sector)); + sim_debug(RD_DATA_MSG, &mdsad_dev, "MDSAD: " ADDRESS_FORMAT + " READ Start: Drive: %d, Track=%d, Head=%d, Sector=%d\n", + PCX, + mdsad_info->orders.ds, + pDrive->track, + mdsad_info->orders.ss, + pDrive->sector); checksum = 0; @@ -721,9 +712,9 @@ static uint8 MDSAD_Read(const uint32 Addr) if ((pDrive->uptr == NULL) || (pDrive->uptr->fileref == NULL)) { - TRACE_PRINT(RD_DATA_MSG, ("MDSAD: " ADDRESS_FORMAT - " Drive: %d not attached - read ignored." NLP, - PCX, mdsad_info->orders.ds)); + sim_debug(RD_DATA_MSG, &mdsad_dev, "MDSAD: " ADDRESS_FORMAT + " Drive: %d not attached - read ignored.\n", + PCX, mdsad_info->orders.ds); return 0xe5; } @@ -738,7 +729,8 @@ static uint8 MDSAD_Read(const uint32 Addr) rtn = sim_fread(&sdata.u.data[0], 1, MDSAD_SECTOR_LEN, (pDrive->uptr)->fileref); if (rtn != MDSAD_SECTOR_LEN) { - TRACE_PRINT(ERROR_MSG, ("MDSAD: " ADDRESS_FORMAT " READ: sim_fread error." NLP, PCX)); + sim_debug(ERROR_MSG, &mdsad_dev, "MDSAD: " ADDRESS_FORMAT + " READ: sim_fread error.\n", PCX); } } break; @@ -768,9 +760,9 @@ static uint8 MDSAD_Read(const uint32 Addr) PCX, sec_offset, mdsad_info->datacount, cData)); } else { /* checksum */ cData = checksum; - TRACE_PRINT(RD_DATA_MSG, ("MDSAD: " ADDRESS_FORMAT - " READ-DATA: Checksum is: 0x%02x" NLP, - PCX, cData)); + sim_debug(RD_DATA_MSG, &mdsad_dev, "MDSAD: " ADDRESS_FORMAT + " READ-DATA: Checksum is: 0x%02x\n", + PCX, cData); } mdsad_info->datacount++; diff --git a/AltairZ80/s100_scp300f.c b/AltairZ80/s100_scp300f.c index 1aaa35eb..38d7c1fb 100644 --- a/AltairZ80/s100_scp300f.c +++ b/AltairZ80/s100_scp300f.c @@ -120,10 +120,6 @@ static MTAB scp300f_mod[] = { { 0 } }; -#define TRACE_PRINT(level, args) if(scp300f_dev.dctrl & level) { \ - printf args; \ - } - /* Debug Flags */ static DEBTAB scp300f_dt[] = { { "ERROR", ERROR_MSG }, @@ -151,7 +147,7 @@ static t_stat scp300f_reset(DEVICE *dptr) { PNP_INFO *pnp = (PNP_INFO *)dptr->ctxt; - TRACE_PRINT(VERBOSE_MSG, ("SCP300F: Reset." NLP)); + sim_debug(VERBOSE_MSG, &scp300f_dev, "SCP300F: Reset.\n"); if(dptr->flags & DEV_DIS) { /* Disconnect I/O Ports */ sim_map_resource(pnp->io_base, pnp->io_size, RESOURCE_TYPE_IO, &scp300fdev, TRUE); @@ -321,7 +317,7 @@ static uint8 scp300f_rom[SCP300F_ROM_SIZE] = { if(write) { if(scp300f_info->rom_enabled) { - TRACE_PRINT(ROM_MSG, ("SCP300F: " ADDRESS_FORMAT " WR ROM[0x%05x]: Cannot write to ROM." NLP, PCX, Addr)); + sim_debug(ROM_MSG, &scp300f_dev, "SCP300F: " ADDRESS_FORMAT " WR ROM[0x%05x]: Cannot write to ROM.\n", PCX, Addr); } else { } return 0; @@ -370,38 +366,38 @@ static uint8 SCP300F_Read(const uint32 Addr) switch(Addr & SCP300F_IO_MASK) { case SCP300F_MPIC_0: case SCP300F_MPIC_1: - TRACE_PRINT(UART_MSG, ("SCP300F: " ADDRESS_FORMAT " Master 8259 DATA RD[%02x]: not implemented." NLP, PCX, Addr)); + sim_debug(UART_MSG, &scp300f_dev, "SCP300F: " ADDRESS_FORMAT " Master 8259 DATA RD[%02x]: not implemented.\n", PCX, Addr); break; case SCP300F_SPIC_0: case SCP300F_SPIC_1: - TRACE_PRINT(UART_MSG, ("SCP300F: " ADDRESS_FORMAT " Slave 8259 DATA RD[%02x]: not implemented." NLP, PCX, Addr)); + sim_debug(UART_MSG, &scp300f_dev, "SCP300F: " ADDRESS_FORMAT " Slave 8259 DATA RD[%02x]: not implemented.\n", PCX, Addr); break; case SCP300F_9513_DATA: - TRACE_PRINT(UART_MSG, ("SCP300F: " ADDRESS_FORMAT " 9513 DATA RD[%02x]: not implemented." NLP, PCX, Addr)); + sim_debug(UART_MSG, &scp300f_dev, "SCP300F: " ADDRESS_FORMAT " 9513 DATA RD[%02x]: not implemented.\n", PCX, Addr); break; case SCP300F_9513_STATUS: - TRACE_PRINT(UART_MSG, ("SCP300F: " ADDRESS_FORMAT " 9513 STAT RD[%02x]: not implemented." NLP, PCX, Addr)); + sim_debug(UART_MSG, &scp300f_dev, "SCP300F: " ADDRESS_FORMAT " 9513 STAT RD[%02x]: not implemented.\n", PCX, Addr); break; case SCP300F_UART_DATA: /* UART is handled by the 2SIO, if this gets called, then the 2SIO was not */ case SCP300F_UART_STATUS: /* configured properly. */ - TRACE_PRINT(VERBOSE_MSG, ("SCP300F: " ADDRESS_FORMAT " RD[%02x]: UART not configured properly." NLP, PCX, Addr)); + sim_debug(VERBOSE_MSG, &scp300f_dev, "SCP300F: " ADDRESS_FORMAT " RD[%02x]: UART not configured properly.\n", PCX, Addr); break; case SCP300F_PIO_DATA: - TRACE_PRINT(UART_MSG, ("SCP300F: " ADDRESS_FORMAT " PIO DATA RD[%02x]: not implemented." NLP, PCX, Addr)); + sim_debug(UART_MSG, &scp300f_dev, "SCP300F: " ADDRESS_FORMAT " PIO DATA RD[%02x]: not implemented.\n", PCX, Addr); break; case SCP300F_PIO_STATUS: - TRACE_PRINT(UART_MSG, ("SCP300F: " ADDRESS_FORMAT " PIO STATUS RD[%02x]: not implemented." NLP, PCX, Addr)); + sim_debug(UART_MSG, &scp300f_dev, "SCP300F: " ADDRESS_FORMAT " PIO STATUS RD[%02x]: not implemented.\n", PCX, Addr); break; case SCP300F_EPROM_DIS: - TRACE_PRINT(ROM_MSG, ("SCP300F: " ADDRESS_FORMAT " EPROM DIS RD: EPROM Disabled." NLP, PCX)); + sim_debug(ROM_MSG, &scp300f_dev, "SCP300F: " ADDRESS_FORMAT " EPROM DIS RD: EPROM Disabled.\n", PCX); scp300f_info->rom_enabled = 0; break; case SCP300F_SENSE_SW: /* Sense Switch */ cData = scp300f_sr; - TRACE_PRINT(VERBOSE_MSG, ("SCP300F: " ADDRESS_FORMAT " RD: Sense Switch=0x%02x" NLP, PCX, cData)); + sim_debug(VERBOSE_MSG, &scp300f_dev, "SCP300F: " ADDRESS_FORMAT " RD: Sense Switch=0x%02x\n", PCX, cData); break; default: - TRACE_PRINT(VERBOSE_MSG, ("SCP300F: " ADDRESS_FORMAT " RD[%02x]: not Implemented." NLP, PCX, Addr)); + sim_debug(VERBOSE_MSG, &scp300f_dev, "SCP300F: " ADDRESS_FORMAT " RD[%02x]: not Implemented.\n", PCX, Addr); break; } @@ -415,37 +411,37 @@ static uint8 SCP300F_Write(const uint32 Addr, uint8 cData) switch(Addr & SCP300F_IO_MASK) { case SCP300F_MPIC_0: case SCP300F_MPIC_1: - TRACE_PRINT(UART_MSG, ("SCP300F: " ADDRESS_FORMAT " Master 8259 DATA WR[%02x]=%02x: not implemented." NLP, PCX, Addr, cData)); + sim_debug(UART_MSG, &scp300f_dev, "SCP300F: " ADDRESS_FORMAT " Master 8259 DATA WR[%02x]=%02x: not implemented.\n", PCX, Addr, cData); break; case SCP300F_SPIC_0: case SCP300F_SPIC_1: - TRACE_PRINT(UART_MSG, ("SCP300F: " ADDRESS_FORMAT " Slave 8259 DATA WR[%02x]=%02x: not implemented." NLP, PCX, Addr, cData)); + sim_debug(UART_MSG, &scp300f_dev, "SCP300F: " ADDRESS_FORMAT " Slave 8259 DATA WR[%02x]=%02x: not implemented.\n", PCX, Addr, cData); break; case SCP300F_9513_DATA: - TRACE_PRINT(UART_MSG, ("SCP300F: " ADDRESS_FORMAT " 9513 DATA WR[%02x]=%02x: not implemented." NLP, PCX, Addr, cData)); + sim_debug(UART_MSG, &scp300f_dev, "SCP300F: " ADDRESS_FORMAT " 9513 DATA WR[%02x]=%02x: not implemented.\n", PCX, Addr, cData); break; case SCP300F_9513_STATUS: - TRACE_PRINT(UART_MSG, ("SCP300F: " ADDRESS_FORMAT " 9513 STAT WR[%02x]=%02x: not implemented." NLP, PCX, Addr, cData)); + sim_debug(UART_MSG, &scp300f_dev, "SCP300F: " ADDRESS_FORMAT " 9513 STAT WR[%02x]=%02x: not implemented.\n", PCX, Addr, cData); break; case SCP300F_UART_DATA: /* UART is handled by the 2SIO, if this gets called, then the 2SIO was not */ case SCP300F_UART_STATUS: /* configured properly. */ - TRACE_PRINT(UART_MSG, ("SCP300F: " ADDRESS_FORMAT " WR[%02x]: UART not configured properly." NLP, PCX, Addr)); + sim_debug(UART_MSG, &scp300f_dev, "SCP300F: " ADDRESS_FORMAT " WR[%02x]: UART not configured properly.\n", PCX, Addr); break; case SCP300F_PIO_DATA: - TRACE_PRINT(UART_MSG, ("SCP300F: " ADDRESS_FORMAT " PIO DATA WR[%02x]=%02x: not implemented." NLP, PCX, Addr, cData)); + sim_debug(UART_MSG, &scp300f_dev, "SCP300F: " ADDRESS_FORMAT " PIO DATA WR[%02x]=%02x: not implemented.\n", PCX, Addr, cData); break; case SCP300F_PIO_STATUS: - TRACE_PRINT(UART_MSG, ("SCP300F: " ADDRESS_FORMAT " WR[%02x]: Cannot write to PIO STATUS." NLP, PCX, Addr)); + sim_debug(UART_MSG, &scp300f_dev, "SCP300F: " ADDRESS_FORMAT " WR[%02x]: Cannot write to PIO STATUS.\n", PCX, Addr); break; case SCP300F_EPROM_DIS: - TRACE_PRINT(ROM_MSG, ("SCP300F: " ADDRESS_FORMAT " EPROM DIS WR: EPROM Disabled." NLP, PCX)); + sim_debug(ROM_MSG, &scp300f_dev, "SCP300F: " ADDRESS_FORMAT " EPROM DIS WR: EPROM Disabled.\n", PCX); scp300f_info->rom_enabled = 0; break; case SCP300F_SENSE_SW: - TRACE_PRINT(VERBOSE_MSG, ("SCP300F: " ADDRESS_FORMAT " WR[%02x]: Cannot write to SR." NLP, PCX, Addr)); + sim_debug(VERBOSE_MSG, &scp300f_dev, "SCP300F: " ADDRESS_FORMAT " WR[%02x]: Cannot write to SR.\n", PCX, Addr); break; default: - TRACE_PRINT(VERBOSE_MSG, ("SCP300F: " ADDRESS_FORMAT " WR[0x%02x]=0x%02x: not Implemented." NLP, PCX, Addr, cData)); + sim_debug(VERBOSE_MSG, &scp300f_dev, "SCP300F: " ADDRESS_FORMAT " WR[0x%02x]=0x%02x: not Implemented.\n", PCX, Addr, cData); break; } diff --git a/AltairZ80/s100_selchan.c b/AltairZ80/s100_selchan.c index b9a312cd..926a1b6f 100644 --- a/AltairZ80/s100_selchan.c +++ b/AltairZ80/s100_selchan.c @@ -109,10 +109,6 @@ static MTAB selchan_mod[] = { { 0 } }; -#define TRACE_PRINT(level, args) if(selchan_dev.dctrl & level) { \ - printf args; \ - } - /* Debug Flags */ static DEBTAB selchan_dt[] = { { "ERROR", ERROR_MSG }, @@ -167,18 +163,12 @@ static int32 selchandev(const int32 port, const int32 io, const int32 data) selchan_info->reg_cnt ++; if(selchan_info->reg_cnt == 4) { - TRACE_PRINT(VERBOSE_MSG, ("SELCHAN: " ADDRESS_FORMAT " DMA=0x%06x, Mode=0x%02x (%s, %s, %s)" NLP, - PCX, - selchan_info->dma_addr, - selchan_info->dma_mode, - selchan_info->dma_mode & SELCHAN_MODE_WRITE ? "WR" : "RD", - selchan_info->dma_mode & SELCHAN_MODE_IO ? "I/O" : "MEM", - selchan_info->dma_mode & SELCHAN_MODE_IO ? "FIX" : selchan_info->dma_mode & SELCHAN_MODE_CNT_UP ? "INC" : "DEC")); + sim_debug(VERBOSE_MSG, &selchan_dev, "SELCHAN: " ADDRESS_FORMAT " DMA=0x%06x, Mode=0x%02x (%s, %s, %s)\n", PCX, selchan_info->dma_addr, selchan_info->dma_mode, selchan_info->dma_mode & SELCHAN_MODE_WRITE ? "WR" : "RD", selchan_info->dma_mode & SELCHAN_MODE_IO ? "I/O" : "MEM", selchan_info->dma_mode & SELCHAN_MODE_IO ? "FIX" : selchan_info->dma_mode & SELCHAN_MODE_CNT_UP ? "INC" : "DEC"); } return 0; } else { - TRACE_PRINT(VERBOSE_MSG, ("SELCHAN: " ADDRESS_FORMAT " Reset" NLP, PCX)); + sim_debug(VERBOSE_MSG, &selchan_dev, "SELCHAN: " ADDRESS_FORMAT " Reset\n", PCX); selchan_info->reg_cnt = 0; return(0xFF); } @@ -199,9 +189,7 @@ int32 selchan_dma(uint8 *buf, uint32 len) printf("SELCHAN: " ADDRESS_FORMAT " I/O Not supported" NLP, PCX); return (-1); } else { - TRACE_PRINT(DMA_MSG, ("SELCHAN: " ADDRESS_FORMAT " DMA %s Transfer, len=%d" NLP, - PCX, - (selchan_info->dma_mode & SELCHAN_MODE_WRITE) ? "WR" : "RD", len)); + sim_debug(DMA_MSG, &selchan_dev, "SELCHAN: " ADDRESS_FORMAT " DMA %s Transfer, len=%d\n", PCX, (selchan_info->dma_mode & SELCHAN_MODE_WRITE) ? "WR" : "RD", len); for(i=0;idma_mode & SELCHAN_MODE_WRITE) { PutByteDMA(selchan_info->dma_addr + i, buf[i]); diff --git a/AltairZ80/s100_ss1.c b/AltairZ80/s100_ss1.c index 7a92b0a4..95184c05 100644 --- a/AltairZ80/s100_ss1.c +++ b/AltairZ80/s100_ss1.c @@ -207,10 +207,6 @@ static MTAB ss1_mod[] = { { 0 } }; -#define TRACE_PRINT(level, args) if(ss1_dev.dctrl & level) { \ - printf args; \ - } - /* Debug Flags */ static DEBTAB ss1_dt[] = { { "ERROR", ERROR_MSG }, @@ -306,10 +302,12 @@ static uint8 SS1_Read(const uint32 Addr) case SS1_M8259_L: if((ss1_pic[sel_pic].OCW3 & 0x03) == 0x03) { cData = ss1_pic[sel_pic].ISR; - TRACE_PRINT(PIC_MSG, ("SS1: " ADDRESS_FORMAT " RD: %s PIC ISR=0x%02x." NLP, PCX, (sel_pic ? "Slave " : "Master"), cData)); + sim_debug(PIC_MSG, &ss1_dev, "SS1: " ADDRESS_FORMAT + " RD: %s PIC ISR=0x%02x.\n", PCX, (sel_pic ? "Slave " : "Master"), cData); } else if((ss1_pic[sel_pic].OCW3 & 0x03) == 0x02) { cData = ss1_pic[sel_pic].IRR; - TRACE_PRINT(PIC_MSG, ("SS1: " ADDRESS_FORMAT " RD: %s PIC IRR=0x%02x." NLP, PCX, (sel_pic ? "Slave " : "Master"), cData)); + sim_debug(PIC_MSG, &ss1_dev, "SS1: " ADDRESS_FORMAT + " RD: %s PIC IRR=0x%02x.\n", PCX, (sel_pic ? "Slave " : "Master"), cData); } else { cData = 0xFF; } @@ -318,27 +316,32 @@ static uint8 SS1_Read(const uint32 Addr) sel_pic = SLAVE_PIC; case SS1_M8259_H: cData = ss1_pic[sel_pic].IMR; - TRACE_PRINT(PIC_MSG, ("SS1: " ADDRESS_FORMAT " RD: %s PIC IMR=0x%02x." NLP, PCX, (sel_pic ? "Slave " : "Master"), cData)); + sim_debug(PIC_MSG, &ss1_dev, "SS1: " ADDRESS_FORMAT + " RD: %s PIC IMR=0x%02x.\n", PCX, (sel_pic ? "Slave " : "Master"), cData); ss1_pic[sel_pic].IMR = cData; break; case SS1_8253_CTL: cData = ss1_tc[0].CTL; - TRACE_PRINT(TC_MSG, ("SS1: " ADDRESS_FORMAT " RD: TC CTL=0x%02x." NLP, PCX, cData)); + sim_debug(TC_MSG, &ss1_dev, "SS1: " ADDRESS_FORMAT + " RD: TC CTL=0x%02x.\n", PCX, cData); break; case SS1_8253_TC2: sel_tc++; case SS1_8253_TC1: sel_tc++; case SS1_8253_TC0: - TRACE_PRINT(TC_MSG, ("SS1: " ADDRESS_FORMAT " RD: TC [%d]=0x%02x." NLP, PCX, sel_tc, cData)); + sim_debug(TC_MSG, &ss1_dev, "SS1: " ADDRESS_FORMAT + " RD: TC [%d]=0x%02x.\n", PCX, sel_tc, cData); break; case SS1_9511A_DATA: case SS1_9511A_CMD: - TRACE_PRINT(MATH_MSG, ("SS1: " ADDRESS_FORMAT " RD: Math Coprocessor not Implemented." NLP, PCX)); + sim_debug(MATH_MSG, &ss1_dev, "SS1: " ADDRESS_FORMAT + " RD: Math Coprocessor not Implemented.\n", PCX); break; case SS1_RTC_CMD: cData = 0xFF; - TRACE_PRINT(RTC_MSG, ("SS1: " ADDRESS_FORMAT " RD: RTC Cmd=0x%02x." NLP, PCX, cData)); + sim_debug(RTC_MSG, &ss1_dev, "SS1: " ADDRESS_FORMAT + " RD: RTC Cmd=0x%02x.\n", PCX, cData); break; case SS1_RTC_DATA: time(&now); @@ -389,20 +392,24 @@ static uint8 SS1_Read(const uint32 Addr) cData = 0; break; } - TRACE_PRINT(RTC_MSG, ("SS1: " ADDRESS_FORMAT " RD: RTC Data[%x]=0x%02x." NLP, PCX, ss1_rtc[0].digit_sel, cData)); + sim_debug(RTC_MSG, &ss1_dev, "SS1: " ADDRESS_FORMAT + " RD: RTC Data[%x]=0x%02x.\n", PCX, ss1_rtc[0].digit_sel, cData); break; case SS1_UART_DATA: cData = sio0d(Addr, 0, 0); - TRACE_PRINT(UART_MSG, ("SS1: " ADDRESS_FORMAT " RD: UART Data=0x%02x." NLP, PCX, cData)); + sim_debug(UART_MSG, &ss1_dev, "SS1: " ADDRESS_FORMAT + " RD: UART Data=0x%02x.\n", PCX, cData); break; case SS1_UART_STAT: cData = sio0s(Addr, 0, 0); - TRACE_PRINT(UART_MSG, ("SS1: " ADDRESS_FORMAT " RD: UART Stat=0x%02x." NLP, PCX, cData)); + sim_debug(UART_MSG, &ss1_dev, "SS1: " ADDRESS_FORMAT + " RD: UART Stat=0x%02x.\n", PCX, cData); break; case SS1_UART_MODE: case SS1_UART_CMD: - TRACE_PRINT(UART_MSG, ("SS1: " ADDRESS_FORMAT " RD: UART not Implemented." NLP, PCX)); + sim_debug(UART_MSG, &ss1_dev, "SS1: " ADDRESS_FORMAT + " RD: UART not Implemented.\n", PCX); break; } @@ -427,15 +434,18 @@ static uint8 SS1_Write(const uint32 Addr, uint8 cData) sel_pic = SLAVE_PIC; case SS1_M8259_L: if(cData & 0x10) { - TRACE_PRINT(PIC_MSG, ("SS1: " ADDRESS_FORMAT " WR: %s PIC ICW1=0x%02x." NLP, PCX, (sel_pic ? "Slave " : "Master"), cData)); + sim_debug(PIC_MSG, &ss1_dev, "SS1: " ADDRESS_FORMAT + " WR: %s PIC ICW1=0x%02x.\n", PCX, (sel_pic ? "Slave " : "Master"), cData); ss1_pic[sel_pic].ICW[1] = cData; ss1_pic[sel_pic].config_cnt=1; } else { if(cData & 0x08) { /* OCW3 */ - TRACE_PRINT(PIC_MSG, ("SS1: " ADDRESS_FORMAT " WR: %s PIC OCW3=0x%02x." NLP, PCX, (sel_pic ? "Slave " : "Master"), cData)); + sim_debug(PIC_MSG, &ss1_dev, "SS1: " ADDRESS_FORMAT + " WR: %s PIC OCW3=0x%02x.\n", PCX, (sel_pic ? "Slave " : "Master"), cData); ss1_pic[sel_pic].OCW3 = cData; } else { /* OCW2 */ - TRACE_PRINT(PIC_MSG, ("SS1: " ADDRESS_FORMAT " WR: %s PIC OCW2=0x%02x." NLP, PCX, (sel_pic ? "Slave " : "Master"), cData)); + sim_debug(PIC_MSG, &ss1_dev, "SS1: " ADDRESS_FORMAT + " WR: %s PIC OCW2=0x%02x.\n", PCX, (sel_pic ? "Slave " : "Master"), cData); ss1_pic[sel_pic].OCW2 = cData; } } @@ -444,12 +454,12 @@ static uint8 SS1_Write(const uint32 Addr, uint8 cData) sel_pic = SLAVE_PIC; case SS1_M8259_H: if(ss1_pic[sel_pic].config_cnt == 0) { - TRACE_PRINT(PIC_MSG, ("SS1: " ADDRESS_FORMAT " WR: %s PIC IMR=0x%02x." NLP, PCX, (sel_pic ? "Slave " : "Master"), cData)); + sim_debug(PIC_MSG, &ss1_dev, "SS1: " ADDRESS_FORMAT " WR: %s PIC IMR=0x%02x.\n", PCX, (sel_pic ? "Slave " : "Master"), cData); ss1_pic[sel_pic].IMR = cData; generate_ss1_interrupt(); } else { ss1_pic[sel_pic].config_cnt++; - TRACE_PRINT(PIC_MSG, ("SS1: " ADDRESS_FORMAT " WR: %s PIC ICW%d=0x%02x." NLP, PCX, (sel_pic ? "Slave " : "Master"), ss1_pic[sel_pic].config_cnt, cData)); + sim_debug(PIC_MSG, &ss1_dev, "SS1: " ADDRESS_FORMAT " WR: %s PIC ICW%d=0x%02x.\n", PCX, (sel_pic ? "Slave " : "Master"), ss1_pic[sel_pic].config_cnt, cData); ss1_pic[sel_pic].ICW[ss1_pic[sel_pic].config_cnt] = cData; ss1_unit[0].u3 = ss1_pic[SLAVE_PIC].ICW[2]+TC0_IRQ_OFFSET; @@ -464,15 +474,22 @@ static uint8 SS1_Write(const uint32 Addr, uint8 cData) case SS1_8253_CTL: ss1_tc[0].CTL = cData; sel_timer = (ss1_tc[0].CTL & I8253_CTL_SC_MASK) >> 6; - TRACE_PRINT(TC_MSG, ("SS1: " ADDRESS_FORMAT " WR: TC CTL=0x%02x." NLP, PCX, ss1_tc[0].CTL)); + sim_debug(TC_MSG, &ss1_dev, "SS1: " ADDRESS_FORMAT + " WR: TC CTL=0x%02x.\n", + PCX, ss1_tc[0].CTL); if(ss1_tc[0].CTL & I8253_CTL_BCD) { - TRACE_PRINT(ERROR_MSG, ("SS1: " ADDRESS_FORMAT " Timer %d: BCD Mode not supported: TC CTL=0x%02x." NLP, PCX, sel_timer, ss1_tc[0].CTL)); + sim_debug(ERROR_MSG, &ss1_dev, "SS1: " ADDRESS_FORMAT + " Timer %d: BCD Mode not supported: TC CTL=0x%02x.\n", + PCX, sel_timer, ss1_tc[0].CTL); } ss1_tc[0].bcd[sel_timer] = (ss1_tc[0].CTL & I8253_CTL_BCD); ss1_tc[0].mode[sel_timer] = (ss1_tc[0].CTL & I8253_CTL_MODE_MASK) >> 1; ss1_tc[0].rl[sel_timer] = (ss1_tc[0].CTL & I8253_CTL_RL_MASK) >> 4; - TRACE_PRINT(TRACE_MSG, ("SS1: " ADDRESS_FORMAT " Timer %d: Mode: %d, RL=%d, %s." NLP, PCX, - sel_timer, ss1_tc[0].mode[sel_timer], ss1_tc[0].rl[sel_timer], ss1_tc[0].bcd[sel_timer] ? "BCD" : "Binary")); + sim_debug(TRACE_MSG, &ss1_dev, "SS1: " ADDRESS_FORMAT + " Timer %d: Mode: %d, RL=%d, %s.\n", + PCX, sel_timer, ss1_tc[0].mode[sel_timer], + ss1_tc[0].rl[sel_timer], + ss1_tc[0].bcd[sel_timer] ? "BCD" : "Binary"); newcount = 0; bc=0; break; @@ -497,38 +514,45 @@ static uint8 SS1_Write(const uint32 Addr, uint8 cData) sim_activate(&ss1_unit[sel_tc], newcount); } - TRACE_PRINT(TC_MSG, ("SS1: " ADDRESS_FORMAT " WR: TC [%d]=0x%02x." NLP, PCX, sel_tc, cData)); + sim_debug(TC_MSG, &ss1_dev, "SS1: " ADDRESS_FORMAT + " WR: TC [%d]=0x%02x.\n", PCX, sel_tc, cData); if(sel_tc == 0) { } break; case SS1_9511A_DATA: case SS1_9511A_CMD: - TRACE_PRINT(TRACE_MSG, ("SS1: " ADDRESS_FORMAT " WR: Math Coprocessor not Implemented." NLP, PCX)); + sim_debug(TRACE_MSG, &ss1_dev, "SS1: " ADDRESS_FORMAT + " WR: Math Coprocessor not Implemented.\n", PCX); break; case SS1_RTC_CMD: ss1_rtc[0].digit_sel = cData & 0x0F; ss1_rtc[0].flags = (cData >> 4) & 0x0F; - TRACE_PRINT(RTC_MSG, ("SS1: " ADDRESS_FORMAT " WR: RTC Cmd=0x%02x (%s%s%s SEL=%x)" NLP, - PCX, cData, - ss1_rtc[0].flags & 0x4 ? "HOLD " :"", - ss1_rtc[0].flags & 0x2 ? "WR" :"", - ss1_rtc[0].flags & 0x1 ? "RD" :"", - ss1_rtc[0].digit_sel)) + sim_debug(RTC_MSG, &ss1_dev, "SS1: " ADDRESS_FORMAT + " WR: RTC Cmd=0x%02x (%s%s%s SEL=%x)\n", + PCX, cData, + ss1_rtc[0].flags & 0x4 ? "HOLD " :"", + ss1_rtc[0].flags & 0x2 ? "WR" :"", + ss1_rtc[0].flags & 0x1 ? "RD" :"", + ss1_rtc[0].digit_sel); break; case SS1_RTC_DATA: - TRACE_PRINT(RTC_MSG, ("SS1: " ADDRESS_FORMAT " WR: RTC Data=0x%02x" NLP, PCX, cData)); + sim_debug(RTC_MSG, &ss1_dev, "SS1: " ADDRESS_FORMAT + " WR: RTC Data=0x%02x\n", PCX, cData); break; case SS1_UART_DATA: - TRACE_PRINT(UART_MSG, ("SS1: " ADDRESS_FORMAT " WR: UART Data=0x%02x." NLP, PCX, cData)); + sim_debug(UART_MSG, &ss1_dev, "SS1: " ADDRESS_FORMAT + " WR: UART Data=0x%02x.\n", PCX, cData); sio0d(Addr, 1, cData); break; case SS1_UART_STAT: - TRACE_PRINT(UART_MSG, ("SS1: " ADDRESS_FORMAT " WR: UART Stat=0x%02x." NLP, PCX, cData)); + sim_debug(UART_MSG, &ss1_dev, "SS1: " ADDRESS_FORMAT + " WR: UART Stat=0x%02x.\n", PCX, cData); sio0s(Addr, 1, cData); break; case SS1_UART_MODE: case SS1_UART_CMD: - TRACE_PRINT(TRACE_MSG, ("SS1: " ADDRESS_FORMAT " WR: UART not Implemented." NLP, PCX)); + sim_debug(TRACE_MSG, &ss1_dev, "SS1: " ADDRESS_FORMAT + " WR: UART not Implemented.\n", PCX); break; } @@ -564,22 +588,12 @@ static void generate_ss1_interrupt(void) if(irq_bit) { ss1_pic[pic].IRR |= (irq_bit << irq_index); irq = ss1_pic[pic].ICW[2]+irq_index; - TRACE_PRINT(IRQ_MSG, ("Handling interrupt on %s PIC: IMR=0x%02x, ISR=0x%02x, IRR=0x%02x, index=%d" NLP, - pic ? "SLAVE" : "MASTER", - ss1_pic[pic].IMR, - ss1_pic[pic].ISR, - ss1_pic[pic].IRR, - irq_index)); + sim_debug(IRQ_MSG, &ss1_dev, "Handling interrupt on %s PIC: IMR=0x%02x, ISR=0x%02x, IRR=0x%02x, index=%d\n", pic ? "SLAVE" : "MASTER", ss1_pic[pic].IMR, ss1_pic[pic].ISR, ss1_pic[pic].IRR, irq_index); cpu_raise_interrupt(irq); ss1_pic[pic].IRR &= ~(irq_bit << irq_index); ss1_pic[pic].ISR &= ~(irq_bit << irq_index); if(irq_pend & 0x7E) { -/* TRACE_PRINT(IRQ_MSG, ("Requeue interrupt on %s PIC: IMR=0x%02x, ISR=0x%02x, IRR=0x%02x, index=%d" NLP, - pic ? "SLAVE" : "MASTER", - ss1_pic[pic].IMR, - ss1_pic[pic].ISR, - ss1_pic[pic].IRR, - irq_index)); +/* sim_debug(IRQ_MSG, &ss1_dev, "Requeue interrupt on %s PIC: IMR=0x%02x, ISR=0x%02x, IRR=0x%02x, index=%d\n", pic ? "SLAVE" : "MASTER", ss1_pic[pic].IMR, ss1_pic[pic].ISR, ss1_pic[pic].IRR, irq_index); */ sim_activate(&ss1_unit[3], 1000); /* requeue, because more interrupts are pending. */ } @@ -607,7 +621,7 @@ static t_stat ss1_svc (UNIT *uptr) generate_ss1_interrupt(); sim_activate(uptr, 1000); /* requeue, because we still need to handle the timer interrupt. */ } else if((cData & 1) && ((ss1_pic[SLAVE_PIC].IMR & 0x40) == 0)) { - TRACE_PRINT(IRQ_MSG, ("SS1: " ADDRESS_FORMAT " Calling UART Tx ISR." NLP, PCX)); + sim_debug(IRQ_MSG, &ss1_dev, "SS1: " ADDRESS_FORMAT " Calling UART Tx ISR.\n", PCX); ss1_pic[SLAVE_PIC].ISR |= 0x40; generate_ss1_interrupt(); sim_activate(uptr, 1000); /* requeue, because we still need to handle the timer interrupt. */ @@ -626,15 +640,15 @@ static t_stat ss1_svc (UNIT *uptr) break; } if(ss1_tc[0].mode[uptr->u4] == 0x0) { - TRACE_PRINT(TC_MSG, ("SS1: " ADDRESS_FORMAT " Calling Timer%d ISR." NLP, PCX, uptr->u4)); + sim_debug(TC_MSG, &ss1_dev, "SS1: " ADDRESS_FORMAT " Calling Timer%d ISR.\n", PCX, uptr->u4); ss1_pic[SLAVE_PIC].ISR |= irq_bit; generate_ss1_interrupt(); } if(ss1_tc[0].mode[uptr->u4] == 0x3) { - TRACE_PRINT(TC_MSG, ("SS1: " ADDRESS_FORMAT " Calling Timer%d ISR." NLP, PCX, uptr->u4)); + sim_debug(TC_MSG, &ss1_dev, "SS1: " ADDRESS_FORMAT " Calling Timer%d ISR.\n", PCX, uptr->u4); ss1_pic[SLAVE_PIC].ISR |= irq_bit; generate_ss1_interrupt(); - TRACE_PRINT(TC_MSG, ("Timer %d, mode %d, reloading\n", uptr->u4, ss1_tc[0].mode[uptr->u4])); + sim_debug(TC_MSG, &ss1_dev, "Timer %d, mode %d, reloading\n", uptr->u4, ss1_tc[0].mode[uptr->u4]); sim_activate(uptr, 33280); } } diff --git a/AltairZ80/sim_imd.c b/AltairZ80/sim_imd.c index 3d746d93..b9884b25 100644 --- a/AltairZ80/sim_imd.c +++ b/AltairZ80/sim_imd.c @@ -361,6 +361,7 @@ t_stat diskCreate(FILE *fileref, char *ctlr_comment) DISK_INFO *myDisk = NULL; char *comment; char *curptr; + char *result; uint8 answer; int32 len, remaining; @@ -387,8 +388,8 @@ t_stat diskCreate(FILE *fileref, char *ctlr_comment) remaining = MAX_COMMENT_LEN; do { printf("IMD> "); - fgets(curptr, remaining - 3, stdin); - if (strcmp(curptr, ".\n") == 0) { + result = fgets(curptr, remaining - 3, stdin); + if ((result == NULL) || (strcmp(curptr, ".\n") == 0)) { remaining = 0; } else { len = strlen(curptr) - 1; @@ -409,7 +410,10 @@ t_stat diskCreate(FILE *fileref, char *ctlr_comment) #ifdef _WIN32 /* This might work under UNIX and/or VMS since this POSIX, but I haven't tried it. */ _chsize(_fileno(fileref), ftell (fileref)); #else - ftruncate(fileno(fileref), ftell (fileref)); + if (ftruncate(fileno(fileref), ftell (fileref)) == -1) { + printf("SIM_IMD: Error overwriting disk image.\n"); + return(SCPE_OPENERR); + } #endif fprintf(fileref, "IMD SIMH %s %s\n", __DATE__, __TIME__); @@ -722,7 +726,11 @@ t_stat trackWrite(DISK_INFO *myDisk, #ifdef _WIN32 /* This might work under UNIX and/or VMS since this POSIX, but I haven't tried it. */ _chsize(_fileno(fileref), ftell (fileref)); #else - ftruncate(fileno(fileref), ftell (fileref)); + if (ftruncate(fileno(fileref), ftell (fileref)) == -1) { + printf("Disk truncation failed." NLP); + *flags |= IMD_DISK_IO_ERROR_GENERAL; + return(SCPE_IOERR); + } #endif /* Flush and re-parse the IMD file. */ fflush(fileref); diff --git a/AltairZ80/vfdhd.c b/AltairZ80/vfdhd.c index 11db5b54..bc03ed44 100644 --- a/AltairZ80/vfdhd.c +++ b/AltairZ80/vfdhd.c @@ -181,10 +181,6 @@ static MTAB vfdhd_mod[] = { { 0 } }; -#define TRACE_PRINT(level, args) if(vfdhd_dev.dctrl & level) { \ - printf args; \ - } - /* Debug Flags */ static DEBTAB vfdhd_dt[] = { { "ERROR", ERROR_MSG }, @@ -392,7 +388,7 @@ static uint8 VFDHD_Read(const uint32 Addr) cData |= (pDrive->seek_complete & 1) << 4; /* [4] Seek Complete (HD) */ cData |= (pDrive->sync_lost & 1) << 5; /* [5] Loss of Sync (HD) */ cData |= 0xC0; /* [7:6] Reserved (pulled up) */ - TRACE_PRINT(STATUS_MSG, ("VFDHD: " ADDRESS_FORMAT " RD S0 = 0x%02x" NLP, PCX, cData)); + sim_debug(STATUS_MSG, &vfdhd_dev, "VFDHD: " ADDRESS_FORMAT " RD S0 = 0x%02x\n", PCX, cData); break; case FDHD_CTRL_STATUS1: vfdhd_info->floppy_sel = (vfdhd_info->sel_drive == 0) ? 0 : 1; @@ -407,12 +403,12 @@ static uint8 VFDHD_Read(const uint32 Addr) vfdhd_info->controller_busy = 0; - TRACE_PRINT(STATUS_MSG, ("VFDHD: " ADDRESS_FORMAT " RD S1 = 0x%02x" NLP, PCX, cData)); + sim_debug(STATUS_MSG, &vfdhd_dev, "VFDHD: " ADDRESS_FORMAT " RD S1 = 0x%02x\n", PCX, cData); break; case FDHD_DATA: /* DBG_PRINT(("VFDHD: " ADDRESS_FORMAT " RD Data" NLP, PCX)); */ if(vfdhd_info->datacount+40 >= VFDHD_RAW_LEN) { - TRACE_PRINT(ERROR_MSG, ("VFDHD: " ADDRESS_FORMAT " Illegal data count %d." NLP, PCX, vfdhd_info->datacount)); + sim_debug(ERROR_MSG, &vfdhd_dev, "VFDHD: " ADDRESS_FORMAT " Illegal data count %d.\n", PCX, vfdhd_info->datacount); vfdhd_info->datacount = 0; } cData = sdata.raw[vfdhd_info->datacount+40]; @@ -422,7 +418,7 @@ static uint8 VFDHD_Read(const uint32 Addr) /* DBG_PRINT(("VFDHD: " ADDRESS_FORMAT " RD Data Sector %d[%03d]: 0x%02x" NLP, PCX, pDrive->sector, vfdhd_info->datacount, cData)); */ break; case FDHD_RESET_START: /* Reset */ - TRACE_PRINT(CMD_MSG, ("VFDHD: " ADDRESS_FORMAT " Reset" NLP, PCX)); + sim_debug(CMD_MSG, &vfdhd_dev, "VFDHD: " ADDRESS_FORMAT " Reset\n", PCX); vfdhd_info->datacount = 0; cData = 0xFF; /* Return High-Z data */ break; @@ -445,14 +441,7 @@ static uint8 VFDHD_Write(const uint32 Addr, uint8 cData) vfdhd_info->direction = (cData >> 6) & 1; vfdhd_info->rwc = (cData >> 7) & 1; - TRACE_PRINT(WR_DATA_MSG, ("VFDHD: " ADDRESS_FORMAT " WR C0=%02x: sel_drive=%d, head=%d, step=%d, dir=%d, rwc=%d" NLP, - PCX, - cData, - vfdhd_info->sel_drive, - vfdhd_info->head, - vfdhd_info->step, - vfdhd_info->direction, - vfdhd_info->rwc)); + sim_debug(WR_DATA_MSG, &vfdhd_dev, "VFDHD: " ADDRESS_FORMAT " WR C0=%02x: sel_drive=%d, head=%d, step=%d, dir=%d, rwc=%d\n", PCX, cData, vfdhd_info->sel_drive, vfdhd_info->head, vfdhd_info->step, vfdhd_info->direction, vfdhd_info->rwc); if(vfdhd_info->step == 1) { if(vfdhd_info->direction == 1) { /* Step IN */ @@ -462,8 +451,7 @@ static uint8 VFDHD_Write(const uint32 Addr, uint8 cData) pDrive->track--; } } - TRACE_PRINT(SEEK_MSG, ("VFDHD: " ADDRESS_FORMAT " Drive %d on track %d" NLP, - PCX, vfdhd_info->sel_drive, pDrive->track)); + sim_debug(SEEK_MSG, &vfdhd_dev, "VFDHD: " ADDRESS_FORMAT " Drive %d on track %d\n", PCX, vfdhd_info->sel_drive, pDrive->track); } break; @@ -473,8 +461,7 @@ static uint8 VFDHD_Write(const uint32 Addr, uint8 cData) vfdhd_info->ecc_enable = (cData >> 6) & 1; vfdhd_info->precomp = (cData >> 7) & 1; if(cData == 0xFF) { - TRACE_PRINT(SEEK_MSG, ("VFDHD: " ADDRESS_FORMAT " Home Disk %d" NLP, - PCX, vfdhd_info->sel_drive)); + sim_debug(SEEK_MSG, &vfdhd_dev, "VFDHD: " ADDRESS_FORMAT " Home Disk %d\n", PCX, vfdhd_info->sel_drive); pDrive->track = 0; } DBG_PRINT(("VFDHD: " ADDRESS_FORMAT " WR C1=%02x: sector=%d, read=%d, ecc_en=%d, precomp=%d" NLP, @@ -490,20 +477,20 @@ static uint8 VFDHD_Write(const uint32 Addr, uint8 cData) #ifdef USE_VGI if(vfdhd_info->sel_drive > 0) { /* Floppy */ if(vfdhd_info->datacount >= VFDHD_RAW_LEN) { - TRACE_PRINT(ERROR_MSG, ("VFDHD: " ADDRESS_FORMAT " Illegal data count %d." NLP, PCX, vfdhd_info->datacount)); + sim_debug(ERROR_MSG, &vfdhd_dev, "VFDHD: " ADDRESS_FORMAT " Illegal data count %d.\n", PCX, vfdhd_info->datacount); vfdhd_info->datacount = 0; } sdata.raw[vfdhd_info->datacount] = cData; } else { /* Hard */ if(vfdhd_info->datacount+10 >= VFDHD_RAW_LEN) { - TRACE_PRINT(ERROR_MSG, ("VFDHD: " ADDRESS_FORMAT " Illegal data count %d." NLP, PCX, vfdhd_info->datacount)); + sim_debug(ERROR_MSG, &vfdhd_dev, "VFDHD: " ADDRESS_FORMAT " Illegal data count %d.\n", PCX, vfdhd_info->datacount); vfdhd_info->datacount = 0; } sdata.raw[vfdhd_info->datacount+10] = cData; } #else if((vfdhd_info->datacount-13 >= VFDHD_RAW_LEN) || (vfdhd_info->datacount < 13)) { - TRACE_PRINT(ERROR_MSG, ("VFDHD: " ADDRESS_FORMAT " Illegal data count %d." NLP, PCX, vfdhd_info->datacount)); + sim_debug(ERROR_MSG, &vfdhd_dev, "VFDHD: " ADDRESS_FORMAT " Illegal data count %d.\n", PCX, vfdhd_info->datacount); vfdhd_info->datacount = 13; } sdata.u.data[vfdhd_info->datacount-13] = cData; @@ -513,7 +500,7 @@ static uint8 VFDHD_Write(const uint32 Addr, uint8 cData) break; case FDHD_RESET_START: - TRACE_PRINT(CMD_MSG, ("VFDHD: " ADDRESS_FORMAT " Start Command" NLP, PCX)); + sim_debug(CMD_MSG, &vfdhd_dev, "VFDHD: " ADDRESS_FORMAT " Start Command\n", PCX); VFDHD_Command(); break; } @@ -547,14 +534,9 @@ static void VFDHD_Command(void) if(vfdhd_info->read == 1) { /* Perform a Read operation */ unsigned int i, checksum; - uint32 readlen; + unsigned int readlen; - TRACE_PRINT(RD_DATA_MSG, ("VFDHD: " ADDRESS_FORMAT " RD: Drive=%d, Track=%d, Head=%d, Sector=%d" NLP, - PCX, - vfdhd_info->sel_drive, - pDrive->track, - vfdhd_info->head, - vfdhd_info->sector)); + sim_debug(RD_DATA_MSG, &vfdhd_dev, "VFDHD: " ADDRESS_FORMAT " RD: Drive=%d, Track=%d, Head=%d, Sector=%d\n", PCX, vfdhd_info->sel_drive, pDrive->track, vfdhd_info->head, vfdhd_info->sector); /* Clear out unused portion of sector. */ memset(&sdata.u.unused[0], 0x00, 10); @@ -597,7 +579,7 @@ static void VFDHD_Command(void) sim_fseek((pDrive->uptr)->fileref, sec_offset, SEEK_SET); rtn = sim_fread(&sdata.u.sync, 1, 274, /*VFDHD_SECTOR_LEN,*/ (pDrive->uptr)->fileref); if (rtn != 274) { - TRACE_PRINT(ERROR_MSG, ("VFDHD: " ADDRESS_FORMAT " READ: sim_fread error." NLP, PCX)); + sim_debug(ERROR_MSG, &vfdhd_dev, "VFDHD: " ADDRESS_FORMAT " READ: sim_fread error.\n", PCX); } memset(&sdata.u.preamble, 0, 40); @@ -619,14 +601,9 @@ static void VFDHD_Command(void) } } else { /* Perform a Write operation */ - uint32 writelen; + unsigned int writelen; - TRACE_PRINT(WR_DATA_MSG, ("VFDHD: " ADDRESS_FORMAT " WR: Drive=%d, Track=%d, Head=%d, Sector=%d" NLP, - PCX, - vfdhd_info->sel_drive, - pDrive->track, - vfdhd_info->head, - vfdhd_info->sector)); + sim_debug(WR_DATA_MSG, &vfdhd_dev, "VFDHD: " ADDRESS_FORMAT " WR: Drive=%d, Track=%d, Head=%d, Sector=%d\n", PCX, vfdhd_info->sel_drive, pDrive->track, vfdhd_info->head, vfdhd_info->sector); #ifdef USE_VGI #else diff --git a/AltairZ80/wd179x.c b/AltairZ80/wd179x.c index 743e779a..034d7e80 100644 --- a/AltairZ80/wd179x.c +++ b/AltairZ80/wd179x.c @@ -199,6 +199,7 @@ uint8 floorlog2(unsigned int n); WD179X_INFO wd179x_info_data = { { 0x0, 0, 0x30, 4 } }; WD179X_INFO *wd179x_info = &wd179x_info_data; +WD179X_INFO_PUB *wd179x_infop = (WD179X_INFO_PUB *)&wd179x_info_data; static UNIT wd179x_unit[] = { { UDATA (&wd179x_svc, UNIT_FIX + UNIT_ATTABLE + UNIT_DISABLE + UNIT_ROABLE, WD179X_CAPACITY), 58200 }, @@ -218,10 +219,6 @@ static MTAB wd179x_mod[] = { { 0 } }; -#define TRACE_PRINT(level, args) if(wd179x_dev.dctrl & level) { \ - printf args; \ - } - /* Debug Flags */ static DEBTAB wd179x_dt[] = { { "ERROR", ERROR_MSG }, @@ -280,19 +277,21 @@ void wd179x_external_restore(void) WD179X_DRIVE_INFO *pDrive; if(wd179x_info->sel_drive >= WD179X_MAX_DRIVES) { - TRACE_PRINT(ERROR_MSG, ("WD179X: " ADDRESS_FORMAT " Illegal drive selected, cannot restore." NLP, PCX)) + sim_debug(ERROR_MSG, &wd179x_dev, "WD179X: " ADDRESS_FORMAT + " Illegal drive selected, cannot restore.\n", PCX); return; } pDrive = &wd179x_info->drive[wd179x_info->sel_drive]; if(pDrive->uptr == NULL) { - TRACE_PRINT(ERROR_MSG, ("WD179X: " ADDRESS_FORMAT " No drive selected, cannot restore." NLP, PCX)) + sim_debug(ERROR_MSG, &wd179x_dev, "WD179X: " ADDRESS_FORMAT + " No drive selected, cannot restore.\n", PCX); return; } - TRACE_PRINT(SEEK_MSG, - ("WD179X[%d]: " ADDRESS_FORMAT " External Restore drive to track 0" NLP, wd179x_info->sel_drive, PCX)) + sim_debug(SEEK_MSG, &wd179x_dev, "WD179X[%d]: " ADDRESS_FORMAT + " External Restore drive to track 0\n", wd179x_info->sel_drive, PCX); pDrive->track = 0; @@ -445,8 +444,8 @@ uint8 WD179X_Read(const uint32 Addr) { uint8 cData; WD179X_DRIVE_INFO *pDrive; - uint32 flags = 0; - uint32 readlen; + unsigned int flags = 0; + unsigned int readlen; int status; if(wd179x_info->sel_drive >= WD179X_MAX_DRIVES) { @@ -476,19 +475,19 @@ uint8 WD179X_Read(const uint32 Addr) } cData = (pDrive->ready == 0) ? WD179X_STAT_NOT_READY : 0; cData |= wd179x_info->fdc_status; /* Status Register */ - TRACE_PRINT(STATUS_MSG, - ("WD179X: " ADDRESS_FORMAT " RD STATUS = 0x%02x" NLP, PCX, cData)) + sim_debug(STATUS_MSG, &wd179x_dev, "WD179X: " ADDRESS_FORMAT + " RD STATUS = 0x%02x\n", PCX, cData); wd179x_info->intrq = 0; break; case WD179X_TRACK: cData = pDrive->track; - TRACE_PRINT(STATUS_MSG, - ("WD179X: " ADDRESS_FORMAT " RD TRACK = 0x%02x" NLP, PCX, cData)) + sim_debug(STATUS_MSG, &wd179x_dev, "WD179X: " ADDRESS_FORMAT + " RD TRACK = 0x%02x\n", PCX, cData); break; case WD179X_SECTOR: cData = wd179x_info->fdc_sector; - TRACE_PRINT(STATUS_MSG, - ("WD179X: " ADDRESS_FORMAT " RD SECT = 0x%02x" NLP, PCX, cData)) + sim_debug(STATUS_MSG, &wd179x_dev, "WD179X: " ADDRESS_FORMAT + " RD SECT = 0x%02x\n", PCX, cData); break; case WD179X_DATA: cData = 0xFF; /* Return High-Z data */ @@ -496,8 +495,10 @@ uint8 WD179X_Read(const uint32 Addr) if(wd179x_info->fdc_dataindex < wd179x_info->fdc_datacount) { cData = sdata.raw[wd179x_info->fdc_dataindex]; if(wd179x_info->fdc_read_addr == TRUE) { - TRACE_PRINT(STATUS_MSG, - ("WD179X[%d]: " ADDRESS_FORMAT " READ_ADDR[%d] = 0x%02x" NLP, wd179x_info->sel_drive, PCX, wd179x_info->fdc_dataindex, cData)) + sim_debug(STATUS_MSG, &wd179x_dev, "WD179X[%d]: " ADDRESS_FORMAT + " READ_ADDR[%d] = 0x%02x\n", + wd179x_info->sel_drive, PCX, + wd179x_info->fdc_dataindex, cData); } wd179x_info->fdc_dataindex++; @@ -514,21 +515,13 @@ uint8 WD179X_Read(const uint32 Addr) wd179x_info->fdc_sec_len = floorlog2( pDrive->imd->track[pDrive->track][wd179x_info->fdc_head].sectsize) - 7; if((wd179x_info->fdc_sec_len == 0xF8) || (wd179x_info->fdc_sec_len > WD179X_MAX_SEC_LEN)) { /* Error calculating N or N too large */ - TRACE_PRINT(ERROR_MSG, ("WD179X[%d]: " ADDRESS_FORMAT " Invalid sector size!" NLP, - wd179x_info->sel_drive, PCX)); + sim_debug(ERROR_MSG, &wd179x_dev, "WD179X[%d]: " ADDRESS_FORMAT " Invalid sector size!\n", wd179x_info->sel_drive, PCX); wd179x_info->fdc_sec_len = 0; return cData; } wd179x_info->fdc_sector ++; - TRACE_PRINT(RD_DATA_MSG, ("WD179X[%d]: " ADDRESS_FORMAT " MULTI_READ_REC, T:%d/S:%d/N:%d, %s, len=%d" NLP, - wd179x_info->sel_drive, - PCX, - pDrive->track, - wd179x_info->fdc_head, - wd179x_info->fdc_sector, - wd179x_info->ddens ? "DD" : "SD", - 128 << wd179x_info->fdc_sec_len)); + sim_debug(RD_DATA_MSG, &wd179x_dev, "WD179X[%d]: " ADDRESS_FORMAT " MULTI_READ_REC, T:%d/S:%d/N:%d, %s, len=%d\n", wd179x_info->sel_drive, PCX, pDrive->track, wd179x_info->fdc_head, wd179x_info->fdc_sector, wd179x_info->ddens ? "DD" : "SD", 128 << wd179x_info->fdc_sec_len); status = sectRead(pDrive->imd, pDrive->track, @@ -578,8 +571,8 @@ static uint8 Do1793Command(uint8 cCommand) { uint8 result = 0; WD179X_DRIVE_INFO *pDrive; - uint32 flags = 0; - uint32 readlen; + unsigned int flags = 0; + unsigned int readlen; int status; if(wd179x_info->sel_drive >= WD179X_MAX_DRIVES) { @@ -594,8 +587,9 @@ static uint8 Do1793Command(uint8 cCommand) if(wd179x_info->fdc_status & WD179X_STAT_BUSY) { if(((cCommand & 0xF0) != WD179X_FORCE_INTR)) { /* && ((cCommand & 0xF0) != WD179X_RESTORE)) { */ - TRACE_PRINT(ERROR_MSG, ("WD179X[%d]: " ADDRESS_FORMAT " ERROR: Command 0x%02x ignored because controller is BUSY\n" NLP, - wd179x_info->sel_drive, PCX, cCommand)); + sim_debug(ERROR_MSG, &wd179x_dev, "WD179X[%d]: " ADDRESS_FORMAT + " ERROR: Command 0x%02x ignored because controller is BUSY\n\n", + wd179x_info->sel_drive, PCX, cCommand); } return 0xFF; } @@ -617,7 +611,7 @@ static uint8 Do1793Command(uint8 cCommand) wd179x_info->fdc_status |= WD179X_STAT_BUSY; /* Set BUSY */ wd179x_info->fdc_status &= ~(WD179X_STAT_CRC_ERROR | WD179X_STAT_SEEK_ERROR | WD179X_STAT_DRQ); wd179x_info->intrq = 0; - wd179x_info->hld = cCommand && 0x08; + wd179x_info->hld = cCommand & 0x08; wd179x_info->verify = cCommand & 0x04; break; /* Type II Commands */ @@ -648,19 +642,26 @@ static uint8 Do1793Command(uint8 cCommand) switch(cCommand & 0xF0) { /* Type I Commands */ case WD179X_RESTORE: - TRACE_PRINT(CMD_MSG, ("WD179X[%d]: " ADDRESS_FORMAT " CMD=RESTORE %s" NLP, wd179x_info->sel_drive, PCX, wd179x_info->verify ? "[VERIFY]" : "")); + sim_debug(CMD_MSG, &wd179x_dev, "WD179X[%d]: " ADDRESS_FORMAT + " CMD=RESTORE %s\n", wd179x_info->sel_drive, PCX, + wd179x_info->verify ? "[VERIFY]" : ""); pDrive->track = 0; wd179x_info->intrq = 1; break; case WD179X_SEEK: - TRACE_PRINT(SEEK_MSG, ("WD179X[%d]: " ADDRESS_FORMAT " CMD=SEEK, track=%d, new=%d" NLP, wd179x_info->sel_drive, PCX, pDrive->track, wd179x_info->fdc_data)); + sim_debug(SEEK_MSG, &wd179x_dev, "WD179X[%d]: " ADDRESS_FORMAT + " CMD=SEEK, track=%d, new=%d\n", wd179x_info->sel_drive, + PCX, pDrive->track, wd179x_info->fdc_data); pDrive->track = wd179x_info->fdc_data; break; case WD179X_STEP: - TRACE_PRINT(SEEK_MSG, ("WD179X[%d]: " ADDRESS_FORMAT " CMD=STEP" NLP, wd179x_info->sel_drive, PCX)); + sim_debug(SEEK_MSG, &wd179x_dev, "WD179X[%d]: " ADDRESS_FORMAT + " CMD=STEP\n", wd179x_info->sel_drive, PCX); break; case WD179X_STEP_U: - TRACE_PRINT(SEEK_MSG, ("WD179X[%d]: " ADDRESS_FORMAT " CMD=STEP_U dir=%d" NLP, wd179x_info->sel_drive, PCX, wd179x_info->step_dir)); + sim_debug(SEEK_MSG, &wd179x_dev, "WD179X[%d]: " ADDRESS_FORMAT + " CMD=STEP_U dir=%d\n", wd179x_info->sel_drive, + PCX, wd179x_info->step_dir); if(wd179x_info->step_dir == 1) { if (pDrive->track < 255) pDrive->track++; @@ -668,26 +669,30 @@ static uint8 Do1793Command(uint8 cCommand) if (pDrive->track > 0) pDrive->track--; } else { - TRACE_PRINT(ERROR_MSG, ("WD179X[%d]: " ADDRESS_FORMAT " ERROR: undefined direction for STEP" NLP, wd179x_info->sel_drive, PCX)); + sim_debug(ERROR_MSG, &wd179x_dev, "WD179X[%d]: " ADDRESS_FORMAT + " ERROR: undefined direction for STEP\n", + wd179x_info->sel_drive, PCX); } break; case WD179X_STEP_IN: - TRACE_PRINT(SEEK_MSG, ("WD179X[%d]: " ADDRESS_FORMAT " CMD=STEP_IN" NLP, wd179x_info->sel_drive, PCX)); + sim_debug(SEEK_MSG, &wd179x_dev, "WD179X[%d]: " ADDRESS_FORMAT + " CMD=STEP_IN\n", wd179x_info->sel_drive, PCX); break; case WD179X_STEP_IN_U: if (pDrive->track < 255) pDrive->track++; wd179x_info->step_dir = 1; - TRACE_PRINT(SEEK_MSG, ("WD179X[%d]: " ADDRESS_FORMAT " CMD=STEP_IN_U, Track=%d" NLP, - wd179x_info->sel_drive, PCX, pDrive->track)); + sim_debug(SEEK_MSG, &wd179x_dev, "WD179X[%d]: " ADDRESS_FORMAT + " CMD=STEP_IN_U, Track=%d\n", wd179x_info->sel_drive, + PCX, pDrive->track); break; case WD179X_STEP_OUT: - TRACE_PRINT(SEEK_MSG, ("WD179X[%d]: " ADDRESS_FORMAT " CMD=STEP_OUT" NLP, - wd179x_info->sel_drive, PCX)); + sim_debug(SEEK_MSG, &wd179x_dev, "WD179X[%d]: " ADDRESS_FORMAT + " CMD=STEP_OUT\n", wd179x_info->sel_drive, PCX); break; case WD179X_STEP_OUT_U: - TRACE_PRINT(SEEK_MSG, ("WD179X[%d]: " ADDRESS_FORMAT " CMD=STEP_OUT_U" NLP, - wd179x_info->sel_drive, PCX)); + sim_debug(SEEK_MSG, &wd179x_dev, "WD179X[%d]: " ADDRESS_FORMAT + " CMD=STEP_OUT_U\n", wd179x_info->sel_drive, PCX); if (pDrive->track > 0) pDrive->track--; wd179x_info->step_dir = -1; @@ -699,8 +704,8 @@ static uint8 Do1793Command(uint8 cCommand) wd179x_info->fdc_sec_len = floorlog2( pDrive->imd->track[pDrive->track][wd179x_info->fdc_head].sectsize) - 7; if((wd179x_info->fdc_sec_len == 0xF8) || (wd179x_info->fdc_sec_len > WD179X_MAX_SEC_LEN)) { /* Error calculating N or N too large */ - TRACE_PRINT(ERROR_MSG, ("WD179X[%d]: " ADDRESS_FORMAT " Invalid sector size!" NLP, - wd179x_info->sel_drive, PCX)); + sim_debug(ERROR_MSG, &wd179x_dev, "WD179X[%d]: " ADDRESS_FORMAT + " Invalid sector size!\n", wd179x_info->sel_drive, PCX); wd179x_info->fdc_status |= WD179X_STAT_NOT_FOUND; /* Sector not found */ wd179x_info->fdc_status &= ~WD179X_STAT_BUSY; wd179x_info->intrq = 1; @@ -710,14 +715,12 @@ static uint8 Do1793Command(uint8 cCommand) } wd179x_info->fdc_multiple = (cCommand & 0x10) ? TRUE : FALSE; - TRACE_PRINT(RD_DATA_MSG, ("WD179X[%d]: " ADDRESS_FORMAT " CMD=READ_REC, T:%d/S:%d/N:%d, %s, %s len=%d" NLP, - wd179x_info->sel_drive, - PCX, pDrive->track, - wd179x_info->fdc_head, - wd179x_info->fdc_sector, - wd179x_info->fdc_multiple ? "Multiple" : "Single", - wd179x_info->ddens ? "DD" : "SD", - 128 << wd179x_info->fdc_sec_len)); + sim_debug(RD_DATA_MSG, &wd179x_dev, "WD179X[%d]: " ADDRESS_FORMAT + " CMD=READ_REC, T:%d/S:%d/N:%d, %s, %s len=%d\n", + wd179x_info->sel_drive, PCX, pDrive->track, + wd179x_info->fdc_head, wd179x_info->fdc_sector, + wd179x_info->fdc_multiple ? "Multiple" : "Single", + wd179x_info->ddens ? "DD" : "SD", 128 << wd179x_info->fdc_sec_len); if(IMD_MODE_MFM(pDrive->imd->track[pDrive->track][wd179x_info->fdc_head].mode) != (wd179x_info->ddens)) { wd179x_info->fdc_status |= WD179X_STAT_NOT_FOUND; /* Sector not found */ @@ -756,26 +759,21 @@ static uint8 Do1793Command(uint8 cCommand) } break; case WD179X_WRITE_RECS: - TRACE_PRINT(ERROR_MSG, ("WD179X[%d]: " ADDRESS_FORMAT " Error: WRITE_RECS not implemented." NLP, - wd179x_info->sel_drive, PCX)); + sim_debug(ERROR_MSG, &wd179x_dev, "WD179X[%d]: " ADDRESS_FORMAT + " Error: WRITE_RECS not implemented.\n", wd179x_info->sel_drive, PCX); break; case WD179X_WRITE_REC: /* Compute Sector Size */ wd179x_info->fdc_sec_len = floorlog2( pDrive->imd->track[pDrive->track][wd179x_info->fdc_head].sectsize) - 7; if((wd179x_info->fdc_sec_len == 0xF8) || (wd179x_info->fdc_sec_len > WD179X_MAX_SEC_LEN)) { /* Error calculating N or N too large */ - TRACE_PRINT(ERROR_MSG, ("WD179X[%d]: " ADDRESS_FORMAT " Invalid sector size!" NLP, - wd179x_info->sel_drive, PCX)); + sim_debug(ERROR_MSG, &wd179x_dev, "WD179X[%d]: " ADDRESS_FORMAT + " Invalid sector size!\n", wd179x_info->sel_drive, PCX); wd179x_info->fdc_sec_len = 0; } - TRACE_PRINT(WR_DATA_MSG, ("WD179X[%d]: " ADDRESS_FORMAT " CMD=WRITE_REC, T:%d/S:%d/N:%d, %s." NLP, - wd179x_info->sel_drive, - PCX, - pDrive->track, - wd179x_info->fdc_head, - wd179x_info->fdc_sector, - (cCommand & 0x10) ? "Multiple" : "Single")); + sim_debug(WR_DATA_MSG, &wd179x_dev, "WD179X[%d]: " ADDRESS_FORMAT + " CMD=WRITE_REC, T:%d/S:%d/N:%d, %s.\n", wd179x_info->sel_drive, PCX, pDrive->track, wd179x_info->fdc_head, wd179x_info->fdc_sector, (cCommand & 0x10) ? "Multiple" : "Single"); wd179x_info->fdc_status |= (WD179X_STAT_DRQ); /* Set DRQ */ wd179x_info->drq = 1; wd179x_info->fdc_datacount = 128 << wd179x_info->fdc_sec_len; @@ -789,12 +787,9 @@ static uint8 Do1793Command(uint8 cCommand) break; /* Type III Commands */ case WD179X_READ_ADDR: - TRACE_PRINT(RD_DATA_MSG, ("WD179X[%d]: " ADDRESS_FORMAT " CMD=READ_ADDR, T:%d/S:%d, %s" NLP, - wd179x_info->sel_drive, - PCX, - pDrive->track, - wd179x_info->fdc_head, - wd179x_info->ddens ? "DD" : "SD")); + sim_debug(RD_DATA_MSG, &wd179x_dev, "WD179X[%d]: " ADDRESS_FORMAT + " CMD=READ_ADDR, T:%d/S:%d, %s\n", wd179x_info->sel_drive, + PCX, pDrive->track, wd179x_info->fdc_head, wd179x_info->ddens ? "DD" : "SD"); /* For some reason 86-DOS tries to use this track, force it to 0. Need to investigate this more. */ if (pDrive->track == 0xFF) @@ -804,8 +799,8 @@ static uint8 Do1793Command(uint8 cCommand) wd179x_info->fdc_sec_len = floorlog2( pDrive->imd->track[pDrive->track][wd179x_info->fdc_head].sectsize) - 7; if((wd179x_info->fdc_sec_len == 0xF8) || (wd179x_info->fdc_sec_len > WD179X_MAX_SEC_LEN)) { /* Error calculating N or N too large */ - TRACE_PRINT(ERROR_MSG, ("WD179X[%d]: " ADDRESS_FORMAT " Invalid sector size!" NLP, - wd179x_info->sel_drive, PCX)); + sim_debug(ERROR_MSG, &wd179x_dev, "WD179X[%d]: " ADDRESS_FORMAT + " Invalid sector size!\n", wd179x_info->sel_drive, PCX); wd179x_info->fdc_sec_len = 0; } @@ -833,17 +828,17 @@ static uint8 Do1793Command(uint8 cCommand) } break; case WD179X_READ_TRACK: - TRACE_PRINT(RD_DATA_MSG, ("WD179X[%d]: " ADDRESS_FORMAT " CMD=READ_TRACK" NLP, wd179x_info->sel_drive, PCX)); - TRACE_PRINT(ERROR_MSG, ("WD179X[%d]: " ADDRESS_FORMAT " Error: READ_TRACK not implemented." NLP, - wd179x_info->sel_drive, PCX)); + sim_debug(RD_DATA_MSG, &wd179x_dev, "WD179X[%d]: " ADDRESS_FORMAT + " CMD=READ_TRACK\n", wd179x_info->sel_drive, PCX); + sim_debug(ERROR_MSG, &wd179x_dev, "WD179X[%d]: " ADDRESS_FORMAT + " Error: READ_TRACK not implemented.\n", wd179x_info->sel_drive, PCX); break; case WD179X_WRITE_TRACK: - TRACE_PRINT(WR_DATA_MSG, ("WD179X[%d]: " ADDRESS_FORMAT " CMD=WRITE_TRACK" NLP, wd179x_info->sel_drive, PCX)); - TRACE_PRINT(FMT_MSG, ("WD179X[%d]: " ADDRESS_FORMAT " CMD=WRITE_TRACK, T:%d/S:%d." NLP, - wd179x_info->sel_drive, - PCX, - pDrive->track, - wd179x_info->fdc_head)); + sim_debug(WR_DATA_MSG, &wd179x_dev, "WD179X[%d]: " ADDRESS_FORMAT + " CMD=WRITE_TRACK\n", wd179x_info->sel_drive, PCX); + sim_debug(FMT_MSG, &wd179x_dev, "WD179X[%d]: " ADDRESS_FORMAT + " CMD=WRITE_TRACK, T:%d/S:%d.\n", wd179x_info->sel_drive, + PCX, pDrive->track, wd179x_info->fdc_head); wd179x_info->fdc_status |= (WD179X_STAT_DRQ); /* Set DRQ */ wd179x_info->drq = 1; wd179x_info->fdc_datacount = 128 << wd179x_info->fdc_sec_len; @@ -858,7 +853,8 @@ static uint8 Do1793Command(uint8 cCommand) break; /* Type IV Commands */ case WD179X_FORCE_INTR: - TRACE_PRINT(CMD_MSG, ("WD179X[%d]: " ADDRESS_FORMAT " CMD=FORCE_INTR" NLP, wd179x_info->sel_drive, PCX)); + sim_debug(CMD_MSG, &wd179x_dev, "WD179X[%d]: " ADDRESS_FORMAT + " CMD=FORCE_INTR\n", wd179x_info->sel_drive, PCX); if((cCommand & 0x0F) == 0) { /* I0-I3 == 0, no intr, but clear BUSY and terminate command */ wd179x_info->fdc_status &= ~(WD179X_STAT_DRQ | WD179X_STAT_BUSY); /* Clear DRQ, BUSY */ wd179x_info->drq = 0; @@ -887,8 +883,8 @@ static uint8 Do1793Command(uint8 cCommand) } break; default: - TRACE_PRINT(ERROR_MSG, ("WD179X[%d]: " ADDRESS_FORMAT " ERROR: Unknown command 0x%02x.\n" NLP, - wd179x_info->sel_drive, PCX, cCommand)); + sim_debug(ERROR_MSG, &wd179x_dev, "WD179X[%d]: " ADDRESS_FORMAT + " ERROR: Unknown command 0x%02x.\n\n", wd179x_info->sel_drive, PCX, cCommand); break; } @@ -904,15 +900,16 @@ static uint8 Do1793Command(uint8 cCommand) case WD179X_STEP_OUT: case WD179X_STEP_OUT_U: if(wd179x_info->verify) { /* Verify the selected track/head is ok. */ - TRACE_PRINT(SEEK_MSG, ("WD179X[%d]: " ADDRESS_FORMAT " Verify ", wd179x_info->sel_drive, PCX)); + sim_debug(SEEK_MSG, &wd179x_dev, "WD179X[%d]: " ADDRESS_FORMAT + " Verify ", wd179x_info->sel_drive, PCX); if(sectSeek(pDrive->imd, pDrive->track, wd179x_info->fdc_head) != SCPE_OK) { - TRACE_PRINT(SEEK_MSG, ("FAILED" NLP)); + sim_debug(SEEK_MSG, &wd179x_dev, "FAILED\n"); wd179x_info->fdc_status |= WD179X_STAT_NOT_FOUND; } else if(IMD_MODE_MFM(pDrive->imd->track[pDrive->track][wd179x_info->fdc_head].mode) != (wd179x_info->ddens)) { wd179x_info->fdc_status |= WD179X_STAT_NOT_FOUND; /* Sector not found */ - TRACE_PRINT(SEEK_MSG, ("NOT FOUND" NLP)); + sim_debug(SEEK_MSG, &wd179x_dev, "NOT FOUND\n"); } else { - TRACE_PRINT(SEEK_MSG, ("Ok" NLP)); + sim_debug(SEEK_MSG, &wd179x_dev, "Ok\n"); } } @@ -955,8 +952,8 @@ uint8 WD179X_Write(const uint32 Addr, uint8 cData) { WD179X_DRIVE_INFO *pDrive; /* uint8 disk_read = 0; */ - uint32 flags = 0; - uint32 writelen; + unsigned int flags = 0; + unsigned int writelen; if(wd179x_info->sel_drive >= WD179X_MAX_DRIVES) { return 0xFF; @@ -970,8 +967,8 @@ uint8 WD179X_Write(const uint32 Addr, uint8 cData) switch(Addr & 0x3) { case WD179X_STATUS: - TRACE_PRINT(STATUS_MSG, - ("WD179X: " ADDRESS_FORMAT " WR CMD = 0x%02x" NLP, PCX, cData)) + sim_debug(STATUS_MSG, &wd179x_dev, "WD179X: " ADDRESS_FORMAT + " WR CMD = 0x%02x\n", PCX, cData); wd179x_info->fdc_read = FALSE; wd179x_info->fdc_write = FALSE; wd179x_info->fdc_write_track = FALSE; @@ -981,18 +978,18 @@ uint8 WD179X_Write(const uint32 Addr, uint8 cData) Do1793Command(cData); break; case WD179X_TRACK: - TRACE_PRINT(STATUS_MSG, - ("WD179X: " ADDRESS_FORMAT " WR TRACK = 0x%02x" NLP, PCX, cData)) + sim_debug(STATUS_MSG, &wd179x_dev, "WD179X: " ADDRESS_FORMAT + " WR TRACK = 0x%02x\n", PCX, cData); pDrive->track = cData; break; case WD179X_SECTOR: /* Sector Register */ - TRACE_PRINT(STATUS_MSG, - ("WD179X: " ADDRESS_FORMAT " WR SECT = 0x%02x" NLP, PCX, cData)) + sim_debug(STATUS_MSG, &wd179x_dev, "WD179X: " ADDRESS_FORMAT + " WR SECT = 0x%02x\n", PCX, cData); wd179x_info->fdc_sector = cData; break; case WD179X_DATA: - TRACE_PRINT(STATUS_MSG, - ("WD179X: " ADDRESS_FORMAT " WR DATA = 0x%02x" NLP, PCX, cData)) + sim_debug(STATUS_MSG, &wd179x_dev, "WD179X: " ADDRESS_FORMAT + " WR DATA = 0x%02x\n", PCX, cData); if(wd179x_info->fdc_write == TRUE) { if(wd179x_info->fdc_dataindex < wd179x_info->fdc_datacount) { sdata.raw[wd179x_info->fdc_dataindex] = cData; @@ -1003,13 +1000,8 @@ uint8 WD179X_Write(const uint32 Addr, uint8 cData) wd179x_info->drq = 0; wd179x_info->intrq = 1; - TRACE_PRINT(WR_DATA_MSG, ("WD179X[%d]: " ADDRESS_FORMAT " Writing sector, T:%d/S:%d/N:%d, Len=%d" NLP, - wd179x_info->sel_drive, - PCX, - pDrive->track, - wd179x_info->fdc_head, - wd179x_info->fdc_sector, - 128 << wd179x_info->fdc_sec_len)); + sim_debug(WR_DATA_MSG, &wd179x_dev, "WD179X[%d]: " ADDRESS_FORMAT + " Writing sector, T:%d/S:%d/N:%d, Len=%d\n", wd179x_info->sel_drive, PCX, pDrive->track, wd179x_info->fdc_head, wd179x_info->fdc_sector, 128 << wd179x_info->fdc_sec_len); sectWrite(pDrive->imd, pDrive->track, @@ -1026,15 +1018,12 @@ uint8 WD179X_Write(const uint32 Addr, uint8 cData) } if(wd179x_info->fdc_write_track == TRUE) { -/* TRACE_PRINT(FMT_MSG, */ -/* ("WD179X: " ADDRESS_FORMAT " FMT DATA[%d] = 0x%02x" NLP, PCX, wd179x_info->fdc_fmt_state, cData)); */ - if(wd179x_info->fdc_fmt_state == FMT_GAP1) { if(cData != 0xFC) { wd179x_info->fdc_gap[0]++; } else { - TRACE_PRINT(VERBOSE_MSG, - ("WD179X: " ADDRESS_FORMAT " FMT GAP1 Length = %d" NLP, PCX, wd179x_info->fdc_gap[0])); + sim_debug(VERBOSE_MSG, &wd179x_dev, "WD179X: " ADDRESS_FORMAT + " FMT GAP1 Length = %d\n", PCX, wd179x_info->fdc_gap[0]); wd179x_info->fdc_gap[1] = 0; wd179x_info->fdc_fmt_state = FMT_GAP2; } @@ -1042,8 +1031,8 @@ uint8 WD179X_Write(const uint32 Addr, uint8 cData) if(cData != 0xFE) { wd179x_info->fdc_gap[1]++; } else { - TRACE_PRINT(VERBOSE_MSG, - ("WD179X: " ADDRESS_FORMAT " FMT GAP2 Length = %d" NLP, PCX, wd179x_info->fdc_gap[1])); + sim_debug(VERBOSE_MSG, &wd179x_dev, "WD179X: " ADDRESS_FORMAT + " FMT GAP2 Length = %d\n", PCX, wd179x_info->fdc_gap[1]); wd179x_info->fdc_gap[2] = 0; wd179x_info->fdc_fmt_state = FMT_HEADER; wd179x_info->fdc_header_index = 0; @@ -1053,8 +1042,8 @@ uint8 WD179X_Write(const uint32 Addr, uint8 cData) wd179x_info->fdc_gap[2] = 0; wd179x_info->fdc_fmt_state = FMT_GAP3; } else { - TRACE_PRINT(VERBOSE_MSG, - ("WD179X: " ADDRESS_FORMAT " HEADER[%d]=%02x" NLP, PCX, wd179x_info->fdc_header_index, cData)); + sim_debug(VERBOSE_MSG, &wd179x_dev, "WD179X: " ADDRESS_FORMAT + " HEADER[%d]=%02x\n", PCX, wd179x_info->fdc_header_index, cData); switch(wd179x_info->fdc_header_index) { case 0: pDrive->track = cData; @@ -1080,8 +1069,8 @@ uint8 WD179X_Write(const uint32 Addr, uint8 cData) if(cData != 0xFB) { wd179x_info->fdc_gap[2]++; } else { - TRACE_PRINT(VERBOSE_MSG, - ("WD179X: " ADDRESS_FORMAT " FMT GAP3 Length = %d" NLP, PCX, wd179x_info->fdc_gap[2])); + sim_debug(VERBOSE_MSG, &wd179x_dev, "WD179X: " ADDRESS_FORMAT + " FMT GAP3 Length = %d\n", PCX, wd179x_info->fdc_gap[2]); wd179x_info->fdc_fmt_state = FMT_DATA; wd179x_info->fdc_dataindex = 0; } @@ -1092,28 +1081,26 @@ uint8 WD179X_Write(const uint32 Addr, uint8 cData) } else { wd179x_info->fdc_sec_len = floorlog2(wd179x_info->fdc_dataindex) - 7; if((wd179x_info->fdc_sec_len == 0xF8) || (wd179x_info->fdc_sec_len > WD179X_MAX_SEC_LEN)) { /* Error calculating N or N too large */ - TRACE_PRINT(ERROR_MSG, ("WD179X[%d]: " ADDRESS_FORMAT " Invalid sector size!" NLP, - wd179x_info->sel_drive, PCX)); + sim_debug(ERROR_MSG, &wd179x_dev, "WD179X[%d]: " ADDRESS_FORMAT + " Invalid sector size!\n", wd179x_info->sel_drive, PCX); wd179x_info->fdc_sec_len = 0; } if(wd179x_info->fdc_fmt_sector_count >= WD179X_MAX_SECTOR) { - TRACE_PRINT(ERROR_MSG, ("WD179X: " ADDRESS_FORMAT " Illegal sector count" NLP, PCX)); + sim_debug(ERROR_MSG, &wd179x_dev, "WD179X: " ADDRESS_FORMAT + " Illegal sector count\n", PCX); wd179x_info->fdc_fmt_sector_count = 0; } wd179x_info->fdc_sectormap[wd179x_info->fdc_fmt_sector_count] = wd179x_info->fdc_sector; wd179x_info->fdc_fmt_sector_count++; - TRACE_PRINT(VERBOSE_MSG, - ("WD179X: " ADDRESS_FORMAT " FMT Data Length = %d" NLP, PCX, wd179x_info->fdc_dataindex)); + sim_debug(VERBOSE_MSG, &wd179x_dev, "WD179X: " ADDRESS_FORMAT + " FMT Data Length = %d\n", PCX, wd179x_info->fdc_dataindex); - TRACE_PRINT(FMT_MSG, - ("WD179X: " ADDRESS_FORMAT " FORMAT T:%d/H:%d/N:%d=%d/L=%d[%d] Fill=0x%02x" NLP, PCX, - pDrive->track, - wd179x_info->fdc_head, - wd179x_info->fdc_fmt_sector_count, - wd179x_info->fdc_sectormap[wd179x_info->fdc_fmt_sector_count], - wd179x_info->fdc_dataindex, - wd179x_info->fdc_sec_len, - sdata.raw[0])); + sim_debug(FMT_MSG, &wd179x_dev, "WD179X: " ADDRESS_FORMAT + " FORMAT T:%d/H:%d/N:%d=%d/L=%d[%d] Fill=0x%02x\n", PCX, + pDrive->track, wd179x_info->fdc_head, + wd179x_info->fdc_fmt_sector_count, + wd179x_info->fdc_sectormap[wd179x_info->fdc_fmt_sector_count], + wd179x_info->fdc_dataindex, wd179x_info->fdc_sec_len, sdata.raw[0]); wd179x_info->fdc_gap[1] = 0; wd179x_info->fdc_fmt_state = FMT_GAP2; diff --git a/HP2100/hp2100_baci.c b/HP2100/hp2100_baci.c index 779edf96..ac695f6a 100644 --- a/HP2100/hp2100_baci.c +++ b/HP2100/hp2100_baci.c @@ -1,6 +1,6 @@ /* hp2100_baci.c: HP 12966A buffered asynchronous communications interface simulator - Copyright (c) 2007-2008, J. David Bryan + Copyright (c) 2007-2011, J. David Bryan Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), @@ -25,6 +25,8 @@ BACI 12966A BACI card + 28-Mar-11 JDB Tidied up signal handling + 26-Oct-10 JDB Changed I/O signal handler for revised signal model 25-Nov-08 JDB Revised for new multiplexer library SHOW routines 11-Sep-08 JDB Fixed STC,C losing interrupt request on BREAK 07-Sep-08 JDB Fixed IN_LOOPBACK conflict with netinet/in.h @@ -320,11 +322,13 @@ /* BACI state variables */ -FLIP_FLOP baci_control = CLEAR; /* control flip-flop */ -FLIP_FLOP baci_flag = CLEAR; /* flag flip-flop */ -FLIP_FLOP baci_flagbuf = CLEAR; /* flag buffer flip-flop */ -FLIP_FLOP baci_srq = CLEAR; /* SRQ flip-flop */ -FLIP_FLOP baci_lockout = CLEAR; /* interrupt lockout flip-flop */ +struct { + FLIP_FLOP control; /* control flip-flop */ + FLIP_FLOP flag; /* flag flip-flop */ + FLIP_FLOP flagbuf; /* flag buffer flip-flop */ + FLIP_FLOP srq; /* SRQ flip-flop */ + FLIP_FLOP lockout; /* interrupt lockout flip-flop */ + } baci = { CLEAR, CLEAR, CLEAR, CLEAR, CLEAR }; uint16 baci_ibuf = 0; /* status/data in */ uint16 baci_obuf = 0; /* command/data out */ @@ -372,7 +376,8 @@ static void clock_uart (void); /* BACI global routines */ -uint32 baci_io (uint32 select_code, IOSIG signal, uint32 data); +IOHANDLER baci_io; + t_stat baci_term_svc (UNIT *uptr); t_stat baci_poll_svc (UNIT *uptr); t_stat baci_reset (DEVICE *dptr); @@ -400,13 +405,14 @@ t_stat baci_detach (UNIT *uptr); ten millisecond period. */ -DIB baci_dib = { BACI, &baci_io }; +DIB baci_dib = { &baci_io, BACI, 0 }; DEVICE baci_dev; -UNIT baci_unit[] = - { { UDATA (&baci_term_svc, UNIT_ATTABLE | UNIT_FASTTIME, 0) }, /* terminal I/O unit */ - { UDATA (&baci_poll_svc, UNIT_DIS, POLL_FIRST) } }; /* Telnet poll unit */ +UNIT baci_unit[] = { + { UDATA (&baci_term_svc, UNIT_ATTABLE | UNIT_FASTTIME, 0) }, /* terminal I/O unit */ + { UDATA (&baci_poll_svc, UNIT_DIS, POLL_FIRST) } /* Telnet poll unit */ + }; REG baci_reg[] = { { ORDATA (IBUF, baci_ibuf, 16), REG_FIT }, @@ -438,12 +444,12 @@ REG baci_reg[] = { { FLDATA (ENQFLAG, baci_enq_seen, 0), REG_HRO }, { DRDATA (ENQCNTR, baci_enq_cntr, 16), REG_HRO }, - { FLDATA (LKO, baci_lockout, 0) }, - { FLDATA (CTL, baci_control, 0) }, - { FLDATA (FLG, baci_flag, 0) }, - { FLDATA (FBF, baci_flagbuf, 0) }, - { FLDATA (SRQ, baci_srq, 0) }, - { ORDATA (DEVNO, baci_dib.devno, 6), REG_HRO }, + { FLDATA (LKO, baci.lockout, 0) }, + { FLDATA (CTL, baci.control, 0) }, + { FLDATA (FLG, baci.flag, 0) }, + { FLDATA (FBF, baci.flagbuf, 0) }, + { FLDATA (SRQ, baci.srq, 0) }, + { ORDATA (DEVNO, baci_dib.select_code, 6), REG_HRO }, { NULL } }; @@ -526,232 +532,233 @@ DEVICE baci_dev = { would be cleared, and the interrupt would be lost. */ -uint32 baci_io (uint32 select_code, IOSIG signal, uint32 data) +uint32 baci_io (DIB *dibptr, IOCYCLE signal_set, uint32 stat_data) { -const char *hold_or_clear = (signal > ioCLF ? ",C" : ""); -const IOSIG base_signal = IOBASE (signal); /* derive base signal */ +const char *hold_or_clear = (signal_set & ioCLF ? ",C" : ""); uint8 ch; +uint16 data; uint32 mask; +IOSIGNAL signal; +IOCYCLE working_set = IOADDSIR (signal_set); /* add ioSIR if needed */ -switch (base_signal) { /* dispatch base I/O signal */ +while (working_set) { + signal = IONEXT (working_set); /* isolate next signal */ - case ioCLF: /* clear flag flip-flop */ - baci_flag = baci_flagbuf = CLEAR; /* clear flag and flag buffer */ - baci_srq = CLEAR; /* clear SRQ */ + switch (signal) { /* dispatch I/O signal */ - if (DEBUG_PRI (baci_dev, DEB_CMDS)) - fputs (">>BACI cmds: [CLF] Flag and SRQ cleared\n", sim_deb); - - update_status (); /* FLG might set when SRQ clears */ - break; - - - case ioSTF: /* set flag flip-flop */ - baci_flag = baci_flagbuf = SET; /* set flag and flag buffer */ - baci_lockout = SET; /* set lockout */ - baci_srq = SET; /* set SRQ */ - - if (DEBUG_PRI (baci_dev, DEB_CMDS)) - fputs (">>BACI cmds: [STF] Flag, SRQ, and lockout set\n", sim_deb); - break; - - - case ioENF: /* enable flag */ - baci_flag = baci_flagbuf = SET; /* set device flag and flag buffer */ - baci_lockout = SET; /* set lockout */ - break; - - - case ioSFC: /* skip if flag is clear */ - setstdSKF (baci); - break; - - - case ioSFS: /* skip if flag is set */ - setstdSKF (baci); - break; - - - case ioIOI: /* I/O data input */ - if (baci_control) { /* control set? */ - baci_ibuf = TO_CHARCNT (baci_fcount); /* get FIFO count */ - - if (IO_MODE == RECV) /* receiving? */ - baci_ibuf = baci_ibuf | fifo_get (); /* add char and validity flag */ - - data = baci_ibuf; /* return received data */ - - if (DEBUG_PRI (baci_dev, DEB_CPU)) - fprintf (sim_deb, ">>BACI cpu: [LIx%s] Received data = %06o\n", hold_or_clear, data); - } - - else { /* control clear? */ - data = baci_status; /* return status */ - - if (DEBUG_PRI (baci_dev, DEB_CPU)) - fprintf (sim_deb, ">>BACI cpu: [LIx%s] Status = %06o\n", hold_or_clear, data); - } - break; - - - case ioIOO: /* I/O data output */ - if (DEBUG_PRI (baci_dev, DEB_CPU)) - fprintf (sim_deb, ">>BACI cpu: [OTx%s] Command = %06o\n", hold_or_clear, data); - - baci_obuf = data; - - if (baci_obuf & OUT_MR) { /* master reset? */ - master_reset (); /* do before processing */ - baci_io (select_code, ioSIR, 0); /* set interrupt request */ + case ioCLF: /* clear flag flip-flop */ + baci.flag = baci.flagbuf = CLEAR; /* clear flag and flag buffer */ + baci.srq = CLEAR; /* clear SRQ */ if (DEBUG_PRI (baci_dev, DEB_CMDS)) - fprintf (sim_deb, ">>BACI cmds: [OTx%s] Master reset\n", hold_or_clear); - } + fputs (">>BACI cmds: [CLF] Flag and SRQ cleared\n", sim_deb); - switch (GET_ID (baci_obuf)) { /* isolate ID code */ + update_status (); /* FLG might set when SRQ clears */ + break; - case 0: /* transmit data */ - if (IO_MODE == XMIT) { /* transmitting? */ - ch = baci_obuf & OUT_DATA; /* mask to character */ - fifo_put (ch); /* queue character */ - if (baci_term.flags & UNIT_ATT) { /* attached to network? */ - if (DEBUG_PRI (baci_dev, DEB_CMDS) && /* debugging? */ - (sim_is_active (&baci_term) == 0)) /* service stopped? */ - fprintf (sim_deb, ">>BACI cmds: [OTx%s] Terminal service scheduled, " - "time = %d\n", hold_or_clear, baci_term.wait); + case ioSTF: /* set flag flip-flop */ + baci.flag = baci.flagbuf = SET; /* set flag and flag buffer */ + baci.lockout = SET; /* set lockout */ + baci.srq = SET; /* set SRQ */ - if (baci_fcount == 1) /* first char to xmit? */ - sim_activate_abs (&baci_term, /* start service with full char time */ - baci_term.wait); - else - sim_activate (&baci_term, /* start service if not running */ - baci_term.wait); - } - } - break; + if (DEBUG_PRI (baci_dev, DEB_CMDS)) + fputs (">>BACI cmds: [STF] Flag, SRQ, and lockout set\n", sim_deb); + break; - case 1: /* enable device status interrupt */ - baci_edsiw = baci_obuf; /* load new enable word */ - update_status (); /* may have enabled an interrupt */ - break; - case 2: /* device status reference */ - if ((baci_term.flags & UNIT_DIAG) && /* diagnostic mode? */ - (baci_dsrw & OUT_DIAG) && /* and last DIAG was high? */ - !(baci_obuf & OUT_DIAG) && /* and new DIAG is low? */ - !(baci_icw & OUT_BAUDRATE)) /* and clock is external? */ - clock_uart (); /* pulse UART clock */ + case ioENF: /* enable flag */ + baci.flag = baci.flagbuf = SET; /* set device flag and flag buffer */ + baci.lockout = SET; /* set lockout */ + break; - baci_dsrw = baci_obuf; /* load new reference word */ - update_status (); /* clocking UART may interrupt */ - break; - case 3: /* character frame control */ - baci_cfcw = baci_obuf; /* load new frame word */ - break; + case ioSFC: /* skip if flag is clear */ + setstdSKF (baci); + break; - case 4: /* interface control */ - if ((baci_icw ^ baci_obuf) & OUT_BAUDRATE) { /* baud rate change? */ - baci_term.wait = service_time (baci_obuf); /* set service time to match rate */ - if (baci_term.flags & UNIT_DIAG) /* diagnostic mode? */ - if (baci_obuf & OUT_BAUDRATE) { /* internal baud rate requested? */ - sim_activate (&baci_term, /* activate I/O service */ - baci_term.wait); + case ioSFS: /* skip if flag is set */ + setstdSKF (baci); + break; - if (DEBUG_PRI (baci_dev, DEB_CMDS)) + + case ioIOI: /* I/O data input */ + if (baci.control) { /* control set? */ + baci_ibuf = TO_CHARCNT (baci_fcount); /* get FIFO count */ + + if (IO_MODE == RECV) /* receiving? */ + baci_ibuf = baci_ibuf | fifo_get (); /* add char and validity flag */ + + data = baci_ibuf; /* return received data */ + + if (DEBUG_PRI (baci_dev, DEB_CPU)) + fprintf (sim_deb, ">>BACI cpu: [LIx%s] Received data = %06o\n", hold_or_clear, baci_ibuf); + } + + else { /* control clear? */ + data = baci_status; /* return status */ + + if (DEBUG_PRI (baci_dev, DEB_CPU)) + fprintf (sim_deb, ">>BACI cpu: [LIx%s] Status = %06o\n", hold_or_clear, baci_status); + } + + stat_data = IORETURN (SCPE_OK, data); /* merge in return status */ + break; + + + case ioIOO: /* I/O data output */ + baci_obuf = IODATA (stat_data); /* get data value */ + + if (DEBUG_PRI (baci_dev, DEB_CPU)) + fprintf (sim_deb, ">>BACI cpu: [OTx%s] Command = %06o\n", hold_or_clear, baci_obuf); + + if (baci_obuf & OUT_MR) { /* master reset? */ + master_reset (); /* do before processing */ + baci_io (&baci_dib, ioSIR, 0); /* set interrupt request */ + + if (DEBUG_PRI (baci_dev, DEB_CMDS)) + fprintf (sim_deb, ">>BACI cmds: [OTx%s] Master reset\n", hold_or_clear); + } + + switch (GET_ID (baci_obuf)) { /* isolate ID code */ + + case 0: /* transmit data */ + if (IO_MODE == XMIT) { /* transmitting? */ + ch = baci_obuf & OUT_DATA; /* mask to character */ + fifo_put (ch); /* queue character */ + + if (baci_term.flags & UNIT_ATT) { /* attached to network? */ + if (DEBUG_PRI (baci_dev, DEB_CMDS) && /* debugging? */ + (sim_is_active (&baci_term) == 0)) /* service stopped? */ fprintf (sim_deb, ">>BACI cmds: [OTx%s] Terminal service scheduled, " "time = %d\n", hold_or_clear, baci_term.wait); + + if (baci_fcount == 1) /* first char to xmit? */ + sim_activate_abs (&baci_term, /* start service with full char time */ + baci_term.wait); + else + sim_activate (&baci_term, /* start service if not running */ + baci_term.wait); } + } + break; - else { /* external rate */ - sim_cancel (&baci_term); /* stop I/O service */ + case 1: /* enable device status interrupt */ + baci_edsiw = baci_obuf; /* load new enable word */ + update_status (); /* may have enabled an interrupt */ + break; - if (DEBUG_PRI (baci_dev, DEB_CMDS)) - fprintf (sim_deb, ">>BACI cmds: [OTx%s] Terminal service stopped\n", - hold_or_clear); - } - } + case 2: /* device status reference */ + if ((baci_term.flags & UNIT_DIAG) && /* diagnostic mode? */ + (baci_dsrw & OUT_DIAG) && /* and last DIAG was high? */ + !(baci_obuf & OUT_DIAG) && /* and new DIAG is low? */ + !(baci_icw & OUT_BAUDRATE)) /* and clock is external? */ + clock_uart (); /* pulse UART clock */ - baci_icw = baci_obuf; /* load new reference word */ - update_status (); /* loopback may change status */ - break; + baci_dsrw = baci_obuf; /* load new reference word */ + update_status (); /* clocking UART may interrupt */ + break; - case 5: /* interrupt status reset */ - baci_isrw = baci_obuf; /* load new reset word */ + case 3: /* character frame control */ + baci_cfcw = baci_obuf; /* load new frame word */ + break; - mask = (baci_isrw & OUT_IRQCLR) << /* form reset mask */ - IN_V_IRQCLR; /* for common irqs */ + case 4: /* interface control */ + if ((baci_icw ^ baci_obuf) & OUT_BAUDRATE) { /* baud rate change? */ + baci_term.wait = service_time (baci_obuf); /* set service time to match rate */ - if (baci_isrw & OUT_CSC) /* add special char mask bit */ - mask = mask | IN_SPCHAR; /* if requested */ + if (baci_term.flags & UNIT_DIAG) /* diagnostic mode? */ + if (baci_obuf & OUT_BAUDRATE) { /* internal baud rate requested? */ + sim_activate (&baci_term, /* activate I/O service */ + baci_term.wait); - baci_status = baci_status & ~mask; /* clear specified status bits */ - break; + if (DEBUG_PRI (baci_dev, DEB_CMDS)) + fprintf (sim_deb, ">>BACI cmds: [OTx%s] Terminal service scheduled, " + "time = %d\n", hold_or_clear, baci_term.wait); + } - case 6: /* special character */ - baci_spchar [baci_obuf & OUT_SPCHAR] = /* set special character entry */ - ((baci_obuf & OUT_SPFLAG) != 0); - break; - } - break; + else { /* external rate */ + sim_cancel (&baci_term); /* stop I/O service */ + + if (DEBUG_PRI (baci_dev, DEB_CMDS)) + fprintf (sim_deb, ">>BACI cmds: [OTx%s] Terminal service stopped\n", + hold_or_clear); + } + } + + baci_icw = baci_obuf; /* load new reference word */ + update_status (); /* loopback may change status */ + break; + + case 5: /* interrupt status reset */ + baci_isrw = baci_obuf; /* load new reset word */ + + mask = (baci_isrw & OUT_IRQCLR) << /* form reset mask */ + IN_V_IRQCLR; /* for common irqs */ + + if (baci_isrw & OUT_CSC) /* add special char mask bit */ + mask = mask | IN_SPCHAR; /* if requested */ + + baci_status = baci_status & ~mask; /* clear specified status bits */ + break; + + case 6: /* special character */ + baci_spchar [baci_obuf & OUT_SPCHAR] = /* set special character entry */ + ((baci_obuf & OUT_SPFLAG) != 0); + break; + } + break; - case ioPOPIO: /* power-on preset to I/O */ - /* fall into CRS handler */ + case ioCRS: /* control reset */ + master_reset (); /* issue master reset */ - case ioCRS: /* control reset */ - master_reset (); /* issue master reset */ - - if (DEBUG_PRI (baci_dev, DEB_CMDS)) - fputs (">>BACI cmds: [CRS] Master reset\n", sim_deb); - break; + if (DEBUG_PRI (baci_dev, DEB_CMDS)) + fputs (">>BACI cmds: [CRS] Master reset\n", sim_deb); + break; - case ioCLC: /* clear control flip-flop */ - baci_control = CLEAR; /* clear control */ + case ioCLC: /* clear control flip-flop */ + baci.control = CLEAR; /* clear control */ - if (DEBUG_PRI (baci_dev, DEB_CMDS)) - fprintf (sim_deb, ">>BACI cmds: [CLC%s] Control cleared\n", hold_or_clear); - break; + if (DEBUG_PRI (baci_dev, DEB_CMDS)) + fprintf (sim_deb, ">>BACI cmds: [CLC%s] Control cleared\n", hold_or_clear); + break; - case ioSTC: /* set control flip-flop */ - baci_control = SET; /* set control */ - baci_lockout = CLEAR; /* clear lockout */ + case ioSTC: /* set control flip-flop */ + baci.control = SET; /* set control */ + baci.lockout = CLEAR; /* clear lockout */ - if (DEBUG_PRI (baci_dev, DEB_CMDS)) - fprintf (sim_deb, ">>BACI cmds: [STC%s] Control set and lockout cleared\n", hold_or_clear); + if (DEBUG_PRI (baci_dev, DEB_CMDS)) + fprintf (sim_deb, ">>BACI cmds: [STC%s] Control set and lockout cleared\n", hold_or_clear); - if (signal == ioSTC) /* STC without ,C ? */ - update_status (); /* clearing lockout might interrupt */ - break; + if (!(signal_set & ioCLF)) /* STC without ,C ? */ + update_status (); /* clearing lockout might interrupt */ + break; - case ioSIR: /* set interrupt request */ - setstdPRL (select_code, baci); /* set standard PRL signal */ - setstdIRQ (select_code, baci); /* set standard IRQ signal */ - setSRQ (select_code, baci_srq); /* set SRQ signal */ - break; + case ioSIR: /* set interrupt request */ + setstdPRL (baci); /* set standard PRL signal */ + setstdIRQ (baci); /* set standard IRQ signal */ + setSRQ (dibptr->select_code, baci.srq); /* set SRQ signal */ + break; - case ioIAK: /* interrupt acknowledge */ - baci_flagbuf = CLEAR; - break; + case ioIAK: /* interrupt acknowledge */ + baci.flagbuf = CLEAR; + break; - default: /* all other signals */ - break; /* are ignored */ + default: /* all other signals */ + break; /* are ignored */ + } + + working_set = working_set & ~signal; /* remove current signal from set */ } - -if (signal > ioCLF) /* multiple signals? */ - baci_io (select_code, ioCLF, 0); /* issue CLF */ -else if (signal > ioSIR) /* signal affected interrupt status? */ - baci_io (select_code, ioSIR, 0); /* set interrupt request */ - -return data; +return stat_data; } @@ -931,7 +938,7 @@ while (recv_loop && /* OK to process? */ baci_uart_rhr = CLEAR_HR; /* clear RHR */ update_status (); /* update FIFO status (may set flag) */ - recv_loop = fast_timing && !IRQ (baci_dib.devno); /* loop if fast mode and no IRQ */ + recv_loop = fast_timing && !IRQ (baci_dib.select_code); /* loop if fast mode and no IRQ */ } else { /* xmit or ENQ/ACK, leave char in RHR */ @@ -1002,7 +1009,7 @@ return SCPE_OK; t_stat baci_reset (DEVICE *dptr) { -baci_io (baci_dib.devno, ioPOPIO, 0); /* send POPIO signal */ +IOPRESET (&baci_dib); /* PRESET device (does not use PON) */ baci_ibuf = 0; /* clear input buffer */ baci_obuf = 0; /* clear output buffer */ @@ -1083,10 +1090,10 @@ baci_uart_rr = CLEAR_R; /* clear receiver regist baci_uart_clk = 0; /* clear UART clock */ baci_bcount = 0; /* clear break counter */ -baci_control = CLEAR; /* clear control */ -baci_flag = baci_flagbuf = SET; /* set flag and flag buffer */ -baci_srq = SET; /* set SRQ */ -baci_lockout = SET; /* set lockout flip-flop */ +baci.control = CLEAR; /* clear control */ +baci.flag = baci.flagbuf = SET; /* set flag and flag buffer */ +baci.srq = SET; /* set SRQ */ +baci.lockout = SET; /* set lockout flip-flop */ baci_edsiw = 0; /* clear interrupt enables */ baci_dsrw = 0; /* clear status reference */ @@ -1150,18 +1157,18 @@ if ((baci_status & IN_STDIRQ) || /* standard interrupt? * (baci_edsiw & OUT_ENCM) && /* and char mode */ (baci_fget != baci_fput)) { /* and FIFO not empty? */ - if (baci_lockout) { /* interrupt lockout? */ + if (baci.lockout) { /* interrupt lockout? */ if (DEBUG_PRI (baci_dev, DEB_CMDS)) fputs (">>BACI cmds: Lockout prevents flag set", sim_deb); } - else if (baci_srq) { /* SRQ set? */ + else if (baci.srq) { /* SRQ set? */ if (DEBUG_PRI (baci_dev, DEB_CMDS)) fputs (">>BACI cmds: SRQ prevents flag set", sim_deb); } else { - baci_io (baci_dib.devno, ioENF, 0); /* set flag */ + baci_io (&baci_dib, ioENF, 0); /* set flag */ if (DEBUG_PRI (baci_dev, DEB_CMDS)) fputs (">>BACI cmds: Flag and lockout set", sim_deb); @@ -1175,14 +1182,14 @@ if ((baci_icw & OUT_DCPC) && /* DCPC enabled? */ ((IO_MODE == XMIT) && (baci_fcount < 128) || /* and xmit and room in FIFO */ (IO_MODE == RECV) && (baci_fcount > 0))) { /* or recv and data in FIFO? */ - if (baci_lockout) { /* interrupt lockout? */ + if (baci.lockout) { /* interrupt lockout? */ if (DEBUG_PRI (baci_dev, DEB_CMDS)) fputs (">>BACI cmds: Lockout prevents SRQ set", sim_deb); } else { - baci_srq = SET; /* set SRQ */ - baci_io (baci_dib.devno, ioSIR, 0); /* set interrupt request */ + baci.srq = SET; /* set SRQ */ + baci_io (&baci_dib, ioSIR, 0); /* set interrupt request */ if (DEBUG_PRI (baci_dev, DEB_CMDS)) fputs (">>BACI cmds: SRQ set", sim_deb); diff --git a/HP2100/hp2100_bugfixes.txt b/HP2100/hp2100_bugfixes.txt index 71448791..68ef6e55 100644 --- a/HP2100/hp2100_bugfixes.txt +++ b/HP2100/hp2100_bugfixes.txt @@ -1,6 +1,6 @@ HP 2100 SIMULATOR BUG FIX WRITEUPS ================================== - Last update: 2008-09-30 + Last update: 2011-06-21 1. PROBLEM: Booting from magnetic tape reports "HALT instruction, P: 77756 @@ -138,8 +138,8 @@ the "ex -u" and "ex -s" commands reveals the same data in both sets of locations. The "ex" command isn't using the DMS maps properly. - CAUSE: String constants are used instead of character constants, preventing - the DMS map switches from being recognized. + CAUSE: String constants are used instead of character constants, + preventing the DMS map switches from being recognized. RESOLUTION: Modify "hp2100_cpu.c" to use character constants rather than string constants in "dms_cons" so that DMS map switches work correctly. @@ -151,14 +151,14 @@ program. The EXEC target is below the MP fence, and the expected action is an MP violation interrupt that is recognized and processed by the system as a legal call to the system executive. However, the MP violation isn't - occurring, so the SJP instruction at the actual EXEC entry point (present to - catch EXEC calls made with the interrupt system off) is attempted, and that - causes the DM violation, due to execution of a protected instruction from - the user map. + occurring, so the SJP instruction at the actual EXEC entry point (present + to catch EXEC calls made with the interrupt system off) is attempted, and + that causes the DM violation, due to execution of a protected instruction + from the user map. CAUSE: Memory writes aren't being checked for an MP violation if DMS is - enabled, i.e., if DMS is enabled, and the page is writable, then whether the - target is below the MP fence is not checked. + enabled, i.e., if DMS is enabled, and the page is writable, then whether + the target is below the MP fence is not checked. RESOLUTION: Modify "hp2100_cpu.c" to do MP check on all writes after DMS translation and violation checks are done (so, to pass, the page must be @@ -430,7 +430,7 @@ RESOLUTION: Alter "ptr_svc" (hp2100_stddev.c) to fail if STOP_IOE is set, or to supply feed frames upon encountering the end of the attached file. "SET PTR TRLLIM" sets the maximum number of feed frames to supply. Note - that RTE needs at least 30 feed frames before signalling EOT. + that RTE needs at least 30 feed frames before signaling EOT. STATUS: Fixed in version 3.2-1. @@ -706,8 +706,8 @@ the simulator doesn't supply it explicitly in this case. The HP "7900A Disc Drive Operating and Service Manual" (07900-90002) says, - in section 4-67, "Attention is set high everytime a seek has been completed - and Access Ready comes high." + in section 4-67, "Attention is set high every time a seek has been + completed and Access Ready comes high." TSB code loads the "drive attention" word from the command channel to create a "request status" command. The code assumes that either bit 0 or bit 1 @@ -848,9 +848,9 @@ from issuing a WRITE command until the first data is requested). Most of these are reported as diagnostic failures. - CAUSE: I/O time modelling is not done properly. In some cases, the times + CAUSE: I/O time modeling is not done properly. In some cases, the times indicated are incorrect. In others, certain characteristics (e.g., that - operations from BOT take longer, due to the initial gap) aren't modelled at + operations from BOT take longer, due to the initial gap) aren't modeled at all. RESOLUTION: Revise "mscio" and "msc_svc" (hp2100_ms.c) to model actual I/O @@ -1200,12 +1200,13 @@ ready (i.e., when the unit is attached). CAUSE: Section 4-67 of the "7900A Disc Drive Operating and Service Manual" - (HP 07900-90002) says, "Attention is set high everytime a seek has completed - and Access Ready comes high." This includes the initial head-loading seek - when the drive becomes ready. The "Troubleshooting Diagrams (Sheet 2 of 4)" - on page 5-17 show that after the heads load, Drive Ready, First Status, - Access Ready (a.k.a. not Busy), and Attention are asserted. The - corresponding code in "dpc_attach" sets First Status but not Attention. + (HP 07900-90002) says, "Attention is set high every time a seek has + completed and Access Ready comes high." This includes the initial + head-loading seek when the drive becomes ready. The "Troubleshooting + Diagrams (Sheet 2 of 4)" on page 5-17 show that after the heads load, Drive + Ready, First Status, Access Ready (a.k.a. not Busy), and Attention are + asserted. The corresponding code in "dpc_attach" sets First Status but not + Attention. In addition, the last diagnostic command prior to the loop is a STATUS CHECK. This leaves the 13210A interface polling for attention bits, and @@ -1332,7 +1333,7 @@ - 51. PROBLEM: The diagnostic configurator mis-identifies the host CPU. + 51. PROBLEM: The diagnostic configurator misidentifies the host CPU. VERSION: 3.2-3 @@ -1509,7 +1510,7 @@ missing the option to indicate that commas are glyph separators. RESOLUTION: Modify the appropriate calls to "get_glyph" (scp.c, - sim_console.c) to specify ',' as the the "optional end of glyph character" + sim_console.c) to specify ',' as the "optional end of glyph character" parameter. STATUS: Fixed in version 3.3-0. @@ -2154,7 +2155,7 @@ conclusion of writes when using the 12606 interface. This is an artifact of the interface design. - CAUSE: The status return from the 12606 interface is not modelled properly. + CAUSE: The status return from the 12606 interface is not modeled properly. RESOLUTION: Modify "drv_svc" (hp2100_dr.c) to return DRS_PER at the conclusion of writes when configured as a 2770/2771 disk. @@ -2542,7 +2543,7 @@ Section I, Paragraph 4-17, "Store Field", of the "HP 1000 M/E/F-Series Computers Engineering and Reference Documentation" (HP 92851-90001) says: - "The A and B addressable flip-slops (ABFF) [38A] can be clocked at the + "The A and B addressable flip-flops (ABFF) [38A] can be clocked at the end of every microcycle. Addresses 0 and 1 are detected on the M-bus and the flip-flops are set accordingly. When DCPC uses the M-bus the ABFFST signal is suppressed." @@ -3867,7 +3868,7 @@ the terminal multiplexer. RESOLUTION: Modify the "ioEDT" handler in "iplio" (hp2100_ipl.c) to sleep - for one millisecond before signalling a DMA completion interrupt for an + for one millisecond before signaling a DMA completion interrupt for an output transfer. This allows the SP time to pulse the IPL before the IOP processes the DMA completion interrupt. Modify "dma_cycle" (hp2100_cpu.c) to pass the DMA channel number and I/O direction flag in the "dat" @@ -4711,7 +4712,7 @@ 191. PROBLEM: The action of certain I/O cards (e.g., the 12936A Privileged - Interrupt Fence) cannot be modelled by SIMH. + Interrupt Fence) cannot be modeled by SIMH. VERSION: 3.8-0 @@ -4722,7 +4723,7 @@ CAUSE: The hardware has I/O signals for interrupt request (IRQ) and interrupt priority to lower-priority devices (PRL). These signals are not - modelled directly in SIMH. Rather, they are implied by control, flag, and + modeled directly in SIMH. Rather, they are implied by control, flag, and flag buffer set (for IRQ) and control and flag set (for PRL). If an I/O card does not follow these conventions, then the proper action cannot be simulated. @@ -5065,7 +5066,7 @@ VERSION: 3.8-0 OBSERVATION: The A and B register values are stored in two places: as - "uint16 ABREG[2]" duing execution, and as "uint32 saved_AR" and "uint32 + "uint16 ABREG[2]" during execution, and as "uint32 saved_AR" and "uint32 saved_BR" between executions. The latter was to accommodate the requirement that register variables must be 32 bits in size. That requirement was removed in version 3.5-2 for registers declared with the @@ -5208,10 +5209,10 @@ VERSION: 3.8-0 - OBSERVATION: Page 2-6 of the 12559A 9-Track Magnetic Tape Unit Interface - Kit Operating and Service Manual says that the CLR command channel flag - flip-flop when the command completes. The MT simulator does not, so the - command channel does not interrupt. + OBSERVATION: Page 2-5 of the 12559A 9-Track Magnetic Tape Unit Interface + Kit Operating and Service Manual says that the command channel flag + flip-flop sets when the CLR command completes. The MT simulator does not + do this, so the command channel does not interrupt. CAUSE: Coding error. @@ -5319,7 +5320,7 @@ This second interrupt would normally be allowed, as the STC sc,C instruction clears the "interrupt lockout" flag that was set when the first - interupt was generated. However, the STC signal handler checks for + interrupt was generated. However, the STC signal handler checks for interrupt status between the STC and the succeeding CLF, rather than after the CLF. The result is that the STC clears lockout, then the FIFO status sets the flag and lockout, and then the CLF clears the flag, leaving @@ -5351,3 +5352,554 @@ to the "interrupt trap cell" execution path. STATUS: Fixed in version 3.8-1. + + + +213. PROBLEM: A DO command without a filename prints the wrong error message. + + VERSION: 3.8-1 + + OBSERVATION: The DO command requires a file argument and zero or more + parameter arguments. Entering DO without the file argument should print + "Too few arguments," as other commands that require arguments do (e.g., + ATTACH, BOOT, etc.). Instead, it prints "File open error." + + CAUSE: A test in "do_cmd" attempts to detect when no arguments are passed + and return SCPE_2FARG in response, but the test always fails. As a result, + "fopen" is called with a NULL filename parameter. The call fails, + resulting in the "File open error" message. + + The test follows the initialization of the "do_arg" array and depends on + initialization stopping when a null argument is encountered. The bug fix + of 25-Jul-2008 ("DO cmd missing params now default to null string") + modified "do_arg" initialization to cover the entire array. Therefore, the + test to determine if "do_arg" was not initialized (which implies that the + file argument was not passed) never trips. + + RESOLUTION: Modify "do_arg" (scp.c) to test "do_arg[0]" for NULL and to + return SCPE_2FARG if so. + + STATUS: Fixed in version 3.8-2. + + + +214. PROBLEM: DMA/DCPC cannot steal consecutive I/O cycles. + + VERSION: 3.8-1 + + OBSERVATION: All DMA and DCPC cards are capable of stealing consecutive + I/O cycles, presuming that SRQ is asserted at the proper time before each + cycle. The current SIMH implementation of DMA/DCPC is capable of stealing + only every other cycle, even if SRQ is asserted continuously. The 12821A + Disc Interface diagnostic checks for consecutive cycle-steal capability and + fails when run. + + CAUSE: Each pass through the instruction simulation loop does a device + timeout check, then a potential DMA cycle, and then an instruction cycle. + The device timeout calls the card unit service routine, which sets SRQ and + schedules the next service. The SRQ is then processed with the DMA cycle, + which dispatches ioIOI/IOO and ioCLF to the device. At the end of the DMA + cycle, the next instruction is executed. + + A device capable of transferring data continuously would leave SRQ asserted + after the I/O cycle. But because SRQ is not checked after the DMA cycle, + the next instruction execution is performed unconditionally. Therefore, + even with continuous SRQ assertion, the simulator will interleave DMA + cycles and instructions. + + RESOLUTION: Modify the instruction execution loop (hp2100_cpu.c) to + recalculate SRQ requests after each DMA cycle, and if a request is still + pending, skip instruction execution. This allows consecutive DMA cycles + without intervening instruction executions if SRQ is asserted continuously. + + STATUS: Fixed in version 3.8-2. + + + +215. PROBLEM: DMA/DCPC does not give priority to channel 1 during contention. + + VERSION: 3.8-1 + + OBSERVATION: Dual-channel DMA/DCPC cards give priority to channel 1 if + both channels are requesting a DMA cycle. If channel 1 SRQ is asserted + continuously, then no channel 2 cycles will occur until channel 1 + completes. + + Under simulation, channel cycle requests alternate unconditionally. If + channel 2 requests a DMA cycle, it will always be granted, regardless of + any pending channel 1 requests. + + CAUSE: Each pass through the instruction simulation loop checks for a + channel 1 request and then a channel 2 request, dispatching DMA cycles as + indicated. The check for a channel 2 request should not occur if a channel + 1 request is still pending at the end of its DMA cycle. + + RESOLUTION: Modify the instruction execution loop (hp2100_cpu.c) to + inhibit DMA channel 2 if a channel 1 request is still pending after a + channel 1 cycle. + + STATUS: Fixed in version 3.8-2. + + + +216. ENHANCEMENT: Rename DMA channels 0 and 1 to 1 and 2 to match the + documentation. + + VERSION: 3.8-1 + + OBSERVATION: The HP 2100 simulator presents DMA0 and DMA1 as the DMA + devices. However, all HP literature refers to these as channel 1 and + channel 2. + + RESOLUTION: Modify the device names (hp2100_cpu.c, hp2100_defs.h, and + hp2100_sys.c) from 0 and 1 to 1 and 2 to align with HP usage. + + STATUS: Fixed in version 3.8-2. + + + +217. PROBLEM: The comments for "cpu_set_idle" (hp2100_cpu.c) are obsolete. + + VERSION: 3.8-1 + + OBSERVATION: The comments for the above routine note the requirement for + clock stabilization. This was added in 3.8-1, but the comments were not + changed. + + CAUSE: Oversight. + + RESOLUTION: Removed obsolete comments. + + STATUS: Fixed in version 3.8-2. + + + +218. PROBLEM: The 12578A DMA device is modeled incorrectly. + + VERSION: 3.8-1 + + OBSERVATION: The 12578A DMA device simulation incorporates a latency + counter that delays the first DMA cycle for one instruction after the STC + is issued to enable the channel. This is incorrect; if SRQ is already + asserted, the first cycle occurs immediately after the channel is enabled. + + CAUSE: Incorrect understanding. + + RESOLUTION: Modify hp2100_cpu.c to remove the latency counter. + + STATUS: Fixed in version 3.8-2. + + + +219. PROBLEM: DMA IOO and CLF/EDT signals are not concurrent. + + VERSION: 3.8-1 + + OBSERVATION: A DMA transfer to the 12821A Disc Interface should not set + the end-of-data-transfer flip-flop on the DI card until the last word has + been sent. Instead, each word transferred sets the flip-flop. + + CAUSE: In the packed output mode, the end-of-data-transfer flip-flop is + set either if the the OTx instruction does not clear the flag (i.e., if OTA + used instead of OTA,C), or if the DMA EDT signal is asserted. DMA + transfers are programmed to clear the flag with each write to prevent the + flip-flop from setting until the EDT signal asserts when the last word is + output. + + In hardware, CLF or EDT is asserted concurrently with IOO. In simulation, + "dma_cycle" calls the device's I/O signal handler with ioIOO, then with + ioCLF, and then, for the last cycle only, with ioEDT. At the time that the + handler receives ioIOO, it has no way of knowing whether ioCLF will follow. + Therefore, the DI sets its end-of-data-transfer flip-flop on the first word + transferred instead of on the last word transferred. + + The fundamental problem is that DMA hardware may assert multiple concurrent + signals, upon which I/O card designs may test and act, but simulation + serializes the signals and therefore prevents concurrency detection. + + RESOLUTION: Modify "dma_cycle" (hp2100_cpu.c) to send one set of + concurrent I/O signals to the target handler for each DMA I/O cycle, and + modify all I/O device handlers to allow processing of multiple concurrent + signals. + + STATUS: Fixed in version 3.8-2. + + + +220. ENHANCEMENT: Enhance the I/O signal dispatcher to provide for multiple + devices controlled by the same device signal handler. + + VERSION: 3.8-1 + + OBSERVATION: Currently, the DCPC, IPL, and DI simulations control multiple + devices. The first two control a pair of devices each and determine the + desired device by checking the select code. The DI will control three, + complicating the test that would have to be done at each signal handler + entry. + + RESOLUTION: Modify "devdisp" (hp2100_cpu.c) to pass the Device Information + Block (DIB) pointer instead of the select code to device signal handlers, + and modify all signal handlers accordingly. Modify all device DIBs to add + card numbers to allow for multiple-device handlers. + + STATUS: Fixed in version 3.8-2. + + + +221. PROBLEM: The LPS diagnostic mode is modeled incorrectly. + + VERSION: 3.8-1 + + OBSERVATION: The 12578A DMA simulation was modified to remove the latency + from enabling a channel to issuing the first DMA cycle. After this change + was made, the card failed DMA diagnostic test 17. + + CAUSE: The LPS device offers a diagnostic mode that simulates a 12566B + Microcircuit Interface card equipped with a loopback connector. This + configuration is used for a number of diagnostics that require an I/O card + in addition to the card under test. Typically, this is to test I/O or + interrupt capability. Jumpers on the card configure it for the diagnostic + response expected. The SET LPS DIAG mode configures the card properly for + all diagnostics except the 12578A DMA diagnostic. + + SET LPS DIAG simulates jumper W1 in position C and W2 in position B. In + these positions, an STC will set the card flag one instruction later. When + used for a DMA transfer, instructions and DMA cycles will interleave 1:1, + i.e., DMA will steal every other cycle. + + The 12578A diagnostic requires jumper W1 in position B and W2 in position + C. In these positions, an STC will set the card flag two instructions + later, so DMA will steal every third cycle, allowing two instructions + between DMA cycles. The 12578A diagnostic depends on this and will report + errors otherwise. + + RESOLUTION: Modify "lpsio" (hp2100_lps.c) to schedule device service in + DIAG mode in three instructions if the CPU is a 2114, 2115, or 2116 and in + two instructions otherwise. + + STATUS: Fixed in version 3.8-2. + + + +222. PROBLEM: The 12821A Disc Interface diagnostic aborts with "Unit not + attached." + + VERSION: 3.8-1 + + OBSERVATION: The 12821A Disc Interface diagnostic locates the card to test + by issuing a CLC sc,C / OTA sc / LIA sc sequence to each card in the card + cage; this writes a zero value and then looks for a specific response that + is characteristic of the DI. When the zero value is written to the MT + device (HP 3030 tape drive), it responds with "Unit not attached." + + CAUSE: The MT device is unusual in that commands are executed when they + are written to the card, rather than in response to STC. Therefore, when + the zero value is written, the MT device attempts to interpret that value + as a command. + + The IOO processor checks for a valid command before proceeding. Zero is + not a valid command, but the check is not coded properly. The search + through the command table loops for the number of bytes in the table, not + for the number of entries. One of the values beyond the end of the table + equals zero, so the command is considered valid, and unit service is + scheduled. The unit service routine determines that the unit is not + attached and returns an error code, causing a simulator stop. + + RESOLUTION: Modify "mtcio" (hp2100_mt.c) to use the count of command table + entries as the loop count. + + STATUS: Fixed in version 3.8-2. + + + +223. ENHANCEMENT: Consolidate reporting of consecutive CRS signals. + + VERSION: 3.8-1 + + OBSERVATION: HP 2000 Time Shared BASIC begins its start sequence by + issuing 128K CLC 0 instructions. This sequence is required by the 12920A + Terminal Multiplexer. If debugging is enabled, the IPL device writes 128K + lines to the log file. It would be more helpful if the ioCRS processor + detected consecutive calls and summarized them in a single line. + + RESOLUTION: Modify "iplio" (hp2100_ipl.c) to add a CRS invocation counter + and to report a single debug line for consecutive CRS calls. + + STATUS: Fixed in version 3.8-2. + + + +224. PROBLEM: Simulation stops are ignored during DMA cycles. + + VERSION: 3.8-1 + + OBSERVATION: An I/O routine may return an error code other than SCPE_OK to + stop the simulator. For example, IPL may return SCPE_IOERR if STC is + issued to a card with a disconnected socket. If the device is invoked via + programmed I/O, an error value return will cause a simulation stop. If the + device is invoked by DMA, it will not. + + CAUSE: The "iogrp" function returns the status code to the instruction + loop, but the "dma_cycle" function ignores status returns from the I/O + handlers. + + RESOLUTION: Modify "dma_cycle" (hp2100_cpu.c) to return the status from + the device signal handler, and modify "sim_instr" to stop instruction + execution if the returned status is not SCPE_OK. + + STATUS: Fixed in version 3.8-2. + + + +225. PROBLEM: Simulation stops do not always preserve the CPU state for + restarting. + + VERSION: 3.8-1 + + OBSERVATION: If the CPU simulator is stopped by certain errors, e.g., an + unimplemented instruction execution, simulation control returns with the + CPU state set as it was just prior to the error. This allows the error to + be corrected and simulation to be resumed. It also allows identification + of the problem instruction. + + Other errors, e.g., SCPE_IOERR returned by the IPL device signal handler, + stop the CPU after processing the offending instruction. In this case, the + PC points to the instruction after the offending instruction, so + identification, correction, and resumption are more difficult. DMA cycles + are also affected, as DMA registers are updated even if the I/O cycle + fails. + + CAUSE: The CPU instruction and DMA cycle routines do not back out properly + when a simulation stop is indicated by a device signal handler. + + RESOLUTION: Modify "sim_instr" (hp2100_cpu.c) to back out the current + instruction if it indicates a simulation stop (except for the HLT + instruction), modify "dma_cycle" to update the address and word count only + if the I/O cycle completes successfully, and modify "iplio" (hp2100_ipl.c) + to allow for restarting of a failed I/O cycle. + + STATUS: Fixed in version 3.8-2. + + + +226. PROBLEM: The comments for the floating-point divide routine are + incomplete. + + VERSION: 3.8-1 + + OBSERVATION: In the comments for the "divide" function in "hp2100_fp1.c", + the explanation of the simulation implementation trails off with, "The + resulting 32-bit quotient is ..." It appears that the comments were never + finished before release. + + CAUSE: Oversight. + + RESOLUTION: Expanded and completed the comments in the "divide" function + (hp2100_fp1.c). + + STATUS: Fixed in version 3.8-2. + + + +227. PROBLEM: The 79xx disc returns incorrect status for a disabled drive. + + VERSION: 3.8-1 + + OBSERVATION: The same "unit present; heads unloaded" status is reported + for both an enabled but unattached unit and a disabled unit. The latter + should report "unit not present" status. + + CAUSE: SIMH initially defines the DS device as having eight 7905 drives + connected to the controller. Each drive reports "heads unloaded" status + (status-2 bits 1-0 = 11) until it has a disc image attached. If a unit is + disabled, it continues to report "heads unloaded" status. It should be + reporting "unit not present" (status-2 bits 1-0 = 10) status. + + RESOLUTION: Modify "ds_updds2" (hp2100_ds.c) to report an "enabled and + unloaded" condition as Not Ready and Busy, and a "disabled" condition as + Not Ready only. + + STATUS: Fixed in version 3.8-2. + + + +228. PROBLEM: The 79xx disc returns incorrect status for an auto-seek beyond + the drive limits. + + VERSION: 3.8-1 + + OBSERVATION: When an auto-seek causes the disc address to move beyond the + drive limits, the wrong status is returned. For example, the following + OPDSN program: + + SM,3 -- set file mask to auto-seek, cylinder mode, incremental + SK,410,2,47 -- seek to last sector of the drive + RD,256 -- read two sectors + EN + + ...results in Cylinder Compare Error status; status-2 shows a seek check. + The result is identical if SM,1 (surface auto-seek, rather than cylinder + auto-seek) is used. + + If the RD,256 is replaced by RF,276, the result is Normal Completion and a + seek check. The resulting disc address is 411,0,1. + + If decremental seeks are used: + + SM,13 -- set file mask to auto-seek, cylinder mode, decremental + SK,0,2,47 -- seek to last sector of the first cylinder + RD,256 -- read two sectors + EN + + ...the status return is the same as above. + + In each of these cases, the result should be Status-2 (Seek Check) on the + second sector transfer. + + CAUSE: If an auto-seek exceeds the drive bounds, a seek check is correctly + detected, but it is not reported back to the host. + + RESOLUTION: Modify "ds_start_rw" (hp2100_ds.c) to check for Seek Check on + an auto-seek and to report Status-2 if set. Also, a reseek resulting from + a cylinder miscompare now either succeeds if the cylinder is valid or + reports Status-2 and Seek Check if the cylinder is invalid. Finally, an + invalid head or sector value reports Status-2 and Seek Check instead of + Head-Sector Compare Error (Head-Sector and Cylinder Compare Errors can only + occur during sparing operations which are not supported in simulation). + + STATUS: Fixed in version 3.8-2. + + + +229. PROBLEM: The Read Without Verify command does not verify the address when a + track boundary is crossed. + + VERSION: 3.8-1 + + OBSERVATION: The Read Without Verify command is identical to the Read + command except that it skips address verification before beginning the + read. If the read continues past a track boundary and auto-seek is + enabled, the new track location should be verified. This does not occur. + The following OPDSN program illustrates the problem: + + SM,3 -- set file mask to auto-seek, cylinder mode, incremental + SK,0,0,47 -- seek to last sector on cylinder 0 head 0 + DB,128,000047 -- fill the sector buffer with the CHS address + WD,128 -- write sector 0/0/47 + DB,128,000100 -- fill the sector buffer with the CHS address + WD,128 -- write sector 0/1/0 + SK,1,0,47 -- seek to the last sector on cylinder 1 head 0 + DB,128,100047 -- fill the sector buffer with the CHS address + WD,128 -- write sector 1/0/47 + DB,128,100100 -- fill the sector buffer with the CHS address + WD,128 -- write sector 1/1/0 + SK,0,0,47 -- seek to last sector on cylinder 0 head 0 + AR,1,0,47 -- change controller address to cylinder 1 + RW,256 -- read two sectors + DR,120,135 -- display end of first sector and start of second sector + EN + + If address verification is performed at the end of track 0, the second + sector will be read from 1,1,0 instead of 0,1,0 because of the cylinder + miscompare after the auto-seek: + + 0120: 000047 000047 000047 000047 000047 000047 000047 000047 + 0128: 100100 100100 100100 100100 100100 100100 100100 100100 + + However, the above program prints: + + 0120: 000047 000047 000047 000047 000047 000047 000047 000047 + 0128: 000100 000100 000100 000100 000100 000100 000100 000100 + + ...indicating that address verification was not done for either sector. + Note that if the Read Without Verify above is changed to Read (RD,256), the + result is: + + 0120: 100047 100047 100047 100047 100047 100047 100047 100047 + 0128: 100100 100100 100100 100100 100100 100100 100100 100100 + + ...indicating that address verification was done correctly for the first + sector. + + CAUSE: The Read Without Verify handler disables address verification for + the entire transfer. It should be disabled only until a track switch + occurs. + + RESOLUTION: Modify the Read Without Verify command handler in "ds_svc_u" + (hp2100_ds.c) to begin verifying if a track boundary is crossed. + + STATUS: Fixed in version 3.8-2. + + + +230. PROBLEM: The Request Sector Address command does not check the unit + number. + + VERSION: 3.8-1 + + OBSERVATION: The Request Sector Address command accepts invalid, unloaded, + or missing units without reporting status errors. Also, the specified unit + number is not reported in the status-1 field of a subsequent Request Status + command. Assuming that unit "ds1" is not attached (heads unloaded) and + unit "ds2" is disabled, the following OPDSN programs illustrate the + problem: + + SD,1 + RA + ST + SC,0001001100000001,1XXXXXX000X00011 + DR,0 + EN + + SD,2 + RA + ST + SC,0001001100000010,1XXXXXX000X00010 + DR,0 + EN + + SD,10 + RA + ST + SC + DR,0 + EN + + All of these should return Status-2 but instead return Normal Completion. + + SD,15 + RA + ST + SC,0001011100001111,1XXXXXX000X00010 + DR,0 + EN + + This should return Unit Unavailable but instead returns Normal Completion. + + CAUSE: The Request Sector Address command handler is not checking the unit + range or status. + + RESOLUTION: Modify "ds_docmd" (hp2100_ds.c) to set the unit number into + the status-1 field and to check for invalid units and report Unit + Unavailable if so. Modify "ds_svc_u" to check that the heads are loaded on + the target unit and report Status-2 if not. + + STATUS: Fixed in version 3.8-2. + + + +231. PROBLEM: The Wakeup command does not check the unit number. + + VERSION: 3.8-1 + + OBSERVATION: The Wakeup command accepts invalid units without reporting + status errors. Also, the specified unit number is not reported in the + status-1 field of a subsequent Request Status command. + + CAUSE: The Wakeup command handler is not checking the unit range. + + RESOLUTION: Modify "ds_docmd" (hp2100_ds.c) to set the unit number into + the status-1 field and to check for invalid units and report Unit + Unavailable if so. + + STATUS: Fixed in version 3.8-2. diff --git a/HP2100/hp2100_cpu.c b/HP2100/hp2100_cpu.c index 8a20b98e..0f7331b5 100644 --- a/HP2100/hp2100_cpu.c +++ b/HP2100/hp2100_cpu.c @@ -1,6 +1,6 @@ /* hp2100_cpu.c: HP 21xx/1000 CPU simulator - Copyright (c) 1993-2008, Robert M. Supnik + Copyright (c) 1993-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"), @@ -26,9 +26,21 @@ CPU 2114C/2115A/2116C/2100A/1000-M/E/F central processing unit 12731A memory expansion module MP 12581A/12892B memory protect - DMA0,DMA1 12607B/12578A/12895A direct memory access controller - DCPC0,DCPC1 12897B dual channel port controller + DMA1,DMA2 12607B/12578A/12895A direct memory access controller + DCPC1,DCPC2 12897B dual channel port controller + 07-Apr-11 JDB Fixed I/O return status bug for DMA cycles + Failed I/O cycles now stop on failing instruction + 28-Mar-11 JDB Tidied up signal handling + 29-Oct-10 JDB Revised DMA for new multi-card paradigm + Consolidated DMA reset routines + DMA channels renamed from 0,1 to 1,2 to match documentation + 27-Oct-10 JDB Changed I/O instructions, handlers, and DMA for revised signal model + Changed I/O dispatch table to use DIB pointers + 19-Oct-10 JDB Removed DMA latency counter + 13-Oct-10 JDB Fixed DMA requests to enable stealing every cycle + Fixed DMA priority for channel 1 over channel 2 + Corrected comments for "cpu_set_idle" 30-Sep-08 JDB Breakpoints on interrupt trap cells now work 05-Sep-08 JDB VIS and IOP are now mutually exclusive on 1000-F 11-Aug-08 JDB Removed A/B shadow register variables @@ -442,22 +454,31 @@ /* DMA channels */ +typedef enum { ch1, ch2 } CHANNEL; /* channel number */ + +#define DMA_CHAN_COUNT 2 /* number of DMA channels */ + #define DMA_OE 020000000000 /* byte packing odd/even flag */ #define DMA1_STC 0100000 /* DMA - issue STC */ #define DMA1_PB 0040000 /* DMA - pack bytes */ #define DMA1_CLC 0020000 /* DMA - issue CLC */ #define DMA2_OI 0100000 /* DMA - output/input */ -struct DMA { /* DMA channel */ - uint32 cw1; /* device select */ - uint32 cw2; /* direction, address */ - uint32 cw3; /* word count */ - uint32 latency; /* 1st cycle delay */ - uint32 packer; /* byte-packer holding reg */ - }; +typedef struct { + FLIP_FLOP control; /* control flip-flop */ + FLIP_FLOP flag; /* flag flip-flop */ + FLIP_FLOP flagbuf; /* flag buffer flip-flop */ + FLIP_FLOP xferen; /* transfer enable flip-flop */ + FLIP_FLOP select; /* register select flip-flop */ -#define DMAR0 1 -#define DMAR1 2 + uint32 cw1; /* device select */ + uint32 cw2; /* direction, address */ + uint32 cw3; /* word count */ + uint32 packer; /* byte-packer holding reg */ + } DMA_STATE; + +#define DMA_1_REQ (1 << ch1) /* channel 1 request */ +#define DMA_2_REQ (1 << ch2) /* channel 2 request */ /* Command line switches */ @@ -525,12 +546,7 @@ jmp_buf save_env; /* MP abort handler */ /* DMA global data */ -struct DMA dmac[2] = { { 0 }, { 0 } }; /* DMA channels */ -FLIP_FLOP dma_xferen [2] = { CLEAR, CLEAR }; /* transfer enable flip-flops */ -FLIP_FLOP dma_control [2] = { CLEAR, CLEAR }; /* control flip-flops */ -FLIP_FLOP dma_flag [2] = { CLEAR, CLEAR }; /* flag flip-flops */ -FLIP_FLOP dma_flagbuf [2] = { CLEAR, CLEAR }; /* flag buffer flip-flops */ -FLIP_FLOP dma_select [2] = { CLEAR, CLEAR }; /* register select flip-flops */ +DMA_STATE dma [DMA_CHAN_COUNT]; /* per-channel state */ /* Dynamic mapping system global data */ @@ -558,10 +574,10 @@ static t_stat Ea (uint32 IR, uint32 *addr, uint32 irq); static uint16 ReadTAB (uint32 va); static uint32 dms (uint32 va, uint32 map, uint32 prot); static uint32 shift (uint32 inval, uint32 flag, uint32 oper); -static void dma_cycle (uint32 chan, uint32 map); +static t_stat dma_cycle (CHANNEL chan, uint32 map); static uint32 calc_dma (void); static t_bool dev_conflict (void); -static uint32 devdisp (uint32 select_code, IOSIG signal, uint32 data); +static uint32 devdisp (uint32 select_code, IOCYCLE signal_set, uint16 data); /* CPU global routines */ @@ -570,8 +586,7 @@ 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 mp_reset (DEVICE *dptr); -t_stat dma0_reset (DEVICE *dptr); -t_stat dma1_reset (DEVICE *dptr); +t_stat dma_reset (DEVICE *dptr); t_stat cpu_set_size (UNIT *uptr, int32 new_size, char *cptr, void *desc); t_stat cpu_set_model (UNIT *uptr, int32 new_model, char *cptr, void *desc); t_stat cpu_show_model (FILE *st, UNIT *uptr, int32 val, void *desc); @@ -582,13 +597,13 @@ t_stat cpu_set_idle (UNIT *uptr, int32 option, char *cptr, void *desc); t_stat cpu_show_idle (FILE *st, UNIT *uptr, int32 val, void *desc); void hp_post_cmd (t_bool from_scp); -uint32 cpuio (uint32 select_code, IOSIG signal, uint32 data); -uint32 ovflio (uint32 select_code, IOSIG signal, uint32 data); -uint32 pwrfio (uint32 select_code, IOSIG signal, uint32 data); -uint32 protio (uint32 select_code, IOSIG signal, uint32 data); -uint32 dmasio (uint32 select_code, IOSIG signal, uint32 data); -uint32 dmapio (uint32 select_code, IOSIG signal, uint32 data); -uint32 nullio (uint32 select_code, IOSIG signal, uint32 data); +IOHANDLER cpuio; +IOHANDLER ovflio; +IOHANDLER pwrfio; +IOHANDLER protio; +IOHANDLER dmapio; +IOHANDLER dmasio; +IOHANDLER nullio; /* External routines */ @@ -652,8 +667,13 @@ static struct FEATURE_TABLE cpu_features[] = { /* features in UNIT_xxxx }; +/* Null device information block */ + +DIB null_dib = { &nullio, 0 }; + /* CPU data structures + cpu_dib CPU device information block cpu_dev CPU device descriptor cpu_unit CPU unit descriptor cpu_reg CPU register list @@ -661,6 +681,8 @@ static struct FEATURE_TABLE cpu_features[] = { /* features in UNIT_xxxx cpu_deb CPU debug flags */ +DIB cpu_dib = { &cpuio, CPU }; + UNIT cpu_unit = { UDATA (NULL, UNIT_FIX + UNIT_BINK, 0) }; REG cpu_reg[] = { @@ -815,13 +837,21 @@ DEVICE cpu_dev = { &cpu_boot, /* boot routine */ NULL, /* attach routine */ NULL, /* detach routine */ - NULL, /* device information block */ + &cpu_dib, /* device information block */ DEV_DEBUG, /* device flags */ 0, /* debug control flags */ cpu_deb, /* debug flag name table */ NULL, /* memory size change routine */ NULL }; /* logical device name */ +/* Overflow device information block */ + +DIB ovfl_dib = { &ovflio, OVF }; + +/* Powerfail device information block */ + +DIB pwrf_dib = { &pwrfio, PWR }; + /* Memory protect data structures mp_dib MP device information block @@ -831,7 +861,7 @@ DEVICE cpu_dev = { mp_mod MP modifiers list */ -DIB mp_dib = { PRO, &protio }; +DIB mp_dib = { &protio, PRO }; UNIT mp_unit = { UDATA (NULL, UNIT_MP_SEL1, 0) }; /* default is JSB in, INT in, SEL1 out */ @@ -887,65 +917,22 @@ DEVICE mp_dev = { dmax_reg DMAx register list */ -DIB dma0_dib = { DMA0, &dmapio }; - -UNIT dma0_unit = { UDATA (NULL, 0, 0) }; - -REG dma0_reg[] = { - { FLDATA (XFR, dma_xferen [0], 0) }, - { FLDATA (CTL, dma_control [0], 0) }, - { FLDATA (FLG, dma_flag [0], 0) }, - { FLDATA (FBF, dma_flagbuf [0], 0) }, - { FLDATA (CTL2, dma_select [0], 0) }, - { ORDATA (CW1, dmac[0].cw1, 16) }, - { ORDATA (CW2, dmac[0].cw2, 16) }, - { ORDATA (CW3, dmac[0].cw3, 16) }, - { DRDATA (LATENCY, dmac[0].latency, 8) }, - { FLDATA (BYTE, dmac[0].packer, 31) }, - { ORDATA (PACKER, dmac[0].packer, 8) }, - { NULL } - }; - -DEVICE dma0_dev = { - "DMA0", /* device name */ - &dma0_unit, /* unit array */ - dma0_reg, /* register array */ - NULL, /* modifier array */ - 1, /* number of units */ - 8, /* address radix */ - 1, /* address width */ - 1, /* address increment */ - 8, /* data radix */ - 16, /* data width */ - NULL, /* examine routine */ - NULL, /* deposit routine */ - &dma0_reset, /* reset routine */ - NULL, /* boot routine */ - NULL, /* attach routine */ - NULL, /* detach routine */ - &dma0_dib, /* device information block */ - DEV_DISABLE, /* device flags */ - 0, /* debug control flags */ - NULL, /* debug flag name table */ - NULL, /* memory size change routine */ - NULL }; /* logical device name */ - -DIB dma1_dib = { DMA1, &dmapio }; +DIB dmap1_dib = { &dmapio, DMA1, ch1 }; +DIB dmas1_dib = { &dmasio, DMALT1, ch1 }; UNIT dma1_unit = { UDATA (NULL, 0, 0) }; REG dma1_reg[] = { - { FLDATA (XFR, dma_xferen [1], 0) }, - { FLDATA (CTL, dma_control [1], 0) }, - { FLDATA (FLG, dma_flag [1], 0) }, - { FLDATA (FBF, dma_flagbuf [1], 0) }, - { FLDATA (CTL3, dma_select [1], 0) }, - { ORDATA (CW1, dmac[1].cw1, 16) }, - { ORDATA (CW2, dmac[1].cw2, 16) }, - { ORDATA (CW3, dmac[1].cw3, 16) }, - { DRDATA (LATENCY, dmac[1].latency, 8) }, - { FLDATA (BYTE, dmac[1].packer, 31) }, - { ORDATA (PACKER, dmac[1].packer, 8) }, + { FLDATA (XFR, dma [ch1].xferen, 0) }, + { FLDATA (CTL, dma [ch1].control, 0) }, + { FLDATA (FLG, dma [ch1].flag, 0) }, + { FLDATA (FBF, dma [ch1].flagbuf, 0) }, + { FLDATA (CTL2, dma [ch1].select, 0) }, + { ORDATA (CW1, dma [ch1].cw1, 16) }, + { ORDATA (CW2, dma [ch1].cw2, 16) }, + { ORDATA (CW3, dma [ch1].cw3, 16) }, + { FLDATA (BYTE, dma [ch1].packer, 31) }, + { ORDATA (PACKER, dma [ch1].packer, 8) }, { NULL } }; @@ -962,50 +949,97 @@ DEVICE dma1_dev = { 16, /* data width */ NULL, /* examine routine */ NULL, /* deposit routine */ - &dma1_reset, /* reset routine */ + &dma_reset, /* reset routine */ NULL, /* boot routine */ NULL, /* attach routine */ NULL, /* detach routine */ - &dma1_dib, /* device information block */ + &dmap1_dib, /* device information block */ DEV_DISABLE, /* device flags */ 0, /* debug control flags */ NULL, /* debug flag name table */ NULL, /* memory size change routine */ NULL }; /* logical device name */ +DIB dmap2_dib = { &dmapio, DMA2, ch2 }; +DIB dmas2_dib = { &dmasio, DMALT2, ch2 }; + +UNIT dma2_unit = { UDATA (NULL, 0, 0) }; + +REG dma2_reg[] = { + { FLDATA (XFR, dma [ch2].xferen, 0) }, + { FLDATA (CTL, dma [ch2].control, 0) }, + { FLDATA (FLG, dma [ch2].flag, 0) }, + { FLDATA (FBF, dma [ch2].flagbuf, 0) }, + { FLDATA (CTL2, dma [ch2].select, 0) }, + { ORDATA (CW1, dma [ch2].cw1, 16) }, + { ORDATA (CW2, dma [ch2].cw2, 16) }, + { ORDATA (CW3, dma [ch2].cw3, 16) }, + { FLDATA (BYTE, dma [ch2].packer, 31) }, + { ORDATA (PACKER, dma [ch2].packer, 8) }, + { NULL } + }; + +DEVICE dma2_dev = { + "DMA2", /* device name */ + &dma2_unit, /* unit array */ + dma2_reg, /* register array */ + NULL, /* modifier array */ + 1, /* number of units */ + 8, /* address radix */ + 1, /* address width */ + 1, /* address increment */ + 8, /* data radix */ + 16, /* data width */ + NULL, /* examine routine */ + NULL, /* deposit routine */ + &dma_reset, /* reset routine */ + NULL, /* boot routine */ + NULL, /* attach routine */ + NULL, /* detach routine */ + &dmap2_dib, /* device information block */ + DEV_DISABLE, /* device flags */ + 0, /* debug control flags */ + NULL, /* debug flag name table */ + NULL, /* memory size change routine */ + NULL }; /* logical device name */ + +static DEVICE *dma_dptrs [] = { &dma1_dev, &dma2_dev }; + /* Interrupt deferral table (1000 version) */ /* Deferral for I/O subops: soHLT, soFLG, soSFC, soSFS, soMIX, soLIX, soOTX, soCTL */ static t_bool defer_tab [] = { FALSE, TRUE, TRUE, TRUE, FALSE, FALSE, FALSE, TRUE }; -/* Device dispatch table */ +/* Device I/O dispatch table */ + +DIB *dtab [64] = { &cpu_dib, &ovfl_dib }; /* init with immutable devices */ -IODISP *dtab[64] = { &cpuio, &ovflio }; /* init with immutable devices */ /* Execute CPU instructions. This routine is the instruction decode routine for the HP 2100. 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. + memory, starting at the simulated PC. It runs until 'reason' is set to a + status other than SCPE_OK. */ t_stat sim_instr (void) { uint32 intrq, dmarq; /* set after setjmp */ uint32 iotrap = 0; /* set after setjmp */ -t_stat reason; /* set after setjmp */ +t_stat reason = SCPE_OK; /* set after setjmp */ int32 i; /* temp */ DEVICE *dptr; /* temp */ -DIB *dibp; /* temp */ +DIB *dibptr; /* temp */ int abortval; /* Restore register state */ -if (dev_conflict ()) return SCPE_STOP; /* check consistency */ +if (dev_conflict ()) /* check device assignment consistency */ + return SCPE_STOP; /* conflict; stop execution */ + err_PC = PC = PC & VAMASK; /* load local PC */ -reason = 0; /* Restore I/O state */ @@ -1013,25 +1047,25 @@ dev_prl [0] = dev_prl [1] = ~(uint32) 0; /* set all priority lows dev_irq [0] = dev_irq [1] = 0; /* clear all interrupt requests */ dev_srq [0] = dev_srq [1] = 0; /* clear all service requests */ -for (i = OPTDEV; i <= I_DEVMASK; i++) /* default optional devices dispatch */ - dtab [i] = &nullio; +for (i = OPTDEV; i <= MAXDEV; i++) /* default optional devices */ + dtab [i] = &null_dib; -dtab [PWR] = &pwrfio; /* for now, powerfail is always present */ +dtab [PWR] = &pwrf_dib; /* for now, powerfail is always present */ for (i = 0; dptr = sim_devices [i]; i++) { /* loop thru dev */ - dibp = (DIB *) dptr->ctxt; /* get DIB */ + dibptr = (DIB *) dptr->ctxt; /* get DIB */ - if (dibp && !(dptr->flags & DEV_DIS)) { /* exist, enabled? */ - dtab [dibp->devno] = dibp->iot; /* set I/O signal dispatch */ - dtab [dibp->devno] (dibp->devno, ioSIR, 0); /* set interrupt request state */ + if (dibptr && !(dptr->flags & DEV_DIS)) { /* handler exists and device is enabled? */ + dtab [dibptr->select_code] = dibptr; /* set DIB pointer into dispatch table */ + dibptr->io_handler (dibptr, ioSIR, 0); /* set interrupt request state */ } } -if (dtab [DMA0] == &dmapio) /* first DMA channel enabled? */ - dtab [DMALT0] = &dmasio; /* set up secondary handler */ +if (dtab [DMA1] != &null_dib) /* first DMA channel enabled? */ + dtab [DMALT1] = &dmas1_dib; /* set up secondary device handler */ -if (dtab [DMA1] == &dmapio) /* second DMA channel enabled? */ - dtab [DMALT1] = &dmasio; /* set up secondary handler */ +if (dtab [DMA2] != &null_dib) /* second DMA channel enabled? */ + dtab [DMALT2] = &dmas2_dib; /* set up secondary device handler */ /* Configure interrupt deferral table */ @@ -1085,7 +1119,7 @@ if (abortval) { /* memory protect abort? dms_upd_vr (abortval); /* update violation register (if not MEV) */ if (ion) /* interrupt system on? */ - protio (PRO, ioENF, 0); /* set flag */ + protio (dtab [PRO], ioENF, 0); /* set flag */ } dmarq = calc_dma (); /* initial recalc of DMA masks */ @@ -1094,30 +1128,92 @@ intrq = calc_int (); /* initial recalc of int /* Main instruction fetch/decode loop */ -while (reason == 0) { /* loop until halted */ +while (reason == SCPE_OK) { /* loop until halted */ uint32 IR, MA, absel, v1, t, skip; + err_PC = PC; /* save PC for error recovery */ + if (sim_interval <= 0) { /* event timeout? */ - if (reason = sim_process_event ()) /* process event service */ - break; /* service status not OK */ + reason = sim_process_event (); /* process event service */ + + if (reason != SCPE_OK) /* service failed? */ + break; /* stop execution */ dmarq = calc_dma (); /* recalc DMA reqs */ intrq = calc_int (); /* recalc interrupts */ } +/* DMA cycles are requested by an I/O card asserting its SRQ signal. If a DMA + channel is programmed to respond to that card's select code, a DMA cycle will + be initiated. A DMA cycle consists of a memory cycle and an I/O cycle. + These cycles are synchronized with the control processor on the 21xx CPUs. + On the 1000s, memory cycles are asynchronous, while I/O cycles are + synchronous. Memory cycle time is about 40% of the I/O cycle time. + + With properly designed interface cards, DMA is capable of taking consecutive + I/O cycles. On all machines except the 1000 M-Series, a DMA cycle freezes + the CPU for the duration of the cycle. On the M-Series, a DMA cycle freezes + the CPU if it attempts an I/O cycle (including IAK) or a directly-interfering + memory cycle. An interleaved memory cycle is allowed. Otherwise, the + control processor is allowed to run. Therefore, during consecutive DMA + cycles, the M-Series CPU will run until an IOG instruction is attempted, + whereas the other CPUs will freeze completely. + + All DMA cards except the 12607B provide two independent channels. If both + channels are active simultaneously, channel 1 has priority for I/O cycles + over channel 2. + + Most I/O cards assert SRQ no more than 50% of the time. A few buffered + cards, such as the 12821A and 13175A Disc Interfaces, are capable of + asserting SRQ continuously while filling or emptying the buffer. If SRQ for + channel 1 is asserted continuously when both channels are active, then no + channel 2 cycles will occur until channel 1 completes. + + Implementation notes: + + 1. CPU freeze is simulated by skipping instruction execution during the + current loop cycle. + + 2. If both channels have SRQ asserted, DMA priority is simulated by skipping + the channel 2 cycle if channel 1's SRQ is still asserted at the end of + its cycle. If it is not, then channel 2 steals the next cycle from the + CPU. + + 3. The 1000 M-Series allows some CPU processing concurrently with + continuous DMA cycles, whereas all other CPUs freeze. The processor + freezes if an I/O cycle is attempted, including an interrupt + acknowledgement. Because some microcode extensions (e.g., Access IOP, + RTE-6/VM OS) perform I/O cycles, advance detection of I/O cycles is + difficult. Therefore, we freeze all processing for the M-Series as well. +*/ + if (dmarq) { - if (dmarq & DMAR0) /* DMA channel 1 request? */ - dma_cycle (0, PAMAP); /* do one DMA cycle using port A map */ + if (dmarq & DMA_1_REQ) { /* DMA channel 1 request? */ + reason = dma_cycle (ch1, PAMAP); /* do one DMA cycle using port A map */ - if (dmarq & DMAR1) /* DMA channel 2 request? */ - dma_cycle (1, PBMAP); /* do one DMA cycle using port B map */ + if (reason == SCPE_OK) /* cycle OK? */ + dmarq = calc_dma (); /* recalc DMA requests */ + else + break; /* cycle failed, so stop */ + } - dmarq = calc_dma (); /* recalc DMA requests */ - intrq = calc_int (); /* recalc interrupts */ + if ((dmarq & (DMA_1_REQ | DMA_2_REQ)) == DMA_2_REQ) { /* DMA channel 1 idle and channel 2 request? */ + reason = dma_cycle (ch2, PBMAP); /* do one DMA cycle using port B map */ + + if (reason == SCPE_OK) /* cycle OK? */ + dmarq = calc_dma (); /* recalc DMA requests */ + else + break; /* cycle failed, so stop */ + } + + if (dmarq) /* DMA request still pending? */ + continue; /* service it before instruction execution */ + + intrq = calc_int (); /* recalc interrupts */ } - if (intrq && ion_defer) /* interrupt pending but deferred? */ - ion_defer = calc_defer (); /* confirm deferral */ + if (intrq && ion_defer) /* interrupt pending but deferred? */ + ion_defer = calc_defer (); /* confirm deferral */ /* Check for pending interrupt request. @@ -1182,23 +1278,28 @@ while (reason == 0) { /* loop until halted */ IR = ReadW (intaddr); /* get trap cell instruction */ - devdisp (intaddr, ioIAK, IR); /* acknowledge interrupt */ + devdisp (intaddr, ioIAK, (uint16) IR); /* acknowledge interrupt */ if (intaddr != PRO) /* not MP interrupt? */ - protio (intaddr, ioIAK, IR); /* send IAK for device to MP too */ + protio (dtab [intaddr], ioIAK, IR); /* send IAK for device to MP too */ } else { /* normal instruction */ iotrap = 0; /* not a trap cell instruction */ - err_PC = PC; /* save PC for error */ + if (sim_brk_summ && /* any breakpoints? */ sim_brk_test (PC, SWMASK ('E') | /* unconditional or */ - (dms_enb? (dms_ump? SWMASK ('U'): SWMASK ('S')): - SWMASK ('N')))) { /* or right type for DMS? */ + (dms_enb ? /* correct type for DMS state? */ + (dms_ump ? + SWMASK ('U') : SWMASK ('S')) : + SWMASK ('N')))) { reason = STOP_IBKPT; /* stop simulation */ break; } - if (mp_evrff) mp_viol = PC; /* if ok, upd mp_viol */ + + if (mp_evrff) /* violation register enabled */ + mp_viol = PC; /* update with current PC */ + IR = ReadW (PC); /* fetch instr */ PC = (PC + 1) & VAMASK; ion_defer = FALSE; @@ -1221,7 +1322,8 @@ while (reason == 0) { /* loop until halted */ 1 0 0 0 1 0 1 0 extended instr group 0 (A/B must be set) 1 0 0 0 x 0 1 1 extended instr group 1 (A/B ignored) */ - absel = (IR & I_AB)? 1: 0; /* get A/B select */ + absel = (IR & I_AB) ? 1 : 0; /* get A/B select */ + switch ((IR >> 8) & 0377) { /* decode IR<15:8> */ /* Memory reference instructions */ @@ -1230,7 +1332,11 @@ while (reason == 0) { /* loop until halted */ case 0024:case 0025:case 0026:case 0027: case 0220:case 0221:case 0222:case 0223: case 0224:case 0225:case 0226:case 0227: - if (reason = Ea (IR, &MA, intrq)) break; /* AND */ + reason = Ea (IR, &MA, intrq); /* AND */ + + if (reason != SCPE_OK) /* address failed to resolve? */ + break; /* stop execution */ + AR = AR & ReadW (MA); break; @@ -1250,7 +1356,10 @@ while (reason == 0) { /* loop until halted */ case 0030:case 0031:case 0032:case 0033: case 0034:case 0035:case 0036:case 0037: - if (reason = Ea (IR, &MA, intrq)) break; /* JSB */ + reason = Ea (IR, &MA, intrq); /* JSB */ + + if (reason != SCPE_OK) /* address failed to resolve? */ + break; /* stop execution */ mp_dms_jmp (MA, jsb_plb); /* validate jump address */ @@ -1263,7 +1372,11 @@ while (reason == 0) { /* loop until halted */ case 0044:case 0045:case 0046:case 0047: case 0240:case 0241:case 0242:case 0243: case 0244:case 0245:case 0246:case 0247: - if (reason = Ea (IR, &MA, intrq)) break; /* XOR */ + reason = Ea (IR, &MA, intrq); /* XOR */ + + if (reason != SCPE_OK) /* address failed to resolve? */ + break; /* stop execution */ + AR = AR ^ ReadW (MA); break; @@ -1317,7 +1430,11 @@ while (reason == 0) { /* loop until halted */ case 0050:case 0051:case 0052:case 0053: case 0054:case 0055:case 0056:case 0057: - if (reason = Ea (IR, &MA, intrq)) break; /* JMP */ + reason = Ea (IR, &MA, intrq); /* JMP */ + + if (reason != SCPE_OK) /* address failed to resolve? */ + break; /* stop execution */ + mp_dms_jmp (MA, 0); /* validate jump addr */ PCQ_ENTRY; PC = MA; /* jump */ @@ -1349,7 +1466,7 @@ while (reason == 0) { /* loop until halted */ ((PC == (err_PC - 1)) && /* RTE-6/VM */ ((ReadW (PC) & I_MRG) == I_ISZ))) && /* RTE jump target */ (mp_fence == CLEAR) && (M [xeqt] == 0) && /* RTE idle indications */ - (M [tbg] == clk_dib.devno) || /* RTE verification */ + (M [tbg] == clk_dib.select_code) || /* RTE verification */ (PC == (err_PC - 3)) && /* DOS through DOS-III */ (ReadW (PC) == I_STF) && /* DOS jump target */ @@ -1364,7 +1481,11 @@ while (reason == 0) { /* loop until halted */ case 0064:case 0065:case 0066:case 0067: case 0260:case 0261:case 0262:case 0263: case 0264:case 0265:case 0266:case 0267: - if (reason = Ea (IR, &MA, intrq)) break; /* IOR */ + reason = Ea (IR, &MA, intrq); /* IOR */ + + if (reason != SCPE_OK) /* address failed to resolve? */ + break; /* stop execution */ + AR = AR | ReadW (MA); break; @@ -1372,21 +1493,36 @@ while (reason == 0) { /* loop until halted */ case 0074:case 0075:case 0076:case 0077: case 0270:case 0271:case 0272:case 0273: case 0274:case 0275:case 0276:case 0277: - if (reason = Ea (IR, &MA, intrq)) break; /* ISZ */ + reason = Ea (IR, &MA, intrq); /* ISZ */ + + if (reason != SCPE_OK) /* address failed to resolve? */ + break; /* stop execution */ + t = (ReadW (MA) + 1) & DMASK; WriteW (MA, t); - if (t == 0) PC = (PC + 1) & VAMASK; + + if (t == 0) + PC = (PC + 1) & VAMASK; break; case 0100:case 0101:case 0102:case 0103: case 0104:case 0105:case 0106:case 0107: case 0300:case 0301:case 0302:case 0303: case 0304:case 0305:case 0306:case 0307: - if (reason = Ea (IR, &MA, intrq)) break; /* ADA */ + reason = Ea (IR, &MA, intrq); /* ADA */ + + if (reason != SCPE_OK) /* address failed to resolve? */ + break; /* stop execution */ + v1 = ReadW (MA); t = AR + v1; - if (t > DMASK) E = 1; - if (((~AR ^ v1) & (AR ^ t)) & SIGN) O = 1; + + if (t > DMASK) + E = 1; + + if (((~AR ^ v1) & (AR ^ t)) & SIGN) + O = 1; + AR = t & DMASK; break; @@ -1394,11 +1530,20 @@ while (reason == 0) { /* loop until halted */ case 0114:case 0115:case 0116:case 0117: case 0310:case 0311:case 0312:case 0313: case 0314:case 0315:case 0316:case 0317: - if (reason = Ea (IR, &MA, intrq)) break; /* ADB */ + reason = Ea (IR, &MA, intrq); /* ADB */ + + if (reason != SCPE_OK) /* address failed to resolve? */ + break; /* stop execution */ + v1 = ReadW (MA); t = BR + v1; - if (t > DMASK) E = 1; - if (((~BR ^ v1) & (BR ^ t)) & SIGN) O = 1; + + if (t > DMASK) + E = 1; + + if (((~BR ^ v1) & (BR ^ t)) & SIGN) + O = 1; + BR = t & DMASK; break; @@ -1406,23 +1551,37 @@ while (reason == 0) { /* loop until halted */ case 0124:case 0125:case 0126:case 0127: case 0320:case 0321:case 0322:case 0323: case 0324:case 0325:case 0326:case 0327: - if (reason = Ea (IR, &MA, intrq)) break; /* CPA */ - if (AR != ReadW (MA)) PC = (PC + 1) & VAMASK; + reason = Ea (IR, &MA, intrq); /* CPA */ + + if (reason != SCPE_OK) /* address failed to resolve? */ + break; /* stop execution */ + + if (AR != ReadW (MA)) + PC = (PC + 1) & VAMASK; break; case 0130:case 0131:case 0132:case 0133: case 0134:case 0135:case 0136:case 0137: case 0330:case 0331:case 0332:case 0333: case 0334:case 0335:case 0336:case 0337: - if (reason = Ea (IR, &MA, intrq)) break; /* CPB */ - if (BR != ReadW (MA)) PC = (PC + 1) & VAMASK; + reason = Ea (IR, &MA, intrq); /* CPB */ + + if (reason != SCPE_OK) /* address failed to resolve? */ + break; /* stop execution */ + + if (BR != ReadW (MA)) + PC = (PC + 1) & VAMASK; break; case 0140:case 0141:case 0142:case 0143: case 0144:case 0145:case 0146:case 0147: case 0340:case 0341:case 0342:case 0343: case 0344:case 0345:case 0346:case 0347: - if (reason = Ea (IR, &MA, intrq)) break; /* LDA */ + reason = Ea (IR, &MA, intrq); /* LDA */ + + if (reason != SCPE_OK) /* address failed to resolve? */ + break; /* stop execution */ + AR = ReadW (MA); break; @@ -1430,7 +1589,11 @@ while (reason == 0) { /* loop until halted */ case 0154:case 0155:case 0156:case 0157: case 0350:case 0351:case 0352:case 0353: case 0354:case 0355:case 0356:case 0357: - if (reason = Ea (IR, &MA, intrq)) break; /* LDB */ + reason = Ea (IR, &MA, intrq); /* LDB */ + + if (reason != SCPE_OK) /* address failed to resolve? */ + break; /* stop execution */ + BR = ReadW (MA); break; @@ -1438,7 +1601,11 @@ while (reason == 0) { /* loop until halted */ case 0164:case 0165:case 0166:case 0167: case 0360:case 0361:case 0362:case 0363: case 0364:case 0365:case 0366:case 0367: - if (reason = Ea (IR, &MA, intrq)) break; /* STA */ + reason = Ea (IR, &MA, intrq); /* STA */ + + if (reason != SCPE_OK) /* address failed to resolve? */ + break; /* stop execution */ + WriteW (MA, AR); break; @@ -1446,7 +1613,11 @@ while (reason == 0) { /* loop until halted */ case 0174:case 0175:case 0176:case 0177: case 0370:case 0371:case 0372:case 0373: case 0374:case 0375:case 0376:case 0377: - if (reason = Ea (IR, &MA, intrq)) break; /* STB */ + reason = Ea (IR, &MA, intrq); /* STB */ + + if (reason != SCPE_OK) /* address failed to resolve? */ + break; /* stop execution */ + WriteW (MA, BR); break; @@ -1455,42 +1626,85 @@ while (reason == 0) { /* loop until halted */ case 0004:case 0005:case 0006:case 0007: case 0014:case 0015:case 0016:case 0017: skip = 0; /* no skip */ - if (IR & 000400) t = 0; /* CLx */ - else t = ABREG[absel]; - if (IR & 001000) t = t ^ DMASK; /* CMx */ + + if (IR & 000400) /* CLx */ + t = 0; + else + t = ABREG[absel]; + + if (IR & 001000) /* CMx */ + t = t ^ DMASK; + if (IR & 000001) { /* RSS? */ - if ((IR & 000040) && (E != 0)) skip = 1; /* SEZ,RSS */ - if (IR & 000100) E = 0; /* CLE */ - if (IR & 000200) E = E ^ 1; /* CME */ + if ((IR & 000040) && (E != 0)) /* SEZ,RSS */ + skip = 1; + + if (IR & 000100) /* CLE */ + E = 0; + + if (IR & 000200) /* CME */ + E = E ^ 1; + if (((IR & 000030) == 000030) && /* SSx,SLx,RSS */ - ((t & 0100001) == 0100001)) skip = 1; + ((t & 0100001) == 0100001)) + skip = 1; + if (((IR & 000030) == 000020) && /* SSx,RSS */ - ((t & SIGN) != 0)) skip = 1; + ((t & SIGN) != 0)) + skip = 1; + if (((IR & 000030) == 000010) && /* SLx,RSS */ - ((t & 1) != 0)) skip = 1; + ((t & 1) != 0)) + skip = 1; + if (IR & 000004) { /* INx */ t = (t + 1) & DMASK; - if (t == 0) E = 1; - if (t == SIGN) O = 1; + + if (t == 0) + E = 1; + + if (t == SIGN) + O = 1; } - if ((IR & 000002) && (t != 0)) skip = 1; /* SZx,RSS */ - if ((IR & 000072) == 0) skip = 1; /* RSS */ + + if ((IR & 000002) && (t != 0)) /* SZx,RSS */ + skip = 1; + + if ((IR & 000072) == 0) /* RSS */ + skip = 1; } /* end if RSS */ + else { - if ((IR & 000040) && (E == 0)) skip = 1; /* SEZ */ - if (IR & 000100) E = 0; /* CLE */ - if (IR & 000200) E = E ^ 1; /* CME */ + if ((IR & 000040) && (E == 0)) /* SEZ */ + skip = 1; + + if (IR & 000100) /* CLE */ + E = 0; + + if (IR & 000200) /* CME */ + E = E ^ 1; + if ((IR & 000020) && /* SSx */ - ((t & SIGN) == 0)) skip = 1; + ((t & SIGN) == 0)) + skip = 1; + if ((IR & 000010) && /* SLx */ - ((t & 1) == 0)) skip = 1; + ((t & 1) == 0)) + skip = 1; + if (IR & 000004) { /* INx */ t = (t + 1) & DMASK; - if (t == 0) E = 1; - if (t == SIGN) O = 1; + + if (t == 0) + E = 1; + + if (t == SIGN) + O = 1; } - if ((IR & 000002) && (t == 0)) skip = 1; /* SZx */ + if ((IR & 000002) && (t == 0)) /* SZx */ + skip = 1; } /* end if ~RSS */ + ABREG[absel] = t; /* store result */ PC = (PC + skip) & VAMASK; /* add in skip */ break; /* end if alter/skip */ @@ -1500,9 +1714,13 @@ while (reason == 0) { /* loop until halted */ case 0000:case 0001:case 0002:case 0003: case 0010:case 0011:case 0012:case 0013: t = shift (ABREG[absel], IR & 01000, IR >> 6); /* do first shift */ - if (IR & 000040) E = 0; /* CLE */ + + if (IR & 000040) /* CLE */ + E = 0; + if ((IR & 000010) && ((t & 1) == 0)) /* SLx */ PC = (PC + 1) & VAMASK; + ABREG[absel] = shift (t, IR & 00020, IR); /* do second shift */ break; /* end if shift */ @@ -1538,33 +1756,44 @@ while (reason == 0) { /* loop until halted */ if (reason == NOTE_IOG) { /* I/O instr exec? */ dmarq = calc_dma (); /* recalc DMA masks */ intrq = calc_int (); /* recalc interrupts */ - reason = 0; /* continue */ + reason = SCPE_OK; /* continue */ } else if (reason == NOTE_INDINT) { /* intr pend during indir? */ PC = err_PC; /* back out of inst */ - reason = 0; /* continue */ + reason = SCPE_OK; /* continue */ } } /* end while */ /* Simulation halted */ -if (iotrap && (reason == STOP_HALT)) MR = intaddr; /* HLT in trap cell? */ -else MR = (PC - 1) & VAMASK; /* no, M = P - 1 */ -TR = ReadTAB (MR); /* last word fetched */ +if (iotrap && (reason == STOP_HALT)) /* HLT in trap cell? */ + MR = intaddr; /* M = interrupt address */ +else /* normal HLT */ + MR = (PC - 1) & VAMASK; /* M = P - 1 */ + +TR = ReadTAB (MR); /* T = last word fetched */ saved_MR = MR; /* save for T cmd update */ -if ((reason == STOP_RSRV) || (reason == STOP_IODV) || /* instr error? */ - (reason == STOP_IND)) PC = err_PC; /* back up PC */ + +if (reason == STOP_HALT) /* programmed halt? */ + cpu_set_ldr (NULL, FALSE, NULL, NULL); /* disable loader (after T is read) */ +else /* simulation stop */ + PC = err_PC; /* back out instruction */ + dms_upd_sr (); /* update dms_sr */ dms_upd_vr (MR); /* update dms_vr */ -if (reason == STOP_HALT) /* programmed halt? */ - cpu_set_ldr (NULL, FALSE, NULL, NULL); /* disable loader (ignore errors) */ pcq_r->qptr = pcq_p; /* update pc q ptr */ -if (dms_enb) /* default breakpoint type */ - if (dms_ump) sim_brk_dflt = SWMASK ('U'); /* to current map mode */ - else sim_brk_dflt = SWMASK ('S'); -else sim_brk_dflt = SWMASK ('N'); -return reason; + +if (dms_enb) /* DMS enabled? */ + if (dms_ump) /* set default */ + sim_brk_dflt = SWMASK ('U'); /* breakpoint type */ + else /* to current */ + sim_brk_dflt = SWMASK ('S'); /* map mode */ + +else /* DMS disabled */ + sim_brk_dflt = SWMASK ('N'); /* set breakpoint type to non-DMS */ + +return reason; /* return status code */ } @@ -1595,9 +1824,13 @@ for (i = 0; (i < ind_max) && (MA & I_IA); i++) { /* resolve multilevel */ if ((i > 2) || int_enable) /* 4th or higher or INT out? */ return NOTE_INDINT; /* break out now */ } + MA = ReadW (MA & VAMASK); /* follow address chain */ } -if (MA & I_IA) return STOP_IND; /* indirect loop? */ + +if (MA & I_IA) /* indirect loop? */ + return STOP_IND; /* stop simulation */ + *addr = MA; return SCPE_OK; } @@ -1610,7 +1843,10 @@ static t_stat Ea (uint32 IR, uint32 *addr, uint32 irq) uint32 MA; MA = IR & (I_IA | I_DISP); /* ind + disp */ -if (IR & I_CP) MA = ((PC - 1) & I_PAGENO) | MA; /* current page? */ + +if (IR & I_CP) /* current page? */ + MA = ((PC - 1) & I_PAGENO) | MA; /* merge in page from PC */ + return resolve (MA, addr, irq); /* resolve indirects */ } @@ -1654,8 +1890,13 @@ if (flag) { /* enabled? */ return (((t << 4) | (t >> 12)) & DMASK); } /* end case */ } /* end if */ -if (op == 05) E = t & 1; /* disabled ext rgt rot */ -if (op == 06) E = (t >> 15) & 1; /* disabled ext lft rot */ + +if (op == 05) /* disabled ext rgt rot */ + E = t & 1; + +if (op == 06) /* disabled ext lft rot */ + E = (t >> 15) & 1; + return t; /* input unchanged */ } @@ -1702,48 +1943,49 @@ return t; /* input unchanged */ t_stat iogrp (uint32 ir, uint32 iotrap) { -/* Translation for I/O subopcodes: soHLT, soFLG, soSFC, soSFS, soMIX, soLIX, soOTX, soCTL */ -static const IOSIG generate_signal [] = { ioNONE, ioSTF, ioSFC, ioSFS, ioIOI, ioIOI, ioIOO, ioSTC }; +/* Translation for I/O subopcodes: soHLT, soFLG, soSFC, soSFS, soMIX, soLIX, soOTX, soCTL */ +static const IOSIGNAL generate_signal [] = { ioNONE, ioSTF, ioSFC, ioSFS, ioIOI, ioIOI, ioIOO, ioSTC }; -const uint32 dev = ir & I_DEVMASK; /* device select code */ -const uint32 sop = I_GETIOOP (ir); /* I/O subopcode */ -const uint32 ab = (ir & I_AB) != 0; /* A/B register select */ -const t_bool clf = (ir & I_HC) != 0; /* H/C flag select */ -uint32 iodata = (SCPE_OK << IOT_V_REASON) | (uint32) ioNONE; /* initialize for SKF test */ +const uint32 dev = ir & I_DEVMASK; /* device select code */ +const uint32 sop = I_GETIOOP (ir); /* I/O subopcode */ +const uint32 ab = (ir & I_AB) != 0; /* A/B register select */ +const t_bool clf = (ir & I_HC) != 0; /* H/C flag select */ +uint16 iodata = (uint16) ioNONE; /* initialize for SKF test */ uint32 ioreturn; t_stat iostat; -IOSIG iosig; +IOCYCLE signal_set; if (!iotrap && mp_control && /* instr not in trap cell and MP on? */ ((sop == soHLT) || /* and is HLT? */ ((dev != OVF) && (mp_unit.flags & UNIT_MP_SEL1)))) { /* or is not SC 01 and SEL1 out? */ if (sop == soLIX) /* MP violation; is LIA/B instruction? */ ABREG [ab] = 0; /* A/B writes anyway */ + MP_ABORT (err_PC); /* MP abort */ } -iosig = generate_signal [sop]; /* generate I/O signal */ +signal_set = generate_signal [sop]; /* generate I/O signal from instruction */ ion_defer = defer_tab [sop]; /* defer depending on instruction */ if (sop == soOTX) /* OTA/B instruction? */ - iodata = (SCPE_OK << IOT_V_REASON) | ABREG [ab]; /* pass A/B register value */ + iodata = ABREG [ab]; /* pass A/B register value */ else if ((sop == soCTL) && (ir & I_CTL)) /* CLC instruction? */ - iosig = ioCLC; /* change STC to CLC signal */ + signal_set = ioCLC; /* change STC to CLC signal */ if ((sop == soFLG) && clf) /* CLF instruction? */ - iosig = ioCLF; /* change STF to CLF signal */ + signal_set = ioCLF; /* change STF to CLF signal */ else if (clf) /* CLF with another instruction? */ - iosig = iosig + ioCLF; /* add CLF signal */ + signal_set = signal_set | ioCLF; /* add CLF signal */ -ioreturn = devdisp (dev, iosig, iodata); /* dispatch I/O signal */ +ioreturn = devdisp (dev, signal_set, IORETURN (SCPE_OK, iodata)); /* dispatch I/O signal */ -iostat = (t_stat) (ioreturn >> IOT_V_REASON); /* extract status */ -iodata = ioreturn & DMASK; /* extract return data value */ +iostat = IOSTATUS (ioreturn); /* extract status */ +iodata = IODATA (ioreturn); /* extract return data value */ if (((sop == soSFC) || (sop == soSFS)) && /* testing flag state? */ - ((IOSIG) iodata == ioSKF)) /* and SKF asserted? */ + ((IOSIGNAL) iodata == ioSKF)) /* and SKF asserted? */ PC = (PC + 1) & VAMASK; /* bump P to skip next instruction */ else if (sop == soLIX) /* LIA/B instruction? */ @@ -1765,11 +2007,13 @@ else /* abnormal status */ } -/* Device dispatcher */ +/* Device I/O signal dispatcher */ -static uint32 devdisp (uint32 select_code, IOSIG signal, uint32 data) +static uint32 devdisp (uint32 select_code, IOCYCLE signal_set, uint16 data) { -return dtab [select_code] (select_code, signal, data); +return dtab [select_code]->io_handler (dtab [select_code], + signal_set, + IORETURN (SCPE_OK, data)); } @@ -1779,10 +2023,10 @@ static uint32 calc_dma (void) { uint32 r = 0; -if (dma_xferen [0] && SRQ (dmac[0].cw1 & I_DEVMASK)) /* check DMA0 cycle */ - r = r | DMAR0; -if (dma_xferen [1] && SRQ (dmac[1].cw1 & I_DEVMASK)) /* check DMA1 cycle */ - r = r | DMAR1; +if (dma [ch1].xferen && SRQ (dma [ch1].cw1 & I_DEVMASK)) /* check DMA1 cycle */ + r = r | DMA_1_REQ; +if (dma [ch2].xferen && SRQ (dma [ch2].cw1 & I_DEVMASK)) /* check DMA2 cycle */ + r = r | DMA_2_REQ; return r; } @@ -1854,8 +2098,8 @@ else bit that is clear. The device corresponding to that bit is the only device that may interrupt (a higher priority device that had IRQ set would also have had PRL set, which is a state violation). We calculate a priority mask by - ANDing the complement of the PRL bits with an increment of the PRL bits. Only - the lowest-order bit will differ. For example: + ANDing the complement of the PRL bits with an increment of the PRL bits. + Only the lowest-order bit will differ. For example: dev_prl : ...1 1 0 1 1 0 1 1 1 1 1 1 (PRL denied for SC 06 and 11) @@ -1896,7 +2140,7 @@ if (ion) /* interrupt system else { /* interrupt system off */ req_grant [0] = req_grant [0] & /* only PF and PE can interrupt */ - (INT_M (PWR) | INT_M (PRO)); + (BIT_M (PWR) | BIT_M (PRO)); req_grant [1] = 0; } @@ -2265,14 +2509,30 @@ uint32 map_sel; if ((dms_enb == 0) || /* DMS off? */ (sw & (SWMASK ('N') | SIM_SW_REST))) /* no mapping rqst or save/rest? */ return va; /* use physical address */ -else if (sw & SWMASK ('S')) map_sel = SMAP; -else if (sw & SWMASK ('U')) map_sel = UMAP; -else if (sw & SWMASK ('P')) map_sel = PAMAP; -else if (sw & SWMASK ('Q')) map_sel = PBMAP; -else map_sel = dms_ump; /* dflt to log addr, cur map */ -if (va >= VASIZE) return MEMSIZE; /* virtual, must be 15b */ -else if (dms_enb) return dms (va, map_sel, NOPROT); /* DMS on? go thru map */ -else return va; /* else return virtual */ + +else if (sw & SWMASK ('S')) + map_sel = SMAP; + +else if (sw & SWMASK ('U')) + map_sel = UMAP; + +else if (sw & SWMASK ('P')) + map_sel = PAMAP; + +else if (sw & SWMASK ('Q')) + map_sel = PBMAP; + +else /* dflt to log addr, cur map */ + map_sel = dms_ump; + +if (va >= VASIZE) /* virtual, must be 15b */ + return MEMSIZE; + +else if (dms_enb) /* DMS on? go thru map */ + return dms (va, map_sel, NOPROT); + +else /* else return virtual */ + return va; } @@ -2407,9 +2667,16 @@ return dms_vr; uint32 dms_upd_sr (void) { dms_sr = dms_sr & ~(MST_ENB | MST_UMP | MST_PRO); -if (dms_enb) dms_sr = dms_sr | MST_ENB; -if (dms_ump) dms_sr = dms_sr | MST_UMP; -if (mp_control) dms_sr = dms_sr | MST_PRO; + +if (dms_enb) + dms_sr = dms_sr | MST_ENB; + +if (dms_ump) + dms_sr = dms_sr | MST_UMP; + +if (mp_control) + dms_sr = dms_sr | MST_PRO; + return dms_sr; } @@ -2421,6 +2688,12 @@ return dms_sr; the interrupt system. When the interrupt system is off, only power fail and parity error interrupts are allowed. + A PON reset initializes certain CPU registers. The 1000 series does a + microcoded memory clear and leaves the T and P registers set as a result. + + Front-panel PRESET performs additional initialization. We also handle MEM + preset here. + Implementation notes: 1. An IOI signal reads the floating I/O bus (0 on all machines). @@ -2450,46 +2723,80 @@ return dms_sr; 4. Select code 0 cannot interrupt, so there is no SIR handler. */ -uint32 cpuio (uint32 select_code, IOSIG signal, uint32 data) +uint32 cpuio (DIB *dibptr, IOCYCLE signal_set, uint32 stat_data) { -const IOSIG base_signal = IOBASE (signal); /* derive base signal */ uint32 sc; +IOSIGNAL signal; +IOCYCLE working_set = signal_set; /* no SIR handler needed */ -switch (base_signal) { /* dispatch base I/O signal */ +while (working_set) { + signal = IONEXT (working_set); /* isolate next signal */ - case ioCLF: /* clear flag flip-flop */ - ion = CLEAR; /* turn interrupt system off */ - break; + switch (signal) { /* dispatch I/O signal */ - case ioSTF: /* set flag flip-flop */ - ion = SET; /* turn interrupt system on */ - break; + case ioCLF: /* clear flag flip-flop */ + ion = CLEAR; /* turn interrupt system off */ + break; - case ioSFC: /* skip if flag is clear */ - setSKF (!ion); /* skip if interrupt system is off */ - break; + case ioSTF: /* set flag flip-flop */ + ion = SET; /* turn interrupt system on */ + break; - case ioSFS: /* skip if flag is set */ - setSKF (ion); /* skip if interupt system is on */ - break; + case ioSFC: /* skip if flag is clear */ + setSKF (!ion); /* skip if interrupt system is off */ + break; - case ioIOI: /* I/O input */ - data = 0; /* returns 0 */ - break; + case ioSFS: /* skip if flag is set */ + setSKF (ion); /* skip if interupt system is on */ + break; - case ioCLC: /* clear control flip-flop */ - for (sc = 6; sc <= I_DEVMASK; sc++) /* send CRS to devices */ - devdisp (sc, ioCRS, 0); /* from select code 6 and up */ - break; + case ioIOI: /* I/O input */ + stat_data = IORETURN (SCPE_OK, 0); /* returns 0 */ + break; - default: /* all other signals */ - break; /* are ignored */ + case ioPON: /* power on normal */ + AR = 0; /* clear A register */ + BR = 0; /* clear B register */ + SR = 0; /* clear S register */ + TR = 0; /* clear T register */ + E = 1; /* set E register */ + + if (UNIT_CPU_FAMILY == UNIT_FAMILY_1000) { /* 1000 series? */ + memset (M, 0, MEMSIZE * 2); /* zero allocated memory */ + MR = 0077777; /* set M register */ + PC = 0100000; /* set P register */ + } + + else { /* 21xx series */ + MR = 0; /* clear M register */ + PC = 0; /* clear P register */ + } + break; + + case ioPOPIO: /* power-on preset to I/O */ + O = 0; /* clear O register */ + ion = CLEAR; /* turn off interrupt system */ + ion_defer = FALSE; /* clear interrupt deferral */ + + dms_enb = 0; /* turn DMS off */ + dms_ump = 0; /* init to system map */ + dms_sr = 0; /* clear status register and BP fence */ + dms_vr = 0; /* clear violation register */ + break; + + case ioCLC: /* clear control flip-flop */ + for (sc = CRSDEV; sc <= MAXDEV; sc++) /* send CRS to devices */ + devdisp (sc, ioCRS, 0); /* from select code 6 and up */ + break; + + default: /* all other signals */ + break; /* are ignored */ + } + + working_set = working_set & ~signal; /* remove current signal from set */ } -if (signal > ioCLF) /* multiple signals? */ - cpuio (select_code, ioCLF, 0); /* issue CLF */ - -return data; +return stat_data; } @@ -2507,46 +2814,50 @@ return data; 1. Select code 1 cannot interrupt, so there is no SIR handler. */ -uint32 ovflio (uint32 select_code, IOSIG signal, uint32 data) +uint32 ovflio (DIB *dibptr, IOCYCLE signal_set, uint32 stat_data) { -const IOSIG base_signal = IOBASE (signal); /* derive base signal */ +IOSIGNAL signal; +IOCYCLE working_set = signal_set; /* no SIR handler needed */ -switch (base_signal) { /* dispatch base I/O signal */ +while (working_set) { + signal = IONEXT (working_set); /* isolate next signal */ - case ioCLF: /* clear flag flip-flop */ - O = 0; /* clear overflow */ - break; + switch (signal) { /* dispatch I/O signal */ - case ioSTF: /* set flag flip-flop */ - O = 1; /* set overflow */ - break; + case ioCLF: /* clear flag flip-flop */ + O = 0; /* clear overflow */ + break; - case ioSFC: /* skip if flag is clear */ - setSKF (!O); /* skip if overflow is clear */ - break; + case ioSTF: /* set flag flip-flop */ + O = 1; /* set overflow */ + break; - case ioSFS: /* skip if flag is set */ - setSKF (O); /* skip if overflow is set */ - break; + case ioSFC: /* skip if flag is clear */ + setSKF (!O); /* skip if overflow is clear */ + break; - case ioIOI: /* I/O input */ - data = SR; /* read switch register value */ - break; + case ioSFS: /* skip if flag is set */ + setSKF (O); /* skip if overflow is set */ + break; - case ioIOO: /* I/O output */ - if ((UNIT_CPU_MODEL != UNIT_2116) && /* no S register display on */ - (UNIT_CPU_MODEL != UNIT_2115)) /* 2116 and 2115 machines */ - SR = data; /* write S register value */ - break; + case ioIOI: /* I/O input */ + stat_data = IORETURN (SCPE_OK, SR); /* read switch register value */ + break; - default: /* all other signals */ - break; /* are ignored */ + case ioIOO: /* I/O output */ + if ((UNIT_CPU_MODEL != UNIT_2116) && /* no S register display on */ + (UNIT_CPU_MODEL != UNIT_2115)) /* 2116 and 2115 machines */ + SR = IODATA (stat_data); /* write S register value */ + break; + + default: /* all other signals */ + break; /* are ignored */ + } + + working_set = working_set & ~signal; /* remove current signal from set */ } -if (signal > ioCLF) /* multiple signals? */ - ovflio (select_code, ioCLF, 0); /* issue CLF */ - -return data; +return stat_data; } @@ -2561,35 +2872,37 @@ return data; interrupt register (CIR) is always read by an IOI directed to select code 4. */ -uint32 pwrfio (uint32 select_code, IOSIG signal, uint32 data) +uint32 pwrfio (DIB *dibptr, IOCYCLE signal_set, uint32 stat_data) { -const IOSIG base_signal = IOBASE (signal); /* derive base signal */ +IOSIGNAL signal; +IOCYCLE working_set = IOADDSIR (signal_set); /* add ioSIR if needed */ -switch (base_signal) { /* dispatch base I/O signal */ +while (working_set) { + signal = IONEXT (working_set); /* isolate next signal */ - case ioSTC: /* set control flip-flop */ - break; /* reinitializes power fail */ + switch (signal) { /* dispatch I/O signal */ - case ioCLC: /* clear control flip-flop */ - break; /* reinitializes power fail */ + case ioSTC: /* set control flip-flop */ + break; /* reinitializes power fail */ - case ioSFC: /* skip if flag is clear */ - break; /* skips if power fail occurred */ + case ioCLC: /* clear control flip-flop */ + break; /* reinitializes power fail */ - case ioIOI: /* I/O input */ - data = intaddr; /* input CIR value */ - break; + case ioSFC: /* skip if flag is clear */ + break; /* skips if power fail occurred */ - default: /* all other signals */ - break; /* are ignored */ + case ioIOI: /* I/O input */ + stat_data = IORETURN (SCPE_OK, intaddr); /* input CIR value */ + break; + + default: /* all other signals */ + break; /* are ignored */ + } + + working_set = working_set & ~signal; /* remove current signal from set */ } -if (signal > ioCLF) /* multiple signals? */ - pwrfio (select_code, ioCLF, 0); /* issue CLF */ -else if (signal > ioSIR) /* signal affected interrupt status? */ - pwrfio (select_code, ioSIR, 0); /* set interrupt request */ - -return data; +return stat_data; } @@ -2634,7 +2947,7 @@ return data; 1. Because the card uses IAK unqualified, this routine is called whenever any interrupt occurs. If the MP card itself is not interrupting, the select code passed will not be SC 05. In either case, the trap cell - instruction is passed in the "data" parameter. + instruction is passed in the data portion of the "stat_data" parameter. 2. The MEV flip-flop records memory expansion (a.k.a. dynamic mapping) violations. It is set when an DM violation is encountered and can be @@ -2649,83 +2962,88 @@ return data; 4. Parity error logic is not implemented. */ -uint32 protio (uint32 select_code, IOSIG signal, uint32 data) +uint32 protio (DIB *dibptr, IOCYCLE signal_set, uint32 stat_data) { -const IOSIG base_signal = IOBASE (signal); /* derive base signal */ +uint16 data; +IOSIGNAL signal; +IOCYCLE working_set = IOADDSIR (signal_set); /* add ioSIR if needed */ -switch (base_signal) { /* dispatch base I/O signal */ +while (working_set) { + signal = IONEXT (working_set); /* isolate next signal */ - case ioCLF: /* clear flag flip-flop */ - break; /* turns off PE interrupt */ + switch (signal) { /* dispatch I/O signal */ - case ioSTF: /* set flag flip-flop */ - break; /* turns on PE interrupt */ + case ioCLF: /* clear flag flip-flop */ + break; /* turns off PE interrupt */ - case ioENF: /* enable flag */ - mp_flag = mp_flagbuf = SET; /* set flag buffer and flag flip-flops */ - mp_evrff = CLEAR; /* inhibit violation register updates */ - break; + case ioSTF: /* set flag flip-flop */ + break; /* turns on PE interrupt */ - case ioSFC: /* skip if flag is clear */ - setSKF (!mp_mevff); /* skip if MP interrupt */ - break; + case ioENF: /* enable flag */ + mp_flag = mp_flagbuf = SET; /* set flag buffer and flag flip-flops */ + mp_evrff = CLEAR; /* inhibit violation register updates */ + break; - case ioSFS: /* skip if flag is set */ - setSKF (mp_mevff); /* skip if DMS interrupt */ - break; + case ioSFC: /* skip if flag is clear */ + setSKF (!mp_mevff); /* skip if MP interrupt */ + break; - case ioIOI: /* I/O input */ - data = mp_viol; /* read MP violation register */ - break; + case ioSFS: /* skip if flag is set */ + setSKF (mp_mevff); /* skip if DMS interrupt */ + break; - case ioIOO: /* I/O output */ - mp_fence = data & VAMASK; /* write to MP fence register */ + case ioIOI: /* I/O input */ + stat_data = IORETURN (SCPE_OK, mp_viol); /* read MP violation register */ + break; - if (cpu_unit.flags & UNIT_2100) /* 2100 IOP uses MP fence */ - iop_sp = mp_fence; /* as a stack pointer */ - break; + case ioIOO: /* I/O output */ + mp_fence = IODATA (stat_data) & VAMASK; /* write to MP fence register */ - case ioPOPIO: /* power-on preset to I/O */ - mp_control = CLEAR; /* clear control flip-flop */ - mp_flag = mp_flagbuf = CLEAR; /* clear flag and flag buffer flip-flops */ - mp_mevff = CLEAR; /* clear memory expansion violation flip-flop */ - mp_evrff = SET; /* set enable violation register flip-flop */ - break; + if (cpu_unit.flags & UNIT_2100) /* 2100 IOP uses MP fence */ + iop_sp = mp_fence; /* as a stack pointer */ + break; - case ioSTC: /* set control flip-flop */ - mp_control = SET; /* turn on MP */ - mp_mevff = CLEAR; /* clear memory expansion violation flip-flop */ - mp_evrff = SET; /* set enable violation register flip-flop */ - break; + case ioPOPIO: /* power-on preset to I/O */ + mp_control = CLEAR; /* clear control flip-flop */ + mp_flag = mp_flagbuf = CLEAR; /* clear flag and flag buffer flip-flops */ + mp_mevff = CLEAR; /* clear memory expansion violation flip-flop */ + mp_evrff = SET; /* set enable violation register flip-flop */ + break; - case ioSIR: /* set interrupt request */ - setPRL (PRO, !mp_flag); /* set PRL signal */ - setIRQ (PRO, mp_flag); /* set IRQ signal */ - break; + case ioSTC: /* set control flip-flop */ + mp_control = SET; /* turn on MP */ + mp_mevff = CLEAR; /* clear memory expansion violation flip-flop */ + mp_evrff = SET; /* set enable violation register flip-flop */ + break; - case ioIAK: /* interrupt acknowledge */ - if (select_code == PRO) /* MP interrupt acknowledgement? */ - mp_flag = mp_flagbuf = CLEAR; /* clear flag and flag buffer */ + case ioSIR: /* set interrupt request */ + setPRL (PRO, !mp_flag); /* set PRL signal */ + setIRQ (PRO, mp_flag); /* set IRQ signal */ + break; - if (((data & I_NMRMASK) != I_IO) || /* trap cell instruction not I/O */ - (I_GETIOOP (data) == soHLT)) /* or is halt? */ - mp_control = CLEAR; /* turn protection off */ - else { /* non-HLT I/O instruction leaves MP on */ - mp_mevff = CLEAR; /* but clears MEV flip-flop */ - mp_evrff = SET; /* and reenables violation register flip-flop */ - } - break; + case ioIAK: /* interrupt acknowledge */ + if (dibptr->select_code == PRO) /* MP interrupt acknowledgement? */ + mp_flag = mp_flagbuf = CLEAR; /* clear flag and flag buffer */ - default: /* all other signals */ - break; /* are ignored */ + data = IODATA (stat_data); /* get trap cell instruction */ + + if (((data & I_NMRMASK) != I_IO) || /* trap cell instruction not I/O */ + (I_GETIOOP (data) == soHLT)) /* or is halt? */ + mp_control = CLEAR; /* turn protection off */ + else { /* non-HLT I/O instruction leaves MP on */ + mp_mevff = CLEAR; /* but clears MEV flip-flop */ + mp_evrff = SET; /* and reenables violation register flip-flop */ + } + break; + + default: /* all other signals */ + break; /* are ignored */ + } + + working_set = working_set & ~signal; /* remove current signal from set */ } -if (signal > ioCLF) /* multiple signals? */ - protio (select_code, ioCLF, 0); /* issue CLF */ -else if (signal > ioSIR) /* signal affected interrupt status? */ - protio (select_code, ioSIR, 0); /* set interrupt request */ - -return data; +return stat_data; } @@ -2753,45 +3071,55 @@ return data; 2. Select codes 2 and 3 cannot interrupt, so there is no SIR handler. */ -uint32 dmasio (uint32 select_code, IOSIG signal, uint32 data) +uint32 dmasio (DIB *dibptr, IOCYCLE signal_set, uint32 stat_data) { -const uint32 ch = select_code & 1; /* DMA channel number */ -const IOSIG base_signal = IOBASE (signal); /* derive base signal */ +const CHANNEL ch = dibptr->card_index; /* DMA channel number */ +uint16 data; +IOSIGNAL signal; +IOCYCLE working_set = signal_set; /* no SIR handler needed */ -switch (base_signal) { /* dispatch base I/O signal */ +while (working_set) { + signal = IONEXT (working_set); /* isolate next signal */ - case ioIOI: /* I/O data input */ - if (UNIT_CPU_MODEL == UNIT_2114) /* 2114? */ - data = dmac [ch].cw3 & 0017777; /* only 13-bit count */ - else if (UNIT_CPU_TYPE == UNIT_TYPE_211X) /* 2115/2116? */ - data = dmac [ch].cw3 & 0037777; /* only 14-bit count */ - else /* other models */ - data = dmac [ch].cw3; /* rest use full value */ - break; /* read remaining word count */ + switch (signal) { /* dispatch I/O signal */ - case ioIOO: /* I/O data output */ - if (dma_select [ch]) /* word count selected? */ - dmac [ch].cw3 = data; /* save count */ - else /* memory address selected */ + case ioIOI: /* I/O data input */ if (UNIT_CPU_MODEL == UNIT_2114) /* 2114? */ - dmac [ch].cw2 = data & 0137777; /* only 14-bit address */ + data = dma [ch].cw3 & 0017777; /* only 13-bit count */ + else if (UNIT_CPU_TYPE == UNIT_TYPE_211X) /* 2115/2116? */ + data = dma [ch].cw3 & 0037777; /* only 14-bit count */ else /* other models */ - dmac [ch].cw2 = data; /* full address stored */ - break; + data = dma [ch].cw3; /* rest use full value */ - case ioCLC: /* clear control flip-flop */ - dma_select [ch] = CLEAR; /* set for word count access */ - break; + stat_data = IORETURN (SCPE_OK, data); /* merge status and remaining word count */ + break; - case ioSTC: /* set control flip-flop */ - dma_select [ch] = SET; /* set for memory address access */ - break; + case ioIOO: /* I/O data output */ + if (dma [ch].select) /* word count selected? */ + dma [ch].cw3 = IODATA (stat_data); /* save count */ + else /* memory address selected */ + if (UNIT_CPU_MODEL == UNIT_2114) /* 2114? */ + dma [ch].cw2 = IODATA (stat_data) & 0137777; /* only 14-bit address */ + else /* other models */ + dma [ch].cw2 = IODATA (stat_data); /* full address stored */ + break; - default: /* all other signals */ - break; /* are ignored */ + case ioCLC: /* clear control flip-flop */ + dma [ch].select = CLEAR; /* set for word count access */ + break; + + case ioSTC: /* set control flip-flop */ + dma [ch].select = SET; /* set for memory address access */ + break; + + default: /* all other signals */ + break; /* are ignored */ + } + + working_set = working_set & ~signal; /* remove current signal from set */ } -return data; +return stat_data; } @@ -2819,99 +3147,95 @@ return data; flip-flops. Under simulation, ioCRS is dispatched to select codes 6 and up, so we reset the flip-flop in our handler. - 3. The 12578A card does not start the transfer until one instruction after - the STC 6/7 has executed. The diagnostic tests for this, so we - implement a startup latency counter to provide the proper delay. - - 4. The 12578A supports byte-sized transfers by setting bit 14. Bit 14 is + 3. The 12578A supports byte-sized transfers by setting bit 14. Bit 14 is ignored by all other DMA cards, which support word transfers only. Under simulation, we use a byte-packing/unpacking register to hold one byte while the other is read or written during the DMA cycle. */ -uint32 dmapio (uint32 select_code, IOSIG signal, uint32 data) +uint32 dmapio (DIB *dibptr, IOCYCLE signal_set, uint32 stat_data) { -const uint32 ch = select_code & 1; /* DMA channel number */ -const IOSIG base_signal = IOBASE (signal); /* derive base signal */ +const CHANNEL ch = dibptr->card_index; /* DMA channel number */ +uint16 data; +IOSIGNAL signal; +IOCYCLE working_set = IOADDSIR (signal_set); /* add ioSIR if needed */ -switch (base_signal) { /* dispatch base I/O signal */ +while (working_set) { + signal = IONEXT (working_set); /* isolate next signal */ - case ioCLF: /* clear flag flip-flop */ - dma_flag [ch] = dma_flagbuf [ch] = CLEAR; /* clear flag and flag buffer */ - break; + switch (signal) { /* dispatch I/O signal */ - case ioSTF: /* set flag flip-flop */ - case ioENF: /* enable flag */ - dma_flag [ch] = dma_flagbuf [ch] = SET; /* set flag and flag buffer */ - dma_xferen [ch] = CLEAR; /* clear transfer enable to abort transfer */ - break; + case ioCLF: /* clear flag flip-flop */ + dma [ch].flag = dma [ch].flagbuf = CLEAR; /* clear flag and flag buffer */ + break; - case ioSFC: /* skip if flag is clear */ - setSKF (!dma_flag [ch]); /* skip if transfer in progress */ - break; + case ioSTF: /* set flag flip-flop */ + case ioENF: /* enable flag */ + dma [ch].flag = dma [ch].flagbuf = SET; /* set flag and flag buffer */ + dma [ch].xferen = CLEAR; /* clear transfer enable to abort transfer */ + break; - case ioSFS: /* skip if flag is set */ - setSKF (dma_flag [ch]); /* skip if transfer is complete */ - break; + case ioSFC: /* skip if flag is clear */ + setstdSKF (dma [ch]); /* skip if transfer in progress */ + break; - case ioIOI: /* I/O data input */ - if (UNIT_CPU_TYPE == UNIT_TYPE_1000) /* 1000? */ - data = DMASK; /* return all ones */ - else /* other models */ - data = 0; /* return all zeros */ - break; + case ioSFS: /* skip if flag is set */ + setstdSKF (dma [ch]); /* skip if transfer is complete */ + break; - case ioIOO: /* I/O data output */ - if (UNIT_CPU_MODEL == UNIT_2114) /* 12607? */ - dmac [ch].cw1 = (data & 0137707) | 010; /* mask SC, convert to 10-17 */ - else if (UNIT_CPU_TYPE == UNIT_TYPE_211X) /* 12578? */ - dmac [ch].cw1 = data; /* store full select code, flags */ - else /* 12895, 12897 */ - dmac [ch].cw1 = data & ~DMA1_PB; /* clip byte-packing flag */ - break; + case ioIOI: /* I/O data input */ + if (UNIT_CPU_TYPE == UNIT_TYPE_1000) /* 1000? */ + stat_data = IORETURN (SCPE_OK, DMASK); /* return all ones */ + else /* other models */ + stat_data = IORETURN (SCPE_OK, 0); /* return all zeros */ + break; - case ioPOPIO: /* power-on preset to I/O */ - dma_flag [ch] = dma_flagbuf [ch] = SET; /* set flag and flag buffer */ - /* fall into CRS handler */ + case ioIOO: /* I/O data output */ + data = IODATA (stat_data); /* clear supplied status */ - case ioCRS: /* control reset */ - dma_xferen [ch] = CLEAR; /* clear transfer enable */ - dma_select [ch] = CLEAR; /* set secondary for word count access */ + if (UNIT_CPU_MODEL == UNIT_2114) /* 12607? */ + dma [ch].cw1 = (data & 0137707) | 010; /* mask SC, convert to 10-17 */ + else if (UNIT_CPU_TYPE == UNIT_TYPE_211X) /* 12578? */ + dma [ch].cw1 = data; /* store full select code, flags */ + else /* 12895, 12897 */ + dma [ch].cw1 = data & ~DMA1_PB; /* clip byte-packing flag */ + break; + + case ioPOPIO: /* power-on preset to I/O */ + dma [ch].flag = dma [ch].flagbuf = SET; /* set flag and flag buffer */ + break; + + case ioCRS: /* control reset */ + dma [ch].xferen = CLEAR; /* clear transfer enable */ + dma [ch].select = CLEAR; /* set secondary for word count access */ /* fall into CLC handler */ - case ioCLC: /* clear control flip-flop */ - dma_control [ch] = CLEAR; /* clear control */ - break; + case ioCLC: /* clear control flip-flop */ + dma [ch].control = CLEAR; /* clear control */ + break; - case ioSTC: /* set control flip-flop */ - if (UNIT_CPU_TYPE == UNIT_TYPE_211X) /* slow DMA card? */ - dmac [ch].latency = 1; /* needs startup latency */ - else - dmac [ch].latency = 0; /* DCPC starts immediately */ + case ioSTC: /* set control flip-flop */ + dma [ch].packer = 0; /* clear packing register */ + dma [ch].xferen = dma [ch].control = SET; /* set transfer enable and control */ + break; - dmac [ch].packer = 0; /* clear packing register */ - dma_xferen [ch] = dma_control [ch] = SET; /* set transfer enable and control */ - break; + case ioSIR: /* set interrupt request */ + setstdPRL (dma [ch]); + setstdIRQ (dma [ch]); + break; - case ioSIR: /* set interrupt request */ - setPRL (select_code, !(dma_control [ch] & dma_flag [ch])); - setIRQ (select_code, dma_control [ch] & dma_flag [ch] & dma_flagbuf [ch]); - break; + case ioIAK: /* interrupt acknowledge */ + dma [ch].flagbuf = CLEAR; /* clear flag buffer */ + break; - case ioIAK: /* interrupt acknowledge */ - dma_flagbuf [ch] = CLEAR; /* clear flag buffer */ - break; + default: /* all other signals */ + break; /* are ignored */ + } - default: /* all other signals */ - break; /* are ignored */ + working_set = working_set & ~signal; /* remove current signal from set */ } -if (signal > ioCLF) /* multiple signals? */ - dmapio (select_code, ioCLF, 0); /* issue CLF */ -else if (signal > ioSIR) /* signal affected interrupt status? */ - dmapio (select_code, ioSIR, 0); /* set interrupt request */ - -return data; +return stat_data; } @@ -2935,134 +3259,173 @@ return data; device is accessed. */ -uint32 nullio (uint32 select_code, IOSIG signal, uint32 data) +uint32 nullio (DIB *dibptr, IOCYCLE signal_set, uint32 stat_data) { -const IOSIG base_signal = IOBASE (signal); /* derive base signal */ +uint16 data = 0; +IOSIGNAL signal; +IOCYCLE working_set = signal_set; /* no SIR handler needed */ -switch (base_signal) { /* dispatch base I/O signal */ +while (working_set) { + signal = IONEXT (working_set); /* isolate next signal */ - case ioIOI: /* I/O data input */ - if ((select_code < VARDEV) && /* internal device */ - (UNIT_CPU_TYPE == UNIT_TYPE_1000)) /* and 1000? */ - data = DMASK; /* return all ones */ - else /* external or other model */ - data = 0; /* return all zeros */ - break; + switch (signal) { /* dispatch I/O signal */ - default: /* all other signals */ - break; /* are ignored */ + case ioIOI: /* I/O data input */ + if ((dibptr->select_code < VARDEV) && /* internal device */ + (UNIT_CPU_TYPE == UNIT_TYPE_1000)) /* and 1000? */ + data = DMASK; /* return all ones */ + else /* external or other model */ + data = 0; /* return all zeros */ + break; + + default: /* all other signals */ + break; /* are ignored */ + } + + working_set = working_set & ~signal; /* remove current signal from set */ } -return (stop_dev << IOT_V_REASON) | data; /* flag missing device */ +return IORETURN (stop_dev, data); /* flag missing device */ } -/* DMA cycle routine +/* DMA cycle routine. + + This routine performs one DMA input or output cycle using the indicated DMA + channel number and DMS map. When the transfer word count reaches zero, the + flag is set on the corresponding DMA channel to indicate completion. The 12578A card supports byte-packing. If bit 14 in control word 1 is set, each transfer will involve one read/write from memory and two output/input operations in order to transfer sequential bytes to/from the device. - The last cycle (word count reaches 0) logic is quite tricky. + DMA I/O cycles differ from programmed I/O cycles in that multiple I/O control + backplane signals may be asserted simultaneously. With programmed I/O, only + CLF may be asserted with other signals, specifically with STC, CLC, SFS, SFC, + IOI, or IOO. With DMA, as many as five signals may be asserted concurrently. - Input cases: - - CLC requested: issue CLC + DMA I/O timing looks like this: - Output cases: - - neither STC nor CLC requested: issue CLF - - STC requested but not CLC: issue STC,C - - CLC requested but not STC: issue CLC,C - - STC and CLC both requested: issue STC,C and CLC,C, in that order + ------------ Input ------------ ----------- Output ------------ + Sig Normal Cycle Last Cycle Normal Cycle Last Cycle + === ============== ============== ============== ============== + IOI T2-T3 T2-T3 + IOO T3-T4 T3-T4 + STC * T3 T3 T3 + CLC * T3-T4 T3-T4 + CLF T3 T3 T3 + EDT T4 T4 - Either case: issue EDT + * if enabled by control word 1 + + Under simulation, this routine dispatches one set of I/O signals per DMA + cycle to the target device's I/O signal handler. The signals correspond to + the table above, except that all signals for a given cycle are concurrent + (e.g., the last input cycle has IOI, EDT, and optionally CLC asserted, even + though IOI and EDT are not coincident in hardware). I/O signal handlers will + process these signals sequentially, in the order listed above, before + returning. Implementation notes: - 1. The EDT signal is sent to the device signal handler with the "data" - parameter set to ioIOI or ioIOO to indicate the completion of an input or - output transfer, respectively. The IPL device is the only one that uses - this (at the moment). + 1. The address increment and word count decrement is done only after the I/O + cycle has completed successfully. This allows a failed transfer to be + retried after correcting the I/O error. */ -static void dma_cycle (uint32 ch, uint32 map) +static t_stat dma_cycle (CHANNEL ch, uint32 map) { -uint32 temp, dev; -int32 MA; -int32 inp = dmac[ch].cw2 & DMA2_OI; /* input flag */ -int32 byt = dmac[ch].cw1 & DMA1_PB; /* pack bytes flag */ +const uint32 dev = dma [ch].cw1 & I_DEVMASK; /* device select code */ +const uint32 stc = dma [ch].cw1 & DMA1_STC; /* STC enable flag */ +const uint32 bytes = dma [ch].cw1 & DMA1_PB; /* pack bytes flag */ +const uint32 clc = dma [ch].cw1 & DMA1_CLC; /* CLC enable flag */ +const uint32 MA = dma [ch].cw2 & VAMASK; /* memory address */ +const uint32 input = dma [ch].cw2 & DMA2_OI; /* input flag */ +const uint32 even = dma [ch].packer & DMA_OE; /* odd/even packed byte flag */ +uint16 data; +t_stat status; +uint32 ioresult; +IOCYCLE signals; -if (dmac[ch].latency) { /* start-up latency? */ - dmac[ch].latency = dmac[ch].latency - 1; /* decrease it */ - return; /* that's all this cycle */ +if (bytes && !even || dma [ch].cw3 != DMASK) { /* normal cycle? */ + if (input) /* input cycle? */ + signals = ioIOI | ioCLF; /* assert IOI and CLF */ + else /* output cycle */ + signals = ioIOO | ioCLF; /* assert IOO and CLF */ + + if (stc) /* STC wanted? */ + signals = signals | ioSTC; /* assert STC */ } -dev = dmac[ch].cw1 & I_DEVMASK; /* get device */ -MA = dmac[ch].cw2 & VAMASK; /* get mem addr */ +else { /* last cycle */ + if (input) /* input cycle? */ + signals = ioIOI | ioEDT; /* assert IOI and EDT */ + else { /* output cycle */ + signals = ioIOO | ioCLF | ioEDT; /* assert IOO and CLF and EDT */ -if (inp) { /* input cycle? */ - temp = devdisp (dev, ioIOI, 0); /* do I/O input */ - - if (byt) { /* byte packing? */ - if (dmac[ch].packer & DMA_OE) { /* second byte? */ - temp = (dmac[ch].packer << 8) | /* merge stored byte */ - (temp & DMASK8); - WriteIO (MA, temp, map); /* store word data */ - } - else /* first byte */ - dmac[ch].packer = (temp & DMASK8); /* save it */ - - dmac[ch].packer = dmac[ch].packer ^ DMA_OE; /* flip odd/even bit */ + if (stc) /* STC wanted? */ + signals = signals | ioSTC; /* assert STC */ } - else /* no byte packing */ - WriteIO (MA, temp, map); /* store word data */ + + if (clc) /* CLC wanted? */ + signals = signals | ioCLC; /* assert CLC */ } + +if (input) { /* input cycle? */ + ioresult = devdisp (dev, signals, /* do I/O input */ + IORETURN (SCPE_OK, 0)); + + status = IOSTATUS (ioresult); /* get cycle status */ + + if (status == SCPE_OK) { /* good I/O cycle? */ + data = IODATA (ioresult); /* extract return data value */ + + if (bytes) { /* byte packing? */ + if (even) { /* second byte? */ + data = (dma [ch].packer << 8) | /* merge stored byte */ + (data & DMASK8); + WriteIO (MA, data, map); /* store word data */ + } + else /* first byte */ + dma [ch].packer = (data & DMASK8); /* save it */ + + dma [ch].packer = dma [ch].packer ^ DMA_OE; /* flip odd/even bit */ + } + else /* no byte packing */ + WriteIO (MA, data, map); /* store word data */ + } + } + else { /* output cycle */ - if (byt) { /* byte packing? */ - if (dmac[ch].packer & DMA_OE) /* second byte? */ - temp = dmac[ch].packer & DMASK8; /* retrieve it */ + if (bytes) { /* byte packing? */ + if (even) /* second byte? */ + data = dma [ch].packer & DMASK8; /* retrieve it */ else { /* first byte */ - dmac[ch].packer = ReadIO (MA, map); /* read word data */ - temp = (dmac[ch].packer >> 8) & DMASK8; /* get high byte */ + dma [ch].packer = ReadIO (MA, map); /* read word data */ + data = (dma [ch].packer >> 8) & DMASK8; /* get high byte */ } - dmac[ch].packer = dmac[ch].packer ^ DMA_OE; /* flip odd/even bit */ + dma [ch].packer = dma [ch].packer ^ DMA_OE; /* flip odd/even bit */ } else /* no byte packing */ - temp = ReadIO (MA, map); /* read word data */ + data = ReadIO (MA, map); /* read word data */ - devdisp (dev, ioIOO, temp); /* do I/O output */ + ioresult = devdisp (dev, signals, /* do I/O output */ + IORETURN (SCPE_OK, data)); + + status = IOSTATUS (ioresult); /* get cycle status */ } -if ((dmac[ch].packer & DMA_OE) == 0) { /* new byte or no packing? */ - dmac[ch].cw2 = (dmac[ch].cw2 & DMA2_OI) | /* increment address */ - ((dmac[ch].cw2 + 1) & VAMASK); - dmac[ch].cw3 = (dmac[ch].cw3 + 1) & DMASK; /* increment word count */ +if ((even || !bytes) && (status == SCPE_OK)) { /* new byte or no packing and good xfer? */ + dma [ch].cw2 = input | (dma [ch].cw2 + 1) & VAMASK; /* increment address */ + dma [ch].cw3 = (dma [ch].cw3 + 1) & DMASK; /* increment word count */ + + if (dma [ch].cw3 == 0) /* end of transfer? */ + dmapio (dtab [DMA1 + ch], ioENF, 0); /* set DMA channel flag */ } -if (dmac[ch].cw3) { /* more to do? */ - if (dmac[ch].cw1 & DMA1_STC) /* if STC flag, */ - devdisp (dev, ioSTC + ioCLF, 0); /* do STC,C dev */ - else devdisp (dev, ioCLF, 0); /* else CLF dev */ - } -else { - if (inp) { /* last cycle, input? */ - if (dmac[ch].cw1 & DMA1_CLC) /* CLC at end? */ - devdisp (dev, ioCLC, 0); /* yes */ - } /* end input */ - else { /* output */ - if ((dmac[ch].cw1 & (DMA1_STC | DMA1_CLC)) == 0) - devdisp (dev, ioCLF, 0); /* clear flag */ - if (dmac[ch].cw1 & DMA1_STC) /* if STC flag, */ - devdisp (dev, ioSTC + ioCLF, 0); /* do STC,C dev */ - if (dmac[ch].cw1 & DMA1_CLC) /* CLC at end? */ - devdisp (dev, ioCLC + ioCLF, 0); /* yes */ - } /* end output */ - - dmapio (DMA0 + ch, ioENF, 0); /* set DMA channel flag */ - devdisp (dev, ioEDT, (uint32) (inp ? ioIOI : ioIOO)); /* send EDT to device */ - } -return; +return status; /* return I/O status */ } @@ -3070,9 +3433,9 @@ return; The reset routines are called to simulate either an initial power on condition or a front-panel PRESET button press. For initial power on - (corresponds to PON signal assertion in the CPU), the "P" command switch will - be set. For PRESET (corresponds to POPIO and CRS assertion), the switch will - be clear. + (corresponds to PON, POPIO, and CRS signal assertion in the CPU), the "P" + command switch will be set. For PRESET (corresponds to POPIO and CRS + assertion), the switch will be clear. SCP delivers a power-on reset to all devices when the simulator is started. A RUN, BOOT, RESET, or RESET ALL command delivers a PRESET to all devices. A @@ -3084,15 +3447,6 @@ return; If this is the first call after simulator startup, allocate the initial memory array, set the default CPU model, and install the default BBL. - - A PON reset initializes certain CPU registers. The 1000 series does a - microcoded memory clear and leaves the T and P registers set as a result. - - Front-panel PRESET performs additional initialization. We also handle MEM - preset here. - - Because PRESET is dispatched to every device separately, each of which will - handle POPIO and CRS in response, we do not need to dispatch POPIO ourselves. */ t_stat cpu_reset (DEVICE *dptr) @@ -3121,33 +3475,10 @@ if (M == NULL) { /* initial call after st } } -if (sim_switches & SWMASK ('P')) { /* PON reset? */ - AR = 0; /* clear A register */ - BR = 0; /* clear B register */ - SR = 0; /* clear S register */ - TR = 0; /* clear T register */ - E = 1; /* set E register */ - - if (UNIT_CPU_FAMILY == UNIT_FAMILY_1000) { /* 1000 series? */ - memset (M, 0, MEMSIZE * 2); /* zero allocated memory */ - MR = 0077777; /* set M register */ - PC = 0100000; /* set P register */ - } - - else { /* 21xx series */ - MR = 0; /* clear M register */ - PC = 0; /* clear P register */ - } - } - -O = 0; /* PRESET: clear O register */ -ion = CLEAR; /* PRESET: turn off interrupt system */ -ion_defer = FALSE; /* PRESET: clear interrupt deferral */ - -dms_enb = 0; /* POPIO: turn DMS off */ -dms_ump = 0; /* POPIO: init to system map */ -dms_sr = 0; /* POPIO: clear status register and BP fence */ -dms_vr = 0; /* POPIO: clear violation register */ +if (sim_switches & SWMASK ('P')) /* PON reset? */ + IOPOWERON (&cpu_dib); +else /* PRESET */ + IOPRESET (&cpu_dib); sim_brk_dflt = SWMASK ('N'); /* type is nomap as DMS is off */ @@ -3159,7 +3490,7 @@ return SCPE_OK; t_stat mp_reset (DEVICE *dptr) { -protio (PRO, ioPOPIO, 0); /* send POPIO signal */ +IOPRESET (&mp_dib); /* PRESET device (does not use PON) */ mp_fence = 0; /* clear fence register */ mp_viol = 0; /* clear violation register */ @@ -3168,36 +3499,27 @@ return SCPE_OK; } -/* DMA channel 1 reset */ +/* DMA reset */ -t_stat dma0_reset (DEVICE *tptr) +t_stat dma_reset (DEVICE *dptr) { +DIB *dibptr = (DIB *) dptr->ctxt; /* DIB pointer */ +const CHANNEL ch = dibptr->card_index; /* DMA channel number */ + if (UNIT_CPU_MODEL != UNIT_2114) /* 2114 has only one channel */ - hp_enbdis_pair (&dma0_dev, &dma1_dev); /* make pair cons */ + hp_enbdis_pair (dma_dptrs [ch], /* make specified channel */ + dma_dptrs [ch ^ 1]); /* consistent with other channel */ -if (sim_switches & SWMASK ('P')) /* PON reset? */ - dmac[0].cw1 = dmac[0].cw2 = dmac[0].cw3 = 0; /* clear control word registers */ +if (sim_switches & SWMASK ('P')) { /* power-on reset? */ + dma [ch].cw1 = 0; /* clear control word registers */ + dma [ch].cw2 = 0; + dma [ch].cw3 = 0; + } -dmapio (DMA0, ioPOPIO, 0); /* send POPIO signal */ +IOPRESET (dibptr); /* PRESET device (does not use PON) */ -dmac[0].latency = dmac[0].packer = 0; /* clear latency and byte packer */ -return SCPE_OK; -} +dma [ch].packer = 0; /* clear byte packer */ - -/* DMA channel 2 reset */ - -t_stat dma1_reset (DEVICE *tptr) -{ -if (UNIT_CPU_MODEL != UNIT_2114) /* 2114 has only one channel */ - hp_enbdis_pair (&dma1_dev, &dma0_dev); /* make pair cons */ - -if (sim_switches & SWMASK ('P')) /* PON reset? */ - dmac[1].cw1 = dmac[1].cw2 = dmac[1].cw3 = 0; /* clear control word registers */ - -dmapio (DMA1, ioPOPIO, 0); /* send POPIO signal */ - -dmac[1].latency = dmac[1].packer = 0; /* clear latency and byte packer */ return SCPE_OK; } @@ -3251,8 +3573,11 @@ return SCPE_OK; void hp_enbdis_pair (DEVICE *ccp, DEVICE *dcp) { -if (ccp->flags & DEV_DIS) dcp->flags = dcp->flags | DEV_DIS; -else dcp->flags = dcp->flags & ~DEV_DIS; +if (ccp->flags & DEV_DIS) + dcp->flags = dcp->flags | DEV_DIS; +else + dcp->flags = dcp->flags & ~DEV_DIS; + return; } @@ -3277,38 +3602,51 @@ return; static t_bool dev_conflict (void) { DEVICE *dptr; -DIB *dibp; +DIB *dibptr; uint32 i, j, k; t_bool is_conflict = FALSE; -uint32 conflicts[I_DEVMASK + 1] = { 0 }; +uint32 conflicts[MAXDEV + 1] = { 0 }; for (i = 0; dptr = sim_devices[i]; i++) { - dibp = (DIB *) dptr->ctxt; - if (dibp && !(dptr->flags & DEV_DIS)) - if (++conflicts[dibp->devno] > 1) + dibptr = (DIB *) dptr->ctxt; + if (dibptr && !(dptr->flags & DEV_DIS)) + if (++conflicts[dibptr->select_code] > 1) is_conflict = TRUE; } if (is_conflict) { sim_ttcmd(); - for (i = 0; i <= I_DEVMASK; i++) { + for (i = 0; i <= MAXDEV; i++) { if (conflicts[i] > 1) { k = conflicts[i]; + printf ("Select code %o conflict:", i); - if (sim_log) fprintf (sim_log, "Select code %o conflict:", i); + + if (sim_log) + fprintf (sim_log, "Select code %o conflict:", i); + for (j = 0; dptr = sim_devices[j]; j++) { - dibp = (DIB *) dptr->ctxt; - if (dibp && !(dptr->flags & DEV_DIS) && (i == dibp->devno)) { + dibptr = (DIB *) dptr->ctxt; + if (dibptr && !(dptr->flags & DEV_DIS) && (i == dibptr->select_code)) { if (k < conflicts[i]) { printf (" and"); - if (sim_log) fputs (" and", sim_log); + + if (sim_log) + fputs (" and", sim_log); } + printf (" %s", sim_dname (dptr)); - if (sim_log) fprintf (sim_log, " %s", sim_dname (dptr)); + + if (sim_log) + fprintf (sim_log, " %s", sim_dname (dptr)); + k = k - 1; + if (k == 0) { putchar ('\n'); - if (sim_log) fputc ('\n', sim_log); + + if (sim_log) + fputc ('\n', sim_log); break; } } @@ -3345,7 +3683,9 @@ if ((new_size <= 0) || (new_size > PASIZE) || ((new_size & 07777) != 0)) return SCPE_NXM; /* invalid size (prog err) */ if (!(sim_switches & SWMASK ('F'))) { /* force truncation? */ - for (i = new_size; i < MEMSIZE; i++) mc = mc | M[i]; + for (i = new_size; i < MEMSIZE; i++) /* check truncated memory */ + mc = mc | M[i]; /* for content */ + if ((mc != 0) && (!get_yn ("Really truncate memory [N]?", FALSE))) return SCPE_INCOMP; } @@ -3358,7 +3698,9 @@ if (UNIT_CPU_FAMILY == UNIT_FAMILY_21XX) { /* 21xx CPU? */ else /* loader unsupported */ fwanxm = MEMSIZE = new_size; /* set new memory size */ -for (i = fwanxm; i < old_size; i++) M[i] = 0; /* zero non-existent memory */ +for (i = fwanxm; i < old_size; i++) /* zero non-existent memory */ + M[i] = 0; + return SCPE_OK; } @@ -3367,7 +3709,7 @@ return SCPE_OK; For convenience, MP and DMA are typically enabled if available; they may be disabled subsequently if desired. Note that the 2114 supports only one DMA - channel (channel 0). All other models support two channels. + channel (channel 1). All other models support two channels. Validation: - Sets standard equipment and convenience features. @@ -3400,41 +3742,41 @@ else if (cpu_features[new_index].typ & UNIT_DMA) { /* DMA in typ config? */ - dma0_dev.flags = dma0_dev.flags & ~DEV_DIS; /* enable DMA channel 0 */ + dma1_dev.flags = dma1_dev.flags & ~DEV_DIS; /* enable DMA channel 1 */ if (new_model == UNIT_2114) /* 2114 has only one channel */ - dma1_dev.flags = dma1_dev.flags | DEV_DIS; /* disable channel 1 */ + dma2_dev.flags = dma2_dev.flags | DEV_DIS; /* disable channel 2 */ else /* all others have two channels */ - dma1_dev.flags = dma1_dev.flags & ~DEV_DIS; /* enable it */ + dma2_dev.flags = dma2_dev.flags & ~DEV_DIS; /* enable it */ } else { - dma0_dev.flags = dma0_dev.flags | DEV_DIS; /* disable channel 0 */ dma1_dev.flags = dma1_dev.flags | DEV_DIS; /* disable channel 1 */ + dma2_dev.flags = dma2_dev.flags | DEV_DIS; /* disable channel 2 */ } if (cpu_features[new_index].opt & UNIT_DMA) { /* DMA an option? */ - dma0_dev.flags = dma0_dev.flags | DEV_DISABLE; /* make it alterable */ + dma1_dev.flags = dma1_dev.flags | DEV_DISABLE; /* make it alterable */ if (new_model == UNIT_2114) /* 2114 has only one channel */ - dma1_dev.flags = dma1_dev.flags & ~DEV_DISABLE; /* make it unalterable */ + dma2_dev.flags = dma2_dev.flags & ~DEV_DISABLE; /* make it unalterable */ else /* all others have two channels */ - dma1_dev.flags = dma1_dev.flags | DEV_DISABLE; /* make it alterable */ + dma2_dev.flags = dma2_dev.flags | DEV_DISABLE; /* make it alterable */ } else { - dma0_dev.flags = dma0_dev.flags & ~DEV_DISABLE; /* make it unalterable */ dma1_dev.flags = dma1_dev.flags & ~DEV_DISABLE; /* make it unalterable */ + dma2_dev.flags = dma2_dev.flags & ~DEV_DISABLE; /* make it unalterable */ } if ((old_family == UNIT_FAMILY_1000) && /* if current family is 1000 */ (new_family == UNIT_FAMILY_21XX)) { /* and new family is 21xx */ - deassign_device (&dma0_dev); /* delete DCPC names */ - deassign_device (&dma1_dev); + deassign_device (&dma1_dev); /* delete DCPC names */ + deassign_device (&dma2_dev); } else if ((old_family == UNIT_FAMILY_21XX) && /* if current family is 21xx */ (new_family == UNIT_FAMILY_1000)) { /* and new family is 1000 */ - assign_device (&dma0_dev, "DCPC0"); /* change DMA device name */ - assign_device (&dma1_dev, "DCPC1"); /* to DCPC for familiarity */ + assign_device (&dma1_dev, "DCPC1"); /* change DMA device name */ + assign_device (&dma2_dev, "DCPC2"); /* to DCPC for familiarity */ } if ((MEMSIZE == 0) || /* current mem size not set? */ @@ -3593,16 +3935,7 @@ return SCPE_OK; } -/* Idle set/clear. - - Idling must have a calibrated clock before sleeping, or the TBG rate will - be wrong. When we handle a SET CPU IDLE, we want to... - - ...do something to allow the clock to stabilize before actually enabling. - Probably set sim_idle_enab immediately, so idling is reported as on, but - don't actually call sim_idle() until clock stabilizes. Maybe "cpu_idle" = 0 - and then = 1 after 100 clocks? - */ +/* Idle enable/disable */ t_stat cpu_set_idle (UNIT *uptr, int32 option, char *cptr, void *desc) { @@ -3629,7 +3962,9 @@ extern const BOOT_ROM ptr_rom, dq_rom, ms_rom, ds_rom; int32 dev = (SR >> IBL_V_DEV) & I_DEVMASK; int32 sel = (SR >> IBL_V_SEL) & IBL_M_SEL; -if (dev < 010) return SCPE_NOFNC; +if (dev < 010) + return SCPE_NOFNC; + switch (sel) { case 0: /* PTR boot */ @@ -3657,11 +3992,11 @@ return SCPE_OK; - Use memory size to set the initial PC and base of the boot area - Copy boot ROM to memory, updating I/O instructions - - Place 2's complement of boot base in last location + - Place 2s complement of boot base in last location Notes: - SR settings are done by the caller - - Boot ROM's must be assembled with a device code of 10 (10 and 11 for + - Boot ROMs must be assembled with a device code of 10 (10 and 11 for devices requiring two codes) */ @@ -3672,16 +4007,23 @@ uint16 wd; cpu_set_ldr (NULL, TRUE, NULL, NULL); /* enable loader (ignore errors) */ -if (dev < 010) return SCPE_ARG; /* valid device? */ +if (dev < 010) /* valid device? */ + return SCPE_ARG; + PC = ((MEMSIZE - 1) & ~IBL_MASK) & VAMASK; /* start at mem top */ + for (i = 0; i < IBL_LNT; i++) { /* copy bootstrap */ wd = rom[i]; /* get word */ + if (((wd & I_NMRMASK) == I_IO) && /* IO instruction? */ ((wd & I_DEVMASK) >= 010) && /* dev >= 10? */ (I_GETIOOP (wd) != soHLT)) /* not a HALT? */ M[PC + i] = (wd + (dev - 010)) & DMASK; /* change dev code */ - else M[PC + i] = wd; /* leave unchanged */ + + else /* leave unchanged */ + M[PC + i] = wd; } + M[PC + IBL_DPC] = (M[PC + IBL_DPC] + (dev - 010)) & DMASK; /* patch DMA ctrl */ M[PC + IBL_END] = (~PC + 1) & DMASK; /* fill in start of boot */ return SCPE_OK; diff --git a/HP2100/hp2100_cpu.h b/HP2100/hp2100_cpu.h index 4b1f8e94..4e0db47e 100644 --- a/HP2100/hp2100_cpu.h +++ b/HP2100/hp2100_cpu.h @@ -281,24 +281,25 @@ extern uint32 O; /* O register */ /* CPU state */ -extern uint32 err_PC; -extern uint32 dms_enb; -extern uint32 dms_ump; -extern uint32 dms_sr; -extern uint32 dms_vr; -extern FLIP_FLOP mp_control; -extern uint32 mp_fence; -extern uint32 mp_viol; -extern FLIP_FLOP mp_mevff; -extern uint32 iop_sp; -extern t_bool ion_defer; -extern uint32 intaddr; -extern uint16 pcq [PCQ_SIZE]; -extern uint32 pcq_p; -extern uint32 stop_inst; -extern UNIT cpu_unit; -extern DEVICE cpu_dev; -extern jmp_buf save_env; +extern uint32 err_PC; +extern uint32 dms_enb; +extern uint32 dms_ump; +extern uint32 dms_sr; +extern uint32 dms_vr; +extern FLIP_FLOP mp_control; +extern uint32 mp_fence; +extern uint32 mp_viol; +extern FLIP_FLOP mp_mevff; +extern uint32 iop_sp; +extern t_bool ion_defer; +extern uint32 intaddr; +extern uint16 pcq [PCQ_SIZE]; +extern uint32 pcq_p; +extern uint32 stop_inst; +extern UNIT cpu_unit; +extern DEVICE cpu_dev; +extern jmp_buf save_env; + /* CPU functions */ diff --git a/HP2100/hp2100_cpu0.c b/HP2100/hp2100_cpu0.c index df199de2..2e7e6eb2 100644 --- a/HP2100/hp2100_cpu0.c +++ b/HP2100/hp2100_cpu0.c @@ -1,6 +1,6 @@ /* hp2100_cpu0.c: HP 1000 user microcode and unimplemented instruction set stubs - Copyright (c) 2006-2008, J. David Bryan + Copyright (c) 2006-2010, J. David Bryan Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), @@ -25,6 +25,7 @@ CPU0 User microcode and unimplemented firmware options + 04-Nov-10 JDB Removed DS note regarding PIF card (is now implemented) 18-Sep-08 JDB .FLUN and self-tests for VIS and SIGNAL are NOP if not present 11-Sep-08 JDB Moved microcode function prototypes to hp2100_cpu1.h 05-Sep-08 JDB Removed option-present tests (now in UIG dispatchers) @@ -81,8 +82,7 @@ the cards. Implementation of the DS instructions will also require simulation of the - 12665A Hardwired Serial Data Interface Card and the 12620A RTE Privileged - Interrupt Fence. These are required for DS/1000. + 12665A Hardwired Serial Data Interface Card. Option implementation by CPU was as follows: @@ -180,11 +180,11 @@ t_stat reason = SCPE_OK; if (UNIT_CPU_TYPE == UNIT_TYPE_211X) /* 2116/15/14 CPU? */ return stop_inst; /* user microprograms not supported */ -switch (IR) { /* opcodes for firmware detection */ - case 0105226: /* FFP .FLUN */ - case 0105355: /* RTE-6/VM OS self-test */ - case 0105477: /* VIS self-test */ - case 0105617: /* SIGNAL/1000 self-test */ +switch (IR) { + case 0105226: /* firmware detection: FFP .FLUN */ + case 0105355: /* firmware detection: RTE-6/VM OS self-test */ + case 0105477: /* firmware detection: VIS self-test */ + case 0105617: /* firmware detection: SIGNAL/1000 self-test */ return SCPE_OK; /* execute as NOP */ } diff --git a/HP2100/hp2100_cpu6.c b/HP2100/hp2100_cpu6.c index f0a464de..5606a178 100644 --- a/HP2100/hp2100_cpu6.c +++ b/HP2100/hp2100_cpu6.c @@ -1,6 +1,6 @@ /* hp2100_cpu6.c: HP 1000 RTE-6/VM OS instructions - Copyright (c) 2006-2008, J. David Bryan + Copyright (c) 2006-2010, J. David Bryan Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), @@ -25,6 +25,7 @@ CPU6 RTE-6/VM OS instructions + 29-Oct-10 JDB DMA channels renamed from 0,1 to 1,2 to match documentation 18-Sep-08 JDB Corrected .SIP debug formatting 11-Sep-08 JDB Moved microcode function prototypes to hp2100_cpu1.h 05-Sep-08 JDB Removed option-present tests (now in UIG dispatchers) @@ -258,8 +259,8 @@ if (iotrap) { /* do priv setup only if if (priv_fence) { /* privileged system? */ reason = iogrp (STC_0 + priv_fence, iotrap); /* STC SC on priv fence */ - reason = iogrp (CLC_0 + DMA0, iotrap); /* CLC 6 to inh IRQ on DCPC 0 */ - reason = iogrp (CLC_0 + DMA1, iotrap); /* CLC 7 to inh IRQ on DCPC 1 */ + reason = iogrp (CLC_0 + DMA1, iotrap); /* CLC 6 to inh IRQ on DCPC 1 */ + reason = iogrp (CLC_0 + DMA2, iotrap); /* CLC 7 to inh IRQ on DCPC 2 */ reason = iogrp (STF_0, iotrap); /* turn interrupt system back on */ } } @@ -600,11 +601,11 @@ switch (entry) { /* decode IR<3:0> */ reason = iogrp (CLC_0 + priv_fence, iotrap); /* CLC SC on priv fence */ reason = iogrp (STF_0 + priv_fence, iotrap); /* STF SC on priv fence */ - if (cpu_get_intbl (DMA0) & SIGN) /* DCPC 0 active? */ - reason = iogrp (STC_0 + DMA0, iotrap); /* STC 6 to enable IRQ on DCPC 0 */ - if (cpu_get_intbl (DMA1) & SIGN) /* DCPC 1 active? */ - reason = iogrp (STC_0 + DMA1, iotrap); /* STC 7 to enable IRQ on DCPC 1 */ + reason = iogrp (STC_0 + DMA1, iotrap); /* STC 6 to enable IRQ on DCPC 1 */ + + if (cpu_get_intbl (DMA2) & SIGN) /* DCPC 2 active? */ + reason = iogrp (STC_0 + DMA2, iotrap); /* STC 7 to enable IRQ on DCPC 2 */ } tbg_tick = 0; /* .IRT terminates TBG servicing */ diff --git a/HP2100/hp2100_defs.h b/HP2100/hp2100_defs.h index b0e8ff40..f999867b 100644 --- a/HP2100/hp2100_defs.h +++ b/HP2100/hp2100_defs.h @@ -1,6 +1,6 @@ /* hp2100_defs.h: HP 2100 simulator definitions - Copyright (c) 1993-2008, Robert M. Supnik + Copyright (c) 1993-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"), @@ -23,6 +23,10 @@ be used in advertising or otherwise to promote the sale, use or other dealings in this Software without prior written authorization from Robert M Supnik. + 28-Mar-11 JDB Tidied up signal handling + 29-Oct-10 JDB DMA channels renamed from 0,1 to 1,2 to match documentation + 27-Oct-10 JDB Revised I/O signal enum values for concurrent signals + Revised I/O macros for new signal handling 07-Sep-08 JDB Added POLL_FIRST to indicate immediate connection attempt 15-Jul-08 JDB Rearranged declarations with hp2100_cpu.h 26-Jun-08 JDB Rewrote device I/O to model backplane signals @@ -128,87 +132,18 @@ typedef enum { INITIAL, SERVICE } POLLMODE; /* poll synchronization #define soOTX 6 /* output from A/B */ #define soCTL 7 /* set/clear control */ - -/* I/O backplane signals. - - The IOSIG declarations mirror the I/O backplane signals. These are sent to - the device I/O signal handlers for action. Normally, only one signal may be - sent at a time. However, the ioCLF signal may be added (arithmetically) to - another signal; the handlers will process the other signal first and then the - CLF signal. - - Implementation notes: - - 1. The first valid signal must have a value > 0, and ioCLF must be - enumerated last, so that adding ioCLF produces a result > ioCLF. - - 2. The signals are structured so that all those that might change the - interrupt state are enumerated after ioSIR. The handlers will detect - this and add an ioSIR signal automatically. - - 3. In hardware, the POPIO signal is asserted concurrently with the CRS - signal. Under simulation, ioPOPIO implies ioCRS, so the handlers are - structured to fall from POPIO handling into CRS handling. It is not - necessary to send both signals for a PRESET. - - 4. In hardware, the SIR signal is generated unconditionally every T5 period - to time the setting of the IRQ flip-flop. Under simulation, ioSIR is - sent to set the PRL, IRQ, and SRQ signals as indicated by the interface - logic. It is necessary to send ioSIR only when that logic indicates a - change in one or more of the three signals. - - 5. In hardware, the ENF signal is unconditionally generated every T2 period - to time the setting of the flag flip-flop and to reset the IRQ flip-flop. - If the flag buffer flip-flip is set, then flag will be set by ENF. If - the flag buffer is clear, ENF will not affect flag. Under simulation, - ioENF is sent to set the flag buffer and flag flip-flops. For those - interfaces where this action is identical to that provided by STF, the - ioENF handler may simply fall into the ioSTF handler. - - 6. The ioSKF signal is never sent to an I/O device. Rather, it is returned - from the device if the SFC or SFS condition is true. - - 7. A device will receive ioNONE when a HLT instruction is executed, and the - H/C bit is clear (i.e., no CLF generated). -*/ - -typedef enum { CLEAR, SET } FLIP_FLOP; /* flip-flop type and values */ - -typedef enum { ioNONE, /* no signal asserted */ - ioSKF, /* skip on flag */ - ioSFC, /* skip if flag is clear */ - ioSFS, /* skip if flag is set */ - ioIOI, /* I/O data input */ - ioIOO, /* I/O data output */ - ioEDT, /* end data transfer */ - ioSIR, /* set interrupt request */ - ioIAK, /* interrupt acknowledge */ - ioCRS, /* control reset */ - ioPOPIO, /* power-on preset to I/O */ - ioCLC, /* clear control flip-flop */ - ioSTC, /* set control flip-flop */ - ioENF, /* enable flag */ - ioSTF, /* set flag flip-flop */ - ioCLF } IOSIG; /* clear flag flip-flop */ - -/* I/O devices - fixed assignments */ +/* I/O devices - fixed select code assignments */ #define CPU 000 /* interrupt control */ #define OVF 001 /* overflow */ -#define DMALT0 002 /* DMA 0 alternate */ -#define DMALT1 003 /* DMA 1 alternate */ +#define DMALT1 002 /* DMA 1 alternate */ +#define DMALT2 003 /* DMA 2 alternate */ #define PWR 004 /* power fail */ #define PRO 005 /* parity/mem protect */ -#define DMA0 006 /* DMA channel 0 */ -#define DMA1 007 /* DMA channel 1 */ -#define OPTDEV DMALT0 /* start of optional devices */ -#define VARDEV (DMA1 + 1) /* start of var assign */ -#define M_NXDEV (INT_M (CPU) | INT_M (OVF) | \ - INT_M (DMALT0) | INT_M (DMALT1)) -#define M_FXDEV (M_NXDEV | INT_M (PWR) | INT_M (PRO) | \ - INT_M (DMA0) | INT_M (DMA1)) +#define DMA1 006 /* DMA channel 1 */ +#define DMA2 007 /* DMA channel 2 */ -/* I/O devices - variable assignment defaults */ +/* I/O devices - variable select code assignment defaults */ #define PTR 010 /* 12597A-002 paper tape reader */ #define TTY 011 /* 12531C teleprinter */ @@ -236,6 +171,11 @@ typedef enum { ioNONE, /* no signal asserted */ #define MUXU 041 /* 12920A upper data */ #define MUXC 042 /* 12920A control */ +#define OPTDEV 002 /* start of optional devices */ +#define CRSDEV 006 /* start of devices that receive CRS */ +#define VARDEV 010 /* start of variable assignments */ +#define MAXDEV 077 /* end of select code range */ + /* IBL assignments */ #define IBL_V_SEL 14 /* ROM select */ @@ -257,41 +197,240 @@ typedef enum { ioNONE, /* no signal asserted */ typedef uint16 BOOT_ROM [IBL_LNT]; /* boot ROM data */ -/* Dynamic device information table */ -typedef uint32 IODISP (uint32 select_code, IOSIG signal, uint32 data); /* I/O signal dispatch function */ +/* I/O backplane signals. -typedef struct { - uint32 devno; /* device select code */ - IODISP *iot; /* pointer to I/O signal dispatcher */ - } DIB; + The IOSIGNAL declarations mirror the hardware I/O backplane signals. A set + of one or more signals forms an IOCYCLE that is sent to a device IOHANDLER + for action. The CPU and DMA dispatch one signal set to the target device + handler per I/O cycle. A CPU cycle consists of either one or two signals; if + present, the second signal will be CLF. A DMA cycle consists of from two to + five signals. In addition, a front-panel PRESET or power-on reset dispatches + two or three signals, respectively. -/* I/O macros */ + In hardware, signals are assigned to one or more specific I/O T-periods, and + some signals are asserted concurrently. For example, a programmed STC sc,C + instruction asserts the STC and CLF signals together in period T4. Under + simulation, signals are ORed to form an I/O cycle; in this example, the + signal handler would receive an IOCYCLE value of "ioSTC | ioCLF". -#define IOBASE(S) ((S) > ioCLF ? (S) - ioCLF : (S)) /* base signal from compound signal */ + Hardware allows parallel action for concurrent signals. Under simulation, a + "concurrent" set of signals is processed sequentially by the signal handler + in order of ascending numerical value. Although assigned T-periods differ + between programmed I/O and DMA I/O cycles, a single processing order is used. + The order of execution generally follows the order of T-period assertion, + except that ioSIR is processed after all other signals that may affect the + interrupt request chain. -#define INT_V(x) ((x) & 037) /* device bit position */ -#define INT_M(x) (1u << INT_V (x)) /* device bit mask */ + Implementation notes: -#define setSKF(B) data = (uint32) ((B) ? ioSKF : ioNONE) + 1. The ioCLF signal must be processed after ioSFS/ioSFC to ensure that a + true skip test generates ioSKF before the flag is cleared, and after + ioIOI/ioIOO/ioSTC/ioCLC to meet the requirement that executing an + instruction having the H/C bit set is equivalent to executing the same + instruction with the H/C bit clear and then a CLF instruction. -#define setPRL(S,B) dev_prl[(S)/32] = dev_prl[(S)/32] & ~INT_M (S) | (((B) & 1) << INT_V (S)) -#define setIRQ(S,B) dev_irq[(S)/32] = dev_irq[(S)/32] & ~INT_M (S) | (((B) & 1) << INT_V (S)) -#define setSRQ(S,B) dev_srq[(S)/32] = dev_srq[(S)/32] & ~INT_M (S) | (((B) & 1) << INT_V (S)) + 2. The ioSKF signal is never sent to an I/O handler. Rather, it is returned + from the handler if the SFC or SFS condition is true. If the condition + is false, ioNONE is returned instead. As these two values are returned + in the 16-bit data portion of the returned value, their assigned values + must be <= 100000 octal. -#define setstdSKF(N) setSKF ((base_signal == ioSFC) && !N ## _flag || \ - (base_signal == ioSFS) && N ## _flag) + 3. An I/O handler will receive ioCRS as a result of a CLC 0 instruction, + ioPOPIO and ioCRS as a result of a RESET command, and ioPON, ioPOPIO, and + ioCRS as a result of a RESET -P command. -#define setstdPRL(S,N) setPRL ((S), !(N ## _control & N ## _flag)); -#define setstdIRQ(S,N) setIRQ ((S), N ## _control & N ## _flag & N ## _flagbuf); -#define setstdSRQ(S,N) setSRQ ((S), N ## _flag); + 4. An I/O handler will receive ioNONE when a HLT instruction is executed + that has the H/C bit clear (i.e., no CLF generated). -#define PRL(S) ((dev_prl[(S)/32] >> INT_V (S)) & 1) -#define IRQ(S) ((dev_irq[(S)/32] >> INT_V (S)) & 1) -#define SRQ(S) ((dev_srq[(S)/32] >> INT_V (S)) & 1) + 5. In hardware, the SIR signal is generated unconditionally every T5 period + to time the setting of the IRQ flip-flop. Under simulation, ioSIR + indicates that the I/O handler must set the PRL, IRQ, and SRQ signals as + required by the interface logic. ioSIR must be included in the I/O cycle + if any of the flip-flops affecting these signals are changed and the + interface supports interrupts or DMA transfers. + + 6. In hardware, the ENF signal is unconditionally generated every T2 period + to time the setting of the flag flip-flop and to reset the IRQ flip-flop. + If the flag buffer flip-flip is set, then flag will be set by ENF. If + the flag buffer is clear, ENF will not affect flag. Under simulation, + ioENF is sent to set the flag buffer and flag flip-flops. For those + interfaces where this action is identical to that provided by STF, the + ioENF handler may simply fall into the ioSTF handler. + + 7. In hardware, the PON signal is asserted continuously while the CPU is + operating. Under simulation, ioPON is asserted only at simulator + initialization or when processing a RESET -P command. +*/ + +typedef enum { ioNONE = 0000000, /* -- -- -- -- -- no signal asserted */ + ioPON = 0000001, /* T2 T3 T4 T5 T6 power on normal */ + ioENF = 0000002, /* T2 -- -- -- -- enable flag */ + ioIOI = 0000004, /* -- -- T4 T5 -- I/O data input (CPU) + T2 T3 -- -- -- I/O data input (DMA) */ + ioIOO = 0000010, /* -- T3 T4 -- -- I/O data output */ + ioSKF = 0000020, /* -- T3 T4 T5 -- skip on flag */ + ioSFS = 0000040, /* -- T3 T4 T5 -- skip if flag is set */ + ioSFC = 0000100, /* -- T3 T4 T5 -- skip if flag is clear */ + ioSTC = 0000200, /* -- -- T4 -- -- set control flip-flop (CPU) + -- T3 -- -- -- set control flip-flop (DMA) */ + ioCLC = 0000400, /* -- -- T4 -- -- clear control flip-flop (CPU) + -- T3 T4 -- -- clear control flip-flop (DMA) */ + ioSTF = 0001000, /* -- T3 -- -- -- set flag flip-flop */ + ioCLF = 0002000, /* -- -- T4 -- -- clear flag flip-flop (CPU) + -- T3 -- -- -- clear flag flip-flop (DMA) */ + ioEDT = 0004000, /* -- -- T4 -- -- end data transfer */ + ioCRS = 0010000, /* -- -- -- T5 -- control reset */ + ioPOPIO = 0020000, /* -- -- -- T5 -- power-on preset to I/O */ + ioIAK = 0040000, /* -- -- -- -- T6 interrupt acknowledge */ + ioSIR = 0100000 } IOSIGNAL; /* -- -- -- T5 -- set interrupt request */ + + +typedef uint32 IOCYCLE; /* a set of signals forming one I/O cycle */ + +#define IOIRQSET (ioSTC | ioCLC | ioENF | \ + ioSTF | ioCLF | ioIAK | \ + ioCRS | ioPOPIO | ioPON) /* signals that may affect interrupt state */ + + +/* I/O structures */ + +typedef enum { CLEAR, SET } FLIP_FLOP; /* flip-flop type and values */ + +typedef struct dib DIB; /* incomplete definition */ + +typedef uint32 IOHANDLER (DIB *dibptr, /* I/O signal handler prototype */ + IOCYCLE signal_set, + uint32 stat_data); + +struct dib { /* Device information block */ + IOHANDLER *io_handler; /* pointer to device's I/O signal handler */ + uint32 select_code; /* device's select code */ + uint32 card_index; /* device's card index for state variables */ + }; + + +/* I/O signal and status macros. + + The following macros are useful in I/O signal handlers and unit service + routines. The parameter definition symbols employed are: + + I = an IOCYCLE value + E = a t_stat error status value + D = a uint16 data value + C = a uint32 combined status and data value + P = a pointer to a DIB structure + B = a Boolean test value + + Implementation notes: + + 1. The IONEXT macro isolates the next signal in sequence to process from the + I/O cycle I. + + 2. The IOADDSIR macro adds an ioSIR signal to the I/O cycle I if it + contains signals that might change the interrupt state. + + 3. The IORETURN macro forms the combined status and data value to be + returned by a handler from the t_stat error code E and the 16-bit data + value D. + + 4. The IOSTATUS macro isolates the t_stat error code from a combined status + and data value value C. + + 5. The IODATA macro isolates the 16-bit data value from a combined status + and data value value C. + + 6. The IOPOWERON macro calls signal handler P->H with DIB pointer P to + process a power-on reset action. + + 7. The IOPRESET macro calls signal handler P->H with DIB pointer P to + process a front-panel PRESET action. + + 8. The IOERROR macro returns t_stat error code E from a unit service routine + if the Boolean test B is true. +*/ + +#define IONEXT(I) (IOSIGNAL) ((I) & (IOCYCLE) (- (int32) (I))) /* extract next I/O signal to handle */ +#define IOADDSIR(I) ((I) & IOIRQSET ? (I) | ioSIR : (I)) /* add SIR if IRQ state might change */ + +#define IORETURN(E,D) ((uint32) ((E) << 16 | (D) & DMASK)) /* form I/O handler return value */ +#define IOSTATUS(C) ((t_stat) ((C) >> 16) & DMASK) /* extract I/O status from combined value */ +#define IODATA(C) ((uint16) ((C) & DMASK)) /* extract data from combined value */ + +#define IOPOWERON(P) (P)->io_handler ((P), ioPON | ioPOPIO | ioCRS, 0) /* send power-on signals to handler */ +#define IOPRESET(P) (P)->io_handler ((P), ioPOPIO | ioCRS, 0) /* send PRESET signals to handler */ +#define IOERROR(B,E) ((B) ? (E) : SCPE_OK) /* stop on I/O error if enabled */ + + +/* I/O signal logic macros. + + The following macros implement the logic for the SKF, PRL, IRQ, and SRQ + signals. Both standard and general logic macros are provided. The parameter + definition symbols employed are: + + S = a uint32 select code value + B = a Boolean test value + N = a name of a structure containing the standard flip-flops + + Implementation notes: + + 1. The setSKF macro sets the Skip on Flag signal in the return data value if + the Boolean value B is true. + + 2. The setPRL macro sets the Priority Low signal for select code S to the + Boolean value B. + + 3. The setIRQ macro sets the Interrupt Request signal for select code S to + the Boolean value B. + + 4. The setSRQ macro sets the Service Request signal for select code S to the + Boolean value B. + + 5. The PRL macro returns the Priority Low signal for select code S as a + Boolean value. + + 6. The IRQ macro returns the Interrupt Request signal for select code S as a + Boolean value. + + 7. The SRQ macro returns the Service Request signal for select code S as a + Boolean value. + + 8. The setstdSKF macro sets Skip on Flag signal in the return data value if + the flag state in structure N matches the current skip test condition. + + 9. The setstdPRL macro sets the Priority Low signal for the select code + referenced by "dibptr" using the standard logic and the control and flag + states in structure N. + + 10. The setstdIRQ macro sets the Interrupt Request signal for the select code + referenced by "dibptr" using the standard logic and the control, flag, + and flag buffer states in structure N. + + 11. The setstdSRQ macro sets the Service Request signal for the select code + referenced by "dibptr" using the standard logic and the flag state in + structure N. +*/ + +#define BIT_V(S) ((S) & 037) /* convert select code to bit position */ +#define BIT_M(S) (1u << BIT_V (S)) /* convert select code to bit mask */ + +#define setSKF(B) stat_data = IORETURN (SCPE_OK, (uint16) ((B) ? ioSKF : ioNONE)) + +#define setPRL(S,B) dev_prl[(S)/32] = dev_prl[(S)/32] & ~BIT_M (S) | (((B) & 1) << BIT_V (S)) +#define setIRQ(S,B) dev_irq[(S)/32] = dev_irq[(S)/32] & ~BIT_M (S) | (((B) & 1) << BIT_V (S)) +#define setSRQ(S,B) dev_srq[(S)/32] = dev_srq[(S)/32] & ~BIT_M (S) | (((B) & 1) << BIT_V (S)) + +#define PRL(S) ((dev_prl[(S)/32] >> BIT_V (S)) & 1) +#define IRQ(S) ((dev_irq[(S)/32] >> BIT_V (S)) & 1) +#define SRQ(S) ((dev_srq[(S)/32] >> BIT_V (S)) & 1) + +#define setstdSKF(N) setSKF ((signal == ioSFC) && !N.flag || \ + (signal == ioSFS) && N.flag) + +#define setstdPRL(N) setPRL (dibptr->select_code, !(N.control & N.flag)); +#define setstdIRQ(N) setIRQ (dibptr->select_code, N.control & N.flag & N.flagbuf); +#define setstdSRQ(N) setSRQ (dibptr->select_code, N.flag); -#define IOT_V_REASON 16 -#define IORETURN(F,V) ((F) ? (V) : SCPE_OK) /* stop on I/O error */ /* CPU state */ diff --git a/HP2100/hp2100_dp.c b/HP2100/hp2100_dp.c index 86e4ed6c..f2eddd5c 100644 --- a/HP2100/hp2100_dp.c +++ b/HP2100/hp2100_dp.c @@ -1,6 +1,6 @@ /* hp2100_dp.c: HP 2100 12557A/13210A disk simulator - Copyright (c) 1993-2008, Robert M. Supnik + Copyright (c) 1993-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"), @@ -26,6 +26,8 @@ DP 12557A 2871 disk subsystem 13210A 7900 disk subsystem + 28-Mar-11 JDB Tidied up signal handling + 26-Oct-10 JDB Changed I/O signal handler for revised signal model 10-Aug-08 JDB Added REG_FIT to register variables < 32-bit size 26-Jun-08 JDB Rewrote device I/O to model backplane signals 28-Dec-06 JDB Added ioCRS state to I/O decoders @@ -206,10 +208,12 @@ #define STA_UNLOADED (dp_ctype ? (STA_NRDY | STA_BSY) : STA_NRDY) #define STA_MBZ13 (STA_ATN | STA_RWU | STA_SKI) /* zero in 13210 */ -FLIP_FLOP dpc_command = CLEAR; /* cch command flip-flop */ -FLIP_FLOP dpc_control = CLEAR; /* cch control flip-flop */ -FLIP_FLOP dpc_flag = CLEAR; /* cch flag flip-flop */ -FLIP_FLOP dpc_flagbuf = CLEAR; /* cch flag buffer flip-flop */ +struct { + FLIP_FLOP command; /* cch command flip-flop */ + FLIP_FLOP control; /* cch control flip-flop */ + FLIP_FLOP flag; /* cch flag flip-flop */ + FLIP_FLOP flagbuf; /* cch flag buffer flip-flop */ + } dpc = { CLEAR, CLEAR, CLEAR, CLEAR }; enum { A12557, A13210 } dp_ctype = A13210; /* ctrl type */ int32 dpc_busy = 0; /* cch unit */ @@ -223,10 +227,12 @@ int32 dpc_dtime = 2; /* dch time */ int32 dpd_obuf = 0, dpd_ibuf = 0; /* dch buffers */ int32 dpc_obuf = 0; /* cch buffers */ -FLIP_FLOP dpd_command = CLEAR; /* dch command flip-flop */ -FLIP_FLOP dpd_control = CLEAR; /* dch control flip-flop */ -FLIP_FLOP dpd_flag = CLEAR; /* dch flag flip-flop */ -FLIP_FLOP dpd_flagbuf = CLEAR; /* dch flag buffer flip-flop */ +struct { + FLIP_FLOP command; /* dch command flip-flop */ + FLIP_FLOP control; /* dch control flip-flop */ + FLIP_FLOP flag; /* dch flag flip-flop */ + FLIP_FLOP flagbuf; /* dch flag buffer flip-flop */ + } dpd = { CLEAR, CLEAR, CLEAR, CLEAR }; int32 dpd_xfer = 0; /* xfer in prog */ int32 dpd_wval = 0; /* write data valid */ @@ -239,8 +245,10 @@ uint16 dpc_sta[DP_NUMDRV] = { 0 }; /* status regs */ uint16 dpxb[DP_NUMWD]; /* sector buffer */ DEVICE dpd_dev, dpc_dev; -uint32 dpdio (uint32 select_code, IOSIG signal, uint32 data); -uint32 dpcio (uint32 select_code, IOSIG signal, uint32 data); + +IOHANDLER dpdio; +IOHANDLER dpcio; + t_stat dpc_svc (UNIT *uptr); t_stat dpd_svc (UNIT *uptr); t_stat dpc_reset (DEVICE *dptr); @@ -261,8 +269,8 @@ t_stat dp_showtype (FILE *st, UNIT *uptr, int32 val, void *desc); */ DIB dp_dib[] = { - { DPD, &dpdio }, - { DPC, &dpcio } + { &dpdio, DPD }, + { &dpcio, DPC } }; #define dpd_dib dp_dib[0] @@ -275,13 +283,13 @@ REG dpd_reg[] = { { ORDATA (OBUF, dpd_obuf, 16) }, { BRDATA (DBUF, dpxb, 8, 16, DP_NUMWD) }, { DRDATA (BPTR, dp_ptr, DP_N_NUMWD) }, - { FLDATA (CMD, dpd_command, 0) }, - { FLDATA (CTL, dpd_control, 0) }, - { FLDATA (FLG, dpd_flag, 0) }, - { FLDATA (FBF, dpd_flagbuf, 0) }, + { FLDATA (CMD, dpd.command, 0) }, + { FLDATA (CTL, dpd.control, 0) }, + { FLDATA (FLG, dpd.flag, 0) }, + { FLDATA (FBF, dpd.flagbuf, 0) }, { FLDATA (XFER, dpd_xfer, 0) }, { FLDATA (WVAL, dpd_wval, 0) }, - { ORDATA (DEVNO, dpd_dib.devno, 6), REG_HRO }, + { ORDATA (DEVNO, dpd_dib.select_code, 6), REG_HRO }, { NULL } }; @@ -322,10 +330,10 @@ REG dpc_reg[] = { { ORDATA (OBUF, dpc_obuf, 16) }, { ORDATA (BUSY, dpc_busy, 4), REG_RO }, { ORDATA (CNT, dpc_cnt, 5) }, - { FLDATA (CMD, dpc_command, 0) }, - { FLDATA (CTL, dpc_control, 0) }, - { FLDATA (FLG, dpc_flag, 0) }, - { FLDATA (FBF, dpc_flagbuf, 0) }, + { FLDATA (CMD, dpc.command, 0) }, + { FLDATA (CTL, dpc.control, 0) }, + { FLDATA (FLG, dpc.flag, 0) }, + { FLDATA (FBF, dpc.flagbuf, 0) }, { FLDATA (EOC, dpc_eoc, 0) }, { FLDATA (POLL, dpc_poll, 0) }, { DRDATA (RARC, dpc_rarc, 8), PV_RZRO | REG_FIT }, @@ -342,7 +350,7 @@ REG dpc_reg[] = { DP_NUMDRV, REG_HRO) }, { URDATA (CAPAC, dpc_unit[0].capac, 10, T_ADDR_W, 0, DP_NUMDRV, PV_LEFT | REG_HRO) }, - { ORDATA (DEVNO, dpc_dib.devno, 6), REG_HRO }, + { ORDATA (DEVNO, dpc_dib.select_code, 6), REG_HRO }, { NULL } }; @@ -389,112 +397,114 @@ DEVICE dpc_dev = { register. */ -uint32 dpdio (uint32 select_code, IOSIG signal, uint32 data) +uint32 dpdio (DIB *dibptr, IOCYCLE signal_set, uint32 stat_data) { -const IOSIG base_signal = IOBASE (signal); /* derive base signal */ +IOSIGNAL signal; +IOCYCLE working_set = IOADDSIR (signal_set); /* add ioSIR if needed */ -switch (base_signal) { /* dispatch base I/O signal */ +while (working_set) { + signal = IONEXT (working_set); /* isolate next signal */ - case ioCLF: /* clear flag flip-flop */ - dpd_flag = dpd_flagbuf = CLEAR; - break; + switch (signal) { /* dispatch I/O signal */ + + case ioCLF: /* clear flag flip-flop */ + dpd.flag = dpd.flagbuf = CLEAR; + break; - case ioSTF: /* set flag flip-flop */ - case ioENF: /* enable flag */ - dpd_flag = dpd_flagbuf = SET; - break; + case ioSTF: /* set flag flip-flop */ + case ioENF: /* enable flag */ + dpd.flag = dpd.flagbuf = SET; + break; - case ioSFC: /* skip if flag is clear */ - setstdSKF (dpd); - break; + case ioSFC: /* skip if flag is clear */ + setstdSKF (dpd); + break; - case ioSFS: /* skip if flag is set */ - setstdSKF (dpd); - break; + case ioSFS: /* skip if flag is set */ + setstdSKF (dpd); + break; - case ioIOI: /* I/O data input */ - data = dpd_ibuf; - break; + case ioIOI: /* I/O data input */ + stat_data = IORETURN (SCPE_OK, dpd_ibuf); /* merge in return status */ + break; - case ioIOO: /* I/O data output */ - dpd_obuf = data; + case ioIOO: /* I/O data output */ + dpd_obuf = IODATA (stat_data); /* clear supplied status */ - if (!dpc_busy || dpd_xfer) /* if !overrun */ - dpd_wval = 1; /* valid */ - break; + if (!dpc_busy || dpd_xfer) /* if !overrun */ + dpd_wval = 1; /* valid */ + break; - case ioPOPIO: /* power-on preset to I/O */ - dpd_flag = dpd_flagbuf = SET; /* set flag buffer and flag */ + case ioPOPIO: /* power-on preset to I/O */ + dpd.flag = dpd.flagbuf = SET; /* set flag buffer and flag */ - if (dp_ctype == A12557) /* 12557? */ - dpd_obuf = 0; /* clear output buffer */ - /* fall into CRS handler */ - - case ioCRS: /* control reset */ - dpd_command = CLEAR; /* clear command */ - - if (dp_ctype == A12557) /* 12557? */ - dpd_control = CLEAR; /* clear control */ - - else { /* 13210 */ - dpc_rarc = 0; /* clear controller cylinder address */ - dpc_ucyl [CW_GETDRV (dpc_obuf)] = 0; /* clear last drive addressed cylinder */ - } - break; + if (dp_ctype == A12557) /* 12557? */ + dpd_obuf = 0; /* clear output buffer */ + break; - case ioCLC: /* clear control flip-flop */ - if (dp_ctype == A12557) /* 12557? */ - dpd_control = CLEAR; /* clear control */ + case ioCRS: /* control reset */ + dpd.command = CLEAR; /* clear command */ - dpd_xfer = 0; /* clr xfer in progress */ - break; + if (dp_ctype == A12557) /* 12557? */ + dpd.control = CLEAR; /* clear control */ + + else { /* 13210 */ + dpc_rarc = 0; /* clear controller cylinder address */ + dpc_ucyl [CW_GETDRV (dpc_obuf)] = 0; /* clear last drive addressed cylinder */ + } + break; - case ioSTC: /* set control flip-flop */ - if (dp_ctype == A12557) /* 12557? */ - dpd_control = SET; /* set control */ + case ioCLC: /* clear control flip-flop */ + if (dp_ctype == A12557) /* 12557? */ + dpd.control = CLEAR; /* clear control */ - dpd_command = SET; /* set cmd */ - - if (dpc_busy && !dpd_xfer) /* overrun? */ - dpc_sta[dpc_busy - 1] |= STA_OVR; - break; + dpd_xfer = 0; /* clr xfer in progress */ + break; - case ioSIR: /* set interrupt request */ - if (dp_ctype == A12557) { /* 12557? */ - setstdPRL (select_code, dpd); /* set standard PRL signal */ - setstdIRQ (select_code, dpd); /* set standard IRQ signal */ - } + case ioSTC: /* set control flip-flop */ + if (dp_ctype == A12557) /* 12557? */ + dpd.control = SET; /* set control */ - setstdSRQ (select_code, dpd); /* set standard SRQ signal */ - break; + dpd.command = SET; /* set cmd */ + + if (dpc_busy && !dpd_xfer) /* overrun? */ + dpc_sta[dpc_busy - 1] |= STA_OVR; + break; - case ioIAK: /* interrupt acknowledge */ - if (dp_ctype == A12557) /* 12557? */ - dpd_flagbuf = CLEAR; /* clear flag buffer */ - break; + case ioSIR: /* set interrupt request */ + if (dp_ctype == A12557) { /* 12557? */ + setstdPRL (dpd); /* set standard PRL signal */ + setstdIRQ (dpd); /* set standard IRQ signal */ + } + + setstdSRQ (dpd); /* set standard SRQ signal */ + break; - default: /* all other signals */ - break; /* are ignored */ + case ioIAK: /* interrupt acknowledge */ + if (dp_ctype == A12557) /* 12557? */ + dpd.flagbuf = CLEAR; /* clear flag buffer */ + break; + + + default: /* all other signals */ + break; /* are ignored */ + } + + working_set = working_set & ~signal; /* remove current signal from set */ } - -if (signal > ioCLF) /* multiple signals? */ - dpdio (select_code, ioCLF, 0); /* issue CLF */ -else if (signal > ioSIR) /* signal affected interrupt status? */ - dpdio (select_code, ioSIR, 0); /* set interrupt request */ - -return data; +return stat_data; } @@ -515,139 +525,144 @@ return data; to interrupt. */ -uint32 dpcio (uint32 select_code, IOSIG signal, uint32 data) +uint32 dpcio (DIB *dibptr, IOCYCLE signal_set, uint32 stat_data) { -const IOSIG base_signal = IOBASE (signal); /* derive base signal */ +uint16 data; int32 i, fnc, drv; +IOSIGNAL signal; +IOCYCLE working_set = IOADDSIR (signal_set); /* add ioSIR if needed */ -switch (base_signal) { /* dispatch base I/O signal */ +while (working_set) { + signal = IONEXT (working_set); /* isolate next signal */ - case ioCLF: /* clear flag flip-flop */ - dpc_flag = dpc_flagbuf = CLEAR; - break; + switch (signal) { /* dispatch I/O signal */ + + case ioCLF: /* clear flag flip-flop */ + dpc.flag = dpc.flagbuf = CLEAR; + break; - case ioSTF: /* set flag flip-flop */ - case ioENF: /* enable flag */ - dpc_flag = dpc_flagbuf = SET; - break; + case ioSTF: /* set flag flip-flop */ + case ioENF: /* enable flag */ + dpc.flag = dpc.flagbuf = SET; + break; - case ioSFC: /* skip if flag is clear */ - setstdSKF (dpc); - break; + case ioSFC: /* skip if flag is clear */ + setstdSKF (dpc); + break; - case ioSFS: /* skip if flag is set */ - setstdSKF (dpc); - break; + case ioSFS: /* skip if flag is set */ + setstdSKF (dpc); + break; - case ioIOI: /* I/O data input */ - data = 0; + case ioIOI: /* I/O data input */ + data = 0; - for (i = 0; i < DP_NUMDRV; i++) /* form attention register value */ - if (dpc_sta[i] & STA_ATN) data = data | (1 << i); - break; + for (i = 0; i < DP_NUMDRV; i++) /* form attention register value */ + if (dpc_sta[i] & STA_ATN) data = data | (1 << i); + + stat_data = IORETURN (SCPE_OK, data); /* merge in return status */ + break; - case ioIOO: /* I/O data output */ - dpc_obuf = data; + case ioIOO: /* I/O data output */ + dpc_obuf = IODATA (stat_data); /* clear supplied status */ - if (dp_ctype == A13210) /* 13210? */ - dpcio (select_code, ioCLC, 0); /* OTx causes CLC */ - break; + if (dp_ctype == A13210) /* 13210? */ + dpcio (dibptr, ioCLC, 0); /* OTx causes CLC */ + break; - case ioPOPIO: /* power-on preset to I/O */ - dpc_flag = dpc_flagbuf = SET; /* set flag buffer and flag */ + case ioPOPIO: /* power-on preset to I/O */ + dpc.flag = dpc.flagbuf = SET; /* set flag buffer and flag */ - if (dp_ctype == A12557) /* 12557? */ - dpd_obuf = 0; /* clear output buffer */ - /* fall into CRS handler */ - - case ioCRS: /* control reset */ - dpc_control = CLEAR; /* clear control */ - - if (dp_ctype == A12557) /* 12557? */ - dpc_command = CLEAR; /* clear command */ - break; - - - case ioCLC: /* clear control flip-flop */ - dpc_control = CLEAR; /* clr ctl */ - - if (dp_ctype == A12557) /* 12557? */ - dpc_command = CLEAR; /* cancel non-seek */ - - if (dpc_busy) - sim_cancel (&dpc_unit[dpc_busy - 1]); - - sim_cancel (&dpd_unit); /* cancel dch */ - dpd_xfer = 0; /* clr dch xfer */ - dpc_busy = 0; /* clr cch busy */ - dpc_poll = 0; /* clr cch poll */ - break; - - - case ioSTC: /* set control flip-flop */ - dpc_control = SET; /* set ctl */ - - if ((dp_ctype == A13210) || !dpc_command) { /* 13210 or command is clear? */ if (dp_ctype == A12557) /* 12557? */ - dpc_command = SET; /* set command */ - - drv = CW_GETDRV (dpc_obuf); /* get fnc, drv */ - fnc = CW_GETFNC (dpc_obuf); /* from cmd word */ - - switch (fnc) { /* case on fnc */ - - case FNC_SEEK: /* seek */ - dpc_poll = 1; /* enable polling */ - dp_god (fnc, drv, dpc_dtime); /* sched dch xfr */ - break; - - case FNC_STA: /* rd sta */ - if (dp_ctype == A13210) /* 13210? clr dch flag */ - dpdio (dpd_dib.devno, ioCLF, 0); - - case FNC_CHK: /* check */ - case FNC_AR: /* addr rec */ - dp_god (fnc, drv, dpc_dtime); /* sched dch xfr */ - break; - - case FNC_RD: case FNC_WD: /* read, write */ - case FNC_REF: case FNC_INIT: /* refine, init */ - dp_goc (fnc, drv, dpc_ctime); /* sched drive */ - break; - } /* end case */ - } /* end if */ - break; + dpd_obuf = 0; /* clear output buffer */ + break; - case ioSIR: /* set interrupt request */ - setstdPRL (select_code, dpc); /* set standard PRL signal */ - setstdIRQ (select_code, dpc); /* set standard IRQ signal */ - setstdSRQ (select_code, dpc); /* set standard SRQ signal */ - break; + case ioCRS: /* control reset */ + dpc.control = CLEAR; /* clear control */ + + if (dp_ctype == A12557) /* 12557? */ + dpc.command = CLEAR; /* clear command */ + break; - case ioIAK: /* interrupt acknowledge */ - dpc_flagbuf = CLEAR; /* clear flag buffer */ - break; + case ioCLC: /* clear control flip-flop */ + dpc.control = CLEAR; /* clr ctl */ + + if (dp_ctype == A12557) /* 12557? */ + dpc.command = CLEAR; /* cancel non-seek */ + + if (dpc_busy) + sim_cancel (&dpc_unit[dpc_busy - 1]); + + sim_cancel (&dpd_unit); /* cancel dch */ + dpd_xfer = 0; /* clr dch xfer */ + dpc_busy = 0; /* clr cch busy */ + dpc_poll = 0; /* clr cch poll */ + break; - default: /* all other signals */ - break; /* are ignored */ + case ioSTC: /* set control flip-flop */ + dpc.control = SET; /* set ctl */ + + if ((dp_ctype == A13210) || !dpc.command) { /* 13210 or command is clear? */ + if (dp_ctype == A12557) /* 12557? */ + dpc.command = SET; /* set command */ + + drv = CW_GETDRV (dpc_obuf); /* get fnc, drv */ + fnc = CW_GETFNC (dpc_obuf); /* from cmd word */ + + switch (fnc) { /* case on fnc */ + + case FNC_SEEK: /* seek */ + dpc_poll = 1; /* enable polling */ + dp_god (fnc, drv, dpc_dtime); /* sched dch xfr */ + break; + + case FNC_STA: /* rd sta */ + if (dp_ctype == A13210) /* 13210? clr dch flag */ + dpdio (&dpd_dib, ioCLF, 0); + + case FNC_CHK: /* check */ + case FNC_AR: /* addr rec */ + dp_god (fnc, drv, dpc_dtime); /* sched dch xfr */ + break; + + case FNC_RD: case FNC_WD: /* read, write */ + case FNC_REF: case FNC_INIT: /* refine, init */ + dp_goc (fnc, drv, dpc_ctime); /* sched drive */ + break; + } /* end case */ + } /* end if */ + break; + + + case ioSIR: /* set interrupt request */ + setstdPRL (dpc); /* set standard PRL signal */ + setstdIRQ (dpc); /* set standard IRQ signal */ + setstdSRQ (dpc); /* set standard SRQ signal */ + break; + + + case ioIAK: /* interrupt acknowledge */ + dpc.flagbuf = CLEAR; /* clear flag buffer */ + break; + + + default: /* all other signals */ + break; /* are ignored */ + } + + working_set = working_set & ~signal; /* remove current signal from set */ } - -if (signal > ioCLF) /* multiple signals? */ - dpcio (select_code, ioCLF, 0); /* issue CLF */ -else if (signal > ioSIR) /* signal affected interrupt status? */ - dpcio (select_code, ioSIR, 0); /* set interrupt request */ - -return data; +return stat_data; } @@ -712,12 +727,12 @@ switch (uptr->FNC) { /* case function */ case FNC_AR: /* arec, need cyl */ case FNC_SEEK: /* seek, need cyl */ - if (dpd_command) { /* dch active? */ + if (dpd.command) { /* dch active? */ dpc_rarc = DA_GETCYL (dpd_obuf); /* set RAR from cyl word */ dpd_wval = 0; /* clr data valid */ - dpd_command = CLEAR; /* clr dch cmd */ - dpdio (dpd_dib.devno, ioENF, 0); /* set dch flg */ + dpd.command = CLEAR; /* clr dch cmd */ + dpdio (&dpd_dib, ioENF, 0); /* set dch flg */ if (uptr->FNC == FNC_AR) uptr->FNC = FNC_AR1; else uptr->FNC = FNC_SEEK1; /* advance state */ @@ -727,17 +742,17 @@ switch (uptr->FNC) { /* case function */ case FNC_AR1: /* arec, need hd/sec */ case FNC_SEEK1: /* seek, need hd/sec */ - if (dpd_command) { /* dch active? */ + if (dpd.command) { /* dch active? */ dpc_rarh = DA_GETHD (dpd_obuf); /* set RAR from head */ dpc_rars = DA_GETSC (dpd_obuf); /* set RAR from sector */ dpd_wval = 0; /* clr data valid */ - dpd_command = CLEAR; /* clr dch cmd */ - dpdio (dpd_dib.devno, ioENF, 0); /* set dch flg */ + dpd.command = CLEAR; /* clr dch cmd */ + dpdio (&dpd_dib, ioENF, 0); /* set dch flg */ if (uptr->FNC == FNC_AR1) { - dpc_command = CLEAR; /* clr cch cmd */ - dpcio (dpc_dib.devno, ioENF, 0); /* set cch flg */ + dpc.command = CLEAR; /* clr cch cmd */ + dpcio (&dpc_dib, ioENF, 0); /* set cch flg */ dpc_sta[drv] = dpc_sta[drv] | STA_ATN; /* set drv attn */ break; /* done if Address Record */ @@ -766,7 +781,7 @@ switch (uptr->FNC) { /* case function */ break; case FNC_STA: /* read status */ - if (dpd_command || (dp_ctype == A13210)) { /* dch act or 13210? */ + if (dpd.command || (dp_ctype == A13210)) { /* dch act or 13210? */ if ((dpc_unit[drv].flags & UNIT_UNLOAD) == 0) { /* drive up? */ dpd_ibuf = dpc_sta[drv] & ~STA_ERR; /* clear err */ if (dp_ctype == A13210) dpd_ibuf = /* 13210? */ @@ -777,9 +792,9 @@ switch (uptr->FNC) { /* case function */ if (dpd_ibuf & STA_ANYERR) /* errors? set flg */ dpd_ibuf = dpd_ibuf | STA_ERR; - dpc_command = CLEAR; /* clr cch cmd */ - dpd_command = CLEAR; /* clr dch cmd */ - dpdio (dpd_dib.devno, ioENF, 0); /* set dch flg */ + dpc.command = CLEAR; /* clr cch cmd */ + dpd.command = CLEAR; /* clr dch cmd */ + dpdio (&dpd_dib, ioENF, 0); /* set dch flg */ } dpc_sta[drv] = dpc_sta[drv] & /* clr sta flags */ @@ -789,14 +804,14 @@ switch (uptr->FNC) { /* case function */ dpc_poll = 1; /* enable polling */ for (i = 0; i < DP_NUMDRV; i++) { /* loop thru drives */ if (dpc_sta[i] & STA_ATN) { /* any ATN set? */ - dpcio (dpc_dib.devno, ioENF, 0); /* set cch flg */ + dpcio (&dpc_dib, ioENF, 0); /* set cch flg */ break; } } break; case FNC_CHK: /* check, need cnt */ - if (dpd_command) { /* dch active? */ + if (dpd.command) { /* dch active? */ dpc_cnt = dpd_obuf & DA_CKMASK; /* get count */ dpd_wval = 0; /* clr data valid */ dp_goc (FNC_CHK1, drv, dpc_xtime); /* sched drv */ @@ -836,8 +851,8 @@ err = 0; /* assume no err */ drv = uptr - dpc_dev.units; /* get drive no */ if (uptr->flags & UNIT_UNLOAD) { /* drive down? */ - dpc_command = CLEAR; /* clr cch cmd */ - dpcio (dpc_dib.devno, ioENF, 0); /* set cch flg */ + dpc.command = CLEAR; /* clr cch cmd */ + dpcio (&dpc_dib, ioENF, 0); /* set cch flg */ dpc_sta[drv] = 0; /* clr status */ dpc_busy = 0; /* ctlr is free */ @@ -852,8 +867,8 @@ switch (uptr->FNC) { /* case function */ dpc_sta[drv] = (dpc_sta[drv] | STA_ATN) & ~STA_BSY; /* fall into cmpl */ case FNC_SEEK3: /* seek complete */ if (dpc_poll) { /* polling enabled? */ - dpc_command = CLEAR; /* clr cch cmd */ - dpcio (dpc_dib.devno, ioENF, 0); /* set cch flg */ + dpc.command = CLEAR; /* clr cch cmd */ + dpcio (&dpc_dib, ioENF, 0); /* set cch flg */ } return SCPE_OK; @@ -863,7 +878,7 @@ switch (uptr->FNC) { /* case function */ case FNC_RD: /* read */ case FNC_CHK1: /* check */ if (dp_ptr == 0) { /* new sector? */ - if (!dpd_command && (uptr->FNC != FNC_CHK1)) break; + if (!dpd.command && (uptr->FNC != FNC_CHK1)) break; if (dpc_rarc != dpc_ucyl[drv]) /* RAR cyl miscompare? */ dpc_sta[drv] = dpc_sta[drv] | STA_AER; /* set flag, read */ if (dpc_rars >= DP_NUMSC) { /* bad sector? */ @@ -893,17 +908,17 @@ switch (uptr->FNC) { /* case function */ } dp_ptr = 0; /* wrap buf ptr */ } - if (dpd_command && dpd_xfer) /* dch on, xfer? */ - dpdio (dpd_dib.devno, ioENF, 0); /* set dch flg */ + if (dpd.command && dpd_xfer) /* dch on, xfer? */ + dpdio (&dpd_dib, ioENF, 0); /* set dch flg */ - dpd_command = CLEAR; /* clr dch cmd */ + dpd.command = CLEAR; /* clr dch cmd */ sim_activate (uptr, dpc_xtime); /* sched next word */ return SCPE_OK; case FNC_INIT: /* init */ case FNC_WD: /* write */ if (dp_ptr == 0) { /* start sector? */ - if (!dpd_command && !dpd_wval) break; /* xfer done? */ + if (!dpd.command && !dpd_wval) break; /* xfer done? */ if (uptr->flags & UNIT_WPRT) { /* wr prot? */ dpc_sta[drv] = dpc_sta[drv] | STA_FLG; /* set status */ break; /* done */ @@ -933,10 +948,10 @@ switch (uptr->FNC) { /* case function */ if (err = ferror (uptr->fileref)) break; /* error? */ dp_ptr = 0; /* next sector */ } - if (dpd_command && dpd_xfer) /* dch on, xfer? */ - dpdio (dpd_dib.devno, ioENF, 0); /* set dch flg */ + if (dpd.command && dpd_xfer) /* dch on, xfer? */ + dpdio (&dpd_dib, ioENF, 0); /* set dch flg */ - dpd_command = CLEAR; /* clr dch cmd */ + dpd.command = CLEAR; /* clr dch cmd */ sim_activate (uptr, dpc_xtime); /* sched next word */ return SCPE_OK; @@ -946,8 +961,8 @@ switch (uptr->FNC) { /* case function */ dpc_sta[drv] = dpc_sta[drv] | STA_ATN; /* set ATN */ -dpc_command = CLEAR; /* clr cch cmd */ -dpcio (dpc_dib.devno, ioENF, 0); /* set cch flg */ +dpc.command = CLEAR; /* clr cch cmd */ +dpcio (&dpc_dib, ioENF, 0); /* set cch flg */ dpc_busy = 0; /* ctlr is free */ dpd_xfer = dpd_wval = 0; @@ -966,21 +981,18 @@ return SCPE_OK; t_stat dpc_reset (DEVICE *dptr) { int32 drv; +DIB *dibptr = (DIB *) dptr->ctxt; /* DIB pointer */ hp_enbdis_pair (dptr, /* make pair cons */ - (dptr == &dpd_dev)? &dpc_dev: &dpd_dev); + (dptr == &dpd_dev) ? &dpc_dev : &dpd_dev); -if (sim_switches & SWMASK ('P')) { /* PON reset? */ - dpd_ibuf = 0; /* clear buffers */ - dpd_obuf = 0; - dpc_obuf = 0; +if (sim_switches & SWMASK ('P')) { /* initialization reset? */ + dpd_ibuf = dpd_obuf = 0; /* clear buffers */ + dpc_obuf = 0; /* clear buffer */ dpc_rarc = dpc_rarh = dpc_rars = 0; /* clear RAR */ } -if (dptr == &dpc_dev) /* command channel reset? */ - dpcio (dpc_dib.devno, ioPOPIO, 0); /* send POPIO signal to command channel */ -else /* data channel reset */ - dpdio (dpd_dib.devno, ioPOPIO, 0); /* send POPIO signal to data channel */ +IOPRESET (dibptr); /* PRESET device (does not use PON) */ dpc_busy = 0; /* reset controller state */ dpc_poll = 0; @@ -1040,7 +1052,7 @@ else { /* load heads */ drv = uptr - dpc_dev.units; /* get drive no */ dpc_sta[drv] = dpc_sta[drv] | STA_ATN | STA_1ST; /* update status */ if (dpc_poll) /* polling enabled? */ - dpcio (dpc_dib.devno, ioENF, 0); /* set flag */ + dpcio (&dpc_dib, ioENF, 0); /* set flag */ } return SCPE_OK; } @@ -1144,7 +1156,7 @@ t_stat dpc_boot (int32 unitno, DEVICE *dptr) int32 dev; if (unitno != 0) return SCPE_NOFNC; /* only unit 0 */ -dev = dpd_dib.devno; /* get data chan dev */ +dev = dpd_dib.select_code; /* get data chan dev */ if (ibl_copy (dp_rom, dev)) return SCPE_IERR; /* copy boot to memory */ SR = (SR & IBL_OPT) | IBL_DP | (dev << IBL_V_DEV); /* set SR */ if (sim_switches & SWMASK ('R')) SR = SR | IBL_DP_REM; /* boot from removable? */ diff --git a/HP2100/hp2100_dq.c b/HP2100/hp2100_dq.c index 216dfc03..726aa4ba 100644 --- a/HP2100/hp2100_dq.c +++ b/HP2100/hp2100_dq.c @@ -1,7 +1,7 @@ /* hp2100_dq.c: HP 2100 12565A disk simulator Copyright (c) 1993-2006, Bill McDermith - Copyright (c) 2004-2008 J. David Bryan + Copyright (c) 2004-2011 J. David Bryan Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), @@ -26,6 +26,8 @@ DQ 12565A 2883 disk system + 28-Mar-11 JDB Tidied up signal handling + 26-Oct-10 JDB Changed I/O signal handler for revised signal model 10-Aug-08 JDB Added REG_FIT to register variables < 32-bit size 26-Jun-08 JDB Rewrote device I/O to model backplane signals 28-Dec-06 JDB Added ioCRS state to I/O decoders @@ -144,10 +146,12 @@ #define STA_ERR 0000001 /* any error */ #define STA_ANYERR (STA_NRDY | STA_EOC | STA_AER | STA_FLG | STA_DTE) -FLIP_FLOP dqc_command = CLEAR; /* cch command flip-flop */ -FLIP_FLOP dqc_control = CLEAR; /* cch control flip-flop */ -FLIP_FLOP dqc_flag = CLEAR; /* cch flag flip-flop */ -FLIP_FLOP dqc_flagbuf = CLEAR; /* cch flag buffer flip-flop */ +struct { + FLIP_FLOP command; /* cch command flip-flop */ + FLIP_FLOP control; /* cch control flip-flop */ + FLIP_FLOP flag; /* cch flag flip-flop */ + FLIP_FLOP flagbuf; /* cch flag buffer flip-flop */ + } dqc = { CLEAR, CLEAR, CLEAR, CLEAR }; int32 dqc_busy = 0; /* cch xfer */ int32 dqc_cnt = 0; /* check count */ @@ -156,10 +160,12 @@ int32 dqc_ctime = 100; /* command time */ int32 dqc_xtime = 3; /* xfer time */ int32 dqc_dtime = 2; /* dch time */ -FLIP_FLOP dqd_command = CLEAR; /* dch command flip-flop */ -FLIP_FLOP dqd_control = CLEAR; /* dch control flip-flop */ -FLIP_FLOP dqd_flag = CLEAR; /* dch flag flip-flop */ -FLIP_FLOP dqd_flagbuf = CLEAR; /* dch flag buffer flip-flop */ +struct { + FLIP_FLOP command; /* dch command flip-flop */ + FLIP_FLOP control; /* dch control flip-flop */ + FLIP_FLOP flag; /* dch flag flip-flop */ + FLIP_FLOP flagbuf; /* dch flag buffer flip-flop */ + } dqd = { CLEAR, CLEAR, CLEAR, CLEAR }; int32 dqd_obuf = 0, dqd_ibuf = 0; /* dch buffers */ int32 dqc_obuf = 0; /* cch buffers */ @@ -175,8 +181,10 @@ uint16 dqc_sta[DQ_NUMDRV] = { 0 }; /* unit status */ uint16 dqxb[DQ_NUMWD]; /* sector buffer */ DEVICE dqd_dev, dqc_dev; -uint32 dqdio (uint32 select_code, IOSIG signal, uint32 data); -uint32 dqcio (uint32 select_code, IOSIG signal, uint32 data); + +IOHANDLER dqdio; +IOHANDLER dqcio; + t_stat dqc_svc (UNIT *uptr); t_stat dqd_svc (UNIT *uptr); t_stat dqc_reset (DEVICE *dptr); @@ -195,8 +203,8 @@ void dq_goc (int32 fnc, int32 drv, int32 time); */ DIB dq_dib[] = { - { DQD, &dqdio }, - { DQC, &dqcio } + { &dqdio, DQD }, + { &dqcio, DQC } }; #define dqd_dib dq_dib[0] @@ -209,13 +217,13 @@ REG dqd_reg[] = { { ORDATA (OBUF, dqd_obuf, 16) }, { BRDATA (DBUF, dqxb, 8, 16, DQ_NUMWD) }, { DRDATA (BPTR, dq_ptr, DQ_N_NUMWD) }, - { FLDATA (CMD, dqd_command, 0) }, - { FLDATA (CTL, dqd_control, 0) }, - { FLDATA (FLG, dqd_flag, 0) }, - { FLDATA (FBF, dqd_flagbuf, 0) }, + { FLDATA (CMD, dqd.command, 0) }, + { FLDATA (CTL, dqd.control, 0) }, + { FLDATA (FLG, dqd.flag, 0) }, + { FLDATA (FBF, dqd.flagbuf, 0) }, { FLDATA (XFER, dqd_xfer, 0) }, { FLDATA (WVAL, dqd_wval, 0) }, - { ORDATA (DEVNO, dqd_dib.devno, 6), REG_HRO }, + { ORDATA (DEVNO, dqd_dib.select_code, 6), REG_HRO }, { NULL } }; @@ -252,10 +260,10 @@ REG dqc_reg[] = { { ORDATA (OBUF, dqc_obuf, 16) }, { ORDATA (BUSY, dqc_busy, 2), REG_RO }, { ORDATA (CNT, dqc_cnt, 9) }, - { FLDATA (CMD, dqc_command, 0) }, - { FLDATA (CTL, dqc_control, 0) }, - { FLDATA (FLG, dqc_flag, 0) }, - { FLDATA (FBF, dqc_flagbuf, 0) }, + { FLDATA (CMD, dqc.command, 0) }, + { FLDATA (CTL, dqc.control, 0) }, + { FLDATA (FLG, dqc.flag, 0) }, + { FLDATA (FBF, dqc.flagbuf, 0) }, { DRDATA (RARC, dqc_rarc, 8), PV_RZRO | REG_FIT }, { DRDATA (RARH, dqc_rarh, 5), PV_RZRO | REG_FIT }, { DRDATA (RARS, dqc_rars, 5), PV_RZRO | REG_FIT }, @@ -268,7 +276,7 @@ REG dqc_reg[] = { { DRDATA (XTIME, dqc_xtime, 24), REG_NZ + PV_LEFT }, { URDATA (UFNC, dqc_unit[0].FNC, 8, 8, 0, DQ_NUMDRV, REG_HRO) }, - { ORDATA (DEVNO, dqc_dib.devno, 6), REG_HRO }, + { ORDATA (DEVNO, dqc_dib.select_code, 6), REG_HRO }, { NULL } }; @@ -293,93 +301,95 @@ DEVICE dqc_dev = { /* Data channel I/O signal handler */ -uint32 dqdio (uint32 select_code, IOSIG signal, uint32 data) +uint32 dqdio (DIB *dibptr, IOCYCLE signal_set, uint32 stat_data) { -const IOSIG base_signal = IOBASE (signal); /* derive base signal */ +IOSIGNAL signal; +IOCYCLE working_set = IOADDSIR (signal_set); /* add ioSIR if needed */ -switch (base_signal) { /* dispatch base I/O signal */ +while (working_set) { + signal = IONEXT (working_set); /* isolate next signal */ - case ioCLF: /* clear flag flip-flop */ - dqd_flag = dqd_flagbuf = CLEAR; - break; + switch (signal) { /* dispatch I/O signal */ + + case ioCLF: /* clear flag flip-flop */ + dqd.flag = dqd.flagbuf = CLEAR; + break; - case ioSTF: /* set flag flip-flop */ - case ioENF: /* enable flag */ - dqd_flag = dqd_flagbuf = SET; - break; + case ioSTF: /* set flag flip-flop */ + case ioENF: /* enable flag */ + dqd.flag = dqd.flagbuf = SET; + break; - case ioSFC: /* skip if flag is clear */ - setstdSKF (dqd); - break; + case ioSFC: /* skip if flag is clear */ + setstdSKF (dqd); + break; - case ioSFS: /* skip if flag is set */ - setstdSKF (dqd); - break; + case ioSFS: /* skip if flag is set */ + setstdSKF (dqd); + break; - case ioIOI: /* I/O data input */ - data = dqd_ibuf; - break; + case ioIOI: /* I/O data input */ + stat_data = IORETURN (SCPE_OK, dqd_ibuf); /* merge in return status */ + break; - case ioIOO: /* I/O data output */ - dqd_obuf = data; + case ioIOO: /* I/O data output */ + dqd_obuf = IODATA (stat_data); /* clear supplied status */ - if (!dqc_busy || dqd_xfer) - dqd_wval = 1; /* if !overrun, valid */ - break; + if (!dqc_busy || dqd_xfer) + dqd_wval = 1; /* if !overrun, valid */ + break; - case ioPOPIO: /* power-on preset to I/O */ - dqd_flag = dqd_flagbuf = SET; /* set flag and flag buffer */ - dqd_obuf = 0; /* clear output buffer */ - /* fall into CRS handler */ + case ioPOPIO: /* power-on preset to I/O */ + dqd.flag = dqd.flagbuf = SET; /* set flag and flag buffer */ + dqd_obuf = 0; /* clear output buffer */ + break; - case ioCRS: /* control reset */ - dqd_command = CLEAR; /* clear command */ + + case ioCRS: /* control reset */ + dqd.command = CLEAR; /* clear command */ /* fall into CLC handler */ - case ioCLC: /* clear control flip-flop */ - dqd_control = CLEAR; /* clear control */ - dqd_xfer = 0; /* clr xfer */ - break; + case ioCLC: /* clear control flip-flop */ + dqd.control = CLEAR; /* clear control */ + dqd_xfer = 0; /* clr xfer */ + break; - case ioSTC: /* set control flip-flop */ - dqd_command = SET; /* set ctl, cmd */ - dqd_control = SET; + case ioSTC: /* set control flip-flop */ + dqd.command = SET; /* set ctl, cmd */ + dqd.control = SET; - if (dqc_busy && !dqd_xfer) /* overrun? */ - dqc_sta[dqc_busy - 1] |= STA_DTE; - break; + if (dqc_busy && !dqd_xfer) /* overrun? */ + dqc_sta[dqc_busy - 1] |= STA_DTE; + break; - case ioSIR: /* set interrupt request */ - setstdPRL (select_code, dqd); /* set standard PRL signal */ - setstdIRQ (select_code, dqd); /* set standard IRQ signal */ - setstdSRQ (select_code, dqd); /* set standard SRQ signal */ - break; + case ioSIR: /* set interrupt request */ + setstdPRL (dqd); /* set standard PRL signal */ + setstdIRQ (dqd); /* set standard IRQ signal */ + setstdSRQ (dqd); /* set standard SRQ signal */ + break; - case ioIAK: /* interrupt acknowledge */ - dqd_flagbuf = CLEAR; - break; + case ioIAK: /* interrupt acknowledge */ + dqd.flagbuf = CLEAR; + break; - default: /* all other signals */ - break; /* are ignored */ + default: /* all other signals */ + break; /* are ignored */ + } + + working_set = working_set & ~signal; /* remove current signal from set */ } - -if (signal > ioCLF) /* multiple signals? */ - dqdio (select_code, ioCLF, 0); /* issue CLF */ -else if (signal > ioSIR) /* signal affected interrupt status? */ - dqdio (select_code, ioSIR, 0); /* set interrupt request */ - -return data; +return stat_data; } @@ -392,113 +402,112 @@ return data; signalled. */ -uint32 dqcio (uint32 select_code, IOSIG signal, uint32 data) +uint32 dqcio (DIB *dibptr, IOCYCLE signal_set, uint32 stat_data) { -const IOSIG base_signal = IOBASE (signal); /* derive base signal */ int32 fnc, drv; +IOSIGNAL signal; +IOCYCLE working_set = IOADDSIR (signal_set); /* add ioSIR if needed */ -switch (base_signal) { /* dispatch base I/O signal */ +while (working_set) { + signal = IONEXT (working_set); /* isolate next signal */ - case ioCLF: /* clear flag flip-flop */ - dqc_flag = dqc_flagbuf = CLEAR; - break; + switch (signal) { /* dispatch I/O signal */ + + case ioCLF: /* clear flag flip-flop */ + dqc.flag = dqc.flagbuf = CLEAR; + break; - case ioSTF: /* set flag flip-flop */ - case ioENF: /* enable flag */ - dqc_flag = dqc_flagbuf = SET; - break; + case ioSTF: /* set flag flip-flop */ + case ioENF: /* enable flag */ + dqc.flag = dqc.flagbuf = SET; + break; - case ioSFC: /* skip if flag is clear */ - setstdSKF (dqc); - break; + case ioSFC: /* skip if flag is clear */ + setstdSKF (dqc); + break; - case ioSFS: /* skip if flag is set */ - setstdSKF (dqc); - break; + case ioSFS: /* skip if flag is set */ + setstdSKF (dqc); + break; - case ioIOI: /* I/O data input */ - data = 0; /* no data */ - break; + case ioIOI: /* I/O data input */ + stat_data = IORETURN (SCPE_OK, 0); /* no data */ + break; - case ioIOO: /* I/O data output */ - dqc_obuf = data; - break; + case ioIOO: /* I/O data output */ + dqc_obuf = IODATA (stat_data); /* clear supplied status */ + break; - case ioPOPIO: /* power-on preset to I/O */ - dqc_flag = dqc_flagbuf = SET; /* set flag and flag buffer */ - dqc_obuf = 0; /* clear output buffer */ - /* fall into CRS handler */ - - case ioCRS: /* control reset */ - /* fall into CLC handler */ - - case ioCLC: /* clear control flip-flop */ - dqc_command = CLEAR; /* clear command */ - dqc_control = CLEAR; /* clear control */ - - if (dqc_busy) - sim_cancel (&dqc_unit[dqc_busy - 1]); - - sim_cancel (&dqd_unit); /* cancel dch */ - dqd_xfer = 0; /* clr dch xfer */ - dqc_busy = 0; /* clr busy */ - break; + case ioPOPIO: /* power-on preset to I/O */ + dqc.flag = dqc.flagbuf = SET; /* set flag and flag buffer */ + dqc_obuf = 0; /* clear output buffer */ + break; - case ioSTC: /* set control flip-flop */ - dqc_control = SET; /* set ctl */ + case ioCRS: /* control reset */ + case ioCLC: /* clear control flip-flop */ + dqc.command = CLEAR; /* clear command */ + dqc.control = CLEAR; /* clear control */ - if (!dqc_command) { /* cmd clr? */ - dqc_command = SET; /* set cmd */ - drv = CW_GETDRV (dqc_obuf); /* get fnc, drv */ - fnc = CW_GETFNC (dqc_obuf); /* from cmd word */ + if (dqc_busy) + sim_cancel (&dqc_unit[dqc_busy - 1]); - switch (fnc) { /* case on fnc */ - case FNC_SEEK: case FNC_RCL: /* seek, recal */ - case FNC_CHK: /* check */ - dqc_sta[drv] = 0; /* clear status */ - case FNC_STA: case FNC_LA: /* rd sta, load addr */ - dq_god (fnc, drv, dqc_dtime); /* sched dch xfer */ - break; - case FNC_RD: case FNC_WD: /* read, write */ - case FNC_RA: case FNC_WA: /* rd addr, wr addr */ - case FNC_AS: /* address skip */ - dq_goc (fnc, drv, dqc_ctime); /* sched drive */ - break; - } /* end case */ - } /* end if !CMD */ - break; + sim_cancel (&dqd_unit); /* cancel dch */ + dqd_xfer = 0; /* clr dch xfer */ + dqc_busy = 0; /* clr busy */ + break; - case ioSIR: /* set interrupt request */ - setstdPRL (select_code, dqc); /* set standard PRL signal */ - setstdIRQ (select_code, dqc); /* set standard IRQ signal */ - setstdSRQ (select_code, dqc); /* set standard SRQ signal */ - break; + case ioSTC: /* set control flip-flop */ + dqc.control = SET; /* set ctl */ + + if (!dqc.command) { /* cmd clr? */ + dqc.command = SET; /* set cmd */ + drv = CW_GETDRV (dqc_obuf); /* get fnc, drv */ + fnc = CW_GETFNC (dqc_obuf); /* from cmd word */ + + switch (fnc) { /* case on fnc */ + case FNC_SEEK: case FNC_RCL: /* seek, recal */ + case FNC_CHK: /* check */ + dqc_sta[drv] = 0; /* clear status */ + case FNC_STA: case FNC_LA: /* rd sta, load addr */ + dq_god (fnc, drv, dqc_dtime); /* sched dch xfer */ + break; + case FNC_RD: case FNC_WD: /* read, write */ + case FNC_RA: case FNC_WA: /* rd addr, wr addr */ + case FNC_AS: /* address skip */ + dq_goc (fnc, drv, dqc_ctime); /* sched drive */ + break; + } /* end case */ + } /* end if !CMD */ + break; - case ioIAK: /* interrupt acknowledge */ - dqc_flagbuf = CLEAR; - break; + case ioSIR: /* set interrupt request */ + setstdPRL (dqc); /* set standard PRL signal */ + setstdIRQ (dqc); /* set standard IRQ signal */ + setstdSRQ (dqc); /* set standard SRQ signal */ + break; - default: /* all other signals */ - break; /* are ignored */ + case ioIAK: /* interrupt acknowledge */ + dqc.flagbuf = CLEAR; + break; + + + default: /* all other signals */ + break; /* are ignored */ + } + + working_set = working_set & ~signal; /* remove current signal from set */ } - - -if (signal > ioCLF) /* multiple signals? */ - dqcio (select_code, ioCLF, 0); /* issue CLF */ -else if (signal > ioSIR) /* signal affected interrupt status? */ - dqcio (select_code, ioSIR, 0); /* set interrupt request */ - -return data; +return stat_data; } @@ -562,11 +571,11 @@ switch (uptr->FNC) { /* case function */ case FNC_LA: /* arec, need cyl */ case FNC_SEEK: /* seek, need cyl */ - if (dqd_command) { /* dch active? */ + if (dqd.command) { /* dch active? */ dqc_rarc = DA_GETCYL (dqd_obuf); /* set RAR from cyl word */ dqd_wval = 0; /* clr data valid */ - dqd_command = CLEAR; /* clr dch cmd */ - dqdio (dqd_dib.devno, ioENF, 0); /* set dch flg */ + dqd.command = CLEAR; /* clr dch cmd */ + dqdio (&dqd_dib, ioENF, 0); /* set dch flg */ if (uptr->FNC == FNC_LA) uptr->FNC = FNC_LA1; else uptr->FNC = FNC_SEEK1; /* advance state */ } @@ -575,15 +584,15 @@ switch (uptr->FNC) { /* case function */ case FNC_LA1: /* arec, need hd/sec */ case FNC_SEEK1: /* seek, need hd/sec */ - if (dqd_command) { /* dch active? */ + if (dqd.command) { /* dch active? */ dqc_rarh = DA_GETHD (dqd_obuf); /* set RAR from head */ dqc_rars = DA_GETSC (dqd_obuf); /* set RAR from sector */ dqd_wval = 0; /* clr data valid */ - dqd_command = CLEAR; /* clr dch cmd */ - dqdio (dqd_dib.devno, ioENF, 0); /* set dch flg */ + dqd.command = CLEAR; /* clr dch cmd */ + dqdio (&dqd_dib, ioENF, 0); /* set dch flg */ if (uptr->FNC == FNC_LA1) { - dqc_command = CLEAR; /* clr cch cmd */ - dqcio (dqc_dib.devno, ioENF, 0); /* set cch flg */ + dqc.command = CLEAR; /* clr cch cmd */ + dqcio (&dqc_dib, ioENF, 0); /* set cch flg */ break; /* done if Load Address */ } if (sim_is_active (&dqc_unit[drv])) break; /* if busy, seek check */ @@ -610,23 +619,23 @@ switch (uptr->FNC) { /* case function */ break; case FNC_STA: /* read status */ - if (dqd_command) { /* dch active? */ + if (dqd.command) { /* dch active? */ if ((dqc_unit[drv].flags & UNIT_UNLOAD) == 0) /* drive up? */ dqd_ibuf = dqc_sta[drv] & ~STA_DID; else dqd_ibuf = STA_NRDY; if (dqd_ibuf & STA_ANYERR) /* errors? set flg */ dqd_ibuf = dqd_ibuf | STA_ERR; if (drv) dqd_ibuf = dqd_ibuf | STA_DID; - dqc_command = CLEAR; /* clr cch cmd */ - dqd_command = CLEAR; /* clr dch cmd */ - dqdio (dqd_dib.devno, ioENF, 0); /* set dch flg */ + dqc.command = CLEAR; /* clr cch cmd */ + dqd.command = CLEAR; /* clr dch cmd */ + dqdio (&dqd_dib, ioENF, 0); /* set dch flg */ dqc_sta[drv] = dqc_sta[drv] & ~STA_ANYERR; /* clr sta flags */ } else sim_activate (uptr, dqc_xtime); /* wait more */ break; case FNC_CHK: /* check, need cnt */ - if (dqd_command) { /* dch active? */ + if (dqd.command) { /* dch active? */ dqc_cnt = dqd_obuf & DA_CKMASK; /* get count */ dqd_wval = 0; /* clr data valid */ dq_goc (FNC_CHK1, drv, dqc_ctime); /* sched drv */ @@ -663,15 +672,13 @@ return SCPE_OK; t_stat dqc_svc (UNIT *uptr) { -int32 da, drv, devc, devd, err; +int32 da, drv, err; err = 0; /* assume no err */ drv = uptr - dqc_dev.units; /* get drive no */ -devc = dqc_dib.devno; /* get cch devno */ -devd = dqd_dib.devno; /* get dch devno */ if (uptr->flags & UNIT_UNLOAD) { /* drive down? */ - dqc_command = CLEAR; /* clr cch cmd */ - dqcio (dqc_dib.devno, ioENF, 0); /* set cch flg */ + dqc.command = CLEAR; /* clr cch cmd */ + dqcio (&dqc_dib, ioENF, 0); /* set cch flg */ dqc_sta[drv] = 0; /* clr status */ dqc_busy = 0; /* ctlr is free */ dqd_xfer = dqd_wval = 0; @@ -686,18 +693,18 @@ switch (uptr->FNC) { /* case function */ } else dqc_sta[drv] = dqc_sta[drv] & ~STA_BSY; /* drive not busy */ case FNC_SEEK3: - if (dqc_busy || dqc_flag) { /* ctrl busy? */ + if (dqc_busy || dqc.flag) { /* ctrl busy? */ uptr->FNC = FNC_SEEK3; /* next state */ sim_activate (uptr, dqc_xtime); /* ctrl busy? wait */ } else { - dqc_command = CLEAR; /* clr cch cmd */ - dqcio (dqc_dib.devno, ioENF, 0); /* set cch flg */ + dqc.command = CLEAR; /* clr cch cmd */ + dqcio (&dqc_dib, ioENF, 0); /* set cch flg */ } return SCPE_OK; case FNC_RA: /* read addr */ - if (!dqd_command) break; /* dch clr? done */ + if (!dqd.command) break; /* dch clr? done */ if (dq_ptr == 0) dqd_ibuf = dqc_ucyl[drv]; /* 1st word? */ else if (dq_ptr == 1) { /* second word? */ dqd_ibuf = (dqc_uhed[drv] << DA_V_HD) | /* use drive head */ @@ -706,8 +713,8 @@ switch (uptr->FNC) { /* case function */ } else break; dq_ptr = dq_ptr + 1; - dqd_command = CLEAR; /* clr dch cmd */ - dqdio (dqd_dib.devno, ioENF, 0); /* set dch flg */ + dqd.command = CLEAR; /* clr dch cmd */ + dqdio (&dqd_dib, ioENF, 0); /* set dch flg */ sim_activate (uptr, dqc_xtime); /* sched next word */ return SCPE_OK; @@ -715,7 +722,7 @@ switch (uptr->FNC) { /* case function */ case FNC_RD: /* read */ case FNC_CHK1: /* check */ if (dq_ptr == 0) { /* new sector? */ - if (!dqd_command && (uptr->FNC != FNC_CHK1)) break; + if (!dqd.command && (uptr->FNC != FNC_CHK1)) break; if ((dqc_rarc != dqc_ucyl[drv]) || /* RAR cyl miscompare? */ (dqc_rarh != dqc_uhed[drv]) || /* RAR head miscompare? */ (dqc_rars >= DQ_NUMSC)) { /* bad sector? */ @@ -743,17 +750,17 @@ switch (uptr->FNC) { /* case function */ } dq_ptr = 0; /* wrap buf ptr */ } - if (dqd_command && dqd_xfer) { /* dch on, xfer? */ - dqdio (dqd_dib.devno, ioENF, 0); /* set flag */ + if (dqd.command && dqd_xfer) { /* dch on, xfer? */ + dqdio (&dqd_dib, ioENF, 0); /* set flag */ } - dqd_command = CLEAR; /* clr dch cmd */ + dqd.command = CLEAR; /* clr dch cmd */ sim_activate (uptr, dqc_xtime); /* sched next word */ return SCPE_OK; case FNC_WA: /* write address */ case FNC_WD: /* write */ if (dq_ptr == 0) { /* sector start? */ - if (!dqd_command && !dqd_wval) break; /* xfer done? */ + if (!dqd.command && !dqd_wval) break; /* xfer done? */ if (uptr->flags & UNIT_WPRT) { /* write protect? */ dqc_sta[drv] = dqc_sta[drv] | STA_FLG; break; /* done */ @@ -782,10 +789,10 @@ switch (uptr->FNC) { /* case function */ if (err = ferror (uptr->fileref)) break; dq_ptr = 0; } - if (dqd_command && dqd_xfer) { /* dch on, xfer? */ - dqdio (dqd_dib.devno, ioENF, 0); /* set flag */ + if (dqd.command && dqd_xfer) { /* dch on, xfer? */ + dqdio (&dqd_dib, ioENF, 0); /* set flag */ } - dqd_command = CLEAR; /* clr dch cmd */ + dqd.command = CLEAR; /* clr dch cmd */ sim_activate (uptr, dqc_xtime); /* sched next word */ return SCPE_OK; @@ -793,8 +800,8 @@ switch (uptr->FNC) { /* case function */ return SCPE_IERR; } /* end case fnc */ -dqc_command = CLEAR; /* clr cch cmd */ -dqcio (dqc_dib.devno, ioENF, 0); /* set cch flg */ +dqc.command = CLEAR; /* clr cch cmd */ +dqcio (&dqc_dib, ioENF, 0); /* set cch flg */ dqc_busy = 0; /* ctlr is free */ dqd_xfer = dqd_wval = 0; if (err != 0) { /* error? */ @@ -810,21 +817,19 @@ return SCPE_OK; t_stat dqc_reset (DEVICE *dptr) { int32 drv; +DIB *dibptr = (DIB *) dptr->ctxt; /* DIB pointer */ hp_enbdis_pair (dptr, /* make pair cons */ (dptr == &dqd_dev)? &dqc_dev: &dqd_dev); -if (sim_switches & SWMASK ('P')) { /* PON reset? */ +if (sim_switches & SWMASK ('P')) { /* initialization reset? */ dqd_ibuf = 0; /* clear buffers */ dqd_obuf = 0; - dqc_obuf = 0; + dqc_obuf = 0; /* clear buffer */ dqc_rarc = dqc_rarh = dqc_rars = 0; /* clear RAR */ } -if (dptr == &dqc_dev) /* command channel reset? */ - dqcio (dqc_dib.devno, ioPOPIO, 0); /* send POPIO signal to command channel */ -else /* data channel reset */ - dqdio (dqd_dib.devno, ioPOPIO, 0); /* send POPIO signal to data channel */ +IOPRESET (dibptr); /* PRESET device (does not use PON) */ dqc_busy = 0; /* reset controller state */ dqd_xfer = 0; @@ -947,7 +952,7 @@ t_stat dqc_boot (int32 unitno, DEVICE *dptr) int32 dev; if (unitno != 0) return SCPE_NOFNC; /* only unit 0 */ -dev = dqd_dib.devno; /* get data chan dev */ +dev = dqd_dib.select_code; /* get data chan dev */ if (ibl_copy (dq_rom, dev)) return SCPE_IERR; /* copy boot to memory */ SR = (SR & IBL_OPT) | IBL_DQ | (dev << IBL_V_DEV); /* set SR */ return SCPE_OK; diff --git a/HP2100/hp2100_dr.c b/HP2100/hp2100_dr.c index d8af0a68..1ae61f6a 100644 --- a/HP2100/hp2100_dr.c +++ b/HP2100/hp2100_dr.c @@ -1,6 +1,6 @@ /* hp2100_dr.c: HP 2100 12606B/12610B fixed head disk/drum simulator - Copyright (c) 1993-2008, Robert M. Supnik + Copyright (c) 1993-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"), @@ -26,6 +26,8 @@ DR 12606B 2770/2771 fixed head disk 12610B 2773/2774/2775 drum + 28-Mar-11 JDB Tidied up signal handling + 26-Oct-10 JDB Changed I/O signal handler for revised signal model 09-Jul-08 JDB Revised drc_boot to use ibl_copy 26-Jun-08 JDB Rewrote device I/O to model backplane signals 28-Dec-06 JDB Added ioCRS state to I/O decoders @@ -178,8 +180,10 @@ int32 drc_cw = 0; /* fnc, addr */ int32 drc_sta = 0; /* status */ int32 drc_run = 0; /* run flip-flop */ -FLIP_FLOP drd_control = CLEAR; -FLIP_FLOP drd_flag = CLEAR; +struct { + FLIP_FLOP control; /* control flip-flop */ + FLIP_FLOP flag; /* flag flip-flop */ + } drd = { CLEAR, CLEAR }; int32 drd_ibuf = 0; /* input buffer */ int32 drd_obuf = 0; /* output buffer */ @@ -192,9 +196,9 @@ static int32 sz_tab[16] = { 184320, 1048576, 368640, 1572864, 737280, 393216, 0, 524288, 0, 655360, 0, 786432, 0, 917504, 0, 0 }; -DEVICE drd_dev, drc_dev; -uint32 drdio (uint32 select_code, IOSIG signal, uint32 data); -uint32 drcio (uint32 select_code, IOSIG signal, uint32 data); +IOHANDLER drdio; +IOHANDLER drcio; + t_stat drc_svc (UNIT *uptr); t_stat drc_reset (DEVICE *dptr); t_stat drc_attach (UNIT *uptr, char *cptr); @@ -205,6 +209,8 @@ t_stat dr_set_prot (UNIT *uptr, int32 val, char *cptr, void *desc); t_stat dr_show_prot (FILE *st, UNIT *uptr, int32 val, void *desc); t_stat dr_set_size (UNIT *uptr, int32 val, char *cptr, void *desc); +DEVICE drd_dev, drc_dev; + /* DRD data structures drd_dev device descriptor @@ -213,8 +219,8 @@ t_stat dr_set_size (UNIT *uptr, int32 val, char *cptr, void *desc); */ DIB dr_dib[] = { - { DRD, &drdio }, - { DRC, &drcio } + { &drdio, DRD }, + { &drcio, DRC } }; #define drd_dib dr_dib[0] @@ -231,10 +237,10 @@ UNIT drd_unit[] = { REG drd_reg[] = { { ORDATA (IBUF, drd_ibuf, 16) }, { ORDATA (OBUF, drd_obuf, 16) }, - { FLDATA (CTL, drd_control, 0) }, - { FLDATA (FLG, drd_flag, 0) }, + { FLDATA (CTL, drd.control, 0) }, + { FLDATA (FLG, drd.flag, 0) }, { ORDATA (BPTR, drd_ptr, 6) }, - { ORDATA (DEVNO, drd_dib.devno, 6), REG_HRO }, + { ORDATA (DEVNO, drd_dib.select_code, 6), REG_HRO }, { NULL } }; @@ -272,7 +278,7 @@ REG drc_reg[] = { { FLDATA (RUN, drc_run, 0) }, { DRDATA (TIME, dr_time, 24), REG_NZ + PV_LEFT }, { FLDATA (STOP_IOE, dr_stopioe, 0) }, - { ORDATA (DEVNO, drc_dib.devno, 6), REG_HRO }, + { ORDATA (DEVNO, drc_dib.select_code, 6), REG_HRO }, { DRDATA (CAPAC, drc_unit.capac, 24), REG_HRO }, { NULL } }; @@ -326,82 +332,80 @@ DEVICE drc_dev = { and as CRS is sent to all devices, we simply clear the control word here. */ -uint32 drdio (uint32 select_code, IOSIG signal, uint32 data) +uint32 drdio (DIB *dibptr, IOCYCLE signal_set, uint32 stat_data) { -const IOSIG base_signal = IOBASE (signal); /* derive base signal */ int32 t; +IOSIGNAL signal; +IOCYCLE working_set = IOADDSIR (signal_set); /* add ioSIR if needed */ -switch (base_signal) { /* dispatch base I/O signal */ +while (working_set) { + signal = IONEXT (working_set); /* isolate next signal */ - case ioCLF: /* clear flag flip-flop */ - drd_flag = CLEAR; - break; + switch (signal) { /* dispatch I/O signal */ + + case ioCLF: /* clear flag flip-flop */ + drd.flag = CLEAR; + break; - case ioENF: /* enable flag */ - drd_flag = SET; - break; + case ioENF: /* enable flag */ + drd.flag = SET; + break; - case ioIOI: /* I/O data input */ - data = drd_ibuf; - break; + case ioIOI: /* I/O data input */ + stat_data = IORETURN (SCPE_OK, drd_ibuf); /* merge in return status */ + break; - case ioIOO: /* I/O data output */ - drd_obuf = data; - break; + case ioIOO: /* I/O data output */ + drd_obuf = IODATA (stat_data); /* clear supplied status */ + break; - case ioPOPIO: /* power-on preset to I/O */ - /* fall into CRS handler */ - - case ioCRS: /* control reset */ - if (!(drc_unit.flags & UNIT_DRUM)) /* 12606B? */ - drc_cw = 0; /* clear control word */ + case ioCRS: /* control reset */ + if (!(drc_unit.flags & UNIT_DRUM)) /* 12606B? */ + drc_cw = 0; /* clear control word */ /* fall into CLC handler */ - case ioCLC: /* clear control flip-flop */ - drd_flag = drd_control = CLEAR; /* clear control and flag */ + case ioCLC: /* clear control flip-flop */ + drd.flag = drd.control = CLEAR; /* clear control and flag */ - if (!drc_run) /* cancel curr op */ - sim_cancel (&drc_unit); + if (!drc_run) /* cancel curr op */ + sim_cancel (&drc_unit); - drc_sta = drc_sta & ~DRS_SAC; /* clear SAC flag */ - break; + drc_sta = drc_sta & ~DRS_SAC; /* clear SAC flag */ + break; - case ioSTC: /* set control flip-flop */ - drd_control = SET; /* set ctl */ + case ioSTC: /* set control flip-flop */ + drd.control = SET; /* set ctl */ - if (drc_cw & CW_WR) /* writing? */ - drd_flag = SET; /* prime DMA */ + if (drc_cw & CW_WR) /* writing? */ + drd.flag = SET; /* prime DMA */ - drc_sta = 0; /* clr status */ - drd_ptr = 0; /* clear sec ptr */ - sim_cancel (&drc_unit); /* cancel curr op */ - t = CW_GETSEC (drc_cw) - dr_seccntr (sim_gtime()); - if (t <= 0) t = t + DR_NUMSC; - sim_activate (&drc_unit, t * DR_NUMWD * dr_time); - break; + drc_sta = 0; /* clr status */ + drd_ptr = 0; /* clear sec ptr */ + sim_cancel (&drc_unit); /* cancel curr op */ + t = CW_GETSEC (drc_cw) - dr_seccntr (sim_gtime()); + if (t <= 0) t = t + DR_NUMSC; + sim_activate (&drc_unit, t * DR_NUMWD * dr_time); + break; - case ioSIR: /* set interrupt request */ - setstdSRQ (select_code, drd); /* set SRQ signal */ - break; + case ioSIR: /* set interrupt request */ + setstdSRQ (drd); /* set SRQ signal */ + break; - default: /* all other signals */ - break; /* are ignored */ + default: /* all other signals */ + break; /* are ignored */ + } + + working_set = working_set & ~signal; /* remove current signal from set */ } - -if (signal > ioCLF) /* multiple signals? */ - drdio (select_code, ioCLF, 0); /* issue CLF */ -else if (signal > ioSIR) /* signal affected interrupt status? */ - drdio (select_code, ioSIR, 0); /* set interrupt request */ - -return data; +return stat_data; } @@ -423,81 +427,80 @@ return data; 2. The command channel cannot interrupt, so there is no SIR handler. */ -uint32 drcio (uint32 select_code, IOSIG signal, uint32 data) +uint32 drcio (DIB *dibptr, IOCYCLE signal_set, uint32 stat_data) { -const IOSIG base_signal = IOBASE (signal); /* derive base signal */ + +uint16 data; int32 sec; +IOSIGNAL signal; +IOCYCLE working_set = IOADDSIR (signal_set); /* add ioSIR if needed */ -switch (base_signal) { /* dispatch base I/O signal */ +while (working_set) { + signal = IONEXT (working_set); /* isolate next signal */ - case ioCLF: /* clear flag flip-flop */ - if (!(drc_unit.flags & UNIT_DRUM)) { /* disk? */ - sec = dr_seccntr (sim_gtime ()); /* current sector */ - sim_cancel (&drd_unit[TMR_ORG]); /* sched origin tmr */ - sim_activate (&drd_unit[TMR_ORG], - (DR_FNUMSC - sec) * DR_NUMWD * dr_time); - } - break; + switch (signal) { /* dispatch I/O signal */ + + case ioCLF: /* clear flag flip-flop */ + if (!(drc_unit.flags & UNIT_DRUM)) { /* disk? */ + sec = dr_seccntr (sim_gtime ()); /* current sector */ + sim_cancel (&drd_unit[TMR_ORG]); /* sched origin tmr */ + sim_activate (&drd_unit[TMR_ORG], + (DR_FNUMSC - sec) * DR_NUMWD * dr_time); + } + break; - case ioSFC: /* skip if flag is clear */ - if (!(drc_unit.flags & UNIT_DRUM)) /* 12606? */ - setSKF (!(CALC_SCP (sim_gtime()))); /* skip if nearing end of sector */ - break; + case ioSFC: /* skip if flag is clear */ + if (!(drc_unit.flags & UNIT_DRUM)) /* 12606? */ + setSKF (!(CALC_SCP (sim_gtime()))); /* skip if nearing end of sector */ + break; - case ioSFS: /* skip if flag is set */ - if (!(drc_unit.flags & UNIT_DRUM)) /* 12606? */ - setSKF (!sim_is_active (&drd_unit[TMR_ORG])); /* skip if origin seen */ - break; + case ioSFS: /* skip if flag is set */ + if (!(drc_unit.flags & UNIT_DRUM)) /* 12606? */ + setSKF (!sim_is_active (&drd_unit[TMR_ORG])); /* skip if origin seen */ + break; - case ioIOI: /* I/O data input */ - data = drc_sta; /* static bits */ + case ioIOI: /* I/O data input */ + data = drc_sta; /* static bits */ - if (!(drc_unit.flags & UNIT_PROT) || /* not protected? */ - (CW_GETTRK(drc_cw) >= drc_pcount)) /* or not in range? */ - data = data | DRS_WEN; /* set wrt enb status */ + if (!(drc_unit.flags & UNIT_PROT) || /* not protected? */ + (CW_GETTRK(drc_cw) >= drc_pcount)) /* or not in range? */ + data = data | DRS_WEN; /* set wrt enb status */ - if (drc_unit.flags & UNIT_ATT) { /* attached? */ - data = data | (dr_seccntr (sim_gtime()) << DRS_V_NS) | DRS_RDY; - if (sim_is_active (&drc_unit)) /* op in progress? */ - data = data | DRS_BSY; - if (CALC_SCP (sim_gtime())) /* SCP ff set? */ - data = data | DRS_SEC; /* set sector flag */ - if (sim_is_active (&drd_unit[TMR_INH]) && /* inhibit timer on? */ - !(drc_cw & CW_WR)) - data = data | DRS_RIF; /* set read inh flag */ - } - break; + if (drc_unit.flags & UNIT_ATT) { /* attached? */ + data = data | (dr_seccntr (sim_gtime()) << DRS_V_NS) | DRS_RDY; + if (sim_is_active (&drc_unit)) /* op in progress? */ + data = data | DRS_BSY; + if (CALC_SCP (sim_gtime())) /* SCP ff set? */ + data = data | DRS_SEC; /* set sector flag */ + if (sim_is_active (&drd_unit[TMR_INH]) && /* inhibit timer on? */ + !(drc_cw & CW_WR)) + data = data | DRS_RIF; /* set read inh flag */ + } + + stat_data = IORETURN (SCPE_OK, data); /* merge in return status */ + break; - case ioIOO: /* I/O data output */ - if (!(drc_unit.flags & UNIT_DRUM)) { /* disk? */ - sim_cancel (&drd_unit[TMR_INH]); /* schedule inhibit timer */ - sim_activate (&drd_unit[TMR_INH], DR_FTIME * DR_NUMWD); - } - drc_cw = data; /* get control word */ - break; + case ioIOO: /* I/O data output */ + if (!(drc_unit.flags & UNIT_DRUM)) { /* disk? */ + sim_cancel (&drd_unit[TMR_INH]); /* schedule inhibit timer */ + sim_activate (&drd_unit[TMR_INH], DR_FTIME * DR_NUMWD); + } + drc_cw = IODATA (stat_data); /* get control word */ + break; - case ioPOPIO: /* power-on preset to I/O */ - /* fall into CRS handler */ + default: /* all other signals */ + break; /* are ignored */ + } - case ioCRS: /* control reset */ - break; /* allow data channel to handle this */ - - - default: /* all other signals */ - break; /* are ignored */ + working_set = working_set & ~signal; /* remove current signal from set */ } - -if (signal > ioCLF) /* multiple signals? */ - drcio (select_code, ioCLF, 0); /* issue CLF */ - -return data; - +return stat_data; } @@ -511,7 +514,7 @@ uint16 *bptr = (uint16 *) uptr->filebuf; if ((uptr->flags & UNIT_ATT) == 0) { drc_sta = DRS_ABO; - return IORETURN (dr_stopioe, SCPE_UNATT); + return IOERROR (dr_stopioe, SCPE_UNATT); } trk = CW_GETTRK (drc_cw); @@ -527,8 +530,8 @@ if (drc_cw & CW_WR) { /* write? */ uptr->hwmark = da + drd_ptr + 1; } drd_ptr = dr_incda (trk, sec, drd_ptr); /* inc disk addr */ - if (drd_control) { /* dch active? */ - drdio (drd_dib.devno, ioENF, 0); /* set SRQ */ + if (drd.control) { /* dch active? */ + drdio (&drd_dib, ioENF, 0); /* set SRQ */ sim_activate (uptr, dr_time); /* sched next word */ } else { /* done */ @@ -541,11 +544,11 @@ if (drc_cw & CW_WR) { /* write? */ } } /* end write */ else { /* read */ - if (drd_control) { /* dch active? */ + if (drd.control) { /* dch active? */ if ((da >= uptr->capac) || (sec >= DR_NUMSC)) drd_ibuf = 0; else drd_ibuf = bptr[da + drd_ptr]; drd_ptr = dr_incda (trk, sec, drd_ptr); - drdio (drd_dib.devno, ioENF, 0); /* set SRQ */ + drdio (&drd_dib, ioENF, 0); /* set SRQ */ sim_activate (uptr, dr_time); /* sched next word */ } else drc_run = 0; /* clear run ff */ @@ -601,16 +604,17 @@ else return ((curword - DR_OVRHEAD) / DR_NUMWD + t_stat drc_reset (DEVICE *dptr) { +DIB *dibptr = (DIB *) dptr->ctxt; /* DIB pointer */ + hp_enbdis_pair (dptr, /* make pair cons */ (dptr == &drd_dev)? &drc_dev: &drd_dev); -if (sim_switches & SWMASK ('P')) /* PON reset? */ - drc_sta = drc_cw = drd_ptr = 0; /* clear controller state variables */ +if (sim_switches & SWMASK ('P')) { /* power-on reset? */ + drd_ptr = 0; /* clear sector pointer */ + drc_sta = drc_cw = 0; /* clear controller state variables */ + } -if (dptr == &drc_dev) /* command channel reset? */ - drcio (drc_dib.devno, ioPOPIO, 0); /* send POPIO signal to command channel */ -else /* data channel reset */ - drdio (drd_dib.devno, ioPOPIO, 0); /* send POPIO signal to data channel */ +IOPRESET (dibptr); /* PRESET device (does not use PON) */ sim_cancel (&drc_unit); sim_cancel (&drd_unit[TMR_ORG]); @@ -726,7 +730,7 @@ static const BOOT_ROM dr_rom = { /* padded to start at x7 t_stat drc_boot (int32 unitno, DEVICE *dptr) { -const int32 dev = drd_dib.devno; /* data chan select code */ +const int32 dev = drd_dib.select_code; /* data chan select code */ if (unitno != 0) /* only unit 0 */ return SCPE_NOFNC; diff --git a/HP2100/hp2100_ds.c b/HP2100/hp2100_ds.c index 7017736c..ee22bead 100644 --- a/HP2100/hp2100_ds.c +++ b/HP2100/hp2100_ds.c @@ -1,6 +1,6 @@ /* hp2100_ds.c: HP 2100 13037 disk controller simulator - Copyright (c) 2004-2008, Robert M. Supnik + Copyright (c) 2004-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"), @@ -25,6 +25,13 @@ DS 13037 disk controller + 21-Jun-11 JDB Corrected status returns for disabled drive, auto-seek + beyond drive limits, Request Sector Address and Wakeup + with invalid or offline unit + Address verification reenabled if auto-seek during + Read Without Verify + 28-Mar-11 JDB Tidied up signal handling + 26-Oct-10 JDB Changed I/O signal handler for revised signal model 26-Jun-08 JDB Rewrote device I/O to model backplane signals 31-Dec-07 JDB Corrected and verified ioCRS action 20-Dec-07 JDB Corrected DPTR register definition from FLDATA to DRDATA @@ -346,10 +353,12 @@ static struct drvtyp drv_tab[] = { { 0 } }; -FLIP_FLOP ds_control = CLEAR; -FLIP_FLOP ds_flag = CLEAR; -FLIP_FLOP ds_flagbuf = CLEAR; -FLIP_FLOP ds_srq = CLEAR; +struct { + FLIP_FLOP control; /* control flip-flop */ + FLIP_FLOP flag; /* flag flip-flop */ + FLIP_FLOP flagbuf; /* flag buffer flip-flop */ + FLIP_FLOP srq; /* service request flip-flop */ + } ds = { CLEAR, CLEAR, CLEAR, CLEAR }; uint32 ds_fifo[DS_FIFO_SIZE] = { 0 }; /* fifo */ uint32 ds_fifo_ip = 0; /* insertion ptr */ @@ -412,7 +421,9 @@ static const uint32 ds_opflags[32] = { /* flags for ops */ }; DEVICE ds_dev; -uint32 dsio (uint32 select_code, IOSIG signal, uint32 data); + +IOHANDLER dsio; + t_stat ds_svc_c (UNIT *uptr); t_stat ds_svc_u (UNIT *uptr); t_stat ds_svc_t (UNIT *uptr); @@ -455,7 +466,7 @@ void ds_fifo_reset (void); ds_mod DS modifier list */ -DIB ds_dib = { DS, &dsio }; +DIB ds_dib = { &dsio, DS }; UNIT ds_unit[] = { { UDATA (&ds_svc_u, UNIT_FIX | UNIT_ATTABLE | UNIT_ROABLE | @@ -491,10 +502,10 @@ REG ds_reg[] = { { DRDATA (FIP, ds_fifo_ip, 4) }, { DRDATA (FRP, ds_fifo_rp, 4) }, { DRDATA (FCNT, ds_fifo_cnt, 5) }, - { FLDATA (CTL, ds_control, 0) }, - { FLDATA (FLG, ds_flag, 0) }, - { FLDATA (FBF, ds_flagbuf, 0) }, - { FLDATA (SRQ, ds_srq, 0) }, + { FLDATA (CTL, ds.control, 0) }, + { FLDATA (FLG, ds.flag, 0) }, + { FLDATA (FBF, ds.flagbuf, 0) }, + { FLDATA (SRQ, ds.srq, 0) }, { FLDATA (BUSY, ds_busy, 0) }, { FLDATA (CMDF, ds_cmdf, 0) }, { FLDATA (CMDP, ds_cmdp, 0) }, @@ -515,7 +526,7 @@ REG ds_reg[] = { DS_NUMDR + 1, REG_HRO) }, { URDATA (CAPAC, ds_unit[0].capac, 10, T_ADDR_W, 0, DS_NUMDR, PV_LEFT | REG_HRO) }, - { ORDATA (DEVNO, ds_dib.devno, 6), REG_HRO }, + { ORDATA (DEVNO, ds_dib.select_code, 6), REG_HRO }, { NULL } }; @@ -576,7 +587,7 @@ DEVICE ds_dev = { of a command. Also unusual is that SFC and SFS test different things, rather than - complementaty states of the same thing. SFC tests the busy flip-flop, and + complementary states of the same thing. SFC tests the busy flip-flop, and SFS tests the flag flip-flop. Implementation notes: @@ -586,108 +597,110 @@ DEVICE ds_dev = { access to fail. */ -uint32 dsio (uint32 select_code, IOSIG signal, uint32 data) +uint32 dsio (DIB *dibptr, IOCYCLE signal_set, uint32 stat_data) { -const IOSIG base_signal = IOBASE (signal); /* derive base signal */ +IOSIGNAL signal; +IOCYCLE working_set = IOADDSIR (signal_set); /* add ioSIR if needed */ -switch (base_signal) { /* dispatch base I/O signal */ +while (working_set) { + signal = IONEXT (working_set); /* isolate next signal */ - case ioCLF: /* clear flag flip-flop */ - ds_flag = ds_flagbuf = CLEAR; /* clear flag */ - ds_srq = CLEAR; /* CLF clears SRQ */ - break; + switch (signal) { /* dispatch I/O signal */ + + case ioCLF: /* clear flag flip-flop */ + ds.flag = ds.flagbuf = CLEAR; /* clear flag */ + ds.srq = CLEAR; /* CLF clears SRQ */ + break; - case ioSTF: /* set flag flip-flop */ - case ioENF: /* enable flag */ - ds_flag = ds_flagbuf = SET; /* set flag and flag buffer */ - break; + case ioSTF: /* set flag flip-flop */ + case ioENF: /* enable flag */ + ds.flag = ds.flagbuf = SET; /* set flag and flag buffer */ + break; - case ioSFC: /* skip if flag is clear */ - setSKF (ds_busy == 0); /* skip if not busy */ - break; + case ioSFC: /* skip if flag is clear */ + setSKF (ds_busy == 0); /* skip if not busy */ + break; - case ioSFS: /* skip if flag is set */ - setstdSKF (ds); - break; + case ioSFS: /* skip if flag is set */ + setstdSKF (ds); + break; - case ioIOI: /* I/O data input */ - data = ds_fifo_read (); - break; + case ioIOI: /* I/O data input */ + stat_data = IORETURN (SCPE_OK, ds_fifo_read ()); /* merge in return status */ + break; - case ioIOO: /* I/O data output */ - if (ds_cmdf) { /* expecting command? */ - ds_cmd = data; /* save command */ - ds_cmdf = 0; - ds_cmdp = 1; /* command present */ - } + case ioIOO: /* I/O data output */ + if (ds_cmdf) { /* expecting command? */ + ds_cmd = IODATA (stat_data); /* save command */ + ds_cmdf = 0; + ds_cmdp = 1; /* command present */ + } - else - ds_fifo_write (data); /* put in fifo */ - break; + else + ds_fifo_write (IODATA (stat_data)); /* put in fifo */ + break; - case ioPOPIO: /* power-on preset to I/O */ - ds_flag = ds_flagbuf = SET; /* set flag and flag buffer */ - ds_cmdp = 0; /* clear command ready */ - /* fall into CRS handler */ - - case ioCRS: /* control reset */ - ds_control = CLEAR; /* clear control */ - ds_cmdf = 0; /* not expecting command */ - ds_clear (); /* do controller CLEAR */ - break; + case ioPOPIO: /* power-on preset to I/O */ + ds.flag = ds.flagbuf = SET; /* set flag and flag buffer */ + ds_cmdp = 0; /* clear command ready */ + break; - case ioCLC: /* clear control flip-flop */ - ds_control = CLEAR; /* clear control */ - ds_cmdf = 1; /* expecting command */ - ds_cmdp = 0; /* none pending */ - ds_eod = 1; /* set EOD flag */ - ds_fifo_reset (); /* clear fifo */ - break; + case ioCRS: /* control reset */ + ds.control = CLEAR; /* clear control */ + ds_cmdf = 0; /* not expecting command */ + ds_clear (); /* do controller CLEAR */ + break; - case ioSTC: /* set control flip-flop */ - ds_control = SET; /* set control */ - break; + case ioCLC: /* clear control flip-flop */ + ds.control = CLEAR; /* clear control */ + ds_cmdf = 1; /* expecting command */ + ds_cmdp = 0; /* none pending */ + ds_eod = 1; /* set EOD flag */ + ds_fifo_reset (); /* clear fifo */ + break; - case ioEDT: /* end data transfer */ - ds_eod = 1; /* flag end transfer */ - break; + case ioSTC: /* set control flip-flop */ + ds.control = SET; /* set control */ + break; - case ioSIR: /* set interrupt request */ - setstdPRL (select_code, ds); /* set standard PRL signal */ - setstdIRQ (select_code, ds); /* set standard IRQ signal */ - setSRQ (select_code, ds_srq); /* set SRQ signal */ - break; + case ioEDT: /* end data transfer */ + ds_eod = 1; /* flag end transfer */ + break; - case ioIAK: /* interrupt acknowledge */ - ds_flagbuf = CLEAR; - break; + case ioSIR: /* set interrupt request */ + setstdPRL (ds); /* set standard PRL signal */ + setstdIRQ (ds); /* set standard IRQ signal */ + setSRQ (dibptr->select_code, ds.srq); /* set SRQ signal */ + break; - default: /* all other signals */ - break; /* are ignored */ + case ioIAK: /* interrupt acknowledge */ + ds.flagbuf = CLEAR; + break; + + + default: /* all other signals */ + break; /* are ignored */ + } + + working_set = working_set & ~signal; /* remove current signal from set */ } -if (signal > ioCLF) /* multiple signals? */ - dsio (select_code, ioCLF, 0); /* issue CLF */ -else if (signal > ioSIR) /* signal affected interrupt status? */ - dsio (select_code, ioSIR, 0); /* set interrupt request */ - - -if ((signal != ioSIR) && (signal != ioENF)) /* if not IRQ update */ +if (!(signal_set & ioSIR) && !(signal_set & ioENF)) /* if not IRQ update */ ds_poll (); /* run the controller */ -return data; +return stat_data; } @@ -702,7 +715,7 @@ void ds_poll (void) { if ((ds_state != DS_BUSY) && ds_cmdp) /* cmd pending? */ ds_docmd (ds_cmd); /* do it */ -if ((ds_state == DS_IDLE) && ds_control) /* idle? */ +if ((ds_state == DS_IDLE) && ds.control) /* idle? */ ds_doatn (); /* check ATN */ return; } @@ -719,7 +732,7 @@ return; void ds_docmd (uint32 cmd) { -uint32 op, f, dtyp, unum; +uint32 op, f, unum; op = DSC_GETOP (cmd); /* operation */ f = ds_opflags[op]; /* flags */ @@ -749,6 +762,7 @@ switch (op) { (DSC_GETCSC (ds_cmd) << DSHS_V_SC); case DSC_RECAL: /* recalibrate */ case DSC_SEEK: /* seek */ + case DSC_RSA: /* read sector address */ case DSC_READ: /* read */ case DSC_RFULL: /* read full */ case DSC_ROFF: /* read offset */ @@ -786,12 +800,6 @@ switch (op) { ds_sched_ctrl_op (DSC_RSTA, 2, SET_BUSY); /* sched 2 wds, busy */ break; - case DSC_RSA: /* read sector address */ - dtyp = GET_DTYPE (ds_unit[unum].flags); /* get unit type */ - dsxb[0] = GET_CURSEC (ds_dtime * DS_NUMWD, dtyp); /* rot position */ - ds_sched_ctrl_op (DSC_RSTA, 1, SET_BUSY); /* sched 1 wd, busy */ - break; - case DSC_RDA: /* read disk address */ ds_reqad (&dsxb[1], &dsxb[0]); /* return disk address */ ds_sched_ctrl_op (DSC_RSTA, 2, SET_BUSY); /* sched 2 wds, busy */ @@ -806,10 +814,15 @@ switch (op) { /* Other controller commands */ + case DSC_WAKE: /* wakeup */ + ds_sr1 = unum; /* init status */ + if (unum >= DS_NUMDR) { /* invalid unit? */ + ds_sched_ctrl_op (DSC_BADU, unum, CLR_BUSY);/* sched, not busy */ + return; + } case DSC_SFM: /* set file mask */ case DSC_CLEAR: /* clear */ case DSC_AREC: /* address record */ - case DSC_WAKE: /* wakeup */ case DSC_WTIO: /* write TIO */ ds_sched_ctrl_op (op, 0, SET_BUSY); /* schedule, busy */ break; @@ -833,7 +846,7 @@ for (i = 0; i < DS_NUMDR; i++) { /* intr disabled? */ ds_lastatn = (ds_lastatn + 1) & DS_DRMASK; /* loop through units */ if (ds_unit[ds_lastatn].STA & DS2_ATN) { /* ATN set? */ ds_unit[ds_lastatn].STA &= ~DS2_ATN; /* clear ATN */ - dsio (ds_dib.devno, ioENF, 0); /* request interrupt */ + dsio (&ds_dib, ioENF, 0); /* request interrupt */ ds_sr1 = DS1_ATN | ds_lastatn; /* set up status 1 */ ds_state = DS_WAIT; /* block atn intrs */ return; @@ -889,9 +902,9 @@ switch (op) { case DSC_CLEAR: /* clear */ ds_clear (); /* reset ctrl */ - ds_control = CLEAR; /* clear CTL, SRQ */ - ds_srq = CLEAR; - dsio (ds_dib.devno, ioSIR, 0); /* set interrupt request */ + ds.control = CLEAR; /* clear CTL, SRQ */ + ds.srq = CLEAR; + dsio (&ds_dib, ioSIR, 0); /* set interrupt request */ ds_cmd_done (1, DS1_OK); /* op done, set flag */ break; @@ -994,6 +1007,15 @@ switch (op) { /* case on function */ /* Read variants */ + case DSC_RSA: /* read sector address */ + if ((uptr->flags & UNIT_UNLOAD) == 0) { /* drive up? */ + dsxb[0] = GET_CURSEC (ds_dtime * DS_NUMWD, dtyp); /* rot position */ + ds_sched_ctrl_op (DSC_RSTA, 1, SET_BUSY); /* sched 1 wd, busy */ + } + else /* no drive or heads unloaded */ + ds_cmd_done (1, DS1_S2ERR); /* not ready error */ + break; + case DSC_ROFF: /* read with offset */ ds_wait_for_cpu (uptr, DSC_ROFF|DSC_2ND); /* set flag, new state */ break; @@ -1001,7 +1023,7 @@ switch (op) { /* case on function */ if (!DS_FIFO_EMPTY) { /* OTA ds? new state */ ds_fifo_read (); /* drain fifo */ uptr->FNC = DSC_READ; - dsio (ds_dib.devno, ioENF, 0); /* handshake */ + dsio (&ds_dib, ioENF, 0); /* handshake */ } sim_activate (uptr, ds_ctime); /* schedule unit */ break; @@ -1022,14 +1044,15 @@ switch (op) { /* case on function */ ds_end_rw (uptr, DSC_READ); /* see if more to do */ break; - case DSC_RNOVFY: /* read, no verify */ + case DSC_RNOVFY: /* read, no verify before xfer */ if (r = ds_start_rd (uptr, 0, 0)) return r; /* new sector; error? */ break; case DSC_RNOVFY | DSC_2ND: /* word transfer */ ds_cont_rd (uptr, DS_NUMWD); /* xfr wd, check end */ break; case DSC_RNOVFY | DSC_3RD: /* end of sector */ - ds_end_rw (uptr, DSC_RNOVFY); /* see if more to do */ + ds_end_rw (uptr, /* see if more to do */ + DSHS_GETSC (ds_hs) ? DSC_RNOVFY : DSC_READ); /* start verifying if end of track */ break; case DSC_RFULL: /* read full */ @@ -1049,7 +1072,7 @@ switch (op) { /* case on function */ case DSC_VFY: /* verify */ ds_wait_for_cpu (uptr, DSC_VFY|DSC_2ND); /* set flag, new state */ break; - case DSC_VFY | DSC_2ND: /* poll done */ + case DSC_VFY | DSC_2ND: /* poll done */ if (!DS_FIFO_EMPTY) { /* OTA ds? */ ds_vctr = ds_fifo_read (); /* save count */ uptr->FNC = DSC_VFY | DSC_3RD; /* next state */ @@ -1058,11 +1081,11 @@ switch (op) { /* case on function */ else sim_activate (uptr, ds_ctime); /* no, continue poll */ break; case DSC_VFY | DSC_3RD: /* start sector */ - if (ds_start_rw (uptr, ds_dtime * DS_NUMWD, 1)) break; - /* new sector; error? */ + if (ds_start_rw (uptr, ds_dtime * DS_NUMWD, 1)) /* new sector; error? */ + break; ds_next_sec (uptr); /* increment hd, sc */ break; - case DSC_VFY | DSC_4TH: /* end sector */ + case DSC_VFY | DSC_4TH: /* end sector */ ds_vctr = (ds_vctr - 1) & DMASK; /* decrement count */ if (ds_vctr) ds_end_rw (uptr, DSC_VFY|DSC_3RD); /* more to do? */ else ds_cmd_done (1, DS1_OK); /* no, set done */ @@ -1120,7 +1143,7 @@ return SCPE_OK; void ds_wait_for_cpu (UNIT *uptr, uint32 newst) { -dsio (ds_dib.devno, ioENF, 0); /* set flag */ +dsio (&ds_dib, ioENF, 0); /* set flag */ uptr->FNC = newst; /* new state */ sim_activate (uptr, ds_ctime); /* activate unit */ sim_cancel (&ds_timer); /* activate timeout */ @@ -1154,7 +1177,7 @@ return; void ds_cmd_done (t_bool sf, uint32 sr1) { if (sf) /* set host flag? */ - dsio (ds_dib.devno, ioENF, 0); /* set flag */ + dsio (&ds_dib, ioENF, 0); /* set flag */ ds_busy = 0; /* clear visible busy */ ds_sr1 = ds_sr1 | sr1; /* final status */ @@ -1165,7 +1188,20 @@ return; } -/* Return drive status (status word 2) */ +/* Return drive status (status word 2). + + In hardware, the controller outputs the Address Unit command on the drive tag + bus and the unit number on the drive control bus. The addressed drive + responds by setting its internal "selected" flag. The controller then + outputs Request Status on the tag bug. If a drive is selected but the heads + are unloaded, the drive returns Not Ready and Busy status on the control bus. + If no drive is selected, the control bus floats inactive. This is + interpreted by the controller as Not Ready status (because the drive returns + inactive Ready status). + + Under simulation, an enabled but detached unit corresponds to "selected but + heads unloaded," and a disabled unit corresponds to a non-existent unit. +*/ uint32 ds_updds2 (UNIT *uptr) { @@ -1174,10 +1210,11 @@ uint32 dtyp = GET_DTYPE (uptr->flags); sta = drv_tab[dtyp].id | /* form status */ uptr->STA | /* static bits */ - ((uptr->flags & UNIT_WPR)? DS2_RO: 0) | /* dynamic bits */ - ((uptr->flags & UNIT_FMT)? DS2_FRM: 0) | - ((uptr->flags & UNIT_UNLOAD)? DS2_NR | DS2_BS: 0) | - (sim_is_active (uptr)? DS2_BS: 0); + ((uptr->flags & UNIT_WPR) ? DS2_RO : 0) | /* dynamic bits */ + ((uptr->flags & UNIT_FMT) ? DS2_FRM : 0) | + ((uptr->flags & UNIT_DIS) ? DS2_NR : + (uptr->flags & UNIT_UNLOAD) ? DS2_NR | DS2_BS : 0) | + (sim_is_active (uptr) ? DS2_BS : 0); if (sta & DS2_ALLERR) sta = sta | DS2_ERR; /* set error */ return sta; } @@ -1240,7 +1277,12 @@ return; - If error, set command done, return TRUE, nothing is scheduled - If implicit seek, return TRUE, implicit seek is scheduled, but state is not changed - we will return here when seek is done - - Otherwise, advance state, set position in file, schedule next state */ + - Otherwise, advance state, set position in file, schedule next state + + If a an auto-seek was done, it may have incremented or decremented beyond the + cylinder bounds. If so, then Seek Check status will have been set. If we + see that, terminate the current command with a Status-2 error. +*/ t_bool ds_start_rw (UNIT *uptr, int32 tm, t_bool vfy) { @@ -1249,8 +1291,8 @@ uint32 dtyp = GET_DTYPE (uptr->flags); ds_eod = 0; /* init eod */ ds_ptr = 0; /* init buffer ptr */ -if (uptr->flags & UNIT_UNLOAD) { /* drive down? */ - ds_cmd_done (1, DS1_S2ERR); +if (uptr->flags & UNIT_UNLOAD | uptr->STA & DS2_SC) { /* drive down or seek check? */ + ds_cmd_done (1, DS1_S2ERR); /* report Status-2 error */ return TRUE; } if (ds_eoc) { /* at end of cylinder? */ @@ -1258,21 +1300,16 @@ if (ds_eoc) { /* at end of cylinder? * return TRUE; /* or error */ } if (vfy && ((uint32) uptr->CYL != ds_cyl)) { /* on wrong cylinder? */ - if (ds_cyl >= drv_tab[dtyp].cyl) /* seeking to bad? */ - ds_cmd_done (1, DS1_CYLCE); /* lose */ - else ds_start_seek (uptr, ds_cyl, uptr->FNC); /* seek right cyl */ + ds_start_seek (uptr, ds_cyl, uptr->FNC); /* seek right cyl */ return TRUE; } hd = DSHS_GETHD (ds_hs); sc = DSHS_GETSC (ds_hs); -if ((uint32) uptr->CYL >= drv_tab[dtyp].cyl) { /* valid cylinder? */ - uptr->STA = uptr->STA | DS2_SC; /* set seek check */ - ds_cmd_done (1, DS1_S2ERR); /* error */ - return TRUE; - } -if ((hd >= drv_tab[dtyp].hd) || /* valid head, sector? */ +if (((uint32) uptr->CYL >= drv_tab[dtyp].cyl) || /* valid cylinder? (sanity check) */ + (hd >= drv_tab[dtyp].hd) || /* valid head, sector? */ (sc >= drv_tab[dtyp].sc)) { - ds_cmd_done (1, DS1_HSCE); /* no, error */ + uptr->STA = uptr->STA | DS2_SC; /* set seek check */ + ds_cmd_done (1, DS1_S2ERR); /* report Status-2 error */ return TRUE; } da = GET_DA (uptr->CYL, hd, sc, dtyp); /* position in file */ @@ -1327,8 +1364,8 @@ if ((uptr->flags & UNIT_WPR) || /* write protected? */ } if (ds_start_rw (uptr, ds_rtime, vfy)) return; /* new sec; err or seek? */ for (i = 0; i < DS_NUMWDF; i++) dsxb[i] = 0; /* clear buffer */ -ds_srq = SET; /* request word */ -dsio (ds_dib.devno, ioSIR, 0); /* set interrupt request */ +ds.srq = SET; /* request word */ +dsio (&ds_dib, ioSIR, 0); /* set interrupt request */ return; } @@ -1355,7 +1392,10 @@ return; /* Advance to next cylinder - If autoseek enabled, seek to cylinder +/- 1 - - Otherwise, done with end of cylinder error */ + - Otherwise, done with end of cylinder error. + + If we exceed the cylinder range, the seek will set Seek Check status. +*/ void ds_next_cyl (UNIT *uptr) { @@ -1378,14 +1418,14 @@ return; void ds_cont_rd (UNIT *uptr, uint32 bsize) { if (ds_eod) ds_cmd_done (1, DS1_OK); /* DMA end? done */ -else if (ds_srq) { /* overrun? */ +else if (ds.srq) { /* overrun? */ ds_cmd_done (1, DS1_OVRUN); /* set done */ return; } else { ds_fifo_write (dsxb[ds_ptr++]); /* next word */ - ds_srq = SET; /* request service */ - dsio (ds_dib.devno, ioSIR, 0); /* set interrupt request */ + ds.srq = SET; /* request service */ + dsio (&ds_dib, ioSIR, 0); /* set interrupt request */ if (ds_ptr >= bsize) uptr->FNC += DSC_NEXT; /* sec done? next state */ sim_activate (uptr, ds_dtime); /* schedule */ } @@ -1398,13 +1438,13 @@ return; - Copy word from fifo to buffer - If end of data, write buffer, terminate command, nothing scheduled - If end of sector, write buffer, next state, schedule - - Otherwises, set service request, schedule */ + - Otherwise, set service request, schedule */ t_stat ds_cont_wr (UNIT *uptr, uint32 off, uint32 bsize) { uint32 i, dat; -if (ds_srq) { /* overrun? */ +if (ds.srq) { /* overrun? */ ds_cmd_done (1, DS1_OVRUN); /* set done */ return SCPE_OK; } @@ -1422,8 +1462,8 @@ if (ds_eod || (ds_ptr >= bsize)) { /* xfr or sector done? * else uptr->FNC += DSC_NEXT; /* no, next state */ } else { - ds_srq = SET; /* request next word */ - dsio (ds_dib.devno, ioSIR, 0); /* set interrupt request */ + ds.srq = SET; /* request next word */ + dsio (&ds_dib, ioSIR, 0); /* set interrupt request */ } sim_activate (uptr, ds_dtime); /* schedule */ return SCPE_OK; @@ -1529,8 +1569,8 @@ return SCPE_OK; t_stat ds_reset (DEVICE *dptr) { -dsio (ds_dib.devno, ioPOPIO, 0); /* send POPIO signal */ -ds_srq = CLEAR; /* clear SRQ */ +IOPRESET (&ds_dib); /* PRESET device */ +ds.srq = CLEAR; /* clear SRQ */ return SCPE_OK; } @@ -1593,7 +1633,7 @@ void ds_sched_atn (UNIT *uptr) { int32 i; -if (!ds_control || (sim_switches & SIM_SW_REST)) return; +if (!ds.control || (sim_switches & SIM_SW_REST)) return; for (i = 0; i < (DS_NUMDR + 1); i++) { /* check units, ctrl */ if (sim_is_active (ds_dev.units + i)) return; } @@ -1687,7 +1727,7 @@ t_stat ds_boot (int32 unitno, DEVICE *dptr) int32 dev; if (unitno != 0) return SCPE_NOFNC; /* only unit 0 */ -dev = ds_dib.devno; /* get data chan dev */ +dev = ds_dib.select_code; /* get data chan dev */ if (ibl_copy (ds_rom, dev)) return SCPE_IERR; /* copy boot to memory */ SR = (SR & (IBL_OPT | IBL_DS_HEAD)) | IBL_DS | IBL_MAN | (dev << IBL_V_DEV); return SCPE_OK; diff --git a/HP2100/hp2100_fp1.c b/HP2100/hp2100_fp1.c index 0ca50848..cf078435 100644 --- a/HP2100/hp2100_fp1.c +++ b/HP2100/hp2100_fp1.c @@ -1,6 +1,6 @@ /* hp2100_fp1.c: HP 1000 multiple-precision floating point routines - Copyright (c) 2005-2008, J. David Bryan + Copyright (c) 2005-2011, J. David Bryan Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), @@ -23,6 +23,7 @@ in advertising or otherwise to promote the sale, use or other dealings in this Software without prior written authorization from the author. + 21-Jun-11 JDB Completed the comments for divide; no code changes 08-Jun-08 JDB Quieted bogus gcc warning in fp_exec 10-May-08 JDB Fixed uninitialized return in fp_accum when setting 19-Mar-08 JDB Reworked "complement" to avoid inlining bug in gcc-4.x @@ -153,7 +154,7 @@ initial letters of the instructions (F/X/T) to indicate the precision used. The FPP hardware consisted of two circuit boards that interfaced to the main - CPU via the Microprogammable Processor Port (MPP) that had been introduced + CPU via the Microprogrammable Processor Port (MPP) that had been introduced with the 1000 E-Series. One board contained argument registers and ALUs, split into separate mantissa and exponent parts. The other contained a state machine sequencer. FPP results were copied automatically to the argument @@ -675,9 +676,9 @@ return; two operands. If the magnitude of the difference between the exponents is greater than the number of significant bits, then the smaller number has been scaled to zero (swamped), and so the sum is simply the larger operand. - Otherwise, the sum is computed and checked for overflow, which has occured if - the signs of the operands are the same but differ from that of the result. - Scaling and renormalization is perfomed if overflow occurred. + Otherwise, the sum is computed and checked for overflow, which has occurred + if the signs of the operands are the same but differ from that of the result. + Scaling and renormalization is performed if overflow occurred. */ static void add (FPU *sum, FPU augend, FPU addend) @@ -727,11 +728,11 @@ return; The single-precision firmware (FMP) operates differently from the firmware extended-precision (.XMPY) and the hardware multiplies of any precision. - Firmware implementations form 16-bit x 16-bit = 32-bit partial products and - sum them to form the result. The hardware uses a series of shifts and adds. - This means that firmware FMP and hardware FMP return slightly different - values, as may be seen by attempting to run the firmware FMP diagnostic on - the FPP. + Firmware implementations use the MPY micro-order to form 16-bit x 16-bit = + 32-bit partial products and sum them to form the result. The hardware uses a + series of shifts and adds. This means that firmware FMP and hardware FMP + return slightly different values, as may be seen by attempting to run the + firmware FMP diagnostic on the FPP. The FMP microcode calls a signed multiply routine to calculate three partial products (all but LSB * LSB). Because the LSBs are unsigned, i.e., all bits @@ -779,7 +780,7 @@ return; The basic FPP hardware algorithm scans the multiplier and adds a shifted copy of the multiplicand whenever a one-bit is detected. To avoid successive adds when a string of ones is encountered (because adds are more expensive than - shifts), the hardware instead adds the multiplicand shifted by N+1+P and + shifts), the hardware instead adds the multiplicand shifted by N + 1 + P and subtracts the multiplicand shifted by P to obtain the equivalent value with a maximum of two operations. @@ -884,16 +885,32 @@ return; As with multiply, the single-precision firmware (FDV) operates differently from the firmware extended-precision (.XDIV) and the hardware divisions of - any precision. Firmware implementations utilize a "divide and correct" - algorithm, wherein the quotient is estimated and then corrected by comparing - the dividend to the product of the quotient and the divisor. The hardware - uses a series of shifts and subtracts. This means that firmware FDV and - hardware FDV once again return slightly different values. + any precision. Firmware implementations use the DIV micro-order to form + 32-bit / 16-bit = 16-bit quotients and 16-bit remainders. These are used in + a "divide and correct" algorithm, wherein the quotient is estimated and then + corrected by comparing the dividend to the product of the quotient and the + divisor. The hardware uses a series of shifts and subtracts. This means + that firmware FDV and hardware FDV once again return slightly different + values. Under simulation, the classic divide-and-correct method is employed, using - 64-bit / 32-bit = 32-bit divisions. This involves dividing the 64-bit - dividend "a1a2a3a4" by the first 32-bit digit "b1b2" of the 64-bit divisor - "b1b2b3b4". The resulting 32-bit quotient is ... + 64-bit / 32-bit = 32-bit divisions. This method considers the 64-bit + dividend and divisor each to consist of two 32-bit "digits." The 64-bit + dividend "a1a2a3a4" is divided by the first 32-bit digit "b1b2" of the 64-bit + divisor "b1b2b3b4", yielding a 32-bit trial quotient digit and a 32-bit + remainder digit. A correction is developed by subtracting the product of the + second 32-bit digit "b3b4" of the divisor and the trial quotient digit from + the remainder (we take advantage of the eight bits vacated by the exponent + during unpacking to ensure that this product will not overflow into the sign + bit). If the remainder is negative, the trial quotient is too large, so it + is decremented, and the (full 64-bit) divisor is added to the correction. + This is repeated until the correction is non-negative, indicating that the + first quotient digit is correct. The process is then repeated using the + remainder as the dividend to develop the second 32-bit digit of the quotient. + The two digits are then concatenated for produce the final 64-bit value. + + (See, "Divide-and-Correct Methods for Multiple Precision Division" by Marvin + L. Stein, Communications of the ACM, August 1964 for background.) The microcoded single-precision division avoids overflows by right-shifting some values, which leads to a loss of precision in the LSBs. We duplicate @@ -1365,7 +1382,7 @@ return 0; } - /* Complement an unpacked mantissa. +/* Complement an unpacked mantissa. An unpacked mantissa is passed as a "packed" number with a zero exponent. The exponent increment, i.e., either zero or one, depending on whether a diff --git a/HP2100/hp2100_ipl.c b/HP2100/hp2100_ipl.c index 69eebc90..14811d01 100644 --- a/HP2100/hp2100_ipl.c +++ b/HP2100/hp2100_ipl.c @@ -1,6 +1,6 @@ /* hp2100_ipl.c: HP 2000 interprocessor link simulator - Copyright (c) 2002-2008, Robert M Supnik + Copyright (c) 2002-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"), @@ -25,6 +25,11 @@ IPLI, IPLO 12875A interprocessor link + 07-Apr-11 JDB A failed STC may now be retried + 28-Mar-11 JDB Tidied up signal handling + 27-Mar-11 JDB Consolidated reporting of consecutive CRS signals + 29-Oct-10 JDB Revised for new multi-card paradigm + 26-Oct-10 JDB Changed I/O signal handler for revised signal model 07-Sep-08 JDB Changed Telnet poll to connect immediately after reset or attach 15-Jul-08 JDB Revised EDT handler to refine completion delay conditions 09-Jul-08 JDB Revised ipl_boot to use ibl_copy @@ -62,6 +67,10 @@ #include "sim_sock.h" #include "sim_tmxr.h" +typedef enum { ipli, iplo } CARD_INDEX; /* card index number */ + +#define CARD_COUNT 2 /* count of cards supported */ + #define UNIT_V_DIAG (UNIT_V_UF + 0) /* diagnostic mode */ #define UNIT_V_ACTV (UNIT_V_UF + 1) /* making connection */ #define UNIT_V_ESTB (UNIT_V_UF + 2) /* connection established */ @@ -83,19 +92,21 @@ extern DIB ptr_dib; /* need PTR select code for boot */ -typedef enum { CIN, COUT } CARD; /* ipli/iplo selector */ - int32 ipl_edtdelay = 1; /* EDT delay (msec) */ int32 ipl_ptime = 31; /* polling interval */ int32 ipl_stopioe = 0; /* stop on error */ -int32 ipl_hold[2] = { 0 }; /* holding character */ -FLIP_FLOP ipl_control [2] = { CLEAR, CLEAR }; -FLIP_FLOP ipl_flag [2] = { CLEAR, CLEAR }; -FLIP_FLOP ipl_flagbuf [2] = { CLEAR, CLEAR }; +typedef struct { + FLIP_FLOP control; /* control flip-flop */ + FLIP_FLOP flag; /* flag flip-flop */ + FLIP_FLOP flagbuf; /* flag buffer flip-flop */ + int32 hold; /* holding character */ + } CARD_STATE; + +CARD_STATE ipl [CARD_COUNT]; /* per-card state */ + +IOHANDLER iplio; -DEVICE ipli_dev, iplo_dev; -uint32 iplio (uint32 select_code, IOSIG signal, uint32 data); t_stat ipl_svc (UNIT *uptr); t_stat ipl_reset (DEVICE *dptr); t_stat ipl_attach (UNIT *uptr, char *cptr); @@ -107,12 +118,37 @@ t_bool ipl_check_conn (UNIT *uptr); /* Debug flags table */ -DEBTAB ipl_deb[] = { +DEBTAB ipl_deb [] = { { "CMDS", DEB_CMDS }, { "CPU", DEB_CPU }, { "XFER", DEB_XFER }, { NULL, 0 } }; +/* Common structures */ + +DEVICE ipli_dev, iplo_dev; + +static DEVICE *dptrs [] = { &ipli_dev, &iplo_dev }; + + +UNIT ipl_unit [] = { + { UDATA (&ipl_svc, UNIT_ATTABLE, 0) }, + { UDATA (&ipl_svc, UNIT_ATTABLE, 0) } + }; + +#define ipli_unit ipl_unit [ipli] +#define iplo_unit ipl_unit [iplo] + + +DIB ipl_dib [] = { + { &iplio, IPLI, 0 }, + { &iplio, IPLO, 1 } + }; + +#define ipli_dib ipl_dib [ipli] +#define iplo_dib ipl_dib [iplo] + + /* IPLI data structures ipli_dev IPLI device descriptor @@ -120,36 +156,20 @@ DEBTAB ipl_deb[] = { ipli_reg IPLI register list */ -DIB ipl_dib[] = { - { IPLI, &iplio }, - { IPLO, &iplio } - }; - -#define ipli_dib ipl_dib[0] -#define iplo_dib ipl_dib[1] - -UNIT ipl_unit[] = { - { UDATA (&ipl_svc, UNIT_ATTABLE, 0) }, - { UDATA (&ipl_svc, UNIT_ATTABLE, 0) } - }; - -#define ipli_unit ipl_unit[0] -#define iplo_unit ipl_unit[1] - -REG ipli_reg[] = { +REG ipli_reg [] = { { ORDATA (IBUF, ipli_unit.IBUF, 16) }, { ORDATA (OBUF, ipli_unit.OBUF, 16) }, - { FLDATA (CTL, ipl_control [CIN], 0) }, - { FLDATA (FLG, ipl_flag [CIN], 0) }, - { FLDATA (FBF, ipl_flagbuf [CIN], 0) }, - { ORDATA (HOLD, ipl_hold[CIN], 8) }, + { FLDATA (CTL, ipl [ipli].control, 0) }, + { FLDATA (FLG, ipl [ipli].flag, 0) }, + { FLDATA (FBF, ipl [ipli].flagbuf, 0) }, + { ORDATA (HOLD, ipl [ipli].hold, 8) }, { DRDATA (TIME, ipl_ptime, 24), PV_LEFT }, { FLDATA (STOP_IOE, ipl_stopioe, 0) }, - { ORDATA (DEVNO, ipli_dib.devno, 6), REG_HRO }, + { ORDATA (DEVNO, ipli_dib.select_code, 6), REG_HRO }, { NULL } }; -MTAB ipl_mod[] = { +MTAB ipl_mod [] = { { UNIT_DIAG, UNIT_DIAG, "diagnostic mode", "DIAG", &ipl_setdiag }, { UNIT_DIAG, 0, "link mode", "LINK", &ipl_setdiag }, { MTAB_XTD | MTAB_VDV, 0, NULL, "DISCONNECT", @@ -175,15 +195,15 @@ DEVICE ipli_dev = { iplo_reg IPLO register list */ -REG iplo_reg[] = { +REG iplo_reg [] = { { ORDATA (IBUF, iplo_unit.IBUF, 16) }, { ORDATA (OBUF, iplo_unit.OBUF, 16) }, - { FLDATA (CTL, ipl_control [COUT], 0) }, - { FLDATA (FLG, ipl_flag [COUT], 0) }, - { FLDATA (FBF, ipl_flagbuf [COUT], 0) }, - { ORDATA (HOLD, ipl_hold[COUT], 8) }, + { FLDATA (CTL, ipl [iplo].control, 0) }, + { FLDATA (FLG, ipl [iplo].flag, 0) }, + { FLDATA (FBF, ipl [iplo].flagbuf, 0) }, + { ORDATA (HOLD, ipl [iplo].hold, 8) }, { DRDATA (TIME, ipl_ptime, 24), PV_LEFT }, - { ORDATA (DEVNO, iplo_dib.devno, 6), REG_HRO }, + { ORDATA (DEVNO, iplo_dib.select_code, 6), REG_HRO }, { NULL } }; @@ -206,11 +226,7 @@ DEVICE iplo_dev = { Implementation notes: - 1. Because this routine is written to handle two devices, the flip-flops are - stored in arrays, preventing the use of the "setstd" macros for PRL, IRQ, - and SRQ signals. The logic for all three is standard, however. - - 2. 2000 Access has a race condition that manifests itself by an apparently + 1. 2000 Access has a race condition that manifests itself by an apparently normal boot and operational system console but no PLEASE LOG IN response to terminals connected to the multiplexer. The frequency of occurrence is higher on multiprocessor host systems, where the SP and IOP instances @@ -259,157 +275,176 @@ DEVICE iplo_dev = { sleep expiration, the SP still has not executed the STC/CLC. Still, in testing, the incidence dropped dramatically, so the problem is much less intrusive. + + 2. The operating manual for the 12920A Terminal Multiplexer says that "at + least 100 milliseconds of CLC 0s must be programmed" by systems employing + the multiplexer to ensure that the multiplexer resets. In practice, such + systems issue 128K CLC 0 instructions. As we provide debug logging of + IPL resets, a CRS counter is used to ensure that only one debug line is + printed in response to these 128K CRS invocations. + + 3. The STC handler may return "Unit not attached", "I/O error", or "No + connection on interprocessor link" status if the link fails or is + improperly configured. If the error is corrected, the operation may be + retried by resuming simulated execution. */ -uint32 iplio (uint32 select_code, IOSIG signal, uint32 data) +uint32 iplio (DIB *dibptr, IOCYCLE signal_set, uint32 stat_data) { -const CARD card = (select_code == iplo_dib.devno); /* set card selector */ -UNIT *const uptr = &(ipl_unit [card]); /* associated unit pointer */ -const char uc = (card == CIN) ? 'I' : 'O'; /* identify unit for debug */ -const DEVICE *dbdev = (card == CIN) ? &ipli_dev : &iplo_dev; /* identify device for debug */ -const char *iotype[] = { "Status", "Command" }; -const IOSIG base_signal = IOBASE (signal); /* derive base signal */ +const CARD_INDEX card = dibptr->card_index; /* set card selector */ +UNIT *const uptr = &(ipl_unit [card]); /* associated unit pointer */ +const char *iotype [] = { "Status", "Command" }; int32 sta; -char msg[2]; +char msg [2]; +static uint32 crs_count [CARD_COUNT] = { 0, 0 }; /* per-card cntrs for ioCRS repeat */ +IOSIGNAL signal; +IOCYCLE working_set = IOADDSIR (signal_set); /* add ioSIR if needed */ -switch (base_signal) { /* dispatch base I/O signal */ +if (crs_count [card] && !(signal_set & ioCRS)) { /* counting CRSes and not present? */ + if (DEBUG_PRJ (dptrs [card], DEB_CMDS)) /* report reset count */ + fprintf (sim_deb, ">>%s cmds: [CRS] Control cleared %d times\n", + dptrs [card]->name, crs_count [card]); - case ioCLF: /* clear flag flip-flop */ - ipl_flag [card] = ipl_flagbuf [card] = CLEAR; - break; - - - case ioSTF: /* set flag flip-flop */ - case ioENF: /* enable flag */ - ipl_flag [card] = ipl_flagbuf [card] = SET; - break; - - - case ioSFC: /* skip if flag is clear */ - setSKF (!ipl_flag [card]); - break; - - - case ioSFS: /* skip if flag is set */ - setSKF (ipl_flag [card]); - break; - - - case ioIOI: /* I/O data input */ - data = uptr->IBUF; /* get return data */ - - if (DEBUG_PRJ (dbdev, DEB_CPU)) - fprintf (sim_deb, ">>IPL%c LIx: %s = %06o\n", uc, iotype [card ^ 1], data); - break; - - - case ioIOO: /* I/O data output */ - uptr->OBUF = data; - - if (DEBUG_PRJ (dbdev, DEB_CPU)) - fprintf (sim_deb, ">>IPL%c OTx: %s = %06o\n", uc, iotype [card], data); - break; - - - case ioPOPIO: /* power-on preset to I/O */ - ipl_flag [card] = ipl_flagbuf [card] = SET; /* set flag buffer and flag */ - uptr->OBUF = 0; /* clear output buffer */ - /* fall into CRS handler */ - - case ioCRS: /* control reset */ - ipl_control [card] = CLEAR; /* clear control */ - - if (DEBUG_PRJ (dbdev, DEB_CMDS)) - fprintf (sim_deb, ">>IPL%c CRS: Control cleared\n", uc); - break; - - - case ioCLC: /* clear control flip-flop */ - ipl_control [card] = CLEAR; /* clear ctl */ - - if (DEBUG_PRJ (dbdev, DEB_CMDS)) - fprintf (sim_deb, ">>IPL%c CLC: Control cleared\n", uc); - break; - - - case ioSTC: /* set control flip-flop */ - ipl_control [card] = SET; /* set ctl */ - - if (DEBUG_PRJ (dbdev, DEB_CMDS)) - fprintf (sim_deb, ">>IPL%c STC: Control set\n", uc); - - if (uptr->flags & UNIT_ATT) { /* attached? */ - if ((uptr->flags & UNIT_ESTB) == 0) /* established? */ - if (!ipl_check_conn (uptr)) { /* not established? */ - data = STOP_NOCONN << IOT_V_REASON; /* lose */ - break; - } - - msg[0] = (uptr->OBUF >> 8) & 0377; - msg[1] = uptr->OBUF & 0377; - sta = sim_write_sock (uptr->DSOCKET, msg, 2); - - if (DEBUG_PRJ (dbdev, DEB_XFER)) - fprintf (sim_deb, - ">>IPL%c STC: Socket write = %06o, status = %d\n", - uc, uptr->OBUF, sta); - - if (sta == SOCKET_ERROR) { - printf ("IPL: socket write error\n"); - data = SCPE_IOERR << IOT_V_REASON; - break; - } - - sim_os_sleep (0); - } - - else if (uptr->flags & UNIT_DIAG) { /* diagnostic mode? */ - ipl_unit [card ^ 1].IBUF = uptr->OBUF; /* output to other */ - iplio (ipl_dib [card ^ 1].devno, ioENF, 0); /* set other flag */ - } - - else - data = SCPE_UNATT << IOT_V_REASON; /* lose */ - break; - - - case ioEDT: /* end data transfer */ - if ((cpu_unit.flags & UNIT_IOP) && /* are we the IOP? */ - ((IOSIG) data == ioIOO) && (card == CIN)) { /* and doing output on input card? */ - - if (DEBUG_PRJ (dbdev, DEB_CMDS)) - fprintf (sim_deb, - ">>IPL%c EDT: Delaying DMA completion interrupt for %d msec\n", - uc, ipl_edtdelay); - - sim_os_ms_sleep (ipl_edtdelay); /* delay completion */ - } - break; - - - case ioSIR: /* set interrupt request */ - setPRL (select_code, !(ipl_control [card] & ipl_flag [card])); - setIRQ (select_code, ipl_control [card] & ipl_flag [card] & ipl_flagbuf [card]); - setSRQ (select_code, ipl_flag [card]); - break; - - - case ioIAK: /* interrupt acknowledge */ - ipl_flagbuf [card] = CLEAR; - break; - - - default: /* all other signals */ - break; /* are ignored */ + crs_count [card] = 0; /* clear counter */ } +while (working_set) { + signal = IONEXT (working_set); /* isolate next signal */ -if (signal > ioCLF) /* multiple signals? */ - iplio (select_code, ioCLF, 0); /* issue CLF */ -else if (signal > ioSIR) /* signal affected interrupt status? */ - iplio (select_code, ioSIR, 0); /* set interrupt request */ + switch (signal) { /* dispatch I/O signal */ -return data; + case ioCLF: /* clear flag flip-flop */ + ipl [card].flag = ipl [card].flagbuf = CLEAR; + break; + + + case ioSTF: /* set flag flip-flop */ + case ioENF: /* enable flag */ + ipl [card].flag = ipl [card].flagbuf = SET; + break; + + + case ioSFC: /* skip if flag is clear */ + setstdSKF (ipl [card]); + break; + + + case ioSFS: /* skip if flag is set */ + setstdSKF (ipl [card]); + break; + + + case ioIOI: /* I/O data input */ + stat_data = IORETURN (SCPE_OK, uptr->IBUF); /* get return data */ + + if (DEBUG_PRJ (dptrs [card], DEB_CPU)) + fprintf (sim_deb, ">>%s cpu: [LIx] %s = %06o\n", dptrs [card]->name, iotype [card ^ 1], uptr->IBUF); + break; + + + case ioIOO: /* I/O data output */ + uptr->OBUF = IODATA (stat_data); /* clear supplied status */ + + if (DEBUG_PRJ (dptrs [card], DEB_CPU)) + fprintf (sim_deb, ">>%s cpu: [OTx] %s = %06o\n", dptrs [card]->name, iotype [card], uptr->OBUF); + break; + + + case ioPOPIO: /* power-on preset to I/O */ + ipl [card].flag = ipl [card].flagbuf = SET; /* set flag buffer and flag */ + uptr->OBUF = 0; /* clear output buffer */ + break; + + + case ioCRS: /* control reset */ + if (crs_count [card] == 0) /* first reset? */ + ipl [card].control = CLEAR; /* clear control */ + + crs_count [card] = crs_count [card] + 1; /* increment count */ + break; + + + case ioCLC: /* clear control flip-flop */ + ipl [card].control = CLEAR; /* clear ctl */ + + if (DEBUG_PRJ (dptrs [card], DEB_CMDS)) + fprintf (sim_deb, ">>%s cmds: [CLC] Control cleared\n", dptrs [card]->name); + break; + + + case ioSTC: /* set control flip-flop */ + if (DEBUG_PRJ (dptrs [card], DEB_CMDS)) + fprintf (sim_deb, ">>%s cmds: [STC] Control set\n", dptrs [card]->name); + + if (uptr->flags & UNIT_ATT) { /* attached? */ + if (!ipl_check_conn (uptr)) /* not established? */ + return IORETURN (STOP_NOCONN, 0); /* lose */ + + msg [0] = (uptr->OBUF >> 8) & 0377; + msg [1] = uptr->OBUF & 0377; + sta = sim_write_sock (uptr->DSOCKET, msg, 2); + + if (DEBUG_PRJ (dptrs [card], DEB_XFER)) + fprintf (sim_deb, + ">>%s xfer: [STC] Socket write = %06o, status = %d\n", + dptrs [card]->name, uptr->OBUF, sta); + + if (sta == SOCKET_ERROR) { + printf ("IPL socket write error\n"); + return IORETURN (SCPE_IOERR, 0); + } + + ipl [card].control = SET; /* set ctl */ + + sim_os_sleep (0); + } + + else if (uptr->flags & UNIT_DIAG) { /* diagnostic mode? */ + ipl [card].control = SET; /* set ctl */ + ipl_unit [card ^ 1].IBUF = uptr->OBUF; /* output to other */ + iplio ((DIB *) dptrs [card ^ 1]->ctxt, ioENF, 0); /* set other flag */ + } + + else + return IORETURN (SCPE_UNATT, 0); /* lose */ + break; + + + case ioEDT: /* end data transfer */ + if ((cpu_unit.flags & UNIT_IOP) && /* are we the IOP? */ + (signal_set & ioIOO) && /* and doing output? */ + (card == ipli)) { /* on the input card? */ + + if (DEBUG_PRJ (dptrs [card], DEB_CMDS)) + fprintf (sim_deb, + ">>%s cmds: [EDT] Delaying DMA completion interrupt for %d msec\n", + dptrs [card]->name, ipl_edtdelay); + + sim_os_ms_sleep (ipl_edtdelay); /* delay completion */ + } + break; + + + case ioSIR: /* set interrupt request */ + setstdPRL (ipl [card]); + setstdIRQ (ipl [card]); + setstdSRQ (ipl [card]); + break; + + + case ioIAK: /* interrupt acknowledge */ + ipl [card].flagbuf = CLEAR; + break; + + + default: /* all other signals */ + break; /* are ignored */ + } + + working_set = working_set & ~signal; /* remove current signal from set */ + } + +return stat_data; } @@ -417,46 +452,46 @@ return data; t_stat ipl_svc (UNIT *uptr) { -CARD card; +CARD_INDEX card; int32 nb; -char msg[2], uc; -DEVICE *dbdev; /* device ptr for debug */ +char msg [2]; + +if ((uptr->flags & UNIT_ATT) == 0) /* not attached? */ + return SCPE_OK; -if ((uptr->flags & UNIT_ATT) == 0) return SCPE_OK; /* not attached? */ sim_activate (uptr, ipl_ptime); /* reactivate */ -if ((uptr->flags & UNIT_ESTB) == 0) /* not established? */ - if (!ipl_check_conn (uptr)) /* check for conn */ - return SCPE_OK; /* cot connected */ +if (!ipl_check_conn (uptr)) /* check for conn */ + return SCPE_OK; /* not connected */ nb = sim_read_sock (uptr->DSOCKET, msg, ((uptr->flags & UNIT_HOLD)? 1: 2)); + if (nb < 0) { /* connection closed? */ - printf ("IPL: socket read error\n"); + printf ("IPL socket read error\n"); return SCPE_IOERR; } -if (nb == 0) return SCPE_OK; /* no data? */ + +else if (nb == 0) /* no data? */ + return SCPE_OK; card = (uptr == &iplo_unit); /* set card selector */ if (uptr->flags & UNIT_HOLD) { /* holdover byte? */ - uptr->IBUF = (ipl_hold[card] << 8) | (((int32) msg[0]) & 0377); + uptr->IBUF = (ipl [card].hold << 8) | (((int32) msg [0]) & 0377); uptr->flags = uptr->flags & ~UNIT_HOLD; } else if (nb == 1) { - ipl_hold[card] = ((int32) msg[0]) & 0377; + ipl [card].hold = ((int32) msg [0]) & 0377; uptr->flags = uptr->flags | UNIT_HOLD; } -else uptr->IBUF = ((((int32) msg[0]) & 0377) << 8) | - (((int32) msg[1]) & 0377); +else + uptr->IBUF = ((((int32) msg [0]) & 0377) << 8) | (((int32) msg [1]) & 0377); -iplio (ipl_dib [card].devno, ioENF, 0); /* set flag */ +iplio ((DIB *) dptrs [card]->ctxt, ioENF, 0); /* set flag */ -uc = (card == CIN) ? 'I' : 'O'; /* identify unit for debug */ -dbdev = (card == CIN) ? &ipli_dev : &iplo_dev; /* identify device for debug */ - -if (DEBUG_PRJ (dbdev, DEB_XFER)) - fprintf (sim_deb, ">>IPL%c svc: Socket read = %06o, status = %d\n", - uc, uptr->IBUF, nb); +if (DEBUG_PRJ (dptrs [card], DEB_XFER)) + fprintf (sim_deb, ">>%s xfer: Socket read = %06o, status = %d\n", + dptrs [card]->name, uptr->IBUF, nb); return SCPE_OK; } @@ -466,15 +501,23 @@ t_bool ipl_check_conn (UNIT *uptr) { SOCKET sock; -if (uptr->flags & UNIT_ESTB) return TRUE; /* established? */ +if (uptr->flags & UNIT_ESTB) /* established? */ + return TRUE; + if (uptr->flags & UNIT_ACTV) { /* active connect? */ - if (sim_check_conn (uptr->DSOCKET, 0) <= 0) return FALSE; + if (sim_check_conn (uptr->DSOCKET, 0) <= 0) + return FALSE; } + else { sock = sim_accept_conn (uptr->LSOCKET, NULL); /* poll connect */ - if (sock == INVALID_SOCKET) return FALSE; /* got a live one? */ + + if (sock == INVALID_SOCKET) /* got a live one? */ + return FALSE; + uptr->DSOCKET = sock; /* save data socket */ } + uptr->flags = uptr->flags | UNIT_ESTB; /* conn established */ return TRUE; } @@ -493,17 +536,15 @@ return TRUE; t_stat ipl_reset (DEVICE *dptr) { UNIT *uptr = dptr->units; +DIB *dibptr = (DIB *) dptr->ctxt; /* DIB pointer */ +CARD_INDEX card = dibptr->card_index; /* card number */ -hp_enbdis_pair (dptr, /* make pair cons */ - (dptr == &ipli_dev)? &iplo_dev: &ipli_dev); +hp_enbdis_pair (dptr, dptrs [card ^ 1]); /* make pair cons */ -if (sim_switches & SWMASK ('P')) /* PON reset? */ +if (sim_switches & SWMASK ('P')) /* initialization reset? */ uptr->IBUF = uptr->OBUF = 0; /* clr buffers */ -if (dptr == &ipli_dev) /* input channel reset? */ - iplio (ipli_dib.devno, ioPOPIO, 0); /* send POPIO signal */ -else /* output channel reset */ - iplio (iplo_dib.devno, ioPOPIO, 0); /* send POPIO signal */ +IOPRESET (dibptr); /* PRESET device (does not use PON) */ if (uptr->flags & UNIT_ATT) /* socket attached? */ sim_activate (uptr, POLL_FIRST); /* activate first poll "immediately" */ @@ -529,31 +570,39 @@ char *tptr; t_stat r; r = get_ipaddr (cptr, &ipa, &ipp); -if ((r != SCPE_OK) || (ipp == 0)) return SCPE_ARG; +if ((r != SCPE_OK) || (ipp == 0)) + return SCPE_ARG; oldf = uptr->flags; -if (oldf & UNIT_ATT) ipl_detach (uptr); +if (oldf & UNIT_ATT) + ipl_detach (uptr); if ((sim_switches & SWMASK ('C')) || ((sim_switches & SIM_SW_REST) && (oldf & UNIT_ACTV))) { - if (ipa == 0) ipa = 0x7F000001; + if (ipa == 0) + ipa = 0x7F000001; newsock = sim_connect_sock (ipa, ipp); - if (newsock == INVALID_SOCKET) return SCPE_IOERR; + if (newsock == INVALID_SOCKET) + return SCPE_IOERR; printf ("Connecting to IP address %d.%d.%d.%d, port %d\n", (ipa >> 24) & 0xff, (ipa >> 16) & 0xff, (ipa >> 8) & 0xff, ipa & 0xff, ipp); - if (sim_log) fprintf (sim_log, - "Connecting to IP address %d.%d.%d.%d, port %d\n", - (ipa >> 24) & 0xff, (ipa >> 16) & 0xff, - (ipa >> 8) & 0xff, ipa & 0xff, ipp); + if (sim_log) + fprintf (sim_log, + "Connecting to IP address %d.%d.%d.%d, port %d\n", + (ipa >> 24) & 0xff, (ipa >> 16) & 0xff, + (ipa >> 8) & 0xff, ipa & 0xff, ipp); uptr->flags = uptr->flags | UNIT_ACTV; uptr->LSOCKET = 0; uptr->DSOCKET = newsock; } else { - if (ipa != 0) return SCPE_ARG; + if (ipa != 0) + return SCPE_ARG; newsock = sim_master_sock (ipp); - if (newsock == INVALID_SOCKET) return SCPE_IOERR; + if (newsock == INVALID_SOCKET) + return SCPE_IOERR; printf ("Listening on port %d\n", ipp); - if (sim_log) fprintf (sim_log, "Listening on port %d\n", ipp); + if (sim_log) + fprintf (sim_log, "Listening on port %d\n", ipp); uptr->flags = uptr->flags & ~UNIT_ACTV; uptr->LSOCKET = newsock; uptr->DSOCKET = 0; @@ -570,12 +619,14 @@ uptr->filename = tptr; /* save */ sim_activate (uptr, POLL_FIRST); /* activate first poll "immediately" */ if (sim_switches & SWMASK ('W')) { /* wait? */ for (i = 0; i < 30; i++) { /* check for 30 sec */ - if (t = ipl_check_conn (uptr)) break; /* established? */ + if (t = ipl_check_conn (uptr)) /* established? */ + break; if ((i % 10) == 0) /* status every 10 sec */ printf ("Waiting for connnection\n"); sim_os_sleep (1); /* sleep 1 sec */ } - if (t) printf ("Connection established\n"); + if (t) + printf ("Connection established\n"); } return SCPE_OK; } @@ -584,13 +635,18 @@ return SCPE_OK; t_stat ipl_detach (UNIT *uptr) { -if (!(uptr->flags & UNIT_ATT)) return SCPE_OK; /* attached? */ -if (uptr->flags & UNIT_ACTV) sim_close_sock (uptr->DSOCKET, 1); +if (!(uptr->flags & UNIT_ATT)) /* attached? */ + return SCPE_OK; + +if (uptr->flags & UNIT_ACTV) + sim_close_sock (uptr->DSOCKET, 1); + else { if (uptr->flags & UNIT_ESTB) /* if established, */ sim_close_sock (uptr->DSOCKET, 0); /* close data socket */ sim_close_sock (uptr->LSOCKET, 1); /* closen listen socket */ } + free (uptr->filename); /* free string */ uptr->filename = NULL; uptr->LSOCKET = 0; @@ -604,9 +660,12 @@ return SCPE_OK; t_stat ipl_dscln (UNIT *uptr, int32 val, char *cptr, void *desc) { -if (cptr) return SCPE_ARG; -if (((uptr->flags & UNIT_ATT) == 0) || (uptr->flags & UNIT_ACTV) || - ((uptr->flags & UNIT_ESTB) == 0)) return SCPE_NOFNC; +if (cptr) + return SCPE_ARG; +if (((uptr->flags & UNIT_ATT) == 0) || + (uptr->flags & UNIT_ACTV) || + ((uptr->flags & UNIT_ESTB) == 0)) + return SCPE_NOFNC; sim_close_sock (uptr->DSOCKET, 0); uptr->DSOCKET = 0; uptr->flags = uptr->flags & ~UNIT_ESTB; @@ -705,14 +764,14 @@ static const BOOT_ROM ipl_rom = { t_stat ipl_boot (int32 unitno, DEVICE *dptr) { -const int32 devi = ipli_dib.devno; -const int32 devp = ptr_dib.devno; +const int32 devi = ipli_dib.select_code; +const int32 devp = ptr_dib.select_code; ibl_copy (ipl_rom, devi); /* copy bootstrap to memory */ SR = (devi << IBL_V_DEV) | devp; /* set SR */ WritePW (PC + MAX_BASE, (~PC + 1) & DMASK); /* fix ups */ -WritePW (PC + IPL_PNTR, ipl_rom[IPL_PNTR] | PC); -WritePW (PC + PTR_PNTR, ipl_rom[PTR_PNTR] | PC); +WritePW (PC + IPL_PNTR, ipl_rom [IPL_PNTR] | PC); +WritePW (PC + PTR_PNTR, ipl_rom [PTR_PNTR] | PC); WritePW (PC + IPL_DEVA, devi); WritePW (PC + PTR_DEVA, devp); return SCPE_OK; diff --git a/HP2100/hp2100_lps.c b/HP2100/hp2100_lps.c index 5d165358..165c2190 100644 --- a/HP2100/hp2100_lps.c +++ b/HP2100/hp2100_lps.c @@ -1,6 +1,6 @@ /* hp2100_lps.c: HP 2100 12653A/2767 line printer simulator - Copyright (c) 1993-2008, Robert M. Supnik + Copyright (c) 1993-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"), @@ -26,6 +26,10 @@ LPS 12653A 2767 line printer 12566B microcircuit interface with loopback diagnostic connector + 28-Mar-11 JDB Tidied up signal handling + 26-Oct-10 JDB Changed I/O signal handler for revised signal model + Revised detection of CLC at last DMA cycle + 19-Oct-10 JDB Corrected 12566B (DIAG mode) jumper settings 26-Jun-08 JDB Rewrote device I/O to model backplane signals 10-May-07 RMS Added UNIT_TEXT flag 11-Jan-07 JDB CLC cancels I/O event if DIAG (jumper W9 in "A" pos) @@ -58,16 +62,24 @@ This module simulates two different devices. In "diagnostic mode," it - simulates a 12566B microcircuit interface card with a loopback connector and - the jumpers set as required for execution of the General Purpose Register - diagnostic. In non-diagnostic mode, it simulates a 12653A line printer - interface card and a 2767 line printer. + simulates a 12566B microcircuit interface card with a loopback connector. In + non-diagnostic mode, it simulates a 12653A line printer interface card and a + 2767 line printer. + + In diagnostic mode, the 12566B interface has a loopback connector that ties + the output data lines to the input data lines and the device command output + to the device flag input. In addition, card configuration jumpers are set as + needed for the diagnostic programs. + + Jumper settings depend on the CPU model. For the 2114/15/16 CPUs, jumper W1 + is installed in position B and jumper W2 in position C. In these positions, + the card flag sets two instructions after the STC, allowing DMA to steal + every third cycle. For the 2100 and 1000 CPUs, jumper W1 is installed in + position C and jumper W2 in position B. In these positions, the card flag + sets one instruction after the STC, allowing DMA to steal every other cycle. + For all CPUs, jumpers W3 and W4 are installed in position B, W5-W8 are + installed, and W9 is installed in position A. - The 12566B interface with the loopback connector ties the device command - output to the device flag input. Setting control therefore causes device - flag to set almost immediately. Device command is active only during that - interim. Under simulation, the loopback occurs within the STC handler, and - CMD is never set. The 2767 impact printer has a rotating drum with 80 columns of 64 raised characters. ASCII codes 32 through 95 (SPACE through "_") form the print @@ -144,9 +156,11 @@ #define UNIT_POWEROFF (1 << UNIT_V_POWEROFF) #define UNIT_OFFLINE (1 << UNIT_V_OFFLINE) -FLIP_FLOP lps_control = CLEAR; -FLIP_FLOP lps_flag = CLEAR; -FLIP_FLOP lps_flagbuf = CLEAR; +struct { + FLIP_FLOP control; /* control flip-flop */ + FLIP_FLOP flag; /* flag flip-flop */ + FLIP_FLOP flagbuf; /* flag buffer flip-flop */ + } lps = { CLEAR, CLEAR, CLEAR }; int32 lps_ccnt = 0; /* character count */ int32 lps_lcnt = 0; /* line count */ @@ -190,7 +204,9 @@ const TIMESET lps_times[2] = { }; DEVICE lps_dev; -uint32 lpsio (uint32 select_code, IOSIG signal, uint32 data); + +IOHANDLER lpsio; + t_stat lps_svc (UNIT *uptr); t_stat lps_reset (DEVICE *dptr); t_stat lps_restart (UNIT *uptr, int32 value, char *cptr, void *desc); @@ -207,7 +223,7 @@ t_stat lps_show_timing (FILE *st, UNIT *uptr, int32 val, void *desc); lps_reg LPS register list */ -DIB lps_dib = { LPS, &lpsio }; +DIB lps_dib = { &lpsio, LPS }; UNIT lps_unit = { UDATA (&lps_svc, UNIT_SEQ+UNIT_ATTABLE+UNIT_DISABLE+UNIT_TEXT, 0) @@ -217,9 +233,9 @@ REG lps_reg[] = { { ORDATA (BUF, lps_unit.buf, 16) }, { ORDATA (STA, lps_sta, 16) }, { ORDATA (POWER, lps_power, 2), REG_RO }, - { FLDATA (CTL, lps_control, 0) }, - { FLDATA (FLG, lps_flag, 0) }, - { FLDATA (FBF, lps_flagbuf, 0) }, + { FLDATA (CTL, lps.control, 0) }, + { FLDATA (FLG, lps.flag, 0) }, + { FLDATA (FBF, lps.flagbuf, 0) }, { DRDATA (CCNT, lps_ccnt, 7), PV_LEFT }, { DRDATA (LCNT, lps_lcnt, 7), PV_LEFT }, { DRDATA (POS, lps_unit.pos, T_ADDR_W), PV_LEFT }, @@ -229,7 +245,7 @@ REG lps_reg[] = { { DRDATA (RTIME, lps_rtime, 24), PV_LEFT }, { FLDATA (TIMING, lps_timing, 0), REG_HRO }, { FLDATA (STOP_IOE, lps_stopioe, 0) }, - { ORDATA (DEVNO, lps_dib.devno, 6), REG_HRO }, + { ORDATA (DEVNO, lps_dib.select_code, 6), REG_HRO }, { NULL } }; @@ -260,164 +276,174 @@ DEVICE lps_dev = { }; -/* I/O signal handler */ +/* I/O signal handler. -uint32 lpsio (uint32 select_code, IOSIG signal, uint32 data) + Implementation note: + + 1. The 211x DMA diagnostic expects that a programmed STC and CLC sequence + will set the card flag in two instructions, whereas a last-DMA-cycle + assertion of STC and CLC simultaneously will not. +*/ + +uint32 lpsio (DIB *dibptr, IOCYCLE signal_set, uint32 stat_data) { -const t_bool clf = (signal > ioCLF); -const IOSIG base_signal = IOBASE (signal); /* derive base signal */ int32 sched; +IOSIGNAL signal; +IOCYCLE working_set = IOADDSIR (signal_set); /* add ioSIR if needed */ -switch (base_signal) { /* dispatch base I/O signal */ +while (working_set) { + signal = IONEXT (working_set); /* isolate next signal */ - case ioCLF: /* clear flag flip-flop */ - lps_flag = lps_flagbuf = CLEAR; - break; + switch (signal) { /* dispatch I/O signal */ + + case ioCLF: /* clear flag flip-flop */ + lps.flag = lps.flagbuf = CLEAR; + break; - case ioSTF: /* set flag flip-flop */ - case ioENF: /* enable flag */ - lps_flag = lps_flagbuf = SET; - break; + case ioSTF: /* set flag flip-flop */ + case ioENF: /* enable flag */ + lps.flag = lps.flagbuf = SET; + break; - case ioSFC: /* skip if flag is clear */ - setstdSKF (lps); - break; + case ioSFC: /* skip if flag is clear */ + setstdSKF (lps); + break; - case ioSFS: /* skip if flag is set */ - setstdSKF (lps); - break; + case ioSFS: /* skip if flag is set */ + setstdSKF (lps); + break; - case ioIOI: /* I/O data input */ - if ((lps_unit.flags & UNIT_DIAG) == 0) { /* real lpt? */ - if (lps_power == LPS_ON) { /* power on? */ - if (((lps_unit.flags & UNIT_ATT) == 0) || /* paper out? */ - (lps_unit.flags & UNIT_OFFLINE) || /* offline? */ - sim_is_active (&lps_unit)) lps_sta = LPS_BUSY; + case ioIOI: /* I/O data input */ + if ((lps_unit.flags & UNIT_DIAG) == 0) { /* real lpt? */ + if (lps_power == LPS_ON) { /* power on? */ + if (((lps_unit.flags & UNIT_ATT) == 0) || /* paper out? */ + (lps_unit.flags & UNIT_OFFLINE) || /* offline? */ + sim_is_active (&lps_unit)) lps_sta = LPS_BUSY; - else - lps_sta = 0; - } - - else - lps_sta = LPS_PWROFF; - } - - data = lps_sta; /* diag, rtn status */ - - if (DEBUG_PRS (lps_dev)) - fprintf (sim_deb, ">>LPS LIx: Status %06o returned\n", data); - break; - - - case ioIOO: /* I/O data output */ - if (DEBUG_PRS (lps_dev)) - fprintf (sim_deb, ">>LPS OTx: Character %06o output\n", data); - - lps_unit.buf = data; - break; - - - case ioPOPIO: /* power-on preset to I/O */ - lps_flag = lps_flagbuf = SET; /* set flag and flag buffer */ - lps_unit.buf = 0; /* clear output buffer */ - /* fall into CRS handler */ - - case ioCRS: /* control reset */ - lps_control = CLEAR; /* clear control */ - sim_cancel (&lps_unit); /* deactivate unit */ - break; - - - case ioCLC: /* clear control flip-flop */ - lps_control = CLEAR; - - if ((lps_unit.flags & UNIT_DIAG) && clf) /* diagnostic mode and clearing flag? */ - sim_cancel (&lps_unit); /* prevent FLG/SRQ */ - break; - - - case ioSTC: /* set control flip-flop */ - lps_control = SET; /* set control */ - - if (lps_unit.flags & UNIT_DIAG) { /* diagnostic? */ - lps_sta = lps_unit.buf; /* loop back data */ - sim_activate (&lps_unit, 2); /* schedule flag */ - } - - else { /* real lpt, sched */ - if (DEBUG_PRS (lps_dev)) fprintf (sim_deb, - ">>LPS STC: Character %06o scheduled for line %d, column %d, ", - lps_unit.buf, lps_lcnt + 1, lps_ccnt + 1); - - if ((lps_unit.buf != '\f') && - (lps_unit.buf != '\n') && - (lps_unit.buf != '\r')) { /* normal char */ - lps_ccnt = lps_ccnt + 1; /* incr char counter */ - if (lps_ccnt % LPS_ZONECNT == 0) /* end of zone? */ - sched = lps_ptime; /* print zone */ - else - sched = lps_ctime; /* xfer char */ - } - - else { /* print cmd */ - if (lps_ccnt % LPS_ZONECNT == 0) /* last zone printed? */ - sched = lps_ctime; /* yes, so just char time */ - else - sched = lps_ptime; /* no, so print needed */ - - lps_ccnt = 0; /* reset char counter */ - - if (lps_unit.buf == '\n') { /* line advance */ - lps_lcnt = (lps_lcnt + 1) % LPS_PAGELNT; - - if (lps_lcnt > 0) - sched = sched + lps_stime; else - sched = sched + /* allow for perf skip */ - lps_stime * (LPS_FORMLNT - LPS_PAGELNT); + lps_sta = 0; } - else if (lps_unit.buf == '\f') { /* form advance */ - sched = sched + lps_stime * (LPS_FORMLNT - lps_lcnt); - lps_lcnt = 0; - } + else + lps_sta = LPS_PWROFF; } - sim_activate (&lps_unit, sched); + stat_data = IORETURN (SCPE_OK, lps_sta); /* diag, rtn status */ if (DEBUG_PRS (lps_dev)) - fprintf (sim_deb, "time = %d\n", sched); - } - break; + fprintf (sim_deb, ">>LPS LIx: Status %06o returned\n", lps_sta); + break; - case ioSIR: /* set interrupt request */ - setstdPRL (select_code, lps); /* set standard PRL signal */ - setstdIRQ (select_code, lps); /* set standard IRQ signal */ - setstdSRQ (select_code, lps); /* set standard SRQ signal */ - break; + case ioIOO: /* I/O data output */ + lps_unit.buf = IODATA (stat_data); + + if (DEBUG_PRS (lps_dev)) + fprintf (sim_deb, ">>LPS OTx: Character %06o output\n", lps_unit.buf); + break; - case ioIAK: /* interrupt acknowledge */ - lps_flagbuf = CLEAR; - break; + case ioPOPIO: /* power-on preset to I/O */ + lps.flag = lps.flagbuf = SET; /* set flag and flag buffer */ + lps_unit.buf = 0; /* clear output buffer */ + break; - default: /* all other signals */ - break; /* are ignored */ + case ioCRS: /* control reset */ + lps.control = CLEAR; /* clear control */ + sim_cancel (&lps_unit); /* deactivate unit */ + break; + + + case ioCLC: /* clear control flip-flop */ + lps.control = CLEAR; + break; + + + case ioSTC: /* set control flip-flop */ + lps.control = SET; /* set control */ + + if (lps_unit.flags & UNIT_DIAG) { /* diagnostic? */ + lps_sta = lps_unit.buf; /* loop back data */ + + if (!(signal_set & ioCLC)) /* CLC not asserted simultaneously? */ + if (UNIT_CPU_TYPE == UNIT_TYPE_211X) /* 2114/15/16 CPU? */ + sim_activate (&lps_unit, 3); /* schedule flag after two instructions */ + else /* 2100 or 1000 */ + sim_activate (&lps_unit, 2); /* schedule flag after next instruction */ + } + + else { /* real lpt, sched */ + if (DEBUG_PRS (lps_dev)) fprintf (sim_deb, + ">>LPS STC: Character %06o scheduled for line %d, column %d, ", + lps_unit.buf, lps_lcnt + 1, lps_ccnt + 1); + + if ((lps_unit.buf != '\f') && + (lps_unit.buf != '\n') && + (lps_unit.buf != '\r')) { /* normal char */ + lps_ccnt = lps_ccnt + 1; /* incr char counter */ + if (lps_ccnt % LPS_ZONECNT == 0) /* end of zone? */ + sched = lps_ptime; /* print zone */ + else + sched = lps_ctime; /* xfer char */ + } + + else { /* print cmd */ + if (lps_ccnt % LPS_ZONECNT == 0) /* last zone printed? */ + sched = lps_ctime; /* yes, so just char time */ + else + sched = lps_ptime; /* no, so print needed */ + + lps_ccnt = 0; /* reset char counter */ + + if (lps_unit.buf == '\n') { /* line advance */ + lps_lcnt = (lps_lcnt + 1) % LPS_PAGELNT; + + if (lps_lcnt > 0) + sched = sched + lps_stime; + else + sched = sched + /* allow for perf skip */ + lps_stime * (LPS_FORMLNT - LPS_PAGELNT); + } + + else if (lps_unit.buf == '\f') { /* form advance */ + sched = sched + lps_stime * (LPS_FORMLNT - lps_lcnt); + lps_lcnt = 0; + } + } + + sim_activate (&lps_unit, sched); + + if (DEBUG_PRS (lps_dev)) + fprintf (sim_deb, "time = %d\n", sched); + } + break; + + + case ioSIR: /* set interrupt request */ + setstdPRL (lps); /* set standard PRL signal */ + setstdIRQ (lps); /* set standard IRQ signal */ + setstdSRQ (lps); /* set standard SRQ signal */ + break; + + + case ioIAK: /* interrupt acknowledge */ + lps.flagbuf = CLEAR; + break; + + + default: /* all other signals */ + break; /* are ignored */ + } + + working_set = working_set & ~signal; /* remove current signal from set */ } - -if (signal > ioCLF) /* multiple signals? */ - lpsio (select_code, ioCLF, 0); /* issue CLF */ -else if (signal > ioSIR) /* signal affected interrupt status? */ - lpsio (select_code, ioSIR, 0); /* set interrupt request */ - -return data; +return stat_data; } @@ -435,17 +461,17 @@ if (lps_power == LPS_TURNING_ON) { /* printer warmed up? */ return SCPE_OK; /* done */ } if (uptr->flags & UNIT_DIAG) { /* diagnostic? */ - lpsio (lps_dib.devno, ioENF, 0); /* set flag */ + lpsio (&lps_dib, ioENF, 0); /* set flag */ return SCPE_OK; /* done */ } if ((uptr->flags & UNIT_ATT) == 0) /* attached? */ - return IORETURN (lps_stopioe, SCPE_UNATT); + return IOERROR (lps_stopioe, SCPE_UNATT); else if (uptr->flags & UNIT_OFFLINE) /* offline? */ - return IORETURN (lps_stopioe, STOP_OFFLINE); + return IOERROR (lps_stopioe, STOP_OFFLINE); else if (uptr->flags & UNIT_POWEROFF) /* powered off? */ - return IORETURN (lps_stopioe, STOP_PWROFF); + return IOERROR (lps_stopioe, STOP_PWROFF); -lpsio (lps_dib.devno, ioENF, 0); /* set flag */ +lpsio (&lps_dib, ioENF, 0); /* set flag */ if (((c < ' ') || (c > '_')) && /* non-printing char? */ (c != '\f') && (c != '\n') && (c != '\r')) { @@ -482,12 +508,12 @@ return SCPE_OK; t_stat lps_reset (DEVICE *dptr) { -if (sim_switches & SWMASK ('P')) { /* PON reset? */ +if (sim_switches & SWMASK ('P')) { /* power-on reset? */ lps_power = LPS_ON; /* power is on */ lps_set_timing (NULL, lps_timing, NULL, NULL); /* init timing set */ } -lpsio (lps_dib.devno, ioPOPIO, 0); /* send POPIO signal */ +IOPRESET (&lps_dib); /* PRESET device (does not use PON) */ lps_sta = 0; /* clear status */ sim_cancel (&lps_unit); /* deactivate unit */ @@ -511,7 +537,7 @@ return SCPE_OK; t_stat lps_restart (UNIT *uptr, int32 value, char *cptr, void *desc) { -if (lps_control && !sim_is_active (uptr)) +if (lps.control && !sim_is_active (uptr)) sim_activate (uptr, 0); /* reschedule I/O */ return SCPE_OK; } diff --git a/HP2100/hp2100_lpt.c b/HP2100/hp2100_lpt.c index b2f67439..6122841d 100644 --- a/HP2100/hp2100_lpt.c +++ b/HP2100/hp2100_lpt.c @@ -1,6 +1,6 @@ /* hp2100_lpt.c: HP 2100 12845B line printer simulator - Copyright (c) 1993-2008, Robert M. Supnik + Copyright (c) 1993-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"), @@ -25,6 +25,8 @@ LPT 12845B 2607 line printer + 28-Mar-11 JDB Tidied up signal handling + 26-Oct-10 JDB Changed I/O signal handler for revised signal model 26-Jun-08 JDB Rewrote device I/O to model backplane signals Changed CTIME register width to match documentation 22-Jan-07 RMS Added UNIT_TEXT flag @@ -89,9 +91,11 @@ #define UNIT_POWEROFF (1 << UNIT_V_POWEROFF) #define UNIT_OFFLINE (1 << UNIT_V_OFFLINE) -FLIP_FLOP lpt_control = CLEAR; -FLIP_FLOP lpt_flag = CLEAR; -FLIP_FLOP lpt_flagbuf = CLEAR; +struct { + FLIP_FLOP control; /* control flip-flop */ + FLIP_FLOP flag; /* flag flip-flop */ + FLIP_FLOP flagbuf; /* flag buffer flip-flop */ + } lpt = { CLEAR, CLEAR, CLEAR }; int32 lpt_ctime = 4; /* char time */ int32 lpt_ptime = 10000; /* print time */ @@ -102,7 +106,9 @@ static int32 lpt_cct[8] = { }; DEVICE lpt_dev; -uint32 lptio (uint32 select_code, IOSIG signal, uint32 data); + +IOHANDLER lptio; + t_stat lpt_svc (UNIT *uptr); t_stat lpt_reset (DEVICE *dptr); t_stat lpt_restart (UNIT *uptr, int32 value, char *cptr, void *desc); @@ -115,7 +121,7 @@ t_stat lpt_attach (UNIT *uptr, char *cptr); lpt_reg LPT register list */ -DIB lpt_dib = { LPT, &lptio }; +DIB lpt_dib = { &lptio, LPT }; UNIT lpt_unit = { UDATA (&lpt_svc, UNIT_SEQ+UNIT_ATTABLE+UNIT_DISABLE+UNIT_TEXT, 0) @@ -123,15 +129,15 @@ UNIT lpt_unit = { REG lpt_reg[] = { { ORDATA (BUF, lpt_unit.buf, 7) }, - { FLDATA (CTL, lpt_control, 0) }, - { FLDATA (FLG, lpt_flag, 0) }, - { FLDATA (FBF, lpt_flagbuf, 0) }, + { FLDATA (CTL, lpt.control, 0) }, + { FLDATA (FLG, lpt.flag, 0) }, + { FLDATA (FBF, lpt.flagbuf, 0) }, { DRDATA (LCNT, lpt_lcnt, 7) }, { DRDATA (POS, lpt_unit.pos, T_ADDR_W), PV_LEFT }, { DRDATA (CTIME, lpt_ctime, 24), PV_LEFT }, { DRDATA (PTIME, lpt_ptime, 24), PV_LEFT }, { FLDATA (STOP_IOE, lpt_stopioe, 0) }, - { ORDATA (DEVNO, lpt_dib.devno, 6), REG_HRO }, + { ORDATA (DEVNO, lpt_dib.select_code, 6), REG_HRO }, { NULL } }; @@ -156,101 +162,102 @@ DEVICE lpt_dev = { /* I/O signal handler */ -uint32 lptio (uint32 select_code, IOSIG signal, uint32 data) +uint32 lptio (DIB *dibptr, IOCYCLE signal_set, uint32 stat_data) { -const IOSIG base_signal = IOBASE (signal); /* derive base signal */ +uint16 data; +IOSIGNAL signal; +IOCYCLE working_set = IOADDSIR (signal_set); /* add ioSIR if needed */ -switch (base_signal) { /* dispatch base I/O signal */ +while (working_set) { + signal = IONEXT (working_set); /* isolate next signal */ - case ioCLF: /* clear flag flip-flop */ - lpt_flag = lpt_flagbuf = CLEAR; - break; + switch (signal) { /* dispatch I/O signal */ + + case ioCLF: /* clear flag flip-flop */ + lpt.flag = lpt.flagbuf = CLEAR; + break; - case ioSTF: /* set flag flip-flop */ - case ioENF: /* enable flag */ - lpt_flag = lpt_flagbuf = SET; - break; + case ioSTF: /* set flag flip-flop */ + case ioENF: /* enable flag */ + lpt.flag = lpt.flagbuf = SET; + break; - case ioSFC: /* skip if flag is clear */ - setstdSKF (lpt); - break; + case ioSFC: /* skip if flag is clear */ + setstdSKF (lpt); + break; - case ioSFS: /* skip if flag is set */ - setstdSKF (lpt); - break; + case ioSFS: /* skip if flag is set */ + setstdSKF (lpt); + break; - case ioIOI: /* I/O data input */ - if (lpt_unit.flags & UNIT_POWEROFF) /* power off? */ - data = LPT_PWROFF; + case ioIOI: /* I/O data input */ + data = 0; - else if (!(lpt_unit.flags & UNIT_OFFLINE)) { /* online? */ - if (lpt_unit.flags & UNIT_ATT) { /* paper loaded? */ - data = LPT_RDY; - if (!sim_is_active (&lpt_unit)) /* printer busy? */ - data = data | LPT_NBSY; + if (lpt_unit.flags & UNIT_POWEROFF) /* power off? */ + data = LPT_PWROFF; + + else if (!(lpt_unit.flags & UNIT_OFFLINE)) { /* online? */ + if (lpt_unit.flags & UNIT_ATT) { /* paper loaded? */ + data = LPT_RDY; + if (!sim_is_active (&lpt_unit)) /* printer busy? */ + data = data | LPT_NBSY; + } + + else if (lpt_lcnt == LPT_PAGELNT - 1) /* paper out, at BOF? */ + data = LPT_PAPO; } - else if (lpt_lcnt == LPT_PAGELNT - 1) /* paper out, at BOF? */ - data = LPT_PAPO; - } - - else - data = 0; - break; + stat_data = IORETURN (SCPE_OK, data); /* merge in return status */ + break; - case ioIOO: /* I/O data output */ - lpt_unit.buf = data & (LPT_CTL | 0177); - break; + case ioIOO: /* I/O data output */ + lpt_unit.buf = IODATA (stat_data) & (LPT_CTL | 0177); + break; - case ioPOPIO: /* power-on preset to I/O */ - lpt_flag = lpt_flagbuf = SET; /* set flag and flag buffer */ - lpt_unit.buf = 0; /* clear output buffer */ - /* fall into CRS handler */ + case ioPOPIO: /* power-on preset to I/O */ + lpt.flag = lpt.flagbuf = SET; /* set flag and flag buffer */ + lpt_unit.buf = 0; /* clear output buffer */ + break; - case ioCRS: /* control reset */ - /* fall into CLC handler */ - - case ioCLC: /* clear control flip-flop */ - lpt_control = CLEAR; - break; + case ioCRS: /* control reset */ + case ioCLC: /* clear control flip-flop */ + lpt.control = CLEAR; + break; - case ioSTC: /* set control flip-flop */ - lpt_control = SET; - sim_activate (&lpt_unit, /* schedule op */ - (lpt_unit.buf & LPT_CTL)? lpt_ptime: lpt_ctime); - break; + case ioSTC: /* set control flip-flop */ + lpt.control = SET; + sim_activate (&lpt_unit, /* schedule op */ + (lpt_unit.buf & LPT_CTL)? lpt_ptime: lpt_ctime); + break; - case ioSIR: /* set interrupt request */ - setstdPRL (select_code, lpt); /* set standard PRL signal */ - setstdIRQ (select_code, lpt); /* set standard IRQ signal */ - setstdSRQ (select_code, lpt); /* set standard SRQ signal */ - break; + case ioSIR: /* set interrupt request */ + setstdPRL (lpt); /* set standard PRL signal */ + setstdIRQ (lpt); /* set standard IRQ signal */ + setstdSRQ (lpt); /* set standard SRQ signal */ + break; - case ioIAK: /* interrupt acknowledge */ - lpt_flagbuf = CLEAR; - break; + case ioIAK: /* interrupt acknowledge */ + lpt.flagbuf = CLEAR; + break; - default: /* all other signals */ - break; /* are ignored */ + default: /* all other signals */ + break; /* are ignored */ + } + + working_set = working_set & ~signal; /* remove current signal from set */ } - -if (signal > ioCLF) /* multiple signals? */ - lptio (select_code, ioCLF, 0); /* issue CLF */ -else if (signal > ioSIR) /* signal affected interrupt status? */ - lptio (select_code, ioSIR, 0); /* set interrupt request */ - -return data; +return stat_data; } @@ -261,13 +268,13 @@ t_stat lpt_svc (UNIT *uptr) int32 i, skip, chan; if ((uptr->flags & UNIT_ATT) == 0) /* attached? */ - return IORETURN (lpt_stopioe, SCPE_UNATT); + return IOERROR (lpt_stopioe, SCPE_UNATT); else if (uptr->flags & UNIT_OFFLINE) /* offline? */ - return IORETURN (lpt_stopioe, STOP_OFFLINE); + return IOERROR (lpt_stopioe, STOP_OFFLINE); else if (uptr->flags & UNIT_POWEROFF) /* powered off? */ - return IORETURN (lpt_stopioe, STOP_PWROFF); + return IOERROR (lpt_stopioe, STOP_PWROFF); -lptio (lpt_dib.devno, ioENF, 0); /* set flag */ +lptio (&lpt_dib, ioENF, 0); /* set flag */ if (uptr->buf & LPT_CTL) { /* control word? */ if (uptr->buf & LPT_CHAN) { @@ -302,7 +309,7 @@ return SCPE_OK; t_stat lpt_reset (DEVICE *dptr) { -lptio (lpt_dib.devno, ioPOPIO, 0); /* send POPIO signal */ +IOPRESET (&lpt_dib); /* PRESET device (does not use PON) */ sim_cancel (&lpt_unit); /* deactivate unit */ return SCPE_OK; @@ -325,7 +332,7 @@ return SCPE_OK; t_stat lpt_restart (UNIT *uptr, int32 value, char *cptr, void *desc) { -if (lpt_control && !sim_is_active (uptr)) +if (lpt.control && !sim_is_active (uptr)) sim_activate (uptr, 0); /* reschedule I/O */ return SCPE_OK; } diff --git a/HP2100/hp2100_mpx.c b/HP2100/hp2100_mpx.c index 46ecf043..ab51adf0 100644 --- a/HP2100/hp2100_mpx.c +++ b/HP2100/hp2100_mpx.c @@ -1,6 +1,6 @@ /* hp2100_mpx.c: HP 12792C eight-channel asynchronous multiplexer simulator - Copyright (c) 2008, J. David Bryan + Copyright (c) 2008-2011, J. David Bryan Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), @@ -25,6 +25,8 @@ MPX 12792C 8-channel multiplexer card + 28-Mar-11 JDB Tidied up signal handling + 26-Oct-10 JDB Changed I/O signal handler for revised signal model 25-Nov-08 JDB Revised for new multiplexer library SHOW routines 14-Nov-08 JDB Cleaned up VC++ size mismatch warnings for zero assignments 03-Oct-08 JDB Fixed logic for ENQ/XOFF transmit wait @@ -517,10 +519,11 @@ uint32 mpx_portkey = 0; /* current port's key */ t_bool mpx_uien = FALSE; /* unsolicited interrupts enabled */ uint32 mpx_uicode = 0; /* unsolicited interrupt reason and port */ -FLIP_FLOP mpx_control = CLEAR; /* control flip-flop */ -FLIP_FLOP mpx_flag = CLEAR; /* flag flip-flop */ -FLIP_FLOP mpx_flagbuf = CLEAR; /* flag buffer flip-flop */ - +struct { + FLIP_FLOP control; /* control flip-flop */ + FLIP_FLOP flag; /* flag flip-flop */ + FLIP_FLOP flagbuf; /* flag buffer flip-flop */ + } mpx = { CLEAR, CLEAR, CLEAR }; /* Multiplexer per-line state variables */ @@ -581,7 +584,7 @@ static uint32 buf_avail (IO_OPER rw, uint32 port); /* Multiplexer global routines */ -uint32 mpx_io (uint32 select_code, IOSIG signal, uint32 data); +IOHANDLER mpx_io; t_stat mpx_line_svc (UNIT *uptr); t_stat mpx_cntl_svc (UNIT *uptr); @@ -632,7 +635,7 @@ int32 mpx_order [MPX_PORTS] = { -1 }; /* connection order TMLN mpx_ldsc [MPX_PORTS] = { { 0 } }; /* line descriptors */ TMXR mpx_desc = { MPX_PORTS, 0, 0, mpx_ldsc, mpx_order }; /* device descriptor */ -DIB mpx_dib = { MPX, &mpx_io }; +DIB mpx_dib = { &mpx_io, MPX }; DEVICE mpx_dev; @@ -682,10 +685,10 @@ REG mpx_reg [] = { { BRDATA (SEP, mpx_sep, 10, 10, MPX_PORTS * 2) }, { BRDATA (PUT, mpx_put, 10, 10, MPX_PORTS * 2) }, - { FLDATA (CTL, mpx_control, 0) }, - { FLDATA (FLG, mpx_flag, 0) }, - { FLDATA (FBF, mpx_flagbuf, 0) }, - { ORDATA (DEVNO, mpx_dib.devno, 6), REG_HRO }, + { FLDATA (CTL, mpx.control, 0) }, + { FLDATA (FLG, mpx.flag, 0) }, + { FLDATA (FBF, mpx.flagbuf, 0) }, + { ORDATA (DEVNO, mpx_dib.select_code, 6), REG_HRO }, { BRDATA (CONNORD, mpx_order, 10, 32, MPX_PORTS), REG_HRO }, { NULL } @@ -746,7 +749,6 @@ DEVICE mpx_dev = { NULL }; /* logical device name */ - /* I/O signal handler. Commands are sent to the card via an OTA/B. Issuing an STC SC,C causes the @@ -798,161 +800,156 @@ DEVICE mpx_dev = { 2. The "Fast binary read" command inhibits all other commands until the card is reset. - - 3. The card does not respond to POPIO. However, as PRESET asserts POPIO and - CRS together, we fall into the latter from the former. */ -uint32 mpx_io (uint32 select_code, IOSIG signal, uint32 data) +uint32 mpx_io (DIB *dibptr, IOCYCLE signal_set, uint32 stat_data) { static const char *output_state [] = { "Command", "Command override", "Parameter", "Data" }; static const char *input_state [] = { "Status", "Invalid status", "Parameter", "Data" }; -const char *hold_or_clear = (signal > ioCLF ? ",C" : ""); -const IOSIG base_signal = IOBASE (signal); /* derive base signal */ +const char *hold_or_clear = (signal_set & ioCLF ? ",C" : ""); int32 delay; +IOSIGNAL signal; +IOCYCLE working_set = IOADDSIR (signal_set); /* add ioSIR if needed */ -switch (base_signal) { /* dispatch base I/O signal */ +while (working_set) { + signal = IONEXT (working_set); /* isolate next signal */ - case ioCLF: /* clear flag flip-flop */ - mpx_flag = mpx_flagbuf = CLEAR; /* clear flag and flag buffer */ + switch (signal) { /* dispatch I/O signal */ - if (DEBUG_PRI (mpx_dev, DEB_CMDS)) - fputs (">>MPX cmds: [CLF] Flag cleared\n", sim_deb); - break; - - - case ioSTF: /* set flag flip-flop */ - if (DEBUG_PRI (mpx_dev, DEB_CMDS)) - fputs (">>MPX cmds: [STF] Flag set\n", sim_deb); - /* fall into ENF */ - - case ioENF: /* enable flag */ - mpx_flag = mpx_flagbuf = SET; /* set flag and flag buffer */ - break; - - - case ioSFC: /* skip if flag is clear */ - setstdSKF (mpx); - break; - - - case ioSFS: /* skip if flag is set */ - setstdSKF (mpx); - break; - - - case ioIOI: /* I/O data input */ - data = mpx_ibuf; /* return info */ - - if (DEBUG_PRI (mpx_dev, DEB_CPU)) - fprintf (sim_deb, ">>MPX cpu: [LIx%s] %s = %06o\n", - hold_or_clear, input_state [mpx_state], data); - - if (mpx_state == exec) /* if this is input data word */ - sim_activate (&mpx_cntl, DATA_DELAY); /* continue transmission */ - break; - - - case ioIOO: /* I/O data output */ - if (DEBUG_PRI (mpx_dev, DEB_CPU)) - fprintf (sim_deb, ">>MPX cpu: [OTx%s] %s = %06o\n", - hold_or_clear, output_state [mpx_state], data); - - mpx_obuf = data; /* save word */ - - if (mpx_state == param) { /* if this is parameter word */ - sim_activate (&mpx_cntl, CMD_DELAY); /* do command now */ + case ioCLF: /* clear flag flip-flop */ + mpx.flag = mpx.flagbuf = CLEAR; /* clear flag and flag buffer */ if (DEBUG_PRI (mpx_dev, DEB_CMDS)) - fprintf (sim_deb, ">>MPX cmds: [OTx%s] Command %03o parameter %06o scheduled, " - "time = %d\n", hold_or_clear, mpx_cmd, mpx_obuf, CMD_DELAY); - } - - else if (mpx_state == exec) /* else if this is output data word */ - sim_activate (&mpx_cntl, DATA_DELAY); /* then do transmission */ - break; + fputs (">>MPX cmds: [CLF] Flag cleared\n", sim_deb); + break; - case ioPOPIO: /* power-on preset to I/O */ - /* fall into CRS handler */ + case ioSTF: /* set flag flip-flop */ + if (DEBUG_PRI (mpx_dev, DEB_CMDS)) + fputs (">>MPX cmds: [STF] Flag set\n", sim_deb); + /* fall into ENF */ - case ioCRS: /* control reset */ - controller_reset (); /* reset firmware to power-on defaults */ - mpx_obuf = 0; /* clear output buffer */ - - mpx_control = CLEAR; /* clear control */ - mpx_flagbuf = CLEAR; /* clear flag buffer */ - mpx_flag = CLEAR; /* clear flag */ - - if (DEBUG_PRI (mpx_dev, DEB_CMDS)) - fputs (">>MPX cmds: [CRS] Controller reset\n", sim_deb); - break; + case ioENF: /* enable flag */ + mpx.flag = mpx.flagbuf = SET; /* set flag and flag buffer */ + break; - case ioCLC: /* clear control flip-flop */ - mpx_control = CLEAR; /* clear control */ - - if (DEBUG_PRI (mpx_dev, DEB_CMDS)) - fprintf (sim_deb, ">>MPX cmds: [CLC%s] Control cleared\n", hold_or_clear); - break; + case ioSFC: /* skip if flag is clear */ + setstdSKF (mpx); + break; - case ioSTC: /* set control flip-flop */ - mpx_control = SET; /* set control */ - - if (mpx_cmd == CMD_BINARY_READ) /* executing fast binary read? */ - break; /* further command execution inhibited */ - - mpx_cmd = GET_OPCODE (mpx_obuf); /* get command opcode */ - mpx_portkey = GET_KEY (mpx_obuf); /* get port key */ - - if (mpx_state == cmd) /* already scheduled? */ - sim_cancel (&mpx_cntl); /* cancel to get full delay */ - - mpx_state = cmd; /* set command state */ - - if (mpx_cmd & CMD_TWO_WORDS) /* two-word command? */ - delay = PARAM_DELAY; /* specify parameter wait */ - else /* one-word command */ - delay = CMD_DELAY; /* specify command wait */ - - sim_activate (&mpx_cntl, delay); /* schedule command */ - - if (DEBUG_PRI (mpx_dev, DEB_CMDS)) - fprintf (sim_deb, ">>MPX cmds: [STC%s] Command %03o key %d scheduled, " - "time = %d\n", hold_or_clear, mpx_cmd, mpx_portkey, delay); - break; + case ioSFS: /* skip if flag is set */ + setstdSKF (mpx); + break; - case ioEDT: /* end data transfer */ - if (DEBUG_PRI (mpx_dev, DEB_CPU)) - fputs (">>MPX cpu: [EDT] DCPC transfer ended\n", sim_deb); - break; + case ioIOI: /* I/O data input */ + stat_data = IORETURN (SCPE_OK, mpx_ibuf); /* return info */ + + if (DEBUG_PRI (mpx_dev, DEB_CPU)) + fprintf (sim_deb, ">>MPX cpu: [LIx%s] %s = %06o\n", + hold_or_clear, input_state [mpx_state], mpx_ibuf); + + if (mpx_state == exec) /* if this is input data word */ + sim_activate (&mpx_cntl, DATA_DELAY); /* continue transmission */ + break; - case ioSIR: /* set interrupt request */ - setstdPRL (select_code, mpx); /* set standard PRL signal */ - setstdIRQ (select_code, mpx); /* set standard IRQ signal */ - setstdSRQ (select_code, mpx); /* set standard SRQ signal */ - break; + case ioIOO: /* I/O data output */ + mpx_obuf = IODATA (stat_data); /* save word */ + + if (DEBUG_PRI (mpx_dev, DEB_CPU)) + fprintf (sim_deb, ">>MPX cpu: [OTx%s] %s = %06o\n", + hold_or_clear, output_state [mpx_state], mpx_obuf); + + if (mpx_state == param) { /* if this is parameter word */ + sim_activate (&mpx_cntl, CMD_DELAY); /* do command now */ + + if (DEBUG_PRI (mpx_dev, DEB_CMDS)) + fprintf (sim_deb, ">>MPX cmds: [OTx%s] Command %03o parameter %06o scheduled, " + "time = %d\n", hold_or_clear, mpx_cmd, mpx_obuf, CMD_DELAY); + } + + else if (mpx_state == exec) /* else if this is output data word */ + sim_activate (&mpx_cntl, DATA_DELAY); /* then do transmission */ + break; - case ioIAK: /* interrupt acknowledge */ - mpx_flagbuf = CLEAR; /* clear flag buffer */ - break; + case ioCRS: /* control reset */ + controller_reset (); /* reset firmware to power-on defaults */ + mpx_obuf = 0; /* clear output buffer */ + + mpx.control = CLEAR; /* clear control */ + mpx.flagbuf = CLEAR; /* clear flag buffer */ + mpx.flag = CLEAR; /* clear flag */ + + if (DEBUG_PRI (mpx_dev, DEB_CMDS)) + fputs (">>MPX cmds: [CRS] Controller reset\n", sim_deb); + break; - default: /* all other signals */ - break; /* are ignored */ + case ioCLC: /* clear control flip-flop */ + mpx.control = CLEAR; /* clear control */ + + if (DEBUG_PRI (mpx_dev, DEB_CMDS)) + fprintf (sim_deb, ">>MPX cmds: [CLC%s] Control cleared\n", hold_or_clear); + break; + + + case ioSTC: /* set control flip-flop */ + mpx.control = SET; /* set control */ + + if (mpx_cmd == CMD_BINARY_READ) /* executing fast binary read? */ + break; /* further command execution inhibited */ + + mpx_cmd = GET_OPCODE (mpx_obuf); /* get command opcode */ + mpx_portkey = GET_KEY (mpx_obuf); /* get port key */ + + if (mpx_state == cmd) /* already scheduled? */ + sim_cancel (&mpx_cntl); /* cancel to get full delay */ + + mpx_state = cmd; /* set command state */ + + if (mpx_cmd & CMD_TWO_WORDS) /* two-word command? */ + delay = PARAM_DELAY; /* specify parameter wait */ + else /* one-word command */ + delay = CMD_DELAY; /* specify command wait */ + + sim_activate (&mpx_cntl, delay); /* schedule command */ + + if (DEBUG_PRI (mpx_dev, DEB_CMDS)) + fprintf (sim_deb, ">>MPX cmds: [STC%s] Command %03o key %d scheduled, " + "time = %d\n", hold_or_clear, mpx_cmd, mpx_portkey, delay); + break; + + + case ioEDT: /* end data transfer */ + if (DEBUG_PRI (mpx_dev, DEB_CPU)) + fputs (">>MPX cpu: [EDT] DCPC transfer ended\n", sim_deb); + break; + + + case ioSIR: /* set interrupt request */ + setstdPRL (mpx); /* set standard PRL signal */ + setstdIRQ (mpx); /* set standard IRQ signal */ + setstdSRQ (mpx); /* set standard SRQ signal */ + break; + + + case ioIAK: /* interrupt acknowledge */ + mpx.flagbuf = CLEAR; /* clear flag buffer */ + break; + + + default: /* all other signals */ + break; /* are ignored */ + } + + working_set = working_set & ~signal; /* remove current signal from set */ } - -if (signal > ioCLF) /* multiple signals? */ - mpx_io (select_code, ioCLF, 0); /* issue CLF */ -else if (signal > ioSIR) /* signal affected interrupt status? */ - mpx_io (select_code, ioSIR, 0); /* set interrupt request */ - -return data; +return stat_data; } @@ -1591,7 +1588,7 @@ if (DEBUG_PRI (mpx_dev, DEB_CMDS) && /* debug print? */ } if (set_flag) { - mpx_io (mpx_dib.devno, ioENF, 0); /* set device flag */ + mpx_io (&mpx_dib, ioENF, 0); /* set device flag */ if (DEBUG_PRI (mpx_dev, DEB_CMDS)) fputs (">>MPX cmds: Flag set\n", sim_deb); @@ -1909,7 +1906,7 @@ if (fast_binary_read) { /* fast binary read mpx_ibuf = mpx_ibuf | (chx & DMASK8); /* merge it into word */ mpx_flags [0] |= FL_HAVEBUF; /* mark buffer as ready */ - mpx_io (mpx_dib.devno, ioENF, 0); /* set device flag */ + mpx_io (&mpx_dib, ioENF, 0); /* set device flag */ if (DEBUG_PRI (mpx_dev, DEB_CMDS)) fputs (">>MPX cmds: Flag and SRQ set\n", sim_deb); @@ -2021,14 +2018,14 @@ return SCPE_OK; t_stat mpx_reset (DEVICE *dptr) { -if (sim_switches & SWMASK ('P')) { /* PON reset? */ +if (sim_switches & SWMASK ('P')) { /* power-on reset? */ emptying_flags [ioread] = FL_RDEMPT; /* initialize buffer flags constants */ emptying_flags [iowrite] = FL_WREMPT; filling_flags [ioread] = FL_RDFILL; filling_flags [iowrite] = FL_WRFILL; } -mpx_io (mpx_dib.devno, ioPOPIO, 0); /* send POPIO signal */ +IOPRESET (&mpx_dib); /* PRESET device (does not use PON) */ mpx_ibuf = 0; /* clear input buffer */ diff --git a/HP2100/hp2100_ms.c b/HP2100/hp2100_ms.c index fc0490b7..d9f44416 100644 --- a/HP2100/hp2100_ms.c +++ b/HP2100/hp2100_ms.c @@ -1,6 +1,6 @@ /* hp2100_ms.c: HP 2100 13181A/13183A magnetic tape simulator - Copyright (c) 1993-2008, Robert M. Supnik + Copyright (c) 1993-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"), @@ -26,6 +26,8 @@ MS 13181A 7970B 800bpi nine track magnetic tape 13183A 7970E 1600bpi nine track magnetic tape + 28-Mar-11 JDB Tidied up signal handling + 26-Oct-10 JDB Changed I/O signal handler for revised signal model 11-Aug-08 JDB Revised to use AR instead of saved_AR in boot 26-Jun-08 JDB Rewrote device I/O to model backplane signals 28-Dec-06 JDB Added ioCRS state to I/O decoders @@ -152,9 +154,11 @@ enum { A13181, A13183 } ms_ctype = A13181; /* ctrl type */ int32 ms_timing = 1; /* timing type */ -FLIP_FLOP msc_control = CLEAR; -FLIP_FLOP msc_flag = CLEAR; -FLIP_FLOP msc_flagbuf = CLEAR; +struct { + FLIP_FLOP control; /* control flip-flop */ + FLIP_FLOP flag; /* flag flip-flop */ + FLIP_FLOP flagbuf; /* flag buffer flip-flop */ + } msc = { CLEAR, CLEAR, CLEAR }; int32 msc_sta = 0; /* status */ int32 msc_buf = 0; /* buffer */ @@ -162,9 +166,11 @@ int32 msc_usl = 0; /* unit select */ int32 msc_1st = 0; /* first service */ int32 msc_stopioe = 1; /* stop on error */ -FLIP_FLOP msd_control = CLEAR; -FLIP_FLOP msd_flag = CLEAR; -FLIP_FLOP msd_flagbuf = CLEAR; +struct { + FLIP_FLOP control; /* control flip-flop */ + FLIP_FLOP flag; /* flag flip-flop */ + FLIP_FLOP flagbuf; /* flag buffer flip-flop */ + } msd = { CLEAR, CLEAR, CLEAR }; int32 msd_buf = 0; /* data buffer */ uint8 msxb[DBSIZE] = { 0 }; /* data buffer */ @@ -206,8 +212,10 @@ const TIMESET msc_times[3] = { }; DEVICE msd_dev, msc_dev; -uint32 msdio (uint32 select_code, IOSIG signal, uint32 data); -uint32 mscio (uint32 select_code, IOSIG signal, uint32 data); + +IOHANDLER msdio; +IOHANDLER mscio; + t_stat msc_svc (UNIT *uptr); t_stat msc_reset (DEVICE *dptr); t_stat msc_attach (UNIT *uptr, char *cptr); @@ -235,8 +243,8 @@ t_stat ms_clear (void); */ DIB ms_dib[] = { - { MSD, &msdio }, - { MSC, &mscio } + { &msdio, MSD }, + { &mscio, MSC } }; #define msd_dib ms_dib[0] @@ -246,13 +254,13 @@ UNIT msd_unit = { UDATA (NULL, 0, 0) }; REG msd_reg[] = { { ORDATA (BUF, msd_buf, 16) }, - { FLDATA (CTL, msd_control, 0) }, - { FLDATA (FLG, msd_flag, 0) }, - { FLDATA (FBF, msd_flagbuf, 0) }, + { FLDATA (CTL, msd.control, 0) }, + { FLDATA (FLG, msd.flag, 0) }, + { FLDATA (FBF, msd.flagbuf, 0) }, { BRDATA (DBUF, msxb, 8, 8, DBSIZE) }, { DRDATA (BPTR, ms_ptr, DB_N_SIZE + 1) }, { DRDATA (BMAX, ms_max, DB_N_SIZE + 1) }, - { ORDATA (DEVNO, msd_dib.devno, 6), REG_HRO }, + { ORDATA (DEVNO, msd_dib.select_code, 6), REG_HRO }, { NULL } }; @@ -295,9 +303,9 @@ REG msc_reg[] = { { ORDATA (BUF, msc_buf, 16) }, { ORDATA (USEL, msc_usl, 2) }, { FLDATA (FSVC, msc_1st, 0) }, - { FLDATA (CTL, msc_control, 0) }, - { FLDATA (FLG, msc_flag, 0) }, - { FLDATA (FBF, msc_flagbuf, 0) }, + { FLDATA (CTL, msc.control, 0) }, + { FLDATA (FLG, msc.flag, 0) }, + { FLDATA (FBF, msc.flagbuf, 0) }, { URDATA (POS, msc_unit[0].pos, 10, T_ADDR_W, 0, MS_NUMDR, PV_LEFT) }, { URDATA (FNC, msc_unit[0].FNC, 8, 8, 0, MS_NUMDR, REG_HRO) }, { URDATA (UST, msc_unit[0].UST, 8, 12, 0, MS_NUMDR, REG_HRO) }, @@ -311,7 +319,7 @@ REG msc_reg[] = { { FLDATA (TIMING, ms_timing, 0), REG_HRO }, { FLDATA (STOP_IOE, msc_stopioe, 0) }, { FLDATA (CTYPE, ms_ctype, 0), REG_HRO }, - { ORDATA (DEVNO, msc_dib.devno, 6), REG_HRO }, + { ORDATA (DEVNO, msc_dib.select_code, 6), REG_HRO }, { NULL } }; @@ -362,75 +370,77 @@ DEVICE msc_dev = { /* Data channel I/O signal handler */ -uint32 msdio (uint32 select_code, IOSIG signal, uint32 data) +uint32 msdio (DIB *dibptr, IOCYCLE signal_set, uint32 stat_data) { -const IOSIG base_signal = IOBASE (signal); /* derive base signal */ +IOSIGNAL signal; +IOCYCLE working_set = IOADDSIR (signal_set); /* add ioSIR if needed */ -switch (base_signal) { /* dispatch base I/O signal */ +while (working_set) { + signal = IONEXT (working_set); /* isolate next signal */ - case ioCLF: /* clear flag flip-flop */ - msd_flag = msd_flagbuf = CLEAR; - break; + switch (signal) { /* dispatch I/O signal */ + case ioCLF: /* clear flag flip-flop */ + msd.flag = msd.flagbuf = CLEAR; + break; - case ioSTF: /* set flag flip-flop */ - case ioENF: /* enable flag */ - msd_flag = msd_flagbuf = SET; - break; + case ioSTF: /* set flag flip-flop */ + case ioENF: /* enable flag */ + msd.flag = msd.flagbuf = SET; + break; - case ioSFC: /* skip if flag is clear */ - setstdSKF (msd); - break; + case ioSFC: /* skip if flag is clear */ + setstdSKF (msd); + break; - case ioSFS: /* skip if flag is set */ - setstdSKF (msd); - break; + case ioSFS: /* skip if flag is set */ + setstdSKF (msd); + break; - case ioIOI: /* I/O data input */ - data = msd_buf; - break; + case ioIOI: /* I/O data input */ + stat_data = IORETURN (SCPE_OK, msd_buf); /* merge in return status */ + break; - case ioIOO: /* I/O data output */ - msd_buf = data; /* store data */ - break; + case ioIOO: /* I/O data output */ + msd_buf = IODATA (stat_data); /* store data */ + break; - case ioPOPIO: /* power-on preset to I/O */ - ms_clear (); /* issue CLR to controller */ - /* fall into CRS handler */ - case ioCRS: /* control reset */ - msd_flag = msd_flagbuf = SET; /* set flag and flag buffer */ + case ioPOPIO: /* power-on preset to I/O */ + ms_clear (); /* issue CLR to controller */ + break; + + case ioCRS: /* control reset */ + msd.flag = msd.flagbuf = SET; /* set flag and flag buffer */ /* fall into CLC handler */ - case ioCLC: /* clear control flip-flop */ - msd_control = CLEAR; - break; + case ioCLC: /* clear control flip-flop */ + msd.control = CLEAR; + break; - case ioSTC: /* set control flip-flop */ - msd_control = SET; - break; + case ioSTC: /* set control flip-flop */ + msd.control = SET; + break; - case ioEDT: /* end data transfer */ - msd_flag = msd_flagbuf = CLEAR; /* same as CLF */ - break; + case ioEDT: /* end data transfer */ + msd.flag = msd.flagbuf = CLEAR; /* same as CLF */ + break; - case ioSIR: /* set interrupt request */ - setstdPRL (select_code, msd); /* set standard PRL signal */ - setstdIRQ (select_code, msd); /* set standard IRQ signal */ - setstdSRQ (select_code, msd); /* set standard SRQ signal */ - break; + case ioSIR: /* set interrupt request */ + setstdPRL (msd); /* set standard PRL signal */ + setstdIRQ (msd); /* set standard IRQ signal */ + setstdSRQ (msd); /* set standard SRQ signal */ + break; - case ioIAK: /* interrupt acknowledge */ - msd_flagbuf = CLEAR; - break; + case ioIAK: /* interrupt acknowledge */ + msd.flagbuf = CLEAR; + break; - default: /* all other signals */ - break; /* are ignored */ + default: /* all other signals */ + break; /* are ignored */ + } + + working_set = working_set & ~signal; /* remove current signal from set */ } -if (signal > ioCLF) /* multiple signals? */ - msdio (select_code, ioCLF, 0); /* issue CLF */ -else if (signal > ioSIR) /* signal affected interrupt status? */ - msdio (select_code, ioSIR, 0); /* set interrupt request */ - -return data; +return stat_data; } @@ -453,195 +463,197 @@ return data; the command card under simulation to allow the command card to interrupt. */ -uint32 mscio (uint32 select_code, IOSIG signal, uint32 data) +uint32 mscio (DIB *dibptr, IOCYCLE signal_set, uint32 stat_data) { static const uint8 map_sel[16] = { 0, 0, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3 }; -const IOSIG base_signal = IOBASE (signal); /* derive base signal */ +uint16 data; int32 sched_time; UNIT *uptr = msc_dev.units + msc_usl; -switch (base_signal) { /* dispatch base I/O signal */ +IOSIGNAL signal; +IOCYCLE working_set = IOADDSIR (signal_set); /* add ioSIR if needed */ - case ioCLF: /* clear flag flip-flop */ - msc_flag = msc_flagbuf = CLEAR; - break; +while (working_set) { + signal = IONEXT (working_set); /* isolate next signal */ + switch (signal) { /* dispatch I/O signal */ - case ioSTF: /* set flag flip-flop */ - case ioENF: /* enable flag */ - msc_flag = msc_flagbuf = SET; - break; - - - case ioSFC: /* skip if flag is clear */ - setstdSKF (msc); - break; - - - case ioSFS: /* skip if flag is set */ - setstdSKF (msc); - break; - - - case ioIOI: /* I/O data input */ - data = msc_sta & ~STA_DYN; /* get card status */ - - if ((uptr->flags & UNIT_OFFLINE) == 0) { /* online? */ - data = data | uptr->UST; /* add unit status */ - - if (sim_tape_bot (uptr)) /* BOT? */ - data = data | STA_BOT; - - if (sim_is_active (uptr) && /* TBSY unless RWD at BOT */ - !((uptr->FNC & FNF_RWD) && sim_tape_bot (uptr))) - data = data | STA_TBSY; - - if (sim_tape_wrp (uptr)) /* write prot? */ - data = data | STA_WLK; - - if (sim_tape_eot (uptr)) /* EOT? */ - data = data | STA_EOT; - } - - else - data = data | STA_TBSY | STA_LOCAL; - - if (ms_ctype == A13183) /* 13183A? */ - data = data | STA_PE | (msc_usl << STA_V_SEL); - - if (DEBUG_PRI (msc_dev, DEB_CPU)) - fprintf (sim_deb, ">>MSC LIx: Status = %06o\n", data); - - break; - - - case ioIOO: /* I/O data output */ - if (DEBUG_PRI (msc_dev, DEB_CPU)) - fprintf (sim_deb, ">>MSC OTx: Command = %06o\n", data); - - msc_buf = data; - msc_sta = msc_sta & ~STA_REJ; /* clear reject */ - - if ((data & 0377) == FNC_CLR) /* clear always ok */ + case ioCLF: /* clear flag flip-flop */ + msc.flag = msc.flagbuf = CLEAR; break; - if (msc_sta & STA_BUSY) { /* busy? reject */ - msc_sta = msc_sta | STA_REJ; /* dont chg select */ + + case ioSTF: /* set flag flip-flop */ + case ioENF: /* enable flag */ + msc.flag = msc.flagbuf = SET; break; - } - - if (data & FNF_CHS) { /* select change */ - msc_usl = map_sel[FNC_GETSEL (data)]; /* is immediate */ - uptr = msc_dev.units + msc_usl; - if (DEBUG_PRI (msc_dev, DEB_CMDS)) - fprintf (sim_deb, ">>MSC OTx: Unit %d selected\n", msc_usl); - } - - if (((data & FNF_MOT) && sim_is_active (uptr)) || - ((data & FNF_REV) && sim_tape_bot (uptr)) || - ((data & FNF_WRT) && sim_tape_wrp (uptr))) - msc_sta = msc_sta | STA_REJ; /* reject? */ - - break; - case ioPOPIO: /* power-on preset to I/O */ - /* fall into CRS handler */ + case ioSFC: /* skip if flag is clear */ + setstdSKF (msc); + break; - case ioCRS: /* control reset */ - msc_flag = msc_flagbuf = SET; /* set flag and flag buffer */ + + case ioSFS: /* skip if flag is set */ + setstdSKF (msc); + break; + + + case ioIOI: /* I/O data input */ + data = msc_sta & ~STA_DYN; /* get card status */ + + if ((uptr->flags & UNIT_OFFLINE) == 0) { /* online? */ + data = data | uptr->UST; /* add unit status */ + + if (sim_tape_bot (uptr)) /* BOT? */ + data = data | STA_BOT; + + if (sim_is_active (uptr) && /* TBSY unless RWD at BOT */ + !((uptr->FNC & FNF_RWD) && sim_tape_bot (uptr))) + data = data | STA_TBSY; + + if (sim_tape_wrp (uptr)) /* write prot? */ + data = data | STA_WLK; + + if (sim_tape_eot (uptr)) /* EOT? */ + data = data | STA_EOT; + } + + else + data = data | STA_TBSY | STA_LOCAL; + + if (ms_ctype == A13183) /* 13183A? */ + data = data | STA_PE | (msc_usl << STA_V_SEL); + + if (DEBUG_PRI (msc_dev, DEB_CPU)) + fprintf (sim_deb, ">>MSC LIx: Status = %06o\n", data); + + stat_data = IORETURN (SCPE_OK, data); /* merge in return status */ + break; + + + case ioIOO: /* I/O data output */ + msc_buf = IODATA (stat_data); /* clear supplied status */ + + if (DEBUG_PRI (msc_dev, DEB_CPU)) + fprintf (sim_deb, ">>MSC OTx: Command = %06o\n", msc_buf); + + msc_sta = msc_sta & ~STA_REJ; /* clear reject */ + + if ((msc_buf & 0377) == FNC_CLR) /* clear always ok */ + break; + + if (msc_sta & STA_BUSY) { /* busy? reject */ + msc_sta = msc_sta | STA_REJ; /* dont chg select */ + break; + } + + if (msc_buf & FNF_CHS) { /* select change */ + msc_usl = map_sel[FNC_GETSEL (msc_buf)]; /* is immediate */ + uptr = msc_dev.units + msc_usl; + if (DEBUG_PRI (msc_dev, DEB_CMDS)) + fprintf (sim_deb, ">>MSC OTx: Unit %d selected\n", msc_usl); + } + + if (((msc_buf & FNF_MOT) && sim_is_active (uptr)) || + ((msc_buf & FNF_REV) && sim_tape_bot (uptr)) || + ((msc_buf & FNF_WRT) && sim_tape_wrp (uptr))) + msc_sta = msc_sta | STA_REJ; /* reject? */ + + break; + + + case ioCRS: /* control reset */ + msc.flag = msc.flagbuf = SET; /* set flag and flag buffer */ /* fall into CLC handler */ - case ioCLC: /* clear control flip-flop */ - msc_control = CLEAR; - break; + case ioCLC: /* clear control flip-flop */ + msc.control = CLEAR; + break; - case ioSTC: /* set control flip-flop */ - if (!(msc_sta & STA_REJ)) { /* last cmd rejected? */ - if ((msc_buf & 0377) == FNC_CLR) { /* clear? */ - ms_clear (); /* issue CLR to controller */ + case ioSTC: /* set control flip-flop */ + if (!(msc_sta & STA_REJ)) { /* last cmd rejected? */ + if ((msc_buf & 0377) == FNC_CLR) { /* clear? */ + ms_clear (); /* issue CLR to controller */ - msc_control = SET; /* set CTL for STC */ - msc_flag = msc_flagbuf = SET; /* set FLG for completion */ + msc.control = SET; /* set CTL for STC */ + msc.flag = msc.flagbuf = SET; /* set FLG for completion */ - signal = ioSTC; /* eliminate possible CLF */ + working_set = working_set & ~ioCLF; /* eliminate possible CLF */ - if (DEBUG_PRI (msc_dev, DEB_CMDS)) - fputs (">>MSC STC: Controller cleared\n", sim_deb); + if (DEBUG_PRI (msc_dev, DEB_CMDS)) + fputs (">>MSC STC: Controller cleared\n", sim_deb); - break; /* command completes immediately */ + break; /* command completes immediately */ + } + + uptr->FNC = msc_buf & 0377; /* save function */ + + if (uptr->FNC & FNF_RWD) { /* rewind? */ + if (!sim_tape_bot (uptr)) /* not at BOT? */ + uptr->UST = STA_REW; /* set rewinding */ + + sched_time = msc_rtime; /* set response time */ + } + + else { + if (sim_tape_bot (uptr)) /* at BOT? */ + sched_time = msc_btime; /* use BOT start time */ + + else if ((uptr->FNC == FNC_GAP) || (uptr->FNC == FNC_GFM)) + sched_time = msc_gtime; /* use gap traversal time */ + + else sched_time = 0; + + if (uptr->FNC != FNC_GAP) + sched_time += msc_ctime; /* add base command time */ + } + + if (msc_buf & ~FNC_SEL) { /* NOP for unit sel alone */ + sim_activate (uptr, sched_time); /* else schedule op */ + + if (DEBUG_PRI (msc_dev, DEB_CMDS)) + fprintf (sim_deb, + ">>MSC STC: Unit %d command %03o (%s) scheduled, " + "pos = %d, time = %d\n", + msc_usl, uptr->FNC, ms_cmd_name (uptr->FNC), + uptr->pos, sched_time); + } + + else if (DEBUG_PRI (msc_dev, DEB_CMDS)) + fputs (">>MSC STC: Unit select (NOP)\n", sim_deb); + + msc_sta = STA_BUSY; /* ctrl is busy */ + msc_1st = 1; + msc.control = SET; /* go */ } - - uptr->FNC = msc_buf & 0377; /* save function */ - - if (uptr->FNC & FNF_RWD) { /* rewind? */ - if (!sim_tape_bot (uptr)) /* not at BOT? */ - uptr->UST = STA_REW; /* set rewinding */ - - sched_time = msc_rtime; /* set response time */ - } - - else { - if (sim_tape_bot (uptr)) /* at BOT? */ - sched_time = msc_btime; /* use BOT start time */ - - else if ((uptr->FNC == FNC_GAP) || (uptr->FNC == FNC_GFM)) - sched_time = msc_gtime; /* use gap traversal time */ - - else sched_time = 0; - - if (uptr->FNC != FNC_GAP) - sched_time += msc_ctime; /* add base command time */ - } - - if (msc_buf & ~FNC_SEL) { /* NOP for unit sel alone */ - sim_activate (uptr, sched_time); /* else schedule op */ - - if (DEBUG_PRI (msc_dev, DEB_CMDS)) - fprintf (sim_deb, - ">>MSC STC: Unit %d command %03o (%s) scheduled, " - "pos = %d, time = %d\n", - msc_usl, uptr->FNC, ms_cmd_name (uptr->FNC), - uptr->pos, sched_time); - } - - else if (DEBUG_PRI (msc_dev, DEB_CMDS)) - fputs (">>MSC STC: Unit select (NOP)\n", sim_deb); - - msc_sta = STA_BUSY; /* ctrl is busy */ - msc_1st = 1; - msc_control = SET; /* go */ - } - break; + break; - case ioSIR: /* set interrupt request */ - setstdPRL (select_code, msc); /* set standard PRL signal */ - setstdIRQ (select_code, msc); /* set standard IRQ signal */ - setstdSRQ (select_code, msc); /* set standard SRQ signal */ - break; + case ioSIR: /* set interrupt request */ + setstdPRL (msc); /* set standard PRL signal */ + setstdIRQ (msc); /* set standard IRQ signal */ + setstdSRQ (msc); /* set standard SRQ signal */ + break; - case ioIAK: /* interrupt acknowledge */ - msc_flagbuf = CLEAR; - break; + case ioIAK: /* interrupt acknowledge */ + msc.flagbuf = CLEAR; + break; - default: /* all other signals */ - break; /* are ignored */ + default: /* all other signals */ + break; /* are ignored */ + } + + working_set = working_set & ~signal; /* remove current signal from set */ } - -if (signal > ioCLF) /* multiple signals? */ - mscio (select_code, ioCLF, 0); /* issue CLF */ -else if (signal > ioSIR) /* signal affected interrupt status? */ - mscio (select_code, ioSIR, 0); /* set interrupt request */ - -return data; +return stat_data; } @@ -671,8 +683,8 @@ unum = uptr - msc_dev.units; /* get unit number */ if ((uptr->FNC != FNC_RWS) && (uptr->flags & UNIT_OFFLINE)) { /* offline? */ msc_sta = (msc_sta | STA_REJ) & ~STA_BUSY; /* reject */ - mscio (msc_dib.devno, ioENF, 0); /* set flag */ - return IORETURN (msc_stopioe, SCPE_UNATT); + mscio (&msc_dib, ioENF, 0); /* set flag */ + return IOERROR (msc_stopioe, SCPE_UNATT); } switch (uptr->FNC) { /* case on function */ @@ -779,12 +791,12 @@ switch (uptr->FNC) { /* case on function */ if (ms_ctype == A13183) msc_sta = msc_sta | STA_ODD; /* set ODD for 13183A */ } - if (msd_control && (ms_ptr < ms_max)) { /* DCH on, more data? */ - if (msd_flag) msc_sta = msc_sta | STA_TIM | STA_PAR; + if (msd.control && (ms_ptr < ms_max)) { /* DCH on, more data? */ + if (msd.flag) msc_sta = msc_sta | STA_TIM | STA_PAR; msd_buf = ((uint16) msxb[ms_ptr] << 8) | ((ms_ptr + 1 == ms_max) ? 0 : msxb[ms_ptr + 1]); ms_ptr = ms_ptr + 2; - msdio (msd_dib.devno, ioENF, 0); /* set flag */ + msdio (&msd_dib, ioENF, 0); /* set flag */ sim_activate (uptr, msc_xtime); /* re-activate */ return SCPE_OK; } @@ -822,8 +834,8 @@ switch (uptr->FNC) { /* case on function */ } else msc_sta = msc_sta | STA_PAR; } - if (msd_control) { /* xfer flop set? */ - msdio (msd_dib.devno, ioENF, 0); /* set flag */ + if (msd.control) { /* xfer flop set? */ + msdio (&msd_dib, ioENF, 0); /* set flag */ sim_activate (uptr, msc_xtime); /* re-activate */ return SCPE_OK; } @@ -853,7 +865,7 @@ switch (uptr->FNC) { /* case on function */ break; } -mscio (msc_dib.devno, ioENF, 0); /* set flag */ +mscio (&msc_dib, ioENF, 0); /* set flag */ msc_sta = msc_sta & ~STA_BUSY; /* update status */ if (DEBUG_PRI (msc_dev, DEB_CMDS)) fprintf (sim_deb, @@ -973,17 +985,15 @@ t_stat msc_reset (DEVICE *dptr) { int32 i; UNIT *uptr; +DIB *dibptr = (DIB *) dptr->ctxt; /* DIB pointer */ hp_enbdis_pair (dptr, /* make pair cons */ (dptr == &msd_dev) ? &msc_dev : &msd_dev); -if (sim_switches & SWMASK ('P')) /* PON reset? */ +if (sim_switches & SWMASK ('P')) /* initialization reset? */ ms_config_timing (); -if (dptr == &msc_dev) /* command channel reset? */ - mscio (msc_dib.devno, ioPOPIO, 0); /* send POPIO signal to command channel */ -else /* data channel reset */ - msdio (msd_dib.devno, ioPOPIO, 0); /* send POPIO signal to data channel */ +IOPRESET (dibptr); /* PRESET device (does not use PON) */ msc_buf = msd_buf = 0; msc_sta = msc_usl = 0; @@ -1247,7 +1257,7 @@ t_stat msc_boot (int32 unitno, DEVICE *dptr) int32 dev; if (unitno != 0) return SCPE_NOFNC; /* only unit 0 */ -dev = msd_dib.devno; /* get data chan dev */ +dev = msd_dib.select_code; /* get data chan dev */ if (ibl_copy (ms_rom, dev)) return SCPE_IERR; /* copy boot to memory */ SR = (SR & IBL_OPT) | IBL_MS | (dev << IBL_V_DEV); /* set SR */ if ((sim_switches & SWMASK ('S')) && AR) SR = SR | 1; /* skip? */ diff --git a/HP2100/hp2100_mt.c b/HP2100/hp2100_mt.c index d0360aa7..32c0f072 100644 --- a/HP2100/hp2100_mt.c +++ b/HP2100/hp2100_mt.c @@ -1,6 +1,6 @@ /* hp2100_mt.c: HP 2100 12559A magnetic tape simulator - Copyright (c) 1993-2008, Robert M. Supnik + Copyright (c) 1993-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"), @@ -25,6 +25,9 @@ MT 12559A 3030 nine track magnetic tape + 28-Mar-11 JDB Tidied up signal handling + 29-Oct-10 JDB Fixed error in command scan in mtcio ioIOO handler + 26-Oct-10 JDB Changed I/O signal handler for revised signal model 04-Sep-08 JDB Fixed missing flag after CLR command 02-Sep-08 JDB Moved write enable and format commands from MTD to MTC 26-Jun-08 JDB Rewrote device I/O to model backplane signals @@ -105,12 +108,16 @@ #define STA_PAR 0002 /* parity error */ #define STA_BUSY 0001 /* busy (d) */ -FLIP_FLOP mtd_flag = CLEAR; -FLIP_FLOP mtd_flagbuf = CLEAR; +struct { + FLIP_FLOP flag; /* flag flip-flop */ + FLIP_FLOP flagbuf; /* flag buffer flip-flop */ + } mtd = { CLEAR, CLEAR }; -FLIP_FLOP mtc_control = CLEAR; -FLIP_FLOP mtc_flag = CLEAR; -FLIP_FLOP mtc_flagbuf = CLEAR; +struct { + FLIP_FLOP control; /* control flip-flop */ + FLIP_FLOP flag; /* flag flip-flop */ + FLIP_FLOP flagbuf; /* flag buffer flip-flop */ + } mtc = { CLEAR, CLEAR, CLEAR }; int32 mtc_fnc = 0; /* function */ int32 mtc_sta = 0; /* status register */ @@ -124,10 +131,13 @@ uint8 mtxb[DBSIZE] = { 0 }; /* data buffer */ t_mtrlnt mt_ptr = 0, mt_max = 0; /* buffer ptrs */ static const uint32 mtc_cmd[] = { FNC_WC, FNC_RC, FNC_GAP, FNC_FSR, FNC_BSR, FNC_REW, FNC_RWS, FNC_WFM }; +static const uint32 mtc_cmd_count = sizeof (mtc_cmd) / sizeof (mtc_cmd[0]); DEVICE mtd_dev, mtc_dev; -uint32 mtdio (uint32 select_code, IOSIG signal, uint32 data); -uint32 mtcio (uint32 select_code, IOSIG signal, uint32 data); + +IOHANDLER mtdio; +IOHANDLER mtcio; + t_stat mtc_svc (UNIT *uptr); t_stat mt_reset (DEVICE *dptr); t_stat mtc_attach (UNIT *uptr, char *cptr); @@ -143,8 +153,8 @@ t_stat mt_clear (void); */ DIB mt_dib[] = { - { MTD, &mtdio }, - { MTC, &mtcio } + { &mtdio, MTD }, + { &mtcio, MTC } }; #define mtd_dib mt_dib[0] @@ -153,12 +163,12 @@ DIB mt_dib[] = { UNIT mtd_unit = { UDATA (NULL, 0, 0) }; REG mtd_reg[] = { - { FLDATA (FLG, mtd_flag, 0) }, - { FLDATA (FBF, mtd_flagbuf, 0) }, + { FLDATA (FLG, mtd.flag, 0) }, + { FLDATA (FBF, mtd.flagbuf, 0) }, { BRDATA (DBUF, mtxb, 8, 8, DBSIZE) }, { DRDATA (BPTR, mt_ptr, DB_V_SIZE + 1) }, { DRDATA (BMAX, mt_max, DB_V_SIZE + 1) }, - { ORDATA (DEVNO, mtd_dib.devno, 6), REG_HRO }, + { ORDATA (DEVNO, mtd_dib.select_code, 6), REG_HRO }, { NULL } }; @@ -190,9 +200,9 @@ REG mtc_reg[] = { { ORDATA (FNC, mtc_fnc, 8) }, { ORDATA (STA, mtc_sta, 9) }, { ORDATA (BUF, mtc_unit.buf, 8) }, - { FLDATA (CTL, mtc_control, 0) }, - { FLDATA (FLG, mtc_flag, 0) }, - { FLDATA (FBF, mtc_flagbuf, 0) }, + { FLDATA (CTL, mtc.control, 0) }, + { FLDATA (FLG, mtc.flag, 0) }, + { FLDATA (FBF, mtc.flagbuf, 0) }, { FLDATA (DTF, mtc_dtf, 0) }, { FLDATA (FSVC, mtc_1st, 0) }, { DRDATA (POS, mtc_unit.pos, T_ADDR_W), PV_LEFT }, @@ -200,7 +210,7 @@ REG mtc_reg[] = { { DRDATA (GTIME, mtc_gtime, 24), REG_NZ + PV_LEFT }, { DRDATA (XTIME, mtc_xtime, 24), REG_NZ + PV_LEFT }, { FLDATA (STOP_IOE, mtc_stopioe, 0) }, - { ORDATA (DEVNO, mtc_dib.devno, 6), REG_HRO }, + { ORDATA (DEVNO, mtc_dib.select_code, 6), REG_HRO }, { NULL } }; @@ -240,63 +250,63 @@ DEVICE mtc_dev = { so the flag buffer serves no other purpose. */ -uint32 mtdio (uint32 select_code, IOSIG signal, uint32 data) +uint32 mtdio (DIB *dibptr, IOCYCLE signal_set, uint32 stat_data) { -const IOSIG base_signal = IOBASE (signal); /* derive base signal */ +IOSIGNAL signal; +IOCYCLE working_set = IOADDSIR (signal_set); /* add ioSIR if needed */ -switch (base_signal) { /* dispatch base I/O signal */ +while (working_set) { + signal = IONEXT (working_set); /* isolate next signal */ - case ioCLF: /* clear flag flip-flop */ - mtd_flag = mtd_flagbuf = CLEAR; - break; + switch (signal) { /* dispatch I/O signal */ - case ioSTF: /* set flag flip-flop */ - case ioENF: /* enable flag */ - mtd_flag = mtd_flagbuf = SET; - break; + case ioCLF: /* clear flag flip-flop */ + mtd.flag = mtd.flagbuf = CLEAR; + break; - case ioSFC: /* skip if flag is clear */ - setstdSKF (mtd); - break; + case ioSTF: /* set flag flip-flop */ + case ioENF: /* enable flag */ + mtd.flag = mtd.flagbuf = SET; + break; - case ioSFS: /* skip if flag is set */ - setstdSKF (mtd); - break; + case ioSFC: /* skip if flag is clear */ + setstdSKF (mtd); + break; - case ioIOI: /* I/O data input */ - data = mtc_unit.buf; - break; + case ioSFS: /* skip if flag is set */ + setstdSKF (mtd); + break; - case ioIOO: /* I/O data output */ - mtc_unit.buf = data & 0377; /* store data */ - break; + case ioIOI: /* I/O data input */ + stat_data = IORETURN (SCPE_OK, mtc_unit.buf); /* merge in return status */ + break; - case ioPOPIO: /* power-on preset to I/O */ - mt_clear (); /* issue CLR to controller */ - mtd_flag = mtd_flagbuf = CLEAR; /* clear flag and flag buffer */ - /* fall into CRS handler */ - case ioCRS: /* control reset */ - break; + case ioIOO: /* I/O data output */ + mtc_unit.buf = IODATA (stat_data) & DMASK8; /* store data */ + break; - case ioCLC: /* clear control flip-flop */ - mtc_dtf = 0; /* clr xfer flop */ - mtd_flag = mtd_flagbuf = CLEAR; /* clear flag and flag buffer */ - break; + case ioPOPIO: /* power-on preset to I/O */ + mt_clear (); /* issue CLR to controller */ + mtd.flag = mtd.flagbuf = CLEAR; /* clear flag and flag buffer */ + break; - case ioSIR: /* set interrupt request */ - setstdSRQ (select_code, mtd); /* set standard SRQ signal */ - break; + case ioCLC: /* clear control flip-flop */ + mtc_dtf = 0; /* clr xfer flop */ + mtd.flag = mtd.flagbuf = CLEAR; /* clear flag and flag buffer */ + break; - default: /* all other signals */ - break; /* are ignored */ + case ioSIR: /* set interrupt request */ + setstdSRQ (mtd); /* set standard SRQ signal */ + break; + + default: /* all other signals */ + break; /* are ignored */ + } + + working_set = working_set & ~signal; /* remove current signal from set */ } -if (signal > ioCLF) /* multiple signals? */ - mtdio (select_code, ioCLF, 0); /* issue CLF */ -else if (signal > ioSIR) /* signal affected interrupt status? */ - mtdio (select_code, ioSIR, 0); /* set interrupt request */ - -return data; +return stat_data; } @@ -322,126 +332,131 @@ return data; complete immediately, and the BUSY bit never sets.. */ -uint32 mtcio (uint32 select_code, IOSIG signal, uint32 data) +uint32 mtcio (DIB *dibptr, IOCYCLE signal_set, uint32 stat_data) { -const IOSIG base_signal = IOBASE (signal); /* derive base signal */ +uint16 data; uint32 i; int32 valid; +IOSIGNAL signal; +IOCYCLE working_set = IOADDSIR (signal_set); /* add ioSIR if needed */ -switch (base_signal) { /* dispatch base I/O signal */ +while (working_set) { + signal = IONEXT (working_set); /* isolate next signal */ - case ioCLF: /* clear flag flip-flop */ - mtc_flag = mtc_flagbuf = CLEAR; - break; + switch (signal) { /* dispatch I/O signal */ + + case ioCLF: /* clear flag flip-flop */ + mtc.flag = mtc.flagbuf = CLEAR; + break; - case ioSTF: /* set flag flip-flop */ - case ioENF: /* enable flag */ - mtc_flag = mtc_flagbuf = SET; - break; + case ioSTF: /* set flag flip-flop */ + case ioENF: /* enable flag */ + mtc.flag = mtc.flagbuf = SET; + break; - case ioSFC: /* skip if flag is clear */ - setstdSKF (mtc); - break; + case ioSFC: /* skip if flag is clear */ + setstdSKF (mtc); + break; - case ioSFS: /* skip if flag is set */ - setstdSKF (mtc); - break; + case ioSFS: /* skip if flag is set */ + setstdSKF (mtc); + break; - case ioIOI: /* I/O data input */ - data = mtc_sta & ~(STA_LOCAL | STA_WLK | STA_BUSY); + case ioIOI: /* I/O data input */ + data = mtc_sta & ~(STA_LOCAL | STA_WLK | STA_BUSY); - if (mtc_unit.flags & UNIT_ATT) { /* construct status */ - if (sim_is_active (&mtc_unit)) - data = data | STA_BUSY; + if (mtc_unit.flags & UNIT_ATT) { /* construct status */ + if (sim_is_active (&mtc_unit)) + data = data | STA_BUSY; - if (sim_tape_wrp (&mtc_unit)) - data = data | STA_WLK; - } - else - data = data | STA_BUSY | STA_LOCAL; - break; + if (sim_tape_wrp (&mtc_unit)) + data = data | STA_WLK; + } + else + data = data | STA_BUSY | STA_LOCAL; + + stat_data = IORETURN (SCPE_OK, data); /* merge in return status */ + break; - case ioIOO: /* I/O data output */ - data = data & 0377; - mtc_sta = mtc_sta & ~STA_REJ; /* clear reject */ + case ioIOO: /* I/O data output */ + data = IODATA (stat_data) & DMASK8; + mtc_sta = mtc_sta & ~STA_REJ; /* clear reject */ - if (data == FNC_CLR) { /* clear? */ - mt_clear (); /* send CLR to controller */ + if (data == FNC_CLR) { /* clear? */ + mt_clear (); /* send CLR to controller */ - mtd_flag = mtd_flagbuf = CLEAR; /* clear data flag and flag buffer */ - mtc_flag = mtc_flagbuf = SET; /* set command flag and flag buffer */ - break; /* command completes immediately */ - } + mtd.flag = mtd.flagbuf = CLEAR; /* clear data flag and flag buffer */ + mtc.flag = mtc.flagbuf = SET; /* set command flag and flag buffer */ + break; /* command completes immediately */ + } - for (i = valid = 0; i < sizeof (mtc_cmd); i++) /* is fnc valid? */ - if (data == mtc_cmd[i]) - valid = 1; + for (i = valid = 0; i < mtc_cmd_count; i++) /* is fnc valid? */ + if (data == mtc_cmd[i]) { + valid = 1; + break; + } - if (!valid || sim_is_active (&mtc_unit) || /* is cmd valid? */ - ((mtc_sta & STA_BOT) && (data == FNC_BSR)) || - (sim_tape_wrp (&mtc_unit) && - ((data == FNC_WC) || (data == FNC_GAP) || (data == FNC_WFM)))) - mtc_sta = mtc_sta | STA_REJ; + if (!valid || sim_is_active (&mtc_unit) || /* is cmd valid? */ + ((mtc_sta & STA_BOT) && (data == FNC_BSR)) || + (sim_tape_wrp (&mtc_unit) && + ((data == FNC_WC) || (data == FNC_GAP) || (data == FNC_WFM)))) + mtc_sta = mtc_sta | STA_REJ; - else { - sim_activate (&mtc_unit, mtc_ctime); /* start tape */ - mtc_fnc = data; /* save function */ - mtc_sta = STA_BUSY; /* unit busy */ - mt_ptr = 0; /* init buffer ptr */ + else { + sim_activate (&mtc_unit, mtc_ctime); /* start tape */ + mtc_fnc = data; /* save function */ + mtc_sta = STA_BUSY; /* unit busy */ + mt_ptr = 0; /* init buffer ptr */ - mtcio (select_code, ioCLF, 0); /* clear flags */ - mtcio (mtd_dib.devno, ioCLF, 0); + mtcio (&mtc_dib, ioCLF, 0); /* clear flags */ + mtcio (&mtd_dib, ioCLF, 0); - mtc_1st = 1; /* set 1st flop */ - mtc_dtf = 1; /* set xfer flop */ - } - break; + mtc_1st = 1; /* set 1st flop */ + mtc_dtf = 1; /* set xfer flop */ + } + break; - case ioPOPIO: /* power-on preset to I/O */ - mtc_flag = mtc_flagbuf = CLEAR; /* clear flag and flag buffer */ - /* fall into CRS handler */ - - case ioCRS: /* control reset */ - /* fall into CLC handler */ - - case ioCLC: /* clear control flip-flop */ - mtc_control = CLEAR; - break; + case ioPOPIO: /* power-on preset to I/O */ + mtc.flag = mtc.flagbuf = CLEAR; /* clear flag and flag buffer */ + break; - case ioSTC: /* set control flip-flop */ - mtc_control = SET; - break; + case ioCRS: /* control reset */ + case ioCLC: /* clear control flip-flop */ + mtc.control = CLEAR; + break; - case ioSIR: /* set interrupt request */ - setstdPRL (select_code, mtc); /* set standard PRL signal */ - setstdIRQ (select_code, mtc); /* set standard IRQ signal */ - setstdSRQ (select_code, mtc); /* set standard SRQ signal */ - break; - - case ioIAK: /* interrupt acknowledge */ - mtc_flagbuf = CLEAR; - break; + case ioSTC: /* set control flip-flop */ + mtc.control = SET; + break; - default: /* all other signals */ - break; /* are ignored */ + case ioSIR: /* set interrupt request */ + setstdPRL (mtc); /* set standard PRL signal */ + setstdIRQ (mtc); /* set standard IRQ signal */ + setstdSRQ (mtc); /* set standard SRQ signal */ + break; + + case ioIAK: /* interrupt acknowledge */ + mtc.flagbuf = CLEAR; + break; + + + default: /* all other signals */ + break; /* are ignored */ + } + + working_set = working_set & ~signal; /* remove current signal from set */ } - -if (signal > ioCLF) /* multiple signals? */ - mtcio (select_code, ioCLF, 0); /* issue CLF */ -else if (signal > ioSIR) /* signal affected interrupt status? */ - mtcio (select_code, ioSIR, 0); /* set interrupt request */ - -return data; +return stat_data; } @@ -460,8 +475,8 @@ t_stat st, r = SCPE_OK; if ((mtc_unit.flags & UNIT_ATT) == 0) { /* offline? */ mtc_sta = STA_LOCAL | STA_REJ; /* rejected */ - mtcio (mtc_dib.devno, ioENF, 0); /* set cch flg */ - return IORETURN (mtc_stopioe, SCPE_UNATT); + mtcio (&mtc_dib, ioENF, 0); /* set cch flg */ + return IOERROR (mtc_stopioe, SCPE_UNATT); } switch (mtc_fnc) { /* case on function */ @@ -514,9 +529,9 @@ switch (mtc_fnc) { /* case on function */ } } if (mtc_dtf && (mt_ptr < mt_max)) { /* more chars? */ - if (mtd_flag) mtc_sta = mtc_sta | STA_TIM; + if (mtd.flag) mtc_sta = mtc_sta | STA_TIM; mtc_unit.buf = mtxb[mt_ptr++]; /* fetch next */ - mtdio (mtd_dib.devno, ioENF, 0); /* set dch flg */ + mtdio (&mtd_dib, ioENF, 0); /* set dch flg */ sim_activate (uptr, mtc_xtime); /* re-activate */ return SCPE_OK; } @@ -534,7 +549,7 @@ switch (mtc_fnc) { /* case on function */ else mtc_sta = mtc_sta | STA_PAR; } if (mtc_dtf) { /* xfer flop set? */ - mtdio (mtd_dib.devno, ioENF, 0); /* set dch flg */ + mtdio (&mtd_dib, ioENF, 0); /* set dch flg */ sim_activate (uptr, mtc_xtime); /* re-activate */ return SCPE_OK; } @@ -552,7 +567,7 @@ switch (mtc_fnc) { /* case on function */ break; } -mtcio (mtc_dib.devno, ioENF, 0); /* set cch flg */ +mtcio (&mtc_dib, ioENF, 0); /* set cch flg */ mtc_sta = mtc_sta & ~STA_BUSY; /* not busy */ return r; } @@ -626,13 +641,12 @@ return SCPE_OK; t_stat mt_reset (DEVICE *dptr) { +DIB *dibptr = (DIB *) dptr->ctxt; /* DIB pointer */ + hp_enbdis_pair (dptr, /* make pair cons */ (dptr == &mtd_dev) ? &mtc_dev : &mtd_dev); -if (dptr == &mtc_dev) /* command channel reset? */ - mtcio (mtc_dib.devno, ioPOPIO, 0); /* send POPIO signal to command channel */ -else /* data channel reset */ - mtdio (mtd_dib.devno, ioPOPIO, 0); /* send POPIO signal to data channel */ +IOPRESET (dibptr); /* PRESET device (does not use PON) */ mtc_fnc = 0; mtc_1st = mtc_dtf = 0; diff --git a/HP2100/hp2100_mux.c b/HP2100/hp2100_mux.c index ecd89e87..2712f1c4 100644 --- a/HP2100/hp2100_mux.c +++ b/HP2100/hp2100_mux.c @@ -1,6 +1,6 @@ /* hp2100_mux.c: HP 2100 12920A terminal multiplexor simulator - Copyright (c) 2002-2008, Robert M Supnik + Copyright (c) 2002-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"), @@ -25,6 +25,8 @@ MUX,MUXL,MUXM 12920A terminal multiplexor + 28-Mar-11 JDB Tidied up signal handling + 26-Oct-10 JDB Changed I/O signal handler for revised signal model 25-Nov-08 JDB Revised for new multiplexer library SHOW routines 09-Oct-08 JDB "muxl_unit" defined one too many units (17 instead of 16) 10-Sep-08 JDB SHOW MUX CONN/STAT with SET MUX DIAG is no longer disallowed @@ -265,9 +267,11 @@ static const uint8 odd_par [256] = { /* Multiplexer controller state variables */ -FLIP_FLOP muxl_control = CLEAR; -FLIP_FLOP muxl_flag = CLEAR; -FLIP_FLOP muxl_flagbuf = CLEAR; +struct { + FLIP_FLOP control; /* control flip-flop */ + FLIP_FLOP flag; /* flag flip-flop */ + FLIP_FLOP flagbuf; /* flag buffer flip-flop */ + } muxl = { CLEAR, CLEAR, CLEAR }; uint32 muxl_ibuf = 0; /* low in: rcv data */ uint32 muxl_obuf = 0; /* low out: param */ @@ -275,9 +279,11 @@ uint32 muxl_obuf = 0; /* low out: param */ uint32 muxu_ibuf = 0; /* upr in: status */ uint32 muxu_obuf = 0; /* upr out: chan */ -FLIP_FLOP muxc_control = CLEAR; -FLIP_FLOP muxc_flag = CLEAR; -FLIP_FLOP muxc_flagbuf = CLEAR; +struct { + FLIP_FLOP control; /* control flip-flop */ + FLIP_FLOP flag; /* flag flip-flop */ + FLIP_FLOP flagbuf; /* flag buffer flip-flop */ + } muxc = { CLEAR, CLEAR, CLEAR }; uint32 muxc_chan = 0; /* ctrl chan */ uint32 muxc_scan = 0; /* ctrl scan */ @@ -311,9 +317,10 @@ void mux_diag (int32 c); /* Multiplexer global routines */ -uint32 muxlio (uint32 select_code, IOSIG signal, uint32 data); -uint32 muxuio (uint32 select_code, IOSIG signal, uint32 data); -uint32 muxcio (uint32 select_code, IOSIG signal, uint32 data); +IOHANDLER muxlio; +IOHANDLER muxuio; +IOHANDLER muxcio; + t_stat muxi_svc (UNIT *uptr); t_stat muxo_svc (UNIT *uptr); t_stat muxc_reset (DEVICE *dptr); @@ -334,8 +341,8 @@ TMLN mux_ldsc [MUX_LINES] = { { 0 } }; /* line descriptors TMXR mux_desc = { MUX_LINES, 0, 0, mux_ldsc, mux_order }; /* device descriptor */ DIB mux_dib[] = { - { MUXL, &muxlio }, - { MUXU, &muxuio } + { &muxlio, MUXL }, + { &muxuio, MUXU } }; #define muxl_dib mux_dib[0] @@ -373,9 +380,9 @@ UNIT muxl_unit[] = { }; REG muxl_reg[] = { - { FLDATA (CTL, muxl_control, 0) }, - { FLDATA (FLG, muxl_flag, 0) }, - { FLDATA (FBF, muxl_flagbuf, 0) }, + { FLDATA (CTL, muxl.control, 0) }, + { FLDATA (FLG, muxl.flag, 0) }, + { FLDATA (FBF, muxl.flagbuf, 0) }, { BRDATA (STA, mux_sta, 8, 16, MUX_LINES + MUX_ILINES) }, { BRDATA (RPAR, mux_rpar, 8, 16, MUX_LINES + MUX_ILINES) }, { BRDATA (XPAR, mux_xpar, 8, 16, MUX_LINES) }, @@ -386,7 +393,7 @@ REG muxl_reg[] = { { BRDATA (BDFR, mux_defer, 8, 1, MUX_LINES) }, { URDATA (TIME, muxl_unit[0].wait, 10, 24, 0, MUX_LINES, REG_NZ + PV_LEFT) }, - { ORDATA (DEVNO, muxl_dib.devno, 6), REG_HRO }, + { ORDATA (DEVNO, muxl_dib.select_code, 6), REG_HRO }, { NULL } }; @@ -450,7 +457,7 @@ UNIT muxu_unit = { UDATA (&muxi_svc, UNIT_ATTABLE, 0), POLL_FIRST }; REG muxu_reg[] = { { ORDATA (IBUF, muxu_ibuf, 16) }, { ORDATA (OBUF, muxu_obuf, 16) }, - { ORDATA (DEVNO, muxu_dib.devno, 6), REG_HRO }, + { ORDATA (DEVNO, muxu_dib.select_code, 6), REG_HRO }, { NULL } }; @@ -512,19 +519,19 @@ DEVICE muxu_dev = { DEVICE muxc_dev; -DIB muxc_dib = { MUXC, &muxcio }; +DIB muxc_dib = { &muxcio, MUXC }; UNIT muxc_unit = { UDATA (NULL, 0, 0) }; REG muxc_reg[] = { - { FLDATA (CTL, muxc_control, 0) }, - { FLDATA (FLG, muxc_flag, 0) }, - { FLDATA (FBF, muxc_flagbuf, 0) }, + { FLDATA (CTL, muxc.control, 0) }, + { FLDATA (FLG, muxc.flag, 0) }, + { FLDATA (FBF, muxc.flagbuf, 0) }, { FLDATA (SCAN, muxc_scan, 0) }, { ORDATA (CHAN, muxc_chan, 4) }, { BRDATA (DSO, muxc_ota, 8, 6, MUX_LINES) }, { BRDATA (DSI, muxc_lia, 8, 2, MUX_LINES) }, - { ORDATA (DEVNO, muxc_dib.devno, 6), REG_HRO }, + { ORDATA (DEVNO, muxc_dib.select_code, 6), REG_HRO }, { NULL } }; @@ -570,191 +577,190 @@ DEVICE muxc_dev = { to these 128K CRS invocations. */ -uint32 muxlio (uint32 select_code, IOSIG signal, uint32 data) +uint32 muxlio (DIB *dibptr, IOCYCLE signal_set, uint32 stat_data) { int32 ln; -const char *hold_or_clear = (signal > ioCLF ? ",C" : ""); -const IOSIG base_signal = IOBASE (signal); /* derive base signal */ +const char *hold_or_clear = (signal_set & ioCLF ? ",C" : ""); static uint32 crs_count = 0; /* cntr for ioCRS repeat */ +IOSIGNAL signal; +IOCYCLE working_set = IOADDSIR (signal_set); /* add ioSIR if needed */ -switch (base_signal) { /* dispatch base I/O signal */ - - case ioCLF: /* clear flag flip-flop */ - muxl_flag = muxl_flagbuf = CLEAR; - - if (DEBUG_PRI (muxu_dev, DEB_CMDS)) - fputs (">>MUXl cmds: [CLF] Flag cleared\n", sim_deb); - - mux_data_int (); /* look for new int */ - break; - - - case ioSTF: /* set flag flip-flop */ - case ioENF: /* enable flag */ - muxl_flag = muxl_flagbuf = SET; - - if (DEBUG_PRI (muxu_dev, DEB_CMDS)) - fputs (">>MUXl cmds: [STF] Flag set\n", sim_deb); - break; - - - case ioSFC: /* skip if flag is clear */ - setstdSKF (muxl); - break; - - - case ioSFS: /* skip if flag is set */ - setstdSKF (muxl); - break; - - - case ioIOI: /* I/O data input */ - data = muxl_ibuf; - - if (DEBUG_PRI (muxu_dev, DEB_CPU)) - fprintf (sim_deb, ">>MUXl cpu: [LIx%s] Data = %06o\n", hold_or_clear, data); - break; - - - case ioIOO: /* I/O data output */ - muxl_obuf = data; /* store data */ - - if (DEBUG_PRI (muxu_dev, DEB_CPU)) - if (data & OTL_P) - fprintf (sim_deb, ">>MUXl cpu: [OTx%s] Parameter = %06o\n", hold_or_clear, data); - else - fprintf (sim_deb, ">>MUXl cpu: [OTx%s] Data = %06o\n", hold_or_clear, data); - break; - - - case ioPOPIO: /* power-on preset to I/O */ - muxl_flag = muxl_flagbuf = SET; /* set flag andflag buffer */ - /* fall into CRS handler */ - - case ioCRS: /* control reset */ - if (crs_count) /* already reset? */ - break; /* skip redundant clear */ - - muxl_control = CLEAR; /* clear control flip-flop */ - - for (ln = 0; ln < MUX_LINES; ln++) { /* clear transmit info */ - mux_xbuf[ln] = mux_xpar[ln] = 0; - muxc_ota[ln] = muxc_lia[ln] = mux_xdon[ln] = 0; - } - - for (ln = 0; ln < (MUX_LINES + MUX_ILINES); ln++) { - mux_rbuf[ln] = mux_rpar[ln] = 0; /* clear receive info */ - mux_sta[ln] = mux_rchp[ln] = 0; - } - break; - - - case ioCLC: /* clear control flip-flop */ - muxl_control = CLEAR; - - if (DEBUG_PRI (muxu_dev, DEB_CMDS)) - fprintf (sim_deb, ">>MUXl cmds: [CLC%s] Data interrupt inhibited\n", hold_or_clear); - break; - - - case ioSTC: /* set control flip-flop */ - muxl_control = SET; /* set control */ - - ln = MUX_CHAN (muxu_obuf); /* get chan # */ - - if (muxl_obuf & OTL_TX) { /* transmit? */ - if (ln < MUX_LINES) { /* line valid? */ - if (muxl_obuf & OTL_P) { /* parameter? */ - mux_xpar[ln] = muxl_obuf; /* store param value */ - if (DEBUG_PRI (muxu_dev, DEB_CMDS)) - fprintf (sim_deb, - ">>MUXl cmds: [STC%s] Transmit channel %d parameter %06o stored\n", - hold_or_clear, ln, muxl_obuf); - } - - else { /* data */ - if (mux_xpar[ln] & OTL_TPAR) /* parity requested? */ - muxl_obuf = /* add parity bit */ - muxl_obuf & ~OTL_PAR | - XMT_PAR(muxl_obuf); - mux_xbuf[ln] = muxl_obuf; /* load buffer */ - - if (sim_is_active (&muxl_unit[ln])) { /* still working? */ - mux_sta[ln] = mux_sta[ln] | LIU_LOST; /* char lost */ - if (DEBUG_PRI (muxu_dev, DEB_CMDS)) - fprintf (sim_deb, ">>MUXl cmds: [STC%s] Transmit channel %d data overrun\n", - hold_or_clear, ln); - } - else { - if (muxu_unit.flags & UNIT_DIAG) /* loopback? */ - mux_ldsc[ln].conn = 1; /* connect this line */ - sim_activate (&muxl_unit[ln], muxl_unit[ln].wait); - if (DEBUG_PRI (muxu_dev, DEB_CMDS)) - fprintf (sim_deb, ">>MUXl cmds: [STC%s] Transmit channel %d data %06o scheduled\n", - hold_or_clear, ln, muxl_obuf); - } - } - } - else if (DEBUG_PRI (muxu_dev, DEB_CMDS)) /* line invalid */ - fprintf (sim_deb, ">>MUXl cmds: [STC%s] Transmit channel %d invalid\n", hold_or_clear, ln); - } - - else /* receive */ - if (ln < (MUX_LINES + MUX_ILINES)) { /* line valid? */ - if (muxl_obuf & OTL_P) { /* parameter? */ - mux_rpar[ln] = muxl_obuf; /* store param value */ - if (DEBUG_PRI (muxu_dev, DEB_CMDS)) - fprintf (sim_deb, - ">>MUXl cmds: [STC%s] Receive channel %d parameter %06o stored\n", - hold_or_clear, ln, muxl_obuf); - } - - else if (DEBUG_PRI (muxu_dev, DEB_CMDS)) /* data (invalid action) */ - fprintf (sim_deb, - ">>MUXl cmds: [STC%s] Receive channel %d parameter %06o invalid action\n", - hold_or_clear, ln, muxl_obuf); - } - - else if (DEBUG_PRI (muxu_dev, DEB_CMDS)) /* line invalid */ - fprintf (sim_deb, ">>MUXl cmds: [STC%s] Receive channel %d invalid\n", hold_or_clear, ln); - break; - - - case ioSIR: /* set interrupt request */ - setstdPRL (select_code, muxl); /* set standard PRL signal */ - setstdIRQ (select_code, muxl); /* set standard IRQ signal */ - setstdSRQ (select_code, muxl); /* set standard SRQ signal */ - break; - - - case ioIAK: /* interrupt acknowledge */ - muxl_flagbuf = CLEAR; - break; - - - default: /* all other signals */ - break; /* are ignored */ - } - - -if (signal > ioCLF) /* multiple signals? */ - muxlio (select_code, ioCLF, 0); /* issue CLF */ - -else if (signal > ioSIR) /* signal affected interrupt status? */ - muxlio (select_code, ioSIR, 0); /* set interrupt request */ - - -if (signal == ioCRS) /* control reset? */ - crs_count = crs_count + 1; /* increment count */ - -else if (crs_count && (signal != ioSIR)) { /* counting CRSes? */ +if (crs_count && !(signal_set & ioCRS)) { /* counting CRSes and not present? */ if (DEBUG_PRI (muxu_dev, DEB_CMDS)) /* report reset count */ fprintf (sim_deb, ">>MUXl cmds: [CRS] Multiplexer reset %d times\n", crs_count); + crs_count = 0; /* clear counter */ } -return data; +while (working_set) { + signal = IONEXT (working_set); /* isolate next signal */ + + switch (signal) { /* dispatch I/O signal */ + + case ioCLF: /* clear flag flip-flop */ + muxl.flag = muxl.flagbuf = CLEAR; + + if (DEBUG_PRI (muxu_dev, DEB_CMDS)) + fputs (">>MUXl cmds: [CLF] Flag cleared\n", sim_deb); + + mux_data_int (); /* look for new int */ + break; + + + case ioSTF: /* set flag flip-flop */ + case ioENF: /* enable flag */ + muxl.flag = muxl.flagbuf = SET; + + if (DEBUG_PRI (muxu_dev, DEB_CMDS)) + fputs (">>MUXl cmds: [STF] Flag set\n", sim_deb); + break; + + + case ioSFC: /* skip if flag is clear */ + setstdSKF (muxl); + break; + + + case ioSFS: /* skip if flag is set */ + setstdSKF (muxl); + break; + + + case ioIOI: /* I/O data input */ + stat_data = IORETURN (SCPE_OK, muxl_ibuf); /* merge in return status */ + + if (DEBUG_PRI (muxu_dev, DEB_CPU)) + fprintf (sim_deb, ">>MUXl cpu: [LIx%s] Data = %06o\n", hold_or_clear, muxl_ibuf); + break; + + + case ioIOO: /* I/O data output */ + muxl_obuf = IODATA (stat_data); /* store data */ + + if (DEBUG_PRI (muxu_dev, DEB_CPU)) + if (muxl_obuf & OTL_P) + fprintf (sim_deb, ">>MUXl cpu: [OTx%s] Parameter = %06o\n", hold_or_clear, muxl_obuf); + else + fprintf (sim_deb, ">>MUXl cpu: [OTx%s] Data = %06o\n", hold_or_clear, muxl_obuf); + break; + + + case ioPOPIO: /* power-on preset to I/O */ + muxl.flag = muxl.flagbuf = SET; /* set flag andflag buffer */ + break; + + + case ioCRS: /* control reset */ + if (crs_count == 0) { /* first reset? */ + muxl.control = CLEAR; /* clear control flip-flop */ + + for (ln = 0; ln < MUX_LINES; ln++) { /* clear transmit info */ + mux_xbuf[ln] = mux_xpar[ln] = 0; + muxc_ota[ln] = muxc_lia[ln] = mux_xdon[ln] = 0; + } + + for (ln = 0; ln < (MUX_LINES + MUX_ILINES); ln++) { + mux_rbuf[ln] = mux_rpar[ln] = 0; /* clear receive info */ + mux_sta[ln] = mux_rchp[ln] = 0; + } + } + + crs_count = crs_count + 1; /* increment count */ + break; + + + case ioCLC: /* clear control flip-flop */ + muxl.control = CLEAR; + + if (DEBUG_PRI (muxu_dev, DEB_CMDS)) + fprintf (sim_deb, ">>MUXl cmds: [CLC%s] Data interrupt inhibited\n", hold_or_clear); + break; + + + case ioSTC: /* set control flip-flop */ + muxl.control = SET; /* set control */ + + ln = MUX_CHAN (muxu_obuf); /* get chan # */ + + if (muxl_obuf & OTL_TX) { /* transmit? */ + if (ln < MUX_LINES) { /* line valid? */ + if (muxl_obuf & OTL_P) { /* parameter? */ + mux_xpar[ln] = muxl_obuf; /* store param value */ + if (DEBUG_PRI (muxu_dev, DEB_CMDS)) + fprintf (sim_deb, + ">>MUXl cmds: [STC%s] Transmit channel %d parameter %06o stored\n", + hold_or_clear, ln, muxl_obuf); + } + + else { /* data */ + if (mux_xpar[ln] & OTL_TPAR) /* parity requested? */ + muxl_obuf = /* add parity bit */ + muxl_obuf & ~OTL_PAR | + XMT_PAR(muxl_obuf); + mux_xbuf[ln] = muxl_obuf; /* load buffer */ + + if (sim_is_active (&muxl_unit[ln])) { /* still working? */ + mux_sta[ln] = mux_sta[ln] | LIU_LOST; /* char lost */ + if (DEBUG_PRI (muxu_dev, DEB_CMDS)) + fprintf (sim_deb, ">>MUXl cmds: [STC%s] Transmit channel %d data overrun\n", + hold_or_clear, ln); + } + else { + if (muxu_unit.flags & UNIT_DIAG) /* loopback? */ + mux_ldsc[ln].conn = 1; /* connect this line */ + sim_activate (&muxl_unit[ln], muxl_unit[ln].wait); + if (DEBUG_PRI (muxu_dev, DEB_CMDS)) + fprintf (sim_deb, ">>MUXl cmds: [STC%s] Transmit channel %d data %06o scheduled\n", + hold_or_clear, ln, muxl_obuf); + } + } + } + else if (DEBUG_PRI (muxu_dev, DEB_CMDS)) /* line invalid */ + fprintf (sim_deb, ">>MUXl cmds: [STC%s] Transmit channel %d invalid\n", hold_or_clear, ln); + } + + else /* receive */ + if (ln < (MUX_LINES + MUX_ILINES)) { /* line valid? */ + if (muxl_obuf & OTL_P) { /* parameter? */ + mux_rpar[ln] = muxl_obuf; /* store param value */ + if (DEBUG_PRI (muxu_dev, DEB_CMDS)) + fprintf (sim_deb, + ">>MUXl cmds: [STC%s] Receive channel %d parameter %06o stored\n", + hold_or_clear, ln, muxl_obuf); + } + + else if (DEBUG_PRI (muxu_dev, DEB_CMDS)) /* data (invalid action) */ + fprintf (sim_deb, + ">>MUXl cmds: [STC%s] Receive channel %d parameter %06o invalid action\n", + hold_or_clear, ln, muxl_obuf); + } + + else if (DEBUG_PRI (muxu_dev, DEB_CMDS)) /* line invalid */ + fprintf (sim_deb, ">>MUXl cmds: [STC%s] Receive channel %d invalid\n", hold_or_clear, ln); + break; + + + case ioSIR: /* set interrupt request */ + setstdPRL (muxl); /* set standard PRL signal */ + setstdIRQ (muxl); /* set standard IRQ signal */ + setstdSRQ (muxl); /* set standard SRQ signal */ + break; + + + case ioIAK: /* interrupt acknowledge */ + muxl.flagbuf = CLEAR; + break; + + + default: /* all other signals */ + break; /* are ignored */ + } + + working_set = working_set & ~signal; /* remove current signal from set */ + } + +return stat_data; } @@ -771,34 +777,41 @@ return data; the lower data card CRS handler. */ -uint32 muxuio (uint32 select_code, IOSIG signal, uint32 data) +uint32 muxuio (DIB *dibptr, IOCYCLE signal_set, uint32 stat_data) { -const IOSIG base_signal = IOBASE (signal); /* derive base signal */ +IOSIGNAL signal; +IOCYCLE working_set = IOADDSIR (signal_set); /* add ioSIR if needed */ -switch (base_signal) { /* dispatch base I/O signal */ +while (working_set) { + signal = IONEXT (working_set); /* isolate next signal */ - case ioIOI: /* I/O data input */ - data = muxu_ibuf; + switch (signal) { /* dispatch I/O signal */ - if (DEBUG_PRI (muxu_dev, DEB_CPU)) - fprintf (sim_deb, ">>MUXu cpu: [LIx] Status = %06o, channel = %d\n", - data, MUX_CHAN(data)); - break; + case ioIOI: /* I/O data input */ + stat_data = IORETURN (SCPE_OK, muxu_ibuf); /* merge in return status */ + + if (DEBUG_PRI (muxu_dev, DEB_CPU)) + fprintf (sim_deb, ">>MUXu cpu: [LIx] Status = %06o, channel = %d\n", + muxu_ibuf, MUX_CHAN(muxu_ibuf)); + break; - case ioIOO: /* I/O data output */ - muxu_obuf = data; /* store data */ + case ioIOO: /* I/O data output */ + muxu_obuf = IODATA (stat_data); /* store data */ - if (DEBUG_PRI (muxu_dev, DEB_CPU)) - fprintf (sim_deb, ">>MUXu cpu: [OTx] Data channel = %d\n", MUX_CHAN(data)); - break; + if (DEBUG_PRI (muxu_dev, DEB_CPU)) + fprintf (sim_deb, ">>MUXu cpu: [OTx] Data channel = %d\n", MUX_CHAN(muxu_obuf)); + break; - default: /* all other signals */ - break; /* are ignored */ + default: /* all other signals */ + break; /* are ignored */ + } + + working_set = working_set & ~signal; /* remove current signal from set */ } -return data; +return stat_data; } @@ -809,139 +822,142 @@ return data; test is performed after IOO processing. */ -uint32 muxcio (uint32 select_code, IOSIG signal, uint32 data) +uint32 muxcio (DIB *dibptr, IOCYCLE signal_set, uint32 stat_data) { -const char *hold_or_clear = (signal > ioCLF ? ",C" : ""); -const IOSIG base_signal = IOBASE (signal); /* derive base signal */ +const char *hold_or_clear = (signal_set & ioCLF ? ",C" : ""); +uint16 data; int32 ln, old; +IOSIGNAL signal; +IOCYCLE working_set = IOADDSIR (signal_set); /* add ioSIR if needed */ -switch (base_signal) { /* dispatch base I/O signal */ +while (working_set) { + signal = IONEXT (working_set); /* isolate next signal */ - case ioCLF: /* clear flag flip-flop */ - muxc_flag = muxc_flagbuf = CLEAR; + switch (signal) { /* dispatch I/O signal */ - if (DEBUG_PRI (muxu_dev, DEB_CMDS)) - fputs (">>MUXc cmds: [CLF] Flag cleared\n", sim_deb); + case ioCLF: /* clear flag flip-flop */ + muxc.flag = muxc.flagbuf = CLEAR; - mux_ctrl_int (); /* look for new int */ - break; + if (DEBUG_PRI (muxu_dev, DEB_CMDS)) + fputs (">>MUXc cmds: [CLF] Flag cleared\n", sim_deb); + + mux_ctrl_int (); /* look for new int */ + break; - case ioSTF: /* set flag flip-flop */ - case ioENF: /* enable flag */ - muxc_flag = muxc_flagbuf = SET; + case ioSTF: /* set flag flip-flop */ + case ioENF: /* enable flag */ + muxc.flag = muxc.flagbuf = SET; - if (DEBUG_PRI (muxu_dev, DEB_CMDS)) - fputs (">>MUXc cmds: [STF] Flag set\n", sim_deb); - break; + if (DEBUG_PRI (muxu_dev, DEB_CMDS)) + fputs (">>MUXc cmds: [STF] Flag set\n", sim_deb); + break; - case ioSFC: /* skip if flag is clear */ - setstdSKF (muxc); - break; + case ioSFC: /* skip if flag is clear */ + setstdSKF (muxc); + break; - case ioSFS: /* skip if flag is set */ - setstdSKF (muxc); - break; + case ioSFS: /* skip if flag is set */ + setstdSKF (muxc); + break; - case ioIOI: /* I/O data input */ - data = LIC_MBO | PUT_CCH (muxc_chan) | /* mbo, chan num */ - LIC_TSTI (muxc_chan) | /* I2, I1 */ - (muxc_ota[muxc_chan] & (OTC_ES2 | OTC_ES1)) | /* ES2, ES1 */ - (muxc_lia[muxc_chan] & (LIC_S2 | LIC_S1)); /* S2, S1 */ + case ioIOI: /* I/O data input */ + data = LIC_MBO | PUT_CCH (muxc_chan) | /* mbo, chan num */ + LIC_TSTI (muxc_chan) | /* I2, I1 */ + (muxc_ota[muxc_chan] & (OTC_ES2 | OTC_ES1)) | /* ES2, ES1 */ + (muxc_lia[muxc_chan] & (LIC_S2 | LIC_S1)); /* S2, S1 */ - if (DEBUG_PRI (muxu_dev, DEB_CPU)) - fprintf (sim_deb, ">>MUXc cpu: [LIx%s] Status = %06o, channel = %d\n", - hold_or_clear, data, muxc_chan); + if (DEBUG_PRI (muxu_dev, DEB_CPU)) + fprintf (sim_deb, ">>MUXc cpu: [LIx%s] Status = %06o, channel = %d\n", + hold_or_clear, data, muxc_chan); - muxc_chan = (muxc_chan + 1) & LIC_M_CHAN; /* incr channel */ - break; + muxc_chan = (muxc_chan + 1) & LIC_M_CHAN; /* incr channel */ + stat_data = IORETURN (SCPE_OK, data); /* merge in return status */ + break; - case ioIOO: /* I/O data output */ - ln = muxc_chan = OTC_CHAN (data); /* set channel */ + case ioIOO: /* I/O data output */ + data = IODATA (stat_data); /* clear supplied status */ + ln = muxc_chan = OTC_CHAN (data); /* set channel */ - if (data & OTC_SCAN) muxc_scan = 1; /* set scan flag */ - else muxc_scan = 0; + if (data & OTC_SCAN) muxc_scan = 1; /* set scan flag */ + else muxc_scan = 0; - if (data & OTC_UPD) { /* update? */ - old = muxc_ota[ln]; /* save prior val */ - muxc_ota[ln] = /* save ESn,SSn */ - (muxc_ota[ln] & ~OTC_RW) | (data & OTC_RW); + if (data & OTC_UPD) { /* update? */ + old = muxc_ota[ln]; /* save prior val */ + muxc_ota[ln] = /* save ESn,SSn */ + (muxc_ota[ln] & ~OTC_RW) | (data & OTC_RW); - if (data & OTC_EC2) /* if EC2, upd C2 */ - muxc_ota[ln] = - (muxc_ota[ln] & ~OTC_C2) | (data & OTC_C2); + if (data & OTC_EC2) /* if EC2, upd C2 */ + muxc_ota[ln] = + (muxc_ota[ln] & ~OTC_C2) | (data & OTC_C2); - if (data & OTC_EC1) /* if EC1, upd C1 */ - muxc_ota[ln] = - (muxc_ota[ln] & ~OTC_C1) | (data & OTC_C1); + if (data & OTC_EC1) /* if EC1, upd C1 */ + muxc_ota[ln] = + (muxc_ota[ln] & ~OTC_C1) | (data & OTC_C1); - if (muxu_unit.flags & UNIT_DIAG) /* loopback? */ - muxc_lia[ln ^ 1] = /* set S1, S2 to C1, C2 */ - (muxc_lia[ln ^ 1] & ~(LIC_S2 | LIC_S1)) | - (muxc_ota[ln] & (OTC_C1 | OTC_C2)) >> OTC_V_C; + if (muxu_unit.flags & UNIT_DIAG) /* loopback? */ + muxc_lia[ln ^ 1] = /* set S1, S2 to C1, C2 */ + (muxc_lia[ln ^ 1] & ~(LIC_S2 | LIC_S1)) | + (muxc_ota[ln] & (OTC_C1 | OTC_C2)) >> OTC_V_C; - else if ((muxl_unit[ln].flags & UNIT_MDM) && /* modem ctrl? */ - (old & DTR) && /* DTR drop? */ - !(muxc_ota[ln] & DTR)) { - tmxr_linemsg (&mux_ldsc[ln], "\r\nLine hangup\r\n"); - tmxr_reset_ln (&mux_ldsc[ln]); /* reset line */ - muxc_lia[ln] = 0; /* dataset off */ - } - } /* end update */ + else if ((muxl_unit[ln].flags & UNIT_MDM) && /* modem ctrl? */ + (old & DTR) && /* DTR drop? */ + !(muxc_ota[ln] & DTR)) { + tmxr_linemsg (&mux_ldsc[ln], "\r\nLine hangup\r\n"); + tmxr_reset_ln (&mux_ldsc[ln]); /* reset line */ + muxc_lia[ln] = 0; /* dataset off */ + } + } /* end update */ - if (DEBUG_PRI (muxu_dev, DEB_CPU)) - fprintf (sim_deb, ">>MUXc cpu: [OTx%s] Parameter = %06o, channel = %d\n", - hold_or_clear, data, ln); + if (DEBUG_PRI (muxu_dev, DEB_CPU)) + fprintf (sim_deb, ">>MUXc cpu: [OTx%s] Parameter = %06o, channel = %d\n", + hold_or_clear, data, ln); - if ((muxu_unit.flags & UNIT_DIAG) && (!muxc_flag)) /* loopback and flag clear? */ - mux_ctrl_int (); /* status chg may interrupt */ - break; + if ((muxu_unit.flags & UNIT_DIAG) && (!muxc.flag)) /* loopback and flag clear? */ + mux_ctrl_int (); /* status chg may interrupt */ + break; - case ioPOPIO: /* power-on preset to I/O */ - muxc_flag = muxc_flagbuf = SET; /* set flag and flag buffer */ - /* fall into CRS handler */ - - case ioCRS: /* control reset */ - /* fall into CLC handler */ - - case ioCLC: /* clear control flip-flop */ - muxc_control = CLEAR; - break; + case ioPOPIO: /* power-on preset to I/O */ + muxc.flag = muxc.flagbuf = SET; /* set flag and flag buffer */ + break; - case ioSTC: /* set control flip-flop */ - muxc_control = SET; - break; + case ioCRS: /* control reset */ + case ioCLC: /* clear control flip-flop */ + muxc.control = CLEAR; + break; - case ioSIR: /* set interrupt request */ - setstdPRL (select_code, muxc); /* set standard PRL signal */ - setstdIRQ (select_code, muxc); /* set standard IRQ signal */ - setstdSRQ (select_code, muxc); /* set standard SRQ signal */ - break; + case ioSTC: /* set control flip-flop */ + muxc.control = SET; + break; - case ioIAK: /* interrupt acknowledge */ - muxc_flagbuf = CLEAR; - break; + case ioSIR: /* set interrupt request */ + setstdPRL (muxc); /* set standard PRL signal */ + setstdIRQ (muxc); /* set standard IRQ signal */ + setstdSRQ (muxc); /* set standard SRQ signal */ + break; - default: /* all other signals */ - break; /* are ignored */ + case ioIAK: /* interrupt acknowledge */ + muxc.flagbuf = CLEAR; + break; + + + default: /* all other signals */ + break; /* are ignored */ + } + + working_set = working_set & ~signal; /* remove current signal from set */ } - -if (signal > ioCLF) /* multiple signals? */ - muxcio (select_code, ioCLF, 0); /* issue CLF */ -else if (signal > ioSIR) /* signal affected interrupt status? */ - muxcio (select_code, ioSIR, 0); /* set interrupt request */ - -return data; +return stat_data; } @@ -1004,8 +1020,8 @@ for (ln = 0; ln < MUX_LINES; ln++) { /* loop thru lines */ muxc_lia[ln] = 0; /* line disconnected */ } -if (!muxl_flag) mux_data_int (); /* scan for data int */ -if (!muxc_flag) mux_ctrl_int (); /* scan modem */ +if (!muxl.flag) mux_data_int (); /* scan for data int */ +if (!muxc.flag) mux_ctrl_int (); /* scan modem */ return SCPE_OK; } @@ -1066,7 +1082,7 @@ if (mux_ldsc[ln].conn) { /* connected? */ } } -if (!muxl_flag) mux_data_int (); /* scan for int */ +if (!muxl.flag) mux_data_int (); /* scan for int */ return SCPE_OK; } @@ -1143,7 +1159,7 @@ for (i = 0; i < MUX_LINES; i++) { /* rcv lines */ if (DEBUG_PRI (muxu_dev, DEB_CMDS)) fprintf (sim_deb, ">>MUXl cmds: Receive channel %d interrupt requested\n", i); - muxlio (muxl_dib.devno, ioENF, 0); /* interrupt */ + muxlio (&muxl_dib, ioENF, 0); /* interrupt */ return; } } @@ -1159,7 +1175,7 @@ for (i = 0; i < MUX_LINES; i++) { /* xmt lines */ if (DEBUG_PRI (muxu_dev, DEB_CMDS)) fprintf (sim_deb, ">>MUXl cmds: Transmit channel %d interrupt requested\n", i); - muxlio (muxl_dib.devno, ioENF, 0); /* interrupt */ + muxlio (&muxl_dib, ioENF, 0); /* interrupt */ return; } } @@ -1175,7 +1191,7 @@ for (i = MUX_LINES; i < (MUX_LINES + MUX_ILINES); i++) { /* diag lines */ if (DEBUG_PRI (muxu_dev, DEB_CMDS)) fprintf (sim_deb, ">>MUXl cmds: Receive channel %d interrupt requested\n", i); - muxlio (muxl_dib.devno, ioENF, 0); /* interrupt */ + muxlio (&muxl_dib, ioENF, 0); /* interrupt */ return; } } @@ -1208,7 +1224,7 @@ for (i = 0; i < line_count; i++) { ">>MUXc cmds: Control channel %d interrupt requested (poll = %d)\n", muxc_chan, i + 1); - muxcio (muxc_dib.devno, ioENF, 0); /* set flag */ + muxcio (&muxc_dib, ioENF, 0); /* set flag */ break; } } @@ -1260,6 +1276,7 @@ return; t_stat muxc_reset (DEVICE *dptr) { int32 i; +DIB *dibptr = (DIB *) dptr->ctxt; /* DIB pointer */ if (dptr == &muxc_dev) { /* make all consistent */ hp_enbdis_pair (dptr, &muxl_dev); @@ -1274,12 +1291,7 @@ else { hp_enbdis_pair (dptr, &muxl_dev); } -if (dptr == &muxl_dev) /* lower data reset? */ - muxlio (muxl_dib.devno, ioPOPIO, 0); /* send POPIO signal to lower data card */ -else if (dptr == &muxu_dev) /* upper data reset? */ - muxuio (muxu_dib.devno, ioPOPIO, 0); /* send POPIO signal to upper data card */ -else /* control card reset */ - muxcio (muxc_dib.devno, ioPOPIO, 0); /* send POPIO signal to control card */ +IOPRESET (dibptr); /* PRESET device (does not use PON) */ muxc_chan = muxc_scan = 0; /* init modem scan */ diff --git a/HP2100/hp2100_pif.c b/HP2100/hp2100_pif.c index 6ce98a00..494f5860 100644 --- a/HP2100/hp2100_pif.c +++ b/HP2100/hp2100_pif.c @@ -1,6 +1,6 @@ /* hp2100_pif.c: HP 12620A/12936A privileged interrupt fence simulator - Copyright (c) 2008, J. David Bryan + Copyright (c) 2008-2011, J. David Bryan Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), @@ -25,6 +25,8 @@ PIF 12620A/12936A privileged interrupt fence + 28-Mar-11 JDB Tidied up signal handling + 26-Oct-10 JDB Changed I/O signal handler for revised signal model 26-Jun-08 JDB Rewrote device I/O to model backplane signals 18-Jun-08 JDB Created PIF device @@ -103,14 +105,16 @@ /* PIF state variables */ -FLIP_FLOP pif_control = CLEAR; /* control flip-flop */ -FLIP_FLOP pif_flag = CLEAR; /* flag flip-flop */ -FLIP_FLOP pif_flagbuf = CLEAR; /* flag buffer flip-flop */ +struct { + FLIP_FLOP control; /* control flip-flop */ + FLIP_FLOP flag; /* flag flip-flop */ + FLIP_FLOP flagbuf; /* flag buffer flip-flop */ + } pif = { CLEAR, CLEAR, CLEAR }; /* PIF global routines */ -uint32 pif_io (uint32 select_code, IOSIG signal, uint32 data); +IOHANDLER pif_io; t_stat pif_reset (DEVICE *dptr); t_stat pif_set_card (UNIT *uptr, int32 val, char *cptr, void *desc); @@ -136,17 +140,17 @@ t_stat pif_show_card (FILE *st, UNIT *uptr, int32 val, void *desc); DEVICE pif_dev; -DIB pif_dib = { PIF, &pif_io }; +DIB pif_dib = { &pif_io, PIF }; UNIT pif_unit = { UDATA (NULL, 0, 0) /* dummy unit */ }; REG pif_reg [] = { - { FLDATA (CTL, pif_control, 0) }, - { FLDATA (FLG, pif_flag, 0) }, - { FLDATA (FBF, pif_flagbuf, 0) }, - { ORDATA (DEVNO, pif_dib.devno, 6), REG_HRO }, + { FLDATA (CTL, pif.control, 0) }, + { FLDATA (FLG, pif.flag, 0) }, + { FLDATA (FBF, pif.flagbuf, 0) }, + { ORDATA (DEVNO, pif_dib.select_code, 6), REG_HRO }, { NULL } }; @@ -155,7 +159,6 @@ MTAB pif_mod [] = { { MTAB_XTD | MTAB_VDV, 1, NULL, "12936A", &pif_set_card, NULL, NULL }, { MTAB_XTD | MTAB_VDV, 0, "TYPE", NULL, NULL, &pif_show_card, NULL }, { MTAB_XTD | MTAB_VDV, 0, "DEVNO", "DEVNO", &hp_setdev, &hp_showdev, &pif_dev }, - { 0 } }; @@ -184,7 +187,6 @@ DEVICE pif_dev = { NULL }; /* logical device name */ - /* I/O signal handler. Operation of the 12620A and the 12936A is different. The I/O responses of @@ -210,118 +212,120 @@ DEVICE pif_dev = { Note that PRL and IRQ are non-standard for the 12936A. */ -uint32 pif_io (uint32 select_code, IOSIG signal, uint32 data) +uint32 pif_io (DIB *dibptr, IOCYCLE signal_set, uint32 stat_data) { -const char *hold_or_clear = (signal > ioCLF ? ",C" : ""); +const char *hold_or_clear = (signal_set & ioCLF ? ",C" : ""); const t_bool is_rte_pif = (pif_dev.flags & DEV_12936) == 0; -const IOSIG base_signal = IOBASE (signal); /* derive base signal */ -switch (base_signal) { /* dispatch base I/O signal */ +IOSIGNAL signal; +IOCYCLE working_set = IOADDSIR (signal_set); /* add ioSIR if needed */ - case ioCLF: /* clear flag flip-flop */ - pif_flag = pif_flagbuf = CLEAR; /* clear flag buffer and flag */ +while (working_set) { + signal = IONEXT (working_set); /* isolate next signal */ - if (DEBUG_PRS (pif_dev)) - fputs (">>PIF: [CLF] Flag cleared\n", sim_deb); - break; + switch (signal) { /* dispatch I/O signal */ - - case ioSTF: /* set flag flip-flop */ - if (is_rte_pif) { /* RTE PIF? */ - pif_flag = pif_flagbuf = SET; /* set flag buffer and flag */ + case ioCLF: /* clear flag flip-flop */ + pif.flag = pif.flagbuf = CLEAR; /* clear flag buffer and flag */ if (DEBUG_PRS (pif_dev)) - fputs (">>PIF: [STF] Flag set\n", sim_deb); - } - break; + fputs (">>PIF: [CLF] Flag cleared\n", sim_deb); + break; - case ioSFC: /* skip if flag is clear */ - if (is_rte_pif) /* RTE PIF? */ - setstdSKF (pif); /* card responds to SFC */ - break; + case ioSTF: /* set flag flip-flop */ + if (is_rte_pif) { /* RTE PIF? */ + pif.flag = pif.flagbuf = SET; /* set flag buffer and flag */ + + if (DEBUG_PRS (pif_dev)) + fputs (">>PIF: [STF] Flag set\n", sim_deb); + } + break; - case ioSFS: /* skip if flag is set */ - if (is_rte_pif) /* RTE PIF? */ - setstdSKF (pif); /* card responds to SFS */ - break; + case ioSFC: /* skip if flag is clear */ + if (is_rte_pif) /* RTE PIF? */ + setstdSKF (pif); /* card responds to SFC */ + break; - case ioIOO: /* I/O data output */ - if (!is_rte_pif) { /* DOS PIF? */ - pif_flag = pif_flagbuf = SET; /* set flag buffer and flag */ - pif_io (select_code, ioSIR, 0); /* set IRQ (not normally done for IOO) */ + case ioSFS: /* skip if flag is set */ + if (is_rte_pif) /* RTE PIF? */ + setstdSKF (pif); /* card responds to SFS */ + break; + + + case ioIOO: /* I/O data output */ + if (!is_rte_pif) { /* DOS PIF? */ + pif.flag = pif.flagbuf = SET; /* set flag buffer and flag */ + working_set = working_set | ioSIR; /* set SIR (not normally done for IOO) */ + + if (DEBUG_PRS (pif_dev)) + fprintf (sim_deb, ">>PIF: [OTx%s] Flag set\n", hold_or_clear); + } + break; + + + case ioPOPIO: /* power-on preset to I/O */ + pif.flag = pif.flagbuf = /* set or clear flag and flag buffer */ + (is_rte_pif ? SET : CLEAR); if (DEBUG_PRS (pif_dev)) - fprintf (sim_deb, ">>PIF: [OTx%s] Flag set\n", hold_or_clear); - } - break; + fprintf (sim_deb, ">>PIF: [POPIO] Flag %s\n", + (is_rte_pif ? "set" : "cleared")); + break; - case ioPOPIO: /* power-on preset to I/O */ - pif_flag = pif_flagbuf = /* set or clear flag and flag buffer */ - (is_rte_pif ? SET : CLEAR); + case ioCRS: /* control reset */ + case ioCLC: /* clear control flip-flop */ + pif.control = CLEAR; /* clear control */ - if (DEBUG_PRS (pif_dev)) - fprintf (sim_deb, ">>PIF: [POPIO] Flag %s\n", - (is_rte_pif ? "set" : "cleared")); - /* fall into CRS handler */ - - case ioCRS: /* control reset */ - /* fall into CLC handler */ - - case ioCLC: /* clear control flip-flop */ - pif_control = CLEAR; /* clear control */ - - if (DEBUG_PRS (pif_dev)) - fprintf (sim_deb, ">>PIF: [%s%s] Control cleared\n", - (signal == ioCRS ? "CRS" : "CLC"), hold_or_clear); - break; + if (DEBUG_PRS (pif_dev)) + fprintf (sim_deb, ">>PIF: [%s%s] Control cleared\n", + (signal == ioCRS ? "CRS" : "CLC"), hold_or_clear); + break; - case ioSTC: /* set control flip-flop */ - pif_control = SET; /* set control */ + case ioSTC: /* set control flip-flop */ + pif.control = SET; /* set control */ - if (DEBUG_PRS (pif_dev)) - fprintf (sim_deb, ">>PIF: [STC%s] Control set\n", hold_or_clear); - break; + if (DEBUG_PRS (pif_dev)) + fprintf (sim_deb, ">>PIF: [STC%s] Control set\n", hold_or_clear); + break; - case ioSIR: /* set interrupt request */ - if (is_rte_pif) { /* RTE PIF? */ - setstdPRL (select_code, pif); /* set standard PRL signal */ - setstdIRQ (select_code, pif); /* set standard IRQ signal */ - setstdSRQ (select_code, pif); /* set standard SRQ signal */ - } + case ioSIR: /* set interrupt request */ + if (is_rte_pif) { /* RTE PIF? */ + setstdPRL (pif); /* set standard PRL signal */ + setstdIRQ (pif); /* set standard IRQ signal */ + setstdSRQ (pif); /* set standard SRQ signal */ + } - else { /* DOS PIF */ - setPRL (select_code, !(pif_control | pif_flag)); - setIRQ (select_code, !pif_control & pif_flag & pif_flagbuf); - } + else { /* DOS PIF */ + setPRL (dibptr->select_code, !(pif.control | pif.flag)); + setIRQ (dibptr->select_code, !pif.control & pif.flag & pif.flagbuf); + } - if (DEBUG_PRS (pif_dev)) - fprintf (sim_deb, ">>PIF: [SIR] PRL = %d, IRQ = %d\n", - PRL (select_code), IRQ (select_code)); - break; + if (DEBUG_PRS (pif_dev)) + fprintf (sim_deb, ">>PIF: [SIR] PRL = %d, IRQ = %d\n", + PRL (dibptr->select_code), + IRQ (dibptr->select_code)); + break; - case ioIAK: /* interrupt acknowledge */ - pif_flagbuf = CLEAR; - break; + case ioIAK: /* interrupt acknowledge */ + pif.flagbuf = CLEAR; + break; - default: /* all other signals */ - break; /* are ignored */ + default: /* all other signals */ + break; /* are ignored */ + } + + working_set = working_set & ~signal; /* remove current signal from set */ } - -if (signal > ioCLF) /* multiple signals? */ - pif_io (select_code, ioCLF, 0); /* issue CLF */ -else if (signal > ioSIR) /* signal affected interrupt status? */ - pif_io (select_code, ioSIR, 0); /* set interrupt request */ - -return data; +return stat_data; } @@ -329,7 +333,7 @@ return data; t_stat pif_reset (DEVICE *dptr) { -pif_io (pif_dib.devno, ioPOPIO, 0); /* send POPIO signal */ +IOPRESET (&pif_dib); /* PRESET device (does not use PON) */ return SCPE_OK; } diff --git a/HP2100/hp2100_stddev.c b/HP2100/hp2100_stddev.c index 5389bdf2..ebc8c04f 100644 --- a/HP2100/hp2100_stddev.c +++ b/HP2100/hp2100_stddev.c @@ -1,6 +1,6 @@ /* hp2100_stddev.c: HP2100 standard devices simulator - Copyright (c) 1993-2008, Robert M. Supnik + Copyright (c) 1993-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"), @@ -28,6 +28,8 @@ TTY 12531C buffered teleprinter interface CLK 12539C time base generator + 28-Mar-11 JDB Tidied up signal handling + 26-Oct-10 JDB Changed I/O signal handler for revised signal model 26-Jun-08 JDB Rewrote device I/O to model backplane signals 25-Apr-08 JDB Changed TTY output wait from 100 to 200 for MSU BASIC 18-Apr-08 JDB Removed redundant control char handling definitions @@ -125,23 +127,29 @@ #define CLK_V_ERROR 4 /* clock overrun */ #define CLK_ERROR (1 << CLK_V_ERROR) -FLIP_FLOP ptr_control = CLEAR; -FLIP_FLOP ptr_flag = CLEAR; -FLIP_FLOP ptr_flagbuf = CLEAR; +struct { + FLIP_FLOP control; /* control flip-flop */ + FLIP_FLOP flag; /* flag flip-flop */ + FLIP_FLOP flagbuf; /* flag buffer flip-flop */ + } ptr = { CLEAR, CLEAR, CLEAR }; int32 ptr_stopioe = 0; /* stop on error */ int32 ptr_trlcnt = 0; /* trailer counter */ int32 ptr_trllim = 40; /* trailer to add */ -FLIP_FLOP ptp_control = CLEAR; -FLIP_FLOP ptp_flag = CLEAR; -FLIP_FLOP ptp_flagbuf = CLEAR; +struct { + FLIP_FLOP control; /* control flip-flop */ + FLIP_FLOP flag; /* flag flip-flop */ + FLIP_FLOP flagbuf; /* flag buffer flip-flop */ + } ptp = { CLEAR, CLEAR, CLEAR }; int32 ptp_stopioe = 0; -FLIP_FLOP tty_control = CLEAR; -FLIP_FLOP tty_flag = CLEAR; -FLIP_FLOP tty_flagbuf = CLEAR; +struct { + FLIP_FLOP control; /* control flip-flop */ + FLIP_FLOP flag; /* flag flip-flop */ + FLIP_FLOP flagbuf; /* flag buffer flip-flop */ + } tty = { CLEAR, CLEAR, CLEAR }; int32 ttp_stopioe = 0; int32 tty_buf = 0; /* tty buffer */ @@ -149,9 +157,11 @@ int32 tty_mode = 0; /* tty mode */ int32 tty_shin = 0377; /* tty shift in */ int32 tty_lf = 0; /* lf flag */ -FLIP_FLOP clk_control = CLEAR; -FLIP_FLOP clk_flag = CLEAR; -FLIP_FLOP clk_flagbuf = CLEAR; +struct { + FLIP_FLOP control; /* control flip-flop */ + FLIP_FLOP flag; /* flag flip-flop */ + FLIP_FLOP flagbuf; /* flag buffer flip-flop */ + } clk = { CLEAR, CLEAR, CLEAR }; int32 clk_select = 0; /* clock time select */ int32 clk_error = 0; /* clock error */ @@ -169,17 +179,17 @@ uint32 clk_tick = 0; /* instructions per tick DEVICE ptr_dev, ptp_dev, tty_dev, clk_dev; -uint32 ptrio (uint32 select_code, IOSIG signal, uint32 data); +IOHANDLER ptrio; t_stat ptr_svc (UNIT *uptr); t_stat ptr_attach (UNIT *uptr, char *cptr); t_stat ptr_reset (DEVICE *dptr); t_stat ptr_boot (int32 unitno, DEVICE *dptr); -uint32 ptpio (uint32 select_code, IOSIG signal, uint32 data); +IOHANDLER ptpio; t_stat ptp_svc (UNIT *uptr); t_stat ptp_reset (DEVICE *dptr); -uint32 ttyio (uint32 select_code, IOSIG signal, uint32 data); +IOHANDLER ttyio; t_stat tti_svc (UNIT *uptr); t_stat tto_svc (UNIT *uptr); t_stat tty_reset (DEVICE *dptr); @@ -188,7 +198,7 @@ t_stat tty_set_alf (UNIT *uptr, int32 val, char *cptr, void *desc); t_stat tto_out (int32 c); t_stat ttp_out (int32 c); -uint32 clkio (uint32 select_code, IOSIG signal, uint32 data); +IOHANDLER clkio; t_stat clk_svc (UNIT *uptr); t_stat clk_reset (DEVICE *dptr); int32 clk_delay (int32 flg); @@ -201,7 +211,7 @@ int32 clk_delay (int32 flg); ptr_reg PTR register list */ -DIB ptr_dib = { PTR, &ptrio }; +DIB ptr_dib = { &ptrio, PTR }; UNIT ptr_unit = { UDATA (&ptr_svc, UNIT_SEQ+UNIT_ATTABLE+UNIT_ROABLE, 0), @@ -210,15 +220,15 @@ UNIT ptr_unit = { REG ptr_reg[] = { { ORDATA (BUF, ptr_unit.buf, 8) }, - { FLDATA (CTL, ptr_control, 0) }, - { FLDATA (FLG, ptr_flag, 0) }, - { FLDATA (FBF, ptr_flagbuf, 0) }, + { FLDATA (CTL, ptr.control, 0) }, + { FLDATA (FLG, ptr.flag, 0) }, + { FLDATA (FBF, ptr.flagbuf, 0) }, { DRDATA (TRLCTR, ptr_trlcnt, 8), REG_HRO }, { DRDATA (TRLLIM, ptr_trllim, 8), PV_LEFT }, { DRDATA (POS, ptr_unit.pos, T_ADDR_W), PV_LEFT }, { DRDATA (TIME, ptr_unit.wait, 24), PV_LEFT }, { FLDATA (STOP_IOE, ptr_stopioe, 0) }, - { ORDATA (DEVNO, ptr_dib.devno, 6), REG_HRO }, + { ORDATA (DEVNO, ptr_dib.select_code, 6), REG_HRO }, { NULL } }; @@ -246,7 +256,7 @@ DEVICE ptr_dev = { ptp_reg PTP register list */ -DIB ptp_dib = { PTP, &ptpio }; +DIB ptp_dib = { &ptpio, PTP }; UNIT ptp_unit = { UDATA (&ptp_svc, UNIT_SEQ+UNIT_ATTABLE, 0), SERIAL_OUT_WAIT @@ -254,13 +264,13 @@ UNIT ptp_unit = { REG ptp_reg[] = { { ORDATA (BUF, ptp_unit.buf, 8) }, - { FLDATA (CTL, ptp_control, 0) }, - { FLDATA (FLG, ptp_flag, 0) }, - { FLDATA (FBF, ptp_flagbuf, 0) }, + { FLDATA (CTL, ptp.control, 0) }, + { FLDATA (FLG, ptp.flag, 0) }, + { FLDATA (FBF, ptp.flagbuf, 0) }, { DRDATA (POS, ptp_unit.pos, T_ADDR_W), PV_LEFT }, { DRDATA (TIME, ptp_unit.wait, 24), PV_LEFT }, { FLDATA (STOP_IOE, ptp_stopioe, 0) }, - { ORDATA (DEVNO, ptp_dib.devno, 6), REG_HRO }, + { ORDATA (DEVNO, ptp_dib.select_code, 6), REG_HRO }, { NULL } }; @@ -290,7 +300,7 @@ DEVICE ptp_dev = { #define TTO 1 #define TTP 2 -DIB tty_dib = { TTY, &ttyio }; +DIB tty_dib = { &ttyio, TTY }; UNIT tty_unit[] = { { UDATA (&tti_svc, UNIT_IDLE | TT_MODE_UC, 0), POLL_WAIT }, @@ -302,9 +312,9 @@ REG tty_reg[] = { { ORDATA (BUF, tty_buf, 8) }, { ORDATA (MODE, tty_mode, 16) }, { ORDATA (SHIN, tty_shin, 8), REG_HRO }, - { FLDATA (CTL, tty_control, 0) }, - { FLDATA (FLG, tty_flag, 0) }, - { FLDATA (FBF, tty_flagbuf, 0) }, + { FLDATA (CTL, tty.control, 0) }, + { FLDATA (FLG, tty.flag, 0) }, + { FLDATA (FBF, tty.flagbuf, 0) }, { FLDATA (KLFP, tty_lf, 0), REG_HRO }, { DRDATA (KPOS, tty_unit[TTI].pos, T_ADDR_W), PV_LEFT }, { DRDATA (KTIME, tty_unit[TTI].wait, 24), REG_NZ + PV_LEFT }, @@ -312,7 +322,7 @@ REG tty_reg[] = { { DRDATA (TTIME, tty_unit[TTO].wait, 24), REG_NZ + PV_LEFT }, { DRDATA (PPOS, tty_unit[TTP].pos, T_ADDR_W), PV_LEFT }, { FLDATA (STOP_IOE, ttp_stopioe, 0) }, - { ORDATA (DEVNO, tty_dib.devno, 6), REG_HRO }, + { ORDATA (DEVNO, tty_dib.select_code, 6), REG_HRO }, { NULL } }; @@ -344,20 +354,20 @@ DEVICE tty_dev = { clk_reg CLK register list */ -DIB clk_dib = { CLK, &clkio }; +DIB clk_dib = { &clkio, CLK }; UNIT clk_unit = { UDATA (&clk_svc, UNIT_IDLE, 0) }; REG clk_reg[] = { { ORDATA (SEL, clk_select, 3) }, { DRDATA (CTR, clk_ctr, 14) }, - { FLDATA (CTL, clk_control, 0) }, - { FLDATA (FLG, clk_flag, 0) }, - { FLDATA (FBF, clk_flagbuf, 0) }, + { FLDATA (CTL, clk.control, 0) }, + { FLDATA (FLG, clk.flag, 0) }, + { FLDATA (FBF, clk.flagbuf, 0) }, { FLDATA (ERR, clk_error, CLK_V_ERROR) }, { BRDATA (TIME, clk_time, 10, 24, 8) }, { DRDATA (IPTICK, clk_tick, 24), PV_RSPC | REG_RO }, - { ORDATA (DEVNO, clk_dib.devno, 6), REG_HRO }, + { ORDATA (DEVNO, clk_dib.select_code, 6), REG_HRO }, { NULL } }; @@ -392,78 +402,79 @@ DEVICE clk_dev = { simulation, we omit the buffer clear. */ -uint32 ptrio (uint32 select_code, IOSIG signal, uint32 data) +uint32 ptrio (DIB *dibptr, IOCYCLE signal_set, uint32 stat_data) { -const IOSIG base_signal = IOBASE (signal); /* derive base signal */ +IOSIGNAL signal; +IOCYCLE working_set = IOADDSIR (signal_set); /* add ioSIR if needed */ -switch (base_signal) { /* dispatch base I/O signal */ +while (working_set) { + signal = IONEXT (working_set); /* isolate next signal */ - case ioCLF: /* clear flag flip-flop */ - ptr_flag = ptr_flagbuf = CLEAR; - break; + switch (signal) { /* dispatch I/O signal */ + + case ioCLF: /* clear flag flip-flop */ + ptr.flag = ptr.flagbuf = CLEAR; + break; - case ioSTF: /* set flag flip-flop */ - case ioENF: /* enable flag */ - ptr_flag = ptr_flagbuf = SET; - break; + case ioSTF: /* set flag flip-flop */ + case ioENF: /* enable flag */ + ptr.flag = ptr.flagbuf = SET; + break; - case ioSFC: /* skip if flag is clear */ - setstdSKF (ptr); - break; + case ioSFC: /* skip if flag is clear */ + setstdSKF (ptr); + break; - case ioSFS: /* skip if flag is set */ - setstdSKF (ptr); - break; + case ioSFS: /* skip if flag is set */ + setstdSKF (ptr); + break; - case ioIOI: /* I/O data input */ - data = ptr_unit.buf; - break; + case ioIOI: /* I/O data input */ + stat_data = IORETURN (SCPE_OK, ptr_unit.buf); /* merge in return status */ + break; - case ioPOPIO: /* power-on preset to I/O */ - ptr_flag = ptr_flagbuf = SET; /* set flag and flag buffer */ - /* fall into CRS handler */ - - case ioCRS: /* control reset */ - /* fall into CLC handler */ - - case ioCLC: /* clear control flip-flop */ - ptr_control = CLEAR; - break; + case ioPOPIO: /* power-on preset to I/O */ + ptr.flag = ptr.flagbuf = SET; /* set flag and flag buffer */ + break; - case ioSTC: /* set control flip-flop */ - ptr_control = SET; - sim_activate (&ptr_unit, ptr_unit.wait); - break; + case ioCRS: /* control reset */ + case ioCLC: /* clear control flip-flop */ + ptr.control = CLEAR; + break; - case ioSIR: /* set interrupt request */ - setstdPRL (select_code, ptr); /* set standard PRL signal */ - setstdIRQ (select_code, ptr); /* set standard IRQ signal */ - setstdSRQ (select_code, ptr); /* set standard SRQ signal */ - break; + case ioSTC: /* set control flip-flop */ + ptr.control = SET; + sim_activate (&ptr_unit, ptr_unit.wait); + break; - case ioIAK: /* interrupt acknowledge */ - ptr_flagbuf = CLEAR; - break; + case ioSIR: /* set interrupt request */ + setstdPRL (ptr); /* set standard PRL signal */ + setstdIRQ (ptr); /* set standard IRQ signal */ + setstdSRQ (ptr); /* set standard SRQ signal */ + break; - default: /* all other signals */ - break; /* are ignored */ + case ioIAK: /* interrupt acknowledge */ + ptr.flagbuf = CLEAR; + break; + + + default: /* all other signals */ + break; /* are ignored */ + } + + working_set = working_set & ~signal; /* remove current signal from set */ } -if (signal > ioCLF) /* multiple signals? */ - ptrio (select_code, ioCLF, 0); /* issue CLF */ -else if (signal > ioSIR) /* signal affected interrupt status? */ - ptrio (select_code, ioSIR, 0); /* set interrupt request */ - -return data; +return stat_data; } @@ -474,7 +485,7 @@ t_stat ptr_svc (UNIT *uptr) int32 temp; if ((ptr_unit.flags & UNIT_ATT) == 0) /* attached? */ - return IORETURN (ptr_stopioe, SCPE_UNATT); + return IOERROR (ptr_stopioe, SCPE_UNATT); while ((temp = getc (ptr_unit.fileref)) == EOF) { /* read byte, error? */ if (feof (ptr_unit.fileref)) { /* end of file? */ if ((ptr_unit.flags & UNIT_DIAG) && (ptr_unit.pos > 0)) { @@ -501,7 +512,7 @@ while ((temp = getc (ptr_unit.fileref)) == EOF) { /* read byte, error? */ } } -ptrio (ptr_dib.devno, ioENF, 0); /* set flag */ +ptrio (&ptr_dib, ioENF, 0); /* set flag */ ptr_unit.buf = temp & 0377; /* put byte in buf */ ptr_unit.pos = ftell (ptr_unit.fileref); @@ -526,7 +537,7 @@ return attach_unit (uptr, cptr); t_stat ptr_reset (DEVICE *dptr) { -ptrio (ptr_dib.devno, ioPOPIO, 0); /* send POPIO signal */ +IOPRESET (&ptr_dib); /* PRESET device (does not use PON) */ sim_cancel (&ptr_unit); /* deactivate unit */ return SCPE_OK; } @@ -591,7 +602,7 @@ t_stat ptr_boot (int32 unitno, DEVICE *dptr) { int32 dev; -dev = ptr_dib.devno; /* get device no */ +dev = ptr_dib.select_code; /* get device no */ if (ibl_copy (ptr_rom, dev)) return SCPE_IERR; /* copy boot to memory */ SR = (SR & IBL_OPT) | IBL_PTR | (dev << IBL_V_DEV); /* set SR */ return SCPE_OK; @@ -608,87 +619,88 @@ return SCPE_OK; state is implied by the activation of the PTP unit. */ -uint32 ptpio (uint32 select_code, IOSIG signal, uint32 data) +uint32 ptpio (DIB *dibptr, IOCYCLE signal_set, uint32 stat_data) { -const IOSIG base_signal = IOBASE (signal); /* derive base signal */ +IOSIGNAL signal; +IOCYCLE working_set = IOADDSIR (signal_set); /* add ioSIR if needed */ -switch (base_signal) { /* dispatch base I/O signal */ +while (working_set) { + signal = IONEXT (working_set); /* isolate next signal */ - case ioCLF: /* clear flag flip-flop */ - ptp_flag = ptp_flagbuf = CLEAR; - break; + switch (signal) { /* dispatch I/O signal */ + + case ioCLF: /* clear flag flip-flop */ + ptp.flag = ptp.flagbuf = CLEAR; + break; - case ioSTF: /* set flag flip-flop */ - case ioENF: /* enable flag */ - ptp_flag = ptp_flagbuf = SET; - break; + case ioSTF: /* set flag flip-flop */ + case ioENF: /* enable flag */ + ptp.flag = ptp.flagbuf = SET; + break; - case ioSFC: /* skip if flag is clear */ - setstdSKF (ptp); - break; + case ioSFC: /* skip if flag is clear */ + setstdSKF (ptp); + break; - case ioSFS: /* skip if flag is set */ - setstdSKF (ptp); - break; + case ioSFS: /* skip if flag is set */ + setstdSKF (ptp); + break; - case ioIOI: /* I/O data input */ - if ((ptp_unit.flags & UNIT_ATT) == 0) /* not attached? */ - data = PTP_LOW; /* report as out of tape */ - else - data = 0; - break; + case ioIOI: /* I/O data input */ + if ((ptp_unit.flags & UNIT_ATT) == 0) /* not attached? */ + stat_data = IORETURN (SCPE_OK, PTP_LOW); /* report as out of tape */ + else + stat_data = IORETURN (SCPE_OK, 0); + break; - case ioIOO: /* I/O data output */ - ptp_unit.buf = data; - break; + case ioIOO: /* I/O data output */ + ptp_unit.buf = IODATA (stat_data); /* clear supplied status */ + break; - case ioPOPIO: /* power-on preset to I/O */ - ptp_flag = ptp_flagbuf = SET; /* set flag and flag buffer */ - ptp_unit.buf = 0; /* clear output buffer */ - /* fall into CRS handler */ - - case ioCRS: /* control reset */ - /* fall into CLC handler */ - - case ioCLC: /* clear control flip-flop */ - ptp_control = CLEAR; - break; + case ioPOPIO: /* power-on preset to I/O */ + ptp.flag = ptp.flagbuf = SET; /* set flag and flag buffer */ + ptp_unit.buf = 0; /* clear output buffer */ + break; - case ioSTC: /* set control flip-flop */ - ptp_control = SET; - sim_activate (&ptp_unit, ptp_unit.wait); - break; + case ioCRS: /* control reset */ + case ioCLC: /* clear control flip-flop */ + ptp.control = CLEAR; + break; - case ioSIR: /* set interrupt request */ - setstdPRL (select_code, ptp); /* set standard PRL signal */ - setstdIRQ (select_code, ptp); /* set standard IRQ signal */ - setstdSRQ (select_code, ptp); /* set standard SRQ signal */ - break; + case ioSTC: /* set control flip-flop */ + ptp.control = SET; + sim_activate (&ptp_unit, ptp_unit.wait); + break; - case ioIAK: /* interrupt acknowledge */ - ptp_flagbuf = CLEAR; - break; + case ioSIR: /* set interrupt request */ + setstdPRL (ptp); /* set standard PRL signal */ + setstdIRQ (ptp); /* set standard IRQ signal */ + setstdSRQ (ptp); /* set standard SRQ signal */ + break; - default: /* all other signals */ - break; /* are ignored */ + case ioIAK: /* interrupt acknowledge */ + ptp.flagbuf = CLEAR; + break; + + + default: /* all other signals */ + break; /* are ignored */ + } + + working_set = working_set & ~signal; /* remove current signal from set */ } -if (signal > ioCLF) /* multiple signals? */ - ptpio (select_code, ioCLF, 0); /* issue CLF */ -else if (signal > ioSIR) /* signal affected interrupt status? */ - ptpio (select_code, ioSIR, 0); /* set interrupt request */ - -return data; +return stat_data; } @@ -696,10 +708,10 @@ return data; t_stat ptp_svc (UNIT *uptr) { -ptpio (ptp_dib.devno, ioENF, 0); /* set flag */ +ptpio (&ptp_dib, ioENF, 0); /* set flag */ if ((ptp_unit.flags & UNIT_ATT) == 0) /* attached? */ - return IORETURN (ptp_stopioe, SCPE_UNATT); + return IOERROR (ptp_stopioe, SCPE_UNATT); if (putc (ptp_unit.buf, ptp_unit.fileref) == EOF) { /* output byte */ perror ("PTP I/O error"); clearerr (ptp_unit.fileref); @@ -714,7 +726,7 @@ return SCPE_OK; t_stat ptp_reset (DEVICE *dptr) { -ptpio (ptp_dib.devno, ioPOPIO, 0); /* send POPIO signal */ +IOPRESET (&ptp_dib); /* PRESET device (does not use PON) */ sim_cancel (&ptp_unit); /* deactivate unit */ return SCPE_OK; } @@ -722,97 +734,100 @@ return SCPE_OK; /* Terminal I/O signal handler */ -uint32 ttyio (uint32 select_code, IOSIG signal, uint32 data) +uint32 ttyio (DIB *dibptr, IOCYCLE signal_set, uint32 stat_data) { -const IOSIG base_signal = IOBASE (signal); /* derive base signal */ +uint16 data; +IOSIGNAL signal; +IOCYCLE working_set = IOADDSIR (signal_set); /* add ioSIR if needed */ -switch (base_signal) { /* dispatch base I/O signal */ +while (working_set) { + signal = IONEXT (working_set); /* isolate next signal */ - case ioCLF: /* clear flag flip-flop */ - tty_flag = tty_flagbuf = CLEAR; - break; + switch (signal) { /* dispatch I/O signal */ + + case ioCLF: /* clear flag flip-flop */ + tty.flag = tty.flagbuf = CLEAR; + break; - case ioSTF: /* set flag flip-flop */ - case ioENF: /* enable flag */ - tty_flag = tty_flagbuf = SET; - break; + case ioSTF: /* set flag flip-flop */ + case ioENF: /* enable flag */ + tty.flag = tty.flagbuf = SET; + break; - case ioSFC: /* skip if flag is clear */ - setstdSKF (tty); - break; + case ioSFC: /* skip if flag is clear */ + setstdSKF (tty); + break; - case ioSFS: /* skip if flag is set */ - setstdSKF (tty); - break; + case ioSFS: /* skip if flag is set */ + setstdSKF (tty); + break; - case ioIOI: /* I/O data input */ - data = tty_buf; + case ioIOI: /* I/O data input */ + data = tty_buf; - if (!(tty_mode & TM_KBD) && sim_is_active (&tty_unit[TTO])) - data = data | TP_BUSY; - break; + if (!(tty_mode & TM_KBD) && sim_is_active (&tty_unit[TTO])) + data = data | TP_BUSY; + + stat_data = IORETURN (SCPE_OK, data); /* merge in return status */ + break; - case ioIOO: /* I/O data output */ - if (data & TM_MODE) - tty_mode = data & (TM_KBD|TM_PRI|TM_PUN); + case ioIOO: /* I/O data output */ + data = IODATA (stat_data); /* clear supplied status */ - tty_buf = data & 0377; - break; + if (data & TM_MODE) + tty_mode = data & (TM_KBD|TM_PRI|TM_PUN); + + tty_buf = data & 0377; + break; - case ioPOPIO: /* power-on preset to I/O */ - /* fall into CRS handler */ - - case ioCRS: /* control reset */ - tty_control = CLEAR; /* clear control */ - tty_flag = tty_flagbuf = SET; /* set flag and flag buffer */ - tty_mode = TM_KBD; /* set tty, clear print/punch */ - tty_shin = 0377; /* input inactive */ - tty_lf = 0; /* no lf pending */ - break; + case ioCRS: /* control reset */ + tty.control = CLEAR; /* clear control */ + tty.flag = tty.flagbuf = SET; /* set flag and flag buffer */ + tty_mode = TM_KBD; /* set tty, clear print/punch */ + tty_shin = 0377; /* input inactive */ + tty_lf = 0; /* no lf pending */ + break; - case ioCLC: /* clear control flip-flop */ - tty_control = CLEAR; - break; + case ioCLC: /* clear control flip-flop */ + tty.control = CLEAR; + break; - case ioSTC: /* set control flip-flop */ - tty_control = SET; + case ioSTC: /* set control flip-flop */ + tty.control = SET; - if (!(tty_mode & TM_KBD)) /* output? */ - sim_activate (&tty_unit[TTO], tty_unit[TTO].wait); - break; + if (!(tty_mode & TM_KBD)) /* output? */ + sim_activate (&tty_unit[TTO], tty_unit[TTO].wait); + break; - case ioSIR: /* set interrupt request */ - setstdPRL (select_code, tty); /* set standard PRL signal */ - setstdIRQ (select_code, tty); /* set standard IRQ signal */ - setstdSRQ (select_code, tty); /* set standard SRQ signal */ - break; + case ioSIR: /* set interrupt request */ + setstdPRL (tty); /* set standard PRL signal */ + setstdIRQ (tty); /* set standard IRQ signal */ + setstdSRQ (tty); /* set standard SRQ signal */ + break; - case ioIAK: /* interrupt acknowledge */ - tty_flagbuf = CLEAR; - break; + case ioIAK: /* interrupt acknowledge */ + tty.flagbuf = CLEAR; + break; - default: /* all other signals */ - break; /* are ignored */ + default: /* all other signals */ + break; /* are ignored */ + } + + working_set = working_set & ~signal; /* remove current signal from set */ } - -if (signal > ioCLF) /* multiple signals? */ - ttyio (select_code, ioCLF, 0); /* issue CLF */ -else if (signal > ioSIR) /* signal affected interrupt status? */ - ttyio (select_code, ioSIR, 0); /* set interrupt request */ - -return data; +return stat_data; } @@ -880,7 +895,7 @@ if (tty_mode & TM_KBD) { /* keyboard enabled? */ tty_buf = c; /* put char in buf */ uptr->pos = uptr->pos + 1; - ttyio (tty_dib.devno, ioENF, 0); /* set flag */ + ttyio (&tty_dib, ioENF, 0); /* set flag */ if (c) { tto_out (c); /* echo? */ @@ -907,7 +922,7 @@ if ((r = tto_out (c)) != SCPE_OK) { /* output; error? */ return ((r == SCPE_STALL)? SCPE_OK: r); /* !stall? report */ } -ttyio (tty_dib.devno, ioENF, 0); /* set flag */ +ttyio (&tty_dib, ioENF, 0); /* set flag */ return ttp_out (c); /* punch if enabled */ } @@ -932,7 +947,7 @@ t_stat ttp_out (int32 c) { if (tty_mode & TM_PUN) { /* punching? */ if ((tty_unit[TTP].flags & UNIT_ATT) == 0) /* attached? */ - return IORETURN (ttp_stopioe, SCPE_UNATT); + return IOERROR (ttp_stopioe, SCPE_UNATT); if (putc (c, tty_unit[TTP].fileref) == EOF) { /* output char */ perror ("TTP I/O error"); clearerr (tty_unit[TTP].fileref); @@ -948,10 +963,10 @@ return SCPE_OK; t_stat tty_reset (DEVICE *dptr) { -if (sim_switches & SWMASK ('P')) /* PON reset? */ +if (sim_switches & SWMASK ('P')) /* initialization reset? */ tty_buf = 0; /* clear buffer */ -ttyio (tty_dib.devno, ioPOPIO, 0); /* send POPIO signal */ +IOPRESET (&tty_dib); /* PRESET device (does not use PON) */ tty_unit[TTI].wait = POLL_WAIT; /* reset initial poll */ sim_rtcn_init (tty_unit[TTI].wait, TMR_POLL); /* init poll timer */ @@ -1024,105 +1039,105 @@ int32 poll_time; expected. */ -uint32 clkio (uint32 select_code, IOSIG signal, uint32 data) +uint32 clkio (DIB *dibptr, IOCYCLE signal_set, uint32 stat_data) { -const IOSIG base_signal = IOBASE (signal); /* derive base signal */ +IOSIGNAL signal; +IOCYCLE working_set = IOADDSIR (signal_set); /* add ioSIR if needed */ -switch (base_signal) { /* dispatch base I/O signal */ +while (working_set) { + signal = IONEXT (working_set); /* isolate next signal */ - case ioCLF: /* clear flag flip-flop */ - clk_flag = clk_flagbuf = CLEAR; - break; + switch (signal) { /* dispatch I/O signal */ + + case ioCLF: /* clear flag flip-flop */ + clk.flag = clk.flagbuf = CLEAR; + break; - case ioSTF: /* set flag flip-flop */ - case ioENF: /* enable flag */ - clk_flag = clk_flagbuf = SET; - break; + case ioSTF: /* set flag flip-flop */ + case ioENF: /* enable flag */ + clk.flag = clk.flagbuf = SET; + break; - case ioSFC: /* skip if flag is clear */ - setstdSKF (clk); - break; + case ioSFC: /* skip if flag is clear */ + setstdSKF (clk); + break; - case ioSFS: /* skip if flag is set */ - setstdSKF (clk); - break; + case ioSFS: /* skip if flag is set */ + setstdSKF (clk); + break; - case ioIOI: /* I/O data input */ - data = clk_error; - break; + case ioIOI: /* I/O data input */ + stat_data = IORETURN (SCPE_OK, clk_error); /* merge in return status */ + break; - case ioIOO: /* I/O data output */ - clk_select = data & 07; /* save select */ - sim_cancel (&clk_unit); /* stop the clock */ - clk_control = CLEAR; /* clear control */ - clkio (select_code, ioSIR, 0); /* set interrupt request (IOO normally doesn't) */ - break; + case ioIOO: /* I/O data output */ + clk_select = IODATA (stat_data) & 07; /* save select */ + sim_cancel (&clk_unit); /* stop the clock */ + clk.control = CLEAR; /* clear control */ + working_set = working_set | ioSIR; /* set interrupt request (IOO normally doesn't) */ + break; - case ioPOPIO: /* power-on preset to I/O */ - clk_flag = clk_flagbuf = SET; /* set flag and flag buffer */ - /* fall into CRS handler */ - - case ioCRS: /* control reset */ - /* fall into CLC handler */ - - case ioCLC: /* clear control flip-flop */ - clk_control = CLEAR; - sim_cancel (&clk_unit); /* deactivate unit */ - break; + case ioPOPIO: /* power-on preset to I/O */ + clk.flag = clk.flagbuf = SET; /* set flag and flag buffer */ + break; - case ioSTC: /* set control flip-flop */ - clk_control = SET; - if (clk_unit.flags & UNIT_DIAG) /* diag mode? */ - clk_unit.flags = clk_unit.flags & ~UNIT_IDLE; /* not calibrated */ - else - clk_unit.flags = clk_unit.flags | UNIT_IDLE; /* is calibrated */ - - if (!sim_is_active (&clk_unit)) { /* clock running? */ - clk_tick = clk_delay (0); /* get tick count */ - - if ((clk_unit.flags & UNIT_DIAG) == 0) /* calibrated? */ - if (clk_select == 2) /* 10 msec. interval? */ - clk_tick = sync_poll (INITIAL); /* sync poll */ - else - sim_rtcn_init (clk_tick, TMR_CLK); /* initialize timer */ - - sim_activate (&clk_unit, clk_tick); /* start clock */ - clk_ctr = clk_delay (1); /* set repeat ctr */ - } - clk_error = 0; /* clear error */ - break; + case ioCRS: /* control reset */ + case ioCLC: /* clear control flip-flop */ + clk.control = CLEAR; + sim_cancel (&clk_unit); /* deactivate unit */ + break; - case ioSIR: /* set interrupt request */ - setstdPRL (select_code, clk); /* set standard PRL signal */ - setstdIRQ (select_code, clk); /* set standard IRQ signal */ - setstdSRQ (select_code, clk); /* set standard SRQ signal */ - break; + case ioSTC: /* set control flip-flop */ + clk.control = SET; + if (clk_unit.flags & UNIT_DIAG) /* diag mode? */ + clk_unit.flags = clk_unit.flags & ~UNIT_IDLE; /* not calibrated */ + else + clk_unit.flags = clk_unit.flags | UNIT_IDLE; /* is calibrated */ + + if (!sim_is_active (&clk_unit)) { /* clock running? */ + clk_tick = clk_delay (0); /* get tick count */ + + if ((clk_unit.flags & UNIT_DIAG) == 0) /* calibrated? */ + if (clk_select == 2) /* 10 msec. interval? */ + clk_tick = sync_poll (INITIAL); /* sync poll */ + else + sim_rtcn_init (clk_tick, TMR_CLK); /* initialize timer */ + + sim_activate (&clk_unit, clk_tick); /* start clock */ + clk_ctr = clk_delay (1); /* set repeat ctr */ + } + clk_error = 0; /* clear error */ + break; - case ioIAK: /* interrupt acknowledge */ - clk_flagbuf = CLEAR; - break; + case ioSIR: /* set interrupt request */ + setstdPRL (clk); /* set standard PRL signal */ + setstdIRQ (clk); /* set standard IRQ signal */ + setstdSRQ (clk); /* set standard SRQ signal */ + break; - default: /* all other signals */ - break; /* are ignored */ + case ioIAK: /* interrupt acknowledge */ + clk.flagbuf = CLEAR; + break; + + + default: /* all other signals */ + break; /* are ignored */ + } + + working_set = working_set & ~signal; /* remove current signal from set */ } - -if (signal > ioCLF) /* multiple signals? */ - clkio (select_code, ioCLF, 0); /* issue CLF */ -else if (signal > ioSIR) /* signal affected interrupt status? */ - clkio (select_code, ioSIR, 0); /* set interrupt request */ - -return data; +return stat_data; } @@ -1134,7 +1149,7 @@ return data; t_stat clk_svc (UNIT *uptr) { -if (!clk_control) /* control clear? */ +if (!clk.control) /* control clear? */ return SCPE_OK; /* done */ if (clk_unit.flags & UNIT_DIAG) /* diag mode? */ @@ -1147,10 +1162,10 @@ else sim_activate (uptr, clk_tick); /* reactivate */ clk_ctr = clk_ctr - 1; /* decrement counter */ if (clk_ctr <= 0) { /* end of interval? */ - if (clk_flag) + if (clk.flag) clk_error = CLK_ERROR; /* overrun? error */ else - clkio (clk_dib.devno, ioENF, 0); /* set flag */ + clkio (&clk_dib, ioENF, 0); /* set flag */ clk_ctr = clk_delay (1); /* reset counter */ } return SCPE_OK; @@ -1161,13 +1176,13 @@ return SCPE_OK; t_stat clk_reset (DEVICE *dptr) { -if (sim_switches & SWMASK ('P')) { /* PON reset? */ +if (sim_switches & SWMASK ('P')) { /* initialization reset? */ clk_error = 0; /* clear error */ clk_select = 0; /* clear select */ clk_ctr = 0; /* clear counter */ } -clkio (clk_dib.devno, ioPOPIO, 0); /* send POPIO signal */ +IOPRESET (&clk_dib); /* PRESET device (does not use PON) */ return SCPE_OK; } diff --git a/HP2100/hp2100_sys.c b/HP2100/hp2100_sys.c index 98e0e76d..044c2825 100644 --- a/HP2100/hp2100_sys.c +++ b/HP2100/hp2100_sys.c @@ -1,6 +1,6 @@ /* hp2100_sys.c: HP 2100 simulator interface - Copyright (c) 1993-2008, Robert M. Supnik + 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"), @@ -23,6 +23,8 @@ used in advertising or otherwise to promote the sale, use or other dealings in this Software without prior written authorization from Robert M Supnik. + 29-Oct-10 JDB DMA channels renamed from 0,1 to 1,2 to match documentation + 26-Oct-10 JDB Changed DIB access for revised signal model 03-Sep-08 JDB Fixed IAK instruction dual-use mnemonic display 07-Aug-08 JDB Moved hp_setdev, hp_showdev from hp2100_cpu.c Changed sim_load to use WritePW instead of direct M[] access @@ -60,7 +62,7 @@ extern UNIT cpu_unit; extern REG cpu_reg[]; extern DEVICE mp_dev; -extern DEVICE dma0_dev, dma1_dev; +extern DEVICE dma1_dev, dma2_dev; extern DEVICE ptr_dev, ptp_dev; extern DEVICE tty_dev, clk_dev; extern DEVICE lps_dev; @@ -98,8 +100,7 @@ int32 sim_emax = 3; DEVICE *sim_devices[] = { &cpu_dev, &mp_dev, - &dma0_dev, - &dma1_dev, + &dma1_dev, &dma2_dev, &ptr_dev, &ptp_dev, &tty_dev, @@ -772,18 +773,18 @@ else { /* printable character * t_stat hp_setdev (UNIT *uptr, int32 num, char *cptr, void *desc) { DEVICE *dptr = (DEVICE *) desc; -DIB *dibp; +DIB *dibptr; int32 i, newdev; t_stat r; if (cptr == NULL) return SCPE_ARG; if ((desc == NULL) || (num > 1)) return SCPE_IERR; -dibp = (DIB *) dptr->ctxt; -if (dibp == NULL) return SCPE_IERR; +dibptr = (DIB *) dptr->ctxt; +if (dibptr == NULL) return SCPE_IERR; newdev = get_uint (cptr, 8, I_DEVMASK - num, &r); if (r != SCPE_OK) return r; if (newdev < VARDEV) return SCPE_ARG; -for (i = 0; i <= num; i++, dibp++) dibp->devno = newdev + i; +for (i = 0; i <= num; i++, dibptr++) dibptr->select_code = newdev + i; return SCPE_OK; } @@ -793,13 +794,13 @@ return SCPE_OK; t_stat hp_showdev (FILE *st, UNIT *uptr, int32 num, void *desc) { DEVICE *dptr = (DEVICE *) desc; -DIB *dibp; +DIB *dibptr; int32 i; if ((desc == NULL) || (num > 1)) return SCPE_IERR; -dibp = (DIB *) dptr->ctxt; -if (dibp == NULL) return SCPE_IERR; -fprintf (st, "devno=%o", dibp->devno); -for (i = 1; i <= num; i++) fprintf (st, "/%o", dibp->devno + i); +dibptr = (DIB *) dptr->ctxt; +if (dibptr == NULL) return SCPE_IERR; +fprintf (st, "devno=%o", dibptr->select_code); +for (i = 1; i <= num; i++) fprintf (st, "/%o", dibptr->select_code + i); return SCPE_OK; } diff --git a/I1401/i1401_cpu.c b/I1401/i1401_cpu.c index b07d272f..71d49610 100644 --- a/I1401/i1401_cpu.c +++ b/I1401/i1401_cpu.c @@ -266,6 +266,7 @@ REG cpu_reg[] = { { 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) }, diff --git a/I1401/i1401_iq.c b/I1401/i1401_iq.c index 2d299e4d..e0fa7eb9 100644 --- a/I1401/i1401_iq.c +++ b/I1401/i1401_iq.c @@ -93,8 +93,8 @@ ind[IN_INC] = 0; /* clear inq clear */ switch (mod) { /* case on mod */ case BCD_R: /* input */ -/* if (ind[IN_INR] == 0) /* return if no req */ - return SCPE_OK; +/* if (ind[IN_INR] == 0) +/* return SCPE_OK; /* return if no req */ ind[IN_INR] = 0; /* clear req */ puts_tty ("[Enter]\r\n"); /* prompt */ for (i = 0; M[BS] != (BCD_GRPMRK + WM); i++) { /* until GM + WM */ diff --git a/I7094/i7094_clk.c b/I7094/i7094_clk.c index f516819a..d3020093 100644 --- a/I7094/i7094_clk.c +++ b/I7094/i7094_clk.c @@ -1,6 +1,6 @@ /* i7094_clk.c: IBM 7094 clock - Copyright (c) 2003-2008, Robert M. Supnik + 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"), @@ -25,6 +25,8 @@ clk RPQ F89349 interval timer Chronolog calendar clock + + 25-Mar-11 RMS According to RPQ, clock clears on RESET */ #include "i7094_defs.h" @@ -68,9 +70,9 @@ t_uint64 ctr; if ((clk_dev.flags & DEV_DIS) == 0) { /* clock enabled? */ ctr = ReadP (CLK_CTR); - ctr = (ctr + 1) & DMASK; /* increment */ + ctr = (ctr + 1) & MMASK; /* increment */ WriteP (CLK_CTR, ctr); - if ((ctr & MMASK) == 0) /* overflow? req trap */ + if (ctr == 0) /* overflow? req trap */ chtr_clk = 1; sim_activate (uptr, sim_rtcn_calb (CLK_TPS, TMR_CLK)); /* reactivate unit */ } @@ -126,6 +128,9 @@ 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)); +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_old.c b/I7094/i7094_com_old.c deleted file mode 100644 index 4a665453..00000000 --- a/I7094/i7094_com_old.c +++ /dev/null @@ -1,1179 +0,0 @@ -/* i7094_com.c: IBM 7094 7750 communications interface 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. - - com 7750 controller - coml 7750 lines - - 19-Nov-2008 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. 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 32 /* 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 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 0200000000000 /* line is 12b */ -#define COMO_LINCTL 0100000000000 /* control msg */ -#define COMO_GETLN(x) (((uint32) ((x) >> 24)) & 0777) -#define COMO_CTLRST 0000077770000 /* 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 004000000000000000000 /* prog check */ -#define COMS_DCHK 002000000000000000000 /* data check */ -#define COMS_EXCC 001000000000000000000 /* exc cond */ -#define COMS_MLNT 000040000000000000000 /* message length check */ -#define COMS_CHNH 000020000000000000000 /* channel hold */ -#define COMS_CHNQ 000010000000000000000 /* channel queue full */ -#define COMS_ITMO 000000100000000000000 /* interface timeout */ -#define COMS_DATR 000000004000000000000 /* data message ready */ -#define COMS_INBF 000000002000000000000 /* input buffer free */ -#define COMS_SVCR 000000001000000000000 /* service message ready */ -#define COMS_PALL 000000000000000000000 -#define COMS_DALL 000000000000000000000 -#define COMS_EALL 000000000000000000000 -#define COMS_DYN 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 input queue - outq[ln] output queue for line ln - - The input queue has two entries for each character; the first is the - line number, the second the character. The output queues have only - one entry for each character. - - 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 = 0; /* 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 */ -uint32 com_not_ret[COM_TLINES] = { 0 }; /* chars not returned */ -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 */ -LISTHD com_inpq; /* input queue */ -LISTHD com_outq[COM_TLINES]; /* output queue */ -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_inq (FILE *st, UNIT *uptr, int32 val, void *desc); -t_stat com_show_aoutq (FILE *st, UNIT *uptr, int32 val, void *desc); -t_stat com_show_outq (FILE *st, UNIT *uptr, int32 val, void *desc); -void com_reset_ln (uint32 i); -uint16 com_gethd_free (LISTHD *lh); -uint16 com_gethd (LISTHD *lh); -t_bool com_new_puttl (LISTHD *lh, uint16 val); -void com_puttl (LISTHD *lh, uint16 ent); -t_bool com_inp_msg (uint32 ln, uint16 msg); -void com_skip_outc (uint32 ln); -t_stat com_test_atn (uint32 ch); -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); -t_stat com_send_ccmp (uint32 ln); -t_stat 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 } - }; - -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) }, - { 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 }, - { BRDATA (FREEQ, &com_free, 10, 16, 2) }, - { BRDATA (INPQ, &com_inpq, 10, 16, 2) }, - { 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, "INQ", 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, -1, "ALL", NULL, - NULL, &com_show_ctrl, 0 }, - { MTAB_XTD | MTAB_VUN | MTAB_NMO, 0, "OUTQ", NULL, - NULL, &com_show_outq, 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_NET | 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 -*/ - -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 (&como_svc, 0, 0), COML_WAIT }, - { UDATA (&comto_svc, 0, 0), COML_WAIT }, - }; - -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 }, - { 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_inpq.head) /* 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, ent; -uint16 chr; -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; i < COMI_12BMAX; i++) { /* fill buffer */ - ent = com_gethd_free (&com_inpq); /* get next entry */ - if (ent == 0) /* q empty, done */ - break; - if ((i % 3) == 0) /* next word? */ - j++; - com_buf[j] = (com_buf[j] << 12) | /* pack data */ - ((t_uint64) (com_pkt[ent].data & 07777)); - } - 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? */ - return com_test_atn (com_ch); /* test atn, 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 == 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; - if (dat & 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 com_test_atn (com_ch); /* test atn, 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; -t_stat r; - -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[COM_MLINES].NEEDID) /* ID needed? */ - return com_send_id (COM_MLINES); -if ((c & SCPE_KFLAG) && ((c = c & 0177) != 0)) { /* char input? */ - if (r = com_queue_in (COM_MLINES, c)) - return r; - if (sim_tt_outcvt (c, TT_MODE_7P) >= 0) - sim_putchar (c); - if (c == '\r') - sim_putchar ('\n'); - } -return com_test_atn (com_ch); /* 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; -t_stat r; - -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 */ - } -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 (r = com_queue_in (ln, c)) /* queue char, err? */ - return r; - if (com_ldsc[ln].xmte) { /* output enabled? */ - if (sim_tt_outcvt (c, TT_MODE_7P) >= 0) /* echo char */ - 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 */ - if (!com_inp_msg (ln, COMI_HANGUP)) /* hangup message */ - return STOP_NOIFREE; - } - } /* end for */ -return com_test_atn (com_ch); /* set ATN if input */ -} - -/* Unit service - console transmit */ - -t_stat comto_svc (UNIT *uptr) -{ -uint32 c, c1; - -if (com_outq[COM_MLINES].head == 0) /* no more characters? */ - return com_send_ccmp (COM_MLINES); /* free any remaining */ -c = com_queue_out (COM_MLINES, &c1); /* get character, cvt */ -if (c) /* printable? output */ - sim_putchar (c); -if (c1) /* second char? output */ - sim_putchar (c1); -sim_activate (uptr, uptr->wait); /* next char */ -if (com_not_ret[COM_MLINES] >= COMI_CMAX) /* completion needed? */ - return com_send_ccmp (COM_MLINES); /* generate msg */ -return SCPE_OK; -} - -/* Unit service - transmit side */ - -t_stat como_svc (UNIT *uptr) -{ -uint32 c, c1; -int32 ln = uptr - coml_unit; /* line # */ - -if (com_outq[ln].head == 0) /* no more characters? */ - return com_send_ccmp (ln); /* free any remaining */ -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 */ - sim_activate (uptr, uptr->wait); /* next char */ - if (com_not_ret[ln] >= COMI_CMAX) /* completion needed? */ - return com_send_ccmp (ln); /* generate msg */ - } /* end if conn */ -return SCPE_OK; -} - -/* Send ID sequence on input */ - -t_stat com_send_id (uint32 ln) -{ -com_inp_msg (ln, COMI_DIALUP); /* input message: */ -if (coml_unit[ln].flags & UNIT_K35) /* dialup, ID, endID */ - com_inp_msg (ln, COMI_K35); -else com_inp_msg (ln, COMI_K37); -com_inp_msg (ln, 0); -com_inp_msg (ln, 0); -com_inp_msg (ln, 0); -com_inp_msg (ln, 0); -com_inp_msg (ln, (uint16) (ln + COM_LBASE)); -if (!com_inp_msg (ln, COMI_ENDID)) /* make sure there */ - return STOP_NOIFREE; /* was room for msg */ -coml_unit[ln].NEEDID = 0; -return SCPE_OK; -} - -/* Translate and queue input character */ - -t_stat com_queue_in (uint32 ln, uint32 c) -{ -uint16 out; - -if (c == com_intr) - out = COMI_INTR; -else if (c == com_quit) - out = COMI_QUIT; -else { - 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 */ - } -if (!com_inp_msg (ln, out)) /* input message */ - return STOP_NOIFREE; -return SCPE_OK; -} - -/* Retrieve and translate output character */ - -uint32 com_queue_out (uint32 ln, uint32 *c1) -{ -uint32 c, ent, raw; - -*c1 = 0; /* assume non-printing */ -ent = com_gethd_free (&com_outq[ln]); /* get character */ -if (ent == 0) /* nothing? */ - return 0; -raw = com_pkt[ent].data; /* get 12b character */ -com_not_ret[ln]++; -if (raw == COMO_BITRPT) { /* insert delay? */ - com_skip_outc (ln); - return 0; - } -c = (~raw >> 1) & 0177; /* remove start, parity */ -if (c >= 040) { /* printable? */ - if (c == 0177) /* DEL? ignore */ - return 0; - 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? */ - if (coml_unit[ln].flags & UNIT_K35) /* KSR-35? */ - *c1 = '\n'; /* lf after cr */ - return c; - - case '\n': /* line feed? */ - if (!(coml_unit[ln].flags & UNIT_K35)) { /* KSR-37? */ - *c1 = '\n'; /* lf after cr */ - return '\r'; - } - return c; /* print lf */ - - case 022: /* DC2 */ - if (!(com_unit[ln].flags & UNIT_K35)) { /* KSR-37? */ - com_skip_outc (ln); /* skip next */ - return '\n'; /* print lf */ - } - break; - - case 023: /* DC3 */ - if (!(com_unit[ln].flags & UNIT_K35)) /* KSR-37? */ - com_skip_outc (ln); /* skip next */ - break; - } - -return 0; /* ignore others */ -} - -/* Generate completion message, if needed */ - -t_stat com_send_ccmp (uint32 ln) -{ -uint32 t; - -if (t = com_not_ret[ln]) { /* chars not returned? */ - if (t > COMI_CMAX) /* limit to max */ - t = COMI_CMAX; - com_not_ret[ln] -= t; /* keep count */ - if (!com_inp_msg (ln, COMI_COMP (t))) /* gen completion msg */ - return STOP_NOIFREE; - } -return SCPE_OK; -} - -/* Skip next char in output queue */ - -void com_skip_outc (uint32 ln) -{ -if (com_gethd_free (&com_outq[ln])) /* count it */ - com_not_ret[ln]++; -return; -} - -/* 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; -} - -/* Set attention if input pending */ - -t_stat com_test_atn (uint32 ch) -{ -if (com_inpq.head) - ch9_set_atn (ch); -return SCPE_OK; -} - -/* 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; -} - -/* 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; -} - -/* 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; -} - -/* Insert line and message into input queue */ - -t_bool com_inp_msg (uint32 ln, uint16 msg) -{ -uint16 ent1, ent2; - -if ((ent1 = com_gethd (&com_free)) != 0) { /* pkt avail? */ - if ((ent2 = com_gethd (&com_free)) != 0) { /* 2nd pkt avail? */ - com_pkt[ent1].data = (ln + COM_LBASE) | COMI_VALIDL; /* 1st pkt = line# */ - com_pkt[ent2].data = msg; /* 2nd pkt = char */ - com_puttl (&com_inpq, ent1); /* queue pkts */ - com_puttl (&com_inpq, ent2); - return TRUE; - } - com_puttl (&com_free, ent1); /* free 1st */ - } -return FALSE; /* failed */ -} - -/* 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; -com_inpq.head = 0; /* init queues */ -com_inpq.tail = 0; -for (i = 0; i < COM_TLINES; i++) { - 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_outq[ln])) ; -com_not_ret[ln] = 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 had %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_inq (FILE *st, UNIT *uptr, int32 val, void *desc) -{ -uint32 entc, ln, i, next; - -if (entc = com_show_qsumm (st, &com_inpq, "Input queue")) { - for (i = 0, next = com_inpq.head; next != 0; - i++, next = com_pkt[next].next) { - if ((i % 4) == 0) - fprintf (st, "%d:\t", i); - ln = com_pkt[next].data; - next = com_pkt[next].next; - if (next == 0) { - fprintf (st, "Line number without data\n"); - return SCPE_OK; - } - fprintf (st, "%d/", ln); - com_show_char (st, com_pkt[next].data); - fputc ((((i % 4) == 3)? '\n': '\t'), st); - } - if (i % 4) - fputc ('\n', st); - } -return SCPE_OK; -} - -t_stat com_show_outq (FILE *st, UNIT *uptr, int32 val, void *desc) -{ -uint32 entc, ln, i, next; -char name[20]; - -ln = uptr - com_dev.units; -sprintf (name, "Output queue %d", ln); -if (entc = com_show_qsumm (st, &com_outq[ln], name)) { - for (i = 0, next = com_outq[ln].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 >> 1); - fputc ((((i % 8) == 7)? '\n': '\t'), st); - } - if (i % 8) - fputc ('\n', st); - } -return SCPE_OK; -} - -t_stat com_show_aoutq (FILE *st, UNIT *uptr, int32 val, void *desc) -{ -uint32 i; - -for (i = 0; i < COM_TLINES; i++) - com_show_outq (st, com_dev.units + i, 1, 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, 1, desc); -if (val & COMR_IQ) - com_show_inq (st, uptr, 1, desc); -if (val & COMR_OQ) - com_show_aoutq (st, uptr, 1, desc); -return SCPE_OK; -} diff --git a/I7094/i7094_cpu.c b/I7094/i7094_cpu.c index 2ea5d8fe..3719999b 100644 --- a/I7094/i7094_cpu.c +++ b/I7094/i7094_cpu.c @@ -1,6 +1,6 @@ /* i7094_cpu.c: IBM 7094 CPU simulator - Copyright (c) 2003-2010, Robert M. Supnik + 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"), @@ -25,7 +25,10 @@ cpu 7094 central processor - 16-Jul-10 RMS Fixed PSE, MSE user mode protection (found by Dave Pitts) + 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 (found by Dave Pitts) Fixed issues in storage nullification mode 28-Apr-07 RMS Removed clock initialization 29-Oct-06 RMS Added additional expanded core instructions @@ -57,6 +60,9 @@ 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) @@ -121,8 +127,8 @@ 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, ENAB, RCT, RDS, - or WDS (cleared after one instruction) + 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. @@ -179,6 +185,9 @@ 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 */ @@ -307,6 +316,9 @@ REG cpu_reg[] = { { 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) }, @@ -572,8 +584,8 @@ const uint8 op_flags[1024] = { I_XNR|I_CT, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , - I_XN , 0 , I_XNR|I_9X, I_XN|I_94 , /* -600 */ - 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 */ @@ -685,6 +697,10 @@ while (reason == SCPE_OK) { /* loop until error */ 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? */ @@ -945,9 +961,15 @@ while (reason == SCPE_OK) { /* loop until error */ case 00101: /* (CTSS) TIA */ if (prot_trap (0)) /* not user mode? */ break; - PCQ_ENTRY; - PC = ea; - inst_base = 0; + 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 */ @@ -1267,6 +1289,9 @@ while (reason == SCPE_OK) { /* loop until error */ 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 */ @@ -1380,6 +1405,8 @@ while (reason == SCPE_OK) { /* loop until error */ /* Negative instructions */ case 01021: /* ESNT */ + if (prot_trap (0)) /* user mode? */ + break; mode_storn = 1; /* enter nullification */ PCQ_ENTRY; PC = ea; /* branch, no trap */ @@ -1431,10 +1458,15 @@ while (reason == SCPE_OK) { /* loop until error */ case 01101: /* (CTSS) TIB */ if (prot_trap (0)) /* user mode? */ break; - PCQ_ENTRY; - PC = ea; - mode_user = 1; - inst_base = BCORE_BASE; + 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 */ @@ -1624,12 +1656,21 @@ while (reason == SCPE_OK) { /* loop until error */ 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); @@ -1642,6 +1683,13 @@ while (reason == SCPE_OK) { /* loop until error */ 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); @@ -1833,10 +1881,8 @@ while (reason == SCPE_OK) { /* loop until error */ case 00640: case 00641: case 00642: case 00643: /* SCHx */ case 01640: case 01641: case 01642: case 01643: - if (prot_trap (0)) /* user mode? */ - break; - ch = ((op & 03) << 1) | ((op >> 9) & 01); - if ((reason = ch_op_store (ch, &SR)) == SCPE_OK) + ch = ((op & 03) << 1) | ((op >> 9) & 01); + if ((reason = ch_op_store (ch, &SR)) == SCPE_OK) Write (ea, SR); break; @@ -1848,7 +1894,7 @@ while (reason == SCPE_OK) { /* loop until error */ break; case 00762: /* RDS */ - if (prot_trap (0) || sel_trap (PC)) + 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)); @@ -1856,7 +1902,7 @@ while (reason == SCPE_OK) { /* loop until error */ break; case 00764: /* BSR */ - if (prot_trap (0) || sel_trap (PC)) + 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)); @@ -1864,7 +1910,7 @@ while (reason == SCPE_OK) { /* loop until error */ break; case 00766: /* WRS */ - if (prot_trap (0) || sel_trap (PC)) + 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)); @@ -1872,7 +1918,7 @@ while (reason == SCPE_OK) { /* loop until error */ break; case 00770: /* WEF */ - if (prot_trap (0) || sel_trap (PC)) + 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)); @@ -1880,7 +1926,7 @@ while (reason == SCPE_OK) { /* loop until error */ break; case 00772: /* REW */ - if (prot_trap (0) || sel_trap (PC)) + 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)); @@ -1888,7 +1934,7 @@ while (reason == SCPE_OK) { /* loop until error */ break; case 01764: /* BSF */ - if (prot_trap (0) || sel_trap (PC)) + 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)); @@ -1896,7 +1942,7 @@ while (reason == SCPE_OK) { /* loop until error */ break; case 01772: /* RUN */ - if (prot_trap (0) || sel_trap (PC)) + 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)); @@ -1904,7 +1950,7 @@ while (reason == SCPE_OK) { /* loop until error */ break; case 00776: /* SDN */ - if (prot_trap (0) || sel_trap (PC)) + 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)); @@ -2069,7 +2115,8 @@ WriteP (pa, mem); mode_ctrap = 0; mode_strap = 0; mode_storn = 0; -mode_user = 0; +mode_user = user_buf = 0; +mode_reloc = reloc_buf = 0; inst_base = 0; data_base = 0; return; @@ -2121,7 +2168,8 @@ PC = newpc; mode_ctrap = 0; mode_strap = 0; mode_storn = 0; -mode_user = 0; +mode_user = user_buf = 0; +mode_reloc = reloc_buf = 0; inst_base = 0; data_base = 0; return; @@ -2131,12 +2179,11 @@ return; t_bool ReadI (uint32 va, t_uint64 *val) { -if (mode_user) { +if (mode_reloc) va = (va + ind_reloc) & AMASK; - if ((va < ind_start) || (va > ind_limit)) { - prot_trap (0); - return FALSE; - } +if (mode_user && ((va < ind_start) || (va > ind_limit))) { + prot_trap (0); + return FALSE; } *val = M[va | inst_base]; return TRUE; @@ -2146,12 +2193,11 @@ return TRUE; t_bool Read (uint32 va, t_uint64 *val) { -if (mode_user) { +if (mode_reloc) va = (va + ind_reloc) & AMASK; - if ((va < ind_start) || (va > ind_limit)) { - prot_trap (0); - return FALSE; - } +if (mode_user && ((va < ind_start) || (va > ind_limit))) { + prot_trap (0); + return FALSE; } *val = M[va | data_base]; return TRUE; @@ -2161,12 +2207,11 @@ return TRUE; t_bool Write (uint32 va, t_uint64 dat) { -if (mode_user) { +if (mode_reloc) va = (va + ind_reloc) & AMASK; - if ((va < ind_start) || (va > ind_limit)) { - prot_trap (0); - return FALSE; - } +if (mode_user && ((va < ind_start) || (va > ind_limit))) { + prot_trap (0); + return FALSE; } M[va | data_base] = dat; return TRUE; @@ -2191,7 +2236,8 @@ mode_storn = 0; if (cpu_model & (I_94|I_CT)) mode_multi = 0; else mode_multi = 1; -mode_user = 0; +mode_user = user_buf = 0; +mode_reloc = reloc_buf = 0; inst_base = 0; data_base = 0; ch_req = 0; @@ -2220,8 +2266,7 @@ if (vptr == NULL) return SCPE_ARG; if ((sw & (SWMASK ('A') | SWMASK ('B')))? (ea > AMASK): (ea >= MEMSIZE)) return SCPE_NXM; -if ((sw & SWMASK ('B')) || - ((sw & SWMASK ('V')) && mode_user && inst_base)) +if (sw & SWMASK ('B')) ea = ea | BCORE_BASE; *vptr = M[ea] & DMASK; return SCPE_OK; diff --git a/I7094/i7094_cpu1.c b/I7094/i7094_cpu1.c index c5c4ea12..1b682eb0 100644 --- a/I7094/i7094_cpu1.c +++ b/I7094/i7094_cpu1.c @@ -1,6 +1,6 @@ /* i7094_cpu1.c: IBM 7094 CPU complex instructions - Copyright (c) 2003-2010, Robert M. Supnik + 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"), @@ -23,6 +23,9 @@ 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 (from Dave Pitts) Added SPUx, SPTx, SPRx */ @@ -296,10 +299,11 @@ switch (addr) { break; case 00007: /* ETM */ - if (prot_trap (0)) /* user mode? */ - break; - if (cpu_model & I_9X) /* 709X only */ + if (cpu_model & I_9X) { /* 709X only */ + if (prot_trap (0)) /* user mode? */ + break; mode_ttrap = 1; + } break; case 00010: /* RND */ @@ -322,6 +326,8 @@ switch (addr) { 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 */ @@ -350,10 +356,8 @@ switch (addr) { case 001000: case 002000: case 003000: case 004000: /* BTT */ case 005000: case 060000: case 070000: case 010000: - if (prot_trap (0)) /* user mode? */ - break; - if (cpu_model & I_9X) { /* 709X only */ - if (sel_trap (PC)) /* sel trap? */ + 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? */ @@ -437,32 +441,43 @@ switch (addr) { break; case 00004: /* LFTM */ - if (prot_trap (0)) /* user mode? */ - break; - if (cpu_model & I_9X) /* 709X only */ + 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 (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 (cpu_model & I_9X) { /* 709X only */ + if (prot_trap (0)) /* user mode? */ + break; mode_ctrap = 1; + } break; case 00007: /* LTM */ - if (prot_trap (0)) /* user mode? */ - break; - if (cpu_model & I_9X) /* 709X only */ + 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 (cpu_model & I_9X) { /* 709X only */ + if (prot_trap (0)) /* user mode? */ + break; mode_storn = 0; + } break; case 00012: /* RTT (704) */ @@ -497,7 +512,7 @@ switch (addr) { case 001000: case 002000: case 003000: case 004000: /* ETT */ case 005000: case 006000: case 007000: case 010000: - if (sel_trap (PC)) /* sel trap? */ + 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? */ diff --git a/I7094/i7094_cpu1_old.c b/I7094/i7094_cpu1_old.c deleted file mode 100644 index 18afca55..00000000 --- a/I7094/i7094_cpu1_old.c +++ /dev/null @@ -1,887 +0,0 @@ -/* i7094_cpu1.c: IBM 7094 CPU complex instructions - - 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. -*/ - -#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]; - -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 (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 */ - 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 */ - 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 01000: case 02000: case 03000: case 04000: /* BTT */ - case 05000: case 06000: case 07000: case 10000: - if (cpu_model & I_9X) { /* 709X only */ - if (sel_trap (PC)) /* sel trap? */ - 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: - 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: - ch = GET_U_CH (addr); /* get channel */ - return ch_op_reset (ch, 0); - } /* 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 (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 */ - mode_ftrap = 0; - break; - - case 00005: /* ESTM */ - if (cpu_model & I_9X) /* 709X only */ - mode_strap = 1; - break; - - case 00006: /* ECTM */ - if (cpu_model & I_9X) /* 709X only */ - mode_ctrap = 1; - break; - - case 00007: /* LTM */ - if (cpu_model & I_9X) /* 709X only */ - mode_ttrap = 0; - break; - - case 00010: /* LSNM */ - if (cpu_model & I_9X) /* 709X only */ - 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 (PC)) /* sel trap? */ - 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_cpu_old.c b/I7094/i7094_cpu_old.c deleted file mode 100644 index 87c46fca..00000000 --- a/I7094/i7094_cpu_old.c +++ /dev/null @@ -1,2439 +0,0 @@ -/* i7094_cpu.c: IBM 7094 CPU simulator - - Copyright (c) 2003-2007, 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 - - 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 - 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, ENAB, RCT, RDS, - or WDS (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 */ - -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 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 */ -static uint32 eamask = AMASK; /* (dynamic) addr mask */ - -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]; -extern FILE *sim_deb; -extern int32 sim_int_char; -extern int32 sim_interval; -extern int32 sim_switches; -extern uint32 sim_brk_types, sim_brk_dflt, sim_brk_summ; /* breakpoint info */ - -/* 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 (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 , 0 , I_XNR|I_9X, I_XN|I_94 , /* -600 */ - 0 , 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; -eamask = mode_storn? A704_MASK: AMASK; /* set eff addr mask */ -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 */ - } - 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; - 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 & 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; - 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 */ - if (prot_trap (0)) /* user mode? */ - break; - 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 */ - 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; - PCQ_ENTRY; - PC = ea; - mode_user = 1; - 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; - break; - - case 01600: /* STQ */ - Write (ea, MQ); - 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 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 */ - if (prot_trap (0)) /* user mode? */ - break; - 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: - if (prot_trap (0)) /* user mode? */ - break; - 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 (prot_trap (0) || sel_trap (PC)) - 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 (prot_trap (0) || sel_trap (PC)) - 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 (prot_trap (0) || sel_trap (PC)) - 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 (prot_trap (0) || sel_trap (PC)) - 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 (prot_trap (0) || sel_trap (PC)) - 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 (prot_trap (0) || sel_trap (PC)) - 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 (prot_trap (0) || sel_trap (PC)) - 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 (prot_trap (0) || sel_trap (PC)) - 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 = 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 = 0; -inst_base = 0; -data_base = 0; -return; -} - -/* Read instruction and indirect */ - -t_bool ReadI (uint32 va, t_uint64 *val) -{ -if (mode_user) { - va = (va + ind_reloc) & AMASK; - if ((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_user) { - va = (va + ind_reloc) & AMASK; - if ((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_user) { - va = (va + ind_reloc) & AMASK; - if ((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 = 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')) || - ((sw & SWMASK ('V')) && mode_user && inst_base)) - 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; -t_value sim_eval; -extern t_stat fprint_sym (FILE *ofile, t_addr addr, t_value *val, - UNIT *uptr, int32 sw); - -sim_eval = ir; -if (pc & HIST_PC) { /* instruction? */ - fputs ("CPU ", st); - fprintf (st, "%05o ", 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 ", pc & AMASK); - fputs (" ", st); - fprintf (st, "%05o ", 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_defs.h b/I7094/i7094_defs.h index 929f8b73..b100989e 100644 --- a/I7094/i7094_defs.h +++ b/I7094/i7094_defs.h @@ -1,6 +1,6 @@ /* i7094_defs.h: IBM 7094 simulator definitions - Copyright (c) 2003-2010, Robert M Supnik + 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"), @@ -28,6 +28,7 @@ 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 */ @@ -419,7 +420,7 @@ typedef struct { #define CHF_M_LCC 077 #define CHF_CLR_7909 07775000177 /* 7909 clear flags */ -#define CHF_SDC_7909 07776000000 /* 7909 SDC flags */ +#define CHF_SDC_7909 07777600000 /* 7909 SDC flags */ /* Channel characteristics (in dev.flags) */ diff --git a/I7094/i7094_drm.c b/I7094/i7094_drm.c index f8a15306..d7d91da9 100644 --- a/I7094/i7094_drm.c +++ b/I7094/i7094_drm.c @@ -1,6 +1,6 @@ /* i7094_drm.c: 7289/7320A drum simulator - Copyright (c) 2005-2008, Robert M Supnik + 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"), @@ -25,31 +25,29 @@ drm 7289/7320A "fast" drum - Very little is known about this device; the behavior simulated here is - what is used by CTSS. + 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 8 or less. + - 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's behavior if a sector boundary is crossed in mid-transfer is - unknown. CTSS never does this. - - The drum's behavior with record operations is unknown. CTSS only uses - IOCD and IOCP. - - The drum's error indicators are unknown. CTSS regards bits <0:2,13> of - the returned SCD data as errors, as well as the normal 7607 trap flags. - - The drum's rotational speed is unknown. + - 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. - Assumptions in this simulator: + Limitations in this simulator: - - Transfers may not cross a sector boundary. An attempt to do so sets - the EOF flag and causes an immediate disconnect. - - The hardware never sets end of record. + - Chain mode is not implemented. + - Write protect switches are not implemented. For speed, the entire drum is buffered in memory. */ @@ -65,6 +63,7 @@ #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)), \ @@ -73,7 +72,7 @@ /* Drum address from channel */ #define DRM_V_PHY 30 /* physical drum sel */ -#define DRM_M_PHY 07 +#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 */ @@ -83,15 +82,30 @@ #define DRM_GETWDA(x) ((((uint32) (x)) >> DRM_V_WDA) & DRM_M_WDA) #define DRM_GETDA(x) (((DRM_GETLOG(x) - 1) * DRM_NUMWDL) + DRM_GETWDA(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_HWDA 24 /* high word addr */ +#define DRMS_M_HWDA 017 +#define DRMS_V_GRP 23 /* group */ +#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_DATA 2 -#define DRM_EOS 3 +#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_sta = 0; /* state */ uint32 drm_op = 0; /* operation */ t_uint64 drm_chob = 0; /* output buf */ @@ -131,13 +145,14 @@ UNIT drm_unit[] = { { 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) } + UNIT_MUSTBUF+UNIT_DISABLE+UNIT_DIS, DRM_SIZE) }, }; REG drm_reg[] = { - { ORDATA (STATE, drm_sta, 2) }, + { ORDATA (STATE, drm_sta, 3) }, { ORDATA (DA, drm_da, 18) }, { FLDATA (OP, drm_op, 0) }, + { ORDATA (UNIT,drm_phy, 3) }, { ORDATA (CHOB, drm_chob, 36) }, { FLDATA (CHOBV, drm_chob_v, 0) }, { DRDATA (TIME, drm_time, 24), REG_NZ + PV_LEFT }, @@ -188,14 +203,14 @@ return SCPE_OK; t_stat drm_chwr (uint32 ch, t_uint64 val, uint32 flags) { -uint32 u, l; +uint32 l; int32 cp, dp; if (drm_sta == DRM_1ST) { - u = DRM_GETPHY (val); /* get unit */ + drm_phy = DRM_GETPHY (val); /* get unit */ l = DRM_GETLOG (val); /* get logical address */ - if ((u >= DRM_NUMDR) || /* invalid unit? */ - (drm_unit[u].flags & UNIT_DIS) || /* disabled unit? */ + if ((drm_phy >= DRM_NUMDR) || /* invalid unit? */ + (drm_unit[drm_phy].flags & UNIT_DIS) || /* disabled unit? */ (l == 0) || (l > DRM_NUMLD)) { /* invalid log drum? */ ch6_err_disc (ch, U_DRM, CHF_TRC); /* disconnect */ drm_sta = DRM_IDLE; @@ -206,10 +221,12 @@ if (drm_sta == DRM_1ST) { 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[u], dp * drm_time); /* schedule */ - if (drm_op) /* if write, get word */ + 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_DATA; + drm_sta = DRM_FILL; /* sector fill */ + } + else drm_sta = DRM_DATA; /* data transfer */ drm_chob = 0; /* clr, inval buffer */ drm_chob_v = 0; } @@ -224,6 +241,7 @@ return SCPE_OK; t_stat drm_svc (UNIT *uptr) { +uint32 i; t_uint64 *fbuf = (t_uint64 *) uptr->filebuf; if ((uptr->flags & UNIT_BUF) == 0) { /* not buf? */ @@ -239,6 +257,13 @@ if (drm_da >= DRM_SIZE) { /* nx logical drum? */ switch (drm_sta) { /* case on state */ + case DRM_FILL: /* write, clr sector */ + for (i = drm_da & ~DRM_SCMASK; i <= (drm_da | DRM_SCMASK); i++) + fbuf[i] = 0; /* clear sector */ + 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 */ @@ -258,7 +283,7 @@ switch (drm_sta) { /* case on state */ sim_activate (uptr, drm_time); /* next word */ break; - case DRM_EOS: /* end sector */ + 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 */ @@ -272,10 +297,10 @@ return SCPE_OK; t_bool drm_da_incr (void) { -drm_da = drm_da + 1; -if (drm_da & DRM_SCMASK) +drm_da = (drm_da & ~DRM_LDMASK) | ((drm_da + 1) & DRM_LDMASK); +if ((drm_da & DRM_LDMASK) != 0) return FALSE; -drm_sta = DRM_EOS; +drm_sta = DRM_EOD; return TRUE; } @@ -285,6 +310,7 @@ t_stat drm_reset (DEVICE *dptr) { uint32 i; +drm_phy = 0; drm_da = 0; drm_op = 0; drm_sta = DRM_IDLE; diff --git a/I7094/i7094_mt_old.c b/I7094/i7094_mt_old.c deleted file mode 100644 index 6c8f9cf4..00000000 --- a/I7094/i7094_mt_old.c +++ /dev/null @@ -1,861 +0,0 @@ -/* i7094_mt.c: IBM 7094 magnetic tape simulator - - 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. - - mt magtape simulator -*/ - -#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; -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 FILE *sim_deb; -extern 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 - }, - { - "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: - case CHSL_BSR: - case CHSL_BSF: /* rd, wr, backspace */ - sim_activate (uptr, mt_tstart); /* schedule op */ - break; - - case CHSL_WEF: /* write eof? */ - sim_activate (uptr, mt_twef); /* schedule op */ - break; - - case CHSL_RUN: - sim_activate (uptr, mt_tshort); /* schedule quick event */ - break; - case CHSL_REW: - 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: /* backspace rec */ - r = sim_tape_sprecr (uptr, &bc); /* space backwards */ - mt_unit[ch] = 0; /* clr ctrl busy */ - ch6_end_nds (ch); /* disconnect */ - 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: /* backspace file */ - while ((r = sim_tape_sprecr (uptr, &bc)) == MTSE_OK) ; - mt_unit[ch] = 0; /* clr ctrl busy */ - ch6_end_nds (ch); /* disconnect */ - 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] = { - 0076200000000 + U_MTBIN - 1, /* RDS MT_binary */ - 0054000000000 + BOOT_START + 4, /* RCHA *+3 */ - 0054400000000, /* LCHA 0 */ - 0002100000001, /* TTR 1 */ - 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 index 0c818061..0b757f91 100644 --- a/I7094/i7094_sys.c +++ b/I7094/i7094_sys.c @@ -1,6 +1,6 @@ /* i7094_sys.c: IBM 7094 simulator interface - Copyright (c) 2003-2010, Robert M Supnik + 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"), @@ -23,6 +23,7 @@ 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 @@ -362,7 +363,8 @@ static const char *opcode[] = { "RSCF", "RSCH", "STCB", "STCD", "STCF", "STCH", - "STQ", "ORS", "DST", + "STQ", "SRI", "ORS", "DST", + "SPI", "SLQ", "STL", "SXD", "SCD", "SCHB", "SCHD", @@ -533,7 +535,8 @@ static const t_uint64 opc_v[] = { 0454200000000+I_MXN, 0454300000000+I_MXN, 0454400000000+I_MXN, 0454500000000+I_MXN, 0454600000000+I_MXN, 0454700000000+I_MXN, - 0460000000000+I_MXN, 0460200000000+I_MXN, 0460300000000+I_MXN, + 0460000000000+I_MXN, 0460100000000+I_MXN, 0460200000000+I_MXN, 0460300000000+I_MXN, + 0460400000000+I_MXN, 0462000000000+I_MXN, 0462500000000+I_MXN, 0463400000000+I_MXR, 0463600000000+I_MXR, 0464000000000+I_MXN, 0464000000000+I_MXN, diff --git a/I7094/i7094_sys_old.c b/I7094/i7094_sys_old.c deleted file mode 100644 index 1d36e3bc..00000000 --- a/I7094/i7094_sys_old.c +++ /dev/null @@ -1,748 +0,0 @@ -/* i7094_sys.c: IBM 7094 simulator interface - - 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. - - 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 0000000000000000 /* no operand */ -#define I_MXR 0010000000000000 /* addr(tag) */ -#define I_MXN 0020000000000000 /* *addr(tag) */ -#define I_MXV 0030000000000000 /* var mul/div */ -#define I_MXC 0040000000000000 /* convert */ -#define I_DNP 0050000000000000 /* decr, no oper */ -#define I_DEC 0060000000000000 /* decrement */ -#define I_SNS 0070000000000000 /* sense */ -#define I_IMM 0100000000000000 /* 18b immediate */ -#define I_TAG 0110000000000000 /* tag only */ -#define I_IOX 0120000000000000 /* IO channel */ -#define I_TCH 0130000000000000 /* transfer channel */ -#define I_I9N 0140000000000000 /* 7909 with nostore */ -#define I_I9S 0150000000000000 /* 7909 */ -#define IFAKE_7607 0001000000000000 /* fake op extensions */ -#define IFAKE_7909 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 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[14] = { - 03777700000000, 03777700000000, - 03777700000000, 03777700000000, - 03777400000000, 03700000000000, - 03700000000000, 03777700077777, - 03777700000000, 03777700000000, - 03700000200000, 03700000200000, - 03760000200000, 03740000200000 }; - -static const uint32 fld_max[14][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 } - }; - -static const uint32 fld_fmt[14][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 */ - }; - -static const t_uint64 ind_test[14] = { - 0, 0, INST_IND, 0, 0, 0, 0, - 0, 0, 0, CHI_IND, CHI_IND, CHI_IND, CHI_IND - }; - -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", - - "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", "ORS", "DST", - "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[] = { - 0100000000000+I_DEC, 0200000000000+I_DEC, 0300000000000+I_DEC, - 0500000000000+I_DNP, 0600000000000+I_DEC, 0700000000000+I_DEC, - 0000000000000+I_MXN, 0002000000000+I_MXN, 0002100000000+I_MXN, - - 0076000000000+I_SNS, 0076000000001+I_SNS, 0076000000002+I_SNS, - 0076000000003+I_SNS, 0076000000004+I_SNS, 0076000000005+I_SNS, - 0076000000006+I_SNS, 0076000000007+I_SNS, 0076000000010+I_SNS, - 0076000000011+I_SNS, 0076000000012+I_SNS, 0076000000014+I_SNS, - 0076000000016+I_SNS, 0076000000140+I_SNS, 0076000000141+I_SNS, - 0076000000142+I_SNS, 0076000000143+I_SNS, 0076000000144+I_SNS, - 0076000000161+I_SNS, 0076000000162+I_SNS, 0076000000163+I_SNS, - 0076000000164+I_SNS, 0076000000165+I_SNS, 0076000000166+I_SNS, - 0076000001000+I_SNS, 0076000002000+I_SNS, 0076000003000+I_SNS, - 0076000004000+I_SNS, 0076000005000+I_SNS, 0076000006000+I_SNS, - 0076000007000+I_SNS, 0076000010000+I_SNS, - 0076000001350+I_SNS, 0076000002350+I_SNS, 0076000003350+I_SNS, - 0076000004350+I_SNS, 0076000005350+I_SNS, 0076000006350+I_SNS, - 0076000007350+I_SNS, 0076000010350+I_SNS, - 0076000001352+I_SNS, 0076000002352+I_SNS, 0076000003352+I_SNS, - 0076000004352+I_SNS, 0076000005352+I_SNS, 0076000006352+I_SNS, - 0076000007352+I_SNS, 0076000010352+I_SNS, - - 0002200000000+I_MXN, 0002400000000+I_MXN, - 0002600000000+I_MXN, 0002700000000+I_MXN, - 0003000000000+I_MXN, 0003100000000+I_MXN, - 0003200000000+I_MXN, 0003300000000+I_MXN, - 0004000000000+I_MXN, 0004100000000+I_NOP, 0004200000000+I_MXR, - 0004300000000+I_NOP, 0004400000000+I_NOP, 0004600000000+I_MXR, - 0005100000000+I_IMM, 0005400000000+I_IMM, 0005500000000+I_IMM, - 0005600000000+I_IMM, 0005700000000+I_IMM, - 0006000000000+I_MXN, 0006100000000+I_MXN, 0006200000000+I_MXN, - 0006300000000+I_MXN, 0006400000000+I_MXN, 0006500000000+I_MXN, - 0006600000000+I_MXN, 0006700000000+I_MXN, 0007400000000+I_MXR, - 0010000000000+I_MXN, 0011400000000+I_MXC, 0012000000000+I_MXN, - 0013100000000+I_NOP, 0014000000000+I_MXN, - 0016100000000+I_MXN, 0016200000000+I_MXN, - 0020000000000+I_MXN, 0020400000000+I_MXV, 0020500000000+I_MXV, - 0022000000000+I_MXN, 0022100000000+I_MXN, - 0022400000000+I_MXV, 0022500000000+I_MXV, - 0022600000000+I_MXV, 0022700000000+I_MXV, - 0024000000000+I_MXN, 0024100000000+I_MXN, - 0026000000000+I_MXN, 0026100000000+I_MXN, - 0030000000000+I_MXN, 0030100000000+I_MXN, - 0030200000000+I_MXN, 0030300000000+I_MXN, - 0030400000000+I_MXN, 0030500000000+I_MXN, - 0030600000000+I_MXN, 0030700000000+I_MXN, - 0032000000000+I_MXN, 0032200000000+I_MXN, - 0034000000000+I_MXN, 0036100000000+I_MXN, - 0040000000000+I_MXN, 0040100000000+I_MXN, - 0040200000000+I_MXN, 0440000000000+I_MXN, - 0042000000000+I_NOP, 0044000000000+I_MXN, 0044100000000+I_MXN, - 0044200000000+I_MXN, 0044300000000+I_MXN, 0044400000000+I_MXN, - 0044500000000+I_MXN, 0044600000000+I_MXN, - 0050000000000+I_MXN, 0050200000000+I_MXN, - 0052000000000+I_MXN, 0052200000000+I_MXN, - 0053400000000+I_MXR, 0053500000000+I_MXR, - 0054000000000+I_MXN, 0054100000000+I_MXN, - 0054200000000+I_MXN, 0054300000000+I_MXN, - 0054400000000+I_MXN, 0054500000000+I_MXN, - 0054600000000+I_MXN, 0054700000000+I_MXN, - 0054000000000+I_MXN, 0054100000000+I_MXN, - 0054200000000+I_MXN, 0054300000000+I_MXN, - 0054400000000+I_MXN, 0054500000000+I_MXN, - 0054600000000+I_MXN, 0054700000000+I_MXN, - 0056000000000+I_MXN, 0056400000000+I_MXN, - 0060000000000+I_MXN, 0060100000000+I_MXN, 0060200000000+I_MXN, - 0060400000000+I_MXN, 0062100000000+I_MXN, 0062200000000+I_MXN, - 0062500000000+I_MXN, 0063000000000+I_MXN, - 0063400000000+I_MXR, 0063600000000+I_MXR, - 0064000000000+I_MXN, 0064000000000+I_MXN, - 0064200000000+I_MXN, 0064300000000+I_MXN, - 0064400000000+I_MXN, 0064500000000+I_MXN, - 0064600000000+I_MXN, 0064700000000+I_MXN, - 0073400000000+I_TAG, 0073700000000+I_TAG, - 0075400000000+I_TAG, 0075600000000+I_TAG, - 0076000000000+I_MXR, 0076100000000+I_NOP, 0076200000000+I_MXR, - 0076300000000+I_MXR, 0076400000000+I_MXR, 0076500000000+I_MXR, - 0076600000000+I_MXR, 0076700000000+I_MXR, 0077000000000+I_MXR, - 0077100000000+I_MXR, 0077200000000+I_MXR, 0077400000000+I_MXR, - 0077600000000+I_MXR, - - 0476000000000+I_SNS, 0476000000001+I_SNS, 0476000000002+I_SNS, - 0476000000003+I_SNS, 0476000000004+I_SNS, 0476000000005+I_SNS, - 0476000000006+I_SNS, 0476000000007+I_SNS, 0476000000010+I_SNS, - 0476000000016+I_SNS, 0476000000141+I_SNS, 0476000000142+I_SNS, - 0476000000143+I_SNS, 0476000000144+I_SNS, - 0476000001000+I_SNS, 0476000002000+I_SNS, 0476000003000+I_SNS, - 0476000004000+I_SNS, 0476000005000+I_SNS, 0476000006000+I_SNS, - 0476000007000+I_SNS, 0476000010000+I_SNS, - - 0402100000000+I_MXN, - 0402200000000+I_MXN, 0402400000000+I_MXN, - 0402600000000+I_MXN, 0402700000000+I_MXN, - 0403000000000+I_MXN, 0403100000000+I_MXN, - 0403200000000+I_MXN, 0403300000000+I_MXN, - 0404200000000+I_NOP, 0404600000000+I_NOP, - 0405100000000+I_IMM, 0405400000000+I_IMM, 0405500000000+I_IMM, - 0405600000000+I_IMM, 0405700000000+I_IMM, - 0406000000000+I_MXN, 0406100000000+I_MXN, 0406200000000+I_MXN, - 0406300000000+I_MXN, 0406400000000+I_MXN, 0406500000000+I_MXN, - 0406600000000+I_MXN, 0406700000000+I_MXN, - 0410000000000+I_MXN, 0411400000000+I_MXC, 0412000000000+I_MXN, - 0413000000000+I_NOP, 0414000000000+I_MXN, 0415400000000+I_MXC, - 0420000000000+I_MXN, 0424000000000+I_MXN, 0424100000000+I_MXN, - 0426000000000+I_MXN, 0426100000000+I_MXN, - 0430000000000+I_MXN, 0430100000000+I_MXN, - 0430200000000+I_MXN, 0430300000000+I_MXN, - 0430400000000+I_MXN, 0430500000000+I_MXN, - 0430600000000+I_MXN, 0430700000000+I_MXN, - 0432000000000+I_MXN, 0434000000000+I_MXN, - 0450000000000+I_MXN, 0450100000000+I_MXN, 0452000000000+I_MXN, - 0453400000000+I_MXR, 0453500000000+I_MXR, - 0454000000000+I_MXN, 0454100000000+I_MXN, - 0454200000000+I_MXN, 0454300000000+I_MXN, - 0454400000000+I_MXN, 0454500000000+I_MXN, - 0454600000000+I_MXN, 0454700000000+I_MXN, - 0454000000000+I_MXN, 0454100000000+I_MXN, - 0454200000000+I_MXN, 0454300000000+I_MXN, - 0454400000000+I_MXN, 0454500000000+I_MXN, - 0454600000000+I_MXN, 0454700000000+I_MXN, - 0460000000000+I_MXN, 0460200000000+I_MXN, 0460300000000+I_MXN, - 0462000000000+I_MXN, 0462500000000+I_MXN, - 0463400000000+I_MXR, 0463600000000+I_MXR, - 0464000000000+I_MXN, 0464000000000+I_MXN, - 0464200000000+I_MXN, 0464300000000+I_MXN, - 0464400000000+I_MXN, 0464500000000+I_MXN, - 0464600000000+I_MXN, 0464700000000+I_MXN, - 0473400000000+I_TAG, 0473700000000+I_TAG, - 0475400000000+I_TAG, 0475600000000+I_TAG, - 0476000000000+I_MXR, 0476300000000+I_MXR, 0476400000000+I_MXR, - 0476500000000+I_MXR, 0477300000000+I_MXR, 0477200000000+I_MXR, - 0477400000000+I_MXR, - - 0010100000000+I_MXN, 0410100000000+I_MXN, - 0056200000000+I_MXN, 0456400000000+I_MXN, - 0476100000041+I_SNS, 0476100000042+I_SNS, - 0476100000043+I_SNS, 0476100000044+I_SNS, - - 01000000000000+I_IOX, 01000000200000+I_IOX, 01100000000000+I_TCH, - 01200000000000+I_IOX, 01200000200000+I_IOX, - 01300000000000+I_IOX, 01300000200000+I_IOX, - 01400000000000+I_IOX, 01400000200000+I_IOX, - 01500000000000+I_IOX, 01500000200000+I_IOX, - 01600000000000+I_IOX, 01600000200000+I_IOX, - 01700000000000+I_IOX, 01700000200000+I_IOX, - - 02000000000000+I_TCH, 02000000200000+I_IOX, - 02100000000000+I_TCH, 02100000200000+I_TCH, - 02200000000000+I_I9N, 02220000000000+I_TCH, - 02200000200000+I_I9N, 02220000200000+I_TCH, - 02240000000000+I_I9N, 02260000000000+I_TCH, - 02240000200000+I_I9N, - 02300000000000+I_I9S, 02300000200000+I_I9S, - 02340000000000+I_I9S, - 02400000000000+I_IOX, - 02500000000000+I_IOX, 02500000200000+I_IOX, - 02600000200000+I_I9S, 02640000000000+I_I9S, 02640000200000+I_I9S, - 02700000000000+I_I9S, 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/LGP/lgp_defs.h b/LGP/lgp_defs.h index aed3fe04..ebe442ed 100644 --- a/LGP/lgp_defs.h +++ b/LGP/lgp_defs.h @@ -24,7 +24,6 @@ in this Software without prior written authorization from Robert M Supnik. 22-May-10 RMS Added check for 64b definitions - */ #ifndef _LGP_DEFS_H_ diff --git a/PDP10/pdp10_sys.c b/PDP10/pdp10_sys.c index 78b1d2c0..061f0e40 100644 --- a/PDP10/pdp10_sys.c +++ b/PDP10/pdp10_sys.c @@ -1,6 +1,6 @@ /* pdp10_sys.c: PDP-10 simulator interface - Copyright (c) 1993-2008, Robert M Supnik + Copyright (c) 1993-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"), @@ -23,6 +23,7 @@ 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-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 @@ -54,7 +55,6 @@ extern DEVICE dz_dev; extern DEVICE ry_dev; extern DEVICE cr_dev; extern DEVICE lp20_dev; -extern DEVICE xu_dev; extern UNIT cpu_unit; extern REG cpu_reg[]; extern d10 *M; @@ -90,7 +90,6 @@ DEVICE *sim_devices[] = { &rp_dev, &tu_dev, &dz_dev, - &xu_dev, NULL }; diff --git a/PDP11/pdp11_dc.c b/PDP11/pdp11_dc.c index 1228538e..b1def4a7 100644 --- a/PDP11/pdp11_dc.c +++ b/PDP11/pdp11_dc.c @@ -1,6 +1,6 @@ /* pdp11_dc.c: PDP-11 DC11 multiple terminal interface simulator - Copyright (c) 1993-2008, Robert M Supnik + Copyright (c) 1993-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"), @@ -25,6 +25,7 @@ dci,dco DC11 terminal input/output + 17-Aug-2011 RMS Added AUTOCONFIGURE modifier 19-Nov-2008 RMS Revised for common TMXR show routines Revised to autoconfigure vectors @@ -175,6 +176,8 @@ MTAB dci_mod[] = { 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", diff --git a/PDP11/pdp11_dl.c b/PDP11/pdp11_dl.c index 00dff0ec..aebd38f4 100644 --- a/PDP11/pdp11_dl.c +++ b/PDP11/pdp11_dl.c @@ -1,6 +1,6 @@ /* pdp11_dl.c: PDP-11 multiple terminal interface simulator - Copyright (c) 1993-2008, Robert M Supnik + Copyright (c) 1993-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"), @@ -25,6 +25,7 @@ dli,dlo DL11 terminal input/output + 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 @@ -142,6 +143,8 @@ MTAB dli_mod[] = { 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", diff --git a/PDP11/pdp11_io.c b/PDP11/pdp11_io.c index 45c08891..1e687530 100644 --- a/PDP11/pdp11_io.c +++ b/PDP11/pdp11_io.c @@ -23,7 +23,7 @@ used in advertising or otherwise to promote the sale, use or other dealings in this Software without prior written authorization from Robert M Supnik. - 12-Dec-11 RMS Fixed interrupts to treat all Qbus devices as BR4 + 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 diff --git a/PDP11/pdp11_rl.c b/PDP11/pdp11_rl.c index 19944926..9c97888d 100644 --- a/PDP11/pdp11_rl.c +++ b/PDP11/pdp11_rl.c @@ -1,6 +1,6 @@ /* pdp11_rl.c: RL11 (RLV12) cartridge disk simulator - Copyright (c) 1993-2009, Robert M Supnik + 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"), @@ -25,7 +25,20 @@ rl RL11(RLV12)/RL01/RL02 cartridge disk - 10-Oct-09 RMS Added debug support + 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 (from Sterling Garwood) 16-Aug-05 RMS Fixed C++ declaration and cast problems 07-Jul-05 RMS Removed extraneous externs @@ -82,26 +95,36 @@ #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 (1 << 16) /* max transfer */ -#define RL01_SIZE (RL_NUMCY * RL_NUMSF * RL_NUMSC * RL_NUMWD) /* words/drive */ +#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 */ -#define UNIT_DUMMY (1 << UNIT_V_DUMMY) +#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) @@ -109,74 +132,85 @@ extern uint32 cpu_opt; /* Parameters in the unit descriptor */ -#define TRK u3 /* current track */ +#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 */ +/* RLDS, NI = not implemented, * = kept in STAT, ^ = kept in TRK , ! = kept in uptr */ -#define RLDS_LOAD 0 /* no cartridge */ -#define RLDS_LOCK 5 /* lock on */ -#define RLDS_BHO 0000010 /* brushes home NI */ -#define RLDS_HDO 0000020 /* heads out NI */ -#define RLDS_CVO 0000040 /* cover open NI */ -#define RLDS_HD 0000100 /* head select ^ */ -#define RLDS_RL02 0000200 /* RL02 */ -#define RLDS_DSE 0000400 /* drv sel err NI */ -#define RLDS_VCK 0001000 /* vol check * */ -#define RLDS_WGE 0002000 /* wr gate err * */ -#define RLDS_SPE 0004000 /* spin err * */ -#define RLDS_STO 0010000 /* seek time out NI */ -#define RLDS_WLK 0020000 /* wr locked */ -#define RLDS_HCE 0040000 /* hd curr err NI */ -#define RLDS_WDE 0100000 /* wr data err NI */ -#define RLDS_ATT (RLDS_HDO+RLDS_BHO+RLDS_LOCK) /* att status */ -#define RLDS_UNATT (RLDS_CVO+RLDS_LOAD) /* unatt status */ -#define RLDS_ERR (RLDS_WDE+RLDS_HCE+RLDS_STO+RLDS_SPE+RLDS_WGE+ \ - RLDS_VCK+RLDS_DSE) /* errors bits */ +#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_V_FUNC 1 -#define RLCS_M_MEX 03 /* memory extension */ -#define RLCS_V_MEX 4 +#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_HDE 0010000 /* header error */ -#define RLCS_NXM 0020000 /* non-exist memory */ -#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 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_SK_DIR 0000004 /* direction */ -#define RLDA_GS_CLR 0000010 /* clear errors */ -#define RLDA_SK_HD 0000020 /* head select */ +#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_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_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) @@ -186,11 +220,11 @@ extern uint32 cpu_opt; /* RLBA */ -#define RLBA_IMP 0177776 /* implemented */ +#define RLBA_IMP (0177777) /* implemented */ /* RLBAE */ -#define RLBAE_IMP 0000077 /* implemented */ +#define RLBAE_IMP (0000077) /* implemented */ extern int32 int_req[IPL_HLVL]; extern FILE *sim_deb; @@ -205,6 +239,7 @@ int32 rl_swait = 10; /* seek wait */ int32 rl_rwait = 10; /* rotate wait */ int32 rl_stopioe = 1; /* stop on error */ +/* forward references */ DEVICE rl_dev; t_stat rl_rd (int32 *data, int32 PA, int32 access); t_stat rl_wr (int32 data, int32 PA, int32 access); @@ -215,31 +250,42 @@ 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 *, int, void *); +t_stat rl_set_load (UNIT *, int32, char *, void *); +t_stat rl_show_load (FILE *, UNIT *, int, void *); +t_stat rl_show_dstate (FILE *, UNIT *, int, 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, int 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 + rl_dev RL device descriptor + rl_unit RL unit list + rl_reg RL register list + rl_mod RL modifier list */ -DIB rl_dib = { +static DIB rl_dib = { IOBA_RL, IOLN_RL, &rl_rd, &rl_wr, 1, IVCL (RL), VEC_RL, { NULL } }; -UNIT rl_unit[] = { +static UNIT rl_unit[] = { { UDATA (&rl_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+ - UNIT_ROABLE+UNIT_AUTO, RL01_SIZE) }, + UNIT_ROABLE+UNIT_AUTO, RL01_SIZE) }, { UDATA (&rl_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+ - UNIT_ROABLE+UNIT_AUTO, RL01_SIZE) }, + UNIT_ROABLE+UNIT_AUTO, RL01_SIZE) }, { UDATA (&rl_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+ - UNIT_ROABLE+UNIT_AUTO, RL01_SIZE) }, + UNIT_ROABLE+UNIT_AUTO, RL01_SIZE) }, { UDATA (&rl_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+ - UNIT_ROABLE+UNIT_AUTO, RL01_SIZE) } + UNIT_ROABLE+UNIT_AUTO, RL01_SIZE) } }; -REG rl_reg[] = { +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) }, @@ -261,7 +307,22 @@ REG rl_reg[] = { { NULL } }; -MTAB rl_mod[] = { +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 }, @@ -281,20 +342,26 @@ MTAB rl_mod[] = { }; DEVICE rl_dev = { - "RL", rl_unit, rl_reg, rl_mod, + "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, NULL, - &rl_dib, DEV_DEBUG | DEV_DISABLE | DEV_UBUS | DEV_QBUS + &rl_boot, &rl_attach, &rl_detach, + &rl_dib, DEV_DISABLE | DEV_UBUS | DEV_QBUS | DEV_DEBUG }; -/* I/O dispatch routines, I/O addresses 17774400 - 17774407 +/* Drive states */ +static const char * const state[] = { + "Load Cartridge", "Spin Up", "Brush", "Load Heads", + "Seek", "Lock On", "Unload Heads", "Spin Down" +}; - 17774400 RLCS read/write - 17774402 RLBA read/write - 17774404 RLDA read/write - 17774406 RLMP read/write - 17774410 RLBAE read/write +/* 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) @@ -304,15 +371,37 @@ UNIT *uptr; switch ((PA >> 1) & 07) { /* decode PA<2:1> */ case 0: /* RLCS */ - rlcs = (rlcs & ~RLCS_MEX) | ((rlbae & RLCS_M_MEX) << RLCS_V_MEX); - if (rlcs & RLCS_ALLERR) - rlcs = rlcs | RLCS_ERR; - uptr = rl_dev.units + GET_DRIVE (rlcs); - if (sim_is_active (uptr)) - rlcs = rlcs & ~RLCS_DRDY; - else rlcs = rlcs | RLCS_DRDY; /* see if ready */ - *data = rlcs; - break; + 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; @@ -329,111 +418,278 @@ switch ((PA >> 1) & 07) { /* decode PA<2:1> */ break; case 4: /* RLBAE */ - if (UNIBUS) /* not in RL11 */ + if (UNIBUS || (rl_dev.flags & DEV_RLV11)) /* not in RL11/RLV11 */ return SCPE_NXM; *data = rlbae & RLBAE_IMP; break; - } /* end switch */ -if (DEBUG_PRS (rl_dev)) - fprintf (sim_deb, ">>RL read: reg%d=%o\n", (PA >> 1) & 07, *data); + default: + return (SCPE_NXM); + } /* end switch */ return SCPE_OK; } t_stat rl_wr (int32 data, int32 PA, int32 access) { -int32 curr, offs, newc, maxc; +int32 curr, offs, newc, maxc, tim; UNIT *uptr; -if (DEBUG_PRS (rl_dev)) - fprintf (sim_deb, ">>RL write: reg%d=%o\n", (PA >> 1) & 07, data); - switch ((PA >> 1) & 07) { /* decode PA<2:1> */ case 0: /* RLCS */ rlcs = (rlcs & ~RLCS_MEX) | ((rlbae & RLCS_M_MEX) << RLCS_V_MEX); - if (rlcs & RLCS_ALLERR) - rlcs = rlcs | RLCS_ERR; uptr = rl_dev.units + GET_DRIVE (data); /* get new drive */ - if (sim_is_active (uptr)) - rlcs = rlcs & ~RLCS_DRDY; - else rlcs = rlcs | RLCS_DRDY; /* see if ready */ - 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); - 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; - } +/* +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 & ~RLCS_ALLERR; /* clear errors */ + 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 */ - curr = GET_CYL (uptr->TRK); /* current cylinder */ - offs = GET_CYL (rlda); /* offset */ - if (rlda & RLDA_SK_DIR) { /* in or out? */ - newc = curr + offs; /* out */ + 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 */ + } else { + newc = curr - offs; /* in */ if (newc < 0) newc = 0; - } - uptr->TRK = (newc << RLDA_V_CYL) | /* put on track */ + } + /* 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); - sim_activate (uptr, rl_swait * abs (newc - curr)); +/* +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; - default: /* data transfer */ + 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 = 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, 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 & RLBA_IMP; + 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 = data; + if (DEBUG_PRS (rl_dev)) + fprintf (sim_deb, ">>RL wr: RLMP %06o\n", rlmp); break; case 4: /* RLBAE */ - if (UNIBUS) /* not in RL11 */ + 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 uint32 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 (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 = rlda; + rlxb[0] = calcCRC (1, &w); /* calculate CRC */ + rlda = (rlda & ~0377) | ((rlda + 1) & 0377); + + /* 5: check the CRC of (DAR + 4) */ + w = 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 @@ -446,78 +702,178 @@ return SCPE_OK; t_stat rl_svc (UNIT *uptr) { int32 err, wc, maxwc, t; -int32 i, func, da, awc; +int32 i, da, awc; uint32 ma; uint16 comp; +static const char * const funcname[] = { + "NOP", "WCK", "GSTA", "SEEK", + "RHDR", "WT", "RD", "RNOHDR", "SPECIAL", +}; -func = GET_FUNC (rlcs); /* get function */ -if (func == RLCS_GSTA) { /* get status */ - if (rlda & RLDA_GS_CLR) - uptr->STAT = uptr->STAT & ~RLDS_ERR; - rlmp = uptr->STAT | (uptr->TRK & RLDS_HD) | - ((uptr->flags & UNIT_ATT)? RLDS_ATT: RLDS_UNATT); - if (uptr->flags & UNIT_RL02) - rlmp = rlmp | RLDS_RL02; - if (uptr->flags & UNIT_WPRT) - rlmp = rlmp | RLDS_WLK; - rlmp2 = rlmp1 = rlmp; - rl_set_done (0); /* done */ - return SCPE_OK; +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? */ - rlcs = rlcs & ~RLCS_DRDY; /* clear drive ready */ - uptr->STAT = uptr->STAT | RLDS_SPE; /* spin error */ + uptr->STAT |= RLDS_SPE; /* spin error */ rl_set_done (RLCS_ERR | RLCS_INCMP); /* flag error */ return IORETURN (rl_stopioe, SCPE_UNATT); } -if ((func == RLCS_WRITE) && (uptr->flags & UNIT_WPRT)) { - uptr->STAT = uptr->STAT | RLDS_WGE; /* write and locked */ +if ((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 (func == RLCS_SEEK) { /* seek? */ - rl_set_done (0); /* done */ - 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 (func == RLCS_RHDR) { /* read header? */ - rlmp = (uptr->TRK & RLDA_TRACK) | GET_SECT (rlda); - rlmp1 = rlmp2 = 0; +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 */ - return SCPE_OK; + /* 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 (((func != RLCS_RNOHDR) && ((uptr->TRK & RLDA_CYL) != (rlda & RLDA_CYL))) - || (GET_SECT (rlda) >= RL_NUMSC)) { /* bad cyl or sector? */ - rl_set_done (RLCS_ERR | RLCS_HDE | RLCS_INCMP); /* wrong cylinder? */ - return SCPE_OK; - } +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 */ -da = GET_DA (rlda) * RL_NUMWD; /* get disk addr */ wc = 0200000 - rlmp; /* get true wc */ -maxwc = (RL_NUMSC - GET_SECT (rlda)) * RL_NUMWD; /* max transfer */ if (wc > maxwc) /* track overrun? */ wc = maxwc; err = fseek (uptr->fileref, da * sizeof (int16), SEEK_SET); -if ((func >= RLCS_READ) && (err == 0)) { /* read (no hdr)? */ - i = fxread (rlxb, sizeof (int16), wc, uptr->fileref); - err = ferror (uptr->fileref); - 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 */ +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 ((func == RLCS_WRITE) && (err == 0)) { /* write? */ - if (t = Map_ReadW (ma, wc << 1, rlxb)) { /* fetch buffer */ + 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 */ } @@ -530,7 +886,8 @@ if ((func == RLCS_WRITE) && (err == 0)) { /* write? */ } } /* end write */ -if ((func == RLCS_WCHK) && (err == 0)) { /* write check? */ +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 */ @@ -546,14 +903,30 @@ if ((func == RLCS_WCHK) && (err == 0)) { /* write check? */ } /* 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 | RLCS_ERR | RLCS_INCMP; -ma = ma + (wc << 1); /* final byte addr */ + 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); -rlda = rlda + ((wc + (RL_NUMWD - 1)) / RL_NUMWD); + +/* +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? */ @@ -568,11 +941,10 @@ return SCPE_OK; void rl_set_done (int32 status) { -rlcs = rlcs | status | CSR_DONE; /* set done */ +rlcs |= status | CSR_DONE; /* set done */ if (rlcs & CSR_IE) SET_INT (RL); else CLR_INT (RL); -return; } /* Device reset @@ -591,7 +963,7 @@ CLR_INT (RL); for (i = 0; i < RL_NUMDR; i++) { uptr = rl_dev.units + i; sim_cancel (uptr); - uptr->STAT = 0; + uptr->STAT &= ~RLDS_ERR; } if (rlxb == NULL) rlxb = (uint16 *) calloc (RL_MAXFR, sizeof (uint16)); @@ -611,8 +983,12 @@ 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_VCK; /* new volume */ +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; @@ -631,6 +1007,16 @@ else { 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) @@ -648,6 +1034,105 @@ 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, int 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, int 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, int 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_is_active (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, int val, void *desc) +{ + 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) @@ -709,7 +1194,7 @@ extern int32 saved_PC; for (i = 0; i < BOOT_LEN; i++) M[(BOOT_START >> 1) + i] = boot_rom[i]; M[BOOT_UNIT >> 1] = unitno & RLCS_M_DRIVE; -M[BOOT_CSR >> 1] = rl_dib.ba & DMASK; +M[BOOT_CSR >> 1] = rl_dib.ba & 0177777; saved_PC = BOOT_ENTRY; return SCPE_OK; } @@ -722,4 +1207,3 @@ return SCPE_NOFNC; } #endif - diff --git a/PDP11/pdp11_rq.c b/PDP11/pdp11_rq.c index e0c54727..c7b8cc70 100644 --- a/PDP11/pdp11_rq.c +++ b/PDP11/pdp11_rq.c @@ -850,14 +850,14 @@ MTAB rq_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 }, #else { MTAB_XTD|MTAB_VDV, 004, "ADDRESS", NULL, NULL, &show_addr, NULL }, #endif { MTAB_XTD|MTAB_VDV, 0, "VECTOR", NULL, NULL, &show_vec, NULL }, - { MTAB_XTD | MTAB_VDV, 0, NULL, "AUTOCONFIGURE", - &set_addr_flt, NULL, NULL }, { 0 } }; diff --git a/PDP11/pdp11_rx.c b/PDP11/pdp11_rx.c index bba47ec4..67335d22 100644 --- a/PDP11/pdp11_rx.c +++ b/PDP11/pdp11_rx.c @@ -130,7 +130,7 @@ 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); +void rx_done (int esr_flags, int new_ecode); /* RX11 data structures @@ -179,12 +179,19 @@ REG rx_reg[] = { 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, "VECTOR", "VECTOR", - &set_vec, &show_vec, 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 } }; diff --git a/PDP11/pdp11_ry.c b/PDP11/pdp11_ry.c index 5d69ae0f..7310cf80 100644 --- a/PDP11/pdp11_ry.c +++ b/PDP11/pdp11_ry.c @@ -161,7 +161,7 @@ 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); +void ry_done (int esr_flags, int new_ecode); t_stat ry_set_size (UNIT *uptr, int32 val, char *cptr, void *desc); t_stat ry_attach (UNIT *uptr, char *cptr); @@ -223,13 +223,18 @@ MTAB ry_mod[] = { { 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, "VECTOR", "VECTOR", - &set_vec, &show_vec, NULL }, -#if defined (VM_PDP11) { 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 } }; diff --git a/PDP11/pdp11_tq.c b/PDP11/pdp11_tq.c index 2fbf5ed9..b993f349 100644 --- a/PDP11/pdp11_tq.c +++ b/PDP11/pdp11_tq.c @@ -27,6 +27,7 @@ 23-Jan-12 MP Added missing support for Logical EOT detection while positioning. + 17-Aug-11 RMS Added CAPACITY modifier 05-Mar-11 MP Added missing state for proper save/restore 01-Mar-11 MP - Migrated complex physical tape activities to sim_tape - adopted use of asynch I/O interfaces from sim_tape @@ -419,10 +420,10 @@ DIB tq_dib = { }; UNIT tq_unit[] = { - { UDATA (&tq_svc, UNIT_IDLE|UNIT_ATTABLE|UNIT_DISABLE|UNIT_ROABLE, 0), INIT_CAP }, - { UDATA (&tq_svc, UNIT_IDLE|UNIT_ATTABLE|UNIT_DISABLE|UNIT_ROABLE, 0), INIT_CAP }, - { UDATA (&tq_svc, UNIT_IDLE|UNIT_ATTABLE|UNIT_DISABLE|UNIT_ROABLE, 0), INIT_CAP }, - { UDATA (&tq_svc, UNIT_IDLE|UNIT_ATTABLE|UNIT_DISABLE|UNIT_ROABLE, 0), 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_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) } }; @@ -499,9 +500,13 @@ MTAB tq_mod[] = { 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 }, diff --git a/VAX/vax780_bug_history.txt b/VAX/vax780_bug_history.txt index a8f4aa32..ff6a7e31 100644 --- a/VAX/vax780_bug_history.txt +++ b/VAX/vax780_bug_history.txt @@ -56,6 +56,11 @@ Bugs Found And Fixed During Simulator Debug 53. MTPR SBR/PCBB/SCBB: 11/780 only checks that bits<1:0> == 0. 54. MTPR xLR: 11/780 excludes bits<31:24> from mbz test. 55. MTPR PxBR: 11/780 only checks bits<31,1:0> == 1,00. +56. EMODx: integer overflow case requiring left shift returns wrong result. +57. BPT, XFC: not clearing PSL before taking exception. +58. POLYx: add step require truncation (proved by AXE tests). + + diff --git a/VAX/vax780_syslist.c b/VAX/vax780_syslist.c index 71140c05..d35eb932 100644 --- a/VAX/vax780_syslist.c +++ b/VAX/vax780_syslist.c @@ -1,4 +1,4 @@ -/* vax_syslist.c: VAX device list +/* vax780_syslist.c: VAX 780 device list Copyright (c) 1998-2008, Robert M Supnik diff --git a/VAX/vax_cpu.c b/VAX/vax_cpu.c index af9f1c5c..e38f7efa 100644 --- a/VAX/vax_cpu.c +++ b/VAX/vax_cpu.c @@ -35,6 +35,8 @@ approach taken in the other BSD derived OSes. Determining a reasonable idle detection pattern does not seem possible for these versions. + 13-Sep-11 RMS Fixed XFC, BPT to clear PSL before exception + (found by Camiel Vanderhoeven) 23-Mar-11 RMS Revised for new idle design (from Mark Pizzolato) 05-Jan-11 MP Added Asynch I/O support 24-Apr-10 RMS Added OLDVMS idle timer option @@ -1585,7 +1587,7 @@ for ( ;; ) { case TSTL: CC_IIZZ_L (op0); /* set cc's */ - if ((cc == CC_Z) && + if ((cc == CC_Z) && /* zero result and */ ((((cpu_idle_mask & VAX_IDLE_ULTOLD) && /* running Old Ultrix or friends? */ (PSL_GETIPL (PSL) == 0x1)) || /* at IPL 1? */ ((cpu_idle_mask & VAX_IDLE_QUAD) && /* running Quasijarus or friends? */ @@ -2553,12 +2555,14 @@ for ( ;; ) { case BPT: SETPC (fault_PC); + PSL = PSL & ~PSL_TP; /* clear */ cc = intexc (SCB_BPT, cc, 0, IE_EXC); GET_CUR; break; case XFC: SETPC (fault_PC); + PSL = PSL & ~PSL_TP; /* clear */ cc = intexc (SCB_XFC, cc, 0, IE_EXC); GET_CUR; break; diff --git a/VAX/vax_cpu1.c b/VAX/vax_cpu1.c index 8eeac8d9..ccd0ae34 100644 --- a/VAX/vax_cpu1.c +++ b/VAX/vax_cpu1.c @@ -1,6 +1,6 @@ /* vax_cpu1.c: VAX complex instructions - Copyright (c) 1998-2011, Robert M Supnik + Copyright (c) 1998-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"), @@ -23,6 +23,7 @@ used in advertising or otherwise to promote the sale, use or other dealings in this Software without prior written authorization from Robert M Supnik. + 15-Mar-12 RMS Fixed potential integer overflow in LDPCTX (from Mark Pizzolato) 25-Nov-11 RMS Added VEC_QBUS test in interrupt handler 23-Mar-11 RMS Revised idle design (from Mark Pizzolato) 28-May-08 RMS Inlined physical memory routines @@ -1137,7 +1138,7 @@ else { SP = KSP; /* new stack */ } } -if (ei == IE_INT) { /* if int, new IPL */ +if (ei > 0) { /* if int, new IPL */ int32 newipl; if (VEC_QBUS && ((vec & VEC_Q) != 0)) /* Qbus and Qbus vector? */ newipl = PSL_IPL17; /* force IPL 17 */ @@ -1274,7 +1275,7 @@ return newpsl & CC_MASK; /* set new cc */ void op_ldpctx (int32 acc) { -int32 newpc, newpsl, pcbpa, t; +uint32 newpc, newpsl, pcbpa, t; if (PSL & PSL_CUR) /* must be kernel */ RSVD_INST_FAULT; diff --git a/VAX/vax_defs.h b/VAX/vax_defs.h index 964736c3..608f8662 100644 --- a/VAX/vax_defs.h +++ b/VAX/vax_defs.h @@ -1,6 +1,6 @@ /* vax_defs.h: VAX architecture definitions file - Copyright (c) 1998-2008, Robert M Supnik + Copyright (c) 1998-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"), @@ -26,6 +26,7 @@ The author gratefully acknowledges the help of Stephen Shirron, Antonio Carlini, and Kevin Peterson in providing specifications for the Qbus VAX's + 05-Nov-11 RMS Added PSL_IPL17 definition 09-May-06 RMS Added system PTE ACV error code 03-May-06 RMS Added EDITPC get/put cc's macros 03-Nov-05 RMS Added 780 stop codes diff --git a/VAX/vax_fpa.c b/VAX/vax_fpa.c index 9a88bb57..222e52f0 100644 --- a/VAX/vax_fpa.c +++ b/VAX/vax_fpa.c @@ -1,6 +1,6 @@ /* vax_fpa.c - VAX f_, d_, g_floating instructions - Copyright (c) 1998-2008, Robert M Supnik + Copyright (c) 1998-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"), @@ -23,6 +23,9 @@ 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-11 RMS Fixed integer overflow bug in EMODx + Fixed POLYx normalizing before add mask bug + (both from Camiel Vanderhoeven) 28-May-08 RMS Inlined physical memory routines 16-May-06 RMS Fixed bug in 32b floating multiply routine Fixed bug in 64b extended modulus routine @@ -103,7 +106,7 @@ void unpackg (int32 hi, int32 lo, UFP *a); void norm (UFP *a); int32 rpackfd (UFP *a, int32 *rh); int32 rpackg (UFP *a, int32 *rh); -void vax_fadd (UFP *a, UFP *b); +void vax_fadd (UFP *a, UFP *b, uint32 mhi, uint32 mlo); void vax_fmul (UFP *a, UFP *b, t_bool qd, int32 bias, uint32 mhi, uint32 mlo); void vax_fdiv (UFP *b, UFP *a, int32 prec, int32 bias); void vax_fmod (UFP *a, int32 bias, int32 *intgr, int32 *flg); @@ -347,10 +350,11 @@ return rpackg (&a, flo); /* return frac */ /* Unpacked floating point routines */ -void vax_fadd (UFP *a, UFP *b) +void vax_fadd (UFP *a, UFP *b, uint32 mhi, uint32 mlo) { int32 ediff; UFP t; +t_uint64 mask = (((t_uint64) mhi) << 32) | ((t_uint64) mlo); if (a->frac == 0) { /* s1 = 0? */ *a = *b; @@ -374,6 +378,7 @@ if (a->sign ^ b->sign) { /* eff sub? */ a->frac = a->frac + b->frac; /* add frac */ } else a->frac = a->frac - b->frac; /* sub frac */ + a->frac = a->frac & ~mask; /* mask before norm */ norm (a); /* normalize */ } else { @@ -386,6 +391,7 @@ else { a->frac = UF_NM | (a->frac >> 1); /* shift in carry */ a->exp = a->exp + 1; /* skip norm */ } + a->frac = a->frac & ~mask; /* mask */ } return; } @@ -454,7 +460,11 @@ else if (a->exp <= (bias + 64)) { /* in range [1,64]? */ a->exp = bias; } else { - *intgr = 0; /* out of range */ + if (a->exp < (bias + 96)) /* need left shift? */ + *intgr = (int32) (a->frac << (a->exp - bias - 64)); + else *intgr = 0; /* out of range */ + if (a->sign) + *intgr = -*intgr; a->frac = a->sign = a->exp = 0; /* result 0 */ *flg = CC_V; /* overflow */ } @@ -639,7 +649,7 @@ void unpackg (uint32 hi, uint32 lo, UFP *a); void norm (UFP *a); int32 rpackfd (UFP *a, int32 *rh); int32 rpackg (UFP *a, int32 *rh); -void vax_fadd (UFP *a, UFP *b); +void vax_fadd (UFP *a, UFP *b, uint32 mhi, uint32 mlo); void vax_fmul (UFP *a, UFP *b, t_bool qd, int32 bias, uint32 mhi, uint32 mlo); void vax_fmod (UFP *a, int32 bias, int32 *intgr, int32 *flg); void vax_fdiv (UFP *b, UFP *a, int32 prec, int32 bias); @@ -921,6 +931,8 @@ if (a->sign ^ b->sign) { /* eff sub? */ dp_add (&a->frac, &b->frac); /* "add" frac */ } else dp_sub (&a->frac, &b->frac); /* a >= b */ + a->frac.hi = a->frac.hi & ~mhi; /* mask before norm */ + a->frac.lo = a->frac.lo & ~mlo; norm (a); /* normalize */ } else { @@ -932,6 +944,8 @@ else { a->frac.hi = a->frac.hi | UF_NM_H; /* add norm bit */ a->exp = a->exp + 1; /* skip norm */ } + a->frac.hi = a->frac.hi & ~mhi; /* mask */ + a->frac.lo = a->frac.lo & ~mlo; } return; } @@ -1004,7 +1018,14 @@ else if (a->exp <= (bias + 64)) { /* in range [1,64]? */ a->exp = bias; } else { - *intgr = 0; /* out of range */ + if (a->exp < (bias + 96)) { /* need left shift? */ + ifr = a->frac; + dp_lsh (&ifr, a->exp - bias - 64); + *intgr = ifr.lo; + } + else *intgr = 0; /* out of range */ + if (a->sign) + *intgr = -*intgr; a->frac.hi = a->frac.lo = a->sign = a->exp = 0; /* result 0 */ *flg = CC_V; /* overflow */ } @@ -1379,7 +1400,7 @@ unpackf (opnd[0], &a); /* F format */ unpackf (opnd[1], &b); if (sub) /* sub? -s1 */ a.sign = a.sign ^ FPSIGN; -vax_fadd (&a, &b); /* add fractions */ +vax_fadd (&a, &b, 0, 0); /* add fractions */ return rpackfd (&a, NULL); } @@ -1391,7 +1412,7 @@ unpackd (opnd[0], opnd[1], &a); unpackd (opnd[2], opnd[3], &b); if (sub) /* sub? -s1 */ a.sign = a.sign ^ FPSIGN; -vax_fadd (&a, &b); /* add fractions */ +vax_fadd (&a, &b, 0, 0); /* add fractions */ return rpackfd (&a, rh); } @@ -1403,7 +1424,7 @@ unpackg (opnd[0], opnd[1], &a); unpackg (opnd[2], opnd[3], &b); if (sub) /* sub? -s1 */ a.sign = a.sign ^ FPSIGN; -vax_fadd (&a, &b); /* add fractions */ +vax_fadd (&a, &b, 0, 0); /* add fractions */ return rpackg (&a, rh); /* round and pack */ } @@ -1499,7 +1520,7 @@ for (i = 0; i < deg; i++) { /* loop */ wd = Read (ptr, L_LONG, RD); /* get Cnext */ ptr = ptr + 4; unpackf (wd, &c); /* unpack Cnext */ - vax_fadd (&r, &c); /* r = r + Cnext */ + vax_fadd (&r, &c, 1, LMASK); /* r = r + Cnext */ res = rpackfd (&r, NULL); /* round and pack */ } R[0] = res; @@ -1530,7 +1551,7 @@ for (i = 0; i < deg; i++) { /* loop */ wd1 = Read (ptr + 4, L_LONG, RD); ptr = ptr + 8; unpackd (wd, wd1, &c); /* unpack Cnext */ - vax_fadd (&r, &c); /* r = r + Cnext */ + vax_fadd (&r, &c, 0, 1); /* r = r + Cnext */ res = rpackfd (&r, &resh); /* round and pack */ } R[0] = res; @@ -1564,7 +1585,7 @@ for (i = 0; i < deg; i++) { /* loop */ wd1 = Read (ptr + 4, L_LONG, RD); ptr = ptr + 8; unpackg (wd, wd1, &c); /* unpack Cnext */ - vax_fadd (&r, &c); /* r = r + Cnext */ + vax_fadd (&r, &c, 0, 1); /* r = r + Cnext */ res = rpackg (&r, &resh); /* round and pack */ } R[0] = res; diff --git a/VAX/vax_octa.c b/VAX/vax_octa.c index 5b0448da..b4e0fd3e 100644 --- a/VAX/vax_octa.c +++ b/VAX/vax_octa.c @@ -1,6 +1,6 @@ /* vax_octa.c - VAX octaword and h_floating instructions - Copyright (c) 2004-2008, Robert M Supnik + Copyright (c) 2004-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"), @@ -25,6 +25,9 @@ This module simulates the VAX h_floating instruction set. + 15-Sep-11 RMS Fixed integer overflow bug in EMODH + Fixed POLYH normalizing before add mask bug + (both from Camiel Vanderhoeven) 28-May-08 RMS Inlined physical memory routines 10-May-06 RMS Fixed bug in reported VA on faulting cross-page write 03-May-06 RMS Fixed MNEGH to test negated sign, clear C @@ -93,7 +96,7 @@ void h_write_w (int32 spec, int32 va, int32 val, int32 acc); void h_write_l (int32 spec, int32 va, int32 val, int32 acc); void h_write_q (int32 spec, int32 va, int32 vl, int32 vh, int32 acc); void h_write_o (int32 spec, int32 va, int32 *val, int32 acc); -void vax_hadd (UFPH *a, UFPH *b); +void vax_hadd (UFPH *a, UFPH *b, uint32 mlo); void vax_hmul (UFPH *a, UFPH *b, uint32 mlo); void vax_hmod (UFPH *a, int32 *intgr, int32 *flg); void vax_hdiv (UFPH *a, UFPH *b); @@ -581,7 +584,7 @@ h_unpackh (&opnd[0], &a); /* unpack s1, s2 */ h_unpackh (&opnd[4], &b); if (sub) /* sub? -s1 */ a.sign = a.sign ^ FPSIGN; -vax_hadd (&a, &b); /* do add */ +vax_hadd (&a, &b, 0); /* do add */ return h_rpackh (&a, hflt); /* round and pack */ } @@ -643,7 +646,7 @@ for (i = 0; i < deg; i++) { /* loop */ wd[3] = Read (ptr + 12, L_LONG, RD); ptr = ptr + 16; h_unpackh (wd, &c); /* unpack Cnext */ - vax_hadd (&r, &c); /* r = r + Cnext */ + vax_hadd (&r, &c, 1); /* r = r + Cnext */ h_rpackh (&r, res); /* round and pack */ } R[0] = res[0]; /* result */ @@ -678,7 +681,7 @@ return h_rpackh (&a, hflt); /* round and pack frac * /* Floating add */ -void vax_hadd (UFPH *a, UFPH *b) +void vax_hadd (UFPH *a, UFPH *b, uint32 mlo) { int32 ediff; UFPH t; @@ -703,6 +706,7 @@ if (a->sign ^ b->sign) { /* eff sub? */ if (ediff) /* denormalize */ qp_rsh_s (&b->frac, ediff, 1); qp_add (&a->frac, &b->frac); /* "add" frac */ + a->frac.f0 = a->frac.f0 & ~mlo; /* mask before norm */ h_normh (a); /* normalize */ } else { @@ -713,6 +717,7 @@ else { a->frac.f3 = a->frac.f3 | UH_NM_H; /* add norm bit */ a->exp = a->exp + 1; /* incr exp */ } + a->frac.f0 = a->frac.f0 & ~mlo; /* mask */ } return; } @@ -778,7 +783,14 @@ else if (a->exp <= (H_BIAS + 128)) { /* in range? */ a->exp = H_BIAS; } else { - *intgr = 0; /* out of range */ + if (a->exp < (H_BIAS + 160)) { /* left shift needed? */ + ifr = a->frac; + qp_lsh (&ifr, a->exp - H_BIAS - 128); + *intgr = ifr.f0; + } + else *intgr = 0; /* out of range */ + if (a->sign) + *intgr = -*intgr; a->frac.f0 = a->frac.f1 = 0; /* result 0 */ a->frac.f2 = a->frac.f3 = 0; a->sign = a->exp = 0; diff --git a/VAX/vax_syslist.c b/VAX/vax_syslist.c index f2e4eefe..aba7119c 100644 --- a/VAX/vax_syslist.c +++ b/VAX/vax_syslist.c @@ -1,4 +1,4 @@ -/* vax_sys.c: VAX simulator interface +/* vax_syslist.c: VAX device list Copyright (c) 1998-2008, Robert M Supnik diff --git a/Visual Studio Projects/AltairZ80.vcproj b/Visual Studio Projects/AltairZ80.vcproj index b910589a..9125307d 100644 --- a/Visual Studio Projects/AltairZ80.vcproj +++ b/Visual Studio Projects/AltairZ80.vcproj @@ -237,10 +237,6 @@ RelativePath="..\AltairZ80\i86_prim_ops.c" > - - diff --git a/alpha/alpha_500au_syslist.c b/alpha/alpha_500au_syslist.c new file mode 100644 index 00000000..5acdc997 --- /dev/null +++ b/alpha/alpha_500au_syslist.c @@ -0,0 +1,49 @@ +/* alpha_500au_syslist.c: Alpha device list for 500au + + Copyright (c) 2003-2006, Robert M Supnik + + Permission is hereby granted, free of charge, to any person obtaining a + copy of this software and associated documentation files (the "Software"), + to deal in the Software without restriction, including without limitation + the rights to use, copy, modify, merge, publish, distribute, sublicense, + and/or sell copies of the Software, and to permit persons to whom the + Software is furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + ROBERT M SUPNIK BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + Except as contained in this notice, the name of Robert M Supnik shall not be + used in advertising or otherwise to promote the sale, use or other dealings + in this Software without prior written authorization from Robert M Supnik. +*/ + +#include "alpha_defs.h" + +extern DEVICE cpu_dev; +extern DEVICE tlb_dev; +extern DEVICE ev5pal_dev; +extern DEVICE rom_dev; + +/* SCP data structures and interface routines + + sim_name simulator name + sim_devices array of pointers to simulated devices +*/ + +char sim_name[] = "Alpha"; + +DEVICE *sim_devices[] = { + &cpu_dev, + &tlb_dev, + &ev5pal_dev, + &rom_dev, + NULL + }; + diff --git a/alpha/alpha_cpu.c b/alpha/alpha_cpu.c new file mode 100644 index 00000000..7cacf0ea --- /dev/null +++ b/alpha/alpha_cpu.c @@ -0,0 +1,1865 @@ +/* alpha_cpu.c: Alpha CPU simulator + + Copyright (c) 2003-2006, 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. + + Alpha architecturally-defined CPU state: + + PC<63:0> program counter + R[0:31]<63:0> integer registers + F[0:31]<63:0> floating registers + FPCR<63:0> floating point control register + (only left 32b are implemented) + PCC<63:0> hardware cycle counter + trap_summ<6:0> arithmetic trap summary + trap_mask<63:0> arithmetic trap register mask + lock_flag load_locked flag + vax_flag<0> VAX compatibility interrupt flag + FEN<0> floating point enable flag + + The Alpha CPU privileged state is "soft" and varies significantly from + operating system to operating system. Alpha provides an intermediate layer + of software (called PALcode) that implements the privileged state as well + as a library of complex instruction functions. PALcode implementations + are chip specific and system specific, as well as OS specific. + + Alpha memory management is also "soft" and supported a variety of mapping + schemes. VMS and Unix use a three level page table and directly expose + the underlying 64b hardware PTE. NT uses a condensed 32b PTE. + + All Alpha instructions are 32b wide. There are five basic formats: PALcall, + branch, memory reference, integer operate, and floating operate. + + 3 3 2 2 2 2 2 2 2 2 2 2 1 1 1 1 1 1 1 1 1 1 + 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | | | + | opcode | PAL function | PAL + | | | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + + 3 3 2 2 2 2 2 2 2 2 2 2 1 1 1 1 1 1 1 1 1 1 + 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | | | | + | opcode | Ra | branch displacement | branch + | | | | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + + 3 3 2 2 2 2 2 2 2 2 2 2 1 1 1 1 1 1 1 1 1 1 + 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | | | | | + | opcode | Ra | Rb | address displacement | memory + | | | | | reference + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + + 3 3 2 2 2 2 2 2 2 2 2 2 1 1 1 1 1 1 1 1 1 1 + 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | | | | | | | | + | opcode | Ra | Rb |0 0 0|0| function | Rc | integer + | | | | | | | | operate + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | | | + | literal |1| + | | | + +-+-+-+-+-+-+-+-+-+ + + 3 3 2 2 2 2 2 2 2 2 2 2 1 1 1 1 1 1 1 1 1 1 + 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | | | | | | | | + | opcode | Ra | Rb | trap|rnd| function | Rc | floating + | | | | | | | | operate + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + + Memory reference format is also used for some two-operand operates; + the address displacement is the function code. + + This routine is the instruction decode routine for the Alpha. 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. Traps and interrupts. Variable trap_summ summarizes the outstanding + trap requests (if any). Variable intr_summ summarizes the outstanding + interrupt requests (if any). + + 2. Interrupt requests are maintained in the int_req array, one word per + interrupt level, one bit per device. + + 3. Adding I/O devices. These modules must be modified: + + alpha_defs.h add device address and interrupt definitions + alpha_sys.c add sim_devices table entry +*/ + +#include "alpha_defs.h" + +#define UNIT_V_CONH (UNIT_V_UF + 0) /* halt to console */ +#define UNIT_V_MSIZE (UNIT_V_UF + 1) +#define UNIT_CONH (1 << UNIT_V_CONH) +#define UNIT_MSIZE (1 << UNIT_V_MSIZE) + +#define HIST_PC 0x2 +#define HIST_MIN 64 +#define HIST_MAX (1 << 18) + +typedef struct { + t_uint64 pc; + uint32 ir; + uint32 filler; + t_uint64 ra; + t_uint64 rb; + } InstHistory; + +#define H_A 0x01 +#define H_B 0x02 +#define H_B_LIT 0x04 +#define H_EA 0x08 +#define H_EA_B 0x10 +#define H_EA_L16 0x20 +#define H_MRF (H_A|H_B|H_EA) +#define H_BRA (H_A|H_EA|H_EA_B) +#define H_IOP (H_A|H_B|H_B_LIT) +#define H_FOP (H_A|H_B) +#define H_PAL (H_A|H_EA|H_EA_L16) +#define H_JMP (H_A|H_B|H_EA|H_EA_L16) + +t_uint64 *M = 0; /* memory */ +t_uint64 R[32]; /* integer reg */ +t_uint64 FR[32]; /* floating reg */ +t_uint64 PC; /* PC, <1:0> MBZ */ +uint32 pc_align = 0; /* PC<1:0> */ +t_uint64 trap_mask = 0; /* trap reg mask */ +uint32 trap_summ = 0; /* trap summary */ +uint32 fpcr = 0; /* fp ctrl reg */ +uint32 pcc_l = 0; /* rpcc high */ +uint32 pcc_h = 0; /* rpcc low */ +uint32 pcc_enb = 0; +uint32 arch_mask = AMASK_BWX | AMASK_PRC; /* arch mask */ +uint32 impl_ver = IMPLV_EV5; /* impl version */ +uint32 lock_flag = 0; /* load lock flag */ +uint32 vax_flag = 0; /* vax intr flag */ +uint32 intr_summ = 0; /* interrupt summary */ +uint32 pal_mode = 1; /* PAL mode */ +uint32 pal_type = PAL_UNDF; /* PAL type */ +uint32 dmapen = 0; /* data mapping enable */ +uint32 fpen = 0; /* flt point enabled */ +uint32 ir = 0; /* instruction register */ +t_uint64 p1 = 0; /* exception parameter */ +uint32 int_req[IPL_HLVL] = { 0 }; /* interrupt requests */ +REG *pcq_r = NULL; /* PC queue reg ptr */ +t_uint64 pcq[PCQ_SIZE] = { 0 }; /* PC queue */ +int32 pcq_p = 0; /* PC queue ptr */ +uint32 cpu_astop = 0; +uint32 hst_p = 0; /* history pointer */ +uint32 hst_lnt = 0; /* history length */ +InstHistory *hst = NULL; /* instruction history */ +jmp_buf save_env; + +const t_uint64 byte_mask[8] = { + 0x00000000000000FF, 0x000000000000FF00, + 0x0000000000FF0000, 0x00000000FF000000, + 0x000000FF00000000, 0x0000FF0000000000, + 0x00FF000000000000, 0xFF00000000000000 + }; + +const t_uint64 word_mask[4] = { + 0x000000000000FFFF, 0x00000000FFFF0000, + 0x0000FFFF00000000, 0xFFFF000000000000 + }; + +extern int32 sim_interval; +extern int32 sim_int_char; +extern FILE *sim_deb; +extern uint32 sim_brk_types, sim_brk_dflt, sim_brk_summ; /* breakpoint info */ + +t_uint64 uemul64 (t_uint64 a, t_uint64 b, t_uint64 *hi); +t_uint64 byte_zap (t_uint64 op, uint32 mask); +t_stat cpu_reset (DEVICE *dptr); +t_stat cpu_boot (int32 unitno, DEVICE *dptr); +t_stat cpu_ex (t_value *vptr, t_addr exta, UNIT *uptr, int32 sw); +t_stat cpu_dep (t_value val, t_addr exta, UNIT *uptr, int32 sw); +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_virt (FILE *of, UNIT *uptr, int32 val, void *desc); +t_stat cpu_fprint_one_inst (FILE *st, uint32 ir, t_uint64 pc, t_uint64 ra, t_uint64 rb); + +extern t_uint64 op_ldf (t_uint64 op); +extern t_uint64 op_ldg (t_uint64 op); +extern t_uint64 op_lds (t_uint64 op); +extern t_uint64 op_stf (t_uint64 op); +extern t_uint64 op_stg (t_uint64 op); +extern t_uint64 op_sts (t_uint64 op); +extern t_uint64 vax_sqrt (uint32 ir, t_bool dp); +extern t_uint64 ieee_sqrt (uint32 ir, t_bool dp); +extern void vax_fop (uint32 ir); +extern void ieee_fop (uint32 ir); +extern t_stat pal_19 (uint32 ir); +extern t_stat pal_1b (uint32 ir); +extern t_stat pal_1d (uint32 ir); +extern t_stat pal_1e (uint32 ir); +extern t_stat pal_1f (uint32 ir); +extern t_uint64 trans_c (t_uint64 va); +extern t_stat cpu_show_tlb (FILE *of, UNIT *uptr, int32 val, void *desc); +extern t_stat pal_eval_intr (uint32 flag); +extern t_stat pal_proc_excp (uint32 type); +extern t_stat pal_proc_trap (uint32 type); +extern t_stat pal_proc_intr (uint32 type); +extern t_stat pal_proc_inst (uint32 fnc); +extern uint32 tlb_set_cm (int32 cm); + +/* 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, INITMEMSIZE) }; + +REG cpu_reg[] = { + { HRDATA (PC, PC, 64), PV_LEFT }, + { HRDATA (PCALG, pc_align, 3) }, + { HRDATA (R0, R[0], 64) }, + { HRDATA (R1, R[1], 64) }, + { HRDATA (R2, R[2], 64) }, + { HRDATA (R3, R[3], 64) }, + { HRDATA (R4, R[4], 64) }, + { HRDATA (R5, R[5], 64) }, + { HRDATA (R6, R[6], 64) }, + { HRDATA (R7, R[7], 64) }, + { HRDATA (R8, R[8], 64) }, + { HRDATA (R9, R[9], 64) }, + { HRDATA (R10, R[10], 64) }, + { HRDATA (R11, R[11], 64) }, + { HRDATA (R12, R[12], 64) }, + { HRDATA (R13, R[13], 64) }, + { HRDATA (R14, R[14], 64) }, + { HRDATA (R15, R[15], 64) }, + { HRDATA (R16, R[16], 64) }, + { HRDATA (R17, R[17], 64) }, + { HRDATA (R18, R[18], 64) }, + { HRDATA (R19, R[19], 64) }, + { HRDATA (R20, R[20], 64) }, + { HRDATA (R21, R[21], 64) }, + { HRDATA (R22, R[22], 64) }, + { HRDATA (R23, R[23], 64) }, + { HRDATA (R24, R[24], 64) }, + { HRDATA (R25, R[25], 64) }, + { HRDATA (R26, R[26], 64) }, + { HRDATA (R27, R[27], 64) }, + { HRDATA (R28, R[28], 64) }, + { HRDATA (R29, R[29], 64) }, + { HRDATA (R30, R[30], 64) }, + { HRDATA (R31, R[31], 64), REG_RO }, + { HRDATA (F0, FR[0], 64) }, + { HRDATA (F1, FR[1], 64) }, + { HRDATA (F2, FR[2], 64) }, + { HRDATA (F3, FR[3], 64) }, + { HRDATA (F4, FR[4], 64) }, + { HRDATA (F5, FR[5], 64) }, + { HRDATA (F6, FR[6], 64) }, + { HRDATA (F7, FR[7], 64) }, + { HRDATA (F8, FR[8], 64) }, + { HRDATA (F9, FR[9], 64) }, + { HRDATA (F10, FR[10], 64) }, + { HRDATA (F11, FR[11], 64) }, + { HRDATA (F12, FR[12], 64) }, + { HRDATA (F13, FR[13], 64) }, + { HRDATA (F14, FR[14], 64) }, + { HRDATA (F15, FR[15], 64) }, + { HRDATA (F16, FR[16], 64) }, + { HRDATA (F17, FR[17], 64) }, + { HRDATA (F18, FR[18], 64) }, + { HRDATA (F19, FR[19], 64) }, + { HRDATA (F20, FR[20], 64) }, + { HRDATA (F21, FR[21], 64) }, + { HRDATA (F22, FR[22], 64) }, + { HRDATA (F23, FR[23], 64) }, + { HRDATA (F24, FR[24], 64) }, + { HRDATA (F25, FR[25], 64) }, + { HRDATA (F26, FR[26], 64) }, + { HRDATA (F27, FR[27], 64) }, + { HRDATA (F28, FR[28], 64) }, + { HRDATA (F29, FR[29], 64) }, + { HRDATA (F30, FR[30], 64) }, + { HRDATA (F31, FR[31], 64), REG_RO }, + { HRDATA (FPCR, fpcr, 32) }, + { FLDATA (FEN, fpen, 0) }, + { HRDATA (TRAPS, trap_summ, 8) }, + { HRDATA (TRAPM, trap_mask, 64) }, + { HRDATA (PCCH, pcc_h, 32) }, + { HRDATA (PCCL, pcc_l, 32) }, + { FLDATA (LOCK, lock_flag, 0) }, + { FLDATA (VAXF, vax_flag, 0) }, + { FLDATA (PALMODE, pal_mode, 0) }, + { HRDATA (PALTYPE, pal_type, 2), REG_HRO }, + { HRDATA (DMAPEN, dmapen, 0) }, + { HRDATA (AMASK, arch_mask, 13), REG_RO }, + { HRDATA (IMPLV, impl_ver, 2), REG_RO }, + { BRDATA (PCQ, pcq, 16, 32, PCQ_SIZE), REG_RO+REG_CIRC }, + { HRDATA (PCQP, pcq_p, 6), REG_HRO }, + { HRDATA (WRU, sim_int_char, 8) }, + { NULL } + }; + +MTAB cpu_mod[] = { + { UNIT_MSIZE, (1u << 25), NULL, "32M", &cpu_set_size }, + { UNIT_MSIZE, (1u << 26), NULL, "64M", &cpu_set_size }, + { UNIT_MSIZE, (1u << 27), NULL, "128M", &cpu_set_size }, + { UNIT_MSIZE, (1u << 28), NULL, "256M", &cpu_set_size }, + { UNIT_MSIZE, (1u << 29), NULL, "512M", &cpu_set_size }, + { UNIT_CONH, 0, "HALT to SIMH", "SIMHALT", NULL }, + { UNIT_CONH, UNIT_CONH, "HALT to console", "CONHALT", NULL }, + { MTAB_XTD|MTAB_VDV|MTAB_NMO|MTAB_SHP, 0, "VIRTUAL", NULL, + NULL, &cpu_show_virt }, + { MTAB_XTD|MTAB_VDV|MTAB_NMO|MTAB_SHP, 0, "ITLB", NULL, + NULL, &cpu_show_tlb }, + { MTAB_XTD|MTAB_VDV|MTAB_NMO|MTAB_SHP, 1, "DTLB", NULL, + NULL, &cpu_show_tlb }, + { 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, 48, 8, 16, 64, + &cpu_ex, &cpu_dep, &cpu_reset, + &cpu_boot, NULL, NULL, + NULL, DEV_DYNM|DEV_DEBUG, 0, + NULL, &cpu_set_size, NULL + }; + +t_stat sim_instr (void) +{ +t_stat reason; +int abortval; +t_bool tracing; + +PC = PC | pc_align; /* put PC together */ +abortval = setjmp (save_env); /* set abort hdlr */ +if (abortval != 0) { /* exception? */ + if (abortval < 0) { /* SCP stop? */ + pcc_l = pcc_l & M32; + pcq_r->qptr = pcq_p; /* update pc q ptr */ + pc_align = ((uint32) PC) & 3; /* separate PC<1:0> */ + PC = PC & 0xFFFFFFFFFFFFFFFC; + return -abortval; + } + reason = pal_proc_excp (abortval); /* pal processing */ + } +else reason = 0; +tlb_set_cm (-1); /* resync cm */ +tracing = ((hst_lnt != 0) || DEBUG_PRS (cpu_dev)); + +intr_summ = pal_eval_intr (1); /* eval interrupts */ + +/* Main instruction loop */ + +while (reason == 0) { + + int32 i; + uint32 op, ra, rb, rc, fnc, sc, s32, t32, sgn; + t_int64 s1, s2, sr; + t_uint64 ea, dsp, rbv, res, s64, t64; + + if (cpu_astop) { /* debug stop? */ + cpu_astop = 0; /* clear */ + reason = SCPE_STOP; /* stop simulation */ + break; + } + + if (sim_interval <= 0) { /* chk clock queue */ + if (reason = sim_process_event ()) break; + intr_summ = pal_eval_intr (1); /* eval interrupts */ + } + + if (intr_summ && !pal_mode) { /* interrupt pending? */ + reason = pal_proc_intr (intr_summ); /* pal processing */ + intr_summ = pal_eval_intr (1); /* eval interrupts */ + continue; + } + + if (sim_brk_summ && sim_brk_test (PC, SWMASK ('E'))) { /* breakpoint? */ + reason = STOP_IBKPT; /* stop simulation */ + break; + } + + sim_interval = sim_interval - 1; /* count instr */ + pcc_l = pcc_l + pcc_enb; + ir = ReadI (PC); /* get instruction */ + op = I_GETOP (ir); /* get opcode */ + ra = I_GETRA (ir); /* get ra */ + rb = I_GETRB (ir); /* get rb */ + + if (tracing) { /* trace or history? */ + if (hst_lnt) { /* history enabled? */ + hst_p = (hst_p + 1); /* next entry */ + if (hst_p >= hst_lnt) hst_p = 0; + hst[hst_p].pc = PC | pc_align | HIST_PC; /* save PC */ + hst[hst_p].ir = ir; /* save ir */ + hst[hst_p].ra = R[ra]; /* save Ra */ + hst[hst_p].rb = R[rb]; /* save Rb */ + } + if (DEBUG_PRS (cpu_dev)) /* trace enabled? */ + cpu_fprint_one_inst (sim_deb, ir, PC | pc_align, R[ra], R[rb]); + } + + PC = (PC + 4) & M64; /* advance PC */ + switch (op) { + +/* Memory reference instructions */ + + case OP_LDA: /* LDA */ + if (ra != 31) { + dsp = I_GETMDSP (ir); + ea = (R[rb] + SEXT_MDSP (dsp)) & M64; + R[ra] = ea; + } + break; + + case OP_LDAH: /* LDAH */ + if (ra != 31) { + dsp = I_GETMDSP (ir) << 16; + ea = (R[rb] + SEXT_L_Q (dsp)) & M64; + R[ra] = ea; + } + break; + + case OP_LDBU: /* LDBU */ + if (!(arch_mask & AMASK_BWX)) ABORT (EXC_RSVI); /* EV56 or later */ + if (ra != 31) { + dsp = I_GETMDSP (ir); + ea = (R[rb] + SEXT_MDSP (dsp)) & M64; + R[ra] = ReadB (ea); + } + break; + + case OP_LDQ_U: /* LDQ_U */ + if (ra != 31) { + dsp = I_GETMDSP (ir); + ea = (R[rb] + SEXT_MDSP (dsp)) & M64; + R[ra] = ReadQ (ea & ~7); /* ignore ea<2:0> */ + } + break; + + case OP_LDWU: /* LDWU */ + if (!(arch_mask & AMASK_BWX)) ABORT (EXC_RSVI); /* EV56 or later */ + if (ra != 31) { + dsp = I_GETMDSP (ir); + ea = (R[rb] + SEXT_MDSP (dsp)) & M64; + R[ra] = ReadW (ea); + } + break; + + case OP_STW: /* STW */ + if (!(arch_mask & AMASK_BWX)) ABORT (EXC_RSVI); /* EV56 or later */ + dsp = I_GETMDSP (ir); + ea = (R[rb] + SEXT_MDSP (dsp)) & M64; + WriteW (ea, R[ra]); + break; + + case OP_STB: /* STB */ + if (!(arch_mask & AMASK_BWX)) ABORT (EXC_RSVI); /* EV56 or later */ + dsp = I_GETMDSP (ir); + ea = (R[rb] + SEXT_MDSP (dsp)) & M64; + WriteB (ea, R[ra]); + break; + + case OP_STQ_U: /* STQ_U */ + dsp = I_GETMDSP (ir); + ea = (R[rb] + SEXT_MDSP (dsp)) & M64; + WriteQ (ea & ~7, R[ra]); /* ignore ea<2:0> */ + break; + + case OP_LDF: /* LDF */ + if (fpen == 0) ABORT (EXC_FPDIS); /* flt point disabled? */ + if (ra != 31) { + dsp = I_GETMDSP (ir); + ea = (R[rb] + SEXT_MDSP (dsp)) & M64; + FR[ra] = op_ldf (ReadL (ea)); /* swizzle bits */ + } + break; + + case OP_LDG: /* LDG */ + if (fpen == 0) ABORT (EXC_FPDIS); /* flt point disabled? */ + if (ra != 31) { + dsp = I_GETMDSP (ir); + ea = (R[rb] + SEXT_MDSP (dsp)) & M64; + FR[ra] = op_ldg (ReadQ (ea)); /* swizzle bits */ + } + break; + + case OP_LDS: /* LDS */ + if (fpen == 0) ABORT (EXC_FPDIS); /* flt point disabled? */ + if (ra != 31) { + dsp = I_GETMDSP (ir); + ea = (R[rb] + SEXT_MDSP (dsp)) & M64; + FR[ra] = op_lds (ReadL (ea)); /* swizzle bits */ + } + break; + + case OP_LDT: /* LDT */ + if (fpen == 0) ABORT (EXC_FPDIS); /* flt point disabled? */ + if (ra != 31) { + dsp = I_GETMDSP (ir); + ea = (R[rb] + SEXT_MDSP (dsp)) & M64; + FR[ra] = ReadQ (ea); /* no swizzling needed */ + } + break; + + case OP_STF: /* STF */ + if (fpen == 0) ABORT (EXC_FPDIS); /* flt point disabled? */ + dsp = I_GETMDSP (ir); + ea = (R[rb] + SEXT_MDSP (dsp)) & M64; + WriteL (ea, op_stf (FR[ra])); /* swizzle bits */ + break; + + case OP_STG: /* STG */ + if (fpen == 0) ABORT (EXC_FPDIS); /* flt point disabled? */ + dsp = I_GETMDSP (ir); + ea = (R[rb] + SEXT_MDSP (dsp)) & M64; + WriteQ (ea, op_stg (FR[ra])); /* swizzle bits */ + break; + + case OP_STS: /* STS */ + if (fpen == 0) ABORT (EXC_FPDIS); /* flt point disabled? */ + dsp = I_GETMDSP (ir); + ea = (R[rb] + SEXT_MDSP (dsp)) & M64; + WriteL (ea, op_sts (FR[ra])); /* swizzle bits */ + break; + + case OP_STT: /* STT */ + if (fpen == 0) ABORT (EXC_FPDIS); /* flt point disabled? */ + dsp = I_GETMDSP (ir); + ea = (R[rb] + SEXT_MDSP (dsp)) & M64; + WriteQ (ea, FR[ra]); /* no swizzling needed */ + break; + + case OP_LDL: /* LDL */ + if (ra != 31) { + dsp = I_GETMDSP (ir); + ea = (R[rb] + SEXT_MDSP (dsp)) & M64; + res = ReadL (ea); + R[ra] = SEXT_L_Q (res); + } + break; + + case OP_LDQ: /* LDQ */ + if (ra != 31) { + dsp = I_GETMDSP (ir); + ea = (R[rb] + SEXT_MDSP (dsp)) & M64; + R[ra] = ReadQ (ea); + } + break; + + case OP_LDL_L: /* LDL_L */ + if (ra != 31) { + dsp = I_GETMDSP (ir); + ea = (R[rb] + SEXT_MDSP (dsp)) & M64; + res = ReadL (ea); + R[ra] = SEXT_L_Q (res); + lock_flag = 1; /* set lock flag */ + } + break; + + case OP_LDQ_L: /* LDQ_L */ + if (ra != 31) { + dsp = I_GETMDSP (ir); + ea = (R[rb] + SEXT_MDSP (dsp)) & M64; + R[ra] = ReadQ (ea); + lock_flag = 1; /* set lock flag */ + } + break; + + case OP_STL: /* STL */ + dsp = I_GETMDSP (ir); + ea = (R[rb] + SEXT_MDSP (dsp)) & M64; + WriteL (ea, R[ra]); + break; + + case OP_STQ: /* STQ */ + dsp = I_GETMDSP (ir); + ea = (R[rb] + SEXT_MDSP (dsp)) & M64; + WriteQ (ea, R[ra]); + break; + + case OP_STL_C: /* STL_C */ + dsp = I_GETMDSP (ir); + ea = (R[rb] + SEXT_MDSP (dsp)) & M64; + if (lock_flag) WriteL (ea, R[ra]); /* unlocking? ok */ + else R[ra] = 0; /* write fails */ + lock_flag = 0; /* clear lock */ + break; + + case OP_STQ_C: /* STQ_C */ + dsp = I_GETMDSP (ir); + ea = (R[rb] + SEXT_MDSP (dsp)) & M64; + if (lock_flag) WriteQ (ea, R[ra]); /* unlocking? ok */ + else R[ra] = 0; /* write fails */ + lock_flag = 0; /* clear lock */ + break; + +/* Control instructions */ + + case OP_JMP: /* JMP */ + PCQ_ENTRY; + rbv = R[rb]; /* in case Ra = Rb */ + if (ra != 31) R[ra] = PC; /* save PC */ + PC = rbv; /* jump */ + break; + + case OP_BR: /* BR, BSR */ + case OP_BSR: + PCQ_ENTRY; + if (ra != 31) R[ra] = PC; /* save PC */ + dsp = I_GETBDSP (ir); + PC = (PC + (SEXT_BDSP (dsp) << 2)) & M64; /* branch */ + break; + + case OP_FBEQ: /* FBEQ */ + if (fpen == 0) ABORT (EXC_FPDIS); /* flt point disabled? */ + if ((FR[ra] & ~FPR_SIGN) == 0) { /* +0 or - 0? */ + PCQ_ENTRY; + dsp = I_GETBDSP (ir); + PC = (PC + (SEXT_BDSP (dsp) << 2)) & M64; + } + break; + + case OP_FBLT: /* FBLT */ + if (fpen == 0) ABORT (EXC_FPDIS); /* flt point disabled? */ + if (FR[ra] > FPR_SIGN) { /* -0 to -n? */ + PCQ_ENTRY; + dsp = I_GETBDSP (ir); + PC = (PC + (SEXT_BDSP (dsp) << 2)) & M64; + } + break; + + case OP_FBLE: /* FBLE */ + if (fpen == 0) ABORT (EXC_FPDIS); /* flt point disabled? */ + if ((FR[ra] & FPR_SIGN) || (FR[ra] == 0)) { /* - or 0? */ + PCQ_ENTRY; + dsp = I_GETBDSP (ir); + PC = (PC + (SEXT_BDSP (dsp) << 2)) & M64; + } + break; + + case OP_FBNE: /* FBNE */ + if (fpen == 0) ABORT (EXC_FPDIS); /* flt point disabled? */ + if ((FR[ra] & ~FPR_SIGN) != 0) { /* not +0 or -0? */ + PCQ_ENTRY; + dsp = I_GETBDSP (ir); + PC = (PC + (SEXT_BDSP (dsp) << 2)) & M64; + } + break; + + case OP_FBGE: /* FBGE */ + if (fpen == 0) ABORT (EXC_FPDIS); /* flt point disabled? */ + if (FR[ra] <= FPR_SIGN) { /* +0 to +n? */ + PCQ_ENTRY; + dsp = I_GETBDSP (ir); + PC = (PC + (SEXT_BDSP (dsp) << 2)) & M64; + } + break; + + case OP_FBGT: /* FBGT */ + if (fpen == 0) ABORT (EXC_FPDIS); /* flt point disabled? */ + if (!(FR[ra] & FPR_SIGN) && (FR[ra] != 0)) { /* not - and not 0? */ + PCQ_ENTRY; + dsp = I_GETBDSP (ir); + PC = (PC + (SEXT_BDSP (dsp) << 2)) & M64; + } + break; + + case OP_BLBC: /* BLBC */ + if ((R[ra] & 1) == 0) { /* R<0> == 0? */ + PCQ_ENTRY; + dsp = I_GETBDSP (ir); + PC = (PC + (SEXT_BDSP (dsp) << 2)) & M64; + } + break; + + case OP_BEQ: /* BEQ */ + if (R[ra] == 0) { /* R == 0? */ + PCQ_ENTRY; + dsp = I_GETBDSP (ir); + PC = (PC + (SEXT_BDSP (dsp) << 2)) & M64; + } + break; + + case OP_BLT: /* BLT */ + if (R[ra] & Q_SIGN) { /* R<63> == 1? */ + PCQ_ENTRY; + dsp = I_GETBDSP (ir); + PC = (PC + (SEXT_BDSP (dsp) << 2)) & M64; + } + break; + + case OP_BLE: /* BLE */ + if ((R[ra] == 0) || (R[ra] & Q_SIGN)) { /* R == 0 || R<63> == 1? */ + PCQ_ENTRY; + dsp = I_GETBDSP (ir); + PC = (PC + (SEXT_BDSP (dsp) << 2)) & M64; + } + break; + + case OP_BLBS: /* BLBS */ + if ((R[ra] & 1) != 0) { /* R<0> == 1? */ + PCQ_ENTRY; + dsp = I_GETBDSP (ir); + PC = (PC + (SEXT_BDSP (dsp) << 2)) & M64; + } + break; + + case OP_BNE: /* BNE */ + if (R[ra] != 0) { /* R != 0? */ + PCQ_ENTRY; + dsp = I_GETBDSP (ir); + PC = (PC + (SEXT_BDSP (dsp) << 2)) & M64; + } + break; + + case OP_BGE: /* BGE */ + if (!(R[ra] & Q_SIGN)) { /* R<63> == 0? */ + PCQ_ENTRY; + dsp = I_GETBDSP (ir); + PC = (PC + (SEXT_BDSP (dsp) << 2)) & M64; + } + break; + + case OP_BGT: /* BGT */ + if ((R[ra] != 0) && !(R[ra] & Q_SIGN)) { /* R != 0 && R<63> == 0? */ + PCQ_ENTRY; + dsp = I_GETBDSP (ir); + PC = (PC + (SEXT_BDSP (dsp) << 2)) & M64; + } + break; + +/* Integer arithmetic operates (10) */ + + case OP_IALU: /* integer arith opr */ + rc = I_GETRC (ir); /* get rc */ + if (ir & I_ILIT) rbv = I_GETLIT8 (ir); /* literal? rbv = lit */ + else rbv = R[rb]; /* no, rbv = R[rb] */ + fnc = I_GETIFNC (ir); /* get function */ + switch (fnc) { /* case on function */ + + case 0x00: /* ADDL */ + res = SEXT_L_Q (R[ra] + rbv); + break; + + case 0x02: /* S4ADDL */ + res = SEXT_L_Q ((R[ra] << 2) + rbv); + break; + + case 0x09: /* SUBL */ + res = SEXT_L_Q (R[ra] - rbv); + break; + + case 0x0B: /* S4SUBL */ + res = SEXT_L_Q ((R[ra] << 2) - rbv); + break; + + case 0x0F: /* CMPBGE */ + for (i = 0, res = 0; i < 8; i++) { + if ((R[ra] & byte_mask[i]) >= (rbv & byte_mask[i])) + res = res | ((t_uint64) 1u << i); + } + break; + + case 0x12: /* S8ADDL */ + res = SEXT_L_Q ((R[ra] << 3) + rbv); + break; + + case 0x1B: /* S8SUBL */ + res = SEXT_L_Q ((R[ra] << 3) - rbv); + break; + + case 0x1D: /* CMPULT */ + res = (R[ra] < rbv); + break; + + case 0x20: /* ADDQ */ + res = R[ra] + rbv; + break; + + case 0x22: /* S4ADDQ */ + res = (R[ra] << 2) + rbv; + break; + + case 0x29: /* SUBQ */ + res = R[ra] - rbv; + break; + + case 0x2B: /* S4SUBQ */ + res = (R[ra] << 2) - rbv; + break; + + case 0x2D: /* CMPEQ */ + res = (R[ra] == rbv); + break; + + case 0x32: /* S8ADDQ */ + res = (R[ra] << 3) + rbv; + break; + + case 0x3B: /* S8SUBQ */ + res = (R[ra] << 3) - rbv; + break; + + case 0x3D: /* CMPULE */ + res = (R[ra] <= rbv); + break; + + case 0x40: /* ADDL/V */ + res = SEXT_L_Q (R[ra] + rbv); + if (((~R[ra] ^ rbv) & (R[ra] ^ res)) & L_SIGN) + arith_trap (TRAP_IOV, ir); + break; + + case 0x49: /* SUBL/V */ + res = SEXT_L_Q (R[ra] - rbv); + if (((R[ra] ^ rbv) & (~rbv ^ res)) & L_SIGN) + arith_trap (TRAP_IOV, ir); + break; + + case 0x4D: /* CMPLT */ + sgn = Q_GETSIGN (R[ra]); /* get Ra sign */ + if (sgn ^ Q_GETSIGN (rbv)) res = sgn; /* signs diff? */ + else res = sgn ^ (R[ra] < rbv); + break; + + case 0x60: /* ADDQ/V */ + res = R[ra] + rbv; + if (((~R[ra] ^ rbv) & (R[ra] ^ res)) & Q_SIGN) + arith_trap (TRAP_IOV, ir); + break; + + case 0x69: /* SUBQ/V */ + res = R[ra] - rbv; + if (((R[ra] ^ rbv) & (~rbv ^ res)) & Q_SIGN) + arith_trap (TRAP_IOV, ir); + break; + + case 0x6D: /* CMPLE */ + if (R[ra] == rbv) res = 1; + else { + sgn = Q_GETSIGN (R[ra]); /* get Ra sign */ + if (sgn ^ Q_GETSIGN (rbv)) res = sgn; /* signs diff? */ + else res = sgn ^ (R[ra] < rbv); + } + + break; + default: + res = R[rc]; + break; + } + + if (rc != 31) R[rc] = res & M64; + break; + +/* Integer logical operates (11) */ + + case OP_ILOG: /* integer logic opr */ + rc = I_GETRC (ir); /* get rc */ + if (ir & I_ILIT) rbv = I_GETLIT8 (ir); /* literal? rbv = lit */ + else rbv = R[rb]; /* no, rbv = R[rb] */ + fnc = I_GETIFNC (ir); /* get function */ + switch (fnc) { /* case on function */ + + case 0x00: /* AND */ + res = R[ra] & rbv; + break; + + case 0x08: /* BIC */ + res = R[ra] & ~rbv; + break; + + case 0x14: /* CMOVLBS */ + if ((R[ra] & 1) != 0) res = rbv; + else res = R[rc]; + break; + + case 0x16: /* CMOVLBC */ + if ((R[ra] & 1) == 0) res = rbv; + else res = R[rc]; + break; + + case 0x20: /* BIS */ + res = R[ra] | rbv; + break; + + case 0x24: /* CMOVEQ */ + if (R[ra] == 0) res = rbv; + else res = R[rc]; + break; + + case 0x26: /* CMOVNE */ + if (R[ra] != 0) res = rbv; + else res = R[rc]; + break; + + case 0x28: /* ORNOT */ + res = R[ra] | ~rbv; + break; + + case 0x40: /* XOR */ + res = R[ra] ^ rbv; + break; + + case 0x44: /* CMOVLT */ + if (R[ra] & Q_SIGN) res = rbv; + else res = R[rc]; + break; + + case 0x46: /* CMOVGE */ + if (!(R[ra] & Q_SIGN)) res = rbv; + else res = R[rc]; + break; + + case 0x48: /* EQV */ + res = R[ra] ^ ~rbv; + break; + + case 0x61: /* AMASK */ + res = rbv & ~arch_mask; + break; + + case 0x64: /* CMOVLE */ + if ((R[ra] & Q_SIGN) || (R[ra] == 0)) res = rbv; + else res = R[rc]; + break; + + case 0x66: /* CMOVGT */ + if (!(R[ra] & Q_SIGN) && (R[ra] != 0)) res = rbv; + else res = R[rc]; + break; + + case 0x6C: /* IMPLVER */ + res = impl_ver; + break; + + default: + res = R[rc]; + break; + } + + if (rc != 31) R[rc] = res & M64; + break; + +/* Integer logical shifts (12) */ + + case OP_ISHFT: /* integer shifts */ + rc = I_GETRC (ir); /* get rc */ + if (ir & I_ILIT) rbv = I_GETLIT8 (ir); /* literal? rbv = lit */ + else rbv = R[rb]; /* no, rbv = R[rb] */ + fnc = I_GETIFNC (ir); /* get function */ + switch (fnc) { /* case on function */ + + case 0x02: /* MSKBL */ + sc = ((uint32) rbv) & 7; + res = byte_zap (R[ra], 0x1 << sc); + break; + + case 0x06: /* EXTBL */ + sc = (((uint32) rbv) << 3) & 0x3F; + res = (R[ra] >> sc) & M8; + break; + + case 0x0B: /* INSBL */ + sc = (((uint32) rbv) << 3) & 0x3F; + res = (R[ra] & M8) << sc; + break; + + case 0x12: /* MSKWL */ + sc = ((uint32) rbv) & 7; + res = byte_zap (R[ra], 0x3 << sc); + break; + + case 0x16: /* EXTWL */ + sc = (((uint32) rbv) << 3) & 0x3F; + res = (R[ra] >> sc) & M16; + break; + + case 0x1B: /* INSWL */ + sc = (((uint32) rbv) << 3) & 0x3F; + res = (R[ra] & M16) << sc; + break; + + case 0x22: /* MSKLL */ + sc = ((uint32) rbv) & 7; + res = byte_zap (R[ra], 0xF << sc); + break; + + case 0x26: /* EXTLL */ + sc = (((uint32) rbv) << 3) & 0x3F; + res = (R[ra] >> sc) & M32; + break; + + case 0x2B: /* INSLL */ + sc = (((uint32) rbv) << 3) & 0x3F; + res = (R[ra] & M32) << sc; + break; + + case 0x30: /* ZAP */ + res = byte_zap (R[ra], (uint32) rbv); + break; + + case 0x31: /* ZAPNOT */ + res = byte_zap (R[ra], ~((uint32) rbv)); + break; + + case 0x32: /* MSKQL */ + sc = ((uint32) rbv) & 7; + res = byte_zap (R[ra], 0xFF << sc); + break; + + case 0x34: /* SRL */ + sc = ((uint32) rbv) & 0x3F; + res = R[ra] >> sc; + break; + + case 0x36: /* EXTQL */ + sc = (((uint32) rbv) << 3) & 0x3F; + res = R[ra] >> sc; + break; + + case 0x39: /* SLL */ + sc = ((uint32) rbv) & 0x3F; + res = R[ra] << sc; + break; + + case 0x3B: /* INSQL */ + sc = (((uint32) rbv) << 3) & 0x3F; + res = R[ra] << sc; + break; + + case 0x3C: /* SRA */ + sc = ((uint32) rbv) & 0x3F; + res = (R[ra] >> sc); + if (sc && (R[ra] & Q_SIGN)) res = res | + (((t_uint64) M64) << (64 - sc)); + break; + + case 0x52: /* MSKWH */ + sc = 8 - (((uint32) rbv) & 7); + res = byte_zap (R[ra], 0x3 >> sc); + break; + + case 0x57: /* EXTWH */ + sc = (64 - (((uint32) rbv) << 3)) & 0x3F; + res = (R[ra] << sc) & M16; + break; + + case 0x5A: /* INSWH */ + sc = (64 - (((uint32) rbv) << 3)) & 0x3F; + res = (R[ra] & M16) >> sc; + break; + + case 0x62: /* MSKLH */ + sc = 8 - (((uint32) rbv) & 7); + res = byte_zap (R[ra], 0xF >> sc); + break; + + case 0x67: /* EXTLH */ + sc = (64 - (((uint32) rbv) << 3)) & 0x3F; + res = (R[ra] << sc) & M32; + break; + + case 0x6A: /* INSLH */ + sc = (64 - (((uint32) rbv) << 3)) & 0x3F; + res = (R[ra] & M32) >> sc; + break; + + case 0x72: /* MSKQH */ + sc = 8 - (((uint32) rbv) & 7); + res = byte_zap (R[ra], 0xFF >> sc); + break; + + case 0x77: /* EXTQH */ + sc = (64 - (((uint32) rbv) << 3)) & 0x3F; + res = R[ra] << sc; + break; + + case 0x7A: /* INSQH */ + sc = (64 - (((uint32) rbv) << 3)) & 0x3F; + res = R[ra] >> sc; + break; + + default: + res = R[rc]; + break; + } + + if (rc != 31) R[rc] = res & M64; + break; + +/* Integer multiply (13) */ + + case OP_IMUL: /* integer multiply */ + rc = I_GETRC (ir); /* get rc */ + if (ir & I_ILIT) rbv = I_GETLIT8 (ir); /* literal? rbv = lit */ + else rbv = R[rb]; /* no, rbv = R[rb] */ + fnc = I_GETIFNC (ir); /* get function */ + switch (fnc) { /* case on function */ + + case 0x00: /* MULL */ + s1 = SEXT_L_Q (R[ra]); + s2 = SEXT_L_Q (rbv); + sr = s1 * s2; + res = SEXT_L_Q (sr); + break; + + case 0x20: /* MULQ */ + res = uemul64 (R[ra], rbv, NULL); /* low 64b invariant */ + break; /* with sign/unsigned */ + + case 0x30: /* UMULH */ + uemul64 (R[ra], rbv, &res); + break; + + case 0x40: /* MULL/V */ + s1 = SEXT_L_Q (R[ra]); + s2 = SEXT_L_Q (rbv); + sr = s1 * s2; + res = SEXT_L_Q (sr); + if (((sr ^ res) & M64) != 0) /* overflow? */ + arith_trap (TRAP_IOV, ir); + break; + + case 0x60: /* MULQ/V */ + res = uemul64 (R[ra], rbv, &t64); + if (Q_GETSIGN(R[ra])) + t64 = (t64 - rbv) & M64; + if (Q_GETSIGN(rbv)) + t64 = (t64 - R[ra]) & M64; + if (Q_GETSIGN (res)? (t64 != M64): (t64 != 0)) + arith_trap (TRAP_IOV, ir); + break; + + default: + res = R[rc]; + break; + } + + if (rc != 31) R[rc] = res & M64; + break; + +/* FIX optional floating point set (14) */ + + case OP_IFLT: /* int to flt */ + if (!(arch_mask & AMASK_FIX)) ABORT (EXC_RSVI); /* EV56 or later */ + if (fpen == 0) ABORT (EXC_FPDIS); /* flt point disabled? */ + rc = I_GETRC (ir); /* get rc */ + fnc = I_GETFFNC (ir); /* get function */ + switch (fnc) { /* case on function */ + + case 0x04: /* ITOFS */ + if (ir & (I_FRND|I_FTRP)) ABORT (EXC_RSVI); + t32 = ((uint32) R[ra]) & M32; + res = op_lds (t32); + break; + + case 0x0A: /* SQRTF */ + if (ir & I_F_VAXRSV) ABORT (EXC_RSVI); + res = vax_sqrt (ir, DT_F); + break; + + case 0x0B: /* SQRTS */ + res = ieee_sqrt (ir, DT_S); + break; + + case 0x14: /* ITOFF */ + if (ir & (I_FRND|I_FTRP)) ABORT (EXC_RSVI); + t32 = ((uint32) R[ra]) & M32; + res = op_ldf (SWAP_VAXF (t32)); + break; + + case 0x24: /* ITOFT */ + if (ir & (I_FRND|I_FTRP)) ABORT (EXC_RSVI); + res = R[ra]; + break; + + case 0x2A: /* SQRTG */ + if (ir & I_F_VAXRSV) ABORT (EXC_RSVI); + res = vax_sqrt (ir, DT_G); + break; + + case 0x2B: /* SQRTT */ + res = ieee_sqrt (ir, DT_T); + break; + + default: + ABORT (EXC_RSVI); + } + + if (rc != 31) FR[rc] = res & M64; + break; + +/* VAX and IEEE floating point operates - done externally */ + + case OP_VAX: /* VAX fp opr */ + if (ir & I_F_VAXRSV) ABORT (EXC_RSVI); /* reserved */ + if (fpen == 0) ABORT (EXC_FPDIS); /* flt point disabled? */ + vax_fop (ir); + break; + + case OP_IEEE: /* IEEE fp opr */ + if (fpen == 0) ABORT (EXC_FPDIS); /* flt point disabled? */ + ieee_fop (ir); + break; + +/* Data type independent floating point (17) */ + + case OP_FP: /* other fp */ + if (fpen == 0) ABORT (EXC_FPDIS); /* flt point disabled? */ + rc = I_GETRC (ir); /* get rc */ + fnc = I_GETFFNC (ir); /* get function */ + switch (fnc) { /* case on function */ + + case 0x10: /* CVTLQ */ + res = ((FR[rb] >> 32) & 0xC0000000) | ((FR[rb] >> 29) & 0x3FFFFFFF); + res = SEXT_L_Q (res); + break; + + case 0x20: /* CPYS */ + res = (FR[ra] & FPR_SIGN) | (FR[rb] & ~FPR_SIGN); + break; + + case 0x21: /* CPYSN */ + res = ((FR[ra] & FPR_SIGN) ^ FPR_SIGN) | (FR[rb] & ~FPR_SIGN); + break; + + case 0x22: /* CPYSE */ + res = (FR[ra] & (FPR_SIGN|FPR_EXP)) | (FR[rb] & ~(FPR_SIGN|FPR_EXP)); + break; + + case 0x24: /* MT_FPCR */ + fpcr = ((uint32) (FR[ra] >> 32)) & ~FPCR_RAZ; + res = FR[rc]; + break; + + case 0x25: /* MF_FPCR */ + res = ((t_uint64) fpcr) << 32; + break; + + case 0x2A: /* FCMOVEQ */ + if ((FR[ra] & ~FPR_SIGN) == 0) res = FR[rb]; + else res = FR[rc]; + break; + + case 0x2B: /* FCMOVNE */ + if ((FR[ra] & ~FPR_SIGN) != 0) res = FR[rb]; + else res = FR[rc]; + break; + + case 0x2C: /* FCMOVLT */ + if (FR[ra] > FPR_SIGN) res = FR[rb]; + else res = FR[rc]; + break; + + case 0x2D: /* FCMOVGE */ + if (FR[ra] <= FPR_SIGN) res = FR[rb]; + else res = FR[rc]; + break; + + case 0x2E: /* FCMOVLE */ + if (FPR_GETSIGN (FR[ra]) || (FR[ra] == 0)) res = FR[rb]; + else res = FR[rc]; + break; + + case 0x2F: /* FCMOVGT */ + if (!FPR_GETSIGN (FR[ra]) && (FR[ra] != 0)) res = FR[rb]; + else res = FR[rc]; + break; + + case 0x30: /* CVTQL */ + res = ((FR[rb] & 0xC0000000) << 32) | ((FR[rb] & 0x3FFFFFFF) << 29); + if (FPR_GETSIGN (FR[rb])? + (FR[rb] < 0xFFFFFFFF80000000): + (FR[rb] > 0x000000007FFFFFFF)) { + fpcr = fpcr | FPCR_IOV | FPCR_INE | FPCR_SUM; + if (ir & I_FTRP_V) arith_trap (TRAP_IOV, ir); + } + break; + + default: + res = FR[rc]; + break; + } + + if (rc != 31) FR[rc] = res & M64; + break; + +/* Barriers and misc (18) + + Alpha has a weak memory ordering model and an imprecise exception model; + together, they require a wide variety of barrier instructions to guarantee + memory coherency in multiprocessor systems, as well as backward compatible + exception instruction semantics. + + The simulator is uniprocessor only, and has ordered memory accesses and + precise exceptions. Therefore, the barriers are all NOP's. */ + + case OP_MISC: /* misc */ + fnc = I_GETMDSP (ir); /* get function */ + switch (fnc) { /* case on function */ + + case 0xC000: /* RPCC */ + pcc_l = pcc_l & M32; + if (ra != 31) R[ra] = (((t_uint64) pcc_h) << 32) | ((t_uint64) pcc_l); + break; + + case 0xE000: /* RC */ + if (ra != 31) R[ra] = vax_flag; + vax_flag = 0; + break; + + case 0xF000: /* RS */ + if (ra != 31) R[ra] = vax_flag; + vax_flag = 1; + break; + + default: + break; + } + + break; + +/* Optional instruction sets (1C) */ + + case OP_FLTI: /* float to int */ + rc = I_GETRC (ir); /* get rc */ + if (ir & I_ILIT) rbv = I_GETLIT8 (ir); /* literal? rbv = lit */ + else rbv = R[rb]; /* no, rbv = R[rb] */ + fnc = I_GETIFNC (ir); /* get function */ + switch (fnc) { /* case on function */ + + case 0x00: /* SEXTB */ + if (!(arch_mask & AMASK_BWX)) ABORT (EXC_RSVI); + res = SEXT_B_Q (rbv); + break; + + case 0x01: /* SEXTW */ + if (!(arch_mask & AMASK_BWX)) ABORT (EXC_RSVI); + res = SEXT_W_Q (rbv); + break; + + case 0x30: /* CTPOP */ + if (!(arch_mask & AMASK_CIX)) ABORT (EXC_RSVI); + for (res = 0; rbv != 0; res++) { + rbv = rbv & ~(rbv & NEG_Q (rbv)); + } + break; + + case 0x31: /* PERR */ + if (!(arch_mask & AMASK_MVI)) ABORT (EXC_RSVI); + for (i = 0, res = 0; i < 64; i = i + 8) { + s32 = (uint32) (R[ra] >> i) & M8; + t32 = (uint32) (rbv >> i) & M8; + res = res + ((t_uint64) (s32 >= t32)? (s32 - t32): (t32 - s32)); + } + break; + + case 0x32: /* CTLZ */ + if (!(arch_mask & AMASK_CIX)) ABORT (EXC_RSVI); + for (i = 0, res = 0; i < 64; i++) { + if ((rbv >> (63 - i)) & 1) break; + res = res + 1; + } + break; + + case 0x33: /* CTTZ */ + if (!(arch_mask & AMASK_CIX)) ABORT (EXC_RSVI); + for (i = 0, res = 0; i < 64; i++) { + if ((rbv >> i) & 1) break; + res = res + 1; + } + break; + + case 0x34: /* UNPKBL */ + if (!(arch_mask & AMASK_MVI)) ABORT (EXC_RSVI); + res = ((rbv & 0xFF00) << 24) | (rbv & 0xFF); + break; + + case 0x35: /* UNPKBW */ + if (!(arch_mask & AMASK_MVI)) ABORT (EXC_RSVI); + res = ((rbv & 0xFF000000) << 24) | ((rbv & 0xFF0000) << 16) | + ((rbv & 0xFF00) << 8) | (rbv & 0xFF); + break; + + case 0x36: /* PKWB */ + if (!(arch_mask & AMASK_MVI)) ABORT (EXC_RSVI); + res = ((rbv >> 24) & 0xFF000000) | ((rbv >> 16) & 0xFF0000) | + ((rbv >> 8) & 0xFF00) | (rbv & 0xFF); + break; + + case 0x37: /* PKLB */ + if (!(arch_mask & AMASK_MVI)) ABORT (EXC_RSVI); + res = ((rbv >> 24) & 0xFF00) | (rbv & 0xFF); + break; + + case 0x38: /* MINSB8 */ + if (!(arch_mask & AMASK_MVI)) ABORT (EXC_RSVI); + for (i = 0, res = 0; i < 8; i++) { + s1 = SEXT_B_Q (R[ra] >> (i << 3)); + s2 = SEXT_B_Q (rbv >> (i << 3)); + res = res | (((s1 <= s2)? R[ra]: rbv) & byte_mask[i]); + } + break; + + case 0x39: /* MINSW4 */ + if (!(arch_mask & AMASK_MVI)) ABORT (EXC_RSVI); + for (i = 0, res = 0; i < 8; i = i++) { + s1 = SEXT_W_Q (R[ra] >> (i << 4)); + s2 = SEXT_W_Q (rbv >> (i << 4)); + res = res | (((s1 <= s2)? R[ra]: rbv) & word_mask[i]); + } + break; + + case 0x3A: /* MINUB8 */ + if (!(arch_mask & AMASK_MVI)) ABORT (EXC_RSVI); + for (i = 0, res = 0; i < 8; i++) { + s64 = R[ra] & byte_mask[i]; + t64 = rbv & byte_mask[i]; + res = res | ((s64 <= t64)? s64: t64); + } + break; + + case 0x3B: /* MINUW4 */ + if (!(arch_mask & AMASK_MVI)) ABORT (EXC_RSVI); + for (i = 0, res = 0; i < 8; i = i++) { + s64 = R[ra] & word_mask[i]; + t64 = rbv & word_mask[i]; + res = res | ((s64 <= t64)? s64: t64); + } + break; + + case 0x3C: /* MAXUB8 */ + if (!(arch_mask & AMASK_MVI)) ABORT (EXC_RSVI); + for (i = 0, res = 0; i < 8; i++) { + s64 = R[ra] & byte_mask[i]; + t64 = rbv & byte_mask[i]; + res = res | ((s64 >= t64)? s64: t64); + } + break; + + case 0x3D: /* MAXUW4 */ + if (!(arch_mask & AMASK_MVI)) ABORT (EXC_RSVI); + for (i = 0, res = 0; i < 8; i = i++) { + s64 = R[ra] & word_mask[i]; + t64 = rbv & word_mask[i]; + res = res | ((s64 >= t64)? s64: t64); + } + break; + + case 0x3E: /* MAXSB8 */ + if (!(arch_mask & AMASK_MVI)) ABORT (EXC_RSVI); + for (i = 0, res = 0; i < 8; i++) { + s1 = SEXT_B_Q (R[ra] >> (i << 3)); + s2 = SEXT_B_Q (rbv >> (i << 3)); + res = res | (((s1 >= s2)? R[ra]: rbv) & byte_mask[i]); + } + break; + + case 0x3F: /* MAXSW4 */ + if (!(arch_mask & AMASK_MVI)) ABORT (EXC_RSVI); + for (i = 0, res = 0; i < 8; i = i++) { + s1 = SEXT_W_Q (R[ra] >> (i << 4)); + s2 = SEXT_W_Q (rbv >> (i << 4)); + res = res | (((s1 >= s2)? R[ra]: rbv) & word_mask[i]); + } + break; + + case 0x70: /* FTOIS */ + if (!(arch_mask & AMASK_FIX)) ABORT (EXC_RSVI); + if (fpen == 0) ABORT (EXC_FPDIS); /* flt point disabled? */ + res = op_sts (FR[ra]); + break; + + case 0x78: /* FTOIT */ + if (!(arch_mask & AMASK_FIX)) ABORT (EXC_RSVI); + if (fpen == 0) ABORT (EXC_FPDIS); /* flt point disabled? */ + res = FR[ra]; + break; + + default: + ABORT (EXC_RSVI); + } + + if (rc != 31) R[rc] = res & M64; + break; + +/* PAL hardware functions */ + + case OP_PAL19: + reason = pal_19 (ir); + intr_summ = pal_eval_intr (1); /* eval interrupts */ + break; + + case OP_PAL1B: + reason = pal_1b (ir); + intr_summ = pal_eval_intr (1); /* eval interrupts */ + break; + + case OP_PAL1D: + reason = pal_1d (ir); + intr_summ = pal_eval_intr (1); /* eval interrupts */ + break; + + case OP_PAL1E: + reason = pal_1e (ir); + intr_summ = pal_eval_intr (1); /* eval interrupts */ + break; + + case OP_PAL1F: + reason = pal_1f (ir); + intr_summ = pal_eval_intr (1); /* eval interrupts */ + break; + + case OP_PAL: /* PAL code */ + fnc = I_GETPAL (ir); /* get function code */ + if ((fnc & 0x40) || (fnc >= 0xC0)) /* out of range? */ + ABORT (EXC_RSVI); + reason = pal_proc_inst (fnc); /* processed externally */ + intr_summ = pal_eval_intr (1); /* eval interrupts */ + break; + + default: + ABORT (EXC_RSVI); + } /* end case */ + if (trap_summ) { /* any traps? */ + reason = pal_proc_trap (trap_summ); /* process trap */ + trap_summ = 0; /* clear trap reg */ + trap_mask = 0; + intr_summ = pal_eval_intr (1); /* eval interrupts */ + } + } /* end while */ +pcc_l = pcc_l & M32; +pcq_r->qptr = pcq_p; /* update pc q ptr */ +pc_align = ((uint32) PC) & 3; /* separate PC<1:0> */ +PC = PC & 0xFFFFFFFFFFFFFFFC; +return reason; +} + +/* Utility routines */ + +/* Byte zap function */ + +t_uint64 byte_zap (t_uint64 op, uint32 m) +{ +int32 i; + +m = m & 0xFF; /* 8 bit mask */ +for (i = 0; m != 0; m = m >> 1, i++) { + if (m & 1) op = op & ~byte_mask[i]; + } +return op; +} + +/* 64b * 64b unsigned multiply */ + +t_uint64 uemul64 (t_uint64 a, t_uint64 b, t_uint64 *hi) +{ +t_uint64 ahi, alo, bhi, blo, rhi, rmid1, rmid2, rlo; + +ahi = (a >> 32) & M32; +alo = a & M32; +bhi = (b >> 32) & M32; +blo = b & M32; +rhi = ahi * bhi; +rmid1 = ahi * blo; +rmid2 = alo * bhi; +rlo = alo * blo; +rhi = rhi + ((rmid1 >> 32) & M32) + ((rmid2 >> 32) & M32); +rmid1 = (rmid1 << 32) & M64; +rmid2 = (rmid2 << 32) & M64; +rlo = (rlo + rmid1) & M64; +if (rlo < rmid1) rhi = rhi + 1; +rlo = (rlo + rmid2) & M64; +if (rlo < rmid2) rhi = rhi + 1; +if (hi) *hi = rhi & M64; +return rlo; +} + +/* 64b / 64b unsigned fraction divide */ + +t_uint64 ufdiv64 (t_uint64 dvd, t_uint64 dvr, uint32 prec, uint32 *sticky) +{ +t_uint64 quo; +uint32 i; + +quo = 0; /* clear quotient */ +for (i = 0; (i < prec) && dvd; i++) { /* divide loop */ + quo = quo << 1; /* shift quo */ + if (dvd >= dvr) { /* div step ok? */ + dvd = dvd - dvr; /* subtract */ + quo = quo + 1; /* quo bit = 1 */ + } + dvd = dvd << 1; /* shift divd */ + } +quo = quo << (UF_V_NM - i + 1); /* shift quo */ +if (sticky) *sticky = (dvd? 1: 0); /* set sticky bit */ +return quo; /* return quotient */ +} + +/* Set arithmetic trap */ + +void arith_trap (uint32 mask, uint32 ir) +{ +uint32 rc = I_GETRC (ir); + +trap_summ = trap_summ | mask; +if (ir & I_FTRP_S) trap_summ = trap_summ | TRAP_SWC; +if ((mask & TRAP_IOV) == 0) rc = rc + 32; +trap_mask = trap_mask | ((t_uint64) 1u << rc); +return; +} + +/* Reset */ + +t_stat cpu_reset (DEVICE *dptr) +{ +R[31] = 0; +FR[31] = 0; +pal_mode = 1; +dmapen = 0; +fpen = 1; +vax_flag = 0; +lock_flag = 0; +trap_summ = 0; +trap_mask = 0; +if (M == NULL) M = (t_uint64 *) calloc (((uint32) MEMSIZE) >> 3, 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; +} + +/* Bootstrap */ + +t_stat cpu_boot (int32 unitno, DEVICE *dptr) +{ +return SCPE_ARG; +} + +/* Memory examine */ + +t_stat cpu_ex (t_value *vptr, t_addr addr, UNIT *uptr, int32 sw) +{ +if (vptr == NULL) return SCPE_ARG; +if (sw & SWMASK ('V') && dmapen) { + addr = trans_c (addr); + if (addr == M64) return STOP_MME; + } +if (ADDR_IS_MEM (addr)) { + *vptr = ReadPQ (addr); + return SCPE_OK; + } +return SCPE_NXM; +} + +/* Memory deposit */ + +t_stat cpu_dep (t_value val, t_addr addr, UNIT *uptr, int32 sw) +{ +if (sw & SWMASK ('V') && dmapen) { + addr = trans_c (addr); + if (addr == M64) return STOP_MME; + } +if (ADDR_IS_MEM (addr)) { + WritePQ (addr, val); + return SCPE_OK; + } +return SCPE_NXM; +} + +/* Memory allocation */ + +t_stat cpu_set_size (UNIT *uptr, int32 val, char *cptr, void *desc) +{ +t_uint64 mc = 0; +uint32 i, clim; +t_uint64 *nM = NULL; + +for (i = val; i < MEMSIZE; i = i + 8) mc = mc | M[i >> 3]; +if ((mc != 0) && !get_yn ("Really truncate memory [N]?", FALSE)) + return SCPE_OK; +nM = (t_uint64 *) calloc (val >> 3, sizeof (t_uint64)); +if (nM == NULL) return SCPE_MEM; +clim = (uint32) ((((uint32) val) < MEMSIZE)? val: MEMSIZE); +for (i = 0; i < clim; i = i + 8) nM[i >> 3] = M[i >>3]; +free (M); +M = nM; +MEMSIZE = val; +return SCPE_OK; +} + +/* Show virtual address */ + +t_stat cpu_show_virt (FILE *of, UNIT *uptr, int32 val, void *desc) +{ +t_stat r; +char *cptr = (char *) desc; +t_uint64 va, pa; + +if (cptr) { + DEVICE *dptr = find_dev_from_unit (uptr); + if (dptr == NULL) return SCPE_IERR; + va = get_uint (cptr, 16, M64, &r); + if (r == SCPE_OK) { + pa = trans_c (va); + if (pa == M64) { + fprintf (of, "Translation error\n"); + return SCPE_OK; + } + fputs ("Virtual ", of); + fprint_val (of, va, 16, 64, PV_LEFT); + fputs (" = physical ", of); + fprint_val (of, pa, 16, 64, PV_LEFT); + fputc ('\n', of); + return SCPE_OK; + } + } +fprintf (of, "Invalid argument\n"); +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; +} + +/* Print instruction trace */ + +t_stat cpu_fprint_one_inst (FILE *st, uint32 ir, t_uint64 pc, t_uint64 ra, t_uint64 rb) +{ +uint32 op; +t_value sim_val; +extern t_stat fprint_sym (FILE *ofile, t_addr addr, t_value *val, + UNIT *uptr, int32 sw); + +static const h_fmt[64] = { + 0, 0, 0, 0, 0, 0, 0, 0, + H_MRF, H_MRF, H_MRF, H_MRF, H_MRF, H_MRF, H_MRF, H_MRF, + H_IOP, H_IOP, H_IOP, H_IOP, H_FOP, H_FOP, H_FOP, H_FOP, + 0, H_PAL, H_JMP, H_PAL, H_FOP, H_PAL, H_PAL, H_PAL, + H_MRF, H_MRF, H_MRF, H_MRF, H_MRF, H_MRF, H_MRF, H_MRF, + H_MRF, H_MRF, H_MRF, H_MRF, H_MRF, H_MRF, H_MRF, H_MRF, + H_BRA, H_BRA, H_BRA, H_BRA, H_BRA, H_BRA, H_BRA, H_BRA, + H_BRA, H_BRA, H_BRA, H_BRA, H_BRA, H_BRA, H_BRA, H_BRA + }; + +pc = pc & ~HIST_PC; +fprint_val (st, pc, 16, 64, PV_RZRO); +fputc (' ', st); +op = I_GETOP (ir); /* get opcode */ +if (h_fmt[op] & H_A) fprint_val (st, ra, 16, 64, PV_RZRO); +else fputs (" ", st); +fputc (' ', st); +if (h_fmt[op] & H_B) { /* Rb? */ + t_uint64 rbv; + if ((h_fmt[op] & H_B_LIT) && (ir & I_ILIT)) + rbv = I_GETLIT8 (ir); /* literal? rbv = lit */ + else rbv = rb; /* no, rbv = R[rb] */ + fprint_val (st, rbv, 16, 64, PV_RZRO); + } +else fputs (" ", st); +fputc (' ', st); +if (h_fmt[op] & H_EA) { /* ea? */ + t_uint64 ea; + if (h_fmt[op] & H_EA_L16) ea = ir & M16; + else if (h_fmt[op] & H_EA_B) + ea = (pc + (SEXT_BDSP (I_GETBDSP (ir)) << 2)) & M64; + else ea = (rb + SEXT_MDSP (I_GETMDSP (ir))) & M64; + fprint_val (st, ea, 16, 64, PV_RZRO); + } +else fputs (" ", st); +fputc (' ', st); +if (pc & 4) sim_val = ((t_uint64) ir) << 32; +else sim_val = ir; +if ((fprint_sym (st, pc & ~03, &sim_val, &cpu_unit, SWMASK ('M'))) > 0) + fprintf (st, "(undefined) %08X", ir); +fputc ('\n', st); /* end line */ +return SCPE_OK; +} + +/* Show history */ + +t_stat cpu_show_hist (FILE *st, UNIT *uptr, int32 val, void *desc) +{ +uint32 k, di, lnt; +char *cptr = (char *) desc; +t_stat r; +InstHistory *h; + +if (hst_lnt == 0) return SCPE_NOFNC; /* enabled? */ +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 Ra Rb IR\n\n"); +for (k = 0; k < lnt; k++) { /* print specified */ + h = &hst[(++di) % hst_lnt]; /* entry pointer */ + if (h->pc & HIST_PC) { /* instruction? */ + cpu_fprint_one_inst (st, h->ir, h->pc, h->ra, h->rb); + } /* end if */ + } /* end for */ +return SCPE_OK; +} diff --git a/alpha/alpha_defs.h b/alpha/alpha_defs.h new file mode 100644 index 00000000..6f1ee907 --- /dev/null +++ b/alpha/alpha_defs.h @@ -0,0 +1,457 @@ +/* alpha_defs.h: Alpha architecture definitions file + + Copyright (c) 2003-2006, 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. + + Respectfully dedicated to the great people of the Alpha chip, systems, and + software development projects; and to the memory of Peter Conklin, of the + Alpha Program Office. +*/ + +#ifndef _ALPHA_DEFS_H_ +#define _ALPHA_DEFS_H_ 0 + +#include "sim_defs.h" +#include + +#if defined (__GNUC__) +#define INLINE inline +#else +#define INLINE +#endif + +/* Configuration */ + +#define INITMEMSIZE (1 << 24) /* !!debug!! */ +#define MEMSIZE (cpu_unit.capac) +#define ADDR_IS_MEM(x) ((x) < MEMSIZE) +#define DEV_DIB (1u << (DEV_V_UF + 0)) /* takes a DIB */ + +/* Simulator stops */ + +#define STOP_HALT 1 /* halt */ +#define STOP_IBKPT 2 /* breakpoint */ +#define STOP_NSPAL 3 /* non-supported PAL */ +#define STOP_KSNV 4 /* kernel stk inval */ +#define STOP_INVABO 5 /* invalid abort code */ +#define STOP_MME 6 /* console mem mgt error */ + +/* Bit patterns */ + +#define M8 0xFF +#define M16 0xFFFF +#define M32 0xFFFFFFFF +#define M64 0xFFFFFFFFFFFFFFFF +#define B_SIGN 0x80 +#define W_SIGN 0x8000 +#define L_SIGN 0x80000000 +#define Q_SIGN 0x8000000000000000 +#define Q_GETSIGN(x) (((uint32) ((x) >> 63)) & 1) + +/* Architectural variants */ + +#define AMASK_BWX 0x0001 /* byte/word */ +#define AMASK_FIX 0x0002 /* sqrt/flt-int moves */ +#define AMASK_CIX 0x0004 /* counts */ +#define AMASK_MVI 0x0100 /* multimedia */ +#define AMASK_PRC 0x0200 /* precise exceptions */ +#define AMASK_PFM 0x1000 /* prefetch w modify */ + +#define IMPLV_EV4 0x0 /* EV4 (21064) */ +#define IMPLV_EV5 0x1 /* EV5 (21164) */ +#define IMPLV_EV6 0x2 /* EV6 (21264) */ +#define IMPLV_EV7 0x3 /* EV7 (21364) */ + +/* Instruction formats */ + +#define I_V_OP 26 /* opcode */ +#define I_M_OP 0x3F +#define I_OP (I_M_OP << I_V_OP) +#define I_V_RA 21 /* Ra */ +#define I_M_RA 0x1F +#define I_V_RB 16 /* Rb */ +#define I_M_RB 0x1F +#define I_V_FTRP 13 /* floating trap mode */ +#define I_M_FTRP 0x7 +#define I_FTRP (I_M_FTRP << I_V_FTRP) +#define I_F_VAXRSV 0x4800 /* VAX reserved */ +#define I_FTRP_V 0x2000 /* /V trap */ +#define I_FTRP_U 0x2000 /* /U trap */ +#define I_FTRP_S 0x8000 /* /S trap */ +#define I_FTRP_SUI 0xE000 /* /SUI trap */ +#define I_FTRP_SVI 0xE000 /* /SVI trap */ +#define I_V_FRND 11 /* floating round mode */ +#define I_M_FRND 0x3 +#define I_FRND (I_M_FRND << I_V_FRND) +#define I_FRND_C 0 /* chopped */ +#define I_FRND_M 1 /* to minus inf */ +#define I_FRND_N 2 /* normal */ +#define I_FRND_D 3 /* dynamic */ +#define I_FRND_P 3 /* in FPCR: plus inf */ +#define I_V_FSRC 9 /* floating source */ +#define I_M_FSRC 0x3 +#define I_FSRC (I_M_FSRC << I_V_FSRC) +#define I_FSRC_X 0x0200 /* data type X */ +#define I_V_FFNC 5 /* floating function */ +#define I_M_FFNC 0x3F +#define I_V_LIT8 13 /* integer 8b literal */ +#define I_M_LIT8 0xFF +#define I_V_ILIT 12 /* literal flag */ +#define I_ILIT (1u << I_V_ILIT) +#define I_V_IFNC 5 /* integer function */ +#define I_M_IFNC 0x3F +#define I_V_RC 0 /* Rc */ +#define I_M_RC 0x1F +#define I_V_MDSP 0 /* memory displacement */ +#define I_M_MDSP 0xFFFF +#define I_V_BDSP 0 +#define I_M_BDSP 0x1FFFFF /* branch displacement */ +#define I_V_PALOP 0 +#define I_M_PALOP 0x3FFFFFF /* PAL subopcode */ +#define I_GETOP(x) (((x) >> I_V_OP) & I_M_OP) +#define I_GETRA(x) (((x) >> I_V_RA) & I_M_RA) +#define I_GETRB(x) (((x) >> I_V_RB) & I_M_RB) +#define I_GETLIT8(x) (((x) >> I_V_LIT8) & I_M_LIT8) +#define I_GETIFNC(x) (((x) >> I_V_IFNC) & I_M_IFNC) +#define I_GETFRND(x) (((x) >> I_V_FRND) & I_M_FRND) +#define I_GETFFNC(x) (((x) >> I_V_FFNC) & I_M_FFNC) +#define I_GETRC(x) (((x) >> I_V_RC) & I_M_RC) +#define I_GETMDSP(x) (((x) >> I_V_MDSP) & I_M_MDSP) +#define I_GETBDSP(x) (((x) >> I_V_BDSP) & I_M_BDSP) +#define I_GETPAL(x) (((x) >> I_V_PALOP) & I_M_PALOP) + +/* Floating point types */ + +#define DT_F 0 /* type F */ +#define DT_G 1 /* type G */ +#define DT_S 0 /* type S */ +#define DT_T 1 /* type T */ + +/* Floating point memory format (VAX F) */ + +#define F_V_SIGN 15 +#define F_SIGN (1u << F_V_SIGN) +#define F_V_EXP 7 +#define F_M_EXP 0xFF +#define F_BIAS 0x80 +#define F_EXP (F_M_EXP << F_V_EXP) +#define F_V_FRAC 29 +#define F_GETEXP(x) ((uint32) (((x) >> F_V_EXP) & F_M_EXP)) +#define SWAP_VAXF(x) ((((x) >> 16) & 0xFFFF) | (((x) & 0xFFFF) << 16)) + +/* Floating point memory format (VAX G) */ + +#define G_V_SIGN 15 +#define G_SIGN (1u << F_V_SIGN) +#define G_V_EXP 4 +#define G_M_EXP 0x7FF +#define G_BIAS 0x400 +#define G_EXP (G_M_EXP << G_V_EXP) +#define G_GETEXP(x) ((uint32) (((x) >> G_V_EXP) & G_M_EXP)) +#define SWAP_VAXG(x) ((((x) & 0x000000000000FFFF) << 48) | \ + (((x) & 0x00000000FFFF0000) << 16) | \ + (((x) >> 16) & 0x00000000FFFF0000) | \ + (((x) >> 48) & 0x000000000000FFFF)) + +/* Floating memory format (IEEE S) */ + +#define S_V_SIGN 31 +#define S_SIGN (1u << S_V_SIGN) +#define S_V_EXP 23 +#define S_M_EXP 0xFF +#define S_BIAS 0x7F +#define S_NAN 0xFF +#define S_EXP (S_M_EXP << S_V_EXP) +#define S_V_FRAC 29 +#define S_GETEXP(x) ((uint32) (((x) >> S_V_EXP) & S_M_EXP)) + +/* Floating point memory format (IEEE T) */ + +#define T_V_SIGN 63 +#define T_SIGN 0x8000000000000000 +#define T_V_EXP 52 +#define T_M_EXP 0x7FF +#define T_BIAS 0x3FF +#define T_NAN 0x7FF +#define T_EXP 0x7FF0000000000000 +#define T_FRAC 0x000FFFFFFFFFFFFF +#define T_GETEXP(x) ((uint32) (((uint32) ((x) >> T_V_EXP)) & T_M_EXP)) + +/* Floating point register format (all except VAX D) */ + +#define FPR_V_SIGN 63 +#define FPR_SIGN 0x8000000000000000 +#define FPR_V_EXP 52 +#define FPR_M_EXP 0x7FF +#define FPR_NAN 0x7FF +#define FPR_EXP 0x7FF0000000000000 +#define FPR_HB 0x0010000000000000 +#define FPR_FRAC 0x000FFFFFFFFFFFFF +#define FPR_GUARD (UF_V_NM - FPR_V_EXP) +#define FPR_GETSIGN(x) (((uint32) ((x) >> FPR_V_SIGN)) & 1) +#define FPR_GETEXP(x) (((uint32) ((x) >> FPR_V_EXP)) & FPR_M_EXP) +#define FPR_GETFRAC(x) ((x) & FPR_FRAC) + +#define FP_TRUE 0x4000000000000000 /* 0.5/2.0 in reg */ + +/* Floating point register format (VAX D) */ + +#define FDR_V_SIGN 63 +#define FDR_SIGN 0x8000000000000000 +#define FDR_V_EXP 55 +#define FDR_M_EXP 0xFF +#define FDR_EXP 0x7F80000000000000 +#define FDR_HB 0x0080000000000000 +#define FDR_FRAC 0x007FFFFFFFFFFFFF +#define FDR_GUARD (UF_V_NM - FDR_V_EXP) +#define FDR_GETSIGN(x) (((uint32) ((x) >> FDR_V_SIGN)) & 1) +#define FDR_GETEXP(x) (((uint32) ((x) >> FDR_V_EXP)) & FDR_M_EXP) +#define FDR_GETFRAC(x) ((x) & FDR_FRAC) + +#define D_BIAS 0x80 + +/* Unpacked floating point number */ + +typedef struct { + uint32 sign; + int32 exp; + t_uint64 frac; + } UFP; + +#define UF_V_NM 63 +#define UF_NM 0x8000000000000000 /* normalized */ + +/* IEEE control register (left 32b only) */ + +#define FPCR_SUM 0x80000000 /* summary */ +#define FPCR_INED 0x40000000 /* inexact disable */ +#define FPCR_UNFD 0x20000000 /* underflow disable */ +#define FPCR_UNDZ 0x10000000 /* underflow to 0 */ +#define FPCR_V_RMOD 26 /* rounding mode */ +#define FPCR_M_RMOD 0x3 +#define FPCR_IOV 0x02000000 /* integer overflow */ +#define FPCR_INE 0x01000000 /* inexact */ +#define FPCR_UNF 0x00800000 /* underflow */ +#define FPCR_OVF 0x00400000 /* overflow */ +#define FPCR_DZE 0x00200000 /* div by zero */ +#define FPCR_INV 0x00100000 /* invalid operation */ +#define FPCR_OVFD 0x00080000 /* overflow disable */ +#define FPCR_DZED 0x00040000 /* div by zero disable */ +#define FPCR_INVD 0x00020000 /* invalid op disable */ +#define FPCR_DNZ 0x00010000 /* denormal to zero */ +#define FPCR_DNOD 0x00008000 /* denormal disable */ +#define FPCR_RAZ 0x00007FFF /* zero */ +#define FPCR_ERR (FPCR_IOV|FPCR_INE|FPCR_UNF|FPCR_OVF|FPCR_DZE|FPCR_INV) +#define FPCR_GETFRND(x) (((x) >> FPCR_V_RMOD) & FPCR_M_RMOD) + +/* PTE - hardware format */ + +#define PTE_V_PFN 32 /* PFN */ +#define PFN_MASK 0xFFFFFFFF +#define PTE_V_UWE 15 /* write enables */ +#define PTE_V_SWE 14 +#define PTE_V_EWE 13 +#define PTE_V_KWE 12 +#define PTE_V_URE 11 /* read enables */ +#define PTE_V_SRE 10 +#define PTE_V_ERE 9 +#define PTE_V_KRE 8 +#define PTE_V_GH 5 /* granularity hint */ +#define PTE_M_GH 0x3 +#define PTE_GH (PTE_M_GH << PTE_V_GH) +#define PTE_V_ASM 4 /* address space match */ +#define PTE_V_FOE 3 /* fault on execute */ +#define PTE_V_FOW 2 /* fault on write */ +#define PTE_V_FOR 1 /* fault on read */ +#define PTE_V_V 0 /* valid */ +#define PTE_UWE (1u << PTE_V_UWE) +#define PTE_SWE (1u << PTE_V_SWE) +#define PTE_EWE (1u << PTE_V_EWE) +#define PTE_KWE (1u << PTE_V_KWE) +#define PTE_URE (1u << PTE_V_URE) +#define PTE_SRE (1u << PTE_V_SRE) +#define PTE_ERE (1u << PTE_V_ERE) +#define PTE_KRE (1u << PTE_V_KRE) +#define PTE_ASM (1u << PTE_V_ASM) +#define PTE_FOE (1u << PTE_V_FOE) +#define PTE_FOW (1u << PTE_V_FOW) +#define PTE_FOR (1u << PTE_V_FOR) +#define PTE_V (1u << PTE_V_V) +#define PTE_MASK 0xFF7F +#define PTE_GETGH(x) ((((uint32) (x)) >> PTE_V_GH) & PTE_M_GH) +#define VPN_GETLVL1(x) (((x) >> ((2 * VA_N_LVL) - 3)) & (VA_M_LVL << 3)) +#define VPN_GETLVL2(x) (((x) >> (VA_N_LVL - 3)) & (VA_M_LVL << 3)) +#define VPN_GETLVL3(x) (((x) << 3) & (VA_M_LVL << 3)) + +#define ACC_E(m) ((PTE_KRE << (m)) | PTE_FOE | PTE_V) +#define ACC_R(m) ((PTE_KRE << (m)) | PTE_FOR | PTE_V) +#define ACC_W(m) ((PTE_KWE << (m)) | PTE_FOW | PTE_V) +#define ACC_M(m) (((PTE_KRE|PTE_KWE) << (m)) | PTE_FOR | PTE_FOW | PTE_V) + +/* Exceptions */ + +#define ABORT(x) longjmp (save_env, (x)) +#define ABORT1(x,y) { p1 = (x); longjmp (save_env, (y)); } + +#define EXC_RSVI 0x01 /* reserved instruction */ +#define EXC_RSVO 0x02 /* reserved operand */ +#define EXC_ALIGN 0x03 /* operand alignment */ +#define EXC_FPDIS 0x04 /* flt point disabled */ +#define EXC_TBM 0x08 /* TLB miss */ +#define EXC_FOX 0x10 /* fault on r/w/e */ +#define EXC_ACV 0x14 /* access control viol */ +#define EXC_TNV 0x18 /* translation not valid */ +#define EXC_BVA 0x1C /* bad address format */ +#define EXC_E 0x00 /* offset for execute */ +#define EXC_R 0x01 /* offset for read */ +#define EXC_W 0x02 /* offset for write */ + +/* Traps - corresponds to arithmetic trap summary register */ + +#define TRAP_SWC 0x001 /* software completion */ +#define TRAP_INV 0x002 /* invalid operand */ +#define TRAP_DZE 0x004 /* divide by zero */ +#define TRAP_OVF 0x008 /* overflow */ +#define TRAP_UNF 0x010 /* underflow */ +#define TRAP_INE 0x020 /* inexact */ +#define TRAP_IOV 0x040 /* integer overflow */ +#define TRAP_SUMM_RW 0x07F + +/* PALcode */ + +#define SP R[30] /* stack pointer */ +#define MODE_K 0 /* kernel */ +#define MODE_E 1 /* executive (UNIX user) */ +#define MODE_S 2 /* supervisor */ +#define MODE_U 3 /* user */ + +#define PAL_UNDF 0 /* undefined */ +#define PAL_VMS 1 /* VMS */ +#define PAL_UNIX 2 /* UNIX */ +#define PAL_NT 3 /* Windows NT */ + +/* Machine check error summary register */ + +#define MCES_INP 0x01 /* in progress */ +#define MCES_SCRD 0x02 /* sys corr in prog */ +#define MCES_PCRD 0x04 /* proc corr in prog */ +#define MCES_DSCRD 0x08 /* disable system corr */ +#define MCES_DPCRD 0x10 /* disable proc corr */ +#define MCES_W1C (MCES_INP|MCES_SCRD|MCES_PCRD) +#define MCES_DIS (MCES_DSCRD|MCES_DPCRD) + +/* I/O devices */ + +#define L_BYTE 0 /* IO request lengths */ +#define L_WORD 1 +#define L_LONG 2 +#define L_QUAD 3 + +/* Device information block */ + +typedef struct { /* device info block */ + t_uint64 low; /* low addr */ + t_uint64 high; /* high addr */ + t_bool (*read)(t_uint64 pa, t_uint64 *val, uint32 lnt); + t_bool (*write)(t_uint64 pa, t_uint64 val, uint32 lnt); + uint32 ipl; + } DIB; + +/* Interrupt system - 6 levels in EV4 and EV6, 4 in EV5 - software expects 4 */ + +#define IPL_HMAX 0x17 /* highest hwre level */ +#define IPL_HMIN 0x14 /* lowest hwre level */ +#define IPL_HLVL (IPL_HMAX - IPL_HMIN + 1) /* # hardware levels */ +#define IPL_SMAX 0x0F /* highest swre level */ + +/* Macros */ + +#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 - 4) & M64 + +#define SEXT_B_Q(x) (((x) & B_SIGN)? ((x) | ~((t_uint64) M8)): ((x) & M8)) +#define SEXT_W_Q(x) (((x) & W_SIGN)? ((x) | ~((t_uint64) M16)): ((x) & M16)) +#define SEXT_L_Q(x) (((x) & L_SIGN)? ((x) | ~((t_uint64) M32)): ((x) & M32)) +#define NEG_Q(x) ((~(x) + 1) & M64) +#define ABS_Q(x) (((x) & Q_SIGN)? NEG_Q (x): (x)) + +#define SIGN_BDSP 0x100000 +#define SIGN_MDSP 0x008000 +#define SEXT_MDSP(x) (((x) & SIGN_MDSP)? \ + ((x) | ~((t_uint64) I_M_MDSP)): ((x) & I_M_MDSP)) +#define SEXT_BDSP(x) (((x) & SIGN_BDSP)? \ + ((x) | ~((t_uint64) I_M_BDSP)): ((x) & I_M_BDSP)) + +/* Opcodes */ + +enum opcodes { + OP_PAL, OP_OPC01, OP_OPC02, OP_OPC03, + OP_OPC04, OP_OPC05, OP_OPC06, OP_OPC07, + OP_LDA, OP_LDAH, OP_LDBU, OP_LDQ_U, + OP_LDWU, OP_STW, OP_STB, OP_STQ_U, + OP_IALU, OP_ILOG, OP_ISHFT, OP_IMUL, + OP_IFLT, OP_VAX, OP_IEEE, OP_FP, + OP_MISC, OP_PAL19, OP_JMP, OP_PAL1B, + OP_FLTI, OP_PAL1D, OP_PAL1E, OP_PAL1F, + OP_LDF, OP_LDG, OP_LDS, OP_LDT, + OP_STF, OP_STG, OP_STS, OP_STT, + OP_LDL, OP_LDQ, OP_LDL_L, OP_LDQ_L, + OP_STL, OP_STQ, OP_STL_C, OP_STQ_C, + OP_BR, OP_FBEQ, OP_FBLT, OP_FBLE, + OP_BSR, OP_FBNE, OP_FBGE, OP_FBGT, + OP_BLBC, OP_BEQ, OP_BLT, OP_BLE, + OP_BLBS, OP_BNE, OP_BGE, OP_BGT + }; + +/* Function prototypes */ + +uint32 ReadI (t_uint64 va); +t_uint64 ReadB (t_uint64 va); +t_uint64 ReadW (t_uint64 va); +t_uint64 ReadL (t_uint64 va); +t_uint64 ReadQ (t_uint64 va); +t_uint64 ReadAccL (t_uint64 va, uint32 acc); +t_uint64 ReadAccQ (t_uint64 va, uint32 acc); +INLINE t_uint64 ReadPB (t_uint64 pa); +INLINE t_uint64 ReadPW (t_uint64 pa); +INLINE t_uint64 ReadPL (t_uint64 pa); +INLINE t_uint64 ReadPQ (t_uint64 pa); +t_bool ReadIO (t_uint64 pa, t_uint64 *val, uint32 lnt); +void WriteB (t_uint64 va, t_uint64 dat); +void WriteW (t_uint64 va, t_uint64 dat); +void WriteL (t_uint64 va, t_uint64 dat); +void WriteQ (t_uint64 va, t_uint64 dat); +void WriteAccL (t_uint64 va, t_uint64 dat, uint32 acc); +void WriteAccQ (t_uint64 va, t_uint64 dat, uint32 acc); +INLINE void WritePB (t_uint64 pa, t_uint64 dat); +INLINE void WritePW (t_uint64 pa, t_uint64 dat); +INLINE void WritePL (t_uint64 pa, t_uint64 dat); +INLINE void WritePQ (t_uint64 pa, t_uint64 dat); +t_bool WriteIO (t_uint64 pa, t_uint64 val, uint32 lnt); +uint32 mmu_set_cm (uint32 mode); +void mmu_set_icm (uint32 mode); +void mmu_set_dcm (uint32 mode); +void arith_trap (uint32 trap, uint32 ir); + +#endif diff --git a/alpha/alpha_ev5_cons.c b/alpha/alpha_ev5_cons.c new file mode 100644 index 00000000..fb576705 --- /dev/null +++ b/alpha/alpha_ev5_cons.c @@ -0,0 +1,143 @@ +/* alpha_ev5_cons.c - Alpha console support routines for EV5 + + Copyright (c) 2003-2006, Robert M Supnik + + Permission is hereby granted, free of charge, to any person obtaining a + copy of this software and associated documentation files (the "Software"), + to deal in the Software without restriction, including without limitation + the rights to use, copy, modify, merge, publish, distribute, sublicense, + and/or sell copies of the Software, and to permit persons to whom the + Software is furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + ROBERT M SUPNIK BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + Except as contained in this notice, the name of Robert M Supnik shall not be + used in advertising or otherwise to promote the sale, use or other dealings + in this Software without prior written authorization from Robert M Supnik. +*/ + +#include "alpha_defs.h" +#include "alpha_ev5_defs.h" + +t_uint64 srm_ptbr = 1; + +extern uint32 dtlb_spage; +extern uint32 pal_type; +extern uint32 ev5_mcsr; +extern t_uint64 *M; +extern t_uint64 ev5_mvptbr; +extern UNIT cpu_unit; + +/* Local quadword physical read - exceptions or IO space lookups */ + +t_stat l_ReadPQ (t_uint64 pa, t_uint64 *dat) +{ +if (ADDR_IS_MEM (pa)) { + *dat = M[pa >> 3]; + return TRUE; + } +return FALSE; +} + +/* "SRM" 3-level pte lookup + + Inputs: + va = virtual address + *pte = pointer to pte to be returned + Output: + status = 0 for successful fill + EXC_ACV for ACV on intermediate level + EXC_TNV for TNV on intermediate level +*/ + +uint32 cons_find_pte_srm (t_uint64 va, t_uint64 *l3pte) +{ +t_uint64 vptea, l1ptea, l2ptea, l3ptea, l1pte, l2pte; +uint32 vpte_vpn; +TLBENT *vpte_p; + +vptea = FMT_MVA_VMS (va); /* try virt lookup */ +vpte_vpn = VA_GETVPN (vptea); /* get vpte vpn */ +vpte_p = dtlb_lookup (vpte_vpn); /* get vpte tlb ptr */ +if (vpte_p && ((vpte_p->pte & (PTE_KRE|PTE_V)) == (PTE_KRE|PTE_V))) + l3ptea = PHYS_ADDR (vpte_p->pfn, vptea); +else { + uint32 vpn = VA_GETVPN (va); + if (srm_ptbr & 1) return 1; /* uninitialized? */ + l1ptea = srm_ptbr + VPN_GETLVL1 (vpn); + if (!l_ReadPQ (l1ptea, &l1pte)) return 1; + if ((l1pte & PTE_V) == 0) + return ((l1pte & PTE_KRE)? EXC_TNV: EXC_ACV); + l2ptea = (l1pte & PFN_MASK) >> (PTE_V_PFN - VA_N_OFF); + l2ptea = l2ptea + VPN_GETLVL2 (vpn); + if (!l_ReadPQ (l2ptea, &l2pte)) return 1; + if ((l2pte & PTE_V) == 0) + return ((l2pte & PTE_KRE)? EXC_TNV: EXC_ACV); + l3ptea = (l2pte & PFN_MASK) >> (PTE_V_PFN - VA_N_OFF); + l3ptea = l3ptea + VPN_GETLVL3 (vpn); + } +if (!l_ReadPQ (l3ptea, l3pte)) return 1; +return 0; +} + +/* NT 2-level pte lookup + + Inputs: + va = virtual address + *pte = pointer to pte to be returned + Output: + status = 0 for successful fill + EXC_ACV for ACV on intermediate level + EXC_TNV for TNV on intermediate level +*/ + +uint32 cons_find_pte_nt (t_uint64 va, t_uint64 *l3pte) +{ +t_uint64 vptea, l3ptea; +uint32 vpte_vpn; +TLBENT *vpte_p; + +vptea = FMT_MVA_NT (va); /* try virt lookup */ +vpte_vpn = VA_GETVPN (vptea); /* get vpte vpn */ +vpte_p = dtlb_lookup (vpte_vpn); /* get vpte tlb ptr */ +if (vpte_p && ((vpte_p->pte & (PTE_KRE|PTE_V)) == (PTE_KRE|PTE_V))) + l3ptea = PHYS_ADDR (vpte_p->pfn, vptea); +else { + return 1; /* for now */ + } +if (!l_ReadPQ (l3ptea, l3pte)) return 1; +return 0; +} + +/* Translate address for console access */ + +t_uint64 trans_c (t_uint64 va) +{ +uint32 va_sext = VA_GETSEXT (va); +uint32 vpn = VA_GETVPN (va); +TLBENT *tlbp; +t_uint64 pte64; +uint32 exc, pfn; + +if ((va_sext != 0) && (va_sext != VA_M_SEXT)) /* invalid virt addr? */ + return M64; +if ((dtlb_spage & SPEN_43) && (VPN_GETSP43 (vpn) == 2)) + return (va & SP43_MASK); /* 43b superpage? */ +if ((dtlb_spage & SPEN_32) && (VPN_GETSP32 (vpn) == 0x1FFE)) + return (va & SP32_MASK); /* 32b superpage? */ +if (tlbp = dtlb_lookup (vpn)) /* try TLB */ + return PHYS_ADDR (tlbp->pfn, va); /* found it */ +if (ev5_mcsr & MCSR_NT) exc = cons_find_pte_nt (va, &pte64); +else exc = cons_find_pte_srm (va, &pte64); +if (exc || ((pte64 & PTE_V) == 0)) return M64; /* check valid */ +pfn = (uint32) (pte64 >> 32) & M32; +return PHYS_ADDR (pfn, va); /* return phys addr */ +} diff --git a/alpha/alpha_ev5_defs.h b/alpha/alpha_ev5_defs.h new file mode 100644 index 00000000..cba29614 --- /dev/null +++ b/alpha/alpha_ev5_defs.h @@ -0,0 +1,428 @@ +/* alpha_ev5_defs.h: Alpha EV5 chip definitions file + + Copyright (c) 2003-2005, 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. + + Respectfully dedicated to the great people of the Alpha chip, systems, and + software development projects; and to the memory of Peter Conklin, of the + Alpha Program Office. +*/ + +#ifndef _ALPHA_EV5_DEFS_H_ +#define _ALPHA_EV5_DEFS_H_ 0 + +/* Address limits */ + +#define VA_SIZE 43 /* VA size */ +#define NTVA_WIDTH 32 /* VA width for NT */ +#define VA_MASK 0x000007FFFFFFFFFF +#define EV5_PA_SIZE 40 /* PA size */ +#define EV5_PA_MASK 0x000000FFFFFFFFFF + +/* Virtual address */ + +#define VA_N_OFF 13 /* offset size */ +#define VA_PAGSIZE (1u << VA_N_OFF) /* page size */ +#define VA_M_OFF ((1u << VA_N_OFF) - 1) /* offset mask */ +#define VA_N_LVL 10 /* width per level */ +#define VA_M_LVL ((1u << VA_N_LVL) - 1) /* level mask */ +#define VA_V_VPN VA_N_OFF /* vpn start */ +#define VA_N_VPN (VA_N_LVL * 3) /* vpn size */ +#define VA_M_VPN ((1u << VA_N_VPN) - 1) /* vpn mask */ +#define VA_WIDTH (VA_N_VPN + VA_N_OFF) /* total VA size */ +#define VA_V_SEXT (VA_WIDTH - 1) /* sext start */ +#define VA_M_SEXT ((1u << (64 - VA_V_SEXT)) - 1) /* sext mask */ +#define VA_GETOFF(x) (((uint32) (x)) & VA_M_OFF) +#define VA_GETVPN(x) (((uint32) ((x) >> VA_V_VPN)) & VA_M_VPN) +#define VA_GETSEXT(x) (((uint32) ((x) >> VA_V_SEXT)) & VA_M_SEXT) +#define PHYS_ADDR(p,v) ((((t_uint64) (p)) < VA_N_OFF) | VA_GETOFF (v)) + +/* 43b and 32b superpages - present in all implementations */ + +#define SPEN_43 0x2 +#define SPEN_32 0x1 +#define SP43_MASK 0x000001FFFFFFFFFF +#define SP32_MASK 0x000000003FFFFFFF +#define VPN_GETSP43(x) ((uint32) (((x) >> (VA_WIDTH - VA_N_OFF - 2)) & 3)) +#define VPN_GETSP32(x) ((uint32) (((x) >> (NTVA_WIDTH - VA_N_OFF - 2)) & 0x1FFF)) + +/* TLBs */ + +#define INV_TAG M32 +#define ITLB_SIZE 48 +#define DTLB_SIZE 64 +#define ITLB_WIDTH 6 +#define DTLB_WIDTH 6 + +#define TLB_CI 0x1 /* clear I */ +#define TLB_CD 0x2 /* clear D */ +#define TLB_CA 0x4 /* clear all */ + +typedef struct { + uint32 tag; /* tag */ + uint8 asn; /* addr space # */ + uint8 idx; /* entry # */ + uint16 gh_mask; /* gh mask */ + uint32 pfn; /* pfn */ + uint32 pte; /* swre/pte */ + } TLBENT; + +/* Register shadow */ + +#define PALSHAD_SIZE 8 +#define PAL_USE_SHADOW \ + ev5_palsave[0] = R[8]; ev5_palsave[1] = R[9]; \ + ev5_palsave[2] = R[10]; ev5_palsave[3] = R[11]; \ + ev5_palsave[4] = R[12]; ev5_palsave[5] = R[13]; \ + ev5_palsave[6] = R[14]; ev5_palsave[7] = R[25]; \ + R[8] = ev5_palshad[0]; R[9] = ev5_palshad[1]; \ + R[10] = ev5_palshad[2]; R[11] = ev5_palshad[3]; \ + R[12] = ev5_palshad[4]; R[13] = ev5_palshad[5]; \ + R[14] = ev5_palshad[6]; R[25] = ev5_palshad[7] +#define PAL_USE_MAIN \ + ev5_palshad[0] = R[8]; ev5_palshad[1] = R[9]; \ + ev5_palshad[2] = R[10]; ev5_palshad[3] = R[11]; \ + ev5_palshad[4] = R[12]; ev5_palshad[5] = R[13]; \ + ev5_palshad[6] = R[14]; ev5_palshad[7] = R[25]; \ + R[8] = ev5_palsave[0]; R[9] = ev5_palsave[1]; \ + R[10] = ev5_palsave[2]; R[11] = ev5_palsave[3]; \ + R[12] = ev5_palsave[4]; R[13] = ev5_palsave[5]; \ + R[14] = ev5_palsave[6]; R[25] = ev5_palsave[7] + +/* PAL instructions */ + +#define HW_MFPR 0x19 +#define HW_LD 0x1B +#define HW_MTPR 0x1D +#define HW_REI 0x1E +#define HW_ST 0x1F + +#define HW_LD_V 0x8000 +#define HW_LD_ALT 0x4000 +#define HW_LD_WCH 0x2000 +#define HW_LD_Q 0x1000 +#define HW_LD_PTE 0x0800 +#define HW_LD_LCK 0x0400 +#define HW_LD_DSP 0x03FF +#define SIGN_HW_LD_DSP 0x0200 +#define HW_LD_GETDSP(x) ((x) & HW_LD_DSP) +#define SEXT_HW_LD_DSP(x) (((x) & SIGN_HW_LD_DSP)? \ + ((x) | ~((t_uint64) HW_LD_DSP)): ((x) & HW_LD_DSP)) + +#define HW_REI_S 0x4000 + +/* PAL entry offsets */ + +#define PALO_RESET 0x0000 +#define PALO_IACV 0x0080 +#define PALO_INTR 0x0100 +#define PALO_ITBM 0x0180 +#define PALO_DTBM 0x0200 +#define PALO_DTBM_D 0x0280 +#define PALO_ALGN 0x0300 +#define PALO_DFLT 0x0380 +#define PALO_MCHK 0x0400 +#define PALO_RSVI 0x0480 +#define PALO_TRAP 0x0500 +#define PALO_FDIS 0x0580 +#define PALO_CALLPR 0x2000 +#define PALO_CALLUNPR 0x3000 + +/* Special (above 1F) and normal interrupt levels */ + +#define IPL_HALT 0x40 +#define IPL_SLI 0x20 +#define IPL_1F 0x1F /* highest level */ +#define IPL_CRD 0x1F /* corrected read data */ +#define IPL_PWRFL 0x1E /* power fail */ +#define IPL_AST 0x02 /* AST interrupt level */ + +/* Internal registers */ + +#define PALTEMP_SIZE 24 + +enum ev5_internal_reg { + ISR = 0x100, ITB_TAG, ITB_PTE, ITB_ASN, + ITB_PTE_TEMP, ITB_IA, ITB_IAP, ITB_IS, + SIRR, ASTRR, ASTEN, EXC_ADDR, + EXC_SUMM, EXC_MASK, PAL_BASE, ICM, + IPLR, INTID, IFAULT_VA_FORM, IVPTBR, + HWINT_CLR = 0x115, SL_XMIT, SL_RCV, + ICSR, IC_FLUSH_CTL, ICPERR_STAT, PMCTR = 0x11C, + PALTEMP = 0x140, + DTB_ASN = 0x200, DTB_CM, DTB_TAG, DTB_PTE, + DTB_PTE_TEMP, MM_STAT, VA, VA_FORM, + MVPTBR, DTB_IAP, DTB_IA, DTB_IS, + ALTMODE, CC, CC_CTL, MCSR, + DC_FLUSH, DC_PERR_STAT = 0x212, DC_TEST_CTL, + DC_TEST_TAG, DC_TEST_TAG_TEMP, DC_MODE, MAF_MODE + }; + +/* Ibox registers */ +/* ISR - instruction summary register - read only */ + +#define ISR_V_AST 0 +#define ISR_V_SIRR 4 +#define ISR_V_ATR 19 +#define ISR_V_IRQ0 20 +#define ISR_V_IRQ1 21 +#define ISR_V_IRQ2 22 +#define ISR_V_IRQ3 23 +#define ISR_V_PFL 30 +#define ISR_V_MCHK 31 +#define ISR_V_CRD 32 +#define ISR_V_SLI 33 +#define ISR_V_HALT 34 + +#define ISR_ATR (((t_uint64) 1u) << ISR_V_ATR) +#define ISR_IRQ0 (((t_uint64) 1u) << ISR_V_IRQ0) +#define ISR_IRQ1 (((t_uint64) 1u) << ISR_V_IRQ1) +#define ISR_IRQ2 (((t_uint64) 1u) << ISR_V_IRQ2) +#define ISR_IRQ3 (((t_uint64) 1u) << ISR_V_IRQ3) +#define ISR_HALT (((t_uint64) 1u) << ISR_V_HALT) + +/* ITB_TAG - ITLB tag - write only - stores VPN (tag) of faulting address */ + +/* ITB_PTE - ITLB pte - read and write in different formats */ + +#define ITBR_PTE_V_ASM 13 +#define ITBR_PTE_ASM (1u << ITBR_PTE_V_ASM) +#define ITBR_PTE_V_KRE 18 +#define ITBR_PTE_GH0 0x00000000 +#define ITBR_PTE_GH1 0x20000000 +#define ITBR_PTE_GH2 0x60000000 +#define ITBR_PTE_GH3 0xE0000000 + +/* ITB_ASN - ITLB ASN - read write */ + +#define ITB_ASN_V_ASN 4 +#define ITB_ASN_M_ASN 0x7F +#define ITB_ASN_WIDTH 7 + +/* ITB_PTE_TEMP - ITLB PTE readout - read only */ + +/* ITB_IA, ITB_IAP, ITB_IS - ITLB invalidates - write only */ + +/* SIRR - software interrupt request register - read/write */ + +#define SIRR_V_SIRR 4 +#define SIRR_M_SIRR 0x7FFF + +/* ASTRR, ASTEN - AST request, enable registers - read/write */ + +#define AST_MASK 0xF /* AST bits */ + +/* EXC_ADDR - read/write */ + +/* EXC_SUMM - read/cleared on write */ + +/* EXC_MASK - read only */ + +/* PAL_BASE - read/write */ + +#define PAL_BASE_RW 0x000000FFFFFFFFC000 + +/* ICM - ITLB current mode - read/write */ + +#define ICM_V_CM 3 +#define ICM_M_CM 0x3 + +/* IPLR - interrupt priority level - read/write */ + +#define IPLR_V_IPL 0 +#define IPLR_M_IPL 0x1F + +/* INTID - interrupt ID - read only */ + +#define INTID_MASK 0x1F + +/* IFAULT_VA_FORM - formated fault VA - read only */ + +/* IVPTBR - virtual page table base - read/write */ + +#define IVPTBR_VMS 0xFFFFFFF800000000 +#define IVPTBR_NT 0xFFFFFFFFC0000000 +#define FMT_IVA_VMS(x) (ev5_ivptbr | (((x) >> (VA_N_OFF - 3)) & 0x1FFFFFFF8)) +#define FMT_IVA_NT(x) (ev5_ivptbr | (((x) >> (VA_N_OFF - 3)) & 0x0003FFFF8)) + +/* HWINT_CLR - hardware interrupt clear - write only */ + +#define HWINT_CLR_W1C 0x00000003C8000000 + +/* SL_XMIT - serial line transmit - write only */ + +/* SL_RCV - real line receive - read only */ + +/* ICSR - Ibox control/status - read/write */ + +#define ICSR_V_PME 8 +#define ICSR_M_PME 0x3 +#define ICSR_V_BSE 17 +#define ICSR_V_MSK0 20 +#define ICSR_V_MSK1 21 +#define ICSR_V_MSK2 22 +#define ICSR_V_MSK3 23 +#define ICSR_V_TMM 24 +#define ICSR_V_TMD 25 +#define ICSR_V_FPE 26 +#define ICSR_V_HWE 27 +#define ICSR_V_SPE 28 +#define ICSR_M_SPE 0x3 +#define ICSR_V_SDE 30 +#define ICSR_V_CRDE 32 +#define ICSR_V_SLE 33 +#define ICSR_V_FMS 34 +#define ICSR_V_FBT 35 +#define ICSR_V_FBD 36 +#define ICSR_V_BIST 38 +#define ICSR_V_TEST 39 + +#define ICSR_NT (((t_uint64) 1u) << ICSR_V_SPE) +#define ICSR_BSE (((t_uint64) 1u) << ICSR_V_BSE) +#define ICSR_MSK0 (((t_uint64) 1u) << ICSR_V_MSK0) +#define ICSR_MSK1 (((t_uint64) 1u) << ICSR_V_MSK1) +#define ICSR_MSK2 (((t_uint64) 1u) << ICSR_V_MSK2) +#define ICSR_MSK3 (((t_uint64) 1u) << ICSR_V_MSK3) +#define ICSR_HWE (((t_uint64) 1u) << ICSR_V_HWE) +#define ICSR_SDE (((t_uint64) 1u) << ICSR_V_SDE) +#define ICSR_CRDE (((t_uint64) 1u) << ICSR_V_CRDE) +#define ICSR_SLE (((t_uint64) 1u) << ICSR_V_SLE) + +#define ICSR_RW 0x0000009F4BF00300 +#define ICSR_MBO 0x0000006000000000 + +/* IC_FLUSH_CTL - Icache flush control - write only */ + +/* ICPERR_STAT - Icache parity status - read/write 1 to clear */ + +#define ICPERR_V_DPE 11 +#define ICPERR_V_TPE 12 +#define ICPERR_V_TMO 13 + +#define ICPERR_DPE (1u << ICPERR_V_DPE) +#define ICPERR_TPE (1u << ICPERR_V_TPE) +#define ICPERR_TMO (1u << ICPERR_V_TMO) + +#define ICPERR_W1C (ICPERR_DPE|ICPERR_TPE|ICPERR_TMO) + +/* Mbox registers */ +/* DTB_ASN - DTLB ASN - write only */ + +#define DTB_ASN_V_ASN 57 +#define DTB_ASN_M_ASN 0x7F +#define DTB_ASN_WIDTH 7 + +/* DTB_CM - DTLB current mode - write only */ + +#define DCM_V_CM 3 +#define DCM_M_CM 0x3 + +/* DTB_TAG - DTLB tag and update - write only */ + +/* DTB_PTE - DTLB PTE - read/write */ + +/* DTB_PTE_TEMP - DTLB PTE read out register - read only */ + +/* MM_STAT - data fault status register - read only */ + +#define MM_STAT_WR 0x00001 +#define MM_STAT_ACV 0x00002 +#define MM_STAT_FOR 0x00004 +#define MM_STAT_FOW 0x00008 +#define MM_STAT_TBM 0x00010 +#define MM_STAT_BVA 0x00020 +#define MM_STAT_V_RA 6 +#define MM_STAT_IMASK 0x1FFC0 + +/* VA - data fault virtual address - read only */ + +/* VA_FORM - data fault formated virtual address - read only */ + +#define FMT_MVA_VMS(x) (ev5_mvptbr | (((x) >> (VA_N_OFF - 3)) & 0x1FFFFFFF8)) +#define FMT_MVA_NT(x) (ev5_mvptbr | (((x) >> (VA_N_OFF - 3)) & 0x0003FFFF8)) + +/* MVPTBR - DTB virtual page table base - write only */ + +#define MVPTBR_MBZ ((t_uint64) 0x3FFFFFFF) + +/* DTB_IAP, DTB_IA, DTB_IS - DTB invalidates - write only */ + +/* ALT_MODE - DTLB current mode - write only */ + +#define ALT_V_CM 3 +#define ALT_M_CM 0x3 + +/* CC - cycle counter - upper half is RW, lower half is RO */ + +/* CC_CTL - cycle counter control - write only */ + +#define CC_CTL_ENB 0x100000000 +#define CC_CTL_MBZ 0xF + +/* MCSR - Mbox control/status register - read/write */ + +#define MCSR_RW 0x11 +#define MCSR_V_SPE 1 +#define MCSR_M_SPE 0x3 +#define MCSR_NT 0x02 + +/* DC_PERR_STAT - data cache parity error status - read/write */ + +#define DC_PERR_W1C 0x3 +#define DC_PERR_ERR 0x1C + +/* DC_MODE - data cache mode - read/write */ + +#define DC_MODE_RW 0xF + +/* MAF_MODE - miss address file mode - read/write */ + +#define MAF_MODE_RW 0xFF + +/* DC_TEST_CTL - data cache test control - read/write */ + +#define DC_TEST_CTL_RW 0x1FFFB + +/* DC_TEST_TAG - data cache test tag - read/write */ + +#define DC_TEST_TAG_RW 0x0000007FFFFFFF04 + +/* Function prototypes (TLB interface) */ + +void tlb_ia (uint32 flags); +void tlb_is (t_uint64 va, uint32 flags); +void itlb_set_asn (uint32 asn); +void itlb_set_cm (uint32 mode); +void itlb_set_spage (uint32 spage); +TLBENT *itlb_lookup (uint32 vpn); +TLBENT *itlb_load (uint32 vpn, t_uint64 pte); +t_uint64 itlb_read (void); +void dtlb_set_asn (uint32 asn); +void dtlb_set_cm (uint32 mode); +void dtlb_set_spage (uint32 spage); +TLBENT *dtlb_lookup (uint32 vpn); +TLBENT *dtlb_load (uint32 vpn, t_uint64 pte); +t_uint64 dtlb_read (void); + +#endif + diff --git a/alpha/alpha_ev5_pal.c b/alpha/alpha_ev5_pal.c new file mode 100644 index 00000000..4910b0ce --- /dev/null +++ b/alpha/alpha_ev5_pal.c @@ -0,0 +1,961 @@ +/* alpha_ev5_pal.c - Alpha EV5 PAL mode simulator + + Copyright (c) 2003-2006, 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. + + EV5 was the second generation Alpha CPU. It was a four-way, in order issue + CPU with onchip primary instruction and data caches, an onchip second level + cache, and support for an offchip third level cache. EV56 was a shrink, with + added support for byte and word operations. PCA56 was a version of EV56 + without the onchip second level cache. PCA57 was a shrink of PCA56. + + EV5 includes the usual five PALcode instructions: + + HW_LD PALcode load + HW_ST PALcode store + HW_MTPR PALcode move to internal processor register + HW_MFPR PALcode move from internal processor register + HW_REI PALcode return + + PALcode instructions can only be issued in PALmode, or in kernel mode + if the appropriate bit is set in ICSR. + + EV5 implements 8 "PAL shadow" registers, which replace R8-R14, R25 in + PALmode without save/restore; and 24 "PAL temporary" registers. + + Internal registers fall into three groups: IBox IPRs, MBox IPRs, and + PAL temporaries. +*/ + +#include "alpha_defs.h" +#include "alpha_ev5_defs.h" + +t_uint64 ev5_palshad[PALSHAD_SIZE] = { 0 }; /* PAL shadow reg */ +t_uint64 ev5_palsave[PALSHAD_SIZE] = { 0 }; /* PAL save main */ +t_uint64 ev5_paltemp[PALTEMP_SIZE] = { 0 }; /* PAL temps */ +t_uint64 ev5_palbase = 0; /* PALcode base */ +t_uint64 ev5_excaddr = 0; /* exception address */ +t_uint64 ev5_isr = 0; /* intr summary */ +t_uint64 ev5_icsr = 0; /* IBox control */ +t_uint64 ev5_itb_pte = 0; /* ITLB pte */ +t_uint64 ev5_itb_pte_temp = 0; /* ITLB readout */ +t_uint64 ev5_ivptbr = 0; /* IBox virt ptbl */ +t_uint64 ev5_iva_form = 0; /* Ibox fmt'd VA */ +t_uint64 ev5_va = 0; /* Mbox VA */ +t_uint64 ev5_mvptbr = 0; /* Mbox virt ptbl */ +t_uint64 ev5_va_form = 0; /* Mbox fmt'd VA */ +t_uint64 ev5_dtb_pte = 0; /* DTLB pte */ +t_uint64 ev5_dtb_pte_temp = 0; /* DTLB readout */ +t_uint64 ev5_dc_test_tag = 0; /* Dcache test tag */ +t_uint64 ev5_dc_test_tag_temp = 0; /* Dcache tag readout */ +uint32 ev5_itb_tag = 0; /* ITLB tag (vpn) */ +uint32 ev5_dtb_tag = 0; /* DTLB tag (vpn) */ +uint32 ev5_icperr = 0; /* Icache par err */ +uint32 ev5_mm_stat = 0; /* MBox fault code */ +uint32 ev5_mcsr = 0; /* MBox control */ +uint32 ev5_alt_mode = 0; /* MBox alt mode */ +uint32 ev5_dc_mode = 0; /* Dcache mode */ +uint32 ev5_dcperr = 0; /* Dcache par err */ +uint32 ev5_dc_test_ctl = 0; /* Dcache test ctrl */ +uint32 ev5_maf_mode = 0; /* MAF mode */ +uint32 ev5_va_lock = 0; /* VA lock flag */ +uint32 ev5_mchk = 0; /* machine check pin */ +uint32 ev5_sli = 0; /* serial line intr */ +uint32 ev5_crd = 0; /* corr read data pin */ +uint32 ev5_pwrfl = 0; /* power fail pin */ +uint32 ev5_ipl = 0; /* ipl */ +uint32 ev5_sirr = 0; /* software int req */ +uint32 ev5_astrr = 0; /* AST requests */ +uint32 ev5_asten = 0; /* AST enables */ +const uint32 ast_map[4] = { 0x1, 0x3, 0x7, 0xF }; + +t_stat ev5_palent (t_uint64 fpc, uint32 off); +t_stat ev5_palent_d (t_uint64 fpc, uint32 off, uint32 sta); +t_stat pal_proc_reset_hwre (DEVICE *dptr); +t_stat pal_proc_intr_ev5 (uint32 lvl); +uint32 pal_eval_intr_ev5 (uint32 flag); + +extern t_uint64 R[32]; +extern t_uint64 PC; +extern t_uint64 trap_mask; +extern t_uint64 p1; +extern uint32 ir; +extern uint32 vax_flag, lock_flag; +extern uint32 fpen; +extern uint32 pcc_h, pcc_l, pcc_enb; +extern uint32 trap_summ; +extern uint32 arch_mask; +extern uint32 pal_mode, pal_type; +extern uint32 int_req[IPL_HLVL]; +extern uint32 itlb_cm, dtlb_cm; +extern uint32 itlb_asn, dtlb_asn; +extern uint32 itlb_spage, dtlb_spage; +extern jmp_buf save_env; +extern uint32 pal_type; +extern t_uint64 pcq[PCQ_SIZE]; /* PC queue */ +extern int32 pcq_p; /* PC queue ptr */ + +extern int32 parse_reg (char *cptr); + +/* EV5PAL data structures + + ev5pal_dev device descriptor + ev5pal_unit unit + ev5pal_reg register list +*/ + +UNIT ev5pal_unit = { UDATA (NULL, 0, 0) }; + +REG ev5pal_reg[] = { + { BRDATA (PALSHAD, ev5_palshad, 16, 64, PALSHAD_SIZE) }, + { BRDATA (PALSAVE, ev5_palsave, 16, 64, PALSHAD_SIZE) }, + { BRDATA (PALTEMP, ev5_paltemp, 16, 64, PALTEMP_SIZE) }, + { HRDATA (PALBASE, ev5_palbase, 64) }, + { HRDATA (EXCADDR, ev5_excaddr, 64) }, + { HRDATA (IPL, ev5_ipl, 5) }, + { HRDATA (SIRR, ev5_sirr, 15) }, + { HRDATA (ASTRR, ev5_astrr, 4) }, + { HRDATA (ASTEN, ev5_asten, 4) }, + { HRDATA (ISR, ev5_isr, 35) }, + { HRDATA (ICSR, ev5_icsr, 40) }, + { HRDATA (ITB_TAG, ev5_itb_tag, 32) }, + { HRDATA (ITB_PTE, ev5_itb_pte, 64) }, + { HRDATA (ITB_PTE_TEMP, ev5_itb_pte_temp, 64) }, + { HRDATA (IVA_FORM, ev5_iva_form, 64) }, + { HRDATA (IVPTBR, ev5_ivptbr, 64) }, + { HRDATA (ICPERR_STAT, ev5_icperr, 14) }, + { HRDATA (VA, ev5_va, 64) }, + { HRDATA (VA_FORM, ev5_va_form, 64) }, + { HRDATA (MVPTBR, ev5_mvptbr, 64) }, + { HRDATA (MM_STAT, ev5_mm_stat, 17) }, + { HRDATA (MCSR, ev5_mcsr, 6) }, + { HRDATA (DTB_TAG, ev5_dtb_tag, 32) }, + { HRDATA (DTB_PTE, ev5_dtb_pte, 64) }, + { HRDATA (DTB_PTE_TEMP, ev5_dtb_pte_temp, 64) }, + { HRDATA (DC_MODE, ev5_dc_mode, 4) }, + { HRDATA (DC_PERR_STAT, ev5_dcperr, 6) }, + { HRDATA (DC_TEST_CTL, ev5_dc_test_ctl, 13) }, + { HRDATA (DC_TEST_TAG, ev5_dc_test_tag, 39) }, + { HRDATA (DC_TEST_TAG_TEMP, ev5_dc_test_tag_temp, 39) }, + { HRDATA (MAF_MODE, ev5_maf_mode, 8) }, + { FLDATA (VA_LOCK, ev5_va_lock, 0) }, + { FLDATA (MCHK, ev5_mchk, 0) }, + { FLDATA (CRD, ev5_crd, 0) }, + { FLDATA (PWRFL, ev5_pwrfl, 0) }, + { FLDATA (SLI, ev5_sli, 0) }, + { NULL } + }; + +DEVICE ev5pal_dev = { + "EV5PAL", &ev5pal_unit, ev5pal_reg, NULL, + 1, 16, 1, 1, 16, 8, + NULL, NULL, &pal_proc_reset_hwre, + NULL, NULL, NULL, + NULL, DEV_DIS + }; + +/* EV5 interrupt dispatch - reached from top of instruction loop - + dispatch to PALcode */ + +t_stat pal_proc_intr (uint32 lvl) +{ +return ev5_palent (PC, PALO_INTR); +} + +/* EV5 trap dispatch - reached from bottom of instruction loop - + trap_mask and trap_summ are set up correctly - dispatch to PALcode */ + +t_stat pal_proc_trap (uint32 summ) +{ +return ev5_palent (PC, PALO_TRAP); +} + +/* EV5 exception dispatch - reached from ABORT handler - + set up any exception-specific registers - dispatch to PALcode */ + +t_stat pal_proc_excp (uint32 abval) +{ +switch (abval) { + + case EXC_RSVI: /* reserved instruction */ + return ev5_palent (PC, PALO_RSVI); + + case EXC_ALIGN: /* unaligned */ + return ev5_palent (PC, PALO_ALGN); + + case EXC_FPDIS: /* fp disabled */ + return ev5_palent (PC, PALO_FDIS); + + case EXC_FOX+EXC_R: /* FOR */ + return ev5_palent_d (PC, PALO_DFLT, MM_STAT_FOR); + + case EXC_FOX+EXC_W: /* FOW */ + return ev5_palent_d (PC, PALO_DFLT, MM_STAT_FOR|MM_STAT_WR); + + case EXC_BVA+EXC_E: /* instr bad VA */ + case EXC_ACV+EXC_E: /* instr ACV */ + ev5_itb_tag = VA_GETVPN (PC); /* fault VPN */ + if (ev5_icsr & ICSR_NT) /* formatted addr */ + ev5_iva_form = ev5_ivptbr | FMT_IVA_NT (PC); + else ev5_iva_form = ev5_ivptbr | FMT_IVA_VMS (PC); + return ev5_palent (PC, PALO_IACV); + + case EXC_ACV+EXC_R: /* data read ACV */ + return ev5_palent_d (PC, PALO_DFLT, MM_STAT_ACV); + + case EXC_ACV+EXC_W: /* data write ACV */ + return ev5_palent_d (PC, PALO_DFLT, MM_STAT_ACV|MM_STAT_WR); + + case EXC_BVA+EXC_R: /* data read bad addr */ + return ev5_palent_d (PC, PALO_DFLT, MM_STAT_BVA); + + case EXC_BVA+EXC_W: /* data write bad addr */ + return ev5_palent_d (PC, PALO_DFLT, MM_STAT_BVA|MM_STAT_WR); + + case EXC_TBM + EXC_E: /* TLB miss */ + ev5_itb_tag = VA_GETVPN (PC); /* fault VPN */ + if (ev5_icsr & ICSR_NT) /* formatted addr */ + ev5_iva_form = ev5_ivptbr | FMT_IVA_NT (PC); + else ev5_iva_form = ev5_ivptbr | FMT_IVA_VMS (PC); + return ev5_palent (PC, PALO_ITBM); + + case EXC_TBM + EXC_R: /* data TB miss read */ + if ((I_GETOP (ir) == HW_LD) && (ir & HW_LD_PTE)) + return ev5_palent_d (PC, PALO_DTBM_D, MM_STAT_TBM); + return ev5_palent_d (PC, PALO_DTBM, MM_STAT_TBM); + + case EXC_TBM + EXC_W: /* data TB miss write */ + if ((I_GETOP (ir) == HW_LD) && (ir & HW_LD_PTE)) + return ev5_palent_d (PC, PALO_DTBM_D, MM_STAT_TBM|MM_STAT_WR); + return ev5_palent_d (PC, PALO_DTBM, MM_STAT_TBM|MM_STAT_WR); + + case EXC_RSVO: /* reserved operand */ + case EXC_TNV+EXC_E: /* instr TNV */ + case EXC_TNV+EXC_R: /* data read TNV */ + case EXC_TNV+EXC_W: /* data write TNV */ + case EXC_FOX+EXC_E: /* FOE */ + return SCPE_IERR; /* should never get here */ + + default: + return STOP_INVABO; + } + +return SCPE_OK; +} + +/* EV5 call PAL - reached from instruction decoder - + compute offset from function code - dispatch to PALcode */ + +t_stat pal_proc_inst (uint32 fnc) +{ +uint32 off = (fnc & 0x3F) << 6; + +if (fnc & 0x80) return ev5_palent (PC, PALO_CALLUNPR + off); +if (itlb_cm != MODE_K) ABORT (EXC_RSVI); +return ev5_palent (PC, PALO_CALLPR + off); +} + +/* EV5 evaluate interrupts - returns highest outstanding + interrupt level about target ipl - plus nonmaskable flags + + flag = 1: evaluate for real interrupt capability + flag = 0: evaluate as though IPL = 0, normal mode */ + +uint32 pal_eval_intr (uint32 flag) +{ +uint32 i, req = 0; +uint32 lvl = flag? ev5_ipl: 0; + +if (flag && pal_mode) return 0; +if (ev5_mchk) req = IPL_1F; +else if (ev5_crd && (ICSR & ICSR_CRDE)) req = IPL_CRD; +else if (ev5_pwrfl) req = IPL_PWRFL; +else if (int_req[3] && !(ICSR & ICSR_MSK3)) req = IPL_HMIN + 3; +else if (int_req[2] && !(ICSR & ICSR_MSK2)) req = IPL_HMIN + 2; +else if (int_req[1] && !(ICSR & ICSR_MSK1)) req = IPL_HMIN + 1; +else if (int_req[0] && !(ICSR & ICSR_MSK0)) req = IPL_HMIN + 0; +else if (ev5_sirr) { + for (i = IPL_SMAX; i > 0; i--) { /* check swre int */ + if ((ev5_sirr >> (i - 1)) & 1) { /* req != 0? int */ + req = i; + break; + } + } + } +if ((req < IPL_AST) && (ev5_astrr & ev5_asten & ast_map[itlb_cm])) + req = IPL_AST; +if (req <= lvl) req = 0; +if (ev5_sli && (ICSR & ICSR_SLE)) req = req | IPL_SLI; +if (ev5_isr & ISR_HALT) req = req | IPL_HALT; +return req; +} + +/* EV5 enter PAL, data TLB miss/memory management flows - + set Mbox registers - dispatch to PALcode */ + +t_stat ev5_palent_d (t_uint64 fpc, uint32 off, uint32 sta) +{ +if (!ev5_va_lock) { /* not locked? */ + ev5_mm_stat = sta | /* merge IR<31:21> */ + ((ir >> (I_V_RA - MM_STAT_V_RA)) & MM_STAT_IMASK); + ev5_va = p1; /* fault address */ + if (ev5_mcsr & MCSR_NT) /* formatted VA */ + ev5_va_form = ev5_mvptbr | FMT_MVA_NT (p1); + else ev5_va_form = ev5_mvptbr | FMT_MVA_VMS (p1); + ev5_va_lock = 1; /* lock registers */ + } +return ev5_palent (fpc, off); +} + +/* EV5 enter PAL */ + +t_stat ev5_palent (t_uint64 fpc, uint32 off) +{ +ev5_excaddr = fpc | pal_mode; /* save exc addr */ +PCQ_ENTRY; /* save PC */ +PC = ev5_palbase + off; /* new PC */ +if (!pal_mode && (ev5_icsr & ICSR_SDE)) { /* entering PALmode? */ + PAL_USE_SHADOW; /* swap in shadows */ + } +pal_mode = 1; /* in PAL mode */ +return SCPE_OK; +} + +/* PAL instructions */ + +/* 1B: HW_LD */ + +t_stat pal_1b (uint32 ir) +{ +t_uint64 dsp, ea, res; +uint32 ra, rb, acc, mode; + +if (!pal_mode && (!(itlb_cm == MODE_K) || /* pal mode, or kernel */ + !(ev5_icsr & ICSR_HWE))) ABORT (EXC_RSVI); /* and enabled? */ +ra = I_GETRA (ir); /* get ra */ +rb = I_GETRB (ir); /* get rb */ +dsp = HW_LD_GETDSP (ir); /* get displacement */ +ea = (R[rb] + (SEXT_HW_LD_DSP (dsp))) & M64; /* eff address */ +if (ir & HW_LD_V) { /* virtual? */ + mode = (ir & HW_LD_ALT)? ev5_alt_mode: dtlb_cm; /* access mode */ + acc = (ir & HW_LD_WCH)? ACC_W (mode): ACC_R (mode); + if (ir & HW_LD_Q) res = ReadAccQ (ea, acc); /* quad? */ + else { /* long, sext */ + res = ReadAccL (ea, acc); + res = SEXT_L_Q (res); + } + } +else if (ir & HW_LD_Q) R[ra] = ReadPQ (ea); /* physical, quad? */ +else { + res = ReadPL (ea); /* long, sext */ + res = SEXT_L_Q (res); + } +if (ir & HW_LD_LCK) lock_flag = 1; /* lock? set flag */ +if (ra != 31) R[ra] = res; /* if not R31, store */ +return SCPE_OK; +} + +/* 1F: HW_ST */ + +t_stat pal_1f (uint32 ir) +{ +t_uint64 dsp, ea; +uint32 ra, rb, acc, mode; + +if (!pal_mode && (!(itlb_cm == MODE_K) || /* pal mode, or kernel */ + !(ev5_icsr & ICSR_HWE))) ABORT (EXC_RSVI); /* and enabled? */ +ra = I_GETRA (ir); /* get ra */ +rb = I_GETRB (ir); /* get rb */ +dsp = HW_LD_GETDSP (ir); /* get displacement */ +ea = (R[rb] + (SEXT_HW_LD_DSP (dsp))) & M64; /* eff address */ +if ((ir & HW_LD_LCK) && !lock_flag) R[ra] = 0; /* lock fail? */ +else { + if (ir & HW_LD_V) { /* virtual? */ + mode = (ir & HW_LD_ALT)? ev5_alt_mode: dtlb_cm; /* access mode */ + acc = ACC_W (mode); + if (ir & HW_LD_Q) WriteAccQ (ea, R[ra], acc); /* quad? */ + else WriteAccL (ea, R[ra], acc); /* long */ + } + else if (ir & HW_LD_Q) WritePQ (ea, R[ra]); /* physical, quad? */ + else WritePL (ea, R[ra]); /* long */ + if (ir & HW_LD_LCK) lock_flag = 0; /* unlock? clr flag */ + } +return SCPE_OK; +} + +/* 1E: HW_REI */ + +t_stat pal_1e (uint32 ir) +{ +uint32 new_pal = ((uint32) ev5_excaddr) & 1; + +if (!pal_mode && (!(itlb_cm == MODE_K) || /* pal mode, or kernel */ + !(ev5_icsr & ICSR_HWE))) ABORT (EXC_RSVI); /* and enabled? */ +PCQ_ENTRY; +PC = ev5_excaddr; +if (pal_mode && !new_pal && (ev5_icsr & ICSR_SDE)) { /* leaving PAL mode? */ + PAL_USE_MAIN; /* swap out shadows */ + } +pal_mode = new_pal; +return SCPE_OK; +} + +/* PAL move from processor registers */ + +t_stat pal_19 (uint32 ir) +{ +t_uint64 res; +uint32 fnc, ra; +static const uint32 itbr_map_gh[4] = { + ITBR_PTE_GH0, ITBR_PTE_GH1, ITBR_PTE_GH2, ITBR_PTE_GH3 }; + +if (!pal_mode && (!(itlb_cm == MODE_K) || /* pal mode, or kernel */ + !(ev5_icsr & ICSR_HWE))) ABORT (EXC_RSVI); /* and enabled? */ +fnc = I_GETMDSP (ir); +ra = I_GETRA (ir); +switch (fnc) { + + case ISR: /* intr summary */ + res = ev5_isr | ((ev5_astrr & ev5_asten) << ISR_V_AST) | + ((ev5_sirr & SIRR_M_SIRR) << ISR_V_SIRR) | + (int_req[0] && !(ev5_icsr & ICSR_MSK0)? ISR_IRQ0: 0) | + (int_req[1] && !(ev5_icsr & ICSR_MSK1)? ISR_IRQ1: 0) | + (int_req[2] && !(ev5_icsr & ICSR_MSK2)? ISR_IRQ2: 0) | + (int_req[3] && !(ev5_icsr & ICSR_MSK3)? ISR_IRQ3: 0); + if (ev5_astrr & ev5_asten & ast_map[itlb_cm]) res = res | ISR_ATR; + break; + + case ITB_PTE: + res = itlb_read (); + ev5_itb_pte_temp = (res & PFN_MASK) | + ((res & PTE_ASM)? ITBR_PTE_ASM: 0) | + ((res & (PTE_KRE|PTE_ERE|PTE_SRE|PTE_URE)) << + (ITBR_PTE_V_KRE - PTE_V_KRE)) | + itbr_map_gh[PTE_GETGH (res)]; + res = 0; + break; + + case ITB_ASN: + res = (itlb_asn & ITB_ASN_M_ASN) << ITB_ASN_V_ASN; + break; + + case ITB_PTE_TEMP: + res = ev5_itb_pte_temp; + break; + + case SIRR: + res = (ev5_sirr & SIRR_M_SIRR) << SIRR_V_SIRR; + break; + + case ASTRR: + res = ev5_astrr & AST_MASK; + break; + + case ASTEN: + res = ev5_asten & AST_MASK; + break; + + case EXC_ADDR: + res = ev5_excaddr; + break; + + case EXC_SUMM: + res = trap_summ & TRAP_SUMM_RW; + break; + + case EXC_MASK: + res = trap_mask; + break; + + case PAL_BASE: + res = ev5_palbase & PAL_BASE_RW; + break; + + case ICM: + res = (itlb_cm & ICM_M_CM) << ICM_V_CM; + break; + + case IPLR: + res = (ev5_ipl & IPLR_M_IPL) << IPLR_V_IPL; + break; + + case INTID: + res = pal_eval_intr (0) & INTID_MASK; + break; + + case IFAULT_VA_FORM: + res = ev5_iva_form; + break; + + case IVPTBR: + res = ev5_ivptbr; + break; + + case ICSR: + res = (ev5_icsr & ICSR_RW) | ICSR_MBO | + ((itlb_spage & ICSR_M_SPE) << ICSR_V_SPE) | + ((fpen & 1) << ICSR_V_FPE) | + ((arch_mask & AMASK_BWX)? ICSR_BSE: 0); + break; + + case PALTEMP+0x00: case PALTEMP+0x01: case PALTEMP+0x02: case PALTEMP+0x03: + case PALTEMP+0x04: case PALTEMP+0x05: case PALTEMP+0x06: case PALTEMP+0x07: + case PALTEMP+0x08: case PALTEMP+0x09: case PALTEMP+0x0A: case PALTEMP+0x0B: + case PALTEMP+0x0C: case PALTEMP+0x0D: case PALTEMP+0x0E: case PALTEMP+0x0F: + case PALTEMP+0x10: case PALTEMP+0x11: case PALTEMP+0x12: case PALTEMP+0x13: + case PALTEMP+0x14: case PALTEMP+0x15: case PALTEMP+0x16: case PALTEMP+0x17: + res = ev5_paltemp[fnc - PALTEMP]; + break; + + case DTB_PTE: + ev5_dtb_pte_temp = dtlb_read (); + res = 0; + break; + + case DTB_PTE_TEMP: + res = ev5_dtb_pte_temp; + break; + + case MM_STAT: + res = ev5_mm_stat; + break; + + case VA: + res = ev5_va; + ev5_va_lock = 0; + break; + + case VA_FORM: + res = ev5_va_form; + break; + + case DC_PERR_STAT: + res = ev5_dcperr; + break; + + case MCSR: + res = (ev5_mcsr & MCSR_RW) | ((dtlb_spage & MCSR_M_SPE) << MCSR_V_SPE); + break; + + case DC_MODE: + res = ev5_dc_mode & DC_MODE_RW; + break; + + case MAF_MODE: + res = ev5_maf_mode & MAF_MODE_RW; + break; + + case CC: + res = (((t_uint64) pcc_h) << 32) | ((t_uint64) pcc_l); + break; + + case DC_TEST_CTL: + res = ev5_dc_test_ctl & DC_TEST_CTL_RW; + break; + + case DC_TEST_TAG: + // to be determined + res = 0; + break; + + case DC_TEST_TAG_TEMP: + res = ev5_dc_test_tag_temp & DC_TEST_TAG_RW; + break; + + default: + res = 0; + break; + } + +if (ra != 31) R[ra] = res & M64; +return SCPE_OK; +} + +/* PAL move to processor registers */ + +t_stat pal_1d (uint32 ir) +{ +uint32 fnc = I_GETMDSP (ir); +uint32 ra = I_GETRA (ir); +t_uint64 val = R[ra]; + +if (!pal_mode && (!(itlb_cm == MODE_K) || /* pal mode, or kernel */ + !(ev5_icsr & ICSR_HWE))) ABORT (EXC_RSVI); /* and enabled? */ +switch (fnc) { + + case ITB_TAG: + ev5_itb_tag = VA_GETVPN (val); + break; + + case ITB_PTE: + ev5_itb_pte = (val | PTE_V) & (PFN_MASK | ((t_uint64) (PTE_ASM | PTE_GH | + PTE_KRE | PTE_ERE | PTE_SRE | PTE_URE))); + itlb_load (ev5_itb_tag, ev5_itb_pte); + break; + + case ITB_ASN: + itlb_set_asn ((((uint32) val) >> ITB_ASN_V_ASN) & ITB_ASN_M_ASN); + break; + + case ITB_IA: + tlb_ia (TLB_CI | TLB_CA); + break; + + case ITB_IAP: + tlb_ia (TLB_CI); + break; + + case ITB_IS: + tlb_is (val, TLB_CI); + break; + + case SIRR: + ev5_sirr = (((uint32) val) >> SIRR_V_SIRR) & SIRR_M_SIRR; + break; + + case ASTRR: + ev5_astrr = ((uint32) val) & AST_MASK; + break; + + case ASTEN: + ev5_asten = ((uint32) val) & AST_MASK; + break; + + case EXC_ADDR: + ev5_excaddr = val; + break; + + case EXC_SUMM: + trap_summ = 0; + trap_mask = 0; + break; + + case PAL_BASE: + ev5_palbase = val & PAL_BASE_RW; + break; + + case ICM: + itlb_set_cm ((((uint32) val) >> ICM_V_CM) & ICM_M_CM); + break; + + case IPLR: + ev5_ipl = (((uint32) val) >> IPLR_V_IPL) & IPLR_M_IPL; + break; + + case IVPTBR: + if (ev5_icsr & ICSR_NT) ev5_ivptbr = val & IVPTBR_NT; + else ev5_ivptbr = val & IVPTBR_VMS; + break; + + case HWINT_CLR: + ev5_isr = ev5_isr & ~(val & HWINT_CLR_W1C); + break; + + case ICSR: + if (pal_mode && ((val ^ ev5_icsr) & ICSR_SDE)) { + if (val & ICSR_SDE) { PAL_USE_SHADOW; } + else { PAL_USE_MAIN; } + } + ev5_icsr = val & ICSR_RW; + itlb_set_spage ((((uint32) val) >> ICSR_V_SPE) & ICSR_M_SPE); + fpen = (((uint32) val) >> ICSR_V_FPE) & 1; + if (val & ICSR_BSE) arch_mask = arch_mask | AMASK_BWX; + else arch_mask = arch_mask & ~AMASK_BWX; + break; + + case ICPERR_STAT: + ev5_icperr = ev5_icperr & ~(((uint32) val) & ICPERR_W1C); + break; + + case PALTEMP+0x00: case PALTEMP+0x01: case PALTEMP+0x02: case PALTEMP+0x03: + case PALTEMP+0x04: case PALTEMP+0x05: case PALTEMP+0x06: case PALTEMP+0x07: + case PALTEMP+0x08: case PALTEMP+0x09: case PALTEMP+0x0A: case PALTEMP+0x0B: + case PALTEMP+0x0C: case PALTEMP+0x0D: case PALTEMP+0x0E: case PALTEMP+0x0F: + case PALTEMP+0x10: case PALTEMP+0x11: case PALTEMP+0x12: case PALTEMP+0x13: + case PALTEMP+0x14: case PALTEMP+0x15: case PALTEMP+0x16: case PALTEMP+0x17: + ev5_paltemp[fnc - PALTEMP] = val; + break; + + case DTB_ASN: + dtlb_set_asn (((uint32) (val >> DTB_ASN_V_ASN)) & DTB_ASN_M_ASN); + break; + + case DTB_CM: + dtlb_set_cm (((uint32) (val >> ICM_V_CM)) & ICM_M_CM); + break; + + case DTB_TAG: + ev5_dtb_tag = VA_GETVPN (val); + val = (val | PTE_V) & (PFN_MASK | ((t_uint64) (PTE_MASK & ~PTE_FOE))); + dtlb_load (ev5_dtb_tag, val); + break; + + case DTB_PTE: + ev5_dtb_pte = val; + break; + + case MVPTBR: + ev5_mvptbr = val & ~MVPTBR_MBZ; + break; + + case DC_PERR_STAT: + ev5_dcperr = ev5_dcperr & ~(((uint32) val) & DC_PERR_W1C); + if ((ev5_dcperr & DC_PERR_W1C) == 0) ev5_dcperr = 0; + break; + + case DTB_IA: + tlb_ia (TLB_CD | TLB_CA); + break; + + case DTB_IAP: + tlb_ia (TLB_CD); + break; + + case DTB_IS: + tlb_is (val, TLB_CD); + break; + + case MCSR: + ev5_mcsr = ((uint32) val) & MCSR_RW; + dtlb_set_spage ((((uint32) val) >> MCSR_V_SPE) & MCSR_M_SPE); + if (ev5_mcsr & MCSR_NT) pal_type = PAL_NT; + break; + + case DC_MODE: + ev5_dc_mode = ((uint32) val) & DC_MODE_RW; + break; + + case MAF_MODE: + ev5_maf_mode = ((uint32) val) & MAF_MODE_RW; + break; + + case CC: + pcc_h = (uint32) ((val >> 32) & M32); + break; + + case CC_CTL: + pcc_l = ((uint32) val) & (M32 & ~CC_CTL_MBZ); + if (val & CC_CTL_ENB) pcc_enb = 1; + else pcc_enb = 0; + break; + + case DC_TEST_CTL: + ev5_dc_test_ctl = ((uint32) val) & DC_TEST_CTL_RW; + break; + + case DC_TEST_TAG: + ev5_dc_test_tag = val & DC_TEST_TAG_RW; + break; + + default: + break; + } + +return SCPE_OK; +} + +/* EV5 PALcode reset */ + +t_stat pal_proc_reset_hwre (DEVICE *dptr) +{ +ev5_palbase = 0; +ev5_mchk = 0; +ev5_pwrfl = 0; +ev5_crd = 0; +ev5_sli = 0; +itlb_set_cm (MODE_K); +itlb_set_asn (0); +itlb_set_spage (0); +dtlb_set_cm (MODE_K); +dtlb_set_asn (0); +dtlb_set_spage (0); +return SCPE_OK; +} + +/* EV5 PAL instruction print and parse routines */ + +static const char *pal_inam[] = { + "HW_MFPR", "HW_LD", "HW_MTPR", "HW_REI", "HW_ST", NULL + }; + +static const uint32 pal_ival[] = { + 0x64000000, 0x6C000000, 0x74000000, 0x7BFF8000, 0x7C000000 + }; + +struct pal_opt { + uint32 mask; /* bit mask */ + char let; /* matching letter */ + }; + +static struct pal_opt ld_st_opt[] = { + { HW_LD_V, 'V' }, + { HW_LD_ALT, 'A' }, + { HW_LD_WCH, 'W' }, + { HW_LD_Q, 'Q' }, + { HW_LD_PTE, 'P' }, + { HW_LD_LCK, 'L' }, + { 0 } + }; + +static struct pal_opt rei_opt[] = { + { HW_REI_S, 'S' }, + { 0 } + }; + +/* Print options for hardware PAL instruction */ + +void fprint_opt_ev5 (FILE *of, uint32 inst, struct pal_opt opt[]) +{ +uint32 i; + +for (i = 0; opt[i].mask != 0; i++) { + if (inst & opt[i].mask) { + fprintf (of, "/%c", opt[i].let); + inst = inst & ~opt[i].mask; + } + } +return; +} + +/* Parse options for hardware PAL instruction */ + +char *parse_opt_ev5 (char *cptr, uint32 *val, struct pal_opt opt[]) +{ +uint32 i; +char *tptr, gbuf[CBUFSIZE]; + +if (*(cptr - 1) != '/') return cptr; +cptr = get_glyph (cptr - 1, tptr = gbuf, 0); +while (*tptr == '/') { + tptr++; + for (i = 0; opt[i].mask != 0; i++) { + if (*tptr == opt[i].let) { + *val = *val | opt[i].mask; + break; + } + } + if (opt[i].mask == 0) return NULL; + tptr++; + } +if (*tptr != 0) return NULL; +return cptr; +} + +/* Print PAL hardware opcode symbolically */ + +t_stat fprint_pal_hwre (FILE *of, uint32 inst) +{ +uint32 op, ra, rb; + +op = I_GETOP (inst); +ra = I_GETRA (inst); +rb = I_GETRB (inst); +switch (op) { + + case OP_PAL19: /* HW_MFPR */ + case OP_PAL1D: /* HW_MTPR */ + fputs ((op == OP_PAL19)? "HW_MFPR": "HW_MTPR", of); + fprintf (of, " R%d,%X", ra, inst & M16); + break; + + case OP_PAL1B: /* HW_LD */ + case OP_PAL1F: /* HW_ST */ + fputs ((op == OP_PAL1B)? "HW_LD": "HW_ST", of); + fprint_opt_ev5 (of, inst, ld_st_opt); + fprintf (of, " R%d,%X", ra, inst & HW_LD_DSP); + if (rb != 31) fprintf (of, "(R%d)", rb); + break; + + case OP_PAL1E: /* HW_REI */ + fputs ("HW_REI", of); + fprint_opt_ev5 (of, inst, rei_opt); + break; + + default: + return SCPE_ARG; + } + +return -3; +} + +/* Parse PAL hardware opcode symbolically */ + +t_stat parse_pal_hwre (char *cptr, t_value *inst) +{ +uint32 i, d, val = 0; +int32 reg; +char *tptr, gbuf[CBUFSIZE]; +t_stat r; + +cptr = get_glyph (cptr, gbuf, '/'); +for (i = 0; pal_inam[i] != NULL; i++) { + if (strcmp (gbuf, pal_inam[i]) == 0) val = pal_ival[i]; + } +if (val == 0) return SCPE_ARG; +switch (I_GETOP (val)) { + + case OP_PAL19: /* HW_MFPR */ + case OP_PAL1D: /* HW_MTPR */ + if (*(cptr - 1) == '/') return SCPE_ARG; + cptr = get_glyph (cptr, gbuf, ','); /* get reg */ + if ((reg = parse_reg (gbuf)) < 0) return SCPE_ARG; + val = val | (reg << I_V_RA) | (reg << I_V_RB); + cptr = get_glyph (cptr, gbuf, 0); /* get ipr */ + d = (uint32) get_uint (gbuf, 16, M16, &r); + if (r != SCPE_OK) return r; + val = val | d; + break; + + case OP_PAL1B: /* HW_LD */ + case OP_PAL1F: /* HW_ST */ + cptr = parse_opt_ev5 (cptr, &val, ld_st_opt); + if (cptr == NULL) return SCPE_ARG; + cptr = get_glyph (cptr, gbuf, ','); /* get reg */ + if ((reg = parse_reg (gbuf)) < 0) return SCPE_ARG; + val = val | (reg << I_V_RA); + cptr = get_glyph (cptr, gbuf, 0); + d = (uint32) strtotv (gbuf, &tptr, 16); + if ((gbuf == tptr) || (d > HW_LD_DSP)) return SCPE_ARG; + val = val | d; + if (*tptr == '(') { + tptr = get_glyph (tptr + 1, gbuf, ')'); + if ((reg = parse_reg (gbuf)) < 0) return SCPE_ARG; + val = val | (reg << I_V_RB); + } + else val = val | (31 << I_V_RB); + break; + + case OP_PAL1E: /* HW_REI */ + cptr = parse_opt_ev5 (cptr, &val, rei_opt); + if (cptr == NULL) return SCPE_ARG; + break; + + default: + return SCPE_ARG; + } + +*inst = val; +if (*cptr != 0) return SCPE_ARG; +return -3; +} + diff --git a/alpha/alpha_ev5_tlb.c b/alpha/alpha_ev5_tlb.c new file mode 100644 index 00000000..9cfded4a --- /dev/null +++ b/alpha/alpha_ev5_tlb.c @@ -0,0 +1,566 @@ +/* alpha_ev5_tlb.c - Alpha EV5 TLB simulator + + Copyright (c) 2003-2006, 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. + + EV5 was the second generation Alpha CPU. It was a four-way, in order issue + CPU with onchip primary instruction and data caches, an onchip second level + cache, and support for an offchip third level cache. EV56 was a shrink, with + added support for byte and word operations. EV56PC was a version of EV56 + without the onchip second level cache. + + This module contains the routines for + + itlb_lookup lookup vpn in instruction TLB + itlb_load load pte into instruction TLB + itlb_read read pte from instruction TLB using NLU pointer + itlb_set_asn set iasn + itlb_set_cm set icm + itlb_set_spage set ispage + dtlb_lookup lookup vpn in data TLB + dtlb_load load pte into data TLB + dtlb_read read pte from data TLB using NLU pointer + dtlb_set_asn set dasn + dtlb_set_cm set dcm + dtlb_set_spage set dspage + tlb_ia TLB invalidate all + tlb_is TLB invalidate single + tlb_set_cm TLB set current mode +*/ + +#include "alpha_defs.h" +#include "alpha_ev5_defs.h" + +#define ITLB_SORT qsort (itlb, ITLB_SIZE, sizeof (TLBENT), &tlb_comp); +#define DTLB_SORT qsort (dtlb, DTLB_SIZE, sizeof (TLBENT), &tlb_comp); +#define TLB_ESIZE (sizeof (TLBENT)/sizeof (uint32)) +#define MM_RW(x) (((x) & PTE_FOW)? EXC_W: EXC_R) + +uint32 itlb_cm = 0; /* current modes */ +uint32 itlb_spage = 0; /* superpage enables */ +uint32 itlb_asn = 0; +uint32 itlb_nlu = 0; +TLBENT i_mini_tlb; +TLBENT itlb[ITLB_SIZE]; +uint32 dtlb_cm = 0; +uint32 dtlb_spage = 0; +uint32 dtlb_asn = 0; +uint32 dtlb_nlu = 0; +TLBENT d_mini_tlb; +TLBENT dtlb[DTLB_SIZE]; + +uint32 cm_eacc = ACC_E (MODE_K); /* precomputed */ +uint32 cm_racc = ACC_R (MODE_K); /* access checks */ +uint32 cm_wacc = ACC_W (MODE_K); +uint32 cm_macc = ACC_M (MODE_K); + +extern t_uint64 p1; +extern jmp_buf save_env; + +uint32 mm_exc (uint32 macc); +void tlb_inval (TLBENT *tlbp); +t_stat itlb_reset (void); +t_stat dtlb_reset (void); +int tlb_comp (const void *e1, const void *e2); +t_stat tlb_reset (DEVICE *dptr); + +/* TLB data structures + + tlb_dev pager device descriptor + tlb_unit pager units + tlb_reg pager register list +*/ + +UNIT tlb_unit = { UDATA (NULL, 0, 0) }; + +REG tlb_reg[] = { + { HRDATA (ICM, itlb_cm, 2) }, + { HRDATA (ISPAGE, itlb_spage, 2), REG_HRO }, + { HRDATA (IASN, itlb_asn, ITB_ASN_WIDTH) }, + { HRDATA (INLU, itlb_nlu, ITLB_WIDTH) }, + { BRDATA (IMINI, &i_mini_tlb, 16, 32, TLB_ESIZE) }, + { BRDATA (ITLB, itlb, 16, 32, ITLB_SIZE*TLB_ESIZE) }, + { HRDATA (DCM, dtlb_cm, 2) }, + { HRDATA (DSPAGE, dtlb_spage, 2), REG_HRO }, + { HRDATA (DASN, dtlb_asn, DTB_ASN_WIDTH) }, + { HRDATA (DNLU, dtlb_nlu, DTLB_WIDTH) }, + { BRDATA (DMINI, &d_mini_tlb, 16, 32, TLB_ESIZE) }, + { BRDATA (DTLB, dtlb, 16, 32, DTLB_SIZE*TLB_ESIZE) }, + { NULL } + }; + +DEVICE tlb_dev = { + "TLB", &tlb_unit, tlb_reg, NULL, + 1, 0, 0, 1, 0, 0, + NULL, NULL, &tlb_reset, + NULL, NULL, NULL + }; + +/* Translate address, instruction, data, and console + + Inputs: + va = virtual address + acc = (VAX only) access mode + Outputs: + pa = translation buffer index +*/ + +t_uint64 trans_i (t_uint64 va) +{ +uint32 va_sext = VA_GETSEXT (va); +uint32 vpn = VA_GETVPN (va); +TLBENT *tlbp; + +if ((va_sext != 0) && (va_sext != VA_M_SEXT)) /* invalid virt addr? */ + ABORT1 (va, EXC_BVA + EXC_E); +if ((itlb_spage & SPEN_43) && VPN_GETSP43 (vpn) == 2) { /* 43b superpage? */ + if (itlb_cm != MODE_K) ABORT1 (va, EXC_ACV + EXC_E); + return (va & SP43_MASK); + } +if ((itlb_spage & SPEN_32) && (VPN_GETSP32 (vpn) == 0x1FFE)) { + if (itlb_cm != MODE_K) ABORT1 (va, EXC_ACV + EXC_E); + return (va & SP32_MASK); /* 32b superpage? */ + } +if (!(tlbp = itlb_lookup (vpn))) /* lookup vpn; miss? */ + ABORT1 (va, EXC_TBM + EXC_E); /* abort reference */ +if (cm_eacc & ~tlbp->pte) /* check access */ + ABORT1 (va, mm_exc (cm_eacc & ~tlbp->pte) | EXC_E); +return PHYS_ADDR (tlbp->pfn, va); /* return phys addr */ +} + +t_uint64 trans_d (t_uint64 va, uint32 acc) +{ +uint32 va_sext = VA_GETSEXT (va); +uint32 vpn = VA_GETVPN (va); +TLBENT *tlbp; + +if ((va_sext != 0) && (va_sext != VA_M_SEXT)) /* invalid virt addr? */ + ABORT1 (va, EXC_BVA + MM_RW (acc)); +if ((dtlb_spage & SPEN_43) && (VPN_GETSP43 (vpn) == 2)) { + if (dtlb_cm != MODE_K) ABORT1 (va, EXC_ACV + MM_RW (acc)); + return (va & SP43_MASK); /* 43b superpage? */ + } +if ((dtlb_spage & SPEN_32) && (VPN_GETSP32 (vpn) == 0x1FFE)) { + if (dtlb_cm != MODE_K) ABORT1 (va, EXC_ACV + MM_RW (acc)); + return (va & SP32_MASK); /* 32b superpage? */ + } +if (!(tlbp = dtlb_lookup (vpn))) /* lookup vpn; miss? */ + ABORT1 (va, EXC_TBM + MM_RW (acc)); /* abort reference */ +if (acc & ~tlbp->pte) /* check access */ + ABORT1 (va, mm_exc (acc & ~tlbp->pte) | MM_RW (acc)); +return PHYS_ADDR (tlbp->pfn, va); /* return phys addr */ +} + +/* Generate a memory management error code, based on the access check bits not + set in PTE + + - If the access check bits, without FOx and V, fail, then ACV + - If FOx set, then FOx + - Otherwise, TNV */ + +uint32 mm_exc (uint32 not_set) +{ +uint32 tacc; + +tacc = not_set & ~(PTE_FOR | PTE_FOW | PTE_FOE | PTE_V); +if (tacc) return EXC_ACV; +tacc = not_set & (PTE_FOR | PTE_FOW | PTE_FOE); +if (tacc) return EXC_FOX; +return EXC_TNV; +} + +/* TLB invalidate single */ + +void tlb_is (t_uint64 va, uint32 flags) +{ +uint32 va_sext = VA_GETSEXT (va); +uint32 vpn = VA_GETVPN (va); +TLBENT *itlbp, *dtlbp; + +if ((va_sext != 0) && (va_sext != VA_M_SEXT)) return; +if ((flags & TLB_CI) && (itlbp = itlb_lookup (vpn))) { + tlb_inval (itlbp); + tlb_inval (&i_mini_tlb); + ITLB_SORT; + } +if ((flags & TLB_CD) && (dtlbp = dtlb_lookup (vpn))) { + tlb_inval (dtlbp); + tlb_inval (&d_mini_tlb); + DTLB_SORT; + } +return; +} + +/* TLB invalidate all */ + +void tlb_ia (uint32 flags) +{ +uint32 i; + +if (flags & TLB_CA) { + if (flags & TLB_CI) itlb_reset (); + if (flags & TLB_CD) dtlb_reset (); + return; + } +if (flags & TLB_CI) { + for (i = 0; i < ITLB_SIZE; i++) { + if (!(itlb[i].pte & PTE_ASM)) tlb_inval (&itlb[i]); + } + tlb_inval (&i_mini_tlb); + ITLB_SORT; + } +if (flags & TLB_CD) { + for (i = 0; i < DTLB_SIZE; i++) { + if (!(dtlb[i].pte & PTE_ASM)) tlb_inval (&dtlb[i]); + } + tlb_inval (&d_mini_tlb); + DTLB_SORT; + } +return; +} + +/* TLB lookup */ + +TLBENT *itlb_lookup (uint32 vpn) +{ +int32 p, hi, lo; + +if (vpn == i_mini_tlb.tag) return &i_mini_tlb; +lo = 0; /* initial bounds */ +hi = ITLB_SIZE - 1; +do { + p = (lo + hi) >> 1; /* probe */ + if ((itlb_asn == itlb[p].asn) && + (((vpn ^ itlb[p].tag) & + ~((uint32) itlb[p].gh_mask)) == 0)) { /* match to TLB? */ + i_mini_tlb.tag = vpn; + i_mini_tlb.pte = itlb[p].pte; + i_mini_tlb.pfn = itlb[p].pfn; + itlb_nlu = itlb[p].idx + 1; + if (itlb_nlu >= ITLB_SIZE) itlb_nlu = 0; + return &i_mini_tlb; + } + if ((itlb_asn < itlb[p].asn) || + ((itlb_asn == itlb[p].asn) && (vpn < itlb[p].tag))) + hi = p - 1; /* go down? p is upper */ + else lo = p + 1; /* go up? p is lower */ + } +while (lo <= hi); +return NULL; +} + +TLBENT *dtlb_lookup (uint32 vpn) +{ +int32 p, hi, lo; + +if (vpn == d_mini_tlb.tag) return &d_mini_tlb; +lo = 0; /* initial bounds */ +hi = DTLB_SIZE - 1; +do { + p = (lo + hi) >> 1; /* probe */ + if ((dtlb_asn == dtlb[p].asn) && + (((vpn ^ dtlb[p].tag) & + ~((uint32) dtlb[p].gh_mask)) == 0)) { /* match to TLB? */ + d_mini_tlb.tag = vpn; + d_mini_tlb.pte = dtlb[p].pte; + d_mini_tlb.pfn = dtlb[p].pfn; + dtlb_nlu = dtlb[p].idx + 1; + if (dtlb_nlu >= DTLB_SIZE) dtlb_nlu = 0; + return &d_mini_tlb; + } + if ((dtlb_asn < dtlb[p].asn) || + ((dtlb_asn == dtlb[p].asn) && (vpn < dtlb[p].tag))) + hi = p - 1; /* go down? p is upper */ + else lo = p + 1; /* go up? p is lower */ + } +while (lo <= hi); +return NULL; +} + +/* Load TLB entry at NLU pointer, advance NLU pointer */ + +TLBENT *itlb_load (uint32 vpn, t_uint64 l3pte) +{ +uint32 i, gh; + +for (i = 0; i < ITLB_SIZE; i++) { + if (itlb[i].idx == itlb_nlu) { + TLBENT *tlbp = itlb + i; + itlb_nlu = itlb_nlu + 1; + if (itlb_nlu >= ITLB_SIZE) itlb_nlu = 0; + tlbp->tag = vpn; + tlbp->pte = (uint32) (l3pte & PTE_MASK) ^ (PTE_FOR|PTE_FOR|PTE_FOE); + tlbp->pfn = ((uint32) (l3pte >> PTE_V_PFN)) & PFN_MASK; + tlbp->asn = itlb_asn; + gh = PTE_GETGH (tlbp->pte); + tlbp->gh_mask = (1u << (3 * gh)) - 1; + tlb_inval (&i_mini_tlb); + ITLB_SORT; + return tlbp; + } + } +fprintf (stderr, "%%ITLB entry not found, itlb_nlu = %d\n", itlb_nlu); +ABORT (-SCPE_IERR); +return NULL; +} + +TLBENT *dtlb_load (uint32 vpn, t_uint64 l3pte) +{ +uint32 i, gh; + +for (i = 0; i < DTLB_SIZE; i++) { + if (dtlb[i].idx == dtlb_nlu) { + TLBENT *tlbp = dtlb + i; + dtlb_nlu = dtlb_nlu + 1; + if (dtlb_nlu >= ITLB_SIZE) dtlb_nlu = 0; + tlbp->tag = vpn; + tlbp->pte = (uint32) (l3pte & PTE_MASK) ^ (PTE_FOR|PTE_FOR|PTE_FOE); + tlbp->pfn = ((uint32) (l3pte >> PTE_V_PFN)) & PFN_MASK; + tlbp->asn = dtlb_asn; + gh = PTE_GETGH (tlbp->pte); + tlbp->gh_mask = (1u << (3 * gh)) - 1; + tlb_inval (&d_mini_tlb); + DTLB_SORT; + return tlbp; + } + } +fprintf (stderr, "%%DTLB entry not found, dtlb_nlu = %d\n", dtlb_nlu); +ABORT (-SCPE_IERR); +return NULL; +} + +/* Read TLB entry at NLU pointer, advance NLU pointer */ + +t_uint64 itlb_read (void) +{ +uint8 i; + +for (i = 0; i < ITLB_SIZE; i++) { + if (itlb[i].idx == itlb_nlu) { + TLBENT *tlbp = itlb + i; + itlb_nlu = itlb_nlu + 1; + if (itlb_nlu >= ITLB_SIZE) itlb_nlu = 0; + return (((t_uint64) tlbp->pfn) << PTE_V_PFN) | + ((tlbp->pte ^ (PTE_FOR|PTE_FOR|PTE_FOE)) & PTE_MASK); + } + } +fprintf (stderr, "%%ITLB entry not found, itlb_nlu = %d\n", itlb_nlu); +ABORT (-SCPE_IERR); +return 0; +} + +t_uint64 dtlb_read (void) +{ +uint8 i; + +for (i = 0; i < DTLB_SIZE; i++) { + if (dtlb[i].idx == dtlb_nlu) { + TLBENT *tlbp = dtlb + i; + dtlb_nlu = dtlb_nlu + 1; + if (dtlb_nlu >= DTLB_SIZE) dtlb_nlu = 0; + return (((t_uint64) tlbp->pfn) << PTE_V_PFN) | + ((tlbp->pte ^ (PTE_FOR|PTE_FOR|PTE_FOE)) & PTE_MASK); + } + } +fprintf (stderr, "%%DTLB entry not found, dtlb_nlu = %d\n", dtlb_nlu); +ABORT (-SCPE_IERR); +return 0; +} + +/* Set ASN - rewrite TLB globals with correct ASN */ + +void itlb_set_asn (uint32 asn) +{ +int32 i; + +itlb_asn = asn; +for (i = 0; i < ITLB_SIZE; i++) { + if (itlb[i].pte & PTE_ASM) itlb[i].asn = asn; + } +tlb_inval (&i_mini_tlb); +ITLB_SORT; +return; +} + +void dtlb_set_asn (uint32 asn) +{ +int32 i; + +dtlb_asn = asn; +for (i = 0; i < DTLB_SIZE; i++) { + if (dtlb[i].pte & PTE_ASM) dtlb[i].asn = asn; + } +tlb_inval (&d_mini_tlb); +DTLB_SORT; +return; +} + +/* Set superpage */ + +void itlb_set_spage (uint32 spage) +{ +itlb_spage = spage; +return; +} + +void dtlb_set_spage (uint32 spage) +{ +dtlb_spage = spage; +return; +} + +/* Set current mode */ + +void itlb_set_cm (uint32 mode) +{ +itlb_cm = mode; +cm_eacc = ACC_E (mode); +return; +} + +void dtlb_set_cm (uint32 mode) +{ +dtlb_cm = mode; +cm_racc = ACC_R (mode); +cm_wacc = ACC_W (mode); +return; +} + +uint32 tlb_set_cm (int32 cm) +{ +if (cm >= 0) { + itlb_set_cm (cm); + dtlb_set_cm (cm); + return cm; + } +itlb_set_cm (itlb_cm); +dtlb_set_cm (dtlb_cm); +return dtlb_cm; +} + +/* Invalidate TLB entry */ + +void tlb_inval (TLBENT *tlbp) +{ +tlbp->tag = INV_TAG; +tlbp->pte = 0; +tlbp->pfn = 0; +tlbp->asn = tlbp->idx; +tlbp->gh_mask = 0; +return; +} + +/* Compare routine for qsort */ + +int tlb_comp (const void *e1, const void *e2) +{ +TLBENT *t1 = (TLBENT *) e1; +TLBENT *t2 = (TLBENT *) e2; + +if (t1->asn > t2->asn) return +1; +if (t1->asn < t2->asn) return -1; +if (t1->tag > t2->tag) return +1; +if (t1->tag < t2->tag) return -1; +return 0; +} + +/* ITLB reset */ + +t_stat itlb_reset (void) +{ +int32 i; + +itlb_nlu = 0; +for (i = 0; i < ITLB_SIZE; i++) { + itlb[i].tag = INV_TAG; + itlb[i].pte = 0; + itlb[i].pfn = 0; + itlb[i].asn = i; + itlb[i].gh_mask = 0; + itlb[i].idx = i; + } +tlb_inval (&i_mini_tlb); +return SCPE_OK; +} +/* DTLB reset */ + +t_stat dtlb_reset (void) +{ +int32 i; + +dtlb_nlu = 0; +for (i = 0; i < DTLB_SIZE; i++) { + dtlb[i].tag = INV_TAG; + dtlb[i].pte = 0; + dtlb[i].pfn = 0; + dtlb[i].asn = i; + dtlb[i].gh_mask = 0; + dtlb[i].idx = i; + } +tlb_inval (&d_mini_tlb); +return SCPE_OK; +} + +/* SimH reset */ + +t_stat tlb_reset (DEVICE *dptr) +{ +itlb_reset (); +dtlb_reset (); +return SCPE_OK; +} + +/* Show TLB entry or entries */ + +t_stat cpu_show_tlb (FILE *of, UNIT *uptr, int32 val, void *desc) +{ +t_addr lo, hi; +uint32 lnt; +TLBENT *tlbp; +DEVICE *dptr; +char *cptr = (char *) desc; + +lnt = (val)? DTLB_SIZE: ITLB_SIZE; +dptr = find_dev_from_unit (uptr); +if (dptr == NULL) return SCPE_IERR; +if (cptr) { + cptr = get_range (dptr, cptr, &lo, &hi, 10, lnt, 0); + if ((cptr == NULL) || (*cptr != 0)) return SCPE_ARG; + } +else { + lo = 0; + hi = lnt - 1; + } +tlbp = (val)? dtlb + lo: itlb + lo; + +do { + fprintf (of, "TLB %02d\tTAG=%02X/%08X, ", (uint32) lo, tlbp->asn, tlbp->tag); + fprintf (of, "MASK=%X, INDX=%d, ", tlbp->gh_mask, tlbp->idx); + fprintf (of, "PTE=%04X, PFN=%08X\n", tlbp->pte, tlbp->pfn); + tlbp++; + lo++; + } while (lo <= hi); + +return SCPE_OK; +} + diff --git a/alpha/alpha_fpi.c b/alpha/alpha_fpi.c new file mode 100644 index 00000000..62c7b459 --- /dev/null +++ b/alpha/alpha_fpi.c @@ -0,0 +1,776 @@ +/* alpha_fpi.c - Alpha IEEE floating point simulator + + Copyright (c) 2003-2006, 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 contains the instruction simulators for + + - single precision floating point, S + - double precision floating point, T + + Portions of this module (specifically, the convert floating to integer + routine and the square root routine) are a derivative work from SoftFloat, + written by John Hauser. SoftFloat includes the following license terms: + + Written by John R. Hauser. This work was made possible in part by the + International Computer Science Institute, located at Suite 600, 1947 Center + Street, Berkeley, California 94704. Funding was partially provided by the + National Science Foundation under grant MIP-9311980. The original version + of this code was written as part of a project to build a fixed-point vector + processor in collaboration with the University of California at Berkeley, + overseen by Profs. Nelson Morgan and John Wawrzynek. More information + is available through the Web page 'http://www.cs.berkeley.edu/~jhauser/ + arithmetic/SoftFloat.html'. + + THIS SOFTWARE IS DISTRIBUTED AS IS, FOR FREE. Although reasonable effort has + been made to avoid it, THIS SOFTWARE MAY CONTAIN FAULTS THAT WILL AT TIMES + RESULT IN INCORRECT BEHAVIOR. USE OF THIS SOFTWARE IS RESTRICTED TO PERSONS + AND ORGANIZATIONS WHO CAN AND WILL TAKE FULL RESPONSIBILITY FOR ALL LOSSES, + COSTS, OR OTHER PROBLEMS THEY INCUR DUE TO THE SOFTWARE, AND WHO FURTHERMORE + EFFECTIVELY INDEMNIFY JOHN HAUSER AND THE INTERNATIONAL COMPUTER SCIENCE + INSTITUTE (possibly via similar legal warning) AGAINST ALL LOSSES, COSTS, OR + OTHER PROBLEMS INCURRED BY THEIR CUSTOMERS AND CLIENTS DUE TO THE SOFTWARE. + + Derivative works are acceptable, even for commercial purposes, so long as + (1) the source code for the derivative work includes prominent notice that + the work is derivative, and (2) the source code includes prominent notice with + these four paragraphs for those parts of this code that are retained. +*/ + +#include "alpha_defs.h" + +#define UFT_ZERO 0 /* unpacked: zero */ +#define UFT_FIN 1 /* finite */ +#define UFT_DENORM 2 /* denormal */ +#define UFT_INF 3 /* infinity */ +#define UFT_NAN 4 /* not a number */ + +#define Q_FINITE(x) ((x) <= UFT_FIN) /* finite */ +#define Q_SUI(x) (((x) & I_FTRP) == I_FTRP_SVI) + +/* Register format constants */ + +#define QNAN 0x0008000000000000 /* quiet NaN flag */ +#define CQNAN 0xFFF8000000000000 /* canonical quiet NaN */ +#define FPZERO 0x0000000000000000 /* plus zero (fp) */ +#define FMZERO 0x8000000000000000 /* minus zero (fp) */ +#define FPINF 0x7FF0000000000000 /* plus infinity (fp) */ +#define FMINF 0xFFF0000000000000 /* minus infinity (fp) */ +#define FPMAX 0x7FEFFFFFFFFFFFFF /* plus MAX (fp) */ +#define FMMAX 0xFFEFFFFFFFFFFFFF /* minus MAX (fp) */ +#define IPMAX 0x7FFFFFFFFFFFFFFF /* plus MAX (int) */ +#define IMMAX 0x8000000000000000 /* minus MAX (int) */ + +/* Unpacked rounding constants */ + +#define UF_SRND 0x0000008000000000 /* S normal round */ +#define UF_SINF 0x000000FFFFFFFFFF /* S infinity round */ +#define UF_TRND 0x0000000000000400 /* T normal round */ +#define UF_TINF 0x00000000000007FF /* T infinity round */ + +extern t_uint64 FR[32]; +extern uint32 fpcr; +extern jmp_buf save_env; + +t_bool ieee_unpack (t_uint64 op, UFP *r, uint32 ir); +void ieee_norm (UFP *r); +t_uint64 ieee_rpack (UFP *r, uint32 ir, uint32 dp); +void ieee_trap (uint32 trap, uint32 instenb, uint32 fpcrdsb, uint32 ir); +int32 ieee_fcmp (t_uint64 a, t_uint64 b, uint32 ir, uint32 signal_nan); +t_uint64 ieee_cvtst (t_uint64 op, uint32 ir); +t_uint64 ieee_cvtts (t_uint64 op, uint32 ir); +t_uint64 ieee_cvtif (t_uint64 val, uint32 ir, uint32 dp); +t_uint64 ieee_cvtfi (t_uint64 op, uint32 ir); +t_uint64 ieee_fadd (t_uint64 a, t_uint64 b, uint32 ir, uint32 dp, t_bool sub); +t_uint64 ieee_fmul (t_uint64 a, t_uint64 b, uint32 ir, uint32 dp); +t_uint64 ieee_fdiv (t_uint64 a, t_uint64 b, uint32 ir, uint32 dp); +uint32 estimateSqrt32 (uint32 exp, uint32 a); +t_uint64 estimateDiv128 (t_uint64 hi, t_uint64 lo, t_uint64 dvr); + +extern t_uint64 uemul64 (t_uint64 a, t_uint64 b, t_uint64 *hi); +extern t_uint64 ufdiv64 (t_uint64 dvd, t_uint64 dvr, uint32 prec, uint32 *sticky); +t_uint64 fsqrt64 (t_uint64 frac, int32 exp); + +/* IEEE S load */ + +t_uint64 op_lds (t_uint64 op) +{ +uint32 exp = S_GETEXP (op); /* get exponent */ + +if (exp == S_NAN) exp = FPR_NAN; /* inf or NaN? */ +else if (exp != 0) exp = exp + T_BIAS - S_BIAS; /* zero or denorm? */ +return (((t_uint64) (op & S_SIGN))? FPR_SIGN: 0) | /* reg format */ + (((t_uint64) exp) << FPR_V_EXP) | + (((t_uint64) (op & ~(S_SIGN|S_EXP))) << S_V_FRAC); +} + +/* IEEE S store */ + +t_uint64 op_sts (t_uint64 op) +{ +uint32 sign = FPR_GETSIGN (op)? S_SIGN: 0; +uint32 frac = ((uint32) (op >> S_V_FRAC)) & M32; +uint32 exp = FPR_GETEXP (op); + +if (exp == FPR_NAN) exp = S_NAN; /* inf or NaN? */ +else if (exp != 0) exp = exp + S_BIAS - T_BIAS; /* non-zero? */ +exp = (exp & S_M_EXP) << S_V_EXP; +return (t_uint64) (sign | exp | (frac & ~(S_SIGN|S_EXP))); +} + +/* IEEE floating operate */ + +void ieee_fop (uint32 ir) +{ +UFP a, b; +uint32 ftpa, ftpb, fnc, ra, rb, rc; +t_uint64 res; + +fnc = I_GETFFNC (ir); /* get function */ +ra = I_GETRA (ir); /* get registers */ +rb = I_GETRB (ir); +rc = I_GETRC (ir); +switch (fnc) { /* case on func */ + + case 0x00: /* ADDS */ + res = ieee_fadd (FR[ra], FR[rb], ir, DT_S, 0); + break; + + case 0x01: /* SUBS */ + res = ieee_fadd (FR[ra], FR[rb], ir, DT_S, 1); + break; + + case 0x02: /* MULS */ + res = ieee_fmul (FR[ra], FR[rb], ir, DT_S); + break; + + case 0x03: /* DIVS */ + res = ieee_fdiv (FR[ra], FR[rb], ir, DT_S); + break; + + case 0x20: /* ADDT */ + res = ieee_fadd (FR[ra], FR[rb], ir, DT_T, 0); + break; + + case 0x21: /* SUBT */ + res = ieee_fadd (FR[ra], FR[rb], ir, DT_T, 1); + break; + + case 0x22: /* MULT */ + res = ieee_fmul (FR[ra], FR[rb], ir, DT_T); + break; + + case 0x23: /* DIVT */ + res = ieee_fdiv (FR[ra], FR[rb], ir, DT_T); + break; + + case 0x24: /* CMPTUN */ + ftpa = ieee_unpack (FR[ra], &a, ir); /* unpack */ + ftpb = ieee_unpack (FR[rb], &b, ir); + if ((ftpa == UFT_NAN) || (ftpb == UFT_NAN)) /* if NaN, T */ + res = FP_TRUE; + else res = 0; + break; + + case 0x25: /* CMPTEQ */ + if (ieee_fcmp (FR[ra], FR[rb], ir, 0) == 0) res = FP_TRUE; + else res = 0; + break; + + case 0x26: /* CMPTLT */ + if (ieee_fcmp (FR[ra], FR[rb], ir, 1) < 0) res = FP_TRUE; + else res = 0; + break; + + case 0x27: /* CMPTLE */ + if (ieee_fcmp (FR[ra], FR[rb], ir, 1) <= 0) res = FP_TRUE; + else res = 0; + break; + + case 0x2C: /* CVTST, CVTTS */ + if (ir & 0x2000) res = ieee_cvtst (FR[rb], ir); /* CVTST */ + else res = ieee_cvtts (FR[rb], ir); /* CVTTS */ + break; + + case 0x2F: /* CVTTQ */ + res = ieee_cvtfi (FR[rb], ir); + break; + + case 0x3C: /* CVTQS */ + res = ieee_cvtif (FR[rb], ir, DT_S); + break; + + case 0x3E: /* CVTQT */ + res = ieee_cvtif (FR[rb], ir, DT_T); + break; + + default: + if ((ir & I_FSRC) == I_FSRC_X) ABORT (EXC_RSVI); + res = FR[rc]; + break; + } + +if (rc != 31) FR[rc] = res & M64; +return; +} + +/* IEEE S to T convert - LDS doesn't handle denorms correctly */ + +t_uint64 ieee_cvtst (t_uint64 op, uint32 ir) +{ +UFP b; +uint32 ftpb; + +ftpb = ieee_unpack (op, &b, ir); /* unpack; norm dnorm */ +if (ftpb == UFT_DENORM) { /* denormal? */ + b.exp = b.exp + T_BIAS - S_BIAS; /* change 0 exp to T */ + return ieee_rpack (&b, ir, DT_T); /* round, pack */ + } +else return op; /* identity */ +} + +/* IEEE T to S convert */ + +t_uint64 ieee_cvtts (t_uint64 op, uint32 ir) +{ +UFP b; +uint32 ftpb; + +ftpb = ieee_unpack (op, &b, ir); /* unpack */ +if (Q_FINITE (ftpb)) return ieee_rpack (&b, ir, DT_S); /* finite? round, pack */ +if (ftpb == UFT_NAN) return (op | QNAN); /* nan? cvt to quiet */ +if (ftpb == UFT_INF) return op; /* inf? unchanged */ +return 0; /* denorm? 0 */ +} + +/* IEEE floating compare + + - Take care of NaNs + - Force -0 to +0 + - Then normal compare will work (even on inf and denorms) */ + +int32 ieee_fcmp (t_uint64 s1, t_uint64 s2, uint32 ir, uint32 trap_nan) +{ +UFP a, b; +uint32 ftpa, ftpb; + +ftpa = ieee_unpack (s1, &a, ir); +ftpb = ieee_unpack (s2, &b, ir); +if ((ftpa == UFT_NAN) || (ftpb == UFT_NAN)) { /* NaN involved? */ + if (trap_nan) ieee_trap (TRAP_INV, 1, FPCR_INVD, ir); + return +1; /* force failure */ + } +if (ftpa == UFT_ZERO) a.sign = 0; /* only +0 allowed */ +if (ftpb == UFT_ZERO) b.sign = 0; +if (a.sign != b.sign) return (a.sign? -1: +1); /* unequal signs? */ +if (a.exp != b.exp) return ((a.sign ^ (a.exp < b.exp))? -1: +1); +if (a.frac != b.frac) return ((a.sign ^ (a.frac < b.frac))? -1: +1); +return 0; +} + +/* IEEE integer to floating convert */ + +t_uint64 ieee_cvtif (t_uint64 val, uint32 ir, uint32 dp) +{ +UFP a; + +if (val == 0) return 0; /* 0? return +0 */ +if (val & FPR_SIGN) { /* < 0? */ + a.sign = 1; /* set sign */ + val = NEG_Q (val); /* |val| */ + } +else a.sign = 0; +a.exp = 63 + T_BIAS; /* set exp */ +a.frac = val; /* set frac */ +ieee_norm (&a); /* normalize */ +return ieee_rpack (&a, ir, dp); /* round and pack */ +} + +/* IEEE floating to integer convert - rounding code from SoftFloat + The Alpha architecture specifies return of the low order bits of + the true result, whereas the IEEE standard specifies the return + of the maximum plus or minus value */ + +t_uint64 ieee_cvtfi (t_uint64 op, uint32 ir) +{ +UFP a; +t_uint64 sticky; +uint32 rndm, ftpa, ovf; +int32 ubexp; + +ftpa = ieee_unpack (op, &a, ir); /* unpack */ +if (!Q_FINITE (ftpa)) { /* inf, NaN, dnorm? */ + ieee_trap (TRAP_INV, 1, FPCR_INVD, ir); /* inv operation */ + return 0; + } +if (ftpa == UFT_ZERO) return 0; /* zero? */ +ovf = 0; /* assume no ovflo */ +ubexp = a.exp - T_BIAS; /* unbiased exp */ +if (ubexp < 0) { /* < 1? */ + if (ubexp == -1) sticky = a.frac; /* [.5,1)? */ + else sticky = 1; /* (0,.5) */ + a.frac = 0; + } +else if (ubexp < UF_V_NM) { /* in range? */ + sticky = (a.frac << (64 - (UF_V_NM - ubexp))) & M64; + a.frac = a.frac >> (UF_V_NM - ubexp); /* result */ + } +else if (ubexp == UF_V_NM) sticky = 0; /* at limit of range? */ +else { + if ((ubexp - UF_V_NM) > 63) a.frac = 0; /* out of range */ + else a.frac = (a.frac << (ubexp - UF_V_NM)) & M64; + ovf = 1; /* overflow */ + sticky = 0; /* no rounding */ + } +rndm = I_GETFRND (ir); /* get round mode */ +if (((rndm == I_FRND_N) && (sticky & Q_SIGN)) || /* nearest? */ + ((rndm == I_FRND_P) && !a.sign && sticky) || /* +inf and +? */ + ((rndm == I_FRND_M) && a.sign && sticky)) { /* -inf and -? */ + a.frac = (a.frac + 1) & M64; + if (a.frac == 0) ovf = 1; /* overflow? */ + if ((rndm == I_FRND_N) && (sticky == Q_SIGN)) /* round nearest hack */ + a.frac = a.frac & ~1; + } +if (a.frac > (a.sign? IMMAX: IPMAX)) ovf = 1; /* overflow? */ +if (ovf) ieee_trap (TRAP_IOV, ir & I_FTRP_V, 0, 0); /* overflow trap */ +if (ovf || sticky) /* ovflo or round? */ + ieee_trap (TRAP_INE, Q_SUI (ir), FPCR_INED, ir); +return (a.sign? NEG_Q (a.frac): a.frac); +} + +/* IEEE floating add + + - Take care of NaNs and infinites + - Test for zero (fast exit) + - Sticky logic for floating add + > If result normalized, sticky in right place + > If result carries out, renormalize, retain sticky + - Sticky logic for floating subtract + > If shift < guard, no sticky bits; 64b result is exact + If shift <= 1, result may require extensive normalization, + but there are no sticky bits to worry about + > If shift >= guard, there is a sticky bit, + but normalization is at most 1 place, sticky bit is retained + for rounding purposes (but not in low order bit) */ + +t_uint64 ieee_fadd (t_uint64 s1, t_uint64 s2, uint32 ir, uint32 dp, t_bool sub) +{ +UFP a, b, t; +uint32 ftpa, ftpb; +uint32 sticky, rndm; +int32 ediff; + +ftpa = ieee_unpack (s1, &a, ir); /* unpack operands */ +ftpb = ieee_unpack (s2, &b, ir); +if (ftpb == UFT_NAN) return s2 | QNAN; /* B = NaN? quiet B */ +if (ftpa == UFT_NAN) return s1 | QNAN; /* A = NaN? quiet A */ +if (sub) b.sign = b.sign ^ 1; /* sign of B */ +if (ftpb == UFT_INF) { /* B = inf? */ + if ((ftpa == UFT_INF) && (a.sign ^ b.sign)) { /* eff sub of inf? */ + ieee_trap (TRAP_INV, 1, FPCR_INVD, ir); /* inv op trap */ + return CQNAN; /* canonical NaN */ + } + return (sub? (s2 ^ FPR_SIGN): s2); /* return B */ + } +if (ftpa == UFT_INF) return s1; /* A = inf? ret A */ +rndm = I_GETFRND (ir); /* inst round mode */ +if (rndm == I_FRND_D) rndm = FPCR_GETFRND (fpcr); /* dynamic? use FPCR */ +if (ftpa == UFT_ZERO) { /* A = 0? */ + if (ftpb != UFT_ZERO) a = b; /* B != 0? result is B */ + else if (a.sign != b.sign) /* both 0, subtract? */ + a.sign = (rndm == I_FRND_M); /* +0 unless RM */ + } +else if (ftpb != UFT_ZERO) { /* s2 != 0? */ + if ((a.exp < b.exp) || /* s1 < s2? swap */ + ((a.exp == b.exp) && (a.frac < b.frac))) { + t = a; + a = b; + b = t; + } + ediff = a.exp - b.exp; /* exp diff */ + if (ediff > 63) b.frac = 1; /* >63? retain sticky */ + else if (ediff) { /* [1,63]? shift */ + sticky = ((b.frac << (64 - ediff)) & M64)? 1: 0; /* lost bits */ + b.frac = ((b.frac >> ediff) & M64) | sticky; + } + if (a.sign ^ b.sign) { /* eff sub? */ + a.frac = (a.frac - b.frac) & M64; /* subtract fractions */ + if (a.frac == 0) { /* result 0? */ + a.exp = 0; + a.sign = (rndm == I_FRND_M); /* +0 unless RM */ + } + else ieee_norm (&a); /* normalize */ + } + else { /* eff add */ + a.frac = (a.frac + b.frac) & M64; /* add frac */ + if (a.frac < b.frac) { /* chk for carry */ + a.frac = UF_NM | (a.frac >> 1) | /* shift in carry */ + (a.frac & 1); /* retain sticky */ + a.exp = a.exp + 1; /* skip norm */ + } + } + } /* end else if */ +return ieee_rpack (&a, ir, dp); /* round and pack */ +} + +/* IEEE floating multiply + + - Take care of NaNs and infinites + - Test for zero operands (fast exit) + - 64b x 64b fraction multiply, yielding 128b result + - Normalize (at most 1 bit) + - Insert "sticky" bit in low order fraction, for rounding + + Because IEEE fractions have a range of [1,2), the result can have a range + of [1,4). Results in the range of [1,2) appear to be denormalized by one + place, when in fact they are correct. Results in the range of [2,4) appear + to be in correct, when in fact they are 2X larger. This problem is taken + care of in the result exponent calculation. */ + +t_uint64 ieee_fmul (t_uint64 s1, t_uint64 s2, uint32 ir, uint32 dp) +{ +UFP a, b; +uint32 ftpa, ftpb; +t_uint64 resl; + +ftpa = ieee_unpack (s1, &a, ir); /* unpack operands */ +ftpb = ieee_unpack (s2, &b, ir); +if (ftpb == UFT_NAN) return s2 | QNAN; /* B = NaN? quiet B */ +if (ftpa == UFT_NAN) return s1 | QNAN; /* A = NaN? quiet A */ +a.sign = a.sign ^ b.sign; /* sign of result */ +if ((ftpa == UFT_ZERO) || (ftpb == UFT_ZERO)) { /* zero operand? */ + if ((ftpa == UFT_INF) || (ftpb == UFT_INF)) { /* 0 * inf? */ + ieee_trap (TRAP_INV, 1, FPCR_INVD, ir); /* inv op trap */ + return CQNAN; /* canonical NaN */ + } + return (a.sign? FMZERO: FPZERO); /* return signed 0 */ + } +if (ftpb == UFT_INF) return (a.sign? FMINF: FPINF); /* B = inf? */ +if (ftpa == UFT_INF) return (a.sign? FMINF: FPINF); /* A = inf? */ +a.exp = a.exp + b.exp + 1 - T_BIAS; /* add exponents */ +resl = uemul64 (a.frac, b.frac, &a.frac); /* multiply fracs */ +ieee_norm (&a); /* normalize */ +a.frac = a.frac | (resl? 1: 0); /* sticky bit */ +return ieee_rpack (&a, ir, dp); /* round and pack */ +} + +/* Floating divide + + - Take care of NaNs and infinites + - Check for zero cases + - Divide fractions (55b to develop a rounding bit) + - Set sticky bit if remainder non-zero + + Because IEEE fractions have a range of [1,2), the result can have a range + of (.5,2). Results in the range of [1,2) are correct. Results in the + range of (.5,1) need to be normalized by one place. */ + +t_uint64 ieee_fdiv (t_uint64 s1, t_uint64 s2, uint32 ir, uint32 dp) +{ +UFP a, b; +uint32 ftpa, ftpb, sticky; + +ftpa = ieee_unpack (s1, &a, ir); +ftpb = ieee_unpack (s2, &b, ir); +if (ftpb == UFT_NAN) return s2 | QNAN; /* B = NaN? quiet B */ +if (ftpa == UFT_NAN) return s1 | QNAN; /* A = NaN? quiet A */ +a.sign = a.sign ^ b.sign; /* sign of result */ +if (ftpb == UFT_INF) { /* B = inf? */ + if (ftpa == UFT_INF) { /* inf/inf? */ + ieee_trap (TRAP_INV, 1, FPCR_INVD, ir); /* inv op trap */ + return CQNAN; /* canonical NaN */ + } + return (a.sign? FMZERO: FPZERO); /* !inf/inf, ret 0 */ + } +if (ftpa == UFT_INF) /* A = inf? */ + return (a.sign? FMINF: FPINF); /* return inf */ +if (ftpb == UFT_ZERO) { /* B = 0? */ + if (ftpa == UFT_ZERO) { /* 0/0? */ + ieee_trap (TRAP_INV, 1, FPCR_INVD, ir); /* inv op trap */ + return CQNAN; /* canonical NaN */ + } + ieee_trap (TRAP_DZE, 1, FPCR_DZED, ir); /* div by 0 trap */ + return (a.sign? FMINF: FPINF); /* return inf */ + } +if (ftpa == UFT_ZERO) return (a.sign? FMZERO: FPZERO); /* A = 0? */ +a.exp = a.exp - b.exp + T_BIAS; /* unbiased exp */ +a.frac = a.frac >> 1; /* allow 1 bit left */ +b.frac = b.frac >> 1; +a.frac = ufdiv64 (a.frac, b.frac, 55, &sticky); /* divide */ +ieee_norm (&a); /* normalize */ +a.frac = a.frac | sticky; /* insert sticky */ +return ieee_rpack (&a, ir, dp); /* round and pack */ +} + +/* IEEE floating square root + + - Take care of NaNs, +infinite, zero + - Check for negative operand + - Compute result exponent + - Compute sqrt of fraction */ + +t_uint64 ieee_sqrt (uint32 ir, uint32 dp) +{ +t_uint64 op; +uint32 ftpb; +UFP b; + +op = FR[I_GETRB (ir)]; /* get F[rb] */ +ftpb = ieee_unpack (op, &b, ir); /* unpack */ +if (ftpb == UFT_NAN) return op | QNAN; /* NaN? */ +if ((ftpb == UFT_ZERO) || /* zero? */ + ((ftpb == UFT_INF) && !b.sign)) return op; /* +infinity? */ +if (b.sign) { /* minus? */ + ieee_trap (TRAP_INV, 1, FPCR_INVD, ir); /* signal inv op */ + return CQNAN; + } +b.exp = ((b.exp - T_BIAS) >> 1) + T_BIAS - 1; /* result exponent */ +b.frac = fsqrt64 (b.frac, b.exp); /* result fraction */ +return ieee_rpack (&b, ir, dp); /* round and pack */ +} + +/* Support routines */ + +t_bool ieee_unpack (t_uint64 op, UFP *r, uint32 ir) +{ +r->sign = FPR_GETSIGN (op); /* get sign */ +r->exp = FPR_GETEXP (op); /* get exponent */ +r->frac = FPR_GETFRAC (op); /* get fraction */ +if (r->exp == 0) { /* exponent = 0? */ + if (r->frac == 0) return UFT_ZERO; /* frac = 0? then true 0 */ + if (fpcr & FPCR_DNZ) { /* denorms to 0? */ + r->frac = 0; /* clear fraction */ + return UFT_ZERO; + } + r->frac = r->frac << FPR_GUARD; /* guard fraction */ + ieee_norm (r); /* normalize dnorm */ + ieee_trap (TRAP_INV, 1, FPCR_INVD, ir); /* signal inv op */ + return UFT_DENORM; + } +if (r->exp == FPR_NAN) { /* exponent = max? */ + if (r->frac == 0) return UFT_INF; /* frac = 0? then inf */ + if (!(r->frac & QNAN)) /* signaling NaN? */ + ieee_trap (TRAP_INV, 1, FPCR_INVD, ir); /* signal inv op */ + return UFT_NAN; + } +r->frac = (r->frac | FPR_HB) << FPR_GUARD; /* ins hidden bit, guard */ +return UFT_FIN; /* finite */ +} + +/* Normalize - input must be zero, finite, or denorm */ + +void ieee_norm (UFP *r) +{ +int32 i; +static t_uint64 normmask[5] = { + 0xc000000000000000, 0xf000000000000000, 0xff00000000000000, + 0xffff000000000000, 0xffffffff00000000 + }; +static int32 normtab[6] = { 1, 2, 4, 8, 16, 32 }; + +r->frac = r->frac & M64; +if (r->frac == 0) { /* if fraction = 0 */ + r->sign = 0; + r->exp = 0; /* result is 0 */ + return; + } +while ((r->frac & UF_NM) == 0) { /* normalized? */ + for (i = 0; i < 5; i++) { /* find first 1 */ + if (r->frac & normmask[i]) break; + } + r->frac = r->frac << normtab[i]; /* shift frac */ + r->exp = r->exp - normtab[i]; /* decr exp */ + } +return; +} + +/* Round and pack + + Much of the treachery of the IEEE standard is buried here + - Rounding modes (chopped, +infinity, nearest, -infinity) + - Inexact (set if there are any rounding bits, regardless of rounding) + - Overflow (result is infinite if rounded, max if not) + - Underflow (no denorms!) + + Underflow handling is particularly complicated + - Result is always 0 + - UNF and INE are always set in FPCR + - If /U is set, + o If /S is clear, trap + o If /S is set, UNFD is set, but UNFZ is clear, ignore UNFD and + trap, because the hardware cannot produce denormals + o If /S is set, UNFD is set, and UNFZ is set, do not trap + - If /SUI is set, and INED is clear, trap */ + +t_uint64 ieee_rpack (UFP *r, uint32 ir, uint32 dp) +{ +static const t_uint64 stdrnd[2] = { UF_SRND, UF_TRND }; +static const t_uint64 infrnd[2] = { UF_SINF, UF_TINF }; +static const int32 expmax[2] = { T_BIAS - S_BIAS + S_M_EXP - 1, T_M_EXP - 1 }; +static const int32 expmin[2] = { T_BIAS - S_BIAS, 0 }; +t_uint64 rndadd, rndbits, res; +uint32 rndm; + +if (r->frac == 0) /* result 0? */ + return ((t_uint64) r->sign << FPR_V_SIGN); +rndm = I_GETFRND (ir); /* inst round mode */ +if (rndm == I_FRND_D) rndm = FPCR_GETFRND (fpcr); /* dynamic? use FPCR */ +rndbits = r->frac & infrnd[dp]; /* isolate round bits */ +if (rndm == I_FRND_N) rndadd = stdrnd[dp]; /* round to nearest? */ +else if (((rndm == I_FRND_P) && !r->sign) || /* round to inf and */ + ((rndm == I_FRND_M) && r->sign)) /* right sign? */ + rndadd = infrnd[dp]; +else rndadd = 0; +r->frac = (r->frac + rndadd) & M64; /* round */ +if ((r->frac & UF_NM) == 0) { /* carry out? */ + r->frac = (r->frac >> 1) | UF_NM; /* renormalize */ + r->exp = r->exp + 1; + } +if (rndbits) /* inexact? */ + ieee_trap (TRAP_INE, Q_SUI (ir), FPCR_INED, ir); /* set inexact */ +if (r->exp > expmax[dp]) { /* ovflo? */ + ieee_trap (TRAP_OVF, 1, FPCR_OVFD, ir); /* set overflow trap */ + ieee_trap (TRAP_INE, Q_SUI (ir), FPCR_INED, ir); /* set inexact */ + if (rndadd) /* did we round? */ + return (r->sign? FMINF: FPINF); /* return infinity */ + return (r->sign? FMMAX: FPMAX); /* no, return max */ + } +if (r->exp <= expmin[dp]) { /* underflow? */ + ieee_trap (TRAP_UNF, ir & I_FTRP_U, /* set underflow trap */ + (fpcr & FPCR_UNDZ)? FPCR_UNFD: 0, ir); /* (dsbl only if UNFZ set) */ + ieee_trap (TRAP_INE, Q_SUI (ir), FPCR_INED, ir); /* set inexact */ + return 0; /* underflow to +0 */ + } +res = (((t_uint64) r->sign) << FPR_V_SIGN) | /* form result */ + (((t_uint64) r->exp) << FPR_V_EXP) | + ((r->frac >> FPR_GUARD) & FPR_FRAC); +if ((rndm == I_FRND_N) && (rndbits == stdrnd[dp])) /* nearest and halfway? */ + res = res & ~1; /* clear lo bit */ +return res; +} + +/* IEEE arithmetic trap - only one can be set at a time! */ + +void ieee_trap (uint32 trap, uint32 instenb, uint32 fpcrdsb, uint32 ir) +{ +fpcr = fpcr | (trap << 19); /* FPCR to trap summ offset */ +if ((instenb == 0) || /* not enabled in inst? ignore */ + ((ir & I_FTRP_S) && (fpcr & fpcrdsb))) return; /* /S and disabled? ignore */ +arith_trap (trap, ir); /* set Alpha trap */ +return; +} + +/* Fraction square root routine - code from SoftFloat */ + +t_uint64 fsqrt64 (t_uint64 asig, int32 exp) +{ +t_uint64 zsig, remh, reml, t; +uint32 sticky = 0; + +zsig = estimateSqrt32 (exp, (uint32) (asig >> 32)); + +/* Calculate the final answer in two steps. First, do one iteration of + Newton's approximation. The divide-by-2 is accomplished by clever + positioning of the operands. Then, check the bits just below the + (double precision) rounding bit to see if they are close to zero + (that is, the rounding bits are close to midpoint). If so, make + sure that the result^2 is the input operand */ + +asig = asig >> ((exp & 1)? 3: 2); /* leave 2b guard */ +zsig = estimateDiv128 (asig, 0, zsig << 32) + (zsig << 30 ); +if ((zsig & 0x1FF) <= 5) { /* close to even? */ + reml = uemul64 (zsig, zsig, &remh); /* result^2 */ + remh = asig - remh - (reml? 1:0); /* arg - result^2 */ + reml = NEG_Q (reml); + while (Q_GETSIGN (remh) != 0) { /* if arg < result^2 */ + zsig = zsig - 1; /* decr result */ + t = (zsig << 1) | 1; /* incr result^2 */ + reml = reml + t; /* and retest */ + remh = remh + (zsig >> 63) + ((reml < t)? 1: 0); + } + if ((remh | reml) != 0 ) sticky = 1; /* not exact? */ + } +return zsig; +} + +/* Estimate 32b SQRT + + Calculate an approximation to the square root of the 32-bit significand given + by 'a'. Considered as an integer, 'a' must be at least 2^31. If bit 0 of + 'exp' (the least significant bit) is 1, the integer returned approximates + 2^31*sqrt('a'/2^31), where 'a' is considered an integer. If bit 0 of 'exp' + is 0, the integer returned approximates 2^31*sqrt('a'/2^30). In either + case, the approximation returned lies strictly within +/-2 of the exact + value. */ + +uint32 estimateSqrt32 (uint32 exp, uint32 a) +{ +uint32 index, z; +static const uint32 sqrtOdd[] = { + 0x0004, 0x0022, 0x005D, 0x00B1, 0x011D, 0x019F, 0x0236, 0x02E0, + 0x039C, 0x0468, 0x0545, 0x0631, 0x072B, 0x0832, 0x0946, 0x0A67 + }; +static const uint32 sqrtEven[] = { + 0x0A2D, 0x08AF, 0x075A, 0x0629, 0x051A, 0x0429, 0x0356, 0x029E, + 0x0200, 0x0179, 0x0109, 0x00AF, 0x0068, 0x0034, 0x0012, 0x0002 + }; + +index = (a >> 27) & 0xF; /* bits<30:27> */ +if (exp & 1) { /* odd exp? */ + z = 0x4000 + (a >> 17) - sqrtOdd[index]; /* initial guess */ + z = ((a / z) << 14) + (z << 15); /* Newton iteration */ + a = a >> 1; + } +else { + z = 0x8000 + (a >> 17) - sqrtEven[index]; /* initial guess */ + z = (a / z) + z; /* Newton iteration */ + z = (z >= 0x20000) ? 0xFFFF8000: (z << 15); + if (z <= a) z = (a >> 1) | 0x80000000; + } +return (uint32) ((((((t_uint64) a) << 31) / ((t_uint64) z)) + (z >> 1)) & M32); +} + +/* Estimate 128b unsigned divide */ + +t_uint64 estimateDiv128 (t_uint64 a0, t_uint64 a1, t_uint64 b) +{ +t_uint64 b0, b1; +t_uint64 rem0, rem1, term0, term1; +t_uint64 z; + +if (b <= a0) return 0xFFFFFFFFFFFFFFFF; +b0 = b >> 32; +z = ((b0 << 32) <= a0)? 0xFFFFFFFF00000000: ((a0 / b0) << 32); +term1 = uemul64 (b, z, &term0); +rem0 = a0 - term0 - (a1 < term1); +rem1 = a1 - term1; +while (Q_GETSIGN (rem0)) { + z = z - ((t_uint64) 0x100000000); + b1 = b << 32; + rem1 = b1 + rem1; + rem0 = b0 + rem0 + (rem1 < b1); + } +rem0 = (rem0 << 32) | (rem1 >> 32); +z |= (((b0 << 32) <= rem0)? 0xFFFFFFFF : (rem0 / b0)); +return z; +} diff --git a/alpha/alpha_fpv.c b/alpha/alpha_fpv.c new file mode 100644 index 00000000..67fca723 --- /dev/null +++ b/alpha/alpha_fpv.c @@ -0,0 +1,457 @@ +/* alpha_fpv.c - Alpha VAX floating point simulator + + Copyright (c) 2003-2006, 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 contains the instruction simulators for + + - single precision floating point, F + - double precision floating point, G +*/ + +#include "alpha_defs.h" + +#define IPMAX 0x7FFFFFFFFFFFFFFF /* plus MAX (int) */ +#define IMMAX 0x8000000000000000 /* minus MAX (int) */ + +/* Unpacked rounding constants */ + +#define UF_FRND 0x0000008000000000 /* F round */ +#define UF_DRND 0x0000000000000080 /* D round */ +#define UF_GRND 0x0000000000000400 /* G round */ + +extern t_uint64 FR[32]; +extern jmp_buf save_env; + +t_bool vax_unpack (t_uint64 op, UFP *a, uint32 ir); +t_bool vax_unpack_d (t_uint64 op, UFP *a, uint32 ir); +void vax_norm (UFP *a); +t_uint64 vax_rpack (UFP *a, uint32 ir, uint32 dp); +t_uint64 vax_rpack_d (UFP *a, uint32 ir); +int32 vax_fcmp (t_uint64 a, t_uint64 b, uint32 ir); +t_uint64 vax_cvtif (t_uint64 val, uint32 ir, uint32 dp); +t_uint64 vax_cvtfi (t_uint64 op, uint32 ir); +t_uint64 vax_fadd (t_uint64 a, t_uint64 b, uint32 ir, uint32 dp, t_bool sub); +t_uint64 vax_fmul (t_uint64 a, t_uint64 b, uint32 ir, uint32 dp); +t_uint64 vax_fdiv (t_uint64 a, t_uint64 b, uint32 ir, uint32 dp); + +extern t_uint64 uemul64 (t_uint64 a, t_uint64 b, t_uint64 *hi); +extern t_uint64 ufdiv64 (t_uint64 dvd, t_uint64 dvr, uint32 prec, uint32 *sticky); +extern t_uint64 fsqrt64 (t_uint64 frac, int32 exp); + +/* VAX floating point loads and stores */ + +t_uint64 op_ldf (t_uint64 op) +{ +uint32 exp = F_GETEXP (op); + +if (exp != 0) exp = exp + G_BIAS - F_BIAS; /* zero? */ +return (((t_uint64) (op & F_SIGN))? FPR_SIGN: 0) | /* finite non-zero */ + (((t_uint64) exp) << FPR_V_EXP) | + (((t_uint64) SWAP_VAXF (op & ~(F_SIGN|F_EXP))) << F_V_FRAC); +} + +t_uint64 op_ldg (t_uint64 op) +{ +return SWAP_VAXG (op); /* swizzle bits */ +} + +t_uint64 op_stf (t_uint64 op) +{ +uint32 sign = FPR_GETSIGN (op)? F_SIGN: 0; +uint32 frac = (uint32) (op >> F_V_FRAC); +uint32 exp = FPR_GETEXP (op); + +if (exp != 0) exp = exp + F_BIAS - G_BIAS; /* zero? */ +exp = (exp & F_M_EXP) << F_V_EXP; +return (t_uint64) (sign | exp | (SWAP_VAXF (frac) & ~(F_SIGN|F_EXP))); +} + +t_uint64 op_stg (t_uint64 op) +{ +return SWAP_VAXG (op); /* swizzle bits */ +} + +/* VAX floating point operate */ + +void vax_fop (uint32 ir) +{ +UFP b; +t_uint64 res; +uint32 fnc, ra, rb, rc; + +fnc = I_GETFFNC (ir); /* get function */ +ra = I_GETRA (ir); /* get registers */ +rb = I_GETRB (ir); +rc = I_GETRC (ir); +switch (fnc) { /* case on func */ + + case 0x00: /* ADDF */ + res = vax_fadd (FR[ra], FR[rb], ir, DT_F, 0); + break; + + case 0x01: /* SUBF */ + res = vax_fadd (FR[ra], FR[rb], ir, DT_F, 1); + break; + + case 0x02: /* MULF */ + res = vax_fmul (FR[ra], FR[rb], ir, DT_F); + break; + + case 0x03: /* DIVF */ + res = vax_fdiv (FR[ra], FR[rb], ir, DT_F); + break; + + case 0x20: /* ADDG */ + res = vax_fadd (FR[ra], FR[rb], ir, DT_G, 0); + break; + + case 0x21: /* SUBG */ + res = vax_fadd (FR[ra], FR[rb], ir, DT_G, 1); + break; + + case 0x22: /* MULG */ + res = vax_fmul (FR[ra], FR[rb], ir, DT_G); + break; + + case 0x23: /* DIVG */ + res = vax_fdiv (FR[ra], FR[rb], ir, DT_G); + break; + + case 0x25: /* CMPGEQ */ + if (vax_fcmp (FR[ra], FR[rb], ir) == 0) res = FP_TRUE; + else res = 0; + break; + + case 0x26: /* CMPGLT */ + if (vax_fcmp (FR[ra], FR[rb], ir) < 0) res = FP_TRUE; + else res = 0; + break; + + case 0x27: /* CMPGLE */ + if (vax_fcmp (FR[ra], FR[rb], ir) <= 0) res = FP_TRUE; + else res = 0; + break; + + case 0x1E: /* CVTDG */ + if (vax_unpack_d (FR[rb], &b, ir)) res = 0; + else res = vax_rpack (&b, ir, DT_G); + break; + + case 0x2C: /* CVTGF */ + if (vax_unpack (FR[rb], &b, ir)) res = 0; + else res = vax_rpack (&b, ir, DT_F); + break; + + case 0x2D: /* CVTGD */ + if (vax_unpack (FR[rb], &b, ir)) res = 0; + else res = vax_rpack_d (&b, ir); + break; + + case 0x2F: /* CVTGQ */ + res = vax_cvtfi (FR[rb], ir); + break; + + case 0x3C: /* CVTQF */ + res = vax_cvtif (FR[rb], ir, DT_F); + break; + + case 0x3E: /* CVTQG */ + res = vax_cvtif (FR[rb], ir, DT_G); + break; + + default: + res = FR[rc]; + break; + } + +if (rc != 31) FR[rc] = res & M64; +return; +} + +/* VAX floating compare */ + +int32 vax_fcmp (t_uint64 s1, t_uint64 s2, uint32 ir) +{ +UFP a, b; + +if (vax_unpack (s1, &a, ir)) return +1; /* unpack, rsv? */ +if (vax_unpack (s2, &b, ir)) return +1; /* unpack, rsv? */ +if (s1 == s2) return 0; /* equal? */ +if (a.sign != b.sign) return (a.sign? -1: +1); /* opp signs? */ +return (((s1 < s2) ^ a.sign)? -1: +1); /* like signs */ +} + +/* VAX integer to floating convert */ + +t_uint64 vax_cvtif (t_uint64 val, uint32 ir, uint32 dp) +{ +UFP a; + +if (val == 0) return 0; /* 0? return +0 */ +if (val < 0) { /* < 0? */ + a.sign = 1; /* set sign */ + val = NEG_Q (val); /* |val| */ + } +else a.sign = 0; +a.exp = 64 + G_BIAS; /* set exp */ +a.frac = val; /* set frac */ +vax_norm (&a); /* normalize */ +return vax_rpack (&a, ir, dp); /* round and pack */ +} + +/* VAX floating to integer convert - note that rounding cannot cause a + carry unless the fraction has been shifted right at least FP_GUARD + places; in which case a carry out is impossible */ + +t_uint64 vax_cvtfi (t_uint64 op, uint32 ir) +{ +UFP a; +uint32 rndm = I_GETFRND (ir); +int32 ubexp; + +if (vax_unpack (op, &a, ir)) return 0; /* unpack, rsv? */ +ubexp = a.exp - G_BIAS; /* unbiased exp */ +if (ubexp < 0) return 0; /* zero or too small? */ +if (ubexp <= UF_V_NM) { /* in range? */ + a.frac = a.frac >> (UF_V_NM - ubexp); /* leave rnd bit */ + if (rndm) a.frac = a.frac + 1; /* not chopped, round */ + a.frac = a.frac >> 1; /* now justified */ + if ((a.frac > (a.sign? IMMAX: IPMAX)) && /* out of range? */ + (ir & I_FTRP_V)) /* trap enabled? */ + arith_trap (TRAP_IOV, ir); /* set overflow */ + } +else { + if (ubexp > (UF_V_NM + 64)) a.frac = 0; /* out of range */ + else a.frac = (a.frac << (ubexp - UF_V_NM - 1)) & M64; /* no rnd bit */ + if (ir & I_FTRP_V) /* trap enabled? */ + arith_trap (TRAP_IOV, ir); /* set overflow */ + } +return (a.sign? NEG_Q (a.frac): a.frac); +} + +/* VAX floating add */ + +t_uint64 vax_fadd (t_uint64 s1, t_uint64 s2, uint32 ir, uint32 dp, t_bool sub) +{ +UFP a, b, t; +uint32 sticky; +int32 ediff; + +if (vax_unpack (s1, &a, ir)) return 0; /* unpack, rsv? */ +if (vax_unpack (s2, &b, ir)) return 0; /* unpack, rsv? */ +if (sub) b.sign = b.sign ^ 1; /* sub? invert b sign */ +if (a.exp == 0) a = b; /* s1 = 0? */ +else if (b.exp) { /* s2 != 0? */ + if ((a.exp < b.exp) || /* |s1| < |s2|? swap */ + ((a.exp == b.exp) && (a.frac < b.frac))) { + t = a; + a = b; + b = t; + } + ediff = a.exp - b.exp; /* exp diff */ + if (a.sign ^ b.sign) { /* eff sub? */ + if (ediff > 63) b.frac = 1; /* >63? retain sticky */ + else if (ediff) { /* [1,63]? shift */ + sticky = ((b.frac << (64 - ediff)) & M64)? 1: 0; /* lost bits */ + b.frac = (b.frac >> ediff) | sticky; + } + a.frac = (a.frac - b.frac) & M64; /* subtract fractions */ + vax_norm (&a); /* normalize */ + } + else { /* eff add */ + if (ediff > 63) b.frac = 0; /* >63? b disappears */ + else if (ediff) b.frac = b.frac >> ediff; /* denormalize */ + a.frac = (a.frac + b.frac) & M64; /* add frac */ + if (a.frac < b.frac) { /* chk for carry */ + a.frac = UF_NM | (a.frac >> 1); /* shift in carry */ + a.exp = a.exp + 1; /* skip norm */ + } + } + } /* end else if */ +return vax_rpack (&a, ir, dp); /* round and pack */ +} + +/* VAX floating multiply */ + +t_uint64 vax_fmul (t_uint64 s1, t_uint64 s2, uint32 ir, uint32 dp) +{ +UFP a, b; + +if (vax_unpack (s1, &a, ir)) return 0; /* unpack, rsv? */ +if (vax_unpack (s2, &b, ir)) return 0; /* unpack, rsv? */ +if ((a.exp == 0) || (b.exp == 0)) return 0; /* zero argument? */ +a.sign = a.sign ^ b.sign; /* sign of result */ +a.exp = a.exp + b.exp - G_BIAS; /* add exponents */ +uemul64 (a.frac, b.frac, &a.frac); /* mpy fractions */ +vax_norm (&a); /* normalize */ +return vax_rpack (&a, ir, dp); /* round and pack */ +} + +/* VAX floating divide + Needs to develop at least one rounding bit. Since the first + divide step can fail, develop 2 more bits than the precision of + the fraction. */ + +t_uint64 vax_fdiv (t_uint64 s1, t_uint64 s2, uint32 ir, uint32 dp) +{ +UFP a, b; + +if (vax_unpack (s1, &a, ir)) return 0; /* unpack, rsv? */ +if (vax_unpack (s2, &b, ir)) return 0; /* unpack, rsv? */ +if (b.exp == 0) { /* divr = 0? */ + arith_trap (TRAP_DZE, ir); /* dze trap */ + return 0; + } +if (a.exp == 0) return 0; /* divd = 0? */ +a.sign = a.sign ^ b.sign; /* result sign */ +a.exp = a.exp - b.exp + G_BIAS + 1; /* unbiased exp */ +a.frac = a.frac >> 1; /* allow 1 bit left */ +b.frac = b.frac >> 1; +a.frac = ufdiv64 (a.frac, b.frac, 55, NULL); /* divide */ +vax_norm (&a); /* normalize */ +return vax_rpack (&a, ir, dp); /* round and pack */ +} + +/* VAX floating square root */ + +t_uint64 vax_sqrt (uint32 ir, uint32 dp) +{ +t_uint64 op; +UFP b; + +op = FR[I_GETRB (ir)]; /* get F[rb] */ +if (vax_unpack (op, &b, ir)) return 0; /* unpack, rsv? */ +if (b.exp == 0) return 0; /* zero? */ +if (b.sign) { /* minus? */ + arith_trap (TRAP_INV, ir); /* invalid operand */ + return 0; + } +b.exp = ((b.exp + 1 - G_BIAS) >> 1) + G_BIAS; /* result exponent */ +b.frac = fsqrt64 (b.frac, b.exp); /* result fraction */ +return vax_rpack (&b, ir, dp); /* round and pack */ +} + +/* Support routines */ + +t_bool vax_unpack (t_uint64 op, UFP *r, uint32 ir) +{ +r->sign = FPR_GETSIGN (op); /* get sign */ +r->exp = FPR_GETEXP (op); /* get exponent */ +r->frac = FPR_GETFRAC (op); /* get fraction */ +if (r->exp == 0) { /* exp = 0? */ + if (op != 0) arith_trap (TRAP_INV, ir); /* rsvd op? */ + r->frac = r->sign = 0; + return TRUE; + } +r->frac = (r->frac | FPR_HB) << FPR_GUARD; /* ins hidden bit, guard */ +return FALSE; +} + +t_bool vax_unpack_d (t_uint64 op, UFP *r, uint32 ir) +{ +r->sign = FDR_GETSIGN (op); /* get sign */ +r->exp = FDR_GETEXP (op); /* get exponent */ +r->frac = FDR_GETFRAC (op); /* get fraction */ +if (r->exp == 0) { /* exp = 0? */ + if (op != 0) arith_trap (TRAP_INV, ir); /* rsvd op? */ + r->frac = r->sign = 0; + return TRUE; + } +r->exp = r->exp + G_BIAS - D_BIAS; /* change to G bias */ +r->frac = (r->frac | FDR_HB) << FDR_GUARD; /* ins hidden bit, guard */ +return FALSE; +} + +/* VAX normalize */ + +void vax_norm (UFP *r) +{ +int32 i; +static t_uint64 normmask[5] = { + 0xc000000000000000, 0xf000000000000000, 0xff00000000000000, + 0xffff000000000000, 0xffffffff00000000 + }; +static int32 normtab[6] = { 1, 2, 4, 8, 16, 32 }; + +r->frac = r->frac & M64; +if (r->frac == 0) { /* if fraction = 0 */ + r->sign = r->exp = 0; /* result is 0 */ + return; + } +while ((r->frac & UF_NM) == 0) { /* normalized? */ + for (i = 0; i < 5; i++) { /* find first 1 */ + if (r->frac & normmask[i]) break; + } + r->frac = r->frac << normtab[i]; /* shift frac */ + r->exp = r->exp - normtab[i]; /* decr exp */ + } +return; +} + +/* VAX round and pack */ + +t_uint64 vax_rpack (UFP *r, uint32 ir, uint32 dp) +{ +uint32 rndm = I_GETFRND (ir); +static const t_uint64 roundbit[2] = { UF_FRND, UF_GRND }; +static const int32 expmax[2] = { G_BIAS - F_BIAS + F_M_EXP, G_M_EXP }; +static const int32 expmin[2] = { G_BIAS - F_BIAS, 0 }; + +if (r->frac == 0) return 0; /* result 0? */ +if (rndm) { /* round? */ + r->frac = (r->frac + roundbit[dp]) & M64; /* add round bit */ + if ((r->frac & UF_NM) == 0) { /* carry out? */ + r->frac = (r->frac >> 1) | UF_NM; /* renormalize */ + r->exp = r->exp + 1; + } + } +if (r->exp > expmax[dp]) { /* ovflo? */ + arith_trap (TRAP_OVF, ir); /* set trap */ + r->exp = expmax[dp]; /* return max */ + } +if (r->exp <= expmin[dp]) { /* underflow? */ + if (ir & I_FTRP_V) arith_trap (TRAP_UNF, ir); /* enabled? set trap */ + return 0; /* underflow to 0 */ + } +return (((t_uint64) r->sign) << FPR_V_SIGN) | + (((t_uint64) r->exp) << FPR_V_EXP) | + ((r->frac >> FPR_GUARD) & FPR_FRAC); +} + +t_uint64 vax_rpack_d (UFP *r, uint32 ir) +{ +if (r->frac == 0) return 0; /* result 0? */ +r->exp = r->exp + D_BIAS - G_BIAS; /* rebias */ +if (r->exp > FDR_M_EXP) { /* ovflo? */ + arith_trap (TRAP_OVF, ir); /* set trap */ + r->exp = FDR_M_EXP; /* return max */ + } +if (r->exp <= 0) { /* underflow? */ + if (ir & I_FTRP_V) arith_trap (TRAP_UNF, ir); /* enabled? set trap */ + return 0; /* underflow to 0 */ + } +return (((t_uint64) r->sign) << FDR_V_SIGN) | + (((t_uint64) r->exp) << FDR_V_EXP) | + ((r->frac >> FDR_GUARD) & FDR_FRAC); +} diff --git a/alpha/alpha_io.c b/alpha/alpha_io.c new file mode 100644 index 00000000..aa021d41 --- /dev/null +++ b/alpha/alpha_io.c @@ -0,0 +1,214 @@ +/* alpha_io.c: Alpha I/O and miscellaneous devices + + Copyright (c) 2006, 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. + + rom boot ROM +*/ + +#include "alpha_defs.h" +#include "alpha_sys_defs.h" + +t_uint64 *rom = NULL; /* boot ROM */ + +extern DEVICE *sim_devices[]; + +t_bool rom_rd (t_uint64 pa, t_uint64 *val, uint32 lnt); +t_bool rom_wr (t_uint64 pa, t_uint64 val, uint32 lnt); +t_stat rom_ex (t_value *vptr, t_addr exta, UNIT *uptr, int32 sw); +t_stat rom_dep (t_value val, t_addr exta, UNIT *uptr, int32 sw); +t_stat rom_reset (DEVICE *dptr); + +/* ROM data structures + + rom_dev ROM device descriptor + rom_unit ROM units + rom_reg ROM register list +*/ + +DIB rom_dib = { + ROMBASE, ROMBASE + ROMSIZE, &rom_rd, &rom_wr, 0 + }; + +UNIT rom_unit = { + UDATA (NULL, UNIT_FIX+UNIT_BINK, ROMSIZE) + }; + +REG rom_reg[] = { + { NULL } + }; + +DEVICE rom_dev = { + "ROM", &rom_unit, rom_reg, NULL, + 1, 16, 24, 8, 16, 64, + &rom_ex, &rom_dep, &rom_reset, + NULL, NULL, NULL, + &rom_dib, DEV_DIB + }; + +/* ReadIO - read IO space + + Inputs: + pa = physical address + *dat = pointer to data + lnt = length (BWLQ) + Output: + TRUE if read succeeds, else FALSE +*/ + +t_bool ReadIO (t_uint64 pa, t_uint64 *dat, uint32 lnt) +{ +DEVICE *dptr; +uint32 i; + +for (i = 0; sim_devices[i] != NULL; i++) { + dptr = sim_devices[i]; + if (dptr->flags & DEV_DIB) { + DIB *dibp = (DIB *) dptr->ctxt; + if ((pa >= dibp->low) && (pa < dibp->high)) + return dibp->read (pa, dat, lnt); + } + } +return FALSE; +} + +/* WriteIO - write register space + + Inputs: + ctx = CPU context + pa = physical address + val = data to write, right justified in 64b quadword + lnt = length (BWLQ) + Output: + TRUE if write succeeds, else FALSE +*/ + +t_bool WriteIO (t_uint64 pa, t_uint64 dat, uint32 lnt) +{ +DEVICE *dptr; +uint32 i; + +for (i = 0; sim_devices[i] != NULL; i++) { + dptr = sim_devices[i]; + if (dptr->flags & DEV_DIB) { + DIB *dibp = (DIB *) dptr->ctxt; + if ((pa >= dibp->low) && (pa < dibp->high)) + return dibp->write (pa, dat, lnt); + } + } +return FALSE; +} + +/* Boot ROM read */ + +t_bool rom_rd (t_uint64 pa, t_uint64 *val, uint32 lnt) +{ +uint32 sc, rg = ((uint32) ((pa - ROMBASE) & (ROMSIZE - 1))) >> 3; + +switch (lnt) { + + case L_BYTE: + sc = (((uint32) pa) & 7) * 8; + *val = (rom[rg] >> sc) & M8; + break; + + case L_WORD: + sc = (((uint32) pa) & 6) * 8; + *val = (rom[rg] >> sc) & M16; + break; + + case L_LONG: + if (pa & 4) *val = (rom[rg] >> 32) & M32; + else *val = rom[rg] & M32; + break; + + case L_QUAD: + *val = rom[rg]; + break; + } + +return TRUE; +} + +/* Boot ROM write */ + +t_bool rom_wr (t_uint64 pa, t_uint64 val, uint32 lnt) +{ +uint32 sc, rg = ((uint32) ((pa - ROMBASE) & (ROMSIZE - 1))) >> 3; + +switch (lnt) { + + case L_BYTE: + sc = (((uint32) pa) & 7) * 8; + rom[rg] = (rom[rg] & ~(((t_uint64) M8) << sc)) | (((t_uint64) (val & M8)) << sc); + break; + + case L_WORD: + sc = (((uint32) pa) & 6) * 8; + rom[rg] = (rom[rg] & ~(((t_uint64) M16) << sc)) | (((t_uint64) (val & M16)) << sc); + break; + + case L_LONG: + if (pa & 4) rom[rg] = ((t_uint64) (rom[rg] & M32)) | (((t_uint64) (val & M32)) << 32); + else rom[rg] = (rom[rg] & ~((t_uint64) M32)) | ((t_uint64) val & M32); + break; + + case L_QUAD: + rom[rg] = val; + break; + } + +return TRUE; +} + +/* ROM examine */ + +t_stat rom_ex (t_value *vptr, t_addr exta, UNIT *uptr, int32 sw) +{ +uint32 addr = (uint32) exta; + +if (vptr == NULL) return SCPE_ARG; +if (addr >= ROMSIZE) return SCPE_NXM; +*vptr = rom[addr >> 3]; +return SCPE_OK; +} + +/* ROM deposit */ + +t_stat rom_dep (t_value val, t_addr exta, UNIT *uptr, int32 sw) +{ +uint32 addr = (uint32) exta; + +if (addr >= ROMSIZE) return SCPE_NXM; +rom[addr >> 3] = val; +return SCPE_OK; +} + +/* ROM reset */ + +t_stat rom_reset (DEVICE *dptr) +{ +if (rom == NULL) rom = (t_uint64 *) calloc (ROMSIZE >> 3, sizeof (t_uint64)); +if (rom == NULL) return SCPE_MEM; +return SCPE_OK; +} diff --git a/alpha/alpha_mmu.c b/alpha/alpha_mmu.c new file mode 100644 index 00000000..8d000b09 --- /dev/null +++ b/alpha/alpha_mmu.c @@ -0,0 +1,308 @@ +/* alpha_mmu.c - Alpha memory management simulator + + Copyright (c) 2003-2006, 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 contains the routines for + + ReadB,W,L,Q - read aligned virtual + ReadAccL,Q - read aligned virtual, special access check + ReadPB,W,L,Q - read aligned physical + WriteB,W,L,Q - write aligned virtual + WriteAccL,Q - write aligned virtual, special access check + WritePB,W,L,Q - write aligned physical + + The TLB is organized for optimum lookups and is broken up into three fields: + + tag VA<42:13> for an 8KB page system + pte PTE<31:0>, <31:16> are zero; FOE, FOR, FOW stored inverted + pfn PFN<31:0> left shifted by page size + + The inversion of FOE, FOR, FOW means that all checked bits must be one + for a reference to proceed. + + All Alpha implementations provide support for a 43b superpage for Unix, + and a 32b superpage for NT: + + 43b superpage 0xFFFFFC0000000000:0xFFFFFDFFFFFFFFFF + 32b superpage 0xFFFFFFFF80000000:0xFFFFFFFFBFFFFFFF +*/ + +#include "alpha_defs.h" + +extern t_uint64 trans_i (t_uint64 va); +extern t_uint64 trans_d (t_uint64 va, uint32 acc); + +extern t_uint64 *M; +extern t_uint64 p1; +extern uint32 pal_mode, dmapen; +extern uint32 cm_eacc, cm_racc, cm_wacc; +extern jmp_buf save_env; +extern UNIT cpu_unit; + +/* Read virtual aligned + + Inputs: + va = virtual address + Output: + returned data, right justified +*/ + +t_uint64 ReadB (t_uint64 va) +{ +t_uint64 pa; + +if (dmapen) pa = trans_d (va, cm_racc); /* mapping on? */ +else pa = va; +return ReadPB (pa); +} + +t_uint64 ReadW (t_uint64 va) +{ +t_uint64 pa; + +if (va & 1) ABORT1 (va, EXC_ALIGN); /* must be W aligned */ +if (dmapen) pa = trans_d (va, cm_racc); /* mapping on? */ +else pa = va; +return ReadPW (pa); +} + +t_uint64 ReadL (t_uint64 va) +{ +t_uint64 pa; + +if (va & 3) ABORT1 (va, EXC_ALIGN); /* must be L aligned */ +if (dmapen) pa = trans_d (va, cm_racc); /* mapping on? */ +else pa = va; +return ReadPL (pa); +} + +t_uint64 ReadQ (t_uint64 va) +{ +t_uint64 pa; + +if (va & 7) ABORT1 (va, EXC_ALIGN); /* must be Q aligned */ +if (dmapen) pa = trans_d (va, cm_racc); /* mapping on? */ +else pa = va; +return ReadPQ (pa); +} + +/* Read with generalized access controls - used by PALcode */ + +t_uint64 ReadAccL (t_uint64 va, uint32 acc) +{ +t_uint64 pa; + +if (va & 3) ABORT1 (va, EXC_ALIGN); /* must be L aligned */ +if (dmapen) pa = trans_d (va, acc); /* mapping on? */ +else pa = va; +return ReadPL (pa); +} + +t_uint64 ReadAccQ (t_uint64 va, uint32 acc) +{ +t_uint64 pa; + +if (va & 7) ABORT1 (va, EXC_ALIGN); /* must be Q aligned */ +if (dmapen) pa = trans_d (va, acc); /* mapping on? */ +else pa = va; +return ReadPQ (pa); +} + +/* Read instruction */ + +uint32 ReadI (t_uint64 va) +{ +t_uint64 pa; + +if (!pal_mode) pa = trans_i (va); /* mapping on? */ +else pa = va; +return (uint32) ReadPL (pa); +} + +/* Write virtual aligned + + Inputs: + va = virtual address + val = data to be written, right justified in 32b or 64b + Output: + none +*/ + +void WriteB (t_uint64 va, t_uint64 dat) +{ +t_uint64 pa; + +if (dmapen) pa = trans_d (va, cm_wacc); /* mapping on? */ +else pa = va; +WritePB (pa, dat); +return; +} + +void WriteW (t_uint64 va, t_uint64 dat) +{ +t_uint64 pa; + +if (va & 1) ABORT1 (va, EXC_ALIGN); /* must be W aligned */ +if (dmapen) pa = trans_d (va, cm_wacc); /* mapping on? */ +else pa = va; +WritePW (pa, dat); +return; +} + +void WriteL (t_uint64 va, t_uint64 dat) +{ +t_uint64 pa; + +if (va & 3) ABORT1 (va, EXC_ALIGN); /* must be L aligned */ +if (dmapen) pa = trans_d (va, cm_wacc); /* mapping on? */ +else pa = va; +WritePL (pa, dat); +return; +} + +void WriteQ (t_uint64 va, t_uint64 dat) +{ +t_uint64 pa; + +if (va & 7) ABORT1 (va, EXC_ALIGN); /* must be Q aligned */ +if (dmapen) pa = trans_d (va, cm_wacc); /* mapping on? */ +else pa = va; +WritePQ (pa, dat); +return; +} + +/* Write with generalized access controls - used by PALcode */ + +void WriteAccL (t_uint64 va, t_uint64 dat, uint32 acc) +{ +t_uint64 pa; + +if (va & 3) ABORT1 (va, EXC_ALIGN); /* must be L aligned */ +if (dmapen) pa = trans_d (va, acc); /* mapping on? */ +else pa = va; +WritePL (pa, dat); +return; +} + +void WriteAccQ (t_uint64 va, t_uint64 dat, uint32 acc) +{ +t_uint64 pa; + +if (va & 7) ABORT1 (va, EXC_ALIGN); /* must be Q aligned */ +if (dmapen) pa = trans_d (va, acc); /* mapping on? */ +else pa = va; +WritePQ (pa, dat); +return; +} + +/* Read and write physical aligned - access point to I/O */ + +INLINE t_uint64 ReadPB (t_uint64 pa) +{ +t_uint64 val; + +if (ADDR_IS_MEM (pa)) { + uint32 bo = ((uint32) pa) & 07; + return (((M[pa >> 3] >> (bo << 3))) & M8); + } +if (ReadIO (pa, &val, L_BYTE)) return val; +return 0; +} + +INLINE t_uint64 ReadPW (t_uint64 pa) +{ +t_uint64 val; + +if (ADDR_IS_MEM (pa)) { + uint32 bo = ((uint32) pa) & 06; + return (((M[pa >> 3] >> (bo << 3))) & M16); + } +if (ReadIO (pa, &val, L_WORD)) return val; +return 0; +} + +INLINE t_uint64 ReadPL (t_uint64 pa) +{ +t_uint64 val; + +if (ADDR_IS_MEM (pa)) { + if (pa & 4) return (((M[pa >> 3] >> 32)) & M32); + return ((M[pa >> 3]) & M32); + } +if (ReadIO (pa, &val, L_LONG)) return val; +return 0; +} + +INLINE t_uint64 ReadPQ (t_uint64 pa) +{ +t_uint64 val; + +if (ADDR_IS_MEM (pa)) return M[pa >> 3]; +if (ReadIO (pa, &val, L_QUAD)) return val; +return 0; +} + +INLINE void WritePB (t_uint64 pa, t_uint64 dat) +{ +dat = dat & M8; +if (ADDR_IS_MEM (pa)) { + uint32 bo = ((uint32) pa) & 07; + M[pa >> 3] = (M[pa >> 3] & ~(((t_uint64) M8) << (bo << 3))) | + (dat << (bo << 3)); + } +else WriteIO (pa, dat, L_BYTE); +return; +} + +INLINE void WritePW (t_uint64 pa, t_uint64 dat) +{ +dat = dat & M16; +if (ADDR_IS_MEM (pa)) { + uint32 bo = ((uint32) pa) & 07; + M[pa >> 3] = (M[pa >> 3] & ~(((t_uint64) M16) << (bo << 3))) | + (dat << (bo << 3)); + } +else WriteIO (pa, dat, L_WORD); +return; +} + +INLINE void WritePL (t_uint64 pa, t_uint64 dat) +{ +dat = dat & M32; +if (ADDR_IS_MEM (pa)) { + if (pa & 4) M[pa >> 3] = (M[pa >> 3] & M32) | + (dat << 32); + else M[pa >> 3] = (M[pa >> 3] & ~((t_uint64) M32)) | dat; + } +else WriteIO (pa, dat, L_LONG); +return; +} + +INLINE void WritePQ (t_uint64 pa, t_uint64 dat) +{ +if (ADDR_IS_MEM (pa)) M[pa >> 3] = dat; +else WriteIO (pa, dat, L_QUAD); +return; +} + diff --git a/alpha/alpha_sys.c b/alpha/alpha_sys.c new file mode 100644 index 00000000..630f9df5 --- /dev/null +++ b/alpha/alpha_sys.c @@ -0,0 +1,814 @@ +/* alpha_sys.c: Alpha simulator interface + + Copyright (c) 2003-2006, Robert M Supnik + + Permission is hereby granted, free of charge, to any person obtaining a + copy of this software and associated documentation files (the "Software"), + to deal in the Software without restriction, including without limitation + the rights to use, copy, modify, merge, publish, distribute, sublicense, + and/or sell copies of the Software, and to permit persons to whom the + Software is furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + ROBERT M SUPNIK BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + Except as contained in this notice, the name of Robert M Supnik shall not be + used in advertising or otherwise to promote the sale, use or other dealings + in this Software without prior written authorization from Robert M Supnik. +*/ + +#include "alpha_defs.h" +#include + +extern UNIT cpu_unit; +extern REG cpu_reg[]; +extern int32 sim_switches; +extern uint32 pal_type; + +t_stat fprint_sym_m (FILE *of, t_addr addr, uint32 inst); +t_stat parse_sym_m (char *cptr, t_addr addr, t_value *inst); +int32 parse_reg (char *cptr); + +extern t_stat fprint_pal_hwre (FILE *of, uint32 inst); +extern t_stat parse_pal_hwre (char *cptr, t_value *inst); +extern t_bool rom_wr (t_uint64 pa, t_uint64 val, uint32 lnt); + +/* SCP data structures and interface routines + + sim_PC pointer to saved PC register descriptor + sim_emax number of words for examine + sim_stop_messages array of pointers to stop messages + sim_load binary loader +*/ + +REG *sim_PC = &cpu_reg[0]; + +int32 sim_emax = 1; + +const char *sim_stop_messages[] = { + "Unknown error", + "HALT instruction", + "Breakpoint", + "Unsupported PAL variation", + "Kernel stack not valid", + "Unknown abort code", + "Memory management error" + }; + +/* Binary loader + + The binary loader handles absolute system images, that is, system + images linked /SYSTEM. These are simply a byte stream, with no + origin or relocation information. + + -r load ROM + -o specify origin +*/ + +t_stat sim_load (FILE *fileref, char *cptr, char *fnam, int flag) +{ +t_stat r; +int32 i; +t_uint64 origin; + +if (flag) return SCPE_ARG; /* dump? */ +origin = 0; /* memory */ +if (sim_switches & SWMASK ('O')) { /* origin? */ + origin = get_uint (cptr, 16, 0xFFFFFFFF, &r); + if (r != SCPE_OK) return SCPE_ARG; + } + +while ((i = getc (fileref)) != EOF) { /* read byte stream */ + if (sim_switches & SWMASK ('R')) { /* ROM? */ + if (!rom_wr (origin, i, L_BYTE)) + return SCPE_NXM; + } + else if (ADDR_IS_MEM (origin)) /* valid memory? */ + WritePB (origin, i); + else return SCPE_NXM; + origin = origin + 1; + } +return SCPE_OK; +} + +/* Opcode mnemonics table */ + +#define CL_NO 0 /* no operand */ +#define CL_BR 1 /* branch */ +#define CL_MR 2 /* memory reference */ +#define CL_IO 3 /* integer opr */ +#define CL_FO 4 /* floating opr */ +#define CL_MO 5 /* memory opr */ +#define CL_JP 6 /* jump */ +#define CL_HW 7 /* hardware */ +#define CL_M_PAL 0x00F0 +#define CL_V_PAL 4 +#define CL_VMS (1u << (PAL_VMS + CL_V_PAL)) +#define CL_UNIX (1u << (PAL_UNIX + CL_V_PAL)) +#define CL_NT (1u << (PAL_NT + CL_V_PAL)) +#define FL_RA 0x0100 +#define FL_RB 0x0200 +#define FL_RC 0x0400 +#define FL_RBI 0x0800 +#define FL_MDP 0x1000 +#define FL_BDP 0x2000 +#define FL_JDP 0x4000 +#define FL_LIT 0x8000 +#define CL_CLASS 0x000F +#define PAL_MASK(x) (1u << (pal_type + CL_V_PAL)) + +#define C_NO CL_NO +#define C_PCM CL_NO | CL_VMS | CL_UNIX | CL_NT +#define C_PVM CL_NO | CL_VMS +#define C_PUN CL_NO | CL_UNIX +#define C_PNT CL_NO | CL_NT +#define C_BR CL_BR | FL_RA | FL_BDP +#define C_MR CL_MR | FL_RA | FL_RB | FL_RBI | FL_MDP +#define C_FE CL_MO | FL_RB | FL_RBI +#define C_RV CL_MO | FL_RA +#define C_MO CL_MO | FL_RA | FL_RB +#define C_IO CL_IO | FL_RA | FL_RB | FL_RC | FL_LIT +#define C_IAC CL_IO | FL_RA | FL_RC +#define C_IBC CL_IO | FL_RB | FL_RC | FL_LIT +#define C_FO CL_FO | FL_RA | FL_RB | FL_RC +#define C_FAC CL_FO | FL_RA | FL_RC +#define C_FBC CL_FO | FL_RB | FL_RC +#define C_JP CL_JP | FL_RA | FL_RB | FL_RBI | FL_JDP +#define C_HW CL_HW + +uint32 masks[8] = { + 0xFFFFFFFF, 0xFC000000, + 0xFC000000, 0xFC000FE0, + 0xFC00FFE0, 0xFC00FFFF, + 0xFC00C000, 0xFC000000 + }; + +const char *opcode[] = { + "HALT", "DRAINA", "CFLUSH", "LDQP", /* VMS PALcode */ + "STQP", "SWPCTX", "MFPR_ASN", "MTPR_ASTEN", + "MTPR_ASTSR", "CSERVE", "SWPPAL", "MFPR_FEN", + "MTPR_FEN", "MTPR_IPIR", "MFPR_IPL", "MTPR_IPL", + "MFPR_MCES", "MTPR_MCES", "MFPR_PCBB", "MFPR_PRBR", + "MTPR_PRBR", "MFPR_PTBR", "MFPR_SCBB", "MTPR_SCBB", + "MTPR_SIRR", "MFPR_SISR", "MFPR_TBCHK", "MTPR_TBIA", + "MTPR_TBIAP", "MTPR_TBIS", "MFPR_ESP", "MTPR_ESP", + "MFPR_SSP", "MTPR_SSP", "MFPR_USP", "MTPR_USP", + "MTPR_TBISD", "MTPR_TBISI", "MFPR_ASTEN", "MFPR_ASTSR", + "MFPR_VTBR", "MTPR_VTBR", "MTPR_PERFMON", "MTPR_DATFX", + "MFPR_VIRBND", "MTPR_VIRBND", "MFPR_SYSPTBR", "MTPR_SYSPTBR", + "WTINT", "MFPR_WHAMI", + "BPT", "BUGCHK", "CHME", "CHMK", + "CHMS", "CHMU", "IMB", "INSQHIL", + "INSQTIL", "INSQHIQ", "INSQTIQ", "INSQUEL", + "INSQUEQ", "INSQUEL/D", "INSQUEQ/D", "PROBER", + "PROBEW", "RD_PS", "REI", "REMQHIL", + "REMQTIL", "REMQHIQ", "REMQTIQ", "REMQUEL", + "REMQUEQ", "REMQUEL/D", "REMQUEQ/D", "SWASTEN", + "WR_PS_SW", "RSCC", "RD_UNQ", "WR_UNQ", + "AMOVRR", "AMOVRM", "INSQHILR", "INSQTILR", + "INSQHIQR", "INSQTIQR", "REMQHILR", "REMQTILR", + "REMQHIQR", "REMQTIQR", "GENTRAP", "CLRFEN", + "RDMCES", "WRMCES", "WRVIRBND", "WRSYSPTBR", /* UNIX PALcode */ + "WRFEN", "WRVPTPTR", "WRASN", + "SWPCTX", "WRVAL", "RDVAL", "TBI", + "WRENT", "SWPIPL", "RDPS", "WRKGP", + "WRUSP", "WRPERFMON", "RDUSP", + "WHAMI", "RETSYS", "RTI", + "URTI", "RDUNIQUE", "WRUNIQUE", + "LDA", "LDAH", "LDBU", "LDQ_U", + "LDWU", "STW", "STB", "STQ_U", + "ADDL", "S4ADDL", "SUBL", "S4SUBL", + "CMPBGE", "S8ADDL", "S8SUBL", "CMPULT", + "ADDQ", "S4ADDQ", "SUBQ", "S4SUBQ", + "CMPEQ", "S8ADDQ", "S8SUBQ", "CMPULE", + "ADDL/V", "SUBL/V", "CMPLT", + "ADDQ/V", "SUBQ/V", "CMPLE", + "AND", "BIC", "CMOVLBS", "CMOVLBC", + "BIS", "CMOVEQ", "CMOVNE", "ORNOT", + "XOR", "CMOVLT", "CMOVGE", "EQV", + "CMOVLE", "CMOVGT", + "MSKBL", "EXTBL", "INSBL", + "MSKWL", "EXTWL", "INSWL", + "MSKLL", "EXTLL", "INSLL", + "ZAP", "ZAPNOT", "MSKQL", "SRL", + "EXTQL", "SLL", "INSQL", "SRA", + "MSKWQ", "EXTWQ", "INSWQ", + "MSKLQ", "EXTLQ", "INSLQ", + "MSKQH", "EXTQH", "INSQH", + "MULL", "MULQ", "UMULH", + "MULL/V", "MULLQ/V", + "ITOFS", "ITOFF", "ITOFT", + "SQRTF/C", "SQRTF", "SQRTF/UC", "SQRTF/U", + "SQRTF/SC", "SQRTF/S", "SQRTF/SUC", "SQRTF/SU", + "SQRTG/C", "SQRTG", "SQRTG/UC", "SQRTG/U", + "SQRTG/SC", "SQRTG/S", "SQRTG/SUC", "SQRTG/SU", + "SQRTS/C", "SQRTS/M", "SQRTS", "SQRTS/D", + "SQRTS/UC", "SQRTS/UM", "SQRTS/U", "SQRTS/UD", + "SQRTS/SUC", "SQRTS/SUM", "SQRTS/SU", "SQRTS/SUD", + "SQRTS/SUIC", "SQRTS/SUIM", "SQRTS/SUI", "SQRTS/SUID", + "SQRTT/C", "SQRTT/M", "SQRTT", "SQRTT/D", + "SQRTT/UC", "SQRTT/UM", "SQRTT/U", "SQRTT/UD", + "SQRTT/SUC", "SQRTT/SUM", "SQRTT/SU", "SQRTT/SUD", + "SQRTT/SUIC", "SQRTT/SUIM", "SQRTT/SUI", "SQRTT/SUID", + "ADDF/C", "ADDF", "ADDF/UC", "ADDF/U", + "ADDF/SC", "ADDF/S", "ADDF/SUC", "ADDF/SU", + "SUBF/C", "SUBF", "SUBF/UC", "SUBF/U", + "SUBF/SC", "SUBF/S", "SUBF/SUC", "SUBF/SU", + "MULF/C", "MULF", "MULF/UC", "MULF/U", + "MULF/SC", "MULF/S", "MULF/SUC", "MULF/SU", + "DIVF/C", "DIVF", "DIVF/UC", "DIVF/U", + "DIVF/SC", "DIVF/S", "DIVF/SUC", "DIVF/SU", + "ADDG/C", "ADDG", "ADDG/UC", "ADDG/U", + "ADDG/SC", "ADDG/S", "ADDG/SUC", "ADDG/SU", + "SUBG/C", "SUBG", "SUBG/UC", "SUBG/U", + "SUBG/SC", "SUBG/S", "SUBG/SUC", "SUBG/SU", + "MULG/C", "MULG", "MULG/UC", "MULG/U", + "MULG/SC", "MULG/S", "MULG/SUC", "MULG/SU", + "DIVG/C", "DIVG", "DIVG/UC", "DIVG/U", + "DIVG/SC", "DIVG/S", "DIVG/SUC", "DIVG/SU", + "CVTDG/C", "CVTDG", "CVTDG/UC", "CVTDG/U", + "CVTDG/SC", "CVTDG/S", "CVTDG/SUC", "CVTDG/SU", + "CVTGF/C", "CVTGF", "CVTGF/UC", "CVTGF/U", + "CVTGF/SC", "CVTGF/S", "CVTGF/SUC", "CVTGF/SU", + "CVTGD/C", "CVTGD", "CVTGD/UC", "CVTGD/U", + "CVTGD/SC", "CVTGD/S", "CVTGD/SUC", "CVTGD/SU", + "CVTGQ/C", "CVTGQ", "CVTGQ/VC", "CVTGQ/V", + "CVTGQ/SC", "CVTGQ/S", "CVTGQ/SVC", "CVTGQ/SV", + "CVTQF/C", "CVTQF", "CVTQG/C", "CVTQG", + "CMPGEQ/C", "CMPGEQ/SC", "CMPGLT/C", "CMPGLT/SC", + "CMPGLE/C", "CMPGLE/SC", + "ADDS/C", "ADDS/M", "ADDS", "ADDS/D", + "ADDS/UC", "ADDS/UM", "ADDS/U", "ADDS/UD", + "ADDS/SUC", "ADDS/SUM", "ADDS/SU", "ADDS/SUD", + "ADDS/SUIC", "ADDS/SUIM", "ADDS/SUI", "ADDS/SUID", + "SUBS/C", "SUBS/M", "SUBS", "SUBS/D", + "SUBS/UC", "SUBS/UM", "SUBS/U", "SUBS/UD", + "SUBS/SUC", "SUBS/SUM", "SUBS/SU", "SUBS/SUD", + "SUBS/SUIC", "SUBS/SUIM", "SUBS/SUI", "SUBS/SUID", + "MULS/C", "MULS/M", "MULS", "MULS/D", + "MULS/UC", "MULS/UM", "MULS/U", "MULS/UD", + "MULS/SUC", "MULS/SUM", "MULS/SU", "MULS/SUD", + "MULS/SUIC", "MULS/SUIM", "MULS/SUI", "MULS/SUID", + "DIVS/C", "DIVS/M", "DIVS", "DIVS/D", + "DIVS/UC", "DIVS/UM", "DIVS/U", "DIVS/UD", + "DIVS/SUC", "DIVS/SUM", "DIVS/SU", "DIVS/SUD", + "DIVS/SUIC", "DIVS/SUIM", "DIVS/SUI", "DIVS/SUID", + "ADDT/C", "ADDT/M", "ADDT", "ADDT/D", + "ADDT/UC", "ADDT/UM", "ADDT/U", "ADDT/UD", + "ADDT/SUC", "ADDT/SUM", "ADDT/SU", "ADDT/SUD", + "ADDT/SUIC", "ADDT/SUIM", "ADDT/SUI", "ADDT/SUID", + "SUBT/C", "SUBT/M", "SUBT", "SUBT/D", + "SUBT/UC", "SUBT/UM", "SUBT/U", "SUBT/UD", + "SUBT/SUC", "SUBT/SUM", "SUBT/SU", "SUBT/SUD", + "SUBT/SUIC", "SUBT/SUIM", "SUBT/SUI", "SUBT/SUID", + "MULT/C", "MULT/M", "MULT", "MULT/D", + "MULT/UC", "MULT/UM", "MULT/U", "MULT/UD", + "MULT/SUC", "MULT/SUM", "MULT/SU", "MULT/SUD", + "MULT/SUIC", "MULT/SUIM", "MULT/SUI", "MULT/SUID", + "DIVT/C", "DIVT/M", "DIVT", "DIVT/D", + "DIVT/UC", "DIVT/UM", "DIVT/U", "DIVT/UD", + "DIVT/SUC", "DIVT/SUM", "DIVT/SU", "DIVT/SUD", + "DIVT/SUIC", "DIVT/SUIM", "DIVT/SUI", "DIVT/SUID", + "CVTTS/C", "CVTTS/M", "CVTTS", "CVTTS/D", + "CVTTS/UC", "CVTTS/UM", "CVTTS/U", "CVTTS/UD", + "CVTTS/SUC", "CVTTS/SUM", "CVTTS/SU", "CVTTS/SUD", + "CVTTS/SUIC", "CVTTS/SUIM", "CVTTS/SUI", "CVTTS/SUID", + "CVTTQ/C", "CVTTQ/M", "CVTTQ", "CVTTQ/D", + "CVTTQ/VC", "CVTTQ/VM", "CVTTQ/V", "CVTTQ/VD", + "CVTTQ/SVC", "CVTTQ/SVM", "CVTTQ/SV", "CVTTQ/SVD", + "CVTTQ/SVIC", "CVTTQ/SVIM", "CVTTQ/SVI", "CVTTQ/SVID", + "CVTQS/C", "CVTQS/M", "CVTQS", "CVTQS/D", + "CVTQS/SUIC", "CVTQS/SUIM", "CVTQS/SUI", "CVTQS/SUID", + "CVTQT/C", "CVTQT/M", "CVTQT", "CVTQT/D", + "CVTQT/SUIC", "CVTQT/SUIM", "CVTQT/SUI", "CVTQT/SUID", + "CMPTUN/C", "CMPTUN/S", "CMPTEQ/C", "CMPTEQ/S", + "CMPTLT/C", "CMPTLT/S", "CMPTLE/C", "CMPTLE/S", + "CVTLQ", "CPYS", "CPYSN", "CPYSE", + "MT_FPCR", "MF_FPCR", + "FCMOVEQ", "FCMOVNE", "FCMOVLT", + "FCMOVGE", "FCMOVLE", "FCMOVGT", + "CVTQL", "CVTQL/V", "CVTQL/SV", + "TRAPB", "EXCB", "MB", "WMB", + "FETCH", "FETCH_M", "RPCC", + "RC", "RS", + "JMP", "JSR", "RET", "JSR_COROUTINE", + "SEXTB", "SEXTW", + "CTPOP", "PERR", "CTLZ", "CTTZ", + "UNPKBW", "UNPKBL", "PKWB", "PKLB", + "MINSB8", "MINSW4", "MINUB8", "MINUW4", + "MAXSB8", "MAXSW4", "MAXUB8", "MAXUW4", + "FTOIT", "FTOIS", + "LDF", "LDG", "LDS", "LDT", + "STS", "STG", "STS", "STT", + "LDL", "LDQ", "LDL_L", "LDQ_L", + "STL", "STQ", "STL_L", "STQ_L", + "BR", "FBEQ", "FBLT", "FBLE", + "BSR", "FBNE", "BFGE", "FBGT", + "BLBC", "BEQ", "BLT", "BLE", + "BLBS", "BNE", "BGE", "BGT", + NULL + }; + +const uint32 opval[] = { + 0x00000000, C_PCM, 0x00000001, C_PCM, 0x00000002, C_PCM, 0x00000003, C_PVM, + 0x00000004, C_PVM, 0x00000005, C_PVM, 0x00000006, C_PVM, 0x00000007, C_PVM, + 0x00000008, C_PVM, 0x00000009, C_PCM, 0x0000000A, C_PCM, 0x0000000B, C_PVM, + 0x0000000C, C_PVM, 0x0000000D, C_PVM, 0x0000000E, C_PVM, 0x0000000F, C_PVM, + 0x00000010, C_PVM, 0x00000011, C_PVM, 0x00000012, C_PVM, 0x00000013, C_PVM, + 0x00000014, C_PVM, 0x00000015, C_PVM, 0x00000016, C_PVM, 0x00000017, C_PVM, + 0x00000018, C_PVM, 0x00000019, C_PVM, 0x0000001A, C_PVM, 0x0000001B, C_PVM, + 0x0000001C, C_PVM, 0x0000001D, C_PVM, 0x0000001E, C_PVM, 0x0000001F, C_PVM, + 0x00000020, C_PVM, 0x00000021, C_PVM, 0x00000022, C_PVM, 0x00000023, C_PVM, + 0x00000024, C_PVM, 0x00000025, C_PVM, 0x00000026, C_PVM, 0x00000027, C_PVM, + 0x00000029, C_PVM, 0x0000002A, C_PVM, 0x0000002B, C_PVM, 0x0000002E, C_PVM, + 0x00000030, C_PVM, 0x00000031, C_PVM, 0x00000032, C_PVM, 0x00000033, C_PVM, + 0x0000003E, C_PCM, 0x0000003F, C_PVM, + 0x00000080, C_PCM, 0x00000081, C_PCM, 0x00000082, C_PVM, 0x00000083, C_PVM, + 0x00000084, C_PVM, 0x00000085, C_PVM, 0x00000086, C_PCM, 0x00000087, C_PVM, + 0x00000088, C_PVM, 0x00000089, C_PVM, 0x0000008A, C_PVM, 0x0000008B, C_PVM, + 0x0000008C, C_PVM, 0x0000008D, C_PVM, 0x0000008E, C_PVM, 0x0000008F, C_PVM, + 0x00000090, C_PVM, 0x00000091, C_PVM, 0x00000092, C_PVM, 0x00000093, C_PVM, + 0x00000094, C_PVM, 0x00000095, C_PVM, 0x00000096, C_PVM, 0x00000097, C_PVM, + 0x00000098, C_PVM, 0x00000099, C_PVM, 0x0000009A, C_PVM, 0x0000009B, C_PVM, + 0x0000009C, C_PVM, 0x0000009D, C_PVM, 0x0000009E, C_PVM, 0x0000009F, C_PVM, + 0x000000A0, C_PVM, 0x000000A1, C_PVM, 0x000000A2, C_PVM, 0x000000A3, C_PVM, + 0x000000A4, C_PVM, 0x000000A5, C_PVM, 0x000000A6, C_PVM, 0x000000A7, C_PVM, + 0x000000A8, C_PVM, 0x000000A9, C_PVM, 0x000000AA, C_PCM, 0x000000AE, C_PCM, + 0x00000010, C_PUN, 0x00000011, C_PUN, 0x00000013, C_PUN, 0x00000014, C_PUN, + 0x0000002B, C_PUN, 0x0000002D, C_PUN, 0x0000002E, C_PUN, + 0x00000030, C_PUN, 0x00000031, C_PUN, 0x00000032, C_PUN, 0x00000033, C_PUN, + 0x00000034, C_PUN, 0x00000035, C_PUN, 0x00000036, C_PUN, 0x00000037, C_PUN, + 0x00000038, C_PUN, 0x00000039, C_PUN, 0x0000003A, C_PUN, + 0x0000003C, C_PUN, 0x0000003D, C_PUN, 0x0000003F, C_PUN, + 0x00000092, C_PUN, 0x0000009E, C_PUN, 0x0000009F, C_PUN, + 0x20000000, C_MR, 0x24000000, C_MR, 0x28000000, C_MR, 0x2C000000, C_MR, + 0x30000000, C_MR, 0x34000000, C_MR, 0x38000000, C_MR, 0x3C000000, C_MR, + 0x40000000, C_IO, 0x40000040, C_IO, 0x40000120, C_IO, 0x40000160, C_IO, + 0x400001C0, C_IO, 0x40000240, C_IO, 0x40000360, C_IO, 0x400003A0, C_IO, + 0x40000400, C_IO, 0x40000440, C_IO, 0x40000520, C_IO, 0x40000560, C_IO, + 0x400005A0, C_IO, 0x40000640, C_IO, 0x40000760, C_IO, 0x400007A0, C_IO, + 0x40000800, C_IO, 0x40000920, C_IO, 0x400009A0, C_IO, + 0x40000C00, C_IO, 0x40000D20, C_IO, 0x40000DA0, C_IO, + 0x44000000, C_IO, 0x44000100, C_IO, 0x44000280, C_IO, 0x440002C0, C_IO, + 0x44000400, C_IO, 0x44000480, C_IO, 0x440004C0, C_IO, 0x44000500, C_IO, + 0x44000800, C_IO, 0x44000880, C_IO, 0x440008C0, C_IO, 0x44000900, C_IO, + 0x44000C80, C_IO, 0x44000CC0, C_IO, + 0x48000040, C_IO, 0x480000C0, C_IO, 0x48000160, C_IO, + 0x48000240, C_IO, 0x480002C0, C_IO, 0x48000360, C_IO, + 0x48000440, C_IO, 0x480004C0, C_IO, 0x48000560, C_IO, + 0x48000600, C_IO, 0x48000620, C_IO, 0x48000640, C_IO, 0x48000680, C_IO, + 0x480006C0, C_IO, 0x48000720, C_IO, 0x48000760, C_IO, 0x48000780, C_IO, + 0x48000A40, C_IO, 0x48000AE0, C_IO, 0x48000B40, C_IO, + 0x48000C40, C_IO, 0x48000CE0, C_IO, 0x48000D40, C_IO, + 0x48000E40, C_IO, 0x48000EE0, C_IO, 0x48000F40, C_IO, + 0x4C000000, C_IO, 0x4C000400, C_IO, 0x4C000600, C_IO, + 0x4C000800, C_IO, 0x4C000C00, C_IO, + 0x501F0080, C_FAC, 0x501F0280, C_FAC, 0x501F0480, C_FAC, + 0x53E00140, C_FBC, 0x53E01140, C_FBC, 0x53E02140, C_FBC, 0x53E03140, C_FBC, + 0x53E08140, C_FBC, 0x53E09140, C_FBC, 0x53E0A140, C_FBC, 0x53E0B140, C_FBC, + 0x53E00540, C_FBC, 0x53E01540, C_FBC, 0x53E02540, C_FBC, 0x53E03540, C_FBC, + 0x53E08540, C_FBC, 0x53E09540, C_FBC, 0x53E0A540, C_FBC, 0x53E0B540, C_FBC, + 0x53E00160, C_FBC, 0x53E00960, C_FBC, 0x53E01160, C_FBC, 0x53E01960, C_FBC, + 0x53E02160, C_FBC, 0x53E02960, C_FBC, 0x53E03160, C_FBC, 0x53E03960, C_FBC, + 0x53E0A160, C_FBC, 0x53E0A960, C_FBC, 0x53E0B160, C_FBC, 0x53E0B960, C_FBC, + 0x53E0E160, C_FBC, 0x53E0E960, C_FBC, 0x53E0F160, C_FBC, 0x53E0F960, C_FBC, + 0x53E00560, C_FBC, 0x53E00D60, C_FBC, 0x53E01560, C_FBC, 0x53E01D60, C_FBC, + 0x53E02560, C_FBC, 0x53E02D60, C_FBC, 0x53E03560, C_FBC, 0x53E03D60, C_FBC, + 0x53E0A560, C_FBC, 0x53E0AD60, C_FBC, 0x53E0B560, C_FBC, 0x53E0BD60, C_FBC, + 0x53E0E560, C_FBC, 0x53E0ED60, C_FBC, 0x53E0F560, C_FBC, 0x53E0FD60, C_FBC, + 0x54000000, C_FO, 0x54001000, C_FO, 0x54002000, C_FO, 0x54003000, C_FO, + 0x54008000, C_FO, 0x54009000, C_FO, 0x5400A000, C_FO, 0x5400B000, C_FO, + 0x54000020, C_FO, 0x54001020, C_FO, 0x54002020, C_FO, 0x54003020, C_FO, + 0x54008020, C_FO, 0x54009020, C_FO, 0x5400A020, C_FO, 0x5400B020, C_FO, + 0x54000040, C_FO, 0x54001040, C_FO, 0x54002040, C_FO, 0x54003040, C_FO, + 0x54008040, C_FO, 0x54009040, C_FO, 0x5400A040, C_FO, 0x5400B040, C_FO, + 0x54000060, C_FO, 0x54001060, C_FO, 0x54002060, C_FO, 0x54003060, C_FO, + 0x54008060, C_FO, 0x54009060, C_FO, 0x5400A060, C_FO, 0x5400B060, C_FO, + 0x54000400, C_FO, 0x54001400, C_FO, 0x54002400, C_FO, 0x54003400, C_FO, + 0x54008400, C_FO, 0x54009400, C_FO, 0x5400A400, C_FO, 0x5400B400, C_FO, + 0x54000420, C_FO, 0x54001420, C_FO, 0x54002420, C_FO, 0x54003420, C_FO, + 0x54008420, C_FO, 0x54009420, C_FO, 0x5400A420, C_FO, 0x5400B420, C_FO, + 0x54000440, C_FO, 0x54001440, C_FO, 0x54002440, C_FO, 0x54003440, C_FO, + 0x54008440, C_FO, 0x54009440, C_FO, 0x5400A440, C_FO, 0x5400B440, C_FO, + 0x54000460, C_FO, 0x54001460, C_FO, 0x54002460, C_FO, 0x54003460, C_FO, + 0x54008460, C_FO, 0x54009460, C_FO, 0x5400A460, C_FO, 0x5400B460, C_FO, + 0x57E003C0, C_FBC, 0x57E013C0, C_FBC, 0x57E023C0, C_FBC, 0x57E033C0, C_FBC, + 0x57E083C0, C_FBC, 0x57E093C0, C_FBC, 0x57E0A3C0, C_FBC, 0x57E0B3C0, C_FBC, + 0x57E00580, C_FBC, 0x57E01580, C_FBC, 0x57E02580, C_FBC, 0x57E03580, C_FBC, + 0x57E08580, C_FBC, 0x57E09580, C_FBC, 0x57E0A580, C_FBC, 0x57E0B580, C_FBC, + 0x57E005A0, C_FBC, 0x57E015A0, C_FBC, 0x57E025A0, C_FBC, 0x57E035A0, C_FBC, + 0x57E085A0, C_FBC, 0x57E095A0, C_FBC, 0x57E0A5A0, C_FBC, 0x57E0B5A0, C_FBC, + 0x57E005E0, C_FBC, 0x57E015E0, C_FBC, 0x57E025E0, C_FBC, 0x57E035E0, C_FBC, + 0x57E085E0, C_FBC, 0x57E095E0, C_FBC, 0x57E0A5E0, C_FBC, 0x57E0B5E0, C_FBC, + 0x57E00780, C_FBC, 0x57E01780, C_FBC, 0x57E007C0, C_FBC, 0x57E017C0, C_FBC, + 0x540014A0, C_FO, 0x540094A0, C_FO, 0x540014C0, C_FO, 0x540094C0, C_FO, + 0x540014E0, C_FO, 0x540094E0, C_FO, + 0x58000000, C_FO, 0x58000800, C_FO, 0x58001000, C_FO, 0x58001800, C_FO, + 0x58002000, C_FO, 0x58002800, C_FO, 0x58003000, C_FO, 0x58003800, C_FO, + 0x5800A000, C_FO, 0x5800A800, C_FO, 0x5800B000, C_FO, 0x5800B800, C_FO, + 0x5800E000, C_FO, 0x5800E800, C_FO, 0x5800F000, C_FO, 0x5800F800, C_FO, + 0x58000020, C_FO, 0x58000820, C_FO, 0x58001020, C_FO, 0x58001820, C_FO, + 0x58002020, C_FO, 0x58002820, C_FO, 0x58003020, C_FO, 0x58003820, C_FO, + 0x5800A020, C_FO, 0x5800A820, C_FO, 0x5800B020, C_FO, 0x5800B820, C_FO, + 0x5800E020, C_FO, 0x5800E820, C_FO, 0x5800F020, C_FO, 0x5800F820, C_FO, + 0x58000040, C_FO, 0x58000840, C_FO, 0x58001040, C_FO, 0x58001840, C_FO, + 0x58002040, C_FO, 0x58002840, C_FO, 0x58003040, C_FO, 0x58003840, C_FO, + 0x5800A040, C_FO, 0x5800A840, C_FO, 0x5800B040, C_FO, 0x5800B840, C_FO, + 0x5800E040, C_FO, 0x5800E840, C_FO, 0x5800F040, C_FO, 0x5800F840, C_FO, + 0x58000060, C_FO, 0x58000860, C_FO, 0x58001060, C_FO, 0x58001860, C_FO, + 0x58002060, C_FO, 0x58002860, C_FO, 0x58003060, C_FO, 0x58003860, C_FO, + 0x5800A060, C_FO, 0x5800A860, C_FO, 0x5800B060, C_FO, 0x5800B860, C_FO, + 0x5800E060, C_FO, 0x5800E860, C_FO, 0x5800F060, C_FO, 0x5800F860, C_FO, + 0x58000400, C_FO, 0x58000C00, C_FO, 0x58001400, C_FO, 0x58001C00, C_FO, + 0x58002400, C_FO, 0x58002C00, C_FO, 0x58003400, C_FO, 0x58003C00, C_FO, + 0x5800A400, C_FO, 0x5800AC00, C_FO, 0x5800B400, C_FO, 0x5800BC00, C_FO, + 0x5800E400, C_FO, 0x5800EC00, C_FO, 0x5800F400, C_FO, 0x5800FC00, C_FO, + 0x58000420, C_FO, 0x58000C20, C_FO, 0x58001420, C_FO, 0x58001C20, C_FO, + 0x58002420, C_FO, 0x58002C20, C_FO, 0x58003420, C_FO, 0x58003C20, C_FO, + 0x5800A420, C_FO, 0x5800AC20, C_FO, 0x5800B420, C_FO, 0x5800BC20, C_FO, + 0x5800E420, C_FO, 0x5800EC20, C_FO, 0x5800F420, C_FO, 0x5800FC20, C_FO, + 0x58000440, C_FO, 0x58000C40, C_FO, 0x58001440, C_FO, 0x58001C40, C_FO, + 0x58002440, C_FO, 0x58002C40, C_FO, 0x58003440, C_FO, 0x58003C40, C_FO, + 0x5800A440, C_FO, 0x5800AC40, C_FO, 0x5800B440, C_FO, 0x5800BC40, C_FO, + 0x5800E440, C_FO, 0x5800EC40, C_FO, 0x5800F440, C_FO, 0x5800FC40, C_FO, + 0x58000460, C_FO, 0x58000C60, C_FO, 0x58001460, C_FO, 0x58001C60, C_FO, + 0x58002460, C_FO, 0x58002C60, C_FO, 0x58003460, C_FO, 0x58003C60, C_FO, + 0x5800A460, C_FO, 0x5800AC60, C_FO, 0x5800B460, C_FO, 0x5800BC60, C_FO, + 0x5800E460, C_FO, 0x5800EC60, C_FO, 0x5800F460, C_FO, 0x5800FC60, C_FO, + 0x5BE00580, C_FBC, 0x5BE00D80, C_FBC, 0x5BE01580, C_FBC, 0x5BE01D80, C_FBC, + 0x5BE02580, C_FBC, 0x5BE02D80, C_FBC, 0x5BE03580, C_FBC, 0x5BE03D80, C_FBC, + 0x5BE0A580, C_FBC, 0x5BE0AD80, C_FBC, 0x5BE0B580, C_FBC, 0x5BE0BD80, C_FBC, + 0x5BE0E580, C_FBC, 0x5BE0ED80, C_FBC, 0x5BE0F580, C_FBC, 0x5BE0FD80, C_FBC, + 0x5BE005E0, C_FBC, 0x5BE00DE0, C_FBC, 0x5BE015E0, C_FBC, 0x5BE01DE0, C_FBC, + 0x5BE025E0, C_FBC, 0x5BE02DE0, C_FBC, 0x5BE035E0, C_FBC, 0x5BE03DE0, C_FBC, + 0x5BE0A5E0, C_FBC, 0x5BE0ADE0, C_FBC, 0x5BE0B5E0, C_FBC, 0x5BE0BDE0, C_FBC, + 0x5BE0E5E0, C_FBC, 0x5BE0EDE0, C_FBC, 0x5BE0F5E0, C_FBC, 0x5BE0FDE0, C_FBC, + 0x5BE00780, C_FBC, 0x5BE00F80, C_FBC, 0x5BE01780, C_FBC, 0x5BE01F80, C_FBC, + 0x5BE0E780, C_FBC, 0x5BE0EF80, C_FBC, 0x5BE0F780, C_FBC, 0x5BE0FF80, C_FBC, + 0x5BE007C0, C_FBC, 0x5BE00FC0, C_FBC, 0x5BE017C0, C_FBC, 0x5BE01FC0, C_FBC, + 0x5BE0E7C0, C_FBC, 0x5BE0EFC0, C_FBC, 0x5BE0F7C0, C_FBC, 0x5BE0FFC0, C_FBC, + 0x58001480, C_FO, 0x58009480, C_FO, 0x580014A0, C_FO, 0x580094A0, C_FO, + 0x580014C0, C_FO, 0x580094C0, C_FO, 0x580014E0, C_FO, 0x580094E0, C_FO, + 0x5FE00200, C_IBC, 0x5C000400, C_IO, 0x5C000420, C_IO, 0x5C000440, C_IO, + 0x5C000480, C_IO, 0x5C0004A0, C_IO, + 0x5C000540, C_IO, 0x5C000560, C_IO, 0x5C000580, C_IO, + 0x5C0005A0, C_IO, 0x5C0005C0, C_IO, 0x5C0005E0, C_IO, + 0x5FE00060, C_IBC, 0x5FE00260, C_IBC, 0x5FE00A60, C_IBC, + 0x60000000, C_NO, 0x60000400, C_NO, 0x60004000, C_NO, 0x60004400, C_NO, + 0x60008000, C_FE, 0x6000A000, C_FE, 0x6000C000, C_NO, + 0x6000E000, C_RV, 0x6000F000, C_RV, + 0x68000000, C_JP, 0x68004000, C_JP, 0x68008000, C_JP, 0x6800C000, C_JP, + 0x73E00000, C_IBC, 0x73E00020, C_IBC, + 0x73E00600, C_IBC, 0x70000620, C_IO, 0x73E00640, C_IBC, 0x73E00660, C_IBC, + 0x73E00680, C_IBC, 0x73E006A0, C_IBC, 0x73E006C0, C_IBC, 0x73E006E0, C_IBC, + 0x70000700, C_IO, 0x70000720, C_IO, 0x70000740, C_IO, 0x70000780, C_IO, + 0x70000780, C_IO, 0x700007A0, C_IO, 0x700007C0, C_IO, 0x700007E0, C_IO, + 0x701F0E00, C_IAC, 0x701F0F00, C_IAC, + 0x80000000, C_MR, 0x84000000, C_MR, 0x88000000, C_MR, 0x8C000000, C_MR, + 0x90000000, C_MR, 0x94000000, C_MR, 0x98000000, C_MR, 0x9C000000, C_MR, + 0xA0000000, C_MR, 0xA4000000, C_MR, 0xA8000000, C_MR, 0xAC000000, C_MR, + 0xB0000000, C_MR, 0xB4000000, C_MR, 0xB8000000, C_MR, 0xBC000000, C_MR, + 0xC0000000, C_BR, 0xC4000000, C_BR, 0xC8000000, C_BR, 0xCC000000, C_BR, + 0xD0000000, C_BR, 0xD4000000, C_BR, 0xD8000000, C_BR, 0xDC000000, C_BR, + 0xE0000000, C_BR, 0xE4000000, C_BR, 0xE8000000, C_BR, 0xEC000000, C_BR, + 0xF0000000, C_BR, 0xF4000000, C_BR, 0xF8000000, C_BR, 0xFC000000, C_BR, + M32, 0 + }; + +/* 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) +{ +uint32 c, sc, rdx; +t_stat r; +DEVICE *dptr; + +if (uptr == NULL) uptr = &cpu_unit; /* anon = CPU */ +else if (uptr != &cpu_unit) return SCPE_ARG; /* CPU only */ +dptr = find_dev_from_unit (uptr); /* find dev */ +if (dptr == NULL) return SCPE_IERR; +if (sw & SWMASK ('D')) rdx = 10; /* get radix */ +else if (sw & SWMASK ('O')) rdx = 8; +else if (sw & SWMASK ('H')) rdx = 16; +else rdx = dptr->dradix; + +if (sw & SWMASK ('A')) { /* ASCII? */ + sc = (uint32) (addr & 0x7) * 8; /* shift count */ + c = (uint32) (val[0] >> sc) & 0x7F; + fprintf (of, (c < 0x20)? "<%02X>": "%c", c); + return 0; + } +if (sw & SWMASK ('B')) { /* byte? */ + sc = (uint32) (addr & 0x7) * 8; /* shift count */ + c = (uint32) (val[0] >> sc) & M8; + fprintf (of, "%02X", c); + return 0; + } +if (sw & SWMASK ('W')) { /* word? */ + sc = (uint32) (addr & 0x6) * 8; /* shift count */ + c = (uint32) (val[0] >> sc) & M16; + fprintf (of, "%04X", c); + return -1; + } +if (sw & SWMASK ('L')) { /* long? */ + if (addr & 4) c = (uint32) (val[0] >> 32) & M32; + else c = (uint32) val[0] & M32; + fprintf (of, "%08X", c); + return -3; + } +if (sw & SWMASK ('C')) { /* char format? */ + for (sc = 0; sc < 64; sc = sc + 8) { /* print string */ + c = (uint32) (val[0] >> sc) & 0x7F; + fprintf (of, (c < 0x20)? "<%02X>": "%c", c); + } + return -7; /* return # chars */ + } +if (sw & SWMASK ('M')) { /* inst format? */ + if (addr & 4) c = (uint32) (val[0] >> 32) & M32; + else c = (uint32) val[0] & M32; + r = fprint_sym_m (of, addr, c); /* decode inst */ + if (r <= 0) return r; + } + +fprint_val (of, val[0], rdx, 64, PV_RZRO); +return -7; +} + +/* Symbolic decode for -m + + Inputs: + of = output stream + addr = current PC + inst = instruction to decode + Outputs: + return = if >= 0, error code + if < 0, number of extra bytes retired (-3) +*/ + +t_stat fprint_sym_m (FILE *of, t_addr addr, uint32 inst) +{ +uint32 i, j, k, fl, ra, rb, rc, md, bd, jd, lit8, any; +t_stat r; + +if ((r = fprint_pal_hwre (of, inst)) < 0) return r; /* PAL instruction? */ +for (i = 0; opval[i] != M32; i = i + 2) { /* loop thru ops */ + fl = opval[i + 1]; /* flags */ + j = fl & CL_CLASS; /* get class */ + k = i >> 1; + if (((opval[i] & masks[j]) == (inst & masks[j])) && /* match? */ + ((j != CL_NO) || (fl & PAL_MASK (pal_type)))) { + ra = I_GETRA (inst); /* all fields */ + rb = I_GETRB (inst); + rc = I_GETRC (inst); + lit8 = I_GETLIT8 (inst); + md = I_GETMDSP (inst); + bd = I_GETBDSP (inst); + jd = inst & 0x3FFF; + any = 0; + fprintf (of, "%s", opcode[k]); /* opcode */ + if (fl & FL_RA) /* ra? */ + any = fprintf (of, " R%d", ra); + if (fl & FL_BDP) { /* branch? */ + addr = (addr + (SEXT_BDSP (bd) << 2) + 4) & M64; + any = fprintf (of, (any? ",": " ")); + fprint_val (of, addr, 16, 64, PV_LEFT); + } + else if (fl & FL_MDP) { /* mem ref? */ + if ((fl & FL_RBI) && (rb != 31)) + any = fprintf (of, (any? ",%X(R%d)": " %X(R%d)"), md, rb); + else any = fprintf (of, (any? ",%X": " %X"), md); + } + else if (fl & FL_RB) { /* rb? */ + if (fl & FL_RBI) + any = fprintf (of, (any? ",(R%d)": " (R%d)"), rb); + else if ((fl & FL_LIT) && (inst & I_ILIT)) + any = fprintf (of, (any? ",#%X": " #%X"), lit8); + else any = fprintf (of, (any? ",R%d": " R%d"), rb); + } + if ((fl & FL_JDP) && jd) /* jmp? */ + any = fprintf (of, (any? ",%X": " %X"), jd); + else if (fl & FL_RC) /* rc? */ + any = fprintf (of, (any? ",R%d": " R%d"), rc); + return -3; + } /* 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 = > 0 error code + <= 0 -number of extra words +*/ + +t_stat parse_sym (char *cptr, t_addr addr, UNIT *uptr, t_value *val, int32 sw) +{ +t_value num; +uint32 i, sc, rdx; +t_stat r; +DEVICE *dptr; + +if (uptr == NULL) uptr = &cpu_unit; /* anon = CPU */ +else if (uptr != &cpu_unit) return SCPE_ARG; /* CPU only */ +dptr = find_dev_from_unit (uptr); /* find dev */ +if (dptr == NULL) return SCPE_IERR; +if (sw & SWMASK ('D')) rdx = 10; /* get radix */ +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) return SCPE_ARG; /* must have 1 char */ + sc = (uint32) (addr & 0x7) * 8; /* shift count */ + val[0] = (val[0] & ~(((t_uint64) M8) << sc)) | + (((t_uint64) cptr[0]) << sc); + return 0; + } +if (sw & SWMASK ('B')) { /* byte? */ + num = get_uint (cptr, rdx, M8, &r); /* get byte */ + if (r != SCPE_OK) return SCPE_ARG; + sc = (uint32) (addr & 0x7) * 8; /* shift count */ + val[0] = (val[0] & ~(((t_uint64) M8) << sc)) | + (num << sc); + return 0; + } +if (sw & SWMASK ('W')) { /* word? */ + num = get_uint (cptr, rdx, M16, &r); /* get word */ + if (r != SCPE_OK) return SCPE_ARG; + sc = (uint32) (addr & 0x6) * 8; /* shift count */ + val[0] = (val[0] & ~(((t_uint64) M16) << sc)) | + (num << sc); + return -1; + } +if (sw & SWMASK ('L')) { /* longword? */ + num = get_uint (cptr, rdx, M32, &r); /* get longword */ + if (r != SCPE_OK) return SCPE_ARG; + sc = (uint32) (addr & 0x4) * 8; /* shift count */ + val[0] = (val[0] & ~(((t_uint64) M32) << sc)) | + (num << sc); + return -3; + } +if ((sw & SWMASK ('C')) || ((*cptr == '"') && cptr++)) { /* ASCII chars? */ + if (cptr[0] == 0) return SCPE_ARG; /* must have 1 char */ + for (i = 0; i < 8; i++) { + if (cptr[i] == 0) break; + sc = i * 8; + val[0] = (val[0] & ~(((t_uint64) M8) << sc)) | + (((t_uint64) cptr[i]) << sc); + } + return -7; + } + +if ((addr & 3) == 0) { /* aligned only */ + r = parse_sym_m (cptr, addr, &num); /* try to parse inst */ + if (r <= 0) { /* ok? */ + sc = (uint32) (addr & 0x4) * 8; /* shift count */ + val[0] = (val[0] & ~(((t_uint64) M32) << sc)) | + (num << sc); + return -3; + } + } + +val[0] = get_uint (cptr, rdx, M64, &r); /* get number */ +if (r != SCPE_OK) return r; +return -7; +} + +/* Symbolic input + + Inputs: + *cptr = pointer to input string + addr = current PC + *val = pointer to output values + Outputs: + status = > 0 error code + <= 0 -number of extra words +*/ + +t_stat parse_sym_m (char *cptr, t_addr addr, t_value *inst) +{ +t_uint64 bra, df, db; +uint32 i, k, lit8, fl; +int32 reg; +t_stat r; +char *tptr, gbuf[CBUFSIZE]; + +if ((r = parse_pal_hwre (cptr, inst)) < 0) return r; /* PAL hardware? */ +cptr = get_glyph (cptr, gbuf, 0); /* get opcode */ +for (i = 0; opcode[i] != NULL; i++) { /* loop thru opcodes */ + if (strcmp (opcode[i], gbuf) == 0) { /* string match? */ + k = i << 1; /* index to opval */ + fl = opval[k + 1]; /* get flags */ + if (((fl & CL_CLASS) != CL_NO) || /* not PAL or */ + (fl & PAL_MASK (pal_type))) break; /* PAL type match? */ + } + } +if (opcode[i] == NULL) return SCPE_ARG; +*inst = opval[k]; /* save base op */ + +if (fl & FL_RA) { /* need Ra? */ + cptr = get_glyph (cptr, gbuf, ','); /* get reg */ + if ((reg = parse_reg (gbuf)) < 0) return SCPE_ARG; + *inst = *inst | (reg << I_V_RA); + } +if (fl & FL_BDP) { /* need branch disp? */ + cptr = get_glyph (cptr, gbuf, 0); + bra = get_uint (gbuf, 16, M64, &r); + if ((r != SCPE_OK) || (bra & 3)) return SCPE_ARG; + df = ((bra - (addr + 4)) >> 2) & I_M_BDSP; + db = ((addr + 4 - bra) >> 2) & I_M_BDSP; + if (bra == ((addr + 4 + (SEXT_BDSP (df) << 2)) & M64)) + *inst = *inst | (uint32) df; + else if (bra == ((addr + 4 + (SEXT_BDSP (db) << 2)) & M64)) + *inst = *inst | (uint32) db; + else return SCPE_ARG; + } +else if (fl & FL_MDP) { /* need mem disp? */ + cptr = get_glyph (cptr, gbuf, 0); + df = strtotv (gbuf, &tptr, 16); + if ((gbuf == tptr) || (df > I_M_MDSP)) return SCPE_ARG; + *inst = *inst | (uint32) df; + if (*tptr == '(') { + tptr = get_glyph (tptr + 1, gbuf, ')'); + if ((reg = parse_reg (gbuf)) < 0) return SCPE_ARG; + *inst = *inst | (reg << I_V_RB); + } + else *inst = *inst | (31 << I_V_RB); + if (*tptr != 0) return SCPE_ARG; + } +else if (fl & FL_RBI) { /* indexed? */ + cptr = get_glyph (cptr, gbuf, ','); + if (gbuf[0] != '(') return SCPE_ARG; + tptr = get_glyph (gbuf + 1, gbuf, ')'); + if ((reg = parse_reg (gbuf)) < 0) return SCPE_ARG; + *inst = *inst | (reg << I_V_RB); + if (*tptr != 0) return SCPE_ARG; + } +else if (fl & FL_RB) { + cptr = get_glyph (cptr, gbuf, ','); /* get reg/lit */ + if ((gbuf[0] == '#') && (fl & FL_LIT)) { /* literal? */ + lit8 = (uint32) get_uint (gbuf + 1, 16, I_M_LIT8, &r); + if (r != SCPE_OK) return r; + *inst = *inst | I_ILIT | (lit8 << I_V_LIT8); + } + else { /* rb */ + if ((reg = parse_reg (gbuf)) < 0) return SCPE_ARG; + *inst = *inst | (reg << I_V_RB); + } + } +if (fl & FL_JDP) { /* jmp? */ + cptr = get_glyph (cptr, gbuf, 0); /* get disp */ + df = get_uint (gbuf, 16, 0x3FFF, &r); + if (r != SCPE_OK) return r; + *inst = *inst | df; + } +else if (fl & FL_RC) { /* rc? */ + cptr = get_glyph (cptr, gbuf, ','); /* get reg */ + if ((reg = parse_reg (gbuf)) < 0) return SCPE_ARG; + *inst = *inst | (reg << I_V_RC); + } + +if (*cptr != 0) return SCPE_ARG; /* any leftovers? */ +return -3; +} + +/* Parse a register */ + +int32 parse_reg (char *cptr) +{ +t_stat r; +int32 reg; + +if ((*cptr == 'R') || (*cptr == 'r') || + (*cptr == 'F') || (*cptr == 'f')) cptr++; +reg = (int32) get_uint (cptr, 10, 31, &r); +if (r != SCPE_OK) return -1; +return reg; +} + diff --git a/alpha/alpha_sys_defs.h b/alpha/alpha_sys_defs.h new file mode 100644 index 00000000..7af5a908 --- /dev/null +++ b/alpha/alpha_sys_defs.h @@ -0,0 +1,43 @@ +/* alpha_system_defs.h: Alpha system definitions file + + Copyright (c) 2003-2006, 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. + + Respectfully dedicated to the great people of the Alpha chip, systems, and + software development projects; and to the memory of Peter Conklin, of the + Alpha Program Office. + + This is a STUB! +*/ + +#ifndef _ALPHA_SYS_DEFS_H_ +#define _ALPHA_SYS_DEFS_H_ 0 + +#define PA_SIZE 36 /* PA size */ +#define PA_MASK 0x0000000FFFFFFFFF + +#define ROMBASE 0x000000FFFC000000 +#define ROMSIZE 0x0000000004000000 + +#endif + diff --git a/alpha/old_pal/alpha_pal_defs.h b/alpha/old_pal/alpha_pal_defs.h new file mode 100644 index 00000000..6471e36b --- /dev/null +++ b/alpha/old_pal/alpha_pal_defs.h @@ -0,0 +1,208 @@ +/* alpha_pal_defs.h: Alpha architecture PAL definitions file + + Copyright (c) 2003-2006, 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. + + Respectfully dedicated to the great people of the Alpha chip, systems, and + software development projects; and to the memory of Peter Conklin, of the + Alpha Program Office. +*/ + +#ifndef _ALPHA_PAL_DEFS_H_ +#define _ALPHA_PAL_DEFS_H_ 0 + +/* VA - NT software format */ + +#define NTVA_N_PDE (VA_N_OFF - 2) /* PDE width */ +#define NTVA_M_PDE ((1u << NTVA_N_PDE) - 1) /* PDE mask */ +#define NTVA_N_PTD (32 - VA_N_OFF - NTVA_N_PDE) /* PTD width */ +#define NTVA_M_PTD ((1u << NTVA_N_PTD) - 1) /* PTD mask */ +#define NTVA_M_VPN (M32 >> VA_N_OFF) /* 32b VPN mask */ +#define NTVPN_N_SEXT (VA_WIDTH - 32 + 1) /* VPN sext size */ +#define NTVPN_V_SEXT (VA_N_VPN - NTVPN_N_SEXT) /* VPN sext start */ +#define NTVPN_M_SEXT ((1u << NTVPN_N_SEXT) - 1) /* VPN sext mask */ +#define NTVPN_GETSEXT(x) (((x) >> NTVPN_V_SEXT) & NTVPN_M_SEXT) + +/* PTE - NT software format */ + +#define NT_VPTB 0xFFFFFFFFC0000000 /* virt page tbl base */ +#define NTP_V_PFN 9 /* PFN */ +#define NTP_M_PFN 0x7FFFFF +#define NTP_PFN (NTP_M_PFN << NTP_V_PFN) +#define NTP_V_GH 5 +#define NTP_M_GH 0x3 +#define NTP_V_GBL 4 /* global = ASM */ +#define NTP_V_DIRTY 2 /* dirty = !FOW */ +#define NTP_V_OWNER 1 /* owner */ +#define NTP_V_V 0 /* valid */ +#define NTP_GBL (1u << NTP_V_GBL) +#define NTP_DIRTY (1u << NTP_V_DIRTY) +#define NTP_OWNER (1u << NTP_V_OWNER) +#define NTP_V (1u << NTP_V_V) +#define NT_VPNPTD(x) (((x) >> (NTVA_N_PDE - 2)) & (NTVA_M_PTD << 2)) +#define NT_VPNPDE(x) (((x) << 2) & (NTVA_M_PDE << 2)) + +/* VMS PALcode */ + +#define PSV_V_SPA 56 /* VMS PS: stack align */ +#define PSV_M_SPA 0x3F +#define PSV_V_IPL 8 /* interrupt priority */ +#define PSV_M_IPL 0x1F +#define PSV_V_VMM 7 /* virt machine monitor */ +#define PSV_V_CM 3 /* current mode */ +#define PSV_M_CM 0x3 +#define PSV_V_IP 2 /* intr in progress */ +#define PSV_V_SW 0 /* software */ +#define PSV_M_SW 0x3 +#define PSV_VMM (1u << PSV_V_VMM) +#define PSV_IP (1u << PSV_V_IP) +#define PSV_MASK (PSV_VMM | PSV_IP | PSV_M_SW) +#define PSV_MBZ 0xC0FFFFFFFFFFE0E4 /* must be zero */ + +#define PCBV_FLAGS 56 /* PCB flags word */ + +#define SISR_MASK 0xFFFE /* SISR bits */ + +#define IPL_SMAX 0x0F /* highest swre level */ + +#define SCB_FDIS 0x010 /* SCB offsets */ +#define SCB_ACV 0x080 +#define SCB_TNV 0x090 +#define SCB_FOR 0x0A0 +#define SCB_FOW 0x0B0 +#define SCB_FOE 0x0C0 +#define SCB_ARITH 0x200 +#define SCB_KAST 0x240 +#define SCB_EAST 0x250 +#define SCB_SAST 0x260 +#define SCB_UAST 0x270 +#define SCB_ALIGN 0x280 +#define SCB_BPT 0x400 +#define SCB_BUG 0x410 +#define SCB_RSVI 0x420 +#define SCB_RSVO 0x430 +#define SCB_GENTRAP 0x440 +#define SCB_CHMK 0x480 +#define SCB_CHME 0x490 +#define SCB_CHMS 0x4A0 +#define SCB_CHMU 0x4B0 +#define SCB_SISR0 0x500 +#define SCB_CLOCK 0x600 +#define SCB_IPIR 0x610 +#define SCB_SCRD 0x620 +#define SCB_PCRD 0x630 +#define SCB_POWER 0x640 +#define SCB_PERFM 0x650 +#define SCB_SMCHK 0x660 +#define SCB_PMCHK 0x670 +#define SCB_PASVR 0x6F0 +#define SCB_IO 0x800 + +#define VMS_L_STKF (8 * 8) /* stack frame length */ +#define VMS_MME_E 0x0000000000000001 /* mem mgt error flags */ +#define VMS_MME_R 0x0000000000000000 +#define VMS_MME_W 0x8000000000000000 + +/* VAX compatible data length definitions (for ReadUna, WriteUna) */ + +#define L_BYTE 1 +#define L_WORD 2 +#define L_LONG 4 +#define L_QUAD 8 + +/* Unix PALcode */ + +#define PSU_V_CM 3 /* Unix PS: curr mode */ +#define PSU_M_CM 0x1 +#define PSU_CM (PSU_M_CM << PSU_V_CM) +#define PSU_V_IPL 0 /* IPL */ +#define PSU_M_IPL 0x7 +#define PSU_IPL (PSU_M_IPL << PSU_V_IPL) + +#define PCBU_FLAGS 40 /* PCB flags word */ + +#define UNIX_L_STKF (6 * 8) /* kernel stack frame */ +#define UNIX_IF_BPT 0 /* entIF a0 values */ +#define UNIX_IF_BUG 1 +#define UNIX_IF_GEN 2 +#define UNIX_IF_FDIS 3 +#define UNIX_IF_RSVI 4 +#define UNIX_INT_IPIR 0 /* entInt a0 values */ +#define UNIX_INT_CLK 1 +#define UNIX_INT_MCRD 2 +#define UNIX_INT_IO 3 +#define UNIX_INT_PERF 4 +#define UNIX_MMCSR_TNV 0 /* entMM a1 values */ +#define UNIX_MMCSR_ACV 1 +#define UNIX_MMCSR_FOR 2 +#define UNIX_MMCSR_FOW 3 +#define UNIX_MMCSR_FOE 4 +#define UNIX_MME_E M64 /* entMM a2 values */ +#define UNIX_MME_R 0 +#define UNIX_MME_W 1 + +enum vms_pal_opcodes { + OP_HALT, OP_DRAINA, OP_CFLUSH, OP_LDQP, + OP_STQP, OP_SWPCTX, MF_ASN, MT_ASTEN, + MT_ASTSR, OP_CSERVE, OP_SWPPAL, MF_FEN, + MT_FEN, MT_IPIR, MF_IPL, MT_IPL, + MF_MCES, MT_MCES, MF_PCBB, MF_PRBR, + MT_PRBR, MF_PTBR, MF_SCBB, MT_SCBB, + MT_SIRR, MF_SISR, MF_TBCHK, MT_TBIA, + MT_TBIAP, MT_TBIS, MF_ESP, MT_ESP, + MF_SSP, MT_SSP, MF_USP, MT_USP, + MT_TBISD, MT_TBISI, MF_ASTEN, MF_ASTSR, + MF_VTBR = 0x29, MT_VTBR,MT_PERFMON, MT_DATFX = 0x2E, + MF_VIRBND = 0x30, MT_VIRBND, MF_SYSPTBR, MT_SYSPTBR, + OP_WTINT = 0x3E, MF_WHAMI = 0x3F, + OP_BPT = 0x80, OP_BUGCHK, OP_CHME, OP_CHMK, + OP_CHMS, OP_CHMU, OP_IMB, OP_INSQHIL, + OP_INSQTIL, OP_INSQHIQ, OP_INSQTIQ, OP_INSQUEL, + OP_INSQUEQ, OP_INSQUELD,OP_INSQUEQD,OP_PROBER, + OP_PROBEW, OP_RD_PS, OP_REI, OP_REMQHIL, + OP_REMQTIL, OP_REMQHIQ, OP_REMQTIQ, OP_REMQUEL, + OP_REMQUEQ, OP_REMQUELD,OP_REMQUEQD,OP_SWASTEN, + OP_WR_PS_SW,OP_RSCC, OP_RD_UNQ, OP_WR_UNQ, + OP_AMOVRR, OP_AMOVRM, OP_INSQHILR,OP_INSQTILR, + OP_INSQHIQR,OP_INSQTIQR,OP_REMQHILR,OP_REMQTILR, + OP_REMQHIQR,OP_REMQTIQR,OP_GENTRAP, + OP_CLRFEN = 0xAE + }; + +enum unix_pal_opcodes { + OP_halt, OP_draina, OP_cflush, + OP_cserve = 0x9, OP_swppal, + OP_rdmces = 0x10, OP_wrmces, + OP_wrvirbnd = 0x13, OP_wrsysptbr = 0x14, + OP_wrfen = 0x2B, OP_wrvptptr = 0x2D, OP_wrasn, + OP_swpctx = 0x30, OP_wrval, OP_rdval, OP_tbi, + OP_wrent, OP_swpipl, OP_rdps, OP_wrkgp, + OP_wrusp, OP_wrperfmon, OP_rdusp, + OP_whami = 0x3C, OP_retsys, OP_wtint, OP_rti, + OP_bpt = 0x80, OP_bugchk, OP_syscall = 0x83, + OP_imb = 0x86, + OP_urti = 0x92, OP_rdunique = 0x9E, OP_wrunique, + OP_gentrap = 0xAA, OP_clrfen = 0xAE + }; + +#endif diff --git a/alpha/old_pal/alpha_pal_unix.c b/alpha/old_pal/alpha_pal_unix.c new file mode 100644 index 00000000..73fa8011 --- /dev/null +++ b/alpha/old_pal/alpha_pal_unix.c @@ -0,0 +1,702 @@ +/* alpha_pal_unix.c - Alpha Unix PAL code simulator + + Copyright (c) 2003-2005, 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 contains the PALcode implementation for Alpha Unix, except for + the console, which is always done in hardware mode. + + Alpha Unix/Linux requires the following privileged state: + + ps<3:0> processor status + cm<0> current mode - in base + ipl<2:0> interrupt level - in base + ksp<63:0> kernel stack pointer + kgp<63:0> kernel global pointer + usp<63:0> user stack pointer + pcbb<63:0> process control block base + ptptr<63:0> page table base + vptptr<63:0> virtual page table base + virbnd<63:0> virtual address boundary + sysptbr<63:0> system page table base register + sysval<63:0> processor base (sysvalue) + unique<63:0> thread-unique value + entArith<63:0> entry vector, arithmetic trap + entIF<63:0> entry vector, instruction + entInt<63:0> entry vector, interrupt + entSys<63:0> entry vector, system call + entMM<63:0> entry vector, memory management fault + entUna<63:0> entry vector, unaligned + + Unix maps kernel/user to the hardware's kernel/executive. It maps the + 8 IPL's to the hardware IPL's as follows: + + 0 0 + 1 1 + 2 2 + 3 IPL_HMIN + 4 IPL_HMIN+1 + 5 IPL_HMIN+2 + 6 IPL_HMIN+3 + 7 IPL_1F +*/ + +#include "alpha_defs.h" + +#define GET_PSU (((unix_cm & PSU_M_CM) << PSU_V_CM) | \ + ((unix_ipl & PSU_M_IPL) << PSU_V_IPL)) + +// kludge for debugging... +#define io_get_vec(x) 0 + +#define ksp unix_stkp[MODE_K] +#define usp unix_stkp[MODE_E] +#define entInt unix_entVec[0] +#define entArith unix_entVec[1] +#define entMM unix_entVec[2] +#define entIF unix_entVec[3] +#define entUna unix_entVec[4] +#define entSys unix_entVec[5] +#define v0 R[0] +#define a0 R[16] +#define a1 R[17] +#define a2 R[18] +#define a3 R[19] +#define at R[28] +#define gp R[29] + +t_uint64 unix_ptptr = 0; /* page table base */ +t_uint64 unix_vptptr = 0; /* virt page table base */ +t_uint64 unix_virbnd = M64; /* virtual boundary */ +t_uint64 unix_sysptbr = 0; /* system page table base */ +t_uint64 unix_hwpcb = 0; /* hardware PCB */ +t_uint64 unix_unique = 0; /* thread unique */ +t_uint64 unix_sysval = 0; /* processor unique */ +t_uint64 unix_mces = 0; /* machine check err summ */ +t_uint64 unix_stkp[2] = { 0 }; +t_uint64 unix_entVec[6] = { 0 }; +t_uint64 unix_kgp = 0; +uint32 unix_ipl = 0; +uint32 unix_cm = 0; + +static const uint32 map_ipl[8] = { + 0, 1, 2, IPL_HMIN, IPL_HMIN + 1, IPL_HMIN + 2, IPL_HMIN + 3, IPL_1F + }; + +extern t_uint64 R[32]; +extern t_uint64 PC, trap_mask; +extern t_uint64 p1; +extern uint32 vax_flag, lock_flag; +extern uint32 fpen; +extern uint32 ir, pcc_h, pcc_l, pcc_enb; +extern uint32 cm_racc, cm_wacc; +extern uint32 mmu_ispage, mmu_dspage; +extern jmp_buf save_env; +extern uint32 int_req[IPL_HLVL]; + +t_stat unix_syscall (void); +t_stat unix_retsys (void); +t_stat unix_rti (void); +void unix_urti (void); +void unix_swpctx (void); +t_stat unix_intexc (t_uint64 vec, t_uint64 arg); +t_stat unix_mm_intexc (t_uint64 par1, t_uint64 par2); +t_stat pal_proc_reset_unix (DEVICE *dptr); +uint32 pal_find_pte_unix (uint32 vpn, t_uint64 *l3pte); + +extern t_stat (*pal_eval_intr) (uint32 ipl); +extern t_stat (*pal_proc_excp) (uint32 type); +extern t_stat (*pal_proc_trap) (uint32 type); +extern t_stat (*pal_proc_intr) (uint32 type); +extern t_stat (*pal_proc_inst) (uint32 fnc); +extern uint32 (*pal_find_pte) (uint32 vpn, t_uint64 *pte); +extern uint32 Test (t_uint64 va, uint32 acc, t_uint64 *pa); + +/* UNIXPAL data structures + + unixpal_dev device descriptor + unixpal_unit unit + unixpal_reg register list +*/ + +UNIT unixpal_unit = { UDATA (NULL, 0, 0) }; + +REG unixpal_reg[] = { + { HRDATA (KSP, ksp, 64) }, + { HRDATA (USP, usp, 64) }, + { HRDATA (ENTARITH, entArith, 64) }, + { HRDATA (ENTIF, entIF, 64) }, + { HRDATA (ENTINT, entInt, 64) }, + { HRDATA (ENTMM, entMM, 64) }, + { HRDATA (ENTSYS, entSys, 64) }, + { HRDATA (ENTUNA, entUna, 64) }, + { HRDATA (KGP, unix_kgp, 64) }, + { HRDATA (PTPTR, unix_ptptr, 64) }, + { HRDATA (VPTPTR, unix_vptptr, 64) }, + { HRDATA (VIRBND, unix_virbnd, 64) }, + { HRDATA (SYSPTBR, unix_sysptbr, 64) }, + { HRDATA (UNIQUE, unix_unique, 64) }, + { HRDATA (SYSVAL, unix_sysval, 64) }, + { HRDATA (HWPCB, unix_hwpcb, 64) }, + { HRDATA (MCES, unix_mces, 64) }, + { HRDATA (IPL, unix_ipl, 3) }, + { HRDATA (CM, unix_cm, 0) }, + { NULL } + }; + +DEVICE unixpal_dev = { + "UNIXPAL", &unixpal_unit, unixpal_reg, NULL, + 1, 16, 1, 1, 16, 8, + NULL, NULL, &pal_proc_reset_unix, + NULL, NULL, NULL, + NULL, DEV_DIS + }; + +/* Unix interrupt evaluator - returns IPL of highest priority interrupt */ + +uint32 pal_eval_intr_unix (uint32 lvl) +{ +uint32 i; +uint32 mipl = map_ipl[lvl & PSU_M_IPL]; + +for (i = IPL_HMAX; i >= IPL_HMIN; i--) { /* chk hwre int */ + if (i <= mipl) return 0; /* at ipl? no int */ + if (int_req[i - IPL_HMIN]) return i; /* req != 0? int */ + } +return 0; +} + +/* Unix interrupt dispatch - reached from top of execute loop */ + +t_stat pal_proc_intr_unix (uint32 lvl) +{ +t_stat r; + +if (lvl > IPL_HMAX) return SCPE_IERR; /* above max? */ +else if (lvl >= IPL_HMIN) a1 = io_get_vec (lvl); /* hwre? get vector */ +else return SCPE_IERR; /* bug */ +r = unix_intexc (entInt, UNIX_INT_IO); /* do interrupt */ +if (a1 == SCB_CLOCK) a0 = UNIX_INT_CLK; +if (a1 == SCB_IPIR) a0 = UNIX_INT_IPIR; +unix_ipl = lvl; +return r; +} + +/* Unix trap dispatch - reached synchronously from bottom of execute loop */ + +t_stat pal_proc_trap_unix (uint32 tsum) +{ +t_stat r; + +r = unix_intexc (entArith, tsum); /* arithmetic trap */ +a1 = trap_mask; /* set parameter */ +return r; +} + +/* Unix exception dispatch - reached from the ABORT handler */ + +t_stat pal_proc_excp_unix (uint32 abval) +{ +t_stat r; + +switch (abval) { + + case EXC_RSVI: /* reserved instruction */ + return unix_intexc (entIF, UNIX_IF_RSVI); /* trap */ + + case EXC_RSVO: /* reserved operand */ + return unix_intexc (entIF, UNIX_IF_RSVI); /* trap */ + + case EXC_ALIGN: /* unaligned */ + PC = (PC - 4) & M64; /* back up PC */ + r = unix_intexc (entUna, PC); /* fault */ + a1 = I_GETOP (ir); /* get opcode */ + a2 = I_GETRA (ir); /* get ra */ + return r; + + case EXC_FPDIS: /* fp disabled */ + PC = (PC - 4) & M64; /* backup PC */ + return unix_intexc (entIF, UNIX_IF_FDIS); /* fault */ + + case EXC_FOX+EXC_E: /* FOE */ + tlb_is (p1, TLB_CI); + return unix_mm_intexc (UNIX_MMCSR_FOE, UNIX_MME_E); + + case EXC_FOX+EXC_R: /* FOR */ + PC = (PC - 4) & M64; /* back up PC */ + return unix_mm_intexc (UNIX_MMCSR_FOR, UNIX_MME_R); + + case EXC_FOX+EXC_W: /* FOW */ + PC = (PC - 4) & M64; /* back up PC */ + return unix_mm_intexc (UNIX_MMCSR_FOW, UNIX_MME_W); + + case EXC_BVA+EXC_E: + case EXC_ACV+EXC_E: /* instr ACV */ + return unix_mm_intexc (UNIX_MMCSR_ACV, UNIX_MME_E); + + case EXC_BVA+EXC_R: + case EXC_ACV+EXC_R: /* data read ACV */ + PC = (PC - 4) & M64; /* back up PC */ + return unix_mm_intexc (UNIX_MMCSR_ACV, UNIX_MME_R); + + case EXC_BVA+EXC_W: + case EXC_ACV+EXC_W: /* data write ACV */ + PC = (PC - 4) & M64; /* back up PC */ + return unix_mm_intexc (UNIX_MMCSR_ACV, UNIX_MME_W); + + case EXC_TNV+EXC_E: /* instr TNV */ + tlb_is (p1, TLB_CI); + return unix_mm_intexc (UNIX_MMCSR_TNV, UNIX_MME_E); + + case EXC_TNV+EXC_R: /* data read TNV */ + tlb_is (p1, TLB_CD); + PC = (PC - 4) & M64; /* back up PC */ + return unix_mm_intexc (UNIX_MMCSR_TNV, UNIX_MME_R); + + case EXC_TNV+EXC_W: /* data write TNV */ + tlb_is (p1, TLB_CD); + PC = (PC - 4) & M64; /* back up PC */ + return unix_mm_intexc (UNIX_MMCSR_TNV, UNIX_MME_W); + + case EXC_TBM + EXC_E: /* TLB miss */ + case EXC_TBM + EXC_R: + case EXC_TBM + EXC_W: + return SCPE_IERR; /* should not occur */ + + default: + return STOP_INVABO; + } +return SCPE_OK; +} + +/* PALcode instruction dispatcher - function code verified in CPU */ + +t_stat pal_proc_inst_unix (uint32 fnc) +{ +uint32 arg32 = (uint32) a0; + +if ((fnc < 0x40) && (unix_cm != MODE_K)) ABORT (EXC_RSVI); +switch (fnc) { + + case OP_halt: + return STOP_HALT; + + case OP_cflush: + case OP_draina: + break; + + case OP_cserve: + //tbd + break; + + case OP_swppal: + v0 = 0; + break; + + case OP_rdmces: + v0 = unix_mces; + break; + + case OP_wrmces: + unix_mces = (unix_mces | (arg32 & MCES_DIS)) & ~(arg32 & MCES_W1C); + break; + + case OP_wrvirbnd: + unix_virbnd = a0; + break; + + case OP_wrsysptbr: + unix_sysptbr = a0; + break; + + case OP_wrfen: + fpen = arg32 & 1; + arg32 = ReadPL (unix_hwpcb + PCBU_FLAGS); + arg32 = (arg32 & ~1) | fpen; + WritePL (unix_hwpcb + PCBU_FLAGS, arg32); + break; + + case OP_wrvptptr: + unix_vptptr = a0; + break; + + case OP_wrasn: + itlb_set_asn (arg32 & M16); + dtlb_set_asn (arg32 & M16); + WritePL (unix_hwpcb + 28, arg32 & M16); + break; + + case OP_swpctx: + unix_swpctx (); + break; + + case OP_wrval: + unix_sysval = a0; + break; + + case OP_rdval: + v0 = unix_sysval; + break; + + case OP_tbi: + switch (a0 + 2) { + case 0: /* -2 = tbia */ + tlb_ia (TLB_CI | TLB_CD | TLB_CA); + break; + case 1: /* -1 = tbiap */ + tlb_ia (TLB_CI | TLB_CD); + break; + case 3: /* +1 = tbis */ + tlb_is (a1, TLB_CI | TLB_CD); + break; + case 4: /* +2 = tbisd */ + tlb_is (a1, TLB_CD); + break; + case 5: /* +3 = tbisi */ + tlb_is (a1, TLB_CI); + break; + default: + break; + } + break; + + case OP_wrent: + if (a0 <= 5) unix_entVec[arg32] = a0; + break; + + case OP_swpipl: + v0 = unix_ipl; + unix_ipl = arg32 & PSU_M_IPL; + break; + + case OP_rdps: + v0 = GET_PSU; + break; + + case OP_wrkgp: + unix_kgp = a0; + break; + + case OP_wrusp: + usp = a0; + break; + + case OP_wrperfmon: + // tbd + break; + + case OP_rdusp: + v0 = usp; + break; + + case OP_whami: + v0 = 0; + break; + + case OP_retsys: + unix_retsys (); + break; + + case OP_wtint: + v0 = 0; + break; + + case OP_rti: + unix_rti (); + break; + +/* Non-privileged */ + + case OP_bpt: + return unix_intexc (entIF, UNIX_IF_BPT); + + case OP_bugchk: + return unix_intexc (entIF, UNIX_IF_BUG); + + case OP_syscall: + if (unix_cm == MODE_K) { + //tbd + } + return unix_syscall (); + + case OP_imb: + break; + + case OP_urti: + if (unix_cm == MODE_K) { + //tbd + } + unix_urti (); + break; + + case OP_rdunique: + v0 = unix_unique; + break; + + case OP_wrunique: + unix_unique = a0; + break; + + case OP_gentrap: + return unix_intexc (entIF, UNIX_IF_GEN); + + case OP_clrfen: + fpen = 0; + arg32 = ReadPL (unix_hwpcb + PCBU_FLAGS); + arg32 = arg32 & ~1; + WritePL (unix_hwpcb + PCBU_FLAGS, arg32); + break; + + default: + ABORT (EXC_RSVI); + } + +return SCPE_OK; +} + +/* Swap privileged context */ + +void unix_swpctx (void) +{ +t_uint64 val; +uint32 tmp1; + +WritePQ (unix_hwpcb + 0, SP); /* save stack ptrs */ +WritePQ (unix_hwpcb + 8, usp); +tmp1 = (pcc_h + pcc_l) & M32; /* elapsed time */ +WritePL (unix_hwpcb + 24, tmp1); /* save PCC */ +WritePQ (unix_hwpcb + 32, unix_unique); /* save unique */ +v0 = unix_hwpcb; /* return curr PCBB */ +unix_hwpcb = a0; /* new PCBB */ +SP = ksp = ReadPQ (unix_hwpcb + 0); /* read stack ptrs */ +usp = ReadPQ (unix_hwpcb + 8); +val = ReadPQ (unix_hwpcb + 16) << VA_N_OFF; /* read new PTBR */ +if (val != unix_ptptr) tlb_ia (TLB_CI | TLB_CD); /* ptbr change? zap TLB */ +unix_ptptr = val; +tmp1 = ReadPL (unix_hwpcb + 24); /* restore PCC */ +pcc_h = (tmp1 - pcc_l) & M32; +tmp1 = ReadPL (unix_hwpcb + 28) & M16; /* read ASN */ +itlb_set_asn (tmp1); +dtlb_set_asn (tmp1); +unix_unique = ReadPQ (unix_hwpcb + 32); /* read unique */ +fpen = ReadPL (unix_hwpcb + PCBU_FLAGS) & 1; /* read FEN */ +return; +} + +/* Unix interrupt or exception - always to kernel mode + + Inputs: + vec = entry vector + arg = argument for a0 + Outputs: + reason = possible processor halt +*/ + +t_stat unix_intexc (t_uint64 vec, t_uint64 arg) +{ +t_uint64 sav_ps = GET_PSU; /* old PS */ + +if ((unix_cm & PSU_M_CM) != MODE_K) { /* not kernel? */ + usp = SP; /* save SP */ + SP = ksp; /* load new SP */ + unix_cm = mmu_set_cm (MODE_K); /* PS = 0 */ + unix_ipl = 0; + } +SP = (SP - UNIX_L_STKF) & M64; /* decr stack */ +if (Test (SP, cm_wacc, NULL)) return STOP_KSNV; /* validate writes */ +if (Test (SP + UNIX_L_STKF - 8, cm_wacc, NULL) < 0) return STOP_KSNV; +WriteQ (SP, sav_ps); /* save PS, PC, gp */ +WriteQ (SP + 8, PC); +WriteQ (SP + 16, gp); +WriteQ (SP + 24, a0); /* save a0-a2 */ +WriteQ (SP + 32, a1); +WriteQ (SP + 40, a2); +PC = vec; /* new PC */ +gp = unix_kgp; /* kernel GP */ +a0 = arg; /* argument */ +return SCPE_OK; +} + +/* Memory management fault */ + +t_stat unix_mm_intexc (t_uint64 par1, t_uint64 par2) +{ +t_stat r; + +r = unix_intexc (entMM, p1); /* do exception */ +a1 = par1; /* set arguments */ +a2 = par2; +tlb_is (p1, TLB_CI | TLB_CD); /* zap TLB entry */ +return r; +} + +/* System call - always user to kernel, abbreviated stack frame, no arguments */ + +t_stat unix_syscall (void) +{ +t_uint64 sav_ps = GET_PSU; /* save PS */ + +usp = SP; /* save user SP */ +SP = ksp; /* load kernel SP */ +unix_cm = mmu_set_cm (MODE_K); /* PS = 0 */ +unix_ipl = 0; +SP = (SP - UNIX_L_STKF) & M64; /* decr stack */ +if (Test (SP, cm_wacc, NULL)) return STOP_KSNV; /* validate writes */ +if (Test (SP + UNIX_L_STKF - 8, cm_wacc, NULL)) return STOP_KSNV; +WriteQ (SP, sav_ps); /* save PS, PC, gp */ +WriteQ (SP + 8, PC); +WriteQ (SP + 16, gp); +PC = entSys; /* new PC */ +gp = unix_kgp; /* kernel GP */ +return SCPE_OK; +} + +/* Return from trap or interrupt - always from kernel */ + +t_stat unix_rti (void) +{ +t_uint64 tpc; +uint32 tps, newm; + +if (Test (SP, cm_racc, NULL)) return STOP_KSNV; /* validate reads */ +if (Test (SP + UNIX_L_STKF - 8, cm_racc, NULL)) return STOP_KSNV; +tps = (uint32) ReadQ (SP); /* read PS, PC */ +tpc = ReadQ (SP + 8); +gp = ReadQ (SP + 16); /* restore gp, a0-a2 */ +a0 = ReadQ (SP + 24); +a1 = ReadQ (SP + 32); +a2 = ReadQ (SP + 40); +SP = (SP + UNIX_L_STKF); /* incr stack */ +newm = (tps >> PSU_V_CM) & PSU_M_CM; +unix_cm = mmu_set_cm (newm); /* new current mode */ +if (newm) { /* to user? */ + ksp = SP; /* save kernel stack */ + SP = usp; /* load user stack */ + unix_ipl = 0; /* ipl = 0 */ + } +else unix_ipl = (tps >> PSU_V_IPL) & PSU_V_IPL; /* restore ipl */ +PC = tpc; /* restore PC */ +vax_flag = 0; /* clear VAX, lock flags */ +lock_flag = 0; +return SCPE_OK; +} + +/* Return from system call - always from kernel to user */ + +t_stat unix_retsys (void) +{ +t_uint64 tpc; + +if (Test (SP + 8, cm_racc, NULL)) return STOP_KSNV; /* validate reads */ +if (Test (SP + 16, cm_racc, NULL)) return STOP_KSNV; +tpc = ReadQ (SP + 8); /* read PC */ +gp = ReadQ (SP + 16); /* restore GP */ +ksp = (SP + UNIX_L_STKF); /* update kernel stack */ +SP = usp; /* restore user stack */ +unix_cm = mmu_set_cm (MODE_E); /* PS = 8 */ +unix_ipl = 0; +PC = tpc; /* restore PC */ +vax_flag = 0; /* clear VAX, lock flags */ +lock_flag = 0; +return SCPE_OK; +} + +/* Return from user mode trap - always from user to user */ + +void unix_urti (void) +{ +t_uint64 tsp, tpc; +uint32 tps; + +if (SP & 0x3F) ABORT (EXC_RSVO); /* not aligned? */ +tps = ReadL (SP + 16); /* read PS */ +if (!(tps & PSU_CM) || (tps & PSU_IPL)) ABORT (EXC_RSVO); +at = ReadQ (SP + 0); /* restore at */ +tsp = ReadQ (SP + 8); /* read SP, PC */ +tpc = ReadQ (SP + 24); +gp = ReadQ (SP + 32); /* restore gp, a0-a2 */ +a0 = ReadQ (SP + 40); +a1 = ReadQ (SP + 48); +a2 = ReadQ (SP + 56); +SP = tsp; /* restore SP */ +PC = tpc; /* restore PC */ +vax_flag = 0; /* clear VAX, lock flags */ +lock_flag = 0; +return; +} + +/* Unix 3-level PTE lookup + + Inputs: + vpn = virtual page number (30b, sext) + *pte = pointer to pte to be returned + Output: + status = 0 for successful fill + EXC_ACV for ACV on intermediate level + EXC_TNV for TNV on intermediate level +*/ + +uint32 pal_find_pte_unix (uint32 vpn, t_uint64 *l3pte) +{ +t_uint64 vptea, l1ptea, l2ptea, l3ptea, l1pte, l2pte; +uint32 vpte_vpn; +TLBENT *vpte_p; + +vptea = unix_vptptr | (((t_uint64) (vpn & VA_M_VPN)) << 3); /* try virtual lookup */ +vpte_vpn = VA_GETVPN (vptea); /* get vpte vpn */ +vpte_p = dtlb_lookup (vpte_vpn); /* get vpte tlb ptr */ +if (vpte_p && ((vpte_p->pte & (PTE_KRE|PTE_V)) == (PTE_KRE|PTE_V))) + l3ptea = vpte_p->pfn | VA_GETOFF (vptea); +else { + l1ptea = unix_ptptr + VPN_GETLVL1 (vpn); + l1pte = ReadPQ (l1ptea); + if ((l1pte & PTE_V) == 0) + return ((l1pte & PTE_KRE)? EXC_TNV: EXC_ACV); + l2ptea = (l1pte & PFN_MASK) >> (PTE_V_PFN - VA_N_OFF); + l2ptea = l2ptea + VPN_GETLVL2 (vpn); + l2pte = ReadPQ (l2ptea); + if ((l2pte & PTE_V) == 0) + return ((l2pte & PTE_KRE)? EXC_TNV: EXC_ACV); + l3ptea = (l2pte & PFN_MASK) >> (PTE_V_PFN - VA_N_OFF); + l3ptea = l3ptea + VPN_GETLVL3 (vpn); + } +*l3pte = ReadPQ (l3ptea); +return 0; +} + +/* Unix PALcode reset */ + +t_stat pal_proc_reset_unix (DEVICE *dptr) +{ +mmu_ispage = mmu_dspage = SPEN_43; +unix_ipl = PSU_M_IPL; +unix_cm = mmu_set_cm (MODE_K); +pcc_enb = 1; +pal_eval_intr = &pal_eval_intr_unix; +pal_proc_intr = &pal_proc_intr_unix; +pal_proc_trap = &pal_proc_trap_unix; +pal_proc_excp = &pal_proc_excp_unix; +pal_proc_inst = &pal_proc_inst_unix; +pal_find_pte = &pal_find_pte_unix; +return SCPE_OK; +} diff --git a/alpha/old_pal/alpha_pal_vms.c b/alpha/old_pal/alpha_pal_vms.c new file mode 100644 index 00000000..df0612da --- /dev/null +++ b/alpha/old_pal/alpha_pal_vms.c @@ -0,0 +1,1780 @@ +/* alpha_pal_vms.c - Alpha VMS PAL code simulator + + Copyright (c) 2003-2005, 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 contains the PALcode implementation for Alpha VMS, except for + the console, which is always done in hardware mode. + + Alpha VMS requires a complex privileged state, modelled after the VAX: + + PS<12:0> processor status + IPL<4:0> interrupt level - in base + VMM<0> virtual machine mode + CM<1:0> current mode - in base + IP<0> interrupt in progress + SW<1:0> software controlled + KSP<63:0> kernel stack pointer + ESP<63:0> executive stack pointer + SSP<63:0> supervisor stack pointer + USP<63:0> user stack pointer + SSC<63:0> system cycle counter + PCBB<63:0> process control block base + SCBB<63:0> system control block base + PTBR<63:0> page table base + VTBR<63:0> virtual page table base + VIRBND<63:0> virtual address boundary + SYSPTBR<63:0> system page table base register + PRBR<63:0> processor base register + THREAD<63:0> thread-unique value + SIRR<15:1> software interrupt requests + ASTEN<3:0> AST enables + ASTRQ<3:0> AST requests + FEN<0> floating enable + DATFX<0> data alignment trap enable + + Note that some of this state exists in the hardware implementations and + so is declared in the base CPU. +*/ + +#include "alpha_defs.h" + +/* Alignment table */ + +#define ALG_W 1 /* word inst */ +#define ALG_L 2 /* long inst */ +#define ALG_Q 3 /* quad inst */ +#define ALG_ST 0x10 /* store */ +#define ALG_INV -1 /* invalid inst */ +#define ALG_ERR 0 /* internal error */ +#define ALG_GETLNT(x) ((x) & 3) + +#define GET_PSV ((vms_ipl << PSV_V_IPL) | (vms_cm << PSV_V_CM) | \ + (vms_ps & PSV_MASK)) +#define AST_TST(l) (((l) < IPL_AST) && (vms_asten & vms_astsr & ast_map[vms_cm])) +#define MOST_PRIV(m1,m2) (((m1) < (m2))? (m1): (m2)) + +#define ksp vms_stkp[MODE_K] +#define esp vms_stkp[MODE_E] +#define ssp vms_stkp[MODE_S] +#define usp vms_stkp[MODE_U] + +// kludge for debugging... +#define io_get_vec(x) 0 + +t_uint64 vms_ptbr = 0; /* page table base */ +t_uint64 vms_vtbr = 0; /* virt page table base */ +t_uint64 vms_virbnd = M64; /* virtual boundary */ +t_uint64 vms_sysptbr = 0; /* system page table base */ +t_uint64 vms_hwpcb = 0; /* hardware PCB */ +t_uint64 vms_thread = 0; /* thread unique */ +t_uint64 vms_prbr = 0; /* processor unique */ +t_uint64 vms_stkp[4]; /* stack pointers */ +t_uint64 vms_scbb = 0; /* SCB base */ +t_uint64 vms_scc = 0; /* system cycle ctr */ +t_uint64 vms_mces = 0; /* machine check err summ */ +uint32 vms_ipl = 0; /* hardware IPL */ +uint32 vms_cm = 0; /* inst current mode */ +uint32 vms_sisr = 0; /* software int req */ +uint32 vms_asten = 0; /* AST enables */ +uint32 vms_astsr = 0; /* AST requests */ +uint32 vms_last_pcc = 0; /* last pcc_l */ +uint32 vms_datfx = 0; /* data alignment */ +uint32 vms_ps = 0; /* static PS */ + +const uint32 ast_map[4] = { 0x1, 0x3, 0x7, 0xF }; +const uint32 ast_pri[16] = { + 0, MODE_K, MODE_E, MODE_K, MODE_S, MODE_K, MODE_E, MODE_K, + MODE_U, MODE_K, MODE_E, MODE_K, MODE_S, MODE_K, MODE_E, MODE_K + }; +static const uint32 lnt_map[4] = { L_BYTE, L_WORD, L_LONG, L_QUAD }; +static const int8 alg_map[64] = { + ALG_ERR, ALG_ERR, ALG_ERR, ALG_ERR, + ALG_ERR, ALG_ERR, ALG_ERR, ALG_ERR, + ALG_ERR, ALG_ERR, ALG_ERR, ALG_ERR, + ALG_W, ALG_W|ALG_ST, ALG_ERR, ALG_ERR, + ALG_ERR, ALG_ERR, ALG_ERR, ALG_ERR, + ALG_ERR, ALG_ERR, ALG_ERR, ALG_ERR, + ALG_ERR, ALG_ERR, ALG_ERR, ALG_ERR, + ALG_ERR, ALG_ERR, ALG_ERR, ALG_ERR, + ALG_L, ALG_Q, ALG_L, ALG_Q, + ALG_L|ALG_ST, ALG_Q|ALG_ST, ALG_L|ALG_ST, ALG_Q|ALG_ST, + ALG_L, ALG_Q, ALG_INV, ALG_INV, + ALG_L|ALG_ST, ALG_Q|ALG_ST, ALG_INV, ALG_INV, + ALG_ERR, ALG_ERR, ALG_ERR, ALG_ERR, + ALG_ERR, ALG_ERR, ALG_ERR, ALG_ERR, + ALG_ERR, ALG_ERR, ALG_ERR, ALG_ERR, + ALG_ERR, ALG_ERR, ALG_ERR, ALG_ERR + }; + +extern t_uint64 R[32]; +extern t_uint64 PC, trap_mask; +extern t_uint64 p1; +extern uint32 vax_flag, lock_flag; +extern uint32 fpen; +extern uint32 ir, pcc_h, pcc_l, pcc_enb; +extern uint32 cm_racc, cm_wacc, cm_macc; +extern uint32 mmu_ispage, mmu_dspage; +extern jmp_buf save_env; +extern uint32 int_req[IPL_HLVL]; + +t_int64 vms_insqhil (void); +t_int64 vms_insqtil (void); +t_int64 vms_insqhiq (void); +t_int64 vms_insqtiq (void); +t_int64 vms_insquel (uint32 defer); +t_int64 vms_insqueq (uint32 defer); +t_int64 vms_remqhil (void); +t_int64 vms_remqtil (void); +t_int64 vms_remqhiq (void); +t_int64 vms_remqtiq (void); +t_int64 vms_remquel (uint32 defer); +t_int64 vms_remqueq (uint32 defer); +t_int64 vms_insqhilr (void); +t_int64 vms_insqtilr (void); +t_int64 vms_insqhiqr (void); +t_int64 vms_insqtiqr (void); +t_int64 vms_remqhilr (void); +t_int64 vms_remqtilr (void); +t_int64 vms_remqhiqr (void); +t_int64 vms_remqtiqr (void); +uint32 vms_probe (uint32 acc); +uint32 vms_amovrr (void); +uint32 vms_amovrm (void); +t_stat vms_rei (void); +void vms_swpctx (void); +t_stat vms_intexc (uint32 vec, uint32 newmode, uint32 newipl); +t_stat vms_mm_intexc (uint32 vec, t_uint64 par2); +t_stat pal_proc_reset_vms (DEVICE *dptr); +t_uint64 ReadUna (t_uint64 va, uint32 lnt, uint32 acc); +void WriteUna (t_uint64 va, t_uint64 val, uint32 lnt, uint32 acc); +uint32 tlb_check (t_uint64 va); +uint32 Test (t_uint64 va, uint32 acc, t_uint64 *pa); + +extern t_stat (*pal_eval_intr) (uint32 ipl); +extern t_stat (*pal_proc_excp) (uint32 type); +extern t_stat (*pal_proc_trap) (uint32 type); +extern t_stat (*pal_proc_intr) (uint32 type); +extern t_stat (*pal_proc_inst) (uint32 fnc); +extern uint32 (*pal_find_pte) (uint32 vpn, t_uint64 *pte); + +/* VMSPAL data structures + + vmspal_dev device descriptor + vmspal_unit unit + vmspal_reg register list +*/ + +UNIT vmspal_unit = { UDATA (NULL, 0, 0) }; + +REG vmspal_reg[] = { + { HRDATA (KSP, ksp, 64) }, + { HRDATA (ESP, esp, 64) }, + { HRDATA (SSP, ssp, 64) }, + { HRDATA (USP, usp, 64) }, + { HRDATA (PTBR, vms_ptbr, 64) }, + { HRDATA (VTBR, vms_vtbr, 64) }, + { HRDATA (VIRBND, vms_virbnd, 64) }, + { HRDATA (SYSPTBR, vms_sysptbr, 64) }, + { HRDATA (THREAD, vms_thread, 64) }, + { HRDATA (PRBR, vms_prbr, 64) }, + { HRDATA (HWPCB, vms_hwpcb, 64) }, + { HRDATA (SCBB, vms_scbb, 64) }, + { HRDATA (SCC, vms_scc, 64) }, + { HRDATA (LASTPCC, vms_last_pcc, 32), REG_HRO }, + { HRDATA (MCES, vms_mces, 64) }, + { HRDATA (PS, vms_ps, 13) }, + { HRDATA (IPL, vms_ipl, 5) }, + { HRDATA (CM, vms_cm, 2) }, + { HRDATA (SISR, vms_sisr, 16) }, + { HRDATA (ASTEN, vms_asten, 4) }, + { HRDATA (ASTSR, vms_astsr, 4) }, + { FLDATA (DATFX, vms_datfx, 0) }, + { NULL } + }; + +DEVICE vmspal_dev = { + "VMSPAL", &vmspal_unit, vmspal_reg, NULL, + 1, 16, 1, 1, 16, 8, + NULL, NULL, &pal_proc_reset_vms, + NULL, NULL, NULL, + NULL, 0 + }; + +/* VMS interrupt evaluator - returns IPL of highest priority interrupt */ + +uint32 pal_eval_intr_vms (uint32 lvl) +{ +uint32 i; +static const int32 sw_int_mask[32] = { + 0xFFFE, 0xFFFC, 0xFFF8, 0xFFF0, /* 0 - 3 */ + 0xFFE0, 0xFFC0, 0xFF80, 0xFF00, /* 4 - 7 */ + 0xFE00, 0xFC00, 0xF800, 0xF000, /* 8 - B */ + 0xE000, 0xC000, 0x8000, 0x0000, /* C - F */ + 0x0000, 0x0000, 0x0000, 0x0000, /* 10+ */ + 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000 + }; + +vms_scc = vms_scc + ((pcc_l - vms_last_pcc) & M32); /* update scc */ +vms_last_pcc = pcc_l; +for (i = IPL_HMAX; i >= IPL_HMIN; i--) { /* chk hwre int */ + if (i <= lvl) return 0; /* at ipl? no int */ + if (int_req[i - IPL_HMIN]) return i; /* req != 0? int */ + } +if (vms_sisr & sw_int_mask[lvl]) { /* swre interrupt? */ + for (i = IPL_SMAX; i > lvl; i--) { /* check swre int */ + if ((vms_sisr >> i) & 1) /* req != 0? int */ + return (AST_TST (i)? IPL_AST: i); /* check for AST */ + } + } +return (AST_TST (lvl)? IPL_AST: 0); /* no swre, check AST */ +} + +/* VMS interrupt dispatch - reached from top of execute loop */ + +t_stat pal_proc_intr_vms (uint32 lvl) +{ +uint32 vec; +t_stat r; + +if (lvl > IPL_HMAX) return SCPE_IERR; /* above max? */ +else if (lvl >= IPL_HMIN) vec = io_get_vec (lvl); /* hwre? get vector */ +else if (lvl > IPL_SMAX) return SCPE_IERR; /* above swre max? */ +else if (lvl > 0) { /* swre int? */ + if ((lvl == IPL_AST) && (vms_asten & vms_astsr & ast_map[vms_cm])) { + uint32 astm = ast_pri[vms_astsr & 0xF]; /* get AST priority */ + vms_astsr = vms_astsr & ~(1u << astm); /* clear hi pri */ + vec = SCB_KAST + (astm << 4); + } + else { /* swre int */ + vms_sisr = vms_sisr & ~(1u << lvl); + vec = SCB_SISR0 + (lvl << 4); + } + } +else return SCPE_IERR; /* bug */ +if (vec == 0) vec = SCB_PASVR; /* passive release? */ +r = vms_intexc (vec, MODE_K, lvl); /* do interrupt */ +vms_ps = vms_ps | PSV_IP; /* set int in prog */ +return r; +} + +/* VMS trap dispatch - reached synchronously from bottom of execute loop */ + +t_stat pal_proc_trap_vms (uint32 tsum) +{ +t_stat r; + +r = vms_intexc (SCB_ARITH, MODE_K, vms_ipl); /* arithmetic trap */ +R[4] = trap_mask; /* set parameters */ +R[5] = tsum; +return r; +} + +/* VMS exception dispatch - reached from the ABORT handler */ + +t_stat pal_proc_excp_vms (uint32 abval) +{ +uint32 op, ra, lntc; +int8 fl; +t_stat r; + +switch (abval) { + + case EXC_RSVI: /* reserved instr */ + return vms_intexc (SCB_RSVI, MODE_K, vms_ipl); /* trap */ + + case EXC_RSVO: /* reserved operand */ + return vms_intexc (SCB_RSVO, MODE_K, vms_ipl); /* trap */ + + case EXC_ALIGN: /* unaligned */ + op = I_GETOP (ir); /* get opcode */ + ra = I_GETRA (ir); /* get RA */ + fl = alg_map[op]; /* get alignment map */ + if (fl == ALG_ERR) return SCPE_IERR; /* impossible? */ + if (fl == ALG_INV) return (SCB_RSVI, MODE_K, vms_ipl); /* conditional? */ + lntc = ALG_GETLNT (fl); /* get length code */ + if (fl & ALG_ST) /* store? */ + WriteUna (p1, R[ra], lnt_map[lntc], cm_wacc); + else if (ra != 31) + R[ra] = ReadUna (p1, lnt_map[lntc], cm_racc); + if (vms_datfx) break; /* trap? */ + r = vms_intexc (SCB_ALIGN, MODE_K, vms_ipl); /* do trap */ + R[4] = p1; /* R4 = va */ + R[5] = (fl & ALG_ST)? 1: 0; /* R5 = load/store */ + return r; + + case EXC_FPDIS: /* fp disabled */ + PC = (PC - 4) & M64; /* back up PC */ + return vms_intexc (SCB_FDIS, MODE_K, vms_ipl); /* fault */ + + case EXC_FOX+EXC_E: /* FOE */ + tlb_is (p1, TLB_CI); + return vms_mm_intexc (SCB_FOE, VMS_MME_E); + + case EXC_FOX+EXC_R: /* FOR */ + PC = (PC - 4) & M64; /* back up PC */ + return vms_mm_intexc (SCB_FOR, VMS_MME_R); + + case EXC_FOX+EXC_W: /* FOW */ + PC = (PC - 4) & M64; /* back up PC */ + return vms_mm_intexc (SCB_FOW, VMS_MME_W); + + case EXC_BVA+EXC_E: + case EXC_ACV+EXC_E: /* instr ACV */ + return vms_mm_intexc (SCB_ACV, VMS_MME_E); + + case EXC_BVA+EXC_R: + case EXC_ACV+EXC_R: /* data read ACV */ + PC = (PC - 4) & M64; /* back up PC */ + return vms_mm_intexc (SCB_ACV, VMS_MME_R); + + case EXC_BVA+EXC_W: + case EXC_ACV+EXC_W: /* data write ACV */ + PC = (PC - 4) & M64; /* back up PC */ + return vms_mm_intexc (SCB_ACV, VMS_MME_W); + + case EXC_TNV+EXC_E: /* instr TNV */ + tlb_is (p1, TLB_CI); + return vms_mm_intexc (SCB_TNV, VMS_MME_E); + + case EXC_TNV+EXC_R: /* data read TNV */ + tlb_is (p1, TLB_CD); + PC = (PC - 4) & M64; /* back up PC */ + return vms_mm_intexc (SCB_TNV, VMS_MME_R); + + case EXC_TNV+EXC_W: /* data write TNV */ + tlb_is (p1, TLB_CD); + PC = (PC - 4) & M64; /* back up PC */ + return vms_mm_intexc (SCB_TNV, VMS_MME_W); + + case EXC_TBM + EXC_E: /* TLB miss */ + case EXC_TBM + EXC_R: + case EXC_TBM + EXC_W: + return SCPE_IERR; /* should not occur */ + + default: + return STOP_INVABO; + } + +return SCPE_OK; +} + +/* PALcode instruction dispatcher - function code verified in CPU */ + +t_stat pal_proc_inst_vms (uint32 fnc) +{ +t_uint64 val; +uint32 arg32 = (uint32) R[16]; + +if ((fnc < 0x40) && (vms_cm != MODE_K)) ABORT (EXC_RSVI); +switch (fnc) { + + case OP_HALT: + return STOP_HALT; + + case OP_CFLUSH: + case OP_DRAINA: + break; + + case OP_LDQP: + R[0] = ReadPQ (R[16]); + break; + + case OP_STQP: + WritePQ (R[16], R[17]); + break; + + case OP_SWPCTX: + vms_swpctx (); + break; + + case MF_ASN: + R[0] = itlb_read_asn (); + break; + + case MT_ASTEN: + R[0] = vms_asten & AST_MASK; + vms_asten = ((vms_asten & arg32) | (arg32 >> 4)) & AST_MASK; + break; + + case MT_ASTSR: + R[0] = vms_astsr & AST_MASK; + vms_astsr = ((vms_astsr & arg32) | (arg32 >> 4)) & AST_MASK; + break; + + case OP_CSERVE: + // tbd + break; + + case OP_SWPPAL: + R[0] = 0; + break; + + case MF_FEN: + R[0] = fpen & 1; + break; + + case MT_FEN: + fpen = arg32 & 1; + arg32 = ReadPL (vms_hwpcb + PCBV_FLAGS); + arg32 = (arg32 & ~1) | fpen; + WritePL (vms_hwpcb + PCBV_FLAGS, arg32); + break; + + case MT_IPIR: + //tbd + break; + + case MF_IPL: + R[0] = vms_ipl & PSV_M_IPL; + break; + + case MT_IPL: + R[0] = vms_ipl & PSV_M_IPL; + vms_ipl = arg32 & PSV_M_IPL; + break; + + case MF_MCES: + R[0] = vms_mces; + break; + + case MT_MCES: + vms_mces = (vms_mces | (arg32 & MCES_DIS)) & ~(arg32 & MCES_W1C); + break; + + case MF_PCBB: + R[0] = vms_hwpcb; + break; + + case MF_PRBR: + R[0] = vms_prbr; + break; + + case MT_PRBR: + vms_prbr = R[16]; + break; + + case MF_PTBR: + R[0] = (vms_ptbr >> VA_N_OFF); /* PFN only */ + break; + + case MF_SCBB: + R[0] = vms_scbb; + break; + + case MT_SCBB: + vms_scbb = R[16]; + break; + + case MF_SISR: + R[0] = vms_sisr & SISR_MASK; + break; + + case MT_SIRR: + vms_sisr = (vms_sisr | (1u << (arg32 & 0xF))) & SISR_MASK; + break; + + case MF_TBCHK: + if (tlb_check (R[16])) R[0] = Q_SIGN + 1; + else R[0] = Q_SIGN; + break; + + case MT_TBIA: + tlb_ia (TLB_CI | TLB_CD | TLB_CA); + break; + + case MT_TBIAP: + tlb_ia (TLB_CI | TLB_CD); + break; + + case MT_TBIS: + tlb_is (R[16], TLB_CI | TLB_CD | TLB_CA); + break; + + case MF_ESP: + R[0] = esp; + break; + + case MT_ESP: + esp = R[16]; + break; + + case MF_SSP: + R[0] = ssp; + break; + + case MT_SSP: + ssp = R[16]; + break; + + case MF_USP: + R[0] = usp; + break; + + case MT_USP: + usp = R[16]; + break; + + case MT_TBISI: + tlb_is (R[16], TLB_CI | TLB_CA); + break; + + case MT_TBISD: + tlb_is (R[16], TLB_CD | TLB_CA); + break; + + case MF_ASTEN: + R[0] = vms_asten & AST_MASK; + break; + + case MF_ASTSR: + R[0] = vms_astsr & AST_MASK; + break; + + case MF_VTBR: + R[0] = vms_vtbr; + break; + + case MT_VTBR: + vms_vtbr = R[16]; + break; + + case MT_PERFMON: + // tbd + break; + + case MT_DATFX: + vms_datfx = arg32 & 1; + val = ReadPQ (vms_hwpcb + PCBV_FLAGS); + val = (val & ~0x8000000000000000) | (((t_uint64) vms_datfx) << 63); + WritePQ (vms_hwpcb + PCBV_FLAGS, val); + break; + + case MF_VIRBND: + R[0] = vms_virbnd; + break; + + case MT_VIRBND: + vms_virbnd = R[16]; + break; + + case MF_SYSPTBR: + R[0] = vms_sysptbr; + break; + + case MT_SYSPTBR: + vms_sysptbr = R[16]; + break; + + case OP_WTINT: + R[0] = 0; + break; + + case MF_WHAMI: + R[0] = 0; + break; + +/* Non-privileged */ + + case OP_BPT: + return vms_intexc (SCB_BPT, MODE_K, vms_ipl); + + case OP_BUGCHK: + return vms_intexc (SCB_BUG, MODE_K, vms_ipl); + + case OP_CHME: + return vms_intexc (SCB_CHME, MOST_PRIV (MODE_E, vms_cm), vms_ipl); + + case OP_CHMK: + return vms_intexc (SCB_CHMK, MODE_K, vms_ipl); + + case OP_CHMS: + return vms_intexc (SCB_CHMS, MOST_PRIV (MODE_S, vms_cm), vms_ipl); + + case OP_CHMU: + return vms_intexc (SCB_CHMU, vms_cm, vms_ipl); + break; + + case OP_IMB: + break; + + case OP_INSQHIL: + R[0] = vms_insqhil (); + break; + + case OP_INSQTIL: + R[0] = vms_insqtil (); + break; + + case OP_INSQHIQ: + R[0] = vms_insqhiq (); + break; + + case OP_INSQTIQ: + R[0] = vms_insqtiq (); + break; + + case OP_INSQUEL: + R[0] = vms_insquel (0); + break; + + case OP_INSQUEQ: + R[0] = vms_insqueq (0); + break; + + case OP_INSQUELD: + R[0] = vms_insquel (1); + break; + + case OP_INSQUEQD: + R[0] = vms_insqueq (1); + break; + + case OP_PROBER: + R[0] = vms_probe (PTE_KRE); + break; + + case OP_PROBEW: + R[0] = vms_probe (PTE_KRE|PTE_KWE); + break; + + case OP_RD_PS: + R[0] = GET_PSV; + break; + + case OP_REI: + return vms_rei (); + + case OP_REMQHIL: + R[0] = vms_insqhil (); + break; + + case OP_REMQTIL: + R[0] = vms_remqtil (); + break; + + case OP_REMQHIQ: + R[0] = vms_remqhiq (); + break; + + case OP_REMQTIQ: + R[0] = vms_remqtiq (); + break; + + case OP_REMQUEL: + R[0] = vms_remquel (0); + break; + + case OP_REMQUEQ: + R[0] = vms_remqueq (0); + break; + + case OP_REMQUELD: + R[0] = vms_remquel (1); + break; + + case OP_REMQUEQD: + R[0] = vms_remqueq (1); + break; + + case OP_SWASTEN: + R[0] = (vms_asten >> vms_cm) & 1; + vms_asten = (vms_asten & ~(1u << vms_cm)) | ((arg32 & 1) << vms_cm); + break; + + case OP_WR_PS_SW: + vms_ps = (vms_ps & ~PSV_M_SW) | (arg32 & PSV_M_SW); + break; + + case OP_RSCC: + vms_scc = vms_scc + ((pcc_l - vms_last_pcc) & M32); /* update scc */ + vms_last_pcc = pcc_l; + R[0] = vms_scc; + break; + + case OP_RD_UNQ: + R[0] = vms_thread; + break; + + case OP_WR_UNQ: + vms_thread = R[16]; + break; + + case OP_AMOVRR: + R[18] = vms_amovrr (); + break; + + case OP_AMOVRM: + R[18] = vms_amovrm (); + break; + + case OP_INSQHILR: + R[0] = vms_insqhilr (); + break; + + case OP_INSQTILR: + R[0] = vms_insqtilr (); + break; + + case OP_INSQHIQR: + R[0] = vms_insqhiqr (); + break; + + case OP_INSQTIQR: + R[0] = vms_insqtiqr (); + break; + + case OP_REMQHILR: + R[0] = vms_insqhilr (); + break; + + case OP_REMQTILR: + R[0] = vms_remqtilr (); + break; + + case OP_REMQHIQR: + R[0] = vms_remqhiqr (); + break; + + case OP_REMQTIQR: + R[0] = vms_remqtiqr (); + break; + + case OP_GENTRAP: + return vms_intexc (SCB_GENTRAP, MODE_K, vms_ipl); + + case OP_CLRFEN: + fpen = 0; + arg32 = ReadPL (vms_hwpcb + PCBV_FLAGS); + arg32 = arg32 & ~1; + WritePL (vms_hwpcb + PCBV_FLAGS, arg32); + break; + + default: + ABORT (EXC_RSVI); + } + +return SCPE_OK; +} + +/* Interlocked insert instructions + + R[16] = entry + R[17] = header + + Pictorially: + + BEFORE AFTER INSQHI AFTER INSQTI + + H: A-H H: D-H W H: A-H W for interlock + H+4/8: C-H H+4/8: C-H H+4/8: D-H W + + A: B-A A: B-A A: B-A + A+4/8: H-A A+4/8: D-A W A+4/8: H-A + + B: C-B B: C-B B: C-B + B+4/8: A-B B+4/8: A-B B+4/8: A-B + + C: H-C C: H-C C: D-C W + C+4/8: B-C C+4/8: B-C C+4/8: B-C + + D: --- D: A-D W D: H-D W + D+4/8: --- D+4/8: H-D W D+4/8: C-D W + + Note that the queue header, the entry to be inserted, and all + the intermediate entries that are "touched" in any way must be + QUAD(OCTA)WORD aligned. In addition, the header and the entry + must not be equal. + + Note that the offset arithmetic (+4, +8) cannot overflow 64b, + because the entries are quad or octa aligned. +*/ + +t_int64 vms_insqhil (void) +{ +t_uint64 h = R[16]; +t_uint64 d = R[17]; +t_uint64 ar, a; + +if ((h == d) || ((h | d) & 07) || /* h, d quad align? */ + ((SEXT_L_Q (h) & M64) != h) || + ((SEXT_L_Q (d) & M64) != d)) ABORT (EXC_RSVO); +ReadAccQ (d, cm_wacc); /* wchk (d) */ +ar = ReadQ (h); /* a <- (h) */ +if (ar & 06) ABORT (EXC_RSVO); /* a quad align? */ +if (ar & 01) return -1; /* busy, ret -1 */ +WriteQ (h, ar | 1); /* get interlock */ +a = (SEXT_L_Q (ar + h)) & M64; /* abs addr of a */ +if (Test (a, cm_wacc, NULL)) WriteQ (h, ar); /* wtst a, rls if err */ +WriteL (a + 4, (uint32) (d - a)); /* (a+4) <- d-a, flt ok */ +WriteL (d, (uint32) (a - d)); /* (d) <- a-d */ +WriteL (d + 4, (uint32) (h - d)); /* (d+4) <- h-d */ +WriteL (h, (uint32) (d - h)); /* (h) <- d-h, rls int */ +return ((ar & M32) == 0)? 0: +1; /* ret 0 if q was empty */ +} + +t_int64 vms_insqhilr (void) +{ +t_uint64 h = R[16]; +t_uint64 d = R[17]; +t_uint64 ar, a; + +ar = ReadQ (h); /* a <- (h) */ +if (ar & 01) return -1; /* busy, ret -1 */ +WriteQ (h, ar | 1); /* get interlock */ +a = (SEXT_L_Q (ar + h)) & M64; /* abs addr of a */ +WriteL (a + 4, (uint32) (d - a)); /* (a+4) <- d-a, flt ok */ +WriteL (d, (uint32) (a - d)); /* (d) <- a-d */ +WriteL (d + 4, (uint32) (h - d)); /* (d+4) <- h-d */ +WriteL (h, (uint32) (d - h)); /* (h) <- d-h, rls int */ +return ((ar & M32) == 0)? 0: +1; /* ret 0 if q was empty */ +} + +t_int64 vms_insqhiq (void) +{ +t_uint64 h = R[16]; +t_uint64 d = R[17]; +t_uint64 ar, a; + +if ((h == d) || ((h | d) & 0xF)) ABORT (EXC_RSVO); /* h, d octa align? */ +ReadAccQ (d, cm_wacc); /* wchk (d) */ +ar = ReadQ (h); /* a <- (h) */ +if (ar & 0xE) ABORT (EXC_RSVO); /* a octa align? */ +if (ar & 01) return -1; /* busy, ret -1 */ +WriteQ (h, ar | 1); /* get interlock */ +a = (ar + h) & M64; /* abs addr of a */ +if (Test (a, cm_wacc, NULL)) WriteQ (h, ar); /* wtst a, rls if err */ +WriteQ (a + 8, (d - a) & M64); /* (a+8) <- d-a, flt ok */ +WriteQ (d, (a - d) & M64); /* (d) <- a-d */ +WriteQ (d + 8, (h - d) & M64); /* (d+8) <- h-d */ +WriteQ (h, (d - h) & M64); /* (h) <- d-h, rls int */ +return (ar == 0)? 0: +1; /* ret 0 if q was empty */ +} + +t_int64 vms_insqhiqr (void) +{ +t_uint64 h = R[16]; +t_uint64 d = R[17]; +t_uint64 ar, a; + +ar = ReadQ (h); /* a <- (h) */ +if (ar & 01) return -1; /* busy, ret -1 */ +WriteQ (h, ar | 1); /* get interlock */ +a = (ar + h) & M64; /* abs addr of a */ +WriteQ (a + 8, (d - a) & M64); /* (a+8) <- d-a, flt ok */ +WriteQ (d, (a - d) & M64); /* (d) <- a-d */ +WriteQ (d + 8, (h - d) & M64); /* (d+8) <- h-d */ +WriteQ (h, (d - h) & M64); /* (h) <- d-h, rls int */ +return (ar == 0)? 0: +1; /* ret 0 if q was empty */ +} + +t_int64 vms_insqtil (void) +{ +t_uint64 h = R[16]; +t_uint64 d = R[17]; +t_uint64 ar, c; + +if ((h == d) || ((h | d) & 07) || /* h, d quad align? */ + ((SEXT_L_Q (h) & M64) != h) || + ((SEXT_L_Q (d) & M64) != d)) ABORT (EXC_RSVO); +ReadAccQ (d, cm_wacc); /* wchk (d) */ +ar = ReadQ (h); /* a <- (h) */ +if ((ar & M32) == 0) return vms_insqhil (); /* if empty, ins hd */ +if (ar & 06) ABORT (EXC_RSVO); /* a quad align? */ +if (ar & 01) return -1; /* busy, ret -1 */ +WriteQ (h, ar | 1); /* acquire interlock */ +c = ar >> 32; /* c <- (h+4) */ +c = (SEXT_L_Q (c + h)) & M64; /* abs addr of c */ +if (c & 07) { /* c quad aligned? */ + WriteQ (h, ar); /* release interlock */ + ABORT (EXC_RSVO); /* fault */ + } +if (Test (c, cm_wacc, NULL)) WriteQ (h, ar); /* wtst c, rls if err */ +WriteL (c, (uint32) (d - c)); /* (c) <- d-c, flt ok */ +WriteL (d, (uint32) (h - d)); /* (d) <- h-d */ +WriteL (d + 4, (uint32) (c - d)); /* (d+4) <- c-d */ +WriteL (h + 4, (uint32) (d - h)); /* (h+4) <- d-h */ +WriteL (h, (uint32) ar); /* release interlock */ +return 0; /* q was not empty */ +} + +t_int64 vms_insqtilr (void) +{ +t_uint64 h = R[16]; +t_uint64 d = R[17]; +t_uint64 ar, c; + +ar = ReadQ (h); /* a <- (h) */ +if ((ar & M32) == 0) return vms_insqhilr (); /* if empty, ins hd */ +if (ar & 01) return -1; /* busy, ret -1 */ +WriteQ (h, ar | 1); /* acquire interlock */ +c = ar >> 32; /* c <- (h+4) */ +c = (SEXT_L_Q (c + h)) & M64; /* abs addr of c */ +WriteL (c, (uint32) (d - c)); /* (c) <- d-c */ +WriteL (d, (uint32) (h - d)); /* (d) <- h-d */ +WriteL (d + 4, (uint32) (c - d)); /* (d+4) <- c-d */ +WriteL (h + 4, (uint32) (d - h)); /* (h+4) <- d-h */ +WriteL (h, (uint32) ar); /* release interlock */ +return 0; /* q was not empty */ +} + +t_int64 vms_insqtiq (void) +{ +t_uint64 h = R[16]; +t_uint64 d = R[17]; +t_uint64 ar, c; + +if ((h == d) || ((h | d) & 0xF)) ABORT (EXC_RSVO); /* h, d octa align? */ +ReadAccQ (d, cm_wacc); /* wchk ent */ +ar = ReadQ (h); /* a <- (h) */ +if (ar == 0) return vms_insqhiq (); /* if empty, ins hd */ +if (ar & 0xE) ABORT (EXC_RSVO); /* a octa align? */ +if (ar & 01) return -1; /* busy, ret -1 */ +WriteQ (h, ar | 1); /* acquire interlock */ +c = ReadQ (h + 8); /* c <- (h+8) */ +c = (c + h) & M64; /* abs addr of C */ +if (c & 0xF) { /* c octa aligned? */ + WriteQ (h, ar); /* release interlock */ + ABORT (EXC_RSVO); /* fault */ + } +if (Test (c, cm_wacc, NULL)) WriteQ (h, ar); /* wtst c, rls if err */ +WriteQ (c, (d - c) & M64); /* (c) <- d-c, flt ok */ +WriteQ (d, (h - d) & M64); /* (d) <- h-d */ +WriteQ (d + 8, (c - d) & M64); /* (d+8) <- c-d */ +WriteQ (h + 8, (d - h) & M64); /* (h+8) <- d-h */ +WriteQ (h, ar); /* release interlock */ +return 0; /* q was not empty */ +} + +t_int64 vms_insqtiqr (void) +{ +t_uint64 h = R[16]; +t_uint64 d = R[17]; +t_uint64 ar, c; + +ar = ReadQ (h); /* a <- (h) */ +if (ar == 0) return vms_insqhiqr (); /* if empty, ins hd */ +if (ar & 01) return -1; /* busy, ret -1 */ +WriteQ (h, ar | 1); /* acquire interlock */ +c = ReadQ (h + 8); /* c <- (h+8) */ +c = (c + h) & M64; /* abs addr of C */ +WriteQ (c, (d - c) & M64); /* (c) <- d-c */ +WriteQ (d, (h - d) & M64); /* (d) <- h-d */ +WriteQ (d + 8, (c - d) & M64); /* (d+8) <- c-d */ +WriteQ (h + 8, (d - h) & M64); /* (h+8) <- d-h */ +WriteQ (h, ar); /* release interlock */ +return 0; /* q was not empty */ +} + +/* Interlocked remove instructions + + R[16] = header (hdr.aq) + R[1] ] = receives destination address + + Pictorially: + + BEFORE AFTER REMQHI AFTER REMQTI + + H: A-H H: B-H W H: A-H W for interlock + H+4/8: C-H H+4/8: C-H H+4/8: B-H W + + A: B-A A: B-A R A: B-A + A+4/8: H-A A+4/8: H-A A+4/8: H-A + + B: C-B B: C-B B: H-B W + B+4/8: A-B B+4/8: H-B W B+4/8: A-B + + C: H-C C: H-C C: H-C + C+4/8: B-C C+4/8: B-C C+4/8: B-C R + + Note that the queue header and all the entries that are + "touched" in any way must be QUAD(OCTA)WORD aligned. +*/ + +t_int64 vms_remqhil (void) +{ +t_uint64 h = R[16]; +t_uint64 ar, a, b; + +if ((h & 07) || ((SEXT_L_Q (h) & M64) != h)) /* h quad aligned? */ + ABORT (EXC_RSVO); +ar = ReadQ (h); /* ar <- (h) */ +if (ar & 06) ABORT (EXC_RSVO); /* a quad aligned? */ +if (ar & 01) return -1; /* busy, ret -1 */ +if ((ar & M32) == 0) return 0; /* queue empty? */ +WriteQ (h, ar | 1); /* acquire interlock */ +a = (SEXT_L_Q (ar + h)) & M64; /* abs addr of a */ +if (Test (a, cm_racc, NULL)) WriteQ (h, ar); /* rtst a, rls if err */ +b = ReadL (a); /* b <- (a), flt ok */ +b = (SEXT_L_Q (b + a)) & M64; /* abs addr of b */ +if (b & 07) { /* b quad aligned? */ + WriteQ (h, ar); /* release interlock */ + ABORT (EXC_RSVO); /* fault */ + } +if (Test (b, cm_wacc, NULL)) WriteQ (h, ar); /* wtst b, rls if err */ +WriteL (b + 4, (uint32) (h - b)); /* (b+4) <- h-b, flt ok */ +WriteL (h, (uint32) (b - h)); /* (h) <- b-h, rls int */ +R[1] = a; /* address of entry */ +return ((b & M32) == (h & M32))? +2: +1; /* if b = h, q empty */ +} + +t_int64 vms_remqhilr (void) +{ +t_uint64 h = R[16]; +t_uint64 ar, a, b; + +ar = ReadQ (h); /* ar <- (h) */ +if (ar & 01) return -1; /* busy, ret -1 */ +if ((ar & M32) == 0) return 0; /* queue empty? */ +WriteQ (h, ar | 1); /* acquire interlock */ +a = (SEXT_L_Q (ar + h)) & M64; /* abs addr of a */ +b = ReadL (a); /* b <- (a), flt ok */ +b = (SEXT_L_Q (b + a)) & M64; /* abs addr of b */ +WriteL (b + 4, (uint32) (h - b)); /* (b+4) <- h-b, flt ok */ +WriteL (h, (uint32) (b - h)); /* (h) <- b-h, rls int */ +R[1] = a; /* address of entry */ +return ((b & M32) == (h & M32))? +2: +1; /* if b = h, q empty */ +} + +t_int64 vms_remqhiq (void) +{ +t_uint64 h = R[16]; +t_uint64 ar, a, b; + +if (h & 0xF) ABORT (EXC_RSVO); /* h octa aligned? */ +ar = ReadQ (h); /* ar <- (h) */ +if (ar & 0xE) ABORT (EXC_RSVO); /* a octa aligned? */ +if (ar & 01) return -1; /* busy, ret -1 */ +if (ar == 0) return 0; /* queue empty? */ +WriteQ (h, ar | 1); /* acquire interlock */ +a = (ar + h) & M64; /* abs addr of a */ +if (Test (a, cm_racc, NULL)) WriteQ (h, ar); /* rtst a, rls if err */ +b = ReadQ (a); /* b <- (a), flt ok */ +b = (b + a) & M64; /* abs addr of b */ +if (b & 0xF) { /* b octa aligned? */ + WriteQ (h, ar); /* release interlock */ + ABORT (EXC_RSVO); /* fault */ + } +if (Test (b, cm_wacc, NULL)) WriteQ (h, ar); /* wtst b, rls if err */ +WriteQ (b + 8, (h - b) & M64); /* (b+8) <- h-b, flt ok */ +WriteQ (h, (b - h) & M64); /* (h) <- b-h, rls int */ +R[1] = a; /* address of entry */ +return (b == h)? +2: +1; /* if b = h, q empty */ +} + +t_int64 vms_remqhiqr (void) +{ +t_uint64 h = R[16]; +t_uint64 ar, a, b; + +ar = ReadQ (h); /* ar <- (h) */ +if (ar & 01) return -1; /* busy, ret -1 */ +if (ar == 0) return 0; /* queue empty? */ +WriteQ (h, ar | 1); /* acquire interlock */ +a = (ar + h) & M64; /* abs addr of a */ +b = ReadQ (a); /* b <- (a) */ +b = (b + a) & M64; /* abs addr of b */ +WriteQ (b + 8, (h - b) & M64); /* (b+8) <- h-b, flt ok */ +WriteQ (h, (b - h) & M64); /* (h) <- b-h, rls int */ +R[1] = a; /* address of entry */ +return (b == h)? +2: +1; /* if b = h, q empty */ +} + +t_int64 vms_remqtil (void) +{ +t_uint64 h = R[16]; +t_uint64 ar, b, c; + +if ((h & 07) || ((SEXT_L_Q (h) & M64) != h)) /* h quad aligned? */ + ABORT (EXC_RSVO); +ar = ReadQ (h); /* a <- (h) */ +if (ar & 06) ABORT (EXC_RSVO); /* a quad aligned? */ +if (ar & 01) return -1; /* busy, return - 1*/ +if ((ar & M32) == 0) return 0; /* empty, return 0 */ +WriteQ (h, ar | 1); /* acquire interlock */ +c = ar >> 32; /* c <- (h+4) */ +if (c & 07) { /* c quad aligned? */ + WriteQ (h, ar); /* release interlock */ + ABORT (EXC_RSVO); /* fault */ + } +if ((ar & M32) == (c & M32)) { /* single entry? */ + WriteQ (h, ar); /* release interlock */ + return vms_remqhil (); /* treat as remqhil */ + } +c = (SEXT_L_Q (c + h)) & M64; /* abs addr of c */ +if (Test (c + 4, cm_racc, NULL)) WriteQ (h, ar); /* rtst c+4, rls if err */ +b = ReadL (c + 4); /* b <- (c+4), flt ok */ +b = (SEXT_L_Q (b + c)) & M64; /* abs addr of b */ +if (b & 07) { /* b quad aligned? */ + WriteQ (h, ar); /* release interlock */ + ABORT (EXC_RSVO); /* fault */ + } +if (Test (b, cm_wacc, NULL)) WriteQ (h, ar); /* wtst b, rls if err */ +WriteL (b, (uint32) (h - b)); /* (b) <- h-b, flt ok */ +WriteL (h + 4, (uint32) (b - h)); /* (h+4) <- b-h */ +WriteL (h, (uint32) ar); /* release interlock */ +R[1] = c; /* store result */ +return +1; /* q can't be empty */ +} + +t_int64 vms_remqtilr (void) +{ +t_uint64 h = R[16]; +t_uint64 ar, b, c; + +ar = ReadQ (h); /* a <- (h) */ +if (ar & 01) return -1; /* busy, return - 1*/ +if ((ar & M32) == 0) return 0; /* emtpy, return 0 */ +WriteQ (h, ar | 1); /* acquire interlock */ +c = ar >> 32; /* c <- (h+4) */ +if ((ar & M32) == (c & M32)) { /* single entry? */ + WriteQ (h, ar); /* release interlock */ + return vms_remqhilr (); /* treat as remqhil */ + } +c = (SEXT_L_Q (c + h)) & M64; /* abs addr of c */ +b = ReadL (c + 4); /* b <- (c+4) */ +b = (SEXT_L_Q (b) + c) & M64; /* abs addr of b */ +WriteL (b, (uint32) (h - b)); /* (b) <- h-b */ +WriteL (h + 4, (uint32) (b - h)); /* (h+4) <- b-h */ +WriteL (h, (uint32) ar); /* release interlock */ +R[1] = c; /* store result */ +return +1; /* q can't be empty */ +} + +t_int64 vms_remqtiq (void) +{ +t_uint64 h = R[16]; +t_uint64 ar, b, c; + +if (h & 0xF) ABORT (EXC_RSVO); /* h octa aligned? */ +ar = ReadQ (h); /* a <- (h) */ +if (ar & 0xE) ABORT (EXC_RSVO); /* a quad aligned? */ +if (ar & 01) return -1; /* busy, return - 1*/ +if (ar == 0) return 0; /* emtpy, return 0 */ +WriteQ (h, ar | 1); /* acquire interlock */ +c = ReadQ (h + 8); /* c <- (h+8) */ +if (c & 0xF) { /* c octa aligned? */ + WriteQ (h, ar); /* release interlock */ + ABORT (EXC_RSVO); /* fault */ + } +if (ar == c) { /* single entry? */ + WriteQ (h, ar); /* release interlock */ + return vms_remqhiq (); /* treat as remqhil */ + } +c = (c + h) & M64; /* abs addr of c */ +if (Test (c + 8, cm_racc, NULL)) WriteQ (h, ar); /* rtst c+8, rls if err */ +b = ReadQ (c + 8); /* b <- (c+8), flt ok */ +b = (b + c) & M64; /* abs addr of b */ +if (b & 0xF) { /* b octa aligned? */ + WriteQ (h, ar); /* release interlock */ + ABORT (EXC_RSVO); /* fault */ + } +if (Test (b, cm_wacc, NULL)) WriteQ (h, ar); /* wtst b, rls if err */ +WriteQ (b, (h - b) & M64); /* (b) <- h-b, flt ok */ +WriteQ (h + 8, (b - h) & M64); /* (h+8) <- b-h */ +WriteQ (h, ar); /* release interlock */ +R[1] = c; /* store result */ +return +1; /* q can't be empty */ +} + +t_int64 vms_remqtiqr (void) +{ +t_uint64 h = R[16]; +t_uint64 ar, b, c; + +ar = ReadQ (h); /* a <- (h) */ +if (ar & 01) return -1; /* busy, return - 1*/ +if (ar == 0) return 0; /* emtpy, return 0 */ +WriteQ (h, ar | 1); /* acquire interlock */ +c = ReadQ (h + 8); /* c <- (h+8) */ +if (ar == c) { /* single entry? */ + WriteQ (h, ar); /* release interlock */ + return vms_remqhiq (); /* treat as remqhil */ + } +c = (c + h) & M64; /* abs addr of c */ +b = ReadQ (c + 8); /* b <- (c+8) */ +b = (b + c) & M64; /* abs addr of b */ +WriteQ (b, (h - b) & M64); /* (b) <- h-b */ +WriteQ (h + 8, (b - h) & M64); /* (h+8) <- b-h */ +WriteQ (h, ar); /* release interlock */ +R[1] = c; /* store result */ +return +1; /* q can't be empty */ +} + +/* INSQUE + + R[16] = predecessor address + R[17] = entry address + + All writes must be checked before any writes are done. + + Pictorially: + + BEFORE AFTER + + P: S P: E W + P+4/8: (n/a) P+4/8: (n/a) + + E: --- E: S W + E+4/8: --- E+4/8: P W + + S: (n/a) S: (n/a) + S+4/8: P S+4/8: E W + + For longword queues, operands can be misaligned. + Quadword queues must be octaword aligned, and the + address addition cannot overflow 64b. + Note that WriteUna masks data to its proper length. +*/ + +t_int64 vms_insquel (uint32 defer) +{ +t_uint64 p = SEXT_L_Q (R[16]) & M64; +t_uint64 e = SEXT_L_Q (R[17]) & M64; +t_uint64 s; + +if (defer) { /* defer? */ + p = ReadUna (p, L_LONG, cm_racc); /* get address */ + p = SEXT_L_Q (p) & M64; /* make 64b */ + } +s = ReadUna (p, L_LONG, cm_macc); /* s <- (p), wchk */ +s = SEXT_L_Q (s) & M64; /* make 64b */ +ReadUna ((s + 4) & M64, L_LONG, cm_wacc); /* wchk s+4 */ +ReadUna ((e + 4) & M64, L_LONG, cm_wacc); /* wchk e+4 */ +WriteUna (e, s, L_LONG, cm_wacc); /* (e) <- s, last unchecked */ +WriteUna ((e + 4) & M64, p, L_LONG, cm_wacc); /* (e+4) <- p */ +WriteUna ((s + 4) & M64, e, L_LONG, cm_wacc); /* (s+4) <- ent */ +WriteUna (p, e, L_LONG, cm_wacc); /* (p) <- e */ +return (((s & M32) == (p & M32))? +1: 0); /* return status */ +} + +t_int64 vms_insqueq (uint32 defer) +{ +t_uint64 p = R[16]; +t_uint64 e = R[17]; +t_uint64 s; + +if (defer) { /* defer? */ + if (p & 07) ABORT (EXC_RSVO); + p = ReadQ (p); + } +if ((e | p) & 0xF) ABORT (EXC_RSVO); /* p, e octa aligned? */ +s = ReadAccQ (p, cm_macc); /* s <- (p), wchk */ +if (s & 0xF) ABORT (EXC_RSVO); /* s octa aligned? */ +ReadAccQ (s + 8, cm_wacc); /* wchk s+8 */ +ReadAccQ (e + 8, cm_wacc); /* wchk e+8 */ +WriteQ (e, s); /* (e) <- s */ +WriteQ (e + 8, p); /* (e+8) <- p */ +WriteQ (s + 8, e); /* (s+8) <- ent */ +WriteQ (p, e); /* (p) <- e */ +return ((s == p)? +1: 0); /* return status */ +} + +/* REMQUE + + R[16] = entry address + + All writes must be checked before any writes are done. + + Pictorially: + + BEFORE AFTER + + P: E P: S W + P+4/8: (n/a) P+4/8: (n/a) + + E: S W E: S + E+4/8: P W E+4/8: P + + S: (n/a) S: (n/a) + S+4/8: E W S+4/8: P + +*/ + +t_int64 vms_remquel (uint32 defer) +{ +t_uint64 e = SEXT_L_Q (R[16]) & M64; +t_uint64 s, p; + +if (defer) { /* defer? */ + e = ReadUna (e, L_LONG, cm_racc); /* get address */ + e = SEXT_L_Q (e) & M64; /* make 64b */ + } +s = ReadUna (e, L_LONG, cm_racc); /* s <- (e) */ +p = ReadUna ((e + 4) & M64, L_LONG, cm_racc); /* p <- (e+4) */ +s = SEXT_L_Q (s) & M64; +p = SEXT_L_Q (p) & M64; +if (e == p) return -1; /* queue empty? */ +ReadUna ((s + 4) & M64, L_LONG, cm_wacc); /* wchk (s+4) */ +WriteUna (p, s, L_LONG, cm_wacc); /* (p) <- s */ +WriteUna ((s + 4) & M64, p, L_LONG, cm_wacc); /* (s+4) <- p */ +return ((s == p)? 0: +1); +} + +t_int64 vms_remqueq (uint32 defer) +{ +t_uint64 e = R[16]; +t_uint64 s, p; + +if (defer) { /* defer? */ + if (e & 07) ABORT (EXC_RSVO); + e = ReadQ (e); + } +if (e & 0xF) ABORT (EXC_RSVO); /* e octa aligned? */ +s = ReadQ (e); /* s <- (e) */ +p = ReadQ (e + 8); /* p <- (e+8) */ +if ((s | p) & 0xF) ABORT (EXC_RSVO); /* s, p octa aligned? */ +if (e == p) return -1; /* queue empty? */ +ReadAccQ (s + 8, cm_wacc); /* wchk (s+8) */ +WriteQ (p, s); /* (p) <- s */ +WriteQ (s + 8, p); /* (s+8) <- p */ +return ((s == p)? 0: +1); +} + +/* Probe */ + +uint32 vms_probe (uint32 acc) +{ +uint32 pm = ((uint32) R[18]) & 3; + +if (pm <= vms_cm) pm = vms_cm; /* least privileged */ +acc = (acc << pm) | PTE_V; /* access test - no FOR/W */ +if (Test (R[16], acc, NULL)) return 0; /* test start */ +if (Test ((R[16] + R[17]) & M64, acc, NULL)) return 0; /* test end */ +return 1; +} + +/* VMS TIE support instructions */ + +uint32 vms_amovrr (void) +{ +uint32 lnt1 = ((uint32) R[18]) & 3; +uint32 lnt2 = ((uint32) R[21]) & 3; + +if (vax_flag == 0) return 0; /* stop if !vax_flag */ +vax_flag = 0; /* clear vax_flag */ +ReadUna (R[17], lnt_map[lnt1], cm_wacc); /* verify writes */ +ReadUna (R[20], lnt_map[lnt2], cm_wacc); +WriteUna (R[17], R[16], lnt_map[lnt1], cm_wacc); /* do both writes */ +WriteUna (R[20], R[21], lnt_map[lnt2], cm_wacc); /* WriteUna masks data */ +return 1; +} + +uint32 vms_amovrm (void) +{ +t_uint64 va, va1; +uint32 lnt1 = ((uint32) R[18]) & 3; +uint32 lnt2 = ((uint32) R[21]) & 0x3F; +uint32 i, dat; + +if (vax_flag == 0) return 0; /* stop if !vax_flag */ +vax_flag = 0; /* clear vax_flag */ +if (lnt2 && ((R[19] | R[20]) & 3)) ABORT (EXC_RSVO); /* lw aligned? */ +ReadUna (R[17], lnt_map[lnt1], cm_wacc); /* verify first write */ +if (lnt2) { /* if second length */ + va = (R[19] + (lnt2 << 2) - 4) & M64; + va1 = (R[20] + (lnt2 << 2) - 4) & M64; + ReadL (R[19]); /* verify source */ + ReadL (va); + ReadAccL (R[20], cm_wacc); /* verify destination */ + ReadAccL (va1, cm_wacc); + } +WriteUna (R[17], R[16], lnt_map[lnt1], cm_wacc); /* do first write */ +for (i = 0, va = R[19], va1 = R[20]; i < lnt2; i++) { /* move data */ + dat = ReadL (va); + WriteL (va1, dat); + va = (va + 4) & M64; + va1 = (va1 + 4) & M64; + } +return 1; +} + +/* Swap privileged context */ + +void vms_swpctx (void) +{ +t_uint64 val; +uint32 tmp; + +if (R[16] & 0x7F) ABORT (EXC_RSVO); /* must be 128B aligned */ +WritePQ (vms_hwpcb + 0, SP); /* save stack ptrs */ +WritePQ (vms_hwpcb + 8, esp); +WritePQ (vms_hwpcb + 16, ssp); +WritePQ (vms_hwpcb + 24, usp); +WritePQ (vms_hwpcb + 48, (vms_astsr << 4) | vms_asten); /* save AST */ +WritePQ (vms_hwpcb + 64, (pcc_h + pcc_l) & M32); /* save PCC */ +WritePQ (vms_hwpcb + 72, vms_thread); /* save UNIQUE */ +vms_hwpcb = R[16]; /* new PCB */ +SP = ksp = ReadPQ (vms_hwpcb + 0); /* read stack ptrs */ +esp = ReadPQ (vms_hwpcb + 8); +ssp = ReadPQ (vms_hwpcb + 16); +usp = ReadPQ (vms_hwpcb + 24); +val = ReadPQ (vms_hwpcb + 32) << VA_N_OFF; /* read PTBR */ +if (val != vms_ptbr) tlb_ia (TLB_CI | TLB_CD); /* if changed, zap TLB */ +vms_ptbr = val; +tmp = ReadPL (vms_hwpcb + 40) & M16; /* read ASN */ +itlb_set_asn (tmp); +dtlb_set_asn (tmp); +tmp = ReadPL (vms_hwpcb + 48); /* read AST */ +vms_astsr = (tmp >> 4) & AST_MASK; /* separate ASTSR, ASTEN */ +vms_asten = tmp & AST_MASK; +val = ReadPQ (vms_hwpcb + PCBV_FLAGS); /* read flags */ +fpen = ((uint32) val) & 1; /* set FEN */ +vms_datfx = ((uint32) (val >> 63)) & 1; /* set DATFX */ +tmp = ReadL (vms_hwpcb + 64); +pcc_h = (tmp - pcc_l) & M32; +vms_thread = ReadPQ (vms_hwpcb + 72); /* read UNIQUE */ +return; +} + +/* VMS interrupt or exception + + Inputs: + vec = SCB vector + newmode = new mode (usually kernel) + newipl = new IPL + Outputs: + reason = possible processor halt +*/ + +t_stat vms_intexc (uint32 vec, uint32 newmode, uint32 newipl) +{ +t_uint64 pa = (vms_scbb + vec) & ~0xF; /* vector */ +t_uint64 sav_ps = GET_PSV; /* old PS */ +uint32 wacc = ACC_W (newmode); +uint32 exc; + +vms_stkp[vms_cm] = SP; /* save SP */ +SP = vms_stkp[newmode]; /* load new SP */ +sav_ps = sav_ps | ((SP & PSV_M_SPA) << PSV_V_SPA); /* save SP align */ +SP = SP & ~PSV_M_SPA; /* align SP */ +SP = (SP - VMS_L_STKF) & M64; +if (exc = Test (SP, wacc, NULL)) { /* check writes */ + if (newmode == MODE_K) return STOP_KSNV; /* error? stop if kernel */ + ABORT1 (SP, exc + EXC_W); /* else, force fault */ + } +if (exc = Test (SP + VMS_L_STKF - 8, wacc, NULL)) { + if (newmode == MODE_K) return STOP_KSNV; + ABORT1 (SP + VMS_L_STKF - 8, exc + EXC_W); + } +vms_cm = mmu_set_cm (newmode); /* switch mode */ +WriteQ (SP, R[2]); /* save R2-R7 */ +WriteQ (SP + 8, R[3]); +WriteQ (SP + 16, R[4]); +WriteQ (SP + 24, R[5]); +WriteQ (SP + 32, R[6]); +WriteQ (SP + 40, R[7]); +WriteQ (SP + 48, PC); /* save PC */ +WriteQ (SP + 56, sav_ps); /* save PS */ +PC = R[2] = ReadPQ (pa); /* set new PC */ +R[3] = ReadPQ (pa + 8); /* set argument */ +vms_ipl = newipl; /* change IPL */ +vms_ps = vms_ps & ~PSV_M_SW; +return SCPE_OK; +} + +/* Memory management fault */ + +t_stat vms_mm_intexc (uint32 vec, t_uint64 par2) +{ +t_stat r; + +r = vms_intexc (vec, MODE_K, vms_ipl); /* take exception */ +R[4] = p1; /* R[4] = va */ +R[5] = par2; /* R[5] = MME */ +tlb_is (p1, TLB_CI | TLB_CD); /* zap TLB entry */ +return r; +} + +/* Return from exception of interrupt */ + +t_stat vms_rei (void) +{ +t_uint64 t1, t2, t3, t4, t5, t6, t7, t8; +uint32 newmode; + +if (SP & PSV_M_SPA) ABORT (EXC_RSVO); /* check alignment */ +if (vms_cm == MODE_K) { /* in kernel mode? */ + if (Test (SP, cm_racc, NULL)) return STOP_KSNV; /* must be accessible */ + if (Test (SP + VMS_L_STKF - 8, cm_racc, NULL)) return STOP_KSNV; + } +t1 = ReadQ (SP); /* pop stack */ +t2 = ReadQ (SP + 8); +t3 = ReadQ (SP + 16); +t4 = ReadQ (SP + 24); +t5 = ReadQ (SP + 32); +t6 = ReadQ (SP + 40); +t7 = ReadQ (SP + 48); +t8 = ReadQ (SP + 56); +newmode = (((uint32) t8) >> PSV_V_CM) && PSV_M_CM; /* get new mode */ +if ((vms_cm != MODE_K) && /* not kernel? check new PS */ + ((newmode < vms_cm) || (t8 & PSV_MBZ))) ABORT (EXC_RSVO); +SP = (SP + VMS_L_STKF) | ((t8 >> PSV_V_SPA) & PSV_M_SPA); +vms_stkp[vms_cm] = SP; /* save SP */ +SP = vms_stkp[newmode]; /* load new SP */ +R[2] = t1; /* restore R2-R7 */ +R[3] = t2; +R[4] = t3; +R[5] = t4; +R[6] = t5; +R[7] = t6; +PC = t7 & ~3; /* restore PC */ +vms_ps = ((uint32) t8) & PSV_MASK; /* restore PS */ +vms_cm = mmu_set_cm (newmode); /* switch modes */ +vms_ipl = (((uint32) t8) >> PSV_V_IPL) & PSV_M_IPL; /* new IPL */ +vax_flag = 0; /* clear vax, lock flags */ +lock_flag = 0; +return SCPE_OK; +} + +/* Unaligned read virtual - for VMS PALcode only + + Inputs: + va = virtual address + lnt = length code (BWLQ) + acc = access code (includes FOR, FOW) + Output: + returned data, right justified +*/ + +t_uint64 ReadUna (t_uint64 va, uint32 lnt, uint32 acc) +{ +t_uint64 pa, pa1, wl, wh; +uint32 exc, bo, sc; + +if (exc = Test (va, acc, &pa)) /* test, translate */ + ABORT1 (va, exc + EXC_R); +if ((pa & (lnt - 1)) == 0) { /* aligned? */ + if (lnt == L_QUAD) return ReadPQ (pa); /* quad? */ + if (lnt == L_LONG) return ReadPL (pa); /* long? */ + if (lnt == L_WORD) return ReadPW (pa); /* word? */ + return ReadPB (pa); /* byte */ + } +if ((VA_GETOFF (va) + lnt) > VA_PAGSIZE) { /* cross page? */ + if (exc = Test (va + 8, acc, &pa1)) /* test, translate */ + ABORT1 (va + 8, exc + EXC_R); + } +else pa1 = (pa + 8) & PA_MASK; /* not cross page */ +bo = ((uint32) pa) & 7; /* byte in qw */ +sc = bo << 3; /* shift count */ +wl = ReadPQ (pa); /* get low qw */ +if (lnt == L_QUAD) { /* qw unaligned? */ + wh = ReadPQ (pa1); /* get high qw */ + return ((((wl >> sc) & (((t_uint64) M64) >> sc)) | + (wh << (64 - sc))) & M64); /* extract data */ + } +if (lnt == L_LONG) { /* lw unaligned? */ + if (bo <= 4) return ((wl >> sc) & M32); /* all in one qw? */ + wh = ReadPQ (pa1); /* get high qw */ + return ((((wl >> sc) & (M32 >> (sc - 32))) | + (wh << (64 - sc))) & M32); + } +if (bo < 7) return ((wl >> sc) & M16); /* wd, all in one qw? */ +wh = ReadPQ (pa1); /* get hi qw, extract */ +return (((wl >> 56) & 0xFF) | ((wh & 0xFF) << 8)); +} + +/* Unaligned write virtual - for VMS PALcode only + + Inputs: + va = virtual address + val = data to be written, right justified in 64b + lnt = length code (BWLQ) + acc = access code (includes FOW) + Output: + none +*/ + +void WriteUna (t_uint64 va, t_uint64 val, uint32 lnt, uint32 acc) +{ +t_uint64 pa, pa1, wl, wh, mask; +uint32 exc, bo, sc; + +if (exc = Test (va, acc, &pa)) /* test, translate */ + ABORT1 (va, exc + EXC_W); +if ((pa & (lnt - 1)) == 0) { /* aligned? */ + if (lnt == L_QUAD) WritePQ (pa, val); /* quad? */ + else if (lnt == L_LONG) WritePL (pa, (uint32) val); /* long? */ + else if (lnt == L_WORD) WritePW (pa, (uint32) val); /* word? */ + else WritePB (pa, (uint32) val); /* byte */ + return; + } +if ((VA_GETOFF (va) + lnt) > VA_PAGSIZE) { /* cross page? */ + if (exc = Test (va + 8, acc, &pa1)) /* test, translate */ + ABORT1 (va + 8, exc + EXC_W); + } +else pa1 = (pa + 8) & PA_MASK; /* not cross page */ +bo = ((uint32) pa) & 7; /* byte in qw */ +sc = bo << 3; /* shift count */ +wl = ReadPQ (pa); /* get low qw */ +if (lnt == L_QUAD) { /* qw unaligned? */ + val = val & M64; /* mask data */ + mask = ((t_uint64) M64) << sc; /* low qw mask */ + wl = (wl & ~mask) | ((val << sc) & mask); /* insert low */ + wh = ReadPQ (pa1); /* hi qw */ + mask = ((t_uint64) M64) >> (64 - sc); /* hi qw mask */ + wh = (wh & ~mask) | ((val >> (64 - sc)) & mask); + WritePQ (pa, wl); /* write low */ + WritePQ (pa, wh); /* write high */ + } +else if (lnt == L_LONG) { /* lw unaligned? */ + val = val & M32; + mask = ((t_uint64) M32) << sc; /* low qw mask */ + wl = (wl & ~mask) | (val << sc); /* insert low */ + WritePQ (pa, wl); /* write low */ + if (bo >= 4) { /* 2nd qw? */ + wh = ReadPQ (pa1); /* read hi qw */ + mask = ((t_uint64) M32) >> (sc - 32); /* hi qw mask */ + wh = (wh & ~mask) | (val >> (sc - 32)); /* insert high */ + WritePQ (pa1, wh); /* write hi */ + } + } +else { + val = val & M16; /* mask data */ + mask = ((t_uint64) M16) << sc; /* word, low qw mask */ + wl = (wl & ~mask) | ((val & M16) << sc); /* insert low */ + WritePQ (pa, wl); /* write low */ + if (bo >= 7) { /* 2nd qw? */ + wh = ReadPQ (pa1); /* read hi */ + mask = 0xFF; /* hi qw mask */ + wh = (wh & ~mask) | (val >> 8); /* insert high */ + WritePQ (pa1, wh); /* write hi */ + } + } +return; +} + +/* Test the accessibility of an address (VMS and UNIX PALcode only) + + - In VMS, superpage is always 0 + - In Unix, current mode is always kernel + - Hence, superpages are always accessible */ + +uint32 Test (t_uint64 va, uint32 acc, t_uint64 *pa) +{ +uint32 va_sext = VA_GETSEXT (va); +uint32 vpn = VA_GETVPN (va); +t_uint64 pte; +uint32 exc; +TLBENT *tlbp; + +if (!dmapen) { /* mapping off? */ + if (pa) *pa = va & PA_MASK; /* pa = va */ + return 0; + } +if ((va_sext != 0) && (va_sext != VA_M_SEXT)) /* invalid virt addr? */ + return EXC_BVA; +if ((mmu_dspage & SPEN_43) && (VPN_GETSP43 (vpn) == 2)) { + if (pa) *pa = va & SP43_MASK; /* 43b superpage? */ + return 0; + } +if ((mmu_dspage & SPEN_32) && (VPN_GETSP32 (vpn) == 0x1FFE)) { + if (pa) *pa = va & SP32_MASK; /* 32b superpage? */ + return 0; + } +if (!(tlbp = dtlb_lookup (vpn))) { /* lookup vpn; miss? */ + if (exc = pal_find_pte (vpn, &pte)) return exc; /* fetch pte; error? */ + tlbp = dtlb_load (vpn, pte); /* load new entry */ + } +if (acc & ~tlbp->pte) return mm_exc (acc & ~tlbp->pte); /* check access */ +if (pa) *pa = PHYS_ADDR (tlbp->pfn, va); /* return phys addr */ +return 0; /* ok */ +} + +/* TLB check - VMS PALcode only */ + +uint32 tlb_check (t_uint64 va) +{ +uint32 va_sext = VA_GETSEXT (va); +uint32 vpn = VA_GETVPN (va); + +if ((va_sext != 0) && (va_sext != VA_M_SEXT)) return 0; +if (itlb_lookup (vpn)) return 1; +if (dtlb_lookup (vpn)) return 1; +return 0; +} + +/* VMS 3-level PTE lookup + + Inputs: + vpn = virtual page number (30b, sext) + *pte = pointer to pte to be returned + Output: + status = 0 for successful fill + EXC_ACV for ACV on intermediate level + EXC_TNV for TNV on intermediate level +*/ + +uint32 pal_find_pte_vms (uint32 vpn, t_uint64 *l3pte) +{ +t_uint64 vptea, l1ptea, l2ptea, l3ptea, l1pte, l2pte; +uint32 vpte_vpn; +TLBENT *vpte_p; + +vptea = vms_vtbr | (((t_uint64) (vpn & VA_M_VPN)) << 3);/* try virtual lookup */ +vpte_vpn = VA_GETVPN (vptea); /* get vpte vpn */ +vpte_p = dtlb_lookup (vpte_vpn); /* get vpte tlb ptr */ +if ((vpte_p->tag == vpte_vpn) && /* TLB hit? */ + ((vpte_p->pte & (PTE_KRE|PTE_V)) == (PTE_KRE|PTE_V))) + l3ptea = vpte_p->pfn | VA_GETOFF (vptea); +else { + l1ptea = vms_ptbr + VPN_GETLVL1 (vpn); + l1pte = ReadPQ (l1ptea); + if ((l1pte & PTE_V) == 0) + return ((l1pte & PTE_KRE)? EXC_TNV: EXC_ACV); + l2ptea = (l1pte & PFN_MASK) >> (PTE_V_PFN - VA_N_OFF); + l2ptea = l2ptea + VPN_GETLVL2 (vpn); + l2pte = ReadPQ (l2ptea); + if ((l2pte & PTE_V) == 0) + return ((l2pte & PTE_KRE)? EXC_TNV: EXC_ACV); + l3ptea = (l2pte & PFN_MASK) >> (PTE_V_PFN - VA_N_OFF); + l3ptea = l3ptea + VPN_GETLVL3 (vpn); + } +*l3pte = ReadPQ (l3ptea); +return 0; +} + +/* VMS PALcode reset */ + +t_stat pal_proc_reset_vms (DEVICE *dptr) +{ +mmu_ispage = mmu_dspage = 0; +vms_cm = mmu_set_cm (MODE_K); +vms_ipl = IPL_1F; +vms_ps = 0; +vms_datfx = 0; +vms_scbb = 0; +vms_prbr = 0; +vms_scc = 0; +vms_last_pcc = pcc_l; +pcc_enb = 1; +pal_eval_intr = &pal_eval_intr_vms; +pal_proc_intr = &pal_proc_intr_vms; +pal_proc_trap = &pal_proc_trap_vms; +pal_proc_excp = &pal_proc_excp_vms; +pal_proc_inst = &pal_proc_inst_vms; +pal_find_pte = &pal_find_pte_vms; +return SCPE_OK; +} diff --git a/doc/gri_doc.doc b/doc/gri_doc.doc new file mode 100644 index 0000000000000000000000000000000000000000..a9832a60d8a87131fa3bfb575f993098e05ee989 GIT binary patch literal 54784 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 Q^S~wXmX^N$B5L6O14C*!?f?J) literal 0 HcmV?d00001 diff --git a/doc/h316_doc.doc b/doc/h316_doc.doc new file mode 100644 index 0000000000000000000000000000000000000000..d39be690023696281c624470963b5966139da1c4 GIT binary patch literal 82432 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 literal 0 HcmV?d00001 diff --git a/doc/hp2100_doc.doc b/doc/hp2100_doc.doc new file mode 100644 index 0000000000000000000000000000000000000000..987acf0319adb6a4f6ae7fc7066b166db9c6a543 GIT binary patch literal 166400 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%0A6Dhit-$QoW_dNABT7IBi) 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 vGxTB%ZR&P3d*;gUm{z3!jy~{zYz00M literal 0 HcmV?d00001 diff --git a/doc/i1401_doc.doc b/doc/i1401_doc.doc new file mode 100644 index 0000000000000000000000000000000000000000..a081da8b1a121d051ec83edff9eb2ccc88f0d6ae GIT binary patch literal 65024 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 literal 0 HcmV?d00001 diff --git a/doc/i1620_doc.doc b/doc/i1620_doc.doc new file mode 100644 index 0000000000000000000000000000000000000000..bdb40704eb5bdc60f2deadef8f244cdcea7feee9 GIT binary patch literal 68096 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 baZ;U0e&;yXb4rcZ7u_kwN&54#E`k3Kk^!4Z literal 0 HcmV?d00001 diff --git a/doc/i7094_doc.doc b/doc/i7094_doc.doc new file mode 100644 index 0000000000000000000000000000000000000000..5ef7d0c3c14ff3e70ba1700bcbd0ecbc2cb584fd GIT binary patch literal 89600 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 Udgct{&7!-+I7xiI&?WHy0qBTUF#rGn literal 0 HcmV?d00001 diff --git a/doc/id_doc.doc b/doc/id_doc.doc new file mode 100644 index 0000000000000000000000000000000000000000..27eabd6cfebdad6974703812fe046cb30a751b0b GIT binary patch literal 116224 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 literal 0 HcmV?d00001 diff --git a/doc/lgp_doc.doc b/doc/lgp_doc.doc new file mode 100644 index 0000000000000000000000000000000000000000..9eebced8c25f008adf0f209f054fa471075ef7df GIT binary patch literal 58880 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

t%Eu>;J<@5>l6I$}(?7fHm2)I!+}g)h?XKCl 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 F_&<{~{G0#) literal 0 HcmV?d00001 diff --git a/doc/nova_doc.doc b/doc/nova_doc.doc new file mode 100644 index 0000000000000000000000000000000000000000..5b0785e5a822ed870ddf34e3f7fcda93f3da4e71 GIT binary patch literal 86528 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 literal 0 HcmV?d00001 diff --git a/doc/pdp10_doc.doc b/doc/pdp10_doc.doc new file mode 100644 index 0000000000000000000000000000000000000000..baddd5ff26c0ab48121769540f063bf439ad4206 GIT binary patch literal 84480 zcmeF42VhiH_V8a4N&-ZB5l|mU37QThp($xVAkAb#Q3NK*BpFF&!b}3hvZ7*dSQl4x z?PABa_U?)zDq_Rl6+7y#imvkg&b{x=OomLrvVT5VMt{t__wGBlpL_1P_q}X*uID?K z-#YMJBkXgK5o7$aEzal^az2{hm)XZX4C4xZN5L=Kwr!Ksm%`tH!#$rrNeO&@^&>{@ z!*Lx9@$?FZnH!(`_QbViD z+Z}A%);(}8(r-J!UFyfmF8Wx$zv-`kxA)!0zMXHW06FY5K%Z>udli?i;QHes;Tkdx z<9?cT&EAGFlO})vAbo$N@4pT!=jPHS*TM7_w8k0#M*2UppRKl3iaCkI6~9ob7MBzU*WB+rB^2w;eA0+is8ccclC6 z^LG69ais6?cc$PbUi%$A9ZZkSEO`DI&Y`<*M3KmC%W0}MtkgM z7~^U69gSZ6Dboqy5dvQlJZvs*_bzdJYRxKdV~fvSTi0ZIyiM*Zm+5S5tarQo zW|P-!B4l|%(KOTVZT3~U63t4t$LVWHG@YJmv)WtL+~D#wIh)*G&-nQG5~Ogs9*Na1 zv$46d-tDh*Rhw>)nKo|RXcCl~m1r*Uxtp3?9<#E=Eb~^nd`)JNS>D{}aW9O|4WuNY zYEDz_7Pt@CNtxa%pK1Sy%J<<=cT zN2y4vU1Xlzs#3FsEpa#1d7GO|pUdCmb5}`OB@(ErzPVb`U|+6xH@J04s@qkCs48go zlLM)vM6ke8ol4$Us-cxa+ItH3d>q{3kmqAa`EF~=;KVrCc5 zF=rGM=Ovo?vrEhJ%gfD@GP9tlw6Gwba|Ok@g%x=P#Z%23?xS~^g#|?g4um>NOo`AE zRglkpQ_Q0LvfOD%&dw<)EO5+8G^Z3eibduWgl3zi*=2Okio)zNv$UeDw4^+r=<^U; zTu?lvj9BuE@{1kGCed=z%%91TSw1bhu+S_k$;mHsNJpwDEiRa0=H!!-?3}`UEt*W^ z7G@U|C7OBJMcGp&HDzWA2`p2=tkle!mak4BKAZn@9R(%DlI+})Vn-Q=iR6k%>|19Q zl;l;(RSdidGd!pauvc1yn&MZGmQ9es&?UsE%TF zF;HJrU;ff6S7Q^slA1^3xIMZlsAi+v3O$e}=5aQtt{Z>dNKOP z?U#N?Kk*{Kx5VvtNmFk0c^kY<{6whVSx;}`u0SYLx;nS{b$6#{*gY!Hp&NZ}WZK%! z*^CzOxsO!35(P!y3QHoH>=xgfGR`&Udd;C}Nu!6FbL-5xN1AXQ~190R6^ev0c&bDEl8mOsU86<8!j^%>o_FEK@yIYwlr z$63S66qmE98SNE8=9rz6IabL`PK(Pet%x9Ltd=xp2dT@@l1LweoiBo{3@s~T2eLA? ztkH259`vW*%&vAeHZe>@kea!3QnR$wF>zCTG*&Yo{gyB#e^dmaSvx0moEADZ&f!M? zn+cABqDT_QX^ENbXFelUOU#HX%}q-)OP#1+)4{)Hnaf!%QItB$B1Dmqx^q#a=_oR{ zi=wpIQ&lH1ltzjnO~;V6gG{9B7_#E>4kZ%~8OFo}DQd27ayQnymP$VI4viE^`p!k7 zI$3)1xVW-uL}E3PM6;|kbxca?*p$?al+;WPi&E25Qb)^~tW>kw=Uyy^LRrKdj@FT< zrS2e$x;rMPrG`cCAU<=7*Vo|0pz@)fE5?j9i=4F{7iOHU$plA5q^w*0HZ5%jvD+Ot zEv~RMJ=M%B$~Fs8zhJU!HX?h-P{ncJu%4`i1PAtO-n2L zZKI!YBTV^Y?06X_8yXo2)NT5fM6<=)Y&JCen;5-nqzY#i&F2y`2r+mWisu&;J2J+| zAlvA~F1Kt&ElCet{BDrIjD0R5CJ`xdasH~tJAYFmTX>J_;U)<_jJ*EVT}ZzbY(#`&dV5A4!z1uPYh!g|T53w1`kEienm(**Y*w=MQH?9)U?CHgki+`M^wf~UhUyxfetl=7vo_?S zFZ7bX#UFC1DKx&NO`dA5sTvVEX*!i@^Q(OGtDQ}%(A4?)OPfOusw8VFKWX!;j|>P; zo8Qlt?NRlNmUwI%LQqm-xix#3xFj^uVf;vtDPe=N(LXA_ zA}5n)o|k(Ryk^tCJ@i~m&gber$?_wH9$&BVJ;^FWJ;q9V)12j zxFJMs)o8WFq->$;SWQcqDyhLBKJQS1s(~siNxG1U0@dRcxetz4&5dG#ju{m%s+BvG z;#J`>Dn;qW=az9=sj-CIytK4YW|e3&ovipWQmlsxv6X#H^ik6?&oo_Xny-c}{u!IX zKN<2*W@0>p*XR`f;bc)@^on;#O~{~^q6V9`<*9MU%HeFeAuqq8I6EaTzpx_P%$GjT zh@|XxoffOHP`DM zrON3so%MdN*!5w7%e~A6bUR~m-`ps(L!}SP^Bv|yec>Q8J1@3xWgQCujX+rGY zC0gqiq?Di#Yni`RS7QeUCec_kf=2uddR*-U)f%+IuvS=(nw5>npkO6yek?X1#L)ld}@vz=3sp_7&<4va=piB(hI zg6@~9*uKLzU~`F2hyr&pxxx~odoF6GZkoJ}(gw6g00mG$v#eGA5}X&!$}eIjq^72h zk}1_fX*2cW@NmT!aF0(M3|69~&wFsD$hV7Wp{v@@c!c+YNusL?Cy3OAcJQ>mEb|4k z#_6sPPUBoYAEi!&s$2P*nPU1~B-c|#ylo^fLP*bIW`lM~;f2taQTu^gD<;#^+<-GI zzS!$YaxKN5Lm84gSCyodnWs;;z$RxUW4cukx(*6Uvh(bQWw&y_SyoV#mYRdU73+|D z#kLpKMWvT#&$Qfl+Lxu9Z2s*0R%dB$O0pltQB{W_n}mg##O+DcCG7x5l#WCR6#q!R z6XVKJxWJu7ryQQ;8lWUa$qN-Y`yPY`NC<01C{CpG4Wb%|~CX;;rmFWJs zWJoh7iGj!%K~$!9B7s&3(^Z>%Ez)DFU0SJY(@SNdsRbj(lyOa0nT%@QM(wFmdPbFl zs$~S&*^;vHQg4iDv~B?T(UC24@t#{J;a<`idH| z)Rpv*D+P{nZiwS67k0L8`8$#Kk<4 zgt?F8OL8cxmGh;!oK4HZ2J(4vdp97qSs4a#Qwp=EN=aK6twhw+JMmQ|OiUX+J}vVg zbh5a>M#aZv=cXnnXXmD6#>I`!h>LS7^&Uu@w3_(10Y zRkMr_W~CEfSujZH)RJNe6EN9a9?@gfrX(vq&XJxf77LfHRwKHO))^mH5s6j%4XUZ8<}0Wz2e;oTrDqk$czkrDwvQ73+qG_5>`b5c@xwHau%P?cW0 zamL5x<&;qnDpa-0U*&T*ie1nu=VqFjKtH1T2%Ns7!091@DXI1)j}8euW=Da?*nvw6 z@{1*Fw4%}ivz~#!-cMInbxchZ;5-h$s#}^|EG;`E{Gzf|?UwD6@z_tRCu~7U+hGez zXl=n@*`-oJtx}^zay}#+M=IIWhg{HIB#>%OO(|rS(dw$5YAzPeEL1Je&ae!ArpO6& zV|q?;-u$BM*-D5z%!&z^Fxqs9o1N#E!ATl;$3CSnBwU(TD3=EX~DBEly@s zUcHlP{SnO#jbbkZk}!c;v3wfPuH>9$p(c~Nw5`hM@AK2YXO)S~PCf&-sf9E0iaion zmOqs^@iY^uG-tb4i*7&@IZ$b$M8yTw(1_V5>R0J&>}Xc`)L3G>DrC43jn3FLOD@W9 zJ;YkmKhj?9#nuo%Jv|;5tQn`C^i<0lqa;Aat%5vO zLzGF(L2-#Xw1y0sjt0gyxj=E~b`UoH1Vd>7gkz{tCRyu&3hQ>eWLY6qqHrBJneeIf zP$t`r^3|?Jm#3QAl9XA4ERn^PmrS2(W+bM`sE^i`FQpijoos8*K*03G(K?{|YVb0t zqJVW+YdDU}E}5QfrY5FkS|ZhVP^Q$c%*Uik!U{uf2pPFWtTii;_8`-;2CQ&ds$rcK zuNHB)*rQ`edt{DhHFsH(2@Ej)fPJG^eALXbRfS3{(+bL&R?X4%DpQ@%lWostKoDp_)tl2XI7 zJu8dL8ZS~Lw5l2jK}#cb^dVb)VozHWKzqqa2W~wpl!>ipp;n^W{uk@ib^)MjrPyc- z6jAFN#YDjWg=2{P*`+Rp6c!B4U|pADrn6&+s1>l0emkfXI)S#Upn!K6%gf&=6MN

H3(E;GShW2*zZ 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

fN~hr9VrZJ`el%FpQI6 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 KfqPZw!2bZi-g1xt literal 0 HcmV?d00001 diff --git a/doc/pdp1_doc.doc b/doc/pdp1_doc.doc new file mode 100644 index 0000000000000000000000000000000000000000..3d475e94642244b60093f59310fb04ad4c3ae273 GIT binary patch literal 83456 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 literal 0 HcmV?d00001 diff --git a/doc/sds_doc.doc b/doc/sds_doc.doc new file mode 100644 index 0000000000000000000000000000000000000000..6e694c44d233b894f95868c0a47f7c5e9cca498b GIT binary patch literal 74240 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ⅈJ^3 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 literal 0 HcmV?d00001 diff --git a/doc/simh_doc.doc b/doc/simh_doc.doc new file mode 100644 index 0000000000000000000000000000000000000000..aaa7d367d200afefc014e167bbe25f806f487530 GIT binary patch literal 198144 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 literal 0 HcmV?d00001 diff --git a/doc/simh_swre.doc b/doc/simh_swre.doc new file mode 100644 index 0000000000000000000000000000000000000000..6a3441125bc7f822f84c6c0220c362ce83b46eaa GIT binary patch literal 101376 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 aQk7YLr`gxjrW^0gxJjIop3j$B1OE?1gXuT` literal 0 HcmV?d00001 diff --git a/doc/vax780_doc.doc b/doc/vax780_doc.doc new file mode 100644 index 0000000000000000000000000000000000000000..07b7f872347d45714e46581bd3a85291a7d72724 GIT binary patch literal 125440 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%0D5bCWRNaIkG=x|0btLqfB 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 literal 0 HcmV?d00001 diff --git a/doc/vax_doc.doc b/doc/vax_doc.doc new file mode 100644 index 0000000000000000000000000000000000000000..19a703292f90cda6f274d74be684cca6da71be7e GIT binary patch literal 123392 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̽=?W)biZFMeGeq8tJ7dxvCah=hw_xAdPQm>Qs&tX$422Wd<-gSlBx%OkNuiTE+I=IVcie-A}6rcWIl}=y%y5Z#}Ar;a# zrnKum_fVfN<~pZO-_X3OdDiXM*%d2&zy8vnM~o|&SFY9N$`@}VPqnW4WR%;ylt))9 zzOdgg%ADrFZFEWJHdOb?WJKEGv;@=v}oZflY@P}_^noZ z@350?XIk!_9#PBmmErxvA;CL)^&dFBey3*hZ&)3@R_^QXyQFoU_uM)1maG28X>-5a z7v!7N-Xdtyetm=Cv*Nuj2WVIDz4#)w%f7EC-}&jO>A~*%+hnX?ylltTVZ)1U44RS9 zFJ=4IL!%OQ8b^7a#)$txu@zNiE?b`EY%QK3U#}mKnwXne{ z_wgI99SdIQ_F~x55j!sa;51;&w0Fl7Pj2YE=6p!N<~}R*{VQ2Vz1ntVh+ov@{nqh^ z8r{pBbvkfI>hCv79KF^1Ugq068!k+q(I{!^**o4PH&nRtIOvz+M-#R@>hP-EzDq;O zj+s1RaLpB-Tdbb7sW*L_)%DveOcW*j`<&JNKDfi-^eHv}ycJWm=0)SoCi_>HZF=X# z&dR5Xw;z<&W7{4RFXOWHSHAo`>*dC!E!rM2Sz4jRs|T-c9=vVPqF<}i>p~Ob?)J3b z`}X0PBb8RRSUT?6)3aqR#PmI!{rABdd*8enz+ij&(XUSXHIQH-R&@2OE!D-0OkyyAdH5aSHN9ewv%9})Y+q%^tCo!p4C^USX(`WsE zNxk(Z*=2Ng)~($&m)ZYR^~^elQiHF~NO#ZJdiBYHR5zF@lmM|YMwoT85QzMKzjlO!mO{>LoN>=NzGw$GuvdOD9 zJV|?1XY?;2zqg*cp}hI}ffdtlTDm4Kb24h+zAml&;3)Sx-|XwVc*B5WQzwLNJorQM zq$Z9#cA1?j)pkn%<(r*1HJ(55Sn&(qDJj((IvMt>obt4GVwTfTmxtc&+My%=Sov$c z!^O)yuq}Ht*1!3=FVDPQ84QtfNj+W-wMIk_^gQf$YyIXeo>i`lc;QrM^_Ue?t=jB2E4OJ{`jH#sDy&QD z;#O_I$b{)hgKmU%?w`?d=b^@)yPnQU*nfH0$#aH5cYCcFy!2SCNUQ8KJ*Us}uB@qSUg|{^%VMowB-LGfzv-ktt{JIy z+b=Y0VAj*T_jkP>nl-K(vUcc=b=NXnOSN3PWXRkFS`(X=9slR(g)LWhZPfVgn5f!) zH@&=4{?(eMm6n`Ln%{p)r`Gc__L^=QY!aBdZeaMrd!xhqnz_~=x~1HxUWzT}dZisd z_s*%U%e`Jh>s(AceB#sqm&{wc4?FZ}*rwL6l`FqBc+sNvn83Xw?w1&T^yTvHwy$EA zPivX()??7-SqA6y&Xt^l)fk@%d?SaO$FOk6HLNxK@Ag zx^jk19xNF4&Hm6IAI^5`Ub^$N%T4`LyeG^KZ}iAAXpU#iPSvY+uW465A+ltR4)YSz zruWE-O?FxNb+0?NE5B=bG&RlR*wpai>{?zk7~Q7>MDcfX$q*kcJ=%)K>qsM z`>`EJ&pfrc{3GVC54|6;EEUB(^&(XrDNpj}kCeZ1@;=hVf+8uaD*0pN-w58v*j((x zx%tQ@(bZFrIuds!^EZ&C-(V!)nzf*6WHTZlGAcMc%+QA=z%_a3J9#9?^$Vq7S-Rx{R%(CQetp%{; zu>ceB4&yk4E^EfG0I)FUNx&$>0ob>&`U# zt(f;SOur5_>%|-w$Xo8^P3Q8qYkA|Xy!BMxd?{}~lsDkXThQc9Sn@U`c_Yp#Z_XbC za0Z$gZOP2ZQ?lhr$?~*Zd17k4Sk+T3<>`6y1T}ezk~~RAo~9yC)R3nt$es0aceUJM zD|gWbF>4_hhw+HTSC{}fgqZ}wDW+g5ra=yCW`Id3W`Sf>#A6QTVjkvW0hk5FA|zlj zz5%nO_!djC3`tmy6c}5(jY=S$K^%c!!Ft$7bk*e&~;Z7>lLYh27YLy||7yuqwur zYG92Da77ddriQ$MvB9D(<_wYOZz$2949Gn#z zq7hus1pN?;L@YxRR^R}Bhki+>4I>z%E4U*0>MUAU|>Z_E$-sm9ZEXS9r0a6e~d%!2zh`ba;QkMwJ- zv7g*VsA*oDNgK`m8hoUm<45|b(yXB6lN)|CPfv5Y$W0@f$J3lH&fKZ4X*{_!Uvodr z=^~eRYaUN?y2vHMn#a?eE^?Wv=J7PAi(IOxc|6VOBA2^q8c!|=)7(#Uy2xJm71aST zmt07gn^9FO#lz;P-npRyRXXnmRD+y(Kq0x*{U%iTT2ftV&jZJ>s}se37mDldR3WJ5 z`N60kMN%LSFC0o00y>dYX+~3|;qGLrHPovPub>}QxfrT)HV4Qgm>fBVn>P4u#!Ye% z$&0Aq?mQ`EY;5#ECN5?s80Ttp)DC}S(F2d zr97iufwtsl)L<1hkSdgrB2`o-U?zcDFhXlMkrt7p#d^}>7HRR8w75rFtd?}Z8Peiw z(&Bs4!k2WIjK-wJanfQp>5zdcq{SK1;W2clFkR}G8KlJ}(&Fp)X`#?!L3CjNW0;^k zDxntYq7j;)HQdn!-7x@z5R4Fv#FvP}6wJieNW?O%!v<`}P8`Hxq~ScS;U@mTBV^(U zp5q1NcOxB`!UE+{3AIrV&TvN;bVol7L?D6@g%Oy5Ntlf}NW?O%M>0~8!ur^Pt=J)0 z$*K5@m6?Tu)p>yiPS@h$smQ3!;Rj?J_D4MC;{pCg1xF6Ikbj+YqKmg*dqxf2_^a01QR@eo&dV;D~13W|BKZQ?Yp z<1a7Lv9+gANEPa1&}_N ziFs%g#7++nctT!^HykUl8mDmwy2Fds0Vx0M=$inWK6?! z%*1TOV?B~_9v5*5myv<1(B4D7js|doGhEOc{V*OAFcI>A!(?nirM&$$^74GoC z5KO{scs65L48@n2hV}Rp&tcM>To@BD4=q}7A_EFH<_+^&aRLoy9hfIXBNpx*DQz(g zE3g6EaR^6Y)`=V+^RNI;ovE=Q26K>z)!2$1P*A%ohACYs>2Msk@h4tFzZ?D09sQAx zUs1d}B@G(D372sdSuppa#6fkq!X2SKC;>6LH#s6K`mm1C0bcM$0Fto-75kFD=!Ra1 z!Dy_+_t=h|7}t;5K6C~$uSmrKWa1@4DVc|1CRSs+AH(1l?!nlfG{bbnBOAJu-ZcWL zk)k!+;RAn+A52b;F~O{B%*P_!#P3KP!pSmh#8x~<7OaP|OmIg>EC}VKA`*si(iIya zuTwmQG#rbfjknN>#z;yT*q|{wjAGSc1V$qXt8omc@Elnf`6VYo@eohYW;7)$yy1s& z_zLeJXUJ=hWjDbrEJo-!wmqD}1-Oi76Gg*V=0n7>j?oQ0F$FWR4Lk7%9;3!2N?!EG zAjD%KTFxd-U>(oV2|A$%uFqvVguE`KB)X$F=3oIz&S$-$E4g3avz=!EcX91Y-SoQKDD<{85<3MMqn3B$ zFs|V)*6(6|;ghPWDg8iOYDSll0jd3H?Ivwe1(PrZQmfg3Q#gbAd&ut~wU)jZh0*x1 zmf}b)rASd4{QtfUC}^s}9_%EFy?BCWke|s;n^GEEaI65!Qj}yETAG{|iB{xHFe*zf zhG!M1ouF7nl^V3W;TE-{HPnQ>YLO#CYC*l>i$K(_N6yR)jCUjlX-JI(*HOYl#h21Q z2r<|RDRIleCdU;@zZ=l?XI@Ybj+hX_v1=%Me>5fXaDHwb#dMH>rPz-nc!;McN2y|i z@p0rX*nlm#jR&YiE?*7u61cvYirLtOeRzOJu$oNG3$5o-LP1^(H5JE^2KD*13I|lj zOgfz0|G&#Xp{MX0=5M_!>D-^$Ci(wN6;?G`7ZaybnT$SrS{rfYOk#buc^>d)B{!9*t|hhpNlI)85-nWY13i17aqBE48{i1cEFNH3-ep~sx)speu$=Evt^t#NLMwZ?>4Ype>PMF=fbh#mhS zM2typh!_(>#F%{cf_RwchVU>agopWOFNl?8ZU`$&LReXT_JZ6mlN;iG8A9AI^VtjX zW4YWAKb9lJkL5Hh2$hk4ZWzk#B1OwAuB&PjOVJ`kik3IuWoXqH@)ELqjdDCUZL_$2 zZORQ@y?okZ)IRR##E21mv2-#dv3z}ZOq~vRO6<}xM_^*@K%PEaqZYma>qBw z7eG0_w~kp{(i`Qpy>%GhTgRL4GN^idJ9f19G1NO+PAp}NOk$X-Vq{8;Ok$Y6ks4lDSvh$f1-d^H|i&q|J$sNqZM_d4yDTKWU+H{&D_P7 zT=SnVm%jSmYT9y!9 z%NDR8vL^CwVuMxNvf{t6iK#<f)>Ni4`ll4DI#xP_ zD7aW9#HW_5I##-bDY#@M%;yxYI#zmwD!6bZ)aRD3I#&9GE4X|m+`lPeb*u~sS#S|c z$bVbP>R1^Pw%}5hu%A-U${LsB5p}sFZ8_%2`(2J@@_v_Nl)T^NI7t1ynBtxC0%W-e zId3DGt0|;?R_8}$+q{&EytYVr1E{o1<@C4AX>%a198QjTq<;ecva>&|CaS)hE5JS&+4|eB$YHWdLKzSH(7LLa79n${k36SUpm!}qdTRx!iLVV>Nv^?(V+*|b%%0SZxp>d z(;i8?JJXftJcQBTi8$H{Jv}XLEdzaRJ$3zCJ@X8qh?Rd{T;m!ls-lv6LR zud6MM#;LbdL^6HV6D8W2#cRbHF~`Mpwe<{jSjEy97`~sBtPD=)GA$ea%RR_`T$vtD zw|d!***1!jffa)I3CC4AZ3CTR+S+>Bx*Dh5nlXnfr!V(3tCybZ#!D)fSUIgc|K86= z&Jy=l&OuP_^DLqmxTSeKo4dBI9;vRcBiCCN+_YwyCACybFH7UYMT~TOb=1#WJ-<8Vdgv-q;gb24W&Cu>Ln*+6wny-BVQyGj>nD(ff; zyf{fCeHE{TFNO?n^C`_Z;q9uZ{=frNZo(z9g@7)E&HT38z zU5jOM`l(n|KHp&rBMTm{iDXl39*PD91Y^r6VEZ&>%hJysI)+a|-6ZAY%<2Q*U+IyZ zZJyKHf~QopBrmgJ50zX+o^c`DwLCY*hCD5bZ$acSs>XorKZ;=@*pGv`tE4!W@=CrV z&$N)-M4mtq!1sb08#>Bds%FQS?A4f@(3rZBF^g+l&?x^8b$dr%Plo)DCDNkHjY-R% zW_1~Cx_*wKqE3x1mt~`!PY+o~(mw$*W)h?($!|`wfhdkbQZpTrvUebveI}&LknC70 zY}8Gav8vKG;(Hs~vNd$2E$Kdhwp5=a=PF4%nzqz^#?UsU9Y@=O_DtF`AF>5=mR(sf z=+&~1jaP8!@DQKq@JO4UQ9J}d*-yQh%5X9-zEQ&?!h(nXqhH?PWL`SU-C!Yh{^8M~ z%3-COM|fy}jn}BC=m1qW8OM=ClGs-06zmrn9u*!KZPO(%FxW4^rgwOxKi%D+FnXRW zX`=kx?AFpF`;KTSKVJzv*W&ph)#um)oyI&kp*&3{@g$8UUzT>Y)v7ihi<+VoC`y5% z6evo8q7*1ffua;BN`ayjC`y5%6evo8q7?X#DWK{2Uyi4>FPyrNXlHFYZxP4;b+eM& z&`mF2HxG`z<#=9>hiNI#JIXP7gba%~$T@(SkRKT4Lr%~qLXP!UL5}5rfE>$jg`CKj za|v?n|1%`^9ppX6mu_Cct-~Xu17i57JSLX2lyYqBm-AiDsL6LZd!Rncq^VtznUMLH z9~BBZcOXwGkm<{@y(~|U;OLM5Wpo*fa}}J>P)$pru;IIOb%BiI2Kg?ZWxfY>ZQo{) zN5}S^J-w9Oq<8!7mPan%#~^Tw0( zR?nxjKR2G7{mUC~X(8j)&lfMDkntRHkZRXnL*{QLYx9wMV&zp8jr_7^7J`~5=| zPks|AOuYB|hbo@bc?uIx_K%{bCrEHUn@k&FE@vTr6QijSEg8X!?;I263F|-`F z+MqIQQ3X{|4N@nlftsj=+NcAmd(?v+>>*{fl>btvka~*LeWbjQGDylbDJ!LZ+5}C} z46cwmTMM|MC0e01q;A+2?q~-Ow1?C|J<$=J&>3AIb=_|04lndTPxL}>^g&OvN-z#|+HGEX>B&h{qhv#XQW%0xZNLBw#VV!4f3mTP(#gBw;yL zU?o=J9hV<{M|%y{;(M&adi;P5NXAB_U=ucD3uN4Fw6|jie#B1fLMnD+4}QX4?8AN> zz(M?sLpY2hIErI9juSYEQ#g$?NW)p2!+HFI3%H0&NXKQ!d}Yx76<2W$*Kq?kA^mUD zzJt5?4fk*#4n^d-gh z@Tt?6h<0+~mPU`9OQtH<=*qfp&(s5z^CVrO$$#YiQJR~Y|04abNH|kfOuc_B`RC1# z3)9ynlq|b6s;D3Te@lAjOkazfU#=94AV>FA=CmIlH-BGq&fu!1toon7zoze!XaBdF ze=~jcv}G&!Z{#C+=b`BH|D6=jV(se~srH}zdAAMQ#`|j+<>Ez~#*OOn1bj!EHsOB5 lLwTybvToSPOZw4Cxl_q!J9U3M7sd0&@(`S&=6`1j{11L;numunits; j++) { /* count units */ uptr = dptr->units + j; - if (uptr->flags & UNIT_DISABLE) - udbl++; - if (!(uptr->flags & UNIT_DIS)) + if (!(uptr->flags & UNIT_DIS)) /* count enabled units */ ucnt++; + else if (uptr->flags & UNIT_DISABLE) + udbl++; /* count user-disabled */ } show_all_mods (st, dptr, dptr->units, MTAB_VDV); /* show dev mods */ if (dptr->numunits == 0) fprintf (st, "\n"); else { - if (udbl && (ucnt == 0)) + if (ucnt == 0) fprintf (st, ", all units disabled\n"); - else if (ucnt > 1) - fprintf (st, ", %d units\n", ucnt); + else if ((ucnt > 1) || (udbl > 0)) + fprintf (st, ", %d units\n", ucnt + udbl); else if (flag) fprintf (st, "\n"); } @@ -1819,7 +1819,7 @@ if (flag) /* dev only? */ for (j = 0; j < dptr->numunits; j++) { /* loop thru units */ uptr = dptr->units + j; if ((uptr->flags & UNIT_DIS) == 0) - show_unit (st, dptr, uptr, ucnt); + show_unit (st, dptr, uptr, ucnt + udbl); } return SCPE_OK; } diff --git a/sigma/Design Notes on the Sigma 7.doc b/sigma/Design Notes on the Sigma 7.doc new file mode 100644 index 0000000000000000000000000000000000000000..fa42bb907269a3017409252d18009152d170e991 GIT binary patch literal 25088 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, instead of > 0. +5. CPU: PSD change instructions were not saving old PC in PC queue. +6. CPU: illegal register pointer does not stop the system on the Sigma 5-7; + instead, registers read as 0's, and writes are ignored. +7. CPU: traps were setting the Sigma 9 vector field unconditionally. +8. CPU: CH does not SEXT Rn<16:31>. +9. CPU: MTW and MTH overflow traps not implemented. +10. CPU: MTH condition code calculations not implemented correctly. +11. CPU: illegal shift opcodes on the Sigma 5-7 are treated as arithmetic + single (according to the AUTO diagnostic). +12. FP: SF did not calculate condition codes correctly. +13. FP: SF left did not detect normalized if the count reached zero. +14. FP: SF right was retaining a guard digit incorrectly. +15. FP: SF right test was not taking into account single/double precision. +16. FP: fp_unpack killed the operand sign before testing it. +17. FP: fp_pack did not recomplement a negative operand. +18. CPU: DW overflow test was incorrect. +19. IO: device status bit field was incorrectly defined. +20. IO: AIO was testing for == 0 instead of != 0. +21. TT: input keyboard character mappings were incorrect. +22. SYS: shifts were not displaying or accepting an index register. +23. CPU: mapping from pulse interrupt number to counter interrupt number + was incorrect. +24. CPU, CIS: handling of instructions aborts was incorrect. +25. CPU: CC2,4 set incorrectly on aborted stack instruction. +26. CPU: CC2,4 set incorrectly on MSP,0 instruction. +27. CPU: PLW not converting operand address to byte address. +28. CPU: PSM, PLM not converting limit operand address to byte address correctly. +29. CPU: PLM wrote registers in inverse order. +30. Definitions: number of virtual, physical pages derived incorrectly. +31. MAP: MMC control set wrap incorrect. +32. MAP: MMC register update of Rn|1 incorrect. +33. CPU: CBS set CC's incorrectly on unequal. +34. CPU: TTBS set CC's incorrectly on early exit. +35. IO: chan_proc_epilog and four other routines extracted device address incorrectly. +36. CPU: DW was fetching halfwords instead of words. +37. CPU: multiples were not setting condition codes on 0 operands. +38. FP: floating add zero test on second operand was inverted. +39. FP: floating add zero cases failed to set the result variable. +40. FP: floating add zero cases failed to go through postnormalization logic. +41. FP: double precision add macro lost high carry out. +42. FP: double precision add macro had an undocumented restriction about operands. +43. FP: all double precision instructions unpacked the wrong low order memory operand. +44. FP: normalization failed to decrement the exponent. +45. FP: in single precision, removing the guard digit created a spurious low-order digit. +46. FP: denormalization failed to clear the low word (single precision). +47. FP: denormalization failed to clear the guard digit (double precision). +48. FP: add/subtract failed to treat abnormal 0's as normal numbers. +49. CIS: WriteDecA set local rather than global condition codes. +50. CIS: Illegal digit check missed byte 0. +51. CIS: Overflow check set wrong condition codes. +52. CIS: NibbleLShift routine overflow check was (also broken in VAX, PDP11). +53. CIS: WordLShift routine overflow check was wrong (also broken in VAX, PDP11). +54. CIS: WordLShift had signed/unsigned variable conflict in compare. +55. CIS: WriteDecA not setting correct condition codes for -0. +55. CIS: WriteDECA not clearing CC3/4 before setting. +56. CIS: DM shift-and-test loop did 14 iterations instead of 15. +57. CIS: DM final shift of 16 done outside non-zero case instead of inside. +58. CIS: DD put quotient and remainder in wrong registers. +59. CIS: DD did not shift remainder to proper place, based on dividend/divisor widths. +60. CIS: DD overflow test missed exact 16 digit quotient case. +61. CIS: algorithm to compute length of operand failed for certain lengths (also broken + in VAX, PDP11). +62. CIS: DM and DD answer was wrong on restart cases. [NOT FIXED YET] +63. CIS: EBS fetched pattern from wrong address pointer. +64. CIS: EBS field separator wrote wrong byte. +65. MAP: Access codes defined incorrectly for access protection check. +66. CPU: LPSD fetching operands with write check rather than read check. +67. CPU: Illegal instruction stop (and other trap stops) weren't rolling back the PC. +68. CPU: History routine merged CC's into history array incorrectly. +69. CPU: History routine stored incremented rather than actualy PC. +70. CPU: History reporting routine printed wrong operand value, due to colliding declarations. +71. IO: Power up/down interrupts should not be implemented. +72. IO: WD was not recalculating int_hiact. +73. IO: Interrupt chain was not linked at powerup. +74. IO: Interrupt chain link algorithm was wrong. +75. IO: WD processing was spanning [beg,end) rather than [beg,end]. +76. RTC: RTC interrupts were happening at the wrong level. +77. PTR: leader skip was testing for channel end. +78. PTR: leader skip was testing per command instead of per reel/file. +79. PTR: end of file was treated as fatal error instead of channel end + length error. +80. PTR, PTP: units were not marked UNIT_SEQ. +81. LPT: unit was not marked UNIT_SEQ. +82. IO: device address set/show updated/displayed wrong field in single unit devices. +83. CPU: address calculation for MTx in interrupt location used incorrect length. +84. LPT: print, format opcode definitions inverted. +85. LPT: wrong index used to count buffer fill loop. +86. IO: CPU/IOP communications through 20/21 were not modelled. +87. CIS: Multiply algorithm incorrect, multiply restart not modelled. +88. CIS: Divide algorithm incorrect, divide restart not modelled. +89. IO: WD .44 not recognized as effective NOP. +90. CPU: Sigma 5 (uniquely) does not implement CVA or CVS. +91. IO: AIO merging status incorrectly. +92. IO: system for returning status byte from IO was muddled; rewrite required. +93. RAD: 7232 track shift offset was incorrectly defined. +94. CPU: MTX for interrupts returned wrong value. +95. CPU: Counter overflow trigger equation was incorrect. +96. CPU: MTX interrupts not recalculating interrupt summary values. +97. RTC: SET/SHOW C1-C4 routines were broken. +98. DP: comparison for sector field overflow was incorrect. +99. DP: cross-cylinder incorrectly set on read to end of cylinder. +100. DP: seek never executed. +101. DP: seek followon state codes set incorrectly. +102. DP: cylinder offset defined incorrectly. +103. DP: SIO not initing unit thread properly for non-zero units. +104. MUX: Line enable must be remembered for lines that are not currently connected. +105. RAD: write check was reading words off disk instead of bytes. +106. RAD: end of transfer routine checking for address error incorrectly. +107. DK: end of transfer routine checking for address error incorrectly. + + +Diagnostic Notes +---------------- + +1. PATTERN paper tape (SA = 60, end pass = 1AC), SET CPU RBLKS=32. + Break at 60 is triggered once during loading process. +2. VERIFY paper tape (SA = 140, end pass = 8E6). +3. AUTO paper tape (SA = 105), SET CPU LASLMS to suppress spurious error message. + AUTO magtape runs correctly with no messages. +4. SUFFIX magtape (SA = 100, end pass = 115), no printouts. +5. FLOAT magtape. +6. DECIMAL paper tape (SA = EE). +7. PROTECT paper tape (SA = F9), long runtime until printout. +8. MAP paper tape (SA = 7C). +9. MEDIC paper tape (SA = 68), set SSW2 after breakpoint, long runtime. +10. INT magtape, stops after M6, set SSW2 and continue, + enters pattern generator and loops forever, as expected. +11. RTC paper tape, clocks must be 500Mhz, reports clocks as "too slow" due + to faster simulation speed. + Runs correctly with SET THROTTLE 500K. + + + + + + + + + + + + + + + diff --git a/sigma/sigma_cis.c b/sigma/sigma_cis.c new file mode 100644 index 00000000..3205ac05 --- /dev/null +++ b/sigma/sigma_cis.c @@ -0,0 +1,990 @@ +/* sigma_cis.c: Sigma decimal instructions + + Copyright (c) 2007-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. + + Questions: + + 1. On the Sigma 9, in ASCII mode, is an ASCII blank used in EBS? +*/ + +#include "sigma_defs.h" + +/* Decimal string structure */ + +#define DSTRLNT 4 /* words per dec string */ +#define DECA 12 /* first dec accum reg */ + +/* Standard characters */ + +#define ZONE_E 0xF0 /* EBCDIC zone bits */ +#define ZONE_A 0x30 /* ASCII zone bits */ +#define ZONE ((PSW1 & PSW1_AS)? ZONE_A: ZONE_E) +#define PKPLUS_E 0xC /* EBCDIC preferred plus */ +#define PKPLUS_A 0xA /* ASCII preferred plus */ +#define PKPLUS ((PSW1 & PSW1_AS)? PKPLUS_A: PKPLUS_E) +#define BLANK_E 0x40 /* EBCDIC blank */ +#define BLANK_A 0x20 /* ASCII blank */ +#define BLANK ((PSW1 & PSW1_AS)? BLANK_A: BLANK_E) + +/* Edit special characters */ + +#define ED_DS 0x20 /* digit select */ +#define ED_SS 0x21 /* start significance */ +#define ED_FS 0x22 /* field separator */ +#define ED_SI 0x23 /* immediate significance */ + +/* Decimal strings run low order (word 0/R15) to high order (word 3/R12) */ + +typedef struct { + uint32 sign; + uint32 val[DSTRLNT]; + } dstr_t; + +/* Copy decimal accumulator to decimal string, no validation or sign separation */ + +#define ReadDecA(src) for (i = 0; i < DSTRLNT; i++) \ + src.val[DSTRLNT - 1 - i] = R[DECA + i]; + +static dstr_t Dstr_zero = { 0, 0, 0, 0, 0 }; + +extern uint32 *R; +extern uint32 CC; +extern uint32 PSW1; +extern uint32 bvamqrx; +extern uint32 cpu_model; + +uint32 ReadDstr (uint32 lnt, uint32 addr, dstr_t *dec); +uint32 WriteDstr (uint32 lnt, uint32 addr, dstr_t *dec); +void WriteDecA (dstr_t *dec, t_bool cln); +void SetCC2Dstr (uint32 lnt, dstr_t *dst); +uint32 TestDstrValid (dstr_t *src); +uint32 DstrInvd (void); +uint32 AddDstr (dstr_t *src1, dstr_t *src2, dstr_t *dst, uint32 cin); +void SubDstr (dstr_t *src1, dstr_t *src2, dstr_t *dst); +int32 CmpDstr (dstr_t *src1, dstr_t *src2); +uint32 LntDstr (dstr_t *dsrc); +uint32 NibbleLshift (dstr_t *dsrc, uint32 sc, uint32 cin); +uint32 NibbleRshift (dstr_t *dsrc, uint32 sc, uint32 cin); +t_bool GenLshift (dstr_t *dsrc, uint32 sc); +void GenRshift (dstr_t *dsrc, uint32 sc); +uint32 ed_getsrc (uint32 sa, uint32 *c, uint32 *d); +void ed_advsrc (uint32 rn, uint32 c); +t_bool cis_test_int (dstr_t *src1, uint32 *kint); +void cis_dm_int (dstr_t *src, dstr_t *dst, uint32 kint); +void cis_dd_int (dstr_t *src, dstr_t *dst, uint32 t, uint32 *kint); + +/* Decimal instructions */ + +uint32 cis_dec (uint32 op, uint32 lnt, uint32 bva) +{ +dstr_t src1, src2, src2x, dst; +uint32 i, t, kint, ldivr, ldivd, ad, c, d, end; +int32 sc; +uint32 tr; + +if (lnt == 0) /* adjust length */ + lnt = 16; +CC &= ~(CC1|CC2); /* clear CC1, CC2 */ + +switch (op) { /* case on opcode */ + + case OP_DL: /* decimal load */ + if ((tr = ReadDstr (lnt, bva, &dst)) != 0) /* read mem string */ + return tr; + WriteDecA (&dst, FALSE); /* store result */ + break; + + case OP_DST: /* decimal store */ + ReadDecA (dst); /* read dec accum */ + if ((tr = TestDstrValid (&dst)) != 0) /* valid? */ + return tr; + if ((tr = WriteDstr (lnt, bva, &dst)) != 0) /* write to mem */ + return tr; + break; + + case OP_DS: /* decimal subtract */ + case OP_DA: /* decimal add */ + ReadDecA (src1); /* read dec accum */ + if ((tr = TestDstrValid (&src1)) != 0) /* valid? */ + return tr; + if ((tr = ReadDstr (lnt, bva, &src2)) != 0) /* read mem string */ + return tr; + if (op == OP_DS) /* sub? invert sign */ + src2.sign = src2.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 */ + } + } + else { /* addition */ + if (AddDstr (&src1, &src2, &dst, 0)) { /* add, overflow? */ + CC |= CC2; /* set CC2 */ + return (PSW1 & PSW1_DM)? TR_DEC: 0; /* trap if enabled */ + } + dst.sign = src1.sign; /* set result sign */ + } + WriteDecA (&dst, TRUE); /* store result */ + break; + + case OP_DC: /* decimal compare */ + ReadDecA ( src1); /* read dec accum */ + if ((tr = TestDstrValid (&src1)) != 0) /* valid? */ + return tr; + if ((tr = ReadDstr (lnt, bva, &src2)) != 0) /* read mem string */ + return tr; + LntDstr (&src1); /* clean -0 */ + LntDstr (&src2); + if (src1.sign ^ src2.sign) /* signs differ? */ + CC = src1.sign? CC4: CC3; /* set < or > */ + else { /* same signs */ + t = CmpDstr (&src1, &src2); /* compare strings */ + if (t < 0) + CC = (src1.sign? CC3: CC4); + else if (t > 0) + CC = (src1.sign? CC4: CC3); + else CC = 0; + } + break; + +/* Decimal multiply - algorithm from George Plue. + + The Sigma does decimal multiply one digit at a time, using the multiplicand + and a doubled copy of the multiplicand. Multiplying by digits 1-5 is + synthesized by 1-3 adds; multiplying by digits 6-9 is synthesized by 1-2 + subtractions, and adding 1 to the next multiplier digit. (That is, + multiplying by 7 is done by multiplying by "10 - 3".) This requires at + most one extra add to fixup the last digit, and minimizes the overall + number of adds (average 1.5 adds per multiplier digit). Note that + multiplication proceeds from right to left. + + The Sigma 5-9 allowed decimal multiply to be interrupted; the 5X0 series + did not. An interrupted multiply uses a sign digit in R12 and R13 as the + divider between the remaining multiplier (to the left of the sign, and + in the low-order digit of R15) and the partial product (to the right of + the sign). Because the partial product may be negative, leading 0x99's + may have been stripped and need to be restored. + + The real Sigma's probably didn't run a validty test after separation of + the partial product and multiplier, but it doesn't hurt, and prevents + certain corner cases from causing errors. */ + + case OP_DM: /* decimal multiply */ + if (lnt >= 9) /* invalid length? */ + return DstrInvd (); + ReadDecA (src1); /* get dec accum */ + if ((tr = ReadDstr (lnt, bva, &src2)) != 0) /* read mem string */ + return tr; + dst = Dstr_zero; /* clear result */ + kint = 0; /* assume no int */ + if (!QCPU_5X0 && /* S5-9? */ + (cis_test_int (&src1, &kint))) /* interrupted? */ + cis_dm_int (&src1, &dst, kint); /* restore */ + else if ((tr = TestDstrValid (&src1)) != 0) /* mpyr valid? */ + return tr; + if (LntDstr (&src1) && LntDstr (&src2)) { /* both opnds != 0? */ + dst.sign = src1.sign ^ src2.sign; /* sign of result */ + AddDstr (&src2, &src2, &src2x, 0); /* get 2*mplcnd */ + for (i = 1; i <= 16; i++) { /* 16 iterations */ + if (i >= kint) { /* past int point? */ + NibbleRshift (&src1, 1, 0); /* mpyr right 4 */ + d = src1.val[0] & 0xF; /* get digit */ + switch (d) { /* case */ + case 5: /* + 2 + 2 + 1 */ + AddDstr (&src2x, &dst, &dst, 0); + case 3: /* + 2 + 1 */ + AddDstr (&src2x, &dst, &dst, 0); + case 1: /* + 1 */ + AddDstr (&src2, &dst, &dst, 0); + case 0: + break; + case 4: /* + 2 + 2 */ + AddDstr (&src2x, &dst, &dst, 0); + case 2: /* + 2 */ + AddDstr (&src2x, &dst, &dst, 0); + break; + case 6: /* - 2 - 2 + 10 */ + SubDstr (&src2x, &dst, &dst); + case 8: /* - 2 + 10 */ + SubDstr (&src2x, &dst, &dst); + src1.val[0] += 0x10; /* + 10 */ + break; + case 7: /* -2 - 1 + 10 */ + SubDstr (&src2x, &dst, &dst); + case 9: /* -1 + 10 */ + SubDstr (&src2, &dst, &dst); + default: /* + 10 */ + src1.val[0] += 0x10; + } /* end switch */ + } /* end if >= kint */ + NibbleLshift (&src2, 1, 0); /* shift mplcnds */ + NibbleLshift (&src2x, 1, 0); + } /* end for */ + } /* end if != 0 */ + WriteDecA (&dst, TRUE); /* store result */ + break; + +/* Decimal divide overflow calculation - if the dividend has true length d, + and the divisor true length r, then the quotient will have (d - r) or + (d - r + 1) digits. Therefore, if (d - r) > 15, the quotient will not + fit. However, if (d - r) == 15, it may or may not fit, depending on + whether the first subtract succeeds. Therefore, it's necessary to test + after the divide to see if the quotient has one extra digit. */ + + case OP_DD: /* decimal divide */ + if (lnt >= 9) /* invalid length? */ + return DstrInvd (); + ReadDecA (src1); /* read dec accum */ + if ((tr = ReadDstr (lnt, bva, &src2)) != 0) /* read mem string */ + return tr; + dst = Dstr_zero; /* clear result */ + kint = 0; /* no interrupt */ + if (!QCPU_5X0 && /* S5-9? */ + (cis_test_int (&src1, &t))) { /* interrupted? */ + cis_dd_int (&src1, &dst, t, &kint); /* restore */ + t = t - 1; + } + else { /* normal start? */ + if ((tr = TestDstrValid (&src1)) != 0) /* divd valid? */ + return tr; + ldivr = LntDstr (&src2); /* divr lnt */ + ldivd = LntDstr (&src1); /* divd lnt */ + if ((ldivr == 0) || /* div by zero? */ + (ldivd > (ldivr + 15))) { /* quo too big? */ + CC |= CC2; /* divide check */ + return (PSW1 & PSW1_DM)? TR_DEC: 0; /* trap if enabled */ + } + if (CmpDstr (&src1, &src2) < 0) { /* no divide? */ + R[12] = src1.val[1]; /* remainder */ + R[13] = src1.val[0] | (PKPLUS + src1.sign); + R[14] = 0; /* quotient */ + R[15] = PKPLUS; + CC = 0; + return SCPE_OK; + } + t = ldivd - ldivr; + } + dst.sign = src1.sign ^ src2.sign; /* calculate sign */ + GenLshift (&src2, t); /* align */ + for (i = 0; i <= t; i++) { /* divide loop */ + for (d = kint; /* find digit */ + (d < 10) && (CmpDstr (&src1, &src2) >= 0); + d++) + SubDstr (&src2, &src1, &src1); + dst.val[0] = (dst.val[0] & ~0xF) | d; /* insert quo dig */ + NibbleLshift (&dst, 1, 0); /* shift quotient */ + NibbleRshift (&src2, 1, 0); /* shift divisor */ + kint = 0; /* no more int */ + } /* end divide loop */ + if (dst.val[2]) { /* quotient too big? */ + CC |= CC2; /* divide check */ + return (PSW1 & PSW1_DM)? TR_DEC: 0; /* trap if enabled */ + } + CC = dst.sign? CC4: CC3; /* set CC's */ + R[12] = src1.val[1]; /* remainder */ + R[13] = src1.val[0] | (PKPLUS + src1.sign); + R[14] = dst.val[1]; /* quotient */ + R[15] = dst.val[0] | (PKPLUS + dst.sign); + break; + + case OP_DSA: /* decimal shift */ + ReadDecA (dst); /* read dec accum */ + if ((tr = TestDstrValid (&dst)) != 0) /* valid? */ + return tr; + CC = 0; /* clear CC's */ + sc = SEXT_H_W (bva >> 2); /* shift count */ + if (sc > 31) /* sc in [-31,31] */ + sc = 31; + if (sc < -31) + sc = -31; + if (sc < 0) { /* right shift? */ + sc = -sc; /* |shift| */ + GenRshift (&dst, sc); /* do shift */ + dst.val[0] = dst.val[0] & ~0xF; /* clear sign */ + } /* end right shift */ + else if (sc) { /* left shift? */ + if (GenLshift (&dst, sc)) /* do shift */ + CC |= CC2; + } /* end left shift */ + WriteDecA (&dst, FALSE); /* store result */ + break; + + case OP_PACK: /* zoned to packed */ + dst = Dstr_zero; /* clear result */ + end = (2 * lnt) - 1; /* zoned length */ + for (i = 1; i <= end; i++) { /* loop thru char */ + ad = (bva + end - i) & bvamqrx; /* zoned character */ + if ((tr = ReadB (ad, &c, VR)) != 0) /* read char */ + return tr; + if (i == 1) { /* sign + digit? */ + uint32 s; + s = (c >> 4) & 0xF; /* get sign */ + if (s < 0xA) + return DstrInvd (); + if ((s == 0xB) || (s == 0xD)) /* negative */ + dst.sign = 1; + } + d = c & 0xF; /* get digit */ + if (d > 0x9) + return DstrInvd (); + dst.val[i / 8] = dst.val[i / 8] | (d << ((i % 8) * 4)); + } + WriteDecA (&dst, FALSE); /* write result */ + break; + + case OP_UNPK: /* packed to zoned */ + ReadDecA (dst); /* read dec accum */ + if ((tr = TestDstrValid (&dst)) != 0) /* valid? */ + return tr; + end = (2 * lnt) - 1; /* zoned length */ + if ((tr = ReadB (bva, &c, VW)) != 0) /* prove writeable */ + return tr; + for (i = 1; i <= end; i++) { /* loop thru chars */ + c = (dst.val[i / 8] >> ((i % 8) * 4)) & 0xF; /* get digit */ + if (i == 1) /* first? */ + c |= ((PKPLUS + dst.sign) << 4); /* or in sign */ + else c |= ZONE; /* no, or in zone */ + ad = (bva + end - i) & bvamqrx; + if ((tr = WriteB (ad, c, VW)) != 0) /* write to memory */ + return tr; + } + SetCC2Dstr (lnt, &dst); /* see if too long */ + break; + } +return 0; +} + +/* Test for interrupted multiply or divide */ + +t_bool cis_test_int (dstr_t *src, uint32 *kint) +{ +int32 i; +uint32 wd, sc, d; + +for (i = 15; i >= 1; i--) { /* test 15 nibbles */ + wd = (DSTRLNT/2) + (i / 8); + sc = (i % 8) * 4; + d = (src->val[wd] >> sc) & 0xF; + if (d >= 0xA) { + *kint = (uint32) i; + return TRUE; + } + } +return FALSE; +} + +/* Resume interrupted multiply + + The sign that was found is the "fence" between the the remaining multiplier + and the partial product: + R val + +--+--+--+--+--+--+--+--+ + | mpyer |sn|pp| 12 3 + +--+--+--+--+--+--+--+--+ + | partial product | 13 2 + +--+--+--+--+--+--+--+--+ + | partial product | 14 1 + +--+--+--+--+--+--+--+--+ + | partial product |mp| 15 0 + +--+--+--+--+--+--+--+--+ + + This routine separates the multiplier and partial product, returns the + multiplier as a valid decimal string in src, and the partial product + as a value with no sign in dst */ + +void cis_dm_int (dstr_t *src, dstr_t *dst, uint32 kint) +{ +uint32 ppneg, wd, sc, d, curd; +int32 k; + +*dst = *src; /* copy input */ +wd = (DSTRLNT/2) + (kint / 8); +sc = (kint % 8) * 4; +d = (src->val[wd] >> sc) & 0xF; /* get sign fence */ +ppneg = ((d >> 2) & 1) ^ 1; /* partial prod neg? */ +curd = (src->val[0] & 0xF) + ppneg; /* bias cur digit */ +src->val[wd] = (src->val[wd] & ~(0xF << sc)) | /* replace sign */ + (curd << sc); /* with digit */ +GenRshift (src, kint + 15); /* right justify */ +src->sign = ((d == 0xB) || (d == 0xD))? 1: 0; /* set mpyr sign */ +src->val[0] = src->val[0] & ~0xF; /* clear sign pos */ + +/* Mask out multiplier */ + +for (k = DSTRLNT - 1; k >= (int32) wd; k--) /* words hi to lo */ + dst->val[k] &= ~(0xFFFFFFFFu << + ((k > (int32) wd)? 0: sc)); + +/* Recreate missing high order digits for negative partial product */ + +if (ppneg) { /* negative? */ + for (k = (DSTRLNT * 4) - 1; k != 0; k--) { /* bytes hi to lo */ + wd = k / 4; + sc = (k % 4) * 8; + if (((dst->val[wd] >> sc) & 0xFF) != 0) + break; + dst->val[wd] |= (0x99 << sc); /* repl 00 with 99 */ + } /* end for */ + } +dst->val[0] &= ~0xF; /* clear pp sign */ +return; +} + +/* Resume interrupted divide + + The sign that was found is the "fence" between the the quotient and the + remaining dividend product: + R val + +--+--+--+--+--+--+--+--+ + | quotient |sn|dv| 12 3 + +--+--+--+--+--+--+--+--+ + | dividend | 13 2 + +--+--+--+--+--+--+--+--+ + | dividend | 14 1 + +--+--+--+--+--+--+--+--+ + | dividend |qu| 15 0 + +--+--+--+--+--+--+--+--+ + + This routine separates the quotient and the remaining dividend, returns + the dividend as a valid decimal string, the quotient as a decimal string + without sign, and kint is the partial value of the last quotient digit. */ + +void cis_dd_int (dstr_t *src, dstr_t *dst, uint32 nib, uint32 *kint) +{ +uint32 wd, sc, d, curd; +int32 k; + +wd = (DSTRLNT/2) + (nib / 8); +sc = (nib % 8) * 4; +curd = src->val[0] & 0xF; /* last quo digit */ +*dst = *src; /* copy input */ +GenRshift (dst, nib + 16); /* right justify quo */ +d = dst->val[0] & 0xF; /* get sign fence */ +dst->val[0] = (dst->val[0] & ~0xF) | curd; /* repl with digit */ +*kint = curd; + +/* Mask out quotient */ + +for (k = DSTRLNT - 1; k >= (int32) wd; k--) /* words hi to lo */ + src->val[k] &= ~(0xFFFFFFFFu << + ((k > (int32) wd)? 0: sc)); +src->sign = ((d == 0xB) || (d == 0xD))? 1: 0; /* set divd sign */ +src->val[0] = src->val[0] & ~0xF; /* clr sign digit */ +return; +} + +/* Get packed decimal string from memory + + Arguments: + lnt = decimal string length + adr = decimal string address + src = decimal string structure + Output: + trap or abort signal + + Per the Sigma spec, bad digits or signs cause a fault or abort */ + +uint32 ReadDstr (uint32 lnt, uint32 adr, dstr_t *src) +{ +uint32 i, c, bva; +uint32 tr; + +*src = Dstr_zero; /* clear result */ +for (i = 0; i < lnt; i++) { /* loop thru string */ + bva = (adr + lnt - i - 1) & bvamqrx; /* from low to high */ + if ((tr = ReadB (bva, &c, VR)) != 0) /* read byte */ + return tr; + src->val[i / 4] = src->val[i / 4] | (c << ((i % 4) * 8)); + } /* end for */ +return TestDstrValid (src); +} + +/* Separate sign, validate sign and digits of decimal string */ + +uint32 TestDstrValid (dstr_t *src) +{ +uint32 i, j, s, t; + +s = src->val[0] & 0xF; /* get sign */ +if (s < 0xA) /* valid? */ + return DstrInvd (); +if ((s == 0xB) || (s == 0xD)) /* negative? */ + src->sign = 1; +else src->sign = 0; +src->val[0] &= ~0xF; /* clear sign */ + +for (i = 0; i < DSTRLNT; i++) { /* check 4 words */ + for (j = 0; j < 8; j++) { /* 8 digit/word */ + t = (src->val[i] >> (28 - (j * 4))) & 0xF; /* get digit */ + if (t > 0x9) /* invalid digit? */ + return DstrInvd (); /* exception */ + } + } +return 0; +} + +/* Invalid digit or sign: set CC1, trap or abort instruction */ + +uint32 DstrInvd (void) +{ +CC |= CC1; /* set CC1 */ +if (PSW1 & PSW1_DM) /* if enabled, trap */ + return TR_DEC; +return WSIGN; /* otherwise, abort */ +} + +/* Store decimal string + + Arguments: + lnt = decimal string length + adr = decimal string address + dst = decimal string structure + + Returns memory management traps (if any) + Bad digits and invalid sign are impossible +*/ + +uint32 WriteDstr (uint32 lnt, uint32 adr, dstr_t *dst) +{ +uint32 i, bva, c; +uint32 tr; + +dst->val[0] = dst->val[0] | (PKPLUS + dst->sign); /* set sign */ +if ((tr = ReadB (adr, &c, VW)) != 0) /* prove writeable */ + return tr; +for (i = 0; i < lnt; i++) { /* loop thru bytes */ + c = (dst->val[i / 4] >> ((i % 4) * 8)) & 0xFF; /* from low to high */ + bva = (adr + lnt - i - 1) & bvamqrx; + if ((tr = WriteB (bva, c, VW)) != 0) /* store byte */ + return tr; + } /* end for */ +SetCC2Dstr (lnt, dst); /* check overflow */ +return 0; +} + +/* Store result in decimal accumulator + + Arguments: + dst = decimal string structure + cln = clean -0 if true + + Sets condition codes CC3 and CC4 + Bad digits and invalid sign are impossible */ + +void WriteDecA (dstr_t *dst, t_bool cln) +{ +uint32 i, nz; + +CC &= ~(CC3|CC4); /* assume zero */ +for (i = 0, nz = 0; i < DSTRLNT; i++) { /* save 32 digits */ + R[DECA + i] = dst->val[DSTRLNT - 1 - i]; + nz |= dst->val[DSTRLNT - 1 - i]; + } +if (nz) /* non-zero? */ + CC |= (dst->sign)? CC4: CC3; /* set CC3 or CC4 */ +else if (cln) /* zero, clean? */ + dst->sign = 0; /* clear sign */ +R[DECA + DSTRLNT - 1] |= (PKPLUS + dst->sign); /* or in sign */ +return; +} + +/* Set CC2 for decimal string store + + Arguments: + lnt = string length + dst = decimal string structure + Output: + sets CC2 if information won't fit */ + +void SetCC2Dstr (uint32 lnt, dstr_t *dst) +{ +uint32 i, limit, mask; +static uint32 masktab[8] = { + 0xFFFFFFF0, 0xFFFFFF00, 0xFFFFF000, 0xFFFF0000, + 0xFFF00000, 0xFF000000, 0xF0000000, 0x00000000 + }; + +lnt = (lnt * 2) - 1; /* number of digits */ +mask = 0; /* can't ovflo */ +limit = lnt / 8; /* limit for test */ +for (i = 0; i < DSTRLNT; i++) { /* loop thru value */ + if (i == limit) /* @limit, get mask */ + mask = masktab[lnt % 8]; + else if (i > limit) /* >limit, test all */ + mask = 0xFFFFFFFF; + if (dst->val[i] & mask) /* test for ovflo */ + CC |= CC2; + } +return; +} + +/* Add decimal string magnitudes + + Arguments: + s1 = src1 decimal string + s2 = src2 decimal string + ds = dest 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). +*/ + +uint32 AddDstr (dstr_t *s1, dstr_t *s2, dstr_t *ds, uint32 cy) +{ +uint32 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 ovflo */ + tm2 = tm1 ^ sm2; /* get carry flags */ + tm3 = (tm2 >> 3) | (cy << 29); /* compute adjust */ + tm4 = 0x22222222 & ~tm3; /* clrr where carry */ + ds->val[i] = (sm2 - (3 * tm4)) & WMASK; /* final result */ + } +return cy; +} + +/* Subtract decimal string magnitudes + + Arguments: + s1 = src1 decimal string + s2 = src2 decimal string + ds = dest decimal string + + Note: the routine assumes that s1 <= s2 + +*/ + +void SubDstr (dstr_t *s1, dstr_t *s2, dstr_t *ds) +{ +uint32 i; +dstr_t compl; + +for (i = 0; i < DSTRLNT; i++) /* 9's comp s2 */ + compl.val[i] = 0x99999999 - s1->val[i]; +AddDstr (&compl, s2, ds, 1); /* s1 + ~s2 + 1 */ +return; +} + +/* Compare decimal string magnitudes + + Arguments: + s1 = src1 decimal string + s2 = src2 decimal string + Output: + 1 if >, 0 if =, -1 if < +*/ + +int32 CmpDstr (dstr_t *s1, dstr_t *s2) +{ +int32 i; + +for (i = DSTRLNT - 1; i >=0; i--) { + if (s1->val[i] > s2->val[i]) + return 1; + if (s1->val[i] < s2->val[i]) + return -1; + } +return 0; +} + +/* Get exact length of decimal string, clean -0 + + Arguments: + dst = decimal string structure + Output: + number of non-zero digits +*/ + +uint32 LntDstr (dstr_t *dst) +{ +int32 nz, i; + +for (nz = DSTRLNT - 1; nz >= 0; nz--) { + if (dst->val[nz]) { + for (i = 7; i >= 0; i--) { + if ((dst->val[nz] >> (i * 4)) & 0xF) + return (nz * 8) + i; + } + } + } +dst->sign = 0; +return 0; +} + +/* Word shift right + + Arguments: + dsrc = decimal string structure + sc = shift count in nibbles +*/ + +void GenRshift (dstr_t *dsrc, uint32 cnt) +{ +uint32 i, sc, sc1; + +sc = cnt / 8; +sc1 = cnt % 8; +if (sc) { + for (i = 0; i < DSTRLNT; i++) { + if ((i + sc) < DSTRLNT) + dsrc->val[i] = dsrc->val[i + sc]; + else dsrc->val[i] = 0; + } + } +if (sc1) + NibbleRshift (dsrc, sc1, 0); +return; +} + +/* General shift left + + Arguments: + dsrc = decimal string structure + cnt = shift count in nibbles +*/ + +t_bool GenLshift (dstr_t *dsrc, uint32 cnt) +{ +t_bool i, c, sc, sc1; + +c = 0; +sc = cnt / 8; +sc1 = cnt % 8; +if (sc) { + for (i = DSTRLNT - 1; (int32) i >= 0; i--) { + if (i >= sc) + dsrc->val[i] = dsrc->val[i - sc]; + else { + c |= dsrc->val[i]; + dsrc->val[i] = 0; + } + } + } +if (sc1) + c |= NibbleLshift (dsrc, sc1, 0); +return (c? TRUE: FALSE); +} + +/* Nibble shift right + + Arguments: + dsrc = decimal string structure + sc = shift count in nibbles + cin = carry in +*/ + +uint32 NibbleRshift (dstr_t *dsrc, uint32 sc, uint32 cin) +{ +int32 i; +uint32 s, nc; + +if (s = sc * 4) { + for (i = DSTRLNT - 1; (int32) i >= 0; i--) { + nc = (dsrc->val[i] << (32 - s)) & WMASK; + dsrc->val[i] = ((dsrc->val[i] >> s) | + cin) & WMASK; + cin = nc; + } + return cin; + } +return 0; +} + +/* Nibble shift left + + Arguments: + dsrc = decimal string structure + sc = shift count in nibbles + cin = carry in +*/ + +uint32 NibbleLshift (dstr_t *dsrc, uint32 sc, uint32 cin) +{ +uint32 i, s, nc; + +if (s = sc * 4) { + for (i = 0; i < DSTRLNT; i++) { + nc = dsrc->val[i] >> (32 - s); + dsrc->val[i] = ((dsrc->val[i] << s) | + cin) & WMASK; + cin = nc; + } + return cin; + } +return 0; +} +/* Edit instruction */ + +uint32 cis_ebs (uint32 rn, uint32 disp) +{ +uint32 sa, da, c, d, dst, fill, pat; +uint32 tr; + +disp = SEXT_LIT_W (disp) & WMASK; /* sext operand */ +fill = S_GETMCNT (R[rn]); /* fill char */ +while (S_GETMCNT (R[rn|1])) { /* while pattern */ + sa = (disp + R[rn]) & bvamqrx; /* dec str addr */ + da = R[rn|1] & bvamqrx; /* pattern addr */ + if ((tr = ReadB (da, &pat, VR)) != 0) /* get pattern byte */ + return tr; + switch (pat) { /* case on pattern */ + + case ED_DS: /* digit select */ + if ((tr = ed_getsrc (sa, &c, &d)) != 0) /* get src digit */ + return tr; + if (CC & CC4) /* signif? unpack */ + dst = ZONE | d; + else if (d) { /* non-zero? */ + R[1] = da; /* save addr */ + dst = ZONE | d; /* unpack */ + CC |= CC4; /* set signif */ + } + else dst = fill; /* otherwise fill */ + if ((tr = WriteB (da, dst, VW)) != 0) /* overwrite dst */ + return tr; + ed_advsrc (rn, c); /* next src digit */ + break; + + case ED_SS: /* signif start */ + if ((tr = ed_getsrc (sa, &c, &d)) != 0) /* get src digit */ + return tr; + if (CC & CC4) /* signif? unpack */ + dst = ZONE | d; + else if (d) { /* non-zero? */ + R[1] = da; /* save addr */ + dst = ZONE | d; /* unpack */ + } + else { /* otherwise */ + R[1] = da + 1; /* save next */ + dst = fill; /* fill */ + } + CC |= CC4; /* set signif */ + if ((tr = WriteB (da, dst, VW)) != 0) /* overwrite dst */ + return tr; + ed_advsrc (rn, c); /* next src digit */ + break; + + case ED_SI: /* signif immediate */ + if ((tr = ed_getsrc (sa, &c, &d)) != 0) /* get src digit */ + return tr; + R[1] = da; /* save addr */ + dst = ZONE | d; /* unpack */ + CC |= CC4; /* set signif */ + if ((tr = WriteB (da, dst, VW)) != 0) /* overwrite dst */ + return tr; + ed_advsrc (rn, c); /* next src digit */ + break; + + case ED_FS: /* field separator */ + CC &= ~(CC1|CC3|CC4); /* clr all exc CC2 */ + if ((tr = WriteB (da, fill, VW)) != 0) /* overwrite dst */ + return tr; + break; + + default: /* all others */ + if ((CC & CC4) == 0) { /* signif off? */ + dst = (CC & CC1)? BLANK: fill; /* blank or fill */ + if ((tr = WriteB (da, dst, VW)) != 0) /* overwrite dst */ + return tr; + } + break; + } /* end switch dst */ + R[rn|1] = (R[rn|1] + S_ADDRINC) & WMASK; /* next pattern */ + } /* end while */ +return 0; +} + +/* Routine to get and validate the next source digit */ + +uint32 ed_getsrc (uint32 sa, uint32 *c, uint32 *d) +{ +uint32 tr; + +if ((tr = ReadB (sa, c, VR)) != 0) /* read source byte */ + return tr; +*d = ((CC & CC2)? *c: *c >> 4) & 0xF; /* isolate digit */ +if (*d > 0x9) /* invalid? */ + return TR_DEC; +if (*d) /* non-zero? */ + CC |= CC3; +return 0; +} + +/* Routine to advance source string */ + +void ed_advsrc (uint32 rn, uint32 c) +{ +c = c & 0xF; /* get low digit */ +if (((CC & CC2) == 0) && (c > 0x9)) { /* sel left, with sign? */ + if ((c == 0xB) || (c == 0xD)) /* minus? */ + CC = CC | (CC1|CC4); /* CC1, CC4 */ + else CC = (CC | CC1) & ~CC4; /* no, CC1, ~CC4 */ + R[rn] = R[rn] + 1; /* skip two digits */ + } +else { /* adv 1 digit */ + if (CC & CC2) + R[rn] = R[rn] + 1; + CC = CC ^ CC2; + } +return; +} diff --git a/sigma/sigma_coc.c b/sigma/sigma_coc.c new file mode 100644 index 00000000..d7af5c9b --- /dev/null +++ b/sigma/sigma_coc.c @@ -0,0 +1,620 @@ +/* sigma_coc.c: Sigma character-oriented communications subsystem simulator + + Copyright (c) 2007-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 substanXIAl 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. + + coc 7611 communications multiplexor + +*/ + +#include "sigma_io_defs.h" +#include "sim_sock.h" +#include "sim_tmxr.h" +#include + +/* Constants */ + +#define MUX_LINES 64 /* max lines */ +#define MUX_LINES_DFLT 8 /* default lines */ +#define MUX_INIT_POLL 8000 +#define MUXL_WAIT 500 +#define MUX_NUMLIN mux_desc.lines /* curr # lines */ + +#define MUXC 0 /* channel thread */ +#define MUXI 1 /* input thread */ + +/* Line status */ + +#define MUXL_XIA 0x01 /* xmt intr armed */ +#define MUXL_XIR 0x02 /* xmt intr req */ +#define MUXL_REP 0x04 /* rcv enable pend */ +#define MUXL_RBP 0x10 /* rcv break pend */ + +/* Channel state */ + +#define MUXC_IDLE 0 /* idle */ +#define MUXC_INIT 1 /* init */ +#define MUXC_RCV 2 /* receive */ +#define MUXC_END 3 /* end */ + +/* DIO address */ + +#define MUXDIO_V_FNC 0 /* function */ +#define MUXDIO_M_FNC 0xF +#define MUXDIO_V_COC 4 /* ctlr num */ +#define MUXDIO_M_COC 0xF +#define MUXDIO_GETFNC(x) (((x) >> MUXDIO_V_FNC) & MUXDIO_M_FNC) +#define MUXDIO_GETCOC(x) (((x) >> MUXDIO_V_COC) & MUXDIO_M_COC) + +#define MUXDAT_V_LIN 0 /* line num */ +#define MUXDAT_M_LIN (MUX_LINES - 1) +#define MUXDAT_V_CHR 8 /* output char */ +#define MUXDAT_M_CHR 0xFF +#define MUXDAT_GETLIN(x) (((x) >> MUXDAT_V_LIN) & MUXDAT_M_LIN) +#define MUXDAT_GETCHR(x) (((x) >> MUXDAT_V_CHR) & MUXDAT_M_CHR) + +uint8 mux_rbuf[MUX_LINES]; /* rcv buf */ +uint8 mux_xbuf[MUX_LINES]; /* xmt buf */ +uint8 mux_sta[MUX_LINES]; /* status */ +uint32 mux_tps = RTC_HZ_50; /* polls/second */ +uint32 mux_scan = 0; /* scanner */ +uint32 mux_slck = 0; /* scanner locked */ +uint32 muxc_cmd = MUXC_IDLE; /* channel state */ +uint32 mux_rint = INTV (INTG_E2, 0); +uint32 mux_xint = INTV (INTG_E2, 1); + +TMLN mux_ldsc[MUX_LINES] = { 0 }; /* line descrs */ +TMXR mux_desc = { MUX_LINES_DFLT, 0, 0, mux_ldsc }; /* mux descrr */ + +extern uint32 chan_ctl_time; +extern uint32 CC; +extern uint32 *R; + +uint32 mux_disp (uint32 op, uint32 dva, uint32 *dvst); +uint32 mux_dio (uint32 op, uint32 rn, uint32 ad); +uint32 mux_tio_status (void); +t_stat mux_chan_err (uint32 st); +t_stat muxc_svc (UNIT *uptr); +t_stat muxo_svc (UNIT *uptr); +t_stat muxi_rtc_svc (UNIT *uptr); +t_stat mux_reset (DEVICE *dptr); +t_stat mux_attach (UNIT *uptr, char *cptr); +t_stat mux_detach (UNIT *uptr); +t_stat mux_vlines (UNIT *uptr, int32 val, char *cptr, void *desc); +void mux_reset_ln (int32 ln); +void mux_scan_next (t_bool clr); +t_stat muxi_put_char (uint32 c, uint32 ln); + +/* MUX data structures + + mux_dev MUX device descriptor + mux_unit MUX unit descriptor + mux_reg MUX register list + mux_mod MUX modifiers list +*/ + +dib_t mux_dib = { DVA_MUX, &mux_disp, DIO_MUX, &mux_dio }; + +UNIT mux_unit[] = { + { UDATA (&muxc_svc, UNIT_ATTABLE, 0) }, + { UDATA (&muxi_rtc_svc, UNIT_DIS, 0) } + }; + +REG mux_reg[] = { + { BRDATA (STA, mux_sta, 16, 8, MUX_LINES) }, + { BRDATA (RBUF, mux_rbuf, 16, 8, MUX_LINES) }, + { BRDATA (XBUF, mux_xbuf, 16, 8, MUX_LINES) }, + { DRDATA (SCAN, mux_scan, 6) }, + { FLDATA (SLCK, mux_slck, 0) }, + { DRDATA (CMD, muxc_cmd, 2) }, + { DRDATA (TPS, mux_tps, 8), REG_HRO }, + { NULL } + }; + +MTAB mux_mod[] = { + { MTAB_XTD | MTAB_VDV, 1, NULL, "DISCONNECT", + &tmxr_dscln, NULL, &mux_desc }, + { UNIT_ATT, UNIT_ATT, "summary", NULL, + NULL, &tmxr_show_summ, (void *) &mux_desc }, + { MTAB_XTD | MTAB_VDV | MTAB_NMO, 1, "CONNECTIONS", NULL, + NULL, &tmxr_show_cstat, (void *) &mux_desc }, + { MTAB_XTD | MTAB_VDV | MTAB_NMO, 0, "STATISTICS", NULL, + NULL, &tmxr_show_cstat, (void *) &mux_desc }, + { MTAB_XTD|MTAB_VDV, 0, "CHAN", "CHAN", + &io_set_dvc, &io_show_dvc, NULL }, + { MTAB_XTD|MTAB_VDV, 0, "DVA", "DVA", + &io_set_dva, &io_show_dva, NULL }, + { MTAB_XTD | MTAB_VDV, 0, "LINES", "LINES", + &mux_vlines, &tmxr_show_lines, (void *) &mux_desc }, + { MTAB_XTD|MTAB_VDV|MTAB_NMO, 0, "CSTATE", NULL, + NULL, &io_show_cst, NULL }, + { MTAB_XTD|MTAB_VDV|MTAB_NMO, RTC_COC, "POLL", "POLL", + &rtc_set_tps, &rtc_show_tps, (void *) &mux_tps }, + { 0 } + }; + +DEVICE mux_dev = { + "MUX", mux_unit, mux_reg, mux_mod, + 2, 10, 31, 1, 16, 8, + &tmxr_ex, &tmxr_dep, &mux_reset, + NULL, &mux_attach, &mux_detach, + &mux_dib, DEV_NET | DEV_DISABLE + }; + +/* MUXL data structures + + muxl_dev MUXL device descriptor + muxl_unit MUXL unit descriptor + muxl_reg MUXL register list + muxl_mod MUXL modifiers list +*/ + +UNIT muxl_unit[] = { + { UDATA (&muxo_svc, TT_MODE_UC, 0), MUXL_WAIT }, + { UDATA (&muxo_svc, TT_MODE_UC, 0), MUXL_WAIT }, + { UDATA (&muxo_svc, TT_MODE_UC, 0), MUXL_WAIT }, + { UDATA (&muxo_svc, TT_MODE_UC, 0), MUXL_WAIT }, + { UDATA (&muxo_svc, TT_MODE_UC, 0), MUXL_WAIT }, + { UDATA (&muxo_svc, TT_MODE_UC, 0), MUXL_WAIT }, + { UDATA (&muxo_svc, TT_MODE_UC, 0), MUXL_WAIT }, + { UDATA (&muxo_svc, TT_MODE_UC, 0), MUXL_WAIT }, + { UDATA (&muxo_svc, TT_MODE_UC|UNIT_DIS, 0), MUXL_WAIT }, + { UDATA (&muxo_svc, TT_MODE_UC|UNIT_DIS, 0), MUXL_WAIT }, + { UDATA (&muxo_svc, TT_MODE_UC|UNIT_DIS, 0), MUXL_WAIT }, + { UDATA (&muxo_svc, TT_MODE_UC|UNIT_DIS, 0), MUXL_WAIT }, + { UDATA (&muxo_svc, TT_MODE_UC|UNIT_DIS, 0), MUXL_WAIT }, + { UDATA (&muxo_svc, TT_MODE_UC|UNIT_DIS, 0), MUXL_WAIT }, + { UDATA (&muxo_svc, TT_MODE_UC|UNIT_DIS, 0), MUXL_WAIT }, + { UDATA (&muxo_svc, TT_MODE_UC|UNIT_DIS, 0), MUXL_WAIT }, + { UDATA (&muxo_svc, TT_MODE_UC|UNIT_DIS, 0), MUXL_WAIT }, + { UDATA (&muxo_svc, TT_MODE_UC|UNIT_DIS, 0), MUXL_WAIT }, + { UDATA (&muxo_svc, TT_MODE_UC|UNIT_DIS, 0), MUXL_WAIT }, + { UDATA (&muxo_svc, TT_MODE_UC|UNIT_DIS, 0), MUXL_WAIT }, + { UDATA (&muxo_svc, TT_MODE_UC|UNIT_DIS, 0), MUXL_WAIT }, + { UDATA (&muxo_svc, TT_MODE_UC|UNIT_DIS, 0), MUXL_WAIT }, + { UDATA (&muxo_svc, TT_MODE_UC|UNIT_DIS, 0), MUXL_WAIT }, + { UDATA (&muxo_svc, TT_MODE_UC|UNIT_DIS, 0), MUXL_WAIT }, + { UDATA (&muxo_svc, TT_MODE_UC|UNIT_DIS, 0), MUXL_WAIT }, + { UDATA (&muxo_svc, TT_MODE_UC|UNIT_DIS, 0), MUXL_WAIT }, + { UDATA (&muxo_svc, TT_MODE_UC|UNIT_DIS, 0), MUXL_WAIT }, + { UDATA (&muxo_svc, TT_MODE_UC|UNIT_DIS, 0), MUXL_WAIT }, + { UDATA (&muxo_svc, TT_MODE_UC|UNIT_DIS, 0), MUXL_WAIT }, + { UDATA (&muxo_svc, TT_MODE_UC|UNIT_DIS, 0), MUXL_WAIT }, + { UDATA (&muxo_svc, TT_MODE_UC|UNIT_DIS, 0), MUXL_WAIT }, + { UDATA (&muxo_svc, TT_MODE_UC|UNIT_DIS, 0), MUXL_WAIT }, + { UDATA (&muxo_svc, TT_MODE_UC|UNIT_DIS, 0), MUXL_WAIT }, + { UDATA (&muxo_svc, TT_MODE_UC|UNIT_DIS, 0), MUXL_WAIT }, + { UDATA (&muxo_svc, TT_MODE_UC|UNIT_DIS, 0), MUXL_WAIT }, + { UDATA (&muxo_svc, TT_MODE_UC|UNIT_DIS, 0), MUXL_WAIT }, + { UDATA (&muxo_svc, TT_MODE_UC|UNIT_DIS, 0), MUXL_WAIT }, + { UDATA (&muxo_svc, TT_MODE_UC|UNIT_DIS, 0), MUXL_WAIT }, + { UDATA (&muxo_svc, TT_MODE_UC|UNIT_DIS, 0), MUXL_WAIT }, + { UDATA (&muxo_svc, TT_MODE_UC|UNIT_DIS, 0), MUXL_WAIT }, + { UDATA (&muxo_svc, TT_MODE_UC|UNIT_DIS, 0), MUXL_WAIT }, + { UDATA (&muxo_svc, TT_MODE_UC|UNIT_DIS, 0), MUXL_WAIT }, + { UDATA (&muxo_svc, TT_MODE_UC|UNIT_DIS, 0), MUXL_WAIT }, + { UDATA (&muxo_svc, TT_MODE_UC|UNIT_DIS, 0), MUXL_WAIT }, + { UDATA (&muxo_svc, TT_MODE_UC|UNIT_DIS, 0), MUXL_WAIT }, + { UDATA (&muxo_svc, TT_MODE_UC|UNIT_DIS, 0), MUXL_WAIT }, + { UDATA (&muxo_svc, TT_MODE_UC|UNIT_DIS, 0), MUXL_WAIT }, + { UDATA (&muxo_svc, TT_MODE_UC|UNIT_DIS, 0), MUXL_WAIT }, + { UDATA (&muxo_svc, TT_MODE_UC|UNIT_DIS, 0), MUXL_WAIT }, + { UDATA (&muxo_svc, TT_MODE_UC|UNIT_DIS, 0), MUXL_WAIT }, + { UDATA (&muxo_svc, TT_MODE_UC|UNIT_DIS, 0), MUXL_WAIT }, + { UDATA (&muxo_svc, TT_MODE_UC|UNIT_DIS, 0), MUXL_WAIT }, + { UDATA (&muxo_svc, TT_MODE_UC|UNIT_DIS, 0), MUXL_WAIT }, + { UDATA (&muxo_svc, TT_MODE_UC|UNIT_DIS, 0), MUXL_WAIT }, + { UDATA (&muxo_svc, TT_MODE_UC|UNIT_DIS, 0), MUXL_WAIT }, + { UDATA (&muxo_svc, TT_MODE_UC|UNIT_DIS, 0), MUXL_WAIT }, + { UDATA (&muxo_svc, TT_MODE_UC|UNIT_DIS, 0), MUXL_WAIT }, + { UDATA (&muxo_svc, TT_MODE_UC|UNIT_DIS, 0), MUXL_WAIT }, + { UDATA (&muxo_svc, TT_MODE_UC|UNIT_DIS, 0), MUXL_WAIT }, + { UDATA (&muxo_svc, TT_MODE_UC|UNIT_DIS, 0), MUXL_WAIT }, + { UDATA (&muxo_svc, TT_MODE_UC|UNIT_DIS, 0), MUXL_WAIT }, + { UDATA (&muxo_svc, TT_MODE_UC|UNIT_DIS, 0), MUXL_WAIT }, + { UDATA (&muxo_svc, TT_MODE_UC|UNIT_DIS, 0), MUXL_WAIT }, + { UDATA (&muxo_svc, TT_MODE_UC|UNIT_DIS, 0), MUXL_WAIT } + }; + +MTAB muxl_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, &mux_desc }, + { MTAB_XTD|MTAB_VUN|MTAB_NC, 0, "LOG", "LOG", + &tmxr_set_log, &tmxr_show_log, &mux_desc }, + { MTAB_XTD|MTAB_VUN|MTAB_NC, 0, NULL, "NOLOG", + &tmxr_set_nolog, NULL, &mux_desc }, + { 0 } + }; + +REG muxl_reg[] = { + { URDATA (TIME, muxl_unit[0].wait, 10, 24, 0, + MUX_LINES, REG_NZ + PV_LEFT) }, + { NULL } + }; + +DEVICE muxl_dev = { + "MUXL", muxl_unit, muxl_reg, muxl_mod, + MUX_LINES, 10, 31, 1, 8, 8, + NULL, NULL, &mux_reset, + NULL, NULL, NULL, + NULL, 0 + }; + +/* MUX: IO dispatch routine */ + +uint32 mux_disp (uint32 op, uint32 dva, uint32 *dvst) +{ +switch (op) { /* case on op */ + + case OP_SIO: /* start I/O */ + *dvst = mux_tio_status (); /* get status */ + if ((*dvst & DVS_CST) == 0) { /* ctrl idle? */ + muxc_cmd = MUXC_INIT; /* start dev thread */ + sim_activate (&mux_unit[MUXC], chan_ctl_time); + } + break; + + case OP_TIO: /* test status */ + *dvst = mux_tio_status (); /* return status */ + break; + + case OP_TDV: /* test status */ + *dvst = 0; /* no status */ + break; + + case OP_HIO: /* halt I/O */ + *dvst = mux_tio_status (); /* get status */ + muxc_cmd = MUXC_IDLE; /* stop dev thread */ + sim_cancel (&mux_unit[MUXC]); + io_sclr_req (mux_rint, 0); /* clr rcv int */ + io_sclr_req (mux_xint, 0); + break; + + case OP_AIO: /* acknowledge int */ + *dvst = 0; /* no status */ + break; + + default: + *dvst = 0; + return SCPE_IERR; + } + +return 0; +} + +/* MUX: DIO dispatch routine */ + +uint32 mux_dio (uint32 op, uint32 rn, uint32 ad) +{ +int32 ln; +uint32 fnc = MUXDIO_GETFNC (ad); +uint32 coc = MUXDIO_GETCOC (ad); + +if (op == OP_RD) { /* read direct */ + if (coc != 0) /* nx COC? */ + return 0; + R[rn] = mux_scan | 0x40; /* return line num */ + mux_sta[mux_scan] &= ~MUXL_XIR; /* clear int req */ + return 0; + } +ln = MUXDAT_GETLIN (R[rn]); /* get line num */ +if (fnc & 0x4) { /* transmit */ + if ((coc != 0) || /* nx COC or */ + (ln >= MUX_NUMLIN)) { /* nx line? */ + CC |= CC4; + return 0; + } + if ((fnc & 0x7) == 0x5) { /* send char? */ + if (fnc & 0x8) /* space? */ + mux_xbuf[ln] = 0; + else mux_xbuf[ln] = MUXDAT_GETCHR (R[rn]); /* no, get char */ + sim_activate (&muxl_unit[ln], muxl_unit[ln].wait); + mux_sta[ln] = (mux_sta[ln] | MUXL_XIA) & ~MUXL_XIR; + mux_scan_next (1); /* unlock scanner */ + } + else if (fnc == 0x06) { /* stop transmit */ + mux_sta[ln] &= ~MUXL_XIA|MUXL_XIR; /* disable int */ + mux_scan_next (1); /* unlock scanner */ + } + else if (fnc == 0x07) { /* disconnect */ + tmxr_reset_ln (&mux_ldsc[ln]); /* reset line */ + mux_reset_ln (ln); /* reset state */ + } + CC = (sim_is_active (&muxl_unit[ln])? 0: CC4) | + (mux_ldsc[ln].conn? CC3: 0); + } +else { /* receive */ + if ((coc != 0) || /* nx COC or */ + (ln >= MUX_NUMLIN)) /* nx line */ + return 0; + if (fnc == 0x01) { /* set rcv enable */ + if (mux_ldsc[ln].conn) /* connected? */ + mux_ldsc[ln].rcve = 1; /* just enable */ + else mux_sta[ln] |= MUXL_REP; /* enable pending */ + } + else if (fnc == 0x02) { /* clr rcv enable */ + mux_ldsc[ln].rcve = 0; + mux_sta[ln] &= ~MUXL_REP; + } + else if (fnc == 0x03) { /* disconnect */ + tmxr_reset_ln (&mux_ldsc[ln]); /* reset line */ + mux_reset_ln (ln); /* reset state */ + } + if (mux_sta[ln] & MUXL_RBP) /* break pending? */ + CC = CC3|CC4; + else CC = mux_ldsc[ln].rcve? CC4: CC3; + } +return 0; +} + +/* Unit service - channel overhead */ + +t_stat muxc_svc (UNIT *uptr) +{ +uint32 st; +uint32 cmd; + +if (muxc_cmd == MUXC_INIT) { /* init state? */ + st = chan_get_cmd (mux_dib.dva, &cmd); /* get command */ + if (CHS_IFERR (st)) /* channel error? */ + mux_chan_err (st); /* go idle */ + else muxc_cmd = MUXC_RCV; /* no, receive */ + } +else if (muxc_cmd == MUXC_END) { /* end state? */ + st = chan_end (mux_dib.dva); /* set channel end */ + if (CHS_IFERR (st)) /* channel error? */ + mux_chan_err (st); /* go idle */ + else if (st == CHS_CCH) { /* command chain? */ + muxc_cmd = MUXC_INIT; /* restart thread */ + sim_activate (uptr, chan_ctl_time); /* schedule soon */ + } + else muxc_cmd = MUXC_IDLE; /* else idle */ + } +return SCPE_OK; +} + +/* Unit service - polled input - called from rtc scheduler + + Poll for new connections + Poll all connected lines for input +*/ + +t_stat muxi_rtc_svc (UNIT *uptr) +{ +t_stat r; +int32 newln, ln, c; + +if ((mux_unit[MUXC].flags & UNIT_ATT) == 0) /* attached? */ + return SCPE_OK; +newln = tmxr_poll_conn (&mux_desc); /* look for connect */ +if ((newln >= 0) && (mux_sta[newln] & MUXL_REP)) { /* rcv enb pending? */ + mux_ldsc[newln].rcve = 1; /* enable rcv */ + mux_sta[newln] &= ~MUXL_REP; /* clr pending */ + } +tmxr_poll_rx (&mux_desc); /* poll for input */ +for (ln = 0; ln < MUX_NUMLIN; ln++) { /* loop thru lines */ + if (mux_ldsc[ln].conn) { /* connected? */ + if (c = tmxr_getc_ln (&mux_ldsc[ln])) { /* get char */ + if (c & SCPE_BREAK) /* break? */ + mux_sta[ln] |= MUXL_RBP; /* set rcv brk */ + else { /* normal char */ + mux_sta[ln] &= ~MUXL_RBP; /* clr rcv brk */ + c = sim_tt_inpcvt (c, TT_GET_MODE (muxl_unit[ln].flags)); + mux_rbuf[ln] = c; /* save char */ + if ((muxc_cmd == MUXC_RCV) && /* chan active? */ + (r = muxi_put_char (c, ln))) /* char to chan */ + return r; + } /* end else char */ + } /* end if char */ + } /* end if conn */ + else mux_sta[ln] &= ~MUXL_RBP; /* disconnected */ + } /* end for */ +return SCPE_OK; +} + +/* Put character and line number in memory via channel */ + +t_stat muxi_put_char (uint32 c, uint32 ln) +{ +uint32 st; + +st = chan_WrMemB (mux_dib.dva, c); /* write char */ +if (CHS_IFERR (st)) /* channel error? */ + return mux_chan_err (st); +st = chan_WrMemB (mux_dib.dva, ln); /* write line */ +if (CHS_IFERR (st)) /* channel error? */ + return mux_chan_err (st); +if (st == CHS_ZBC) { /* bc == 0? */ + muxc_cmd = MUXC_END; /* end state */ + sim_activate (&mux_unit[MUXC], chan_ctl_time); /* quick schedule */ + } +io_sclr_req (mux_rint, 1); /* req ext intr */ +return SCPE_OK; +} + +/* Channel error */ + +t_stat mux_chan_err (uint32 st) +{ +chan_uen (mux_dib.dva); /* uend */ +muxc_cmd = MUXC_IDLE; /* go idle */ +if (st < CHS_ERR) + return st; +return 0; +} + +/* Unit service - transmit side */ + +t_stat muxo_svc (UNIT *uptr) +{ +int32 c; +uint32 ln = uptr - muxl_unit; /* line # */ + +if (mux_ldsc[ln].conn) { /* connected? */ + if (mux_ldsc[ln].xmte) { /* xmt enabled? */ + c = sim_tt_outcvt (mux_xbuf[ln], TT_GET_MODE (muxl_unit[ln].flags)); + if (c >= 0) + tmxr_putc_ln (&mux_ldsc[ln], c); /* output char */ + tmxr_poll_tx (&mux_desc); /* poll xmt */ + if (mux_sta[ln] & MUXL_XIA) { /* armed? */ + mux_sta[ln] |= MUXL_XIR; /* req intr */ + mux_scan_next (0); /* kick scanner */ + } + } + else { /* buf full */ + tmxr_poll_tx (&mux_desc); /* poll xmt */ + sim_activate (uptr, muxl_unit[ln].wait); /* wait */ + return SCPE_OK; + } + } +return SCPE_OK; +} + +/* MUX status routine */ + +uint32 mux_tio_status (void) +{ +if (muxc_cmd == MUXC_IDLE) /* idle? */ + return DVS_AUTO; +else return (DVS_AUTO|DVS_CBUSY|DVS_DBUSY|(CC2 << DVT_V_CC)); +} + +/* Kick scanner */ + +void mux_scan_next (t_bool clr) +{ +int32 i; + +if (clr) /* unlock? */ + mux_slck = 0; +else if (mux_slck) /* locked? */ + return; +for (i = 0; i < MUX_NUMLIN; i++) { /* scan lines */ + mux_scan = mux_scan + 1; /* next line */ + if (mux_scan >= (uint32) MUX_NUMLIN) + mux_scan = 0; + if (mux_sta[mux_scan] & MUXL_XIR) { /* flag set? */ + mux_slck = 1; /* lock scanner */ + io_sclr_req (mux_xint, 1); /* req ext int */ + return; + } + } +return; +} + +/* Reset routine */ + +t_stat mux_reset (DEVICE *dptr) +{ +int32 i; + +if (mux_dev.flags & DEV_DIS) /* master disabled? */ + muxl_dev.flags = muxl_dev.flags | DEV_DIS; /* disable lines */ +else muxl_dev.flags = muxl_dev.flags & ~DEV_DIS; +if (mux_unit[MUXC].flags & UNIT_ATT) /* master att? */ + rtc_register (RTC_COC, mux_tps, &mux_unit[MUXI]); /* register timer */ +else rtc_register (RTC_COC, RTC_HZ_OFF, NULL); /* else dereg */ +for (i = 0; i < MUX_LINES; i++) /* reset lines */ + mux_reset_ln (i); +return SCPE_OK; +} + +/* Attach master unit */ + +t_stat mux_attach (UNIT *uptr, char *cptr) +{ +t_stat r; + +r = tmxr_attach (&mux_desc, uptr, cptr); /* attach */ +if (r != SCPE_OK) /* error */ + return r; +rtc_register (RTC_COC, mux_tps, &mux_unit[MUXC]); /* register timer */ +return SCPE_OK; +} + +/* Detach master unit */ + +t_stat mux_detach (UNIT *uptr) +{ +int32 i; +t_stat r; + +r = tmxr_detach (&mux_desc, uptr); /* detach */ +for (i = 0; i < MUX_LINES; i++) /* disable rcv */ + mux_reset_ln (i); +rtc_register (RTC_COC, RTC_HZ_OFF, NULL); /* dereg */ +return r; +} + + +/* Change number of lines */ + +t_stat mux_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, MUX_LINES, &r); +if ((r != SCPE_OK) || (newln == MUX_NUMLIN)) + return r; +if (newln == 0) return SCPE_ARG; +if (newln < MUX_NUMLIN) { + for (i = newln, t = 0; i < MUX_NUMLIN; i++) t = t | mux_ldsc[i].conn; + if (t && !get_yn ("This will disconnect users; proceed [N]?", FALSE)) + return SCPE_OK; + for (i = newln; i < MUX_NUMLIN; i++) { + if (mux_ldsc[i].conn) { + tmxr_linemsg (&mux_ldsc[i], "\r\nOperator disconnected line\r\n"); + tmxr_reset_ln (&mux_ldsc[i]); /* reset line */ + } + muxl_unit[i].flags = muxl_unit[i].flags | UNIT_DIS; + mux_reset_ln (i); + } + } +else { + for (i = MUX_NUMLIN; i < newln; i++) { + muxl_unit[i].flags = muxl_unit[i].flags & ~UNIT_DIS; + mux_reset_ln (i); + } + } +MUX_NUMLIN = newln; +return SCPE_OK; +} + +/* Reset an individual line */ + +void mux_reset_ln (int32 ln) +{ +sim_cancel (&muxl_unit[ln]); +mux_sta[ln] = 0; +mux_rbuf[ln] = 0; +mux_xbuf[ln] = 0; +mux_ldsc[ln].rcve = 0; +return; +} diff --git a/sigma/sigma_cpu.c b/sigma/sigma_cpu.c new file mode 100644 index 00000000..22e1a44a --- /dev/null +++ b/sigma/sigma_cpu.c @@ -0,0 +1,2848 @@ +/* sigma_cpu.c: XDS Sigma CPU simulator + + Copyright (c) 2007-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 central processor + + The system state for the Sigma CPU is as follows: + + RF[0:15][0:31]<0:31> register blocks + PSW1<0:31> processor status word 1 + CC<0:3> condition codes + PC<0:17> program counter (called IA in Sigma documentation) + PSW2<0:31> processor status word 2 + PSW2_WLK<0:3> write key (2b on S5-9) + PSW4<0:31> processor status word 4 (5X0 only) + MAP[0:511]<0:10> memory map (8b on S5-8) + WLK[0:2047]<0:3> write locks (256 2b entries on S5-9) + SSW<0:3> sense switches + PDF processor detected fault flag (S8-9, 5X0 only) + + Notes on features not documented in the Reference Manuals: + + 1. Memory mapping was available for the Sigma 5 (see map diagnostic). + 2. The Sigma 6/7 were field retrofitted with the LAS/LMS instructions + (see auto diagnostic). + 3. The Sigma 8/9 returned different results for WD .45 (see Telefile + System exerciser). + 4. Expanded memory beyond 128KB was retrofitted to the Sigma 5/6/7, + creating the so-called "Big 5/6/7." As a minimum, these systems + also included the "mode altered" feature and the 11b relocation map. + + The Sigma CPU has two instruction formats, memory reference and immediate. + The memory reference format is: + + 3 3 2 2 2 2 2 2 2 2 2 2 1 1 1 1 1 1 1 1 1 1 + 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + |I| | | | | + |N| opcode | R | X | address | memory + |D| | | | | reference + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + + where + + IND = indirect flag + opcode = operation code + R = source/destination register + X = index register (0 if none) + address = operand address + + The immediate format is: + + 3 3 2 2 2 2 2 2 2 2 2 2 1 1 1 1 1 1 1 1 1 1 + 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | | | | | + |0| opcode | R | immediate | immediate + | | | | | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + + This routine is the instruction decode routine for the Sigma 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 + invalid instruction and stop_op flag set + I/O error in I/O simulator + EXU loop exceeding limit + illegal interrupt or trap instruction + illegal register pointer + illegal vector + + 2. Interrupts. The interrupt structure consists of the following: + Each interrupt is part of a group that determines its priority. + The interrupt group is either controlled by a PSW inhibit or is + unconditional. Interrupts can be armed or disarmed (which controls + whether they are recognized at all) and enabled or disabled (which + controls whether they occur). See the sigma_io.c module for details. + + 3. Channels. The Sigma system has a channel-based I/O structure. Each + channel is represented by a set of registers. Channels test the + I/O transfer requests from devices. + + 4. Non-existent memory. On the Sigma, accesses to non-existent memory + trap. + + 5. Adding I/O devices. These modules must be modified: + + sigma_defs.h add definitions + sigma_io.c add dispatches + sigma_sys.c add pointer to data structures to sim_devices +*/ + +#include "sigma_io_defs.h" + +#define CPUF_V_MODEL (UNIT_V_UF + 6) /* CPU model */ +#define CPUF_M_MODEL 0x7 +#define CPUF_MODEL (CPUF_M_MODEL << CPUF_V_MODEL) +#define CPUF_S5 (CPU_V_S5 << CPUF_V_MODEL) +#define CPUF_S6 (CPU_V_S6 << CPUF_V_MODEL) +#define CPUF_S7 (CPU_V_S7 << CPUF_V_MODEL) +#define CPUF_S8 (CPU_V_S8 << CPUF_V_MODEL) +#define CPUF_S7B (CPU_V_S7B << CPUF_V_MODEL) +#define CPUF_S9 (CPU_V_S9 << CPUF_V_MODEL) +#define CPUF_550 (CPU_V_550 << CPUF_V_MODEL) +#define CPUF_560 (CPU_V_560 << CPUF_V_MODEL) +#define CPUF_GETMOD(x) (((x) >> CPUF_V_MODEL) & CPUF_M_MODEL) + +#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] = real_pc; + +#define HIST_MIN 64 +#define HIST_MAX (1u << 20) +#define H_INST 0x00800000 +#define H_CHAN 0x00400000 +#define H_ITRP 0x00200000 +#define H_ABRT 0x00100000 + +typedef struct { + uint32 typ_cc_pc; + uint32 ir; + uint32 rn; + uint32 rn1; + uint32 x; /* unused */ + uint32 ea; + uint32 op; + uint32 op1; + } InstHistory; + +uint32 cpu_model = CPU_V_S7; /* CPU model */ +uint32 *M; /* memory */ +uint32 rf[RF_NBLK * RF_NUM] = { 0 }; /* register files */ +uint32 *R = rf; /* cur reg file */ +uint32 PSW1 = PSW1_DFLT; /* PSD */ +uint32 PSW2 = PSW2_DFLT; +uint32 PSW4 = 0; /* 5X0 only */ +uint32 CC; +uint32 PC; +uint32 PSW2_WLK = 0; /* write lock key */ +uint32 PSW_QRX9; /* Sigma 9 real extended */ +uint32 bvamqrx = BVAMASK; /* BVA mask, 17b/20b */ +uint32 SSW = 0; /* sense switches */ +uint32 cpu_pdf = 0; /* proc detected fault */ +uint32 cons_alarm = 0; /* console alarm */ +uint32 cons_alarm_enb = 0; /* alarm enable */ +uint32 cons_pcf = 0; +uint32 rf_bmax = 4; /* num reg blocks */ +uint32 exu_lim = 32; /* nested EXU limit */ +uint32 stop_op = 0; /* stop on ill op */ +uint32 cpu_astop = 0; /* address stop */ +uint32 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 */ + +extern int32 sim_int_char; +extern int32 sim_interval; +extern int32 sim_switches; +extern uint32 sim_brk_types, sim_brk_dflt, sim_brk_summ; /* breakpoint info */ +extern uint32 int_hiact; /* highest act int */ +extern uint32 int_hireq; /* highest int req */ + +t_stat cpu_svc (UNIT *uptr); +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_type (UNIT *uptr, int32 val, char *cptr, 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_rblks (UNIT *uptr, int32 val, char *cptr, void *desc); +t_stat cpu_show_rblks (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_stat cpu_set_alarm (UNIT *uptr, int32 val, char *cptr, void *desc); +t_stat cpu_show_alarm (FILE *st, UNIT *uptr, int32 val, void *desc); +t_stat cpu_show_addr (FILE *st, UNIT *uptr, int32 val, void *desc); +void set_rf_display (uint32 *rfbase); +void inst_hist (uint32 ir, uint32 pc, uint32 typ); +uint32 cpu_one_inst (uint32 real_pc, uint32 IR); +uint32 ImmOp (uint32 ir, uint32 *imm); +uint32 EaP20 (uint32 IR, uint32 *bva, uint32 lnt); +uint32 EaSh (uint32 ir, uint32 *stype, uint32 *sc); +uint32 Add32 (uint32 s1, uint32 s2, uint32 cin); +uint32 SMul64 (uint32 a, uint32 b, uint32 *lo); +t_bool SDiv64 (uint32 dvdh, uint32 dvdl, uint32 dvr, uint32 *res, uint32 *rem); +uint32 Cmp32 (uint32 a, uint32 b); +uint32 Shift (uint32 rn, uint32 stype, uint32 sc); +uint32 TestSP1 (uint32 sp1, int32 mod); +uint32 ModWrSP (uint32 bva, uint32 sp, uint32 sp1, int32 mod); +uint32 cpu_int_mtx (uint32 vec, uint32 *cc); +uint32 cpu_trap_or_int (uint32 vec); +uint32 cpu_xpsd (uint32 ir, uint32 bva, uint32 ra); +uint32 cpu_pss (uint32 ir, uint32 bva, uint32 acc); +uint32 cpu_pls (uint32 IR); +void cpu_assemble_PSD (void); +uint32 cpu_new_PSD (uint32 lrp, uint32 p1, uint32 p2); +uint32 cpu_new_RP (uint32 rp); +uint32 cpu_new_PC (uint32 bva); +uint32 cpu_add_PC (uint32 pc, uint32 val); +t_stat cpu_bad_rblk (UNIT *uptr); +void cpu_fprint_one_inst (FILE *st, uint32 tcp, uint32 ir, uint32 rn, + uint32 rn1, uint32 ea, uint32 op, uint32 op1); + +extern uint32 fp (uint32 op, uint32 rn, uint32 bva); +extern uint32 cis_dec (uint32 op, uint32 rn, uint32 bva); +extern uint32 cis_ebs (uint32 rn, uint32 disp); +extern void ShiftF (uint32 rn, uint32 stype, uint32 sc); +extern uint32 map_mmc (uint32 rn, uint32 map); +extern uint32 map_lra (uint32 rn, uint32 inst); +extern uint32 map_las (uint32 rn, uint32 bva); +extern uint32 map_lms (uint32 rn, uint32 bva); +extern t_stat io_init (void); +extern uint32 io_eval_int (void); +extern uint32 io_actv_int (void); +extern t_bool io_poss_int (void); +extern uint32 io_ackn_int (uint32 hireq); +extern uint32 io_rels_int (uint32 hiact, t_bool arm); +extern uint32 io_rwd (uint32 op, uint32 rn, uint32 bva); +extern uint32 io_sio (uint32 rn, uint32 bva); +extern uint32 io_tio (uint32 rn, uint32 bva); +extern uint32 io_tdv (uint32 rn, uint32 bva); +extern uint32 io_hio (uint32 rn, uint32 bva); +extern uint32 io_aio (uint32 rn, uint32 bva); +extern uint32 int_reset (DEVICE *dev); +extern void io_set_eimax (uint32 lnt); +extern void io_sclr_req (uint32 inum, uint32 val); +extern void io_sclr_arm (uint32 inum, uint32 val); +extern t_stat io_set_nchan (UNIT *uptr, int32 val, char *cptr, void *desc); +extern t_stat io_show_nchan (FILE *st, UNIT *uptr, int32 val, 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 (&cpu_svc, UNIT_FIX+CPUF_S7+CPUF_ALLOPT+UNIT_BINK, MAXMEMSIZE), + }; + +UNIT cpu_rblk_unit = { + UDATA (&cpu_bad_rblk, UNIT_DIS, 0) + }; + +REG cpu_reg[] = { + { GRDATA (PC, PSW1, 16, VASIZE, PSW1_V_PC) }, + { HRDATA (R0, rf[0], 32) }, /* addr in memory */ + { HRDATA (R1, rf[1], 32) }, /* modified at exit */ + { HRDATA (R2, rf[2], 32) }, /* to SCP */ + { HRDATA (R3, rf[3], 32) }, + { HRDATA (R4, rf[4], 32) }, + { HRDATA (R5, rf[5], 32) }, + { HRDATA (R6, rf[6], 32) }, + { HRDATA (R7, rf[7], 32) }, + { HRDATA (R8, rf[8], 32) }, + { HRDATA (R9, rf[9], 32) }, + { HRDATA (R10, rf[10], 32) }, + { HRDATA (R11, rf[11], 32) }, + { HRDATA (R12, rf[12], 32) }, + { HRDATA (R13, rf[13], 32) }, + { HRDATA (R14, rf[14], 32) }, + { HRDATA (R15, rf[15], 32) }, + { HRDATA (PSW1, PSW1, 32) }, + { HRDATA (PSW2, PSW2, 32) }, + { HRDATA (PSW4, PSW4, 32) }, + { GRDATA (CC, PSW1, 16, 4, PSW1_V_CC) }, + { GRDATA (RP, PSW2, 16, 4, PSW2_V_RP) }, + { FLDATA (SSW1, SSW, 3) }, + { FLDATA (SSW2, SSW, 2) }, + { FLDATA (SSW3, SSW, 1) }, + { FLDATA (SSW4, SSW, 0) }, + { FLDATA (PDF, cpu_pdf, 0) }, + { FLDATA (ALARM, cons_alarm, 0) }, + { FLDATA (ALENB, cons_alarm_enb, 0), REG_HRO }, + { FLDATA (PCF, cons_pcf, 0) }, + { DRDATA (EXULIM, exu_lim, 8), PV_LEFT + REG_NZ }, + { FLDATA (STOP_ILL, stop_op, 0) }, + { BRDATA (REG, rf, 16, 32, RF_NUM * RF_NBLK) }, + { DRDATA (RBLKS, rf_bmax, 5), REG_HRO }, + { BRDATA (PCQ, pcq, 16, VASIZE, PCQ_SIZE), REG_RO+REG_CIRC }, + { DRDATA (PCQP, pcq_p, 6), REG_HRO }, + { HRDATA (WRU, sim_int_char, 8) }, + { NULL } + }; + +MTAB cpu_mod[] = { + { CPUF_MODEL, CPUF_S5, "Sigma 5", "SIGMA5", &cpu_set_type }, + { CPUF_MODEL, CPUF_S6, "Sigma 6", "SIGMA6", &cpu_set_type }, + { CPUF_MODEL, CPUF_S7, "Sigma 7", "SIGMA7", &cpu_set_type }, +// { CPUF_MODEL, CPUF_S8, "Sigma 8", "SIGMA8", &cpu_set_type }, +// { CPUF_MODEL, CPUF_S9, "Sigma 9", "SIGMA9", &cpu_set_type }, +// { CPUF_MODEL, CPUF_550, "550", "550", &cpu_set_type }, +// { CPUF_MODEL, CPUF_560, "560", "560", &cpu_set_type }, + { MTAB_XTD|MTAB_VDV, 0, "register blocks", "RBLKS", + &cpu_set_rblks, &cpu_show_rblks }, + { MTAB_XTD|MTAB_VDV, 0, "channels", "CHANNELS", + &io_set_nchan, &io_show_nchan }, + { CPUF_FP, CPUF_FP, "floating point", "FP", &cpu_set_opt }, + { CPUF_FP, 0, "no floating point", NULL }, + { MTAB_XTD|MTAB_VDV, CPUF_FP, NULL, "NOFP", &cpu_clr_opt }, + { CPUF_DEC, CPUF_DEC, "decimal", "DECIMAL", &cpu_set_opt }, + { CPUF_DEC, 0, "no decimal", NULL }, + { MTAB_XTD|MTAB_VDV, CPUF_DEC, NULL, "NODECIMAL", &cpu_clr_opt }, + { CPUF_LAMS, CPUF_LAMS, "LAS/LMS", "LASLMS", &cpu_set_opt }, + { CPUF_LAMS, 0, "no LAS/LMS", NULL }, + { MTAB_XTD|MTAB_VDV, CPUF_LAMS, NULL, "NOLASLMS", &cpu_clr_opt }, + { CPUF_MAP, CPUF_MAP, "map", "MAP", &cpu_set_opt }, + { CPUF_MAP, 0, "no map", NULL }, + { MTAB_XTD|MTAB_VDV, CPUF_MAP, NULL, "NOMAP", &cpu_clr_opt }, + { CPUF_WLK, CPUF_WLK, "write lock", "WRITELOCK", &cpu_set_opt }, + { CPUF_WLK, 0, "no write lock", NULL }, + { MTAB_XTD|MTAB_VDV, CPUF_WLK, NULL, "NOWRITELOCK", &cpu_clr_opt }, + { MTAB_XTD|MTAB_VDV|MTAB_NMO, 1, "ALARM", "ALON", &cpu_set_alarm, &cpu_show_alarm }, + { MTAB_XTD|MTAB_VDV|MTAB_NMO, 0, NULL, "ALOFF", & cpu_set_alarm }, + { CPUF_MSIZE, (1u << 15), NULL, "32K", &cpu_set_size }, + { CPUF_MSIZE, (1u << 16), NULL, "64K", &cpu_set_size }, + { CPUF_MSIZE, (1u << 17), NULL, "128K", &cpu_set_size }, + { CPUF_MSIZE, (1u << 18), NULL, "256K", &cpu_set_size }, + { CPUF_MSIZE, (1u << 19), NULL, "512K", &cpu_set_size }, + { CPUF_MSIZE, (1u << 20), NULL, "1M", &cpu_set_size }, + { MTAB_XTD|MTAB_VDV|MTAB_NMO|MTAB_SHP, BY, "BA", NULL, + NULL, &cpu_show_addr }, + { MTAB_XTD|MTAB_VDV|MTAB_NMO|MTAB_SHP, HW, "HA", NULL, + NULL, &cpu_show_addr }, + { MTAB_XTD|MTAB_VDV|MTAB_NMO|MTAB_SHP, WD, "WA", NULL, + NULL, &cpu_show_addr }, + { MTAB_XTD|MTAB_VDV|MTAB_NMO|MTAB_SHP, DW, "DA", NULL, + NULL, &cpu_show_addr }, + { 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, 20, 1, 16, 32, + &cpu_ex, &cpu_dep, &cpu_reset, + NULL, NULL, NULL, + }; + +static uint8 anlz_tab[128] = { + 0x9, 0x9, 0x9, 0x9, 0x8, 0x8, 0x8, 0x8, /* 00 - 0F */ + 0xC, 0xC, 0xC, 0xC, 0xC, 0xC, 0xC, 0xC, + 0xC, 0xC, 0xC, 0xC, 0xC, 0xC, 0xC, 0xC, /* 10 - 1F */ + 0xC, 0xC, 0xC, 0xC, 0xC, 0xC, 0xC, 0xC, + 0x9, 0x9, 0x9, 0x9, 0x8, 0x8, 0x8, 0x8, /* 20 - 2F */ + 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, + 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, /* 30 - 3F */ + 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, + 0x1, 0x1, 0x1, 0x1, 0x8, 0x8, 0x8, 0x8, /* 40 - 4F */ + 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, + 0x4, 0x4, 0x4, 0x4, 0x4, 0x4, 0x4, 0x4, /* 50 - 5F */ + 0x4, 0x4, 0x4, 0x4, 0x4, 0x4, 0x4, 0x4, + 0x1, 0x1, 0x1, 0x1, 0x8, 0x8, 0x8, 0x8, /* 60 - 6F */ + 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, /* 70 - 7F */ + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 + }; + +cpu_var_t cpu_tab[] = { + +/* psw1_mbz psw2_mbz m_map1 pamask eint chan + cc standard optional */ + { 0x080E0000, 0xC8FFFE0F, 0x0FC, PAMASK17, 14, 8, /* S5 */ + CC1|CC2, 0, CPUF_MAP|CPUF_WLK|CPUF_FP }, + { 0x080E0000, 0xC8FFFE0F, 0x0FC, PAMASK17, 14, 8, /* S6 */ + CC1|CC2, CPUF_STR|CPUF_MAP|CPUF_WLK|CPUF_DEC, CPUF_FP|CPUF_LAMS }, + { 0x080E0000, 0xC8FFFE0F, 0x0FC, PAMASK17, 14, 8, /* S7 */ + CC1|CC2, CPUF_STR|CPUF_MAP|CPUF_WLK, CPUF_FP|CPUF_DEC|CPUF_LAMS }, + { 0x084E0000, 0xC8FF00C7, 0x0FC, PAMASK17, 14, 8, /* S8 */ + CC1|CC2|CC3, CPUF_STR|CPUF_FP|CPUF_WLK|CPUF_LAMS, 0 }, + { 0x08060000, 0xC8400007, 0x0FC, PAMASK22, 14, 8, /* S9 */ + CC1|CC2|CC3, CPUF_STR|CPUF_MAP|CPUF_WLK|CPUF_DEC|CPUF_FP|CPUF_LAMS, 0 }, + { 0x002E0000, 0x080FFFC3, 0x7FE, PAMASK20, 4, 4, /* 550 */ + CC1|CC2|CC3|CC4, CPUF_MAP|CPUF_WLK|CPUF_LAMS, CPUF_FP }, + { 0x000E0000, 0x080FFFC3, 0x7FE, PAMASK20, 4, 4, /* 560 */ + CC1|CC2|CC3|CC4, CPUF_STR|CPUF_MAP|CPUF_WLK|CPUF_DEC|CPUF_FP|CPUF_LAMS, 0 } + }; + +/* Simulation loop */ + +t_stat sim_instr (void) +{ +uint32 ir, rpc, old_PC; +t_stat reason, tr, tr2; + +/* Restore register state */ + +if (io_init ()) /* init IO; conflict? */ + return STOP_INVIOC; +reason = 0; +if (cpu_new_PSD (1, PSW1, PSW2)) /* restore PSD, RP etc */ + return STOP_INVPSD; +int_hireq = io_eval_int (); + +/* Main instruction fetch/decode loop */ + +while (reason == 0) { /* loop until stop */ + + PSW2 &= ~PSW2_RA; /* clr reg altered */ + if (cpu_astop) { /* debug stop? */ + cpu_astop = 0; + return STOP_ASTOP; + } + + if (sim_interval <= 0) { /* event queue? */ + if (reason = sim_process_event ()) /* process */ + break; + int_hireq = io_eval_int (); /* re-evaluate intr */ + } + sim_interval = sim_interval - 1; /* count down */ + + if (int_hireq < NO_INT) { /* interrupt req? */ + uint32 sav_hi, vec, wd, op; + + vec = io_ackn_int (sav_hi = int_hireq); /* get vector */ + if (vec == 0) { /* illegal vector? */ + reason = STOP_ILLVEC; /* something wrong */ + break; + } + ReadPW (vec, &wd); /* read vector */ + op = I_GETOP (wd); /* get opcode */ + if ((op == OP_MTB) || (op == OP_MTH) || (op == OP_MTW)) { + uint32 res; + tr2 = cpu_int_mtx (vec, &res); /* do single cycle */ + io_sclr_req (sav_hi, 0); /* clear request */ + io_sclr_arm (sav_hi, 1); /* set armed */ + if ((res == 0) && /* count overflow */ + ((vec >= VEC_C1P) || (vec <= VEC_C4P))) /* on clock? */ + io_sclr_req (INTV (INTG_CTR, vec - VEC_C1P), 1); + int_hiact = io_actv_int (); /* re-eval active */ + int_hireq = io_eval_int (); /* re-eval intr */ + } + else tr2 = cpu_trap_or_int (vec); /* XPSD/PSS intr */ + if (tr2 & TR_FL) { /* trap? */ + if (QCPU_S89_5X0) /* S89 or 5X0? */ + tr2 = cpu_trap_or_int (tr2); /* try again */ + reason = (tr2 == TR_INVTRP)? STOP_ILLTRP: STOP_TRPT; + } + else reason = tr2; /* normal status code */ + } + else { /* normal instruction */ + if (sim_brk_summ && + sim_brk_test (PC, SWMASK ('E'))) { /* breakpoint? */ + reason = STOP_IBKPT; /* stop simulation */ + break; + } + if (PSW_QRX9 && (PC & PSW1_XA)) /* S9 real ext && ext? */ + rpc = (PSW2 & PSW2_EA) | (PC & ~PSW1_XA); /* 22b phys address */ + else rpc = PC; /* standard 17b PC */ + PC = cpu_add_PC (old_PC = PC, 1); /* increment PC */ + if (((tr = ReadW (rpc << 2, &ir, VI)) != 0) || /* fetch inst, err? */ + ((tr = cpu_one_inst (rpc, ir)) != 0)) { /* exec inst, error? */ + if (tr & TR_FL) { /* trap? */ + PC = old_PC; /* roll back PC */ + tr2 = cpu_trap_or_int (tr); /* do trap */ + if (tr2 & TR_FL) { /* trap? */ + if (QCPU_S89_5X0) /* S89 or 5X0? */ + tr2 = cpu_trap_or_int (tr2); /* try again */ + reason = (tr2 == TR_INVTRP)? STOP_ILLTRP: STOP_TRPT; + } /* end if trap-in-trap */ + else reason = tr2; /* normal status */ + } /* end if trap */ + else reason = tr; /* normal status */ + if ((reason >= STOP_ROLLBACK) && /* roll back PC? */ + (reason <= STOP_MAX)) + PC = old_PC; + } /* end if abnormal status */ + } /* end else normal */ + } /* end while */ + +/* Simulation halted */ + +pcq_r->qptr = pcq_p; /* update pc q ptr */ +cpu_assemble_PSD (); /* visible PSD */ +set_rf_display (R); /* visible registers */ +return reason; +} + +/* Execute one instruction */ + +uint32 cpu_one_inst (uint32 real_pc, uint32 IR) +{ +uint32 op, rn, bva, opnd, opnd1, opnd2, t; +uint32 res, res1, tr, stype, sc, cnt; +uint32 sa, da, mask, c, c1, i, lim, aop, exu_cnt; +int32 sop, sop1; +t_bool mprot; + +exu_cnt = 0; /* init EXU count */ +EXU_LOOP: +if (hst_lnt) /* history? record */ + inst_hist (IR, real_pc, H_INST); +op = I_GETOP (IR); /* get opcode */ +rn = I_GETRN (IR); /* get reg num */ +switch (op) { + +/* Loads and stores */ + + case OP_LI: /* load immediate */ + if ((tr = ImmOp (IR, &opnd)) != 0) /* get immed opnd */ + return tr; + opnd = SEXT_LIT_W (opnd) & WMASK; /* sext to 32b */ + CC34_W (opnd); /* set cc's */ + R[rn] = opnd; /* store result */ + break; + + case OP_LB: /* load byte */ + if ((tr = Ea (IR, &bva, VR, BY)) != 0) /* get eff addr */ + return tr; + if ((tr = ReadB (bva, &opnd, VR)) != 0) /* read byte */ + return tr; + CC34_W (opnd); /* set cc's */ + R[rn] = opnd; /* store result */ + break; + + case OP_LH: /* load halfword */ + if ((tr = Ea (IR, &bva, VR, HW)) != 0) /* get eff addr */ + return tr; + if ((tr = ReadH (bva, &opnd, VR)) != 0) /* read halfword */ + return tr; + opnd = SEXT_H_W (opnd) & WMASK; /* sext to 32b */ + CC34_W (opnd); /* set cc's */ + R[rn] = opnd; /* store result */ + break; + + case OP_LCH: /* load comp hw */ + if ((tr = Ea (IR, &bva, VR, HW)) != 0) /* get eff addr */ + return tr; + if ((tr = ReadH (bva, &opnd, VR)) != 0) /* read halfword */ + return tr; + opnd = SEXT_H_W (opnd); /* sext to 32b */ + opnd = NEG_W (opnd); /* negate */ + CC34_W (opnd); /* set cc's */ + R[rn] = opnd; /* store result */ + break; + + case OP_LAH: /* load abs hw */ + if ((tr = Ea (IR, &bva, VR, HW)) != 0) /* get eff addr */ + return tr; + if ((tr = ReadH (bva, &opnd, VR)) != 0) /* read halfword */ + return tr; + if (opnd & HSIGN) /* negative? */ + opnd = NEG_W (opnd) & HMASK; /* negate */ + CC34_W (opnd); /* set cc's */ + R[rn] = opnd; /* store result */ + break; + + case OP_LW: /* load word */ + if ((tr = Ea (IR, &bva, VR, WD)) != 0) /* get eff addr */ + return tr; + if ((tr = ReadW (bva, &opnd, VR)) != 0) /* read word */ + return tr; + CC34_W (opnd); /* set cc's */ + R[rn] = opnd; /* store result */ + break; + + case OP_LCW: /* load comp word */ + if ((tr = Ea (IR, &bva, VR, WD)) != 0) /* get eff addr */ + return tr; + if ((tr = ReadW (bva, &opnd, VR)) != 0) /* read word */ + return tr; + opnd = NEG_W (opnd); /* negate */ + CC34_W (opnd); /* set cc's */ + R[rn] = opnd; /* store result */ + if (opnd == WSIGN) { /* overflow? */ + CC |= CC2; /* set CC2 */ + if (PSW1 & PSW1_AM) /* trap if enabled */ + return TR_FIX; + } + else CC &= ~CC2; /* no, clear CC2 */ + break; + + case OP_LAW: /* load abs word */ + if ((tr = Ea (IR, &bva, VR, WD)) != 0) /* get eff addr */ + return tr; + if ((tr = ReadW (bva, &opnd, VR)) != 0) /* read word */ + return tr; + if (opnd & WSIGN) /* negative? */ + opnd = NEG_W (opnd); /* take abs value */ + CC34_W (opnd); /* set cc's */ + R[rn] = opnd; /* store result */ + if (opnd == WSIGN) { /* overflow? */ + CC |= CC2; /* set CC2 */ + if (PSW1 & PSW1_AM) /* trap if enabled */ + return TR_FIX; + } + else CC &= ~CC2; /* no, clear CC2 */ + break; + + case OP_LS: /* load selective */ + if ((tr = Ea (IR, &bva, VR, WD)) != 0) /* get eff addr */ + return tr; + if ((tr = ReadW (bva, &opnd, VR)) != 0) /* read word */ + return tr; + res = (R[rn] & ~R[rn|1]) | (opnd & R[rn|1]); /* load under mask */ + CC34_W (res); /* set cc's */ + R[rn] = res; /* store result */ + break; + + case OP_LAS: /* load and set */ + if ((cpu_unit.flags & CPUF_LAMS) == 0) /* not included? */ + return TR_NXI; + if ((tr = Ea (IR, &bva, VR, WD)) != 0) /* get eff addr */ + return tr; + if ((tr = map_las (rn, bva)) != 0) /* do instruction */ + return tr; + CC34_W (R[rn]); /* set CC's */ + break; + + case OP_LVAW: /* load virt addr */ + if (!QCPU_5X0) /* 5X0 only */ + return TR_NXI; + if ((tr = Ea (IR, &bva, VR, WD)) != 0) /* get eff addr */ + return tr; + R[rn] = bva >> 2; /* store */ + break; + + case OP_LD: /* load doubleword */ + if ((tr = Ea (IR, &bva, VR, DW)) != 0) /* get eff addr */ + return tr; + if ((tr = ReadD (bva, &opnd, &opnd1, VR)) != 0) /* read doubleword */ + return tr; + if ((opnd == 0) && (opnd1 != 0)) /* 0'non-zero? */ + CC = (CC & ~CC4) | CC3; /* set CC3 */ + else CC34_W (opnd); /* else hi sets CC */ + R[rn|1] = opnd1; /* store result */ + R[rn] = opnd; + break; + + case OP_LCD: /* load comp double */ + if ((tr = Ea (IR, &bva, VR, DW)) != 0) /* get eff addr */ + return tr; + if ((tr = ReadD (bva, &opnd, &opnd1, VR)) != 0) /* read doubleword */ + return tr; + NEG_D (opnd, opnd1); /* negate */ + if ((opnd == 0) && (opnd1 != 0)) /* 0'non-zero? */ + CC = (CC & ~CC4) | CC3; /* set CC3 */ + else CC34_W (opnd); /* else hi sets CC */ + R[rn|1] = opnd1; /* store result */ + R[rn] = opnd; + if ((opnd == WSIGN) && (opnd1 == 0)) { /* overflow? */ + CC |= CC2; /* set CC2 */ + if (PSW1 & PSW1_AM) /* trap if enabled */ + return TR_FIX; + } + else CC &= ~CC2; /* no, clear CC2 */ + break; + + case OP_LAD: /* load abs double */ + if ((tr = Ea (IR, &bva, VR, DW)) != 0) /* get eff addr */ + return tr; + if ((tr = ReadD (bva, &opnd, &opnd1, VR)) != 0) /* read doubleword */ + return tr; + if (opnd & WSIGN) /* negative? */ + NEG_D (opnd, opnd1); /* take abs value */ + if ((opnd == 0) && (opnd1 != 0)) /* 0'non-zero? */ + CC = (CC & ~CC4) | CC3; /* set CC3 */ + else CC34_W (opnd); /* else hi sets CC */ + R[rn|1] = opnd1; /* store result */ + R[rn] = opnd; + if ((opnd == WSIGN) && (opnd1 == 0)) { /* overflow? */ + CC |= CC2; /* set CC2 */ + if (PSW1 & PSW1_AM) /* trap if enabled */ + return TR_FIX; + } + else CC &= ~CC2; /* no, clear CC2 */ + break; + +/* Note: the Sigma 7 does not prove the instruction can execute successfully + before starting to load registers; the Sigma 9 (and the simulator) do. */ + + case OP_LM: /* load multiple */ + lim = CC? CC: 16; /* CC sets count */ + if ((tr = Ea (IR, &bva, VR, WD)) != 0) /* get eff addr */ + return tr; + if ((tr = ReadW ((bva + ((lim - 1) << 2)) & bvamqrx, &opnd, VR)) != 0) + return tr; /* test readability */ + for (i = 0; i < lim; i++) { /* loop thru reg */ + if ((tr = ReadW (bva, &opnd, VR)) != 0) /* read next */ + return tr; + R[rn] = opnd; /* store in reg */ + bva = (bva + 4) & bvamqrx; /* next word */ + rn = (rn + 1) & RNMASK; /* next reg */ + PSW2 |= PSW2_RA; /* reg altered */ + } + break; + + case OP_LCFI: /* load cc, flt immed */ + if ((tr = ImmOp (IR, &opnd)) != 0) /* get immed opnd */ + return tr; + if (IR & IRB(10)) /* load CC's? */ + CC = (opnd >> 4) & 0xF; + if (IR & IRB(11)) /* load FP ctrls? */ + PSW1 = ((PSW1 & ~PSW1_FPC) | /* set ctrls */ + ((opnd & PSW1_M_FPC) << PSW1_V_FPC)) & + ~cpu_tab[cpu_model].psw1_mbz; /* clear mbz */ + break; + + case OP_LCF: /* load cc, flt */ + if ((tr = Ea (IR, &bva, VR, BY)) != 0) /* get eff addr */ + return tr; + if ((tr = ReadB (bva, &opnd, VR)) != 0) /* get byte */ + return tr; + if (IR & IRB(10)) /* load CC's? */ + CC = (opnd >> 4) & 0xF; + if (IR & IRB(11)) /* load FP ctrls? */ + PSW1 = ((PSW1 & ~PSW1_FPC) | /* set ctrls */ + ((opnd & PSW1_M_FPC) << PSW1_V_FPC)) & + ~cpu_tab[cpu_model].psw1_mbz; /* clear mbz */ + break; + + case OP_XW: /* exchange word */ + if ((tr = Ea (IR, &bva, VR, WD)) != 0) /* get eff addr */ + return tr; + if ((tr = ReadW (bva, &opnd, VR)) != 0) /* read word */ + return tr; + if ((tr = WriteW (bva, R[rn], VW)) != 0) /* write reg */ + return tr; + CC34_W (opnd); /* set cc's */ + R[rn] = opnd; /* store result */ + break; + + case OP_STB: /* store byte */ + if ((tr = Ea (IR, &bva, VR, BY)) != 0) /* get eff addr */ + return tr; + if ((tr = WriteB (bva, R[rn], VW)) != 0) /* store */ + return tr; + break; + + case OP_STH: /* store halfword */ + if ((tr = Ea (IR, &bva, VR, HW)) != 0) /* get eff addr */ + return tr; + if ((tr = WriteH (bva, R[rn], VW)) != 0) /* store */ + return tr; + if (R[rn] == (SEXT_H_W (R[rn]) & WMASK)) /* rn a sext hw? */ + CC &= ~CC2; /* yes, clr CC2 */ + else CC |= CC2; + break; + + case OP_STW: /* store word */ + if ((tr = Ea (IR, &bva, VR, WD)) != 0) /* get eff addr */ + return tr; + if ((tr = WriteW (bva, R[rn], VW)) != 0) /* store */ + return tr; + break; + + case OP_STD: /* store doubleword */ + if ((tr = Ea (IR, &bva, VR, DW)) != 0) /* get eff addr */ + return tr; + if ((tr = WriteD (bva, R[rn], R[rn|1], VW)) != 0) /* store */ + return tr; + break; + + case OP_STS: /* store selective */ + if ((tr = Ea (IR, &bva, VR, WD)) != 0) /* get eff addr */ + return tr; + if ((tr = ReadW (bva, &opnd, VR)) != 0) /* read word */ + return tr; + res = (opnd & ~R[rn|1]) | (R[rn] & R[rn|1]); /* set under mask */ + if ((tr = WriteW (bva, res, VW)) != 0) /* store */ + return tr; + break; + +/* Note: the Sigma 7 does not prove the instruction can execute successfully + before starting to store registers; the Sigma 9 (and the simulator) do. */ + + case OP_STM: /* store multiple */ + lim = CC? CC: 16; /* CC sets count */ + if ((tr = Ea (IR, &bva, VR, WD)) != 0) /* get eff addr */ + return tr; + if ((tr = ReadW ((bva + ((lim - 1) << 2)) & bvamqrx, &opnd, VW)) != 0) + return tr; /* test writeability */ + for (i = 0; i < lim; i++) { /* loop thru reg */ + if ((tr = WriteW (bva, R[rn], VW)) != 0) /* write reg */ + return tr; + bva = (bva + 4) & bvamqrx; /* next address */ + rn = (rn + 1) & RNMASK; /* next register */ + } + break; + + case OP_STCF: /* store cc, flt */ + if ((tr = Ea (IR, &bva, VR, BY)) != 0) /* get eff addr */ + return tr; + res = (CC << 4) | ((PSW1 >> PSW1_V_FPC) & PSW1_M_FPC); + if ((tr = WriteB (bva, res, VW)) != 0) /* store */ + return tr; + break; + +/* Analyze: Sigma 9 uses <5:7> for trap codes, the 5X0 uses <1:3> */ + + case OP_ANLZ: /* analyze */ + mprot = ((PSW1 & (PSW1_MS|PSW1_MM)) == PSW1_MM) && + ((PSW2 & (PSW2_MA9|PSW2_MA5X0)) != 0); /* mstr prot */ + sc = QCPU_5X0? 4: 0; /* 5X0 vs S9 */ + if ((tr = Ea (IR, &bva, VR, WD)) != 0) { /* get eff address */ + if (mprot && QCPU_S9) { /* S9 mprot? */ + R[rn] = 0x07000000 | (bva >> 2); /* show failure */ + break; + } + return tr; /* others trap */ + } + if ((tr = ReadW (bva, &opnd, VR)) != 0) { /* get word */ + if (mprot) { /* trap, mprot? */ + R[rn] = (0x30000000 >> sc) | (bva >> 2); /* show failure */ + break; + } + return tr; /* others trap */ + } + aop = I_GETOP (opnd); /* get opcode */ + CC = anlz_tab[aop] & (CC1|CC2|CC4); /* set CC1,CC2,CC4 */ + if (TST_IND (opnd)) /* indirect? */ + CC |= CC3; /* set CC3 */ + if ((anlz_tab[aop] & CC4) == 0) { /* mem ref? */ + uint32 aln = anlz_tab[aop] >> 2; /* get length */ + if ((tr = Ea (opnd, &bva, VR, aln)) != 0) { /* get eff addr */ + if (mprot) { /* trap, mprot? */ + R[rn] = (0x10000000 >> sc) | (bva >> 2); /* show failure */ + break; + } + return tr; /* others trap */ + } + R[rn] = bva >> aln; /* cvt addr */ + } + break; + +/* Interpret */ + + case OP_INT: /* interpret */ + if ((tr = Ea (IR, &bva, VR, WD)) != 0) /* get eff addr */ + return tr; + if ((tr = ReadW (bva, &opnd, VR)) != 0) /* get word */ + return tr; + CC = (opnd >> 28) & 0xF; /* <0:3> -> CC */ + R[rn] = (opnd >> 16) & 0xFFF; /* <4:15> -> Rn */ + R[rn|1] = opnd & 0xFFFF; /* <16:31> -> Rn|1 */ + break; + +/* Arithmetic */ + + case OP_AI: /* add immediate */ + if ((tr = ImmOp (IR, &opnd)) != 0) /* get immed opnd */ + return tr; + opnd = SEXT_LIT_W (opnd) & WMASK; /* sext to 32b */ + res = Add32 (R[rn], opnd, 0); /* add, set CC's */ + R[rn] = res; /* store result */ + if ((CC & CC2) && (PSW1 & PSW1_AM)) /* ovfo, enabled? */ + return TR_FIX; + break; + + case OP_AH: /* add halfword */ + if ((tr = Ea (IR, &bva, VR, HW)) != 0) /* get eff addr */ + return tr; + if ((tr = ReadH (bva, &opnd, VR)) != 0) /* read halfword */ + return tr; + opnd = SEXT_H_W (opnd) & WMASK; /* sext to 32b */ + res = Add32 (R[rn], opnd, 0); /* add, set CC's */ + R[rn] = res; /* store result */ + if ((CC & CC2) && (PSW1 & PSW1_AM)) /* ovflo, enabled? */ + return TR_FIX; + break; + + case OP_AW: /* add word */ + if ((tr = Ea (IR, &bva, VR, WD)) != 0) /* get eff addr */ + return tr; + if ((tr = ReadW (bva, &opnd, VR)) != 0) /* read word */ + return tr; + res = Add32 (R[rn], opnd, 0); /* add, set CC's */ + R[rn] = res; /* store result */ + if ((CC & CC2) && (PSW1 & PSW1_AM)) /* ovflo, enabled? */ + return TR_FIX; + break; + + case OP_AD: /* add doubleword */ + if (QCPU_S89_5X0 && (rn & 1)) /* invalid reg? */ + return TR_INVREG; + if ((tr = Ea (IR, &bva, VR, DW)) != 0) /* get eff addr */ + return tr; + if ((tr = ReadD (bva, &opnd, &opnd1, VR)) != 0) /* read doubleword */ + return tr; + res1 = Add32 (R[rn|1], opnd1, 0); /* add low, high */ + res = Add32 (R[rn], opnd, (CC & CC1) != 0); + if ((res == 0) && (res1 != 0)) /* 0'non-zero? */ + CC = (CC & ~CC4) | CC3; /* set CC3 */ + R[rn|1] = res1; /* store */ + R[rn] = res; + if ((CC & CC2) && (PSW1 & PSW1_AM)) /* ovflo, enabled? */ + return TR_FIX; + break; + + case OP_AWM: /* add word to memory */ + if ((tr = Ea (IR, &bva, VR, WD)) != 0) /* get eff addr */ + return tr; + if ((tr = ReadW (bva, &opnd, VR)) != 0) /* read word */ + return tr; + res = Add32 (R[rn], opnd, 0); /* add, set CC's */ + if ((tr = WriteW (bva, res, VW)) != 0) /* store */ + return tr; + if ((CC & CC2) && (PSW1 & PSW1_AM)) /* ovflo, enabled? */ + return TR_FIX; + break; + + case OP_SH: /* subtract halfword */ + if ((tr = Ea (IR, &bva, VR, HW)) != 0) /* get eff addr */ + return tr; + if ((tr = ReadH (bva, &opnd, VR)) != 0) /* read halfword */ + return tr; + opnd = SEXT_H_W (opnd) & WMASK; /* sext to 32b */ + res = Add32 (R[rn], opnd ^ WMASK, 1); /* subtract, set CC's */ + R[rn] = res; /* store */ + if ((CC & CC2) && (PSW1 & PSW1_AM)) /* ovflo, enabled? */ + return TR_FIX; + break; + + case OP_SW: /* subtract word */ + if ((tr = Ea (IR, &bva, VR, WD)) != 0) /* get eff addr */ + return tr; + if ((tr = ReadW (bva, &opnd, VR)) != 0) /* read word */ + return tr; + res = Add32 (R[rn], opnd ^ WMASK, 1); /* subtract */ + R[rn] = res; /* store */ + if ((CC & CC2) && (PSW1 & PSW1_AM)) /* ovflo, enabled? */ + return TR_FIX; + break; + + case OP_SD: /* subtract doubleword */ + if (QCPU_S89_5X0 && (rn & 1)) /* invalid reg? */ + return TR_INVREG; + if ((tr = Ea (IR, &bva, VR, DW)) != 0) /* get eff addr */ + return tr; + if ((tr = ReadD (bva, &opnd, &opnd1, VR)) != 0) /* read doubleword */ + return tr; + res1 = Add32 (R[rn|1], opnd1 ^ WMASK, 1); /* sub low, high */ + res = Add32 (R[rn], opnd ^ WMASK, (CC & CC1) != 0); + if ((res == 0) && (res1 != 0)) /* 0'non-zero? */ + CC = (CC & ~CC4) | CC3; /* set CC3 */ + R[rn|1] = res1; /* store */ + R[rn] = res; + if ((CC & CC2) && (PSW1 & PSW1_AM)) /* ovflo, enabled? */ + return TR_FIX; + break; + + case OP_MI: /* multiply immed */ + if ((tr = ImmOp (IR, &opnd)) != 0) /* get immed opnd */ + return tr; + opnd = SEXT_LIT_W (opnd) & WMASK; /* sext to 32b */ + res = SMul64 (R[rn|1], opnd, &res1); /* 64b product */ + R[rn] = res; /* store */ + R[rn|1] = res1; + break; + + case OP_MH: /* multiply half */ + if ((tr = Ea (IR, &bva, VR, HW)) != 0) /* get eff addr */ + return tr; + if ((tr = ReadH (bva, &opnd, VR)) != 0) /* read halfword */ + return tr; + sop = (int32) SEXT_H_W (R[rn]); /* sext operands */ + sop1 = (int32) SEXT_H_W (opnd); + res = (uint32) ((sop * sop1) & WMASK); /* product */ + CC34_W (res); /* set CC's */ + R[rn|1] = res; /* store */ + break; + + case OP_MW: /* multiply word */ + if ((tr = Ea (IR, &bva, VR, WD)) != 0) /* get eff addr */ + return tr; + if ((tr = ReadW (bva, &opnd, VR)) != 0) /* read word */ + return tr; + res = SMul64 (R[rn|1], opnd, &res1); /* 64b product */ + R[rn] = res; /* store */ + R[rn|1] = res1; + break; + + case OP_DH: /* divide halfword */ + if ((tr = Ea (IR, &bva, VR, HW)) != 0) /* get eff addr */ + return tr; + if ((tr = ReadH (bva, &opnd, VR)) != 0) /* read halfword */ + return tr; + sop = (int32) R[rn]; /* sext operands */ + sop1 = (int32) SEXT_H_W (opnd); + if ((opnd == 0) || /* div by zero? */ + ((R[rn] == WSIGN) && /* -2^31 / -1? */ + (opnd == HMASK))) { + CC |= CC2; /* overflow */ + if (PSW1 & PSW1_AM) /* trap if enabled */ + return TR_FIX; + } + else { + res = (uint32) ((sop / sop1) & WMASK); /* quotient */ + CC &= ~CC2; /* no overflow */ + CC34_W (res); /* set CC's */ + R[rn] = res; /* store */ + } + break; + + case OP_DW: /* divide word */ + if ((tr = Ea (IR, &bva, VR, WD)) != 0) /* get eff addr */ + return tr; + if ((tr = ReadW (bva, &opnd2, VR)) != 0) /* get divisor */ + return tr; + if (rn & 1) /* odd reg? */ + opnd = (R[rn] & WSIGN)? WMASK: 0; /* high is sext low */ + else opnd = R[rn]; + opnd1 = R[rn|1]; /* low divd */ + if (SDiv64 (opnd, opnd1, opnd2, &res, &res1)) { /* 64b/32b divide */ + CC |= CC2; /* overflow, set CC2 */ + if (PSW1 & PSW1_AM) /* trap if enabled */ + return TR_FIX; + } + else { + CC &= ~CC2; /* clear CC2 */ + CC34_W (res); /* set CC's from quo */ + R[rn] = res1; /* store */ + R[rn|1] = res; + } + break; + + case OP_MTB: /* mod and test byte */ + if ((tr = Ea (IR, &bva, VR, BY)) != 0) /* get eff addr */ + return tr; + if ((tr = ReadB (bva, &opnd, VR)) != 0) /* read byte */ + return tr; + opnd1 = SEXT_RN_W (rn) & BMASK; /* mod is sext rn */ + res = (opnd + opnd1) & BMASK; /* do zext add */ + if (res < opnd) /* carry out? */ + CC = CC1; + else CC = 0; + CC34_W (res); /* set cc's */ + if (rn && /* any mod? */ + ((tr = WriteB (bva, res, VW)) != 0)) /* rewrite */ + return tr; + break; + + case OP_MTH: /* mod and test half */ + if ((tr = Ea (IR, &bva, VR, HW)) != 0) /* get eff addr */ + return tr; + if ((tr = ReadH (bva, &opnd, VR)) != 0) /* read halfword */ + return tr; + opnd = opnd & HMASK; /* 16 operands */ + opnd1 = SEXT_RN_W (rn) & HMASK; /* mod is sext rn */ + res = opnd + opnd1; /* 16b add */ + if ((res & HMASK) == 0) /* 16b CC tests */ + CC = 0; + else if (res & HSIGN) + CC = CC4; + else CC = CC3; + if ((res & ~HMASK) != 0) /* carry? */ + CC |= CC1; + if (((opnd ^ ~opnd1) & (opnd ^ res)) & HSIGN) /* set overflow */ + CC |= CC2; + if (rn && /* any mod? */ + ((tr = WriteH (bva, res, VW)) != 0)) /* rewrite */ + return tr; + if ((CC & CC2) && (PSW1 & PSW1_AM)) /* ovflo, enabled? */ + return TR_FIX; + break; + + case OP_MTW: /* mod and test word */ + if ((tr = Ea (IR, &bva, VR, WD)) != 0) /* get eff addr */ + return tr; + if ((tr = ReadW (bva, &opnd, VR)) != 0) /* get word */ + return tr; + opnd1 = SEXT_RN_W (rn) & WMASK; /* mod is sext rn */ + res = Add32 (opnd, opnd1, 0); /* do add */ + if (rn && /* any mod? */ + ((tr = WriteW (bva, res, VW)) != 0)) /* rewrite */ + return tr; + if ((CC & CC2) && (PSW1 & PSW1_AM)) /* ovflo, enabled? */ + return TR_FIX; + break; + +/* Logical */ + + case OP_AND: /* and */ + if ((tr = Ea (IR, &bva, VR, WD)) != 0) /* get eff addr */ + return tr; + if ((tr = ReadW (bva, &opnd, VR)) != 0) /* get word */ + return tr; + res = R[rn] & opnd; + CC34_W (res); /* set CC's */ + R[rn] = res; /* store */ + break; + + case OP_OR: /* or */ + if ((tr = Ea (IR, &bva, VR, WD)) != 0) /* get eff addr */ + return tr; + if ((tr = ReadW (bva, &opnd, VR)) != 0) /* get word */ + return tr; + res = R[rn] | opnd; + CC34_W (res); /* set CC's */ + R[rn] = res; /* store */ + break; + + case OP_EOR: /* xor */ + if ((tr = Ea (IR, &bva, VR, WD)) != 0) /* get eff addr */ + return tr; + if ((tr = ReadW (bva, &opnd, VR)) != 0) /* get word */ + return tr; + res = R[rn] ^ opnd; + CC34_W (res); /* set CC's */ + R[rn] = res; /* store */ + break; + +/* Compares */ + + case OP_CI: /* compare immed */ + if ((tr = ImmOp (IR, &opnd)) != 0) /* get immed opnd */ + return tr; + opnd = SEXT_LIT_W (opnd) & WMASK; /* sext to 32b */ + CC234_CMP (R[rn], opnd); /* set CC's */ + break; + + case OP_CB: /* compare byte */ + if ((tr = Ea (IR, &bva, VR, BY)) != 0) /* get eff addr */ + return tr; + if ((tr = ReadB (bva, &opnd, VR)) != 0) /* read byte */ + return tr; + opnd1 = R[rn] & BMASK; /* zext operand */ + CC234_CMP (opnd1, opnd); /* set CC's */ + break; + + case OP_CH: /* compare halfword */ + if ((tr = Ea (IR, &bva, VR, HW)) != 0) /* get eff addr */ + return tr; + if ((tr = ReadH (bva, &opnd, VR)) != 0) /* read halfword */ + return tr; + opnd = SEXT_H_W (opnd) & WMASK; /* sext to 32b */ + CC234_CMP (R[rn], opnd); /* set CC's */ + break; + + case OP_CW: /* compare word */ + if ((tr = Ea (IR, &bva, VR, WD)) != 0) /* get eff addr */ + return tr; + if ((tr = ReadW (bva, &opnd, VR)) != 0) /* read word */ + return tr; + CC234_CMP (R[rn], opnd); /* set CC's */ + break; + + case OP_CD: /* compare double */ + if ((tr = Ea (IR, &bva, VR, DW)) != 0) /* get eff addr */ + return tr; + if ((tr = ReadD (bva, &opnd, &opnd1, VR)) != 0) /* read doubleword */ + return tr; + CC &= ~(CC3|CC4); + if (R[rn] != opnd) /* hi unequal? */ + CC |= Cmp32 (R[rn], opnd); + else if (R[rn|1] != opnd1) /* low unequal? */ + CC |= (R[rn|1] < opnd1)? CC4: CC3; /* like signs */ + break; + + case OP_CS: /* compare select */ + if ((tr = Ea (IR, &bva, VR, WD)) != 0) /* get eff addr */ + return tr; + if ((tr = ReadW (bva, &opnd, VR)) != 0) /* read word */ + return tr; + opnd1 = R[rn] & R[rn|1]; /* mask operands */ + opnd = opnd & R[rn|1]; + if (opnd1 < opnd) /* unsigned compare */ + CC = (CC & ~CC3) | CC4; + else if (opnd1 > opnd) + CC = (CC & ~CC4) | CC3; + else CC &= ~(CC3|CC4); + break; + + case OP_CLR: /* compare limit reg */ + if ((tr = Ea (IR, &bva, VR, WD)) != 0) /* get eff addr */ + return tr; + if ((tr = ReadW (bva, &opnd, VR)) != 0) /* read word */ + return tr; + CC = Cmp32 (R[rn], opnd) | /* compare high reg */ + (Cmp32 (R[rn|1], opnd) << 2); /* compare low reg */ + break; + + case OP_CLM: /* compare limit mem */ + if ((tr = Ea (IR, &bva, VR, DW)) != 0) /* get eff addr */ + return tr; + if ((tr = ReadD (bva, &opnd, &opnd1, VR)) != 0) /* get doubleword */ + return tr; + CC = Cmp32 (R[rn], opnd) | /* compare high mem */ + (Cmp32 (R[rn], opnd1) << 2); /* compare low mem */ + break; + +/* Shift and convert instructions */ + + case OP_S: /* shift */ + if ((tr = EaSh (IR, &stype, &sc)) != 0) /* get type, count */ + return tr; + if ((stype >= 0x6) && QCPU_S567) /* invalid, S5-7? */ + stype = 0x4; /* treat as arith */ + CC = (CC & ~(CC1|CC2|CC4)) | /* shift, set CC's */ + Shift (rn, stype, sc); + break; + + case OP_SF: /* shift floating */ + if ((tr = EaSh (IR, &stype, &sc)) != 0) /* get type, count */ + return tr; + ShiftF (rn, stype & 1, sc); /* shift, set CC's */ + break; + + case OP_CVA: /* cvt by addition */ + if (QCPU_S5) /* not on Sigma 5 */ + return TR_NXI; + if ((tr = Ea (IR, &bva, VR, WD)) != 0) /* get eff addr */ + return tr; + CC &= ~CC1; /* clear CC1 (carry) */ + for (i = 0, res = 0; i < 32; i++) { /* 32 iterations */ + if ((R[rn|1] >> (31 - i)) & 1) { /* bit set? */ + uint32 ad = (bva + (i << 2)) & bvamqrx; /* table offset */ + if ((tr = ReadW (ad, &opnd, VR)) != 0) + return tr; /* read table word */ + res = (res + opnd) & WMASK; /* add into result */ + if (res < opnd) /* carry? set CC1 */ + CC |= CC1; + } /* end bit set */ + } /* end for */ + CC34_W (res); /* set CC's */ + R[rn] = res; /* store */ + break; + + case OP_CVS: /* cvt by subtraction */ + if (QCPU_S5) /* not on Sigma 5 */ + return TR_NXI; + if ((tr = Ea (IR, &bva, VR, WD)) != 0) /* get eff addr */ + return tr; + for (i = 0, res = R[rn], res1 = 0; i < 32; i++) { /* 32 iterations */ + uint32 ad = (bva + (i << 2)) & bvamqrx; /* table offset */ + if ((tr = ReadW (ad, &opnd, VR)) != 0) /* read table word */ + return tr; + if (opnd <= res) { /* residue >= entry? */ + res = (res - opnd) & WMASK; /* subtract entry */ + res1 |= 1u << (31 - i); /* set bit */ + } + } + CC34_W (res1); /* set CC's */ + R[rn] = res; /* store */ + R[rn|1] = res1; + break; + +/* Push down instructions */ + + case OP_PSW: /* push word */ + if ((tr = Ea (IR, &bva, VR, DW)) != 0) /* get eff addr */ + return tr; + if ((tr = ReadD (bva, &opnd, &opnd1, VW)) != 0) /* read stack ptr */ + return tr; + if ((tr = TestSP1 (opnd1, 1)) != 0) /* will push work? */ + return ((tr & WSIGN)? 0: tr); + if ((tr = WriteW (((opnd + 1) << 2) & bvamqrx, R[rn], VW)) != 0) + return tr; /* push word */ + if ((tr = ModWrSP (bva, opnd, opnd1, 1)) != 0) /* mod, rewrite sp */ + return tr; + break; + + case OP_PLW: /* pull word */ + if ((tr = Ea (IR, &bva, VR, DW)) != 0) /* get eff addr */ + return tr; + if ((tr = ReadD (bva, &opnd, &opnd1, VW)) != 0) /* read stack ptr */ + return tr; + if ((tr = TestSP1 (opnd1, -1)) != 0) /* will pull work? */ + return ((tr & WSIGN)? 0: tr); + if ((tr = ReadW (opnd << 2, &res, VR)) != 0) /* pull word */ + return tr; + if ((tr = ModWrSP (bva, opnd, opnd1, -1)) != 0) /* mod, rewrite sp */ + return tr; + R[rn] = res; + break; + + case OP_PSM: /* push multiple */ + if ((tr = Ea (IR, &bva, VR, DW)) != 0) /* get eff addr */ + return tr; + if ((tr = ReadD (bva, &opnd, &opnd1, VW)) != 0) /* read stack ptr */ + return tr; + lim = CC? CC: 16; /* words to push */ + if ((tr = TestSP1 (opnd1, lim)) != 0) /* will push work? */ + return ((tr & WSIGN)? 0: tr); + if ((tr = ReadW (((opnd + lim) << 2) & bvamqrx, &res, VW)) != 0) + return tr; /* will last work? */ + for (i = 0; i < lim; i++) { /* loop thru reg */ + if ((tr = WriteW (((opnd + i + 1) << 2) & bvamqrx, R[rn], VW)) != 0) + return tr; /* push word */ + rn = (rn + 1) & RNMASK; + } + if ((tr = ModWrSP (bva, opnd, opnd1, lim)) != 0) /* mod, rewrite sp */ + return tr; + break; + + case OP_PLM: /* pull multiple */ + if ((tr = Ea (IR, &bva, VR, DW)) != 0) /* get eff addr */ + return tr; + if ((tr = ReadD (bva, &opnd, &opnd1, VW)) != 0) /* read stack ptr */ + return tr; + lim = CC? CC: 16; /* words to pull */ + if ((tr = TestSP1 (opnd1, -((int32)lim))) != 0) /* will pull work? */ + return ((tr & WSIGN)? 0: tr); + rn = (rn + lim - 1) & RNMASK; + if ((tr = ReadW (((opnd - (lim - 1)) << 2) & bvamqrx, &res, VR)) != 0) + return tr; /* will last work? */ + for (i = 0; i < lim; i++) { /* loop thru reg */ + if ((tr = ReadW (((opnd - i) << 2) & bvamqrx, &res, VR)) != 0) + return tr; /* pull word */ + R[rn] = res; + rn = (rn - 1) & RNMASK; + } + if ((tr = ModWrSP (bva, opnd, opnd1, -((int32) lim))) != 0) + return tr; + break; + + case OP_MSP: /* modify stack ptr */ + if ((tr = Ea (IR, &bva, VR, DW)) != 0) /* get eff addr */ + return tr; + if ((tr = ReadD (bva, &opnd, &opnd1, VW)) != 0) /* read stack ptr */ + return tr; + sop = SEXT_H_W (R[rn]); /* get modifier */ + if ((tr = TestSP1 (opnd1, sop)) != 0) /* will mod work? */ + return ((tr & WSIGN)? 0: tr); + if ((tr = ModWrSP (bva, opnd, opnd1, sop)) != 0) /* mod, rewrite sp */ + return tr; + break; + +/* Control instructions */ + + case OP_EXU: /* execute */ + if (exu_cnt++ > exu_lim) /* too many? */ + return STOP_EXULIM; + if ((tr = Ea (IR, &bva, VR, WD)) != 0) /* get eff addr */ + return tr; + if ((tr = ReadW (bva, &opnd, VR)) != 0) /* read word */ + return tr; + IR = opnd; /* new instruction */ + goto EXU_LOOP; + + case OP_BCS: /* branch cond set */ + if ((tr = Ea (IR, &bva, VR, WD)) != 0) /* get eff addr */ + return tr; + if ((CC & rn) != 0) { /* branch taken? */ + if ((tr = ReadW (bva, &opnd, VI)) != 0) /* new PC readable? */ + return tr; + PCQ_ENTRY; + PC = cpu_new_PC (bva); /* branch */ + } + break; + + case OP_BCR: /* branch cond reset */ + if ((tr = Ea (IR, &bva, VR, WD)) != 0) /* get eff addr */ + return tr; + if ((CC & rn) == 0) { /* branch taken? */ + if ((tr = ReadW (bva, &opnd, VI)) != 0) /* new PC readable? */ + return tr; + PCQ_ENTRY; + PC = cpu_new_PC (bva); /* branch */ + } + break; + + case OP_BIR: /* branch incr reg */ + if ((tr = Ea (IR, &bva, VR, WD)) != 0) /* get eff addr */ + return tr; + res = (R[rn] + 1) & WMASK; /* ++R[rn] */ + if ((res & WSIGN) != 0) { /* < 0? */ + if ((tr = ReadW (bva, &opnd, VI)) != 0) /* new PC readable? */ + return tr; + PCQ_ENTRY; + PC = cpu_new_PC (bva); /* branch */ + } + R[rn] = res; /* actual increment */ + break; + + case OP_BDR: /* branch decr reg */ + if ((tr = Ea (IR, &bva, VR, WD)) != 0) /* get eff addr */ + return tr; + res = (R[rn] - 1) & WMASK; /* --R[rn] */ + if (((res & WSIGN) == 0) && (res != 0)) { /* > 0? */ + if ((tr = ReadW (bva, &opnd, VI)) != 0) /* new PC readable? */ + return tr; + PCQ_ENTRY; + PC = cpu_new_PC (bva); /* branch */ + } + R[rn] = res; /* actual decrement */ + break; + + case OP_BAL: /* branch and link */ + if ((tr = Ea (IR, &bva, VR, WD)) != 0) /* get eff addr */ + return tr; + if ((tr = ReadW (bva, &opnd, VI)) != 0) /* new PC readable? */ + return tr; + R[rn] = cpu_add_PC (real_pc, 1); /* save incr PC */ + PCQ_ENTRY; + PC = cpu_new_PC (bva); /* branch */ + break; + + case OP_CAL1: /* CALL 1 */ + return TR_C1 (rn); + + case OP_CAL2: /* CALL 2 */ + return TR_C2 (rn); + + case OP_CAL3: /* CALL 3 */ + return TR_C3 (rn); + + case OP_CAL4: /* CALL 4 */ + return TR_C4 (rn); + +/* Privileged instructions */ + + case OP_MMC: /* MMC */ + if (PSW1 & PSW1_MS) /* slave mode? */ + return TR_PRV; + if (TST_IND (IR) && /* indirect? */ + ((tr = ReadW (I_GETADDR (IR) << 2, &opnd, VNT)) != 0)) + return tr; + return map_mmc (rn, I_GETXR (IR)); + + case OP_LPSD: /* load PSD */ + if (PSW1 & PSW1_MS) /* slave mode? */ + return TR_PRV; + if ((tr = Ea (IR, &bva, VR, DW)) != 0) /* get eff addr */ + return tr; + if ((tr = ReadD (bva, &opnd, &opnd1, VR)) != 0) /* read stack ptr */ + return tr; + if ((tr = cpu_new_PSD (IR & IRB (8), opnd, opnd1)) != 0) + return tr; + PCQ_ENTRY; /* no traps, upd PCQ */ + if (IR & IRB (10)) /* clr hi pri int? */ + int_hireq = io_rels_int (int_hiact, IR & IRB (11)); + else if (IR & IRB (11)) /* clr PDF flag? */ + cpu_pdf = 0; + break; + + case OP_XPSD: /* exchange PSD */ + if (PSW1 & PSW1_MS) /* slave mode? */ + return TR_PRV; + if ((tr = Ea (IR, &bva, VR, DW)) != 0) /* get eff addr */ + return tr; + if ((tr = cpu_xpsd (IR & ~IRB (11), bva, VR)) != 0) /* do XPSD */ + return tr; + PCQ_ENTRY; /* no traps, upd PCQ */ + break; + + case OP_LRP: + if (PSW1 & PSW1_MS) /* slave mode? */ + return TR_PRV; + if ((tr = Ea (IR, &bva, VR, WD)) != 0) /* get eff addr */ + return tr; + if ((tr = ReadW (bva, &opnd, VR)) != 0) /* read word */ + return tr; + return cpu_new_RP (opnd); /* update RP */ + + case OP_RD: /* direct I/O */ + case OP_WD: + if (PSW1 & PSW1_MS) /* slave mode? */ + return TR_PRV; + if ((tr = Ea (IR, &bva, VR, WD)) != 0) /* get eff addr */ + return tr; + if ((tr = io_rwd (op, rn, bva)) != 0) /* do direct I/O */ + return tr; + int_hiact = io_actv_int (); /* re-eval active */ + int_hireq = io_eval_int (); /* re-eval intr */ + break; + + case OP_WAIT: /* wait for int */ + if (PSW1 & PSW1_MS) /* slave mode? */ + return TR_PRV; + if ((tr = Ea (IR, &bva, VR, WD)) != 0) /* get eff addr */ + return tr; + if (!io_poss_int ()) /* intr possible? */ + return STOP_WAITNOINT; /* machine is hung */ +// put idle here + int_hireq = io_eval_int (); /* re-eval intr */ + break; + + case OP_AIO: /* acknowledge int */ + if (PSW1 & PSW1_MS) /* slave mode? */ + return TR_PRV; + if ((tr = Ea (IR, &bva, VR, WD)) != 0) /* get eff addr */ + return tr; + if ((tr = io_aio (rn, bva)) != 0) /* do AIO */ + return tr; + int_hireq = io_eval_int (); /* re-eval intr */ + break; + + case OP_SIO: /* start IO */ + if (PSW1 & PSW1_MS) /* slave mode? */ + return TR_PRV; + if ((tr = Ea (IR, &bva, VR, WD)) != 0) /* get eff addr */ + return tr; + if ((tr = io_sio (rn, bva)) != 0) /* do SIO */ + return tr; + int_hireq = io_eval_int (); /* re-eval intr */ + break; + + case OP_HIO: /* halt IO */ + if (PSW1 & PSW1_MS) /* slave mode? */ + return TR_PRV; + if ((tr = Ea (IR, &bva, VR, WD)) != 0) /* get eff addr */ + return tr; + if ((tr = io_hio (rn, bva)) != 0) /* do HIO */ + return tr; + int_hireq = io_eval_int (); /* re-eval intr */ + break; + + case OP_TIO: /* test IO */ + if (PSW1 & PSW1_MS) /* slave mode? */ + return TR_PRV; + if ((tr = Ea (IR, &bva, VR, WD)) != 0) /* get eff addr */ + return tr; + if ((tr = io_tio (rn, bva)) != 0) /* do AIO */ + return tr; + int_hireq = io_eval_int (); /* re-eval intr */ + break; + + case OP_TDV: /* test device */ + if (PSW1 & PSW1_MS) /* slave mode? */ + return TR_PRV; + if ((tr = Ea (IR, &bva, VR, WD)) != 0) /* get eff addr */ + return tr; + if ((tr = io_tdv (rn, bva)) != 0) /* do I/O */ + return tr; + int_hireq = io_eval_int (); /* re-eval intr */ + break; + + case OP_LRA: /* load real addr */ + if (QCPU_S89_5X0) { /* late models only */ + if (PSW1 & PSW1_MS) /* slave mode? */ + return TR_PRV; + return map_lra (rn, IR); /* in map */ + } + return (PSW1 & PSW1_MS)? TR_NXI|TR_PRV: TR_NXI; + + case OP_LMS: /* load mem system */ + if ((cpu_unit.flags & CPUF_LAMS) == 0) /* implemented? */ + return (PSW1 & PSW1_MS)? TR_NXI|TR_PRV: TR_NXI; + if ((tr = Ea (IR, &bva, VR, WD)) != 0) /* get eff addr */ + return tr; + if (QCPU_S567) /* old CPU? */ + R[rn] = IR; /* loads inst to IR */ + else if (PSW1 & PSW1_MS) /* slave mode? */ + return TR_PRV; + else return map_lms (rn, bva); /* in map */ + break; + + case OP_PSS: /* push status */ + if (QCPU_5X0) { /* 5X0 only */ + if (PSW1 & PSW1_MS) /* slave mode? */ + return TR_PRV; + if ((tr = Ea (IR, &bva, VR, DW)) != 0) /* get eff addr */ + return tr; + if ((tr = cpu_pss (IR, bva, VR)) != 0) /* push status */ + return tr; + PCQ_ENTRY; + break; + } + return (PSW1 & PSW1_MS)? TR_NXI|TR_PRV: TR_NXI; + + case OP_PLS: /* pull status */ + if (QCPU_5X0) { /* 5X0 only */ + if (PSW1 & PSW1_MS) /* slave mode? */ + return TR_PRV; + if ((tr = cpu_pls (IR)) != 0) /* pull status */ + return tr; + PCQ_ENTRY; + break; + } + return (PSW1 & PSW1_MS)? TR_NXI|TR_PRV: TR_NXI; + +/* String instructions */ + + case OP_MBS: /* move byte string */ + if ((cpu_unit.flags & CPUF_STR) == 0) /* not implemented? */ + return TR_UNI; + if ((tr = ImmOp (IR, &opnd)) != 0) /* get immed opnd */ + return tr; + opnd = SEXT_LIT_W (opnd) & WMASK; /* sign extend */ + if ((cnt = S_GETMCNT (R[rn|1])) != 0) { /* any move? */ + sa = (opnd + (rn? R[rn] + cnt - 1: 0)) & bvamqrx; /* last src addr */ + da = (R[rn|1] + cnt - 1) & bvamqrx; /* last dst addr */ + if (((tr = ReadB (sa, &c, VR)) != 0) || /* test last bytes */ + ((tr = ReadB (da, &c, VW)) != 0)) + return tr; + } + while (S_GETMCNT (R[rn|1])) { /* while count */ + sa = (opnd + (rn? R[rn]: 0)) & bvamqrx; /* src addr */ + da = R[rn|1] & bvamqrx; /* dst addr */ + if ((tr = ReadB (sa, &c, VR)) != 0) /* read src */ + return tr; + if ((tr = WriteB (da, c, VW)) != 0) /* write dst */ + return tr; + if (rn && !(rn & 1)) /* rn even, > 0? */ + R[rn] = (R[rn] + 1) & WMASK; /* inc saddr */ + R[rn|1] = (R[rn|1] + S_ADDRINC) & WMASK; /* inc daddr, dec cnt */ + } + break; + + case OP_CBS: /* compare byte str */ + if ((cpu_unit.flags & CPUF_STR) == 0) /* not implemented? */ + return TR_UNI; + if ((tr = ImmOp (IR, &opnd)) != 0) /* get immed opnd */ + return tr; + opnd = SEXT_LIT_W (opnd) & WMASK; /* sign extend */ + if ((cnt = S_GETMCNT (R[rn|1])) != 0) { /* any compare? */ + sa = (opnd + (rn? R[rn] + cnt - 1: 0)) & bvamqrx; /* last src addr */ + da = (R[rn|1] + cnt - 1) & bvamqrx; /* last dst addr */ + if (((tr = ReadB (sa, &c, VR)) != 0) || /* test last bytes */ + ((tr = ReadB (da, &c, VR)) != 0)) + return tr; + } + CC = CC & ~(CC3|CC4); /* assume equal */ + while (S_GETMCNT (R[rn|1])) { /* while count */ + sa = (opnd + (rn? R[rn]: 0)) & bvamqrx; /* src addr */ + da = R[rn|1] & bvamqrx; /* dst addr */ + if ((tr = ReadB (sa, &c, VR)) != 0) /* read src */ + return tr; + if ((tr = ReadB (da, &c1, VR)) != 0) /* read dst */ + return tr; + if (c != c1) { /* not a match */ + CC |= ((c < c1)? CC4: CC3); + break; /* set CC's, done */ + } + if (rn && !(rn & 1)) /* rn even, > 0? */ + R[rn] = (R[rn] + 1) & WMASK; /* inc saddr */ + R[rn|1] = (R[rn|1] + S_ADDRINC) & WMASK; /* inc daddr, dec cnt */ + } + break; + + case OP_TBS: /* xlate byte string */ + if ((cpu_unit.flags & CPUF_STR) == 0) /* not implemented? */ + return TR_UNI; + if (QCPU_S89_5X0 && (rn & 1)) /* invalid reg? */ + return TR_INVREG; + if ((tr = ImmOp (IR, &opnd)) != 0) /* get immed opnd */ + return tr; + opnd = SEXT_LIT_W (opnd) & WMASK; /* sign extend */ + if ((cnt = S_GETMCNT (R[rn|1])) != 0) { /* any translate? */ + da = (R[rn] + cnt - 1) & bvamqrx; /* last dst addr */ + if ((tr = ReadB (da, &c, VW)) != 0) /* test last byte */ + return tr; + } + while (S_GETMCNT (R[rn|1])) { /* while count */ + sa = (opnd + (rn? R[rn]: 0)) & bvamqrx; /* src addr */ + da = R[rn|1] & bvamqrx; /* dst addr */ + if ((tr = ReadB (da, &c, VR)) != 0) /* read dst */ + return tr; + if ((tr = ReadB ((sa + c) & bvamqrx, &c1, VR)) != 0) + return tr; /* translate byte */ + if ((tr = WriteB (da, c1, VW)) != 0) /* write dst */ + return tr; + R[rn|1] = (R[rn|1] + S_ADDRINC) & WMASK; /* inc daddr, dec cnt */ + } + break; + + case OP_TTBS: /* xlate, test string */ + if ((cpu_unit.flags & CPUF_STR) == 0) /* not implemented? */ + return TR_UNI; + if (QCPU_S89_5X0 && (rn & 1)) /* invalid reg? */ + return TR_INVREG; + if ((tr = ImmOp (IR, &opnd)) != 0) /* get immed opnd */ + return tr; + opnd = SEXT_LIT_W (opnd) & WMASK; /* sign extend */ + mask = rn? S_GETMCNT (R[rn]): 0xFF; /* get mask */ + if ((cnt = S_GETMCNT (R[rn|1])) != 0) { /* any translate? */ + da = (R[rn] + cnt - 1) & bvamqrx; /* last dst addr */ + if ((tr = ReadB (da, &c, VR)) != 0) /* test last byte */ + return tr; + } + CC &= ~CC4; /* clear CC4 */ + while (S_GETMCNT (R[rn|1])) { /* while count */ + sa = (opnd + (rn? R[rn]: 0)) & bvamqrx; /* src addr */ + da = R[rn|1] & bvamqrx; /* dst addr */ + if ((tr = ReadB (da, &c, VR)) != 0) /* read dst */ + return tr; + if ((tr = ReadB ((sa + c) & bvamqrx, &c1, VR)) != 0) + return tr; /* translate byte */ + if ((t = c1 & mask) != 0) { /* byte & mask != 0? */ + if (rn) /* if !r0, repl mask */ + R[rn] = (R[rn] & ~S_MCNT) | (t << S_V_MCNT); + CC |= CC4; /* set CC4, stop */ + break; + } + R[rn|1] = (R[rn|1] + S_ADDRINC) & WMASK; /* inc daddr, dec cnt */ + } + break; + +/* Optional floating point instructions */ + + case OP_FAS: + case OP_FSS: + case OP_FMS: + case OP_FDS: /* short fp */ + if((cpu_unit.flags & CPUF_FP) == 0) /* option present? */ + return TR_UNI; + if ((tr = Ea (IR, &bva, VR, WD)) != 0) /* get eff addr */ + return tr; + return fp (op, rn, bva); /* go process */ + + case OP_FAL: + case OP_FSL: + case OP_FML: + case OP_FDL: /* long fp */ + if (QCPU_S89_5X0 && (rn & 1)) /* invalid reg? */ + return TR_INVREG; + if((cpu_unit.flags & CPUF_FP) == 0) /* option present? */ + return TR_UNI; + if ((tr = Ea (IR, &bva, VR, DW)) != 0) /* get eff addr */ + return tr; + return fp (op, rn, bva); /* go process */ + +/* Optional decimal instructions */ + + case OP_DL: + case OP_DST: + case OP_DA: + case OP_DS: + case OP_DM: + case OP_DD: + case OP_DC: + case OP_DSA: + case OP_PACK: + case OP_UNPK: /* decimal */ + if((cpu_unit.flags & CPUF_DEC) == 0) /* option present? */ + return TR_UNI; + if ((tr = Ea (IR, &bva, VR, BY)) != 0) /* get eff addr */ + return tr; + if ((tr = cis_dec (op, rn, bva)) & WSIGN) /* process, abort? */ + return 0; + else return tr; + + case OP_EBS: /* edit byte string */ + if ((tr = ImmOp (IR, &opnd)) != 0) /* get immed opnd */ + return tr; + if ((cpu_unit.flags & CPUF_DEC) == 0) /* option present? */ + return TR_UNI; + if (QCPU_S89_5X0 && ((rn == 0) || (rn & 1))) /* invalid reg? */ + return TR_INVREG; + if ((tr = cis_ebs (rn, opnd)) & WSIGN) /* process, abort? */ + return 0; + else return tr; + + default: /* undefined inst */ + return (stop_op? STOP_ILLEG: TR_NXI); + } +return 0; +} + +/* Execute MTx in an interrupt location + + Sigma 5/6/7/8 - 17b virtual or real addressing + Sigma 9/5X0 - 17b virtual or 20b real addressing, no indexing + + acc is either PH (physical) or VNT (no traps) + Memory map traps are suppressed, NXM's cause undefined behavior + (returns a nested trap fault) */ + +uint32 cpu_int_mtx (uint32 vec, uint32 *res) +{ +uint32 IR, bva, wd, op, rn, lnt, acc; + +ReadPW (vec, &IR); /* get instruction */ +op = I_GETOP (IR); /* get op */ +lnt = 3 - (op >> 5); /* 73, 53, 33 */ +acc = (vec == VEC_C4P)? VNT: PH; /* access */ +rn = I_GETRN (IR); /* register */ +if (hst_lnt) /* if history */ + inst_hist (IR, PC, H_ITRP); /* record inst */ +if ((acc || QCPU_S567)? /* virt or S5-7? */ + (Ea (IR, &bva, acc, lnt) != 0): /* get eff addr */ + (EaP20 (IR, &bva, lnt) != 0)) /* get real addr */ + return TR_NESTED; + + switch (lnt) { + case BY: + if (ReadB (bva, &wd, acc) != 0) /* read byte */ + return TR_NESTED; + wd = (wd + SEXT_RN_W (rn)) & BMASK; /* modify */ + if (rn && (WriteB (bva, wd, acc) != 0)) /* if mod, rewrite */ + return TR_NESTED; + break; + case HW: + if (ReadH (bva, &wd, acc) != 0) /* read halfword */ + return TR_NESTED; + wd = (wd + SEXT_RN_W (rn)) & HMASK; /* modify */ + if (rn && (WriteB (bva, wd, acc) != 0)) /* if mod, rewrite */ + return TR_NESTED; + break; + case WD: + if (ReadW (bva, &wd, acc) != 0) /* read word */ + return TR_NESTED; + wd = (wd + SEXT_RN_W (rn)) & WMASK; /* modify */ + if (rn && (WriteW (bva, wd, acc) != 0)) /* if mod, rewrite */ + return TR_NESTED; + break; + } + +*res = wd; +return 0; +} + +/* Execute XSPD or PSS in trap or interrupt location */ + +uint32 cpu_trap_or_int (uint32 vec) +{ +uint32 IR, op, bva, acc, cc; + +ReadPW (TR_GETVEC (vec), &IR); /* read vector */ +op = I_GETOP (IR); /* get op */ +if (hst_lnt) { /* if history */ + if (vec & TR_FL) /* trap? */ + hst[hst_p].typ_cc_pc |= H_ABRT; /* mark prev abt */ + inst_hist (IR, PC, H_ITRP); /* record inst */ + } +if (vec & TR_FL) { /* trap? */ + if (QCPU_S89) /* Sigma 89? */ + PSW2 = (PSW2 & ~PSW2_TSF) | ((vec & PSW2_M_TSF) << PSW2_V_TSF); + if (vec == TR_INVRPN) /* non-trap reg ptr? */ + vec = TR_INVRPT; /* cvt to trapped */ + if (vec & TR_PDF) /* trap sets PDF? */ + cpu_pdf = 1; + } +if (op == OP_XPSD) { /* XPSD? */ + acc = (IR & IRB (10))? VNT: PH; /* virt vs phys */ + if ((acc || QCPU_S567)? /* virt or S5-7? */ + (Ea (IR, &bva, acc, DW) != 0): /* get eff addr */ + (EaP20 (IR, &bva, DW) != 0)) /* get real addr */ + return TR_NESTED; + if (cpu_xpsd (IR, bva, acc) != 0) /* do XPSD */ + return TR_NESTED; + if ((cc = TR_GETCC (vec)) != 0) { /* modify CC's? */ + CC = CC | cc; /* modify new CC's */ + if (IR & IRB (9)) /* and maybe new PC */ + PC = cpu_add_PC (PC, cc); + } + return 0; + } +if (QCPU_5X0 && (op == OP_PSS)) { /* 5X0 PSS? */ + if (EaP20 (IR, &bva, DW) != 0) /* get real addr */ + return TR_NESTED; + if (cpu_pss (IR, bva, PH)) /* do PSS */ + return TR_NESTED; + } +return TR_INVTRP; +} + +/* Immediate operand */ + +uint32 ImmOp (uint32 IR, uint32 *imm) +{ +if (TST_IND (IR)) /* indirect traps */ + return TR_NXI; +*imm = I_GETLIT (IR); +if (hst_lnt) /* record history */ + hst[hst_p].ea = hst[hst_p].op = *imm; +return 0; +} + +/* Calculate effective address for normal instructions + Note that in the event of a failure reading the ind addr, + Ea must return that value in bva (for ANLZ) */ + +uint32 Ea (uint32 IR, uint32 *bva, uint32 acc, uint32 lnt) +{ +uint32 ad, xr, wd; +uint32 tr; + +xr = I_GETXR (IR); /* get index reg */ +ad = I_GETADDR (IR) << 2; /* get byte address */ +if (TST_IND (IR)) { /* indirect */ + if ((tr = ReadW (ad, &wd, acc)) != 0) { /* read ind word */ + *bva = ad; /* err? return addr */ + return tr; + } + if (PSW_QRX9 && (wd & WSIGN)) { /* S9 real ext special? */ + wd = wd & VAMASK; /* use only 17b */ + ad = (wd & PSW1_XA)? /* extended word? */ + (PSW2 & PSW2_EA) | (wd & ~PSW1_XA): wd; + ad = ad << 2; + } + else ad = (wd & bvamqrx) << 2; /* get byte address */ + } +*bva = (ad + (xr? (R[xr] << lnt): 0)) & bvamqrx; /* index, mask */ +if (hst_lnt) { /* history? */ + hst[hst_p].ea = *bva; + ReadHist (*bva, &hst[hst_p].op, &hst[hst_p].op1, acc? VNT: PH, lnt); + } +return 0; +} + +/* Calculate effective address for 20b interrupt/trap instructions */ + +uint32 EaP20 (uint32 IR, uint32 *bva, uint32 lnt) +{ +uint32 pa, wd; + +pa = I_GETADDR20 (IR); /* get 20b ref addr */ +if (TST_IND (IR)) { /* indirect? */ + if (ReadPW (pa, &wd)) { /* valid? */ + *bva = pa << 2; + return TR_NXM; + } + pa = wd & cpu_tab[cpu_model].pamask; /* get indirect */ + } +*bva = pa << 2; +if (hst_lnt) { /* history? */ + hst[hst_p].ea = *bva; + ReadHist (*bva, &hst[hst_p].op, &hst[hst_p].op1, PH, lnt); + } +return 0; +} + +/* Calculate effective address for shift */ + +uint32 EaSh (uint32 IR, uint32 *stype, uint32 *sc) +{ +uint32 ad, xr, wd, tr; + +xr = I_GETXR (IR); /* get index reg */ +ad = I_GETADDR (IR); /* get word addr */ +if (TST_IND (IR)) { /* indirect? */ + if ((tr = ReadW (ad << 2, &wd, VR)) != 0) /* read ind word */ + return tr; + ad = I_GETADDR (wd); /* get word addr */ + } +if (xr) + ad = (ad & ~SHF_M_SC) | ((ad + R[xr]) & SHF_M_SC); /* indexing? */ +*stype = SHF_GETSOP (ad); /* extract type */ +*sc = SHF_GETSC (ad); /* extract count */ +if (hst_lnt) { + hst[hst_p].ea = ad << 2; + hst[hst_p].op = ad; + } +return 0; +} + +/* Shift routines */ + +uint32 Shift (uint32 rn, uint32 stype, uint32 sc) +{ +uint32 i, opnd, opnd1, t, cc; + +opnd = R[rn]; /* get operand(s) */ +opnd1 = R[rn|1]; +cc = CC & CC4; + +if (sc & SCSIGN) { /* right? */ + sc = SHF_M_SC + 1 - sc; + switch (stype) { + + case 0x0: /* right log sgl */ + if (sc > 31) /* >31? res = 0 */ + R[rn] = 0; + else R[rn] = R[rn] >> sc; + break; + + case 0x1: /* right log dbl */ + if (sc > 63) /* >63? res = 0 */ + opnd = opnd1 = 0; + else if (sc > 31) { /* >31? */ + sc = sc - 32; + opnd1 = opnd >> sc; + opnd = 0; + } + else { + opnd1 = ((opnd1 >> sc) | (opnd << (32 - sc))) & WMASK; + opnd = opnd >> sc; + } + R[rn|1] = opnd1; + R[rn] = opnd; + break; + + case 0x2: /* right circ sgl */ + sc = sc % 32; /* mod 32 */ + R[rn] = ((R[rn] >> sc) | (R[rn] << (32 - sc))) & WMASK; + break; + + case 0x3: /* right circ dbl */ + sc = sc % 64; /* mod 64 */ + t = opnd; + if (sc > 31) { /* >31? */ + sc = sc - 32; + opnd = ((opnd1 >> sc) | (opnd << (32 - sc))) & WMASK; + opnd1 = ((t >> sc) | (opnd1 << (32 - sc))) & WMASK; + } + else { + opnd = ((opnd >> sc) | (opnd1 << (32 - sc))) & WMASK; + opnd1 = ((opnd1 >> sc) | (t << (32 - sc))) & WMASK; + } + R[rn|1] = opnd1; + R[rn] = opnd; + break; + + case 0x4: /* right arith sgl */ + t = (R[rn] & WSIGN)? WMASK: 0; + if (sc > 31) /* >31? res = sign */ + R[rn] = t; + else R[rn] = ((R[rn] >> sc) | (t << (32 - sc))) & WMASK; + break; + + case 0x5: /* right arith dbl */ + t = (R[rn] & WSIGN)? WMASK: 0; + if (sc > 63) /* >63? res = sign */ + opnd = opnd1 = t; + else if (sc > 31) { /* >31? */ + sc = sc - 32; + opnd1 = ((opnd >> sc) | (t << (32 - sc))) & WMASK; + opnd = t; + } + else { + opnd1 = ((opnd1 >> sc) | (opnd << (32 - sc))) & WMASK; + opnd = ((opnd >> sc) | (t << (32 - sc))) & WMASK; + } + R[rn|1] = opnd1; + R[rn] = opnd; + break; + + case 0x6: /* right search sgl */ + for (i = 0; (i < sc) && !(opnd & WSIGN); i++) { + opnd = ((opnd >> 1) | (opnd << 31)) & WMASK; + } + cc = (opnd & WSIGN)? (cc | CC4): (cc & ~CC4); + R[rn] = opnd; + R[1] = sc - i; + break; + + case 0x7: /* right search dbl */ + for (i = 0; (i < sc) & !(opnd & WSIGN); i++) { + t = opnd; + opnd = ((opnd >> 1) | (opnd1 << 31)) & WMASK; + opnd1 = ((opnd1 >> 1) | (t << 31)) & WMASK; + } + cc = (opnd & WSIGN)? (cc | CC4): (cc & ~CC4); + R[rn|1] = opnd1; + R[rn] = opnd; + R[1] = sc - i; + break; + } + } /* end if */ + +else { /* left shift */ + switch (stype) { /* switch on type */ + + case 0x0: /* left log sgl */ + case 0x4: /* left arith sgl */ + for (i = 0; i < sc; i++) { + if (opnd & WSIGN) /* count 1's */ + cc = cc ^ CC1; + opnd = (opnd << 1) & WMASK; + if ((opnd ^ R[rn]) & WSIGN) /* sign change? */ + cc |= CC2; + } + R[rn] = opnd; + break; + + case 0x1: /* left log dbl */ + case 0x5: /* left arith dbl */ + for (i = 0; i < sc; i++) { + if (opnd & WSIGN) /* count 1's */ + cc = cc ^ CC1; + opnd = ((opnd << 1) | (opnd1 >> 31)) & WMASK; + opnd1 = (opnd1 << 1) & WMASK; + if ((opnd ^ R[rn]) & WSIGN) /* sign change? */ + cc |= CC2; + } + R[rn|1] = opnd1; + R[rn] = opnd; + break; + + case 0x2: /* left circ sgl */ + for (i = 0; i < sc; i++) { + if (opnd & WSIGN) /* count 1's */ + cc = cc ^ CC1; + opnd = ((opnd << 1) | (opnd >> 31)) & WMASK; + if ((opnd ^ R[rn]) & WSIGN) /* sign change? */ + cc |= CC2; + } + R[rn] = opnd; + break; + + case 0x3: /* left circ dbl */ + for (i = 0; i < sc; i++) { + if ((t = opnd & WSIGN) != 0) /* count 1's */ + cc = cc ^ CC1; + opnd = ((opnd << 1) | (opnd1 >> 31)) & WMASK; + opnd1 = ((opnd1 << 1) | (t >> 31)) & WMASK; + if ((opnd ^ R[rn]) & WSIGN) /* sign change? */ + cc |= CC2; + } + R[rn|1] = opnd1; + R[rn] = opnd; + break; + + case 0x6: /* left search sgl */ + for (i = 0; (i < sc) & !(opnd & WSIGN); i++) { + opnd = ((opnd << 1) | (opnd >> 31)) & WMASK; + if ((opnd ^ R[rn]) & WSIGN) /* sign change? */ + cc |= CC2; + } + cc = (opnd & WSIGN)? (cc | CC4): (cc & ~CC4); + R[rn] = opnd; + R[1] = sc - i; + break; + + case 0x7: /* left search dbl */ + for (i = 0; (i < sc) & !(opnd & WSIGN); i++) { + t = opnd; + opnd = ((opnd << 1) | (opnd1 >> 31)) & WMASK; + opnd1 = ((opnd1 << 1) | (t >> 31)) & WMASK; + if ((opnd ^ R[rn]) & WSIGN) /* sign change? */ + cc |= CC2; + } + cc = (opnd & WSIGN)? (cc | CC4): (cc & ~CC4); + R[rn|1] = opnd1; + R[rn] = opnd; + R[1] = sc - i; + break; + } /* end switch */ + } /* end else */ +return cc; +} + +/* Arithmetic routines */ + +uint32 Add32 (uint32 s1, uint32 s2, uint32 cin) +{ +uint32 t = (s1 + s2 + cin) & WMASK; /* add + carry in */ + +if (t & WSIGN) /* set CC34 */ + CC = CC4; +else if (t != 0) + CC = CC3; +else CC = 0; +if (cin? (t <= s1): (t < s1)) /* set carry out */ + CC |= CC1; +if (((s1 ^ ~s2) & (s1 ^ t)) & WSIGN) /* set overflow */ + CC |= CC2; +return t; +} + +uint32 SMul64 (uint32 a, uint32 b, uint32 *lo) +{ +uint32 ah, bh, al, bl, rhi, rlo, rmid1, rmid2, sign; + +CC &= CC1; /* clr CC2-4 */ +if ((a == 0) || (b == 0)) { /* zero argument? */ + *lo = 0; /* result is zero */ + return 0; + } +sign = a ^ b; /* sign of result */ +if (a & WSIGN) /* |a|, |b| */ + a = NEG_W (a); +if (b & WSIGN) + b = NEG_W (b); +ah = (a >> 16) & HMASK; /* split operands */ +bh = (b >> 16) & HMASK; /* into 16b chunks */ +al = a & HMASK; +bl = b & HMASK; +rhi = ah * bh; /* high result */ +rmid1 = ah * bl; +rmid2 = al * bh; +rlo = al * bl; +rhi = rhi + ((rmid1 >> 16) & HMASK) + ((rmid2 >> 16) & HMASK); +rmid1 = (rlo + (rmid1 << 16)) & WMASK; /* add mid1 to lo */ +if (rmid1 < rlo) /* carry? incr hi */ + rhi = rhi + 1; +rmid2 = (rmid1 + (rmid2 << 16)) & WMASK; /* add mid2 to to */ +if (rmid2 < rmid1) /* carry? incr hi */ + rhi = rhi + 1; +rhi = rhi & WMASK; +if (sign & WSIGN) /* neg result? */ + NEG_D (rhi, rmid2); +if (rhi & WSIGN) /* < 0, set CC4 */ + CC |= CC4; +else if (rhi || rmid2) /* > 0, set CC3 */ + CC |= CC3; +if (rhi != ((rmid2 & WSIGN)? WMASK: 0)) /* fit in 32b? */ + CC |= CC2; /* set CC2 */ +*lo = rmid2; +return rhi; +} + +t_bool SDiv64 (uint32 dvdh, uint32 dvdl, uint32 dvr, uint32 *res, uint32 *rem) +{ +uint32 i, quo, quos, rems; + +quos = dvdh ^ dvr; +rems = dvdh; +if (dvdh & WSIGN) { /* |dividend| */ + NEG_D (dvdh, dvdl); + } +if (dvr & WSIGN) /* |divisor| */ + dvr = NEG_W (dvr); +if (dvdh >= dvr) /* divide work? */ + return TRUE; +for (i = quo = 0; i < 32; i++) { /* 32 iterations */ + quo = (quo << 1) & WMASK; /* shift quotient */ + dvdh = ((dvdh << 1) | (dvdl >> 31)) & WMASK; /* shift dividend */ + dvdl = (dvdl << 1) & WMASK; + if (dvdh >= dvr) { /* step work? */ + dvdh = (dvdh - dvr) & WMASK; /* subtract dvr */ + quo = quo + 1; + } + } +if (quo & WSIGN) /* quotient ovflo? */ + return TRUE; +*rem = (rems & WSIGN)? NEG_W (dvdh): dvdh; /* sign of rem */ +*res = (quos & WSIGN)? NEG_W (quo): quo; +return FALSE; /* no overflow */ +} + +uint32 Cmp32 (uint32 a, uint32 b) +{ +if (a == b) /* ==? */ + return 0; +if ((a ^ b) & WSIGN) /* unlike signs? */ + return (a & WSIGN)? CC4: CC3; +return (a < b)? CC4: CC3; /* like signs */ +} + +/* Test stack pointer space/words to see if it can be modified - + returns special abort status (WSIGN) */ + +uint32 TestSP1 (uint32 sp1, int32 mod) +{ +int32 spc, wds; +uint32 cc; + +cc = 0; +spc = (int32) SP_GETSPC (sp1); /* get space */ +wds = (int32) SP_GETWDS (sp1); /* get words */ +if (((wds + mod) > SP_M_WDS) || ((wds + mod) < 0)) { /* words overflow? */ + if ((sp1 & SP_TW) == 0) /* trap if enabled */ + return TR_PSH; + cc |= CC3; + } +if (((spc - mod) > SP_M_WDS) || ((spc - mod) < 0)) { /* space overflow? */ + if ((sp1 & SP_TS) == 0) /* trap if enabled */ + return TR_PSH; + cc |= CC1; + } +CC = cc; +if (cc || (mod == 0)) { /* mod fails? */ + CC |= ((spc? 0: CC2) | (wds? 0: CC4)); + return WSIGN; + } +return 0; +} + +/* Actually modify stack pointer space/words and set CC's, + used by PSW/PLW/PSM/PLM */ + +uint32 ModWrSP (uint32 bva, uint32 sp, uint32 sp1, int32 mod) +{ +uint32 tr; + +sp = (sp + mod) & WMASK; +sp1 = (sp1 & (SP_TS|SP_TW)) | + (((SP_GETSPC (sp1) - mod) & SP_M_SPC) << SP_V_SPC) | + (((SP_GETWDS (sp1) + mod) & SP_M_WDS) << SP_V_WDS); +if ((tr = WriteD (bva, sp, sp1, VW)) != 0) + return tr; +if ((mod > 0) && SP_GETSPC (sp1) == 0) + CC |= CC2; +if ((mod < 0) && SP_GETWDS (sp1) == 0) + CC |= CC4; +return 0; +} + +/* XPSD instruction */ + +uint32 cpu_xpsd (uint32 IR, uint32 bva, uint32 ra) +{ +uint32 wa, wd, wd1, wd3; +uint32 tr; + +if (ra == VR) /* virtual? */ + wa = VW; /* set write virt */ +else wa = ra; /* no, phys */ +cpu_assemble_PSD (); +wd = PSW1; /* no more changes */ +wd1 = PSW2; +wd3 = PSW4; +if ((tr = WriteD (bva, wd, wd1, wa)) != 0) /* write curr PSD */ + return tr; +bva = bva + 8; +if (QCPU_5X0 && (IR & IRB (11))) { /* extra words? */ + if ((tr = WriteW (bva | 4, wd3, VW)) != 0) + return tr; + bva = bva + 8; + } +if ((tr = ReadD (bva, &wd, &wd1, ra)) != 0) /* read new PSD */ + return tr; +wd1 = (wd1 & ~(cpu_tab[cpu_model].psw2_mbz)) | /* merge inhibits */ + (PSW2 & PSW2_ALLINH); +if ((tr = cpu_new_PSD (IR & IRB (8), wd, wd1)) != 0) /* update PSD */ + return tr; +return 0; +} + +/* PSS instruction */ + +uint32 cpu_pss (uint32 IR, uint32 bva, uint32 acc) +{ +uint32 i, wd, wd1, tos, swc; +uint32 tr; + +cpu_assemble_PSD (); /* get old PSD */ +if ((tr = ReadD (bva, &wd, &wd1, acc)) != 0) /* read new PSD */ + return tr; +ReadPW (SSP_TOS, &tos); /* read system SP */ +ReadPW (SSP_SWC, &swc); +for (i = 0; i < RF_NUM; i++) { /* push registers */ + if (WritePW (tos + SSP_FR_RN + i + 1, R[i])) + return TR_NXM; + } +if (WritePW (tos + SSP_FR_PSW1 + 1, PSW1) || /* push PSD */ + WritePW (tos + SSP_FR_PSW2 + 1, PSW2)) + return TR_NXM; +WritePW (SSP_TOS, (tos + SSP_FR_LNT) & WMASK); /* tos + 28 */ +swc = (swc & (SP_TS|SP_TW)) | /* spc-28, wds+28 */ + (((SP_GETWDS (swc) + SSP_FR_LNT) & SP_M_WDS) << SP_V_WDS) | + (((SP_GETSPC (swc) - SSP_FR_LNT) & SP_M_SPC) << SP_V_SPC); +if (SP_GETWDS (swc) < SSP_FR_LNT) /* wds overflow? */ + swc |= SP_TW; /* set sticky bit */ +WritePW (SSP_SWC, swc); +wd1 = (wd1 & ~(cpu_tab[cpu_model].psw2_mbz)) | /* merge inhibits */ + (PSW2 & PSW2_ALLINH); +if ((tr = cpu_new_PSD (IR & IRB (8), wd, wd1)) != 0) /* update PSD */ + return tr; +return 0; +} + +/* PLS instruction */ + +uint32 cpu_pls (uint32 IR) +{ +uint32 i, wd, wd1, tos, swc, spc; +uint32 tr; + +ReadPW (SSP_TOS, &tos); /* read system SP */ +ReadPW (SSP_SWC, &swc); +spc = SP_GETSPC (swc); /* space left */ +if (spc == 0) { /* none? */ + ReadPW (SSP_DFLT_PSW1, &wd); /* use default PSD */ + ReadPW (SSP_DFLT_PSW2, &wd1); + } +else if (spc < SSP_FR_LNT) /* not enough? */ + return TR_INVSSP; +else { + tos = (tos - SSP_FR_LNT) & WMASK; /* modify TOS */ + for (i = 0; i < RF_NUM; i++) { /* pull registers */ + if (ReadPW (tos + SSP_FR_RN + i + 1, &wd)) + return TR_NXM; + R[i] = wd; + } + if (ReadPW (tos + SSP_FR_PSW1 + 1, &wd) || /* pull new PSD */ + ReadPW (tos + SSP_FR_PSW2 + 1, &wd1)) + return TR_NXM; + WritePW (SSP_TOS, tos); /* rewrite SP */ + swc = (swc & (SP_TS|SP_TW)) | /* spc+28, wds-28 */ + (((SP_GETWDS (swc) - SSP_FR_LNT) & SP_M_WDS) << SP_V_WDS) | + (((SP_GETSPC (swc) + SSP_FR_LNT) & SP_M_SPC) << SP_V_SPC); + if (SP_GETSPC (swc) < SSP_FR_LNT) /* spc overflow? */ + swc |= SP_TS; /* set sticky bit */ + WritePW (SSP_SWC, swc); + } +wd1 = (wd1 & ~(cpu_tab[cpu_model].psw2_mbz)) | /* merge inhibits */ + (PSW2 & PSW2_ALLINH); +if ((tr = cpu_new_PSD (IR & IRB (8), wd, wd1)) != 0) /* update PSD */ + return tr; +if (IR & IRB (10)) /* clr hi pri int? */ + int_hireq = io_rels_int (int_hiact, IR & IRB (11)); +else if (IR & IRB (11)) /* clr PDF flag? */ + cpu_pdf = 0; + +return 0; +} + +/* Load new PSD */ + +uint32 cpu_new_PSD (uint32 lrp, uint32 p1, uint32 p2) +{ +uint32 tr; + +PSW1 = p1 & ~cpu_tab[cpu_model].psw1_mbz; /* clear mbz bits */ +PSW2 = ((p2 & ~PSW2_RP) | (PSW2 & PSW2_RP)) & /* save reg ptr */ + ~cpu_tab[cpu_model].psw2_mbz; +if (lrp && /* load reg ptr? */ + ((tr = cpu_new_RP (p2)) != 0)) /* invalid? */ + return tr; /* trap */ +CC = PSW1_GETCC (PSW1); /* extract CC's */ +PC = PSW1_GETPC (PSW1); /* extract PC */ +PSW2_WLK = PSW2_GETWLK (PSW2); /* extract lock */ +int_hireq = io_eval_int (); /* update intr */ +if ((PSW1 & PSW1_MM) || /* mapped or */ + ((PSW2 & (PSW2_MA9|PSW2_MA5X0)) == 0)) { /* not real ext? */ + bvamqrx = BVAMASK; /* 17b masks */ + PSW_QRX9 = 0; + } +else { /* phys real ext */ + if ((PSW_QRX9 = PSW2 & PSW2_MA9) != 0) /* Sigma 9? */ + bvamqrx = BPAMASK22; /* yes, 22b masks */ + else bvamqrx = BPAMASK20; /* no, 20b masks */ + } +return 0; +} + +/* Load new RP */ + +uint32 cpu_new_RP (uint32 rp) +{ +uint32 rp1, j; + +PSW2 = (PSW2 & ~PSW2_RP) | (rp & PSW2_RP); /* merge to PSW2 */ +PSW2 = PSW2 & ~cpu_tab[cpu_model].psw2_mbz; /* clear nx bits */ +rp1 = PSW2_GETRP (rp); +if (rp1 >= rf_bmax) { /* nx reg file? */ + if (QCPU_S89) + return TR_INVRPN; + if (QCPU_5X0) + return TR_INVREG; + for (j = 0; j < RF_NUM; j++) /* clear nx set */ + rf[(rp1 * RF_NUM) + j] = 0; + sim_activate (&cpu_rblk_unit, 1); /* sched cleaner */ + } +R = rf + (rp1 * RF_NUM); +return 0; +} + +/* This routine is scheduled if the current registr block doesn't exist */ + +t_stat cpu_bad_rblk (UNIT *uptr) +{ +uint32 rp1, j; + +rp1 = PSW2_GETRP (PSW2); /* get reg ptr */ +if (rp1 >= rf_bmax) { /* still bad? */ + for (j = 0; j < RF_NUM; j++) /* clear nx set */ + rf[(rp1 * RF_NUM) + j] = 0; + sim_activate (uptr, 1); /* sched again */ + } +return SCPE_OK; +} + +/* Load new PC for branch instruction */ + +uint32 cpu_new_PC (uint32 bva) +{ +uint32 npc = bva >> 2; + +if (PSW_QRX9 && (npc & PSW1_XA)) /* S9 real ext, XA? */ + PSW2 = (PSW2 & ~PSW2_EA) | (npc & PSW2_EA); /* change PSW2 EA */ +return npc & BVAMASK; +} + +/* Add value to PC for fetch, BAL, trap */ + +uint32 cpu_add_PC (uint32 pc, uint32 inc) +{ +if (PSW_QRX9) /* S9 real ext? */ + return ((pc & ~(PSW1_M_PC & ~PSW1_XA)) | /* modulo 16b inc */ + ((pc + inc) & (PSW1_M_PC & ~PSW1_XA))); +return ((pc + inc) & BVAMASK); /* no, mod 17b inc */ +} + +/* Assemble PSD */ + +void cpu_assemble_PSD (void) +{ +PSW1 = (PSW1 & ~(PSW1_CCMASK|PSW1_PCMASK|cpu_tab[cpu_model].psw1_mbz)) | + (CC << PSW1_V_CC) | (PC << PSW1_V_PC); +PSW2 = (PSW2 & ~(PSW2_WLKMASK|cpu_tab[cpu_model].psw2_mbz)) | + (PSW2_WLK << PSW2_V_WLK); +return; +} + +/* Reset routine */ + +t_stat cpu_reset (DEVICE *dptr) +{ +cpu_new_PSD (1, PSW1_DFLT | (PSW1 & PSW1_PCMASK), PSW2_DFLT); +cpu_pdf = 0; +cons_alarm = 0; +cons_pcf = 0; +set_rf_display (R); +if (M == NULL) + M = (uint32 *) calloc (MAXMEMSIZE, sizeof (uint32)); +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'); +rtc_register (RTC_ALARM, RTC_HZ_2, &cpu_unit); +return int_reset (dptr); +} + +/* Memory examine */ + +t_stat cpu_ex (t_value *vptr, t_addr addr, UNIT *uptr, int32 sw) +{ +uint32 lnt; + +if (sw & SWMASK ('C')) + lnt = 2; +else if ((sw & SWMASK ('B')) || (sw & SWMASK ('A')) || (sw & SWMASK ('E'))) + lnt = 0; +else if (sw & SWMASK ('H')) + lnt = 1; +else lnt = 2; +if (sw & SWMASK ('V')) { + if (ReadW (addr << lnt, vptr, VNT) != 0) + return SCPE_REL; + } +else if (ReadW (addr << lnt, vptr, PH) != 0) + return SCPE_NXM; +return SCPE_OK; +} + +/* Memory deposit */ + +t_stat cpu_dep (t_value val, t_addr addr, UNIT *uptr, int32 sw) +{ +uint32 lnt; + +if (sw & SWMASK ('C')) + lnt = 2; +else if ((sw & SWMASK ('B')) || (sw & SWMASK ('A')) || (sw & SWMASK ('E'))) + lnt = 0; +else if (sw & SWMASK ('H')) + lnt = 1; +else lnt = 2; +if (sw & SWMASK ('V')) { + if (WriteW (addr << lnt, val, VNT) != 0) + return SCPE_REL; + } +else if (WriteW (addr << lnt, val, PH) != 0) + return SCPE_NXM; +return SCPE_OK; +} + +/* CPU configuration management + + These routines (for type, memory size, options, number of reg blocks, + number of external int blocks) must generate a consistent result. + To assure this, all changes (except memory size) reset the CPU. */ + +/* Set CPU type */ + +t_stat cpu_set_type (UNIT *uptr, int32 val, char *cptr, void *desc) +{ +uint32 model = CPUF_GETMOD (val); + +if (model == cpu_model) /* no change? */ + return SCPE_OK; +cpu_reset (&cpu_dev); +if (MEMSIZE > (cpu_tab[cpu_model].pamask + 1)) + cpu_set_size (uptr, cpu_tab[cpu_model].pamask + 1, NULL, (void *) uptr); +cpu_model = model; +cpu_unit.flags = (cpu_unit.flags | cpu_tab[model].std) & ~cpu_tab[model].opt; +rf_bmax = RF_DFLT; +io_set_eimax (EIGRP_DFLT); +return SCPE_OK; +} + +/* Set memory size */ + +t_stat cpu_set_size (UNIT *uptr, int32 val, char *cptr, void *desc) +{ +uint32 mc = 0; +uint32 i; + +if ((val <= 0) || (val > (int32)(cpu_tab[cpu_model].pamask + 1))) + return SCPE_ARG; +if (!desc) { /* force trunc? */ + 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 and clear options */ + +t_stat cpu_set_opt (UNIT *uptr, int32 val, char *cptr, void *desc) +{ +if ((val & (cpu_tab[cpu_model].std | cpu_tab[cpu_model].opt)) == 0) + return SCPE_NOFNC; +cpu_unit.flags |= val; +return SCPE_OK; +} + +t_stat cpu_clr_opt (UNIT *uptr, int32 val, char *cptr, void *desc) +{ +if (val & cpu_tab[cpu_model].std) + return SCPE_NOFNC; +cpu_unit.flags &= ~val; +return SCPE_OK; +} + +/* Set/show register blocks */ + +t_stat cpu_set_rblks (UNIT *uptr, int32 val, char *cptr, void *desc) +{ +int32 invmask, lnt, i, j; +t_stat r; + +if (QCPU_5X0) /* 5X0 fixed */ + return SCPE_NOFNC; +if (cptr == NULL) + return SCPE_ARG; +invmask = PSW2_GETRP (cpu_tab[cpu_model].psw2_mbz); +if (QCPU_S89) + invmask |= 0x10; +lnt = (int32) get_uint (cptr, 10, RF_NBLK, &r); +if ((r != SCPE_OK) || (lnt == 0) || (lnt & invmask)) + return SCPE_ARG; +cpu_reset (&cpu_dev); +rf_bmax = lnt; +for (i = rf_bmax; i < RF_NBLK; i++) { /* zero unused */ + for (j = 0; j < RF_NUM; j++) + rf[(i * RF_NUM) + j] = 0; + } +return SCPE_OK; +} + +t_stat cpu_show_rblks (FILE *st, UNIT *uptr, int32 val, void *desc) +{ +fprintf (st, "register blocks=%d", rf_bmax); +return SCPE_OK; +} + +/* Set current register file pointers for SCP */ + +void set_rf_display (uint32 *rfbase) +{ +extern REG *find_reg (char *cptr, char **optr, DEVICE *dptr); +REG *rptr; +uint32 i; + +rptr = find_reg ("R0", NULL, &cpu_dev); +if (rptr == NULL) return; +for (i = 0; i < RF_NUM; i++, rptr++) + rptr->loc = (void *) (rfbase + i); +return; +} + +/* Front panael alarm */ + +t_stat cpu_set_alarm (UNIT *uptr, int32 val, char *cptr, void *desc) +{ +cons_alarm_enb = val; +return SCPE_OK; +} + +t_stat cpu_show_alarm (FILE *st, UNIT *uptr, int32 val, void *desc) +{ +fputs (cons_alarm_enb? "alarm enabled\n": "alarm disabled\n", st); +return SCPE_OK; +} + +t_stat cpu_svc (UNIT *uptr) +{ +if (cons_alarm && cons_alarm_enb) + sim_putchar ('\a'); +return SCPE_OK; +} + +/* Address converter and display */ + +/* Virtual address translation */ + +t_stat cpu_show_addr (FILE *of, UNIT *uptr, int32 val, void *desc) +{ +t_stat r; +char *cptr = (char *) desc; +uint32 ad, bpa, dlnt, virt; +static const char *lnt_str[] = { + "byte", + "halfword", + "word", + "doubleword", + }; +extern uint32 map_reloc (uint32 bva, uint32 acc, uint32 *bpa); + +if ((val < 0) || (val > DW)) + return SCPE_IERR; +virt = (sim_switches & SWMASK ('V'))? 1: 0; +if (cptr) { + ad = (uint32) get_uint (cptr, 16, virt? VAMASK: PAMASK22, &r); + if (r == SCPE_OK) { + if (sim_switches & SWMASK ('B')) + dlnt = 0; + else if (sim_switches & SWMASK ('H')) + dlnt = 1; + else if (sim_switches & SWMASK ('D')) + dlnt = 3; + else dlnt = 2; + bpa = ad << val; + if (virt && map_reloc (bpa, VNT, &bpa)) + fprintf (of, "Virtual address %-X: memory management error\n"); + else fprintf (of, "%s %s %-X: physical %s %-X\n", + ((virt)? "Virtual": "Physical"), lnt_str[val], ad, lnt_str[dlnt], bpa >> dlnt); + return SCPE_OK; + } + } +fprintf (of, "Invalid argument\n"); +return SCPE_OK; +} + +/* Record history */ + +void inst_hist (uint32 ir, uint32 pc, uint32 tp) +{ +uint32 rn = I_GETRN (ir); + +hst_p = (hst_p + 1); /* next entry */ +if (hst_p >= hst_lnt) + hst_p = 0; +hst[hst_p].typ_cc_pc = (CC << PSW1_V_CC) | pc | tp; +hst[hst_p].ir = ir; +hst[hst_p].rn = R[rn]; +hst[hst_p].rn1 = R[rn|1]; +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].typ_cc_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; +} + +/* Print one instruction */ + +void cpu_fprint_one_inst (FILE *st, uint32 tcp, uint32 ir, uint32 rn, uint32 rn1, + uint32 ea, uint32 opnd, uint32 opnd1) +{ +t_value sim_val; +extern t_stat fprint_sym (FILE *ofile, t_addr addr, t_value *val, + UNIT *uptr, int32 sw); + +if (tcp & (H_INST|H_ITRP)) { /* instr or trap? */ + uint32 op = I_GETOP (ir); + uint32 cc = PSW1_GETCC (tcp); + uint32 pc = tcp & PAMASK20; + uint8 fl = anlz_tab[op]; + + fprintf (st, "%c %05X %X %08X %08X ", /* standard fields */ + ((tcp & H_INST)? ' ': 'T'), pc, cc, rn, rn1); + if (tcp & H_ABRT) /* aborted? */ + fputs ("aborted ", st); + else { + if (fl & CC4) /* immediate? */ + fprintf (st, "%05X ", ea); + else if ((fl >> 2) != DW) /* byte/half/word? */ + fprintf (st, "%05X %08X ", ea >> 2, opnd); + else fprintf (st, "%05X %08X %08X ", ea >> 2, opnd, opnd1); + } + sim_val = ir; + if ((fprint_sym (st, pc, &sim_val, NULL, SWMASK ('M'))) > 0) + fprintf (st, "(undefined) %08X", ir); + fputc ('\n', st); /* end line */ + } +return; +} + +/* Show history */ + +t_stat cpu_show_hist (FILE *st, UNIT *uptr, int32 val, void *desc) +{ +int32 k, di, lnt; +t_stat r; +char *cptr = (char *) desc; +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 CC Rn Rn|1 EA operand operand1 IR\n\n"); +for (k = 0; k < lnt; k++) { /* print specified */ + h = &hst[(++di) % hst_lnt]; /* entry pointer */ + if (h->typ_cc_pc) /* instruction? */ + cpu_fprint_one_inst (st, h->typ_cc_pc, h->ir, h->rn, h->rn1, h->ea, h->op, h->op1); + } /* end for */ +return SCPE_OK; +} diff --git a/sigma/sigma_defs.h b/sigma/sigma_defs.h new file mode 100644 index 00000000..5c6951ee --- /dev/null +++ b/sigma/sigma_defs.h @@ -0,0 +1,478 @@ +/* sigma_defs.h: XDS Sigma simulator definitions + + Copyright (c) 2007-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. + + The author gratefullly acknowledges the help of George Plue, who provided + answers to many puzzling questions about how the Sigma series worked. + + 22-May-10 RMS Added check for 64b definitions +*/ + +#ifndef _SIGMA_DEFS_H_ +#define _SIGMA_DEFS_H_ 0 + +#include "sim_defs.h" /* simulator defns */ + +#if defined(USE_INT64) || defined(USE_ADDR64) +#error "Sigma 32b does not support 64b values!" +#endif + +/* Simulator stops */ + +#define STOP_INVIOC 1 /* invalid IO config */ +#define STOP_IBKPT 2 /* breakpoint */ +#define STOP_ASTOP 3 /* address stop */ +#define STOP_WAITNOINT 4 /* WAIT, no intr */ +#define STOP_INVPSD 5 /* invalid PSD */ +#define STOP_ROLLBACK 6 /* >= here, rollback PC */ +#define STOP_EXULIM 6 /* EXU loop */ +#define STOP_ILLEG 7 /* illegal instr */ +#define STOP_ILLTRP 8 /* illegal trap inst */ +#define STOP_ILLVEC 9 /* illegal vector */ +#define STOP_TRPT 10 /* trap inside int/trap */ +#define STOP_MAX 15 /* <= here for all stops */ + +/* Timers */ + +#define TMR_RTC 0 /* clocks */ + +/* Architectural constants */ + +#define PASIZE17 17 /* phys addr width, S5-8 */ +#define PASIZE20 20 /* phys addr width, 5X0 */ +#define PASIZE22 22 /* phys addr width, S9 */ +#define PAMASK17 ((1u << PASIZE17) - 1) +#define BPAMASK17 ((1u << (PASIZE17 + 2)) - 1) +#define PAMASK20 ((1u << PASIZE20) - 1) +#define BPAMASK20 ((1u << (PASIZE20 + 2)) - 1) +#define PAMASK22 ((1u << PASIZE22) - 1) +#define BPAMASK22 ((1u << (PASIZE22 + 2)) - 1) +#define MAXMEMSIZE (1u << PASIZE20) /* maximum memory */ +#define MEMSIZE (cpu_unit.capac) +#define MEM_IS_NXM(x) ((x) >= MEMSIZE) +#define BPA_IS_NXM(x) (((x) >> 2) >= MEMSIZE) +#define VASIZE 17 /* virtual addr width */ +#define VAMASK ((1u << VASIZE) - 1) /* virtual addr mask */ +#define BVAMASK ((1u << (VASIZE + 2)) - 1) /* byte virtual addr mask */ +#define RF_NUM 16 /* number of registers */ +#define RF_NBLK 32 /* max number reg blocks */ +#define RF_DFLT 4 /* default reg blocks */ + +/* CPU models, options, and variable data */ + +#define CPUF_STR (1u << (UNIT_V_UF + 0)) /* byte string */ +#define CPUF_DEC (1u << (UNIT_V_UF + 1)) /* decimal */ +#define CPUF_FP (1u << (UNIT_V_UF + 2)) /* floating point */ +#define CPUF_MAP (1u << (UNIT_V_UF + 3)) /* memory map */ +#define CPUF_WLK (1u << (UNIT_V_UF + 4)) /* write lock protect */ +#define CPUF_LAMS (1u << (UNIT_V_UF + 5)) /* LAS/LMS */ +#define CPUF_ALLOPT (CPUF_STR|CPUF_DEC|CPUF_FP|CPUF_MAP|CPUF_WLK|CPUF_LAMS) +#define CPUF_MSIZE (1u << (UNIT_V_UF + 6)) /* dummy for memory */ + +#define CPU_V_S5 0 +#define CPU_V_S6 1 +#define CPU_V_S7 2 +#define CPU_V_S8 3 /* not supported */ +#define CPU_V_S9 4 /* not supported */ +#define CPU_V_550 5 /* not supported */ +#define CPU_V_560 6 /* not supported */ +#define CPU_S5 (1u << CPU_V_S5) +#define CPU_S6 (1u << CPU_V_S6) +#define CPU_S7 (1u << CPU_V_S7) +#define CPU_S7B (1u << CPU_V_S7B) +#define CPU_S8 (1u << CPU_V_S8) +#define CPU_S9 (1u << CPU_V_S9) +#define CPU_550 (1u << CPU_V_550) +#define CPU_560 (1u << CPU_V_560) + +#define QCPU_S5 (cpu_model == CPU_V_S5) +#define QCPU_S9 (cpu_model == CPU_V_S9) +#define QCPU_5X0 ((1u << cpu_model) & (CPU_550|CPU_560)) +#define QCPU_S567 ((1u << cpu_model) & (CPU_S5|CPU_S6|CPU_S7)) +#define QCPU_S89 ((1u << cpu_model) & (CPU_S8|CPU_S9)) +#define QCPU_S89_5X0 ((1u << cpu_model) & (CPU_S8|CPU_S9|CPU_550|CPU_560)) +#define QCPU_BIGM ((1u << cpu_model) & (CPU_S9|CPU_550|CPU_560)) + +#define CPU_MUNIT_SIZE (1u << 15) /* mem unit size */ + +typedef struct { + uint32 psw1_mbz; /* PSW1 mbz */ + uint32 psw2_mbz; /* PSW2 mbz */ + uint32 mmc_cm_map1; /* MMC mode 1 cmask */ + uint32 pamask; /* physical addr mask */ + uint32 eigrp_max; /* max num ext int groups */ + uint32 chan_max; /* max num channels */ + uint32 iocc; /* IO instr CC bits */ + uint32 std; /* required options */ + uint32 opt; /* variable options */ + } cpu_var_t; + +/* Instruction format */ + +#define INST_V_IND 31 /* indirect */ +#define INST_IND (1u << INST_V_IND) +#define INST_V_OP 24 /* opcode */ +#define INST_M_OP 0x7F +#define INST_V_RN 20 /* register */ +#define INST_M_RN 0xF +#define INST_V_XR 17 /* index */ +#define INST_M_XR 0x7 +#define INST_V_ADDR 0 /* 17b addr */ +#define INST_M_ADDR 0x1FFFF +#define INST_V_LIT 0 /* 20b literal or addr */ +#define INST_M_LIT 0xFFFFF +#define TST_IND(x) ((x) & INST_IND) +#define I_GETOP(x) (((x) >> INST_V_OP) & INST_M_OP) +#define I_GETRN(x) (((x) >> INST_V_RN) & INST_M_RN) +#define I_GETXR(x) (((x) >> INST_V_XR) & INST_M_XR) +#define I_GETADDR(x) (((x) >> INST_V_ADDR) & INST_M_ADDR) +#define I_GETADDR20(x) (((x) >> INST_V_ADDR) & PAMASK20) +#define I_GETLIT(x) (((x) >> INST_V_LIT) & INST_M_LIT) +#define IRB(x) (1u << (31 - (x))) + +/* Shift instructions */ + +#define SHF_V_SOP 8 /* shift operation */ +#define SHF_M_SOP 0x7 +#define SHF_V_SC 0 /* shift count */ +#define SHF_M_SC 0x7F +#define SCSIGN 0x40 +#define SHF_GETSOP(x) (((x) >> SHF_V_SOP) & SHF_M_SOP) +#define SHF_GETSC(x) (((x) >> SHF_V_SC) & SHF_M_SC) + +/* String instructions */ + +#define S_V_MCNT 24 /* string mask/count */ +#define S_M_MCNT 0xFF +#define S_MCNT (S_M_MCNT << S_V_MCNT) +#define S_GETMCNT(x) (((x) >> S_V_MCNT) & S_M_MCNT) +#define S_ADDRINC (S_MCNT + 1) + +/* Data types */ + +#define WMASK 0xFFFFFFFF /* word */ +#define WSIGN 0x80000000 /* word sign */ +#define LITMASK (INST_M_LIT) /* literal */ +#define LITSIGN 0x80000 /* literal sign */ +#define HMASK 0xFFFF /* halfword mask */ +#define HSIGN 0x8000 /* halfword sign */ +#define BMASK 0xFF /* byte */ +#define BSIGN 0x80 /* byte sign */ +#define RNMASK (INST_M_RN) /* reg lit */ +#define RNSIGN 0x08 /* reg lit sign */ + +#define FP_V_SIGN 31 /* sign */ +#define FP_SIGN (1u << FP_V_SIGN) +#define FP_V_EXP 24 /* exponent */ +#define FP_M_EXP 0x7F +#define FP_BIAS 0x40 /* exponent bias */ +#define FP_V_FRHI 0 /* high fraction */ +#define FP_M_FRHI 0x00FFFFFF +#define FP_NORM 0x00F00000 +#define FP_M_FRLO 0xFFFFFFFF /* low fraction */ +#define FP_GETSIGN(x) (((x) >> FP_V_SIGN) & 1) +#define FP_GETEXP(x) (((x) >> FP_V_EXP) & FP_M_EXP) +#define FP_GETFRHI(x) (((x) >> FP_V_FRHI) & FP_M_FRHI) +#define FP_GETFRLO(x) ((x) & FP_M_FRLO) + +/* PSW1 fields */ + +#define PSW1_V_CC 28 /* cond codes */ +#define PSW1_M_CC 0xF +#define CC1 0x8 +#define CC2 0x4 +#define CC3 0x2 +#define CC4 0x1 +#define PSW1_V_FR 27 /* fp mode controls */ +#define PSW1_V_FS 26 +#define PSW1_V_FZ 25 +#define PSW1_V_FN 24 +#define PSW1_V_FPC 24 /* as a group */ +#define PSW1_M_FPC 0xF +#define PSW1_FPC (PSW1_M_FPC << PSW1_V_FPC) +#define PSW1_V_MS 23 /* master/slave */ +#define PSW1_V_MM 22 /* memory map */ +#define PSW1_V_DM 21 /* decimal trap */ +#define PSW1_V_AM 20 /* arithmetic trap */ +#define PSW1_V_AS 19 /* EBCDIC/ASCII, S9 */ +#define PSW1_V_XA 15 /* ext addr flag, S9 */ +#define PSW1_V_PC 0 /* PC */ +#define PSW1_M_PC (VAMASK) +#define PSW1_FR (1u << PSW1_V_FR) +#define PSW1_FS (1u << PSW1_V_FS) +#define PSW1_FZ (1u << PSW1_V_FZ) +#define PSW1_FN (1u << PSW1_V_FN) +#define PSW1_MS (1u << PSW1_V_MS) +#define PSW1_MM (1u << PSW1_V_MM) +#define PSW1_DM (1u << PSW1_V_DM) +#define PSW1_AM (1u << PSW1_V_AM) +#define PSW1_AS (1u << PSW1_V_AS) +#define PSW1_XA (1u << PSW1_V_XA) +#define PSW1_CCMASK (PSW1_M_CC << PSW1_V_CC) +#define PSW1_PCMASK (PSW1_M_PC << PSW1_V_PC) +#define PSW1_GETCC(x) (((x) >> PSW1_V_CC) & PSW1_M_CC) +#define PSW1_GETPC(x) (((x) >> PSW1_V_PC) & PSW1_M_PC) +#define PSW1_DFLT 0 + +/* PSW2 fields */ + +#define PSW2_V_WLK 28 /* write key */ +#define PSW2_M_WLK 0xF +#define PSW2_V_CI 26 /* counter int inhibit */ +#define PSW2_V_II 25 /* IO int inhibit */ +#define PSW2_V_EI 24 /* external int inhibit */ +#define PSW2_V_INH (PSW2_V_EI) /* inhibits as a group */ +#define PSW2_M_INH 0x7 +#define PSW2_V_MA9 23 /* mode altered, S9 */ +#define PSW2_V_EA 16 /* ext addr, S9 */ +#define PSW2_M_EA 0x3F +#define PSW2_EA (PSW2_M_EA << PSW2_V_EA) +#define PSW2_V_TSF 8 /* trapped status, S9 */ +#define PSW2_M_TSF 0xFF +#define PSW2_TSF (PSW2_M_TSF << PSW2_V_TSF) +#define PSW2_V_RP 4 /* register block ptr */ +#define PSW2_M_RP5B 0x1F +#define PSW2_M_RP4B 0xF +#define PSW2_RP ((QCPU_S567? PSW2_M_RP5B: PSW2_M_RP4B) << PSW2_V_RP) +#define PSW2_V_RA 3 /* reg altered, 9,5X0 */ +#define PSW2_V_MA5X0 2 /* mode altered, 5X0 */ +#define PSW2_CI (1u << PSW2_V_CI) +#define PSW2_II (1u << PSW2_V_II) +#define PSW2_EI (1u << PSW2_V_EI) +#define PSW2_ALLINH (PSW2_CI|PSW2_II|PSW2_EI) /* all inhibits */ +#define PSW2_MA9 (1u << PSW2_V_MA9) +#define PSW2_RA (1u << PSW2_V_RA) +#define PSW2_MA5X0 (1u << PSW2_V_MA5X0) +#define PSW2_WLKMASK (PSW2_M_WLK << PSW2_V_WLK) +#define PSW2_RPMASK (PSW2_M_RP << PSW2_V_RP) +#define PSW2_GETINH(x) (((x) >> PSW2_V_INH) & PSW2_M_INH); +#define PSW2_GETWLK(x) (((x) >> PSW2_V_WLK) & PSW2_M_WLK) +#define PSW2_GETRP(x) (((x) & PSW2_RP) >> PSW2_V_RP) +#define PSW2_DFLT 0 + +/* Stack pointers */ + +#define SP_V_TS 31 /* space trap enable */ +#define SP_TS (1u << SP_V_TS) +#define SP_V_SPC 16 /* space */ +#define SP_M_SPC 0x7FFF +#define SP_V_TW 15 /* words trap enable */ +#define SP_TW (1u << SP_V_TW) +#define SP_V_WDS 0 /* words */ +#define SP_M_WDS 0x7FFF +#define SP_GETSPC(x) (((x) >> SP_V_SPC) & SP_M_SPC) +#define SP_GETWDS(x) (((x) >> SP_V_WDS) & SP_M_WDS) + +/* System stack pointer (5X0 only) */ + +#define SSP_TOS 0 /* system stack */ +#define SSP_SWC 1 /* space/word count */ +#define SSP_DFLT_PSW1 2 /* default PSD */ +#define SSP_DFLT_PSW2 3 +#define SSP_FR_LNT 28 /* frame length */ +#define SSP_FR_RN 0 /* registers */ +#define SSP_FR_PSW1 24 /* PSD */ +#define SSP_FR_PSW2 25 +#define SSP_FR_PSW4 27 + +/* The Sigma series had word addressable memory, but byte addressable + data. Virtual addresses in the simulator are BYTE addresses, and + these definitions are in terms of a byte address (word << 2). */ + +#define VA_NUM_PAG (1 << (VASIZE - (BVA_V_PAG - 2))) +#define PA_NUM_PAG (1 << (PASIZE22 - (BVA_V_PAG - 2))) +#define BVA_V_OFF 0 /* offset */ +#define BVA_M_OFF 0x7FF +#define BVA_V_PAG 11 /* page */ +#define BVA_M_PAG 0xFF +#define BVA_GETOFF(x) (((x) >> BVA_V_OFF) & BVA_M_OFF) +#define BVA_GETPAG(x) (((x) >> BVA_V_PAG) & BVA_M_PAG) +#define BPA_V_PAG (BVA_V_PAG) /* phys page */ +#define BPA_M_PAG 0x1FFF +#define BPA_GETPAG(x) (((x) >> BPA_V_PAG) & BPA_M_PAG) + +/* Memory maps */ + +#define MMC_V_CNT 24 /* count */ +#define MMC_M_CNT 0xFF +#define MMC_CNT (MMC_M_CNT << MMC_V_CNT) +#define MMC_V_CS 9 /* start of page */ +/* /* map 1: 2b locks, per model */ +#define MMC_M_CS2 0xFC /* map 2: access controls */ +#define MMC_M_CS3 0x7FE /* map 3: 4b locks */ +#define MMC_M_CS4 0xFF /* map 4: 8b relocation */ +#define MMC_M_CS5 0xFF /* map 5: 13b relocation */ +#define MMC_GETCNT(x) (((x) >> MMC_V_CNT) & MMC_M_CNT) +#define MMC_L_CS1 (VA_NUM_PAG) /* map lengths */ +#define MMC_L_CS2 (VA_NUM_PAG) +#define MMC_L_CS3 (PA_NUM_PAG) +#define MMC_L_CS4 (VA_NUM_PAG) +#define MMC_L_CS5 (VA_NUM_PAG) + +/* Trap codes */ + +#define TR_V_FL 17 /* trap flag */ +#define TR_FL (1u << TR_V_FL) +#define TR_V_PDF 16 /* proc detected fault */ +#define TR_PDF (1u << TR_V_FL) +#define TR_V_CC 12 /* or'd to CC/addr offset */ +#define TR_M_CC 0xF +#define TR_V_VEC 0 /* trap address */ +#define TR_M_VEC 0xFFF +#define TR_GETVEC(x) (((x) >> TR_V_VEC) & TR_M_VEC) +#define TR_GETCC(x) (((x) >> TR_V_CC) & TR_M_CC) + +#define TR_NXI (TR_FL|0x8040) /* non-existent inst */ +#define TR_NXM (TR_FL|0x4040) /* non-existent memory */ +#define TR_PRV (TR_FL|0x2040) /* privileged inst */ +#define TR_MPR (TR_FL|0x1040) /* mem protect violation */ +#define TR_WLK (TR_FL|0x3040) /* write lock (5x0 only) */ +#define TR_UNI (TR_FL|0x0041) /* unimplemented inst */ +#define TR_PSH (TR_FL|0x0042) /* pushdown overflow */ +#define TR_FIX (TR_FL|0x0043) /* fixed point arith */ +#define TR_FLT (TR_FL|0x0044) /* floating point arith */ +#define TR_DEC (TR_FL|0x0045) /* decimal arithmetic */ +#define TR_WAT (TR_FL|0x0046) /* watchdog timer */ +#define TR_47 (TR_FL|0x0047) /* 5X0 - WD trap */ +#define TR_C1(x) (TR_FL|0x0048|((x) << TR_V_CC)) /* call instruction */ +#define TR_C2(x) (TR_FL|0x0049|((x) << TR_V_CC)) /* call instruction */ +#define TR_C3(x) (TR_FL|0x004A|((x) << TR_V_CC)) /* call instruction */ +#define TR_C4(x) (TR_FL|0x004B|((x) << TR_V_CC)) /* call instruction */ +#define TR_NESTED (TR_FL|TR_PDF|0xF04D) /* 9,5X0 - fault in inv/trap */ +#define TR_INVTRP (TR_FL|TR_PDF|0xC04D) /* 9,5X0 - inv int/trap inst */ +#define TR_INVRPT (TR_FL|TR_PDF|0x804D) /* 9 - inv new RP in trap */ +#define TR_INVSSP (TR_FL|TR_PDF|0x404D) /* 5X0 - inv SSP for PLS */ +#define TR_INVMMC (TR_FL|TR_PDF|0x204D) /* 9,5X0 - inv MMC config */ +#define TR_INVREG (TR_FL|0x104D) /* 9,5x0 - inv reg num */ +#define TR_INVRPN (TR_FL|TR_PDF|0x004D) /* 9 - inv new RP, non-trap */ + +/* Effective address and memory access routines interface + + The access types are defined to make the following equation work: + + trap if ((access_type != 0) && (access_control >= access_type)) + + The length codes are defined so that length in bytes = 1 << length_code */ + +#define PH 0x0 /* physical */ +#define VW 0x1 /* write */ +#define VI 0x2 /* instruction */ +#define VR 0x3 /* read */ +#define VNT 0x4 /* no traps */ + +#define BY 0x0 /* byte */ +#define HW 0x1 /* halfword */ +#define WD 0x2 /* word */ +#define DW 0x3 /* doubleword */ + +/* Interrupt groups - the Sigma's have flexibly configured interrupt groups + of various widths that map non-uniformly to control register bits */ + +typedef struct { + uint32 psw2_inh; /* PSW2 inhibit */ + uint32 nbits; /* number of bits */ + uint32 vecbase; /* vector base */ + uint32 rwgroup; /* RWdirect group */ + uint32 regbit; /* RWdirect reg bit */ + } int_grp_t; + +#define INTG_MAX 17 /* max # int groups */ +#define EIGRP_DFLT 1 /* dflt # ei groups */ +#define INTG_OVR 0 /* override group */ +#define INTG_CTR 1 /* counter group */ +#define INTG_IO 2 /* I/O group */ +#define INTGIO_IO 0x2 /* I/O interrupt */ +#define INTGIO_PANEL 0x1 /* panel interrupt */ +#define INTG_E2 3 /* ext group 2 */ +#define INTG_E3 4 /* ext group 3 */ + +#define INT_V_GRP 4 /* interrupt group */ +#define INT_M_GRP 0x1F +#define INT_V_BIT 0 /* interrupt bit */ +#define INT_M_BIT 0xF +#define INT_GETGRP(x) (((x) >> INT_V_GRP) & INT_M_GRP) +#define INT_GETBIT(x) (((x) >> INT_V_BIT) & INT_M_BIT) +#define INTV(x,y) (((x) << INT_V_GRP) | ((y) << INT_V_BIT)) +#define NO_INT (INTV (INTG_MAX, 0)) + +#define VEC_C1P 0x52 /* clock pulse vectors */ +#define VEC_C4P 0x55 +#define VEC_C1Z 0x58 /* clock zero vector */ + +/* Integer data operations and condition codes */ + +#define SEXT_RN_W(x) (((x) & RNSIGN)? ((x) | ~RNMASK): ((x) & RNMASK)) +#define SEXT_H_W(x) (((x) & HSIGN)? ((x) | ~HMASK): ((x) & HMASK)) +#define SEXT_LIT_W(x) (((x) & LITSIGN)? ((x) | ~LITMASK): ((x) & LITMASK)) +#define NEG_W(x) ((~(x) + 1) & WMASK) +#define NEG_D(x,y) do { y = NEG_W(y); x = (~(x) + ((y) == 0)) & WMASK; } while (0) +#define CC34_W(x) CC = (((x) & WSIGN)? \ + ((CC & ~CC3) | CC4): \ + (((x) != 0)? \ + ((CC & ~CC4) | CC3): \ + (CC & ~(CC3|CC4)))) +#define CC234_CMP(x,y) CC = (CC & CC1) | Cmp32 ((x), (y)) | \ + (((x) & (y))? CC2: 0) + +/* Instructions */ + +enum opcodes { + OP_00, OP_01, OP_LCFI, OP_03, OP_CAL1, OP_CAL2, OP_CAL3, OP_CAL4, + OP_PLW, OP_PSW, OP_PLM, OP_PSM, OP_PLS, OP_PSS, OP_LPSD, OP_XPSD, + OP_AD, OP_CD, OP_LD, OP_MSP, OP_14, OP_STD, OP_16, OP_17, + OP_SD, OP_CLM, OP_LCD, OP_LAD, OP_FSL, OP_FAL, OP_FDL, OP_FML, + OP_AI, OP_CI, OP_LI, OP_MI, OP_SF, OP_S, OP_LAS, OP_27, + OP_CVS, OP_CVA, OP_LM, OP_STM, OP_LRA, OP_LMS, OP_WAIT, OP_LRP, + OP_AW, OP_CW, OP_LW, OP_MTW, OP_LVAW, OP_STW, OP_DW, OP_MW, + OP_SW, OP_CLR, OP_LCW, OP_LAW, OP_FSS, OP_FAS, OP_FDS, OP_FMS, + OP_TTBS, OP_TBS, OP_42, OP_43, OP_ANLZ, OP_CS, OP_XW, OP_STS, + OP_EOR, OP_OR, OP_LS, OP_AND, OP_SIO, OP_TIO, OP_TDV, OP_HIO, + OP_AH, OP_CH, OP_LH, OP_MTH, OP_54, OP_STH, OP_DH, OP_MH, + OP_SH, OP_59, OP_LCH, OP_LAH, OP_5C, OP_5D, OP_5E, OP_5F, + OP_CBS, OP_MBS, OP_62, OP_EBS, OP_BDR, OP_BIR, OP_AWM, OP_EXU, + OP_BCR, OP_BCS, OP_BAL, OP_INT, OP_RD, OP_WD, OP_AIO, OP_MMC, + OP_LCF, OP_CB, OP_LB, OP_MTB, OP_STCF, OP_STB, OP_PACK, OP_UNPK, + OP_DS, OP_DA, OP_DD, OP_DM, OP_DSA, OP_DC, OP_DL, OP_DST + }; + +/* Function prototypes */ + +uint32 Ea (uint32 ir, uint32 *bva, uint32 acc, uint32 lnt); +uint32 ReadB (uint32 bva, uint32 *dat, uint32 acc); +uint32 ReadH (uint32 bva, uint32 *dat, uint32 acc); +uint32 ReadW (uint32 bva, uint32 *dat, uint32 acc); +uint32 ReadD (uint32 bva, uint32 *dat, uint32 *dat1, uint32 acc); +uint32 WriteB (uint32 bva, uint32 dat, uint32 acc); +uint32 WriteH (uint32 bva, uint32 dat, uint32 acc); +uint32 WriteW (uint32 bva, uint32 dat, uint32 acc); +uint32 WriteD (uint32 bva, uint32 dat, uint32 dat1, uint32 acc); +uint32 ReadMemVW (uint32 bva, uint32 *dat, uint32 acc); +uint32 WriteMemVW (uint32 bva, uint32 dat, uint32 acc); +uint32 ReadPB (uint32 ba, uint32 *dat); +uint32 WritePB (uint32 ba, uint32 dat); +uint32 ReadPW (uint32 pa, uint32 *dat); +uint32 WritePW (uint32 pa, uint32 dat); +uint32 ReadHist (uint32 bva, uint32 *dat, uint32 *dat1, uint32 acc, uint32 lnt); + +#endif \ No newline at end of file diff --git a/sigma/sigma_dk.c b/sigma/sigma_dk.c new file mode 100644 index 00000000..e732465b --- /dev/null +++ b/sigma/sigma_dk.c @@ -0,0 +1,470 @@ +/* sigma_dk.c: 7250/7251-7252 cartridge disk simulator + + Copyright (c) 2007-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. + + dk 7250/7251-7252 cartridge disk + + Transfers are always done a sector at a time. +*/ + +#include "sigma_io_defs.h" +#include + +#define UNIT_V_HWLK (UNIT_V_UF + 0) /* hwre write lock */ +#define UNIT_HWLK (1u << UNIT_V_HWLK) +#define UNIT_WPRT (UNIT_HWLK|UNIT_RO) /* write prot */ +#define UTRK u3 /* current track */ + +/* Constants */ + +#define DK_NUMDR 8 /* drives/ctlr */ +#define DK_WDSC 90 /* words/sector */ +#define DK_SCTK 16 /* sectors/track */ +#define DK_TKUN 408 /* tracks/unit */ +#define DK_WDUN (DK_WDSC*DK_SCTK*DK_TKUN) /* words/unit */ + +/* Address bytes */ + +#define DKA_V_TK 4 /* track offset */ +#define DKA_M_TK 0x1FF +#define DKA_V_SC 0 /* sector offset */ +#define DKA_M_SC 0xF +#define DKA_GETTK(x) (((x) >> DKA_V_TK) & DKA_M_TK) +#define DKA_GETSC(x) (((x) >> DKA_V_SC) & DKA_M_SC) + +/* Status byte 3 is current sector */ + +#define DKS_NBY 3 + +/* Device state */ + +#define DKS_INIT 0x101 +#define DKS_END 0x102 +#define DKS_WRITE 0x01 +#define DKS_READ 0x02 +#define DKS_SEEK 0x03 +#define DKS_SEEK2 0x103 +#define DKS_SENSE 0x04 +#define DKS_CHECK 0x05 +#define DKS_RDEES 0x12 +#define DKS_TEST 0x13 + +/* Device status */ + +#define DKV_OVR 0x80 /* overrun - NI */ +#define DKV_BADS 0x20 /* bad track */ +#define DKV_WPE 0x10 + +#define GET_PSC(x) ((int32) fmod (sim_gtime() / ((double) (x * DK_WDSC)), \ + ((double) DK_SCTK))) + +uint32 dk_cmd = 0; /* state */ +uint32 dk_flags = 0; /* status flags */ +uint32 dk_ad = 0; /* disk address */ +uint32 dk_time = 5; /* inter-word time */ +uint32 dk_stime = 20; /* inter-track time */ +uint32 dk_stopioe = 1; /* stop on I/O error */ + +extern uint32 chan_ctl_time; + +uint32 dk_disp (uint32 op, uint32 dva, uint32 *dvst); +uint32 dk_tio_status (uint32 un); +uint32 dk_tdv_status (uint32 un); +t_stat dk_chan_err (uint32 st); +t_stat dk_svc (UNIT *uptr); +t_stat dk_reset (DEVICE *dptr); +t_bool dk_inv_ad (uint32 *da); +t_bool dk_inc_ad (void); +t_bool dk_end_sec (UNIT *uptr, uint32 lnt, uint32 exp, uint32 st); + +/* DK data structures + + dk_dev DK device descriptor + dk_unit DK unit descriptor + dk_reg DK register list +*/ + +dib_t dk_dib = { DVA_DK, &dk_disp }; + +UNIT dk_unit[] = { + { UDATA (&dk_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+UNIT_BUFABLE+UNIT_MUSTBUF, DK_WDUN) }, + { UDATA (&dk_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+UNIT_BUFABLE+UNIT_MUSTBUF, DK_WDUN) }, + { UDATA (&dk_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+UNIT_BUFABLE+UNIT_MUSTBUF, DK_WDUN) }, + { UDATA (&dk_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+UNIT_BUFABLE+UNIT_MUSTBUF, DK_WDUN) }, + { UDATA (&dk_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+UNIT_BUFABLE+UNIT_MUSTBUF, DK_WDUN) }, + { UDATA (&dk_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+UNIT_BUFABLE+UNIT_MUSTBUF, DK_WDUN) }, + { UDATA (&dk_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+UNIT_BUFABLE+UNIT_MUSTBUF, DK_WDUN) }, + { UDATA (&dk_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+UNIT_BUFABLE+UNIT_MUSTBUF, DK_WDUN) } + }; + +REG dk_reg[] = { + { HRDATA (CMD, dk_cmd, 9) }, + { HRDATA (FLAGS, dk_flags, 8) }, + { HRDATA (ADDR, dk_ad, 8) }, + { DRDATA (TIME, dk_time, 24), PV_LEFT+REG_NZ }, + { DRDATA (STIME, dk_stime, 24), PV_LEFT+REG_NZ }, + { FLDATA (STOPIOE, dk_stopioe, 0) }, + { HRDATA (DEVNO, dk_dib.dva, 12), REG_HRO }, + { NULL } + }; + +MTAB dk_mod[] = { + { UNIT_HWLK, 0, "write enabled", "WRITEENABLED", NULL }, + { UNIT_HWLK, UNIT_HWLK, "write locked", "LOCKED", NULL }, + { MTAB_XTD|MTAB_VDV, 0, "CHAN", "CHAN", + &io_set_dvc, &io_show_dvc, NULL }, + { MTAB_XTD|MTAB_VDV, 0, "DVA", "DVA", + &io_set_dva, &io_show_dva, NULL }, + { MTAB_XTD|MTAB_VDV|MTAB_NMO, 0, "CSTATE", NULL, + NULL, &io_show_cst, NULL }, + { 0 } + }; + +DEVICE dk_dev = { + "DK", dk_unit, dk_reg, dk_mod, + DK_NUMDR, 16, 22, 1, 16, 32, + NULL, NULL, &dk_reset, + NULL, NULL, NULL, + &dk_dib, DEV_DISABLE + }; + +/* DK: IO dispatch routine */ + +uint32 dk_disp (uint32 op, uint32 dva, uint32 *dvst) +{ +uint32 i; +uint32 un = DVA_GETUNIT (dva); +UNIT *uptr; + +if ((un >= DK_NUMDR) || /* inv unit num? */ + (dk_unit[un].flags & UNIT_DIS)) /* disabled unit? */ + return DVT_NODEV; +switch (op) { /* case on op */ + + case OP_SIO: /* start I/O */ + *dvst = dk_tio_status (un); /* get status */ + if ((*dvst & (DVS_CST|DVS_DST)) == 0) { /* ctrl + dev idle? */ + dk_cmd = DKS_INIT; /* start dev thread */ + sim_activate (&dk_unit[un], chan_ctl_time); + } + break; + + case OP_TIO: /* test status */ + *dvst = dk_tio_status (un); /* return status */ + break; + + case OP_TDV: /* test status */ + *dvst = dk_tdv_status (un); /* return status */ + break; + + case OP_HIO: /* halt I/O */ + chan_clr_chi (dk_dib.dva); /* clr int */ + *dvst = dk_tio_status (un); /* get status */ + if ((*dvst & DVS_CST) != 0) { /* ctrl busy? */ + for (i = 0; i < DK_NUMDR; i++) { /* find busy unit */ + uptr = &dk_unit[i]; + if (sim_is_active (uptr)) { /* active? */ + sim_cancel (uptr); /* stop */ + chan_uen (dk_dib.dva); /* uend */ + } /* end if active */ + } /* end for */ + } + break; + + case OP_AIO: /* acknowledge int */ + chan_clr_chi (dk_dib.dva); /* clr int */ + *dvst = dk_tdv_status (un); /* status like TDV */ + break; + + default: + *dvst = 0; + return SCPE_IERR; + } + +return 0; +} + +/* Unit service */ + +t_stat dk_svc (UNIT *uptr) +{ +uint32 i, sc, da, wd, wd1, cmd, c[3]; +uint32 *fbuf = (uint32 *) uptr->filebuf; +int32 t, dc; +uint32 st; + +switch (dk_cmd) { + + case DKS_INIT: /* init state */ + st = chan_get_cmd (dk_dib.dva, &cmd); /* get command */ + if (CHS_IFERR (st)) /* channel error? */ + return dk_chan_err (st); + if ((cmd == 0) || /* invalid cmd? */ + ((cmd > DKS_CHECK) && (cmd != DKS_RDEES) && (cmd != DKS_TEST))) { + chan_uen (dk_dib.dva); /* uend */ + return SCPE_OK; + } + dk_flags = 0; /* clear status */ + dk_cmd = cmd & 0x17; /* next state */ + if ((cmd == DKS_SEEK) || /* fast cmd? */ + (cmd == DKS_SENSE) || + (cmd == DKS_TEST)) + sim_activate (uptr, chan_ctl_time); /* schedule soon */ + else { /* data transfer */ + sc = DKA_GETSC (dk_ad); /* new sector */ + t = sc - GET_PSC (dk_time); /* delta to new */ + if (t < 0) /* wrap around? */ + t = t + DK_SCTK; + sim_activate (uptr, t * dk_time * DK_WDSC); /* schedule op */ + } + return SCPE_OK; + + case DKS_END: /* end state */ + st = chan_end (dk_dib.dva); /* set channel end */ + if (CHS_IFERR (st)) /* channel error? */ + return dk_chan_err (st); + if (st == CHS_CCH) { /* command chain? */ + dk_cmd = DKS_INIT; /* restart thread */ + sim_activate (uptr, chan_ctl_time); + } + return SCPE_OK; /* done */ + + case DKS_SEEK: /* seek */ + c[0] = c[1] = 0; + for (i = 0, st = 0; (i < 2) && (st != CHS_ZBC); i++) { + st = chan_RdMemB (dk_dib.dva, &c[i]); /* get byte */ + if (CHS_IFERR (st)) /* channel error? */ + return dk_chan_err (st); + } + dk_ad = ((c[0] & 0x7F) << 8) | c[1]; /* new address */ + if (((i != 2) || (st != CHS_ZBC)) && /* length error? */ + chan_set_chf (dk_dib.dva, CHF_LNTE)) /* care? */ + return SCPE_OK; + dc = DKA_GETTK (dk_ad); /* desired track */ + t = abs (uptr->UTRK - dc); /* get track diff */ + if (t == 0) + t = 1; + sim_activate (uptr, t * dk_stime); + uptr->UTRK = dc; /* put on track */ + dk_cmd = DKS_SEEK2; + return SCPE_OK; + + case DKS_SEEK2: /* seek complete */ + if (uptr->UTRK >= DK_TKUN) { + dk_flags |= DKV_BADS; + chan_uen (dk_dib.dva); + return SCPE_OK; + } + break; /* seek done */ + + case DKS_SENSE: /* sense */ + c[0] = ((dk_ad >> 8) & 0x7F) | ((uptr->flags & UNIT_RO)? 0x80: 0); + c[1] = dk_ad & 0xFF; /* address */ + c[2] = GET_PSC (dk_time); /* curr sector */ + for (i = 0, st = 0; (i < DKS_NBY) && (st != CHS_ZBC); i++) { + st = chan_WrMemB (dk_dib.dva, c[i]); /* store char */ + if (CHS_IFERR (st)) /* channel error? */ + return dk_chan_err (st); + } + if (((i != DKS_NBY) || (st != CHS_ZBC)) && + chan_set_chf (dk_dib.dva, CHF_LNTE)) /* length error? */ + return SCPE_OK; + break; + + case DKS_WRITE: /* write */ + if (uptr->flags & UNIT_RO) { /* write locked? */ + dk_flags |= DKV_WPE; /* set status */ + chan_uen (dk_dib.dva); /* uend */ + return SCPE_OK; + } + if (dk_inv_ad (&da)) { /* invalid addr? */ + chan_uen (dk_dib.dva); /* uend */ + return SCPE_OK; + } + for (i = 0, st = 0; i < DK_WDSC; da++, i++) { /* sector loop */ + if (st != CHS_ZBC) { /* chan not done? */ + st = chan_RdMemW (dk_dib.dva, &wd); /* read word */ + if (CHS_IFERR (st)) { /* channel error? */ + dk_inc_ad (); /* da increments */ + return dk_chan_err (st); + } + } + else wd = 0; + fbuf[da] = wd; /* store in buffer */ + if (da >= uptr->hwmark) /* update length */ + uptr->hwmark = da + 1; + } + if (dk_end_sec (uptr, i, DK_WDSC, st)) /* transfer done? */ + return SCPE_OK; /* err or cont */ + break; + +/* Must be done by bytes to get precise miscompare */ + + case DKS_CHECK: /* write check */ + if (dk_inv_ad (&da)) { /* invalid addr? */ + chan_uen (dk_dib.dva); /* uend */ + return SCPE_OK; + } + for (i = 0, st = 0; (i < (DK_WDSC * 4)) && (st != CHS_ZBC); ) { + st = chan_RdMemB (dk_dib.dva, &wd); /* read byte */ + if (CHS_IFERR (st)) { /* channel error? */ + dk_inc_ad (); /* da increments */ + return dk_chan_err (st); + } + wd1 = (fbuf[da] >> (24 - ((i % 4) * 8))) & 0xFF; /* byte */ + if (wd != wd1) { /* check error? */ + dk_inc_ad (); /* da increments */ + chan_set_chf (dk_dib.dva, CHF_XMDE); /* set xmt err flag */ + chan_uen (dk_dib.dva); /* force uend */ + return SCPE_OK; + } + da = da + ((++i % 4) == 0); /* every 4th byte */ + } + if (dk_end_sec (uptr, i, DK_WDSC * 4, st)) /* transfer done? */ + return SCPE_OK; /* err or cont */ + break; + + case DKS_READ: /* read */ + if (dk_inv_ad (&da)) { /* invalid addr? */ + chan_uen (dk_dib.dva); /* uend */ + return SCPE_OK; + } + for (i = 0, st = 0; (i < DK_WDSC) && (st != CHS_ZBC); da++, i++) { + st = chan_WrMemW (dk_dib.dva, fbuf[da]); /* store in mem */ + if (CHS_IFERR (st)) { /* channel error? */ + dk_inc_ad (); /* da increments */ + return dk_chan_err (st); + } + } + if (dk_end_sec (uptr, i, DK_WDSC, st)) /* transfer done? */ + return SCPE_OK; /* err or cont */ + break; + } + +dk_cmd = DKS_END; /* op done, next state */ +sim_activate (uptr, chan_ctl_time); +return SCPE_OK; +} + +/* Common read/write sector end routine + + case 1 - more to transfer, not end disk - reschedule, return TRUE + case 2 - more to transfer, end disk - uend, return TRUE + case 3 - transfer done, length error - uend, return TRUE + case 4 - transfer done, no length error - return FALSE (sched end state) +*/ + +t_bool dk_end_sec (UNIT *uptr, uint32 lnt, uint32 exp, uint32 st) +{ +if (st != CHS_ZBC) { /* end record? */ + if (dk_inc_ad ()) /* inc addr, ovf? */ + chan_uen (dk_dib.dva); /* uend */ + else sim_activate (uptr, dk_time * 16); /* no, next sector */ + return TRUE; + } +dk_inc_ad (); /* just incr addr */ +if ((lnt != exp) && /* length error? */ + chan_set_chf (dk_dib.dva, CHF_LNTE)) /* do we care? */ + return TRUE; +return FALSE; /* cmd done */ +} + +/* DK status routine */ + +uint32 dk_tio_status (uint32 un) +{ +uint32 i; + +for (i = 0; i < DK_NUMDR; i++) { /* loop thru units */ + if (sim_is_active (&dk_unit[i])) /* active? */ + return (DVS_AUTO | DVS_CBUSY | (CC2 << DVT_V_CC) | + ((i == un)? DVS_DBUSY: 0)); + } +return DVS_AUTO; +} + +uint32 dk_tdv_status (uint32 un) +{ +return dk_flags | (dk_inv_ad (NULL)? DKV_BADS: 0); +} + +/* Validate disk address */ + +t_bool dk_inv_ad (uint32 *da) +{ +uint32 tk = DKA_GETTK (dk_ad); +uint32 sc = DKA_GETSC (dk_ad); + +if (tk >= DK_TKUN) /* badtrk? */ + return TRUE; +if (da) /* return word addr */ + *da = ((tk * DK_SCTK) + sc) * DK_WDSC; +return FALSE; +} + +/* Increment disk address */ + +t_bool dk_inc_ad (void) +{ +uint32 tk = DKA_GETTK (dk_ad); +uint32 sc = DKA_GETSC (dk_ad); + +sc = sc + 1; /* sector++ */ +if (sc >= DK_SCTK) { /* overflow? */ + sc = 0; /* wrap sector */ + tk = tk + 1; /* track++ */ + } +dk_ad = ((tk << DKA_V_TK) | /* rebuild dk_ad */ + (sc << DKA_V_SC)); +if (tk >= DK_TKUN) /* invalid addr? */ + return TRUE; +return FALSE; +} + +/* Channel error */ + +t_stat dk_chan_err (uint32 st) +{ +chan_uen (dk_dib.dva); /* uend */ +if (st < CHS_ERR) + return st; +return SCPE_OK; +} + +/* Reset routine */ + +t_stat dk_reset (DEVICE *dptr) +{ +uint32 i; + +for (i = 0; i < DK_NUMDR; i++) { + sim_cancel (&dk_unit[i]); /* stop dev thread */ + dk_unit[i].UTRK = 0; + } +dk_cmd = 0; +dk_flags = 0; +dk_ad = 0; +chan_reset_dev (dk_dib.dva); /* clr int, active */ +return SCPE_OK; +} diff --git a/sigma/sigma_doc.doc b/sigma/sigma_doc.doc new file mode 100644 index 0000000000000000000000000000000000000000..0cfb805c4d2bd5fe73bd0967e8f8b2610a545fd7 GIT binary patch literal 90624 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 G0{ + +#define UNIT_V_HWLK (UNIT_V_UF + 0) /* hwre write lock */ +#define UNIT_HWLK (1u << UNIT_V_HWLK) +#define UNIT_WPRT (UNIT_HWLK|UNIT_RO) /* write prot */ +#define UNIT_V_AUTO (UNIT_V_UF + 1) /* autosize */ +#define UNIT_AUTO (1u << UNIT_V_AUTO) +#define UNIT_V_DTYPE (UNIT_V_UF + 2) /* drive type */ +#define UNIT_M_DTYPE 0x7 +#define UNIT_DTYPE (UNIT_M_DTYPE << UNIT_V_DTYPE) +#define UDA u3 /* disk addr */ +#define UCMD u4 /* current command */ +#define UCTX u5 /* ctrl/ctx index */ +#define GET_DTYPE(x) (((x) >> UNIT_V_DTYPE) & UNIT_M_DTYPE) + +/* Constants */ + +#define DP_NUMCTL 2 /* number of controllers */ +#define DP_C7270 0 /* 7270 ctrl */ +#define DP_C3281 1 /* 3281 ctrl */ +#define DP_NUMDR_7270 8 /* drives/ctrl */ +#define DP_NUMDR_3281 15 +#define DP_CONT DP_NUMDR_3281 /* ctrl's drive # */ +#define DP_WDSC 256 /* words/sector */ +#define DP_BYHD 8 /* byte/header */ +#define DP_NUMDR ((uint32) ((ctx->dp_ctype == DP_C7270)? DP_NUMDR_7270: DP_NUMDR_3281)) +#define DP_SEEK (DP_CONT + 1) + +/* Address bytes */ + +#define DPA_V_CY 16 /* cylinder offset */ +#define DPA_M_CY 0x3FF +#define DPA_V_HD 8 /* head offset */ +#define DPA_M_HD 0x1F +#define DPA_V_SC 0 /* sector offset */ +#define DPA_M_SC 0x1F +#define DPA_GETCY(x) (((x) >> DPA_V_CY) & DPA_M_CY) +#define DPA_GETHD(x) (((x) >> DPA_V_HD) & DPA_M_HD) +#define DPA_GETSC(x) (((x) >> DPA_V_SC) & DPA_M_SC) + +/* Sense order */ + +#define DPS_NBY_7270 10 +#define DPS_NBY_3281 16 +#define DPS_NBY ((uint32) ((ctx->dp_ctype == DP_C7270)? DPS_NBY_7270: DPS_NBY_3281)) + +/* Test mode */ + +#define DPT_NBY_7270 1 /* bytes/test mode spec */ +#define DPT_NBY_3281 2 +#define DPT_NBY ((uint32) ((ctx->dp_ctype == DP_C7270)? DPT_NBY_7270: DPT_NBY_3281)) + +/* Commands */ + +#define DPS_INIT 0x100 +#define DPS_END 0x101 +#define DPS_WRITE 0x01 +#define DPS_READ 0x02 +#define DPS_SEEK 0x03 +#define DPS_SEEKI 0x83 +#define DPS_SENSE 0x04 +#define DPS_CHECK 0x05 +#define DPS_RSRV 0x07 +#define DPS_WHDR 0x09 +#define DPS_RHDR 0x0A +#define DPS_CRIOF 0x0F +#define DPS_RDEES 0x12 +#define DPS_TEST 0x13 +#define DPS_RLS 0x17 +#define DPS_CRION 0x1F +#define DPS_RLSA 0x23 +#define DPS_RECAL 0x33 +#define DPS_RECALI 0xB3 + +/* Seek completion states */ + +#define DSC_SEEK 0x00 /* seeking */ +#define DSC_SEEKI 0x80 /* seeking, then int */ +#define DSC_SEEKW 0x01 /* waiting to int */ + +/* Device status - note that these are device independent */ + +#define DPF_V_WCHK 0 +#define DPF_V_DPE 1 +#define DPF_V_SNZ 2 +#define DPF_V_EOC 3 +#define DPF_V_IVA 4 +#define DPF_V_PGE 5 +#define DPF_V_WPE 6 +#define DPF_V_AIM 7 +#define DPF_WCHK (1u << DPF_V_WCHK) /* wrt chk error */ +#define DPF_DPE (1u << DPF_V_DPE) /* data error */ +#define DPF_SNZ (1u << DPF_V_SNZ) /* sec# != 0 */ +#define DPF_EOC (1u << DPF_V_EOC) /* end cylinder */ +#define DPF_IVA (1u << DPF_V_IVA) /* invalid addr */ +#define DPF_PGE (1u << DPF_V_PGE) /* prog error */ +#define DPF_WPE (1u << DPF_V_WPE) /* wrt prot err */ +#define DPF_AIM (1u << DPF_V_AIM) /* arm in motion */ +#define DPF_V_DIFF 16 +#define DPF_M_DIFF 0xFFFFu +#define DPF_DIFF (DPF_M_DIFF << DPF_V_DIFF) + +/* Drive types */ + +/* These controllers support many different disk drive types: + + type #sectors/ #surfaces/ #cylinders/ + surface cylinder drive + + 7242 6 20 204 + 7261 11 20 204 + 7271 6 20 408 + 3288 17 5 823 =67MB + 7275 11 19 411 =88MB + 7276 11 19 815 =176MB + 3283 17 18 815 + + 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 DP_SZ(x) ((DPCY_##x) * (DPHD_##x) * (DPSC_##x) * DP_WDSC) +#define DP_ENT(x,y) (DP_##x), (DPCY_##x), (DPHD_##x), (DPSC_##x), (DP_C##y), (DPSZ_##x) + +#define DP_7242 0 +#define DPCY_7242 204 +#define DPHD_7242 20 +#define DPSC_7242 6 +#define DPSZ_7242 DP_SZ(7242) + +#define DP_7261 1 +#define DPCY_7261 204 +#define DPHD_7261 20 +#define DPSC_7261 11 +#define DPSZ_7261 DP_SZ(7261) + +#define DP_7271 2 +#define DPCY_7271 408 +#define DPHD_7271 20 +#define DPSC_7271 6 +#define DPSZ_7271 DP_SZ(7271) + +#define DP_3288 3 +#define DPCY_3288 822 +#define DPHD_3288 5 +#define DPSC_3288 17 +#define DPSZ_3288 DP_SZ(3288) + +#define DP_7275 4 +#define DPCY_7275 411 +#define DPHD_7275 19 +#define DPSC_7275 11 +#define DPSZ_7275 DP_SZ(7275) + +#define DP_7276 5 +#define DPCY_7276 815 +#define DPHD_7276 19 +#define DPSC_7276 11 +#define DPSZ_7276 DP_SZ(7276) + +#define DP_3283 6 +#define DPCY_3283 815 +#define DPHD_3283 19 +#define DPSC_3283 17 +#define DPSZ_3283 DP_SZ(3283) + +#define GET_PSC(x,s) ((int32) fmod (sim_gtime() / ((double) (x * DP_WDSC)), \ + ((double) (s)))) + +typedef struct { + uint32 dp_ctype; /* controller type */ + uint32 dp_flags; /* status flags */ + uint32 dp_ski; /* seek interrupts */ + uint32 dp_time; /* inter-word time */ + uint32 dp_stime; /* inter-track time */ + uint32 dp_stopioe; /* stop on I/O error */ + uint32 dp_test; /* test mode */ + } DP_CTX; + +typedef struct { + uint32 dtype; /* drive type */ + uint32 cy; /* cylinders */ + uint32 hd; /* heads */ + uint32 sc; /* sectors */ + uint32 ctype; /* controller */ + uint32 capac; /* capacity */ + } DP_TYPE; + +typedef struct { + uint32 byte; /* offset in array */ + uint32 mask; /* test mask */ + uint32 fpos; /* from position */ + uint32 tpos; /* to position */ + } DP_SNSTAB; + +static uint32 dp_buf[DP_WDSC]; + +extern uint32 chan_ctl_time; + +uint32 dpa_disp (uint32 op, uint32 dva, uint32 *dvst); +uint32 dpb_disp (uint32 op, uint32 dva, uint32 *dvst); +uint32 dp_disp (uint32 cidx, uint32 op, uint32 dva, uint32 *dvst); +uint32 dp_tio_status (uint32 cidx, uint32 un); +uint32 dp_tdv_status (uint32 cidx, uint32 un); +uint32 dp_aio_status (uint32 cidx, uint32 un); +void dp_set_sense (UNIT *uptr, uint32 *c); +t_stat dp_chan_err (uint32 dva, uint32 st); +t_stat dp_svc (UNIT *uptr); +t_stat dps_svc (UNIT *uptr); +t_stat dp_reset (DEVICE *dptr); +t_bool dp_inv_ad (UNIT *uptr, uint32 *da); +t_bool dp_inc_ad (UNIT *uptr); +t_stat dp_read (UNIT *uptr, uint32 da); +t_stat dp_write (UNIT *uptr, uint32 da); +t_stat dp_ioerr (UNIT *uptr); +t_bool dp_test_mode (uint32 cidx); +t_bool dp_end_sec (UNIT *uptr, uint32 lnt, uint32 exp, uint32 st); +int32 dp_clr_int (uint32 cidx); +void dp_set_ski (uint32 cidx, uint32 un); +void dp_clr_ski (uint32 cidx, uint32 un); +t_stat dp_attach (UNIT *uptr, char *cptr); +t_stat dp_set_size (UNIT *uptr, int32 val, char *cptr, void *desc); +t_stat dp_set_ctl (UNIT *uptr, int32 val, char *cptr, void *desc); +t_stat dp_show_ctl (FILE *st, UNIT *uptr, int32 val, void *desc); + +static DP_TYPE dp_tab[] = { + { DP_ENT (7242, 7270) }, + { DP_ENT (7261, 3281) }, + { DP_ENT (7271, 7270) }, + { DP_ENT (3288, 3281) }, + { DP_ENT (7275, 3281) }, + { DP_ENT (7276, 3281) }, + { DP_ENT (3283, 3281) }, + { 0, 0, 0, 0, 0, 0 }, + }; + +static DP_SNSTAB dp_sense_7270[] = { + { 8, DPF_WCHK, DPF_V_WCHK, 6 }, + { 8, DPF_SNZ, DPF_V_SNZ, 2 }, + { 9, 0x01000000, 24, 0 }, + { 0, 0, 0, 0 } + }; + +static DP_SNSTAB dp_sense_3281[] = { + { 8, DPF_WCHK, DPF_V_WCHK, 7 }, + { 8, DPF_EOC, DPF_V_EOC, 3}, + { 8, DPF_AIM, DPF_V_AIM, 2}, + { 14, 0xFF000000, 24, 0 }, + { 15, 0x00FF0000, 16, 0 }, + { 0, 0, 0, 0 } + }; + +/* Command table, indexed by command */ + +#define C_7270 (1u << DP_C7270) +#define C_3281 (1u << DP_C3281) +#define C_B (C_7270|C_3281) +#define C_F (1u << 2) /* fast */ +#define C_C (1u << 3) /* ctrl cmd */ + +static uint8 dp_cmd[256] = { + 0, C_B, C_B, C_B, C_B|C_F, C_B, 0, C_3281|C_F, + 0, C_B, C_B, 0, 0, 0, 0, C_3281|C_F|C_C, + 0, 0, C_B, C_B|C_F, 0, 0, 0, C_3281|C_F, + 0, 0, 0, 0, 0, 0, 0, C_3281|C_F|C_C, + 0, 0, 0, C_7270|C_F, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, C_B, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, C_B, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, C_3281, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0 + }; + +/* DP data structures + + dp_dev DP device descriptor + dp_unit DP unit descriptor + dp_reg DP register list +*/ + +dib_t dp_dib[] = { + { DVA_DPA, &dpa_disp }, + { DVA_DPB, &dpb_disp } + }; + +DP_CTX dp_ctx[] = { + { DP_C7270 }, + { DP_C3281 } + }; + +UNIT dpa_unit[] = { + { UDATA (&dp_svc, (DP_7271 << UNIT_V_DTYPE)+UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE, DPSZ_7271) }, + { UDATA (&dp_svc, (DP_7271 << UNIT_V_DTYPE)+UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE, DPSZ_7271) }, + { UDATA (&dp_svc, (DP_7271 << UNIT_V_DTYPE)+UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE, DPSZ_7271) }, + { UDATA (&dp_svc, (DP_7271 << UNIT_V_DTYPE)+UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE, DPSZ_7271) }, + { UDATA (&dp_svc, (DP_7271 << UNIT_V_DTYPE)+UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE, DPSZ_7271) }, + { UDATA (&dp_svc, (DP_7271 << UNIT_V_DTYPE)+UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE, DPSZ_7271) }, + { UDATA (&dp_svc, (DP_7271 << UNIT_V_DTYPE)+UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE, DPSZ_7271) }, + { UDATA (&dp_svc, (DP_7271 << UNIT_V_DTYPE)+UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE, DPSZ_7271) }, + { UDATA (&dp_svc, (DP_7271 << UNIT_V_DTYPE)+UNIT_FIX+UNIT_ATTABLE+UNIT_DIS, DPSZ_7271) }, + { UDATA (&dp_svc, (DP_7271 << UNIT_V_DTYPE)+UNIT_FIX+UNIT_ATTABLE+UNIT_DIS, DPSZ_7271) }, + { UDATA (&dp_svc, (DP_7271 << UNIT_V_DTYPE)+UNIT_FIX+UNIT_ATTABLE+UNIT_DIS, DPSZ_7271) }, + { UDATA (&dp_svc, (DP_7271 << UNIT_V_DTYPE)+UNIT_FIX+UNIT_ATTABLE+UNIT_DIS, DPSZ_7271) }, + { UDATA (&dp_svc, (DP_7271 << UNIT_V_DTYPE)+UNIT_FIX+UNIT_ATTABLE+UNIT_DIS, DPSZ_7271) }, + { UDATA (&dp_svc, (DP_7271 << UNIT_V_DTYPE)+UNIT_FIX+UNIT_ATTABLE+UNIT_DIS, DPSZ_7271) }, + { UDATA (&dp_svc, (DP_7271 << UNIT_V_DTYPE)+UNIT_FIX+UNIT_ATTABLE+UNIT_DIS, DPSZ_7271) }, + { UDATA (&dp_svc, UNIT_DIS, 0) }, + { UDATA (&dps_svc, UNIT_DIS, 0) }, + { UDATA (&dps_svc, UNIT_DIS, 0) }, + { UDATA (&dps_svc, UNIT_DIS, 0) }, + { UDATA (&dps_svc, UNIT_DIS, 0) }, + { UDATA (&dps_svc, UNIT_DIS, 0) }, + { UDATA (&dps_svc, UNIT_DIS, 0) }, + { UDATA (&dps_svc, UNIT_DIS, 0) }, + { UDATA (&dps_svc, UNIT_DIS, 0) }, + { UDATA (&dps_svc, UNIT_DIS, 0) }, + { UDATA (&dps_svc, UNIT_DIS, 0) }, + { UDATA (&dps_svc, UNIT_DIS, 0) }, + { UDATA (&dps_svc, UNIT_DIS, 0) }, + { UDATA (&dps_svc, UNIT_DIS, 0) }, + { UDATA (&dps_svc, UNIT_DIS, 0) }, + { UDATA (&dps_svc, UNIT_DIS, 0) }, + }; + +UNIT dpb_unit[] = { + { UDATA (&dp_svc, (DP_7276 << UNIT_V_DTYPE)+UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE, DPSZ_7276) }, + { UDATA (&dp_svc, (DP_7276 << UNIT_V_DTYPE)+UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE, DPSZ_7276) }, + { UDATA (&dp_svc, (DP_7276 << UNIT_V_DTYPE)+UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE, DPSZ_7276) }, + { UDATA (&dp_svc, (DP_7276 << UNIT_V_DTYPE)+UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE, DPSZ_7276) }, + { UDATA (&dp_svc, (DP_7276 << UNIT_V_DTYPE)+UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE, DPSZ_7276) }, + { UDATA (&dp_svc, (DP_7276 << UNIT_V_DTYPE)+UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE, DPSZ_7276) }, + { UDATA (&dp_svc, (DP_7276 << UNIT_V_DTYPE)+UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE, DPSZ_7276) }, + { UDATA (&dp_svc, (DP_7276 << UNIT_V_DTYPE)+UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE, DPSZ_7276) }, + { UDATA (&dp_svc, (DP_7276 << UNIT_V_DTYPE)+UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+UNIT_DIS, DPSZ_7276) }, + { UDATA (&dp_svc, (DP_7276 << UNIT_V_DTYPE)+UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+UNIT_DIS, DPSZ_7276) }, + { UDATA (&dp_svc, (DP_7276 << UNIT_V_DTYPE)+UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+UNIT_DIS, DPSZ_7276) }, + { UDATA (&dp_svc, (DP_7276 << UNIT_V_DTYPE)+UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+UNIT_DIS, DPSZ_7276) }, + { UDATA (&dp_svc, (DP_7276 << UNIT_V_DTYPE)+UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+UNIT_DIS, DPSZ_7276) }, + { UDATA (&dp_svc, (DP_7276 << UNIT_V_DTYPE)+UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+UNIT_DIS, DPSZ_7276) }, + { UDATA (&dp_svc, (DP_7276 << UNIT_V_DTYPE)+UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+UNIT_DIS, DPSZ_7276) }, + { UDATA (&dp_svc, UNIT_DIS, 0) }, + { UDATA (&dps_svc, UNIT_DIS, 0) }, + { UDATA (&dps_svc, UNIT_DIS, 0) }, + { UDATA (&dps_svc, UNIT_DIS, 0) }, + { UDATA (&dps_svc, UNIT_DIS, 0) }, + { UDATA (&dps_svc, UNIT_DIS, 0) }, + { UDATA (&dps_svc, UNIT_DIS, 0) }, + { UDATA (&dps_svc, UNIT_DIS, 0) }, + { UDATA (&dps_svc, UNIT_DIS, 0) }, + { UDATA (&dps_svc, UNIT_DIS, 0) }, + { UDATA (&dps_svc, UNIT_DIS, 0) }, + { UDATA (&dps_svc, UNIT_DIS, 0) }, + { UDATA (&dps_svc, UNIT_DIS, 0) }, + { UDATA (&dps_svc, UNIT_DIS, 0) }, + { UDATA (&dps_svc, UNIT_DIS, 0) }, + { UDATA (&dps_svc, UNIT_DIS, 0) }, + }; + +REG dpa_reg[] = { + { HRDATA (CTYPE, dp_ctx[0].dp_ctype, 1), REG_HRO }, + { HRDATA (FLAGS, dp_ctx[0].dp_flags, 8) }, + { GRDATA (DIFF, dp_ctx[0].dp_flags, 16, 16, 16) }, + { HRDATA (SKI, dp_ctx[0].dp_ski, 16) }, + { HRDATA (TEST, dp_ctx[0].dp_test, 16) }, + { URDATA (ADDR, dpa_unit[0].UDA, 16, 32, 0, DP_NUMDR_3281, 0) }, + { URDATA (CMD, dpa_unit[0].UCMD, 16, 10, 0, DP_NUMDR_3281, 0) }, + { DRDATA (TIME, dp_ctx[0].dp_time, 24), PV_LEFT+REG_NZ }, + { DRDATA (STIME, dp_ctx[0].dp_stime, 24), PV_LEFT+REG_NZ }, + { FLDATA (STOP_IOE, dp_ctx[0].dp_stopioe, 0) }, + { HRDATA (DEVNO, dp_dib[0].dva, 12), REG_HRO }, + { NULL } + }; + +REG dpb_reg[] = { + { HRDATA (CTYPE, dp_ctx[1].dp_ctype, 1), REG_HRO }, + { HRDATA (FLAGS, dp_ctx[1].dp_flags, 8) }, + { GRDATA (DIFF, dp_ctx[1].dp_flags, 16, 16, 16) }, + { HRDATA (SKI, dp_ctx[1].dp_ski, 16) }, + { HRDATA (TEST, dp_ctx[1].dp_test, 16) }, + { URDATA (ADDR, dpa_unit[1].UDA, 16, 32, 0, DP_NUMDR_3281, 0) }, + { URDATA (CMD, dpa_unit[1].UCMD, 16, 10, 0, DP_NUMDR_3281, 0) }, + { DRDATA (TIME, dp_ctx[1].dp_time, 24), PV_LEFT+REG_NZ }, + { DRDATA (STIME, dp_ctx[1].dp_stime, 24), PV_LEFT+REG_NZ }, + { FLDATA (STOP_IOE, dp_ctx[1].dp_stopioe, 0) }, + { HRDATA (DEVNO, dp_dib[1].dva, 12), REG_HRO }, + { NULL } + }; + +MTAB dp_mod[] = { + { MTAB_XTD|MTAB_VDV, DP_C7270, "C7270", "C7270", + &dp_set_ctl, &dp_show_ctl, NULL }, + { MTAB_XTD|MTAB_VDV, DP_C3281, "C3281", "C3281", + &dp_set_ctl, &dp_show_ctl, NULL }, + { (UNIT_DTYPE+UNIT_ATT), (DP_7242 << UNIT_V_DTYPE) + UNIT_ATT, + "7242", NULL, NULL }, + { (UNIT_DTYPE+UNIT_ATT), (DP_7261 << UNIT_V_DTYPE) + UNIT_ATT, + "7261", NULL, NULL }, + { (UNIT_DTYPE+UNIT_ATT), (DP_7271 << UNIT_V_DTYPE) + UNIT_ATT, + "7271", NULL, NULL }, + { (UNIT_DTYPE+UNIT_ATT), (DP_3288 << UNIT_V_DTYPE) + UNIT_ATT, + "3288", NULL, NULL }, + { (UNIT_DTYPE+UNIT_ATT), (DP_7275 << UNIT_V_DTYPE) + UNIT_ATT, + "7275", NULL, NULL }, + { (UNIT_DTYPE+UNIT_ATT), (DP_7276 << UNIT_V_DTYPE) + UNIT_ATT, + "7276", NULL, NULL }, + { (UNIT_DTYPE+UNIT_ATT), (DP_3283 << UNIT_V_DTYPE) + UNIT_ATT, + "3283", NULL, NULL }, + { (UNIT_AUTO+UNIT_DTYPE+UNIT_ATT), (DP_7242 << UNIT_V_DTYPE), + "7242", NULL, NULL }, + { (UNIT_AUTO+UNIT_DTYPE+UNIT_ATT), (DP_7261 << UNIT_V_DTYPE), + "7261", NULL, NULL }, + { (UNIT_AUTO+UNIT_DTYPE+UNIT_ATT), (DP_7271 << UNIT_V_DTYPE), + "7271", NULL, NULL }, + { (UNIT_AUTO+UNIT_DTYPE+UNIT_ATT), (DP_3288 << UNIT_V_DTYPE), + "3288", NULL, NULL }, + { (UNIT_AUTO+UNIT_DTYPE+UNIT_ATT), (DP_7275 << UNIT_V_DTYPE), + "7275", NULL, NULL }, + { (UNIT_AUTO+UNIT_DTYPE+UNIT_ATT), (DP_7276 << UNIT_V_DTYPE), + "7276", NULL, NULL }, + { (UNIT_AUTO+UNIT_DTYPE+UNIT_ATT), (DP_3283 << UNIT_V_DTYPE), + "3283", NULL, NULL }, + { (UNIT_AUTO+UNIT_ATT), UNIT_AUTO, "autosize", NULL, NULL }, + { UNIT_AUTO, UNIT_AUTO, NULL, "AUTOSIZE", NULL }, + { (UNIT_AUTO+UNIT_DTYPE), (DP_7242 << UNIT_V_DTYPE), + NULL, "7242", &dp_set_size }, + { (UNIT_AUTO+UNIT_DTYPE), (DP_7261 << UNIT_V_DTYPE), + NULL, "7261", &dp_set_size }, + { (UNIT_AUTO+UNIT_DTYPE), (DP_7271 << UNIT_V_DTYPE), + NULL, "7271", &dp_set_size }, + { (UNIT_AUTO+UNIT_DTYPE), (DP_3288 << UNIT_V_DTYPE), + NULL, "3288", &dp_set_size }, + { (UNIT_AUTO+UNIT_DTYPE), (DP_7275 << UNIT_V_DTYPE), + NULL, "7275", &dp_set_size }, + { (UNIT_AUTO+UNIT_DTYPE), (DP_7276 << UNIT_V_DTYPE), + NULL, "7276", &dp_set_size }, + { (UNIT_AUTO+UNIT_DTYPE), (DP_7276 << UNIT_V_DTYPE), + NULL, "3282", &dp_set_size }, + { (UNIT_AUTO+UNIT_DTYPE), (DP_3283 << UNIT_V_DTYPE), + NULL, "3283", &dp_set_size }, + { UNIT_HWLK, 0, "write enabled", "WRITEENABLED", NULL }, + { UNIT_HWLK, UNIT_HWLK, "write locked", "LOCKED", NULL }, + { MTAB_XTD|MTAB_VDV, 0, "CHAN", "CHAN", + &io_set_dvc, &io_show_dvc, NULL }, + { MTAB_XTD|MTAB_VDV, 0, "DVA", "DVA", + &io_set_dva, &io_show_dva, NULL }, + { MTAB_XTD|MTAB_VDV|MTAB_NMO, 0, "CSTATE", NULL, + NULL, &io_show_cst, NULL }, + { 0 } + }; + +DEVICE dp_dev[] = { + { + "DPA", dpa_unit, dpa_reg, dp_mod, + (2 * DP_NUMDR_3281) + 1, 16, 28, 1, 16, 32, + NULL, NULL, &dp_reset, + &io_boot, &dp_attach, NULL, + &dp_dib[0], DEV_DISABLE + }, + { + "DPB", dpb_unit, dpb_reg, dp_mod, + (2 * DP_NUMDR_3281) + 1, 16, 28, 1, 16, 32, + NULL, NULL, &dp_reset, + &io_boot, &dp_attach, NULL, + &dp_dib[1], DEV_DISABLE + } + }; + +/* DP: IO dispatch routine */ + +uint32 dpa_disp (uint32 op, uint32 dva, uint32 *dvst) +{ +return dp_disp (0, op, dva, dvst); +} + +uint32 dpb_disp (uint32 op, uint32 dva, uint32 *dvst) +{ +return dp_disp (1, op, dva, dvst); +} + +uint32 dp_disp (uint32 cidx, uint32 op, uint32 dva, uint32 *dvst) +{ +uint32 un = DVA_GETUNIT (dva); +UNIT *dp_unit = dp_dev[cidx].units; +UNIT *uptr = dp_unit + un; +int32 iu; +uint32 i; +DP_CTX *ctx; + +if (cidx >= DP_NUMCTL) /* inv ctrl num? */ + return DVT_NODEV; +ctx = &dp_ctx[cidx]; +if ((un >= DP_NUMDR) || /* inv unit num? */ + ((uptr->flags & UNIT_DIS) && /* disabled unit? */ + ((un != 0xF) || (ctx->dp_ctype != C_3281)))) /* not 3281 unit F? */ + return DVT_NODEV; + +switch (op) { /* case on op */ + + case OP_SIO: /* start I/O */ + *dvst = dp_tio_status (cidx, un); /* get status */ + if ((*dvst & (DVS_CST|DVS_DST)) == 0) { /* ctrl + dev idle? */ + uptr->UCMD = DPS_INIT; /* start dev thread */ + sim_activate (uptr, chan_ctl_time); + } + break; + + case OP_TIO: /* test status */ + *dvst = dp_tio_status (cidx, un); /* return status */ + break; + + case OP_TDV: /* test status */ + *dvst = dp_tdv_status (cidx, un); /* return status */ + break; + + case OP_HIO: /* halt I/O */ + *dvst = dp_tio_status (cidx, un); /* return status */ + if (un != 0xF) { /* not controller */ + if ((int32) un == chan_chk_chi (dva)) /* halt active ctlr int? */ + chan_clr_chi (dva); /* clear ctlr int */ + if (sim_is_active (uptr)) { /* chan active? */ + sim_cancel (uptr); /* stop unit */ + chan_uen (dva); /* uend */ + } + dp_clr_ski (cidx, un); /* clear seek int */ + sim_cancel (uptr + DP_SEEK); /* cancel seek compl */ + } + else { + for (i = 0; i < DP_NUMDR; i++) { /* do every unit */ + if (sim_is_active (&dp_unit[i])) { /* chan active? */ + sim_cancel (&dp_unit[i]); /* cancel */ + chan_uen (dva); /* uend */ + } + dp_clr_ski (cidx, i); /* clear seek int */ + sim_cancel (&dp_unit[i] + DP_SEEK); /* cancel seek compl */ + } + chan_clr_chi (dva); /* clear chan int */ + } + break; + + case OP_AIO: /* acknowledge int */ + iu = dp_clr_int (cidx); /* clear int */ + *dvst = dp_aio_status (cidx, iu) | /* get status */ + (iu << DVT_V_UN); + break; + + default: + *dvst = 0; + return SCPE_IERR; + } + +return 0; +} + +/* Unit service */ + +t_stat dp_svc (UNIT *uptr) +{ +uint32 i, da, wd, wd1, c[DPS_NBY_3281]; +uint32 cidx = uptr->UCTX; +uint32 dva = dp_dib[cidx].dva; +uint32 dtype = GET_DTYPE (uptr->flags); +UNIT *dp_unit = dp_dev[cidx].units; +uint32 un = uptr - dp_unit; +DP_CTX *ctx = &dp_ctx[cidx]; +int32 t, dc; +uint32 st, cmd, sc; +t_stat r; + +if (uptr->UCMD == DPS_INIT) { /* init state? */ + st = chan_get_cmd (dva, &cmd); /* get command */ + if (CHS_IFERR (st)) /* channel error? */ + return dp_chan_err (dva, st); + ctx->dp_flags = 0; /* clear status */ + if (!(dp_cmd[cmd] & (1u << ctx->dp_ctype))) { /* cmd valid for dev? */ + ctx->dp_flags |= DPF_PGE; + chan_uen (dva); /* uend */ + return SCPE_OK; + } + if ((un == 0xF) && /* to controller? */ + !(dp_cmd[cmd] & C_C)) { /* not valid? */ + ctx->dp_flags |= DPF_PGE; + chan_uen (dva); /* uend */ + return SCPE_OK; + } + uptr->UCMD = cmd; /* save state */ + if (dp_cmd[cmd] & C_F) /* fast command? */ + sim_activate_abs (uptr, chan_ctl_time); /* schedule soon */ + else { /* data transfer */ + sc = DPA_GETSC (uptr->UDA); /* new sector */ + t = sc - GET_PSC (ctx->dp_time, dp_tab[dtype].sc); /* delta to new */ + if (t < 0) /* wrap around? */ + t = t + dp_tab[dtype].sc; + sim_activate_abs (uptr, t * ctx->dp_time * DP_WDSC); /* schedule op */ + } + sim_cancel (uptr + DP_SEEK); /* cancel rest of seek */ + return SCPE_OK; + } +else if (uptr->UCMD == DPS_END) { /* end state? */ + st = chan_end (dva); /* set channel end */ + if (CHS_IFERR (st)) /* channel error? */ + return dp_chan_err (dva, st); + if (st == CHS_CCH) { /* command chain? */ + uptr->UCMD = DPS_INIT; /* restart thread */ + sim_activate (uptr, chan_ctl_time); + } + return SCPE_OK; /* done */ + } + +da = 0; +dc = 0; +switch (uptr->UCMD) { + + case DPS_SEEK: /* seek */ + case DPS_SEEKI: + for (i = 0; i < 4; i++) + c[i] = 0; + for (i = 0, st = 0; (i < 4) && (st != CHS_ZBC); i++) { + st = chan_RdMemB (dva, &c[i]); /* get byte */ + if (CHS_IFERR (st)) /* channel error? */ + return dp_chan_err (dva, st); + } + da = (c[0] << 24) | (c[1] << 16) | (c[2] << 8) | c[3]; + if (c[0] & 0xFC) /* hi 6b non-zero? */ + ctx->dp_flags |= DPF_PGE; /* set prog err */ + if (((i != 4) || (st != CHS_ZBC)) && /* length error? */ + chan_set_chf (dva, CHF_LNTE)) { /* care? */ + ctx->dp_flags |= DPF_PGE; /* set prog err */ + return SCPE_OK; + } + if (i < 4) { /* at least 4? */ + chan_uen (dva); + return SCPE_OK; + } + dc = DPA_GETCY (da); /* desired cyl */ + case DPS_RECAL: + case DPS_RECALI: + t = DPA_GETCY (uptr->UDA) - dc; /* get cyl diff */ + ctx->dp_flags = (ctx->dp_flags & ~DPF_DIFF) | + ((t & DPF_M_DIFF) << DPF_V_DIFF); /* save difference */ + if (t == 0) + t = 1; + else t = abs (t); + uptr->UDA = da; /* save addr */ + sim_activate (uptr + DP_SEEK, t * ctx->dp_stime); + dp_unit[un + DP_SEEK].UCMD = /* sched seek */ + (chan_tst_cmf (dva, CMF_CCH)? DSC_SEEK: uptr->UCMD & 0x80); + break; /* sched end */ + + case DPS_SENSE: /* sense */ + for (i = 0; i < DPS_NBY_3281; i++) + c[i] = 0; + c[0] = (uptr->UDA >> 24) & 0xFF; + c[1] = (uptr->UDA >> 16) & 0xFF; + c[2] = (uptr->UDA >> 8) & 0xFF; + c[3] = uptr->UDA & 0xFF; + c[4] = GET_PSC (ctx->dp_time, dp_tab[dtype].sc) | /* curr sector */ + ((sim_is_active (uptr) && ((uptr->UCMD & 0x7F) == DPS_SEEK))? 0x80: 0); + if (ctx->dp_ctype == DP_C3281) { + c[5] = c[7] = un; + c[10] = (ctx->dp_ski >> 8) & 0xFF; + c[11] = ctx->dp_ski & 0xFF; + } + dp_set_sense (uptr, &c[0]); + for (i = 0, st = 0; (i < DPS_NBY) && (st != CHS_ZBC); i++) { + st = chan_WrMemB (dva, c[i]); /* store char */ + if (CHS_IFERR (st)) /* channel error? */ + return dp_chan_err (dva, st); + } + if ((i != DPS_NBY) || (st != CHS_ZBC)) { /* length error? */ + ctx->dp_flags |= DPF_PGE; /* set prog err */ + if (chan_set_chf (dva, CHF_LNTE)) /* do we care? */ + return SCPE_OK; + } + break; + + case DPS_WRITE: /* write */ + if (uptr->flags & UNIT_RO) { /* write locked? */ + ctx->dp_flags |= DPF_WPE; + chan_uen (dva); /* uend */ + return SCPE_OK; + } + if (dp_inv_ad (uptr, &da)) { /* invalid addr? */ + chan_uen (dva); /* uend */ + return SCPE_OK; + } + for (i = 0, st = 0; i < DP_WDSC; i++) { /* sector loop */ + if (st != CHS_ZBC) { /* chan not done? */ + st = chan_RdMemW (dva, &wd); /* read word */ + if (CHS_IFERR (st)) { /* channel error? */ + dp_inc_ad (uptr); /* da increments */ + return dp_chan_err (dva, st); + } + } + else wd = 0; + dp_buf[i] = wd; /* store in buffer */ + } + if (r = dp_write (uptr, da)) /* write buf, err? */ + return r; + if (dp_end_sec (uptr, DP_WDSC, DP_WDSC, st)) /* transfer done? */ + return SCPE_OK; /* err or cont */ + break; + +/* Write header "writes" eight bytes per sector and throws them in the bit bucket */ + + case DPS_WHDR: + if (uptr->flags & UNIT_RO) { /* write locked? */ + ctx->dp_flags |= DPF_WPE; + chan_uen (dva); /* uend */ + return SCPE_OK; + } + if (dp_inv_ad (uptr, &da)) { /* invalid addr? */ + chan_uen (dva); /* uend */ + return SCPE_OK; + } + if (DPA_GETSC (uptr->UDA) != 0) { + ctx->dp_flags |= DPF_SNZ; + chan_uen (dva); + return SCPE_OK; + } + for (i = 0, st = 0; (i < 8) && (st != CHS_ZBC); i++) { /* sector loop */ + if (st != CHS_ZBC) { /* chan not done? */ + st = chan_RdMemB (dva, &wd); /* read word */ + if (CHS_IFERR (st)) { /* channel error? */ + dp_inc_ad (uptr); /* da increments */ + return dp_chan_err (dva, st); + } + } + } + if (dp_end_sec (uptr, i, 8, st)) /* transfer done? */ + return SCPE_OK; /* err or cont */ + +/* Write check must be done by bytes to get precise miscompare */ + + case DPS_CHECK: /* write check */ + if (dp_inv_ad (uptr, &da)) { /* invalid addr? */ + chan_uen (dva); /* uend */ + return SCPE_OK; + } + if (r = dp_read (uptr, da)) /* read buf, error? */ + return r; + for (i = 0, st = 0; (i < (DP_WDSC * 4)) && (st != CHS_ZBC); i++) { + st = chan_RdMemB (dva, &wd); /* read byte */ + if (CHS_IFERR (st)) { /* channel error? */ + dp_inc_ad (uptr); /* da increments */ + return dp_chan_err (dva, st); + } + wd1 = (dp_buf[i >> 2] >> (24 - ((i % 4) * 8))) & 0xFF; /* byte */ + if (wd != wd1) { /* check error? */ + dp_inc_ad (uptr); /* da increments */ + ctx->dp_flags |= DPF_WCHK; /* set status */ + chan_uen (dva); /* force uend */ + return SCPE_OK; + } + } + if (dp_end_sec (uptr, i, DP_WDSC * 4, st)) /* transfer done? */ + return SCPE_OK; /* err or cont */ + break; + + case DPS_READ: /* read */ + if (dp_inv_ad (uptr, &da)) { /* invalid addr? */ + chan_uen (dva); /* uend */ + return SCPE_OK; + } + if (r = dp_read (uptr, da)) /* read buf, error? */ + return r; + for (i = 0, st = 0; (i < DP_WDSC) && (st != CHS_ZBC); i++) { + st = chan_WrMemW (dva, dp_buf[i]); /* store in mem */ + if (CHS_IFERR (st)) { /* channel error? */ + dp_inc_ad (uptr); /* da increments */ + return dp_chan_err (dva, st); + } + } + if (dp_end_sec (uptr, i, DP_WDSC, st)) /* transfer done? */ + return SCPE_OK; /* err or cont */ + break; + +/* Read header reads 8 bytes per sector */ + + case DPS_RHDR: /* read header */ + if (dp_inv_ad (uptr, &da)) { /* invalid addr? */ + chan_uen (dva); /* uend */ + return SCPE_OK; + } + c[0] = c[5] = c[6] = c[7] = 0; + wd = DPA_GETCY (uptr->UDA); + c[1] = (wd >> 8) & 0xFF; + c[2] = wd & 0xFF; + c[3] = DPA_GETHD (uptr->UDA); + c[4] = DPA_GETSC (uptr->UDA); + for (i = 0, st = 0; (i < 8) && (st != CHS_ZBC); i++) { + st = chan_WrMemB (dva, c[i]); /* store in mem */ + if (CHS_IFERR (st)) { /* channel error? */ + dp_inc_ad (uptr); /* da increments */ + return dp_chan_err (dva, st); + } + } + if (dp_end_sec (uptr, i, 8, st)) /* transfer done? */ + return SCPE_OK; /* err or cont */ + break; + +/* Test mode is not really implemented */ + + case DPS_TEST: /* test mode */ + if (!dp_test_mode (cidx)) /* enter test mode */ + return SCPE_OK; + break; + + case DPS_RSRV: /* reserve */ + case DPS_RLS: /* release */ + case DPS_RLSA: /* release */ + break; /* nop */ + } + +uptr->UCMD = DPS_END; /* op done, next state */ +sim_activate (uptr, chan_ctl_time); +return SCPE_OK; +} + +/* Seek completion service */ + +t_stat dps_svc (UNIT *uptr) +{ +uint32 cidx = uptr->UCTX; +DP_CTX *ctx = &dp_ctx[cidx]; +UNIT *dp_unit = dp_dev[cidx].units; +uint32 un = uptr - dp_unit - DP_SEEK; +uint32 dtype = GET_DTYPE (dp_unit[un].flags); + +if (uptr->UCMD != DSC_SEEK) { /* int? */ + if (chan_chk_chi (dp_dib[cidx].dva) >= 0) { /* ctl int pending? */ + sim_activate (uptr, ctx->dp_time * dp_tab[dtype].sc); + uptr->UCMD = DSC_SEEKW; + } + else dp_set_ski (cidx, un); + } +return SCPE_OK; +} + +/* Common read/write sector end routine + + case 1 - more to transfer, not end cylinder - reschedule, return TRUE + case 2 - more to transfer, end cylinder - uend, return TRUE + case 3 - transfer done, length error - uend, return TRUE + case 4 - transfer done, no length error - return FALSE (sched end state) +*/ + +t_bool dp_end_sec (UNIT *uptr, uint32 lnt, uint32 exp, uint32 st) +{ +uint32 cidx = uptr->UCTX; +uint32 dva = dp_dib[cidx].dva; +uint32 dtype = GET_DTYPE (uptr->flags); +DP_CTX *ctx = &dp_ctx[cidx]; + +if (st != CHS_ZBC) { /* end record? */ + if (dp_inc_ad (uptr)) { /* inc addr, cross cyl? */ + ctx->dp_flags |= (DPF_IVA | DPF_EOC); + chan_uen (dva); /* uend */ + } + else sim_activate (uptr, ctx->dp_time * 16); /* no, next sector */ + return TRUE; + } +dp_inc_ad (uptr); /* just incr addr */ +if (lnt != exp) { /* length error at end? */ + if (exp == 8) /* hdr op? */ + ctx->dp_flags |= DPF_PGE; /* set PGE */ + if (chan_set_chf (dva, CHF_LNTE)) /* do we care? */ + return TRUE; + } +return FALSE; /* cmd done */ +} + +/* DP status routine */ + +uint32 dp_tio_status (uint32 cidx, uint32 un) +{ +uint32 i; +DP_CTX *ctx = &dp_ctx[cidx]; +UNIT *dp_unit = dp_dev[cidx].units; + +for (i = 0; i < DP_NUMDR; i++) { + if (sim_is_active (&dp_unit[i])) + return (DVS_AUTO|DVS_CBUSY|DVS_DBUSY|(CC2 << DVT_V_CC)); + } +for (i = 0; i < DP_NUMDR; i++) { + if (sim_is_active (&dp_unit[i + DP_SEEK]) && + (dp_unit[i + DP_SEEK].UCMD != DSC_SEEKW)) + return (DVS_AUTO|DVS_DBUSY|(CC2 << DVT_V_CC)); + } +return DVS_AUTO; +} + +uint32 dp_tdv_status (uint32 cidx, uint32 un) +{ +uint32 st; +DP_CTX *ctx = &dp_ctx[cidx]; +UNIT *dp_unit = dp_dev[cidx].units; +t_bool on_cyl; + +st = 0; +on_cyl = !sim_is_active (&dp_unit[un + DP_SEEK]) || + (dp_unit[un + DP_SEEK].UCMD == DSC_SEEKW); +if (dp_ctx[cidx].dp_ctype == DP_C7270) + st = ((dp_ctx[cidx].dp_flags & DPF_IVA)? 0x20: 0) | + (on_cyl? 0x04: 0); +else st = ((dp_ctx[cidx].dp_flags & DPF_PGE)? 0x20: 0) | + ((dp_ctx[cidx].dp_flags & DPF_WPE)? 0x08: 0); +return st; +} + +uint32 dp_aio_status (uint32 cidx, uint32 un) +{ +uint32 st; +DP_CTX *ctx = &dp_ctx[cidx]; +UNIT *dp_unit = dp_dev[cidx].units; +t_bool on_cyl; + +st = 0; +on_cyl = !sim_is_active (&dp_unit[un + DP_SEEK]) || + (dp_unit[un + DP_SEEK].UCMD == DSC_SEEKW); +if ((dp_ctx[cidx].dp_ctype == DP_C7270) && on_cyl) + st |= 0x04; +if (chan_chk_chi (dp_dib[cidx].dva) < 0) + st |= 0x08; +return st; +} + +/* Set sense status */ + +void dp_set_sense (UNIT *uptr, uint32 *c) +{ +uint32 cidx = uptr->UCTX; +UNIT *sptr = uptr + DP_SEEK; +DP_CTX *ctx = &dp_ctx[cidx]; +uint8 data; +DP_SNSTAB *tptr; + +if (sim_is_active (sptr) && + (sptr->UCMD != DSC_SEEKW)) + ctx->dp_flags |= DPF_AIM; +else ctx->dp_flags &= ~DPF_AIM; +if (ctx->dp_ctype == DP_C7270) + tptr = dp_sense_7270; +else tptr = dp_sense_3281; +while (tptr->byte != 0) { + if (ctx->dp_flags & tptr->mask) { + data = (uint8) ((ctx->dp_flags & tptr->mask) >> tptr->fpos); + c[tptr->byte] |= (data << tptr->tpos); + } + } +return; +} + +/* Validate disk address */ + +t_bool dp_inv_ad (UNIT *uptr, uint32 *da) +{ +uint32 dtype = GET_DTYPE (uptr->flags); +uint32 cy = DPA_GETCY (uptr->UDA); +uint32 hd = DPA_GETHD (uptr->UDA); +uint32 sc = DPA_GETSC (uptr->UDA); + +if ((cy >= dp_tab[dtype].cy) || + (hd >= dp_tab[dtype].hd) || + (sc >= dp_tab[dtype].sc)) + return TRUE; +if (da) /* return word addr */ + *da = ((((cy * dp_tab[dtype].hd) + hd) * dp_tab[dtype].sc) + sc) * DP_WDSC; +return FALSE; +} + +/* Increment disk address */ + +t_bool dp_inc_ad (UNIT *uptr) +{ +uint32 dtype = GET_DTYPE (uptr->flags); +uint32 cy = DPA_GETCY (uptr->UDA); +uint32 hd = DPA_GETHD (uptr->UDA); +uint32 sc = DPA_GETSC (uptr->UDA); + +sc = sc + 1; /* sector++ */ +if (sc >= dp_tab[dtype].sc) { /* overflow? */ + sc = 0; /* wrap sector */ + hd = hd + 1; /* head++ */ + if (hd >= dp_tab[dtype].hd) /* overflow? */ + hd = 0; /* wrap heads */ + } +uptr->UDA = (cy << DPA_V_CY) | (hd << DPA_V_HD) | (sc << DPA_V_SC); +if ((hd == 0) && (sc == 0)) + return TRUE; +return FALSE; +} + +/* Read and write sector */ + +t_stat dp_read (UNIT *uptr, uint32 da) +{ +int32 err, awc; + +err = fseek (uptr->fileref, da * sizeof (int32), SEEK_SET); +if (err == 0) { + awc = fxread (dp_buf, sizeof (uint32), DP_WDSC, uptr->fileref); + err = ferror (uptr->fileref); + for (; awc < DP_WDSC; awc++) /* fill buf */ + dp_buf[awc] = 0; + } +if (err != 0) + return dp_ioerr (uptr); +return SCPE_OK; +} + +t_stat dp_write (UNIT *uptr, uint32 da) +{ +int32 err; + +err = fseek (uptr->fileref, da * sizeof (int32), SEEK_SET); +if (err == 0) { + fxwrite (dp_buf, sizeof (uint32), DP_WDSC, uptr->fileref); + err = ferror (uptr->fileref); + } +if (err != 0) + return dp_ioerr (uptr); +return SCPE_OK; +} + +t_stat dp_ioerr (UNIT *uptr) +{ +uint32 cidx = uptr->UCTX; +uint32 dva = dp_dib[cidx].dva; + +perror ("DP I/O error"); +clearerr (uptr->fileref); +dp_ctx[cidx].dp_flags |= DPF_DPE; /* set DPE flag */ +chan_set_chf (dva, CHF_XMDE); +chan_uen (dva); /* force uend */ +return SCPE_IOERR; +} + +/* Test mode */ + +t_bool dp_test_mode (uint32 cidx) +{ +DP_CTX *ctx = &dp_ctx[cidx]; +uint32 dva = dp_dib[cidx].dva; +uint32 i, st, wd; + +ctx->dp_test = 0; +for (i = 0, st = 0; i < DPT_NBY; i++) { /* sector loop */ + if (st != CHS_ZBC) { /* chan not done? */ + st = chan_RdMemB (dva, &wd); /* read word */ + if (CHS_IFERR (st)) { + dp_chan_err (dva, st); + return FALSE; + } + } + else wd = 0; + ctx->dp_test |= (wd & 0xFF) << (i * 8); + } +return TRUE; +} + +/* Channel error */ + +t_stat dp_chan_err (uint32 dva, uint32 st) +{ +chan_uen (dva); /* uend */ +if (st < CHS_ERR) return st; +return SCPE_OK; +} + +/* Clear controller/device interrupt */ + +int32 dp_clr_int (uint32 cidx) +{ +int32 iu; +DP_CTX *ctx = &dp_ctx[cidx]; + +if ((iu = chan_clr_chi (dp_dib[cidx].dva)) >= 0) { /* chan int? clear */ + if (ctx->dp_ski != 0) /* more int? */ + chan_set_dvi (dp_dib[cidx].dva); /* set INP */ + return iu; + } +for (iu = 0; iu < (int32) DP_NUMDR; iu++) { /* seek int? */ + if (ctx->dp_ski & (1u << iu)) { + dp_clr_ski (cidx, iu); /* clear */ + return iu; + } + } +return 0; +} + +/* Set seek interrupt */ + +void dp_set_ski (uint32 cidx, uint32 un) +{ +dp_ctx[cidx].dp_ski |= (1u << un); +chan_set_dvi (dp_dib[cidx].dva); /* set INP */ +return; +} + +/* Clear seek interrupt */ + +void dp_clr_ski (uint32 cidx, uint32 un) +{ +dp_ctx[cidx].dp_ski &= ~(1u << un); /* clear */ +if (dp_ctx[cidx].dp_ski != 0) /* more int? */ + chan_set_dvi (dp_dib[cidx].dva); /* set INP */ +else if (chan_chk_chi (dp_dib[cidx].dva) < 0) /* any int? */ + chan_clr_chi (dp_dib[cidx].dva); /* clr INP */ +return; +} + +/* Reset routine */ + +t_stat dp_reset (DEVICE *dptr) +{ +uint32 i; +uint32 cidx = dptr - dp_dev; +UNIT *dp_unit; +DP_CTX *ctx; + +if (cidx >= DP_NUMCTL) + return SCPE_IERR; +dp_unit = dptr->units; +ctx = &dp_ctx[cidx]; +for (i = 0; i < DP_NUMDR; i++) { + sim_cancel (&dp_unit[i]); /* stop dev thread */ + dp_unit[i].UDA = 0; + dp_unit[i].UCMD = 0; + dp_unit[i].UCTX = cidx; + } +ctx->dp_flags = 0; +ctx->dp_ski = 0; +ctx->dp_test = 0; +chan_reset_dev (dp_dib[cidx].dva); /* clr int, active */ +return SCPE_OK; +} + +/* Device attach */ + +t_stat dp_attach (UNIT *uptr, char *cptr) +{ +uint32 i, p; +t_stat r; + +uptr->capac = dp_tab[GET_DTYPE (uptr->flags)].capac; +r = attach_unit (uptr, cptr); /* attach unit */ +if (r != SCPE_OK) /* error? */ + return r; +if ((uptr->flags & UNIT_AUTO) == 0) /* autosize? */ + return SCPE_OK; +p = sim_fsize (uptr->fileref); +for (i = 0; dp_tab[i].sc != 0; i++) { + if (p <= (dp_tab[i].capac * (uint32) sizeof (int32))) { + uptr->flags = (uptr->flags & ~UNIT_DTYPE) | (i << UNIT_V_DTYPE); + uptr->capac = dp_tab[i].capac; + return SCPE_OK; + } + } +return SCPE_OK; +} + +/* Set drive type command validation routine */ + +t_stat dp_set_size (UNIT *uptr, int32 val, char *cptr, void *desc) +{ +uint32 dtype = GET_DTYPE (val); +uint32 cidx = uptr->UCTX; + +if (cidx >= DP_NUMCTL) /* valid ctrl idx? */ + return SCPE_IERR; +if (uptr->flags & UNIT_ATT) /* unattached? */ + return SCPE_ALATT; +if (dp_tab[dtype].ctype != dp_ctx[cidx].dp_ctype) /* valid for curr ctrl? */ + return SCPE_NOFNC; +uptr->capac = dp_tab[dtype].capac; +return SCPE_OK; +} + +/* Set controller type command validation routine */ + +t_stat dp_set_ctl (UNIT *uptr, int32 val, char *cptr, void *desc) +{ +uint32 i, cidx = uptr->UCTX; +DP_CTX *ctx = &dp_ctx[cidx]; +UNIT *dp_unit = dp_dev[cidx].units; + +if ((cidx >= DP_NUMCTL) || (val >= DP_NUMCTL)) /* valid ctrl idx? */ + return SCPE_IERR; +if (val == dp_ctx[cidx].dp_ctype) + return SCPE_OK; +for (i = 0; i < DP_NUMDR; i++) { /* all units detached? */ + if (dp_unit[i].flags & UNIT_ATT) + return SCPE_ALATT; + } +for (i = 0; i < DP_NUMDR; i++) { + if (val == DP_C7270) { /* changing to 7270? */ + dp_unit[i].flags = (dp_unit[i].flags & ~UNIT_DTYPE) | + (DP_7271 << UNIT_V_DTYPE); + dp_unit[i].capac = DPSZ_7271; + if (i >= DP_NUMDR_7270) + dp_unit[i].flags = (dp_unit[i].flags | UNIT_DIS) & ~UNIT_DISABLE; + } + else { + dp_unit[i].flags = (dp_unit[i].flags & ~UNIT_DTYPE) | + (DP_7275 << UNIT_V_DTYPE); + dp_unit[i].capac = DPSZ_7275; + if (i >= DP_NUMDR_7270) + dp_unit[i].flags = dp_unit[i].flags | UNIT_DISABLE; + } + } +return SCPE_OK; +} + +t_stat dp_show_ctl (FILE *st, UNIT *uptr, int32 val, void *desc) +{ +uint32 cidx = uptr->UCTX; + +if (cidx >= DP_NUMCTL) /* valid ctrl idx? */ + return SCPE_IERR; +if (dp_ctx[cidx].dp_ctype == DP_C7270) + fprintf (st, "7270 controller"); +else fprintf (st, "3281 controller"); +return SCPE_OK; +} diff --git a/sigma/sigma_fp.c b/sigma/sigma_fp.c new file mode 100644 index 00000000..a82f6516 --- /dev/null +++ b/sigma/sigma_fp.c @@ -0,0 +1,421 @@ +/* sigma_fp.c: XDS Sigma floating point simulator + + Copyright (c) 2007-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. +*/ + +#include "sigma_defs.h" + +#define UFP_V_GUARD 4 +#define UFP_NORM (FP_NORM << UFP_V_GUARD) +#define UFP_CARRY (UFP_NORM << 4) +#define UFP_FRHI (UFP_CARRY|UFP_NORM|FP_M_FRHI) +#define UFP_FRLO 0xFFFFFFFF + +/* Double precision fraction add/subtract/compare */ +/* Note: UFP_ADD (s, r, r) will not work!!! */ + +#define UFP_ADD(s1,s2,d) do { \ + d.l = (s1.l + s2.l) & UFP_FRLO; \ + d.h = (s1.h + s2.h + (d.l < s2.l)) & UFP_FRHI; \ + } while (0) + +#define UFP_SUB(s1,s2,d) do { \ + d.h = (s1.h - s2.h - (s1.l < s2.l)) & UFP_FRHI; \ + d.l = (s1.l - s2.l) & UFP_FRLO; \ + } while (0) + +#define UFP_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 UFP_RSH_V(v,s) do { \ + if ((s) < 32) { \ + v.l = ((v.l >> (s)) | \ + ( v.h << (32 - (s)))) & UFP_FRLO; \ + v.h = v.h >> (s); \ + } \ + else if ((s) < 64) { \ + v.l = v.h >> ((s) - 32); \ + v.h = 0; \ + } \ + else v.l = v.h = 0; \ + } while (0) + +#define UFP_RSH_K(v,s) do { \ + v.l = ((v.l >> (s)) | \ + (v.h << (32 - (s)))) & UFP_FRLO; \ + v.h = v.h >> (s); \ + } while (0) + +#define UFP_LSH_K(v,s) do { \ + v.h = ((v.h << (s)) | \ + (v.l >> (32 - (s)))) & UFP_FRHI; \ + v.l = (v.l << (s)) & UFP_FRLO; \ + } while (0) + +#define UFP_RSH_KP(v,s) do { \ + v->l = ((v->l >> (s)) | \ + (v->h << (32 - (s)))) & UFP_FRLO; \ + v->h = v->h >> (s); \ + } while (0) + +#define UFP_LSH_KP(v,s) do { \ + v->h = ((v->h << (s)) | \ + (v->l >> (32 - (s)))) & UFP_FRHI; \ + v->l = (v->l << (s)) & UFP_FRLO; \ + } while (0) + +typedef struct { + uint32 sign; + int32 exp; + uint32 h; + uint32 l; + } ufp_t; + +extern uint32 *R; +extern uint32 PSW1; +extern uint32 CC; + +void fp_unpack (uint32 hi, uint32 lo, ufp_t *dst); +t_bool fp_clnzro (ufp_t *src, t_bool abnorm); +uint32 fp_pack (ufp_t *src, uint32 rn, t_bool dbl, t_bool rndtrap); +uint32 fp_norm (ufp_t *src); + +uint32 fp (uint32 op, uint32 rn, uint32 bva) +{ +uint32 rh, rl, mh, ml, i, ediff, nsh; +t_bool s1nz, s2nz; +t_bool dbl = ((op & 0x20) == 0); +ufp_t fop1, fop2, t; +ufp_t res = { 0, 0, 0, 0 }; +uint32 tr; + +if (dbl) { /* double prec? */ + rh = R[rn]; /* get reg operands */ + rl = R[rn|1]; + if ((tr = ReadD (bva, &mh, &ml, VR)) != 0) /* get mem word */ + return tr; + } +else { /* single precision */ + rh = R[rn]; /* pad to double */ + rl = 0; + if ((tr = ReadW (bva, &mh, VR)) != 0) + return tr; + ml = 0; + } +fp_unpack (rh, rl, &fop1); /* unpack, test */ +fp_unpack (mh, ml, &fop2); +CC = 0; + +switch (op) { /* case on opcode */ + + case OP_FSS: /* subtract */ + case OP_FSL: + fop2.sign = fop2.sign ^ 1; /* invert mem sign */ + /* fall through */ + case OP_FAS: /* add */ + case OP_FAL: + s1nz = fp_clnzro (&fop1, TRUE); /* test, clean op1 */ + s2nz = fp_clnzro (&fop2, TRUE); + if (!s1nz) /* op1 = 0? res = op2 */ + res = fop2; + else if (!s2nz) /* op2 = 0? res = op1 */ + res = fop1; + else { /* both non-zero */ + if (fop1.exp < fop2.exp) { /* exp1 < exp2? */ + t = fop2; /* swap operands */ + fop2 = fop1; + fop1 = t; + } + ediff = fop1.exp - fop2.exp; /* exp difference */ + res.sign = fop1.sign; /* result sign, exp */ + res.exp = fop1.exp; + if (ediff) { /* any difference? */ + UFP_RSH_V (fop2, ediff * 4); /* shift frac */ + if (dbl) { /* double? */ + if ((PSW1 & PSW1_FR) == 0) /* rounding off? */ + fop2.l &= ~0xF; /* no guard */ + } + else fop2.l = 0; /* single? clr lo */ + } + if (fop1.sign ^ fop2.sign) { /* eff subtract */ + if (UFP_GE (fop1, fop2)) { /* fop1 >= fop2? */ + UFP_SUB (fop1, fop2, res); /* sub fractions */ + } + else { /* fop2 > fop1 */ + UFP_SUB (fop2, fop1, res); /* rev subtract */ + res.sign = fop2.sign; /* change signs */ + } + } /* end subtract */ + else { /* eff add */ + UFP_ADD (fop1, fop2, res); /* add fractions */ + if (res.h & UFP_CARRY) { /* carry out? */ + UFP_RSH_K (res, 4); /* renormalize */ + res.exp = res.exp + 1; /* incr exp */ + } + } /* end add */ + } /* end nz operands */ + if (!dbl) /* single? clr lo */ + res.l = 0; + if ((PSW1 & PSW1_FN) == 0) { /* postnormalize? */ + if ((res.h | res.l) == 0) { /* result zero? */ + CC = CC1; /* set signif flag */ + if (PSW1 & PSW1_FS) /* trap enabled? */ + return TR_FLT; + return fp_pack (&res, rn, dbl, FALSE); /* pack up */ + } + nsh = fp_norm (&res); /* normalize */ + if ((res.exp < 0) && /* underflow? */ + !(PSW1 & PSW1_FZ) && /* !FN */ + (PSW1 & PSW1_FS) && /* FS */ + (nsh > 2)) { /* shifts > 2? */ + CC = CC1 | (res.sign? CC4: CC3); /* signif CC's */ + return TR_FLT; /* trap */ + } /* end if underflow */ + else if (nsh > 2) { /* shifts > 2? */ + CC |= CC1 | (res.sign? CC4: CC3); /* set CC1 */ + if (PSW1 & PSW1_FS) /* trap enabled? */ + return TR_FLT; + } + } /* end if postnorm */ + return fp_pack (&res, rn, dbl, TRUE); /* pack result */ + + case OP_FMS: + case OP_FML: /* floating multiply */ + s1nz = fp_clnzro (&fop1, FALSE); /* test, clean op1 */ + s2nz = fp_clnzro (&fop2, FALSE); + if (s1nz && s2nz) { /* both non-zero? */ + fp_norm (&fop1); /* prenormalize */ + fp_norm (&fop2); + UFP_RSH_K (fop2, 4); /* undo guard */ + res.sign = fop1.sign ^ fop2.sign; /* result sign */ + res.exp = fop1.exp + fop2.exp - FP_BIAS; /* result exp */ + if (!dbl) { /* 24b x 24b? */ + for (i = 0; i < 24; i++) { /* 24 iterations */ + if (fop2.h & 1) + res.h = res.h + fop1.h; /* add hi only */ + UFP_RSH_K (res, 1); /* shift dp res */ + fop2.h = fop2.h >> 1; + } + res.l = 0; /* single prec */ + } + else { /* some low 0's */ + for (i = 0; i < 56; i++) { /* 56 iterations */ + if (fop2.l & 1) { + UFP_ADD (res, fop1, res); + } + UFP_RSH_K (res, 1); + UFP_RSH_K (fop2, 1); + } + } + fp_norm (&res); /* normalize result */ + } + return fp_pack (&res, rn, dbl, TRUE); /* pack result */ + + case OP_FDS: + case OP_FDL: /* floating divide */ + s1nz = fp_clnzro (&fop1, FALSE); /* test, clean op1 */ + s2nz = fp_clnzro (&fop2, FALSE); + if (!s2nz) { /* divide by zero? */ + CC = CC2; /* set CC2 */ + return TR_FLT; /* trap */ + } + if (s1nz) { /* divd non-zero? */ + fp_norm (&fop1); /* prenormalize */ + fp_norm (&fop2); + res.sign = fop1.sign ^ fop2.sign; /* result sign */ + res.exp = fop1.exp - fop2.exp + FP_BIAS; /* result exp */ + if (!UFP_GE (fop1, fop2)) { + UFP_LSH_K (fop1, 4); /* ensure success */ + } + else res.exp = res.exp + 1; /* incr exponent */ + for (i = 0; i < (uint32)(dbl? 15: 7); i++) {/* 7/15 hex digits */ + UFP_LSH_K (res, 4); /* shift quotient */ + while (UFP_GE (fop1, fop2)) { /* while sub works */ + UFP_SUB (fop1, fop2, fop1); /* decrement */ + res.l = res.l + 1; /* add quo bit */ + } + UFP_LSH_K (fop1, 4); /* shift divd */ + } /* end hex loop */ + if (!dbl) { /* single? */ + res.h = res.l; /* move quotient */ + res.l = 0; + } + fp_norm (&res); /* normalize result */ + } + return fp_pack (&res, rn, dbl, TRUE); /* pack result */ + } /* end case */ + +return SCPE_IERR; +} + +void ShiftF (uint32 rn, uint32 stype, uint32 sc) +{ +uint32 opnd, opnd1; +ufp_t src; + +opnd = R[rn]; /* get operands */ +opnd1 = stype? R[rn|1]: 0; /* zextend single */ +fp_unpack (opnd, opnd1, &src); /* unpack */ + +CC = 0; +if (sc & SCSIGN) { /* right? */ + sc = SHF_M_SC + 1 - sc; + while (sc > 0) { /* while count */ + UFP_RSH_K (src, 4); /* shift right hex */ + if (stype) /* zero guard */ + src.l &= ~0xF; + else src.h &= ~0xF; + src.exp++; /* incr exp */ + sc--; + if (src.exp > FP_M_EXP) { /* overflow? */ + CC |= CC2; /* set CC2, stop */ + break; + } + } /* end while */ + if ((src.h | src.l) == 0) { /* result 0? */ + if (stype) /* result is true 0 */ + R[rn|1] = 0; + R[rn] = 0; + CC = 0; + return; + } + } +else { /* left */ + if ((src.h | src.l) == 0) { /* fraction 0? */ + if (stype) /* result is true 0 */ + R[rn|1] = 0; + R[rn] = 0; + CC = CC1; + return; + } + while ((sc > 0) && ((src.h & UFP_NORM) == 0)) { /* while count & !norm */ + UFP_LSH_K (src, 4); /* hex shift left */ + src.exp--; /* decr exp */ + sc--; + if (src.exp < 0) { /* underflow? */ + CC |= CC2; /* set CC2, stop */ + break; + } + } /* end while */ + if (src.h & UFP_NORM) /* normalized? */ + CC |= CC1; /* set CC1 */ + } +fp_pack (&src, rn, stype, FALSE); /* pack result */ +return; +} + +void fp_unpack (uint32 hi, uint32 lo, ufp_t *dst) +{ +dst->sign = FP_GETSIGN (hi); /* get sign */ +if (dst->sign) /* negative? */ + NEG_D (hi, lo); /* 2's compl */ +dst->h = FP_GETFRHI (hi); /* get fraction */ +dst->l = FP_GETFRLO (lo); +dst->exp = FP_GETEXP (hi); /* get exp */ +UFP_LSH_KP (dst, 4); /* guard result */ +return; +} + +/* Test for and clean a floating point zero + abnorm defines whether to allow "abnormal" zeros */ + +t_bool fp_clnzro (ufp_t *src, t_bool abnorm) +{ +if (((src->h | src->l) == 0) && /* frac zero and */ + (!abnorm || (src->exp == 0))) { /* exp zero or !ab */ + src->sign = 0; /* true zero */ + src->exp = 0; + return FALSE; + } +return TRUE; /* non-zero */ +} + +uint32 fp_pack (ufp_t *src, uint32 rn, t_bool dbl, t_bool rndtrap) +{ +static ufp_t fp_zero = { 0, 0, 0, 0}; +uint32 opnd, opnd1; + +if (src->h || (dbl && src->l)) { /* result != 0? */ + CC |= (src->sign? CC4: CC3); /* set CC's */ + if (rndtrap) { /* round, trap? */ + if (PSW1 & PSW1_FR) { /* round? */ + if (dbl) { /* double prec? */ + src->l = (src->l + 0x8) & UFP_FRLO; + src->h = src->h + (src->l < 0x8); + } + else src->h = src->h + 0x8; /* no, single */ + if (src->h & UFP_CARRY) { /* carry out? */ + UFP_RSH_KP (src, 4); /* renormalize */ + src->exp = src->exp + 1; + } + } /* end if round */ + if (src->exp > FP_M_EXP) { /* overflow? */ + CC |= CC2; /* flag */ + return TR_FLT; + } + else if (src->exp < 0) { /* underflow? */ + if (PSW1 & PSW1_FZ) { /* trap enabled? */ + CC |= CC1 | CC2; /* flag */ + return TR_FLT; + } + *src = fp_zero; /* result 0 */ + CC = CC1|CC2; /* special CC's */ + } + } /* end rnd trap */ + UFP_RSH_KP (src, 4); /* remove guard */ + if (!dbl) /* single? lose lower */ + src->l = 0; + if ((src->h | src->l) == 0) /* result now 0? */ + src->exp = src->sign = 0; + } +else *src = fp_zero; +opnd = ((src->exp & FP_M_EXP) << FP_V_EXP) | /* repack */ + ((src->h & FP_M_FRHI) << FP_V_FRHI); +opnd1 = src->l & FP_M_FRLO; +if (src->sign) /* negative? */ + NEG_D (opnd, opnd1); +R[rn] = opnd; /* store result */ +if (dbl && ((rn & 1) == 0)) + R[rn|1] = opnd1; +return 0; +} + +uint32 fp_norm (ufp_t *src) +{ +uint32 nsh; + +nsh = 0; +src->h &= UFP_FRHI; +if (src->h || src->l) { /* if non-zero */ + while ((src->h & UFP_NORM) == 0) { /* until normalized */ + UFP_LSH_KP (src, 4); /* hex shift left */ + src->exp--; /* decr exponent */ + nsh++; /* count shifts */ + } + } +return nsh; +} + diff --git a/sigma/sigma_io.c b/sigma/sigma_io.c new file mode 100644 index 00000000..f1193069 --- /dev/null +++ b/sigma/sigma_io.c @@ -0,0 +1,1497 @@ +/* sigma_io.c: XDS Sigma IO simulator + + Copyright (c) 2007-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. +*/ + +#include "sigma_io_defs.h" + +#define VALID_DVA(c,d) \ + (((c) < chan_num) && ((d) < CHAN_N_DEV) && (chan[c].disp[d] != NULL)) + +uint32 int_hiact = NO_INT; /* hi act int */ +uint32 int_hireq = NO_INT; /* hi int req */ +uint32 chan_ctl_time = 5; +uint32 ei_bmax = EIGRP_DFLT; /* ext int grps */ +uint32 s9_snap = 0; +uint32 s9_marg = 0; +uint32 chan_num = CHAN_DFLT; /* num chan */ +uint32 s5x0_ireg[] = { 0 }; +uint16 int_arm[INTG_MAX]; /* int grps: arm */ +uint16 int_enb[INTG_MAX]; /* enable */ +uint16 int_req[INTG_MAX]; /* request */ +uint8 int_lnk[INTG_MAX] = { /* pri chain */ + INTG_OVR, INTG_CTR, INTG_IO, 0 + }; + +/* Interrupt group priority chain templates */ + +#define I_STD 0x80 + +static uint8 igrp_dflt_5x0[] = { + I_STD|INTG_OVR, I_STD|INTG_CTR, I_STD|INTG_IO, INTG_E2, + INTG_E3, INTG_E3+1, INTG_E3+2, 0 + }; + +static uint8 igrp_dflt_S56789[] = { + I_STD|INTG_OVR, I_STD|INTG_CTR, I_STD|INTG_IO, INTG_E2, + INTG_E3, INTG_E3+1, INTG_E3+2, INTG_E3+3, + INTG_E3+4, INTG_E3+5, INTG_E3+6, INTG_E3+7, + INTG_E3+9, INTG_E3+9, INTG_E3+10, INTG_E3+11, + INTG_E3+12, 0 + }; + +chan_t chan[CHAN_N_CHAN]; +uint32 (*dio_disp[DIO_N_MOD])(uint32, uint32, uint32); + +int_grp_t int_tab[INTG_MAX] = { +/* PSW inh #bits vec grp regbit */ + { 0, 6, 0x052, 0x0, 16 }, + { PSW2_CI, 4, 0x058, 0x0, 22 }, + { PSW2_II, 2, 0x05C, 0x0, 26 }, + { PSW2_EI, 16, 0x060, 0x2, 16 }, + { PSW2_EI, 16, 0x070, 0x3, 16 }, + { PSW2_EI, 16, 0x080, 0x4, 16 }, + { PSW2_EI, 16, 0x090, 0x5, 16 }, + { PSW2_EI, 16, 0x0A0, 0x6, 16 }, + { PSW2_EI, 16, 0x0B0, 0x7, 16 }, + { PSW2_EI, 16, 0x0C0, 0x8, 16 }, + { PSW2_EI, 16, 0x0D0, 0x9, 16 }, + { PSW2_EI, 16, 0x0E0, 0xA, 16 }, + { PSW2_EI, 16, 0x0F0, 0xB, 16 }, + { PSW2_EI, 16, 0x100, 0xC, 16 }, + { PSW2_EI, 16, 0x110, 0xD, 16 }, + { PSW2_EI, 16, 0x120, 0xE, 16 }, + { PSW2_EI, 16, 0x130, 0xF, 16 } + }; + +extern uint32 *R; +extern uint32 PSW1, PSW2; +extern uint32 CC, SSW; +extern uint32 stop_op; +extern uint32 cpu_model; +extern uint32 cons_alarm, cons_pcf; +extern UNIT cpu_unit; +extern cpu_var_t cpu_tab[]; +extern DEVICE *sim_devices[]; +extern FILE *sim_log; + +void io_eval_ioint (void); +t_bool io_init_inst (uint32 ad, uint32 rn, uint32 ch, uint32 dev, uint32 r0); +uint32 io_set_status (uint32 rn, uint32 ch, uint32 dev, uint32 dvst, t_bool tdv); +uint32 io_rwd_m0 (uint32 op, uint32 rn, uint32 ad); +uint32 io_rwd_m1 (uint32 op, uint32 rn, uint32 ad); +t_stat io_set_eiblks (UNIT *uptr, int32 val, char *cptr, void *desc); +t_stat io_show_eiblks (FILE *st, UNIT *uptr, int32 val, void *desc); +t_stat int_reset (DEVICE *dptr); +t_stat chan_reset (DEVICE *dptr); +uint32 chan_new_cmd (uint32 ch, uint32 dev, uint32 clc); +void io_set_eimax (uint32 max); +uint32 chan_proc_prolog (uint32 dva, uint32 *ch, uint32 *dev); +uint32 chan_proc_epilog (uint32 dva, int32 cnt); + +extern uint32 cpu_new_PSD (uint32 lrp, uint32 p1, uint32 p2); + +/* IO data structures + + io_dev IO device descriptor + io_unit IO unit + io_reg IO register list + io_mod IO modifier list +*/ + +dib_t int_dib = { 0, NULL, 1, io_rwd_m1 }; + +UNIT int_unit = { UDATA (NULL, 0, 0) }; + +REG int_reg[] = { + { HRDATA (IHIACT, int_hiact, 9) }, + { HRDATA (IHIREQ, int_hireq, 9) }, + { BRDATA (IREQ, int_req, 16, 16, INTG_MAX) }, + { BRDATA (IENB, int_enb, 16, 16, INTG_MAX) }, + { BRDATA (IARM, int_arm, 16, 16, INTG_MAX) }, + { BRDATA (ILNK, int_lnk, 10, 8, INTG_MAX), REG_HRO }, + { DRDATA (EIBLKS, ei_bmax, 4), REG_HRO }, + { HRDATA (S9_SNAP, s9_snap, 32) }, + { HRDATA (S9_MARG, s9_marg, 32) }, + { BRDATA (S5X0_IREG, s5x0_ireg, 16, 32, 32) }, + { NULL } + }; + +MTAB int_mod[] = { + { MTAB_XTD|MTAB_VDV, 0, "EIBLKS", "EIBLKS", + &io_set_eiblks, &io_show_eiblks }, + { 0 } + }; + +DEVICE int_dev = { + "INT", &int_unit, int_reg, int_mod, + 1, 16, 16, 1, 16, 32, + NULL, NULL, &int_reset, + NULL, NULL, NULL, + &int_dib, 0 + }; + +/* Channel data structures */ + +UNIT chan_unit[] = { + { UDATA (NULL, 0, 0) }, + { UDATA (NULL, 0, 0) }, + { UDATA (NULL, 0, 0) }, + { UDATA (NULL, 0, 0) }, + { UDATA (NULL, 0, 0) }, + { UDATA (NULL, 0, 0) }, + { UDATA (NULL, 0, 0) }, + { UDATA (NULL, 0, 0) } + }; + +REG chana_reg[] = { + { BRDATA (CLC, chan[0].clc, 16, 20, CHAN_N_DEV) }, + { BRDATA (CMD, chan[0].cmd, 16, 8, CHAN_N_DEV) }, + { BRDATA (CMF, chan[0].cmf, 16, 8, CHAN_N_DEV) }, + { BRDATA (BA, chan[0].ba, 16, 24, CHAN_N_DEV) }, + { BRDATA (BC, chan[0].bc, 16, 16, CHAN_N_DEV) }, + { BRDATA (CHF, chan[0].chf, 16, 16, CHAN_N_DEV) }, + { BRDATA (CHI, chan[0].chi, 16, 8, CHAN_N_DEV) }, + { BRDATA (CHSF, chan[0].chsf, 16, 8, CHAN_N_DEV) }, + { NULL } + }; + +REG chanb_reg[] = { + { BRDATA (CLC, chan[1].clc, 16, 20, CHAN_N_DEV) }, + { BRDATA (CMD, chan[1].cmd, 16, 8, CHAN_N_DEV) }, + { BRDATA (CMF, chan[1].cmf, 16, 8, CHAN_N_DEV) }, + { BRDATA (BA, chan[1].ba, 16, 24, CHAN_N_DEV) }, + { BRDATA (BC, chan[1].bc, 16, 16, CHAN_N_DEV) }, + { BRDATA (CHF, chan[1].chf, 16, 16, CHAN_N_DEV) }, + { BRDATA (CHI, chan[1].chi, 16, 8, CHAN_N_DEV) }, + { BRDATA (CHSF, chan[1].chsf, 16, 8, CHAN_N_DEV) }, + { NULL } + }; + +REG chanc_reg[] = { + { BRDATA (CLC, chan[2].clc, 16, 20, CHAN_N_DEV) }, + { BRDATA (CMD, chan[2].cmd, 16, 8, CHAN_N_DEV) }, + { BRDATA (CMF, chan[2].cmf, 16, 8, CHAN_N_DEV) }, + { BRDATA (BA, chan[2].ba, 16, 24, CHAN_N_DEV) }, + { BRDATA (BC, chan[2].bc, 16, 16, CHAN_N_DEV) }, + { BRDATA (CHF, chan[2].chf, 16, 16, CHAN_N_DEV) }, + { BRDATA (CHI, chan[2].chi, 16, 8, CHAN_N_DEV) }, + { BRDATA (CHSF, chan[2].chsf, 16, 8, CHAN_N_DEV) }, + { NULL } + }; + +REG chand_reg[] = { + { BRDATA (CLC, chan[3].clc, 16, 20, CHAN_N_DEV) }, + { BRDATA (CMD, chan[3].cmd, 16, 8, CHAN_N_DEV) }, + { BRDATA (CMF, chan[3].cmf, 16, 8, CHAN_N_DEV) }, + { BRDATA (BA, chan[3].ba, 16, 24, CHAN_N_DEV) }, + { BRDATA (BC, chan[3].bc, 16, 16, CHAN_N_DEV) }, + { BRDATA (CHF, chan[3].chf, 16, 16, CHAN_N_DEV) }, + { BRDATA (CHI, chan[3].chi, 16, 8, CHAN_N_DEV) }, + { BRDATA (CHSF, chan[3].chsf, 16, 8, CHAN_N_DEV) }, + { NULL } + }; + +REG chane_reg[] = { + { BRDATA (CLC, chan[4].clc, 16, 20, CHAN_N_DEV) }, + { BRDATA (CMD, chan[4].cmd, 16, 8, CHAN_N_DEV) }, + { BRDATA (CMF, chan[4].cmf, 16, 8, CHAN_N_DEV) }, + { BRDATA (BA, chan[4].ba, 16, 24, CHAN_N_DEV) }, + { BRDATA (BC, chan[4].bc, 16, 16, CHAN_N_DEV) }, + { BRDATA (CHF, chan[4].chf, 16, 16, CHAN_N_DEV) }, + { BRDATA (CHI, chan[4].chi, 16, 8, CHAN_N_DEV) }, + { BRDATA (CHSF, chan[4].chsf, 16, 8, CHAN_N_DEV) }, + { NULL } + }; + +REG chanf_reg[] = { + { BRDATA (CLC, chan[5].clc, 16, 20, CHAN_N_DEV) }, + { BRDATA (CMD, chan[5].cmd, 16, 8, CHAN_N_DEV) }, + { BRDATA (CMF, chan[5].cmf, 16, 8, CHAN_N_DEV) }, + { BRDATA (BA, chan[5].ba, 16, 24, CHAN_N_DEV) }, + { BRDATA (BC, chan[5].bc, 16, 16, CHAN_N_DEV) }, + { BRDATA (CHF, chan[5].chf, 16, 16, CHAN_N_DEV) }, + { BRDATA (CHI, chan[5].chi, 16, 8, CHAN_N_DEV) }, + { BRDATA (CHSF, chan[5].chsf, 16, 8, CHAN_N_DEV) }, + { NULL } + }; + +REG chang_reg[] = { + { BRDATA (CLC, chan[6].clc, 16, 20, CHAN_N_DEV) }, + { BRDATA (CMD, chan[6].cmd, 16, 8, CHAN_N_DEV) }, + { BRDATA (CMF, chan[6].cmf, 16, 8, CHAN_N_DEV) }, + { BRDATA (BA, chan[6].ba, 16, 24, CHAN_N_DEV) }, + { BRDATA (BC, chan[6].bc, 16, 16, CHAN_N_DEV) }, + { BRDATA (CHF, chan[6].chf, 16, 16, CHAN_N_DEV) }, + { BRDATA (CHI, chan[6].chi, 16, 8, CHAN_N_DEV) }, + { BRDATA (CHSF, chan[6].chsf, 16, 8, CHAN_N_DEV) }, + { NULL } + }; + +REG chanh_reg[] = { + { BRDATA (CLC, chan[7].clc, 16, 20, CHAN_N_DEV) }, + { BRDATA (CMD, chan[7].cmd, 16, 8, CHAN_N_DEV) }, + { BRDATA (CMF, chan[7].cmf, 16, 8, CHAN_N_DEV) }, + { BRDATA (BA, chan[7].ba, 16, 24, CHAN_N_DEV) }, + { BRDATA (BC, chan[7].bc, 16, 16, CHAN_N_DEV) }, + { BRDATA (CHF, chan[7].chf, 16, 16, CHAN_N_DEV) }, + { BRDATA (CHI, chan[7].chi, 16, 8, CHAN_N_DEV) }, + { BRDATA (CHSF, chan[7].chsf, 16, 8, CHAN_N_DEV) }, + { NULL } + }; + +DEVICE chan_dev[] = { + { + "CHANA", &chan_unit[0], chana_reg, NULL, + 1, 16, 16, 1, 16, 32, + NULL, NULL, &chan_reset, + NULL, NULL, NULL, + NULL, CHAN_MIOP, 0 + }, + { + "CHANB", &chan_unit[1], chanb_reg, NULL, + 1, 16, 16, 1, 16, 32, + NULL, NULL, &chan_reset, + NULL, NULL, NULL, + NULL, CHAN_MIOP, 0 + }, + { + "CHANC", &chan_unit[2], chanc_reg, NULL, + 1, 16, 16, 1, 16, 32, + NULL, NULL, &chan_reset, + NULL, NULL, NULL, + NULL, CHAN_SIOP, 0 + }, + { + "CHAND", &chan_unit[3], chand_reg, NULL, + 1, 16, 16, 1, 16, 32, + NULL, NULL, &chan_reset, + NULL, NULL, NULL, + NULL, CHAN_SIOP, 0 + }, + { + "CHANE", &chan_unit[4], chane_reg, NULL, + 1, 16, 16, 1, 16, 32, + NULL, NULL, &chan_reset, + NULL, NULL, NULL, + NULL, CHAN_SIOP|DEV_DIS, 0 + }, + { + "CHANF", &chan_unit[5], chanf_reg, NULL, + 1, 16, 16, 1, 16, 32, + NULL, NULL, &chan_reset, + NULL, NULL, NULL, + NULL, CHAN_SIOP|DEV_DIS, 0 + }, + { + "CHANG", &chan_unit[6], chang_reg, NULL, + 1, 16, 16, 1, 16, 32, + NULL, NULL, &chan_reset, + NULL, NULL, NULL, + NULL, CHAN_SIOP|DEV_DIS, 0 + }, + { + "CHANH", &chan_unit[7], chanh_reg, NULL, + 1, 16, 16, 1, 16, 32, + NULL, NULL, &chan_reset, + NULL, NULL, NULL, + NULL, CHAN_SIOP|DEV_DIS, 0 + } + }; + + +/* Read direct */ + +uint32 io_rwd (uint32 op, uint32 rn, uint32 bva) +{ +uint32 ad = bva >> 2; +uint32 mode = DIO_GETMOD (ad); /* mode */ + +if (dio_disp[mode] != NULL) /* if defined */ + return dio_disp[mode] (op, rn, ad); /* dispatch */ +return (stop_op)? STOP_ILLEG: 0; /* ill inst */ +} + +/* Start IO */ + +uint32 io_sio (uint32 rn, uint32 bva) +{ +uint32 ad = bva >> 2; +uint32 ch, dev, dvst; +uint32 st; + +CC &= ~cpu_tab[cpu_model].iocc; /* clear CC's */ +ch = DVA_GETCHAN (ad); /* get chan, dev */ +dev = DVA_GETDEV (ad); +if (!io_init_inst (rn, ad, ch, dev, R[0])) { /* valid inst? */ + CC |= CC1|CC2; + return 0; + } +if (chan[ch].chf[dev] & CHF_INP) { /* int pending? */ + chan[ch].disp[dev] (OP_TIO, ad, &dvst); /* get status */ + CC |= (CC2 | io_set_status (rn, ch, dev, dvst, 0)); /* set status */ + return 0; + } +st = chan[ch].disp[dev] (OP_SIO, ad, &dvst); /* start I/O */ +CC |= io_set_status (rn, ch, dev, dvst, 0); /* set status */ +if (CC & cpu_tab[cpu_model].iocc) /* error? */ + return 0; +chan[ch].chf[dev] = 0; /* clear flags */ +chan[ch].chi[dev] = 0; /* clear intrs */ +chan[ch].chsf[dev] |= CHSF_ACT; /* set chan active */ +chan_new_cmd (ch, dev, R[0]); /* new command */ +return st; +} + +/* Test IO */ + +uint32 io_tio (uint32 rn, uint32 bva) +{ +uint32 ad = bva >> 2; +uint32 ch, dev, dvst; +uint32 st; + +CC &= ~cpu_tab[cpu_model].iocc; /* clear CC's */ +ch = DVA_GETCHAN (ad); /* get chan, dev */ +dev = DVA_GETDEV (ad); +if (!io_init_inst (rn, ad, ch, dev, 0)) { /* valid inst? */ + CC |= CC1|CC2; + return 0; + } +st = chan[ch].disp[dev] (OP_TIO, ad, &dvst); /* test status */ +CC |= io_set_status (rn, ch, dev, dvst, 0); /* set status */ +return st; +} + +/* Test device status */ + +uint32 io_tdv (uint32 rn, uint32 bva) +{ +uint32 ad = bva >> 2; +uint32 ch, dev, dvst; +uint32 st; + +CC &= ~cpu_tab[cpu_model].iocc; /* clear CC's */ +ch = DVA_GETCHAN (ad); /* get chan, dev */ +dev = DVA_GETDEV (ad); +if (!io_init_inst (rn, ad, ch, dev, 0)) { /* valid inst? */ + CC |= CC1|CC2; + return 0; + } +st = chan[ch].disp[dev] (OP_TDV, ad, &dvst); /* test status */ +CC |= io_set_status (rn, ch, dev, dvst, 1); /* set status */ +return st; +} + +/* Halt IO */ + +uint32 io_hio (uint32 rn, uint32 bva) +{ +uint32 ad = bva >> 2; +uint32 ch, dev, subop, dvst; +uint32 st; + +CC &= ~cpu_tab[cpu_model].iocc; +ad = bva >> 2; +ch = DVA_GETCHAN (ad); /* get chan, dev */ +dev = DVA_GETDEV (ad); +subop = (ad >> 13) & 0x7; +if (subop) { /* extended fnc? */ + if (!QCPU_S89_5X0 || (subop > 3)) /* S9, 5X0 only */ + return (stop_op? STOP_ILLEG: 0); + if (ch >= chan_num) { /* valid channel? */ + CC |= CC1|CC2; + return 0; + } + switch (subop) { + + case 1: /* reset channel */ + chan_reset (&chan_dev[ch]); + break; + + case 2: case 3: /* poll processor */ + if (rn) /* NI */ + R[rn] = 0; + break; + } + } +else { /* normal HIO */ + if (!io_init_inst (rn, ad, ch, dev, 0)) { /* valid inst? */ + CC |= CC1|CC2; + return 0; + } + st = chan[ch].disp[dev] (OP_HIO, ad, &dvst); /* halt IO */ + CC |= io_set_status (rn, ch, dev, dvst, 0); /* set status */ + } +return st; +} + +/* Acknowledge interrupt (ignores device address) */ + +uint32 io_aio (uint32 rn, uint32 bva) +{ +uint32 i, j, dva, dvst; +uint32 st; + +if (DVA_GETCHAN (bva >> 2) != 0) /* non std I/O addr? */ + return (stop_op? STOP_ILLEG: 0); +CC = CC & ~cpu_tab[cpu_model].iocc; /* clear CC's */ +for (i = 0; i < chan_num; i++) { /* loop thru chan */ + for (j = 0; j < CHAN_N_DEV; j++) { /* loop thru dev */ + if (chan[i].chf[j] & CHF_INP) { /* intr pending? */ + if (chan[i].disp[j] == NULL) { /* false interrupt? */ + chan[i].chf[j] &= ~CHF_INP; /* clear intr */ + continue; + } + dva = (i << DVA_V_CHAN) | /* chan number */ + ((chan[i].chsf[j] & CHSF_MU)? /* device number */ + ((j << DVA_V_DEVMU) | DVA_MU): + (j << DVA_V_DEVSU)); + st = chan[i].disp[j] (OP_AIO, dva, &dvst); /* get AIO status */ + dva |= DVT_GETUN (dvst); /* finish dev addr */ + if (rn) /* want status? */ + R[rn] = (DVT_GETDVS (dvst) << 24) | /* device status */ + ((uint32) ((chan[i].chf[j] & (CHF_LNTE|CHF_XMDE)) | + CHI_GETINT (chan[i].chi[j])) << 16) | dva; + if (chan[i].chi[j] & CHI_UEN) /* unusual end? */ + CC |= CC2; /* set CC2 */ + return st; + } + } /* end for dev */ + } /* end for chan */ +CC |= CC1|CC2; /* no recognition */ +return 0; +} + +/* Initiate I/O instruction */ + +t_bool io_init_inst (uint32 rn, uint32 ad, uint32 ch, uint32 dev, uint32 r0) +{ +uint32 loc20; + +if (ch >= chan_num) /* bad chan? */ + return FALSE; +loc20 = ((ad & 0xFF) << 24) | /* <0:7> = dev ad */ + ((rn & 1) | (rn? 3: 0) << 22) | /* <8:9> = reg ind */ + (r0 & (cpu_tab[cpu_model].pamask >> 1)); /* <14/16:31> = r0 */ +WritePW (0x20, loc20); +return (chan[ch].disp[dev] != NULL)? TRUE: FALSE; +} + +/* Set status for I/O instruction */ + +uint32 io_set_status (uint32 rn, uint32 ch, uint32 dev, uint32 dvst, t_bool tdv) +{ +uint32 mrgst; +uint32 odd = rn & 1; + +if ((rn != 0) && !(dvst & DVT_NOST)) { /* return status? */ + if (tdv) + mrgst = (DVT_GETDVS (dvst) << 8) | (chan[ch].chf[dev] & 0xFF); + else mrgst = ((DVT_GETDVS(dvst) << 8) & ~CHF_ALL) | (chan[ch].chf[dev] & CHF_ALL); + R[rn] = chan[ch].clc[dev]; /* even reg */ + if (!odd) /* even pair? */ + WritePW (0x20, R[rn]); /* write to 20 */ + R[rn|1] = (mrgst << 16) | chan[ch].bc[dev]; /* odd reg */ + WritePW (0x20 + odd, R[rn|1]); /* write to 20/21 */ + } +return DVT_GETCC (dvst); +} + +/* Channel support routines */ + +/* Get new command */ + +uint32 chan_get_cmd (uint32 dva, uint32 *cmd) +{ +uint32 ch, dev; +t_stat st; + +if ((st = chan_proc_prolog (dva, &ch, &dev)) != 0) /* valid, active? */ + return st; +*cmd = chan[ch].cmd[dev]; /* return cmd */ +return 0; +} + +/* Channel end */ + +uint32 chan_end (uint32 dva) +{ +uint32 ch, dev; +uint32 st; + +if ((st = chan_proc_prolog (dva, &ch, &dev)) != 0) /* valid, active? */ + return st; +if (chan[ch].cmf[dev] & CMF_ICE) /* int on chan end? */ + chan_set_chi (dva, CHI_END); +if ((chan[ch].cmf[dev] & CMF_CCH) && /* command chain? */ + !chan_new_cmd (ch, dev, chan[ch].clc[dev] + 1)) /* next command? */ + return CHS_CCH; +else chan[ch].chsf[dev] &= ~CHSF_ACT; /* channel inactive */ +return 0; +} + +/* Channel error */ + +uint32 chan_set_chf (uint32 dva, uint32 fl) +{ +uint32 ch, dev; + +ch = DVA_GETCHAN (dva); /* get chan, dev */ +dev = DVA_GETDEV (dva); +if (!VALID_DVA (ch, dev)) /* valid? */ + return SCPE_IERR; +fl &= ~CHF_INP; /* ignore int pend */ +chan[ch].chf[dev] |= fl; +if ((fl & CHF_LNTE) && /* length error */ + ((chan[ch].cmf[dev] & CMF_SIL) || /* suppressed? */ + !(chan[ch].cmf[dev] & CMF_HTE))) /* or don't stop? */ + fl &= ~CHF_LNTE; /* ignore it */ +if ((fl & CHF_XMDE) && /* data error? */ + !(chan[ch].cmf[dev] & CMF_HTE)) /* don't stop? */ + fl &= ~CHF_XMDE; /* ignore it */ +if ((fl & CHF_XMME) && /* memory error? */ + !(chan[ch].cmf[dev] & CMF_HTE)) /* don't stop? */ + fl &= ~CHF_XMME; /* ignore it */ +if (fl) /* fatal error? */ + return chan_uen (dva); /* unusual end */ +return 0; +} + +/* Channel test command flags */ + +t_bool chan_tst_cmf (uint32 dva, uint32 fl) +{ +uint32 ch, dev; + +ch = DVA_GETCHAN (dva); /* get chan, dev */ +dev = DVA_GETDEV (dva); +if (VALID_DVA (ch, dev) && /* valid? */ + (chan[ch].cmf[dev] & fl)) + return TRUE; +return FALSE; +} + +/* Channel unusual end */ + +uint32 chan_uen (uint32 dva) +{ +uint32 ch, dev; + +ch = DVA_GETCHAN (dva); /* get chan, dev */ +dev = DVA_GETDEV (dva); +if (!VALID_DVA (ch, dev)) /* valid? */ + return SCPE_IERR; +if (chan[ch].cmf[dev] & CMF_IUE) /* int on uend? */ + chan_set_chi (dva, CHI_UEN); +chan[ch].chf[dev] |= CHF_UEN; /* flag uend */ +chan[ch].chsf[dev] &= ~CHSF_ACT; +return CHS_INACTV; /* done */ +} + +/* Channel read processes */ + +uint32 chan_RdMemB (uint32 dva, uint32 *dat) +{ +uint32 ch, dev; +uint32 st; + +if ((st = chan_proc_prolog (dva, &ch, &dev)) != 0) /* valid, active? */ + return st; +if (chan[ch].cmf[dev] & CMF_SKP) /* skip? */ + *dat = 0; +else if (ReadPB (chan[ch].ba[dev], dat)) { /* read data, nxm? */ + chan[ch].chf[dev] |= CHF_XMAE; /* addr error */ + return CHS_NXM; /* dev will uend */ + } +return chan_proc_epilog (dva, 1); /* adjust counts */ +} + +uint32 chan_RdMemW (uint32 dva, uint32 *dat) +{ +uint32 ch, dev; +uint32 st; + +if ((st = chan_proc_prolog (dva, &ch, &dev)) != 0) /* valid, active? */ + return st; +if (chan[ch].cmf[dev] & CMF_SKP) /* skip? */ + *dat = 0; +else if ((chan[ch].bc[dev] < 4) || /* unaligned? */ + ((chan[ch].ba[dev] & 0x3) != 0)) { + uint32 i, wd; + for (i = 0, *dat = 0, wd = 0; i < 4; i++) { /* up to 4 bytes */ + st = chan_RdMemB (dva, &wd); /* get byte */ + *dat |= ((wd & 0xFF) << (24 - (i * 8))); /* pack */ + if (st != 0) /* stop if error */ + return st; + } + return 0; + } +else if (ReadPW (chan[ch].ba[dev] >> 2, dat)) { /* read word, nxm? */ + chan[ch].chf[dev] |= CHF_XMAE; /* addr error */ + return CHS_NXM; /* dev will uend */ + } +return chan_proc_epilog (dva, 4); /* adjust counts */ +} + +/* Channel write processes */ + +uint32 chan_WrMemB (uint32 dva, uint32 dat) +{ +uint32 ch, dev; +uint32 st; + +if ((st = chan_proc_prolog (dva, &ch, &dev)) != 0) /* valid, active? */ + return st; +if (((chan[ch].cmf[dev] & CMF_SKP) == 0) && /* skip? */ + WritePB (chan[ch].ba[dev], dat)) { /* write data, nxm? */ + chan[ch].chf[dev] |= CHF_XMAE; /* addr error */ + return CHS_NXM; /* dev will uend */ + } +return chan_proc_epilog (dva, 1); /* adjust counts */ +} + +uint32 chan_WrMemBR (uint32 dva, uint32 dat) +{ +uint32 ch, dev; +uint32 st; + +if ((st = chan_proc_prolog (dva, &ch, &dev)) != 0) /* valid, active? */ + return st; +if (((chan[ch].cmf[dev] & CMF_SKP) == 0) && /* skip? */ + WritePB (chan[ch].ba[dev], dat)) { /* write data, nxm? */ + chan[ch].chf[dev] |= CHF_XMAE; /* addr error */ + return CHS_NXM; /* dev will uend */ + } +return chan_proc_epilog (dva, -1); /* adjust counts */ +} + +uint32 chan_WrMemW (uint32 dva, uint32 dat) +{ +uint32 ch, dev; +uint32 st; + +if ((st = chan_proc_prolog (dva, &ch, &dev)) != 0) /* valid, active? */ + return st; +if ((chan[ch].bc[dev] < 4) || /* unaligned? */ + ((chan[ch].ba[dev] & 0x3) != 0)) { + uint32 i, wd; + for (i = 0; i < 4; i++) { /* up to 4 bytes */ + wd = (dat >> (24 - (i * 8))) & 0xFF; /* get byte */ + if ((st = chan_WrMemB (dva, wd)) != 0) /* write */ + return st; /* stop if error */ + } + return 0; + } +if (((chan[ch].cmf[dev] & CMF_SKP) == 0) && /* skip? */ + WritePW (chan[ch].ba[dev] >> 2, dat)) { /* write word, nxm? */ + chan[ch].chf[dev] |= CHF_XMAE; /* addr error */ + return CHS_NXM; /* dev will uend */ + } +return chan_proc_epilog (dva, 4); /* adjust counts */ +} + +/* Channel process common code */ + +uint32 chan_proc_prolog (uint32 dva, uint32 *ch, uint32 *dev) +{ +*ch = DVA_GETCHAN (dva); /* get chan, dev */ +*dev = DVA_GETDEV (dva); +if (!VALID_DVA (*ch, *dev)) /* valid? */ + return SCPE_IERR; +if ((chan[*ch].chsf[*dev] & CHSF_ACT) == 0) /* active? */ + return CHS_INACTV; +return 0; +} + +uint32 chan_proc_epilog (uint32 dva, int32 cnt) +{ +uint32 ch = DVA_GETCHAN (dva); /* get ch, dev */ +uint32 dev = DVA_GETDEV (dva); + +chan[ch].ba[dev] = (chan[ch].ba[dev] + cnt) & CHBA_MASK; +chan[ch].bc[dev] = (chan[ch].bc[dev] - abs (cnt)) & CHBC_MASK; +if (chan[ch].bc[dev] != 0) /* more to do? */ + return 0; +if (chan[ch].cmf[dev] & CMF_IZC) /* int on zero?*/ + chan_set_chi (dva, CHI_ZBC); +if (chan[ch].cmf[dev] & CMF_DCH) { /* data chaining? */ + if (chan_new_cmd (ch, dev, chan[ch].clc[dev] + 1)) + return CHS_ZBC; + return 0; + } +return CHS_ZBC; +} + +/* New channel command */ + +uint32 chan_new_cmd (uint32 ch, uint32 dev, uint32 clc) +{ +uint32 i, ccw1, ccw2, cmd; + +for (i = 0; i < 2; i++) { /* max twice */ + clc = clc & (cpu_tab[cpu_model].pamask >> 1); /* mask clc */ + chan[ch].clc[dev] = clc; /* and save */ + if (ReadPW (clc << 1, &ccw1)) { /* get ccw1, nxm? */ + chan[ch].chf[dev] |= CHF_IOME; /* memory error */ + chan[ch].chsf[dev] &= ~CHSF_ACT; /* stop channel */ + return CHS_INACTV; + } + ReadPW ((clc << 1) + 1, &ccw2); /* get ccw2 */ + cmd = CCW1_GETCMD (ccw1); /* get chan cmd */ + if ((cmd & 0xF) == CMD_TIC) /* transfer? */ + clc = ccw1; /* try again */ + else { + chan[ch].cmd[dev] = cmd; /* decompose CCW */ + chan[ch].ba[dev] = CCW1_GETBA (ccw1); + chan[ch].cmf[dev] = CCW2_GETCMF (ccw2); + chan[ch].bc[dev] = CCW2_GETBC (ccw2); + return 0; + } + } +chan[ch].chf[dev] |= CHF_IOCE; /* control error */ +chan[ch].chsf[dev] &= ~CHSF_ACT; /* stop channel */ +return CHS_INACTV; +} + +/* Set, clear, test channel interrupt */ + +void chan_set_chi (uint32 dva, uint32 fl) +{ +uint32 ch = DVA_GETCHAN (dva); /* get ch, dev */ +uint32 dev = DVA_GETDEV (dva); +uint32 un = DVA_GETUNIT (dva); /* get unit */ + +chan[ch].chf[dev] |= CHF_INP; /* int pending */ +chan[ch].chi[dev] = (chan[ch].chi[dev] & CHI_FLAGS) | /* update status */ + fl | CHI_CTL | un; /* save unit */ +return; +} + +int32 chan_clr_chi (uint32 dva) +{ +uint32 ch = DVA_GETCHAN (dva); /* get ch, dev */ +uint32 dev = DVA_GETDEV (dva); +uint32 old_chi = chan[ch].chi[dev]; + +chan[ch].chf[dev] &= ~CHF_INP; /* clr int pending */ +chan[ch].chi[dev] &= CHI_FLAGS; /* clr ctl int */ +if (old_chi & CHI_CTL) + return CHI_GETUN (old_chi); +else return -1; +} + +int32 chan_chk_chi (uint32 dva) +{ +uint32 ch = DVA_GETCHAN (dva); /* get ch, dev */ +uint32 dev = DVA_GETDEV (dva); + +if (chan[ch].chi[dev] & CHI_CTL) /* ctl int pending? */ + return CHI_GETUN (chan[ch].chi[dev]); +else return -1; +} + +/* Set device interrupt */ + +void chan_set_dvi (uint32 dva) +{ +uint32 ch = DVA_GETCHAN (dva); /* get ch, dev */ +uint32 dev = DVA_GETDEV (dva); + +chan[ch].chf[dev] |= CHF_INP; /* int pending */ +return; +} + +/* Called by device reset to reset channel registers */ + +t_stat chan_reset_dev (uint32 dva) +{ +uint32 ch, dev; + +ch = DVA_GETCHAN (dva); /* get chan, dev */ +dev = DVA_GETDEV (dva); +if (!VALID_DVA (ch, dev)) /* valid? */ + return SCPE_IERR; +chan[ch].chf[dev] &= ~CHF_INP; /* clear intr */ +chan[ch].chsf[dev] &= ~CHSF_ACT; /* clear active */ +return SCPE_OK; +} + +/* Find highest priority pending interrupt + Question: must an interrupt be armed to be recognized? + Answer: yes; req'arm = 11 signifies waiting state */ + +uint32 io_eval_int (void) +{ +uint32 i, j, t, curr, mask, newi; + +if (int_arm[INTG_IO] & INTGIO_IO) /* I/O armed? */ + io_eval_ioint (); /* eval I/O interrupt */ +for (i = 0, curr = 0; i < INTG_MAX; i++) { /* loop thru groups */ + t = int_req[curr] & int_arm[curr] & int_enb[curr]; /* req, armed, enb */ + if ((t != 0) && /* any waiting req? */ + ((PSW2 & int_tab[curr].psw2_inh) == 0)) { /* group not inh? */ + for (j = 0; j < int_tab[curr].nbits; j++) { /* loop thru reqs */ + mask = 1u << (int_tab[curr].nbits - j - 1); + if (t & mask) { /* request active? */ + newi = INTV (curr, j); /* get int number */ + if (newi < int_hiact) /* higher priority? */ + return newi; /* new highest actv */ + return NO_INT; /* no pending intr */ + } + } + printf ("%%int eval consistency error = %X\r\n", t); + int_req[curr] = 0; /* "impossible" */ + } + if (curr == INT_GETGRP (int_hiact)) /* at active group? */ + return NO_INT; /* no pending intr */ + curr = int_lnk[curr]; /* next group */ + if (curr == 0) /* end of list? */ + return NO_INT; /* no pending intr */ + } +printf ("%%int eval consistency error, list end not found\r\n"); +return NO_INT; +} + +/* See if any interrupt is possible (used by WAIT) */ + +t_bool io_poss_int (void) +{ +uint32 i, curr; + +for (i = 0, curr = 0; i < INTG_MAX; i++) { /* loop thru groups */ + if (((int_arm[curr] & int_enb[curr]) != 0) && + ((PSW2 & int_tab[curr].psw2_inh) == 0)) /* group not inh? */ + return TRUE; /* int can occur */ + curr = int_lnk[curr]; /* next group */ + if (curr == 0) /* end of list? */ + return FALSE; /* no int possible */ + } +printf ("%%int possible consistency error, list end not found\r\n"); +return FALSE; +} + +/* Evaluate I/O interrupts */ + +void io_eval_ioint (void) +{ +uint32 i, j; + +for (i = 0; i < chan_num; i++) { /* loop thru chan */ + for (j = 0; j < CHAN_N_DEV; j++) { /* loop thru dev */ + if (chan[i].chf[j] & CHF_INP) { /* intr pending? */ + int_req[INTG_IO] |= INTGIO_IO; /* set I/O intr */ + return; + } /* end if int pend */ + } /* end for dev */ + } /* end for chan */ +return; +} + +/* Find highest priority active interrupt + Question: is an inhibited or disabled interrupt recognized? + Answer: yes; req'arm = 10 signifies active state */ + +uint32 io_actv_int (void) +{ +uint32 i, j, t, curr, mask; + +for (i = 0, curr = 0; i < INTG_MAX; i++) { /* loop thru groups */ + if ((t = int_req[curr] & ~int_arm[curr]) != 0) { /* req active? */ + for (j = 0; j < int_tab[curr].nbits; j++) { /* loop thru reqs */ + mask = 1u << (int_tab[curr].nbits - j - 1); + if (t & mask) /* req active? */ + return INTV (curr, j); /* return int num */ + } + printf ("%%int actv consistency error = %X\r\n", t); + int_req[curr] = 0; /* "impossible" */ + } + curr = int_lnk[curr]; /* next group */ + if (curr == 0) /* end of list? */ + return NO_INT; /* no pending interupt */ + } +printf ("%%int actv consistency error, list end not found\r\n"); +return NO_INT; +} + +/* Acknowledge interrupt and get vector */ + +uint32 io_ackn_int (uint32 hireq) +{ +uint32 grp, bit, mask; + +if (hireq >= NO_INT) /* none pending? */ + return 0; +grp = INT_GETGRP (hireq); /* get grp, bit */ +bit = INT_GETBIT (hireq); +if (bit >= int_tab[grp].nbits) { /* validate bit */ + printf ("%%int ack consistency error, hireq=%X\r\n", hireq); + return 0; + } +mask = 1u << (int_tab[grp].nbits - bit - 1); +int_arm[grp] &= ~mask; /* clear armed */ +int_hiact = hireq; /* now active */ +int_hireq = io_eval_int (); /* paranoia */ +if (int_hireq != NO_INT) + printf ("%%int ack consistency error, post iack req=%X\r\n", int_hireq); +return int_tab[grp].vecbase + bit; +} + +/* Release interrupt and set new armed/disarmed state */ + +extern uint32 io_rels_int (uint32 hiact, t_bool arm) +{ +uint32 grp, bit, mask; + +if (hiact < NO_INT) { /* intr active? */ + grp = INT_GETGRP (hiact); /* get grp, bit */ + bit = INT_GETBIT (hiact); + if (bit >= int_tab[grp].nbits) { /* validate bit */ + printf ("%%int release consistency error, hiact=%X\r\n", hiact); + return 0; + } + mask = 1u << (int_tab[grp].nbits - bit - 1); + int_req[grp] &= ~mask; /* clear req */ + if (arm) /* rearm? */ + int_arm[grp] |= mask; + else int_arm[grp] &= ~mask; + } +int_hiact = io_actv_int (); /* new highest actv */ +return io_eval_int (); /* new request */ +} + +/* Set panel interrupt */ + +t_stat io_set_pint (void) +{ +int_req[INTG_IO] |= INTGIO_PANEL; +return SCPE_OK; +} + +/* Set or clear interrupt status flags */ + +void io_sclr_req (uint32 inum, uint32 val) +{ +uint32 grp, bit, mask; + +if (inum < NO_INT) { /* valid? */ + grp = INT_GETGRP (inum); /* get grp, bit */ + bit = INT_GETBIT (inum); + if (bit >= int_tab[grp].nbits) { /* validate bit */ + printf ("%%intreq set/clear consistency error, inum=%X\r\n", inum); + return; + } + mask = 1u << (int_tab[grp].nbits - bit - 1); + if (val) { /* set req? */ + if (int_arm[grp] & mask) /* must be armed */ + int_req[grp] |= mask; + } + else int_req[grp] &= ~mask; /* clr req */ + } +return; +} + +void io_sclr_arm (uint32 inum, uint32 val) +{ +uint32 grp, bit, mask; + +if (inum < NO_INT) { /* valid? */ + grp = INT_GETGRP (inum); /* get grp, bit */ + bit = INT_GETBIT (inum); + if (bit >= int_tab[grp].nbits) { /* validate bit */ + printf ("%%intarm set/clear consistency error, inum=%X\r\n", inum); + return; + } + mask = 1u << (int_tab[grp].nbits - bit - 1); + if (val) /* set or clr arm */ + int_arm[grp] |= mask; + else int_arm[grp] &= ~mask; + } +return; +} + +/* Read/write direct mode 0 - processor miscellaneous */ + +uint32 io_rwd_m0 (uint32 op, uint32 rn, uint32 ad) +{ +uint32 wd; +uint32 fnc = DIO_GET0FNC (ad); +uint32 dat = rn? R[rn]: 0; + +if (op == OP_RD) { /* read direct? */ + if (fnc == 0x000) { /* copy SSW to SC */ + CC = SSW; + } + else if (fnc == 0x010) { /* read mem fault */ + if (rn) + R[rn] = 0; + CC = SSW; + } + else if (QCPU_S89_5X0 && (fnc == 0x040)) { /* S89, 5X0 only */ + if (rn) /* read inhibits */ + R[rn] = PSW2_GETINH (PSW2); + } + else if (QCPU_S89 && (fnc == 0x045)) { /* S89 only */ + if (rn) + R[rn] = s9_marg & 0x00C00000 | /* <8,9> = margins */ + (QCPU_S9? 0x00100000: 0x00200000); /* S8 sets 10, S9 11 */ + } + else if (QCPU_S89 && (fnc == 0x049)) { /* S89 only */ + if (rn) /* read snapshot */ + R[rn] = s9_snap; + } + else if (QCPU_5X0 && ((fnc & 0xFC0) == 0x100)) { /* 5X0 only */ + ReadPW (fnc & 0x1F, &wd); /* read low mem */ + if (rn) + R[rn] = wd; + } + else if (QCPU_5X0 && ((fnc & 0xFC0) == 0x300)) { /* 5X0 only */ + if (rn) /* read int reg */ + R[rn] = s5x0_ireg[fnc & 0x1F]; + } + else return (stop_op)? STOP_ILLEG: 0; + } +else { /* write direct */ + if (QCPU_5X0 && (fnc == 0x000)) /* 5X0 only */ + SSW = dat & 0xF; /* write SSW */ + else if (QCPU_5X0 && (fnc == 0x002)) /* 5X0 only */ + return TR_47; /* trap to 47 */ + else if ((fnc & 0xFF0) == 0x020) /* bit clear inh */ + PSW2 &= ~((ad & PSW2_M_INH) << PSW2_V_INH); + else if ((fnc & 0xFF0) == 0x030) /* bit set inh */ + PSW2 |= ((ad & PSW2_M_INH) << PSW2_V_INH); + else if (fnc == 0x040) /* alarm off */ + cons_alarm = 0; + else if (fnc == 0x041) /* alarm on */ + cons_alarm = 1; + else if (fnc == 0x042) { /* toggle freq */ + cons_alarm = 0; + cons_pcf ^= 1; + } + else if (fnc == 0x044) ; /* S5 reset IIOP */ + else if (QCPU_S89 && (fnc == 0x045)) /* S89 only */ + s9_marg = dat; /* write margins */ + else if (QCPU_S89_5X0 && (fnc == 0x046)) /* S89, 5X0 only */ + PSW2 &= ~(PSW2_MA9|PSW2_MA5X0); /* clr mode altered */ + else if (QCPU_S9 && (fnc == 0x047)) /* S9 set mode alt */ + PSW2 |= PSW2_MA9; + else if (QCPU_5X0 && (fnc == 0x047)) /* 5X0 set mode alt */ + PSW2 |= PSW2_MA5X0; + else if (QCPU_S89 && (fnc == 0x049)) /* S9 only */ + s9_snap = dat; /* write snapshot */ + else if (QCPU_5X0 && ((fnc & 0xFC0) == 0x100)) /* 5X0 only */ + WritePW (fnc & 0x1F, dat); /* write low mem */ + else if (QCPU_5X0 && ((fnc & 0xFC0) == 0x300)) /* 5X0 only */ + s5x0_ireg[fnc & 0x1F] = dat; /* write int reg */ + else return (stop_op)? STOP_ILLEG: 0; + } +return 0; +} + +/* Read/write direct mode 1 - interrupt flags + This is the only routine that has to map between architecturally + defined interrupts groups and the internal representation. */ + +uint32 io_rwd_m1 (uint32 op, uint32 rn, uint32 ad) +{ +uint32 i, beg, end, mask, sc; +uint32 grp = DIO_GET1GRP (ad); +uint32 fnc = DIO_GET1FNC (ad); + +if (grp == 0) { /* overrides? */ + beg = INTG_OVR; + end = INTG_IO; + } +else if (grp == 1) /* group 1? */ + return 0; /* not there */ +else beg = end = grp + 1; + +if (op == OP_RD) { /* read direct? */ + if (!QCPU_S89_5X0) /* S89, 5X0 only */ + return (stop_op? STOP_ILLEG: 0); + if (rn == 0) /* want result? */ + return 0; + R[rn] = 0; /* clear reg */ + } +for (i = beg; i <= end; i++) { /* loop thru grps */ + mask = (1u << int_tab[i].nbits) - 1; + sc = 32 - int_tab[i].regbit - int_tab[i].nbits; + if (op == OP_RD) { /* read direct? */ + if (fnc & 0x1) + R[rn] |= ((mask & int_arm[i]) << sc); + if (fnc & 0x2) + R[rn] |= ((mask & int_req[i]) << sc); + if (fnc & 0x4) + R[rn] |= ((mask & int_enb[i]) << sc); + } + else { /* write direct */ + mask = (R[rn] >> sc) & mask; + switch (fnc) { + + case 0x0: /* armed||wait->act */ + if (QCPU_S89_5X0) { + int_req[i] |= (mask & int_arm[i]); + int_arm[i] &= mask; + } + else return (stop_op? STOP_ILLEG: 0); + break; + + case 0x1: /* disarm, clr req */ + int_arm[i] &= ~mask; + int_req[i] &= ~mask; + break; + + case 0x2: /* arm, enb, clr req */ + int_arm[i] |= mask; + int_enb[i] |= mask; + int_req[i] &= ~mask; + break; + + case 0x3: /* arm, dsb, clr req */ + int_arm[i] |= mask; + int_enb[i] &= ~mask; + int_req[i] &= ~mask; + break; + + case 0x4: /* enable */ + int_enb[i] |= mask; + break; + + case 0x5: /* disable */ + int_enb[i] &= ~mask; + break; + + case 0x6: /* direct set enb */ + int_enb[i] = mask; + break; + + case 0x7: /* armed->waiting */ + int_req[i] |= (mask & int_arm[i]); + } + } + } +return 0; +} + +/* Reset routines */ + +t_stat int_reset (DEVICE *dptr) +{ +uint32 i; + +if (int_lnk[0] == 0) /* int chain not set up? */ + io_set_eimax (ei_bmax); +for (i = 0; i < INTG_MAX; i++) { + int_arm[i] = 0; + int_enb[i] = 0; + int_req[i] = 0; + } +int_hiact = NO_INT; +int_hireq = NO_INT; +return SCPE_OK; +} + +t_stat chan_reset (DEVICE *dptr) +{ +uint32 ch = dptr - &chan_dev[0]; +uint32 i, j; +DEVICE *devp; + +if (ch >= CHAN_N_CHAN) + return SCPE_IERR; +for (i = 0; i < CHAN_N_DEV; i++) { + chan[ch].clc[i] = 0; + chan[ch].cmd[i] = 0; + chan[ch].cmf[i] = 0; + chan[ch].ba[i] = 0; + chan[ch].bc[i] = 0; + chan[ch].chf[i] = 0; + chan[ch].chi[i] = 0; + chan[ch].chsf[i] &= ~CHSF_ACT; + for (j = 0; (devp = sim_devices[j]) != NULL; j++) { /* loop thru dev */ + if (devp->ctxt != NULL) { + dib_t *dibp = (dib_t *) devp->ctxt; + if ((DVA_GETCHAN (dibp->dva) == ch) && (devp->reset)) + devp->reset (devp); + } + } + } +return SCPE_OK; +} + +/* Universal boot routine */ + +static uint32 boot_rom[] = { + 0x00000000, 0x00000000, 0x020000A8, 0x0E000058, + 0x00000011, 0x00000000, 0x32000024, 0xCC000025, + 0xCD000025, 0x69C00028, 0x00000000, 0x00000000 + }; + +t_stat io_boot (int32 u, DEVICE *dptr) +{ +uint32 i; +dib_t *dibp = (dib_t *) dptr->ctxt; + +for (i = 0; i < MEMSIZE; i++) /* boot clrs mem */ + WritePW (i, 0); +if ((dibp == NULL) || + ((u != 0) && + ((dibp->dva & DVA_MU) == 0))) + return SCPE_ARG; +for (i = 0; i < BOOT_LNT; i++) + WritePW (BOOT_SA + i, boot_rom[i]); +WritePW (BOOT_DEV, dibp->dva | u); +cpu_new_PSD (1, BOOT_PC, 0); +return SCPE_OK; +} + +/* I/O table initialization routine */ + +t_stat io_init (void) +{ +uint32 i, j, ch, dev, dio; +DEVICE *dptr; +dib_t *dibp; + +for (i = 0; i < CHAN_N_CHAN; i++) { + for (j = 0; j < CHAN_N_DEV; j++) { + chan[i].chsf[j] &= ~CHSF_MU; + chan[i].disp[j] = NULL; + } + } +dio_disp[0] = &io_rwd_m0; +for (i = 1; i < DIO_N_MOD; i++) + dio_disp[i] = NULL; + +for (i = 0; (dptr = sim_devices[i]) != NULL; i++) { + if ((dibp = (dib_t *) dptr->ctxt) != NULL) { + ch = DVA_GETCHAN (dibp->dva); + dev = DVA_GETDEV (dibp->dva); + dio = dibp->dio; + if ((ch >= chan_num) || + (dev >= CHAN_N_DEV) || + (dio >= DIO_N_MOD)) { + printf ("%s: invalid device address, chan = %d, dev = %X, dio = %X\n", + sim_dname (dptr), ch, DVA_GETDEV (dibp->dva), dio); + if (sim_log) + fprintf (sim_log, "%s: invalid device address, chan = %d, dev = %X, dio = %X\n", + sim_dname (dptr), ch, DVA_GETDEV (dibp->dva), dio); + return SCPE_STOP; + } + if ((dibp->disp != NULL) && (chan[ch].disp[dev] != NULL)) { + printf ("%s: device address conflict, chan = %d, dev = %X\n", + sim_dname (dptr), ch, DVA_GETDEV (dibp->dva)); + if (sim_log) + fprintf (sim_log, "%s: device address conflict, chan = %d, dev = %X\n", + sim_dname (dptr), ch, DVA_GETDEV (dibp->dva)); + return SCPE_STOP; + } + if ((dibp->dio_disp != NULL) && (dio_disp[dio] != NULL)) { + printf ("%s: direct I/O address conflict, dio = %X\n", + sim_dname (dptr), dio); + if (sim_log) + fprintf (sim_log, "%s: direct I/O address conflict, dio = %X\n", + sim_dname (dptr), dio); + return SCPE_STOP; + } + if (dibp->disp) + chan[ch].disp[dev] = dibp->disp; + if (dibp->dio_disp) + dio_disp[dio] = dibp->dio_disp; + if (dibp->dva & DVA_MU) + chan[ch].chsf[dev] |= CHSF_MU; + } + } +return SCPE_OK; +} + +/* Set/show external interrupt blocks */ + +t_stat io_set_eiblks (UNIT *uptr, int32 val, char *cptr, void *desc) +{ +int32 lnt; +t_stat r; + +if (cptr == NULL) + return SCPE_ARG; +lnt = (int32) get_uint (cptr, 10, cpu_tab[cpu_model].eigrp_max, &r); +if ((r != SCPE_OK) || (lnt == 0)) + return SCPE_ARG; +int_reset (&int_dev); +io_set_eimax (lnt); +return SCPE_OK; +} + +t_stat io_show_eiblks (FILE *st, UNIT *uptr, int32 val, void *desc) +{ +fprintf (st, "eiblks=%d", ei_bmax); +return SCPE_OK; +} + +/* Change the number of external I/O blocks, and restore the default + chain configuration */ + +void io_set_eimax (uint32 max) +{ +uint32 i, curr, ngrp; +uint8 *dflt_p; + +ei_bmax = max; +if (QCPU_5X0) + dflt_p = igrp_dflt_5x0; +else dflt_p = igrp_dflt_S56789; +curr = dflt_p[0] & ~I_STD; +for (i = 1, ngrp = 0; dflt_p[i] != 0; i++) { + if (dflt_p[i] & I_STD) { + int_lnk[curr] = dflt_p[i] & ~I_STD; + curr = int_lnk[curr]; + } + else if (ngrp < ei_bmax) { + int_lnk[curr] = dflt_p[i]; + curr = int_lnk[curr]; + ngrp++; + } + else int_lnk[curr] = 0; + } +return; +} + +/* Set or show number of channels */ + +t_stat io_set_nchan (UNIT *uptr, int32 val, char *cptr, void *desc) +{ +int32 i, num; +t_stat r; + +if (cptr == NULL) + return SCPE_ARG; +num = (int32) get_uint (cptr, 10, cpu_tab[cpu_model].chan_max, &r); +if ((r != SCPE_OK) || (num == 0)) + return SCPE_ARG; +chan_num = num; +for (i = 0; i < CHAN_N_CHAN; i++) { + if (i < num) + chan_dev[i].flags &= ~DEV_DIS; + else chan_dev[i].flags |= DEV_DIS; + chan_reset (&chan_dev[i]); + } +return SCPE_OK; +} + +t_stat io_show_nchan (FILE *st, UNIT *uptr, int32 val, void *desc) +{ +fprintf (st, "channels=%d", chan_num); +return SCPE_OK; +} + +/* Set or show device channel assignment */ + +t_stat io_set_dvc (UNIT* uptr, int32 val, char *cptr, void *desc) +{ +int32 num; +DEVICE *dptr; +dib_t *dibp; + +if (((dptr = find_dev_from_unit (uptr)) == NULL) || + ((dibp = (dib_t *) dptr->ctxt) == NULL)) + return SCPE_IERR; +if ((cptr == NULL) || (*cptr == 0) || (*(cptr + 1) != 0)) + return SCPE_ARG; +num = *cptr - 'A'; +if ((num < 0) || (num >= (int32) chan_num)) + return SCPE_ARG; +dibp->dva = (dibp->dva & ~DVA_CHAN) | (num << DVA_V_CHAN); +return SCPE_OK; +} + +t_stat io_show_dvc (FILE *st, UNIT *uptr, int32 val, void *desc) +{ +DEVICE *dptr; +dib_t *dibp; + +if (((dptr = find_dev_from_unit (uptr)) == NULL) || + ((dibp = (dib_t *) dptr->ctxt) == NULL)) + return SCPE_IERR; +fprintf (st, "channel=%c", DVA_GETCHAN (dibp->dva) + 'A'); +return SCPE_OK; +} + +/* Set or show device address */ + +t_stat io_set_dva (UNIT* uptr, int32 val, char *cptr, void *desc) +{ +int32 num; +DEVICE *dptr; +dib_t *dibp; +t_stat r; + +if (((dptr = find_dev_from_unit (uptr)) == NULL) || + ((dibp = (dib_t *) dptr->ctxt) == NULL)) + return SCPE_IERR; +if (cptr == NULL) + return SCPE_ARG; +num = (int32) get_uint (cptr, 16, CHAN_N_DEV, &r); +if (r != SCPE_OK) + return SCPE_ARG; +if (dibp->dva & DVA_MU) + dibp->dva = (dibp->dva & ~DVA_DEVMU) | ((num & DVA_M_DEVMU) << DVA_V_DEVMU); +else dibp->dva = (dibp->dva & ~DVA_DEVSU) | ((num & DVA_M_DEVSU) << DVA_V_DEVSU); +return SCPE_OK; +} + +t_stat io_show_dva (FILE *st, UNIT *uptr, int32 val, void *desc) +{ +DEVICE *dptr; +dib_t *dibp; + +if (((dptr = find_dev_from_unit (uptr)) == NULL) || + ((dibp = (dib_t *) dptr->ctxt) == NULL)) + return SCPE_IERR; +fprintf (st, "address=%02X", DVA_GETDEV (dibp->dva)); +return SCPE_OK; +} + +/* Show channel state */ + +t_stat io_show_cst (FILE *st, UNIT *uptr, int32 val, void *desc) +{ +DEVICE *dptr; +dib_t *dibp; +uint32 ch, dva; + +if (((dptr = find_dev_from_unit (uptr)) == NULL) || + ((dibp = (dib_t *) dptr->ctxt) == NULL)) + return SCPE_IERR; +ch = DVA_GETCHAN (dibp->dva); +dva = DVA_GETDEV (dibp->dva); +fprintf (st, "Status for device %s, channel=%02X, address=%02X:\n", + sim_dname(dptr), ch, dva); +fprintf (st, "CLC:\t%06X\nBA:\t%06X\nBC:\t%04X\nCMD:\t%02X\n", + chan[ch].clc[dva], chan[ch].ba[dva], + chan[ch].bc[dva], chan[ch].cmd[dva]); +fprintf (st, "CMF:\t%02X\nCHF\t%04X\nCHI:\t%02X\nCHSF:\t%02X\n", + chan[ch].cmf[dva], chan[ch].chf[dva], + chan[ch].chi[dva], chan[ch].chsf[dva]); +return SCPE_OK; +} diff --git a/sigma/sigma_io_defs.h b/sigma/sigma_io_defs.h new file mode 100644 index 00000000..a44c4f91 --- /dev/null +++ b/sigma/sigma_io_defs.h @@ -0,0 +1,276 @@ +/* sigma_io_defs.h: XDS Sigma I/O device simulator definitions + + Copyright (c) 2007-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. +*/ + +#ifndef _SIGMA_IO_DEFS_H_ +#define _SIGMA_IO_DEFS_H_ 0 + +#include "sim_defs.h" /* simulator defns */ +#include "sigma_defs.h" + +/* Channel constants */ + +#define CHAN_N_CHAN 8 /* max # channels */ +#define CHAN_DFLT 4 /* default # chan */ +#define CHAN_N_DEV 32 /* max dev per chan */ +#define CHAN_V_IOPT (DEV_V_UF + 0) /* channel type */ +#define CHAN_MIOP (0 << CHAN_V_IOPT) +#define CHAN_SIOP (1 << CHAN_V_IOPT) + +/* I/O device definition block */ + +typedef struct { + uint32 dva; /* dev addr (chan+dev) */ + uint32 (*disp)(uint32 op, uint32 dva, uint32 *dvst); + uint32 dio; /* dev addr (direct IO) */ + uint32 (*dio_disp)(uint32 op, uint32 rn, uint32 dva); + } dib_t; + +/* Channel data structure */ + +typedef struct { + uint32 clc[CHAN_N_DEV]; /* location counter */ + uint32 ba[CHAN_N_DEV]; /* mem addr */ + uint16 bc[CHAN_N_DEV]; /* byte count */ + uint8 cmd[CHAN_N_DEV]; /* command */ + uint8 cmf[CHAN_N_DEV]; /* command flags */ + uint16 chf[CHAN_N_DEV]; /* channel flags */ + uint8 chi[CHAN_N_DEV]; /* interrupts */ + uint8 chsf[CHAN_N_DEV]; /* simulator flags */ + uint32 (*disp[CHAN_N_DEV])(uint32 op, uint32 dva, uint32 *dvst); + } chan_t; + +/* Channel command words */ + +#define CCW1_V_CMD 24 /* command */ +#define CCW1_M_CMD 0xFF +#define CCW1_V_BA 0 +#define CCW1_M_BA ((cpu_tab[cpu_model].pamask << 2) | 0x3) +#define CHBA_MASK (CCW1_M_BA << CCW1_V_BA) +#define CCW2_V_CMF 24 /* cmd flags */ +#define CCW2_M_CMF 0xFF +#define CCW2_V_BC 0 +#define CCW2_M_BC 0xFFFF +#define CHBC_MASK (CCW2_M_BC << CCW2_V_BC) +#define CCW1_GETCMD(x) (((x) >> CCW1_V_CMD) & CCW1_M_CMD) +#define CCW1_GETBA(x) (((x) >> CCW1_V_BA) & CCW1_M_BA) +#define CCW2_GETCMF(x) (((x) >> CCW2_V_CMF) & CCW2_M_CMF) +#define CCW2_GETBC(x) (((x) >> CCW2_V_BC) & CCW2_M_BC) + +/* Channel commands */ + +#define CMD_TIC 0x8 /* transfer */ + +/* Channel command flags */ + +#define CMF_DCH 0x80 /* data chain */ +#define CMF_IZC 0x40 /* int on zero cnt */ +#define CMF_CCH 0x20 /* command chain */ +#define CMF_ICE 0x10 /* int on chan end */ +#define CMF_HTE 0x08 /* hlt on xmit err */ +#define CMF_IUE 0x04 /* int on uend */ +#define CMF_SIL 0x02 /* suppress lnt err */ +#define CMF_SKP 0x01 /* skip */ + +/* Channel flags */ + +#define CHF_INP 0x8000 /* int pending */ +#define CHF_UEN 0x0400 /* unusual end */ +#define CHF_LNTE 0x0080 /* length error */ +#define CHF_XMDE 0x0040 /* xmit data error */ +#define CHF_XMME 0x0020 /* xmit mem error */ +#define CHF_XMAE 0x0010 /* xmit addr error */ +#define CHF_IOME 0x0008 /* IOP mem error */ +#define CHF_IOCE 0x0004 /* IOP ctrl error */ +#define CHF_IOHE 0x0002 /* IOP halted */ +#define CHF_ALL (CHF_INP|CHF_UEN|0xFF) + +/* Channel interrupts */ + +#define CHI_F_SHF 1 /* flag shift */ +#define CHI_CTL (0x40 << CHI_F_SHF) /* ctl int (fake) */ +#define CHI_ZBC (0x20 << CHI_F_SHF) /* zero by cnt int */ +#define CHI_END (0x10 << CHI_F_SHF) /* channel end int */ +#define CHI_UEN (0x08 << CHI_F_SHF) /* unusual end int */ +#define CHI_FLAGS (CHI_ZBC|CHI_END|CHI_UEN) +#define CHI_V_UN 0 +#define CHI_M_UN 0xF +#define CHI_GETUN(x) (((x) >> CHI_V_UN) & CHI_M_UN) +#define CHI_GETINT(x) (((x) & CHI_FLAGS) >> CHI_F_SHF) + +/* Internal simulator flags */ + +#define CHSF_ACT 0x0001 /* channel active */ +#define CHSF_MU 0x0002 /* multi-unit dev */ + +/* Dispatch routine status return value */ + +#define DVT_V_UN 24 /* unit addr (AIO only) */ +#define DVT_M_UN 0xF +#define DVT_V_CC 16 /* cond codes */ +#define DVT_M_CC 0xF +#define DVT_V_DVS 0 /* device status */ +#define DVT_M_DVS 0xFF +#define DVS_V_DST 5 /* device status */ +#define DVS_M_DST 0x3 +#define DVS_DST (DVS_M_DST << DVS_V_DST) +#define DVS_DOFFL (0x1 << DVS_V_DST) +#define DVS_DBUSY (0x3 << DVS_V_DST) +#define DVS_AUTO 0x10 /* manual/automatic */ +#define DVS_V_CST 1 /* ctrl status */ +#define DVS_M_CST 0x3 +#define DVS_CBUSY (0x3 << DVS_V_CST) +#define DVS_CST (DVS_M_CST << DVS_V_CST) +#define DVT_GETUN(x) (((x) >> DVT_V_UN) & DVT_M_UN) +#define DVT_GETCC(x) (((x) >> DVT_V_CC) & DVT_M_CC) +#define DVT_GETDVS(x) (((x) >> DVT_V_DVS) & DVT_M_DVS) +#define DVT_NOST (CC1 << DVT_V_CC) /* no status */ +#define DVT_NODEV ((CC1|CC2) < DVT_V_CC) /* no device */ + +/* Read and write direct address format */ + +#define DIO_V_MOD 12 /* mode */ +#define DIO_M_MOD 0xF +#define DIO_V_0FNC 0 /* mode 0 func */ +#define DIO_M_0FNC 0xFFF +#define DIO_V_1FNC 8 /* mode 1 int func */ +#define DIO_M_1FNC 0x7 +#define DIO_V_1GRP 0 /* int group */ +#define DIO_M_1GRP 0xF +#define DIO_GETMOD(x) (((x) >> DIO_V_MOD) & DIO_M_MOD) +#define DIO_GET0FNC(x) (((x) >> DIO_V_0FNC) & DIO_M_0FNC) +#define DIO_GET1FNC(x) (((x) >> DIO_V_1FNC) & DIO_M_1FNC) +#define DIO_GET1GRP(x) (((x) >> DIO_V_1GRP) & DIO_M_1GRP) +#define DIO_N_MOD (DIO_M_MOD + 1) /* # DIO "modes" */ + +/* I/O instruction address format */ + +#define DVA_V_CHAN 8 /* channel */ +#define DVA_M_CHAN (CHAN_N_CHAN - 1) +#define DVA_CHAN (DVA_M_CHAN << DVA_V_CHAN) +#define DVA_V_DEVSU 0 /* dev, 1 unit */ +#define DVA_M_DEVSU 0x7F +#define DVA_DEVSU (DVA_M_DEVSU << DVA_V_DEVSU) +#define DVA_MU 0x80 /* multi-unit flg */ +#define DVA_V_DEVMU 4 /* dev, multi */ +#define DVA_M_DEVMU 0x7 +#define DVA_DEVMU (DVA_M_DEVMU << DVA_V_DEVMU) +#define DVA_V_UNIT 0 /* unit number */ +#define DVA_M_UNIT 0xF +#define DVA_GETCHAN(x) (((x) >> DVA_V_CHAN) & DVA_M_CHAN) +#define DVA_GETDEV(x) (((x) & DVA_MU)? \ + (((x) >> DVA_V_DEVMU) & DVA_M_DEVMU): \ + (((x) >> DVA_V_DEVSU) & DVA_M_DEVSU)) +#define DVA_GETUNIT(x) (((x) & DVA_MU)? \ + (((x) >> DVA_V_UNIT) & DVA_M_UNIT): 0) + +/* Default I/O device addresses */ + +#define DVA_TT 0x001 +#define DVA_LP 0x002 +#define DVA_CR 0x003 +#define DVA_CP 0x004 +#define DVA_PT 0x005 +#define DVA_MUX 0x006 +#define DIO_MUX 0x3 +#define DVA_MT 0x080 +#define DVA_RAD 0x180 +#define DVA_DK 0x190 +#define DVA_DPA 0x280 +#define DVA_DPB 0x380 + +/* Channel routine status codes */ + +#define CHS_ERR 0x4000 /* any error */ +#define CHS_INF 0x8000 /* information */ +#define CHS_IFERR(x) (((x) != 0) && ((x) < CHS_INF)) + +#define CHS_INACTV (CHS_ERR + 0) +#define CHS_NXM (CHS_ERR + 1) +#define CHS_SEQ (CHS_ERR + 2) + +#define CHS_ZBC (CHS_INF + 1) /* zero byte count */ +#define CHS_CCH (CHS_INF + 2) /* command chain */ + +/* Boot ROM */ + +#define BOOT_SA 0x20 +#define BOOT_LNT 12 +#define BOOT_DEV 0x25 +#define BOOT_PC 0x26 + +/* Internal real-time scheduler */ + +#define RTC_C1 0 +#define RTC_C2 1 +#define RTC_C3 2 +#define RTC_C4 3 +#define RTC_NUM_CNTRS 4 +#define RTC_TTI (RTC_NUM_CNTRS + 0) +#define RTC_COC (RTC_NUM_CNTRS + 1) +#define RTC_ALARM (RTC_NUM_CNTRS + 2) +#define RTC_NUM_EVNTS (RTC_NUM_CNTRS + 3) + +#define RTC_HZ_OFF 0 +#define RTC_HZ_500 1 +#define RTC_HZ_50 2 +#define RTC_HZ_60 3 +#define RTC_HZ_100 4 +#define RTC_HZ_2 5 +#define RTC_NUM_HZ 6 + +/* Function prototypes */ + +uint32 chan_get_cmd (uint32 dva, uint32 *cmd); +uint32 chan_set_chf (uint32 dva, uint32 fl); +t_bool chan_tst_cmf (uint32 dva, uint32 fl); +void chan_set_chi (uint32 dva, uint32 fl); +void chan_set_dvi (uint32 dva); +int32 chan_clr_chi (uint32 dva); +int32 chan_chk_chi (uint32 dva); +uint32 chan_end (uint32 dva); +uint32 chan_uen (uint32 dva); +uint32 chan_RdMemB (uint32 dva, uint32 *dat); +uint32 chan_WrMemB (uint32 dva, uint32 dat); +uint32 chan_WrMemBR (uint32 dva, uint32 dat); +uint32 chan_RdMemW (uint32 dva, uint32 *dat); +uint32 chan_WrMemW (uint32 dva, uint32 dat); +t_stat chan_reset_dev (uint32 dva); +void io_sclr_req (uint32 inum, uint32 val); +void io_sclr_arm (uint32 inum, uint32 val); +t_stat io_set_dvc (UNIT* uptr, int32 val, char *cptr, void *desc); +t_stat io_show_dvc (FILE *st, UNIT *uptr, int32 val, void *desc); +t_stat io_set_dva (UNIT* uptr, int32 val, char *cptr, void *desc); +t_stat io_show_dva (FILE *st, UNIT *uptr, int32 val, void *desc); +t_stat io_show_cst (FILE *st, UNIT *uptr, int32 val, void *desc); +t_stat io_boot (int32 u, DEVICE *dptr); + +/* Internal real-time event scheduler */ + +t_stat rtc_set_tps (UNIT *uptr, int32 val, char *cptr, void *desc); +t_stat rtc_show_tps (FILE *of, UNIT *uptr, int32 val, void *desc); +t_stat rtc_register (uint32 tm, uint32 idx, UNIT *uptr); + +#endif \ No newline at end of file diff --git a/sigma/sigma_lp.c b/sigma/sigma_lp.c new file mode 100644 index 00000000..70261e4d --- /dev/null +++ b/sigma/sigma_lp.c @@ -0,0 +1,529 @@ +/* sigma_lp.c: Sigma 7440/7450 line printer + + Copyright (c) 2007-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. + + lp 7440/7445 or 7450 line printer +*/ + +#include "sigma_io_defs.h" + +/* Device definitions */ + +#define CCT_LNT 256 /* carriage ctl max */ +#define BUF_LNT4 132 /* line lengths */ +#define BUF_LNT5 128 + +#define LP_7440 0 /* models */ +#define LP_7450 1 + +/* Device states */ + +#define LPS_INIT 0x101 +#define LPS_END 0x102 +#define LPS_PRI 0x1 +#define LPS_FMT 0x3 +#define LPS_FMTP 0x5 +#define LPS_INT 0x40 + +/* Device status */ + +#define LPDV_ODD 0x40 /* odd */ +#define LPDV_TOF 0x10 /* top of form */ +#define LPDV_MOV 0x08 /* paper moving */ +#define LPDV_V_RUN 2 /* runaway CCT */ +#define LPDV_RUN (1u << LPDV_V_RUN) +#define LPDV_WT2 0x02 /* waiting for 2nd */ + +/* Format characters */ + +#define FMT_INH 0x60 +#define FMT_SPC 0xC0 +#define FMT_SKP 0xF0 + +#define FMT_MSPC4 15 /* max space cmd */ +#define FMT_MSPC5 7 +#define SPC_MASK ((lp_model == LP_7440)? FMT_MSPC4: FMT_MSPC5) +#define FMT_MCH4 7 /* max CCT channel */ +#define FMT_MCH5 1 +#define CCH_MASK ((lp_model == LP_7440)? FMT_MCH5: FMT_MCH4) + +#define CH_BOF 0 /* CCT bot of form */ +#define CH_TOF 1 /* CCT top of form */ + +#define CHP(ch,val) ((val) & (1 << (ch))) + +uint32 lp_cmd = 0; +uint32 lp_stopioe = 1; +uint32 lp_cctp = 0; /* CCT position */ +uint32 lp_cctl = 1; /* CCT length */ +uint32 lp_lastcmd = 0; /* last command */ +uint32 lp_pass = 0; /* 7450 print pass */ +uint32 lp_inh = 0; /* space inhibit */ +uint32 lp_run = 0; /* CCT runaway */ +uint32 lp_model = LP_7440; +uint8 lp_buf[BUF_LNT4]; /* print buffer */ +uint8 lp_cct[CCT_LNT] = { 0xFF }; /* carriage ctl tape */ +uint8 lp_to_ascii[64] = { + ' ', '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', '^', ',', '%', '_', '>', '?', + '0', '1', '2', '3', '4', '5', '6', '7', + '8', '9', ':', '#', '@', '\'', '=', '"' + }; + +extern uint32 chan_ctl_time; + +uint32 lp_disp (uint32 op, uint32 dva, uint32 *dvst); +uint32 lp_tio_status (void); +uint32 lp_tdv_status (void); +t_stat lp_chan_err (uint32 st); +t_stat lp_svc (UNIT *uptr); +t_stat lp_reset (DEVICE *dptr); +t_stat lp_attach (UNIT *uptr, char *cptr); +t_stat lp_settype (UNIT *uptr, int32 val, char *cptr, void *desc); +t_stat lp_showtype (FILE *st, UNIT *uptr, int32 val, void *desc); +t_stat lp_load_cct (UNIT *uptr, int32 val, char *cptr, void *desc); +uint32 lp_fmt (UNIT *uptr); +uint32 lp_skip (UNIT *uptr, uint32 ch); +uint32 lp_space (UNIT *uptr, uint32 lines, t_bool skp); +uint32 lp_print (UNIT *uptr); + +/* LP data structures + + lp_dev LP device descriptor + lp_unit LP unit descriptors + lp_reg LP register list + lp_mod LP modifiers list +*/ + +dib_t lp_dib = { DVA_LP, lp_disp, 0, NULL }; + +UNIT lp_unit = { UDATA (&lp_svc, UNIT_ATTABLE+UNIT_SEQ, 0), SERIAL_OUT_WAIT }; + +REG lp_reg[] = { + { HRDATA (CMD, lp_cmd, 9) }, + { BRDATA (BUF, lp_buf, 16, 7, BUF_LNT4) }, + { FLDATA (PASS, lp_pass, 0) }, + { FLDATA (INH, lp_inh, 0) }, + { FLDATA (RUNAWAY, lp_run, LPDV_V_RUN) }, + { BRDATA (CCT, lp_cct, 8, 8, CCT_LNT) }, + { DRDATA (CCTP, lp_cctp, 8), PV_LEFT }, + { DRDATA (CCTL, lp_cctl, 8), PV_LEFT + REG_HRO + REG_NZ }, + { DRDATA (POS, lp_unit.pos, T_ADDR_W), PV_LEFT }, + { DRDATA (TIME, lp_unit.wait, 24), PV_LEFT }, + { FLDATA (STOP_IOE, lp_stopioe, 0) }, + { HRDATA (LASTC, lp_lastcmd, 8), REG_HIDDEN }, + { FLDATA (MODEL, lp_model, 0), REG_HRO }, + { HRDATA (DEVNO, lp_dib.dva, 12), REG_HRO }, + { NULL } + }; + +MTAB lp_mod[] = { + { MTAB_XTD | MTAB_VDV, LP_7440, NULL, "7440", + &lp_settype, NULL, NULL }, + { MTAB_XTD | MTAB_VDV, LP_7450, NULL, "7450", + &lp_settype, NULL, NULL }, + { MTAB_XTD | MTAB_VDV, 0, "TYPE", NULL, + NULL, &lp_showtype, NULL }, + { MTAB_XTD | MTAB_VDV | MTAB_NC, 0, NULL, "CCT", + &lp_load_cct, NULL, NULL }, + { MTAB_XTD|MTAB_VDV, 0, "CHAN", "CHAN", + &io_set_dvc, &io_show_dvc, NULL }, + { MTAB_XTD|MTAB_VDV, 0, "DVA", "DVA", + &io_set_dva, &io_show_dva, NULL }, + { MTAB_XTD|MTAB_VDV|MTAB_NMO, 0, "CSTATE", NULL, + NULL, &io_show_cst, NULL }, + { 0 } + }; + +DEVICE lp_dev = { + "LP", &lp_unit, lp_reg, lp_mod, + 1, 10, 31, 1, 16, 8, + NULL, NULL, &lp_reset, + NULL, &lp_attach, NULL, + &lp_dib, 0 + }; + +/* Line printer: IO dispatch routine */ + +uint32 lp_disp (uint32 op, uint32 dva, uint32 *dvst) +{ +switch (op) { /* case on op */ + + case OP_SIO: /* start I/O */ + *dvst = lp_tio_status (); /* get status */ + if ((*dvst & DVS_DST) == 0) { /* idle? */ + lp_cmd = LPS_INIT; /* start dev thread */ + sim_activate (&lp_unit, chan_ctl_time); + } + break; + + case OP_TIO: /* test status */ + *dvst = lp_tio_status (); /* return status */ + break; + + case OP_TDV: /* test status */ + *dvst = lp_tdv_status (); /* return status */ + break; + + case OP_HIO: /* halt I/O */ + chan_clr_chi (lp_dib.dva); /* clear int */ + *dvst = lp_tio_status (); /* get status */ + if ((*dvst & DVS_DST) != 0) { /* busy? */ + sim_cancel (&lp_unit); /* stop dev thread */ + chan_uen (lp_dib.dva); /* uend */ + } + break; + + case OP_AIO: /* acknowledge int */ + chan_clr_chi (lp_dib.dva); /* clear int */ + *dvst = lp_lastcmd & LPS_INT; /* int requested */ + lp_lastcmd = 0; + break; + + default: + *dvst = 0; + return SCPE_IERR; + } + +return 0; +} + +/* Service routine */ + +t_stat lp_svc (UNIT *uptr) +{ +uint32 cmd; +uint32 st; + +switch (lp_cmd) { /* case on state */ + + case LPS_INIT: /* I/O init */ + st = chan_get_cmd (lp_dib.dva, &cmd); /* get command */ + if (CHS_IFERR (st)) /* channel error? */ + return lp_chan_err (st); + lp_inh = 0; /* clear inhibit, */ + lp_run = 0; /* runaway */ + lp_cmd = lp_lastcmd = cmd; /* save command */ + sim_activate (uptr, chan_ctl_time); /* continue thread */ + break; + + case LPS_FMT: + case LPS_FMT|LPS_INT: /* format only */ + sim_activate (uptr, uptr->wait); /* continue thread */ + if ((uptr->flags & UNIT_ATT) == 0) /* not attached? */ + return lp_stopioe? SCPE_UNATT: SCPE_OK; + st = lp_fmt (uptr); /* format */ + if (CHS_IFERR (st)) /* error? */ + return lp_chan_err (st); + if ((lp_model == LP_7440) && /* 7440? lnt chk */ + (st != CHS_ZBC) && + chan_set_chf (lp_dib.dva, CHF_LNTE)) /* not ignored? */ + return lp_chan_err (SCPE_OK); /* force uend */ + lp_cmd = LPS_END; /* actual print */ + break; + + case LPS_FMTP: + case LPS_FMTP|LPS_INT: /* format and print */ + sim_activate (uptr, uptr->wait); /* continue thread */ + if ((uptr->flags & UNIT_ATT) == 0) /* not attached? */ + return lp_stopioe? SCPE_UNATT: SCPE_OK; + st = lp_fmt (uptr); /* format */ + if (CHS_IFERR (st)) /* error? */ + return lp_chan_err (st); + if (st == CHS_ZBC) { /* command done? */ + if ((lp_model == LP_7440) && /* 7440? lnt err */ + chan_set_chf (lp_dib.dva, CHF_LNTE)) /* not ignored? */ + return lp_chan_err (SCPE_OK); + } + else { /* more to do */ + st = lp_print (uptr); /* print */ + if (CHS_IFERR (st)) /* error */ + return lp_chan_err (st); + } + break; + + case LPS_PRI: + case LPS_PRI|LPS_INT: /* print only */ + sim_activate (uptr, uptr->wait); /* continue thread */ + if ((uptr->flags & UNIT_ATT) == 0) /* not attached? */ + return lp_stopioe? SCPE_UNATT: SCPE_OK; + st = lp_print (uptr); /* print */ + if (CHS_IFERR (st)) /* error? */ + return lp_chan_err (st); + break; + + case LPS_END: /* command done */ + if ((lp_lastcmd & LPS_INT) && !lp_pass) /* int requested? */ + chan_set_chi (lp_dib.dva, 0); + st = chan_end (lp_dib.dva); /* set channel end */ + if (CHS_IFERR (st)) /* channel error? */ + return lp_chan_err (st); + if (st == CHS_CCH) { /* command chain? */ + lp_cmd = LPS_INIT; /* restart thread */ + sim_activate (uptr, chan_ctl_time); + } + break; + + default: /* invalid cmd */ + chan_uen (lp_dib.dva); /* uend */ + break; + } + +return SCPE_OK; +} + +/* Format routine */ + +uint32 lp_fmt (UNIT *uptr) +{ +uint32 c, i; +uint32 st; + +st = chan_RdMemB (lp_dib.dva, &c); /* get char */ +if (CHS_IFERR (st)) /* channel error? */ + return st; /* caller handles */ +if (lp_pass) /* only on pass 1 */ + return 0; +if ((c & 0x7F) == FMT_INH) /* inhibit? */ + lp_inh = 1; +else if ((c & ~(((lp_model == LP_7450)? 0x20: 0) | SPC_MASK)) == FMT_SPC) { + c = c & SPC_MASK; /* space? */ + for (i = 1; i <= c; i++) { /* look for BOF */ + if (CHP (CH_BOF, lp_cct[(lp_cctp + i) % lp_cctl])) + return lp_skip (uptr, CH_TOF); /* found, TOF */ + } + return lp_space (uptr, c, FALSE); /* space */ + } +else if ((c & ~CCH_MASK) == FMT_SKP) /* skip? */ + return lp_skip (uptr, c & CCH_MASK); /* skip to chan */ +return 0; +} + +/* Skip to channel */ + +uint32 lp_skip (UNIT *uptr, uint32 ch) +{ +uint32 i; + +for (i = 1; i < (lp_cctl + 1); i++) { /* sweep thru CCT */ + if (CHP (ch, lp_cct[(lp_cctp + i) % lp_cctl])) /* channel punched? */ + return lp_space (uptr, i, TRUE); /* space to chan */ + } +lp_run = LPDV_RUN; /* runaway CCT */ +return lp_space (uptr, lp_cctl, TRUE); /* space max */ +} + +/* Space routine */ + +uint32 lp_space (UNIT *uptr, uint32 cnt, t_bool skp) +{ +uint32 i; + +lp_cctp = (lp_cctp + cnt) % lp_cctl; /* adv cct, mod lnt */ +if (skp && CHP (CH_TOF, lp_cct[lp_cctp])) /* skip, TOF? */ + fputs ("\f", uptr->fileref); /* ff */ + else { /* space */ + for (i = 0; i < cnt; i++) + fputc ('\n', uptr->fileref); + } +uptr->pos = ftell (uptr->fileref); /* update position */ +if (ferror (uptr->fileref)) { /* error? */ + perror ("Line printer I/O error"); + clearerr (uptr->fileref); + chan_set_chf (lp_dib.dva, CHF_XMDE); + return SCPE_IOERR; + } +return 0; +} + +/* Print routine */ + +uint32 lp_print (UNIT *uptr) +{ +uint32 i, bp, c; +uint32 max = (lp_model == LP_7440)? BUF_LNT4: BUF_LNT5; +uint32 st; + +if (lp_pass == 0) { /* pass 1? clr buf */ + for (i = 0; i < BUF_LNT4; i++) lp_buf[i] = ' '; + } +for (bp = 0, st = 0; (bp < max) && !st; bp++) { /* fill buffer */ + st = chan_RdMemB (lp_dib.dva, &c); /* get char */ + if (CHS_IFERR (st)) /* channel error? */ + return st; /* caller handles */ + if ((lp_model == LP_7440) || /* 7440 or */ + ((bp & 1) == lp_pass)) /* correct pass? */ + lp_buf[bp] = lp_to_ascii[c & 0x3F]; + } +if ((lp_model == LP_7440) || lp_pass) { /* ready to print? */ + lp_pass = 0; + for (i = BUF_LNT4; (i > 0) && (lp_buf[i - 1] == ' '); i--) ; /* trim */ + if (i) /* write line */ + sim_fwrite (lp_buf, 1, i, uptr->fileref); + fputc (lp_inh? '\r': '\n', uptr->fileref); /* cr or nl */ + uptr->pos = ftell (uptr->fileref); /* update position */ + if (ferror (uptr->fileref)) { /* error? */ + perror ("Line printer I/O error"); + clearerr (uptr->fileref); + chan_set_chf (lp_dib.dva, CHF_XMDE); + return SCPE_IOERR; + } + if ((lp_model == LP_7440) && /* 7440? */ + ((bp != BUF_LNT4) || (st != CHS_ZBC)) && /* check lnt err */ + chan_set_chf (lp_dib.dva, CHF_LNTE)) + return CHS_INACTV; /* stop if asked */ + } +else lp_pass = 1; /* 7450 pass 2 */ +lp_cmd = LPS_END; /* end state */ +return 0; +} + +/* LP status routine */ + +uint32 lp_tio_status (void) +{ +uint32 st; + +st = (lp_unit.flags & UNIT_ATT)? DVS_AUTO: 0; /* auto? */ +if (sim_is_active (&lp_unit)) /* busy? */ + st |= (DVS_CBUSY | DVS_DBUSY | (CC2 << DVT_V_CC)); +return st; +} + +uint32 lp_tdv_status (void) +{ +uint32 st; + +st = lp_run; /* runaway flag */ +if ((lp_unit.flags & UNIT_ATT) == 0) /* fault? */ + st |= (CC2 << DVT_V_CC); +if (lp_cmd == LPS_END) /* end state? */ + st |= LPDV_MOV; /* printing */ +if (lp_pass && (lp_model == LP_7450)) { /* 7450 pass 2? */ + st |= LPDV_ODD; /* odd state */ + if (lp_cmd == LPS_INIT) /* wait for cmd? */ + st |= LPDV_WT2; + } +return st; +} + +/* Channel error */ + +t_stat lp_chan_err (uint32 st) +{ +sim_cancel (&lp_unit); /* stop dev thread */ +chan_uen (lp_dib.dva); /* uend */ +if (st < CHS_ERR) + return st; +return SCPE_OK; +} + +/* Reset routine */ + +t_stat lp_reset (DEVICE *dptr) +{ +sim_cancel (&lp_unit); /* stop dev thread */ +lp_cmd = 0; +lp_lastcmd = 0; +lp_pass = 0; +lp_inh = 0; +lp_run = 0; +chan_reset_dev (lp_dib.dva); /* clr int, active */ +return SCPE_OK; +} + +/* Attach routine */ + +t_stat lp_attach (UNIT *uptr, char *cptr) +{ +lp_cctp = 0; /* clear cct ptr */ +lp_pass = 0; +return attach_unit (uptr, cptr); +} + +/* Set carriage control tape */ + +t_stat lp_load_cct (UNIT *uptr, int32 val, char *cptr, void *desc) +{ +uint32 col, rpt, ptr, mask; +uint8 cctbuf[CCT_LNT]; +t_stat r; +char cbuf[CBUFSIZE], gbuf[CBUFSIZE]; +FILE *cfile; + +if ((cptr == NULL) || (*cptr == 0)) return SCPE_ARG; +if ((cfile = fopen (cptr, "r")) == NULL) + return SCPE_OPENERR; +ptr = 0; +for ( ; (cptr = fgets (cbuf, CBUFSIZE, cfile)) != NULL; ) { + 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, FMT_MCH4, &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; +lp_cctl = ptr; +lp_cctp = 0; +for (rpt = 0; rpt < lp_cctl; rpt++) + lp_cct[rpt] = cctbuf[rpt]; +return SCPE_OK; +} + +/* Set controller type */ + +t_stat lp_settype (UNIT *uptr, int32 val, char *cptr, void *desc) +{ +lp_model = val; +lp_reset (&lp_dev); +return SCPE_OK; +} + +/* Show controller type */ + +t_stat lp_showtype (FILE *st, UNIT *uptr, int32 val, void *desc) +{ +fprintf (st, lp_model? "7450": "7440"); +return SCPE_OK; +} diff --git a/sigma/sigma_map.c b/sigma/sigma_map.c new file mode 100644 index 00000000..898de7bb --- /dev/null +++ b/sigma/sigma_map.c @@ -0,0 +1,591 @@ +/* sigma_map.c: XDS Sigma memory access routines + + Copyright (c) 2007, Robert M Supnik + + Permission is hereby granted, free of charge, to any person obtaining a + copy of this software and associated documentation files (the "Software"), + to deal in the Software without restriction, including without limitation + the rights to use, copy, modify, merge, publish, distribute, sublicense, + and/or sell copies of the Software, and to permit persons to whom the + Software is furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + ROBERT M SUPNIK BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + Except as contained in this notice, the name of Robert M Supnik shall not be + used in advertising or otherwise to promote the sale, use or other dealings + in this Software without prior written authorization from Robert M Supnik. +*/ + +#include "sigma_defs.h" + +#define BVA_REG (RF_NUM << 2) +#define BPAMASK ((cpu_tab[cpu_model].pamask << 2) | 0x3) +#define NUM_MUNITS (MAXMEMSIZE / CPU_MUNIT_SIZE) + +/* Sigma 8-9 memory status words */ + +#define S89_SR0_BADLMS 0x00800000 /* bad LMS */ +#define S89_SR0_RD (S89_SR0_BADLMS) +#define S89_SR0_V_PORTS 12 + +#define S89_SR1_FIXED 0x50C40000 /* always 1 */ +#define S89_SR1_M_MEMU 0xF /* mem unit */ +#define S89_SR1_V_MEMU 24 +#define S89_SR1_MARG 0x00F80000 /* margin write */ +#define S89_SR1_MAROFF 2 /* offset to read */ + +/* 5X0 memory status words */ + +#define S5X0_SR0_FIXED 0x40000000 +#define S5X0_SR0_BADLMS 0x00000004 /* bad LMS */ +#define S5X0_SR0_RD (S5X0_SR0_BADLMS) +#define S5X0_SR0_V_PORTS 21 + +#define S5X0_SR1_FIXED 0xB0000000 /* fixed */ +#define S5X0_SR1_M_MEMU 0x7 /* mem unit */ +#define S5X0_SR1_V_MEMU 25 +#define S5X0_SR1_V_SA 18 /* start addr */ + +#define S8 + +typedef struct { + uint32 width; /* item width */ + uint32 dmask; /* data mask */ + uint32 cmask; /* control start mask */ + uint32 lnt; /* array length */ + uint32 opt; /* option control */ + } mmc_ctl_t; + +uint16 mmc_rel[VA_NUM_PAG]; +uint8 mmc_acc[VA_NUM_PAG]; +uint8 mmc_wlk[PA_NUM_PAG]; + +uint32 mem_sr0[NUM_MUNITS]; +uint32 mem_sr1[NUM_MUNITS]; + +mmc_ctl_t mmc_tab[8] = { + { 0, 0, 0, 0 }, + { 2, 0x003, 0, MMC_L_CS1, CPUF_WLK }, /* map 1: 2b locks */ + { 2, 0x003, MMC_M_CS2, MMC_L_CS2, CPUF_MAP }, /* map 2: 2b access ctls */ + { 4, 0x00F, MMC_M_CS3, MMC_L_CS3, CPUF_WLK }, /* map 3: 4b locks */ + { 8, 0x0FF, MMC_M_CS4, MMC_L_CS4, CPUF_MAP }, /* map 4: 8b relocation */ + { 16, 0x7FF, MMC_M_CS5, MMC_L_CS5, CPUF_MAP }, /* map 5: 16b relocation */ + { 0, 0, 0, 0 }, + { 0, 0, 0, 0 } + }; + +extern uint32 *R; +extern uint32 *M; +extern uint32 PSW1, PSW2, PSW4; +extern uint32 CC, PSW2_WLK; +extern uint32 stop_op; +extern uint32 cpu_model; +extern uint32 chan_num; +extern UNIT cpu_unit; +extern cpu_var_t cpu_tab[]; + +uint32 map_reloc (uint32 bva, uint32 acc, uint32 *bpa); +uint32 map_viol (uint32 bva, uint32 bpa, uint32 tr); +t_stat map_reset (DEVICE *dptr); +uint32 map_las (uint32 rn, uint32 bva); + +/* Map data structures + + map_dev map device descriptor + map_unit map units + map_reg map register list +*/ + +UNIT map_unit = { UDATA (NULL, 0, 0) }; + +REG map_reg[] = { + { BRDATA (REL, mmc_rel, 16, 13, VA_NUM_PAG) }, + { BRDATA (ACC, mmc_acc, 16, 2, VA_NUM_PAG) }, + { BRDATA (WLK, mmc_wlk, 16, 4, PA_NUM_PAG) }, + { BRDATA (SR0, mem_sr0, 16, 32, NUM_MUNITS) }, + { BRDATA (SR1, mem_sr1, 16, 32, NUM_MUNITS) }, + { NULL } + }; + +DEVICE map_dev = { + "MAP", &map_unit, map_reg, NULL, + 1, 16, 16, 1, 16, 32, + NULL, NULL, &map_reset, + NULL, NULL, NULL, + NULL, 0 + }; + +/* Read and write virtual routines - per length */ + +uint32 ReadB (uint32 bva, uint32 *dat, uint32 acc) +{ +uint32 bpa, sc, tr; + +sc = 24 - ((bva & 3) << 3); +if (bva < BVA_REG) /* register access */ + *dat = (R[bva >> 2] >> sc) & BMASK; +else { /* memory access */ + if ((tr = map_reloc (bva, acc, &bpa)) != 0) /* relocate addr */ + return tr; + *dat = (M[bpa >> 2] >> sc) & BMASK; + } /* end else memory */ +return 0; +} + +uint32 ReadH (uint32 bva, uint32 *dat, uint32 acc) +{ +uint32 bpa, tr; + +if (bva < BVA_REG) { /* register access */ + if (bva & 2) + *dat = R[bva >> 2] & HMASK; + else *dat = (R[bva >> 2] >> 16) & HMASK; + } +else { /* memory access */ + if ((tr = map_reloc (bva, acc, &bpa)) != 0) /* relocate addr */ + return tr; + if (bva & 2) + *dat = M[bpa >> 2] & HMASK; + else *dat = (M[bpa >> 2] >> 16) & HMASK; + } /* end else memory */ +return 0; +} + +uint32 ReadW (uint32 bva, uint32 *dat, uint32 acc) +{ +uint32 bpa, tr; + +if (bva < BVA_REG) /* register access */ + *dat = R[bva >> 2]; +else { /* memory access */ + if ((tr = map_reloc (bva, acc, &bpa)) != 0) /* relocate addr */ + return tr; + *dat = M[bpa >> 2]; + } /* end else memory */ +return 0; +} + +uint32 ReadD (uint32 bva, uint32 *dat, uint32 *dat1, uint32 acc) +{ +uint32 bpa, tr; + +if (bva < BVA_REG) { /* register access */ + *dat = R[(bva >> 2) & ~1]; /* force alignment */ + *dat1 = R[(bva >> 2) | 1]; + } +else { /* memory access */ + if ((tr = map_reloc (bva, acc, &bpa)) != 0) /* relocate addr */ + return tr; + *dat = M[(bpa >> 2) & ~1]; /* force alignment */ + *dat1 = M[(bpa >> 2) | 1]; + } /* end else memory */ + +return 0; +} + +uint32 WriteB (uint32 bva, uint32 dat, uint32 acc) +{ +uint32 bpa, sc, tr; + +sc = 24 - ((bva & 3) << 3); +if (bva < BVA_REG) /* register access */ + R[bva >> 2] = (R[bva >> 2] & ~(BMASK << sc)) | ((dat & BMASK) << sc); +else { /* memory access */ + if ((tr = map_reloc (bva, acc, &bpa)) != 0) /* relocate addr */ + return tr; + M[bpa >> 2] = (M[bpa >> 2] & ~(BMASK << sc)) | ((dat & BMASK) << sc); + } /* end else memory */ +PSW2 |= PSW2_RA; /* state altered */ +return 0; +} + +uint32 WriteH (uint32 bva, uint32 dat, uint32 acc) +{ +uint32 bpa, tr; + +if (bva < BVA_REG) { /* register access */ + if (bva & 2) + R[bva >> 2] = (R[bva >> 2] & ~HMASK) | (dat & HMASK); + else R[bva >> 2] = (R[bva >> 2] & HMASK) | ((dat & HMASK) << 16); + } /* end if register */ +else { /* memory access */ + if ((tr = map_reloc (bva, acc, &bpa)) != 0) /* relocate addr */ + return tr; + if (bva & 2) + M[bpa >> 2] = (M[bpa >> 2] & ~HMASK) | (dat & HMASK); + else M[bpa >> 2] = (M[bpa >> 2] & HMASK) | ((dat & HMASK) << 16); + } /* end else memory */ +PSW2 |= PSW2_RA; /* state altered */ +return 0; +} + +uint32 WriteW (uint32 bva, uint32 dat, uint32 acc) +{ +uint32 bpa, tr; + +if (bva < BVA_REG) /* register access */ + R[bva >> 2] = dat & WMASK; +else { /* memory access */ + if ((tr = map_reloc (bva, acc, &bpa)) != 0) /* relocate addr */ + return tr; + M[bpa >> 2] = dat & WMASK; + } /* end else memory */ +PSW2 |= PSW2_RA; /* state altered */ +return 0; +} + +uint32 WriteD (uint32 bva, uint32 dat, uint32 dat1, uint32 acc) +{ +uint32 bpa, tr; + +if (bva < BVA_REG) { /* register access */ + R[(bva >> 2) & ~1] = dat & WMASK; /* force alignment */ + R[(bva >> 2) | 1] = dat1 & WMASK; + } +else { /* memory access */ + if ((tr = map_reloc (bva, acc, &bpa)) != 0) /* relocate addr */ + return tr; + M[(bpa >> 2) & ~1] = dat & WMASK; /* force alignment */ + M[(bpa >> 2) | 1] = dat1 & WMASK; + } /* end else memory */ +PSW2 |= PSW2_RA; /* state altered */ +return 0; +} + +/* General virtual read for instruction history */ + +uint32 ReadHist (uint32 bva, uint32 *dat, uint32 *dat1, uint32 acc, uint32 lnt) +{ +switch (lnt) { /* case on length */ + + case BY: /* byte */ + return ReadB (bva, dat, acc); + + case HW: /* halfword */ + return ReadH (bva, dat, acc); + + case WD: /* word */ + return ReadW (bva, dat, acc); + + case DW: /* doubleword first */ + return ReadD (bva, dat, dat1, acc); + } /* end case length */ + +return SCPE_IERR; +} + +/* Specialized virtual read and write word routines - + treats all addresses as memory addresses */ + +uint32 ReadMemVW (uint32 bva, uint32 *dat, uint32 acc) +{ +uint32 bpa; +uint32 tr; + +if ((tr = map_reloc (bva, acc, &bpa)) != 0) /* relocate addr */ + return tr; +*dat = M[bpa >> 2] & WMASK; +return 0; +} + +uint32 WriteMemVW (uint32 bva, uint32 dat, uint32 acc) +{ +uint32 bpa; +uint32 tr; + +if ((tr = map_reloc (bva, acc, &bpa)) != 0) /* relocate addr */ + return tr; +M[bpa >> 2] = dat & WMASK; +return 0; +} + +/* Relocation routine */ + +uint32 map_reloc (uint32 bva, uint32 acc, uint32 *bpa) +{ +if ((acc != 0) && (PSW1 & PSW1_MM)) { /* virt, map on? */ + uint32 vpag = BVA_GETPAG (bva); /* virt page num */ + *bpa = ((mmc_rel[vpag] << BVA_V_PAG) + BVA_GETOFF (bva)) & BPAMASK; + if (((PSW1 & PSW1_MS) || /* slave mode? */ + (PSW2 & (PSW2_MA9|PSW2_MA5X0))) && /* master prot? */ + (mmc_acc[vpag] >= acc)) /* access viol? */ + return map_viol (bva, *bpa, TR_MPR); + } +else *bpa = bva; /* no, physical */ +if ((acc == VW) && PSW2_WLK) { /* write check? */ + uint32 ppag = BPA_GETPAG (*bpa); /* phys page num */ + if (PSW2_WLK && mmc_wlk[ppag] && /* lock, key != 0 */ + (PSW2_WLK != mmc_wlk[ppag])) /* lock != key? */ + return map_viol (bva, *bpa, TR_WLK); + } +if (BPA_IS_NXM (*bpa)) /* memory exist? */ + return TR_NXM; /* don't set TSF */ +return 0; +} + +/* Memory management error */ + +uint32 map_viol (uint32 bva, uint32 bpa, uint32 tr) +{ +uint32 vpag = BVA_GETPAG (bva); /* virt page num */ + +if (QCPU_S9) /* Sigma 9? */ + PSW2 = (PSW2 & ~PSW2_TSF) | (vpag << PSW2_V_TSF); /* save address */ +PSW4 = bva >> 2; /* 5X0 address */ +if ((tr == TR_WLK) && !QCPU_5X0) /* wlock on S5-9? */ + tr = TR_MPR; /* mem prot trap */ +if (BPA_IS_NXM (bpa)) /* also check NXM */ + tr |= TR_NXM; /* on MPR or WLK */ +return tr; +} + +/* Physical byte access routines */ + +uint32 ReadPB (uint32 ba, uint32 *wd) +{ +uint32 sc; + +ba = ba & BPAMASK; +if (BPA_IS_NXM (ba)) + return TR_NXM; +sc = 24 - ((ba & 3) << 3); +*wd = (M[ba >> 2] >> sc) & BMASK; +return 0; +} + +uint32 WritePB (uint32 ba, uint32 wd) +{ +uint32 sc; + +ba = ba & BPAMASK; +if (BPA_IS_NXM (ba)) + return TR_NXM; +sc = 24 - ((ba & 3) << 3); +M[ba >> 2] = (M[ba >> 2] & ~(BMASK << sc)) | ((wd & BMASK) << sc); +return 0; +} + +/* Physical word access routines */ + +uint32 ReadPW (uint32 pa, uint32 *wd) +{ +pa = pa & cpu_tab[cpu_model].pamask; +if (MEM_IS_NXM (pa)) + return TR_NXM; +*wd = M[pa]; +return 0; +} + +uint32 WritePW (uint32 pa, uint32 wd) +{ +pa = pa & cpu_tab[cpu_model].pamask; +if (MEM_IS_NXM (pa)) + return TR_NXM; +M[pa] = wd; +return 0; +} + +/* LRA - load real address (extended memory systems only) */ + +uint32 map_lra (uint32 rn, uint32 IR) +{ +uint32 lnt, bva, bpa, vpag, ppag; +uint32 tr; + +lnt = CC >> 2; /* length */ +CC = 0; /* clear */ +if ((tr = Ea (IR, &bva, VR, lnt)) != 0) { /* get eff addr */ + if (tr == TR_NXM) /* NXM trap? */ + CC = CC1|CC2; + R[rn] = bva >> 2; /* fails */ + } +else if (bva < BVA_REG) { /* reg ref? */ + CC = CC1|CC2; + R[rn] = bva >> 2; /* fails */ + } +else { + vpag = BVA_GETPAG (bva); /* virt page num */ + bpa = ((mmc_rel[vpag] << BVA_V_PAG) + BVA_GETOFF (bva)) & BPAMASK; + ppag = BPA_GETPAG (bpa); /* phys page num */ + if (MEM_IS_NXM (bpa)) /* NXM? */ + CC = CC1|CC2; + R[rn] = (QCPU_S9? (mmc_wlk[ppag] << 24): 0) | /* result */ + (bpa >> lnt); + CC |= mmc_acc[vpag]; /* access prot */ + } +return 0; +} + +/* MMC - load memory map control */ + +uint32 map_mmc (uint32 rn, uint32 map) +{ +uint32 tr; +uint32 wd, i, map_width, maps_per_word, map_cmask, cs; + +map_width = mmc_tab[map].width; /* width in bits */ +maps_per_word = 32 / map_width; +if (map != 1) /* maps 2-7? */ + map_cmask = mmc_tab[map].cmask; /* std ctl mask */ +else map_cmask = cpu_tab[cpu_model].mmc_cm_map1; /* model based */ +if ((map_width == 0) || /* validate map */ + ((cpu_unit.flags & mmc_tab[map].opt) == 0) || + ((map == 3) && !QCPU_5X0) || + ((map == 5) && !QCPU_BIGM)) { + if (QCPU_S89_5X0) /* S89, 5X0 trap */ + return TR_INVMMC; + return stop_op? STOP_ILLEG: 0; + } +do { + cs = (R[rn|1] >> MMC_V_CS) & map_cmask; /* ptr into map */ + if ((tr = ReadW ((R[rn] << 2) & BVAMASK, &wd, VR)) != 0) + return tr; + for (i = 0; i < maps_per_word; i++) { /* loop thru word */ + wd = ((wd << map_width) | (wd >> (32 - map_width))) & WMASK; + switch (map) { + + case 1: case 3: /* write locks */ + mmc_wlk[cs] = wd & mmc_tab[map].dmask; + break; + + case 2: /* access ctls */ + mmc_acc[cs] = wd & mmc_tab[map].dmask; + break; + + case 4: case 5: /* relocation */ + mmc_rel[cs] = wd & mmc_tab[map].dmask; + break; + }; + cs = (cs + 1) % mmc_tab[map].lnt; /* incr mod lnt */ + } /* end for */ + R[rn] = (R[rn] + 1) & WMASK; /* incr mem ptr */ + R[rn|1] = (R[rn|1] & ~(MMC_CNT | (map_cmask << MMC_V_CS))) | + (((MMC_GETCNT (R[rn|1]) - 1) & MMC_M_CNT) << MMC_V_CNT) | + ((cs & map_cmask) << MMC_V_CS); + } while (MMC_GETCNT (R[rn|1]) != 0); +return SCPE_OK; +} + +/* LAS instruction (reused by LMS), without condition code settings */ + +uint32 map_las (uint32 rn, uint32 bva) +{ +uint32 opnd, tr; + +if ((bva < (RF_NUM << 2)) && QCPU_5X0) /* on 5X0, reg */ + ReadW (bva, &opnd, VR); /* refs ignored */ +else { /* go to mem */ + if ((tr = ReadMemVW (bva, &opnd, VR)) != 0) /* read word */ + return tr; + if ((tr = WriteMemVW (bva, opnd | WSIGN, VW)) != 0) /* set bit */ + return tr; + } +R[rn] = opnd; /* store */ +return 0; +} + +/* Load memory status */ + +uint32 map_lms (uint32 rn, uint32 bva) +{ +uint32 tr, wd, low, ppag; +uint32 memu = (bva >> 2) / CPU_MUNIT_SIZE; + +if (CC == 0) /* LAS */ + return map_las (rn, bva); +if (CC == 1) { /* read no par */ + if ((tr = ReadW (bva, &wd, PH)) != 0) + return tr; + R[rn] = wd; + for (CC = CC3; wd != 0; CC ^= CC3) { /* calc odd par */ + low = wd & -((int32) wd); + wd = wd & ~low; + } + return 0; + } + +ppag = BPA_GETPAG (bva); /* phys page num */ +wd = mem_sr0[memu]; /* save sr0 */ +if (QCPU_S89) + switch (CC) { /* Sigma 8-9 */ + case 0x2: /* read bad par */ + if ((tr = ReadW (bva, &wd, VR)) != 0) + return tr; + R[rn] = wd; + break; + case 0x7: /* set margins */ + mem_sr1[memu] = S89_SR1_FIXED | + ((memu & S89_SR1_M_MEMU) << S89_SR1_V_MEMU) | + ((R[rn] & S89_SR1_MARG) >> S89_SR1_MAROFF); + break; + case 0xB: /* read sr0, clr */ + mem_sr0[memu] = mem_sr1[memu] = 0; + case 0x8: /* read sr0 */ + R[rn] = (wd & S89_SR0_RD) | + (((1u << (chan_num + 1)) - 1) << (S89_SR0_V_PORTS - (chan_num + 1))); + break; + case 0x9: /* read sr1 */ + R[rn] = mem_sr1[memu]; + break; + case 0xA: case 0xE: /* read sr2 */ + R[rn] = 0; + break; + case 0xF: /* clear word */ + return WriteW (bva, 0, VW); + break; + default: + mem_sr0[memu] |= S89_SR0_BADLMS; + break; + } +else switch (CC) { /* 5X0 */ + case 0x2: /* clear word */ + return WriteW (bva, 0, VW); + case 0x6: /* read wlk */ + R[rn] = (mmc_wlk[ppag & ~1] << 4) | mmc_wlk[ppag | 1]; + break; + case 0x7: /* write wlk */ + mmc_wlk[ppag & ~1] = (R[rn] >> 4) & 0xF; + mmc_wlk[ppag | 1] = R[rn] & 0xF; + break; + case 0xC: /* read sr0, clr */ + mem_sr0[memu] = 0; + case 0x8: /* read sr0 */ + R[rn] = S5X0_SR0_FIXED | (wd & S5X0_SR0_RD) | + (((1u << (chan_num + 1)) - 1) << (S5X0_SR0_V_PORTS - (chan_num + 1))); + break; + case 0xA: /* read sr1 */ + R[rn] = S5X0_SR1_FIXED | + ((memu & S5X0_SR1_M_MEMU) << S5X0_SR1_V_MEMU) | + (memu << S5X0_SR1_V_SA); + break; + case 0xE: /* trash mem */ + return WriteW (bva, R[rn] & ~0xFF, VW); + default: + mem_sr0[memu] |= S5X0_SR0_BADLMS; + break; + } +return 0; +} + +/* Device reset */ + +t_stat map_reset (DEVICE *dptr) +{ +uint32 i; + +for (i = 0; i < VA_NUM_PAG; i++) { /* clear mmc arrays */ + mmc_rel[i] = 0; + mmc_acc[i] = 0; + } +for (i = 0; i < PA_NUM_PAG; i++) + mmc_wlk[i] = 0; +return SCPE_OK; +} diff --git a/sigma/sigma_mt.c b/sigma/sigma_mt.c new file mode 100644 index 00000000..7e3e9f35 --- /dev/null +++ b/sigma/sigma_mt.c @@ -0,0 +1,645 @@ +/* sigma_mt.c: Sigma 732X 9-track magnetic tape + + Copyright (c) 2007-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 7320 and 7322/7323 magnetic tape + + 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 + 32 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 "sigma_io_defs.h" +#include "sim_tape.h" + +/* Device definitions */ + +#define MT_NUMDR 8 /* #drives */ +#define MT_REW (MT_NUMDR) /* rewind threads */ +#define UST u3 /* unit status */ +#define UCMD u4 /* unit command */ +#define MT_MAXFR (1 << 16) /* max record lnt */ + +/* Unit commands */ + +#define MCM_INIT 0x100 +#define MCM_END 0x101 +#define MCM_WRITE 0x01 +#define MCM_READ 0x02 +#define MCM_SETC 0x03 +#define MCM_SENSE 0x04 +#define MCM_RDBK 0x0C +#define MCM_RWI 0x13 +#define MCM_RWU 0x23 +#define MCM_REW 0x33 +#define MCM_SFWR 0x43 +#define MCM_SBKR 0x4B +#define MCM_SFWF 0x53 +#define MCM_SBKF 0x5B +#define MCM_ERS 0x63 +#define MCM_WTM 0x73 + +/* Command flags */ + +#define O_ATT 0x01 /* req attached */ +#define O_WRE 0x02 /* req write enb */ +#define O_REV 0x04 /* reverse oper */ +#define O_NMT 0x10 /* no motion */ + +/* Device status in UST, ^ = dynamic */ + +#define MTDV_OVR 0x80 /* overrun - NI */ +#define MTDV_WRE 0x40 /* write enabled^ */ +#define MTDV_WLE 0x20 /* write lock err */ +#define MTDV_EOF 0x10 /* end of file */ +#define MTDV_DTE 0x08 /* data error */ +#define MTDV_BOT 0x04 /* begin of tape */ +#define MTDV_EOT 0x02 /* end of tape^ */ +#define MTDV_REW 0x01 /* rewinding^ */ + +#define MTAI_MASK (MTDV_OVR|MTDV_WLE|MTDV_EOF|MTDV_DTE) +#define MTAI_V_INT 6 +#define MTAI_INT (1u << MTAI_V_INT) + +uint32 mt_stopioe = 1; +int32 mt_rwtime = 10000; /* rewind latency */ +int32 mt_ctime = 100; /* command latency */ +int32 mt_time = 10; /* record latency */ +uint32 mt_rwi = 0; /* rewind interrupts */ +t_mtrlnt mt_bptr; +t_mtrlnt mt_blim; +uint8 mt_xb[MT_MAXFR]; /* transfer buffer */ +uint8 mt_op[128] = { + 0, O_ATT|O_WRE, O_ATT, O_NMT, O_NMT, 0, 0, 0, /* wr, rd, set, sense */ + 0, 0, 0, 0, O_ATT|O_REV, 0, 0, 0, /* rd rev */ + 0, 0, 0, O_ATT, 0, 0, 0, 0, /* rewind & int */ + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, O_ATT, 0, 0, 0, 0, /* rewind offline */ + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, O_ATT, 0, 0, 0, 0, /* rewind */ + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, O_ATT, 0, 0, 0, 0, /* space fwd rec */ + 0, 0, 0, O_ATT|O_REV, 0, 0, 0, 0, /* space bk rec */ + 0, 0, 0, O_ATT, 0, 0, 0, 0, /* space fwd file */ + 0, 0, 0, O_ATT|O_REV, 0, 0, 0, 0, /* space bk file */ + 0, 0, 0, O_NMT, 0, 0, 0, 0, /* set erase */ + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, O_ATT|O_WRE, 0, 0, 0, 0, /* write tmk */ + 0, 0, 0, 0, 0, 0, 0, 0 + }; + +extern uint32 chan_ctl_time; +extern uint8 ascii_to_ebcdic[128]; +extern uint8 ebcdic_to_ascii[256]; + +uint32 mt_disp (uint32 op, uint32 dva, uint32 *dvst); +uint32 mt_tio_status (uint32 un); +uint32 mt_tdv_status (uint32 un); +t_stat mt_chan_err (uint32 st); +t_stat mtu_svc (UNIT *uptr); +t_stat mtr_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_flush_buf (uptr); +t_stat mt_map_err (UNIT *uptr, t_stat r); +int32 mt_clr_int (uint32 dva); +void mt_set_rwi (uint32 un); +void mt_clr_rwi (uint32 un); + +/* MT data structures + + mt_dev MT device descriptor + mt_unit MT unit descriptors + mt_reg MT register list + mt_mod MT modifiers list +*/ + +dib_t mt_dib = { DVA_MT, mt_disp }; + +/* First 'n' units are tape drives; second 'n' are rewind threads */ + +UNIT mt_unit[] = { + { UDATA (&mtu_svc, UNIT_ATTABLE+UNIT_ROABLE+UNIT_DISABLE, 0) }, + { UDATA (&mtu_svc, UNIT_ATTABLE+UNIT_ROABLE+UNIT_DISABLE, 0) }, + { UDATA (&mtu_svc, UNIT_ATTABLE+UNIT_ROABLE+UNIT_DISABLE, 0) }, + { UDATA (&mtu_svc, UNIT_ATTABLE+UNIT_ROABLE+UNIT_DISABLE, 0) }, + { UDATA (&mtu_svc, UNIT_ATTABLE+UNIT_ROABLE+UNIT_DISABLE, 0) }, + { UDATA (&mtu_svc, UNIT_ATTABLE+UNIT_ROABLE+UNIT_DISABLE, 0) }, + { UDATA (&mtu_svc, UNIT_ATTABLE+UNIT_ROABLE+UNIT_DISABLE, 0) }, + { UDATA (&mtu_svc, UNIT_ATTABLE+UNIT_ROABLE+UNIT_DISABLE, 0) }, + { UDATA (&mtr_svc, UNIT_DIS, 0) }, + { UDATA (&mtr_svc, UNIT_DIS, 0) }, + { UDATA (&mtr_svc, UNIT_DIS, 0) }, + { UDATA (&mtr_svc, UNIT_DIS, 0) }, + { UDATA (&mtr_svc, UNIT_DIS, 0) }, + { UDATA (&mtr_svc, UNIT_DIS, 0) }, + { UDATA (&mtr_svc, UNIT_DIS, 0) }, + { UDATA (&mtr_svc, UNIT_DIS, 0) } + }; + +REG mt_reg[] = { + { BRDATA (BUF, mt_xb, 16, 8, MT_MAXFR) }, + { DRDATA (BPTR, mt_bptr, 17) }, + { DRDATA (BLNT, mt_blim, 17) }, + { HRDATA (RWINT, mt_rwi, MT_NUMDR) }, + { DRDATA (TIME, mt_time, 24), PV_LEFT+REG_NZ }, + { DRDATA (CTIME, mt_ctime, 24), PV_LEFT+REG_NZ }, + { DRDATA (RWTIME, mt_rwtime, 24), PV_LEFT+REG_NZ }, + { URDATA (UST, mt_unit[0].UST, 16, 8, 0, MT_NUMDR, 0) }, + { URDATA (UCMD, mt_unit[0].UCMD, 16, 8, 0, 2 * MT_NUMDR, 0) }, + { URDATA (POS, mt_unit[0].pos, 10, T_ADDR_W, 0, + MT_NUMDR, PV_LEFT | REG_RO) }, + { FLDATA (STOP_IOE, mt_stopioe, 0) }, + { HRDATA (DEVNO, mt_dib.dva, 12), 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, "CHAN", "CHAN", + &io_set_dvc, &io_show_dvc, NULL }, + { MTAB_XTD|MTAB_VDV, 0, "DVA", "DVA", + &io_set_dva, &io_show_dva, NULL }, + { MTAB_XTD|MTAB_VDV|MTAB_NMO, 0, "CSTATE", NULL, + NULL, &io_show_cst, NULL }, + { 0 } + }; + +DEVICE mt_dev = { + "MT", mt_unit, mt_reg, mt_mod, + MT_NUMDR * 2, 10, T_ADDR_W, 1, 16, 8, + NULL, NULL, &mt_reset, + &io_boot, &mt_attach, &mt_detach, + &mt_dib, DEV_DISABLE + }; + +/* Magtape: IO dispatch routine */ + +uint32 mt_disp (uint32 op, uint32 dva, uint32 *dvst) +{ +uint32 un = DVA_GETUNIT (dva); +UNIT *uptr = &mt_unit[un]; + +if ((un >= MT_NUMDR) || /* inv unit num? */ + (uptr-> flags & UNIT_DIS)) /* disabled unit? */ + return DVT_NODEV; +switch (op) { /* case on op */ + + case OP_SIO: /* start I/O */ + *dvst = mt_tio_status (un); /* get status */ + if ((*dvst & (DVS_CST|DVS_DST)) == 0) { /* ctrl + dev idle? */ + uptr->UCMD = MCM_INIT; /* start dev thread */ + sim_activate (uptr, chan_ctl_time); + } + break; + + case OP_TIO: /* test status */ + *dvst = mt_tio_status (un); /* return status */ + break; + + case OP_TDV: /* test status */ + *dvst = mt_tdv_status (un); /* return status */ + break; + + case OP_HIO: /* halt I/O */ + *dvst = mt_tio_status (un); /* get status */ + if ((int32) un == chan_chk_chi (dva)) /* halt active ctlr int? */ + chan_clr_chi (dva); /* clear ctlr int */ + if (sim_is_active (uptr)) { /* chan active? */ + sim_cancel (uptr); /* stop unit */ + chan_uen (dva); /* uend */ + } + mt_clr_rwi (un); /* clear rewind int */ + sim_cancel (uptr + MT_REW); /* cancel rewind */ + break; + + case OP_AIO: /* acknowledge int */ + un = mt_clr_int (mt_dib.dva); /* clr int, get unit */ + *dvst = (mt_tdv_status (un) & MTAI_MASK) | /* device status */ + (un & MTAI_INT) | /* device int flag */ + ((un & DVA_M_UNIT) << DVT_V_UN); /* unit number */ + break; + + default: + *dvst = 0; + return SCPE_IERR; + } + +return 0; +} + +/* Unit service */ + +t_stat mtu_svc (UNIT *uptr) +{ +uint32 cmd = uptr->UCMD; +uint32 un = uptr - mt_unit; +uint32 c; +uint32 st; +int32 t; +t_mtrlnt tbc; +t_stat r; + +if (cmd == MCM_INIT) { /* init state */ + if ((t = sim_is_active (uptr + MT_REW)) != 0) { /* rewinding? */ + sim_activate (uptr, t); /* retry later */ + return SCPE_OK; + } + st = chan_get_cmd (mt_dib.dva, &cmd); /* get command */ + if (CHS_IFERR (st)) /* channel error? */ + return mt_chan_err (st); + if ((cmd & 0x80) || /* invalid cmd? */ + (mt_op[cmd] == 0)) { + uptr->UCMD = MCM_END; /* end state */ + sim_activate (uptr, chan_ctl_time); /* resched ctlr */ + return SCPE_OK; + } + else { /* valid cmd */ + if ((mt_op[cmd] & O_REV) && /* reverse op */ + (mt_unit[un].UST & MTDV_BOT)) { /* at load point? */ + chan_uen (mt_dib.dva); /* channel end */ + return SCPE_OK; + } + uptr->UCMD = cmd; /* unit state */ + if (!(mt_op[cmd] & O_NMT)) /* motion? */ + uptr->UST = 0; /* clear status */ + } + mt_blim = 0; /* no buffer yet */ + sim_activate (uptr, chan_ctl_time); /* continue thread */ + return SCPE_OK; /* done */ + } + +if (cmd == MCM_END) { /* end state */ + st = chan_end (mt_dib.dva); /* set channel end */ + if (CHS_IFERR (st)) /* channel error? */ + return mt_chan_err (st); + if (st == CHS_CCH) { /* command chain? */ + uptr->UCMD = MCM_INIT; /* restart thread */ + sim_activate (uptr, chan_ctl_time); + } + else uptr->UCMD = 0; /* ctlr idle */ + return SCPE_OK; /* done */ + } + +if ((mt_op[cmd] & O_ATT) && /* op req att and */ + ((uptr->flags & UNIT_ATT) == 0)) { /* not attached? */ + sim_activate (uptr, mt_ctime); /* retry */ + return mt_stopioe? SCPE_UNATT: SCPE_OK; + } +if ((mt_op[cmd] & O_WRE) && /* write op and */ + sim_tape_wrp (uptr)) { /* write protected? */ + uptr->UST |= MTDV_WLE; /* set status */ + chan_uen (mt_dib.dva); /* unusual end */ + return SCPE_OK; + } + +r = SCPE_OK; +switch (cmd) { /* case on command */ + + case MCM_SFWR: /* space forward */ + if (r = sim_tape_sprecf (uptr, &tbc)) /* spc rec fwd, err? */ + r = mt_map_err (uptr, r); /* map error */ + break; + + case MCM_SBKR: /* space reverse */ + if (r = sim_tape_sprecr (uptr, &tbc)) /* spc rec rev, err? */ + r = mt_map_err (uptr, r); /* map error */ + break; + + case MCM_SFWF: /* space fwd file */ + while ((r = sim_tape_sprecf (uptr, &tbc)) == MTSE_OK) ; + if (r != MTSE_TMK) /* stopped by tmk? */ + r = mt_map_err (uptr, r); /* no, map error */ + else r = SCPE_OK; + break; + + case MCM_SBKF: /* space rev file */ + while ((r = sim_tape_sprecr (uptr, &tbc)) == MTSE_OK) ; + if (r != MTSE_TMK) /* stopped by tmk? */ + r = mt_map_err (uptr, r); /* no, map error */ + else r = SCPE_OK; + break; + + case MCM_WTM: /* write eof */ + if (r = sim_tape_wrtmk (uptr)) /* write tmk, err? */ + r = mt_map_err (uptr, r); /* map error */ + uptr->UST |= MTDV_EOF; /* set eof */ + break; + + case MCM_RWU: /* rewind unload */ + r = detach_unit (uptr); + break; + + case MCM_REW: /* rewind */ + case MCM_RWI: /* rewind and int */ + if (r = sim_tape_rewind (uptr)) /* rewind */ + r = mt_map_err (uptr, r); /* map error */ + mt_unit[un + MT_REW].UCMD = uptr->UCMD; /* copy command */ + sim_activate (uptr + MT_REW, mt_rwtime); /* sched compl */ + break; + + case MCM_READ: /* read */ + if (mt_blim == 0) { /* first read? */ + r = sim_tape_rdrecf (uptr, mt_xb, &mt_blim, MT_MAXFR); + if (r != MTSE_OK) { /* tape error? */ + r = mt_map_err (uptr, r); /* map error */ + break; + } + mt_bptr = 0; /* init rec ptr */ + } + c = mt_xb[mt_bptr++]; /* get char */ + st = chan_WrMemB (mt_dib.dva, c); /* write to memory */ + if (CHS_IFERR (st)) /* channel error? */ + return mt_chan_err (st); + if ((st != CHS_ZBC) && (mt_bptr != mt_blim)) { /* not done? */ + sim_activate (uptr, mt_time); /* continue thread */ + return SCPE_OK; + } + if (((st == CHS_ZBC) ^ (mt_bptr == mt_blim)) && /* length err? */ + chan_set_chf (mt_dib.dva, CHF_LNTE)) /* uend taken? */ + return SCPE_OK; /* finished */ + break; /* normal end */ + + case MCM_RDBK: /* read reverse */ + if (mt_blim == 0) { /* first read? */ + r = sim_tape_rdrecr (uptr, mt_xb, &mt_blim, MT_MAXFR); + if (r != MTSE_OK) { /* tape error? */ + r = mt_map_err (uptr, r); /* map error */ + break; + } + mt_bptr = mt_blim; /* init rec ptr */ + } + c = mt_xb[--mt_bptr]; /* get char */ + st = chan_WrMemBR (mt_dib.dva, c); /* write mem rev */ + if (CHS_IFERR (st)) /* channel error? */ + return mt_chan_err (st); + if ((st != CHS_ZBC) && (mt_bptr != 0)) { /* not done? */ + sim_activate (uptr, mt_time); /* continue thread */ + return SCPE_OK; + } + if (((st == CHS_ZBC) ^ (mt_bptr == 0)) && /* length err? */ + chan_set_chf (mt_dib.dva, CHF_LNTE)) /* uend taken? */ + return SCPE_OK; /* finished */ + break; /* normal end */ + + case MCM_WRITE: /* write */ + st = chan_RdMemB (mt_dib.dva, &c); /* read char */ + if (CHS_IFERR (st)) { /* channel error? */ + mt_flush_buf (uptr); /* flush buffer */ + return mt_chan_err (st); + } + mt_xb[mt_blim++] = c; /* store in buffer */ + if (st != CHS_ZBC) { /* end record? */ + sim_activate (uptr, mt_time); /* continue thread */ + return SCPE_OK; + } + r = mt_flush_buf (uptr); /* flush buffer */ + break; + } + +if (r != SCPE_OK) /* error? abort */ + return CHS_IFERR(r)? SCPE_OK: r; +uptr->UCMD = MCM_END; /* end state */ +sim_activate (uptr, mt_ctime); /* sched ctlr */ +return SCPE_OK; +} + +/* Rewind completion - set BOT, interrupt if desired */ + +t_stat mtr_svc (UNIT *uptr) +{ +uint32 un = uptr - mt_unit - MT_REW; + +mt_unit[un].UST |= MTDV_BOT; /* set BOT */ +if (uptr->UCMD == MCM_RWI) /* int wanted? */ + mt_set_rwi (un); /* interrupt */ +return SCPE_OK; +} + +t_stat mt_flush_buf (UNIT *uptr) +{ +t_stat st; + +if (mt_blim == 0) /* any output? */ + return SCPE_OK; +if (st = sim_tape_wrrecf (uptr, mt_xb, mt_blim)) /* write, err? */ + return mt_map_err (uptr, st); /* map error */ +return SCPE_OK; +} + +/* Map tape error status - returns chan error or SCP 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 */ + case MTSE_WRP: /* write protect */ + chan_set_chf (mt_dib.dva, CHF_XMME); + case MTSE_OK: /* no error */ + chan_uen (mt_dib.dva); /* uend */ + return SCPE_IERR; + + case MTSE_TMK: /* end of file */ + uptr->UST |= MTDV_EOF; /* set eof flag */ + chan_uen (mt_dib.dva); /* uend */ + return CHS_INACTV; + + case MTSE_IOERR: /* IO error */ + uptr->UST |= MTDV_DTE; /* set DTE flag */ + chan_set_chf (mt_dib.dva, CHF_XMDE); + chan_uen (mt_dib.dva); /* force uend */ + return SCPE_IOERR; + + case MTSE_INVRL: /* invalid rec lnt */ + uptr->UST |= MTDV_DTE; /* set DTE flag */ + chan_set_chf (mt_dib.dva, CHF_XMDE); + chan_uen (mt_dib.dva); /* force uend */ + return SCPE_MTRLNT; + + case MTSE_RECE: /* record in error */ + case MTSE_EOM: /* end of medium */ + uptr->UST |= MTDV_DTE; /* set DTE flag */ + return chan_set_chf (mt_dib.dva, CHF_XMDE); /* possible error */ + + case MTSE_BOT: /* reverse into BOT */ + uptr->UST |= MTDV_BOT; /* set BOT */ + chan_uen (mt_dib.dva); /* uend */ + return CHS_INACTV; + } /* end switch */ + +return SCPE_OK; +} + +/* MT status routine */ + +uint32 mt_tio_status (uint32 un) +{ +uint32 i, st; +UNIT *uptr = &mt_unit[un]; + +st = (uptr->flags & UNIT_ATT)? DVS_AUTO: 0; /* AUTO */ +if (sim_is_active (uptr) || /* unit busy */ + sim_is_active (uptr + MT_REW)) /* or rewinding? */ + st |= DVS_DBUSY; +for (i = 0; i < MT_NUMDR; i++) { /* loop thru units */ + if (sim_is_active (&mt_unit[i])) { /* active? */ + st |= (DVS_CBUSY | (CC2 << DVT_V_CC)); /* ctrl is busy */ + } + } +return st; +} + +uint32 mt_tdv_status (uint32 un) +{ +uint32 st; +UNIT *uptr = &mt_unit[un]; + +if (uptr->flags & UNIT_ATT) { /* attached? */ + st = uptr->UST; /* unit stat */ + if (sim_tape_eot (uptr)) /* at EOT? */ + st |= MTDV_EOT; + if (!sim_tape_wrp (uptr)) /* not wlock? */ + st |= MTDV_WRE; + } +else st = (CC2 << DVT_V_CC); +if (sim_is_active (uptr + MT_REW)) /* unit rewinding? */ + st |= (MTDV_REW | (CC2 << DVT_V_CC)); +return st; +} + + +/* Channel error */ + +t_stat mt_chan_err (uint32 st) +{ +chan_uen (mt_dib.dva); /* uend */ +if (st < CHS_ERR) + return st; +return SCPE_OK; +} + +/* Clear controller/device interrupt, return active unit */ + +int32 mt_clr_int (uint32 dva) +{ +int32 iu; + +if ((iu = chan_clr_chi (dva)) >= 0) { /* chan int? clear */ + if (mt_rwi != 0) /* dev ints? */ + chan_set_dvi (dva); /* set them */ + return iu; + } +for (iu = 0; iu < MT_NUMDR; iu++) { /* rewind int? */ + if (mt_rwi & (1u << iu)) { + mt_clr_rwi ((uint32) iu); + return (iu | MTAI_INT); + } + } +return 0; +} + +/* Set rewind interrupt */ + +void mt_set_rwi (uint32 un) +{ +mt_rwi |= (1u << un); +chan_set_dvi (mt_dib.dva); /* set INP */ +return; +} + +/* Clear rewind interrupt */ + +void mt_clr_rwi (uint32 un) +{ +mt_rwi &= ~(1u << un); /* clear */ +if (mt_rwi != 0) /* more? */ + chan_set_dvi (mt_dib.dva); +else if (chan_chk_chi (mt_dib.dva) < 0) /* any int? */ + chan_clr_chi (mt_dib.dva); /* clr INP */ +return; +} + +/* Reset routine */ + +t_stat mt_reset (DEVICE *dptr) +{ +uint32 i; + +for (i = 0; i < MT_NUMDR; i++) { + sim_cancel (&mt_unit[i]); /* stop unit */ + sim_cancel (&mt_unit[i + MT_REW]); /* stop rewind */ + mt_unit[i].UST = 0; + mt_unit[i].UCMD = 0; + } +mt_rwi = 0; +mt_bptr = 0; +mt_blim = 0; +chan_reset_dev (mt_dib.dva); /* clr int, active */ +for (i = 0; i < MT_MAXFR; i++) + mt_xb[i] = 0; +return SCPE_OK; +} + +/* Attach routine */ + +t_stat mt_attach (UNIT *uptr, char *cptr) +{ +t_stat r; + +r = sim_tape_attach (uptr, cptr); +if (r != SCPE_OK) return r; +uptr->UST = MTDV_BOT; +return r; +} + +/* Detach routine */ + +t_stat mt_detach (UNIT* uptr) +{ +uint32 un = uptr - mt_dev.units; + +uptr->UST = 0; +sim_cancel (uptr + MT_REW); +return sim_tape_detach (uptr); +} \ No newline at end of file diff --git a/sigma/sigma_pt.c b/sigma/sigma_pt.c new file mode 100644 index 00000000..f5507f6b --- /dev/null +++ b/sigma/sigma_pt.c @@ -0,0 +1,297 @@ +/* sigma_pt.c: Sigma 7060 paper tape reader/punch + + Copyright (c) 2007-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 7060 paper-tape reader/punch +*/ + +#include "sigma_io_defs.h" + +/* Device definitions */ + +#define PTR 0 +#define PTP 1 + +/* Device states */ + +#define PTS_INIT 0x101 +#define PTS_END 0x102 +#define PTS_WRITE 0x1 +#define PTS_READ 0x2 +#define PTS_READI 0x82 + +/* Device status */ + +#define PTDV_PMAN 0x20 +#define PTDV_RMAN 0x10 + +uint32 pt_cmd = 0; +uint32 ptr_nzc = 0; +uint32 ptr_stopioe = 1; +uint32 ptp_stopioe = 1; + +extern uint32 chan_ctl_time; +extern uint8 ascii_to_ebcdic[128]; +extern uint8 ebcdic_to_ascii[256]; + +uint32 pt_disp (uint32 op, uint32 dva, uint32 *dvst); +uint32 pt_tio_status (void); +uint32 pt_tdv_status (void); +t_stat pt_chan_err (uint32 st); +t_stat pt_svc (UNIT *uptr); +t_stat pt_reset (DEVICE *dptr); +t_stat pt_attach (UNIT *uptr, char *cptr); + +/* PT data structures + + pt_dev PT device descriptor + pt_unit PT unit descriptors + pt_reg PT register list + pt_mod PT modifiers list +*/ + +dib_t pt_dib = { DVA_PT, pt_disp }; + +UNIT pt_unit[] = { + { UDATA (&pt_svc, UNIT_ATTABLE+UNIT_SEQ+UNIT_ROABLE, 0), SERIAL_IN_WAIT }, + { UDATA (&pt_svc, UNIT_ATTABLE+UNIT_SEQ, 0), SERIAL_OUT_WAIT } + }; + +REG pt_reg[] = { + { HRDATA (CMD, pt_cmd, 9) }, + { FLDATA (NZC, ptr_nzc,0) }, + { 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) }, + { DRDATA (PPOS, pt_unit[PTP].pos, T_ADDR_W), PV_LEFT }, + { DRDATA (PTIME, pt_unit[PTP].wait, 24), REG_NZ + PV_LEFT }, + { FLDATA (PSTOP_IOE, ptp_stopioe, 0) }, + { HRDATA (DEVNO, pt_dib.dva, 12), REG_HRO }, + { NULL } + }; + +MTAB pt_mod[] = { + { MTAB_XTD|MTAB_VDV, 0, "CHAN", "CHAN", + &io_set_dvc, &io_show_dvc, NULL }, + { MTAB_XTD|MTAB_VDV, 0, "DVA", "DVA", + &io_set_dva, &io_show_dva, NULL }, + { MTAB_XTD|MTAB_VDV|MTAB_NMO, 0, "CSTATE", NULL, + NULL, &io_show_cst, NULL }, + { 0 } + }; + +DEVICE pt_dev = { + "PT", pt_unit, pt_reg, pt_mod, + 2, 10, 31, 1, 16, 8, + NULL, NULL, &pt_reset, + &io_boot, &pt_attach, NULL, + &pt_dib, DEV_DISABLE + }; + +/* Reader/punch: IO dispatch routine */ + +uint32 pt_disp (uint32 op, uint32 dva, uint32 *dvst) +{ +switch (op) { /* case on op */ + + case OP_SIO: /* start I/O */ + *dvst = pt_tio_status (); /* get status */ + if ((*dvst & DVS_DST) == 0) { /* idle? */ + pt_cmd = PTS_INIT; /* start dev thread */ + sim_activate (&pt_unit[PTR], chan_ctl_time); + } + break; + + case OP_TIO: /* test status */ + *dvst = pt_tio_status (); /* return status */ + break; + + case OP_TDV: /* test status */ + *dvst = pt_tdv_status (); /* return status */ + break; + + case OP_HIO: /* halt I/O */ + chan_clr_chi (pt_dib.dva); /* clr int*/ + *dvst = pt_tio_status (); /* get status */ + if ((*dvst & DVS_DST) != 0) { /* busy? */ + sim_cancel (&pt_unit[PTR]); /* stop dev thread */ + chan_uen (pt_dib.dva); /* uend */ + } + break; + + case OP_AIO: /* acknowledge int */ + chan_clr_chi (pt_dib.dva); /* clr int*/ + *dvst = 0; /* no status */ + break; + + default: + *dvst = 0; + return SCPE_IERR; + } + +return 0; +} + +/* Service routine */ + +t_stat pt_svc (UNIT *uptr) +{ +int32 c; +uint32 cmd; +uint32 st; + +switch (pt_cmd) { /* case on state */ + + case PTS_INIT: /* I/O init */ + st = chan_get_cmd (pt_dib.dva, &cmd); /* get command */ + if (CHS_IFERR (st)) /* channel error? */ + return pt_chan_err (st); + if ((cmd == PTS_WRITE) || /* valid command? */ + ((cmd & 0x7F) == PTS_READ)) + pt_cmd = cmd; /* next state */ + else pt_cmd = PTS_END; /* no, end state */ + sim_activate (uptr, chan_ctl_time); /* continue thread */ + break; + + case PTS_READ: + case PTS_READI: + sim_activate (uptr, uptr->wait); /* continue thread */ + if ((uptr->flags & UNIT_ATT) == 0) /* not attached? */ + return ptr_stopioe? SCPE_UNATT: SCPE_OK; + if ((c = getc (uptr->fileref)) == EOF) { /* read char */ + if (feof (uptr->fileref)) { /* end of file? */ + chan_set_chf (pt_dib.dva, CHF_LNTE); /* length error */ + pt_cmd = PTS_END; /* end state */ + break; + } + else { /* real error */ + perror ("PTR I/O error"); + clearerr (uptr->fileref); + chan_set_chf (pt_dib.dva, CHF_XMDE); /* data error */ + return pt_chan_err (SCPE_IOERR); /* force uend */ + } + } + uptr->pos = uptr->pos + 1; + if (c != 0) /* leader done? */ + ptr_nzc = 1; /* set flag */ + if ((pt_cmd == PTS_READI) || ptr_nzc) { + st = chan_WrMemB (pt_dib.dva, c); /* write to memory */ + if (CHS_IFERR (st)) /* channel error? */ + return pt_chan_err (st); + if (st == CHS_ZBC) /* bc == 0? */ + pt_cmd = PTS_END; /* end state */ + } + break; + + case PTS_WRITE: /* write */ + sim_activate (uptr, pt_unit[PTP].wait); /* continue thread */ + if ((pt_unit[PTP].flags & UNIT_ATT) == 0) /* not attached? */ + return ptp_stopioe? SCPE_UNATT: SCPE_OK; + st = chan_RdMemB (pt_dib.dva, &c); /* read from channel */ + if (CHS_IFERR (st)) /* channel error? */ + return pt_chan_err (st); + if (putc (c, pt_unit[PTP].fileref) == EOF) { + perror ("PTP I/O error"); + clearerr (pt_unit[PTP].fileref); + chan_set_chf (pt_dib.dva, CHF_XMDE); /* data error */ + return pt_chan_err (SCPE_IOERR); /* force uend */ + } + pt_unit[PTP].pos = pt_unit[PTP].pos + 1; + if (st == CHS_ZBC) /* bc == 0? */ + pt_cmd = PTS_END; /* end state */ + break; + + case PTS_END: /* command done */ + st = chan_end (pt_dib.dva); /* set channel end */ + if (CHS_IFERR (st)) /* channel error? */ + return pt_chan_err (st); + if (st == CHS_CCH) { /* command chain? */ + pt_cmd = PTS_INIT; /* restart thread */ + sim_activate (uptr, chan_ctl_time); + } + break; + } + +return SCPE_OK; +} + +/* PT status routine */ + +uint32 pt_tio_status (void) +{ +uint32 st; + +if (((pt_unit[PTR].flags & UNIT_ATT) == 0) || /* rdr not att? */ + ((pt_unit[PTP].flags & UNIT_ATT) == 0)) /* pun not att? */ + st = 0; +else st = DVS_AUTO; /* otherwise ok */ +if (sim_is_active (&pt_unit[PTR])) /* dev busy? */ + st |= (DVS_CBUSY | DVS_DBUSY | (CC2 << DVT_V_CC)); +return st; +} + +uint32 pt_tdv_status (void) +{ +uint32 st; + +st = 0; +if ((pt_unit[PTR].flags & UNIT_ATT) == 0) /* rdr not att? */ + st |= PTDV_RMAN; +if ((pt_unit[PTP].flags & UNIT_ATT) == 0) /* pun not att? */ + st |= PTDV_PMAN; +return st; +} + +/* Channel error */ + +t_stat pt_chan_err (uint32 st) +{ +sim_cancel (&pt_unit[PTR]); /* stop dev thread */ +chan_uen (pt_dib.dva); /* uend */ +if (st < CHS_ERR) + return st; +return SCPE_OK; +} + +/* Reset routine */ + +t_stat pt_reset (DEVICE *dptr) +{ +sim_cancel (&pt_unit[PTR]); /* stop dev thread */ +pt_cmd = 0; +chan_reset_dev (pt_dib.dva); /* clr int, active */ +return SCPE_OK; +} + +/* Attach routine */ + +t_stat pt_attach (UNIT *uptr, char *cptr) +{ +t_stat st; + +st = attach_unit (uptr, cptr); +if ((uptr == &pt_unit[PTR]) && (st == SCPE_OK)) + ptr_nzc = 0; +return st; +} \ No newline at end of file diff --git a/sigma/sigma_rad.c b/sigma/sigma_rad.c new file mode 100644 index 00000000..8ecdbd71 --- /dev/null +++ b/sigma/sigma_rad.c @@ -0,0 +1,532 @@ +/* sigma_rad.c: Sigma 7211/7212 or 7231/7232 fixed head disk simulator + + Copyright (c) 2007-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. + + rad 7211/7212 or 7231/7232 fixed head disk + + The RAD is a head-per-track disk. To minimize overhead, the entire RAD + is buffered in memory. + + Transfers are always done a sector at a time. +*/ + +#include "sigma_io_defs.h" +#include + +/* Constants */ + +#define RAD_7212 0 /* ctlr type */ +#define RAD_7232 1 +#define RAD_NUMDR 4 /* drives/ctlr */ +#define RAD_WDSC 256 /* words/sector */ +#define RAD_WDMASK (RAD_WDSC - 1) +#define RAD_SCTK1 82 /* sectors/track */ +#define RAD_SCTK3 12 +#define RAD_TKUN1 64 /* tracks/unit */ +#define RAD_TKUN3 512 +#define RAD_WDUNDF (RAD_WDSC*RAD_SCTK1*RAD_TKUN1) /* dflt words/unit */ +#define RAD_WDUN (RAD_WDSC*rad_tab[rad_model].sctk*rad_tab[rad_model].tkun) +#define RAD_N_WLK 16 /* num wlk switches */ + +/* Address bytes */ + +#define RADA_V_TK1 7 /* track offset */ +#define RADA_M_TK1 0xFF +#define RADA_V_SC1 0 /* sector offset */ +#define RADA_M_SC1 0x7F +#define RADA_V_TK3 4 +#define RADA_M_TK3 0x3FF +#define RADA_V_SC3 0 +#define RADA_M_SC3 0xF +#define RADA_GETTK(x) (((x) >> rad_tab[rad_model].tk_v) & rad_tab[rad_model].tk_m) +#define RADA_GETSC(x) (((x) >> rad_tab[rad_model].sc_v) & rad_tab[rad_model].sc_m) + +/* Address bad flag */ + +#define RADA_INV 0x80 + +/* Status byte 3 is current sector */ +/* Status byte 4 (7212 only) is failing sector */ + +#define RADS_NBY1 4 /* num status bytes */ +#define RADS_NBY3 3 + +/* Device state */ + +#define RADS_INIT 0x101 +#define RADS_END 0x102 +#define RADS_WRITE 0x01 +#define RADS_READ 0x02 +#define RADS_SEEK 0x03 +#define RADS_SENSE 0x04 +#define RADS_CHECK 0x05 +#define RADS_RDEES 0x12 + +/* Device status */ + +#define RADV_OVR 0x80 /* overrun - NI */ +#define RADV_BADS 0x20 /* bad sector */ +#define RADV_WPE 0x10 + +#define GET_PSC(x) ((int32) fmod (sim_gtime() / ((double) (x * RAD_WDSC)), \ + ((double) rad_tab[rad_model].sctk))) + +/* Model table */ + +typedef struct { + uint32 tk_v; /* track extract */ + uint32 tk_m; + uint32 sc_v; /* sector extract */ + uint32 sc_m; + uint32 sctk; /* sectors/track */ + uint32 tkun; /* tracks/unit */ + uint32 nbys; /* bytes of status */ + } rad_t; + +static rad_t rad_tab[] = { + { RADA_V_TK1, RADA_M_TK1, RADA_V_SC1, RADA_M_SC1, RAD_SCTK1, RAD_TKUN1, RADS_NBY1 }, + { RADA_V_TK3, RADA_M_TK3, RADA_V_SC3, RADA_M_SC3, RAD_SCTK3, RAD_TKUN3, RADS_NBY3 } + }; + +uint32 rad_model = RAD_7212; /* model */ +uint32 rad_cmd = 0; /* state */ +uint32 rad_flags = 0; /* status flags */ +uint32 rad_ad = 0; /* rad address */ +uint32 rad_wlk = 0; /* write lock */ +uint32 rad_time = 2; /* inter-word time */ + +extern uint32 chan_ctl_time; + +uint32 rad_disp (uint32 op, uint32 dva, uint32 *dvst); +uint32 rad_tio_status (uint32 un); +uint32 rad_tdv_status (uint32 un); +t_stat rad_chan_err (uint32 st); +t_stat rad_svc (UNIT *uptr); +t_stat rad_reset (DEVICE *dptr); +t_stat rad_settype (UNIT *uptr, int32 val, char *cptr, void *desc); +t_stat rad_showtype (FILE *st, UNIT *uptr, int32 val, void *desc); +t_bool rad_inv_ad (uint32 *da); +t_bool rad_inc_ad (void); +t_bool rad_end_sec (UNIT *uptr, uint32 lnt, uint32 exp, uint32 st); + +/* RAD data structures + + rad_dev RAD device descriptor + rad_unit RAD unit descriptor + rad_reg RAD register list +*/ + +dib_t rad_dib = { DVA_RAD, &rad_disp }; + +UNIT rad_unit[] = { + { UDATA (&rad_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_BUFABLE+ + UNIT_MUSTBUF+UNIT_DISABLE, RAD_WDUNDF) }, + { UDATA (&rad_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_BUFABLE+ + UNIT_MUSTBUF+UNIT_DISABLE+UNIT_DIS, RAD_WDUNDF) }, + { UDATA (&rad_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_BUFABLE+ + UNIT_MUSTBUF+UNIT_DISABLE+UNIT_DIS, RAD_WDUNDF) }, + { UDATA (&rad_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_BUFABLE+ + UNIT_MUSTBUF+UNIT_DISABLE+UNIT_DIS, RAD_WDUNDF) } + }; + +REG rad_reg[] = { + { HRDATA (CMD, rad_cmd, 9) }, + { HRDATA (FLAGS, rad_flags, 8) }, + { HRDATA (ADDR, rad_ad, 15) }, + { HRDATA (WLK, rad_wlk, RAD_N_WLK) }, + { DRDATA (TIME, rad_time, 24), PV_LEFT }, + { FLDATA (MODEL, rad_model, 0), REG_HRO }, + { HRDATA (DEVNO, rad_dib.dva, 12), REG_HRO }, + { NULL } + }; + +MTAB rad_mod[] = { + { MTAB_XTD | MTAB_VDV, RAD_7212, NULL, "7211", + &rad_settype, NULL, NULL }, + { MTAB_XTD | MTAB_VDV, RAD_7212, NULL, "7212", + &rad_settype, NULL, NULL }, + { MTAB_XTD | MTAB_VDV, RAD_7232, NULL, "7231", + &rad_settype, NULL, NULL }, + { MTAB_XTD | MTAB_VDV, RAD_7232, NULL, "7232", + &rad_settype, NULL, NULL }, + { MTAB_XTD | MTAB_VDV, 0, "TYPE", NULL, + NULL, &rad_showtype, NULL }, + { MTAB_XTD|MTAB_VDV, 0, "CHAN", "CHAN", + &io_set_dvc, &io_show_dvc, NULL }, + { MTAB_XTD|MTAB_VDV, 0, "DVA", "DVA", + &io_set_dva, &io_show_dva, NULL }, + { MTAB_XTD|MTAB_VDV|MTAB_NMO, 0, "CSTATE", NULL, + NULL, &io_show_cst, NULL }, + { 0 } + }; + +DEVICE rad_dev = { + "RAD", rad_unit, rad_reg, rad_mod, + RAD_NUMDR, 16, 21, 1, 16, 32, + NULL, NULL, &rad_reset, + &io_boot, NULL, NULL, + &rad_dib, DEV_DISABLE + }; + +/* RAD: IO dispatch routine */ + +uint32 rad_disp (uint32 op, uint32 dva, uint32 *dvst) +{ +uint32 i; +uint32 un = DVA_GETUNIT (dva); +UNIT *uptr; + +if ((un >= RAD_NUMDR) || /* inv unit num? */ + (rad_unit[un].flags & UNIT_DIS)) /* disabled unit? */ + return DVT_NODEV; +switch (op) { /* case on op */ + + case OP_SIO: /* start I/O */ + *dvst = rad_tio_status (un); /* get status */ + if ((*dvst & (DVS_CST|DVS_DST)) == 0) { /* ctrl + dev idle? */ + rad_cmd = RADS_INIT; /* start dev thread */ + sim_activate (&rad_unit[un], chan_ctl_time); + } + break; + + case OP_TIO: /* test status */ + *dvst = rad_tio_status (un); /* return status */ + break; + + case OP_TDV: /* test status */ + *dvst = rad_tdv_status (un); /* return status */ + break; + + case OP_HIO: /* halt I/O */ + chan_clr_chi (rad_dib.dva); /* clr int*/ + *dvst = rad_tio_status (un); /* get status */ + if ((*dvst & DVS_CST) != 0) { /* ctrl busy? */ + for (i = 0; i < RAD_NUMDR; i++) { /* find busy unit */ + uptr = &rad_unit[i]; + if (sim_is_active (uptr)) { /* active? */ + sim_cancel (uptr); /* stop */ + chan_uen (rad_dib.dva); /* uend */ + } /* end if active */ + } /* end for */ + } + break; + + case OP_AIO: /* acknowledge int */ + chan_clr_chi (rad_dib.dva); /* clr int */ + *dvst = rad_tdv_status (0); /* status like TDV */ + break; + + default: + *dvst = 0; + return SCPE_IERR; + } + +return 0; +} + +/* Unit service - this code assumes the entire disk is buffered */ + +t_stat rad_svc (UNIT *uptr) +{ +uint32 i, sc, da, cmd, wd, wd1, c[4], gp; +uint32 *fbuf = (uint32 *) uptr->filebuf; +uint32 st; +int32 t; + +switch (rad_cmd) { + + case RADS_INIT: /* init state */ + st = chan_get_cmd (rad_dib.dva, &cmd); /* get command */ + if (CHS_IFERR (st)) /* channel error? */ + return rad_chan_err (st); + if ((cmd == 0) || /* invalid cmd? */ + ((cmd > RADS_CHECK) && (cmd != RADS_RDEES))) { + chan_uen (rad_dib.dva); /* uend */ + return SCPE_OK; + } + rad_flags = 0; /* clear status */ + rad_cmd = cmd & 0x7; /* next state */ + if ((cmd == RADS_SEEK) || (cmd == RADS_SENSE)) /* seek or sense? */ + sim_activate (uptr, chan_ctl_time); /* schedule soon */ + else { /* data transfer */ + sc = RADA_GETSC (rad_ad); /* new sector */ + t = sc - GET_PSC (rad_time); /* delta to new */ + if (t < 0) /* wrap around? */ + t = t + rad_tab[rad_model].sctk; + sim_activate (uptr, t * rad_time * RAD_WDSC); /* schedule op */ + } + return SCPE_OK; + + case RADS_END: /* end state */ + st = chan_end (rad_dib.dva); /* set channel end */ + if (CHS_IFERR (st)) /* channel error? */ + return rad_chan_err (st); + if (st == CHS_CCH) { /* command chain? */ + rad_cmd = RADS_INIT; /* restart thread */ + sim_activate (uptr, chan_ctl_time); + } + return SCPE_OK; /* done */ + + case RADS_SEEK: /* seek */ + c[0] = c[1] = 0; + for (i = 0, st = 0; (i < 2) && (st != CHS_ZBC); i++) { + st = chan_RdMemB (rad_dib.dva, &c[i]); /* get byte */ + if (CHS_IFERR (st)) /* channel error? */ + return rad_chan_err (st); + } + rad_ad = ((c[0] & 0x7F) << 8) | c[1]; /* new address */ + if (((i != 2) || (st != CHS_ZBC)) && /* length error? */ + chan_set_chf (rad_dib.dva, CHF_LNTE)) /* care? */ + return SCPE_OK; + break; + + case RADS_SENSE: /* sense */ + c[0] = ((rad_ad >> 8) & 0x7F) | (rad_inv_ad (NULL)? RADA_INV: 0); + c[1] = rad_ad & 0xFF; /* address */ + c[2] = GET_PSC (rad_time); /* curr sector */ + c[3] = 0; + for (i = 0, st = 0; (i < rad_tab[rad_model].nbys) && (st != CHS_ZBC); i++) { + st = chan_WrMemB (rad_dib.dva, c[i]); /* store char */ + if (CHS_IFERR (st)) /* channel error? */ + return rad_chan_err (st); + } + if (((i != rad_tab[rad_model].nbys) || (st != CHS_ZBC)) && + chan_set_chf (rad_dib.dva, CHF_LNTE)) /* length error? */ + return SCPE_OK; + break; + + case RADS_WRITE: /* write */ + gp = (RADA_GETSC (rad_ad) * RAD_N_WLK) / /* write lock group */ + rad_tab[rad_model].tkun; + if ((rad_wlk >> gp) & 1) { /* write lock set? */ + rad_flags |= RADV_WPE; /* set status */ + chan_uen (rad_dib.dva); /* uend */ + return SCPE_OK; + } /* fall through */ + if (rad_inv_ad (&da)) { /* invalid addr? */ + chan_uen (rad_dib.dva); /* uend */ + return SCPE_OK; + } + for (i = 0, st = 0; i < RAD_WDSC; da++, i++) { /* write */ + if (st != CHS_ZBC) { /* chan active? */ + st = chan_RdMemW (rad_dib.dva, &wd); /* get data */ + if (CHS_IFERR (st)) { /* channel error? */ + rad_inc_ad (); /* da increments */ + return rad_chan_err (st); + } + } + else wd = 0; + fbuf[da] = wd; /* store in buffer */ + if (da >= uptr->hwmark) /* update length */ + uptr->hwmark = da + 1; + } + if (rad_end_sec (uptr, i, RAD_WDSC, st)) /* transfer done? */ + return SCPE_OK; + break; + +/* Must be done by bytes to get precise miscompare */ + + case RADS_CHECK: /* write check */ + if (rad_inv_ad (&da)) { /* invalid addr? */ + chan_uen (rad_dib.dva); /* uend */ + return SCPE_OK; + } + for (i = 0, st = 0; (i < (RAD_WDSC * 4)) && (st != CHS_ZBC); ) { + st = chan_RdMemB (rad_dib.dva, &wd); /* read sector */ + if (CHS_IFERR (st)) { /* channel error? */ + rad_inc_ad (); /* da increments */ + return rad_chan_err (st); + } + wd1 = (fbuf[da] >> (24 - ((i % 4) * 8))) & 0xFF; /* byte */ + if (wd != wd1) { /* check error? */ + rad_inc_ad (); /* da increments */ + chan_set_chf (rad_dib.dva, CHF_XMDE); /* set xmt err flag */ + chan_uen (rad_dib.dva); /* force uend */ + return SCPE_OK; + } + da = da + ((++i % 4) == 0); /* every 4th byte */ + } + if (rad_end_sec (uptr, i, RAD_WDSC * 4, st)) /* transfer done? */ + return SCPE_OK; + break; + + case RADS_READ: /* read */ + if (rad_inv_ad (&da)) { /* invalid addr? */ + chan_uen (rad_dib.dva); /* uend */ + return SCPE_OK; + } + for (i = 0, st = 0; (i < RAD_WDSC) && (st != CHS_ZBC); da++, i++) { + st = chan_WrMemW (rad_dib.dva, fbuf[da]); /* store in mem */ + if (CHS_IFERR (st)) { /* channel error? */ + rad_inc_ad (); /* da increments */ + return rad_chan_err (st); + } + } + if (rad_end_sec (uptr, i, RAD_WDSC, st)) /* transfer done? */ + return SCPE_OK; + break; + } + +rad_cmd = RADS_END; /* op done, next state */ +sim_activate (uptr, chan_ctl_time); +return SCPE_OK; +} + +/* Common read/write sector end routine + + case 1 - more to transfer, not end disk - reschedule, return TRUE + case 2 - more to transfer, end disk - uend, return TRUE + case 3 - transfer done, length error - uend, return TRUE + case 4 - transfer done, no length error - return FALSE (sched end state) +*/ + +t_bool rad_end_sec (UNIT *uptr, uint32 lnt, uint32 exp, uint32 st) +{ +if (st != CHS_ZBC) { /* end record? */ + if (rad_inc_ad ()) /* inc addr, ovf? */ + chan_uen (rad_dib.dva); /* uend */ + else sim_activate (uptr, rad_time * 16); /* no, next sector */ + return TRUE; + } +rad_inc_ad (); /* just incr addr */ +if ((lnt != exp) && /* length error? */ + chan_set_chf (rad_dib.dva, CHF_LNTE)) /* do we care? */ + return TRUE; +return FALSE; /* cmd done */ +} + +/* RAD status routine */ + +uint32 rad_tio_status (uint32 un) +{ +uint32 i, st; + +st = DVS_AUTO; /* flags */ +if (sim_is_active (&rad_unit[un])) /* active => busy */ + st |= DVS_DBUSY; +else if ((rad_unit[un].flags & UNIT_ATT) == 0) /* not att => offl */ + st |= DVS_DOFFL; +for (i = 0; i < RAD_NUMDR; i++) { /* loop thru units */ + if (sim_is_active (&rad_unit[i])) { /* active? */ + st |= (DVS_CBUSY |(CC2 << DVT_V_CC)); /* ctrl is busy */ + return st; + } + } +return st; +} + +uint32 rad_tdv_status (uint32 un) +{ +uint32 st; + +st = rad_flags; +if (rad_inv_ad (NULL)) /* bad address? */ + st |= RADV_BADS; +return st; +} + +/* Validate disk address */ + +t_bool rad_inv_ad (uint32 *da) +{ +uint32 tk = RADA_GETTK (rad_ad); +uint32 sc = RADA_GETSC (rad_ad); + +if ((tk >= rad_tab[rad_model].tkun) || /* bad sec or trk? */ + (sc >= rad_tab[rad_model].sctk)) { + return TRUE; + } +if (da) /* return word addr */ + *da = ((tk * rad_tab[rad_model].sctk) + sc) * RAD_WDSC; +return FALSE; +} + +/* Increment disk address */ + +t_bool rad_inc_ad (void) +{ +uint32 tk = RADA_GETTK (rad_ad); +uint32 sc = RADA_GETSC (rad_ad); + +sc = sc + 1; /* sector++ */ +if (sc >= rad_tab[rad_model].sctk) { /* overflow? */ + sc = 0; /* wrap sector */ + tk = tk + 1; /* track++ */ + } +rad_ad = ((tk << rad_tab[rad_model].tk_v) | /* rebuild rad_ad */ + (sc << rad_tab[rad_model].sc_v)); +if (tk >= rad_tab[rad_model].tkun) /* overflow? */ + return TRUE; +return FALSE; +} + +/* Channel error */ + +t_stat rad_chan_err (uint32 st) +{ +chan_uen (rad_dib.dva); /* uend */ +if (st < CHS_ERR) + return st; +return SCPE_OK; +} + +/* Reset routine */ + +t_stat rad_reset (DEVICE *dptr) +{ +uint32 i; + +for (i = 0; i < RAD_NUMDR; i++) + sim_cancel (&rad_unit[i]); /* stop dev thread */ +rad_cmd = 0; +rad_flags = 0; +rad_ad = 0; +chan_reset_dev (rad_dib.dva); /* clr int, active */ +return SCPE_OK; +} + +/* Set controller type */ + +t_stat rad_settype (UNIT *uptr, int32 val, char *cptr, void *desc) +{ +uint32 i; + +for (i = 0; i < RAD_NUMDR; i++) { /* all units unatt? */ + if (rad_unit[i].flags & UNIT_ATT) + return SCPE_ALATT; + } +rad_model = val; /* update model */ +rad_reset (&rad_dev); /* reset */ +for (i = 0; i < RAD_NUMDR; i++) /* update capacity */ + rad_unit[i].capac = RAD_WDUN; +return SCPE_OK; +} + +/* Show controller type */ + +t_stat rad_showtype (FILE *st, UNIT *uptr, int32 val, void *desc) +{ +fprintf (st, (rad_model == RAD_7212)? "7211/7212": "7231/7232"); +return SCPE_OK; +} diff --git a/sigma/sigma_rtc.c b/sigma/sigma_rtc.c new file mode 100644 index 00000000..34982fa3 --- /dev/null +++ b/sigma/sigma_rtc.c @@ -0,0 +1,267 @@ +/* sigma_rtc.c: Sigma clocks + + Copyright (c) 2007, 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. + + rtc clocks + + The real-time clock includes an internal scheduler for events which need to + be driven at multiples of the clock frequency, such as console and multiplexor + polling. Other devices can "register" with the clock module to receive service + callbacks at a timed interval. This replaces the standard SimH event queue + mechanism for real-time synchronous events. +*/ + +#include "sigma_io_defs.h" + +#define RTC_HZ_BASE 500 +#define RTC_TICKS_DFLT 500 + +/* Timed events data structures */ + +uint8 rtc_indx[RTC_NUM_EVNTS]; /* index into rtc_tab */ +uint8 rtc_cntr[RTC_NUM_EVNTS]; /* timer ticks left */ +uint8 rtc_xtra[RTC_NUM_EVNTS]; /* extra counter */ +UNIT *rtc_usrv[RTC_NUM_EVNTS]; /* unit servers */ + +/* Real-time clock counter frequencies */ + +uint16 rtc_tps[RTC_NUM_CNTRS] = { + RTC_HZ_OFF, RTC_HZ_OFF, RTC_HZ_500, RTC_HZ_500 + }; + +/* Frequency descriptors. The base clock runs at 500Hz. To get submultiples, + an event uses a tick counter. If the frequency is not an even submultiple, the + event can specify an "extra" counter. Every "extra" ticks of the event counter, + the event counter is increased by one. Thus, 60Hz counts as 8-8-9, providing + 3 clock ticks for every 25 base timer ticks. */ + +typedef struct { + uint32 hz; + uint32 cntr_reset; + uint32 xtra_reset; + } rtcdef_t; + +static rtcdef_t rtc_tab[RTC_NUM_HZ] = { + { 0, 0, 0 }, + { 500, 1, 0 }, + { 50, 10, 0 }, + { 60, 8, 3 }, + { 100, 5, 0 }, + { 2, 250, 0 }, + }; + +t_stat rtc_svc (UNIT *uptr); +t_stat rtc_cntr_svc (UNIT *uptr); +t_stat rtc_reset (DEVICE *dptr); +t_stat rtc_show_events (FILE *of, UNIT *uptr, int32 val, void *desc); + +/* Clock data structures + + rtc_dev RTC device descriptor + rtc_unit RTC unit + rtc_reg RTC register list +*/ + +UNIT rtc_unit = { UDATA (&rtc_svc, 0, 0), RTC_TICKS_DFLT }; + +UNIT rtc_cntr_unit[RTC_NUM_CNTRS] = { + { UDATA (&rtc_cntr_svc, 0, 0) }, + { UDATA (&rtc_cntr_svc, 0, 0) }, + { UDATA (&rtc_cntr_svc, 0, 0) }, + { UDATA (&rtc_cntr_svc, 0, 0) } + }; + +REG rtc_reg[] = { + { BRDATA (TPS, rtc_tps, 10, 10, RTC_NUM_CNTRS), REG_HRO }, + { BRDATA (INDX, rtc_indx, 10, 4, RTC_NUM_EVNTS), REG_HRO }, + { BRDATA (CNTR, rtc_cntr, 10, 6, RTC_NUM_EVNTS), REG_HRO }, + { BRDATA (XTRA, rtc_xtra, 10, 6, RTC_NUM_EVNTS), REG_HRO }, + { NULL } + }; + +MTAB rtc_mod[] = { + { MTAB_XTD|MTAB_VDV|MTAB_NMO, RTC_C1, "C1", "C1", + &rtc_set_tps, &rtc_show_tps, NULL }, + { MTAB_XTD|MTAB_VDV|MTAB_NMO, RTC_C2, "C2", "C2", + &rtc_set_tps, &rtc_show_tps, NULL }, + { MTAB_XTD|MTAB_VDV|MTAB_NMO, RTC_C3, "C3", "C3", + &rtc_set_tps, &rtc_show_tps, NULL }, + { MTAB_XTD|MTAB_VDV|MTAB_NMO, RTC_C4, "C4", NULL, + NULL, &rtc_show_tps, NULL }, + { MTAB_XTD|MTAB_VDV|MTAB_NMO, 0, "EVENTS", NULL, + NULL, &rtc_show_events, NULL }, + { 0 } + }; + +DEVICE rtc_dev = { + "RTC", &rtc_unit, rtc_reg, rtc_mod, + 1, 16, 8, 1, 16, 8, + NULL, NULL, &rtc_reset, + NULL, NULL, NULL + }; + +/* Master timer service routine */ + +t_stat rtc_svc (UNIT *uptr) +{ +uint32 i, idx; +int32 t; +t_stat st; + +t = sim_rtcn_calb (RTC_HZ_BASE, TMR_RTC); /* calibrate clock */ +sim_activate (uptr, t); /* reactivate unit */ +for (i = 0; i < RTC_NUM_EVNTS; i++) { /* loop thru events */ + if (rtc_cntr[i] != 0) { /* event active? */ + rtc_cntr[i] = rtc_cntr[i] - 1; /* decrement */ + if (rtc_cntr[i] == 0) { /* expired? */ + idx = rtc_indx[i]; + rtc_cntr[i] = rtc_tab[idx].cntr_reset; /* reset counter */ + if (rtc_xtra[i] != 0) { /* fudge factor? */ + rtc_xtra[i] = rtc_xtra[i] - 1; /* decr fudge cntr */ + if (rtc_xtra[i] == 0) { /* expired? */ + rtc_cntr[i]++; /* extra tick */ + rtc_xtra[i] = rtc_tab[idx].xtra_reset; /* reset fudge cntr */ + } /* end fudge = 0 */ + } /* end fudge active */ + if ((rtc_usrv[i] == NULL) || /* registered? */ + (rtc_usrv[i]->action == NULL)) + return SCPE_IERR; /* should be */ + st = rtc_usrv[i]->action (rtc_usrv[i]); /* callback */ + if (st != SCPE_OK) /* error */ + return st; + } /* end cntr = 0 */ + } /* end event active */ + } /* end event loop */ +return SCPE_OK; +} + +/* Callback for a system timer */ + +t_stat rtc_cntr_svc (UNIT *uptr) +{ +uint32 cn = uptr - rtc_cntr_unit; + +io_sclr_req (INTV (INTG_OVR, cn), 1); /* set cntr intr */ +return SCPE_OK; +} + +/* Register a timer */ + +t_stat rtc_register (uint32 tm, uint32 idx, UNIT *uptr) +{ +if ((tm >= RTC_NUM_EVNTS) || /* validate params */ + (idx >= RTC_NUM_HZ) || + (uptr == NULL) || + (uptr->action == NULL)) + return SCPE_IERR; +rtc_usrv[tm] = uptr; +rtc_indx[tm] = idx; +rtc_cntr[tm] = rtc_tab[idx].cntr_reset; /* init event */ +rtc_xtra[tm] = rtc_tab[idx].xtra_reset; +return SCPE_OK; +} + +/* Set timer ticks */ + +t_stat rtc_set_tps (UNIT *uptr, int32 val, char *cptr, void *desc) +{ +uint32 newval, i; +t_stat r; + +if (val >= RTC_NUM_EVNTS) /* validate params */ + return SCPE_IERR; +if (cptr == NULL) /* must have arg */ + return SCPE_ARG; +newval = get_uint (cptr, 10, 10000, &r); +if ((r != SCPE_OK) || /* error? */ + ((newval == 0) && (val >= 2))) /* can't turn off 3,4 */ + return SCPE_ARG; +for (i = 0; i < RTC_NUM_HZ; i++) { /* loop thru freqs */ + if (newval == rtc_tab[i].hz) { /* found freq? */ + rtc_tps[val] = i; + rtc_indx[val] = i; /* save event vals */ + rtc_cntr[val] = rtc_tab[i].cntr_reset; + rtc_xtra[val] = rtc_tab[i].xtra_reset; + return SCPE_OK; + } + } +return SCPE_ARG; +} + +/* Show timer ticks */ + +t_stat rtc_show_tps (FILE *of, UNIT *uptr, int32 val, void *desc) +{ +uint32 idx; + +if (val >= RTC_NUM_EVNTS) + return SCPE_IERR; +idx = rtc_tps[val]; /* ptr to clk defs */ +if (rtc_tab[idx].hz == 0) + fprintf (of, "off\n"); +else fprintf (of, "%dHz\n", rtc_tab[idx].hz); +return SCPE_OK; +} + + +/* Reset routine */ + +t_stat rtc_reset (DEVICE *dptr) +{ +uint32 i; + +sim_rtcn_init (rtc_unit.wait, TMR_RTC); /* init base clock */ +sim_activate_abs (&rtc_unit, rtc_unit.wait); /* activate unit */ + +for (i = 0; i < RTC_NUM_EVNTS; i++) { /* clear counters */ + if (i < RTC_NUM_CNTRS) { + rtc_cntr[i] = 0; + rtc_xtra[i] = 0; + rtc_indx[i] = 0; + rtc_usrv[i] = NULL; + if (rtc_register (i, rtc_tps[i], &rtc_cntr_unit[i]) != SCPE_OK) + return SCPE_IERR; + } + else if ((rtc_usrv[i] != NULL) && + (rtc_register (i, rtc_indx[i], rtc_usrv[i]) != SCPE_OK)) + return SCPE_IERR; + } +return SCPE_OK; +} + +/* Show events */ + +t_stat rtc_show_events (FILE *of, UNIT *uptr, int32 val, void *desc) +{ +uint32 i; + +fprintf (of, "Event Status Frequency Ticks Extra\n"); +for (i = 0; i < RTC_NUM_EVNTS; i++) { + if (rtc_cntr[i]) + fprintf (of, " %d on %3dHz %3d %d\n", + i, rtc_tab[rtc_indx[i]].hz, rtc_cntr[i], rtc_xtra[i]); + else fprintf (of, " %d off\n", i); + } +return SCPE_OK; +} \ No newline at end of file diff --git a/sigma/sigma_sys.c b/sigma/sigma_sys.c new file mode 100644 index 00000000..53aeb6dd --- /dev/null +++ b/sigma/sigma_sys.c @@ -0,0 +1,613 @@ +/* sigma_sys.c: Sigma system interface + + Copyright (c) 2007-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. +*/ + +#include "sigma_defs.h" +#include + +#define FMTASC(x) ((x) < 0x20)? "<%02X>": "%c", (x) + +extern DEVICE cpu_dev; +extern DEVICE map_dev; +extern DEVICE int_dev; +extern DEVICE chan_dev[]; +extern DEVICE rtc_dev; +extern DEVICE tt_dev; +extern DEVICE pt_dev; +extern DEVICE lp_dev; +extern DEVICE rad_dev; +extern DEVICE dk_dev; +extern DEVICE dp_dev[]; +extern DEVICE mt_dev; +extern DEVICE mux_dev, muxl_dev; +extern REG cpu_reg[]; +extern uint32 *M; +extern UNIT cpu_unit; + +t_stat fprint_sym_m (FILE *of, uint32 inst); +t_stat parse_sym_m (char *cptr, t_value *val); +void fprint_ebcdic (FILE *of, uint32 c); + +/* 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[] = "XDS Sigma"; + +REG *sim_PC = &cpu_reg[0]; + +int32 sim_emax = 1; + +DEVICE *sim_devices[] = { + &cpu_dev, + &map_dev, + &int_dev, + &chan_dev[0], + &chan_dev[1], + &chan_dev[2], + &chan_dev[3], + &chan_dev[4], + &chan_dev[5], + &chan_dev[6], + &chan_dev[7], + &rtc_dev, /* must be first */ + &tt_dev, + &pt_dev, + &lp_dev, + &mt_dev, + &rad_dev, + &dk_dev, + &dp_dev[0], + &dp_dev[1], + &mux_dev, + &muxl_dev, + NULL + }; + +const char *sim_stop_messages[] = { + "Unknown error", + "Invalid I/O configuration", + "Breakpoint", + "Address stop", + "Wait, interrupts off", + "Invalid PSD", + "Nested EXU's exceed limit", + "Undefined instruction", + "Illegal trap or interrupt instruction", + "Invalid interrupt vector", + "Nested traps", + }; + +/* Character conversion tables (from Sigma 7 manual) */ + +uint8 ascii_to_ebcdic[128] = { + 0x00, 0x01, 0x02, 0x03, 0x04, 0x09, 0x06, 0x07, /* 00 - 1F */ + 0x08, 0x05, 0x15, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, + 0x10, 0x11, 0x12, 0x13, 0x14, 0x0A, 0x16, 0x17, + 0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F, + 0x40, 0x5A, 0x7F, 0x7B, 0x5B, 0x6C, 0x50, 0x7D, /* 20 - 3F */ + 0x4D, 0x5D, 0x5C, 0x4E, 0x6B, 0x60, 0x4B, 0x61, + 0xF0, 0xF1, 0xF2, 0xF3, 0xF4, 0xF5, 0xF6, 0xF7, + 0xF8, 0xF9, 0x7A, 0x5E, 0x4C, 0x7E, 0x6E, 0x6F, + 0x7C, 0xC1, 0xC2, 0xC3, 0xC4, 0xC5, 0xC6, 0xC7, /* 40 - 5F */ + 0xC8, 0xC9, 0xD1, 0xD2, 0xD3, 0xD4, 0xD5, 0xD6, + 0xD7, 0xD8, 0xD9, 0xE2, 0xE3, 0xE4, 0xE5, 0xE6, + 0xE7, 0xE8, 0xE9, 0xB4, 0xB1, 0xB5, 0x6A, 0x6D, + 0x4A, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, /* 60- 7F */ + 0x88, 0x89, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, + 0x97, 0x98, 0x99, 0xA2, 0xA3, 0xA4, 0xA5, 0xA6, + 0xA7, 0xA8, 0xA9, 0xB2, 0x4F, 0xB3, 0x5F, 0xFF + }; + +uint8 ebcdic_to_ascii[256] = { + 0x00, 0x01, 0x02, 0x03, 0x04, 0x09, 0x06, 0x07, /* 00 - 1F */ + 0x08, 0x05, 0x15, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, + 0x10, 0x11, 0x12, 0x13, 0x14, 0x0A, 0x16, 0x17, + 0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 20 - 3F */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + ' ', 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 40 - 5F */ + 0x00, 0x00, '`', '.', '<', '(', '+', '|', + '&', 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, '!', '$', '*', ')', ';', '~', + '-', '/', 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 60 - 7F */ + 0x00, 0x00, '^', ',', '%', '_', '>', '?', + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, ':', '#', '@', '\'', '=', '"', + 0x00, 'a', 'b', 'c', 'd', 'e', 'f', 'g', /* 80 - 9F */ + 'h', 'i', 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 'j', 'k', 'l', 'm', 'n', 'o', 'p', + 'q', 'r', 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 's', 't', 'u', 'v', 'w', 'x', /* A0 - BF */ + 'y', 'z', 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, '\\', '{', '}', '[', ']', 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 'A', 'B', 'C', 'D', 'E', 'F', 'G', /* C0 - DF */ + 'H', 'I', 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 'J', 'K', 'L', 'M', 'N', 'O', 'P', + 'Q', 'R', 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 'S', 'T', 'U', 'V', 'W', 'X', /* E0 - FF */ + 'Y', 'Z', 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + '0', '1', '2', '3', '4', '5', '6', '7', + '8', '9', 0x00, 0x00, 0x00, 0x00, 0x00, 0x7F, + }; + +/* Binary loader */ + +t_stat sim_load (FILE *fileref, char *cptr, char *fnam, int flag) +{ +return SCPE_NOFNC; +} + +/* Symbol and format tables */ + +#define IC_V_CL 17 /* class */ +#define IC_M_CL 0x1F +#define IC_V_RN 16 /* takes rn */ +#define IC_RN (1u << IC_V_RN) +#define IC_V_IND 15 /* takes ind */ +#define IC_IND (1u << IC_V_IND) +#define IC_V_XR 13 /* takes xr */ +#define IC_M_XR 0x3 +#define IC_NONE 0 +#define IC_XR 1 +#define IC_CTL 2 +#define IC_V_AW 7 /* addr width */ +#define IC_M_AW 0x3F +#define IC_V_AP 2 /* addr position */ +#define IC_M_AP 0x1F +#define IC_V_SGN 1 /* sign allowed */ +#define IC_SGN (1u << IC_V_SGN) +#define IC_V_AOP 0 /* addr optional */ +#define IC_AOP (1u << IC_V_AOP) + +#define ID1_07 0 /* decode 1-7 */ +#define ID1_11 1 /* decode 1-11 */ +#define IDSHFT 2 /* shift */ +#define IDSHFF 3 /* shift floating */ +#define IDMMCX 4 /* MMC ext */ + +#define I_C(c,r,i,w,s,x,sn,ao) \ + (((c) << IC_V_CL) | ((r) << IC_V_RN) | ((i) << IC_V_IND)|\ + ((w) << IC_V_AW) | ((s) << IC_V_AP) | ((x) << IC_V_XR) |\ + ((sn) << IC_V_SGN) | ((ao) << IC_V_AOP)) + +/* decode R I wd ps x sn ao */ +#define IC_MRF I_C(ID1_07,1,1,17, 0,1, 0, 0) /* mem ref */ +#define IC_IMM I_C(ID1_07,1,0,20, 0,0, 1, 0) /* immediate */ +#define IC_LCFI I_C(ID1_07,0,0, 8, 0,2, 0, 0) /* LCFI */ +#define IC_LFI I_C(ID1_11,0,0, 4, 0,0, 0, 0) /* LFI */ +#define IC_LCI I_C(ID1_11,0,0, 4, 4,0, 0, 0) /* LCI */ +#define IC_SHFT I_C(IDSHFT,1,0, 7, 0,1, 1, 0) /* shift */ +#define IC_SHFF I_C(IDSHFF,1,0, 7, 0,1, 1, 0) /* floating shift */ +#define IC_MNOR I_C(ID1_07,0,1,17, 0,1, 0, 0) /* mem ref, no reg */ +#define IC_MNOX I_C(ID1_11,0,1,17, 0,1, 0, 0) /* mef ref ext */ +#define IC_NOP I_C(ID1_07,1,0, 0, 0,0, 0, 0) /* no operand */ +#define IC_NOPX I_C(ID1_11,1,0, 0, 0,0, 0, 0) /* no operand ext */ +#define IC_MMC I_C(ID1_07,1,1, 3,17,0, 0, 0) /* MMC */ +#define IC_MMCX I_C(IDMMCX,1,0, 0, 0,0, 0, 0) /* MMC extended */ +#define IC_MNRI I_C(ID1_11,0,0, 0, 0,0, 0, 0) /* no operands */ +#define IC_MNRO I_C(ID1_07,0,1,17, 0,1, 0, 1) /* mem ref, addr opt */ + +#define IC_GETCL(x) (((x) >> IC_V_CL) & IC_M_CL) +#define IC_GETXR(x) (((x) >> IC_V_XR) & IC_M_XR) +#define IC_GETAW(x) (((x) >> IC_V_AW) & IC_M_AW) +#define IC_GETAP(x) (((x) >> IC_V_AP) & IC_M_AP) + +static const uint32 masks[] = { + 0x7F000000, 0x7FF00000, 0x7F000700, 0x7F000100, + 0x7F0E0000 + }; + +/* Opcode tables - extended mnemonics must precede standard mnemonics */ + +static const uint32 opc_val[] = { + 0x02100000, IC_LFI, 0x02200000, IC_LCI, 0x70100000, IC_MNOX, 0x70200000, IC_MNOX, + 0x25000000, IC_SHFT, 0x25000100, IC_SHFT, 0x25000200, IC_SHFT, 0x25000000, IC_SHFT, + 0x25000400, IC_SHFT, 0x25000500, IC_SHFT, 0x25000600, IC_SHFT, 0x25000700, IC_SHFT, + 0x24000000, IC_SHFT, 0x24000100, IC_SHFT, + 0x68000000, IC_MNOX, 0x68100000, IC_MNOX, 0x68200000, IC_MNOX, 0x68300000, IC_MNOX, + 0x68400000, IC_MNOX, 0x68800000, IC_MNOX, + 0x69000000, IC_MNOX, 0x69100000, IC_MNOX, 0x69200000, IC_MNOX, 0x69300000, IC_MNOX, + 0x69400000, IC_MNOX, 0x69800000, IC_MNOX, + 0x6F020000, IC_MMCX, 0x6F040000, IC_MMCX, 0x6F060000, IC_MMCX, 0x6F080000, IC_MMCX, + 0x6F080000, IC_MMCX, 0x02000000, IC_MNRI, + + 0x02000000, IC_LCFI, + 0x04000000, IC_MRF, 0x05000000, IC_MRF, 0x06000000, IC_MRF, 0x07000000, IC_MRF, + 0x08000000, IC_MRF, 0x09000000, IC_MRF, 0x0A000000, IC_MRF, 0x0B000000, IC_MRF, + 0x0C000000, IC_MRF, 0x0D000000, IC_NOP, 0x0E000000, IC_MRF, 0x0F000000, IC_MRF, + 0x10000000, IC_MRF, 0x11000000, IC_MRF, 0x12000000, IC_MRF, 0x13000000, IC_MRF, + 0x15000000, IC_MRF, + 0x18000000, IC_MRF, 0x19000000, IC_MRF, 0x1A000000, IC_MRF, 0x1B000000, IC_MRF, + 0x1C000000, IC_MRF, 0x1D000000, IC_MRF, 0x1E000000, IC_MRF, 0x1F000000, IC_MRF, + 0x20000000, IC_IMM, 0x21000000, IC_IMM, 0x22000000, IC_IMM, 0x23000000, IC_IMM, + 0x24000000, IC_MRF, 0x25000000, IC_MRF, 0x26000000, IC_MRF, + 0x28000000, IC_MRF, 0x29000000, IC_MRF, 0x2A000000, IC_MRF, 0x2B000000, IC_MRF, + 0x2C000000, IC_MRF, 0x2D000000, IC_MRF, 0x2E000000, IC_MNRO, 0x2F000000, IC_MRF, + 0x30000000, IC_MRF, 0x31000000, IC_MRF, 0x32000000, IC_MRF, 0x33000000, IC_MRF, + 0x34000000, IC_MRF, 0x35000000, IC_MRF, 0x36000000, IC_MRF, 0x37000000, IC_MRF, + 0x38000000, IC_MRF, 0x39000000, IC_MRF, 0x3A000000, IC_MRF, 0x3B000000, IC_MRF, + 0x3C000000, IC_MRF, 0x3D000000, IC_MRF, 0x3E000000, IC_MRF, 0x3F000000, IC_MRF, + 0x40000000, IC_IMM, 0x41000000, IC_IMM, + 0x44000000, IC_MRF, 0x45000000, IC_MRF, 0x46000000, IC_MRF, 0x47000000, IC_MRF, + 0x48000000, IC_MRF, 0x49000000, IC_MRF, 0x4A000000, IC_MRF, 0x4B000000, IC_MRF, + 0x4C000000, IC_MRF, 0x4D000000, IC_MRF, 0x4E000000, IC_MRF, 0x4F000000, IC_MRF, + 0x50000000, IC_MRF, 0x51000000, IC_MRF, 0x52000000, IC_MRF, 0x53000000, IC_MRF, + 0x55000000, IC_MRF, 0x56000000, IC_MRF, 0x57000000, IC_MRF, + 0x58000000, IC_MRF, 0x5A000000, IC_MRF, 0x5B000000, IC_MRF, + + 0x60000000, IC_IMM, 0x61000000, IC_IMM, 0x63000000, IC_IMM, + 0x64000000, IC_MRF, 0x65000000, IC_MRF, 0x66000000, IC_MRF, 0x67000000, IC_MNOR, + 0x68000000, IC_MRF, 0x69000000, IC_MRF, 0x6A000000, IC_MRF, 0x6B000000, IC_MRF, + 0x6C000000, IC_MRF, 0x6D000000, IC_MRF, 0x6E000000, IC_MRF, 0x6F000000, IC_MMC, + 0x70000000, IC_MRF, 0x71000000, IC_MRF, 0x72000000, IC_MRF, 0x73000000, IC_MRF, + 0x74000000, IC_MNOR, 0x75000000, IC_MRF, 0x76000000, IC_MRF, 0x77000000, IC_MRF, + 0x78000000, IC_MRF, 0x79000000, IC_MRF, 0x7A000000, IC_MRF, 0x7B000000, IC_MRF, + 0x7C000000, IC_MNOR, 0x7D000000, IC_MRF, 0x7E000000, IC_MRF, 0x7F000000, IC_MRF, + 0xFFFFFFFF, 0 + }; + +static const char *opcode[] = { + "LFI", "LCI", "LF", "LC", /* extended mmenomics */ + "SLS", "SLD", "SCS", "SCD", + "SAS", "SAD", "SSS", "SSD", + "SFS", "SFL", + "B", "BGE", "BLE", "BE", + "BNOV", "BNC", + "BNVR", "BL", "BG", "BNE", + "BOV", "BC", + "LLOCKS", "LPC", "LLOCKSE", "LMAP", + "LMAPRE", "NOP", + + "LCFI", /* 00 */ + "CAL1", "CAL2", "CAL3", "CAL4", + "PLW", "PSW", "PLM", "PSM", + "PLS", "PSS", "LPSD", "XPSD", + "AD", "CD", "LD", "MSP", /* 10 */ + "STD", + "SD", "CLM", "LCD", "LAD", + "FSL", "FAL", "FDL", "FML", + "AI", "CI", "LI", "MI", /* 20 */ + "SF", "S", "LAS", + "CVS", "CVA", "LM", "STM", + "LRA", "LMS", "WAIT", "LRP", + "AW", "CW", "LW", "MTW", /* 30 */ + "LVAW", "STW", "DW", "MW", + "SW", "CLR", "LCW", "LAW", + "FSS", "FAS", "FDS", "FMS", + "TTBS", "TBS", /* 40 */ + "ANLZ", "CS", "XW", "STS", + "EOR", "OR", "LS", "AND", + "SIO", "TIO", "TDV", "HIO", + "AH", "CH", "LH", "MTH", /* 50 */ + "STH", "DH", "MH", + "SH", "LCH", "LAH", + + "CBS", "MBS", "EBS", /* 60 */ + "BDR", "BIR", "AWM", "EXU", + "BCR", "BCS", "BAL", "INT", + "RD", "WD", "AIO", "MMC", + "LCF", "CB", "LB", "MTB", /* 70 */ + "STCF", "STB", "PACK", "UNPK", + "DS", "DA", "DD", "DM", + "DSA", "DC", "DL", "DST", + NULL + }; + +/* 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 inst, sc, rdx, c; +DEVICE *dptr; + +inst = val[0]; /* get inst */ +if (uptr == NULL) /* anon = CPU */ + uptr = &cpu_unit; +else if (uptr != &cpu_unit) /* CPU only */ + return SCPE_ARG; +dptr = find_dev_from_unit (uptr); /* find dev */ +if (dptr == NULL) + return SCPE_IERR; +if (sw & SWMASK ('D')) /* get radix */ + rdx = 10; +else if (sw & SWMASK ('O')) + rdx = 8; +else if (sw & SWMASK ('X')) + rdx = 16; +else rdx = dptr->dradix; + +if (sw & SWMASK ('C')) { /* char format? */ + for (sc = 0; sc < 32; sc = sc + 8) { /* print string */ + c = (inst >> (24 - sc)) & BMASK; + if (sw & SWMASK ('A')) + fprintf (of, FMTASC (c & 0x7F)); + else fprint_ebcdic (of, c); + } + return 0; /* return # chars */ + } +if (sw & SWMASK ('A')) { /* ASCII? */ + sc = 24 - ((addr & 0x3) * 8); /* shift count */ + c = (inst >> sc) & 0x7F; + fprintf (of, "%c", FMTASC (c)); + return 0; + } +if (sw & SWMASK ('E')) { /* EBCDIC? */ + sc = 24 - ((addr & 0x3) * 8); /* shift count */ + c = (inst >> sc) & BMASK; + fprint_ebcdic (of, c); + return 0; + } +if (sw & SWMASK ('B')) { /* byte? */ + sc = 24 - ((addr & 0x3) * 8); /* shift count */ + c = (inst >> sc) & BMASK; + fprintf (of, "%02X", c); + return 0; + } +if (sw & SWMASK ('H')) { /* halfword? */ + c = ((addr & 1)? inst: inst >> 16) & HMASK; + fprintf (of, "%04X", c); + return 0; + } +if ((sw & SWMASK ('M')) && /* inst format? */ + !fprint_sym_m (of, inst)) /* decode inst */ + return 0; + +fprint_val (of, inst, rdx, 32, PV_RZRO); +return 0; +} + +/* Instruction decode */ + +t_stat fprint_sym_m (FILE *of, uint32 inst) +{ +uint32 i, j; + +for (i = 0; opc_val[i] < 0xFFFFFFFF; i = i + 2) { /* loop thru ops */ + j = IC_GETCL (opc_val[i + 1]); /* get class */ + if (opc_val[i] == (inst & masks[j])) { /* match? */ + uint32 fl = opc_val[i + 1]; /* get format */ + uint32 aw = IC_GETAW (fl); + uint32 ap = IC_GETAP (fl); + uint32 xr = IC_GETXR (fl); + uint32 rn = I_GETRN (inst); /* get fields */ + uint32 xn = I_GETXR (inst); + uint32 mask = (1u << aw) - 1; + uint32 ad = (inst >> ap) & mask; + + fprintf (of, "%s", opcode[i >> 1]); /* opcode */ + if (fl & IC_RN) /* rn? */ + fprintf (of, ",%d", rn); + if (TST_IND (inst) || aw || xr) { /* anything else? */ + fputs (TST_IND (inst)? " *": " ", of); /* space{*} */ + if (aw) { /* any value? */ + if ((fl & IC_SGN) && /* signed and */ + (ad & (1u << (aw - 1)))) /* negative? */ + fprintf (of, "-%X", (mask + 1) - ad); + else fprintf (of, "%X", ad); + if ((xr == IC_XR) && xn) /* any index? */ + fprintf (of, ",%d", xn); + else if (xr == IC_CTL) /* or control? */ + fprintf (of, ",%X", rn); + } + } + return SCPE_OK; + } + } +return SCPE_ARG; +} + +void fprint_ebcdic (FILE *of, uint32 c) +{ +uint32 cv = ebcdic_to_ascii[c]; +if ((cv < 0040) || (cv >= 0177)) + fprintf (of, "<%02X>", c); +else fputc (cv, of); +return; +} + +/* 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) +{ +t_value num; +uint32 i, sc, rdx, c; +t_stat r; +DEVICE *dptr; + +if (uptr == NULL) /* anon = CPU */ + uptr = &cpu_unit; +else if (uptr != &cpu_unit) /* CPU only */ + return SCPE_ARG; +dptr = find_dev_from_unit (uptr); /* find dev */ +if (dptr == NULL) + return SCPE_IERR; +if (sw & SWMASK ('D')) /* get radix */ + rdx = 10; +else if (sw & SWMASK ('O')) + rdx = 8; +else if (sw & SWMASK ('X')) + rdx = 16; +else rdx = dptr->dradix; + +if ((sw & SWMASK ('C')) || ((*cptr == '"') && cptr++)) { /* chars? */ + if (cptr[0] == 0) /* must have 1 char */ + return SCPE_ARG; + for (i = 0; i < 4; i++) { + if (cptr[i] == 0) + break; + sc = 24 - (i * 8); + c = (sw & SWMASK ('A'))? + cptr[i] & 0x7F: + ascii_to_ebcdic[cptr[i]]; + val[0] = (val[0] & ~(BMASK << sc)) | (c << sc); + } + return 0; + } +if ((sw & SWMASK ('A')) || ((*cptr == '#') && cptr++)) { /* ASCII char? */ + if (cptr[0] == 0) /* must have 1 char */ + return SCPE_ARG; + sc = 24 - (addr & 0x3) * 8; /* shift count */ + val[0] = (val[0] & ~(BMASK << sc)) | (cptr[0] << sc); + return 0; + } +if ((sw & SWMASK ('E')) || ((*cptr == '\'') && cptr++)) { /* EBCDIC char? */ + if (cptr[0] == 0) /* must have 1 char */ + return SCPE_ARG; + sc = 24 - (addr & 0x3) * 8; /* shift count */ + val[0] = (val[0] & ~(BMASK << sc)) | (ascii_to_ebcdic[cptr[0]] << sc); + return 0; + } +if (sw & SWMASK ('B')) { /* byte? */ + num = get_uint (cptr, rdx, BMASK, &r); /* get byte */ + if (r != SCPE_OK) + return SCPE_ARG; + sc = 24 - (addr & 0x3) * 8; /* shift count */ + val[0] = (val[0] & ~(BMASK << sc)) | (num << sc); + return 0; + } +if (sw & SWMASK ('H')) { /* halfword? */ + num = get_uint (cptr, rdx, HMASK, &r); /* get half word */ + if (r != SCPE_OK) + return SCPE_ARG; + sc = addr & 1? 0: 16; + val[0] = (val[0] & ~(HMASK << sc)) | (num << sc); + return 0; + } +if (!parse_sym_m (cptr, val)) + return 0; + +val[0] = get_uint (cptr, rdx, WMASK, &r); /* get number */ +if (r != SCPE_OK) + return r; +return 0; +} + +t_stat parse_sym_m (char *cptr, t_value *val) +{ +uint32 i, sgn; +t_stat r; +char *sep; +char gbuf[CBUFSIZE]; + +cptr = get_glyph (cptr, gbuf, 0); /* get opcode+reg*/ +if (sep = strchr (gbuf, ',')) /* , in middle? */ + *sep++ = 0; /* split strings */ +for (i = 0; opcode[i] != NULL; i++) { /* loop thru ops */ + if (strcmp (opcode[i], gbuf) == 0) { /* string match? */ + uint32 rn, xn, ad; + uint32 k = i << 1; /* index to opval */ + uint32 fl = opc_val[k + 1]; + uint32 aw = IC_GETAW (fl); + uint32 ap = IC_GETAP (fl); + uint32 xr = IC_GETXR (fl); + uint32 mask = (1u << aw) - 1; + + val[0] = opc_val[k]; + if (fl & IC_RN) { /* need rn? */ + if (sep == NULL) + return SCPE_ARG; + rn = get_uint (sep, 10, INST_M_RN, &r); + if (r != SCPE_OK) + return SCPE_ARG; + val[0] |= rn << INST_V_RN; + } + else if (sep) /* rn & not wanted */ + return SCPE_ARG; + if (aw) { /* more? */ + if (*cptr == 0) + return (fl & IC_AOP)? SCPE_OK: SCPE_ARG; + if ((fl & IC_IND) && (*cptr == '*')) { /* indirect? */ + val[0] |= INST_IND; + cptr++; + } + if ((fl & IC_SGN) && /* signed val? */ + strchr ("+-", *cptr) && /* with sign? */ + (*cptr++ == '-')) /* and minus? */ + sgn = 1; + else sgn = 0; /* else + */ + cptr = get_glyph (cptr, gbuf, 0); /* get rest */ + if (sep = strchr (gbuf, ',')) /* , in middle? */ + *sep++ = 0; /* split strings */ + ad = get_uint (gbuf, 16, mask, &r); + if (r != SCPE_OK) + return r; + if (sgn && ad) /* negative, nz? */ + ad = (mask + 1) - ad; /* complement */ + val[0] |= (ad << ap); + if ((xr == IC_XR) && sep) { /* index? */ + xn = get_uint (sep, 10, 7, &r); + if (r != SCPE_OK) + return r; + val[0] |= (xn << INST_V_XR); + } + else if (xr == IC_CTL) { /* control? */ + if (sep == NULL) + return SCPE_ARG; + xn = get_uint (gbuf, 16, INST_M_RN, &r); + if (r != SCPE_OK) + return r; + val[0] |= (xn << INST_V_RN); + } + else if (sep) + return SCPE_ARG; + } + if (*cptr != 0) + return SCPE_ARG; + return SCPE_OK; + } + } +return SCPE_ARG; +} diff --git a/sigma/sigma_tt.c b/sigma/sigma_tt.c new file mode 100644 index 00000000..97d32d3c --- /dev/null +++ b/sigma/sigma_tt.c @@ -0,0 +1,331 @@ +/* sigma_tt.c: Sigma 7012 console teletype + + Copyright (c) 2007-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. + + tt 7012 console + + The 7012 has the following special cases on input and output: + + CR input, mapped to NEWLINE and echoes CR-LF + ^H input, mapped to EOM and not echoed + HT input or output, simulates tabbing with fixed 8 character stops +*/ + +#include "sigma_io_defs.h" +#include + +/* Device definitions */ + +#define TTI 0 +#define TTO 1 + +/* Device states */ + +#define TTS_IDLE 0x0 +#define TTS_INIT 0x1 +#define TTS_END 0x2 +#define TTS_WRITE 0x5 +#define TTS_READ 0x6 +#define TTS_READS 0x86 + +/* EBCDIC special characters for input */ + +#define E_EOM 0x08 /* end of medium */ +#define E_HT 0x05 /* tab */ +#define E_NL 0x15 /* new line */ + +uint32 tt_cmd = TTS_IDLE; +uint32 tti_tps = RTC_HZ_100; +uint32 tti_panel = 020; /* panel int char */ +uint32 tto_pos = 0; /* char position */ + +extern uint32 chan_ctl_time; +extern uint8 ascii_to_ebcdic[128]; +extern uint8 ebcdic_to_ascii[256]; + +uint32 tt_disp (uint32 op, uint32 dva, uint32 *dvst); +uint32 tt_tio_status (void); +t_stat tt_chan_err (uint32 st); +t_stat tti_rtc_svc (uint32 tm); +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); +void tto_echo (int32 c); + +extern t_stat io_set_pint (void); + +/* TT data structures + + tt_dev TT device descriptor + tt_unit TT unit descriptors + tt_reg TT register list + tt_mod TT modifiers list +*/ + +dib_t tt_dib = { DVA_TT, tt_disp }; + +UNIT tt_unit[] = { + { UDATA (&tti_svc, TT_MODE_UC, 0), 0 }, + { UDATA (&tto_svc, TT_MODE_UC, 0), SERIAL_OUT_WAIT } + }; + +REG tt_reg[] = { + { HRDATA (CMD, tt_cmd, 9) }, + { DRDATA (KPOS, tt_unit[TTI].pos, T_ADDR_W), PV_LEFT }, + { DRDATA (KTPS, tti_tps, 8), REG_HRO }, + { DRDATA (TPOS, tt_unit[TTO].pos, T_ADDR_W), PV_LEFT }, + { DRDATA (TTIME, tt_unit[TTO].wait, 24), REG_NZ + PV_LEFT }, + { HRDATA (PANEL, tti_panel, 8) }, + { HRDATA (DEVNO, tt_dib.dva, 12), REG_HRO }, + { NULL } + }; + +MTAB tt_mod[] = { + { TT_MODE, TT_MODE_UC, "UC", "UC", &tt_set_mode }, + { TT_MODE, TT_MODE_7P, "7p", "7P", &tt_set_mode }, + { MTAB_XTD|MTAB_VDV|MTAB_NMO, RTC_TTI, "POLL", "POLL", + &rtc_set_tps, &rtc_show_tps, (void *) &tti_tps }, + { MTAB_XTD|MTAB_VDV, 0, "CHAN", "CHAN", + &io_set_dvc, &io_show_dvc, NULL }, + { MTAB_XTD|MTAB_VDV, 0, "DVA", "DVA", + &io_set_dva, &io_show_dva, NULL }, + { MTAB_XTD|MTAB_VDV|MTAB_NMO, 0, "CSTATE", NULL, + NULL, &io_show_cst, NULL }, + { 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 dispatch routine */ + +uint32 tt_disp (uint32 op, uint32 dva, uint32 *dvst) +{ +switch (op) { /* case on op */ + + case OP_SIO: /* start I/O */ + *dvst = tt_tio_status (); /* get status */ + if ((*dvst & DVS_DST) == 0) { /* idle? */ + tt_cmd = TTS_INIT; /* start dev thread */ + sim_activate (&tt_unit[TTO], chan_ctl_time); + } + break; + + case OP_TIO: /* test status */ + *dvst = tt_tio_status (); /* return status */ + break; + + case OP_HIO: /* halt I/O */ + chan_clr_chi (tt_dib.dva); /* clr int*/ + *dvst = tt_tio_status (); /* get status */ + if ((*dvst & DVS_DST) != 0) { /* busy? */ + sim_cancel (&tt_unit[TTO]); /* stop dev thread */ + tt_cmd = TTS_IDLE; + chan_uen (tt_dib.dva); /* uend */ + } + break; + + case OP_AIO: /* acknowledge int */ + chan_clr_chi (tt_dib.dva); /* clr int*/ + case OP_TDV: /* test status */ + *dvst = 0; /* no status */ + break; + + default: + *dvst = 0; + return SCPE_IERR; + } + +return 0; +} + +/* Timed input service routine - runs continuously + Only accepts input in TTS_READx state */ + +t_stat tti_svc (UNIT *uptr) +{ +int32 c, ebcdic; +uint32 st; + +if ((c = sim_poll_kbd ()) < SCPE_KFLAG) /* no char or err? */ + return c; +if (c & SCPE_BREAK) { /* break? */ + if (tt_cmd == TTS_WRITE) { /* during write? */ + tt_cmd = TTS_IDLE; + sim_cancel (&tt_unit[TTO]); /* cancel write */ + chan_uen (tt_dib.dva); /* uend */ + } + return SCPE_OK; + } +c = c & 0x7F; +if (c == tti_panel) /* panel interrupt? */ + return io_set_pint (); +uptr->pos = uptr->pos + 1; /* incr count */ +if (c == '\r') /* map CR to NL */ + c = '\n'; +if (c == 0x7F) /* map ^H back */ + c = 0x08; +c = sim_tt_inpcvt (c, TT_GET_MODE (uptr->flags)); /* input conversion */ +ebcdic = ascii_to_ebcdic[c]; /* then to EBCDIC */ +tto_echo (c); /* echo character */ +if ((tt_cmd & 0x7F) == TTS_READ) { /* waiting for input? */ + st = chan_WrMemB (tt_dib.dva, ebcdic); /* write to memory */ + if (CHS_IFERR (st)) /* channel error? */ + return tt_chan_err (st); + if ((st == CHS_ZBC) || (ebcdic == E_EOM) || /* channel end? */ + ((tt_cmd == TTS_READS) && ((ebcdic == E_HT) || (ebcdic == E_NL)))) { + tt_cmd = TTS_END; /* new state */ + sim_activate (&tt_unit[TTO], chan_ctl_time); /* start dev thread */ + } + } +return SCPE_OK; +} + +/* Output service routine - also acts as overall device thread + Because of possible retry, channel status and converted character + must be preserved across calls. */ + +t_stat tto_svc (UNIT *uptr) +{ +int32 c, cmd; +uint32 st; + +switch (tt_cmd) { /* case on state */ + + case TTS_INIT: /* I/O init */ + st = chan_get_cmd (tt_dib.dva, &cmd); /* get command */ + if (CHS_IFERR (st)) /* channel error? */ + return tt_chan_err (st); + if ((cmd == TTS_WRITE) || /* valid command? */ + ((cmd & 0x7F) == TTS_READ)) + tt_cmd = cmd; /* next state */ + else tt_cmd = TTS_END; /* no, end state */ + sim_activate (uptr, chan_ctl_time); /* continue thread */ + break; + + case TTS_WRITE: /* char output */ + st = chan_RdMemB (tt_dib.dva, &c); /* get char */ + if (CHS_IFERR (st)) /* channel error? */ + return tt_chan_err (st); + c = ebcdic_to_ascii[c & 0xFF]; /* convert to ASCII */ + tto_echo (c); /* echo character */ + sim_activate (uptr, uptr->wait); /* continue thread */ + if (st == CHS_ZBC) /* st = zbc? */ + tt_cmd = TTS_END; /* next is end */ + else tt_cmd = TTS_WRITE; /* next is write */ + break; + + case TTS_END: /* command done */ + st = chan_end (tt_dib.dva); /* set channel end */ + if (CHS_IFERR (st)) /* channel error? */ + return tt_chan_err (st); + if (st == CHS_CCH) { /* command chain? */ + tt_cmd = TTS_INIT; /* restart thread */ + sim_activate (uptr, chan_ctl_time); + } + else tt_cmd = TTS_IDLE; /* all done */ + break; + } + +return SCPE_OK; +} + +/* Actual tty output routines; simulates horizontal tabs */ + +void tto_echo (int32 c) +{ +uint32 cnt; + +cnt = 1; +if (c == '\r') + tto_pos = 0; +else if (c == '\n') { + tto_pos = 0; + sim_putchar ('\r'); + tt_unit[TTO].pos = tt_unit[TTO].pos + 1; + } +else if (c == '\t') { + c = ' '; + cnt = 8 - (tto_pos % 8); + } +else c = sim_tt_outcvt (c, TT_GET_MODE (tt_unit[TTO].flags)); +if (c >= 0) { + while (cnt-- > 0) { + sim_putchar (c); + tto_pos++; + tt_unit[TTO].pos = tt_unit[TTO].pos + 1; + } + } +return; +} + +/* TTY status routine */ + +uint32 tt_tio_status (void) +{ +if (tt_cmd == TTS_IDLE) + return DVS_AUTO; +return (CC2 << DVT_V_CC) | DVS_DBUSY | DVS_CBUSY | DVS_AUTO; +} + +/* Channel error */ + +t_stat tt_chan_err (uint32 st) +{ +tt_cmd = TTS_IDLE; +sim_cancel (&tt_unit[TTO]); /* stop dev thread */ +chan_uen (tt_dib.dva); /* uend */ +if (st < CHS_ERR) + return st; +return SCPE_OK; +} + +/* Reset routine */ + +t_stat tt_reset (DEVICE *dptr) +{ +rtc_register (RTC_TTI, tti_tps, &tt_unit[TTI]); /* register timer */ +sim_cancel (&tt_unit[TTO]); /* stop dev thread */ +tt_cmd = TTS_IDLE; /* idle */ +chan_reset_dev (tt_dib.dva); /* clr int, active */ +tto_pos = 0; +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; +} diff --git a/sim_rev.h b/sim_rev.h index 8d7a623b..e82247d9 100644 --- a/sim_rev.h +++ b/sim_rev.h @@ -28,15 +28,15 @@ #define _SIM_REV_H_ 0 #define SIM_MAJOR 3 -#define SIM_MINOR 8 -#define SIM_PATCH 2 +#define SIM_MINOR 9 +#define SIM_PATCH 0 #define SIM_DELTA 0 -/* V3.8 revision history +/* V3.9 revision history patch date module(s) and fix(es) - 2 tbd scp.c: + 0 xx-yyy-1 scp.c: - added *nix READLINE support (Mark Pizzolato) - fixed handling of DO with no arguments (Dave Bryan) - clarified some help messages (Mark Pizzolato) @@ -53,7 +53,64 @@ patch date module(s) and fix(es) - made option negotiation more reliable (Mark Pizzolato) h316_cpu.c: - - fixed bugs in MPY, DIV introduced in 3.8-1 + - fixed bugs in MPY, DIV introduced in 3.8-1 (from Theo Engel) + - fixed bugs in double precision, normalization, SC (from Adrian Wise) + - fixed XR behavior (from Adrian Wise) + + hp2100 all peripherals (Dave Bryan): + - Changed I/O signal handlers for newly revised signal model + + hp2100_cpu.c (Dave Bryan): + - Revised DMA for new multi-card paradigm + - Consolidated DMA reset routines + - DMA channels renamed from 0,1 to 1,2 to match documentation + - Changed I/O instructions, handlers, and DMA for revised signal model + - Changed I/O dispatch table to use DIB pointers + - Removed DMA latency counter + - Fixed DMA requests to enable stealing every cycle + - Fixed DMA priority for channel 1 over channel 2 + - Corrected comments for "cpu_set_idle" + - Fixed I/O return status bug for DMA cycles + - Failed I/O cycles now stop on failing instruction + + hp2100_cpu.h: + - Changed declarations for VMS compiler + + hp2100_cpu0.c (Dave Bryan): + - Removed DS note regarding PIF card (is now implemented) + + hp2100_cpu6.c (Dave Bryan): + - DMA channels renamed from 0,1 to 1,2 to match documentation + + hp2100_defs.h (Dave Bryan): + - DMA channels renamed from 0,1 to 1,2 to match documentation + - Revised I/O signal enum values for concurrent signals + - Revised I/O macros for new signal handling + + hp2100_ds.c (Dave Bryan): + - Corrected status returns for disabled drive, auto-seek + beyond drive limits, Request Sector Address and Wakeup + with invalid or offline unit + - Address verification reenabled if auto-seek during + Read Without Verify + + hp2100_fp1.c (Dave Bryan): + - Completed the comments for divide; no code changes + + hp2100_ipl.c (Dave Bryan): + - Revised for new multi-card paradigm + - A failed STC may now be retried + + hp2100_lps.c (Dave Bryan): + - Corrected 12566B (DIAG mode) jumper settings + - Revised detection of CLC at last DMA cycle + + hp2100_mt.c (Dave Bryan): + - Fixed error in command scan in mtcio ioIOO handler + + hp2100_sys.c (Dave Bryan): + - DMA channels renamed from 0,1 to 1,2 to match documentation + - Changed DIB access for revised signal model i1401_cd.c: - fixed read stacker operation in column binary mode @@ -71,6 +128,12 @@ patch date module(s) and fix(es) - fixed backspace over tapemark not to set EOR (Van Snyder) - added no rewind option (Van Snyder) + pdp11_defs.h: + - fixed priority of PIRQ vs IO; added INT_INTERNALn + + pdp11_io.c: + - fixed Qbus interrupts to treat all IO devices as BR4 + pdp11_rk.c: - fixed bug in read header (Walter F Mueller) @@ -90,7 +153,7 @@ patch date module(s) and fix(es) - 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 - (All of the above from Mark Pizzolato) + (all of the above from Mark Pizzolato) - fixed comments about register addresses pdp11_ts.c: @@ -103,12 +166,25 @@ patch date module(s) and fix(es) pdp8_sys.c: - added link to FPP + pdp8_td.c: + - fixed SDLC to clear AC (from Dave Gesswein) + vax_cpu.c: - revised idle design (from Mark Pizzolato) - fixed bug in SET CPU IDLE + - fixed failure to clear PSL in BPT, XFC vax_cpu1.c: - revised idle design (from Mark Pizzolato) + - added VEC_QMODE test in interrupt handler + + vax_fpa.c + - fixed integer overflow bug in EMODx (from Camiel Vanderhoeven) + - fixed POLYx normalizing before add mask bug (from Camiel Vanderhoeven) + + vax_octa.c + - fixed integer overflow bug in EMODH (from Camiel Vanderhoeven) + - fixed POLYH normalizing before add mask bug (from Camiel Vanderhoeven) vax_syscm.c: - fixed t_addr printouts for 64b big-endian systems @@ -123,6 +199,11 @@ patch date module(s) and fix(es) vax780_stddev.c - added REBOOT support (from Mark Pizzolato) + vaxmod_def.h + - moved all Qbus devices to BR4; deleted RP definitions + + +/* V3.8 revision history 1 08-Feb-09 scp.c: - revised RESTORE unit logic for consistency @@ -132,6 +213,7 @@ patch date module(s) and fix(es) - decommitted MTAB_VAL - fixed implementation of MTAB_NC - fixed warnings in help printouts + - fixed "SHOW DEVICE" with only one enabled unit (Dave Bryan) sim_tape.c: - fixed signed/unsigned warning in sim_tape_set_fmt (Dave Bryan) diff --git a/sim_timer.c b/sim_timer.c index 2a364cdf..fbf5acf3 100644 --- a/sim_timer.c +++ b/sim_timer.c @@ -590,7 +590,7 @@ return (sim_idle_rate_ms != 0); t_bool sim_idle (uint32 tmr, t_bool sin_cyc) { -static uint32 cyc_ms; +static uint32 cyc_ms = 0; uint32 w_ms, w_idle, act_ms; int32 act_cyc; @@ -601,7 +601,7 @@ if ((sim_clock_queue == NULL) || /* clock queue empty? */ sim_interval = sim_interval - 1; return FALSE; } -if (!cyc_ms) +if (cyc_ms == 0) /* not computed yet? */ cyc_ms = (rtc_currd[tmr] * rtc_hz[tmr]) / 1000; /* cycles per msec */ if ((sim_idle_rate_ms == 0) || (cyc_ms == 0)) { /* not possible? */ if (sin_cyc) @@ -620,8 +620,8 @@ act_cyc = act_ms * cyc_ms; if (act_ms < w_ms) /* awakened early? */ act_cyc += (cyc_ms * sim_idle_rate_ms) / 2; /* account for half an interval's worth of cycles */ if (sim_interval > act_cyc) - sim_interval = sim_interval - act_cyc; -else sim_interval = 0; + sim_interval = sim_interval - act_cyc; /* count down sim_interval */ +else sim_interval = 0; /* or fire immediately */ return TRUE; }