diff --git a/0readme28.txt b/0readme28.txt deleted file mode 100644 index ea8ddaea..00000000 --- a/0readme28.txt +++ /dev/null @@ -1,144 +0,0 @@ -Notes For V2.8 - -1. New Features - -1.1 Directory and documentation - -- Only common files (SCP and libraries) are in the top level - directory. Individual simulator files are in their individual - directories. -- simh_doc.txt has been split up. simh_doc.txt now documents - only SCP. The individual simulators are documented in separate - text files in their own directories. -- mingw_build.bat is a batch file for the MINGW/gcc environment - that will build all the simulators, assuming the root directory - structure is at c:\sim. -- Makefile is a UNIX make file for the gcc environment that will - build all the simulators, assuming the root directory is at - c:\sim. - -1.2 SCP - -- DO executes the SCP commands in the specified file. -- Replicated registers in unit structures can now be declared as - arrays for examine, modify, save, and restore. Most replicated - unit registers (for example, mag tape position registers) have - been changed to arrays. -- The ADD/REMOVE commands have been replaced by SET unit ONLINE - and SET unit OFFLINE, respectively. -- Register names that are unique within an entire simulator do - not have to be prefaced with the device name. -- The ATTACH command can attach files read only, either under - user option (-r), or because the attached file is ready only. -- The SET/SHOW capabilities have been extended. New forms include: - - SET param{=value}{ param ...} - SET param{=value}{ param ...} - SHOW {param param ...} - SHOW {param param ...} - -- Multiple breakpoints have been implemented. Breakpoints are - set/cleared/displayed by: - - BREAK addr_list{[count]} - NOBREAK addr_list - SHOW BREAK addr_list - -1.3 PDP-11 simulator - -- Unibus map implemented, with 22b RP controller (URH70) or 18b - RP controller (URH11) (in debug). -- All DMA peripherals rewritten to use map. -- Many peripherals modified for source sharing with VAX. -- RQDX3 implemented. -- Bugs fixed in RK11 and RL11 write check. - -1.4 PDP-10 simulator - -- ITS 1-proceed implemented. -- Bugs fixed in ITS PC sampling and LPMR - -1.5 18b PDP simulator - -- Interrupts split out to multiple levels to allow easier - expansion. - -1.5 IBM System 3 Simulator - -- Written by Charles (Dutch) Owen. - -1.6 VAX Simulator (in debug) - -- Simulates MicroVAX 3800 (KA655) with 16MB-64MB memory, RQDX3, - RLV12, TSV11, DZV11, LPV11, PCV11. -- CDROM capability has been added to the RQDX3, to allow testing - with VMS hobbyist images. - -1.7 SDS 940 Simulator (not tested) - -- Simulates SDS 940, 16K-64K memory, fixed and moving head - disk, magtape, line printer, console. - -1.8 Altair Z80 - -- Revised from Charles (Dutch) Owen's original by Peter Schorn. -- MITS 8080 with full Z80 simulation. -- 4K and 8K BASIC packages, Prolog package. - -1.9 Interdata - -The I4 simulator has been withdrawn for major rework. Look for -a complete 16b/32b Interdata simulator sometime next year. - -2. Release Notes - -2.1 SCP - -SCP now allows replicated registers in unit structures to be -modelled as arrays. All replicated register declarations have -been replaced by register array declarations. As a result, -save files from prior revisions will generate errors after -restoring main memory. - -2.2 PDP-11 - -The Unibus map code is in debug. The map was implemented primarily -to allow source sharing with the VAX, which requires a DMA map. -DMA devices work correctly with the Unibus map disabled. - -The RQDX3 simulator has run a complete RSTS/E SYSGEN, with multiple -drives, and booted the completed system from scratch. - -2.3 VAX - -The VAX simulator will run the boot code up to the >>> prompt. It -can successfully process a SHOW DEVICE command. It runs the HCORE -instruction diagnostic. It can boot the hobbyist CD through SYSBOOT -and through the date/time dialog and restore the hobbyist CD, using -standalone backup. On the boot of the restored disk, it gets to the -date/time dialog, and then crashes. - -2.4 SDS 940 - -The SDS 940 is untested, awaiting real code. - -2.5 GCC Optimization - -At -O2 and above, GCC does not correctly compile the simulators which -use setjmp-longjmp (PDP-11, PDP-10, VAX). A working hypothesis is -that optimized state maintained in registers is being used in the -setjmp processing routine. On the PDP-11 and PDP-10, all of this -state has been either made global, or volatile, to encourage GCC to -keep the state up to date in memory. The VAX is still vulnerable. - -3. Work list - -3.1 SCP - -- Better ENABLE/DISABLE. - -3.2 PDP-11 RQDX3 - -Software mapped mode, RCT read simulation, VMS debug. - - diff --git a/0readme29.txt b/0readme29.txt new file mode 100644 index 00000000..94397546 --- /dev/null +++ b/0readme29.txt @@ -0,0 +1,48 @@ +Notes For V2.9-11 + +1. New Features + +1.1 GRI-909 + +- This is a new simulator for the GRI-909. +- It has been hand-tested; so far, no software has been discovered. + +1.2 VAX + +- SET CPU CONHALT will cause a HALT instruction to return to the + boot ROM console rather than to SIMH. SET CPU SIMHALT restores + the default behavior. +- BRB/W self at IPL 1F stops the simulator. This is the default + behavior of VMS at exit. + +1.3 PDP-18b + +- ATTACH -A PTR/PTP attaches the reader and punch in ASCII mode. + In ASCII mode, the reader automatically sets the high order bit + of incoming alphabetic data, and the punch clears the high order + bit of outgoing data. + +1.4 SCP + +- DO -V echoes commands from the file as they are executed. +- Under Windows, execution priority is set BELOW_NORMAL when the + simulator is running. + +2. Release Notes + +2.1 Bugs Fixed + +- PDP-11 CPU: fixed updating of MMR0 on a memory management error. +- VAX FPA: changed function names to avoid conflict with C math library. +- 1401 MT: read end of record generates group mark without word mark. +- 1401 DP: fixed address generation and checking. +- SCP: an EXIT within a DO command will cause the simulator to exit. + +3. In Progress + +- Interdata 16b/32b: coded, not tested. +- SDS 940: coded, not tested. +- IBM 1620: coded, not tested. + +If you would like to help with the debugging of the untested simulators, +they can be made available by special request. diff --git a/ALTAIR/altair_sio.c b/ALTAIR/altair_sio.c index c31c71c0..0591b0fe 100644 --- a/ALTAIR/altair_sio.c +++ b/ALTAIR/altair_sio.c @@ -72,7 +72,7 @@ UNIT ptr_unit = { UDATA (&ptr_svc, UNIT_SEQ + UNIT_ATTABLE, 0), REG ptr_reg[] = { { ORDATA (DATA, ptr_unit.buf, 8) }, { ORDATA (STAT, ptr_unit.u3, 8) }, - { ORDATA (POS, ptr_unit.pos, 31) }, + { ORDATA (POS, ptr_unit.pos, 32) }, { NULL } }; DEVICE ptr_dev = { @@ -87,7 +87,7 @@ UNIT ptp_unit = { UDATA (&ptp_svc, UNIT_SEQ + UNIT_ATTABLE, 0), REG ptp_reg[] = { { ORDATA (DATA, ptp_unit.buf, 8) }, { ORDATA (STAT, ptp_unit.u3, 8) }, - { ORDATA (POS, ptp_unit.pos, 31) }, + { ORDATA (POS, ptp_unit.pos, 32) }, { NULL } }; DEVICE ptp_dev = { diff --git a/AltairZ80/altairZ80.txt b/AltairZ80/altairZ80.txt index 90e43ab3..15edf9cf 100644 --- a/AltairZ80/altairZ80.txt +++ b/AltairZ80/altairZ80.txt @@ -1,5 +1,15 @@ -Altair 8800 Simulator -===================== +Altair 8800 Simulator with Z80 support +====================================== + +0. Revision History + +Original version of this document written by Charles E Owen +- 4-May-2002, Peter Schorn (added description of MP/M II sample software) +- 28-Apr-2002, Peter Schorn (added periodic timer interrupts and three + additional consoles) +- 15-Apr-2002, Peter Schorn (added memory breakpoint) +- 7-Apr-2002, Peter Schorn (added ROM / NOROM switch) + 1. Background. @@ -18,6 +28,7 @@ expansion cards to make the Altair quite a respectable little computer. The "Altair Bus" that made this possible was soon called the S-100 Bus, later adopted as an industry standard, and eventually became the IEE-696 Bus. + 2. Hardware We are simulating a fairly "loaded" Altair 8800 from about 1977, @@ -51,10 +62,12 @@ a minimum of 24K. will not or not properly run on a Z80. This is mainly due to the use of the parity flag on the 8080 which has not always the same semantics on the Z80. + SET CPU ITRAP Causes the simulator to halt if an invalid opcode is detected (depending on the chosen CPU). SET CPU NOITRAP Does not stop on an invalid Opcode. This is how the real 8080 works. + SET CPU 4K SET CPU 8K SET CPU 12K @@ -64,10 +77,27 @@ a minimum of 24K. The 2K EPROM at the high end of memory is always present and will always boot. -The BOOT EPROM card starts at address FF00. Jumping to this address -will always boot drive 0 of the floppy controller. If no valid bootable -software is present there the machine crashes. This is historically -accurate behavior. + SET CPU BANKED Enables the banked memory support. The simulated memory + has four banks with address range 0..'common' (see registers below) + and a common area from 'common' to 0xfff which is common to all + banks. The currently active bank is determined by register 'bank' + (see below). You can only switch to banked memory if the memory + is set to 64K. The banked memory is used by CP/M 3. + + SET CPU NONBANKED Disables banked memory support. + + SET CPU ROM Enables the boot EPROM at address 0FF00H and prevents + write access to the locations from 0FF00H to 0FFFFH. This is the + default setting. + + SET CPU NOROM Disables the boot EPROM at address 0FF00H and enables + write access to the locations from 0FF00H to 0FFFFH. + +The BOOT EPROM card starts at address 0FF00H. Jumping to this address +will boot drive 0 of the floppy controller (CPU must be set to ROM or +equivalent code must be present). If no valid bootable software is +present there the machine crashes. This is historically accurate +behavior. The real 8080, on receiving a HLT (Halt) instruction, freezes the processor and only an interrupt or CPU hardware reset will restore it. The simulator @@ -109,6 +139,11 @@ CPU Registers include the following: keystroke so best to change this to something exotic such as 035 (which is Ctl-]). + BANK 3 The currently active memory bank (if banked memory + is activated - see memory options above) + COMMON 16 The starting address of common memory. Originally set + to 0xc000 (note this setting must agree with the + value supplied to GENCPM for CP/M 3 system generation) 2.2 The Serial I/O Card (2SIO) @@ -134,13 +169,39 @@ simple stream of 8-bit bytes. SET SIO BS Map the delete character to backspace SET SIO DEL Map the backspace character to delete - + + SET SIO QUIET Do not print warning messages + SET SIO VERBOSE Print warning messages (useful for debugging) + The register SIOWL determines how often the same warning + is displayed. The default is 3. + You can also attach the SIO to a port: - + ATTACH SIO 23 Console IO goes via a Telnet connection on port 23 DETACH SIO Console IO goes via the regular SIMH console -2.3 The 88-DISK controller. +2.3 The SIMH pseudo device + + The SIMH pseudo device facilitates the communication between the simulated +ALTAIR and the simulator environment. This device defines a number of (most R/O) +registers (see source code) which are primarily useful for debugging purposes. + + The SIMH pseudo device can be configured with + + SET SIMH QUIET Do not print warning messages + SET SIMH VERBOSE Print warning messages (useful for debugging) + + SET SIMH TIMERON Start periodic timer interrupts + SET SIMH TIMEROFF Stop the periodic timer interrupts + + The following variables determine the behavior of the timer: + + TIMD This is the delay between consecutive interrupts in milliseconds. + Use D TIMD 20 for a 50 Hz clock. + TIMH This is the address of the interrupt handler to call for a + timer interrupt. + +2.4 The 88-DISK controller. The MITS 88-DISK is a simple programmed I/O interface to the MITS 8-inch floppy drive, which was basically a Pertec FD-400 with a power @@ -165,9 +226,21 @@ have been defined with the following meaning: 8 Print a message whenever the disk head appears to be waiting for a sector which does not show up (often an indication of an infinite loop) - -For example the command "D TRACE 10" will trace options 2+8 from above. - + +For example the command "D TRACE 10" will trace options 2+8 from above. + + The DSK device can be configured with + + SET DSK QUIET Do not print warning messages for disk + SET DSK VERBOSE Print warning messages for disk + (useful for debugging) + The register DSKWL determines how often the + same warning is displayed. The default is 3. + + SET DSK WRITEENABLED Allow write operations for disk + SET DSK LOCKED Disk is locked, i.e. no write operations + will be allowed. + 3. Sample Software @@ -187,10 +260,8 @@ There were some "official" versions but I don't have them. None were endorsed or sold by MITS to my knowledge, however. To boot CP/M: - sim> attach dsk altcpm.dsk - sim> go ff00 - 62K CP/M VERSION 2.2 (ALTAIR 8800) - A>DIR + sim> attach dsk cpm2.dsk + sim> boot dsk CP/M feels like DOS, sort of. DIR will work. I have included all the standard CP/M utilities, plus a few common public-domain ones. I also @@ -200,60 +271,360 @@ DIR than DIR. ASM will assemble .ASM files to Hex, LOAD will "load" them to binary format (.COM). ED is a simple editor, #A command will bring the source file to the buffer, T command will "type" lines, L will move lines, E exits the editor. 20L20T will move down 20 lines, and type 20. Very -DECish. DDT is the debugger, SUBMIT is a batch-type command processor. +DECish. DDT is the debugger, DO is a batch-type command processor. A sample batch file that will assemble and write out the bootable CP/M -image (on drive A) is "SYSGEN.SUB". To run it, type "SUBMIT SYSGEN". +image (on drive A) is "SYSCPM2.SUB". To run it, type "DO SYSCPM2". In order to efficiently transfer files into the CP/M environment use the -included program READ . If you have a file named foo.ext in +included program R . If you have a file named foo.ext in the current directory (i.e. the directory where SIMH is), executing -READ FOO.EXT under CP/M will transfer the file onto the CP/M disk. READ will -only run with Z80 CPU so remember to "SET CPU Z80". +R FOO.EXT under CP/M will transfer the file onto the CP/M disk. +Transferring a file from the CP/M environment to the SIMH environment is +accomplished by W . -The disk "altcpm.dsk" contains the following files: -Name Ext Size Comment -ABOOT62 ASM 1K Moves CP/M image from MOVCPM location to real location - in memory -ASM COM 8K Standard CP/M assembler -CALC PRO 3K Prolog sample file "Calculator" -CBIOS ASM 8K BIOS for the Altair (used for sysgen) -COPY COM 1K ALTAIR diskette backup program -CPM62 COM 9K CP/M binary (used for sysgen) -DDT COM 5K Dynamic Debugging Tool (Standard CP/M) -DDTZ COM 10K Dynamic Debugging Tool for Z80 -DUMP ASM 5K Assembler source for DUMP utility -DUMP COM 1K Dumps the contents of a file in hex (Standard CP/M) -ED COM 7K Line oriented editor (Standard CP/M) -FAMILY PRO 2K Prolog sample file "Family relations" -FORMAT COM 2K Formats a disk -INTEGER PRO 1K Prolog sample file "Integer arithmetic" -KNAKE PRO 2K Prolog sample file "Logic puzzle" -LOAD COM 2K Loads a hex file and produces an executable - (Standard CP/M) -LS COM 3K Directory utility -MOVCPM COM 12K Regenerates the CP/M system for a particular - memory size (Standard CP/M) -PINST COM 4K Terminal installer for PROLOGZ.COM -PIP COM 8K Peripheral Interchange Program for copying files - (Standard CP/M) -PROLOGZ COM 17K Prolog development environment -PROLOGZ TXT 40K PROLOGZ documentation in German -PTD ASM 2K Writes Altair-format memory image to disk - (used for sysgen) -QUEEN PRO 2K Prolog sample file "N Queens problem" -READ COM 2K Reads a file from the SIMH filesystem to CP/M -README TXT 3K This file -STAT COM 6K Provides information about drives, disks and - files (Standard CP/M) -SUBMIT COM 2K Submits a file of commands for batch processing - (Standard CP/M) -SURVEY COM 2K Provides information about memory and IO ports -SYSCOPY COM 2K Copies the reserved tracks between disks -SYSGEN SUB 2K Submit file for generating the CP/M system -XSUB COM 2K Addition to SUBMIT such that all input is read - from the submit file (Standard CP/M) +The disk "cpm2.dsk" contains the following files: +Name Ext Size Comment +ASM .COM 8K ; CP/M assembler +BDOS .MAC 66K ; Basic Disk Operating System assembler source code +BOOT .COM 1K ; transfer control to boot ROM +BOOT .MAC 2K ; source for BOOT.COM +BOOTGEN .COM 2K ; put a program on the boot sectors +CBIOSX .MAC 10K ; CP/M 2 BIOS source for Altair +CCP .MAC 26K ; Console Command Processor assembler source code +COPY .COM 1K ; copy disks +CPMBOOT .COM 12K ; CP/M operating system +CREF80 .COM 4K ; cross reference utility +DDT .COM 5K ; 8080 debugger +DDTZ .COM 10K ; Z80 debugger +DIF .COM 3K ; determine differences between two files +DO .COM 2K ; batch processing +DSKBOOT .COM 1K ; code for boot ROM +DSKBOOT .MAC 3K ; source for boot ROM +DUMP .COM 1K ; hex dump a file +ED .COM 7K ; line editor +ELIZA .BAS 9K ; Elisa game in Basic +EX8080 .COM 9K ; exercise 8080 instruction set +EX8080 .MAC 47K ; source for EX8080.COM +EX8080 .SUB 1K ; benchmark execution of EX8080.COM +EXZ80 .COM 9K ; exercise Z80 instruction set +EXZ80 .MAC 47K ; source for EXZ80.COM +EXZ80 .SUB 1K ; benchmark execution of EXZ80.COM +FORMAT .COM 2K ; format disks +GO .COM 0K ; start the currently loaded program at 100H +L80 .COM 11K ; Microsoft linker +LADDER .COM 40K ; game +LADDER .DAT 1K ; high score file for LADDER.COM +LIB80 .COM 6K ; library utility +LOAD .COM 2K ; load hex files +LS .COM 3K ; directory utility +LU .COM 20K ; library utility +M80 .COM 20K ; Microsoft macro assembler +MBASIC .COM 24K ; Microsoft Basic interpreter +MC .SUB 1K ; assemble and link an assmbler program +MCC .SUB 1K ; read, assemble and link an assmbler program +MOVER .MAC 2K ; moves operating system in place +OTHELLO .COM 12K ; Othello (Reversi) game +PIP .COM 8K ; Peripheral Interchange Program +R .COM 3K ; read files from SIMH environment +RSETSIMH.COM 1K ; reset SIMH interface +RSETSIMH.MAC 1K ; assembler source for RSETSIMH.COM +SHOWSEC .COM 3K ; show sectors on a disk +SID .COM 8K ; debugger for 8080 +STAT .COM 6K ; provide information about currently logged disks +SURVEY .COM 2K ; system survey +SURVEY .MAC 15K ; assembler source for SURVEY.COM +SYSCOPY .COM 2K ; copy system tracks between disks +SYSCPM2 .SUB 1K ; create CP/M 2 on drive A: +TSHOW .COM 1K ; show split time +TSHOW .MAC 1K ; assembler source for TSHOW.COM +TSTART .COM 1K ; create timer and start it +TSTART .MAC 1K ; assembler source for TSTART.COM +TSTOP .COM 1K ; show final time and stop timer +TSTOP .MAC 1K ; assembler source for TSTOP.COM +UNCR .COM 7K ; un-crunch utility +UNERA .COM 2K ; un-erase a file +UNERA .MAC 16K ; source for UNERA.COM +USQ .COM 2K ; un-squeeze utility +W .COM 3K ; write files to SIMH environment +WM .COM 11K ; word master screen editor +WM .HLP 3K ; help file for WM.COM +WORM .COM 4K ; worm game for VT100 terminal +XSUB .COM 1K ; support for DO.COM +ZSID .COM 10K ; debugger for Z80 +ZTRAN4 .COM 4K ; translate 8080 mnemonics into Z80 equivalents -3.2 MITS Disk Extended BASIC Version 4.1 + +3.2 CP/M Version 3 with banked memory + CP/M 3 is the successor to CP/M 2.2. A customised BIOS (BIOS3.MAC) +is included to facilitate modification if so desired. The defaults supplied in +GENCPM.DAT for system generation can be used. BOOTGEN.COM is used to +place the CP/M loader (LDR.COM) on the boot tracks of a disk. + + Running CP/M 3 with banked memory: + sim> attach dsk cpm3.dsk + sim> reset cpu + sim> set cpu banked + sim> set cpu itrap + sim> boot dsk + +Executing "DO SYSCPM3" will re-generate the banked version of CP/M 3. +You can boot CP/M 3 with or without a Z80 CPU. The Z80 CPU is needed for +both sysgens due to the use of BOOTGEN.COM which requires it. + +The disk "cpm3.dsk" contains the following files: +ASM .COM 8K ; CP/M assembler +ASSIGN .SYS 2K +BDOS3 .SPR 10K +BIOS3 .MAC 28K ; CP/M 3 BIOS source for Altair SIMH +BIOS3 .SPR 4K +BNKBDOS3.SPR 14K +BNKBIOS3.SPR 4K +BOOT .COM 2K ; transfer control to boot ROM +BOOTGEN .COM 2K ; put a program on the boot sectors +CCP .COM 4K +COPYSYS .COM 2K +CPM3 .SYS 18K +CPMLDR .MAC 38K ; CP/M 3 loader assembler source +DATE .COM 4K ; date utility +DDT .COM 6K ; 8080 debugger +DDTZ .COM 10K ; Z80 debugger +DEFS .LIB 2K ; include file for BIOS3.MAC to create banked CP/M 3 +DEVICE .COM 8K +DIF .COM 4K ; determine differences between two files +DIR .COM 16K ; directory utility +DO .COM 6K ; batch processing +DUMP .COM 2K +ED .COM 10K +ERASE .COM 4K +GENCOM .COM 16K +GENCPM .COM 22K +GENCPM .DAT 4K ; CP/M generation information for banked version +GENCPMNB.DAT 4K ; CP/M generation information for non-banked version +GET .COM 8K +HELP .COM 8K ; help utility +HELP .HLP 62K ; help files +HEXCOM .CPM 2K +HIST .UTL 2K +INITDIR .COM 32K +L80 .COM 12K ; Microsoft linker +LDR .COM 4K ; CP/M loader with optimised loader BIOS +LDRBIOS3.MAC 14K ; optimised (for space) loader BIOS +LIB .COM 8K ; Digital Research librarian +LINK .COM 16K ; Digital Research linker +LOAD .COM 2K +M80 .COM 20K ; Microsoft macro assembler +MC .SUB 2K ; assemble and link an assmbler program +MCC .SUB 2K ; read, assemble and link an assembler program +PATCH .COM 4K +PIP .COM 10K ; Peripheral Interchange Program +PROFILE .SUB 2K ; commands to be executed at start up +PUT .COM 8K +R .COM 4K ; read files from SIMH environment +RENAME .COM 4K +RESBDOS3.SPR 2K +RMAC .COM 14K ; Digital Research macro assembler +RSETSIMH.COM 2K ; reset SIMH interface +SAVE .COM 2K +SCB .MAC 2K +SET .COM 12K +SETDEF .COM 6K +SHOW .COM 10K +SHOWSEC .COM 4K ; show sectors on a disk +SID .COM 8K ; 8080 debugger +SYSCOPY .COM 2K ; copy system tracks between disks +SYSCPM3 .SUB 2K ; create banked CP/M 3 system +TRACE .UTL 2K +TSHOW .COM 2K ; show split time +TSTART .COM 2K ; create timer and start it +TSTOP .COM 2K ; show final time and stop timer +TYPE .COM 4K +UNERA .COM 2K ; un-erase a file +W .COM 4K ; write files to SIMH environment +XREF .COM 16K ; cross reference utility +ZSID .COM 10K ; Z80 debugger + + +3.3 MP/M II with banked memory + + MP/M II is an acronym for MultiProgramming Monitor Control Program for +Microprocessors. It is a multiuser operating system for an eight bit +microcomputer. MP/M II supports multiprogramming at each terminal. This +version supports four terminals available via Telnet. To boot: + + sim> attach dsk mpm.dsk + sim> set cpu itrap + sim> set cpu z80 + sim> set cpu rom + sim> set cpu banked + sim> attach sio 23 + sim> boot dsk + +Now connect a Telnet session to the simulator and type "MPM" at the "A>" +prompt. Now you can connect up to three additional terminals via Telnet +to the Altair running MP/M II. To re-generate the system perform +"DO SYSMPM" in the CP/M environment (not possible under MP/M since XSUB +is needed). + +The disk "mpm.dsk" contains the following files: +Name Ext Size Comment +ABORT .PRL 2K ; abort a process +ABORT .RSP 2K +ASM .PRL 10K ; MP/M assembler +BNKBDOS .SPR 12K ; banked BDOS +BNKXDOS .SPR 2K ; banked XDOS +BNKXIOS .SPR 4K ; banked XIOS +BOOTGEN .COM 2K ; copy an executable to the boot section +CONSOLE .PRL 2K ; print console number +CPM .COM 2K ; return to CP/M +CPM .MAC 2K ; source for CPM.COM +DDT .COM 6K ; MP/M DDT +DDT2 .COM 6K ; CP/M DDT +DDTZ .COM 10K ; CP/M DDT with Z80 support +DIF .COM 4K ; difference between two files +DIR .PRL 2K ; directory command +DO .COM 2K ; CP/M submit +DSKRESET.PRL 2K ; disk reset command +DUMP .MAC 6K ; source for DUMP.PRL +DUMP .PRL 2K ; dump command +ED .PRL 10K ; MP/M line editor +ERA .PRL 2K ; erase command +ERAQ .PRL 4K ; erase comand (verbose) +GENHEX .COM 2K +GENMOD .COM 2K +GENSYS .COM 10K +L80 .COM 12K ; Microsoft linker +LDRBIOS .MAC 14K ; loader BIOS +LIB .COM 8K ; library utility +LINK .COM 16K ; linker +LOAD .COM 2K ; loader +M80 .COM 20K ; Microsoft macro assembler +MC .SUB 2K ; assemble and link an assmbler program +MCC .SUB 2K ; read, assemble and link an assembler program +MPM .COM 8K ; start MP/M II +MPM .SYS 26K ; MP/M system file +MPMD .LIB 2K ; define a banked system +MPMLDR .COM 6K ; MP/M loader without LDRBIOS +MPMSTAT .BRS 6K ; status of MP/M system +MPMSTAT .PRL 6K +MPMSTAT .RSP 2K +MPMXIOS .MAC 26K ; XIOS for MP/M +PIP .PRL 10K ; MP/M peripheral interchange program +PIP2 .COM 8K ; CP/M peripheral interchange program +PRINTER .PRL 2K +PRLCOM .PRL 4K +R .COM 4K ; read a file from the SIMH environment +RDT .PRL 8K ; debugger for page relocatable programs +REN .PRL 4K ; rename a file +RESBDOS .SPR 4K ; non-banked BDOS +RMAC .COM 14K ; Digital Research macro assembler +RSETSIMH.COM 2K ; reset SIMH interface +SCHED .BRS 2K ; schedule a job +SCHED .PRL 4K +SCHED .RSP 2K +SDIR .PRL 18K ; fancy directory command +SET .PRL 8K ; set parameters +SHOW .PRL 8K ; show status of disks +SPOOL .BRS 4K ; spool utility +SPOOL .PRL 4K +SPOOL .RSP 2K +STAT .COM 6K ; CP/M stat command +STAT .PRL 10K ; MP/M stat command +STOPSPLR.PRL 2K ; stop spooler +SUBMIT .PRL 6K ; MP/M submit +SYSCOPY .COM 2K ; copy system tracks +SYSMPM .SUB 2K ; do a system generation +SYSTEM .DAT 2K ; default values for system generation +TMP .SPR 2K +TOD .PRL 4K ; time of day +TSHOW .COM 2K ; show split time +TSTART .COM 2K ; create timer and start it +TSTOP .COM 2K ; show final time and stop timer +TYPE .PRL 2K ; type a file on the screen +USER .PRL 2K ; set user area +W .COM 4K ; write a file to SIMH environment +XDOS .SPR 10K ; XDOS +XREF .COM 16K ; cross reference utility +XSUB .COM 2K ; for CP/M DO + + +3.5 CP/M application software + + There is also a small collection of sample application software containing +the following items: + +- SPL: a Small Programming Language with a suite of sample programs +- PROLOGZ: a Prolog interpreter written in SPL with sources +- PASCFORM: a Pascal pretty printer written in Pascal +- Pascal MT+: Pascal language system needed to compile PASCFORM + +The sample software comes on "app.dsk" and to use it do + + sim> attach dsk1 app.dsk + +before booting CP/M. + +The disk "app.dsk" contains the following files: +Name Ext Size Comment +BOOTGEN .COM 2K +BOOTGEN .SPL 6K ; SPL source for BOOTGEN.COM +C .SUB 2K ; batch file for compiling an SPL source file +CALC .PRO 4K ; Prolog demo program calculator +CC .SUB 2K ; compile an SPL source which is on the underlying + file system +DECLARAT. 12K ; common include file, SPL source +DIF .COM 4K +DIF .SPL 10K ; SPL source for DIF.COM +EDIT .SPL 10K ; screen editor for PROLOGZ, SPL source +FAMILY .PRO 4K ; Prolog demo program family relations +INTEGER .PRO 2K ; Prolog demo program integer arithmetic +KNAKE .PRO 2K ; Prolog demo program logic puzzle +LINKMT .COM 12K ; Pascal MT+ 5.5 linker +MAIN .SPL 14K ; main module for PROLOGZ, SPL source +MOVE .MAC 4K ; helper functions for PROLOGZ in assembler +MTERRS .TXT 6K ; Pascal MT+ error messages +MTPLUS .000 14K ; Pascal MT+ 5.5 compiler file +MTPLUS .001 12K ; Pascal MT+ 5.5 compiler file +MTPLUS .002 8K ; Pascal MT+ 5.5 compiler file +MTPLUS .003 8K ; Pascal MT+ 5.5 compiler file +MTPLUS .004 18K ; Pascal MT+ 5.5 compiler file +MTPLUS .005 8K ; Pascal MT+ 5.5 compiler file +MTPLUS .006 6K ; Pascal MT+ 5.5 compiler file +MTPLUS .COM 36K ; Pascal MT+ 5.5 compiler +PASCFORM.COM 36K ; Pascal formatter +PASCFORM.PAS 54K ; Pascal formatter source code +PASCFORM.SUB 2K ; create Pascal formatter +PASLIB .ERL 24K ; Pascal MT+ 5.5 run time library +PINST .COM 4K ; terminal installation program for PROLOGZ +PINST .SPL 16K ; terminal installation program for PROLOGZ, + SPL source +PROLOGZ .COM 18K ; PROLOGZ interpreter and screen editor +PROLOGZ .SPL 2K ; PROLOGZ main program, SPL source +PROLOGZ .TXT 40K ; PROLOGZ documentation in German +PROVE .SPL 16K ; backtrack theorem prover for PROLOGZ, SPL source +PZCLEAN .SUB 2K ; PROLOGZ: remove all created ".rel" and ".lst" files +PZLINK .SUB 2K ; PROLOGZ: create PINST, PROLOGZ and personalise the + serial number +PZMAKE .SUB 2K ; compiles the sources (you can ignore any compiler + errors) +QUEEN .PRO 2K ; Prolog demo program n-queens problem +READ .COM 4K +READ .SPL 10K ; SPL source for R.COM +SHOWSEC .COM 4K +SHOWSEC .SPL 6K ; SPL source for SHOWSEC.COM +SPL .COM 38K ; the SPL compiler itself +SPL .TXT 56K ; SPL language and compiler documentation in German +SPLERROR.DAT 12K ; error messages of the compiler (in German) +SPLIB .REL 6K ; SPL runtime library +STDIO . 2K ; include file for SPL programs +SYSCOPY .COM 2K +SYSCOPY .SPL 6K ; SPL source for SYSCOPY.COM +TERMBDOS.SPL 2K ; terminal interface to CP/M for PROLOGZ, SPL source +UTIL .SPL 18K ; utility functions for PROLOGZ, SPL source +WRITE .COM 4K +WRITE .SPL 8K ; SPL source for W.COM + + +3.6 MITS Disk Extended BASIC Version 4.1 This was the commonly used software for serious users of the Altair computer. It is a powerful (but slow) BASIC with some extended commands to @@ -266,22 +637,22 @@ ran under. To boot: sim> go ff00 MEMORY SIZE? [return] - LINEPRINTER? C [return] - HIGHEST DISK NUMBER? 0 [return] (3 here = 4 drive system) - NUMBER OF FILES? 3 [return] - NUMBER OF RANDOM FILES? 2 [return] + LINEPRINTER? [C return] + HIGHEST DISK NUMBER? [0 return] (0 here = 1 drive system) + NUMBER OF FILES? [3 return] + NUMBER OF RANDOM FILES? [2 return] 44041 BYTES FREE ALTAIR BASIC REV. 4.1 [DISK EXTENDED VERSION] COPYRIGHT 1977 BY MITS INC. OK - MOUNT 0 + [MOUNT 0] OK - FILES + [FILES] -3.3 Altair DOS Version 1.0 +3.7 Altair DOS Version 1.0 This was long promised but not delivered until it was almost irrelevant. A short attempted tour will reveal it to be a dog, far inferior @@ -293,27 +664,28 @@ to CP/M. To boot: MEMORY SIZE? [return] INTERRUPTS? N [return] - HIGHEST DISK NUMBER? 0 [return] (3 here = 4 drive system) - HOW MANY DISK FILES? 3 [return] - HOW MANY RANDOM FILES? 2 [return] + HIGHEST DISK NUMBER? [0 return] (3 here = 4 drive system) + HOW MANY DISK FILES? [3 return] + HOW MANY RANDOM FILES? [2 return] 056449 BYTES AVAILABLE DOS MONITOR VER 1.0 COPYRIGHT 1977 BY MITS INC - .MNT 0 + .[MNT 0] - .DIR 0 + .[DIR 0] -3.4 Altair 4k Basic + +3.8 Altair Basic 3.2 (4k) In order to run the famous 4k Basic, use the following commands (the trick is to get the Switch Register right). - sim> set cpu 8080 ;note 4k Basic will not run on a Z80 CPU - sim> set sio upper ;4k Basic does not like lower case letters as input - sim> set sio ansi ;4k Basic produces 8-bit output, strip to seven bits - sim> d sr 8 ;good setting for the Switch Register - sim> load 4kbas.bin ;load it - sim> go ;and go + sim> set cpu 8080 ;note 4k Basic will not run on a Z80 CPU + sim> set sio upper ;4k Basic does not like lower case letters as input + sim> set sio ansi ;4k Basic produces 8-bit output, strip to seven bits + sim> d sr 8 ;good setting for the Switch Register + sim> load 4kbas.bin 0 ;load it at 0 + sim> go 0 ;and start it MEMORY SIZE? [return] TERMINAL WIDTH? [return] WANT SIN? [Y] @@ -325,19 +697,20 @@ is to get the Switch Register right). OK -3.5 Altair 8k Basic + +3.9 Altair 8k Basic Running 8k Basic follows the procedure for 4k Basic. - sim> set cpu 8080 ;note 8k Basic will not run on a Z80 CPU - sim> set sio upper ;8k Basic does not like lower case letters as input - sim> set sio ansi ;8k Basic produces 8-bit output, strip to seven bits - sim> d sr 8 ;good setting for the Switch Register - sim> load 8kbas.bin ;load it - sim> go ;and go + sim> set cpu 8080 ;note 8k Basic will not run on a Z80 CPU + sim> set sio upper ;8k Basic does not like lower case letters as input + sim> set sio ansi ;8k Basic produces 8-bit output, strip to seven bits + sim> d sr 8 ;good setting for the Switch Register + sim> load 8kbas.bin 0 ;load it at 0 + sim> go 0 ;and start it MEMORY SIZE? [A] - + WRITTEN FOR ROYALTIES BY MICRO-SOFT - + MEMORY SIZE? [return] TERMINAL WIDTH? [return] WANT SIN-COS-TAN-ATN? [Y] @@ -348,9 +721,46 @@ is to get the Switch Register right). COPYRIGHT 1976 BY MITS INC. OK -4. Brief summary of all major changes to the original Altair simulator + +3.10 Altair Basic 4.0 + Execute the following commands to run Altair Extended Basic. + + sim> set sio upper ;Extended Basic does not like lower case letters as input + sim> set sio ansi ;Extended Basic produces 8-bit output, strip to seven bits + sim> d sr 8 ;good setting for the Switch Register + sim> load exbas.bin 0 ;load it at 0 + sim> go 0 ;and start it + 16384 Bytes loaded at 0. + + MEMORY SIZE? [return] + WANT SIN-COS-TAN-ATN? [Y] + + 50606 BYTES FREE + ALTAIR BASIC REV. 4.0 + [EXTENDED VERSION] + COPYRIGHT 1977 BY MITS INC. + OK + + +4. Special simulator features + In addition to the regular SIMH features such as PC queue, breakpoints +etc., this simulator supports memory access breakpoints. A memory access +breakpoint is triggered when a pre-defined memory location is accessed +(read, write or update). To set a memory location breakpoint enter + +sim> break -m + +Execution will stop whenever an operation accesses . Note that +a memory access breakpoint is not triggered by fetching code from memory +(this is the job of regular breakpoints). This feature has been +implemented by using the typing facility of the SIMH breakpoints. + + +5. Brief summary of all major changes to the original Altair simulator - Full support for Z80. CP/M software requiring a Z80 CPU now runs properly. DDTZ and PROLOGZ are included for demonstration purposes. +- Added banked memory support. +- PC queue implemented. - Full assembler and dis-assembler support for Z80 and 8080 mnemonics. Depending on the current setting of the CPU, the appropriate mnemonics are used. @@ -360,16 +770,27 @@ is to get the Switch Register right). - ROM and memory size settings are now fully honored. This means that you cannot write into the ROM or outside the defined RAM (e.g. when the RAM size was truncated with the SET CPU commands). This feature allows programs which - check for the size of available RAM to run properly (e.g. 4k Basic). + check for the size of available RAM to run properly (e.g. 4k Basic). In + addition one can enable and disable the ROM which is useful in special cases + (e.g. when testing a new version of the ROM). - The console can also be used via Telnet. This is useful when a terminal is needed which supports cursor control such as a VT100. PROLOGZ for example has a built-in screen editor which works under Telnet. - Simplified file exchange for CP/M. Using the READ program under CP/M one can easily import files into CP/M from the regular file system. Note that PIP does not work properly on non-text files on PTR. +- The WRITE program can be used to transfer files from the CP/M environment to + the regular environment (binary or ASCII transfer). - The last character read from PTR is always Control-Z (the EOF character for CP/M). This makes sure that PIP (Peripheral Interchange Program on CP/M) will terminate properly. - Fixed a bug in the BIOS warm boot routine which caused CP/M to crash. - Modified the BIOS for CP/M to support 8 disks. -- Changed from octal to hex which is more concise. +- Added CP/M 3 banked version as sample software +- Changed from octal to hex +- Made the DSK and SIO device more robust (previously malicious code could + crash the simulator) +- Added memory access break points +- Added periodic timer interrupts (useful for MP/M) +- Added additional consoles (useful for MP/M) +- Added MP/M II banked version as sample software diff --git a/AltairZ80/altairZ80_cpu.c b/AltairZ80/altairZ80_cpu.c index ad8b1f59..f1684dc2 100644 --- a/AltairZ80/altairZ80_cpu.c +++ b/AltairZ80/altairZ80_cpu.c @@ -1,5 +1,5 @@ /* altairz80_cpu.c: MITS Altair CPU (8080 and Z80) - Written by Peter Schorn, 2001 + Written by Peter Schorn, 2001-2002 Based on work by Charles E Owen ((c) 1997 - Commercial use prohibited) Code for Z80 CPU from Frank D. Cringle ((c) 1995 under GNU license) */ @@ -7,9 +7,23 @@ #include #include "altairZ80_defs.h" -/*-------------------------------- definitions for memory space --------*/ +#define PCQ_SIZE 64 /* must be 2**n */ +#define PCQ_MASK (PCQ_SIZE - 1) +#define PCQ_ENTRY(PC) pcq[pcq_p = (pcq_p - 1) & PCQ_MASK] = PC -uint8 M[MAXMEMSIZE]; /* RAM which is present */ +#define MEMSIZE (cpu_unit.capac) /* actual memory size */ +#define KB 1024 /* kilo byte */ +#define bootrom_origin 0xff00 /* start address of boot rom */ + +/* Simulator stop codes */ +#define STOP_HALT 2 /* HALT */ +#define STOP_IBKPT 3 /* breakpoint (program counter) */ +#define STOP_MEM 4 /* breakpoint (memory access) */ +#define STOP_OPCODE 5 /* unknown 8080 or Z80 instruction */ + +/*-------------------------------- definitions for memory space ------------------*/ + +uint8 M[MAXMEMSIZE][MAXBANKS]; /* RAM which is present */ /* two sets of accumulator / flags */ uint16 af[2]; @@ -54,8 +68,19 @@ uint16 IFF; #define SetPV ((cpu_unit.flags & UNIT_CHIP) ? (((cbits >> 6) ^ (cbits >> 5)) & 4) : (parity(sum))) #define SetPV2(x) ((cpu_unit.flags & UNIT_CHIP) ? (((temp == (x)) << 2)) : (parity(temp))) -/* checkCPU must be invoked whenever a Z80 only instruction is executed */ -#define checkCPU if ((cpu_unit.flags & UNIT_CHIP) == 0) { Bad8080OpOccured = 1; break; } +/* checkCPU8080 must be invoked whenever a Z80 only instruction is executed */ +#define checkCPU8080 \ + if ((cpu_unit.flags & UNIT_CHIP == 0) && (cpu_unit.flags & UNIT_OPSTOP)) { \ + reason = STOP_OPCODE; \ + goto end_decode; \ + } + +/* checkCPUZ80 must be invoked whenever a non Z80 instruction is executed */ +#define checkCPUZ80 \ + if (cpu_unit.flags & UNIT_OPSTOP) { \ + reason = STOP_OPCODE; \ + goto end_decode; \ + } static const uint8 partab[256] = { 4,0,0,4,0,4,4,0,0,4,4,0,4,0,0,4, @@ -83,163 +108,86 @@ static const uint8 partab[256] = { x = y + (RAM_pp(SP) << 8); \ } while (0) -#define JPC(cond) PC = cond ? GetWORD(PC) : PC+2 +#define JPC(cond) { \ + if (cond) { \ + PCQ_ENTRY(PC - 1); \ + PC = GetWORD(PC); \ + } \ + else { \ + PC += 2; \ + } \ +} #define CALLC(cond) { \ if (cond) { \ register uint32 adrr = GetWORD(PC); \ - PUSH(PC+2); \ + CheckBreakWord(SP - 2); \ + PUSH(PC + 2); \ + PCQ_ENTRY(PC - 1); \ PC = adrr; \ } \ - else \ + else { \ + sim_brk_pend = FALSE; \ PC += 2; \ + } \ } -int32 saved_PC = 0; /* program counter */ -int32 SR = 0; /* switch register */ -int32 PCX; /* External view of PC */ +int32 saved_PC = 0; /* program counter */ +int32 SR = 0; /* switch register */ +int32 PCX; /* External view of PC */ +int32 bankSelect = 0; /* determines selected memory bank */ +uint32 common = 0xc000; /* addresses >= 'common' are in common memory */ extern int32 sim_int_char; extern int32 sim_brk_types, sim_brk_dflt, sim_brk_summ; /* breakpoint info */ +extern int32 sio0s (int32 port, int32 io, int32 data); +extern int32 sio0d (int32 port, int32 io, int32 data); +extern int32 sio1s (int32 port, int32 io, int32 data); +extern int32 sio1d (int32 port, int32 io, int32 data); +extern int32 dsk10 (int32 port, int32 io, int32 data); +extern int32 dsk11 (int32 port, int32 io, int32 data); +extern int32 dsk12 (int32 port, int32 io, int32 data); +extern int32 nulldev (int32 port, int32 io, int32 data); +extern int32 simh_dev (int32 port, int32 io, int32 data); +extern int32 sr_dev (int32 port, int32 io, int32 data); +extern int32 bootrom[bootrom_size]; +extern char memoryAccessMessage[]; /* function prototypes */ - -t_stat cpu_ex (t_value *vptr, t_addr addr, UNIT *uptr, int32 sw); -t_stat cpu_dep (t_value val, t_addr addr, UNIT *uptr, int32 sw); -t_stat cpu_reset (DEVICE *dptr); -t_stat cpu_svc (UNIT *uptr); -t_stat cpu_set_size (UNIT *uptr, int32 val, char *cptr, void *desc); +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_banked(UNIT *uptr, int32 value, char *cptr, void *desc); +t_stat cpu_set_rom(UNIT *uptr, int32 value, char *cptr, void *desc); +uint32 in(uint32 Port); +void out(uint32 Port, uint32 Value); +uint8 GetBYTE(register uint32 Addr); +void PutBYTE(register uint32 Addr, register uint32 Value); +void PutBYTEForced(register uint32 Addr, register uint32 Value); +uint16 GetWORD(register uint32 a); +void PutWORD(register uint32 a, register uint32 v); +int32 sim_instr (void); +void install_bootrom(void); void clear_memory(int32 starting); +t_bool sim_brk_lookup (t_addr bloc, int32 btyp); +void prepareMemoryAccessMessage(t_addr loc); -extern int32 sio0s(int32 io, int32 data); -extern int32 sio0d(int32 io, int32 data); -extern int32 sio1s(int32 io, int32 data); -extern int32 sio1d(int32 io, int32 data); -extern int32 dsk10(int32 io, int32 data); -extern int32 dsk11(int32 io, int32 data); -extern int32 dsk12(int32 io, int32 data); -extern int32 nulldev(int32 io, int32 data); -extern int32 simh_dev(int32 io, int32 data); -extern int32 markTimeSP; +/* in case of using inline we need to ensure that the GetBYTE and PutBYTE + are accessible externally */ +#ifndef NO_INLINE +uint8 GetBYTEWrapper(register uint32 Addr); +void PutBYTEWrapper(register uint32 Addr, register uint32 Value); +#endif -/* This is the I/O configuration table. There are 255 possible - device addresses, if a device is plugged to a port it's routine - address is here, 'nulldev' means no device is available -*/ -struct idev { - int32 (*routine)(); -}; -struct idev dev_table[256] = { -{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 00 */ -{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 04 */ -{&dsk10}, {&dsk11}, {&dsk12}, {&nulldev}, /* 08 */ -{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 0C */ -{&sio0s}, {&sio0d}, {&sio1s}, {&sio1d}, /* 10 */ -{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 14 */ -{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 18 */ -{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 1C */ -{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 20 */ -{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 24 */ -{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 28 */ -{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 2C */ -{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 30 */ -{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 34 */ -{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 38 */ -{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 3C */ -{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 40 */ -{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 44 */ -{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 48 */ -{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 4C */ -{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 50 */ -{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 54 */ -{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 58 */ -{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 5C */ -{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 60 */ -{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 64 */ -{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 68 */ -{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 6C */ -{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 70 */ -{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 74 */ -{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 78 */ -{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 7C */ -{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 80 */ -{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 84 */ -{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 88 */ -{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 8C */ -{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 90 */ -{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 94 */ -{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 98 */ -{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 9C */ -{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* A0 */ -{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* A4 */ -{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* A8 */ -{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* AC */ -{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* B0 */ -{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* B4 */ -{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* B8 */ -{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* BC */ -{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* C0 */ -{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* C4 */ -{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* C8 */ -{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* CC */ -{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* D0 */ -{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* D4 */ -{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* D8 */ -{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* DC */ -{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* D0 */ -{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* E4 */ -{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* E8 */ -{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* EC */ -{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* F0 */ -{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* F4 */ -{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* F8 */ -{&nulldev}, {&nulldev}, {&simh_dev}, {&nulldev} }; /* FC */ - -/* Altair MITS modified BOOT EPROM, fits in upper 256 byte of memory */ - -int32 bootrom[bootrom_size] = { - 0x21, 0x00, 0x5c, 0x11, 0x13, 0xff, 0x0e, 0xb9, /* ff00-ff07 */ - 0x1a, 0x77, 0x13, 0x23, 0x0d, 0xc2, 0x08, 0xff, /* ff08-ff0f */ - 0xc3, 0x00, 0x5c, 0x31, 0xa6, 0x5d, 0xaf, 0xd3, /* ff10-ff17 */ - 0x08, 0x3e, 0x04, 0xd3, 0x09, 0xc3, 0x18, 0x5c, /* ff18-ff1f */ - 0xdb, 0x08, 0xe6, 0x02, 0xc2, 0x0d, 0x5c, 0x3e, /* ff20-ff27 */ - 0x02, 0xd3, 0x09, 0xdb, 0x08, 0xe6, 0x40, 0xc2, /* ff28-ff2f */ - 0x0d, 0x5c, 0x11, 0x00, 0x00, 0x06, 0x08, 0xc3, /* ff30-ff37 */ - 0x29, 0x5c, 0x06, 0x00, 0x3e, 0x10, 0xf5, 0xd5, /* ff38-ff3f */ - 0xc5, 0xd5, 0x11, 0x86, 0x80, 0x21, 0xb9, 0x5c, /* ff40-ff47 */ - 0xdb, 0x09, 0x1f, 0xda, 0x35, 0x5c, 0xe6, 0x1f, /* ff48-ff4f */ - 0xb8, 0xc2, 0x35, 0x5c, 0xdb, 0x08, 0xb7, 0xfa, /* ff50-ff57 */ - 0x41, 0x5c, 0xdb, 0x0a, 0x77, 0x23, 0x1d, 0xca, /* ff58-ff5f */ - 0x57, 0x5c, 0x1d, 0xdb, 0x0a, 0x77, 0x23, 0xc2, /* ff60-ff67 */ - 0x41, 0x5c, 0xe1, 0x11, 0xbc, 0x5c, 0x01, 0x80, /* ff68-ff6f */ - 0x00, 0x1a, 0x77, 0xbe, 0x80, 0x47, 0x13, 0x23, /* ff70-ff77 */ - 0x0d, 0xc2, 0x5e, 0x5c, 0x1a, 0xfe, 0xff, 0xc2, /* ff78-ff7f */ - 0x72, 0x5c, 0x13, 0x1a, 0xb8, 0xc1, 0xeb, 0xc2, /* ff80-ff87 */ - 0xac, 0x5c, 0xf1, 0xf1, 0x2a, 0xba, 0x5c, 0xd5, /* ff88-ff8f */ - 0x11, 0x00, 0x5c, 0xcd, 0xb3, 0x5c, 0xd1, 0xcd, /* ff90-ff97 */ - 0xb3, 0x5c, 0xd2, 0xa5, 0x5c, 0x04, 0x04, 0x78, /* ff98-ff9f */ - 0xfe, 0x20, 0xda, 0x29, 0x5c, 0x06, 0x01, 0xca, /* ffa0-ffa7 */ - 0x29, 0x5c, 0xdb, 0x08, 0xe6, 0x02, 0xc2, 0x97, /* ffa8-ffaf */ - 0x5c, 0x3e, 0x01, 0xd3, 0x09, 0xc3, 0x27, 0x5c, /* ffb0-ffb7 */ - 0x3e, 0x80, 0xd3, 0x08, 0xc3, 0x00, 0x00, 0xd1, /* ffb8-ffbf */ - 0xf1, 0x3d, 0xc2, 0x2b, 0x5c, 0x76, 0x7a, 0xbc, /* ffc0-ffc7 */ - 0xc0, 0x7b, 0xbd, 0xc9, 0x00, 0x00, 0x00, 0x00, /* ffc8-ffcf */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* ffd0-ffd7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* ffd8-ffdf */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* ffe0-ffe7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* ffe8-ffef */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* fff0-fff7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 /* fff8-ffff */ -}; - -/* CPU data structures - cpu_dev CPU device descriptor - cpu_unit CPU unit descriptor - cpu_reg CPU register list - cpu_mod CPU modifiers list +/* CPU data structures + cpu_dev CPU device descriptor + cpu_unit CPU unit descriptor + cpu_reg CPU register list + cpu_mod CPU modifiers list */ -UNIT cpu_unit = { UDATA (NULL, UNIT_FIX + UNIT_BINK, MAXMEMSIZE) }; +UNIT cpu_unit = { UDATA (NULL, UNIT_FIX + UNIT_BINK + UNIT_ROM, MAXMEMSIZE) }; int32 AF_S; int32 BC_S; @@ -254,6 +202,9 @@ int32 DE1_S; int32 HL1_S; int32 IFF_S; int32 INT_S; +uint16 pcq[PCQ_SIZE] = { 0 }; /* PC queue */ +int32 pcq_p = 0; /* PC queue ptr */ +REG *pcq_r = NULL; /* PC queue reg ptr */ REG cpu_reg[] = { { HRDATA (PC, saved_PC, 16) }, @@ -268,30 +219,37 @@ REG cpu_reg[] = { { HRDATA (BC1, BC1_S, 16) }, { HRDATA (DE1, DE1_S, 16) }, { HRDATA (HL1, HL1_S, 16) }, - { FLDATA (IFF, IFF_S, 8) }, + { GRDATA (IFF, IFF_S, 2, 2, 0) }, { FLDATA (INT, INT_S, 8) }, { FLDATA (Z80, cpu_unit.flags, UNIT_V_CHIP), REG_HRO }, { FLDATA (OPSTOP, cpu_unit.flags, UNIT_V_OPSTOP), REG_HRO }, { HRDATA (SR, SR, 8) }, + { HRDATA (BANK, bankSelect, MAXBANKSLOG2) }, + { HRDATA (COMMON, common, 16) }, + { BRDATA (PCQ, pcq, 16, 16, PCQ_SIZE), REG_RO + REG_CIRC }, + { DRDATA (PCQP, pcq_p, 6), REG_HRO }, { HRDATA (WRU, sim_int_char, 8) }, - { DRDATA (MARK, markTimeSP, 3), REG_RO }, { NULL } }; MTAB cpu_mod[] = { - { UNIT_CHIP, UNIT_CHIP, "Z80", "Z80", NULL }, - { UNIT_CHIP, 0, "8080", "8080", NULL }, - { UNIT_OPSTOP, UNIT_OPSTOP, "ITRAP", "ITRAP", NULL }, - { UNIT_OPSTOP, 0, "NOITRAP", "NOITRAP", NULL }, - { UNIT_MSIZE, 4*KB, NULL, "4K", &cpu_set_size }, - { UNIT_MSIZE, 8*KB, NULL, "8K", &cpu_set_size }, - { UNIT_MSIZE, 12*KB, NULL, "12K", &cpu_set_size }, - { UNIT_MSIZE, 16*KB, NULL, "16K", &cpu_set_size }, - { UNIT_MSIZE, 20*KB, NULL, "20K", &cpu_set_size }, - { UNIT_MSIZE, 24*KB, NULL, "24K", &cpu_set_size }, - { UNIT_MSIZE, 28*KB, NULL, "28K", &cpu_set_size }, - { UNIT_MSIZE, 32*KB, NULL, "32K", &cpu_set_size }, - { UNIT_MSIZE, 48*KB, NULL, "48K", &cpu_set_size }, - { UNIT_MSIZE, 64*KB, NULL, "64K", &cpu_set_size }, + { UNIT_CHIP, UNIT_CHIP, "Z80", "Z80", NULL }, + { UNIT_CHIP, 0, "8080", "8080", NULL }, + { UNIT_OPSTOP, UNIT_OPSTOP, "ITRAP", "ITRAP", NULL }, + { UNIT_OPSTOP, 0, "NOITRAP", "NOITRAP", NULL }, + { UNIT_BANKED, UNIT_BANKED, "BANKED", "BANKED", &cpu_set_banked }, + { UNIT_BANKED, 0, "NONBANKED", "NONBANKED", NULL }, + { UNIT_ROM, UNIT_ROM, "ROM", "ROM", &cpu_set_rom }, + { UNIT_ROM, 0, "NOROM", "NOROM", NULL }, + { UNIT_MSIZE, 4 * KB, NULL, "4K", &cpu_set_size }, + { UNIT_MSIZE, 8 * KB, NULL, "8K", &cpu_set_size }, + { UNIT_MSIZE, 12 * KB, NULL, "12K", &cpu_set_size }, + { UNIT_MSIZE, 16 * KB, NULL, "16K", &cpu_set_size }, + { UNIT_MSIZE, 20 * KB, NULL, "20K", &cpu_set_size }, + { UNIT_MSIZE, 24 * KB, NULL, "24K", &cpu_set_size }, + { UNIT_MSIZE, 28 * KB, NULL, "28K", &cpu_set_size }, + { UNIT_MSIZE, 32 * KB, NULL, "32K", &cpu_set_size }, + { UNIT_MSIZE, 48 * KB, NULL, "48K", &cpu_set_size }, + { UNIT_MSIZE, 64 * KB, NULL, "64K", &cpu_set_size }, { 0 } }; DEVICE cpu_dev = { @@ -300,49 +258,260 @@ DEVICE cpu_dev = { &cpu_ex, &cpu_dep, &cpu_reset, NULL, NULL, NULL }; -void out(uint32 Port, uint8 Value) { - dev_table[Port].routine(1, Value); -} +/* data structure for IN/OUT instructions */ +struct idev { + int32 (*routine)(int32, int32, int32); +}; -int in(uint32 Port) { - return Port == 0xFF ? SR & 0xFF : dev_table[Port].routine(0, 0); -} - -inline uint8 GetBYTE(register uint16 a) { - return a < MEMSIZE ? M[a] : 0xff; -} - -#define RAM_mm(a) GetBYTE(a--) -#define RAM_pp(a) GetBYTE(a++) - -inline void PutBYTE(register uint16 Addr, register uint8 Value) { - if ((Addr < MEMSIZE) && (Addr < bootrom_origin)) { - M[Addr] = Value; - } -/* - else { - printf("R/O M[%x]:=%x\n", Addr, Value); - } +/* This is the I/O configuration table. There are 255 possible + device addresses, if a device is plugged to a port it's routine + address is here, 'nulldev' means no device is available */ +struct idev dev_table[256] = { +{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 00 */ +{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 04 */ +{&dsk10}, {&dsk11}, {&dsk12}, {&nulldev}, /* 08 */ +{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 0C */ +{&sio0s}, {&sio0d}, {&sio1s}, {&sio1d}, /* 10 */ +{&sio0s}, {&sio0d}, {&sio0s}, {&sio0d}, /* 14 */ +{&sio0s}, {&sio0d}, {&nulldev}, {&nulldev}, /* 18 */ +{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 1C */ +{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 20 */ +{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 24 */ +{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 28 */ +{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 2C */ +{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 30 */ +{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 34 */ +{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 38 */ +{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 3C */ +{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 40 */ +{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 44 */ +{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 48 */ +{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 4C */ +{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 50 */ +{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 54 */ +{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 58 */ +{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 5C */ +{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 60 */ +{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 64 */ +{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 68 */ +{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 6C */ +{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 70 */ +{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 74 */ +{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 78 */ +{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 7C */ +{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 80 */ +{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 84 */ +{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 88 */ +{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 8C */ +{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 90 */ +{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 94 */ +{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 98 */ +{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 9C */ +{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* A0 */ +{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* A4 */ +{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* A8 */ +{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* AC */ +{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* B0 */ +{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* B4 */ +{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* B8 */ +{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* BC */ +{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* C0 */ +{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* C4 */ +{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* C8 */ +{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* CC */ +{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* D0 */ +{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* D4 */ +{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* D8 */ +{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* DC */ +{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* D0 */ +{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* E4 */ +{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* E8 */ +{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* EC */ +{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* F0 */ +{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* F4 */ +{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* F8 */ +{&nulldev}, {&nulldev}, {&simh_dev}, {&sr_dev} }; /* FC */ + +INLINE void out(uint32 Port, uint32 Value) { + dev_table[Port].routine(Port, 1, Value); } +INLINE uint32 in(uint32 Port) { + return dev_table[Port].routine(Port, 0, 0); +} + +INLINE uint8 GetBYTE(register uint32 Addr) { + Addr &= ADDRMASK; /* registers are NOT guaranteed to be always 16-bit values */ + if (cpu_unit.flags & UNIT_BANKED) { + return Addr < common ? M[Addr][bankSelect] : M[Addr][0]; + } + else { + return ((Addr < MEMSIZE) || (bootrom_origin <= Addr)) ? M[Addr][0] : 0xff; + } +} + +INLINE void PutBYTE(register uint32 Addr, register uint32 Value) { + Addr &= ADDRMASK; /* registers are NOT guaranteed to be always 16-bit values */ + if (cpu_unit.flags & UNIT_BANKED) { + if (Addr < common) { + M[Addr][bankSelect] = Value; + } + else if ((Addr < bootrom_origin) || ((cpu_unit.flags & UNIT_ROM) == 0)) { + M[Addr][0] = Value; + } + } + else { + if ((Addr < MEMSIZE) && ((Addr < bootrom_origin) || ((cpu_unit.flags & UNIT_ROM) == 0))) { + M[Addr][0] = Value; + } + } +} + +void PutBYTEForced(register uint32 Addr, register uint32 Value) { + Addr &= ADDRMASK; /* registers are NOT guaranteed to be always 16-bit values */ + if (cpu_unit.flags & UNIT_BANKED) { + if (Addr < common) { + M[Addr][bankSelect] = Value; + } + else { + M[Addr][0] = Value; + } + } + else { + M[Addr][0] = Value; + } +} + +INLINE void PutWORD(register uint32 Addr, register uint32 Value) { + Addr &= ADDRMASK; /* registers are NOT guaranteed to be always 16-bit values */ + if (cpu_unit.flags & UNIT_BANKED) { + if (Addr < common) { + M[Addr][bankSelect] = Value; + } + else if ((Addr < bootrom_origin) || ((cpu_unit.flags & UNIT_ROM) == 0)) { + M[Addr][0] = Value; + } + Addr = (Addr + 1) & ADDRMASK; + if (Addr < common) { + M[Addr][bankSelect] = Value >> 8; + } + else if ((Addr < bootrom_origin) || ((cpu_unit.flags & UNIT_ROM) == 0)) { + M[Addr][0] = Value >> 8; + } + } + else { + if ((Addr < MEMSIZE) && ((Addr < bootrom_origin) || ((cpu_unit.flags & UNIT_ROM) == 0))) { + M[Addr][0] = Value; + } + Addr = (Addr + 1) & ADDRMASK; + if ((Addr < MEMSIZE) && ((Addr < bootrom_origin) || ((cpu_unit.flags & UNIT_ROM) == 0))) { + M[Addr][0] = Value >> 8; + } + } +} + +#ifndef NO_INLINE +uint8 GetBYTEWrapper(register uint32 Addr) { /* make sure that non-inlined version exists */ + return GetBYTE(Addr); +} + +void PutBYTEWrapper(register uint32 Addr, register uint32 Value) { + PutBYTE(Addr, Value); +} +#endif + +#define RAM_mm(a) GetBYTE(a--) +#define RAM_pp(a) GetBYTE(a++) + #define PutBYTE_pp(a,v) PutBYTE(a++, v) #define PutBYTE_mm(a,v) PutBYTE(a--, v) #define mm_PutBYTE(a,v) PutBYTE(--a, v) -inline uint16 GetWORD(register uint16 a) {return (GetBYTE(a) | (GetBYTE((a)+1) << 8));} -inline void PutWORD(register uint16 a, register uint16 v) { - PutBYTE(a, (uint8)(v)); - PutBYTE(a+1, v>>8); +INLINE uint16 GetWORD(register uint32 a) { + return GetBYTE(a) | (GetBYTE(a + 1) << 8); } -#define PUSH(x) do { \ - mm_PutBYTE(SP, (x) >> 8); \ - mm_PutBYTE(SP, x); \ +#define MASK_BRK (TRUE+1) + +/* repeated from scp.c */ +struct brktab { + t_addr addr; + int32 typ; + int32 cnt; + char *act; +}; +typedef struct brktab BRKTAB; + +/* this is a modified version of sim_brk_test with two differences: + 1) is does not set sim_brk_pend to FALSE (this if left to the instruction decode) + 2) it returns MASK_BRK if a breakpoint is found but should be ignored +*/ +int32 sim_brk_lookup (t_addr loc, int32 btyp) { + extern BRKTAB *sim_brk_fnd (t_addr loc); + extern t_bool sim_brk_pend; + extern t_addr sim_brk_ploc; + BRKTAB *bp; + if ((bp = sim_brk_fnd (loc)) && + (btyp & bp -> typ) && + (!sim_brk_pend || (loc != sim_brk_ploc)) && + (--(bp -> cnt) <= 0)) { + bp -> cnt = 0; + sim_brk_ploc = loc; + sim_brk_pend = TRUE; + return TRUE; + } + return (sim_brk_pend && (loc == sim_brk_ploc)) ? MASK_BRK : FALSE; +} + +void prepareMemoryAccessMessage(t_addr loc) { + sprintf(memoryAccessMessage, "Memory access breakpoint [%04xh]", loc); +} + +#define PUSH(x) do { \ + mm_PutBYTE(SP, (x) >> 8); \ + mm_PutBYTE(SP, x); \ } while (0) +#define CheckBreakByte(a) \ + if (sim_brk_summ && sim_brk_test(a, SWMASK('M'))) { \ + reason = STOP_MEM; \ + prepareMemoryAccessMessage(a); \ + goto end_decode; \ + } + +#define CheckBreakTwoBytesExtended(a1, a2, iCode) \ + if (sim_brk_summ) { \ + br1 = sim_brk_lookup(a1, SWMASK('M')); \ + br2 = br1 ? FALSE : sim_brk_lookup(a2, SWMASK('M')); \ + if ((br1 == MASK_BRK) || (br2 == MASK_BRK)) { \ + sim_brk_pend = FALSE; \ + } \ + else if (br1 || br2) { \ + reason = STOP_MEM; \ + if (br1) { \ + prepareMemoryAccessMessage(a1); \ + } \ + else { \ + prepareMemoryAccessMessage(a2); \ + } \ + iCode; \ + goto end_decode; \ + } \ + else { \ + sim_brk_pend = FALSE; \ + } \ + } + +#define CheckBreakTwoBytes(a1, a2) CheckBreakTwoBytesExtended(a1, a2,;) + +#define CheckBreakWord(a) CheckBreakTwoBytes(a, (a+1)) + int32 sim_instr (void) { extern int32 sim_interval; + extern t_bool sim_brk_pend; + extern int32 timerInterrupt; + extern int32 timerInterruptHandler; int32 reason = 0; register uint32 AF; register uint32 BC; @@ -354,8 +523,7 @@ int32 sim_instr (void) { register uint32 IY; register uint32 temp, acu, sum, cbits; register uint32 op, adr; - int32 BadZ80OpOccured = 0; - int32 Bad8080OpOccured = 0; + int32 br1, br2; pc = saved_PC & ADDRMASK; /* load local PC */ af[af_sel] = AF_S; @@ -365,10 +533,10 @@ int32 sim_instr (void) { ix = IX_S; iy = IY_S; sp = SP_S; - af[1-af_sel] = AF1_S; - regs[1-regs_sel].bc = BC1_S; - regs[1-regs_sel].de = DE1_S; - regs[1-regs_sel].hl = HL1_S; + af[1 - af_sel] = AF1_S; + regs[1 - regs_sel].bc = BC1_S; + regs[1 - regs_sel].de = DE1_S; + regs[1 - regs_sel].hl = HL1_S; IFF = IFF_S; ir = INT_S; @@ -382,35 +550,53 @@ int32 sim_instr (void) { IY = iy; /* Main instruction fetch/decode loop */ - while (reason == 0) { /* loop until halted */ - if (sim_interval <= 0) { /* check clock queue */ - if (reason = sim_process_event ()) { + while (TRUE) { /* loop until halted */ + if (sim_interval <= 0) { /* check clock queue */ + if (reason = sim_process_event()) { break; } } - if (sim_brk_summ && - sim_brk_test (PC, SWMASK ('E'))) { /* breakpoint? */ - reason = STOP_IBKPT; /* stop simulation */ + if (timerInterrupt && (IFF & 1)) { + timerInterrupt = FALSE; + IFF = 0; /* disable interrupts */ + CheckBreakTwoBytesExtended(SP - 2, SP - 1, (timerInterrupt = TRUE, IFF |= 1)); + PUSH(PC); + PCQ_ENTRY(PC - 1); + PC = timerInterruptHandler & ADDRMASK; + } + + if (sim_brk_summ && (sim_brk_lookup(PC, SWMASK('E')) == TRUE)) { /* breakpoint? */ + reason = STOP_IBKPT; /* stop simulation */ break; } PCX = PC; sim_interval--; - switch(RAM_pp(PC)) { + + /* make sure that each instructions properly sets sim_brk_pend: + 1) Either directly to FALSE if no memory access takes place or + 2) through a call to a Check... routine + */ + switch(RAM_pp(PC)) { case 0x00: /* NOP */ + sim_brk_pend = FALSE; break; case 0x01: /* LD BC,nnnn */ + sim_brk_pend = FALSE; BC = GetWORD(PC); PC += 2; break; case 0x02: /* LD (BC),A */ + CheckBreakByte(BC) PutBYTE(BC, hreg(AF)); break; case 0x03: /* INC BC */ + sim_brk_pend = FALSE; ++BC; break; case 0x04: /* INC B */ + sim_brk_pend = FALSE; BC += 0x100; temp = hreg(BC); AF = (AF & ~0xfe) | (temp & 0xa8) | @@ -419,6 +605,7 @@ int32 sim_instr (void) { SetPV2(0x80); break; case 0x05: /* DEC B */ + sim_brk_pend = FALSE; BC -= 0x100; temp = hreg(BC); AF = (AF & ~0xfe) | (temp & 0xa8) | @@ -427,73 +614,94 @@ int32 sim_instr (void) { SetPV2(0x7f) | 2; break; case 0x06: /* LD B,nn */ + sim_brk_pend = FALSE; Sethreg(BC, RAM_pp(PC)); break; case 0x07: /* RLCA */ + sim_brk_pend = FALSE; AF = ((AF >> 7) & 0x0128) | ((AF << 1) & ~0x1ff) | (AF & 0xc4) | ((AF >> 15) & 1); break; case 0x08: /* EX AF,AF' */ - checkCPU + sim_brk_pend = FALSE; + checkCPU8080; af[af_sel] = AF; af_sel = 1 - af_sel; AF = af[af_sel]; break; case 0x09: /* ADD HL,BC */ - HL &= 0xffff; - BC &= 0xffff; + sim_brk_pend = FALSE; + HL &= ADDRMASK; + BC &= ADDRMASK; sum = HL + BC; cbits = (HL ^ BC ^ sum) >> 8; HL = sum; AF = (AF & ~0x3b) | ((sum >> 8) & 0x28) | (cbits & 0x10) | ((cbits >> 8) & 1); break; - case 0x0A: /* LD A,(BC) */ + case 0x0a: /* LD A,(BC) */ + CheckBreakByte(BC) Sethreg(AF, GetBYTE(BC)); break; - case 0x0B: /* DEC BC */ + case 0x0b: /* DEC BC */ + sim_brk_pend = FALSE; --BC; break; - case 0x0C: /* INC C */ - temp = lreg(BC)+1; + case 0x0c: /* INC C */ + sim_brk_pend = FALSE; + temp = lreg(BC) + 1; Setlreg(BC, temp); AF = (AF & ~0xfe) | (temp & 0xa8) | (((temp & 0xff) == 0) << 6) | (((temp & 0xf) == 0) << 4) | SetPV2(0x80); break; - case 0x0D: /* DEC C */ - temp = lreg(BC)-1; + case 0x0d: /* DEC C */ + sim_brk_pend = FALSE; + temp = lreg(BC) - 1; Setlreg(BC, temp); AF = (AF & ~0xfe) | (temp & 0xa8) | (((temp & 0xff) == 0) << 6) | (((temp & 0xf) == 0xf) << 4) | SetPV2(0x7f) | 2; break; - case 0x0E: /* LD C,nn */ + case 0x0e: /* LD C,nn */ + sim_brk_pend = FALSE; Setlreg(BC, RAM_pp(PC)); break; - case 0x0F: /* RRCA */ + case 0x0f: /* RRCA */ + sim_brk_pend = FALSE; temp = hreg(AF); sum = temp >> 1; AF = ((temp & 1) << 15) | (sum << 8) | (sum & 0x28) | (AF & 0xc4) | (temp & 1); break; case 0x10: /* DJNZ dd */ - checkCPU - PC += ((BC -= 0x100) & 0xff00) ? (signed char) GetBYTE(PC) + 1 : 1; + sim_brk_pend = FALSE; + checkCPU8080; + if ((BC -= 0x100) & 0xff00) { + PCQ_ENTRY(PC - 1); + PC += (signed char) GetBYTE(PC) + 1; + } + else { + PC++; + } break; case 0x11: /* LD DE,nnnn */ + sim_brk_pend = FALSE; DE = GetWORD(PC); PC += 2; break; case 0x12: /* LD (DE),A */ + CheckBreakByte(DE) PutBYTE(DE, hreg(AF)); break; case 0x13: /* INC DE */ + sim_brk_pend = FALSE; ++DE; break; case 0x14: /* INC D */ + sim_brk_pend = FALSE; DE += 0x100; temp = hreg(DE); AF = (AF & ~0xfe) | (temp & 0xa8) | @@ -502,6 +710,7 @@ int32 sim_instr (void) { SetPV2(0x80); break; case 0x15: /* DEC D */ + sim_brk_pend = FALSE; DE -= 0x100; temp = hreg(DE); AF = (AF & ~0xfe) | (temp & 0xa8) | @@ -510,73 +719,95 @@ int32 sim_instr (void) { SetPV2(0x7f) | 2; break; case 0x16: /* LD D,nn */ + sim_brk_pend = FALSE; Sethreg(DE, RAM_pp(PC)); break; case 0x17: /* RLA */ + sim_brk_pend = FALSE; AF = ((AF << 8) & 0x0100) | ((AF >> 7) & 0x28) | ((AF << 1) & ~0x01ff) | (AF & 0xc4) | ((AF >> 15) & 1); break; case 0x18: /* JR dd */ - checkCPU - PC += (1) ? (signed char) GetBYTE(PC) + 1 : 1; + sim_brk_pend = FALSE; + checkCPU8080; + PCQ_ENTRY(PC - 1); + PC += (signed char) GetBYTE(PC) + 1; break; case 0x19: /* ADD HL,DE */ - HL &= 0xffff; - DE &= 0xffff; + sim_brk_pend = FALSE; + HL &= ADDRMASK; + DE &= ADDRMASK; sum = HL + DE; cbits = (HL ^ DE ^ sum) >> 8; HL = sum; AF = (AF & ~0x3b) | ((sum >> 8) & 0x28) | (cbits & 0x10) | ((cbits >> 8) & 1); break; - case 0x1A: /* LD A,(DE) */ + case 0x1a: /* LD A,(DE) */ + CheckBreakByte(DE) Sethreg(AF, GetBYTE(DE)); break; - case 0x1B: /* DEC DE */ + case 0x1b: /* DEC DE */ + sim_brk_pend = FALSE; --DE; break; - case 0x1C: /* INC E */ - temp = lreg(DE)+1; + case 0x1c: /* INC E */ + sim_brk_pend = FALSE; + temp = lreg(DE) + 1; Setlreg(DE, temp); AF = (AF & ~0xfe) | (temp & 0xa8) | (((temp & 0xff) == 0) << 6) | (((temp & 0xf) == 0) << 4) | SetPV2(0x80); break; - case 0x1D: /* DEC E */ - temp = lreg(DE)-1; + case 0x1d: /* DEC E */ + sim_brk_pend = FALSE; + temp = lreg(DE) - 1; Setlreg(DE, temp); AF = (AF & ~0xfe) | (temp & 0xa8) | (((temp & 0xff) == 0) << 6) | (((temp & 0xf) == 0xf) << 4) | SetPV2(0x7f) | 2; break; - case 0x1E: /* LD E,nn */ + case 0x1e: /* LD E,nn */ + sim_brk_pend = FALSE; Setlreg(DE, RAM_pp(PC)); break; - case 0x1F: /* RRA */ + case 0x1f: /* RRA */ + sim_brk_pend = FALSE; temp = hreg(AF); sum = temp >> 1; AF = ((AF & 1) << 15) | (sum << 8) | (sum & 0x28) | (AF & 0xc4) | (temp & 1); break; case 0x20: /* JR NZ,dd */ - checkCPU - PC += (!TSTFLAG(Z)) ? (signed char) GetBYTE(PC) + 1 : 1; + sim_brk_pend = FALSE; + checkCPU8080; + if (TSTFLAG(Z)) { + PC++; + } + else { + PCQ_ENTRY(PC - 1); + PC += (signed char) GetBYTE(PC) + 1; + } break; case 0x21: /* LD HL,nnnn */ + sim_brk_pend = FALSE; HL = GetWORD(PC); PC += 2; break; case 0x22: /* LD (nnnn),HL */ temp = GetWORD(PC); + CheckBreakWord(temp); PutWORD(temp, HL); PC += 2; break; case 0x23: /* INC HL */ + sim_brk_pend = FALSE; ++HL; break; case 0x24: /* INC H */ + sim_brk_pend = FALSE; HL += 0x100; temp = hreg(HL); AF = (AF & ~0xfe) | (temp & 0xa8) | @@ -585,6 +816,7 @@ int32 sim_instr (void) { SetPV2(0x80); break; case 0x25: /* DEC H */ + sim_brk_pend = FALSE; HL -= 0x100; temp = hreg(HL); AF = (AF & ~0xfe) | (temp & 0xa8) | @@ -593,30 +825,35 @@ int32 sim_instr (void) { SetPV2(0x7f) | 2; break; case 0x26: /* LD H,nn */ + sim_brk_pend = FALSE; Sethreg(HL, RAM_pp(PC)); break; case 0x27: /* DAA */ + sim_brk_pend = FALSE; acu = hreg(AF); temp = ldig(acu); cbits = TSTFLAG(C); if (TSTFLAG(N)) { /* last operation was a subtract */ int hd = cbits || acu > 0x99; if (TSTFLAG(H) || (temp > 9)) { /* adjust low digit */ - if (temp > 5) + if (temp > 5) { SETFLAG(H, 0); + } acu -= 6; acu &= 0xff; } - if (hd) /* adjust high digit */ + if (hd) { /* adjust high digit */ acu -= 0x160; + } } else { /* last operation was an add */ if (TSTFLAG(H) || (temp > 9)) { /* adjust low digit */ SETFLAG(H, (temp > 9)); acu += 6; } - if (cbits || ((acu & 0x1f0) > 0x90)) /* adjust high digit */ + if (cbits || ((acu & 0x1f0) > 0x90)) { /* adjust high digit */ acu += 0x60; + } } cbits |= (acu >> 8) & 1; acu &= 0xff; @@ -624,65 +861,90 @@ int32 sim_instr (void) { (AF & 0x12) | partab[acu] | cbits; break; case 0x28: /* JR Z,dd */ - checkCPU - PC += (TSTFLAG(Z)) ? (signed char) GetBYTE(PC) + 1 : 1; + sim_brk_pend = FALSE; + checkCPU8080; + if (TSTFLAG(Z)) { + PCQ_ENTRY(PC - 1); + PC += (signed char) GetBYTE(PC) + 1; + } + else { + PC++; + } break; case 0x29: /* ADD HL,HL */ - HL &= 0xffff; + sim_brk_pend = FALSE; + HL &= ADDRMASK; sum = HL + HL; cbits = (HL ^ HL ^ sum) >> 8; HL = sum; AF = (AF & ~0x3b) | ((sum >> 8) & 0x28) | (cbits & 0x10) | ((cbits >> 8) & 1); break; - case 0x2A: /* LD HL,(nnnn) */ + case 0x2a: /* LD HL,(nnnn) */ temp = GetWORD(PC); + CheckBreakWord(temp); HL = GetWORD(temp); PC += 2; break; - case 0x2B: /* DEC HL */ + case 0x2b: /* DEC HL */ + sim_brk_pend = FALSE; --HL; break; - case 0x2C: /* INC L */ - temp = lreg(HL)+1; + case 0x2c: /* INC L */ + sim_brk_pend = FALSE; + temp = lreg(HL) + 1; Setlreg(HL, temp); AF = (AF & ~0xfe) | (temp & 0xa8) | (((temp & 0xff) == 0) << 6) | (((temp & 0xf) == 0) << 4) | SetPV2(0x80); break; - case 0x2D: /* DEC L */ - temp = lreg(HL)-1; + case 0x2d: /* DEC L */ + sim_brk_pend = FALSE; + temp = lreg(HL) - 1; Setlreg(HL, temp); AF = (AF & ~0xfe) | (temp & 0xa8) | (((temp & 0xff) == 0) << 6) | (((temp & 0xf) == 0xf) << 4) | SetPV2(0x7f) | 2; break; - case 0x2E: /* LD L,nn */ + case 0x2e: /* LD L,nn */ + sim_brk_pend = FALSE; Setlreg(HL, RAM_pp(PC)); break; - case 0x2F: /* CPL */ + case 0x2f: /* CPL */ + sim_brk_pend = FALSE; AF = (~AF & ~0xff) | (AF & 0xc5) | ((~AF >> 8) & 0x28) | 0x12; break; case 0x30: /* JR NC,dd */ - checkCPU - PC += (!TSTFLAG(C)) ? (signed char) GetBYTE(PC) + 1 : 1; + sim_brk_pend = FALSE; + checkCPU8080; + if (TSTFLAG(C)) { + PC++; + } + else { + PCQ_ENTRY(PC - 1); + PC += (signed char) GetBYTE(PC) + 1; + } break; case 0x31: /* LD SP,nnnn */ + sim_brk_pend = FALSE; SP = GetWORD(PC); PC += 2; break; case 0x32: /* LD (nnnn),A */ temp = GetWORD(PC); + CheckBreakByte(temp); PutBYTE(temp, hreg(AF)); PC += 2; break; case 0x33: /* INC SP */ + sim_brk_pend = FALSE; ++SP; break; case 0x34: /* INC (HL) */ - temp = GetBYTE(HL)+1; + CheckBreakByte(HL); + temp = GetBYTE(HL) + 1; PutBYTE(HL, temp); AF = (AF & ~0xfe) | (temp & 0xa8) | (((temp & 0xff) == 0) << 6) | @@ -690,7 +952,8 @@ int32 sim_instr (void) { SetPV2(0x80); break; case 0x35: /* DEC (HL) */ - temp = GetBYTE(HL)-1; + CheckBreakByte(HL); + temp = GetBYTE(HL) - 1; PutBYTE(HL, temp); AF = (AF & ~0xfe) | (temp & 0xa8) | (((temp & 0xff) == 0) << 6) | @@ -698,33 +961,46 @@ int32 sim_instr (void) { SetPV2(0x7f) | 2; break; case 0x36: /* LD (HL),nn */ + CheckBreakByte(HL); PutBYTE(HL, RAM_pp(PC)); break; case 0x37: /* SCF */ + sim_brk_pend = FALSE; AF = (AF&~0x3b)|((AF>>8)&0x28)|1; break; case 0x38: /* JR C,dd */ - checkCPU - PC += (TSTFLAG(C)) ? (signed char) GetBYTE(PC) + 1 : 1; + sim_brk_pend = FALSE; + checkCPU8080; + if (TSTFLAG(C)) { + PCQ_ENTRY(PC - 1); + PC += (signed char) GetBYTE(PC) + 1; + } + else { + PC++; + } break; case 0x39: /* ADD HL,SP */ - HL &= 0xffff; - SP &= 0xffff; + sim_brk_pend = FALSE; + HL &= ADDRMASK; + SP &= ADDRMASK; sum = HL + SP; cbits = (HL ^ SP ^ sum) >> 8; HL = sum; AF = (AF & ~0x3b) | ((sum >> 8) & 0x28) | (cbits & 0x10) | ((cbits >> 8) & 1); break; - case 0x3A: /* LD A,(nnnn) */ + case 0x3a: /* LD A,(nnnn) */ temp = GetWORD(PC); + CheckBreakByte(temp); Sethreg(AF, GetBYTE(temp)); PC += 2; break; - case 0x3B: /* DEC SP */ + case 0x3b: /* DEC SP */ + sim_brk_pend = FALSE; --SP; break; - case 0x3C: /* INC A */ + case 0x3c: /* INC A */ + sim_brk_pend = FALSE; AF += 0x100; temp = hreg(AF); AF = (AF & ~0xfe) | (temp & 0xa8) | @@ -732,7 +1008,8 @@ int32 sim_instr (void) { (((temp & 0xf) == 0) << 4) | SetPV2(0x80); break; - case 0x3D: /* DEC A */ + case 0x3d: /* DEC A */ + sim_brk_pend = FALSE; AF -= 0x100; temp = hreg(AF); AF = (AF & ~0xfe) | (temp & 0xa8) | @@ -740,206 +1017,273 @@ int32 sim_instr (void) { (((temp & 0xf) == 0xf) << 4) | SetPV2(0x7f) | 2; break; - case 0x3E: /* LD A,nn */ + case 0x3e: /* LD A,nn */ + sim_brk_pend = FALSE; Sethreg(AF, RAM_pp(PC)); break; - case 0x3F: /* CCF */ + case 0x3f: /* CCF */ + sim_brk_pend = FALSE; AF = (AF&~0x3b)|((AF>>8)&0x28)|((AF&1)<<4)|(~AF&1); break; case 0x40: /* LD B,B */ + sim_brk_pend = FALSE; /* nop */ break; case 0x41: /* LD B,C */ + sim_brk_pend = FALSE; BC = (BC & 255) | ((BC & 255) << 8); break; case 0x42: /* LD B,D */ + sim_brk_pend = FALSE; BC = (BC & 255) | (DE & ~255); break; case 0x43: /* LD B,E */ + sim_brk_pend = FALSE; BC = (BC & 255) | ((DE & 255) << 8); break; case 0x44: /* LD B,H */ + sim_brk_pend = FALSE; BC = (BC & 255) | (HL & ~255); break; case 0x45: /* LD B,L */ + sim_brk_pend = FALSE; BC = (BC & 255) | ((HL & 255) << 8); break; case 0x46: /* LD B,(HL) */ + CheckBreakByte(HL); Sethreg(BC, GetBYTE(HL)); break; case 0x47: /* LD B,A */ + sim_brk_pend = FALSE; BC = (BC & 255) | (AF & ~255); break; case 0x48: /* LD C,B */ + sim_brk_pend = FALSE; BC = (BC & ~255) | ((BC >> 8) & 255); break; case 0x49: /* LD C,C */ + sim_brk_pend = FALSE; /* nop */ break; - case 0x4A: /* LD C,D */ + case 0x4a: /* LD C,D */ + sim_brk_pend = FALSE; BC = (BC & ~255) | ((DE >> 8) & 255); break; - case 0x4B: /* LD C,E */ + case 0x4b: /* LD C,E */ + sim_brk_pend = FALSE; BC = (BC & ~255) | (DE & 255); break; - case 0x4C: /* LD C,H */ + case 0x4c: /* LD C,H */ + sim_brk_pend = FALSE; BC = (BC & ~255) | ((HL >> 8) & 255); break; - case 0x4D: /* LD C,L */ + case 0x4d: /* LD C,L */ + sim_brk_pend = FALSE; BC = (BC & ~255) | (HL & 255); break; - case 0x4E: /* LD C,(HL) */ + case 0x4e: /* LD C,(HL) */ + CheckBreakByte(HL); Setlreg(BC, GetBYTE(HL)); break; - case 0x4F: /* LD C,A */ + case 0x4f: /* LD C,A */ + sim_brk_pend = FALSE; BC = (BC & ~255) | ((AF >> 8) & 255); break; case 0x50: /* LD D,B */ + sim_brk_pend = FALSE; DE = (DE & 255) | (BC & ~255); break; case 0x51: /* LD D,C */ + sim_brk_pend = FALSE; DE = (DE & 255) | ((BC & 255) << 8); break; case 0x52: /* LD D,D */ + sim_brk_pend = FALSE; /* nop */ break; case 0x53: /* LD D,E */ + sim_brk_pend = FALSE; DE = (DE & 255) | ((DE & 255) << 8); break; case 0x54: /* LD D,H */ + sim_brk_pend = FALSE; DE = (DE & 255) | (HL & ~255); break; case 0x55: /* LD D,L */ + sim_brk_pend = FALSE; DE = (DE & 255) | ((HL & 255) << 8); break; case 0x56: /* LD D,(HL) */ + CheckBreakByte(HL); Sethreg(DE, GetBYTE(HL)); break; case 0x57: /* LD D,A */ + sim_brk_pend = FALSE; DE = (DE & 255) | (AF & ~255); break; case 0x58: /* LD E,B */ + sim_brk_pend = FALSE; DE = (DE & ~255) | ((BC >> 8) & 255); break; case 0x59: /* LD E,C */ + sim_brk_pend = FALSE; DE = (DE & ~255) | (BC & 255); break; - case 0x5A: /* LD E,D */ + case 0x5a: /* LD E,D */ + sim_brk_pend = FALSE; DE = (DE & ~255) | ((DE >> 8) & 255); break; - case 0x5B: /* LD E,E */ + case 0x5b: /* LD E,E */ + sim_brk_pend = FALSE; /* nop */ break; - case 0x5C: /* LD E,H */ + case 0x5c: /* LD E,H */ + sim_brk_pend = FALSE; DE = (DE & ~255) | ((HL >> 8) & 255); break; - case 0x5D: /* LD E,L */ + case 0x5d: /* LD E,L */ + sim_brk_pend = FALSE; DE = (DE & ~255) | (HL & 255); break; - case 0x5E: /* LD E,(HL) */ + case 0x5e: /* LD E,(HL) */ + CheckBreakByte(HL); Setlreg(DE, GetBYTE(HL)); break; - case 0x5F: /* LD E,A */ + case 0x5f: /* LD E,A */ + sim_brk_pend = FALSE; DE = (DE & ~255) | ((AF >> 8) & 255); break; case 0x60: /* LD H,B */ + sim_brk_pend = FALSE; HL = (HL & 255) | (BC & ~255); break; case 0x61: /* LD H,C */ + sim_brk_pend = FALSE; HL = (HL & 255) | ((BC & 255) << 8); break; case 0x62: /* LD H,D */ + sim_brk_pend = FALSE; HL = (HL & 255) | (DE & ~255); break; case 0x63: /* LD H,E */ + sim_brk_pend = FALSE; HL = (HL & 255) | ((DE & 255) << 8); break; case 0x64: /* LD H,H */ + sim_brk_pend = FALSE; /* nop */ break; case 0x65: /* LD H,L */ + sim_brk_pend = FALSE; HL = (HL & 255) | ((HL & 255) << 8); break; case 0x66: /* LD H,(HL) */ + CheckBreakByte(HL); Sethreg(HL, GetBYTE(HL)); break; case 0x67: /* LD H,A */ + sim_brk_pend = FALSE; HL = (HL & 255) | (AF & ~255); break; case 0x68: /* LD L,B */ + sim_brk_pend = FALSE; HL = (HL & ~255) | ((BC >> 8) & 255); break; case 0x69: /* LD L,C */ + sim_brk_pend = FALSE; HL = (HL & ~255) | (BC & 255); break; - case 0x6A: /* LD L,D */ + case 0x6a: /* LD L,D */ + sim_brk_pend = FALSE; HL = (HL & ~255) | ((DE >> 8) & 255); break; - case 0x6B: /* LD L,E */ + case 0x6b: /* LD L,E */ + sim_brk_pend = FALSE; HL = (HL & ~255) | (DE & 255); break; - case 0x6C: /* LD L,H */ + case 0x6c: /* LD L,H */ + sim_brk_pend = FALSE; HL = (HL & ~255) | ((HL >> 8) & 255); break; - case 0x6D: /* LD L,L */ + case 0x6d: /* LD L,L */ + sim_brk_pend = FALSE; /* nop */ break; - case 0x6E: /* LD L,(HL) */ + case 0x6e: /* LD L,(HL) */ + CheckBreakByte(HL); Setlreg(HL, GetBYTE(HL)); break; - case 0x6F: /* LD L,A */ + case 0x6f: /* LD L,A */ + sim_brk_pend = FALSE; HL = (HL & ~255) | ((AF >> 8) & 255); break; case 0x70: /* LD (HL),B */ + CheckBreakByte(HL); PutBYTE(HL, hreg(BC)); break; case 0x71: /* LD (HL),C */ + CheckBreakByte(HL); PutBYTE(HL, lreg(BC)); break; case 0x72: /* LD (HL),D */ + CheckBreakByte(HL); PutBYTE(HL, hreg(DE)); break; case 0x73: /* LD (HL),E */ + CheckBreakByte(HL); PutBYTE(HL, lreg(DE)); break; case 0x74: /* LD (HL),H */ + CheckBreakByte(HL); PutBYTE(HL, hreg(HL)); break; case 0x75: /* LD (HL),L */ + CheckBreakByte(HL); PutBYTE(HL, lreg(HL)); break; case 0x76: /* HALT */ + sim_brk_pend = FALSE; reason = STOP_HALT; PC--; - continue; + goto end_decode; case 0x77: /* LD (HL),A */ + CheckBreakByte(HL); PutBYTE(HL, hreg(AF)); break; case 0x78: /* LD A,B */ + sim_brk_pend = FALSE; AF = (AF & 255) | (BC & ~255); break; case 0x79: /* LD A,C */ + sim_brk_pend = FALSE; AF = (AF & 255) | ((BC & 255) << 8); break; - case 0x7A: /* LD A,D */ + case 0x7a: /* LD A,D */ + sim_brk_pend = FALSE; AF = (AF & 255) | (DE & ~255); break; - case 0x7B: /* LD A,E */ + case 0x7b: /* LD A,E */ + sim_brk_pend = FALSE; AF = (AF & 255) | ((DE & 255) << 8); break; - case 0x7C: /* LD A,H */ + case 0x7c: /* LD A,H */ + sim_brk_pend = FALSE; AF = (AF & 255) | (HL & ~255); break; - case 0x7D: /* LD A,L */ + case 0x7d: /* LD A,L */ + sim_brk_pend = FALSE; AF = (AF & 255) | ((HL & 255) << 8); break; - case 0x7E: /* LD A,(HL) */ + case 0x7e: /* LD A,(HL) */ + CheckBreakByte(HL); Sethreg(AF, GetBYTE(HL)); break; - case 0x7F: /* LD A,A */ + case 0x7f: /* LD A,A */ + sim_brk_pend = FALSE; /* nop */ break; case 0x80: /* ADD A,B */ + sim_brk_pend = FALSE; temp = hreg(BC); acu = hreg(AF); sum = acu + temp; @@ -950,6 +1294,7 @@ int32 sim_instr (void) { ((cbits >> 8) & 1); break; case 0x81: /* ADD A,C */ + sim_brk_pend = FALSE; temp = lreg(BC); acu = hreg(AF); sum = acu + temp; @@ -960,6 +1305,7 @@ int32 sim_instr (void) { ((cbits >> 8) & 1); break; case 0x82: /* ADD A,D */ + sim_brk_pend = FALSE; temp = hreg(DE); acu = hreg(AF); sum = acu + temp; @@ -970,6 +1316,7 @@ int32 sim_instr (void) { ((cbits >> 8) & 1); break; case 0x83: /* ADD A,E */ + sim_brk_pend = FALSE; temp = lreg(DE); acu = hreg(AF); sum = acu + temp; @@ -980,6 +1327,7 @@ int32 sim_instr (void) { ((cbits >> 8) & 1); break; case 0x84: /* ADD A,H */ + sim_brk_pend = FALSE; temp = hreg(HL); acu = hreg(AF); sum = acu + temp; @@ -990,6 +1338,7 @@ int32 sim_instr (void) { ((cbits >> 8) & 1); break; case 0x85: /* ADD A,L */ + sim_brk_pend = FALSE; temp = lreg(HL); acu = hreg(AF); sum = acu + temp; @@ -1000,6 +1349,7 @@ int32 sim_instr (void) { ((cbits >> 8) & 1); break; case 0x86: /* ADD A,(HL) */ + CheckBreakByte(HL); temp = GetBYTE(HL); acu = hreg(AF); sum = acu + temp; @@ -1010,6 +1360,7 @@ int32 sim_instr (void) { ((cbits >> 8) & 1); break; case 0x87: /* ADD A,A */ + sim_brk_pend = FALSE; temp = hreg(AF); acu = hreg(AF); sum = acu + temp; @@ -1020,6 +1371,7 @@ int32 sim_instr (void) { ((cbits >> 8) & 1); break; case 0x88: /* ADC A,B */ + sim_brk_pend = FALSE; temp = hreg(BC); acu = hreg(AF); sum = acu + temp + TSTFLAG(C); @@ -1030,6 +1382,7 @@ int32 sim_instr (void) { ((cbits >> 8) & 1); break; case 0x89: /* ADC A,C */ + sim_brk_pend = FALSE; temp = lreg(BC); acu = hreg(AF); sum = acu + temp + TSTFLAG(C); @@ -1039,7 +1392,8 @@ int32 sim_instr (void) { (SetPV) | ((cbits >> 8) & 1); break; - case 0x8A: /* ADC A,D */ + case 0x8a: /* ADC A,D */ + sim_brk_pend = FALSE; temp = hreg(DE); acu = hreg(AF); sum = acu + temp + TSTFLAG(C); @@ -1049,7 +1403,8 @@ int32 sim_instr (void) { (SetPV) | ((cbits >> 8) & 1); break; - case 0x8B: /* ADC A,E */ + case 0x8b: /* ADC A,E */ + sim_brk_pend = FALSE; temp = lreg(DE); acu = hreg(AF); sum = acu + temp + TSTFLAG(C); @@ -1059,7 +1414,8 @@ int32 sim_instr (void) { (SetPV) | ((cbits >> 8) & 1); break; - case 0x8C: /* ADC A,H */ + case 0x8c: /* ADC A,H */ + sim_brk_pend = FALSE; temp = hreg(HL); acu = hreg(AF); sum = acu + temp + TSTFLAG(C); @@ -1069,7 +1425,8 @@ int32 sim_instr (void) { (SetPV) | ((cbits >> 8) & 1); break; - case 0x8D: /* ADC A,L */ + case 0x8d: /* ADC A,L */ + sim_brk_pend = FALSE; temp = lreg(HL); acu = hreg(AF); sum = acu + temp + TSTFLAG(C); @@ -1079,7 +1436,8 @@ int32 sim_instr (void) { (SetPV) | ((cbits >> 8) & 1); break; - case 0x8E: /* ADC A,(HL) */ + case 0x8e: /* ADC A,(HL) */ + CheckBreakByte(HL); temp = GetBYTE(HL); acu = hreg(AF); sum = acu + temp + TSTFLAG(C); @@ -1089,7 +1447,8 @@ int32 sim_instr (void) { (SetPV) | ((cbits >> 8) & 1); break; - case 0x8F: /* ADC A,A */ + case 0x8f: /* ADC A,A */ + sim_brk_pend = FALSE; temp = hreg(AF); acu = hreg(AF); sum = acu + temp + TSTFLAG(C); @@ -1100,6 +1459,7 @@ int32 sim_instr (void) { ((cbits >> 8) & 1); break; case 0x90: /* SUB B */ + sim_brk_pend = FALSE; temp = hreg(BC); acu = hreg(AF); sum = acu - temp; @@ -1110,6 +1470,7 @@ int32 sim_instr (void) { ((cbits >> 8) & 1); break; case 0x91: /* SUB C */ + sim_brk_pend = FALSE; temp = lreg(BC); acu = hreg(AF); sum = acu - temp; @@ -1120,6 +1481,7 @@ int32 sim_instr (void) { ((cbits >> 8) & 1); break; case 0x92: /* SUB D */ + sim_brk_pend = FALSE; temp = hreg(DE); acu = hreg(AF); sum = acu - temp; @@ -1130,6 +1492,7 @@ int32 sim_instr (void) { ((cbits >> 8) & 1); break; case 0x93: /* SUB E */ + sim_brk_pend = FALSE; temp = lreg(DE); acu = hreg(AF); sum = acu - temp; @@ -1140,6 +1503,7 @@ int32 sim_instr (void) { ((cbits >> 8) & 1); break; case 0x94: /* SUB H */ + sim_brk_pend = FALSE; temp = hreg(HL); acu = hreg(AF); sum = acu - temp; @@ -1150,6 +1514,7 @@ int32 sim_instr (void) { ((cbits >> 8) & 1); break; case 0x95: /* SUB L */ + sim_brk_pend = FALSE; temp = lreg(HL); acu = hreg(AF); sum = acu - temp; @@ -1160,6 +1525,7 @@ int32 sim_instr (void) { ((cbits >> 8) & 1); break; case 0x96: /* SUB (HL) */ + CheckBreakByte(HL); temp = GetBYTE(HL); acu = hreg(AF); sum = acu - temp; @@ -1170,6 +1536,7 @@ int32 sim_instr (void) { ((cbits >> 8) & 1); break; case 0x97: /* SUB A */ + sim_brk_pend = FALSE; temp = hreg(AF); acu = hreg(AF); sum = acu - temp; @@ -1180,6 +1547,7 @@ int32 sim_instr (void) { ((cbits >> 8) & 1); break; case 0x98: /* SBC A,B */ + sim_brk_pend = FALSE; temp = hreg(BC); acu = hreg(AF); sum = acu - temp - TSTFLAG(C); @@ -1190,6 +1558,7 @@ int32 sim_instr (void) { ((cbits >> 8) & 1); break; case 0x99: /* SBC A,C */ + sim_brk_pend = FALSE; temp = lreg(BC); acu = hreg(AF); sum = acu - temp - TSTFLAG(C); @@ -1199,7 +1568,8 @@ int32 sim_instr (void) { (SetPV) | 2 | ((cbits >> 8) & 1); break; - case 0x9A: /* SBC A,D */ + case 0x9a: /* SBC A,D */ + sim_brk_pend = FALSE; temp = hreg(DE); acu = hreg(AF); sum = acu - temp - TSTFLAG(C); @@ -1209,7 +1579,8 @@ int32 sim_instr (void) { (SetPV) | 2 | ((cbits >> 8) & 1); break; - case 0x9B: /* SBC A,E */ + case 0x9b: /* SBC A,E */ + sim_brk_pend = FALSE; temp = lreg(DE); acu = hreg(AF); sum = acu - temp - TSTFLAG(C); @@ -1219,7 +1590,8 @@ int32 sim_instr (void) { (SetPV) | 2 | ((cbits >> 8) & 1); break; - case 0x9C: /* SBC A,H */ + case 0x9c: /* SBC A,H */ + sim_brk_pend = FALSE; temp = hreg(HL); acu = hreg(AF); sum = acu - temp - TSTFLAG(C); @@ -1229,7 +1601,8 @@ int32 sim_instr (void) { (SetPV) | 2 | ((cbits >> 8) & 1); break; - case 0x9D: /* SBC A,L */ + case 0x9d: /* SBC A,L */ + sim_brk_pend = FALSE; temp = lreg(HL); acu = hreg(AF); sum = acu - temp - TSTFLAG(C); @@ -1239,7 +1612,8 @@ int32 sim_instr (void) { (SetPV) | 2 | ((cbits >> 8) & 1); break; - case 0x9E: /* SBC A,(HL) */ + case 0x9e: /* SBC A,(HL) */ + CheckBreakByte(HL); temp = GetBYTE(HL); acu = hreg(AF); sum = acu - temp - TSTFLAG(C); @@ -1249,7 +1623,8 @@ int32 sim_instr (void) { (SetPV) | 2 | ((cbits >> 8) & 1); break; - case 0x9F: /* SBC A,A */ + case 0x9f: /* SBC A,A */ + sim_brk_pend = FALSE; temp = hreg(AF); acu = hreg(AF); sum = acu - temp - TSTFLAG(C); @@ -1259,111 +1634,136 @@ int32 sim_instr (void) { (SetPV) | 2 | ((cbits >> 8) & 1); break; - case 0xA0: /* AND B */ + case 0xa0: /* AND B */ + sim_brk_pend = FALSE; sum = ((AF & (BC)) >> 8) & 0xff; AF = (sum << 8) | (sum & 0xa8) | ((sum == 0) << 6) | 0x10 | partab[sum]; break; - case 0xA1: /* AND C */ + case 0xa1: /* AND C */ + sim_brk_pend = FALSE; sum = ((AF >> 8) & BC) & 0xff; AF = (sum << 8) | (sum & 0xa8) | 0x10 | ((sum == 0) << 6) | partab[sum]; break; - case 0xA2: /* AND D */ + case 0xa2: /* AND D */ + sim_brk_pend = FALSE; sum = ((AF & (DE)) >> 8) & 0xff; AF = (sum << 8) | (sum & 0xa8) | ((sum == 0) << 6) | 0x10 | partab[sum]; break; - case 0xA3: /* AND E */ + case 0xa3: /* AND E */ + sim_brk_pend = FALSE; sum = ((AF >> 8) & DE) & 0xff; AF = (sum << 8) | (sum & 0xa8) | 0x10 | ((sum == 0) << 6) | partab[sum]; break; - case 0xA4: /* AND H */ + case 0xa4: /* AND H */ + sim_brk_pend = FALSE; sum = ((AF & (HL)) >> 8) & 0xff; AF = (sum << 8) | (sum & 0xa8) | ((sum == 0) << 6) | 0x10 | partab[sum]; break; - case 0xA5: /* AND L */ + case 0xa5: /* AND L */ + sim_brk_pend = FALSE; sum = ((AF >> 8) & HL) & 0xff; AF = (sum << 8) | (sum & 0xa8) | 0x10 | ((sum == 0) << 6) | partab[sum]; break; - case 0xA6: /* AND (HL) */ + case 0xa6: /* AND (HL) */ + CheckBreakByte(HL); sum = ((AF >> 8) & GetBYTE(HL)) & 0xff; AF = (sum << 8) | (sum & 0xa8) | 0x10 | ((sum == 0) << 6) | partab[sum]; break; - case 0xA7: /* AND A */ + case 0xa7: /* AND A */ + sim_brk_pend = FALSE; sum = ((AF & (AF)) >> 8) & 0xff; AF = (sum << 8) | (sum & 0xa8) | ((sum == 0) << 6) | 0x10 | partab[sum]; break; - case 0xA8: /* XOR B */ + case 0xa8: /* XOR B */ + sim_brk_pend = FALSE; sum = ((AF ^ (BC)) >> 8) & 0xff; AF = (sum << 8) | (sum & 0xa8) | ((sum == 0) << 6) | partab[sum]; break; - case 0xA9: /* XOR C */ + case 0xa9: /* XOR C */ + sim_brk_pend = FALSE; sum = ((AF >> 8) ^ BC) & 0xff; AF = (sum << 8) | (sum & 0xa8) | ((sum == 0) << 6) | partab[sum]; break; - case 0xAA: /* XOR D */ + case 0xaa: /* XOR D */ + sim_brk_pend = FALSE; sum = ((AF ^ (DE)) >> 8) & 0xff; AF = (sum << 8) | (sum & 0xa8) | ((sum == 0) << 6) | partab[sum]; break; - case 0xAB: /* XOR E */ + case 0xab: /* XOR E */ + sim_brk_pend = FALSE; sum = ((AF >> 8) ^ DE) & 0xff; AF = (sum << 8) | (sum & 0xa8) | ((sum == 0) << 6) | partab[sum]; break; - case 0xAC: /* XOR H */ + case 0xac: /* XOR H */ + sim_brk_pend = FALSE; sum = ((AF ^ (HL)) >> 8) & 0xff; AF = (sum << 8) | (sum & 0xa8) | ((sum == 0) << 6) | partab[sum]; break; - case 0xAD: /* XOR L */ + case 0xad: /* XOR L */ + sim_brk_pend = FALSE; sum = ((AF >> 8) ^ HL) & 0xff; AF = (sum << 8) | (sum & 0xa8) | ((sum == 0) << 6) | partab[sum]; break; - case 0xAE: /* XOR (HL) */ + case 0xae: /* XOR (HL) */ + CheckBreakByte(HL); sum = ((AF >> 8) ^ GetBYTE(HL)) & 0xff; AF = (sum << 8) | (sum & 0xa8) | ((sum == 0) << 6) | partab[sum]; break; - case 0xAF: /* XOR A */ + case 0xaf: /* XOR A */ + sim_brk_pend = FALSE; sum = ((AF ^ (AF)) >> 8) & 0xff; AF = (sum << 8) | (sum & 0xa8) | ((sum == 0) << 6) | partab[sum]; break; - case 0xB0: /* OR B */ + case 0xb0: /* OR B */ + sim_brk_pend = FALSE; sum = ((AF | (BC)) >> 8) & 0xff; AF = (sum << 8) | (sum & 0xa8) | ((sum == 0) << 6) | partab[sum]; break; - case 0xB1: /* OR C */ + case 0xb1: /* OR C */ + sim_brk_pend = FALSE; sum = ((AF >> 8) | BC) & 0xff; AF = (sum << 8) | (sum & 0xa8) | ((sum == 0) << 6) | partab[sum]; break; - case 0xB2: /* OR D */ + case 0xb2: /* OR D */ + sim_brk_pend = FALSE; sum = ((AF | (DE)) >> 8) & 0xff; AF = (sum << 8) | (sum & 0xa8) | ((sum == 0) << 6) | partab[sum]; break; - case 0xB3: /* OR E */ + case 0xb3: /* OR E */ + sim_brk_pend = FALSE; sum = ((AF >> 8) | DE) & 0xff; AF = (sum << 8) | (sum & 0xa8) | ((sum == 0) << 6) | partab[sum]; break; - case 0xB4: /* OR H */ + case 0xb4: /* OR H */ + sim_brk_pend = FALSE; sum = ((AF | (HL)) >> 8) & 0xff; AF = (sum << 8) | (sum & 0xa8) | ((sum == 0) << 6) | partab[sum]; break; - case 0xB5: /* OR L */ + case 0xb5: /* OR L */ + sim_brk_pend = FALSE; sum = ((AF >> 8) | HL) & 0xff; AF = (sum << 8) | (sum & 0xa8) | ((sum == 0) << 6) | partab[sum]; break; - case 0xB6: /* OR (HL) */ + case 0xb6: /* OR (HL) */ + CheckBreakByte(HL); sum = ((AF >> 8) | GetBYTE(HL)) & 0xff; AF = (sum << 8) | (sum & 0xa8) | ((sum == 0) << 6) | partab[sum]; break; - case 0xB7: /* OR A */ + case 0xb7: /* OR A */ + sim_brk_pend = FALSE; sum = ((AF | (AF)) >> 8) & 0xff; AF = (sum << 8) | (sum & 0xa8) | ((sum == 0) << 6) | partab[sum]; break; - case 0xB8: /* CP B */ + case 0xb8: /* CP B */ + sim_brk_pend = FALSE; temp = hreg(BC); AF = (AF & ~0x28) | (temp & 0x28); acu = hreg(AF); @@ -1374,7 +1774,8 @@ int32 sim_instr (void) { (SetPV) | 2 | (cbits & 0x10) | ((cbits >> 8) & 1); break; - case 0xB9: /* CP C */ + case 0xb9: /* CP C */ + sim_brk_pend = FALSE; temp = lreg(BC); AF = (AF & ~0x28) | (temp & 0x28); acu = hreg(AF); @@ -1385,7 +1786,8 @@ int32 sim_instr (void) { (SetPV) | 2 | (cbits & 0x10) | ((cbits >> 8) & 1); break; - case 0xBA: /* CP D */ + case 0xba: /* CP D */ + sim_brk_pend = FALSE; temp = hreg(DE); AF = (AF & ~0x28) | (temp & 0x28); acu = hreg(AF); @@ -1396,7 +1798,8 @@ int32 sim_instr (void) { (SetPV) | 2 | (cbits & 0x10) | ((cbits >> 8) & 1); break; - case 0xBB: /* CP E */ + case 0xbb: /* CP E */ + sim_brk_pend = FALSE; temp = lreg(DE); AF = (AF & ~0x28) | (temp & 0x28); acu = hreg(AF); @@ -1407,7 +1810,8 @@ int32 sim_instr (void) { (SetPV) | 2 | (cbits & 0x10) | ((cbits >> 8) & 1); break; - case 0xBC: /* CP H */ + case 0xbc: /* CP H */ + sim_brk_pend = FALSE; temp = hreg(HL); AF = (AF & ~0x28) | (temp & 0x28); acu = hreg(AF); @@ -1418,7 +1822,8 @@ int32 sim_instr (void) { (SetPV) | 2 | (cbits & 0x10) | ((cbits >> 8) & 1); break; - case 0xBD: /* CP L */ + case 0xbd: /* CP L */ + sim_brk_pend = FALSE; temp = lreg(HL); AF = (AF & ~0x28) | (temp & 0x28); acu = hreg(AF); @@ -1429,7 +1834,8 @@ int32 sim_instr (void) { (SetPV) | 2 | (cbits & 0x10) | ((cbits >> 8) & 1); break; - case 0xBE: /* CP (HL) */ + case 0xbe: /* CP (HL) */ + CheckBreakByte(HL); temp = GetBYTE(HL); AF = (AF & ~0x28) | (temp & 0x28); acu = hreg(AF); @@ -1440,7 +1846,8 @@ int32 sim_instr (void) { (SetPV) | 2 | (cbits & 0x10) | ((cbits >> 8) & 1); break; - case 0xBF: /* CP A */ + case 0xbf: /* CP A */ + sim_brk_pend = FALSE; temp = hreg(AF); AF = (AF & ~0x28) | (temp & 0x28); acu = hreg(AF); @@ -1451,25 +1858,37 @@ int32 sim_instr (void) { (SetPV) | 2 | (cbits & 0x10) | ((cbits >> 8) & 1); break; - case 0xC0: /* RET NZ */ - if (!TSTFLAG(Z)) POP(PC); + case 0xc0: /* RET NZ */ + if (TSTFLAG(Z)) { + sim_brk_pend = FALSE; + } + else { + CheckBreakWord(SP); + PCQ_ENTRY(PC - 1); + POP(PC); + } break; - case 0xC1: /* POP BC */ + case 0xc1: /* POP BC */ + CheckBreakWord(SP); POP(BC); break; - case 0xC2: /* JP NZ,nnnn */ + case 0xc2: /* JP NZ,nnnn */ + sim_brk_pend = FALSE; JPC(!TSTFLAG(Z)); break; - case 0xC3: /* JP nnnn */ + case 0xc3: /* JP nnnn */ + sim_brk_pend = FALSE; JPC(1); break; - case 0xC4: /* CALL NZ,nnnn */ + case 0xc4: /* CALL NZ,nnnn */ CALLC(!TSTFLAG(Z)); break; - case 0xC5: /* PUSH BC */ + case 0xc5: /* PUSH BC */ + CheckBreakWord(SP - 2); PUSH(BC); break; - case 0xC6: /* ADD A,nn */ + case 0xc6: /* ADD A,nn */ + sim_brk_pend = FALSE; temp = RAM_pp(PC); acu = hreg(AF); sum = acu + temp; @@ -1479,30 +1898,41 @@ int32 sim_instr (void) { (SetPV) | ((cbits >> 8) & 1); break; - case 0xC7: /* RST 0 */ - PUSH(PC); PC = 0; + case 0xc7: /* RST 0 */ + CheckBreakWord(SP - 2); + PUSH(PC); PCQ_ENTRY(PC - 1); PC = 0; break; - case 0xC8: /* RET Z */ - if (TSTFLAG(Z)) POP(PC); + case 0xc8: /* RET Z */ + if (TSTFLAG(Z)) { + CheckBreakWord(SP); + PCQ_ENTRY(PC - 1); + POP(PC); + } + else { + sim_brk_pend = FALSE; + } break; - case 0xC9: /* RET */ + case 0xc9: /* RET */ + CheckBreakWord(SP); + PCQ_ENTRY(PC - 1); POP(PC); break; - case 0xCA: /* JP Z,nnnn */ + case 0xca: /* JP Z,nnnn */ + sim_brk_pend = FALSE; JPC(TSTFLAG(Z)); break; - case 0xCB: /* CB prefix */ - checkCPU + case 0xcb: /* CB prefix */ + checkCPU8080; adr = HL; switch ((op = GetBYTE(PC)) & 7) { - case 0: ++PC; acu = hreg(BC); break; - case 1: ++PC; acu = lreg(BC); break; - case 2: ++PC; acu = hreg(DE); break; - case 3: ++PC; acu = lreg(DE); break; - case 4: ++PC; acu = hreg(HL); break; - case 5: ++PC; acu = lreg(HL); break; - case 6: ++PC; acu = GetBYTE(adr); break; - case 7: ++PC; acu = hreg(AF); break; + case 0: sim_brk_pend = FALSE; ++PC; acu = hreg(BC); break; + case 1: sim_brk_pend = FALSE; ++PC; acu = lreg(BC); break; + case 2: sim_brk_pend = FALSE; ++PC; acu = hreg(DE); break; + case 3: sim_brk_pend = FALSE; ++PC; acu = lreg(DE); break; + case 4: sim_brk_pend = FALSE; ++PC; acu = hreg(HL); break; + case 5: sim_brk_pend = FALSE; ++PC; acu = lreg(HL); break; + case 6: CheckBreakByte(adr); ++PC; acu = GetBYTE(adr); break; + case 7: sim_brk_pend = FALSE; ++PC; acu = hreg(AF); break; } switch (op & 0xc0) { case 0x00: /* shift/rotate */ @@ -1545,13 +1975,16 @@ int32 sim_instr (void) { } break; case 0x40: /* BIT */ - if (acu & (1 << ((op >> 3) & 7))) + if (acu & (1 << ((op >> 3) & 7))) { AF = (AF & ~0xfe) | 0x10 | (((op & 0x38) == 0x38) << 7); - else + } + else { AF = (AF & ~0xfe) | 0x54; - if ((op&7) != 6) + } + if ((op&7) != 6) { AF |= (acu & 0x28); + } temp = acu; break; case 0x80: /* RES */ @@ -1572,13 +2005,14 @@ int32 sim_instr (void) { case 7: Sethreg(AF, temp); break; } break; - case 0xCC: /* CALL Z,nnnn */ + case 0xcc: /* CALL Z,nnnn */ CALLC(TSTFLAG(Z)); break; - case 0xCD: /* CALL nnnn */ + case 0xcd: /* CALL nnnn */ CALLC(1); break; - case 0xCE: /* ADC A,nn */ + case 0xce: /* ADC A,nn */ + sim_brk_pend = FALSE; temp = RAM_pp(PC); acu = hreg(AF); sum = acu + temp + TSTFLAG(C); @@ -1588,28 +2022,41 @@ int32 sim_instr (void) { (SetPV) | ((cbits >> 8) & 1); break; - case 0xCF: /* RST 8 */ - PUSH(PC); PC = 8; + case 0xcf: /* RST 8 */ + CheckBreakWord(SP - 2); + PUSH(PC); PCQ_ENTRY(PC - 1); PC = 8; break; - case 0xD0: /* RET NC */ - if (!TSTFLAG(C)) POP(PC); + case 0xd0: /* RET NC */ + if (TSTFLAG(C)) { + sim_brk_pend = FALSE; + } + else { + CheckBreakWord(SP); + PCQ_ENTRY(PC - 1); + POP(PC); + } break; - case 0xD1: /* POP DE */ + case 0xd1: /* POP DE */ + CheckBreakWord(SP); POP(DE); break; - case 0xD2: /* JP NC,nnnn */ + case 0xd2: /* JP NC,nnnn */ + sim_brk_pend = FALSE; JPC(!TSTFLAG(C)); break; - case 0xD3: /* OUT (nn),A */ + case 0xd3: /* OUT (nn),A */ + sim_brk_pend = FALSE; out(RAM_pp(PC), hreg(AF)); break; - case 0xD4: /* CALL NC,nnnn */ + case 0xd4: /* CALL NC,nnnn */ CALLC(!TSTFLAG(C)); break; - case 0xD5: /* PUSH DE */ + case 0xd5: /* PUSH DE */ + CheckBreakWord(SP - 2); PUSH(DE); break; - case 0xD6: /* SUB nn */ + case 0xd6: /* SUB nn */ + sim_brk_pend = FALSE; temp = RAM_pp(PC); acu = hreg(AF); sum = acu - temp; @@ -1619,14 +2066,23 @@ int32 sim_instr (void) { (SetPV) | 2 | ((cbits >> 8) & 1); break; - case 0xD7: /* RST 10H */ - PUSH(PC); PC = 0x10; + case 0xd7: /* RST 10H */ + CheckBreakWord(SP - 2); + PUSH(PC); PCQ_ENTRY(PC - 1); PC = 0x10; break; - case 0xD8: /* RET C */ - if (TSTFLAG(C)) POP(PC); + case 0xd8: /* RET C */ + if (TSTFLAG(C)) { + CheckBreakWord(SP); + PCQ_ENTRY(PC - 1); + POP(PC); + } + else { + sim_brk_pend = FALSE; + } break; - case 0xD9: /* EXX */ - checkCPU + case 0xd9: /* EXX */ + sim_brk_pend = FALSE; + checkCPU8080; regs[regs_sel].bc = BC; regs[regs_sel].de = DE; regs[regs_sel].hl = HL; @@ -1635,21 +2091,24 @@ int32 sim_instr (void) { DE = regs[regs_sel].de; HL = regs[regs_sel].hl; break; - case 0xDA: /* JP C,nnnn */ + case 0xda: /* JP C,nnnn */ + sim_brk_pend = FALSE; JPC(TSTFLAG(C)); break; - case 0xDB: /* IN A,(nn) */ + case 0xdb: /* IN A,(nn) */ + sim_brk_pend = FALSE; Sethreg(AF, in(RAM_pp(PC))); break; - case 0xDC: /* CALL C,nnnn */ + case 0xdc: /* CALL C,nnnn */ CALLC(TSTFLAG(C)); break; - case 0xDD: /* DD prefix */ - checkCPU + case 0xdd: /* DD prefix */ + checkCPU8080; switch (op = RAM_pp(PC)) { case 0x09: /* ADD IX,BC */ - IX &= 0xffff; - BC &= 0xffff; + sim_brk_pend = FALSE; + IX &= ADDRMASK; + BC &= ADDRMASK; sum = IX + BC; cbits = (IX ^ BC ^ sum) >> 8; IX = sum; @@ -1657,8 +2116,9 @@ int32 sim_instr (void) { (cbits & 0x10) | ((cbits >> 8) & 1); break; case 0x19: /* ADD IX,DE */ - IX &= 0xffff; - DE &= 0xffff; + sim_brk_pend = FALSE; + IX &= ADDRMASK; + DE &= ADDRMASK; sum = IX + DE; cbits = (IX ^ DE ^ sum) >> 8; IX = sum; @@ -1666,18 +2126,22 @@ int32 sim_instr (void) { (cbits & 0x10) | ((cbits >> 8) & 1); break; case 0x21: /* LD IX,nnnn */ + sim_brk_pend = FALSE; IX = GetWORD(PC); PC += 2; break; case 0x22: /* LD (nnnn),IX */ temp = GetWORD(PC); + CheckBreakWord(temp); PutWORD(temp, IX); PC += 2; break; case 0x23: /* INC IX */ + sim_brk_pend = FALSE; ++IX; break; case 0x24: /* INC IXH */ + sim_brk_pend = FALSE; IX += 0x100; temp = hreg(IX); AF = (AF & ~0xfe) | (temp & 0xa8) | @@ -1686,6 +2150,7 @@ int32 sim_instr (void) { ((temp == 0x80) << 2); break; case 0x25: /* DEC IXH */ + sim_brk_pend = FALSE; IX -= 0x100; temp = hreg(IX); AF = (AF & ~0xfe) | (temp & 0xa8) | @@ -1694,46 +2159,54 @@ int32 sim_instr (void) { ((temp == 0x7f) << 2) | 2; break; case 0x26: /* LD IXH,nn */ + sim_brk_pend = FALSE; Sethreg(IX, RAM_pp(PC)); break; case 0x29: /* ADD IX,IX */ - IX &= 0xffff; + sim_brk_pend = FALSE; + IX &= ADDRMASK; sum = IX + IX; cbits = (IX ^ IX ^ sum) >> 8; IX = sum; AF = (AF & ~0x3b) | ((sum >> 8) & 0x28) | (cbits & 0x10) | ((cbits >> 8) & 1); break; - case 0x2A: /* LD IX,(nnnn) */ + case 0x2a: /* LD IX,(nnnn) */ temp = GetWORD(PC); + CheckBreakWord(temp); IX = GetWORD(temp); PC += 2; break; - case 0x2B: /* DEC IX */ + case 0x2b: /* DEC IX */ + sim_brk_pend = FALSE; --IX; break; - case 0x2C: /* INC IXL */ - temp = lreg(IX)+1; + case 0x2c: /* INC IXL */ + sim_brk_pend = FALSE; + temp = lreg(IX) + 1; Setlreg(IX, temp); AF = (AF & ~0xfe) | (temp & 0xa8) | (((temp & 0xff) == 0) << 6) | (((temp & 0xf) == 0) << 4) | ((temp == 0x80) << 2); break; - case 0x2D: /* DEC IXL */ - temp = lreg(IX)-1; + case 0x2d: /* DEC IXL */ + sim_brk_pend = FALSE; + temp = lreg(IX) - 1; Setlreg(IX, temp); AF = (AF & ~0xfe) | (temp & 0xa8) | (((temp & 0xff) == 0) << 6) | (((temp & 0xf) == 0xf) << 4) | ((temp == 0x7f) << 2) | 2; break; - case 0x2E: /* LD IXL,nn */ + case 0x2e: /* LD IXL,nn */ + sim_brk_pend = FALSE; Setlreg(IX, RAM_pp(PC)); break; case 0x34: /* INC (IX+dd) */ adr = IX + (signed char) RAM_pp(PC); - temp = GetBYTE(adr)+1; + CheckBreakByte(adr); + temp = GetBYTE(adr) + 1; PutBYTE(adr, temp); AF = (AF & ~0xfe) | (temp & 0xa8) | (((temp & 0xff) == 0) << 6) | @@ -1742,7 +2215,8 @@ int32 sim_instr (void) { break; case 0x35: /* DEC (IX+dd) */ adr = IX + (signed char) RAM_pp(PC); - temp = GetBYTE(adr)-1; + CheckBreakByte(adr); + temp = GetBYTE(adr) - 1; PutBYTE(adr, temp); AF = (AF & ~0xfe) | (temp & 0xa8) | (((temp & 0xff) == 0) << 6) | @@ -1751,11 +2225,13 @@ int32 sim_instr (void) { break; case 0x36: /* LD (IX+dd),nn */ adr = IX + (signed char) RAM_pp(PC); + CheckBreakByte(adr); PutBYTE(adr, RAM_pp(PC)); break; case 0x39: /* ADD IX,SP */ - IX &= 0xffff; - SP &= 0xffff; + sim_brk_pend = FALSE; + IX &= ADDRMASK; + SP &= ADDRMASK; sum = IX + SP; cbits = (IX ^ SP ^ sum) >> 8; IX = sum; @@ -1763,134 +2239,173 @@ int32 sim_instr (void) { (cbits & 0x10) | ((cbits >> 8) & 1); break; case 0x44: /* LD B,IXH */ + sim_brk_pend = FALSE; Sethreg(BC, hreg(IX)); break; case 0x45: /* LD B,IXL */ + sim_brk_pend = FALSE; Sethreg(BC, lreg(IX)); break; case 0x46: /* LD B,(IX+dd) */ adr = IX + (signed char) RAM_pp(PC); + CheckBreakByte(adr); Sethreg(BC, GetBYTE(adr)); break; - case 0x4C: /* LD C,IXH */ + case 0x4c: /* LD C,IXH */ + sim_brk_pend = FALSE; Setlreg(BC, hreg(IX)); break; - case 0x4D: /* LD C,IXL */ + case 0x4d: /* LD C,IXL */ + sim_brk_pend = FALSE; Setlreg(BC, lreg(IX)); break; - case 0x4E: /* LD C,(IX+dd) */ + case 0x4e: /* LD C,(IX+dd) */ adr = IX + (signed char) RAM_pp(PC); + CheckBreakByte(adr); Setlreg(BC, GetBYTE(adr)); break; case 0x54: /* LD D,IXH */ + sim_brk_pend = FALSE; Sethreg(DE, hreg(IX)); break; case 0x55: /* LD D,IXL */ + sim_brk_pend = FALSE; Sethreg(DE, lreg(IX)); break; case 0x56: /* LD D,(IX+dd) */ adr = IX + (signed char) RAM_pp(PC); + CheckBreakByte(adr); Sethreg(DE, GetBYTE(adr)); break; - case 0x5C: /* LD E,H */ + case 0x5c: /* LD E,H */ + sim_brk_pend = FALSE; Setlreg(DE, hreg(IX)); break; - case 0x5D: /* LD E,L */ + case 0x5d: /* LD E,L */ + sim_brk_pend = FALSE; Setlreg(DE, lreg(IX)); break; - case 0x5E: /* LD E,(IX+dd) */ + case 0x5e: /* LD E,(IX+dd) */ adr = IX + (signed char) RAM_pp(PC); + CheckBreakByte(adr); Setlreg(DE, GetBYTE(adr)); break; case 0x60: /* LD IXH,B */ + sim_brk_pend = FALSE; Sethreg(IX, hreg(BC)); break; case 0x61: /* LD IXH,C */ + sim_brk_pend = FALSE; Sethreg(IX, lreg(BC)); break; case 0x62: /* LD IXH,D */ + sim_brk_pend = FALSE; Sethreg(IX, hreg(DE)); break; case 0x63: /* LD IXH,E */ + sim_brk_pend = FALSE; Sethreg(IX, lreg(DE)); break; case 0x64: /* LD IXH,IXH */ + sim_brk_pend = FALSE; /* nop */ break; case 0x65: /* LD IXH,IXL */ + sim_brk_pend = FALSE; Sethreg(IX, lreg(IX)); break; case 0x66: /* LD H,(IX+dd) */ adr = IX + (signed char) RAM_pp(PC); + CheckBreakByte(adr); Sethreg(HL, GetBYTE(adr)); break; case 0x67: /* LD IXH,A */ + sim_brk_pend = FALSE; Sethreg(IX, hreg(AF)); break; case 0x68: /* LD IXL,B */ + sim_brk_pend = FALSE; Setlreg(IX, hreg(BC)); break; case 0x69: /* LD IXL,C */ + sim_brk_pend = FALSE; Setlreg(IX, lreg(BC)); break; - case 0x6A: /* LD IXL,D */ + case 0x6a: /* LD IXL,D */ + sim_brk_pend = FALSE; Setlreg(IX, hreg(DE)); break; - case 0x6B: /* LD IXL,E */ + case 0x6b: /* LD IXL,E */ + sim_brk_pend = FALSE; Setlreg(IX, lreg(DE)); break; - case 0x6C: /* LD IXL,IXH */ + case 0x6c: /* LD IXL,IXH */ + sim_brk_pend = FALSE; Setlreg(IX, hreg(IX)); break; - case 0x6D: /* LD IXL,IXL */ + case 0x6d: /* LD IXL,IXL */ + sim_brk_pend = FALSE; /* nop */ break; - case 0x6E: /* LD L,(IX+dd) */ + case 0x6e: /* LD L,(IX+dd) */ adr = IX + (signed char) RAM_pp(PC); + CheckBreakByte(adr); Setlreg(HL, GetBYTE(adr)); break; - case 0x6F: /* LD IXL,A */ + case 0x6f: /* LD IXL,A */ + sim_brk_pend = FALSE; Setlreg(IX, hreg(AF)); break; case 0x70: /* LD (IX+dd),B */ adr = IX + (signed char) RAM_pp(PC); + CheckBreakByte(adr); PutBYTE(adr, hreg(BC)); break; case 0x71: /* LD (IX+dd),C */ adr = IX + (signed char) RAM_pp(PC); + CheckBreakByte(adr); PutBYTE(adr, lreg(BC)); break; case 0x72: /* LD (IX+dd),D */ adr = IX + (signed char) RAM_pp(PC); + CheckBreakByte(adr); PutBYTE(adr, hreg(DE)); break; case 0x73: /* LD (IX+dd),E */ adr = IX + (signed char) RAM_pp(PC); + CheckBreakByte(adr); PutBYTE(adr, lreg(DE)); break; case 0x74: /* LD (IX+dd),H */ adr = IX + (signed char) RAM_pp(PC); + CheckBreakByte(adr); PutBYTE(adr, hreg(HL)); break; case 0x75: /* LD (IX+dd),L */ adr = IX + (signed char) RAM_pp(PC); + CheckBreakByte(adr); PutBYTE(adr, lreg(HL)); break; case 0x77: /* LD (IX+dd),A */ adr = IX + (signed char) RAM_pp(PC); + CheckBreakByte(adr); PutBYTE(adr, hreg(AF)); break; - case 0x7C: /* LD A,IXH */ + case 0x7c: /* LD A,IXH */ + sim_brk_pend = FALSE; Sethreg(AF, hreg(IX)); break; - case 0x7D: /* LD A,IXL */ + case 0x7d: /* LD A,IXL */ + sim_brk_pend = FALSE; Sethreg(AF, lreg(IX)); break; - case 0x7E: /* LD A,(IX+dd) */ + case 0x7e: /* LD A,(IX+dd) */ adr = IX + (signed char) RAM_pp(PC); + CheckBreakByte(adr); Sethreg(AF, GetBYTE(adr)); break; case 0x84: /* ADD A,IXH */ + sim_brk_pend = FALSE; temp = hreg(IX); acu = hreg(AF); sum = acu + temp; @@ -1901,6 +2416,7 @@ int32 sim_instr (void) { ((cbits >> 8) & 1); break; case 0x85: /* ADD A,IXL */ + sim_brk_pend = FALSE; temp = lreg(IX); acu = hreg(AF); sum = acu + temp; @@ -1912,6 +2428,7 @@ int32 sim_instr (void) { break; case 0x86: /* ADD A,(IX+dd) */ adr = IX + (signed char) RAM_pp(PC); + CheckBreakByte(adr); temp = GetBYTE(adr); acu = hreg(AF); sum = acu + temp; @@ -1921,7 +2438,8 @@ int32 sim_instr (void) { (((cbits >> 6) ^ (cbits >> 5)) & 4) | ((cbits >> 8) & 1); break; - case 0x8C: /* ADC A,IXH */ + case 0x8c: /* ADC A,IXH */ + sim_brk_pend = FALSE; temp = hreg(IX); acu = hreg(AF); sum = acu + temp + TSTFLAG(C); @@ -1931,7 +2449,8 @@ int32 sim_instr (void) { (((cbits >> 6) ^ (cbits >> 5)) & 4) | ((cbits >> 8) & 1); break; - case 0x8D: /* ADC A,IXL */ + case 0x8d: /* ADC A,IXL */ + sim_brk_pend = FALSE; temp = lreg(IX); acu = hreg(AF); sum = acu + temp + TSTFLAG(C); @@ -1941,8 +2460,9 @@ int32 sim_instr (void) { (((cbits >> 6) ^ (cbits >> 5)) & 4) | ((cbits >> 8) & 1); break; - case 0x8E: /* ADC A,(IX+dd) */ + case 0x8e: /* ADC A,(IX+dd) */ adr = IX + (signed char) RAM_pp(PC); + CheckBreakByte(adr); temp = GetBYTE(adr); acu = hreg(AF); sum = acu + temp + TSTFLAG(C); @@ -1953,6 +2473,7 @@ int32 sim_instr (void) { ((cbits >> 8) & 1); break; case 0x94: /* SUB IXH */ + sim_brk_pend = FALSE; temp = hreg(IX); acu = hreg(AF); sum = acu - temp; @@ -1963,6 +2484,7 @@ int32 sim_instr (void) { ((cbits >> 8) & 1); break; case 0x95: /* SUB IXL */ + sim_brk_pend = FALSE; temp = lreg(IX); acu = hreg(AF); sum = acu - temp; @@ -1974,6 +2496,7 @@ int32 sim_instr (void) { break; case 0x96: /* SUB (IX+dd) */ adr = IX + (signed char) RAM_pp(PC); + CheckBreakByte(adr); temp = GetBYTE(adr); acu = hreg(AF); sum = acu - temp; @@ -1983,7 +2506,8 @@ int32 sim_instr (void) { (((cbits >> 6) ^ (cbits >> 5)) & 4) | 2 | ((cbits >> 8) & 1); break; - case 0x9C: /* SBC A,IXH */ + case 0x9c: /* SBC A,IXH */ + sim_brk_pend = FALSE; temp = hreg(IX); acu = hreg(AF); sum = acu - temp - TSTFLAG(C); @@ -1993,7 +2517,8 @@ int32 sim_instr (void) { (((cbits >> 6) ^ (cbits >> 5)) & 4) | 2 | ((cbits >> 8) & 1); break; - case 0x9D: /* SBC A,IXL */ + case 0x9d: /* SBC A,IXL */ + sim_brk_pend = FALSE; temp = lreg(IX); acu = hreg(AF); sum = acu - temp - TSTFLAG(C); @@ -2003,8 +2528,9 @@ int32 sim_instr (void) { (((cbits >> 6) ^ (cbits >> 5)) & 4) | 2 | ((cbits >> 8) & 1); break; - case 0x9E: /* SBC A,(IX+dd) */ + case 0x9e: /* SBC A,(IX+dd) */ adr = IX + (signed char) RAM_pp(PC); + CheckBreakByte(adr); temp = GetBYTE(adr); acu = hreg(AF); sum = acu - temp - TSTFLAG(C); @@ -2014,49 +2540,59 @@ int32 sim_instr (void) { (((cbits >> 6) ^ (cbits >> 5)) & 4) | 2 | ((cbits >> 8) & 1); break; - case 0xA4: /* AND IXH */ + case 0xa4: /* AND IXH */ + sim_brk_pend = FALSE; sum = ((AF & (IX)) >> 8) & 0xff; AF = (sum << 8) | (sum & 0xa8) | ((sum == 0) << 6) | 0x10 | partab[sum]; break; - case 0xA5: /* AND IXL */ + case 0xa5: /* AND IXL */ + sim_brk_pend = FALSE; sum = ((AF >> 8) & IX) & 0xff; AF = (sum << 8) | (sum & 0xa8) | 0x10 | ((sum == 0) << 6) | partab[sum]; break; - case 0xA6: /* AND (IX+dd) */ + case 0xa6: /* AND (IX+dd) */ adr = IX + (signed char) RAM_pp(PC); + CheckBreakByte(adr); sum = ((AF >> 8) & GetBYTE(adr)) & 0xff; AF = (sum << 8) | (sum & 0xa8) | 0x10 | ((sum == 0) << 6) | partab[sum]; break; - case 0xAC: /* XOR IXH */ + case 0xac: /* XOR IXH */ + sim_brk_pend = FALSE; sum = ((AF ^ (IX)) >> 8) & 0xff; AF = (sum << 8) | (sum & 0xa8) | ((sum == 0) << 6) | partab[sum]; break; - case 0xAD: /* XOR IXL */ + case 0xad: /* XOR IXL */ + sim_brk_pend = FALSE; sum = ((AF >> 8) ^ IX) & 0xff; AF = (sum << 8) | (sum & 0xa8) | ((sum == 0) << 6) | partab[sum]; break; - case 0xAE: /* XOR (IX+dd) */ + case 0xae: /* XOR (IX+dd) */ adr = IX + (signed char) RAM_pp(PC); + CheckBreakByte(adr); sum = ((AF >> 8) ^ GetBYTE(adr)) & 0xff; AF = (sum << 8) | (sum & 0xa8) | ((sum == 0) << 6) | partab[sum]; break; - case 0xB4: /* OR IXH */ + case 0xb4: /* OR IXH */ + sim_brk_pend = FALSE; sum = ((AF | (IX)) >> 8) & 0xff; AF = (sum << 8) | (sum & 0xa8) | ((sum == 0) << 6) | partab[sum]; break; - case 0xB5: /* OR IXL */ + case 0xb5: /* OR IXL */ + sim_brk_pend = FALSE; sum = ((AF >> 8) | IX) & 0xff; AF = (sum << 8) | (sum & 0xa8) | ((sum == 0) << 6) | partab[sum]; break; - case 0xB6: /* OR (IX+dd) */ + case 0xb6: /* OR (IX+dd) */ adr = IX + (signed char) RAM_pp(PC); + CheckBreakByte(adr); sum = ((AF >> 8) | GetBYTE(adr)) & 0xff; AF = (sum << 8) | (sum & 0xa8) | ((sum == 0) << 6) | partab[sum]; break; - case 0xBC: /* CP IXH */ + case 0xbc: /* CP IXH */ + sim_brk_pend = FALSE; temp = hreg(IX); AF = (AF & ~0x28) | (temp & 0x28); acu = hreg(AF); @@ -2067,7 +2603,8 @@ int32 sim_instr (void) { (((cbits >> 6) ^ (cbits >> 5)) & 4) | 2 | (cbits & 0x10) | ((cbits >> 8) & 1); break; - case 0xBD: /* CP IXL */ + case 0xbd: /* CP IXL */ + sim_brk_pend = FALSE; temp = lreg(IX); AF = (AF & ~0x28) | (temp & 0x28); acu = hreg(AF); @@ -2078,8 +2615,9 @@ int32 sim_instr (void) { (((cbits >> 6) ^ (cbits >> 5)) & 4) | 2 | (cbits & 0x10) | ((cbits >> 8) & 1); break; - case 0xBE: /* CP (IX+dd) */ + case 0xbe: /* CP (IX+dd) */ adr = IX + (signed char) RAM_pp(PC); + CheckBreakByte(adr); temp = GetBYTE(adr); AF = (AF & ~0x28) | (temp & 0x28); acu = hreg(AF); @@ -2088,20 +2626,20 @@ int32 sim_instr (void) { AF = (AF & ~0xff) | (sum & 0x80) | (((sum & 0xff) == 0) << 6) | (temp & 0x28) | (((cbits >> 6) ^ (cbits >> 5)) & 4) | 2 | + (cbits & 0x10) | ((cbits >> 8) & 1); break; - case 0xCB: /* CB prefix */ + case 0xcb: /* CB prefix */ adr = IX + (signed char) RAM_pp(PC); - adr = adr; switch ((op = GetBYTE(PC)) & 7) { - case 0: ++PC; acu = hreg(BC); break; - case 1: ++PC; acu = lreg(BC); break; - case 2: ++PC; acu = hreg(DE); break; - case 3: ++PC; acu = lreg(DE); break; - case 4: ++PC; acu = hreg(HL); break; - case 5: ++PC; acu = lreg(HL); break; - case 6: ++PC; acu = GetBYTE(adr); break; - case 7: ++PC; acu = hreg(AF); break; + case 0: sim_brk_pend = FALSE; ++PC; acu = hreg(BC); break; + case 1: sim_brk_pend = FALSE; ++PC; acu = lreg(BC); break; + case 2: sim_brk_pend = FALSE; ++PC; acu = hreg(DE); break; + case 3: sim_brk_pend = FALSE; ++PC; acu = lreg(DE); break; + case 4: sim_brk_pend = FALSE; ++PC; acu = hreg(HL); break; + case 5: sim_brk_pend = FALSE; ++PC; acu = lreg(HL); break; + case 6: CheckBreakByte(adr); ++PC; acu = GetBYTE(adr); break; + case 7: sim_brk_pend = FALSE; ++PC; acu = hreg(AF); break; } switch (op & 0xc0) { case 0x00: /* shift/rotate */ @@ -2144,13 +2682,16 @@ int32 sim_instr (void) { } break; case 0x40: /* BIT */ - if (acu & (1 << ((op >> 3) & 7))) + if (acu & (1 << ((op >> 3) & 7))) { AF = (AF & ~0xfe) | 0x10 | (((op & 0x38) == 0x38) << 7); - else + } + else { AF = (AF & ~0xfe) | 0x54; - if ((op&7) != 6) + } + if ((op&7) != 6) { AF |= (acu & 0x28); + } temp = acu; break; case 0x80: /* RES */ @@ -2171,27 +2712,35 @@ int32 sim_instr (void) { case 7: Sethreg(AF, temp); break; } break; - case 0xE1: /* POP IX */ + case 0xe1: /* POP IX */ + CheckBreakWord(SP); POP(IX); break; - case 0xE3: /* EX (SP),IX */ + case 0xe3: /* EX (SP),IX */ + CheckBreakWord(SP); temp = IX; POP(IX); PUSH(temp); break; - case 0xE5: /* PUSH IX */ + case 0xe5: /* PUSH IX */ + CheckBreakWord(SP - 2); PUSH(IX); break; - case 0xE9: /* JP (IX) */ + case 0xe9: /* JP (IX) */ + sim_brk_pend = FALSE; + PCQ_ENTRY(PC - 2); PC = IX; break; - case 0xF9: /* LD SP,IX */ + case 0xf9: /* LD SP,IX */ + sim_brk_pend = FALSE; SP = IX; break; default: /* ignore DD */ - BadZ80OpOccured = 1; + sim_brk_pend = FALSE; + checkCPUZ80; PC--; } break; - case 0xDE: /* SBC A,nn */ + case 0xde: /* SBC A,nn */ + sim_brk_pend = FALSE; temp = RAM_pp(PC); acu = hreg(AF); sum = acu - temp - TSTFLAG(C); @@ -2201,54 +2750,80 @@ int32 sim_instr (void) { (SetPV) | 2 | ((cbits >> 8) & 1); break; - case 0xDF: /* RST 18H */ - PUSH(PC); PC = 0x18; + case 0xdf: /* RST 18H */ + CheckBreakWord(SP - 2); + PUSH(PC); PCQ_ENTRY(PC - 1); PC = 0x18; break; - case 0xE0: /* RET PO */ - if (!TSTFLAG(P)) POP(PC); + case 0xe0: /* RET PO */ + if (TSTFLAG(P)) { + sim_brk_pend = FALSE; + } + else { + CheckBreakWord(SP); + PCQ_ENTRY(PC - 1); + POP(PC); + } break; - case 0xE1: /* POP HL */ + case 0xe1: /* POP HL */ + CheckBreakWord(SP); POP(HL); break; - case 0xE2: /* JP PO,nnnn */ + case 0xe2: /* JP PO,nnnn */ + sim_brk_pend = FALSE; JPC(!TSTFLAG(P)); break; - case 0xE3: /* EX (SP),HL */ + case 0xe3: /* EX (SP),HL */ + CheckBreakWord(SP); temp = HL; POP(HL); PUSH(temp); break; - case 0xE4: /* CALL PO,nnnn */ + case 0xe4: /* CALL PO,nnnn */ CALLC(!TSTFLAG(P)); break; - case 0xE5: /* PUSH HL */ + case 0xe5: /* PUSH HL */ + CheckBreakWord(SP - 2); PUSH(HL); break; - case 0xE6: /* AND nn */ + case 0xe6: /* AND nn */ + sim_brk_pend = FALSE; sum = ((AF >> 8) & RAM_pp(PC)) & 0xff; AF = (sum << 8) | (sum & 0xa8) | 0x10 | ((sum == 0) << 6) | partab[sum]; break; - case 0xE7: /* RST 20H */ - PUSH(PC); PC = 0x20; + case 0xe7: /* RST 20H */ + CheckBreakWord(SP - 2); + PUSH(PC); PCQ_ENTRY(PC - 1); PC = 0x20; break; - case 0xE8: /* RET PE */ - if (TSTFLAG(P)) POP(PC); + case 0xe8: /* RET PE */ + if (TSTFLAG(P)) { + CheckBreakWord(SP); + PCQ_ENTRY(PC - 1); + POP(PC); + } + else { + sim_brk_pend = FALSE; + } break; - case 0xE9: /* JP (HL) */ + case 0xe9: /* JP (HL) */ + sim_brk_pend = FALSE; + PCQ_ENTRY(PC - 1); PC = HL; break; - case 0xEA: /* JP PE,nnnn */ + case 0xea: /* JP PE,nnnn */ + sim_brk_pend = FALSE; JPC(TSTFLAG(P)); break; - case 0xEB: /* EX DE,HL */ + case 0xeb: /* EX DE,HL */ + sim_brk_pend = FALSE; temp = HL; HL = DE; DE = temp; break; - case 0xEC: /* CALL PE,nnnn */ + case 0xec: /* CALL PE,nnnn */ CALLC(TSTFLAG(P)); break; - case 0xED: /* ED prefix */ - checkCPU + case 0xed: /* ED prefix */ + checkCPU8080; switch (op = RAM_pp(PC)) { case 0x40: /* IN B,(C) */ + sim_brk_pend = FALSE; temp = in(lreg(BC)); Sethreg(BC, temp); AF = (AF & ~0xfe) | (temp & 0xa8) | @@ -2256,27 +2831,31 @@ int32 sim_instr (void) { parity(temp); break; case 0x41: /* OUT (C),B */ + sim_brk_pend = FALSE; out(lreg(BC), hreg(BC)); break; case 0x42: /* SBC HL,BC */ - HL &= 0xffff; - BC &= 0xffff; + sim_brk_pend = FALSE; + HL &= ADDRMASK; + BC &= ADDRMASK; sum = HL - BC - TSTFLAG(C); cbits = (HL ^ BC ^ sum) >> 8; HL = sum; AF = (AF & ~0xff) | ((sum >> 8) & 0xa8) | - (((sum & 0xffff) == 0) << 6) | + (((sum & ADDRMASK) == 0) << 6) | (((cbits >> 6) ^ (cbits >> 5)) & 4) | (cbits & 0x10) | 2 | ((cbits >> 8) & 1); break; case 0x43: /* LD (nnnn),BC */ temp = GetWORD(PC); + CheckBreakWord(temp); PutWORD(temp, BC); PC += 2; break; case 0x44: /* NEG */ + sim_brk_pend = FALSE; temp = hreg(AF); - AF = (-(AF & 0xff00) & 0xff00); + AF = ((~(AF & 0xff00) + 1) & 0xff00); /* AF = (-(AF & 0xff00) & 0xff00); */ AF |= ((AF >> 8) & 0xa8) | (((AF & 0xff00) == 0) << 6) | (((temp & 0x0f) != 0) << 4) | ((temp == 0x80) << 2) | @@ -2284,15 +2863,20 @@ int32 sim_instr (void) { break; case 0x45: /* RETN */ IFF |= IFF >> 1; + CheckBreakWord(SP); + PCQ_ENTRY(PC - 2); POP(PC); break; case 0x46: /* IM 0 */ + sim_brk_pend = FALSE; /* interrupt mode 0 */ break; case 0x47: /* LD I,A */ + sim_brk_pend = FALSE; ir = (ir & 255) | (AF & ~255); break; case 0x48: /* IN C,(C) */ + sim_brk_pend = FALSE; temp = in(lreg(BC)); Setlreg(BC, temp); AF = (AF & ~0xfe) | (temp & 0xa8) | @@ -2300,32 +2884,39 @@ int32 sim_instr (void) { parity(temp); break; case 0x49: /* OUT (C),C */ + sim_brk_pend = FALSE; out(lreg(BC), lreg(BC)); break; - case 0x4A: /* ADC HL,BC */ - HL &= 0xffff; - BC &= 0xffff; + case 0x4a: /* ADC HL,BC */ + sim_brk_pend = FALSE; + HL &= ADDRMASK; + BC &= ADDRMASK; sum = HL + BC + TSTFLAG(C); cbits = (HL ^ BC ^ sum) >> 8; HL = sum; AF = (AF & ~0xff) | ((sum >> 8) & 0xa8) | - (((sum & 0xffff) == 0) << 6) | + (((sum & ADDRMASK) == 0) << 6) | (((cbits >> 6) ^ (cbits >> 5)) & 4) | (cbits & 0x10) | ((cbits >> 8) & 1); break; - case 0x4B: /* LD BC,(nnnn) */ + case 0x4b: /* LD BC,(nnnn) */ temp = GetWORD(PC); + CheckBreakWord(temp); BC = GetWORD(temp); PC += 2; break; - case 0x4D: /* RETI */ + case 0x4d: /* RETI */ IFF |= IFF >> 1; + CheckBreakWord(SP); + PCQ_ENTRY(PC - 2); POP(PC); break; - case 0x4F: /* LD R,A */ + case 0x4f: /* LD R,A */ + sim_brk_pend = FALSE; ir = (ir & ~255) | ((AF >> 8) & 255); break; case 0x50: /* IN D,(C) */ + sim_brk_pend = FALSE; temp = in(lreg(BC)); Sethreg(DE, temp); AF = (AF & ~0xfe) | (temp & 0xa8) | @@ -2333,31 +2924,37 @@ int32 sim_instr (void) { parity(temp); break; case 0x51: /* OUT (C),D */ + sim_brk_pend = FALSE; out(lreg(BC), hreg(DE)); break; case 0x52: /* SBC HL,DE */ - HL &= 0xffff; - DE &= 0xffff; + sim_brk_pend = FALSE; + HL &= ADDRMASK; + DE &= ADDRMASK; sum = HL - DE - TSTFLAG(C); cbits = (HL ^ DE ^ sum) >> 8; HL = sum; AF = (AF & ~0xff) | ((sum >> 8) & 0xa8) | - (((sum & 0xffff) == 0) << 6) | + (((sum & ADDRMASK) == 0) << 6) | (((cbits >> 6) ^ (cbits >> 5)) & 4) | (cbits & 0x10) | 2 | ((cbits >> 8) & 1); break; case 0x53: /* LD (nnnn),DE */ temp = GetWORD(PC); + CheckBreakWord(temp); PutWORD(temp, DE); PC += 2; break; case 0x56: /* IM 1 */ + sim_brk_pend = FALSE; /* interrupt mode 1 */ break; case 0x57: /* LD A,I */ + sim_brk_pend = FALSE; AF = (AF & 0x29) | (ir & ~255) | ((ir >> 8) & 0x80) | (((ir & ~255) == 0) << 6) | ((IFF & 2) << 1); break; case 0x58: /* IN E,(C) */ + sim_brk_pend = FALSE; temp = in(lreg(BC)); Setlreg(DE, temp); AF = (AF & ~0xfe) | (temp & 0xa8) | @@ -2365,31 +2962,37 @@ int32 sim_instr (void) { parity(temp); break; case 0x59: /* OUT (C),E */ + sim_brk_pend = FALSE; out(lreg(BC), lreg(DE)); break; - case 0x5A: /* ADC HL,DE */ - HL &= 0xffff; - DE &= 0xffff; + case 0x5a: /* ADC HL,DE */ + sim_brk_pend = FALSE; + HL &= ADDRMASK; + DE &= ADDRMASK; sum = HL + DE + TSTFLAG(C); cbits = (HL ^ DE ^ sum) >> 8; HL = sum; AF = (AF & ~0xff) | ((sum >> 8) & 0xa8) | - (((sum & 0xffff) == 0) << 6) | + (((sum & ADDRMASK) == 0) << 6) | (((cbits >> 6) ^ (cbits >> 5)) & 4) | (cbits & 0x10) | ((cbits >> 8) & 1); break; - case 0x5B: /* LD DE,(nnnn) */ + case 0x5b: /* LD DE,(nnnn) */ temp = GetWORD(PC); + CheckBreakWord(temp); DE = GetWORD(temp); PC += 2; break; - case 0x5E: /* IM 2 */ + case 0x5e: /* IM 2 */ + sim_brk_pend = FALSE; /* interrupt mode 2 */ break; - case 0x5F: /* LD A,R */ + case 0x5f: /* LD A,R */ + sim_brk_pend = FALSE; AF = (AF & 0x29) | ((ir & 255) << 8) | (ir & 0x80) | (((ir & 255) == 0) << 6) | ((IFF & 2) << 1); break; case 0x60: /* IN H,(C) */ + sim_brk_pend = FALSE; temp = in(lreg(BC)); Sethreg(HL, temp); AF = (AF & ~0xfe) | (temp & 0xa8) | @@ -2397,24 +3000,28 @@ int32 sim_instr (void) { parity(temp); break; case 0x61: /* OUT (C),H */ + sim_brk_pend = FALSE; out(lreg(BC), hreg(HL)); break; case 0x62: /* SBC HL,HL */ - HL &= 0xffff; + sim_brk_pend = FALSE; + HL &= ADDRMASK; sum = HL - HL - TSTFLAG(C); cbits = (HL ^ HL ^ sum) >> 8; HL = sum; AF = (AF & ~0xff) | ((sum >> 8) & 0xa8) | - (((sum & 0xffff) == 0) << 6) | + (((sum & ADDRMASK) == 0) << 6) | (((cbits >> 6) ^ (cbits >> 5)) & 4) | (cbits & 0x10) | 2 | ((cbits >> 8) & 1); break; case 0x63: /* LD (nnnn),HL */ temp = GetWORD(PC); + CheckBreakWord(temp); PutWORD(temp, HL); PC += 2; break; case 0x67: /* RRD */ + sim_brk_pend = FALSE; temp = GetBYTE(HL); acu = hreg(AF); PutBYTE(HL, hdig(temp) | (ldig(acu) << 4)); @@ -2423,6 +3030,7 @@ int32 sim_instr (void) { partab[acu] | (AF & 1); break; case 0x68: /* IN L,(C) */ + sim_brk_pend = FALSE; temp = in(lreg(BC)); Setlreg(HL, temp); AF = (AF & ~0xfe) | (temp & 0xa8) | @@ -2430,24 +3038,28 @@ int32 sim_instr (void) { parity(temp); break; case 0x69: /* OUT (C),L */ + sim_brk_pend = FALSE; out(lreg(BC), lreg(HL)); break; - case 0x6A: /* ADC HL,HL */ - HL &= 0xffff; + case 0x6a: /* ADC HL,HL */ + sim_brk_pend = FALSE; + HL &= ADDRMASK; sum = HL + HL + TSTFLAG(C); cbits = (HL ^ HL ^ sum) >> 8; HL = sum; AF = (AF & ~0xff) | ((sum >> 8) & 0xa8) | - (((sum & 0xffff) == 0) << 6) | + (((sum & ADDRMASK) == 0) << 6) | (((cbits >> 6) ^ (cbits >> 5)) & 4) | (cbits & 0x10) | ((cbits >> 8) & 1); break; - case 0x6B: /* LD HL,(nnnn) */ + case 0x6b: /* LD HL,(nnnn) */ temp = GetWORD(PC); + CheckBreakWord(temp); HL = GetWORD(temp); PC += 2; break; - case 0x6F: /* RLD */ + case 0x6f: /* RLD */ + sim_brk_pend = FALSE; temp = GetBYTE(HL); acu = hreg(AF); PutBYTE(HL, (ldig(temp) << 4) | ldig(acu)); @@ -2456,6 +3068,7 @@ int32 sim_instr (void) { partab[acu] | (AF & 1); break; case 0x70: /* IN (C) */ + sim_brk_pend = FALSE; temp = in(lreg(BC)); Setlreg(temp, temp); AF = (AF & ~0xfe) | (temp & 0xa8) | @@ -2463,25 +3076,29 @@ int32 sim_instr (void) { parity(temp); break; case 0x71: /* OUT (C),0 */ + sim_brk_pend = FALSE; out(lreg(BC), 0); break; case 0x72: /* SBC HL,SP */ - HL &= 0xffff; - SP &= 0xffff; + sim_brk_pend = FALSE; + HL &= ADDRMASK; + SP &= ADDRMASK; sum = HL - SP - TSTFLAG(C); cbits = (HL ^ SP ^ sum) >> 8; HL = sum; AF = (AF & ~0xff) | ((sum >> 8) & 0xa8) | - (((sum & 0xffff) == 0) << 6) | + (((sum & ADDRMASK) == 0) << 6) | (((cbits >> 6) ^ (cbits >> 5)) & 4) | (cbits & 0x10) | 2 | ((cbits >> 8) & 1); break; case 0x73: /* LD (nnnn),SP */ temp = GetWORD(PC); + CheckBreakWord(temp); PutWORD(temp, SP); PC += 2; break; case 0x78: /* IN A,(C) */ + sim_brk_pend = FALSE; temp = in(lreg(BC)); Sethreg(AF, temp); AF = (AF & ~0xfe) | (temp & 0xa8) | @@ -2489,32 +3106,37 @@ int32 sim_instr (void) { parity(temp); break; case 0x79: /* OUT (C),A */ + sim_brk_pend = FALSE; out(lreg(BC), hreg(AF)); break; - case 0x7A: /* ADC HL,SP */ - HL &= 0xffff; - SP &= 0xffff; + case 0x7a: /* ADC HL,SP */ + sim_brk_pend = FALSE; + HL &= ADDRMASK; + SP &= ADDRMASK; sum = HL + SP + TSTFLAG(C); cbits = (HL ^ SP ^ sum) >> 8; HL = sum; AF = (AF & ~0xff) | ((sum >> 8) & 0xa8) | - (((sum & 0xffff) == 0) << 6) | + (((sum & ADDRMASK) == 0) << 6) | (((cbits >> 6) ^ (cbits >> 5)) & 4) | (cbits & 0x10) | ((cbits >> 8) & 1); break; - case 0x7B: /* LD SP,(nnnn) */ + case 0x7b: /* LD SP,(nnnn) */ temp = GetWORD(PC); + CheckBreakWord(temp); SP = GetWORD(temp); PC += 2; break; - case 0xA0: /* LDI */ + case 0xa0: /* LDI */ + CheckBreakTwoBytes(HL, DE); acu = RAM_pp(HL); PutBYTE_pp(DE, acu); acu += hreg(AF); AF = (AF & ~0x3e) | (acu & 8) | ((acu & 2) << 4) | - (((--BC & 0xffff) != 0) << 2); + (((--BC & ADDRMASK) != 0) << 2); break; - case 0xA1: /* CPI */ + case 0xa1: /* CPI */ + CheckBreakByte(HL); acu = hreg(AF); temp = RAM_pp(HL); sum = acu - temp; @@ -2522,29 +3144,34 @@ int32 sim_instr (void) { AF = (AF & ~0xfe) | (sum & 0x80) | (!(sum & 0xff) << 6) | (((sum - ((cbits&16)>>4))&2) << 4) | (cbits & 16) | ((sum - ((cbits >> 4) & 1)) & 8) | - ((--BC & 0xffff) != 0) << 2 | 2; - if ((sum & 15) == 8 && (cbits & 16) != 0) + ((--BC & ADDRMASK) != 0) << 2 | 2; + if ((sum & 15) == 8 && (cbits & 16) != 0) { AF &= ~8; + } break; - case 0xA2: /* INI */ + case 0xa2: /* INI */ + CheckBreakByte(HL); PutBYTE(HL, in(lreg(BC))); ++HL; SETFLAG(N, 1); - SETFLAG(P, (--BC & 0xffff) != 0); + SETFLAG(P, (--BC & ADDRMASK) != 0); break; - case 0xA3: /* OUTI */ + case 0xa3: /* OUTI */ + CheckBreakByte(HL); out(lreg(BC), GetBYTE(HL)); ++HL; SETFLAG(N, 1); Sethreg(BC, lreg(BC) - 1); SETFLAG(Z, lreg(BC) == 0); break; - case 0xA8: /* LDD */ + case 0xa8: /* LDD */ + CheckBreakTwoBytes(HL, DE); acu = RAM_mm(HL); PutBYTE_mm(DE, acu); acu += hreg(AF); AF = (AF & ~0x3e) | (acu & 8) | ((acu & 2) << 4) | - (((--BC & 0xffff) != 0) << 2); + (((--BC & ADDRMASK) != 0) << 2); break; - case 0xA9: /* CPD */ + case 0xa9: /* CPD */ + CheckBreakByte(HL); acu = hreg(AF); temp = RAM_mm(HL); sum = acu - temp; @@ -2552,36 +3179,41 @@ int32 sim_instr (void) { AF = (AF & ~0xfe) | (sum & 0x80) | (!(sum & 0xff) << 6) | (((sum - ((cbits&16)>>4))&2) << 4) | (cbits & 16) | ((sum - ((cbits >> 4) & 1)) & 8) | - ((--BC & 0xffff) != 0) << 2 | 2; - if ((sum & 15) == 8 && (cbits & 16) != 0) + ((--BC & ADDRMASK) != 0) << 2 | 2; + if ((sum & 15) == 8 && (cbits & 16) != 0) { AF &= ~8; + } break; - case 0xAA: /* IND */ + case 0xaa: /* IND */ + CheckBreakByte(HL); PutBYTE(HL, in(lreg(BC))); --HL; SETFLAG(N, 1); Sethreg(BC, lreg(BC) - 1); SETFLAG(Z, lreg(BC) == 0); break; - case 0xAB: /* OUTD */ + case 0xab: /* OUTD */ + CheckBreakByte(HL); out(lreg(BC), GetBYTE(HL)); --HL; SETFLAG(N, 1); Sethreg(BC, lreg(BC) - 1); SETFLAG(Z, lreg(BC) == 0); break; - case 0xB0: /* LDIR */ + case 0xb0: /* LDIR */ acu = hreg(AF); - BC &= 0xffff; + BC &= ADDRMASK; do { + CheckBreakTwoBytes(HL, DE); acu = RAM_pp(HL); PutBYTE_pp(DE, acu); } while (--BC); acu += hreg(AF); AF = (AF & ~0x3e) | (acu & 8) | ((acu & 2) << 4); break; - case 0xB1: /* CPIR */ + case 0xb1: /* CPIR */ acu = hreg(AF); - BC &= 0xffff; + BC &= ADDRMASK; do { + CheckBreakByte(HL); temp = RAM_pp(HL); op = --BC != 0; sum = acu - temp; @@ -2591,40 +3223,45 @@ int32 sim_instr (void) { (((sum - ((cbits&16)>>4))&2) << 4) | (cbits & 16) | ((sum - ((cbits >> 4) & 1)) & 8) | op << 2 | 2; - if ((sum & 15) == 8 && (cbits & 16) != 0) + if ((sum & 15) == 8 && (cbits & 16) != 0) { AF &= ~8; + } break; - case 0xB2: /* INIR */ + case 0xb2: /* INIR */ temp = hreg(BC); do { + CheckBreakByte(HL); PutBYTE(HL, in(lreg(BC))); ++HL; } while (--temp); Sethreg(BC, 0); SETFLAG(N, 1); SETFLAG(Z, 1); break; - case 0xB3: /* OTIR */ + case 0xb3: /* OTIR */ temp = hreg(BC); do { + CheckBreakByte(HL); out(lreg(BC), GetBYTE(HL)); ++HL; } while (--temp); Sethreg(BC, 0); SETFLAG(N, 1); SETFLAG(Z, 1); break; - case 0xB8: /* LDDR */ - BC &= 0xffff; + case 0xb8: /* LDDR */ + BC &= ADDRMASK; do { + CheckBreakTwoBytes(HL, DE); acu = RAM_mm(HL); PutBYTE_mm(DE, acu); } while (--BC); acu += hreg(AF); AF = (AF & ~0x3e) | (acu & 8) | ((acu & 2) << 4); break; - case 0xB9: /* CPDR */ + case 0xb9: /* CPDR */ acu = hreg(AF); - BC &= 0xffff; + BC &= ADDRMASK; do { + CheckBreakByte(HL); temp = RAM_mm(HL); op = --BC != 0; sum = acu - temp; @@ -2634,21 +3271,24 @@ int32 sim_instr (void) { (((sum - ((cbits&16)>>4))&2) << 4) | (cbits & 16) | ((sum - ((cbits >> 4) & 1)) & 8) | op << 2 | 2; - if ((sum & 15) == 8 && (cbits & 16) != 0) + if ((sum & 15) == 8 && (cbits & 16) != 0) { AF &= ~8; + } break; - case 0xBA: /* INDR */ + case 0xba: /* INDR */ temp = hreg(BC); do { + CheckBreakByte(HL); PutBYTE(HL, in(lreg(BC))); --HL; } while (--temp); Sethreg(BC, 0); SETFLAG(N, 1); SETFLAG(Z, 1); break; - case 0xBB: /* OTDR */ + case 0xbb: /* OTDR */ temp = hreg(BC); do { + CheckBreakByte(HL); out(lreg(BC), GetBYTE(HL)); --HL; } while (--temp); Sethreg(BC, 0); @@ -2656,62 +3296,90 @@ int32 sim_instr (void) { SETFLAG(Z, 1); break; default: /* ignore ED and following byte */ - BadZ80OpOccured = 1; + sim_brk_pend = FALSE; + checkCPUZ80; } break; - case 0xEE: /* XOR nn */ + case 0xee: /* XOR nn */ + sim_brk_pend = FALSE; sum = ((AF >> 8) ^ RAM_pp(PC)) & 0xff; AF = (sum << 8) | (sum & 0xa8) | ((sum == 0) << 6) | partab[sum]; break; - case 0xEF: /* RST 28H */ - PUSH(PC); PC = 0x28; + case 0xef: /* RST 28H */ + CheckBreakWord(SP - 2); + PUSH(PC); PCQ_ENTRY(PC - 1); PC = 0x28; break; - case 0xF0: /* RET P */ - if (!TSTFLAG(S)) POP(PC); + case 0xf0: /* RET P */ + if (TSTFLAG(S)) { + sim_brk_pend = FALSE; + } + else { + CheckBreakWord(SP); + PCQ_ENTRY(PC - 1); + POP(PC); + } break; - case 0xF1: /* POP AF */ + case 0xf1: /* POP AF */ + CheckBreakWord(SP); POP(AF); break; - case 0xF2: /* JP P,nnnn */ + case 0xf2: /* JP P,nnnn */ + sim_brk_pend = FALSE; JPC(!TSTFLAG(S)); break; - case 0xF3: /* DI */ + + case 0xf3: /* DI */ + sim_brk_pend = FALSE; IFF = 0; break; - case 0xF4: /* CALL P,nnnn */ + case 0xf4: /* CALL P,nnnn */ CALLC(!TSTFLAG(S)); break; - case 0xF5: /* PUSH AF */ + case 0xf5: /* PUSH AF */ + CheckBreakWord(SP - 2); PUSH(AF); break; - case 0xF6: /* OR nn */ + case 0xf6: /* OR nn */ + sim_brk_pend = FALSE; sum = ((AF >> 8) | RAM_pp(PC)) & 0xff; AF = (sum << 8) | (sum & 0xa8) | ((sum == 0) << 6) | partab[sum]; break; - case 0xF7: /* RST 30H */ - PUSH(PC); PC = 0x30; + case 0xf7: /* RST 30H */ + CheckBreakWord(SP - 2); + PUSH(PC); PCQ_ENTRY(PC - 1); PC = 0x30; break; - case 0xF8: /* RET M */ - if (TSTFLAG(S)) POP(PC); + case 0xf8: /* RET M */ + if (TSTFLAG(S)) { + CheckBreakWord(SP); + PCQ_ENTRY(PC - 1); + POP(PC); + } + else { + sim_brk_pend = FALSE; + } break; - case 0xF9: /* LD SP,HL */ + case 0xf9: /* LD SP,HL */ + sim_brk_pend = FALSE; SP = HL; break; - case 0xFA: /* JP M,nnnn */ + case 0xfa: /* JP M,nnnn */ + sim_brk_pend = FALSE; JPC(TSTFLAG(S)); break; - case 0xFB: /* EI */ + case 0xfb: /* EI */ + sim_brk_pend = FALSE; IFF = 3; break; - case 0xFC: /* CALL M,nnnn */ + case 0xfc: /* CALL M,nnnn */ CALLC(TSTFLAG(S)); break; - case 0xFD: /* FD prefix */ - checkCPU + case 0xfd: /* FD prefix */ + checkCPU8080; switch (op = RAM_pp(PC)) { case 0x09: /* ADD IY,BC */ - IY &= 0xffff; - BC &= 0xffff; + sim_brk_pend = FALSE; + IY &= ADDRMASK; + BC &= ADDRMASK; sum = IY + BC; cbits = (IY ^ BC ^ sum) >> 8; IY = sum; @@ -2719,8 +3387,9 @@ int32 sim_instr (void) { (cbits & 0x10) | ((cbits >> 8) & 1); break; case 0x19: /* ADD IY,DE */ - IY &= 0xffff; - DE &= 0xffff; + sim_brk_pend = FALSE; + IY &= ADDRMASK; + DE &= ADDRMASK; sum = IY + DE; cbits = (IY ^ DE ^ sum) >> 8; IY = sum; @@ -2728,18 +3397,22 @@ int32 sim_instr (void) { (cbits & 0x10) | ((cbits >> 8) & 1); break; case 0x21: /* LD IY,nnnn */ + sim_brk_pend = FALSE; IY = GetWORD(PC); PC += 2; break; case 0x22: /* LD (nnnn),IY */ temp = GetWORD(PC); + CheckBreakWord(temp); PutWORD(temp, IY); PC += 2; break; case 0x23: /* INC IY */ + sim_brk_pend = FALSE; ++IY; break; case 0x24: /* INC IYH */ + sim_brk_pend = FALSE; IY += 0x100; temp = hreg(IY); AF = (AF & ~0xfe) | (temp & 0xa8) | @@ -2748,6 +3421,7 @@ int32 sim_instr (void) { ((temp == 0x80) << 2); break; case 0x25: /* DEC IYH */ + sim_brk_pend = FALSE; IY -= 0x100; temp = hreg(IY); AF = (AF & ~0xfe) | (temp & 0xa8) | @@ -2756,46 +3430,54 @@ int32 sim_instr (void) { ((temp == 0x7f) << 2) | 2; break; case 0x26: /* LD IYH,nn */ + sim_brk_pend = FALSE; Sethreg(IY, RAM_pp(PC)); break; case 0x29: /* ADD IY,IY */ - IY &= 0xffff; + sim_brk_pend = FALSE; + IY &= ADDRMASK; sum = IY + IY; cbits = (IY ^ IY ^ sum) >> 8; IY = sum; AF = (AF & ~0x3b) | ((sum >> 8) & 0x28) | (cbits & 0x10) | ((cbits >> 8) & 1); break; - case 0x2A: /* LD IY,(nnnn) */ + case 0x2a: /* LD IY,(nnnn) */ temp = GetWORD(PC); + CheckBreakWord(temp); IY = GetWORD(temp); PC += 2; break; - case 0x2B: /* DEC IY */ + case 0x2b: /* DEC IY */ + sim_brk_pend = FALSE; --IY; break; - case 0x2C: /* INC IYL */ - temp = lreg(IY)+1; + case 0x2c: /* INC IYL */ + sim_brk_pend = FALSE; + temp = lreg(IY) + 1; Setlreg(IY, temp); AF = (AF & ~0xfe) | (temp & 0xa8) | (((temp & 0xff) == 0) << 6) | (((temp & 0xf) == 0) << 4) | ((temp == 0x80) << 2); break; - case 0x2D: /* DEC IYL */ - temp = lreg(IY)-1; + case 0x2d: /* DEC IYL */ + sim_brk_pend = FALSE; + temp = lreg(IY) - 1; Setlreg(IY, temp); AF = (AF & ~0xfe) | (temp & 0xa8) | (((temp & 0xff) == 0) << 6) | (((temp & 0xf) == 0xf) << 4) | ((temp == 0x7f) << 2) | 2; break; - case 0x2E: /* LD IYL,nn */ + case 0x2e: /* LD IYL,nn */ + sim_brk_pend = FALSE; Setlreg(IY, RAM_pp(PC)); break; case 0x34: /* INC (IY+dd) */ adr = IY + (signed char) RAM_pp(PC); - temp = GetBYTE(adr)+1; + CheckBreakByte(adr); + temp = GetBYTE(adr) + 1; PutBYTE(adr, temp); AF = (AF & ~0xfe) | (temp & 0xa8) | (((temp & 0xff) == 0) << 6) | @@ -2804,7 +3486,8 @@ int32 sim_instr (void) { break; case 0x35: /* DEC (IY+dd) */ adr = IY + (signed char) RAM_pp(PC); - temp = GetBYTE(adr)-1; + CheckBreakByte(adr); + temp = GetBYTE(adr) - 1; PutBYTE(adr, temp); AF = (AF & ~0xfe) | (temp & 0xa8) | (((temp & 0xff) == 0) << 6) | @@ -2813,11 +3496,13 @@ int32 sim_instr (void) { break; case 0x36: /* LD (IY+dd),nn */ adr = IY + (signed char) RAM_pp(PC); + CheckBreakByte(adr); PutBYTE(adr, RAM_pp(PC)); break; case 0x39: /* ADD IY,SP */ - IY &= 0xffff; - SP &= 0xffff; + sim_brk_pend = FALSE; + IY &= ADDRMASK; + SP &= ADDRMASK; sum = IY + SP; cbits = (IY ^ SP ^ sum) >> 8; IY = sum; @@ -2825,134 +3510,173 @@ int32 sim_instr (void) { (cbits & 0x10) | ((cbits >> 8) & 1); break; case 0x44: /* LD B,IYH */ + sim_brk_pend = FALSE; Sethreg(BC, hreg(IY)); break; case 0x45: /* LD B,IYL */ + sim_brk_pend = FALSE; Sethreg(BC, lreg(IY)); break; case 0x46: /* LD B,(IY+dd) */ adr = IY + (signed char) RAM_pp(PC); + CheckBreakByte(adr); Sethreg(BC, GetBYTE(adr)); break; - case 0x4C: /* LD C,IYH */ + case 0x4c: /* LD C,IYH */ + sim_brk_pend = FALSE; Setlreg(BC, hreg(IY)); break; - case 0x4D: /* LD C,IYL */ + case 0x4d: /* LD C,IYL */ + sim_brk_pend = FALSE; Setlreg(BC, lreg(IY)); break; - case 0x4E: /* LD C,(IY+dd) */ + case 0x4e: /* LD C,(IY+dd) */ adr = IY + (signed char) RAM_pp(PC); + CheckBreakByte(adr); Setlreg(BC, GetBYTE(adr)); break; case 0x54: /* LD D,IYH */ + sim_brk_pend = FALSE; Sethreg(DE, hreg(IY)); break; case 0x55: /* LD D,IYL */ + sim_brk_pend = FALSE; Sethreg(DE, lreg(IY)); break; case 0x56: /* LD D,(IY+dd) */ adr = IY + (signed char) RAM_pp(PC); + CheckBreakByte(adr); Sethreg(DE, GetBYTE(adr)); break; - case 0x5C: /* LD E,H */ + case 0x5c: /* LD E,H */ + sim_brk_pend = FALSE; Setlreg(DE, hreg(IY)); break; - case 0x5D: /* LD E,L */ + case 0x5d: /* LD E,L */ + sim_brk_pend = FALSE; Setlreg(DE, lreg(IY)); break; - case 0x5E: /* LD E,(IY+dd) */ + case 0x5e: /* LD E,(IY+dd) */ adr = IY + (signed char) RAM_pp(PC); + CheckBreakByte(adr); Setlreg(DE, GetBYTE(adr)); break; case 0x60: /* LD IYH,B */ + sim_brk_pend = FALSE; Sethreg(IY, hreg(BC)); break; case 0x61: /* LD IYH,C */ + sim_brk_pend = FALSE; Sethreg(IY, lreg(BC)); break; case 0x62: /* LD IYH,D */ + sim_brk_pend = FALSE; Sethreg(IY, hreg(DE)); break; case 0x63: /* LD IYH,E */ + sim_brk_pend = FALSE; Sethreg(IY, lreg(DE)); break; case 0x64: /* LD IYH,IYH */ + sim_brk_pend = FALSE; /* nop */ break; case 0x65: /* LD IYH,IYL */ + sim_brk_pend = FALSE; Sethreg(IY, lreg(IY)); break; case 0x66: /* LD H,(IY+dd) */ adr = IY + (signed char) RAM_pp(PC); + CheckBreakByte(adr); Sethreg(HL, GetBYTE(adr)); break; case 0x67: /* LD IYH,A */ + sim_brk_pend = FALSE; Sethreg(IY, hreg(AF)); break; case 0x68: /* LD IYL,B */ + sim_brk_pend = FALSE; Setlreg(IY, hreg(BC)); break; case 0x69: /* LD IYL,C */ + sim_brk_pend = FALSE; Setlreg(IY, lreg(BC)); break; - case 0x6A: /* LD IYL,D */ + case 0x6a: /* LD IYL,D */ + sim_brk_pend = FALSE; Setlreg(IY, hreg(DE)); break; - case 0x6B: /* LD IYL,E */ + case 0x6b: /* LD IYL,E */ + sim_brk_pend = FALSE; Setlreg(IY, lreg(DE)); break; - case 0x6C: /* LD IYL,IYH */ + case 0x6c: /* LD IYL,IYH */ + sim_brk_pend = FALSE; Setlreg(IY, hreg(IY)); break; - case 0x6D: /* LD IYL,IYL */ + case 0x6d: /* LD IYL,IYL */ + sim_brk_pend = FALSE; /* nop */ break; - case 0x6E: /* LD L,(IY+dd) */ + case 0x6e: /* LD L,(IY+dd) */ adr = IY + (signed char) RAM_pp(PC); + CheckBreakByte(adr); Setlreg(HL, GetBYTE(adr)); break; - case 0x6F: /* LD IYL,A */ + case 0x6f: /* LD IYL,A */ + sim_brk_pend = FALSE; Setlreg(IY, hreg(AF)); break; case 0x70: /* LD (IY+dd),B */ adr = IY + (signed char) RAM_pp(PC); + CheckBreakByte(adr); PutBYTE(adr, hreg(BC)); break; case 0x71: /* LD (IY+dd),C */ adr = IY + (signed char) RAM_pp(PC); + CheckBreakByte(adr); PutBYTE(adr, lreg(BC)); break; case 0x72: /* LD (IY+dd),D */ adr = IY + (signed char) RAM_pp(PC); + CheckBreakByte(adr); PutBYTE(adr, hreg(DE)); break; case 0x73: /* LD (IY+dd),E */ adr = IY + (signed char) RAM_pp(PC); + CheckBreakByte(adr); PutBYTE(adr, lreg(DE)); break; case 0x74: /* LD (IY+dd),H */ adr = IY + (signed char) RAM_pp(PC); + CheckBreakByte(adr); PutBYTE(adr, hreg(HL)); break; case 0x75: /* LD (IY+dd),L */ adr = IY + (signed char) RAM_pp(PC); + CheckBreakByte(adr); PutBYTE(adr, lreg(HL)); break; case 0x77: /* LD (IY+dd),A */ adr = IY + (signed char) RAM_pp(PC); + CheckBreakByte(adr); PutBYTE(adr, hreg(AF)); break; - case 0x7C: /* LD A,IYH */ + case 0x7c: /* LD A,IYH */ + sim_brk_pend = FALSE; Sethreg(AF, hreg(IY)); break; - case 0x7D: /* LD A,IYL */ + case 0x7d: /* LD A,IYL */ + sim_brk_pend = FALSE; Sethreg(AF, lreg(IY)); break; - case 0x7E: /* LD A,(IY+dd) */ + case 0x7e: /* LD A,(IY+dd) */ adr = IY + (signed char) RAM_pp(PC); + CheckBreakByte(adr); Sethreg(AF, GetBYTE(adr)); break; case 0x84: /* ADD A,IYH */ + sim_brk_pend = FALSE; temp = hreg(IY); acu = hreg(AF); sum = acu + temp; @@ -2963,6 +3687,7 @@ int32 sim_instr (void) { ((cbits >> 8) & 1); break; case 0x85: /* ADD A,IYL */ + sim_brk_pend = FALSE; temp = lreg(IY); acu = hreg(AF); sum = acu + temp; @@ -2974,6 +3699,7 @@ int32 sim_instr (void) { break; case 0x86: /* ADD A,(IY+dd) */ adr = IY + (signed char) RAM_pp(PC); + CheckBreakByte(adr); temp = GetBYTE(adr); acu = hreg(AF); sum = acu + temp; @@ -2983,7 +3709,8 @@ int32 sim_instr (void) { (((cbits >> 6) ^ (cbits >> 5)) & 4) | ((cbits >> 8) & 1); break; - case 0x8C: /* ADC A,IYH */ + case 0x8c: /* ADC A,IYH */ + sim_brk_pend = FALSE; temp = hreg(IY); acu = hreg(AF); sum = acu + temp + TSTFLAG(C); @@ -2993,7 +3720,8 @@ int32 sim_instr (void) { (((cbits >> 6) ^ (cbits >> 5)) & 4) | ((cbits >> 8) & 1); break; - case 0x8D: /* ADC A,IYL */ + case 0x8d: /* ADC A,IYL */ + sim_brk_pend = FALSE; temp = lreg(IY); acu = hreg(AF); sum = acu + temp + TSTFLAG(C); @@ -3003,8 +3731,9 @@ int32 sim_instr (void) { (((cbits >> 6) ^ (cbits >> 5)) & 4) | ((cbits >> 8) & 1); break; - case 0x8E: /* ADC A,(IY+dd) */ + case 0x8e: /* ADC A,(IY+dd) */ adr = IY + (signed char) RAM_pp(PC); + CheckBreakByte(adr); temp = GetBYTE(adr); acu = hreg(AF); sum = acu + temp + TSTFLAG(C); @@ -3015,6 +3744,7 @@ int32 sim_instr (void) { ((cbits >> 8) & 1); break; case 0x94: /* SUB IYH */ + sim_brk_pend = FALSE; temp = hreg(IY); acu = hreg(AF); sum = acu - temp; @@ -3025,6 +3755,7 @@ int32 sim_instr (void) { ((cbits >> 8) & 1); break; case 0x95: /* SUB IYL */ + sim_brk_pend = FALSE; temp = lreg(IY); acu = hreg(AF); sum = acu - temp; @@ -3036,6 +3767,7 @@ int32 sim_instr (void) { break; case 0x96: /* SUB (IY+dd) */ adr = IY + (signed char) RAM_pp(PC); + CheckBreakByte(adr); temp = GetBYTE(adr); acu = hreg(AF); sum = acu - temp; @@ -3045,7 +3777,8 @@ int32 sim_instr (void) { (((cbits >> 6) ^ (cbits >> 5)) & 4) | 2 | ((cbits >> 8) & 1); break; - case 0x9C: /* SBC A,IYH */ + case 0x9c: /* SBC A,IYH */ + sim_brk_pend = FALSE; temp = hreg(IY); acu = hreg(AF); sum = acu - temp - TSTFLAG(C); @@ -3055,7 +3788,8 @@ int32 sim_instr (void) { (((cbits >> 6) ^ (cbits >> 5)) & 4) | 2 | ((cbits >> 8) & 1); break; - case 0x9D: /* SBC A,IYL */ + case 0x9d: /* SBC A,IYL */ + sim_brk_pend = FALSE; temp = lreg(IY); acu = hreg(AF); sum = acu - temp - TSTFLAG(C); @@ -3065,8 +3799,9 @@ int32 sim_instr (void) { (((cbits >> 6) ^ (cbits >> 5)) & 4) | 2 | ((cbits >> 8) & 1); break; - case 0x9E: /* SBC A,(IY+dd) */ + case 0x9e: /* SBC A,(IY+dd) */ adr = IY + (signed char) RAM_pp(PC); + CheckBreakByte(adr); temp = GetBYTE(adr); acu = hreg(AF); sum = acu - temp - TSTFLAG(C); @@ -3076,49 +3811,59 @@ int32 sim_instr (void) { (((cbits >> 6) ^ (cbits >> 5)) & 4) | 2 | ((cbits >> 8) & 1); break; - case 0xA4: /* AND IYH */ + case 0xa4: /* AND IYH */ + sim_brk_pend = FALSE; sum = ((AF & (IY)) >> 8) & 0xff; AF = (sum << 8) | (sum & 0xa8) | ((sum == 0) << 6) | 0x10 | partab[sum]; break; - case 0xA5: /* AND IYL */ + case 0xa5: /* AND IYL */ + sim_brk_pend = FALSE; sum = ((AF >> 8) & IY) & 0xff; AF = (sum << 8) | (sum & 0xa8) | 0x10 | ((sum == 0) << 6) | partab[sum]; break; - case 0xA6: /* AND (IY+dd) */ + case 0xa6: /* AND (IY+dd) */ adr = IY + (signed char) RAM_pp(PC); + CheckBreakByte(adr); sum = ((AF >> 8) & GetBYTE(adr)) & 0xff; AF = (sum << 8) | (sum & 0xa8) | 0x10 | ((sum == 0) << 6) | partab[sum]; break; - case 0xAC: /* XOR IYH */ + case 0xac: /* XOR IYH */ + sim_brk_pend = FALSE; sum = ((AF ^ (IY)) >> 8) & 0xff; AF = (sum << 8) | (sum & 0xa8) | ((sum == 0) << 6) | partab[sum]; break; - case 0xAD: /* XOR IYL */ + case 0xad: /* XOR IYL */ + sim_brk_pend = FALSE; sum = ((AF >> 8) ^ IY) & 0xff; AF = (sum << 8) | (sum & 0xa8) | ((sum == 0) << 6) | partab[sum]; break; - case 0xAE: /* XOR (IY+dd) */ + case 0xae: /* XOR (IY+dd) */ adr = IY + (signed char) RAM_pp(PC); + CheckBreakByte(adr); sum = ((AF >> 8) ^ GetBYTE(adr)) & 0xff; AF = (sum << 8) | (sum & 0xa8) | ((sum == 0) << 6) | partab[sum]; break; - case 0xB4: /* OR IYH */ + case 0xb4: /* OR IYH */ + sim_brk_pend = FALSE; sum = ((AF | (IY)) >> 8) & 0xff; AF = (sum << 8) | (sum & 0xa8) | ((sum == 0) << 6) | partab[sum]; break; - case 0xB5: /* OR IYL */ + case 0xb5: /* OR IYL */ + sim_brk_pend = FALSE; sum = ((AF >> 8) | IY) & 0xff; AF = (sum << 8) | (sum & 0xa8) | ((sum == 0) << 6) | partab[sum]; break; - case 0xB6: /* OR (IY+dd) */ + case 0xb6: /* OR (IY+dd) */ adr = IY + (signed char) RAM_pp(PC); + CheckBreakByte(adr); sum = ((AF >> 8) | GetBYTE(adr)) & 0xff; AF = (sum << 8) | (sum & 0xa8) | ((sum == 0) << 6) | partab[sum]; break; - case 0xBC: /* CP IYH */ + case 0xbc: /* CP IYH */ + sim_brk_pend = FALSE; temp = hreg(IY); AF = (AF & ~0x28) | (temp & 0x28); acu = hreg(AF); @@ -3129,7 +3874,8 @@ int32 sim_instr (void) { (((cbits >> 6) ^ (cbits >> 5)) & 4) | 2 | (cbits & 0x10) | ((cbits >> 8) & 1); break; - case 0xBD: /* CP IYL */ + case 0xbd: /* CP IYL */ + sim_brk_pend = FALSE; temp = lreg(IY); AF = (AF & ~0x28) | (temp & 0x28); acu = hreg(AF); @@ -3140,8 +3886,9 @@ int32 sim_instr (void) { (((cbits >> 6) ^ (cbits >> 5)) & 4) | 2 | (cbits & 0x10) | ((cbits >> 8) & 1); break; - case 0xBE: /* CP (IY+dd) */ + case 0xbe: /* CP (IY+dd) */ adr = IY + (signed char) RAM_pp(PC); + CheckBreakByte(adr); temp = GetBYTE(adr); AF = (AF & ~0x28) | (temp & 0x28); acu = hreg(AF); @@ -3152,18 +3899,17 @@ int32 sim_instr (void) { (((cbits >> 6) ^ (cbits >> 5)) & 4) | 2 | (cbits & 0x10) | ((cbits >> 8) & 1); break; - case 0xCB: /* CB prefix */ + case 0xcb: /* CB prefix */ adr = IY + (signed char) RAM_pp(PC); - adr = adr; switch ((op = GetBYTE(PC)) & 7) { - case 0: ++PC; acu = hreg(BC); break; - case 1: ++PC; acu = lreg(BC); break; - case 2: ++PC; acu = hreg(DE); break; - case 3: ++PC; acu = lreg(DE); break; - case 4: ++PC; acu = hreg(HL); break; - case 5: ++PC; acu = lreg(HL); break; - case 6: ++PC; acu = GetBYTE(adr); break; - case 7: ++PC; acu = hreg(AF); break; + case 0: sim_brk_pend = FALSE; ++PC; acu = hreg(BC); break; + case 1: sim_brk_pend = FALSE; ++PC; acu = lreg(BC); break; + case 2: sim_brk_pend = FALSE; ++PC; acu = hreg(DE); break; + case 3: sim_brk_pend = FALSE; ++PC; acu = lreg(DE); break; + case 4: sim_brk_pend = FALSE; ++PC; acu = hreg(HL); break; + case 5: sim_brk_pend = FALSE; ++PC; acu = lreg(HL); break; + case 6: CheckBreakByte(adr); ++PC; acu = GetBYTE(adr); break; + case 7: sim_brk_pend = FALSE; ++PC; acu = hreg(AF); break; } switch (op & 0xc0) { case 0x00: /* shift/rotate */ @@ -3206,13 +3952,16 @@ int32 sim_instr (void) { } break; case 0x40: /* BIT */ - if (acu & (1 << ((op >> 3) & 7))) + if (acu & (1 << ((op >> 3) & 7))) { AF = (AF & ~0xfe) | 0x10 | (((op & 0x38) == 0x38) << 7); - else + } + else { AF = (AF & ~0xfe) | 0x54; - if ((op&7) != 6) + } + if ((op&7) != 6) { AF |= (acu & 0x28); + } temp = acu; break; case 0x80: /* RES */ @@ -3233,27 +3982,35 @@ int32 sim_instr (void) { case 7: Sethreg(AF, temp); break; } break; - case 0xE1: /* POP IY */ + case 0xe1: /* POP IY */ + CheckBreakWord(SP); POP(IY); break; - case 0xE3: /* EX (SP),IY */ + case 0xe3: /* EX (SP),IY */ + CheckBreakWord(SP); temp = IY; POP(IY); PUSH(temp); break; - case 0xE5: /* PUSH IY */ + case 0xe5: /* PUSH IY */ + CheckBreakWord(SP - 2); PUSH(IY); break; - case 0xE9: /* JP (IY) */ + case 0xe9: /* JP (IY) */ + sim_brk_pend = FALSE; + PCQ_ENTRY(PC - 2); PC = IY; break; - case 0xF9: /* LD SP,IY */ + case 0xf9: /* LD SP,IY */ + sim_brk_pend = FALSE; SP = IY; break; default: /* ignore FD */ - BadZ80OpOccured = 1; + sim_brk_pend = FALSE; + checkCPUZ80; PC--; } break; - case 0xFE: /* CP nn */ + case 0xfe: /* CP nn */ + sim_brk_pend = FALSE; temp = RAM_pp(PC); AF = (AF & ~0x28) | (temp & 0x28); acu = hreg(AF); @@ -3264,13 +4021,12 @@ int32 sim_instr (void) { (SetPV) | 2 | (cbits & 0x10) | ((cbits >> 8) & 1); break; - case 0xFF: /* RST 38H */ - PUSH(PC); PC = 0x38; - } - if ((BadZ80OpOccured || Bad8080OpOccured) && (cpu_unit.flags & UNIT_OPSTOP)) { - reason = STOP_OPCODE; + case 0xff: /* RST 38H */ + CheckBreakWord(SP - 2); + PUSH(PC); PCQ_ENTRY(PC - 1); PC = 0x38; } } + end_decode: pc = PC; af[af_sel] = AF; regs[regs_sel].bc = BC; @@ -3281,7 +4037,8 @@ int32 sim_instr (void) { sp = SP; /* Simulation halted */ - saved_PC = (reason == STOP_OPCODE) ? PCX : pc; + saved_PC = ((reason == STOP_OPCODE) || (reason == STOP_MEM)) ? PCX : pc; + pcq_r -> qptr = pcq_p; /* update pc q ptr */ AF_S = af[af_sel]; BC_S = regs[regs_sel].bc; DE_S = regs[regs_sel].de; @@ -3289,81 +4046,124 @@ int32 sim_instr (void) { IX_S = ix; IY_S = iy; SP_S = sp; - AF1_S = af[1-af_sel]; - BC1_S = regs[1-regs_sel].bc; - DE1_S = regs[1-regs_sel].de; - HL1_S = regs[1-regs_sel].hl; + AF1_S = af[1 - af_sel]; + BC1_S = regs[1 - regs_sel].bc; + DE1_S = regs[1 - regs_sel].de; + HL1_S = regs[1 - regs_sel].hl; IFF_S = IFF; INT_S = ir; return reason; } -void clear_memory(int32 starting) { +void install_bootrom(void) { int32 i; - for (i = starting; i < MAXMEMSIZE; i++) { - M[i] = 0; - } for (i = 0; i < bootrom_size; i++) { - M[i + bootrom_origin] = bootrom[i] & 0xFF; + M[i + bootrom_origin][0] = bootrom[i] & 0xff; } } +void clear_memory(int32 starting) { + int32 i, j; + if (cpu_unit.flags & UNIT_BANKED) { + for (i = 0; i < MAXMEMSIZE; i++) { + for (j = 0; j < MAXBANKS; j++) { + M[i][j] = 0; + } + } + } + else { + for (i = starting; i < MAXMEMSIZE; i++) { + M[i][0] = 0; + } + } + install_bootrom(); +} + /* Reset routine */ -t_stat cpu_reset (DEVICE *dptr) - -{ - af[0] = af[1] = 0; +t_stat cpu_reset(DEVICE *dptr) { + int32 i; + AF_S = AF1_S = 0; af_sel = 0; - regs[0].bc = regs[0].de = regs[0].hl = 0; + BC_S = DE_S = HL_S = 0; regs_sel = 0; - regs[1].bc = regs[1].de = regs[1].hl = 0; - ir = ix = iy = sp = pc = IFF = 0; + BC1_S = DE1_S = HL1_S = 0; + INT_S = IX_S = IY_S = SP_S = 0; + IFF_S = 3; + bankSelect = 0; saved_PC = 0; clear_memory(0); - markTimeSP = 0; - sim_brk_types = sim_brk_dflt = SWMASK ('E'); + sim_brk_types = (SWMASK('E') | SWMASK('M')); + sim_brk_dflt = SWMASK('E'); + for (i = 0; i < PCQ_SIZE; i++) { + pcq[i] = 0; + } + pcq_p = 0; + pcq_r = find_reg("PCQ", NULL, dptr); + if (pcq_r) { + pcq_r -> qptr = 0; + } + else { + return SCPE_IERR; + } return SCPE_OK; } /* Memory examine */ - -t_stat cpu_ex (t_value *vptr, t_addr addr, UNIT *uptr, int32 sw) -{ - if ((addr >= MEMSIZE) && (addr < bootrom_origin)) { - return SCPE_NXM; +t_stat cpu_ex(t_value *vptr, t_addr addr, UNIT *uptr, int32 sw) { + if (cpu_unit.flags & UNIT_BANKED) { + if (addr >= MAXMEMSIZE) { + return SCPE_NXM; + } + } + else { + if ((addr >= MEMSIZE) && (addr < bootrom_origin)) { + return SCPE_NXM; + } } if (vptr != NULL) { - *vptr = M[addr] & 0xff; + *vptr = GetBYTE(addr) & 0xff; } return SCPE_OK; } /* Memory deposit */ - -t_stat cpu_dep (t_value val, t_addr addr, UNIT *uptr, int32 sw) -{ - if ((addr >= MEMSIZE) || (addr >= bootrom_origin)) { - return SCPE_NXM; +t_stat cpu_dep(t_value val, t_addr addr, UNIT *uptr, int32 sw) { + if (cpu_unit.flags & UNIT_BANKED) { + if ((addr >= bootrom_origin) && (cpu_unit.flags & UNIT_ROM)) { + return SCPE_NXM; + } } - M[addr] = val & 0xff; + else { + if ((addr >= MEMSIZE) || ((addr >= bootrom_origin) && (cpu_unit.flags & UNIT_ROM))) { + return SCPE_NXM; + } + } + PutBYTE(addr, val & 0xff); return SCPE_OK; } -t_stat cpu_set_size (UNIT *uptr, int32 value, char *cptr, void *desc) -{ - int32 mc = 0; - t_addr i; - int32 limit; - - if ((value <= 0) || (value > MAXMEMSIZE) || ((value & 0xFFF) != 0)) { - return SCPE_ARG; +t_stat cpu_set_rom(UNIT *uptr, int32 value, char *cptr, void *desc) { + install_bootrom(); + return SCPE_OK; +} + +t_stat cpu_set_banked(UNIT *uptr, int32 value, char *cptr, void *desc) { + return MEMSIZE < MAXMEMSIZE ? SCPE_ARG : SCPE_OK; +} + +t_stat cpu_set_size(UNIT *uptr, int32 value, char *cptr, void *desc) { + int32 i, limit, mc = 0; + + if ((cpu_unit.flags & UNIT_BANKED) || + (value <= 0) || (value > MAXMEMSIZE) || ((value & 0xfff) != 0)) { + return SCPE_ARG; } limit = (bootrom_origin < MEMSIZE) ? bootrom_origin : MEMSIZE; for (i = value; i < limit; i++) { - mc |= M[i]; + mc |= GetBYTE(i); } - if (mc && (!get_yn ("Really truncate memory [N]?", FALSE))) { + if (mc && (!get_yn("Really truncate memory [N]?", FALSE))) { return SCPE_OK; } MEMSIZE = value; diff --git a/AltairZ80/altairZ80_defs.h b/AltairZ80/altairZ80_defs.h index 93776ccd..931a291e 100644 --- a/AltairZ80/altairZ80_defs.h +++ b/AltairZ80/altairZ80_defs.h @@ -1,30 +1,46 @@ /* altairZ80_defs.h: MITS Altair simulator definitions - Written by Peter Schorn, 2001 + Written by Peter Schorn, 2001-2002 Based on work by Charles E Owen ((c) 1997, Commercial use prohibited) */ -#include "sim_defs.h" /* simulator definitions */ +#include "sim_defs.h" /* simulator definitions */ /* Memory */ -#define MAXMEMSIZE 65536 /* max memory size */ -#define KB 1024 /* kilo byte */ -#define MEMSIZE (cpu_unit.capac) /* actual memory size */ -#define ADDRMASK (MAXMEMSIZE - 1) /* address mask */ -#define bootrom_size 256 /* size of boot rom */ -#define bootrom_origin 0xFF00 /* start address of boot rom */ +#define MAXMEMSIZE 65536 /* max memory size */ +#define ADDRMASK (MAXMEMSIZE - 1) /* address mask */ +#define bootrom_size 256 /* size of boot rom */ +#define MAXBANKS 8 /* max number of memory banks */ +#define MAXBANKSLOG2 3 /* log2 of MAXBANKS */ +#define BANKMASK (MAXBANKS-1) /* bank mask */ -#define BACKSPACE_CHAR 0x08 /* backspace character */ -#define DELETE_CHAR 0x7f /* delete character */ -#define CONTROLZ_CHAR 26 /* control Z character */ - -/* Simulator stop codes */ -#define STOP_HALT 2 /* HALT */ -#define STOP_IBKPT 3 /* breakpoint */ -#define STOP_OPCODE 4 - -#define UNIT_V_OPSTOP (UNIT_V_UF) /* Stop on Invalid OP? */ +#define UNIT_V_OPSTOP (UNIT_V_UF) /* Stop on Invalid OP? */ #define UNIT_OPSTOP (1 << UNIT_V_OPSTOP) -#define UNIT_V_CHIP (UNIT_V_UF+1) /* 8080 or Z80 */ +#define UNIT_V_CHIP (UNIT_V_UF+1) /* 8080 or Z80 */ #define UNIT_CHIP (1 << UNIT_V_CHIP) -#define UNIT_V_MSIZE (UNIT_V_UF+2) /* Memory Size */ +#define UNIT_V_MSIZE (UNIT_V_UF+2) /* Memory Size */ #define UNIT_MSIZE (1 << UNIT_V_MSIZE) +#define UNIT_V_BANKED (UNIT_V_UF+3) /* Banked memory is used */ +#define UNIT_BANKED (1 << UNIT_V_BANKED) +#define UNIT_V_ROM (UNIT_V_UF+4) /* ROM exists */ +#define UNIT_ROM (1 << UNIT_V_ROM) + +#define PCformat "\n[%04xh] " +#define message1(p1) sprintf(messageBuffer,PCformat p1,PCX); printMessage() +#define message2(p1,p2) sprintf(messageBuffer,PCformat p1,PCX,p2); printMessage() +#define message3(p1,p2,p3) sprintf(messageBuffer,PCformat p1,PCX,p2,p3); printMessage() +#define message4(p1,p2,p3,p4) sprintf(messageBuffer,PCformat p1,PCX,p2,p3,p4); printMessage() + +/* The Default is to use "inline". In this case the wrapper functions for + GetBYTE and PutBYTE need to be created. Otherwise they are not needed + and the calls map to the original functions. */ +#ifdef NO_INLINE +#define INLINE +#define GetBYTEWrapper GetBYTE +#define PutBYTEWrapper PutBYTE +#else +#if defined(__DECC) && defined(VMS) +#define INLINE __inline +#else +#define INLINE inline +#endif +#endif diff --git a/AltairZ80/altairZ80_dsk.c b/AltairZ80/altairZ80_dsk.c index 873766a2..3eef5a73 100644 --- a/AltairZ80/altairZ80_dsk.c +++ b/AltairZ80/altairZ80_dsk.c @@ -1,43 +1,43 @@ /* altairZ80_dsk.c: MITS Altair 88-DISK Simulator Written by Charles E Owen ((c) 1997, Commercial use prohibited) - Minor modifications by Peter Schorn, 2001 + Modifications to improve robustness by Peter Schorn, 2001-2002 The 88_DISK is a 8-inch floppy controller which can control up to 16 daisy-chained Pertec FD-400 hard-sectored floppy drives. Each diskette has physically 77 tracks of 32 137-byte sectors each. - + The controller is interfaced to the CPU by use of 3 I/O addreses, standardly, these are device numbers 10, 11, and 12 (octal). - + Address Mode Function ------- ---- -------- - + 10 Out Selects and enables Controller and Drive 10 In Indicates status of Drive and Controller 11 Out Controls Disk Function 11 In Indicates current sector position of disk 12 Out Write data 12 In Read data - + Drive Select Out (Device 10 OUT): - + +---+---+---+---+---+---+---+---+ | C | X | X | X | Device | +---+---+---+---+---+---+---+---+ - + C = If this bit is 1, the disk controller selected by 'device' is cleared. If the bit is zero, 'device' is selected as the device being controlled by subsequent I/O operations. X = not used Device = value zero thru 15, selects drive to be controlled. - + Drive Status In (Device 10 IN): - + +---+---+---+---+---+---+---+---+ | R | Z | I | X | X | H | M | W | +---+---+---+---+---+---+---+---+ - + W - When 0, write circuit ready to write another byte. M - When 0, head movement is allowed H - When 0, indicates head is loaded for read/write @@ -45,20 +45,20 @@ I - When 0, indicates interrupts enabled (not used this simulator) Z - When 0, indicates head is on track 0 R - When 0, indicates that read circuit has new byte to read - + Drive Control (Device 11 OUT): - + +---+---+---+---+---+---+---+---+ | W | C | D | E | U | H | O | I | +---+---+---+---+---+---+---+---+ - + I - When 1, steps head IN one track O - When 1, steps head OUT one track H - When 1, loads head to drive surface U - When 1, unloads head - E - Enables interrupts (ignored this simulator) - D - Disables interrupts (ignored this simulator) - C - When 1 lowers head current (ignored this simulator) + E - Enables interrupts (ignored by this simulator) + D - Disables interrupts (ignored by this simulator) + C - When 1 lowers head current (ignored by this simulator) W - When 1, starts Write Enable sequence: W bit on device 10 (see above) will go 1 and data will be read from port 12 until 137 bytes have been read by the controller from @@ -67,16 +67,16 @@ stepped the track to the desired number, and waited until the right sector number is presented on device 11 IN, then set this bit. - + Sector Position (Device 11 IN): - + As the sectors pass by the read head, they are counted and the number of the current one is available in this register. - + +---+---+---+---+---+---+---+---+ | X | X | Sector Number | T | +---+---+---+---+---+---+---+---+ - + X = Not used Sector number = binary of the sector number currently under the head, 0-31. @@ -88,85 +88,207 @@ #include #include "altairZ80_defs.h" -#define UNIT_V_ENABLE (UNIT_V_UF + 0) /* Write Enable */ -#define UNIT_ENABLE (1 << UNIT_V_ENABLE) -#define DSK_SECTSIZE 137 /* size of sector */ -#define DSK_SECT 32 /* sectors per track */ +#define UNIT_V_WLK (UNIT_V_UF + 0) /* write locked */ +#define UNIT_WLK (1 << UNIT_V_UF) +#define UNIT_V_DSK_VERBOSE (UNIT_V_UF + 1) /* verbose mode, i.e. show error messages */ +#define UNIT_DSK_VERBOSE (1 << UNIT_V_DSK_VERBOSE) +#define DSK_SECTSIZE 137 /* size of sector */ +#define DSK_SECT 32 /* sectors per track */ #define TRACKS 254 /* number of tracks, - original Altair has 77 tracks only */ + original Altair has 77 tracks only */ #define DSK_TRACSIZE (DSK_SECTSIZE * DSK_SECT) #define DSK_SIZE (DSK_TRACSIZE * TRACKS) #define TRACE_IN_OUT 1 #define TRACE_READ_WRITE 2 #define TRACE_SECTOR_STUCK 4 #define TRACE_TRACK_STUCK 8 +#define NUM_OF_DSK 8 /* NUM_OF_DSK must be power of two */ +#define NUM_OF_DSK_MASK (NUM_OF_DSK - 1) -t_stat dsk_svc (UNIT *uptr); -t_stat dsk_reset (DEVICE *dptr); -void writebuf(); +int32 dsk10(int32 port, int32 io, int32 data); +int32 dsk11(int32 port, int32 io, int32 data); +int32 dsk12(int32 port, int32 io, int32 data); +int32 dskseek(UNIT *xptr); +t_stat dsk_boot(int32 unitno); +t_stat dsk_reset(DEVICE *dptr); +t_stat dsk_svc(UNIT *uptr); +void writebuf(void); +t_stat dsk_set_verbose(UNIT *uptr, int32 value, char *cptr, void *desc); +void resetDSKWarningFlags(void); +int32 hasVerbose(void); +char* selectInOut(int32 io); extern int32 PCX; +extern int32 saved_PC; extern FILE *sim_log; +extern void PutBYTEWrapper(register uint32 Addr, register uint32 Value); +extern void printMessage(void); +extern char messageBuffer[]; +extern void install_bootrom(void); /* Global data on status */ -int32 cur_disk = 8; /* Currently selected drive */ -int32 cur_track[9] = {0, 0, 0, 0, 0, 0, 0, 0, 0xff}; -int32 cur_sect[9] = {0, 0, 0, 0, 0, 0, 0, 0, 0xff}; -int32 cur_byte[9] = {0, 0, 0, 0, 0, 0, 0, 0, 0xff}; -int32 cur_flags[9] = {0, 0, 0, 0, 0, 0, 0, 0, 0}; -int32 trace_flag = 0; -int32 in9_count = 0; -int32 in9_message = FALSE; +int32 cur_disk = NUM_OF_DSK; /* Currently selected drive (values are 0 .. NUM_OF_DSK) + cur_disk < NUM_OF_DSK implies that the corresponding disk is attached to a file */ +int32 cur_track [NUM_OF_DSK] = {0, 0, 0, 0, 0, 0, 0, 0}; +int32 cur_sect [NUM_OF_DSK] = {0, 0, 0, 0, 0, 0, 0, 0}; +int32 cur_byte [NUM_OF_DSK] = {0, 0, 0, 0, 0, 0, 0, 0}; +int32 cur_flags [NUM_OF_DSK] = {0, 0, 0, 0, 0, 0, 0, 0}; +int32 trace_flag = 0; +int32 in9_count = 0; +int32 in9_message = FALSE; +int32 dirty = 0; /* 1 when buffer has unwritten data in it */ +int32 warnLevelDSK = 3; +int32 warnLock [NUM_OF_DSK] = {0, 0, 0, 0, 0, 0, 0, 0}; +int32 warnAttached[NUM_OF_DSK] = {0, 0, 0, 0, 0, 0, 0, 0}; +int32 warnDSK10 = 0; +int32 warnDSK11 = 0; +int32 warnDSK12 = 0; +int8 dskbuf[DSK_SECTSIZE]; /* Data Buffer */ -char dskbuf[DSK_SECTSIZE]; /* Data Buffer */ -int32 dirty = 0; /* 1 when buffer has unwritten data in it */ -UNIT *dptr; /* fileref to write dirty buffer to */ +#define LDAInstruction 0x3e /* op-code for LD A,<8-bit value> instruction */ +#define unitNoOffset1 0x37 /* LD A, */ +#define unitNoOffset2 0xb4 /* LD a,80h | */ + +/* Altair MITS modified BOOT EPROM, fits in upper 256 byte of memory */ +int32 bootrom[bootrom_size] = { + 0xf3, 0x06, 0x80, 0x3e, 0x0e, 0xd3, 0xfe, 0x05, /* fe00-fe07 */ + 0xc2, 0x05, 0xff, 0x3e, 0x16, 0xd3, 0xfe, 0x3e, /* fe08-fe0f */ + 0x12, 0xd3, 0xfe, 0xdb, 0xfe, 0xb7, 0xca, 0x20, /* fe10-fe17 */ + 0xff, 0x3e, 0x0c, 0xd3, 0xfe, 0xaf, 0xd3, 0xfe, /* fe18-fe1f */ + 0x21, 0x00, 0x5c, 0x11, 0x33, 0xff, 0x0e, 0x88, /* fe20-fe27 */ + 0x1a, 0x77, 0x13, 0x23, 0x0d, 0xc2, 0x28, 0xff, /* fe28-fe2f */ + 0xc3, 0x00, 0x5c, 0x31, 0x21, 0x5d, 0x3e, 0x00, /* fe30-fe37 */ + 0xd3, 0x08, 0x3e, 0x04, 0xd3, 0x09, 0xc3, 0x19, /* fe38-fe3f */ + 0x5c, 0xdb, 0x08, 0xe6, 0x02, 0xc2, 0x0e, 0x5c, /* fe40-fe47 */ + 0x3e, 0x02, 0xd3, 0x09, 0xdb, 0x08, 0xe6, 0x40, /* fe48-fe4f */ + 0xc2, 0x0e, 0x5c, 0x11, 0x00, 0x00, 0x06, 0x08, /* fe50-fe57 */ + 0xc5, 0xd5, 0x11, 0x86, 0x80, 0x21, 0x88, 0x5c, /* fe58-fe5f */ + 0xdb, 0x09, 0x1f, 0xda, 0x2d, 0x5c, 0xe6, 0x1f, /* fe60-fe67 */ + 0xb8, 0xc2, 0x2d, 0x5c, 0xdb, 0x08, 0xb7, 0xfa, /* fe68-fe6f */ + 0x39, 0x5c, 0xdb, 0x0a, 0x77, 0x23, 0x1d, 0xc2, /* fe70-fe77 */ + 0x39, 0x5c, 0xd1, 0x21, 0x8b, 0x5c, 0x06, 0x80, /* fe78-fe7f */ + 0x7e, 0x12, 0x23, 0x13, 0x05, 0xc2, 0x4d, 0x5c, /* fe80-fe87 */ + 0xc1, 0x21, 0x00, 0x5c, 0x7a, 0xbc, 0xc2, 0x60, /* fe88-fe8f */ + 0x5c, 0x7b, 0xbd, 0xd2, 0x80, 0x5c, 0x04, 0x04, /* fe90-fe97 */ + 0x78, 0xfe, 0x20, 0xda, 0x25, 0x5c, 0x06, 0x01, /* fe98-fe9f */ + 0xca, 0x25, 0x5c, 0xdb, 0x08, 0xe6, 0x02, 0xc2, /* fea0-fea7 */ + 0x70, 0x5c, 0x3e, 0x01, 0xd3, 0x09, 0x06, 0x00, /* fea8-feaf */ + 0xc3, 0x25, 0x5c, 0x3e, 0x80, 0xd3, 0x08, 0xfb, /* feb0-feb7 */ + 0xc3, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* feb8-febf */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* fec0-fec7 */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* fec8-fecf */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* fed0-fed7 */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* fed8-fedf */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* fee0-fee7 */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* fee8-feef */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* fef0-fef7 */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* fef8-feff */ +}; /* 88DSK Standard I/O Data Structures */ UNIT dsk_unit[] = { - { UDATA (&dsk_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+UNIT_ROABLE, DSK_SIZE) }, - { UDATA (&dsk_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+UNIT_ROABLE, DSK_SIZE) }, - { UDATA (&dsk_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+UNIT_ROABLE, DSK_SIZE) }, - { UDATA (&dsk_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+UNIT_ROABLE, DSK_SIZE) }, - { UDATA (&dsk_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+UNIT_ROABLE, DSK_SIZE) }, - { UDATA (&dsk_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+UNIT_ROABLE, DSK_SIZE) }, - { UDATA (&dsk_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+UNIT_ROABLE, DSK_SIZE) }, - { UDATA (&dsk_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+UNIT_ROABLE, DSK_SIZE) } }; + { UDATA (&dsk_svc, UNIT_FIX + UNIT_ATTABLE + UNIT_DISABLE + UNIT_ROABLE, DSK_SIZE) }, + { UDATA (&dsk_svc, UNIT_FIX + UNIT_ATTABLE + UNIT_DISABLE + UNIT_ROABLE, DSK_SIZE) }, + { UDATA (&dsk_svc, UNIT_FIX + UNIT_ATTABLE + UNIT_DISABLE + UNIT_ROABLE, DSK_SIZE) }, + { UDATA (&dsk_svc, UNIT_FIX + UNIT_ATTABLE + UNIT_DISABLE + UNIT_ROABLE, DSK_SIZE) }, + { UDATA (&dsk_svc, UNIT_FIX + UNIT_ATTABLE + UNIT_DISABLE + UNIT_ROABLE, DSK_SIZE) }, + { UDATA (&dsk_svc, UNIT_FIX + UNIT_ATTABLE + UNIT_DISABLE + UNIT_ROABLE, DSK_SIZE) }, + { UDATA (&dsk_svc, UNIT_FIX + UNIT_ATTABLE + UNIT_DISABLE + UNIT_ROABLE, DSK_SIZE) }, + { UDATA (&dsk_svc, UNIT_FIX + UNIT_ATTABLE + UNIT_DISABLE + UNIT_ROABLE, DSK_SIZE) } }; REG dsk_reg[] = { - { DRDATA (DISK, cur_disk, 4) }, - { ORDATA (TRACE, trace_flag, 8) }, - { DRDATA (IN9, in9_count, 4), REG_RO }, + { DRDATA (DISK, cur_disk, 4) }, + { DRDATA (DSKWL, warnLevelDSK, 32) }, + { ORDATA (TRACE, trace_flag, 8) }, + { DRDATA (IN9, in9_count, 4), REG_RO }, { NULL } }; +MTAB dsk_mod[] = { + { UNIT_WLK, 0, "write enabled", "WRITEENABLED", NULL }, + { UNIT_WLK, UNIT_WLK, "write locked", "LOCKED", NULL }, + /* quiet, no warning messages */ + { UNIT_DSK_VERBOSE, 0, "QUIET", "QUIET", NULL }, + /* verbose, show warning messages */ + { UNIT_DSK_VERBOSE, UNIT_DSK_VERBOSE, "VERBOSE", "VERBOSE", &dsk_set_verbose }, + { 0 } }; + DEVICE dsk_dev = { - "DSK", dsk_unit, dsk_reg, NULL, + "DSK", dsk_unit, dsk_reg, dsk_mod, 8, 10, 31, 1, 8, 8, NULL, NULL, &dsk_reset, - NULL, NULL, NULL }; + &dsk_boot, NULL, NULL }; + +void resetDSKWarningFlags(void) { + int32 i; + for (i = 0; i < NUM_OF_DSK; i++) { + warnLock[i] = 0; + warnAttached[i] = 0; + } + warnDSK10 = 0; + warnDSK11 = 0; + warnDSK12 = 0; +} + +t_stat dsk_set_verbose(UNIT *uptr, int32 value, char *cptr, void *desc) { + resetDSKWarningFlags(); + return SCPE_OK; +} + +/* returns TRUE iff there exists a disk with VERBOSE */ +int32 hasVerbose(void) { + int32 i; + for (i = 0; i < NUM_OF_DSK; i++) { + if (((dsk_dev.units + i) -> flags) & UNIT_DSK_VERBOSE) { + return TRUE; + } + } + return FALSE; +} + +char* selectInOut(int32 io) { + return io == 0 ? "IN" : "OUT"; +} /* Service routines to handle simlulator functions */ /* service routine - actually gets char & places in buffer */ -t_stat dsk_svc (UNIT *uptr) -{ +t_stat dsk_svc(UNIT *uptr) { return SCPE_OK; } /* Reset routine */ -t_stat dsk_reset (DEVICE *dptr) -{ - cur_disk = 0; +t_stat dsk_reset(DEVICE *dptr) { + resetDSKWarningFlags(); + cur_disk = NUM_OF_DSK; trace_flag = 0; in9_count = 0; in9_message = FALSE; return SCPE_OK; } +/* The boot routine modifies the boot ROM in such a way that subsequently + the specified disk is used for boot purposes. The program counter will reach + the boot ROM by executing NOP instructions starting from address 0 until + it reaches 0xff00. +*/ +t_stat dsk_boot(int32 unitno) { + install_bootrom(); + /* check whether we are really modifying an LD A,<> instruction */ + if ((bootrom[unitNoOffset1 - 1] == LDAInstruction) && (bootrom[unitNoOffset2 - 1] == LDAInstruction)) { + bootrom[unitNoOffset1] = unitno & 0xff; /* LD A, */ + bootrom[unitNoOffset2] = 0x80 | (unitno & 0xff); /* LD a,80h | */ + return SCPE_OK; + } + else { /* Attempt to modify non LD A,<> instructions is refused. */ + printf("Incorrect boot ROM offsets detected.\n"); + return SCPE_IERR; + } +} + /* I/O instruction handlers, called from the CPU module when an IN or OUT instruction is issued. @@ -186,166 +308,176 @@ t_stat dsk_reset (DEVICE *dptr) simulation requirement that they are reversed in hardware. */ -int32 dsk10(int32 io, int32 data) -{ +int32 dsk10(int32 port, int32 io, int32 data) { + int32 cur_flag; in9_count = 0; - if (io == 0) { /* IN: return flags */ - return ((~cur_flags[cur_disk]) & 0xFF); /* Return the COMPLEMENT! */ + if (io == 0) { /* IN: return flags */ + if (cur_disk >= NUM_OF_DSK) { + if (hasVerbose() && (warnDSK10 < warnLevelDSK)) { + warnDSK10++; +/*01*/ message1("Attempt of IN 0x08 on unattached disk - ignored.\n"); + } + return 0xff; /* no drive selected - can do nothing */ + } + return (~cur_flags[cur_disk]) & 0xff; /* Return the COMPLEMENT! */ } /* OUT: Controller set/reset/enable/disable */ - if (dirty == 1) + if (dirty == 1) {/* implies that cur_disk < NUM_OF_DSK */ writebuf(); - if (trace_flag & TRACE_IN_OUT) { - printf("\n[%x] OUT 08: %x", PCX, data); - if (sim_log) { - fprintf(sim_log, "\n[%x] OUT 08: %x", PCX, data); - } } - cur_disk = data & 0x0F; - if ((((dsk_dev.units + cur_disk) -> flags) & UNIT_ATT) == 0) { /* nothing attached? */ - cur_disk = 8; + if (trace_flag & TRACE_IN_OUT) { + message2("OUT 0x08: %x\n", data); + } + cur_disk = data & NUM_OF_DSK_MASK; /* 0 <= cur_disk < NUM_OF_DSK */ + cur_flag = (dsk_dev.units + cur_disk) -> flags; + if ((cur_flag & UNIT_ATT) == 0) { /* nothing attached? */ + if ( (cur_flag & UNIT_DSK_VERBOSE) && (warnAttached[cur_disk] < warnLevelDSK) ) { + warnAttached[cur_disk]++; +/*02*/message2("Attempt to select unattached DSK%d - ignored.\n", cur_disk); + } + cur_disk = NUM_OF_DSK; } else { cur_sect[cur_disk] = 0xff; /* reset internal counters */ cur_byte[cur_disk] = 0xff; - cur_flags[cur_disk] = data & 0x80 ? 0 /* Disable drive */ : - (cur_track[cur_disk] == 0 ? 0x5A /* Enable: head move true, track 0 if there */ : - 0x1A); /* Enable: head move true */ + cur_flags[cur_disk] = data & 0x80 ? 0 /* Disable drive */ : + (cur_track[cur_disk] == 0 ? 0x5a /* Enable: head move true, track 0 if there */ : + 0x1a); /* Enable: head move true */ } - return (0); /* ignored since OUT */ + return 0; /* ignored since OUT */ } /* Disk Drive Status/Functions */ -int32 dsk11(int32 io, int32 data) -{ - if (io == 0) { /* Read sector position */ +int32 dsk11(int32 port, int32 io, int32 data) { + if (cur_disk >= NUM_OF_DSK) { + if (hasVerbose() && (warnDSK11 < warnLevelDSK)) { + warnDSK11++; +/*03*/message2("Attempt of %s 0x09 on unattached disk - ignored.\n", selectInOut(io)); + } + return 0; /* no drive selected - can do nothing */ + } + + /* now cur_disk < NUM_OF_DSK */ + if (io == 0) { /* Read sector position */ in9_count++; - if ((trace_flag & TRACE_SECTOR_STUCK) && (in9_count > 2*DSK_SECT) && (!in9_message)) { + if ((trace_flag & TRACE_SECTOR_STUCK) && (in9_count > 2 * DSK_SECT) && (!in9_message)) { in9_message = TRUE; - printf("\n[%x] Looping on sector find %d.\n", PCX, cur_disk); - if (sim_log) { - fprintf(sim_log, "\n[%x] Looping on sector find %d.\n", PCX, cur_disk); - } + message2("Looping on sector find %d.\n", cur_disk); } if (trace_flag & TRACE_IN_OUT) { - printf("\n[%x] IN 09", PCX); - if (sim_log) { - fprintf(sim_log, "\n[%x] IN 09", PCX); - } + message1("IN 0x09\n"); } - if (dirty == 1) + if (dirty == 1) {/* implies that cur_disk < NUM_OF_DSK */ writebuf(); + } if (cur_flags[cur_disk] & 0x04) { /* head loaded? */ cur_sect[cur_disk]++; - if (cur_sect[cur_disk] >= DSK_SECT) + if (cur_sect[cur_disk] >= DSK_SECT) { cur_sect[cur_disk] = 0; + } cur_byte[cur_disk] = 0xff; - return (((cur_sect[cur_disk] << 1) & 0x3E) /* return 'sector true' bit = 0 (true) */ - | 0xC0); /* set on 'unused' bits */ + return (((cur_sect[cur_disk] << 1) & 0x3e) /* return 'sector true' bit = 0 (true) */ + | 0xc0); /* set on 'unused' bits */ } else { - return (0); /* head not loaded - return 0 */ + return 0; /* head not loaded - return 0 */ } } in9_count = 0; /* Drive functions */ - if (cur_disk > 7) - return (0); /* no drive selected - can do nothing */ - if (trace_flag & TRACE_IN_OUT) { - printf("\n[%x] OUT 09: %x", PCX, data); - if (sim_log) { - fprintf(sim_log, "\n[%x] OUT 09: %x", PCX, data); - } + message2("OUT 0x09: %x\n", data); } - if (data & 0x01) { /* Step head in */ + if (data & 0x01) { /* Step head in */ if (trace_flag & TRACE_TRACK_STUCK) { - if (cur_track[cur_disk] == (TRACKS-1)) { - printf("\n[%x] Unnecessary step in for disk %d", PCX, cur_disk); - if (sim_log) { - fprintf(sim_log, "\n[%x] Unnecessary step in for disk %d", PCX, cur_disk); - } + if (cur_track[cur_disk] == (TRACKS - 1)) { + message2("Unnecessary step in for disk %d\n", cur_disk); } } cur_track[cur_disk]++; - if (cur_track[cur_disk] > (TRACKS-1) ) - cur_track[cur_disk] = (TRACKS-1); - if (dirty == 1) + if (cur_track[cur_disk] > (TRACKS - 1)) { + cur_track[cur_disk] = (TRACKS - 1); + } + if (dirty == 1) { /* implies that cur_disk < NUM_OF_DSK */ writebuf(); + } cur_sect[cur_disk] = 0xff; cur_byte[cur_disk] = 0xff; } - if (data & 0x02) { /* Step head out */ + if (data & 0x02) { /* Step head out */ if (trace_flag & TRACE_TRACK_STUCK) { if (cur_track[cur_disk] == 0) { - printf("\n[%x] Unnecessary step out for disk %d", PCX, cur_disk); - if (sim_log) { - fprintf(sim_log, "\n[%x] Unnecessary step out for disk %d", PCX, cur_disk); - } + message2("Unnecessary step out for disk %d\n", cur_disk); } } cur_track[cur_disk]--; if (cur_track[cur_disk] < 0) { cur_track[cur_disk] = 0; - cur_flags[cur_disk] |= 0x40; /* track 0 if there */ + cur_flags[cur_disk] |= 0x40; /* track 0 if there */ } - if (dirty == 1) + if (dirty == 1) { /* implies that cur_disk < NUM_OF_DSK */ writebuf(); + } cur_sect[cur_disk] = 0xff; cur_byte[cur_disk] = 0xff; } - if (dirty == 1) + if (dirty == 1) { /* implies that cur_disk < NUM_OF_DSK */ writebuf(); - - if (data & 0x04) { /* Head load */ - cur_flags[cur_disk] |= 0x04; /* turn on head loaded bit */ - cur_flags[cur_disk] |= 0x80; /* turn on 'read data available */ } - if (data & 0x08) { /* Head Unload */ - cur_flags[cur_disk] &= 0xFB; /* off on 'head loaded' */ - cur_flags[cur_disk] &= 0x7F; /* off on 'read data avail */ + if (data & 0x04) { /* Head load */ + cur_flags[cur_disk] |= 0x04; /* turn on head loaded bit */ + cur_flags[cur_disk] |= 0x80; /* turn on 'read data available' */ + } + + if (data & 0x08) { /* Head Unload */ + cur_flags[cur_disk] &= 0xfb; /* turn off 'head loaded' bit */ + cur_flags[cur_disk] &= 0x7f; /* turn off 'read data available' */ cur_sect[cur_disk] = 0xff; cur_byte[cur_disk] = 0xff; } - /* Interrupts & head current are ignored */ + /* Interrupts & head current are ignored */ - if (data & 0x80) { /* write sequence start */ + if (data & 0x80) { /* write sequence start */ cur_byte[cur_disk] = 0; - cur_flags[cur_disk] |= 0x01; /* enter new write data on */ + cur_flags[cur_disk] |= 0x01; /* enter new write data on */ } - return (0); /* ignored since OUT */ + return 0; /* ignored since OUT */ } -/* Disk Data In/Out*/ +/* Disk Data In/Out */ -inline int32 dskseek(UNIT *xptr) { +INLINE int32 dskseek(UNIT *xptr) { return fseek(xptr -> fileref, DSK_TRACSIZE * cur_track[cur_disk] + DSK_SECTSIZE * cur_sect[cur_disk], SEEK_SET); } -int32 dsk12(int32 io, int32 data) -{ +int32 dsk12(int32 port, int32 io, int32 data) { static int32 i; UNIT *uptr; + if (cur_disk >= NUM_OF_DSK) { + if (hasVerbose() && (warnDSK12 < warnLevelDSK)) { + warnDSK12++; +/*04*/message2("Attempt of %s 0x0a on unattached disk - ignored.\n", selectInOut(io)); + } + return 0; + } + + /* now cur_disk < NUM_OF_DSK */ in9_count = 0; uptr = dsk_dev.units + cur_disk; if (io == 0) { if (cur_byte[cur_disk] >= DSK_SECTSIZE) { /* physically read the sector */ if (trace_flag & TRACE_READ_WRITE) { - printf("\n[%x] IN 0A (READ) D%d T%d S%d", PCX, cur_disk, cur_track[cur_disk], cur_sect[cur_disk]); - if (sim_log) { - fprintf(sim_log, "\n[%x] IN 0A (READ) D%d T%d S%d", PCX, cur_disk, cur_track[cur_disk], - cur_sect[cur_disk]); - } + message4("IN 0x0a (READ) D%d T%d S%d\n", cur_disk, cur_track[cur_disk], cur_sect[cur_disk]); } for (i = 0; i < DSK_SECTSIZE; i++) { dskbuf[i] = 0; @@ -354,55 +486,48 @@ int32 dsk12(int32 io, int32 data) fread(dskbuf, DSK_SECTSIZE, 1, uptr -> fileref); cur_byte[cur_disk] = 0; } - return (dskbuf[cur_byte[cur_disk]++] & 0xFF); + return dskbuf[cur_byte[cur_disk]++] & 0xff; } else { if (cur_byte[cur_disk] >= DSK_SECTSIZE) { - writebuf(); + writebuf(); /* from above we have that cur_disk < NUM_OF_DSK */ } else { - dirty = 1; - dptr = uptr; - dskbuf[cur_byte[cur_disk]++] = data & 0xFF; + dirty = 1; /* this guarantees for the next call to writebuf that cur_disk < NUM_OF_DSK */ + dskbuf[cur_byte[cur_disk]++] = data & 0xff; } - return (0); /* ignored since OUT */ + return 0; /* ignored since OUT */ } } -void writebuf() -{ +/* Precondition: cur_disk < NUM_OF_DSK */ +void writebuf(void) { int32 i, rtn; - + UNIT *uptr; i = cur_byte[cur_disk]; /* null-fill rest of sector if any */ while (i < DSK_SECTSIZE) { dskbuf[i++] = 0; } - if (trace_flag & TRACE_READ_WRITE) { - printf("\n[%x] OUT 0A (WRITE) D%d T%d S%d", PCX, cur_disk, - cur_track[cur_disk], cur_sect[cur_disk]); - if (sim_log) { - fprintf (sim_log, "\n[%x] OUT 0A (WRITE) D%d T%d S%d", PCX, cur_disk, - cur_track[cur_disk], cur_sect[cur_disk]); + uptr = dsk_dev.units + cur_disk; + if (((uptr -> flags) & UNIT_WLK) == 0) { /* write enabled */ + if (trace_flag & TRACE_READ_WRITE) { + message4("OUT 0x0a (WRITE) D%d T%d S%d\n", cur_disk, cur_track[cur_disk], cur_sect[cur_disk]); + } + if (dskseek(uptr)) { + message4("fseek failed D%d T%d S%d\n", cur_disk, cur_track[cur_disk], cur_sect[cur_disk]); + } + rtn = fwrite(dskbuf, DSK_SECTSIZE, 1, uptr -> fileref); + if (rtn != 1) { + message4("fwrite failed T%d S%d Return=%d\n", cur_track[cur_disk], cur_sect[cur_disk], rtn); } } - if (dskseek(dptr)) { - printf("\n[%x] fseek failed D%d T%d S%d", PCX, cur_disk, - cur_track[cur_disk], cur_sect[cur_disk]); - if (sim_log) { - fprintf(sim_log, "\n[%x] fseek failed D%d T%d S%d", PCX, cur_disk, - cur_track[cur_disk], cur_sect[cur_disk]); - } + else if ( ((uptr -> flags) & UNIT_DSK_VERBOSE) && (warnLock[cur_disk] < warnLevelDSK) ) { + /* write locked - print warning message if required */ + warnLock[cur_disk]++; +/*05*/ + message2("Attempt to write to locked DSK%d - ignored.\n", cur_disk); } - rtn = fwrite(dskbuf, DSK_SECTSIZE, 1, dptr -> fileref); - if (rtn != 1) { - printf("\n[%x] fwrite failed T%d S%d Return=%d", PCX, cur_track[cur_disk], - cur_sect[cur_disk], rtn); - if (sim_log) { - fprintf(sim_log, "\n[%x] fwrite failed T%d S%d Return=%d", PCX, cur_track[cur_disk], - cur_sect[cur_disk], rtn); - } - } - cur_flags[cur_disk] &= 0xFE; /* ENWD off */ - cur_byte[cur_disk] = 0xff; - dirty = 0; + cur_flags[cur_disk] &= 0xfe; /* ENWD off */ + cur_byte[cur_disk] = 0xff; + dirty = 0; } diff --git a/AltairZ80/altairZ80_sio.c b/AltairZ80/altairZ80_sio.c index 0b4f7937..698149c3 100644 --- a/AltairZ80/altairZ80_sio.c +++ b/AltairZ80/altairZ80_sio.c @@ -1,5 +1,5 @@ /* altairZ80_sio: MITS Altair serial I/O card - Written by Peter Schorn, 2001 + Written by Peter Schorn, 2001-2002 Based on work by Charles E Owen ((c) 1997, Commercial use prohibited) These functions support a simulated MITS 2SIO interface card. @@ -7,21 +7,21 @@ to any serial I/O device that would connect to a current loop, RS232, or TTY interface. Available baud rates were jumper selectable for each port from 110 to 9600. - - All I/O is via programmed I/O. Each each has a status port + + All I/O is via programmed I/O. Each device has a status port and a data port. A write to the status port can select some options for the device (0x03 will reset the port). A read of the status port gets the port status: - + +---+---+---+---+---+---+---+---+ - | X X X X X X O I | + | X | X | X | X | X | X | O | I | +---+---+---+---+---+---+---+---+ - + I - A 1 in this bit position means a character has been received on the data port and is ready to be read. O - A 1 in this bit means the port is ready to receive a character on the data port and transmit it out over the serial line. - + A read to the data port gets the buffered character, a write to the data port writes the character to the device. */ @@ -32,53 +32,156 @@ #include "altairZ80_defs.h" #include "sim_sock.h" #include "sim_tmxr.h" +#include -#define UNIT_V_ANSI (UNIT_V_UF + 0) /* ANSI mode, strip bit 8 on output */ -#define UNIT_ANSI (1 << UNIT_V_ANSI) -#define UNIT_V_UPPER (UNIT_V_UF + 1) /* uppper case mode */ -#define UNIT_UPPER (1 << UNIT_V_UPPER) -#define UNIT_V_BS (UNIT_V_UF + 2) /* map delete to backspace */ -#define UNIT_BS (1 << UNIT_V_BS) -#define Terminals 1 /* lines per mux */ +#define UNIT_V_ANSI (UNIT_V_UF + 0) /* ANSI mode, strip bit 8 on output */ +#define UNIT_ANSI (1 << UNIT_V_ANSI) +#define UNIT_V_UPPER (UNIT_V_UF + 1) /* uppper case mode */ +#define UNIT_UPPER (1 << UNIT_V_UPPER) +#define UNIT_V_BS (UNIT_V_UF + 2) /* map delete to backspace */ +#define UNIT_BS (1 << UNIT_V_BS) +#define UNIT_V_SIO_VERBOSE (UNIT_V_UF + 3) /* verbose mode, i.e. show error messages */ +#define UNIT_SIO_VERBOSE (1 << UNIT_V_SIO_VERBOSE) -TMLN TerminalLines[Terminals] = { { 0 } }; /* we only need one line */ -TMXR altairTMXR = {Terminals, 0, &TerminalLines[0] }; /* mux descriptor */ +#define UNIT_V_SIMH_VERBOSE (UNIT_V_UF + 0) /* verbose mode for SIMH pseudo device */ +#define UNIT_SIMH_VERBOSE (1 << UNIT_V_SIMH_VERBOSE) +#define UNIT_V_SIMH_TIMERON (UNIT_V_UF + 1) /* SIMH pseudo device timer generate interrupts */ +#define UNIT_SIMH_TIMERON (1 << UNIT_V_SIMH_VERBOSE) -t_stat sio_svc (UNIT *uptr); -t_stat sio_reset (DEVICE *dptr); -t_stat sio_attach (UNIT *uptr, char *cptr); -t_stat sio_detach (UNIT *uptr); -t_stat ptr_svc (UNIT *uptr); -t_stat ptr_reset (DEVICE *dptr); -t_stat ptp_svc (UNIT *uptr); -t_stat ptp_reset (DEVICE *dptr); -int32 nulldev(int32 io, int32 data); -int32 simh_dev(int32 io, int32 data); -int32 sio0d(int32 io, int32 data); -int32 sio0s(int32 io, int32 data); -int32 sio1d(int32 io, int32 data); -int32 sio1s(int32 io, int32 data); -void attachCPM(); +#define Terminals 4 /* lines per mux */ -extern t_stat sim_activate (UNIT *uptr, int32 interval); -extern t_stat sim_cancel (UNIT *uptr); -extern t_stat sim_poll_kbd (void); -extern t_stat sim_putchar (int32 out); -extern t_stat attach_unit (UNIT *uptr, char *cptr); +#define BACKSPACE_CHAR 0x08 /* backspace character */ +#define DELETE_CHAR 0x7f /* delete character */ +#define CONTROLZ_CHAR 0x1a /* control Z character */ + +void resetSIOWarningFlags(void); +t_stat sio_set_verbose(UNIT *uptr, int32 value, char *cptr, void *desc); +t_stat sio_svc(UNIT *uptr); +t_stat sio_reset(DEVICE *dptr); +t_stat sio_attach(UNIT *uptr, char *cptr); +t_stat sio_detach(UNIT *uptr); +t_stat ptr_reset(DEVICE *dptr); +t_stat ptp_reset(DEVICE *dptr); +int32 nulldev (int32 port, int32 io, int32 data); +int32 sr_dev (int32 port, int32 io, int32 data); +int32 simh_dev(int32 port, int32 io, int32 data); +int32 sio0d (int32 port, int32 io, int32 data); +int32 sio0s (int32 port, int32 io, int32 data); +int32 sio1d (int32 port, int32 io, int32 data); +int32 sio1s (int32 port, int32 io, int32 data); +void reset_sio_terminals(int32 useDefault); +t_stat simh_dev_reset(void); +t_stat simh_svc(UNIT *uptr); +t_stat simh_dev_set_timeron(void); +t_stat simh_dev_set_timeroff(void); +int32 simh_in(void); +int32 simh_out(int32 data); +void attachCPM(UNIT *uptr); +void setClockZSDOS(void); +void setClockCPM3(void); +time_t mkCPM3Origin(void); +int32 toBCD(int32 x); +int32 fromBCD(int32 x); +void printMessage(void); + +extern t_stat sim_activate(UNIT *uptr, int32 interval); +extern t_stat sim_cancel(UNIT *uptr); +extern t_stat sim_poll_kbd(void); +extern t_stat sim_putchar(int32 out); +extern t_stat attach_unit(UNIT *uptr, char *cptr); extern t_bool rtc_avail; extern FILE *sim_log; +extern int32 PCX; extern int32 sim_switches; -extern uint32 sim_os_msec (void); -extern uint8 M[MAXMEMSIZE]; +extern uint32 sim_os_msec(void); +extern const char *scp_error_messages[]; +extern int32 SR; +extern int32 bankSelect; +extern int32 common; +extern uint8 GetBYTEWrapper(register uint32 Addr); +extern UNIT cpu_unit; + +/* the following variables define state for the SIMH pseudo device */ +/* ZSDOS clock definitions */ +int32 ClockZSDOSDelta = 0; /* delta between real clock and Altair clock */ +int32 setClockZSDOSPos = 0; /* determines state for receiving address of parameter block */ +int32 setClockZSDOSAdr = 0; /* address in M of 6 byte parameter block for setting time */ +int32 getClockZSDOSPos = 0; /* determines state for sending clock information */ + +/* CPM3 clock definitions */ +int32 ClockCPM3Delta = 0; /* delta between real clock and Altair clock */ +int32 setClockCPM3Pos = 0; /* determines state for receiving address of parameter block */ +int32 setClockCPM3Adr = 0; /* address in M of 5 byte parameter block for setting time */ +int32 getClockCPM3Pos = 0; /* determines state for sending clock information */ +int32 daysCPM3SinceOrg = 0; /* days since 1 Jan 1978 */ + +int32 timerDelta = 100; /* interrupt every 100 ms */ +int32 tmpTimerDelta; +uint32 timeOfNextInterrupt; +int32 timerInterrupt = FALSE; /* timer interrupt pending */ +int32 timerInterruptHandler = 0x0fc00;/* default address of interrupt handling routine */ +int32 tmpTimerInterruptHandler; +int32 setTimerDeltaPos = 0; /* determines state for receiving timerDelta */ +int32 setTimerInterruptAdrPos = 0; /* determines state for receiving timerInterruptHandler */ +int32 markTimeSP = 0; /* stack pointer for timer stack */ +int32 versionPos = 0; /* determines state for sending device identifier */ +int32 lastCPMStatus = 0; /* result of last attachCPM command */ +int32 lastCommand = 0; /* most recent command processed on port 0xfeh */ +int32 getCommonPos = 0; /* determines state for sending the 'common' register */ +int32 warnLevelSIO = 3; /* display at most 'warnLevelSIO' times the same warning */ +int32 warnUnattachedPTP = 0; /* display a warning message if < warnLevel and SIO set to + VERBOSE and output to PTP without an attached file */ +int32 warnUnattachedPTR = 0; /* display a warning message if < warnLevel and SIO set to + VERBOSE and attempt to read from PTR without an attached file */ +int32 warnPTREOF = 0; /* display a warning message if < warnLevel and SIO set to + VERBOSE and attempt to read from PTR past EOF */ +int32 warnUnassignedPort = 0; /* display a warning message if < warnLevel and SIO set to + VERBOSE andattempt to perform IN or OUT on an unassigned PORT */ +char messageBuffer[256]; + +void printMessage(void) { + printf(messageBuffer); + if (sim_log) { + fprintf(sim_log, messageBuffer); + } +} + + /* 2SIO Standard I/O Data Structures */ +struct sio_terminal { + int32 data; /* data for this terminal */ + int32 status; /* status information for this terminal */ + int32 statusPort; /* status port of this terminal */ + int32 dataPort; /* data port of this terminal */ + int32 defaultStatus; /* default status value for this terminal */ +}; -UNIT sio_unit = { UDATA (&sio_svc, UNIT_ATTABLE, 0), - KBD_POLL_WAIT }; +typedef struct sio_terminal SIO_TERMINAL; + +SIO_TERMINAL sio_terminals[Terminals] = { {0, 0, 0x10, 0x11, 0x02}, + {0, 0, 0x14, 0x15, 0x00}, + {0, 0, 0x16, 0x17, 0x00}, + {0, 0, 0x18, 0x19, 0x00} }; +TMLN TerminalLines[Terminals] = { {0} }; /* four terminals */ +TMXR altairTMXR = {Terminals, 0, NULL }; /* mux descriptor */ + +UNIT sio_unit = { UDATA (&sio_svc, UNIT_ATTABLE, 0), KBD_POLL_WAIT }; REG sio_reg[] = { - { HRDATA (DATA, sio_unit.buf, 8) }, - { HRDATA (STAT, sio_unit.u3, 8) }, + { HRDATA (DATA0, sio_terminals[0].data, 8) }, + { HRDATA (STAT0, sio_terminals[0].status, 8) }, + { HRDATA (DATA1, sio_terminals[1].data, 8) }, + { HRDATA (STAT1, sio_terminals[1].status, 8) }, + { HRDATA (DATA2, sio_terminals[2].data, 8) }, + { HRDATA (STAT2, sio_terminals[2].status, 8) }, + { HRDATA (DATA3, sio_terminals[3].data, 8) }, + { HRDATA (STAT3, sio_terminals[3].status, 8) }, + { DRDATA (SIOWL, warnLevelSIO, 32) }, + { DRDATA (WUPTP, warnUnattachedPTP, 32) }, + { DRDATA (WUPTR, warnUnattachedPTR, 32) }, + { DRDATA (WPTREOF, warnPTREOF, 32) }, + { DRDATA (WUPORT, warnUnassignedPort, 32) }, { NULL } }; MTAB sio_mod[] = { @@ -88,6 +191,9 @@ MTAB sio_mod[] = { { UNIT_UPPER, UNIT_UPPER, "UPPER", "UPPER", NULL }, /* change input characters to upper case */ { UNIT_BS, 0, "BS", "BS", NULL }, /* map delete to backspace */ { UNIT_BS, UNIT_BS, "DEL", "DEL", NULL }, /* map backspace to delete */ + { UNIT_SIO_VERBOSE, 0, "QUIET", "QUIET", NULL }, /* quiet, no error messages */ + { UNIT_SIO_VERBOSE, UNIT_SIO_VERBOSE, "VERBOSE", "VERBOSE", &sio_set_verbose }, + /* verbose, display warning messages */ { 0 } }; DEVICE sio_dev = { @@ -96,7 +202,7 @@ DEVICE sio_dev = { NULL, NULL, &sio_reset, NULL, &sio_attach, &sio_detach }; -UNIT ptr_unit = { UDATA (&ptr_svc, UNIT_SEQ + UNIT_ATTABLE + UNIT_ROABLE, 0), +UNIT ptr_unit = { UDATA (NULL, UNIT_SEQ + UNIT_ATTABLE + UNIT_ROABLE, 0), KBD_POLL_WAIT }; REG ptr_reg[] = { @@ -111,7 +217,7 @@ DEVICE ptr_dev = { NULL, NULL, &ptr_reset, NULL, NULL, NULL }; -UNIT ptp_unit = { UDATA (&ptp_svc, UNIT_SEQ + UNIT_ATTABLE, 0), +UNIT ptp_unit = { UDATA (NULL, UNIT_SEQ + UNIT_ATTABLE, 0), KBD_POLL_WAIT }; REG ptp_reg[] = { @@ -126,102 +232,153 @@ DEVICE ptp_dev = { NULL, NULL, &ptp_reset, NULL, NULL, NULL }; -t_stat sio_attach (UNIT *uptr, char *cptr) -{ -return tmxr_attach (&altairTMXR, uptr, cptr); /* attach mux */ +/* Synthetic device SIMH for communication + between Altair and SIMH environment using port 0xfe */ +UNIT simh_unit = { UDATA (&simh_svc, 0, 0), KBD_POLL_WAIT }; + +REG simh_reg[] = { + { DRDATA (CZD, ClockZSDOSDelta, 31) }, + { DRDATA (SCZP, setClockZSDOSPos, 8), REG_RO }, + { DRDATA (GCZP, getClockZSDOSPos, 8), REG_RO }, + { HRDATA (SCZA, setClockZSDOSAdr, 17), REG_RO }, + { DRDATA (CC3D, ClockCPM3Delta, 31) }, + { DRDATA (TIMD, timerDelta, 31) }, + { DRDATA (TIMI, timerInterrupt, 3) }, + { HRDATA (TIMH, timerInterruptHandler, 17) }, + { DRDATA (SCC3P, setClockCPM3Pos, 8), REG_RO }, + { DRDATA (GCC3P, getClockCPM3Pos, 8), REG_RO }, + { HRDATA (SCC3A, setClockCPM3Adr, 17), REG_RO }, + { DRDATA (MTSP, markTimeSP, 8), REG_RO }, + { DRDATA (VP, versionPos, 8), REG_RO }, + { DRDATA (CP, getCommonPos, 8), REG_RO }, + { DRDATA (LC, lastCommand, 8), REG_RO }, + { NULL } }; + +MTAB simh_mod[] = { + /* quiet, no warning messages */ + { UNIT_SIMH_VERBOSE, 0, "QUIET", "QUIET", NULL }, + /* verbose, display warning messages */ + { UNIT_SIMH_VERBOSE, UNIT_SIMH_VERBOSE, "VERBOSE", "VERBOSE", NULL }, + /* quiet, no warning messages */ + { UNIT_SIMH_TIMERON, 0, "TIMEROFF", "TIMEROFF", &simh_dev_set_timeroff }, + /* verbose, display warning messages */ + { UNIT_SIMH_TIMERON, UNIT_SIMH_TIMERON, "TIMERON", "TIMERON", &simh_dev_set_timeron }, + { 0 } }; + +DEVICE simh_device = { + "SIMH", &simh_unit, simh_reg, simh_mod, + 1, 10, 31, 1, 16, 4, + NULL, NULL, &simh_dev_reset, + NULL, NULL, NULL }; + + +void resetSIOWarningFlags(void) { + warnUnattachedPTP = 0; + warnUnattachedPTR = 0; + warnPTREOF = 0; + warnUnassignedPort = 0; +} + +t_stat sio_set_verbose(UNIT *uptr, int32 value, char *cptr, void *desc) { + resetSIOWarningFlags(); + return SCPE_OK; +} + +t_stat sio_attach(UNIT *uptr, char *cptr) { + int32 i; + for (i = 0; i < Terminals; i++) { + altairTMXR.ldsc[i] = &TerminalLines[i]; + } + reset_sio_terminals(FALSE); + return tmxr_attach(&altairTMXR, uptr, cptr); /* attach mux */ +} + +void reset_sio_terminals(int32 useDefault) { + int32 i; + for (i = 0; i < Terminals; i++) { + sio_terminals[i].status = useDefault ? sio_terminals[i].defaultStatus : 0; /* Status */ + sio_terminals[i].data = 0x00; /* Data */ + } } /* Detach */ - -t_stat sio_detach (UNIT *uptr) -{ -sio_unit.u3 = 0x02; /* Status */ -sio_unit.buf = 0; /* Data */ -return tmxr_detach (&altairTMXR, uptr); +t_stat sio_detach(UNIT *uptr) { + reset_sio_terminals(TRUE); + return tmxr_detach(&altairTMXR, uptr); } /* Service routines to handle simulator functions */ /* service routine - actually gets char & places in buffer */ -t_stat sio_svc (UNIT *uptr) -{ +t_stat sio_svc(UNIT *uptr) { int32 temp; - sim_activate (&sio_unit, sio_unit.wait); /* continue poll */ - + sim_activate(&sio_unit, sio_unit.wait); /* continue poll */ + if (sio_unit.flags & UNIT_ATT) { - if (sim_poll_kbd () == SCPE_STOP) { /* listen for ^E */ + if (sim_poll_kbd() == SCPE_STOP) { /* listen for ^E */ return SCPE_STOP; } temp = tmxr_poll_conn(&altairTMXR, &sio_unit); /* poll connection */ if (temp >= 0) { - altairTMXR.ldsc[temp] -> rcve = 1; /* enable receive */ + altairTMXR.ldsc[temp] -> rcve = 1; /* enable receive */ } - tmxr_poll_rx(&altairTMXR); /* poll input */ - tmxr_poll_tx(&altairTMXR); /* poll output */ + tmxr_poll_rx(&altairTMXR); /* poll input */ + tmxr_poll_tx(&altairTMXR); /* poll output */ } else { - if ((temp = sim_poll_kbd ()) < SCPE_KFLAG) { - return temp; /* no char or error? */ + if ((temp = sim_poll_kbd()) < SCPE_KFLAG) { + return temp; /* no char or error? */ } - sio_unit.buf = temp & 0xff; /* Save char */ - sio_unit.u3 |= 0x01; /* Set status */ + sio_terminals[0].data = temp & 0xff; /* Save char */ + sio_terminals[0].status |= 0x01; /* Set status */ } return SCPE_OK; } -t_stat ptr_svc (UNIT *uptr) -{ - return SCPE_OK; -} +/* Reset routines */ -t_stat ptp_svc (UNIT *uptr) -{ - return SCPE_OK; -} - - -/* Reset routine */ - -t_stat sio_reset (DEVICE *dptr) -{ +t_stat sio_reset(DEVICE *dptr) { + int32 i; + resetSIOWarningFlags(); if (sio_unit.flags & UNIT_ATT) { - if (altairTMXR.ldsc[0]->conn > 0) { - tmxr_reset_ln(altairTMXR.ldsc[0]); + for (i = 0; i < Terminals; i++) { + if (altairTMXR.ldsc[i] -> conn > 0) { + tmxr_reset_ln(altairTMXR.ldsc[i]); + } } - sio_unit.u3 = 0; /* Status */ + reset_sio_terminals(FALSE); } else { - sio_unit.u3 = 0x02; /* Status */ + reset_sio_terminals(TRUE); } - sio_unit.buf = 0; /* Data */ - sim_activate (&sio_unit, sio_unit.wait); /* activate unit */ + sim_activate(&sio_unit, sio_unit.wait); /* activate unit */ return SCPE_OK; } - -t_stat ptr_reset (DEVICE *dptr) -{ - ptr_unit.buf = 0; - ptr_unit.u3 = 0; - ptr_unit.pos = 0; +t_stat ptr_reset(DEVICE *dptr) { + resetSIOWarningFlags(); + ptr_unit.buf = 0; + ptr_unit.u3 = 0; + ptr_unit.pos = 0; if (ptr_unit.flags & UNIT_ATT) { /* attached? */ rewind(ptr_dev.units -> fileref); } - sim_cancel (&ptp_unit); /* deactivate unit */ + sim_cancel(&ptp_unit); /* deactivate unit */ return SCPE_OK; } -t_stat ptp_reset (DEVICE *dptr) -{ +t_stat ptp_reset(DEVICE *dptr) { + resetSIOWarningFlags(); ptp_unit.buf = 0; ptp_unit.u3 = 0x02; - sim_cancel (&ptp_unit); /* deactivate unit */ + sim_cancel(&ptp_unit); /* deactivate unit */ return SCPE_OK; } + /* I/O instruction handlers, called from the CPU module when an IN or OUT instruction is issued. @@ -229,206 +386,619 @@ t_stat ptp_reset (DEVICE *dptr) the port, and 1 means a write to the port. On input, the actual input is passed as the return value, on output, 'data' is written to the device. + + Port 1 controls console I/O. We distinguish two cases: + 1) SIO attached to a port (i.e. Telnet console I/O) + 2) SIO not attached to a port (i.e. "regular" console I/O) */ -int32 sio0s(int32 io, int32 data) -{ +int32 sio0s(int32 port, int32 io, int32 data) { + int32 ti; + for (ti = 0; ti < Terminals; ti++) { + if (sio_terminals[ti].statusPort == port) { + break; + } + } if (io == 0) { /* IN */ if (sio_unit.flags & UNIT_ATT) { - sio_unit.u3 = (((tmxr_rqln(altairTMXR.ldsc[0]) > 0 ? 0x01 : 0) | /* read possible if character available */ - (altairTMXR.ldsc[0]->conn == 0 ? 0 : 0x02))); /* write possible if connected */ + sio_terminals[ti].status = + (((tmxr_rqln(altairTMXR.ldsc[ti]) > 0 ? 0x01 : 0) | + /* read possible if character available */ + ((altairTMXR.ldsc[ti] -> conn) && (altairTMXR.ldsc[ti] -> xmte) ? 0x02 : 0x00))); + /* write possible if connected and transmit enabled */ } - return (sio_unit.u3); + return sio_terminals[ti].status; } else { /* OUT */ if (sio_unit.flags & UNIT_ATT) { if (data == 0x03) { /* reset port! */ - sio_unit.u3 = 0; - sio_unit.buf = 0; + sio_terminals[ti].status = 0x00; + sio_terminals[ti].data = 0; } } else { if (data == 0x03) { /* reset port! */ - sio_unit.u3 = 0x02; - sio_unit.buf = 0; + sio_terminals[ti].status = sio_terminals[ti].defaultStatus; + sio_terminals[ti].data = 0; } } - return (0); /* ignored since OUT */ + return 0; /* ignored since OUT */ } } -int32 sio0d(int32 io, int32 data) -{ +int32 sio0d(int32 port, int32 io, int32 data) { + int32 ti; + for (ti = 0; ti < Terminals; ti++) { + if (sio_terminals[ti].dataPort == port) { + break; + } + } if (io == 0) { /* IN */ if (sio_unit.flags & UNIT_ATT) { - sio_unit.buf = tmxr_getc_ln(altairTMXR.ldsc[0]) & 0xff; + sio_terminals[ti].data = tmxr_getc_ln(altairTMXR.ldsc[ti]) & 0xff; } - sio_unit.u3 = sio_unit.u3 & 0xFE; + sio_terminals[ti].status &= 0xfe; if (sio_unit.flags & UNIT_BS) { - if (sio_unit.buf == BACKSPACE_CHAR) { - sio_unit.buf = DELETE_CHAR; + if (sio_terminals[ti].data == BACKSPACE_CHAR) { + sio_terminals[ti].data = DELETE_CHAR; } } else { - if (sio_unit.buf == DELETE_CHAR) { - sio_unit.buf = BACKSPACE_CHAR; + if (sio_terminals[ti].data == DELETE_CHAR) { + sio_terminals[ti].data = BACKSPACE_CHAR; } } - return ((sio_unit.flags & UNIT_UPPER) ? toupper(sio_unit.buf) : sio_unit.buf); + return (sio_unit.flags & UNIT_UPPER) ? toupper(sio_terminals[ti].data) : sio_terminals[ti].data; } else { /* OUT */ if (sio_unit.flags & UNIT_ANSI) { data &= 0x7f; } if (sio_unit.flags & UNIT_ATT) { - tmxr_putc_ln(altairTMXR.ldsc[0], data); + tmxr_putc_ln(altairTMXR.ldsc[ti], data); } else { sim_putchar(data); } - return (0); /* ignored since OUT */ + return 0; /* ignored since OUT */ } } /* Port 2 controls the PTR/PTP devices */ -int32 sio1s(int32 io, int32 data) -{ +int32 sio1s(int32 port, int32 io, int32 data) { if (io == 0) { /* reset I bit iff PTR unit not attached or no more data available. */ /* O bit is always set since write always possible. */ - return ((ptr_unit.flags & UNIT_ATT) == 0) || (ptr_unit.u3 != 0) ? 0x02 : 0x03; + if ((ptr_unit.flags & UNIT_ATT) == 0) { + if ((sio_unit.flags & UNIT_SIO_VERBOSE) && (warnUnattachedPTR < warnLevelSIO)) { + warnUnattachedPTR++; +/*06*/ message1("Attempt to test status of unattached PTR. 0x02 returned.\n"); + } + return 0x02; + } + return (ptr_unit.u3 != 0) ? 0x02 : 0x03; } else { /* OUT */ if (data == 0x03) { - ptr_unit.u3 = 0; - ptr_unit.buf = 0; - ptr_unit.pos = 0; - ptp_unit.u3 = 0; - ptp_unit.buf = 0; - ptp_unit.pos = 0; + ptr_unit.u3 = 0; + ptr_unit.buf = 0; + ptr_unit.pos = 0; + ptp_unit.u3 = 0; + ptp_unit.buf = 0; + ptp_unit.pos = 0; } - return (0); /* ignored since OUT */ + return 0; /* ignored since OUT */ } } -int32 sio1d(int32 io, int32 data) -{ +int32 sio1d(int32 port, int32 io, int32 data) { int32 temp; if (io == 0) { /* IN */ - if (((ptr_unit.flags & UNIT_ATT) == 0) || (ptr_unit.u3 != 0)) - return (0); /* not attached or no more data available */ + if (ptr_unit.u3) { /* no more data available */ + if ((sio_unit.flags & UNIT_SIO_VERBOSE) && (warnPTREOF < warnLevelSIO)) { + warnPTREOF++; +/*07*/ message1("PTR attempted to read past EOF. 0x00 returned.\n"); + } + return 0; + } + if ((ptr_unit.flags & UNIT_ATT) == 0) { /* not attached */ + if ((sio_unit.flags & UNIT_SIO_VERBOSE) && (warnUnattachedPTR < warnLevelSIO)) { + warnUnattachedPTR++; +/*08*/ message1("Attempt to read from unattached PTR. 0x00 returned.\n"); + } + return 0; + } if ((temp = getc(ptr_dev.units -> fileref)) == EOF) { /* end of file? */ ptr_unit.u3 = 0x01; - return (CONTROLZ_CHAR); /* control Z denotes end of text file in CP/M */ + return CONTROLZ_CHAR; /* control Z denotes end of text file in CP/M */ } ptr_unit.pos++; - return (temp & 0xFF); + return temp & 0xff; } else { /* OUT */ - putc(data, ptp_dev.units -> fileref); + if (ptp_unit.flags & UNIT_ATT) { /* unit must be attached */ + putc(data, ptp_dev.units -> fileref); + } /* else ignore data */ + else if ((sio_unit.flags & UNIT_SIO_VERBOSE) && (warnUnattachedPTP < warnLevelSIO)) { + warnUnattachedPTP++; +/*09*/message2("Attempt to output '0x%02x' to unattached PTP - ignored.\n", data); + } ptp_unit.pos++; - return (0); /* ignored since OUT */ + return 0; /* ignored since OUT */ } } -int32 nulldev(int32 io, int32 data) -{ - return (io == 0 ? 0xff : 0); +int32 nulldev(int32 port, int32 io, int32 data) { + if ((sio_unit.flags & UNIT_SIO_VERBOSE) && (warnUnassignedPort < warnLevelSIO)) { + warnUnassignedPort++; + if (io == 0) { + message2("Unassigned IN(%2xh) - ignored.\n", port); + } + else { + message3("Unassigned OUT(%2xh) -> %2xh - ignored.\n", port, data); + } + } + return io == 0 ? 0xff : 0; } -#define splimit 10 -#define printTimeCmd 0 -#define markTimeCmd 1 -#define showTimeCmd 2 -#define resetPtrCmd 3 -#define attachCmd 4 -#define detachCmd 5 -#define resetCmd 6 -#define cpmCommandLineLength 128 -uint32 markTime[splimit]; -int32 markTimeSP = 0; -char version[] = "SIMH001"; -int32 versionPos = 0; +int32 sr_dev(int32 port, int32 io, int32 data) { + return io == 0 ? SR : 0; +} -/* The CP/M commandline is used as the name of a file and PTR is attached to it */ -void attachCPM() { +int32 toBCD(int32 x) { + return (x / 10) * 16 + (x % 10); +} + +int32 fromBCD(int32 x) { + return 10 * ((0xf0 & x) >> 4) + (0x0f & x); +} + +/* Z80 or 8080 programs communicate with the SIMH pseudo device via port 0xfe. + The principles are as follows: + + 1) For commands that do not require parameters and do not return results + ld a, + out (0feh),a + Special case is the reset command which needs to be send 128 times to make + sure that the internal state is properly reset. + + 2) For commands that require parameters and do not return results + ld a, + out (0feh),a + ld a, + out (0feh),a + ld a, + out (0feh),a + ... + Note: The calling program must send all parameter bytes. Otherwise + the pseudo device is left in an unexpected state. + + 3) For commands that do not require parameters and return results + ld a, + out (0feh),a + in a,(0feh) ; contains first byte of result + in a,(0feh) ; contains second byte of result + ... + Note: The calling program must request all bytes of the result. Otherwise + the pseudo device is left in an unexpected state. + + 4) Commands requiring parameters and returning results do not exist currently. + +*/ + +#define splimit 10 +#define printTimeCmd 0 /* print the current time in milliseconds */ +#define startTimerCmd 1 /* start a new timer on the top of the timer stack */ +#define stopTimerCmd 2 /* stop timer on top of timer stack and show time difference */ +#define resetPTRCmd 3 /* reset the PTR device */ +#define attachPTRCmd 4 /* attach the PTR device */ +#define detachPTRCmd 5 /* detach the PTR device */ +#define getSIMHVersionCMD 6 /* get the current version of the SIMH pseudo device */ +#define getClockZSDOSCmd 7 /* get the current time in ZSDOS format */ +#define setClockZSDOSCmd 8 /* set the current time in ZSDOS format */ +#define getClockCPM3Cmd 9 /* get the current time in CP/M 3 format */ +#define setClockCPM3Cmd 10 /* set the current time in CP/M 3 format */ +#define getBankSelectCmd 11 /* get the selected bank */ +#define setBankSelectCmd 12 /* set the selected bank */ +#define getCommonCmd 13 /* get the base address of the common memory segment */ +#define resetSIMHInterfaceCmd 14 /* reset the SIMH pseudo device */ +#define showTimerCmd 15 /* show time difference to timer on top of stack */ +#define attachPTPCmd 16 /* attach PTP to the file with name at beginning of CP/M command line */ +#define detachPTPCmd 17 /* detach PTP */ +#define hasBankedMemoryCmd 18 /* determines whether machine has banked memory */ +#define setZ80CPUCmd 19 /* set the CPU to a Z80 */ +#define set8080CPUCmd 20 /* set the CPU to an 8080 */ +#define startTimerInterruptsCmd 21 /* statr timer interrupts */ +#define stopTimerInterruptsCmd 22 /* stop timer interrupts */ +#define setTimerDeltaCmd 23 /* set the timer interval in which interrupts occur */ +#define setTimerInterruptAdrCmd 24 /* set the address to call by timer interrupts */ +#define cpmCommandLineLength 128 +struct tm *currentTime = NULL; +uint32 markTime[splimit]; +char version[] = "SIMH002"; + +t_stat simh_dev_reset(void) { + currentTime = NULL; + ClockZSDOSDelta = 0; + setClockZSDOSPos = 0; + getClockZSDOSPos = 0; + ClockCPM3Delta = 0; + setClockCPM3Pos = 0; + getClockCPM3Pos = 0; + getCommonPos = 0; + setTimerDeltaPos = 0; + setTimerInterruptAdrPos = 0; + markTimeSP = 0; + versionPos = 0; + lastCommand = 0; + lastCPMStatus = SCPE_OK; + timerInterrupt = FALSE; + if (simh_unit.flags & UNIT_SIMH_TIMERON) { + simh_dev_set_timeron(); + } + return SCPE_OK; +} + +t_stat simh_dev_set_timeron(void) { + if (rtc_avail) { + timeOfNextInterrupt = sim_os_msec() + timerDelta; + return sim_activate(&simh_unit, simh_unit.wait); /* activate unit */ + } + else { + printf("Sorry - no real time clock available.\n"); + return SCPE_ARG; + } +} + +t_stat simh_dev_set_timeroff(void) { + timerInterrupt = FALSE; + sim_cancel(&simh_unit); + return SCPE_OK; +} + +t_stat simh_svc(UNIT *uptr) { + uint32 n = sim_os_msec(); + if (n >= timeOfNextInterrupt) { + timerInterrupt = TRUE; + timeOfNextInterrupt += timerDelta; + if (n >= timeOfNextInterrupt) { /* time of next interrupt is not in the future */ + timeOfNextInterrupt = n + timerDelta; /* make sure it is in the future! */ + } + } + if (simh_unit.flags & UNIT_SIMH_TIMERON) { + sim_activate(&simh_unit, simh_unit.wait); /* activate unit */ + } + return SCPE_OK; +} + +/* The CP/M commandline is used as the name of a file and UNIT* uptr is attached to it */ +void attachCPM(UNIT *uptr) { char cpmCommandLine[cpmCommandLineLength]; - uint32 i, len = (M[0x80] & 0x7f) - 1; /* 0x80 contains length of commandline, discard first char */ + uint32 i, len = (GetBYTEWrapper(0x80) & 0x7f) - 1; /* 0x80 contains length of commandline, discard first char */ for (i = 0; i < len; i++) { - cpmCommandLine[i] = (char)M[0x82+i]; /* the first char, typically ' ', is discarded */ + cpmCommandLine[i] = (char)GetBYTEWrapper(0x82 + i); /* the first char, typically ' ', is discarded */ } cpmCommandLine[i] = 0; /* make C string */ - sim_switches = SWMASK ('R'); - attach_unit(&ptr_unit, cpmCommandLine); + if (uptr == &ptr_unit) { + sim_switches = SWMASK('R'); + } + else if (uptr == &ptp_unit) { + sim_switches = SWMASK('W'); + } + lastCPMStatus = attach_unit(uptr, cpmCommandLine); + if ((lastCPMStatus != SCPE_OK) && (simh_unit.flags & UNIT_SIMH_VERBOSE)) { + message3("Cannot open '%s' (%s).\n", cpmCommandLine, scp_error_messages[lastCPMStatus - SCPE_BASE]); + } +} + +/* setClockZSDOSAdr points to 6 byte block in M: YY MM DD HH MM SS in BCD notation */ +void setClockZSDOS(void) { + struct tm newTime; + int32 year = fromBCD(GetBYTEWrapper(setClockZSDOSAdr)); + newTime.tm_year = year < 50 ? year + 100 : year; + newTime.tm_mon = fromBCD(GetBYTEWrapper(setClockZSDOSAdr + 1)) - 1; + newTime.tm_mday = fromBCD(GetBYTEWrapper(setClockZSDOSAdr + 2)); + newTime.tm_hour = fromBCD(GetBYTEWrapper(setClockZSDOSAdr + 3)); + newTime.tm_min = fromBCD(GetBYTEWrapper(setClockZSDOSAdr + 4)); + newTime.tm_sec = fromBCD(GetBYTEWrapper(setClockZSDOSAdr + 5)); + ClockZSDOSDelta = mktime(&newTime) - time(NULL); +} + +#define secondsPerMinute 60 +#define secondsPerHour (60 * secondsPerMinute) +#define secondsPerDay (24 * secondsPerHour) +time_t mkCPM3Origin(void) { + struct tm date; + date.tm_year = 77; + date.tm_mon = 11; + date.tm_mday = 31; + date.tm_hour = 0; + date.tm_min = 0; + date.tm_sec = 0; + return mktime(&date); +} + +/* setClockCPM3Adr points to 5 byte block in M: + 0 - 1 int16: days since 31 Dec 77 + 2 BCD byte: HH + 3 BCD byte: MM + 4 BCD byte: SS */ +void setClockCPM3(void) { + ClockCPM3Delta = mkCPM3Origin() + + (GetBYTEWrapper(setClockCPM3Adr) + GetBYTEWrapper(setClockCPM3Adr + 1) * 256) * secondsPerDay + + fromBCD(GetBYTEWrapper(setClockCPM3Adr + 2)) * secondsPerHour + + fromBCD(GetBYTEWrapper(setClockCPM3Adr + 3)) * secondsPerMinute + + fromBCD(GetBYTEWrapper(setClockCPM3Adr + 4)) - time(NULL); +} + +int32 simh_in(void) { + int32 result; + switch(lastCommand) { + case attachPTRCmd: + case attachPTPCmd: + result = lastCPMStatus; + break; + case getClockZSDOSCmd: + if (currentTime) { + switch(getClockZSDOSPos) { + case 0: + result = toBCD(currentTime -> tm_year > 99 ? + currentTime -> tm_year - 100 : currentTime -> tm_year); + break; + case 1: result = toBCD(currentTime -> tm_mon + 1); break; + case 2: result = toBCD(currentTime -> tm_mday); break; + case 3: result = toBCD(currentTime -> tm_hour); break; + case 4: result = toBCD(currentTime -> tm_min); break; + case 5: result = toBCD(currentTime -> tm_sec); break; + default: result = 0; + } + getClockZSDOSPos++; + } + else { + result = 0; + } + break; + case getClockCPM3Cmd: + if (currentTime) { + switch(getClockCPM3Pos) { + case 0: result = daysCPM3SinceOrg & 0xff; break; + case 1: result = (daysCPM3SinceOrg >> 8) & 0xff; break; + case 2: result = toBCD(currentTime -> tm_hour); break; + case 3: result = toBCD(currentTime -> tm_min); break; + case 4: result = toBCD(currentTime -> tm_sec); break; + default: result = 0; + } + getClockCPM3Pos++; + } + else { + result = 0; + } + break; + case getSIMHVersionCMD: + result = version[versionPos++]; + if (result == 0) { + versionPos = 0; + } + break; + case getBankSelectCmd: + if (cpu_unit.flags & UNIT_BANKED) { + result = bankSelect; + } + else { + result = 0; + if (simh_unit.flags & UNIT_SIMH_VERBOSE) { + message1("Get selected bank ignored for non-banked memory."); + } + } + break; + case getCommonCmd: + if (getCommonPos == 0) { + result = common & 0xff; + getCommonPos = 1; + } + else { + result = (common >> 8) & 0xff; + getCommonPos = 0; + } + break; + case hasBankedMemoryCmd: + result = cpu_unit.flags & UNIT_BANKED ? MAXBANKS : 0; + break; + default: + result = 0; + } + return result; +} + +int32 simh_out(int32 data) { + uint32 delta; + time_t now; + switch(lastCommand) { + case setClockZSDOSCmd: + switch(setClockZSDOSPos) { + case 0: + setClockZSDOSAdr = data; + setClockZSDOSPos++; + break; + case 1: + setClockZSDOSAdr += (data << 8); + setClockZSDOS(); + lastCommand = 0; + break; + default:; + } + break; + case setClockCPM3Cmd: + switch(setClockCPM3Pos) { + case 0: + setClockCPM3Adr = data; + setClockCPM3Pos++; + break; + case 1: + setClockCPM3Adr += (data << 8); + setClockCPM3(); + lastCommand = 0; + break; + default:; + } + break; + case setBankSelectCmd: + if (cpu_unit.flags & UNIT_BANKED) { + bankSelect = data & BANKMASK; + } + else if (simh_unit.flags & UNIT_SIMH_VERBOSE) { + message2("Set selected bank to %i ignored for non-banked memory.", data & 3); + } + lastCommand = 0; + break; + case setTimerDeltaCmd: + switch(setTimerDeltaPos) { + case 0: + tmpTimerDelta = data; + setTimerDeltaPos++; + break; + case 1: + timerDelta = tmpTimerDelta + (data << 8); + lastCommand = 0; + break; + default:; + } + break; + case setTimerInterruptAdrCmd: + switch(setTimerInterruptAdrPos) { + case 0: + tmpTimerInterruptHandler = data; + setTimerInterruptAdrPos++; + break; + case 1: + timerInterruptHandler = tmpTimerInterruptHandler + (data << 8); + lastCommand = 0; + break; + default:; + } + break; + default: + lastCommand = data; + switch(data) { + case printTimeCmd: /* print time */ + if (rtc_avail) { + message2("Current time in milliseconds = %d.\n", sim_os_msec()); + } + break; + case startTimerCmd: /* create a new timer on top of stack */ + if (rtc_avail) { + if (markTimeSP < splimit) { + markTime[markTimeSP++] = sim_os_msec(); + } + else { + message1("Timer stack overflow.\n"); + } + } + break; + case stopTimerCmd: /* stop timer on top of stack and show time difference */ + if (rtc_avail) { + if (markTimeSP > 0) { + delta = sim_os_msec() - markTime[--markTimeSP]; + message2("Timer stopped. Elapsed time in milliseconds = %d.\n", delta); + } + else { + message1("No timer active.\n"); + } + } + break; + case resetPTRCmd: /* reset ptr device */ + ptr_reset(NULL); + 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; + currentTime = localtime(&now); + getClockZSDOSPos = 0; + break; + case setClockZSDOSCmd: + setClockZSDOSPos = 0; + break; + case getClockCPM3Cmd: + time(&now); + now += ClockCPM3Delta; + currentTime = localtime(&now); + daysCPM3SinceOrg = (now - mkCPM3Origin()) / secondsPerDay; + getClockCPM3Pos = 0; + break; + case setClockCPM3Cmd: + setClockCPM3Pos = 0; + break; + case getBankSelectCmd: + break; + case setBankSelectCmd: + break; + case getCommonCmd: + break; + case resetSIMHInterfaceCmd: + markTimeSP = 0; + lastCommand = 0; + break; + case showTimerCmd: /* show time difference to timer on top of stack */ + if (rtc_avail) { + if (markTimeSP > 0) { + delta = sim_os_msec() - markTime[markTimeSP - 1]; + message2("Timer running. Elapsed in milliseconds = %d.\n", delta); + } + else { + message1("No timer active.\n"); + } + } + 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 hasBankedMemoryCmd: + break; + case setZ80CPUCmd: + cpu_unit.flags |= UNIT_CHIP; + break; + case set8080CPUCmd: + cpu_unit.flags &= ~UNIT_CHIP; + break; + case startTimerInterruptsCmd: + if (simh_dev_set_timeron() == SCPE_OK) { + timerInterrupt = FALSE; + simh_unit.flags |= UNIT_SIMH_TIMERON; + } + break; + case stopTimerInterruptsCmd: + simh_unit.flags &= ~UNIT_SIMH_TIMERON; + simh_dev_set_timeroff(); + break; + case setTimerDeltaCmd: + setTimerDeltaPos = 0; + break; + case setTimerInterruptAdrCmd: + setTimerInterruptAdrPos = 0; + break; + default: + if (simh_unit.flags & UNIT_SIMH_VERBOSE) { + message2("Unknown command (%i) to SIMH pseudo device ignored.\n", data); + } + } + } + return 0; /* ignored, since OUT */ } /* port 0xfe is a device for communication SIMH <--> Altair machine */ -int32 simh_dev(int32 io, int32 data) { - uint32 delta; - int32 result; - if (io == 0) { /* IN */ - result = version[versionPos++]; - if (result == 0) { - versionPos = 0; - } - return (result); - } - else { /* OUT */ - switch(data) { - case printTimeCmd: /* print time */ - if (rtc_avail) { - printf("Current time in milliseconds = %d.\n", sim_os_msec ()); - if (sim_log) { - fprintf(sim_log, "Current time in milliseconds = %d.\n", sim_os_msec ()); - } - } - break; - case markTimeCmd: /* mark time */ - if (rtc_avail) { - if (markTimeSP < splimit) { - markTime[markTimeSP++] = sim_os_msec (); - } - else { - printf("Mark stack overflow.\n"); - if (sim_log) { - fprintf(sim_log, "Mark stack overflow.\n"); - } - } - } - break; - case showTimeCmd: /* show time difference */ - if (rtc_avail) { - if (markTimeSP > 0) { - delta = sim_os_msec () - markTime[--markTimeSP]; - printf("Delta to mark in milliseconds = %d.\n", delta); - if (sim_log) { - fprintf(sim_log, "Delta to mark in milliseconds = %d.\n", delta); - } - } - else { - printf("Missing mark.\n"); - if (sim_log) { - fprintf(sim_log, "Missing mark.\n"); - } - } - } - break; - case resetPtrCmd: /* reset ptr device */ - ptr_reset(NULL); - break; - case attachCmd: /* attach ptr to the file with name at beginning of CP/M command line */ - attachCPM(); - break; - case detachCmd: /* detach ptr */ - detach_unit(&ptr_unit); - break; - case resetCmd: - versionPos = 0; - break; - default:; - } - return 0; /* ignored, since OUT */ - } +int32 simh_dev(int32 port, int32 io, int32 data) { + return io == 0 ? simh_in() : simh_out(data); } - diff --git a/AltairZ80/altairZ80_sys.c b/AltairZ80/altairZ80_sys.c index 83afb8f9..6794889e 100644 --- a/AltairZ80/altairZ80_sys.c +++ b/AltairZ80/altairZ80_sys.c @@ -1,5 +1,5 @@ /* altairz80_sys.c: MITS Altair system interface - Written by Peter Schorn, 2001 + Written by Peter Schorn, 2001-2002 Based on work by Charles E Owen ((c) 1997 - Commercial use prohibited) Disassembler from Marat Fayzullin ((c) 1995, 1996, 1997 - Commercial use prohibited) */ @@ -12,19 +12,26 @@ extern DEVICE dsk_dev; extern UNIT cpu_unit; extern REG cpu_reg[]; extern DEVICE sio_dev; +extern DEVICE simh_device; extern DEVICE ptr_dev; extern DEVICE ptp_dev; -extern uint8 M[]; extern int32 saved_PC; +extern char *get_range(char *cptr, t_addr *lo, t_addr *hi, int rdx, + t_addr max, char term); +extern t_value get_uint(char *cptr, int radix, t_value max, t_stat *status); +extern void PutBYTEWrapper(register uint32 Addr, register uint32 Value); +extern uint8 GetBYTEWrapper(register uint32 Addr); -int32 sim_load (FILE *fileref, char *cptr, char *fnam, int32 flag); -int32 fprint_sym (FILE *of, int32 addr, uint32 *val, UNIT *uptr, int32 sw); +int32 sim_load(FILE *fileref, char *cptr, char *fnam, int32 flag); +int32 fprint_sym(FILE *of, int32 addr, uint32 *val, UNIT *uptr, int32 sw); int32 checkbase(char ch, char *numString); int32 numok(char ch, char **numString, int32 minvalue, int32 maxvalue, int32 requireSign, int32 *result); -int32 match(char *pattern, char *input, char *xy, int32 *number, int32 *star, int32 *at, int32 *hat); +int32 match(char *pattern, char *input, char *xy, int32 *number, int32 *star, int32 *at, + int32 *hat, int32 *dollar); int32 parse_X80(char *cptr, int32 addr, uint32 *val, char *Mnemonics[]); -int32 parse_sym (char *cptr, int32 addr, UNIT *uptr, uint32 *val, int32 sw); -int32 DAsm(char *S, uint32 *val, int32 useZ80Mnemonics); +int32 parse_sym(char *cptr, int32 addr, UNIT *uptr, uint32 *val, int32 sw); +int32 DAsm(char *S, uint32 *val, int32 useZ80Mnemonics, int32 addr); +int32 checkXY(char xy); /* SCP data structures sim_name simulator name string @@ -38,229 +45,231 @@ int32 DAsm(char *S, uint32 *val, int32 useZ80Mnemonics); char sim_name[] = "Altair 8800 (Z80)"; REG *sim_PC = &cpu_reg[0]; int32 sim_emax = 4; -DEVICE *sim_devices[] = { &cpu_dev, &sio_dev, &ptr_dev, &ptp_dev, &dsk_dev, NULL }; +DEVICE *sim_devices[] = { &cpu_dev, &sio_dev, &simh_device, &ptr_dev, &ptp_dev, &dsk_dev, NULL }; +char memoryAccessMessage[80]; const char *sim_stop_messages[] = { "Unknown error", "Unknown I/O Instruction", "HALT instruction", "Breakpoint", + memoryAccessMessage, "Invalid Opcode" }; static char *Mnemonics8080[] = { -/*0/8 1/9 2/A 3/B 4/C 5/D 6/E 7/F */ - "NOP", "LXI B,#h", "STAX B", "INX B", "INR B", "DCR B", "MVI B,*h", "RLC", /* 00-07 */ - "DB 09h", "DAD B", "LDAX B", "DCX B", "INR C", "DCR C", "MVI C,*h", "RRC", /* 08-0f */ - "DB 10h", "LXI D,#h", "STAX D", "INX D", "INR D", "DCR D", "MVI D,*h", "RAL", /* 10-17 */ - "DB 18h", "DAD D", "LDAX D", "DCX D", "INR E", "DCR E", "MVI E,*h", "RAR", /* 18-1f */ - "DB 20h", "LXI H,#h", "SHLD #h", "INX H", "INR H", "DCR H", "MVI H,*h", "DAA", /* 20-27 */ - "DB 28h", "DAD H", "LHLD #h", "DCX H", "INR L", "DCR L", "MVI L,*h", "CMA", /* 28-2f */ - "DB 30h", "LXI SP,#h", "STA #h", "INX SP", "INR M", "DCR M", "MVI M,*h", "STC", /* 30-37 */ - "DB 38h", "DAD SP", "LDA #h", "DCX SP", "INR A", "DCR A", "MVI A,*h", "CMC", /* 38-3f */ - "MOV B,B", "MOV B,C", "MOV B,D", "MOV B,E", "MOV B,H", "MOV B,L", "MOV B,M", "MOV B,A", /* 40-47 */ - "MOV C,B", "MOV C,C", "MOV C,D", "MOV C,E", "MOV C,H", "MOV C,L", "MOV C,M", "MOV C,A", /* 48-4f */ - "MOV D,B", "MOV D,C", "MOV D,D", "MOV D,E", "MOV D,H", "MOV D,L", "MOV D,M", "MOV D,A", /* 50-57 */ - "MOV E,B", "MOV E,C", "MOV E,D", "MOV E,E", "MOV E,H", "MOV E,L", "MOV E,M", "MOV E,A", /* 58-5f */ - "MOV H,B", "MOV H,C", "MOV H,D", "MOV H,E", "MOV H,H", "MOV H,L", "MOV H,M", "MOV H,A", /* 60-67 */ - "MOV L,B", "MOV L,C", "MOV L,D", "MOV L,E", "MOV L,H", "MOV L,L", "MOV L,M", "MOV L,A", /* 68-6f */ - "MOV M,B", "MOV M,C", "MOV M,D", "MOV M,E", "MOV M,H", "MOV M,L", "HLT", "MOV M,A", /* 70-77 */ - "MOV A,B", "MOV A,C", "MOV A,D", "MOV A,E", "MOV A,H", "MOV A,L", "MOV A,M", "MOV A,A", /* 78-7f */ - "ADD B", "ADD C", "ADD D", "ADD E", "ADD H", "ADD L", "ADD M", "ADD A", /* 80-87 */ - "ADC B", "ADC C", "ADC D", "ADC E", "ADC H", "ADC L", "ADC M", "ADC A", /* 88-8f */ - "SUB B", "SUB C", "SUB D", "SUB E", "SUB H", "SUB L", "SUB M", "SUB A", /* 90-97 */ - "SBB B", "SBB C", "SBB D", "SBB E", "SBB H", "SBB L", "SBB M", "SBB A", /* 98-9f */ - "ANA B", "ANA C", "ANA D", "ANA E", "ANA H", "ANA L", "ANA M", "ANA A", /* a0-a7 */ - "XRA B", "XRA C", "XRA D", "XRA E", "XRA H", "XRA L", "XRA M", "XRA A", /* a8-af */ - "ORA B", "ORA C", "ORA D", "ORA E", "ORA H", "ORA L", "ORA M", "ORA A", /* b0-b7 */ - "CMP B", "CMP C", "CMP D", "CMP E", "CMP H", "CMP L", "CMP M", "CMP A", /* b8-bf */ - "RNZ", "POP B", "JNZ #h", "JMP #h", "CNZ #h", "PUSH B", "ADI *h", "RST 0", /* c0-c7 */ - "RZ", "RET", "JZ #h", "DB CBh", "CZ #h", "CALL #h", "ACI *h", "RST 1", /* c8-cf */ - "RNC", "POP D", "JNC #h", "OUT *h", "CNC #h", "PUSH D", "SUI *h", "RST 2", /* d0-d7 */ - "RC", "DB D9h", "JC #h", "IN *h", "CC #h", "DB DDh", "SBI *h", "RST 3", /* d8-df */ - "RPO", "POP H", "JPO #h", "XTHL", "CPO #h", "PUSH H", "ANI *h", "RST 4", /* e0-e7 */ - "RPE", "PCHL", "JPE #h", "XCHG", "CPE #h", "DB EDh", "XRI *h", "RST 5", /* e8-ef */ - "RP", "POP PSW", "JP #h", "DI", "CP #h", "PUSH PSW", "ORI *h", "RST 6", /* f0-f7 */ - "RM", "SPHL", "JM #h", "EI", "CM #h", "DB FDh", "CPI *h", "RST 7" /* f8-ff */ +/*0/8 1/9 2/A 3/B 4/C 5/D 6/E 7/F */ + "NOP", "LXI B,#h", "STAX B", "INX B", "INR B", "DCR B", "MVI B,*h", "RLC", /* 00-07 */ + "DB 09h", "DAD B", "LDAX B", "DCX B", "INR C", "DCR C", "MVI C,*h", "RRC", /* 08-0f */ + "DB 10h", "LXI D,#h", "STAX D", "INX D", "INR D", "DCR D", "MVI D,*h", "RAL", /* 10-17 */ + "DB 18h", "DAD D", "LDAX D", "DCX D", "INR E", "DCR E", "MVI E,*h", "RAR", /* 18-1f */ + "DB 20h", "LXI H,#h", "SHLD #h", "INX H", "INR H", "DCR H", "MVI H,*h", "DAA", /* 20-27 */ + "DB 28h", "DAD H", "LHLD #h", "DCX H", "INR L", "DCR L", "MVI L,*h", "CMA", /* 28-2f */ + "DB 30h", "LXI SP,#h", "STA #h", "INX SP", "INR M", "DCR M", "MVI M,*h", "STC", /* 30-37 */ + "DB 38h", "DAD SP", "LDA #h", "DCX SP", "INR A", "DCR A", "MVI A,*h", "CMC", /* 38-3f */ + "MOV B,B", "MOV B,C", "MOV B,D", "MOV B,E", "MOV B,H", "MOV B,L", "MOV B,M", "MOV B,A", /* 40-47 */ + "MOV C,B", "MOV C,C", "MOV C,D", "MOV C,E", "MOV C,H", "MOV C,L", "MOV C,M", "MOV C,A", /* 48-4f */ + "MOV D,B", "MOV D,C", "MOV D,D", "MOV D,E", "MOV D,H", "MOV D,L", "MOV D,M", "MOV D,A", /* 50-57 */ + "MOV E,B", "MOV E,C", "MOV E,D", "MOV E,E", "MOV E,H", "MOV E,L", "MOV E,M", "MOV E,A", /* 58-5f */ + "MOV H,B", "MOV H,C", "MOV H,D", "MOV H,E", "MOV H,H", "MOV H,L", "MOV H,M", "MOV H,A", /* 60-67 */ + "MOV L,B", "MOV L,C", "MOV L,D", "MOV L,E", "MOV L,H", "MOV L,L", "MOV L,M", "MOV L,A", /* 68-6f */ + "MOV M,B", "MOV M,C", "MOV M,D", "MOV M,E", "MOV M,H", "MOV M,L", "HLT", "MOV M,A", /* 70-77 */ + "MOV A,B", "MOV A,C", "MOV A,D", "MOV A,E", "MOV A,H", "MOV A,L", "MOV A,M", "MOV A,A", /* 78-7f */ + "ADD B", "ADD C", "ADD D", "ADD E", "ADD H", "ADD L", "ADD M", "ADD A", /* 80-87 */ + "ADC B", "ADC C", "ADC D", "ADC E", "ADC H", "ADC L", "ADC M", "ADC A", /* 88-8f */ + "SUB B", "SUB C", "SUB D", "SUB E", "SUB H", "SUB L", "SUB M", "SUB A", /* 90-97 */ + "SBB B", "SBB C", "SBB D", "SBB E", "SBB H", "SBB L", "SBB M", "SBB A", /* 98-9f */ + "ANA B", "ANA C", "ANA D", "ANA E", "ANA H", "ANA L", "ANA M", "ANA A", /* a0-a7 */ + "XRA B", "XRA C", "XRA D", "XRA E", "XRA H", "XRA L", "XRA M", "XRA A", /* a8-af */ + "ORA B", "ORA C", "ORA D", "ORA E", "ORA H", "ORA L", "ORA M", "ORA A", /* b0-b7 */ + "CMP B", "CMP C", "CMP D", "CMP E", "CMP H", "CMP L", "CMP M", "CMP A", /* b8-bf */ + "RNZ", "POP B", "JNZ #h", "JMP #h", "CNZ #h", "PUSH B", "ADI *h", "RST 0", /* c0-c7 */ + "RZ", "RET", "JZ #h", "DB CBh", "CZ #h", "CALL #h", "ACI *h", "RST 1", /* c8-cf */ + "RNC", "POP D", "JNC #h", "OUT *h", "CNC #h", "PUSH D", "SUI *h", "RST 2", /* d0-d7 */ + "RC", "DB D9h", "JC #h", "IN *h", "CC #h", "DB DDh", "SBI *h", "RST 3", /* d8-df */ + "RPO", "POP H", "JPO #h", "XTHL", "CPO #h", "PUSH H", "ANI *h", "RST 4", /* e0-e7 */ + "RPE", "PCHL", "JPE #h", "XCHG", "CPE #h", "DB EDh", "XRI *h", "RST 5", /* e8-ef */ + "RP", "POP PSW", "JP #h", "DI", "CP #h", "PUSH PSW", "ORI *h", "RST 6", /* f0-f7 */ + "RM", "SPHL", "JM #h", "EI", "CM #h", "DB FDh", "CPI *h", "RST 7" /* f8-ff */ }; -static char *MnemonicsZ80[256] = -{ - "NOP", "LD BC,#h", "LD (BC),A", "INC BC", "INC B", "DEC B", "LD B,*h", "RLCA", - "EX AF,AF'", "ADD HL,BC", "LD A,(BC)", "DEC BC", "INC C", "DEC C", "LD C,*h", "RRCA", - "DJNZ @h", "LD DE,#h", "LD (DE),A", "INC DE", "INC D", "DEC D", "LD D,*h", "RLA", - "JR @h", "ADD HL,DE", "LD A,(DE)", "DEC DE", "INC E", "DEC E", "LD E,*h", "RRA", - "JR NZ,@h", "LD HL,#h", "LD (#h),HL", "INC HL", "INC H", "DEC H", "LD H,*h", "DAA", - "JR Z,@h", "ADD HL,HL", "LD HL,(#h)", "DEC HL", "INC L", "DEC L", "LD L,*h", "CPL", - "JR NC,@h", "LD SP,#h", "LD (#h),A", "INC SP", "INC (HL)", "DEC (HL)", "LD (HL),*h", "SCF", - "JR C,@h", "ADD HL,SP", "LD A,(#h)", "DEC SP", "INC A", "DEC A", "LD A,*h", "CCF", - "LD B,B", "LD B,C", "LD B,D", "LD B,E", "LD B,H", "LD B,L", "LD B,(HL)", "LD B,A", - "LD C,B", "LD C,C", "LD C,D", "LD C,E", "LD C,H", "LD C,L", "LD C,(HL)", "LD C,A", - "LD D,B", "LD D,C", "LD D,D", "LD D,E", "LD D,H", "LD D,L", "LD D,(HL)", "LD D,A", - "LD E,B", "LD E,C", "LD E,D", "LD E,E", "LD E,H", "LD E,L", "LD E,(HL)", "LD E,A", - "LD H,B", "LD H,C", "LD H,D", "LD H,E", "LD H,H", "LD H,L", "LD H,(HL)", "LD H,A", - "LD L,B", "LD L,C", "LD L,D", "LD L,E", "LD L,H", "LD L,L", "LD L,(HL)", "LD L,A", - "LD (HL),B", "LD (HL),C", "LD (HL),D", "LD (HL),E", "LD (HL),H", "LD (HL),L", "HALT", "LD (HL),A", - "LD A,B", "LD A,C", "LD A,D", "LD A,E", "LD A,H", "LD A,L", "LD A,(HL)", "LD A,A", - "ADD B", "ADD C", "ADD D", "ADD E", "ADD H", "ADD L", "ADD (HL)", "ADD A", - "ADC B", "ADC C", "ADC D", "ADC E", "ADC H", "ADC L", "ADC (HL)", "ADC A", - "SUB B", "SUB C", "SUB D", "SUB E", "SUB H", "SUB L", "SUB (HL)", "SUB A", - "SBC B", "SBC C", "SBC D", "SBC E", "SBC H", "SBC L", "SBC (HL)", "SBC A", - "AND B", "AND C", "AND D", "AND E", "AND H", "AND L", "AND (HL)", "AND A", - "XOR B", "XOR C", "XOR D", "XOR E", "XOR H", "XOR L", "XOR (HL)", "XOR A", - "OR B", "OR C", "OR D", "OR E", "OR H", "OR L", "OR (HL)", "OR A", - "CP B", "CP C", "CP D", "CP E", "CP H", "CP L", "CP (HL)", "CP A", - "RET NZ", "POP BC", "JP NZ,#h", "JP #h", "CALL NZ,#h", "PUSH BC", "ADD *h", "RST 00h", - "RET Z", "RET", "JP Z,#h", "PFX_CB", "CALL Z,#h", "CALL #h", "ADC *h", "RST 08h", - "RET NC", "POP DE", "JP NC,#h", "OUT (*h),A", "CALL NC,#h", "PUSH DE", "SUB *h", "RST 10h", - "RET C", "EXX", "JP C,#h", "IN A,(*h)", "CALL C,#h", "PFX_DD", "SBC *h", "RST 18h", - "RET PO", "POP HL", "JP PO,#h", "EX HL,(SP)", "CALL PO,#h", "PUSH HL", "AND *h", "RST 20h", - "RET PE", "LD PC,HL", "JP PE,#h", "EX DE,HL", "CALL PE,#h", "PFX_ED", "XOR *h", "RST 28h", - "RET P", "POP AF", "JP P,#h", "DI", "CALL P,#h", "PUSH AF", "OR *h", "RST 30h", - "RET M", "LD SP,HL", "JP M,#h", "EI", "CALL M,#h", "PFX_FD", "CP *h", "RST 38h" +static char *MnemonicsZ80[256] = { +/*0/8 1/9 2/A 3/B 4/C 5/D 6/E 7/F */ + "NOP", "LD BC,#h", "LD (BC),A", "INC BC", "INC B", "DEC B", "LD B,*h", "RLCA", /* 00-07 */ + "EX AF,AF'", "ADD HL,BC", "LD A,(BC)", "DEC BC", "INC C", "DEC C", "LD C,*h", "RRCA", /* 08-0f */ + "DJNZ $h", "LD DE,#h", "LD (DE),A", "INC DE", "INC D", "DEC D", "LD D,*h", "RLA", /* 10-17 */ + "JR $h", "ADD HL,DE", "LD A,(DE)", "DEC DE", "INC E", "DEC E", "LD E,*h", "RRA", /* 18-1f */ + "JR NZ,$h", "LD HL,#h", "LD (#h),HL", "INC HL", "INC H", "DEC H", "LD H,*h", "DAA", /* 20-27 */ + "JR Z,$h", "ADD HL,HL", "LD HL,(#h)", "DEC HL", "INC L", "DEC L", "LD L,*h", "CPL", /* 28-2f */ + "JR NC,$h", "LD SP,#h", "LD (#h),A", "INC SP", "INC (HL)", "DEC (HL)", "LD (HL),*h", "SCF", /* 30-37 */ + "JR C,$h", "ADD HL,SP", "LD A,(#h)", "DEC SP", "INC A", "DEC A", "LD A,*h", "CCF", /* 38-3f */ + "LD B,B", "LD B,C", "LD B,D", "LD B,E", "LD B,H", "LD B,L", "LD B,(HL)", "LD B,A", /* 40-47 */ + "LD C,B", "LD C,C", "LD C,D", "LD C,E", "LD C,H", "LD C,L", "LD C,(HL)", "LD C,A", /* 48-4f */ + "LD D,B", "LD D,C", "LD D,D", "LD D,E", "LD D,H", "LD D,L", "LD D,(HL)", "LD D,A", /* 50-57 */ + "LD E,B", "LD E,C", "LD E,D", "LD E,E", "LD E,H", "LD E,L", "LD E,(HL)", "LD E,A", /* 58-5f */ + "LD H,B", "LD H,C", "LD H,D", "LD H,E", "LD H,H", "LD H,L", "LD H,(HL)", "LD H,A", /* 60-67 */ + "LD L,B", "LD L,C", "LD L,D", "LD L,E", "LD L,H", "LD L,L", "LD L,(HL)", "LD L,A", /* 68-6f */ + "LD (HL),B", "LD (HL),C", "LD (HL),D", "LD (HL),E", "LD (HL),H", "LD (HL),L", "HALT", "LD (HL),A", /* 70-77 */ + "LD A,B", "LD A,C", "LD A,D", "LD A,E", "LD A,H", "LD A,L", "LD A,(HL)", "LD A,A", /* 78-7f */ + "ADD A,B", "ADD A,C", "ADD A,D", "ADD A,E", "ADD A,H", "ADD A,L", "ADD A,(HL)", "ADD A,A", /* 80-87 */ + "ADC A,B", "ADC A,C", "ADC A,D", "ADC A,E", "ADC A,H", "ADC A,L", "ADC A,(HL)", "ADC A,A", /* 88-8f */ + "SUB B", "SUB C", "SUB D", "SUB E", "SUB H", "SUB L", "SUB (HL)", "SUB A", /* 90-97 */ + "SBC A,B", "SBC A,C", "SBC A,D", "SBC A,E", "SBC A,H", "SBC A,L", "SBC A,(HL)", "SBC A,A", /* 98-9f */ + "AND B", "AND C", "AND D", "AND E", "AND H", "AND L", "AND (HL)", "AND A", /* a0-a7 */ + "XOR B", "XOR C", "XOR D", "XOR E", "XOR H", "XOR L", "XOR (HL)", "XOR A", /* a8-af */ + "OR B", "OR C", "OR D", "OR E", "OR H", "OR L", "OR (HL)", "OR A", /* b0-b7 */ + "CP B", "CP C", "CP D", "CP E", "CP H", "CP L", "CP (HL)", "CP A", /* b8-bf */ + "RET NZ", "POP BC", "JP NZ,#h", "JP #h", "CALL NZ,#h", "PUSH BC", "ADD A,*h", "RST 00h", /* c0-c7 */ + "RET Z", "RET", "JP Z,#h", "PFX_CB", "CALL Z,#h", "CALL #h", "ADC A,*h", "RST 08h", /* c8-cf */ + "RET NC", "POP DE", "JP NC,#h", "OUT (*h),A", "CALL NC,#h", "PUSH DE", "SUB *h", "RST 10h", /* d0-d7 */ + "RET C", "EXX", "JP C,#h", "IN A,(*h)", "CALL C,#h", "PFX_DD", "SBC A,*h", "RST 18h", /* d8-df */ + "RET PO", "POP HL", "JP PO,#h", "EX (SP),HL", "CALL PO,#h", "PUSH HL", "AND *h", "RST 20h", /* e0-e7 */ + "RET PE", "LD PC,HL", "JP PE,#h", "EX DE,HL", "CALL PE,#h", "PFX_ED", "XOR *h", "RST 28h", /* e8-ef */ + "RET P", "POP AF", "JP P,#h", "DI", "CALL P,#h", "PUSH AF", "OR *h", "RST 30h", /* f0-f7 */ + "RET M", "LD SP,HL", "JP M,#h", "EI", "CALL M,#h", "PFX_FD", "CP *h", "RST 38h" /* f8-ff */ }; -static char *MnemonicsCB[256] = -{ - "RLC B", "RLC C", "RLC D", "RLC E", "RLC H", "RLC L", "RLC (HL)", "RLC A", - "RRC B", "RRC C", "RRC D", "RRC E", "RRC H", "RRC L", "RRC (HL)", "RRC A", - "RL B", "RL C", "RL D", "RL E", "RL H", "RL L", "RL (HL)", "RL A", - "RR B", "RR C", "RR D", "RR E", "RR H", "RR L", "RR (HL)", "RR A", - "SLA B", "SLA C", "SLA D", "SLA E", "SLA H", "SLA L", "SLA (HL)", "SLA A", - "SRA B", "SRA C", "SRA D", "SRA E", "SRA H", "SRA L", "SRA (HL)", "SRA A", - "SLL B", "SLL C", "SLL D", "SLL E", "SLL H", "SLL L", "SLL (HL)", "SLL A", - "SRL B", "SRL C", "SRL D", "SRL E", "SRL H", "SRL L", "SRL (HL)", "SRL A", - "BIT 0,B", "BIT 0,C", "BIT 0,D", "BIT 0,E", "BIT 0,H", "BIT 0,L", "BIT 0,(HL)", "BIT 0,A", - "BIT 1,B", "BIT 1,C", "BIT 1,D", "BIT 1,E", "BIT 1,H", "BIT 1,L", "BIT 1,(HL)", "BIT 1,A", - "BIT 2,B", "BIT 2,C", "BIT 2,D", "BIT 2,E", "BIT 2,H", "BIT 2,L", "BIT 2,(HL)", "BIT 2,A", - "BIT 3,B", "BIT 3,C", "BIT 3,D", "BIT 3,E", "BIT 3,H", "BIT 3,L", "BIT 3,(HL)", "BIT 3,A", - "BIT 4,B", "BIT 4,C", "BIT 4,D", "BIT 4,E", "BIT 4,H", "BIT 4,L", "BIT 4,(HL)", "BIT 4,A", - "BIT 5,B", "BIT 5,C", "BIT 5,D", "BIT 5,E", "BIT 5,H", "BIT 5,L", "BIT 5,(HL)", "BIT 5,A", - "BIT 6,B", "BIT 6,C", "BIT 6,D", "BIT 6,E", "BIT 6,H", "BIT 6,L", "BIT 6,(HL)", "BIT 6,A", - "BIT 7,B", "BIT 7,C", "BIT 7,D", "BIT 7,E", "BIT 7,H", "BIT 7,L", "BIT 7,(HL)", "BIT 7,A", - "RES 0,B", "RES 0,C", "RES 0,D", "RES 0,E", "RES 0,H", "RES 0,L", "RES 0,(HL)", "RES 0,A", - "RES 1,B", "RES 1,C", "RES 1,D", "RES 1,E", "RES 1,H", "RES 1,L", "RES 1,(HL)", "RES 1,A", - "RES 2,B", "RES 2,C", "RES 2,D", "RES 2,E", "RES 2,H", "RES 2,L", "RES 2,(HL)", "RES 2,A", - "RES 3,B", "RES 3,C", "RES 3,D", "RES 3,E", "RES 3,H", "RES 3,L", "RES 3,(HL)", "RES 3,A", - "RES 4,B", "RES 4,C", "RES 4,D", "RES 4,E", "RES 4,H", "RES 4,L", "RES 4,(HL)", "RES 4,A", - "RES 5,B", "RES 5,C", "RES 5,D", "RES 5,E", "RES 5,H", "RES 5,L", "RES 5,(HL)", "RES 5,A", - "RES 6,B", "RES 6,C", "RES 6,D", "RES 6,E", "RES 6,H", "RES 6,L", "RES 6,(HL)", "RES 6,A", - "RES 7,B", "RES 7,C", "RES 7,D", "RES 7,E", "RES 7,H", "RES 7,L", "RES 7,(HL)", "RES 7,A", - "SET 0,B", "SET 0,C", "SET 0,D", "SET 0,E", "SET 0,H", "SET 0,L", "SET 0,(HL)", "SET 0,A", - "SET 1,B", "SET 1,C", "SET 1,D", "SET 1,E", "SET 1,H", "SET 1,L", "SET 1,(HL)", "SET 1,A", - "SET 2,B", "SET 2,C", "SET 2,D", "SET 2,E", "SET 2,H", "SET 2,L", "SET 2,(HL)", "SET 2,A", - "SET 3,B", "SET 3,C", "SET 3,D", "SET 3,E", "SET 3,H", "SET 3,L", "SET 3,(HL)", "SET 3,A", - "SET 4,B", "SET 4,C", "SET 4,D", "SET 4,E", "SET 4,H", "SET 4,L", "SET 4,(HL)", "SET 4,A", - "SET 5,B", "SET 5,C", "SET 5,D", "SET 5,E", "SET 5,H", "SET 5,L", "SET 5,(HL)", "SET 5,A", - "SET 6,B", "SET 6,C", "SET 6,D", "SET 6,E", "SET 6,H", "SET 6,L", "SET 6,(HL)", "SET 6,A", - "SET 7,B", "SET 7,C", "SET 7,D", "SET 7,E", "SET 7,H", "SET 7,L", "SET 7,(HL)", "SET 7,A" +static char *MnemonicsCB[256] = { +/*0/8 1/9 2/A 3/B 4/C 5/D 6/E 7/F */ + "RLC B", "RLC C", "RLC D", "RLC E", "RLC H", "RLC L", "RLC (HL)", "RLC A", /* 00-07 */ + "RRC B", "RRC C", "RRC D", "RRC E", "RRC H", "RRC L", "RRC (HL)", "RRC A", /* 08-0f */ + "RL B", "RL C", "RL D", "RL E", "RL H", "RL L", "RL (HL)", "RL A", /* 10-17 */ + "RR B", "RR C", "RR D", "RR E", "RR H", "RR L", "RR (HL)", "RR A", /* 18-1f */ + "SLA B", "SLA C", "SLA D", "SLA E", "SLA H", "SLA L", "SLA (HL)", "SLA A", /* 20-27 */ + "SRA B", "SRA C", "SRA D", "SRA E", "SRA H", "SRA L", "SRA (HL)", "SRA A", /* 28-2f */ + "SLL B", "SLL C", "SLL D", "SLL E", "SLL H", "SLL L", "SLL (HL)", "SLL A", /* 30-37 */ + "SRL B", "SRL C", "SRL D", "SRL E", "SRL H", "SRL L", "SRL (HL)", "SRL A", /* 38-3f */ + "BIT 0,B", "BIT 0,C", "BIT 0,D", "BIT 0,E", "BIT 0,H", "BIT 0,L", "BIT 0,(HL)", "BIT 0,A", /* 40-47 */ + "BIT 1,B", "BIT 1,C", "BIT 1,D", "BIT 1,E", "BIT 1,H", "BIT 1,L", "BIT 1,(HL)", "BIT 1,A", /* 48-4f */ + "BIT 2,B", "BIT 2,C", "BIT 2,D", "BIT 2,E", "BIT 2,H", "BIT 2,L", "BIT 2,(HL)", "BIT 2,A", /* 50-57 */ + "BIT 3,B", "BIT 3,C", "BIT 3,D", "BIT 3,E", "BIT 3,H", "BIT 3,L", "BIT 3,(HL)", "BIT 3,A", /* 58-5f */ + "BIT 4,B", "BIT 4,C", "BIT 4,D", "BIT 4,E", "BIT 4,H", "BIT 4,L", "BIT 4,(HL)", "BIT 4,A", /* 60-67 */ + "BIT 5,B", "BIT 5,C", "BIT 5,D", "BIT 5,E", "BIT 5,H", "BIT 5,L", "BIT 5,(HL)", "BIT 5,A", /* 68-6f */ + "BIT 6,B", "BIT 6,C", "BIT 6,D", "BIT 6,E", "BIT 6,H", "BIT 6,L", "BIT 6,(HL)", "BIT 6,A", /* 70-77 */ + "BIT 7,B", "BIT 7,C", "BIT 7,D", "BIT 7,E", "BIT 7,H", "BIT 7,L", "BIT 7,(HL)", "BIT 7,A", /* 78-7f */ + "RES 0,B", "RES 0,C", "RES 0,D", "RES 0,E", "RES 0,H", "RES 0,L", "RES 0,(HL)", "RES 0,A", /* 80-87 */ + "RES 1,B", "RES 1,C", "RES 1,D", "RES 1,E", "RES 1,H", "RES 1,L", "RES 1,(HL)", "RES 1,A", /* 88-8f */ + "RES 2,B", "RES 2,C", "RES 2,D", "RES 2,E", "RES 2,H", "RES 2,L", "RES 2,(HL)", "RES 2,A", /* 90-97 */ + "RES 3,B", "RES 3,C", "RES 3,D", "RES 3,E", "RES 3,H", "RES 3,L", "RES 3,(HL)", "RES 3,A", /* 98-9f */ + "RES 4,B", "RES 4,C", "RES 4,D", "RES 4,E", "RES 4,H", "RES 4,L", "RES 4,(HL)", "RES 4,A", /* a0-a7 */ + "RES 5,B", "RES 5,C", "RES 5,D", "RES 5,E", "RES 5,H", "RES 5,L", "RES 5,(HL)", "RES 5,A", /* a8-af */ + "RES 6,B", "RES 6,C", "RES 6,D", "RES 6,E", "RES 6,H", "RES 6,L", "RES 6,(HL)", "RES 6,A", /* b0-b7 */ + "RES 7,B", "RES 7,C", "RES 7,D", "RES 7,E", "RES 7,H", "RES 7,L", "RES 7,(HL)", "RES 7,A", /* b8-bf */ + "SET 0,B", "SET 0,C", "SET 0,D", "SET 0,E", "SET 0,H", "SET 0,L", "SET 0,(HL)", "SET 0,A", /* c0-c7 */ + "SET 1,B", "SET 1,C", "SET 1,D", "SET 1,E", "SET 1,H", "SET 1,L", "SET 1,(HL)", "SET 1,A", /* c8-cf */ + "SET 2,B", "SET 2,C", "SET 2,D", "SET 2,E", "SET 2,H", "SET 2,L", "SET 2,(HL)", "SET 2,A", /* d0-d7 */ + "SET 3,B", "SET 3,C", "SET 3,D", "SET 3,E", "SET 3,H", "SET 3,L", "SET 3,(HL)", "SET 3,A", /* d8-df */ + "SET 4,B", "SET 4,C", "SET 4,D", "SET 4,E", "SET 4,H", "SET 4,L", "SET 4,(HL)", "SET 4,A", /* e0-e7 */ + "SET 5,B", "SET 5,C", "SET 5,D", "SET 5,E", "SET 5,H", "SET 5,L", "SET 5,(HL)", "SET 5,A", /* e8-ef */ + "SET 6,B", "SET 6,C", "SET 6,D", "SET 6,E", "SET 6,H", "SET 6,L", "SET 6,(HL)", "SET 6,A", /* f0-f7 */ + "SET 7,B", "SET 7,C", "SET 7,D", "SET 7,E", "SET 7,H", "SET 7,L", "SET 7,(HL)", "SET 7,A" /* f8-ff */ }; -static char *MnemonicsED[256] = -{ - "DB EDh,00h", "DB EDh,01h", "DB EDh,02h", "DB EDh,03h", "DB EDh,04h", "DB EDh,05h", "DB EDh,06h", "DB EDh,07h", - "DB EDh,08h", "DB EDh,09h", "DB EDh,0Ah", "DB EDh,0Bh", "DB EDh,0Ch", "DB EDh,0Dh", "DB EDh,0Eh", "DB EDh,0Fh", - "DB EDh,10h", "DB EDh,11h", "DB EDh,12h", "DB EDh,13h", "DB EDh,14h", "DB EDh,15h", "DB EDh,16h", "DB EDh,17h", - "DB EDh,18h", "DB EDh,19h", "DB EDh,1Ah", "DB EDh,1Bh", "DB EDh,1Ch", "DB EDh,1Dh", "DB EDh,1Eh", "DB EDh,1Fh", - "DB EDh,20h", "DB EDh,21h", "DB EDh,22h", "DB EDh,23h", "DB EDh,24h", "DB EDh,25h", "DB EDh,26h", "DB EDh,27h", - "DB EDh,28h", "DB EDh,29h", "DB EDh,2Ah", "DB EDh,2Bh", "DB EDh,2Ch", "DB EDh,2Dh", "DB EDh,2Eh", "DB EDh,2Fh", - "DB EDh,30h", "DB EDh,31h", "DB EDh,32h", "DB EDh,33h", "DB EDh,34h", "DB EDh,35h", "DB EDh,36h", "DB EDh,37h", - "DB EDh,38h", "DB EDh,39h", "DB EDh,3Ah", "DB EDh,3Bh", "DB EDh,3Ch", "DB EDh,3Dh", "DB EDh,3Eh", "DB EDh,3Fh", - "IN B,(C)", "OUT (C),B", "SBC HL,BC", "LD (#h),BC", "NEG", "RETN", "IM 0", "LD I,A", - "IN C,(C)", "OUT (C),C", "ADC HL,BC", "LD BC,(#h)", "DB EDh,4Ch", "RETI", "DB EDh,4Eh", "LD R,A", - "IN D,(C)", "OUT (C),D", "SBC HL,DE", "LD (#h),DE", "DB EDh,54h", "DB EDh,55h", "IM 1", "LD A,I", - "IN E,(C)", "OUT (C),E", "ADC HL,DE", "LD DE,(#h)", "DB EDh,5Ch", "DB EDh,5Dh", "IM 2", "LD A,R", - "IN H,(C)", "OUT (C),H", "SBC HL,HL", "LD (#h),HL", "DB EDh,64h", "DB EDh,65h", "DB EDh,66h", "RRD", - "IN L,(C)", "OUT (C),L", "ADC HL,HL", "LD HL,(#h)", "DB EDh,6Ch", "DB EDh,6Dh", "DB EDh,6Eh", "RLD", - "IN F,(C)", "DB EDh,71h", "SBC HL,SP", "LD (#h),SP", "DB EDh,74h", "DB EDh,75h", "DB EDh,76h", "DB EDh,77h", - "IN A,(C)", "OUT (C),A", "ADC HL,SP", "LD SP,(#h)", "DB EDh,7Ch", "DB EDh,7Dh", "DB EDh,7Eh", "DB EDh,7Fh", - "DB EDh,80h", "DB EDh,81h", "DB EDh,82h", "DB EDh,83h", "DB EDh,84h", "DB EDh,85h", "DB EDh,86h", "DB EDh,87h", - "DB EDh,88h", "DB EDh,89h", "DB EDh,8Ah", "DB EDh,8Bh", "DB EDh,8Ch", "DB EDh,8Dh", "DB EDh,8Eh", "DB EDh,8Fh", - "DB EDh,90h", "DB EDh,91h", "DB EDh,92h", "DB EDh,93h", "DB EDh,94h", "DB EDh,95h", "DB EDh,96h", "DB EDh,97h", - "DB EDh,98h", "DB EDh,99h", "DB EDh,9Ah", "DB EDh,9Bh", "DB EDh,9Ch", "DB EDh,9Dh", "DB EDh,9Eh", "DB EDh,9Fh", - "LDI", "CPI", "INI", "OUTI", "DB EDh,A4h", "DB EDh,A5h", "DB EDh,A6h", "DB EDh,A7h", - "LDD", "CPD", "IND", "OUTD", "DB EDh,ACh", "DB EDh,ADh", "DB EDh,AEh", "DB EDh,AFh", - "LDIR", "CPIR", "INIR", "OTIR", "DB EDh,B4h", "DB EDh,B5h", "DB EDh,B6h", "DB EDh,B7h", - "LDDR", "CPDR", "INDR", "OTDR", "DB EDh,BCh", "DB EDh,BDh", "DB EDh,BEh", "DB EDh,BFh", - "DB EDh,C0h", "DB EDh,C1h", "DB EDh,C2h", "DB EDh,C3h", "DB EDh,C4h", "DB EDh,C5h", "DB EDh,C6h", "DB EDh,C7h", - "DB EDh,C8h", "DB EDh,C9h", "DB EDh,CAh", "DB EDh,CBh", "DB EDh,CCh", "DB EDh,CDh", "DB EDh,CEh", "DB EDh,CFh", - "DB EDh,D0h", "DB EDh,D1h", "DB EDh,D2h", "DB EDh,D3h", "DB EDh,D4h", "DB EDh,D5h", "DB EDh,D6h", "DB EDh,D7h", - "DB EDh,D8h", "DB EDh,D9h", "DB EDh,DAh", "DB EDh,DBh", "DB EDh,DCh", "DB EDh,DDh", "DB EDh,DEh", "DB EDh,DFh", - "DB EDh,E0h", "DB EDh,E1h", "DB EDh,E2h", "DB EDh,E3h", "DB EDh,E4h", "DB EDh,E5h", "DB EDh,E6h", "DB EDh,E7h", - "DB EDh,E8h", "DB EDh,E9h", "DB EDh,EAh", "DB EDh,EBh", "DB EDh,ECh", "DB EDh,EDh", "DB EDh,EEh", "DB EDh,EFh", - "DB EDh,F0h", "DB EDh,F1h", "DB EDh,F2h", "DB EDh,F3h", "DB EDh,F4h", "DB EDh,F5h", "DB EDh,F6h", "DB EDh,F7h", - "DB EDh,F8h", "DB EDh,F9h", "DB EDh,FAh", "DB EDh,FBh", "DB EDh,FCh", "DB EDh,FDh", "DB EDh,FEh", "DB EDh,FFh" +static char *MnemonicsED[256] = { +/*0/8 1/9 2/A 3/B 4/C 5/D 6/E 7/F */ + "DB EDh,00h", "DB EDh,01h", "DB EDh,02h", "DB EDh,03h", "DB EDh,04h", "DB EDh,05h", "DB EDh,06h", "DB EDh,07h", /* 00-07 */ + "DB EDh,08h", "DB EDh,09h", "DB EDh,0Ah", "DB EDh,0Bh", "DB EDh,0Ch", "DB EDh,0Dh", "DB EDh,0Eh", "DB EDh,0Fh", /* 08-0f */ + "DB EDh,10h", "DB EDh,11h", "DB EDh,12h", "DB EDh,13h", "DB EDh,14h", "DB EDh,15h", "DB EDh,16h", "DB EDh,17h", /* 10-17 */ + "DB EDh,18h", "DB EDh,19h", "DB EDh,1Ah", "DB EDh,1Bh", "DB EDh,1Ch", "DB EDh,1Dh", "DB EDh,1Eh", "DB EDh,1Fh", /* 18-1f */ + "DB EDh,20h", "DB EDh,21h", "DB EDh,22h", "DB EDh,23h", "DB EDh,24h", "DB EDh,25h", "DB EDh,26h", "DB EDh,27h", /* 20-27 */ + "DB EDh,28h", "DB EDh,29h", "DB EDh,2Ah", "DB EDh,2Bh", "DB EDh,2Ch", "DB EDh,2Dh", "DB EDh,2Eh", "DB EDh,2Fh", /* 28-2f */ + "DB EDh,30h", "DB EDh,31h", "DB EDh,32h", "DB EDh,33h", "DB EDh,34h", "DB EDh,35h", "DB EDh,36h", "DB EDh,37h", /* 30-37 */ + "DB EDh,38h", "DB EDh,39h", "DB EDh,3Ah", "DB EDh,3Bh", "DB EDh,3Ch", "DB EDh,3Dh", "DB EDh,3Eh", "DB EDh,3Fh", /* 38-3f */ + "IN B,(C)", "OUT (C),B", "SBC HL,BC", "LD (#h),BC", "NEG", "RETN", "IM 0", "LD I,A", /* 40-47 */ + "IN C,(C)", "OUT (C),C", "ADC HL,BC", "LD BC,(#h)", "DB EDh,4Ch", "RETI", "DB EDh,4Eh", "LD R,A", /* 48-4f */ + "IN D,(C)", "OUT (C),D", "SBC HL,DE", "LD (#h),DE", "DB EDh,54h", "DB EDh,55h", "IM 1", "LD A,I", /* 50-57 */ + "IN E,(C)", "OUT (C),E", "ADC HL,DE", "LD DE,(#h)", "DB EDh,5Ch", "DB EDh,5Dh", "IM 2", "LD A,R", /* 58-5f */ + "IN H,(C)", "OUT (C),H", "SBC HL,HL", "LD (#h),HL", "DB EDh,64h", "DB EDh,65h", "DB EDh,66h", "RRD", /* 60-67 */ + "IN L,(C)", "OUT (C),L", "ADC HL,HL", "LD HL,(#h)", "DB EDh,6Ch", "DB EDh,6Dh", "DB EDh,6Eh", "RLD", /* 68-6f */ + "IN F,(C)", "DB EDh,71h", "SBC HL,SP", "LD (#h),SP", "DB EDh,74h", "DB EDh,75h", "DB EDh,76h", "DB EDh,77h", /* 70-77 */ + "IN A,(C)", "OUT (C),A", "ADC HL,SP", "LD SP,(#h)", "DB EDh,7Ch", "DB EDh,7Dh", "DB EDh,7Eh", "DB EDh,7Fh", /* 78-7f */ + "DB EDh,80h", "DB EDh,81h", "DB EDh,82h", "DB EDh,83h", "DB EDh,84h", "DB EDh,85h", "DB EDh,86h", "DB EDh,87h", /* 80-87 */ + "DB EDh,88h", "DB EDh,89h", "DB EDh,8Ah", "DB EDh,8Bh", "DB EDh,8Ch", "DB EDh,8Dh", "DB EDh,8Eh", "DB EDh,8Fh", /* 88-8f */ + "DB EDh,90h", "DB EDh,91h", "DB EDh,92h", "DB EDh,93h", "DB EDh,94h", "DB EDh,95h", "DB EDh,96h", "DB EDh,97h", /* 90-97 */ + "DB EDh,98h", "DB EDh,99h", "DB EDh,9Ah", "DB EDh,9Bh", "DB EDh,9Ch", "DB EDh,9Dh", "DB EDh,9Eh", "DB EDh,9Fh", /* 98-9f */ + "LDI", "CPI", "INI", "OUTI", "DB EDh,A4h", "DB EDh,A5h", "DB EDh,A6h", "DB EDh,A7h", /* a0-a7 */ + "LDD", "CPD", "IND", "OUTD", "DB EDh,ACh", "DB EDh,ADh", "DB EDh,AEh", "DB EDh,AFh", /* a8-af */ + "LDIR", "CPIR", "INIR", "OTIR", "DB EDh,B4h", "DB EDh,B5h", "DB EDh,B6h", "DB EDh,B7h", /* b0-b7 */ + "LDDR", "CPDR", "INDR", "OTDR", "DB EDh,BCh", "DB EDh,BDh", "DB EDh,BEh", "DB EDh,BFh", /* b8-bf */ + "DB EDh,C0h", "DB EDh,C1h", "DB EDh,C2h", "DB EDh,C3h", "DB EDh,C4h", "DB EDh,C5h", "DB EDh,C6h", "DB EDh,C7h", /* c0-c7 */ + "DB EDh,C8h", "DB EDh,C9h", "DB EDh,CAh", "DB EDh,CBh", "DB EDh,CCh", "DB EDh,CDh", "DB EDh,CEh", "DB EDh,CFh", /* c8-cf */ + "DB EDh,D0h", "DB EDh,D1h", "DB EDh,D2h", "DB EDh,D3h", "DB EDh,D4h", "DB EDh,D5h", "DB EDh,D6h", "DB EDh,D7h", /* d0-d7 */ + "DB EDh,D8h", "DB EDh,D9h", "DB EDh,DAh", "DB EDh,DBh", "DB EDh,DCh", "DB EDh,DDh", "DB EDh,DEh", "DB EDh,DFh", /* d8-df */ + "DB EDh,E0h", "DB EDh,E1h", "DB EDh,E2h", "DB EDh,E3h", "DB EDh,E4h", "DB EDh,E5h", "DB EDh,E6h", "DB EDh,E7h", /* e0-e7 */ + "DB EDh,E8h", "DB EDh,E9h", "DB EDh,EAh", "DB EDh,EBh", "DB EDh,ECh", "DB EDh,EDh", "DB EDh,EEh", "DB EDh,EFh", /* e8-ef */ + "DB EDh,F0h", "DB EDh,F1h", "DB EDh,F2h", "DB EDh,F3h", "DB EDh,F4h", "DB EDh,F5h", "DB EDh,F6h", "DB EDh,F7h", /* f0-f7 */ + "DB EDh,F8h", "DB EDh,F9h", "DB EDh,FAh", "DB EDh,FBh", "DB EDh,FCh", "DB EDh,FDh", "DB EDh,FEh", "DB EDh,FFh" /* f8-ff */ }; -static char *MnemonicsXX[256] = -{ - "NOP", "LD BC,#h", "LD (BC),A", "INC BC", "INC B", "DEC B", "LD B,*h", "RLCA", - "EX AF,AF'", "ADD I%,BC", "LD A,(BC)", "DEC BC", "INC C", "DEC C", "LD C,*h", "RRCA", - "DJNZ @h", "LD DE,#h", "LD (DE),A", "INC DE", "INC D", "DEC D", "LD D,*h", "RLA", - "JR @h", "ADD I%,DE", "LD A,(DE)", "DEC DE", "INC E", "DEC E", "LD E,*h", "RRA", - "JR NZ,@h", "LD I%,#h", "LD (#h),I%", "INC I%", "INC I%h", "DEC I%h", "LD I%h,*h", "DAA", - "JR Z,@h", "ADD I%,I%", "LD I%,(#h)", "DEC I%", "INC I%l", "DEC I%l", "LD I%l,*h", "CPL", - "JR NC,@h", "LD SP,#h", "LD (#h),A", "INC SP", "INC (I%+^h)", "DEC (I%+^h)", "LD (I%+^h),*h", "SCF", - "JR C,@h", "ADD I%,SP", "LD A,(#h)", "DEC SP", "INC A", "DEC A", "LD A,*h", "CCF", - "LD B,B", "LD B,C", "LD B,D", "LD B,E", "LD B,I%h", "LD B,I%l", "LD B,(I%+^h)", "LD B,A", - "LD C,B", "LD C,C", "LD C,D", "LD C,E", "LD C,I%h", "LD C,I%l", "LD C,(I%+^h)", "LD C,A", - "LD D,B", "LD D,C", "LD D,D", "LD D,E", "LD D,I%h", "LD D,I%l", "LD D,(I%+^h)", "LD D,A", - "LD E,B", "LD E,C", "LD E,D", "LD E,E", "LD E,I%h", "LD E,I%l", "LD E,(I%+^h)", "LD E,A", - "LD I%h,B", "LD I%h,C", "LD I%h,D", "LD I%h,E", "LD I%h,I%h", "LD I%h,I%l", "LD H,(I%+^h)", "LD I%h,A", - "LD I%l,B", "LD I%l,C", "LD I%l,D", "LD I%l,E", "LD I%l,I%h", "LD I%l,I%l", "LD L,(I%+^h)", "LD I%l,A", - "LD (I%+^h),B", "LD (I%+^h),C", "LD (I%+^h),D", "LD (I%+^h),E", "LD (I%+^h),H", "LD (I%+^h),L", "HALT", "LD (I%+^h),A", - "LD A,B", "LD A,C", "LD A,D", "LD A,E", "LD A,I%h", "LD A,I%l", "LD A,(I%+^h)", "LD A,A", - "ADD B", "ADD C", "ADD D", "ADD E", "ADD I%h", "ADD I%l", "ADD (I%+^h)", "ADD A", - "ADC B", "ADC C", "ADC D", "ADC E", "ADC I%h", "ADC I%l", "ADC (I%+^h)", "ADC,A", - "SUB B", "SUB C", "SUB D", "SUB E", "SUB I%h", "SUB I%l", "SUB (I%+^h)", "SUB A", - "SBC B", "SBC C", "SBC D", "SBC E", "SBC I%h", "SBC I%l", "SBC (I%+^h)", "SBC A", - "AND B", "AND C", "AND D", "AND E", "AND I%h", "AND I%l", "AND (I%+^h)", "AND A", - "XOR B", "XOR C", "XOR D", "XOR E", "XOR I%h", "XOR I%l", "XOR (I%+^h)", "XOR A", - "OR B", "OR C", "OR D", "OR E", "OR I%h", "OR I%l", "OR (I%+^h)", "OR A", - "CP B", "CP C", "CP D", "CP E", "CP I%h", "CP I%l", "CP (I%+^h)", "CP A", - "RET NZ", "POP BC", "JP NZ,#h", "JP #h", "CALL NZ,#h", "PUSH BC", "ADD *h", "RST 00h", - "RET Z", "RET", "JP Z,#h", "PFX_CB", "CALL Z,#h", "CALL #h", "ADC *h", "RST 08h", - "RET NC", "POP DE", "JP NC,#h", "OUT (*h),A", "CALL NC,#h", "PUSH DE", "SUB *h", "RST 10h", - "RET C", "EXX", "JP C,#h", "IN A,(*h)", "CALL C,#h", "PFX_DD", "SBC *h", "RST 18h", - "RET PO", "POP I%", "JP PO,#h", "EX I%,(SP)", "CALL PO,#h", "PUSH I%", "AND *h", "RST 20h", - "RET PE", "LD PC,I%", "JP PE,#h", "EX DE,I%", "CALL PE,#h", "PFX_ED", "XOR *h", "RST 28h", - "RET P", "POP AF", "JP P,#h", "DI", "CALL P,#h", "PUSH AF", "OR *h", "RST 30h", - "RET M", "LD SP,I%", "JP M,#h", "EI", "CALL M,#h", "PFX_FD", "CP *h", "RST 38h" +static char *MnemonicsXX[256] = { +/*0/8 1/9 2/A 3/B 4/C 5/D 6/E 7/F */ + "NOP", "LD BC,#h", "LD (BC),A", "INC BC", "INC B", "DEC B", "LD B,*h", "RLCA", /* 00-07 */ + "EX AF,AF'", "ADD I%,BC", "LD A,(BC)", "DEC BC", "INC C", "DEC C", "LD C,*h", "RRCA", /* 08-0f */ + "DJNZ $h", "LD DE,#h", "LD (DE),A", "INC DE", "INC D", "DEC D", "LD D,*h", "RLA", /* 10-17 */ + "JR $h", "ADD I%,DE", "LD A,(DE)", "DEC DE", "INC E", "DEC E", "LD E,*h", "RRA", /* 18-1f */ + "JR NZ,$h", "LD I%,#h", "LD (#h),I%", "INC I%", "INC I%h", "DEC I%h", "LD I%h,*h", "DAA", /* 20-27 */ + "JR Z,$h", "ADD I%,I%", "LD I%,(#h)", "DEC I%", "INC I%l", "DEC I%l", "LD I%l,*h", "CPL", /* 28-2f */ + "JR NC,$h", "LD SP,#h", "LD (#h),A", "INC SP", "INC (I%+^h)", "DEC (I%+^h)", "LD (I%+^h),*h", "SCF", /* 30-37 */ + "JR C,$h", "ADD I%,SP", "LD A,(#h)", "DEC SP", "INC A", "DEC A", "LD A,*h", "CCF", /* 38-3f */ + "LD B,B", "LD B,C", "LD B,D", "LD B,E", "LD B,I%h", "LD B,I%l", "LD B,(I%+^h)", "LD B,A", /* 40-47 */ + "LD C,B", "LD C,C", "LD C,D", "LD C,E", "LD C,I%h", "LD C,I%l", "LD C,(I%+^h)", "LD C,A", /* 48-4f */ + "LD D,B", "LD D,C", "LD D,D", "LD D,E", "LD D,I%h", "LD D,I%l", "LD D,(I%+^h)", "LD D,A", /* 50-57 */ + "LD E,B", "LD E,C", "LD E,D", "LD E,E", "LD E,I%h", "LD E,I%l", "LD E,(I%+^h)", "LD E,A", /* 58-5f */ + "LD I%h,B", "LD I%h,C", "LD I%h,D", "LD I%h,E", "LD I%h,I%h", "LD I%h,I%l", "LD H,(I%+^h)", "LD I%h,A", /* 60-67 */ + "LD I%l,B", "LD I%l,C", "LD I%l,D", "LD I%l,E", "LD I%l,I%h", "LD I%l,I%l", "LD L,(I%+^h)", "LD I%l,A", /* 68-6f */ + "LD (I%+^h),B", "LD (I%+^h),C", "LD (I%+^h),D", "LD (I%+^h),E", "LD (I%+^h),H", "LD (I%+^h),L", "HALT", "LD (I%+^h),A", /* 70-77 */ + "LD A,B", "LD A,C", "LD A,D", "LD A,E", "LD A,I%h", "LD A,I%l", "LD A,(I%+^h)", "LD A,A", /* 78-7f */ + "ADD A,B", "ADD A,C", "ADD A,D", "ADD A,E", "ADD A,I%h", "ADD A,I%l", "ADD A,(I%+^h)", "ADD A,A", /* 80-87 */ + "ADC A,B", "ADC A,C", "ADC A,D", "ADC A,E", "ADC A,I%h", "ADC A,I%l", "ADC A,(I%+^h)", "ADC A,A", /* 88-8f */ + "SUB B", "SUB C", "SUB D", "SUB E", "SUB I%h", "SUB I%l", "SUB (I%+^h)", "SUB A", /* 90-97 */ + "SBC A,B", "SBC A,C", "SBC A,D", "SBC A,E", "SBC A,I%h", "SBC A,I%l", "SBC A,(I%+^h)", "SBC A,A", /* 98-9f */ + "AND B", "AND C", "AND D", "AND E", "AND I%h", "AND I%l", "AND (I%+^h)", "AND A", /* a0-a7 */ + "XOR B", "XOR C", "XOR D", "XOR E", "XOR I%h", "XOR I%l", "XOR (I%+^h)", "XOR A", /* a8-af */ + "OR B", "OR C", "OR D", "OR E", "OR I%h", "OR I%l", "OR (I%+^h)", "OR A", /* b0-b7 */ + "CP B", "CP C", "CP D", "CP E", "CP I%h", "CP I%l", "CP (I%+^h)", "CP A", /* b8-bf */ + "RET NZ", "POP BC", "JP NZ,#h", "JP #h", "CALL NZ,#h", "PUSH BC", "ADD A,*h", "RST 00h", /* c8-cf */ + "RET Z", "RET", "JP Z,#h", "PFX_CB", "CALL Z,#h", "CALL #h", "ADC A,*h", "RST 08h", /* c8-cf */ + "RET NC", "POP DE", "JP NC,#h", "OUT (*h),A", "CALL NC,#h", "PUSH DE", "SUB *h", "RST 10h", /* d0-d7 */ + "RET C", "EXX", "JP C,#h", "IN A,(*h)", "CALL C,#h", "PFX_DD", "SBC A,*h", "RST 18h", /* d8-df */ + "RET PO", "POP I%", "JP PO,#h", "EX (SP),I%", "CALL PO,#h", "PUSH I%", "AND *h", "RST 20h", /* e0-e7 */ + "RET PE", "LD PC,I%", "JP PE,#h", "EX DE,I%", "CALL PE,#h", "PFX_ED", "XOR *h", "RST 28h", /* e8-ef */ + "RET P", "POP AF", "JP P,#h", "DI", "CALL P,#h", "PUSH AF", "OR *h", "RST 30h", /* f0-f7 */ + "RET M", "LD SP,I%", "JP M,#h", "EI", "CALL M,#h", "PFX_FD", "CP *h", "RST 38h" /* f8-ff */ }; -static char *MnemonicsXCB[256] = -{ - "RLC B", "RLC C", "RLC D", "RLC E", "RLC H", "RLC L", "RLC (I%@h)", "RLC A", - "RRC B", "RRC C", "RRC D", "RRC E", "RRC H", "RRC L", "RRC (I%@h)", "RRC A", - "RL B", "RL C", "RL D", "RL E", "RL H", "RL L", "RL (I%@h)", "RL A", - "RR B", "RR C", "RR D", "RR E", "RR H", "RR L", "RR (I%@h)", "RR A", - "SLA B", "SLA C", "SLA D", "SLA E", "SLA H", "SLA L", "SLA (I%@h)", "SLA A", - "SRA B", "SRA C", "SRA D", "SRA E", "SRA H", "SRA L", "SRA (I%@h)", "SRA A", - "SLL B", "SLL C", "SLL D", "SLL E", "SLL H", "SLL L", "SLL (I%@h)", "SLL A", - "SRL B", "SRL C", "SRL D", "SRL E", "SRL H", "SRL L", "SRL (I%@h)", "SRL A", - "BIT 0,B", "BIT 0,C", "BIT 0,D", "BIT 0,E", "BIT 0,H", "BIT 0,L", "BIT 0,(I%@h)", "BIT 0,A", - "BIT 1,B", "BIT 1,C", "BIT 1,D", "BIT 1,E", "BIT 1,H", "BIT 1,L", "BIT 1,(I%@h)", "BIT 1,A", - "BIT 2,B", "BIT 2,C", "BIT 2,D", "BIT 2,E", "BIT 2,H", "BIT 2,L", "BIT 2,(I%@h)", "BIT 2,A", - "BIT 3,B", "BIT 3,C", "BIT 3,D", "BIT 3,E", "BIT 3,H", "BIT 3,L", "BIT 3,(I%@h)", "BIT 3,A", - "BIT 4,B", "BIT 4,C", "BIT 4,D", "BIT 4,E", "BIT 4,H", "BIT 4,L", "BIT 4,(I%@h)", "BIT 4,A", - "BIT 5,B", "BIT 5,C", "BIT 5,D", "BIT 5,E", "BIT 5,H", "BIT 5,L", "BIT 5,(I%@h)", "BIT 5,A", - "BIT 6,B", "BIT 6,C", "BIT 6,D", "BIT 6,E", "BIT 6,H", "BIT 6,L", "BIT 6,(I%@h)", "BIT 6,A", - "BIT 7,B", "BIT 7,C", "BIT 7,D", "BIT 7,E", "BIT 7,H", "BIT 7,L", "BIT 7,(I%@h)", "BIT 7,A", - "RES 0,B", "RES 0,C", "RES 0,D", "RES 0,E", "RES 0,H", "RES 0,L", "RES 0,(I%@h)", "RES 0,A", - "RES 1,B", "RES 1,C", "RES 1,D", "RES 1,E", "RES 1,H", "RES 1,L", "RES 1,(I%@h)", "RES 1,A", - "RES 2,B", "RES 2,C", "RES 2,D", "RES 2,E", "RES 2,H", "RES 2,L", "RES 2,(I%@h)", "RES 2,A", - "RES 3,B", "RES 3,C", "RES 3,D", "RES 3,E", "RES 3,H", "RES 3,L", "RES 3,(I%@h)", "RES 3,A", - "RES 4,B", "RES 4,C", "RES 4,D", "RES 4,E", "RES 4,H", "RES 4,L", "RES 4,(I%@h)", "RES 4,A", - "RES 5,B", "RES 5,C", "RES 5,D", "RES 5,E", "RES 5,H", "RES 5,L", "RES 5,(I%@h)", "RES 5,A", - "RES 6,B", "RES 6,C", "RES 6,D", "RES 6,E", "RES 6,H", "RES 6,L", "RES 6,(I%@h)", "RES 6,A", - "RES 7,B", "RES 7,C", "RES 7,D", "RES 7,E", "RES 7,H", "RES 7,L", "RES 7,(I%@h)", "RES 7,A", - "SET 0,B", "SET 0,C", "SET 0,D", "SET 0,E", "SET 0,H", "SET 0,L", "SET 0,(I%@h)", "SET 0,A", - "SET 1,B", "SET 1,C", "SET 1,D", "SET 1,E", "SET 1,H", "SET 1,L", "SET 1,(I%@h)", "SET 1,A", - "SET 2,B", "SET 2,C", "SET 2,D", "SET 2,E", "SET 2,H", "SET 2,L", "SET 2,(I%@h)", "SET 2,A", - "SET 3,B", "SET 3,C", "SET 3,D", "SET 3,E", "SET 3,H", "SET 3,L", "SET 3,(I%@h)", "SET 3,A", - "SET 4,B", "SET 4,C", "SET 4,D", "SET 4,E", "SET 4,H", "SET 4,L", "SET 4,(I%@h)", "SET 4,A", - "SET 5,B", "SET 5,C", "SET 5,D", "SET 5,E", "SET 5,H", "SET 5,L", "SET 5,(I%@h)", "SET 5,A", - "SET 6,B", "SET 6,C", "SET 6,D", "SET 6,E", "SET 6,H", "SET 6,L", "SET 6,(I%@h)", "SET 6,A", - "SET 7,B", "SET 7,C", "SET 7,D", "SET 7,E", "SET 7,H", "SET 7,L", "SET 7,(I%@h)", "SET 7,A" +static char *MnemonicsXCB[256] = { +/*0/8 1/9 2/A 3/B 4/C 5/D 6/E 7/F */ + "RLC B", "RLC C", "RLC D", "RLC E", "RLC H", "RLC L", "RLC (I%@h)", "RLC A", /* 00-07 */ + "RRC B", "RRC C", "RRC D", "RRC E", "RRC H", "RRC L", "RRC (I%@h)", "RRC A", /* 08-0f */ + "RL B", "RL C", "RL D", "RL E", "RL H", "RL L", "RL (I%@h)", "RL A", /* 10-17 */ + "RR B", "RR C", "RR D", "RR E", "RR H", "RR L", "RR (I%@h)", "RR A", /* 18-1f */ + "SLA B", "SLA C", "SLA D", "SLA E", "SLA H", "SLA L", "SLA (I%@h)", "SLA A", /* 20-27 */ + "SRA B", "SRA C", "SRA D", "SRA E", "SRA H", "SRA L", "SRA (I%@h)", "SRA A", /* 28-2f */ + "SLL B", "SLL C", "SLL D", "SLL E", "SLL H", "SLL L", "SLL (I%@h)", "SLL A", /* 30-37 */ + "SRL B", "SRL C", "SRL D", "SRL E", "SRL H", "SRL L", "SRL (I%@h)", "SRL A", /* 38-3f */ + "BIT 0,B", "BIT 0,C", "BIT 0,D", "BIT 0,E", "BIT 0,H", "BIT 0,L", "BIT 0,(I%@h)", "BIT 0,A", /* 40-47 */ + "BIT 1,B", "BIT 1,C", "BIT 1,D", "BIT 1,E", "BIT 1,H", "BIT 1,L", "BIT 1,(I%@h)", "BIT 1,A", /* 48-4f */ + "BIT 2,B", "BIT 2,C", "BIT 2,D", "BIT 2,E", "BIT 2,H", "BIT 2,L", "BIT 2,(I%@h)", "BIT 2,A", /* 50-57 */ + "BIT 3,B", "BIT 3,C", "BIT 3,D", "BIT 3,E", "BIT 3,H", "BIT 3,L", "BIT 3,(I%@h)", "BIT 3,A", /* 58-5f */ + "BIT 4,B", "BIT 4,C", "BIT 4,D", "BIT 4,E", "BIT 4,H", "BIT 4,L", "BIT 4,(I%@h)", "BIT 4,A", /* 60-67 */ + "BIT 5,B", "BIT 5,C", "BIT 5,D", "BIT 5,E", "BIT 5,H", "BIT 5,L", "BIT 5,(I%@h)", "BIT 5,A", /* 68-6f */ + "BIT 6,B", "BIT 6,C", "BIT 6,D", "BIT 6,E", "BIT 6,H", "BIT 6,L", "BIT 6,(I%@h)", "BIT 6,A", /* 70-77 */ + "BIT 7,B", "BIT 7,C", "BIT 7,D", "BIT 7,E", "BIT 7,H", "BIT 7,L", "BIT 7,(I%@h)", "BIT 7,A", /* 78-7f */ + "RES 0,B", "RES 0,C", "RES 0,D", "RES 0,E", "RES 0,H", "RES 0,L", "RES 0,(I%@h)", "RES 0,A", /* 80-87 */ + "RES 1,B", "RES 1,C", "RES 1,D", "RES 1,E", "RES 1,H", "RES 1,L", "RES 1,(I%@h)", "RES 1,A", /* 88-8f */ + "RES 2,B", "RES 2,C", "RES 2,D", "RES 2,E", "RES 2,H", "RES 2,L", "RES 2,(I%@h)", "RES 2,A", /* 90-97 */ + "RES 3,B", "RES 3,C", "RES 3,D", "RES 3,E", "RES 3,H", "RES 3,L", "RES 3,(I%@h)", "RES 3,A", /* 98-9f */ + "RES 4,B", "RES 4,C", "RES 4,D", "RES 4,E", "RES 4,H", "RES 4,L", "RES 4,(I%@h)", "RES 4,A", /* a0-a7 */ + "RES 5,B", "RES 5,C", "RES 5,D", "RES 5,E", "RES 5,H", "RES 5,L", "RES 5,(I%@h)", "RES 5,A", /* a8-af */ + "RES 6,B", "RES 6,C", "RES 6,D", "RES 6,E", "RES 6,H", "RES 6,L", "RES 6,(I%@h)", "RES 6,A", /* b0-b7 */ + "RES 7,B", "RES 7,C", "RES 7,D", "RES 7,E", "RES 7,H", "RES 7,L", "RES 7,(I%@h)", "RES 7,A", /* b8-bf */ + "SET 0,B", "SET 0,C", "SET 0,D", "SET 0,E", "SET 0,H", "SET 0,L", "SET 0,(I%@h)", "SET 0,A", /* c0-c7 */ + "SET 1,B", "SET 1,C", "SET 1,D", "SET 1,E", "SET 1,H", "SET 1,L", "SET 1,(I%@h)", "SET 1,A", /* c8-cf */ + "SET 2,B", "SET 2,C", "SET 2,D", "SET 2,E", "SET 2,H", "SET 2,L", "SET 2,(I%@h)", "SET 2,A", /* d0-d7 */ + "SET 3,B", "SET 3,C", "SET 3,D", "SET 3,E", "SET 3,H", "SET 3,L", "SET 3,(I%@h)", "SET 3,A", /* d8-df */ + "SET 4,B", "SET 4,C", "SET 4,D", "SET 4,E", "SET 4,H", "SET 4,L", "SET 4,(I%@h)", "SET 4,A", /* e0-e7 */ + "SET 5,B", "SET 5,C", "SET 5,D", "SET 5,E", "SET 5,H", "SET 5,L", "SET 5,(I%@h)", "SET 5,A", /* e8-ef */ + "SET 6,B", "SET 6,C", "SET 6,D", "SET 6,E", "SET 6,H", "SET 6,L", "SET 6,(I%@h)", "SET 6,A", /* f0-f7 */ + "SET 7,B", "SET 7,C", "SET 7,D", "SET 7,E", "SET 7,H", "SET 7,L", "SET 7,(I%@h)", "SET 7,A" /* f8-ff */ }; /* Symbolic disassembler @@ -268,36 +277,36 @@ static char *MnemonicsXCB[256] = Inputs: *val = instructions to disassemble useZ80Mnemonics = > 0 iff Z80 mnemonics are to be used + addr = current PC Outputs: *S = output text - + DAsm is Copyright (C) Marat Fayzullin 1995,1996,1997 You are not allowed to distribute this software commercially. */ -int32 DAsm(char *S, uint32 *val, int32 useZ80Mnemonics) -{ +int32 DAsm(char *S, uint32 *val, int32 useZ80Mnemonics, int32 addr) { char R[128], H[10], C= '\0', *T, *P; uint8 J = 0, Offset; uint16 B = 0; if (useZ80Mnemonics) { switch(val[B]) { - case 0xCB: + case 0xcb: B++; T = MnemonicsCB[val[B++]]; break; - case 0xED: + case 0xed: B++; T = MnemonicsED[val[B++]]; break; - case 0xDD: - case 0xFD: - C = (val[B] == 0xDD) ? 'X' : 'Y'; + case 0xdd: + case 0xfd: + C = (val[B] == 0xdd) ? 'X' : 'Y'; B++; - if (val[B] == 0xCB) { + if (val[B] == 0xcb) { B++; Offset = val[B++]; J = 1; @@ -315,8 +324,7 @@ int32 DAsm(char *S, uint32 *val, int32 useZ80Mnemonics) T = Mnemonics8080[val[B++]]; } - if (P = strchr(T, '^')) - { + if (P = strchr(T, '^')) { strncpy(R, T, P - T); R[P - T] = '\0'; sprintf(H, "%02X", val[B++]); @@ -328,7 +336,9 @@ int32 DAsm(char *S, uint32 *val, int32 useZ80Mnemonics) } if (P = strchr(R, '%')) { *P = C; - if (P = strchr(P + 1, '%')) *P = C; + if (P = strchr(P + 1, '%')) { + *P = C; + } } if(P = strchr(R, '*')) { @@ -350,10 +360,18 @@ int32 DAsm(char *S, uint32 *val, int32 useZ80Mnemonics) strcat(S, H); strcat(S, P + 1); } + else if (P = strchr(R, '$')) { + strncpy(S, R, P - R); + S[P - R] = '\0'; + Offset = val[B++]; + sprintf(H, "%04X", addr + 2 + (Offset & 0x80 ? (Offset - 256) : Offset)); + strcat(S, H); + strcat(S, P + 1); + } else if (P = strchr(R, '#')) { strncpy(S, R, P - R); S[P - R] = '\0'; - sprintf(H, "%04X", val[B] + 256*val[B + 1]); + sprintf(H, "%04X", val[B] + 256 * val[B + 1]); strcat(S, H); strcat(S, P + 1); B += 2; @@ -376,23 +394,22 @@ int32 DAsm(char *S, uint32 *val, int32 useZ80Mnemonics) status = error code */ -int32 fprint_sym (FILE *of, int32 addr, uint32 *val, UNIT *uptr, int32 sw) -{ +int32 fprint_sym(FILE *of, int32 addr, uint32 *val, UNIT *uptr, int32 sw) { char disasm[128]; int32 ch = val[0] & 0x7f; - if (sw & (SWMASK ('A') | SWMASK ('C'))) { + if (sw & (SWMASK('A') | SWMASK('C'))) { fprintf(of, ((0x20 <= ch) && (ch < 0x7f)) ? "'%c'" : "%02x", ch); return SCPE_OK; } - if (!(sw & SWMASK ('M'))) { + if (!(sw & SWMASK('M'))) { return SCPE_ARG; } - ch = DAsm(disasm, val, cpu_unit.flags & UNIT_CHIP); + ch = DAsm(disasm, val, cpu_unit.flags & UNIT_CHIP, addr); fprintf(of, "%s", disasm); - return (1-ch); /* need to return additional bytes */ + return 1 - ch; /* need to return additional bytes */ } -/* numString checks determines the base of the number (ch, *numString) +/* numString checks determines the base of the number (ch, *numString) and returns FALSE if the number is bad */ int32 checkbase(char ch, char *numString) { int32 decimal = (ch <= '9'); @@ -431,12 +448,12 @@ int32 numok(char ch, char **numString, int32 minvalue, int32 maxvalue, int32 req if (toupper(ch) != 'H') { (*numString)--; } - *result = value*sign; + *result = value * sign; return (minvalue <= value) && (value <= maxvalue); } int32 match(char *pattern, char *input, char *xy, int32 *number, int32 *star, - int32 *at, int32 *hat) { + int32 *at, int32 *hat, int32 *dollar) { char pat = *pattern++; char inp = *input++; while ((pat) && (inp)) { @@ -490,6 +507,14 @@ int32 match(char *pattern, char *input, char *xy, int32 *number, int32 *star, return FALSE; } break; + case '$': + if (numok(inp, &input, 0, 65535, FALSE, dollar)) { + pattern++; /* skip h */ + } + else { + return FALSE; + } + break; case '^': if (numok(inp, &input, 0, 255, FALSE, hat)) { pattern++; /* skip h */ @@ -512,12 +537,12 @@ int32 match(char *pattern, char *input, char *xy, int32 *number, int32 *star, return (pat == 0) && (inp == 0); } -inline int32 checkXY(char xy) { +INLINE int32 checkXY(char xy) { if (xy == 'X') { - return 0xDD; + return 0xdd; } else if (xy == 'Y') { - return 0xFD; + return 0xfd; } else { printf("X or Y expected.\n"); @@ -527,27 +552,34 @@ inline int32 checkXY(char xy) { int32 parse_X80(char *cptr, int32 addr, uint32 *val, char *Mnemonics[]) { char xy; - int32 op, number, star, at, hat; + int32 op, number, star, at, hat, dollar; for (op = 0; op < 256; op++) { - number = star = at = -129; - if (match(Mnemonics[op], cptr, &xy, &number, &star, &at, &hat)) { + number = star = at = dollar = -129; + if (match(Mnemonics[op], cptr, &xy, &number, &star, &at, &hat, &dollar)) { val[0] = op; if (number >= 0) { val[1] = (0xff) & number; val[2] = (0xff) & (number >> 8); - return (-2); /* two additional bytes returned */ + return -2; /* two additional bytes returned */ } else if (star >= 0) { val[1] = (0xff) & star; - return (-1); /* one additional byte returned */ + return -1; /* one additional byte returned */ } else if (at > -129) { - if (at > 127) { /* assume absolute address is meant */ - at -= addr + 2; /* translate to relative address */ - } - if ((-128 <= at) && (at < 127)) { + if ((-128 <= at) && (at <= 127)) { val[1] = (int8)(at); - return (-1); + return -1; + } + else { + return SCPE_ARG; + } + } + else if (dollar >= 0) { + dollar -= addr + 2; /* relative translation */ + if ((-128 <= dollar) && (dollar <= 127)) { + val[1] = (int8)(dollar); + return -1; /* one additional byte returned */ } else { return SCPE_ARG; @@ -561,35 +593,35 @@ int32 parse_X80(char *cptr, int32 addr, uint32 *val, char *Mnemonics[]) { if (Mnemonics == Mnemonics8080) { return SCPE_ARG; } - + for (op = 0; op < 256; op++) { - if (match(MnemonicsCB[op], cptr, &xy, &number, &star, &at, &hat)) { - val[0] = 0xCB; + if (match(MnemonicsCB[op], cptr, &xy, &number, &star, &at, &hat, &dollar)) { + val[0] = 0xcb; val[1] = op; - return (-1); /* one additional byte returned */ + return -1; /* one additional byte returned */ } } - + for (op = 0; op < 256; op++) { number = -1; - if (match(MnemonicsED[op], cptr, &xy, &number, &star, &at, &hat)) { - val[0] = 0xED; + if (match(MnemonicsED[op], cptr, &xy, &number, &star, &at, &hat, &dollar)) { + val[0] = 0xed; val[1] = op; if (number >= 0) { val[2] = (0xff) & number; val[3] = (0xff) & (number >> 8); - return (-3); /* three additional bytes returned */ + return -3; /* three additional bytes returned */ } else { - return (-1); /* one additional byte returned */ + return -1; /* one additional byte returned */ } } } - + for (op = 0; op < 256; op++) { number = star = hat = -1; xy = ' '; - if (match(MnemonicsXX[op], cptr, &xy, &number, &star, &at, &hat)) { + if (match(MnemonicsXX[op], cptr, &xy, &number, &star, &at, &hat, &dollar)) { if (!(val[0] = checkXY(xy))) { return SCPE_ARG; } @@ -597,35 +629,35 @@ int32 parse_X80(char *cptr, int32 addr, uint32 *val, char *Mnemonics[]) { if (number >= 0) { val[2] = (0xff) & number; val[3] = (0xff) & (number >> 8); - return (-3); /* three additional bytes returned */ + return -3; /* three additional bytes returned */ } else if ((star >= 0) && (hat >= 0)) { val[2] = (0xff) & hat; val[3] = (0xff) & star; - return (-3); /* three additional bytes returned */ + return -3; /* three additional bytes returned */ } else if (star >= 0) { val[2] = (0xff) & star; - return (-2); /* two additional bytes returned */ + return -2; /* two additional bytes returned */ } else if (hat >= 0) { val[2] = (0xff) & hat; - return (-2); /* two additional bytes returned */ + return -2; /* two additional bytes returned */ } else { - return (-1); /* one additional byte returned */ + return -1; /* one additional byte returned */ } } } - + for (op = 0; op < 256; op++) { at = -129; xy = ' '; - if (match(MnemonicsXCB[op], cptr, &xy, &number, &star, &at, &hat)) { + if (match(MnemonicsXCB[op], cptr, &xy, &number, &star, &at, &hat, &dollar)) { if (!(val[0] = checkXY(xy))) { return SCPE_ARG; } - val[1] = 0xCB; + val[1] = 0xcb; if (at > -129) { val[2] = (int8) (at); } @@ -634,7 +666,7 @@ int32 parse_X80(char *cptr, int32 addr, uint32 *val, char *Mnemonics[]) { return SCPE_ARG; } val[3] = op; - return (-3); /* three additional bytes returned */ + return -3; /* three additional bytes returned */ } } return SCPE_ARG; @@ -652,12 +684,11 @@ int32 parse_X80(char *cptr, int32 addr, uint32 *val, char *Mnemonics[]) { Outputs: status = error status */ -int32 parse_sym (char *cptr, int32 addr, UNIT *uptr, uint32 *val, int32 sw) -{ - while (isspace (*cptr)) cptr++; /* absorb spaces */ - if ((sw & (SWMASK ('A') | SWMASK ('C'))) || ((*cptr == '\'') && cptr++)) { /* ASCII char? */ +int32 parse_sym(char *cptr, int32 addr, UNIT *uptr, uint32 *val, int32 sw) { + while (isspace(*cptr)) cptr++; /* absorb spaces */ + if ((sw & (SWMASK('A') | SWMASK('C'))) || ((*cptr == '\'') && cptr++)) { /* ASCII char? */ if (cptr[0] == 0) { - return SCPE_ARG; /* must have 1 char */ + return SCPE_ARG; /* must have one char */ } val[0] = (uint32) cptr[0]; return SCPE_OK; @@ -667,21 +698,45 @@ int32 parse_sym (char *cptr, int32 addr, UNIT *uptr, uint32 *val, int32 sw) } -/* This is the binary loader. The input file is considered to be - a string of literal bytes with no format special format. The - load starts at the current value of the PC. +/* This is the binary loader. The input file is considered to be + a string of literal bytes with no format special format. The + load starts at the current value of the PC. */ -int32 sim_load (FILE *fileref, char *cptr, char *fnam, int32 flag) -{ - int32 i, addr = 0, cnt = 0; - - if ((*cptr != 0) || (flag != 0)) return SCPE_ARG; - addr = saved_PC; - while ((i = getc (fileref)) != EOF) { - M[addr++] = i; - cnt++; - } /* end while */ - printf ("%d Bytes loaded.\n", cnt); - return (SCPE_OK); +int32 sim_load(FILE *fileref, char *cptr, char *fnam, int32 flag) { + int32 i, addr = 0, cnt = 0, org; + t_addr j, lo, hi; + char *result; + t_stat status; + if (flag) { + result = get_range(cptr, &lo, &hi, 16, ADDRMASK, 0); + if (result == NULL) { + return SCPE_ARG; + } + for (j = lo; j <= hi; j++) { + if (putc(GetBYTEWrapper(j), fileref) == EOF) { + return SCPE_IOERR; + } + } + printf("%d Bytes dumped [%x - %x].\n", hi + 1 - lo, lo, hi); + } + else { + if (*cptr == 0) { + addr = saved_PC; + } + else { + addr = get_uint(cptr, 16, ADDRMASK, &status); + if (status != SCPE_OK) { + return status; + } + } + org = addr; + while ((addr < MAXMEMSIZE) && ((i = getc(fileref)) != EOF)) { + PutBYTEWrapper(addr, i); + addr++; + cnt++; + } /* end while */ + printf("%d Bytes loaded at %x.\n", cnt, org); + } + return SCPE_OK; } diff --git a/GRI/gri_cpu.c b/GRI/gri_cpu.c new file mode 100644 index 00000000..26b5dbb9 --- /dev/null +++ b/GRI/gri_cpu.c @@ -0,0 +1,885 @@ +/* gri_cpu.c: GRI-909 CPU simulator + + Copyright (c) 2001-2002, Robert M. Supnik + + Permission is hereby granted, free of charge, to any person obtaining a + copy of this software and associated documentation files (the "Software"), + to deal in the Software without restriction, including without limitation + the rights to use, copy, modify, merge, publish, distribute, sublicense, + and/or sell copies of the Software, and to permit persons to whom the + Software is furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + ROBERT M SUPNIK BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + Except as contained in this notice, the name of Robert M Supnik shall not + be used in advertising or otherwise to promote the sale, use or other dealings + in this Software without prior written authorization from Robert M Supnik. + + The system state for the GRI-909 is: + + AX<0:15> arithmetic input + AY<0:15> arithmetic input + BSW<0:15> byte swapper + BPK<0:15> byte packer + GR[0:5]<0:15> extended general registers + MSR<0:15> machine status register + TRP<0:15> trap register (subroutine return) + SC<0:14> sequence counter + + The GRI-909 has, nominally, just one instruction format: move. + + 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 + +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ + | source | op | destination | move + +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ + + <6:9> operation + + xx1x complement + 01xx add 1 + 10xx rotate left 1 + 11xx rotate right 1 + + In fact, certain of the source and destination operators have side + effects, yielding four additional instruction formats: function out, + skip on function, memory reference, and conditional jump. +*/ + +/* The function out format is: + + 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 + +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ + | 0 0 0 0 1 0| pulse | destination | function out + +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ + + The skip on function format is: + + 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 + +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ + | source | skip |rv| 0 0 0 0 1 0| skip function + +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ + + The memory reference format is (src and/or dst = 006): + + 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 + +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ + | source | op | mode| destination | memory ref + +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ + | address or immediate | + +-----------------------------------------------+ + + <6:9> operation + + xx0x direct, ea = M[SC+1] + xx1x immediate, ea = SC+1 + xxx1 indirect, M[ea] = M[ea]+1, then ea = M[ea] + 01xx add 1 + 10xx rotate left 1 + 11xx rotate right 1 + + The conditional jump format is (src != 006): + + 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 + +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ + | source | cond|rv|df| 0 0 0 0 1 1| cond jump + +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ + | jump address | + +-----------------------------------------------+ + + <6:9> operation + + xxx0 direct, ea = M[SC+1] + xxx1 indirect, ea = M[SC+1], M[ea] = M[ea]+1, + then ea = M[ea] + xx1x reverse conditional sense + x1xx jump if src == 0 + 1xxx jump if src < 0 +*/ + +/* This routine is the instruction decode routine for the GRI-909. + It is called from the simulator control program to execute + instructions in simulated memory, starting at the simulated PC. + It runs until 'reason' is set non-zero. + + General notes: + + 1. Reasons to stop. The simulator can be stopped by: + + HALT instruction + breakpoint encountered + unknown source or destination and STOP_OPR flag set + I/O error in I/O simulator + + 2. Interrupts. The interrupt structure is kept in two parallel variables: + + dev_done device done flags + ISR interrupt status register (enables) + + In addition, there is a master interrupt enable, and a one cycle + interrupt defer, both kept in dev_done. + + 3. Non-existent memory. On the GRI-909, reads to non-existent memory + return zero, and writes are ignored. In the simulator, the + largest possible memory is instantiated and initialized to zero. + Thus, only writes need be checked against actual memory size. + + 4. Adding I/O devices. These modules must be modified: + + gri_defs.h add interrupt request definition + gri_cpu.c add dispatches to dev_tab + gri_sys.c add pointer to data structures to sim_devices +*/ + +#include "gri_defs.h" + +#define SCQ_SIZE 64 /* must be 2**n */ +#define SCQ_MASK (SCQ_SIZE - 1) +#define SCQ_ENTRY scq[scq_p = (scq_p - 1) & SCQ_MASK] = SC +#define UNIT_V_NOEAO (UNIT_V_UF) /* EAO absent */ +#define UNIT_NOEAO (1 << UNIT_V_NOEAO) +#define UNIT_V_MSIZE (UNIT_V_UF + 1) /* dummy mask */ +#define UNIT_MSIZE (1 << UNIT_V_MSIZE) + +uint16 M[MAXMEMSIZE] = { 0 }; /* memory */ +uint32 SC; /* sequence cntr */ +uint32 AX, AY, AO; /* arithmetic unit */ +uint32 IR; /* instr reg */ +uint32 MA; /* memory addr */ +uint32 TRP; /* subr return */ +uint32 MSR; /* machine status */ +uint32 ISR; /* interrupt status */ +uint32 BSW, BPK; /* byte swap, pack */ +uint32 GR[6]; /* extended general regs */ +uint32 SWR; /* switch reg */ +uint32 DR; /* display register */ +uint32 thwh = 0; /* thumbwheel */ +uint32 dev_done = 0; /* device flags */ +uint32 bkp = 0; /* bkpt pending */ +uint32 stop_opr = 1; /* stop ill operator */ +int16 scq[SCQ_SIZE] = { 0 }; /* PC queue */ +int32 scq_p = 0; /* PC queue ptr */ +REG *scq_r = NULL; /* PC queue reg ptr */ +extern int32 sim_interval; +extern int32 sim_int_char; +extern int32 sim_brk_types, sim_brk_dflt, sim_brk_summ; /* breakpoint info */ + +t_stat cpu_ex (t_value *vptr, t_addr addr, UNIT *uptr, int32 sw); +t_stat cpu_dep (t_value val, t_addr addr, UNIT *uptr, int32 sw); +t_stat cpu_reset (DEVICE *dptr); +t_stat cpu_set_size (UNIT *uptr, int32 val, char *cptr, void *desc); +t_stat bus_op (uint32 src, uint32 op, uint32 dst); + +/* Dispatch tables for source, dest, function out, skip on function */ + +uint32 no_rd (uint32 src); +t_stat no_wr (uint32 dst, uint32 val); +t_stat no_fo (uint32 op); +uint32 no_sf (uint32 op); +uint32 zero_rd (uint32 src); +t_stat zero_wr (uint32 dst, uint32 val); +t_stat zero_fo (uint32 op); +uint32 zero_sf (uint32 op); +uint32 ir_rd (uint32 op); +t_stat ir_fo (uint32 op); +uint32 trp_rd (uint32 src); +uint32 isr_rd (uint32 src); +t_stat isr_wr (uint32 dst, uint32 val); +t_stat isr_fo (uint32 op); +uint32 isr_sf (uint32 op); +uint32 ma_rd (uint32 src); +uint32 mem_rd (uint32 src); +t_stat mem_wr (uint32 dst, uint32 val); +uint32 sc_rd (uint32 src); +t_stat sc_wr (uint32 dst, uint32 val); +uint32 swr_rd (uint32 src); +uint32 ax_rd (uint32 src); +t_stat ax_wr (uint32 dst, uint32 val); +uint32 ay_rd (uint32 src); +t_stat ay_wr (uint32 dst, uint32 val); +uint32 ao_rd (uint32 src); +t_stat ao_fo (uint32 op); +uint32 ao_sf (uint32 op); +uint32 ao_update (void); +t_stat eao_fo (uint32 op); +uint32 msr_rd (uint32 src); +t_stat msr_wr (uint32 dst, uint32 val); +uint32 bsw_rd (uint32 src); +t_stat bsw_wr (uint32 dst, uint32 val); +uint32 bpk_rd (uint32 src); +t_stat bpk_wr (uint32 dst, uint32 val); +uint32 gr_rd (uint32 src); +t_stat gr_wr (uint32 dst, uint32 val); + +extern t_stat rtc_fo (uint32 op); +extern uint32 rtc_sf (uint32 op); +extern uint32 hsrp_rd (uint32 src); +extern t_stat hsrp_wr (uint32 dst, uint32 val); +extern t_stat hsrp_fo (uint32 op); +extern uint32 hsrp_sf (uint32 op); +extern uint32 tty_rd (uint32 src); +extern t_stat tty_wr (uint32 dst, uint32 val); +extern t_stat tty_fo (uint32 op); +extern uint32 tty_sf (uint32 op); + +struct gdev dev_tab[64] = { + { &zero_rd, &zero_wr, &zero_fo, &zero_sf }, /* 00: zero */ + { &ir_rd, &zero_wr, &ir_fo, &zero_sf }, /* ir */ + { &no_rd, &no_wr, &no_fo, &no_sf }, /* fo/sf */ + { &trp_rd, &no_wr, &zero_fo, &zero_sf }, /* trp */ + { &isr_rd, &isr_wr, &isr_fo, &isr_sf }, /* isr */ + { &ma_rd, &no_wr, &no_fo, &no_sf }, /* MA */ + { &mem_rd, &mem_wr, &zero_fo, &zero_sf }, /* memory */ + { &sc_rd, &sc_wr, &zero_fo, &zero_sf }, /* sc */ + { &swr_rd, &no_wr, &no_fo, &no_sf }, /* swr */ + { &ax_rd, &ax_wr, &zero_fo, &zero_sf }, /* ax */ + { &ay_rd, &ay_wr, &zero_fo, &zero_sf }, /* ay */ + { &ao_rd, &zero_wr, &ao_fo, &ao_sf }, /* ao */ + { &zero_rd, &zero_wr, &eao_fo, &zero_sf }, /* eao */ + { &no_rd, &no_wr, &no_fo, &no_sf }, + { &no_rd, &no_wr, &no_fo, &no_sf }, + { &msr_rd, &msr_wr, &zero_fo, &zero_sf }, /* msr */ + { &no_rd, &no_wr, &no_fo, &no_sf }, /* 20 */ + { &no_rd, &no_wr, &no_fo, &no_sf }, + { &no_rd, &no_wr, &no_fo, &no_sf }, + { &no_rd, &no_wr, &no_fo, &no_sf }, + { &bsw_rd, &bsw_wr, &no_fo, &no_sf }, /* bsw */ + { &bpk_rd, &bpk_wr, &no_fo, &no_sf }, /* bpk */ + { &no_rd, &no_wr, &no_fo, &no_sf }, + { &no_rd, &no_wr, &no_fo, &no_sf }, + { &gr_rd, &gr_wr, &zero_fo, &zero_sf }, /* 30: gr1 */ + { &gr_rd, &gr_wr, &zero_fo, &zero_sf }, /* gr2 */ + { &gr_rd, &gr_wr, &zero_fo, &zero_sf }, /* gr3 */ + { &gr_rd, &gr_wr, &zero_fo, &zero_sf }, /* gr4 */ + { &gr_rd, &gr_wr, &zero_fo, &zero_sf }, /* gr5 */ + { &gr_rd, &gr_wr, &zero_fo, &zero_sf }, /* gr6 */ + { &no_rd, &no_wr, &no_fo, &no_sf }, + { &no_rd, &no_wr, &no_fo, &no_sf }, + { &no_rd, &no_wr, &no_fo, &no_sf }, /* 40 */ + { &no_rd, &no_wr, &no_fo, &no_sf }, + { &no_rd, &no_wr, &no_fo, &no_sf }, + { &no_rd, &no_wr, &no_fo, &no_sf }, + { &no_rd, &no_wr, &no_fo, &no_sf }, + { &no_rd, &no_wr, &no_fo, &no_sf }, + { &no_rd, &no_wr, &no_fo, &no_sf }, + { &no_rd, &no_wr, &no_fo, &no_sf }, + { &no_rd, &no_wr, &no_fo, &no_sf }, /* 50 */ + { &no_rd, &no_wr, &no_fo, &no_sf }, + { &no_rd, &no_wr, &no_fo, &no_sf }, + { &no_rd, &no_wr, &no_fo, &no_sf }, + { &no_rd, &no_wr, &no_fo, &no_sf }, + { &no_rd, &no_wr, &no_fo, &no_sf }, + { &no_rd, &no_wr, &no_fo, &no_sf }, + { &no_rd, &no_wr, &no_fo, &no_sf }, + { &no_rd, &no_wr, &no_fo, &no_sf }, /* 60 */ + { &no_rd, &no_wr, &no_fo, &no_sf }, + { &no_rd, &no_wr, &no_fo, &no_sf }, + { &no_rd, &no_wr, &no_fo, &no_sf }, + { &no_rd, &no_wr, &no_fo, &no_sf }, + { &no_rd, &no_wr, &no_fo, &no_sf }, + { &no_rd, &no_wr, &no_fo, &no_sf }, + { &no_rd, &no_wr, &no_fo, &no_sf }, + { &no_rd, &no_wr, &no_fo, &no_sf }, /* 70 */ + { &no_rd, &no_wr, &no_fo, &no_sf }, + { &no_rd, &no_wr, &no_fo, &no_sf }, + { &no_rd, &no_wr, &no_fo, &no_sf }, + { &no_rd, &no_wr, &no_fo, &no_sf }, + { &zero_rd, &zero_wr, &rtc_fo, &rtc_sf }, /* rtc */ + { &hsrp_rd, &hsrp_wr, &hsrp_fo, &hsrp_sf }, /* hsrp */ + { &tty_rd, &tty_wr, &tty_fo, &tty_sf } }; /* tty */ + +static const int32 vec_map[16] = { + VEC_TTO, VEC_TTI, VEC_HSP, VEC_HSR, + -1, -1, -1, -1, + -1, -1, -1, VEC_RTC, + -1, -1, -1, -1 }; + +/* CPU data structures + + cpu_dev CPU device descriptor + cpu_unit CPU unit descriptor + cpu_reg CPU register list + cpu_mod CPU modifiers list +*/ + +UNIT cpu_unit = { UDATA (NULL, UNIT_FIX + UNIT_BINK, MAXMEMSIZE) }; + +REG cpu_reg[] = { + { ORDATA (SC, SC, 15) }, + { ORDATA (AX, AX, 16) }, + { ORDATA (AY, AY, 16) }, + { ORDATA (AO, AO, 16), REG_RO }, + { ORDATA (TRP, TRP, 16) }, + { ORDATA (MSR, MSR, 16) }, + { ORDATA (ISR, ISR, 16) }, + { ORDATA (BSW, BSW, 16) }, + { ORDATA (BPK, BPK, 16) }, + { ORDATA (GR1, GR[0], 16) }, + { ORDATA (GR2, GR[1], 16) }, + { ORDATA (GR3, GR[2], 16) }, + { ORDATA (GR4, GR[3], 16) }, + { ORDATA (GR5, GR[4], 16) }, + { ORDATA (GR6, GR[5], 16) }, + { FLDATA (BOV, MSR, MSR_V_BOV) }, + { FLDATA (L, MSR, MSR_V_L) }, + { GRDATA (FOA, MSR, 8, 2, MSR_V_FOA) }, + { FLDATA (AOV, MSR, MSR_V_AOV) }, + { ORDATA (IR, IR, 16), REG_RO }, + { ORDATA (MA, MA, 16), REG_RO }, + { ORDATA (SWR, SWR, 16) }, + { ORDATA (DR, DR, 16) }, + { ORDATA (THW, thwh, 6) }, + { ORDATA (IREQ, dev_done, INT_V_NODEF) }, + { FLDATA (ION, dev_done, INT_V_ON) }, + { FLDATA (INODEF, dev_done, INT_V_NODEF) }, + { FLDATA (BKP, bkp, 0) }, + { BRDATA (SCQ, scq, 8, 15, SCQ_SIZE), REG_RO+REG_CIRC }, + { ORDATA (SCQP, scq_p, 6), REG_HRO }, + { FLDATA (NOEAO, cpu_unit.flags, UNIT_V_NOEAO), REG_HRO }, + { FLDATA (STOP_OPR, stop_opr, 0) }, + { ORDATA (WRU, sim_int_char, 8) }, + { NULL } }; + +MTAB cpu_mod[] = { + { UNIT_NOEAO, UNIT_NOEAO, "no EAO", "NOEAO", NULL }, + { UNIT_NOEAO, 0, "EAO", "EAO", NULL }, + { UNIT_MSIZE, 4096, NULL, "4K", &cpu_set_size }, + { UNIT_MSIZE, 8192, NULL, "8K", &cpu_set_size }, + { UNIT_MSIZE, 12288, NULL, "12K", &cpu_set_size }, + { UNIT_MSIZE, 16384, NULL, "16K", &cpu_set_size }, + { UNIT_MSIZE, 20480, NULL, "20K", &cpu_set_size }, + { UNIT_MSIZE, 24576, NULL, "24K", &cpu_set_size }, + { UNIT_MSIZE, 28672, NULL, "28K", &cpu_set_size }, + { UNIT_MSIZE, 32768, NULL, "32K", &cpu_set_size }, + { 0 } }; + +DEVICE cpu_dev = { + "CPU", &cpu_unit, cpu_reg, cpu_mod, + 1, 8, 15, 1, 8, 16, + &cpu_ex, &cpu_dep, &cpu_reset, + NULL, NULL, NULL }; + +t_stat sim_instr (void) +{ +uint32 src, dst, op, t, jmp; +t_stat reason; +extern UNIT rtc_unit; + +/* Restore register state */ + +SC = SC & AMASK; /* load local PC */ +reason = 0; +AO = ao_update (); /* update AO */ +sim_rtc_init (rtc_unit.wait); /* init calibration */ + +/* Main instruction fetch/decode loop */ + +while (reason == 0) { /* loop until halted */ + +if (sim_interval <= 0) { /* check clock queue */ + if (reason = sim_process_event ()) break; } + +if (bkp) { /* breakpoint? */ + bkp = 0; /* clear request */ + dev_done = dev_done & ~INT_ON; /* int off */ + M[VEC_BKP] = SC; /* save SC */ + SC = VEC_BKP + 1; } /* new SC */ + +else if ((dev_done & (INT_PENDING | ISR)) > (INT_PENDING)) { /* intr? */ + int32 i, vec; + t = dev_done & ISR; /* find hi pri */ + for (i = 15; i >= 0; i--) { + if ((t >> i) & 1) break; } + if ((i < 0) || ((vec = vec_map[i]) < 0)) { /* undefined? */ + reason = STOP_ILLINT; /* stop */ + break; } + dev_done = dev_done & ~INT_ON; /* int off */ + M[vec] = SC; /* save SC */ + SC = vec + 1; /* new SC */ + continue; } + +if (sim_brk_summ && sim_brk_test (SC, SWMASK ('E'))) { /* breakpoint? */ + reason = STOP_IBKPT; /* stop simulation */ + break; } + +MA = SC; /* set mem addr */ +IR = M[MA]; /* fetch instr */ +dev_done = dev_done | INT_NODEF; /* clr ion defer */ +sim_interval = sim_interval - 1; + +/* Decode instruction types */ + +src = I_GETSRC (IR); /* src unit */ +dst = I_GETDST (IR); /* dst unit */ +op = I_GETOP (IR); /* bus op */ + +if (src == U_FSK) { /* func out? */ + reason = dev_tab[dst].FO (op); /* send function */ + SC = (SC + 1) & AMASK; } /* incr SC */ + +else if (dst == U_FSK) { /* skip func? */ + t = dev_tab[src].SF (op & ~1); /* issue SF */ + reason = t >> SF_V_REASON; + if ((t ^ op) & 1) SC = SC + 2; /* skip? */ + SC = (SC + 1) & AMASK; } /* incr SC */ + +else if ((src != U_MEM) && (dst == U_TRP)) { /* cond jump */ + t = dev_tab[src].Src (src); /* get source */ + switch (op >> 1) { /* case on jump */ + case 00: /* never */ + jmp = 0; + break; + case 01: /* always */ + jmp = 1; + break; + case 02: /* src == 0 */ + jmp = (t == 0); + break; + case 03: /* src != 0 */ + jmp = (t != 0); + break; + case 04: /* src < 0 */ + jmp = (t >= SIGN); + break; + case 05: /* src >= 0 */ + jmp = (t < SIGN); + break; + case 06: + jmp = (t == 0) || (t & SIGN); /* src <= 0 */ + break; + case 07: + jmp = (t != 0) && !(t & SIGN); /* src > 0 */ + break; } + if (jmp) { /* jump taken? */ + SCQ_ENTRY; /* save SC */ + SC = (SC + 1) & AMASK; /* incr SC once */ + MA = M[SC]; /* get jump addr */ + if (op & TRP_DEF) { /* defer? */ + t = (M[MA] + 1) & DMASK; /* autoinc */ + if (MEM_ADDR_OK (MA)) M[MA] = t; + MA = t & AMASK; } /* ind addr */ + TRP = SC; /* save SC */ + SC = MA; } /* load new SC */ + else SC = (SC + 2) & AMASK; } /* incr SC twice */ + +else if ((src != U_MEM) && (dst != U_MEM)) { /* reg-reg? */ + reason = bus_op (src, op, dst); /* xmt and modify */ + SC = (SC + 1) & AMASK; } /* incr SC */ + +/* Memory reference. The second SC increment occurs after the first + execution cycle. For direct, defer, and immediate defer, this is + after the first memory read and before the bus transfer; but for + immediate, it is before the bus transfer. +*/ + +else { SC = (SC + 1) & AMASK; /* incr SC */ + switch (op & MEM_MOD) { /* case on addr mode */ + case MEM_DIR: /* direct */ + MA = M[SC] & AMASK; /* get address */ + SC = (SC + 1) & AMASK; /* incr SC again */ + reason = bus_op (src, op & BUS_FNC, dst); /* xmt and modify */ + break; + case MEM_DEF: /* defer */ + MA = M[SC] & AMASK; /* get ind addr */ + SC = (SC + 1) & AMASK; /* incr SC again */ + t = (M[MA] + 1) & DMASK; /* autoinc */ + if (MEM_ADDR_OK (MA)) M[MA] = t; + MA = t & AMASK; /* ind addr */ + reason = bus_op (src, op & BUS_FNC, dst); /* xmt and modify */ + break; + case MEM_IMM: /* immediate */ + MA = SC; /* eff addr */ + reason = bus_op (src, op & BUS_FNC, dst); /* xmt and modify */ + SC = (SC + 1) & AMASK; /* incr SC again */ + break; + case MEM_IDF: /* immediate defer */ + MA = SC; /* get ind addr */ + t = (M[MA] + 1) & DMASK; /* autoinc */ + if (MEM_ADDR_OK (MA)) M[MA] = t; + MA = t & AMASK; /* ind addr */ + SC = (SC + 1) & AMASK; /* incr SC again */ + reason = bus_op (src, op & BUS_FNC, dst); /* xmt and modify */ + break; } /* end switch */ + } /* end mem ref */ +} /* end while */ + +/* Simulation halted */ + +AO = ao_update (); /* update AO */ +return reason; +} + +/* Bus operations */ + +t_stat bus_op (uint32 src, uint32 op, uint32 dst) +{ +uint32 t, old_t; + +t = dev_tab[src].Src (src); /* get src */ +if (op & BUS_COM) t = t ^ DMASK; /* complement? */ +switch (op & BUS_FNC) { /* case op */ +case BUS_P1: /* plus 1 */ + t = t + 1; /* do add */ + if (t & CBIT) MSR = MSR | MSR_BOV; /* set cry out */ + else MSR = MSR & ~MSR_BOV; + break; +case BUS_L1: /* left 1 */ + t = (t << 1) | ((MSR & MSR_L)? 1: 0); /* rotate */ + if (t & CBIT) MSR = MSR | MSR_L; /* set link out */ + else MSR = MSR & ~MSR_L; + break; +case BUS_R1: /* right 1 */ + old_t = t; + t = (t >> 1) | ((MSR & MSR_L)? SIGN: 0); /* rotate */ + if (old_t & 1) MSR = MSR | MSR_L; /* set link out */ + else MSR = MSR & ~MSR_L; + break; } /* end case op */ +if (dst == thwh) DR = t & DMASK; /* display dst? */ +return dev_tab[dst].Dst (dst, t & DMASK); /* store dst */ +} + +/* Non-existent device */ + +uint32 no_rd (uint32 src) +{ +return 0; +} + +t_stat no_wr (uint32 dst, uint32 dat) +{ +return stop_opr; +} + +t_stat no_fo (uint32 fnc) +{ +return stop_opr; +} + +uint32 no_sf (uint32 fnc) +{ +return (stop_opr << SF_V_REASON); +} + +/* Zero device */ + +uint32 zero_rd (uint32 src) +{ +return 0; +} + +t_stat zero_wr (uint32 dst, uint32 val) +{ +return SCPE_OK; +} + +t_stat zero_fo (uint32 op) +{ +switch (op & 3) { /* FOM link */ +case 1: /* CLL */ + MSR = MSR & ~MSR_L; + break; +case 2: /* STL */ + MSR = MSR | MSR_L; + break; +case 3: /* CML */ + MSR = MSR ^ MSR_L; + break; } +if (op & 4) return STOP_HALT; /* HALT */ +return SCPE_OK; +} + +uint32 zero_sf (uint32 op) +{ +if ((op & 010) || /* power always ok */ + ((op & 4) && (MSR & MSR_L)) || /* link set? */ + ((op & 2) && (MSR & MSR_BOV))) return 1; /* BOV set? */ +return 0; +} + +/* Instruction register (01) */ + +uint32 ir_rd (uint32 src) +{ +return IR; +} + +t_stat ir_fo (uint32 op) +{ +if (op & 2) bkp = 1; +return SCPE_OK; +} + +/* Trap register (03) */ + +uint32 trp_rd (uint32 src) +{ +return TRP; +} + +/* Interrupt status register (04) */ + +uint32 isr_rd (uint32 src) +{ +return ISR; +} + +t_stat isr_wr (uint32 dst, uint32 dat) +{ +ISR = dat; +return SCPE_OK; +} + +t_stat isr_fo (uint32 op) +{ +if (op & ISR_ON) dev_done = (dev_done | INT_ON) & ~INT_NODEF; +if (op & ISR_OFF) dev_done = dev_done & ~INT_ON; +return SCPE_OK; +} + +uint32 isr_sf (uint32 op) +{ +return 0; +} + +/* Memory address (05) */ + +uint32 ma_rd (uint32 src) +{ +return MA; +} + +/* Memory (06) */ + +uint32 mem_rd (uint32 src) +{ +return M[MA]; +} + +t_stat mem_wr (uint32 dst, uint32 dat) +{ + +if (MEM_ADDR_OK (MA)) M[MA] = dat; +return SCPE_OK; +} + +/* Sequence counter (07) */ + +uint32 sc_rd (uint32 src) +{ +return SC; +} + +t_stat sc_wr (uint32 dst, uint32 dat) +{ +SCQ_ENTRY; +SC = dat & AMASK; +return SCPE_OK; +} + +/* Switch register (10) */ + +uint32 swr_rd (uint32 src) +{ +return SWR; +} + +/* Machine status register (17) */ + +uint32 msr_rd (uint32 src) +{ +return MSR; +} + +t_stat msr_wr (uint32 src, uint32 dat) +{ +MSR = dat; /* new MSR */ +ao_update (); /* update AOV */ +return SCPE_OK; +} + +/* Arithmetic operators (11:14) */ + +uint32 ao_update (void) +{ +int32 t; +int32 af = MSR_GET_FOA (MSR); + +switch (af) { +case AO_ADD: + t = (AX + AY) & DMASK; /* add */ + break; +case AO_AND: + t = AX & AY; /* and */ + break; +case AO_XOR: /* xor */ + t = AX ^ AY; + break; +case AO_IOR: + t = AX | AY; /* or */ + break; } +if ((AX + AY) & CBIT) MSR = MSR | MSR_AOV; /* always calc AOV */ +else MSR = MSR & ~MSR_AOV; +return t; +} + +uint32 ax_rd (uint32 src) +{ +return AX; +} + +t_stat ax_wr (uint32 dst, uint32 dat) +{ +AX = dat; +return SCPE_OK; +} + +uint32 ay_rd (uint32 src) +{ +return AY; +} + +t_stat ay_wr (uint32 dst, uint32 dat) +{ +AY = dat; +return SCPE_OK; +} + +uint32 ao_rd (uint32 src) +{ +AO = ao_update (); +return AO; +} + +t_stat ao_fo (uint32 op) +{ +uint32 t = OP_GET_FOA (op); /* get func */ +MSR = MSR_PUT_FOA (MSR, t); /* store in MSR */ +ao_update (); /* update AOV */ +return SCPE_OK; +} + +t_stat eao_fo (uint32 op) +{ +uint32 t; + +if (cpu_unit.flags & UNIT_NOEAO) return stop_opr; /* EAO installed? */ +if (op == EAO_MUL) { /* mul? */ + t = AX * AY; /* AX * AY */ + AX = (t >> 16) & DMASK; /* to AX'GR1 */ + GR[0] = t & DMASK; } +if (op == EAO_DIV) { /* div? */ + if (AY && (AX < AY)) { + t = (AX << 16) | GR[0]; /* AX'GR1 / AY */ + GR[0] = t / AY; /* quo to GR1 */ + AX = t % AY; } /* rem to AX */ + } +return SCPE_OK; +} + +uint32 ao_sf (uint32 op) +{ +if (((op & 2) && (MSR & MSR_AOV)) || /* arith carry? */ + ((op & 4) && (SIGN & /* arith overflow? */ + ((AX ^ (AX + AY)) & (~AX ^ AY))))) return 1; +return 0; +} + +/* Byte swapper (24) */ + +uint32 bsw_rd (uint32 src) +{ +return BSW; +} + +t_stat bsw_wr (uint32 dst, uint32 val) +{ +BSW = ((val >> 8) & 0377) | ((val & 0377) << 8); +return SCPE_OK; +} + +/* Byte packer (25) */ + +uint32 bpk_rd (uint32 src) +{ +return BPK; +} + +t_stat bpk_wr (uint32 dst, uint32 val) +{ +BPK = ((BPK & 0377) << 8) | (val & 0377); +return SCPE_OK; +} + +/* General registers (30:35) */ + +uint32 gr_rd (uint32 src) +{ +return GR[src - U_GR]; +} + +t_stat gr_wr (uint32 dst, uint32 dat) +{ +GR[dst - U_GR] = dat; +return SCPE_OK; +} + +/* Reset routine */ + +t_stat cpu_reset (DEVICE *dptr) +{ +int32 i; + +AX = AY = AO = 0; +TRP = 0; +ISR = 0; +MSR = 0; +MA = IR = 0; +BSW = BPK = 0; +for (i = 0; i < 6; i++) GR[i] = 0; +dev_done = dev_done & ~INT_PENDING; +scq_r = find_reg ("SCQ", NULL, dptr); +if (scq_r) scq_r -> qptr = 0; +else return SCPE_IERR; +sim_brk_types = sim_brk_dflt = SWMASK ('E'); +return SCPE_OK; +} + +/* Memory examine */ + +t_stat cpu_ex (t_value *vptr, t_addr addr, UNIT *uptr, int32 sw) +{ +if (addr >= MEMSIZE) return SCPE_NXM; +if (vptr != NULL) *vptr = M[addr] & DMASK; +return SCPE_OK; +} + +/* Memory deposit */ + +t_stat cpu_dep (t_value val, t_addr addr, UNIT *uptr, int32 sw) +{ +if (addr >= MEMSIZE) return SCPE_NXM; +M[addr] = val & DMASK; +return SCPE_OK; +} + +t_stat cpu_set_size (UNIT *uptr, int32 val, char *cptr, void *desc) +{ +int32 mc = 0; +t_addr i; + +if ((val <= 0) || (val > MAXMEMSIZE) || ((val & 07777) != 0)) + return SCPE_ARG; +for (i = val; i < MEMSIZE; i++) mc = mc | M[i]; +if ((mc != 0) && (!get_yn ("Really truncate memory [N]?", FALSE))) + return SCPE_OK; +MEMSIZE = val; +for (i = MEMSIZE; i < MAXMEMSIZE; i++) M[i] = 0; +return SCPE_OK; +} diff --git a/GRI/gri_defs.h b/GRI/gri_defs.h new file mode 100644 index 00000000..4e211075 --- /dev/null +++ b/GRI/gri_defs.h @@ -0,0 +1,218 @@ +/* gri_defs.h: GRI-909 simulator definitions + + Copyright (c) 2001-2002, Robert M. Supnik + + Permission is hereby granted, free of charge, to any person obtaining a + copy of this software and associated documentation files (the "Software"), + to deal in the Software without restriction, including without limitation + the rights to use, copy, modify, merge, publish, distribute, sublicense, + and/or sell copies of the Software, and to permit persons to whom the + Software is furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + ROBERT M SUPNIK BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + Except as contained in this notice, the name of Robert M Supnik shall not + be used in advertising or otherwise to promote the sale, use or other dealings + in this Software without prior written authorization from Robert M Supnik. + + There are several discrepancies between the original GRI-909 Reference + Manual of 1969 and the only surviving code sample, the MIT Crystal Growing + System of 1972: + + 1. Ref Manual documents two GR's at codes 26-27; MITCS documents six GR's + at 30-35. + 2. Ref Manual documents only unsigned overflow (carry) for arithmetic + operator; MITCS uses both unsigned overflow (AOV) and signed overflow + (SOV). + 3. Ref Manual documents a ROM-subroutine multiply operator and mentions + but does not document a "fast multiply"; MITCS uses an extended + arithmetic operator with multiply, divide, and shifts. The behavior + of the extended arithmetic operator can only be inferred partially; + the shifts are never used, and there is no indication of how divide + overflow is handled. + + The simulator follows the code in these instances. + + Outstanding issues: + + 1. Is there any interaction between the byte swapper and the byte packer? + 2. Is SOV testable even if the FOA is not ADD? + 3. How does the EAO handle divide overflow? + 4. What are the other EAO functions beside multiply and divide? +*/ + +#include "sim_defs.h" /* simulator defns */ + +/* Simulator stop codes */ + +#define STOP_DEV 1 /* must be 1 */ +#define STOP_HALT 2 /* HALT */ +#define STOP_IBKPT 3 /* breakpoint */ +#define STOP_ILLINT 4 /* illegal intr */ + +/* Memory */ + +#define MAXMEMSIZE 32768 /* max memory size */ +#define AMASK 077777 /* logical addr mask */ +#define MEMSIZE (cpu_unit.capac) /* actual memory size */ +#define MEM_ADDR_OK(x) (((t_addr) (x)) < MEMSIZE) + +/* Architectural constants */ + +#define SIGN 0100000 /* sign */ +#define DMASK 0177777 /* data mask */ +#define CBIT (DMASK + 1) /* carry bit */ + +/* Instruction format */ + +#define I_M_SRC 077 /* source */ +#define I_V_SRC 10 +#define I_GETSRC(x) (((x) >> I_V_SRC) & I_M_SRC) +#define I_M_OP 017 /* operator */ +#define I_V_OP 6 +#define I_GETOP(x) (((x) >> I_V_OP) & I_M_OP) +#define I_M_DST 077 /* destination */ +#define I_V_DST 0 +#define I_GETDST(x) (((x) >> I_V_DST) & I_M_DST) +#define SF_V_REASON 1 /* SF reason */ + +/* IO return */ + +#define IORETURN(f,v) ((f)? (v): SCPE_OK) /* stop on error */ + +/* Operators */ + +#define U_ZERO 000 /* zero */ +#define U_IR 001 /* instruction reg */ +#define U_FSK 002 /* func out/skip */ +#define U_TRP 003 /* trap */ +#define U_ISR 004 /* intr status */ +#define U_MA 005 /* mem addr */ +#define U_MEM 006 /* mem data */ +#define U_SC 007 /* seq counter */ +#define U_SWR 010 /* switch register */ +#define U_AX 011 /* arith in 1 */ +#define U_AY 012 /* arith in 2 */ +#define U_AO 013 /* arith out */ +#define U_EAO 014 /* ext arith */ +#define U_MSR 017 /* machine status */ +#define U_BSW 024 /* byte swap */ +#define U_BPK 025 /* byte pack */ +/* #define U_GR 026 /* dual general regs */ +#define U_GR 030 /* hex general regs */ +#define U_RTC 075 /* clock */ +#define U_HS 076 /* paper tape */ +#define U_TTY 077 /* console */ + +struct gdev { + int32 (*Src)(); /* source */ + t_stat (*Dst)(); /* dest */ + t_stat (*FO)(); /* func out */ + int32 (*SF)(); /* skip func */ +}; + +/* Trap (jump) */ + +#define TRP_DIR 00 /* direct */ +#define TRP_DEF 01 /* defer */ + +/* Interrupt status */ + +#define ISR_OFF 01 /* int off */ +#define ISR_ON 02 /* int on */ + +/* Bus modifiers */ + +#define BUS_COM 002 /* complement */ +#define BUS_FNC 014 /* function mask */ +#define BUS_P1 004 /* + 1 */ +#define BUS_L1 010 /* rotate left */ +#define BUS_R1 014 /* rotate right */ + +/* Memory address modes */ + +#define MEM_MOD 03 +#define MEM_DIR 00 /* direct */ +#define MEM_DEF 01 /* defer */ +#define MEM_IMM 02 /* immediate */ +#define MEM_IDF 03 /* immediate defer */ + +/* Arithmetic unit */ + +#define FO_V_FOA 8 /* arith func */ +#define FO_M_FOA 03 +#define OP_GET_FOA(x) (((x) >> (FO_V_FOA - I_V_OP)) & FO_M_FOA) +#define AO_ADD 00 /* add */ +#define AO_AND 01 /* and */ +#define AO_XOR 02 /* xor */ +#define AO_IOR 03 /* or */ +#define EAO_MUL 01 /* multiply */ +#define EAO_DIV 02 /* divide */ +#define EAO_ASR 03 /* arith rshft */ + +/* Machine status */ + +#define MSR_V_BOV 15 /* bus carry */ +#define MSR_BOV (1u << MSR_V_BOV) +#define MSR_V_L 14 /* bus link */ +#define MSR_L (1u << MSR_V_L) /* bus link */ +#define MSR_V_FOA 8 /* arith func */ +#define MSR_M_FOA 03 +#define MSR_V_AOV 0 /* arith carry */ +#define MSR_AOV (1u << MSR_V_AOV) +#define MSR_GET_FOA(x) (((x) >> MSR_V_FOA) & MSR_M_FOA) +#define MSR_PUT_FOA(x,n) (((x) & ~(MSR_M_FOA << MSR_V_FOA)) | \ + (((n) & MSR_M_FOA) << MSR_V_FOA)) + +/* Real time clock */ + +#define RTC_OFF 001 /* off */ +#define RTC_ON 002 /* clock on */ +#define RTC_OV 010 /* clock flag */ +#define RTC_CTR 0103 /* counter */ + +/* Terminal */ + +#define TTY_ORDY 002 /* output flag */ +#define TTY_IRDY 010 /* input flag */ + +/* Paper tape */ + +#define PT_STRT 001 /* start reader */ +#define PT_ORDY 002 /* output flag */ +#define PT_IRDY 010 /* input flag */ + +/* Interrupt masks (ISR) */ + +#define INT_V_TTO 0 /* console out */ +#define INT_V_TTI 1 /* console in */ +#define INT_V_HSP 2 /* paper tape punch */ +#define INT_V_HSR 3 /* paper tape reader */ +#define INT_V_RTC 11 /* clock */ +#define INT_V_NODEF 16 /* nodefer */ +#define INT_V_ON 17 /* enable */ +#define INT_TTO (1u << INT_V_TTO) +#define INT_TTI (1u << INT_V_TTI) +#define INT_HSP (1u << INT_V_HSP) +#define INT_HSR (1u << INT_V_HSR) +#define INT_RTC (1u << INT_V_RTC) +#define INT_NODEF (1u << INT_V_NODEF) +#define INT_ON (1u << INT_V_ON) +#define INT_PENDING (INT_ON | INT_NODEF) + +/* Vectors */ + +#define VEC_BKP 0000 /* breakpoint */ +#define VEC_TTO 0011 /* console out */ +#define VEC_TTI 0014 /* console in */ +#define VEC_HSP 0017 /* paper tape punch */ +#define VEC_HSR 0022 /* paper tape reader */ +#define VEC_RTC 0100 /* clock */ diff --git a/GRI/gri_doc.txt b/GRI/gri_doc.txt new file mode 100644 index 00000000..626453e1 --- /dev/null +++ b/GRI/gri_doc.txt @@ -0,0 +1,307 @@ +To: Users +From: Bob Supnik +Subj: GRI-909 Simulator Usage +Date: 15-Jul-02 + + COPYRIGHT NOTICE + +The following copyright notice applies to both the SIMH source and binary: + + Original code published in 1993-2002, written by Robert M Supnik + Copyright (c) 1993-2002, Robert M Supnik + + Permission is hereby granted, free of charge, to any person obtaining a + copy of this software and associated documentation files (the "Software"), + to deal in the Software without restriction, including without limitation + the rights to use, copy, modify, merge, publish, distribute, sublicense, + and/or sell copies of the Software, and to permit persons to whom the + Software is furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + ROBERT M SUPNIK BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + Except as contained in this notice, the name of Robert M Supnik shall not + be used in advertising or otherwise to promote the sale, use or other dealings + in this Software without prior written authorization from Robert M Supnik. + +This memorandum documents the GRI-909 simulator. + + +1. Simulator Files + +sim/ sim_defs.h + scp.c + scp_tty.c + sim_rev.c + +sim/gri/ gri_defs.h + gri_cpu.c + gri_stddev.c + gri_sys.c + +2. GRI-909 Features + +The GRI-909 is configured as follows: + +device simulates +name(s) + +CPU GRI-909 CPU with up to 32KW of memory +HSR S42-004 high speed reader +HSP S42-004 high speed punch +TTI S42-001 Teletype input +TTO S42-002 Teletype output +RTC real-time clock + +The GRI-909 simulator implements the following unique stop conditions: + + - an unimplemented operator is referenced, and register + STOP_OPR is set + - an invalid interrupt request is made + +The LOAD and DUMP commands are not implemented. + +2.1 CPU + +The only CPU options are the presence of the extended arithmetic operator +and the size of main memory. + + SET CPU EAO enable extended arithmetic operator + SET CPU NOEAO disable extended arithmetic operator + SET CPU 4K set memory size = 4K + SET CPU 8K set memory size = 8K + SET CPU 12K set memory size = 12K + SET CPU 16K set memory size = 16K + SET CPU 20K set memory size = 20K + SET CPU 24K set memory size = 24K + SET CPU 28K set memory size = 28K + SET CPU 32K set memory size = 32K + +If memory size is being reduced, and the memory being truncated contains +non-zero data, the simulator asks for confirmation. Data in the truncated +portion of memory is lost. Initial memory size is 32K. + +CPU registers include the visible state of the processor as well as the +control registers for the interrupt system. + + name size comments + + SC 14 sequence counter + AX 16 arithmetic operator input register 1 + AY 16 arithmetic operator input register 2 + AO 16 arithmetic operator output register + TRP 16 TRP register + MSR 16 machine status register + ISR 16 interrupt status register + BSW 16 byte swapper buffer + BPK 16 byte packer buffer + GR1..GR6 16 general registers 1 to 6 + BOV 1 bus overflow (MSR<15>) + L 1 link (MSR<14>) + FOA 2 arithmetic operator function (MSR<9:8>) + AOV 1 arithmetic overflow (MSR<0>) + IR 16 instruction register (read only) + MA 16 memory address register (read only) + SWR 16 switch register + DR 16 display register + THW 6 thumbwheels (selects operator displayed in DR) + IREQ 16 interrupt requests + ION 1 interrupts enabled + INODEF 1 interrupts not deferred + BKP 1 breakpoint request + SCQ[0:63] 16 SC prior to last jump or interrupt; + most recent SC change first + STOP_OPR 1 stop on undefined operator + WRU 8 interrupt character + +2.2 Programmed I/O Devices + +2.2.1 S42-004 High Speed Reader (HSR) + +The paper tape reader (HSR) reads data from or a disk file. The POS +register specifies the number of the next data item to be read. Thus, +by changing POS, the user can backspace or advance the reader. + +The paper tape reader supports the BOOT command. BOOT HSR copies the +boot loader into memory and starts it running. + +The paper tape reader implements these registers: + + name size comments + + BUF 8 last data item processed + IRDY 1 device ready flag + IENB 1 device interrupt enable flag + POS 32 position in the input file + TIME 24 time from I/O initiation to interrupt + STOP_IOE 1 stop on I/O error + +Error handling is as follows: + + error STOP_IOE processed as + + not attached 1 report error and stop + 0 out of tape + + end of file 1 report error and stop + 0 out of tape + + OS I/O error x report error and stop + +2.2.2 S42-006 High Speed Punch (HSP) + +The paper tape punch (HSP) writes data to a disk file. The POS +register specifies the number of the next data item to be written. +Thus, by changing POS, the user can backspace or advance the punch. + +The paper tape punch implements these registers: + + name size comments + + BUF 8 last data item processed + ORDY 1 device ready flag + IENB 1 device interrupt enable flag + POS 32 position in the output file + TIME 24 time from I/O initiation to interrupt + STOP_IOE 1 stop on I/O error + +Error handling is as follows: + + error STOP_IOE processed as + + not attached 1 report error and stop + 0 out of tape + + OS I/O error x report error and stop + +2.2.3 S42-001 Teletype Input (TTI) + +The Teletype input (TTI) polls the console keyboard for input. It +implements these registers: + + name size comments + + BUF 8 last data item processed + IRDY 1 device ready flag + IENB 1 device interrupt enable flag + POS 32 position in the output file + TIME 24 keyboard polling interval + +2.2.4 S42-002 Teletype Output (TTO) + +The Teletype output (TTO) writes to the simulator console window. +It implements these registers: + + name size comments + + BUF 8 last data item processed + ORDY 1 device ready flag + IENB 1 device interrupt enable flag + POS 32 number of characters output + TIME 24 time from I/O initiation to interrupt + +2.2.5 Real-Time Clock (RTC) + +The real-time clock (CLK) implements these registers: + + name size comments + + RDY 1 device ready flag + IENB 1 interrupt enable flag + TIME 24 clock interval + +The real-time clock autocalibrates; the clock interval is adjusted up or +down so that the clock tracks actual elapsed time. + +2.3 Symbolic Display and Input + +The GRI-909 simulator implements symbolic display and input. Display is +controlled by command line switches: + + -a display as ASCII character + -c display as packed ASCII characters + -m display instruction mnemonics + +Input parsing is controlled by the first character typed in or by command +line switches: + + ' or -a ASCII character + " or -c two packed ASCII characters + alphabetic instruction mnemonic + numeric octal number + +Instruction input uses modified GRI-909 basic assembler syntax. There are +thirteen different instruction formats. Operators, functions, and tests may +be octal or symbolic; jump conditions and bus operators are always symbolic. + +Function out, general + Syntax: FO function,operator + Function symbols: INP, IRDY, ORDY, STRT + Example: FO ORDY,TTO + +Function out, named + Syntax: FO{M|I|A} function + Function symbols: M: CLL, CML, STL, HLT; I: ICF, ICO; + A: ADD, AND, XOR, OR + Example: FOA XOR + +Sense function, general + Syntax: SF operator,{NOT} tests + Test symbols: IRDY, ORDY + Example: SF HSR,IRDY + +Sense function, named + Syntax: SF{M|A} {NOT} tests + Test symbols: M: POK BOV LNK; A: SOV AOV + Example: SFM NOT BOV + +Register to register + Syntax: RR{C} src,{bus op,}dst + Bus op symbols: P1, L1, R1 + Example: RRC AX,P1,AY + +Zero to register + Syntax: ZR{C} {bus op,}dst + Bus op symbols: P1, L1, R1 + Example: ZR P1,GR1 + +Register to self + Syntax: RS{C} dst{,bus op} + Bus op symbols: P1, L1, R1 + Example: RS AX,L1 + +Jump unconditional or named condition + Syntax: J{U|O|N}{D} address + Example: JUD 1400 + +Jump conditional + Syntax: JC{D} src,cond,address + Cond symbols: NEVER,ALWAYS,ETZ,NEZ,LTZ,GEZ,LEZ,GTZ + Example: JC AX,LEZ,200 + +Register to memory + syntax: RM{I|D|ID} src,{bus op,}address + Bus op symbols: P1, L1, R1 + Example: RMD AX,P1,1315 + +Zero to memory + Syntax: ZM{I|D|ID} {bus op,}address + Bus op symbols: P1, L1, R1 + Example: ZM P1,5502 + +Memory to register + Syntax: MR{I|D|ID} address,{bus op,}dst + Bus op symbols: P1, L1, R1 + Example: MRI 1405,GR6 + +Memory to self: + Syntax: MS{I|D|ID} address{,bus op} + Bus op symbols: P1, L1, R1 + Example: MS 3333,P1 diff --git a/GRI/gri_stddev.c b/GRI/gri_stddev.c new file mode 100644 index 00000000..6cda663a --- /dev/null +++ b/GRI/gri_stddev.c @@ -0,0 +1,366 @@ +/* gri_stddev.c: GRI-909 standard devices + + Copyright (c) 2001-2002, Robert M Supnik + + Permission is hereby granted, free of charge, to any person obtaining a + copy of this software and associated documentation files (the "Software"), + to deal in the Software without restriction, including without limitation + the rights to use, copy, modify, merge, publish, distribute, sublicense, + and/or sell copies of the Software, and to permit persons to whom the + Software is furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + ROBERT M SUPNIK BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + Except as contained in this notice, the name of Robert M Supnik shall not + be used in advertising or otherwise to promote the sale, use or other dealings + in this Software without prior written authorization from Robert M Supnik. + + tti S42-001 terminal input + tto S42-002 terminal output + hsr S42-004 high speed reader + hsp S42-006 high speed punch + rtc real time clock +*/ + +#include "gri_defs.h" +#include + +#define UNIT_V_UC (UNIT_V_UF + 0) /* UC only */ +#define UNIT_UC (1 << UNIT_V_UC) + +uint32 hsr_stopioe = 1, hsp_stopioe = 1; + +extern uint16 M[]; +extern uint32 dev_done, ISR; + +t_stat tti_svc (UNIT *uhsr); +t_stat tto_svc (UNIT *uhsr); +t_stat tti_reset (DEVICE *dhsr); +t_stat tto_reset (DEVICE *dhsr); +t_stat hsr_svc (UNIT *uhsr); +t_stat hsp_svc (UNIT *uhsr); +t_stat hsr_reset (DEVICE *dhsr); +t_stat hsp_reset (DEVICE *dhsr); +t_stat rtc_svc (UNIT *uhsr); +t_stat rtc_reset (DEVICE *dhsr); +int32 rtc_tps = 1000; + +/* TTI data structures + + tti_dev TTI device descriptor + tti_unit TTI unit descriptor + tti_reg TTI register list + tti_mod TTI modifiers list +*/ + +UNIT tti_unit = { UDATA (&tti_svc, UNIT_UC, 0), KBD_POLL_WAIT }; + +REG tti_reg[] = { + { ORDATA (BUF, tti_unit.buf, 8) }, + { FLDATA (IRDY, dev_done, INT_V_TTI) }, + { FLDATA (IENB, ISR, INT_V_TTI) }, + { DRDATA (POS, tti_unit.pos, 32), PV_LEFT }, + { DRDATA (TIME, tti_unit.wait, 24), REG_NZ + PV_LEFT }, + { FLDATA (UC, tti_unit.flags, UNIT_V_UC), REG_HRO }, + { NULL } }; + +MTAB tti_mod[] = { + { UNIT_UC, 0, "lower case", "LC", NULL }, + { UNIT_UC, UNIT_UC, "upper case", "UC", NULL }, + { 0 } }; + +DEVICE tti_dev = { + "TTI", &tti_unit, tti_reg, tti_mod, + 1, 10, 31, 1, 8, 8, + NULL, NULL, &tti_reset, + NULL, NULL, NULL }; + +/* TTO data structures + + tto_dev TTO device descriptor + tto_unit TTO unit descriptor + tto_reg TTO register list +*/ + +UNIT tto_unit = { UDATA (&tto_svc, 0, 0), SERIAL_OUT_WAIT }; + +REG tto_reg[] = { + { ORDATA (BUF, tto_unit.buf, 8) }, + { FLDATA (ORDY, dev_done, INT_V_TTO) }, + { FLDATA (IENB, ISR, INT_V_TTO) }, + { DRDATA (POS, tto_unit.pos, 32), PV_LEFT }, + { DRDATA (TIME, tto_unit.wait, 24), PV_LEFT }, + { NULL } }; + +DEVICE tto_dev = { + "TTO", &tto_unit, tto_reg, NULL, + 1, 10, 31, 1, 8, 8, + NULL, NULL, &tto_reset, + NULL, NULL, NULL }; + +/* HSR data structures + + hsr_dev HSR device descriptor + hsr_unit HSR unit descriptor + hsr_reg HSR register list + hsr_mod HSR modifiers list +*/ + +UNIT hsr_unit = { + UDATA (&hsr_svc, UNIT_SEQ+UNIT_ATTABLE+UNIT_ROABLE, 0), SERIAL_IN_WAIT }; + +REG hsr_reg[] = { + { ORDATA (BUF, hsr_unit.buf, 8) }, + { FLDATA (IRDY, dev_done, INT_V_HSR) }, + { FLDATA (IENB, ISR, INT_V_HSR) }, + { DRDATA (POS, hsr_unit.pos, 32), PV_LEFT }, + { DRDATA (TIME, hsr_unit.wait, 24), REG_NZ + PV_LEFT }, + { FLDATA (STOP_IOE, hsr_stopioe, 0) }, + { NULL } }; + +DEVICE hsr_dev = { + "HSR", &hsr_unit, hsr_reg, NULL, + 1, 10, 31, 1, 8, 8, + NULL, NULL, &hsr_reset, + NULL, NULL, NULL }; + +/* HSP data structures + + hsp_dev HSP device descriptor + hsp_unit HSP unit descriptor + hsp_reg HSP register list +*/ + +UNIT hsp_unit = { + UDATA (&hsp_svc, UNIT_SEQ+UNIT_ATTABLE, 0), SERIAL_OUT_WAIT }; + +REG hsp_reg[] = { + { ORDATA (BUF, hsp_unit.buf, 8) }, + { FLDATA (ORDY, dev_done, INT_V_HSP) }, + { FLDATA (IENB, ISR, INT_V_HSP) }, + { DRDATA (POS, hsp_unit.pos, 32), PV_LEFT }, + { DRDATA (TIME, hsp_unit.wait, 24), PV_LEFT }, + { FLDATA (STOP_IOE, hsp_stopioe, 0) }, + { NULL } }; + +DEVICE hsp_dev = { + "HSP", &hsp_unit, hsp_reg, NULL, + 1, 10, 31, 1, 8, 8, + NULL, NULL, &hsp_reset, + NULL, NULL, NULL }; + +/* RTC data structures + + rtc_dev RTC device descriptor + rtc_unit RTC unit descriptor + rtc_reg RTC register list +*/ + +UNIT rtc_unit = { UDATA (&rtc_svc, 0, 0), 16000 }; + +REG rtc_reg[] = { + { FLDATA (RDY, dev_done, INT_V_RTC) }, + { FLDATA (IENB, ISR, INT_V_RTC) }, + { DRDATA (TIME, rtc_unit.wait, 24), REG_NZ + PV_LEFT }, + { DRDATA (TPS, rtc_tps, 8), REG_NZ + PV_LEFT + REG_HIDDEN }, + { NULL } }; + +DEVICE rtc_dev = { + "RTC", &rtc_unit, rtc_reg, NULL, + 1, 0, 0, 0, 0, 0, + NULL, NULL, &rtc_reset, + NULL, NULL, NULL }; + +/* Console terminal function processors */ + +int32 tty_rd (int32 src, int32 ea) +{ +return tti_unit.buf; /* return data */ +} + +t_stat tty_wr (uint32 dst, uint32 val) +{ +tto_unit.buf = val & 0377; /* save char */ +dev_done = dev_done & ~INT_TTO; /* clear ready */ +sim_activate (&tto_unit, tto_unit.wait); /* activate unit */ +return SCPE_OK; +} + +t_stat tty_fo (uint32 op) +{ +if (op & TTY_IRDY) dev_done = dev_done & ~INT_TTI; +if (op & TTY_ORDY) dev_done = dev_done & ~INT_TTO; +return SCPE_OK; +} + +uint32 tty_sf (uint32 op) +{ +if (((op & TTY_IRDY) && (dev_done & INT_TTI)) || + ((op & TTY_ORDY) && (dev_done & INT_TTO))) return 1; +return 0; +} + +/* Service routines */ + +t_stat tti_svc (UNIT *uhsr) +{ +int32 temp; + +sim_activate (&tti_unit, tti_unit.wait); /* continue poll */ +if ((temp = sim_poll_kbd ()) < SCPE_KFLAG) return temp; /* no char or error? */ +temp = temp & 0177; +if ((tti_unit.flags & UNIT_UC) && islower (temp)) + temp = toupper (temp); +tti_unit.buf = temp | 0200; /* got char */ +dev_done = dev_done | INT_TTI; /* set ready */ +tti_unit.pos = tti_unit.pos + 1; +return SCPE_OK; +} + +t_stat tto_svc (UNIT *uhsr) +{ +int32 temp; + +dev_done = dev_done | INT_TTO; /* set ready */ +if ((temp = sim_putchar (tto_unit.buf & 0177)) != SCPE_OK) return temp; +tto_unit.pos = tto_unit.pos + 1; +return SCPE_OK; +} + +/* Reset routines */ + +t_stat tti_reset (DEVICE *dhsr) +{ +tti_unit.buf = 0; /* clear buffer */ +dev_done = dev_done & ~INT_TTI; /* clear ready */ +sim_activate (&tti_unit, tti_unit.wait); /* activate unit */ +return SCPE_OK; +} + +t_stat tto_reset (DEVICE *dhsr) +{ +tto_unit.buf = 0; /* clear buffer */ +dev_done = dev_done | INT_TTO; /* set ready */ +sim_cancel (&tto_unit); /* deactivate unit */ +return SCPE_OK; +} + +/* High speed paper tape function processors */ + +int32 hsrp_rd (int32 src, int32 ea) +{ +return hsr_unit.buf; /* return data */ +} + +t_stat hsrp_wr (uint32 dst, uint32 val) +{ +hsp_unit.buf = val & 0377; /* save char */ +dev_done = dev_done & ~INT_HSP; /* clear ready */ +sim_activate (&hsp_unit, hsp_unit.wait); /* activate unit */ +return SCPE_OK; +} + +t_stat hsrp_fo (uint32 op) +{ +if (op & PT_IRDY) dev_done = dev_done & ~INT_HSR; +if (op & PT_ORDY) dev_done = dev_done & ~INT_HSP; +if (op & PT_STRT) sim_activate (&hsr_unit, hsr_unit.wait); +return SCPE_OK; +} + +uint32 hsrp_sf (uint32 op) +{ +if (((op & PT_IRDY) && (dev_done & INT_HSR)) || + ((op & PT_ORDY) && (dev_done & INT_HSP))) return 1; +return 0; +} + +t_stat hsr_svc (UNIT *uhsr) +{ +int32 temp; + +if ((hsr_unit.flags & UNIT_ATT) == 0) /* attached? */ + return IORETURN (hsr_stopioe, SCPE_UNATT); +if ((temp = getc (hsr_unit.fileref)) == EOF) { /* read char */ + if (feof (hsr_unit.fileref)) { /* err or eof? */ + if (hsr_stopioe) printf ("HSR end of file\n"); + else return SCPE_OK; } + else perror ("HSR I/O error"); + clearerr (hsr_unit.fileref); + return SCPE_IOERR; } +dev_done = dev_done | INT_HSR; /* set ready */ +hsr_unit.buf = temp & 0377; /* save char */ +hsr_unit.pos = hsr_unit.pos + 1; +return SCPE_OK; +} + +t_stat hsp_svc (UNIT *uhsr) +{ +dev_done = dev_done | INT_HSP; /* set ready */ +if ((hsp_unit.flags & UNIT_ATT) == 0) /* attached? */ + return IORETURN (hsp_stopioe, SCPE_UNATT); +if (putc (hsp_unit.buf, hsp_unit.fileref) == EOF) { /* write char */ + perror ("HSP I/O error"); /* error? */ + clearerr (hsp_unit.fileref); + return SCPE_IOERR; } +hsp_unit.pos = hsp_unit.pos + 1; +return SCPE_OK; +} + +/* Reset routines */ + +t_stat hsr_reset (DEVICE *dhsr) +{ +hsr_unit.buf = 0; /* clear buffer */ +dev_done = dev_done & ~INT_HSR; /* clear ready */ +sim_cancel (&hsr_unit); /* deactivate unit */ +return SCPE_OK; +} + +t_stat hsp_reset (DEVICE *dhsr) +{ +hsp_unit.buf = 0; /* clear buffer */ +dev_done = dev_done | INT_HSP; /* set ready */ +sim_cancel (&hsp_unit); /* deactivate unit */ +return SCPE_OK; +} + +/* Clock function processors */ + +t_stat rtc_fo (int32 op) +{ +if (op & RTC_OFF) sim_cancel (&rtc_unit); /* clock off? */ +if ((op & RTC_ON) && !sim_is_active (&rtc_unit)) /* clock on? */ + sim_activate (&rtc_unit, sim_rtc_init (rtc_unit.wait)); +if (op & RTC_OV) dev_done = dev_done & ~INT_RTC; /* clr ovflo? */ +return SCPE_OK; +} + +int32 rtc_sf (int32 op) +{ +if ((op & RTC_OV) && (dev_done & INT_RTC)) return 1; +return 0; +} + +t_stat rtc_svc (UNIT *uhsr) +{ +M[RTC_CTR] = (M[RTC_CTR] + 1) & DMASK; /* incr counter */ +if (M[RTC_CTR] == 0) dev_done = dev_done | INT_RTC; /* ovflo? set ready */ +sim_activate (&rtc_unit, sim_rtc_calb (rtc_tps)); /* reactivate */ +return SCPE_OK; +} + +t_stat rtc_reset (DEVICE *dhsr) +{ +dev_done = dev_done & ~INT_RTC; /* clear ready */ +sim_cancel (&rtc_unit); /* stop clock */ +return SCPE_OK; +} \ No newline at end of file diff --git a/GRI/gri_sys.c b/GRI/gri_sys.c new file mode 100644 index 00000000..e8c75c23 --- /dev/null +++ b/GRI/gri_sys.c @@ -0,0 +1,578 @@ +/* gri_sys.c: GRI-909 simulator interface + + Copyright (c) 2001-2002, Robert M Supnik + + Permission is hereby granted, free of charge, to any person obtaining a + copy of this software and associated documentation files (the "Software"), + to deal in the Software without restriction, including without limitation + the rights to use, copy, modify, merge, publish, distribute, sublicense, + and/or sell copies of the Software, and to permit persons to whom the + Software is furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + ROBERT M SUPNIK BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + Except as contained in this notice, the name of Robert M Supnik shall not + be used in advertising or otherwise to promote the sale, use or other dealings + in this Software without prior written authorization from Robert M Supnik. +*/ + +#include "gri_defs.h" +#include + +extern DEVICE cpu_dev; +extern UNIT cpu_unit; +extern DEVICE tti_dev, tto_dev; +extern DEVICE hsr_dev, hsp_dev; +extern DEVICE rtc_dev; +extern REG cpu_reg[]; +extern uint16 M[]; +extern int32 sim_switches; + +/* SCP data structures and interface routines + + sim_name simulator name string + sim_PC pointer to saved PC register descriptor + sim_emax maximum number of words for examine/deposit + sim_devices array of pointers to simulated devices + sim_stop_messages array of pointers to stop messages + sim_load binary loader +*/ + +char sim_name[] = "GRI-909"; + +REG *sim_PC = &cpu_reg[0]; + +int32 sim_emax = 2; + +DEVICE *sim_devices[] = { + &cpu_dev, + &tti_dev, + &tto_dev, + &hsr_dev, + &hsp_dev, + &rtc_dev, + NULL }; + +const char *sim_stop_messages[] = { + "Unknown error", + "Unimplemented unit", + "HALT instruction", + "Breakpoint", + "Invalid interrupt request" }; + +/* Binary loader + + Bootstrap loader format consists of blocks separated by zeroes. Each + word in the block has three frames: a control frame (ignored) and two + data frames. The user must specify the load address. Switch -c means + continue and load all blocks until end of tape. +*/ + +t_stat sim_load (FILE *fileref, char *cptr, char *fnam, int flag) +{ +int32 c, org; +t_stat r; +char gbuf[CBUFSIZE]; + +if (*cptr != 0) { /* more input? */ + cptr = get_glyph (cptr, gbuf, 0); /* get origin */ + org = get_uint (gbuf, 8, AMASK, &r); + if (r != SCPE_OK) return r; + if (*cptr != 0) return SCPE_ARG; } /* no more */ +else org = 0200; /* default 200 */ + +for (;;) { /* until EOF */ + while ((c = getc (fileref)) == 0) ; /* skip starting 0's */ + if (c == EOF) break; /* EOF? done */ + for ( ; c != 0; ) { /* loop until ctl = 0 */ + /* ign ctrl frame */ + if ((c = getc (fileref)) == EOF) /* get high byte */ + return SCPE_FMT; /* EOF is error */ + if (!MEM_ADDR_OK (org)) return SCPE_NXM; + M[org] = ((c & 0377) << 8); /* store high */ + if ((c = getc (fileref)) == EOF) /* get low byte */ + return SCPE_FMT; /* EOF is error */ + M[org] = M[org] | (c & 0377); /* store low */ + org = org + 1; /* incr origin */ + if ((c = getc (fileref)) == EOF) /* get ctrl frame */ + return SCPE_OK; /* EOF is ok */ + } /* end block for */ + if (!(sim_switches & SWMASK ('C'))) return SCPE_OK; + } /* end tape for */ +return SCPE_OK; +} + +/* Symbol tables */ + +#define F_V_FL 16 +#define F_M_FL 017 +#define F_V_FO 000 /* function out */ +#define F_V_FOI 001 /* FO, impl reg */ +#define F_V_SF 002 /* skip function */ +#define F_V_SFI 003 /* SF, impl reg */ +#define F_V_RR 004 /* reg reg */ +#define F_V_ZR 005 /* zero reg */ +#define F_V_RS 006 /* reg self */ +#define F_V_JC 010 /* jump cond */ +#define F_V_JU 011 /* jump uncond */ +#define F_V_RM 012 /* reg mem */ +#define F_V_ZM 013 /* zero mem */ +#define F_V_MR 014 /* mem reg */ +#define F_V_MS 015 /* mem self */ +#define F_2WD 010 /* 2 words */ + +#define F_FO (F_V_FO << F_V_FL) +#define F_FOI (F_V_FOI << F_V_FL) +#define F_SF (F_V_SF << F_V_FL) +#define F_SFI (F_V_SFI << F_V_FL) +#define F_RR (F_V_RR << F_V_FL) +#define F_ZR (F_V_ZR << F_V_FL) +#define F_RS (F_V_RS << F_V_FL) +#define F_JC (F_V_JC << F_V_FL) +#define F_JU (F_V_JU << F_V_FL) +#define F_RM (F_V_RM << F_V_FL) +#define F_ZM (F_V_ZM << F_V_FL) +#define F_MR (F_V_MR << F_V_FL) +#define F_MS (F_V_MS << F_V_FL) + +struct fnc_op { + uint32 inst; /* instr prot */ + uint32 imask; /* instr mask */ + uint32 oper; /* operator */ + uint32 omask; }; /* oper mask */ + +static const int32 masks[] = { + 0176000, 0176077, 0000077, 0176077, + 0000300, 0176300, 0000300, 0177777, + 0000077, 0177777, 0000377, 0176377, + 0176300, 0176377 }; + +/* Instruction mnemonics + + Order is critical, as some instructions are more precise versions of + others. For example, JU must precede JC, otherwise, JU will be decoded + as JC 0,ETZ,dst. There are some ambiguities, eg, what is 02-xxxx-06? + Priority is as follows: + + FO (02-xxxx-rr) + SF (rr-xxxx-02) + MR (06-xxxx-rr) + RM (rr-xxxx-06) + JC (rr-xxxx-03) + RR +*/ + +static const char *opcode[] = { + "FOM", "FOA", "FOI", "FO", /* FOx before FO */ + "SFM", "SFA", "SFI", "SF", /* SFx before SF */ + "ZM", "ZMD", "ZMI", "ZMID", /* ZM before RM */ + "MS", "MSD", "MSI", "MSID", + "RM", "RMD", "RMI", "RMID", + "MR", "MRD", "MRI", "MRID", + "JO", "JOD", "JN", "JND", /* JU before JC */ + "JU", "JUD", "JC", "JCD", + "ZR", "ZRC", "RR", "RRC", /* ZR before RR */ + "RS", "RSC", + NULL }; + +static const uint32 opc_val[] = { + 0004000+F_FOI, 0004013+F_FOI, 0004004+F_FOI, 0004000+F_FO, + 0000002+F_SFI, 0026002+F_SFI, 0010002+F_SFI, 0000002+F_SF, + 0000006+F_ZM, 0000106+F_ZM, 0000206+F_ZM, 0000306+F_ZM, + 0014006+F_MS, 0014106+F_MS, 0014206+F_MS, 0014306+F_MS, + 0000006+F_RM, 0000106+F_RM, 0000206+F_RM, 0000306+F_RM, + 0014000+F_MR, 0014100+F_MR, 0014200+F_MR, 0014300+F_MR, + 0037003+F_JU, 0037103+F_JU, 0037203+F_JU, 0037303+F_JU, + 0000403+F_JU, 0000503+F_JU, 0000003+F_JC, 0000103+F_JC, + 0000000+F_ZR, 0000200+F_ZR, 0000000+F_RR, 0000200+F_RR, + 0000000+F_RS, 0000200+F_RS }; + +/* Unit mnemonics. All 64 units are decoded, most just to octal integers */ + +static const char *unsrc[64] = { + "0", "IR", "2", "TRP", "ISR", "MA", "MB", "SC", /* 00 - 07 */ + "SWR", "AX", "AY", "AO", "14", "15", "16", "MSR", /* 10 - 17 */ + "20", "21", "22", "23", "BSW", "BPK", "26", "27", /* 20 - 27 */ + "GR1", "GR2", "GR3", "GR4", "GR5", "GR6", "36", "37", /* 30 - 37 */ + "40", "41", "42", "43", "44", "45", "46", "47", + "50", "51", "52", "53", "54", "55", "56", "57", + "60", "61", "62", "63", "64", "65", "66", "67", + "70", "71", "72", "73", "74", "RTC", "HSR", "TTI" }; /* 70 - 77 */ + +static const char *undst[64] = { + "0", "IR", "2", "TRP", "ISR", "5", "MB", "SC", /* 00 - 07 */ + "SWR", "AX", "AY", "13", "EAO", "15", "16", "MSR", /* 10 - 17 */ + "20", "21", "22", "23", "BSW", "BPK", "26", "27", /* 20 - 27 */ + "GR1", "GR2", "GR3", "GR4", "GR5", "GR6", "36", "37", /* 30 - 37 */ + "40", "41", "42", "43", "44", "45", "46", "47", + "50", "51", "52", "53", "54", "55", "56", "57", + "60", "61", "62", "63", "64", "65", "66", "67", + "70", "71", "72", "73", "74", "RTC", "HSP", "TTO" }; /* 70 - 77 */ + + /* Operators */ + +static const char *opname[4] = { + NULL, "P1", "L1", "R1" }; + +/* Conditions */ + +static const char *cdname[8] = { + "NEVER", "ALWAYS", "ETZ", "NEZ", "LTZ", "GEZ", "LEZ", "GTZ" }; + +/* Function out/sense function */ + +static const char *fname[] = { + "NOT", /* any SF */ + "POK", "LNK", "BOV", /* SFM */ + "SOV", "AOV", /* SFA */ + "IRDY", "ORDY", /* any SF */ + "CLL", "STL", "CML", "HLT", /* FOM */ + "ICF", "ICO", /* FOI */ + "ADD", "AND", "XOR", "OR", /* FOA */ + "INP", "IRDY", "ORDY", "STRT", /* any FO */ + NULL }; + +static const struct fnc_op fop[] = { + { 0000002, 0000077, 001, 001 }, /* NOT */ + { 0000002, 0176077, 010, 010 }, /* POK */ + { 0000002, 0176077, 004, 004 }, /* LNK */ + { 0000002, 0176077, 002, 002 }, /* BOV */ + { 0026002, 0176077, 004, 004 }, /* SOV */ + { 0026002, 0176077, 002, 002 }, /* AOV */ + { 0000002, 0000077, 010, 010 }, /* IRDY */ + { 0000002, 0000077, 002, 002 }, /* ORDY */ + { 0004000, 0176077, 001, 003 }, /* CLL */ + { 0004000, 0176077, 002, 003 }, /* STL */ + { 0004000, 0176077, 003, 003 }, /* CML */ + { 0004000, 0176077, 004, 004 }, /* HLT */ + { 0004004, 0176077, 001, 001 }, /* ICF */ + { 0004004, 0176077, 002, 002 }, /* ICO */ + { 0004013, 0176077, 000, 014 }, /* ADD */ + { 0004013, 0176077, 004, 014 }, /* AND */ + { 0004013, 0176077, 010, 014 }, /* XOR */ + { 0004013, 0176077, 014, 014 }, /* OR */ + { 0004000, 0176000, 011, 011 }, /* INP */ + { 0004000, 0176000, 010, 010 }, /* IRDY */ + { 0004000, 0176000, 002, 002 }, /* ORDY */ + { 0004000, 0176000, 001, 001 } }; /* STRT */ + +/* Print opcode field for FO, SF */ + +void fprint_op (FILE *of, uint32 inst, uint32 op) +{ +int32 i, nfirst; + +for (i = nfirst = 0; fname[i] != NULL; i++) { + if (((inst & fop[i].imask) == fop[i].inst) && + ((op & fop[i].omask) == fop[i].oper)) { + op = op & ~fop[i].omask; + if (nfirst) fputc (' ', of); + nfirst = 1; + fprintf (of, "%s", fname[i]); } + } +if (op) fprintf (of, " %o", op); +return; +} + +/* Symbolic decode + + Inputs: + *of = output stream + addr = current PC + *val = pointer to data + *uptr = pointer to unit + sw = switches + Outputs: + return = status code +*/ + +#define FMTASC(x) ((x) < 040)? "<%03o>": "%c", (x) + +t_stat fprint_sym (FILE *of, t_addr addr, t_value *val, + UNIT *uptr, int32 sw) +{ +int32 i, j; +uint32 inst, src, dst, op, bop; + +inst = val[0]; +if (sw & SWMASK ('A')) { /* ASCII? */ + if (inst > 0377) return SCPE_ARG; + fprintf (of, FMTASC (inst & 0177)); + return SCPE_OK; } +if (sw & SWMASK ('C')) { /* characters? */ + fprintf (of, FMTASC ((inst >> 8) & 0177)); + fprintf (of, FMTASC (inst & 0177)); + return SCPE_OK; } +if (!(sw & SWMASK ('M'))) return SCPE_ARG; + +/* Instruction decode */ + +inst = val[0]; +src = I_GETSRC (inst); /* get fields */ +op = I_GETOP (inst); +dst = I_GETDST (inst); +bop = op >> 2; /* bus op */ +for (i = 0; opc_val[i] >= 0; i++) { /* loop thru ops */ + j = (opc_val[i] >> F_V_FL) & F_M_FL; /* get class */ + if ((opc_val[i] & DMASK) == (inst & masks[j])) { /* match? */ + + switch (j) { /* case on class */ + case F_V_FO: /* func out */ + fprintf (of, "%s ", opcode[i]); + fprint_op (of, inst, op); + fprintf (of, ",%s", undst[dst]); + break; + case F_V_FOI: /* func out impl */ + fprintf (of, "%s ", opcode[i]); + fprint_op (of, inst, op); + break; + case F_V_SF: /* skip func */ + fprintf (of, "%s %s,", opcode[i], unsrc[src]); + fprint_op (of, inst, op); + break; + case F_V_SFI: /* skip func impl */ + fprintf (of, "%s ", opcode[i]); + fprint_op (of, inst, op); + break; + case F_V_RR: /* reg reg */ + if (strcmp (unsrc[src], undst[dst]) == 0) { + if (bop) fprintf (of, "%s %s,%s", opcode[i + 2], + unsrc[src], opname[bop]); + else fprintf (of, "%s %s", opcode[i + 2], unsrc[src]); } + else { if (bop) fprintf (of, "%s %s,%s,%s", opcode[i], + unsrc[src], opname[bop], undst[dst]); + else fprintf (of, "%s %s,%s", opcode[i], + unsrc[src], undst[dst]); } + break; + case F_V_ZR: /* zero reg */ + if (bop) fprintf (of, "%s %s,%s", opcode[i], + opname[bop], undst[dst]); + else fprintf (of, "%s %s", opcode[i], undst[dst]); + break; + case F_V_JC: /* jump cond */ + fprintf (of, "%s %s,%s,%o", opcode[i], + unsrc[src], cdname[op >> 1], val[1]); + break; + case F_V_JU: /* jump uncond */ + fprintf (of, "%s %o", opcode[i], val[1]); + break; + case F_V_RM: /* reg mem */ + if (bop) fprintf (of, "%s %s,%s,%o", opcode[i], + unsrc[src], opname[bop], val[1]); + else fprintf (of, "%s %s,%o", opcode[i], unsrc[src], val[1]); + break; + case F_V_ZM: /* zero mem */ + if (bop) fprintf (of, "%s %s,%o", opcode[i], + opname[bop], val[1]); + else fprintf (of, "%s %o", opcode[i], val[1]); + break; + case F_V_MR: /* mem reg */ + if (bop) fprintf (of, "%s %o,%s,%s", opcode[i], + val[1], opname[bop], undst[dst]); + else fprintf (of, "%s %o,%s", opcode[i], val[1], undst[dst]); + break; + case F_V_MS: /* mem self */ + if (bop) fprintf (of, "%s %o,%s", opcode[i], + val[1], opname[bop]); + else fprintf (of, "%s %o", opcode[i], val[1]); + break; } /* end case */ + return (j >= F_2WD)? -1: SCPE_OK; } /* end if */ + } /* end for */ +return SCPE_ARG; +} + +/* Field parse routines + + get_fnc get function field + get_ma get memory address + get_sd get source or dest + get_op get optional bus operator +*/ + +char *get_fnc (char *cptr, t_value *val) +{ +char gbuf[CBUFSIZE]; +int32 i; +t_value d; +t_stat r; +uint32 inst = val[0]; +uint32 fncv = 0, fncm = 0; + +while (*cptr) { + cptr = get_glyph (cptr, gbuf, 0); /* get glyph */ + d = get_uint (gbuf, 8, 017, &r); /* octal? */ + if (r == SCPE_OK) { /* ok? */ + if (d & fncm) return NULL; /* already filled? */ + fncv = fncv | d; /* save */ + fncm = fncm | d; } /* field filled */ + else { /* symbol? */ + for (i = 0; fname[i] != NULL; i++) { /* search table */ + if ((strcmp (gbuf, fname[i]) == 0) && /* match for inst? */ + ((inst & fop[i].imask) == fop[i].inst)) { + if (fop[i].oper & fncm) return NULL; /* already filled? */ + fncm = fncm | fop[i].omask; + fncv = fncv | fop[i].oper; + break; } } + if (fname[i] == NULL) return NULL; } /* end else */ + } /* end while */ +val[0] = val[0] | (fncv << I_V_OP); /* store fnc */ +return cptr; +} + +char *get_ma (char *cptr, t_value *val, char term) +{ +char gbuf[CBUFSIZE]; +t_value d; +t_stat r; + +cptr = get_glyph (cptr, gbuf, term); /* get glyph */ +d = get_uint (gbuf, 8, DMASK, &r); /* [0,177777] */ +if (r != SCPE_OK) return NULL; +val[1] = d; /* second wd */ +return cptr; +} + +char *get_sd (char *cptr, t_value *val, char term, t_bool src) +{ +char gbuf[CBUFSIZE]; +int32 d; +t_stat r; + +cptr = get_glyph (cptr, gbuf, term); /* get glyph */ +for (d = 0; d < 64; d++) { /* symbol match? */ + if ((strcmp (gbuf, unsrc[d]) == 0) || + (strcmp (gbuf, undst[d]) == 0)) break; } +if (d >= 64) { /* no, [0,63]? */ + d = get_uint (gbuf, 8, 077, &r); + if (r != SCPE_OK) return NULL; } +val[0] = val[0] | (d << (src? I_V_SRC: I_V_DST)); /* or to inst */ +return cptr; +} + +char *get_op (char *cptr, t_value *val, char term) +{ +char gbuf[CBUFSIZE], *tptr; +int32 i; + +tptr = get_glyph (cptr, gbuf, term); /* get glyph */ +for (i = 1; i < 4; i++) { /* symbol match? */ + if (strcmp (gbuf, opname[i]) == 0) { + val[0] = val[0] | (i << (I_V_OP + 2)); /* or to inst */ + return tptr; } } +return cptr; /* original ptr */ +} + +/* Symbolic input + + Inputs: + *cptr = pointer to input string + addr = current PC + *uptr = pointer to unit + *val = pointer to output values + sw = switches + Outputs: + status = error status +*/ + +t_stat parse_sym (char *cptr, t_addr addr, UNIT *uptr, t_value *val, int32 sw) +{ +int32 i, j, k; +char *tptr, gbuf[CBUFSIZE]; + +while (isspace (*cptr)) cptr++; /* absorb spaces */ +if ((sw & SWMASK ('A')) || ((*cptr == '\'') && cptr++)) { /* ASCII char? */ + if (cptr[0] == 0) return SCPE_ARG; /* must have 1 char */ + val[0] = (t_value) cptr[0] & 0177; + return SCPE_OK; } +if ((sw & SWMASK ('C')) || ((*cptr == '"') && cptr++)) { /* char string? */ + if (cptr[0] == 0) return SCPE_ARG; /* must have 1 char */ + val[0] = (((t_value) cptr[0] & 0177) << 8) | + ((t_value) cptr[1] & 0177); + return SCPE_OK; } + +/* Instruction parse */ + +cptr = get_glyph (cptr, gbuf, 0); /* get opcode */ +for (i = 0; (opcode[i] != NULL) && (strcmp (opcode[i], gbuf) != 0) ; i++) ; +if (opcode[i] == NULL) return SCPE_ARG; +val[0] = opc_val[i] & DMASK; /* get value */ +j = (opc_val[i] >> F_V_FL) & F_M_FL; /* get class */ + +switch (j) { /* case on class */ +case F_V_FO: /* func out */ + tptr = strchr (cptr, ','); /* find dst */ + if (!tptr) return SCPE_ARG; /* none? */ + *tptr = 0; /* split fields */ + cptr = get_fnc (cptr, val); /* fo # */ + if (!cptr) return SCPE_ARG; + cptr = get_sd (tptr + 1, val, 0, FALSE); /* dst */ + break; +case F_V_FOI: /* func out impl */ + cptr = get_fnc (cptr, val); /* fo # */ + break; +case F_V_SF: /* skip func */ + cptr = get_sd (cptr, val, ',', TRUE); /* src */ + if (!cptr) return SCPE_ARG; +case F_V_SFI: /* skip func impl */ + cptr = get_fnc (cptr, val); /* fo # */ + break; +case F_V_RR: /* reg-reg */ + cptr = get_sd (cptr, val, ',', TRUE); /* src */ + if (!cptr) return SCPE_ARG; + cptr = get_op (cptr, val, ','); /* op */ + if (!cptr) return SCPE_ARG; + cptr = get_sd (cptr, val, 0, FALSE); /* dst */ + break; +case F_V_ZR: /* zero-reg */ + cptr = get_op (cptr, val, ','); /* op */ + if (!cptr) return SCPE_ARG; + cptr = get_sd (cptr, val, 0, FALSE); /* dst */ + break; +case F_V_RS: /* reg self */ + cptr = get_sd (cptr, val, ',', TRUE); /* src */ + if (!cptr) return SCPE_ARG; + val[0] = val[0] | I_GETSRC (val[0]); /* duplicate */ + cptr = get_op (cptr, val, 0); /* op */ + break; +case F_V_JC: /* jump cond */ + cptr = get_sd (cptr, val, ',', TRUE); /* src */ + if (!cptr) return SCPE_ARG; + cptr = get_glyph (cptr, gbuf, ','); /* cond */ + for (k = 0; k < 8; k++) { /* symbol? */ + if (strcmp (gbuf, cdname[k]) == 0) break; } + if (k >= 8) return SCPE_ARG; + val[0] = val[0] | (k << (I_V_OP + 1)); /* or to inst */ +case F_V_JU: /* jump uncond */ + cptr = get_ma (cptr, val, 0); /* addr */ + break; +case F_V_RM: /* reg mem */ + cptr = get_sd (cptr, val, ',', TRUE); /* src */ + if (!cptr) return SCPE_ARG; +case F_V_ZM: /* zero mem */ + cptr = get_op (cptr, val, ','); /* op */ + if (!cptr) return SCPE_ARG; + cptr = get_ma (cptr, val, 0); /* addr */ + break; +case F_V_MR: /* mem reg */ + cptr = get_ma (cptr, val, ','); /* addr */ + if (!cptr) return SCPE_ARG; + cptr = get_op (cptr, val, ','); /* op */ + if (!cptr) return SCPE_ARG; + cptr = get_sd (cptr, val, 0, FALSE); /* dst */ + break; +case F_V_MS: /* mem self */ + cptr = get_ma (cptr, val, ','); /* addr */ + if (!cptr) return SCPE_ARG; + cptr = get_op (cptr, val, 0); /* op */ + break; } +if (!cptr || (*cptr != 0)) return SCPE_ARG; /* junk at end? */ +return (j >= F_2WD)? -1: SCPE_OK; +} diff --git a/H316/h316_cpu.c b/H316/h316_cpu.c index 0f4fc778..f0d5c33f 100644 --- a/H316/h316_cpu.c +++ b/H316/h316_cpu.c @@ -1,6 +1,6 @@ /* h316_cpu.c: Honeywell 316/516 CPU simulator - Copyright (c) 1993-2001, Robert M. Supnik + Copyright (c) 1999-2002, Robert M. Supnik Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), @@ -25,6 +25,7 @@ cpu H316/H516 CPU + 30-Dec-01 RMS Added old PC queue 03-Nov-01 RMS Fixed NOHSA modifier 30-Nov-01 RMS Added extended SET/SHOW support @@ -189,6 +190,10 @@ #include "h316_defs.h" +#define PCQ_SIZE 64 /* must be 2**n */ +#define PCQ_MASK (PCQ_SIZE - 1) +#define PCQ_ENTRY pcq[pcq_p = (pcq_p - 1) & PCQ_MASK] = PC +#define PCQ_TOP pcq[pcq_p] #define UNIT_V_MSIZE (UNIT_V_UF) /* dummy mask */ #define UNIT_MSIZE (1 << UNIT_V_MSIZE) #define m7 0001000 /* for generics */ @@ -219,7 +224,9 @@ int32 dev_enable = 0; /* dev enable */ int32 ind_max = 8; /* iadr nest limit */ int32 stop_inst = 1; /* stop on ill inst */ int32 stop_dev = 2; /* stop on ill dev */ -int32 old_PC = 0; /* previous PC */ +uint16 pcq[PCQ_SIZE] = { 0 }; /* PC queue */ +int32 pcq_p = 0; /* PC queue ptr */ +REG *pcq_r = NULL; /* PC queue reg ptr */ int32 dlog = 0; /* debug log */ int32 turnoff = 0; extern int32 sim_int_char; @@ -269,9 +276,10 @@ REG cpu_reg[] = { { FLDATA (STOP_INST, stop_inst, 0) }, { FLDATA (STOP_DEV, stop_dev, 1) }, { DRDATA (INDMAX, ind_max, 8), REG_NZ + PV_LEFT }, - { ORDATA (OLDP, old_PC, 15), REG_RO }, + { BRDATA (PCQ, pcq, 8, 15, PCQ_SIZE), REG_RO+REG_CIRC }, + { ORDATA (PCQP, pcq_p, 6), REG_HRO }, { ORDATA (WRU, sim_int_char, 8) }, - { FLDATA (DLOG, dlog, 0) }, + { FLDATA (DLOG, dlog, 0), REG_HIDDEN }, { FLDATA (HEXT, cpu_unit.flags, UNIT_V_EXT), REG_HRO }, { FLDATA (HSA, cpu_unit.flags, UNIT_V_HSA), REG_HRO }, { NULL } }; @@ -385,11 +393,11 @@ if (dlog && sim_log && !turnoff) { /* cycle log? */ switch (I_GETOP (MB)) { /* case on <1:6> */ case 001: case 021: case 041: case 061: /* JMP */ if (reason = Ea (MB, &Y)) break; /* eff addr */ - old_PC = PC; /* save PC */ + PCQ_ENTRY; /* save PC */ PC = NEWA (PC, Y); /* set new PC */ if (dlog && sim_log) { /* logging? */ int32 op = I_GETOP (M[PC]) & 017; /* get target */ - if ((op == 014) && (PC == (old_PC - 2))) { /* jmp .-1 to IO? */ + if ((op == 014) && (PC == (PCQ_TOP - 2))) { /* jmp .-1 to IO? */ turnoff = 1; /* yes, stop */ fprintf (sim_log, "Idle loop detected\n"); } else turnoff = 0; } /* no, log */ @@ -446,7 +454,7 @@ case 010: case 030: case 050: case 070: /* JST */ if (reason = Ea (MB, &Y)) break; /* eff addr */ MB = NEWA (Read (Y), PC); /* merge old PC */ Write (MB, Y); - old_PC = PC; + PCQ_ENTRY; PC = NEWA (PC, Y + 1); /* set new PC */ break; case 011: case 031: case 051: case 071: /* CAS */ @@ -759,6 +767,7 @@ case 060: saved_AR = AR & DMASK; saved_BR = BR & DMASK; saved_XR = XR & DMASK; +pcq_r -> qptr = pcq_p; /* update pc q ptr */ return reason; } @@ -985,6 +994,9 @@ dp = 0; ext = pme = extoff_pending = 0; dev_ready = dev_ready & ~INT_PENDING; dev_enable = 0; +pcq_r = find_reg ("PCQ", NULL, dptr); +if (pcq_r) pcq_r -> qptr = 0; +else return SCPE_IERR; sim_brk_types = sim_brk_dflt = SWMASK ('E'); return SCPE_OK; } diff --git a/H316/h316_defs.h b/H316/h316_defs.h index bd6f9e53..1ee39506 100644 --- a/H316/h316_defs.h +++ b/H316/h316_defs.h @@ -1,6 +1,6 @@ /* h316_defs.h: Honeywell 316/516 simulator definitions - Copyright (c) 1993-2001, Robert M. Supnik + Copyright (c) 1999-2002, Robert M. Supnik Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), diff --git a/H316/h316_doc.txt b/H316/h316_doc.txt index 32d36018..924a6a94 100644 --- a/H316/h316_doc.txt +++ b/H316/h316_doc.txt @@ -1,14 +1,14 @@ To: Users From: Bob Supnik Subj: H316 Simulator Usage -Date: 1-Dec-2001 +Date: 15-Jun-2002 COPYRIGHT NOTICE The following copyright notice applies to both the SIMH source and binary: - Original code published in 1993-2001, written by Robert M Supnik - Copyright (c) 1993-2001, Robert M Supnik + Original code published in 1993-2002, written by Robert M Supnik + Copyright (c) 1993-2002, Robert M Supnik Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), @@ -113,7 +113,8 @@ control registers for the interrupt system. STOP_INST 1 stop on undefined instruction STOP_DEV 1 stop on undefined device INDMAX 1 indirect address limit - OLDP 15 PC prior to last JMP, JSB, or interrupt + PCQ[0:63] 15 PC prior to last JMP, JSB, or interrupt; + most recent PC change first WRU 8 interrupt character 2.2 Programmed I/O Devices @@ -135,7 +136,7 @@ The paper tape reader implements these registers: INTREQ 1 device interrupt request READY 1 device ready ENABLE 1 device interrupts enabled - POS 31 position in the input or output file + POS 32 position in the input or output file TIME 24 time from I/O initiation to interrupt STOP_IOE 1 stop on I/O error @@ -166,7 +167,7 @@ The paper tape punch implements these registers: READY 1 device ready ENABLE 1 device interrupts enabled POWER 1 device powered up - POS 31 position in the input or output file + POS 32 position in the input or output file TIME 24 time from I/O initiation to interrupt PWRTIME 24 time from I/O request to power up STOP_IOE 1 stop on I/O error @@ -187,7 +188,7 @@ simulator console window. The terminal has one option, UC; when set, the terminal automatically converts lower case input to upper case. This is on by default. -The terminal these registers: +The terminal implements these registers: name size comments @@ -196,9 +197,9 @@ The terminal these registers: INTREQ 1 device interrupt request READY 1 device ready ENABLE 1 device interrupts enabled - KPOS 31 number of characters input + KPOS 32 number of characters input KTIME 24 keyboard polling interval - TPOS 31 number of characters output + TPOS 32 number of characters output TTIME 24 time from I/O initiation to interrupt 2.2.4 316/516-12 Real Time Clock (CLK) @@ -212,6 +213,9 @@ The real time clock (CLK) implements these registers: ENABLE 1 device interrupts enabled TIME 24 clock interval +The real-time clock autocalibrates; the clock interval is adjusted up or +down so that the clock tracks actual elapsed time. + 2.2.5 316/5116 Line Printer (LPT) The line printer (LPT) writes data to a disk file. The POS register @@ -227,12 +231,12 @@ The line printer implements these registers: CRPOS 1 carriage position XFER 1 transfer ready flag PRDN 1 print done flag - INTREQ 1 device interrupt request - ENABLE 1 device interrupt enable + INTREQ 1 device interrupt request + ENABLE 1 device interrupt enable SVCST 2 service state SVCCH 2 service channel BUF 8 buffer - POS 31 number of characters output + POS 32 number of characters output XTIME 24 delay between transfers ETIME 24 delay at end of scan PTIME 24 delay for shuttle/line advance diff --git a/H316/h316_lp.c b/H316/h316_lp.c index b8879845..f0ea4541 100644 --- a/H316/h316_lp.c +++ b/H316/h316_lp.c @@ -1,6 +1,6 @@ /* h316_lp.c: Honeywell 316/516 line printer - Copyright (c) 1993-2001, Robert M. Supnik + Copyright (c) 1999-2002, Robert M. Supnik Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), @@ -24,6 +24,8 @@ in this Software without prior written authorization from Robert M Supnik. lpt line printer + + 30-May-02 RMS Widened POS to 32b */ #include "h316_defs.h" @@ -101,7 +103,7 @@ REG lpt_reg[] = { { ORDATA (SVCST, lpt_svcst, 2) }, { ORDATA (SVCCH, lpt_svcch, 2) }, { BRDATA (BUF, lpt_buf, 8, 8, 120) }, - { DRDATA (POS, lpt_unit.pos, 31), PV_LEFT }, + { DRDATA (POS, lpt_unit.pos, 32), PV_LEFT }, { DRDATA (XTIME, lpt_xtime, 24), PV_LEFT }, { DRDATA (ETIME, lpt_etime, 24), PV_LEFT }, { DRDATA (PTIME, lpt_ptime, 24), PV_LEFT }, diff --git a/H316/h316_stddev.c b/H316/h316_stddev.c index 2dd27cc7..87655f11 100644 --- a/H316/h316_stddev.c +++ b/H316/h316_stddev.c @@ -1,6 +1,6 @@ /* h316_stddev.c: Honeywell 316/516 standard devices - Copyright (c) 1993-2001, Robert M. Supnik + Copyright (c) 1999-2002, Robert M. Supnik Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), @@ -28,6 +28,7 @@ tty 316/516-33 teleprinter clk/options 316/516-12 real time clocks/internal options + 30-May-02 RMS Widened POS to 32b 03-Nov-01 RMS Implemented upper case for console output 29-Nov-01 RMS Added read only unit support 07-Sep-01 RMS Moved function prototypes @@ -75,7 +76,7 @@ REG ptr_reg[] = { { ORDATA (BUF, ptr_unit.buf, 8) }, { FLDATA (READY, dev_ready, INT_V_PTR) }, { FLDATA (ENABLE, dev_enable, INT_V_PTR) }, - { DRDATA (POS, ptr_unit.pos, 31), PV_LEFT }, + { DRDATA (POS, ptr_unit.pos, 32), PV_LEFT }, { DRDATA (TIME, ptr_unit.wait, 24), PV_LEFT }, { FLDATA (STOP_IOE, ptr_stopioe, 0) }, { NULL } }; @@ -102,7 +103,7 @@ REG ptp_reg[] = { { FLDATA (READY, dev_ready, INT_V_PTP) }, { FLDATA (ENABLE, dev_enable, INT_V_PTP) }, { FLDATA (POWER, ptp_power, 0) }, - { DRDATA (POS, ptp_unit.pos, 31), PV_LEFT }, + { DRDATA (POS, ptp_unit.pos, 32), PV_LEFT }, { DRDATA (TIME, ptp_unit.wait, 24), PV_LEFT }, { DRDATA (PWRTIME, ptp_ptime, 24), PV_LEFT }, { FLDATA (STOP_IOE, ptp_stopioe, 0) }, @@ -135,9 +136,9 @@ REG tty_reg[] = { { FLDATA (MODE, tty_mode, 0) }, { FLDATA (READY, dev_ready, INT_V_TTY) }, { FLDATA (ENABLE, dev_enable, INT_V_TTY) }, - { DRDATA (KPOS, tty_unit[TTI].pos, 31), PV_LEFT }, + { DRDATA (KPOS, tty_unit[TTI].pos, 32), PV_LEFT }, { DRDATA (KTIME, tty_unit[TTI].wait, 24), REG_NZ + PV_LEFT }, - { DRDATA (TPOS, tty_unit[TTO].pos, 31), PV_LEFT }, + { DRDATA (TPOS, tty_unit[TTO].pos, 32), PV_LEFT }, { DRDATA (TTIME, tty_unit[TTO].wait, 24), REG_NZ + PV_LEFT }, { FLDATA (UC, tty_unit[TTI].flags, UNIT_V_UC), REG_HRO }, { NULL } }; diff --git a/H316/h316_sys.c b/H316/h316_sys.c index 9098cccf..6175d397 100644 --- a/H316/h316_sys.c +++ b/H316/h316_sys.c @@ -1,6 +1,6 @@ /* h316_sys.c: Honeywell 316/516 simulator interface - Copyright (c) 1993-2001, Robert M Supnik + Copyright (c) 1999-2002, Robert M Supnik Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), diff --git a/HP2100/hp2100_cpu.c b/HP2100/hp2100_cpu.c index 1536e738..85d9694a 100644 --- a/HP2100/hp2100_cpu.c +++ b/HP2100/hp2100_cpu.c @@ -1,6 +1,6 @@ /* hp2100_cpu.c: HP 2100 CPU simulator - Copyright (c) 1993-2001, Robert M. Supnik + Copyright (c) 1993-2002, Robert M. Supnik Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), @@ -23,6 +23,17 @@ be used in advertising or otherwise to promote the sale, use or other dealings in this Software without prior written authorization from Robert M Supnik. + 22-Mar-02 RMS Changed to allocate memory array dynamically + 11-Mar-02 RMS Cleaned up setjmp/auto variable interaction + 17-Feb-02 RMS Added DMS support + Fixed bugs in extended instructions + 03-Feb-02 RMS Added terminal multiplexor support + Changed PCQ macro to use unmodified PC + Fixed flop restore logic (found by Bill McDermith) + Fixed SZx,SLx,RSS bug (found by Bill McDermith) + Added floating point support + 16-Jan-02 RMS Added additional device support + 07-Jan-02 RMS Fixed DMA register tables (found by Bill McDermith) 07-Dec-01 RMS Revised to use breakpoint package 03-Dec-01 RMS Added extended SET/SHOW support 10-Aug-01 RMS Removed register in declarations @@ -239,15 +250,30 @@ */ #include "hp2100_defs.h" +#include +#define PCQ_SIZE 64 /* must be 2**n */ +#define PCQ_MASK (PCQ_SIZE - 1) +#define PCQ_ENTRY pcq[pcq_p = (pcq_p - 1) & PCQ_MASK] = err_PC #define UNIT_V_MSIZE (UNIT_V_UF) /* dummy mask */ #define UNIT_MSIZE (1 << UNIT_V_MSIZE) #define UNIT_V_2100 (UNIT_V_UF + 1) /* 2100 vs 2116 */ #define UNIT_2100 (1 << UNIT_V_2100) #define UNIT_V_21MX (UNIT_V_UF + 2) /* 21MX vs 2100 */ #define UNIT_21MX (1 << UNIT_V_21MX) +#define ABORT(val) longjmp (save_env, (val)) -uint16 M[MAXMEMSIZE] = { 0 }; /* memory */ +#define DMAR0 1 +#define DMAR1 2 +#define SEXT(x) (((x) & SIGN)? (((int32) (x)) | ~DMASK): ((int32) (x))) + +/* Memory protection tests */ + +#define MP_TEST(x) (CTL (PRO) && ((x) > 1) && ((x) < mfence)) + +#define MP_TESTJ(x) (CTL (PRO) && ((x) < mfence)) + +uint16 *M = NULL; /* memory */ int32 saved_AR = 0; /* A register */ int32 saved_BR = 0; /* B register */ int32 PC = 0; /* P register */ @@ -266,23 +292,60 @@ int32 ion_defer = 0; /* interrupt defer */ int32 intaddr = 0; /* interrupt addr */ int32 mfence = 0; /* mem prot fence */ int32 maddr = 0; /* mem prot err addr */ +int32 err_PC = 0; /* error PC */ +int32 dms_enb = 0; /* dms enable */ +int32 dms_ump = 0; /* dms user map */ +int32 dms_sr = 0; /* dms status register */ +int32 dms_fence = 0; /* dms base page fence */ +int32 dms_vr = 0; /* dms violation register */ +int32 dms_sma = 0; /* dms saved ma */ +int32 dms_map[MAP_NUM * MAP_LNT] = { 0 }; /* dms maps */ int32 ind_max = 16; /* iadr nest limit */ int32 stop_inst = 1; /* stop on ill inst */ int32 stop_dev = 2; /* stop on ill dev */ -int32 old_PC = 0; /* previous PC */ +uint16 pcq[PCQ_SIZE] = { 0 }; /* PC queue */ +int32 pcq_p = 0; /* PC queue ptr */ +REG *pcq_r = NULL; /* PC queue reg ptr */ +jmp_buf save_env; /* abort handler */ + +extern int32 sim_interval; extern int32 sim_int_char; extern int32 sim_brk_types, sim_brk_dflt, sim_brk_summ; /* breakpoint info */ +extern FILE *sim_log; +uint8 ReadB (int32 addr); +uint8 ReadBA (int32 addr); +uint16 ReadW (int32 addr); +uint16 ReadWA (int32 addr); +uint32 ReadF (int32 addr); +uint16 ReadIO (int32 addr, int32 map); +void WriteB (int32 addr, int32 dat); +void WriteBA (int32 addr, int32 dat); +void WriteW (int32 addr, int32 dat); +void WriteWA (int32 addr, int32 dat); +void WriteIO (int32 addr, int32 dat, int32 map); +int32 dms (int32 va, int32 map, int32 prot); +uint16 dms_rmap (int32 mapi); +void dms_wmap (int32 mapi, int32 dat); +void dms_viol (int32 va, int32 st, t_bool io); +int32 dms_upd_sr (void); int32 shift (int32 inval, int32 flag, int32 oper); int32 calc_dma (void); int32 calc_int (void); -void dma_cycle (int32 chan); +void dma_cycle (int32 chan, int32 map); t_stat cpu_ex (t_value *vptr, t_addr addr, UNIT *uptr, int32 sw); t_stat cpu_dep (t_value val, t_addr addr, UNIT *uptr, int32 sw); t_stat cpu_reset (DEVICE *dptr); t_stat dma0_reset (DEVICE *dptr); t_stat dma1_reset (DEVICE *dptr); t_stat cpu_set_size (UNIT *uptr, int32 val, char *cptr, void *desc); +t_bool dev_conflict (void); + +extern int32 f_as (uint32 op, t_bool sub); +extern int32 f_mul (uint32 op); +extern int32 f_div (uint32 op); +extern int32 f_fix (void); +extern void f_flt (void); /* CPU data structures @@ -292,8 +355,7 @@ t_stat cpu_set_size (UNIT *uptr, int32 val, char *cptr, void *desc); cpu_mod CPU modifiers list */ -UNIT cpu_unit = { UDATA (NULL, UNIT_FIX + UNIT_BINK, - MAXMEMSIZE) }; +UNIT cpu_unit = { UDATA (NULL, UNIT_FIX + UNIT_BINK, VASIZE) }; REG cpu_reg[] = { { ORDATA (P, PC, 15) }, @@ -312,10 +374,17 @@ REG cpu_reg[] = { { FLDATA (MPFBF, dev_fbf[PRO/32], INT_V (PRO)) }, { ORDATA (MFENCE, mfence, 15) }, { ORDATA (MADDR, maddr, 16) }, + { FLDATA (DMSENB, dms_enb, 0) }, + { FLDATA (DMSCUR, dms_ump, VA_N_PAG) }, + { ORDATA (DMSSR, dms_sr, 16) }, + { ORDATA (DMSVR, dms_vr, 16) }, + { ORDATA (DMSSMA, dms_sma, 15), REG_HIDDEN }, + { BRDATA (DMSMAP, dms_map, 8, PA_N_SIZE, MAP_NUM * MAP_LNT) }, { FLDATA (STOP_INST, stop_inst, 0) }, { FLDATA (STOP_DEV, stop_dev, 1) }, { DRDATA (INDMAX, ind_max, 16), REG_NZ + PV_LEFT }, - { ORDATA (OLDP, old_PC, 15), REG_RO }, + { BRDATA (PCQ, pcq, 8, 15, PCQ_SIZE), REG_RO+REG_CIRC }, + { ORDATA (PCQP, pcq_p, 6), REG_HRO }, { ORDATA (WRU, sim_int_char, 8) }, { FLDATA (T2100, cpu_unit.flags, UNIT_V_2100), REG_HRO }, { FLDATA (T21MX, cpu_unit.flags, UNIT_V_21MX), REG_HRO }, @@ -335,10 +404,13 @@ MTAB cpu_mod[] = { { UNIT_2100 + UNIT_21MX, UNIT_21MX, "21MX", "21MX", NULL }, { UNIT_MSIZE, 4096, NULL, "4K", &cpu_set_size }, { UNIT_MSIZE, 8192, NULL, "8K", &cpu_set_size }, - { UNIT_MSIZE, 12288, NULL, "12K", &cpu_set_size }, { UNIT_MSIZE, 16384, NULL, "16K", &cpu_set_size }, - { UNIT_MSIZE, 24576, NULL, "24K", &cpu_set_size }, { UNIT_MSIZE, 32768, NULL, "32K", &cpu_set_size }, + { UNIT_MSIZE, 65536, NULL, "64K", &cpu_set_size }, + { UNIT_MSIZE, 131072, NULL, "128K", &cpu_set_size }, + { UNIT_MSIZE, 262144, NULL, "256K", &cpu_set_size }, + { UNIT_MSIZE, 524288, NULL, "512K", &cpu_set_size }, + { UNIT_MSIZE, 1048576, NULL, "1024K", &cpu_set_size }, { 0 } }; DEVICE cpu_dev = { @@ -362,7 +434,8 @@ REG dma0_reg[] = { { FLDATA (FBF, dev_fbf[DMA0/32], INT_V (DMA0)) }, { ORDATA (CW1, dmac[0].cw1, 16) }, { ORDATA (CW2, dmac[0].cw2, 16) }, - { ORDATA (CW3, dmac[0].cw3, 16) } }; + { ORDATA (CW3, dmac[0].cw3, 16) }, + { NULL } }; DEVICE dma0_dev = { "DMA0", &dma0_unit, dma0_reg, NULL, @@ -379,7 +452,8 @@ REG dma1_reg[] = { { FLDATA (FBF, dev_fbf[DMA1/32], INT_V (DMA1)) }, { ORDATA (CW1, dmac[1].cw1, 16) }, { ORDATA (CW2, dmac[1].cw2, 16) }, - { ORDATA (CW3, dmac[1].cw3, 16) } }; + { ORDATA (CW3, dmac[1].cw3, 16) }, + { NULL } }; DEVICE dma1_dev = { "DMA1", &dma1_unit, dma1_reg, NULL, @@ -389,23 +463,35 @@ DEVICE dma1_dev = { /* Extended instruction decode tables */ -static const t_bool ext_addr[192] = { /* ext inst format */ - 0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 }; +static const uint8 ext_addr[192] = { /* ext inst format */ + 0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0, /* 1: 2 word inst */ + 1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0, + 1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 }; -static const t_bool exg_breq[16] = { /* ext grp B only */ - 0,0,0,1,0,1,1,0,0,0,0,1,0,1,1,0 }; +static const uint8 exg_breq[64] = { /* ext grp B only */ + 1,1,1,1,1,1,1,1,0,0,0,0,1,1,1,1, /* 1: <11> must be 1 */ + 1,1,0,1,0,0,0,0,0,0,1,1,1,1,1,1, + 0,0,0,1,0,1,1,0,0,0,0,1,0,1,1,0, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1 }; -static const t_bool exg_addr[32] = { /* ext grp format */ - 1,0,1,1,0,1,1,0,1,0,1,1,0,1,1,0,0,0,1,0,0,2,2,0,0,0,1,3,3,3,2,2 }; +static const uint8 exg_addr[64] = { /* ext grp format */ + 0,0,0,0,0,0,0,0,0,0,0,0,1,3,0,0, /* 1: 2 word inst */ + 0,0,0,0,1,1,1,0,0,0,1,1,1,1,1,1, /* 2: 3 word with count */ + 1,0,1,1,0,1,1,0,1,0,1,1,0,1,1,0, /* 3: 3 word inst */ + 0,0,1,0,0,2,2,0,0,0,1,3,3,3,2,2 }; /* Interrupt defer table */ -static const t_bool defer_tab[] = { 0, 1, 1, 1, 0, 0, 0, 1 }; +static const int32 defer_tab[] = { 0, 1, 1, 1, 0, 0, 0, 1 }; /* Device dispatch table */ @@ -428,103 +514,123 @@ int32 (*dtab[64])() = { NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL }; -/* Dynamic device information table */ +/* Device information blocks */ -extern int32 ptrio (int32 op, int32 IR, int32 outdat); -extern int32 ptpio (int32 op, int32 IR, int32 outdat); -extern int32 ttyio (int32 op, int32 IR, int32 outdat); -extern int32 clkio (int32 op, int32 IR, int32 outdat); -extern int32 lptio (int32 op, int32 IR, int32 outdat); -extern int32 mtdio (int32 op, int32 IR, int32 outdat); -extern int32 mtcio (int32 op, int32 IR, int32 outdat); -extern int32 dpdio (int32 op, int32 IR, int32 outdat); -extern int32 dpcio (int32 op, int32 IR, int32 outdat); +extern DIB ptr_dib, ptp_dib; +extern DIB tty_dib; +extern DIB clk_dib; +extern DIB lpt_dib; +extern DIB dp_dib[]; +extern DIB dq_dib[]; +extern DIB dr_dib[]; +extern DIB mt_dib[]; +extern DIB ms_dib[]; +extern DIB mux_dib[]; +extern DIB muxc_dib; -struct hpdev infotab[] = { - { PTR, 0, 0, 0, 0, &ptrio }, - { PTP, 0, 0, 0, 0, &ptpio }, - { TTY, 0, 0, 0, 0, &ttyio }, - { CLK, 0, 0, 0, 0, &clkio }, - { LPT, 0, 0, 0, 0, &lptio }, - { MTD, 0, 0, 0, 0, &mtdio }, - { MTC, 0, 0, 0, 0, &mtcio }, - { DPD, 0, 0, 0, 0, &dpdio }, - { DPC, 0, 0, 0, 0, &dpcio }, - { 0 } }; +DIB *dib_tab[] = { + &ptr_dib, + &ptp_dib, + &tty_dib, + &clk_dib, + &lpt_dib, + &dp_dib[0], + &dp_dib[1], + &dq_dib[0], + &dq_dib[1], + &dr_dib[0], + &dr_dib[1], + &mt_dib[0], + &mt_dib[1], + &ms_dib[0], + &ms_dib[1], + &mux_dib[0], + &mux_dib[1], + &muxc_dib, + NULL }; t_stat sim_instr (void) { -extern int32 sim_interval; -int32 IR, MA, absel, i, t, intrq, dmarq; -int32 err_PC, M1, dev, iodata, op, sc, q, r, wc; -t_stat reason; - -#define DMAR0 1 -#define DMAR1 2 -#define SEXT(x) (((x) & SIGN)? (((int32) (x)) | ~DMASK): ((int32) (x))) -#define LDBY(a) ((M[(a) >> 1] >> (((a) & 1)? 0: 8)) & 0377) -#define STBY(a,d) MA = (a) >> 1; \ - MP_TEST (MA); \ - if (!MEM_ADDR_OK (MA)) break; \ - if ((a) & 1) M[MA] = (M[MA] & 0177400) | ((d) & 0377); \ - else M[MA] = (M[MA] & 0377) | (((d) & 0377) << 8) - -/* Memory protection tests */ - -#define MP_TEST(x) if (CTL (PRO) && ((x) > 1) && ((x) < mfence)) { \ - maddr = err_PC | 0100000; \ - setFLG (PRO); \ - intrq = PRO; \ - break; } - -#define MP_TESTJ(x) if (CTL (PRO) && ((x) < mfence)) { \ - maddr = err_PC | 0100000; \ - setFLG (PRO); \ - intrq = PRO; \ - break; } +int32 intrq, dmarq; /* set after setjmp */ +t_stat reason; /* set after setjmp */ +int32 i, dev; /* temp */ +DIB *dibp; /* temp */ +int abortval; /* Restore register state */ +if (dev_conflict ()) return SCPE_STOP; /* check consistency */ AR = saved_AR & DMASK; /* restore reg */ BR = saved_BR & DMASK; -err_PC = PC = PC & AMASK; /* load local PC */ +dms_fence = dms_sr & MST_FENCE; /* separate fence */ +err_PC = PC = PC & VAMASK; /* load local PC */ reason = 0; /* Restore I/O state */ -for (i = VARDEV; i <= DEVMASK; i++) dtab[i] = NULL; -for (i = 0; infotab[i].devno != 0; i++) { /* loop thru dev */ - dev = infotab[i].devno; /* get dev # */ - if (infotab[i].ctl) { setCMD (dev); } /* restore cmd */ - else { clrCMD (dev); } - if (infotab[i].ctl) { setCTL (dev); } /* restore ctl */ - else { clrCTL (dev); } - if (infotab[i].flg) { setFLG (dev); } /* restore flg */ - else { clrFLG (dev); } - if (infotab[i].fbf) { setFBF (dev); } /* restore fbf */ - else { clrFBF (dev); } - dtab[dev] = infotab[i].iot; } /* set I/O dispatch */ +for (i = VARDEV; i <= DEVMASK; i++) dtab[i] = NULL; /* clr disp table */ +dev_cmd[0] = dev_cmd[0] & M_FXDEV; /* clear dynamic info */ +dev_ctl[0] = dev_ctl[0] & M_FXDEV; +dev_flg[0] = dev_flg[0] & M_FXDEV; +dev_fbf[0] = dev_fbf[0] & M_FXDEV; +dev_cmd[1] = dev_ctl[1] = dev_flg[1] = dev_fbf[1] = 0; +for (i = 0; dibp = dib_tab[i]; i++) { /* loop thru dev */ + if (dibp -> enb) { /* enabled? */ + dev = dibp -> devno; /* get dev # */ + if (dibp -> cmd) { setCMD (dev); } /* restore cmd */ + if (dibp -> ctl) { setCTL (dev); } /* restore ctl */ + if (dibp -> flg) { setFLG (dev); } /* restore flg */ + clrFBF (dev); /* also sets fbf */ + if (dibp -> fbf) { setFBF (dev); } /* restore fbf */ + dtab[dev] = dibp -> iot; } } /* set I/O dispatch */ + +/* Abort handling + + If an abort occurs in memory protection, the relocation routine + executes a longjmp to this area OUTSIDE the main simulation loop. + Memory protection errors are the only sources of aborts in the + HP 2100. All referenced variables must be globals, and all sim_instr + scoped automatics must be set after the setjmp. +*/ + +abortval = setjmp (save_env); /* set abort hdlr */ +if (abortval != 0) { /* mem mgt abort? */ + if (abortval > 0) { setFLG (PRO); } /* dms abort? */ + else maddr = err_PC | 0100000; /* mprot abort */ + intrq = PRO; } /* protection intr */ dmarq = calc_dma (); /* recalc DMA masks */ intrq = calc_int (); /* recalc interrupts */ /* Main instruction fetch/decode loop */ while (reason == 0) { /* loop until halted */ +int32 IR, MA, absel, i, dev, t, opnd; +int32 M1, iodata, op, sc, q, r, wc; +int32 mapi, mapj; +uint32 fop; + if (sim_interval <= 0) { /* check clock queue */ if (reason = sim_process_event ()) break; dmarq = calc_dma (); /* recalc DMA reqs */ intrq = calc_int (); } /* recalc interrupts */ if (dmarq) { - if (dmarq & DMAR0) dma_cycle (0); /* DMA1 cycle? */ - if (dmarq & DMAR1) dma_cycle (1); /* DMA2 cycle? */ + if (dmarq & DMAR0) dma_cycle (0, PAMAP); /* DMA1 cycle? */ + if (dmarq & DMAR1) dma_cycle (1, PBMAP); /* DMA2 cycle? */ dmarq = calc_dma (); /* recalc DMA reqs */ intrq = calc_int (); } /* recalc interrupts */ if (intrq && ((intrq <= PRO) || !ion_defer)) { /* interrupt request? */ clrFBF (intrq); /* clear flag buffer */ intaddr = intrq; /* save int addr */ - IR = M[intrq]; /* get dispatch instr */ + err_PC = PC; /* save PC for error */ + if (dms_enb) dms_sr = dms_sr | MST_ENBI; /* dms enabled? */ + else dms_sr = dms_sr & ~MST_ENBI; + if (dms_ump) { /* user map? */ + dms_sr = dms_sr | MST_UMPI; + dms_ump = 0; } /* switch to system */ + else dms_sr = dms_sr & ~MST_UMPI; + IR = ReadW (intrq); /* get dispatch instr */ ion_defer = 1; /* defer interrupts */ intrq = 0; /* clear request */ clrCTL (PRO); } /* protection off */ @@ -534,8 +640,8 @@ else { if (sim_brk_summ && reason = STOP_IBKPT; /* stop simulation */ break; } err_PC = PC; /* save PC for error */ - IR = M[PC]; /* fetch instr */ - PC = (PC + 1) & AMASK; + IR = ReadW (PC); /* fetch instr */ + PC = (PC + 1) & VAMASK; sim_interval = sim_interval - 1; ion_defer = 0; } absel = (IR & AB)? 1: 0; /* get A/B select */ @@ -546,81 +652,79 @@ if (IR & MROP) { /* mem ref? */ MA = IR & (IA | DISP); /* ind + disp */ if (IR & CP) MA = ((PC - 1) & PAGENO) | MA; /* current page? */ for (i = 0; (i < ind_max) && (MA & IA); i++) /* resolve multi- */ - MA = M[MA & AMASK]; /* level indirect */ + MA = ReadW (MA & VAMASK); /* level indirect */ if (i >= ind_max) { /* indirect loop? */ reason = STOP_IND; break; } switch ((IR >> 11) & 017) { /* decode IR<14:11> */ case 002: /* AND */ - AR = AR & M[MA]; + AR = AR & ReadW (MA); break; case 003: /* JSB */ - MP_TEST (MA); - if (MEM_ADDR_OK (MA)) M[MA] = PC; - old_PC = PC; - PC = (MA + 1) & AMASK; + WriteW (MA, PC); + PCQ_ENTRY; + PC = (MA + 1) & VAMASK; if (IR & IA) ion_defer = 1; break; case 004: /* XOR */ - AR = AR ^ M[MA]; + AR = AR ^ ReadW (MA); break; case 005: /* JMP */ - MP_TESTJ (MA); - old_PC = PC; + if (MP_TESTJ (MA)) ABORT (ABORT_FENCE); + PCQ_ENTRY; PC = MA; if (IR & IA) ion_defer = 1; break; case 006: /* IOR */ - AR = AR | M[MA]; + AR = AR | ReadW (MA); break; case 007: /* ISZ */ - MP_TEST (MA); - t = (M[MA] + 1) & DMASK; - if (MEM_ADDR_OK (MA)) M[MA] = t; - if (t == 0) PC = (PC + 1) & AMASK; + t = (ReadW (MA) + 1) & DMASK; + WriteW (MA, t); + if (t == 0) PC = (PC + 1) & VAMASK; break; /* Memory reference instructions, continued */ case 010: /* ADA */ - t = (int32) AR + (int32) M[MA]; + opnd = (int32) ReadW (MA); + t = (int32) AR + opnd; if (t > DMASK) E = 1; - if (((~AR ^ M[MA]) & (AR ^ t)) & SIGN) O = 1; + if (((~AR ^ opnd) & (AR ^ t)) & SIGN) O = 1; AR = t & DMASK; break; case 011: /* ADB */ - t = (int32) BR + (int32) M[MA]; + opnd = (int32) ReadW (MA); + t = (int32) BR + opnd; if (t > DMASK) E = 1; - if (((~BR ^ M[MA]) & (BR ^ t)) & SIGN) O = 1; + if (((~BR ^ opnd) & (BR ^ t)) & SIGN) O = 1; BR = t & DMASK; break; case 012: /* CPA */ - if (AR != M[MA]) PC = (PC + 1) & AMASK; + if (AR != ReadW (MA)) PC = (PC + 1) & VAMASK; break; case 013: /* CPB */ - if (BR != M[MA]) PC = (PC + 1) & AMASK; + if (BR != ReadW (MA)) PC = (PC + 1) & VAMASK; break; case 014: /* LDA */ - AR = M[MA]; + AR = ReadW (MA); break; case 015: /* LDB */ - BR = M[MA]; + BR = ReadW (MA); break; case 016: /* STA */ - MP_TEST (MA); - if (MEM_ADDR_OK (MA)) M[MA] = AR; + WriteW (MA, AR); break; case 017: /* STB */ - MP_TEST (MA); - if (MEM_ADDR_OK (MA)) M[MA] = BR; + WriteW (MA, BR); break; } /* end case IR */ } /* end if mem ref */ /* Alter/skip instructions */ else if ((IR & NMROP) == ASKP) { /* alter/skip? */ - int skip = 0; /* no skip */ + int32 skip = 0; /* no skip */ if (IR & 000400) t = 0; /* CLx */ else t = ABREG[absel]; @@ -630,7 +734,7 @@ else if ((IR & NMROP) == ASKP) { /* alter/skip? */ if (IR & 000100) E = 0; /* CLE */ if (IR & 000200) E = E ^ 1; /* CME */ if (((IR & 000030) == 000030) && /* SSx,SLx,RSS */ - (t == 0100001)) skip = 1; + ((t & 0100001) == 0100001)) skip = 1; if (((IR & 000030) == 000020) && /* SSx,RSS */ ((t & SIGN) != 0)) skip = 1; if (((IR & 000030) == 000010) && /* SLx,RSS */ @@ -656,7 +760,7 @@ else if ((IR & NMROP) == ASKP) { /* alter/skip? */ if ((IR & 000002) && (t == 0)) skip = 1;/* SZx */ } /* end if ~RSS */ ABREG[absel] = t; /* store result */ - PC = (PC + skip) & AMASK; /* add in skip */ + PC = (PC + skip) & VAMASK; /* add in skip */ } /* end if alter/skip */ /* Shift instructions */ @@ -665,7 +769,7 @@ else if ((IR & NMROP) == SHFT) { /* shift? */ t = shift (ABREG[absel], IR & 01000, IR >> 6); /* do first shift */ if (IR & 000040) E = 0; /* CLE */ if ((IR & 000010) && ((t & 1) == 0)) /* SLx */ - PC = (PC + 1) & AMASK; + PC = (PC + 1) & VAMASK; ABREG[absel] = shift (t, IR & 00020, IR); /* do second shift */ } /* end if shift */ @@ -675,12 +779,10 @@ else if ((IR & NMROP) == IOT) { /* I/O? */ dev = IR & DEVMASK; /* get device */ t = (IR >> 6) & 07; /* get subopcode */ if (CTL (PRO) && ((t == ioHLT) || (dev != OVF))) { - maddr = err_PC | 0100000; - setFLG (PRO); - intrq = PRO; - break; } + ABORT (ABORT_FENCE); } iodata = devdisp (dev, t, IR, ABREG[absel]); /* process I/O */ - if ((t == ioMIX) || (t == ioLIX)) ABREG[absel] = iodata & DMASK; + if ((t == ioMIX) || (t == ioLIX)) /* store ret data */ + ABREG[absel] = iodata & DMASK; if (t == ioHLT) reason = STOP_HALT; else reason = iodata >> IOT_V_REASON; ion_defer = defer_tab[t]; /* set defer */ @@ -695,10 +797,10 @@ else if (cpu_unit.flags & (UNIT_2100 | UNIT_21MX)) { /* ext instr? */ op = (IR >> 4) & 0277; /* get opcode */ if (ext_addr[op]) { /* extended mem ref? */ - MA = M[PC]; /* get next address */ - PC = (PC + 1) & AMASK; + MA = ReadW (PC); /* get next address */ + PC = (PC + 1) & VAMASK; for (i = 0; (i < ind_max) && (MA & IA); i++) - MA = M[MA & AMASK]; + MA = ReadW (MA & VAMASK); if (i >= ind_max) { reason = STOP_IND; break; } } @@ -706,38 +808,36 @@ else if (cpu_unit.flags & (UNIT_2100 | UNIT_21MX)) { /* ext instr? */ if (sc == 0) sc = 16; switch (op) { /* decode IR<11:4> */ case 0010: /* MUL */ - t = SEXT (AR) * SEXT (M[MA]); + t = SEXT (AR) * SEXT (ReadW (MA)); BR = (t >> 16) & DMASK; AR = t & DMASK; O = 0; break; case 0020: /* DIV */ - if ((M[MA] == 0) || /* divide by zero? */ - ((BR == SIGN) && (AR == 0) && (M[MA] == DMASK))) { + t = (SEXT (BR) << 16) | (int32) AR; /* get divd */ + opnd = SEXT (ReadW (MA)); /* get divisor */ + if ((opnd == 0) || /* divide by zero? */ + ((t == SIGN32) && (opnd == -1)) || /* -2**32 / -1? */ + ((q = t / opnd) > 077777) || /* quo too big? */ + (q < -0100000)) { /* quo too small? */ O = 1; /* set overflow */ - break; } - t = (SEXT (BR) << 16) || (int32) AR; - q = t / SEXT (M[MA]); /* quotient */ - r = t % SEXT (M[MA]); /* remainder */ - if ((q >= 077777) || (q < -0100000)) { /* quo too large? */ - if (BR & SIGN) { /* negative divd? */ - AR = (-AR) & DMASK; /* take abs value */ - BR = ((BR ^ DMASK) + (AR == 0)) & DMASK; } - O = 1; } + if (BR & SIGN) { /* divd negative? */ + BR = (-BR) & DMASK; /* make B'A pos */ + AR = (~AR + (BR == 0)) & DMASK; } + } /* end if div fail */ else { AR = q & DMASK; /* set quo, rem */ - BR = r & DMASK; - O = 0; } + BR = (t % opnd) & DMASK; + O = 0; } /* end else ok */ break; case 0210: /* DLD */ - AR = M[MA]; - MA = (MA + 1) & AMASK; - BR = M[MA]; + AR = ReadW (MA); + MA = (MA + 1) & VAMASK; + BR = ReadW (MA); break; case 0220: /* DST */ - MP_TEST (MA); - if (MEM_ADDR_OK (MA)) M[MA] = AR; - MA = (MA + 1) & AMASK; - if (MEM_ADDR_OK (MA)) M[MA] = BR; + WriteW (MA, AR); + MA = (MA + 1) & VAMASK; + WriteW (MA, BR); break; /* Extended arithmetic instructions */ @@ -745,6 +845,7 @@ else if (cpu_unit.flags & (UNIT_2100 | UNIT_21MX)) { /* ext instr? */ case 0001: /* ASL */ t = (SEXT (BR) >> (16 - sc)) & DMASK; if (t != ((BR & SIGN)? DMASK: 0)) O = 1; + else O = 0; BR = (BR & SIGN) || ((BR << sc) & 077777) || (AR >> (16 - sc)); AR = (AR << sc) & DMASK; @@ -761,6 +862,7 @@ else if (cpu_unit.flags & (UNIT_2100 | UNIT_21MX)) { /* ext instr? */ case 0041: /* ASR */ AR = ((BR << (16 - sc)) | (AR >> sc)) & DMASK; BR = (SEXT (BR) >> sc) & DMASK; + O = 0; break; case 0042: /* LSR */ AR = ((BR << (16 - sc)) | (AR >> sc)) & DMASK; @@ -771,223 +873,453 @@ else if (cpu_unit.flags & (UNIT_2100 | UNIT_21MX)) { /* ext instr? */ AR = ((AR >> sc) | (BR << (16 - sc))) & DMASK; BR = ((BR >> sc) | (t << (16 - sc))) & DMASK; break; - -/* Extended instruction group */ - case 0076: /* ext inst grp, A */ - if (exg_breq[IR & 017]) { /* must have B set? */ +/* Floating point instructions */ + + case 0240: /* FAD */ + fop = ReadF (MA); /* get fop */ + O = O | f_as (fop, 0); /* add */ + break; + case 0241: /* FSB */ + fop = ReadF (MA); /* get fop */ + O = O | f_as (fop, 1); /* subtract */ + break; + case 0242: /* FMP */ + fop = ReadF (MA); /* get fop */ + O = O | f_mul (fop); /* multiply */ + break; + case 0243: /* FDV */ + fop = ReadF (MA); /* get fop */ + O = O | f_div (fop); /* divide */ + break; + case 0244: /* FIX */ + O = O | f_fix (); /* fix */ + break; + case 0245: /* FLT */ + f_flt (); /* float */ + break; + +/* Extended instruction group, including DMS */ + + case 0074: case 0075: /* DMS inst grp, A */ + case 0076: case 0077: /* ext inst grp, A */ + if (exg_breq[IR & 077]) { /* must have B set? */ reason = stop_inst; break; } + case 0274: case 0275: /* DMS inst grp, B */ case 0276: case 0277: /* ext inst grp, B */ if ((cpu_unit.flags & UNIT_21MX) == 0) { reason = stop_inst; break; } - op = IR & 037; /* get sub opcode */ + op = IR & 077; /* get sub opcode */ if (exg_addr[op]) { /* mem addr? */ - MA = M[PC]; /* get next address */ - PC = (PC + 1) & AMASK; + MA = ReadW (PC); /* get next address */ + PC = (PC + 1) & VAMASK; for (i = 0; (i < ind_max) && (MA & IA); i++) - MA = M[MA & AMASK]; + MA = ReadW (MA & VAMASK); if (i >= ind_max) { reason = STOP_IND; break; } } if (exg_addr[op] == 2) { /* word of zero? */ - wc = M[MA]; /* get count */ - if (M[PC] == 0) M[PC] = wc; /* save count */ + wc = ReadW (MA); /* get count */ + if (ReadW (PC) == 0) WriteW (PC, wc); awc = PC; /* and addr */ - PC = (PC + 1) & AMASK; } + PC = (PC + 1) & VAMASK; } if (exg_addr[op] == 3) { /* second address? */ - M1 = M[PC]; /* get next address */ - PC = (PC + 1) & AMASK; + M1 = ReadW (PC); /* get next address */ + PC = (PC + 1) & VAMASK; for (i = 0; (i < ind_max) && (M1 & IA); i++) - M1 = M[M1 & AMASK]; + M1 = ReadW (M1 & VAMASK); if (i >= ind_max) { reason = STOP_IND; break; } } switch (op) { /* case on sub op */ - t_bool cmpeql; + +/* Extended instruction group: DMS */ + + case 002: /* MBI */ + dms_viol (err_PC, MVI_PRV, 0); /* priv if PRO */ + if (XR == 0) break; /* nop if X = 0 */ + AR = AR & ~1; /* force A, B even */ + BR = BR & ~1; + for ( ; XR == 0; XR--) { /* loop */ + t = ReadB (AR); /* read curr */ + WriteBA (BR, t); /* write alt */ + AR = (AR + 1) & DMASK; /* inc ptrs */ + BR = (BR + 1) & DMASK; } + break; + case 003: /* MBF */ + if (XR == 0) break; + AR = AR & ~1; /* force A, B even */ + BR = BR & ~1; + for ( ; XR == 0; XR--) { + t = ReadBA (AR); + WriteB (BR, t); + AR = (AR + 1) & DMASK; + BR = (BR + 1) & DMASK; } + break; + case 004: /* MBW */ + dms_viol (err_PC, MVI_PRV, 0); + if (XR == 0) break; + AR = AR & ~1; /* force A, B even */ + BR = BR & ~1; + for ( ; XR == 0; XR--) { + t = ReadBA (AR); + WriteBA (BR, t); + AR = (AR + 1) & DMASK; + BR = (BR + 1) & DMASK; } + break; + case 005: /* MWI */ + dms_viol (err_PC, MVI_PRV, 0); + if (XR == 0) break; + for ( ; XR == 0; XR--) { + t = ReadW (AR & VAMASK); + WriteWA (BR & VAMASK, t); + AR = (AR + 1) & DMASK; + BR = (BR + 1) & DMASK; } + break; + case 006: /* MWF */ + if (XR == 0) break; + for ( ; XR == 0; XR--) { + t = ReadWA (AR & VAMASK); + WriteW (BR & VAMASK, t); + AR = (AR + 1) & DMASK; + BR = (BR + 1) & DMASK; } + break; + case 007: /* MWW */ + dms_viol (err_PC, MVI_PRV, 0); + if (XR == 0) break; + for ( ; XR == 0; XR--) { + t = ReadWA (AR & VAMASK); + WriteWA (BR & VAMASK, t); + AR = (AR + 1) & DMASK; + BR = (BR + 1) & DMASK; } + break; + +/* Extended instruction group: DMS, continued */ + + case 010: /* SYA, SYB */ + case 011: /* USA, USB */ + case 012: /* PAA, PAB */ + case 013: /* PBA, PBB */ + mapi = (op & 03) << VA_N_PAG; /* map base */ + if (ABREG[absel] & SIGN) { /* store? */ + for (i = 0; i < MAP_LNT; i++) { + t = dms_rmap (mapi + i); + WriteW ((ABREG[absel] + i) & VAMASK, t); } } + else { /* load */ + dms_viol (err_PC, MVI_PRV, 0); /* priv if PRO */ + for (i = 0; i < MAP_LNT; i++) { + t = ReadW (ABREG[absel] + i & VAMASK); + dms_wmap (mapi + i, t); } } + ABREG[absel] = (ABREG[absel] + MAP_LNT) & DMASK; + break; + case 014: /* SSM */ + WriteW (MA, dms_upd_sr ()); /* store stat */ + break; + case 015: /* JRS */ + if (dms_ump) dms_viol (err_PC, MVI_PRV, 0); + t = ReadW (MA); /* get status */ + if (t & 0100000) dms_enb = 1; /* set/clr enb */ + else dms_enb = 0; + if (t & 0040000) dms_ump = 1; /* set/clr usr */ + else dms_ump = 0; + PCQ_ENTRY; /* save old PC */ + PC = M1; /* jump */ + ion_defer = 1; /* defer intr */ + break; + +/* Extended instruction group: DMS, continued */ + + case 020: /* XMM */ + if (XR == 0) break; /* nop? */ + if (XR & SIGN) { /* store? */ + for ( ; XR == 0; XR = (XR + 1) & DMASK) { + t = dms_rmap (AR & MAP_MASK); + WriteW (BR & VAMASK, t); + AR = (AR + 1) & DMASK; + BR = (BR + 1) & DMASK; } } + else { /* load */ + for ( ; XR == 0; XR--) { + t = ReadW (BR & VAMASK); + dms_wmap (AR & MAP_MASK, t); + AR = (AR + 1) & DMASK; + BR = (BR + 1) & DMASK; } } + break; + case 021: /* XMS */ + if (XR & SIGN) break; /* nop? */ + for ( ; XR == 0; XR = (XR - 1) & DMASK) { + dms_wmap (AR & MAP_MASK, BR); + AR = (AR + 1) & DMASK; + BR = (BR + 1) & DMASK; } + break; + case 022: /* XMA, XMB */ + if (ABREG[absel] & 0100000) mapi = SMAP; + else mapi = UMAP; + if (ABREG[absel] & 0040000) mapj = PAMAP; + else mapj = PBMAP; + for (i = 0; i < MAP_LNT; i++) { + t = dms_rmap (mapi + i); + dms_wmap (mapj + i, t); } + break; + case 024: /* XLA, XLB */ + ABREG[absel] = ReadWA (MA); /* load alt */ + break; + case 025: /* XSA, XSB */ + dms_viol (err_PC, MVI_PRV, 0); /* priv if PRO */ + WriteWA (MA, ABREG[absel]); /* store alt */ + break; + case 026: /* XCA, XCB */ + if (ABREG[absel] != ReadWA (MA)) + PC = (PC + 1) & VAMASK; + break; + case 027: /* LFA, LFB */ + if (dms_ump) dms_viol (err_PC, MVI_PRV, 0); + dms_sr = (dms_sr & ~(MST_FLT | MST_FENCE)) | + (ABREG[absel] & (MST_FLT | MST_FENCE)); + dms_fence = dms_sr & MST_FENCE; + break; + +/* Extended instruction group: DMS, continued */ + + case 030: /* RSA, RSB */ + ABREG[absel] = dms_upd_sr (); /* save stat */ + break; + case 031: /* RVA, RVB */ + ABREG[absel] = dms_vr; /* save viol */ + break; + case 032: /* DJP */ + if (dms_ump) dms_viol (err_PC, MVI_PRV, 0); + if (MP_TESTJ (MA)) ABORT (ABORT_FENCE); + dms_enb = 0; + PCQ_ENTRY; + PC = MA; + ion_defer = 1; + break; + case 033: /* DJS */ + if (dms_ump) dms_viol (err_PC, MVI_PRV, 0); + dms_enb = 0; + WriteW (MA, PC); + PCQ_ENTRY; + PC = (MA + 1) & VAMASK; + ion_defer = 1; + break; + case 034: /* SJP */ + if (dms_ump) dms_viol (err_PC, MVI_PRV, 0); + if (MP_TESTJ (MA)) ABORT (ABORT_FENCE); + dms_enb = 1; + dms_ump = 0; + PCQ_ENTRY; + PC = MA; + ion_defer = 1; + break; + case 035: /* SJS */ + if (dms_ump) dms_viol (err_PC, MVI_PRV, 0); + dms_enb = 1; + dms_ump = 0; + WriteW (MA, PC); + PCQ_ENTRY; + PC = (MA + 1) & VAMASK; + ion_defer = 1; + break; + case 036: /* UJP */ + if (dms_ump) dms_viol (err_PC, MVI_PRV, 0); + if (MP_TESTJ (MA)) ABORT (ABORT_FENCE); + dms_enb = 1; + dms_ump = 1; + PCQ_ENTRY; + PC = MA; + ion_defer = 1; + break; + case 037: /* UJS */ + if (dms_ump) dms_viol (err_PC, MVI_PRV, 0); + dms_enb = 1; + dms_ump = 1; + WriteW (MA, PC); + PCQ_ENTRY; + PC = (MA + 1) & VAMASK; + ion_defer = 1; + break; /* Extended instruction group: index register instructions */ - case 000: /* SAX, SBX */ - MA = (MA + XR) & AMASK; - MP_TEST (MA); - if (MEM_ADDR_OK (MA)) M[MA] = ABREG[absel]; + case 040: /* SAX, SBX */ + MA = (MA + XR) & VAMASK; + WriteW (MA, ABREG[absel]); break; - case 001: /* CAX, CBX */ + case 041: /* CAX, CBX */ XR = ABREG[absel]; break; - case 002: /* LAX, LBX */ - MA = (MA + XR) & AMASK; - ABREG[absel] = M[MA]; + case 042: /* LAX, LBX */ + MA = (MA + XR) & VAMASK; + ABREG[absel] = ReadW (MA); break; - case 003: /* STX */ - MP_TEST (MA); - if (MEM_ADDR_OK (MA)) M[MA] = XR; + case 043: /* STX */ + WriteW (MA, XR); break; - case 004: /* CXA, CXB */ + case 044: /* CXA, CXB */ ABREG[absel] = XR; break; - case 005: /* LDX */ - XR = M[MA]; + case 045: /* LDX */ + XR = ReadW (MA); break; - case 006: /* ADX */ - t = XR + M[MA]; + case 046: /* ADX */ + opnd = ReadW (MA); + t = XR + opnd; if (t > DMASK) E = 1; - if (((~XR ^ M[MA]) & (XR ^ t)) & SIGN) O = 1; + if (((~XR ^ opnd) & (XR ^ t)) & SIGN) O = 1; XR = t & DMASK; break; - case 007: /* XAX, XBX */ + case 047: /* XAX, XBX */ t = XR; XR = ABREG[absel]; ABREG[absel] = t; break; - case 010: /* SAY, SBY */ - MA = (MA + YR) & AMASK; - MP_TEST (MA); - if (MEM_ADDR_OK (MA)) M[MA] = ABREG[absel]; + case 050: /* SAY, SBY */ + MA = (MA + YR) & VAMASK; + WriteW (MA, ABREG[absel]); break; - case 011: /* CAY, CBY */ + case 051: /* CAY, CBY */ YR = ABREG[absel]; break; - case 012: /* LAY, LBY */ - MA = (MA + YR) & AMASK; - ABREG[absel] = M[MA]; + case 052: /* LAY, LBY */ + MA = (MA + YR) & VAMASK; + ABREG[absel] = ReadW (MA); break; - case 013: /* STY */ - MP_TEST (MA); - if (MEM_ADDR_OK (MA)) M[MA] = YR; + case 053: /* STY */ + WriteW (MA, YR); break; - case 014: /* CYA, CYB */ + case 054: /* CYA, CYB */ ABREG[absel] = YR; break; - case 015: /* LDY */ - YR = M[MA]; + case 055: /* LDY */ + YR = ReadW (MA); break; - case 016: /* ADY */ - t = YR + M[MA]; + case 056: /* ADY */ + opnd = ReadW (MA); + t = YR + opnd; if (t > DMASK) E = 1; - if (((~YR ^ M[MA]) & (YR ^ t)) & SIGN) O = 1; + if (((~YR ^ opnd) & (YR ^ t)) & SIGN) O = 1; YR = t & DMASK; break; - case 017: /* XAY, XBY */ + case 057: /* XAY, XBY */ t = YR; YR = ABREG[absel]; ABREG[absel] = t; break; - case 020: /* ISX */ + case 060: /* ISX */ XR = (XR + 1) & DMASK; - if (XR == 0) PC = (PC + 1) & AMASK; + if (XR == 0) PC = (PC + 1) & VAMASK; break; - case 021: /* DSX */ + case 061: /* DSX */ XR = (XR - 1) & DMASK; - if (XR == 0) PC = (PC + 1) & AMASK; + if (XR == 0) PC = (PC + 1) & VAMASK; break; - case 022: /* JLY */ - MP_TESTJ (MA); - old_PC = PC; + case 062: /* JLY */ + if (MP_TESTJ (MA)) ABORT (ABORT_FENCE); + PCQ_ENTRY; YR = PC; PC = MA; break; - case 030: /* ISY */ + case 070: /* ISY */ YR = (YR + 1) & DMASK; - if (YR == 0) PC = (PC + 1) & AMASK; + if (YR == 0) PC = (PC + 1) & VAMASK; break; - case 031: /* DSY */ + case 071: /* DSY */ YR = (YR - 1) & DMASK; - if (YR == 0) PC = (PC + 1) & AMASK; + if (YR == 0) PC = (PC + 1) & VAMASK; break; - case 032: /* JPY */ - MA = (M[PC] + YR) & AMASK; /* no indirect */ - PC = (PC + 1) & AMASK; - MP_TESTJ (MA); - old_PC = PC; + case 072: /* JPY */ + MA = (ReadW (PC) + YR) & VAMASK; /* no indirect */ + PC = (PC + 1) & VAMASK; + if (MP_TESTJ (MA)) ABORT (ABORT_FENCE); + PCQ_ENTRY; PC = MA; break; /* Extended instruction group: byte */ - case 023: /* LBT */ - AR = LDBY (BR); + case 063: /* LBT */ + AR = ReadB (BR); + BR = (BR + 1) & DMASK; break; - case 024: /* SBT */ - STBY (BR, AR); + case 064: /* SBT */ + WriteB (BR, AR); + BR = (BR + 1) & DMASK; break; - case 025: /* MBT */ - while (M[awc]) { /* while count */ - q = LDBY (AR); /* load byte */ - STBY (BR, q); /* store byte */ - AR = (AR + 1) & DMASK; /* incr src */ - BR = (BR + 1) & DMASK; /* incr dst */ - M[awc] = (M[awc] - 1) & DMASK; } + case 065: /* MBT */ + t = ReadW (awc); /* get wc */ + while (t) { /* while count */ + q = ReadB (AR); /* move byte */ + WriteB (BR, q); + AR = (AR + 1) & DMASK; /* incr src */ + BR = (BR + 1) & DMASK; /* incr dst */ + t = (t - 1) & DMASK; /* decr cnt */ + WriteW (awc, t); } break; - case 026: /* CBT */ - cmpeql = TRUE; - while (M[awc]) { /* while count */ - q = LDBY (AR); /* get src1 */ - r = LDBY (BR); /* get src2 */ - if (cmpeql && (q != r)) { /* compare */ - PC = (PC + 1 + (q > r)) & AMASK; - cmpeql = FALSE; } - AR = (AR + 1) & DMASK; - BR = (BR + 1) & DMASK; - M[awc] = (M[awc] - 1) & DMASK; } + case 066: /* CBT */ + t = ReadW (awc); /* get wc */ + while (t) { /* while count */ + q = ReadB (AR); /* get src1 */ + r = ReadB (BR); /* get src2 */ + if (q != r) { /* compare */ + PC = (PC + 1 + (q > r)) & VAMASK; + BR = (BR + t) & DMASK; /* update BR */ + WriteW (awc, 0); /* clr awc */ + break; } + AR = (AR + 1) & DMASK; /* incr src1 */ + BR = (BR + 1) & DMASK; /* incr src2 */ + t = (t - 1) & DMASK; /* decr cnt */ + WriteW (awc, t); } break; - case 027: /* SFB */ + case 067: /* SFB */ q = AR & 0377; /* test byte */ r = (AR >> 8) & 0377; /* term byte */ for (;;) { /* scan */ - t = LDBY (BR); /* get byte */ - if (t == q) break; /* test match? */ - BR = (BR + 1) & DMASK; - if (t == r) { /* term match? */ - PC = (PC + 1) & AMASK; - break; } } + t = ReadB (BR); /* get byte */ + if (t == q) break; /* test match? */ + BR = (BR + 1) & DMASK; + if (t == r) { /* term match? */ + PC = (PC + 1) & VAMASK; + break; } } break; /* Extended instruction group: bit, word */ - case 033: /* SBS */ - MP_TEST (M1); - if (MEM_ADDR_OK (M1)) M[M1] = M[M1] | M[MA]; + case 073: /* SBS */ + WriteW (M1, M[M1] | M [MA]); break; - case 034: /* CBS */ - MP_TEST (M1); - if (MEM_ADDR_OK (M1)) M[M1] = M[M1] & ~M[MA]; + case 074: /* CBS */ + WriteW (M1, M[M1] & ~M[MA]); break; - case 035: /* TBS */ - if ((M[M1] & M[MA]) != M[MA]) PC = (PC + 1) & AMASK; + case 075: /* TBS */ + if ((M[M1] & M[MA]) != M[MA]) PC = (PC + 1) & VAMASK; break; - case 036: /* CMW */ - cmpeql = TRUE; - while (M[awc]) { /* while count */ - q = SEXT (M[AR & AMASK]); - r = SEXT (M[BR & AMASK]); - if (cmpeql && (q != r)) { /* compare */ - PC = (PC + 1 + (q > r)) & AMASK; - cmpeql = FALSE; } - AR = (AR + 1) & DMASK; - BR = (BR + 1) & DMASK; - M[awc] = (M[awc] - 1) & DMASK; } + case 076: /* CMW */ + t = ReadW (awc); /* get wc */ + while (t) { /* while count */ + q = SEXT (M[AR & VAMASK]); + r = SEXT (M[BR & VAMASK]); + if (q != r) { /* compare */ + PC = (PC + 1 + (q > r)) & VAMASK; + BR = (BR + t) & DMASK; /* update BR */ + WriteW (awc, 0); /* clr awc */ + break; } + AR = (AR + 1) & DMASK; /* incr src1 */ + BR = (BR + 1) & DMASK; /* incr src2 */ + t = (t - 1) & DMASK; /* decr cnt */ + WriteW (awc, t); } break; - case 037: /* MVW */ - while (M[awc]) { /* while count */ - MP_TEST (BR & AMASK); - if (MEM_ADDR_OK (BR & AMASK)) - M[BR & AMASK] = M[AR & AMASK]; - BR = (BR + 1) & DMASK; - AR = (AR + 1) & DMASK; - M[awc] = (M[awc] - 1) & DMASK; } + case 077: /* MVW */ + t = ReadW (awc); /* get wc */ + while (t) { /* while count */ + q = ReadW (AR & VAMASK); /* move word */ + WriteW (BR & VAMASK, q); + AR = (AR + 1) & DMASK; /* incr src */ + BR = (BR + 1) & DMASK; /* incr dst */ + t = (t - 1) & DMASK; /* decr cnt */ + WriteW (awc, t); } break; } /* end ext group */ - -/* Floating point instructions */ - - case 0240: /* FAD */ - case 0241: /* FSB */ - case 0242: /* FMP */ - case 0243: /* FDV */ - case 0244: /* FIX */ - case 0245: /* FLT */ default: reason = stop_inst; } /* end switch IR */ } /* end if extended */ @@ -997,16 +1329,13 @@ else if (cpu_unit.flags & (UNIT_2100 | UNIT_21MX)) { /* ext instr? */ saved_AR = AR & DMASK; saved_BR = BR & DMASK; -for (i = 0; infotab[i].devno != 0; i++) { /* save dynamic info */ - dev = infotab[i].devno; - infotab[i].ctl = CMD (dev); - infotab[i].ctl = CTL (dev); - infotab[i].flg = FLG (dev); - infotab[i].fbf = FBF (dev); } -dev_flg[0] = dev_flg[0] & M_FXDEV; /* clear dynamic info */ -dev_fbf[0] = dev_fbf[0] & M_FXDEV; -dev_ctl[0] = dev_ctl[0] & M_FXDEV; -dev_flg[1] = dev_fbf[1] = dev_ctl[1] = 0; +for (i = 0; dibp = dib_tab[i]; i++) { /* loop thru dev */ + dev = dibp -> devno; + dibp -> cmd = CMD (dev); + dibp -> ctl = CTL (dev); + dibp -> flg = FLG (dev); + dibp -> fbf = FBF (dev); } +pcq_r -> qptr = pcq_p; /* update pc q ptr */ return reason; } @@ -1070,16 +1399,16 @@ return r; /* Calculate interrupt requests This routine takes into account all the relevant state of the - interrupt system: ion, dev_flg, dev_buf, and dev_ctl. + interrupt system: ion, dev_flg, dev_fbf, and dev_ctl. 1. dev_flg & dev_ctl determines the end of the priority grant. The break in the chain will occur at the first device for - which dev_flag & dev_ctl is true. This is determined by + which dev_flg & dev_ctl is true. This is determined by AND'ing the set bits with their 2's complement; only the low order (highest priority) bit will differ. 1 less than that, or'd with the single set bit itself, is the mask of - possible interrupting devices. If ION is clear, only devices - 4 and 5 are eligible to interrupt. + possible interrupting devices. If ION is clear, only devices + 4 and 5 are eligible to interrupt. 2. dev_flg & dev_ctl & dev_fbf determines the outstanding interrupt requests. All three bits must be on for a device to request an interrupt. This is the masked under the @@ -1109,12 +1438,199 @@ else { req[0] = req[0] & (INT_M (PWR) | INT_M (PRO)); if (req[0]) { /* if low request */ for (j = 0; j < 32; j++) { /* find dev # */ if (req[0] & INT_M (j)) return j; } } -if (req[1]) { /* if hi request */ +if (req[1]) { /* if hi request */ for (j = 0; j < 32; j++) { /* find dev # */ if (req[1] & INT_M (j)) return (32 + j); } } return 0; } +/* Memory access routines */ + +uint8 ReadB (int32 va) +{ +int32 pa; + +if (dms_enb) pa = dms (va >> 1, dms_ump, RD); +else pa = va >> 1; +if (va & 1) return (M[pa] & 0377); +else return ((M[pa] >> 8) & 0377); +} + +uint8 ReadBA (int32 va) +{ +int32 pa; + +if (dms_enb) pa = dms (va >> 1, dms_ump ^ MAP_LNT, RD); +else pa = va >> 1; +if (va & 1) return (M[pa] & 0377); +else return ((M[pa] >> 8) & 0377); +} + +uint16 ReadW (int32 va) +{ +int32 pa; + +if (dms_enb) pa = dms (va, dms_ump, RD); +else pa = va; +return M[pa]; +} + +uint16 ReadWA (int32 va) +{ +int32 pa; + +if (dms_enb) pa = dms (va, dms_ump ^ MAP_LNT, RD); +else pa = va; +return M[pa]; +} + +uint32 ReadF (int32 va) +{ +uint32 t = ReadW (va); +uint32 t1 = ReadW ((va + 1) & VAMASK); +return (t << 16) | t1; +} + +uint16 ReadIO (int32 va, int32 map) +{ +int32 pa; + +if (dms_enb) pa = dms (va, map, RD); +else pa = va; +return M[pa]; +} + +void WriteB (int32 va, int32 dat) +{ +int32 pa; + +if (MP_TEST (va)) ABORT (ABORT_FENCE); +if (dms_enb) pa = dms (va >> 1, dms_ump ^ MAP_LNT, WR); +else pa = va >> 1; +if (MEM_ADDR_OK (pa)) { + if (va & 1) M[pa] = (M[pa] & 0177400) | (dat & 0377); + else M[pa] = (M[pa] & 0377) | ((dat & 0377) << 8); } +return; +} + +void WriteBA (int32 va, int32 dat) +{ +int32 pa; + +if (MP_TEST (va)) ABORT (ABORT_FENCE); +if (dms_enb) pa = dms (va >> 1, dms_ump ^ MAP_LNT, WR); +else pa = va >> 1; +if (MEM_ADDR_OK (pa)) { + if (va & 1) M[pa] = (M[pa] & 0177400) | (dat & 0377); + else M[pa] = (M[pa] & 0377) | ((dat & 0377) << 8); } +return; +} + +void WriteW (int32 va, int32 dat) +{ +int32 pa; + +if (MP_TEST (va)) ABORT (ABORT_FENCE); +if (dms_enb) pa = dms (va, dms_ump, WR); +else pa = va; +if (MEM_ADDR_OK (pa)) M[pa] = dat; +return; +} + +void WriteWA (int32 va, int32 dat) +{ +int32 pa; + +if (MP_TEST (va)) ABORT (ABORT_FENCE); +if (dms_enb) pa = dms (va, dms_ump ^ MAP_LNT, WR); +else pa = va; +if (MEM_ADDR_OK (pa)) M[pa] = dat; +return; +} + +void WriteIO (int32 va, int32 dat, int32 map) +{ +int32 pa; + +if (dms_enb) pa = dms (va, map, WR); +else pa = va; +if (MEM_ADDR_OK (pa)) M[pa] = dat; +return; +} + +/* DMS relocation */ + +int32 dms (int32 va, int32 map, int32 prot) +{ +int32 pgn, mpr; + +if (va <= 1) return va; /* A, B */ +pgn = VA_GETPAG (va); /* get page num */ +if (pgn == 0) { /* base page? */ + if ((dms_sr & MST_FLT)? /* check unmapped */ + (va >= dms_fence): /* 1B10: >= fence */ + (va < dms_fence)) { /* 0B10: < fence */ + if (prot == WR) dms_viol (va, MVI_BPG, 0); /* if W, viol */ + return va; } } /* no mapping */ +mpr = dms_map[map + pgn]; /* get map reg */ +if (mpr & prot) dms_viol (va, prot << (MVI_V_WPR - MAPA_V_WPR), 0); +return (PA_GETPAG (mpr) | VA_GETOFF (va)); +} + +/* DMS read and write maps */ + +uint16 dms_rmap (int32 mapi) +{ +int32 t; +mapi = mapi & MAP_MASK; +t = (((dms_map[mapi] >> VA_N_OFF) & PA_M_PAG) | + ((dms_map[mapi] & (RD | WR)) << (MAPM_V_WPR - MAPA_V_WPR))); +return (uint16) t; +} + +void dms_wmap (int32 mapi, int32 dat) +{ +mapi = mapi & MAP_MASK; +dms_map[mapi] = ((dat & PA_M_PAG) << VA_N_OFF) | + ((dat >> (MAPM_V_WPR - MAPA_V_WPR)) & (RD | WR)); +return; +} + +/* DMS violation + + DMS violation processing occurs in two parts + - The violation register is set based on DMS status + - An interrupt (abort) occurs only if CTL (PRO) is set + + Bit 7 (ME bus disabled/enabled) records whether relocation + actually occurred in the aborted cycle. For read and write + violations, bit 7 will be set; for base page and privilege + violations, it will be clear + + I/O map references set status bits but never abort +*/ + +void dms_viol (int32 va, int32 st, t_bool io) +{ +dms_sr = st | VA_GETPAG (va) | + ((st & (MVI_RPR | MVI_WPR))? MVI_MEB: 0) | /* set MEB */ + (dms_enb? MVI_MEM: 0) | /* set MEM */ + (dms_ump? MVI_UMP: 0); /* set UMAP */ +if (CTL (PRO) && !io) ABORT (ABORT_DMS); +return; +} + +/* DMS update status */ + +int32 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 (CTL (PRO)) dms_sr = dms_sr | MST_PRO; +return dms_sr; +} + /* Device 0 (CPU) I/O routine */ int32 cpuio (int32 inst, int32 IR, int32 dat) @@ -1126,10 +1642,10 @@ case ioFLG: /* flag */ ion = (IR & HC)? 0: 1; /* interrupts off/on */ return dat; case ioSFC: /* skip flag clear */ - if (!ion) PC = (PC + 1) & AMASK; + if (!ion) PC = (PC + 1) & VAMASK; return dat; case ioSFS: /* skip flag set */ - if (ion) PC = (PC + 1) & AMASK; + if (ion) PC = (PC + 1) & VAMASK; return dat; case ioLIX: /* load */ dat = 0; /* returns 0 */ @@ -1153,10 +1669,10 @@ case ioFLG: /* flag */ O = (IR & HC)? 0: 1; /* clear/set overflow */ return dat; case ioSFC: /* skip flag clear */ - if (!O) PC = (PC + 1) & AMASK; + if (!O) PC = (PC + 1) & VAMASK; break; /* can clear flag */ case ioSFS: /* skip flag set */ - if (O) PC = (PC + 1) & AMASK; + if (O) PC = (PC + 1) & VAMASK; break; /* can clear flag */ case ioMIX: /* merge */ dat = dat | SR; @@ -1195,7 +1711,7 @@ int32 proio (int32 inst, int32 IR, int32 dat) { switch (inst) { /* case on opcode */ case ioSFC: /* skip flag clear */ - if (FLG (PRO)) PC = (PC + 1) & AMASK; + if (FLG (PRO)) PC = (PC + 1) & VAMASK; return dat; case ioSFS: /* skip flag set */ return dat; @@ -1206,7 +1722,7 @@ case ioLIX: /* load */ dat = maddr; break; case ioOTX: /* output */ - mfence = dat & AMASK; + mfence = dat & VAMASK; break; case ioCTL: /* control clear/set */ if ((IR & AB) == 0) { /* STC */ @@ -1258,10 +1774,10 @@ case ioFLG: /* flag */ if ((IR & HC) == 0) { clrCMD (DMA0 + ch); } /* set -> abort */ break; case ioSFC: /* skip flag clear */ - if (FLG (DMA0 + ch) == 0) PC = (PC + 1) & AMASK; + if (FLG (DMA0 + ch) == 0) PC = (PC + 1) & VAMASK; return dat; case ioSFS: /* skip flag set */ - if (FLG (DMA0 + ch) != 0) PC = (PC + 1) & AMASK; + if (FLG (DMA0 + ch) != 0) PC = (PC + 1) & VAMASK; return dat; case ioMIX: case ioLIX: /* load, merge */ dat = DMASK; @@ -1282,17 +1798,17 @@ return dat; /* DMA cycle routine */ -void dma_cycle (int32 ch) +void dma_cycle (int32 ch, int32 map) { int32 temp, dev, MA; dev = dmac[ch].cw1 & DEVMASK; /* get device */ -MA = dmac[ch].cw2 & AMASK; /* get mem addr */ +MA = dmac[ch].cw2 & VAMASK; /* get mem addr */ if (dmac[ch].cw2 & DMA2_OI) { /* input? */ temp = devdisp (dev, ioLIX, HC + dev, 0); /* do LIA dev,C */ - if (MEM_ADDR_OK (MA)) M[MA] = temp & DMASK; } /* store data */ -else devdisp (dev, ioOTX, HC + dev, M[MA]); /* do OTA dev,C */ -dmac[ch].cw2 = (dmac[ch].cw2 & DMA2_OI) | ((dmac[ch].cw2 + 1) & AMASK); + WriteIO (MA, temp & DMASK, map); } /* store data */ +else devdisp (dev, ioOTX, HC + dev, ReadIO (MA, map)); /* do OTA dev,C */ +dmac[ch].cw2 = (dmac[ch].cw2 & DMA2_OI) | ((dmac[ch].cw2 + 1) & VAMASK); dmac[ch].cw3 = (dmac[ch].cw3 + 1) & DMASK; /* incr wcount */ if (dmac[ch].cw3) { /* more to do? */ if (dmac[ch].cw1 & DMA1_STC) devdisp (dev, ioCTL, dev, 0); } @@ -1310,7 +1826,7 @@ int32 nulio (int32 inst, int32 IR, int32 dat) { switch (inst) { /* case on opcode */ case ioSFC: /* skip flag clear */ - PC = (PC + 1) & AMASK; + PC = (PC + 1) & VAMASK; return (stop_dev << IOT_V_REASON) | dat; case ioSFS: /* skip flag set */ return (stop_dev << IOT_V_REASON) | dat; @@ -1339,7 +1855,15 @@ clrFLG (PRO); clrFBF (PRO); mfence = 0; maddr = 0; +dms_enb = dms_ump = 0; +dms_sr = dms_fence = 0; +dms_vr = dms_sma = 0; +pcq_r = find_reg ("PCQ", NULL, dptr); sim_brk_types = sim_brk_dflt = SWMASK ('E'); +if (M == NULL) M = calloc (PASIZE, sizeof (unsigned int16)); +if (M == NULL) return SCPE_MEM; +if (pcq_r) pcq_r -> qptr = 0; +else return SCPE_IERR; return SCPE_OK; } @@ -1393,63 +1917,103 @@ t_stat cpu_set_size (UNIT *uptr, int32 val, char *cptr, void *desc) int32 mc = 0; t_addr i; -if ((val <= 0) || (val > MAXMEMSIZE) || ((val & 07777) != 0)) +if ((val <= 0) || (val > PASIZE) || ((val & 07777) != 0) || + (!(uptr -> flags & UNIT_21MX) && (val > 32768))) return SCPE_ARG; for (i = val; i < MEMSIZE; i++) mc = mc | M[i]; if ((mc != 0) && (!get_yn ("Really truncate memory [N]?", FALSE))) return SCPE_OK; MEMSIZE = val; -for (i = MEMSIZE; i < MAXMEMSIZE; i++) M[i] = 0; +for (i = MEMSIZE; i < PASIZE; i++) M[i] = 0; return SCPE_OK; } /* Set/show device number */ -t_stat hp_setdev (UNIT *uptr, int32 ord, char *cptr, void *desc) +t_stat hp_setdev (UNIT *uptr, int32 num, char *cptr, void *desc) { int32 i, newdev; +DIB *dibp = (DIB *) desc; t_stat r; if (cptr == NULL) return SCPE_ARG; -newdev = get_uint (cptr, 8, DEVMASK, &r); +if ((dibp == NULL) || (num > 1)) return SCPE_IERR; +newdev = get_uint (cptr, 8, DEVMASK - num, &r); if (r != SCPE_OK) return r; if (newdev < VARDEV) return SCPE_ARG; -for (i = 0; infotab[i].devno != 0; i++) { - if ((i != ord) && (newdev == infotab[i].devno)) - return SCPE_ARG; } -infotab[ord].devno = newdev; +for (i = 0; i <= num; i++, dibp++) dibp -> devno = newdev + i; return SCPE_OK; } -t_stat hp_showdev (FILE *st, UNIT *uptr, int32 ord, void *desc) +t_stat hp_showdev (FILE *st, UNIT *uptr, int32 num, void *desc) { -fprintf (st, "devno=%o", infotab[ord].devno); +int32 i; +DIB *dibp = (DIB *) desc; + +if (dibp == NULL) return SCPE_IERR; +fprintf (st, "devno=%o", dibp -> devno); +for (i = 1; i <= num; i++) fprintf (st, "/%o", dibp -> devno + i); return SCPE_OK; } -/* Set/show device number for data/control pair */ +/* Enable a device */ -t_stat hp_setdev2 (UNIT *uptr, int32 ord, char *cptr, void *desc) +t_stat set_enb (UNIT *uptr, int32 num, char *cptr, void *desc) { -int32 i, olddev, newdev; -t_stat r; +int32 i; +DEVICE *dptr; +DIB *dibp; -olddev = infotab[ord].devno; -if ((r = hp_setdev (uptr, ord, cptr, NULL)) != SCPE_OK) return r; -newdev = infotab[ord].devno + 1; -if (newdev > DEVMASK) { - infotab[ord].devno = olddev; - return SCPE_ARG; } -for (i = 0; infotab[i].devno != 0; i++) { - if ((i != (ord + 1)) && (newdev == infotab[i].devno)) { - infotab[ord].devno = olddev; - return SCPE_ARG; } } -infotab[ord + 1].devno = infotab[ord].devno + 1; -return SCPE_OK; +if (cptr != NULL) return SCPE_ARG; +if ((uptr == NULL) || (desc == NULL)) return SCPE_IERR; +dptr = find_dev_from_unit (uptr); /* find device */ +if (dptr == NULL) return SCPE_IERR; +dibp = (DIB *) desc; +if (dibp -> enb) return SCPE_OK; /* already enb? */ +for (i = 0; i <= num; i++, dibp++) dibp -> enb = 1; +if (dptr -> reset) return dptr -> reset (dptr); +else return SCPE_OK; } -t_stat hp_showdev2 (FILE *st, UNIT *uptr, int32 ord, void *desc) +/* Disable a device */ + +t_stat set_dis (UNIT *uptr, int32 num, char *cptr, void *desc) { -fprintf (st, "devno=%o/%o", infotab[ord].devno, infotab[ord + 1].devno); -return SCPE_OK; +int32 i; +DEVICE *dptr; +DIB *dibp; +UNIT *up; + +if (cptr != NULL) return SCPE_ARG; +if ((uptr == NULL) || (desc == NULL)) return SCPE_IERR; +dptr = find_dev_from_unit (uptr); /* find device */ +if (dptr == NULL) return SCPE_IERR; +dibp = (DIB *) desc; +if (dibp -> enb == 0) return SCPE_OK; /* already dis? */ +for (i = 0; i < dptr -> numunits; i++) { /* check units */ + up = (dptr -> units) + i; + if ((up -> flags & UNIT_ATT) || sim_is_active (up)) + return SCPE_NOFNC; } +for (i = 0; i <= num; i++, dibp++) dibp -> enb = 0; +if (dptr -> reset) return dptr -> reset (dptr); +else return SCPE_OK; +} + +/* Test for device conflict */ + +t_bool dev_conflict (void) +{ +DIB *dibp, *chkp; +int32 i, j, dno; + +for (i = 0; chkp = dib_tab[i]; i++) { + if (chkp -> enb) { + dno = chkp -> devno; + for (j = 0; dibp = dib_tab[j]; j++) { + if (dibp -> enb && (chkp != dibp) && (dno == dibp -> devno)) { + printf ("Device number conflict, devno = %d\n", dno); + if (sim_log) fprintf (sim_log, + "Device number conflict, devno = %d\n", dno); + return TRUE; } } } } +return FALSE; } diff --git a/HP2100/hp2100_defs.h b/HP2100/hp2100_defs.h index 7c6472c7..f9c771d4 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-2001, Robert M. Supnik + Copyright (c) 1993-2002, Robert M. Supnik Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), @@ -23,6 +23,9 @@ be used in advertising or otherwise to promote the sale, use or other dealings in this Software without prior written authorization from Robert M Supnik. + 08-Feb-02 RMS Added DMS definitions + 01-Feb-02 RMS Added terminal multiplexor support + 16-Jan-02 RMS Added additional device support 30-Nov-01 RMS Added extended SET/SHOW support 15-Oct-00 RMS Added dynamic device numbers 14-Apr-99 RMS Changed t_addr to unsigned @@ -41,17 +44,25 @@ #define STOP_IBKPT 4 /* breakpoint */ #define STOP_IND 5 /* indirect loop */ +#define ABORT_DMS 1 /* DMS abort */ +#define ABORT_FENCE -1 /* fence abort */ + /* Memory */ -#define MAXMEMSIZE 32768 /* max memory size */ #define MEMSIZE (cpu_unit.capac) /* actual memory size */ -#define AMASK (MAXMEMSIZE - 1) /* address mask */ #define MEM_ADDR_OK(x) (((t_addr) (x)) < MEMSIZE) +#define VA_N_SIZE 15 /* virtual addr size */ +#define VASIZE (1 << VA_N_SIZE) +#define VAMASK (VASIZE - 1) /* virt addr mask */ +#define PA_N_SIZE 20 /* phys addr size */ +#define PASIZE (1 << PA_N_SIZE) +#define PAMASK (PASIZE - 1) /* phys addr mask */ /* Architectural constants */ -#define SIGN 0100000 /* sign */ -#define DMASK 0177777 /* data mask */ +#define SIGN32 020000000000 /* 32b sign */ +#define SIGN 0100000 /* 16b sign */ +#define DMASK 0177777 /* 16b data mask */ #define AR M[0] /* A = location 0 */ #define BR M[1] /* B = location 1 */ #define ABREG M /* register array */ @@ -87,6 +98,67 @@ struct DMA { /* DMA channel */ int32 cw3; /* word count */ }; +/* Memory management */ + +#define VA_N_OFF 10 /* offset width */ +#define VA_M_OFF ((1 << VA_N_OFF) - 1) /* offset mask */ +#define VA_GETOFF(x) ((x) & VA_M_OFF) +#define VA_N_PAG (VA_N_SIZE - VA_N_OFF) /* page width */ +#define VA_V_PAG (VA_N_OFF) +#define VA_M_PAG ((1 << VA_N_PAG) - 1) +#define VA_GETPAG(x) (((x) >> VA_V_PAG) & VA_M_PAG) + +/* Maps */ + +#define MAP_NUM 4 /* num maps */ +#define MAP_LNT (1 << VA_N_PAG) /* map length */ +#define MAP_MASK ((MAP_NUM * MAP_LNT) - 1) +#define SMAP 0 /* system map */ +#define UMAP (SMAP + MAP_LNT) /* user map */ +#define PAMAP (UMAP + MAP_LNT) /* port A map */ +#define PBMAP (PAMAP + MAP_LNT) /* port B map */ + +/* Map entries are left shifted by VA_N_OFF, flags in lower 2b */ + +#define PA_N_PAG (PA_N_SIZE - VA_N_OFF) /* page width */ +#define PA_V_PAG (VA_N_OFF) +#define PA_M_PAG ((1 << PA_N_PAG) - 1) +#define MAPM_V_RPR 15 /* in mem: read prot */ +#define MAPM_V_WPR 14 /* write prot */ +#define MAPA_V_RPR 1 /* in array: */ +#define MAPA_V_WPR 0 +#define PA_GETPAG(x) ((x) & (PA_M_PAG << VA_V_PAG)) +#define RD (1 << MAPA_V_RPR) +#define WR (1 << MAPA_V_WPR) + +/* Map status register */ + +#define MST_ENBI 0100000 /* mem enb @ int */ +#define MST_UMPI 0040000 /* usr map @ int */ +#define MST_ENB 0020000 /* mem enb */ +#define MST_UMP 0010000 /* usr map */ +#define MST_PRO 0004000 /* protection */ +#define MST_FLT 0002000 /* fence comp */ +#define MST_FENCE 0001777 /* base page fence */ + +/* Map violation register */ + +#define MVI_V_RPR 15 +#define MVI_V_WPR 14 +#define MVI_RPR (1 << MVI_V_RPR) /* rd viol */ +#define MVI_WPR (1 << MVI_V_WPR) /* wr viol */ +#define MVI_BPG 0020000 /* base page viol */ +#define MVI_PRV 0010000 /* priv viol */ +#define MVI_MEB 0000200 /* me bus enb @ viol */ +#define MVI_MEM 0000100 /* mem enb @ viol */ +#define MVI_UMP 0000040 /* usr map @ viol */ +#define MVI_PAG 0000037 /* pag sel */ + +/* Timers */ + +#define TMR_CLK 0 /* clock */ +#define TMR_MUX 1 /* multiplexor */ + /* I/O sub-opcodes */ #define ioHLT 0 /* halt */ @@ -121,17 +193,25 @@ struct DMA { /* DMA channel */ #define PTP 012 /* paper tape punch */ #define CLK 013 /* clock */ #define LPT 014 /* line printer */ -#define MTD 020 /* mag tape data */ -#define MTC 021 /* mag tape control */ -#define DPD 022 /* disk pack data */ -#define DPC 023 /* disk pack control */ -#define DPBD 024 /* second disk pack data */ -#define DPBC 025 /* second disk pack control */ +#define MTD 020 /* 12559A data */ +#define MTC 021 /* 12559A control */ +#define DPD 022 /* 12557A data */ +#define DPC 023 /* 12557A control */ +#define DQD 024 /* 12565A data */ +#define DQC 025 /* 12565A control */ +#define DRD 026 /* 12610A data */ +#define DRC 027 /* 12610A control */ +#define MSD 030 /* 13181A data */ +#define MSC 031 /* 13181A control */ +#define MUXL 040 /* 12920A lower data */ +#define MUXU 041 /* 12920A upper data */ +#define MUXC 042 /* 12920A control */ /* Dynamic device information table */ -struct hpdev { +struct hp_dib { int32 devno; /* device number */ + int32 enb; /* enabled */ int32 cmd; /* saved command */ int32 ctl; /* saved control */ int32 flg; /* saved flag */ @@ -139,21 +219,7 @@ struct hpdev { int32 (*iot)(); /* I/O routine */ }; -/* Offsets in device information table */ - -#define inPTR 0 /* infotab ordinals */ -#define inPTP 1 -#define inTTY 2 -#define inCLK 3 -#define inLPT 4 -#define inMTD 5 -#define inMTC 6 -#define inDPD 7 -#define inDPC 8 -#define inDPBD 9 -#define inDPBC 10 - -#define UNIT_DEVNO (1 << UNIT_V_UF) /* dummy flag */ +typedef struct hp_dib DIB; /* I/O macros */ @@ -181,5 +247,5 @@ struct hpdev { t_stat hp_setdev (UNIT *uptr, int32 val, char *cptr, void *desc); t_stat hp_showdev (FILE *st, UNIT *uptr, int32 val, void *desc); -t_stat hp_setdev2 (UNIT *uptr, int32 val, char *cptr, void *desc); -t_stat hp_showdev2 (FILE *st, UNIT *uptr, int32 val, void *desc); +t_stat set_enb (UNIT *uptr, int32 num, char *cptr, void *desc); +t_stat set_dis (UNIT *uptr, int32 num, char *cptr, void *desc); diff --git a/HP2100/hp2100_doc.txt b/HP2100/hp2100_doc.txt index c120b6b5..31bd6d98 100644 --- a/HP2100/hp2100_doc.txt +++ b/HP2100/hp2100_doc.txt @@ -1,14 +1,14 @@ To: Users From: Bob Supnik Subj: HP2100 Simulator Usage -Date: 1-Dec-01 +Date: 15-Jun-2002 COPYRIGHT NOTICE The following copyright notice applies to both the SIMH source and binary: - Original code published in 1993-2001, written by Robert M Supnik - Copyright (c) 1993-2001, Robert M Supnik + Original code published in 1993-2002, written by Robert M Supnik + Copyright (c) 1993-2002, Robert M Supnik Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), @@ -43,9 +43,14 @@ sim/ sim_defs.h sim/hp2100/ hp2100_defs.h hp2100_cpu.c + hp2100_fp.c hp2100_dp.c + hp2100_dq.c + hp2100_dr.c hp2100_lp.c hp2100_mt.c + hp2100_ms.c + hp2100_mux.c hp2100_stddev.c hp2100_sys.c @@ -62,8 +67,12 @@ PTR,PTP 12597A paper tape reader/punch TTY 12631C buffered teleprinter LPT 12653A line printer CLK 12539A/B/C time base generator -DP 12557A cartridge disk controller with four drives +MUXL,MUXU,MUXC 12920A terminal multiplexor +DP 12557A/13210A disk controller with four drives +DQ 12565A disk controller with two drives +DR 12606A/12610A fixed head disk/drum controller MT 12559C magnetic tape controller with one drives +MS 13181A magnetic tape controller with four drives The HP2100 simulator implements several unique stop conditions: @@ -116,7 +125,8 @@ control registers for the interrupt system. STOP_INST 1 stop on undefined instruction STOP_DEV 1 stop on undefined device INDMAX 1 indirect address limit - OLDP 15 PC prior to last JMP, JSB, or interrupt + PCQ[0:63] 15 PC of last JMP, JSB, or interrupt; + most recent PC change first WRU 8 interrupt character 2.2 DMA Controllers @@ -140,22 +150,34 @@ On the HP2100, I/O device take their device numbers from the backplane slot they are plugged into. Thus, device number assignments vary considerably from system to system, and software package to software package. The HP2100 simulator supports dynamic device number assignment. -The current device device is shown with the command SHOW DEVNO: +To show the current device number, use the SHOW DEVNO command: sim> SHOW PTR DEV device=10 -The user can change the device number with the SET DEVNO= -command: +To change the device number, use the SET DEVNO= command: sim> SET PTR DEV=30 sim> SHOW PTR DEV device=30 -The new device number must be in the range 010..077 (octal) and must -not be currently assigned to another device. For devices with two -device numbers, only the lower numbered device number can be changed; -the higher is automatically set to the lower + 1. +The new device number must be in the range 010..077 (octal). For devices +with two device numbers, only the lower numbered device number can be +changed; the higher is automatically set to the lower + 1. If a +device number conflict occurs, the simulator will return an error +message when started. + +In addition, most devices can be enabled or disabled. To enable a +device, use the SET ENABLED command: + + sim> SET DP ENABLED + +To disable a device, use the SET DISABLED command: + + sim> SET DP DISABLED + +For devices with two device numbers, disabling or enabling one device +in the pair disables or enables the other. 2.4 Programmed I/O Devices @@ -177,10 +199,9 @@ The paper tape reader implements these registers: CTL 1 device/interrupt enable FLG 1 device ready FBF 1 device ready buffer - POS 31 position in the input file + POS 32 position in the input file TIME 24 time from I/O initiation to interrupt STOP_IOE 1 stop on I/O error - DEVNO 6 current device number (read only) Error handling is as follows: @@ -209,10 +230,9 @@ The paper tape punch implements these registers: CTL 1 device/interrupt enable FLG 1 device ready FBF 1 device ready buffer - POS 31 position in the output file + POS 32 position in the output file TIME 24 time from I/O initiation to interrupt STOP_IOE 1 stop on I/O error - DEVNO 6 current device number (read only) Error handling is as follows: @@ -241,13 +261,12 @@ The terminal implements these registers: CTL 1 device/interrupt enable FLG 1 device ready FBF 1 device ready buffer - KPOS 31 number of characters input + KPOS 32 number of characters input KTIME 24 keyboard polling interval - TPOS 31 number of characters printed + TPOS 32 number of characters printed TTIME 24 time from I/O initiation to interrupt - PPOS 31 position in the punch output file + PPOS 32 position in the punch output file STOP_IOE 1 punch stop on I/O error - DEVNO 6 current device number (read only) Error handling for the punch is as follows: @@ -273,11 +292,10 @@ The line printer implements these registers: CTL 1 device/interrupt enable FLG 1 device ready FBF 1 device ready buffer - POS 31 position in the output file + POS 32 position in the output file CTIME 24 time between characters PTIME 24 time for a print operation STOP_IOE 1 stop on I/O error - DEVNO 6 current device number (read only) Error handling is as follows: @@ -302,12 +320,106 @@ The time base generator (CLK) implements these registers: TIME[0:7] 31 clock intervals, select = 0..7 DEVNO 6 current device number (read only) -2.5 12557A Cartridge Disk (DP) +2.4.6 12920A Terminal Multiplexor (MUXL, MUXU, MUXC) -The 12557A cartridge disk has two separate devices, a data channel and +The 12920A is a 16-line terminal multiplexor, with five additional +receive-only diagnostic lines. It consists of three devices: + + MUX scanning logic (corresponding more or less + to the upper data card) + MUXL individual lines (corresponding more or + less to the lower data card) + MUXC modem control and status logic (corresponding + to the control card) + +The MUX performs input and output through Telnet sessions connected to a +user-specified port. The ATTACH command to the scanning logic specifies +the port to be used: + + ATTACH MUX set up listening port + +where port is a decimal number between 1 and 65535 that is not being used +for other TCP/IP activities. + +Each line (each unit of MUXL) supports two options. UC, when set, causes +lower case input characters to be automatically converted to upper case. +DATASET, when set, enables modem control. By default, UC is on, and +DATASET is off. + +The modem controls model a simplified Bell 103A dataset with just four +lines: data terminal ready and request to send from the computer to the +data set, and carrier detect and data set ready from the data set to +the computer. There is no ring detection. If data terminal ready is +set when a Telnet connection starts up, then carrier detect and data +set ready are also set. The connection is established whether data +terminal ready is set or not. + +Once MUX is attached and the simulator is running, the multiplexor listens +for connections on the specified port. It assumes that the incoming +connections are Telnet connections. The connections remain open until +disconnected either by the Telnet client, a SET MUXL DISCONNECT command, +or a DETACH MUX command. + +The SHOW MUX CONNECTIONS command displays the current connections to the +extra terminals. The SHOW MUX STATISTICS command displays statistics for +active connections. The SET MUX DISCONNECT=linenumber disconnects the +specified line. + +The scanner (MUX) implements these registers: + + name size comments + + IBUF 16 input buffer, holds line status + OBUF 16 output buffer, holds channel select + +The lines (MUXL) implements these registers: + + name size comments + + CTL 1 device/interrupt enable + FLG 1 device ready + FBF 1 device ready buffer + STA[0:20] 16 line status, lines 0-20 + RPAR[0:20] 16 receive parameters, lines 0-20 + XPAR[0:15] 16 transmit parameters, lines 0-15 + RBUF[0:20] 8 receive buffer, lines 0-20 + XBUF[0:15] 8 transmit buffer, lines 0-15 + RCHP[0:20] 1 receive character present, lines 0-20 + XDON[0:15] 1 transmit done, lines 0-15 + TIME[0:15] 24 transmit time, lines 0-15 + +The modem control (MUXM) implements these registers: + + name size comments + + CTL 1 device/interrupt enable + FLG 1 device ready + FBF 1 device ready buffer + SCAN 1 scan enabled + CHAN 4 current line + DSO[0:15] 6 C2,C1,ES2,ES1,SS2,SS1, lines 0-15 + DSI[0:15] 2 S2,S1, lines 0-15 + + +The terminal multiplexor does not support save and restore. All open +connections are lost when the simulator shuts down or MUXU is detached. + +2.5 12557A/13210A Disk Controller (DP) + +The 12557A/13210A disk controller can be configured as either a +12557A, supporting 2.5MB drives, or a 13210A, supporting 5MB drives, +with the commands: + + SET DP 12557A 2.5MB drives + SET DP 13210A 5.0MB drives + +Drive types cannot be intermixed; the controller is configured for +one type or the other. + +The simulated controller has two separate devices, a data channel and a device controller. The data channel includes a 128-word (one sector) buffer for reads and writes. The device controller includes the four -disk drives. Disk drives can be REMOVEd or ADDed to the configuration. +disk drives. Disk drives can be set ONLINE or OFFLINE. The data channel implements these registers: @@ -315,12 +427,12 @@ The data channel implements these registers: IBUF 16 input buffer OBUF 16 output buffer + DBUF[0:127] 16 sector buffer BPTR 7 sector buffer pointer CMD 1 channel enable CTL 1 interrupt enable FLG 1 channel ready FBF 1 channel ready buffer - DEVNO 6 current device number (read only) The device controller implements these registers: @@ -341,7 +453,6 @@ The device controller implements these registers: STIME 24 seek delay time, per cylinder XTIME 24 interword transfer time STA[0:3] 16 drive status, drives 0-3 - DEVNO 6 current device number (read only) Error handling is as follows: @@ -353,27 +464,125 @@ Error handling is as follows: OS I/O error report error and stop -2.6 12559C Magnetic Tape (MT) +2.6 12565A Disk Controller (DP) + +The 12565A disk controller has two separate devices, a data channel and +a device controller. The data channel includes a 128-word (one sector) +buffer for reads and writes. The device controller includes the two +disk drives. Disk drives can be set ONLINE or OFFLINE. + +The data channel implements these registers: + + name size comments + + IBUF 16 input buffer + OBUF 16 output buffer + DBUF[0:127] 16 sector buffer + BPTR 7 sector buffer pointer + CMD 1 channel enable + CTL 1 interrupt enable + FLG 1 channel ready + FBF 1 channel ready buffer + +The device controller implements these registers: + + name size comments + + OBUF 16 output buffer + BUSY 2 busy (unit #, + 1, of active unit) + RARC 8 record address register cylinder + RARH 5 record address register head + RARS 5 record address register sector + CNT 5 check record count + CMD 1 controller enable + CTL 1 interrupt enable + FLG 1 controller ready + FBF 1 controller ready buffer + EOC 1 end of cylinder pending + CTIME 24 command delay time + STIME 24 seek delay time, per cylinder + XTIME 24 interword transfer time + STA[0:3] 16 drive status, drives 0-3 + +Error handling is as follows: + + error processed as + + not attached disk not ready + + end of file assume rest of disk is zero + + OS I/O error report error and stop + +2.7 12606A/12610A Fixed Head Disk/Drum Controller (DR) + +The 12606A/12610A fixed head disk/drum controller has two separate devices, +a data channel and a device controller. The device controller includes the +actual drive. Ten different models are supported: + + SET DR 180K 12606A, 180K words + SET DR 360K 12606A, 360K words + SET DR 720K 12606A, 720K words + SET DR 384K 12610A, 384K words + SET DR 512K 12610A, 512K words + SET DR 640K 12610A, 640K words + SET DR 768K 12610A, 768K words + SET DR 896K 12610A, 896K words + SET DR 1024K 12610A, 1024K words + SET DR 1536K 12610A, 1536K words + +The data channel implements these registers: + + name size comments + + IBUF 16 input buffer + OBUF 16 output buffer + CMD 1 channel enable + CTL 1 interrupt enable + FLG 1 channel ready + FBF 1 channel ready buffer + BPTR 6 sector buffer pointer + +The device controller implements these registers: + + name size comments + + CW 16 command word + STA 16 status + CMD 1 controller enable + CTL 1 interrupt enable + FLG 1 controller ready + FBF 1 controller ready buffer + TIME 24 interword transfer time + STOP_IOE 1 stop on I/O error + +Error handling is as follows: + + error processed as + + not attached disk not ready + +2.8 12559C Magnetic Tape (MT) Magnetic tape options include the ability to make the unit write enabled or write locked. SET MT LOCKED set unit write locked - SET MT ENABLED set unit write enabled + SET MT WRITEENABLED set unit write enabled The 12559C mag tape drive has two separate devices, a data channel and a device controller. The data channel includes a maximum record sized buffer for reads and writes. The device controller includes the tape -unit +unit. The data channel implements these registers: name size comments FLG 1 channel ready + DBUF[0:65535] 8 transfer buffer BPTR 16 buffer pointer (reads and writes) BMAX 16 buffer size (writes) - DEVNO 6 current device number (read only) The device controller implements these registers: @@ -382,17 +591,15 @@ The device controller implements these registers: FNC 8 current function STA 9 tape status BUF 8 buffer - BUSY 3 busy (unit #, + 1, of active unit) CTL 1 interrupt enabled FLG 1 controller ready FBF 1 controller ready buffer DTF 1 data transfer flop FSVC 1 first service flop - POS 31 magtape position + POS 32 magtape position CTIME 24 command delay time XTIME 24 interword transfer delay time STOP_IOE 1 stop on I/O error - DEVNO 6 current device number (read only) Error handling is as follows: @@ -405,7 +612,59 @@ Error handling is as follows: OS I/O error report error and stop -2.7 Symbolic Display and Input +2.9 13181A Magnetic Tape (MS) + +Magnetic tape options include the ability to make the unit write enabled +or write locked. + + SET MT LOCKED set unit write locked + SET MT WRITEENABLED set unit write enabled + +The 13181A mag tape drive has two separate devices, a data channel and +a device controller. The data channel includes a maximum record sized +buffer for reads and writes. The device controller includes the tape +units. + +The data channel implements these registers: + + name size comments + + BUF 16 data buffer + CTL 1 interrupt enabled + FLG 1 channel ready + FBF 1 channel ready buffer + DBUF[0:65535] 8 transfer buffer + BPTR 17 buffer pointer (reads and writes) + BMAX 17 buffer size (writes) + +The device controller implements these registers: + + name size comments + + STA 12 tape status + BUF 16 buffer + USEL 2 currently selected unit + FSVC 1 first service flop + CTL 1 interrupt enabled + FLG 1 controller ready + FBF 1 controller ready buffer + POS[0:3] 32 magtape position + CTIME 24 command delay time + XTIME 24 interword transfer delay time + STOP_IOE 1 stop on I/O error + +Error handling is as follows: + + error processed as + + not attached tape not ready + + end of file (read or space) end of physical tape + (write) ignored + + OS I/O error report error and stop + +2.10 Symbolic Display and Input The HP2100 simulator implements symbolic display and input. Display is controlled by command line switches: diff --git a/HP2100/hp2100_dp.c b/HP2100/hp2100_dp.c index 59c926ca..514dc891 100644 --- a/HP2100/hp2100_dp.c +++ b/HP2100/hp2100_dp.c @@ -1,6 +1,6 @@ -/* hp2100_dp.c: HP 2100 disk pack simulator +/* hp2100_dp.c: HP 2100 12557A/13210A disk pack simulator - Copyright (c) 1993-2001, Robert M. Supnik + Copyright (c) 1993-2002, Robert M. Supnik Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), @@ -23,8 +23,10 @@ be used in advertising or otherwise to promote the sale, use or other dealings in this Software without prior written authorization from Robert M Supnik. - dp 12557A cartridge disk system + dp 12557A/13210A disk pack subsystem + 15-Jan-02 RMS Fixed INIT handling (found by Bill McDermith) + 10-Jan-02 RMS Fixed f(x)write call (found by Bill McDermith) 03-Dec-01 RMS Changed DEVNO to use extended SET/SHOW 24-Nov-01 RMS Changed STA to be an array 07-Sep-01 RMS Moved function prototypes @@ -40,12 +42,15 @@ #define FNC u3 /* saved function */ #define CYL u4 /* cylinder */ -#define DP_W_NUMWD 7 -#define DP_NUMWD (1 << DP_W_NUMWD) /* words/sector */ -#define DP_NUMSC 12 /* sectors/track */ -#define DP_NUMTR 203 /* tracks/surface */ -#define DP_NUMSF 4 /* surfaces/track */ -#define DP_SIZE (DP_NUMSF * DP_NUMTR * DP_NUMSC * DP_NUMWD) +#define DP_N_NUMWD 7 +#define DP_NUMWD (1 << DP_N_NUMWD) /* words/sector */ +#define DP_NUMSC2 12 /* sectors/srf 12557 */ +#define DP_NUMSC3 24 /* sectors/srf 13210 */ +#define DP_NUMSC (dp_ctype? DP_NUMSC3: DP_NUMSC2) +#define DP_NUMSF 4 /* surfaces/cylinder */ +#define DP_NUMCY 203 /* cylinders/disk */ +#define DP_SIZE2 (DP_NUMSF * DP_NUMCY * DP_NUMSC2 * DP_NUMWD) +#define DP_SIZE3 (DP_NUMSF * DP_NUMCY * DP_NUMSC3 * DP_NUMWD) #define DP_NUMDRV 4 /* # drives */ /* Command word */ @@ -78,8 +83,13 @@ #define DA_M_HD 03 #define DA_GETHD(x) (((x) >> DA_V_HD) & DA_M_HD) #define DA_V_SC 0 /* sector */ -#define DA_M_SC 017 +#define DA_M_SC2 017 +#define DA_M_SC3 037 +#define DA_M_SC (dp_ctype? DA_M_SC3: DA_M_SC2) #define DA_GETSC(x) (((x) >> DA_V_SC) & DA_M_SC) +#define DA_CKMASK2 037 /* check mask */ +#define DA_CKMASK3 077 +#define DA_CKMASK (dp_ctype? DA_CKMASK3: DA_CKMASK2) /* Status */ @@ -88,8 +98,8 @@ #define STA_OVR 0020000 /* overrun */ #define STA_RWU 0010000 /* rw unsafe */ #define STA_ACU 0004000 /* access unsafe */ -#define STA_HUNT 0002000 /* hunting */ -#define STA_SKI 0001000 /* incomplete */ +#define STA_HUNT 0002000 /* hunting NI */ +#define STA_SKI 0001000 /* incomplete NI */ #define STA_SKE 0000400 /* seek error */ /* 0000200 /* unused */ #define STA_NRDY 0000100 /* not ready */ @@ -102,11 +112,11 @@ #define STA_ALLERR (STA_ATN + STA_1ST + STA_OVR + STA_RWU + STA_ACU + \ STA_HUNT + STA_SKI + STA_SKE + STA_NRDY + STA_EOC + \ STA_FLG + STA_DTE) +#define STA_MBZ13 (STA_ATN + STA_RWU + STA_SKI) /* zero in 13210 */ -extern uint16 M[]; -extern struct hpdev infotab[]; extern int32 PC; extern int32 dev_cmd[2], dev_ctl[2], dev_flg[2], dev_fbf[2]; +int32 dp_ctype = 0; /* ctrl type */ int32 dpc_busy = 0; /* cch busy */ int32 dpc_cnt = 0; /* check count */ int32 dpc_eoc = 0; /* end of cyl */ @@ -118,16 +128,18 @@ int32 dpc_rarc = 0, dpc_rarh = 0, dpc_rars = 0; /* record addr */ int32 dpd_obuf = 0, dpd_ibuf = 0; /* dch buffers */ int32 dpc_obuf = 0; /* cch buffers */ int32 dp_ptr = 0; /* buffer ptr */ -uint16 dp_buf[DP_NUMWD]; /* sector buffer */ +uint16 dpxb[DP_NUMWD]; /* sector buffer */ +int32 dpdio (int32 inst, int32 IR, int32 dat); +int32 dpcio (int32 inst, int32 IR, int32 dat); t_stat dpc_svc (UNIT *uptr); t_stat dpc_reset (DEVICE *dptr); t_stat dpc_vlock (UNIT *uptr, int32 val); t_stat dpc_attach (UNIT *uptr, char *cptr); t_stat dpc_detach (UNIT *uptr); -t_stat dpd_ex (t_value *vptr, t_addr addr, UNIT *uptr, int32 sw); -t_stat dpd_dep (t_value val, t_addr addr, UNIT *uptr, int32 sw); void dp_go (int32 fnc, int32 drv, int32 time, int32 attdev); +t_stat dp_settype (UNIT *uptr, int32 val, char *cptr, void *desc); +t_stat dp_showtype (FILE *st, UNIT *uptr, int32 val, void *desc); /* DPD data structures @@ -136,23 +148,37 @@ void dp_go (int32 fnc, int32 drv, int32 time, int32 attdev); dpd_reg DPD register list */ -UNIT dpd_unit = { UDATA (NULL, UNIT_FIX, DP_NUMWD) }; +DIB dp_dib[] = { + { DPD, 1, 0, 0, 0, 0, &dpdio }, + { DPC, 1, 0, 0, 0, 0, &dpcio } }; + +#define dpd_dib dp_dib[0] +#define dpc_dib dp_dib[1] + +UNIT dpd_unit = { UDATA (NULL, 0, 0) }; REG dpd_reg[] = { { ORDATA (IBUF, dpd_ibuf, 16) }, { ORDATA (OBUF, dpd_obuf, 16) }, - { FLDATA (CMD, infotab[inDPD].cmd, 0) }, - { FLDATA (CTL, infotab[inDPD].ctl, 0) }, - { FLDATA (FLG, infotab[inDPD].flg, 0) }, - { FLDATA (FBF, infotab[inDPD].fbf, 0) }, - { DRDATA (BPTR, dp_ptr, DP_W_NUMWD) }, - { ORDATA (DEVNO, infotab[inDPD].devno, 6), REG_RO }, + { FLDATA (CMD, dpd_dib.cmd, 0) }, + { FLDATA (CTL, dpd_dib.ctl, 0) }, + { FLDATA (FLG, dpd_dib.flg, 0) }, + { FLDATA (FBF, dpd_dib.fbf, 0) }, + { BRDATA (DBUF, dpxb, 8, 16, DP_NUMWD) }, + { DRDATA (BPTR, dp_ptr, DP_N_NUMWD) }, + { ORDATA (DEVNO, dpd_dib.devno, 6), REG_HRO }, + { FLDATA (*DEVENB, dpd_dib.enb, 0), REG_HRO }, { NULL } }; +MTAB dpd_mod[] = { + { MTAB_XTD | MTAB_VDV, 1, "DEVNO", "DEVNO", + &hp_setdev, &hp_showdev, &dpd_dib }, + { 0 } }; + DEVICE dpd_dev = { - "DPD", &dpd_unit, dpd_reg, NULL, - 1, 10, DP_W_NUMWD, 1, 8, 16, - &dpd_ex, &dpd_dep, &dpc_reset, + "DPD", &dpd_unit, dpd_reg, dpd_mod, + 1, 10, DP_N_NUMWD, 1, 8, 16, + NULL, NULL, &dpc_reset, NULL, NULL, NULL }; /* DPC data structures @@ -164,10 +190,10 @@ DEVICE dpd_dev = { */ UNIT dpc_unit[] = { - { UDATA (&dpc_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE, DP_SIZE) }, - { UDATA (&dpc_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE, DP_SIZE) }, - { UDATA (&dpc_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE, DP_SIZE) }, - { UDATA (&dpc_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE, DP_SIZE) } }; + { UDATA (&dpc_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE, DP_SIZE2) }, + { UDATA (&dpc_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE, DP_SIZE2) }, + { UDATA (&dpc_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE, DP_SIZE2) }, + { UDATA (&dpc_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE, DP_SIZE2) } }; REG dpc_reg[] = { { ORDATA (OBUF, dpc_obuf, 16) }, @@ -176,31 +202,39 @@ REG dpc_reg[] = { { ORDATA (RARH, dpc_rarh, 2) }, { ORDATA (RARS, dpc_rars, 4) }, { ORDATA (CNT, dpc_cnt, 5) }, - { FLDATA (CMD, infotab[inDPC].cmd, 0) }, - { FLDATA (CTL, infotab[inDPC].ctl, 0) }, - { FLDATA (FLG, infotab[inDPC].flg, 0) }, - { FLDATA (FBF, infotab[inDPC].fbf, 0) }, + { FLDATA (CMD, dpc_dib.cmd, 0) }, + { FLDATA (CTL, dpc_dib.ctl, 0) }, + { FLDATA (FLG, dpc_dib.flg, 0) }, + { FLDATA (FBF, dpc_dib.fbf, 0) }, { FLDATA (EOC, dpc_eoc, 0) }, { DRDATA (CTIME, dpc_ctime, 24), PV_LEFT }, { DRDATA (STIME, dpc_stime, 24), PV_LEFT }, { DRDATA (XTIME, dpc_xtime, 24), REG_NZ + PV_LEFT }, { BRDATA (STA, dpc_sta, 8, 16, DP_NUMDRV) }, - { GRDATA (UFLG0, dpc_unit[0].flags, 8, UNIT_W_UF, UNIT_V_UF - 1), - REG_HRO }, - { GRDATA (UFLG1, dpc_unit[1].flags, 8, UNIT_W_UF, UNIT_V_UF - 1), - REG_HRO }, - { GRDATA (UFLG2, dpc_unit[2].flags, 8, UNIT_W_UF, UNIT_V_UF - 1), - REG_HRO }, - { GRDATA (UFLG3, dpc_unit[3].flags, 8, UNIT_W_UF, UNIT_V_UF - 1), - REG_HRO }, - { ORDATA (DEVNO, infotab[inDPC].devno, 6), REG_RO }, + { FLDATA (CTYPE, dp_ctype, 0), REG_HRO }, + { URDATA (CAPAC, dpc_unit[0].capac, 10, 31, 0, + DP_NUMDRV, PV_LEFT | REG_HRO) }, + { URDATA (UFLG, dpc_unit[0].flags, 8, UNIT_W_UF, UNIT_V_UF - 1, + DP_NUMDRV, REG_HRO) }, + { ORDATA (DEVNO, dpc_dib.devno, 6), REG_HRO }, + { FLDATA (*DEVENB, dpc_dib.enb, 0), REG_HRO }, { NULL } }; MTAB dpc_mod[] = { /* { UNIT_WLK, 0, "write enabled", "ENABLED", &dpc_vlock }, */ /* { UNIT_WLK, UNIT_WLK, "write locked", "LOCKED", &dpc_vlock }, */ - { MTAB_XTD | MTAB_VDV, inDPD, "DEVNO", "DEVNO", - &hp_setdev2, &hp_showdev2, NULL }, + { MTAB_XTD | MTAB_VDV, 1, NULL, "13210A", + &dp_settype, NULL, NULL }, + { MTAB_XTD | MTAB_VDV, 0, NULL, "12557A", + &dp_settype, NULL, NULL }, + { MTAB_XTD | MTAB_VDV, 0, "TYPE", NULL, + NULL, &dp_showtype, NULL }, + { MTAB_XTD | MTAB_VDV, 1, NULL, "ENABLED", + &set_enb, NULL, &dpd_dib }, + { MTAB_XTD | MTAB_VDV, 1, NULL, "DISABLED", + &set_dis, NULL, &dpd_dib }, + { MTAB_XTD | MTAB_VDV, 1, "DEVNO", "DEVNO", + &hp_setdev, &hp_showdev, &dpd_dib }, { 0 } }; DEVICE dpc_dev = { @@ -221,10 +255,10 @@ case ioFLG: /* flag clear/set */ if ((IR & HC) == 0) { setFLG (devd); } /* STF */ break; case ioSFC: /* skip flag clear */ - if (FLG (devd) == 0) PC = (PC + 1) & AMASK; + if (FLG (devd) == 0) PC = (PC + 1) & VAMASK; return dat; case ioSFS: /* skip flag set */ - if (FLG (devd) != 0) PC = (PC + 1) & AMASK; + if (FLG (devd) != 0) PC = (PC + 1) & VAMASK; return dat; case ioOTX: /* output */ dpd_obuf = dat; @@ -258,10 +292,10 @@ case ioFLG: /* flag clear/set */ if ((IR & HC) == 0) { setFLG (devc); } /* STF */ break; case ioSFC: /* skip flag clear */ - if (FLG (devc) == 0) PC = (PC + 1) & AMASK; + if (FLG (devc) == 0) PC = (PC + 1) & VAMASK; return dat; case ioSFS: /* skip flag set */ - if (FLG (devc) != 0) PC = (PC + 1) & AMASK; + if (FLG (devc) != 0) PC = (PC + 1) & VAMASK; return dat; case ioOTX: /* output */ dpc_obuf = dat; @@ -296,12 +330,8 @@ case ioCTL: /* control clear/set */ dp_go (fnc, drv, dpc_xtime, devc); break; case FNC_REF: case FNC_RD: case FNC_WD: /* ref, read, write */ - dp_go (fnc, drv, dpc_ctime, devc); - break; case FNC_INIT: /* init */ - dpc_sta[drv] = dpc_sta[drv] | STA_FLG; - setFLG (devc); /* set cch flg */ - clrCMD (devc); /* clr cch cmd */ + dp_go (fnc, drv, dpc_ctime, devc); break; } /* end case */ } /* end else */ @@ -341,8 +371,8 @@ int32 i, da, drv, devc, devd, err, st, maxsc; err = 0; /* assume no err */ drv = uptr - dpc_dev.units; /* get drive no */ -devc = infotab[inDPC].devno; /* get cch devno */ -devd = infotab[inDPD].devno; /* get dch devno */ +devc = dpc_dib.devno; /* get cch devno */ +devd = dpd_dib.devno; /* get dch devno */ switch (uptr -> FNC) { /* case function */ case FNC_SEEK: /* seek, need cyl */ @@ -370,9 +400,11 @@ case FNC_SEEK1: /* seek, need hd/sec */ case FNC_SEEK2: /* seek done */ if (dpc_busy) sim_activate (uptr, dpc_xtime); /* ctrl busy? wait */ else { dpc_sta[drv] = (dpc_sta[drv] | STA_ATN) & ~STA_BSY; - if (uptr -> CYL >= DP_NUMTR) { /* error? */ + if (uptr -> CYL >= DP_NUMCY) { /* invalid cyl? */ dpc_sta[drv] = dpc_sta[drv] | STA_SKE; uptr -> CYL = 0; } + if (dpc_rars >= DP_NUMSC) /* invalid sec? */ + dpc_sta[drv] = dpc_sta[drv] | STA_SKE; setFLG (devc); /* set cch flg */ clrCMD (devc); } /* clr cch cmd */ return SCPE_OK; @@ -397,10 +429,11 @@ case FNC_AR1: /* arec, need hd/sec */ case FNC_STA: /* read status */ if (CMD (devd)) { /* dch active? */ - dpd_ibuf = dpc_sta[drv] | ((dpc_sta[drv] & STA_ALLERR)? STA_ERR: 0); + dpd_ibuf = dpc_sta[drv] & ~(dp_ctype? STA_MBZ13: 0); + if (dpc_sta[drv] & STA_ALLERR) dpd_ibuf = dpd_ibuf | STA_ERR; setFLG (devd); /* set dch flg */ clrCMD (devd); /* clr dch cmd */ - dpc_sta[drv] = dpc_sta[drv] & /* clr sta flags */ + dpc_sta[drv] = dpc_sta[drv] & /* clr sta flags */ ~(STA_ATN | STA_DTE | STA_FLG | STA_AER | STA_EOC); dpc_busy = 0; } /* ctlr is free */ else sim_activate (uptr, dpc_xtime); /* wait more */ @@ -409,7 +442,7 @@ case FNC_STA: /* read status */ case FNC_REF: /* refine sector */ if ((uptr -> CYL != dpc_rarc) || (dpc_rars >= DP_NUMSC)) dpc_sta[drv] = dpc_sta[drv] | STA_AER; - else { for (i = 0; i < DP_NUMWD; i++) dp_buf[i] = 0; + else { for (i = 0; i < DP_NUMWD; i++) dpxb[i] = 0; da = GETDA (dpc_rarc, dpc_rarh, dpc_rars); /* get addr */ dpc_rars = dpc_rars + 1; /* incr sector */ if (dpc_rars >= DP_NUMSC) { /* end of trk? */ @@ -417,13 +450,13 @@ case FNC_REF: /* refine sector */ dpc_rarh = dpc_rarh ^ 1; } /* next surf */ if (err = fseek (uptr -> fileref, da * sizeof (int16), SEEK_SET)) break; - fxwrite (dp_buf, sizeof (int16), DP_NUMWD, uptr -> fileref); + fxwrite (dpxb, sizeof (int16), DP_NUMWD, uptr -> fileref); err = ferror (uptr -> fileref); } break; case FNC_CHK: /* check, need cnt */ if (CMD (devd)) { /* dch active? */ - dpc_cnt = dpd_obuf & 037; /* get count */ + dpc_cnt = dpd_obuf & DA_CKMASK; /* get count */ setFLG (devd); /* set dch flg */ clrCMD (devd); /* clr dch cmd */ sim_activate (uptr, dpc_ctime); /* schedule op */ @@ -461,23 +494,24 @@ case FNC_RD: /* read */ dpc_eoc = ((dpc_rarh & 1) == 0); } /* calc eoc */ if (err = fseek (uptr -> fileref, da * sizeof (int16), SEEK_SET)) break; - fxread (dp_buf, sizeof (int16), DP_NUMWD, uptr -> fileref); + fxread (dpxb, sizeof (int16), DP_NUMWD, uptr -> fileref); if (err = ferror (uptr -> fileref)) break; } - dpd_ibuf = dp_buf[dp_ptr++]; /* get word */ + dpd_ibuf = dpxb[dp_ptr++]; /* get word */ if (dp_ptr >= DP_NUMWD) dp_ptr = 0; /* wrap if last */ setFLG (devd); /* set dch flg */ clrCMD (devd); /* clr dch cmd */ sim_activate (uptr, dpc_xtime); /* sched next word */ return SCPE_OK; +case FNC_INIT: /* init */ case FNC_WD: /* write */ if (dpc_eoc) { /* end of cyl? */ dpc_sta[drv] = dpc_sta[drv] | STA_EOC; /* set status */ break; } /* done */ if (FLG (devd)) dpc_sta[drv] = dpc_sta[drv] | STA_OVR; - dp_buf[dp_ptr++] = dpd_obuf; /* store word */ + dpxb[dp_ptr++] = dpd_obuf; /* store word */ if (!CMD (devd)) { /* dch clr? done */ - for ( ; dp_ptr < DP_NUMWD; dp_ptr++) dp_buf[dp_ptr] = 0; } + for ( ; dp_ptr < DP_NUMWD; dp_ptr++) dpxb[dp_ptr] = 0; } if (dp_ptr >= DP_NUMWD) { /* buffer full? */ if ((uptr -> CYL != dpc_rarc) || (dpc_rars >= DP_NUMSC)) { dpc_sta[drv] = dpc_sta[drv] | STA_AER; @@ -490,7 +524,7 @@ case FNC_WD: /* write */ dpc_eoc = ((dpc_rarh & 1) == 0); } /* calc eoc */ if (err = fseek (uptr -> fileref, da * sizeof (int16), SEEK_SET)) return TRUE; - fwrite (dp_buf, sizeof (int16), DP_NUMWD, uptr -> fileref); + fxwrite (dpxb, sizeof (int16), DP_NUMWD, uptr -> fileref); if (err = ferror (uptr -> fileref)) break; dp_ptr = 0; } if (CMD (devd)) { /* dch active? */ @@ -538,10 +572,10 @@ dpc_busy = dpc_obuf = 0; dpc_eoc = 0; dp_ptr = 0; dpc_rarc = dpc_rarh = dpc_rars = 0; /* clear rar */ -infotab[inDPC].cmd = infotab[inDPD].cmd = 0; /* clear cmd */ -infotab[inDPC].ctl = infotab[inDPD].ctl = 0; /* clear ctl */ -infotab[inDPC].fbf = infotab[inDPD].fbf = 1; /* set fbf */ -infotab[inDPC].flg = infotab[inDPD].flg = 1; /* set flg */ +dpc_dib.cmd = dpd_dib.cmd = 0; /* clear cmd */ +dpc_dib.ctl = dpd_dib.ctl = 0; /* clear ctl */ +dpc_dib.fbf = dpd_dib.fbf = 1; /* set fbf */ +dpc_dib.flg = dpd_dib.flg = 1; /* set flg */ for (i = 0; i < DP_NUMDRV; i++) { /* loop thru drives */ sim_cancel (&dpc_unit[i]); /* cancel activity */ dpc_unit[i].FNC = 0; /* clear function */ @@ -586,20 +620,28 @@ if (uptr -> flags & UNIT_ATT) return SCPE_ARG; return SCPE_OK; } -/* Buffer examine */ +/* Set controller type */ -t_stat dpd_ex (t_value *vptr, t_addr addr, UNIT *uptr, int32 sw) +t_stat dp_settype (UNIT *uptr, int32 val, char *cptr, void *desc) { -if (addr >= DP_NUMWD) return SCPE_NXM; -if (vptr != NULL) *vptr = dp_buf[addr] & DMASK; +int32 i; + +if ((val < 0) || (val > 1) || (cptr != NULL)) return SCPE_ARG; +for (i = 0; i < DP_NUMDRV; i++) { + if (dpc_unit[i].flags & UNIT_ATT) return SCPE_ALATT; } +for (i = 0; i < DP_NUMDRV; i++) + dpc_unit[i].capac = (val? DP_SIZE3: DP_SIZE2); +dp_ctype = val; return SCPE_OK; } -/* Buffer deposit */ +/* Show controller type */ -t_stat dpd_dep (t_value val, t_addr addr, UNIT *uptr, int32 sw) +t_stat dp_showtype (FILE *st, UNIT *uptr, int32 val, void *desc) { -if (addr >= DP_NUMWD) return SCPE_NXM; -dp_buf[addr] = val & DMASK; +if (dp_ctype) fprintf (st, "13210A"); +else fprintf (st, "12557A"); return SCPE_OK; } + + diff --git a/HP2100/hp2100_dq.c b/HP2100/hp2100_dq.c new file mode 100644 index 00000000..1bd6384b --- /dev/null +++ b/HP2100/hp2100_dq.c @@ -0,0 +1,583 @@ +/* hp2100_dq.c: HP 2100 12565A disk simulator + + Copyright (c) 1993-2002, Robert M. Supnik + Modified from hp2100_dp.c by Bill McDermith; used by permission + + Permission is hereby granted, free of charge, to any person obtaining a + copy of this software and associated documentation files (the "Software"), + to deal in the Software without restriction, including without limitation + the rights to use, copy, modify, merge, publish, distribute, sublicense, + and/or sell copies of the Software, and to permit persons to whom the + Software is furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY 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. + + dq 12565A 2883/2884 disk system + + 09-Jan-02 WOM Copied dp driver and mods for 2883 +*/ + +#include "hp2100_defs.h" + +#define UNIT_V_WLK (UNIT_V_UF + 0) /* write locked */ +#define UNIT_WLK (1 << UNIT_V_WLK) +#define UNIT_W_UF 2 /* # flags */ +#define FNC u3 /* saved function */ +#define CYL u4 /* cylinder */ + +#define DQ_N_NUMWD 7 +#define DQ_NUMWD (1 << DQ_N_NUMWD) /* words/sector */ +#define DQ_NUMSC 23 /* sectors/track */ +#define DQ_NUMSF 20 /* tracks/cylinder */ +#define DQ_NUMCY 203 /* cylinders/disk */ +#define DQ_SIZE (DQ_NUMSF * DQ_NUMCY * DQ_NUMSC * DQ_NUMWD) +#define DQ_NUMDRV 2 /* # drives */ + +/* Command word */ + +#define CW_V_FNC 12 /* function */ +#define CW_M_FNC 017 +#define CW_GETFNC(x) (((x) >> CW_V_FNC) & CW_M_FNC) +/* 000 /* unused */ +#define FNC_STA 001 /* status check */ +#define FNC_RCL 002 /* recalibrate */ +#define FNC_SEEK 003 /* seek */ +#define FNC_RD 004 /* read */ +#define FNC_WD 005 /* write */ +#define FNC_RA 006 /* read address */ +#define FNC_WA 007 /* write address */ +#define FNC_CHK 010 /* check */ +#define FNC_LA 013 /* load address */ +#define FNC_AS 014 /* address skip */ + +#define FNC_SEEK1 020 /* fake - seek1 */ +#define FNC_SEEK2 021 /* fake - seek2 */ +#define FNC_CHK1 022 /* fake - check1 */ +#define FNC_LA1 023 /* fake - arec1 */ +#define FNC_RCL1 024 /* fake - recal1 */ + +#define CW_V_DRV 0 /* drive */ +#define CW_M_DRV 01 +#define CW_GETDRV(x) (((x) >> CW_V_DRV) & CW_M_DRV) + +/* Disk address words */ + +#define DA_V_CYL 0 /* cylinder */ +#define DA_M_CYL 0377 +#define DA_GETCYL(x) (((x) >> DA_V_CYL) & DA_M_CYL) +#define DA_V_HD 8 /* head */ +#define DA_M_HD 037 +#define DA_GETHD(x) (((x) >> DA_V_HD) & DA_M_HD) +#define DA_V_SC 0 /* sector */ +#define DA_M_SC 037 +#define DA_GETSC(x) (((x) >> DA_V_SC) & DA_M_SC) +#define DA_CKMASK 0777 /* check mask */ + +/* Status */ + +#define STA_DID 0000200 /* drive ID */ +#define STA_NRDY 0000100 /* not ready */ +#define STA_EOC 0000040 /* end of cylinder */ +#define STA_AER 0000020 /* addr error */ +#define STA_FLG 0000010 /* flagged */ +#define STA_BSY 0000004 /* seeking */ +#define STA_DTE 0000002 /* data error */ +#define STA_ERR 0000001 /* any error */ +#define STA_ALLERR (STA_DID + STA_NRDY + STA_EOC + \ + STA_FLG + STA_DTE) + +extern int32 PC; +extern int32 dev_cmd[2], dev_ctl[2], dev_flg[2], dev_fbf[2]; +int32 dqc_busy = 0; /* cch busy */ +int32 dqc_cnt = 0; /* check count */ +int32 dqc_eoc = 0; /* end of cyl */ +int32 dqc_sta[DQ_NUMDRV] = { 0 }; /* status regs */ +int32 dqc_stime = 10; /* seek time */ +int32 dqc_ctime = 10; /* command time */ +int32 dqc_xtime = 5; /* xfer time */ +int32 dqc_rarc = 0, dqc_rarh = 0, dqc_rars = 0; /* record addr */ +int32 dqd_obuf = 0, dqd_ibuf = 0; /* dch buffers */ +int32 dqc_obuf = 0; /* cch buffers */ +int32 dq_ptr = 0; /* buffer ptr */ +uint16 dqxb[DQ_NUMWD]; /* sector buffer */ + +int32 dqdio (int32 inst, int32 IR, int32 dat); +int32 dqcio (int32 inst, int32 IR, int32 dat); +t_stat dqc_svc (UNIT *uptr); +t_stat dqc_reset (DEVICE *dptr); +t_stat dqc_vlock (UNIT *uptr, int32 val); +t_stat dqc_attach (UNIT *uptr, char *cptr); +t_stat dqc_detach (UNIT *uptr); +void dq_go (int32 fnc, int32 drv, int32 time, int32 attdev); + +/* DQD data structures + + dqd_dev DQD device descriptor + dqd_unit DQD unit list + dqd_reg DQD register list +*/ + +DIB dq_dib[] = { + { DQD, 1, 0, 0, 0, 0, &dqdio }, + { DQC, 1, 0, 0, 0, 0, &dqcio } }; + +#define dqd_dib dq_dib[0] +#define dqc_dib dq_dib[1] + +UNIT dqd_unit = { UDATA (NULL, 0, 0) }; + +REG dqd_reg[] = { + { ORDATA (IBUF, dqd_ibuf, 16) }, + { ORDATA (OBUF, dqd_obuf, 16) }, + { FLDATA (CMD, dqd_dib.cmd, 0) }, + { FLDATA (CTL, dqd_dib.ctl, 0) }, + { FLDATA (FLG, dqd_dib.flg, 0) }, + { FLDATA (FBF, dqd_dib.fbf, 0) }, + { BRDATA (DBUF, dqxb, 8, 16, DQ_NUMWD) }, + { DRDATA (BPTR, dq_ptr, DQ_N_NUMWD) }, + { ORDATA (DEVNO, dqd_dib.devno, 6), REG_HRO }, + { FLDATA (*DEVENB, dqd_dib.enb, 0), REG_HRO }, + { NULL } }; + +MTAB dqd_mod[] = { + { MTAB_XTD | MTAB_VDV, 1, "DEVNO", "DEVNO", + &hp_setdev, &hp_showdev, &dqd_dib }, + { 0 } }; + +DEVICE dqd_dev = { + "DQD", &dqd_unit, dqd_reg, dqd_mod, + 1, 10, DQ_N_NUMWD, 1, 8, 16, + NULL, NULL, &dqc_reset, + NULL, NULL, NULL }; + +/* DQC data structures + + dqc_dev DQC device descriptor + dqc_unit DQC unit list + dqc_reg DQC register list + dqc_mod DQC modifier list +*/ + +UNIT dqc_unit[] = { + { UDATA (&dqc_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE, DQ_SIZE) }, + { UDATA (&dqc_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE, DQ_SIZE) } }; + +REG dqc_reg[] = { + { ORDATA (OBUF, dqc_obuf, 16) }, + { ORDATA (BUSY, dqc_busy, 2), REG_RO }, + { ORDATA (RARC, dqc_rarc, 8) }, + { ORDATA (RARH, dqc_rarh, 5) }, + { ORDATA (RARS, dqc_rars, 5) }, + { ORDATA (CNT, dqc_cnt, 5) }, + { FLDATA (CMD, dqc_dib.cmd, 0) }, + { FLDATA (CTL, dqc_dib.ctl, 0) }, + { FLDATA (FLG, dqc_dib.flg, 0) }, + { FLDATA (FBF, dqc_dib.fbf, 0) }, + { FLDATA (EOC, dqc_eoc, 0) }, + { DRDATA (CTIME, dqc_ctime, 24), PV_LEFT }, + { DRDATA (STIME, dqc_stime, 24), PV_LEFT }, + { DRDATA (XTIME, dqc_xtime, 24), REG_NZ + PV_LEFT }, + { BRDATA (STA, dqc_sta, 8, 16, DQ_NUMDRV) }, + { URDATA (UFLG, dqc_unit[0].flags, 8, UNIT_W_UF, UNIT_V_UF - 1, + DQ_NUMDRV, REG_HRO) }, + { ORDATA (DEVNO, dqc_dib.devno, 6), REG_HRO }, + { FLDATA (*DEVENB, dqc_dib.enb, 0), REG_HRO }, + { NULL } }; + +MTAB dqc_mod[] = { +/* { UNIT_WLK, 0, "write enabled", "ENABLED", &dqc_vlock }, */ +/* { UNIT_WLK, UNIT_WLK, "write locked", "LOCKED", &dqc_vlock }, */ + { MTAB_XTD | MTAB_VDV, 1, NULL, "ENABLED", + &set_enb, NULL, &dqd_dib }, + { MTAB_XTD | MTAB_VDV, 1, NULL, "DISABLED", + &set_dis, NULL, &dqd_dib }, + { MTAB_XTD | MTAB_VDV, 1, "DEVNO", "DEVNO", + &hp_setdev, &hp_showdev, &dqd_dib }, + { 0 } }; + +DEVICE dqc_dev = { + "DQC", dqc_unit, dqc_reg, dqc_mod, + DQ_NUMDRV, 8, 24, 1, 8, 16, + NULL, NULL, &dqc_reset, + NULL, &dqc_attach, &dqc_detach }; + +/* IOT routines */ + +int32 dqdio (int32 inst, int32 IR, int32 dat) +{ +int32 devd; + +devd = IR & DEVMASK; /* get device no */ +switch (inst) { /* case on opcode */ +case ioFLG: /* flag clear/set */ + if ((IR & HC) == 0) { setFLG (devd); } /* STF */ + break; +case ioSFC: /* skip flag clear */ + if (FLG (devd) == 0) PC = (PC + 1) & VAMASK; + return dat; +case ioSFS: /* skip flag set */ + if (FLG (devd) != 0) PC = (PC + 1) & VAMASK; + return dat; +case ioOTX: /* output */ + dqd_obuf = dat; + break; +case ioMIX: /* merge */ + dat = dat | dqd_ibuf; + break; +case ioLIX: /* load */ + dat = dqd_ibuf; + break; +case ioCTL: /* control clear/set */ + if (IR & AB) { /* CLC */ + clrCTL (devd); /* clr ctl, cmd */ + clrCMD (devd); } + else { setCTL (devd); /* STC */ + setCMD (devd); } /* set ctl, cmd */ + break; +default: + break; } +if (IR & HC) { clrFLG (devd); } /* H/C option */ +return dat; +} + +int32 dqcio (int32 inst, int32 IR, int32 dat) +{ +int32 devc, fnc, drv; + +devc = IR & DEVMASK; /* get device no */ +switch (inst) { /* case on opcode */ +case ioFLG: /* flag clear/set */ + if ((IR & HC) == 0) { setFLG (devc); } /* STF */ + break; +case ioSFC: /* skip flag clear */ + if (FLG (devc) == 0) PC = (PC + 1) & VAMASK; + return dat; +case ioSFS: /* skip flag set */ + if (FLG (devc) != 0) PC = (PC + 1) & VAMASK; + return dat; +case ioOTX: /* output */ + dqc_obuf = dat; + break; +case ioLIX: /* load */ + dat = 0; +case ioMIX: /* merge */ + break; /* no data */ +case ioCTL: /* control clear/set */ + if (IR & AB) { /* CLC? */ + clrCMD (devc); /* clr cmd, ctl */ + clrCTL (devc); /* cancel non-seek */ + if (dqc_busy) sim_cancel (&dqc_unit[dqc_busy - 1]); + dqc_busy = 0; } /* clr busy */ + else if (!CTL (devc)) { /* set and now clr? */ + setCMD (devc); /* set cmd, ctl */ + setCTL (devc); + drv = CW_GETDRV (dqc_obuf); /* get fnc, drv */ + fnc = CW_GETFNC (dqc_obuf); /* from cmd word */ + switch (fnc) { /* case on fnc */ + case FNC_SEEK: case FNC_RCL: /* seek, recal */ + dqc_sta[drv] = dqc_sta[drv] | STA_BSY; + dq_go (fnc, drv, dqc_xtime, devc); + break; + case FNC_STA: case FNC_LA: /* rd sta, load addr */ + dq_go (fnc, drv, dqc_xtime, 0); + break; + case FNC_CHK: /* check */ + dq_go (fnc, drv, dqc_xtime, devc); + break; + case FNC_RD: case FNC_WD: case FNC_WA: /* read, write, wr addr */ + dq_go (fnc, drv, dqc_ctime, devc); + break; + } /* end case */ + } /* end else */ + break; +default: + break; } +if (IR & HC) { clrFLG (devc); } /* H/C option */ +return dat; +} + +/* Unit service + + Unit must be attached; detach cancels operation. + + Seek substates + seek - transfer cylinder + seek1 - transfer head/surface + seek2 - done + Load address + la - transfer cylinder + la1 - transfer head/surface, finish operation + Status check - transfer status, finish operation + Check data + chk - transfer sector count + chk1 - finish operation + Read + Write +*/ + +#define GETDA(x,y,z) \ + (((((x) * DQ_NUMSF) + (y)) * DQ_NUMSC) + (z)) * DQ_NUMWD + +t_stat dqc_svc (UNIT *uptr) +{ +int32 i, da, drv, devc, devd, err, st, maxsc; + +err = 0; /* assume no err */ +drv = uptr - dqc_dev.units; /* get drive no */ +devc = dqc_dib.devno; /* get cch devno */ +devd = dqd_dib.devno; /* get dch devno */ +switch (uptr -> FNC) { /* case function */ + +case FNC_SEEK: /* seek, need cyl */ + if (CMD (devd)) { /* dch active? */ + dqc_rarc = DA_GETCYL (dqd_obuf); /* take cyl word */ + setFLG (devd); /* set dch flg */ + clrCMD (devd); /* clr dch cmd */ + uptr -> FNC = FNC_SEEK1; } /* advance state */ + sim_activate (uptr, dqc_xtime); /* no, wait more */ + return SCPE_OK; +case FNC_SEEK1: /* seek, need hd/sec */ + if (CMD (devd)) { /* dch active? */ + dqc_rarh = DA_GETHD (dqd_obuf); /* get head */ + dqc_rars = DA_GETSC (dqd_obuf); /* get sector */ + setFLG (devd); /* set dch flg */ + clrCMD (devd); /* clr dch cmd */ + st = abs (dqc_rarc - uptr -> CYL) * dqc_stime; /* calc diff */ + if (st == 0) st = dqc_xtime; /* min time */ + sim_activate (uptr, st); /* schedule op */ + uptr -> CYL = dqc_rarc; /* on cylinder */ + dqc_busy = 0; /* ctrl is free */ + uptr -> FNC = FNC_SEEK2; } /* advance state */ + else sim_activate (uptr, dqc_xtime); /* no, wait more */ + return SCPE_OK; +case FNC_SEEK2: /* seek done */ + if (dqc_busy) sim_activate (uptr, dqc_xtime); /* ctrl busy? wait */ + else { dqc_sta[drv] = dqc_sta[drv] & ~STA_BSY; + if (uptr -> CYL >= DQ_NUMCY) { /* invalid cyl? */ + dqc_sta[drv] = dqc_sta[drv] | STA_AER; + uptr -> CYL = 0; } + if (dqc_rars >= DQ_NUMSC) /* invalid sec? */ + dqc_sta[drv] = dqc_sta[drv] | STA_AER; + setFLG (devc); /* set cch flg */ + clrCMD (devc); } /* clr cch cmd */ + return SCPE_OK; +case FNC_RCL: /* recalibrate */ + if (dqc_busy) sim_activate (uptr, dqc_xtime); /* ctrl busy? wait */ + else { st = uptr -> CYL * dqc_stime; /* calc diff */ + if (st == 0) st = dqc_xtime; /* min time */ + sim_activate (uptr, st); /* schedule op */ + uptr -> CYL = 0; /* on cylinder */ + dqc_busy = 0; /* ctrl is free */ + uptr -> FNC = FNC_RCL1; } /* advance state */ + return SCPE_OK; +case FNC_RCL1: /* recal done */ + if (dqc_busy) sim_activate (uptr, dqc_xtime); /* ctrl busy? wait */ + else { dqc_sta[drv] = dqc_sta[drv] & ~STA_BSY; + setFLG (devc); /* set cch flg */ + clrCMD (devc); } /* clr cch cmd */ + return SCPE_OK; + +case FNC_LA: /* arec, need cyl */ + if (CMD (devd)) { /* dch active? */ + dqc_rarc = DA_GETCYL (dqd_obuf); /* take cyl word */ + setFLG (devd); /* set dch flg */ + clrCMD (devd); /* clr dch cmd */ + uptr -> FNC = FNC_LA1; } /* advance state */ + sim_activate (uptr, dqc_xtime); /* no, wait more */ + return SCPE_OK; +case FNC_LA1: /* arec, need hd/sec */ + if (CMD (devd)) { /* dch active? */ + dqc_rarh = DA_GETHD (dqd_obuf); /* get head */ + dqc_rars = DA_GETSC (dqd_obuf); /* get sector */ + setFLG (devd); /* set dch flg */ + clrCMD (devd); } /* clr dch cmd */ + else { sim_activate (uptr, dqc_xtime); /* no, wait more */ + return SCPE_OK; } + break; /* done */ + +case FNC_STA: /* read status */ + if (CMD (devd)) { /* dch active? */ + dqd_ibuf = dqc_sta[drv] | ((dqc_sta[drv] & STA_ALLERR)? STA_ERR: 0); + setFLG (devd); /* set dch flg */ + clrCMD (devd); /* clr dch cmd */ + dqc_sta[drv] = dqc_sta[drv] & /* clr sta flags */ + ~(STA_DTE | STA_FLG | STA_AER | STA_EOC); + dqc_busy = 0; } /* ctlr is free */ + else sim_activate (uptr, dqc_xtime); /* wait more */ + return SCPE_OK; + +case FNC_CHK: /* check, need cnt */ + if (CMD (devd)) { /* dch active? */ + dqc_cnt = dqd_obuf & DA_CKMASK; /* get count */ + setFLG (devd); /* set dch flg */ + clrCMD (devd); /* clr dch cmd */ + sim_activate (uptr, dqc_ctime); /* schedule op */ + uptr -> FNC = FNC_CHK1; } /* advance state */ + else sim_activate (uptr, dqc_xtime); /* wait more */ + return SCPE_OK; +case FNC_CHK1: + if ((uptr -> CYL != dqc_rarc) || (dqc_rars >= DQ_NUMSC)) + dqc_sta[drv] = dqc_sta[drv] | STA_AER; + else { maxsc = ((2 - (dqc_rarh & 1)) * DQ_NUMSC) - dqc_rars; + if (dqc_cnt > maxsc) { /* too many sec? */ + dqc_sta[drv] = dqc_sta[drv] | STA_EOC; + dqc_rarh = dqc_rarh & ~1; /* rar = 0/2, 0 */ + dqc_rars = 0; } + else { i = dqc_rars + dqc_cnt; /* final sector */ + dqc_rars = i % DQ_NUMSC; /* reposition */ + dqc_rarh = dqc_rarh ^ ((i / DQ_NUMSC) & 1); } } + break; /* done */ + +case FNC_RD: /* read */ + if (!CMD (devd)) break; /* dch clr? done */ + if (FLG (devd)) dqc_sta[drv] = dqc_sta[drv] | STA_DTE; + if (dq_ptr == 0) { /* new sector? */ + if ((uptr -> CYL != dqc_rarc) || (dqc_rars >= DQ_NUMSC)) { + dqc_sta[drv] = dqc_sta[drv] | STA_AER; + break; } + if (dqc_eoc) { /* end of cyl? */ + dqc_sta[drv] = dqc_sta[drv] | STA_EOC; + break; } + da = GETDA (dqc_rarc, dqc_rarh, dqc_rars); /* get addr */ + dqc_rars = dqc_rars + 1; /* incr address */ + if (dqc_rars >= DQ_NUMSC) { /* end of trk? */ + dqc_rars = 0; /* wrap to */ + dqc_rarh = dqc_rarh ^ 1; /* next cyl */ + dqc_eoc = ((dqc_rarh & 1) == 0); } /* calc eoc */ + if (err = fseek (uptr -> fileref, da * sizeof (int16), + SEEK_SET)) break; + fxread (dqxb, sizeof (int16), DQ_NUMWD, uptr -> fileref); + if (err = ferror (uptr -> fileref)) break; } + dqd_ibuf = dqxb[dq_ptr++]; /* get word */ + if (dq_ptr >= DQ_NUMWD) dq_ptr = 0; /* wrap if last */ + setFLG (devd); /* set dch flg */ + clrCMD (devd); /* clr dch cmd */ + sim_activate (uptr, dqc_xtime); /* sched next word */ + return SCPE_OK; + +case FNC_WA: /* write address */ +case FNC_WD: /* write */ + if (dqc_eoc) { /* end of cyl? */ + dqc_sta[drv] = dqc_sta[drv] | STA_EOC; /* set status */ + break; } /* done */ + if (FLG (devd)) dqc_sta[drv] = dqc_sta[drv] | STA_DTE; + dqxb[dq_ptr++] = dqd_obuf; /* store word */ + if (!CMD (devd)) { /* dch clr? done */ + for ( ; dq_ptr < DQ_NUMWD; dq_ptr++) dqxb[dq_ptr] = 0; } + if (dq_ptr >= DQ_NUMWD) { /* buffer full? */ + if ((uptr -> CYL != dqc_rarc) || (dqc_rars >= DQ_NUMSC)) { + dqc_sta[drv] = dqc_sta[drv] | STA_AER; + break; } + da = GETDA (dqc_rarc, dqc_rarh, dqc_rars); /* get addr */ + dqc_rars = dqc_rars + 1; /* incr address */ + if (dqc_rars >= DQ_NUMSC) { /* end of trk? */ + dqc_rars = 0; /* wrap to */ + dqc_rarh = dqc_rarh ^ 1; /* next cyl */ + dqc_eoc = ((dqc_rarh & 1) == 0); } /* calc eoc */ + if (err = fseek (uptr -> fileref, da * sizeof (int16), + SEEK_SET)) return TRUE; + fxwrite (dqxb, sizeof (int16), DQ_NUMWD, uptr -> fileref); + if (err = ferror (uptr -> fileref)) break; + dq_ptr = 0; } + if (CMD (devd)) { /* dch active? */ + setFLG (devd); /* set dch flg */ + clrCMD (devd); /* clr dch cmd */ + sim_activate (uptr, dqc_xtime); /* sched next word */ + return SCPE_OK; } + break; } /* end case fnc */ + +setFLG (devc); /* set cch flg */ +clrCMD (devc); /* clr cch cmd */ +dqc_busy = 0; /* ctlr is free */ +if (err != 0) { /* error? */ + perror ("DQ I/O error"); + clearerr (uptr -> fileref); + return SCPE_IOERR; } +return SCPE_OK; +} + +/* Start disk operation */ + +void dq_go (int32 fnc, int32 drv, int32 time, int32 dev) +{ +if (dev && ((dqc_unit[drv].flags & UNIT_ATT) == 0)) { /* attach check? */ + dqc_sta[drv] = STA_NRDY; /* not attached */ + setFLG (dev); /* set cch flag */ + clrCMD (dev); } /* clr cch cmd */ +else { dqc_busy = drv + 1; /* set busy */ + dq_ptr = 0; /* init buf ptr */ + dqc_eoc = 0; /* clear end cyl */ + dqc_unit[drv].FNC = fnc; /* save function */ + sim_activate (&dqc_unit[drv], time); } /* activate unit */ +return; +} + +/* Reset routine */ + +t_stat dqc_reset (DEVICE *dptr) +{ +int32 i; + +dqd_ibuf = dqd_obuf = 0; /* clear buffers */ +dqc_busy = dqc_obuf = 0; +dqc_eoc = 0; +dq_ptr = 0; +dqc_rarc = dqc_rarh = dqc_rars = 0; /* clear rar */ +dqc_dib.cmd = dqd_dib.cmd = 0; /* clear cmd */ +dqc_dib.ctl = dqd_dib.ctl = 0; /* clear ctl */ +dqc_dib.fbf = dqd_dib.fbf = 1; /* set fbf */ +dqc_dib.flg = dqd_dib.flg = 1; /* set flg */ +for (i = 0; i < DQ_NUMDRV; i++) { /* loop thru drives */ + sim_cancel (&dqc_unit[i]); /* cancel activity */ + dqc_unit[i].FNC = 0; /* clear function */ + dqc_unit[i].CYL = 0; + dqc_sta[i] = (dqc_unit[i].flags & UNIT_ATT)? 0: STA_NRDY; } +return SCPE_OK; +} + +/* Attach routine */ + +t_stat dqc_attach (UNIT *uptr, char *cptr) +{ +int32 drv; +t_stat r; + +drv = uptr - dqc_dev.units; /* get drive no */ +r = attach_unit (uptr, cptr); /* attach unit */ +if (r != SCPE_OK) return r; +dqc_sta[drv] = dqc_sta[drv] & ~STA_NRDY; /* update status */ +return r; +} + +/* Detach routine */ + +t_stat dqc_detach (UNIT* uptr) +{ +int32 drv; + +drv = uptr - dqc_dev.units; /* get drive no */ +dqc_sta[drv] = dqc_sta[drv] | STA_NRDY; /* update status */ +if (drv == (dqc_busy + 1)) dqc_busy = 0; /* update busy */ +sim_cancel (uptr); /* cancel op */ +return detach_unit (uptr); /* detach unit */ +} + +/* Write lock/enable routine */ + +t_stat dqc_vlock (UNIT *uptr, int32 val) +{ +if (uptr -> flags & UNIT_ATT) return SCPE_ARG; +return SCPE_OK; +} diff --git a/HP2100/hp2100_dr.c b/HP2100/hp2100_dr.c new file mode 100644 index 00000000..5fce8f7a --- /dev/null +++ b/HP2100/hp2100_dr.c @@ -0,0 +1,356 @@ +/* hp2100_dr.c: HP 2100 12606B/12610B fixed head disk/drum simulator + + Copyright (c) 1993-2000, Robert M. Supnik + + Permission is hereby granted, free of charge, to any person obtaining a + copy of this software and associated documentation files (the "Software"), + to deal in the Software without restriction, including without limitation + the rights to use, copy, modify, merge, publish, distribute, sublicense, + and/or sell copies of the Software, and to permit persons to whom the + Software is furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + ROBERT M SUPNIK BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + Except as contained in this notice, the name of Robert M Supnik shall not + be used in advertising or otherwise to promote the sale, use or other dealings + in this Software without prior written authorization from Robert M Supnik. + + fhd 12606B fixed head disk + 12619B drum + + These head-per-track devices are buffered in memory, to minimize overhead. + + The drum data channel does not have a command flip-flop. Further, its + control flip-flop is not wired into the interrupt chain. Accordingly, + the simulator uses command rather than control for the data channel. + + The drum control channel does not have any of the traditional flip-flops. +*/ + +#include "hp2100_defs.h" +#include + +/* Constants */ + +#define DR_NUMWD 64 /* words/sector */ +#define DR_FNUMSC 90 /* fhd sec/track */ +#define DR_DNUMSC 32 /* drum sec/track */ +#define DR_NUMSC ((drc_unit.flags & UNIT_DR)? DR_DNUMSC: DR_FNUMSC) +#define DR_SIZE (512 * DR_DNUMSC * DR_NUMWD) /* initial size */ +#define UNIT_V_DR (UNIT_V_UF) /* disk vs drum */ +#define UNIT_DR (1 << UNIT_V_DR) + +/* Command word */ + +#define CW_WR 0100000 /* write vs read */ +#define CW_V_FTRK 7 +#define CW_M_FTRK 0177 +#define CW_V_DTRK 5 +#define CW_M_DTRK 01777 +#define MAX_TRK (((drc_unit.flags & UNIT_DR)? CW_M_DTRK: CW_M_FTRK) + 1) +#define CW_GETTRK(x) ((drc_unit.flags & UNIT_DR)? \ + (((x) >> CW_V_DTRK) & CW_M_DTRK): \ + (((x) >> CW_V_FTRK) & CW_M_FTRK)) +#define CW_PUTTRK(x) ((drc_unit.flags & UNIT_DR)? \ + (((x) & CW_M_DTRK) << CW_V_DTRK): \ + (((x) & CW_M_FTRK) << CW_V_FTRK)) +#define CW_V_FSEC 0 +#define CW_M_FSEC 0177 +#define CW_V_DSEC 0 +#define CW_M_DSEC 037 +#define CW_GETSEC(x) ((drc_unit.flags & UNIT_DR)? \ + (((x) >> CW_V_DSEC) & CW_M_DSEC): \ + (((x) >> CW_V_FSEC) & CW_M_FSEC)) +#define CW_PUTSEC(x) ((drc_unit.flags & UNIT_DR)? \ + (((x) & CW_M_DSEC) << CW_V_DSEC): \ + (((x) & CW_M_FSEC) << CW_V_FSEC)) + +/* Status register */ + +#define DRS_V_NS 8 /* next sector */ +#define DRS_M_NS 0177 +#define DRS_SEC 0100000 /* sector flag */ +#define DRS_RDY 0000200 /* ready */ +#define DRS_RIF 0000100 /* read inhibit */ +#define DRS_SAC 0000040 /* sector coincidence */ +#define DRS_ABO 0000010 /* abort */ +#define DRS_WEN 0000004 /* write enabled */ +#define DRS_PER 0000002 /* parity error */ +#define DRS_BSY 0000001 /* busy */ + +#define GET_CURSEC(x) ((int32) fmod (sim_gtime() / ((double) (x)), \ + ((double) ((drc_unit.flags & UNIT_DR)? DR_DNUMSC: DR_FNUMSC)))) + +extern UNIT cpu_unit; +extern int32 PC; +extern int32 dev_cmd[2], dev_ctl[2], dev_flg[2], dev_fbf[2]; +int32 drc_cw = 0; /* fnc, addr */ +int32 drc_sta = 0; /* status */ +int32 drd_ibuf = 0; /* input buffer */ +int32 drd_obuf = 0; /* output buffer */ +int32 drd_ptr = 0; /* sector pointer */ +int32 dr_stopioe = 1; /* stop on error */ +int32 dr_time = 5; /* time per word*/ + +int32 drdio (int32 inst, int32 IR, int32 dat); +int32 drcio (int32 inst, int32 IR, int32 dat); +t_stat drc_svc (UNIT *uptr); +t_stat drc_reset (DEVICE *dptr); +int32 dr_incda (int32 trk, int32 sec, int32 ptr); +t_stat dr_set_size (UNIT *uptr, int32 val, char *cptr, void *desc); + +/* DRD data structures + + drd_dev device descriptor + drd_unit unit descriptor + drd_reg register list +*/ + +DIB dr_dib[] = { + { DRD, 1, 0, 0, 0, 0, &drdio }, + { DRC, 1, 0, 0, 0, 0, &drcio } }; + +#define drd_dib dr_dib[0] +#define drc_dib dr_dib[1] + +UNIT drd_unit = { UDATA (NULL, 0, 0) }; + +REG drd_reg[] = { + { ORDATA (IBUF, drd_ibuf, 16) }, + { ORDATA (OBUF, drd_obuf, 16) }, + { FLDATA (CMD, drd_dib.cmd, 0) }, + { FLDATA (CTL, drd_dib.ctl, 0) }, + { FLDATA (FLG, drd_dib.flg, 0) }, + { FLDATA (FBF, drd_dib.fbf, 0) }, + { ORDATA (BPTR, drd_ptr, 6) }, + { ORDATA (DEVNO, drd_dib.devno, 6), REG_HRO }, + { FLDATA (*DEVENB, drd_dib.enb, 0), REG_HRO }, + { NULL } }; + +MTAB drd_mod[] = { + { MTAB_XTD | MTAB_VDV, 1, "DEVNO", "DEVNO", + &hp_setdev, &hp_showdev, &drd_dib }, + { 0 } }; + +DEVICE drd_dev = { + "DRD", &drd_unit, drd_reg, drd_mod, + 1, 0, 0, 0, 0, 0, + NULL, NULL, NULL, + NULL, NULL, NULL }; + +/* DRC data structures + + drc_dev device descriptor + drc_unit unit descriptor + drc_mod unit modifiers + drc_reg register list +*/ + +UNIT drc_unit = + { UDATA (&drc_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_BUFABLE+ + UNIT_MUSTBUF+UNIT_DR+UNIT_BINK, DR_SIZE) }; + +REG drc_reg[] = { + { ORDATA (CW, drc_cw, 16) }, + { ORDATA (STA, drc_sta, 16) }, + { FLDATA (CMD, drc_dib.cmd, 0) }, + { FLDATA (CTL, drc_dib.ctl, 0) }, + { FLDATA (FLG, drc_dib.flg, 0) }, + { FLDATA (FBF, drc_dib.fbf, 0) }, + { DRDATA (TIME, dr_time, 24), REG_NZ + PV_LEFT }, + { FLDATA (STOP_IOE, dr_stopioe, 0) }, + { ORDATA (DEVNO, drc_dib.devno, 6), REG_HRO }, + { FLDATA (*DEVENB, drc_dib.enb, 0), REG_HRO }, + { NULL } }; + +MTAB drc_mod[] = { + { UNIT_DR, 0, "disk", NULL, NULL }, + { UNIT_DR, UNIT_DR, "drum", NULL, NULL }, + { UNIT_DR, 184320, NULL, "180K", &dr_set_size }, + { UNIT_DR, 368640, NULL, "360K", &dr_set_size }, + { UNIT_DR, 737280, NULL, "720K", &dr_set_size }, + { UNIT_DR, 368640+1, NULL, "384K", &dr_set_size }, + { UNIT_DR, 524280+1, NULL, "512K", &dr_set_size }, + { UNIT_DR, 655360+1, NULL, "640K", &dr_set_size }, + { UNIT_DR, 786432+1, NULL, "768K", &dr_set_size }, + { UNIT_DR, 917504+1, NULL, "896K", &dr_set_size }, + { UNIT_DR, 1048576+1, NULL, "1024K", &dr_set_size }, + { UNIT_DR, 1572864+1, NULL, "1536K", &dr_set_size }, + { MTAB_XTD | MTAB_VDV, 1, NULL, "ENABLED", + &set_enb, NULL, &drd_dib }, + { MTAB_XTD | MTAB_VDV, 1, NULL, "DISABLED", + &set_dis, NULL, &drd_dib }, + { MTAB_XTD | MTAB_VDV, 1, "DEVNO", "DEVNO", + &hp_setdev, &hp_showdev, &drd_dib }, + { 0 } }; + +DEVICE drc_dev = { + "DRC", &drc_unit, drc_reg, drc_mod, + 1, 8, 21, 1, 8, 16, + NULL, NULL, &drc_reset, + NULL, NULL, NULL }; + +/* IOT routines */ + +int32 drdio (int32 inst, int32 IR, int32 dat) +{ +int32 devd, t; + +devd = IR & DEVMASK; /* get device no */ +switch (inst) { /* case on opcode */ +case ioFLG: /* flag clear/set */ + if ((IR & HC) == 0) { setFLG (devd); } /* STF */ + break; +case ioSFC: /* skip flag clear */ + if (FLG (devd) == 0) PC = (PC + 1) & VAMASK; + return dat; +case ioSFS: /* skip flag set */ + if (FLG (devd) != 0) PC = (PC + 1) & VAMASK; + return dat; +case ioOTX: /* output */ + drd_obuf = dat; + break; +case ioMIX: /* merge */ + dat = dat | drd_ibuf; + break; +case ioLIX: /* load */ + dat = drd_ibuf; + break; +case ioCTL: /* control clear/set */ + if (IR & AB) { /* CLC */ + clrCMD (devd); /* clr "ctl" */ + clrFLG (devd); /* clr flg */ + drc_sta = drc_sta & ~DRS_SAC; } /* clear SAC flag */ + else if (!CMD (devd)) { /* STC, not set? */ + setCMD (devd); /* set "ctl" */ + if (drc_cw & CW_WR) setFLG (devd); /* prime DMA */ + drc_sta = 0; /* clear errors */ + drd_ptr = 0; /* clear sec ptr */ + sim_cancel (&drc_unit); /* cancel curr op */ + t = CW_GETSEC (drc_cw) - GET_CURSEC (dr_time * DR_NUMWD); + if (t <= 0) t = t + DR_NUMSC; + sim_activate (&drc_unit, t * DR_NUMWD * dr_time); } + break; +default: + break; } +if (IR & HC) { clrFLG (devd); } /* H/C option */ +return dat; +} + +int32 drcio (int32 inst, int32 IR, int32 dat) +{ +int32 devc, st; + +devc = IR & DEVMASK; /* get device no */ +switch (inst) { /* case on opcode */ +case ioSFC: /* skip flag clear */ + PC = (PC + 1) & VAMASK; + return dat; +case ioOTX: /* output */ + drc_cw = dat; + break; +case ioLIX: /* load */ + dat = 0; +case ioMIX: /* merge */ + if (drc_unit.flags & UNIT_ATT) + st = GET_CURSEC (dr_time) | DRS_RDY | drc_sta | + (sim_is_active (&drc_unit)? DRS_BSY: 0); + else st = drc_sta; + break; +default: + break; } +return dat; +} + +/* Unit service */ + +t_stat drc_svc (UNIT *uptr) +{ +int32 devc, devd, trk, sec; +uint32 da; + +if ((uptr -> flags & UNIT_ATT) == 0) { + drc_sta = DRS_ABO; + return IORETURN (dr_stopioe, SCPE_UNATT); } + +drc_sta = drc_sta | DRS_SAC; +devc = drc_dib.devno; /* get cch devno */ +devd = drd_dib.devno; /* get dch devno */ +trk = CW_GETTRK (drc_cw); +sec = CW_GETSEC (drc_cw); +da = ((trk * DR_NUMSC) + sec) * DR_NUMWD; + +if (drc_cw & CW_WR) { /* write? */ + if ((da < uptr -> capac) && (sec < DR_NUMSC)) { + *(((uint16 *) uptr -> filebuf) + da + drd_ptr) = drd_obuf; + if (((t_addr) (da + drd_ptr)) >= uptr -> hwmark) + uptr -> hwmark = da + drd_ptr + 1; } + drd_ptr = dr_incda (trk, sec, drd_ptr); /* inc disk addr */ + if (CMD (devd)) { /* dch active? */ + setFLG (devd); /* set dch flg */ + sim_activate (uptr, dr_time); } /* sched next word */ + else if (drd_ptr) { /* done, need to fill? */ + for ( ; drd_ptr < DR_NUMWD; drd_ptr++) + *(((uint16 *) uptr -> filebuf) + da + drd_ptr) = 0; } + } /* end write */ +else { /* read */ + if (CMD (devd)) { /* dch active? */ + if ((da >= uptr -> capac) || (sec >= DR_NUMSC)) drd_ibuf = 0; + else drd_ibuf = *(((uint16 *) uptr -> filebuf) + da + drd_ptr); + drd_ptr = dr_incda (trk, sec, drd_ptr); + setFLG (devd); /* set dch flg */ + sim_activate (uptr, dr_time); } /* sched next word */ + } +return SCPE_OK; +} + +/* Increment current disk address */ + +int32 dr_incda (int32 trk, int32 sec, int32 ptr) +{ +ptr = ptr + 1; /* inc pointer */ +if (ptr >= DR_NUMWD) { /* end sector? */ + ptr = 0; /* new sector */ + sec = sec + 1; /* adv sector */ + if (sec >= DR_NUMSC) { /* end track? */ + sec = 0; /* new track */ + trk = trk + 1; /* adv track */ + if (trk >= MAX_TRK) trk = 0; } /* wraps at max */ + drc_cw = (drc_cw & CW_WR) | CW_PUTTRK (trk) | CW_PUTSEC (sec); + } +return ptr; +} + +/* Reset routine */ + +t_stat drc_reset (DEVICE *dptr) +{ +drc_sta = drc_cw = drd_ptr = 0; +drc_dib.cmd = drd_dib.cmd = 0; /* clear cmd */ +drc_dib.ctl = drd_dib.ctl = 0; /* clear ctl */ +drc_dib.fbf = drd_dib.fbf = 0; /* clear fbf */ +drc_dib.flg = drd_dib.flg = 0; /* clear flg */ +sim_cancel (&drc_unit); +return SCPE_OK; +} + +/* Set size routine */ + +/* Set size command validation routine */ + +t_stat dr_set_size (UNIT *uptr, int32 val, char *cptr, void *desc) +{ +if (uptr -> flags & UNIT_ATT) return SCPE_ALATT; +if (val & 1) uptr -> flags = uptr -> flags | UNIT_DR; +else uptr -> flags = uptr -> flags & ~UNIT_DR; +uptr -> capac = val & ~1; +return SCPE_OK; +} diff --git a/HP2100/hp2100_fp.c b/HP2100/hp2100_fp.c new file mode 100644 index 00000000..eba04975 --- /dev/null +++ b/HP2100/hp2100_fp.c @@ -0,0 +1,296 @@ +/* hp2100_fp.c: HP 2100 floating point instructions + + Copyright (c) 2002, Robert M. Supnik + + Permission is hereby granted, free of charge, to any person obtaining a + copy of this software and associated documentation files (the "Software"), + to deal in the Software without restriction, including without limitation + the rights to use, copy, modify, merge, publish, distribute, sublicense, + and/or sell copies of the Software, and to permit persons to whom the + Software is furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + ROBERT M SUPNIK BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + Except as contained in this notice, the name of Robert M Supnik shall not + be used in advertising or otherwise to promote the sale, use or other dealings + in this Software without prior written authorization from Robert M Supnik. + + The HP2100 uses a unique binary floating point format: + + 15 14 0 + +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ + |S | fraction high | : A + +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ + | fraction low | exponent |XS| : A + 1 + +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ + 15 8 7 1 0 + + where S = 0 for plus fraction, 1 for minus fraction + fraction = s.bbbbb..., 24 binary digits + exponent = 2**+/-n + XS = 0 for plus exponent, 1 for minus exponent + + Numbers can be normalized or unnormalized but are always normalized + when loaded. + + Unpacked floating point numbers are stored in structure ufp + + sign = fraction sign, 0 = +, 1 = - + exp = exponent, 2's complement + h'l = fraction, 2's comp, with 1 high guard bit + + Questions: + 1. Are fraction and exponent magnitude or 2's complement? 2's complement + 2. Do operations round? yes, with IEEE like standards (sticky bits) +*/ + +#include "hp2100_defs.h" + +struct ufp { /* unpacked fp */ + int32 sign; /* sign */ + int32 exp; /* exp */ + uint32 h; /* frac */ + uint32 l; }; + +#define FP_V_SIGN 31 /* sign */ +#define FP_M_SIGN 01 +#define FP_GETSIGN(x) (((x) >> FP_V_SIGN) & FP_M_SIGN) +#define FP_V_FRH 8 /* fraction */ +#define FP_M_FRH 077777777 +#define FP_FRH (FP_M_FRH << FP_V_FRH) +#define FP_V_EXP 1 /* exponent */ +#define FP_M_EXP 0177 +#define FP_GETEXP(x) (((x) >> FP_V_EXP) & FP_M_EXP) +#define FP_V_EXPS 0 /* exp sign */ +#define FP_M_EXPS 01 +#define FP_GETEXPS(x) (((x) >> FP_V_EXPS) & FP_M_EXPS) + +#define UFP_GUARD 1 /* 1 extra left */ +#define UFP_V_SIGN (FP_V_SIGN - UFP_GUARD) /* sign */ +#define UFP_SIGN (1 << UFP_V_SIGN) +#define UFP_CRY (1 << (UFP_V_SIGN + 1)) /* carry */ +#define UFP_NORM (1 << (UFP_V_SIGN - 1)) /* normalized */ +#define UFP_V_LOW (FP_V_FRH - UFP_GUARD) /* low bit */ +#define UFP_LOW (1 << UFP_V_LOW) +#define UFP_RND (1 << (UFP_V_LOW - 1)) /* round */ +#define UFP_STKY (UFP_RND - 1) /* sticky bits */ + +#define FPAB ((((uint32) AR) << 16) | ((uint32) BR)) + +#define HFMASK 0x7FFFFFFF /* hi frac mask */ +#define LFMASK 0xFFFFFFFF /* lo frac mask */ + +/* Fraction shift; 0 < shift < 32 */ + +#define FR_ARSH(v,s) v.l = ((v.l >> (s)) | \ + (v.h << (32 - (s)))) & LFMASK; \ + v.h = ((v.h >> (s)) | ((v.h & UFP_SIGN)? \ + (LFMASK << (32 - (s))): 0)) & HFMASK + +#define FR_LRSH(v,s) v.l = ((v.l >> (s)) | \ + (v.h << (32 - (s)))) & LFMASK; \ + v.h = (v.h >> (s)) & HFMASK + +#define FR_NEG(v) v.l = (~v.l + 1) & LFMASK; \ + v.h = (~v.h + (v.l == 0)) & HFMASK + +#define FR_NEGH(v) v = (~v + 1) & HFMASK + +extern uint16 *M; +void UnpackFP (struct ufp *fop, uint32 opnd, t_bool abs); +void NormFP (struct ufp *fop); +int32 StoreFP (struct ufp *fop, t_bool rnd); + +/* Floating to integer conversion */ + +int32 f_fix (void) +{ +struct ufp res; + +UnpackFP (&res, FPAB, 0); /* unpack A-B, norm */ +if ((res.h == 0) || (res.exp <= 0)) { /* result zero? */ + AR = 0; + return 0; } +if (res.exp > 15) { + AR = 077777; + return 1; } +FR_ARSH (res, (30 - res.exp)); /* right align frac */ +if (res.sign && res.l) res.h = res.h + 1; /* round? */ +AR = res.h & DMASK; /* store result */ +return 0; +} + +/* Integer to floating conversion */ + +void f_flt (void) +{ +struct ufp res = { 0, 15, 0, 0 }; /* +, 2**15 */ + +res.h = ((uint32) AR) << 15; /* left justify */ +if (res.h & UFP_SIGN) res.sign = 1; /* set sign */ +NormFP (&res); /* normalize */ +StoreFP (&res, 0); /* store result */ +return; +} + +/* Floating point add/subtract */ + +int32 f_as (uint32 opnd, t_bool sub) +{ +struct ufp fop1, fop2, t; +int32 ediff; + +UnpackFP (&fop1, FPAB, 0); /* unpack A-B, norm */ +UnpackFP (&fop2, opnd, 0); /* get op, norm */ +if (sub) { /* subtract? */ + fop2.sign = fop2.sign ^ 1; /* negate sign */ + fop2.h = FR_NEGH (fop2.h); /* negate frac */ + if (fop2.h & UFP_SIGN) { /* -1/2? */ + fop2.h = UFP_NORM; /* special case */ + fop2.exp = fop2.exp + 1; } } +if (fop1.h == 0) fop1 = fop2; /* op1 = 0? res = op2 */ +else if (fop2.h != 0) { /* op2 = 0? no add */ + if (fop1.exp < fop2.exp) { /* |op1| < |op2|? */ + t = fop2; /* swap operands */ + fop2 = fop1; + fop1 = t; } + ediff = fop1.exp - fop2.exp; /* get exp diff */ + if (ediff <= 24) { + if (ediff) { FR_ARSH (fop2, ediff); } /* denorm, signed */ + fop1.h = fop1.h + fop2.h; /* add fractions */ + if (fop1.sign ^ fop2.sign) { /* eff subtract */ + if (fop1.h & UFP_SIGN) fop1.sign = 1; /* result neg? */ + else fop1.sign = 0; + NormFP (&fop1); } /* normalize result */ + else if (fop1.h & (fop1.sign? UFP_CRY: UFP_SIGN)) { /* add, cry out? */ + fop1.h = fop1.h >> 1; /* renormalize */ + fop1.exp = fop1.exp + 1; } /* incr exp */ + } /* end if ediff */ + } /* end if fop2 */ +return StoreFP (&fop1, 1); /* store result */ +} + +/* Floating point multiply */ + +int32 f_mul (uint32 opnd) +{ +struct ufp fop1, fop2; +struct ufp res = { 0, 0, 0, 0 }; +int32 i; + +UnpackFP (&fop1, FPAB, 1); /* unpack |A-B|, norm */ +UnpackFP (&fop2, opnd, 1); /* unpack |op|, norm */ +if (fop1.h && fop2.h) { /* if both != 0 */ + res.sign = fop1.sign ^ fop2.sign; /* sign = diff */ + res.exp = fop1.exp + fop2.exp; /* exp = sum */ + for (i = 0; i < 24; i++) { /* 24 iterations */ + if (fop2.h & UFP_LOW) /* mplr bit set? */ + res.h = res.h + fop1.h; /* add mpcn to res */ + fop2.h = fop2.h >> 1; /* shift mplr */ + FR_LRSH (res, 1); } /* shift res */ + if (res.sign) FR_NEG (res); /* correct sign */ + NormFP (&res); /* normalize */ + } +return StoreFP (&res, 1); /* store */ +} + +/* Floating point divide */ + +int32 f_div (uint32 opnd) +{ +struct ufp fop1, fop2; +struct ufp quo = { 0, 0, 0, 0 }; +int32 i; + +UnpackFP (&fop1, FPAB, 1); /* unpack |A-B|, norm */ +UnpackFP (&fop2, opnd, 1); /* unpack |op|, norm */ +if (fop2.h == 0) return 1; /* div by zero? */ +if (fop1.h) { /* dvd != 0? */ + quo.sign = fop1.sign ^ fop2.sign; /* sign = diff */ + quo.exp = fop1.exp - fop2.exp; /* exp = diff */ + if (fop1.h < fop2.h) { /* will sub work? */ + fop1.h = fop1.h << 1; /* ensure success */ + quo.exp = quo.exp - 1; } + for (i = 0; i < 24; i++) { /* 24 digits */ + quo.h = quo.h << 1; /* shift quotient */ + if (fop1.h >= fop2.h) { /* subtract work? */ + fop1.h = fop1.h - fop2.h; /* decrement */ + quo.h = quo.h + UFP_RND; } /* add quo bit */ + fop1.h = fop1.h << 1; } /* shift divd */ + } /* end if fop1.h */ +if (quo.sign) quo.h = FR_NEGH (quo.h); /* correct sign */ +NormFP (&quo); /* negate */ +return StoreFP (&quo, 1); /* store result */ +} + +/* Utility routines */ + +/* Unpack operand */ + +void UnpackFP (struct ufp *fop, uint32 opnd, t_bool abs) +{ +fop -> h = (opnd & FP_FRH) >> UFP_GUARD; /* get frac, guard */ +if (fop -> h) { /* non-zero? */ + fop -> sign = FP_GETSIGN (opnd); /* get sign */ + fop -> exp = FP_GETEXP (opnd); /* get exp */ + if (FP_GETEXPS (opnd)) /* get exp sign */ + fop -> exp = fop -> exp | ~FP_M_EXP; /* if -, sext */ + if (abs && fop -> sign) { /* want abs val? */ + fop -> h = FR_NEGH (fop -> h); /* negate frac*/ + if (fop -> h == UFP_SIGN) { /* -1/2? */ + fop -> h = fop -> h >> 1; /* special case */ + fop -> exp = fop -> exp + 1; } } + NormFP (fop); } /* normalize */ +else fop -> sign = fop -> exp = 0; /* clean zero */ +fop -> l = 0; +return; +} + +/* Normalize unpacked floating point number */ + +void NormFP (struct ufp *fop) +{ +if (fop -> h | fop -> l) { /* any fraction? */ + uint32 test = (fop -> h >> 1) & UFP_NORM; + while ((fop -> h & UFP_NORM) == test) { /* until norm */ + fop -> exp = fop -> exp - 1; + fop -> h = (fop -> h << 1) | (fop -> l >> 31); + fop -> l = fop -> l << 1; } } +else fop -> sign = fop -> exp = 0; /* clean 0 */ +return; +} + +/* Round fp number, store, generate overflow */ + +int32 StoreFP (struct ufp *fop, t_bool rnd) +{ +int32 hi, ov; + +if (rnd && (fop -> h & UFP_RND) && + ((fop -> sign == 0) || (fop -> h & UFP_STKY) || fop -> l)) { + fop -> h = fop -> h + UFP_RND; /* round */ + if (fop -> h & ((fop -> sign)? UFP_CRY: UFP_SIGN)) { + fop -> h = fop -> h >> 1; + fop -> exp = fop -> exp + 1; } } +if (fop -> h == 0) hi = ov = 0; /* result 0? */ +else if (fop -> exp < -(FP_M_EXP + 1)) { /* underflow? */ + hi = 0; /* store clean 0 */ + ov = 1; } +else if (fop -> exp > FP_M_EXP) { /* overflow? */ + hi = 0x7FFFFFFE; /* all 1's */ + ov = 1; } +else { hi = ((fop -> h << UFP_GUARD) & FP_FRH) | /* merge frac */ + ((fop -> exp & FP_M_EXP) << FP_V_EXP); /* and exp */ + if (fop -> exp < 0) hi = hi | (1 << FP_V_EXPS); } /* add exp sign */ +AR = (hi >> 16) & DMASK; +BR = hi & DMASK; +return ov; +} diff --git a/HP2100/hp2100_lp.c b/HP2100/hp2100_lp.c index e50a2871..bf7981d8 100644 --- a/HP2100/hp2100_lp.c +++ b/HP2100/hp2100_lp.c @@ -1,6 +1,6 @@ -/* hp2100_lp.c: HP 2100 line printer simulator +/* hp2100_lp.c: HP 2100 12653A line printer simulator - Copyright (c) 1993-2001, Robert M. Supnik + Copyright (c) 1993-2002, Robert M. Supnik Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), @@ -25,6 +25,7 @@ lpt 12653A line printer + 30-May-02 RMS Widened POS to 32b 03-Dec-01 RMS Changed DEVNO to use extended SET/SHOW 07-Sep-01 RMS Moved function prototypes 21-Nov-00 RMS Fixed flag, fbf power up state @@ -41,9 +42,10 @@ extern int32 PC; extern int32 dev_cmd[2], dev_ctl[2], dev_flg[2], dev_fbf[2]; int32 lpt_ctime = 10; /* char time */ int32 lpt_stopioe = 0; /* stop on error */ + +int32 lptio (int32 inst, int32 IR, int32 dat); t_stat lpt_svc (UNIT *uptr); t_stat lpt_reset (DEVICE *dptr); -extern struct hpdev infotab[]; /* LPT data structures @@ -52,25 +54,32 @@ extern struct hpdev infotab[]; lpt_reg LPT register list */ +DIB lpt_dib = { LPT, 1, 0, 0, 0, 0, &lptio }; + UNIT lpt_unit = { UDATA (&lpt_svc, UNIT_SEQ+UNIT_ATTABLE, 0), SERIAL_OUT_WAIT }; REG lpt_reg[] = { { ORDATA (BUF, lpt_unit.buf, 7) }, - { FLDATA (CMD, infotab[inLPT].cmd, 0) }, - { FLDATA (CTL, infotab[inLPT].ctl, 0) }, - { FLDATA (FLG, infotab[inLPT].flg, 0) }, - { FLDATA (FBF, infotab[inLPT].fbf, 0) }, - { DRDATA (POS, lpt_unit.pos, 31), PV_LEFT }, + { FLDATA (CMD, lpt_dib.cmd, 0) }, + { FLDATA (CTL, lpt_dib.ctl, 0) }, + { FLDATA (FLG, lpt_dib.flg, 0) }, + { FLDATA (FBF, lpt_dib.fbf, 0) }, + { DRDATA (POS, lpt_unit.pos, 32), PV_LEFT }, { DRDATA (CTIME, lpt_ctime, 31), PV_LEFT }, { DRDATA (PTIME, lpt_unit.wait, 24), PV_LEFT }, { FLDATA (STOP_IOE, lpt_stopioe, 0) }, - { ORDATA (DEVNO, infotab[inLPT].devno, 6), REG_RO }, + { ORDATA (DEVNO, lpt_dib.devno, 6), REG_HRO }, + { FLDATA (*DEVENB, lpt_dib.enb, 0), REG_HRO }, { NULL } }; MTAB lpt_mod[] = { - { MTAB_XTD | MTAB_VDV, inLPT, "DEVNO", "DEVNO", - &hp_setdev, &hp_showdev, NULL }, + { MTAB_XTD | MTAB_VDV, 0, NULL, "ENABLED", + &set_enb, NULL, &lpt_dib }, + { MTAB_XTD | MTAB_VDV, 0, NULL, "DISABLED", + &set_dis, NULL, &lpt_dib }, + { MTAB_XTD | MTAB_VDV, 0, "DEVNO", "DEVNO", + &hp_setdev, &hp_showdev, &lpt_dib }, { 0 } }; DEVICE lpt_dev = { @@ -91,10 +100,10 @@ case ioFLG: /* flag clear/set */ if ((IR & HC) == 0) { setFLG (dev); } /* STF */ break; case ioSFC: /* skip flag clear */ - if (FLG (dev) == 0) PC = (PC + 1) & AMASK; + if (FLG (dev) == 0) PC = (PC + 1) & VAMASK; return dat; case ioSFS: /* skip flag set */ - if (FLG (dev) != 0) PC = (PC + 1) & AMASK; + if (FLG (dev) != 0) PC = (PC + 1) & VAMASK; return dat; case ioOTX: /* output */ lpt_unit.buf = dat & 0177; @@ -124,7 +133,7 @@ t_stat lpt_svc (UNIT *uptr) { int32 dev; -dev = infotab[inLPT].devno; /* get dev no */ +dev = lpt_dib.devno; /* get dev no */ clrCMD (dev); /* clear cmd */ if ((lpt_unit.flags & UNIT_ATT) == 0) /* attached? */ return IORETURN (lpt_stopioe, SCPE_UNATT); @@ -137,12 +146,12 @@ lpt_unit.pos = ftell (lpt_unit.fileref); /* update pos */ return SCPE_OK; } -/* Reset routine - called from SCP, flags in infotab */ +/* Reset routine - called from SCP, flags in DIB */ t_stat lpt_reset (DEVICE *dptr) { -infotab[inLPT].cmd = infotab[inLPT].ctl = 0; /* clear cmd, ctl */ -infotab[inLPT].flg = infotab[inLPT].fbf = 1; /* set flg, fbf */ +lpt_dib.cmd = lpt_dib.ctl = 0; /* clear cmd, ctl */ +lpt_dib.flg = lpt_dib.fbf = 1; /* set flg, fbf */ lpt_unit.buf = 0; sim_cancel (&lpt_unit); /* deactivate unit */ return SCPE_OK; diff --git a/HP2100/hp2100_ms.c b/HP2100/hp2100_ms.c new file mode 100644 index 00000000..9160f499 --- /dev/null +++ b/HP2100/hp2100_ms.c @@ -0,0 +1,509 @@ +/* hp2100_ms.c: HP 2100 13181A magnetic tape simulator + + Copyright (c) 1993-2002, Robert M. Supnik + + Permission is hereby granted, free of charge, to any person obtaining a + copy of this software and associated documentation files (the "Software"), + to deal in the Software without restriction, including without limitation + the rights to use, copy, modify, merge, publish, distribute, sublicense, + and/or sell copies of the Software, and to permit persons to whom the + Software is furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + ROBERT M SUPNIK BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + Except as contained in this notice, the name of Robert M Supnik shall not + be used in advertising or otherwise to promote the sale, use or other dealings + in this Software without prior written authorization from Robert M Supnik. + + ms 13181A nine track magnetic tape + + 30-May-02 RMS Widened POS to 32b + 22-Apr-02 RMS Added maximum record length test + + Magnetic tapes are represented as a series of variable records + of the form: + + 32b byte count + byte 0 + byte 1 + : + byte n-2 + byte n-1 + 32b byte count + + If the byte count is odd, the record is padded with an extra byte + of junk. File marks are represented by a byte count of 0. + + Unusually among HP peripherals, the 12559 does not have a command flop, + and its flag and flag buffer power up as clear rather than set. +*/ + +#include "hp2100_defs.h" + +#define MS_NUMDR 4 /* number of drives */ +#define UNIT_V_WLK (UNIT_V_UF + 0) /* write locked */ +#define UNIT_WLK (1 << UNIT_V_WLK) +#define DB_N_SIZE 16 /* max data buf */ +#define DBSIZE (1 << DB_N_SIZE) /* max data cmd */ +#define DBMASK (DBSIZE - 1) +#define UNIT_WPRT (UNIT_WLK | UNIT_RO) /* write protect */ +#define FNC u3 /* function */ +#define UST u4 /* unit status */ + +/* Command - msc_fnc */ + +#define FNC_CLR 0110 /* clear */ +#define FNC_GAP 0015 /* write gap */ +#define FNC_GFM 0215 /* gap+file mark */ +#define FNC_RC 0023 /* read */ +#define FNC_WC 0031 /* write */ +#define FNC_FSR 0003 /* forward space */ +#define FNC_BSR 0041 /* backward space */ +#define FNC_FSF 0203 /* forward file */ +#define FNC_BSF 0241 /* backward file */ +#define FNC_REW 0101 /* rewind */ +#define FNC_RWS 0105 /* rewind and offline */ +#define FNC_WFM 0211 /* write file mark */ +#define FNC_CHS 0400 /* change select */ +#define FNC_V_SEL 9 /* select */ +#define FNC_M_SEL 017 +#define FNC_GETSEL(x) (((x) >> FNC_V_SEL) & FNC_M_SEL) + +#define FNF_MOT 0001 /* motion */ +#define FNF_OFL 0004 +#define FNF_WRT 0010 /* write */ +#define FNF_REV 0040 /* reverse */ +#define FNF_RWD 0100 /* rewind */ + +/* Status - stored in msc_sta, unit.UST (u), or dynamic (d) */ + +#define STA_ODD 04000 /* odd bytes */ +#define STA_REW 02000 /* rewinding (u) */ +#define STA_TBSY 01000 /* transport busy (d) */ +#define STA_BUSY 00400 /* ctrl busy */ +#define STA_EOF 00200 /* end of file */ +#define STA_BOT 00100 /* beg of tape (d) */ +#define STA_EOT 00040 /* end of tape (u) */ +#define STA_TIM 00020 /* timing error */ +#define STA_REJ 00010 /* programming error */ +#define STA_WLK 00004 /* write locked (d) */ +#define STA_PAR 00002 /* parity error */ +#define STA_LOCAL 00001 /* local (d) */ +#define STA_STATIC (STA_ODD|STA_BUSY|STA_EOF|STA_TIM|STA_REJ|STA_PAR) + +extern int32 PC; +extern int32 dev_cmd[2], dev_ctl[2], dev_flg[2], dev_fbf[2]; +int32 msc_sta = 0; /* status */ +int32 msc_buf = 0; /* buffer */ +int32 msc_usl = 0; /* unit select */ +int32 msc_1st = 0; +int32 msc_ctime = 1000; /* command wait */ +int32 msc_xtime = 10; /* data xfer time */ +int32 msc_stopioe = 1; /* stop on error */ +int32 msd_buf = 0; /* data buffer */ +uint8 msxb[DBSIZE] = { 0 }; /* data buffer */ +t_mtrlnt ms_ptr = 0, ms_max = 0; /* buffer ptrs */ + +int32 msdio (int32 inst, int32 IR, int32 dat); +int32 mscio (int32 inst, int32 IR, int32 dat); +t_stat msc_svc (UNIT *uptr); +t_stat msc_reset (DEVICE *dptr); +t_stat msc_vlock (UNIT *uptr, int32 val, char *cptr, void *desc); +t_bool ms_forwsp (UNIT *uptr, int32 *err); +t_bool ms_backsp (UNIT *uptr, int32 *err); + +/* MSD data structures + + msd_dev MSD device descriptor + msd_unit MSD unit list + msd_reg MSD register list +*/ + +DIB ms_dib[] = { + { MSD, 1, 0, 0, 0, 0, &msdio }, + { MSC, 1, 0, 0, 0, 0, &mscio } }; + +#define msd_dib ms_dib[0] +#define msc_dib ms_dib[1] + +UNIT msd_unit = { UDATA (NULL, 0, 0) }; + +REG msd_reg[] = { + { ORDATA (BUF, msd_buf, 16) }, + { FLDATA (CMD, msd_dib.cmd, 0), REG_HRO }, + { FLDATA (CTL, msd_dib.ctl, 0) }, + { FLDATA (FLG, msd_dib.flg, 0) }, + { FLDATA (FBF, msd_dib.fbf, 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 }, + { FLDATA (*DEVENB, msd_dib.enb, 0), REG_HRO }, + { NULL } }; + +MTAB msd_mod[] = { + { MTAB_XTD | MTAB_VDV, 1, "DEVNO", "DEVNO", + &hp_setdev, &hp_showdev, &msd_dib }, + { 0 } }; + +DEVICE msd_dev = { + "MSD", &msd_unit, msd_reg, msd_mod, + 1, 10, DB_N_SIZE, 1, 8, 8, + NULL, NULL, &msc_reset, + NULL, NULL, NULL }; + +/* MSC data structures + + msc_dev MSC device descriptor + msc_unit MSC unit list + msc_reg MSC register list + msc_mod MSC modifier list +*/ + +UNIT msc_unit[] = { + { UDATA (&msc_svc, UNIT_ATTABLE + UNIT_ROABLE + UNIT_DISABLE, 0) }, + { UDATA (&msc_svc, UNIT_ATTABLE + UNIT_ROABLE + UNIT_DISABLE, 0) }, + { UDATA (&msc_svc, UNIT_ATTABLE + UNIT_ROABLE + UNIT_DISABLE, 0) }, + { UDATA (&msc_svc, UNIT_ATTABLE + UNIT_ROABLE + UNIT_DISABLE, 0) } }; + +REG msc_reg[] = { + { ORDATA (STA, msc_sta, 12) }, + { ORDATA (BUF, msc_buf, 16) }, + { ORDATA (USEL, msc_usl, 2) }, + { FLDATA (FSVC, msc_1st, 0) }, + { FLDATA (CMD, msc_dib.cmd, 0), REG_HRO }, + { FLDATA (CTL, msc_dib.ctl, 0) }, + { FLDATA (FLG, msc_dib.flg, 0) }, + { FLDATA (FBF, msc_dib.fbf, 0) }, + { URDATA (POS, msc_unit[0].pos, 8, 32, 0, MS_NUMDR, PV_LEFT) }, + { URDATA (FNC, msc_unit[0].FNC, 8, 12, 0, MS_NUMDR, REG_HRO) }, + { URDATA (UST, msc_unit[0].UST, 8, 12, 0, MS_NUMDR, REG_HRO) }, + { DRDATA (CTIME, msc_ctime, 24), REG_NZ + PV_LEFT }, + { DRDATA (XTIME, msc_xtime, 24), REG_NZ + PV_LEFT }, + { FLDATA (STOP_IOE, msc_stopioe, 0) }, + { URDATA (WLK, msc_unit[0].flags, 8, 1, UNIT_V_WLK, MS_NUMDR, REG_HRO) }, + { ORDATA (DEVNO, msc_dib.devno, 6), REG_HRO }, + { FLDATA (*DEVENB, msc_dib.enb, 0), REG_HRO }, + { NULL } }; + +MTAB msc_mod[] = { + { UNIT_WLK, 0, "write enabled", "WRITEENABLED", &msc_vlock }, + { UNIT_WLK, UNIT_WLK, "write locked", "LOCKED", &msc_vlock }, + { MTAB_XTD | MTAB_VDV, 1, NULL, "ENABLED", + &set_enb, NULL, &msd_dib }, + { MTAB_XTD | MTAB_VDV, 1, NULL, "DISABLED", + &set_dis, NULL, &msd_dib }, + { MTAB_XTD | MTAB_VDV, 1, "DEVNO", "DEVNO", + &hp_setdev, &hp_showdev, &msd_dib }, + { 0 } }; + +DEVICE msc_dev = { + "MSC", msc_unit, msc_reg, msc_mod, + MS_NUMDR, 10, 31, 1, 8, 8, + NULL, NULL, &msc_reset, + NULL, NULL, NULL }; + +/* IOT routines */ + +int32 msdio (int32 inst, int32 IR, int32 dat) +{ +int32 devd; + +devd = IR & DEVMASK; /* get device no */ +switch (inst) { /* case on opcode */ +case ioFLG: /* flag clear/set */ + if ((IR & HC) == 0) { setFLG (devd); } /* STF */ + break; +case ioSFC: /* skip flag clear */ + if (FLG (devd) == 0) PC = (PC + 1) & VAMASK; + return dat; +case ioSFS: /* skip flag set */ + if (FLG (devd) != 0) PC = (PC + 1) & VAMASK; + return dat; +case ioOTX: /* output */ + msd_buf = dat; /* store data */ + break; +case ioMIX: /* merge */ + dat = dat | msd_buf; + break; +case ioLIX: /* load */ + dat = msd_buf; + break; +case ioCTL: /* control clear/set */ + if (IR & AB) { /* CLC */ + clrCTL (devd); /* clr ctl, cmd */ + clrCMD (devd); } + else { setCTL (devd); /* STC */ + setCMD (devd); } /* set ctl, cmd */ + break; +default: + break; } +if (IR & HC) { clrFLG (devd); } /* H/C option */ +return dat; +} + +int32 mscio (int32 inst, int32 IR, int32 dat) +{ +int32 i, devc, devd; +UNIT *uptr = msc_dev.units + msc_usl; +static const uint8 map_sel[16] = { + 0, 0, 1, 1, 2, 2, 2, 2, + 3, 3, 3, 3, 3, 3, 3, 3 }; + +devc = IR & DEVMASK; /* get device no */ +devd = devc - 1; +switch (inst) { /* case on opcode */ +case ioFLG: /* flag clear/set */ + if ((IR & HC) == 0) { setFLG (devc); } /* STF */ + break; +case ioSFC: /* skip flag clear */ + if (FLG (devc) == 0) PC = (PC + 1) & VAMASK; + return dat; +case ioSFS: /* skip flag set */ + if (FLG (devc) != 0) PC = (PC + 1) & VAMASK; + return dat; +case ioOTX: /* output */ + msc_buf = dat = dat & 07777; + if (dat == FNC_CLR) { /* clear? */ + for (i = 0; i < MS_NUMDR; i++) { + if ((msc_unit[i].UST & STA_REW) == 0) + sim_cancel (&msc_unit[i]); } + clrCTL (devc); /* init device */ + clrFLG (devc); + clrCTL (devd); + clrFLG (devd); + msc_sta = msd_buf = msc_buf = msc_1st = 0; + break; } + if (msc_sta & STA_BUSY) { + msc_sta = msc_sta | STA_REJ; + break; } + if (dat & FNC_CHS) { + msc_usl = map_sel[FNC_GETSEL (dat)]; + uptr = msc_dev.units + msc_usl; } + if (((dat & FNF_MOT) && sim_is_active (uptr)) || + ((dat & FNF_REV) && (uptr -> pos == 0)) || + ((dat & FNF_WRT) && (uptr -> flags & UNIT_WPRT))) + msc_sta = msc_sta | STA_REJ; + break; +case ioLIX: /* load */ + dat = 0; +case ioMIX: /* merge */ + msc_sta = (msc_sta & STA_STATIC) | uptr -> UST; + if (uptr -> flags & UNIT_ATT) { + msc_sta = msc_sta & ~(STA_LOCAL | STA_WLK | STA_TBSY); + if (sim_is_active (uptr)) + msc_sta = msc_sta | STA_TBSY; + if (uptr -> flags & UNIT_WPRT) + msc_sta = msc_sta | STA_WLK; } + else msc_sta = msc_sta | STA_TBSY | STA_LOCAL; + dat = dat | msc_sta; + break; +case ioCTL: /* control clear/set */ + if (IR & AB) { clrCTL (devc); } /* CLC */ + else if (!CTL (devc)) { /* STC, not busy? */ + uptr -> FNC = msc_buf; /* save function */ + if (uptr -> FNC & FNF_RWD) { + uptr -> UST = STA_REW; + sim_activate (uptr, msc_xtime); } + else { uptr -> UST = 0; /* clr unit status */ + sim_activate (uptr, msc_ctime); } + msc_sta = STA_BUSY; + msc_1st = 1; + setCTL (devc); } + break; +default: + break; } +if (IR & HC) { clrFLG (devc); } /* H/C option */ +return dat; +} + +/* Unit service + + If rewind done, reposition to start of tape, set status + else, do operation, set done, interrupt + + Can't be write locked, can only write lock detached unit +*/ + +t_stat msc_svc (UNIT *uptr) +{ +int32 devc, devd, err, i; +static t_mtrlnt bceof = { 0 }; + +if ((uptr -> flags & UNIT_ATT) == 0) { /* offline? */ + msc_sta = STA_LOCAL | STA_BUSY | STA_REJ; + return IORETURN (msc_stopioe, SCPE_UNATT); } +devc = msc_dib.devno; /* get device nos */ +devd = msd_dib.devno; + +if (uptr -> UST & STA_REW) { /* rewinding? */ + if (msc_sta & STA_BUSY) { /* controller busy? */ + sim_activate (uptr, msc_ctime); /* do real rewind */ + setFLG (devc); /* set cch flg */ + msc_sta = msc_sta & ~STA_BUSY; } /* update status */ + else { uptr -> pos = 0; /* rewind done */ + uptr -> UST = 0; /* offline? */ + if (uptr -> FNC & FNF_OFL) detach_unit (uptr); } + return SCPE_OK; } + +err = 0; /* assume no errors */ +switch (uptr -> FNC & 07777) { /* case on function */ +case FNC_GFM: /* gap file mark */ +case FNC_WFM: /* write file mark */ + fseek (uptr -> fileref, uptr -> pos, SEEK_SET); + fxwrite (&bceof, sizeof (t_mtrlnt), 1, uptr -> fileref); + err = ferror (uptr -> fileref); + uptr -> pos = uptr -> pos + sizeof (t_mtrlnt); /* update tape pos */ + msc_sta = msc_sta | STA_EOF; /* set EOF status */ +case FNC_GAP: /* erase gap */ + break; + +case FNC_FSF: + while (ms_forwsp (uptr, &err)) ; /* spc until EOF/EOT */ + break; +case FNC_FSR: /* space forward */ + ms_forwsp (uptr, &err); + break; +case FNC_BSF: + while (ms_backsp (uptr, &err)) ; /* spc until EOF/EOT */ + break; +case FNC_BSR: /* space reverse */ + ms_backsp (uptr, &err); + break; + +/* Unit service, continued */ + +case FNC_RC: /* read */ + if (msc_1st) { /* first svc? */ + msc_1st = ms_ptr = 0; /* clr 1st flop */ + fseek (uptr -> fileref, uptr -> pos, SEEK_SET); + fxread (&ms_max, sizeof (t_mtrlnt), 1, uptr -> fileref); + if ((err = ferror (uptr -> fileref)) || + feof (uptr -> fileref)) { /* error or eof? */ + uptr -> UST = STA_EOT; + break; } + if (ms_max == 0) { /* tape mark? */ + uptr -> pos = uptr -> pos + sizeof (t_mtrlnt); + msc_sta = msc_sta | STA_EOF; + break; } + ms_max = MTRL (ms_max); /* ignore errors */ + uptr -> pos = uptr -> pos + ((ms_max + 1) & ~1) + + (2 * sizeof (t_mtrlnt)); /* update position */ + if (ms_max > DBSIZE) return SCPE_MTRLNT;/* record too long? */ + i = fxread (msxb, sizeof (int8), ms_max, uptr -> fileref); + for ( ; i < ms_max; i++) msxb[i] = 0; /* fill with 0's */ + err = ferror (uptr -> fileref); } + if (ms_ptr < ms_max) { /* more chars? */ + if (FLG (devd)) msc_sta = msc_sta | STA_TIM; + msd_buf = ((uint16) msxb[ms_ptr] << 8) | + msxb[ms_ptr + 1]; + ms_ptr = ms_ptr + 2; + setFLG (devd); /* set dch flg */ + sim_activate (uptr, msc_xtime); /* re-activate */ + return SCPE_OK; } + if (ms_max & 1) msc_sta = msc_sta | STA_ODD; + break; +case FNC_WC: /* write */ + if (msc_1st) msc_1st = ms_ptr = 0; + else { if (ms_ptr < DBSIZE) { /* room in buffer? */ + msxb[ms_ptr] = msd_buf >> 8; + msxb[ms_ptr + 1] = msd_buf & 0377; + ms_ptr = ms_ptr + 2; } + else msc_sta = msc_sta | STA_PAR; } + if (CTL (devd)) { /* xfer flop set? */ + setFLG (devd); /* set dch flag */ + sim_activate (uptr, msc_xtime); /* re-activate */ + return SCPE_OK; } + if (ms_ptr) { /* write buffer */ + fseek (uptr -> fileref, uptr -> pos, SEEK_SET); + fxwrite (&ms_ptr, sizeof (t_mtrlnt), 1, uptr -> fileref); + fxwrite (msxb, sizeof (int8), ms_ptr, uptr -> fileref); + fxwrite (&ms_ptr, sizeof (t_mtrlnt), 1, uptr -> fileref); + err = ferror (uptr -> fileref); + uptr -> pos = uptr -> pos + ((ms_ptr + 1) & ~1) + + (2 * sizeof (t_mtrlnt)); } + break; } + +/* Unit service, continued */ + +setFLG (devc); /* set cch flg */ +msc_sta = msc_sta & ~STA_BUSY; /* update status */ +if (err != 0) { /* I/O error */ + perror ("MT I/O error"); + clearerr (uptr -> fileref); + IORETURN (msc_stopioe, SCPE_IOERR); } +return SCPE_OK; +} + +t_bool ms_forwsp (UNIT *uptr, int32 *err) +{ +t_mtrlnt tbc; + +fseek (uptr -> fileref, uptr -> pos, SEEK_SET); /* position */ +fxread (&tbc, sizeof (t_mtrlnt), 1, uptr -> fileref); /* get bc */ +if ((*err = ferror (uptr -> fileref)) || feof (uptr -> fileref)) { + uptr -> UST = STA_EOT; + return FALSE; } +if (tbc == 0) { /* zero bc? */ + uptr -> pos = uptr -> pos + sizeof (t_mtrlnt); + msc_sta = msc_sta | STA_EOF; /* eof */ + return FALSE; } +uptr -> pos = uptr -> pos + ((MTRL (tbc) + 1) & ~1) + (2 * sizeof (t_mtrlnt)); +return TRUE; +} + +t_bool ms_backsp (UNIT *uptr, int32 *err) +{ +t_mtrlnt tbc; + +if (uptr -> pos == 0) return FALSE; /* at bot? */ +fseek (uptr -> fileref, uptr -> pos - sizeof (t_mtrlnt), SEEK_SET); +fxread (&tbc, sizeof (t_mtrlnt), 1, uptr -> fileref); /* get bc */ +if ((*err = ferror (uptr -> fileref)) || feof (uptr -> fileref)) { + uptr -> UST = STA_EOT; + uptr -> pos = 0; + return FALSE; } +if (tbc == 0) { /* zero bc? */ + uptr -> pos = uptr -> pos - sizeof (t_mtrlnt); + msc_sta = msc_sta | STA_EOF; /* eof */ + return FALSE; } +uptr -> pos = uptr -> pos - ((MTRL (tbc) + 1) & ~1) - (2 * sizeof (t_mtrlnt)); +return TRUE; +} + +/* Reset routine */ + +t_stat msc_reset (DEVICE *dptr) +{ +int32 i; +UNIT *uptr; + +msc_buf = msd_buf = 0; +msc_sta = msc_usl = 0; +msc_1st = 0; +msc_dib.cmd = msd_dib.cmd = 0; /* clear cmd */ +msc_dib.ctl = msd_dib.ctl = 0; /* clear ctl */ +msc_dib.flg = msd_dib.flg = 0; /* clear flg */ +msc_dib.fbf = msd_dib.fbf = 0; /* clear fbf */ +for (i = 0; i < MS_NUMDR; i++) { + uptr = msc_dev.units + i; + sim_cancel (uptr); + uptr -> UST = 0; } +return SCPE_OK; +} + +/* Write lock/enable routine */ + +t_stat msc_vlock (UNIT *uptr, int32 val, char *cptr, void *desc) +{ +if (val && (uptr -> flags & UNIT_ATT)) return SCPE_ARG; +return SCPE_OK; +} diff --git a/HP2100/hp2100_mt.c b/HP2100/hp2100_mt.c index b4d32454..9838902b 100644 --- a/HP2100/hp2100_mt.c +++ b/HP2100/hp2100_mt.c @@ -1,6 +1,6 @@ -/* hp2100_mt.c: HP 2100 magnetic tape simulator +/* hp2100_mt.c: HP 2100 12559A magnetic tape simulator - Copyright (c) 1993-2001, Robert M. Supnik + Copyright (c) 1993-2002, Robert M. Supnik Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), @@ -25,6 +25,9 @@ mt 12559A nine track magnetic tape + 30-May-02 RMS Widened POS to 32b + 22-Apr-02 RMS Added maximum record length test + 20-Jan-02 RMS Fixed bug on last character write 03-Dec-01 RMS Added read only unit, extended SET/SHOW support 07-Sep-01 RMS Moved function prototypes 30-Nov-00 RMS Made variable names unique @@ -81,8 +84,6 @@ #define STA_PAR 0002 /* parity error */ #define STA_BUSY 0001 /* busy */ -extern uint16 M[]; -extern struct hpdev infotab[]; extern int32 PC; extern int32 dev_cmd[2], dev_ctl[2], dev_flg[2], dev_fbf[2]; int32 mtc_fnc = 0; /* function */ @@ -92,18 +93,18 @@ int32 mtc_1st = 0; /* first svc flop */ int32 mtc_ctime = 1000; /* command wait */ int32 mtc_xtime = 10; /* data xfer time */ int32 mtc_stopioe = 1; /* stop on error */ -uint8 mt_buf[DBSIZE] = { 0 }; /* data buffer */ +uint8 mtxb[DBSIZE] = { 0 }; /* data buffer */ t_mtrlnt mt_ptr = 0, mt_max = 0; /* buffer ptrs */ static const int32 mtc_cmd[] = { FNC_WC, FNC_RC, FNC_GAP, FNC_FSR, FNC_BSR, FNC_REW, FNC_RWS, FNC_WFM }; +int32 mtdio (int32 inst, int32 IR, int32 dat); +int32 mtcio (int32 inst, int32 IR, int32 dat); t_stat mtc_svc (UNIT *uptr); t_stat mtc_reset (DEVICE *dptr); t_stat mtc_vlock (UNIT *uptr, int32 val, char *cptr, void *desc); t_stat mtc_attach (UNIT *uptr, char *cptr); t_stat mtc_detach (UNIT *uptr); -t_stat mtd_ex (t_value *vptr, t_addr addr, UNIT *uptr, int32 sw); -t_stat mtd_dep (t_value val, t_addr addr, UNIT *uptr, int32 sw); /* MTD data structures @@ -112,22 +113,36 @@ t_stat mtd_dep (t_value val, t_addr addr, UNIT *uptr, int32 sw); mtd_reg MTD register list */ -UNIT mtd_unit = { UDATA (NULL, UNIT_FIX + UNIT_BINK, DBSIZE) }; +DIB mt_dib[] = { + { MTD, 1, 0, 0, 0, 0, &mtdio }, + { MTC, 1, 0, 0, 0, 0, &mtcio } }; + +#define mtd_dib mt_dib[0] +#define mtc_dib mt_dib[1] + +UNIT mtd_unit = { UDATA (NULL, 0, 0) }; REG mtd_reg[] = { - { FLDATA (CMD, infotab[inMTD].cmd, 0), REG_HRO }, - { FLDATA (CTL, infotab[inMTD].ctl, 0), REG_HRO }, - { FLDATA (FLG, infotab[inMTD].flg, 0) }, - { FLDATA (FBF, infotab[inMTD].fbf, 0), REG_HRO }, + { FLDATA (CMD, mtd_dib.cmd, 0), REG_HRO }, + { FLDATA (CTL, mtd_dib.ctl, 0), REG_HRO }, + { FLDATA (FLG, mtd_dib.flg, 0) }, + { FLDATA (FBF, mtd_dib.fbf, 0), REG_HRO }, + { BRDATA (DBUF, mtxb, 8, 8, DBSIZE) }, { DRDATA (BPTR, mt_ptr, DB_V_SIZE + 1) }, { DRDATA (BMAX, mt_max, DB_V_SIZE + 1) }, - { ORDATA (DEVNO, infotab[inMTD].devno, 6), REG_RO }, + { ORDATA (DEVNO, mtd_dib.devno, 6), REG_HRO }, + { FLDATA (*DEVENB, mtd_dib.enb, 0), REG_HRO }, { NULL } }; +MTAB mtd_mod[] = { + { MTAB_XTD | MTAB_VDV, 1, "DEVNO", "DEVNO", + &hp_setdev, &hp_showdev, &mtd_dib }, + { 0 } }; + DEVICE mtd_dev = { - "MTD", &mtd_unit, mtd_reg, NULL, + "MTD", &mtd_unit, mtd_reg, mtd_mod, 1, 10, 16, 1, 8, 8, - &mtd_ex, &mtd_dep, &mtc_reset, + NULL, NULL, &mtc_reset, NULL, NULL, NULL }; /* MTC data structures @@ -144,25 +159,30 @@ REG mtc_reg[] = { { ORDATA (FNC, mtc_fnc, 8) }, { ORDATA (STA, mtc_sta, 9) }, { ORDATA (BUF, mtc_unit.buf, 8) }, - { FLDATA (CMD, infotab[inMTC].cmd, 0), REG_HRO }, - { FLDATA (CTL, infotab[inMTC].ctl, 0) }, - { FLDATA (FLG, infotab[inMTC].flg, 0) }, - { FLDATA (FBF, infotab[inMTC].fbf, 0) }, + { FLDATA (CMD, mtc_dib.cmd, 0), REG_HRO }, + { FLDATA (CTL, mtc_dib.ctl, 0) }, + { FLDATA (FLG, mtc_dib.flg, 0) }, + { FLDATA (FBF, mtc_dib.fbf, 0) }, { FLDATA (DTF, mtc_dtf, 0) }, { FLDATA (FSVC, mtc_1st, 0) }, - { DRDATA (POS, mtc_unit.pos, 31), PV_LEFT }, + { DRDATA (POS, mtc_unit.pos, 32), PV_LEFT }, { DRDATA (CTIME, mtc_ctime, 24), REG_NZ + PV_LEFT }, { DRDATA (XTIME, mtc_xtime, 24), REG_NZ + PV_LEFT }, { FLDATA (STOP_IOE, mtc_stopioe, 0) }, { FLDATA (WLK, mtc_unit.flags, UNIT_V_WLK), REG_HRO }, - { ORDATA (CDEVNO, infotab[inMTC].devno, 6), REG_RO }, + { ORDATA (DEVNO, mtc_dib.devno, 6), REG_HRO }, + { FLDATA (*DEVENB, mtc_dib.enb, 0), REG_HRO }, { NULL } }; MTAB mtc_mod[] = { - { UNIT_WLK, 0, "write enabled", "ENABLED", &mtc_vlock }, + { UNIT_WLK, 0, "write enabled", "WRITEENABLED", &mtc_vlock }, { UNIT_WLK, UNIT_WLK, "write locked", "LOCKED", &mtc_vlock }, - { MTAB_XTD | MTAB_VDV, inMTD, "DEVNO", "DEVNO", - &hp_setdev2, &hp_showdev2, NULL }, + { MTAB_XTD | MTAB_VDV, 1, NULL, "ENABLED", + &set_enb, NULL, &mtd_dib }, + { MTAB_XTD | MTAB_VDV, 1, NULL, "DISABLED", + &set_dis, NULL, &mtd_dib }, + { MTAB_XTD | MTAB_VDV, 1, "DEVNO", "DEVNO", + &hp_setdev, &hp_showdev, &mtd_dib }, { 0 } }; DEVICE mtc_dev = { @@ -183,10 +203,10 @@ case ioFLG: /* flag clear/set */ if ((IR & HC) == 0) { setFLG (devd); } /* STF */ break; case ioSFC: /* skip flag clear */ - if (FLG (devd) == 0) PC = (PC + 1) & AMASK; + if (FLG (devd) == 0) PC = (PC + 1) & VAMASK; return dat; case ioSFS: /* skip flag set */ - if (FLG (devd) != 0) PC = (PC + 1) & AMASK; + if (FLG (devd) != 0) PC = (PC + 1) & VAMASK; return dat; case ioOTX: /* output */ mtc_unit.buf = dat & 0377; /* store data */ @@ -217,10 +237,10 @@ case ioFLG: /* flag clear/set */ if ((IR & HC) == 0) { setFLG (devc); } /* STF */ break; case ioSFC: /* skip flag clear */ - if (FLG (devc) == 0) PC = (PC + 1) & AMASK; + if (FLG (devc) == 0) PC = (PC + 1) & VAMASK; return dat; case ioSFS: /* skip flag set */ - if (FLG (devc) != 0) PC = (PC + 1) & AMASK; + if (FLG (devc) != 0) PC = (PC + 1) & VAMASK; return dat; case ioOTX: /* output */ dat = dat & 0377; @@ -287,15 +307,14 @@ static t_mtrlnt bceof = { 0 }; if ((mtc_unit.flags & UNIT_ATT) == 0) { /* offline? */ mtc_sta = STA_LOCAL | STA_BUSY | STA_REJ; return IORETURN (mtc_stopioe, SCPE_UNATT); } -devc = infotab[inMTC].devno; /* get device nos */ -devd = infotab[inMTD].devno; +devc = mtc_dib.devno; /* get device nos */ +devd = mtd_dib.devno; err = 0; /* assume no errors */ switch (mtc_fnc & 0377) { /* case on function */ case FNC_REW: /* rewind */ mtc_unit.pos = 0; /* BOT */ - setFLG (devc); /* set cch flg */ - mtc_sta = (mtc_sta | STA_BOT) & ~STA_BUSY; /* update status */ + mtc_sta = mtc_sta | STA_BOT; /* update status */ break; case FNC_RWS: /* rewind and offline */ mtc_unit.pos = 0; /* BOT */ @@ -308,15 +327,11 @@ case FNC_WFM: /* write file mark */ mtc_unit.pos = mtc_unit.pos + sizeof (t_mtrlnt); /* update tape pos */ mtc_sta = mtc_sta | STA_EOF; /* set EOF status */ case FNC_GAP: /* erase gap */ - setFLG (devc); /* set cch flg */ - mtc_sta = mtc_sta & ~STA_BUSY; /* update status */ break; /* Unit service, continued */ case FNC_FSR: /* space forward */ - setFLG (devc); /* set cch flg */ - mtc_sta = mtc_sta & ~STA_BUSY; /* update status */ fseek (mtc_unit.fileref, mtc_unit.pos, SEEK_SET); fxread (&mt_max, sizeof (t_mtrlnt), 1, mtc_unit.fileref); if ((err = ferror (mtc_unit.fileref)) || /* error or eof? */ @@ -328,8 +343,6 @@ case FNC_FSR: /* space forward */ (2 * sizeof (t_mtrlnt)); /* update position */ break; case FNC_BSR: /* space reverse */ - setFLG (devc); /* set cch flg */ - mtc_sta = mtc_sta & ~STA_BUSY; /* update status */ if (mtc_unit.pos == 0) { /* at BOT? */ mtc_sta = mtc_sta | STA_BOT; /* update status */ break; } @@ -365,45 +378,44 @@ case FNC_RC: /* read */ mt_max = MTRL (mt_max); /* ignore errors */ mtc_unit.pos = mtc_unit.pos + ((mt_max + 1) & ~1) + (2 * sizeof (t_mtrlnt)); /* update position */ - if ((mt_max > DBSIZE) || (mt_max < 12)) { + if (mt_max > DBSIZE) return SCPE_MTRLNT;/* record too long? */ + if (mt_max < 12) { /* record too short? */ setFLG (devc); /* set cch flg */ mtc_sta = (mtc_sta | STA_PAR) & ~STA_BUSY; break; } - i = fxread (mt_buf, sizeof (int8), mt_max, mtc_unit.fileref); - for ( ; i < mt_max; i++) mt_buf[i] = 0; /* fill with 0's */ + i = fxread (mtxb, sizeof (int8), mt_max, mtc_unit.fileref); + for ( ; i < mt_max; i++) mtxb[i] = 0; /* fill with 0's */ err = ferror (mtc_unit.fileref); } if (mt_ptr < mt_max) { /* more chars? */ if (FLG (devd)) mtc_sta = mtc_sta | STA_TIM; - mtc_unit.buf = mt_buf[mt_ptr++]; /* fetch next */ + mtc_unit.buf = mtxb[mt_ptr++]; /* fetch next */ setFLG (devd); /* set dch flg */ - sim_activate (uptr, mtc_xtime); } /* re-activate */ - else { setFLG (devc); /* set cch flg */ - mtc_sta = mtc_sta & ~STA_BUSY; } /* update status */ + sim_activate (uptr, mtc_xtime); /* re-activate */ + return SCPE_OK; } break; case FNC_WC: /* write */ + if (mtc_1st) mtc_1st = 0; /* no xfr on first */ + else { if (mt_ptr < DBSIZE) /* room in buffer? */ + mtxb[mt_ptr++] = mtc_unit.buf; + else mtc_sta = mtc_sta | STA_PAR; } if (mtc_dtf) { /* xfer flop set? */ - if (!mtc_1st) { /* not first? */ - if (mt_ptr < DBSIZE) /* room in buffer? */ - mt_buf[mt_ptr++] = mtc_unit.buf; - else mtc_sta = mtc_sta | STA_PAR; } - mtc_1st = 0; /* clr 1st flop */ setFLG (devd); /* set dch flag */ sim_activate (uptr, mtc_xtime); /* re-activate */ - break; } + return SCPE_OK; } if (mt_ptr) { /* write buffer */ fseek (mtc_unit.fileref, mtc_unit.pos, SEEK_SET); fxwrite (&mt_ptr, sizeof (t_mtrlnt), 1, mtc_unit.fileref); - fxwrite (mt_buf, sizeof (int8), mt_ptr, mtc_unit.fileref); + fxwrite (mtxb, sizeof (int8), mt_ptr, mtc_unit.fileref); fxwrite (&mt_ptr, sizeof (t_mtrlnt), 1, mtc_unit.fileref); err = ferror (mtc_unit.fileref); mtc_unit.pos = mtc_unit.pos + ((mt_ptr + 1) & ~1) + (2 * sizeof (t_mtrlnt)); } - setFLG (devc); /* set cch flg */ - mtc_sta = mtc_sta & ~STA_BUSY; /* update status */ break; } /* Unit service, continued */ +setFLG (devc); /* set cch flg */ +mtc_sta = mtc_sta & ~STA_BUSY; /* not busy */ if (err != 0) { /* I/O error */ perror ("MT I/O error"); clearerr (mtc_unit.fileref); @@ -416,10 +428,10 @@ return SCPE_OK; t_stat mtc_reset (DEVICE *dptr) { mtc_fnc = 0; -infotab[inMTC].cmd = infotab[inMTD].cmd = 0; /* clear cmd */ -infotab[inMTC].ctl = infotab[inMTD].ctl = 0; /* clear ctl */ -infotab[inMTC].flg = infotab[inMTD].flg = 0; /* clear flg */ -infotab[inMTC].fbf = infotab[inMTD].fbf = 0; /* clear fbf */ +mtc_dib.cmd = mtd_dib.cmd = 0; /* clear cmd */ +mtc_dib.ctl = mtd_dib.ctl = 0; /* clear ctl */ +mtc_dib.flg = mtd_dib.flg = 0; /* clear flg */ +mtc_dib.fbf = mtd_dib.fbf = 0; /* clear fbf */ sim_cancel (&mtc_unit); /* cancel activity */ if (mtc_unit.flags & UNIT_ATT) mtc_sta = ((mtc_unit.pos)? 0: STA_BOT) | ((mtc_unit.flags & UNIT_WPRT)? STA_WLK: 0); @@ -454,21 +466,3 @@ t_stat mtc_vlock (UNIT *uptr, int32 val, char *cptr, void *desc) if (val && (uptr -> flags & UNIT_ATT)) return SCPE_ARG; return SCPE_OK; } - -/* Buffer examine */ - -t_stat mtd_ex (t_value *vptr, t_addr addr, UNIT *uptr, int32 sw) -{ -if (addr >= DBSIZE) return SCPE_NXM; -if (vptr != NULL) *vptr = mt_buf[addr] & 0377; -return SCPE_OK; -} - -/* Buffer deposit */ - -t_stat mtd_dep (t_value val, t_addr addr, UNIT *uptr, int32 sw) -{ -if (addr >= DBSIZE) return SCPE_NXM; -mt_buf[addr] = val & 0377; -return SCPE_OK; -} diff --git a/HP2100/hp2100_mux.c b/HP2100/hp2100_mux.c new file mode 100644 index 00000000..3b1fc4d1 --- /dev/null +++ b/HP2100/hp2100_mux.c @@ -0,0 +1,715 @@ +/* hp2100_mux.c: HP 2100 12920A terminal multiplexor simulator + + Copyright (c) 2002, Robert M Supnik + + Permission is hereby granted, free of charge, to any person obtaining a + copy of this software and associated documentation files (the "Software"), + to deal in the Software without restriction, including without limitation + the rights to use, copy, modify, merge, publish, distribute, sublicense, + and/or sell copies of the Software, and to permit persons to whom the + Software is furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + ROBERT M SUPNIK BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + Except as contained in this notice, the name of Robert M Supnik shall not + be used in advertising or otherwise to promote the sale, use or other dealings + in this Software without prior written authorization from Robert M Supnik. + + mux,muxl,muxc 12920A terminal multiplexor + + The 12920A consists of three separate devices + + mux scanner (upper data card) + muxl lines (lower data card) + muxm modem control (control card) + + The lower data card has no CMD flop; the control card has no CMD flop. + The upper data card has none of the usual flops. +*/ + +#include "hp2100_defs.h" +#include "sim_sock.h" +#include "sim_tmxr.h" +#include + +#define MUX_LINES 16 /* user lines */ +#define MUX_ILINES 5 /* diag rcv only */ +#define UNIT_V_UC (UNIT_V_UF + 0) /* UC only */ +#define UNIT_V_MDM (UNIT_V_UF + 1) /* modem control */ +#define UNIT_UC (1 << UNIT_V_UC) +#define UNIT_MDM (1 << UNIT_V_MDM) +#define MUXU_INIT_POLL 8000 +#define MUXL_WAIT 500 + +/* Channel number (OTA upper, LIA lower or upper) */ + +#define MUX_V_CHAN 10 /* channel num */ +#define MUX_M_CHAN 037 +#define MUX_CHAN(x) (((x) >> MUX_V_CHAN) & MUX_M_CHAN) + +/* OTA, lower = parameters or data */ + +#define OTL_P 0100000 /* parameter */ +#define OTL_TX 0040000 /* transmit */ +#define OTL_ENB 0020000 /* enable */ +#define OTL_TPAR 0010000 /* xmt parity */ +#define OTL_ECHO 0010000 /* rcv echo */ +#define OTL_DIAG 0004000 /* diagnose */ +#define OTL_SYNC 0004000 /* sync */ +#define OTL_V_LNT 8 /* char length */ +#define OTL_M_LNT 07 +#define OTL_LNT(x) (((x) >> OTL_V_LNT) & OTL_M_LNT) +#define OTL_V_BAUD 0 /* baud rate */ +#define OTL_M_BAUD 0377 +#define OTL_BAUD(x) (((x) >> OTL_V_BAUD) & OTL_M_BAUD) +#define OTL_CHAR 01777 /* char mask */ + +/* LIA, lower = received data */ + +#define LIL_PAR 0100000 /* parity */ +#define PUT_DCH(x) (((x) & MUX_M_CHAN) << MUX_V_CHAN) +#define LIL_CHAR 01777 /* character */ + +/* LIA, upper = status */ + +#define LIU_SEEK 0100000 /* seeking NI */ +#define LIU_DG 0000010 /* diagnose */ +#define LIU_BRK 0000004 /* break NI */ +#define LIU_LOST 0000002 /* char lost */ +#define LIU_TR 0000001 /* trans/rcv */ + +/* OTA, control */ + +#define OTC_SCAN 0100000 /* scan */ +#define OTC_UPD 0040000 /* update */ +#define OTC_V_CHAN 10 /* channel */ +#define OTC_M_CHAN 017 +#define OTC_CHAN(x) (((x) >> OTC_V_CHAN) & OTC_M_CHAN) +#define OTC_EC2 0000200 /* enable Cn upd */ +#define OTC_EC1 0000100 +#define OTC_C2 0000040 /* Cn flops */ +#define OTC_C1 0000020 +#define OTC_ES2 0000010 /* enb comparison */ +#define OTC_ES1 0000004 +#define OTC_V_ES 2 +#define OTC_SS2 0000002 /* SSn flops */ +#define OTC_SS1 0000001 +#define OTC_RW (OTC_ES2|OTC_ES1|OTC_SS2|OTC_SS1) +#define RTS OCT_C2 /* C2 = rts */ +#define DTR OTC_C1 /* C1 = dtr */ + +/* LIA, control */ + +#define LIC_MBO 0140000 /* always set */ +#define LIC_V_CHAN 10 /* channel */ +#define LIC_M_CHAN 017 +#define PUT_CCH(x) (((x) & OTC_M_CHAN) << OTC_V_CHAN) +#define LIC_I2 0001000 /* change flags */ +#define LIC_I1 0000400 +#define LIC_S2 0000002 /* Sn flops */ +#define LIC_S1 0000001 +#define LIC_V_I 8 /* S1 to I1 */ +#define CDET LIC_S2 /* S2 = cdet */ +#define DSR LIC_S1 /* S1 = dsr */ + +#define LIC_TSTI(ch) (((muxc_lia[ch] ^ muxc_ota[ch]) & \ + ((muxc_ota[ch] & (OTC_ES2|OTC_ES1)) >> OTC_V_ES)) \ + << LIC_V_I) + +extern int32 PC; +extern int32 dev_cmd[2], dev_ctl[2], dev_flg[2], dev_fbf[2]; + +uint16 mux_sta[MUX_LINES]; /* line status */ +uint16 mux_rpar[MUX_LINES + MUX_ILINES]; /* rcv param */ +uint16 mux_xpar[MUX_LINES]; /* xmt param */ +uint8 mux_rbuf[MUX_LINES + MUX_ILINES]; /* rcv buf */ +uint8 mux_xbuf[MUX_LINES]; /* xmt buf */ +uint8 mux_rchp[MUX_LINES + MUX_ILINES]; /* rcv chr pend */ +uint8 mux_xdon[MUX_LINES]; /* xmt done */ +uint8 muxc_ota[MUX_LINES]; /* ctrl: Cn,ESn,SSn */ +uint8 muxc_lia[MUX_LINES]; /* ctrl: Sn */ +uint32 mux_tps = 100; /* polls/second */ +uint32 muxl_ibuf = 0; /* low in: rcv data */ +uint32 muxl_obuf = 0; /* low out: param */ +uint32 muxu_ibuf = 0; /* upr in: status */ +uint32 muxu_obuf = 0; /* upr out: chan */ +uint32 muxc_chan = 0; /* ctrl chan */ +uint32 muxc_scan = 0; /* ctrl scan */ + +TMLN mux_ldsc[MUX_LINES] = { 0 }; /* line descriptors */ +TMXR mux_desc = { MUX_LINES, 0, NULL }; /* mux descriptor */ + +int32 muxlio (int32 inst, int32 IR, int32 dat); +int32 muxuio (int32 inst, int32 IR, int32 dat); +int32 muxcio (int32 inst, int32 IR, int32 dat); +t_stat muxi_svc (UNIT *uptr); +t_stat muxo_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_summ (FILE *st, UNIT *uptr, int32 val, void *desc); +t_stat mux_show (FILE *st, UNIT *uptr, int32 val, void *desc); +void mux_data_int (void); +void mux_ctrl_int (void); +void mux_diag (int32 c); +t_stat mux_enb (UNIT *uptr, int32 num, char *cptr, void *desc); +t_stat mux_dis (UNIT *uptr, int32 num, char *cptr, void *desc); + +static uint8 odd_par[256] = { + 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, /* 000-017 */ + 0, 1, 1, 0, 1, 0, 1, 0, 1, 0, 0, 1, 0, 1, 1, 0, /* 020-037 */ + 0, 1, 1, 0, 1, 0, 1, 0, 1, 0, 0, 1, 0, 1, 1, 0, /* 040-067 */ + 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, /* 060-077 */ + 0, 1, 1, 0, 1, 0, 1, 0, 1, 0, 0, 1, 0, 1, 1, 0, /* 100-117 */ + 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, /* 120-137 */ + 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, /* 140-157 */ + 0, 1, 1, 0, 1, 0, 1, 0, 1, 0, 0, 1, 0, 1, 1, 0, /* 160-177 */ + 0, 1, 1, 0, 1, 0, 1, 0, 1, 0, 0, 1, 0, 1, 1, 0, /* 200-217 */ + 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, /* 220-237 */ + 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, /* 240-257 */ + 0, 1, 1, 0, 1, 0, 1, 0, 1, 0, 0, 1, 0, 1, 1, 0, /* 260-277 */ + 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, /* 300-317 */ + 0, 1, 1, 0, 1, 0, 1, 0, 1, 0, 0, 1, 0, 1, 1, 0, /* 320-337 */ + 0, 1, 1, 0, 1, 0, 1, 0, 1, 0, 0, 1, 0, 1, 1, 0, /* 340-367 */ + 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1 }; /* 360-377 */ + +#define RCV_PAR(x) (odd_par[(x) & 0377]? LIL_PAR: 0) + + DIB mux_dib[] = { + { MUXL, 1, 0, 0, 0, 0, &muxlio }, + { MUXU, 1, 0, 0, 0, 0, &muxuio } }; + +#define muxl_dib mux_dib[0] +#define muxu_dib mux_dib[1] + +/* MUX data structures + + muxu_dev MUX device descriptor + muxu_unit MUX unit descriptor + muxu_reg MUX register list + muxu_mod MUX modifiers list +*/ + +UNIT muxu_unit = { UDATA (&muxi_svc, UNIT_ATTABLE, 0), MUXU_INIT_POLL }; + +REG muxu_reg[] = { + { ORDATA (IBUF, muxu_ibuf, 16) }, + { ORDATA (OBUF, muxu_obuf, 16) }, + { FLDATA (CMD, muxu_dib.cmd, 0), REG_HRO }, + { FLDATA (CTL, muxu_dib.ctl, 0), REG_HRO }, + { FLDATA (FLG, muxu_dib.flg, 0), REG_HRO }, + { FLDATA (FBF, muxu_dib.fbf, 0), REG_HRO }, + { ORDATA (DEVNO, muxu_dib.devno, 6), REG_HRO }, + { FLDATA (*DEVENB, muxu_dib.enb, 0), REG_HRO }, + { NULL } }; + +MTAB muxu_mod[] = { + { MTAB_XTD | MTAB_VDV, 1, NULL, "DISCONNECT", + &tmxr_dscln, NULL, &mux_desc }, + { UNIT_ATT, UNIT_ATT, "connections", NULL, NULL, &mux_summ }, + { MTAB_XTD | MTAB_VDV | MTAB_NMO, 1, "CONNECTIONS", NULL, + NULL, &mux_show, NULL }, + { MTAB_XTD | MTAB_VDV | MTAB_NMO, 0, "STATISTICS", NULL, + NULL, &mux_show, NULL }, + { MTAB_XTD | MTAB_VDV, 0, NULL, "ENABLED", + &mux_enb, NULL, NULL }, + { MTAB_XTD | MTAB_VDV, 0, NULL, "DISABLED", + &mux_dis, NULL, NULL }, + { MTAB_XTD|MTAB_VDV, 1, "DEVNO", "DEVNO", + &hp_setdev, &hp_showdev, &mux_dib }, + { 0 } }; + +DEVICE muxu_dev = { + "MUX", &muxu_unit, muxu_reg, muxu_mod, + 1, 10, 31, 1, 8, 8, + &tmxr_ex, &tmxr_dep, &mux_reset, + NULL, &mux_attach, &mux_detach }; + +/* 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, UNIT_UC, 0), MUXL_WAIT }, + { UDATA (&muxo_svc, UNIT_UC, 0), MUXL_WAIT }, + { UDATA (&muxo_svc, UNIT_UC, 0), MUXL_WAIT }, + { UDATA (&muxo_svc, UNIT_UC, 0), MUXL_WAIT }, + { UDATA (&muxo_svc, UNIT_UC, 0), MUXL_WAIT }, + { UDATA (&muxo_svc, UNIT_UC, 0), MUXL_WAIT }, + { UDATA (&muxo_svc, UNIT_UC, 0), MUXL_WAIT }, + { UDATA (&muxo_svc, UNIT_UC, 0), MUXL_WAIT }, + { UDATA (&muxo_svc, UNIT_UC, 0), MUXL_WAIT }, + { UDATA (&muxo_svc, UNIT_UC, 0), MUXL_WAIT }, + { UDATA (&muxo_svc, UNIT_UC, 0), MUXL_WAIT }, + { UDATA (&muxo_svc, UNIT_UC, 0), MUXL_WAIT }, + { UDATA (&muxo_svc, UNIT_UC, 0), MUXL_WAIT }, + { UDATA (&muxo_svc, UNIT_UC, 0), MUXL_WAIT }, + { UDATA (&muxo_svc, UNIT_UC, 0), MUXL_WAIT }, + { UDATA (&muxo_svc, UNIT_UC, 0), MUXL_WAIT }, + { UDATA (&muxo_svc, UNIT_UC, 0), MUXL_WAIT } }; + +MTAB muxl_mod[] = { + { UNIT_UC, 0, "lower case", "LC", NULL }, + { UNIT_UC, UNIT_UC, "upper case", "UC", NULL }, + { UNIT_MDM, 0, "no dataset", "NODATASET", NULL }, + { UNIT_MDM, UNIT_MDM, "dataset", "DATASET", NULL }, + { MTAB_XTD | MTAB_VDV, 0, NULL, "ENABLED", + &mux_enb, NULL, NULL }, + { MTAB_XTD | MTAB_VDV, 0, NULL, "DISABLED", + &mux_dis, NULL, NULL }, + { MTAB_XTD|MTAB_VDV, 1, "DEVNO", "DEVNO", + &hp_setdev, &hp_showdev, &mux_dib }, + { 0 } }; + +REG muxl_reg[] = { + { FLDATA (CMD, muxl_dib.cmd, 0), REG_HRO }, + { FLDATA (CTL, muxl_dib.ctl, 0) }, + { FLDATA (FLG, muxl_dib.flg, 0) }, + { FLDATA (FBF, muxl_dib.fbf, 0) }, + { BRDATA (STA, mux_sta, 8, 16, MUX_LINES) }, + { BRDATA (RPAR, mux_rpar, 8, 16, MUX_LINES + MUX_ILINES) }, + { BRDATA (XPAR, mux_xpar, 8, 16, MUX_LINES) }, + { BRDATA (RBUF, mux_rbuf, 8, 8, MUX_LINES + MUX_ILINES) }, + { BRDATA (XBUF, mux_xbuf, 8, 8, MUX_LINES) }, + { BRDATA (RCHP, mux_rchp, 8, 1, MUX_LINES + MUX_ILINES) }, + { BRDATA (XDON, mux_xdon, 8, 1, MUX_LINES) }, + { URDATA (TIME, muxl_unit[0].wait, 10, 24, 0, + MUX_LINES, REG_NZ + PV_LEFT) }, + { URDATA (FLGS, muxl_unit[0].flags, 8, 2, UNIT_V_UF, + MUX_LINES, REG_HRO) }, + { ORDATA (DEVNO, muxl_dib.devno, 6), REG_HRO }, + { FLDATA (*DEVENB, muxl_dib.enb, 0), REG_HRO }, + { NULL } }; + +DEVICE muxl_dev = { + "MUXL", muxl_unit, muxl_reg, muxl_mod, + MUX_LINES, 10, 31, 1, 8, 8, + NULL, NULL, &mux_reset, + NULL, NULL, NULL }; + +/* MUXM data structures + + muxc_dev MUXM device descriptor + muxc_unit MUXM unit descriptor + muxc_reg MUXM register list + muxc_mod MUXM modifiers list +*/ + +DIB muxc_dib = { MUXC, 1, 0, 0, 0, 0, &muxcio }; + +UNIT muxc_unit = { UDATA (NULL, 0, 0) }; + +REG muxc_reg[] = { + { FLDATA (CMD, muxc_dib.cmd, 0), REG_HRO }, + { FLDATA (CTL, muxc_dib.ctl, 0) }, + { FLDATA (FLG, muxc_dib.flg, 0) }, + { FLDATA (FBF, muxc_dib.fbf, 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 }, + { FLDATA (*DEVENB, muxc_dib.enb, 0), REG_HRO }, + { NULL } }; + +MTAB muxc_mod[] = { + { MTAB_XTD | MTAB_VDV, 0, NULL, "ENABLED", + &mux_enb, NULL, NULL }, + { MTAB_XTD | MTAB_VDV, 0, NULL, "DISABLED", + &mux_dis, NULL, NULL }, + { MTAB_XTD|MTAB_VDV, 0, "DEVNO", "DEVNO", + &hp_setdev, &hp_showdev, &muxc_dib }, + { 0 } }; + +DEVICE muxc_dev = { + "MUXM", &muxc_unit, muxc_reg, muxc_mod, + 1, 10, 31, 1, 8, 8, + NULL, NULL, &mux_reset, + NULL, NULL, NULL }; + +/* IOT routines: data cards */ + +int32 muxlio (int32 inst, int32 IR, int32 dat) +{ +int32 dev, ln; + +dev = IR & DEVMASK; /* get device no */ +switch (inst) { /* case on opcode */ +case ioFLG: /* flag clear/set */ + if ((IR & HC) == 0) { setFLG (dev); } /* STF */ + break; +case ioSFC: /* skip flag clear */ + if (FLG (dev) == 0) PC = (PC + 1) & VAMASK; + return dat; +case ioSFS: /* skip flag set */ + if (FLG (dev) != 0) PC = (PC + 1) & VAMASK; + return dat; +case ioOTX: /* output */ + muxl_obuf = dat; /* store data */ + break; +case ioMIX: /* merge */ + dat = dat | muxl_ibuf; + break; +case ioLIX: /* load */ + dat = muxl_ibuf; + break; +case ioCTL: /* control clear/set */ + if (IR & AB) { clrCTL (dev); } /* CLC */ + else { /* STC */ + setCTL (dev); /* set ctl */ + ln = MUX_CHAN (muxu_obuf); /* get chan # */ + if (muxl_obuf & OTL_P) { /* parameter set? */ + if (muxl_obuf & OTL_TX) { /* transmit? */ + if (ln < MUX_LINES) /* to valid line? */ + mux_xpar[ln] = muxl_obuf; } + else if (ln < (MUX_LINES + MUX_ILINES)) /* rcv, valid line? */ + mux_rpar[ln] = muxl_obuf; } + else if ((muxl_obuf & OTL_TX) && /* xmit data? */ + (ln < MUX_LINES)) { /* to valid line? */ + if (sim_is_active (&muxl_unit[ln])) /* still working? */ + mux_sta[ln] = mux_sta[ln] | LIU_LOST; + else sim_activate (&muxl_unit[ln], muxl_unit[ln].wait); + mux_xbuf[ln] = muxl_obuf & OTL_CHAR; } /* load buffer */ + } /* end STC */ + break; +default: + break; } +if (IR & HC) { /* H/C option */ + clrFLG (dev); /* clear flag */ + mux_data_int (); } /* look for new int */ +return dat; +} + +int32 muxuio (int32 inst, int32 IR, int32 dat) +{ +switch (inst) { /* case on opcode */ +case ioOTX: /* output */ + muxu_obuf = dat; /* store data */ + break; +case ioMIX: /* merge */ + dat = dat | muxu_ibuf; + break; +case ioLIX: /* load */ + dat = muxu_ibuf; + break; +default: + break; } +return dat; +} + +/* IOT routine: control card */ + +int32 muxcio (int32 inst, int32 IR, int32 dat) +{ +int32 dev, ln, t, old; + +dev = IR & DEVMASK; /* get device no */ +switch (inst) { /* case on opcode */ +case ioFLG: /* flag clear/set */ + if ((IR & HC) == 0) { setFLG (dev); } /* STF */ + break; +case ioSFC: /* skip flag clear */ + if (FLG (dev) == 0) PC = (PC + 1) & VAMASK; + return dat; +case ioSFS: /* skip flag set */ + if (FLG (dev) != 0) PC = (PC + 1) & VAMASK; + return dat; +case ioOTX: /* output */ + if (dat & OTC_SCAN) muxc_scan = 1; /* set scan flag */ + else muxc_scan = 0; + if (dat & OTC_UPD) { /* update? */ + ln = OTC_CHAN (dat); /* get channel */ + old = muxc_ota[ln]; /* save prior val */ + muxc_ota[ln] = (muxc_ota[ln] & ~OTC_RW) | /* save ESn,SSn */ + (dat & OTC_RW); + if (dat & OTC_EC2) muxc_ota[ln] = /* if EC2, upd C2 */ + (muxc_ota[ln] & ~OTC_C2) | (dat & OTC_C2); + if (dat & OTC_EC1) muxc_ota[ln] = /* if EC1, upd C1 */ + (muxc_ota[ln] & ~OTC_C1) | (dat & OTC_C1); + if ((muxl_unit[ln].flags & UNIT_MDM) && /* modem ctrl? */ + (old & DTR) && !(muxc_ota[ln] & DTR)) { /* DTR drop? */ + tmxr_msg (mux_ldsc[ln].conn, "\r\nLine hangup\r\n"); + tmxr_reset_ln (&mux_ldsc[ln]); /* reset line */ + muxc_lia[ln] = 0; } /* dataset off */ + } /* end update */ + break; +case ioLIX: /* load */ + dat = 0; +case ioMIX: /* merge */ + t = 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 */ + dat = dat | t; /* return status */ + muxc_chan = (muxc_chan + 1) & LIC_M_CHAN; /* incr channel */ + break; +case ioCTL: /* ctrl clear/set */ + if (IR & AB) { clrCTL (dev); } /* CLC */ + else { setCTL (dev); } /* STC */ + break; +default: + break; } +if (IR & HC) { /* H/C option */ + clrFLG (dev); /* clear flag */ + mux_ctrl_int (); } /* look for new int */ +return dat; +} + +/* Unit service - receive side + + Poll for new connections + Poll all active lines for input +*/ + +t_stat muxi_svc (UNIT *uptr) +{ +int32 ln, c, t; + +if ((uptr -> flags & UNIT_ATT) == 0) return SCPE_OK; /* attached? */ +t = sim_rtcn_calb (mux_tps, TMR_MUX); /* calibrate */ +sim_activate (uptr, t); /* continue poll */ +ln = tmxr_poll_conn (&mux_desc, uptr); /* look for connect */ +if (ln >= 0) { /* got one? */ + if ((muxl_unit[ln].flags & UNIT_MDM) && /* modem ctrl? */ + (muxc_ota[ln] & DTR)) /* DTR? */ + muxc_lia[ln] = muxc_lia[ln] | CDET; /* set cdet */ + muxc_lia[ln] = muxc_lia[ln] | DSR; /* set dsr */ + mux_ldsc[ln].rcve = 1; } /* rcv enabled */ +tmxr_poll_rx (&mux_desc); /* poll for input */ +for (ln = 0; ln < MUX_LINES; ln++) { /* loop thru lines */ + if (mux_ldsc[ln].conn) { /* connected? */ + if (c = tmxr_getc_ln (&mux_ldsc[ln])) { /* get char */ + if (mux_rchp[ln]) mux_sta[ln] = mux_sta[ln] | LIU_LOST; + if ((muxl_unit[ln].flags & UNIT_UC) && /* cvt to UC? */ + islower (c & 0177)) c = toupper (c); + if (mux_rpar[ln] & OTL_ECHO) { /* echo? */ + TMLN *lp = &mux_ldsc[ln]; /* get line */ + tmxr_putc_ln (lp, c); /* output char */ + tmxr_poll_tx (&mux_desc); } /* poll xmt */ + if (mux_rpar[ln] & OTL_DIAG) mux_diag (c); /* rcv diag? */ + mux_rbuf[ln] = c; /* save char */ + mux_rchp[ln] = 1; } } /* char pending */ + else muxc_lia[ln] = 0; } /* disconnected */ /* end for */ +if (!FLG (muxl_dib.devno)) mux_data_int (); /* scan for data int */ +if (!FLG (muxc_dib.devno)) mux_ctrl_int (); /* scan modem */ +return SCPE_OK; +} + +/* Unit service - transmit side */ + +t_stat muxo_svc (UNIT *uptr) +{ +int32 c, ln = uptr - muxl_unit; /* line # */ + +if (mux_ldsc[ln].conn) { /* connected? */ + if (mux_ldsc[ln].xmte) { /* xmt enabled? */ + if ((mux_xbuf[ln] & OTL_SYNC) == 0) { /* start bit 0? */ + TMLN *lp = &mux_ldsc[ln]; /* get line */ + c = mux_xbuf[ln] & 0177; /* get char */ + if ((muxl_unit[ln].flags & UNIT_UC) && islower (c)) + c = toupper (c); /* cvt to UC? */ + if (mux_xpar[ln] & OTL_DIAG) /* xmt diag? */ + mux_diag (mux_xbuf[ln]); /* before munge */ + mux_xdon[ln] = 1; /* set done */ + tmxr_putc_ln (lp, c); /* output char */ + tmxr_poll_tx (&mux_desc); } } /* poll xmt */ + else { /* buf full */ + tmxr_poll_tx (&mux_desc); /* poll xmt */ + sim_activate (uptr, muxl_unit[ln].wait); /* wait */ + return SCPE_OK; } } +if (!FLG (muxl_dib.devno)) mux_data_int (); /* scan for int */ +return SCPE_OK; +} + +/* Look for data interrupt */ + +void mux_data_int (void) +{ +int32 i; + +for (i = 0; i < MUX_LINES; i++) { /* rcv lines */ + if ((mux_rpar[i] & OTL_ENB) && mux_rchp[i]) { /* enabled, char? */ + muxl_ibuf = PUT_CCH (i) | mux_rbuf[i] | /* lo buf = char */ + RCV_PAR (mux_rbuf[i]); + muxu_ibuf = PUT_CCH (i) | mux_sta[i]; /* hi buf = stat */ + mux_rchp[i] = 0; /* clr char, stat */ + mux_sta[i] = 0; + setFLG (muxl_dib.devno); /* interrupt */ + return; } } +for (i = 0; i < MUX_LINES; i++) { /* xmt lines */ + if ((mux_xpar[i] & OTL_ENB) && mux_xdon[i]) { /* enabled, done? */ + muxu_ibuf = PUT_CCH (i) | mux_sta[i] | LIU_TR; /* hi buf = stat */ + mux_xdon[i] = 0; /* clr done, stat */ + mux_sta[i] = 0; + setFLG (muxl_dib.devno); /* interrupt */ + return; } } +for (i = MUX_LINES; i < (MUX_LINES + MUX_ILINES); i++) { /* diag lines */ + if ((mux_rpar[i] & OTL_ENB) && mux_rchp[i]) { /* enabled, char? */ + muxl_ibuf = PUT_CCH (i) | mux_rbuf[i] | /* lo buf = char */ + RCV_PAR (mux_rbuf[i]); + muxu_ibuf = PUT_CCH (i) | mux_sta[i] | LIU_DG; /* hi buf = stat */ + mux_rchp[i] = 0; /* clr char, stat */ + mux_sta[i] = 0; + setFLG (muxl_dib.devno); + return; } } +return; +} + +/* Look for control interrupt */ + +void mux_ctrl_int (void) +{ +int32 i; + +if (muxc_scan == 0) return; +for (i = 0; i < MUX_LINES; i++) { + muxc_chan = (muxc_chan + 1) & LIC_M_CHAN; /* step channel */ + if (LIC_TSTI (muxc_chan)) { /* status change? */ + setFLG (muxc_dib.devno); /* set flag */ + break; } } +return; +} + +/* Set diagnostic lines for given character */ + +void mux_diag (int32 c) +{ +int32 i; + +for (i = MUX_LINES; i < (MUX_LINES + MUX_ILINES); i++) { + if (mux_rchp[i]) mux_sta[i] = mux_sta[i] | LIU_LOST; + mux_rchp[i] = 1; + mux_rbuf[i] = c; } +return; +} + +/* Reset an individual line */ + +void mux_reset_ln (int32 i) +{ +mux_rbuf[i] = mux_xbuf[i] = 0; /* clear state */ +mux_rpar[i] = mux_xpar[i] = 0; +mux_rchp[i] = mux_xdon[i] = 0; +mux_sta[i] = 0; +muxc_ota[i] = muxc_lia[i] = 0; /* clear modem */ +if (mux_ldsc[i].conn) /* connected? */ + muxc_lia[i] = muxc_lia[i] | DSR | /* cdet, dsr */ + (muxl_unit[i].flags & UNIT_MDM? CDET: 0); +sim_cancel (&muxl_unit[i]); +return; +} + +/* Reset routine */ + +t_stat mux_reset (DEVICE *dptr) +{ +int32 i, t; + +muxl_dib.cmd = muxl_dib.ctl = 0; /* init lower */ +muxl_dib.flg = muxl_dib.fbf = 1; +muxu_dib.cmd = muxu_dib.ctl = 0; /* upper not */ +muxu_dib.flg = muxu_dib.fbf = 0; /* implemented */ +muxc_dib.cmd = muxc_dib.ctl = 0; /* init ctrl */ +muxc_dib.flg = muxc_dib.fbf = 1; +muxc_chan = muxc_scan = 0; /* init modem scan */ +if (muxu_unit.flags & UNIT_ATT) { /* master att? */ + if (!sim_is_active (&muxu_unit)) { + t = sim_rtcn_init (muxu_unit.wait, TMR_MUX); + sim_activate (&muxu_unit, t); } } /* activate */ +else sim_cancel (&muxu_unit); /* else stop */ +for (i = 0; i < MUX_LINES; i++) { + mux_desc.ldsc[i] = &mux_ldsc[i]; + mux_reset_ln (i); } +return SCPE_OK; +} + +/* Attach master unit */ + +t_stat mux_attach (UNIT *uptr, char *cptr) +{ +t_stat r; +int32 t; + +r = tmxr_attach (&mux_desc, uptr, cptr); /* attach */ +if (r != SCPE_OK) return r; /* error */ +t = sim_rtcn_init (muxu_unit.wait, TMR_MUX); +sim_activate (uptr, t); /* start poll */ +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++) mux_ldsc[i].rcve = 0; /* disable rcv */ +sim_cancel (uptr); /* stop poll */ +return SCPE_OK; +} + +/* Show summary processor */ + +t_stat mux_summ (FILE *st, UNIT *uptr, int32 val, void *desc) +{ +int32 i, t; + +for (i = t = 0; i < MUX_LINES; i++) t = t + (mux_ldsc[i].conn != 0); +if (t == 1) fprintf (st, "1 connection"); +else fprintf (st, "%d connections", t); +return SCPE_OK; +} + +/* SHOW CONN/STAT processor */ + +t_stat mux_show (FILE *st, UNIT *uptr, int32 val, void *desc) +{ +int32 i; + +for (i = 0; (i < MUX_LINES) && (mux_ldsc[i].conn == 0); i++) ; +if (i < MUX_LINES) { + for (i = 0; i < MUX_LINES; i++) { + if (mux_ldsc[i].conn) + if (val) tmxr_fconns (st, &mux_ldsc[i], i); + else tmxr_fstats (st, &mux_ldsc[i], i); } } +else fprintf (st, "all disconnected\n"); +return SCPE_OK; +} + +/* Enable device */ + +t_stat mux_enb (UNIT *uptr, int32 num, char *cptr, void *desc) +{ +if (cptr != NULL) return SCPE_ARG; +muxl_dib.enb = 1; +muxu_dib.enb = 1; +muxc_dib.enb = 1; +return mux_reset (&muxl_dev); +} + +/* Disable device */ + +t_stat mux_dis (UNIT *uptr, int32 num, char *cptr, void *desc) +{ +if (cptr != NULL) return SCPE_ARG; +if (muxu_unit.flags & UNIT_ATT) return SCPE_NOFNC; +muxl_dib.enb = 0; +muxu_dib.enb = 0; +muxc_dib.enb = 0; +return mux_reset (&muxl_dev); +} + diff --git a/HP2100/hp2100_stddev.c b/HP2100/hp2100_stddev.c index ebeb8bfa..cc8445e5 100644 --- a/HP2100/hp2100_stddev.c +++ b/HP2100/hp2100_stddev.c @@ -1,6 +1,6 @@ -/* hp2100_stddev.c: HP2100 standard devices +/* hp2100_stddev.c: HP2100 standard devices simulator - Copyright (c) 1993-2001, Robert M. Supnik + Copyright (c) 1993-2002, Robert M. Supnik Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), @@ -28,6 +28,8 @@ tty 12531C buffered teleprinter interface clk 12539A/B/C time base generator + 30-May-02 RMS Widened POS to 32b + 22-Mar-02 RMS Revised for dynamically allocated memory 03-Nov-01 RMS Changed DEVNO to use extended SET/SHOW 29-Nov-01 RMS Added read only unit support 24-Nov-01 RMS Changed TIME to an array @@ -53,11 +55,10 @@ #define CLK_V_ERROR 4 /* clock overrun */ #define CLK_ERROR (1 << CLK_V_ERROR) -extern uint16 M[]; +extern uint16 *M; extern int32 PC; extern int32 dev_cmd[2], dev_ctl[2], dev_flg[2], dev_fbf[2]; extern UNIT cpu_unit; -extern struct hpdev infotab[]; int32 ptr_stopioe = 0, ptp_stopioe = 0; /* stop on error */ int32 ttp_stopioe = 0; int32 tty_buf = 0, tty_mode = 0; /* tty buffer, mode */ @@ -65,14 +66,19 @@ int32 clk_select = 0; /* clock time select */ int32 clk_error = 0; /* clock error */ int32 clk_delay[8] = /* clock intervals */ { 50, 500, 5000, 50000, 500000, 5000000, 50000000, 50000000 }; + +int32 ptrio (int32 inst, int32 IR, int32 dat); t_stat ptr_svc (UNIT *uptr); t_stat ptr_reset (DEVICE *dptr); t_stat ptr_boot (int32 unitno); +int32 ptpio (int32 inst, int32 IR, int32 dat); t_stat ptp_svc (UNIT *uptr); t_stat ptp_reset (DEVICE *dptr); +int32 ttyio (int32 inst, int32 IR, int32 dat); t_stat tti_svc (UNIT *uptr); t_stat tto_svc (UNIT *uptr); t_stat tty_reset (DEVICE *dptr); +int32 clkio (int32 inst, int32 IR, int32 dat); t_stat clk_svc (UNIT *uptr); t_stat clk_reset (DEVICE *dptr); @@ -84,25 +90,32 @@ t_stat clk_reset (DEVICE *dptr); ptr_reg PTR register list */ +DIB ptr_dib = { PTR, 1, 0, 0, 0, 0, &ptrio }; + UNIT ptr_unit = { UDATA (&ptr_svc, UNIT_SEQ+UNIT_ATTABLE+UNIT_ROABLE, 0), SERIAL_IN_WAIT }; REG ptr_reg[] = { { ORDATA (BUF, ptr_unit.buf, 8) }, - { FLDATA (CMD, infotab[inPTR].cmd, 0) }, - { FLDATA (CTL, infotab[inPTR].ctl, 0) }, - { FLDATA (FLG, infotab[inPTR].flg, 0) }, - { FLDATA (FBF, infotab[inPTR].fbf, 0) }, - { DRDATA (POS, ptr_unit.pos, 31), PV_LEFT }, + { FLDATA (CMD, ptr_dib.cmd, 0) }, + { FLDATA (CTL, ptr_dib.ctl, 0) }, + { FLDATA (FLG, ptr_dib.flg, 0) }, + { FLDATA (FBF, ptr_dib.fbf, 0) }, + { DRDATA (POS, ptr_unit.pos, 32), PV_LEFT }, { DRDATA (TIME, ptr_unit.wait, 24), PV_LEFT }, { FLDATA (STOP_IOE, ptr_stopioe, 0) }, - { ORDATA (DEVNO, infotab[inPTR].devno, 6), REG_RO }, + { ORDATA (DEVNO, ptr_dib.devno, 6), REG_HRO }, + { FLDATA (*DEVENB, ptr_dib.enb, 0), REG_HRO }, { NULL } }; MTAB ptr_mod[] = { - { MTAB_XTD | MTAB_VDV, inPTR, "DEVNO", "DEVNO", - &hp_setdev, &hp_showdev, NULL }, + { MTAB_XTD | MTAB_VDV, 0, NULL, "ENABLED", + &set_enb, NULL, &ptr_dib }, + { MTAB_XTD | MTAB_VDV, 0, NULL, "DISABLED", + &set_dis, NULL, &ptr_dib }, + { MTAB_XTD | MTAB_VDV, 0, "DEVNO", "DEVNO", + &hp_setdev, &hp_showdev, &ptr_dib }, { 0 } }; DEVICE ptr_dev = { @@ -119,24 +132,31 @@ DEVICE ptr_dev = { ptp_reg PTP register list */ +DIB ptp_dib = { PTP, 1, 0, 0, 0, 0, &ptpio }; + UNIT ptp_unit = { UDATA (&ptp_svc, UNIT_SEQ+UNIT_ATTABLE, 0), SERIAL_OUT_WAIT }; REG ptp_reg[] = { { ORDATA (BUF, ptp_unit.buf, 8) }, - { FLDATA (CMD, infotab[inPTP].cmd, 0) }, - { FLDATA (CTL, infotab[inPTP].ctl, 0) }, - { FLDATA (FLG, infotab[inPTP].flg, 0) }, - { FLDATA (FBF, infotab[inPTP].fbf, 0) }, - { DRDATA (POS, ptp_unit.pos, 31), PV_LEFT }, + { FLDATA (CMD, ptp_dib.cmd, 0) }, + { FLDATA (CTL, ptp_dib.ctl, 0) }, + { FLDATA (FLG, ptp_dib.flg, 0) }, + { FLDATA (FBF, ptp_dib.fbf, 0) }, + { DRDATA (POS, ptp_unit.pos, 32), PV_LEFT }, { DRDATA (TIME, ptp_unit.wait, 24), PV_LEFT }, { FLDATA (STOP_IOE, ptp_stopioe, 0) }, - { ORDATA (DEVNO, infotab[inPTP].devno, 6), REG_RO }, + { ORDATA (DEVNO, ptp_dib.devno, 6), REG_HRO }, + { FLDATA (*DEVENB, ptr_dib.enb, 0), REG_HRO }, { NULL } }; MTAB ptp_mod[] = { - { MTAB_XTD | MTAB_VDV, inPTP, "DEVNO", "DEVNO", - &hp_setdev, &hp_showdev, NULL }, + { MTAB_XTD | MTAB_VDV, 0, NULL, "ENABLED", + &set_enb, NULL, &ptp_dib }, + { MTAB_XTD | MTAB_VDV, 0, NULL, "DISABLED", + &set_dis, NULL, &ptp_dib }, + { MTAB_XTD | MTAB_VDV, 0, "DEVNO", "DEVNO", + &hp_setdev, &hp_showdev, &ptp_dib }, { 0 } }; DEVICE ptp_dev = { @@ -157,6 +177,8 @@ DEVICE ptp_dev = { #define TTO 1 #define TTP 2 +DIB tty_dib = { TTY, 1, 0, 0, 0, 0, &ttyio }; + UNIT tty_unit[] = { { UDATA (&tti_svc, UNIT_UC, 0), KBD_POLL_WAIT }, { UDATA (&tto_svc, 0, 0), SERIAL_OUT_WAIT }, @@ -165,25 +187,25 @@ UNIT tty_unit[] = { REG tty_reg[] = { { ORDATA (BUF, tty_buf, 8) }, { ORDATA (MODE, tty_mode, 16) }, - { FLDATA (CMD, infotab[inTTY].cmd, 0), REG_HRO }, - { FLDATA (CTL, infotab[inTTY].ctl, 0) }, - { FLDATA (FLG, infotab[inTTY].flg, 0) }, - { FLDATA (FBF, infotab[inTTY].fbf, 0) }, - { DRDATA (KPOS, tty_unit[TTI].pos, 31), PV_LEFT }, + { FLDATA (CMD, tty_dib.cmd, 0), REG_HRO }, + { FLDATA (CTL, tty_dib.ctl, 0) }, + { FLDATA (FLG, tty_dib.flg, 0) }, + { FLDATA (FBF, tty_dib.fbf, 0) }, + { DRDATA (KPOS, tty_unit[TTI].pos, 32), PV_LEFT }, { DRDATA (KTIME, tty_unit[TTI].wait, 24), REG_NZ + PV_LEFT }, - { DRDATA (TPOS, tty_unit[TTO].pos, 31), PV_LEFT }, + { DRDATA (TPOS, tty_unit[TTO].pos, 32), PV_LEFT }, { DRDATA (TTIME, tty_unit[TTO].wait, 24), REG_NZ + PV_LEFT }, - { DRDATA (PPOS, tty_unit[TTP].pos, 31), PV_LEFT }, + { DRDATA (PPOS, tty_unit[TTP].pos, 32), PV_LEFT }, { FLDATA (STOP_IOE, ttp_stopioe, 0) }, - { ORDATA (DEVNO, infotab[inTTY].devno, 6), REG_RO }, + { ORDATA (DEVNO, tty_dib.devno, 6), REG_HRO }, { FLDATA (UC, tty_unit[TTI].flags, UNIT_V_UC), REG_HRO }, { NULL } }; MTAB tty_mod[] = { { UNIT_UC, 0, "lower case", "LC", NULL }, { UNIT_UC, UNIT_UC, "upper case", "UC", NULL }, - { MTAB_XTD | MTAB_VDV, inTTY, "DEVNO", "DEVNO", - &hp_setdev, &hp_showdev, NULL }, + { MTAB_XTD | MTAB_VDV, 0, "DEVNO", "DEVNO", + &hp_setdev, &hp_showdev, &tty_dib }, { 0 } }; DEVICE tty_dev = { @@ -200,23 +222,25 @@ DEVICE tty_dev = { clk_reg CLK register list */ +DIB clk_dib = { CLK, 1, 0, 0, 0, 0, &clkio }; + UNIT clk_unit = { UDATA (&clk_svc, 0, 0) }; REG clk_reg[] = { { ORDATA (SEL, clk_select, 3) }, - { FLDATA (CMD, infotab[inCLK].cmd, 0), REG_HRO }, - { FLDATA (CTL, infotab[inCLK].ctl, 0) }, - { FLDATA (FLG, infotab[inCLK].flg, 0) }, - { FLDATA (FBF, infotab[inCLK].fbf, 0) }, + { FLDATA (CMD, clk_dib.cmd, 0), REG_HRO }, + { FLDATA (CTL, clk_dib.ctl, 0) }, + { FLDATA (FLG, clk_dib.flg, 0) }, + { FLDATA (FBF, clk_dib.fbf, 0) }, { FLDATA (ERR, clk_error, CLK_V_ERROR) }, { BRDATA (TIME, clk_delay, 8, 31, 8) }, - { ORDATA (DEVNO, infotab[inCLK].devno, 6), REG_RO }, + { ORDATA (DEVNO, clk_dib.devno, 6), REG_HRO }, { NULL } }; MTAB clk_mod[] = { - { MTAB_XTD | MTAB_VDV, inCLK, "DEVNO", "DEVNO", - &hp_setdev, &hp_showdev, NULL }, + { MTAB_XTD | MTAB_VDV, 0, "DEVNO", "DEVNO", + &hp_setdev, &hp_showdev, &clk_dib }, { 0 } }; DEVICE clk_dev = { @@ -237,10 +261,10 @@ case ioFLG: /* flag clear/set */ if ((IR & HC) == 0) { setFLG (dev); } /* STF */ break; case ioSFC: /* skip flag clear */ - if (FLG (dev) == 0) PC = (PC + 1) & AMASK; + if (FLG (dev) == 0) PC = (PC + 1) & VAMASK; return dat; case ioSFS: /* skip flag set */ - if (FLG (dev) != 0) PC = (PC + 1) & AMASK; + if (FLG (dev) != 0) PC = (PC + 1) & VAMASK; return dat; case ioMIX: /* merge */ dat = dat | ptr_unit.buf; @@ -268,7 +292,7 @@ t_stat ptr_svc (UNIT *uptr) { int32 dev, temp; -dev = infotab[inPTR].devno; /* get device no */ +dev = ptr_dib.devno; /* get device no */ clrCMD (dev); /* clear cmd */ if ((ptr_unit.flags & UNIT_ATT) == 0) /* attached? */ return IORETURN (ptr_stopioe, SCPE_UNATT); @@ -285,12 +309,12 @@ ptr_unit.pos = ftell (ptr_unit.fileref); return SCPE_OK; } -/* Reset routine - called from SCP, flags in infotab */ +/* Reset routine - called from SCP, flags in DIB's */ t_stat ptr_reset (DEVICE *dptr) { -infotab[inPTR].cmd = infotab[inPTR].ctl = 0; /* clear cmd, ctl */ -infotab[inPTR].flg = infotab[inPTR].fbf = 1; /* set flg, fbf */ +ptr_dib.cmd = ptr_dib.ctl = 0; /* clear cmd, ctl */ +ptr_dib.flg = ptr_dib.fbf = 1; /* set flg, fbf */ ptr_unit.buf = 0; sim_cancel (&ptr_unit); /* deactivate unit */ return SCPE_OK; @@ -323,7 +347,7 @@ t_stat ptr_boot (int32 unit) { int32 i, dev; -dev = infotab[inPTR].devno; /* get device no */ +dev = ptr_dib.devno; /* get device no */ PC = (MEMSIZE - 1) & ~PBOOT_MASK; /* start at mem top */ for (i = 0; i < PBOOT_SIZE; i++) /* copy bootstrap */ M[PC + i] = (pboot[i] & CHANGE_DEV)? /* insert ptr dev no */ @@ -343,10 +367,10 @@ case ioFLG: /* flag clear/set */ if ((IR & HC) == 0) { setFLG (dev); } /* STF */ break; case ioSFC: /* skip flag clear */ - if (FLG (dev) == 0) PC = (PC + 1) & AMASK; + if (FLG (dev) == 0) PC = (PC + 1) & VAMASK; return dat; case ioSFS: /* skip flag set */ - if (FLG (dev) != 0) PC = (PC + 1) & AMASK; + if (FLG (dev) != 0) PC = (PC + 1) & VAMASK; return dat; case ioLIX: /* load */ dat = 0; @@ -377,7 +401,7 @@ t_stat ptp_svc (UNIT *uptr) { int32 dev; -dev = infotab[inPTP].devno; /* get device no */ +dev = ptp_dib.devno; /* get device no */ clrCMD (dev); /* clear cmd */ setFLG (dev); /* set flag */ if ((ptp_unit.flags & UNIT_ATT) == 0) /* attached? */ @@ -394,8 +418,8 @@ return SCPE_OK; t_stat ptp_reset (DEVICE *dptr) { -infotab[inPTP].cmd = infotab[inPTP].ctl = 0; /* clear cmd, ctl */ -infotab[inPTP].flg = infotab[inPTP].fbf = 1; /* set flg, fbf */ +ptp_dib.cmd = ptp_dib.ctl = 0; /* clear cmd, ctl */ +ptp_dib.flg = ptp_dib.fbf = 1; /* set flg, fbf */ ptp_unit.buf = 0; sim_cancel (&ptp_unit); /* deactivate unit */ return SCPE_OK; @@ -413,10 +437,10 @@ case ioFLG: /* flag clear/set */ if ((IR & HC) == 0) { setFLG (dev); } /* STF */ break; case ioSFC: /* skip flag clear */ - if (FLG (dev) == 0) PC = (PC + 1) & AMASK; + if (FLG (dev) == 0) PC = (PC + 1) & VAMASK; return dat; case ioSFS: /* skip flag set */ - if (FLG (dev) != 0) PC = (PC + 1) & AMASK; + if (FLG (dev) != 0) PC = (PC + 1) & VAMASK; return dat; case ioLIX: /* load */ dat = 0; @@ -448,6 +472,7 @@ t_stat tto_out (int32 ch) t_stat ret = SCPE_OK; if (tty_mode & TM_PRI) { /* printing? */ + ch = ch & 0177; if ((tty_unit[TTI].flags & UNIT_UC) && islower (ch)) /* upper case? */ ch = toupper (ch); ret = sim_putchar (ch & 0177); /* output char */ @@ -467,7 +492,7 @@ t_stat tti_svc (UNIT *uptr) { int32 temp, dev; -dev = infotab[inTTY].devno; /* get device no */ +dev = tty_dib.devno; /* get device no */ sim_activate (&tty_unit[TTI], tty_unit[TTI].wait); /* continue poll */ if ((temp = sim_poll_kbd ()) < SCPE_KFLAG) return temp; /* no char or error? */ temp = temp & 0177; @@ -485,7 +510,7 @@ t_stat tto_svc (UNIT *uptr) { int32 ch, dev; -dev = infotab[inTTY].devno; /* get device no */ +dev = tty_dib.devno; /* get device no */ setFLG (dev); /* set done flag */ ch = tty_buf; tty_buf = 0377; /* defang buf */ @@ -496,8 +521,8 @@ return tto_out (ch); /* print and/or punch */ t_stat tty_reset (DEVICE *dptr) { -infotab[inTTY].cmd = infotab[inTTY].ctl = 0; /* clear cmd, ctl */ -infotab[inTTY].flg = infotab[inTTY].fbf = 1; /* set flg, fbf */ +tty_dib.cmd = tty_dib.ctl = 0; /* clear cmd, ctl */ +tty_dib.flg = tty_dib.fbf = 1; /* set flg, fbf */ tty_mode = 0; tty_buf = 0; sim_activate (&tty_unit[TTI], tty_unit[TTI].wait); /* activate poll */ @@ -517,10 +542,10 @@ case ioFLG: /* flag clear/set */ if ((IR & HC) == 0) { setFLG (dev); } /* STF */ break; case ioSFC: /* skip flag clear */ - if (FLG (dev) == 0) PC = (PC + 1) & AMASK; + if (FLG (dev) == 0) PC = (PC + 1) & VAMASK; return dat; case ioSFS: /* skip flag set */ - if (FLG (dev) != 0) PC = (PC + 1) & AMASK; + if (FLG (dev) != 0) PC = (PC + 1) & VAMASK; return dat; case ioMIX: /* merge */ dat = dat | clk_error; @@ -551,7 +576,7 @@ t_stat clk_svc (UNIT *uptr) { int32 dev; -dev = infotab[inCLK].devno; /* get device no */ +dev = clk_dib.devno; /* get device no */ if (FLG (dev)) clk_error = CLK_ERROR; /* overrun? */ setFLG (dev); /* set device flag */ return SCPE_OK; @@ -561,8 +586,8 @@ return SCPE_OK; t_stat clk_reset (DEVICE *dptr) { -infotab[inCLK].cmd = infotab[inCLK].ctl = 0; /* clear cmd, ctl */ -infotab[inCLK].flg = infotab[inCLK].fbf = 1; /* set flg, fbf */ +clk_dib.cmd = clk_dib.ctl = 0; /* clear cmd, ctl */ +clk_dib.flg = clk_dib.fbf = 1; /* set flg, fbf */ clk_error = 0; /* clear error */ clk_select = 0; /* clear select */ sim_cancel (&clk_unit); /* deactivate unit */ diff --git a/HP2100/hp2100_sys.c b/HP2100/hp2100_sys.c index e0617a0f..287d8180 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-2001, Robert M. Supnik + Copyright (c) 1993-2002, Robert M. Supnik Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), @@ -23,6 +23,11 @@ be used in advertising or otherwise to promote the sale, use or other dealings in this Software without prior written authorization from Robert M Supnik. + 22-Mar-02 RMS Revised for dynamically allocated memory + 14-Feb-02 RMS Added DMS instructions + 04-Feb-02 RMS Fixed bugs in alter/skip display and parsing + 01-Feb-02 RMS Added terminal multiplexor support + 16-Jan-02 RMS Added additional device support 17-Sep-01 RMS Removed multiconsole support 27-May-01 RMS Added multiconsole support 14-Mar-01 RMS Revised load/dump interface (again) @@ -40,9 +45,13 @@ extern DEVICE dma0_dev, dma1_dev; extern DEVICE ptr_dev, ptp_dev; extern DEVICE tty_dev, clk_dev, lpt_dev; extern DEVICE mtd_dev, mtc_dev; +extern DEVICE msd_dev, msc_dev; extern DEVICE dpd_dev, dpc_dev; +extern DEVICE dqd_dev, dqc_dev; +extern DEVICE drd_dev, drc_dev; +extern DEVICE muxl_dev, muxu_dev, muxc_dev; extern REG cpu_reg[]; -extern uint16 M[]; +extern uint16 *M; /* SCP data structures and interface routines @@ -65,8 +74,12 @@ DEVICE *sim_devices[] = { &cpu_dev, &ptr_dev, &ptp_dev, &tty_dev, &clk_dev, &lpt_dev, - &mtd_dev, &mtc_dev, &dpd_dev, &dpc_dev, + &dqd_dev, &dqc_dev, + &drd_dev, &drc_dev, + &mtd_dev, &mtc_dev, + &msd_dev, &msc_dev, + &muxu_dev, &muxl_dev, &muxc_dev, NULL }; const char *sim_stop_messages[] = { @@ -129,24 +142,24 @@ return SCPE_OK; #define I_V_FL 16 /* flag start */ #define I_M_FL 017 /* flag mask */ #define I_V_NPN 0 /* no operand */ -#define I_V_NPNC 1 /* no operand + C */ +#define I_V_NPC 1 /* no operand + C */ #define I_V_MRF 2 /* mem ref */ #define I_V_ASH 3 /* alter/skip, shift */ -#define I_V_ESHF 4 /* extended shift */ -#define I_V_EMRF 5 /* extended mem ref */ -#define I_V_IOT1 6 /* I/O + HC */ -#define I_V_IOT2 7 /* I/O only */ -#define I_V_EG1Z 010 /* ext grp, 1 op + 0 */ +#define I_V_ESH 4 /* extended shift */ +#define I_V_EMR 5 /* extended mem ref */ +#define I_V_IO1 6 /* I/O + HC */ +#define I_V_IO2 7 /* I/O only */ +#define I_V_EGZ 010 /* ext grp, 1 op + 0 */ #define I_V_EG2 011 /* ext grp, 2 op */ #define I_NPN (I_V_NPN << I_V_FL) -#define I_NPNC (I_V_NPNC << I_V_FL) +#define I_NPC (I_V_NPC << I_V_FL) #define I_MRF (I_V_MRF << I_V_FL) #define I_ASH (I_V_ASH << I_V_FL) -#define I_ESHF (I_V_ESHF << I_V_FL) -#define I_EMRF (I_V_EMRF << I_V_FL) -#define I_IOT1 (I_V_IOT1 << I_V_FL) -#define I_IOT2 (I_V_IOT2 << I_V_FL) -#define I_EG1Z (I_V_EG1Z << I_V_FL) +#define I_ESH (I_V_ESH << I_V_FL) +#define I_EMR (I_V_EMR << I_V_FL) +#define I_IO1 (I_V_IO1 << I_V_FL) +#define I_IO2 (I_V_IO2 << I_V_FL) +#define I_EGZ (I_V_EGZ << I_V_FL) #define I_EG2 (I_V_EG2 << I_V_FL) static const int32 masks[] = { @@ -169,6 +182,18 @@ static const char *opcode[] = { "SFC", "SFS", "MIA", "MIB", "LIA", "LIB", "OTA", "OTB", "STC", "CLC", + "SYA", "USA", "PAA", "PBA", + "XMA", + "XLA", "XSA", "XCA", "LFA", + "RSA", "RVA", + "MBI", "MBF", + "MBW", "MWI", "MWF", "MWW", + "SYB", "USB", "PAB", "PBB", + "SSM", "JRS", + "XMM", "XMS", "XMB", + "XLB", "XSB", "XCB", "LFB", + "RSB", "RVB", "DJP", "DJS", + "SJP", "SJS", "UJP", "UJS", "SAX", "SBX", "CAX", "CBX", "LAX", "LBX", "STX", "CXA", "CXB", "LDX", @@ -189,28 +214,40 @@ static const int32 opc_val[] = { 0020000+I_MRF, 0024000+I_MRF, 0030000+I_MRF, 0034000+I_MRF, 0040000+I_MRF, 0044000+I_MRF, 0050000+I_MRF, 0054000+I_MRF, 0060000+I_MRF, 0064000+I_MRF, 0070000+I_MRF, 0074000+I_MRF, - 0100020+I_ESHF, 0100040+I_ESHF, 0100100+I_ESHF, - 0101020+I_ESHF, 0101040+I_ESHF, 0101100+I_ESHF, - 0100200+I_EMRF, 0100400+I_EMRF, 0104200+I_EMRF, 0104400+I_EMRF, - 0105000+I_EMRF, 0105020+I_EMRF, 0105040+I_EMRF, 0105060+I_EMRF, + 0100020+I_ESH, 0100040+I_ESH, 0100100+I_ESH, + 0101020+I_ESH, 0101040+I_ESH, 0101100+I_ESH, + 0100200+I_EMR, 0100400+I_EMR, 0104200+I_EMR, 0104400+I_EMR, + 0105000+I_EMR, 0105020+I_EMR, 0105040+I_EMR, 0105060+I_EMR, 0105100+I_NPN, 0105120+I_NPN, - 0102101+I_NPN, 0103101+I_NPN, 0102201+I_NPNC, 0102301+I_NPNC, - 0102000+I_IOT1, 0102100+I_IOT2, 0103100+I_IOT2, - 0102200+I_IOT2, 0102300+I_IOT2, 0102400+I_IOT1, 0106400+I_IOT1, - 0102500+I_IOT1, 0106500+I_IOT1, 0102600+I_IOT1, 0106600+I_IOT1, - 0102700+I_IOT1, 0106700+I_IOT1, - 0101740+I_EMRF, 0105740+I_EMRF, 0101741+I_NPN, 0105741+I_NPN, - 0101742+I_EMRF, 0105742+I_EMRF, 0105743+I_EMRF, - 0101744+I_NPN, 0105744+I_NPN, 0105745+I_EMRF, - 0105746+I_EMRF, 0101747+I_NPN, 0105747+I_NPN, - 0101750+I_EMRF, 0105750+I_EMRF, 0101751+I_NPN, 0105751+I_NPN, - 0101752+I_EMRF, 0105752+I_EMRF, 0105753+I_EMRF, - 0101754+I_NPN, 0105754+I_NPN, 0105755+I_EMRF, - 0105756+I_EMRF, 0101757+I_NPN, 0105757+I_NPN, - 0105760+I_NPN, 0105761+I_NPN, 0105762+I_EMRF, 0105763+I_NPN, - 0105764+I_NPN, 0105765+I_EG1Z, 0105766+I_EG1Z, 0105767+I_NPN, - 0105770+I_NPN, 0105771+I_NPN, 0105772+I_EMRF, 0105773+I_EG2, - 0105774+I_EG2, 0105775+I_EG2, 0105776+I_EG1Z, 0105777+I_EG1Z, + 0102101+I_NPN, 0103101+I_NPN, 0102201+I_NPC, 0102301+I_NPC, + 0102000+I_IO1, 0102100+I_IO2, 0103100+I_IO2, + 0102200+I_IO2, 0102300+I_IO2, 0102400+I_IO1, 0106400+I_IO1, + 0102500+I_IO1, 0106500+I_IO1, 0102600+I_IO1, 0106600+I_IO1, + 0102700+I_IO1, 0106700+I_IO1, + 0101710+I_NPN, 0101711+I_NPN, 0101712+I_NPN, 0101713+I_NPN, + 0101722+I_NPN, + 0101724+I_EMR, 0101725+I_EMR, 0101726+I_EMR, 0101727+I_NPN, + 0101730+I_NPN, 0101731+I_NPN, + 0105702+I_NPN, 0105703+I_NPN, + 0105704+I_NPN, 0105705+I_NPN, 0105706+I_NPN, 0105707+I_NPN, + 0105710+I_NPN, 0105711+I_NPN, 0105712+I_NPN, 0105713+I_NPN, + 0105714+I_EMR, 0105715+I_EG2, + 0105720+I_NPN, 0105721+I_NPN, 0105722+I_NPN, + 0105724+I_EMR, 0105725+I_EMR, 0105726+I_EMR, 0105727+I_NPN, + 0105730+I_NPN, 0105731+I_NPN, 0105732+I_EMR, 0105733+I_EMR, + 0105734+I_EMR, 0105735+I_EMR, 0105736+I_EMR, 0105737+I_EMR, + 0101740+I_EMR, 0105740+I_EMR, 0101741+I_NPN, 0105741+I_NPN, + 0101742+I_EMR, 0105742+I_EMR, 0105743+I_EMR, + 0101744+I_NPN, 0105744+I_NPN, 0105745+I_EMR, + 0105746+I_EMR, 0101747+I_NPN, 0105747+I_NPN, + 0101750+I_EMR, 0105750+I_EMR, 0101751+I_NPN, 0105751+I_NPN, + 0101752+I_EMR, 0105752+I_EMR, 0105753+I_EMR, + 0101754+I_NPN, 0105754+I_NPN, 0105755+I_EMR, + 0105756+I_EMR, 0101757+I_NPN, 0105757+I_NPN, + 0105760+I_NPN, 0105761+I_NPN, 0105762+I_EMR, 0105763+I_NPN, + 0105764+I_NPN, 0105765+I_EGZ, 0105766+I_EGZ, 0105767+I_NPN, + 0105770+I_NPN, 0105771+I_NPN, 0105772+I_EMR, 0105773+I_EG2, + 0105774+I_EG2, 0105775+I_EG2, 0105776+I_EGZ, 0105777+I_EGZ, 0000000+I_ASH, /* decode only */ -1 }; @@ -230,8 +267,8 @@ static const char *stab[] = { static const int32 mtab[] = { 0007700, 0007700, 0007700, 0007700, 0007700, 0007700, 0007700, 0007700, 0007700, 0007700, 0007700, 0007700, 0007700, 0007700, 0007700, 0007700, - 0007400, 0007400, 0007400, 0007400, 0007400, 0007400, - 0002040, 0002040, 0002300, 0002300, 0002300, + 0006400, 0007000, 0007400, 0006400, 0007000, 0007400, + 0002040, 0002040, 0002100, 0002200, 0002300, 0006020, 0006020, 0004010, 0004010, 0006027, 0006027, 0006027, 0006027, 0006027, 0006027, 0006027, 0006027, 0006027, 0006027, 0006027, 0006027, 0006027, 0006027, 0006027, 0006027, @@ -288,15 +325,15 @@ for (i = 0; opc_val[i] >= 0; i++) { /* loop thru ops */ switch (j) { /* case on class */ case I_V_NPN: /* no operands */ - fprintf (of, "%s", opcode[i]); /* opcode */ + fprintf (of, "%s", opcode[i]); /* opcode */ break; - case I_V_NPNC: /* no operands + C */ + case I_V_NPC: /* no operands + C */ fprintf (of, "%s", opcode[i]); if (inst & HC) fprintf (of, " C"); break; case I_V_MRF: /* mem ref */ disp = inst & DISP; /* displacement */ - fprintf (of, "%s ", opcode[i]); /* opcode */ + fprintf (of, "%s ", opcode[i]); /* opcode */ if (inst & CP) { /* current page? */ if (cflag) fprintf (of, "%-o", (addr & PAGENO) | disp); else fprintf (of, "C %-o", disp); } @@ -306,36 +343,37 @@ for (i = 0; opc_val[i] >= 0; i++) { /* loop thru ops */ case I_V_ASH: /* shift, alter-skip */ cm = FALSE; for (i = 0; mtab[i] != 0; i++) { - if ((inst & mtab[i]) == vtab[i]) { - if (cm) fprintf (of, ","); - cm = TRUE; - fprintf (of, "%s", stab[i]); } } - if (!cm) return SCPE_ARG; /* nothing decoded? */ + if ((inst & mtab[i]) == vtab[i]) { + inst = inst & ~(vtab[i] & 01777); + if (cm) fprintf (of, ","); + cm = TRUE; + fprintf (of, "%s", stab[i]); } } + if (!cm) return SCPE_ARG; /* nothing decoded? */ break; - case I_V_ESHF: /* extended shift */ + case I_V_ESH: /* extended shift */ disp = inst & 017; /* shift count */ if (disp == 0) disp = 16; fprintf (of, "%s %d", opcode[i], disp); break; - case I_V_EMRF: /* extended mem ref */ - fprintf (of, "%s %-o", opcode[i], val[1] & AMASK); + case I_V_EMR: /* extended mem ref */ + fprintf (of, "%s %-o", opcode[i], val[1] & VAMASK); if (val[1] & IA) fprintf (of, ",I"); return -1; /* extra word */ - case I_V_IOT1: /* IOT with H/C */ + case I_V_IO1: /* IOT with H/C */ fprintf (of, "%s %-o", opcode[i], inst & DEVMASK); if (inst & HC) fprintf (of, ",C"); break; - case I_V_IOT2: /* IOT */ + case I_V_IO2: /* IOT */ fprintf (of, "%s %-o", opcode[i], inst & DEVMASK); break; - case I_V_EG1Z: /* ext grp 1 op + 0 */ - fprintf (of, "%s %-o", opcode[i], val[1] & AMASK); + case I_V_EGZ: /* ext grp 1 op + 0 */ + fprintf (of, "%s %-o", opcode[i], val[1] & VAMASK); if (val[1] & IA) fprintf (of, ",I"); return -2; /* extra words */ case I_V_EG2: /* ext grp 2 op */ - fprintf (of, "%s %-o", opcode[i], val[1] & AMASK); + fprintf (of, "%s %-o", opcode[i], val[1] & VAMASK); if (val[1] & IA) fprintf (of, ",I"); - fprintf (of, " %-o", val[2] & AMASK); + fprintf (of, " %-o", val[2] & VAMASK); if (val[2] & IA) fprintf (of, ",I"); return -2; } /* extra words */ return SCPE_OK; } /* end if */ @@ -359,7 +397,7 @@ t_stat r; char gbuf[CBUFSIZE]; cptr = get_glyph (cptr, gbuf, ','); /* get next field */ -d = get_uint (gbuf, 8, AMASK, &r); /* construe as addr */ +d = get_uint (gbuf, 8, VAMASK, &r); /* construe as addr */ if (r != SCPE_OK) return -1; if (*cptr != 0) { /* more? */ cptr = get_glyph (cptr, gbuf, 0); /* look for indirect */ @@ -410,7 +448,7 @@ if (opcode[i]) { /* found opcode? */ switch (j) { /* case on class */ case I_V_NPN: /* no operand */ break; - case I_V_NPNC: /* no operand + C */ + case I_V_NPC: /* no operand + C */ if (*cptr != 0) { cptr = get_glyph (cptr, gbuf, 0); if (strcmp (gbuf, "C")) return SCPE_ARG; @@ -424,24 +462,24 @@ if (opcode[i]) { /* found opcode? */ else if (k = (strcmp (gbuf, "Z") == 0)) { /* Z specified? */ cptr = get_glyph (cptr, gbuf, ','); } if ((d = get_addr (gbuf)) < 0) return SCPE_ARG; - if ((d & AMASK) <= DISP) val[0] = val[0] | d; + if ((d & VAMASK) <= DISP) val[0] = val[0] | d; else if (cflag && !k && (((addr ^ d) & PAGENO) == 0)) val[0] = val[0] | (d & (IA | DISP)) | CP; else return SCPE_ARG; break; - case I_V_ESHF: /* extended shift */ + case I_V_ESH: /* extended shift */ cptr = get_glyph (cptr, gbuf, 0); d = get_uint (gbuf, 10, 16, &r); if ((r != SCPE_OK) || (d == 0)) return SCPE_ARG; val[0] = val[0] | (d & 017); break; - case I_V_EMRF: /* extended mem ref */ + case I_V_EMR: /* extended mem ref */ cptr = get_glyph (cptr, gbuf, 0); /* get next field */ if ((d = get_addr (gbuf)) < 0) return SCPE_ARG; val[1] = d; ret = -1; break; - case I_V_IOT1: /* IOT + optional C */ + case I_V_IO1: /* IOT + optional C */ cptr = get_glyph (cptr, gbuf, ','); /* get device */ d = get_uint (gbuf, 8, DEVMASK, &r); if (r != SCPE_OK) return SCPE_ARG; @@ -451,13 +489,13 @@ if (opcode[i]) { /* found opcode? */ if (strcmp (gbuf, "C")) return SCPE_ARG; val[0] = val[0] | HC; } break; - case I_V_IOT2: /* IOT */ + case I_V_IO2: /* IOT */ cptr = get_glyph (cptr, gbuf, 0); /* get device */ d = get_uint (gbuf, 8, DEVMASK, &r); if (r != SCPE_OK) return SCPE_ARG; val[0] = val[0] | d; break; - case I_V_EG1Z: /* ext grp 1 op + 0 */ + case I_V_EGZ: /* ext grp 1 op + 0 */ cptr = get_glyph (cptr, gbuf, 0); /* get next field */ if ((d = get_addr (gbuf)) < 0) return SCPE_ARG; val[1] = d; @@ -523,7 +561,7 @@ for (cptr = get_glyph (iptr, gbuf, ','); gbuf[0] != 0; val[0] = val[0] | vtab[i]; } /* fill value */ if (clef) { /* CLE seen? */ if (val[0] & ASKP) { /* alter-skip? */ - if (val[0] & 0300) return SCPE_ARG; /* already filled in? */ + if (tbits & 0100) return SCPE_ARG; /* already filled in? */ else val[0] = val[0] | 0100; } else val[0] = val[0] | 040; } /* fill in shift */ return ret; diff --git a/I1401/i1401_cd.c b/I1401/i1401_cd.c index 2f9fa7b7..7501859d 100644 --- a/I1401/i1401_cd.c +++ b/I1401/i1401_cd.c @@ -1,6 +1,6 @@ /* i1401_cd.c: IBM 1402 card reader/punch - Copyright (c) 1993-2001, Robert M. Supnik + Copyright (c) 1993-2002, Robert M. Supnik Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), @@ -35,6 +35,8 @@ Cards are represented as ASCII text streams terminated by newlines. This allows cards to be created and edited as normal files. + 30-May-02 RMS Widened POS to 32b + 30-Jan-02 RMS New zero footprint card bootstrap from Van Snyder 29-Nov-01 RMS Added read only unit support 13-Apr-01 RMS Revised for register arrays */ @@ -68,7 +70,7 @@ REG cdr_reg[] = { { FLDATA (ERR, ind[IN_READ], 0) }, { FLDATA (S1, s1sel, 0) }, { FLDATA (S2, s2sel, 0) }, - { DRDATA (POS, cdr_unit.pos, 31), PV_LEFT }, + { DRDATA (POS, cdr_unit.pos, 32), PV_LEFT }, { DRDATA (TIME, cdr_unit.wait, 24), PV_LEFT }, { BRDATA (BUF, rbuf, 8, 8, CDR_WIDTH) }, { NULL } }; @@ -93,7 +95,7 @@ REG cdp_reg[] = { { FLDATA (ERR, ind[IN_PNCH], 0) }, { FLDATA (S4, s4sel, 0) }, { FLDATA (S8, s8sel, 0) }, - { DRDATA (POS, cdp_unit.pos, 31), PV_LEFT }, + { DRDATA (POS, cdp_unit.pos, 32), PV_LEFT }, { NULL } }; DEVICE cdp_dev = { @@ -117,10 +119,10 @@ UNIT stack_unit[] = { { UDATA (NULL, UNIT_SEQ+UNIT_ATTABLE, 0) } }; REG stack_reg[] = { - { DRDATA (POS0, stack_unit[0].pos, 31), PV_LEFT }, - { DRDATA (POS1, stack_unit[1].pos, 31), PV_LEFT }, - { DRDATA (POS28, stack_unit[2].pos, 31), PV_LEFT }, - { DRDATA (POS4, stack_unit[4].pos, 31), PV_LEFT }, + { DRDATA (POS0, stack_unit[0].pos, 32), PV_LEFT }, + { DRDATA (POS1, stack_unit[1].pos, 32), PV_LEFT }, + { DRDATA (POS28, stack_unit[2].pos, 32), PV_LEFT }, + { DRDATA (POS4, stack_unit[4].pos, 32), PV_LEFT }, { NULL } }; DEVICE stack_dev = { @@ -261,14 +263,11 @@ return attach_unit (uptr, cptr); /* Bootstrap routine */ -#define BOOT_START 100 +#define BOOT_START 0 #define BOOT_LEN (sizeof (boot_rom) / sizeof (unsigned char)) static const unsigned char boot_rom[] = { - OP_R + WM, /* R */ - OP_SWM + WM, BCD_ZERO, BCD_ZERO, BCD_ONE, /* SWM 001 */ - OP_CS + WM, BCD_ZERO, BCD_ZERO, BCD_ONE, /* CS 001 111 */ - BCD_ONE, BCD_ONE, BCD_ONE }; + OP_R + WM, OP_NOP + WM }; /* R, NOP */ t_stat cdr_boot (int32 unitno) { diff --git a/I1401/i1401_cpu.c b/I1401/i1401_cpu.c index 67790d4c..5c95ca37 100644 --- a/I1401/i1401_cpu.c +++ b/I1401/i1401_cpu.c @@ -1,6 +1,6 @@ /* i1401_cpu.c: IBM 1401 CPU simulator - Copyright (c) 1993-2001, Robert M. Supnik + Copyright (c) 1993-2002, Robert M. Supnik Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), @@ -23,6 +23,9 @@ be used in advertising or otherwise to promote the sale, use or other dealings in this Software without prior written authorization from Robert M Supnik. + 03-Jun-03 RMS Added 1311 support + 22-May-02 RMS Added multiply and divide + 30-Dec-01 RMS Added old PC queue 30-Nov-01 RMS Added extended SET/SHOW support 10-Aug-01 RMS Removed register in declarations 07-Dec-00 RMS Fixed bugs found by Charles Owen @@ -106,22 +109,33 @@ #include "i1401_defs.h" +#define PCQ_SIZE 64 /* must be 2**n */ +#define PCQ_MASK (PCQ_SIZE - 1) +#define PCQ_ENTRY pcq[pcq_p = (pcq_p - 1) & PCQ_MASK] = saved_IS + +/* These macros validate addresses. If an addresses error is detected, + they return an error status to the caller. These macros should only + be used in a routine that returns a t_stat value. +*/ + #define MM(x) x = x - 1; \ if (x < 0) { \ x = BA + MAXMEMSIZE - 1; \ reason = STOP_WRAP; \ - break; } + break; } + #define PP(x) x = x + 1; \ if (ADDR_ERR (x)) { \ x = BA + (x % MAXMEMSIZE); \ reason = STOP_WRAP; \ break; } + #define BRANCH if (ADDR_ERR (AS)) { \ reason = STOP_INVBR; \ break; } \ if (cpu_unit.flags & XSA) BS = IS; \ else BS = BA + 0; \ - oldIS = saved_IS; \ + PCQ_ENTRY; \ IS = AS; uint8 M[MAXMEMSIZE] = { 0 }; /* main memory */ @@ -129,7 +143,9 @@ int32 saved_IS = 0; /* saved IS */ int32 AS = 0; /* AS */ int32 BS = 0; /* BS */ int32 as_err = 0, bs_err = 0; /* error flags */ -int32 oldIS = 0; /* previous IS */ +uint16 pcq[PCQ_SIZE] = { 0 }; /* PC queue */ +int32 pcq_p = 0; /* PC queue ptr */ +REG *pcq_r = NULL; /* PC queue reg ptr */ int32 ind[64] = { 0 }; /* indicators */ int32 ssa = 1; /* sense switch A */ int32 prchk = 0; /* process check stop */ @@ -144,6 +160,9 @@ t_stat cpu_set_size (UNIT *uptr, int32 val, char *cptr, void *desc); int32 store_addr_h (int32 addr); int32 store_addr_t (int32 addr); int32 store_addr_u (int32 addr); +int32 div_add (int32 ap, int32 bp, int32 aend); +int32 div_sub (int32 ap, int32 bp, int32 aend); +void div_sign (int32 dvrc, int32 dvdc, int32 qp, int32 rp); t_stat iomod (int32 ilnt, int32 mod, const int32 *tptr); t_stat iodisp (int32 dev, int32 unit, int32 flag, int32 mod); @@ -154,6 +173,7 @@ extern t_stat carriage_control (int32 mod); extern t_stat write_line (int32 ilnt, int32 mod); extern t_stat inq_io (int32 flag, int32 mod); extern t_stat mt_io (int32 unit, int32 flag, int32 mod); +extern t_stat dp_io (int32 fnc, int32 flag, int32 mod); extern t_stat mt_func (int32 unit, int32 mod); extern t_stat sim_activate (UNIT *uptr, int32 delay); @@ -188,7 +208,8 @@ REG cpu_reg[] = { { FLDATA (OVF, ind[IN_OVF], 0) }, { FLDATA (IOCHK, iochk, 0) }, { FLDATA (PRCHK, prchk, 0) }, - { DRDATA (OLDIS, oldIS, 14), REG_RO + PV_LEFT }, + { BRDATA (ISQ, pcq, 10, 14, PCQ_SIZE), REG_RO+REG_CIRC }, + { ORDATA (ISQP, pcq_p, 6), REG_HRO }, { ORDATA (WRU, sim_int_char, 8) }, { NULL } }; @@ -205,6 +226,8 @@ MTAB cpu_mod[] = { { MR, 0, "no MR", "NOMR", NULL }, { EPE, EPE, "EPE", "EPE", NULL }, { EPE, 0, "no EPE", "NOEPE", NULL }, + { MDV, MDV, "MDV", "MDV", NULL }, + { MDV, 0, "no MDV", "NOMDV", NULL }, { UNIT_MSIZE, 4000, NULL, "4K", &cpu_set_size }, { UNIT_MSIZE, 8000, NULL, "8K", &cpu_set_size }, { UNIT_MSIZE, 12000, NULL, "12K", &cpu_set_size }, @@ -217,6 +240,8 @@ DEVICE cpu_dev = { &cpu_ex, &cpu_dep, &cpu_reset, NULL, NULL, NULL }; +/* Tables */ + /* Opcode table - length, dispatch, and option flags. This table is also used by the symbolic input routine to validate instruction lengths */ @@ -321,10 +346,10 @@ const int32 one_table[64] = { BA+12000, 12001, 12002, 12003, 12004, 12005, 12006, 12007, 12008, 12009, 12000, BA+12003, BA+12004, BA+12005, BA+12006, BA+12007 }; -static const int32 bin_to_bcd[16] = { +const int32 bin_to_bcd[16] = { 10, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 }; -static const int32 bcd_to_bin[16] = { +const int32 bcd_to_bin[16] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 3, 4, 5, 6, 7 }; /* ASCII to BCD conversion */ @@ -358,15 +383,6 @@ char bcd_to_ascii[64] = { 'Q', 'R', '!', '$', '*', ']', ';', '_', '&', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', '?', '.', ')', '[', '<', '"' }; - -t_stat sim_instr (void) -{ -extern int32 sim_interval; -int32 IS, D, ilnt, flags; -int32 op, xa, t, wm, dev, unit; -int32 a, b, i, bsave, carry; -int32 qzero, qawm, qbody, qsign, qdollar, qaster, qdecimal; -t_stat reason, r1, r2; /* Indicator resets - a 1 marks an indicator that resets when tested */ @@ -392,24 +408,71 @@ static const int32 col_table[64] = { 006, 032, 033, 034, 035, 036, 037, 040, 041, 042, 031, 001, 002, 003, 004, 005 }; -/* Summing table for two decimal digits, converted back to BCD */ +/* Summing table for two decimal digits, converted back to BCD + Also used for multiplying two decimal digits, converted back to BCD, + with carry forward +*/ -static const int32 sum_table[20] = { - 10, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 1, 2, 3, 4, 5, 6, 7, 8, 9 }; +static const int32 sum_table[100] = { + BCD_ZERO, BCD_ONE, BCD_TWO, BCD_THREE, BCD_FOUR, + BCD_FIVE, BCD_SIX, BCD_SEVEN, BCD_EIGHT, BCD_NINE, + BCD_ZERO, BCD_ONE, BCD_TWO, BCD_THREE, BCD_FOUR, + BCD_FIVE, BCD_SIX, BCD_SEVEN, BCD_EIGHT, BCD_NINE, + BCD_ZERO, BCD_ONE, BCD_TWO, BCD_THREE, BCD_FOUR, + BCD_FIVE, BCD_SIX, BCD_SEVEN, BCD_EIGHT, BCD_NINE, + BCD_ZERO, BCD_ONE, BCD_TWO, BCD_THREE, BCD_FOUR, + BCD_FIVE, BCD_SIX, BCD_SEVEN, BCD_EIGHT, BCD_NINE, + BCD_ZERO, BCD_ONE, BCD_TWO, BCD_THREE, BCD_FOUR, + BCD_FIVE, BCD_SIX, BCD_SEVEN, BCD_EIGHT, BCD_NINE, + BCD_ZERO, BCD_ONE, BCD_TWO, BCD_THREE, BCD_FOUR, + BCD_FIVE, BCD_SIX, BCD_SEVEN, BCD_EIGHT, BCD_NINE, + BCD_ZERO, BCD_ONE, BCD_TWO, BCD_THREE, BCD_FOUR, + BCD_FIVE, BCD_SIX, BCD_SEVEN, BCD_EIGHT, BCD_NINE, + BCD_ZERO, BCD_ONE, BCD_TWO, BCD_THREE, BCD_FOUR, + BCD_FIVE, BCD_SIX, BCD_SEVEN, BCD_EIGHT, BCD_NINE, + BCD_ZERO, BCD_ONE, BCD_TWO, BCD_THREE, BCD_FOUR, + BCD_FIVE, BCD_SIX, BCD_SEVEN, BCD_EIGHT, BCD_NINE, + BCD_ZERO, BCD_ONE, BCD_TWO, BCD_THREE, BCD_FOUR, + BCD_FIVE, BCD_SIX, BCD_SEVEN, BCD_EIGHT, BCD_NINE }; + +static const int32 cry_table[100] = { + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9 }; /* Legal modifier tables */ static const int32 w_mod[] = { BCD_S, BCD_SQUARE, -1 }; static const int32 ss_mod[] = { 1, 2, 4, 8, -1 }; static const int32 mtf_mod[] = { BCD_B, BCD_E, BCD_M, BCD_R, BCD_U, -1 }; - +t_stat sim_instr (void) +{ +extern int32 sim_interval; +int32 IS, D, ilnt, flags; +int32 op, xa, t, wm, dev, unit; +int32 a, b, i, asave, bsave; +int32 carry, lowprd, sign, ps; +int32 quo, ahigh, qs; +int32 qzero, qawm, qbody, qsign, qdollar, qaster, qdecimal; +t_stat reason, r1, r2; + /* Restore saved state */ IS = saved_IS; +if (as_err) AS = AS | BA; /* flag bad addresses */ +if (bs_err) BS = BS | BA; +as_err = bs_err = 0; /* reset error flags */ D = 0; reason = 0; - + /* Main instruction fetch/decode loop */ while (reason == 0) { /* loop until halted */ @@ -551,6 +614,7 @@ case OP_MSZ: /* move suppress zero */ wm = M[AS]; MM (AS); MM (BS); } /* decr pointers */ while ((wm & WM) == 0); /* stop on A WM */ + if (reason) break; /* addr err? stop */ do { PP (BS); /* adv B */ t = M[BS]; /* get B, cant be WM */ if ((t == BCD_ZERO) || (t == BCD_COMMA)) { @@ -681,6 +745,7 @@ case OP_A: case OP_S: /* add/sub */ else M[BS] = (b & WM) + sum_table[t]; /* normal add */ MM (BS); } while ((b & WM) == 0); /* stop on B WM */ + if (reason) break; /* address err? */ if (qsign && (carry == 0)) { /* recompl, no carry? */ M[bsave] = M[bsave] ^ ABIT; /* XOR sign */ for (carry = 1; bsave != BS; --bsave) { /* rescan */ @@ -863,6 +928,7 @@ case OP_MCE: /* edit */ MM (BS); } /* decr B pointer */ while ((b & WM) == 0); /* stop on B WM */ + if (reason) break; /* address err? */ if (!qawm || !qzero) { /* rescan? */ if (qdollar) reason = STOP_MCE3; /* error if $ */ break; } @@ -913,6 +979,141 @@ case OP_MCE: /* edit */ BS--; } /* end for */ break; /* done at last! */ +/* Multiply. Comments from the PDP-10 based simulator by Len Fehskens. + + Multiply, with variable length operands, is necessarily done the same + way you do it with paper and pencil, except that partial products are + added into the incomplete final product as they are computed, rather + than at the end. The 1401 multiplier format allows the product to + be developed in place, without scratch storage. + + The A field contains the multiplicand, length LD. The B field must be + LD + 1 + length of multiplier. Locate the low order multiplier digit, + and at the same time zero out the product field. Then compute the sign + of the result. +*/ + +case OP_MUL: + asave = AS; bsave = lowprd = BS; /* save AS, BS */ + do { a = M[AS]; /* get mpcd char */ + M[BS] = BCD_ZERO; /* zero prod */ + MM (AS); MM (BS); } /* decr pointers */ + while ((a & WM) == 0); /* until A WM */ + if (reason) break; /* address err? */ + M[BS] = BCD_ZERO; /* zero hi prod */ + MM (BS); /* addr low mpyr */ + sign = ((M[asave] & ZONE) == BBIT) ^ ((M[BS] & ZONE) == BBIT); + +/* Outer loop on multiplier (BS) and product digits (ps), + inner loop on multiplicand digits (AS). + AS and ps cannot produce an address error. +*/ + + do { ps = bsave; /* ptr to prod */ + AS = asave; /* ptr to mpcd */ + carry = 0; /* init carry */ + b = M[BS]; /* get mpyr char */ + do { a = M[AS]; /* get mpcd char */ + t = (bcd_to_bin[a & DIGIT] * /* mpyr * mpcd */ + bcd_to_bin[b & DIGIT]) + /* + c + partial prod */ + carry + bcd_to_bin[M[ps] & DIGIT]; + carry = cry_table[t]; + M[ps] = (M[ps] & WM) | sum_table[t]; + MM (AS); ps--; } + while ((a & WM) == 0); /* until mpcd done */ + M[BS] = (M[BS] & WM) | BCD_ZERO; /* zero mpyr just used */ + t = bcd_to_bin[M[ps] & DIGIT] + carry; /* add carry to prod */ + M[ps] = (M[ps] & WM) | sum_table[t]; /* store */ + bsave--; /* adv prod ptr */ + MM (BS); } /* adv mpyr ptr */ + while ((b & WM) == 0); /* until mpyr done */ + M[lowprd] = M[lowprd] | ZONE; /* assume + */ + if (sign) M[lowprd] = M[lowprd] & ~ABIT; /* if minus, B only */ + break; + +/* Divide. Comments from the PDP-10 based simulator by Len Fehskens. + + Divide is done, like multiply, pretty muchy the same way you do it with + pencil and paper; successive subtraction of the divisor from a substring + of the dividend while counting up the corresponding quotient digit. + + Let LS be the length of the divisor, LD the length of the dividend: + - AS points to the low order divisor digit. + - BS points to the high order dividend digit. + - The low order dividend digit is identified by sign (zone) bits. + - To the left of the dividend is a zero field of length LS + 1. + The low quotient is at low dividend - LS - 1. As BS points to the + high dividend, the low dividend is at BS + LD - 1, so the low + quotient is at BS + LD - LS - 2. The longest possible quotient is + LD - LS + 1, so the first possible non-zero quotient bit will be + found as BS - 2. + + This pointer calculation assumes that the divisor has no leading zeroes. + For each leading zero, the start of the quotient will be one position + further left. + + Start by locating the high order non-zero digit of the divisor. This + also tests for a divide by zero. +*/ + +case OP_DIV: + asave = AS; ahigh = -1; + do { a = M[AS]; /* get dvr char */ + if ((a & CHAR) != BCD_ZERO) ahigh = AS; /* mark non-zero */ + MM (AS); } + while ((a & WM) == 0); + if (reason) break; /* address err? */ + if (ahigh < 0) { /* div? by zero */ + ind[IN_OVF] = 1; /* set ovf indic */ + qs = bsave = BS; /* quo, dividend */ + do { b = M[bsave]; /* find end divd */ + PP (bsave); } /* marked by zone */ + while ((b & ZONE) == 0); + if (reason) break; /* address err? */ + if (ADDR_ERR (qs)) { /* address err? */ + reason = STOP_WRAP; /* address wrap? */ + break; } + div_sign (M[asave], b, qs - 1, bsave - 1); /* set signs */ + BS = (BS - 2) - (asave - (AS + 1)); /* final bs */ + break; } + bsave = BS + (asave - ahigh); /* end subdivd */ + qs = (BS - 2) - (ahigh - (AS + 1)); /* quo start */ + +/* Divide loop - done with subroutines to keep the code clean. + In the loop, + + asave = low order divisor + bsave = low order subdividend + qs = current quotient digit +*/ + + do { quo = 0; /* clear quo digit */ + if (ADDR_ERR (qs) || ADDR_ERR (bsave)) { + reason = STOP_WRAP; /* address wrap? */ + break; } + b = M[bsave]; /* save low divd */ + do { t = div_sub (asave, bsave, ahigh); /* subtract */ + quo++; } /* incr quo digit */ + while (t == 0); /* until borrow */ + div_add (asave, bsave, ahigh); quo--; /* restore */ + M[qs] = (M[qs] & WM) | sum_table[quo]; /* store quo digit */ + bsave++; qs++; } /* adv divd, quo */ + while ((b & ZONE) == 0); /* until B sign */ + if (reason) break; /* address err? */ + +/* At this point, + + AS = high order divisor - 1 + asave = unit position of divisor + b = unit character of dividend + bsave = unit position of remainder + 1 + qs = unit position of quotient + 1 +*/ + + div_sign (M[asave], b, qs - 1, bsave - 1); /* set signs */ + BS = qs - 2; /* BS = quo 10's pos */ + break; + /* Miscellaneous instructions A check B check SWM: set WM on A char and B char fetch fetch @@ -970,14 +1171,17 @@ default: reason = STOP_NXI; /* unimplemented */ break; } /* end switch */ } /* end while */ - + /* Simulation halted */ -as_err = (AS > ADDRMASK); -bs_err = (BS > ADDRMASK); +as_err = ADDR_ERR (AS); /* get addr err flags */ +bs_err = ADDR_ERR (BS); +AS = AS & ADDRMASK; /* clean addresses */ +BS = BS & ADDRMASK; +pcq_r -> qptr = pcq_p; /* update pc q ptr */ return reason; } /* end sim_instr */ - + /* store addr_x - convert address to BCD character in x position Inputs: @@ -1006,6 +1210,59 @@ int32 thous; thous = (addr / 1000) & 014; return bin_to_bcd[addr % 10] | (thous << (V_ZONE - 2)); } + +/* div_add - add string for divide */ + +int32 div_add (int32 ap, int32 bp, int32 aend) +{ +int32 a, b, c, r; + +c = 0; /* init carry */ +do { a = M[ap]; b = M[bp]; /* get operands */ + r = bcd_to_bin[b & DIGIT] + /* sum digits + c */ + bcd_to_bin[a & DIGIT] + c; + c = (r >= 10); /* set carry out */ + M[bp] = sum_table[r]; /* store result */ + ap--; bp--; } +while (ap >= aend); +return c; +} + +/* div_sub - substract string for divide */ + +int32 div_sub (int32 ap, int32 bp, int32 aend) +{ +int32 a, b, c, r; + +c = 0; /* init borrow */ +do { a = M[ap]; b = M[bp]; /* get operands */ + r = bcd_to_bin[b & DIGIT] - /* a - b - borrow */ + bcd_to_bin[a & DIGIT] - c; + c = (r < 0); /* set borrow out */ + M[bp] = sum_table[r + 10]; /* store result */ + ap--; bp--; } +while (ap >= aend); +b = M[bp] & CHAR; /* borrow position */ +if (b != BCD_ZERO) { /* non-zero? */ + r = bcd_to_bin[b & DIGIT] - c; /* subtract borrow */ + M[bp] = sum_table[r]; /* store result */ + return 0; } /* subtract worked */ +return c; /* return borrow */ +} + +/* div_sign - set signs for divide */ + +void div_sign (int32 dvrc, int32 dvdc, int32 qp, int32 rp) +{ +int32 sign = dvrc & ZONE; /* divisor sign */ + +M[rp] = M[rp] | ZONE; /* assume rem pos */ +if (sign == BBIT) M[rp] = M[rp] & ~ABIT; /* if dvr -, rem - */ +M[qp] = M[qp] | ZONE; /* assume quo + */ +if (((dvdc & ZONE) == BBIT) ^ (sign == BBIT)) /* dvr,dvd diff? */ + M[qp] = M[qp] & ~ABIT; /* make quo - */ +return; +} /* iomod - check on I/O modifiers @@ -1038,6 +1295,7 @@ return STOP_INVM; t_stat iodisp (int32 dev, int32 unit, int32 flag, int32 mod) { if (dev == IO_INQ) return inq_io (flag, mod); /* inq terminal? */ +if (dev == IO_DP) return dp_io (unit, flag, mod); /* disk pack? */ if (dev == IO_MT) return mt_io (unit, flag, mod); /* magtape? */ if (dev == IO_MTB) { /* binary? */ if (flag == MD_WM) return STOP_INVM; /* invalid */ @@ -1055,6 +1313,9 @@ for (i = 0; i < 64; i++) ind[i] = 0; ind[IN_UNC] = 1; AS = 0; as_err = 1; BS = 0; bs_err = 1; +pcq_r = find_reg ("ISQ", NULL, dptr); +if (pcq_r) pcq_r -> qptr = 0; +else return SCPE_IERR; sim_brk_types = sim_brk_dflt = SWMASK ('E'); return SCPE_OK; } diff --git a/I1401/i1401_dat.h b/I1401/i1401_dat.h new file mode 100644 index 00000000..4de65ee1 --- /dev/null +++ b/I1401/i1401_dat.h @@ -0,0 +1,32 @@ + +/* ASCII to BCD conversion */ + +const char ascii_to_bcd[128] = { + 000, 000, 000, 000, 000, 000, 000, 000, /* 000 - 037 */ + 000, 000, 000, 000, 000, 000, 000, 000, + 000, 000, 000, 000, 000, 000, 000, 000, + 000, 000, 000, 000, 000, 000, 000, 000, + 000, 052, 077, 013, 053, 034, 060, 032, /* 040 - 077 */ + 017, 074, 054, 037, 033, 040, 073, 021, + 012, 001, 002, 003, 004, 005, 006, 007, + 010, 011, 015, 056, 076, 035, 016, 072, + 014, 061, 062, 063, 064, 065, 066, 067, /* 100 - 137 */ + 070, 071, 041, 042, 043, 044, 045, 046, + 047, 050, 051, 022, 023, 024, 025, 026, + 027, 030, 031, 075, 036, 055, 020, 057, + 000, 061, 062, 063, 064, 065, 066, 067, /* 140 - 177 */ + 070, 071, 041, 042, 043, 044, 045, 046, + 047, 050, 051, 022, 023, 024, 025, 026, + 027, 030, 031, 000, 000, 000, 000, 000 }; + +/* BCD to ASCII conversion - also the "full" print chain */ + +char bcd_to_ascii[64] = { + ' ', '1', '2', '3', '4', '5', '6', '7', + '8', '9', '0', '#', '@', ':', '>', '(', + '^', '/', 'S', 'T', 'U', 'V', 'W', 'X', + 'Y', 'Z', '\'', ',', '%', '=', '\\', '+', + '-', 'J', 'K', 'L', 'M', 'N', 'O', 'P', + 'Q', 'R', '!', '$', '*', ']', ';', '_', + '&', 'A', 'B', 'C', 'D', 'E', 'F', 'G', + 'H', 'I', '?', '.', ')', '[', '<', '"' }; diff --git a/I1401/i1401_defs.h b/I1401/i1401_defs.h index d3c68c41..5480d674 100644 --- a/I1401/i1401_defs.h +++ b/I1401/i1401_defs.h @@ -1,6 +1,6 @@ /* i1401_defs.h: IBM 1401 simulator definitions - Copyright (c) 1993-2001, Robert M. Supnik + Copyright (c) 1993-2002, Robert M. Supnik Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), @@ -23,6 +23,7 @@ be used in advertising or otherwise to promote the sale, use or other dealings in this Software without prior written authorization from Robert M Supnik. + 03-Jun-03 RMS Added 1311 support 14-Apr-99 RMS Converted t_addr to unsigned This simulator is based on the 1401 simulator written by Len Fehskens @@ -56,6 +57,15 @@ #define STOP_MCE2 19 /* MCE short B field */ #define STOP_MCE3 20 /* MCE hanging $ */ #define STOP_IOC 21 /* I/O check */ +#define STOP_INVDSC 22 /* invalid disk sector */ +#define STOP_INVDCN 23 /* invalid disk count */ +#define STOP_INVDSK 24 /* invalid disk unit */ +#define STOP_INVDFN 25 /* invalid disk func */ +#define STOP_INVDLN 26 /* invalid disk reclen */ +#define STOP_WRADIS 27 /* write address dis */ +#define STOP_WRCHKE 28 /* write check error */ +#define STOP_INVDAD 39 /* invalid disk addr */ +#define STOP_INVDCY 30 /* invalid direct seek */ /* Memory and devices */ @@ -111,7 +121,7 @@ #define HLE (1 << (UNIT_V_UF + 6)) /* high/low/equal */ #define UNIT_MSIZE (1 << (UNIT_V_UF + 7)) /* fake flag */ #define ALLOPT (MDV + MR + XSA + EPE + MA + BBE + HLE) -#define STDOPT (MR + XSA + EPE + MA + BBE + HLE) +#define STDOPT (MDV + MR + XSA + EPE + MA + BBE + HLE) /* Fetch control */ @@ -238,13 +248,14 @@ #define IN_EQU 022 /* equal */ #define IN_LOW 023 /* low */ #define IN_HGH 024 /* high */ -#define IN_PAR 025 /* parity check */ +#define IN_DPW 025 /* parity/compare check */ #define IN_LNG 026 /* wrong lnt record */ #define IN_UNA 027 /* unequal addr cmp */ #define IN_DSK 030 /* disk error */ #define IN_OVF 031 /* overflow */ #define IN_LPT 032 /* printer error */ #define IN_PRO 034 /* process check */ +#define IN_DBY 036 /* disk busy */ #define IN_END 042 /* end indicator */ #define IN_TAP 043 /* tape error */ #define IN_ACC 045 /* access error */ @@ -261,3 +272,5 @@ #define IN_SSF 066 /* sense switch F */ #define IN_SSG 067 /* sense switch G */ #define IN_READ 072 /* reader error */ + +#define CRETIOE(f,c) return ((f)? (c): SCPE_OK) \ No newline at end of file diff --git a/I1401/i1401_doc.txt b/I1401/i1401_doc.txt index be770b95..f3100532 100644 --- a/I1401/i1401_doc.txt +++ b/I1401/i1401_doc.txt @@ -1,14 +1,14 @@ To: Users From: Bob Supnik Subj: IBM 1401 Simulator Usage -Date: 1-Dec-01 +Date: 15-Jun-2002 COPYRIGHT NOTICE The following copyright notice applies to both the SIMH source and binary: - Original code published in 1993-2001, written by Robert M Supnik - Copyright (c) 1993-2001, Robert M Supnik + Original code published in 1993-2002, written by Robert M Supnik + Copyright (c) 1993-2002, Robert M Supnik Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), @@ -43,8 +43,10 @@ sim/ sim_defs.h sim/i1401/ i1401_defs.h i1401_cpu.c + i1401_cd.c i1401_iq.c i1401_lp.c + i1401_dp.c i1401_mt.c i1401_sys.c @@ -59,6 +61,7 @@ CPU IBM 1401 CPU with 16K of memory CDR,CDP IBM 1402 card reader/punch LPT IBM 1403 line printer INQ IBM 1407 inquiry terminal +DP IBM 1311 disk pack with five drives MT IBM 729 7-track magnetic tape controller with six drives The IBM 1401 simulator implements many unique stop conditions. On almost @@ -83,8 +86,13 @@ any kind of error the simulator stops: single character B field in MCE hanging $ in MCE with EPE enabled I/O check with I/O stop switch set + invalid disk drive + invalid disk sector address + invalid disk sector count + invalid disk address compare -The LOAD and DUMP commands are not implemented. +The LOAD command is used to load a line printer carriage-control tape. +The DUMP command is not implemented. 2.1 CPU @@ -102,6 +110,8 @@ when memory size is greater than 4K. SET CPU NOMR disable move record SET CPU EPE enable extended print edit special feature SET CPU NOEPE disable extended print edit + SET CPU MDV enable multiply/divide special feature + SET CPU NOMDV disable multiply/divide SET CPU 4K set memory size = 4K SET CPU 8K set memory size = 8K SET CPU 12K set memory size = 12K @@ -147,7 +157,8 @@ interrupt system. OVF 1 overflow indicator IOCHK 1 I/O check switch PRCHK 1 process check switch - OLDIS 1 IS prior to last branch + ISQ 1 IS prior to last branch; + most recent IS change first WRU 8 interrupt character 2.2 1402 Card Reader/Punch (CDR, CDP, STKR) @@ -177,7 +188,7 @@ The reader/punch registers are: ERR 1 error indicator S1 1 stacker 1 select flag S2 1 stacker 2 select flag - POS 31 position + POS 32 position TIME 24 delay window for stacker select BUF[0:79] 8 reader buffer @@ -185,10 +196,10 @@ The reader/punch registers are: S4 1 stacker 4 select flag S8 1 stacker 8 select flag - STKR POS0 31 position, normal reader stack - POS1 31 position, reader stacker 1 - POS2 31 position, shared stacker 2/8 - POS4 31 position, punch stacker 4 + STKR POS0 32 position, normal reader stack + POS1 32 position, reader stacker 1 + POS2 32 position, shared stacker 2/8 + POS4 32 position, punch stacker 4 Error handling is as follows: @@ -245,7 +256,7 @@ The line printer registers are: CCTP 8 carriage control tape pointer CCTL 8 carriage control tape length (read only) ERR 1 error indicator - POS 31 position + POS 32 position CCT[0:131] 32 carriage control tape array Error handling is as follows: @@ -278,18 +289,68 @@ character is typed in. The latter cancels the type-in and sets INC. The inquiry terminal has no errors. -2.5 729 Magnetic Tape (MT) +2.5 1311 Disk Pack (DP) + +The disk pack controller supports 5 drives, numbered 0 through 4. Disk +pack options include the ability to enable address writing (formatting). + + SET DPn ADDROFF set unit n address enable off + SET DPn ADDRON set unit n address enable on + +Units can also be set ONLINE or OFFLINE. Disk data is buffered in +memory; IO errors cannot occur. + +Unlike most simulated disks, the 1311 includes explicit representation +for sector addresses. This is to support non-standard formats, such as +the inclusion of the drive number in the sector address. As a result, +1311 sectors are 106 characters long: 6 address characters and 100 +data characters. If the 1311 has not been formatted, the addresses +are blanks and are synthesized, if needed, based on the sector number. + +The 1311 also supports two modes of operation: move mode and load mode. +In move mode, word marks are ignored on writes and left untouched on reads, +and sectors hold 100 characters. In load mode, word marks are included +on writes and stored on reads, and sectors hold 90 characters. No attempt +is made to deal with sectors written in load mode and read in move mode, +or vice versa; on a real 1401, this causes a fatal parity error. + +The disk pack controller implements these registers: + + name size comments + + ACC 1 access error indicator + PWC 1 parity or write check error indicator + WLR 1 wrong length record error indicator + UNA 1 unequal address compare error indicator + DSK 1 any disk error indicator + BSY 1 disk access busy indicator + LASTF 3 most recent function + TIME 24 seek time + +Error handling is as follows: + + error processed as + + not attached set DSK indicator + if IOCHK set, report error and stop + +The 1311 has a primative overlapped seek capability. If TIME is set +non-zero, the 1311 will report itself busy for the specified amount +of time following a seek. This allows programs to utilize the seek +time for processing. + +2.6 729 Magnetic Tape (MT) The magnetic tape controller supports six drives, numbered 1 through 6. Magnetic tape options include the ability to make units write enabled or or write locked. SET MTn LOCKED set unit n write locked - SET MTn ENABLED set unit n write enabled + SET MTn WRITEENABLED set unit n write enabled -Units can also be REMOVEd or ADDed to the configuration. The magnetic -tape simulator supports the BOOT command. BOOT MT reads the first -record off tape, starting at location 1, and then branches to it. +Units can also be set ONLINE or OFFLINE. The magnetic tape simulator +supports the BOOT command. BOOT MT reads the first record off tape, +starting at location 1, and then branches to it. The magnetic tape controller implements these registers: @@ -298,7 +359,7 @@ The magnetic tape controller implements these registers: END 1 end of file indicator ERR 1 error indicator PAR 1 parity error indicator - POS1..6 31 position, drives 1..6 + POS1..6 32 position, drives 1..6 Error handling is as follows: @@ -313,7 +374,7 @@ Error handling is as follows: if IOCHK set, report error and stop otherwise, set ERR indicator -2.6 Symbolic Display and Input +2.7 Symbolic Display and Input The IBM 1401 simulator implements symbolic display and input. Display is controlled by command line switches: @@ -324,6 +385,8 @@ controlled by command line switches: (CPU only) -m display instruction mnemonics (CPU only) + -d display 50 characters per line, with word + marks denoted by "1" on the line below In a CPU character display, word marks are denoted by ~. diff --git a/I1401/i1401_dp.c b/I1401/i1401_dp.c new file mode 100644 index 00000000..72270ef1 --- /dev/null +++ b/I1401/i1401_dp.c @@ -0,0 +1,554 @@ +/* i1401_dp.c: IBM 1311 disk simulator + + Copyright (c) 2002, Robert M. Supnik + + Permission is hereby granted, free of charge, to any person obtaining a + copy of this software and associated documentation files (the "Software"), + to deal in the Software without restriction, including without limitation + the rights to use, copy, modify, merge, publish, distribute, sublicense, + and/or sell copies of the Software, and to permit persons to whom the + Software is furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + ROBERT M SUPNIK BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + Except as contained in this notice, the name of Robert M Supnik shall not + be used in advertising or otherwise to promote the sale, use or other dealings + in this Software without prior written authorization from Robert M Supnik. + + dp 1311 disk pack + + 15-Jun-02 Reworked address comparison logic + + The 1311 disk pack has 100 cylinders, 10 tracks/cylinder, 20 sectors/track. + Each sector contains 106 characters of information: + + 6c sector address + 100c sector data + + By default, a sector's address field will be '000000', which is illegal. + This is interpreted to mean the implied sector number that would be in + place if the disk pack had been formatted with sequential sector numbers. + + The sector data can be 100 characters without word marks, or 90 characters + with word marks. Load mode transfers 90 characters per sector with + word marks, move mode transfers 100 characters per sector without word + marks. No attempt is made to catch incompatible writes (eg, load mode + write followed by move mode read). +*/ + +#include "i1401_defs.h" + +#define DP_NUMDR 5 /* #drives */ +#define UNIT_V_WAE (UNIT_V_UF + 0) /* write addr enab */ +#define UNIT_WAE (1 << UNIT_V_WAE) +#define UNIT_W_UF 2 /* #save flags */ + +/* Disk format */ + +#define DP_ADDR 6 /* address */ +#define DP_DATA 100 /* data */ +#define DP_NUMCH (DP_ADDR + DP_DATA) + +#define DP_NUMSC 20 /* #sectors */ +#define DP_NUMSF 10 /* #surfaces */ +#define DP_NUMCY 100 /* #cylinders */ +#define DP_TOTSC (DP_NUMCY*DP_NUMSF*DP_NUMSC) +#define DP_SIZE (DP_TOTSC*DP_NUMCH) + +/* Disk control field */ + +#define DCF_DRV 0 /* drive select */ +#define DCF_SEC 1 /* sector addr */ +#define DCF_SEC_LEN 6 +#define DCF_CNT (DCF_SEC + DCF_SEC_LEN) /* sector count */ +#define DCF_CNT_LEN 3 +#define DCF_LEN (DCF_CNT + DCF_CNT_LEN) +#define DCF_DIR 1 /* direct seek */ +#define DCF_DIR_LEN 4 +#define DCF_DIR_FL (DCF_DIR + DCF_DIR_LEN) /* direct seek flag */ +#define DCF_DSEEK 0xB + +/* Functions */ + +#define FNC_SEEK 0 /* seek */ +#define FNC_CHECK 3 /* check */ +#define FNC_READ 1 /* read sectors */ +#define FNC_RSCO 5 /* read sec cnt overlay */ +#define FNC_RTRK 6 /* read track */ +#define FNC_WOFF 10 /* offset for write */ +#define FNC_WRITE 11 /* write sectors */ +#define FNC_WRSCO 15 /* write sec cnt overlay */ +#define FNC_WRTRK 16 /* write track */ + +#define CYL u3 /* current cylinder */ + +extern uint8 M[]; /* memory */ +extern int32 ind[64]; +extern int32 AS, BS, iochk; +extern int32 bcd_to_bin[16]; +extern int32 bin_to_bcd[16]; +extern UNIT cpu_unit; + +int32 dp_lastf = 0; /* prior function */ +int32 dp_time = 0; /* seek time */ + +t_stat dp_reset (DEVICE *dptr); +t_stat dp_rdadr (UNIT *uptr, int32 sec, int32 flg, int32 wchk); +t_stat dp_rdsec (UNIT *uptr, int32 sec, int32 flg, int32 wchk); +t_stat dp_wradr (UNIT *uptr, int32 sec, int32 flg); +t_stat dp_wrsec (UNIT *uptr, int32 sec, int32 flg); +int32 dp_fndsec (UNIT *uptr, int32 sec, int32 dcf, int32 flg); +t_stat dp_nexsec (UNIT *uptr, int32 psec, int32 dcf, int32 flg); +t_bool dp_zeroad (uint8 *ap); +t_bool dp_cmp_ad (uint8 *ap, int32 dcf, int32 flg); +int32 dp_trkop (int32 drv, int32 sec); +int32 dp_cvt_bcd (int32 ad, int32 len); +void dp_cvt_bin (int32 ad, int32 len, int32 val, int32 flg); +int32 dp_get_cnt (int32 dcf); +void dp_fill (UNIT *uptr, uint32 da, int32 cnt); + +/* DP data structures + + dp_dev DSK device descriptor + dp_unit DSK unit list + dp_reg DSK register list + dp_mod DSK modifier list +*/ + +UNIT dp_unit[] = { + { UDATA (NULL, UNIT_FIX + UNIT_DISABLE + UNIT_ATTABLE + + UNIT_BUFABLE + UNIT_MUSTBUF + UNIT_BCD, DP_SIZE) }, + { UDATA (NULL, UNIT_FIX + UNIT_DISABLE + UNIT_ATTABLE + + UNIT_BUFABLE + UNIT_MUSTBUF + UNIT_BCD, DP_SIZE) }, + { UDATA (NULL, UNIT_FIX + UNIT_DISABLE + UNIT_ATTABLE + + UNIT_BUFABLE + UNIT_MUSTBUF + UNIT_BCD, DP_SIZE) }, + { UDATA (NULL, UNIT_FIX + UNIT_DISABLE + UNIT_ATTABLE + + UNIT_BUFABLE + UNIT_MUSTBUF + UNIT_BCD, DP_SIZE) }, + { UDATA (NULL, UNIT_FIX + UNIT_DISABLE + UNIT_ATTABLE + + UNIT_BUFABLE + UNIT_MUSTBUF + UNIT_BCD, DP_SIZE) } }; + +REG dp_reg[] = { + { FLDATA (ACC, ind[IN_ACC], 0) }, + { FLDATA (PWC, ind[IN_DPW], 0) }, + { FLDATA (WLR, ind[IN_LNG], 0) }, + { FLDATA (UNA, ind[IN_UNA], 0) }, + { FLDATA (ERR, ind[IN_DSK], 0) }, + { FLDATA (BSY, ind[IN_DBY], 0) }, + { DRDATA (LASTF, dp_lastf, 3) }, + { DRDATA (TIME, dp_time, 24), PV_LEFT }, + { URDATA (CYL, dp_unit[0].CYL, 10, 8, 0, + DP_NUMDR, PV_LEFT + REG_RO) }, + { URDATA (FLG, dp_unit[0].flags, 8, UNIT_W_UF, UNIT_V_UF - 1, + DP_NUMDR, REG_HRO) }, + { NULL } }; + +MTAB dp_mod[] = { + { UNIT_WAE, 0, "write address disabled", "ADDROFF", NULL }, + { UNIT_WAE, UNIT_WAE, "write address enabled", "ADDRON", NULL }, + { 0 } }; + +DEVICE dp_dev = { + "DP", dp_unit, dp_reg, dp_mod, + DP_NUMDR, 10, 21, 1, 8, 7, + NULL, NULL, &dp_reset, + NULL, NULL, NULL }; + +/* Disk IO routine + + Inputs: + fnc = function character + flg = load vs move mode + mod = modifier character + Outputs: + status = status +*/ + +t_stat dp_io (int32 fnc, int32 flg, int32 mod) +{ +int32 dcf, drv, sec, psec, cnt, qwc, qzr, diff; +UNIT *uptr; +t_stat r = SCPE_OK; + +dcf = BS; /* save DCF addr */ +qwc = 0; /* not wcheck */ +ind[IN_DPW] = ind[IN_LNG] = ind[IN_UNA] = 0; /* clr indicators */ +ind[IN_DSK] = ind[IN_ACC] = ind[IN_DBY] = 0; +if (sim_is_active (&dp_unit[0])) { /* ctlr busy? */ + ind[IN_DBY] = ind[IN_DSK] = 1; /* set indicators */ + return SCPE_OK; } /* done */ + +AS = dcf + 6; /* AS for most ops */ +BS = dcf + DCF_CNT - 1; /* minimum DCF */ +if (ADDR_ERR (BS)) return STOP_WRAP; /* DCF in memory? */ +if (M[dcf] & BBIT) drv = M[dcf + DCF_SEC + 1] & 0xE; /* impl sel? cyl 8-4-2 */ +else drv = M[dcf] & DIGIT; /* get drive sel */ +if ((drv == 0) || (drv & 1) || (drv > BCD_ZERO)) /* bad drive #? */ + return STOP_INVDSK; +drv = bcd_to_bin[drv] >> 1; /* convert */ +uptr = dp_dev.units + drv; /* get unit ptr */ +if ((uptr -> flags & UNIT_ATT) == 0) { /* attached? */ + ind[IN_DSK] = ind[IN_ACC] = 1; /* no, error */ + CRETIOE (iochk, SCPE_UNATT); } + +if ((fnc == FNC_SEEK) && /* seek and */ + (M[dcf + DCF_DIR_FL] & DCF_DSEEK) == DCF_DSEEK) { /* direct flag? */ + diff = dp_cvt_bcd (dcf + DCF_DIR, DCF_DIR_LEN); /* cvt diff */ + if (diff < 0) return STOP_INVDSC; /* error? */ + diff = diff >> 1; /* diff is *2 */ + if ((M[dcf + DCF_DIR + DCF_DIR_LEN - 1] & ZONE) == BBIT) + diff = -diff; /* get sign */ + uptr -> CYL = uptr -> CYL + diff; /* bound seek */ + if (uptr -> CYL < 0) uptr -> CYL = 0; + else if (uptr -> CYL >= DP_NUMCY) { /* too big? */ + uptr -> CYL = 0; /* system hangs */ + return STOP_INVDCY; } + sim_activate (&dp_unit[0], dp_time); /* set ctlr busy */ + return SCPE_OK; } /* done! */ + +sec = dp_cvt_bcd (dcf + DCF_SEC, DCF_SEC_LEN); /* cvt sector */ +if ((sec < 0) || (sec >= (DP_NUMDR * DP_TOTSC))) /* bad sector? */ + return STOP_INVDSC; +if (fnc == FNC_SEEK) { /* seek? */ + uptr -> CYL = (sec / (DP_NUMSF * DP_NUMSC)) % /* set cyl # */ + DP_NUMCY; + sim_activate (&dp_unit[0], dp_time); /* set ctlr busy */ + return SCPE_OK; } /* done! */ + +BS = dcf + DCF_LEN; /* full DCF */ +if (ADDR_ERR (BS)) return STOP_WRAP; /* DCF in memory? */ +cnt = dp_get_cnt (dcf); /* get count */ +if (cnt < 0) return STOP_INVDCN; /* bad count? */ + +if (fnc >= FNC_WOFF) return STOP_INVDFN; /* invalid func */ +if (mod == BCD_W) { /* write? */ + if (fnc == FNC_CHECK) { /* write check? */ + qwc = 1; /* special read */ + fnc = dp_lastf; } /* use last func */ + else { dp_lastf = fnc; /* save func */ + fnc = fnc + FNC_WOFF; } } /* change to write */ +else if (mod == BCD_R) dp_lastf = fnc; /* read? save func */ +else return STOP_INVM; /* other? error */ +psec = dp_fndsec (uptr, sec, dcf, flg); /* find sector */ + +switch (fnc) { /* case on function */ +case FNC_RSCO: /* read sec cnt ov */ + BS = dcf + DCF_CNT; /* set count back */ + /* fall thru */ +case FNC_READ: /* read */ + if (psec < 0) CRETIOE (iochk, STOP_INVDAD); /* addr cmp error? */ + for (;;) { /* loop */ + qzr = (--cnt == 0); /* set zero latch */ + dp_cvt_bin (dcf + DCF_CNT, DCF_CNT_LEN, cnt, MD_WM); /* redo count */ + if (r = dp_rdsec (uptr, psec, flg, qwc)) /* read sector */ + break; + cnt = dp_get_cnt (dcf); /* get new count */ + if (cnt < 0) return STOP_INVDCN; /* bad count? */ + if (qzr) break; /* zero latch? done */ + sec++; psec++; /* next sector */ + dp_cvt_bin (dcf + DCF_SEC, DCF_SEC_LEN, sec, flg); /* rewr sec */ + if (r = dp_nexsec (uptr, psec, dcf, flg)) break; /* find next */ + } + break; /* done, clean up */ + +case FNC_RTRK: /* read track */ + AS = dcf + 9; /* special AS */ + psec = dp_trkop (drv, sec); /* start of track */ + for (;;) { /* loop */ + qzr = (--cnt == 0); /* set zero latch */ + dp_cvt_bin (dcf + DCF_CNT, DCF_CNT_LEN, cnt, MD_WM); /* redo count */ + if (r = dp_rdadr (uptr, psec, flg, qwc)) /* read addr */ + break; /* error? */ + if (r = dp_rdsec (uptr, psec, flg, qwc)) /* read data */ + break; /* error? */ + cnt = dp_get_cnt (dcf); /* get new count */ + if (cnt < 0) return STOP_INVDCN; /* bad count? */ + if (qzr) break; /* zero latch? done */ + psec = dp_trkop (drv, sec) + ((psec + 1) % DP_NUMSC); } + break; /* done, clean up */ + +case FNC_WRSCO: /* write sec cnt ov */ + BS = dcf + DCF_CNT; /* set count back */ + /* fall through */ +case FNC_WRITE: /* read */ + if (psec < 0) CRETIOE (iochk, STOP_INVDAD); /* addr cmp error? */ + for (;;) { /* loop */ + qzr = (--cnt == 0); /* set zero latch */ + dp_cvt_bin (dcf + DCF_CNT, DCF_CNT_LEN, cnt, MD_WM); /* rewr cnt */ + if (r = dp_wrsec (uptr, psec, flg)) break; /* write data */ + if (qzr) break; /* zero latch? done */ + sec++; psec++; /* next sector */ + dp_cvt_bin (dcf + DCF_SEC, DCF_SEC_LEN, sec, flg); /* rewr sec */ + if (r = dp_nexsec (uptr, psec, dcf, flg)) break; /* find next */ + } + break; /* done, clean up */ + +case FNC_WRTRK: /* write track */ + if ((uptr -> flags & UNIT_WAE) == 0) /* enabled? */ + return STOP_WRADIS; + AS = dcf + 9; /* special AS */ + psec = dp_trkop (drv, sec); /* start of track */ + for (;;) { /* loop */ + qzr = (--cnt == 0); /* set zero latch */ + dp_cvt_bin (dcf + DCF_CNT, DCF_CNT_LEN, cnt, MD_WM); /* redo count */ + if (r = dp_wradr (uptr, psec, flg)) break; /* write addr */ + if (r = dp_wrsec (uptr, psec, flg)) break; /* write data */ + if (qzr) break; /* zero latch? done */ + psec = dp_trkop (drv, sec) + ((psec + 1) % DP_NUMSC); } + break; /* done, clean up */ + +default: /* unknown */ + return STOP_INVDFN; } + +if (r == SCPE_OK) { /* normal so far? */ + BS++; /* advance BS */ + if (ADDR_ERR (BS)) return STOP_WRAP; /* address error? */ + if (M[BS - 1] != (WM + BCD_GRPMRK)) { /* GM + WM at end? */ + ind[IN_LNG] = ind[IN_DSK] = 1; /* no, error */ + r = STOP_INVDLN; } } +CRETIOE (iochk || !ind[IN_DSK], r); /* return status */ +} + +/* Read or compare address with memory */ + +t_stat dp_rdadr (UNIT *uptr, int32 sec, int32 flg, int32 qwc) +{ +int32 i; +uint8 ac; +int32 da = (sec % DP_TOTSC) * DP_NUMCH; /* char number */ +uint8 *ap = ((uint8 *) uptr -> filebuf) + da; /* buf ptr */ +t_bool zad = dp_zeroad (ap); /* zero address */ +static const int32 dec_tab[DP_ADDR] = /* powers of 10 */ + { 100000, 10000, 1000, 100, 10, 1} ; + +for (i = 0; i < DP_ADDR; i++) { /* copy address */ + if (M[BS] == (WM | BCD_GRPMRK)) { /* premature GWM? */ + ind[IN_LNG] = ind[IN_DSK] = 1; /* error */ + return STOP_INVDLN; } + if (zad) { /* addr zero? */ + ac = sec / dec_tab[i]; /* get addr digit */ + sec = sec % dec_tab[i]; /* get remainder */ + ac = bcd_to_bin[ac]; } /* cvt to BCD */ + else ac = *ap; /* addr char */ + if (qwc) { /* wr chk? zad ok */ + if (!zad && (flg? (M[BS] != *ap): /* L? cmp with WM */ + ((M[BS] & CHAR) != (*ap & CHAR)))) { /* M? cmp w/o WM */ + ind[IN_DPW] = ind[IN_DSK] = 1; + return STOP_WRCHKE; } } + else if (flg) M[BS] = *ap & CHAR; /* load mode */ + else M[BS] = (M[BS] & WM) | (*ap & CHAR); /* move mode */ + ap++; BS++; /* adv ptrs */ + if (ADDR_ERR (BS)) return STOP_WRAP; } +return SCPE_OK; +} + +/* Read or compare data with memory */ + +t_stat dp_rdsec (UNIT *uptr, int32 sec, int32 flg, int32 qwc) +{ +int32 i, lim; +int32 da = (sec % DP_TOTSC) * DP_NUMCH; /* char number */ +uint8 *ap = ((uint8 *) uptr -> filebuf) + da + DP_ADDR; /* buf ptr */ + +lim = flg? (DP_DATA - 10): DP_DATA; /* load vs move */ +for (i = 0; i < lim; i++) { /* copy data */ + if (M[BS] == (WM | BCD_GRPMRK)) { /* premature GWM? */ + ind[IN_LNG] = ind[IN_DSK] = 1; /* error */ + return STOP_INVDLN; } + if (qwc) { /* write check? */ + if (flg? (M[BS] != *ap): /* load mode cmp */ + ((M[BS] & CHAR) != (*ap & CHAR))) { /* move mode cmp */ + ind[IN_DPW] = ind[IN_DSK] = 1; /* error */ + return STOP_WRCHKE; } } + else if (flg) M[BS] = *ap & (WM | CHAR); /* load mode */ + else M[BS] = (M[BS] & WM) | (*ap & CHAR); /* word mode */ + ap++; BS++; /* adv ptrs */ + if (ADDR_ERR (BS)) return STOP_WRAP; } +return SCPE_OK; +} + +/* Write address to disk */ + +t_stat dp_wradr (UNIT *uptr, int32 sec, int32 flg) +{ +int32 i; +uint32 da = (sec % DP_TOTSC) * DP_NUMCH; /* char number */ +uint8 *ap = ((uint8 *) uptr -> filebuf) + da; /* buf ptr */ + +for (i = 0; i < DP_ADDR; i++) { /* copy address */ + if (M[BS] == (WM | BCD_GRPMRK)) { /* premature GWM? */ + dp_fill (uptr, da, DP_NUMCH - i); /* fill, set err */ + ind[IN_LNG] = ind[IN_DSK] = 1; /* error */ + return STOP_INVDLN; } + if (flg) *ap = M[BS] & (WM | CHAR); /* L? copy WM */ + else *ap = M[BS] & CHAR; /* M? strip WM */ + if (da >= uptr -> hwmark) uptr -> hwmark = da + 1; + da++; ap++; BS++; /* adv ptrs */ + if (ADDR_ERR (BS)) return STOP_WRAP; } +return SCPE_OK; +} + +/* Write data to disk */ + +t_stat dp_wrsec (UNIT *uptr, int32 sec, int32 flg) +{ +int32 i, lim; +uint32 da = ((sec % DP_TOTSC) * DP_NUMCH) + DP_ADDR; /* char number */ +uint8 *ap = ((uint8 *) uptr -> filebuf) + da; /* buf ptr */ + +lim = flg? (DP_DATA - 10): DP_DATA; /* load vs move */ +for (i = 0; i < lim; i++) { /* copy data */ + if (M[BS] == (WM | BCD_GRPMRK)) { /* premature GWM? */ + dp_fill (uptr, da, DP_DATA - i); /* fill, set err */ + ind[IN_LNG] = ind[IN_DSK] = 1; /* error */ + return STOP_INVDLN; } + if (flg) *ap = M[BS] & (WM | CHAR); /* load, copy WM */ + else *ap = M[BS] & CHAR; /* move, strip WM */ + if (da >= uptr -> hwmark) uptr -> hwmark = da + 1; + da++; ap++; BS++; /* adv ptrs */ + if (ADDR_ERR (BS)) return STOP_WRAP; } +return SCPE_OK; +} + +/* Find sector */ + +int32 dp_fndsec (UNIT *uptr, int32 sec, int32 dcf, int32 flg) +{ +int32 ctrk = sec % (DP_NUMSF * DP_NUMSC); /* curr trk-sec */ +int32 psec = ((uptr -> CYL) * (DP_NUMSF * DP_NUMSC)) + ctrk; +int32 da = psec * DP_NUMCH; /* char number */ +uint8 *ap = ((uint8 *) uptr -> filebuf) + da; /* buf ptr */ +int32 i; + +if (dp_zeroad (ap)) return psec; /* addr zero? ok */ +if (dp_cmp_ad (ap, dcf, flg)) return psec; /* addr comp? ok */ +psec = psec - (psec % DP_NUMSC); /* sector 0 */ +for (i = 0; i < DP_NUMSC; i++, psec++) { /* check track */ + da = psec * DP_NUMCH; /* char number */ + ap = ((uint8 *) uptr -> filebuf) + da; /* word pointer */ + if (dp_zeroad (ap)) continue; /* no implicit match */ + if (dp_cmp_ad (ap, dcf, flg)) return psec; } /* match? */ +ind[IN_UNA] = ind[IN_DSK] = 1; /* no match */ +return -1; +} + +/* Find next sector - must be sequential, cannot cross cylinder boundary */ + +t_stat dp_nexsec (UNIT *uptr, int32 psec, int32 dcf, int32 flg) +{ +int32 ctrk = psec % (DP_NUMSF * DP_NUMSC); /* curr trk-sec */ +int32 da = psec * DP_NUMCH; /* word number */ +uint8 *ap = ((uint8 *) uptr -> filebuf) + da; /* buf ptr */ + +if (ctrk) { /* not trk zero? */ + if (dp_zeroad (ap)) return SCPE_OK; /* addr zero? ok */ + if (dp_cmp_ad (ap, dcf, flg)) return SCPE_OK; }/* addr comp? ok */ +ind[IN_UNA] = ind[IN_DSK] = 1; /* no, error */ +return STOP_INVDAD; +} + +/* Test for zero address */ + +t_bool dp_zeroad (uint8 *ap) +{ +int32 i; + +for (i = 0; i < DP_ADDR; i++, ap++) { /* loop thru addr */ + if (*ap & CHAR) return FALSE; } /* nonzero? lose */ +return TRUE; /* all zeroes */ +} + +/* Compare disk address to memory sector address - always omit word marks */ + +t_bool dp_cmp_ad (uint8 *ap, int32 dcf, int32 flg) +{ +int32 i; +uint8 c; + +for (i = 0; i < DP_ADDR; i++, ap++) { /* loop thru addr */ + c = M[dcf + DCF_SEC + i]; /* sector addr char */ + if ((c & CHAR) != (*ap & CHAR)) /* cmp w/o WM */ + return FALSE; } +return TRUE; /* compare ok */ +} + +/* Track operation setup */ + +int32 dp_trkop (int32 drv, int32 sec) +{ +int32 ctrk = (sec / DP_NUMSC) % DP_NUMSF; + +return ((drv * DP_TOTSC) + (dp_unit[drv].CYL * DP_NUMSF * DP_NUMSC) + + (ctrk * DP_NUMSC)); +} + +/* Convert DCF BCD field to binary */ + +int32 dp_cvt_bcd (int32 ad, int32 len) +{ +uint8 c; +int32 r; + +for (r = 0; len > 0; len--) { /* loop thru char */ + c = M[ad] & DIGIT; /* get digit */ + if ((c == 0) || (c > BCD_ZERO)) return -1; /* invalid? */ + r = (r * 10) + bcd_to_bin[c]; /* cvt to bin */ + ad++; } /* next digit */ +return r; +} + +/* Convert binary to DCF BCD field */ + +void dp_cvt_bin (int32 ad, int32 len, int32 val, int32 flg) +{ +int32 r; + +for ( ; len > 0; len--) { /* loop thru char */ + r = val % 10; /* get digit */ + if (flg) M[ad + len - 1] = bin_to_bcd[r]; /* load mode? */ + else M[ad + len - 1] = (M[ad + len - 1] & WM) | bin_to_bcd[r]; + val = val / 10; } +return; +} + +/* Get and validate count */ + +int32 dp_get_cnt (int32 dcf) +{ +int32 cnt = dp_cvt_bcd (dcf + DCF_CNT, DCF_CNT_LEN); /* get new count */ +if (cnt < 0) return -1; /* bad count? */ +if (cnt == 0) return 1000; /* 0 => 1000 */ +return cnt; +} + +/* Fill sector buffer with blanks */ + +void dp_fill (UNIT *uptr, uint32 da, int32 cnt) +{ +while (cnt-- > 0) { /* fill with blanks */ + *(((uint8 *) uptr -> filebuf) + da) = BCD_BLANK; + if (da >= uptr -> hwmark) uptr -> hwmark = da + 1; + da++; } +return; +} + +/* Reset routine */ + +t_stat dp_reset (DEVICE *dptr) +{ +int32 i; + +for (i = 0; i < DP_NUMDR; i++) dp_unit[i].CYL = 0; /* reset cylinder */ +dp_lastf = 0; /* clear state */ +ind[IN_DPW] = ind[IN_LNG] = ind[IN_UNA] = 0; /* clr indicators */ +ind[IN_DSK] = ind[IN_ACC] = ind[IN_DBY] = 0; +sim_cancel (&dp_unit[0]); /* cancel timer */ +return SCPE_OK; +} diff --git a/I1401/i1401_iq.c b/I1401/i1401_iq.c index 3ee61262..bd30d8ef 100644 --- a/I1401/i1401_iq.c +++ b/I1401/i1401_iq.c @@ -1,6 +1,6 @@ /* i1401_iq.c: IBM 1407 inquiry terminal - Copyright (c) 1993-2001, Robert M. Supnik + Copyright (c) 1993-2002, Robert M. Supnik Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), diff --git a/I1401/i1401_lp.c b/I1401/i1401_lp.c index 16bfbc66..432338ef 100644 --- a/I1401/i1401_lp.c +++ b/I1401/i1401_lp.c @@ -1,6 +1,6 @@ /* i1401_lp.c: IBM 1403 line printer simulator - Copyright (c) 1993-2001, Robert M. Supnik + Copyright (c) 1993-2002, Robert M. Supnik Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), @@ -25,6 +25,7 @@ lpt 1403 line printer + 30-May-02 RMS Widened POS to 32b 13-Apr-01 RMS Revised for register arrays */ @@ -83,7 +84,7 @@ UNIT lpt_unit = { REG lpt_reg[] = { { FLDATA (ERR, ind[IN_LPT], 0) }, - { DRDATA (POS, lpt_unit.pos, 31), PV_LEFT }, + { DRDATA (POS, lpt_unit.pos, 32), PV_LEFT }, { BRDATA (CCT, cct, 8, 32, CCT_LNT) }, { DRDATA (LINES, lines, 8), PV_LEFT }, { DRDATA (CCTP, cctptr, 8), PV_LEFT }, diff --git a/I1401/i1401_mt.c b/I1401/i1401_mt.c index adf9fa8e..8965923f 100644 --- a/I1401/i1401_mt.c +++ b/I1401/i1401_mt.c @@ -1,6 +1,6 @@ /* i1401_mt.c: IBM 1401 magnetic tape simulator - Copyright (c) 1993-2001, Robert M. Supnik + Copyright (c) 1993-2002, Robert M. Supnik Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), @@ -25,6 +25,13 @@ mt 7-track magtape + 12-Jun-02 RMS End-of-record on read sets GM without WM + (found by Van Snyder) + 03-Jun-02 RMS Modified for 1311 support + 30-May-02 RMS Widened POS to 32b + 22-Apr-02 RMS Added protection against bad record lengths + 30-Jan-02 RMS New zero footprint tape bootstrap from Van Snyder + 20-Jan-02 RMS Changed write enabled modifier 29-Nov-01 RMS Added read only unit support 18-Apr-01 RMS Changed to rewind tape before boot 07-Dec-00 RMS Widened display width from 6 to 8 bits to see record lnt @@ -54,12 +61,13 @@ #define UNIT_WLK (1 << UNIT_V_WLK) #define UNIT_W_UF 2 /* #save flags */ #define UNIT_WPRT (UNIT_WLK | UNIT_RO) /* write protect */ +#define MT_MAXFR (MAXMEMSIZE * 2) /* max transfer */ extern uint8 M[]; /* memory */ extern int32 ind[64]; extern int32 BS, iochk; extern UNIT cpu_unit; -unsigned int8 dbuf[MAXMEMSIZE * 2]; /* tape buffer */ +uint8 dbuf[MT_MAXFR]; /* tape buffer */ t_stat mt_reset (DEVICE *dptr); t_stat mt_boot (int32 unitno); UNIT *get_unit (int32 unit); @@ -90,13 +98,12 @@ UNIT mt_unit[] = { REG mt_reg[] = { { FLDATA (END, ind[IN_END], 0) }, { FLDATA (ERR, ind[IN_TAP], 0) }, - { FLDATA (PAR, ind[IN_PAR], 0) }, - { DRDATA (POS1, mt_unit[1].pos, 31), PV_LEFT + REG_RO }, - { DRDATA (POS2, mt_unit[2].pos, 31), PV_LEFT + REG_RO }, - { DRDATA (POS3, mt_unit[3].pos, 31), PV_LEFT + REG_RO }, - { DRDATA (POS4, mt_unit[4].pos, 31), PV_LEFT + REG_RO }, - { DRDATA (POS5, mt_unit[5].pos, 31), PV_LEFT + REG_RO }, - { DRDATA (POS6, mt_unit[6].pos, 31), PV_LEFT + REG_RO }, + { DRDATA (POS1, mt_unit[1].pos, 32), PV_LEFT + REG_RO }, + { DRDATA (POS2, mt_unit[2].pos, 32), PV_LEFT + REG_RO }, + { DRDATA (POS3, mt_unit[3].pos, 32), PV_LEFT + REG_RO }, + { DRDATA (POS4, mt_unit[4].pos, 32), PV_LEFT + REG_RO }, + { DRDATA (POS5, mt_unit[5].pos, 32), PV_LEFT + REG_RO }, + { DRDATA (POS6, mt_unit[6].pos, 32), PV_LEFT + REG_RO }, { GRDATA (FLG1, mt_unit[1].flags, 8, UNIT_W_UF, UNIT_V_UF - 1), REG_HRO }, { GRDATA (FLG2, mt_unit[2].flags, 8, UNIT_W_UF, UNIT_V_UF - 1), @@ -112,7 +119,7 @@ REG mt_reg[] = { { NULL } }; MTAB mt_mod[] = { - { UNIT_WLK, 0, "write enabled", "ENABLED", NULL }, + { UNIT_WLK, 0, "write enabled", "WRITEENABLED", NULL }, { UNIT_WLK, UNIT_WLK, "write locked", "LOCKED", NULL }, { 0 } }; @@ -211,13 +218,20 @@ case BCD_R: /* read */ ind[IN_END] = 1; /* set end mark */ uptr -> pos = uptr -> pos + sizeof (t_mtrlnt); break; } - tbc = MTRL (tbc); /* ignore error flag */ + tbc = MTRL (tbc); /* ignore error flag */ + if (tbc > MT_MAXFR) return SCPE_MTRLNT; /* record too long? */ i = fxread (dbuf, sizeof (int8), tbc, uptr -> fileref); for ( ; i < tbc; i++) dbuf[i] = 0; /* fill with 0's */ - err = ferror (uptr -> fileref); + if (err = ferror (uptr -> fileref)) break; /* I/O error? */ uptr -> pos = uptr -> pos + ((tbc + 1) & ~1) + (2 * sizeof (t_mtrlnt)); - for (i = 0; (i < tbc) && (M[BS] != (BCD_GRPMRK + WM)); i++) { + for (i = 0; i < tbc; i++) { /* loop thru buf */ + if (M[BS] == (BCD_GRPMRK + WM)) { /* GWM in memory? */ + BS++; /* incr BS */ + if (ADDR_ERR (BS)) { /* test for wrap */ + BS = BA | (BS % MAXMEMSIZE); + return STOP_WRAP; } + return SCPE_OK; } /* done */ t = dbuf[i]; /* get char */ if ((flag != MD_BIN) && (t == BCD_ALT)) t = BCD_BLANK; if (flag == MD_WM) { /* word mk mode? */ @@ -226,10 +240,11 @@ case BCD_R: /* read */ wm_seen = 0; } } else M[BS] = (M[BS] & WM) | (t & CHAR); if (!wm_seen) BS++; - if (ADDR_ERR (BS)) { + if (ADDR_ERR (BS)) { /* check next BS */ BS = BA | (BS % MAXMEMSIZE); - return STOP_NXM; } } - M[BS++] = BCD_GRPMRK + WM; /* end of record */ + return STOP_WRAP; } } + if (flag == MD_WM) M[BS] = BCD_GRPMRK; /* load? clear WM */ + else M[BS] = (M[BS] & WM) | BCD_GRPMRK; /* move? save WM */ break; case BCD_W: @@ -241,16 +256,19 @@ case BCD_W: if (((t & CHAR) == BCD_BLANK) && (flag != MD_BIN)) dbuf[tbc++] = BCD_ALT; else dbuf[tbc++] = t & CHAR; - if (ADDR_ERR (BS)) { + if (ADDR_ERR (BS)) { /* check next BS */ BS = BA | (BS % MAXMEMSIZE); - return STOP_NXM; } } + return STOP_WRAP; } } fseek (uptr -> fileref, uptr -> pos, SEEK_SET); fxwrite (&tbc, sizeof (t_mtrlnt), 1, uptr -> fileref); fxwrite (dbuf, sizeof (int8), (tbc + 1) & ~1, uptr -> fileref); fxwrite (&tbc, sizeof (t_mtrlnt), 1, uptr -> fileref); - err = ferror (uptr -> fileref); + if (err = ferror (uptr -> fileref)) break; /* I/O error? */ uptr -> pos = uptr -> pos + ((tbc + 1) & ~1) + (2 * sizeof (t_mtrlnt)); + if (ADDR_ERR (BS)) { /* check final BS */ + BS = BA | (BS % MAXMEMSIZE); + return STOP_WRAP; } break; default: return STOP_INVM; } @@ -258,8 +276,8 @@ default: if (err != 0) { /* I/O error */ perror ("MT I/O error"); clearerr (uptr -> fileref); - if (iochk) return SCPE_IOERR; - ind[IN_TAP] = 1; } /* flag error */ + ind[IN_TAP] = 1; /* flag error */ + if (iochk) return SCPE_IOERR; } return SCPE_OK; } @@ -275,29 +293,19 @@ else return mt_dev.units + unit; t_stat mt_reset (DEVICE *dptr) { -ind[IN_END] = ind[IN_PAR] = ind[IN_TAP] = 0; /* clear indicators */ +ind[IN_END] = ind[IN_TAP] = 0; /* clear indicators */ return SCPE_OK; } /* Bootstrap routine */ -#define BOOT_START 3980 -#define BOOT_LEN (sizeof (boot_rom) / sizeof (unsigned char)) - -static const unsigned char boot_rom[] = { - OP_LCA + WM, BCD_PERCNT, BCD_U, BCD_ONE, - BCD_ZERO, BCD_ZERO, BCD_ONE, BCD_R, /* LDA %U1 001 R */ - OP_B + WM, BCD_ZERO, BCD_ZERO, BCD_ONE, /* B 001 */ - OP_H + WM }; /* HALT */ - t_stat mt_boot (int32 unitno) { -int32 i; extern int32 saved_IS; -mt_unit[unitno].pos = 0; -for (i = 0; i < BOOT_LEN; i++) M[BOOT_START + i] = boot_rom[i]; -M[BOOT_START + 3] = unitno & 07; -saved_IS = BOOT_START; +mt_unit[unitno].pos = 0; /* force rewind */ +BS = 1; /* set BS = 001 */ +mt_io (unitno, MD_WM, BCD_R); /* LDA %U1 001 R */ +saved_IS = 1; return SCPE_OK; } diff --git a/I1401/i1401_sys.c b/I1401/i1401_sys.c index a5ed5ad5..c897d1aa 100644 --- a/I1401/i1401_sys.c +++ b/I1401/i1401_sys.c @@ -1,6 +1,6 @@ /* i1401_sys.c: IBM 1401 simulator interface - Copyright (c) 1993-2001, Robert M. Supnik + Copyright (c) 1993-2002, Robert M. Supnik Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), @@ -23,6 +23,9 @@ be used in advertising or otherwise to promote the sale, use or other dealings in this Software without prior written authorization from Robert M Supnik. + 03-Jun-02 RMS Added 1311 support + 18-May-02 RMS Added -D feature from Van Snyder + 26-Jan-02 RMS Fixed H, NOP with no trailing wm (found by Van Snyder) 17-Sep-01 RMS Removed multiconsole support 13-Jul-01 RMS Fixed bug in symbolic output (found by Peter Schorn) 27-May-01 RMS Added multiconsole support @@ -37,7 +40,7 @@ #define LINE_LNT 80 extern DEVICE cpu_dev, inq_dev, lpt_dev; extern DEVICE cdr_dev, cdp_dev, stack_dev; -extern DEVICE mt_dev; +extern DEVICE dp_dev, mt_dev; extern UNIT cpu_unit; extern REG cpu_reg[]; extern uint8 M[]; @@ -63,9 +66,16 @@ REG *sim_PC = &cpu_reg[0]; int32 sim_emax = LINE_LNT; -DEVICE *sim_devices[] = { &cpu_dev, &inq_dev, - &cdr_dev, &cdp_dev, &stack_dev, &lpt_dev, - &mt_dev, NULL }; +DEVICE *sim_devices[] = { + &cpu_dev, + &inq_dev, + &cdr_dev, + &cdp_dev, + &stack_dev, + &lpt_dev, + &mt_dev, + &dp_dev, + NULL }; const char *sim_stop_messages[] = { "Unknown error", @@ -89,7 +99,17 @@ const char *sim_stop_messages[] = { "MCE data field too short", "MCE control field too short", "MCE EPE hanging $", - "I/O check" }; + "I/O check", + "Invalid disk sector address", + "Invalid disk sector count", + "Invalid disk unit", + "Invalid disk function", + "Invalid disk record length", + "Write track while disabled", + "Write check error", + "Disk address miscompare", + "Direct seek cylinder exceeds maximum" + }; /* Binary loader -- load carriage control tape @@ -187,6 +207,11 @@ if (sw & SWMASK ('C')) { /* character? */ else fprintf (of, FMTASC (t & 0177)); return SCPE_OK; } if ((uptr != NULL) && (uptr != &cpu_unit)) return SCPE_ARG; /* CPU? */ +if (sw & SWMASK ('D')) { /* dump? */ + for (i = 0; i < 50; i++) fprintf (of, "%c", bcd_to_ascii[val[i]&CHAR]) ; + fprintf (of, "\n\t"); + for (i = 0; i < 50; i++) fprintf (of, (val[i]&WM)? "1": " ") ; + return -(i - 1); } if (sw & SWMASK ('S')) { /* string? */ i = 0; do { t = val[i++]; @@ -199,15 +224,15 @@ if ((val[0] & WM) == 0) return STOP_NOWM; /* WM under op? */ op = val[0]& CHAR; /* isolate op */ flags = op_table[op]; /* get flags */ for (ilnt = 1; ilnt < sim_emax; ilnt++) if (val[ilnt] & WM) break; -if (flags & HNOP) ilnt = 1; /* halt, nop? */ -else if ((flags & NOWM) && (ilnt > 7)) ilnt = 7; /* cs, swm? */ +if ((flags & (NOWM | HNOP)) && (ilnt > 7)) ilnt = 7; /* cs, swm, h, nop? */ else if ((op == OP_B) && (ilnt > 4) && (val[4] == BCD_BLANK)) ilnt = 4; -else if (ilnt > 8) ilnt = 8; /* cap length */ -if ((flags & len_table[ilnt]) == 0) return STOP_INVL; /* legal length? */ +else if ((ilnt > 8) && (op != OP_NOP)) ilnt = 8; /* cap length */ +if (((flags & len_table[ilnt]) == 0) && /* valid lnt, */ + ((op != OP_NOP) == 0)) return STOP_INVL; /* nop? */ fprintf (of, "%s",opcode[op]); /* print opcode */ if (ilnt > 2) { /* A address? */ - if ((flags & IO) && (val[1] == BCD_PERCNT)) fprintf (of, " %%%c%c", - bcd_to_ascii[val[2]], bcd_to_ascii[val[3]]); + if (((flags & IO) || (op == OP_NOP)) && (val[1] == BCD_PERCNT)) + fprintf (of, " %%%c%c", bcd_to_ascii[val[2]], bcd_to_ascii[val[3]]); else fprint_addr (of, &val[1]); } if (ilnt > 5) fprint_addr (of, &val[4]); /* B address? */ if ((ilnt == 2) || (ilnt == 5) || (ilnt == 8)) /* d character? */ @@ -291,12 +316,12 @@ for (op = 0; op < 64; op++) /* look it up */ if (opcode[op] && strcmp (gbuf, opcode[op]) == 0) break; if (op >= 64) return SCPE_ARG; /* successful? */ val[0] = op | WM; /* store opcode */ -cptr = get_glyph (cptr, gbuf, ' '); /* get addr or d */ +cptr = get_glyph (cptr, gbuf, 0); /* get addr or d */ if (((op_table[op] && IO) && (get_io (gbuf, &val[1]) == SCPE_OK)) || (get_addr (gbuf, &val[1]) == SCPE_OK)) { - cptr = get_glyph (cptr, gbuf, ' '); /* get addr or d */ + cptr = get_glyph (cptr, gbuf, 0); /* get addr or d */ if (get_addr (gbuf, &val[4]) == SCPE_OK) { - cptr = get_glyph (cptr, gbuf, ' '); /* get d */ + cptr = get_glyph (cptr, gbuf, ','); /* get d */ ilnt = 7; } /* a and b addresses */ else ilnt = 4; } /* a address */ else ilnt = 1; /* no addresses */ @@ -306,6 +331,7 @@ if ((gbuf[0] == '\'') || (gbuf[0] == '"')) { /* d character? */ return SCPE_ARG; /* end and legal? */ val[ilnt] = ascii_to_bcd[t]; /* save D char */ ilnt = ilnt + 1; } +else if (gbuf[0] != 0) return SCPE_ARG; /* not done? */ if ((op_table[op] & len_table[ilnt]) == 0) return STOP_INVL; return -(ilnt - 1); } diff --git a/Ibm1130/1130consoleblank.bmp b/Ibm1130/1130consoleblank.bmp new file mode 100644 index 00000000..9b6c7780 Binary files /dev/null and b/Ibm1130/1130consoleblank.bmp differ diff --git a/Ibm1130/HAND.CUR b/Ibm1130/HAND.CUR new file mode 100644 index 00000000..eb0796dd Binary files /dev/null and b/Ibm1130/HAND.CUR differ diff --git a/Ibm1130/ibm1130.mak b/Ibm1130/ibm1130.mak new file mode 100644 index 00000000..b7101148 --- /dev/null +++ b/Ibm1130/ibm1130.mak @@ -0,0 +1,274 @@ +# Microsoft Visual C++ Generated NMAKE File, Format Version 2.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Console Application" 0x0103 + +!IF "$(CFG)" == "" +CFG=Win32 Debug +!MESSAGE No configuration specified. Defaulting to Win32 Debug. +!ENDIF + +!IF "$(CFG)" != "Win32 Release" && "$(CFG)" != "Win32 Debug" +!MESSAGE Invalid configuration "$(CFG)" specified. +!MESSAGE You can specify a configuration when running NMAKE on this makefile +!MESSAGE by defining the macro CFG on the command line. For example: +!MESSAGE +!MESSAGE NMAKE /f "ibm1130.mak" CFG="Win32 Debug" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "Win32 Release" (based on "Win32 (x86) Console Application") +!MESSAGE "Win32 Debug" (based on "Win32 (x86) Console Application") +!MESSAGE +!ERROR An invalid configuration is specified. +!ENDIF + +################################################################################ +# Begin Project +# PROP Target_Last_Scanned "Win32 Debug" +CPP=cl.exe +RSC=rc.exe + +!IF "$(CFG)" == "Win32 Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "WinRel" +# PROP BASE Intermediate_Dir "WinRel" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "WinRel" +# PROP Intermediate_Dir "WinRel" +OUTDIR=.\WinRel +INTDIR=.\WinRel + +ALL : $(OUTDIR)/ibm1130.exe $(OUTDIR)/ibm1130.bsc + +$(OUTDIR) : + if not exist $(OUTDIR)/nul mkdir $(OUTDIR) + +# ADD BASE CPP /nologo /W3 /GX /YX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /FR /c +# ADD CPP /nologo /W3 /GX /YX /O2 /I "c:\pdp11\supnik" /D "NDEBUG" /D "WIN32" /D "_CONSOLE" /D "GUI_SUPPORT" /U "VMS" /FR /c +CPP_PROJ=/nologo /W3 /GX /YX /O2 /I "c:\pdp11\supnik" /D "NDEBUG" /D "WIN32" /D\ + "_CONSOLE" /D "GUI_SUPPORT" /U "VMS" /FR$(INTDIR)/ /Fp$(OUTDIR)/"ibm1130.pch"\ + /Fo$(INTDIR)/ /c +CPP_OBJS=.\WinRel/ +# ADD BASE RSC /l 0x409 /d "NDEBUG" +# ADD RSC /l 0x409 /d "NDEBUG" +RSC_PROJ=/l 0x409 /fo$(INTDIR)/"ibm1130.res" /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +BSC32_FLAGS=/nologo /o$(OUTDIR)/"ibm1130.bsc" +BSC32_SBRS= \ + $(INTDIR)/ibm1130_cpu.sbr \ + $(INTDIR)/ibm1130_sys.sbr \ + $(INTDIR)/ibm1130_cr.sbr \ + $(INTDIR)/ibm1130_stddev.sbr \ + $(INTDIR)/ibm1130_disk.sbr \ + $(INTDIR)/scp_tty.sbr \ + $(INTDIR)/scp.sbr + +$(OUTDIR)/ibm1130.bsc : $(OUTDIR) $(BSC32_SBRS) + $(BSC32) @<< + $(BSC32_FLAGS) $(BSC32_SBRS) +<< + +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /NOLOGO /SUBSYSTEM:console /MACHINE:I386 +# ADD LINK32 kernel32.lib user32.lib gdi32.lib comdlg32.lib advapi32.lib /NOLOGO /SUBSYSTEM:console /MACHINE:I386 +LINK32_FLAGS=kernel32.lib user32.lib gdi32.lib comdlg32.lib advapi32.lib\ + /NOLOGO /SUBSYSTEM:console /INCREMENTAL:no /PDB:$(OUTDIR)/"ibm1130.pdb"\ + /MACHINE:I386 /OUT:$(OUTDIR)/"ibm1130.exe" +DEF_FILE= +LINK32_OBJS= \ + $(INTDIR)/ibm1130_cpu.obj \ + $(INTDIR)/ibm1130_sys.obj \ + $(INTDIR)/ibm1130_cr.obj \ + $(INTDIR)/ibm1130_stddev.obj \ + $(INTDIR)/ibm1130.res \ + $(INTDIR)/ibm1130_disk.obj \ + $(INTDIR)/scp_tty.obj \ + $(INTDIR)/scp.obj + +$(OUTDIR)/ibm1130.exe : $(OUTDIR) $(DEF_FILE) $(LINK32_OBJS) + $(LINK32) @<< + $(LINK32_FLAGS) $(LINK32_OBJS) +<< + +!ELSEIF "$(CFG)" == "Win32 Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "WinDebug" +# PROP BASE Intermediate_Dir "WinDebug" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "WinDebug" +# PROP Intermediate_Dir "WinDebug" +OUTDIR=.\WinDebug +INTDIR=.\WinDebug + +ALL : $(OUTDIR)/ibm1130.exe $(OUTDIR)/ibm1130.bsc + +$(OUTDIR) : + if not exist $(OUTDIR)/nul mkdir $(OUTDIR) + +# ADD BASE CPP /nologo /W3 /GX /Zi /YX /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /FR /c +# ADD CPP /nologo /W3 /GX /Zi /YX /Od /I "c:\pdp11\supnik" /D "_DEBUG" /D "WIN32" /D "_CONSOLE" /D "GUI_SUPPORT" /U "VMS" /FR /c +CPP_PROJ=/nologo /W3 /GX /Zi /YX /Od /I "c:\pdp11\supnik" /D "_DEBUG" /D\ + "WIN32" /D "_CONSOLE" /D "GUI_SUPPORT" /U "VMS" /FR$(INTDIR)/\ + /Fp$(OUTDIR)/"ibm1130.pch" /Fo$(INTDIR)/ /Fd$(OUTDIR)/"ibm1130.pdb" /c +CPP_OBJS=.\WinDebug/ +# ADD BASE RSC /l 0x409 /d "_DEBUG" +# ADD RSC /l 0x409 /d "_DEBUG" +RSC_PROJ=/l 0x409 /fo$(INTDIR)/"ibm1130.res" /d "_DEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +BSC32_FLAGS=/nologo /o$(OUTDIR)/"ibm1130.bsc" +BSC32_SBRS= \ + $(INTDIR)/ibm1130_cpu.sbr \ + $(INTDIR)/ibm1130_sys.sbr \ + $(INTDIR)/ibm1130_cr.sbr \ + $(INTDIR)/ibm1130_stddev.sbr \ + $(INTDIR)/ibm1130_disk.sbr \ + $(INTDIR)/scp_tty.sbr \ + $(INTDIR)/scp.sbr + +$(OUTDIR)/ibm1130.bsc : $(OUTDIR) $(BSC32_SBRS) + $(BSC32) @<< + $(BSC32_FLAGS) $(BSC32_SBRS) +<< + +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /NOLOGO /SUBSYSTEM:console /DEBUG /MACHINE:I386 +# ADD LINK32 kernel32.lib user32.lib gdi32.lib comdlg32.lib advapi32.lib /NOLOGO /SUBSYSTEM:console /DEBUG /MACHINE:I386 +LINK32_FLAGS=kernel32.lib user32.lib gdi32.lib comdlg32.lib advapi32.lib\ + /NOLOGO /SUBSYSTEM:console /INCREMENTAL:yes /PDB:$(OUTDIR)/"ibm1130.pdb" /DEBUG\ + /MACHINE:I386 /OUT:$(OUTDIR)/"ibm1130.exe" +DEF_FILE= +LINK32_OBJS= \ + $(INTDIR)/ibm1130_cpu.obj \ + $(INTDIR)/ibm1130_sys.obj \ + $(INTDIR)/ibm1130_cr.obj \ + $(INTDIR)/ibm1130_stddev.obj \ + $(INTDIR)/ibm1130.res \ + $(INTDIR)/ibm1130_disk.obj \ + $(INTDIR)/scp_tty.obj \ + $(INTDIR)/scp.obj + +$(OUTDIR)/ibm1130.exe : $(OUTDIR) $(DEF_FILE) $(LINK32_OBJS) + $(LINK32) @<< + $(LINK32_FLAGS) $(LINK32_OBJS) +<< + +!ENDIF + +.c{$(CPP_OBJS)}.obj: + $(CPP) $(CPP_PROJ) $< + +.cpp{$(CPP_OBJS)}.obj: + $(CPP) $(CPP_PROJ) $< + +.cxx{$(CPP_OBJS)}.obj: + $(CPP) $(CPP_PROJ) $< + +################################################################################ +# Begin Group "Source Files" + +################################################################################ +# Begin Source File + +SOURCE=.\ibm1130_cpu.c +DEP_IBM11=\ + .\ibm1130_defs.h\ + ..\sim_defs.h + +$(INTDIR)/ibm1130_cpu.obj : $(SOURCE) $(DEP_IBM11) $(INTDIR) + +# End Source File +################################################################################ +# Begin Source File + +SOURCE=.\ibm1130_sys.c +DEP_IBM113=\ + .\ibm1130_defs.h\ + ..\sim_defs.h + +$(INTDIR)/ibm1130_sys.obj : $(SOURCE) $(DEP_IBM113) $(INTDIR) + +# End Source File +################################################################################ +# Begin Source File + +SOURCE=.\ibm1130_cr.c +DEP_IBM1130=\ + .\ibm1130_defs.h\ + ..\sim_defs.h + +$(INTDIR)/ibm1130_cr.obj : $(SOURCE) $(DEP_IBM1130) $(INTDIR) + +# End Source File +################################################################################ +# Begin Source File + +SOURCE=.\ibm1130_stddev.c +DEP_IBM1130_=\ + .\ibm1130_defs.h\ + .\ibm1130_conout.h\ + .\ibm1130_conin.h\ + .\ibm1130_prtwheel.h\ + ..\sim_defs.h + +$(INTDIR)/ibm1130_stddev.obj : $(SOURCE) $(DEP_IBM1130_) $(INTDIR) + +# End Source File +################################################################################ +# Begin Source File + +SOURCE=.\ibm1130.rc +DEP_IBM1130_R=\ + .\1130consoleblank.bmp\ + .\HAND.CUR + +$(INTDIR)/ibm1130.res : $(SOURCE) $(DEP_IBM1130_R) $(INTDIR) + $(RSC) $(RSC_PROJ) $(SOURCE) + +# End Source File +################################################################################ +# Begin Source File + +SOURCE=.\ibm1130_disk.c +DEP_IBM1130_D=\ + .\ibm1130_defs.h\ + ..\sim_defs.h + +$(INTDIR)/ibm1130_disk.obj : $(SOURCE) $(DEP_IBM1130_D) $(INTDIR) + +# End Source File +################################################################################ +# Begin Source File + +SOURCE=..\scp_tty.c +DEP_SCP_T=\ + ..\sim_defs.h + +$(INTDIR)/scp_tty.obj : $(SOURCE) $(DEP_SCP_T) $(INTDIR) + $(CPP) $(CPP_PROJ) $(SOURCE) + +# End Source File +################################################################################ +# Begin Source File + +SOURCE=.\scp.c +DEP_SCP_C=\ + .\sim_defs.h\ + ..\sim_rev.h + +$(INTDIR)/scp.obj : $(SOURCE) $(DEP_SCP_C) $(INTDIR) + +# End Source File +# End Group +# End Project +################################################################################ diff --git a/Ibm1130/ibm1130.rc b/Ibm1130/ibm1130.rc new file mode 100644 index 00000000..64f9da0d --- /dev/null +++ b/Ibm1130/ibm1130.rc @@ -0,0 +1,61 @@ +//Microsoft Visual C++ generated resource script. +// +#include "ibm1130res.h" + +#define APSTUDIO_READONLY_SYMBOLS +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 2 resource. +// +#include + +///////////////////////////////////////////////////////////////////////////// +#undef APSTUDIO_READONLY_SYMBOLS + + +#ifdef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// TEXTINCLUDE +// + +1 TEXTINCLUDE DISCARDABLE +BEGIN + "ibm1130res.h\0" +END + +2 TEXTINCLUDE DISCARDABLE +BEGIN + "#include \r\n" + "\0" +END + +3 TEXTINCLUDE DISCARDABLE +BEGIN + "\r\n" + "\0" +END + +///////////////////////////////////////////////////////////////////////////// +#endif // APSTUDIO_INVOKED + + +///////////////////////////////////////////////////////////////////////////// +// +// Bitmap +// + +IDB_CONSOLE BITMAP DISCARDABLE "1130consoleblank.bmp" + +IDC_HAND CURSOR DISCARDABLE "HAND.CUR" + +#ifndef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 3 resource. +// + + +///////////////////////////////////////////////////////////////////////////// +#endif // not APSTUDIO_INVOKED + diff --git a/Ibm1130/ibm1130_conin.h b/Ibm1130/ibm1130_conin.h new file mode 100644 index 00000000..de39ae22 --- /dev/null +++ b/Ibm1130/ibm1130_conin.h @@ -0,0 +1,30 @@ +// ctrl-M (Enter) => EOF +// ctrl-U => Erase field +// ctrl-Q => Interrupt request (not here) +// ctrl-C => Program stop (not here) +// \ => "not" +// Del => backspace +// Ctrl-H => backspace + + +static uint16 ascii_to_conin[] = /* ASCII to ((hollerith << 4) | special key flags) */ +{ + /* 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F */ + /* 00 */ 0, 0, 0, 0, 0, 0, 0, 0,0x0004, 0, 0, 0, 0,0x0008, 0, 0, + /* 01 */ 0, 0, 0, 0, 0,0x0002, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + /* 20 */ 0x0001,0x4820,0x0060,0x0420,0x4420,0x2220,0x8000,0x0120,0x8120,0x4120,0x4220,0x80a0,0x2420,0x4000,0x8420,0x3000, + /* 30 */ 0x2000,0x1000,0x0800,0x0400,0x0200,0x0100,0x0080,0x0040,0x0020,0x0010,0x0820,0x40a0,0x8220,0x00a0,0x20a0,0x2060, + /* 40 */ 0x0220,0x9000,0x8800,0x8400,0x8200,0x8100,0x8080,0x8040,0x8020,0x8010,0x5000,0x4800,0x4400,0x4200,0x4100,0x4080, + /* 50 */ 0x4040,0x4020,0x4010,0x2800,0x2400,0x2200,0x2100,0x2080,0x2040,0x2020,0x2010,0xa420, 0,0xc420,0x4060,0x2120, + /* 60 */ 0,0x9000,0x8800,0x8400,0x8200,0x8100,0x8080,0x8040,0x8020,0x8010,0x5000,0x4800,0x4400,0x4200,0x4100,0x4080, + /* 70 */ 0x4040,0x4020,0x4010,0x2800,0x2400,0x2200,0x2100,0x2080,0x2040,0x2020,0x2010,0xa420, 0,0x8060, 0,0x0004, + /* 80 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + /* 90 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + /* a0 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + /* b0 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + /* c0 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + /* d0 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + /* e0 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + /* f0 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,0x0004, +}; + diff --git a/Ibm1130/ibm1130_conout.h b/Ibm1130/ibm1130_conout.h new file mode 100644 index 00000000..4bbc6df7 --- /dev/null +++ b/Ibm1130/ibm1130_conout.h @@ -0,0 +1,32 @@ +/* IBM1130 CONSOLE OUTPUT TO ASCII CONVERSION TABLE */ + +#define _0_ '\0' + +#define CENT '\xA2' +#define REST IGNR +#define RDRSTP '?' +#define NOT '\xAC' +#define IGNR '\xFF' +#define CRLF '\r' + +static char conout_to_ascii[] = /* console output code to ASCII */ +{ + /* 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F */ + /* 00 */ '.', _0_, CENT, '\n', '@', REST, '%', _0_, _0_,RDRSTP, _0_, _0_, _0_, _0_, _0_, _0_, + /* 10 */ 'f', '\b', 'F', _0_, 'g', _0_, 'G', _0_, 'b', _0_, 'B', _0_, 'c', _0_, 'C', _0_, + /* 20 */ 'i', ' ', 'I', _0_, 'h', _0_, 'H', _0_, _0_, _0_, _0_, _0_, _0_, _0_, _0_, _0_, + /* 30 */ 'd', _0_, 'D', _0_, 'e', _0_, 'E', _0_, _0_, _0_, _0_, _0_, 'a', _0_, 'A', _0_, + /* 40 */ '$', _0_, '!', _0_, '&', _0_, '>', _0_, _0_, _0_, _0_, _0_, _0_, _0_, _0_, _0_, + /* 50 */ 'o', _0_, 'O', _0_, 'p', _0_, 'P', _0_, 'k', _0_, 'K', _0_, 'l', _0_, 'L', _0_, + /* 60 */ 'r', _0_, 'R', _0_, 'q', _0_, 'Q', _0_, _0_, _0_, _0_, _0_, _0_, _0_, _0_, _0_, + /* 70 */ 'm', _0_, 'M', _0_, 'n', _0_, 'N', _0_, _0_, _0_, _0_, _0_, 'j', _0_, _0_, _0_, + /* 80 */ ',', CRLF, ':', _0_, '-', _0_, '?', _0_, _0_, _0_, _0_, _0_, _0_, _0_, _0_, _0_, + /* 90 */ 'w', _0_, 'W', _0_, 'x', _0_, 'X', _0_, 's', _0_, 'S', _0_, 't', _0_, 'T', _0_, + /* A0 */ 'z', _0_, 'Z', _0_, 'y', _0_, 'Y', _0_, _0_, _0_, _0_, _0_, _0_, _0_, _0_, _0_, + /* B0 */ 'u', _0_, 'U', _0_, 'v', _0_, 'V', _0_, _0_, _0_, _0_, _0_, '/', _0_, '_', _0_, + /* C0 */ '#', _0_, '=', _0_, '0', _0_, '|', _0_, _0_, _0_, _0_, _0_, _0_, _0_, 'J', _0_, + /* D0 */ '6', _0_, ';', _0_, '7', _0_, '*', _0_, '2', _0_, '+', _0_, '3', _0_, '<', _0_, + /* E0 */ '9', _0_, '"', _0_, '8', _0_, '\'', _0_, _0_, _0_, _0_, _0_, _0_, _0_, _0_, _0_, + /* F0 */ '4', _0_, NOT, _0_, '5', _0_, ')', _0_, _0_, _0_, _0_, _0_, '1', _0_, '(', _0_, +}; + diff --git a/Ibm1130/ibm1130_cpu.c b/Ibm1130/ibm1130_cpu.c new file mode 100644 index 00000000..e9ee607f --- /dev/null +++ b/Ibm1130/ibm1130_cpu.c @@ -0,0 +1,2324 @@ +/* ibm1130_cpu.c: IBM 1130 CPU simulator + + Copyright (c) 2002, Brian Knittel + Based on PDP-11 simulator written by Robert M Supnik + + Permission is hereby granted, free of charge, to any person obtaining a + copy of this software and associated documentation files (the "Software"), + to deal in the Software without restriction, including without limitation + the rights to use, copy, modify, merge, publish, distribute, sublicense, + and/or sell copies of the Software, and to permit persons to whom the + Software is furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + ROBERT M SUPNIK BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + 25-Jun-01 BLK Written + 27-Mar-02 BLK Made BOSC work even in short form + + The register state for the IBM 1130 CPU is: + + IAR instruction address register + ACC accumulator + EXT accumulator extension + Oflow overflow bit + Carry carry bit + CES console entry switches + ipl current interrupt level, -1 = non interrupt + iplpending bitmap of pending interrupts + wait_state current CPU state: running or waiting + DSW console run/stop switch device status word + RUNMODE processor step/run mode (may also imply IntRun) + BREAK breakpoint address + WRU simulator-break character + IntRun Int Run flag (causes level 5 interrupt after every instruction) + ILSW0..5 interrupt level status words + IPS instructions per second throttle (not a real 1130 register) + + The SAR (storage address register) and SBR (storage buffer register) are updated + but not saved in the CPU state; they matter only to the GUI. + + Interrupt handling: interrupts occur when any device on any level has an + active interrupt. XIO commands can clear specific IRQ bits. When this + happens, we have to evaluate all devices on the same IRQ level for remaining + indicators. The flag int_req is set with a bit corresponding to the IRQ level + when any interrupt indicator is activated. + + The 1130 console has a switch that controls several run modes: SS (single processor + step), SCLK (single clock step), SINST (single instruction step), INT_RUN + (IRQ 5 after each non interrupt-handler instruction) and RUN (normal operation). + This simulator does not implement SS and SCLK. The simulator GUI console handles + SINST, so we only have to worry about INT_RUN. The console command SET CPU IntRun sets + the tmode (trace mode) flag; this causes a level 5 interrupt after each + instruction. + + The IBM 1130 instruction formats are + + +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ + | opcode | F| T | | general format + +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ + + +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ + | opcode | 0| T | DISPLACEMENT | short instruction + +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ + + +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ + | opcode | 1| T | I| MODIFIER | long instruction + +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ + | ADDRESS | + +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ + + opcode in MSBits + + F = format. 0 = short (1 word), 1 = long (2 word) instruction + + T = Tag 00 = no index register (e.g. IAR relative) + 01 = use index register 1 (e.g. core address 1 = M[1]) + 02 = use index register 2 (e.g. core address 2 = M[2]) + 03 = use index register 3 (e.g. core address 3 = M[3]) + + DISPLACEMENT = two's complement (must be sign-extended) + + I = Indirect + + Note that IAR = instruction address+1 when instruction is being decoded. + + In normal addressing mode, effective address (EA) is computed as follows: + + F = 0 T = 0 EA = IAR + DISPLACEMENT + 0 1 IAR + DISPLACEMENT + M[1] + 0 2 IAR + DISPLACEMENT + M[2] + 0 3 IAR + DISPLACEMENT + M[3] + + F = 1 T = 0 I = 0 EA = ADDRESS + 1 1 0 ADDRESS + M[1] + 1 2 0 ADDRESS + M[2] + 1 3 0 ADDRESS + M[3] + 1 0 1 M[ADDRESS] + 1 1 1 M[ADDRESS + M[1]] + 1 2 1 M[ADDRESS + M[2]] + 1 3 1 M[ADDRESS + M[3]] + + Loads or stores are then made to/from MEM[EA]. Some instructions have special + weird addressing modes. Simulator code precomputes standard addressing for + all instructions though it's not always used. + + General notes: + + Adding I/O devices requires modifications to three modules: + + ibm1130_defs.h add interrupt request definitions + ibm1130_cpu.c add XIO command linkages + ibm1130_sys.c add to sim_devices +*/ + +/* ------------------------------------------------------------------------ + * Definitions + * ------------------------------------------------------------------------ */ + +#include + +#include "ibm1130_defs.h" + +#define save_ibkpt (cpu_unit.u3) /* will be SAVEd */ + +#define UPDATE_INTERVAL 2500 // GUI: set to 100000/f where f = desired updates/second of 1130 time + +/* ------------------------------------------------------------------------ + * initializers for globals + * ------------------------------------------------------------------------ */ + +#define SIGN_BIT(v) ((v) & 0x8000) +#define DWSIGN_BIT(v) ((v) & 0x80000000) + +#define MODE_SS 3 /* RUNMODE values. SS and SMC are not implemented in this simulator */ +#define MODE_SMC 2 +#define MODE_INT_RUN 1 +#define MODE_RUN 0 +#define MODE_SI -1 +#define MODE_DISP -2 +#define MODE_LOAD -3 + +uint16 M[MAXMEMSIZE]; /* core memory, up to 32Kwords */ +uint16 ILSW[6] = {0,0,0,0,0,0}; /* interrupt level status words */ +int32 IAR; /* instruction address register */ +int32 SAR, SBR; /* storage address/buffer registers */ +int32 OP, TAG, CCC; /* instruction decoded pieces */ +int32 CES; /* console entry switches */ +int32 ACC, EXT; /* accumulator and extension */ +int32 RUNMODE; /* processor run/step mode */ +int32 ipl = -1; /* current interrupt level (-1 = not handling irq) */ +int32 iplpending = 0; /* interrupted IPL's */ +int32 tbit = 0; /* trace flag (causes level 5 IRQ after each instr) */ +int32 V = 0, C = 0; /* condition codes */ +int32 wait_state = 0; /* wait state (waiting for an IRQ) */ +int32 int_req = 0; /* sum of interrupt request levels active */ +int32 int_mask; /* current active interrupt mask (ipl sensitive) */ +int32 SR = 0; /* switch register */ +int32 DR = 0; /* display register */ +int32 mem_mask; +int32 IPS = 0; /* throttle: instructions per second */ +int32 ibkpt_addr = -1; /* breakpoint addr */ + +t_bool display_console = 1; + +/* ------------------------------------------------------------------------ + * Function declarations + * ------------------------------------------------------------------------ */ + +t_stat cpu_ex (t_value *vptr, t_addr addr, UNIT *uptr, int32 sw); +t_stat cpu_dep (t_value val, t_addr addr, UNIT *uptr, int32 sw); +t_stat cpu_reset (DEVICE *dptr); +t_stat cpu_svc (UNIT *uptr); +t_stat cpu_set_size (UNIT *uptr, int32 value); + +t_stat console_reset (DEVICE *dptr); + +extern t_stat ts_wr (int32 data, int32 addr, int32 access); + +extern UNIT cr_unit; + +void calc_ints (void); + +static t_bool bsctest (int32 DSPLC, t_bool reset_V); +static void exit_irq (void); +static void trace_instruction (void); + +static int32 int_masks[6] = { + 0x00, 0x20, 0x30, 0x38, 0x3C, 0x3E /* IPL 0 is highest prio (sees no other interrupts) */ +}; + +static void init_console_window (void); +static void destroy_console_window (void); +static void sleep_msec (int msec); + +/* ------------------------------------------------------------------------ + * cpu IO state + * ------------------------------------------------------------------------ */ + +static int con_dsw = 0; + +/* ------------------------------------------------------------------------ + * CPU data structures: + * cpu_dev CPU device descriptor + * cpu_unit CPU unit descriptor + * cpu_reg CPU register list + * cpu_mod CPU modifier list + * ------------------------------------------------------------------------ */ + +UNIT cpu_unit = { UDATA (&cpu_svc, UNIT_FIX + UNIT_BINK, INIMEMSIZE) }; + +REG cpu_reg[] = { + { HRDATA (IAR, IAR, 32) }, + { HRDATA (ACC, ACC, 32) }, + { HRDATA (EXT, EXT, 32) }, + { FLDATA (Oflow, V, 1) }, + { FLDATA (Carry, C, 1) }, + { HRDATA (CES, CES, 32) }, + { HRDATA (ipl, ipl, 32), REG_RO }, + { HRDATA (iplpending, iplpending, 32), REG_RO }, + { HRDATA (wait_state, wait_state, 32)}, + { HRDATA (DSW, con_dsw, 32), REG_RO }, + { HRDATA (RUNMODE, RUNMODE, 32) }, + { HRDATA (BREAK, ibkpt_addr, 32) }, + { ORDATA (WRU, sim_int_char, 8) }, + { FLDATA (IntRun, tbit, 1) }, + + { HRDATA (ILSW0, ILSW[0], 32), REG_RO }, + { HRDATA (ILSW1, ILSW[1], 32), REG_RO }, + { HRDATA (ILSW2, ILSW[2], 32), REG_RO }, + { HRDATA (ILSW3, ILSW[3], 32), REG_RO }, + { HRDATA (ILSW4, ILSW[4], 32), REG_RO }, + { HRDATA (ILSW5, ILSW[5], 32), REG_RO }, + + { HRDATA (IPS, IPS, 32) }, + + { NULL} +}; + +MTAB cpu_mod[] = { + { UNIT_MSIZE, 4096, NULL, "4KW", &cpu_set_size}, + { UNIT_MSIZE, 8192, NULL, "8KW", &cpu_set_size}, + { UNIT_MSIZE, 16384, NULL, "16KW", &cpu_set_size}, + { UNIT_MSIZE, 32768, NULL, "32KW", &cpu_set_size}, + { 0 } }; + +DEVICE cpu_dev = { + "CPU", &cpu_unit, cpu_reg, cpu_mod, + 1, 16, 16, 1, 16, 16, + &cpu_ex, &cpu_dep, &cpu_reset, + NULL, NULL, NULL }; + +REG console_reg[] = { // the GUI, so you can use Enable/Disable console + {HRDATA (*DEVENB, display_console, 1) }, + {NULL} +}; + +DEVICE console_dev = { + "CONSOLE", NULL, console_reg, NULL, + 0, 16, 16, 1, 16, 16, + NULL, NULL, console_reset, + NULL, NULL, NULL }; + +/* ------------------------------------------------------------------------ + Memory read/write -- save SAR and SBR on the way in and out + * ------------------------------------------------------------------------ */ + +int32 ReadW (int32 a) +{ + SAR = a; + SBR = (int32) M[(a) & mem_mask]; + return SBR; +} + +void WriteW (int32 a, int32 d) +{ + SAR = a; + SBR = d; + M[a & mem_mask] = (int16) d; +} + +/* ------------------------------------------------------------------------ + * upcase - force a string to uppercase (ASCII) + * ------------------------------------------------------------------------ */ + +char *upcase (char *str) +{ + char *s; + + for (s = str; *s; s++) { + if (*s >= 'a' && *s <= 'z') + *s -= 32; + } + + return str; +} + +/* ------------------------------------------------------------------------ + * calc_ints - set appropriate bits in int_req if any interrupts are pending on given levels + * + * int_req: + * bit 5 4 3 2 1 0 + * \ \ \ \ \ \ + * \ \ \ \ \ interrupt level 5 pending (lowest priority) + * \ . . . + * interrupt level 0 pending (highest priority) + * + * int_mask is set according to current interrupt level (ipl) + * + * 0 0 0 0 0 0 ipl = 0 (currently servicing highest priority interrupt) + * 1 0 0 0 0 0 1 + * 1 1 0 0 0 0 2 + * 1 1 1 0 0 0 3 + * 1 1 1 1 0 0 4 + * 1 1 1 1 1 0 5 (currently servicing lowest priority interrupt) + * 1 1 1 1 1 1 -1 (not servicing an interrupt) + * ------------------------------------------------------------------------ */ + +void calc_ints (void) +{ + register int i; + register int32 newbits = 0; + + GUI_BEGIN_CRITICAL_SECTION // using critical section here so we don't mislead the GUI thread + + for (i = 6; --i >= 0; ) { + newbits >>= 1; + if (ILSW[i]) + newbits |= 0x20; + } + + int_req = newbits; + int_mask = (ipl < 0) ? 0xFFFF : int_masks[ipl]; /* be sure this is set correctly */ + + GUI_END_CRITICAL_SECTION +} + +/* ------------------------------------------------------------------------ + * instruction processor + * ------------------------------------------------------------------------ */ + +#define INCREMENT_IAR IAR = (IAR + 1) & mem_mask +#define DECREMENT_IAR IAR = (IAR - 1) & mem_mask + +void bail (char *msg) +{ + fprintf(stderr, "%s\n", msg); + exit(1); +} + +static void weirdop (char *msg, int offset) +{ + fprintf(stderr, "Weird opcode: %s at %04x\n", msg, IAR+offset); +} + +static char *xio_devs[] = { + "0?", "console", "1142card", "1134papertape", + "dsk0", "1627plot", "1132print", "switches", + "1231omr", "2501card", "comm", "b?", + "sys7", "d?", "e?", "f?", + "10?", "dsk1", "dsk2", "dsk3", + "dsk4", "dsk5", "dsk6", "dsk7+", + "18?", "2250disp", "1a?", "1b", + "1c?", "1d?", "1e?", "1f?" +}; + +static char *xio_funcs[] = { + "0?", "write", "read", "sense_irq", + "control", "initw", "initr", "sense" +}; + +static t_stat reason; /* execution loop control */ +static t_bool running = FALSE; +static t_bool power = TRUE; + +t_stat sim_instr (void) +{ + extern int32 sim_interval; + extern UNIT *sim_clock_queue; + int32 i, eaddr, INDIR, IR, F, DSPLC, word2, oldval, newval, src, src2, dst, abit, xbit; + int32 iocc_addr, iocc_op, iocc_dev, iocc_func, iocc_mod; + char msg[50]; + int cwincount = 0, idelay, status; + static long ninstr = 0; + + if (running) /* this is definitely not reentrant */ + return -1; + + if (! power) /* this matters only to the GUI */ + return STOP_POWER_OFF; + + running = TRUE; + + mem_mask = MEMSIZE - 1; /* set other useful variables */ + calc_ints(); + + /* Main instruction fetch/decode loop */ + + reason = 0; + + idelay = (IPS == 0) ? 0 : 1000/IPS; + +#ifdef GUI_SUPPORT + update_gui(TRUE); +#endif + + while (reason == 0) { +#ifdef GUI_SUPPORT + if (idelay) { /* if we're running in slow mode, update GUI every time */ + update_gui(TRUE); + sleep_msec(idelay); + } + else { +#if (UPDATE_INTERVAL > 0) + if (--cwincount <= 0) { + update_gui(FALSE); /* update console lamps only every so many instructions */ + cwincount = UPDATE_INTERVAL + (rand() % MIN(UPDATE_INTERVAL, 32)); + } +#else + update_gui(FALSE); +#endif // UPDATE_INTERVAL + } +#endif // GUI_SUPPORT + + if (sim_interval <= 0) { /* any events timed out? */ + if (sim_clock_queue != NULL) { + if ((status = sim_process_event()) != 0) + reason = status; + calc_ints(); + continue; + } + } + + if (int_req & int_mask) { /* any pending interrupts? */ + for (i = 0; i <= 5; i++) /* find highest pending interrupt */ + if ((int_req & int_mask) & (0x20 >> i)) + break; + + if (i >= 6) { /* nothing to do? */ + calc_ints(); /* weird. recalculate */ + continue; /* back to fetch */ + } + + GUI_BEGIN_CRITICAL_SECTION + + if (ipl >= 0) /* save previous IPL in bit stack */ + iplpending |= (0x20 >> ipl); + + ipl = i; /* set new interrupt level */ + int_mask = int_masks[i]; /* set appropriate mask */ + + GUI_END_CRITICAL_SECTION + + wait_state = 0; /* exit wait state */ + eaddr = ReadW(8+i); /* get IRQ vector */ + WriteW(eaddr, IAR); /* save IAR */ + IAR = (eaddr+1) & mem_mask; /* go to next address */ + continue; /* now continue processing */ + } /* end if int_req */ + + if (wait_state) { /* waiting? */ + sim_interval = 0; /* run the clock out */ + + if (sim_qcount() <= 1) { /* waiting for keyboard only */ + if (keyboard_is_locked()) { /* CPU is not expecting a keystroke */ + if (wait_state == WAIT_OP) + reason = STOP_WAIT; /* end the simulation */ + else + reason = STOP_INVALID_INSTR; + } + else { /* we are actually waiting for a keystroke */ + if ((status = sim_process_event()) != 0) /* get it with wait_state still set */ + reason = status; + } + } + else if (sim_clock_queue == NULL) { /* not waiting for anything */ + if (wait_state == WAIT_OP) + reason = STOP_WAIT; /* end the simulation */ + else + reason = STOP_INVALID_INSTR; + } + + continue; + } + + if (IAR == ibkpt_addr) { /* simulator breakpoint? */ + save_ibkpt = ibkpt_addr; /* save bkpt */ + ibkpt_addr = ibkpt_addr | ILL_ADR_FLAG; /* disable */ + sim_activate(&cpu_unit, 1); /* sched re-enable after next instruction */ + reason = STOP_IBKPT; /* stop simulation */ + cwincount = 0; + continue; + } + + ninstr++; + trace_instruction(); /* log CPU details if logging is enabled */ + + IR = ReadW(IAR); /* fetch 1st word of instruction */ + INCREMENT_IAR; + sim_interval = sim_interval - 1; /* this constitutes one tick of the simulation clock */ + + OP = (IR >> 11) & 0x1F; /* opcode */ + F = IR & 0x0400; /* format bit: 1 = long instr */ + TAG = IR & 0x0300; /* tag bits: index reg x */ + if (TAG) + TAG >>= 8; + + // here I compute the usual effective address on the assumption that the instruction will need it. Some don't. + + if (F) { /* long instruction, ASSUME it's valid (have to decrement IAR if not) */ + INDIR = IR & 0x0080; /* indirect bit */ + DSPLC = IR & 0x007F; /* displacement or modifier */ + if (DSPLC & 0x0040) + DSPLC |= ~ 0x7F; /* sign extend */ + + word2 = ReadW(IAR); /* get reference address */ + INCREMENT_IAR; /* bump the instruction address register */ + + eaddr = word2; /* assume standard addressing & compute effective address */ + if (TAG) /* if indexed */ + eaddr += ReadW(TAG); /* add index register value (stored in core) */ + if (INDIR) /* if indirect addressing */ + eaddr = ReadW(eaddr); /* pick up referenced address */ + } + else { /* short instruction, use displacement */ + INDIR = 0; /* never indirect */ + DSPLC = IR & 0x00FF; /* get displacement */ + if (DSPLC & 0x0080) + DSPLC |= ~ 0xFF; + + if (TAG) /* if indexed */ + eaddr = ReadW(TAG) + DSPLC; /* add index register value (stored in core) */ + else + eaddr = IAR + DSPLC; /* otherwise relative to IAR after fetch */ + } + + switch (OP) { /* decode instruction */ + case 0x01: /* --- XIO --- */ + iocc_addr = ReadW(eaddr); /* get IOCC packet */ + iocc_op = ReadW(eaddr|1); /* note 'or' not plus, address must be even for proper operation */ + + iocc_dev = (iocc_op >> 11) & 0x001F; + iocc_func = (iocc_op >> 8) & 0x0007; + iocc_mod = iocc_op & 0x00FF; + + trace_io("* XIO %s %s mod %02x addr %04x", xio_funcs[iocc_func], xio_devs[iocc_dev], iocc_mod, iocc_addr); + + ACC = 0; /* ACC is destroyed, and default XIO_SENSE_DEV result is 0 */ + + switch (iocc_func) { + case XIO_UNUSED: + sprintf(msg, "Unknown XIO op %x on XIO device %02x", iocc_func, iocc_dev); + xio_error(msg); + break; + + case XIO_SENSE_IRQ: /* examine current Interrupt Level Status Word */ + ACC = (ipl >= 0) ? ILSW[ipl] : 0; + break; + + default: /* perform device-specific operation */ + switch (iocc_dev) { + case 0x01: /* console keyboard and printer */ + xio_1131_console(iocc_addr, iocc_func, iocc_mod); + break; + case 0x02: /* 1142 card reader/punch */ + xio_1142_card(iocc_addr, iocc_func, iocc_mod); + break; + case 0x03: /* 1134 paper tape reader/punch */ + xio_1134_papertape(iocc_addr, iocc_func, iocc_mod); + break; + case 0x04: /* CPU disk storage */ + xio_disk(iocc_addr, iocc_func, iocc_mod, 0); + break; + case 0x05: /* 1627 plotter */ + xio_1627_plotter(iocc_addr, iocc_func, iocc_mod); + break; + case 0x06: /* 1132 Printer */ + xio_1132_printer(iocc_addr, iocc_func, iocc_mod); + break; + case 0x07: /* console switches, stop key, run mode */ + xio_1131_switches(iocc_addr, iocc_func, iocc_mod); + break; + case 0x08: /* 1231 optical mark reader */ + xio_1231_optical(iocc_addr, iocc_func, iocc_mod); + break; + case 0x09: /* 2501 card reader */ + xio_2501_card(iocc_addr, iocc_func, iocc_mod); + break; + case 0x0a: /* synchronous comm adapter */ + xio_1131_synch(iocc_addr, iocc_func, iocc_mod); + break; + case 0x0c: /* IBM System/7 interprocessor link */ + xio_system7(iocc_addr, iocc_func, iocc_mod); + break; + case 0x11: /* 2310 Disk Storage, Drive 1, or 2311 Disk Storage Drive. Drive 1, Disk 1 */ + xio_disk(iocc_addr, iocc_func, iocc_mod, 1); + break; + case 0x12: /* 2310 Disk Storage, Drive 2, or 2311 Disk Storage Drive. Drive 1, Disk 2 */ + xio_disk(iocc_addr, iocc_func, iocc_mod, 2); + break; + case 0x13: /* 2310 Disk Storage, Drive 3, or 2311 Disk Storage Drive. Drive 1, Disk 3 */ + xio_disk(iocc_addr, iocc_func, iocc_mod, 3); + break; + case 0x14: /* 2310 Disk Storage, Drive 4, or 2311 Disk Storage Drive. Drive 1, Disk 4 */ + xio_disk(iocc_addr, iocc_func, iocc_mod, 4); + break; + case 0x15: /* 1403 Printer */ + xio_1403_printer(iocc_addr, iocc_func, iocc_mod); + break; + case 0x16: /* 2311 Disk Storage Drive. Drive 1, Disk 5 */ + xio_disk(iocc_addr, iocc_func, iocc_mod, -1); + break; + case 0x17: /* 2311 Disk Storage Drive, Drive 2, Disk 1 through 5 */ + xio_disk(iocc_addr, iocc_func, iocc_mod, -1); + break; + case 0x19: /* 2250 Display Unit */ + xio_2250_display(iocc_addr, iocc_func, iocc_mod); + break; + default: + sprintf(msg, "XIO on unknown device %02x", iocc_dev); + xio_error(msg); + break; + } + } + + calc_ints(); /* after every XIO, reset int_mask just in case */ + break; + + case 0x02: /* --- SLA,SLT,SLC,SLCA,NOP - Shift Left family --- */ + if (F) { + weirdop("Long Left Shift", -2); + DECREMENT_IAR; + } + + CCC = ((TAG == 0) ? DSPLC : ReadW(TAG)) & 0x003F; + if (CCC == 0) + break; /* shift of zero is a NOP */ + + switch (IR & 0x00C0) { + case 0x0040: /* SLCA */ + if (TAG) { + while (CCC > 0 && (ACC & 0x8000) == 0) { + ACC <<= 1; + CCC--; + } + C = (CCC != 0); + WriteW(TAG, ReadW(TAG) & 0xFF00 | CCC); /* put low 6 bits back into index register and zero bits 8 and 9 */ + break; + } + /* if TAG == 0, fall through and treat like normal shift SLA */ + + case 0x0000: /* SLA */ + while (CCC > 0) { + C = (ACC & 0x8000); + ACC = (ACC << 1) & 0xFFFF; + CCC--; + } + break; + + case 0x00C0: /* SLC */ + if (TAG) { + while (CCC > 0 && (ACC & 0x8000) == 0) { + abit = (EXT & 0x8000) >> 15; + ACC = ((ACC << 1) & 0xFFFF) | abit; + EXT = (EXT << 1); + CCC--; + } + C = (CCC != 0); + WriteW(TAG, ReadW(TAG) & 0xFF00 | CCC); /* put 6 bits back into low byte of index register */ + break; + } + /* if TAG == 0, fall through and treat like normal shift SLT */ + + case 0x0080: /* SLT */ + while (CCC > 0) { + C = (ACC & 0x8000); + abit = (EXT & 0x8000) >> 15; + ACC = ((ACC << 1) & 0xFFFF) | abit; + EXT = (EXT << 1) & 0xFFFF; + CCC--; + } + break; + + default: + bail("SLA switch, can't happen"); + break; + } + break; + + case 0x03: /* --- SRA, SRT, RTE - Shift Right family --- */ + if (F) { + weirdop("Long Right Shift", -2); + DECREMENT_IAR; + } + + CCC = ((TAG == 0) ? DSPLC : ReadW(TAG)) & 0x3F; + if (CCC == 0) + break; /* NOP */ + + switch (IR & 0x00C0) { + case 0x0000: /* SRA */ + ACC = (CCC < 16) ? ((ACC & 0xFFFF) >> CCC) : 0; + CCC = 0; + break; + + case 0x0040: /* invalid */ + wait_state = WAIT_INVALID_OP; + break; + + case 0x0080: /* SRT */ + while (CCC > 0) { + xbit = (ACC & 0x0001) << 15; + abit = (ACC & 0x8000); + ACC = (ACC >> 1) & 0x7FFF | abit; + EXT = (EXT >> 1) & 0x7FFF | xbit; + CCC--; + } + break; + + case 0x00C0: /* RTE */ + while (CCC > 0) { + abit = (EXT & 0x0001) << 15; + xbit = (ACC & 0x0001) << 15; + ACC = (ACC >> 1) & 0x7FFF | abit; + EXT = (EXT >> 1) & 0x7FFF | xbit; + CCC--; + } + break; + + default: + bail("SRA switch, can't happen"); + break; + } + break; + + case 0x04: /* --- LDS - Load Status --- */ + if (F) { /* never fetches second word */ + weirdop("Long LDS", -2); + DECREMENT_IAR; + } + + V = (DSPLC & 1); + C = (DSPLC & 2) >> 1; + break; + + case 0x05: /* --- STS - Store Status --- */ + newval = ReadW(eaddr) & 0xFF00; + if (C) + newval |= 2; + if (V) + newval |= 1; + + WriteW(eaddr, newval); + C = V = 0; /* clear flags after storing */ + break; + + case 0x06: /* --- WAIT --- */ + wait_state = WAIT_OP; + /* note: not valid in long mode, but what happens if we try? */ + if (F) { + weirdop("Long WAIT", -2); + DECREMENT_IAR; /* assume it wouldn't have fetched 2nd word */ + } + break; + + case 0x08: /* --- BSI - Branch and store IAR --- */ + if (F) { + if (bsctest(IR, F)) /* do standard BSC long format testing */ + break; /* if any condition is true, do nothing */ + } + WriteW(eaddr, IAR); /* do subroutine call */ + IAR = (eaddr + 1) & mem_mask; + break; + + case 0x09: /* --- BSC - Branch and skip on Condition --- */ + if (F) { + if (bsctest(IR, F)) /* long format; any indicator cancels branch */ + break; + + IAR = eaddr; /* no indicator means branch taken */ + } + else { /* short format: skip if any indicator hits */ + if (bsctest(IR, F)) + INCREMENT_IAR; + } +// 27Mar02: moved this test out of the (F) condition; BOSC works even in the +// short form. The displacement field in this instruction is always the set of +// condition bits, and the interrupt clear bit doesn't collide. + if (DSPLC & 0x40) { /* BOSC = exit from interrupt handler */ + exit_irq(); + cwincount = 0; + } + break; + + case 0x0c: /* --- LDX - Load Index --- */ + if (F) + eaddr = (INDIR) ? ReadW(word2) : word2; + else + eaddr = DSPLC; + + if (TAG) + WriteW(TAG, eaddr); + else + IAR = eaddr; /* what happens in short form? can onlyjump to low addresses? */ + break; + + case 0x0d: /* --- STX - Store Index --- */ + if (F) { /* compute EA without any indexing */ + eaddr = (INDIR) ? ReadW(word2) : word2; + } + else { + eaddr = IAR + DSPLC; + } + WriteW(eaddr, TAG ? ReadW(TAG) : IAR); + break; + + case 0x0e: /* --- MDX - Modify Index and Skip --- */ + if (F) { /* long mode: adjust memory location */ + if (TAG) { + oldval = ReadW(TAG); /* add word2 to index */ + newval = oldval + (INDIR ? ReadW(word2) : word2); + WriteW(TAG, newval); + } + else { + oldval = ReadW(word2); + DSPLC = IR & 0x00FF; /* use extended displacement (includes INDIR bit) */ + if (DSPLC & 0x0080) + DSPLC |= ~ 0xFF; + newval = oldval + DSPLC; /* add modifier to @word2 */ + WriteW(word2, newval); + } + } + else { /* short mode: adust IAR or index */ + if (TAG) { + oldval = ReadW(TAG);/* add displacement to index */ + newval = oldval + DSPLC; + WriteW(TAG, newval); + } + else { + oldval = IAR; /* add displacement to IAR */ + newval = IAR + DSPLC; + IAR = newval & mem_mask; + } + } + + if ((F || TAG) && ((newval == 0) || ((oldval & 0x8000) != (newval & 0x8000)))) + INCREMENT_IAR; /* skip if index sign change or zero */ + + break; + + case 0x10: /* --- A - Add --- */ + /* in adds and subtracts, carry is set or cleared, overflow is set only */ + src = ReadW(eaddr); + src2 = ACC; + ACC = (ACC + src) & 0xFFFF; + + C = ACC < src; + if (! V) + V = SIGN_BIT((~src ^ src2) & (src ^ ACC)); + break; + + case 0x11: /* --- AD - Add Double --- */ + src = ((ACC << 16) + (EXT & 0xFFFF)); + src2 = (ReadW(eaddr) << 16) + ReadW(eaddr|1); + dst = src + src2; + ACC = (dst >> 16) & 0xFFFF; + EXT = dst & 0xFFFF; + + C = (unsigned int32) dst < (unsigned int32) src; + if (! V) + V = DWSIGN_BIT((~src ^ src2) & (src ^ dst)); + break; + + case 0x12: /* --- S - Subtract --- */ + src = ACC; + src2 = ReadW(eaddr); + ACC = (ACC-src2) & 0xFFFF; + + C = src2 < src; + if (! V) + V = SIGN_BIT((src ^ src2) & (src ^ ACC)); + break; + + case 0x13: /* --- SD - Subtract Double --- */ + src = ((ACC << 16) + (EXT & 0xFFFF)); + src2 = (ReadW(eaddr) << 16) + ReadW(eaddr|1); + dst = src - src2; + ACC = (dst >> 16) & 0xFFFF; + EXT = dst & 0xFFFF; + + C = (unsigned int32) src2 < (unsigned int32) src; + if (! V) + V = DWSIGN_BIT((src ^ src2) & (src ^ dst)); + break; + + case 0x14: /* --- M - Multiply --- */ + dst = ACC * ReadW(eaddr); + ACC = (dst >> 16) & 0xFFFF; + EXT = dst & 0xFFFF; + break; + + case 0x15: /* --- D - Divide --- */ + src = ((ACC << 16) + EXT); + src2 = ReadW(eaddr); + if (src2 == 0) + V = 1; /* divide by zero just sets overflow, ACC & EXT are undefined */ + else { + ACC = (src / src2) & 0xFFFF; + EXT = (src % src2) & 0xFFFF; + } + break; + + case 0x18: /* --- LD - Load ACC --- */ + ACC = ReadW(eaddr); + break; + + case 0x19: /* --- LDD - Load Double --- */ + ACC = ReadW(eaddr); + EXT = ReadW(eaddr|1); /* notice address is |1 not +1 */ + break; + + case 0x1a: /* --- STO - Store ACC --- */ + WriteW(eaddr, ACC); + break; + + case 0x1b: /* --- STD - Store Double --- */ + WriteW(eaddr|1, EXT); + WriteW(eaddr, ACC); /* order is important: if odd addr, only ACC is stored */ + break; + + case 0x1c: /* --- AND - Logical AND --- */ + ACC &= ReadW(eaddr); + break; + + case 0x1d: /* --- OR - Logical OR --- */ + ACC |= ReadW(eaddr); + break; + + case 0x1e: /* --- EOR - Logical Excl OR --- */ + ACC ^= ReadW(eaddr); + break; + + default: +/* all invalid instructions act like waits */ +/* case 0x00: */ +/* case 0x07: */ +/* case 0x0a: */ +/* case 0x0b: */ +/* case 0x0e: */ +/* case 0x0f: */ +/* case 0x16: */ +/* case 0x17: */ +/* case 0x1f: */ + wait_state = WAIT_INVALID_OP; + if (F) + DECREMENT_IAR; /* assume it wouldn't have fetched 2nd word? */ + + break; + } /* end instruction decode switch */ + + if (RUNMODE != MODE_RUN && RUNMODE != MODE_INT_RUN) + reason = STOP_WAIT; + + if (tbit && (ipl < 0)) { /* if INT_RUN mode, set IRQ5 after this instr */ + GUI_BEGIN_CRITICAL_SECTION + SETBIT(con_dsw, CON_DSW_INT_RUN); + SETBIT(ILSW[5], ILSW_5_INT_RUN); + int_req |= INT_REQ_5; + GUI_END_CRITICAL_SECTION + } + } /* end main loop */ + + running = FALSE; + + if (reason == STOP_WAIT || reason == STOP_INVALID_INSTR) { + wait_state = 0; // on resume, don't wait + } + + + return reason; +} + +/* ------------------------------------------------------------------------ + * bsctest - perform standard set of condition tests. We return TRUE if any + * of the condition bits specified in DSPLC test positive, FALSE if none are true. + * If reset_V is TRUE, we reset the oVerflow flag after testing it. + * ------------------------------------------------------------------------ */ + +static t_bool bsctest (int32 DSPLC, t_bool reset_V) +{ + if (DSPLC & 0x01) { /* Overflow off (note inverted sense) */ + if (! V) + return TRUE; + else if (reset_V) /* reset after testing */ + V = 0; + } + + if (DSPLC & 0x02) { /* Carry off (note inverted sense) */ + if (! C) + return TRUE; + } + + if (DSPLC & 0x04) /* Even */ + if ((ACC & 1) == 0) + return TRUE; + + if (DSPLC & 0x08) /* Positive */ + if ((ACC & 0x8000) == 0 && ACC != 0) + return TRUE; + + if (DSPLC & 0x10) /* Negative */ + if (ACC & 0x8000) + return TRUE; + + if (DSPLC & 0x20) /* Zero */ + if (ACC == 0) + return TRUE; + + return FALSE; +} + +/* ------------------------------------------------------------------------ + * exit_irq - pop interrupt stack as part of return from subroutine (BOSC) + * ------------------------------------------------------------------------ */ + +static void exit_irq (void) +{ + int i, bit; + + GUI_BEGIN_CRITICAL_SECTION + + ipl = -1; /* default: return to main processor level */ + int_mask = 0xFFFF; + + if (iplpending) { /* restore previous interrupt status */ + for (i = 0, bit = 0x20; i < 6; i++, bit >>= 1) { + if (iplpending & bit) { + iplpending &= ~bit; + ipl = i; + int_mask = int_masks[i]; + break; + } + } + } + GUI_END_CRITICAL_SECTION + + calc_ints(); /* recompute pending interrupt mask */ +} /* because we probably cleared some ILSW bits before this instruction */ + +/* ------------------------------------------------------------------------ + * SIMH required routines + * ------------------------------------------------------------------------ */ + +/* ------------------------------------------------------------------------ + * Reset routine + * ------------------------------------------------------------------------ */ + +t_stat cpu_reset (DEVICE *dptr) +{ + wait_state = 0; /* cancel wait */ + + GUI_BEGIN_CRITICAL_SECTION + + int_req = 0; /* reset all interrupts */ + ipl = -1; + int_mask = 0xFFFF; + iplpending = 0; + memset(ILSW, 0, sizeof(ILSW)); + + con_dsw = 0; /* clear int req and prot stop bits */ + tbit = 0; /* cancel INT_RUN mode */ + + C = V = 0; /* clear processor flags */ + IAR = SAR = SBR = 0; /* clear IAR and other registers */ + ACC = EXT = OP = TAG = CCC = C = V = 0; + + mem_mask = MEMSIZE - 1; /* wraparound mask */ + + GUI_END_CRITICAL_SECTION + + return cpu_svc(&cpu_unit); /* reset breakpoint */ +} + +// reset for the "console" display device + +t_stat console_reset (DEVICE *dptr) +{ + if (display_console) + init_console_window(); + else + destroy_console_window(); + + return SCPE_OK; +} + +/* ------------------------------------------------------------------------ + * Memory examine + * ------------------------------------------------------------------------ */ + +t_stat cpu_ex (t_value *vptr, t_addr addr, UNIT *uptr, int32 sw) +{ + if (vptr == NULL) return SCPE_ARG; + + /* check this out -- save command hits it in weird way */ + /* I wish I remembered what I meant when I wrote that */ + if (addr < MEMSIZE) { + *vptr = M[addr] & 0xFFFF; + return SCPE_OK; + } + return SCPE_NXM; +} + +/* ------------------------------------------------------------------------ + * Memory deposit + * ------------------------------------------------------------------------ */ + +t_stat cpu_dep (t_value val, t_addr addr, UNIT *uptr, int32 sw) +{ + if (addr < MEMSIZE) { + M[addr] = val & 0xFFFF; + return SCPE_OK; + } + return SCPE_NXM; +} + +/* ------------------------------------------------------------------------ + * Breakpoint service + * ------------------------------------------------------------------------ */ + +t_stat cpu_svc (UNIT *uptr) +{ + if ((ibkpt_addr & ~ILL_ADR_FLAG) == save_ibkpt) + ibkpt_addr = save_ibkpt; + + save_ibkpt = -1; + return SCPE_OK; +} + +/* ------------------------------------------------------------------------ + * Memory allocation + * ------------------------------------------------------------------------ */ + +t_stat cpu_set_size (UNIT *uptr, int32 value) +{ + t_bool used; + int32 i; + + if ((value <= 0) || (value > MAXMEMSIZE) || ((value & 0xFFF) != 0)) + return SCPE_ARG; + + for (i = value, used = FALSE; i < (int32) MEMSIZE; i++) { + if (M[i] != 0) { + used = TRUE; + break; + } + } + + if (used && ! get_yn ("Really truncate memory [N]?", FALSE)) + return SCPE_OK; + + for (i = MEMSIZE; i < value; i++) /* clear expanded area */ + M[i] = 0; + + MEMSIZE = value; + mem_mask = MEMSIZE - 1; + + return SCPE_OK; +} + +/* ------------------------------------------------------------------------ + * IO function for console switches + * ------------------------------------------------------------------------ */ + +void xio_1131_switches (int32 addr, int32 func, int32 modify) +{ + char msg[80]; + + switch (func) { + case XIO_READ: + WriteW(addr, CES); + break; + + case XIO_SENSE_DEV: + ACC = con_dsw; + if (modify & 0x01) { /* reset interrupts */ + CLRBIT(con_dsw, CON_DSW_PROGRAM_STOP|CON_DSW_INT_RUN); + CLRBIT(ILSW[5], ILSW_5_INT_RUN); /* (these bits are set in the keyboard handler in 1130_stddev.c) */ + } + break; + + default: + sprintf(msg, "Invalid console switch XIO function %x", func); + xio_error(msg); + } +} + +/* ------------------------------------------------------------------------ + * Illegal IO operation. Not yet sure what the actual CPU does in this case + * ------------------------------------------------------------------------ */ + +void xio_error (char *msg) +{ + fprintf(stderr, "*** XIO error: %s\n", msg); +} + +/* ------------------------------------------------------------------------ + * LOG device - if attached to a file, records a CPU trace + * ------------------------------------------------------------------------ */ + +static t_stat log_reset (DEVICE *dptr); +static t_stat log_attach (UNIT *uptr, char *cptr); + +UNIT log_unit = { UDATA (NULL, UNIT_ATTABLE + UNIT_SEQ, 0) }; + +DEVICE log_dev = { + "LOG", &log_unit, NULL, NULL, + 1, 16, 16, 1, 16, 16, + NULL, NULL, log_reset, + NULL, log_attach, NULL }; + +t_stat fprint_sym (FILE *of, t_addr addr, t_value *val, UNIT *uptr, int32 sw); + +#ifdef WIN32 +# define CRLF "\r\n" +#else +# define CRLF "\n" +#endif + +static t_bool new_log; + +static t_stat log_attach (UNIT *uptr, char *cptr) +{ + unlink(cptr); // delete old log file, if present + new_log = TRUE; + return attach_unit(uptr, cptr); +} + +static void trace_instruction (void) +{ + t_value v[2]; + + if ((log_unit.flags & UNIT_ATT) == 0) + return; + + if (new_log) { + fseek(log_unit.fileref, 0, SEEK_END); + fprintf(log_unit.fileref, " IAR ACC EXT XR1 XR2 XR3 CVI OPERATION" CRLF); + fprintf(log_unit.fileref, "---- ---- ---- ---- ---- ---- --- ---------" CRLF); + new_log = FALSE; + } + + fprintf(log_unit.fileref, "%04x %04x %04x %04x %04x %04x %c%c%c ", + IAR & 0xFFFF, ACC & 0xFFFF, EXT & 0xFFFF, M[1] & 0xFFFF, M[2] & 0xFFFF, M[3] & 0xFFFF, + C ? 'C' : ' ', V ? 'V' : ' ', + (ipl < 0) ? ' ' : (ipl+'0')); + + v[0] = M[ IAR & mem_mask]; + v[1] = M[(IAR+1) & mem_mask]; + fprint_sym(log_unit.fileref, IAR & mem_mask, v, NULL, SWMASK('M')); + + fputs(CRLF, log_unit.fileref); +} + +void trace_io (char *fmt, ...) +{ + va_list args; + + if ((log_unit.flags & UNIT_ATT) == 0) + return; + + va_start(args, fmt); // get pointer to argument list + vfprintf(log_unit.fileref, fmt, args); // write errors to terminal (stderr) + va_end(args); + + fputs(CRLF, log_unit.fileref); +} + +static t_stat log_reset (DEVICE *dptr) +{ + if ((log_unit.flags & UNIT_ATT) == 0) + return SCPE_OK; + + fseek(log_unit.fileref, 0, SEEK_END); + fprintf(log_unit.fileref, "---RESET---" CRLF); + return SCPE_OK; +} + +/* ------------------------------------------------------------------------ + * Console display - on Windows builds (only) this code displays the 1130 console + * and toggle switches. It really enhances the experience. + * + * Currently, when the IPS throttle is nonzero, I update the display after every + * UPDATE_INTERVAL instructions, plus or minus a random amount to avoid aliased + * sampling in loops. When UPDATE_INTERVAL is defined as zero, we update every + * instruction no matter what the throttle. This makes the simulator too slow + * but it's cool and helpful during development. + * ------------------------------------------------------------------------ */ + +#ifndef GUI_SUPPORT + +void update_gui (int force) {} /* stubs for non-GUI builds */ +void forms_check (int set) {} +void print_check (int set) {} +void keyboard_select (int select) {} +void keyboard_selected (int select) {} +void disk_ready (int ready) {} +void disk_unlocked (int unlocked) {} +static void init_console_window (void) {} +static void destroy_console_window (void) {} +static void sleep_msec (int msec) {} +#else + +#ifdef WIN32 + +// only have a WIN32 gui right now + +#include +#include +#include "ibm1130res.h" + +static BOOL class_defined = FALSE; +static HWND hConsoleWnd = NULL; +static HBITMAP hBitmap = NULL; +static HFONT hFont = NULL; +static HFONT hBtnFont = NULL; +static HBRUSH hbLampOut = NULL; +static HBRUSH hbWhite = NULL; +static HBRUSH hbBlack = NULL; +static HBRUSH hbGray = NULL; +static HPEN hSwitchPen = NULL; +static HPEN hWhitePen = NULL; +static HPEN hBlackPen = NULL; +static HPEN hLtGreyPen = NULL; +static HPEN hGreyPen = NULL; +static HPEN hDkGreyPen = NULL; + +static HCURSOR hcArrow = NULL; +static HCURSOR hcHand = NULL; +static HINSTANCE hInstance; +static HDC hCDC = NULL; +static char szConsoleClassName[] = "1130CONSOLE"; +static DWORD PumpID = 0; +static HANDLE hPump = INVALID_HANDLE_VALUE; +static int bmwid, bmht; + +#define BUTTON_WIDTH 90 +#define BUTTON_HEIGHT 50 + +#define IDC_KEYBOARD_SELECT 0 +#define IDC_DISK_UNLOCK 1 +#define IDC_RUN 2 +#define IDC_PARITY_CHECK 3 +#define IDC_UNUSED 4 +#define IDC_FILE_READY 5 +#define IDC_FORMS_CHECK 6 +#define IDC_POWER_ON 7 +#define IDC_POWER 8 +#define IDC_PROGRAM_START 9 +#define IDC_PROGRAM_STOP 10 +#define IDC_LOAD_IAR 11 +#define IDC_KEYBOARD 12 +#define IDC_IMM_STOP 13 +#define IDC_RESET 14 +#define IDC_PROGRAM_LOAD 15 + +#define LAMPTIME 500 // 500 msec delay on updating +#define UPDATE_TIMER_ID 1 + +static struct tag_btn { + int x, y; + char *txt; + BOOL pushable, immed_off; + DWORD offtime; + COLORREF clr; + HBRUSH hbrLit, hbrDark; + HWND hBtn; +} btn[] = { + 0, 0, "KEYBOARD\nSELECT", FALSE, TRUE, 0, RGB(255,255,180), NULL, NULL, NULL, + 0, 1, "DISK\nUNLOCK", FALSE, TRUE, 0, RGB(255,255,180), NULL, NULL, NULL, + 0, 2, "RUN", FALSE, FALSE, 0, RGB(0,255,0), NULL, NULL, NULL, + 0, 3, "PARITY\nCHECK", FALSE, TRUE, 0, RGB(255,0,0), NULL, NULL, NULL, + + 1, 0, "", FALSE, TRUE, 0, RGB(255,255,180), NULL, NULL, NULL, + 1, 1, "FILE\nREADY", FALSE, TRUE, 0, RGB(0,255,0), NULL, NULL, NULL, + 1, 2, "FORMS\nCHECK", FALSE, TRUE, 0, RGB(255,255,0), NULL, NULL, NULL, + 1, 3, "POWER\nON", FALSE, TRUE, 0, RGB(255,255,180), NULL, NULL, NULL, + + 2, 0, "POWER", TRUE, TRUE, 0, RGB(255,255,180), NULL, NULL, NULL, + 2, 1, "PROGRAM\nSTART", TRUE, TRUE, 0, RGB(0,255,0), NULL, NULL, NULL, + 2, 2, "PROGRAM\nSTOP", TRUE, TRUE, 0, RGB(255,0,0), NULL, NULL, NULL, + 2, 3, "LOAD\nIAR", TRUE, TRUE, 0, RGB(0,0,255), NULL, NULL, NULL, + + 3, 0, "KEYBOARD", TRUE, TRUE, 0, RGB(255,255,180), NULL, NULL, NULL, + 3, 1, "IMM\nSTOP", TRUE, TRUE, 0, RGB(255,0,0), NULL, NULL, NULL, + 3, 2, "CHECK\nRESET", TRUE, TRUE, 0, RGB(0,0,255), NULL, NULL, NULL, + 3, 3, "PROGRAM\nLOAD", TRUE, TRUE, 0, RGB(0,0,255), NULL, NULL, NULL, +}; +#define NBUTTONS (sizeof(btn) / sizeof(btn[0])) + +LRESULT CALLBACK ConsoleWndProc (HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam); +static DWORD WINAPI Pump (LPVOID arg); + +/* ------------------------------------------------------------------------ + * sleep_msec - delay msec to throttle the cpu down + * ------------------------------------------------------------------------ */ + +static void sleep_msec (int msec) +{ + Sleep(msec); +} + +/* ------------------------------------------------------------------------ + * init_console_window - display the 1130 console. Actually just creates a thread + * to run the Pump routine which does the actual work. + * ------------------------------------------------------------------------ */ + +static void init_console_window (void) +{ + static BOOL did_atexit = FALSE; + + if (hConsoleWnd != NULL) + return; + + if (PumpID == 0) + hPump = CreateThread(NULL, 0, Pump, 0, 0, &PumpID); + + if (! did_atexit) { + atexit(destroy_console_window); + did_atexit = TRUE; + } +} + +/* ------------------------------------------------------------------------ + * destroy_console_window - delete GDI objects. + * ------------------------------------------------------------------------ */ + +#define NIXOBJECT(hObj) if (hObj != NULL) {DeleteObject(hObj); hObj = NULL;} + +static void destroy_console_window (void) +{ + int i; + + if (hConsoleWnd != NULL) + SendMessage(hConsoleWnd, WM_CLOSE, 0, 0); // cross thread call is OK + + if (hPump != INVALID_HANDLE_VALUE) { // this is not the most graceful way to do it + TerminateThread(hPump, 0); + hPump = INVALID_HANDLE_VALUE; + PumpID = 0; + hConsoleWnd = NULL; + } + if (hCDC != NULL) { + DeleteDC(hCDC); + hCDC = NULL; + } + + NIXOBJECT(hBitmap) + NIXOBJECT(hbLampOut) + NIXOBJECT(hFont) + NIXOBJECT(hBtnFont); + NIXOBJECT(hcHand) + NIXOBJECT(hSwitchPen) + NIXOBJECT(hLtGreyPen) + NIXOBJECT(hGreyPen) + NIXOBJECT(hDkGreyPen) + + for (i = 0; i < NBUTTONS; i++) { + NIXOBJECT(btn[i].hbrLit); + NIXOBJECT(btn[i].hbrDark); + } + +// if (class_defined) { +// UnregisterClass(hInstance, szConsoleClassName); +// class_defined = FALSE; +// } +} + +/* ------------------------------------------------------------------------ + * these variables hold the displayed versions of the system registers + * ------------------------------------------------------------------------ */ + +static int shown_iar = 0, shown_sar = 0, shown_sbr = 0, shown_afr = 0, shown_acc = 0, shown_ext = 0; +static int shown_op = 0, shown_tag = 0, shown_irq = 0, shown_ccc = 0, shown_cnd = 0, shown_wait = 0; +static int shown_ces = 0, shown_runmode = MODE_RUN; +static int CND; + +/* ------------------------------------------------------------------------ + * RedrawRegion - mark a region for redrawing without background erase + * ------------------------------------------------------------------------ */ + +static void RedrawRegion (HWND hWnd, int left, int top, int right, int bottom) +{ + RECT r; + + r.left = left; + r.top = top; + r.right = right; + r.bottom = bottom; + + InvalidateRect(hWnd, &r, FALSE); +} + +/* ------------------------------------------------------------------------ + * RepaintRegion - mark a region for redrawing with background erase + * ------------------------------------------------------------------------ */ + +static void RepaintRegion (HWND hWnd, int left, int top, int right, int bottom) +{ + RECT r; + + r.left = left; + r.top = top; + r.right = right; + r.bottom = bottom; + + InvalidateRect(hWnd, &r, TRUE); +} + +/* ------------------------------------------------------------------------ + * update_gui - sees if anything on the console display has changed, and invalidates + * the changed regions. Then it calls UpdateWindow to force an immediate repaint. This + * function (update_gui) should probably not be called every time through the main + * instruction loop but it should be called at least whenever wait_state or int_req change, and then + * every so many instructions. It's also called after every simh command so manual changes are + * reflected instantly. + * ------------------------------------------------------------------------ */ + +void update_gui (BOOL force) +{ + int i, sts; + + if (hConsoleWnd == NULL) + return; + + CND = 0; /* combine carry and V as two bits */ + if (C) + CND |= 2; + if (V) + CND |= 1; + + if (RUNMODE == MODE_LOAD) + SBR = CES; /* in load mode, SBR follows the console switches */ + + if (IAR != shown_iar) + {shown_iar = IAR; RedrawRegion(hConsoleWnd, 75, 8, 364, 32);} /* lamps: don't bother erasing bkgnd */ + if (SAR != shown_sar) + {shown_sar = SAR; RedrawRegion(hConsoleWnd, 75, 42, 364, 65);} + if (ACC != shown_acc) + {shown_acc = ACC; RedrawRegion(hConsoleWnd, 75, 141, 364, 164);} + if (EXT != shown_ext) + {shown_ext = EXT; RedrawRegion(hConsoleWnd, 75, 174, 364, 197);} + if (SBR != shown_sbr) + {shown_sbr = SBR; RedrawRegion(hConsoleWnd, 75, 77, 364, 97);} + if (OP != shown_op) + {shown_op = OP; RedrawRegion(hConsoleWnd, 501, 8, 595, 32);} + if (TAG != shown_tag) + {shown_tag = TAG; RedrawRegion(hConsoleWnd, 501, 77, 595, 97);} + if (int_req != shown_irq) + {shown_irq = int_req; RedrawRegion(hConsoleWnd, 501, 108, 595, 130);} + if (CCC != shown_ccc) + {shown_ccc = CCC; RedrawRegion(hConsoleWnd, 501, 141, 595, 164);} + if (CND != shown_cnd) + {shown_cnd = CND; RedrawRegion(hConsoleWnd, 501, 174, 595, 197);} + if (wait_state != shown_wait) + {shown_wait= wait_state; RedrawRegion(hConsoleWnd, 380, 77, 414, 97);} + if (CES != shown_ces) + {shown_ces = CES; RepaintRegion(hConsoleWnd, 115, 230, 478, 275);} /* console entry sw: do erase bkgnd */ + if (RUNMODE != shown_runmode) + {shown_runmode = RUNMODE;RepaintRegion(hConsoleWnd, 270, 359, 330, 418);} + + for (i = 0; i < NBUTTONS; i++) { + if (btn[i].pushable) + continue; + + switch (i) { + case IDC_RUN: sts = running && ! wait_state; break; +// case IDC_PARITY_CHECK: sts = FALSE; break; +// case IDC_POWER_ON: sts = TRUE; break; + default: + continue; + +// case IDC_FILE_READY: these windows are enabled&disabled directly +// case IDC_FORMS_CHECK: +// case IDC_KEYBOARD_SELECT: +// case IDC_DISK_UNLOCK: + } + + if (sts != IsWindowEnabled(btn[i].hBtn)) { // status has changed + if (sts || force || btn[i].immed_off) { // if lamp should be on or must be set now + EnableWindow(btn[i].hBtn, sts); // set it and reset cumulative off-time + btn[i].offtime = 0; + } + else if (btn[i].offtime == 0) { // it just went out, note the time + btn[i].offtime = GetTickCount(); + } + else if ((GetTickCount()-btn[i].offtime) >= LAMPTIME) { + EnableWindow(btn[i].hBtn, FALSE); // it's been long enough -- switch the lamp off + } + } + } + +/* UpdateWindow(hConsoleWnd); */ +} + +WNDPROC oldButtonProc = NULL; + +/* ------------------------------------------------------------------------ + * ------------------------------------------------------------------------ */ + +LRESULT CALLBACK ButtonProc (HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) +{ + int i; + + i = GetWindowLong(hWnd, GWL_ID); + + if (! btn[i].pushable) { + if (uMsg == WM_LBUTTONDOWN || uMsg == WM_LBUTTONUP || uMsg == WM_LBUTTONDBLCLK) + return 0; + if (uMsg == WM_CHAR) + if ((TCHAR) wParam == ' ') + return 0; + } + + return CallWindowProc(oldButtonProc, hWnd, uMsg, wParam, lParam); +} + +static int occurs (char *txt, char ch) +{ + int count = 0; + + while (*txt) + if (*txt++ == ch) + count++; + + return count; +} + +// turns out to get properly colored buttons you have to paint them yourself. Sheesh. +// On the plus side, this lets do a better job of aligning the button text than +// the button would by itself. + +void PaintButton (LPDRAWITEMSTRUCT dis) +{ + int i = dis->CtlID, nc, nlines, x, y, dy; + BOOL down = dis->itemState & ODS_SELECTED; + HPEN hOldPen; + HFONT hOldFont; + UINT oldAlign; + COLORREF oldBk; + char *txt, *tstart; + + if (! BETWEEN(i, 0, NBUTTONS-1)) + return; + + FillRect(dis->hDC, &dis->rcItem, ((btn[i].pushable || power) && IsWindowEnabled(btn[i].hBtn)) ? btn[i].hbrLit : btn[i].hbrDark); + + if (! btn[i].pushable) { + hOldPen = SelectObject(dis->hDC, hBlackPen); + MoveToEx(dis->hDC, dis->rcItem.left, dis->rcItem.top, NULL); + LineTo(dis->hDC, dis->rcItem.right-1, dis->rcItem.top); + LineTo(dis->hDC, dis->rcItem.right-1, dis->rcItem.bottom-1); + LineTo(dis->hDC, dis->rcItem.left, dis->rcItem.bottom-1); + LineTo(dis->hDC, dis->rcItem.left, dis->rcItem.top); + } + else if (down) { + // do the three-D thing + hOldPen = SelectObject(dis->hDC, hDkGreyPen); + MoveToEx(dis->hDC, dis->rcItem.left, dis->rcItem.bottom-2, NULL); + LineTo(dis->hDC, dis->rcItem.left, dis->rcItem.top); + LineTo(dis->hDC, dis->rcItem.right-1, dis->rcItem.top); + + SelectObject(dis->hDC, hWhitePen); + MoveToEx(dis->hDC, dis->rcItem.left, dis->rcItem.bottom-1, NULL); + LineTo(dis->hDC, dis->rcItem.right-1, dis->rcItem.bottom-1); + LineTo(dis->hDC, dis->rcItem.right-1, dis->rcItem.top); + + SelectObject(dis->hDC, hGreyPen); + MoveToEx(dis->hDC, dis->rcItem.left+1, dis->rcItem.bottom-3, NULL); + LineTo(dis->hDC, dis->rcItem.left+1, dis->rcItem.top+1); + LineTo(dis->hDC, dis->rcItem.right-3, dis->rcItem.top+1); + } + else { + hOldPen = SelectObject(dis->hDC, hWhitePen); + MoveToEx(dis->hDC, dis->rcItem.left, dis->rcItem.bottom-2, NULL); + LineTo(dis->hDC, dis->rcItem.left, dis->rcItem.top); + LineTo(dis->hDC, dis->rcItem.right-1, dis->rcItem.top); + + SelectObject(dis->hDC, hDkGreyPen); + MoveToEx(dis->hDC, dis->rcItem.left, dis->rcItem.bottom-1, NULL); + LineTo(dis->hDC, dis->rcItem.right-1, dis->rcItem.bottom-1); + LineTo(dis->hDC, dis->rcItem.right-1, dis->rcItem.top); + + SelectObject(dis->hDC, hGreyPen); + MoveToEx(dis->hDC, dis->rcItem.left+1, dis->rcItem.bottom-2, NULL); + LineTo(dis->hDC, dis->rcItem.right-2, dis->rcItem.bottom-2); + LineTo(dis->hDC, dis->rcItem.right-2, dis->rcItem.top+1); + } + + SelectObject(dis->hDC, hOldPen); + + hOldFont = SelectObject(dis->hDC, hBtnFont); + oldAlign = SetTextAlign(dis->hDC, TA_CENTER|TA_TOP); + oldBk = SetBkMode(dis->hDC, TRANSPARENT); + + txt = btn[i].txt; + nlines = occurs(txt, '\n')+1; + x = (dis->rcItem.left + dis->rcItem.right) / 2; + y = (dis->rcItem.top + dis->rcItem.bottom) / 2; + + dy = 14; + y = y - (nlines*dy)/2; + + if (down) { + x += 1; + y += 1; + } + + for (;;) { + for (nc = 0, tstart = txt; *txt && *txt != '\n'; txt++, nc++) + ; + + TextOut(dis->hDC, x, y, tstart, nc); + + if (*txt == '\0') + break; + + txt++; + y += dy; + } + + SetTextAlign(dis->hDC, oldAlign); + SetBkMode(dis->hDC, oldBk); + SelectObject(dis->hDC, hOldFont); +} + +/* ------------------------------------------------------------------------ + * ------------------------------------------------------------------------ */ + +HWND CreateSubclassedButton (HWND hwParent, int i) +{ + HWND hBtn; + int x, y; + int r, g, b; + + y = bmht - (4*BUTTON_HEIGHT) + BUTTON_HEIGHT * btn[i].y; + x = (btn[i].x < 2) ? (btn[i].x*BUTTON_WIDTH) : (bmwid - (4-btn[i].x)*BUTTON_WIDTH); + + if ((hBtn = CreateWindow("BUTTON", btn[i].txt, WS_CHILD|WS_VISIBLE|BS_CENTER|BS_MULTILINE|BS_OWNERDRAW, + x, y, BUTTON_WIDTH, BUTTON_HEIGHT, hwParent, (HMENU) i, hInstance, NULL)) == NULL) + return NULL; + + btn[i].hBtn = hBtn; + + if (oldButtonProc == NULL) + oldButtonProc = (WNDPROC) GetWindowLong(hBtn, GWL_WNDPROC); + + btn[i].hbrLit = CreateSolidBrush(btn[i].clr); + + if (! btn[i].pushable) { + r = GetRValue(btn[i].clr) / 4; + g = GetGValue(btn[i].clr) / 4; + b = GetBValue(btn[i].clr) / 4; + + btn[i].hbrDark = CreateSolidBrush(RGB(r,g,b)); + EnableWindow(hBtn, FALSE); + } + + SetWindowLong(hBtn, GWL_WNDPROC, (LONG) ButtonProc); + return hBtn; +} + +/* ------------------------------------------------------------------------ + * Pump - thread that takes care of the console window. It has to be a separate thread so that it gets + * execution time even when the simulator is compute-bound or IO-blocked. This routine creates the window + * and runs a standard Windows message pump. The window function does the actual display work. + * ------------------------------------------------------------------------ */ + +static DWORD WINAPI Pump (LPVOID arg) +{ + MSG msg; + int wx, wy, i; + RECT r, ra; + BITMAP bm; + WNDCLASS cd; + HDC hDC; + HWND hActWnd; + + hActWnd = GetForegroundWindow(); + + if (! class_defined) { /* register Window class */ + hInstance = GetModuleHandle(NULL); + + memset(&cd, 0, sizeof(cd)); + cd.style = CS_NOCLOSE; + cd.lpfnWndProc = ConsoleWndProc; + cd.cbClsExtra = 0; + cd.cbWndExtra = 0; + cd.hInstance = hInstance; + cd.hIcon = NULL; + cd.hCursor = hcArrow; + cd.hbrBackground = NULL; + cd.lpszMenuName = NULL; + cd.lpszClassName = szConsoleClassName; + + if (! RegisterClass(&cd)) { + PumpID = 0; + return 0; + } + + class_defined = TRUE; + } + + hbWhite = GetStockObject(WHITE_BRUSH); /* create or fetch useful GDI objects */ + hbBlack = GetStockObject(BLACK_BRUSH); /* create or fetch useful GDI objects */ + hbGray = GetStockObject(GRAY_BRUSH); + hSwitchPen = CreatePen(PS_SOLID, 5, RGB(255,255,255)); + + hWhitePen = GetStockObject(WHITE_PEN); + hBlackPen = GetStockObject(BLACK_PEN); + hLtGreyPen = CreatePen(PS_SOLID, 1, RGB(190,190,190)); + hGreyPen = CreatePen(PS_SOLID, 1, RGB(128,128,128)); + hDkGreyPen = CreatePen(PS_SOLID, 1, RGB(64,64,64)); + + hcArrow = LoadCursor(NULL, IDC_ARROW); + hcHand = LoadCursor(hInstance, MAKEINTRESOURCE(IDC_HAND)); + + if (hBitmap == NULL) + hBitmap = LoadBitmap(hInstance, MAKEINTRESOURCE(IDB_CONSOLE)); + if (hbLampOut == NULL) + hbLampOut = CreateSolidBrush(RGB(50,50,50)); + if (hFont == NULL) + hFont = CreateFont(-10, 0, 0, 0, FW_NORMAL, 0, 0, 0, DEFAULT_CHARSET, OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS, FIXED_PITCH, FF_SWISS, "Arial"); + if (hBtnFont == NULL) + hBtnFont = CreateFont(-12, 0, 0, 0, FW_NORMAL, 0, 0, 0, DEFAULT_CHARSET, OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS, FIXED_PITCH, FF_SWISS, "Arial"); + + if (hConsoleWnd == NULL) { /* create window */ + if ((hConsoleWnd = CreateWindow(szConsoleClassName, "IBM 1130", WS_OVERLAPPED, 0, 0, 200, 200, NULL, NULL, hInstance, NULL)) == NULL) { + PumpID = 0; + return 0; + } + } + + GetObject(hBitmap, sizeof(bm), &bm); /* get bitmap size */ + bmwid = bm.bmWidth; + bmht = bm.bmHeight; + + for (i = 0; i < NBUTTONS; i++) + CreateSubclassedButton(hConsoleWnd, i); + + EnableWindow(btn[IDC_POWER_ON].hBtn, TRUE); + EnableWindow(btn[IDC_DISK_UNLOCK].hBtn, TRUE); + + GetWindowRect(hConsoleWnd, &r); /* get window size as created */ + wx = r.right - r.left + 1; + wy = r.bottom - r.top + 1; + + if (hCDC == NULL) { /* get a memory DC and select the bitmap into ti */ + hDC = GetDC(hConsoleWnd); + hCDC = CreateCompatibleDC(hDC); + SelectObject(hCDC, hBitmap); + ReleaseDC(hConsoleWnd, hDC); + } + + GetClientRect(hConsoleWnd, &r); + wx = (wx - r.right - 1) + bmwid; /* compute new desired size based on how client area came out */ + wy = (wy - r.bottom - 1) + bmht; + MoveWindow(hConsoleWnd, 0, 0, wx, wy, FALSE); /* resize window */ + + ShowWindow(hConsoleWnd, SW_SHOWNOACTIVATE); /* display it */ + UpdateWindow(hConsoleWnd); + + if (hActWnd != NULL) { /* bring console (sim) window back to top */ + GetWindowRect(hConsoleWnd, &r); + ShowWindow(hActWnd, SW_NORMAL); /* and move it just below the display window */ + SetWindowPos(hActWnd, HWND_TOP, 0, r.bottom, 0, 0, SWP_NOSIZE); + GetWindowRect(hActWnd, &ra); + if (ra.bottom >= GetSystemMetrics(SM_CYSCREEN)) { /* resize if it goes of bottom of screen */ + ra.bottom = GetSystemMetrics(SM_CYSCREEN) - 1; + SetWindowPos(hActWnd, 0, 0, 0, ra.right-ra.left+1, ra.bottom-ra.top+1, SWP_NOZORDER|SWP_NOMOVE); + } + } + + while (GetMessage(&msg, hConsoleWnd, 0, 0)) { /* message pump - this basically loops forevermore */ + TranslateMessage(&msg); + DispatchMessage(&msg); + } + + if (hConsoleWnd != NULL) { + DestroyWindow(hConsoleWnd); /* but if a quit message got posted, clean up */ + hConsoleWnd = NULL; + } + + PumpID = 0; + return 0; +} + +/* ------------------------------------------------------------------------ + * DrawBits - starting at position (x,y), draw lamps for nbits bits of word 'bits', looking only at masked bits + * ------------------------------------------------------------------------ */ + +static void DrawBits (HDC hDC, int x, int y, int bits, int nbits, int mask, char *syms) +{ + int i, b = 0x0001 << (nbits-1); + + for (i = 0; i < nbits; i++, b >>= 1) { + if (mask & b) { /* select white or black lettering then write 2 chars */ + SetTextColor(hDC, (b & bits && power) ? RGB(255,255,255) : RGB(0,0,0)); + TextOut(hDC, x, y, syms, 2); + } + syms += 2; /* go to next symbol pair */ + + if (i < 10) + x += 15; /* step between lamps */ + else + x += 19; + + if (x < 500) { + if (b & 0x1110) + x += 10; /* step over nibble divisions on left side */ + else if (b & 0x0001) + x += 9; + } + } +} + +/* ------------------------------------------------------------------------ + * DrawToggles - display the console sense switches + * ------------------------------------------------------------------------ */ + +static void DrawToggles (HDC hDC, int bits) +{ + int b, x; + + for (b = 0x8000, x = 122; b != 0; b >>= 1) { + if (shown_ces & b) { /* up */ + SelectObject(hDC, hbWhite); + Rectangle(hDC, x, 232, x+9, 240); + SelectObject(hDC, hbGray); + Rectangle(hDC, x, 239, x+9, 255); + } + else { /* down */ + SelectObject(hDC, hbWhite); + Rectangle(hDC, x, 263, x+9, 271); + SelectObject(hDC, hbGray); + Rectangle(hDC, x, 248, x+9, 264); + } + + x += (b & 0x1111) ? 31 : 21; + } +} + +/* ------------------------------------------------------------------------ + * DrawRunmode - draw the run mode rotary switch's little tip + * ------------------------------------------------------------------------ */ + +void DrawRunmode (HDC hDC, int mode) +{ + double angle = (mode*45. + 90.) * 3.1415926 / 180.; /* convert mode position to angle in radians */ + double ca, sa; /* sine and cosine */ + int x0, y0, x1, y1; + HPEN hOldPen; + + ca = cos(angle); + sa = sin(angle); + + x0 = 301 + (int) (20.*ca + 0.5); /* inner radius */ + y0 = 389 - (int) (20.*sa + 0.5); + x1 = 301 + (int) (25.*ca + 0.5); /* outer radius */ + y1 = 389 - (int) (25.*sa + 0.5); + + hOldPen = SelectObject(hDC, hSwitchPen); + + MoveToEx(hDC, x0, y0, NULL); + LineTo(hDC, x1, y1); + + SelectObject(hDC, hOldPen); +} + +/* ------------------------------------------------------------------------ + * HandleClick - handle mouse clicks on the console window. Now we just + * look at the console sense switches. Actual says this is a real click, rather + * than a mouse-region test. Return value TRUE means the cursor is over a hotspot. + * ------------------------------------------------------------------------ */ + +static BOOL HandleClick (HWND hWnd, int xh, int yh, BOOL actual) +{ + int b, x, r, ang, i; + + for (b = 0x8000, x = 122; b != 0; b >>= 1) { + if (BETWEEN(xh, x-3, x+8+3) && BETWEEN(yh, 230, 275)) { + if (actual) { + CES ^= b; /* a hit. Invert the bit and redisplay */ + update_gui(TRUE); + } + return TRUE; + } + x += (b & 0x1111) ? 31 : 21; + } + + if (BETWEEN(xh, 245, 355) && BETWEEN(yh, 345, 425)) { /* hit near rotary switch */ + ang = (int) (atan2(301.-xh, 389.-yh)*180./3.1415926); /* this does implicit 90 deg rotation by the way */ + r = (int) sqrt((xh-301)*(xh-301)+(yh-389)*(yh-389)); + if (r > 12) { + for (i = MODE_LOAD; i <= MODE_INT_RUN; i++) { + if (BETWEEN(ang, i*45-12, i*45+12)) { + if (actual) { + RUNMODE = i; + update_gui(TRUE); + } + return TRUE; + } + } + + } + } + + return FALSE; +} + +/* ------------------------------------------------------------------------ + * DrawConsole - refresh the console display. (This routine could be sped up by intersecting + * the various components' bounding rectangles with the repaint rectangle. The bounding rects + * could be put into an array and used both here and in the refresh routine). + * + * RedrawRegion -> force repaint w/o background redraw. used for lamps which are drawn in the same place in either state + * RepaintRegion-> repaint with background redraw. Used for toggles which change position. + * ------------------------------------------------------------------------ */ + +static void DrawConsole (HDC hDC) +{ + static char digits[] = " 0 1 2 3 4 5 6 7 8 9101112131415"; + static char cccs[] = "3216 8 4 2 1"; + static char cnds[] = " C V"; + static char waits[] = " W"; + HFONT hOldFont, hOldBrush; + + hOldFont = SelectObject(hDC, hFont); /* use that tiny font */ + hOldBrush = SelectObject(hDC, hbWhite); + + SetBkMode(hDC, TRANSPARENT); /* overlay letters w/o changing background */ + + DrawBits(hDC, 76, 15, shown_iar, 16, 0x3FFF, digits); + DrawBits(hDC, 76, 48, shown_sar, 16, 0x3FFF, digits); + DrawBits(hDC, 76, 81, shown_sbr, 16, 0xFFFF, digits); + DrawBits(hDC, 76, 147, shown_acc, 16, 0xFFFF, digits); + DrawBits(hDC, 76, 180, shown_ext, 16, 0xFFFF, digits); + + DrawBits(hDC, 506, 15, shown_op, 5, 0x001F, digits); + DrawBits(hDC, 506, 81, shown_tag, 4, 0x0007, digits); + DrawBits(hDC, 506, 114, shown_irq, 6, 0x003F, digits); + DrawBits(hDC, 506, 147, shown_ccc, 6, 0x003F, cccs); + DrawBits(hDC, 506, 180, shown_cnd, 2, 0x0003, cnds); + + DrawBits(hDC, 390, 81, shown_wait?1:0,1, 0x0001, waits); + + DrawToggles(hDC, shown_ces); + + DrawRunmode(hDC, shown_runmode); + + SelectObject(hDC, hOldFont); + SelectObject(hDC, hOldBrush); +} + +/* ------------------------------------------------------------------------ + * Handles button presses. Remember that this occurs in the context of + * the Pump thread, not the simulator thread. + * ------------------------------------------------------------------------ */ + +extern void stuff_cmd (char *cmd); +extern void remark_cmd (char *cmd); + +void flash_run (void) +{ + EnableWindow(btn[IDC_RUN].hBtn, TRUE); // enable the run lamp + btn[IDC_RUN].offtime = GetTickCount(); // reset timeout + + KillTimer(hConsoleWnd, UPDATE_TIMER_ID); // (re)schedule lamp update + SetTimer(hConsoleWnd, UPDATE_TIMER_ID, LAMPTIME+1, NULL); +} + +void HandleCommand (HWND hWnd, WPARAM wParam, LPARAM lParam) +{ + int i; + + switch (wParam) { + case IDC_POWER: /* toggle system power */ + power = ! power; + reset_all(0); + if (running && ! power) { /* turning off */ + reason = STOP_POWER_OFF; + while (running) + Sleep(10); /* wait for execution thread to exit */ + } + EnableWindow(btn[IDC_POWER_ON].hBtn, power); + for (i = 0; i < NBUTTONS; i++) + InvalidateRect(btn[i].hBtn, NULL, TRUE); + break; + + case IDC_PROGRAM_START: /* begin execution */ + if (! running) { + switch (RUNMODE) { + case MODE_INT_RUN: + case MODE_RUN: + case MODE_SI: + stuff_cmd("go"); + break; + + case MODE_DISP: /* display core and advance IAR */ + ReadW(IAR); + IAR = IAR+1; + flash_run(); /* illuminate run lamp for .5 sec */ + break; + + case MODE_LOAD: /* store to core and advance IAR */ + WriteW(IAR, CES); + IAR = IAR+1; + flash_run(); + break; + } + } + break; + + case IDC_PROGRAM_STOP: + if (running) { /* potential race condition here */ + GUI_BEGIN_CRITICAL_SECTION + SETBIT(con_dsw, CON_DSW_PROGRAM_STOP); + SETBIT(ILSW[5], ILSW_5_PROGRAM_STOP); + int_req |= INT_REQ_5; + GUI_END_CRITICAL_SECTION + } + break; + + case IDC_LOAD_IAR: + if (! running) { + IAR = CES & 0x3FFF; /* set IAR from console entry switches */ + } + break; + + case IDC_KEYBOARD: /* toggle between console/keyboard mode */ + break; + + case IDC_IMM_STOP: + if (running) { + reason = STOP_WAIT; /* terminate execution without setting wait_mode */ + while (running) + Sleep(10); /* wait for execution thread to exit */ + } + break; + + case IDC_RESET: + if (! running) { /* check-reset is disabled while running */ + reset_all(0); + forms_check(0); /* clear forms-check status */ + print_check(0); + } + break; + + case IDC_PROGRAM_LOAD: + if (! running) { /* if card reader is attached to a file, do cold start read of one card */ + IAR = 0; /* reset IAR */ +// stuff_cmd("boot cr"); + if (cr_boot(0) != SCPE_OK) /* load boot card */ + remark_cmd("IPL failed"); + } + break; + } + + update_gui(FALSE); +} + +/* ------------------------------------------------------------------------ + * ConsoleWndProc - window process for the console display + * ------------------------------------------------------------------------ */ + +LRESULT CALLBACK ConsoleWndProc (HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) +{ + HDC hDC; + PAINTSTRUCT ps; + POINT p; + RECT clip, xsect, rbmp; + int i; + + switch (uMsg) { + case WM_CLOSE: + DestroyWindow(hWnd); + break; + + case WM_DESTROY: + hConsoleWnd = NULL; + break; + + case WM_ERASEBKGND: + hDC = (HDC) wParam; + GetClipBox(hDC, &clip); + SetRect(&rbmp, 0, 0, bmwid, bmht); + if (IntersectRect(&xsect, &clip, &rbmp)) + BitBlt(hDC, xsect.left, xsect.top, xsect.right-xsect.left+1, xsect.bottom-xsect.top+1, hCDC, xsect.left, xsect.top, SRCCOPY); +// rbmp.top = rbmp.bottom; +// rbmp.bottom += 200; +// if (IntersectRect(&xsect, &clip, &rbmp)) +// FillRect(hDC, &xsect, hbBlack); + return TRUE; /* let Paint do this so we know what the update region is (ps.rcPaint) */ + + case WM_PAINT: + hDC = BeginPaint(hWnd, &ps); + DrawConsole(hDC); + EndPaint(hWnd, &ps); + break; + + case WM_COMMAND: /* button click */ + HandleCommand(hWnd, wParam, lParam); + break; + + case WM_DRAWITEM: + PaintButton((LPDRAWITEMSTRUCT) lParam); + break; + + case WM_SETCURSOR: + GetCursorPos(&p); + ScreenToClient(hWnd, &p); + SetCursor(HandleClick(hWnd, p.x, p.y, FALSE) ? hcHand : hcArrow); + return TRUE; + + case WM_LBUTTONDOWN: + HandleClick(hWnd, LOWORD(lParam), HIWORD(lParam), TRUE); + break; + + case WM_CTLCOLORBTN: + i = GetWindowLong((HWND) lParam, GWL_ID); + if (BETWEEN(i, 0, NBUTTONS-1)) + return (LRESULT) (power && IsWindowEnabled((HWND) lParam) ? btn[i].hbrLit : btn[i].hbrDark); + + case WM_TIMER: + if (wParam == UPDATE_TIMER_ID) { + update_gui(FALSE); + KillTimer(hWnd, UPDATE_TIMER_ID); + } + break; + + default: + return DefWindowProc(hWnd, uMsg, wParam, lParam); + } + + return 0; +} + +enum {PRINTER_OK = 0, FORMS_CHECK = 1, PRINT_CHECK = 2, BOTH_CHECK = 3} printerstatus = PRINTER_OK; + +void forms_check (int set) +{ + COLORREF oldcolor = btn[IDC_FORMS_CHECK].clr; + + if (set) + SETBIT(printerstatus, FORMS_CHECK); + else + CLRBIT(printerstatus, FORMS_CHECK); + + btn[IDC_FORMS_CHECK].clr = (printerstatus & PRINT_CHECK) ? RGB(255,0,0) : RGB(255,255,0); + + EnableWindow(btn[IDC_FORMS_CHECK].hBtn, printerstatus); + + if (btn[IDC_FORMS_CHECK].clr != oldcolor) + InvalidateRect(btn[IDC_FORMS_CHECK].hBtn, NULL, TRUE); // change color in any case +} + +void print_check (int set) +{ + COLORREF oldcolor = btn[IDC_FORMS_CHECK].clr; + + if (set) + SETBIT(printerstatus, PRINT_CHECK); + else + CLRBIT(printerstatus, PRINT_CHECK); + + btn[IDC_FORMS_CHECK].clr = (printerstatus & PRINT_CHECK) ? RGB(255,0,0) : RGB(255,255,0); + + EnableWindow(btn[IDC_FORMS_CHECK].hBtn, printerstatus); + + if (btn[IDC_FORMS_CHECK].clr != oldcolor) + InvalidateRect(btn[IDC_FORMS_CHECK].hBtn, NULL, TRUE); // change color in any case +} + +void keyboard_selected (int select) +{ + EnableWindow(btn[IDC_KEYBOARD_SELECT].hBtn, select); +} + +void disk_ready (int ready) +{ + EnableWindow(btn[IDC_FILE_READY].hBtn, ready); +} + +void disk_unlocked (int unlocked) +{ + EnableWindow(btn[IDC_DISK_UNLOCK].hBtn, unlocked); +} + +CRITICAL_SECTION critsect; + +void begin_critical_section (void) +{ + static BOOL mustinit = TRUE; + + if (mustinit) { + InitializeCriticalSection(&critsect); + mustinit = FALSE; + } + + EnterCriticalSection(&critsect); +} + +void end_critical_section (void) +{ + LeaveCriticalSection(&critsect); +} + +#endif // WIN32 +#endif // GUI_SUPPORT diff --git a/Ibm1130/ibm1130_cr.c b/Ibm1130/ibm1130_cr.c new file mode 100644 index 00000000..7b18616f --- /dev/null +++ b/Ibm1130/ibm1130_cr.c @@ -0,0 +1,1092 @@ +#include "ibm1130_defs.h" + +/* ibm1130_cr.c: IBM 1130 1442 Card Reader simulator + + Copyright (c) 2002, Brian Knittel + Based on PDP-11 simulator written by Robert M Supnik + +NOTE - there is a problem with this code. The Device Status Word (DSW) is +computed from current conditions when requested by an XIO load status +command; the value of DSW available to the simulator's examine & save +commands may NOT be accurate. This should probably be fixed. + +* Update 2002-02-29: Added deck-list option. If you issue an attach + command and specify the filename as "@filename", the named file is interpreted + as a list of filenames to be read in sequence; the effect is that the reader + sees the concatenation of all of the files named. "reset" rewinds the deck + list. Filenames can be followed by whitespace and the letter "a" or "b", + which indicates "ascii to 029" or "binary", respectively. Example: + + attach cr @decklist + + where file "decklist" contains: + + file01 a + file02 b + file03 b + file04 b + + If "a" or "b" is not specified, the device mode setting is used. + + ('a' means 029, so, if you need 026 coding, specify the + device default as the correct 026 code and omit the 'a' on the text files lines). + +* note: I'm not sure but I think we'll need a way to simulate the 'start' + button. What may end up being necessary is to fake this in the 'attach' + command. In a GUI build we may want to wait until they press a button. + Have to research: does DMS issue a read request which is only + satisfied when START is pressed, or does START cause an interrupt that + then asks DMS to issue a read request. I think it's the former but need + to check. After all the status register says "empty" and "not ready" + when the hopper is empty. So what gives? On the 360 I think the start + button causes issues some sort of attention request. + +* Card image format. + Card files can be ascii text or binary. There are several ASCII modes: + CODE_029, CODE_26F, etc, corresponding to different code sets. + Punch and reader modes can be set independently. + + The 1442 card read/punch has several cycles: + + feed cycle: moves card from hopper to read station + card from read station to punch station + card from punch station to stacker + + read or punch: operates on card at read or punch station (but not both). + + The simulator requires input cards to be read from the file attached + to the card reader unit. A feed cycle reads one line (text mode) or + 160 bytes (binary mode) from the input file to the read station buffer, + copies the read station buffer to the punch station buffer, and if + the punch unit is attached to a file, writes the punch station buffer to + the output file. + + The read and punch cycles operate on the appropriate card buffer. + + Detaching the card punch flushes the punch station buffer if necessary. + + As does the 1442, a read or punch cycle w/o a feed cycle causes a + feed cycle first. + + A feed cycle on an empty deck (reader unattaced or at EOF) clears + the appropriate buffer, so you can punch w/o attaching a deck to + the card reader. + +// -- this may need changing depending on how things work in hardware. TBD. +|| A read cycle on an empty deck causes an error. +|| Hmmm -- what takes the place of the Start button on +\\ the card reader? + + Binary format is stored using fwrite of short ints, in this format: + + 1 1 + 2 2 0 1 2 3 4 5 6 7 8 9 + * * * * * * * * * * * * 0 0 0 0 + + MSB LSB + byte 0 [ 6] [ 7] [ 8] [ 9] 0 0 0 0 + byte 1 [12] [11] [ 0] [ 1] [ 2] [ 3] [ 4] [ 5] + + This means we can read words (little endian) and get this in memory: + + 12 11 0 1 2 3 4 5 6 7 8 9 - - - - + + which is what the 1130 sees. + + ASCII can be read in blocks of 80 characters but can be terminated by newline prematurely. + + Booting: card reader IPL loads 80 columns (1 card) into memory starting + at location 0 in a split fashion: + + ________________ _ _ _ + / + 12 | + 11 | + 0 | + 1 | + 2 | + 3 | Punched card + 4 | + 5 | + 6 | + 7 | + 8 | + 9 | + +------------------ - - - + + 12 11 0 1 2 3 4 5 6 7 8 9 + | | | | | 0 0 0 / \ | | | | | | + +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ + | 0| 1| 2| 3| 4| 5| 6| 7| 8| 9|10|11|12|13|14|15| + +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ + | OPCODE | F| Tag | DISPLACEMENT | + +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ + + The zeros mean that all IPL instructions are short form, + nonindexed. The 3 column is repeated in bits 8 and 9 so + it's a sign bit. + + Boot command on a binary deck does this. Boot on an unattached + reader loads the standard boot2 card image. Boot with an ASCII + deck will not be very helpful. +*/ + +#define READ_DELAY 100 +#define PUNCH_DELAY 300 +#define FEED_DELAY 500 + +// #define IS_ONLINE(u) (((u)->flags & (UNIT_ATT|UNIT_DIS)) == UNIT_ATT) + +static t_stat cr_svc (UNIT *uptr); +static t_stat cr_reset (DEVICE *dptr); +static t_stat cr_set_code (UNIT *uptr, int32 match); +static t_stat cr_attach (UNIT *uptr, char *cptr); +static t_stat cr_detach (UNIT *uptr); + +static t_stat cp_reset (DEVICE *dptr); +static t_stat cp_set_code (UNIT *uptr, int32 match); +static t_stat cp_detach (UNIT *uptr); + +static int16 cr_dsw = 0; /* device status word */ +static int32 cr_wait = READ_DELAY; /* read per-column wait */ +static int32 cf_wait = PUNCH_DELAY; /* punch per-column wait */ +static int32 cp_wait = FEED_DELAY; /* feed op wait */ + +#define UNIT_V_OPERATION (UNIT_V_UF + 0) /* operation in progress */ +#define UNIT_V_CODE (UNIT_V_UF + 2) +#define UNIT_V_EMPTY (UNIT_V_UF + 4) + +#define UNIT_V_LASTPUNCH (UNIT_V_UF + 0) /* bit in unit_cp flags */ + +#define UNIT_OP (3u << UNIT_V_OPERATION) /* two bits */ +#define UNIT_CODE (3u << UNIT_V_CODE) /* two bits */ +#define UNIT_EMPTY (1u << UNIT_V_EMPTY) + +#define UNIT_LASTPUNCH (1u << UNIT_V_LASTPUNCH) + +#define OP_IDLE (0u << UNIT_V_OPERATION) +#define OP_READING (1u << UNIT_V_OPERATION) +#define OP_PUNCHING (2u << UNIT_V_OPERATION) +#define OP_FEEDING (3u << UNIT_V_OPERATION) + +#define SET_OP(op) {cr_unit.flags &= ~UNIT_OP; cr_unit.flags |= op;} + +#define CODE_029 (0u << UNIT_V_CODE) +#define CODE_026F (1u << UNIT_V_CODE) +#define CODE_026C (2u << UNIT_V_CODE) +#define CODE_BINARY (3u << UNIT_V_CODE) + +#define SET_CODE(un,cd) {un.flags &= ~UNIT_CODE; un.flags |= cd;} + +#define COLUMN u4 /* column field in unit record */ + +UNIT cr_unit = { UDATA (&cr_svc, UNIT_ATTABLE, 0) }; +UNIT cp_unit = { UDATA (NULL, UNIT_ATTABLE, 0) }; + +MTAB cr_mod[] = { + { UNIT_CODE, CODE_029, "029", "029", &cr_set_code}, + { UNIT_CODE, CODE_026F, "026F", "026F", &cr_set_code}, + { UNIT_CODE, CODE_026C, "026C", "026C", &cr_set_code}, + { UNIT_CODE, CODE_BINARY, "BINARY", "BINARY", &cr_set_code}, + { 0 } }; + +MTAB cp_mod[] = { + { UNIT_CODE, CODE_029, "029", "029", &cp_set_code}, + { UNIT_CODE, CODE_026F, "026F", "026F", &cp_set_code}, + { UNIT_CODE, CODE_026C, "026C", "026C", &cp_set_code}, + { UNIT_CODE, CODE_BINARY, "BINARY", "BINARY", &cp_set_code}, + { 0 } }; + +REG cr_reg[] = { + { HRDATA (CRDSW, cr_dsw, 16) }, /* device status word */ + { DRDATA (CRTIME, cr_wait, 24), PV_LEFT }, /* operation wait */ + { DRDATA (CFTIME, cf_wait, 24), PV_LEFT }, /* operation wait */ + { NULL } }; + +REG cp_reg[] = { + { DRDATA (CPTIME, cp_wait, 24), PV_LEFT }, /* operation wait */ + { NULL } }; + +DEVICE cr_dev = { + "CR", &cr_unit, cr_reg, cr_mod, + 1, 16, 16, 1, 16, 16, + NULL, NULL, cr_reset, + cr_boot, cr_attach, cr_detach}; + +DEVICE cp_dev = { + "CP", &cp_unit, cp_reg, cp_mod, + 1, 16, 16, 1, 16, 16, + NULL, NULL, cp_reset, + NULL, NULL, cp_detach}; + +#define CR_DSW_READ_RESPONSE 0x8000 /* device status word bits */ +#define CR_DSW_PUNCH_RESPONSE 0x4000 +#define CR_DSW_ERROR_CHECK 0x2000 +#define CR_DSW_LAST_CARD 0x1000 +#define CR_DSW_OP_COMPLETE 0x0800 +#define CR_DSW_FEED_CHECK 0x0100 +#define CR_DSW_BUSY 0x0002 +#define CR_DSW_NOT_READY 0x0001 + +typedef struct { + int hollerith; + char ascii; +} CPCODE; + +static CPCODE cardcode_029[] = +{ + 0x0000, ' ', + 0x8000, '&', // + in 026 Fortran + 0x4000, '-', + 0x2000, '0', + 0x1000, '1', + 0x0800, '2', + 0x0400, '3', + 0x0200, '4', + 0x0100, '5', + 0x0080, '6', + 0x0040, '7', + 0x0020, '8', + 0x0010, '9', + 0x9000, 'A', + 0x8800, 'B', + 0x8400, 'C', + 0x8200, 'D', + 0x8100, 'E', + 0x8080, 'F', + 0x8040, 'G', + 0x8020, 'H', + 0x8010, 'I', + 0x5000, 'J', + 0x4800, 'K', + 0x4400, 'L', + 0x4200, 'M', + 0x4100, 'N', + 0x4080, 'O', + 0x4040, 'P', + 0x4020, 'Q', + 0x4010, 'R', + 0x3000, '/', + 0x2800, 'S', + 0x2400, 'T', + 0x2200, 'U', + 0x2100, 'V', + 0x2080, 'W', + 0x2040, 'X', + 0x2020, 'Y', + 0x2010, 'Z', + 0x0820, ':', + 0x0420, '#', // = in 026 Fortran + 0x0220, '@', // ' in 026 Fortran + 0x0120, '\'', + 0x00A0, '=', + 0x0060, '"', + 0x8820, 'c', // cent + 0x8420, '.', + 0x8220, '<', // ) in 026 Fortran + 0x8120, '(', + 0x80A0, '+', + 0x8060, '|', + 0x4820, '!', + 0x4420, '$', + 0x4220, '*', + 0x4120, ')', + 0x40A0, ';', + 0x4060, 'n', // not + 0x2820, 'x', // what? + 0x2420, ',', + 0x2220, '%', // ( in 026 Fortran + 0x2120, '_', + 0x20A0, '>', + 0x2060, '>', +}; + +static CPCODE cardcode_026F[] = // 026 fortran +{ + 0x0000, ' ', + 0x8000, '+', + 0x4000, '-', + 0x2000, '0', + 0x1000, '1', + 0x0800, '2', + 0x0400, '3', + 0x0200, '4', + 0x0100, '5', + 0x0080, '6', + 0x0040, '7', + 0x0020, '8', + 0x0010, '9', + 0x9000, 'A', + 0x8800, 'B', + 0x8400, 'C', + 0x8200, 'D', + 0x8100, 'E', + 0x8080, 'F', + 0x8040, 'G', + 0x8020, 'H', + 0x8010, 'I', + 0x5000, 'J', + 0x4800, 'K', + 0x4400, 'L', + 0x4200, 'M', + 0x4100, 'N', + 0x4080, 'O', + 0x4040, 'P', + 0x4020, 'Q', + 0x4010, 'R', + 0x3000, '/', + 0x2800, 'S', + 0x2400, 'T', + 0x2200, 'U', + 0x2100, 'V', + 0x2080, 'W', + 0x2040, 'X', + 0x2020, 'Y', + 0x2010, 'Z', + 0x0420, '=', + 0x0220, '\'', // ' in 026 Fortran + 0x8420, '.', + 0x8220, ')', + 0x4420, '$', + 0x4220, '*', + 0x2420, ',', + 0x2220, '(', +}; + +static CPCODE cardcode_026C[] = // 026 commercial +{ + 0x0000, ' ', + 0x8000, '+', + 0x4000, '-', + 0x2000, '0', + 0x1000, '1', + 0x0800, '2', + 0x0400, '3', + 0x0200, '4', + 0x0100, '5', + 0x0080, '6', + 0x0040, '7', + 0x0020, '8', + 0x0010, '9', + 0x9000, 'A', + 0x8800, 'B', + 0x8400, 'C', + 0x8200, 'D', + 0x8100, 'E', + 0x8080, 'F', + 0x8040, 'G', + 0x8020, 'H', + 0x8010, 'I', + 0x5000, 'J', + 0x4800, 'K', + 0x4400, 'L', + 0x4200, 'M', + 0x4100, 'N', + 0x4080, 'O', + 0x4040, 'P', + 0x4020, 'Q', + 0x4010, 'R', + 0x3000, '/', + 0x2800, 'S', + 0x2400, 'T', + 0x2200, 'U', + 0x2100, 'V', + 0x2080, 'W', + 0x2040, 'X', + 0x2020, 'Y', + 0x2010, 'Z', + 0x0420, '=', + 0x0220, '\'', // ' in 026 Fortran + 0x8420, '.', + 0x8220, ')', + 0x4420, '$', + 0x4220, '*', + 0x2420, ',', + 0x2220, '(', +}; + +static int16 ascii_to_card[256]; + +CPCODE *cardcode; +int ncardcode; +int32 active_cr_code; /* the code most recently specified */ +FILE *deckfile = NULL; + +static int16 punchstation[80]; +static int16 readstation[80]; +static enum {STATION_EMPTY, STATION_LOADED, STATION_READ, STATION_PUNCHED} punchstate = STATION_EMPTY, readstate = STATION_EMPTY; + +static t_bool nextdeck (void); +static void checkdeck (void); + +/* lookup_codetable - use code flag setting to get code table pointer and length */ + +static t_bool lookup_codetable (int32 match, CPCODE **pcode, int *pncode) +{ + switch (match) { + case CODE_029: + *pcode = cardcode_029; + *pncode = sizeof(cardcode_029) / sizeof(CPCODE); + break; + + case CODE_026F: + *pcode = cardcode_026F; + *pncode = sizeof(cardcode_026F) / sizeof(CPCODE); + break; + + case CODE_026C: + *pcode = cardcode_026C; + *pncode = sizeof(cardcode_026C) / sizeof(CPCODE); + break; + + case CODE_BINARY: + *pcode = NULL; + *pncode = 0; + break; + + default: + printf("Eek! Undefined code table index"); + return FALSE; + } + return TRUE; +} + +t_stat set_active_cr_code (int match) +{ + CPCODE *code; + int i, ncode; + + active_cr_code = match; + + if (! lookup_codetable(match, &code, &ncode)) + return SCPE_ARG; + + memset(ascii_to_card, 0, sizeof(ascii_to_card)); + + for (i = 0; i < ncode; i++) // set ascii to card code table + ascii_to_card[code[i].ascii] = (int16) code[i].hollerith; + + return SCPE_OK; +} + +t_stat cr_set_code (UNIT *uptr, int32 match) +{ + return set_active_cr_code(match); +} + +t_stat cp_set_code (UNIT *uptr, int32 match) +{ + CPCODE *code; + int ncode; + + if (! lookup_codetable(match, &code, &ncode)) + return SCPE_ARG; + + cardcode = code; // save code table for punch output + ncardcode = ncode; + + return SCPE_OK; +} + +t_stat load_cr_boot (int drvno) +{ + /* this is from the "boot2" cold start card. Columns have been */ + /* expanded already from 12 to 16 bits. */ + + static unsigned short boot2_data[] = { + 0xc80a, 0x18c2, 0xd008, 0xc019, 0x8007, 0xd017, 0xc033, 0x100a, + 0xd031, 0x7015, 0x000c, 0xe800, 0x0020, 0x08f8, 0x4828, 0x7035, + 0x70fa, 0x4814, 0xf026, 0x2000, 0x8800, 0x9000, 0x9800, 0xa000, + 0xb000, 0xb800, 0xb810, 0xb820, 0xb830, 0xb820, 0x3000, 0x08ea, + 0xc0eb, 0x4828, 0x70fb, 0x9027, 0x4830, 0x70f8, 0x8001, 0xd000, + 0xc0f4, 0xd0d9, 0xc01d, 0x1804, 0xe8d6, 0xd0d9, 0xc8e3, 0x18d3, + 0xd017, 0x18c4, 0xd0d8, 0x9016, 0xd815, 0x90db, 0xe8cc, 0xd0ef, + 0xc016, 0x1807, 0x0035, 0x00d0, 0xc008, 0x1803, 0xe8c4, 0xd00f, + 0x080d, 0x08c4, 0x1003, 0x4810, 0x70d9, 0x3000, 0x08df, 0x3000, + 0x7010, 0x00d1, 0x0028, 0x000a, 0x70f3, 0x0000, 0x00d0, 0xa0c0 + }; + int i; + + if (drvno >= 0) /* if specified, set toggle switches to disk drive no */ + CES = drvno; /* so BOOT DSK1 will work correctly */ + + IAR = 0; /* clear IAR */ + + for (i = 0; i < 80; i++) /* copy memory */ + WriteW(i, boot2_data[i]); + +#ifdef GUI_SUPPORT + remark_cmd("Loaded BOOT2 cold start card\n"); +#endif + return SCPE_OK; +} + +t_stat cr_boot (int unitno) +{ + t_stat rval; + short buf[80]; + int i; + + if ((rval = reset_all(0)) != SCPE_OK) + return rval; + + if (! (cr_unit.flags & UNIT_ATT)) // no deck; load standard boot anyway + return load_cr_boot(-1); + + if ((active_cr_code & UNIT_CODE) != CODE_BINARY) { + printf("Can only boot from card reader when set to BINARY mode"); + return SCPE_IOERR; + } + + if (fread(buf, sizeof(short), 80, cr_unit.fileref) != 80) + return SCPE_IOERR; + + IAR = 0; /* Program Load sets IAR = 0 */ + + for (i = 0; i < 80; i++) /* shift 12 bits into 16 */ + WriteW(i, (buf[i] & 0xF800) | ((buf[i] & 0x0400) ? 0x00C0 : 0x0000) | ((buf[i] & 0x03F0) >> 4)); + + return SCPE_OK; +} + +char card_to_ascii (int16 hol) +{ + int i; + + for (i = 0; i < ncardcode; i++) + if (cardcode[i].hollerith == hol) + return cardcode[i].ascii; + + return ' '; +} + +/* feedcycle - move cards to next station */ + +static void feedcycle (t_bool load, t_bool punching) +{ + char buf[84], *x; + int i, nread, nwrite, ch; + + /* write punched card if punch is attached to a file */ + if (cp_unit.flags & UNIT_ATT) { + if (punchstate != STATION_EMPTY) { + if ((cp_unit.flags & UNIT_CODE) == CODE_BINARY) { + fwrite(punchstation, sizeof(short), 80, cp_unit.fileref); + } + else { + for (i = 80; --i >= 0; ) { /* find last nonblank column */ + if (buf[i] != 0) + break; + } + + /* i is now index of last character to output or -1 if all blank */ + + for (nwrite = 0; nwrite <= i; nwrite++) { /* convert characters */ + buf[nwrite] = card_to_ascii(punchstation[nwrite]); + } + + /* nwrite is now number of characters to output */ + + buf[nwrite++] = '\n'; /* append newline */ + fwrite(buf, sizeof(char), nwrite, cp_unit.fileref); + } + } + } + + if (! load) // all we wanted to do was flush the punch + return; + + /* slide cards from reader to punch. If we know we're punching, + * generate a blank card in any case. Otherwise, it should take two feed + * cycles to get a read card from the hopper to punch station */ + + if (readstate == STATION_EMPTY) { + if (punching) { + memset(punchstation, 0, sizeof(punchstation)); + punchstate = STATION_LOADED; + } + else + punchstate = STATION_EMPTY; + } + else { + memcpy(punchstation, readstation, sizeof(punchstation)); + punchstate = STATION_LOADED; + } + + /* load card into read station */ + +again: /* jump here if we've loaded a new deck after emptying the previous one */ + + if (cr_unit.flags & UNIT_ATT) { + + memset(readstation, 0, sizeof(readstation)); /* blank out the card image */ + + if (cr_unit.fileref == NULL) { + nread = 0; + } + else if ((active_cr_code & UNIT_CODE) == CODE_BINARY) { /* binary read is straightforward */ + nread = fread(readstation, sizeof(short), 80, cr_unit.fileref); + } + else { /* text read is harder: */ + if (fgets(buf, 81, cr_unit.fileref) == NULL) /* read up to 80 chars */ + nread = 0; /* hmm, end of file */ + else { /* check for newline */ + if ((x = strchr(buf, '\r')) == NULL) + x = strchr(buf, '\n'); + + if (x == NULL) { /* there were no delimiters, check for newline after the 80 chars, eat if present */ + ch = getc(cr_unit.fileref); + if (ch != '\r' && ch != '\n' && ch != EOF) + ungetc(ch, cr_unit.fileref); + + nread = 80; + } + else { + *x = ' '; /* replace with blank */ + nread = x-buf+1; + } + } + + upcase(buf); /* force uppercase */ + + for (i = 0; i < nread; i++) /* convert ascii to punch code */ + readstation[i] = ascii_to_card[buf[i]]; + } + + if (nread <= 0) { /* set hopper flag accordingly */ + if (deckfile != NULL && nextdeck()) + goto again; + + SETBIT(cr_unit.flags, UNIT_EMPTY); + readstate = STATION_EMPTY; + } + else { + CLRBIT(cr_unit.flags, UNIT_EMPTY); + readstate = STATION_LOADED; + } + } + else + readstate = STATION_EMPTY; + + cr_unit.COLUMN = -1; /* neither device is currently cycling */ + cp_unit.COLUMN = -1; +} + +#ifdef NO_USE_FOR_THIS_CURRENTLY + +/* this routine should probably be hooked up to the GUI somehow */ + +/* NPRO - nonprocess runout, flushes out the reader/punch */ + +static void npro (void) +{ + if (cr_unit.flags & UNIT_ATT) + fseek(cr_unit.fileref, 0, SEEK_END); /* push reader to EOF */ + if (deckfile != NULL) + fseek(deckfile, 0, SEEK_END); /* skip to end of deck list */ + + if (punchstate == STATION_PUNCHED) + feedcycle(FALSE, FALSE); /* flush out card just punched */ + + readstate = punchstate = STATION_EMPTY; + cr_unit.COLUMN = -1; /* neither device is currently cycling */ + cp_unit.COLUMN = -1; + SETBIT(cr_unit.flags, UNIT_EMPTY); /* set hopper empty */ +} + +#endif + +/* skipbl - skip leading whitespace in a string */ + +static char * skipbl (char *str) +{ + while (*str && *str <= ' ') + str++; + + return str; +} + +/* alltrim - remove all leading and trailing whitespace from a string */ + +static char * alltrim (char *str) +{ + char *s, *lastnb; + + if ((s = skipbl(str)) != str) /* slide down over leading whitespace */ + strcpy(str, s); + + for (lastnb = str-1, s = str; *s; s++) /* point to last nonblank characteter in string */ + if (*s > ' ') + lastnb = s; + + lastnb[1] = '\0'; /* clip just after it */ + + return str; +} + +/* checkdeck - set hopper empty status based on condition of current reader file */ + +static void checkdeck (void) +{ + t_bool empty; + + if (cr_unit.fileref == NULL) { /* there is no open file */ + empty = TRUE; + } + else { + fseek(cr_unit.fileref, 0, SEEK_END); + empty = ftell(cr_unit.fileref) <= 0; /* see if file has anything) */ + fseek(cr_unit.fileref, 0, SEEK_SET); /* rewind deck */ + } + + if (empty) { + SETBIT(cr_unit.flags, UNIT_EMPTY); + if (cr_unit.fileref != NULL) /* real file but it's empty, hmmm, try another */ + nextdeck(); + } + else + CLRBIT(cr_unit.flags, UNIT_EMPTY); +} + +/* nextdeck - attempt to load a new file from the deck list into the hopper */ + +static t_bool nextdeck (void) +{ + char buf[200], *e; + int code; + + if (deckfile == NULL) /* we can't help */ + return FALSE; + + code = cr_unit.flags & UNIT_CODE; /* default code */ + + if (cr_unit.fileref != NULL) { + fclose(cr_unit.fileref); + cr_unit.fileref = NULL; + } + + for (;;) { /* get a filename */ + if (fgets(buf, sizeof(buf), deckfile) == NULL) + break; /* oops, no more names */ + + alltrim(buf); + if (! *buf) + continue; /* empty line */ + + e = buf + strlen(buf) - 1; /* last character in name */ + if (e > (buf+1) && e[-1] <= ' ') { /* if there is at least a name + blank + character, and 2nd to last is blank */ + if (*e == 'b' || *e == 'B') { + code = CODE_BINARY; + e[-1] = '\0'; /* clip at the space and re-trim */ + alltrim(buf); + } + else if (*e == 'a' || *e == 'A') { + code = CODE_029; + e[-1] = '\0'; + alltrim(buf); + } + } + + if ((cr_unit.fileref = fopen(buf, "rb")) == NULL) + printf("File '%s' specified in deck file '%s' cannot be opened\n", buf, cr_unit.filename+1); + else + break; + } + + checkdeck(); + + set_active_cr_code(code); /* set specified code */ + + return (cr_unit.flags & UNIT_EMPTY) == 0; /* return TRUE if a deck has been loaded */ +} + +static t_stat cr_reset (DEVICE *dptr) +{ + cr_set_code(&cr_unit, active_cr_code & UNIT_CODE); /* reset to specified code table */ + + readstate = STATION_EMPTY; + + cr_dsw = 0; + sim_cancel(&cr_unit); /* cancel any pending ops */ + calc_ints(); + + SET_OP(OP_IDLE); + + SETBIT(cr_unit.flags, UNIT_EMPTY); /* assume hopper empty */ + + if (cr_unit.flags & UNIT_ATT) { +// if (deckfile != NULL) { +// fseek(deckfile, 0, SEEK_SET); +// nextdeck(); +// } +// else +// checkdeck(); + + if (cr_unit.fileref != NULL) + feedcycle(FALSE, FALSE); + } + + cr_unit.COLUMN = -1; /* neither device is currently cycling */ + + return SCPE_OK; +} + +static t_stat cp_reset (DEVICE *dptr) +{ + cp_set_code(&cp_unit, cp_unit.flags & UNIT_CODE); + punchstate = STATION_EMPTY; + + cp_unit.COLUMN = -1; + return SCPE_OK; +} + +static t_stat cr_attach (UNIT *uptr, char *cptr) +{ + t_stat rval; + t_bool use_decklist; + +// no - don't cancel pending read? +// sim_cancel(uptr); /* cancel pending operations */ + + cr_detach(uptr); /* detach file and possibly deckfile */ + + cptr = skipbl(cptr); /* skip any leading whitespace */ + + use_decklist = (*cptr == '@'); /* filename starts with @: it's a deck list */ + if (use_decklist) + cptr++; + + if ((rval = attach_unit(uptr, cptr)) != SCPE_OK) + return rval; + + if (use_decklist) { /* if we skipped the '@', store the actually-specified name */ + strncpy(uptr->filename, cptr-1, CBUFSIZE); + deckfile = cr_unit.fileref; /* save the deck file stream in our local variable */ + cr_unit.fileref = NULL; + nextdeck(); + } + else + checkdeck(); + +// no - don't reset the reader +// cr_reset(&cr_dev); /* reset the whole thing */ +// cp_reset(&cp_dev); + + return SCPE_OK; +} + +static t_stat cr_detach (UNIT *uptr) +{ + if (deckfile != NULL) { + fclose(deckfile); + deckfile = NULL; + } + + return detach_unit(uptr); +} + +static t_stat cp_detach (UNIT *uptr) +{ + if (cp_unit.flags & UNIT_ATT) + if (punchstate == STATION_PUNCHED) + feedcycle(FALSE, FALSE); /* flush out card just punched */ + + return detach_unit(uptr); +} + +static void op_done (void) +{ + SET_OP(OP_IDLE); + SETBIT(cr_dsw, CR_DSW_OP_COMPLETE); + SETBIT(ILSW[4], ILSW_4_1442_CARD); + calc_ints(); +} + +static t_stat cr_svc (UNIT *uptr) +{ + switch (cr_unit.flags & UNIT_OP) { + case OP_IDLE: + break; + + case OP_FEEDING: + op_done(); + break; + + case OP_READING: + if (readstate == STATION_EMPTY) { /* read active but no cards? hang */ + sim_activate(&cr_unit, cf_wait); + break; + } + + if (++cr_unit.COLUMN < 80) { + SETBIT(cr_dsw, CR_DSW_READ_RESPONSE); + SETBIT(ILSW[0], ILSW_0_1442_CARD); + calc_ints(); + sim_activate(&cr_unit, cr_wait); + } + else { + readstate = STATION_READ; + op_done(); + } + break; + + case OP_PUNCHING: + if (punchstate == STATION_EMPTY) { /* punch active but no cards? hang */ + sim_activate(&cr_unit, cf_wait); + break; + } + + if (cp_unit.flags & UNIT_LASTPUNCH) { + punchstate = STATION_PUNCHED; + op_done(); + } + else { + SETBIT(cr_dsw, CR_DSW_PUNCH_RESPONSE); + SETBIT(ILSW[0], ILSW_0_1442_CARD); + calc_ints(); + sim_activate(&cr_unit, cp_wait); + } + break; + } + + return SCPE_OK; +} + +void xio_1142_card (int32 addr, int32 func, int32 modify) +{ + char msg[80]; + int ch; + int16 wd; + t_bool lastcard; + + switch (func) { + case XIO_SENSE_DEV: + if (cp_unit.flags & UNIT_ATT) + lastcard = FALSE; /* if punch file is open, assume infinite blank cards in reader */ + else if (readstate == STATION_EMPTY || (cr_unit.flags & UNIT_ATT) == 0) + lastcard = TRUE; /* if nothing to read, hopper's empty */ + else if ((ch = getc(cr_unit.fileref)) == EOF) + lastcard = TRUE; /* there is nothing left to read for a next card */ + else { + ungetc(ch, cr_unit.fileref); /* put character back; hopper's not empty */ + lastcard = FALSE; + } + + CLRBIT(cr_dsw, CR_DSW_LAST_CARD|CR_DSW_BUSY|CR_DSW_NOT_READY); + + if (lastcard) + SETBIT(cr_dsw, CR_DSW_LAST_CARD); + + if ((cr_unit.flags & UNIT_OP) != OP_IDLE) + SETBIT(cr_dsw, CR_DSW_BUSY|CR_DSW_NOT_READY); + else if (readstate == STATION_EMPTY && punchstate == STATION_EMPTY && ! lastcard) + SETBIT(cr_dsw, CR_DSW_NOT_READY); + + if (modify & 0x01) { /* reset interrupts */ + CLRBIT(cr_dsw, CR_DSW_READ_RESPONSE|CR_DSW_PUNCH_RESPONSE); + CLRBIT(ILSW[0], ILSW_0_1442_CARD); + } + + if (modify & 0x02) { + CLRBIT(cr_dsw, CR_DSW_OP_COMPLETE); + CLRBIT(ILSW[4], ILSW_4_1442_CARD); + } + + ACC = cr_dsw; /* return the DSW */ + break; + + case XIO_READ: /* get card data into word pointed to in IOCC packet */ + if (cr_unit.flags & OP_READING) { + if (cr_unit.COLUMN < 0) { + xio_error("1442: Premature read!"); + } + else if (cr_unit.COLUMN < 80) { + WriteW(addr, readstation[cr_unit.COLUMN]); + } + else if (cr_unit.COLUMN == 80) { + xio_error("1442: Read past column 80!"); + cr_unit.COLUMN++; // don't report it again + } + } + else { + xio_error("1442: Read when not in a read cycle!"); + } + break; + + case XIO_WRITE: + if (cr_unit.flags & OP_PUNCHING) { + if (cp_unit.COLUMN < 0) { + xio_error("1442: Premature write!"); + } + else if (cp_unit.flags & UNIT_LASTPUNCH) { + xio_error("1442: Punch past last-punch column!"); + cp_unit.COLUMN = 81; + } + else if (cp_unit.COLUMN < 80) { + wd = ReadW(addr); /* store one word to punch buffer */ + punchstation[cp_unit.COLUMN] = wd & 0xFFF0; + if (wd & 0x0008) /* mark this as last column to be punched */ + SETBIT(cp_unit.flags, UNIT_LASTPUNCH); + } + else if (cp_unit.COLUMN == 80) { + xio_error("1442: Punch past column 80!"); + cp_unit.COLUMN++; // don't report it again + } + } + else { + xio_error("1442: Write when not in a punch cycle!"); + } + break; + + case XIO_CONTROL: + switch (modify & 7) { + case 1: /* start punch */ + if (punchstate != STATION_LOADED) + feedcycle(TRUE, TRUE); + + SET_OP(OP_PUNCHING); + cp_unit.COLUMN = -1; + + CLRBIT(cp_unit.flags, UNIT_LASTPUNCH); + + sim_cancel(&cr_unit); + sim_activate(&cr_unit, cp_wait); + break; + + case 2: /* feed cycle */ + feedcycle(TRUE, FALSE); + + SET_OP(OP_FEEDING); + + sim_cancel(&cr_unit); + sim_activate(&cr_unit, cf_wait); + break; + + case 4: /* start read */ + if (readstate != STATION_LOADED) + feedcycle(TRUE, FALSE); + + SET_OP(OP_READING); + cr_unit.COLUMN = -1; + + sim_cancel(&cr_unit); + sim_activate(&cr_unit, cr_wait); + break; + + case 0: + break; + + default: + sprintf(msg, "1442: Multiple operations in XIO_CONTROL: %x", modify); + xio_error(msg); + return; + } + + break; + + default: + sprintf(msg, "Invalid 1442 XIO function %x", func); + xio_error(msg); + break; + } +} diff --git a/Ibm1130/ibm1130_defs.h b/Ibm1130/ibm1130_defs.h new file mode 100644 index 00000000..570e82a4 --- /dev/null +++ b/Ibm1130/ibm1130_defs.h @@ -0,0 +1,229 @@ +/* ibm1130_defs.h: IBM-1130 simulator definitions + */ + +#include "sim_defs.h" /* main SIMH defns (include path should include .., or make a copy) */ +#include +#include + +#if defined(VMS) + # include /* to pick up 'unlink' */ +#endif + +#define MIN(a,b) (((a) <= (b)) ? (a) : (b)) +#define MAX(a,b) (((a) >= (b)) ? (a) : (b)) + +// #define ENABLE_GUI // uncomment to compile the GUI extensions + +/* ------------------------------------------------------------------------ */ +/* Architectural constants */ + +#define MAXMEMSIZE (32768) /* 32Kwords */ +#define INIMEMSIZE (16384) /* 16Kwords */ +#define MEMSIZE (cpu_unit.capac) + +#define UNIT_MSIZE (1 << (UNIT_V_UF + 7)) /* flag for memory size setting */ + +#define ILL_ADR_FLAG 0x40000000 /* an impossible 1130 address */ + +/* ------------------------------------------------------------------------ */ +/* Global state */ + +extern uint16 M[]; /* core memory, up to 32Kwords */ +extern uint16 ILSW[]; /* interrupt level status words */ +extern int32 IAR; /* instruction address register */ +extern int32 CES; /* console entry switches */ +extern int32 ACC, EXT; /* accumulator and extension */ +extern int32 ipl; /* current interrupt level (-1 = not handling irq) */ +extern int32 iplpending; /* bitfield: interrupted IPL's */ +extern int32 tbit; /* trace flag (causes level 5 IRQ after each instr) */ +extern int32 V, C; /* condition codes: overflow, carry */ +extern int32 wait_state; /* wait state (waiting for an IRQ or processor halted) */ +extern int32 int_req; /* bitfield: interrupt request levels active */ +extern int32 int_mask; /* current active interrupt mask (ipl sensitive) */ +extern int32 SR; /* switch register */ +extern int32 DR; /* display register */ +extern int32 wait_enable; /* wait state enable */ +extern int32 mem_mask; /* mem_mask - valid address mask (memsize-1) */ +extern int32 ibkpt_addr; /* breakpoint addr */ +extern int32 sim_int_char; + +#define WAIT_OP 1 /* wait state causes: wait instruction, invalid instruction*/ +#define WAIT_INVALID_OP 2 + +/* ------------------------------------------------------------------------ */ +/* memory IO routines */ + +int32 ReadW (int32 a); +void WriteW (int32 a, int32 d); + +/* ------------------------------------------------------------------------ */ +/* handy macros */ + +#define CLRBIT(v,b) ((v) &= ~(b)) +#define SETBIT(v,b) ((v) |= (b)) +#define BETWEEN(v,a,b) (((v) >= (a)) && ((v) <= (b))) + +/* ------------------------------------------------------------------------ */ +/* Simulator stop codes */ + +#define STOP_WAIT 1 /* wait, no events */ +#define STOP_INVALID_INSTR 2 /* bad instruction */ +#define STOP_IBKPT 3 /* simulator breakpoint */ +#define STOP_INCOMPLETE 4 /* simulator coding not complete here */ +#define STOP_POWER_OFF 5 /* no power */ + +#define IORETURN(f,v) ((f)? (v): SCPE_OK) /* cond error return */ + +#define INT_REQ_0 0x01 /* bits for interrupt levels (ipl, iplpending, int_req, int_mask) */ +#define INT_REQ_1 0x02 +#define INT_REQ_2 0x04 +#define INT_REQ_3 0x08 +#define INT_REQ_4 0x10 +#define INT_REQ_5 0x20 + +#define XIO_UNUSED 0x00 /* XIO commands */ +#define XIO_WRITE 0x01 +#define XIO_READ 0x02 +#define XIO_SENSE_IRQ 0x03 +#define XIO_CONTROL 0x04 +#define XIO_INITW 0x05 +#define XIO_INITR 0x06 +#define XIO_SENSE_DEV 0x07 + +#define XIO_FAILED 0x20 /* fake function to record error */ + +/* ILSW bits - set by appropriate device whenever an interrupt is outstanding */ + +#define ILSW_0_1442_CARD 0x8000 /* not actually used */ + +#define ILSW_1_SCA 0x8000 +#define ILSW_1_1132_PRINTER 0x4000 + +#define ILSW_2_1131_DISK 0x8000 + +#define ILSW_2_2310_DRV_1 0x4000 +#define ILSW_2_2310_DRV_2 0x2000 +#define ILSW_2_2310_DRV_3 0x1000 +#define ILSW_2_2310_DRV_4 0x0800 /* can have 2310 or 2311 */ + +#define ILSW_2_2311_DRV_1_DISK_1 0x4000 +#define ILSW_2_2311_DRV_1_DISK_2 0x2000 +#define ILSW_2_2311_DRV_1_DISK_3 0x1000 +#define ILSW_2_2311_DRV_1_DISK_4 0x0800 + +#define ILSW_2_2311_DRV_1_DISK_5 0x0400 +#define ILSW_2_2311_DRV_2_DISK_1 0x0200 +#define ILSW_2_2311_DRV_2_DISK_2 0x0100 +#define ILSW_2_2311_DRV_2_DISK_3 0x0080 +#define ILSW_2_2311_DRV_2_DISK_4 0x0040 +#define ILSW_2_2311_DRV_2_DISK_5 0x0020 + +#define ILSW_2_SAC_BIT_11 0x0010 +#define ILSW_2_SAC_BIT_12 0x0008 +#define ILSW_2_SAC_BIT_13 0x0004 +#define ILSW_2_SAC_BIT_14 0x0002 +#define ILSW_2_SAC_BIT_15 0x0001 + +#define ILSW_3_1627_PLOTTER 0x8000 +#define ILSW_3_SAC_BIT_01 0x4000 +#define ILSW_3_SAC_BIT_02 0x2000 +#define ILSW_3_SAC_BIT_03 0x1000 +#define ILSW_3_2250_DISPLAY 0x0800 +#define ILSW_3_SYSTEM7 0x0800 +#define ILSW_3_SAC_BIT_05 0x0400 +#define ILSW_3_SAC_BIT_06 0x0200 +#define ILSW_3_SAC_BIT_07 0x0100 +#define ILSW_3_SAC_BIT_08 0x0080 +#define ILSW_3_SAC_BIT_09 0x0040 +#define ILSW_3_SAC_BIT_10 0x0020 +#define ILSW_3_SAC_BIT_11 0x0010 +#define ILSW_3_SAC_BIT_12 0x0008 +#define ILSW_3_SAC_BIT_13 0x0004 +#define ILSW_3_SAC_BIT_14 0x0002 +#define ILSW_3_SAC_BIT_15 0x0001 + +#define ILSW_4_1134_TAPE 0x8000 +#define ILSW_4_1055_TAPE 0x8000 +#define ILSW_4_CONSOLE 0x4000 +#define ILSW_4_1442_CARD 0x2000 +#define ILSW_4_2501_CARD 0x1000 +#define ILSW_4_1403_PRINTER 0x0800 +#define ILSW_4_1231_MARK 0x0400 +#define ILSW_4_SAC_BIT_06 0x0200 +#define ILSW_4_SAC_BIT_07 0x0100 +#define ILSW_4_SAC_BIT_08 0x0080 +#define ILSW_4_SAC_BIT_09 0x0040 +#define ILSW_4_SAC_BIT_10 0x0020 +#define ILSW_4_SAC_BIT_11 0x0010 +#define ILSW_4_SAC_BIT_12 0x0008 +#define ILSW_4_SAC_BIT_13 0x0004 +#define ILSW_4_SAC_BIT_14 0x0002 +#define ILSW_4_SAC_BIT_15 0x0001 + +#define ILSW_5_INT_RUN 0x8000 +#define ILSW_5_PROGRAM_STOP 0x8000 +#define ILSW_5_SAC_BIT_01 0x4000 +#define ILSW_5_SAC_BIT_02 0x2000 +#define ILSW_5_SAC_BIT_03 0x1000 +#define ILSW_5_SAC_BIT_04 0x0800 +#define ILSW_5_SAC_BIT_05 0x0400 +#define ILSW_5_SAC_BIT_06 0x0200 +#define ILSW_5_SAC_BIT_07 0x0100 +#define ILSW_5_SAC_BIT_08 0x0080 +#define ILSW_5_SAC_BIT_09 0x0040 +#define ILSW_5_SAC_BIT_10 0x0020 +#define ILSW_5_SAC_BIT_11 0x0010 +#define ILSW_5_SAC_BIT_12 0x0008 +#define ILSW_5_SAC_BIT_13 0x0004 +#define ILSW_5_SAC_BIT_14 0x0002 +#define ILSW_5_SAC_BIT_15 0x0001 + +//* console DSW bits + +#define CON_DSW_PROGRAM_STOP 0x8000 +#define CON_DSW_INT_RUN 0x4000 + +/* prototypes: xio handlers */ + +void xio_1131_console (int32 addr, int32 func, int32 modify); // console keyboard and printer +void xio_1142_card (int32 addr, int32 func, int32 modify); // standard card reader/punch +void xio_1134_papertape (int32 addr, int32 func, int32 modify); // paper tape reader/punch +void xio_disk (int32 addr, int32 func, int32 modify, int drv); // internal CPU disk +void xio_1627_plotter (int32 addr, int32 func, int32 modify); // XY plotter +void xio_1132_printer (int32 addr, int32 func, int32 modify); // standard line printer +void xio_1131_switches (int32 addr, int32 func, int32 modify); // console buttons & switches +void xio_1231_optical (int32 addr, int32 func, int32 modify); // optical mark page reader +void xio_2501_card (int32 addr, int32 func, int32 modify); // alternate high-speed card reader +void xio_1131_synch (int32 addr, int32 func, int32 modify); // synchronous communications adapter +void xio_system7 (int32 addr, int32 func, int32 modify); // system/7 interprocessor IO link +void xio_1403_printer (int32 addr, int32 func, int32 modify); // alternate high-speed printer +void xio_2250_display (int32 addr, int32 func, int32 modify); // vector display processor +void xio_error (char *msg); + +void bail (char *msg); +t_stat load_cr_boot (int drv); +t_stat cr_boot (int unitno); +void calc_ints (void); /* recalculate interrupt bitmask */ +void trace_io (char *fmt, ...); /* debugging printout */ +void panic (char *msg); /* bail out of simulator */ +char *upcase(char *str); + +/* GUI interface routines */ +void remark_cmd (char *remark); +void stuff_cmd (char *cmd); +t_bool keyboard_is_locked (void); +void forms_check (int set); /* device notification to console lamp display */ +void print_check (int set); +void keyboard_selected (int select); +void disk_ready (int ready); +void disk_unlocked (int unlocked); + +#ifdef ENABLE_GUI +# define GUI_BEGIN_CRITICAL_SECTION begin_critical_section(); +# define GUI_END_CRITICAL_SECTION end_critical_section(); + void begin_critical_section (void); + void end_critical_section (void); +#else +# define GUI_BEGIN_CRITICAL_SECTION +# define GUI_END_CRITICAL_SECTION +#endif diff --git a/Ibm1130/ibm1130_disk.c b/Ibm1130/ibm1130_disk.c new file mode 100644 index 00000000..9e7dad99 --- /dev/null +++ b/Ibm1130/ibm1130_disk.c @@ -0,0 +1,441 @@ +/* ibm1130_disk.c: IBM 1130 disk IO simulator + +NOTE - there is a problem with this code. The Device Status Word (DSW) is +computed from current conditions when requested by an XIO load status +command; the value of DSW available to the simulator's examine & save +commands may NOT be accurate. This should probably be fixed. + + Copyright (c) 2002, Brian Knittel + Based on PDP-11 simulator written by Robert M Supnik + + Revision History + + 31July2001 - Derived from pdp11_stddev.c, which carries this disclaimer: + Copyright (c) 1993-2001, Robert M Supnik + + Permission is hereby granted, free of charge, to any person obtaining a + copy of this software and associated documentation files (the "Software"), + to deal in the Software without restriction, including without limitation + the rights to use, copy, modify, merge, publish, distribute, sublicense, + and/or sell copies of the Software, and to permit persons to whom the + Software is furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + ROBERT M SUPNIK BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + Except as contained in this notice, the name of Robert M Supnik shall not + be used in advertising or otherwise to promote the sale, use or other dealings + in this Software without prior written authorization from Robert M Supnik. +*/ + +#include "ibm1130_defs.h" + +/* Constants */ + +#define DSK_NUMWD 321 /* words/sector */ +#define DSK_NUMSC 4 /* sectors/surface */ +#define DSK_NUMSF 2 /* surfaces/cylinder */ +#define DSK_NUMCY 203 /* cylinders/drive */ +#define DSK_NUMTR (DSK_NUMCY * DSK_NUMSF) /* tracks/drive */ +#define DSK_NUMDR 5 /* drives/controller */ +#define DSK_SIZE (DSK_NUMCY * DSK_NUMSF * DSK_NUMSC * DSK_NUMWD) /* words/drive */ + +#define UNIT_V_RONLY (UNIT_V_UF + 0) /* hwre write lock */ +#define UNIT_V_OPERR (UNIT_V_UF + 1) /* operation error flag */ +#define UNIT_V_HARDERR (UNIT_V_UF + 2) /* hard error flag (reset on power down) */ +#define UNIT_RONLY (1u << UNIT_V_RONLY) +#define UNIT_OPERR (1u << UNIT_V_OPERR) +#define UNIT_HARDERR (1u << UNIT_V_HARDERR) + +static int16 dsk_dsw[DSK_NUMDR] = {0}; /* device status words */ +static int16 dsk_sec[DSK_NUMDR] = {0}; /* next-sector-up */ +int32 dsk_swait = 10; /* seek time */ +int32 dsk_rwait = 10; /* rotate time */ + +#define DSK_DSW_DATA_ERROR 0x8000 /* device status word bits */ +#define DSK_DSW_OP_COMPLETE 0x4000 +#define DSK_DSW_NOT_READY 0x2000 +#define DSK_DSW_DISK_BUSY 0x1000 +#define DSK_DSW_CARRIAGE_HOME 0x0800 +#define DSK_DSW_SECTOR_MASK 0x0003 + +static t_stat dsk_svc (UNIT *uptr); +static t_stat dsk_reset (DEVICE *dptr); +static t_stat dsk_attach (UNIT *uptr, char *cptr); +static t_stat dsk_detach (UNIT *uptr); +static t_stat dsk_boot (int unitno); + +static void diskfail (UNIT *uptr, int errflag); + +/* DSK data structures + + dsk_dev disk device descriptor + dsk_unit unit descriptor + dsk_reg register list +*/ + +UNIT dsk_unit[] = { + { UDATA (&dsk_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE, DSK_SIZE) }, + { UDATA (&dsk_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE, DSK_SIZE) }, + { UDATA (&dsk_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE, DSK_SIZE) }, + { UDATA (&dsk_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE, DSK_SIZE) }, + { UDATA (&dsk_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE, DSK_SIZE) } +}; + +#define IS_ONLINE(u) (((u)->flags & (UNIT_ATT|UNIT_DIS)) == UNIT_ATT) + +/* Parameters in the unit descriptor */ + +#define CYL u3 /* current cylinder */ +#define FUNC u4 /* current function */ + +REG dsk_reg[] = { + { HRDATA (DSKDSW0, dsk_dsw[0], 16) }, + { HRDATA (DSKDSW1, dsk_dsw[1], 16) }, + { HRDATA (DSKDSW2, dsk_dsw[2], 16) }, + { HRDATA (DSKDSW3, dsk_dsw[3], 16) }, + { HRDATA (DSKDSW4, dsk_dsw[4], 16) }, + { DRDATA (STIME, dsk_swait, 24), PV_LEFT }, + { DRDATA (RTIME, dsk_rwait, 24), PV_LEFT }, + { NULL } }; + +MTAB dsk_mod[] = { + { UNIT_RONLY, 0, "write enabled", "ENABLED", NULL }, + { UNIT_RONLY, UNIT_RONLY, "write locked", "LOCKED", NULL }, + { 0 } }; + +DEVICE dsk_dev = { + "DSK", dsk_unit, dsk_reg, dsk_mod, + DSK_NUMDR, 16, 16, 1, 16, 16, + NULL, NULL, &dsk_reset, + dsk_boot, dsk_attach, dsk_detach}; + +static int32 dsk_ilswbit[DSK_NUMDR] = { /* interrupt level status word bits for the drives */ + ILSW_2_1131_DISK, + ILSW_2_2310_DRV_1, + ILSW_2_2310_DRV_2, + ILSW_2_2310_DRV_3, + ILSW_2_2310_DRV_4, +}; + +static int32 dsk_ilswlevel[DSK_NUMDR] = +{ + 2, /* interrupt levels for the drives */ + 2, 2, 2, 2 +}; + +/* xio_disk - XIO command interpreter for the disk drives */ +/* + * device status word: + * + * 0 data error, occurs when: + * 1. A modulo 4 error is detected during a read, read-check, or write operation. + * 2. The disk storage is in a read or write mode at the leading edge of a sector pulse. + * 3. A seek-incomplete signal is received from the 2311. + * 4. A write select error has occurred in the disk storage drive. + * 5. The power unsafe latch is set in the attachment. + * Conditions 1, 2, and 3 are turned off by a sense device command with modifier bit 15 + * set to 1. Conditions 4 and 5 are turned off by powering the drive off and back on. + * 1 operation complete + * 2 not ready, occurs when disk not ready or busy or disabled or off-line or + * power unsafe latch set. Also included in the disk not ready is the write select error, + * which can be a result of power unsafe or write select. + * 3 disk busy + * 4 carriage home (on cyl 0) + * 15-16: number of next sector spinning into position. + */ + +void xio_disk (int32 iocc_addr, int32 func, int32 modify, int drv) +{ + int i, rev, nsteps, newcyl, sec, nwords; + t_addr newpos; + char msg[80]; + UNIT *uptr = dsk_unit+drv; + int16 buf[DSK_NUMWD]; + + if (! BETWEEN(drv, 0, DSK_NUMDR-1)) { // hmmm, invalid drive */ + if (func != XIO_SENSE_DEV) { // tried to use it, too + sprintf(msg, "Op %x on invalid drive number %d", func, drv); + xio_error(msg); + } + return; + } + + CLRBIT(uptr->flags, UNIT_OPERR); /* clear pending error flag from previous op, if any */ + + switch (func) { + case XIO_INITR: + if (! IS_ONLINE(uptr)) { /* disk is offline */ + diskfail(uptr, UNIT_HARDERR); /* make error stick till reset or attach */ + break; + } + + sim_cancel(uptr); /* cancel any pending ops */ + dsk_dsw[drv] |= DSK_DSW_DISK_BUSY; /* and mark the disk as busy */ + + nwords = M[iocc_addr++ & mem_mask]; /* get word count w/o upsetting SAR/SBR */ + + if (nwords == 0) /* this is bad -- locks up disk controller ! */ + break; + + nwords &= 1023; /* sanity check */ + if (! BETWEEN(nwords, 1, DSK_NUMWD)) { /* count bad */ + SETBIT(uptr->flags, UNIT_OPERR); /* set data error DSW bit when op complete */ + nwords = DSK_NUMWD; /* limit xfer to proper sector size */ + } + + sec = modify & 0x07; /* get sector on cylinder */ + + if ((modify & 0x0080) == 0) { /* it's real if not a read check */ + newpos = (uptr->CYL*DSK_NUMSC*DSK_NUMSF + sec)*2*DSK_NUMWD; + if (uptr->pos != newpos) + fseek(uptr->fileref, newpos, SEEK_SET); + + fread(buf, 2, DSK_NUMWD, uptr->fileref); // read whole sector so we're in position for next read + uptr->pos = newpos + 2*DSK_NUMWD; + + trace_io("* DSK%d read %d words from %d.%d (%x) to M[%04x-%04x]", uptr-dsk_unit, nwords, uptr->CYL, sec, newpos, iocc_addr & mem_mask, + (iocc_addr + nwords - 1) & mem_mask); + + for (i = 0; i < nwords; i++) + M[iocc_addr++ & mem_mask] = buf[i]; + } + else + trace_io("* DSK%d verify %d.%d", uptr-dsk_unit, uptr->CYL, sec); + + uptr->FUNC = func; + sim_activate(uptr, dsk_rwait); + + break; + + case XIO_INITW: + if (! IS_ONLINE(uptr)) { /* disk is offline */ + diskfail(uptr, UNIT_HARDERR); /* make error stick till reset or attach */ + break; + } + + if (uptr->flags & UNIT_RONLY) { /* oops, write to RO disk? permanent error */ + diskfail(uptr, UNIT_HARDERR); + break; + } + + sim_cancel(uptr); /* cancel any pending ops */ + dsk_dsw[drv] |= DSK_DSW_DISK_BUSY; /* and mark drive as busy */ + + nwords = M[iocc_addr++ & mem_mask]; /* get word count w/o upsetting SAR/SBR */ + + if (nwords == 0) /* this is bad -- locks up disk controller ! */ + break; + + nwords &= 1023; /* sanity check */ + if (! BETWEEN(nwords, 1, DSK_NUMWD)) { /* count bad */ + SETBIT(uptr->flags, UNIT_OPERR); /* set data error DSW bit when op complete */ + nwords = DSK_NUMWD; /* limit xfer to proper sector size */ + } + + sec = modify & 0x07; /* get sector on cylinder */ + newpos = (uptr->CYL*DSK_NUMSC*DSK_NUMSF + sec)*2*DSK_NUMWD; + if (uptr->pos != newpos) + fseek(uptr->fileref, newpos, SEEK_SET); + + trace_io("* DSK%d wrote %d words from M[%04x-%04x] to %d.%d (%x)", uptr-dsk_unit, nwords, iocc_addr & mem_mask, (iocc_addr + nwords - 1) & mem_mask, uptr->CYL, sec, newpos); + + for (i = 0; i < nwords; i++) + buf[i] = M[iocc_addr++ & mem_mask]; + + for (; i < DSK_NUMWD; i++) /* rest of sector gets zeroed */ + buf[i] = 0; + + fwrite(buf, 2, DSK_NUMWD, uptr->fileref); + uptr->pos = newpos + 2*DSK_NUMWD; + + uptr->FUNC = func; + sim_activate(uptr, dsk_rwait); + break; + + case XIO_CONTROL: /* step fwd/rev */ + if (! IS_ONLINE(uptr)) { + diskfail(uptr, UNIT_HARDERR); + break; + } + + sim_cancel(uptr); + + rev = modify & 4; + nsteps = iocc_addr & 0x00FF; + if (nsteps == 0) /* 0 steps does not cause op complete interrupt */ + break; + + newcyl = uptr->CYL + (rev ? (-nsteps) : nsteps); + if (newcyl < 0) + newcyl = 0; + else if (newcyl >= DSK_NUMCY) + newcyl = DSK_NUMCY-1; + + uptr->FUNC = func; + uptr->CYL = newcyl; + sim_activate(uptr, dsk_swait); /* schedule interrupt */ + + dsk_dsw[drv] |= DSK_DSW_DISK_BUSY; + trace_io("* DSK%d at cyl %d", uptr-dsk_unit, newcyl); + break; + + case XIO_SENSE_DEV: + CLRBIT(dsk_dsw[drv], DSK_DSW_CARRIAGE_HOME|DSK_DSW_NOT_READY); + + if ((uptr->flags & UNIT_HARDERR) || (dsk_dsw[drv] & DSK_DSW_DISK_BUSY) || ! IS_ONLINE(uptr)) + SETBIT(dsk_dsw[drv], DSK_DSW_NOT_READY); + else if (uptr->CYL <= 0) { + SETBIT(dsk_dsw[drv], DSK_DSW_CARRIAGE_HOME); + uptr->CYL = 0; + } + + dsk_sec[drv] = (dsk_sec[drv] + 1) % 4; /* advance the "next sector" count every time */ + ACC = dsk_dsw[drv] | dsk_sec[drv]; + + if (modify & 0x01) { /* reset interrupts */ + CLRBIT(dsk_dsw[drv], DSK_DSW_OP_COMPLETE|DSK_DSW_DATA_ERROR); + CLRBIT(ILSW[dsk_ilswlevel[drv]], dsk_ilswbit[drv]); + } + break; + + default: + sprintf(msg, "Invalid disk XIO function %x", func); + xio_error(msg); + } +} + +/* diskfail - schedule an operation complete that sets the error bit */ + +static void diskfail (UNIT *uptr, int errflag) +{ + sim_cancel(uptr); /* cancel any pending ops */ + SETBIT(uptr->flags, errflag); /* set the error flag */ + uptr->FUNC = XIO_FAILED; /* tell svc routine why it failed */ + sim_activate(uptr, 1); /* schedule an immediate op complete interrupt */ +} + +t_stat dsk_svc (UNIT *uptr) +{ + int drv = uptr - dsk_unit; + + CLRBIT(dsk_dsw[drv], DSK_DSW_DISK_BUSY); /* activate operation complete interrupt */ + SETBIT(dsk_dsw[drv], DSK_DSW_OP_COMPLETE); + + if (uptr->flags & (UNIT_OPERR|UNIT_HARDERR)) { /* word count error or data error */ + SETBIT(dsk_dsw[drv], DSK_DSW_DATA_ERROR); + CLRBIT(uptr->flags, UNIT_OPERR); /* but don't clear hard error */ + } + + SETBIT(ILSW[dsk_ilswlevel[drv]], dsk_ilswbit[drv]); + +#ifdef XXXX + switch (uptr->FUNC) { + case XIO_CONTROL: + case XIO_INITR: + case XIO_INITW: + case XIO_FAILED: + break; + + default: + fprintf(stderr, "Unexpected FUNC %x in dsk_svc(%d)\n", uptr->FUNC, drv); + break; + + } + uptr->FUNC = -1; // we're done with this operation +#endif + + return SCPE_OK; +} + +t_stat dsk_reset (DEVICE *dptr) +{ + int drv; + UNIT *uptr; + + for (drv = 0, uptr = dsk_dev.units; drv < DSK_NUMDR; drv++, uptr++) { + sim_cancel(uptr); + + CLRBIT(ILSW[2], dsk_ilswbit[drv]); + CLRBIT(uptr->flags, UNIT_OPERR|UNIT_HARDERR); + + uptr->CYL = 0; + uptr->FUNC = -1; + dsk_dsw[drv] = (uptr->flags & UNIT_ATT) ? DSK_DSW_CARRIAGE_HOME : 0; + } + + calc_ints(); + + return SCPE_OK; +} + +static t_stat dsk_attach (UNIT *uptr, char *cptr) +{ + int drv = uptr - dsk_unit; + t_stat rval; + + sim_cancel(uptr); + + if ((rval = attach_unit(uptr, cptr)) != SCPE_OK) + return rval; + + CLRBIT(ILSW[2], dsk_ilswbit[drv]); + CLRBIT(uptr->flags, UNIT_OPERR|UNIT_HARDERR); + calc_ints(); + + uptr->CYL = 0; + uptr->FUNC = -1; + dsk_dsw[drv] = DSK_DSW_CARRIAGE_HOME; + + if (drv == 0) { + disk_ready(TRUE); + disk_unlocked(FALSE); + } + + return SCPE_OK; +} + +static t_stat dsk_detach (UNIT *uptr) +{ + t_stat rval; + int drv = uptr - dsk_unit; + + sim_cancel(uptr); + + if ((rval = detach_unit (uptr)) != SCPE_OK) + return rval; + + CLRBIT(ILSW[2], dsk_ilswbit[drv]); + CLRBIT(uptr->flags, UNIT_OPERR|UNIT_HARDERR); + calc_ints(); + + uptr->CYL = 0; + uptr->FUNC = -1; + dsk_dsw[drv] = 0; + + if (drv == 0) { + disk_unlocked(TRUE); + disk_ready(FALSE); + } + + return SCPE_OK; +} + +// boot routine - if they type BOOT DSK, load the standard boot card. + +static t_stat dsk_boot (int unitno) +{ + t_stat rval; + + if ((rval = reset_all(0)) != SCPE_OK) + return rval; + + return load_cr_boot(unitno); +} diff --git a/Ibm1130/ibm1130_prtwheel.h b/Ibm1130/ibm1130_prtwheel.h new file mode 100644 index 00000000..b57e5d37 --- /dev/null +++ b/Ibm1130/ibm1130_prtwheel.h @@ -0,0 +1,20 @@ +static struct tag_codewheel { + unsigned char ascii; + unsigned char ebcdic; +} codewheel1132[] = +{ /* characters and EBCDIC codes in printwheel order */ + 'A', 0xC1, 'B', 0xC2, 'C', 0xC3, 'D', 0xC4, + 'E', 0xC5, 'F', 0xC6, 'G', 0xC7, 'H', 0xC8, + 'I', 0xC9, 'J', 0xD1, 'K', 0xD2, 'L', 0xD3, + 'M', 0xD4, 'N', 0xD5, 'O', 0xD6, 'P', 0xD7, + 'Q', 0xD8, 'R', 0xD9, 'S', 0xE2, 'T', 0xE3, + 'U', 0xE4, 'V', 0xE5, 'W', 0xE6, 'X', 0xE7, + 'Y', 0xE8, 'Z', 0xE9, '0', 0xF0, '1', 0xF1, + '2', 0xF2, '3', 0xF3, '4', 0xF4, '5', 0xF5, + '6', 0xF6, '7', 0xF7, '8', 0xF8, '9', 0xF9, + '&', 0x50, '-', 0x60, '/', 0x61, '.', 0x4B, + '$', 0x5B, ',', 0x6B, '*', 0x5C, '(', 0x4D, + ')', 0x5D, '\'', 0x7D, '+', 0x4E, '=', 0x7E +}; + +#define WHEELCHARS (sizeof(codewheel1132)/sizeof(codewheel1132[0])) diff --git a/Ibm1130/ibm1130_stddev.c b/Ibm1130/ibm1130_stddev.c new file mode 100644 index 00000000..7d8fa67a --- /dev/null +++ b/Ibm1130/ibm1130_stddev.c @@ -0,0 +1,748 @@ +/* ibm1130_stddev.c: IBM 1130 standard I/O devices simulator + + Copyright (c) 2001, Brian Knittel + Based on PDP-11 simulator written by Robert M Supnik + + Brian Knittel + Revision History + + 31July2001 - Derived from pdp11_stddev.c, which carries this disclaimer: + + Copyright (c) 1993-2001, Robert M Supnik + + Permission is hereby granted, free of charge, to any person obtaining a + copy of this software and associated documentation files (the "Software"), + to deal in the Software without restriction, including without limitation + the rights to use, copy, modify, merge, publish, distribute, sublicense, + and/or sell copies of the Software, and to permit persons to whom the + Software is furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + ROBERT M SUPNIK BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + Except as contained in this notice, the name of Robert M Supnik shall not + be used in advertising or otherwise to promote the sale, use or other dealings + in this Software without prior written authorization from Robert M Supnik. +*/ + +#include "ibm1130_defs.h" + +/* ---------------------------------------------------------------------------- */ + +static void badio (char *dev) +{ +// the real 1130 just ignores attempts to use uninstalled devices. They get tested +// at times, so it's best to be quiet about this +// printf("%s I/O is not yet supported", dev); +// wait_state = WAIT_INVALID_OP; +} + +void xio_1134_papertape (int32 addr, int32 func, int32 modify) {badio("papertape");} +void xio_1627_plotter (int32 addr, int32 func, int32 modify) {badio("plotter");} +void xio_1231_optical (int32 addr, int32 func, int32 modify) {badio("optical mark");} +void xio_2501_card (int32 addr, int32 func, int32 modify) {badio("2501 card");} +void xio_1131_synch (int32 addr, int32 func, int32 modify) {badio("SCA");} +void xio_system7 (int32 addr, int32 func, int32 modify) {badio("System 7");} +void xio_1403_printer (int32 addr, int32 func, int32 modify) {badio("1403 printer");} + +void xio_2250_display (int32 addr, int32 func, int32 modify) +{ + if (func != XIO_CONTROL) + badio("2250 display"); // resmon issues stop control, so ignore XIO_CONTROL +} + +/* ---------------------------------------------------------------------------- */ + +static int32 tti_dsw = 0; /* device status words */ +static int32 tto_dsw = 0; +static int32 con_dsw = 0; + +static t_stat tti_svc (UNIT *uptr); +static t_stat tto_svc (UNIT *uptr); +static t_stat tti_reset (DEVICE *dptr); +static t_stat tto_reset (DEVICE *dptr); + +extern t_stat sim_poll_kbd (void); +extern t_stat sim_wait_kbd (void); +extern t_stat sim_putchar (int32 out); + +extern UNIT *sim_clock_queue; + +#define CSET_MASK 1 /* character set */ +#define CSET_NORMAL 0 +#define CSET_ASCII 1 + +#define IRQ_KEY 0x11 /* ctrl-Q */ +#define PROGRAM_STOP_KEY 0x03 /* ctrl-C */ + +#include "ibm1130_conout.h" /* conout_to_ascii table */ +#include "ibm1130_conin.h" /* ascii_to_conin table */ + +/* TTI data structures + + tti_dev TTI device descriptor + tti_unit TTI unit descriptor + tti_reg TTI register list +*/ + +UNIT tti_unit = { UDATA (&tti_svc, 0, 0), KBD_POLL_WAIT }; + +REG tti_reg[] = { + { ORDATA (BUF, tti_unit.buf, 8) }, + { ORDATA (DSW, tti_dsw, 16) }, + { DRDATA (POS, tti_unit.pos, 32), PV_LEFT }, + { DRDATA (STIME, tti_unit.wait, 24), REG_NZ + PV_LEFT }, + { NULL } }; + +MTAB tti_mod[] = { + { CSET_MASK, CSET_NORMAL, NULL, "1130", NULL}, + { CSET_MASK, CSET_ASCII, NULL, "ASCII", NULL}, + { 0 } }; + +DEVICE tti_dev = { + "KEYBOARD", &tti_unit, tti_reg, tti_mod, + 1, 10, 31, 1, 8, 8, + NULL, NULL, &tti_reset, + NULL, NULL, NULL }; + +/* TTO data structures + + tto_dev TTO device descriptor + tto_unit TTO unit descriptor + tto_reg TTO register list +*/ + +UNIT tto_unit = { UDATA (&tto_svc, 0, 0), SERIAL_OUT_WAIT }; + +REG tto_reg[] = { + { ORDATA (BUF, tto_unit.buf, 8) }, + { ORDATA (DSW, tto_dsw, 16) }, + { DRDATA (POS, tto_unit.pos, 32), PV_LEFT }, + { DRDATA (STIME, tto_unit.wait, 24), PV_LEFT }, + { NULL } }; + +MTAB tto_mod[] = { + { CSET_MASK, CSET_NORMAL, NULL, "1130", NULL}, + { CSET_MASK, CSET_ASCII, NULL, "ASCII", NULL}, + { 0 } }; + +DEVICE tto_dev = { + "TTO", &tto_unit, tto_reg, tto_mod, + 1, 10, 31, 1, 8, 8, + NULL, NULL, &tto_reset, + NULL, NULL, NULL }; + +/* Terminal input routines + + tti_svc process event (character ready) + tti_reset process reset + tto_svc process event (print character) + tto_reset process reset +*/ + +#define TT_DSW_PRINTER_RESPONSE 0x8000 +#define TT_DSW_KEYBOARD_RESPONSE 0x4000 +#define TT_DSW_INTERRUPT_REQUEST 0x2000 +#define TT_DSW_KEYBOARD_CONSOLE 0x1000 +#define TT_DSW_PRINTER_BUSY 0x0800 +#define TT_DSW_PRINTER_NOT_READY 0x0400 +#define TT_DSW_KEYBOARD_BUSY 0x0200 + +void xio_1131_console (int32 iocc_addr, int32 func, int32 modify) +{ + int ch; + char msg[80]; + + switch (func) { + case XIO_CONTROL: + SETBIT(tti_dsw, TT_DSW_KEYBOARD_BUSY); + keyboard_selected(TRUE); +// sim_activate(&tti_unit, tti_unit.wait); /* poll keyboard never stops */ + break; + + case XIO_READ: + WriteW(iocc_addr, tti_unit.buf); + CLRBIT(tti_dsw, TT_DSW_KEYBOARD_BUSY); + keyboard_selected(FALSE); + break; + + case XIO_WRITE: + ch = (ReadW(iocc_addr) >> 8) & 0xFF; /* get character to write */ + + if ((tto_unit.flags & CSET_MASK) == CSET_NORMAL) + ch = conout_to_ascii[ch]; /* convert to ASCII */ + + if (ch == 0) + ch = '?'; /* hmmm, unknown character */ + + tto_unit.buf = ch; /* save character to write */ + SETBIT(tto_dsw, TT_DSW_PRINTER_BUSY); + sim_activate(&tto_unit, tto_unit.wait); /* schedule interrupt */ + break; + + case XIO_SENSE_DEV: + ACC = tto_dsw | tti_dsw; + if (modify & 0x01) { /* reset interrupts */ + CLRBIT(tto_dsw, TT_DSW_PRINTER_RESPONSE); + CLRBIT(tti_dsw, TT_DSW_KEYBOARD_RESPONSE); + CLRBIT(ILSW[4], ILSW_4_CONSOLE); + } + break; + + default: + sprintf(msg, "Invalid console XIO function %x", func); + xio_error(msg); + } +} + +static void Beep (void) // notify user keyboard was locked or key was bad +{ + sim_putchar(7); +} + +// tti_svc - keyboard polling (never stops) + +t_stat tti_svc (UNIT *uptr) +{ + int32 temp; + + sim_activate(&tti_unit, tti_unit.wait); /* continue polling */ + + temp = sim_poll_kbd(); + + if (temp < SCPE_KFLAG) + return temp; /* no char or error? */ + + temp &= 0xFF; /* remove SCPE_KFLAG */ + + if (temp == IRQ_KEY) { /* interrupt request key */ + SETBIT(tti_dsw, TT_DSW_INTERRUPT_REQUEST); /* queue interrupt */ + SETBIT(ILSW[4], ILSW_4_CONSOLE); + calc_ints(); + + return SCPE_OK; + } + + if (temp == PROGRAM_STOP_KEY) { /* simulate the program stop button */ + SETBIT(con_dsw, CON_DSW_PROGRAM_STOP); + SETBIT(ILSW[5], ILSW_5_PROGRAM_STOP); + calc_ints(); + + return SCPE_OK; + } + + if (tti_dsw & TT_DSW_KEYBOARD_BUSY) { /* only store character if it was requested (keyboard unlocked) */ + if ((uptr->flags & CSET_MASK) == CSET_NORMAL) + temp = ascii_to_conin[temp]; + + if (temp == 0) { /* ignore invalid characters */ + Beep(); + calc_ints(); + return SCPE_OK; + } + + tti_unit.buf = temp & 0xFFFE; /* save keystroke except last bit (not defined, */ + tti_unit.pos = tti_unit.pos + 1; /* but it lets us distinguish 0 from no punch ' ' */ + + CLRBIT(tti_dsw, TT_DSW_KEYBOARD_BUSY); /* clear busy flag (relock keyboard) */ + keyboard_selected(FALSE); + + SETBIT(tti_dsw, TT_DSW_KEYBOARD_RESPONSE); /* queue interrupt */ + SETBIT(ILSW[4], ILSW_4_CONSOLE); + calc_ints(); + } + else + Beep(); + + return SCPE_OK; +} + +t_stat tti_reset (DEVICE *dptr) +{ + tti_unit.buf = 0; + tti_dsw = 0; + + CLRBIT(ILSW[4], ILSW_4_CONSOLE); + calc_ints(); + keyboard_selected(FALSE); + + sim_activate(&tti_unit, tti_unit.wait); /* always poll keyboard */ + + return SCPE_OK; +} + +t_bool keyboard_is_locked (void) /* return TRUE if keyboard is not expecting a character */ +{ + return (tti_dsw & TT_DSW_KEYBOARD_BUSY) == 0; +} + +t_stat tto_svc (UNIT *uptr) +{ + int32 temp; + int ch; + + CLRBIT(tto_dsw, TT_DSW_PRINTER_BUSY); + SETBIT(tto_dsw, TT_DSW_PRINTER_RESPONSE); + + SETBIT(ILSW[4], ILSW_4_CONSOLE); + calc_ints(); + + ch = tto_unit.buf & 0xFF; + + switch (ch) { + case IGNR: + break; + + case CRLF: + if ((temp = sim_putchar('\r')) != SCPE_OK) + return temp; + if ((temp = sim_putchar('\n')) != SCPE_OK) + return temp; + + break; + + default: + if ((temp = sim_putchar(ch)) != SCPE_OK) + return temp; + + break; + } + + tto_unit.pos = tto_unit.pos + 1; /* hmm, why do we count these? */ + + return SCPE_OK; +} + +t_stat tto_reset (DEVICE *dptr) +{ + tto_unit.buf = 0; + tto_dsw = 0; + + CLRBIT(ILSW[4], ILSW_4_CONSOLE); + calc_ints(); + + sim_cancel(&tto_unit); /* deactivate unit */ + + return SCPE_OK; +} + +/*************************************************************************************** + * 1132 PRINTER + ***************************************************************************************/ + +#define PRT_DSW_READ_EMITTER_RESPONSE 0x8000 +#define PRT_DSW_SKIP_RESPONSE 0x4000 +#define PRT_DSW_SPACE_RESPONSE 0x2000 +#define PRT_DSW_CARRIAGE_BUSY 0x1000 +#define PRT_DSW_PRINT_SCAN_CHECK 0x0800 +#define PRT_DSW_NOT_READY 0x0400 +#define PRT_DSW_PRINTER_BUSY 0x0200 + +#define PRT_DSW_CHANNEL_MASK 0x00FF +#define PRT_DSW_CHANNEL_1 0x0080 +#define PRT_DSW_CHANNEL_2 0x0040 +#define PRT_DSW_CHANNEL_3 0x0020 +#define PRT_DSW_CHANNEL_4 0x0010 +#define PRT_DSW_CHANNEL_5 0x0008 +#define PRT_DSW_CHANNEL_6 0x0004 +#define PRT_DSW_CHANNEL_9 0x0002 +#define PRT_DSW_CHANNEL_12 0x0001 + +#define IS_ONLINE(u) (((u)->flags & (UNIT_ATT|UNIT_DIS)) == UNIT_ATT) + +static t_stat prt_svc (UNIT *uptr); +static t_stat prt_reset (DEVICE *dptr); +static t_stat prt_attach (UNIT *uptr, char *cptr); +static t_stat prt_detach (UNIT *uptr); + +static int16 prt_dsw = 0; /* device status word */ +static int32 prt_swait = 500; /* line skip wait */ +static int32 prt_cwait = 1000; /* character rotation wait */ + +#define UNIT_V_FORMCHECK (UNIT_V_UF + 0) /* out of paper error */ +#define UNIT_V_DATACHECK (UNIT_V_UF + 1) /* printer overrun error */ +#define UNIT_V_SKIPPING (UNIT_V_UF + 2) /* printer skipping */ +#define UNIT_V_SPACING (UNIT_V_UF + 3) /* printer is spacing */ +#define UNIT_V_PRINTING (UNIT_V_UF + 4) /* printer printing */ + +#define UNIT_FORMCHECK (1u << UNIT_V_FORMCHECK) +#define UNIT_DATACHECK (1u << UNIT_V_DATACHECK) +#define UNIT_SKIPPING (1u << UNIT_V_SKIPPING) +#define UNIT_SPACING (1u << UNIT_V_SPACING) +#define UNIT_PRINTING (1u << UNIT_V_PRINTING) + +UNIT prt_unit[] = { + { UDATA (&prt_svc, UNIT_ATTABLE, 0) }, +}; + +/* Parameter in the unit descriptor */ + +#define CMD_NONE 0 +#define CMD_SPACE 1 +#define CMD_SKIP 2 +#define CMD_PRINT 3 + +REG prt_reg[] = { + { HRDATA (PRTDSW, prt_dsw, 16) }, /* device status word */ + { DRDATA (STIME, prt_swait, 24), PV_LEFT }, /* line skip wait */ + { DRDATA (CTIME, prt_cwait, 24), PV_LEFT }, /* character rotation wait */ + { NULL } }; + +DEVICE prt_dev = { + "PRT", prt_unit, prt_reg, NULL, + 1, 16, 16, 1, 16, 16, + NULL, NULL, &prt_reset, + NULL, prt_attach, prt_detach}; + +#define PRT_COLUMNS 120 +#define PRT_ROWLEN 120 +#define MAX_OVPRINT 20 + +static char prtbuf[PRT_ROWLEN*MAX_OVPRINT]; +static int nprint[PRT_COLUMNS], ncol[MAX_OVPRINT], maxnp; +static int prt_nchar, prt_row; /* current printwheel position, current page row */ +static int prt_nnl; /* number of queued newlines */ + +#define CC_CHANNEL_1 0x0080 /* carriage control tape punch values */ +#define CC_CHANNEL_2 0x0040 +#define CC_CHANNEL_3 0x0020 +#define CC_CHANNEL_4 0x0010 +#define CC_CHANNEL_5 0x0008 +#define CC_CHANNEL_6 0x0004 +#define CC_CHANNEL_9 0x0002 +#define CC_CHANNEL_12 0x0001 + +#define PRT_PAGELENGTH 66 + +// glunk need to fill these two arrays in -- cctape and codewheel1132 + +static int cctape[PRT_PAGELENGTH]; /* standard carriage control tape */ + +static struct tag_ccpunches { /* list of rows and punches on tape */ + int row, channels; +} ccpunches[] = { + 7, CC_CHANNEL_12, /* these came from the tape in our printer */ + 13, CC_CHANNEL_1 /* modulo 66 */ +}; + +#include "ibm1130_prtwheel.h" + +// reset_prt_line - clear the print line following paper advancement + +static void reset_prt_line (void) +{ + memset(nprint, 0, sizeof(nprint)); + memset(ncol, 0, sizeof(ncol)); + maxnp = 0; +} + +// save_prt_line - fire hammers for character 'ch' + +static t_bool save_prt_line (int ch) +{ + int i, r, addr = 32; + int32 mask = 0, wd = 0; + + for (i = 0; i < PRT_COLUMNS; i++) { + if (mask == 0) { // fetch next word from memory + mask = 0x8000; + wd = M[addr++]; + } + + if (wd & mask) { // hammer is to fire in this column + if ((r = nprint[i]) < MAX_OVPRINT) { + if (ncol[r] <= i) { // we haven't moved this far yet + if (ncol[r] == 0) // first char in this row? + memset(prtbuf+r*PRT_ROWLEN, ' ', PRT_COLUMNS); // blank out the new row + ncol[r] = i+1; // remember new row length + } + prtbuf[r*PRT_ROWLEN + i] = (char) ch; // save the character + + nprint[i]++; // remember max overprintings for this column + maxnp = MAX(maxnp, nprint[i]); + } + } + + mask >>= 1; // prepare to examine next bit + } + + return wd & 1; // return TRUE if the last word has lsb set, which means all bits had been set +} + +// write_line - write collected line to output file. No need to trim spaces as the hammers +// are never fired for them, so ncol[r] is the last printed position on each line. + +static void flush_prt_line (FILE *fd, t_bool space) +{ + int r; + + if (! (space || maxnp)) // nothing to do + return; + + prt_row = (prt_row+1) % PRT_PAGELENGTH; // NEXT line + + if (space && ! maxnp) { // spacing only + if (prt_row == 0 && prt_nnl) { + putc('\f', fd); + prt_nnl = 0; + } + else + prt_nnl++; + + return; + } + + if (prt_nnl) { // there are queued newlines + if (prt_row == 0 && prt_nnl) { // we spaced to top of form: use formfeed + putc('\f', fd); + prt_nnl = 0; + } + else { + while (prt_nnl > 0) { // spit out queued newlines +#ifdef WIN32 + putc('\r', fd); // DOS/Windows: end with cr/lf +#endif + putc('\n', fd); // otherwise end with lf + prt_nnl--; + } + } + } + + for (r = 0; r < maxnp; r++) { + if (r > 0) + putc('\r', fd); // carriage return between overprinted lines + fwrite(&prtbuf[r*PRT_ROWLEN], 1, ncol[r], fd); + } + + reset_prt_line(); + + prt_nnl++; // queue a newline +} + +#define PRT_CMD_START_PRINTER 0x0080 +#define PRT_CMD_STOP_PRINTER 0x0040 +#define PRT_CMD_START_CARRIAGE 0x0004 +#define PRT_CMD_STOP_CARRIAGE 0x0002 +#define PRT_CMD_SPACE 0x0001 + +#define PRT_CMD_MASK 0x00C7 + +/* xio_1132_printer - XIO command interpreter for the 1132 printer */ + +void xio_1132_printer (int32 iocc_addr, int32 func, int32 modify) +{ + char msg[80]; + UNIT *uptr = &prt_unit[0]; + + switch (func) { + case XIO_READ: + M[iocc_addr & mem_mask] = codewheel1132[prt_nchar].ebcdic << 8; + + if ((uptr->flags & UNIT_PRINTING) == 0) /* if we're not printing, advance this after every test */ + prt_nchar = (prt_nchar + 1) % WHEELCHARS; + break; + + case XIO_SENSE_DEV: + ACC = prt_dsw; + if (modify & 0x01) { /* reset interrupts */ + CLRBIT(prt_dsw, PRT_DSW_READ_EMITTER_RESPONSE | PRT_DSW_SKIP_RESPONSE | PRT_DSW_SPACE_RESPONSE); + CLRBIT(ILSW[1], ILSW_1_1132_PRINTER); + } + break; + + case XIO_CONTROL: + if (modify & PRT_CMD_START_PRINTER) + SETBIT(uptr->flags, UNIT_PRINTING); + + if (modify & PRT_CMD_STOP_PRINTER) + CLRBIT(uptr->flags, UNIT_PRINTING); + + if (modify & PRT_CMD_START_CARRIAGE) + SETBIT(uptr->flags, UNIT_SKIPPING); + + if (modify & PRT_CMD_STOP_CARRIAGE) + CLRBIT(uptr->flags, UNIT_SKIPPING); + + if (modify & PRT_CMD_SPACE) + SETBIT(uptr->flags, UNIT_SPACING); + + sim_cancel(uptr); + if (uptr->flags & PRT_CMD_MASK) { // busy bit = doing something + SETBIT(prt_dsw, PRT_DSW_PRINTER_BUSY); + sim_activate(uptr, prt_cwait); + } + else + CLRBIT(prt_dsw, PRT_DSW_PRINTER_BUSY); + + if (uptr->flags & (UNIT_SKIPPING|UNIT_SPACING)) + SETBIT(prt_dsw, PRT_DSW_CARRIAGE_BUSY); + else + CLRBIT(prt_dsw, PRT_DSW_CARRIAGE_BUSY); + + if ((uptr->flags & (UNIT_SKIPPING|UNIT_SPACING)) == (UNIT_SKIPPING|UNIT_SPACING)) { + sprintf(msg, "1132 printer skip and space at same time?"); + xio_error(msg); + } + break; + + default: + sprintf(msg, "Invalid 1132 printer XIO function %x", func); + xio_error(msg); + } +} + +#define SET_ACTION(u,a) {(u)->flags &= ~(UNIT_SKIPPING|UNIT_SPACING|UNIT_PRINTING); (u)->flags |= a;} + +static t_stat prt_svc (UNIT *uptr) +{ + if (prt_dsw & PRT_DSW_NOT_READY) { // cancel operation if printer went offline + SETBIT(uptr->flags, UNIT_FORMCHECK); + SET_ACTION(uptr, 0); + forms_check(TRUE); // and turn on forms check lamp + return SCPE_OK; + } + + if (uptr->flags & UNIT_SPACING) { + flush_prt_line(uptr->fileref, TRUE); + + prt_dsw = prt_dsw & ~PRT_DSW_CHANNEL_MASK; + prt_dsw |= cctape[prt_row]; + + SETBIT(prt_dsw, PRT_DSW_SPACE_RESPONSE); + SETBIT(ILSW[1], ILSW_1_1132_PRINTER); + calc_ints(); + + CLRBIT(uptr->flags, UNIT_SPACING); // done with this + CLRBIT(prt_dsw, PRT_DSW_PRINTER_BUSY|PRT_DSW_CARRIAGE_BUSY); + } + + if (uptr->flags & UNIT_SKIPPING) { + do { + flush_prt_line(uptr->fileref, TRUE); + prt_dsw = (prt_dsw & ~PRT_DSW_CHANNEL_MASK) | cctape[prt_row]; + } while (cctape[prt_row] == 0); // slew directly to a cc tape punch + + SETBIT(prt_dsw, PRT_DSW_SKIP_RESPONSE); + SETBIT(ILSW[1], ILSW_1_1132_PRINTER); + calc_ints(); + } + + if (uptr->flags & UNIT_PRINTING) { + if (! save_prt_line(codewheel1132[prt_nchar].ascii)) { // save previous printed line + SETBIT(uptr->flags, UNIT_DATACHECK); // buffer wasn't set in time + SET_ACTION(uptr, 0); + print_check(TRUE); // and turn on forms check lamp + return SCPE_OK; + } + + prt_nchar = (prt_nchar + 1) % WHEELCHARS; // advance print drum + + SETBIT(prt_dsw, PRT_DSW_READ_EMITTER_RESPONSE); // issue interrupt to tell printer to set buffer + SETBIT(ILSW[1], ILSW_1_1132_PRINTER); // we'll save the printed stuff just before next emitter response (later than on real 1130) + calc_ints(); + } + + if (uptr->flags & (UNIT_SPACING|UNIT_SKIPPING|UNIT_PRINTING)) { // still doing something + SETBIT(prt_dsw, PRT_DSW_PRINTER_BUSY); + sim_activate(uptr, prt_cwait); + } + else + CLRBIT(prt_dsw, PRT_DSW_PRINTER_BUSY); + + return SCPE_OK; +} + +static t_stat prt_reset (DEVICE *dptr) +{ + UNIT *uptr = &prt_unit[0]; + int i; + + sim_cancel(uptr); + + memset(cctape, 0, sizeof(cctape)); // copy punch list into carriage control tape image + for (i = 0; i < (sizeof(ccpunches)/sizeof(ccpunches[0])); i++) + cctape[ccpunches[i].row-1] |= ccpunches[i].channels; + + CLRBIT(ILSW[1], ILSW_1_1132_PRINTER); + CLRBIT(uptr->flags, UNIT_FORMCHECK|UNIT_DATACHECK); + SET_ACTION(uptr, 0); + calc_ints(); + + prt_nchar = 0; + prt_row = 0; + prt_nnl = 0; + prt_dsw = cctape[prt_row]; + reset_prt_line(); + + if (! IS_ONLINE(uptr)) + SETBIT(prt_dsw, PRT_DSW_NOT_READY); + + forms_check(FALSE); + return SCPE_OK; +} + +static t_stat prt_attach (UNIT *uptr, char *cptr) +{ + t_stat rval; + + if (uptr->flags & UNIT_ATT) { + if ((rval = prt_detach(uptr)) != SCPE_OK) { + prt_dsw |= PRT_DSW_NOT_READY; + return rval; + } + } + + sim_cancel(uptr); + + if ((rval = attach_unit(uptr, cptr)) != SCPE_OK) { + prt_dsw |= PRT_DSW_NOT_READY; + return rval; + } + + CLRBIT(ILSW[1], ILSW_1_1132_PRINTER); + CLRBIT(uptr->flags, UNIT_FORMCHECK|UNIT_DATACHECK); + SET_ACTION(uptr, 0); + calc_ints(); + + prt_nchar = 0; + prt_nnl = 0; + prt_row = 0; + prt_dsw = (prt_dsw & ~PRT_DSW_CHANNEL_MASK) | cctape[prt_row]; + if (IS_ONLINE(uptr)) + CLRBIT(prt_dsw, PRT_DSW_NOT_READY); + else + SETBIT(prt_dsw, PRT_DSW_NOT_READY); + + reset_prt_line(); + forms_check(FALSE); + return SCPE_OK; +} + +static t_stat prt_detach (UNIT *uptr) +{ + t_stat rval; + + flush_prt_line(uptr->fileref, FALSE); + + if ((rval = detach_unit(uptr)) != SCPE_OK) + return rval; + + sim_cancel(uptr); + + CLRBIT(ILSW[1], ILSW_1_1132_PRINTER); + CLRBIT(uptr->flags, UNIT_FORMCHECK|UNIT_DATACHECK); + SET_ACTION(uptr, 0); + calc_ints(); + + SETBIT(prt_dsw, PRT_DSW_NOT_READY); + + forms_check(FALSE); + return SCPE_OK; +} diff --git a/Ibm1130/ibm1130_sys.c b/Ibm1130/ibm1130_sys.c new file mode 100644 index 00000000..f46a7864 --- /dev/null +++ b/Ibm1130/ibm1130_sys.c @@ -0,0 +1,416 @@ +/* ibm1130_sys.c: IBM 1130 simulator interface + + Copyright (c) 2002, Brian Knittel + Based on PDP-11 simulator written by Robert M Supnik + + Revision History + 0.24 2002Mar27 - Fixed BOSC bug; BOSC works in short instructions too + 0.23 2002Feb26 - Added @decklist feature for ATTACH CR. + 0.22 2002Feb26 - Replaced "strupr" with "upcase" for compatibility. + 0.21 2002Feb25 - Some compiler compatibiity changes, couple of compiler-detected + bugs + 0.01 2001Jul31 - Derived from pdp11_sys.c, which carries this disclaimer: + + Copyright (c) 1993-2001, Robert M Supnik + Permission is hereby granted, free of charge, to any person obtaining a + copy of this software and associated documentation files (the "Software"), + to deal in the Software without restriction, including without limitation + the rights to use, copy, modify, merge, publish, distribute, sublicense, + and/or sell copies of the Software, and to permit persons to whom the + Software is furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + ROBERT M SUPNIK BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + Except as contained in this notice, the name of Robert M Supnik shall not + be used in advertising or otherwise to promote the sale, use or other dealings + in this Software without prior written authorization from Robert M Supnik. +*/ + +#include "ibm1130_defs.h" +#include + +extern DEVICE cpu_dev, console_dev, dsk_dev, cr_dev, cp_dev; +extern DEVICE tti_dev, tto_dev, prt_dev, log_dev; +extern UNIT cpu_unit; +extern REG cpu_reg[]; +extern int32 saved_PC; + +/* SCP data structures and interface routines + + sim_name simulator name string + sim_PC pointer to saved PC register descriptor + sim_emax number of words for examine + sim_devices array of pointers to simulated devices + sim_stop_messages array of pointers to stop messages + sim_load binary loader +*/ + +char sim_name[] = "IBM 1130"; +char sim_version[] = "V0.24"; + +REG *sim_PC = &cpu_reg[0]; + +int32 sim_emax = 4; + +DEVICE *sim_devices[] = { + &cpu_dev, /* the cpu */ + &log_dev, /* cpu logging virtual device */ +#ifdef GUI_SUPPORT + &console_dev, /* console display (windows GUI) */ +#endif + &dsk_dev, /* disk drive(s) */ + &cr_dev, /* card reader/punch */ + &cp_dev, + &tti_dev, /* console keyboard, selectric printer */ + &tto_dev, + &prt_dev, /* 1132 printer */ + NULL +}; + +const char *sim_stop_messages[] = { + "Unknown error", + "Wait", + "Invalid command", + "Simulator breakpoint", + "Use of incomplete simulator function", +}; + +/* Loader. IPL is normally performed by card reader (boot command). This function + * loads hex data from a file for testing purposes. The format is: + * + * blank lines or lines starting with ; / or # are ignored as comments + * + * @XXXX set load addresss to hex value XXXX + * XXXX store hex word value XXXX at current load address and increment address + * ... + * =XXXX set IAR to hex value XXXX + * ZXXXX zero XXXX words and increment load address + * SXXXX set console entry switches to XXXX. This lets a program specify the + * default value for the toggle switches. + * + * Multiple @ and data sections may be entered. If more than one = or S value is specified + * the last one wins. + * + * Note: the load address @XXXX and data values XXXX can be followed by the letter + * R to indicate that the values are relocatable addresses. This is ignored in this loader, + * but the asm1130 cross assembler may put them there. + */ + +t_stat my_load (FILE *fileref, char *cptr, char *fnam) +{ + char line[150], *c; + int iaddr = -1, runaddr = -1, val, nwords; + + while (fgets(line, sizeof(line), fileref) != NULL) { + for (c = line; *c && *c <= ' '; c++) // find first nonblank + ; + + if (*c == '\0' || *c == '#' || *c == '/' || *c == ';') + continue; // empty line or comment + + if (*c == '@') { // set load address + if (sscanf(c+1, "%x", &iaddr) != 1) + return SCPE_FMT; + } + else if (*c == '=') { + if (sscanf(c+1, "%x", &runaddr) != 1) + return SCPE_FMT; + } + else if (*c == 's' || *c == 'S') { + if (sscanf(c+1, "%x", &val) != 1) + return SCPE_FMT; + + CES = val & 0xFFFF; // preload console entry switches + } + else if (*c == 'z' || *c == 'Z') { + if (sscanf(c+1, "%x", &nwords) != 1) + return SCPE_FMT; + + if (iaddr == -1) + return SCPE_FMT; + + while (--nwords >= 0) { + WriteW(iaddr, 0); + iaddr++; + } + } + else if (strchr("0123456789abcdefABCDEF", *c) != NULL) { + if (sscanf(c, "%x", &val) != 1) + return SCPE_FMT; + + if (iaddr == -1) + return SCPE_FMT; + + WriteW(iaddr, val); // store data + iaddr++; + } + else + return SCPE_FMT; // unexpected data + } + + if (runaddr != -1) + IAR = runaddr; + + return SCPE_OK; +} + +t_stat my_save (FILE *fileref, char *cptr, char *fnam) +{ + int iaddr, nzeroes = 0, nwords = (int) (MEMSIZE/2), val; + + fprintf(fileref, "=%04x\r\n", IAR); + fprintf(fileref, "@0000\r\n"); + for (iaddr = 0; iaddr < nwords; iaddr++) { + val = ReadW(iaddr); + if (val == 0) // queue up zeroes + nzeroes++; + else { + if (nzeroes >= 4) { // spit out a Z directive + fprintf(fileref, "Z%04x\r\n", nzeroes); + nzeroes = 0; + } + else { // write queued zeroes literally + while (nzeroes > 0) { + fprintf(fileref, " 0000\r\n"); + nzeroes--; + } + } + fprintf(fileref, " %04x\r\n", val); + } + } + if (nzeroes >= 4) { // emit any queued zeroes + fprintf(fileref, "Z%04x\r\n", nzeroes); + nzeroes = 0; + } + else { + while (nzeroes > 0) { + fprintf(fileref, " 0000\r\n"); + nzeroes--; + } + } + + return SCPE_OK; +} + +t_stat sim_load (FILE *fileref, char *cptr, char *fnam, int flag) +{ + if (flag) + return my_save(fileref, cptr, fnam); + else + return my_load(fileref, cptr, fnam); +} + +/* Specifier decode + + Inputs: + *of = output stream + addr = current PC + spec = specifier + nval = next word + flag = TRUE if decoding for CPU + iflag = TRUE if decoding integer instruction + Outputs: + count = -number of extra words retired +*/ + +/* Symbolic decode + + Inputs: + *of = output stream + addr = current PC + *val = values to decode + *uptr = pointer to unit + sw = switches + Outputs: + return = if >= 0, error code + if < 0, number of extra words retired +*/ + +static char *opcode[] = { + "?00 ", "XIO ", "SLA ", "SRA ", + "LDS ", "STS ", "WAIT", "?07 ", + "BSI ", "BSC ", "?0A ", "?0B ", + "LDX ", "STD ", "MDX ", "?0F ", + "A ", "AD ", "S ", "SD ", + "M ", "D ", "?16 ", "?17 ", + "LD ", "LDD ", "STO ", "STD ", + "AND ", "OR ", "EOR ", "?1F ", +}; + +static char relative[] = { // true if short mode displacements are IAR relative + FALSE, TRUE, FALSE, FALSE, + FALSE, TRUE, FALSE, FALSE, + TRUE, FALSE, FALSE, FALSE, + TRUE, TRUE, TRUE, FALSE, + TRUE, TRUE, TRUE, TRUE, + TRUE, TRUE, FALSE, FALSE, + TRUE, TRUE, TRUE, TRUE, + TRUE, TRUE, TRUE, FALSE +}; + +static char *lsopcode[] = {"SLA ", "SLCA ", "SLT ", "SLC "}; +static char *rsopcode[] = {"SRA ", "?188 ", "SRT ", "RTE "}; +static char tagc[] = " 123"; + +t_stat fprint_sym (FILE *of, t_addr addr, t_value *val, UNIT *uptr, int32 sw) +{ + int32 cflag, c1, c2, OP, F, TAG, INDIR, DSPLC, IR, eaddr; + char *mnem, tst[12]; + + cflag = (uptr == NULL) || (uptr == &cpu_unit); + c1 = val[0] & 0177; + c2 = (val[0] >> 8) & 0177; + + if (sw & SWMASK ('A')) { /* ASCII? */ + fprintf (of, (c1 < 040)? "<%03o>": "%c", c1); + return SCPE_OK; + } + + if (sw & SWMASK ('C')) { /* character? */ + fprintf (of, (c1 < 040)? "<%03o>": "%c", c1); + fprintf (of, (c2 < 040)? "<%03o>": "%c", c2); + return SCPE_OK; + } + + if (! (sw & SWMASK ('M'))) + return SCPE_ARG; + + IR = val[0]; + OP = (IR >> 11) & 0x1F; /* opcode */ + F = IR & 0x0400; /* format bit: 1 = long instr */ + TAG = IR & 0x0300; /* tag bits: index reg select */ + if (TAG) + TAG >>= 8; + + if (F) { /* long instruction, ASSUME it's valid (have to decrement IAR if not) */ + INDIR = IR & 0x0080; /* indirect bit */ + DSPLC = IR & 0x007F; /* displacement or modifier */ + if (DSPLC & 0x0040) + DSPLC |= ~ 0x7F; /* sign extend */ + + eaddr = val[1]; /* get reference address */ + } + else { /* short instruction, use displacement */ + INDIR = 0; /* never indirect */ + DSPLC = IR & 0x00FF; /* get displacement */ + if (DSPLC & 0x0080) + DSPLC |= ~ 0xFF; + + eaddr = DSPLC; + if (relative[OP] && ! TAG) + eaddr += addr+1; /* turn displacement into address */ + } + + mnem = opcode[OP]; /* get mnemonic */ + if (OP == 0x02) { /* left shifts are special */ + mnem = lsopcode[(DSPLC >> 6) & 0x0003]; + DSPLC &= 0x003F; + eaddr = DSPLC; + } + else if (OP == 0x03) { /* right shifts too */ + mnem = rsopcode[(DSPLC >> 6) & 0x0003]; + DSPLC &= 0x003F; + eaddr = DSPLC; + } + else if (OP == 0x09) { + if (IR & 0x40) + mnem = "BOSC"; + + tst[0] = '\0'; + if (DSPLC & 0x20) strcat(tst, "Z"); + if (DSPLC & 0x10) strcat(tst, "-"); + if (DSPLC & 0x08) strcat(tst, "+"); + if (DSPLC & 0x04) strcat(tst, "E"); + if (DSPLC & 0x02) strcat(tst, "C"); + if (DSPLC & 0x01) strcat(tst, "O"); + + if (F) { + fprintf(of, "%04x %s %c%c %s,%04x ", IR & 0xFFFF, mnem, F ? (INDIR ? 'I' : 'L') : ' ', tagc[TAG], tst, eaddr & 0xFFFF); + return -1; + } + fprintf(of, "%04x %s %c%c %s ", IR & 0xFFFF, mnem, F ? (INDIR ? 'I' : 'L') : ' ', tagc[TAG], tst); + return SCPE_OK; + } + else if (OP == 0x0e && TAG == 0) { // MDX with no tag => MDM or jump + if (F) { + fprintf(of, "%04x %s %c%c %04x,%x (%d) ", IR & 0xFFFF, "MDM ", (INDIR ? 'I' : 'L'), tagc[TAG], eaddr & 0xFFFF, DSPLC & 0xFFFF, DSPLC); + return -1; + } + mnem = "JMP "; + } + + fprintf(of, "%04x %s %c%c %04x ", IR & 0xFFFF, mnem, F ? (INDIR ? 'I' : 'L') : ' ', tagc[TAG], eaddr & 0xFFFF); + return F ? -1 : SCPE_OK; /* inform how many words we read */ +} + +int32 get_reg (char *cptr, const char *strings[], char mchar) +{ +return -1; +} + +/* Number or memory address + + Inputs: + *cptr = pointer to input string + *dptr = pointer to output displacement + *pflag = pointer to accumulating flags + Outputs: + cptr = pointer to next character in input string + NULL if parsing error + + Flags: 0 (no result), A_NUM (number), A_REL (relative) +*/ + +char *get_addr (char *cptr, int32 *dptr, int32 *pflag) +{ + return 0; +} + +/* Specifier decode + + Inputs: + *cptr = pointer to input string + addr = current PC + n1 = 0 if no extra word used + -1 if extra word used in prior decode + *sptr = pointer to output specifier + *dptr = pointer to output displacement + cflag = true if parsing for the CPU + iflag = true if integer specifier + Outputs: + status = = -1 extra word decoded + = 0 ok + = +1 error +*/ + +t_stat get_spec (char *cptr, t_addr addr, int32 n1, int32 *sptr, t_value *dptr, + int32 cflag, int32 iflag) +{ + return -1; +} + +/* Symbolic input + + Inputs: + *cptr = pointer to input string + addr = current PC + *uptr = pointer to unit + *val = pointer to output values + sw = switches + Outputs: + status = > 0 error code + <= 0 -number of extra words +*/ + +t_stat parse_sym (char *cptr, t_addr addr, UNIT *uptr, t_value *val, int32 sw) +{ + return SCPE_ARG; +} diff --git a/Ibm1130/ibm1130res.h b/Ibm1130/ibm1130res.h new file mode 100644 index 00000000..ce47382e --- /dev/null +++ b/Ibm1130/ibm1130res.h @@ -0,0 +1,18 @@ +//{{NO_DEPENDENCIES}} +// Microsoft Visual C++ generated include file. +// Used by ibm1130.rc +// + +#define IDB_CONSOLE 101 +#define IDC_HAND 102 + +// Next default values for new objects +// +#ifdef APSTUDIO_INVOKED +#ifndef APSTUDIO_READONLY_SYMBOLS +#define _APS_NEXT_RESOURCE_VALUE 103 +#define _APS_NEXT_COMMAND_VALUE 40001 +#define _APS_NEXT_CONTROL_VALUE 1000 +#define _APS_NEXT_SYMED_VALUE 101 +#endif +#endif diff --git a/Ibm1130/readme1130.txt b/Ibm1130/readme1130.txt new file mode 100644 index 00000000..33686d01 --- /dev/null +++ b/Ibm1130/readme1130.txt @@ -0,0 +1,209 @@ +Here's the 1130 simulator as it stands now. + +Status: 10 April 2002 + + * The 1132 printer now works (at least printing numbers) + and there are some corrections to the assembler. The + Disk Cartridge Initialiation Program (DCIP) is now + included and works. See notes below. + + * For updated information about the 1130 and for + future simulator, 1130 OS and application software + developments, check www.ibm1130.org periodically. + Sign up for the mailing list to get updates as they occur! + + * I still haven't written any documentation. + + * Thanks to Oscar E Wyss (www.cosecans.ch) for + the DMS V12 source code listings and one card + programs, to Douglas W. Jones for the DMS V10, 11 and + 12 microfiche (which will end up scanned on IBM1130.org). + + * Thanks to Robert Alan Byer for adding the 1130 + to the simh makefiles & testing the builds on several + platforms. + + * I now have the source code for the 1130 Disk + Monitor System and compilers in the software package. + The asm1130 assembler is not quite up to the task of + compiling it yet. We have located a copy of the binary + disk load deck that will let us build a working disk + image. I hope to have these available online and as part + of this distribution, respectively, by Summer, 2002. + At that point the source code will be included too. + + * Assembler has been updated to handle card image input + correctly. The DMS sources seems to mix up @ and ' + as a leading symbol in labels, I have to find out why + this is. + + * see bug list below + +Brian Knittel +brian@ibm1130.org + +-------------------------------------------------------------------------- + +Contents: + +There are two programs: + + ibm1130 the simulator + asm1130 cross assembler + + actual 1130 software: + zdcip.asm "disk cartridge initialization program" + + dmsboot.asm the DMS cold start loader + + zcrdumpc.asm a cold-start-mode one card memory dump program + +And several files in the software (sw) directory: + + test.dsk disk image, a formatted but empty 1130 disk + onecard/* one-card programs from Oscar Wyss + + boot2 script to boot the 1130 + boot2.ldr an older DMS cold start loader + boot1.ldr APL cold start loader + + type.asm program to type on console printer + prtcr.asm program to copy card deck to console printer + +-------------------------------------------------------------------------- +Status of the simulator: + +* bugs: + + (1) Deck files may not work correctly; have to check. When second deck file + is loaded it appears that the second file is not read correctly? + +* the card punch is untested + +* the card reader emulator now supports deck files: a list of multiple files from + which to read; this makes it possible to assemble complex decks of mixed + text and binary cards without having to actually combine the components + into one file. + +* the card reader, punch and disk don't compute their device status word + until an XIO requests it; this is probably bad as the examine command + will show the wrong value. + +* there is a reasonably fun GUI available for Windows builds; this requires + the use of modified scp.c and scp_tty.c. These are enclosed. You should + merge the noted modifications into the current versions of scp and scp_tty. + You will also need to define symbol GUI_SUPPORT during the builds; the Visual + C makefile has this set. + +-------------------------------------------------------------------------- +Some sample things to run: + +* Disk Cartridge Initialization: + + asm1130 zdcip.asm + ibm1130 + +then: attach dsk0 test.dsk + attach prt 1132.lst + load zdcip.out + go + +then: on GUI: on console: + ---------------- ----------------- + raise switch 6 dep ces 0200 + program start go + lower 6 dep ces 0 + program start go + raise 3, 6, 10, 11, 13 dep ces 1234 + program start go + program start go + + (this formats the disk) + + program start go + + lower all switches + raise switch 2 dep ces 2000 + program start go + lower all switches dep ces 0 + program start go + raise switch 14 dep ces 2 + program start go + + (this dumps two sectors to printer output file 1132.lst) + + (now try to boot the disk) + + lower all switches dep ces 0 + check reset reset + program load load dmsboot.out + program start go + +* echo console keyboard to console printer. This one is really fun +* with the GUI enabled; the lights flash in a pleasing manner. + + asm1130 type + ibm1130 + load type.out + go + +* copy card deck to console printer + + asm1130 prtcr + ibm1130 + load prtcr.out + attach cr + go + + +-------------------------------------------------------------------------- +sample usage +-------------------------------------------------------------------------- + +asm1130 -l resmon.asm + + compiles source file, creates simulator load + file (resmon.out) and listing file (resmon.lst) + + I had to type in the resident monitor, so it's missing + the comments. I'll add them later. + + The cross assembler wants files either in strict column + layout matching the IBM spec, or, if tabs are present in the + source file, + + labelopcodeflagsoperand + + The output file is in the format used by the 1130 simulator's + load command. + +-------------------------------------------------------------------------- +cardscan -x image.bmp + + where x = b for binary interpretation + a for ascii interpretation + l for boot loader interpretation + +-------------------------------------------------------------------------- +ibm1130 + starts SIMH-based simulator. + + Enhancements: + + * Displays a console window (you can hide with DISABLE CONSOLE) + with buttons & lights. + + * CPU activity log + + the command "attach log file.log" will make the simulator + write a detailed log of CPU and IO activity, good for + debugging. Turn off with "detach log". + + * DO command + reads file 'filename' for SIMH commands. Lets you write + simh command files to be run from the prompt rather + than just the command line. Bob Supnik has added this to + the main simh code tree. + +-------------------------------------------------------------------------- +check www.ibm1130.org for updates... \ No newline at end of file diff --git a/Ibm1130/scp.c b/Ibm1130/scp.c new file mode 100644 index 00000000..f7705bb6 --- /dev/null +++ b/Ibm1130/scp.c @@ -0,0 +1,3116 @@ +/* scp.c: simulator control program + + Copyright (c) 1993-2002, Robert M Supnik + + Permission is hereby granted, free of charge, to any person obtaining a + copy of this software and associated documentation files (the "Software"), + to deal in the Software without restriction, including without limitation + the rights to use, copy, modify, merge, publish, distribute, sublicense, + and/or sell copies of the Software, and to permit persons to whom the + Software is furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + ROBERT M SUPNIK BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + Except as contained in this notice, the name of Robert M Supnik shall not + be used in advertising or otherwise to promote the sale, use or other dealings + in this Software without prior written authorization from Robert M Supnik. + + 04-Feb-02 BLK Added GUI_SUPPORT code and read_cmdline changes + 06-Jan-02 RMS Moved device enable/disable to simulators + 30-Dec-01 RMS Generalized timer packaged, added circular arrays + 19-Dec-01 RMS Fixed DO command bug (found by John Dundas) + 07-Dec-01 RMS Implemented breakpoint package + 05-Dec-01 RMS Fixed bug in universal register logic + 03-Dec-01 RMS Added read-only units, extended SET/SHOW, universal registers + 24-Nov-01 RMS Added unit-based registers + 16-Nov-01 RMS Added DO command + 28-Oct-01 RMS Added relative range addressing + 08-Oct-01 RMS Added SHOW VERSION + 30-Sep-01 RMS Relaxed attach test in BOOT + 27-Sep-01 RMS Added queue count routine, fixed typo in ex/mod + 17-Sep-01 RMS Removed multiple console support + 07-Sep-01 RMS Removed conditional externs on function prototypes + Added special modifier print + 31-Aug-01 RMS Changed int64 to t_int64 for Windoze (V2.7) + 18-Jul-01 RMS Minor changes for Macintosh port + 12-Jun-01 RMS Fixed bug in big-endian I/O (found by Dave Conroy) + 27-May-01 RMS Added multiple console support + 16-May-01 RMS Added logging + 15-May-01 RMS Added features from Tim Litt + 12-May-01 RMS Fixed missing return in disable_cmd + 25-Mar-01 RMS Added ENABLE/DISABLE + 14-Mar-01 RMS Revised LOAD/DUMP interface (again) + 05-Mar-01 RMS Added clock calibration support + 05-Feb-01 RMS Fixed bug, DETACH buffered unit with hwmark = 0 + 04-Feb-01 RMS Fixed bug, RESTORE not using device's attach routine + 21-Jan-01 RMS Added relative time + 22-Dec-00 RMS Fixed find_device for devices ending in numbers + 08-Dec-00 RMS V2.5a changes + 30-Oct-00 RMS Added output file option to examine + 11-Jul-99 RMS V2.5 changes + 13-Apr-99 RMS Fixed handling of 32b addresses + 04-Oct-98 RMS V2.4 changes + 20-Aug-98 RMS Added radix commands + 05-Jun-98 RMS Fixed bug in ^D handling for UNIX + 10-Apr-98 RMS Added switches to all commands + 26-Oct-97 RMS Added search capability + 25-Jan-97 RMS Revised data types + 23-Jan-97 RMS Added bi-endian I/O + 06-Sep-96 RMS Fixed bug in variable length IEXAMINE + 16-Jun-96 RMS Changed interface to parse/print_sym + 06-Apr-96 RMS Added error checking in reset all + 07-Jan-96 RMS Added register buffers in save/restore + 11-Dec-95 RMS Fixed ordering bug in save/restore + 22-May-95 RMS Added symbolic input + 13-Apr-95 RMS Added symbolic printouts +*/ + +#if defined(VMS) + # define FOPEN(file_spec, mode) fopen(file_spec, mode, "MBF=6", "MBC=128", "ROP=rah,wbh") +#else + # define FOPEN(file_spec, mode) fopen(file_spec, mode) +#endif + +#include "sim_defs.h" +#include "sim_rev.h" +#include +#include + +#define EX_D 0 /* deposit */ +#define EX_E 1 /* examine */ +#define EX_I 2 /* interactive */ +#define SCH_OR 0 /* search logicals */ +#define SCH_AND 1 +#define SCH_XOR 2 +#define SCH_E 0 /* search booleans */ +#define SCH_N 1 +#define SCH_G 2 +#define SCH_L 3 +#define SCH_EE 4 +#define SCH_NE 5 +#define SCH_GE 6 +#define SCH_LE 7 +#define SSH_ST 0 /* set */ +#define SSH_SH 1 /* show */ +#define SSH_CL 2 /* clear */ +#define RU_RUN 0 /* run */ +#define RU_GO 1 /* go */ +#define RU_STEP 2 /* step */ +#define RU_CONT 3 /* continue */ +#define RU_BOOT 4 /* boot */ + +#define SWHIDE (1u << 26) /* enable hiding */ +#define SRBSIZ 1024 /* save/restore buffer */ +#define SIM_BRK_INILNT 1024 /* bpt tbl length */ +#define SIM_BRK_ALLTYP 0xFFFFFFFF +#define SIM_NTIMERS 8 /* # timers */ +#define SIM_TMAX 500 /* max timer makeup */ +#define UPDATE_SIM_TIME(x) sim_time = sim_time + (x - sim_interval); \ + sim_rtime = sim_rtime + ((uint32) (x - sim_interval)); \ + x = sim_interval + +struct brktab { + t_addr addr; + int32 typ; + int32 cnt; + char *act; +}; + +typedef struct brktab BRKTAB; + +extern char sim_name[]; +extern DEVICE *sim_devices[]; +extern REG *sim_PC; +extern char *sim_stop_messages[]; +extern t_stat sim_instr (void); +extern t_stat sim_load (FILE *ptr, char *cptr, char *fnam, int flag); +extern int32 sim_emax; +extern t_stat fprint_sym (FILE *ofile, t_addr addr, t_value *val, + UNIT *uptr, int32 sw); +extern t_stat parse_sym (char *cptr, t_addr addr, UNIT *uptr, t_value *val, + int32 sw); +extern t_stat ttinit (void); +extern t_stat ttrunstate (void); +extern t_stat ttcmdstate (void); +extern t_stat ttclose (void); +extern t_stat sim_putchar (int32 out); +extern uint32 sim_os_msec (void); +UNIT *sim_clock_queue = NULL; +int32 sim_interval = 0; +int32 sim_switches = 0; +int32 sim_is_running = 0; +uint32 sim_brk_summ = 0; +uint32 sim_brk_types = 0; +uint32 sim_brk_dflt = 0; +BRKTAB *sim_brk_tab = NULL; +int32 sim_brk_ent = 0; +int32 sim_brk_lnt = 0; +int32 sim_brk_ins = 0; +t_bool sim_brk_pend = FALSE; +t_addr sim_brk_ploc = 0; +static double sim_time; +static uint32 sim_rtime; +static int32 noqueue_time; +volatile int32 stop_cpu = 0; +t_value *sim_eval = NULL; +int32 sim_end = 1; /* 1 = little */ +FILE *sim_log = NULL; /* log file */ +unsigned char sim_flip[FLIP_SIZE]; + +t_stat sim_brk_init (void); +t_stat sim_brk_set (t_addr loc, int32 sw, int32 ncnt); +t_stat sim_brk_clr (t_addr loc, int32 sw); +t_stat sim_brk_clrall (int32 sw); +t_stat sim_brk_show (FILE *st, t_addr loc, int32 sw); +t_stat sim_brk_showall (FILE *st, int32 sw); +void sim_brk_npc (void); +#define print_val(a,b,c,d) fprint_val (stdout, (a), (b), (c), (d)) +#define SZ_D(dp) (size_map[((dp) -> dwidth + CHAR_BIT - 1) / CHAR_BIT]) +#define SZ_R(rp) \ + (size_map[((rp) -> width + (rp) -> offset + CHAR_BIT - 1) / CHAR_BIT]) +#if defined (t_int64) +#define SZ_LOAD(sz,v,mb,j) \ + if (sz == sizeof (uint8)) v = *(((uint8 *) mb) + j); \ + else if (sz == sizeof (uint16)) v = *(((uint16 *) mb) + j); \ + else if (sz == sizeof (uint32)) v = *(((uint32 *) mb) + j); \ + else v = *(((t_uint64 *) mb) + j); +#define SZ_STORE(sz,v,mb,j) \ + if (sz == sizeof (uint8)) *(((uint8 *) mb) + j) = (uint8) v; \ + else if (sz == sizeof (uint16)) *(((uint16 *) mb) + j) = (uint16) v; \ + else if (sz == sizeof (uint32)) *(((uint32 *) mb) + j) = (uint32) v; \ + else *(((t_uint64 *) mb) + j) = v; +#else +#define SZ_LOAD(sz,v,mb,j) \ + if (sz == sizeof (uint8)) v = *(((uint8 *) mb) + j); \ + else if (sz == sizeof (uint16)) v = *(((uint16 *) mb) + j); \ + else v = *(((uint32 *) mb) + j); +#define SZ_STORE(sz,v,mb,j) \ + if (sz == sizeof (uint8)) *(((uint8 *) mb) + j) = (uint8) v; \ + else if (sz == sizeof (uint16)) *(((uint16 *) mb) + j) = (uint16) v; \ + else *(((uint32 *) mb) + j) = v; +#endif +#define GET_SWITCHES(cp,gb) \ + sim_switches = 0; \ + while (*cp == '-') { \ + int32 lsw; \ + cp = get_glyph (cp, gb, 0); \ + if ((lsw = get_switches (gb)) <= 0) return SCPE_INVSW; \ + sim_switches = sim_switches | lsw; } +#define GET_RADIX(val,dft) \ + if (sim_switches & SWMASK ('O')) val = 8; \ + else if (sim_switches & SWMASK ('D')) val = 10; \ + else if (sim_switches & SWMASK ('H')) val = 16; \ + else val = dft; + +t_stat set_glob (CTAB *tab, char *gbuf, DEVICE *dptr, UNIT *uptr); +t_stat ssh_break (FILE *st, char *cptr, int32 flg); +t_stat set_radix (DEVICE *dptr, UNIT *uptr, int flag); +t_stat set_onoff (DEVICE *dptr, UNIT *uptr, int32 flag); +t_stat show_config (FILE *st, int32 flag); +t_stat show_queue (FILE *st, int32 flag); +t_stat show_time (FILE *st, int32 flag); +t_stat show_mod_names (FILE *st, int32 flag); +t_stat show_device (FILE *st, DEVICE *dptr, int32 flag); +t_stat show_unit (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag); +t_stat show_all_mods (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flg); +t_stat show_one_mod (FILE *st, DEVICE *dptr, UNIT *uptr, MTAB *mptr, int32 flag); +int32 get_switches (char *cptr); +t_value get_rval (REG *rptr, int idx); +void put_rval (REG *rptr, int idx, t_value val); +t_stat get_aval (t_addr addr, DEVICE *dptr, UNIT *uptr); +t_value strtotv (char *inptr, char **endptr, int radix); +t_stat fprint_val (FILE *stream, t_value val, int rdx, int wid, int fmt); +void fprint_stopped (FILE *stream, t_stat r); +char *read_line (char *ptr, int size, FILE *stream); +DEVICE *find_dev (char *ptr); +DEVICE *find_unit (char *ptr, UNIT **uptr); +REG *find_reg_glob (char *ptr, char **optr, DEVICE **gdptr); +t_bool qdisable (DEVICE *dptr); +t_stat attach_err (UNIT *uptr, t_stat stat); +t_stat detach_all (int32 start_device, t_bool shutdown); +t_stat ex_reg (FILE *ofile, t_value val, int flag, REG *rptr, t_addr idx); +t_stat dep_reg (int flag, char *cptr, REG *rptr, t_addr idx); +t_stat ex_addr (FILE *ofile, int flag, t_addr addr, DEVICE *dptr, UNIT *uptr); +t_stat dep_addr (int flag, char *cptr, t_addr addr, DEVICE *dptr, + UNIT *uptr, int dfltinc); +char *get_range (char *cptr, t_addr *lo, t_addr *hi, int rdx, + t_addr max, char term); +SCHTAB *get_search (char *cptr, DEVICE *dptr, SCHTAB *schptr); +int test_search (t_value val, SCHTAB *schptr); +t_stat step_svc (UNIT *ptr); +t_stat show_version (FILE *st, int flag); +char *read_cmdline (char *ptr, int size); /* BLK - added */ + +UNIT step_unit = { UDATA (&step_svc, 0, 0) }; +const char save_vercur[] = "V2.6"; +const char save_ver25[] = "V2.5"; +const char *scp_error_messages[] = { + "Address space exceeded", + "Unit not attached", + "I/O error", + "Checksum error", + "Format error", + "Unit not attachable", + "File open error", + "Memory exhausted", + "Invalid argument", + "Step expired", + "Unknown command", + "Read only argument", + "Command not completed", + "Simulation stopped", + "Goodbye", + "Console input I/O error", + "Console output I/O error", + "End of file", + "Relocation error", + "No settable parameters", + "Unit already attached", + "Hardware timer error", + "SIGINT handler setup error", + "Console terminal setup error", + "Subscript out of range", + "Command not allowed", + "Unit disabled", + "Logging enabled", + "Logging disabled", + "Read only operation not allowed", + "Invalid switch", + "Missing value", + "Too few arguments", + "Too many arguments", + "Non-existent device", + "Non-existent unit", + "Non-existent register", + "Non-existent parameter", + "Nested DO commands", + "Internal error" +}; + +const size_t size_map[] = { sizeof (int8), + sizeof (int8), sizeof (int16), sizeof (int32), sizeof (int32) +#if defined (t_int64) + , sizeof (t_int64), sizeof (t_int64), sizeof (t_int64), sizeof (t_int64) +#endif +}; + +const t_value width_mask[] = { 0, + 0x1, 0x3, 0x7, 0xF, + 0x1F, 0x3F, 0x7F, 0xFF, + 0x1FF, 0x3FF, 0x7FF, 0xFFF, + 0x1FFF, 0x3FFF, 0x7FFF, 0xFFFF, + 0x1FFFF, 0x3FFFF, 0x7FFFF, 0xFFFFF, + 0x1FFFFF, 0x3FFFFF, 0x7FFFFF, 0xFFFFFF, + 0x1FFFFFF, 0x3FFFFFF, 0x7FFFFFF, 0xFFFFFFF, + 0x1FFFFFFF, 0x3FFFFFFF, 0x7FFFFFFF, 0xFFFFFFFF +#if defined (t_int64) + , 0x1FFFFFFFF, 0x3FFFFFFFF, 0x7FFFFFFFF, 0xFFFFFFFFF, + 0x1FFFFFFFFF, 0x3FFFFFFFFF, 0x7FFFFFFFFF, 0xFFFFFFFFFF, + 0x1FFFFFFFFFF, 0x3FFFFFFFFFF, 0x7FFFFFFFFFF, 0xFFFFFFFFFFF, + 0x1FFFFFFFFFFF, 0x3FFFFFFFFFFF, 0x7FFFFFFFFFFF, 0xFFFFFFFFFFFF, + 0x1FFFFFFFFFFFF, 0x3FFFFFFFFFFFF, 0x7FFFFFFFFFFFF, 0xFFFFFFFFFFFFF, + 0x1FFFFFFFFFFFFF, 0x3FFFFFFFFFFFFF, 0x7FFFFFFFFFFFFF, 0xFFFFFFFFFFFFFF, + 0x1FFFFFFFFFFFFFF, 0x3FFFFFFFFFFFFFF, + 0x7FFFFFFFFFFFFFF, 0xFFFFFFFFFFFFFFF, + 0x1FFFFFFFFFFFFFFF, 0x3FFFFFFFFFFFFFFF, + 0x7FFFFFFFFFFFFFFF, 0xFFFFFFFFFFFFFFFF +#endif +}; + +t_stat reset_cmd (int flag, char *ptr); +t_stat exdep_cmd (int flag, char *ptr); +t_stat load_cmd (int flag, char *ptr); +t_stat run_cmd (int flag, char *ptr); +t_stat attach_cmd (int flag, char *ptr); +t_stat detach_cmd (int flag, char *ptr); +t_stat save_cmd (int flag, char *ptr); +t_stat restore_cmd (int flag, char *ptr); +t_stat exit_cmd (int flag, char *ptr); +t_stat set_cmd (int flag, char *ptr); +t_stat show_cmd (int flag, char *ptr); +t_stat log_cmd (int flag, char *ptr); +t_stat nolog_cmd (int flag, char *ptr); +t_stat brk_cmd (int flag, char *ptr); +t_stat do_cmd (int flag, char *ptr); +t_stat help_cmd (int flag, char *ptr); + +static CTAB cmd_table[] = { + { "RESET", &reset_cmd, 0 }, + { "EXAMINE", &exdep_cmd, EX_E }, + { "IEXAMINE", &exdep_cmd, EX_E+EX_I }, + { "DEPOSIT", &exdep_cmd, EX_D }, + { "IDEPOSIT", &exdep_cmd, EX_D+EX_I }, + { "RUN", &run_cmd, RU_RUN }, + { "GO", &run_cmd, RU_GO }, + { "STEP", &run_cmd, RU_STEP }, + { "CONT", &run_cmd, RU_CONT }, + { "BOOT", &run_cmd, RU_BOOT }, + { "ATTACH", &attach_cmd, 0 }, + { "DETACH", &detach_cmd, 0 }, + { "SAVE", &save_cmd, 0 }, + { "RESTORE", &restore_cmd, 0 }, + { "GET", &restore_cmd, 0 }, + { "LOAD", &load_cmd, 0 }, + { "DUMP", &load_cmd, 1 }, + { "EXIT", &exit_cmd, 0 }, + { "QUIT", &exit_cmd, 0 }, + { "BYE", &exit_cmd, 0 }, + { "SET", &set_cmd, 0 }, + { "SHOW", &show_cmd, 0 }, + { "LOG", &log_cmd, 0 }, + { "NOLOG", &nolog_cmd, 0 }, + { "BREAK", &brk_cmd, SSH_ST }, + { "NOBREAK", &brk_cmd, SSH_CL }, + { "DO", &do_cmd, 0 }, + { "HELP", &help_cmd, 0 }, + { NULL, NULL, 0 } }; + +/* Main command loop */ + +int main (int argc, char *argv[]) +{ +char cbuf[CBUFSIZE], gbuf[CBUFSIZE], *cptr; +int32 i; +t_stat stat; +union {int32 i; char c[sizeof (int32)]; } end_test; + +#if defined (__MWERKS__) && defined (macintosh) +argc = ccommand(&argv); +#endif + +if ((stat = ttinit ()) != SCPE_OK) { + printf ("Fatal terminal initialization error\n%s\n", + scp_error_messages[stat - SCPE_BASE]); + return 0; } +printf ("\n"); +show_version (stdout, 0); +end_test.i = 1; /* test endian-ness */ +sim_end = end_test.c[0]; +stop_cpu = 0; +sim_interval = 0; +sim_time = sim_rtime = 0; +noqueue_time = 0; +sim_clock_queue = NULL; +sim_is_running = 0; +sim_log = NULL; +if (sim_emax <= 0) sim_emax = 1; +if ((sim_eval = calloc (sim_emax, sizeof (t_value))) == NULL) { + printf ("Unable to allocate examine buffer\n"); + return 0; }; +if ((stat = reset_all (0)) != SCPE_OK) { + printf ("Fatal simulator initialization error\n%s\n", + scp_error_messages[stat - SCPE_BASE]); + return 0; } +if ((stat = sim_brk_init ()) != SCPE_OK) { + printf ("Fatal breakpoint table initialization error\n%s\n", + scp_error_messages[stat - SCPE_BASE]); + return 0; } + +if ((argc > 1) && argv[1]) { /* cmd file arg? */ + stat = do_cmd (0, argv[1]); /* proc cmd file */ + if (stat == SCPE_OPENERR) fprintf (stderr, /* error? */ + "Can't open file %s\n", argv[1]); } + +do { printf ("sim> "); /* prompt */ +#ifdef GUI_SUPPORT + cptr = read_cmdline (cbuf, CBUFSIZE); /* read command line */ +#else + cptr = read_line (cbuf, CBUFSIZE, stdin); /* read command line */ +#endif + stat = SCPE_UNK; + if (cptr == NULL) continue; /* ignore EOF */ + if (*cptr == 0) continue; /* ignore blank */ + if (sim_log) fprintf (sim_log, "sim> %s\n", cbuf); /* log cmd */ + cptr = get_glyph (cptr, gbuf, 0); /* get command glyph */ + for (i = 0; cmd_table[i].name != NULL; i++) { + if (MATCH_CMD (gbuf, cmd_table[i].name) == 0) { + stat = cmd_table[i].action (cmd_table[i].arg, cptr); + break; } } + if (stat >= SCPE_BASE) { /* error? */ + printf ("%s\n", scp_error_messages[stat - SCPE_BASE]); + if (sim_log) fprintf (sim_log, "%s\n", + scp_error_messages[stat - SCPE_BASE]); } +#ifdef GUI_SUPPORT + update_gui(TRUE); +#endif +} while (stat != SCPE_EXIT); + +detach_all (0, TRUE); /* close files */ +nolog_cmd (0, NULL); /* close log */ +ttclose (); /* close console */ +return 0; +} + +/* Exit command */ + +t_stat exit_cmd (int flag, char *cptr) +{ +return SCPE_EXIT; +} + +/* Help command */ + +void fprint_help (FILE *st) +{ +fprintf (st, "r{eset} {ALL|} reset simulator\n"); +fprintf (st, "e{xamine} examine memory or registers\n"); +fprintf (st, "ie{xamine} interactive examine memory or registers\n"); +fprintf (st, "d{eposit} deposit in memory or registers\n"); +fprintf (st, "id{eposit} interactive deposit in memory or registers\n"); +fprintf (st, "l{oad} {} load binary file\n"); +fprintf (st, "du(mp) {} dump binary file\n"); +fprintf (st, "ru{n} {new PC} reset and start simulation\n"); +fprintf (st, "go {new PC} start simulation\n"); +fprintf (st, "c{ont} continue simulation\n"); +fprintf (st, "s{tep} {n} simulate n instructions\n"); +fprintf (st, "b{oot} bootstrap unit\n"); +fprintf (st, "br{eak} set breakpoints\n"); +fprintf (st, "nobr{eak} clear breakpoints\n"); +fprintf (st, "at{tach} attach file to simulated unit\n"); +fprintf (st, "det{ach} detach file from simulated unit\n"); +fprintf (st, "sa{ve} save simulator to file\n"); +fprintf (st, "rest{ore}|ge{t} restore simulator from file\n"); +fprintf (st, "exi{t}|q{uit}|by{e} exit from simulation\n"); +fprintf (st, "set | set device/unit parameter\n"); +fprintf (st, "sh{ow} | show device parameters\n"); +fprintf (st, "sh{ow} c{onfiguration} show configuration\n"); +fprintf (st, "sh{ow} d{evices} show devices\n"); +fprintf (st, "sh{ow} m{odifiers} show modifiers\n"); +fprintf (st, "sh{ow} q{ueue} show event queue\n"); +fprintf (st, "sh{ow} t{ime} show simulated time\n"); +fprintf (st, "sh{ow} v{ersion} show simulator version\n"); +fprintf (st, "log enable logging to file\n"); +fprintf (st, "nolog disable logging\n"); +fprintf (st, "do process command file\n"); +fprintf (st, "h{elp} type this message\n"); +return; +} + +t_stat help_cmd (int flag, char *cptr) +{ +fprint_help (stdout); +if (sim_log) fprint_help (sim_log); +return SCPE_OK; +} + +/* Do command */ + +t_stat do_cmd (int flag, char *fcptr) +{ +char *cptr, cbuf[CBUFSIZE], gbuf[CBUFSIZE]; +FILE *fpin; +int32 i; +t_stat stat; + +if ((fpin = fopen (fcptr, "r")) != NULL) { /* cmd file open? */ + do { + cptr = read_line (cbuf, CBUFSIZE, fpin); /* get cmd line */ + if (cptr == NULL) break; /* exit on eof */ + if (*cptr == 0) continue; /* ignore blank */ + if (sim_log) fprintf (sim_log, "do> %s\n", cptr); + cptr = get_glyph (cptr, gbuf, 0); /* get command glyph */ + if (strcmp (gbuf, "do") == 0) { /* don't recurse */ + fclose (fpin); + return SCPE_NEST; } + stat = SCPE_BASE; + for (i = 0; cmd_table[i].name != NULL; i++) { /* find cmd */ + if (MATCH_CMD (gbuf, cmd_table[i].name) == 0) { + stat = cmd_table[i].action (cmd_table[i].arg, cptr); + break; } } + if (stat >= SCPE_BASE) /* error? */ + printf ("%s\n", scp_error_messages[stat - SCPE_BASE]); +#ifdef GUI_SUPPORT + update_gui(TRUE); +#endif + } while (stat != SCPE_EXIT); + fclose (fpin); /* close file */ + return SCPE_OK; } /* end if cmd file */ +return SCPE_OPENERR; +} + +/* Set command */ + +t_stat set_cmd (int flag, char *cptr) +{ +int32 lvl; +t_stat r; +char gbuf[CBUFSIZE], *cvptr; +DEVICE *dptr; +UNIT *uptr; +MTAB *mptr; +CTAB *ctbr; +static CTAB set_dev_tab[] = { + { "OCTAL", &set_radix, 8 }, + { "DECIMAL", &set_radix, 10 }, + { "HEX", &set_radix, 16 }, + { NULL, NULL, 0 } }; +static CTAB set_unit_tab[] = { + { "ONLINE", &set_onoff, 1 }, + { "OFFLINE", &set_onoff, 0 }, + { NULL, NULL, 0 } }; + +GET_SWITCHES (cptr, gbuf); /* get switches */ +if (*cptr == 0) return SCPE_2FARG; /* must be more */ +cptr = get_glyph (cptr, gbuf, 0); /* get glob/dev/unit */ +if (*cptr == 0) return SCPE_2FARG; /* must be more */ + +if (dptr = find_dev (gbuf)) { /* device match? */ + uptr = dptr -> units; /* first unit */ + ctbr = set_dev_tab; /* global table */ + lvl = MTAB_VDV; } /* device match */ +else if (dptr = find_unit (gbuf, &uptr)) { /* unit match? */ + if (uptr == NULL) return SCPE_NXUN; /* invalid unit */ + ctbr = set_unit_tab; /* global table */ + lvl = MTAB_VUN; } /* unit match */ +else return SCPE_NXDEV; /* no match */ +if (dptr -> modifiers == NULL) return SCPE_NOPARAM; /* any modifiers? */ + +while (*cptr != 0) { /* do all mods */ + cptr = get_glyph (cptr, gbuf, ','); /* get modifier */ + if (cvptr = strchr (gbuf, '=')) *cvptr++ = 0; /* = value? */ + if (set_glob (ctbr, gbuf, dptr, uptr) == SCPE_OK) /* global match? */ + return SCPE_OK; + for (mptr = dptr -> modifiers; mptr -> mask != 0; mptr++) { + if ((mptr -> mstring) && /* match string */ + (MATCH_CMD (gbuf, mptr -> mstring) == 0)) { /* matches option? */ + if (mptr -> mask & MTAB_XTD) { /* extended? */ + if ((lvl & mptr -> mask) == 0) return SCPE_ARG; + if ((lvl & MTAB_VUN) && (uptr -> flags & UNIT_DIS)) + return SCPE_UDIS; /* unit disabled? */ + if (mptr -> valid) { /* validation rtn? */ + r = mptr -> valid (uptr, mptr -> match, cvptr, mptr -> desc); + if (r != SCPE_OK) return r; } + else if (!mptr -> desc) break; /* value desc? */ + else if (mptr -> mask & MTAB_VAL) { /* take a value? */ + if (!cvptr) return SCPE_MISVAL; /* none? error */ + r = dep_reg (0, cvptr, (REG *) mptr -> desc, 0); + if (r != SCPE_OK) return r; } + else if (cvptr) return SCPE_ARG; /* = value? */ + else *((int32 *) mptr -> desc) = mptr -> match; + } /* end if xtd */ + else { /* old style */ + if (cvptr) return SCPE_ARG; /* = value? */ + if (uptr -> flags & UNIT_DIS) /* disabled? */ + return SCPE_UDIS; + if ((mptr -> valid) && ((r = mptr -> valid + (uptr, mptr -> match, cvptr, mptr -> desc)) + != SCPE_OK)) return r; /* invalid? */ + uptr -> flags = (uptr -> flags & ~(mptr -> mask)) | + (mptr -> match & mptr -> mask); /* set new value */ + } /* end else xtd */ + break; /* terminate for */ + } /* end if match */ + } /* end for */ + if (mptr -> mask == 0) return SCPE_NXPAR; /* any match? */ + } /* end while */ +return SCPE_OK; /* done all */ +} + +t_stat set_glob (CTAB *tab, char *gbuf, DEVICE *dptr, UNIT *uptr) +{ +for (; tab -> name != NULL; tab++) { + if (MATCH_CMD (gbuf, tab -> name) == 0) + return tab -> action (dptr, uptr, tab -> arg); } +return SCPE_NXPAR; +} + +/* Set radix routine */ + +t_stat set_radix (DEVICE *dptr, UNIT *uptr, int32 flag) +{ +dptr -> dradix = flag & 017; +return SCPE_OK; +} + +/* Set online/offline routine */ + +t_stat set_onoff (DEVICE *dptr, UNIT *uptr, int32 flag) +{ +if (!(uptr -> flags & UNIT_DISABLE)) return SCPE_NOFNC; /* allowed? */ +if (flag) uptr -> flags = uptr -> flags & ~UNIT_DIS; /* onl? enable */ +else { /* offline? */ + if ((uptr -> flags & UNIT_ATT) || sim_is_active (uptr)) + return SCPE_NOFNC; /* more tests */ + uptr -> flags = uptr -> flags | UNIT_DIS; } /* disable */ +return SCPE_OK; +} + +/* Show command */ + +t_stat show_cmd (int flag, char *cptr) +{ +int32 i, lvl; +t_stat r; +char gbuf[CBUFSIZE]; +DEVICE *dptr; +UNIT *uptr; +MTAB *mptr; + +static CTAB show_table[] = { + { "CONFIGURATION", &show_config, 0 }, + { "DEVICES", &show_config, 1 }, + { "QUEUE", &show_queue, 0 }, + { "TIME", &show_time, 0 }, + { "MODIFIERS", &show_mod_names, 0 }, + { "VERSION", &show_version, 0 }, + { NULL, NULL, 0 } }; + +GET_SWITCHES (cptr, gbuf); /* test for switches */ +if (*cptr == 0) return SCPE_2FARG; /* must be more */ +cptr = get_glyph (cptr, gbuf, 0); /* get next glyph */ +for (i = 0; show_table[i].name != NULL; i++) { /* find command */ + if (MATCH_CMD (gbuf, show_table[i].name) == 0) { + if (*cptr != 0) return SCPE_2MARG; /* now eol? */ + r = show_table[i].action (stdout, show_table[i].arg); + if (sim_log) show_table[i].action (sim_log, show_table[i].arg); + return r; } } + +if (MATCH_CMD (gbuf, "BREAK") == 0) { /* SHOW BREAK? */ + r = ssh_break (stdout, cptr, 1); + if (sim_log) ssh_break (sim_log, cptr, SSH_SH); + return r; } +if (dptr = find_dev (gbuf)) { /* device match? */ + uptr = dptr -> units; /* first unit */ + lvl = MTAB_VDV; } /* device match */ +else if (dptr = find_unit (gbuf, &uptr)) { /* unit match? */ + if (uptr == NULL) return SCPE_NXUN; /* invalid unit */ + if (uptr -> flags & UNIT_DIS) return SCPE_UDIS; /* disabled? */ + lvl = MTAB_VUN; } /* unit match */ +else return SCPE_NXDEV; /* no match */ + +if (*cptr == 0) { /* now eol? */ + if (lvl == MTAB_VDV) { /* show dev? */ + r = show_device (stdout, dptr, 0); + if (sim_log) show_device (sim_log, dptr, 0); + return r; } + else { + r = show_unit (stdout, dptr, uptr, -1); + if (sim_log) show_unit (sim_log, dptr, uptr, -1); + return r; } } +if (dptr -> modifiers == NULL) return SCPE_NOPARAM; /* any modifiers? */ + +while (*cptr != 0) { /* do all mods */ + cptr = get_glyph (cptr, gbuf, ','); /* get modifier */ + for (mptr = dptr -> modifiers; mptr -> mask != 0; mptr++) { + if (((mptr -> mask & MTAB_XTD)? /* right level? */ + (mptr -> mask & lvl): (MTAB_VUN & lvl)) && + ((mptr -> disp && mptr -> pstring && /* named disp? */ + (MATCH_CMD (gbuf, mptr -> pstring) == 0)) || + ((mptr -> mask & MTAB_VAL) && /* named value? */ + mptr -> mstring && + (MATCH_CMD (gbuf, mptr -> mstring) == 0)))) { + show_one_mod (stdout, dptr, uptr, mptr, 1); + if (sim_log) show_one_mod (sim_log, dptr, uptr, mptr, 1); + break; + } /* end if */ + } /* end for */ + if (mptr -> mask == 0) return SCPE_ARG; /* any match? */ + } /* end while */ +return SCPE_OK; +} + +/* Show processors */ + +t_stat show_device (FILE *st, DEVICE *dptr, int32 flag) +{ +int32 j, ucnt; +UNIT *uptr; + +fprintf (st, "%s", dptr -> name); /* print dev name */ +if (qdisable (dptr)) { /* disabled? */ + fprintf (st, ", disabled\n"); + return SCPE_OK; } +for (j = ucnt = 0; j < dptr -> numunits; j++) { /* count units */ + uptr = (dptr -> units) + j; + if (!(uptr -> flags & UNIT_DIS)) ucnt++; } +show_all_mods (st, dptr, dptr -> units, MTAB_VDV); /* show dev mods */ +if (dptr -> numunits == 0) fprintf (st, "\n"); +else { if (ucnt == 0) fprintf (st, ", all units disabled\n"); + else if (ucnt > 1) fprintf (st, ", %d units\n", ucnt); + else if (flag) fprintf (st, "\n"); } +if (flag) return SCPE_OK; /* dev only? */ +for (j = 0; j < dptr -> numunits; j++) { /* loop thru units */ + uptr = (dptr -> units) + j; + if ((uptr -> flags & UNIT_DIS) == 0) + show_unit (st, dptr, uptr, ucnt); } +return SCPE_OK; +} + +t_stat show_unit (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag) +{ +t_addr kval = (uptr -> flags & UNIT_BINK)? 1024: 1000; +int32 u = uptr - dptr -> units; + +if (flag > 1) fprintf (st, " %s%d", dptr -> name, u); +else if (flag < 0) fprintf (st, "%s%d", dptr -> name, u); +if (uptr -> flags & UNIT_FIX) { + if (uptr -> capac < kval) + fprintf (st, ", %d%s", uptr -> capac, + ((dptr -> dwidth / dptr -> aincr) > 8)? "W": "B"); + else fprintf (st, ", %dK%s", uptr -> capac / kval, + ((dptr -> dwidth / dptr -> aincr) > 8)? "W": "B"); } +if (uptr -> flags & UNIT_ATT) { + fprintf (st, ", attached to %s", uptr -> filename); + if (uptr -> flags & UNIT_RO) fprintf (st, ", read only"); } +else if (uptr -> flags & UNIT_ATTABLE) + fprintf (st, ", not attached"); +show_all_mods (st, dptr, uptr, MTAB_VUN); /* show unit mods */ +fprintf (st, "\n"); +return SCPE_OK; +} + +t_stat show_version (FILE *st, int32 flag) +{ +int32 vmaj = SIM_MAJOR, vmin = SIM_MINOR, vpat = SIM_PATCH; + +fprintf (st, "%s simulator V%d.%d-%d\n", sim_name, vmaj, vmin, vpat); +return SCPE_OK; +} + +t_stat show_config (FILE *st, int32 flag) +{ +int32 i; +DEVICE *dptr; + +fprintf (st, "%s simulator configuration\n\n", sim_name); +for (i = 0; (dptr = sim_devices[i]) != NULL; i++) + show_device (st, dptr, flag); +return SCPE_OK; +} + +t_stat show_queue (FILE *st, int32 flag) +{ +DEVICE *dptr; +UNIT *uptr; +int32 accum; + +if (sim_clock_queue == NULL) { + fprintf (st, "%s event queue empty, time = %-16.0f\n", + sim_name, sim_time); + return SCPE_OK; } +fprintf (st, "%s event queue status, time = %-16.0f\n", + sim_name, sim_time); +accum = 0; +for (uptr = sim_clock_queue; uptr != NULL; uptr = uptr -> next) { + if (uptr == &step_unit) fprintf (st, " Step timer"); + else if ((dptr = find_dev_from_unit (uptr)) != NULL) { + fprintf (st, " %s", dptr -> name); + if (dptr -> numunits > 1) fprintf (st, " unit %d", + uptr - dptr -> units); } + else fprintf (st, " Unknown"); + fprintf (st, " at %d\n", accum + uptr -> time); + accum = accum + uptr -> time; } +return SCPE_OK; +} + +t_stat show_time (FILE *st, int32 flag) +{ +fprintf (st, "Time: %-16.0f\n", sim_time); +return SCPE_OK; +} + +t_stat show_mod_names (FILE *st, int32 flag) +{ +int i, any; +DEVICE *dptr; +MTAB *mptr; + +for (i = 0; (dptr = sim_devices[i]) != NULL; i++) { + if (dptr -> modifiers) { + any = 0; + for (mptr = dptr -> modifiers; mptr -> mask != 0; mptr++) { + if (mptr -> mstring) { + if (any++) fprintf (st, ", %s", mptr -> mstring); + else fprintf (st, "%s\t%s", dptr -> name, mptr -> mstring); } } + if (any) fprintf (st, "\n"); } } +return SCPE_OK; +} + +t_stat show_all_mods (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag) +{ +MTAB *mptr; + +if (dptr -> modifiers == NULL) return SCPE_OK; +for (mptr = dptr -> modifiers; mptr -> mask != 0; mptr++) { + if (mptr -> pstring && ((mptr -> mask & MTAB_XTD)? + ((mptr -> mask & flag) && !(mptr -> mask & MTAB_NMO)): + ((MTAB_VUN & flag) && ((uptr -> flags & mptr -> mask) == mptr -> match)))) { + fputs (", ", st); + show_one_mod (st, dptr, uptr, mptr, 0); } } +return SCPE_OK; +} + +t_stat show_one_mod (FILE *st, DEVICE *dptr, UNIT *uptr, MTAB *mptr, int32 flag) +{ +t_value val; + +if (mptr -> disp) mptr -> disp (st, uptr, mptr -> match, mptr -> desc); +else if ((mptr -> mask & MTAB_XTD) && (mptr -> mask & MTAB_VAL)) { + REG *rptr = (REG *) mptr -> desc; + fprintf (st, "%s=", mptr -> pstring); + val = get_rval (rptr, 0); + fprint_val (st, val, rptr -> radix, rptr -> width, + rptr -> flags & REG_FMT); } +else fputs (mptr -> pstring, st); +if (flag && !((mptr -> mask & MTAB_XTD) && + (mptr -> mask & MTAB_NMO))) fputc ('\n', st); +return SCPE_OK; +} + +/* Breakpoint commands */ + +t_stat brk_cmd (int flg, char *cptr) +{ +char gbuf[CBUFSIZE]; + +GET_SWITCHES (cptr, gbuf); /* test for switches */ +if (*cptr == 0) return SCPE_2FARG; /* must be more */ +return ssh_break (NULL, cptr, flg); /* call common code */ +} + +t_stat ssh_break (FILE *st, char *cptr, int32 flg) +{ +char gbuf[CBUFSIZE], *tptr, *t1ptr; +DEVICE *dptr = sim_devices[0]; +UNIT *uptr = dptr -> units; +t_stat r; +t_addr lo, hi, max = uptr -> capac - dptr -> aincr; +int32 cnt; + +if (*cptr == 0) return SCPE_2FARG; +if (sim_brk_types == 0) return SCPE_NOFNC; +if ((dptr == NULL) || (uptr == NULL)) return SCPE_IERR; +while (*cptr) { + cptr = get_glyph (cptr, gbuf, ','); + tptr = get_range (gbuf, &lo, &hi, dptr -> aradix, max, 0); + if (tptr == NULL) return SCPE_ARG; + if (*tptr == '[') { + errno = 0; + cnt = strtoul (tptr + 1, &t1ptr, 10); + if (errno || (tptr == t1ptr) || (*t1ptr != ']') || + (flg != SSH_ST)) return SCPE_ARG; + tptr = t1ptr + 1; } + else cnt = 0; + if (*tptr != 0) return SCPE_ARG; + if ((lo == 0) && (hi == max)) { + if (flg == SSH_CL) sim_brk_clrall (sim_switches); + else if (flg == SSH_SH) sim_brk_showall (st, sim_switches); + else return SCPE_ARG; } + else { + for ( ; lo <= hi; lo = lo + dptr -> aincr) { + if (flg == SSH_ST) r = sim_brk_set (lo, sim_switches, cnt); + else if (flg == SSH_CL) r = sim_brk_clr (lo, sim_switches); + else if (flg == SSH_SH) r = sim_brk_show (st, lo, sim_switches); + else return SCPE_ARG; + } + } + } +return SCPE_OK; +} + +/* Logging commands + + log filename open log file + nolog close log file +*/ + +t_stat log_cmd (int flag, char *cptr) +{ +char gbuf[CBUFSIZE]; + +GET_SWITCHES (cptr, gbuf); /* test for switches */ +if (*cptr == 0) return (sim_log? SCPE_LOGON: SCPE_LOGOFF); +cptr = get_glyph_nc (cptr, gbuf, 0); /* get file name */ +if (*cptr != 0) return SCPE_2MARG; /* now eol? */ +nolog_cmd (0, NULL); /* close cur log */ +sim_log = fopen (gbuf, "a"); /* open log */ +if (sim_log == NULL) return SCPE_OPENERR; /* error? */ +printf ("Logging to file \"%s\"\n", gbuf); /* start of log */ +fprintf (sim_log, "Logging to file \"%s\"\n", gbuf); +return SCPE_OK; +} + +t_stat nolog_cmd (int flag, char *cptr) +{ +char gbuf[CBUFSIZE]; + +if (cptr) { + GET_SWITCHES (cptr, gbuf); /* test for switches */ + if (*cptr != 0) return SCPE_2MARG; } /* now eol? */ +if (sim_log == NULL) return SCPE_OK; /* no log? */ +printf ("Log file closed\n"); +fprintf (sim_log, "Log file closed\n"); /* close log */ +fclose (sim_log); +sim_log = NULL; +return SCPE_OK; +} + +/* Reset command and routines + + re[set] reset all devices + re[set] all reset all devices + re[set] device reset specific device +*/ + +t_stat reset_cmd (int flag, char *cptr) +{ +char gbuf[CBUFSIZE]; +DEVICE *dptr; + +GET_SWITCHES (cptr, gbuf); /* test for switches */ +if (*cptr == 0) return (reset_all (0)); /* reset(cr) */ +cptr = get_glyph (cptr, gbuf, 0); /* get next glyph */ +if (*cptr != 0) return SCPE_2MARG; /* now eol? */ +if (strcmp (gbuf, "ALL") == 0) return (reset_all (0)); +dptr = find_dev (gbuf); /* locate device */ +if (dptr == NULL) return SCPE_NXDEV; /* found it? */ +if (dptr -> reset != NULL) return dptr -> reset (dptr); +else return SCPE_OK; +} + +/* Reset devices start..end + + Inputs: + start = number of starting device + Outputs: + status = error status +*/ + +t_stat reset_all (int start) +{ +DEVICE *dptr; +int32 i; +t_stat reason; + +if (start < 0) return SCPE_IERR; +for (i = 0; i < start; i++) { + if (sim_devices[i] == NULL) return SCPE_IERR; } +for (i = start; (dptr = sim_devices[i]) != NULL; i++) { + if (dptr -> reset != NULL) { + reason = dptr -> reset (dptr); + if (reason != SCPE_OK) return reason; } } +return SCPE_OK; +} + +/* Load and dump commands + + lo[ad] filename {arg} load specified file + du[mp] filename {arg} dump to specified file +*/ + +t_stat load_cmd (int flag, char *cptr) +{ +char gbuf[CBUFSIZE]; +FILE *loadfile; +t_stat reason; + +GET_SWITCHES (cptr, gbuf); /* test for switches */ +if (*cptr == 0) return SCPE_2FARG; /* must be more */ +cptr = get_glyph_nc (cptr, gbuf, 0); /* get file name */ +loadfile = fopen (gbuf, flag? "wb": "rb"); /* open for wr/rd */ +if (loadfile == NULL) return SCPE_OPENERR; +reason = sim_load (loadfile, cptr, gbuf, flag); /* load or dump */ +fclose (loadfile); +return reason; +} + +/* Attach command + + at[tach] unit file attach specified unit to file +*/ + +t_stat attach_cmd (int flag, char *cptr) +{ +char gbuf[CBUFSIZE]; +DEVICE *dptr; +UNIT *uptr; + +GET_SWITCHES (cptr, gbuf); /* test for switches */ +if (*cptr == 0) return SCPE_2FARG; /* must be more */ +cptr = get_glyph (cptr, gbuf, 0); /* get next glyph */ +if (*cptr == 0) return SCPE_2MARG; /* now eol? */ +dptr = find_unit (gbuf, &uptr); /* locate unit */ +if (dptr == NULL) return SCPE_NXDEV; /* found dev? */ +if (uptr == NULL) return SCPE_NXUN; /* valid unit? */ +if (dptr -> attach != NULL) return dptr -> attach (uptr, cptr); +return attach_unit (uptr, cptr); +} + +t_stat attach_unit (UNIT *uptr, char *cptr) +{ +DEVICE *dptr; +t_stat reason; + +if (uptr -> flags & UNIT_DIS) return SCPE_UDIS; /* disabled? */ +if (!(uptr -> flags & UNIT_ATTABLE)) return SCPE_NOATT; /* not attachable? */ +if ((dptr = find_dev_from_unit (uptr)) == NULL) return SCPE_NOATT; +if (uptr -> flags & UNIT_ATT) { /* already attached? */ + reason = detach_unit (uptr); + if (reason != SCPE_OK) return reason; } +uptr -> filename = calloc (CBUFSIZE, sizeof (char)); +if (uptr -> filename == NULL) return SCPE_MEM; +strncpy (uptr -> filename, cptr, CBUFSIZE); +if (sim_switches & SWMASK ('R')) { /* read only? */ + if ((uptr -> flags & UNIT_ROABLE) == 0) /* allowed? */ + return attach_err (uptr, SCPE_NORO); /* no, error */ + uptr -> fileref = FOPEN (cptr, "rb"); /* open rd only */ + if (uptr -> fileref == NULL) /* open fail? */ + return attach_err (uptr, SCPE_OPENERR); /* yes, error */ + uptr -> flags = uptr -> flags | UNIT_RO; /* set rd only */ + printf ("%s: unit is read only\n", dptr -> name); } +else { /* normal */ + uptr -> fileref = FOPEN (cptr, "rb+"); /* open r/w */ + if (uptr -> fileref == NULL) { /* open fail? */ + if (errno == EROFS) { /* read only? */ + if ((uptr -> flags & UNIT_ROABLE) == 0) /* allowed? */ + return attach_err (uptr, SCPE_NORO); /* no error */ + uptr -> fileref = FOPEN (cptr, "rb"); /* open rd only */ + if (uptr -> fileref == NULL) /* open fail? */ + return attach_err (uptr, SCPE_OPENERR); /* yes, error */ + uptr -> flags = uptr -> flags | UNIT_RO; /* set rd only */ + printf ("%s: unit is read only\n", dptr -> name); } + else { /* doesn't exist */ + if (sim_switches & SWMASK ('E')) /* must exist? */ + return attach_err (uptr, SCPE_OPENERR); /* yes, error */ + uptr -> fileref = FOPEN (cptr, "wb+"); /* open new file */ + if (uptr -> fileref == NULL) /* open fail? */ + return attach_err (uptr, SCPE_OPENERR); /* yes, error */ + printf ("%s: creating new file\n", dptr -> name); } + } /* end if null */ + } /* end else */ +if (uptr -> flags & UNIT_BUFABLE) { /* buffer? */ + if ((uptr -> filebuf = calloc (uptr -> capac, SZ_D (dptr))) != NULL) { + printf ("%s: buffering file in memory\n", dptr -> name); + uptr -> hwmark = fxread (uptr -> filebuf, SZ_D (dptr), + uptr -> capac, uptr -> fileref); + uptr -> flags = uptr -> flags | UNIT_BUF; } + else if (uptr -> flags & UNIT_MUSTBUF) /* must buf? */ + return attach_err (uptr, SCPE_MEM); } +uptr -> flags = uptr -> flags | UNIT_ATT; +uptr -> pos = 0; +return SCPE_OK; +} + +t_stat attach_err (UNIT *uptr, t_stat stat) +{ +free (uptr -> filename); +uptr -> filename = NULL; +return stat; +} + +/* Detach command + + det[ach] all detach all units + det[ach] unit detach specified unit +*/ + +t_stat detach_cmd (int flag, char *cptr) +{ +char gbuf[CBUFSIZE]; +DEVICE *dptr; +UNIT *uptr; + +GET_SWITCHES (cptr, gbuf); /* test for switches */ +if (*cptr == 0) return SCPE_2FARG; /* must be more */ +cptr = get_glyph (cptr, gbuf, 0); /* get next glyph */ +if (*cptr != 0) return SCPE_2MARG; /* now eol? */ +if (strcmp (gbuf, "ALL") == 0) return (detach_all (0, FALSE)); +dptr = find_unit (gbuf, &uptr); /* locate unit */ +if (dptr == NULL) return SCPE_NXDEV; /* found dev? */ +if (uptr == NULL) return SCPE_NXUN; /* valid unit? */ +if (!(uptr -> flags & UNIT_ATTABLE)) return SCPE_NOATT; +if (dptr -> detach != NULL) return dptr -> detach (uptr); +return detach_unit (uptr); +} + +/* Detach devices start..end + + Inputs: + start = number of starting device + shutdown = TRUE if simulator shutting down + Outputs: + status = error status +*/ + +t_stat detach_all (int32 start, t_bool shutdown) +{ +int32 i, j; +t_stat reason; +DEVICE *dptr; +UNIT *uptr; + +if ((start < 0) || (start > 1)) return SCPE_IERR; +for (i = start; (dptr = sim_devices[i]) != NULL; i++) { + for (j = 0; j < dptr -> numunits; j++) { + uptr = (dptr -> units) + j; + if ((uptr -> flags & UNIT_ATTABLE) || shutdown) { + if (dptr -> detach != NULL) reason = dptr -> detach (uptr); + else reason = detach_unit (uptr); + if (reason != SCPE_OK) return reason; } } } +return SCPE_OK; +} + +t_stat detach_unit (UNIT *uptr) +{ +DEVICE *dptr; + +if (uptr == NULL) return SCPE_IERR; +if (!(uptr -> flags & UNIT_ATT)) return SCPE_OK; +if ((dptr = find_dev_from_unit (uptr)) == NULL) return SCPE_OK; +if (uptr -> flags & UNIT_BUF) { + if (uptr -> hwmark && ((uptr -> flags & UNIT_RO) == 0)) { + printf ("%s: writing buffer to file\n", dptr -> name); + rewind (uptr -> fileref); + fxwrite (uptr -> filebuf, SZ_D (dptr), uptr -> hwmark, uptr -> fileref); + if (ferror (uptr -> fileref)) perror ("I/O error"); } + free (uptr -> filebuf); + uptr -> flags = uptr -> flags & ~UNIT_BUF; + uptr -> filebuf = NULL; } +uptr -> flags = uptr -> flags & ~(UNIT_ATT | UNIT_RO); +free (uptr -> filename); +uptr -> filename = NULL; +return (fclose (uptr -> fileref) == EOF)? SCPE_IOERR: SCPE_OK; +} + +/* Save command + + sa[ve] filename save state to specified file +*/ + +t_stat save_cmd (int flag, char *cptr) +{ +char gbuf[CBUFSIZE]; +void *mbuf; +FILE *sfile; +int32 i, j, l, t; +t_addr k, high; +t_value val; +t_stat r; +t_bool zeroflg; +size_t sz; +DEVICE *dptr; +UNIT *uptr; +REG *rptr; + +#define WRITE_I(xx) fxwrite (&(xx), sizeof (xx), 1, sfile) + +GET_SWITCHES (cptr, gbuf); /* test for switches */ +if (*cptr == 0) return SCPE_2FARG; /* must be more */ +if ((sfile = fopen (cptr, "wb")) == NULL) return SCPE_OPENERR; +fputs (save_vercur, sfile); /* save format version */ +fputc ('\n', sfile); +fputs (sim_name, sfile); /* sim name */ +fputc ('\n', sfile); +WRITE_I (sim_time); /* sim time */ +WRITE_I (sim_rtime); /* sim relative time */ + +for (i = 0; (dptr = sim_devices[i]) != NULL; i++) { /* loop thru devices */ + fputs (dptr -> name, sfile); /* device name */ + fputc ('\n', sfile); + for (j = 0; j < dptr -> numunits; j++) { + uptr = (dptr -> units) + j; + t = sim_is_active (uptr); + WRITE_I (j); /* unit number */ + WRITE_I (t); /* activation time */ + WRITE_I (uptr -> u3); /* unit specific */ + WRITE_I (uptr -> u4); + if (uptr -> flags & UNIT_ATT) fputs (uptr -> filename, sfile); + fputc ('\n', sfile); + if (((uptr -> flags & (UNIT_FIX + UNIT_ATTABLE)) == UNIT_FIX) && + (dptr -> examine != NULL) && + ((high = uptr -> capac) != 0)) { /* memory-like unit? */ + WRITE_I (high); /* write size */ + sz = SZ_D (dptr); + if ((mbuf = calloc (SRBSIZ, sz)) == NULL) { + fclose (sfile); + return SCPE_MEM; } + for (k = 0; k < high; ) { + zeroflg = TRUE; + for (l = 0; (l < SRBSIZ) && (k < high); + l++, k = k + (dptr -> aincr)) { + r = dptr -> examine (&val, k, uptr, 0); + if (r != SCPE_OK) return r; + if (val) zeroflg = FALSE; + SZ_STORE (sz, val, mbuf, l); + } /* end for l */ + if (zeroflg) { /* all zero's? */ + l = -l; /* invert block count */ + WRITE_I (l); } /* write only count */ + else { + WRITE_I (l); /* block count */ + fxwrite (mbuf, l, sz, sfile); } + } /* end for k */ + free (mbuf); /* dealloc buffer */ + } /* end if mem */ + else { high = 0; + WRITE_I (high); } /* no memory */ + } /* end unit loop */ + j = -1; /* write marker */ + WRITE_I (j); + for (rptr = dptr -> registers; /* loop thru regs */ + (rptr != NULL) && (rptr -> name != NULL); rptr++) { + fputs (rptr -> name, sfile); /* name */ + fputc ('\n', sfile); + for (j = 0; j < rptr -> depth; j++) { /* loop thru values */ + val = get_rval (rptr, j); /* get value */ + WRITE_I (val); } } /* store */ + fputc ('\n', sfile); } /* end registers */ +fputc ('\n', sfile); /* end devices */ +r = (ferror (sfile))? SCPE_IOERR: SCPE_OK; /* error during save? */ +fclose (sfile); +return r; +} + +/* Restore command + + re[store] filename restore state from specified file +*/ + +t_stat restore_cmd (int flag, char *cptr) +{ +char buf[CBUFSIZE]; +void *mbuf; +FILE *rfile; +int32 i, j, blkcnt, limit, unitno, time; +t_addr k, high; +t_value val, mask, vzro = 0; +t_stat r; +size_t sz; +t_bool v26 = FALSE, v25 = FALSE; +DEVICE *dptr; +UNIT *uptr; +REG *rptr; + +#define READ_S(xx) if (read_line ((xx), CBUFSIZE, rfile) == NULL) \ + { fclose (rfile); return SCPE_IOERR; } +#define READ_I(xx) if (fxread (&xx, sizeof (xx), 1, rfile) <= 0) \ + { fclose (rfile); return SCPE_IOERR; } + +GET_SWITCHES (cptr, buf); /* test for switches */ +if (*cptr == 0) return SCPE_2FARG; /* must be more */ +if ((rfile = fopen (cptr, "rb")) == NULL) return SCPE_OPENERR; +READ_S (buf); /* save ver or sim name */ +if (strcmp (buf, save_vercur) == 0) { /* version 2.6? */ + v26 = v25 = TRUE; /* set flag */ + READ_S (buf); } /* read name */ +else if (strcmp (buf, save_ver25) == 0) { /* version 2.5? */ + v25 = TRUE; /* set flag */ + READ_S (buf); } /* read name */ +if (strcmp (buf, sim_name)) { /* name match? */ + printf ("Wrong system type: %s\n", buf); + fclose (rfile); + return SCPE_INCOMP; } +READ_I (sim_time); /* sim time */ +if (v26) { READ_I (sim_rtime); } /* sim relative time */ + +for ( ;; ) { /* device loop */ + READ_S (buf); /* read device name */ + if (buf[0] == 0) break; /* last? */ + if ((dptr = find_dev (buf)) == NULL) { /* locate device */ + printf ("Invalid device name: %s\n", buf); + fclose (rfile); + return SCPE_INCOMP; } + for ( ;; ) { /* unit loop */ + READ_I (unitno); /* unit number */ + if (unitno < 0) break; + if (unitno >= dptr -> numunits) { + printf ("Invalid unit number %s%d\n", dptr -> name, + unitno); + fclose (rfile); + return SCPE_INCOMP; } + READ_I (time); /* event time */ + uptr = (dptr -> units) + unitno; + sim_cancel (uptr); + if (time > 0) sim_activate (uptr, time - 1); + READ_I (uptr -> u3); /* device specific */ + READ_I (uptr -> u4); + READ_S (buf); /* attached file */ + if (buf[0] != 0) { + uptr -> flags = uptr -> flags & ~UNIT_DIS; + if (dptr -> attach != NULL) r = dptr -> attach (uptr, buf); + else r = attach_unit (uptr, buf); + if (r != SCPE_OK) return r; } + READ_I (high); /* memory capacity */ + if (high > 0) { /* any memory? */ + if (((uptr -> flags & (UNIT_FIX + UNIT_ATTABLE)) != UNIT_FIX) || + (high > uptr -> capac) || (dptr -> deposit == NULL)) { + printf ("Invalid memory bound: %u\n", high); + fclose (rfile); + return SCPE_INCOMP; } + if (v25) { + sz = SZ_D (dptr); + if ((mbuf = calloc (SRBSIZ, sz)) == NULL) { + fclose (rfile); + return SCPE_MEM; } + for (k = 0; k < high; ) { + READ_I (blkcnt); + if (blkcnt < 0) limit = -blkcnt; + else limit = fxread (mbuf, sz, blkcnt, rfile); + if (limit <= 0) { + fclose (rfile); + return SCPE_IOERR; } + for (j = 0; j < limit; j++, k = k + (dptr -> aincr)) { + if (blkcnt < 0) val = 0; + else SZ_LOAD (sz, val, mbuf, j); + r = dptr -> deposit (val, k, uptr, 0); + if (r != SCPE_OK) return r; + } /* end for j */ + } /* end for k */ + free (mbuf); /* dealloc buffer */ + } /* end if v25 */ + else { for (k = 0; k < high; k = k + (dptr -> aincr)) { + READ_I (val); + if (((t_svalue) val) < 0) { + for (j = (int32) val + 1; j < 0; j++) { + r = dptr -> deposit (vzro, k, uptr, 0); + if (r != SCPE_OK) return r; + k = k + (dptr -> aincr); } + val = 0; } + r = dptr -> deposit (val, k, uptr, 0); + if (r != SCPE_OK) return r; } + } /* end else v25 */ + } /* end if high */ + } /* end unit loop */ + for ( ;; ) { /* register loop */ + READ_S (buf); /* read reg name */ + if (buf[0] == 0) break; /* last? */ + if ((rptr = find_reg (buf, NULL, dptr)) == NULL) { + printf ("Invalid register name: %s\n", buf); + READ_I (val); /* assume depth=1 */ + continue; } /* and pray! */ + mask = width_mask[rptr -> width]; + for (i = 0; i < rptr -> depth; i++) { /* loop thru values */ + READ_I (val); /* read value */ + if (val > mask) + printf ("Invalid register value: %s\n", buf); + else put_rval (rptr, i, val); } } + } /* end device loop */ +fclose (rfile); +return SCPE_OK; +} + +/* Run, go, cont, step commands + + ru[n] [new PC] reset and start simulation + go [new PC] start simulation + co[nt] start simulation + s[tep] [step limit] start simulation for 'limit' instructions + b[oot] device bootstrap from device and start simulation +*/ + +t_stat run_cmd (int flag, char *cptr) +{ +char gbuf[CBUFSIZE]; +int32 i, j, step, unitno; +t_stat r; +DEVICE *dptr; +UNIT *uptr; +void int_handler (int signal); + +GET_SWITCHES (cptr, gbuf); /* test for switches */ +step = 0; +if (((flag == RU_RUN) || (flag == RU_GO)) && (*cptr != 0)) { /* run or go */ + cptr = get_glyph (cptr, gbuf, 0); /* get next glyph */ + if ((r = dep_reg (0, gbuf, sim_PC, 0)) != SCPE_OK) return r; } + +if (flag == RU_STEP) { /* step */ + if (*cptr == 0) step = 1; + else { cptr = get_glyph (cptr, gbuf, 0); + step = (int32) get_uint (gbuf, 10, INT_MAX, &r); + if ((r != SCPE_OK) || (step == 0)) return SCPE_ARG; } } + +if (flag == RU_BOOT) { /* boot */ + if (*cptr == 0) return SCPE_2FARG; /* must be more */ + cptr = get_glyph (cptr, gbuf, 0); /* get next glyph */ + dptr = find_unit (gbuf, &uptr); /* locate unit */ + if (dptr == NULL) return SCPE_NXDEV; /* found dev? */ + if (uptr == NULL) return SCPE_NXUN; /* valid unit? */ + if (dptr -> boot == NULL) return SCPE_NOFNC; /* can it boot? */ + if (uptr -> flags & UNIT_DIS) return SCPE_UDIS; /* disabled? */ + if ((uptr -> flags & UNIT_ATTABLE) && + !(uptr -> flags & UNIT_ATT)) return SCPE_UNATT; + unitno = uptr - dptr -> units; /* recover unit# */ + if ((r = dptr -> boot (unitno)) != SCPE_OK) return r; } + +if (*cptr != 0) return SCPE_2MARG; /* now eol? */ + +if ((flag == RU_RUN) || (flag == RU_BOOT)) { /* run or boot */ + sim_interval = 0; /* reset queue */ + sim_time = sim_rtime = 0; + noqueue_time = 0; + sim_clock_queue = NULL; + if ((r = reset_all (0)) != SCPE_OK) return r; } +for (i = 1; (dptr = sim_devices[i]) != NULL; i++) { + for (j = 0; j < dptr -> numunits; j++) { + uptr = (dptr -> units) + j; + if ((uptr -> flags & (UNIT_ATT + UNIT_SEQ)) == + (UNIT_ATT + UNIT_SEQ)) + fseek (uptr -> fileref, uptr -> pos, SEEK_SET); } } +stop_cpu = 0; +if ((int) signal (SIGINT, int_handler) == -1) { /* set WRU */ + return SCPE_SIGERR; } +if (ttrunstate () != SCPE_OK) { /* set console */ + ttcmdstate (); + return SCPE_TTYERR; } +if (step) sim_activate (&step_unit, step); /* set step timer */ +sim_is_running = 1; /* flag running */ +r = sim_instr(); + +sim_is_running = 0; /* flag idle */ +ttcmdstate (); /* restore console */ +signal (SIGINT, SIG_DFL); /* cancel WRU */ +sim_cancel (&step_unit); /* cancel step timer */ +if (sim_clock_queue != NULL) { /* update sim time */ + UPDATE_SIM_TIME (sim_clock_queue -> time); } +else { UPDATE_SIM_TIME (noqueue_time); } +#if defined (VMS) +printf ("\n"); +#endif +fprint_stopped (stdout, r); /* print msg */ +if (sim_log) fprint_stopped (sim_log, r); /* log if enabled */ +return SCPE_OK; +} + +/* Print stopped message */ + +void fprint_stopped (FILE *stream, t_stat v) +{ +int32 i; +t_stat r; +t_addr k; +t_value pcval; +DEVICE *dptr; + +if (v >= SCPE_BASE) fprintf (stream, "\n%s, %s: ", + scp_error_messages[v - SCPE_BASE], sim_PC -> name); +else fprintf (stream, "\n%s, %s: ", sim_stop_messages[v], sim_PC -> name); +pcval = get_rval (sim_PC, 0); +fprint_val (stream, pcval, sim_PC -> radix, sim_PC -> width, + sim_PC -> flags & REG_FMT); +if (((dptr = sim_devices[0]) != NULL) && (dptr -> examine != NULL)) { + for (i = 0; i < sim_emax; i++) sim_eval[i] = 0; + for (i = 0, k = (t_addr) pcval; i < sim_emax; i++, k = k + dptr -> aincr) { + if (r = dptr -> examine (&sim_eval[i], k, dptr -> units, + SWMASK ('V')) != SCPE_OK) break; } + if ((r == SCPE_OK) || (i > 0)) { + fprintf (stream, " ("); + if (fprint_sym (stream, (t_addr) pcval, sim_eval, NULL, SWMASK('M')) > 0) + fprint_val (stream, sim_eval[0], dptr -> dradix, + dptr -> dwidth, PV_RZRO); + fprintf (stream, ")"); } } +fprintf (stream, "\n"); +return; +} + +/* Unit service for step timeout, originally scheduled by STEP n command + + Return step timeout SCP code, will cause simulation to stop +*/ + +t_stat step_svc (UNIT *uptr) +{ +return SCPE_STEP; +} + +/* Signal handler for ^C signal + + Set stop simulation flag +*/ + +void int_handler (int sig) +{ +stop_cpu = 1; +return; +} + +/* Examine/deposit commands + + ex[amine] [modifiers] list examine + de[posit] [modifiers] list val deposit + ie[xamine] [modifiers] list interactive examine + id[eposit] [modifiers] list interactive deposit + + modifiers + @filename output file + -letter(s) switches + devname'n device name and unit number + [{&|^}value]{=|==|!|!=|>|>=|<|<=} value search specification + + list list of addresses and registers + addr[:addr|-addr] address range + ALL all addresses + register[:register|-register] register range + STATE all registers +*/ + +t_stat exdep_cmd (int flag, char *cptr) +{ +char gbuf[CBUFSIZE], *gptr, *tptr; +int32 t; +t_bool exd2f; +t_addr low, high; +t_stat reason; +DEVICE *dptr, *tdptr; +UNIT *uptr, *tuptr; +REG *lowr, *highr; +SCHTAB stab, *schptr; +FILE *ofile; +t_stat exdep_addr_loop (FILE *ofile, SCHTAB *schptr, int flag, char *ptr, + t_addr low, t_addr high, DEVICE *dptr, UNIT *uptr); +t_stat exdep_reg_loop (FILE *ofile, SCHTAB *schptr, int flag, char *ptr, + REG *lowr, REG *highr, t_addr lows, t_addr highs); + +ofile = NULL; /* no output file */ +exd2f = FALSE; +sim_switches = 0; /* no switches */ +schptr = NULL; /* no search */ +stab.logic = SCH_OR; /* default search params */ +stab.bool = SCH_GE; +stab.mask = stab.comp = 0; +dptr = sim_devices[0]; /* default device, unit */ +uptr = dptr -> units; +for (;;) { /* loop through modifiers */ + if (*cptr == 0) return SCPE_2FARG; /* must be more */ + if (*cptr == '@') { /* output file spec? */ + if (flag != EX_E) return SCPE_ARG; /* examine only */ + if (exd2f) { /* already got one? */ + fclose (ofile); /* one per customer */ + return SCPE_ARG; } + cptr = get_glyph_nc (cptr + 1, gbuf, 0); + ofile = fopen (gbuf, "a"); /* open for append */ + if (ofile == NULL) return SCPE_OPENERR; + exd2f = TRUE; + continue; } /* look for more */ + cptr = get_glyph (cptr, gbuf, 0); + if ((t = get_switches (gbuf)) != 0) { /* try for switches */ + if (t < 0) return SCPE_INVSW; /* err if bad switch */ + sim_switches = sim_switches | t; } /* or in new switches */ + else if (get_search (gbuf, dptr, &stab) != NULL) { /* try for search */ + schptr = &stab; } /* set search */ + else if (((tdptr = find_unit (gbuf, &tuptr)) != NULL) && + (tuptr != NULL)) { /* try for unit */ + dptr = tdptr; /* set as default */ + uptr = tuptr; } + else break; } /* not rec, break out */ +if (uptr == NULL) return SCPE_NXUN; /* got a unit? */ +if ((*cptr == 0) == (flag == 0)) return SCPE_ARG; /* eol if needed? */ + +if (ofile == NULL) ofile = stdout; /* no file? stdout */ +for (gptr = gbuf, reason = SCPE_OK; + (*gptr != 0) && (reason == SCPE_OK); gptr = tptr) { + tdptr = dptr; /* working dptr */ + if (strncmp (gptr, "STATE", strlen ("STATE")) == 0) { + tptr = gptr + strlen ("STATE"); + if (*tptr && (*tptr++ != ',')) return SCPE_ARG; + if ((lowr = dptr -> registers) == NULL) return SCPE_NXREG; + for (highr = lowr; highr -> name != NULL; highr++) ; + sim_switches = sim_switches | SWHIDE; + reason = exdep_reg_loop (ofile, schptr, flag, cptr, + lowr, --highr, 0, 0); + continue; } + + if ((lowr = find_reg (gptr, &tptr, tdptr)) || + (lowr = find_reg_glob (gptr, &tptr, &tdptr))) { + low = high = 0; + if ((*tptr == '-') || (*tptr == ':')) { + highr = find_reg (tptr + 1, &tptr, tdptr); + if (highr == NULL) return SCPE_NXREG; } + else { highr = lowr; + if (*tptr == '[') { + if (lowr -> depth <= 1) return SCPE_ARG; + tptr = get_range (tptr + 1, &low, &high, + 10, lowr -> depth - 1, ']'); + if (tptr == NULL) return SCPE_ARG; } } + if (*tptr && (*tptr++ != ',')) return SCPE_ARG; + reason = exdep_reg_loop (ofile, schptr, flag, cptr, + lowr, highr, low, high); + continue; } + + tptr = get_range (gptr, &low, &high, dptr -> aradix, + (((uptr -> capac == 0) || (flag == EX_E))? 0: + uptr -> capac - dptr -> aincr), 0); + if (tptr == NULL) return SCPE_ARG; + if (*tptr && (*tptr++ != ',')) return SCPE_ARG; + reason = exdep_addr_loop (ofile, schptr, flag, cptr, low, high, + dptr, uptr); + } /* end for */ +if (exd2f) fclose (ofile); /* close output file */ +return reason; +} + +/* Loop controllers for examine/deposit + + exdep_reg_loop examine/deposit range of registers + exdep_addr_loop examine/deposit range of addresses +*/ + +t_stat exdep_reg_loop (FILE *ofile, SCHTAB *schptr, int flag, char *cptr, + REG *lowr, REG *highr, t_addr lows, t_addr highs) +{ +t_stat reason; +t_addr idx; +t_value val; +REG *rptr; + +if ((lowr == NULL) || (highr == NULL)) return SCPE_IERR; +if (lowr > highr) return SCPE_ARG; +for (rptr = lowr; rptr <= highr; rptr++) { + if ((sim_switches & SWHIDE) && + (rptr -> flags & REG_HIDDEN)) continue; + for (idx = lows; idx <= highs; idx++) { + if (idx >= (t_addr) rptr -> depth) return SCPE_SUB; + val = get_rval (rptr, idx); + if (schptr && !test_search (val, schptr)) continue; + if (flag != EX_D) { + reason = ex_reg (ofile, val, flag, rptr, idx); + if (reason != SCPE_OK) return reason; + if (sim_log && (ofile == stdout)) + ex_reg (sim_log, val, flag, rptr, idx); } + if (flag != EX_E) { + reason = dep_reg (flag, cptr, rptr, idx); + if (reason != SCPE_OK) return reason; } } } +return SCPE_OK; +} + +t_stat exdep_addr_loop (FILE *ofile, SCHTAB *schptr, int flag, char *cptr, + t_addr low, t_addr high, DEVICE *dptr, UNIT *uptr) +{ +t_addr i, mask; +t_stat reason; + +if (uptr -> flags & UNIT_DIS) return SCPE_UDIS; /* disabled? */ +reason = 0; +mask = (t_addr) width_mask[dptr -> awidth]; +if ((low > mask) || (high > mask) || (low > high)) return SCPE_ARG; +for (i = low; i <= high; i = i + (dptr -> aincr)) { + reason = get_aval (i, dptr, uptr); /* get data */ + if (reason != SCPE_OK) return reason; /* return if error */ + if (schptr && !test_search (sim_eval[0], schptr)) continue; + if (flag != EX_D) { + reason = ex_addr (ofile, flag, i, dptr, uptr); + if (reason > SCPE_OK) return reason; + if (sim_log && (ofile == stdout)) + ex_addr (sim_log, flag, i, dptr, uptr); } + if (flag != EX_E) { + reason = dep_addr (flag, cptr, i, dptr, uptr, reason); + if (reason > SCPE_OK) return reason; } + if (reason < SCPE_OK) i = i - (reason * dptr -> aincr); } +return SCPE_OK; +} + +/* Examine register routine + + Inputs: + ofile = output stream + val = current register value + flag = type of ex/mod command (ex, iex, idep) + rptr = pointer to register descriptor + idx = index + Outputs: + return = error status +*/ + +t_stat ex_reg (FILE *ofile, t_value val, int flag, REG *rptr, t_addr idx) +{ +int32 rdx; + +if (rptr == NULL) return SCPE_IERR; +if (rptr -> depth > 1) fprintf (ofile, "%s[%d]: ", rptr -> name, idx); +else fprintf (ofile, "%s: ", rptr -> name); +if (!(flag & EX_E)) return SCPE_OK; +GET_RADIX (rdx, rptr -> radix); +fprint_val (ofile, val, rdx, rptr -> width, rptr -> flags & REG_FMT); +if (flag & EX_I) fprintf (ofile, " "); +else fprintf (ofile, "\n"); +return SCPE_OK; +} + +/* Get register value + + Inputs: + rptr = pointer to register descriptor + idx = index + Outputs: + return = register value +*/ + +t_value get_rval (REG *rptr, int idx) +{ +size_t sz; +t_value val; +UNIT *uptr; + +sz = SZ_R (rptr); +if ((rptr -> depth > 1) && (rptr -> flags & REG_CIRC)) { + idx = idx + rptr -> qptr; + if (idx >= rptr -> depth) idx = idx - rptr -> depth; } +if ((rptr -> depth > 1) && (rptr -> flags & REG_UNIT)) { + uptr = ((UNIT *) rptr -> loc) + idx; + val = *((uint32 *) uptr); } +else if ((rptr -> depth > 1) && (sz == sizeof (uint8))) + val = *(((uint8 *) rptr -> loc) + idx); +else if ((rptr -> depth > 1) && (sz == sizeof (uint16))) + val = *(((uint16 *) rptr -> loc) + idx); +#if !defined (t_int64) +else val = *(((uint32 *) rptr -> loc) + idx); +#else +else if (sz <= sizeof (uint32)) + val = *(((uint32 *) rptr -> loc) + idx); +else val = *(((t_uint64 *) rptr -> loc) + idx); +#endif +val = (val >> rptr -> offset) & width_mask[rptr -> width]; +return val; +} + +/* Deposit register routine + + Inputs: + flag = type of deposit (normal/interactive) + cptr = pointer to input string + rptr = pointer to register descriptor + idx = index + Outputs: + return = error status +*/ + +t_stat dep_reg (int flag, char *cptr, REG *rptr, t_addr idx) +{ +t_stat r; +t_value val, mask; +int32 rdx; +char gbuf[CBUFSIZE]; + +if ((cptr == NULL) || (rptr == NULL)) return SCPE_IERR; +if (rptr -> flags & REG_RO) return SCPE_RO; +if (flag & EX_I) { + cptr = read_line (gbuf, CBUFSIZE, stdin); + if (sim_log) fprintf (sim_log, (cptr? "%s\n": "\n"), cptr); + if (cptr == NULL) return 1; /* force exit */ + if (*cptr == 0) return SCPE_OK; } /* success */ +mask = width_mask[rptr -> width]; +GET_RADIX (rdx, rptr -> radix); +val = get_uint (cptr, rdx, mask, &r); +if (r != SCPE_OK) return SCPE_ARG; +if ((rptr -> flags & REG_NZ) && (val == 0)) return SCPE_ARG; +put_rval (rptr, idx, val); +return SCPE_OK; +} + +/* Put register value + + Inputs: + rptr = pointer to register descriptor + idx = index + val = new value + mask = mask + Outputs: + none +*/ + +void put_rval (REG *rptr, int idx, t_value val) +{ +size_t sz; +t_value mask; +UNIT *uptr; + +#define PUT_RVAL(sz,rp,id,v,m) \ + *(((sz *) rp -> loc) + id) = \ + (*(((sz *) rp -> loc) + id) & \ + ~((m) << (rp) -> offset)) | ((v) << (rp) -> offset) + +if (rptr == sim_PC) sim_brk_npc (); +sz = SZ_R (rptr); +mask = width_mask[rptr -> width]; +if ((rptr -> depth > 1) && (rptr -> flags & REG_CIRC)) { + idx = idx + rptr -> qptr; + if (idx >= rptr -> depth) idx = idx - rptr -> depth; } +if ((rptr -> depth > 1) && (rptr -> flags & REG_UNIT)) { + uptr = ((UNIT *) rptr -> loc) + idx; + *((uint32 *) uptr) = + (*((uint32 *) uptr) & + ~(((uint32) mask) << rptr -> offset)) | + (((uint32) val) << rptr -> offset); } +else if ((rptr -> depth > 1) && (sz == sizeof (uint8))) + PUT_RVAL (uint8, rptr, idx, (uint32) val, (uint32) mask); +else if ((rptr -> depth > 1) && (sz == sizeof (uint16))) + PUT_RVAL (uint16, rptr, idx, (uint32) val, (uint32) mask); +#if !defined (t_int64) +else PUT_RVAL (uint32, rptr, idx, val, mask); +#else +else if (sz <= sizeof (uint32)) + PUT_RVAL (uint32, rptr, idx, (int32) val, (uint32) mask); +else PUT_RVAL (t_uint64, rptr, idx, val, mask); +#endif +return; +} + +/* Examine address routine + + Inputs: (sim_eval is an implicit argument) + ofile = output stream + flag = type of ex/mod command (ex, iex, idep) + addr = address to examine + dptr = pointer to device + uptr = pointer to unit + Outputs: + return = if >= 0, error status + if < 0, number of extra words retired +*/ + +t_stat ex_addr (FILE *ofile, int flag, t_addr addr, DEVICE *dptr, UNIT *uptr) +{ +t_stat reason; +int32 rdx; + +fprint_val (ofile, addr, dptr -> aradix, dptr -> awidth, PV_LEFT); +fprintf (ofile, ": "); +if (!(flag & EX_E)) return SCPE_OK; + +GET_RADIX (rdx, dptr -> dradix); +if ((reason = fprint_sym (ofile, addr, sim_eval, uptr, sim_switches)) > 0) + reason = fprint_val (ofile, sim_eval[0], rdx, dptr -> dwidth, PV_RZRO); +if (flag & EX_I) fprintf (ofile, " "); +else fprintf (ofile, "\n"); +return reason; +} + +/* Get address routine + + Inputs: + flag = type of ex/mod command (ex, iex, idep) + addr = address to examine + dptr = pointer to device + uptr = pointer to unit + Outputs: (sim_eval is an implicit output) + return = error status +*/ + +t_stat get_aval (t_addr addr, DEVICE *dptr, UNIT *uptr) +{ +int32 i; +t_value mask; +t_addr j, loc; +t_stat reason = SCPE_OK; +size_t sz; + +if ((dptr == NULL) || (uptr == NULL)) return SCPE_IERR; +mask = width_mask[dptr -> dwidth]; +for (i = 0; i < sim_emax; i++) sim_eval[i] = 0; +for (i = 0, j = addr; i < sim_emax; i++, j = j + dptr -> aincr) { + if (dptr -> examine != NULL) { + reason = dptr -> examine (&sim_eval[i], j, uptr, sim_switches); + if (reason != SCPE_OK) break; } + else { if (!(uptr -> flags & UNIT_ATT)) return SCPE_UNATT; + if ((uptr -> flags & UNIT_FIX) && (j >= uptr -> capac)) { + reason = SCPE_NXM; + break; } + sz = SZ_D (dptr); + loc = j / dptr -> aincr; + if (uptr -> flags & UNIT_BUF) { + SZ_LOAD (sz, sim_eval[i], uptr -> filebuf, loc); } + else { fseek (uptr -> fileref, sz * loc, SEEK_SET); + fxread (&sim_eval[i], sz, 1, uptr -> fileref); + if ((feof (uptr -> fileref)) && + !(uptr -> flags & UNIT_FIX)) { + reason = SCPE_EOF; + break; } + else if (ferror (uptr -> fileref)) { + clearerr (uptr -> fileref); + reason = SCPE_IOERR; + break; } } } + sim_eval[i] = sim_eval[i] & mask; } +if ((reason != SCPE_OK) && (i == 0)) return reason; +return SCPE_OK; +} + +/* Deposit address routine + + Inputs: + flag = type of deposit (normal/interactive) + cptr = pointer to input string + addr = address to examine + dptr = pointer to device + uptr = pointer to unit + dfltinc = value to return on cr input + Outputs: + return = if >= 0, error status + if < 0, number of extra words retired +*/ + +t_stat dep_addr (int flag, char *cptr, t_addr addr, DEVICE *dptr, + UNIT *uptr, int dfltinc) +{ +int32 i, count, rdx; +t_addr j, loc; +t_stat r, reason; +t_value mask; +size_t sz; +char gbuf[CBUFSIZE]; + +if (dptr == NULL) return SCPE_IERR; +if (flag & EX_I) { + cptr = read_line (gbuf, CBUFSIZE, stdin); + if (sim_log) fprintf (sim_log, (cptr? "%s\n": "\n"), cptr); + if (cptr == NULL) return 1; /* force exit */ + if (*cptr == 0) return dfltinc; } /* success */ +if (uptr -> flags & UNIT_RO) return SCPE_RO; /* read only? */ +mask = width_mask[dptr -> dwidth]; + +GET_RADIX (rdx, dptr -> dradix); +if ((reason = parse_sym (cptr, addr, uptr, sim_eval, sim_switches)) > 0) { + sim_eval[0] = get_uint (cptr, rdx, mask, &reason); + if (reason != SCPE_OK) return reason; } +count = 1 - reason; + +for (i = 0, j = addr; i < count; i++, j = j + dptr -> aincr) { + sim_eval[i] = sim_eval[i] & mask; + if (dptr -> deposit != NULL) { + r = dptr -> deposit (sim_eval[i], j, uptr, sim_switches); + if (r != SCPE_OK) return r; } + else { if (!(uptr -> flags & UNIT_ATT)) return SCPE_UNATT; + if ((uptr -> flags & UNIT_FIX) && (j >= uptr -> capac)) + return SCPE_NXM; + sz = SZ_D (dptr); + loc = j / dptr -> aincr; + if (uptr -> flags & UNIT_BUF) { + SZ_STORE (sz, sim_eval[i], uptr -> filebuf, loc); + if (loc >= uptr -> hwmark) uptr -> hwmark = loc + 1; } + else { fseek (uptr -> fileref, sz * loc, SEEK_SET); + fxwrite (sim_eval, sz, 1, uptr -> fileref); + if (ferror (uptr -> fileref)) { + clearerr (uptr -> fileref); + return SCPE_IOERR; } } } } +return reason; +} + +/* String processing routines + + read_line read line + + Inputs: + cptr = pointer to buffer + size = maximum size + stream = pointer to input stream + Outputs: + optr = pointer to first non-blank character + NULL if EOF +*/ + +char *read_line (char *cptr, int size, FILE *stream) +{ +char *tptr; + +cptr = fgets (cptr, size, stream); /* get cmd line */ +if (cptr == NULL) { + clearerr (stream); /* clear error */ + return NULL; } /* ignore EOF */ +for (tptr = cptr; tptr < (cptr + size); tptr++) /* remove cr */ + if (*tptr == '\n') *tptr = 0; +while (isspace (*cptr)) cptr++; /* absorb spaces */ +if (*cptr == ';') *cptr = 0; /* ignore comment */ +return cptr; +} + +/* get_glyph get next glyph (force upper case) + get_glyph_nc get next glyph (no conversion) + get_glyph_gen get next glyph (general case) + + Inputs: + iptr = pointer to input string + optr = pointer to output string + mchar = optional end of glyph character + flag = TRUE for convert to upper case (_gen only) + Outputs + result = pointer to next character in input string +*/ + +char *get_glyph_gen (char *iptr, char *optr, char mchar, t_bool uc) +{ +while ((isspace (*iptr) == 0) && (*iptr != 0) && (*iptr != mchar)) { + if (islower (*iptr) && uc) *optr = toupper (*iptr); + else *optr = *iptr; + iptr++; optr++; } +*optr = 0; +if (mchar && (*iptr == mchar)) iptr++; /* skip terminator */ +while (isspace (*iptr)) iptr++; /* absorb spaces */ +return iptr; +} + +char *get_glyph (char *iptr, char *optr, char mchar) +{ +return get_glyph_gen (iptr, optr, mchar, TRUE); +} + +char *get_glyph_nc (char *iptr, char *optr, char mchar) +{ +return get_glyph_gen (iptr, optr, mchar, FALSE); +} + +/* get_yn yes/no question + + Inputs: + cptr = pointer to question + deflt = default answer + Outputs: + result = true if yes, false if no +*/ + +t_stat get_yn (char *ques, t_stat deflt) +{ +char cbuf[CBUFSIZE], *cptr; + +printf ("%s ", ques); +cptr = read_line (cbuf, CBUFSIZE, stdin); +if ((cptr == NULL) || (*cptr == 0)) return deflt; +if ((*cptr == 'Y') || (*cptr == 'y')) return TRUE; +return FALSE; +} + +/* get_uint unsigned number + + Inputs: + cptr = pointer to input string + radix = input radix + max = maximum acceptable value + *status = pointer to error status + Outputs: + val = value +*/ + +t_value get_uint (char *cptr, int radix, t_value max, t_stat *status) +{ +t_value val; +char *tptr; + +val = strtotv (cptr, &tptr, radix); +if ((cptr == tptr) || (val > max) || (*tptr != 0)) *status = SCPE_ARG; +else *status = SCPE_OK; +return val; +} + +/* get_range range specification + + Inputs: + cptr = pointer to input string + *lo = pointer to low result + *hi = pointer to high result + aradix = address radix + max = default high value + term = terminating character, 0 if none + Outputs: + tptr = input pointer after processing + NULL if error +*/ + +char *get_range (char *cptr, t_addr *lo, t_addr *hi, int rdx, + t_addr max, char term) +{ +char *tptr; +t_addr hb; + +*lo = *hi = hb = 0; +if (max && strncmp (cptr, "ALL", strlen ("ALL")) == 0) { /* ALL? */ + tptr = cptr + strlen ("ALL"); + *hi = max; } +else { errno = 0; + *lo = strtoul (cptr, &tptr, rdx); /* get low */ + if (errno || (cptr == tptr)) return NULL; /* error? */ + if ((*tptr == '-') || (*tptr == ':') || (*tptr == '/')) { + if (*tptr == '/') hb = *lo; /* relative? */ + cptr = tptr + 1; + errno = 0; + *hi = hb + strtoul (cptr, &tptr, rdx); /* get high */ + if (errno || (cptr == tptr)) return NULL; + if (*lo > *hi) return NULL; } + else *hi = *lo; } +if (term && (*tptr++ != term)) return NULL; +return tptr; +} + +/* Find_device find device matching input string + + Inputs: + cptr = pointer to input string + Outputs: + result = pointer to device +*/ + +DEVICE *find_dev (char *cptr) +{ +int32 i; +DEVICE *dptr; + +for (i = 0; (dptr = sim_devices[i]) != NULL; i++) { + if (strcmp (cptr, dptr -> name) == 0) return dptr; } +return NULL; +} + +/* Find_unit find unit matching input string + + Inputs: + cptr = pointer to input string + uptr = pointer to unit pointer + Outputs: + result = pointer to device (null if no dev) + *iptr = pointer to unit (null if nx unit) +*/ + +DEVICE *find_unit (char *cptr, UNIT **uptr) +{ +int32 i, lenn, u; +t_stat r; +DEVICE *dptr; + +if (uptr == NULL) return NULL; /* arg error? */ +for (i = 0; (dptr = sim_devices[i]) != NULL; i++) { /* exact match? */ + if (strcmp (cptr, dptr -> name) == 0) { + if (qdisable (dptr)) return NULL; /* disabled? */ + *uptr = dptr -> units; /* unit 0 */ + return dptr; } } + +for (i = 0; (dptr = sim_devices[i]) != NULL; i++) { /* base + unit#? */ + lenn = strlen (dptr -> name); + if ((dptr -> numunits == 0) || /* no units? */ + (strncmp (cptr, dptr -> name, lenn) != 0)) continue; + if (qdisable (dptr)) return NULL; /* disabled? */ + cptr = cptr + lenn; /* skip devname */ + u = (int32) get_uint (cptr, 10, dptr -> numunits - 1, &r); + if (r != SCPE_OK) *uptr = NULL; /* error? */ + else *uptr = dptr -> units + u; + return dptr; } +return NULL; +} + +/* Find_dev_from_unit find device for unit + + Inputs: + uptr = pointer to unit + Outputs: + result = pointer to device +*/ + +DEVICE *find_dev_from_unit (UNIT *uptr) +{ +DEVICE *dptr; +int32 i, j; + +if (uptr == NULL) return NULL; +for (i = 0; (dptr = sim_devices[i]) != NULL; i++) { + for (j = 0; j < dptr -> numunits; j++) { + if (uptr == (dptr -> units + j)) return dptr; } } +return NULL; +} + +/* Test for disabled device */ + +t_bool qdisable (DEVICE *dptr) +{ +REG *rptr; + +rptr = find_reg ("*DEVENB", NULL, dptr); /* locate enable */ +if (rptr == NULL) return FALSE; /* found it? */ +return (get_rval (rptr, 0)? FALSE: TRUE); /* return flag */ +} + +/* find_reg_glob find globally unique register + + Inputs: + cptr = pointer to input string + optr = pointer to output pointer (can be null) + gdptr = pointer to global device + Outputs: + result = pointer to register, NULL if error + *optr = pointer to next character in input string + *gdptr = pointer to device where found +*/ + +REG *find_reg_glob (char *cptr, char **optr, DEVICE **gdptr) +{ +int32 i; +DEVICE *dptr; +REG *rptr, *srptr = NULL; + +for (i = 0; (dptr = sim_devices[i]) != 0; i++) { /* all dev */ + if (rptr = find_reg (cptr, optr, dptr)) { /* found? */ + if (srptr) return NULL; /* ambig? err */ + srptr = rptr; /* save reg */ + *gdptr = dptr; } } /* save unit */ +return srptr; +} + +/* find_reg find register matching input string + + Inputs: + cptr = pointer to input string + optr = pointer to output pointer (can be null) + dptr = pointer to device + Outputs: + result = pointer to register, NULL if error + *optr = pointer to next character in input string +*/ + +REG *find_reg (char *cptr, char **optr, DEVICE *dptr) +{ +char *tptr; +REG *rptr; + +if ((cptr == NULL) || (dptr == NULL) || + (dptr -> registers == NULL)) return NULL; +tptr = cptr; +do { tptr++; } + while (isalnum (*tptr) || (*tptr == '*') || (*tptr == '_')); +for (rptr = dptr -> registers; rptr -> name != NULL; rptr++) { + if (strncmp (cptr, rptr -> name, tptr - cptr) == 0) { + if (optr != NULL) *optr = tptr; + return rptr; } } +return NULL; +} + +/* get_switches get switches from input string + + Inputs: + cptr = pointer to input string + Outputs: + sw = switch bit mask + 0 if no switches, -1 if error +*/ + +int32 get_switches (char *cptr) +{ +int32 sw; + +if (*cptr != '-') return 0; +sw = 0; +for (cptr++; (isspace (*cptr) == 0) && (*cptr != 0); cptr++) { + if (isalpha (*cptr) == 0) return -1; + sw = sw | SWMASK (*cptr); } +return sw; +} + +t_bool match_ext (char *fnam, char *ext) +{ +char *fptr, *eptr; + +if ((fnam == NULL) || (ext == NULL)) return FALSE; +fptr = strrchr (fnam, '.'); +if (fptr == NULL) return FALSE; +for (fptr++, eptr = ext; *fptr; fptr++, eptr++) { + if (toupper (*fptr) != toupper (*eptr)) return FALSE; } +if (*eptr) return FALSE; +return TRUE; +} + +/* Get search specification + + Inputs: + cptr = pointer to input string + dptr = pointer to device + schptr = pointer to search table + Outputs: + return = NULL if error + schptr if valid search specification +*/ + +SCHTAB *get_search (char *cptr, DEVICE *dptr, SCHTAB *schptr) +{ +int c, logop, cmpop; +t_value logval, cmpval; +char *sptr, *tptr; +const char logstr[] = "|&^", cmpstr[] = "=!><"; + +if (*cptr == 0) return NULL; /* check for clause */ +for (logop = cmpop = -1; c = *cptr++; ) { /* loop thru clauses */ + if (sptr = strchr (logstr, c)) { /* check for mask */ + logop = sptr - logstr; + logval = strtotv (cptr, &tptr, dptr -> dradix); + if (cptr == tptr) return NULL; + cptr = tptr; } + else if (sptr = strchr (cmpstr, c)) { /* check for bool */ + cmpop = sptr - cmpstr; + if (*cptr == '=') { + cmpop = cmpop + strlen (cmpstr); + cptr++; } + cmpval = strtotv (cptr, &tptr, dptr -> dradix); + if (cptr == tptr) return NULL; + cptr = tptr; } + else return NULL; } /* end while */ +if (logop >= 0) { + schptr -> logic = logop; + schptr -> mask = logval; } +if (cmpop >= 0) { + schptr -> bool = cmpop; + schptr -> comp = cmpval; } +return schptr; +} + +/* Test value against search specification + + Inputs: + val = value to test + schptr = pointer to search table + Outputs: + return = 1 if value passes search criteria, 0 if not +*/ + +int test_search (t_value val, SCHTAB *schptr) +{ +if (schptr == NULL) return 0; +switch (schptr -> logic) { /* case on logical */ +case SCH_OR: + val = val | schptr -> mask; + break; +case SCH_AND: + val = val & schptr -> mask; + break; +case SCH_XOR: + val = val ^ schptr -> mask; + break; } +switch (schptr -> bool) { /* case on comparison */ +case SCH_E: case SCH_EE: + return (val == schptr -> comp); +case SCH_N: case SCH_NE: + return (val != schptr -> comp); +case SCH_G: + return (val > schptr -> comp); +case SCH_GE: + return (val >= schptr -> comp); +case SCH_L: + return (val < schptr -> comp); +case SCH_LE: + return (val <= schptr -> comp); } +return 0; +} + +/* Radix independent input/output package + + strtotv - general radix input routine + + Inputs: + inptr = string to convert + endptr = pointer to first unconverted character + radix = radix for input + Outputs: + value = converted value + + On an error, the endptr will equal the inptr. +*/ + +t_value strtotv (char *inptr, char **endptr, int radix) +{ +int nodigit; +t_value val; +int c, digit; + +*endptr = inptr; /* assume fails */ +if ((radix < 2) || (radix > 36)) return 0; +while (isspace (*inptr)) inptr++; /* bypass white space */ +val = 0; +nodigit = 1; +for (c = *inptr; isalnum(c); c = *++inptr) { /* loop through char */ + if (islower (c)) c = toupper (c); + if (isdigit (c)) digit = c - (int) '0'; /* digit? */ + else digit = c + 10 - (int) 'A'; /* no, letter */ + if (digit >= radix) return 0; /* valid in radix? */ + val = (val * radix) + digit; /* add to value */ + nodigit = 0; } +if (nodigit) return 0; /* no digits? */ +*endptr = inptr; /* result pointer */ +return val; +} + +/* fprint_val - general radix printing routine + + Inputs: + stream = stream designator + val = value to print + radix = radix to print + width = width to print + format = leading zeroes format + Outputs: + status = error status +*/ + +t_stat fprint_val (FILE *stream, t_value val, int radix, + int width, int format) +{ +#define MAX_WIDTH ((int) (CHAR_BIT * sizeof (t_value))) +t_value owtest, wtest; +int32 d, digit, ndigits; +char dbuf[MAX_WIDTH + 1]; + +for (d = 0; d < MAX_WIDTH; d++) dbuf[d] = (format == PV_RZRO)? '0': ' '; +dbuf[MAX_WIDTH] = 0; +d = MAX_WIDTH; +do { d = d - 1; + digit = (int32) (val % (unsigned) radix); + val = val / (unsigned) radix; + dbuf[d] = (digit <= 9)? '0' + digit: 'A' + (digit - 10); + } while ((d > 0) && (val != 0)); + +if (format != PV_LEFT) { + wtest = owtest = radix; + ndigits = 1; + while ((wtest < width_mask[width]) && (wtest >= owtest)) { + owtest = wtest; + wtest = wtest * radix; + ndigits = ndigits + 1; } + if ((MAX_WIDTH - ndigits) < d) d = MAX_WIDTH - ndigits; } +if (fputs (&dbuf[d], stream) == EOF) return SCPE_IOERR; +return SCPE_OK; +} + +/* Event queue package + + sim_activate add entry to event queue + sim_cancel remove entry from event queue + sim_process_event process entries on event queue + sim_is_active see if entry is on event queue + sim_atime return absolute time for an entry + sim_gtime return global time + sim_qcount return event queue entry count + + Asynchronous events are set up by queueing a unit data structure + to the event queue with a timeout (in simulator units, relative + to the current time). Each simulator 'times' these events by + counting down interval counter sim_interval. When this reaches + zero the simulator calls sim_process_event to process the event + and to see if further events need to be processed, or sim_interval + reset to count the next one. + + The event queue is maintained in clock order; entry timeouts are + RELATIVE to the time in the previous entry. + + sim_process_event - process event + + Inputs: + none + Outputs: + reason reason code returned by any event processor, + or 0 (SCPE_OK) if no exceptions +*/ + +t_stat sim_process_event (void) +{ +UNIT *uptr; +t_stat reason; + +if (stop_cpu) return SCPE_STOP; /* stop CPU? */ +if (sim_clock_queue == NULL) { /* queue empty? */ + UPDATE_SIM_TIME (noqueue_time); /* update sim time */ + sim_interval = noqueue_time = NOQUEUE_WAIT; /* flag queue empty */ + return SCPE_OK; } +UPDATE_SIM_TIME (sim_clock_queue -> time); /* update sim time */ +do { uptr = sim_clock_queue; /* get first */ + sim_clock_queue = uptr -> next; /* remove first */ + uptr -> next = NULL; /* hygiene */ + uptr -> time = 0; + if (sim_clock_queue != NULL) sim_interval = sim_clock_queue -> time; + else sim_interval = noqueue_time = NOQUEUE_WAIT; + if (uptr -> action != NULL) reason = uptr -> action (uptr); + else reason = SCPE_OK; + } while ((reason == SCPE_OK) && (sim_interval == 0)); + +/* Empty queue forces sim_interval != 0 */ + +return reason; +} + +/* sim_activate - activate (queue) event + + Inputs: + uptr = pointer to unit + event_time = relative timeout + Outputs: + reason = result (SCPE_OK if ok) +*/ + +t_stat sim_activate (UNIT *uptr, int32 event_time) +{ +UNIT *cptr, *prvptr; +int32 accum; + +if (event_time < 0) return SCPE_IERR; +if (sim_is_active (uptr)) return SCPE_OK; /* already active? */ +if (sim_clock_queue == NULL) { UPDATE_SIM_TIME (noqueue_time); } +else { UPDATE_SIM_TIME (sim_clock_queue -> time); } /* update sim time */ + +prvptr = NULL; +accum = 0; +for (cptr = sim_clock_queue; cptr != NULL; cptr = cptr -> next) { + if (event_time < (accum + cptr -> time)) break; + accum = accum + cptr -> time; + prvptr = cptr; } +if (prvptr == NULL) { /* insert at head */ + cptr = uptr -> next = sim_clock_queue; + sim_clock_queue = uptr; } +else { cptr = uptr -> next = prvptr -> next; /* insert at prvptr */ + prvptr -> next = uptr; } +uptr -> time = event_time - accum; +if (cptr != NULL) cptr -> time = cptr -> time - uptr -> time; +sim_interval = sim_clock_queue -> time; +return SCPE_OK; +} + +/* sim_cancel - cancel (dequeue) event + + Inputs: + uptr = pointer to unit + Outputs: + reason = result (SCPE_OK if ok) + +*/ + +t_stat sim_cancel (UNIT *uptr) +{ +UNIT *cptr, *nptr; + +if (sim_clock_queue == NULL) return SCPE_OK; +UPDATE_SIM_TIME (sim_clock_queue -> time); /* update sim time */ +nptr = NULL; +if (sim_clock_queue == uptr) nptr = sim_clock_queue = uptr -> next; +else { for (cptr = sim_clock_queue; cptr != NULL; cptr = cptr -> next) { + if (cptr -> next == uptr) { + nptr = cptr -> next = uptr -> next; + break; } } } /* end queue scan */ +if (nptr != NULL) nptr -> time = nptr -> time + uptr -> time; +uptr -> next = NULL; /* hygiene */ +uptr -> time = 0; +if (sim_clock_queue != NULL) sim_interval = sim_clock_queue -> time; +else sim_interval = noqueue_time = NOQUEUE_WAIT; +return SCPE_OK; +} + +/* sim_is_active - test for entry in queue, return activation time + + Inputs: + uptr = pointer to unit + Outputs: + result = absolute activation time + 1, 0 if inactive +*/ + +int32 sim_is_active (UNIT *uptr) +{ +UNIT *cptr; +int32 accum; + +accum = 0; +for (cptr = sim_clock_queue; cptr != NULL; cptr = cptr -> next) { + accum = accum + cptr -> time; + if (cptr == uptr) return accum + 1; } +return 0; +} + +/* sim_gtime - return global time + sim_grtime - return global time with rollover + + Inputs: none + Outputs: + time = global time +*/ + +double sim_gtime (void) +{ +if (sim_clock_queue == NULL) { UPDATE_SIM_TIME (noqueue_time); } +else { UPDATE_SIM_TIME (sim_clock_queue -> time); } +return sim_time; +} + +uint32 sim_grtime (void) +{ +if (sim_clock_queue == NULL) { UPDATE_SIM_TIME (noqueue_time); } +else { UPDATE_SIM_TIME (sim_clock_queue -> time); } +return sim_rtime; +} + +/* sim_qcount - return queue entry count + + Inputs: none + Outputs: + count = number of entries on the queue +*/ + +int32 sim_qcount (void) +{ +int32 cnt; +UNIT *uptr; + +cnt = 0; +for (uptr = sim_clock_queue; uptr != NULL; uptr = uptr -> next) cnt++; +return cnt; +} + +/* Endian independent binary I/O package + + For consistency, all binary data read and written by the simulator + is stored in little endian data order. That is, in a multi-byte + data item, the bytes are written out right to left, low order byte + to high order byte. On a big endian host, data is read and written + from high byte to low byte. Consequently, data written on a little + endian system must be byte reversed to be usable on a big endian + system, and vice versa. + + These routines are analogs of the standard C runtime routines + fread and fwrite. If the host is little endian, or the data items + are size char, then the calls are passed directly to fread or + fwrite. Otherwise, these routines perform the necessary byte swaps + using an intermediate buffer. +*/ + +size_t fxread (void *bptr, size_t size, size_t count, FILE *fptr) +{ +size_t c, j, nelem, nbuf, lcnt, total; +int32 i, k; +unsigned char *sptr, *dptr; + +if (sim_end || (size == sizeof (char))) + return fread (bptr, size, count, fptr); +if ((size == 0) || (count == 0)) return 0; +nelem = FLIP_SIZE / size; /* elements in buffer */ +nbuf = count / nelem; /* number buffers */ +lcnt = count % nelem; /* count in last buf */ +if (lcnt) nbuf = nbuf + 1; +else lcnt = nelem; +total = 0; +dptr = bptr; /* init output ptr */ +for (i = nbuf; i > 0; i--) { + c = fread (sim_flip, size, (i == 1? lcnt: nelem), fptr); + if (c == 0) return total; + total = total + c; + for (j = 0, sptr = sim_flip; j < c; j++) { + for (k = size - 1; k >= 0; k--) *(dptr + k) = *sptr++; + dptr = dptr + size; } } +return total; +} + +size_t fxwrite (void *bptr, size_t size, size_t count, FILE *fptr) +{ +size_t c, j, nelem, nbuf, lcnt, total; +int32 i, k; +unsigned char *sptr, *dptr; + +if (sim_end || (size == sizeof (char))) + return fwrite (bptr, size, count, fptr); +if ((size == 0) || (count == 0)) return 0; +nelem = FLIP_SIZE / size; /* elements in buffer */ +nbuf = count / nelem; /* number buffers */ +lcnt = count % nelem; /* count in last buf */ +if (lcnt) nbuf = nbuf + 1; +else lcnt = nelem; +total = 0; +sptr = bptr; /* init input ptr */ +for (i = nbuf; i > 0; i--) { + c = (i == 1)? lcnt: nelem; + for (j = 0, dptr = sim_flip; j < c; j++) { + for (k = size - 1; k >= 0; k--) *(dptr + k) = *sptr++; + dptr = dptr + size; } + c = fwrite (sim_flip, size, c, fptr); + if (c == 0) return total; + total = total + c; } +return total; +} + +/* OS independent clock calibration package + + sim_rtc_init initialize calibration + sim_rtc_calb calibrate clock +*/ + +static int32 rtc_ticks[SIM_NTIMERS] = { 0 }; /* ticks */ +static uint32 rtc_rtime[SIM_NTIMERS] = { 0 }; /* real time */ +static uint32 rtc_vtime[SIM_NTIMERS] = { 0 }; /* virtual time */ +static uint32 rtc_nxintv[SIM_NTIMERS] = { 0 }; /* next interval */ +static int32 rtc_based[SIM_NTIMERS] = { 0 }; /* base delay */ +static int32 rtc_currd[SIM_NTIMERS] = { 0 }; /* current delay */ +extern t_bool rtc_avail; + +int32 sim_rtcn_init (int32 time, int32 tmr) +{ +if ((tmr < 0) || (tmr > SIM_NTIMERS)) return time; +rtc_rtime[tmr] = sim_os_msec (); +rtc_vtime[tmr] = rtc_rtime[tmr]; +rtc_nxintv[tmr] = 1000; +rtc_ticks[tmr] = 0; +rtc_based[tmr] = time; +rtc_currd[tmr] = time; +return time; +} + +int32 sim_rtcn_calb (int32 ticksper, int32 tmr) +{ +uint32 new_rtime, delta_rtime; +int32 delta_vtime; + +if ((tmr < 0) || (tmr > SIM_NTIMERS)) return 10000; +rtc_ticks[tmr] = rtc_ticks[tmr] + 1; /* count ticks */ +if (rtc_ticks[tmr] < ticksper) return rtc_currd[tmr]; /* 1 sec yet? */ +rtc_ticks[tmr] = 0; /* reset ticks */ +if (!rtc_avail) return rtc_currd[tmr]; /* no timer? */ +new_rtime = sim_os_msec (); /* wall time */ +delta_rtime = new_rtime - rtc_rtime[tmr]; /* elapsed wtime */ +if (delta_rtime == 0) return rtc_currd[tmr]; /* can't calibr */ +rtc_based[tmr] = (int32) (((double) rtc_based[tmr] * (double) rtc_nxintv[tmr]) / + ((double) delta_rtime)); /* new base rate */ +rtc_rtime[tmr] = new_rtime; /* adv wall time */ +rtc_vtime[tmr] = rtc_vtime[tmr] + 1000; /* adv sim time */ +delta_vtime = rtc_vtime[tmr] - rtc_rtime[tmr]; /* gap */ +if (delta_vtime > SIM_TMAX) delta_vtime = SIM_TMAX; /* limit gap */ +else if (delta_vtime < -SIM_TMAX) delta_vtime = -SIM_TMAX; +rtc_nxintv[tmr] = 1000 + delta_vtime; /* next wtime */ +rtc_currd[tmr] = (int32) (((double) rtc_based[tmr] * (double) rtc_nxintv[tmr]) / + 1000.0); /* next delay */ +return rtc_currd[tmr]; +} + +/* Prior interfaces - default to timer 0 */ + +int32 sim_rtc_init (int32 time) +{ +return sim_rtcn_init (time, 0); +} + +int32 sim_rtc_calb (int32 ticksper) +{ +return sim_rtcn_calb (ticksper, 0); +} + +/* Breakpoint package. This module replaces the VM-implemented one + instruction breakpoint capability. + + Breakpoints are stored in table sim_brk_tab, which is ordered by address for + efficient binary searching. A breakpoint consists of a four entry structure: + + addr address of the breakpoint + type types of breakpoints set on the address + a bit mask representing letters A-Z + cnt number of iterations before breakp is taken + action pointer to list of commands to be executed + when break is taken + + sim_brk_summ is a summary of the types of breakpoints that are currently set (it + is the bitwise OR of all the type fields). A simulator need only check for + a breakpoint of type X if bit SWMASK('X') is set in sim_brk_sum. + + The package contains the following public routines: + + sim_brk_init initialize + sim_brk_pchg PC change + sim_brk_set set breakpoint + sim_brk_clr clear breakpoint + sim_brk_clrall clear all breakpoints + sim_brk_show show breakpoint + sim_brk_showall show all breakpoints + sim_brk_test test for breakpoint + sim_brk_npc PC has been changed + + Initialize breakpoint system. If simulator has filled in sim_brk_types, + allocate an initial breakpoint table, otherwise, allocate a minimal table. +*/ + +t_stat sim_brk_init (void) +{ +if (sim_brk_types) sim_brk_lnt = SIM_BRK_INILNT; +else sim_brk_lnt = 1; +sim_brk_tab = calloc (sim_brk_lnt, sizeof (BRKTAB)); +if (sim_brk_tab == NULL) return SCPE_MEM; +sim_brk_ent = sim_brk_ins = 0; +return SCPE_OK; +} + +/* Search for a breakpoint in the sorted breakpoint table */ + +BRKTAB *sim_brk_fnd (t_addr loc) +{ +int32 lo, hi, p; +BRKTAB *bp; + +if (sim_brk_ent == 0) { /* table empty? */ + sim_brk_ins = 0; /* insrt at head */ + return NULL; } /* sch fails */ +lo = 0; /* initial bounds */ +hi = sim_brk_ent - 1; +do { p = (lo + hi) >> 1; /* probe */ + bp = sim_brk_tab + p; /* table addr */ + if (loc == bp -> addr) return bp; /* match? */ + else if (loc < bp -> addr) hi = p - 1; /* go down? p is upper */ + else lo = p + 1; } /* go up? p is lower */ +while (lo <= hi); +if (loc < bp -> addr) sim_brk_ins = p; /* insrt before or */ +else sim_brk_ins = p + 1; /* after last sch */ +return NULL; +} + +/* Insert a breakpoint */ + +BRKTAB *sim_brk_new (t_addr loc) +{ +BRKTAB *bp; + +if (sim_brk_ins < 0) return NULL; +if (sim_brk_ent >= sim_brk_lnt) return NULL; +if (sim_brk_ins != sim_brk_ent) { /* move needed? */ + for (bp = sim_brk_tab + sim_brk_ent; + bp > sim_brk_tab + sim_brk_ins; bp--) + *bp = *(bp - 1); } +bp = sim_brk_tab + sim_brk_ins; +bp -> addr = loc; +bp -> typ = 0; +bp -> cnt = 0; +bp -> act = NULL; +sim_brk_ent = sim_brk_ent + 1; +return bp; +} + +/* Set a breakpoint of type sw */ + +t_stat sim_brk_set (t_addr loc, int32 sw, int32 ncnt) +{ +BRKTAB *bp; + +if (sw == 0) sw = sim_brk_dflt; +if ((sim_brk_types & sw) == 0) return SCPE_NOFNC; +bp = sim_brk_fnd (loc); +if (!bp) bp = sim_brk_new (loc); +if (!bp) return SCPE_MEM; +bp -> typ = sw; +bp -> cnt = ncnt; +sim_brk_summ = sim_brk_summ | sw; +return SCPE_OK; +} + +/* Clear a breakpoint */ + +t_stat sim_brk_clr (t_addr loc, int32 sw) +{ +BRKTAB *bp = sim_brk_fnd (loc); + +if (!bp) return SCPE_OK; +if (sw == 0) sw = SIM_BRK_ALLTYP; +bp -> typ = bp -> typ & ~sw; +if (bp -> typ) return SCPE_OK; +for ( ; bp < (sim_brk_tab + sim_brk_ent - 1); bp++) + *bp = *(bp + 1); +sim_brk_ent = sim_brk_ent - 1; +sim_brk_summ = 0; +for (bp = sim_brk_tab; bp < (sim_brk_tab + sim_brk_ent); bp++) + sim_brk_summ = sim_brk_summ | bp -> typ; +return SCPE_OK; +} + +/* Clear all breakpoints */ + +t_stat sim_brk_clrall (int32 sw) +{ +BRKTAB *bp; + +if (sw == 0) sw = SIM_BRK_ALLTYP; +if ((sim_brk_summ & ~sw) == 0) sim_brk_ent = sim_brk_summ = 0; +else { for (bp = sim_brk_tab; bp < (sim_brk_tab + sim_brk_ent); bp++) { + if (bp -> typ & sw) sim_brk_clr (bp -> addr, sw); } } +return SCPE_OK; +} + +/* Show a breakpoint */ + +t_stat sim_brk_show (FILE *st, t_addr loc, int32 sw) +{ +BRKTAB *bp = sim_brk_fnd (loc); +DEVICE *dptr; +int32 i, any; + +if (sw == 0) sw = SIM_BRK_ALLTYP; +if (!bp || (!(bp -> typ & sw))) return SCPE_OK; +dptr = sim_devices[0]; +if (dptr == NULL) return SCPE_OK; +fprint_val (st, loc, dptr -> aradix, dptr -> awidth, PV_LEFT); +fprintf (st, ":\t"); +for (i = any = 0; i < 26; i++) { + if ((bp -> typ >> i) & 1) { + if (any) fprintf (st, ", "); + fputc (i + 'A', st); + any = 1; } } +if (bp -> cnt > 0) fprintf (st, " [%d]", bp -> cnt); +fprintf (st, "\n"); +return SCPE_OK; +} + +/* Show all breakpoints */ + +t_stat sim_brk_showall (FILE *st, int32 sw) +{ +BRKTAB *bp; + +if (sw == 0) sw = SIM_BRK_ALLTYP; +for (bp = sim_brk_tab; bp < (sim_brk_tab + sim_brk_ent); bp++) { + if (bp -> typ & sw) sim_brk_show (st, bp -> addr, sw); } +return SCPE_OK; +} + +/* Test for breakpoint */ + +t_bool sim_brk_test (t_addr loc, int32 btyp) +{ +BRKTAB *bp; + +if ((bp = sim_brk_fnd (loc)) && + (btyp & bp -> typ) && + (!sim_brk_pend || (loc != sim_brk_ploc)) && + (--(bp -> cnt) <= 0)) { + bp -> cnt = 0; + sim_brk_ploc = loc; + sim_brk_pend = TRUE; + return TRUE; } +sim_brk_pend = FALSE; +return FALSE; +} + +/* New PC */ + +void sim_brk_npc (void) +{ +sim_brk_pend = FALSE; +return; +} + +/* BLK - added the following routines */ + +/* panic - report fatal internal programming error */ + +void panic (char *msg) +{ + fprintf(stderr, "%s\n", msg); + exit(1); +} + +/* read_cmdline - read command from stdin with allowance for simulated console button input */ + +#ifdef GUI_SUPPORT + +#ifndef MIN +# define MIN(a,b) (((a) <= (b)) ? (a) : (b)) +#endif + +#ifdef WIN32 + + /* win32 - use a separate thread to read command lines so the GUI + * can insert commands as well */ + + #include + + static HANDLE hCmdThread = NULL; + static DWORD iCmdThreadID = 0; + static HANDLE hCmdReadEvent = NULL; + static HANDLE hCmdReadyEvent = NULL; + static BOOL scp_stuffed = FALSE, scp_reading = FALSE; + static char cmdbuffer[256]; + + /* CmdThread - separate thread to read commands from stdin upon request */ + + static DWORD WINAPI CmdThread (LPVOID arg) + { + for (;;) { + WaitForSingleObject(hCmdReadEvent, INFINITE); /* wait for request */ + read_line(cmdbuffer, sizeof(cmdbuffer), stdin); /* read one line */ + scp_stuffed = FALSE; /* say how we got it */ + SetEvent(hCmdReadyEvent); /* notify main thread a line is ready */ + } + return 0; + } + + char *read_cmdline (char *ptr, int size) + { + char *cptr; + + if (hCmdThread == NULL) { /* set up command-reading thread */ + if ((hCmdReadEvent = CreateEvent(NULL, FALSE, FALSE, NULL)) == NULL) + panic("Can't create command line read event"); + + if ((hCmdReadyEvent = CreateEvent(NULL, FALSE, FALSE, NULL)) == NULL) + panic("Can't create command line ready event"); + /* start up the command thread */ + if ((hCmdThread = CreateThread(NULL, 0, CmdThread, NULL, 0, &iCmdThreadID)) == NULL) + panic("Unable to create command line reading thread"); + } + + scp_reading = TRUE; + + SetEvent(hCmdReadEvent); /* let read thread get one line */ + WaitForSingleObject(hCmdReadyEvent, INFINITE); /* wait for read thread or GUI to respond */ + + scp_reading = FALSE; + + strncpy(ptr, cmdbuffer, MIN(size, sizeof(cmdbuffer))); /* copy line to caller's buffer */ + + for (cptr = ptr; isspace(*cptr); cptr++) /* absorb spaces */ + ; + + if (scp_stuffed) { /* stuffed command needs to be echoed */ + printf("%s\n", cptr); + if (sim_log) fprintf(sim_log, "%s\n", cptr); + } + + return cptr; + } + + /* stuff_cmd - force a command into the read_cmdline output buffer. Called asynchronously by GUI */ + + void stuff_cmd (char *cmd) + { + strcpy(cmdbuffer, cmd); /* save the string */ + scp_stuffed = TRUE; /* note where it came from */ + SetEvent(hCmdReadyEvent); /* notify main thread a line is ready */ + } + + /* remark_cmd - print a remark from inside a command processor. This routine takes + * into account the possiblity that the command might have been stuffed, in which + * case the sim> prompt needs to be reprinted. + */ + + void remark_cmd (char *remark) + { + printf("%s\n", remark); + if (sim_log) fprintf(sim_log, "%s\n", remark); + if (scp_reading) { + printf("sim> "); + if (sim_log) fprintf(sim_log, "sim> "); + } + } + +#else /* ifdef WIN32 */ + + /* GUI support is not currently implemented under other operating systems */ + + char *read_cmdline (char *ptr, int size) + { + return read_line(ptr, size, stdin); + } + + void stuff_cmd (char *cmd) + { + printf("Sorry, couldn't stuff \"%s\"\n", cmd); + } + + void remark_cmd (char *remark) + { + printf("%s\n", remark); + if (sim_log) fprintf(sim_log, "%s\n", remark); + } +#endif /* ifdef WIN32 */ + +#else /* ifdef GUI_SUPPORT */ + +/* read_cmdline - w/o GUI support, just read a line from stdin */ + +char *read_cmdline (char *ptr, int size) +{ + return read_line(ptr, size, stdin); +} + +#endif /* ifdef GUI_SUPPORT */ diff --git a/Ibm1130/sim_defs.h b/Ibm1130/sim_defs.h new file mode 100644 index 00000000..23f95e20 --- /dev/null +++ b/Ibm1130/sim_defs.h @@ -0,0 +1,373 @@ +/* sim_defs.h: simulator definitions + + Copyright (c) 1993-2002, Robert M Supnik + + Permission is hereby granted, free of charge, to any person obtaining a + copy of this software and associated documentation files (the "Software"), + to deal in the Software without restriction, including without limitation + the rights to use, copy, modify, merge, publish, distribute, sublicense, + and/or sell copies of the Software, and to permit persons to whom the + Software is furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + ROBERT M SUPNIK BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + Except as contained in this notice, the name of Robert M Supnik shall not + be used in advertising or otherwise to promote the sale, use or other dealings + in this Software without prior written authorization from Robert M Supnik. + + 30-Dec-01 RMS Generalized timer package, added circular arrays + 07-Dec-01 RMS Added breakpoint package + 01-Dec-01 RMS Added read-only unit support, extended SET/SHOW features, + improved error messages + 24-Nov-01 RMS Added unit-based registers + 27-Sep-01 RMS Added queue count prototype + 17-Sep-01 RMS Removed multiple console support + 07-Sep-01 RMS Removed conditional externs on function prototypes + 31-Aug-01 RMS Changed int64 to t_int64 for Windoze + 17-Jul-01 RMS Added additional function prototypes + 27-May-01 RMS Added multiple console support + 15-May-01 RMS Increased string buffer size + 25-Feb-01 RMS Revisions for V2.6 + 15-Oct-00 RMS Editorial revisions for V2.5 + 11-Jul-99 RMS Added unsigned int data types + 14-Apr-99 RMS Converted t_addr to unsigned + 04-Oct-98 RMS Additional definitions for V2.4 + + The interface between the simulator control package (SCP) and the + simulator consists of the following routines and data structures + + sim_name simulator name string + sim_devices[] array of pointers to simulated devices + sim_PC pointer to saved PC register descriptor + sim_interval simulator interval to next event + sim_stop_messages[] array of pointers to stop messages + sim_instr() instruction execution routine + sim_load() binary loader routine + sim_emax maximum number of words in an instruction + + In addition, the simulator must supply routines to print and parse + architecture specific formats + + print_sym print symbolic output + parse_sym parse symbolic input +*/ + +#include +#include +#include +#include +#include +#include + +#ifndef TRUE +#define TRUE 1 +#define FALSE 0 +#endif + +/* Length specific integer declarations */ + +#define int8 char +#define int16 short +#define int32 int +typedef int t_stat; /* status */ +typedef int t_bool; /* boolean */ +typedef unsigned int8 uint8; +typedef unsigned int16 uint16; +typedef unsigned int32 uint32, t_addr; /* address */ +#if defined (USE_INT64) && defined (_WIN32) +#define t_int64 __int64 /* for Windows */ +#elif defined (USE_INT64) && defined (VMS) && defined (__ALPHA) +#define t_int64 __int64 /* for AVMS */ +#elif defined (USE_INT64) && defined (__ALPHA) && defined (__unix__) +#define t_int64 long /* for DUNIX */ +#elif defined (USE_INT64) +#define t_int64 long long /* for GCC */ +#endif +#if defined (t_int64) +typedef unsigned t_int64 t_uint64, t_value; /* value */ +typedef t_int64 t_svalue; /* signed value */ +#else +typedef unsigned int32 t_value; +typedef int32 t_svalue; +#endif + +/* System independent definitions */ + +typedef int32 t_mtrlnt; /* magtape rec lnt */ +#define MTRF(x) ((x) & (1u << 31)) /* record error flg */ +#define MTRL(x) ((x) & ((1u << 31) - 1)) /* record length */ +#define FLIP_SIZE (1 << 16) /* flip buf size */ +#if !defined (PATH_MAX) /* usually in limits */ +#define PATH_MAX 512 +#endif +#define CBUFSIZE (128 + PATH_MAX) /* string buf size */ +#define CONS_SIZE 4096 /* console buffer */ + +/* Simulator status codes + + 0 ok + 1 - (SCPE_BASE - 1) simulator specific + SCPE_BASE - n general +*/ + +#define SCPE_OK 0 /* normal return */ +#define SCPE_BASE 32 /* base for messages */ +#define SCPE_NXM (SCPE_BASE + 0) /* nxm */ +#define SCPE_UNATT (SCPE_BASE + 1) /* no file */ +#define SCPE_IOERR (SCPE_BASE + 2) /* I/O error */ +#define SCPE_CSUM (SCPE_BASE + 3) /* loader cksum */ +#define SCPE_FMT (SCPE_BASE + 4) /* loader format */ +#define SCPE_NOATT (SCPE_BASE + 5) /* not attachable */ +#define SCPE_OPENERR (SCPE_BASE + 6) /* open error */ +#define SCPE_MEM (SCPE_BASE + 7) /* alloc error */ +#define SCPE_ARG (SCPE_BASE + 8) /* argument error */ +#define SCPE_STEP (SCPE_BASE + 9) /* step expired */ +#define SCPE_UNK (SCPE_BASE + 10) /* unknown command */ +#define SCPE_RO (SCPE_BASE + 11) /* read only */ +#define SCPE_INCOMP (SCPE_BASE + 12) /* incomplete */ +#define SCPE_STOP (SCPE_BASE + 13) /* sim stopped */ +#define SCPE_EXIT (SCPE_BASE + 14) /* sim exit */ +#define SCPE_TTIERR (SCPE_BASE + 15) /* console tti err */ +#define SCPE_TTOERR (SCPE_BASE + 16) /* console tto err */ +#define SCPE_EOF (SCPE_BASE + 17) /* end of file */ +#define SCPE_REL (SCPE_BASE + 18) /* relocation error */ +#define SCPE_NOPARAM (SCPE_BASE + 19) /* no parameters */ +#define SCPE_ALATT (SCPE_BASE + 20) /* already attached */ +#define SCPE_TIMER (SCPE_BASE + 21) /* hwre timer err */ +#define SCPE_SIGERR (SCPE_BASE + 22) /* signal err */ +#define SCPE_TTYERR (SCPE_BASE + 23) /* tty setup err */ +#define SCPE_SUB (SCPE_BASE + 24) /* subscript err */ +#define SCPE_NOFNC (SCPE_BASE + 25) /* func not imp */ +#define SCPE_UDIS (SCPE_BASE + 26) /* unit disabled */ +#define SCPE_LOGON (SCPE_BASE + 27) /* logging enabled */ +#define SCPE_LOGOFF (SCPE_BASE + 28) /* logging disabled */ +#define SCPE_NORO (SCPE_BASE + 29) /* rd only not ok */ +#define SCPE_INVSW (SCPE_BASE + 30) /* invalid switch */ +#define SCPE_MISVAL (SCPE_BASE + 31) /* missing value */ +#define SCPE_2FARG (SCPE_BASE + 32) /* too few arguments */ +#define SCPE_2MARG (SCPE_BASE + 33) /* too many arguments */ +#define SCPE_NXDEV (SCPE_BASE + 34) /* nx device */ +#define SCPE_NXUN (SCPE_BASE + 35) /* nx unit */ +#define SCPE_NXREG (SCPE_BASE + 36) /* nx register */ +#define SCPE_NXPAR (SCPE_BASE + 37) /* nx parameter */ +#define SCPE_NEST (SCPE_BASE + 38) /* nested DO */ +#define SCPE_IERR (SCPE_BASE + 39) /* internal error */ +#define SCPE_KFLAG 01000 /* tti data flag */ + +/* Print value format codes */ + +#define PV_RZRO 0 /* right, zero fill */ +#define PV_RSPC 1 /* right, space fill */ +#define PV_LEFT 2 /* left justify */ + +/* Default timing parameters */ + +#define KBD_POLL_WAIT 5000 /* keyboard poll */ +#define SERIAL_IN_WAIT 100 /* serial in time */ +#define SERIAL_OUT_WAIT 10 /* serial output */ +#define NOQUEUE_WAIT 10000 /* min check time */ + +/* Convert switch letter to bit mask */ + +#define SWMASK(x) (1u << (((int) (x)) - ((int) 'A'))) + +/* String match */ + +#define MATCH_CMD(ptr,cmd) strncmp ((ptr), (cmd), strlen (ptr)) + +/* Device data structure */ + +struct device { + char *name; /* name */ + struct unit *units; /* units */ + struct reg *registers; /* registers */ + struct mtab *modifiers; /* modifiers */ + int32 numunits; /* #units */ + int32 aradix; /* address radix */ + int32 awidth; /* address width */ + int32 aincr; /* addr increment */ + int32 dradix; /* data radix */ + int32 dwidth; /* data width */ + t_stat (*examine)(); /* examine routine */ + t_stat (*deposit)(); /* deposit routine */ + t_stat (*reset)(); /* reset routine */ + t_stat (*boot)(); /* boot routine */ + t_stat (*attach)(); /* attach routine */ + t_stat (*detach)(); /* detach routine */ +}; + +/* Unit data structure + + Parts of the unit structure are device specific, that is, they are + not referenced by the simulator control package and can be freely + used by device simulators. Fields starting with 'buf', and flags + starting with 'UF', are device specific. The definitions given here + are for a typical sequential device. +*/ + +struct unit { + struct unit *next; /* next active */ + t_stat (*action)(); /* action routine */ + char *filename; /* open file name */ + FILE *fileref; /* file reference */ + void *filebuf; /* memory buffer */ + t_addr hwmark; /* high water mark */ + int32 time; /* time out */ + int32 flags; /* flags */ + t_addr capac; /* capacity */ + t_addr pos; /* file position */ + int32 buf; /* buffer */ + int32 wait; /* wait */ + int32 u3; /* device specific */ + int32 u4; /* device specific */ +}; + +/* Unit flags */ + +#define UNIT_ATTABLE 000001 /* attachable */ +#define UNIT_RO 000002 /* read only */ +#define UNIT_FIX 000004 /* fixed capacity */ +#define UNIT_SEQ 000010 /* sequential */ +#define UNIT_ATT 000020 /* attached */ +#define UNIT_BINK 000040 /* K = power of 2 */ +#define UNIT_BUFABLE 000100 /* bufferable */ +#define UNIT_MUSTBUF 000200 /* must buffer */ +#define UNIT_BUF 000400 /* buffered */ +#define UNIT_ROABLE 001000 /* read only ok */ +#define UNIT_DISABLE 002000 /* disable-able */ +#define UNIT_DIS 004000 /* disabled */ +#define UNIT_V_UF 12 /* device specific */ + /* must be DIS+1!! */ +#define UNIT_V_RSV 31 /* reserved!! */ + +/* Register data structure */ + +struct reg { + char *name; /* name */ + void *loc; /* location */ + int32 radix; /* radix */ + int32 width; /* width */ + int32 offset; /* starting bit */ + int32 depth; /* save depth */ + int32 flags; /* flags */ + int32 qptr; /* circ q ptr */ +}; + +#define REG_FMT 0003 /* see PV_x */ +#define REG_RO 0004 /* read only */ +#define REG_HIDDEN 0010 /* hidden */ +#define REG_NZ 0020 /* must be non-zero */ +#define REG_UNIT 0040 /* in unit struct */ +#define REG_CIRC 0100 /* circular array */ +#define REG_HRO (REG_RO | REG_HIDDEN) /* hidden, read only */ + +/* Command table */ + +struct ctab { + char *name; /* name */ + t_stat (*action)(); /* action routine */ + int32 arg; /* argument */ +}; + +/* Modifier table - only extended entries have disp, reg, or flags */ + +struct mtab { + int32 mask; /* mask or radix */ + int32 match; /* match or max */ + char *pstring; /* print string */ + char *mstring; /* match string */ + t_stat (*valid)(); /* validation routine */ + t_stat (*disp)(); /* display routine */ + void *desc; /* value descriptor */ + /* REG * if MTAB_VAL */ + /* int * if not */ +}; + +#define MTAB_XTD (1u << UNIT_V_RSV) /* ext entry flag */ +#define MTAB_VDV 001 /* valid for dev */ +#define MTAB_VUN 002 /* valid for unit */ +#define MTAB_VAL 004 /* takes a value */ +#define MTAB_NMO 010 /* only if named */ + +/* Search table */ + +struct schtab { + int logic; /* logical operator */ + int bool; /* boolean operator */ + t_value mask; /* mask for logical */ + t_value comp; /* comparison for boolean */ +}; + +/* The following macros define structure contents */ + +#define UDATA(act,fl,cap) NULL,act,NULL,NULL,NULL,0,0,(fl),(cap),0,0 + +#if defined (__STDC__) || defined (_WIN32) +#define ORDATA(nm,loc,wd) #nm, &(loc), 8, (wd), 0, 1 +#define DRDATA(nm,loc,wd) #nm, &(loc), 10, (wd), 0, 1 +#define HRDATA(nm,loc,wd) #nm, &(loc), 16, (wd), 0, 1 +#define FLDATA(nm,loc,pos) #nm, &(loc), 2, 1, (pos), 1 +#define GRDATA(nm,loc,rdx,wd,pos) #nm, &(loc), (rdx), (wd), (pos), 1 +#define BRDATA(nm,loc,rdx,wd,dep) #nm, (loc), (rdx), (wd), 0, (dep) +#define URDATA(nm,loc,rdx,wd,off,dep,fl) \ + #nm, &(loc), (rdx), (wd), (off), (dep), ((fl) | REG_UNIT) +#else +#define ORDATA(nm,loc,wd) "nm", &(loc), 8, (wd), 0, 1 +#define DRDATA(nm,loc,wd) "nm", &(loc), 10, (wd), 0, 1 +#define HRDATA(nm,loc,wd) "nm", &(loc), 16, (wd), 0, 1 +#define FLDATA(nm,loc,pos) "nm", &(loc), 2, 1, (pos), 1 +#define GRDATA(nm,loc,rdx,wd,pos) "nm", &(loc), (rdx), (wd), (pos), 1 +#define BRDATA(nm,loc,rdx,wd,dep) "nm", (loc), (rdx), (wd), 0, (dep) +#define URDATA(nm,loc,rdx,wd,off,dep,fl) \ + "nm", &(loc), (rdx), (wd), (off), (dep), ((fl) | REG_UNIT) +#endif + +/* Typedefs for principal structures */ + +typedef struct device DEVICE; +typedef struct unit UNIT; +typedef struct reg REG; +typedef struct ctab CTAB; +typedef struct mtab MTAB; +typedef struct schtab SCHTAB; + +/* Function prototypes */ + +t_stat sim_process_event (void); +t_stat sim_activate (UNIT *uptr, int32 interval); +t_stat sim_cancel (UNIT *uptr); +int32 sim_is_active (UNIT *uptr); +double sim_gtime (void); +uint32 sim_grtime (void); +int32 sim_qcount (void); +t_stat attach_unit (UNIT *uptr, char *cptr); +t_stat detach_unit (UNIT *uptr); +t_stat reset_all (int start_device); +size_t fxread (void *bptr, size_t size, size_t count, FILE *fptr); +size_t fxwrite (void *bptr, size_t size, size_t count, FILE *fptr); +t_stat get_yn (char *ques, t_stat deflt); +char *get_glyph (char *iptr, char *optr, char mchar); +char *get_glyph_nc (char *iptr, char *optr, char mchar); +t_value get_uint (char *cptr, int radix, t_value max, t_stat *status); +t_value strtotv (char *cptr, char **endptr, int radix); +DEVICE *find_dev_from_unit (UNIT *uptr); +REG *find_reg (char *ptr, char **optr, DEVICE *dptr); +int32 sim_rtc_init (int32 time); +int32 sim_rtc_calb (int32 ticksper); +int32 sim_rtcn_init (int32 time, int32 tmr); +int32 sim_rtcn_calb (int32 time, int32 tmr); +t_stat sim_poll_kbd (void); +t_stat sim_putchar (int32 out); +t_bool sim_brk_test (t_addr bloc, int32 btyp); + +#ifdef GUI_SUPPORT +void update_gui (t_bool force); +#endif diff --git a/NOVA/eclipse_cpu.c b/NOVA/eclipse_cpu.c index 25ff4f68..9a8e3e80 100644 --- a/NOVA/eclipse_cpu.c +++ b/NOVA/eclipse_cpu.c @@ -2,8 +2,8 @@ Modified from the original NOVA simulator by Robert Supnik. - Copyright (c) 1998-2001, Charles E Owen - Portions Copyright (c) 1993-2001, Robert M Supnik + Copyright (c) 1998-2002, Charles E Owen + Portions Copyright (c) 1993-2002, Robert M Supnik Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), @@ -28,6 +28,7 @@ cpu Eclipse central processor + 28-Jan-02 RMS Cleaned up compiler warnings 30-Nov-01 RMS Added extended SET/SHOW support 01-Jun-01 RMS Added second terminal, plotter support 26-Apr-01 RMS Added device enable/disable support @@ -431,6 +432,7 @@ t_stat map_svc (UNIT *uptr); int32 GetMap(int32 addr); int32 PutMap(int32 addr, int32 data); int32 Debug_Entry(int32 PC, int32 inst, int32 inst2, int32 AC0, int32 AC1, int32 AC2, int32 AC3, int32 flags); + extern int32 ptr (int32 pulse, int32 code, int32 AC); extern int32 ptp (int32 pulse, int32 code, int32 AC); extern int32 tti (int32 pulse, int32 code, int32 AC); @@ -444,8 +446,7 @@ extern int32 dsk (int32 pulse, int32 code, int32 AC); extern int32 dkp (int32 pulse, int32 code, int32 AC); extern int32 mta (int32 pulse, int32 code, int32 AC); int32 nulldev (int32 pulse, int32 code, int32 AC); -extern t_stat sim_activate (UNIT *uptr, int32 delay); -t_stat fprint_sym (FILE *of, t_addr addr, t_value *val, +extern t_stat fprint_sym (FILE *of, t_addr addr, t_value *val, UNIT *uptr, int32 sw); /* IOT dispatch table */ @@ -1640,7 +1641,7 @@ if ((IR & 0100017) == 0100010) { /* This pattern for all */ AC[3] = da; d = GetMap(GetMap(044) + op); PC = indirect(d) & AMASK; - if ((GetMap(040) & AMASK) > GetMap(042) & AMASK) { + if ((GetMap(040) & AMASK) > (GetMap(042) & AMASK)) { pushrtn(PC); PC = indirect(GetMap(043)); PutMap(040, (GetMap(040) & 077777)); @@ -3406,6 +3407,42 @@ int32 Debug_Dump(UNIT *uptr, int32 val, char *cptr, void *desc) ctr = 0; } fclose(Dumpf); - printf("\n%d records dumped to history.log\n"); + printf("\n%d records dumped to history.log\n", count); return SCPE_OK; } + +/* Device enable routine */ + +t_stat set_enb (UNIT *uptr, int32 val, char *cptr, void *desc) +{ +DEVICE *dptr; + +if (cptr != NULL) return SCPE_ARG; +if ((uptr == NULL) || (val == 0)) return SCPE_IERR; +dptr = find_dev_from_unit (uptr); +if (dptr == NULL) return SCPE_IERR; +iot_enb = iot_enb | val; +if (dptr -> reset) dptr -> reset (dptr); +return SCPE_OK; +} + +/* Device disable routine */ + +t_stat set_dsb (UNIT *uptr, int32 val, char *cptr, void *desc) +{ +int32 i; +DEVICE *dptr; +UNIT *up; + +if (cptr != NULL) return SCPE_ARG; +if ((uptr == NULL) || (val == 0)) return SCPE_IERR; +dptr = find_dev_from_unit (uptr); +if (dptr == NULL) return SCPE_IERR; +for (i = 0; i < dptr -> numunits; i++) { /* check units */ + up = (dptr -> units) + i; + if ((up -> flags & UNIT_ATT) || sim_is_active (up)) + return SCPE_NOFNC; } +iot_enb = iot_enb & ~val; +if (dptr -> reset) dptr -> reset (dptr); +return SCPE_OK; +} diff --git a/NOVA/eclipse_tt.c b/NOVA/eclipse_tt.c index 4b24279e..f3448983 100644 --- a/NOVA/eclipse_tt.c +++ b/NOVA/eclipse_tt.c @@ -1,27 +1,32 @@ /* eclipse_tt.c: Eclipse console terminal simulator - Copyright (c) 1993-1997, - Robert M Supnik, Digital Equipment Corporation + Copyright (c) 1998-2002, Charles E Owen + Portions copyright (c) 1993-2002, Robert M Supnik + Written by Charles Owen, used by gracious permission Commercial use prohibited tti terminal input tto terminal output + + 30-May-02 RMS Widened POS to 32b + 28-Jan-02 RMS Cleaned up compiler warnings */ #include "nova_defs.h" #define UNIT_V_DASHER (UNIT_V_UF + 0) /* Dasher mode */ #define UNIT_DASHER (1 << UNIT_V_DASHER) + extern int32 int_req, dev_busy, dev_done, dev_disable; + t_stat tti_svc (UNIT *uptr); t_stat tto_svc (UNIT *uptr); t_stat tti_reset (DEVICE *dptr); t_stat tto_reset (DEVICE *dptr); t_stat ttx_setmod (UNIT *uptr, int32 value); -extern t_stat sim_activate (UNIT *uptr, int32 delay); -extern t_stat sim_cancel (UNIT *uptr); -extern t_stat sim_poll_kbd (void); -extern t_stat sim_putchar (int32 out); +void translate_in(); +int32 translate_out(int32 c); +int32 putseq(char *seq); /* TTI data structures @@ -39,7 +44,7 @@ REG tti_reg[] = { { FLDATA (DONE, dev_done, INT_V_TTI) }, { FLDATA (DISABLE, dev_disable, INT_V_TTI) }, { FLDATA (INT, int_req, INT_V_TTI) }, - { DRDATA (POS, tti_unit.pos, 31), PV_LEFT }, + { DRDATA (POS, tti_unit.pos, 32), PV_LEFT }, { DRDATA (TIME, tti_unit.wait, 24), REG_NZ + PV_LEFT }, { FLDATA (MODE, tti_unit.flags, UNIT_V_DASHER), REG_HRO }, { NULL } }; @@ -70,7 +75,7 @@ REG tto_reg[] = { { FLDATA (DONE, dev_done, INT_V_TTO) }, { FLDATA (DISABLE, dev_disable, INT_V_TTO) }, { FLDATA (INT, int_req, INT_V_TTO) }, - { DRDATA (POS, tto_unit.pos, 31), PV_LEFT }, + { DRDATA (POS, tto_unit.pos, 32), PV_LEFT }, { DRDATA (TIME, tto_unit.wait, 24), PV_LEFT }, { FLDATA (MODE, tto_unit.flags, UNIT_V_DASHER), REG_HRO }, { NULL } }; @@ -132,7 +137,7 @@ int spec200 = 0; /* signals next char is 'special' */ /* Translation: Vt100 input to D200 keycodes. */ -int32 translate_in() +void translate_in() { char rev = 0; diff --git a/NOVA/nova_clk.c b/NOVA/nova_clk.c index 7fd6e643..a0411417 100644 --- a/NOVA/nova_clk.c +++ b/NOVA/nova_clk.c @@ -1,6 +1,6 @@ /* nova_clk.c: NOVA real-time clock simulator - Copyright (c) 1993-2001, Robert M. Supnik + Copyright (c) 1993-2002, Robert M. Supnik Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), diff --git a/NOVA/nova_cpu.c b/NOVA/nova_cpu.c index 44973c9c..625543ae 100644 --- a/NOVA/nova_cpu.c +++ b/NOVA/nova_cpu.c @@ -1,6 +1,6 @@ /* nova_cpu.c: NOVA CPU simulator - Copyright (c) 1993-2001, Robert M. Supnik + Copyright (c) 1993-2002, Robert M. Supnik Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), @@ -25,6 +25,7 @@ cpu Nova central processor + 30-Dec-01 RMS Added old PC queue 07-Dec-01 RMS Revised to use breakpoint package 30-Nov-01 RMS Added extended SET/SHOW support 10-Aug-01 RMS Removed register in declarations @@ -202,6 +203,10 @@ #include "nova_defs.h" +#define PCQ_SIZE 64 /* must be 2**n */ +#define PCQ_MASK (PCQ_SIZE - 1) +#define PCQ_ENTRY pcq[pcq_p = (pcq_p - 1) & PCQ_MASK] = PC + #define INCA(x) (((x) + 1) & AMASK) #define DECA(x) (((x) - 1) & AMASK) #define SEXT(x) (((x) & SIGN)? ((x) | ~DMASK): (x)) @@ -241,7 +246,9 @@ int32 pimask = 0; /* priority int mask */ int32 pwr_low = 0; /* power fail flag */ int32 ind_max = 16; /* iadr nest limit */ int32 stop_dev = 0; /* stop on ill dev */ -int32 old_PC = 0; /* previous PC */ +uint16 pcq[PCQ_SIZE] = { 0 }; /* PC queue */ +int32 pcq_p = 0; /* PC queue ptr */ +REG *pcq_r = NULL; /* PC queue reg ptr */ extern int32 sim_int_char; extern int32 sim_brk_types, sim_brk_dflt, sim_brk_summ; /* breakpoint info */ @@ -336,14 +343,15 @@ REG cpu_reg[] = { { FLDATA (ISTK, cpu_unit.flags, UNIT_V_STK), REG_HRO }, { FLDATA (IBYT, cpu_unit.flags, UNIT_V_BYT), REG_HRO }, { DRDATA (INDMAX, ind_max, 16), REG_NZ + PV_LEFT }, - { ORDATA (OLDPC, old_PC, 15), REG_RO }, + { BRDATA (PCQ, pcq, 8, 16, PCQ_SIZE), REG_RO+REG_CIRC }, + { ORDATA (PCQP, pcq_p, 6), REG_HRO }, { ORDATA (WRU, sim_int_char, 8) }, { ORDATA (IOTENB, iot_enb, 32), REG_HRO }, { NULL } }; MTAB cpu_mod[] = { - { UNIT_IOPT, UNIT_NOVA4, "NOVA4", "NOVA4", NULL }, { UNIT_IOPT, UNIT_NOVA3, "NOVA3", "NOVA3", NULL }, + { UNIT_IOPT, UNIT_NOVA4, "NOVA4", "NOVA4", NULL }, { UNIT_IOPT, UNIT_MDV, "MDV", "MDV", NULL }, { UNIT_IOPT, 0, "none", "NONE", NULL }, { UNIT_MSIZE, 4096, NULL, "4K", &cpu_set_size }, @@ -386,8 +394,9 @@ if (sim_interval <= 0) { /* check clock queue */ if (int_req > INT_PENDING) { /* interrupt? */ int32 MA, indf; - int_req = int_req & ~INT_ION; - old_PC = M[INT_SAV] = PC; + int_req = int_req & ~INT_ION; /* intr off */ + PCQ_ENTRY; /* save old PC */ + M[INT_SAV] = PC; if (int_req & INT_STK) { /* stack overflow? */ int_req = int_req & ~INT_STK; /* clear */ MA = STK_JMP; } /* jmp @3 */ @@ -470,8 +479,9 @@ if (IR & I_OPR) { /* operate? */ switch (I_GETSKP (IR)) { /* decode skip */ case 0: /* nop */ if ((IR & I_NLD) && (cpu_unit.flags & UNIT_STK)) { - int32 indf, MA; /* Nova 3 or 4 trap */ - old_PC = M[TRP_SAV] = (PC - 1) & AMASK; + int32 indf, MA; /* Nova 3 or 4 trap */ + PCQ_ENTRY; /* save old PC */ + M[TRP_SAV] = (PC - 1) & AMASK; MA = TRP_JMP; /* jmp @47 */ for (i = 0, indf = 1; indf && (i < ind_max); i++) { indf = IND_STEP (MA); } /* resolve ind */ @@ -541,7 +551,7 @@ else if (IR < 060000) { /* mem ref? */ case 001: /* JSR */ AC[3] = PC; case 000: /* JMP */ - old_PC = PC; + PCQ_ENTRY; PC = MA; break; case 002: /* ISZ */ @@ -675,7 +685,7 @@ else { /* IOT */ AC[3] = FP = SP & AMASK; STK_CHECK (SP, 5); } if (pulse == iopC) { /* retn */ - old_PC = PC; + PCQ_ENTRY; SP = FP & AMASK; C = (M[SP] << 1) & CBIT; PC = M[SP] & AMASK; @@ -791,6 +801,7 @@ else { /* IOT */ /* Simulation halted */ saved_PC = PC; +pcq_r -> qptr = pcq_p; /* update pc q ptr */ return reason; } @@ -823,6 +834,9 @@ int_req = int_req & ~(INT_ION | INT_STK); pimask = 0; dev_disable = 0; pwr_low = 0; +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; } @@ -912,3 +926,46 @@ for (i = 0; i < BOOT_LEN; i++) M[BOOT_START + i] = boot_rom[i]; saved_PC = BOOT_START; return SCPE_OK; } + +/* Device enable routine */ + +t_stat set_enb (UNIT *uptr, int32 val, char *cptr, void *desc) +{ +DEVICE *dptr; + +if (cptr != NULL) return SCPE_ARG; +if ((uptr == NULL) || (val == 0)) return SCPE_IERR; +dptr = find_dev_from_unit (uptr); +if (dptr == NULL) return SCPE_IERR; +iot_enb = iot_enb | val; +if (dptr -> reset) dptr -> reset (dptr); +return SCPE_OK; +} + +/* Device disable routine */ + +t_stat set_dsb (UNIT *uptr, int32 val, char *cptr, void *desc) +{ +int32 i; +DEVICE *dptr; +UNIT *up; + +if (cptr != NULL) return SCPE_ARG; +if ((uptr == NULL) || (val == 0)) return SCPE_IERR; +dptr = find_dev_from_unit (uptr); +if (dptr == NULL) return SCPE_IERR; +for (i = 0; i < dptr -> numunits; i++) { /* check units */ + up = (dptr -> units) + i; + if ((up -> flags & UNIT_ATT) || sim_is_active (up)) + return SCPE_NOFNC; } +iot_enb = iot_enb & ~val; +if (dptr -> reset) dptr -> reset (dptr); +return SCPE_OK; +} + +/* 1-to-1 map for I/O devices */ + +int32 MapAddr (int32 map, int32 addr) +{ +return addr; +} diff --git a/NOVA/nova_defs.h b/NOVA/nova_defs.h index 5cedf87a..05cee81b 100644 --- a/NOVA/nova_defs.h +++ b/NOVA/nova_defs.h @@ -1,6 +1,6 @@ /* nova_defs.h: NOVA/Eclipse simulator definitions - Copyright (c) 1993-2001, Robert M. Supnik + Copyright (c) 1993-2002, Robert M. Supnik Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), @@ -233,3 +233,9 @@ struct ndev { /* #define PI_DCM 0100000 */ /* #define PI_CAS 0000040 */ /* #define PI_ADCV 0000002 */ + +/* Function prototypes */ + +int32 MapAddr (int32 map, int32 addr); +t_stat set_enb (UNIT *uptr, int32 val, char *cptr, void *desc); +t_stat set_dsb (UNIT *uptr, int32 val, char *cptr, void *desc); diff --git a/NOVA/nova_dkp.c b/NOVA/nova_dkp.c index ec21fec5..f6ab8399 100644 --- a/NOVA/nova_dkp.c +++ b/NOVA/nova_dkp.c @@ -1,6 +1,6 @@ /* nova_dkp.c: NOVA moving head disk simulator - Copyright (c) 1993-2001, Robert M. Supnik + Copyright (c) 1993-2002, Robert M. Supnik Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), @@ -25,6 +25,7 @@ dkp moving head disk + 06-Jan-02 RMS Revised enable/disable support 30-Nov-01 RMS Added read only unit, extended SET/SHOW support 24-Nov-01 RMS Changed FLG, CAPAC to arrays 26-Apr-01 RMS Added device enable/disable support @@ -286,11 +287,6 @@ t_stat dkp_boot (int32 unitno); t_stat dkp_attach (UNIT *uptr, char *cptr); t_stat dkp_go (void); t_stat dkp_set_size (UNIT *uptr, int32 val, char *cptr, void *desc); -#if defined (ECLIPSE) -extern int32 MapAddr (int32 map, int32 addr); -#else -#define MapAddr(m,a) (a) -#endif /* DKP data structures @@ -329,7 +325,7 @@ REG dkp_reg[] = { { NULL } }; MTAB dkp_mod[] = { - { UNIT_WLK, 0, "write enabled", "ENABLED", NULL }, + { UNIT_WLK, 0, "write enabled", "WRITEENABLED", NULL }, { UNIT_WLK, UNIT_WLK, "write locked", "LOCKED", NULL }, { (UNIT_DTYPE+UNIT_ATT), (TYPE_FLP << UNIT_V_DTYPE) + UNIT_ATT, "6030 (floppy)", NULL, NULL }, @@ -423,6 +419,8 @@ MTAB dkp_mod[] = { NULL, "4231", &dkp_set_size }, { (UNIT_AUTO+UNIT_DTYPE), (TYPE_4231 << UNIT_V_DTYPE), NULL, "3330", &dkp_set_size }, + { MTAB_XTD|MTAB_VDV, INT_DKP, NULL, "ENABLED", &set_enb }, + { MTAB_XTD|MTAB_VDV, INT_DKP, NULL, "DISABLED", &set_dsb }, { 0 } }; DEVICE dkp_dev = { diff --git a/NOVA/nova_doc.txt b/NOVA/nova_doc.txt index 27eb5912..13af4395 100644 --- a/NOVA/nova_doc.txt +++ b/NOVA/nova_doc.txt @@ -1,14 +1,14 @@ To: Users From: Bob Supnik Subj: Nova Simulator Usage -Date: 1-Dec-01 +Date: 15-Jun-2002 COPYRIGHT NOTICE The following copyright notice applies to both the SIMH source and binary: - Original code published in 1993-2001, written by Robert M Supnik - Copyright (c) 1993-2001, Robert M Supnik + Original code published in 1993-2002, written by Robert M Supnik + Copyright (c) 1993-2002, Robert M Supnik Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), @@ -68,7 +68,7 @@ CPU Nova CPU with 32KW of memory - hardware multiply/divide PTR,PTP paper tape reader/punch TTI,TTO console terminal -TTI1,TTO1 second terminal +TTI1,TTO1 second terminal LPT line printer PLT plotter CLK real-time clock @@ -76,7 +76,7 @@ DK head-per-track disk controller DP moving head disk controller with four drives MT magnetic tape controller with eight drives -The TTI1/TTO1, PLT, DK, DP, and MT devices can be DISABLEd. +The TTI1/TTO1, PLT, DK, DP, and MT devices can be set DISABLED. The Nova simulator implements these unique stop conditions: @@ -134,7 +134,8 @@ control registers for the interrupt system. DISABLE 15 device interrupt disable flags STOP_DEV 1 stop on undefined IOT INDMAX 15 maximum number of nested indirects - OLDPC 15 PC prior to last JMP, JMS, or interrupt + PCQ[0:63] 15 PC prior to last JMP, JMS, or interrupt; + most recent PC change first WRU 8 interrupt character 2.2 Programmed I/O Devices @@ -154,7 +155,7 @@ The paper tape reader implements these registers: DONE 1 device done flag DISABLE 1 interrupt disable flag INT 1 interrupt pending flag - POS 31 position in the input file + POS 32 position in the input file TIME 24 time from I/O initiation to interrupt STOP_IOE 1 stop on I/O error @@ -185,7 +186,7 @@ The paper tape punch implements these registers: DONE 1 device done flag DISABLE 1 interrupt disable flag INT 1 interrupt pending flag - POS 31 position in the output file + POS 32 position in the output file TIME 24 time from I/O initiation to interrupt STOP_IOE 1 stop on I/O error @@ -219,7 +220,7 @@ The terminal input implements these registers: DONE 1 device done flag DISABLE 1 interrupt disable flag INT 1 interrupt pending flag - POS 31 number of characters input + POS 32 number of characters input TIME 24 keyboard polling interval 2.2.4 Terminal Output (TTO) @@ -243,7 +244,7 @@ The terminal output implements these registers: DONE 1 device done flag DISABLE 1 interrupt disable flag INT 1 interrupt pending flag - POS 31 number of characters output + POS 32 number of characters output TIME 24 time from I/O initiation to interrupt 2.2.5 Line Printer (LPT) @@ -261,7 +262,7 @@ The line printer implements these registers: DONE 1 device done flag DISABLE 1 interrupt disable flag INT 1 interrupt pending flag - POS 31 position in the output file + POS 32 position in the output file TIME 24 time from I/O initiation to interrupt STOP_IOE 1 stop on I/O error @@ -308,7 +309,7 @@ The plotter implements these registers: DONE 1 device done flag DISABLE 1 interrupt disable flag INT 1 interrupt pending flag - POS 31 position in the output file + POS 32 position in the output file TIME 24 time from I/O initiation to interrupt STOP_IOE 1 stop on I/O error @@ -328,7 +329,7 @@ The additional terminal performs input and output through a Telnet session connecting into a user-specified port. The ATTACH command specifies the port to be used: - ATTACH TTI1 (cr) -- set up listening port + ATTACH TTI1 set up listening port where port is a decimal number between 1 and 65535 that is not being used for other TCP/IP activities. @@ -349,8 +350,9 @@ setting limited Dasher-compatibility mode or ANSI mode: Setting either TTI1 or TTO1 changes both devices. In Dasher mode, carriage return is changed to newline on input, and ^X is changed to backspace. -The SHOW TTI1 LINESTATUS command displays the current connection to the -second terminal. +The SHOW TTI1 CONNECTIONS command displays the current connection to TTI1. +The SHOW TTI1 STATISTICS command displays statistics for the current connection. +The SET TTI1 DISCONNECT{=0} disconnects the current connection. The second terminal input implements these registers: @@ -361,7 +363,6 @@ The second terminal input implements these registers: DONE 1 device done flag DISABLE 1 interrupt disable flag INT 1 interrupt pending flag - POS 31 number of characters input TIME 24 keyboard polling interval The second terminal output implements these registers: @@ -373,7 +374,6 @@ The second terminal output implements these registers: DONE 1 device done flag DISABLE 1 interrupt disable flag INT 1 interrupt pending flag - POS 31 number of characters output TIME 24 time from I/O initiation to interrupt 2.3 Fixed Head Disk (DK) @@ -411,7 +411,7 @@ Moving head disk options include the ability to make units write enabled or write locked, and to select the type of drive: SET DPn LOCKED set unit n write locked - SET DPn ENABLED set unit n write enabled + SET DPn WRITEENABLED set unit n write enabled SET DPn FLOPPY set unit n to floppy disk SET DPn D31 set unit n to Diablo 31 SET DPn D44 set unit n to Diablo 44 @@ -424,8 +424,8 @@ write locked, and to select the type of drive: SET DPn 6103 set unit n to 6103 SET DPn 4231 set unit n to 4231 -Units can also be REMOVEd or ADDed to the configuration. The moving head -disk controller supports the BOOT command. +Units can also be set ONLINE or OFFLINE. The moving head disk controller +supports the BOOT command. All drives have 256 16b words per sector. The other disk parameters are: @@ -474,10 +474,10 @@ Magnetic tape options include the ability to make units write enabled or or write locked. SET MTn LOCKED set unit n write locked - SET MTn ENABLED set unit n write enabled + SET MTn WRITEENABLED set unit n write enabled -Units can also be REMOVEd or ADDed to the configuration. The magnetic -tape controller supports the BOOT command. +Units can also be set ONLINE or OFFLINE. The magnetic tape controller +supports the BOOT command. The magnetic tape controller implements these registers: diff --git a/NOVA/nova_dsk.c b/NOVA/nova_dsk.c index 3f81042e..5eb89ecf 100644 --- a/NOVA/nova_dsk.c +++ b/NOVA/nova_dsk.c @@ -1,6 +1,6 @@ /* nova_dsk.c: 4019 fixed head disk simulator - Copyright (c) 1993-2001, Robert M. Supnik + Copyright (c) 1993-2002, Robert M. Supnik Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), @@ -25,6 +25,7 @@ dsk fixed head disk + 06-Jan-02 RMS Revised enable/disable support 23-Aug-01 RMS Fixed bug in write watermarking 26-Apr-01 RMS Added device enable/disable support 10-Dec-00 RMS Added Eclipse support @@ -88,11 +89,6 @@ int32 dsk_time = 100; /* time per sector */ t_stat dsk_svc (UNIT *uptr); t_stat dsk_reset (DEVICE *dptr); t_stat dsk_boot (int32 unitno); -#if defined (ECLIPSE) -extern int32 MapAddr (int32 map, int32 addr); -#else -#define MapAddr(m,a) (a) -#endif /* DSK data structures @@ -119,8 +115,13 @@ REG dsk_reg[] = { { FLDATA (*DEVENB, iot_enb, INT_V_DSK), REG_HRO }, { NULL } }; +MTAB dsk_mod[] = { + { MTAB_XTD|MTAB_VDV, INT_DSK, NULL, "ENABLED", &set_enb }, + { MTAB_XTD|MTAB_VDV, INT_DSK, NULL, "DISABLED", &set_dsb }, + { 0 } }; + DEVICE dsk_dev = { - "DK", &dsk_unit, dsk_reg, NULL, + "DK", &dsk_unit, dsk_reg, dsk_mod, 1, 8, 21, 1, 8, 16, NULL, NULL, &dsk_reset, &dsk_boot, NULL, NULL }; diff --git a/NOVA/nova_lp.c b/NOVA/nova_lp.c index 36ee1799..c2095838 100644 --- a/NOVA/nova_lp.c +++ b/NOVA/nova_lp.c @@ -1,6 +1,6 @@ /* nova_lp.c: NOVA line printer simulator - Copyright (c) 1993-2001, Robert M. Supnik + Copyright (c) 1993-2002, Robert M. Supnik Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), @@ -24,6 +24,8 @@ in this Software without prior written authorization from Robert M Supnik. lpt line printer + + 30-May-02 RMS Widened POS to 32b */ #include "nova_defs.h" @@ -49,7 +51,7 @@ REG lpt_reg[] = { { FLDATA (DONE, dev_done, INT_V_LPT) }, { FLDATA (DISABLE, dev_disable, INT_V_LPT) }, { FLDATA (INT, int_req, INT_V_LPT) }, - { DRDATA (POS, lpt_unit.pos, 31), PV_LEFT }, + { DRDATA (POS, lpt_unit.pos, 32), PV_LEFT }, { DRDATA (TIME, lpt_unit.wait, 24), PV_LEFT }, { FLDATA (STOP_IOE, lpt_stopioe, 0) }, { NULL } }; diff --git a/NOVA/nova_mta.c b/NOVA/nova_mta.c index 63b6271f..8d61142d 100644 --- a/NOVA/nova_mta.c +++ b/NOVA/nova_mta.c @@ -1,6 +1,6 @@ /* nova_mta.c: NOVA magnetic tape simulator - Copyright (c) 1993-2001, Robert M. Supnik + Copyright (c) 1993-2002, Robert M. Supnik Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), @@ -25,6 +25,9 @@ mta magnetic tape + 30-May-02 RMS Widened POS to 32b + 22-Apr-02 RMS Added maximum record length test + 06-Jan-02 RMS Revised enable/disable support 30-Nov-01 RMS Added read only unit, extended SET/SHOW support 24-Nov-01 RMS Changed POS, USTAT, FLG to an array 26-Apr-01 RMS Added device enable/disable support @@ -60,6 +63,7 @@ #define UNIT_W_UF 2 /* saved flags width */ #define USTAT u3 /* unit status */ #define UNUM u4 /* unit number */ +#define MTA_MAXFR (1 << 16) /* max record lnt */ #define DTSIZE (1 << 14) /* max data xfer */ #define DTMASK (DTSIZE - 1) #define UNIT_WPRT (UNIT_WLK | UNIT_RO) /* write protect */ @@ -153,11 +157,6 @@ t_stat mta_detach (UNIT *uptr); int32 mta_updcsta (UNIT *uptr); void mta_upddsta (UNIT *uptr, int32 newsta); t_stat mta_vlock (UNIT *uptr, int32 val, char *cptr, void *desc); -#if defined (ECLIPSE) -extern int32 MapAddr (int32 map, int32 addr); -#else -#define MapAddr(m,a) (a) -#endif static const int ctype[32] = { /* c vs r timing */ 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, @@ -195,7 +194,7 @@ REG mta_reg[] = { { DRDATA (CTIME, mta_cwait, 24), PV_LEFT }, { DRDATA (RTIME, mta_rwait, 24), PV_LEFT }, { URDATA (UST, mta_unit[0].USTAT, 8, 32, 0, MTA_NUMDR, 0) }, - { URDATA (POS, mta_unit[0].pos, 8, 31, 0, + { URDATA (POS, mta_unit[0].pos, 8, 32, 0, MTA_NUMDR, REG_RO | PV_LEFT) }, { URDATA (FLG, mta_unit[0].flags, 8, UNIT_W_UF, UNIT_V_UF - 1, MTA_NUMDR, REG_HRO) }, @@ -203,8 +202,10 @@ REG mta_reg[] = { { NULL } }; MTAB mta_mod[] = { - { UNIT_WLK, 0, "write enabled", "ENABLED", &mta_vlock }, + { UNIT_WLK, 0, "write enabled", "WRITEENABLED", &mta_vlock }, { UNIT_WLK, UNIT_WLK, "write locked", "LOCKED", &mta_vlock }, + { MTAB_XTD|MTAB_VDV, INT_MTA, NULL, "ENABLED", &set_enb }, + { MTAB_XTD|MTAB_VDV, INT_MTA, NULL, "DISABLED", &set_dsb }, { 0 } }; DEVICE mta_dev = { @@ -347,6 +348,7 @@ case CU_READNS: /* read non-stop */ uptr -> pos = uptr -> pos + sizeof (t_mtrlnt); break; } tbc = MTRL (tbc); /* ignore error flag */ + if (tbc > MTA_MAXFR) return SCPE_MTRLNT; /* record too long? */ cbc = wc * 2; /* expected bc */ if (tbc & 1) mta_sta = mta_sta | STA_ODD; /* odd byte count? */ if (tbc > cbc) mta_sta = mta_sta | STA_WCO; /* too big? */ diff --git a/NOVA/nova_plt.c b/NOVA/nova_plt.c index 30343faa..66479f26 100644 --- a/NOVA/nova_plt.c +++ b/NOVA/nova_plt.c @@ -1,6 +1,6 @@ /* nova_plt.c: NOVA plotter simulator - Copyright (c) 2000-2001, Robert M. Supnik + Copyright (c) 2000-2002, Robert M. Supnik Written by Bruce Ray and used with his gracious permission. Permission is hereby granted, free of charge, to any person obtaining a @@ -26,6 +26,8 @@ plt plotter + 30-May-02 RMS Widened POS to 32b + 06-Jan-02 RMS Revised enable/disable support 26-Apr-01 RMS Added device enable/disable support */ @@ -52,14 +54,19 @@ REG plt_reg[] = { { FLDATA (DONE, dev_done, INT_V_PLT) }, { FLDATA (DISABLE, dev_disable, INT_V_PLT) }, { FLDATA (INT, int_req, INT_V_PLT) }, - { DRDATA (POS, plt_unit.pos, 31), PV_LEFT }, + { DRDATA (POS, plt_unit.pos, 32), PV_LEFT }, { DRDATA (TIME, plt_unit.wait, 24), PV_LEFT }, { FLDATA (STOP_IOE, plt_stopioe, 0) }, { FLDATA (*DEVENB, iot_enb, INT_V_PLT), REG_HRO }, { NULL } }; +MTAB plt_mod[] = { + { MTAB_XTD|MTAB_VDV, INT_PLT, NULL, "ENABLED", &set_enb }, + { MTAB_XTD|MTAB_VDV, INT_PLT, NULL, "DISABLED", &set_dsb }, + { 0 } }; + DEVICE plt_dev = { - "PLT", &plt_unit, plt_reg, NULL, + "PLT", &plt_unit, plt_reg, plt_mod, 1, 10, 31, 1, 8, 8, NULL, NULL, &plt_reset, NULL, NULL, NULL }; diff --git a/NOVA/nova_pt.c b/NOVA/nova_pt.c index 922233b7..629b1db1 100644 --- a/NOVA/nova_pt.c +++ b/NOVA/nova_pt.c @@ -1,6 +1,6 @@ /* nova_pt.c: NOVA paper tape read/punch simulator - Copyright (c) 1993-2001, Robert M. Supnik + Copyright (c) 1993-2002, Robert M. Supnik Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), @@ -26,6 +26,7 @@ ptr paper tape reader ptp paper tape punch + 30-May-02 RMS Widened POS to 32b 29-Nov-01 RMS Added read only unit support */ @@ -55,7 +56,7 @@ REG ptr_reg[] = { { FLDATA (DONE, dev_done, INT_V_PTR) }, { FLDATA (DISABLE, dev_disable, INT_V_PTR) }, { FLDATA (INT, int_req, INT_V_PTR) }, - { DRDATA (POS, ptr_unit.pos, 31), PV_LEFT }, + { DRDATA (POS, ptr_unit.pos, 32), PV_LEFT }, { DRDATA (TIME, ptr_unit.wait, 24), PV_LEFT }, { FLDATA (STOP_IOE, ptr_stopioe, 0) }, { NULL } }; @@ -82,7 +83,7 @@ REG ptp_reg[] = { { FLDATA (DONE, dev_done, INT_V_PTP) }, { FLDATA (DISABLE, dev_disable, INT_V_PTP) }, { FLDATA (INT, int_req, INT_V_PTP) }, - { DRDATA (POS, ptp_unit.pos, 31), PV_LEFT }, + { DRDATA (POS, ptp_unit.pos, 32), PV_LEFT }, { DRDATA (TIME, ptp_unit.wait, 24), PV_LEFT }, { FLDATA (STOP_IOE, ptp_stopioe, 0) }, { NULL } }; diff --git a/NOVA/nova_sys.c b/NOVA/nova_sys.c index 4de0798c..dbde1a05 100644 --- a/NOVA/nova_sys.c +++ b/NOVA/nova_sys.c @@ -1,6 +1,6 @@ /* nova_sys.c: NOVA simulator interface - Copyright (c) 1993-2001, Robert M. Supnik + Copyright (c) 1993-2002, Robert M. Supnik Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), diff --git a/NOVA/nova_tt.c b/NOVA/nova_tt.c index 7cc75741..c611f335 100644 --- a/NOVA/nova_tt.c +++ b/NOVA/nova_tt.c @@ -1,6 +1,6 @@ /* nova_tt.c: NOVA console terminal simulator - Copyright (c) 1993-2001, Robert M. Supnik + Copyright (c) 1993-2002, Robert M. Supnik Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), @@ -26,6 +26,7 @@ tti terminal input tto terminal output + 30-May-02 RMS Widened POS to 32b 30-Nov-01 RMS Added extended SET/SHOW support 17-Sep-01 RMS Removed multiconsole support 07-Sep-01 RMS Moved function prototypes @@ -59,7 +60,7 @@ REG tti_reg[] = { { FLDATA (DONE, dev_done, INT_V_TTI) }, { FLDATA (DISABLE, dev_disable, INT_V_TTI) }, { FLDATA (INT, int_req, INT_V_TTI) }, - { DRDATA (POS, tti_unit.pos, 31), PV_LEFT }, + { DRDATA (POS, tti_unit.pos, 32), PV_LEFT }, { DRDATA (TIME, tti_unit.wait, 24), REG_NZ + PV_LEFT }, { FLDATA (MODE, tti_unit.flags, UNIT_V_DASHER), REG_HRO }, { NULL } }; @@ -90,7 +91,7 @@ REG tto_reg[] = { { FLDATA (DONE, dev_done, INT_V_TTO) }, { FLDATA (DISABLE, dev_disable, INT_V_TTO) }, { FLDATA (INT, int_req, INT_V_TTO) }, - { DRDATA (POS, tto_unit.pos, 31), PV_LEFT }, + { DRDATA (POS, tto_unit.pos, 32), PV_LEFT }, { DRDATA (TIME, tto_unit.wait, 24), PV_LEFT }, { FLDATA (MODE, tto_unit.flags, UNIT_V_DASHER), REG_HRO }, { NULL } }; diff --git a/NOVA/nova_tt1.c b/NOVA/nova_tt1.c index 6d70840e..8aedfb9f 100644 --- a/NOVA/nova_tt1.c +++ b/NOVA/nova_tt1.c @@ -1,6 +1,6 @@ /* nova_tt1.c: NOVA second terminal simulator - Copyright (c) 1993-2001, Robert M. Supnik + Copyright (c) 1993-2002, Robert M. Supnik Written by Bruce Ray and used with his gracious permission. Permission is hereby granted, free of charge, to any person obtaining a @@ -27,6 +27,9 @@ tti1 second terminal input tto1 second terminal output + 30-May-02 RMS Widened POS to 32b + 06-Jan-02 RMS Revised enable/disable support + 30-Dec-01 RMS Added show statistics, set disconnect 30-Nov-01 RMS Added extended SET/SHOW support 17-Sep-01 RMS Changed to use terminal multiplexor library 07-Sep-01 RMS Moved function prototypes @@ -53,7 +56,8 @@ t_stat tto1_reset (DEVICE *dptr); t_stat ttx1_setmod (UNIT *uptr, int32 val, char *cptr); t_stat tti1_attach (UNIT *uptr, char *cptr); t_stat tti1_detach (UNIT *uptr); -t_stat tti1_status (FILE *st, UNIT *uptr, int32 val, void *desc); +t_stat tti1_summ (FILE *st, UNIT *uptr, int32 val, void *desc); +t_stat tti1_show (FILE *st, UNIT *uptr, int32 val, void *desc); /* TTI1 data structures @@ -71,22 +75,28 @@ REG tti1_reg[] = { { FLDATA (DONE, dev_done, INT_V_TTI1) }, { FLDATA (DISABLE, dev_disable, INT_V_TTI1) }, { FLDATA (INT, int_req, INT_V_TTI1) }, - { DRDATA (POS, tt1_ldsc.rxcnt, 31), PV_LEFT }, + { DRDATA (POS, tt1_ldsc.rxcnt, 32), PV_LEFT }, { DRDATA (TIME, tti1_unit.wait, 24), REG_NZ + PV_LEFT }, { FLDATA (MODE, tti1_unit.flags, UNIT_V_DASHER), REG_HRO }, { FLDATA (*DEVENB, iot_enb, INT_V_TTI1), REG_HRO }, { NULL } }; -MTAB ttx1_mod[] = { +MTAB tti1_mod[] = { { UNIT_DASHER, 0, "ANSI", "ANSI", &ttx1_setmod }, { UNIT_DASHER, UNIT_DASHER, "Dasher", "DASHER", &ttx1_setmod }, - { UNIT_ATT, UNIT_ATT, "line status", NULL, NULL, &tti1_status }, - { MTAB_XTD | MTAB_VDV | MTAB_VUN | MTAB_NMO, 0, "LINE", NULL, - NULL, &tti1_status, NULL }, + { UNIT_ATT, UNIT_ATT, "summary", NULL, NULL, &tti1_summ }, + { MTAB_XTD | MTAB_VDV, 0, NULL, "DISCONNECT", + &tmxr_dscln, NULL, &tt_desc }, + { MTAB_XTD | MTAB_VDV | MTAB_NMO, 1, "CONNECTIONS", NULL, + NULL, &tti1_show, NULL }, + { MTAB_XTD | MTAB_VDV | MTAB_NMO, 0, "STATISTICS", NULL, + NULL, &tti1_show, NULL }, + { MTAB_XTD|MTAB_VDV, INT_TTI1 | INT_TTO1, NULL, "ENABLED", &set_enb }, + { MTAB_XTD|MTAB_VDV, INT_TTI1 | INT_TTO1, NULL, "DISABLED", &set_dsb }, { 0 } }; DEVICE tti1_dev = { - "TTI1", &tti1_unit, tti1_reg, ttx1_mod, + "TTI1", &tti1_unit, tti1_reg, tti1_mod, 1, 10, 31, 1, 8, 8, &tmxr_ex, &tmxr_dep, &tti1_reset, NULL, &tti1_attach, &tti1_detach }; @@ -106,14 +116,19 @@ REG tto1_reg[] = { { FLDATA (DONE, dev_done, INT_V_TTO1) }, { FLDATA (DISABLE, dev_disable, INT_V_TTO1) }, { FLDATA (INT, int_req, INT_V_TTO1) }, - { DRDATA (POS, tt1_ldsc.txcnt, 31), PV_LEFT }, + { DRDATA (POS, tt1_ldsc.txcnt, 32), PV_LEFT }, { DRDATA (TIME, tto1_unit.wait, 24), PV_LEFT }, { FLDATA (MODE, tto1_unit.flags, UNIT_V_DASHER), REG_HRO }, - { FLDATA (*DEVENB, iot_enb, INT_V_TTI1), REG_HRO }, + { FLDATA (*DEVENB, iot_enb, INT_V_TTO1), REG_HRO }, { NULL } }; +MTAB tto1_mod[] = { + { UNIT_DASHER, 0, "ANSI", "ANSI", &ttx1_setmod }, + { UNIT_DASHER, UNIT_DASHER, "Dasher", "DASHER", &ttx1_setmod }, + { 0 } }; + DEVICE tto1_dev = { - "TTO1", &tto1_unit, tto1_reg, ttx1_mod, + "TTO1", &tto1_unit, tto1_reg, tto1_mod, 1, 10, 31, 1, 8, 8, NULL, NULL, &tto1_reset, NULL, NULL, NULL }; @@ -267,10 +282,20 @@ sim_cancel (uptr); /* stop poll */ return r; } -/* Status routine */ +/* Show summary processor */ -t_stat tti1_status (FILE *st, UNIT *uptr, int32 val, void *desc) +t_stat tti1_summ (FILE *st, UNIT *uptr, int32 val, void *desc) { -tmxr_fstatus (st, &tt1_ldsc, -1); +if (tt1_ldsc.conn) fprintf (st, "connected"); +else fprintf (st, "disconnected"); return SCPE_OK; -} \ No newline at end of file +} + +/* SHOW CONN/STAT processor */ + +t_stat tti1_show (FILE *st, UNIT *uptr, int32 val, void *desc) +{ +if (val) tmxr_fconns (st, &tt1_ldsc, -1); +else tmxr_fstats (st, &tt1_ldsc, -1); +return SCPE_OK; +} diff --git a/PDP1/pdp1_cpu.c b/PDP1/pdp1_cpu.c index 355a7620..3be08d24 100644 --- a/PDP1/pdp1_cpu.c +++ b/PDP1/pdp1_cpu.c @@ -1,6 +1,6 @@ /* pdp1_cpu.c: PDP-1 CPU simulator - Copyright (c) 1993-2001, Robert M. Supnik + Copyright (c) 1993-2002, Robert M. Supnik Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), @@ -25,6 +25,7 @@ cpu PDP-1 central processor + 30-Dec-01 RMS Added old PC queue 07-Dec-01 RMS Revised to use breakpoint package 30-Nov-01 RMS Added extended SET/SHOW support 16-Dec-00 RMS Fixed bug in XCT address calculation @@ -214,6 +215,9 @@ #include "pdp1_defs.h" +#define PCQ_SIZE 64 /* must be 2**n */ +#define PCQ_MASK (PCQ_SIZE - 1) +#define PCQ_ENTRY pcq[pcq_p = (pcq_p - 1) & PCQ_MASK] = PC #define UNIT_V_MDV (UNIT_V_UF) /* mul/div */ #define UNIT_MDV (1 << UNIT_V_MDV) #define UNIT_V_MSIZE (UNIT_V_UF+1) /* dummy mask */ @@ -237,7 +241,9 @@ int32 extm_init = 0; /* ext mem startup */ int32 stop_inst = 0; /* stop on rsrv inst */ int32 xct_max = 16; /* nested XCT limit */ int32 ind_max = 16; /* nested ind limit */ -int32 old_PC = 0; /* old PC */ +uint16 pcq[PCQ_SIZE] = { 0 }; /* PC queue */ +int32 pcq_p = 0; /* PC queue ptr */ +REG *pcq_r = NULL; /* PC queue reg ptr */ extern UNIT *sim_clock_queue; extern int32 sim_int_char; extern int32 sim_brk_types, sim_brk_dflt, sim_brk_summ; /* breakpoint info */ @@ -313,7 +319,8 @@ REG cpu_reg[] = { { FLDATA (SBIP, sbs, SB_V_IP) }, { FLDATA (IOH, ioh, 0) }, { FLDATA (IOC, ioc, 0) }, - { ORDATA (OLDPC, old_PC, ASIZE), REG_RO }, + { BRDATA (PCQ, pcq, 8, ASIZE, PCQ_SIZE), REG_RO+REG_CIRC }, + { ORDATA (PCQP, pcq_p, 6), REG_HRO }, { FLDATA (STOP_INST, stop_inst, 0) }, { FLDATA (SBS_INIT, sbs_init, SB_V_ON) }, { FLDATA (EXTM_INIT, extm_init, 0) }, @@ -369,7 +376,7 @@ if (sim_interval <= 0) { /* check clock queue */ if (sbs == (SB_ON | SB_RQ)) { /* interrupt? */ sbs = SB_ON | SB_IP; /* set in prog flag */ - old_PC = PC; /* save old PC */ + PCQ_ENTRY; /* save old PC */ M[0] = AC; /* save state */ M[1] = EPC_WORD; M[2] = IO; @@ -392,7 +399,7 @@ sim_interval = sim_interval - 1; xct_instr: /* label for XCT */ if ((IR == 0610001) && ((MA & EPCMASK) == 0) && (sbs & SB_ON)) { sbs = sbs & ~SB_IP; /* seq debreak */ - old_PC = PC; /* save old PC */ + PCQ_ENTRY; /* save old PC */ OV = (M[1] >> 17) & 1; /* restore OV */ extm = (M[1] >> 16) & 1; /* restore ext mode */ PC = M[1] & AMASK; /* JMP I 1 */ @@ -433,7 +440,7 @@ case 004: /* XCT */ goto xct_instr; /* go execute */ case 007: /* CAL, JDA */ MA = (PC & EPCMASK) | ((IR & IA)? (IR & DAMASK): 0100); - old_PC = PC; + PCQ_ENTRY; M[MA] = AC; AC = EPC_WORD; PC = INCR_ADDR (MA); @@ -509,12 +516,12 @@ case 025: /* SAS */ if (AC == M[MA]) PC = INCR_ADDR (PC); break; case 030: /* JMP */ - old_PC = PC; + PCQ_ENTRY; PC = MA; break; case 031: /* JSP */ AC = EPC_WORD; - old_PC = PC; + PCQ_ENTRY; PC = MA; break; case 034: /* LAW */ @@ -724,6 +731,7 @@ default: /* undefined */ reason = STOP_RSRV; /* halt */ break; } /* end switch opcode */ } /* end while */ +pcq_r -> qptr = pcq_p; /* update pc q ptr */ return reason; } @@ -736,6 +744,9 @@ extm = extm_init; ioh = ioc = 0; OV = 0; PF = 0; +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; } diff --git a/PDP1/pdp1_defs.h b/PDP1/pdp1_defs.h index 6cf7aa78..18c5b40f 100644 --- a/PDP1/pdp1_defs.h +++ b/PDP1/pdp1_defs.h @@ -1,6 +1,6 @@ /* pdp1_defs.h: 18b PDP simulator definitions - Copyright (c) 1993-2001, Robert M. Supnik + Copyright (c) 1993-2002, Robert M. Supnik Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), diff --git a/PDP1/pdp1_doc.txt b/PDP1/pdp1_doc.txt index fdca74e6..786d4ce9 100644 --- a/PDP1/pdp1_doc.txt +++ b/PDP1/pdp1_doc.txt @@ -1,14 +1,14 @@ To: Users From: Bob Supnik Subj: PDP-1 Simulator Usage -Date: 1-Dec-01 +Date: 15-Jun-02 COPYRIGHT NOTICE The following copyright notice applies to both the SIMH source and binary: - Original code published in 1993-2001, written by Robert M Supnik - Copyright (c) 1993-2001, Robert M Supnik + Original code published in 1993-2002, written by Robert M Supnik + Copyright (c) 1993-2002, Robert M Supnik Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), @@ -114,7 +114,8 @@ control registers for the interrupt system. SBIP 1 sequence break in progress IOH 1 I/O halt in progress IOC 1 I/O continue - OLDPC 16 PC prior to last transfer + PCQ[0:63] 16 PC prior to last jump or interrupt; + most recent PC change first STOP_INST 1 stop on undefined instruction SBS_INIT 1 initial state of sequence break enable EXTM_INIT 1 initial state of extend mode @@ -138,7 +139,7 @@ The paper tape reader implements these registers: BUF 8 last data item processed DONE 1 device done flag RPLS 1 return restart pulse flag - POS 31 position in the input file + POS 32 position in the input file TIME 24 time from I/O initiation to interrupt STOP_IOE 1 stop on I/O error @@ -167,7 +168,7 @@ The paper tape punch implements these registers: BUF 8 last data item processed DONE 1 device done flag RPLS 1 return restart pulse flag - POS 31 position in the output file + POS 32 position in the output file TIME 24 time from I/O initiation to interrupt STOP_IOE 1 stop on I/O error @@ -189,7 +190,7 @@ implements these registers: BUF 8 last data item processed DONE 1 device done flag - POS 31 number of characters input + POS 32 number of characters input TIME 24 keyboard polling interval 2.2.4 Terminal Output (TTO) @@ -202,7 +203,7 @@ It implements these registers: BUF 8 last data item processed DONE 1 device done flag RPLS 1 return restart pulse flag - POS 31 number of characters output + POS 32 number of characters output TIME 24 time from I/O initiation to interrupt 2.2.5 Type 62 Line Printer (LPT) @@ -220,7 +221,7 @@ The line printer implements these registers: SPC 1 spacing done flag RPLS 1 return restart pulse flag BPTR 6 print buffer pointer - POS 31 position in the output file + POS 32 position in the output file TIME 24 time from I/O initiation to interrupt STOP_IOE 1 stop on I/O error LBUF[0:119] 8 line buffer diff --git a/PDP1/pdp1_lp.c b/PDP1/pdp1_lp.c index cc6f68aa..4da02c47 100644 --- a/PDP1/pdp1_lp.c +++ b/PDP1/pdp1_lp.c @@ -1,6 +1,6 @@ /* pdp1_lp.c: PDP-1 line printer simulator - Copyright (c) 1993-2001, Robert M. Supnik + Copyright (c) 1993-2002, Robert M. Supnik Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), @@ -25,6 +25,7 @@ lpt Type 62 line printer for the PDP-1 + 30-May-02 RMS Widened POS to 32b 13-Apr-01 RMS Revised for register arrays */ @@ -55,7 +56,7 @@ REG lpt_reg[] = { { FLDATA (RPLS, lpt_rpls, 0) }, { DRDATA (BPTR, bptr, 6) }, { ORDATA (LPT_STATE, lpt_iot, 6), REG_HRO }, - { DRDATA (POS, lpt_unit.pos, 31), PV_LEFT }, + { DRDATA (POS, lpt_unit.pos, 32), PV_LEFT }, { DRDATA (TIME, lpt_unit.wait, 24), PV_LEFT }, { FLDATA (STOP_IOE, lpt_stopioe, 0) }, { BRDATA (LBUF, lpt_buf, 8, 8, LPT_BSIZE) }, diff --git a/PDP1/pdp1_stddev.c b/PDP1/pdp1_stddev.c index 21c0830e..8201bce7 100644 --- a/PDP1/pdp1_stddev.c +++ b/PDP1/pdp1_stddev.c @@ -1,6 +1,6 @@ /* pdp1_stddev.c: PDP-1 standard devices - Copyright (c) 1993-2001, Robert M. Supnik + Copyright (c) 1993-2002, Robert M. Supnik Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), @@ -28,6 +28,7 @@ tti keyboard tto teleprinter + 30-May-02 RMS Widened POS to 32b 29-Nov-01 RMS Added read only unit support 07-Sep-01 RMS Moved function prototypes 10-Jun-01 RMS Fixed comment @@ -112,7 +113,7 @@ REG ptr_reg[] = { { FLDATA (DONE, iosta, IOS_V_PTR) }, { FLDATA (RPLS, ptr_rpls, 0) }, { ORDATA (STATE, ptr_state, 5), REG_HRO }, - { DRDATA (POS, ptr_unit.pos, 31), PV_LEFT }, + { DRDATA (POS, ptr_unit.pos, 32), PV_LEFT }, { DRDATA (TIME, ptr_unit.wait, 24), PV_LEFT }, { FLDATA (STOP_IOE, ptr_stopioe, 0) }, { NULL } }; @@ -137,7 +138,7 @@ REG ptp_reg[] = { { ORDATA (BUF, ptp_unit.buf, 8) }, { FLDATA (DONE, iosta, IOS_V_PTP) }, { FLDATA (RPLS, ptp_rpls, 0) }, - { DRDATA (POS, ptp_unit.pos, 31), PV_LEFT }, + { DRDATA (POS, ptp_unit.pos, 32), PV_LEFT }, { DRDATA (TIME, ptp_unit.wait, 24), PV_LEFT }, { FLDATA (STOP_IOE, ptp_stopioe, 0) }, { NULL } }; @@ -161,7 +162,7 @@ REG tti_reg[] = { { ORDATA (BUF, tti_unit.buf, 6) }, { FLDATA (DONE, iosta, IOS_V_TTI) }, { ORDATA (STATE, tti_state, 10), REG_HRO }, - { DRDATA (POS, tti_unit.pos, 31), PV_LEFT }, + { DRDATA (POS, tti_unit.pos, 32), PV_LEFT }, { DRDATA (TIME, tti_unit.wait, 24), REG_NZ + PV_LEFT }, { NULL } }; @@ -185,7 +186,7 @@ REG tto_reg[] = { { FLDATA (DONE, iosta, IOS_V_TTO) }, { FLDATA (RPLS, tto_rpls, 0) }, { ORDATA (STATE, tto_state, 10), REG_HRO }, - { DRDATA (POS, tto_unit.pos, 31), PV_LEFT }, + { DRDATA (POS, tto_unit.pos, 32), PV_LEFT }, { DRDATA (TIME, tto_unit.wait, 24), PV_LEFT }, { NULL } }; diff --git a/PDP1/pdp1_sys.c b/PDP1/pdp1_sys.c index 7a5ee31d..1babdf54 100644 --- a/PDP1/pdp1_sys.c +++ b/PDP1/pdp1_sys.c @@ -1,6 +1,6 @@ /* pdp1_sys.c: PDP-1 simulator interface - Copyright (c) 1993-2001, Robert M. Supnik + Copyright (c) 1993-2002, Robert M. Supnik Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), diff --git a/PDP10/pdp10_cpu.c b/PDP10/pdp10_cpu.c index 7611d85b..b203ba4c 100644 --- a/PDP10/pdp10_cpu.c +++ b/PDP10/pdp10_cpu.c @@ -1,6 +1,6 @@ /* pdp10_cpu.c: PDP-10 CPU simulator - Copyright (c) 1993-2001, Robert M. Supnik + Copyright (c) 1993-2002, Robert M. Supnik Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), @@ -25,6 +25,7 @@ cpu KS10 central processor + 30-Dec-01 RMS Added old PC queue 25-Dec-01 RMS Cleaned up sim_inst declarations 07-Dec-01 RMS Revised to use new breakpoint package 21-Nov-01 RMS Implemented ITS 1-proceed hack @@ -128,6 +129,9 @@ #include "pdp10_defs.h" #include +#define PCQ_SIZE 64 /* must be 2**n */ +#define PCQ_MASK (PCQ_SIZE - 1) +#define PCQ_ENTRY pcq[pcq_p = (pcq_p - 1) & PCQ_MASK] = PC #define UNIT_V_MSIZE (UNIT_V_T20V41 + 1) /* dummy mask */ #define UNIT_MSIZE (1 << UNIT_V_MSIZE) @@ -169,7 +173,9 @@ int32 stop_op0 = 0; /* stop on 0 */ int32 rlog = 0; /* extend fixup log */ int32 ind_max = 32; /* nested ind limit */ int32 xct_max = 32; /* nested XCT limit */ -a10 old_PC = 0; /* old PC */ +a10 pcq[PCQ_SIZE] = { 0 }; /* PC queue */ +int32 pcq_p = 0; /* PC queue ptr */ +REG *pcq_r = NULL; /* PC queue reg ptr */ jmp_buf save_env; extern int32 sim_int_char; @@ -351,7 +357,8 @@ REG cpu_reg[] = { { ORDATA (APRLVL, apr_lvl, 3) }, { ORDATA (RLOG, rlog, 10) }, { FLDATA (F1PR, its_1pr, 0) }, - { ORDATA (OLDPC, old_PC, VASIZE), REG_RO }, + { BRDATA (PCQ, pcq, 8, VASIZE, PCQ_SIZE), REG_RO+REG_CIRC }, + { ORDATA (PCQP, pcq_p, 6), REG_HRO }, { DRDATA (INDMAX, ind_max, 8), PV_LEFT + REG_NZ }, { DRDATA (XCTMAX, xct_max, 8), PV_LEFT + REG_NZ }, { FLDATA (ITS, cpu_unit.flags, UNIT_V_ITS), REG_HRO }, @@ -434,7 +441,7 @@ static t_stat jrst_tab[16] = { #define IM ((d10) ea) #define IMS (((d10) ea) << 18) -#define JUMP(x) old_PC = PC, PC = ((a10) (x)) & AMASK +#define JUMP(x) PCQ_ENTRY, PC = ((a10) (x)) & AMASK #define SUBJ(x) CLRF (F_AFI | F_FPD | F_TR); JUMP (x) #define INCPC PC = INCA (PC) @@ -572,7 +579,7 @@ static t_stat jrst_tab[16] = { t_stat sim_instr (void) { -a10 PC; +a10 PC; /* set by setjmp */ int abortval = 0; /* abort value */ /* Restore register state */ @@ -598,6 +605,7 @@ if ((abortval > 0) || pager_pi) { /* stop or pi err? */ abortval = STOP_PAGINT; /* stop for pi err */ saved_PC = pager_PC & AMASK; /* failing instr PC */ set_ac_display (ac_cur); /* set up AC display */ + pcq_r -> qptr = pcq_p; /* update pc q ptr */ return abortval; } /* return to SCP */ /* Page fail - checked against KS10 ucode @@ -2035,6 +2043,9 @@ set_ac_display (ac_cur); pi_eval (); if (M == NULL) M = calloc (MAXMEMSIZE, sizeof (d10)); if (M == NULL) return SCPE_MEM; +pcq_r = find_reg ("PCQ", NULL, dptr); +if (pcq_r) pcq_r -> qptr = 0; +else return SCPE_IERR; sim_brk_types = sim_brk_dflt = SWMASK ('E'); return SCPE_OK; } diff --git a/PDP10/pdp10_defs.h b/PDP10/pdp10_defs.h index 767d356f..98b63e16 100644 --- a/PDP10/pdp10_defs.h +++ b/PDP10/pdp10_defs.h @@ -1,6 +1,6 @@ /* pdp10_defs.h: PDP-10 simulator definitions - Copyright (c) 1993-2001, Robert M Supnik + Copyright (c) 1993-2002, Robert M Supnik Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), @@ -23,8 +23,10 @@ be used in advertising or otherwise to promote the sale, use or other dealings in this Software without prior written authorization from Robert M Supnik. + 22-Apr-02 RMS Removed magtape record length error + 20-Jan-02 RMS Added multiboard DZ11 support 23-Oct-01 RMS New IO page address constants - 19-Oct-01 RMS Added DZ definitions + 19-Oct-01 RMS Added DZ11 definitions 07-Sep-01 RMS Revised for PDP-11 multi-level interrupts 31-Aug-01 RMS Changed int64 to t_int64 for Windoze 29-Aug-01 RMS Corrected models and dates (found by Lars Brinkhoff) @@ -93,9 +95,8 @@ typedef t_int64 d10; /* PDP-10 data (36b) */ #define STOP_IND 8 /* indirection loop */ #define STOP_XCT 9 /* XCT loop */ #define STOP_ILLIOC 10 /* invalid UBA num */ -#define STOP_MTRLNT 11 /* invalid mt rec lnt */ -#define STOP_ASTOP 12 /* address stop */ -#define STOP_UNKNOWN 13 /* unknown stop */ +#define STOP_ASTOP 11 /* address stop */ +#define STOP_UNKNOWN 12 /* unknown stop */ #define PAGE_FAIL -1 /* page fail */ #define INTERRUPT -2 /* interrupt */ #define ABORT(x) longjmp (save_env, (x)) /* abort */ @@ -573,30 +574,51 @@ typedef t_int64 d10; /* PDP-10 data (36b) */ #define IO_UBA3 (3 << IO_V_UBA) #define GET_IOUBA(x) (((x) >> IO_V_UBA) & IO_M_UBA) +/* Device information block */ + +struct pdp_dib { + uint32 enb; /* enabled */ + uint32 ba; /* base addr */ + uint32 lnt; /* length */ + t_stat (*rd)(int32 *dat, int32 ad, int32 md); + t_stat (*wr)(int32 dat, int32 ad, int32 md); }; + +typedef struct pdp_dib DIB; + /* DZ11 parameters */ -#define DZ_MUXES 1 /* # of muxes */ +#define DZ_MUXES 4 /* max # of muxes */ #define DZ_LINES 8 /* lines per mux */ /* I/O page layout */ -#define IOBA_DZ 0760010 /* DZ11 */ -#define IOLN_DZ (010 * DZ_MUXES) -#define IOBA_TCU 0760770 /* TCU150 */ -#define IOLN_TCU 006 -#define IOBA_UBMAP 0763000 /* Unibus map */ -#define IOLN_UBMAP 0100 -#define IOBA_UBCS 0763100 /* Unibus c/s reg */ -#define IOLN_UBCS 001 -#define IOBA_UBMNT 0763101 /* Unibus maint reg */ -#define IOLN_UBMNT 001 -#define IOBA_TU 0772440 /* RH11/tape */ -#define IOLN_TU 034 -#define IOBA_RP 0776700 /* RH11/disk */ +#define IOPAGEBASE 0760000 /* I/O page base */ +#define IOBA_UBMAP 0763000 + +#define IOBA_UBMAP1 (IO_UBA1 + IOBA_UBMAP) /* Unibus 1 map */ +#define IOLN_UBMAP1 0100 +#define IOBA_UBCS1 (IO_UBA1 + 0763100) /* Unibus 1 c/s reg */ +#define IOLN_UBCS1 001 +#define IOBA_UBMNT1 (IO_UBA1 + 0763101) /* Unibus 1 maint reg */ +#define IOLN_UBMNT1 001 +#define IOBA_RP (IO_UBA1 + 0776700) /* RH11/disk */ #define IOLN_RP 050 -#define IOBA_LP20 0775400 /* LP20 */ + +#define IOBA_DZ (IO_UBA3 + 0760010) /* DZ11 */ +#define IOLN_DZ 010 +#define IOBA_TCU (IO_UBA3 + 0760770) /* TCU150 */ +#define IOLN_TCU 006 +#define IOBA_UBMAP3 (IO_UBA3 + IOBA_UBMAP) /* Unibus 3 map */ +#define IOLN_UBMAP3 0100 +#define IOBA_UBCS3 (IO_UBA3 + 0763100) /* Unibus 3 c/s reg */ +#define IOLN_UBCS3 001 +#define IOBA_UBMNT3 (IO_UBA3 + 0763101) /* Unibus 3 maint reg */ +#define IOLN_UBMNT3 001 +#define IOBA_TU (IO_UBA3 + 0772440) /* RH11/tape */ +#define IOLN_TU 034 +#define IOBA_LP20 (IO_UBA3 + 0775400) /* LP20 */ #define IOLN_LP20 020 -#define IOBA_PT 0777550 /* PC11 */ +#define IOBA_PT (IO_UBA3 + 0777550) /* PC11 */ #define IOLN_PT 010 /* Common Unibus CSR flags */ @@ -664,3 +686,10 @@ typedef t_int64 d10; /* PDP-10 data (36b) */ #define IREQ(dv) int_req #define SET_INT(dv) IREQ(dv) = IREQ(dv) | (INT_##dv) #define CLR_INT(dv) IREQ(dv) = IREQ(dv) & ~(INT_##dv) + +/* Function prototypes */ + +t_stat set_addr (UNIT *uptr, int32 val, char *cptr, void *desc); +t_stat show_addr (FILE *st, UNIT *uptr, int32 val, void *desc); +t_stat set_enbdis (UNIT *uptr, int32 val, char *cptr, void *desc); +t_bool dev_conflict (uint32 nba, DIB *curr); diff --git a/PDP10/pdp10_doc.txt b/PDP10/pdp10_doc.txt index 1c9cf60c..d5ed0f55 100644 --- a/PDP10/pdp10_doc.txt +++ b/PDP10/pdp10_doc.txt @@ -1,14 +1,14 @@ To: Users From: Bob Supnik Subj: PDP-10 Simulator Usage -Date: 1-Dec-01 +Date: 15-Jun-2002 COPYRIGHT NOTICE The following copyright notice applies to both the SIMH source and binary: - Original code published in 1993-2001, written by Robert M Supnik - Copyright (c) 1993-2001, Robert M Supnik + Original code published in 1993-2002, written by Robert M Supnik + Copyright (c) 1993-2002, Robert M Supnik Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), @@ -76,13 +76,14 @@ UBA Unibus adapters (translation maps) FE console TIM timer PTR,PTP PC11 paper tape reader/punch -DZ DZ11 8-line terminal multiplexor +DZ DZ11 8-line terminal multiplexor (up to 4) LP20 LP20 line printer RP RH11/RP04/RP05/RP06/RP07/RM03/RM05/RM80 controller with eight drives TU RH11/TM02/TU45 controller with eight drives -The PTR/PTP are initially DISABLEd. The DZ11 can also be DISABLEd. +The PTR/PTP are initially set DISABLED. The DZ11 and LP20 can also be +set DISABLED. The PDP-10 simulator implements several unique stop condition: @@ -99,7 +100,7 @@ The PDP-10 loader supports RIM10B format paper tapes, SAV binary files, and EXE binary files. LOAD switches -r, -s, -e specify RIM10, SAV, EXE format, respectively. If no switch is specified, the LOAD command checks the file extension; .RIM, .SAV, .EXE specify RIM10, SAV, EXE format, respectively. -If no switch specified, and no extension matches, the LOAD command checks +If no switch is specified, and no extension matches, the LOAD command checks the file format to try to determine the file type. 2.1 CPU @@ -146,7 +147,8 @@ control registers for the interrupt system. APRLVL 3 PI level for APR interrupt IND_MAX 8 indirect address nesting limit XCT_MAX 8 execute chaining limit - OLDPC 18 PC prior to last transfer instruction + PCQ[0:63] 18 PC prior to last jump or interrupt; + most recent PC change first WRU 8 interrupt character REG[0:127] 36 fast memory blocks @@ -173,7 +175,7 @@ The Unibus adapters link the system I/O devices to the CPU. Unibus adapter 1 (UBA1) is unit 0, and Unibus adapter 3 is unit 1. The adapter's Unibus map is the memory space of the corresponding unit. -The Unibus Adapter has the following registers: +The Unibus adapter has the following registers: name size comments @@ -194,10 +196,10 @@ The front end has the following registers: name size comments IBUF 8 input buffer - ICOUNT 31 count of input characters + ICOUNT 32 count of input characters ITIME 24 keyboard polling interval OBUF 8 output buffer - OCOUNT 31 count of output characters + OCOUNT 32 count of output characters OTIME 24 console output response time 2.5 Timer (TIM) @@ -205,7 +207,7 @@ The front end has the following registers: The timer (TIM) implements the system timer, the interval timer, and the time of day clock used to get the date and time at system startup. Because most PDP-10 software is not Y2K compliant, the timer implements -one option +one option: SET TIM NOY2K software not Y2K compliant, limit time of day clock to 1999 (default) @@ -243,7 +245,7 @@ The paper tape reader implements these registers: BUSY 1 busy flag (CSR<11>) DONE 1 device done flag (CSR<7>) IE 1 interrupt enable flag (CSR<6>) - POS 31 position in the input file + POS 32 position in the input file TIME 24 time from I/O initiation to interrupt STOP_IOE 1 stop on I/O error @@ -276,7 +278,7 @@ The paper tape punch implements these registers: ERR 1 error flag (CSR<15>) DONE 1 device done flag (CSR<7>) IE 1 interrupt enable flag (CSR<6>) - POS 31 position in the input or output file + POS 32 position in the input or output file TIME 24 time from I/O initiation to interrupt STOP_IOE 1 stop on I/O error @@ -291,11 +293,18 @@ Error handling is as follows: 2.8 DZ11 Terminal Multiplexor (DZ) -The DZ11 is an 8-line terminal multiplexor. The terminal lines perform -input and output through Telnet sessions connected to a user-specified -port. The ATTACH command specifies the port to be used: +The DZ11 is an 8-line terminal multiplexor. Up to 4 DZ11's (32 lines) +are supported. The number of lines can be changed with the command - ATTACH {-am} DZ (cr) -- set up listening port + SET DZ LINES=n set line count to n + +The line count must be a multiple of 8, with a maximum of 32. + +The terminal lines perform input and output through Telnet sessions +connected to a user-specified port. The ATTACH command specifies +the port to be used: + + ATTACH {-am} DZ set up listening port where port is a decimal number between 1 and 65535 that is not being used for other TCP/IP activities. The optional switch -m turns on the DZ11's @@ -305,25 +314,28 @@ modem controls; the optional switch -a turns on active disconnects Once the DZ is attached and the simulator is running, the DZ will listen for connections on the specified port. It assumes that the incoming connections are Telnet connections. The connection remains open until -disconnected either by the simulated program or by the Telnet client. +disconnected by the simulated program, the Telnet client, a SET DZ +DISCONNECT command, or a DETACH DZ command. -The SHOW DZ LINESTATUS command displays the current connections to the DZ. +The SHOW DZ CONNECTIONS command displays the current connections to the DZ. +The SHOW DZ STATISTICS command displays statistics for active connections. +The SET DZ DISCONNECT=linenumber disconnects the specified line. The DZ11 implements these registers: name size comments - CSR 16 control/status register - RBUF 16 receive buffer - LPR 16 line parameter register - TCR 16 transmission control register - MSR 16 modem status register - TDR 16 transmit data register - SAENB 1 silo alarm enabled + CSR[0:3] 16 control/status register, boards 0-3 + RBUF[0:3] 16 receive buffer, boards 0-3 + LPR[0:3] 16 line parameter register, boards 0-3 + TCR[0:3] 16 transmission control register, boards 0-3 + MSR[0:3] 16 modem status register, boards 0-3 + TDR[0:3] 16 transmit data register, boards 0-3 + SAENB[0:3] 1 silo alarm enabled, boards 0-3 + RXINT 4 receive interrupts, boards 3..0 + TXINT 4 transmit interrupts, boards 3..0 MDMTCL 1 modem control enabled AUTODS 1 autodisconnect enabled - RPOS0..7 32 count of characters received - TPOS0..7 32 count of characters transmitted The DZ11 does not support save and restore. All open connections are lost when the simulator shuts down or the DZ is detached. @@ -340,7 +352,7 @@ RP options include the ability to set units write enabled or write locked, to set the drive type to one of six disk types, or autosize: SET RPn LOCKED set unit n write locked - SET RPn ENABLED set unit n write enabled + SET RPn WRITEENABLED set unit n write enabled SET RPn RM03 set type to RM03 SET RPn RM05 set type to RM05 SET RPn RM80 set type to RM80 @@ -350,8 +362,9 @@ to set the drive type to one of six disk types, or autosize: SET RPn AUTOSIZE set type based on file size at attach The type options can be used only when a unit is not attached to a file. -Note that TOPS-10 V7.03 only supported the RP06 and RM03; V7.04 added -support for the RP07. Units can be REMOVEd or ADDed to the configuration. +Note that TOPS-10 V7.03 supported only the RP06 and RM03; V7.04 added +support for the RP07. TOPS-20 V4.1 also supported only the RP06 and +RM03. Units can be set ONLINE or OFFLINE. The RP controller implements these registers: @@ -399,9 +412,9 @@ TM02 formatter and up to eight TU45 drives. Magnetic tape options include the ability to make units write enabled or locked. SET TUn LOCKED set unit n write locked - SET TUn ENABLED set unit n write enabled + SET TUn WRITEENABLED set unit n write enabled -Units can also be REMOVEd or ADDed to the configuration. +Units can also be set ONLINE or OFFLINE. The magnetic tape controller implements these registers: @@ -424,7 +437,7 @@ The magnetic tape controller implements these registers: STOP_IOE 1 stop on I/O error TIME 24 delay UST[0:7] 16 unit status, units 0-7 - POS[0:7] 31 position, units 0-7 + POS[0:7] 32 position, units 0-7 Error handling is as follows: @@ -440,7 +453,7 @@ Error handling is as follows: 2.11 LP20 DMA Line Printer (LP20) The LP20 is a DMA-based line printer controller. There is one -line printer option to clear the vertical forms unit (VFU). +line printer option to clear the vertical forms unit (VFU): SET LP20 VFUCLEAR clear the vertical forms unit @@ -464,7 +477,7 @@ The LP20 implements these registers: ERR 1 error flag DONE 1 done flag IE 1 interrupt enable flag - POS 31 position in output file + POS 32 position in output file TIME 24 response time STOP_IOE 1 stop on I/O error TXRAM[0:255] 12 translation RAM diff --git a/PDP10/pdp10_dz.c b/PDP10/pdp10_dz.c index fe09d12d..4859cbd5 100644 --- a/PDP10/pdp10_dz.c +++ b/PDP10/pdp10_dz.c @@ -1,6 +1,6 @@ /* pdp10_dz.c: DZ11 terminal multiplexor simulator - Copyright (c) 1993-2001, Robert M Supnik + Copyright (c) 1993-2002, Robert M Supnik Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), diff --git a/PDP10/pdp10_fe.c b/PDP10/pdp10_fe.c index 9ba9cc30..fc820cf1 100644 --- a/PDP10/pdp10_fe.c +++ b/PDP10/pdp10_fe.c @@ -1,6 +1,6 @@ /* pdp10_fe.c: PDP-10 front end (console terminal) simulator - Copyright (c) 1993-2001, Robert M Supnik + Copyright (c) 1993-2002, Robert M Supnik Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), @@ -25,6 +25,7 @@ fe KS10 console front end + 30-May-02 RMS Widened COUNT to 32b 30-Nov-01 RMS Added extended SET/SHOW support 23-Oct-01 RMS New IO page address constants 07-Sep-01 RMS Moved function prototypes @@ -57,10 +58,10 @@ UNIT fe_unit[] = { REG fe_reg[] = { { ORDATA (IBUF, fei_unit.buf, 8) }, - { DRDATA (ICOUNT, fei_unit.pos, 31), REG_RO + PV_LEFT }, + { DRDATA (ICOUNT, fei_unit.pos, 32), REG_RO + PV_LEFT }, { DRDATA (ITIME, fei_unit.wait, 24), REG_NZ + PV_LEFT }, { ORDATA (OBUF, feo_unit.buf, 8) }, - { DRDATA (OCOUNT, feo_unit.pos, 31), REG_RO + PV_LEFT }, + { DRDATA (OCOUNT, feo_unit.pos, 32), REG_RO + PV_LEFT }, { DRDATA (OTIME, feo_unit.wait, 24), REG_NZ + PV_LEFT }, { NULL } }; diff --git a/PDP10/pdp10_ksio.c b/PDP10/pdp10_ksio.c index e7e70e24..f363a06b 100644 --- a/PDP10/pdp10_ksio.c +++ b/PDP10/pdp10_ksio.c @@ -1,6 +1,6 @@ /* pdp10_ksio.c: PDP-10 KS10 I/O subsystem simulator - Copyright (c) 1993-2001, Robert M Supnik + Copyright (c) 1993-2002, Robert M Supnik Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), @@ -25,6 +25,8 @@ uba Unibus adapters + 25-Jan-02 RMS Revised for multiple DZ11's + 06-Jan-02 RMS Revised enable/disable support 23-Sep-01 RMS New IO page address constants 07-Sep-01 RMS Revised device disable mechanism 25-Aug-01 RMS Enabled DZ11 @@ -94,26 +96,17 @@ extern d10 *ac_cur; extern d10 pager_word; extern int32 flags, pi_l2bit[8]; extern UNIT cpu_unit; +extern FILE *sim_log; extern jmp_buf save_env; extern d10 Read (a10 ea); extern void pi_eval (); -extern t_stat dz_rd (int32 *data, int32 addr, int32 access); -extern t_stat dz_wr (int32 data, int32 addr, int32 access); -extern int32 dz_enb; -extern t_stat pt_rd (int32 *data, int32 addr, int32 access); -extern t_stat pt_wr (int32 data, int32 addr, int32 access); -extern int32 pt_enb; -extern t_stat lp20_rd (int32 *data, int32 addr, int32 access); -extern t_stat lp20_wr (int32 data, int32 addr, int32 access); -extern int32 lp20_inta (void); -extern t_stat rp_rd (int32 *data, int32 addr, int32 access); -extern t_stat rp_wr (int32 data, int32 addr, int32 access); +extern DIB dz_dib, pt_dib, lp20_dib, rp_dib, tu_dib, tcu_dib; extern int32 rp_inta (void); -extern t_stat tu_rd (int32 *data, int32 addr, int32 access); -extern t_stat tu_wr (int32 data, int32 addr, int32 access); extern int32 tu_inta (void); -extern t_stat tcu_rd (int32 *data, int32 addr, int32 access); +extern int32 lp20_inta (void); +extern int32 dz_rxinta (void); +extern int32 dz_txinta (void); t_stat ubmap_rd (int32 *data, int32 addr, int32 access); t_stat ubmap_wr (int32 data, int32 addr, int32 access); t_stat ubs_rd (int32 *data, int32 addr, int32 access); @@ -125,6 +118,7 @@ t_stat uba_dep (t_value val, t_addr addr, UNIT *uptr, int32 sw); t_stat uba_reset (DEVICE *dptr); d10 ReadIO (a10 ea); void WriteIO (a10 ea, d10 val, int32 mode); +t_bool dev_conflict (uint32 nba, DIB *curr); /* Unibus adapter data structures @@ -133,6 +127,14 @@ void WriteIO (a10 ea, d10 val, int32 mode); uba_reg UBA register list */ +DIB ubmp1_dib = { 1, IOBA_UBMAP1, IOLN_UBMAP1, &ubmap_rd, &ubmap_wr }; +DIB ubmp3_dib = { 1, IOBA_UBMAP3, IOLN_UBMAP3, &ubmap_rd, &ubmap_wr }; +DIB ubcs1_dib = { 1, IOBA_UBCS1, IOLN_UBCS1, &ubs_rd, &ubs_wr }; +DIB ubcs3_dib = { 1, IOBA_UBCS3, IOLN_UBCS3, &ubs_rd, &ubs_wr }; +DIB ubmn1_dib = { 1, IOBA_UBMNT1, IOLN_UBMNT1, &rd_zro, &wr_nop }; +DIB ubmn3_dib = { 1, IOBA_UBMNT3, IOLN_UBMNT3, &rd_zro, &wr_nop }; +DIB msys_dib = { 1, 00100000, 00100001, &rd_zro, &wr_nop }; + UNIT uba_unit[] = { { UDATA (NULL, UNIT_FIX, UMAP_MEMSIZE) }, { UDATA (NULL, UNIT_FIX, UMAP_MEMSIZE) } }; @@ -151,50 +153,28 @@ DEVICE uba_dev = { /* PDP-11 I/O structures */ -struct iolink { /* I/O page linkage */ - int32 low; /* low I/O addr */ - int32 high; /* high I/O addr */ - int32 *enb; /* enable flag */ - t_stat (*read)(); /* read routine */ - t_stat (*write)(); }; /* write routine */ - -/* Table of I/O devices and corresponding read/write routines - The expected Unibus adapter number is included as the high 2 bits */ - -struct iolink iotable[] = { - { IO_UBA1+IOBA_RP, IO_UBA1+IOBA_RP+IOLN_RP, - NULL, &rp_rd, &rp_wr }, /* disk */ - { IO_UBA3+IOBA_TU, IO_UBA3+IOBA_TU+IOLN_TU, - NULL, &tu_rd, &tu_wr }, /* mag tape */ - { IO_UBA3+IOBA_DZ, IO_UBA3+IOBA_DZ+IOLN_DZ, - &dz_enb, &dz_rd, &dz_wr }, /* terminal mux */ - { IO_UBA3+IOBA_LP20, IO_UBA3+IOBA_LP20+IOLN_LP20, - NULL, &lp20_rd, &lp20_wr }, /* line printer */ - { IO_UBA3+IOBA_PT, IO_UBA3+IOBA_PT+IOLN_PT, - &pt_enb, &pt_rd, &pt_wr }, /* paper tape */ - { IO_UBA1+IOBA_UBMAP, IO_UBA1+IOBA_UBMAP+IOLN_UBMAP, - NULL, &ubmap_rd, &ubmap_wr }, /* Unibus 1 map */ - { IO_UBA3+IOBA_UBMAP, IO_UBA3+IOBA_UBMAP+IOLN_UBMAP, - NULL, &ubmap_rd, &ubmap_wr }, /* Unibus 3 map */ - { IO_UBA1+IOBA_UBCS, IO_UBA1+IOBA_UBCS+IOLN_UBCS, - NULL, &ubs_rd, &ubs_wr }, /* Unibus 1 c/s */ - { IO_UBA3+IOBA_UBCS, IO_UBA3+IOBA_UBCS+IOLN_UBCS, - NULL, &ubs_rd, &ubs_wr }, /* Unibus 3 c/s */ - { IO_UBA1+IOBA_UBMNT, IO_UBA1+IOBA_UBMNT+IOLN_UBMNT, - NULL, &rd_zro, &wr_nop }, /* Unibus 1 maint */ - { IO_UBA3+IOBA_UBMNT, IO_UBA3+IOBA_UBMNT+IOLN_UBMNT, - NULL, &rd_zro, &wr_nop }, /* Unibus 3 maint */ - { IO_UBA3+IOBA_TCU, IO_UBA3+IOBA_TCU+IOLN_TCU, - NULL, &tcu_rd, &wr_nop }, /* TCU150 */ - { 00100000, 00100000, NULL, &rd_zro, &wr_nop }, /* Mem sys stat */ - { 0, 0, 0, NULL, NULL } }; +DIB *dib_tab[] = { + &rp_dib, + &tu_dib, + &dz_dib, + &lp20_dib, + &pt_dib, + &tcu_dib, + &ubmp1_dib, + &ubmp3_dib, + &ubcs1_dib, + &ubcs3_dib, + &ubmn1_dib, + &ubmn3_dib, + &msys_dib, + NULL }; /* Interrupt request to interrupt action map */ int32 (*int_ack[32])() = { /* int ack routines */ NULL, NULL, NULL, NULL, NULL, NULL, &rp_inta, &tu_inta, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + &dz_rxinta, &dz_txinta, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, &lp20_inta, NULL, NULL, NULL, NULL, NULL }; /* Interrupt request to vector map */ @@ -393,14 +373,14 @@ return; d10 ReadIO (a10 ea) { -int32 n, pa, val; -struct iolink *p; +uint32 pa = (uint32) ea; +int32 i, n, val; +DIB *dibp; -pa = (int32) ea; /* cvt addr to 32b */ -for (p = &iotable[0]; p -> low != 0; p++ ) { - if ((pa >= p -> low) && (pa < p -> high) && - ((p -> enb == NULL) || *p -> enb)) { - p -> read (&val, pa, READ); +for (i = 0; dibp = dib_tab[i]; i++ ) { + if (dibp -> enb && (pa >= dibp -> ba) && + (pa < (dibp -> ba + dibp -> lnt))) { + dibp -> rd (&val, pa, READ); pi_eval (); return ((d10) val); } } UBNXM_FAIL (pa, READ); @@ -408,14 +388,14 @@ UBNXM_FAIL (pa, READ); void WriteIO (a10 ea, d10 val, int32 mode) { -int32 n, pa; -struct iolink *p; +uint32 pa = (uint32) ea; +int32 i, n; +DIB *dibp; -pa = (int32) ea; /* cvt addr to 32b */ -for (p = &iotable[0]; p -> low != 0; p++ ) { - if ((pa >= p -> low) && (pa < p -> high) && - ((p -> enb == NULL) || *p -> enb)) { - p -> write ((int32) val, pa, mode); +for (i = 0; dibp = dib_tab[i]; i++ ) { + if (dibp -> enb && (pa >= dibp -> ba) && + (pa < (dibp -> ba + dibp -> lnt))) { + dibp -> wr ((int32) val, pa, mode); pi_eval (); return; } } UBNXM_FAIL (pa, mode); @@ -549,3 +529,87 @@ for (uba = 0; uba < UBANUM; uba++) { pi_eval (); return SCPE_OK; } + +/* Change device number for a device */ + +t_stat set_addr (UNIT *uptr, int32 val, char *cptr, void *desc) +{ +DIB *dibp; +uint32 newba; +t_stat r; + +if (cptr == NULL) return SCPE_ARG; +if ((val == 0) || (desc == NULL)) return SCPE_IERR; +dibp = (DIB *) desc; +newba = (uint32) get_uint (cptr, 8, PAMASK, &r); /* get new */ +if ((r != SCPE_OK) || (newba == dibp -> ba)) return r; +if ((newba & AMASK) <= IOPAGEBASE) return SCPE_ARG; /* must be > 0 */ +if (newba % ((uint32) val)) return SCPE_ARG; /* check modulus */ +if (GET_IOUBA (newba) != GET_IOUBA (dibp -> ba)) return SCPE_ARG; +if (dev_conflict (newba, dibp)) return SCPE_OK; +dibp -> ba = newba; /* store */ +return SCPE_OK; +} + +/* Show device address */ + +t_stat show_addr (FILE *st, UNIT *uptr, int32 val, void *desc) +{ +DIB *dibp; + +if (desc == NULL) return SCPE_IERR; +dibp = (DIB *) desc; +if (dibp -> ba <= IOPAGEBASE) return SCPE_IERR; +fprintf (st, "address=%07o", dibp -> ba); +if (dibp -> lnt > 1) + fprintf (st, "-%07o", dibp -> ba + dibp -> lnt - 1); +return SCPE_OK; +} + +/* Enable or disable a device */ + +t_stat set_enbdis (UNIT *uptr, int32 val, char *cptr, void *desc) +{ +int32 i; +DEVICE *dptr; +DIB *dibp; +UNIT *up; + +if (cptr != NULL) return SCPE_ARG; +if ((uptr == NULL) || (desc == NULL)) return SCPE_IERR; +dptr = find_dev_from_unit (uptr); /* find device */ +if (dptr == NULL) return SCPE_IERR; +dibp = (DIB *) desc; +if ((val ^ dibp -> enb) == 0) return SCPE_OK; /* enable chg? */ +if (val) { /* enable? */ + if (dev_conflict (dibp -> ba, dibp)) return SCPE_OK; } +else { /* disable */ + for (i = 0; i < dptr -> numunits; i++) { /* check units */ + up = (dptr -> units) + i; + if ((up -> flags & UNIT_ATT) || sim_is_active (up)) + return SCPE_NOFNC; } } +dibp -> enb = val; +if (dptr -> reset) return dptr -> reset (dptr); +else return SCPE_OK; +} + +/* Test for conflict in device addresses */ + +t_bool dev_conflict (uint32 nba, DIB *curr) +{ +uint32 i, end; +DIB *dibp; + +end = nba + curr -> lnt - 1; /* get end */ +for (i = 0; dibp = dib_tab[i]; i++) { /* loop thru dev */ + if (!dibp -> enb || (dibp == curr)) continue; /* skip disabled */ + if (((nba >= dibp -> ba) && + (nba < (dibp -> ba + dibp -> lnt))) || + ((end >= dibp -> ba) && + (end < (dibp -> ba + dibp -> lnt)))) { + printf ("Device address conflict at %07o\n", dibp -> ba); + if (sim_log) fprintf (sim_log, + "Device number conflict at %07o\n", dibp -> ba); + return TRUE; } } +return FALSE; +} diff --git a/PDP10/pdp10_lp20.c b/PDP10/pdp10_lp20.c index 3d2eced3..5c709a6c 100644 --- a/PDP10/pdp10_lp20.c +++ b/PDP10/pdp10_lp20.c @@ -1,6 +1,6 @@ /* pdp10_lp20.c: PDP-10 LP20 line printer simulator - Copyright (c) 1993-2001, Robert M Supnik + Copyright (c) 1993-2002, Robert M Supnik Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), @@ -25,6 +25,8 @@ lp20 line printer + 30-May-02 RMS Widened POS to 32b + 06-Jan-02 RMS Added enable/disable support 30-Nov-01 RMS Added extended SET/SHOW support */ @@ -150,6 +152,9 @@ int32 lp20_irq = 0; /* int request */ int32 lp20_stopioe = 0; /* stop on error */ int16 txram[TX_SIZE] = { 0 }; /* translation RAM */ int16 davfu[DV_SIZE] = { 0 }; /* DAVFU */ + +t_stat lp20_rd (int32 *data, int32 pa, int32 access); +t_stat lp20_wr (int32 data, int32 pa, int32 access); t_stat lp20_svc (UNIT *uptr); t_stat lp20_reset (DEVICE *dptr); t_stat lp20_attach (UNIT *uptr, char *ptr); @@ -167,6 +172,8 @@ void update_lpcs (int32 flg); lp20_reg LPT register list */ +DIB lp20_dib = { 1, IOBA_LP20, IOLN_LP20, &lp20_rd, &lp20_wr }; + UNIT lp20_unit = { UDATA (&lp20_svc, UNIT_SEQ+UNIT_ATTABLE, 0), SERIAL_OUT_WAIT }; @@ -188,7 +195,7 @@ REG lp20_reg[] = { { FLDATA (ERR, lpcsa, CSR_V_ERR) }, { FLDATA (DONE, lpcsa, CSR_V_DONE) }, { FLDATA (IE, lpcsa, CSR_V_IE) }, - { DRDATA (POS, lp20_unit.pos, 31), PV_LEFT }, + { DRDATA (POS, lp20_unit.pos, 32), PV_LEFT }, { DRDATA (TIME, lp20_unit.wait, 24), PV_LEFT }, { FLDATA (STOP_IOE, lp20_stopioe, 0) }, { BRDATA (TXRAM, txram, 8, 12, TX_SIZE) }, @@ -197,6 +204,12 @@ REG lp20_reg[] = { MTAB lp20_mod[] = { { UNIT_DUMMY, 0, NULL, "VFUCLEAR", &lp20_clear_vfu }, + { MTAB_XTD|MTAB_VDV, 004, "ADDRESS", "ADDRESS", + &set_addr, &show_addr, &lp20_dib }, + { MTAB_XTD|MTAB_VDV, 1, NULL, "ENABLED", + &set_enbdis, NULL, &lp20_dib }, + { MTAB_XTD|MTAB_VDV, 0, NULL, "DISABLED", + &set_enbdis, NULL, &lp20_dib }, { 0 } }; DEVICE lp20_dev = { diff --git a/PDP10/pdp10_mdfp.c b/PDP10/pdp10_mdfp.c index cab690ad..a7945268 100644 --- a/PDP10/pdp10_mdfp.c +++ b/PDP10/pdp10_mdfp.c @@ -1,6 +1,6 @@ /* pdp10_mdfp.c: PDP-10 multiply/divide and floating point simulator - Copyright (c) 1993-2001, Robert M Supnik + Copyright (c) 1993-2002, Robert M Supnik Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), diff --git a/PDP10/pdp10_pag.c b/PDP10/pdp10_pag.c index 924b7d3b..77d41637 100644 --- a/PDP10/pdp10_pag.c +++ b/PDP10/pdp10_pag.c @@ -1,6 +1,6 @@ /* pdp10_pag.c: PDP-10 paging subsystem simulator - Copyright (c) 1993-2001, Robert M Supnik + Copyright (c) 1993-2002, Robert M Supnik Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), diff --git a/PDP10/pdp10_pt.c b/PDP10/pdp10_pt.c index 224b3b51..0b9017ed 100644 --- a/PDP10/pdp10_pt.c +++ b/PDP10/pdp10_pt.c @@ -1,6 +1,6 @@ /* pdp10_pt.c: PDP-10 Unibus paper tape reader/punch simulator - Copyright (c) 1993-2001, Robert M Supnik + Copyright (c) 1993-2002, Robert M Supnik Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), @@ -26,6 +26,8 @@ ptr paper tape reader ptp paper tape punch + 30-May-02 RMS Widened POS to 32b + 06-Jan-02 RMS Revised enable/disable support 29-Nov-01 RMS Added read only unit support 07-Sep-01 RMS Revised disable mechanism */ @@ -42,7 +44,9 @@ int32 ptr_csr = 0; /* control/status */ int32 ptr_stopioe = 0; /* stop on error */ int32 ptp_csr = 0; /* control/status */ int32 ptp_stopioe = 0; /* stop on error */ -int32 pt_enb = 0; /* device enable */ + +t_stat pt_rd (int32 *data, int32 PA, int32 access); +t_stat pt_wr (int32 data, int32 PA, int32 access); t_stat ptr_svc (UNIT *uptr); t_stat ptp_svc (UNIT *uptr); t_stat ptr_reset (DEVICE *dptr); @@ -59,6 +63,8 @@ t_stat ptp_detach (UNIT *uptr); ptr_reg PTR register list */ +DIB pt_dib = { 0, IOBA_PT, IOLN_PT, &pt_rd, &pt_wr }; + UNIT ptr_unit = { UDATA (&ptr_svc, UNIT_SEQ+UNIT_ATTABLE+UNIT_ROABLE, 0), SERIAL_IN_WAIT }; @@ -71,14 +77,23 @@ REG ptr_reg[] = { { FLDATA (BUSY, ptr_csr, CSR_V_BUSY) }, { FLDATA (DONE, ptr_csr, CSR_V_DONE) }, { FLDATA (IE, ptr_csr, CSR_V_IE) }, - { DRDATA (POS, ptr_unit.pos, 31), PV_LEFT }, + { DRDATA (POS, ptr_unit.pos, 32), PV_LEFT }, { DRDATA (TIME, ptr_unit.wait, 24), PV_LEFT }, { FLDATA (STOP_IOE, ptr_stopioe, 0) }, - { FLDATA (*DEVENB, pt_enb, 0), REG_HRO }, + { FLDATA (*DEVENB, pt_dib.enb, 0), REG_HRO }, { NULL } }; +MTAB ptr_mod[] = { + { MTAB_XTD|MTAB_VDV, 0, "ADDRESS", NULL, + NULL, &show_addr, &pt_dib }, + { MTAB_XTD|MTAB_VDV, 1, NULL, "ENABLED", + &set_enbdis, NULL, &pt_dib }, + { MTAB_XTD|MTAB_VDV, 0, NULL, "DISABLED", + &set_enbdis, NULL, &pt_dib }, + { 0 } }; + DEVICE ptr_dev = { - "PTR", &ptr_unit, ptr_reg, NULL, + "PTR", &ptr_unit, ptr_reg, ptr_mod, 1, 10, 31, 1, 8, 8, NULL, NULL, &ptr_reset, NULL, &ptr_attach, &ptr_detach }; @@ -100,14 +115,23 @@ REG ptp_reg[] = { { FLDATA (ERR, ptp_csr, CSR_V_ERR) }, { FLDATA (DONE, ptp_csr, CSR_V_DONE) }, { FLDATA (IE, ptp_csr, CSR_V_IE) }, - { DRDATA (POS, ptp_unit.pos, 31), PV_LEFT }, + { DRDATA (POS, ptp_unit.pos, 32), PV_LEFT }, { DRDATA (TIME, ptp_unit.wait, 24), PV_LEFT }, { FLDATA (STOP_IOE, ptp_stopioe, 0) }, - { FLDATA (*DEVENB, pt_enb, 0), REG_HRO }, + { FLDATA (*DEVENB, pt_dib.enb, 0), REG_HRO }, { NULL } }; +MTAB ptp_mod[] = { + { MTAB_XTD|MTAB_VDV, 0, "ADDRESS", NULL, + NULL, &show_addr, &pt_dib }, + { MTAB_XTD|MTAB_VDV, 1, NULL, "ENABLED", + &set_enbdis, NULL, &pt_dib }, + { MTAB_XTD|MTAB_VDV, 0, NULL, "DISABLED", + &set_enbdis, NULL, &pt_dib }, + { 0 } }; + DEVICE ptp_dev = { - "PTP", &ptp_unit, ptp_reg, NULL, + "PTP", &ptp_unit, ptp_reg, ptp_mod, 1, 10, 31, 1, 8, 8, NULL, NULL, &ptp_reset, NULL, &ptp_attach, &ptp_detach }; diff --git a/PDP10/pdp10_rp.c b/PDP10/pdp10_rp.c index b471acfd..2e3d47df 100644 --- a/PDP10/pdp10_rp.c +++ b/PDP10/pdp10_rp.c @@ -1,6 +1,6 @@ /* pdp10_rp.c - RH11/RP04/05/06/07 RM02/03/05/80 "Massbus" disk controller - Copyright (c) 1993-2001, Robert M Supnik + Copyright (c) 1993-2002, Robert M Supnik Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), @@ -339,14 +339,16 @@ int reg_in_drive[32] = { 0, 0, 0, 1, 0, 1, 1, 0, 1, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; -void update_rpcs (int32 flags, int32 drv); -void rp_go (int32 drv, int32 fnc); -t_stat rp_set_size (UNIT *uptr, int32 val, char *cptr, void *desc); +t_stat rp_rd (int32 *data, int32 PA, int32 access); +t_stat rp_wr (int32 data, int32 PA, int32 access); t_stat rp_svc (UNIT *uptr); t_stat rp_reset (DEVICE *dptr); t_stat rp_boot (int32 unitno); t_stat rp_attach (UNIT *uptr, char *cptr); t_stat rp_detach (UNIT *uptr); +void update_rpcs (int32 flags, int32 drv); +void rp_go (int32 drv, int32 fnc); +t_stat rp_set_size (UNIT *uptr, int32 val, char *cptr, void *desc); /* RP data structures @@ -356,6 +358,8 @@ t_stat rp_detach (UNIT *uptr); rp_mod RP modifier list */ +DIB rp_dib = { 1, IOBA_RP, IOLN_RP, &rp_rd, &rp_wr }; + UNIT rp_unit[] = { { UDATA (&rp_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+ UNIT_ROABLE+(RP06_DTYPE << UNIT_V_DTYPE), RP06_SIZE) }, @@ -406,7 +410,7 @@ REG rp_reg[] = { { NULL } }; MTAB rp_mod[] = { - { UNIT_WLK, 0, "write enabled", "ENABLED", NULL }, + { UNIT_WLK, 0, "write enabled", "WRITEENABLED", NULL }, { UNIT_WLK, UNIT_WLK, "write locked", "LOCKED", NULL }, { (UNIT_DTYPE+UNIT_ATT), (RM03_DTYPE << UNIT_V_DTYPE) + UNIT_ATT, "RM03", NULL, NULL }, @@ -446,6 +450,8 @@ MTAB rp_mod[] = { NULL, "RM05", &rp_set_size }, { (UNIT_AUTO+UNIT_DTYPE), (RP07_DTYPE << UNIT_V_DTYPE), NULL, "RP07", &rp_set_size }, + { MTAB_XTD|MTAB_VDV, 0, "ADDRESS", NULL, + NULL, &show_addr, &rp_dib }, { 0 } }; DEVICE rp_dev = { diff --git a/PDP10/pdp10_sys.c b/PDP10/pdp10_sys.c index a8cc6f5f..30b8ff19 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-2001, Robert M Supnik + Copyright (c) 1993-2002, Robert M Supnik Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), @@ -23,6 +23,7 @@ be used in advertising or otherwise to promote the sale, use or other dealings in this Software without prior written authorization from Robert M Supnik. + 22-Apr-02 RMS Removed magtape record length error 17-Sep-01 RMS Removed multiconsole support 25-Aug-01 RMS Enabled DZ11 27-May-01 RMS Added multiconsole support @@ -72,9 +73,9 @@ DEVICE *sim_devices[] = { &ptr_dev, &ptp_dev, &lp20_dev, - &dz_dev, &rp_dev, &tu_dev, + &dz_dev, NULL }; const char *sim_stop_messages[] = { @@ -89,7 +90,6 @@ const char *sim_stop_messages[] = { "Nested indirect address limit exceeded", "Nested XCT limit exceeded", "Invalid I/O controller", - "Invalid magtape record length", "Address stop", "Panic stop" }; diff --git a/PDP10/pdp10_tim.c b/PDP10/pdp10_tim.c index 5ac77977..1c13e7f5 100644 --- a/PDP10/pdp10_tim.c +++ b/PDP10/pdp10_tim.c @@ -1,6 +1,6 @@ /* pdp10_tim.c: PDP-10 tim subsystem simulator - Copyright (c) 1993-2001, Robert M Supnik + Copyright (c) 1993-2002, Robert M Supnik Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), @@ -25,6 +25,7 @@ tim timer subsystem + 06-Jan-02 RMS Added enable/disable support 02-Dec-01 RMS Fixed bug in ITS PC sampling (found by Dave Conroy) 31-Aug-01 RMS Changed int64 to t_int64 for Windoze 17-Jul-01 RMS Moved function prototype @@ -54,6 +55,8 @@ d10 quant = 0; /* ITS quantum */ int32 diagflg = 0; /* diagnostics? */ int32 tmxr_poll = TIM_DELAY * DZ_MULT; /* term mux poll */ +t_stat tcu_rd (int32 *data, int32 PA, int32 access); +extern t_stat wr_nop (int32 data, int32 PA, int32 access); t_stat tim_svc (UNIT *uptr); t_stat tim_reset (DEVICE *dptr); extern d10 Read (a10 ea, int32 prv); @@ -69,6 +72,8 @@ extern int32 pi_eval (void); tim_reg TIM register list */ +DIB tcu_dib = { 1, IOBA_TCU, IOLN_TCU, &tcu_rd, &wr_nop }; + UNIT tim_unit = { UDATA (&tim_svc, 0, 0), TIM_DELAY }; REG tim_reg[] = { @@ -84,6 +89,12 @@ REG tim_reg[] = { MTAB tim_mod[] = { { UNIT_Y2K, 0, "non Y2K OS", "NOY2K", NULL }, { UNIT_Y2K, UNIT_Y2K, "Y2K OS", "Y2K", NULL }, + { MTAB_XTD|MTAB_VDV, 000, "ADDRESS", NULL, + NULL, &show_addr, &tcu_dib }, + { MTAB_XTD|MTAB_VDV, 1, NULL, "ENABLED", + &set_enbdis, NULL, &tcu_dib }, + { MTAB_XTD|MTAB_VDV, 0, NULL, "DISABLED", + &set_enbdis, NULL, &tcu_dib }, { 0 } }; DEVICE tim_dev = { diff --git a/PDP10/pdp10_tu.c b/PDP10/pdp10_tu.c index f5a6987a..ff2dce3d 100644 --- a/PDP10/pdp10_tu.c +++ b/PDP10/pdp10_tu.c @@ -1,6 +1,6 @@ /* pdp10_tu.c - PDP-10 RH11/TM03/TU45 magnetic tape simulator - Copyright (c) 1993-2001, Robert M Supnik + Copyright (c) 1993-2002, Robert M Supnik Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), @@ -25,6 +25,9 @@ tu RH11/TM03/TU45 magtape + 30-May-02 RMS Widened POS to 32b + 22-Apr-02 RMS Changed record length error code + 06-Jan-02 RMS Revised enable/disable support 30-Nov-01 RMS Added read only unit, extended SET/SHOW support 24-Nov-01 RMS Changed POS, FLG, UST to arrays 23-Oct-01 RMS Fixed bug in error interrupts @@ -296,6 +299,8 @@ int fmt_test[16] = { /* fmt bytes/10 wd */ int den_test[8] = { /* valid densities */ 0, 0, 0, 1, 1, 0, 0, 0 }; +t_stat tu_rd (int32 *data, int32 PA, int32 access); +t_stat tu_wr (int32 data, int32 PA, int32 access); t_stat tu_svc (UNIT *uptr); t_stat tu_reset (DEVICE *dptr); t_stat tu_attach (UNIT *uptr, char *cptr); @@ -313,6 +318,8 @@ t_stat tu_vlock (UNIT *uptr, int32 val, char *cptr, void *desc); tu_mod TU modifier list */ +DIB tu_dib = { 1, IOBA_TU, IOLN_TU, &tu_rd, &tu_wr }; + UNIT tu_unit[] = { { UDATA (&tu_svc, UNIT_ATTABLE+UNIT_DISABLE+UNIT_ROABLE, 0) }, { UDATA (&tu_svc, UNIT_ATTABLE+UNIT_DISABLE+UNIT_ROABLE, 0) }, @@ -342,7 +349,7 @@ REG tu_reg[] = { { FLDATA (STOP_IOE, tu_stopioe, 0) }, { DRDATA (TIME, tu_time, 24), PV_LEFT }, { URDATA (UST, tu_unit[0].USTAT, 8, 17, 0, TU_NUMDR, 0) }, - { URDATA (POS, tu_unit[0].pos, 8, 31, 0, + { URDATA (POS, tu_unit[0].pos, 8, 32, 0, TU_NUMDR, PV_LEFT | REG_RO) }, { URDATA (FLG, tu_unit[0].flags, 8, UNIT_W_UF, UNIT_V_UF - 1, TU_NUMDR, REG_HRO) }, @@ -350,8 +357,10 @@ REG tu_reg[] = { { NULL } }; MTAB tu_mod[] = { - { UNIT_WLK, 0, "write enabled", "ENABLED", &tu_vlock }, + { UNIT_WLK, 0, "write enabled", "WRITEENABLED", &tu_vlock }, { UNIT_WLK, UNIT_WLK, "write locked", "LOCKED", &tu_vlock }, + { MTAB_XTD|MTAB_VDV, 0, "ADDRESS", NULL, + NULL, &show_addr, &tu_dib }, { 0 } }; DEVICE tu_dev = { @@ -763,7 +772,7 @@ case FNC_WCHKF: /* wcheck = read */ tufs = tufs | FS_TMK; uptr -> pos = uptr -> pos + sizeof (t_mtrlnt); break; } - if (tbc > XBUFLNT) return STOP_MTRLNT; /* bad rec length? */ + if (tbc > XBUFLNT) return SCPE_MTRLNT; /* bad rec length? */ i = fxread (xbuf, sizeof (int8), tbc, uptr -> fileref); for ( ; i < tbc + 4; i++) xbuf[i] = 0; /* fill/pad with 0's */ err = ferror (uptr -> fileref); @@ -825,7 +834,7 @@ case FNC_WCHKR: /* wcheck = read */ tufs = tufs | FS_TMK; uptr -> pos = uptr -> pos - sizeof (t_mtrlnt); break; } - if (tbc > XBUFLNT) return STOP_MTRLNT; /* bad rec length? */ + if (tbc > XBUFLNT) return SCPE_MTRLNT; /* bad rec length? */ fseek (uptr -> fileref, uptr -> pos - sizeof (t_mtrlnt) - ((tbc + 1) & ~1), SEEK_SET); fxread (xbuf + 4, sizeof (int8), tbc, uptr -> fileref); diff --git a/PDP10/pdp10_xtnd.c b/PDP10/pdp10_xtnd.c index 89bfaf5b..8023ab0a 100644 --- a/PDP10/pdp10_xtnd.c +++ b/PDP10/pdp10_xtnd.c @@ -1,6 +1,6 @@ /* pdp10_xtnd.c: PDP-10 extended instruction simulator - Copyright (c) 1993-2001, Robert M Supnik + Copyright (c) 1993-2002, Robert M Supnik Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), diff --git a/PDP11/pdp11_cis.c b/PDP11/pdp11_cis.c index 436e0240..80a4bbf4 100644 --- a/PDP11/pdp11_cis.c +++ b/PDP11/pdp11_cis.c @@ -1,6 +1,6 @@ /* pdp11_cis.c: PDP-11 CIS optional instruction set simulator - Copyright (c) 1993-2001, Robert M Supnik + Copyright (c) 1993-2002, Robert M Supnik Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), diff --git a/PDP11/pdp11_cpu.c b/PDP11/pdp11_cpu.c index d8acf5d3..c93a47f7 100644 --- a/PDP11/pdp11_cpu.c +++ b/PDP11/pdp11_cpu.c @@ -1,6 +1,6 @@ /* pdp11_cpu.c: PDP-11 CPU simulator - Copyright (c) 1993-2001, Robert M Supnik + Copyright (c) 1993-2002, Robert M Supnik Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), @@ -25,6 +25,20 @@ cpu PDP-11 CPU (J-11 microprocessor) + 14-Jul-02 RMS Fixed bug in MMR0 error status load + 03-Jun-02 RMS Fixed relocation add overflow, added PS<15:12> = 1111 + special case logic to MFPI and removed it from MTPI + (found by John Dundas) + 29-Apr-02 RMS More fixes to DIV and ASH/ASHC (found by John Dundas) + 28-Apr-02 RMS Fixed bugs in illegal instruction 000010 and in + write-only memory pages (found by Wolfgang Helbig) + 21-Apr-02 RMS Fixed bugs in DIV by zero, DIV overflow, TSTSET, RTS, + ASHC -32, and red zone trap (found by John Dundas) + 04-Mar-02 RMS Changed double operand evaluation order for M+ + 23-Feb-02 RMS Fixed bug in MAINT, CPUERR, MEMERR read + 28-Jan-02 RMS Revised for multiple timers; fixed calc_MMR1 macros + 06-Jan-02 RMS Revised enable/disable support + 30-Dec-01 RMS Added old PC queue 25-Dec-01 RMS Cleaned up sim_inst declarations 11-Dec-01 RMS Moved interrupt debug code 07-Dec-01 RMS Revised to use new breakpoint package @@ -173,7 +187,7 @@ 4. Adding I/O devices. This requires modifications to three modules: pdp11_defs.h add interrupt request definitions - pdp11_io.c add I/O page linkages + pdp11_io.c add to dib_tab pdp11_sys.c add to sim_devices */ @@ -181,15 +195,18 @@ #include "pdp11_defs.h" +#define PCQ_SIZE 64 /* must be 2**n */ +#define PCQ_MASK (PCQ_SIZE - 1) +#define PCQ_ENTRY pcq[pcq_p = (pcq_p - 1) & PCQ_MASK] = PC #define calc_is(md) ((md) << VA_V_MODE) #define calc_ds(md) (calc_is((md)) | ((MMR3 & dsmask[(md)])? VA_DS: 0)) -#define calc_MMR1(val) (MMR1 = MMR1? ((val) << 8) | MMR1: (val)) +#define calc_MMR1(val) ((MMR1)? (((val) << 8) | MMR1): (val)) #define GET_SIGN_W(v) ((v) >> 15) #define GET_SIGN_B(v) ((v) >> 7) #define GET_Z(v) ((v) == 0) -#define JMP_PC(x) old_PC = PC; PC = (x) -#define BRANCH_F(x) old_PC = PC; PC = (PC + (((x) + (x)) & 0377)) & 0177777 -#define BRANCH_B(x) old_PC = PC; PC = (PC + (((x) + (x)) | 0177400)) & 0177777 +#define JMP_PC(x) PCQ_ENTRY; PC = (x) +#define BRANCH_F(x) PCQ_ENTRY; PC = (PC + (((x) + (x)) & 0377)) & 0177777 +#define BRANCH_B(x) PCQ_ENTRY; PC = (PC + (((x) + (x)) | 0177400)) & 0177777 #define last_pa (cpu_unit.u4) /* auto save/rest */ #define UNIT_V_18B (UNIT_V_UF) /* force 18b addr */ #define UNIT_V_UBM (UNIT_V_UF + 1) /* bus map present */ @@ -239,22 +256,28 @@ int32 cpu_bme = 0; /* bus map enable */ int32 cpu_18b = 0; /* 18b CPU config'd */ int32 cpu_ubm = 0; /* bus map config'd */ int32 cpu_rh11 = 0; /* RH11 config'd */ +int32 cpu_astop = 0; /* address stop */ int32 isenable = 0, dsenable = 0; /* i, d space flags */ int32 CPUERR = 0; /* CPU error reg */ int32 MEMERR = 0; /* memory error reg */ int32 CCR = 0; /* cache control reg */ int32 HITMISS = 0; /* hit/miss reg */ -int32 MAINT = MAINT_Q | MAINT_NOFPA | MAINT_KDJ; /* maint reg */ +int32 MAINT = MAINT_Q | MAINT_NOFPA | MAINT_KDJ | MAINT_BPOK; /* maint reg */ int32 stop_trap = 1; /* stop on trap */ int32 stop_vecabort = 1; /* stop on vec abort */ int32 stop_spabort = 1; /* stop on SP abort */ int32 wait_enable = 0; /* wait state enable */ int32 cpu_log = 0; /* logging */ -int32 old_PC = 0; /* previous PC */ +uint16 pcq[PCQ_SIZE] = { 0 }; /* PC queue */ +int32 pcq_p = 0; /* PC queue ptr */ +REG *pcq_r = NULL; /* PC queue reg ptr */ int32 dev_enb = (-1) & ~INT_TS; /* dev enables */ jmp_buf save_env; /* abort handler */ int32 dsmask[4] = { MMR3_KDS, MMR3_SDS, 0, MMR3_UDS }; /* dspace enables */ +extern int32 sim_interval; +extern UNIT *sim_clock_queue; +extern UNIT clk_unit; extern int32 sim_int_char; extern int32 sim_brk_types, sim_brk_dflt, sim_brk_summ; /* breakpoint info */ @@ -276,10 +299,19 @@ void WriteW (int32 data, int32 addr); void WriteB (int32 data, int32 addr); void PWriteW (int32 data, int32 addr); void PWriteB (int32 data, int32 addr); +t_stat CPU_rd (int32 *data, int32 addr, int32 access); t_stat CPU_wr (int32 data, int32 addr, int32 access); +t_stat APR_rd (int32 *data, int32 addr, int32 access); +t_stat APR_wr (int32 data, int32 addr, int32 access); +t_stat SR_MMR012_rd (int32 *data, int32 addr, int32 access); +t_stat SR_MMR012_wr (int32 data, int32 addr, int32 access); +t_stat MMR3_rd (int32 *data, int32 addr, int32 access); +t_stat MMR3_wr (int32 data, int32 addr, int32 access); +t_stat ubm_rd (int32 *data, int32 addr, int32 access); +t_stat ubm_wr (int32 data, int32 addr, int32 access); -extern t_stat iopageR (int32 *data, int32 addr, int32 access); -extern t_stat iopageW (int32 data, int32 addr, int32 access); +extern t_stat iopageR (int32 *data, uint32 addr, int32 access); +extern t_stat iopageW (int32 data, uint32 addr, int32 access); extern int32 calc_ints (int32 nipl, int32 trq); extern int32 get_vector (int32 nipl); @@ -292,7 +324,7 @@ int32 trap_vec[TRAP_V_MAX] = { /* trap req to vector */ VEC_YEL, VEC_PWRFL, VEC_FPE }; int32 trap_clear[TRAP_V_MAX] = { /* trap clears */ - TRAP_RED+TRAP_PAR+TRAP_YEL+TRAP_TRC, + TRAP_RED+TRAP_PAR+TRAP_YEL+TRAP_TRC+TRAP_ODD+TRAP_NXM, TRAP_ODD+TRAP_PAR+TRAP_YEL+TRAP_TRC, TRAP_MME+TRAP_PAR+TRAP_YEL+TRAP_TRC, TRAP_NXM+TRAP_PAR+TRAP_YEL+TRAP_TRC, @@ -301,6 +333,15 @@ int32 trap_clear[TRAP_V_MAX] = { /* trap clears */ TRAP_IOT+TRAP_TRC, TRAP_EMT+TRAP_TRC, TRAP_TRAP+TRAP_TRC, TRAP_TRC, TRAP_YEL, TRAP_PWRFL, TRAP_FPE }; + +/* Fixed I/O address table entries */ + +DIB cpu0_dib = { 1, IOBA_CPU, IOLN_CPU, &CPU_rd, &CPU_wr }; +DIB cpu1_dib = { 1, IOBA_APR, IOLN_APR, &APR_rd, &APR_wr }; +DIB cpu2_dib = { 1, IOBA_APR1, IOLN_APR1, &APR_rd, &APR_wr }; +DIB cpu3_dib = { 1, IOBA_SRMM, IOLN_SRMM, &SR_MMR012_rd, &SR_MMR012_wr }; +DIB cpu4_dib = { 1, IOBA_MMR3, IOLN_MMR3, &MMR3_rd, &MMR3_wr }; +DIB ubm_dib = { 0, IOBA_UBM, IOLN_UBM, &ubm_rd, &ubm_wr }; /* CPU data structures @@ -475,7 +516,8 @@ REG cpu_reg[] = { { FLDATA (UB_MAP, cpu_unit.flags, UNIT_V_UBM), REG_HRO }, { FLDATA (RH11, cpu_unit.flags, UNIT_V_RH11), REG_HRO }, { FLDATA (CIS, cpu_unit.flags, UNIT_V_CIS), REG_HRO }, - { ORDATA (OLDPC, old_PC, 16), REG_RO }, + { BRDATA (PCQ, pcq, 8, 16, PCQ_SIZE), REG_RO+REG_CIRC }, + { ORDATA (PCQP, pcq_p, 6), REG_HRO }, { ORDATA (WRU, sim_int_char, 8) }, { ORDATA (DEVENB, dev_enb, 32), REG_HRO }, { NULL} }; @@ -516,11 +558,8 @@ DEVICE cpu_dev = { t_stat sim_instr (void) { -extern int32 sim_interval; -extern UNIT *sim_clock_queue; -extern UNIT clk_unit; int abortval, i; -volatile int32 trapea; /* needed at longjmp */ +volatile int32 trapea; /* used by setjmp */ t_stat reason; void fp11 (int32 IR); void cis11 (int32 IR); @@ -534,6 +573,8 @@ void cis11 (int32 IR); 5. Interrupt system */ +if (cpu_unit.flags & UNIT_UBM) ubm_dib.enb = 1; /* enb/dis map */ +else ubm_dib.enb = 0; cm = (PSW >> PSW_V_CM) & 03; /* call calc_is,ds */ pm = (PSW >> PSW_V_PM) & 03; rs = (PSW >> PSW_V_RS) & 01; @@ -559,7 +600,7 @@ cpu_rh11 = cpu_unit.flags & UNIT_RH11; trap_req = calc_ints (ipl, trap_req); /* upd int req */ trapea = 0; reason = 0; -sim_rtc_init (clk_unit.wait); /* init clock */ +sim_rtcn_init (clk_unit.wait, TMR_CLK); /* init line clock */ /* Abort handling @@ -573,6 +614,9 @@ sim_rtc_init (clk_unit.wait); /* init clock */ special handling. If the abort occured on the stack pushes, and the mode (encoded in trapea) is kernel, an "emergency" kernel stack is created at 4, and a red zone stack trap taken. + + All variables used in setjmp processing, or assumed to be valid + after setjmp, must be volatile or global. */ abortval = setjmp (save_env); /* set abort hdlr */ @@ -595,9 +639,14 @@ if (abortval != 0) { while (reason == 0) { int32 IR, srcspec, srcreg, dstspec, dstreg; -int32 src, src2, dst; +int32 src, src2, dst, ea; int32 i, t, sign, oldrs, trapnum; +if (cpu_astop) { + cpu_astop = 0; + reason = SCPE_STOP; + break; } + if (sim_interval <= 0) { /* intv cnt expired? */ reason = sim_process_event (); /* process events */ trap_req = calc_ints (ipl, trap_req); /* recalc int req */ @@ -703,12 +752,13 @@ switch ((IR >> 12) & 017) { /* decode IR<15:12> */ case 000: switch ((IR >> 6) & 077) { /* decode IR<11:6> */ case 000: /* no operand */ - if (IR > 000010) { /* 000010 - 000077 */ + if (IR >= 000010) { /* 000010 - 000077 */ setTRAP (TRAP_ILL); /* illegal */ break; } switch (IR) { /* decode IR<2:0> */ case 0: /* HALT */ - if (cm == KERNEL) reason = STOP_HALT; + if ((cm == KERNEL) && ((MAINT & MAINT_HTRAP) == 0)) + reason = STOP_HALT; else { setTRAP (TRAP_PRV); setCPUERR (CPUE_HALT); } break; @@ -781,7 +831,7 @@ case 000: dstspec = dstspec & 07; JMP_PC (R[dstspec]); R[dstspec] = ReadW (SP | dsenable); - SP = (SP + 2) & 0177777; + if (dstspec != 6) SP = (SP + 2) & 0177777; break; } /* end if RTS */ if (IR < 000230) { setTRAP (TRAP_ILL); @@ -1003,7 +1053,9 @@ case 000: if (dstreg) { if ((dstspec == 6) && (cm != pm)) dst = STACKFILE[pm]; else dst = R[dstspec]; } - else dst = ReadW ((GeteaW (dstspec) & 0177777) | calc_is (pm)); + else { i = ((cm == pm) && (cm == USER))? + calc_ds (pm): calc_is (pm); + dst = ReadW ((GeteaW (dstspec) & 0177777) | i); } N = GET_SIGN_W (dst); Z = GET_Z (dst); V = 0; @@ -1024,9 +1076,7 @@ case 000: if (dstreg) { if ((dstspec == 6) && (cm != pm)) STACKFILE[pm] = dst; else R[dstspec] = dst; } - else { i = ((cm == pm) && (cm == USER))? - calc_ds (pm): calc_is (pm); - WriteW (dst, (GeteaW (dstspec) & 0177777) | i); } + else WriteW (dst, (GeteaW (dstspec) & 0177777) | calc_is (pm)); break; case 067: /* SXT */ dst = N? 0177777: 0; @@ -1064,8 +1114,8 @@ case 000: Z = GET_Z (dst); V = 0; C = (dst & 1); - PWriteW (R[0] | 1, last_pa); - R[0] = dst; } + R[0] = dst; /* R[0] <- dst */ + PWriteW (R[0] | 1, last_pa); } /* dst <- R[0] | 1 */ break; case 073: /* WRTLCK */ if (dstreg) setTRAP (TRAP_ILL); @@ -1081,21 +1131,33 @@ case 000: /* Opcodes 01 - 06: double operand word instructions + J-11 (and F-11) optimize away register source operand decoding. + As a result, dop R,+/-(R) use the modified version of R as source. + Most (but not all) other PDP-11's fetch the source operand before + any destination operand decoding. + Add: v = [sign (src) = sign (src2)] and [sign (src) != sign (result)] Cmp: v = [sign (src) != sign (src2)] and [sign (src2) = sign (result)] */ case 001: /* MOV */ - dst = srcreg? R[srcspec]: ReadW (GeteaW (srcspec)); + if (srcreg && !dstreg) { /* R,not R */ + ea = GeteaW (dstspec); + dst = R[srcspec]; } + else { dst = srcreg? R[srcspec]: ReadW (GeteaW (srcspec)); + if (!dstreg) ea = GeteaW (dstspec); } N = GET_SIGN_W (dst); Z = GET_Z (dst); V = 0; if (dstreg) R[dstspec] = dst; - else WriteW (dst, GeteaW (dstspec)); + else WriteW (dst, ea); break; case 002: /* CMP */ - src = srcreg? R[srcspec]: ReadW (GeteaW (srcspec)); - src2 = dstreg? R[dstspec]: ReadW (GeteaW (dstspec)); + if (srcreg && !dstreg) { /* R,not R */ + src2 = ReadW (GeteaW (dstspec)); + src = R[srcspec]; } + else { src = srcreg? R[srcspec]: ReadW (GeteaW (srcspec)); + src2 = dstreg? R[dstspec]: ReadW (GeteaW (dstspec)); } dst = (src - src2) & 0177777; N = GET_SIGN_W (dst); Z = GET_Z (dst); @@ -1103,16 +1165,22 @@ case 002: /* CMP */ C = (src < src2); break; case 003: /* BIT */ - src = srcreg? R[srcspec]: ReadW (GeteaW (srcspec)); - src2 = dstreg? R[dstspec]: ReadW (GeteaW (dstspec)); + if (srcreg && !dstreg) { /* R,not R */ + src2 = ReadW (GeteaW (dstspec)); + src = R[srcspec]; } + else { src = srcreg? R[srcspec]: ReadW (GeteaW (srcspec)); + src2 = dstreg? R[dstspec]: ReadW (GeteaW (dstspec)); } dst = src2 & src; N = GET_SIGN_W (dst); Z = GET_Z (dst); V = 0; break; case 004: /* BIC */ - src = srcreg? R[srcspec]: ReadW (GeteaW (srcspec)); - src2 = dstreg? R[dstspec]: ReadMW (GeteaW (dstspec)); + if (srcreg && !dstreg) { /* R,not R */ + src2 = ReadMW (GeteaW (dstspec)); + src = R[srcspec]; } + else { src = srcreg? R[srcspec]: ReadW (GeteaW (srcspec)); + src2 = dstreg? R[dstspec]: ReadMW (GeteaW (dstspec)); } dst = src2 & ~src; N = GET_SIGN_W (dst); Z = GET_Z (dst); @@ -1121,8 +1189,11 @@ case 004: /* BIC */ else PWriteW (dst, last_pa); break; case 005: /* BIS */ - src = srcreg? R[srcspec]: ReadW (GeteaW (srcspec)); - src2 = dstreg? R[dstspec]: ReadMW (GeteaW (dstspec)); + if (srcreg && !dstreg) { /* R,not R */ + src2 = ReadMW (GeteaW (dstspec)); + src = R[srcspec]; } + else { src = srcreg? R[srcspec]: ReadW (GeteaW (srcspec)); + src2 = dstreg? R[dstspec]: ReadMW (GeteaW (dstspec)); } dst = src2 | src; N = GET_SIGN_W (dst); Z = GET_Z (dst); @@ -1131,8 +1202,11 @@ case 005: /* BIS */ else PWriteW (dst, last_pa); break; case 006: /* ADD */ - src = srcreg? R[srcspec]: ReadW (GeteaW (srcspec)); - src2 = dstreg? R[dstspec]: ReadMW (GeteaW (dstspec)); + if (srcreg && !dstreg) { /* R,not R */ + src2 = ReadMW (GeteaW (dstspec)); + src = R[srcspec]; } + else { src = srcreg? R[srcspec]: ReadW (GeteaW (srcspec)); + src2 = dstreg? R[dstspec]: ReadMW (GeteaW (dstspec)); } dst = (src2 + src) & 0177777; N = GET_SIGN_W (dst); Z = GET_Z (dst); @@ -1177,24 +1251,25 @@ case 007: break; case 1: /* DIV */ src2 = dstreg? R[dstspec]: ReadW (GeteaW (dstspec)); - src = (R[srcspec] << 16) | R[srcspec | 1]; + src = (((uint32) R[srcspec]) << 16) | R[srcspec | 1]; if (src2 == 0) { - V = C = 1; + N = 0; /* J11,11/70 compat */ + Z = V = C = 1; /* N = 0, Z = 1 */ break; } if ((src == 020000000000) && (src2 == 0177777)) { - V = 1; - C = 0; + V = 1; /* J11,11/70 compat */ + N = Z = C = 0; /* N = Z = 0 */ break; } if (GET_SIGN_W (src2)) src2 = src2 | ~077777; if (GET_SIGN_W (R[srcspec])) src = src | ~017777777777; dst = src / src2; + N = (dst < 0); /* N set on 32b result */ if ((dst > 077777) || (dst < -0100000)) { - V = 1; - C = 0; + V = 1; /* J11,11/70 compat */ + Z = C = 0; /* Z = C = 0 */ break; } R[srcspec] = dst & 0177777; R[srcspec | 1] = (src - (src2 * dst)) & 0177777; - N = (dst < 0); Z = GET_Z (dst); V = C = 0; break; @@ -1218,7 +1293,10 @@ case 007: dst = 0; V = (src != 0); C = (src << (src2 - 16)) & 1; } - else { /* [-32,-1] */ + else if (src2 == 32) { /* [32] = -32 */ + dst = -sign; + V = C = 0; } + else { /* [33,63] = -31,-1 */ dst = (src >> (64 - src2)) | (-sign << (src2 - 32)); V = 0; C = ((src >> (63 - src2)) & 1); } @@ -1230,16 +1308,20 @@ case 007: src2 = dstreg? R[dstspec]: ReadW (GeteaW (dstspec)); src2 = src2 & 077; sign = GET_SIGN_W (R[srcspec]); - src = (R[srcspec] << 16) | R[srcspec | 1]; + src = (((uint32) R[srcspec]) << 16) | R[srcspec | 1]; if (src2 == 0) { /* [0] */ dst = src; V = C = 0; } else if (src2 <= 31) { /* [1,31] */ - dst = src << src2; + dst = ((uint32) src) << src2; i = (src >> (32 - src2)) | (-sign << src2); V = (i != ((dst & 020000000000)? -1: 0)); C = (i & 1); } - else { /* [-32,-1] */ + else if (src2 == 32) { /* [32] = -32 */ + dst = -sign; + V = 0; + C = (src >> 31) & 1; } + else { /* [33,63] = -31,-1 */ dst = (src >> (64 - src2)) | (-sign << (src2 - 32)); V = 0; C = ((src >> (63 - src2)) & 1); } @@ -1516,16 +1598,23 @@ case 010: */ case 011: /* MOVB */ - dst = srcreg? R[srcspec] & 0377: ReadB (GeteaB (srcspec)); + if (srcreg && !dstreg) { /* R,not R */ + ea = GeteaB (dstspec); + dst = R[srcspec] & 0377; } + else { dst = srcreg? R[srcspec] & 0377: ReadB (GeteaB (srcspec)); + if (!dstreg) ea = GeteaB (dstspec); } N = GET_SIGN_B (dst); Z = GET_Z (dst); V = 0; if (dstreg) R[dstspec] = (dst & 0200)? 0177400 | dst: dst; - else WriteB (dst, GeteaB (dstspec)); + else WriteB (dst, ea); break; case 012: /* CMPB */ - src = srcreg? R[srcspec] & 0377: ReadB (GeteaB (srcspec)); - src2 = dstreg? R[dstspec] & 0377: ReadB (GeteaB (dstspec)); + if (srcreg && !dstreg) { /* R,not R */ + src2 = ReadB (GeteaB (dstspec)); + src = R[srcspec] & 0377; } + else { src = srcreg? R[srcspec] & 0377: ReadB (GeteaB (srcspec)); + src2 = dstreg? R[dstspec] & 0377: ReadB (GeteaB (dstspec)); } dst = (src - src2) & 0377; N = GET_SIGN_B (dst); Z = GET_Z (dst); @@ -1533,16 +1622,22 @@ case 012: /* CMPB */ C = (src < src2); break; case 013: /* BITB */ - src = srcreg? R[srcspec]: ReadB (GeteaB (srcspec)); - src2 = dstreg? R[dstspec]: ReadB (GeteaB (dstspec)); + if (srcreg && !dstreg) { /* R,not R */ + src2 = ReadB (GeteaB (dstspec)); + src = R[srcspec] & 0377; } + else { src = srcreg? R[srcspec] & 0377: ReadB (GeteaB (srcspec)); + src2 = dstreg? R[dstspec] & 0377: ReadB (GeteaB (dstspec)); } dst = (src2 & src) & 0377; N = GET_SIGN_B (dst); Z = GET_Z (dst); V = 0; break; case 014: /* BICB */ - src = srcreg? R[srcspec]: ReadB (GeteaB (srcspec)); - src2 = dstreg? R[dstspec]: ReadMB (GeteaB (dstspec)); + if (srcreg && !dstreg) { /* R,not R */ + src2 = ReadMB (GeteaB (dstspec)); + src = R[srcspec]; } + else { src = srcreg? R[srcspec]: ReadB (GeteaB (srcspec)); + src2 = dstreg? R[dstspec]: ReadMB (GeteaB (dstspec)); } dst = (src2 & ~src) & 0377; N = GET_SIGN_B (dst); Z = GET_Z (dst); @@ -1551,8 +1646,11 @@ case 014: /* BICB */ else PWriteB (dst, last_pa); break; case 015: /* BISB */ - src = srcreg? R[srcspec]: ReadB (GeteaB (srcspec)); - src2 = dstreg? R[dstspec]: ReadMB (GeteaB (dstspec)); + if (srcreg && !dstreg) { /* R,not R */ + src2 = ReadMB (GeteaB (dstspec)); + src = R[srcspec]; } + else { src = srcreg? R[srcspec]: ReadB (GeteaB (srcspec)); + src2 = dstreg? R[dstspec]: ReadMB (GeteaB (dstspec)); } dst = (src2 | src) & 0377; N = GET_SIGN_B (dst); Z = GET_Z (dst); @@ -1561,8 +1659,11 @@ case 015: /* BISB */ else PWriteB (dst, last_pa); break; case 016: /* SUB */ - src = srcreg? R[srcspec]: ReadW (GeteaW (srcspec)); - src2 = dstreg? R[dstspec]: ReadMW (GeteaW (dstspec)); + if (srcreg && !dstreg) { /* R,not R */ + src2 = ReadMW (GeteaW (dstspec)); + src = R[srcspec]; } + else { src = srcreg? R[srcspec]: ReadW (GeteaW (srcspec)); + src2 = dstreg? R[dstspec]: ReadMW (GeteaW (dstspec)); } dst = (src2 - src) & 0177777; N = GET_SIGN_W (dst); Z = GET_Z (dst); @@ -1588,6 +1689,7 @@ PSW = (cm << PSW_V_CM) | (pm << PSW_V_PM) | (rs << PSW_V_RS) | for (i = 0; i < 6; i++) REGFILE[i][rs] = R[i]; STACKFILE[cm] = SP; saved_PC = PC & 0177777; +pcq_r -> qptr = pcq_p; /* update pc q ptr */ return reason; } @@ -1910,15 +2012,17 @@ if (MMR0 & MMR0_MME) { /* if mmgt */ apr = APRFILE[apridx]; /* with va<18:13> */ dbn = va & VA_BN; /* extr block num */ plf = (apr & PDR_PLF) >> 2; /* extr page length */ - if ((apr & PDR_NR) == 0) { /* if non-resident */ - if (update_MM) MMR0 = MMR0 | (apridx << MMR0_V_PAGE); - MMR0 = MMR0 | MMR0_NR; + if ((apr & PDR_PRD) == 0) { /* not readable? */ + if (update_MM) MMR0 = /* update MMR0 */ + (MMR0 & ~MMR0_PAGE) | (apridx << MMR0_V_PAGE); + MMR0 = MMR0 | MMR0_NR; /* err non-resident */ ABORT (TRAP_MME); } /* abort ref */ if ((apr & PDR_ED)? dbn < plf: dbn > plf) { /* if pg lnt error */ - if (update_MM) MMR0 = MMR0 | (apridx << MMR0_V_PAGE); + if (update_MM) MMR0 = /* update MMR0 */ + (MMR0 & ~MMR0_PAGE) | (apridx << MMR0_V_PAGE); MMR0 = MMR0 | MMR0_PL; ABORT (TRAP_MME); } /* abort ref */ - pa = (va & VA_DF) + ((apr >> 10) & 017777700); + pa = ((va & VA_DF) + ((apr >> 10) & 017777700)) & PAMASK; if ((MMR3 & MMR3_M22E) == 0) { pa = pa & 0777777; if (pa >= 0760000) pa = 017000000 | pa; } } @@ -1950,20 +2054,23 @@ if (MMR0 & MMR0_MME) { /* if mmgt */ apr = APRFILE[apridx]; /* with va<18:13> */ dbn = va & VA_BN; /* extr block num */ plf = (apr & PDR_PLF) >> 2; /* extr page length */ - if ((apr & PDR_NR) == 0) { /* if non-resident */ - if (update_MM) MMR0 = MMR0 | (apridx << MMR0_V_PAGE); - MMR0 = MMR0 | MMR0_NR; + if ((apr & PDR_PRD) == 0) { /* not readable? */ + if (update_MM) MMR0 = /* update MMR0 */ + (MMR0 & ~MMR0_PAGE) | (apridx << MMR0_V_PAGE); + MMR0 = MMR0 | MMR0_NR; /* err non-resident */ ABORT (TRAP_MME); } /* abort ref */ if ((apr & PDR_ED)? dbn < plf: dbn > plf) { /* if pg lnt error */ - if (update_MM) MMR0 = MMR0 | (apridx << MMR0_V_PAGE); + if (update_MM) MMR0 = /* update MMR0 */ + (MMR0 & ~MMR0_PAGE) | (apridx << MMR0_V_PAGE); MMR0 = MMR0 | MMR0_PL; ABORT (TRAP_MME); } /* abort ref */ - if ((apr & PDR_RW) == 0) { /* if rd only error */ - if (update_MM) MMR0 = MMR0 | (apridx << MMR0_V_PAGE); - MMR0 = MMR0 | MMR0_RO; + if ((apr & PDR_PWR) == 0) { /* not writeable? */ + if (update_MM) MMR0 = /* update MMR0 */ + (MMR0 & ~MMR0_PAGE) | (apridx << MMR0_V_PAGE); + MMR0 = MMR0 | MMR0_RO; /* err read only */ ABORT (TRAP_MME); } /* abort ref */ APRFILE[apridx] = apr | PDR_W; /* set W */ - pa = (va & VA_DF) + ((apr >> 10) & 017777700); + pa = ((va & VA_DF) + ((apr >> 10) & 017777700)) & PAMASK; if ((MMR3 & MMR3_M22E) == 0) { pa = pa & 0777777; if (pa >= 0760000) pa = 017000000 | pa; } } @@ -1997,9 +2104,9 @@ if (MMR0 & MMR0_MME) { /* if mmgt */ apr = APRFILE[apridx]; /* with va<18:13> */ dbn = va & VA_BN; /* extr block num */ plf = (apr & PDR_PLF) >> 2; /* extr page length */ - if ((apr & PDR_NR) == 0) return -1; + if ((apr & PDR_PRD) == 0) return -1; /* not readable? */ if ((apr & PDR_ED)? dbn < plf: dbn > plf) return -1; - pa = (va & VA_DF) + ((apr >> 10) & 017777700); + pa = ((va & VA_DF) + ((apr >> 10) & 017777700)) & PAMASK; if ((MMR3 & MMR3_M22E) == 0) { pa = pa & 0777777; if (pa >= 0760000) pa = 017000000 | pa; } } @@ -2111,7 +2218,7 @@ curr = left? (APRFILE[idx] >> 16) & 0177777: APRFILE[idx] & PDR_IMP; if (access == WRITEB) data = (pa & 1)? (curr & 0377) | (data << 8): (curr & ~0377) | data; if (left) APRFILE[idx] = - ((APRFILE[idx] & 0177777) | (data << 16)) & ~PDR_W; + ((APRFILE[idx] & 0177777) | (((uint32) data) << 16)) & ~PDR_W; else APRFILE[idx] = ((APRFILE[idx] & ~PDR_RW) | (data & PDR_RW)) & ~PDR_W; return SCPE_OK; @@ -2133,21 +2240,19 @@ t_stat CPU_rd (int32 *data, int32 pa, int32 access) switch ((pa >> 1) & 017) { /* decode pa<4:1> */ case 2: /* MEMERR */ *data = MEMERR; - MEMERR = 0; return SCPE_OK; case 3: /* CCR */ *data = CCR; return SCPE_OK; case 4: /* MAINT */ if (cpu_ubm) *data = MAINT | MAINT_U; - else *data = MAINT | MAINT_Q; + else *data = MAINT & ~MAINT_U; return SCPE_OK; case 5: /* Hit/miss */ *data = HITMISS; return SCPE_OK; case 013: /* CPUERR */ *data = CPUERR & CPUE_IMP; - CPUERR = 0; return SCPE_OK; case 015: /* PIRQ */ *data = PIRQ; @@ -2258,6 +2363,9 @@ trap_req = 0; wait_state = 0; if (M == NULL) M = calloc (MEMSIZE >> 1, sizeof (unsigned int16)); if (M == NULL) return SCPE_MEM; +pcq_r = find_reg ("PCQ", NULL, dptr); +if (pcq_r) pcq_r -> qptr = 0; +else return SCPE_IERR; for (i = 0; i < UBM_LNT_LW; i++) ub_map[i] = 0; sim_brk_types = sim_brk_dflt = SWMASK ('E'); return SCPE_OK; diff --git a/PDP11/pdp11_defs.h b/PDP11/pdp11_defs.h index bbf43606..5df26f95 100644 --- a/PDP11/pdp11_defs.h +++ b/PDP11/pdp11_defs.h @@ -1,6 +1,6 @@ /* pdp11_defs.h: PDP-11 simulator definitions - Copyright (c) 1993-2001, Robert M Supnik + Copyright (c) 1993-2002, Robert M Supnik Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), @@ -26,6 +26,10 @@ The author gratefully acknowledges the help of Max Burnet, Megan Gentry, and John Wilson in resolving questions about the PDP-11 + 28-Apr-02 RMS Clarified PDF ACF mnemonics + 22-Apr-02 RMS Added HTRAP, BPOK maint register flags, MT_MAXFR + 06-Mar-02 RMS Changed system type to KDJ11A + 20-Jan-02 RMS Added multiboard DZ11 support 09-Nov-01 RMS Added bus map support 07-Nov-01 RMS Added RQDX3 support 26-Oct-01 RMS Added symbolic definitions for IO page @@ -114,6 +118,8 @@ #define MMR0_MME 0000001 /* mem mgt enable */ #define MMR0_V_PAGE 1 /* offset to pageno */ +#define MMR0_M_PAGE 077 /* mask for pageno */ +#define MMR0_PAGE (MMR0_M_PAGE << MMR0_V_PAGE) #define MMR0_RO 0020000 /* read only error */ #define MMR0_PL 0040000 /* page lnt error */ #define MMR0_NR 0100000 /* no access error */ @@ -134,7 +140,8 @@ /* PDR */ -#define PDR_NR 0000002 /* non-resident ACF */ +#define PDR_PRD 0000002 /* page readable */ +#define PDR_PWR 0000004 /* page writeable */ #define PDR_ED 0000010 /* expansion dir */ #define PDR_W 0000100 /* written flag */ #define PDR_PLF 0077400 /* page lnt field */ @@ -179,7 +186,11 @@ #define MAINT_NOFPA (0 << MAINT_V_FPA) #define MAINT_FPA (1 << MAINT_V_FPA) #define MAINT_V_TYP 4 /* system type */ -#define MAINT_KDJ (4 << MAINT_V_TYP) +#define MAINT_KDJ (1 << MAINT_V_TYP) /* KDJ11A */ +#define MAINT_V_HTRAP 3 /* trap 4 on HALT */ +#define MAINT_HTRAP (1 << MAINT_V_HTRAP) +#define MAINT_V_BPOK 0 /* power OK */ +#define MAINT_BPOK (1 << MAINT_V_BPOK) /* Floating point accumulators */ @@ -266,15 +277,32 @@ typedef struct fpac fpac_t; #define STOP_RQ (TRAP_V_MAX + 6) /* RQDX3 panic */ #define IORETURN(f,v) ((f)? (v): SCPE_OK) /* cond error return */ -/* DZ11 parameters */ +/* Timers */ -#define DZ_MUXES 1 /* # of muxes */ +#define TMR_CLK 0 /* line clock */ +#define TMR_KWP 1 /* KW11P */ + +/* IO parameters */ + +#define DZ_MUXES 4 /* max # of muxes */ #define DZ_LINES 8 /* lines per mux */ +#define MT_MAXFR (1 << 16) /* magtape max rec */ + +/* Device information block */ + +struct pdp_dib { + uint32 enb; /* enabled */ + uint32 ba; /* base addr */ + uint32 lnt; /* length */ + t_stat (*rd)(int32 *dat, int32 ad, int32 md); + t_stat (*wr)(int32 dat, int32 ad, int32 md); }; + +typedef struct pdp_dib DIB; /* I/O page layout */ #define IOBA_DZ (IOPAGEBASE + 000100) /* DZ11 */ -#define IOLN_DZ (010 * DZ_MUXES) +#define IOLN_DZ 010 #define IOBA_UBM (IOPAGEBASE + 010200) /* Unibus map */ #define IOLN_UBM (UBM_LNT_LW * sizeof (int32)) #define IOBA_RQ (IOPAGEBASE + 012150) /* RQDX3 */ @@ -301,8 +329,12 @@ typedef struct fpac fpac_t; #define IOLN_RK6 040 #define IOBA_LPT (IOPAGEBASE + 017514) /* LP11 */ #define IOLN_LPT 004 -#define IOBA_STD (IOPAGEBASE + 017546) /* KW11L, DL11, PC11 */ -#define IOLN_STD 022 +#define IOBA_CLK (IOPAGEBASE + 017546) /* KW11L */ +#define IOLN_CLK 002 +#define IOBA_PT (IOPAGEBASE + 017550) /* PC11 */ +#define IOLN_PT 010 +#define IOBA_TT (IOPAGEBASE + 017560) /* DL11 */ +#define IOLN_TT 010 #define IOBA_SRMM (IOPAGEBASE + 017570) /* SR, MMR0-2 */ #define IOLN_SRMM 010 #define IOBA_APR1 (IOPAGEBASE + 017600) /* APRs */ @@ -452,3 +484,7 @@ int32 Map_ReadB (t_addr ba, int32 bc, uint8 *buf, t_bool ub); int32 Map_ReadW (t_addr ba, int32 bc, uint16 *buf, t_bool ub); int32 Map_WriteB (t_addr ba, int32 bc, uint8 *buf, t_bool ub); int32 Map_WriteW (t_addr ba, int32 bc, uint16 *buf, t_bool ub); +t_stat set_addr (UNIT *uptr, int32 val, char *cptr, void *desc); +t_stat show_addr (FILE *st, UNIT *uptr, int32 val, void *desc); +t_stat set_enbdis (UNIT *uptr, int32 val, char *cptr, void *desc); +t_bool dev_conflict (uint32 nba, DIB *curr); diff --git a/PDP11/pdp11_doc.txt b/PDP11/pdp11_doc.txt index f1fa1c93..9257048e 100644 --- a/PDP11/pdp11_doc.txt +++ b/PDP11/pdp11_doc.txt @@ -1,14 +1,14 @@ To: Users From: Bob Supnik Subj: PDP-11 Simulator Usage -Date: 1-Dec-01 +Date: 15-Jun-2002 COPYRIGHT NOTICE The following copyright notice applies to both the SIMH source and binary: - Original code published in 1993-2001, written by Robert M Supnik - Copyright (c) 1993-2001, Robert M Supnik + Original code published in 1993-2002, written by Robert M Supnik + Copyright (c) 1993-2002, Robert M Supnik Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), @@ -79,7 +79,7 @@ PTR,PTP PC11 paper tape reader/punch TTI,TTO DL11 console terminal LPT LP11 line printer CLK line frequency clock -DZ DZ11 8-line terminal multiplexor +DZ DZ11 8-line terminal multiplexor (up to 4) RK RK11/RK05 cartridge disk controller with eight drives RL RLV12/RL01(2) cartridge disk controller with four drives RP RM02/03/05/80, RP04/05/06/07 Massbus style controller @@ -90,13 +90,16 @@ TC TC11/TU56 DECtape controller with eight drives TM TM11/TU10 magnetic tape controller with eight drives TS TS11/TSV05 magnetic tape controller with one drive -The DZ, RK, RL, RP, RQ, RX, TC, TM, and TS devices can be DISABLEd. The -PDP-11 can support either a TM11 or a TS11, but not both, since they use -the same I/O addresses. The simulator defaults to the TM11. To change -the magtape, +The DZ, RK, RL, RP, RQ, RX, TC, TM, and TS devices can be set DISABLED. +With default I/O page addressing, the PDP-11 can support either a TM11 +or a TS11, but not both, since they use the same I/O addresses. The +simulator defaults to the TM11. To change the magtape from TM11 to TS11, - ENABLE TM11 enable TM11 and disable TS11 - ENABLE TS11 enable TS11 and disable TM11 + SET TM DISABLED disable TM11 + SET TS ENABLED enable TS11 + +Most devices support the SET ADDRESS command, which allows the I/O page +address of the device to be changed. The PDP-11 simulator implements several unique stop conditions: @@ -197,7 +200,8 @@ control registers for the interrupt system. STOP_TRAPS 18 stop on trap flags STOP_VECA 1 stop on read abort in trap or interrupt STOP_SPA 1 stop on stack push abort in trap or interrupt - OLDPC 16 PC prior to last JMP, JMS, or interrupt + PCQ[0:63] 16 PC prior to last jump, branch, or interrupt; + most recent PC change first WRU 8 interrupt character 2.2 Programmed I/O Devices @@ -219,7 +223,7 @@ The paper tape reader implements these registers: BUSY 1 busy flag (CSR<11>) DONE 1 device done flag (CSR<7>) IE 1 interrupt enable flag (CSR<6>) - POS 31 position in the input file + POS 32 position in the input file TIME 24 time from I/O initiation to interrupt STOP_IOE 1 stop on I/O error @@ -251,7 +255,7 @@ The paper tape punch implements these registers: ERR 1 error flag (CSR<15>) DONE 1 device done flag (CSR<7>) IE 1 interrupt enable flag (CSR<6>) - POS 31 position in the output file + POS 32 position in the output file TIME 24 time from I/O initiation to interrupt STOP_IOE 1 stop on I/O error @@ -277,7 +281,7 @@ implements these registers: ERR 1 error flag (CSR<15>) DONE 1 device done flag (CSR<7>) IE 1 interrupt enable flag (CSR<6>) - POS 31 number of characters input + POS 32 number of characters input TIME 24 keyboard polling interval 2.2.4 DL11 Terminal Output (TTO) @@ -293,7 +297,7 @@ implements these registers: ERR 1 error flag (CSR<15>) DONE 1 device done flag (CSR<7>) IE 1 interrupt enable flag (CSR<6>) - POS 31 number of characters input + POS 32 number of characters input TIME 24 time from I/O initiation to interrupt 2.2.5 LP11 Line Printer (LPT) @@ -312,7 +316,7 @@ The line printer implements these registers: ERR 1 error flag (CSR<15>) DONE 1 device done flag (CSR<7>) IE 1 interrupt enable flag (CSR<6>) - POS 31 position in the output file + POS 32 position in the output file TIME 24 time from I/O initiation to interrupt STOP_IOE 1 stop on I/O error @@ -327,7 +331,7 @@ Error handling is as follows: 2.2.6 Line-Time Clock (CLK) -The clock (CLK) implements these registers: +The line-time clock (CLK) implements these registers: name size comments @@ -338,16 +342,23 @@ The clock (CLK) implements these registers: TIME 24 clock frequency TPS 8 ticks per second (60 or 50) -The real-time clock autocalibrates; the clock interval is adjusted up or +The line-time clock autocalibrates; the clock interval is adjusted up or down so that the clock tracks actual elapsed time. 2.2.7 DZ11 Terminal Multiplexor (DZ) -The DZ11 is an 8-line terminal multiplexor. The terminal lines perform -input and output through Telnet sessions connected to a user-specified -port. The ATTACH command specifies the port to be used: +The DZ11 is an 8-line terminal multiplexor. Up to 4 DZ11's (32 lines) +are supported. The number of lines can be changed with the command - ATTACH {-am} DZ (cr) -- set up listening port + SET DZ LINES=n set line count to n + +The line count must be a multiple of 8, with a maximum of 32. + +The terminal lines perform input and output through Telnet sessions +connected to a user-specified port. The ATTACH command specifies +the port to be used: + + ATTACH {-am} DZ set up listening port where port is a decimal number between 1 and 65535 that is not being used for other TCP/IP activities. The optional switch -m turns on the DZ11's @@ -357,25 +368,28 @@ modem controls; the optional switch -a turns on active disconnects Once the DZ is attached and the simulator is running, the DZ will listen for connections on the specified port. It assumes that the incoming connections are Telnet connections. The connection remains open until -disconnected either by the simulated program or by the Telnet client. +disconnected by the simulated program, the Telnet client, a SET DZ +DISCONNECT command, or a DETACH DZ command. -The SHOW DZ LINESTATUS command displays the current connections to the DZ. +The SHOW DZ CONNECTIONS command displays the current connections to the DZ. +The SHOW DZ STATISTICS command displays statistics for active connections. +The SET DZ DISCONNECT=linenumber disconnects the specified line. The DZ11 implements these registers: name size comments - CSR 16 control/status register - RBUF 16 receive buffer - LPR 16 line parameter register - TCR 16 transmission control register - MSR 16 modem status register - TDR 16 transmit data register - SAENB 1 silo alarm enabled + CSR[0:3] 16 control/status register, boards 0..3 + RBUF[0:3] 16 receive buffer, boards 0..3 + LPR[0:3] 16 line parameter register, boards 0..3 + TCR[0:3] 16 transmission control register, boards 0..3 + MSR[0:3] 16 modem status register, boards 0..3 + TDR[0:3] 16 transmit data register, boards 0..3 + SAENB[0:3] 1 silo alarm enabled, boards 0..3 + RXINT 4 receive interrupts, boards 3..0 + TXINT 4 transmit interrupts, boards 3..0 MDMTCL 1 modem control enabled AUTODS 1 autodisconnect enabled - RPOS0..7 32 count of characters received - TPOS0..7 32 count of characters transmitted The DZ11 does not support save and restore. All open connections are lost when the simulator shuts down or the DZ is detached. @@ -385,10 +399,9 @@ lost when the simulator shuts down or the DZ is detached. RK11 options include the ability to make units write enabled or write locked: SET RKn LOCKED set unit n write locked - SET RKn ENABLED set unit n write enabled + SET RKn WRITEENABLED set unit n write enabled -Units can also be REMOVEd or ADDed to the configuration. The RK11 supports -the BOOT command. +Units can also be set ONLINE or OFFLINE. The RK11 supports the BOOT command. The RK11 implements these registers: @@ -427,7 +440,7 @@ Error handling is as follows: RX11 options include the ability to make units write enabled or write locked: SET RXn LOCKED set unit n write locked - SET RXn ENABLED set unit n write enabled + SET RXn WRITEENABLED set unit n write enabled The RX11 supports the BOOT command. @@ -471,7 +484,7 @@ to set the drive size to RL01, RL02, or autosize, and to write a DEC standard 044 compliant bad block table on the last track: SET RLn LOCKED set unit n write locked - SET RLn ENABLED set unit n write enabled + SET RLn WRITEENABLED set unit n write enabled SET RLn RL01 set size to RL01 SET RLn RL02 set size to RL02 SET RLn AUTOSIZE set size based on file size at attach @@ -479,8 +492,7 @@ to set the drive size to RL01, RL02, or autosize, and to write a DEC standard The size options can be used only when a unit is not attached to a file. The bad block option can be used only when a unit is attached to a file. Units -can also be REMOVEd or ADDed to the configuration. The RL11 supports the -BOOT command. +can also be set ONLINE or OFFLINE. The RL11 supports the BOOT command. The RL11 implements these registers: @@ -523,7 +535,7 @@ to set the drive type to one of six disk types, or autosize, and to write a DEC standard 044 compliant bad block table on the last track: SET RPn LOCKED set unit n write locked - SET RPn ENABLED set unit n write enabled + SET RPn WRITEENABLED set unit n write enabled SET RPn RM03 set type to RM03 SET RPn RM05 set type to RM05 SET RPn RM80 set type to RM80 @@ -533,10 +545,10 @@ a DEC standard 044 compliant bad block table on the last track: SET RPn AUTOSIZE set type based on file size at attach SET RPn BADBLOCK write bad block table on last track -The type options can be used only when a unit is not attached to a file. The -bad block option can be used only when a unit is attached to a file. Units -can also be REMOVEd or ADDed to the configuration. The RP controller supports -the BOOT command. +The type options can be used only when a unit is not attached to a file. +The bad block option can be used only when a unit is attached to a file. +Units can also be set ONLINE or OFFLINE. The RP controller supports the +BOOT command. The RP controller implements these registers: @@ -586,7 +598,7 @@ include the ability to set units write enabled or write locked, and to set the drive type to one of eleven disk types: SET RQn LOCKED set unit n write locked - SET RQn ENABLED set unit n write enabled + SET RQn WRITEENABLED set unit n write enabled SET RQn RX50 set type to RX50 SET RQn RX33 set type to RX33 SET RQn RD51 set type to RD51 @@ -598,10 +610,11 @@ set the drive type to one of eleven disk types: SET RQn RA72 set type to RA72 SET RQn RA90 set type to RA90 SET RQn RA92 set type to RA92 + SET RQn RRD40 set type to RRD40 (CD ROM) The type options can be used only when a unit is not attached to a file. -Units can also be REMOVEd or ADDed to the configuration. The RQ controller -supports the BOOT command. +Units can also be set ONLINE or OFFLINE. The RQ controller supports the +BOOT command. The RQ controller implements the following special SHOW commands: @@ -631,17 +644,23 @@ The RQ controller implements these registers: CSTA 4 controller state PERR 9 port error number CRED 5 host credits - HAT 16 host available timer + HAT 17 host available timer HTMO 17 host timeout value CPKT[0:3] 5 current packet, units 0-3 PKTQ[0:3] 5 packet queue, units 0-3 UFLG[0:3] 16 unit flags, units 0-3 INT 1 interrupt request + ITIME 1 response time for initialization steps + (except for step 4) QTIME 24 response time for 'immediate' packets XTIME 24 response time for data transfers PKTS[33*32] 16 packet buffers, 33W each, 32 entries +Some DEC operating systems, notably RSX11M/M+, are very sensitive to +the timing parameters. Changing the default values may cause M/M+ to +crash on boot or to hang during operation. + Error handling is as follows: error processed as @@ -659,17 +678,16 @@ DECtape options include the ability to make units write enabled or write locked. SET DTn LOCKED set unit n write locked - SET DTn ENABLED set unit n write enabled + SET DTn WRITEENABLED set unit n write enabled -Units can also be REMOVEd or ADDed to the configuration. The TC11 supports -the BOOT command. +Units can also be set ONLINE or OFFLINE. The TC11 supports the BOOT command. The TC11 supports both PDP-8 format and PDP-9/11/15 format DECtape images. ATTACH tries to determine the tape format from the DECtape image; the user can force a particular format with switches: - -f foreign (PDP-8) format - -n native (PDP-9/11/15) format + -f foreign (PDP-8) format + -n native (PDP-9/11/15) format The DECtape controller is a data-only simulator; the timing and mark track, and block header and trailer, are not stored. Thus, the WRITE @@ -695,7 +713,7 @@ The DECtape controller implements these registers: ACTIME 31 time to accelerate to full speed DCTIME 31 time to decelerate to a full stop SUBSTATE 2 read/write command substate - POS[0:7] 31 position, in lines, units 0-7 + POS[0:7] 32 position, in lines, units 0-7 STATT[0-7] 31 unit state, units 0-7 It is critically important to maintain certain timing relationships @@ -711,9 +729,9 @@ operate correctly. TM options include the ability to make units write enabled or write locked. SET TMn LOCKED set unit n write locked - SET TMn ENABLED set unit n write enabled + SET TMn WRITEENABLED set unit n write enabled -Units can also be REMOVEd or ADDed to the configuration. +Units can also be set ONLINE or OFFLINE. The TM11 supports the BOOT command. The bootstrap supports both original and DEC standard boot formats. Originally, a tape bootstrap read and @@ -737,7 +755,7 @@ The magnetic tape controller implements these registers: STOP_IOE 1 stop on I/O error TIME 24 delay UST[0:7] 16 unit status, units 0-7 - POS[0:7] 31 position, units 0-7 + POS[0:7] 32 position, units 0-7 Error handling is as follows: @@ -757,7 +775,7 @@ work with TS11 drivers. TS options include the ability to make the unit write enabled or write locked. SET TS LOCKED set unit write locked - SET TS ENABLED set unit write enabled + SET TS WRITEENABLED set unit write enabled The TS11 supports the BOOT command. The bootstrap supports only DEC standard boot formats. To allow for ANSI labels, the DEC standard bootstrap @@ -791,7 +809,7 @@ The magnetic tape controller implements these registers: OWNC 1 if set, tape owns command buffer OWNM 1 if set, tape owns message buffer TIME 24 delay - POS 31 position + POS 32 position Error handling is as follows: diff --git a/PDP11/pdp11_dz.c b/PDP11/pdp11_dz.c index 47620948..77a1296c 100644 --- a/PDP11/pdp11_dz.c +++ b/PDP11/pdp11_dz.c @@ -1,6 +1,6 @@ /* pdp11_dz.c: DZ11 terminal multiplexor simulator - Copyright (c) 1993-2001, Robert M Supnik + Copyright (c) 2001-2002, Robert M Supnik Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), diff --git a/PDP11/pdp11_fp.c b/PDP11/pdp11_fp.c index 0b61e8c3..3365f9be 100644 --- a/PDP11/pdp11_fp.c +++ b/PDP11/pdp11_fp.c @@ -1,6 +1,6 @@ /* pdp11_fp.c: PDP-11 floating point simulator (32b version) - Copyright (c) 1993-2001, Robert M Supnik + Copyright (c) 1993-2002, Robert M Supnik Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), diff --git a/PDP11/pdp11_io.c b/PDP11/pdp11_io.c index da5e9ff6..be31c414 100644 --- a/PDP11/pdp11_io.c +++ b/PDP11/pdp11_io.c @@ -1,6 +1,6 @@ /* pdp11_io.c: PDP-11 I/O simulator - Copyright (c) 1993-2001, Robert M Supnik + Copyright (c) 1993-2002, Robert M Supnik Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), @@ -23,6 +23,8 @@ be used in advertising or otherwise to promote the sale, use or other dealings in this Software without prior written authorization from Robert M Supnik. + 26-Jan-02 RMS Revised for multiple DZ's + 06-Jan-02 RMS Revised I/O access, enable/disable support 11-Dec-01 RMS Moved interrupt debug code 08-Nov-01 RMS Cloned from cpu sources */ @@ -39,83 +41,45 @@ extern int32 cpu_log; extern FILE *sim_log; int32 calc_ints (int32 nipl, int32 trq); -extern t_stat CPU_rd (int32 *data, int32 addr, int32 access); -extern t_stat CPU_wr (int32 data, int32 addr, int32 access); -extern t_stat APR_rd (int32 *data, int32 addr, int32 access); -extern t_stat APR_wr (int32 data, int32 addr, int32 access); -extern t_stat SR_MMR012_rd (int32 *data, int32 addr, int32 access); -extern t_stat SR_MMR012_wr (int32 data, int32 addr, int32 access); -extern t_stat MMR3_rd (int32 *data, int32 addr, int32 access); -extern t_stat MMR3_wr (int32 data, int32 addr, int32 access); -extern t_stat ubm_rd (int32 *data, int32 addr, int32 access); -extern t_stat ubm_wr (int32 data, int32 addr, int32 access); -extern t_stat std_rd (int32 *data, int32 addr, int32 access); -extern t_stat std_wr (int32 data, int32 addr, int32 access); -extern t_stat lpt_rd (int32 *data, int32 addr, int32 access); -extern t_stat lpt_wr (int32 data, int32 addr, int32 access); -extern t_stat dz_rd (int32 *data, int32 addr, int32 access); -extern t_stat dz_wr (int32 data, int32 addr, int32 access); -extern t_stat rk_rd (int32 *data, int32 addr, int32 access); -extern t_stat rk_wr (int32 data, int32 addr, int32 access); +extern DIB cpu0_dib, cpu1_dib, cpu2_dib; +extern DIB cpu3_dib, cpu4_dib, ubm_dib; +extern DIB pt_dib, tt_dib, clk_dib; +extern DIB lpt_dib, dz_dib; +extern DIB rk_dib, rl_dib; +extern DIB rp_dib, rq_dib; +extern DIB rx_dib, dt_dib; +extern DIB tm_dib, ts_dib; extern int32 rk_inta (void); -extern int32 rk_enb; -/* extern t_stat rk6_rd (int32 *data, int32 addr, int32 access); -extern t_stat rk6_wr (int32 data, int32 addr, int32 access); -extern int32 rk6_inta (void); -extern int32 rk6_enb; */ -extern t_stat rl_rd (int32 *data, int32 addr, int32 access); -extern t_stat rl_wr (int32 data, int32 addr, int32 access); -extern int32 rl_enb; -extern t_stat rp_rd (int32 *data, int32 addr, int32 access); -extern t_stat rp_wr (int32 data, int32 addr, int32 access); extern int32 rp_inta (void); -extern int32 rp_enb; -extern t_stat rq_rd (int32 *data, int32 addr, int32 access); -extern t_stat rq_wr (int32 data, int32 addr, int32 access); extern int32 rq_inta (void); -extern int32 rq_enb; -extern t_stat rx_rd (int32 *data, int32 addr, int32 access); -extern t_stat rx_wr (int32 data, int32 addr, int32 access); -extern int32 rx_enb; -extern t_stat dt_rd (int32 *data, int32 addr, int32 access); -extern t_stat dt_wr (int32 data, int32 addr, int32 access); -extern int32 dt_enb; -extern t_stat tm_rd (int32 *data, int32 addr, int32 access); -extern t_stat tm_wr (int32 data, int32 addr, int32 access); -extern int32 tm_enb; -extern t_stat ts_rd (int32 *data, int32 addr, int32 access); -extern t_stat ts_wr (int32 data, int32 addr, int32 access); -extern int32 ts_enb; +extern int32 dz_rxinta (void); +extern int32 dz_txinta (void); + +t_bool dev_conflict (uint32 nba, DIB *curr); /* I/O data structures */ -struct iolink { /* I/O page linkage */ - int32 low; /* low I/O addr */ - int32 high; /* high I/O addr */ - int32 *enb; /* enable flag */ - t_stat (*read)(); /* read routine */ - t_stat (*write)(); }; /* write routine */ - -struct iolink iotable[] = { - { IOBA_CPU, IOBA_CPU+IOLN_CPU, NULL, &CPU_rd, &CPU_wr }, - { IOBA_STD, IOBA_STD+IOLN_STD, NULL, &std_rd, &std_wr }, - { IOBA_LPT, IOBA_LPT+IOLN_LPT, NULL, &lpt_rd, &lpt_wr }, - { IOBA_DZ, IOBA_DZ +IOLN_DZ, NULL, &dz_rd, &dz_wr }, - { IOBA_RK, IOBA_RK +IOLN_RK, &rk_enb, &rk_rd, &rk_wr }, - { IOBA_RL, IOBA_RL +IOLN_RL, &rl_enb, &rl_rd, &rl_wr }, - { IOBA_RP, IOBA_RP +IOLN_RP, &rp_enb, &rp_rd, &rp_wr }, - { IOBA_RQ, IOBA_RQ +IOLN_RQ, &rq_enb, &rq_rd, &rq_wr }, - { IOBA_RX, IOBA_RX +IOLN_RX, &rx_enb, &rx_rd, &rx_wr }, - { IOBA_TC, IOBA_TC +IOLN_TC, &dt_enb, &dt_rd, &dt_wr }, - { IOBA_TM, IOBA_TM +IOLN_TM, &tm_enb, &tm_rd, &tm_wr }, - { IOBA_TS, IOBA_TS +IOLN_TS, &ts_enb, &ts_rd, &ts_wr }, -/* { IOBA_RK6, IOBA_RK6+IOLN_RK6, &rk6_enb, &rk6_rd, &rk6_wr }, */ - { IOBA_APR, IOBA_APR+IOLN_APR, NULL, &APR_rd, &APR_wr }, - { IOBA_APR1, IOBA_APR1+IOLN_APR1, NULL, &APR_rd, &APR_wr }, - { IOBA_SRMM, IOBA_SRMM+IOLN_SRMM, NULL, &SR_MMR012_rd, &SR_MMR012_wr }, - { IOBA_MMR3, IOBA_MMR3+IOLN_MMR3, NULL, &MMR3_rd, &MMR3_wr }, - { IOBA_UBM, IOBA_UBM+IOLN_UBM, NULL, &ubm_rd, &ubm_wr }, - { 0, 0, NULL, NULL, NULL } }; +DIB *dib_tab[] = { + &cpu0_dib, + &cpu1_dib, + &cpu2_dib, + &cpu3_dib, + &cpu4_dib, + &ubm_dib, + &pt_dib, + &tt_dib, + &clk_dib, + &lpt_dib, + &dz_dib, + &rk_dib, + &rl_dib, + &rp_dib, + &rq_dib, + &rx_dib, + &dt_dib, + &tm_dib, + &ts_dib, + NULL }; int32 int_vec[IPL_HLVL][32] = { /* int req to vector */ { 0 }, /* IPL 0 */ @@ -137,7 +101,8 @@ int32 (*int_ack[IPL_HLVL][32])() = { /* int ack routines */ { NULL }, /* IPL 3 */ { NULL }, /* IPL 4 */ { &rk_inta, NULL, NULL, NULL, /* IPL 5 */ - &rp_inta, NULL, NULL, &rq_inta }, + &rp_inta, NULL, NULL, &rq_inta, + &dz_rxinta, &dz_txinta, NULL }, { NULL }, /* IPL 6 */ { NULL } }; /* IPL 7 */ @@ -152,29 +117,31 @@ int32 (*int_ack[IPL_HLVL][32])() = { /* int ack routines */ status = SCPE_OK or SCPE_NXM */ -t_stat iopageR (int32 *data, int32 pa, int32 access) +t_stat iopageR (int32 *data, uint32 pa, int32 access) { +int32 i; +DIB *dibp; t_stat stat; -struct iolink *p; -for (p = &iotable[0]; p -> low != 0; p++ ) { - if ((pa >= p -> low) && (pa < p -> high) && - ((p -> enb == NULL) || *p -> enb)) { - stat = p -> read (data, pa, access); +for (i = 0; dibp = dib_tab[i]; i++ ) { + if (dibp -> enb && (pa >= dibp -> ba) && + (pa < (dibp -> ba + dibp -> lnt))) { + stat = dibp -> rd (data, pa, access); trap_req = calc_ints (ipl, trap_req); return stat; } } return SCPE_NXM; } -t_stat iopageW (int32 data, int32 pa, int32 access) +t_stat iopageW (int32 data, uint32 pa, int32 access) { +int32 i; +DIB *dibp; t_stat stat; -struct iolink *p; -for (p = &iotable[0]; p -> low != 0; p++ ) { - if ((pa >= p -> low) && (pa < p -> high) && - ((p -> enb == NULL) || *p -> enb)) { - stat = p -> write (data, pa, access); +for (i = 0; dibp = dib_tab[i]; i++ ) { + if (dibp -> enb && (pa >= dibp -> ba) && + (pa < (dibp -> ba + dibp -> lnt))) { + stat = dibp -> wr (data, pa, access); trap_req = calc_ints (ipl, trap_req); return stat; } } return SCPE_NXM; @@ -359,3 +326,86 @@ else { /* physical */ M[ba >> 1] = *buf++; } return (lim - alim); } } + +/* Change device number for a device */ + +t_stat set_addr (UNIT *uptr, int32 val, char *cptr, void *desc) +{ +DIB *dibp; +uint32 newba; +t_stat r; + +if (cptr == NULL) return SCPE_ARG; +if ((val == 0) || (desc == NULL)) return SCPE_IERR; +dibp = (DIB *) desc; +newba = get_uint (cptr, 8, PAMASK, &r); /* get new */ +if ((r != SCPE_OK) || (newba == dibp -> ba)) return r; +if (newba <= IOPAGEBASE) return SCPE_ARG; /* > IO page base? */ +if (newba % ((uint32) val)) return SCPE_ARG; /* check modulus */ +if (dev_conflict (newba, dibp)) return SCPE_OK; +dibp -> ba = newba; /* store */ +return SCPE_OK; +} + +/* Show device address */ + +t_stat show_addr (FILE *st, UNIT *uptr, int32 val, void *desc) +{ +DIB *dibp; + +if (desc == NULL) return SCPE_IERR; +dibp = (DIB *) desc; +if (dibp -> ba <= IOPAGEBASE) return SCPE_IERR; +fprintf (st, "address=%08o", dibp -> ba); +if (dibp -> lnt > 1) + fprintf (st, "-%08o", dibp -> ba + dibp -> lnt - 1); +return SCPE_OK; +} + +/* Enable or disable a device */ + +t_stat set_enbdis (UNIT *uptr, int32 val, char *cptr, void *desc) +{ +int32 i; +DEVICE *dptr; +DIB *dibp; +UNIT *up; + +if (cptr != NULL) return SCPE_ARG; +if ((uptr == NULL) || (desc == NULL)) return SCPE_IERR; +dptr = find_dev_from_unit (uptr); /* find device */ +if (dptr == NULL) return SCPE_IERR; +dibp = (DIB *) desc; +if ((val ^ dibp -> enb) == 0) return SCPE_OK; /* enable chg? */ +if (val) { /* enable? */ + if (dev_conflict (dibp -> ba, dibp)) return SCPE_OK; } +else { /* disable */ + for (i = 0; i < dptr -> numunits; i++) { /* check units */ + up = (dptr -> units) + i; + if ((up -> flags & UNIT_ATT) || sim_is_active (up)) + return SCPE_NOFNC; } } +dibp -> enb = val; +if (dptr -> reset) return dptr -> reset (dptr); +else return SCPE_OK; +} + +/* Test for conflict in device addresses */ + +t_bool dev_conflict (uint32 nba, DIB *curr) +{ +uint32 i, end; +DIB *dibp; + +end = nba + curr -> lnt - 1; /* get end */ +for (i = 0; dibp = dib_tab[i]; i++) { /* loop thru dev */ + if (!dibp -> enb || (dibp == curr)) continue; /* skip disabled */ + if (((nba >= dibp -> ba) && /* overlap start? */ + (nba < (dibp -> ba + dibp -> lnt))) || + ((end >= dibp -> ba) && /* overlap end? */ + (end < (dibp -> ba + dibp -> lnt)))) { + printf ("Device address conflict at %08o\n", dibp -> ba); + if (sim_log) fprintf (sim_log, + "Device number conflict at %08o\n", dibp -> ba); + return TRUE; } } +return FALSE; +} diff --git a/PDP11/pdp11_lp.c b/PDP11/pdp11_lp.c index fec48890..a688d4b2 100644 --- a/PDP11/pdp11_lp.c +++ b/PDP11/pdp11_lp.c @@ -1,6 +1,6 @@ /* pdp11_lp.c: PDP-11 line printer simulator - Copyright (c) 1993-2001, Robert M Supnik + Copyright (c) 1993-2002, Robert M Supnik Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), @@ -25,6 +25,8 @@ lpt LP11 line printer + 30-May-02 RMS Widened POS to 32b + 06-Jan-02 RMS Added enable/disable support 09-Nov-01 RMS Added VAX support 07-Sep-01 RMS Revised interrupt mechanism 30-Oct-00 RMS Standardized register naming @@ -45,8 +47,12 @@ #define LPTCSR_RW (CSR_IE) /* read/write */ extern int32 int_req[IPL_HLVL]; + int32 lpt_csr = 0; /* control/status */ int32 lpt_stopioe = 0; /* stop on error */ + +t_stat lpt_rd (int32 *data, int32 PA, int32 access); +t_stat lpt_wr (int32 data, int32 PA, int32 access); t_stat lpt_svc (UNIT *uptr); t_stat lpt_reset (DEVICE *dptr); t_stat lpt_attach (UNIT *uptr, char *ptr); @@ -59,6 +65,8 @@ t_stat lpt_detach (UNIT *uptr); lpt_reg LPT register list */ +DIB lpt_dib = { 1, IOBA_LPT, IOLN_LPT, &lpt_rd, &lpt_wr }; + UNIT lpt_unit = { UDATA (&lpt_svc, UNIT_SEQ+UNIT_ATTABLE, 0), SERIAL_OUT_WAIT }; @@ -69,13 +77,24 @@ REG lpt_reg[] = { { FLDATA (ERR, lpt_csr, CSR_V_ERR) }, { FLDATA (DONE, lpt_csr, CSR_V_DONE) }, { FLDATA (IE, lpt_csr, CSR_V_IE) }, - { DRDATA (POS, lpt_unit.pos, 31), PV_LEFT }, + { DRDATA (POS, lpt_unit.pos, 32), PV_LEFT }, { DRDATA (TIME, lpt_unit.wait, 24), PV_LEFT }, { FLDATA (STOP_IOE, lpt_stopioe, 0) }, + { GRDATA (DEVADDR, lpt_dib.ba, LPT_DRDX, 32, 0), REG_HRO }, + { FLDATA (*DEVENB, lpt_dib.enb, 0), REG_HRO }, { NULL } }; +MTAB lpt_mod[] = { + { MTAB_XTD|MTAB_VDV, 004, "ADDRESS", "ADDRESS", + &set_addr, &show_addr, &lpt_dib }, + { MTAB_XTD|MTAB_VDV, 1, NULL, "ENABLED", + &set_enbdis, NULL, &lpt_dib }, + { MTAB_XTD|MTAB_VDV, 0, NULL, "DISABLED", + &set_enbdis, NULL, &lpt_dib }, + { 0 } }; + DEVICE lpt_dev = { - "LPT", &lpt_unit, lpt_reg, NULL, + "LPT", &lpt_unit, lpt_reg, lpt_mod, 1, 10, 31, 1, LPT_DRDX, 8, NULL, NULL, &lpt_reset, NULL, &lpt_attach, &lpt_detach }; diff --git a/PDP11/pdp11_rk.c b/PDP11/pdp11_rk.c index fb940df0..72a9e74c 100644 --- a/PDP11/pdp11_rk.c +++ b/PDP11/pdp11_rk.c @@ -1,6 +1,6 @@ /* pdp11_rk.c: RK11 cartridge disk simulator - Copyright (c) 1993-2001, Robert M Supnik + Copyright (c) 1993-2002, Robert M Supnik Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), @@ -25,6 +25,8 @@ rk RK11/RK05 cartridge disk + 26-Jan-02 RMS Revised bootstrap to conform to M9312 + 06-Jan-02 RMS Revised enable/disable support 30-Nov-01 RMS Added read only unit, extended SET/SHOW support 24-Nov-01 RMS Converted FLG to array 09-Nov-01 RMS Added bus map support @@ -179,7 +181,9 @@ int32 last_drv = 0; /* last r/w drive */ int32 rk_stopioe = 1; /* stop on error */ int32 rk_swait = 10; /* seek time */ int32 rk_rwait = 10; /* rotate time */ -int32 rk_enb = 1; /* device enable */ + +t_stat rk_rd (int32 *data, int32 PA, int32 access); +t_stat rk_wr (int32 data, int32 PA, int32 access); t_stat rk_svc (UNIT *uptr); t_stat rk_reset (DEVICE *dptr); void rk_go (void); @@ -195,6 +199,8 @@ t_stat rk_boot (int32 unitno); rk_mod RK modifier list */ +DIB rk_dib = { 1, IOBA_RK, IOLN_RK, &rk_rd, &rk_wr }; + UNIT rk_unit[] = { { UDATA (&rk_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+ UNIT_ROABLE, RK_SIZE) }, @@ -231,12 +237,19 @@ REG rk_reg[] = { { URDATA (FLG, rk_unit[0].flags, 8, UNIT_W_UF, UNIT_V_UF - 1, RK_NUMDR, REG_HRO) }, { FLDATA (STOP_IOE, rk_stopioe, 0) }, - { FLDATA (*DEVENB, rk_enb, 0), REG_HRO }, + { ORDATA (DEVADDR, rk_dib.ba, 32), REG_HRO }, + { FLDATA (*DEVENB, rk_dib.enb, 0), REG_HRO }, { NULL } }; MTAB rk_mod[] = { - { UNIT_HWLK, 0, "write enabled", "ENABLED", NULL }, + { UNIT_HWLK, 0, "write enabled", "WRITEENABLED", NULL }, { UNIT_HWLK, UNIT_HWLK, "write locked", "LOCKED", NULL }, + { MTAB_XTD|MTAB_VDV, 020, "ADDRESS", "ADDRESS", + &set_addr, &show_addr, &rk_dib }, + { MTAB_XTD|MTAB_VDV, 1, NULL, "ENABLED", + &set_enbdis, NULL, &rk_dib }, + { MTAB_XTD|MTAB_VDV, 0, NULL, "DISABLED", + &set_enbdis, NULL, &rk_dib }, { 0 } }; DEVICE rk_dev = { @@ -551,11 +564,13 @@ return SCPE_OK; /* Device bootstrap */ -#define BOOT_START 02000 /* start */ -#define BOOT_UNIT 02006 /* unit number */ +#define BOOT_START 02000 /* start */ +#define BOOT_ENTRY 02002 /* entry */ +#define BOOT_UNIT 02010 /* unit number */ #define BOOT_LEN (sizeof (boot_rom) / sizeof (int32)) static const int32 boot_rom[] = { + 0042113, /* "KD" */ 0012706, 0002000, /* MOV #2000, SP */ 0012700, 0000000, /* MOV #unit, R0 ; unit number */ 0010003, /* MOV R0, R3 */ @@ -572,8 +587,8 @@ static const int32 boot_rom[] = { 0012741, 0000005, /* MOV #READ+GO, -(R1) ; read & go */ 0005002, /* CLR R2 */ 0005003, /* CLR R3 */ - 0005004, /* CLR R4 */ - 0012705, 0045504, /* MOV #"DK, R5 */ + 0012704, BOOT_START+020, /* MOV #START+20, R4 */ + 0005005, /* CLR R5 */ 0105711, /* TSTB (R1) */ 0100376, /* BPL .-2 */ 0105011, /* CLRB (R1) */ @@ -587,6 +602,6 @@ extern int32 saved_PC; for (i = 0; i < BOOT_LEN; i++) M[(BOOT_START >> 1) + i] = boot_rom[i]; M[BOOT_UNIT >> 1] = unitno & RK_M_NUMDR; -saved_PC = BOOT_START; +saved_PC = BOOT_ENTRY; return SCPE_OK; } diff --git a/PDP11/pdp11_rl.c b/PDP11/pdp11_rl.c index 07cbc29e..36d4f7ca 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-2001, Robert M Supnik + Copyright (c) 1993-2002, Robert M Supnik Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), @@ -25,7 +25,9 @@ rl RL11(RLV12)/RL01/RL02 cartridge disk - 30-Nov-01 MRS Added read only, extended SET/SHOW support + 26-Jan-02 RMS Revised bootstrap to conform to M9312 + 06-Jan-02 RMS Revised enable/disable support + 30-Nov-01 RMS Added read only, extended SET/SHOW support 26-Nov-01 RMS Fixed per-drive error handling 24-Nov-01 RMS Converted FLG, CAPAC to arrays 19-Nov-01 RMS Fixed signed/unsigned mismatch in write check @@ -192,7 +194,9 @@ int32 rlmp = 0, rlmp1 = 0, rlmp2 = 0; /* mp register queue */ int32 rl_swait = 10; /* seek wait */ int32 rl_rwait = 10; /* rotate wait */ int32 rl_stopioe = 1; /* stop on error */ -int32 rl_enb = 1; /* device enable */ + +t_stat rl_rd (int32 *data, int32 PA, int32 access); +t_stat rl_wr (int32 data, int32 PA, int32 access); t_stat rl_svc (UNIT *uptr); t_stat rl_reset (DEVICE *dptr); void rl_set_done (int32 error); @@ -210,6 +214,8 @@ extern t_stat pdp11_bad_block (UNIT *uptr, int32 sec, int32 wds); rl_mod RL modifier list */ +DIB rl_dib = { 1, IOBA_RL, IOLN_RL, &rl_rd, &rl_wr }; + UNIT rl_unit[] = { { UDATA (&rl_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+ UNIT_ROABLE+UNIT_AUTO, RL01_SIZE) }, @@ -239,11 +245,12 @@ REG rl_reg[] = { { URDATA (CAPAC, rl_unit[0].capac, 10, 31, 0, RL_NUMDR, PV_LEFT + REG_HRO) }, { FLDATA (STOP_IOE, rl_stopioe, 0) }, - { FLDATA (*DEVENB, rl_enb, 0), REG_HRO }, + { GRDATA (DEVADDR, rl_dib.ba, RL_RDX, 32, 0), REG_HRO }, + { FLDATA (*DEVENB, rl_dib.enb, 0), REG_HRO }, { NULL } }; MTAB rl_mod[] = { - { UNIT_WLK, 0, "write enabled", "ENABLED", NULL }, + { UNIT_WLK, 0, "write enabled", "WRITEENABLED", NULL }, { UNIT_WLK, UNIT_WLK, "write locked", "LOCKED", NULL }, { UNIT_DUMMY, 0, NULL, "BADBLOCK", &rl_set_bad }, { (UNIT_RL02+UNIT_ATT), UNIT_ATT, "RL01", NULL, NULL }, @@ -254,6 +261,12 @@ MTAB rl_mod[] = { { UNIT_AUTO, UNIT_AUTO, NULL, "AUTOSIZE", NULL }, { (UNIT_AUTO+UNIT_RL02), 0, NULL, "RL01", &rl_set_size }, { (UNIT_AUTO+UNIT_RL02), UNIT_RL02, NULL, "RL02", &rl_set_size }, + { MTAB_XTD|MTAB_VDV, 010, "ADDRESS", "ADDRESS", + &set_addr, &show_addr, &rl_dib }, + { MTAB_XTD|MTAB_VDV, 1, NULL, "ENABLED", + &set_enbdis, NULL, &rl_dib }, + { MTAB_XTD|MTAB_VDV, 0, NULL, "DISABLED", + &set_enbdis, NULL, &rl_dib }, { 0 } }; DEVICE rl_dev = { @@ -561,11 +574,13 @@ return pdp11_bad_block (uptr, RL_NUMSC, RL_NUMWD); #if defined (VM_PDP11) -#define BOOT_START 02000 /* start */ -#define BOOT_UNIT 02006 /* unit number */ +#define BOOT_START 02000 /* start */ +#define BOOT_ENTRY 02002 /* entry */ +#define BOOT_UNIT 02010 /* unit number */ #define BOOT_LEN (sizeof (boot_rom) / sizeof (int32)) static const int32 boot_rom[] = { + 0042114, /* "LD" */ 0012706, 0002000, /* MOV #2000, SP */ 0012700, 0000000, /* MOV #UNIT, R0 */ 0010003, /* MOV R0, R3 */ @@ -601,8 +616,8 @@ static const int32 boot_rom[] = { 0042711, 0000377, /* BIC #377, (R1) */ 0005002, /* CLR R2 */ 0005003, /* CLR R3 */ - 0005004, /* CLR R4 */ - 0012705, 0046104, /* MOV "DL, R5 */ + 0012704, BOOT_START+020, /* MOV #START+20, R4 */ + 0005005, /* CLR R5 */ 0005007 /* CLR PC */ }; @@ -614,7 +629,7 @@ extern uint16 *M; for (i = 0; i < BOOT_LEN; i++) M[(BOOT_START >> 1) + i] = boot_rom[i]; M[BOOT_UNIT >> 1] = unitno & RLCS_M_DRIVE; -saved_PC = BOOT_START; +saved_PC = BOOT_ENTRY; return SCPE_OK; } diff --git a/PDP11/pdp11_rp.c b/PDP11/pdp11_rp.c index 207b9fcf..ea825195 100644 --- a/PDP11/pdp11_rp.c +++ b/PDP11/pdp11_rp.c @@ -1,6 +1,6 @@ /* pdp11_rp.c - RP04/05/06/07 RM02/03/05/80 "Massbus style" disk controller - Copyright (c) 1993-2001, Robert M Supnik + Copyright (c) 1993-2002, Robert M Supnik Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), @@ -25,6 +25,9 @@ rp RH/RP/RM moving head disks + 24-Apr-02 RMS Fixed SHOW RP ADDRESS + 26-Jan-02 RMS Revised bootstrap to conform to M9312 + 06-Jan-02 RMS Revised enable/disable support 30-Nov-01 RMS Added read only unit, extended SET/SHOW support 24-Nov-01 RMS Changed RPDS, RPER, FLG, CAPAC, RPFN to arrays 09-Nov-01 RMS Added bus map, VAX support @@ -385,20 +388,21 @@ int32 rpiff = 0; /* INTR flip/flop */ int32 rp_stopioe = 1; /* stop on error */ int32 rp_swait = 10; /* seek time */ int32 rp_rwait = 10; /* rotate time */ -int32 rp_enb = 1; /* device enable */ int reg_in_drive[32] = { 0, 0, 0, 1, 0, 1, 1, 0, 1, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; -void update_rpcs (int32 flags, int32 drv); -void rp_go (int32 drv, int32 fnc); -t_stat rp_set_size (UNIT *uptr, int32 val, char *cptr, void *desc); -t_stat rp_set_bad (UNIT *uptr, int32 val, char *cptr, void *desc); +t_stat rp_rd (int32 *data, int32 PA, int32 access); +t_stat rp_wr (int32 data, int32 PA, int32 access); t_stat rp_svc (UNIT *uptr); t_stat rp_reset (DEVICE *dptr); t_stat rp_boot (int32 unitno); t_stat rp_attach (UNIT *uptr, char *cptr); t_stat rp_detach (UNIT *uptr); +void update_rpcs (int32 flags, int32 drv); +void rp_go (int32 drv, int32 fnc); +t_stat rp_set_size (UNIT *uptr, int32 val, char *cptr, void *desc); +t_stat rp_set_bad (UNIT *uptr, int32 val, char *cptr, void *desc); extern t_stat pdp11_bad_block (UNIT *uptr, int32 sec, int32 wds); /* RP data structures @@ -409,6 +413,8 @@ extern t_stat pdp11_bad_block (UNIT *uptr, int32 sec, int32 wds); rp_mod RP modifier list */ +DIB rp_dib = { 1, IOBA_RP, IOLN_RP, &rp_rd, &rp_wr }; + UNIT rp_unit[] = { { UDATA (&rp_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+UNIT_AUTO+ UNIT_ROABLE+(RM03_DTYPE << UNIT_V_DTYPE), RM03_SIZE) }, @@ -459,11 +465,12 @@ REG rp_reg[] = { { URDATA (CAPAC, rp_unit[0].capac, 10, 31, 0, RP_NUMDR, PV_LEFT | REG_HRO) }, { FLDATA (STOP_IOE, rp_stopioe, 0) }, - { FLDATA (*DEVENB, rp_enb, 0), REG_HRO }, + { GRDATA (DEVADDR, rp_dib.ba, RP_RDX, 32, 0), REG_HRO }, + { FLDATA (*DEVENB, rp_dib.enb, 0), REG_HRO }, { NULL } }; MTAB rp_mod[] = { - { UNIT_WLK, 0, "write enabled", "ENABLED", NULL }, + { UNIT_WLK, 0, "write enabled", "WRITEENABLED", NULL }, { UNIT_WLK, UNIT_WLK, "write locked", "LOCKED", NULL }, { UNIT_DUMMY, 0, NULL, "BADBLOCK", &rp_set_bad }, { (UNIT_DTYPE+UNIT_ATT), (RM03_DTYPE << UNIT_V_DTYPE) + UNIT_ATT, @@ -504,6 +511,12 @@ MTAB rp_mod[] = { NULL, "RM05", &rp_set_size }, { (UNIT_AUTO+UNIT_DTYPE), (RP07_DTYPE << UNIT_V_DTYPE), NULL, "RP07", &rp_set_size }, + { MTAB_XTD|MTAB_VDV, 0100, "ADDRESS", "ADDRESS", + &set_addr, &show_addr, &rp_dib }, + { MTAB_XTD|MTAB_VDV, 1, NULL, "ENABLED", + &set_enbdis, NULL, &rp_dib }, + { MTAB_XTD|MTAB_VDV, 0, NULL, "DISABLED", + &set_enbdis, NULL, &rp_dib }, { 0 } }; DEVICE rp_dev = { @@ -1106,11 +1119,13 @@ return pdp11_bad_block (uptr, drv_tab[GET_DTYPE (uptr -> flags)].sect, RP_NUMWD) #if defined (VM_PDP11) -#define BOOT_START 02000 /* start */ -#define BOOT_UNIT 02006 /* unit number */ +#define BOOT_START 02000 /* start */ +#define BOOT_ENTRY 02002 +#define BOOT_UNIT 02010 /* unit number */ #define BOOT_LEN (sizeof (boot_rom) / sizeof (int32)) static const int32 boot_rom[] = { + 0042102, /* "DB" */ 0012706, 0002000, /* mov #2000, sp */ 0012700, 0000000, /* mov #unit, r0 */ 0012701, 0176700, /* mov #RPCS1, r1 */ @@ -1118,7 +1133,7 @@ static const int32 boot_rom[] = { 0010037, 0176710, /* mov r0, RPCS2 */ 0012711, 0000021, /* mov #RIP+GO, (R1) */ 0012737, 0010000, 0176732, /* mov #FMT16B, RPOF */ - 0005037, 0176750, /* clr RPBAE */ +/* 0005037, 0176750, /* clr RPBAE */ 0005037, 0176704, /* clr RPBA */ 0005037, 0176734, /* clr RPDC */ 0005037, 0176706, /* clr RPDA */ @@ -1126,8 +1141,8 @@ static const int32 boot_rom[] = { 0012711, 0000071, /* mov #READ+GO, (R1) */ 0005002, /* clr R2 */ 0005003, /* clr R3 */ - 0005004, /* clr R4 */ - 0012705, 0050104, /* mov #"DP, r5 */ + 0012704, BOOT_START+020, /* mov #start+020, r4 */ + 0005005, /* clr R5 */ 0105711, /* tstb (R1) */ 0100376, /* bpl .-2 */ 0105011, /* clrb (R1) */ @@ -1141,7 +1156,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 & CS2_M_UNIT; -saved_PC = BOOT_START; +saved_PC = BOOT_ENTRY; return SCPE_OK; } diff --git a/PDP11/pdp11_rq.c b/PDP11/pdp11_rq.c index f8d8e342..c77e1068 100644 --- a/PDP11/pdp11_rq.c +++ b/PDP11/pdp11_rq.c @@ -1,6 +1,6 @@ -/* vax_rq.c: RQDX3 disk controller simulator +/* pdp11_rq.c: RQDX3 disk controller simulator - Copyright (c) 2001, Robert M Supnik + Copyright (c) 2002, Robert M Supnik Derived from work by Stephen F. Shirron Permission is hereby granted, free of charge, to any person obtaining a @@ -26,6 +26,14 @@ rq RQDX3 disk controller + 04-May-02 RMS Fixed bug in polling loop for queued operations + 26-Mar-02 RMS Fixed bug, reset routine cleared UF_WPH + 09-Mar-02 RMS Adjusted delays for M+ timing bugs + 04-Mar-02 RMS Added delays to initialization for M+, RSTS/E + 16-Feb-02 RMS Fixed bugs in host timeout logic, boot + 26-Jan-02 RMS Revised bootstrap to conform to M9312 + 06-Jan-02 RMS Revised enable/disable support + 30-Dec-01 RMS Revised show routines 19-Dec-01 RMS Added bigger drives 17-Dec-01 RMS Added queue process */ @@ -79,8 +87,12 @@ #define GET_DTYPE(x) (((x) >> UNIT_V_DTYPE) & UNIT_M_DTYPE) #define cpkt u3 /* current packet */ #define pktq u4 /* packet queue */ -#define uf buf /* unit flags */ +#define uf buf /* settable unit flags */ #define UNIT_WPRT (UNIT_WLK | UNIT_RO) /* write prot */ +#define RQ_RMV(u) ((drv_tab[GET_DTYPE (u -> flags)].flgs & RQDF_RMV)? \ + UF_RMV: 0) +#define RQ_WPH(u) (((drv_tab[GET_DTYPE (u -> flags)].flgs & RQDF_RO) || \ + (u -> flags & UNIT_WPRT))? UF_WPH: 0) #define CST_S1 0 /* init stage 1 */ #define CST_S1_WR 1 /* stage 1 wrap */ @@ -407,9 +419,13 @@ static struct drvtyp drv_tab[] = { extern int32 int_req[IPL_HLVL]; extern int32 tmr_poll, clk_tps; +extern int32 cpu_log; extern UNIT cpu_unit; +extern FILE *sim_log; + uint16 *rqxb = NULL; /* xfer buffer */ uint32 rq_sa = 0; /* status, addr */ +uint32 rq_saw = 0; /* written data */ uint32 rq_s1dat = 0; /* S1 data */ uint32 rq_csta = 0; /* ctrl state */ uint32 rq_perr = 0; /* last error */ @@ -425,10 +441,14 @@ uint32 rq_pbsy = 0; /* #busy pkts */ uint32 rq_credits = 0; /* credits */ uint32 rq_hat = 0; /* host timer */ uint32 rq_htmo = RQ_DHTMO; /* host timeout */ -int32 rq_qtime = 100; /* queue time */ +int32 rq_itime = 200; /* init time, except */ +int32 rq_itime4 = 10; /* stage 4 */ +int32 rq_qtime = 200; /* queue time */ int32 rq_xtime = 500; /* transfer time */ int32 rq_enb = 1; /* device enable */ +t_stat rq_rd (int32 *data, int32 PA, int32 access); +t_stat rq_wr (int32 data, int32 PA, int32 access); t_stat rq_svc (UNIT *uptr); t_stat rq_tmrsvc (UNIT *uptr); t_stat rq_quesvc (UNIT *uptr); @@ -483,6 +503,8 @@ UNIT *rq_getucb (uint32 lu); rq_mod RQ modifier list */ +DIB rq_dib = { 1, IOBA_RQ, IOLN_RQ, &rq_rd, &rq_wr }; + UNIT rq_unit[] = { { UDATA (&rq_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+UNIT_ROABLE+ (RD54_DTYPE << UNIT_V_DTYPE), RQ_SIZE (RD54)) }, @@ -500,6 +522,7 @@ UNIT rq_unit[] = { REG rq_reg[] = { { GRDATA (SA, rq_sa, RQ_RDX, 16, 0) }, + { GRDATA (SAW, rq_sa, RQ_RDX, 16, 0) }, { GRDATA (S1DAT, rq_s1dat, RQ_RDX, 16, 0) }, { GRDATA (CQBA, rq_cq.ba, RQ_RDX, 22, 0) }, { GRDATA (CQLNT, rq_cq.lnt, RQ_RDX, 8, 2), REG_NZ }, @@ -507,31 +530,33 @@ REG rq_reg[] = { { GRDATA (RQBA, rq_rq.ba, RQ_RDX, 22, 0) }, { GRDATA (RQLNT, rq_rq.lnt, RQ_RDX, 8, 2), REG_NZ }, { GRDATA (RQIDX, rq_rq.idx, RQ_RDX, 8, 2) }, - { GRDATA (FREE, rq_freq, RQ_RDX, 5, 0) }, - { GRDATA (RESP, rq_rspq, RQ_RDX, 5, 0) }, - { GRDATA (PBSY, rq_pbsy, RQ_RDX, 5, 0) }, + { DRDATA (FREE, rq_freq, 5) }, + { DRDATA (RESP, rq_rspq, 5) }, + { DRDATA (PBSY, rq_pbsy, 5) }, { GRDATA (CFLGS, rq_cflgs, RQ_RDX, 16, 0) }, { GRDATA (CSTA, rq_csta, RQ_RDX, 4, 0) }, { GRDATA (PERR, rq_perr, RQ_RDX, 9, 0) }, - { GRDATA (CRED, rq_credits, RQ_RDX, 5, 0) }, - { GRDATA (HAT, rq_hat, RQ_RDX, 16, 0) }, - { GRDATA (HTMO, rq_htmo, RQ_RDX, 17, 0) }, - { URDATA (CPKT, rq_unit[0].cpkt, RQ_RDX, 5, 0, RQ_NUMDR, 0) }, - { URDATA (PKTQ, rq_unit[0].pktq, RQ_RDX, 5, 0, RQ_NUMDR, 0) }, + { DRDATA (CRED, rq_credits, 5) }, + { DRDATA (HAT, rq_hat, 17) }, + { DRDATA (HTMO, rq_htmo, 17) }, + { URDATA (CPKT, rq_unit[0].cpkt, 10, 5, 0, RQ_NUMDR, 0) }, + { URDATA (PKTQ, rq_unit[0].pktq, 10, 5, 0, RQ_NUMDR, 0) }, { URDATA (UFLG, rq_unit[0].uf, RQ_RDX, 16, 0, RQ_NUMDR, 0) }, { URDATA (SFLG, rq_unit[0].flags, RQ_RDX, UNIT_W_UF, UNIT_V_UF-1, RQ_NUMDR, REG_HRO) }, { FLDATA (PRGI, rq_prgi, 0), REG_HIDDEN }, { FLDATA (PIP, rq_pip, 0), REG_HIDDEN }, { FLDATA (INT, IREQ (RQ), INT_V_RQ) }, + { DRDATA (ITIME, rq_itime, 24), PV_LEFT + REG_NZ }, { DRDATA (QTIME, rq_qtime, 24), PV_LEFT + REG_NZ }, { DRDATA (XTIME, rq_xtime, 24), PV_LEFT + REG_NZ }, { BRDATA (PKTS, rq_pkt, RQ_RDX, 16, RQ_NPKTS * (RQ_PKT_SIZE_W + 1)) }, - { FLDATA (*DEVENB, rq_enb, 0), REG_HRO }, + { GRDATA (DEVADDR, rq_dib.ba, RQ_RDX, 32, 0), REG_HRO }, + { FLDATA (*DEVENB, rq_dib.enb, 0), REG_HRO }, { NULL } }; MTAB rq_mod[] = { - { UNIT_WLK, 0, NULL, "ENABLED", &rq_set_wlk }, + { UNIT_WLK, 0, NULL, "WRITEENABLED", &rq_set_wlk }, { UNIT_WLK, UNIT_WLK, NULL, "LOCKED", &rq_set_wlk }, { MTAB_XTD | MTAB_VDV | MTAB_NMO, RQ_SH_RI, "RINGS", NULL, NULL, &rq_show_ctrl, NULL }, @@ -560,11 +585,17 @@ MTAB rq_mod[] = { { UNIT_DTYPE, (RA92_DTYPE << UNIT_V_DTYPE), "RA92", "RA92", &rq_set_size }, { UNIT_DTYPE, (RRD40_DTYPE << UNIT_V_DTYPE), "RRD40", "RRD40", &rq_set_size }, { UNIT_DTYPE, (RRD40_DTYPE << UNIT_V_DTYPE), NULL, "CDROM", &rq_set_size }, + { MTAB_XTD|MTAB_VDV, 004, "ADDRESS", "ADDRESS", + &set_addr, &show_addr, &rq_dib }, + { MTAB_XTD|MTAB_VDV, 1, NULL, "ENABLED", + &set_enbdis, NULL, &rq_dib }, + { MTAB_XTD|MTAB_VDV, 0, NULL, "DISABLED", + &set_enbdis, NULL, &rq_dib }, { 0 } }; DEVICE rq_dev = { "RQ", rq_unit, rq_reg, rq_mod, - RQ_NUMDR + 1, RQ_RDX, 31, RQ_AINC, RQ_RDX, RQ_WID, + RQ_NUMDR + 2, RQ_RDX, 31, RQ_AINC, RQ_RDX, RQ_WID, NULL, NULL, &rq_reset, &rq_boot, &rq_attach, &rq_detach }; @@ -595,49 +626,14 @@ t_stat rq_wr (int32 data, int32 PA, int32 access) switch ((PA >> 1) & 01) { /* decode PA<1> */ case 0: /* IP */ rq_reset (&rq_dev); /* init device */ + if (DBG_LOG (LOG_RQ)) fprintf (sim_log, ">>RQ: initialization started\n"); break; case 1: /* SA */ - switch (rq_csta) { /* controller state? */ - case CST_S1: /* need S1 reply */ - if (data & SA_S1H_VL) { /* valid? */ - if (data & SA_S1H_WR) { /* wrap? */ - rq_sa = data; /* echo data */ - rq_csta = CST_S1_WR; } /* endless loop */ - else { rq_s1dat = data; /* save data */ - rq_sa = SA_S2 | SA_S2C_PT | SA_S2C_EC (rq_s1dat); - rq_csta = CST_S2; /* now in step 2 */ - rq_init_int (); } /* intr if req */ - } - break; - case CST_S1_WR: /* wrap mode */ - rq_sa = data; /* echo data */ - break; - case CST_S2: /* need S2 reply */ - rq_comm = data & SA_S2H_CLO; /* get low addr */ - rq_prgi = data & SA_S2H_PI; /* get purge int */ - rq_sa = SA_S3 | SA_S3C_EC (rq_s1dat); - rq_csta = CST_S3; /* now in step 3 */ - rq_init_int (); /* intr if req */ - break; - case CST_S3: /* need S3 reply */ - rq_comm = ((data & SA_S3H_CHI) << 16) | rq_comm; - if (data & SA_S3H_PP) { /* purge/poll test? */ - rq_sa = 0; /* put 0 */ - rq_csta = CST_S3_PPA; } /* wait for 0 write */ - else rq_step4 (); /* send step 4 */ - break; - case CST_S3_PPA: /* need purge test */ - if (data) rq_fatal (PE_PPF); /* data not zero? */ - else rq_csta = CST_S3_PPB; /* wait for poll */ - break; - case CST_S4: /* need S4 reply */ - if (data & SA_S4H_GO) { /* go set? */ - rq_csta = CST_UP; /* we're up */ - rq_sa = 0; /* clear SA */ - sim_activate (&rq_unit[RQ_TIMER], tmr_poll * clk_tps); - if ((data & SA_S4H_LF) && rq_perr) rq_plf (rq_perr); - rq_perr = 0; } - break; } + rq_saw = data; + if (rq_csta < CST_S4) /* stages 1-3 */ + sim_activate (&rq_unit[RQ_QUEUE], rq_itime); + else if (rq_csta == CST_S4) /* stage 4 (fast) */ + sim_activate (&rq_unit[RQ_QUEUE], rq_itime4); break; } return SCPE_OK; } @@ -670,7 +666,8 @@ return OK; } /* Queue service - invoked when any of the queues (host queue, unit - queues, response queue) require servicing + queues, response queue) require servicing. Also invoked during + initialization to provide some delay to the next step. Process at most one item off the host queue If the host queue is empty, process at most one item off @@ -680,15 +677,68 @@ return OK; If all queues are idle, terminate thread */ - t_stat rq_quesvc (UNIT *uptr) { int32 i, cnid; int32 pkt = 0; +if (rq_csta < CST_UP) { /* still init? */ + switch (rq_csta) { /* controller state? */ + case CST_S1: /* need S1 reply */ + if (rq_saw & SA_S1H_VL) { /* valid? */ + if (rq_saw & SA_S1H_WR) { /* wrap? */ + rq_sa = rq_saw; /* echo data */ + rq_csta = CST_S1_WR; } /* endless loop */ + else { + rq_s1dat = rq_saw; /* save data */ + rq_sa = SA_S2 | SA_S2C_PT | SA_S2C_EC (rq_s1dat); + rq_csta = CST_S2; /* now in step 2 */ + rq_init_int (); } /* intr if req */ + } /* end if valid */ + break; + case CST_S1_WR: /* wrap mode */ + rq_sa = rq_saw; /* echo data */ + break; + case CST_S2: /* need S2 reply */ + rq_comm = rq_saw & SA_S2H_CLO; /* get low addr */ + rq_prgi = rq_saw & SA_S2H_PI; /* get purge int */ + rq_sa = SA_S3 | SA_S3C_EC (rq_s1dat); + rq_csta = CST_S3; /* now in step 3 */ + rq_init_int (); /* intr if req */ + break; + case CST_S3: /* need S3 reply */ + rq_comm = ((rq_saw & SA_S3H_CHI) << 16) | rq_comm; + if (rq_saw & SA_S3H_PP) { /* purge/poll test? */ + rq_sa = 0; /* put 0 */ + rq_csta = CST_S3_PPA; } /* wait for 0 write */ + else rq_step4 (); /* send step 4 */ + break; + case CST_S3_PPA: /* need purge test */ + if (rq_saw) rq_fatal (PE_PPF); /* data not zero? */ + else rq_csta = CST_S3_PPB; /* wait for poll */ + break; + case CST_S4: /* need S4 reply */ + if (rq_saw & SA_S4H_GO) { /* go set? */ + if (DBG_LOG (LOG_RQ)) fprintf (sim_log, + ">>RQ: initialization complete\n"); + rq_csta = CST_UP; /* we're up */ + rq_sa = 0; /* clear SA */ + sim_activate (&rq_unit[RQ_TIMER], tmr_poll * clk_tps); + if ((rq_saw & SA_S4H_LF) && rq_perr) rq_plf (rq_perr); + rq_perr = 0; } + break; } /* end switch */ + return SCPE_OK; } /* end if */ + if (rq_pip) { /* polling? */ if (!rq_getpkt (&pkt)) return SCPE_OK; /* get host pkt */ if (pkt) { /* got one? */ + if (DBG_LOG (LOG_RQ)) { + fprintf (sim_log, ">>RQ: cmd=%04X, mod=%04X, unit=%d, ", + rq_pkt[pkt].d[CMD_OPC], rq_pkt[pkt].d[CMD_MOD], rq_pkt[pkt].d[CMD_UN]); + fprintf (sim_log, "bc=%04X%04X, ma=%04X%04X, lbn=%04X%04X\n", + rq_pkt[pkt].d[RW_BCH], rq_pkt[pkt].d[RW_BCL], + rq_pkt[pkt].d[RW_BAH], rq_pkt[pkt].d[RW_BAL], + rq_pkt[pkt].d[RW_LBNH], rq_pkt[pkt].d[RW_LBNL]); } if (GETP (pkt, UQ_HCTC, TYP) != UQ_TYP_SEQ) /* seq packet? */ return rq_fatal (PE_PIE); /* no, term thread */ cnid = GETP (pkt, UQ_HCTC, CID); /* get conn ID */ @@ -703,15 +753,16 @@ if (rq_pip) { /* polling? */ } /* end if pip */ if (!rq_pip) { /* not polling? */ for (i = 0; i < RQ_NUMDR; i++) { /* chk unit q's */ - if (uptr -> cpkt || (uptr -> pktq == 0)) continue; - pkt = rq_deqh (&uptr -> pktq); /* get top of q */ + UNIT *nuptr = rq_dev.units + i; /* ptr to unit */ + if (nuptr -> cpkt || (nuptr -> pktq == 0)) continue; + pkt = rq_deqh (&nuptr -> pktq); /* get top of q */ if (!rq_mscp (pkt, FALSE)) return SCPE_OK; } /* process */ } /* end if !pip */ if (rq_rspq) { /* resp q? */ pkt = rq_deqh (&rq_rspq); /* get top of q */ if (!rq_putpkt (pkt, FALSE)) return SCPE_OK; /* send to hst */ } /* end if resp q */ -if (pkt) sim_activate (&rq_unit[RQ_QUEUE], rq_qtime); /* more to do? */ +if (pkt) sim_activate (&rq_unit[RQ_QUEUE], rq_qtime); /* more to do? */ return SCPE_OK; /* done */ } @@ -794,7 +845,8 @@ if (uptr = rq_getucb (lu)) { /* get unit */ (GETP32 (uptr -> cpkt, CMD_REFL) == ref)) { /* match ref? */ tpkt = uptr -> cpkt; /* save match */ uptr -> cpkt = 0; /* gonzo */ - sim_cancel (uptr); } /* cancel unit */ + sim_cancel (uptr); /* cancel unit */ + sim_activate (&rq_unit[RQ_QUEUE], rq_qtime); } else if (uptr -> pktq && /* head of q? */ (GETP32 (uptr -> pktq, CMD_REFL) == ref)) { /* match ref? */ tpkt = uptr -> pktq; /* save match */ @@ -827,7 +879,7 @@ if (uptr = rq_getucb (lu)) { /* unit exist? */ rq_enqt (&uptr -> pktq, pkt); /* do later */ return OK; } uptr -> flags = uptr -> flags & ~UNIT_ONL; /* not online */ - uptr -> uf = uptr -> uf & (UF_WPH | UF_RPL | UF_RMV); + uptr -> uf = 0; /* clr flags */ sts = ST_SUC; } /* success */ else sts = ST_OFL; /* offline */ rq_putr (pkt, cmd | OP_END, 0, sts, AVL_LNT, UQ_TYP_SEQ); @@ -923,7 +975,7 @@ return rq_putpkt (pkt, TRUE); t_bool rq_scc (int32 pkt, t_bool q) { -int32 sts, cmd, tmo; +int32 sts, cmd; if (rq_pkt[pkt].d[SCC_MSV]) { /* MSCP ver = 0? */ sts = ST_CMD | I_VRSN; /* no, lose */ @@ -932,8 +984,8 @@ else { sts = ST_SUC; /* success */ cmd = GETP (pkt, CMD_OPC, OPC); /* get opcode */ rq_cflgs = (rq_cflgs & CF_RPL) | /* hack ctrl flgs */ rq_pkt[pkt].d[SCC_CFL]; - if (tmo = rq_pkt[pkt].d[SCC_TMO]) /* valid timeout? */ - rq_htmo = tmo + 2; /* set new val */ + if (rq_htmo = rq_pkt[pkt].d[SCC_TMO]) /* set timeout */ + rq_htmo = rq_htmo + 2; /* if nz, round up */ rq_pkt[pkt].d[SCC_CFL] = rq_cflgs; /* return flags */ rq_pkt[pkt].d[SCC_TMO] = RQ_DCTMO; /* ctrl timeout */ rq_pkt[pkt].d[SCC_VER] = (RQ_HVER << SCC_VER_V_HVER) | @@ -995,9 +1047,9 @@ if (uptr = rq_getucb (lu)) { /* unit exist? */ sts = ST_OFL | SB_OFL_NV; /* no vol */ else if (uptr -> flags & UNIT_ONL) { /* online? */ uptr -> flags = uptr -> flags & ~UNIT_ONL; - uptr -> uf = uptr -> uf & (UF_WPH | UF_RPL | UF_RMV); + uptr -> uf = 0; /* clear flags */ sts = ST_AVL | SB_AVL_INU; } /* avail, in use */ - else if (uptr -> uf & UF_WPH) /* write prot? */ + else if (RQ_WPH (uptr)) /* write prot? */ sts = ST_WPR | SB_WPR_HW; /* can't fmt */ else sts = ST_SUC; /*** for now ***/ } @@ -1066,7 +1118,7 @@ if ((cmd == OP_WR) || (cmd == OP_ERS)) { /* write op? */ return (ST_CMD | I_LBN); /* lbn err */ if (uptr -> uf & UF_WPS) /* swre wlk? */ return (ST_WPR | SB_WPR_SW); - if (uptr -> uf & UF_WPH) /* hwre wlk? */ + if (RQ_WPH (uptr)) /* hwre wlk? */ return (ST_WPR | SB_WPR_HW); } return 0; /* success! */ } @@ -1093,17 +1145,22 @@ if (bc == 0) { /* no xfer? */ rq_rw_end (uptr, 0, ST_SUC); /* ok by me... */ return SCPE_OK; } +if ((cmd == OP_ERS) || (cmd == OP_WR)) { /* write op? */ + if (RQ_WPH (uptr)) { + rq_rw_end (uptr, 0, ST_WPR | SB_WPR_HW); + return SCPE_OK; } + if (uptr -> uf & UF_WPS) { + rq_rw_end (uptr, 0, ST_WPR | SB_WPR_SW); + return SCPE_OK; } } + if (cmd == OP_ERS) { /* erase? */ - if (uptr -> uf & (UF_WPH | UF_WPS)) rq_rw_end (uptr, 0, - ST_WPR | ((uptr -> uf & UF_WPH)? SB_WPR_HW: SB_WPR_SW)); wwc = ((tbc + (RQ_NUMBY - 1)) & ~(RQ_NUMBY - 1)) >> 1; for (i = 0; i < wwc; i++) rqxb[i] = 0; /* clr buf */ err = fseek (uptr -> fileref, da, SEEK_SET); /* set pos */ if (!err) fxwrite (rqxb, sizeof (int16), wwc, uptr -> fileref); err = ferror (uptr -> fileref); } /* end if erase */ + else if (cmd == OP_WR) { /* write? */ - if (uptr -> uf & (UF_WPH | UF_WPS)) rq_rw_end (uptr, 0, - ST_WPR | ((uptr -> uf & UF_WPH)? SB_WPR_HW: SB_WPR_SW)); t = Map_ReadW (ba, tbc, rqxb, QB); /* fetch buffer */ if (abc = tbc - t) { /* any xfer? */ wwc = ((abc + (RQ_NUMBY - 1)) & ~(RQ_NUMBY - 1)) >> 1; @@ -1117,6 +1174,7 @@ else if (cmd == OP_WR) { /* write? */ if (rq_hbe (uptr, ER_NXM)) /* post err log */ rq_rw_end (uptr, EF_LOG, ST_HST | SB_HST_NXM); return SCPE_OK; } } /* end else wr */ + else { err = fseek (uptr -> fileref, da, SEEK_SET); /* set pos */ if (!err) { i = fxread (rqxb, sizeof (int16), tbc >> 1, uptr -> fileref); @@ -1377,6 +1435,9 @@ uint32 desc, lnt, cr; t_addr addr; if (pkt == 0) return OK; /* any packet? */ +if (DBG_LOG (LOG_RQ)) fprintf (sim_log, + ">>RQ: rsp=%04X, sts=%04X\n", + rq_pkt[pkt].d[RSP_OPF], rq_pkt[pkt].d[RSP_STS]); if (!rq_getdesc (&rq_rq, &desc)) return ERR; /* get rsp desc */ if ((desc & UQ_DESC_OWN) == 0) { /* not valid? */ if (qt) rq_enqt (&rq_rspq, pkt); /* normal? q tail */ @@ -1456,8 +1517,7 @@ return uptr; void rq_setf_unit (int32 pkt, UNIT *uptr) { -uptr -> uf = (uptr -> uf & (UF_WPH | UF_RPL | UF_RMV)) | - (rq_pkt[pkt].d[ONL_UFL] & UF_MSK); /* settable flags */ +uptr -> uf = rq_pkt[pkt].d[ONL_UFL] & UF_MSK; /* settable flags */ if ((rq_pkt[pkt].d[CMD_MOD] & MD_SWP) && /* swre wrp enb? */ (rq_pkt[pkt].d[ONL_UFL] & UF_WPS)) /* swre wrp on? */ uptr -> uf = uptr -> uf | UF_WPS; /* simon says... */ @@ -1471,7 +1531,7 @@ void rq_putr_unit (int32 pkt, UNIT *uptr, uint32 lu, t_bool all) uint32 dtyp = GET_DTYPE (uptr -> flags); /* get drive type */ rq_pkt[pkt].d[ONL_MLUN] = lu; /* unit */ -rq_pkt[pkt].d[ONL_UFL] = uptr -> uf; /* flags */ +rq_pkt[pkt].d[ONL_UFL] = uptr -> uf | UF_RPL | RQ_WPH (uptr) | RQ_RMV (uptr); rq_pkt[pkt].d[ONL_RSVL] = rq_pkt[pkt].d[ONL_RSVH] = 0; /* reserved */ rq_pkt[pkt].d[ONL_UIDA] = lu; /* UID low */ rq_pkt[pkt].d[ONL_UIDB] = 0; @@ -1530,6 +1590,7 @@ return (VEC_Q + ((rq_s1dat & SA_S1H_VEC) << 2)); /* prog vector */ t_bool rq_fatal (uint32 err) { +if (DBG_LOG (LOG_RQ)) fprintf (sim_log, ">>RQ: fatal err=%X\n", err); rq_reset (&rq_dev); /* reset device */ rq_sa = SA_ER | err; /* SA = dead code */ rq_csta = CST_DEAD; /* state = dead */ @@ -1544,9 +1605,6 @@ t_stat rq_set_wlk (UNIT *uptr, int32 val, char *cptr, void *desc) uint32 dtyp = GET_DTYPE (uptr -> flags); /* get drive type */ if (drv_tab[dtyp].flgs & RQDF_RO) return SCPE_NOFNC; /* not on read only */ -if (val || (uptr -> flags & UNIT_RO)) - uptr -> uf = uptr -> uf | UF_WPH; /* copy to uf */ -else uptr -> uf = uptr -> uf & ~UF_WPH; return SCPE_OK; } @@ -1557,7 +1615,7 @@ t_stat rq_show_wlk (FILE *st, UNIT *uptr, int32 val, void *desc) uint32 dtyp = GET_DTYPE (uptr -> flags); /* get drive type */ if (drv_tab[dtyp].flgs & RQDF_RO) fprintf (st, "read only"); -else if (uptr -> uf & UF_WPH) fprintf (st, "write locked"); +else if (uptr -> flags & UNIT_WPRT) fprintf (st, "write locked"); else fprintf (st, "write enabled"); return SCPE_OK; } @@ -1566,12 +1624,10 @@ return SCPE_OK; t_stat rq_set_size (UNIT *uptr, int32 val, char *cptr, void *desc) { +uint32 dtyp = GET_DTYPE (val); + if (uptr -> flags & UNIT_ATT) return SCPE_ALATT; uptr -> capac = drv_tab[GET_DTYPE (val)].lbn * RQ_NUMBY; -if (drv_tab[GET_DTYPE (val)].flgs & RQDF_RMV) - uptr -> uf = uptr -> uf | UF_RMV; -else uptr -> uf = uptr -> uf & ~UF_RMV; -if (val == RRD40_DTYPE) uptr -> uf = uptr -> uf | UF_WPH; return SCPE_OK; } @@ -1586,8 +1642,6 @@ uptr -> capac = drv_tab[dtyp].lbn * RQ_NUMBY; r = attach_unit (uptr, cptr); if (r != SCPE_OK) return r; if (rq_csta == CST_UP) uptr -> flags = uptr -> flags | UNIT_ATP; -if ((drv_tab[dtyp].flgs & RQDF_RO) || (uptr -> flags & UNIT_RO)) - uptr -> uf = uptr -> uf | UF_WPH; return SCPE_OK; } @@ -1600,7 +1654,7 @@ t_stat r; r = detach_unit (uptr); /* detach unit */ if (r != SCPE_OK) return r; uptr -> flags = uptr -> flags & ~(UNIT_ONL | UNIT_ATP); /* clr onl, atn pend */ -uptr -> uf = uptr -> uf & (UF_WPH | UF_RPL | UF_RMV); /* clr unit flgs */ +uptr -> uf = 0; /* clr unit flgs */ return SCPE_OK; } @@ -1630,11 +1684,10 @@ rq_pip = 0; /* not polling */ CLR_INT (RQ); /* clr intr req */ for (i = 0; i < RQ_NUMDR; i++) { /* init units */ UNIT *uptr = rq_dev.units + i; + uint32 dtyp = GET_DTYPE (uptr -> flags); /* get drive type */ sim_cancel (uptr); /* clr activity */ uptr -> flags = uptr -> flags & ~UNIT_ONL; /* not online */ - if (drv_tab[GET_DTYPE (uptr -> flags)].flgs & RQDF_RMV) - uptr -> uf = UF_RPL | UF_RMV; /* init flags */ - else uptr -> uf = UF_RPL; + uptr -> uf = 0; /* ctlr unit flags */ uptr -> cpkt = uptr -> pktq = 0; } /* clr pkt q's */ sim_cancel (&rq_unit[RQ_TIMER]); /* clr timer thrd */ sim_cancel (&rq_unit[RQ_QUEUE]); /* clr queue thrd */ @@ -1647,18 +1700,21 @@ return SCPE_OK; #if defined (VM_PDP11) -#define BOOT_START 016000 /* start */ -#define BOOT_UNIT 016006 /* unit number */ +#define BOOT_START 016000 /* start */ +#define BOOT_ENTRY 016002 /* entry */ +#define BOOT_UNIT 016010 /* unit number */ #define BOOT_LEN (sizeof (boot_rom) / sizeof (int16)) static const uint16 boot_rom[] = { + 0042125, /* st: "UD" */ + /* Four step init process */ - 0012706, 0016000, /* st: mov #st,sp */ + 0012706, 0016000, /* mov #st,sp */ 0012700, 0000000, /* mov #unit,r0 */ 0012701, 0172150, /* mov #172150, r1 ; ip addr */ - 0012704, 0016160, /* mov #it, r4 */ + 0012704, 0016162, /* mov #it, r4 */ 0012705, 0004000, /* mov #4000,r5 ; s1 mask */ 0010102, /* mov r1,r2 */ 0005022, /* clr (r2)+ ; init */ @@ -1697,10 +1753,10 @@ static const uint16 boot_rom[] = { /* Boot block read in, jump to 0 */ - 0005002, /* done: clr r2 */ + 0005011, /* done: clr (r1) ; for M+ */ 0005003, /* clr r3 */ - 0012705, 0052504, /* mov #"DU,r5 */ - 0010704, /* mov pc,r4 */ + 0012704, BOOT_START+020, /* mov #st+020,r4 */ + 0005005, /* clr r5 */ 0005007, /* clr pc */ /* Data */ @@ -1723,7 +1779,7 @@ extern uint16 *M; for (i = 0; i < BOOT_LEN; i++) M[(BOOT_START >> 1) + i] = boot_rom[i]; M[BOOT_UNIT >> 1] = unitno & 3; -saved_PC = BOOT_START; +saved_PC = BOOT_ENTRY; return SCPE_OK; } @@ -1743,22 +1799,21 @@ uint32 i, desc; uint16 d[2]; #if defined (VM_PDP11) -fprintf (st, "ring, base = %o, index = %d, length = %d", +fprintf (st, "ring, base = %o, index = %d, length = %d\n", rp -> ba, rp -> idx >> 2, rp -> lnt >> 2); #else -fprintf (st, "ring, base = %x, index = %d, length = %d", +fprintf (st, "ring, base = %x, index = %d, length = %d\n", rp -> ba, rp -> idx >> 2, rp -> lnt >> 2); #endif -for (i = 0; i < rp -> lnt >> 2; i = i++) { - if ((i % RQ_SH_DPL) == 0) fprintf (st, "\n"); +for (i = 0; i < (rp -> lnt >> 2); i++) { if (Map_ReadW (rp -> ba + (i << 2), 4, d, QB)) { - fprintf (st, " %3d: non-existent memory", i); + fprintf (st, " %3d: non-existent memory\n", i); break; } desc = ((uint32) d[0]) | (((uint32) d[1]) << 16); #if defined (VM_PDP11) - fprintf (st, " %3d: %011o", i, desc); + fprintf (st, " %3d: %011o\n", i, desc); #else - fprintf (st, " %3d: %08x", i, desc); + fprintf (st, " %3d: %08x\n", i, desc); #endif } return; @@ -1771,16 +1826,17 @@ uint32 cr = GETP (pkt, UQ_HCTC, CR); uint32 typ = GETP (pkt, UQ_HCTC, TYP); uint32 cid = GETP (pkt, UQ_HCTC, CID); -fprintf (st, "packet %d, credits = %d, type = %d, cid = %d", +fprintf (st, "packet %d, credits = %d, type = %d, cid = %d\n", pkt, cr, typ, cid); for (i = 0; i < RQ_SH_MAX; i = i + RQ_SH_PPL) { - fprintf (st, "\n %2d:", i); - for (j = i; (j < (i + RQ_SH_PPL)); j++) + fprintf (st, " %2d:", i); + for (j = i; j < (i + RQ_SH_PPL); j++) #if defined (VM_PDP11) fprintf (st, " %06o", rq_pkt[pkt].d[j]); #else fprintf (st, " %04x", rq_pkt[pkt].d[j]); #endif + fprintf (st, "\n"); } return; } @@ -1790,21 +1846,21 @@ t_stat rq_show_unitq (FILE *st, UNIT *uptr, int32 val, void *desc) int32 pkt, u = uptr - rq_dev.units; if (rq_csta != CST_UP) { - fprintf (st, "Controller is not initialized"); + fprintf (st, "Controller is not initialized\n"); return SCPE_OK; } if ((uptr -> flags & UNIT_ONL) == 0) { if (uptr -> flags & UNIT_ATT) - fprintf (st, "Unit %d is available", u); - else fprintf (st, "Unit %d is offline", u); + fprintf (st, "Unit %d is available\n", u); + else fprintf (st, "Unit %d is offline\n", u); return SCPE_OK; } if (uptr -> cpkt) { fprintf (st, "Unit %d current ", u); rq_show_pkt (st, uptr -> cpkt); if (pkt = uptr -> pktq) { - do { fprintf (st, "\nUnit %d queued ", u); + do { fprintf (st, "Unit %d queued ", u); rq_show_pkt (st, pkt); } while (pkt = rq_pkt[pkt].link); } } -else fprintf (st, "Unit %d queues are empty", u); +else fprintf (st, "Unit %d queues are empty\n", u); return SCPE_OK; } @@ -1813,37 +1869,35 @@ t_stat rq_show_ctrl (FILE *st, UNIT *uptr, int32 val, void *desc) int32 i, pkt; if (rq_csta != CST_UP) { - fprintf (st, "Controller is not initialized"); + fprintf (st, "Controller is not initialized\n"); return SCPE_OK; } if (val & RQ_SH_RI) { - if (rq_pip) fprintf (st, "Polling in progress\n"); + if (rq_pip) fprintf (st, "Polling in progress, host timer = %d\n", rq_hat); + else fprintf (st, "Host timer = %d\n", rq_hat); fprintf (st, "Command "); rq_show_ring (st, &rq_cq); - fprintf (st, "\nResponse "); + fprintf (st, "Response "); rq_show_ring (st, &rq_rq); } if (val & RQ_SH_FR) { - if (val & RQ_SH_RI) fprintf (st, "\n"); if (pkt = rq_freq) { for (i = 0; pkt != 0; i++, pkt = rq_pkt[pkt].link) { if (i == 0) fprintf (st, "Free queue = %d", pkt); else if ((i % 16) == 0) fprintf (st, ",\n %d", pkt); - else fprintf (st, ", %d", pkt); } } - else fprintf (st, "Free queue is empty"); + else fprintf (st, ", %d", pkt); } + fprintf (st, "\n"); } + else fprintf (st, "Free queue is empty\n"); } if (val & RQ_SH_RS) { - if (val & (RQ_SH_RI | RQ_SH_FR)) fprintf (st, "\n"); if (pkt = rq_rspq) { do { fprintf (st, "Response "); rq_show_pkt (st, pkt); } while (pkt = rq_pkt[pkt].link); } - else fprintf (st, "Response queue is empty"); + else fprintf (st, "Response queue is empty\n"); } if (val & RQ_SH_UN) { - for (i = 0; i < RQ_NUMDR; i++) { - if ((val & (RQ_SH_RI | RQ_SH_FR | RQ_SH_RS)) || i) - fprintf (st, "\n"); - rq_show_unitq (st, &rq_unit[i], 0, NULL); } + for (i = 0; i < RQ_NUMDR; i++) + rq_show_unitq (st, &rq_unit[i], 0, NULL); } return SCPE_OK; } diff --git a/PDP11/pdp11_rx.c b/PDP11/pdp11_rx.c index 16b10a0e..6dfae164 100644 --- a/PDP11/pdp11_rx.c +++ b/PDP11/pdp11_rx.c @@ -1,6 +1,6 @@ /* pdp11_rx.c: RX11/RX01 floppy disk simulator - Copyright (c) 1993-2001, Robert M Supnik + Copyright (c) 1993-2002, Robert M Supnik Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), @@ -25,6 +25,8 @@ rx RX11/RX01 floppy disk + 26-Jan-02 RMS Revised bootstrap to conform to M9312 + 06-Jan-02 RMS Revised enable/disable support 30-Nov-01 RMS Added read only unit, extended SET/SHOW support 24-Nov-01 RMS Converted FLG to array 07-Sep-01 RMS Revised device disable and interrupt mechanisms @@ -107,6 +109,9 @@ int32 rx_xwait = 1; /* tr set time */ unsigned int8 rx_buf[RX_NUMBY] = { 0 }; /* sector buffer */ int32 bptr = 0; /* buffer pointer */ int32 rx_enb = 1; /* device enable */ + +t_stat rx_rd (int32 *data, int32 PA, int32 access); +t_stat rx_wr (int32 data, int32 PA, int32 access); t_stat rx_svc (UNIT *uptr); t_stat rx_reset (DEVICE *dptr); t_stat rx_boot (int32 unitno); @@ -119,6 +124,8 @@ t_stat rx_boot (int32 unitno); rx_mod RX modifier list */ +DIB rx_dib = { 1, IOBA_RX, IOLN_RX, &rx_rd, &rx_wr }; + UNIT rx_unit[] = { { UDATA (&rx_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_BUFABLE+UNIT_MUSTBUF, RX_SIZE) }, @@ -145,12 +152,19 @@ REG rx_reg[] = { { URDATA (FLG, rx_unit[0].flags, 2, 1, UNIT_V_WLK, RX_NUMDR, REG_HRO) }, { FLDATA (STOP_IOE, rx_stopioe, 0) }, { BRDATA (SBUF, rx_buf, 8, 8, RX_NUMBY) }, - { FLDATA (*DEVENB, rx_enb, 0), REG_HRO }, + { ORDATA (DEVADDR, rx_dib.ba, 32), REG_HRO }, + { FLDATA (*DEVENB, rx_dib.enb, 0), REG_HRO }, { NULL } }; MTAB rx_mod[] = { - { UNIT_WLK, 0, "write enabled", "ENABLED", NULL }, + { UNIT_WLK, 0, "write enabled", "WRITEENABLED", NULL }, { UNIT_WLK, UNIT_WLK, "write locked", "LOCKED", NULL }, + { MTAB_XTD|MTAB_VDV, 004, "ADDRESS", "ADDRESS", + &set_addr, &show_addr, &rx_dib }, + { MTAB_XTD|MTAB_VDV, 1, NULL, "ENABLED", + &set_enbdis, NULL, &rx_dib }, + { MTAB_XTD|MTAB_VDV, 0, NULL, "DISABLED", + &set_enbdis, NULL, &rx_dib }, { 0 } }; DEVICE rx_dev = { @@ -383,11 +397,13 @@ return SCPE_OK; /* Device bootstrap */ -#define BOOT_START 02000 -#define BOOT_UNIT 02006 +#define BOOT_START 02000 /* start */ +#define BOOT_ENTRY 02002 /* entry */ +#define BOOT_UNIT 02010 /* unit number */ #define BOOT_LEN (sizeof (boot_rom) / sizeof (int32)) static const int32 boot_rom[] = { + 042130, /* "XD" */ 0012706, 0002000, /* MOV #2000, SP */ 0012700, 0000000, /* MOV #unit, R0 ; unit number */ 0010003, /* MOV R0, R3 */ @@ -417,8 +433,8 @@ static const int32 boot_rom[] = { 0000772, /* BR .-012 */ 0005002, /* CLR R2 */ 0005003, /* CLR R3 */ - 0005004, /* CLR R4 */ - 0012705, 0054104, /* MOV #"DX, R5 */ + 0012704, BOOT_START+020, /* MOV #START+20, R4 */ + 0005005, /* CLR R5 */ 0005007 /* CLR R7 */ }; @@ -430,6 +446,6 @@ extern uint16 *M; for (i = 0; i < BOOT_LEN; i++) M[(BOOT_START >> 1) + i] = boot_rom[i]; M[BOOT_UNIT >> 1] = unitno & RX_M_NUMDR; -saved_PC = BOOT_START; +saved_PC = BOOT_ENTRY; return SCPE_OK; } diff --git a/PDP11/pdp11_stddev.c b/PDP11/pdp11_stddev.c index 0ef8a245..addb18c0 100644 --- a/PDP11/pdp11_stddev.c +++ b/PDP11/pdp11_stddev.c @@ -1,6 +1,6 @@ /* pdp11_stddev.c: PDP-11 standard I/O devices simulator - Copyright (c) 1993-2001, Robert M Supnik + Copyright (c) 1993-2002, Robert M Supnik Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), @@ -27,6 +27,10 @@ tti,tto DL11 terminal input/output clk KW11L line frequency clock + 30-May-02 RMS Widened POS to 32b + 26-Jan-02 RMS Revised for multiple timers + 09-Jan-02 RMS Fixed bugs in KW11L (found by John Dundas) + 06-Jan-02 RMS Split I/O address routines, revised enable/disable support 29-Nov-01 RMS Added read only unit support 09-Nov-01 RMS Added RQDX3 support 07-Oct-01 RMS Upgraded clock to full KW11L for RSTS/E autoconfigure @@ -49,7 +53,7 @@ #define TTOCSR_IMP (CSR_DONE + CSR_IE) /* terminal output */ #define TTOCSR_RW (CSR_IE) #define CLKCSR_IMP (CSR_DONE + CSR_IE) /* real-time clock */ -#define CLKCSR_RW (CSR_DONE + CSR_IE) +#define CLKCSR_RW (CSR_IE) #define CLK_DELAY 8000 extern int32 int_req[IPL_HLVL]; @@ -64,10 +68,16 @@ int32 clk_tps = 60; /* ticks/second */ int32 tmxr_poll = CLK_DELAY; /* term mux poll */ int32 tmr_poll = CLK_DELAY; /* timer poll */ +t_stat pt_rd (int32 *data, int32 PA, int32 access); +t_stat pt_wr (int32 data, int32 PA, int32 access); t_stat ptr_svc (UNIT *uptr); t_stat ptp_svc (UNIT *uptr); +t_stat tt_rd (int32 *data, int32 PA, int32 access); +t_stat tt_wr (int32 data, int32 PA, int32 access); t_stat tti_svc (UNIT *uptr); t_stat tto_svc (UNIT *uptr); +t_stat clk_rd (int32 *data, int32 PA, int32 access); +t_stat clk_wr (int32 data, int32 PA, int32 access); t_stat clk_svc (UNIT *uptr); t_stat ptr_reset (DEVICE *dptr); t_stat ptp_reset (DEVICE *dptr); @@ -86,6 +96,8 @@ t_stat ptp_detach (UNIT *uptr); ptr_reg PTR register list */ +DIB pt_dib = { 1, IOBA_PT, IOLN_PT, &pt_rd, &pt_wr }; + UNIT ptr_unit = { UDATA (&ptr_svc, UNIT_SEQ+UNIT_ATTABLE+UNIT_ROABLE, 0), SERIAL_IN_WAIT }; @@ -98,13 +110,23 @@ REG ptr_reg[] = { { FLDATA (BUSY, ptr_csr, CSR_V_BUSY) }, { FLDATA (DONE, ptr_csr, CSR_V_DONE) }, { FLDATA (IE, ptr_csr, CSR_V_IE) }, - { DRDATA (POS, ptr_unit.pos, 31), PV_LEFT }, + { DRDATA (POS, ptr_unit.pos, 32), PV_LEFT }, { DRDATA (TIME, ptr_unit.wait, 24), PV_LEFT }, { FLDATA (STOP_IOE, ptr_stopioe, 0) }, + { FLDATA (*DEVENB, pt_dib.enb, 0), REG_HRO }, { NULL } }; +MTAB ptr_mod[] = { + { MTAB_XTD|MTAB_VDV, 0, "ADDRESS", NULL, + NULL, &show_addr, &pt_dib }, + { MTAB_XTD|MTAB_VDV, 1, NULL, "ENABLED", + &set_enbdis, NULL, &pt_dib }, + { MTAB_XTD|MTAB_VDV, 0, NULL, "DISABLED", + &set_enbdis, NULL, &pt_dib }, + { 0 } }; + DEVICE ptr_dev = { - "PTR", &ptr_unit, ptr_reg, NULL, + "PTR", &ptr_unit, ptr_reg, ptr_mod, 1, 10, 31, 1, 8, 8, NULL, NULL, &ptr_reset, NULL, &ptr_attach, &ptr_detach }; @@ -126,13 +148,23 @@ REG ptp_reg[] = { { FLDATA (ERR, ptp_csr, CSR_V_ERR) }, { FLDATA (DONE, ptp_csr, CSR_V_DONE) }, { FLDATA (IE, ptp_csr, CSR_V_IE) }, - { DRDATA (POS, ptp_unit.pos, 31), PV_LEFT }, + { DRDATA (POS, ptp_unit.pos, 32), PV_LEFT }, { DRDATA (TIME, ptp_unit.wait, 24), PV_LEFT }, { FLDATA (STOP_IOE, ptp_stopioe, 0) }, + { FLDATA (*DEVENB, pt_dib.enb, 0), REG_HRO }, { NULL } }; +MTAB ptp_mod[] = { + { MTAB_XTD|MTAB_VDV, 0, "ADDRESS", NULL, + NULL, &show_addr, &pt_dib }, + { MTAB_XTD|MTAB_VDV, 1, NULL, "ENABLED", + &set_enbdis, NULL, &pt_dib }, + { MTAB_XTD|MTAB_VDV, 0, NULL, "DISABLED", + &set_enbdis, NULL, &pt_dib }, + { 0 } }; + DEVICE ptp_dev = { - "PTP", &ptp_unit, ptp_reg, NULL, + "PTP", &ptp_unit, ptp_reg, ptp_mod, 1, 10, 31, 1, 8, 8, NULL, NULL, &ptp_reset, NULL, &ptp_attach, &ptp_detach }; @@ -144,6 +176,8 @@ DEVICE ptp_dev = { tti_reg TTI register list */ +DIB tt_dib = { 1, IOBA_TT, IOLN_TT, &tt_rd, &tt_wr }; + UNIT tti_unit = { UDATA (&tti_svc, 0, 0), KBD_POLL_WAIT }; REG tti_reg[] = { @@ -153,12 +187,17 @@ REG tti_reg[] = { { FLDATA (ERR, tti_csr, CSR_V_ERR) }, { FLDATA (DONE, tti_csr, CSR_V_DONE) }, { FLDATA (IE, tti_csr, CSR_V_IE) }, - { DRDATA (POS, tti_unit.pos, 31), PV_LEFT }, + { DRDATA (POS, tti_unit.pos, 32), PV_LEFT }, { DRDATA (TIME, tti_unit.wait, 24), REG_NZ + PV_LEFT }, { NULL } }; +MTAB tti_mod[] = { + { MTAB_XTD|MTAB_VDV, 0, "ADDRESS", NULL, + NULL, &show_addr, &tt_dib }, + { 0 } }; + DEVICE tti_dev = { - "TTI", &tti_unit, tti_reg, NULL, + "TTI", &tti_unit, tti_reg, tti_mod, 1, 10, 31, 1, 8, 8, NULL, NULL, &tti_reset, NULL, NULL, NULL }; @@ -179,12 +218,17 @@ REG tto_reg[] = { { FLDATA (ERR, tto_csr, CSR_V_ERR) }, { FLDATA (DONE, tto_csr, CSR_V_DONE) }, { FLDATA (IE, tto_csr, CSR_V_IE) }, - { DRDATA (POS, tto_unit.pos, 31), PV_LEFT }, + { DRDATA (POS, tto_unit.pos, 32), PV_LEFT }, { DRDATA (TIME, tto_unit.wait, 24), PV_LEFT }, { NULL } }; +MTAB tto_mod[] = { + { MTAB_XTD|MTAB_VDV, 0, "ADDRESS", NULL, + NULL, &show_addr, &tt_dib }, + { 0 } }; + DEVICE tto_dev = { - "TTO", &tto_unit, tto_reg, NULL, + "TTO", &tto_unit, tto_reg, tto_mod, 1, 10, 31, 1, 8, 8, NULL, NULL, &tto_reset, NULL, NULL, NULL }; @@ -196,6 +240,8 @@ DEVICE tto_dev = { clk_reg CLK register list */ +DIB clk_dib = { 1, IOBA_CLK, IOLN_CLK, &clk_rd, &clk_wr }; + UNIT clk_unit = { UDATA (&clk_svc, 0, 0), 8000 }; REG clk_reg[] = { @@ -207,77 +253,43 @@ REG clk_reg[] = { { DRDATA (TPS, clk_tps, 8), REG_NZ + PV_LEFT }, { NULL } }; +MTAB clk_mod[] = { + { MTAB_XTD|MTAB_VDV, 0, "ADDRESS", NULL, + NULL, &show_addr, &clk_dib }, + { 0 } }; + DEVICE clk_dev = { - "CLK", &clk_unit, clk_reg, NULL, + "CLK", &clk_unit, clk_reg, clk_mod, 1, 0, 0, 0, 0, 0, NULL, NULL, &clk_reset, NULL, NULL, NULL }; -/* Standard I/O dispatch routine, I/O addresses 17777546-17777567 +/* Paper tape I/O address routines */ - 17777546 clock CSR - 17777550 ptr CSR - 17777552 ptr buffer - 17777554 ptp CSR - 17777556 ptp buffer - 17777560 tti CSR - 17777562 tti buffer - 17777564 tto CSR - 17777566 tto buffer - - Note: Word access routines filter out odd addresses. Thus, - an odd address implies an (odd) byte access. -*/ - -t_stat std_rd (int32 *data, int32 PA, int32 access) +t_stat pt_rd (int32 *data, int32 PA, int32 access) { -switch ((PA >> 1) & 017) { /* decode PA<4:1> */ -case 03: /* clk csr */ - *data = clk_csr & CLKCSR_IMP; - return SCPE_OK; -case 04: /* ptr csr */ +switch ((PA >> 1) & 03) { /* decode PA<2:1> */ +case 00: /* ptr csr */ *data = ptr_csr & PTRCSR_IMP; return SCPE_OK; -case 05: /* ptr buf */ +case 01: /* ptr buf */ ptr_csr = ptr_csr & ~CSR_DONE; CLR_INT (PTR); *data = ptr_unit.buf & 0377; return SCPE_OK; -case 06: /* ptp csr */ +case 02: /* ptp csr */ *data = ptp_csr & PTPCSR_IMP; return SCPE_OK; -case 07: /* ptp buf */ +case 03: /* ptp buf */ *data = ptp_unit.buf; - return SCPE_OK; -case 010: /* tti csr */ - *data = tti_csr & TTICSR_IMP; - return SCPE_OK; -case 011: /* tti buf */ - tti_csr = tti_csr & ~CSR_DONE; - CLR_INT (TTI); - *data = tti_unit.buf & 0377; - return SCPE_OK; -case 012: /* tto csr */ - *data = tto_csr & TTOCSR_IMP; - return SCPE_OK; -case 013: /* tto buf */ - *data = tto_unit.buf; return SCPE_OK; } /* end switch PA */ return SCPE_NXM; } - -t_stat std_wr (int32 data, int32 PA, int32 access) + +t_stat pt_wr (int32 data, int32 PA, int32 access) { -switch ((PA >> 1) & 017) { /* decode PA<4:1> */ -case 03: /* clk csr */ - if (PA & 1) return SCPE_OK; - if (((data & CSR_IE) == 0) || /* clr IE, DONE? */ - ((data & CSR_DONE) == 0)) CLR_INT (CLK); /* clr intr */ - else if (((clk_csr & CSR_IE) == 0) || /* setting both */ - ((clk_csr & CSR_DONE) == 0)) SET_INT (CLK); /* if prv clr, intr */ - clk_csr = (clk_csr & ~CLKCSR_RW) | (data & CLKCSR_RW); - return SCPE_OK; -case 04: /* ptr csr */ +switch ((PA >> 1) & 03) { /* decode PA<2:1> */ +case 00: /* ptr csr */ if (PA & 1) return SCPE_OK; if ((data & CSR_IE) == 0) CLR_INT (PTR); else if (((ptr_csr & CSR_IE) == 0) && (ptr_csr & (CSR_ERR | CSR_DONE))) @@ -290,55 +302,27 @@ case 04: /* ptr csr */ else sim_activate (&ptr_unit, 0); } /* error if not */ ptr_csr = (ptr_csr & ~PTRCSR_RW) | (data & PTRCSR_RW); return SCPE_OK; -case 05: /* ptr buf */ +case 01: /* ptr buf */ return SCPE_OK; -case 06: /* ptp csr */ +case 02: /* ptp csr */ if (PA & 1) return SCPE_OK; if ((data & CSR_IE) == 0) CLR_INT (PTP); else if (((ptp_csr & CSR_IE) == 0) && (ptp_csr & (CSR_ERR | CSR_DONE))) SET_INT (PTP); ptp_csr = (ptp_csr & ~PTPCSR_RW) | (data & PTPCSR_RW); return SCPE_OK; -case 07: /* ptp buf */ +case 03: /* ptp buf */ if ((PA & 1) == 0) ptp_unit.buf = data & 0377; ptp_csr = ptp_csr & ~CSR_DONE; CLR_INT (PTP); if (ptp_unit.flags & UNIT_ATT) /* file to write? */ sim_activate (&ptp_unit, ptp_unit.wait); else sim_activate (&ptp_unit, 0); /* error if not */ - return SCPE_OK; -case 010: /* tti csr */ - if (PA & 1) return SCPE_OK; - if ((data & CSR_IE) == 0) CLR_INT (TTI); - else if ((tti_csr & (CSR_DONE + CSR_IE)) == CSR_DONE) - SET_INT (TTI); - tti_csr = (tti_csr & ~TTICSR_RW) | (data & TTICSR_RW); - return SCPE_OK; -case 011: /* tti buf */ - return SCPE_OK; -case 012: /* tto csr */ - if (PA & 1) return SCPE_OK; - if ((data & CSR_IE) == 0) CLR_INT (TTO); - else if ((tto_csr & (CSR_DONE + CSR_IE)) == CSR_DONE) - SET_INT (TTO); - tto_csr = (tto_csr & ~TTOCSR_RW) | (data & TTOCSR_RW); - return SCPE_OK; -case 013: /* tto buf */ - if ((PA & 1) == 0) tto_unit.buf = data & 0377; - tto_csr = tto_csr & ~CSR_DONE; - CLR_INT (TTO); - sim_activate (&tto_unit, tto_unit.wait); return SCPE_OK; } /* end switch PA */ return SCPE_NXM; } -/* Paper tape reader routines - - ptr_svc process event (character ready) - ptr_reset process reset - ptr_attach process attach - ptr_detach process detach -*/ +/* Paper tape reader routines */ t_stat ptr_svc (UNIT *uptr) { @@ -387,13 +371,7 @@ ptr_csr = ptr_csr | CSR_ERR; return detach_unit (uptr); } -/* Paper tape punch routines - - ptp_svc process event (character punched) - ptp_reset process reset - ptp_attach process attach - ptp_detach process detach -*/ +/* Paper tape punch routines */ t_stat ptp_svc (UNIT *uptr) { @@ -436,6 +414,56 @@ ptp_csr = ptp_csr | CSR_ERR; return detach_unit (uptr); } +/* Terminal I/O address routines */ + +t_stat tt_rd (int32 *data, int32 PA, int32 access) +{ +switch ((PA >> 1) & 03) { /* decode PA<2:1> */ +case 00: /* tti csr */ + *data = tti_csr & TTICSR_IMP; + return SCPE_OK; +case 01: /* tti buf */ + tti_csr = tti_csr & ~CSR_DONE; + CLR_INT (TTI); + *data = tti_unit.buf & 0377; + return SCPE_OK; +case 02: /* tto csr */ + *data = tto_csr & TTOCSR_IMP; + return SCPE_OK; +case 03: /* tto buf */ + *data = tto_unit.buf; + return SCPE_OK; } /* end switch PA */ +return SCPE_NXM; +} + +t_stat tt_wr (int32 data, int32 PA, int32 access) +{ +switch ((PA >> 1) & 03) { /* decode PA<2:1> */ +case 00: /* tti csr */ + if (PA & 1) return SCPE_OK; + if ((data & CSR_IE) == 0) CLR_INT (TTI); + else if ((tti_csr & (CSR_DONE + CSR_IE)) == CSR_DONE) + SET_INT (TTI); + tti_csr = (tti_csr & ~TTICSR_RW) | (data & TTICSR_RW); + return SCPE_OK; +case 01: /* tti buf */ + return SCPE_OK; +case 02: /* tto csr */ + if (PA & 1) return SCPE_OK; + if ((data & CSR_IE) == 0) CLR_INT (TTO); + else if ((tto_csr & (CSR_DONE + CSR_IE)) == CSR_DONE) + SET_INT (TTO); + tto_csr = (tto_csr & ~TTOCSR_RW) | (data & TTOCSR_RW); + return SCPE_OK; +case 03: /* tto buf */ + if ((PA & 1) == 0) tto_unit.buf = data & 0377; + tto_csr = tto_csr & ~CSR_DONE; + CLR_INT (TTO); + sim_activate (&tto_unit, tto_unit.wait); + return SCPE_OK; } /* end switch PA */ +return SCPE_NXM; +} + /* Terminal input routines tti_svc process event (character ready) @@ -490,11 +518,25 @@ sim_cancel (&tto_unit); /* deactivate unit */ return SCPE_OK; } -/* Clock routines +/* Clock I/O address routines */ - clk_svc process event (clock tick) - clk_reset process reset -*/ +t_stat clk_rd (int32 *data, int32 PA, int32 access) +{ +*data = clk_csr & CLKCSR_IMP; +return SCPE_OK; +} + +t_stat clk_wr (int32 data, int32 PA, int32 access) +{ +if (PA & 1) return SCPE_OK; +clk_csr = (clk_csr & ~CLKCSR_RW) | (data & CLKCSR_RW); +if ((data & CSR_DONE) == 0) clk_csr = clk_csr & ~CSR_DONE; +if (((clk_csr & CSR_IE) == 0) || /* unless IE+DONE */ + ((clk_csr & CSR_DONE) == 0)) CLR_INT (CLK); /* clr intr */ +return SCPE_OK; +} + +/* Clock routines */ t_stat clk_svc (UNIT *uptr) { @@ -502,7 +544,7 @@ int32 t; clk_csr = clk_csr | CSR_DONE; /* set done */ if (clk_csr & CSR_IE) SET_INT (CLK); -t = sim_rtc_calb (clk_tps); /* calibrate clock */ +t = sim_rtcn_calb (clk_tps, TMR_CLK); /* calibrate clock */ sim_activate (&clk_unit, t); /* reactivate unit */ tmr_poll = t; /* set timer poll */ tmxr_poll = t; /* set mux poll */ @@ -511,7 +553,7 @@ return SCPE_OK; t_stat clk_reset (DEVICE *dptr) { -clk_csr = 0; +clk_csr = CSR_DONE; /* set done */ CLR_INT (CLK); sim_activate (&clk_unit, clk_unit.wait); /* activate unit */ tmr_poll = clk_unit.wait; /* set timer poll */ diff --git a/PDP11/pdp11_sys.c b/PDP11/pdp11_sys.c index 7496d880..d1fff505 100644 --- a/PDP11/pdp11_sys.c +++ b/PDP11/pdp11_sys.c @@ -1,6 +1,6 @@ /* pdp11_sys.c: PDP-11 simulator interface - Copyright (c) 1993-2001, Robert M Supnik + Copyright (c) 1993-2002, Robert M Supnik Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), @@ -53,7 +53,6 @@ extern DEVICE rk_dev, rl_dev; extern DEVICE rp_dev, rq_dev; extern DEVICE rx_dev, dt_dev; extern DEVICE tm_dev, ts_dev; -/* extern DEVICE hk_dev; */ extern UNIT cpu_unit; extern REG cpu_reg[]; extern uint16 *M; diff --git a/PDP11/pdp11_tc.c b/PDP11/pdp11_tc.c index 7b4413cd..650a2857 100644 --- a/PDP11/pdp11_tc.c +++ b/PDP11/pdp11_tc.c @@ -1,6 +1,6 @@ /* pdp11_tc.c: PDP-11 DECtape simulator - Copyright (c) 1993-2001, Robert M Supnik + Copyright (c) 1993-2002, Robert M Supnik Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), @@ -25,6 +25,9 @@ tc TC11/TU56 DECtape + 30-May-02 RMS Widened POS to 32b + 26-Jan-02 RMS Revised bootstrap to conform to M9312 + 06-Jan-02 RMS Revised enable/disable support 30-Nov-01 RMS Added read only unit, extended SET/SHOW support 24-Nov-01 RMS Converted POS, STATT, LASTT to arrays 09-Nov-01 RMS Added bus map support @@ -258,8 +261,9 @@ int32 dt_actime = 54000; /* accel time */ int32 dt_dctime = 72000; /* decel time */ int32 dt_substate = 0; int32 dt_logblk = 0; -int32 dt_enb = 1; /* device enable */ +t_stat dt_rd (int32 *data, int32 PA, int32 access); +t_stat dt_wr (int32 data, int32 PA, int32 access); t_stat dt_svc (UNIT *uptr); t_stat dt_svcdone (UNIT *uptr); t_stat dt_reset (DEVICE *dptr); @@ -286,6 +290,8 @@ extern int32 sim_is_running; dt_mod DT modifier list */ +DIB dt_dib = { 1, IOBA_TC, IOLN_TC, &dt_rd, &dt_wr }; + UNIT dt_unit[] = { { UDATA (&dt_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE, DT_CAPAC) }, { UDATA (&dt_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE, DT_CAPAC) }, @@ -315,7 +321,7 @@ REG dt_reg[] = { { DRDATA (DCTIME, dt_dctime, 31), REG_NZ }, { ORDATA (SUBSTATE, dt_substate, 1) }, { DRDATA (LBLK, dt_logblk, 12), REG_HIDDEN }, - { URDATA (POS, dt_unit[0].pos, 10, 31, 0, + { URDATA (POS, dt_unit[0].pos, 10, 32, 0, DT_NUMDR, PV_LEFT | REG_RO) }, { URDATA (STATT, dt_unit[0].STATE, 8, 18, 0, DT_NUMDR, REG_RO) }, @@ -323,14 +329,21 @@ REG dt_reg[] = { DT_NUMDR, REG_HRO) }, { URDATA (FLG, dt_unit[0].flags, 8, UNIT_W_UF, UNIT_V_UF - 1, DT_NUMDR, REG_HRO) }, - { FLDATA (*DEVENB, dt_enb, 0), REG_HRO }, + { ORDATA (DEVADDR, dt_dib.ba, 32), REG_HRO }, + { FLDATA (*DEVENB, dt_dib.enb, 0), REG_HRO }, { NULL } }; MTAB dt_mod[] = { - { UNIT_WLK, 0, "write enabled", "ENABLED", NULL }, + { UNIT_WLK, 0, "write enabled", "WRITEENABLED", NULL }, { UNIT_WLK, UNIT_WLK, "write locked", "LOCKED", NULL }, { UNIT_8FMT, 0, "16b/18b", NULL, NULL }, { UNIT_8FMT, UNIT_8FMT, "12b", NULL, NULL }, + { MTAB_XTD|MTAB_VDV, 004, "ADDRESS", "ADDRESS", + &set_addr, &show_addr, &dt_dib }, + { MTAB_XTD|MTAB_VDV, 1, NULL, "ENABLED", + &set_enbdis, NULL, &dt_dib }, + { MTAB_XTD|MTAB_VDV, 0, NULL, "DISABLED", + &set_enbdis, NULL, &dt_dib }, { 0 } }; DEVICE dt_dev = { @@ -960,11 +973,13 @@ return SCPE_OK; /* Device bootstrap */ -#define BOOT_START 02000 /* start */ -#define BOOT_UNIT 02006 /* unit number */ +#define BOOT_START 02000 /* start */ +#define BOOT_ENTRY 02002 /* entry */ +#define BOOT_UNIT 02010 /* unit number */ #define BOOT_LEN (sizeof (boot_rom) / sizeof (int32)) static const int32 boot_rom[] = { + 0042124, /* "TD" */ 0012706, 0002000, /* MOV #2000, SP */ 0012700, 0000000, /* MOV #unit, R0 ; unit number */ 0010003, /* MOV R0, R3 */ @@ -993,8 +1008,8 @@ static const int32 boot_rom[] = { 0010211, /* MOV R2, (R1) ; load csr */ 0005002, /* CLR R2 */ 0005003, /* CLR R3 */ - 0005004, /* CLR R4 */ - 0012705, 0052104, /* MOV #"DT, R5 */ + 0012704, BOOT_START+020, /* MOV #START+20, R4 */ + 0005005, /* CLR R5 */ 0032711, 0100200, /* BIT #100200, (R1) ; wait */ 0001775, /* BEQ .-4 */ 0100401, /* BMI ER ; err, die */ @@ -1011,7 +1026,7 @@ extern int32 saved_PC; dt_unit[unitno].pos = DT_EZLIN; for (i = 0; i < BOOT_LEN; i++) M[(BOOT_START >> 1) + i] = boot_rom[i]; M[BOOT_UNIT >> 1] = unitno & DT_M_NUMDR; -saved_PC = BOOT_START; +saved_PC = BOOT_ENTRY; return SCPE_OK; } diff --git a/PDP11/pdp11_tm.c b/PDP11/pdp11_tm.c index 3fbfb842..38d5318d 100644 --- a/PDP11/pdp11_tm.c +++ b/PDP11/pdp11_tm.c @@ -1,6 +1,6 @@ /* pdp11_tm.c: PDP-11 magnetic tape simulator - Copyright (c) 1993-2001, Robert M Supnik + Copyright (c) 1993-2002, Robert M Supnik Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), @@ -25,6 +25,11 @@ tm TM11/TU10 magtape + 30-May-02 RMS Widened POS to 32b + 22-Apr-02 RMS Fixed max record length, first block bootstrap + (found by Jonathan Engdahl) + 26-Jan-02 RMS Revised bootstrap to conform to M9312 + 06-Jan-02 RMS Revised enable/disable support 30-Nov-01 RMS Added read only unit, extended SET/SHOW support 24-Nov-01 RMS Converted UST, POS, FLG to arrays 09-Nov-01 RMS Added bus map support @@ -67,7 +72,6 @@ #define UNIT_W_UF 2 /* saved user flags */ #define USTAT u3 /* unit status */ #define UNUM u4 /* unit number */ -#define TM_MAXFR (1 << 16) /* max transfer */ #define UNIT_WPRT (UNIT_WLK | UNIT_RO) /* write protect */ /* Command - tm_cmd */ @@ -145,8 +149,9 @@ int32 tm_db = 0; /* data buffer */ int32 tm_rdl = 0; /* read lines */ int32 tm_time = 10; /* record latency */ int32 tm_stopioe = 1; /* stop on error */ -int32 tm_enb = 1; /* device enable */ +t_stat tm_rd (int32 *data, int32 PA, int32 access); +t_stat tm_wr (int32 data, int32 PA, int32 access); t_stat tm_svc (UNIT *uptr); t_stat tm_reset (DEVICE *dptr); t_stat tm_attach (UNIT *uptr, char *cptr); @@ -165,6 +170,8 @@ t_stat tm_vlock (UNIT *uptr, int32 val, char *cptr, void *desc); tm_mod MT modifier list */ +DIB tm_dib = { 1, IOBA_TM, IOLN_TM, &tm_rd, &tm_wr }; + UNIT tm_unit[] = { { UDATA (&tm_svc, UNIT_ATTABLE + UNIT_DISABLE, 0) }, { UDATA (&tm_svc, UNIT_ATTABLE + UNIT_DISABLE, 0) }, @@ -189,16 +196,23 @@ REG tm_reg[] = { { FLDATA (STOP_IOE, tm_stopioe, 0) }, { DRDATA (TIME, tm_time, 24), PV_LEFT }, { URDATA (UST, tm_unit[0].USTAT, 8, 16, 0, TM_NUMDR, 0) }, - { URDATA (POS, tm_unit[0].pos, 10, 31, 0, + { URDATA (POS, tm_unit[0].pos, 10, 32, 0, TM_NUMDR, PV_LEFT | REG_RO) }, { URDATA (FLG, tm_unit[0].flags, 8, UNIT_W_UF, UNIT_V_UF - 1, TM_NUMDR, REG_HRO) }, - { FLDATA (*DEVENB, tm_enb, 0), REG_HRO }, + { ORDATA (DEVADDR, tm_dib.ba, 32), REG_HRO }, + { FLDATA (*DEVENB, tm_dib.enb, 0), REG_HRO }, { NULL } }; MTAB tm_mod[] = { - { UNIT_WLK, 0, "write enabled", "ENABLED", &tm_vlock }, + { UNIT_WLK, 0, "write enabled", "WRITEENABLED", &tm_vlock }, { UNIT_WLK, UNIT_WLK, "write locked", "LOCKED", &tm_vlock }, + { MTAB_XTD|MTAB_VDV, 020, "ADDRESS", "ADDRESS", + &set_addr, &show_addr, &tm_dib }, + { MTAB_XTD|MTAB_VDV, 1, NULL, "ENABLED", + &set_enbdis, NULL, &tm_dib }, + { MTAB_XTD|MTAB_VDV, 0, NULL, "DISABLED", + &set_enbdis, NULL, &tm_dib }, { 0 } }; DEVICE tm_dev = { @@ -380,6 +394,7 @@ case MTC_READ: /* read */ uptr -> pos = uptr -> pos + sizeof (t_mtrlnt); break; } tbc = MTRL (tbc); /* ignore error flag */ + if (tbc > MT_MAXFR) return SCPE_MTRLNT; /* record too long? */ if (tbc > cbc) tm_sta = tm_sta | STA_RLE; /* wrong size? */ if (tbc < cbc) cbc = tbc; /* use smaller */ i = fxread (tmxb, sizeof (int8), cbc, uptr -> fileref); @@ -501,9 +516,7 @@ t_stat tm_reset (DEVICE *dptr) { int32 u; UNIT *uptr; -extern int32 ts_enb; -if (tm_enb) ts_enb = 0; /* TM or TS */ tm_cmd = MTC_DONE; /* set done */ tm_bc = tm_ca = tm_db = tm_sta = tm_rdl = 0; CLR_INT (TM); /* clear interrupt */ @@ -515,7 +528,7 @@ for (u = 0; u < TM_NUMDR; u++) { /* loop thru units */ ((uptr -> pos)? 0: STA_BOT) | ((uptr -> flags & UNIT_WPRT)? STA_WLK: 0); else uptr -> USTAT = 0; } -if (tmxb == NULL) tmxb = calloc (TM_MAXFR, sizeof (unsigned int8)); +if (tmxb == NULL) tmxb = calloc (MT_MAXFR, sizeof (unsigned int8)); if (tmxb == NULL) return SCPE_MEM; return SCPE_OK; } @@ -563,19 +576,21 @@ return SCPE_OK; use the second block scheme, so it is the default. To boot from the first block, use boot -o (old). - */ +*/ -#define BOOT_START 040000 -#define BOOT_UNIT (BOOT_START + 6) +#define BOOT_START 040000 +#define BOOT_ENTRY (BOOT_START + 2) +#define BOOT_UNIT (BOOT_START + 010) #define BOOT1_LEN (sizeof (boot1_rom) / sizeof (int32)) #define BOOT2_LEN (sizeof (boot2_rom) / sizeof (int32)) static const int32 boot1_rom[] = { + 0046524, /* boot_start: "TM" */ 0012706, 0040000, /* mov #boot_start, sp */ 0012700, 0000000, /* mov #unit_num, r0 */ 0012701, 0172526, /* mov #172526, r1 ; mtcma */ 0005011, /* clr (r1) */ - 0011041, /* mov r1, -(r1) ; mtbrc */ + 0010141, /* mov r1, -(r1) ; mtbrc */ 0010002, /* mov r0,r2 */ 0000302, /* swab r2 */ 0062702, 0060003, /* add #60003, r2 */ @@ -584,12 +599,13 @@ static const int32 boot1_rom[] = { 0100376, /* bpl .-2 */ 0005002, /* clr r2 */ 0005003, /* clr r3 */ - 0005004, /* clr r4 */ - 0012705, 0052115, /* mov #MT, r5 */ + 0012704, BOOT_START+020, /* mov #boot_start+20, r4 */ + 0005005, /* clr r5 */ 0005007 /* clr r7 */ }; static const int32 boot2_rom[] = { + 0046524, /* boot_start: "TM" */ 0012706, 0040000, /* mov #boot_start, sp */ 0012700, 0000000, /* mov #unit_num, r0 */ 0012701, 0172526, /* mov #172526, r1 ; mtcma */ @@ -609,8 +625,8 @@ static const int32 boot2_rom[] = { 0100376, /* bpl .-2 */ 0005002, /* clr r2 */ 0005003, /* clr r3 */ - 0005004, /* clr r4 */ - 0012705, 0052115, /* mov #MT, r5 */ + 0012704, BOOT_START+020, /* mov #boot_start+20, r4 */ + 0005005, /* clr r5 */ 0005007 /* clr r7 */ }; @@ -627,6 +643,6 @@ if (sim_switches & SWMASK ('O')) { else { for (i = 0; i < BOOT2_LEN; i++) M[(BOOT_START >> 1) + i] = boot2_rom[i]; } M[BOOT_UNIT >> 1] = unitno; -saved_PC = BOOT_START; +saved_PC = BOOT_ENTRY; return SCPE_OK; } diff --git a/PDP11/pdp11_ts.c b/PDP11/pdp11_ts.c index ff03b4c7..78d1ed5a 100644 --- a/PDP11/pdp11_ts.c +++ b/PDP11/pdp11_ts.c @@ -1,6 +1,6 @@ /* pdp11_ts.c: TS11/TSV05 magnetic tape simulator - Copyright (c) 1993-2001, Robert M Supnik + Copyright (c) 1993-2002, Robert M Supnik Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), @@ -25,6 +25,12 @@ ts TS11/TSV05 magtape + 30-May-02 RMS Widened POS to 32b + 22-Apr-02 RMS Added maximum record length protection + 04-Apr-02 RMS Fixed bug in residual frame count after space operation + 16-Feb-02 RMS Fixed bug in message header logic + 26-Jan-02 RMS Revised bootstrap to conform to M9312 + 06-Jan-02 RMS Revised enable/disable support 30-Nov-01 RMS Added read only unit, extended SET/SHOW support 09-Nov-01 RMS Added bus map, VAX support 15-Oct-01 RMS Integrated debug logging across simulator @@ -91,7 +97,6 @@ extern int32 cpu_18b, cpu_ubm; #define UNIT_V_WLK (UNIT_V_UF + 0) /* write locked */ #define UNIT_WLK (1 << UNIT_V_WLK) -#define TS_MAXFR (1 << 16) /* max xfer */ #define UNIT_WPRT (UNIT_WLK | UNIT_RO) /* write protect */ /* TSBA/TSDB - 17772520: base address/data buffer register @@ -118,7 +123,8 @@ extern int32 cpu_18b, cpu_ubm; #define TSSR_SSR 0000200 /* subsystem ready */ #define TSSR_OFL 0000100 /* offline */ #define TSSR_V_TC 1 /* term class */ -#define TSSR_TC (07 << TSSR_V_TC) +#define TSSR_M_TC 07 +#define TSSR_TC (TSSR_M_TC << TSSR_V_TC) #define TC0 (0 << TSSR_V_TC) /* ok */ #define TC1 (1 << TSSR_V_TC) /* attention */ #define TC2 (2 << TSSR_V_TC) /* status alert */ @@ -128,6 +134,7 @@ extern int32 cpu_18b, cpu_ubm; #define TC6 (6 << TSSR_V_TC) /* pos lost */ #define TC7 (7 << TSSR_V_TC) /* fatal err */ #define TSSR_MBZ 0060060 +#define GET_TC(x) (((x) >> TSSR_V_TC) & TSSR_M_TC) #define TSDBX_M_XA 017 /* ext addr */ #define TSDBX_BOOT 0000200 /* boot */ @@ -254,6 +261,7 @@ extern int32 cpu_18b, cpu_ubm; extern int32 int_req[IPL_HLVL]; extern UNIT cpu_unit; +extern int32 cpu_log; extern FILE *sim_log; uint8 *tsxb = NULL; /* xfer buffer */ int32 tssr = 0; /* status register */ @@ -267,8 +275,9 @@ int32 ts_ownm = 0; /* tape owns msg */ int32 ts_qatn = 0; /* queued attn */ int32 ts_bcmd = 0; /* boot cmd */ int32 ts_time = 10; /* record latency */ -int32 ts_enb = TS_DF_ENB; /* device enable */ +t_stat ts_rd (int32 *data, int32 PA, int32 access); +t_stat ts_wr (int32 data, int32 PA, int32 access); t_stat ts_svc (UNIT *uptr); t_stat ts_reset (DEVICE *dptr); t_stat ts_attach (UNIT *uptr, char *cptr); @@ -287,6 +296,8 @@ void ts_endcmd (int32 ssf, int32 xs0f, int32 msg); ts_mod TS modifier list */ +DIB ts_dib = { TS_DF_ENB, IOBA_TS, IOLN_TS, &ts_rd, &ts_wr }; + UNIT ts_unit = { UDATA (&ts_svc, UNIT_ATTABLE + UNIT_DISABLE, 0) }; REG ts_reg[] = { @@ -315,14 +326,21 @@ REG ts_reg[] = { { FLDATA (OWNC, ts_ownc, 0) }, { FLDATA (OWNM, ts_ownm, 0) }, { DRDATA (TIME, ts_time, 24), PV_LEFT + REG_NZ }, - { DRDATA (POS, ts_unit.pos, 31), PV_LEFT + REG_RO }, + { DRDATA (POS, ts_unit.pos, 32), PV_LEFT + REG_RO }, { FLDATA (WLK, ts_unit.flags, UNIT_V_WLK), REG_HRO }, - { FLDATA (*DEVENB, ts_enb, 0), REG_HRO }, + { GRDATA (DEVADDR, ts_dib.ba, TS_RDX, 32, 0), REG_HRO }, + { FLDATA (*DEVENB, ts_dib.enb, 0), REG_HRO }, { NULL } }; MTAB ts_mod[] = { - { UNIT_WLK, 0, "write enabled", "ENABLED", NULL }, + { UNIT_WLK, 0, "write enabled", "WRITEENABLED", NULL }, { UNIT_WLK, UNIT_WLK, "write locked", "LOCKED", NULL }, + { MTAB_XTD|MTAB_VDV, 004, "ADDRESS", "ADDRESS", + &set_addr, &show_addr, &ts_dib }, + { MTAB_XTD|MTAB_VDV, 1, NULL, "ENABLED", + &set_enbdis, NULL, &ts_dib }, + { MTAB_XTD|MTAB_VDV, 0, NULL, "DISABLED", + &set_enbdis, NULL, &ts_dib }, { 0 } }; DEVICE ts_dev = { @@ -409,12 +427,13 @@ int32 ts_spacef (UNIT *uptr, int32 fc, t_bool upd) int32 st; t_mtrlnt tbc; -do { if (st = ts_rdlntf (uptr, &tbc)) return st; /* read rec lnt */ +do { fc = (fc - 1) & DMASK; /* decr wc */ + if (upd) msgrfc = fc; + if (st = ts_rdlntf (uptr, &tbc)) return st; /* read rec lnt */ uptr -> pos = uptr -> pos + sizeof (t_mtrlnt); /* update pos */ if (tbc == 0) return (XTC (XS0_TMK | XS0_RLS, TC2)); uptr -> pos = uptr -> pos + ((MTRL (tbc) + 1) & ~1) + sizeof (t_mtrlnt); - fc = (fc - 1) & DMASK; /* decr wc */ - if (upd) msgrfc = fc; } + } while (fc != 0); return 0; } @@ -459,13 +478,15 @@ int32 ts_spacer (UNIT *uptr, int32 fc, t_bool upd) int32 st; t_mtrlnt tbc; +if (upd) msgrfc = fc; do { if (uptr -> pos == 0) break; /* BOT? */ + fc = (fc - 1) & DMASK; /* decr wc */ + if (upd) msgrfc = fc; if (st = ts_rdlntr (uptr, &tbc)) return st; /* read rec lnt */ uptr -> pos = uptr -> pos - sizeof (t_mtrlnt); /* update pos */ if (tbc == 0) return (XTC (XS0_TMK | XS0_RLS, TC2)); uptr -> pos = uptr -> pos - ((MTRL (tbc) + 1) & ~1) - sizeof (t_mtrlnt); - fc = (fc - 1) & DMASK; /* decr wc */ - if (upd) msgrfc = fc; } + } while (fc != 0); if (uptr -> pos == 0) { msgxs3 = msgxs3 | XS3_RIB; @@ -509,8 +530,8 @@ if (tbc == 0) { /* tape mark? */ if (fc == 0) fc = 0200000; /* byte count */ tsba = (cmdadh << 16) | cmdadl; /* buf addr */ tbc = MTRL (tbc); /* ignore err flag */ -wbc = (tbc > TS_MAXFR)? TS_MAXFR: tbc; /* cap rec size */ -wbc = (wbc > fc)? fc: wbc; /* cap buf size */ +if (tbc > MT_MAXFR) return SCPE_MTRLNT; /* record too long? */ +wbc = (tbc > fc)? fc: tbc; /* cap buf size */ i = fxread (tsxb, sizeof (uint8), wbc, uptr -> fileref); /* read record */ if (ferror (uptr -> fileref)) return XTC (XS0_EOT | XS0_RLS, TC2); for ( ; i < wbc; i++) tsxb[i] = 0; /* fill with 0's */ @@ -545,8 +566,8 @@ if (tbc == 0) { /* tape mark? */ if (fc == 0) fc = 0200000; /* byte count */ tsba = (cmdadh << 16) | cmdadl + fc; /* buf addr */ tbc = MTRL (tbc); /* ignore err flag */ -wbc = (tbc > TS_MAXFR)? TS_MAXFR: tbc; /* cap rec size */ -wbc = (wbc > fc)? fc: wbc; /* cap buf size */ +if (tbc > MT_MAXFR) return SCPE_MTRLNT; /* record too long? */ +wbc = (tbc > fc)? fc: tbc; /* cap buf size */ fseek (uptr -> fileref, uptr -> pos - sizeof (t_mtrlnt) - wbc, SEEK_SET); i = fxread (tsxb, sizeof (uint8), wbc, uptr -> fileref); for ( ; i < wbc; i++) tsxb[i] = 0; /* fill with 0's */ @@ -787,6 +808,9 @@ case FNC_POS: break; } ts_cmpendcmd (st0, 0); break; } +if (DBG_LOG (LOG_TS)) + fprintf (sim_log, ">>TS: cmd=%o, mod=%o, buf=%o, lnt=%d, sta=%o, tc=%o, pos=%d\n", + fnc, mod, cmdadl, cmdlnt, msgxs0, GET_TC (tssr), ts_unit.pos); return SCPE_OK; } @@ -821,10 +845,12 @@ static const int32 msg[8] = { MSG_ACK | MSG_CERR, MSG_ACK | MSG_CERR, MSG_ACK | MSG_CERR, MSG_ACK | MSG_CERR }; -xs0 = GET_X (s0 | s1); /* or XS0 errs */ -ssr = GET_T (s0 | s1) & ~TSSR_TC; /* or SSR errs */ -tc = MAX (s0 & TSSR_TC, s1 & TSSR_TC); /* max term code */ -ts_endcmd (ssr | tc, xs0, msg[tc]); /* end cmd */ +xs0 = GET_X (s0) | GET_X (s1); /* or XS0 errs */ +s0 = GET_T (s0); /* get SSR errs */ +s1 = GET_T (s1); +ssr = (s0 | s1) & ~TSSR_TC; /* or SSR errs */ +tc = MAX (GET_TC (s0), GET_TC (s1)); /* max term code */ +ts_endcmd (ssr | (tc << TSSR_V_TC), xs0, msg[tc]); /* end cmd */ return; } @@ -857,11 +883,7 @@ return; t_stat ts_reset (DEVICE *dptr) { int32 i; -#if defined (VM_PDP11) -extern int32 tm_enb; -if (ts_enb) tm_enb = 0; /* TM or TS */ -#endif ts_unit.pos = 0; tsba = tsdbx = 0; ts_ownc = ts_ownm = 0; @@ -873,7 +895,7 @@ for (i = 0; i < WCH_PLNT; i++) tswchp[i] = 0; for (i = 0; i < MSG_PLNT; i++) tsmsgp[i] = 0; msgxs0 = ts_updxs0 (XS0_VCK); CLR_INT (TS); -if (tsxb == NULL) tsxb = calloc (TS_MAXFR, sizeof (unsigned int8)); +if (tsxb == NULL) tsxb = calloc (MT_MAXFR, sizeof (unsigned int8)); if (tsxb == NULL) return SCPE_MEM; return SCPE_OK; } @@ -939,9 +961,9 @@ static const int32 boot_rom[] = { 0005711, /* tst (r1) ; err? */ 0100421, /* bmi hlt */ 0005000, /* clr r0 */ - 0012705, 0051515, /* mov #MS, r5 */ + 0012704, 0001066+020, /* mov #sgnt+20, r4 */ 0005007, /* clr r7 */ - 0046523, /* pad */ + 0046523, /* sgnt: "SM" */ 0140004, /* pkt1: 140004, wcpk, 0, 8. */ 0001100, 0000000, diff --git a/PDP18B/pdp18b_cpu.c b/PDP18B/pdp18b_cpu.c index 02ade4c9..a26a2b11 100644 --- a/PDP18B/pdp18b_cpu.c +++ b/PDP18B/pdp18b_cpu.c @@ -1,6 +1,6 @@ /* pdp18b_cpu.c: 18b PDP CPU simulator - Copyright (c) 1993-2001, Robert M Supnik + Copyright (c) 1993-2002, Robert M Supnik Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), @@ -25,6 +25,8 @@ cpu PDP-4/7/9/15 central processor + 06-Jan-02 RMS Revised enable/disable support + 30-Dec-01 RMS Added old PC queue 30-Nov-01 RMS Added extended SET/SHOW support 25-Nov-01 RMS Revised interrupt structure 19-Sep-01 RMS Fixed bug in EAE (found by Dave Conroy) @@ -246,6 +248,9 @@ #include "pdp18b_defs.h" +#define PCQ_SIZE 64 /* must be 2**n */ +#define PCQ_MASK (PCQ_SIZE - 1) +#define PCQ_ENTRY pcq[pcq_p = (pcq_p - 1) & PCQ_MASK] = PC #define UNIT_V_NOEAE (UNIT_V_UF) /* EAE absent */ #define UNIT_NOEAE (1 << UNIT_V_NOEAE) #define UNIT_V_NOAPI (UNIT_V_UF+1) /* API absent */ @@ -297,7 +302,13 @@ int32 XR = 0; /* index register */ int32 LR = 0; /* limit register */ int32 stop_inst = 0; /* stop on rsrv inst */ int32 xct_max = 16; /* nested XCT limit */ -int32 old_PC = 0; /* old PC */ +#if defined (PDP15) +int32 pcq[PCQ_SIZE] = { 0 }; /* PC queue */ +#else +int16 pcq[PCQ_SIZE] = { 0 }; /* PC queue */ +#endif +int32 pcq_p = 0; /* PC queue ptr */ +REG *pcq_r = NULL; /* PC queue reg ptr */ int32 dev_enb = -1; /* device enables */ extern int32 sim_int_char; extern int32 sim_brk_types, sim_brk_dflt, sim_brk_summ; /* breakpoint info */ @@ -398,7 +409,8 @@ REG cpu_reg[] = { { FLDATA (RESTP, rest_pending, 0) }, { FLDATA (PWRFL, int_hwre[API_PWRFL], INT_V_PWRFL) }, #endif - { ORDATA (OLDPC, old_PC, ADDRSIZE), REG_RO }, + { BRDATA (PCQ, pcq, 8, ADDRSIZE, PCQ_SIZE), REG_RO+REG_CIRC }, + { ORDATA (PCQP, pcq_p, 6), REG_HRO }, { FLDATA (STOP_INST, stop_inst, 0) }, { FLDATA (NOEAE, cpu_unit.flags, UNIT_V_NOEAE), REG_HRO }, { FLDATA (NOAPI, cpu_unit.flags, UNIT_V_NOAPI), REG_HRO }, @@ -631,7 +643,7 @@ if (sim_interval <= 0) { /* check clock queue */ #if defined (PDP7) if (trap_pending) { /* trap pending? */ - old_PC = PC; /* save old PC */ + PCQ_ENTRY; /* save old PC */ M[0] = JMS_WORD (1); /* save state */ PC = 2; /* fetch next from 2 */ ion = 0; /* interrupts off */ @@ -641,7 +653,7 @@ if (trap_pending) { /* trap pending? */ #endif #if defined (PDP9) || defined (PDP15) if (trap_pending) { /* trap pending? */ - old_PC = PC; /* save old PC */ + PCQ_ENTRY; /* save old PC */ MA = ion? 0: 020; /* save in 0 or 20 */ M[MA] = JMS_WORD (1); /* save state */ PC = MA + 1; /* fetch next */ @@ -677,7 +689,7 @@ if (!(api_enb && api_act) && ion && !ion_defer && int_pend) { #else if (ion && !ion_defer && int_pend) { /* interrupt? */ #endif - old_PC = PC; /* save old PC */ + PCQ_ENTRY; /* save old PC */ M[0] = JMS_WORD (usmd); /* save state */ PC = 1; /* fetch next from 1 */ ion = 0; /* interrupts off */ @@ -864,7 +876,7 @@ case 001: case 000: /* CAL */ #endif if (IR & 0020000) { INDIRECT; } /* indirect? */ CHECK_ADDR_W (MA); - old_PC = PC; + PCQ_ENTRY; M[MA] = JMS_WORD (t); /* save state */ PC = INCR_ADDR (MA); break; @@ -877,7 +889,7 @@ case 005: /* JMS, indir */ case 004: /* JMS, dir */ CHECK_INDEX; CHECK_ADDR_W (MA); - old_PC = PC; + PCQ_ENTRY; M[MA] = JMS_WORD (usmd); /* save state */ PC = INCR_ADDR (MA); break; @@ -904,7 +916,7 @@ CHECK_AUTO_INC; /* check auto inc */ emir_pending = rest_pending = 0; case 030: /* JMP, dir */ CHECK_INDEX; - old_PC = PC; /* save old PC */ + PCQ_ENTRY; /* save old PC */ PC = MA; break; @@ -1407,33 +1419,35 @@ case 034: /* IOT */ break; #if defined (TTY1) case 040: /* TTO1 */ - iot_data = tto1 (pulse, iot_data); + if (dev_enb & ENB_TTI1) iot_data = tto1 (pulse, iot_data); + else reason = stop_inst; break; case 041: /* TTI1 */ - iot_data = tti1 (pulse, iot_data); + if (dev_enb & ENB_TTI1) iot_data = tti1 (pulse, iot_data); + else reason = stop_inst; break; #endif #if defined (DRM) case 060: /* drum */ - if (dev_enb & INT_DRM) iot_data = drm60 (pulse, iot_data); + if (dev_enb & ENB_DRM) iot_data = drm60 (pulse, iot_data); else reason = stop_inst; break; case 061: - if (dev_enb & INT_DRM) iot_data = drm61 (pulse, iot_data); + if (dev_enb & ENB_DRM) iot_data = drm61 (pulse, iot_data); else reason = stop_inst; break; case 062: - if (dev_enb & INT_DRM) iot_data = drm62 (pulse, iot_data); + if (dev_enb & ENB_DRM) iot_data = drm62 (pulse, iot_data); else reason = stop_inst; break; #endif #if defined (RP) case 063: /* RP15 */ - if (dev_enb & INT_RP) iot_data = rp63 (pulse, iot_data); + if (dev_enb & ENB_RP) iot_data = rp63 (pulse, iot_data); else reason = stop_inst; break; case 064: - if (dev_enb & INT_RP) iot_data = rp64 (pulse, iot_data); + if (dev_enb & ENB_RP) iot_data = rp64 (pulse, iot_data); else reason = stop_inst; break; #endif @@ -1445,27 +1459,27 @@ case 034: /* IOT */ break; #if defined (RF) case 070: /* RF09 */ - if (dev_enb & INT_RF) iot_data = rf70 (pulse, iot_data); + if (dev_enb & ENB_RF) iot_data = rf70 (pulse, iot_data); else reason = stop_inst; break; case 072: - if (dev_enb & INT_RF) iot_data = rf72 (pulse, iot_data); + if (dev_enb & ENB_RF) iot_data = rf72 (pulse, iot_data); else reason = stop_inst; break; #endif #if defined (MTA) case 073: /* TC59 */ - if (dev_enb & INT_MTA) iot_data = mt (pulse, iot_data); + if (dev_enb & ENB_MTA) iot_data = mt (pulse, iot_data); else reason = stop_inst; break; #endif #if defined (DTA) case 075: /* TC02/TC15 */ - if (dev_enb & INT_DTA) iot_data = dt75 (pulse, iot_data); + if (dev_enb & ENB_DTA) iot_data = dt75 (pulse, iot_data); else reason = stop_inst; break; case 076: - if (dev_enb & INT_DTA) iot_data = dt76 (pulse, iot_data); + if (dev_enb & ENB_DTA) iot_data = dt76 (pulse, iot_data); else reason = stop_inst; break; #endif @@ -1490,6 +1504,7 @@ saved_PC = PC & ADDRMASK; /* save copies */ saved_LAC = LAC & 01777777; saved_MQ = MQ & 0777777; iors = upd_iors (); /* get IORS */ +pcq_r -> qptr = pcq_p; /* update pc q ptr */ return reason; } @@ -1560,6 +1575,9 @@ usmd = usmdbuf = 0; memm = memm_init; nexm = prvn = trap_pending = 0; emir_pending = rest_pending = 0; +pcq_r = find_reg ("PCQ", NULL, dptr); +if (pcq_r) pcq_r -> qptr = 0; +else return SCPE_IERR; sim_brk_types = sim_brk_dflt = SWMASK ('E'); return SCPE_OK; } @@ -1598,3 +1616,39 @@ MEMSIZE = val; for (i = MEMSIZE; i < MAXMEMSIZE; i++) M[i] = 0; return SCPE_OK; } + +/* Device enable routine */ + +t_stat set_enb (UNIT *uptr, int32 val, char *cptr, void *desc) +{ +DEVICE *dptr; + +if (cptr != NULL) return SCPE_ARG; +if ((uptr == NULL) || (val == 0)) return SCPE_IERR; +dptr = find_dev_from_unit (uptr); +if (dptr == NULL) return SCPE_IERR; +dev_enb = dev_enb | val; +if (dptr -> reset) dptr -> reset (dptr); +return SCPE_OK; +} + +/* Device disable routine */ + +t_stat set_dsb (UNIT *uptr, int32 val, char *cptr, void *desc) +{ +int32 i; +DEVICE *dptr; +UNIT *up; + +if (cptr != NULL) return SCPE_ARG; +if ((uptr == NULL) || (val == 0)) return SCPE_IERR; +dptr = find_dev_from_unit (uptr); +if (dptr == NULL) return SCPE_IERR; +for (i = 0; i < dptr -> numunits; i++) { /* check units */ + up = (dptr -> units) + i; + if ((up -> flags & UNIT_ATT) || sim_is_active (up)) + return SCPE_NOFNC; } +dev_enb = dev_enb & ~val; +if (dptr -> reset) dptr -> reset (dptr); +return SCPE_OK; +} diff --git a/PDP18B/pdp18b_defs.h b/PDP18B/pdp18b_defs.h index d7e73f1e..d4135060 100644 --- a/PDP18B/pdp18b_defs.h +++ b/PDP18B/pdp18b_defs.h @@ -1,6 +1,6 @@ /* pdp18b_defs.h: 18b PDP simulator definitions - Copyright (c) 1993-2001, Robert M Supnik + Copyright (c) 1993-2002, Robert M Supnik Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), @@ -23,6 +23,7 @@ be used in advertising or otherwise to promote the sale, use or other dealings in this Software without prior written authorization from Robert M Supnik. + 10-Feb-02 RMS Added PDP-7 DECtape support 25-Nov-01 RMS Revised interrupt structure 27-May-01 RMS Added second Teletype support 21-Jan-01 RMS Added DECtape support @@ -53,6 +54,7 @@ Type 75 paper tape punch integral real time clock Type 647B line printer (sixbit) + Type 550/555 DECtape Type 24 serial drum PDP9 32K KE09A EAE KSR-33 Teletype @@ -99,6 +101,7 @@ #elif defined (PDP7) #define ADDRSIZE 15 #define TYPE647 0 /* sixbit printer */ +#define DTA 0 /* DECtape */ #define DRM 0 /* drum */ #elif defined (PDP9) #define ADDRSIZE 15 @@ -203,7 +206,7 @@ #define ACH_PWRFL 052 -/*API level 1 */ +/* API level 1 */ #define INT_V_DTA 0 /* DECtape */ #define INT_V_MTA 1 /* magtape */ @@ -283,6 +286,22 @@ #define SET_INT(dv) int_hwre[API_##dv] = int_hwre[API_##dv] | INT_##dv #define CLR_INT(dv) int_hwre[API_##dv] = int_hwre[API_##dv] & ~INT_##dv #define TST_INT(dv) (int_hwre[API_##dv] & INT_##dv) + +/* Device enable flags are defined in a single 32b word */ + +#define ENB_V_DTA 0 /* DECtape */ +#define ENB_V_MTA 1 /* magtape */ +#define ENB_V_DRM 2 /* drum */ +#define ENB_V_RF 3 /* fixed head disk */ +#define ENB_V_RP 4 /* disk pack */ +#define ENB_V_TTI1 5 /* 2nd teletype */ + +#define ENB_DTA (1u << ENB_V_DTA) +#define ENB_MTA (1u << ENB_V_MTA) +#define ENB_DRM (1u << ENB_V_DRM) +#define ENB_RF (1u << ENB_V_RF) +#define ENB_RP (1u << ENB_V_RP) +#define ENB_TTI1 (1u << ENB_V_TTI1) /* I/O status flags for the IORS instruction @@ -336,3 +355,8 @@ #define IOS_MTA 0000100 /* magtape */ #define IOS_LPT 0000010 /* line printer */ #endif + +/* Function prototypes */ + +t_stat set_enb (UNIT *uptr, int32 val, char *cptr, void *desc); +t_stat set_dsb (UNIT *uptr, int32 val, char *cptr, void *desc); diff --git a/PDP18B/pdp18b_doc.txt b/PDP18B/pdp18b_doc.txt index dd06f063..a53640d0 100644 --- a/PDP18B/pdp18b_doc.txt +++ b/PDP18B/pdp18b_doc.txt @@ -1,14 +1,14 @@ To: Users From: Bob Supnik Subj: 18b PDP Simulator Usage -Date: 1-Dec-01 +Date: 15-Jul-2002 COPYRIGHT NOTICE The following copyright notice applies to both the SIMH source and binary: - Original code published in 1993-2001, written by Robert M Supnik - Copyright (c) 1993-2001, Robert M Supnik + Original code published in 1993-2002, written by Robert M Supnik + Copyright (c) 1993-2002, Robert M Supnik Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), @@ -88,6 +88,7 @@ PDP-7 CPU PDP-7 CPU with 32KW of memory TTI,TTO KSR 33 console terminal LPT Type 647 line printer CLK integral real-time clock + DT Type 550/555 DECtape DRM Type 24 serial drum PDP-9 CPU PDP-9 CPU with 32KW of memory @@ -120,7 +121,7 @@ PDP-15 CPU PDP-15 CPU with 32KW of memory DT TC15/TU56 DECtape MT TC59/TU10 magnetic tape -The DRM, RF, RP, DT, and MT devices can be DISABLEd. +The DRM, RF, RP, DT, and MT devices can be set DISABLED. The 18b PDP simulators implement several unique stop conditions: @@ -204,7 +205,8 @@ control registers for the interrupt system. 7,9 EMIRP 1 EMIR instruction pending 9,15 RESTP 1 DBR or RES instruction pending 9,15 PWRFL 1 power fail flag - all OLDPC addr PC prior to last transfer + all PCQ[0:63] addr PC prior to last JMP, JMS, CAL, or + interrupt; most recent PC change first all STOP_INST 1 stop on undefined instruction all WRU 8 interrupt character @@ -224,6 +226,11 @@ BOOT PTR copies the RIM loader into memory and starts it running, while BOOT -F PTR copies the funny format binary loader into memory and starts it running. +The PTR ATTACH command recognizes one switch, -a for ASCII mode. In +ASCII mode, data returned by the read alphabetic command has the high +order bit automatically set to 1. This allows normal text files to be +used as input to the paper tape reader. + The paper tape reader implements these registers: name size comments @@ -232,7 +239,7 @@ The paper tape reader implements these registers: INT 1 interrupt pending flag DONE 1 device done flag ERR 1 error flag (PDP-9, PDP-15 only) - POS 31 position in the input file + POS 32 position in the input file TIME 24 time from I/O initiation to interrupt STOP_IOE 1 stop on I/O error @@ -254,6 +261,11 @@ The paper tape punch (PTP) writes data to a disk file. The POS register specifies the number of the next data item to be written. Thus, by changing POS, the user can backspace or advance the punch. +The PTP ATTACH command recognizes one switch, -a for ASCII mode. In +ASCII mode, data is punched with the high order bit clear, and NULL and +DEL characters are supressed. This allows punch output to be processed +with normal text editing utilities. + The paper tape punch implements these registers: name size comments @@ -262,7 +274,7 @@ The paper tape punch implements these registers: INT 1 interrupt pending flag DONE 1 device done flag ERR 1 error flag (PDP-9, PDP-15 only) - POS 31 position in the output file + POS 32 position in the output file TIME 24 time from I/O initiation to interrupt STOP_IOE 1 stop on I/O error @@ -282,10 +294,10 @@ input side has one option, UC; when set, it automatically converts lower case input to upper case. The PDP-9 and PDP-15 operate the console terminal (TTI/TTO), by default, -as half duplex. For backward compatibility, on the PDP-9 and PDP-15 +with local echo. For backward compatibility, on the PDP-9 and PDP-15 the first terminal input has a second option, FDX; when set, it operates -the terminal input in full-duplex mode. The second terminal is always -full duplex. +the terminal input without local echo mode. The second terminal does +not offer local echo. The terminal input implements these registers: @@ -294,7 +306,7 @@ The terminal input implements these registers: BUF 8 last data item processed INT 1 interrupt pending flag DONE 1 device done flag - POS 31 number of characters input + POS 32 number of characters input TIME 24 keyboard polling interval 2.2.4 Terminal Output (TTO) @@ -310,7 +322,7 @@ The terminal output implements these registers: BUF 8 last data item processed INT 1 interrupt pending flag DONE 1 device done flag - POS 31 number of chararacters output + POS 32 number of chararacters output TIME 24 time from I/O initiation to interrupt 2.2.5 Line Printer (LPT) @@ -328,7 +340,7 @@ The PDP-4 used a Type 62 printer controller, with these registers: DONE 1 device done flag SPC 1 spacing done flag BPTR 6 print buffer pointer - POS 31 position in the output file + POS 32 position in the output file TIME 24 time from I/O initiation to interrupt STOP_IOE 1 stop on I/O error LBUF[0:119] 8 line buffer @@ -344,7 +356,7 @@ registers: ENABLE 1 interrupt enable (PDP-9 only) ERR 1 error flag BPTR 7 print buffer pointer - POS 31 position in the output file + POS 32 position in the output file TIME 24 time from I/O initiation to interrupt STOP_IOE 1 stop on I/O error LBUF[0:119] 8 line buffer @@ -359,7 +371,7 @@ The PDP-15 used an LP15 printer controller, with these registers: ENABLE 1 interrupt enable LCNT 8 line counter BPTR 7 print buffer pointer - POS 31 position in the output file + POS 32 position in the output file TIME 24 time from I/O initiation to interrupt STOP_IOE 1 stop on I/O error LBUF[0:131] 8 line buffer @@ -395,7 +407,7 @@ The second terminal performs input and output through a Telnet session connected to a user-specified port. The ATTACH command specifies the port to be used: - ATTACH TTI1 (cr) -- set up listening port + ATTACH TTI1 set up listening port where port is a decimal number between 1 and 65535 that is not being used for other TCP/IP activities. @@ -410,8 +422,9 @@ converts lower case input to upper case. The second terminal output also has one option, UC; when set, it suppresses lower case output (so that ALTMODE is not echoed as }). -The SHOW TTI1 LINESTATUS command displays the current connection to the -second terminal. +The SHOW TTI1 CONNECTIONS command displays the current connection to TTI1. +The SHOW TTI1 STATISTICS command displays statistics for the current connection. +The SET TTI1 DISCONNECT{=0} disconnects the current connection. The second terminal input implements these registers: @@ -420,7 +433,6 @@ The second terminal input implements these registers: BUF 8 last data item processed INT 1 interrupt pending flag DONE 1 device done flag - POS 31 number of characters input TIME 24 keyboard polling interval The second terminal output implements these registers: @@ -430,7 +442,6 @@ The second terminal output implements these registers: BUF 8 last data item processed INT 1 interrupt pending flag DONE 1 device done flag - POS 31 number of chararacters output TIME 24 time from I/O initiation to interrupt 2.3 RP15/RP02 Disk Pack (RP) @@ -438,9 +449,9 @@ The second terminal output implements these registers: RP15 options include the ability to make units write enabled or write locked: SET RPn LOCKED set unit n write locked - SET RPn ENABLED set unit n write enabled + SET RPn WRITEENABLED set unit n write enabled -Units can also be REMOVEd or ADDed to the configuration. +Units can also be set ONLINE or OFFLINE. The RP15 implements these registers: @@ -524,23 +535,29 @@ Error handling is as follows: RF15/RF09 data files are buffered in memory; therefore, end of file and OS I/O errors cannot occur. -2.6 TC02/TU55 and TC15/TU56 DECtape (DT) +2.6 Type 550/555, TC02/TU55, and TC15/TU56 DECtape (DT) + +The PDP-7 used the Type 550 DECtape, a programmed I/O controller. The +PDP-9 used the TC02, and the PDP-15 used the TC15. The TC02 and TC15 were +DMA controllers and programmatically identical. PDP-7 DECtape format had +4 18b words in its block headers and trailers; PDP-9/15 DECtape format +had 5 18b words. DECtapes drives are numbered 1-8; in the simulator, drive 8 is unit 0. DECtape options include the ability to make units write enabled or write locked. + SET DTn WRITEENABLED set unit n write enabled SET DTn LOCKED set unit n write locked - SET DTn ENABLED set unit n write enabled -Units can also be REMOVEd or ADDed to the configuration. +Units can also be set ONLINE or OFFLINE. -The TC02/TC15 supports both PDP-8 format and PDP-9/11/15 format DECtape -images. ATTACH tries to determine the tape format from the DECtape image; -the user can force a particular format with switches: +The Type 550, TC02, and TC15 support both PDP-8 format and PDP-9/11/15 +format DECtape images. ATTACH tries to determine the tape format from +the DECtape image; the user can force a particular format with switches: - -f foreign (PDP-8) format - -n native (PDP-9/11/15) format + -f foreign (PDP-8) format + -n native (PDP-9/11/15) format The DECtape controller is a data-only simulator; the timing and mark track, and block header and trailer, are not stored. Thus, the WRITE @@ -550,22 +567,24 @@ WRITE ALL function dumps non-data words into the bit bucket. The DECtape controller implements these registers: - name size comments + system name size comments - DTSA 12 status register A - DTSB 12 status register B - INT 1 interrupt pending flag - ENB 1 interrupt enable flag - DTF 1 DECtape flag - ERF 1 error flag - CA 18 current address (memory location 30) - WC 18 word count (memory location 31) - LTIME 31 time between lines - ACTIME 31 time to accelerate to full speed - DCTIME 31 time to decelerate to a full stop - SUBSTATE 2 read/write command substate - POS[0:7] 31 position, in lines, units 0-7 - STATT[0:7] 31 unit state, units 0-7 + all DTSA 12 status register A + all DTSB 12 status register B + all DTDB 18 data buffer + all INT 1 interrupt pending flag + 9,15 ENB 1 interrupt enable flag + all DTF 1 DECtape flag + 7 BEF 1 block end flag + all ERF 1 error flag + 9,15 CA 18 current address (memory location 30) + 9,15 WC 18 word count (memory location 31) + all LTIME 31 time between lines + all ACTIME 31 time to accelerate to full speed + all DCTIME 31 time to decelerate to a full stop + all SUBSTATE 2 read/write command substate + all POS[0:7] 32 position, in lines, units 0-7 + all STATT[0:7] 18 unit state, units 0-7 It is critically important to maintain certain timing relationships among the DECtape parameters, or the DECtape simulator will fail to @@ -581,9 +600,9 @@ Magnetic tape options include the ability to make units write enabled or or write locked. SET MTn LOCKED set unit n write locked - SET MTn ENABLED set unit n write enabled + SET MTn WRITEENABLED set unit n write enabled -Units can also be REMOVEd or ADDed to the configuration. +Units can also be set ONLINE or OFFLINE. The magnetic tape controller implements these registers: @@ -597,7 +616,7 @@ The magnetic tape controller implements these registers: STOP_IOE 1 stop on I/O error TIME 24 record delay UST[0:7] 24 unit status, units 0-7 - POS[0:7] 31 position, units 0-7 + POS[0:7] 32 position, units 0-7 Error handling is as follows: diff --git a/PDP18B/pdp18b_drm.c b/PDP18B/pdp18b_drm.c index 8e0ced38..08fcddf3 100644 --- a/PDP18B/pdp18b_drm.c +++ b/PDP18B/pdp18b_drm.c @@ -1,6 +1,6 @@ /* pdp18b_drm.c: drum/fixed head disk simulator - Copyright (c) 1993-2001, Robert M Supnik + Copyright (c) 1993-2002, Robert M Supnik Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), @@ -26,6 +26,8 @@ drm (PDP-7) Type 24 serial drum (PDP-9) RM09 serial drum + 03-Feb-02 RMS Fixed bug in reset routine (found by Robert Alan Byer) + 06-Jan-02 RMS Revised enable/disable support 25-Nov-01 RMS Revised interrupt structure 10-Jun-01 RMS Cleaned up IOT decoding to reflect hardware 26-Apr-01 RMS Added device enable/disable support @@ -87,11 +89,16 @@ REG drm_reg[] = { { ORDATA (WLK, drm_wlk, 32) }, { DRDATA (TIME, drm_time, 24), REG_NZ + PV_LEFT }, { FLDATA (STOP_IOE, drm_stopioe, 0) }, - { FLDATA (*DEVENB, dev_enb, INT_V_DRM), REG_HRO }, + { FLDATA (*DEVENB, dev_enb, ENB_V_DRM), REG_HRO }, { NULL } }; +MTAB drm_mod[] = { + { MTAB_XTD|MTAB_VDV, ENB_DRM, NULL, "ENABLED", &set_enb }, + { MTAB_XTD|MTAB_VDV, ENB_DRM, NULL, "DISABLED", &set_dsb }, + { 0 } }; + DEVICE drm_dev = { - "DRM", &drm_unit, drm_reg, NULL, + "DRM", &drm_unit, drm_reg, drm_mod, 1, 8, 20, 1, 8, 18, NULL, NULL, &drm_reset, &drm_boot, NULL, NULL }; @@ -172,7 +179,7 @@ return SCPE_OK; t_stat drm_reset (DEVICE *dptr) { -drm_ma = drm_ma = drm_err = 0; +drm_da = drm_ma = drm_err = 0; CLR_INT (DRM); /* clear done */ sim_cancel (&drm_unit); return SCPE_OK; diff --git a/PDP18B/pdp18b_dt.c b/PDP18B/pdp18b_dt.c index ed95478d..6a78dd85 100644 --- a/PDP18B/pdp18b_dt.c +++ b/PDP18B/pdp18b_dt.c @@ -1,6 +1,6 @@ -/* pdp18b_dt.c: PDP-9/15 DECtape simulator +/* pdp18b_dt.c: PDP-7/9/15 DECtape simulator - Copyright (c) 1993-2001, Robert M Supnik + Copyright (c) 1993-2002, Robert M Supnik Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), @@ -23,9 +23,13 @@ be used in advertising or otherwise to promote the sale, use or other dealings in this Software without prior written authorization from Robert M Supnik. - dt (PDP-9) TC02/TU55 DECtape + dt (PDP-7) Type 550/555 DECtape + (PDP-9) TC02/TU55 DECtape (PDP-15) TC15/TU56 DECtape + 30-May-02 RMS Widened POS to 32b + 10-Feb-02 RMS Added PDP-7 support + 06-Jan-02 RMS Revised enable/disable support 29-Nov-01 RMS Added read only unit support 25-Nov-01 RMS Revised interrupt structure Changed POS, STATT, LASTT, FLG to arrays @@ -53,7 +57,9 @@ A block consists of five 18b header words, a tape-specific number of data words, and five 18b trailer words. All systems except the PDP-8 use a standard block length of 256 words; the PDP-8 uses a standard block length - of 86 words (x 18b = 129 words x 12b). + of 86 words (x 18b = 129 words x 12b). [A PDP-7 DECtape has only four 18b + header words; for consistency, the PDP-7 uses the same format as the PDP-9 + and PDP-15 but skips the missing header words.] Because a DECtape file only contains data, the simulator cannot support write timing and mark track and can only do a limited implementation @@ -142,6 +148,7 @@ /* Status register A */ +#if defined (PDP9) || defined (PDP15) /* TC02/TC15 */ #define DTA_V_UNIT 15 /* unit select */ #define DTA_M_UNIT 07 #define DTA_UNIT (DTA_M_UNIT << DTA_V_UNIT) @@ -167,6 +174,33 @@ #define DTA_CERF (1u << DTA_V_CERF) #define DTA_CDTF (1u << DTA_V_CDTF) #define DTA_RW (0777700 & ~(DTA_CERF | DTA_CDTF)) +#define DT_UPDINT if ((dtsa & DTA_ENB) && (dtsb & (DTB_ERF | DTB_DTF))) \ + SET_INT (DTA); \ + else CLR_INT (DTA); + +#else /* Type 550 */ +#define DTA_V_UNIT 12 /* unit select */ +#define DTA_M_UNIT 07 +#define DTA_UNIT (DTA_M_UNIT << DTA_V_UNIT) +#define DTA_V_MOT 4 /* motion */ +#define DTA_M_MOT 03 +#define DTA_V_FNC 0 /* function */ +#define DTA_M_FNC 07 +#define FNC_MOVE 00 /* move */ +#define FNC_SRCH 01 /* search */ +#define FNC_READ 02 /* read */ +#define FNC_WRIT 03 /* write */ +#define FNC_RALL 05 /* read all */ +#define FNC_WALL 06 /* write all */ +#define FNC_WMRK 07 /* write timing */ +#define DTA_STSTP (1u << (DTA_V_MOT + 1)) +#define DTA_FWDRV (1u << DTA_V_MOT) +#define DTA_MODE 0 /* not implemented */ +#define DTA_RW 077 +#define DT_UPDINT if (dtsb & (DTB_DTF | DTB_BEF | DTB_ERF)) \ + SET_INT (DTA); \ + else CLR_INT (DTA); +#endif #define DTA_GETUNIT(x) (((x) >> DTA_V_UNIT) & DTA_M_UNIT) #define DTA_GETMOT(x) (((x) >> DTA_V_MOT) & DTA_M_MOT) @@ -174,6 +208,7 @@ /* Status register B */ +#if defined (PDP9) || defined (PDP15) /* TC02/TC15 */ #define DTB_V_ERF 17 /* error flag */ #define DTB_V_MRK 16 /* mark trk err */ #define DTB_V_END 15 /* end zone err */ @@ -191,6 +226,28 @@ #define DTB_ALLERR (DTB_ERF | DTB_MRK | DTB_END | DTB_SEL | \ DTB_PAR | DTB_TIM) +#else /* Type 550 */ +#define DTB_V_DTF 17 /* data flag */ +#define DTB_V_BEF 16 /* block end flag */ +#define DTB_V_ERF 15 /* error flag */ +#define DTB_V_END 14 /* end of tape */ +#define DTB_V_TIM 13 /* timing err */ +#define DTB_V_REV 12 /* reverse */ +#define DTB_V_GO 11 /* go */ +#define DTB_V_MRK 10 /* mark trk err */ +#define DTB_V_SEL 9 /* select err */ +#define DTB_DTF (1u << DTB_V_DTF) +#define DTB_BEF (1u << DTB_V_BEF) +#define DTB_ERF (1u << DTB_V_ERF) +#define DTB_END (1u << DTB_V_END) +#define DTB_TIM (1u << DTB_V_TIM) +#define DTB_REV (1u << DTB_V_REV) +#define DTB_GO (1u << DTB_V_GO) +#define DTB_MRK (1u << DTB_V_MRK) +#define DTB_SEL (1u << DTB_V_SEL) +#define DTB_ALLERR (DTB_END | DTB_TIM | DTB_MRK | DTB_SEL) +#endif + /* DECtape state */ #define DTS_V_MOT 3 /* motion */ @@ -230,9 +287,6 @@ #define LOG_RA 004 /* read all */ #define LOG_BL 010 /* block # lblk */ -#define DT_UPDINT if ((dtsa & DTA_ENB) && (dtsb & (DTB_ERF | DTB_DTF))) \ - SET_INT (DTA); \ - else CLR_INT (DTA); #define ABS(x) (((x) < 0)? (-(x)): (x)) extern int32 M[]; @@ -241,6 +295,7 @@ extern UNIT cpu_unit; extern int32 sim_switches; int32 dtsa = 0; /* status A */ int32 dtsb = 0; /* status B */ +int32 dtdb = 0; /* data buffer */ int32 dt_ltime = 12; /* interline time */ int32 dt_actime = 54000; /* accel time */ int32 dt_dctime = 72000; /* decel time */ @@ -289,21 +344,29 @@ UNIT dt_unit[] = { UNIT_ROABLE, DT_CAPAC) } }; REG dt_reg[] = { - { GRDATA (DTSA, dtsa, 8, 12, 6) }, - { GRDATA (DTSB, dtsb, 8, 12, 6) }, + { ORDATA (DTSA, dtsa, 18) }, + { ORDATA (DTSB, dtsb, 18) }, + { ORDATA (DTDB, dtdb, 18) }, { FLDATA (INT, int_hwre[API_DTA], INT_V_DTA) }, +#if defined (DTA_V_ENB) { FLDATA (ENB, dtsa, DTA_V_ENB) }, +#endif { FLDATA (DTF, dtsb, DTB_V_DTF) }, +#if defined (DTB_V_BEF) + { FLDATA (BEF, dtsb, DTB_V_BEF) }, +#endif { FLDATA (ERF, dtsb, DTB_V_ERF) }, +#if defined (PDP9) || defined (PDP15) { ORDATA (WC, M[DT_WC], 18) }, { ORDATA (CA, M[DT_CA], 18) }, +#endif { DRDATA (LTIME, dt_ltime, 31), REG_NZ }, { DRDATA (ACTIME, dt_actime, 31), REG_NZ }, { DRDATA (DCTIME, dt_dctime, 31), REG_NZ }, { ORDATA (SUBSTATE, dt_substate, 2) }, { ORDATA (LOG, dt_log, 4), REG_HIDDEN }, { DRDATA (LBLK, dt_logblk, 12), REG_HIDDEN }, - { URDATA (POS, dt_unit[0].pos, 10, 31, 0, + { URDATA (POS, dt_unit[0].pos, 10, 32, 0, DT_NUMDR, PV_LEFT | REG_RO) }, { URDATA (STATT, dt_unit[0].STATE, 8, 18, 0, DT_NUMDR, REG_RO) }, @@ -311,14 +374,16 @@ REG dt_reg[] = { DT_NUMDR, REG_HRO) }, { URDATA (FLG, dt_unit[0].flags, 8, UNIT_W_UF, UNIT_V_UF - 1, DT_NUMDR, REG_HRO) }, - { FLDATA (*DEVENB, dev_enb, INT_V_DTA), REG_HRO }, + { FLDATA (*DEVENB, dev_enb, ENB_V_DTA), REG_HRO }, { NULL } }; MTAB dt_mod[] = { - { UNIT_WLK, 0, "write enabled", "ENABLED", NULL }, + { UNIT_WLK, 0, "write enabled", "WRITEENABLED", NULL }, { UNIT_WLK, UNIT_WLK, "write locked", "LOCKED", NULL }, { UNIT_8FMT, 0, "16b/18b", NULL, NULL }, { UNIT_8FMT, UNIT_8FMT, "12b", NULL, NULL }, + { MTAB_XTD|MTAB_VDV, ENB_DTA, NULL, "ENABLED", &set_enb }, + { MTAB_XTD|MTAB_VDV, ENB_DTA, NULL, "DISABLED", &set_dsb }, { 0 } }; DEVICE dt_dev = { @@ -329,6 +394,7 @@ DEVICE dt_dev = { /* IOT routines */ +#if defined (PDP9) || defined (PDP15) int32 dt75 (int32 pulse, int32 AC) { int32 old_dtsa = dtsa, fnc; @@ -367,6 +433,59 @@ if ((pulse & 01) && (dtsb & DTB_DTF)) /* DTDF */ return IOT_SKP + AC; return AC; } + +#else +int32 dt75 (int32 pulse, int32 AC) +{ +int32 old_dtsa = dtsa; + +if (((pulse & 041) == 001) && (dtsb & DTB_DTF)) /* MMDF */ + AC = AC | IOT_SKP; +else if (((pulse & 041) == 041) && (dtsb & DTB_ERF)) /* MMEF */ + AC = AC | IOT_SKP; +if (pulse & 002) { /* MMRD */ + AC = (AC & ~DMASK) | dtdb; + dtsb = dtsb & ~(DTB_DTF | DTB_BEF); } +if (pulse & 004) { /* MMWR */ + dtdb = AC & DMASK; + dtsb = dtsb & ~(DTB_DTF | DTB_BEF); } +DT_UPDINT; +return AC; +} + +int32 dt76 (int32 pulse, int32 AC) +{ +int32 fnc, mot; +UNIT *uptr; + +uptr = dt_dev.units + DTA_GETUNIT (dtsa); /* get unit */ +if ((pulse & 001) && (dtsb & DTB_BEF)) /* MMBF */ + AC = AC | IOT_SKP; +if (pulse & 002) { /* MMRS */ + dtsb = dtsb & ~(DTB_REV | DTB_GO); /* clr rev, go */ + mot = DTS_GETMOT (uptr -> STATE); /* get motion */ + if (mot & DTS_DIR) dtsb = dtsb | DTB_REV; /* rev? set */ + if ((mot >= DTS_ACCF) || (uptr -> STATE & 0777700)) + dtsb = dtsb | DTB_GO; /* accel? go */ + AC = (AC & ~DMASK) | dtsb; } +if ((pulse & 044) == 044) { /* MMSE */ + if ((dtsa ^ AC) & DTA_UNIT) dt_deselect (dtsa); /* new unit? */ + dtsa = (dtsa & ~DTA_UNIT) | (AC & DTA_UNIT); + dtsb = dtsb & ~(DTB_DTF | DTB_BEF | DTB_ERF | DTB_ALLERR); } +else if ((pulse & 044) == 004) { /* MMLC */ + dtsa = (dtsa & ~DTA_RW) | (AC & DTA_RW); /* load dtsa */ + dtsb = dtsb & ~(DTB_DTF | DTB_BEF | DTB_ERF | DTB_ALLERR); + fnc = DTA_GETFNC (dtsa); /* get fnc */ + if (((uptr -> flags) & UNIT_DIS) || /* disabled? */ + (fnc >= FNC_WMRK) || /* write mark? */ + ((fnc == FNC_WRIT) && (uptr -> flags & UNIT_WLK)) || + ((fnc == FNC_WALL) && (uptr -> flags & UNIT_WLK))) + dt_seterr (uptr, DTB_SEL); /* select err */ + else dt_newsa (dtsa); } +DT_UPDINT; +return AC; +} +#endif /* Unit deselect */ @@ -380,7 +499,8 @@ if (old_mot >= DTS_ATSF) /* at speed? */ dt_newfnc (uptr, DTS_STA (old_mot, DTS_OFR)); else if (old_mot >= DTS_ACCF) /* accelerating? */ DTS_SET2ND (DTS_ATSF | (old_mot & DTS_DIR), DTS_OFR); -return; } +return; +} /* Command register change @@ -518,6 +638,7 @@ case FNC_SRCH: /* search */ break; case FNC_WRIT: /* write */ case FNC_READ: /* read */ +#if defined (PDP9) || defined (PDP15) if (DT_QEZ (uptr)) { /* in "ok" end zone? */ if (dir) newpos = DTU_FWDEZ (uptr) - DT_HTLIN - DT_WSIZE; else newpos = DT_EZLIN + DT_HTLIN + (DT_WSIZE - 1); @@ -532,6 +653,7 @@ case FNC_READ: /* read */ else newpos = DT_BLK2LN (((relpos < DT_HTLIN)? blk: blk + 1), uptr) + DT_HTLIN + (DT_WSIZE - 1); break; +#endif case FNC_RALL: /* read all */ case FNC_WALL: /* write all */ if (DT_QEZ (uptr)) { /* in "ok" end zone? */ @@ -547,6 +669,11 @@ case FNC_WALL: /* write all */ default: dt_seterr (uptr, DTB_SEL); /* bad state */ return; } +#if defined (PDP7) +if ((fnc == FNC_WRIT) || (fnc == FNC_WALL)) { /* write function? */ + dtsb = dtsb | DTB_DTF; /* set data flag */ + DT_UPDINT; } +#endif sim_activate (uptr, ABS (newpos - ((int32) uptr -> pos)) * dt_ltime); return; } @@ -619,7 +746,7 @@ int32 dir = mot & DTS_DIR; int32 fnc = DTS_GETFNC (uptr -> STATE); int32 *bptr = uptr -> filebuf; int32 unum = uptr - dt_dev.units; -int32 blk, wrd, ma, relpos, dat; +int32 blk, wrd, ma, relpos; t_addr ba; /* Motion cases @@ -661,6 +788,15 @@ switch (fnc) { /* at speed, check fnc */ case FNC_MOVE: /* move */ dt_seterr (uptr, DTB_END); /* end zone error */ return SCPE_OK; +case DTS_OFR: /* off reel */ + detach_unit (uptr); /* must be deselected */ + uptr -> STATE = uptr -> pos = 0; /* no visible action */ + break; + +/* TC02/TC15 service */ +/* Search */ + +#if defined (PDP9) || defined (PDP15) case FNC_SRCH: /* search */ if (dtsb & DTB_DTF) { /* DTF set? */ dt_seterr (uptr, DTB_TIM); /* timing error */ @@ -672,11 +808,7 @@ case FNC_SRCH: /* search */ if (((dtsa & DTA_MODE) == 0) || (M[DT_WC] == 0)) dtsb = dtsb | DTB_DTF; /* set DTF */ break; -case DTS_OFR: /* off reel */ - detach_unit (uptr); /* must be deselected */ - uptr -> STATE = uptr -> pos = 0; /* no visible action */ - break; - + /* Read has four subcases Start of block, not wc ovf - check that DTF is clear, otherwise normal @@ -707,9 +839,9 @@ case FNC_READ: /* read */ M[DT_CA] = (M[DT_CA] + 1) & DMASK; ma = M[DT_CA] & ADDRMASK; /* mem addr */ ba = (blk * DTU_BSIZE (uptr)) + wrd; /* buffer ptr */ - dat = bptr[ba]; /* get tape word */ - if (dir) dat = dt_comobv (dat); /* rev? comp obv */ - if (MEM_ADDR_OK (ma)) M[ma] = dat; /* mem addr legal? */ + dtdb = bptr[ba]; /* get tape word */ + if (dir) dtdb = dt_comobv (dtdb); /* rev? comp obv */ + if (MEM_ADDR_OK (ma)) M[ma] = dtdb; /* mem addr legal? */ if (M[DT_WC] == 0) dt_substate = DTO_WCO; /* wc ovf? */ case DTO_WCO: /* wc ovf, not sob */ if (wrd != (dir? 0: DTU_BSIZE (uptr) - 1)) /* not last? */ @@ -756,9 +888,9 @@ case FNC_WRIT: /* write */ case DTO_WCO: /* wc ovflo */ ma = M[DT_CA] & ADDRMASK; /* mem addr */ ba = (blk * DTU_BSIZE (uptr)) + wrd; /* buffer ptr */ - dat = dt_substate? 0: M[ma]; /* get word */ - if (dir) dat = dt_comobv (dat); /* rev? comp obv */ - bptr[ba] = dat; /* write word */ + dtdb = dt_substate? 0: M[ma]; /* get word */ + if (dir) dtdb = dt_comobv (dtdb); /* rev? comp obv */ + bptr[ba] = dtdb; /* write word */ if (ba >= uptr -> hwmark) uptr -> hwmark = ba + 1; if (M[DT_WC] == 0) dt_substate = DTO_WCO; if (wrd != (dir? 0: DTU_BSIZE (uptr) - 1)) /* not last? */ @@ -793,11 +925,11 @@ case FNC_RALL: (relpos < (DTU_LPERB (uptr) - DT_HTLIN))) { wrd = DT_LIN2WD (uptr -> pos, uptr); ba = (blk * DTU_BSIZE (uptr)) + wrd; - dat = bptr[ba]; } /* get tape word */ - else dat = dt_gethdr (uptr, blk, relpos); /* get hdr */ - if (dir) dat = dt_comobv (dat); /* rev? comp obv */ + dtdb = bptr[ba]; } /* get tape word */ + else dtdb = dt_gethdr (uptr, blk, relpos); /* get hdr */ + if (dir) dtdb = dt_comobv (dtdb); /* rev? comp obv */ sim_activate (uptr, DT_WSIZE * dt_ltime); - if (MEM_ADDR_OK (ma)) M[ma] = dat; /* mem addr legal? */ + if (MEM_ADDR_OK (ma)) M[ma] = dtdb; /* mem addr legal? */ if (M[DT_WC] == 0) dt_substate = DTO_WCO; if (((dtsa & DTA_MODE) == 0) || (M[DT_WC] == 0)) dtsb = dtsb | DTB_DTF; /* set DTF */ @@ -825,11 +957,11 @@ case FNC_WALL: ma = M[DT_CA] & ADDRMASK; /* mem addr */ if ((relpos >= DT_HTLIN) && /* in data zone? */ (relpos < (DTU_LPERB (uptr) - DT_HTLIN))) { - dat = M[ma]; /* get mem word */ - if (dir) dat = dt_comobv (dat); + dtdb = M[ma]; /* get mem word */ + if (dir) dtdb = dt_comobv (dtdb); wrd = DT_LIN2WD (uptr -> pos, uptr); ba = (blk * DTU_BSIZE (uptr)) + wrd; - bptr[ba] = dat; /* write word */ + bptr[ba] = dtdb; /* write word */ if (ba >= uptr -> hwmark) uptr -> hwmark = ba + 1; } /* /* ignore hdr */ sim_activate (uptr, DT_WSIZE * dt_ltime); @@ -841,6 +973,76 @@ case FNC_WALL: dt_schedez (uptr, dir); /* sched end zone */ break; } /* end case substate */ break; + +/* Type 550 service */ +/* Search */ + +#else +case FNC_SRCH: /* search */ + if (dtsb & DTB_DTF) { /* DTF set? */ + dt_seterr (uptr, DTB_TIM); /* timing error */ + return SCPE_OK; } + sim_activate (uptr, DTU_LPERB (uptr) * dt_ltime);/* sched next block */ + dtdb = blk; /* store block # */ + dtsb = dtsb | DTB_DTF; /* set DTF */ + break; + +/* Read and read all */ + +case FNC_READ: case FNC_RALL: + if (dtsb & DTB_DTF) { /* DTF set? */ + dt_seterr (uptr, DTB_TIM); /* timing error */ + return SCPE_OK; } + sim_activate (uptr, DT_WSIZE * dt_ltime); /* sched next word */ + relpos = DT_LIN2OF (uptr -> pos, uptr); /* cur pos in blk */ + if ((relpos >= DT_HTLIN) && /* in data zone? */ + (relpos < (DTU_LPERB (uptr) - DT_HTLIN))) { + wrd = DT_LIN2WD (uptr -> pos, uptr); + ba = (blk * DTU_BSIZE (uptr)) + wrd; + dtdb = bptr[ba]; /* get tape word */ + dtsb = dtsb | DTB_DTF; } /* set flag */ + else { ma = (2 * DT_HTWRD) + DTU_BSIZE (uptr) - DT_CSMWD - 1; + wrd = relpos / DT_WSIZE; /* hdr start = wd 0 */ + if ((wrd == 0) || /* skip 1st, last */ + (wrd == ((2 * DT_HTWRD) + DTU_BSIZE (uptr) - 1))) break; + if ((fnc == FNC_READ) && /* read, skip if not */ + (wrd != DT_CSMWD) && /* fwd, rev cksum */ + (wrd != ma)) break; + dtdb = dt_gethdr (uptr, blk, relpos); + if (wrd == (dir? DT_CSMWD: ma)) /* at end csum? */ + dtsb = dtsb | DTB_BEF; /* end block */ + else dtsb = dtsb | DTB_DTF; } /* else next word */ + if (dir) dtdb = dt_comobv (dtdb); + break; + +/* Write and write all */ + +case FNC_WRIT: case FNC_WALL: + if (dtsb & DTB_DTF) { /* DTF set? */ + dt_seterr (uptr, DTB_TIM); /* timing error */ + return SCPE_OK; } + sim_activate (uptr, DT_WSIZE * dt_ltime); /* sched next word */ + relpos = DT_LIN2OF (uptr -> pos, uptr); /* cur pos in blk */ + if ((relpos >= DT_HTLIN) && /* in data zone? */ + (relpos < (DTU_LPERB (uptr) - DT_HTLIN))) { + wrd = DT_LIN2WD (uptr -> pos, uptr); + ba = (blk * DTU_BSIZE (uptr)) + wrd; + if (dir) bptr[ba] = dt_comobv (dtdb); /* get data word */ + else bptr[ba] = dtdb; + if (ba >= uptr -> hwmark) uptr -> hwmark = ba + 1; + if (wrd == (dir? 0: DTU_BSIZE (uptr) - 1)) + dtsb = dtsb | DTB_BEF; /* end block */ + else dtsb = dtsb | DTB_DTF; } /* else next word */ + else { wrd = relpos / DT_WSIZE; /* hdr start = wd 0 */ + if ((wrd == 0) || /* skip 1st, last */ + (wrd == ((2 * DT_HTWRD) + DTU_BSIZE (uptr) - 1))) break; + if ((fnc == FNC_WRIT) && /* wr, skip if !csm */ + (wrd != ((2 * DT_HTWRD) + DTU_BSIZE (uptr) - DT_CSMWD - 1))) + break; + dtsb = dtsb | DTB_DTF; } /* set flag */ + break; +#endif + default: dt_seterr (uptr, DTB_SEL); /* impossible state */ break; } @@ -898,11 +1100,20 @@ int32 *bptr = uptr -> filebuf; int32 ba = blk * DTU_BSIZE (uptr); int32 i, csum, wrd; +#if defined (PDP9) || defined (PDP15) csum = 077; /* init csum */ for (i = 0; i < DTU_BSIZE (uptr); i++) { /* loop thru buf */ wrd = bptr[ba + i] ^ 0777777; /* get ~word */ csum = csum ^ (wrd >> 12) ^ (wrd >> 6) ^ wrd; } return (csum & 077); +#else +csum = 0777777; +for (i = 0; i < DTU_BSIZE (uptr); i++) { /* loop thru buf */ + wrd = bptr[ba + i]; /* get word */ + csum = csum + wrd; /* 1's comp add */ + if (csum > 0777777) csum = (csum + 1) & 0777777; } +return (csum ^ 0777777); /* 1's comp res */ +#endif } /* Get header word */ @@ -912,8 +1123,14 @@ int32 dt_gethdr (UNIT *uptr, int32 blk, int32 relpos) int32 wrd = relpos / DT_WSIZE; if (wrd == DT_BLKWD) return blk; /* fwd blknum */ +#if defined (PDP9) || defined (PDP15) if (wrd == (2 * DT_HTWRD + DTU_BSIZE (uptr) - DT_CSMWD - 1)) /* fwd csum */ return (dt_csum (uptr, blk) << 12); +#else +if (wrd == DT_CSMWD) return 0777777; /* rev csum */ +if (wrd == (2 * DT_HTWRD + DTU_BSIZE (uptr) - DT_CSMWD - 1)) /* fwd csum */ + return (dt_csum (uptr, blk)); +#endif if (wrd == (2 * DT_HTWRD + DTU_BSIZE (uptr) - DT_BLKWD - 1)) /* rev blkno */ return dt_comobv (blk); return 0; /* all others */ @@ -948,7 +1165,11 @@ return SCPE_OK; int32 dt_iors (void) { +#if defined IOS_DTA return ((dtsb & (DTB_ERF | DTB_DTF))? IOS_DTA: 0); +#else +return 0; +#endif } /* Attach routine @@ -991,8 +1212,8 @@ if (uptr -> flags & UNIT_8FMT) { /* PDP-8? */ for (k = 0; k < D8_NBSIZE; k = k + 3) { /* loop thru blk */ bptr[ba] = ((uint32) (pdp8b[k] & 07777) << 6) | ((uint32) (pdp8b[k + 1] >> 6) & 077); - bptr[ba + 1] = ((pdp8b[k + 1] & 077) << 12) | - ((uint32) (pdp8b[k + 2] & 07777)); + bptr[ba + 1] = ((uint32) (pdp8b[k + 1] & 077) << 12) | + (pdp8b[k + 2] & 07777); ba = ba + 2; } /* end blk loop */ } /* end file loop */ uptr -> hwmark = ba; } /* end if */ diff --git a/PDP18B/pdp18b_lp.c b/PDP18B/pdp18b_lp.c index 90652f5d..8e14d6d8 100644 --- a/PDP18B/pdp18b_lp.c +++ b/PDP18B/pdp18b_lp.c @@ -1,6 +1,6 @@ /* pdp18b_lp.c: 18b PDP's line printer simulator - Copyright (c) 1993-2001, Robert M Supnik + Copyright (c) 1993-2002, Robert M Supnik Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), @@ -27,6 +27,8 @@ (PDP-7,9) Type 647 line printer (PDP-15) LP15 line printer + 30-May-02 RMS Widened POS to 32b + 03-Feb-02 RMS Fixed typo (found by Robert Alan Byer) 25-Nov-01 RMS Revised interrupt structure 19-Sep-01 RMS Fixed bug in 647 13-Feb-01 RMS Revised for register arrays @@ -67,7 +69,7 @@ REG lpt_reg[] = { { FLDATA (SPC, int_hwre[API_LPTSPC], INT_V_LPTSPC) }, { DRDATA (BPTR, bptr, 6) }, { ORDATA (STATE, lpt_iot, 6), REG_HRO }, - { DRDATA (POS, lpt_unit.pos, 31), PV_LEFT }, + { DRDATA (POS, lpt_unit.pos, 32), PV_LEFT }, { DRDATA (TIME, lpt_unit.wait, 24), PV_LEFT }, { FLDATA (STOP_IOE, lpt_stopioe, 0) }, { BRDATA (LBUF, lpt_buf, 8, 8, LPT_BSIZE) }, @@ -91,27 +93,25 @@ static const char lpt_trans[64] = { 'o','J','K','L','M','N','O','P','Q','R','$','=','-',')','-','(', '_','A','B','C','D','E','F','G','H','I','*','.','+',']','|','[' }; -if (pulse == 001) return (TST_INT (LPT))? IOT_SKP + AC: AC; /* LPSF */ -if (pulse == 002) CLR_INT (LPT); /* LPCF */ -else if (pulse == 042) { /* LPLD */ - if (bptr < BPTR_MAX) { /* limit test ptr */ - i = bptr * 3; /* cvt to chr ptr */ - lpt_buf[i++] = lpt_trans[(AC >> 12) & 077]; - lpt_buf[i++] = lpt_trans[(AC >> 6) & 077]; - lpt_buf[i++] = lpt_trans[AC & 077]; } +if ((pulse & 001) && TST_INT (LPT)) AC = IOT_SKP | AC; /* LPSF */ +if ((pulse & 042) == 002) CLR_INT (LPT); /* LPCF */ +if (((pulse & 042) == 042) && (bptr < BPTR_MAX)) { /* LPLD */ + i = bptr * 3; /* cvt to chr ptr */ + lpt_buf[i++] = lpt_trans[(AC >> 12) & 077]; + lpt_buf[i++] = lpt_trans[(AC >> 6) & 077]; + lpt_buf[i++] = lpt_trans[AC & 077]; bptr = (bptr + 1) & BPTR_MASK; } -else if (pulse == 006) { /* LPSE */ - CLR_INT (LPT); /* clear flag */ +if (pulse & 004) { /* LPSE */ sim_activate (&lpt_unit, lpt_unit.wait); } /* activate */ return AC; } int32 lpt66 (int32 pulse, int32 AC) { -if (pulse == 001) return (TST_INT (LPTSPC))? IOT_SKP + AC: AC; /* LSSF */ +if ((pulse & 001) && TST_INT (LPTSPC)) /* LSSF */ + AC = IOT_SKP | AC; if (pulse & 002) CLR_INT (LPTSPC); /* LSCF */ if (pulse & 004) { /* LSPR */ - CLR_INT (LPTSPC); /* clear flag */ lpt_iot = 020 | (AC & 07); /* space, no print */ sim_activate (&lpt_unit, lpt_unit.wait); } /* activate */ return AC; @@ -219,7 +219,7 @@ REG lpt_reg[] = { { FLDATA (ERR, lpt_err, 0) }, { DRDATA (BPTR, bptr, 7) }, { ORDATA (SCMD, lpt_iot, 6), REG_HRO }, - { DRDATA (POS, lpt_unit.pos, 31), PV_LEFT }, + { DRDATA (POS, lpt_unit.pos, 32), PV_LEFT }, { DRDATA (TIME, lpt_unit.wait, 24), PV_LEFT }, { FLDATA (STOP_IOE, lpt_stopioe, 0) }, { BRDATA (LBUF, lpt_buf, 8, 8, LPT_BSIZE) }, @@ -235,51 +235,62 @@ DEVICE lpt_dev = { int32 lpt65 (int32 pulse, int32 AC) { -int32 i; +int32 i, subp; -if (pulse == 001) return (lpt_done? IOT_SKP + AC: AC); /* LPSF */ +subp = (pulse >> 4) & 03; /* subcode */ +if ((pulse & 001) && lpt_done) AC = IOT_SKP | AC; /* LPSF */ if (pulse & 002) { /* pulse 02 */ lpt_done = 0; /* clear done */ - CLR_INT (LPT); } /* clear int req */ -if (pulse == 002) { /* LPCB */ - for (i = 0; i < LPT_BSIZE; i++) lpt_buf[i] = 0; - bptr = 0; /* reset buf ptr */ - lpt_done = 1; /* set done */ - if (lpt_ie) SET_INT (LPT); } /* set int */ + CLR_INT (LPT); /* clear int req */ + if (subp == 0) { /* LPCB */ + for (i = 0; i < LPT_BSIZE; i++) lpt_buf[i] = 0; + bptr = 0; /* reset buf ptr */ + lpt_done = 1; /* set done */ + if (lpt_ie) SET_INT (LPT); } } /* set int */ +if (pulse & 004) { /* LPDI */ + switch (subp) { /* case on subcode */ + case 0: /* LPDI */ #if defined (PDP9) -if (pulse == 004) { /* LPDI */ - lpt_ie = 0; /* clear int enable */ - CLR_INT (LPT); } /* clear int req */ + lpt_ie = 0; /* clear int enable */ + CLR_INT (LPT); /* clear int req */ #endif -if ((pulse == 046) && (bptr < LPT_BSIZE)) { /* LPB3 */ - lpt_buf[bptr] = lpt_buf[bptr] | ((AC >> 12) & 077); - bptr = bptr + 1; } -if (((pulse == 046) || (pulse == 026)) && (bptr < LPT_BSIZE)) { - lpt_buf[bptr] = lpt_buf[bptr] | ((AC >> 6) & 077); - bptr = bptr + 1; } -if ((pulse == 046) || (pulse == 026) || (pulse == 066)) { - if (bptr < LPT_BSIZE) { - lpt_buf[bptr] = lpt_buf[bptr] | (AC & 077); - bptr = bptr + 1; } - lpt_done = 1; /* set done */ - if (lpt_ie) SET_INT (LPT); } /* set int */ + break; + case 2: /* LPB3 */ + if (bptr < LPT_BSIZE) { + lpt_buf[bptr] = lpt_buf[bptr] | ((AC >> 12) & 077); + bptr = bptr + 1; } + case 1: /* LPB2 */ + if (bptr < LPT_BSIZE) { + lpt_buf[bptr] = lpt_buf[bptr] | ((AC >> 6) & 077); + bptr = bptr + 1; } + case 3: /* LPB1 */ + if (bptr < LPT_BSIZE) { + lpt_buf[bptr] = lpt_buf[bptr] | (AC & 077); + bptr = bptr + 1; } + lpt_done = 1; /* set done */ + if (lpt_ie) SET_INT (LPT); /* set int */ + break; } /* end case */ + } /* end if pulse 4 */ return AC; } int32 lpt66 (int32 pulse, int32 AC) { -if (pulse == 001) return (lpt_err? IOT_SKP + AC: AC); /* LPSE */ +if ((pulse & 001) && lpt_err) AC = IOT_SKP | AC; /* LPSE */ if (pulse & 002) { /* LPCF */ lpt_done = 0; /* clear done, int */ CLR_INT (LPT); } -if (((pulse & 060) < 060) && (pulse & 004)) { /* LPLS, LPPB, LPPS */ - lpt_iot = (pulse & 060) | (AC & 07); /* save parameters */ - sim_activate (&lpt_unit, lpt_unit.wait); } /* activate */ +if (pulse & 004) { + int32 subp = (pulse >> 4) & 03; /* get subpulse */ + if (subp < 3) { /* LPLS, LPPB, LPPS */ + lpt_iot = (pulse & 060) | (AC & 07); /* save parameters */ + sim_activate (&lpt_unit, lpt_unit.wait); } /* activate */ #if defined (PDP9) -if (pulse == 064) { /* LPEI */ - lpt_ie = 1; /* set int enable */ - if (lpt_done) SET_INT (LPT); } + else { /* LPEI */ + lpt_ie = 1; /* set int enable */ + if (lpt_done) SET_INT (LPT); } #endif + } /* end if pulse 4 */ return AC; } @@ -420,7 +431,7 @@ REG lpt_reg[] = { { DRDATA (LCNT, lcnt, 9) }, { DRDATA (BPTR, bptr, 8) }, { FLDATA (MODE, mode, 0) }, - { DRDATA (POS, lpt_unit.pos, 31), PV_LEFT }, + { DRDATA (POS, lpt_unit.pos, 32), PV_LEFT }, { DRDATA (TIME, lpt_unit.wait, 24), PV_LEFT }, { FLDATA (STOP_IOE, lpt_stopioe, 0) }, { BRDATA (LBUF, lpt_buf, 8, 8, LPT_BSIZE) }, @@ -459,7 +470,7 @@ return AC; int32 lpt66 (int32 pulse, int32 AC) { if (pulse == 021) lpt_sta = lpt_sta & ~STA_DON; /* LPCD */ -if (pulse == 041) lpt_sta = lpt_sta = 0; /* LPCF */ +if (pulse == 041) lpt_sta = 0; /* LPCF */ lpt_updsta (0); /* update status */ return AC; } diff --git a/PDP18B/pdp18b_mt.c b/PDP18B/pdp18b_mt.c index d9b222a9..be6ff668 100644 --- a/PDP18B/pdp18b_mt.c +++ b/PDP18B/pdp18b_mt.c @@ -1,6 +1,6 @@ /* pdp18b_mt.c: 18b PDP magnetic tape simulator - Copyright (c) 1993-2001, Robert M Supnik + Copyright (c) 1993-2002, Robert M Supnik Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), @@ -26,6 +26,9 @@ mt (PDP-9) TC59 magtape (PDP-15) TC59D magtape + 30-May-02 RMS Widened POS to 32b + 22-Apr-02 RMS Added maximum record length test + 06-Jan-02 RMS Revised enabled/disable support 29-Nov-01 RMS Added read only unit support 25-Nov-01 RMS Revised interrupt structure Changed UST, POS, FLG to arrays @@ -58,7 +61,8 @@ #define UNIT_W_UF 2 /* saved flag width */ #define USTAT u3 /* unit status */ #define UNUM u4 /* unit number */ -#define DBSIZE (1 << 12) /* max data record */ +#define MT_MAXFR (1 << 16) /* max record length */ +#define DBSIZE (1 << 12) /* max word count */ #define DBMASK (DBSIZE - 1) #define MT_WC 032 /* word count */ #define MT_CA 033 /* current addr */ @@ -153,16 +157,18 @@ REG mt_reg[] = { { FLDATA (STOP_IOE, mt_stopioe, 0) }, { DRDATA (TIME, mt_time, 24), PV_LEFT }, { URDATA (UST, mt_unit[0].USTAT, 8, 16, 0, MT_NUMDR, 0) }, - { URDATA (POS, mt_unit[0].pos, 10, 31, 0, + { URDATA (POS, mt_unit[0].pos, 10, 32, 0, MT_NUMDR, PV_LEFT | REG_RO) }, { URDATA (FLG, mt_unit[0].flags, 8, UNIT_W_UF, UNIT_V_UF - 1, MT_NUMDR, REG_HRO) }, - { FLDATA (*DEVENB, dev_enb, INT_V_MTA), REG_HRO }, + { FLDATA (*DEVENB, dev_enb, ENB_V_MTA), REG_HRO }, { NULL } }; MTAB mt_mod[] = { - { UNIT_WLK, 0, "write enabled", "ENABLED", NULL }, + { UNIT_WLK, 0, "write enabled", "WRITEENABLED", NULL }, { UNIT_WLK, UNIT_WLK, "write locked", "LOCKED", NULL }, + { MTAB_XTD|MTAB_VDV, ENB_MTA, NULL, "ENABLED", &set_enb }, + { MTAB_XTD|MTAB_VDV, ENB_MTA, NULL, "DISABLED", &set_dsb }, { 0 } }; DEVICE mt_dev = { @@ -262,6 +268,7 @@ case FN_CMPARE: /* read/compare */ uptr -> pos = uptr -> pos + sizeof (t_mtrlnt); break; } tbc = MTRL (tbc); /* ignore error flag */ + if (tbc > MT_MAXFR) return SCPE_MTRLNT; /* record too long? */ wc = DBSIZE - (M[MT_WC] & DBMASK); /* get word count */ cbc = PACKED (mt_cu)? wc * 3: wc * 2; /* expected bc */ if (tbc != cbc) mt_sta = mt_sta | STA_RLE; /* wrong size? */ diff --git a/PDP18B/pdp18b_rf.c b/PDP18B/pdp18b_rf.c index 370ead61..c85bcb2d 100644 --- a/PDP18B/pdp18b_rf.c +++ b/PDP18B/pdp18b_rf.c @@ -1,6 +1,6 @@ /* pdp18b_rf.c: fixed head disk simulator - Copyright (c) 1993-2001, Robert M Supnik + Copyright (c) 1993-2002, Robert M Supnik Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), @@ -26,6 +26,7 @@ rf (PDP-9) RF09/RF09 (PDP-15) RF15/RS09 + 06-Jan-02 RMS Revised enable/disable support 25-Nov-01 RMS Revised interrupt structure 24-Nov-01 RMS Changed WLK to array 26-Apr-01 RMS Added device enable/disable support @@ -122,11 +123,16 @@ REG rf_reg[] = { { DRDATA (TIME, rf_time, 24), PV_LEFT + REG_NZ }, { FLDATA (BURST, rf_burst, 0) }, { FLDATA (STOP_IOE, rf_stopioe, 0) }, - { FLDATA (*DEVENB, dev_enb, INT_V_RF), REG_HRO }, + { FLDATA (*DEVENB, dev_enb, ENB_V_RF), REG_HRO }, { NULL } }; +MTAB rf_mod[] = { + { MTAB_XTD|MTAB_VDV, ENB_RF, NULL, "ENABLED", &set_enb }, + { MTAB_XTD|MTAB_VDV, ENB_RF, NULL, "DISABLED", &set_dsb }, + { 0 } }; + DEVICE rf_dev = { - "RF", &rf_unit, rf_reg, NULL, + "RF", &rf_unit, rf_reg, rf_mod, 1, 8, 21, 1, 8, 18, NULL, NULL, &rf_reset, NULL, NULL, NULL }; diff --git a/PDP18B/pdp18b_rp.c b/PDP18B/pdp18b_rp.c index ffbff7bf..53294718 100644 --- a/PDP18B/pdp18b_rp.c +++ b/PDP18B/pdp18b_rp.c @@ -1,6 +1,6 @@ /* pdp18b_rp.c: RP15/RP02 disk pack simulator - Copyright (c) 1993-2001, Robert M Supnik + Copyright (c) 1993-2002, Robert M Supnik Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), @@ -25,6 +25,7 @@ rp RP15/RP02 disk pack + 06-Jan-02 RMS Revised enable/disable support 29-Nov-01 RMS Added read only unit support 25-Nov-01 RMS Revised interrupt structure Changed FLG to array @@ -176,12 +177,14 @@ REG rp_reg[] = { { DRDATA (RTIME, rp_rwait, 24), PV_LEFT }, { URDATA (FLG, rp_unit[0].flags, 8, UNIT_W_UF, UNIT_V_UF - 1, RP_NUMDR, REG_HRO) }, - { FLDATA (*DEVENB, dev_enb, INT_V_RP), REG_HRO }, + { FLDATA (*DEVENB, dev_enb, ENB_V_RP), REG_HRO }, { NULL } }; MTAB rp_mod[] = { - { UNIT_WLK, 0, "write enabled", "ENABLED", NULL }, + { UNIT_WLK, 0, "write enabled", "WRITEENABLED", NULL }, { UNIT_WLK, UNIT_WLK, "write locked", "LOCKED", NULL }, + { MTAB_XTD|MTAB_VDV, ENB_RP, NULL, "ENABLED", &set_enb }, + { MTAB_XTD|MTAB_VDV, ENB_RP, NULL, "DISABLED", &set_dsb }, { 0 } }; DEVICE rp_dev = { diff --git a/PDP18B/pdp18b_stddev.c b/PDP18B/pdp18b_stddev.c index 8d0cf67c..a9ecc1fc 100644 --- a/PDP18B/pdp18b_stddev.c +++ b/PDP18B/pdp18b_stddev.c @@ -1,6 +1,6 @@ /* pdp18b_stddev.c: 18b PDP's standard devices - Copyright (c) 1993-2001, Robert M Supnik + Copyright (c) 1993-2002, Robert M Supnik Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), @@ -29,6 +29,8 @@ tto teleprinter clk clock + 14-Jul-02 RMS Added ASCII reader/punch support (from Hans Pufal) + 30-May-02 RMS Widened POS to 32b 29-Nov-01 RMS Added read only unit support 25-Nov-01 RMS Revised interrupt structure 17-Sep-01 RMS Removed multiconsole support @@ -48,9 +50,16 @@ #include "pdp18b_defs.h" #include +#define UNIT_V_RASCII UNIT_V_UF /* reader ASCII */ +#define UNIT_RASCII (1 << UNIT_V_RASCII) +#define UNIT_V_PASCII UNIT_V_UF /* punch ASCII */ +#define UNIT_PASCII (1 << UNIT_V_PASCII) + extern int32 M[]; extern int32 int_hwre[API_HLVL+1], saved_PC; +extern int32 sim_switches; extern UNIT cpu_unit; + int32 clk_state = 0; int32 ptr_err = 0, ptr_stopioe = 0, ptr_state = 0; int32 ptp_err = 0, ptp_stopioe = 0; @@ -117,9 +126,10 @@ REG ptr_reg[] = { { FLDATA (ERR, ptr_err, 0) }, #endif { ORDATA (STATE, ptr_state, 5), REG_HRO }, - { DRDATA (POS, ptr_unit.pos, 31), PV_LEFT }, + { DRDATA (POS, ptr_unit.pos, 32), PV_LEFT }, { DRDATA (TIME, ptr_unit.wait, 24), PV_LEFT }, { FLDATA (STOP_IOE, ptr_stopioe, 0) }, + { FLDATA (ASCII, ptr_unit.flags, UNIT_V_RASCII), REG_HRO }, { NULL } }; DEVICE ptr_dev = { @@ -145,9 +155,10 @@ REG ptp_reg[] = { #if defined (IOS_PTPERR) { FLDATA (ERR, ptp_err, 0) }, #endif - { DRDATA (POS, ptp_unit.pos, 31), PV_LEFT }, + { DRDATA (POS, ptp_unit.pos, 32), PV_LEFT }, { DRDATA (TIME, ptp_unit.wait, 24), PV_LEFT }, { FLDATA (STOP_IOE, ptp_stopioe, 0) }, + { FLDATA (ASCII, ptp_unit.flags, UNIT_V_PASCII), REG_HRO }, { NULL } }; DEVICE ptp_dev = { @@ -216,7 +227,7 @@ REG tti_reg[] = { { FLDATA (UC, tti_unit.flags, UNIT_V_UC), REG_HRO }, { FLDATA (HDX, tti_unit.flags, UNIT_V_HDX), REG_HRO }, #endif - { DRDATA (POS, tti_unit.pos, 31), PV_LEFT }, + { DRDATA (POS, tti_unit.pos, 32), PV_LEFT }, { DRDATA (TIME, tti_unit.wait, 24), REG_NZ + PV_LEFT }, { NULL } }; @@ -272,7 +283,7 @@ REG tto_reg[] = { #if defined (KSR28) { FLDATA (TTO_STATE, tto_state, 0), REG_HRO }, #endif - { DRDATA (POS, tto_unit.pos, 31), PV_LEFT }, + { DRDATA (POS, tto_unit.pos, 32), PV_LEFT }, { DRDATA (TIME, tto_unit.wait, 24), PV_LEFT }, { NULL } }; @@ -390,7 +401,8 @@ if ((temp = getc (ptr_unit.fileref)) == EOF) { /* end of file? */ else perror ("PTR I/O error"); clearerr (ptr_unit.fileref); return SCPE_IOERR; } -if (ptr_state == 0) ptr_unit.buf = temp & 0377; /* alpha */ +if (ptr_state == 0) ptr_unit.buf = (temp | /* alpha */ + ((ptr_unit.flags & UNIT_RASCII)? 0200: 0)) & 0377; else if (temp & 0200) { /* binary */ ptr_state = ptr_state - 6; ptr_unit.buf = ptr_unit.buf | ((temp & 077) << ptr_state); } @@ -420,6 +432,9 @@ t_stat reason; reason = attach_unit (uptr, cptr); ptr_err = (ptr_unit.flags & UNIT_ATT)? 0: 1; +ptr_unit.flags = ptr_unit.flags & ~UNIT_RASCII; +if (sim_switches & SWMASK ('A')) + ptr_unit.flags = ptr_unit.flags | UNIT_RASCII; return reason; } @@ -626,6 +641,10 @@ SET_INT (PTP); /* set done flag */ if ((ptp_unit.flags & UNIT_ATT) == 0) { /* not attached? */ ptp_err = 1; /* set error */ return IORETURN (ptp_stopioe, SCPE_UNATT); } +if (ptp_unit.flags & UNIT_PASCII) { /* ASCII mode? */ + ptp_unit.buf = ptp_unit.buf & 0177; /* force 7b */ + if ((ptp_unit.buf == 0) || (ptp_unit.buf == 0177)) + return SCPE_OK; } /* skip null, del */ if (putc (ptp_unit.buf, ptp_unit.fileref) == EOF) { /* I/O error? */ ptp_err = 1; /* set error */ perror ("PTP I/O error"); @@ -654,6 +673,9 @@ t_stat reason; reason = attach_unit (uptr, cptr); ptp_err = (ptp_unit.flags & UNIT_ATT)? 0: 1; +ptp_unit.flags = ptp_unit.flags & ~UNIT_PASCII; +if (sim_switches & SWMASK ('A')) + ptp_unit.flags = ptp_unit.flags | UNIT_PASCII; return reason; } diff --git a/PDP18B/pdp18b_sys.c b/PDP18B/pdp18b_sys.c index 6bae4a5a..9545ad06 100644 --- a/PDP18B/pdp18b_sys.c +++ b/PDP18B/pdp18b_sys.c @@ -1,6 +1,6 @@ /* pdp18b_sys.c: 18b PDP's simulator interface - Copyright (c) 1993-2001, Robert M Supnik + Copyright (c) 1993-2002, Robert M Supnik Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), @@ -23,6 +23,8 @@ be used in advertising or otherwise to promote the sale, use or other dealings in this Software without prior written authorization from Robert M Supnik. + 10-Feb-02 RMS Added PDP-7 DECtape IOT's + 03-Feb-02 RMS Fixed typo (found by Robert Alan Byer) 17-Sep-01 RMS Removed multiconsole support 27-May-01 RMS Added second Teletype support 18-May-01 RMS Added PDP-9,-15 API IOT's @@ -328,7 +330,7 @@ static const char *opcode[] = { "LPL2", "LPLD", "LPL1", "LPEF", "LPCF", "LPCF", "LPCF", "LPCF", "LPPB", "LPLS", "LPPS", -#elif defined (LP15) +#elif defined (LP15) /* PDP-15 LPT */ "LPSF", "LPPM", "LPP1", "LPDI", "LPRS", "LPOS", "LPEI", "LPCD", "LPCF", #endif @@ -359,10 +361,15 @@ static const char *opcode[] = { "MTTR", "MTCR", "MTSF", "MTRC", "MTAF", "MTRS", "MTGO", "MTCM", "MTLC", #endif -#if defined (DTA) /* TC02/TC15 */ +#if defined (DTA) /* DECtape */ +#if defined (PDP7) /* Type 550 */ + "MMDF", "MMEF", "MMRD", "MMWR", + "MMBF", "MMRS", "MMLC", "MMSE", +#elif defined (PDP9) || defined (PDP15) /* TC02/TC15 */ "DTCA", "DTRA", "DTXA", "DTLA", "DTEF", "DTRB", "DTDF", #endif +#endif #if defined (TTY1) "KSF1", "KRB1", "TSF1", "TCF1", "TLS1", "TCF1!TLS1", @@ -511,9 +518,14 @@ static const int32 opc_val[] = { 0707352+I_NPN, 0707304+I_NPI, 0707324+I_NPI, 0707326+I_NPI, #endif #if defined (DTA) +#if defined (PDP7) /* Type 550 */ + 0707501+I_NPI, 0707541+I_NPI, 0707512+I_NPN, 0707504+I_NPI, + 0707601+I_NPI, 0707612+I_NPN, 0707604+I_NPI, 0707644+I_NPI, +#elif defined (PDP9) || defined (PDP15) /* TC02/TC15 */ 0707541+I_NPI, 0707552+I_NPN, 0707544+I_NPI, 0707545+I_NPI, 0707561+I_NPI, 0707572+I_NPN, 0707601+I_NPI, #endif +#endif #if defined (TTY1) 0704101+I_NPI, 0704112+I_NPN, 0704001+I_NPI, 0704002+I_NPI, 0704004+I_NPI, 0704006+I_NPI, @@ -618,8 +630,8 @@ return sp; return = status code */ -#define FMTASC(x) ((x) < 040)? "<%03o>": "%c", (x) -#define SIXTOASC(x) (((x) >= 040)? (x): (x) + 0100) +#define FMTASC(x) (((x) < 040)? "<%03o>": "%c", (x)) +#define SIXTOASC(x) (((x) >= 040)? (x): ((x) + 0100)) t_stat fprint_sym (FILE *of, t_addr addr, t_value *val, UNIT *uptr, int32 sw) @@ -631,7 +643,7 @@ i = val[1]; cflag = (uptr == NULL) || (uptr == &cpu_unit); if (sw & SWMASK ('A')) { /* ASCII? */ if (inst > 0377) return SCPE_ARG; - fprintf (of, FMTASC (inst & 0177)); + fprintf (of, "%c", FMTASC (inst & 0177)); return SCPE_OK; } if (sw & SWMASK ('C')) { /* character? */ fprintf (of, "%c", SIXTOASC ((inst >> 12) & 077)); diff --git a/PDP18B/pdp18b_tt1.c b/PDP18B/pdp18b_tt1.c index b558b01e..de7c0c23 100644 --- a/PDP18B/pdp18b_tt1.c +++ b/PDP18B/pdp18b_tt1.c @@ -1,6 +1,6 @@ /* pdp18b_tt1.c: 18b PDP's second Teletype - Copyright (c) 1993-2001, Robert M Supnik + Copyright (c) 1993-2002, Robert M Supnik Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), @@ -26,6 +26,9 @@ tti1 keyboard tto1 teleprinter + 30-May-02 RMS Widened POS to 32b + 06-Jan-02 RMS Added enable/disable support + 30-Dec-01 RMS Added show statistics, set disconnect 30-Nov-01 RMS Added extended SET/SHOW support 25-Nov-01 RMS Revised interrupt structure 19-Sep-01 RMS Fixed typo @@ -42,7 +45,7 @@ #define UNIT_V_UC (UNIT_V_UF + 0) /* UC only */ #define UNIT_UC (1 << UNIT_V_UC) -extern int32 int_hwre[API_HLVL+1]; +extern int32 int_hwre[API_HLVL+1], dev_enb; extern int32 tmxr_poll; /* calibrated poll */ TMLN tt1_ldsc = { 0 }; /* line descriptors */ TMXR tt_desc = { 1, 0, &tt1_ldsc }; /* mux descriptor */ @@ -53,7 +56,8 @@ t_stat tti1_reset (DEVICE *dptr); t_stat tto1_reset (DEVICE *dptr); t_stat tti1_attach (UNIT *uptr, char *cptr); t_stat tti1_detach (UNIT *uptr); -t_stat tti1_status (FILE *st, UNIT *uptr, int32 val, void *desc); +t_stat tti1_summ (FILE *st, UNIT *uptr, int32 val, void *desc); +t_stat tti1_show (FILE *st, UNIT *uptr, int32 val, void *desc); /* TTI1 data structures @@ -70,16 +74,23 @@ REG tti1_reg[] = { { FLDATA (INT, int_hwre[API_TTI1], INT_V_TTI1) }, { FLDATA (DONE, int_hwre[API_TTI1], INT_V_TTI1) }, { FLDATA (UC, tti1_unit.flags, UNIT_V_UC), REG_HRO }, - { DRDATA (POS, tt1_ldsc.rxcnt, 31), PV_LEFT }, + { DRDATA (POS, tt1_ldsc.rxcnt, 32), PV_LEFT }, { DRDATA (TIME, tti1_unit.wait, 24), REG_NZ + PV_LEFT }, + { FLDATA (*DEVENB, dev_enb, ENB_V_TTI1), REG_HRO }, { NULL } }; MTAB tti1_mod[] = { { UNIT_UC, 0, "lower case", "LC", NULL }, { UNIT_UC, UNIT_UC, "upper case", "UC", NULL }, - { UNIT_ATT, UNIT_ATT, "line status", NULL, NULL, &tti1_status }, - { MTAB_XTD | MTAB_VDV | MTAB_VUN | MTAB_NMO, 0, "LINE", NULL, - NULL, &tti1_status, NULL }, + { UNIT_ATT, UNIT_ATT, "summary", NULL, NULL, &tti1_summ }, + { MTAB_XTD | MTAB_VDV, 0, NULL, "DISCONNECT", + &tmxr_dscln, NULL, &tt_desc }, + { MTAB_XTD | MTAB_VDV | MTAB_NMO, 1, "CONNECTIONS", NULL, + NULL, &tti1_show, NULL }, + { MTAB_XTD | MTAB_VDV | MTAB_NMO, 0, "STATISTICS", NULL, + NULL, &tti1_show, NULL }, + { MTAB_XTD|MTAB_VDV, ENB_TTI1, NULL, "ENABLED", &set_enb }, + { MTAB_XTD|MTAB_VDV, ENB_TTI1, NULL, "DISABLED", &set_dsb }, { 0 } }; DEVICE tti1_dev = { @@ -102,8 +113,9 @@ REG tto1_reg[] = { { ORDATA (BUF, tto1_unit.buf, 8) }, { FLDATA (INT, int_hwre[API_TTO1], INT_V_TTO1) }, { FLDATA (DONE, int_hwre[API_TTO1], INT_V_TTO1) }, - { DRDATA (POS, tt1_ldsc.txcnt, 31), PV_LEFT }, + { DRDATA (POS, tt1_ldsc.txcnt, 32), PV_LEFT }, { DRDATA (TIME, tto1_unit.wait, 24), PV_LEFT }, + { FLDATA (*DEVENB, dev_enb, ENB_V_TTI1), REG_HRO }, { NULL } }; MTAB tto1_mod[] = { @@ -235,10 +247,20 @@ sim_cancel (uptr); /* stop poll */ return r; } -/* Status routine */ +/* Show summary processor */ -t_stat tti1_status (FILE *st, UNIT *uptr, int32 val, void *desc) +t_stat tti1_summ (FILE *st, UNIT *uptr, int32 val, void *desc) { -tmxr_fstatus (st, &tt1_ldsc, -1); +if (tt1_ldsc.conn) fprintf (st, "connected"); +else fprintf (st, "disconnected"); +return SCPE_OK; +} + +/* SHOW CONN/STAT processor */ + +t_stat tti1_show (FILE *st, UNIT *uptr, int32 val, void *desc) +{ +if (val) tmxr_fconns (st, &tt1_ldsc, -1); +else tmxr_fstats (st, &tt1_ldsc, -1); return SCPE_OK; } diff --git a/PDP8/pdp8_clk.c b/PDP8/pdp8_clk.c index cb16228c..53e79636 100644 --- a/PDP8/pdp8_clk.c +++ b/PDP8/pdp8_clk.c @@ -1,6 +1,6 @@ /* pdp8_clk.c: PDP-8 real-time clock simulator - Copyright (c) 1993-2001, Robert M Supnik + Copyright (c) 1993-2002, Robert M Supnik Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), @@ -25,6 +25,7 @@ clk real time clock + 30-Dec-01 RMS Removed for generalized timers 05-Sep-01 RMS Added terminal multiplexor support 17-Jul-01 RMS Moved function prototype 05-Mar-01 RMS Added clock calibration support @@ -109,7 +110,7 @@ int32 t; dev_done = dev_done | INT_CLK; /* set done */ int_req = INT_UPDATE; /* update interrupts */ -t = sim_rtc_calb (clk_tps); /* calibrate clock */ +t = sim_rtcn_calb (clk_tps, TMR_CLK); /* calibrate clock */ sim_activate (&clk_unit, t); /* reactivate unit */ tmxr_poll = t; /* set mux poll */ return SCPE_OK; @@ -123,6 +124,5 @@ dev_done = dev_done & ~INT_CLK; /* clear done, int */ int_req = int_req & ~INT_CLK; int_enable = int_enable & ~INT_CLK; /* clear enable */ sim_activate (&clk_unit, clk_unit.wait); /* activate unit */ -tmxr_poll = clk_unit.wait; /* set mux poll */ return SCPE_OK; } diff --git a/PDP8/pdp8_cpu.c b/PDP8/pdp8_cpu.c index d9e78fec..3cbddfb2 100644 --- a/PDP8/pdp8_cpu.c +++ b/PDP8/pdp8_cpu.c @@ -1,6 +1,6 @@ /* pdp8_cpu.c: PDP-8 CPU simulator - Copyright (c) 1993-2001, Robert M Supnik + Copyright (c) 1993-2002, Robert M Supnik Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), @@ -25,6 +25,8 @@ cpu central processor + 06-Jan-02 RMS Added device enable/disable routines + 30-Dec-01 RMS Added old PC queue 16-Dec-01 RMS Fixed bugs in EAE 07-Dec-01 RMS Revised to use new breakpoint package 30-Nov-01 RMS Added RL8A, extended SET/SHOW support @@ -179,6 +181,9 @@ #include "pdp8_defs.h" +#define PCQ_SIZE 64 /* must be 2**n */ +#define PCQ_MASK (PCQ_SIZE - 1) +#define PCQ_ENTRY pcq[pcq_p = (pcq_p - 1) & PCQ_MASK] = PC #define UNIT_V_NOEAE (UNIT_V_UF) /* EAE absent */ #define UNIT_NOEAE (1 << UNIT_V_NOEAE) #define UNIT_V_MSIZE (UNIT_V_UF+1) /* dummy mask */ @@ -197,19 +202,47 @@ int32 SC = 0; /* EAE shift count */ int32 UB = 0; /* User mode Buffer */ int32 UF = 0; /* User mode Flag */ int32 OSR = 0; /* Switch Register */ -int32 old_PC = 0; /* old PC */ +int16 pcq[PCQ_SIZE] = { 0 }; /* PC queue */ +int32 pcq_p = 0; /* PC queue ptr */ +REG *pcq_r = NULL; /* PC queue reg ptr */ int32 dev_done = 0; /* dev done flags */ int32 int_enable = INT_INIT_ENABLE; /* intr enables */ int32 int_req = 0; /* intr requests */ int32 dev_enb = -1 & ~INT_DF & ~INT_RL; /* device enables */ int32 stop_inst = 0; /* trap on ill inst */ +extern int32 sim_interval; extern int32 sim_int_char; extern int32 sim_brk_types, sim_brk_dflt, sim_brk_summ; /* breakpoint info */ +extern UNIT clk_unit, ttix_unit; t_stat cpu_ex (t_value *vptr, t_addr addr, UNIT *uptr, int32 sw); t_stat cpu_dep (t_value val, t_addr addr, UNIT *uptr, int32 sw); t_stat cpu_reset (DEVICE *dptr); t_stat cpu_set_size (UNIT *uptr, int32 val, char *cptr, void *desc); +extern int32 tti (int32 pulse, int32 AC); +extern int32 tto (int32 pulse, int32 AC); +extern int32 ptr (int32 pulse, int32 AC); +extern int32 ptp (int32 pulse, int32 AC); +extern int32 clk (int32 pulse, int32 AC); +extern int32 lpt (int32 pulse, int32 AC); +extern int32 ttix (int32 inst, int32 AC); +extern int32 ttox (int32 inst, int32 AC); +extern int32 rk (int32 pulse, int32 AC); +extern int32 rx (int32 pulse, int32 AC); +extern int32 df60 (int32 pulse, int32 AC); +extern int32 df61 (int32 pulse, int32 AC); +extern int32 df62 (int32 pulse, int32 AC); +extern int32 rf60 (int32 pulse, int32 AC); +extern int32 rf61 (int32 pulse, int32 AC); +extern int32 rf62 (int32 pulse, int32 AC); +extern int32 rf64 (int32 pulse, int32 AC); +extern int32 rl60 (int32 pulse, int32 AC); +extern int32 rl61 (int32 pulse, int32 AC); +extern int32 mt70 (int32 pulse, int32 AC); +extern int32 mt71 (int32 pulse, int32 AC); +extern int32 mt72 (int32 pulse, int32 AC); +extern int32 dt76 (int32 pulse, int32 AC); +extern int32 dt77 (int32 pulse, int32 AC); /* CPU data structures @@ -245,7 +278,8 @@ REG cpu_reg[] = { { ORDATA (DONE, dev_done, INT_V_DIRECT), REG_RO }, { ORDATA (ENABLE, int_enable, INT_V_DIRECT), REG_RO }, { FLDATA (NOEAE, cpu_unit.flags, UNIT_V_NOEAE), REG_HRO }, - { ORDATA (OLDPC, old_PC, 15), REG_RO }, + { BRDATA (PCQ, pcq, 8, 15, PCQ_SIZE), REG_RO+REG_CIRC }, + { ORDATA (PCQP, pcq_p, 6), REG_HRO }, { FLDATA (STOP_INST, stop_inst, 0) }, { ORDATA (WRU, sim_int_char, 8) }, { ORDATA (DEVENB, dev_enb, 32), REG_HRO }, @@ -272,36 +306,10 @@ DEVICE cpu_dev = { t_stat sim_instr (void) { -extern int32 sim_interval; int32 IR, MB, IF, DF, LAC, MQ; t_addr PC, MA; int32 device, pulse, temp, iot_data; t_stat reason; -extern UNIT clk_unit; -extern int32 tti (int32 pulse, int32 AC); -extern int32 tto (int32 pulse, int32 AC); -extern int32 ptr (int32 pulse, int32 AC); -extern int32 ptp (int32 pulse, int32 AC); -extern int32 clk (int32 pulse, int32 AC); -extern int32 lpt (int32 pulse, int32 AC); -extern int32 ttix (int32 inst, int32 AC); -extern int32 ttox (int32 inst, int32 AC); -extern int32 rk (int32 pulse, int32 AC); -extern int32 rx (int32 pulse, int32 AC); -extern int32 df60 (int32 pulse, int32 AC); -extern int32 df61 (int32 pulse, int32 AC); -extern int32 df62 (int32 pulse, int32 AC); -extern int32 rf60 (int32 pulse, int32 AC); -extern int32 rf61 (int32 pulse, int32 AC); -extern int32 rf62 (int32 pulse, int32 AC); -extern int32 rf64 (int32 pulse, int32 AC); -extern int32 rl60 (int32 pulse, int32 AC); -extern int32 rl61 (int32 pulse, int32 AC); -extern int32 mt70 (int32 pulse, int32 AC); -extern int32 mt71 (int32 pulse, int32 AC); -extern int32 mt72 (int32 pulse, int32 AC); -extern int32 dt76 (int32 pulse, int32 AC); -extern int32 dt77 (int32 pulse, int32 AC); /* Restore register state */ @@ -312,7 +320,8 @@ LAC = saved_LAC & 017777; MQ = saved_MQ & 07777; int_req = INT_UPDATE; reason = 0; -sim_rtc_init (clk_unit.wait); /* init calibration */ +sim_rtcn_init (clk_unit.wait, TMR_CLK); /* init clk calib */ +sim_rtcn_init (ttix_unit.wait, TMR_TTX); /* init ttx calib */ /* Main instruction fetch/decode loop */ @@ -324,7 +333,8 @@ if (int_req > INT_PENDING) { /* interrupt? */ int_req = int_req & ~INT_ION; /* interrupts off */ SF = (UF << 6) | (IF >> 9) | (DF >> 12); /* form save field */ IF = IB = DF = UF = UB = 0; /* clear mem ext */ - old_PC = M[0] = PC; /* save PC in 0 */ + PCQ_ENTRY; /* save old PC */ + M[0] = PC; /* save PC in 0 */ PC = 1; } /* fetch next from 1 */ MA = IF | PC; /* form PC */ @@ -469,7 +479,7 @@ case 020: /* JMS, dir, zero */ ZERO_PAGE_J; CHANGE_FIELD; MA = IF | MA; - old_PC = PC; + PCQ_ENTRY; if (MEM_ADDR_OK (MA)) M[MA] = PC; PC = (MA + 1) & 07777; break; @@ -477,7 +487,7 @@ case 021: /* JMS, dir, curr */ CURR_PAGE_J; CHANGE_FIELD; MA = IF | MA; - old_PC = PC; + PCQ_ENTRY; if (MEM_ADDR_OK (MA)) M[MA] = PC; PC = (MA + 1) & 07777; break; @@ -486,7 +496,7 @@ case 022: /* JMS, indir, zero */ INDIRECT_J; CHANGE_FIELD; MA = IF | MA; - old_PC = PC; + PCQ_ENTRY; if (MEM_ADDR_OK (MA)) M[MA] = PC; PC = (MA + 1) & 07777; break; @@ -495,7 +505,7 @@ case 023: /* JMS, indir, curr */ INDIRECT_J; CHANGE_FIELD; MA = IF | MA; - old_PC = PC; + PCQ_ENTRY; if (MEM_ADDR_OK (MA)) M[MA] = PC; PC = (MA + 1) & 07777; break; @@ -505,27 +515,27 @@ case 023: /* JMS, indir, curr */ case 024: /* JMP, dir, zero */ ZERO_PAGE_J; CHANGE_FIELD; - old_PC = PC; + PCQ_ENTRY; PC = MA; break; case 025: /* JMP, dir, curr */ CURR_PAGE_J; CHANGE_FIELD; - old_PC = PC; + PCQ_ENTRY; PC = MA; break; case 026: /* JMP, indir, zero */ ZERO_PAGE; INDIRECT_J; CHANGE_FIELD; - old_PC = PC; + PCQ_ENTRY; PC = MA; break; case 027: /* JMP, indir, curr */ CURR_PAGE; INDIRECT_J; CHANGE_FIELD; - old_PC = PC; + PCQ_ENTRY; PC = MA; break; @@ -1022,11 +1032,13 @@ case 030:case 031:case 032:case 033: /* IOT */ case 013: /* CLK */ iot_data = clk (pulse, iot_data); break; - case 040: case 042: case 044: case 046: /* KL8A in */ - iot_data = ttix (IR, iot_data); + case 040: case 042: case 044: case 046: /* KL8JA in */ + if (dev_enb & INT_TTI1) iot_data = ttix (IR, iot_data); + else reason = stop_inst; break; - case 041: case 043: case 045: case 047: /* KL8A out */ - iot_data = ttox (IR, iot_data); + case 041: case 043: case 045: case 047: /* KL8JA out */ + if (dev_enb & INT_TTI1) iot_data = ttox (IR, iot_data); + else reason = stop_inst; break; case 060: /* DF32/RF08 */ if (dev_enb & INT_DF) iot_data = df60 (pulse, iot_data); @@ -1091,6 +1103,7 @@ saved_PC = IF | (PC & 07777); /* save copies */ saved_DF = DF & 070000; saved_LAC = LAC & 017777; saved_MQ = MQ & 07777; +pcq_r -> qptr = pcq_p; /* update pc q ptr */ return reason; } /* end sim_instr */ @@ -1101,6 +1114,9 @@ t_stat cpu_reset (DEVICE *dptr) int_req = (int_req & ~INT_ION) | INT_NO_CIF_PENDING; saved_DF = IB = saved_PC & 070000; UF = UB = gtf = emode = 0; +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; } @@ -1139,3 +1155,39 @@ MEMSIZE = val; for (i = MEMSIZE; i < MAXMEMSIZE; i++) M[i] = 0; return SCPE_OK; } + +/* Device enable routine */ + +t_stat set_enb (UNIT *uptr, int32 val, char *cptr, void *desc) +{ +DEVICE *dptr; + +if (cptr != NULL) return SCPE_ARG; +if ((uptr == NULL) || (val == 0)) return SCPE_IERR; +dptr = find_dev_from_unit (uptr); +if (dptr == NULL) return SCPE_IERR; +dev_enb = dev_enb | val; +if (dptr -> reset) dptr -> reset (dptr); +return SCPE_OK; +} + +/* Device disable routine */ + +t_stat set_dsb (UNIT *uptr, int32 val, char *cptr, void *desc) +{ +int32 i; +DEVICE *dptr; +UNIT *up; + +if (cptr != NULL) return SCPE_ARG; +if ((uptr == NULL) || (val == 0)) return SCPE_IERR; +dptr = find_dev_from_unit (uptr); +if (dptr == NULL) return SCPE_IERR; +for (i = 0; i < dptr -> numunits; i++) { /* check units */ + up = (dptr -> units) + i; + if ((up -> flags & UNIT_ATT) || sim_is_active (up)) + return SCPE_NOFNC; } +dev_enb = dev_enb & ~val; +if (dptr -> reset) dptr -> reset (dptr); +return SCPE_OK; +} diff --git a/PDP8/pdp8_defs.h b/PDP8/pdp8_defs.h index 3fd82513..110f888d 100644 --- a/PDP8/pdp8_defs.h +++ b/PDP8/pdp8_defs.h @@ -1,6 +1,6 @@ /* pdp8_defs.h: PDP-8 simulator definitions - Copyright (c) 1993-2001, Robert M Supnik + Copyright (c) 1993-2002, Robert M Supnik Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), @@ -23,6 +23,7 @@ be used in advertising or otherwise to promote the sale, use or other dealings in this Software without prior written authorization from Robert M Supnik. + 20-Jan-02 RMS Fixed bug in TTx interrupt enable initialization 25-Nov-01 RMS Added RL8A support 16-Sep-01 RMS Added multiple KL support 18-Mar-01 RMS Added DF32 support @@ -57,6 +58,11 @@ #define IOT_SKP (1 << IOT_V_SKP) #define IOT_REASON (1 << IOT_V_REASON) #define IORETURN(f,v) ((f)? (v): SCPE_OK) /* stop on error */ + +/* Timers */ + +#define TMR_CLK 0 /* timer 0 = clock */ +#define TMR_TTX 1 /* timer 1 = TTx */ /* Interrupt flags @@ -138,6 +144,13 @@ #define INT_ION (1 << INT_V_ION) #define INT_DEV_ENABLE ((1 << INT_V_DIRECT) - 1) /* devices w/enables */ #define INT_ALL ((1 << INT_V_OVHD) - 1) /* all interrupts */ -#define INT_INIT_ENABLE (INT_TTI+INT_TTO+INT_PTR+INT_PTP+INT_LPT) +#define INT_INIT_ENABLE (INT_TTI+INT_TTO+INT_PTR+INT_PTP+INT_LPT) | \ + (INT_TTI1+INT_TTI2+INT_TTI3+INT_TTI4) | \ + (INT_TTO1+INT_TTO2+INT_TTO3+INT_TTO4) #define INT_PENDING (INT_ION+INT_NO_CIF_PENDING+INT_NO_ION_PENDING) #define INT_UPDATE ((int_req & ~INT_DEV_ENABLE) | (dev_done & int_enable)) + +/* Function prototypes */ + +t_stat set_enb (UNIT *uptr, int32 val, char *cptr, void *desc); +t_stat set_dsb (UNIT *uptr, int32 val, char *cptr, void *desc); diff --git a/PDP8/pdp8_df.c b/PDP8/pdp8_df.c index 41209aad..1a90ac4f 100644 --- a/PDP8/pdp8_df.c +++ b/PDP8/pdp8_df.c @@ -1,6 +1,6 @@ /* pdp8_df.c: DF32 fixed head disk simulator - Copyright (c) 1993-2001, Robert M Supnik + Copyright (c) 1993-2002, Robert M Supnik Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), @@ -118,8 +118,13 @@ REG df_reg[] = { { FLDATA (*DEVENB, dev_enb, INT_V_DF), REG_HRO }, { NULL } }; +MTAB df_mod[] = { + { MTAB_XTD|MTAB_VDV, INT_DF, NULL, "ENABLED", &set_enb }, + { MTAB_XTD|MTAB_VDV, INT_DF, NULL, "DISABLED", &set_dsb }, + { 0 } }; + DEVICE df_dev = { - "DF", &df_unit, df_reg, NULL, + "DF", &df_unit, df_reg, df_mod, 1, 8, 17, 1, 8, 12, NULL, NULL, &df_reset, &df_boot, NULL, NULL }; diff --git a/PDP8/pdp8_doc.txt b/PDP8/pdp8_doc.txt index 149d7831..be513ca7 100644 --- a/PDP8/pdp8_doc.txt +++ b/PDP8/pdp8_doc.txt @@ -1,14 +1,14 @@ To: Users From: Bob Supnik Subj: PDP-8 Simulator Usage -Date: 1-Dec-01 +Date: 15-Jun-2002 COPYRIGHT NOTICE The following copyright notice applies to both the SIMH source and binary: - Original code published in 1993-2001, written by Robert M Supnik - Copyright (c) 1993-2001, Robert M Supnik + Original code published in 1993-2002, written by Robert M Supnik + Copyright (c) 1993-2002, Robert M Supnik Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), @@ -67,12 +67,12 @@ The PDP-8 simulator is configured as follows: device simulates name(s) -CPU PDP-8/E CPU with 32KW of memory +CPU PDP-8/E CPU with 4KW-32KW of memory - KE8E extended arithmetic element (EAE) - KM8E memory management and timeshare control PTR,PTP PC8E paper tape reader/punch TTI,TTO KL8E console terminal -TTI1-4,TTO1-4 KL8JA additional terminals +TTIX,TTOX KL8JA additional terminals LPT LE8E line printer CLK DK8E line frequency clock (also PDP-8/A compatible) RK RK8E/RK05 cartridge disk controller with four drives @@ -83,14 +83,14 @@ RX RX8E/RX01 floppy disk controller with two drives DT TC08/TU56 DECtape controller with eight drives MT TM8E/TU10 magnetic tape controller with eight drives -The RK, RF, DF, RL, RX, DT, and MT devices can be DISABLEd. The PDP-8 -can support only one of the set {DF32, RF08, RL8A},since they use the same -IOT's. The simulator defaults to the RF08. To change the disk at device -addresses 60-61: +The RK, RF, DF, RL, RX, DT, MT, and TTIX/TTOX devices can be set DISABLEd. +The PDP-8 can support only one of the set {DF32, RF08, RL8A}, since they +use the same IOT's. The simulator defaults to the RF08. To change the +disk at device addresses 60-61: - ENABLE DF enable DF32, disable RF08 and RL8A - ENABLE RF enable RF08, disable DF32 and RL8A - ENABLE RL enable RL8A, disable DF32 and RF08 + SET RF DISABLED disable RF08 + SET DF ENABLED, or enable DF32 + SET RL ENABLED enable RL8A The PDP-8 simulator implements one unique stop condition: if an undefined instruction (unimplemented IOT or OPR) is decoded, and register STOP_INST @@ -149,7 +149,8 @@ control registers for the interrupt system. INT 15 interrupt pending flags DONE 15 device done flags ENABLE 15 device interrupt enable flags - OLDPC 15 PC prior to last JMP, JMS, or interrupt + PCQ[0:63] 15 PC prior to last JMP, JMS, or interrupt; + most recent PC change first STOP_INST 1 stop on undefined instruction WRU 8 interrupt character @@ -172,7 +173,7 @@ The paper tape reader implements these registers: DONE 1 device done flag ENABLE 1 interrupt enable flag INT 1 interrupt pending flag - POS 31 position in the input file + POS 32 position in the input file TIME 24 time from I/O initiation to interrupt STOP_IOE 1 stop on I/O error @@ -202,7 +203,7 @@ The paper tape punch implements these registers: DONE 1 device done flag ENABLE 1 interrupt enable flag INT 1 interrupt pending flag - POS 31 position in the output file + POS 32 position in the output file TIME 24 time from I/O initiation to interrupt STOP_IOE 1 stop on I/O error @@ -229,7 +230,7 @@ The terminal input implements these registers: DONE 1 device done flag ENABLE 1 interrupt enable flag INT 1 interrupt pending flag - POS 31 number of characters input + POS 32 number of characters input TIME 24 keyboard polling interval 2.2.4 KL8E Terminal Output (TTO) @@ -243,7 +244,7 @@ implements these registers: DONE 1 device done flag ENABLE 1 interrupt enable flag INT 1 interrupt pending flag - POS 31 number of characters output + POS 32 number of characters output TIME 24 time from I/O initiation to interrupt 2.2.5 LE8E Line Printer (LPT) @@ -261,7 +262,7 @@ The line printer implements these registers: DONE 1 device done flag ENABLE 1 interrupt enable flag INT 1 interrupt pending flag - POS 31 position in the output file + POS 32 position in the output file TIME 24 time from I/O initiation to interrupt Error handling is as follows: @@ -288,51 +289,58 @@ The real-time clock (CLK) implements these registers: The real-time clock autocalibrates; the clock interval is adjusted up or down so that the clock tracks actual elapsed time. -2.2.7 KL8JA Additional Terminals (TTI1-4, TTO1-4) +2.2.7 KL8JA Additional Terminals (TTIX, TTOX) -Each additional terminal consists of two independent devices, TTIn and -TTOn. The entire set is modelled as a terminal multiplexor, with TTI1 +The additional terminals consist of two independent devices, TTIX and +TTOX. The entire set is modelled as a terminal multiplexor, with TTIX as the master unit. The additional terminals perform input and output through Telnet sessions connected to a user-specified port. The ATTACH command specifies the port to be used: - ATTACH TTI1 (cr) -- set up listening port + ATTACH TTIX set up listening port where port is a decimal number between 1 and 65535 that is not being used for other TCP/IP activities. -Once TTI1 is attached and the simulator is running, the terminals listen +The additional terminals have one option, UC; when set, lower case input +characters are automatically converted to upper case. This is required +by TSS/8 and is on by default for all lines. + +Once TTIX is attached and the simulator is running, the terminals listen for connections on the specified port. They assume that the incoming connections are Telnet connections. The connections remain open until -disconnected either by the Telnet client, or by a DETACH TTI1 command. +disconnected either by the Telnet client, a SET TTIX DISCONNECT command, +or a DETACH TTIX command. -The SHOW TTI1 LINESTATUS command displays the current connections to the -additional terminals. +The SHOW TTIX CONNECTIONS command displays the current connections to the +extra terminals. The SHOW TTIX STATISTICS command displays statistics for +active connections. The SET TTIX DISCONNECT=linenumber disconnects the +specified line. -The input devices (TTI1-4) implement these registers: +The input device (TTIX) implements these registers: name size comments - BUF 8 last data item processed - DONE 1 device done flag - ENABLE 1 interrupt enable flag - INT 1 interrupt pending flag - POS 31 number of characters input - TIME 24 keyboard polling interval + BUF[0:3] 8 input buffer, lines 0-3 + DONE 4 device done flags (line 0 rightmost) + ENABLE 4 interrupt enable flag + INT 4 interrupt pending flag + TIME 24 initial polling interval + TPS 10 polls per second after calibration -The output devices (TTO1-4) implement these registers: +The output device (TTOX) implements these registers: name size comments - BUF 8 last data item processed - DONE 1 device done flag - ENABLE 1 interrupt enable flag - INT 1 interrupt pending flag - POS 31 number of characters output - TIME 24 time from I/O initiation to interrupt + BUF[0:3] 8 last data item processed, lines 0-3 + DONE 4 device done flag (line 0 rightmost) + ENABLE 4 interrupt enable flag + INT 4 interrupt pending flag + TIME[0:3] 24 time from I/O initiation to interrupt, + lines 0-3 The additional terminals do not support save and restore. All open -connections are lost when the simulator shuts down or TTI1 is detached. +connections are lost when the simulator shuts down or TTIX is detached. 2.3 Moving Head Disks @@ -341,10 +349,9 @@ connections are lost when the simulator shuts down or TTI1 is detached. RK8E options include the ability to make units write enabled or write locked: SET RKn LOCKED set unit n write locked - SET RKn ENABLED set unit n write enabled + SET RKn WRITEENABLED set unit n write enabled -Units can also be REMOVEd or ADDed to the configuration. The RK8E supports -the BOOT command. +Units can also be set ONLINE or OFFLINE. The RK8E supports the BOOT command. The RK8E implements these registers: @@ -375,11 +382,10 @@ Error handling is as follows: RL8A options include the ability to make units write enabled or write locked: - SET RKn LOCKED set unit n write locked - SET RKn ENABLED set unit n write enabled + SET RLn LOCKED set unit n write locked + SET RLn WRITEENABLED set unit n write enabled -Units can also be REMOVEd or ADDed to the configuration. The RK8E supports -the BOOT command. +Units can also be set ONLINE or OFFILE. The RL8A supports the BOOT command. The RL8A implements these registers: @@ -418,7 +424,7 @@ Error handling is as follows: RX8E options include the ability to set units write enabled or write locked: SET RXn LOCKED set unit n write locked - SET RXn ENABLED set unit n write enabled + SET RXn WRITEENABLED set unit n write enabled The RX8E supports the BOOT command. @@ -534,17 +540,16 @@ DECtape options include the ability to make units write enabled or write locked. SET DTn LOCKED set unit n write locked - SET DTn ENABLED set unit n write enabled + SET DTn WRITEENABLED set unit n write enabled -Units can also be REMOVEd or ADDed to the configuration. The TC08 supports -the BOOT command. +Units can also be set ONLINE or OFFLINE. The TC08 supports the BOOT command. The TC08 supports both PDP-8 format and PDP-9/11/15 format DECtape images. ATTACH tries to determine the tape format from the DECtape image; the user can force a particular format with switches: - -f foreign (PDP-9/11/15) format - -n native (PDP-8) format + -f foreign (PDP-9/11/15) format + -n native (PDP-8) format The DECtape controller is a data-only simulator; the timing and mark track, and block header and trailer, are not stored. Thus, the WRITE @@ -568,7 +573,7 @@ The DECtape controller implements these registers: ACTIME 31 time to accelerate to full speed DCTIME 31 time to decelerate to a full stop SUBSTATE 2 read/write command substate - POS[0:7] 31 position, in lines, units 0-7 + POS[0:7] 32 position, in lines, units 0-7 STATT[0:7] 31 unit state, units 0-7 It is critically important to maintain certain timing relationships @@ -585,9 +590,9 @@ Magnetic tape options include the ability to make units write enabled or or write locked. SET MTn LOCKED set unit n write locked - SET MTn ENABLED set unit n write enabled + SET MTn WRITEENABLED set unit n write enabled -Units can also be REMOVEd or ADDed to the configuration. +Units can also be set ONLINE or OFFLINE. The magnetic tape controller implements these registers: @@ -605,7 +610,7 @@ The magnetic tape controller implements these registers: STOP_IOE 1 stop on I/O error TIME 24 record delay UST[0:7] 24 unit status, units 0-7 - POS[0:7] 31 position, units 0-7 + POS[0:7] 32 position, units 0-7 Error handling is as follows: diff --git a/PDP8/pdp8_dt.c b/PDP8/pdp8_dt.c index 4fc23a0c..b64370ca 100644 --- a/PDP8/pdp8_dt.c +++ b/PDP8/pdp8_dt.c @@ -1,6 +1,6 @@ /* pdp8_dt.c: PDP-8 DECtape simulator - Copyright (c) 1993-2001, Robert M Supnik + Copyright (c) 1993-2002, Robert M Supnik Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), @@ -25,6 +25,8 @@ dt TC08/TU56 DECtape + 30-May-02 RMS Widened POS to 32b + 06-Jan-02 RMS Changed enable/disable support 30-Nov-01 RMS Added read only unit, extended SET/SHOW support 24-Nov-01 RMS Changed POS, STATT, LASTT, FLG to arrays 29-Aug-01 RMS Added casts to PDP-18b packup routine @@ -305,7 +307,7 @@ REG dt_reg[] = { { ORDATA (SUBSTATE, dt_substate, 2) }, { ORDATA (LOG, dt_log, 4), REG_HIDDEN }, { DRDATA (LBLK, dt_logblk, 12), REG_HIDDEN }, - { URDATA (POS, dt_unit[0].pos, 10, 31, 0, + { URDATA (POS, dt_unit[0].pos, 10, 32, 0, DT_NUMDR, PV_LEFT | REG_RO) }, { URDATA (STATT, dt_unit[0].STATE, 8, 18, 0, DT_NUMDR, REG_RO) }, @@ -317,10 +319,12 @@ REG dt_reg[] = { { NULL } }; MTAB dt_mod[] = { - { UNIT_WLK, 0, "write enabled", "ENABLED", NULL }, + { UNIT_WLK, 0, "write enabled", "WRITEENABLED", NULL }, { UNIT_WLK, UNIT_WLK, "write locked", "LOCKED", NULL }, { UNIT_8FMT, 0, "16b/18b", NULL, NULL }, { UNIT_8FMT, UNIT_8FMT, "12b", NULL, NULL }, + { MTAB_XTD|MTAB_VDV, INT_DTA, NULL, "ENABLED", &set_enb }, + { MTAB_XTD|MTAB_VDV, INT_DTA, NULL, "DISABLED", &set_dsb }, { 0 } }; DEVICE dt_dev = { diff --git a/PDP8/pdp8_lp.c b/PDP8/pdp8_lp.c index 3705d3f2..0c4d3920 100644 --- a/PDP8/pdp8_lp.c +++ b/PDP8/pdp8_lp.c @@ -1,6 +1,6 @@ /* pdp8_lp.c: PDP-8 line printer simulator - Copyright (c) 1993-2001, Robert M Supnik + Copyright (c) 1993-2002, Robert M Supnik Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), @@ -24,6 +24,8 @@ in this Software without prior written authorization from Robert M Supnik. lpt LP8E line printer + + 30-May-02 RMS Widened POS to 32b */ #include "pdp8_defs.h" @@ -52,7 +54,7 @@ REG lpt_reg[] = { { FLDATA (DONE, dev_done, INT_V_LPT) }, { FLDATA (ENABLE, int_enable, INT_V_LPT) }, { FLDATA (INT, int_req, INT_V_LPT) }, - { DRDATA (POS, lpt_unit.pos, 31), PV_LEFT }, + { DRDATA (POS, lpt_unit.pos, 32), PV_LEFT }, { DRDATA (TIME, lpt_unit.wait, 24), PV_LEFT }, { FLDATA (STOP_IOE, lpt_stopioe, 0) }, { NULL } }; diff --git a/PDP8/pdp8_mt.c b/PDP8/pdp8_mt.c index 16847c57..23c7f606 100644 --- a/PDP8/pdp8_mt.c +++ b/PDP8/pdp8_mt.c @@ -1,6 +1,6 @@ /* pdp8_mt.c: PDP-8 magnetic tape simulator - Copyright (c) 1993-2001, Robert M Supnik + Copyright (c) 1993-2002, Robert M Supnik Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), @@ -25,6 +25,9 @@ mt TM8E/TU10 magtape + 30-May-02 RMS Widened POS to 32b + 22-Apr-02 RMS Added maximum record length test + 06-Jan-02 RMS Changed enable/disable support 30-Nov-01 RMS Added read only unit, extended SET/SHOW support 24-Nov-01 RMS Changed UST, POS, FLG to arrays 25-Apr-01 RMS Added device enable/disable support @@ -55,6 +58,7 @@ #define UNIT_W_UF 2 /* saved user flags */ #define USTAT u3 /* unit status */ #define UNUM u4 /* unit number */ +#define MT_MAXFR (1 << 16) /* max record lnt */ #define DBSIZE (1 << 12) /* max data cmd */ #define DBMASK (SBSIZE - 1) #define UNIT_WPRT (UNIT_WLK | UNIT_RO) /* write protect */ @@ -173,7 +177,7 @@ REG mt_reg[] = { { FLDATA (STOP_IOE, mt_stopioe, 0) }, { DRDATA (TIME, mt_time, 24), PV_LEFT }, { URDATA (UST, mt_unit[0].USTAT, 8, 16, 0, MT_NUMDR, 0) }, - { URDATA (POS, mt_unit[0].pos, 10, 31, 0, + { URDATA (POS, mt_unit[0].pos, 10, 32, 0, MT_NUMDR, PV_LEFT | REG_RO) }, { URDATA (FLG, mt_unit[0].flags, 8, UNIT_W_UF, UNIT_V_UF - 1, MT_NUMDR, REG_HRO) }, @@ -181,8 +185,10 @@ REG mt_reg[] = { { NULL } }; MTAB mt_mod[] = { - { UNIT_WLK, 0, "write enabled", "ENABLED", &mt_vlock }, + { UNIT_WLK, 0, "write enabled", "WRITEENABLED", &mt_vlock }, { UNIT_WLK, UNIT_WLK, "write locked", "LOCKED", &mt_vlock }, + { MTAB_XTD|MTAB_VDV, INT_MT, NULL, "ENABLED", &set_enb }, + { MTAB_XTD|MTAB_VDV, INT_MT, NULL, "DISABLED", &set_dsb }, { 0 } }; DEVICE mt_dev = { @@ -365,8 +371,9 @@ case FN_CMPARE: /* read/compare */ uptr -> USTAT = uptr -> USTAT | STA_EOF | STA_RLE; uptr -> pos = uptr -> pos + sizeof (t_mtrlnt); break; } - cbc = (mt_cu & CU_UNPAK)? wc: wc * 2; /* expected bc */ tbc = MTRL (tbc); /* ignore error flag */ + if (tbc > MT_MAXFR) return SCPE_MTRLNT; /* record too long? */ + cbc = (mt_cu & CU_UNPAK)? wc: wc * 2; /* expected bc */ if (tbc != cbc) mt_sta = mt_sta | STA_RLE; /* wrong size? */ if (tbc < cbc) { /* record small? */ cbc = tbc; /* use smaller */ diff --git a/PDP8/pdp8_pt.c b/PDP8/pdp8_pt.c index 40e9e535..ea353b8f 100644 --- a/PDP8/pdp8_pt.c +++ b/PDP8/pdp8_pt.c @@ -1,6 +1,6 @@ /* pdp8_pt.c: PDP-8 paper tape reader/punch simulator - Copyright (c) 1993-2001, Robert M Supnik + Copyright (c) 1993-2002, Robert M Supnik Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), @@ -25,6 +25,7 @@ ptr,ptp PC8E paper tape reader/punch + 30-May-02 RMS Widened POS to 32b 30-Nov-01 RMS Added read only unit support 30-Mar-98 RMS Added RIM loader as PTR bootstrap */ @@ -55,7 +56,7 @@ REG ptr_reg[] = { { FLDATA (DONE, dev_done, INT_V_PTR) }, { FLDATA (ENABLE, int_enable, INT_V_PTR) }, { FLDATA (INT, int_req, INT_V_PTR) }, - { DRDATA (POS, ptr_unit.pos, 31), PV_LEFT }, + { DRDATA (POS, ptr_unit.pos, 32), PV_LEFT }, { DRDATA (TIME, ptr_unit.wait, 24), PV_LEFT }, { FLDATA (STOP_IOE, ptr_stopioe, 0) }, { NULL } }; @@ -81,7 +82,7 @@ REG ptp_reg[] = { { FLDATA (DONE, dev_done, INT_V_PTP) }, { FLDATA (ENABLE, int_enable, INT_V_PTP) }, { FLDATA (INT, int_req, INT_V_PTP) }, - { DRDATA (POS, ptp_unit.pos, 31), PV_LEFT }, + { DRDATA (POS, ptp_unit.pos, 32), PV_LEFT }, { DRDATA (TIME, ptp_unit.wait, 24), PV_LEFT }, { FLDATA (STOP_IOE, ptp_stopioe, 0) }, { NULL } }; @@ -209,7 +210,7 @@ return SCPE_OK; /* Bootstrap routine */ #define BOOT_START 07756 -#define BOOT_LEN (sizeof (boot_rom) / sizeof (int)) +#define BOOT_LEN (sizeof (boot_rom) / sizeof (int32)) static const int32 boot_rom[] = { 06014, /* 7756, RFC */ diff --git a/PDP8/pdp8_rf.c b/PDP8/pdp8_rf.c index b7ef7228..e4cfa1b0 100644 --- a/PDP8/pdp8_rf.c +++ b/PDP8/pdp8_rf.c @@ -1,6 +1,6 @@ /* pdp8_rf.c: RF08 fixed head disk simulator - Copyright (c) 1993-2001, Robert M Supnik + Copyright (c) 1993-2002, Robert M Supnik Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), @@ -25,6 +25,7 @@ rf RF08 fixed head disk + 06-Nov-02 RMS Changed enable/disable support 28-Nov-01 RMS Added RL8A support 25-Apr-01 RMS Added device enable/disable support 19-Mar-01 RMS Added disk monitor bootstrap, fixed IOT decoding @@ -131,8 +132,13 @@ REG rf_reg[] = { { FLDATA (*DEVENB, dev_enb, INT_V_RF), REG_HRO }, { NULL } }; +MTAB rf_mod[] = { + { MTAB_XTD|MTAB_VDV, INT_RF, NULL, "ENABLED", &set_enb }, + { MTAB_XTD|MTAB_VDV, INT_RF, NULL, "DISABLED", &set_dsb }, + { 0 } }; + DEVICE rf_dev = { - "RF", &rf_unit, rf_reg, NULL, + "RF", &rf_unit, rf_reg, rf_mod, 1, 8, 20, 1, 8, 12, NULL, NULL, &rf_reset, &rf_boot, NULL, NULL }; diff --git a/PDP8/pdp8_rk.c b/PDP8/pdp8_rk.c index 5bf740f2..50c8d8ad 100644 --- a/PDP8/pdp8_rk.c +++ b/PDP8/pdp8_rk.c @@ -1,6 +1,6 @@ /* pdp8_rk.c: RK8E cartridge disk simulator - Copyright (c) 1993-2001, Robert M Supnik + Copyright (c) 1993-2002, Robert M Supnik Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), @@ -25,6 +25,7 @@ rk RK8E/RK05 cartridge disk + 06-Jan-02 RMS Changed enable/disable support 30-Nov-01 RMS Added read only unit, extended SET/SHOW support 24-Nov-01 RMS Converted FLG to array, made register names consistent 25-Apr-01 RMS Added device enable/disable support @@ -170,8 +171,10 @@ REG rk_reg[] = { { NULL } }; MTAB rk_mod[] = { - { UNIT_HWLK, 0, "write enabled", "ENABLED", NULL }, + { UNIT_HWLK, 0, "write enabled", "WRITEENABLED", NULL }, { UNIT_HWLK, UNIT_HWLK, "write locked", "LOCKED", NULL }, + { MTAB_XTD|MTAB_VDV, INT_RK, NULL, "ENABLED", &set_enb }, + { MTAB_XTD|MTAB_VDV, INT_RK, NULL, "DISABLED", &set_dsb }, { 0 } }; DEVICE rk_dev = { diff --git a/PDP8/pdp8_rl.c b/PDP8/pdp8_rl.c index 2ca40dac..e0d7f56a 100644 --- a/PDP8/pdp8_rl.c +++ b/PDP8/pdp8_rl.c @@ -1,6 +1,6 @@ /* pdp8_rl.c: RL8A cartridge disk simulator - Copyright (c) 1993-2001, Robert M Supnik + Copyright (c) 1993-2002, Robert M Supnik Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), @@ -25,6 +25,7 @@ rl RL8A cartridge disk + 06-Jan-02 RMS Changed enable/disable support 30-Nov-01 RMS Cloned from RL11 The RL8A is a four drive cartridge disk subsystem. An RL01 drive @@ -218,7 +219,7 @@ REG rl_reg[] = { { NULL } }; MTAB rl_mod[] = { - { UNIT_WLK, 0, "write enabled", "ENABLED", NULL }, + { UNIT_WLK, 0, "write enabled", "WRITEENABLED", NULL }, { UNIT_WLK, UNIT_WLK, "write locked", "LOCKED", NULL }, { UNIT_DUMMY, 0, NULL, "BADBLOCK", &rl_set_bad }, { (UNIT_RL02+UNIT_ATT), UNIT_ATT, "RL01", NULL, NULL }, @@ -229,6 +230,8 @@ MTAB rl_mod[] = { { UNIT_AUTO, UNIT_AUTO, NULL, "AUTOSIZE", NULL }, { (UNIT_AUTO+UNIT_RL02), 0, NULL, "RL01", &rl_set_size }, { (UNIT_AUTO+UNIT_RL02), UNIT_RL02, NULL, "RL02", &rl_set_size }, + { MTAB_XTD|MTAB_VDV, INT_RL, NULL, "ENABLED", &set_enb }, + { MTAB_XTD|MTAB_VDV, INT_RL, NULL, "DISABLED", &set_dsb }, { 0 } }; DEVICE rl_dev = { diff --git a/PDP8/pdp8_rx.c b/PDP8/pdp8_rx.c index 20ecdccf..fde74076 100644 --- a/PDP8/pdp8_rx.c +++ b/PDP8/pdp8_rx.c @@ -1,6 +1,6 @@ /* pdp8_rx.c: RX8E/RX01 floppy disk simulator - Copyright (c) 1993-2001, Robert M Supnik + Copyright (c) 1993-2002, Robert M Supnik Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), @@ -25,6 +25,7 @@ rx RX8E/RX01 floppy disk + 06-Jan-02 RMS Changed enable/disable support 30-Nov-01 RMS Added read only unit, extended SET/SHOW support 24-Nov-01 RMS Converted FLG to array 17-Jul-01 RMS Fixed warning from VC++ 6 @@ -146,8 +147,10 @@ REG rx_reg[] = { { NULL } }; MTAB rx_mod[] = { - { UNIT_WLK, 0, "write enabled", "ENABLED", NULL }, + { UNIT_WLK, 0, "write enabled", "WRITEENABLED", NULL }, { UNIT_WLK, UNIT_WLK, "write locked", "LOCKED", NULL }, + { MTAB_XTD|MTAB_VDV, INT_RX, NULL, "ENABLED", &set_enb }, + { MTAB_XTD|MTAB_VDV, INT_RX, NULL, "DISABLED", &set_dsb }, { 0 } }; DEVICE rx_dev = { diff --git a/PDP8/pdp8_sys.c b/PDP8/pdp8_sys.c index bc33e52d..c484a717 100644 --- a/PDP8/pdp8_sys.c +++ b/PDP8/pdp8_sys.c @@ -1,6 +1,6 @@ /* pdp8_sys.c: PDP-8 simulator interface - Copyright (c) 1993-2001, Robert M Supnik + Copyright (c) 1993-2002, Robert M Supnik Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), @@ -23,6 +23,7 @@ be used in advertising or otherwise to promote the sale, use or other dealings in this Software without prior written authorization from Robert M Supnik. + 30-Dec-01 RMS Revised for new TTX 26-Nov-01 RMS Added RL8A support 17-Sep-01 RMS Removed multiconsole support 16-Sep-01 RMS Added TSS/8 packed char support, added KL8A support @@ -48,10 +49,7 @@ extern DEVICE rk_dev, rl_dev; extern DEVICE rx_dev; extern DEVICE df_dev, rf_dev; extern DEVICE dt_dev, mt_dev; -extern DEVICE tti1_dev, tto1_dev; -extern DEVICE tti2_dev, tto2_dev; -extern DEVICE tti3_dev, tto3_dev; -extern DEVICE tti4_dev, tto4_dev; +extern DEVICE ttix_dev, ttox_dev; extern REG cpu_reg[]; extern uint16 M[]; extern int32 sim_switches; @@ -77,10 +75,7 @@ DEVICE *sim_devices[] = { &cpu_dev, &ptr_dev, &ptp_dev, &tti_dev, &tto_dev, - &tti1_dev, &tto1_dev, - &tti2_dev, &tto2_dev, - &tti3_dev, &tto3_dev, - &tti4_dev, &tto4_dev, + &ttix_dev, &ttox_dev, &clk_dev, &lpt_dev, &rk_dev, &rl_dev, &rx_dev, diff --git a/PDP8/pdp8_tt.c b/PDP8/pdp8_tt.c index 3dc05940..26bb6f7a 100644 --- a/PDP8/pdp8_tt.c +++ b/PDP8/pdp8_tt.c @@ -1,6 +1,6 @@ /* pdp8_tt.c: PDP-8 console terminal simulator - Copyright (c) 1993-2001, Robert M Supnik + Copyright (c) 1993-2002, Robert M Supnik Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), @@ -25,6 +25,7 @@ tti,tto KL8E terminal input/output + 30-May-02 RMS Widened POS to 32b 07-Sep-01 RMS Moved function prototypes */ @@ -54,7 +55,7 @@ REG tti_reg[] = { { FLDATA (DONE, dev_done, INT_V_TTI) }, { FLDATA (ENABLE, int_enable, INT_V_TTI) }, { FLDATA (INT, int_req, INT_V_TTI) }, - { DRDATA (POS, tti_unit.pos, 31), PV_LEFT }, + { DRDATA (POS, tti_unit.pos, 32), PV_LEFT }, { DRDATA (TIME, tti_unit.wait, 24), REG_NZ + PV_LEFT }, { FLDATA (UC, tti_unit.flags, UNIT_V_UC), REG_HRO }, { NULL } }; @@ -84,7 +85,7 @@ REG tto_reg[] = { { FLDATA (DONE, dev_done, INT_V_TTO) }, { FLDATA (ENABLE, int_enable, INT_V_TTO) }, { FLDATA (INT, int_req, INT_V_TTO) }, - { DRDATA (POS, tto_unit.pos, 31), PV_LEFT }, + { DRDATA (POS, tto_unit.pos, 32), PV_LEFT }, { DRDATA (TIME, tto_unit.wait, 24), PV_LEFT }, { NULL } }; diff --git a/PDP8/pdp8_ttx.c b/PDP8/pdp8_ttx.c index ba5bf5f4..e22742f9 100644 --- a/PDP8/pdp8_ttx.c +++ b/PDP8/pdp8_ttx.c @@ -1,6 +1,6 @@ /* pdp8_ttx.c: PDP-8 additional terminals simulator - Copyright (c) 1993-2001, Robert M Supnik + Copyright (c) 1993-2002, Robert M Supnik Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), @@ -25,6 +25,8 @@ ttix,ttox PT08/KL8JA terminal input/output + 06-Jan-02 RMS Added device enable/disable support + 30-Dec-01 RMS Complete rebuild 30-Nov-01 RMS Added extended SET/SHOW support This module implements four individual serial interfaces similar in function @@ -44,15 +46,13 @@ #define UNIT_UC (1 << UNIT_V_UC) #define TTX_GETLN(x) (((x) >> 4) & TTX_MASK) -extern int32 int_req, int_enable, dev_done, stop_inst; -extern int32 tmxr_poll; /* calibrated poll */ -TMLN tt1_ldsc = { 0 }; /* line descriptors */ -TMLN tt2_ldsc = { 0 }; /* line descriptors */ -TMLN tt3_ldsc = { 0 }; /* line descriptors */ -TMLN tt4_ldsc = { 0 }; /* line descriptors */ - +extern int32 int_req, int_enable, dev_done, dev_enb, stop_inst; +uint8 ttix_buf[TTX_LINES] = { 0 }; /* input buffers */ +uint8 ttox_buf[TTX_LINES] = { 0 }; /* output buffers */ +int32 ttx_tps = 100; /* polls per second */ +TMLN ttx_ldsc[TTX_LINES] = { 0 }; /* line descriptors */ TMXR ttx_desc = { /* mux descriptor */ - TTX_LINES, 0, &tt1_ldsc, &tt2_ldsc, &tt3_ldsc, &tt4_ldsc }; + TTX_LINES, 0, &ttx_ldsc[0], &ttx_ldsc[1], &ttx_ldsc[2], &ttx_ldsc[3] }; t_stat ttix_svc (UNIT *uptr); t_stat ttix_reset (DEVICE *dptr); @@ -60,7 +60,8 @@ t_stat ttox_svc (UNIT *uptr); t_stat ttox_reset (DEVICE *dptr); t_stat ttx_attach (UNIT *uptr, char *cptr); t_stat ttx_detach (UNIT *uptr); -t_stat ttx_status (FILE *st, UNIT *uptr, int32 val, void *desc); +t_stat ttx_summ (FILE *st, UNIT *uptr, int32 val, void *desc); +t_stat ttx_show (FILE *st, UNIT *uptr, int32 val, void *desc); /* TTIx data structures @@ -70,89 +71,36 @@ t_stat ttx_status (FILE *st, UNIT *uptr, int32 val, void *desc); ttix_mod TTIx modifiers list */ -MTAB ttix_mod[] = { - { UNIT_UC, 0, "lower case", "LC", NULL }, - { UNIT_UC, UNIT_UC, "upper case", "UC", NULL }, - { UNIT_ATT, UNIT_ATT, "line status", NULL, NULL, &ttx_status }, - { MTAB_XTD | MTAB_VDV | MTAB_NMO, 0, "LINESTATUS", NULL, - NULL, &ttx_status, NULL }, - { 0 } }; +UNIT ttix_unit = { UDATA (&ttix_svc, UNIT_ATTABLE, 0), KBD_POLL_WAIT }; -UNIT ttix_unit[] = { - { UDATA (&ttix_svc, UNIT_ATTABLE+UNIT_UC, 0), KBD_POLL_WAIT }, - { UDATA (&ttix_svc, UNIT_UC, 0), KBD_POLL_WAIT }, - { UDATA (&ttix_svc, UNIT_UC, 0), KBD_POLL_WAIT }, - { UDATA (&ttix_svc, UNIT_UC, 0), KBD_POLL_WAIT } }; - -#define tti1_unit ttix_unit[0] -#define tti2_unit ttix_unit[1] -#define tti3_unit ttix_unit[2] -#define tti4_unit ttix_unit[3] - -REG tti1_reg[] = { - { ORDATA (BUF, tti1_unit.buf, 8) }, - { FLDATA (DONE, dev_done, INT_V_TTI1) }, - { FLDATA (ENABLE, int_enable, INT_V_TTI1) }, - { FLDATA (INT, int_req, INT_V_TTI1) }, - { DRDATA (POS, tt1_ldsc.rxcnt, 32), PV_LEFT }, - { DRDATA (TIME, tti1_unit.wait, 24), REG_NZ + PV_LEFT }, - { FLDATA (UC, tti1_unit.flags, UNIT_V_UC), REG_HRO }, +REG ttix_reg[] = { + { BRDATA (BUF, ttix_buf, 8, 8, TTX_LINES) }, + { GRDATA (DONE, dev_done, 8, TTX_LINES, INT_V_TTI1) }, + { GRDATA (ENABLE, int_enable, 8, TTX_LINES, INT_V_TTI1) }, + { GRDATA (INT, int_req, 8, TTX_LINES, INT_V_TTI1) }, + { DRDATA (TIME, ttix_unit.wait, 24), REG_NZ + PV_LEFT }, + { DRDATA (TPS, ttx_tps, 10), REG_NZ + PV_LEFT }, + { FLDATA (*DEVENB, dev_enb, INT_V_TTI1), REG_HRO }, { NULL } }; -DEVICE tti1_dev = { - "TTI1", &tti1_unit, tti1_reg, ttix_mod, +MTAB ttix_mod[] = { + { UNIT_ATT, UNIT_ATT, "summary", NULL, NULL, &ttx_summ }, + { MTAB_XTD | MTAB_VDV, 1, NULL, "DISCONNECT", + &tmxr_dscln, NULL, &ttx_desc }, + { MTAB_XTD | MTAB_VDV | MTAB_NMO, 1, "CONNECTIONS", NULL, + NULL, &ttx_show, NULL }, + { MTAB_XTD | MTAB_VDV | MTAB_NMO, 0, "STATISTICS", NULL, + NULL, &ttx_show, NULL }, + { MTAB_XTD|MTAB_VDV, INT_TTI1, NULL, "ENABLED", &set_enb }, + { MTAB_XTD|MTAB_VDV, INT_TTI1, NULL, "DISABLED", &set_dsb }, + { 0 } }; + +DEVICE ttix_dev = { + "TTIX", &ttix_unit, ttix_reg, ttix_mod, 1, 10, 31, 1, 8, 8, &tmxr_ex, &tmxr_dep, &ttix_reset, NULL, &ttx_attach, &ttx_detach }; -REG tti2_reg[] = { - { ORDATA (BUF, tti2_unit.buf, 8) }, - { FLDATA (DONE, dev_done, INT_V_TTI2) }, - { FLDATA (ENABLE, int_enable, INT_V_TTI2) }, - { FLDATA (INT, int_req, INT_V_TTI2) }, - { DRDATA (POS, tt2_ldsc.rxcnt, 32), PV_LEFT }, - { DRDATA (TIME, tti2_unit.wait, 24), REG_NZ + PV_LEFT }, - { FLDATA (UC, tti2_unit.flags, UNIT_V_UC), REG_HRO }, - { NULL } }; - -DEVICE tti2_dev = { - "TTI2", &tti2_unit, tti2_reg, ttix_mod, - 1, 10, 31, 1, 8, 8, - NULL, NULL, &ttix_reset, - NULL, NULL, NULL }; - -REG tti3_reg[] = { - { ORDATA (BUF, tti3_unit.buf, 8) }, - { FLDATA (DONE, dev_done, INT_V_TTI3) }, - { FLDATA (ENABLE, int_enable, INT_V_TTI3) }, - { FLDATA (INT, int_req, INT_V_TTI3) }, - { DRDATA (POS, tt3_ldsc.rxcnt, 32), PV_LEFT }, - { DRDATA (TIME, tti3_unit.wait, 24), REG_NZ + PV_LEFT }, - { FLDATA (UC, tti3_unit.flags, UNIT_V_UC), REG_HRO }, - { NULL } }; - -DEVICE tti3_dev = { - "TTI3", &tti3_unit, tti3_reg, ttix_mod, - 1, 10, 31, 1, 8, 8, - NULL, NULL, &ttix_reset, - NULL, NULL, NULL }; - -REG tti4_reg[] = { - { ORDATA (BUF, tti4_unit.buf, 8) }, - { FLDATA (DONE, dev_done, INT_V_TTI4) }, - { FLDATA (ENABLE, int_enable, INT_V_TTI4) }, - { FLDATA (INT, int_req, INT_V_TTI4) }, - { DRDATA (POS, tt4_ldsc.rxcnt, 32), PV_LEFT }, - { DRDATA (TIME, tti4_unit.wait, 24), REG_NZ + PV_LEFT }, - { FLDATA (UC, tti4_unit.flags, UNIT_V_UC), REG_HRO }, - { NULL } }; - -DEVICE tti4_dev = { - "TTI4", &tti4_unit, tti4_reg, ttix_mod, - 1, 10, 31, 1, 8, 8, - NULL, NULL, &ttix_reset, - NULL, NULL, NULL }; - /* TTOx data structures ttox_dev TTOx device descriptor @@ -161,73 +109,31 @@ DEVICE tti4_dev = { */ UNIT ttox_unit[] = { - { UDATA (&ttox_svc, 0, 0), SERIAL_OUT_WAIT }, - { UDATA (&ttox_svc, 0, 0), SERIAL_OUT_WAIT }, - { UDATA (&ttox_svc, 0, 0), SERIAL_OUT_WAIT }, - { UDATA (&ttox_svc, 0, 0), SERIAL_OUT_WAIT } }; + { UDATA (&ttox_svc, UNIT_UC, 0), SERIAL_OUT_WAIT }, + { UDATA (&ttox_svc, UNIT_UC, 0), SERIAL_OUT_WAIT }, + { UDATA (&ttox_svc, UNIT_UC, 0), SERIAL_OUT_WAIT }, + { UDATA (&ttox_svc, UNIT_UC, 0), SERIAL_OUT_WAIT } }; -#define tto1_unit ttox_unit[0] -#define tto2_unit ttox_unit[0] -#define tto3_unit ttox_unit[0] -#define tto4_unit ttox_unit[0] - -REG tto1_reg[] = { - { ORDATA (BUF, tto1_unit.buf, 8) }, - { FLDATA (DONE, dev_done, INT_V_TTO1) }, - { FLDATA (ENABLE, int_enable, INT_V_TTO1) }, - { FLDATA (INT, int_req, INT_V_TTO1) }, - { DRDATA (POS, tt1_ldsc.txcnt, 32), PV_LEFT }, - { DRDATA (TIME, tto1_unit.wait, 24), PV_LEFT }, +REG ttox_reg[] = { + { BRDATA (BUF, ttox_buf, 8, 8, TTX_LINES) }, + { GRDATA (DONE, dev_done, 8, TTX_LINES, INT_V_TTO1) }, + { GRDATA (ENABLE, int_enable, 8, TTX_LINES, INT_V_TTO1) }, + { GRDATA (INT, int_req, 8, TTX_LINES, INT_V_TTO1) }, + { URDATA (TIME, ttox_unit[0].wait, 10, 24, 0, + TTX_LINES, PV_LEFT) }, + { URDATA (FLGS, ttox_unit[0].flags, 8, 1, UNIT_V_UC, + TTX_LINES, REG_HRO) }, + { FLDATA (*DEVENB, dev_enb, INT_V_TTI1), REG_HRO }, { NULL } }; -DEVICE tto1_dev = { - "TTO1", &tto1_unit, tto1_reg, NULL, - 1, 10, 31, 1, 8, 8, - NULL, NULL, &ttox_reset, - NULL, NULL, NULL }; +MTAB ttox_mod[] = { + { UNIT_UC, 0, "lower case", "LC", NULL }, + { UNIT_UC, UNIT_UC, "upper case", "UC", NULL }, + { 0 } }; -REG tto2_reg[] = { - { ORDATA (BUF, tto2_unit.buf, 8) }, - { FLDATA (DONE, dev_done, INT_V_TTO2) }, - { FLDATA (ENABLE, int_enable, INT_V_TTO2) }, - { FLDATA (INT, int_req, INT_V_TTO2) }, - { DRDATA (POS, tt2_ldsc.txcnt, 32), PV_LEFT }, - { DRDATA (TIME, tto2_unit.wait, 24), PV_LEFT }, - { NULL } }; - -DEVICE tto2_dev = { - "TTO2", &tto2_unit, tto2_reg, NULL, - 1, 10, 31, 1, 8, 8, - NULL, NULL, &ttox_reset, - NULL, NULL, NULL }; - -REG tto3_reg[] = { - { ORDATA (BUF, tto3_unit.buf, 8) }, - { FLDATA (DONE, dev_done, INT_V_TTO3) }, - { FLDATA (ENABLE, int_enable, INT_V_TTO3) }, - { FLDATA (INT, int_req, INT_V_TTO3) }, - { DRDATA (POS, tt3_ldsc.txcnt, 32), PV_LEFT }, - { DRDATA (TIME, tto3_unit.wait, 24), PV_LEFT }, - { NULL } }; - -DEVICE tto3_dev = { - "TTO3", &tto3_unit, tto3_reg, NULL, - 1, 10, 31, 1, 8, 8, - NULL, NULL, &ttox_reset, - NULL, NULL, NULL }; - -REG tto4_reg[] = { - { ORDATA (BUF, tto4_unit.buf, 8) }, - { FLDATA (DONE, dev_done, INT_V_TTO4) }, - { FLDATA (ENABLE, int_enable, INT_V_TTO4) }, - { FLDATA (INT, int_req, INT_V_TTO4) }, - { DRDATA (POS, tt4_ldsc.txcnt, 32), PV_LEFT }, - { DRDATA (TIME, tto4_unit.wait, 24), PV_LEFT }, - { NULL } }; - -DEVICE tto4_dev = { - "TTO4", &tto4_unit, tto4_reg, NULL, - 1, 10, 31, 1, 8, 8, +DEVICE ttox_dev = { + "TTOX", ttox_unit, ttox_reg, ttox_mod, + 4, 10, 31, 1, 8, 8, NULL, NULL, &ttox_reset, NULL, NULL, NULL }; @@ -252,7 +158,7 @@ case 2: /* KCC */ int_req = int_req & ~itti; return 0; /* clear AC */ case 4: /* KRS */ - return (AC | ttix_unit[ln].buf); /* return buf */ + return (AC | ttix_buf[ln]); /* return buf */ case 5: /* KIE */ if (AC & 1) int_enable = int_enable | (itti + itto); else int_enable = int_enable & ~(itti + itto); @@ -261,7 +167,7 @@ case 5: /* KIE */ case 6: /* KRB */ dev_done = dev_done & ~itti; /* clear flag */ int_req = int_req & ~itti; - return ttix_unit[ln].buf; /* return buf */ + return ttix_buf[ln]; /* return buf */ default: return (stop_inst << IOT_V_REASON) + AC; } /* end switch */ return AC; @@ -271,26 +177,24 @@ return AC; t_stat ttix_svc (UNIT *uptr) { -int32 temp, newln; -int32 ln = uptr - ttix_unit; /* line # */ -int32 itti = (INT_TTI1 << ln); /* rx intr */ +int32 ln, c, temp; -if (ttx_desc.ldsc[ln] -> conn) { /* connected? */ - tmxr_poll_rx (&ttx_desc); /* poll for input */ - if (temp = tmxr_getc_ln (ttx_desc.ldsc[ln])) { /* get char */ - temp = temp & 0177; /* mask to 7b */ - if ((uptr -> flags & UNIT_UC) && islower (temp)) - temp = toupper (temp); - uptr -> buf = temp | 0200; /* Teletype code */ - dev_done = dev_done | itti; /* set done */ - int_req = INT_UPDATE; } /* update intr */ - sim_activate (uptr, uptr -> wait); } /* continue poll */ -if (uptr -> flags & UNIT_ATT) { /* attached? */ - newln = tmxr_poll_conn (&ttx_desc, uptr); /* poll connect */ - if (newln >= 0) { /* got one? */ - sim_activate (&ttix_unit[newln], ttix_unit[newln].wait); - ttx_desc.ldsc[newln] -> rcve = 1; } /* rcv enabled */ - sim_activate (uptr, tmxr_poll); } /* sched poll */ +if ((uptr -> flags & UNIT_ATT) == 0) return SCPE_OK; /* attached? */ +temp = sim_rtcn_calb (ttx_tps, TMR_TTX); /* calibrate */ +sim_activate (uptr, temp); /* continue poll */ +ln = tmxr_poll_conn (&ttx_desc, uptr); /* look for connect */ +if (ln >= 0) { /* got one? */ + ttx_ldsc[ln].rcve = 1; } /* rcv enabled */ +tmxr_poll_rx (&ttx_desc); /* poll for input */ +for (ln = 0; ln < TTX_LINES; ln++) { /* loop thru lines */ + if (ttx_ldsc[ln].conn) { /* connected? */ + if (temp = tmxr_getc_ln (&ttx_ldsc[ln])) { /* get char */ + c = temp & 0177; + if ((ttox_unit[ln].flags & UNIT_UC) && islower (c)) + c = toupper (c); + ttix_buf[ln] = c; + dev_done = dev_done | (INT_TTI1 << ln); + int_req = INT_UPDATE; } } } return SCPE_OK; } @@ -298,20 +202,19 @@ return SCPE_OK; t_stat ttix_reset (DEVICE *dptr) { -UNIT *uptr = dptr -> units; /* unit */ -int32 ln = uptr - ttix_unit; /* line # */ -int32 itti = (INT_TTI1 << ln); /* rx intr */ +int32 t, ln, itto; -uptr -> buf = 0; /* clr buf */ -dev_done = dev_done & ~itti; /* clr done, int */ -int_req = int_req & ~itti; -int_enable = int_enable | itti; /* set enable */ -if (ttx_desc.ldsc[ln] -> conn) { /* if conn, */ - sim_activate (uptr, uptr -> wait); /* activate, */ - ttx_desc.ldsc[ln] -> rcve = 1; } /* enable */ -else if (uptr -> flags & UNIT_ATT) /* if attached, */ - sim_activate (uptr, tmxr_poll); /* activate */ -else sim_cancel (uptr); /* else stop */ +if (ttix_unit.flags & UNIT_ATT) { /* if attached, */ + if (!sim_is_active (&ttix_unit)) { + t = sim_rtcn_init (ttix_unit.wait, TMR_TTX); + sim_activate (&ttix_unit, t); } } /* activate */ +else sim_cancel (&ttix_unit); /* else stop */ +for (ln = 0; ln < TTX_LINES; ln++) { /* for all lines */ + ttix_buf[ln] = 0; /* clear buf, */ + itto = (INT_TTI1 << ln); /* interrupt */ + dev_done = dev_done & ~itto; /* clr done, int */ + int_req = int_req & ~itto; + int_enable = int_enable | itto; } /* set enable */ return SCPE_OK; } @@ -342,7 +245,7 @@ case 6: /* TLS */ int_req = int_req & ~itto; /* clear int req */ case 4: /* TPC */ sim_activate (&ttox_unit[ln], ttox_unit[ln].wait); /* activate */ - ttox_unit[ln].buf = AC & 0377; /* load buffer */ + ttox_buf[ln] = AC & 0377; /* load buffer */ break; default: return (stop_inst << IOT_V_REASON) + AC; } /* end switch */ @@ -353,18 +256,20 @@ return AC; t_stat ttox_svc (UNIT *uptr) { -int32 ln = uptr - ttox_unit; /* line # */ -int32 itto = (INT_TTO1 << ln); /* tx intr */ +int32 c, ln = uptr - ttox_unit; /* line # */ if (ttx_desc.ldsc[ln] -> conn) { /* connected? */ if (ttx_desc.ldsc[ln] -> xmte) { /* tx enabled? */ TMLN *lp = ttx_desc.ldsc[ln]; /* get line */ - tmxr_putc_ln (lp, uptr -> buf & 0177); /* output char */ + c = ttox_buf[ln] & 0177; /* get char */ + if ((ttox_unit[ln].flags & UNIT_UC) && islower (c)) + c = toupper (c); + tmxr_putc_ln (lp, c); /* output char */ tmxr_poll_tx (&ttx_desc); } /* poll xmt */ else { tmxr_poll_tx (&ttx_desc); /* poll xmt */ - sim_activate (uptr, tmxr_poll); /* wait */ + sim_activate (uptr, ttox_unit[ln].wait); /* wait */ return SCPE_OK; } } -dev_done = dev_done | itto; /* set done */ +dev_done = dev_done | (INT_TTO1 << ln); /* set done */ int_req = INT_UPDATE; /* update intr */ return SCPE_OK; } @@ -373,15 +278,15 @@ return SCPE_OK; t_stat ttox_reset (DEVICE *dptr) { -UNIT *uptr = dptr -> units; /* unit */ -int32 ln = uptr - ttox_unit; /* line # */ -int32 itto = (INT_TTO1 << ln); /* tx intr */ +int32 ln, itto; -uptr -> buf = 0; /* clr buf */ -dev_done = dev_done & ~itto; /* clr done, int */ -int_req = int_req & ~itto; -int_enable = int_enable | itto; /* set enable */ -sim_cancel (uptr); /* deactivate */ +for (ln = 0; ln < TTX_LINES; ln++) { /* for all lines */ + ttox_buf[ln] = 0; /* clear buf */ + itto = (INT_TTO1 << ln); /* interrupt */ + dev_done = dev_done & ~itto; /* clr done, int */ + int_req = int_req & ~itto; + int_enable = int_enable | itto; /* set enable */ + sim_cancel (&ttox_unit[ln]); } /* deactivate */ return SCPE_OK; } @@ -389,11 +294,13 @@ return SCPE_OK; t_stat ttx_attach (UNIT *uptr, char *cptr) { +int32 t; t_stat r; r = tmxr_attach (&ttx_desc, uptr, cptr); /* attach */ if (r != SCPE_OK) return r; /* error */ -sim_activate (uptr, tmxr_poll); /* start poll */ +t = sim_rtcn_init (ttix_unit.wait, TMR_TTX); /* init calib */ +sim_activate (uptr, t); /* start poll */ return SCPE_OK; } @@ -407,22 +314,34 @@ t_stat r; r = tmxr_detach (&ttx_desc, uptr); /* detach */ for (i = 0; i < TTX_LINES; i++) { /* all lines, */ ttx_desc.ldsc[i] -> rcve = 0; /* disable rcv */ - sim_cancel (&ttix_unit[i]); } /* stop poll */ + sim_cancel (&ttox_unit[i]); } /* stop poll */ return SCPE_OK; } -/* Status */ +/* Show summary processor */ -t_stat ttx_status (FILE *st, UNIT *uptr, int32 val, void *desc) +t_stat ttx_summ (FILE *st, UNIT *uptr, int32 val, void *desc) +{ +int32 i, t; + +for (i = t = 0; i < TTX_LINES; i++) t = t + (ttx_ldsc[i].conn != 0); +if (t == 1) fprintf (st, "1 connection"); +else fprintf (st, "%d connections", t); +return SCPE_OK; +} + +/* SHOW CONN/STAT processor */ + +t_stat ttx_show (FILE *st, UNIT *uptr, int32 val, void *desc) { int32 i; -fprintf (st, "line status:"); -for (i = 0; (i < TTX_LINES) && (ttx_desc.ldsc[i] -> conn == 0); i++) ; +for (i = 0; (i < TTX_LINES) && (ttx_ldsc[i].conn == 0); i++) ; if (i < TTX_LINES) { - for (i = 0; i < TTX_LINES; i++) { - if (ttx_desc.ldsc[i] -> conn) - tmxr_fstatus (st, ttx_desc.ldsc[i], i); } } -else fprintf (st, " all disconnected"); + for (i = 0; i < TTX_LINES; i++) { + if (ttx_ldsc[i].conn) + if (val) tmxr_fconns (st, &ttx_ldsc[i], i); + else tmxr_fstats (st, &ttx_ldsc[i], i); } } +else fprintf (st, "all disconnected\n"); return SCPE_OK; } diff --git a/S3/s3_cd.c b/S3/s3_cd.c index c3ed759a..d5ed05f2 100644 --- a/S3/s3_cd.c +++ b/S3/s3_cd.c @@ -32,7 +32,6 @@ This allows cards to be created and edited as normal files. Set the EBCDIC flag on the card unit allows cards to be read or punched in EBCDIC format, suitable for binary data. - */ #include "s3_defs.h" @@ -47,6 +46,8 @@ t_stat cdr_svc (UNIT *uptr); t_stat cdr_boot (int32 unitno); t_stat cdr_attach (UNIT *uptr, char *cptr); t_stat cd_reset (DEVICE *dptr); +t_stat read_card (int32 ilnt, int32 mod); +t_stat punch_card (int32 ilnt, int32 mod); int32 DAR; /* Data address register */ int32 LCR; /* Length Count Register */ @@ -57,6 +58,9 @@ int32 notready = 0; /* Not ready error */ int32 cdr_ebcdic = 0; /* EBCDIC mode on reader */ int32 cdp_ebcdic = 0; /* EBCDIC mode on punch */ +extern int32 GetMem(int32 addr); +extern int32 PutMem(int32 addr, int32 data); + /* Card reader data structures cdr_dev CDR descriptor @@ -75,7 +79,7 @@ REG cdr_reg[] = { { HRDATA (LCR, LCR, 16) }, { FLDATA (EBCDIC, cdr_ebcdic, 0) }, { FLDATA (S2, s2sel, 0) }, - { DRDATA (POS, cdr_unit.pos, 31), PV_LEFT }, + { DRDATA (POS, cdr_unit.pos, 32), PV_LEFT }, { DRDATA (TIME, cdr_unit.wait, 24), PV_LEFT }, { BRDATA (BUF, rbuf, 8, 8, CDR_WIDTH) }, { NULL } }; @@ -103,7 +107,7 @@ REG cdp_reg[] = { { FLDATA (NOTRDY, notready, 0) }, { HRDATA (DAR, DAR, 16) }, { HRDATA (LCR, LCR, 16) }, - { DRDATA (POS, cdp_unit.pos, 31), PV_LEFT }, + { DRDATA (POS, cdp_unit.pos, 32), PV_LEFT }, { NULL } }; DEVICE cdp_dev = { @@ -123,7 +127,7 @@ UNIT stack_unit[] = { { UDATA (NULL, UNIT_SEQ+UNIT_ATTABLE, 0) } }; REG stack_reg[] = { - { DRDATA (POS0, stack_unit[0].pos, 31), PV_LEFT }, + { DRDATA (POS0, stack_unit[0].pos, 32), PV_LEFT }, { NULL } }; DEVICE stack_dev = { @@ -261,7 +265,7 @@ int32 crd (int32 op, int32 m, int32 n, int32 data) t_stat read_card (int32 ilnt, int32 mod) { -int32 i, cnt; +int32 i; t_stat r; if (sim_is_active (&cdr_unit)) { /* busy? */ diff --git a/S3/s3_cpu.c b/S3/s3_cpu.c index b0f1859c..d125d9bc 100644 --- a/S3/s3_cpu.c +++ b/S3/s3_cpu.c @@ -392,13 +392,19 @@ extern int32 dsk1 (int32 op, int32 m, int32 n, int32 data); extern int32 dsk2 (int32 op, int32 m, int32 n, int32 data); extern int32 cpu (int32 op, int32 m, int32 n, int32 data); extern t_stat sim_activate (UNIT *uptr, int32 delay); +extern int32 fprint_sym (FILE *of, int32 addr, unsigned int32 *val, + UNIT *uptr, int32 sw); int32 nulldev (int32 opcode, int32 m, int32 n, int32 data); int add_zoned (int32 addr1, int32 len1, int32 addr2, int32 len2); int32 subtract_zoned (int32 addr1, int32 len1, int32 addr2, int32 len2); +static int32 compare(int32 byte1, int32 byte2, int32 cond); +static int32 condition(int32 qbyte); static void store_decimal (int32 addr, int32 len, uint8 *dec, int sign); static void load_decimal (int32 addr, int32 len, uint8 *result, int32 *count, int32 *sign); static void add_decimal (uint8 *dec1, uint8 *dec2, uint8 *result, int32 *count); static void subtract_decimal (uint8 *dec1, uint8 *dec2, uint8 *result, int *count, int *sign); +int32 GetMem(int32 addr); +int32 PutMem(int32 addr, int32 data); /* IOT dispatch table */ @@ -496,14 +502,12 @@ t_stat sim_instr (void) { extern int32 sim_interval; register int32 PC, IR; -int32 i, j, carry, zero, gt, f, op1, op2; +int32 i, j, carry, zero, op1, op2; int32 opcode = 0, qbyte = 0, rbyte = 0; int32 opaddr, addr1, addr2, dlen1, dlen2, r; int32 int_savelevel = 8, intpri, intlev, intdev, intmask; int32 devno, devm, devn; char display[3][9]; -char resp[2]; -char trstr[256]; int32 val [32]; register t_stat reason; @@ -1679,7 +1683,6 @@ static void load_decimal (int32 addr, int32 len, uint8 *result, int32 *count, in int h; /* Hexadecimal digit */ int i, j; /* Array subscripts */ int n; /* Significant digit counter */ -int s; if ((GetMem(addr) & 0xf0) == 0xD0) *sign = -1; diff --git a/S3/s3_disk.c b/S3/s3_disk.c index 573734fa..a4d9f795 100644 --- a/S3/s3_disk.c +++ b/S3/s3_disk.c @@ -38,6 +38,9 @@ extern int32 IAR[], level; extern FILE *trace; extern int32 debug_reg; char dbuf[DSK_SECTSIZE]; /* Disk buffer */ +int32 dsk (int32 disk, int32 op, int32 m, int32 n, int32 data); +int32 read_sector(UNIT *uptr, char *dbuf, int32 sect); +int32 write_sector(UNIT *uptr, char *dbuf, int32 sect); t_stat r1_svc (UNIT *uptr); t_stat r1_boot (int32 unitno); t_stat r1_attach (UNIT *uptr, char *cptr); @@ -54,6 +57,8 @@ t_stat f2_svc (UNIT *uptr); t_stat f2_boot (int32 unitno); t_stat f2_attach (UNIT *uptr, char *cptr); t_stat f2_reset (DEVICE *dptr); +extern int32 GetMem(int32 addr); +extern int32 PutMem(int32 addr, int32 data); char opstr[5][5] = { "SIO", "LIO", "TIO", "SNS", "APL" }; @@ -87,7 +92,7 @@ REG r1_reg[] = { { HRDATA (ERR, diskerr[0], 16) }, { DRDATA (CYL, r1_unit.u3, 8) }, { DRDATA (HEAD, seekhead[0], 8) }, - { DRDATA (POS, r1_unit.pos, 31), PV_LEFT }, + { DRDATA (POS, r1_unit.pos, 32), PV_LEFT }, { DRDATA (TIME, r1_unit.wait, 24), PV_LEFT }, { BRDATA (BUF, dbuf, 8, 8, 256) }, { NULL } }; @@ -109,7 +114,7 @@ REG f1_reg[] = { { HRDATA (ERR, diskerr[0], 16) }, { DRDATA (CYL, f1_unit.u3, 8) }, { DRDATA (HEAD, seekhead[0], 8) }, - { DRDATA (POS, f1_unit.pos, 31), PV_LEFT }, + { DRDATA (POS, f1_unit.pos, 32), PV_LEFT }, { DRDATA (TIME, f1_unit.wait, 24), PV_LEFT }, { BRDATA (BUF, dbuf, 8, 8, 256) }, { NULL } }; @@ -131,7 +136,7 @@ REG r2_reg[] = { { HRDATA (ERR, diskerr[1], 16) }, { DRDATA (CYL, r2_unit.u3, 8) }, { DRDATA (HEAD, seekhead[1], 8) }, - { DRDATA (POS, r2_unit.pos, 31), PV_LEFT }, + { DRDATA (POS, r2_unit.pos, 32), PV_LEFT }, { DRDATA (TIME, r2_unit.wait, 24), PV_LEFT }, { BRDATA (BUF, dbuf, 8, 8, 256) }, { NULL } }; @@ -153,7 +158,7 @@ REG f2_reg[] = { { HRDATA (ERR, diskerr[1], 16) }, { DRDATA (CYL, f2_unit.u3, 8) }, { DRDATA (HEAD, seekhead[1], 8) }, - { DRDATA (POS, f2_unit.pos, 31), PV_LEFT }, + { DRDATA (POS, f2_unit.pos, 32), PV_LEFT }, { DRDATA (TIME, f2_unit.wait, 24), PV_LEFT }, { BRDATA (BUF, dbuf, 8, 8, 256) }, { NULL } }; diff --git a/S3/s3_lp.c b/S3/s3_lp.c index 859b5015..e047fc0f 100644 --- a/S3/s3_lp.c +++ b/S3/s3_lp.c @@ -37,7 +37,9 @@ int32 cct[CCT_LNT] = { 03 }; int32 cctlnt = 66, cctptr = 0, lines = 0, lflag = 0; t_stat lpt_reset (DEVICE *dptr); t_stat lpt_attach (UNIT *uptr, char *cptr); +t_stat write_line (int32 ilnt, int32 mod); t_stat space (int32 lines, int32 lflag); +t_stat carriage_control (int32 action, int32 mod); extern unsigned char ebcdic_to_ascii[256]; #define UNIT_V_PCHAIN (UNIT_V_UF + 0) @@ -78,7 +80,7 @@ REG lpt_reg[] = { { HRDATA (LPFLR, LPFLR, 8) }, { HRDATA (LPIAR, LPIAR, 16) }, { DRDATA (LINECT, linectr, 8) }, - { DRDATA (POS, lpt_unit.pos, 31), PV_LEFT }, + { DRDATA (POS, lpt_unit.pos, 32), PV_LEFT }, { BRDATA (CCT, cct, 8, 32, CCT_LNT) }, { DRDATA (LINES, lines, 8), PV_LEFT }, { DRDATA (CCTP, cctptr, 8), PV_LEFT }, @@ -105,7 +107,7 @@ DEVICE lpt_dev = { int32 lpt (int32 op, int32 m, int32 n, int32 data) { - int32 iodata, c, ec, ac; + int32 iodata; switch (op) { case 0: /* SIO 1403 */ iodata = 0; @@ -209,7 +211,6 @@ int32 lpt (int32 op, int32 m, int32 n, int32 data) t_stat write_line (int32 ilnt, int32 mod) { int32 i, t, lc, sup; -char *pch; static char lbuf[LPT_WIDTH + 1]; /* + null */ if ((lpt_unit.flags & UNIT_ATT) == 0) diff --git a/S3/s3_pkb.c b/S3/s3_pkb.c index 2dc156ea..9f4c557e 100644 --- a/S3/s3_pkb.c +++ b/S3/s3_pkb.c @@ -23,6 +23,7 @@ */ #include "s3_defs.h" +#include extern int32 int_req, dev_busy, dev_done, dev_disable; t_stat pkb_svc (UNIT *uptr); @@ -69,7 +70,7 @@ REG pkb_reg[] = { { HRDATA (RTNKEY, key_rtn, 8) }, { HRDATA (CANKEY, key_can, 8) }, { HRDATA (ENDKEY, key_end, 8) }, - { DRDATA (POS, pkb_unit.pos, 31), PV_LEFT }, + { DRDATA (POS, pkb_unit.pos, 32), PV_LEFT }, { DRDATA (TIME, pkb_unit.wait, 24), REG_NZ + PV_LEFT }, { NULL } }; @@ -133,7 +134,7 @@ unsigned char ascii_to_ebcdic[] = { int32 pkb (int32 op, int32 m, int32 n, int32 data) { - int32 iodata= 0, c, ec, ac; + int32 iodata= 0, ec, ac; switch (op) { case 0: /* SIO 5471 */ if (n != 0) diff --git a/S3/s3_sys.c b/S3/s3_sys.c index fdbb277e..82b910f1 100644 --- a/S3/s3_sys.c +++ b/S3/s3_sys.c @@ -25,10 +25,9 @@ extern REG cpu_reg[]; extern unsigned char M[]; extern int32 saved_PC, IAR[]; extern char ebcdic_to_ascii[256]; -extern char *get_glyph (char *cptr, char *gbuf, char term); -extern unsigned int32 get_uint (char *cptr, int32 radix, unsigned int32 max, - int32 *status); char *parse_addr(char *cptr, char *gbuf, int32 *addr, int32 *addrtype); +int32 printf_sym (FILE *of, char *strg, int32 addr, unsigned int32 *val, + UNIT *uptr, int32 sw); /* SCP data structures @@ -247,9 +246,9 @@ int32 fprint_sym (FILE *of, int32 addr, unsigned int32 *val, int32 printf_sym (FILE *of, char *strg, int32 addr, unsigned int32 *val, UNIT *uptr, int32 sw) { -int32 cflag, c1, c2, group, len1, len2, inst, adr, aaddr, baddr; +int32 cflag, c1, c2, group, len1, len2, inst, aaddr, baddr; int32 oplen, groupno, i, j, vpos, qbyte, da, m, n; -char bld[128], bldaddr[32], boperand[32], aoperand[32], regoperand[32]; +char bld[128], bldaddr[32], boperand[32], aoperand[32]; int32 blk[16], blt[16]; int32 blkadd; @@ -481,7 +480,7 @@ return -(oplen - 1); int32 parse_sym (char *cptr, int32 addr, UNIT *uptr, unsigned int32 *val, int32 sw) { -int32 cflag, i = 0, j, k, r, oplen, addtyp, saveaddr, vptr; +int32 cflag, i = 0, j, r, oplen, addtyp, saveaddr, vptr; char gbuf[CBUFSIZE]; cflag = (uptr == NULL) || (uptr == &cpu_unit); diff --git a/VAX/ka655.bin b/VAX/ka655.bin new file mode 100644 index 00000000..1edd8b93 Binary files /dev/null and b/VAX/ka655.bin differ diff --git a/VAX/vax_cpu.c b/VAX/vax_cpu.c new file mode 100644 index 00000000..b4a6d9df --- /dev/null +++ b/VAX/vax_cpu.c @@ -0,0 +1,2343 @@ +/* vax_cpu.c: VAX CPU simulator + + Copyright (c) 1998-2002, Robert M Supnik + + Permission is hereby granted, free of charge, to any person obtaining a + copy of this software and associated documentation files (the "Software"), + to deal in the Software without restriction, including without limitation + the rights to use, copy, modify, merge, publish, distribute, sublicense, + and/or sell copies of the Software, and to permit persons to whom the + Software is furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + ROBERT M SUPNIK BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + Except as contained in this notice, the name of Robert M Supnik shall not + be used in advertising or otherwise to promote the sale, use or other dealings + in this Software without prior written authorization from Robert M Supnik. + + cpu CVAX central processor + + 14-Jul-02 RMS Added halt to console, infinite loop detection + (from Mark Pizzolato) + 02-May-02 RMS Fixed bug in indexed autoincrement register logging + 30-Apr-02 RMS Added TODR powerup routine + 18-Apr-02 RMS Cleanup ambiguous signed left shifts + 15-Apr-02 RMS Fixed bug in CASEL condition codes + + The register state for the VAX is: + + R[0:15] general registers + PSL<31:0> processor status longword + TP<30> trace pending + FPD<27> first part done + IS<26> interrupt stack + CM<25:24> current mode + PM<23:22> previous mode + IPL<20:16> interrupt priority level + PSW<15:0> non-privileged processor status word + DV<7> decimal overflow trap enable + FU<6> floating underflow fault enable + IV<5> integer overflow trap enable + T<4> trace trap enable + CC<3:0> condition codes + SCBB system control block base + PCBB process control block base + SBR system page table base + SLR system page table length + P0BR process region 0 page table base + P0LR process region 0 page table length + P1BR process region 1 page table base + P1LR process region 1 page table length + SIRR/SISR software interrupt request/summary register + ASTLVL AST level register + + The CVAX CPU adds a few specific IPRs: + + CADR cache disable register + MSER memory system error register +*/ + +/* The VAX has a variable length instruction format with up to six operands: + + opcode byte + operand 1 specifier + : + operand n specifier + + Each operand specifier is a byte consisting of an addressing mode, a + register, and possibly 1-8 bytes of extension: + + number name extension mnemonic operation + + 0-3 short literal - #n op <- specifier + 4 index - [Rn] index by Rn + 5 register - Rn op <- Rn + 6 register def - (Rn) op <- M[Rn] + 7 autodecrement - -(Rn) Rn <- Rn - length + op <- M[Rn] + 8 autoincrement - (Rn)+ op <- M[Rn] + Rn <- Rn + length + 9 auto deferred - @(Rn)+ op <- M[M[Rn]] + Rn <- Rn + 4 + A byte displ byte d d(Rn) op <- M[Rn + sxt.d] + B byte displ def byte d @d(Rn) op <- M[M[Rn + sxt.d]] + C word displ word d d(Rn) op <- M[Rn + sxt.d] + D word displ def word d @d(Rn) op <- M[M[Rn + sxt.d]] + E long displ long d d(Rn) op <- M[Rn + d] + F long displ def long d @d(Rn) op <- M[M[Rn + d]] + + When the general register is the PC, certain modes are forbidden, and + others have special interpretations: + + 4F index fault + 5F register fault + 6F register def fault + 7F autodecrement fault + 8F immediate 1-8B #imm op <- imm + 9 absolute 4B @#imm op <- M[imm] + A byte relative byte d d(Rn) op <- M[PC + sxt.d] + B byte rel def byte d @d(Rn) op <- M[M[PC + sxt.d]] + C word relative word d d(Rn) op <- M[PC + sxt.d] + D word rel def word d @d(Rn) op <- M[M[PC + sxt.d]] + E long relative long d d(Rn) op <- M[PC + d] + F long rel def long d @d(Rn) op <- M[M[PC + d]] +*/ + +/* This routine is the instruction decode routine for the VAX. 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 trpirq microencodes the outstanding + trap request (if any) and the level of the highest outstanding + interrupt (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. This requires modifications to three modules: + + vax_defs.h add interrupt request definitions + vax_mm.c add I/O page linkages + vax_sys.c add to sim_devices +*/ + +/* Definitions */ + +#include "vax_defs.h" + +#define OP_MEM -1 +#define UNIT_V_CONH (UNIT_V_UF + 0) /* halt to console */ +#define UNIT_V_MSIZE (UNIT_V_UF + 1) /* dummy */ +#define UNIT_CONH (1u << UNIT_V_CONH) +#define UNIT_MSIZE (1u << UNIT_V_MSIZE) +#define GET_CUR acc = ACC_MASK (PSL_GETCUR (PSL)) + +#define op0 opnd[0] +#define op1 opnd[1] +#define op2 opnd[2] +#define op3 opnd[3] +#define op4 opnd[4] +#define op5 opnd[5] +#define op6 opnd[6] +#define op7 opnd[7] +#define op8 opnd[8] +#define CHECK_FOR_PC if (rn == nPC) RSVD_ADDR_FAULT +#define CHECK_FOR_SP if (rn >= nSP) RSVD_ADDR_FAULT +#define RECW(l) ((l) << 4) | rn +#define WRITE_B(r) if (spec > (GRN | nPC)) Write (va, r, L_BYTE, WA); \ + else R[rn] = (R[rn] & ~BMASK) | ((r) & BMASK) +#define WRITE_W(r) if (spec > (GRN | nPC)) Write (va, r, L_WORD, WA); \ + else R[rn] = (R[rn] & ~WMASK) | ((r) & WMASK) +#define WRITE_L(r) if (spec > (GRN | nPC)) Write (va, r, L_LONG, WA); \ + else R[rn] = (r) +#define WRITE_Q(rl,rh) if (spec > (GRN | nPC)) { \ + if (Test (va + 7, WA, &mstat) >= 0) \ + Write (va, rl, L_LONG, WA); \ + Write (va + 4, rh, L_LONG, WA); } \ + else { R[rn] = rl; R[rnplus1] = rh; } + +uint32 *M = NULL; /* memory */ +int32 R[16]; /* registers */ +int32 STK[5]; /* stack pointers */ +int32 PSL; /* PSL */ +int32 SCBB = 0; /* SCB base */ +int32 PCBB = 0; /* PCB base */ +int32 P0BR = 0; /* P0 mem mgt */ +int32 P0LR = 0; +int32 P1BR = 0; /* P1 mem mgt */ +int32 P1LR = 0; +int32 SBR = 0; /* S0 mem mgt */ +int32 SLR = 0; +int32 SISR; /* swre int req */ +int32 ASTLVL; /* AST level */ +int32 CADR = 0; /* cache disable */ +int32 MSER = 0; /* mem error */ +int32 mapen; /* map enable */ +int32 trpirq; /* trap/intr req */ +int32 conpc, conpsl; /* console reg */ +int32 in_ie = 0; /* in exc, int */ +int32 recq[6]; /* recovery queue */ +int32 recqptr; /* recq pointer */ +int32 mem_err = 0; /* mem err intr */ +int32 crd_err = 0; /* CRD err intr */ +int32 p1 = 0, p2 = 0; /* fault parameters */ +int32 fault_PC; /* fault PC */ +int32 pcq[PCQ_SIZE] = { 0 }; /* PC queue */ +int32 pcq_p = 0; /* PC queue ptr */ +REG *pcq_r = NULL; /* PC queue reg ptr */ +int32 badabo = 0; +int32 cpu_astop = 0; +int32 dbg_stop = 0; +int32 mchk_va, mchk_ref; /* mem ref param */ +int32 ibufl, ibufh; /* prefetch buf */ +int32 ibcnt, ppc; /* prefetch ctl */ +int32 cpu_log = 0; /* logging */ +jmp_buf save_env; + +const uint32 byte_mask[33] = { 0x00000000, + 0x00000001, 0x00000003, 0x00000007, 0x0000000F, + 0x0000001F, 0x0000003F, 0x0000007F, 0x000000FF, + 0x000001FF, 0x000003FF, 0x000007FF, 0x00000FFF, + 0x00001FFF, 0x00003FFF, 0x00007FFF, 0x0000FFFF, + 0x0001FFFF, 0x0003FFFF, 0x0007FFFF, 0x000FFFFF, + 0x001FFFFF, 0x003FFFFF, 0x007FFFFF, 0x00FFFFFF, + 0x01FFFFFF, 0x03FFFFFF, 0x07FFFFFF, 0x0FFFFFFF, + 0x1FFFFFFF, 0x3FFFFFFF, 0x7FFFFFFF, 0xFFFFFFFF }; +const uint32 byte_sign[33] = { 0x00000000, + 0x00000001, 0x00000002, 0x00000004, 0x00000008, + 0x00000010, 0x00000020, 0x00000040, 0x00000080, + 0x00000100, 0x00000200, 0x00000400, 0x00000800, + 0x00001000, 0x00002000, 0x00004000, 0x00008000, + 0x00010000, 0x00020000, 0x00040000, 0x00080000, + 0x00100000, 0x00200000, 0x00400000, 0x00800000, + 0x01000000, 0x02000000, 0x04000000, 0x08000000, + 0x10000000, 0x20000000, 0x40000000, 0x80000000 }; +const uint32 align[4] = { + 0xFFFFFFFF, 0x00FFFFFF, 0x0000FFFF, 0x000000FF }; + +extern int32 sim_interval; +extern int32 sim_int_char; +extern int32 sim_brk_types, sim_brk_dflt, sim_brk_summ; /* breakpoint info */ +extern UNIT clk_unit; + +extern UNIT rom_unit, nvr_unit; +extern int32 op_ashq (int32 *opnd, int32 *rh, int32 *flg); +extern int32 op_emul (int32 mpy, int32 mpc, int32 *rh); +extern int32 op_ediv (int32 *opnd, int32 *rh, int32 *flg); +extern int32 op_bb_n (int32 *opnd, int32 acc); +extern int32 op_bb_x (int32 *opnd, int32 newb, int32 acc); +extern int32 op_extv (int32 *opnd, int32 vfldrp1, int32 acc); +extern int32 op_ffs (uint32 fld, int32 size); +extern void op_insv (int32 *opnd, int32 vfldrp1, int32 acc); +extern int32 op_call (int32 *opnd, t_bool gs, int32 acc); +extern int32 op_ret (int32 acc); +extern int32 op_insque (int32 *opnd, int32 acc); +extern int32 op_remque (int32 *opnd, int32 acc); +extern int32 op_insqhi (int32 *opnd, int32 acc); +extern int32 op_insqti (int32 *opnd, int32 acc); +extern int32 op_remqhi (int32 *opnd, int32 acc); +extern int32 op_remqti (int32 *opnd, int32 acc); +extern void op_pushr (int32 *opnd, int32 acc); +extern void op_popr (int32 *opnd, int32 acc); +extern int32 op_movc (int32 *opnd, int32 opc, int32 acc); +extern int32 op_cmpc (int32 *opnd, int32 opc, int32 acc); +extern int32 op_locskp (int32 *opnd, int32 opc, int32 acc); +extern int32 op_scnspn (int32 *opnd, int32 opc, int32 acc); +extern int32 op_chm (int32 *opnd, int32 cc, int32 opc); +extern int32 op_rei (int32 acc); +extern void op_ldpctx (int32 acc); +extern void op_svpctx (int32 acc); +extern int32 op_probe (int32 *opnd, int32 opc); +extern int32 op_mtpr (int32 *opnd); +extern int32 op_mfpr (int32 *opnd); +extern int32 op_movfd (int32 val); +extern int32 op_movg (int32 val); +extern int32 op_mnegfd (int32 val); +extern int32 op_mnegg (int32 val); +extern int32 op_cmpfd (int32 h1, int32 l1, int32 h2, int32 l2); +extern int32 op_cmpg (int32 h1, int32 l1, int32 h2, int32 l2); +extern int32 op_cvtifdg (int32 val, int32 *rh, int32 opc); +extern int32 op_cvtfdgi (int32 *opnd, int32 *rh, int32 opc); +extern int32 op_cvtdf (int32 *opnd); +extern int32 op_cvtgf (int32 *opnd); +extern int32 op_cvtfg (int32 *opnd, int32 *rh); +extern int32 op_addf (int32 *opnd, t_bool sub); +extern int32 op_addd (int32 *opnd, int32 *rh, t_bool sub); +extern int32 op_addg (int32 *opnd, int32 *rh, t_bool sub); +extern int32 op_mulf (int32 *opnd); +extern int32 op_muld (int32 *opnd, int32 *rh); +extern int32 op_mulg (int32 *opnd, int32 *rh); +extern int32 op_divf (int32 *opnd); +extern int32 op_divd (int32 *opnd, int32 *rh); +extern int32 op_divg (int32 *opnd, int32 *rh); +extern int32 op_emodf (int32 *opnd, int32 *intgr, int32 *flg); +extern int32 op_emodd (int32 *opnd, int32 *rh, int32 *intgr, int32 *flg); +extern int32 op_emodg (int32 *opnd, int32 *rh, int32 *intgr, int32 *flg); +extern void op_polyf (int32 *opnd, int32 acc); +extern void op_polyd (int32 *opnd, int32 acc); +extern void op_polyg (int32 *opnd, int32 acc); +extern int32 op_emulate (int32 *opnd, int32 cc, int32 opc, int32 acc); +extern int32 intexc (int32 vec, int32 cc, int32 ipl, int ei); +extern int32 Read (t_addr va, int32 lnt, int32 acc); +extern void Write (t_addr va, int32 val, int32 lnt, int32 acc); +extern int32 ReadB (t_addr pa); +extern int32 WriteB (t_addr pa, int32 val); +extern int32 Test (t_addr va, int32 acc, int32 *status); +extern int32 ReadLP (t_addr pa); +extern int32 eval_int (void); +extern int32 get_vector (int32 lvl); +extern void set_map_reg (void); +extern void rom_wr (int32 pa, int32 val, int32 lnt); +extern uint16 drom[NUM_INST][MAX_SPEC + 1]; +t_stat cpu_reset (DEVICE *dptr); +t_stat cpu_boot (int32 unitno); +t_stat cpu_ex (t_value *vptr, t_addr addr, UNIT *uptr, int32 sw); +t_stat cpu_dep (t_value val, t_addr addr, UNIT *uptr, int32 sw); +t_stat cpu_set_size (UNIT *uptr, int32 val, char *cptr, void *desc); +t_stat cpu_show_virt (UNIT *uptr, int32 val, char *cptr, void *desc); +int32 get_istr (int32 lnt, int32 acc); + +/* 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, R[nPC], 32) }, + { HRDATA (R0, R[0], 32) }, + { HRDATA (R1, R[1], 32) }, + { HRDATA (R2, R[2], 32) }, + { HRDATA (R3, R[3], 32) }, + { HRDATA (R4, R[4], 32) }, + { HRDATA (R5, R[5], 32) }, + { HRDATA (R6, R[6], 32) }, + { HRDATA (R7, R[7], 32) }, + { HRDATA (R8, R[8], 32) }, + { HRDATA (R9, R[9], 32) }, + { HRDATA (R10, R[10], 32) }, + { HRDATA (R11, R[11], 32) }, + { HRDATA (R12, R[12], 32) }, + { HRDATA (R13, R[13], 32) }, + { HRDATA (R14, R[14], 32) }, + { HRDATA (AP, R[nAP], 32) }, + { HRDATA (FP, R[nFP], 32) }, + { HRDATA (SP, R[nSP], 32) }, + { HRDATA (PSL, PSL, 32) }, + { HRDATA (CC, PSL, 4) }, + { HRDATA (KSP, KSP, 32) }, + { HRDATA (ESP, ESP, 32) }, + { HRDATA (SSP, SSP, 32) }, + { HRDATA (USP, USP, 32) }, + { HRDATA (IS, IS, 32) }, + { HRDATA (SCBB, SCBB, 32) }, + { HRDATA (PCBB, PCBB, 32) }, + { HRDATA (P0BR, P0BR, 32) }, + { HRDATA (P0LR, P0LR, 22) }, + { HRDATA (P1BR, P1BR, 32) }, + { HRDATA (P1LR, P1LR, 22) }, + { HRDATA (SBR, SBR, 32) }, + { HRDATA (SLR, SLR, 22) }, + { HRDATA (SISR, SISR, 16) }, + { HRDATA (ASTLVL, ASTLVL, 4) }, + { HRDATA (CADR, CADR, 8) }, + { HRDATA (MSER, MSER, 8) }, + { FLDATA (MAPEN, mapen, 0) }, + { HRDATA (TRPIRQ, trpirq, 8) }, + { FLDATA (CRDERR, crd_err, 0) }, + { FLDATA (MEMERR, mem_err, 0) }, + { HRDATA (DBGLOG, cpu_log, 16), REG_HIDDEN }, + { FLDATA (DBGSTOP, dbg_stop, 0), REG_HIDDEN }, + { BRDATA (PCQ, pcq, 16, 32, PCQ_SIZE), REG_RO+REG_CIRC }, + { HRDATA (PCQP, pcq_p, 6), REG_HRO }, + { HRDATA (BADABO, badabo, 32), REG_HRO }, + { HRDATA (WRU, sim_int_char, 8) }, + { NULL } }; + +MTAB cpu_mod[] = { + { UNIT_MSIZE, (1u << 23), NULL, "8M", &cpu_set_size }, + { UNIT_MSIZE, (1u << 24), NULL, "16M", &cpu_set_size }, + { UNIT_MSIZE, (1u << 25), NULL, "32M", &cpu_set_size }, + { UNIT_MSIZE, (1u << 26), NULL, "64M", &cpu_set_size }, + { UNIT_CONH, 0, "HALT to SIMH", "SIMHALT", NULL }, + { UNIT_CONH, UNIT_CONH, "HALT to console", "CONHALT", NULL }, + { MTAB_XTD|MTAB_VDV, 0, NULL, "VIRTUAL", &cpu_show_virt }, + { 0 } }; + +DEVICE cpu_dev = { + "CPU", &cpu_unit, cpu_reg, cpu_mod, + 1, 16, 32, 1, 16, 8, + &cpu_ex, &cpu_dep, &cpu_reset, + &cpu_boot, NULL, NULL }; + +t_stat sim_instr (void) +{ +volatile int32 opc, cc; /* used by setjmp */ +int32 acc; /* set by setjmp */ +int abortval; + +cc = PSL & CC_MASK; /* split PSL */ +PSL = PSL & ~CC_MASK; +in_ie = 0; /* not in exc */ +set_map_reg (); /* set map reg */ +GET_CUR; /* set access mask */ +SET_IRQL; /* eval interrupts */ +FLUSH_ISTR; /* clear prefetch */ +sim_rtcn_init (clk_unit.wait, TMR_CLK); /* init clock */ + +abortval = setjmp (save_env); /* set abort hdlr */ +if (abortval > 0) { /* sim stop? */ + PSL = PSL | cc; /* put PSL together */ + pcq_r -> qptr = pcq_p; /* update pc q ptr */ + return abortval; } /* return to SCP */ +else if (abortval < 0) { /* mm or rsrv or int */ + int32 i, temp, st1, st2, hsir; + if ((PSL & PSL_FPD) == 0) { /* FPD? no recovery */ + for (i = 0; i < recqptr; i++) { /* unwind inst */ + int32 rrn, rlnt; + rrn = recq[i] & 0xF; /* recovery reg# */ + rlnt = DR_LNT ((recq[i] >> 4) & 0x3); /* recovery lnt */ + if (recq[i] & 0x800) R[rrn] = R[rrn] - rlnt; + else R[rrn] = R[rrn] + rlnt; } } + recqptr = 0; /* clear queue */ + temp = fault_PC - PC; /* delta PC if needed */ + SETPC (fault_PC); /* restore PC */ + switch (-abortval) { /* case on abort code */ + case SCB_RESIN: case SCB_RESAD: case SCB_RESOP: /* reserved fault */ + if (in_ie) ABORT (STOP_INIE); /* in exc? panic */ + cc = intexc (-abortval, cc, 0, IE_EXC); /* take exception */ + GET_CUR; /* PSL changed */ + break; + case SCB_ARITH: /* arithmetic fault */ + if (in_ie) ABORT (STOP_INIE); /* in exc? panic */ + cc = intexc (-abortval, cc, 0, IE_EXC); /* take exception */ + GET_CUR; + in_ie = 1; + Write (SP - 4, p1, L_LONG, WA); /* write arith param */ + SP = SP - 4; + in_ie = 0; + break; + case SCB_ACV: case SCB_TNV: /* mem management */ + if (in_ie) { /* in exception? */ + if (PSL & PSL_IS) ABORT (STOP_INIE); /* on is? panic */ + cc = intexc (SCB_KSNV, cc, 0, IE_SVE); /* ksnv */ + GET_CUR; } + else { cc = intexc (-abortval, cc, 0, IE_EXC); /* take exception */ + GET_CUR; + in_ie = 1; + Write (SP - 8, p1, L_LONG, WA); /* write mm params */ + Write (SP - 4, p2, L_LONG, WA); + SP = SP - 8; + in_ie = 0; } + break; + case SCB_MCHK: /* machine check */ + if (in_ie) ABORT (STOP_INIE); /* in exception? */ + if (p1 & 0x80) p1 = p1 + mchk_ref; /* mref? set v/p */ + p2 = mchk_va + 4; /* save vap */ + for (i = hsir = 0; i < 16; i++) { /* find hsir */ + if ((SISR >> i) & 1) hsir = i; } + st1 = ((((uint32) opc) & 0xFF) << 24) | + (hsir << 16) | + ((CADR & 0xFF) << 8) | + (MSER & 0xFF); + st2 = 0x00C07000 + (temp & 0xFF); + cc = intexc (-abortval, cc, 0, IE_SVE); /* take exception */ + GET_CUR; /* PSL changed */ + in_ie = 1; + SP = SP - 20; /* push 5 words */ + Write (SP, 16, L_LONG, WA); /* # bytes */ + Write (SP + 4, p1, L_LONG, WA); /* mcheck type */ + Write (SP + 8, p2, L_LONG, WA); /* address */ + Write (SP + 12, st1, L_LONG, WA); /* state 1 */ + Write (SP + 16, st2, L_LONG, WA); /* state 2 */ + in_ie = 0; + break; + case 1: /* interrupt */ + break; /* just proceed */ + default: /* other */ + badabo = abortval; /* save code */ + ABORT (STOP_UNKABO); } /* panic */ +} /* end else */ + +/* Main instruction loop */ + +for ( ;; ) { +int32 spec, disp, rn, index, numspec; +int32 vfldrp1, brdisp, flg, mstat; +int32 i, j, r, rh, temp; +t_addr va, iad; +int32 opnd[10]; /* operand queue */ + +if (cpu_astop) { + cpu_astop = 0; + ABORT (SCPE_STOP); } + +fault_PC = PC; +recqptr = 0; /* clr recovery q */ +if (sim_interval <= 0) { /* chk clock queue */ + temp = sim_process_event (); + if (temp) ABORT (temp); + SET_IRQL; } /* update interrupts */ + +/* Test for non-instruction dispatches, in SRM order + + - trap or interrupt (trpirq != 0) + - PSL set + + If any of these conditions are met, re-dispatch; otherwise, + set PSL from PSL. +*/ + +if (trpirq) { /* trap or interrupt? */ + if (temp = GET_TRAP (trpirq)) { /* trap? */ + cc = intexc (SCB_ARITH, cc, 0, IE_EXC); /* take, clear trap */ + GET_CUR; /* set cur mode */ + in_ie = 1; + Write (SP - 4, temp, L_LONG, WA); /* write parameter */ + SP = SP - 4; + in_ie = 0; } + else if (temp = GET_IRQL (trpirq)) { /* interrupt? */ + int32 vec; + if (temp > IPL_HMAX) { /* error req lvl? */ + if (temp == IPL_MEMERR) { /* mem error? */ + vec = SCB_MEMERR; + mem_err = 0; } + else if (temp == IPL_CRDERR) { /* CRD error? */ + vec = SCB_CRDERR; + crd_err = 0; } + else ABORT (STOP_UIPL); } /* unknown intr */ + else if (temp >= IPL_HMIN) /* hardware req? */ + vec = get_vector (temp); /* get vector */ + else if (temp > IPL_SMAX) ABORT (STOP_UIPL); + else { vec = SCB_IPLSOFT + (temp << 2); + SISR = SISR & ~(1u << temp); } + if (vec) cc = intexc (vec, cc, temp, IE_INT); /* take intr */ + GET_CUR; } /* set cur mode */ + else trpirq = 0; /* clear everything */ + SET_IRQL; /* eval interrupts */ + continue; } + +if (PSL & PSL_TP) { /* trace trap? */ + PSL = PSL & ~PSL_TP; /* clear */ + cc = intexc (SCB_TP, cc, 0, IE_EXC); /* take trap */ + GET_CUR; /* set cur mode */ + continue; } +if (PSL & PSW_T) PSL = PSL | PSL_TP; /* if T, set TP */ + +if (sim_brk_summ && sim_brk_test (PC, SWMASK ('E'))) { /* breakpoint? */ + ABORT (STOP_IBKPT); } /* stop simulation */ + +sim_interval = sim_interval - 1; /* count instr */ +GET_ISTR (opc, L_BYTE); /* get opcode */ +if (opc == 0xFD) { /* 2 byte op? */ + GET_ISTR (opc, L_BYTE); /* get second byte */ + opc = opc | 0x100; } /* flag */ +numspec = drom[opc][0]; /* get # specs */ +if (PSL & PSL_FPD) { + if ((numspec & DR_F) == 0) RSVD_INST_FAULT; } +else { numspec = numspec & DR_NSPMASK; /* get # specifiers */ + +/* Specifier flows. Operands are parsed and placed into queue opnd. + + r.bwl opnd[j] = value of operand + r.q opnd[j:j+1] = value of operand + a.bwlq opnd[j] = address of operand + m.bwl opnd[j] = value of operand + m.q opnd[j:j+1] = value of operand + w.bwlq opnd[j] = register/memory flag + opnd[j+1] = memory address + + For the last memory specifier, the specifier is in spec, the register + number is in rn, and the effective address is in va. Modify specifiers + (always last) can test spec > reg+PC, as short literal are illegal for + modifiers specifiers, and final index specifiers are always illegal. +*/ + + for (i = 1, j = 0; i <= numspec; i++) { /* loop thru specs */ + disp = drom[opc][i]; /* get dispatch */ + if (disp >= BB) { + GET_ISTR (brdisp, DR_LNT (disp)); + break; } + GET_ISTR (spec, L_BYTE); /* get spec byte */ + rn = spec & RGMASK; /* get reg # */ + disp = (spec & ~RGMASK) | disp; /* merge w dispatch */ + switch (disp) { /* dispatch spec */ + +/* Short literal - only read access permitted */ + + case SH0|RB: case SH0|RW: case SH0|RL: + case SH1|RB: case SH1|RW: case SH1|RL: + case SH2|RB: case SH2|RW: case SH2|RL: + case SH3|RB: case SH3|RW: case SH3|RL: + opnd[j++] = spec; + break; + case SH0|RQ: case SH1|RQ: case SH2|RQ: case SH3|RQ: + opnd[j++] = spec; + opnd[j++] = 0; + break; + case SH0|RF: case SH1|RF: case SH2|RF: case SH3|RF: + opnd[j++] = (spec << 4) | 0x4000; + break; + case SH0|RD: case SH1|RD: case SH2|RD: case SH3|RD: + opnd[j++] = (spec << 4) | 0x4000; + opnd[j++] = 0; + break; + case SH0|RG: case SH1|RG: case SH2|RG: case SH3|RG: + opnd[j++] = (spec << 1) | 0x4000; + opnd[j++] = 0; + break; + +/* Register */ + + case GRN|RB: case GRN|MB: + CHECK_FOR_PC; + opnd[j++] = R[rn] & BMASK; + break; + case GRN|RW: case GRN|MW: + CHECK_FOR_PC; + opnd[j++] = R[rn] & WMASK; + break; + case GRN|VB: + vfldrp1 = R[rnplus1]; + case GRN|WB: case GRN|WW: case GRN|WL: case GRN|WQ: + opnd[j++] = rn; + case GRN|RL: case GRN|RF: case GRN|ML: + CHECK_FOR_PC; + opnd[j++] = R[rn]; + break; + case GRN|RQ: case GRN|RD: case GRN|RG: case GRN|MQ: + CHECK_FOR_SP; + opnd[j++] = R[rn]; + opnd[j++] = R[rnplus1]; + break; + +/* Register deferred, autodecrement */ + + case RGD|VB: + case RGD|WB: case RGD|WW: case RGD|WL: case RGD|WQ: + opnd[j++] = OP_MEM; + case RGD|AB: case RGD|AW: case RGD|AL: case RGD|AQ: + CHECK_FOR_PC; + va = opnd[j++] = R[rn]; + break; + case ADC|VB: + case ADC|WB: case ADC|WW: case ADC|WL: case ADC|WQ: + opnd[j++] = OP_MEM; + case ADC|AB: case ADC|AW: case ADC|AL: case ADC|AQ: + CHECK_FOR_PC; + va = opnd[j++] = R[rn] = R[rn] - DR_LNT (disp); + recq[recqptr++] = RECW (disp); + break; + case ADC|RB: case ADC|RW: case ADC|RL: case ADC|RF: + case ADC|MB: case ADC|MW: case ADC|ML: + R[rn] = R[rn] - (DR_LNT (disp)); + recq[recqptr++] = RECW (disp); + case RGD|RB: case RGD|RW: case RGD|RL: case RGD|RF: + case RGD|MB: case RGD|MW: case RGD|ML: + CHECK_FOR_PC; + opnd[j++] = Read (va = R[rn], DR_LNT (disp), RA); + break; + case ADC|RQ: case ADC|RD: case ADC|RG: case ADC|MQ: + R[rn] = R[rn] - 8; + recq[recqptr++] = RECW (disp); + case RGD|RQ: case RGD|RD: case RGD|RG: case RGD|MQ: + CHECK_FOR_PC; + opnd[j++] = Read (va = R[rn], L_LONG, RA); + opnd[j++] = Read (R[rn] + 4, L_LONG, RA); + break; + +/* Autoincrement */ + + case AIN|VB: + case AIN|WB: case AIN|WW: case AIN|WL: case AIN|WQ: +/* CHECK_FOR_PC; */ + opnd[j++] = OP_MEM; + case AIN|AB: case AIN|AW: case AIN|AL: case AIN|AQ: + va = opnd[j++] = R[rn]; + if (rn == nPC) { + if (DR_LNT (disp) == L_QUAD) { + GET_ISTR (temp, L_LONG); + GET_ISTR (temp, L_LONG); } + else GET_ISTR (temp, DR_LNT (disp)); } + else { R[rn] = R[rn] + DR_LNT (disp); + recq[recqptr++] = RECW (disp); } + break; + case AIN|MB: case AIN|MW: case AIN|ML: +/* CHECK_FOR_PC; */ + case AIN|RB: case AIN|RW: case AIN|RL: case AIN|RF: + va = R[rn]; + if (rn == nPC) { GET_ISTR (opnd[j++], DR_LNT (disp)); } + else { opnd[j++] = Read (R[rn], DR_LNT (disp), RA); + R[rn] = R[rn] + DR_LNT (disp); + recq[recqptr++] = RECW (disp); } + break; + case AIN|MQ: +/* CHECK_FOR_PC; */ + case AIN|RQ: case AIN|RD: case AIN|RG: + va = R[rn]; + if (rn == nPC) { + GET_ISTR (opnd[j++], L_LONG); + GET_ISTR (opnd[j++], L_LONG); } + else { opnd[j++] = Read (va, L_LONG, RA); + opnd[j++] = Read (va + 4, L_LONG, RA); + R[rn] = R[rn] + 8; + recq[recqptr++] = RECW (disp); } + break; + +/* Autoincrement deferred */ + + case AID|VB: + case AID|WB: case AID|WW: case AID|WL: case AID|WQ: + opnd[j++] = OP_MEM; + case AID|AB: case AID|AW: case AID|AL: case AID|AQ: + if (rn == nPC) { GET_ISTR (va = opnd[j++], L_LONG); } + else { va = opnd[j++] = Read (R[rn], L_LONG, RA); + R[rn] = R[rn] + 4; + recq[recqptr++] = RECW (AID|RL); } + break; + case AID|RB: case AID|RW: case AID|RL: case AID|RF: + case AID|MB: case AID|MW: case AID|ML: + if (rn == nPC) { GET_ISTR (va, L_LONG); } + else { va = Read (R[rn], L_LONG, RA); + R[rn] = R[rn] + 4; + recq[recqptr++] = RECW (AID|RL); } + opnd[j++] = Read (va, DR_LNT (disp), RA); + break; + case AID|RQ: case AID|RD: case AID|RG: case AID|MQ: + if (rn == nPC) { GET_ISTR (va, L_LONG); } + else { va = Read (R[rn], L_LONG, RA); + R[rn] = R[rn] + 4; + recq[recqptr++] = RECW (AID|RL); } + opnd[j++] = Read (va, L_LONG, RA); + opnd[j++] = Read (va + 4, L_LONG, RA); + break; + +/* Byte displacement */ + + case BDP|VB: + case BDP|WB: case BDP|WW: case BDP|WL: case BDP|WQ: + opnd[j++] = OP_MEM; + case BDP|AB: case BDP|AW: case BDP|AL: case BDP|AQ: + GET_ISTR (temp, L_BYTE); + va = opnd[j++] = R[rn] + SXTB (temp); + break; + case BDP|RB: case BDP|RW: case BDP|RL: case BDP|RF: + case BDP|MB: case BDP|MW: case BDP|ML: + GET_ISTR (temp, L_BYTE); + va = R[rn] + SXTB (temp); + opnd[j++] = Read (va, DR_LNT (disp), RA); + break; + case BDP|RQ: case BDP|RD: case BDP|RG: case BDP|MQ: + GET_ISTR (temp, L_BYTE); + va = R[rn] + SXTB (temp); + opnd[j++] = Read (va, L_LONG, RA); + opnd[j++] = Read (va + 4, L_LONG, RA); + break; + +/* Byte displacement deferred */ + + case BDD|VB: + case BDD|WB: case BDD|WW: case BDD|WL: case BDD|WQ: + opnd[j++] = OP_MEM; + case BDD|AB: case BDD|AW: case BDD|AL: case BDD|AQ: + GET_ISTR (temp, L_BYTE); + iad = R[rn] + SXTB (temp); + va = opnd[j++] = Read (iad, L_LONG, RA); + break; + case BDD|RB: case BDD|RW: case BDD|RL: case BDD|RF: + case BDD|MB: case BDD|MW: case BDD|ML: + GET_ISTR (temp, L_BYTE); + iad = R[rn] + SXTB (temp); + va = Read (iad, L_LONG, RA); + opnd[j++] = Read (va, DR_LNT (disp), RA); + break; + case BDD|RQ: case BDD|RD: case BDD|RG: case BDD|MQ: + GET_ISTR (temp, L_BYTE); + iad = R[rn] + SXTB (temp); + va = Read (iad, L_LONG, RA); + opnd[j++] = Read (va, L_LONG, RA); + opnd[j++] = Read (va + 4, L_LONG, RA); + break; + +/* Word displacement */ + + case WDP|VB: + case WDP|WB: case WDP|WW: case WDP|WL: case WDP|WQ: + opnd[j++] = OP_MEM; + case WDP|AB: case WDP|AW: case WDP|AL: case WDP|AQ: + GET_ISTR (temp, L_WORD); + va = opnd[j++] = R[rn] + SXTW (temp); + break; + case WDP|MB: case WDP|MW: case WDP|ML: + case WDP|RB: case WDP|RW: case WDP|RL: case WDP|RF: + GET_ISTR (temp, L_WORD); + va = R[rn] + SXTW (temp); + opnd[j++] = Read (va, DR_LNT (disp), RA); + break; + case WDP|MQ: case WDP|RQ: case WDP|RD: case WDP|RG: + GET_ISTR (temp, L_WORD); + va = R[rn] + SXTW (temp); + opnd[j++] = Read (va, L_LONG, RA); + opnd[j++] = Read (va + 4, L_LONG, RA); + break; + +/* Word displacement deferred */ + + case WDD|VB: + case WDD|WB: case WDD|WW: case WDD|WL: case WDD|WQ: + opnd[j++] = OP_MEM; + case WDD|AB: case WDD|AW: case WDD|AL: case WDD|AQ: + GET_ISTR (temp, L_WORD); + iad = R[rn] + SXTW (temp); + va = opnd[j++] = Read (iad, L_LONG, RA); + break; + case WDD|MB: case WDD|MW: case WDD|ML: + case WDD|RB: case WDD|RW: case WDD|RL: case WDD|RF: + GET_ISTR (temp, L_WORD); + iad = R[rn] + SXTW (temp); + va = Read (iad, L_LONG, RA); + opnd[j++] = Read (va, DR_LNT (disp), RA); + break; + case WDD|MQ: case WDD|RQ: case WDD|RD: case WDD|RG: + GET_ISTR (temp, L_WORD); + iad = R[rn] + SXTW (temp); + va = Read (iad, L_LONG, RA); + opnd[j++] = Read (va, L_LONG, RA); + opnd[j++] = Read (va + 4, L_LONG, RA); + break; + +/* Longword displacement */ + + case LDP|VB: + case LDP|WB: case LDP|WW: case LDP|WL: case LDP|WQ: + opnd[j++] = OP_MEM; + case LDP|AB: case LDP|AW: case LDP|AL: case LDP|AQ: + GET_ISTR (temp, L_LONG); + va = opnd[j++] = R[rn] + temp; + break; + case LDP|MB: case LDP|MW: case LDP|ML: + case LDP|RB: case LDP|RW: case LDP|RL: case LDP|RF: + GET_ISTR (temp, L_LONG); + va = R[rn] + temp; + opnd[j++] = Read (va, DR_LNT (disp), RA); + break; + case LDP|MQ: case LDP|RQ: case LDP|RD: case LDP|RG: + GET_ISTR (temp, L_LONG); + va = R[rn] + temp; + opnd[j++] = Read (va, L_LONG, RA); + opnd[j++] = Read (va + 4, L_LONG, RA); + break; + +/* Longword displacement deferred */ + + case LDD|VB: + case LDD|WB: case LDD|WW: case LDD|WL: case LDD|WQ: + opnd[j++] = OP_MEM; + case LDD|AB: case LDD|AW: case LDD|AL: case LDD|AQ: + GET_ISTR (temp, L_LONG); + iad = R[rn] + temp; + va = opnd[j++] = Read (iad, L_LONG, RA); + break; + case LDD|MB: case LDD|MW: case LDD|ML: + case LDD|RB: case LDD|RW: case LDD|RL: case LDD|RF: + GET_ISTR (temp, L_LONG); + iad = R[rn] + temp; + va = Read (iad, L_LONG, RA); + opnd[j++] = Read (va, DR_LNT (disp), RA); + break; + case LDD|MQ: case LDD|RQ: case LDD|RD: case LDD|RG: + GET_ISTR (temp, L_LONG); + iad = R[rn] + temp; + va = Read (iad, L_LONG, RA); + opnd[j++] = Read (va, L_LONG, RA); + opnd[j++] = Read (va + 4, L_LONG, RA); + break; + +/* Index */ + + case IDX|VB: + case IDX|WB: case IDX|WW: case IDX|WL: case IDX|WQ: + case IDX|AB: case IDX|AW: case IDX|AL: case IDX|AQ: + case IDX|MB: case IDX|MW: case IDX|ML: case IDX|MQ: + case IDX|RB: case IDX|RW: case IDX|RL: case IDX|RQ: + case IDX|RF: case IDX|RD: case IDX|RG: + index = R[rn] << (disp & 03); + CHECK_FOR_PC; + GET_ISTR (spec, L_BYTE); + rn = spec & RGMASK; + switch (spec & ~RGMASK) { + case ADC: + R[rn] = R[rn] - DR_LNT (disp); + recq[recqptr++] = RECW (ADC | (disp & DR_LNMASK)); + case RGD: + CHECK_FOR_PC; + index = index + R[rn]; + break; + case AIN: + CHECK_FOR_PC; + index = index + R[rn]; + R[rn] = R[rn] + DR_LNT (disp); + recq[recqptr++] = RECW (AIN | (disp & DR_LNMASK)); + break; + case AID: + if (rn == nPC) { GET_ISTR (temp, L_LONG); } + else { temp = Read (R[rn], L_LONG, RA); + R[rn] = R[rn] + 4; + recq[recqptr++] = RECW (AID|RL); } + index = temp + index; + break; + case BDP: + GET_ISTR (temp, L_BYTE); + index = index + R[rn] + SXTB (temp); + break; + case BDD: + GET_ISTR (temp, L_BYTE); + index = index + Read (R[rn] + SXTB (temp), L_LONG, RA); + break; + case WDP: + GET_ISTR (temp, L_WORD); + index = index + R[rn] + SXTW (temp); + break; + case WDD: + GET_ISTR (temp, L_WORD); + index = index + Read (R[rn] + SXTW (temp), L_LONG, RA); + break; + case LDP: + GET_ISTR (temp, L_LONG); + index = index + R[rn] + temp; + break; + case LDD: + GET_ISTR (temp, L_LONG); + index = index + Read (R[rn] + temp, L_LONG, RA); + break; + default: + RSVD_ADDR_FAULT; } /* end case idxspec */ + switch (disp & 0xF) { /* case disp type */ + case WB: case WW: case WL: case WQ: + opnd[j++] = OP_MEM; + case AB: case AW: case AL: case AQ: + va = opnd[j++] = index; + break; + case MB: case MW: case ML: + case RB: case RW: case RL: + opnd[j++] = Read (va = index, DR_LNT (disp), RA); + break; + case RQ: case MQ: + opnd[j++] = Read (va = index, L_LONG, RA); + opnd[j++] = Read (index + 4, L_LONG, RA); + break; } /* end case access/lnt */ + break; /* end index */ + default: /* all others */ + RSVD_ADDR_FAULT; /* fault */ + break; + } /* end case spec */ + } /* end for */ +} /* end if not FPD */ + +/* Dispatch to instructions */ + +switch (opc) { + +/* Single operand instructions with dest, write only - CLRx dst.wx + + spec = reg/memory flag + rn = register number + va = virtual address +*/ + +case CLRB: + WRITE_B (0); /* store result */ + CC_ZZ1P; /* set cc's */ + break; +case CLRW: + WRITE_W (0); /* store result */ + CC_ZZ1P; /* set cc's */ + break; +case CLRL: + WRITE_L (0); /* store result */ + CC_ZZ1P; /* set cc's */ + break; +case CLRQ: + WRITE_Q (0, 0); /* store result */ + CC_ZZ1P; /* set cc's */ + break; + +/* Single operand instructions with source, read only - TSTx src.rx + + opnd[0] = source + */ + +case TSTB: + CC_IIZZ_B (op0); /* set cc's */ + break; +case TSTW: + CC_IIZZ_W (op0); /* set cc's */ + break; +case TSTL: + CC_IIZZ_L (op0); /* set cc's */ + break; + +/* Single operand instructions with source, read/write - op src.mx + + opnd[0] = operand + spec = reg/mem flag + rn = register number + va = operand address +*/ + +case INCB: + r = (op0 + 1) & BMASK; /* calc result */ + WRITE_B (r); /* store result */ + CC_ADD_B (r, 1, op0); /* set cc's */ + break; +case INCW: + r = (op0 + 1) & WMASK; /* calc result */ + WRITE_W (r); /* store result */ + CC_ADD_W (r, 1, op0); /* set cc's */ + break; +case INCL: + r = (op0 + 1) & LMASK; /* calc result */ + WRITE_L (r); /* store result */ + CC_ADD_L (r, 1, op0); /* set cc's */ + break; +case DECB: + r = (op0 - 1) & BMASK; /* calc result */ + WRITE_B (r); /* store result */ + CC_SUB_B (r, 1, op0); /* set cc's */ + break; +case DECW: + r = (op0 - 1) & WMASK; /* calc result */ + WRITE_W (r); /* store result */ + CC_SUB_W (r, 1, op0); /* set cc's */ + break; +case DECL: + r = (op0 - 1) & LMASK; /* calc result */ + WRITE_L (r); /* store result */ + CC_SUB_L (r, 1, op0); /* set cc's */ + break; + +/* Push instructions - PUSHL src.rl or PUSHAx src.ax + + opnd[0] = source +*/ + +case PUSHL: case PUSHAB: case PUSHAW: case PUSHAL: case PUSHAQ: + Write (SP - 4, op0, L_LONG, WA); /* push operand */ + SP = SP - 4; /* decr stack ptr */ + CC_IIZP_L (op0); /* set cc's */ + break; + +/* Moves, converts, and ADAWI - op src.rx, dst.wx + + opnd[0] = source + spec = reg/mem flag + rn = register number + va = operand address +*/ + +case MOVB: + WRITE_B (op0); /* result */ + CC_IIZP_B (op0); /* set cc's */ + break; +case MOVW: case MOVZBW: + WRITE_W (op0); /* result */ + CC_IIZP_W (op0); /* set cc's */ + break; +case MOVL: case MOVZBL: case MOVZWL: +case MOVAB: case MOVAW: case MOVAL: case MOVAQ: + WRITE_L (op0); /* result */ + CC_IIZP_L (op0); /* set cc's */ + break; +case MCOMB: + r = op0 ^ BMASK; /* compl opnd */ + WRITE_B (r); /* store result */ + CC_IIZP_B (r); /* set cc's */ + break; +case MCOMW: + r = op0 ^ WMASK; /* compl opnd */ + WRITE_W (r); /* store result */ + CC_IIZP_W (r); /* set cc's */ + break; +case MCOML: + r = op0 ^ LMASK; /* compl opnd */ + WRITE_L (r); /* store result */ + CC_IIZP_L (r); /* set cc's */ + break; +case MNEGB: + r = (-op0) & BMASK; /* negate opnd */ + WRITE_B (r); /* store result */ + CC_SUB_B (r, op0, 0); /* set cc's */ + break; +case MNEGW: + r = (-op0) & WMASK; /* negate opnd */ + WRITE_W (r); /* store result */ + CC_SUB_W (r, op0, 0); /* set cc's */ + break; +case MNEGL: + r = (-op0) & LMASK; /* negate opnd */ + WRITE_L (r); /* store result */ + CC_SUB_L (r, op0, 0); /* set cc's */ + break; + +case CVTBW: + r = SXTBW (op0); /* ext sign */ + WRITE_W (r); /* store result */ + CC_IIZZ_W (r); /* set cc's */ + break; +case CVTBL: + r = SXTB (op0); /* ext sign */ + WRITE_L (r); /* store result */ + CC_IIZZ_L (r); /* set cc's */ + break; +case CVTWL: + r = SXTW (op0); /* ext sign */ + WRITE_L (r); /* store result */ + CC_IIZZ_L (r); /* set cc's */ + break; +case CVTLB: + r = op0 & BMASK; /* set result */ + WRITE_B (r); /* store result */ + CC_IIZZ_B (r); /* initial cc's */ + if ((op0 > 127) || (op0 < -128)) { V_INTOV; } + break; +case CVTLW: + r = op0 & WMASK; /* set result */ + WRITE_W (r); /* store result */ + CC_IIZZ_W (r); /* initial cc's */ + if ((op0 > 32767) || (op0 < -32768)) { V_INTOV; } + break; +case CVTWB: + r = op0 & BMASK; /* set result */ + WRITE_B (r); /* store result */ + CC_IIZZ_B (r); /* initial cc's */ + temp = SXTW (op0); /* cvt op to long */ + if ((temp > 127) || (temp < -128)) { V_INTOV; } + break; + +case ADAWI: + if (op1 >= 0) { /* reg? ADDW2 */ + temp = R[op1]; + r = R[op1] = (op0 + temp) & WMASK; } + else { if (op2 & 1) RSVD_OPND_FAULT; /* mem? chk align */ + temp = Read (op2, L_WORD, WA); /* ok, ADDW2 */ + r = (op0 + temp) & WMASK; + WRITE_W (r); } + CC_ADD_W (r, op0, temp); /* set cc's */ + break; + +/* Integer operates, 2 operand, read only - op src1.rx, src2.rx + + opnd[0] = source1 + opnd[1] = source2 +*/ + +case CMPB: + CC_CMP_B (op0, op1); /* set cc's */ + break; +case CMPW: + CC_CMP_W (op0, op1); /* set cc's */ + break; +case CMPL: + CC_CMP_L (op0, op1); /* set cc's */ + break; +case BITB: + r = op1 & op0; /* calc result */ + CC_IIZP_B (r); /* set cc's */ + break; +case BITW: + r = op1 & op0; /* calc result */ + CC_IIZP_W (r); /* set cc's */ + break; +case BITL: + r = op1 & op0; /* calc result */ + CC_IIZP_L (r); /* set cc's */ + break; + +/* Integer operates, 2 operand read/write, and 3 operand, also MOVQ + op2 src.rx, dst.mx op3 src.rx, src.rx, dst.wx + + opnd[0] = source1 + opnd[1] = source2 + spec = register/memory flag + rn = register number + va = memory address +*/ + +case ADDB2: case ADDB3: + r = (op1 + op0) & BMASK; /* calc result */ + WRITE_B (r); /* store result */ + CC_ADD_B (r, op0, op1); /* set cc's */ + break; +case ADDW2: case ADDW3: + r = (op1 + op0) & WMASK; /* calc result */ + WRITE_W (r); /* store result */ + CC_ADD_W (r, op0, op1); /* set cc's */ + break; +case ADWC: + r = (op1 + op0 + (cc & CC_C)) & LMASK; /* calc result */ + WRITE_L (r); /* store result */ + CC_ADD_L (r, op0, op1); /* set cc's */ + if ((r == op1) && op0) cc = cc | CC_C; /* special case */ + break; +case ADDL2: case ADDL3: + r = (op1 + op0) & LMASK; /* calc result */ + WRITE_L (r); /* store result */ + CC_ADD_L (r, op0, op1); /* set cc's */ + break; +case SUBB2: case SUBB3: + r = (op1 - op0) & BMASK; /* calc result */ + WRITE_B (r); /* store result */ + CC_SUB_B (r, op0, op1); /* set cc's */ + break; +case SUBW2: case SUBW3: + r = (op1 - op0) & WMASK; /* calc result */ + WRITE_W (r); /* store result */ + CC_SUB_W (r, op0, op1); /* set cc's */ + break; +case SBWC: + r = (op1 - op0 - (cc & CC_C)) & LMASK; /* calc result */ + WRITE_L (r); /* store result */ + CC_SUB_L (r, op0, op1); /* set cc's */ + if ((op0 == op1) && r) cc = cc | CC_C; /* special case */ + break; +case SUBL2: case SUBL3: + r = (op1 - op0) & LMASK; /* calc result */ + WRITE_L (r); /* store result */ + CC_SUB_L (r, op0, op1); /* set cc's */ + break; +case MULB2: case MULB3: + temp = SXTB (op0) * SXTB (op1); /* multiply */ + r = temp & BMASK; /* mask to result */ + WRITE_B (r); /* store result */ + CC_IIZZ_B (r); /* set cc's */ + if ((temp > 127) || (temp < -128)) { V_INTOV; } + break; +case MULW2: case MULW3: + temp = SXTW (op0) * SXTW (op1); /* multiply */ + r = temp & WMASK; /* mask to result */ + WRITE_W (r); /* store result */ + CC_IIZZ_W (r); /* set cc's */ + if ((temp > 32767) || (temp < -32768)) { V_INTOV; } + break; +case MULL2: case MULL3: + r = op_emul (op0, op1, &rh); /* get 64b result */ + WRITE_L (r); /* store result */ + CC_IIZZ_L (r); /* set cc's */ + if (rh != ((r & LSIGN)? -1: 0)) { V_INTOV; } /* chk overflow */ + break; +case DIVB2: case DIVB3: + if (op0 == 0) { /* div by zero? */ + r = op1; + temp = CC_V; + SET_TRAP (TRAP_DIVZRO); } + else if ((op0 == BMASK) && (op1 == BSIGN)) { /* overflow? */ + r = op1; + temp = CC_V; + INTOV; } + else { r = SXTB (op1) / SXTB (op0); /* ok, divide */ + temp = 0; } + WRITE_B (r); /* write result */ + CC_IIZZ_B (r); /* set cc's */ + cc = cc | temp; /* error? set V */ + break; +case DIVW2: case DIVW3: + if (op0 == 0) { /* div by zero? */ + r = op1; + temp = CC_V; + SET_TRAP (TRAP_DIVZRO); } + else if ((op0 == WMASK) && (op1 == WSIGN)) { /* overflow? */ + r = op1; + temp = CC_V; + INTOV; } + else { r = SXTW (op1) / SXTW (op0); /* ok, divide */ + temp = 0; } + WRITE_W (r); /* write result */ + CC_IIZZ_W (r); /* set cc's */ + cc = cc | temp; /* error? set V */ + break; +case DIVL2: case DIVL3: + if (op0 == 0) { /* div by zero? */ + r = op1; + temp = CC_V; + SET_TRAP (TRAP_DIVZRO); } + else if ((op0 == LMASK) && (op1 == LSIGN)) { /* overflow? */ + r = op1; + temp = CC_V; + INTOV; } + else { r = op1 / op0; /* ok, divide */ + temp = 0; } + WRITE_L (r); /* write result */ + CC_IIZZ_L (r); /* set cc's */ + cc = cc | temp; /* error? set V */ + break; + +case BISB2: case BISB3: + r = op1 | op0; /* calc result */ + WRITE_B (r); /* store result */ + CC_IIZP_B (r); /* set cc's */ + break; +case BISW2: case BISW3: + r = op1 | op0; /* calc result */ + WRITE_W (r); /* store result */ + CC_IIZP_W (r); /* set cc's */ + break; +case BISL2: case BISL3: + r = op1 | op0; /* calc result */ + WRITE_L (r); /* store result */ + CC_IIZP_L (r); /* set cc's */ + break; +case BICB2: case BICB3: + r = op1 & ~op0; /* calc result */ + WRITE_B (r); /* store result */ + CC_IIZP_B (r); /* set cc's */ + break; +case BICW2: case BICW3: + r = op1 & ~op0; /* calc result */ + WRITE_W (r); /* store result */ + CC_IIZP_W (r); /* set cc's */ + break; +case BICL2: case BICL3: + r = op1 & ~op0; /* calc result */ + WRITE_L (r); /* store result */ + CC_IIZP_L (r); /* set cc's */ + break; +case XORB2: case XORB3: + r = op1 ^ op0; /* calc result */ + WRITE_B (r); /* store result */ + CC_IIZP_B (r); /* set cc's */ + break; +case XORW2: case XORW3: + r = op1 ^ op0; /* calc result */ + WRITE_W (r); /* store result */ + CC_IIZP_W (r); /* set cc's */ + break; +case XORL2: case XORL3: + r = op1 ^ op0; /* calc result */ + WRITE_L (r); /* store result */ + CC_IIZP_L (r); /* set cc's */ + break; + +/* MOVQ - movq src.rq, dst.wq + + opnd[0:1] = source + spec = register/memory flag + rn = register number + va = memory address + +*/ + +case MOVQ: + WRITE_Q (op0, op1); /* store result */ + CC_IIZP_Q (op0, op1); + break; + +/* Shifts - op shf.rb,src.rl,dst.wl + + opnd[0] = shift count + opnd[1] = source + spec = register/memory flag + rn = register number + va = memory address +*/ + +case ROTL: + j = op0 % 32; /* reduce sc, mod 32 */ + if (j) r = ((((uint32) op1) << j) | + (((uint32) op1) >> (32 - j))) & LMASK; + else r = op1; + WRITE_L (r); /* store result */ + CC_IIZP_L (r); /* set cc's */ + break; +case ASHL: + if (op0 & BSIGN) { /* right shift? */ + temp = 0x100 - op0; /* get |shift| */ + if (temp > 31) r = (op1 & LSIGN)? -1: 0; /* sc > 31? */ + else r = op1 >> temp; /* shift */ + WRITE_L (r); /* store result */ + CC_IIZZ_L (r); /* set cc's */ + break; } + else { if (op0 > 31) r = temp = 0; /* sc > 31? */ + else { r = ((uint32) op1) << op0; /* shift */ + temp = r >> op0; } /* shift back */ + WRITE_L (r); /* store result */ + CC_IIZZ_L (r); /* set cc's */ + if (op1 != temp) { V_INTOV; } } /* bits lost? */ + break; +case ASHQ: + r = op_ashq (opnd, &rh, &flg); /* do qw shift */ + WRITE_Q (r, rh); /* store results */ + CC_IIZZ_Q (r, rh); /* set cc's */ + if (flg) { V_INTOV; } /* if ovflo, set */ + break; + +/* EMUL - emul mplr.rl,mpcn.rl,add.rl,dst.wq + + op0 = multiplier + op1 = multiplicand + op2 = adder + op3:op4 = destination (.wq) +*/ + +case EMUL: + r = op_emul (op0, op1, &rh); /* calc 64b result */ + r = r + op2; /* add 32b value */ + rh = rh + (((uint32) r) < ((uint32) op2)) - /* into 64b result */ + ((op2 & LSIGN)? 1: 0); + WRITE_Q (r, rh); /* write result */ + CC_IIZZ_Q (r, rh); /* set cc's */ + break; + +/* EDIV - ediv dvr.rl,dvd.rq,quo.wl,rem.wl + + op0 = divisor (.rl) + op1:op2 = dividend (.rq) + op3:op4 = quotient address (.wl) + op5:op6 = remainder address (.wl) +*/ + +case EDIV: + if (op5 < 0) Read (op6, L_LONG, WA); /* wtest remainder */ + if (op0 == 0) { /* divide by zero? */ + flg = CC_V; /* set V */ + r = opnd[1]; /* quo = low divd */ + rh = 0; /* rem = 0 */ + SET_TRAP (TRAP_DIVZRO); } /* set trap */ + else { r = op_ediv (opnd, &rh, &flg); /* extended divide */ + if (flg) { INTOV; } } /* if ovf+IV, set trap */ + if (op3 >= 0) R[op3] = r; /* store quotient */ + else Write (op4, r, L_LONG, WA); + if (op5 >= 0) R[op5] = rh; /* store remainder */ + else Write (op6, rh, L_LONG, WA); + CC_IIZZ_L (r); /* set cc's */ + cc = cc | flg; /* set V if required */ + break; + +/* Control instructions */ + +/* Simple branches and subroutine calls */ + +case BRB: + BRANCHB (brdisp); /* branch */ + if ((PC == fault_PC) && (PSL_GETIPL (PSL) == 0x1F)) + ABORT (STOP_LOOP); + break; + +case BRW: + BRANCHW (brdisp); /* branch */ + if ((PC == fault_PC) && (PSL_GETIPL (PSL) == 0x1F)) + ABORT (STOP_LOOP); + break; + +case BSBB: + Write (SP - 4, PC, L_LONG, WA); /* push PC on stk */ + SP = SP - 4; /* decr stk ptr */ + BRANCHB (brdisp); /* branch */ + break; + +case BSBW: + Write (SP - 4, PC, L_LONG, WA); /* push PC on stk */ + SP = SP - 4; /* decr stk ptr */ + BRANCHW (brdisp); /* branch */ + break; + +case BGEQ: + if (!(cc & CC_N)) BRANCHB (brdisp); /* br if N = 0 */ + break; +case BLSS: + if (cc & CC_N) BRANCHB (brdisp); /* br if N = 1 */ + break; +case BNEQ: + if (!(cc & CC_Z)) BRANCHB (brdisp); /* br if Z = 0 */ + break; +case BEQL: + if (cc & CC_Z) BRANCHB (brdisp); /* br if Z = 1 */ + break; +case BVC: + if (!(cc & CC_V)) BRANCHB (brdisp); /* br if V = 0 */ + break; +case BVS: + if (cc & CC_V) BRANCHB (brdisp); /* br if V = 1 */ + break; +case BGEQU: + if (!(cc & CC_C)) BRANCHB (brdisp); /* br if C = 0 */ + break; +case BLSSU: + if (cc & CC_C) BRANCHB (brdisp); /* br if C = 1 */ + break; +case BGTR: + if (!(cc & (CC_N | CC_Z))) BRANCHB (brdisp); /* br if N | Z = 0 */ + break; +case BLEQ: + if (cc & (CC_N | CC_Z)) BRANCHB (brdisp); /* br if N | Z = 1 */ + break; +case BGTRU: + if (!(cc & (CC_C | CC_Z))) BRANCHB (brdisp); /* br if C | Z = 0 */ + break; +case BLEQU: + if (cc & (CC_C | CC_Z)) BRANCHB (brdisp); /* br if C | Z = 1 */ + break; + +/* Simple jumps and subroutine calls - op addr.ab + + opnd[0] = address +*/ + +case JSB: + Write (SP - 4, PC, L_LONG, WA); /* push PC on stk */ + SP = SP - 4; /* decr stk ptr */ +case JMP: + JUMP (op0); /* jump */ + break; + +case RSB: + temp = Read (SP, L_LONG, RA); /* get top of stk */ + SP = SP + 4; /* incr stk ptr */ + JUMP (temp); + break; + +/* SOB instructions - op idx.ml,disp.bb + + opnd[0] = index + spec = register/memory flag + rn = register number + va = memory address +*/ + +case SOBGEQ: + r = op0 - 1; /* decr index */ + WRITE_L (r); /* store result */ + CC_IIZP_L (r); /* set cc's */ + V_SUB_L (r, 1, op0); /* test for ovflo */ + if (r >= 0) BRANCHB (brdisp); /* if >= 0, branch */ + break; +case SOBGTR: + r = op0 - 1; /* decr index */ + WRITE_L (r); /* store result */ + CC_IIZP_L (r); /* set cc's */ + V_SUB_L (r, 1, op0); /* test for ovflo */ + if (r > 0) BRANCHB (brdisp); /* if >= 0, branch */ + break; + +/* AOB instructions - op limit.rl,idx.ml,disp.bb + + opnd[0] = limit + opnd[1] = index + spec = register/memory flag + rn = register number + va = memory address +*/ + +case AOBLSS: + r = op1 + 1; /* incr index */ + WRITE_L (r); /* store result */ + CC_IIZP_L (r); /* set cc's */ + V_ADD_L (r, 1, op1); /* test for ovflo */ + if (r < op0) BRANCHB (brdisp); /* if < lim, branch */ + break; +case AOBLEQ: + r = op1 + 1; /* incr index */ + WRITE_L (r); /* store result */ + CC_IIZP_L (r); /* set cc's */ + V_ADD_L (r, 1, op1); /* test for ovflo */ + if (r <= op0) BRANCHB (brdisp); /* if < lim, branch */ + break; + +/* ACB instructions - op limit.rx,add.rx,index.mx,disp.bw + + opnd[0] = limit + opnd[1] = adder + opnd[2] = index + spec = register/memory flag + rn = register number + va = memory address +*/ + +case ACBB: + r = (op2 + op1) & BMASK; /* calc result */ + WRITE_B (r); /* store result */ + CC_IIZP_B (r); /* set cc's */ + V_ADD_B (r, op1, op2); /* test for ovflo */ + if ((op1 & BSIGN)? (SXTB (r) >= SXTB (op0)): + (SXTB (r) <= SXTB (op0))) BRANCHW (brdisp); + break; +case ACBW: + r = (op2 + op1) & WMASK; /* calc result */ + WRITE_W (r); /* store result */ + CC_IIZP_W (r); /* set cc's */ + V_ADD_W (r, op1, op2); /* test for ovflo */ + if ((op1 & WSIGN)? (SXTW (r) >= SXTW (op0)): + (SXTW (r) <= SXTW (op0))) BRANCHW (brdisp); + break; +case ACBL: + r = (op2 + op1) & LMASK; /* calc result */ + WRITE_L (r); /* store result */ + CC_IIZP_L (r); /* set cc's */ + V_ADD_L (r, op1, op2); /* test for ovflo */ + if ((op1 & LSIGN)? (r >= op0): (r <= op0)) + BRANCHW (brdisp); + break; + +/* CASE instructions - casex sel.rx,base.rx,lim.rx + + opnd[0] = selector + opnd[1] = base + opnd[2] = limit +*/ + +case CASEB: + r = (op0 - op1) & BMASK; /* sel - base */ + CC_CMP_B (r, op2); /* r:limit, set cc's */ + if (r > op2) JUMP (PC + ((op2 + 1) * 2)); /* r > limit (unsgnd)? */ + else { temp = Read (PC + (r * 2), L_WORD, RA); + BRANCHW (temp); } + break; +case CASEW: + r = (op0 - op1) & WMASK; /* sel - base */ + CC_CMP_W (r, op2); /* r:limit, set cc's */ + if (r > op2) JUMP (PC + ((op2 + 1) * 2)); /* r > limit (unsgnd)? */ + else { temp = Read (PC + (r * 2), L_WORD, RA); + BRANCHW (temp); } + break; +case CASEL: + r = (op0 - op1) & LMASK; /* sel - base */ + CC_CMP_L (r, op2); /* r:limit, set cc's */ + if (((uint32) r) > ((uint32) op2)) /* r > limit (unsgnd)? */ + JUMP (PC + ((op2 + 1) * 2)); + else { temp = Read (PC + (r * 2), L_WORD, RA); + BRANCHW (temp); } + break; + +/* Branch on bit instructions - bbxy pos.rl,op.wb,disp.bb + + opnd[0] = position + opnd[1] = register number/memory flag + opnd[2] = memory address, if memory +*/ + +case BBS: + if (op_bb_n (opnd, acc)) BRANCHB (brdisp); /* br if bit set */ + break; +case BBC: + if (!op_bb_n (opnd, acc)) BRANCHB (brdisp); /* br if bit clr */ + break; +case BBSS: case BBSSI: + if (op_bb_x (opnd, 1, acc)) BRANCHB (brdisp); /* br if set, set */ + break; +case BBCC: case BBCCI: + if (!op_bb_x (opnd, 0, acc)) BRANCHB (brdisp); /* br if clr, clr*/ + break; +case BBSC: + if (op_bb_x (opnd, 0, acc)) BRANCHB (brdisp); /* br if clr, set */ + break; +case BBCS: + if (!op_bb_x (opnd, 1, acc)) BRANCHB (brdisp); /* br if set, clr */ + break; +case BLBS: + if (op0 & 1) BRANCHB (brdisp); /* br if bit set */ + break; +case BLBC: + if ((op0 & 1) == 0) BRANCHB (brdisp); /* br if bit clear */ + break; + +/* Extract field instructions - ext?v pos.rl,size.rb,base.wb,dst.wl + + opnd[0] = position + opnd[1] = size + opnd[2] = register number/memory flag + opnd[3] = register content/memory address + spec = register/memory flag + rn = register number + va = memory address +*/ + +case EXTV: + r = op_extv (opnd, vfldrp1, acc); /* get field */ + if (r & byte_sign[op1]) r = r | ~byte_mask[op1]; + WRITE_L (r); /* store field */ + CC_IIZP_L (r); /* set cc's */ + break; +case EXTZV: + r = op_extv (opnd, vfldrp1, acc); /* get field */ + WRITE_L (r); /* store field */ + CC_IIZP_L (r); /* set cc's */ + break; + +/* Compare field instructions - cmp?v pos.rl,size.rb,base.wb,src2.rl + + opnd[0] = position + opnd[1] = size + opnd[2] = register number/memory flag + opnd[3] = register content/memory address + opnd[4] = source2 +*/ + +case CMPV: + r = op_extv (opnd, vfldrp1, acc); /* get field */ + if (r & byte_sign[op1]) r = r | ~byte_mask[op1]; + CC_CMP_L (r, op4); /* set cc's */ + break; +case CMPZV: + r = op_extv (opnd, vfldrp1, acc); /* get field */ + CC_CMP_L (r, op4); /* set cc's */ + break; + +/* Find first field instructions - ff? pos.rl,size.rb,base.wb,dst.wl + + opnd[0] = position + opnd[1] = size + opnd[2] = register number/memory flag + opnd[3] = register content/memory address + spec = register/memory flag + rn = register number + va = memory address +*/ + +case FFS: + r = op_extv (opnd, vfldrp1, acc); /* get field */ + temp = op_ffs (r, op1); /* find first 1 */ + WRITE_L (op0 + temp); /* store result */ + cc = r? 0: CC_Z; /* set cc's */ + break; +case FFC: + r = op_extv (opnd, vfldrp1, acc); /* get field */ + r = r ^ byte_mask[op1]; /* invert bits */ + temp = op_ffs (r, op1); /* find first 1 */ + WRITE_L (op0 + temp); /* store result */ + cc = r? 0: CC_Z; /* set cc's */ + break; + +/* Insert field instruction - insv src.rl,pos.rb,size.rl,base.wb + + opnd[0] = source + opnd[1] = position + opnd[2] = size + opnd[3] = register number/memory flag + opnd[4] = register content/memory address +*/ + +case INSV: + op_insv (opnd, vfldrp1, acc); /* insert field */ + break; + +/* Call and return - call? arg.rx,proc.ab + + opnd[0] = argument + opnd[1] = procedure address +*/ + +case CALLS: + cc = op_call (opnd, TRUE, acc); + break; +case CALLG: + cc = op_call (opnd, FALSE, acc); + break; +case RET: + cc = op_ret (acc); + break; + +/* Miscellaneous instructions */ + +case HALT: + if (PSL & PSL_CUR) RSVD_INST_FAULT; /* not kern? rsvd inst */ + else if (cpu_unit.flags & UNIT_CONH) { /* halt to console? */ + conpc = PC; /* save PC */ + conpsl = ((PSL | cc) & 0xFFFF00FF) | CON_HLTINS; /* PSL, param */ + temp = (PSL >> PSL_V_CUR) & 0x7; /* get is'cur */ + if (temp > 4) conpsl = conpsl | CON_BADPSL; /* invalid? */ + else STK[temp] = SP; /* save stack */ + if (mapen) conpsl = conpsl | CON_MAPON; /* mapping on? */ + mapen = 0; /* turn off map */ + SP = IS; /* set SP from IS */ + PSL = PSL_IS | PSL_IPL1F; /* PSL = 41F0000 */ + cc = 0; + JUMP (ROMBASE); } /* PC = 20040000 */ + else { ABORT (STOP_HALT); } /* halt to simulator */ +case NOP: + break; +case BPT: + SETPC (fault_PC); + cc = intexc (SCB_BPT, cc, 0, IE_EXC); + GET_CUR; + break; +case XFC: + SETPC (fault_PC); + cc = intexc (SCB_XFC, cc, 0, IE_EXC); + GET_CUR; + break; +case BISPSW: + if (opnd[0] & PSW_MBZ) RSVD_OPND_FAULT; + PSL = PSL | (opnd[0] & ~CC_MASK); + cc = cc | (opnd[0] & CC_MASK); + break; +case BICPSW: + if (opnd[0] & PSW_MBZ) RSVD_OPND_FAULT; + PSL = PSL & ~opnd[0]; + cc = cc & ~opnd[0]; + break; +case MOVPSL: + r = PSL | cc; + WRITE_L (r); + break; +case PUSHR: + op_pushr (opnd, acc); + break; +case POPR: + op_popr (opnd, acc); + break; +case INDEX: + if ((op0 < op1) || (op0 > op2)) SET_TRAP (TRAP_SUBSCR); + r = (op0 + op4) * op3; + WRITE_L (r); + CC_IIZZ_L (r); + break; + +/* Queue and interlocked queue */ + +case INSQUE: + cc = op_insque (opnd, acc); + break; +case REMQUE: + cc = op_remque (opnd, acc); + break; +case INSQHI: + cc = op_insqhi (opnd, acc); + break; +case INSQTI: + cc = op_insqti (opnd, acc); + break; +case REMQHI: + cc = op_remqhi (opnd, acc); + break; +case REMQTI: + cc = op_remqti (opnd, acc); + break; + +/* String instructions */ + +case MOVC3: +case MOVC5: + cc = op_movc (opnd, opc & 4, acc); + break; +case CMPC3: +case CMPC5: + cc = op_cmpc (opnd, opc & 4, acc); + break; +case LOCC: +case SKPC: + cc = op_locskp (opnd, opc & 1, acc); + break; +case SCANC: +case SPANC: + cc = op_scnspn (opnd, opc & 1, acc); + break; + +/* Floating point instructions */ + +case TSTF: case TSTD: + r = op_movfd (op0); + CC_IIZZ_FP (r); + break; +case TSTG: + r = op_movg (op0); + CC_IIZZ_FP (r); + break; + +case MOVF: + r = op_movfd (op0); + WRITE_L (r); + CC_IIZP_FP (r); + break; +case MOVD: + if ((r = op_movfd (op0)) == 0) op1 = 0; + WRITE_Q (r, op1); + CC_IIZP_FP (r); + break; +case MOVG: + if ((r = op_movg (op0)) == 0) op1 = 0; + WRITE_Q (r, op1); + CC_IIZP_FP (r); + break; + +case MNEGF: + r = op_mnegfd (op0); + WRITE_L (r); + CC_IIZZ_FP (r); + break; +case MNEGD: + if ((r = op_mnegfd (op0)) == 0) op1 = 0; + WRITE_Q (r, op1); + CC_IIZZ_FP (r); + break; +case MNEGG: + if ((r = op_mnegg (op0)) == 0) op1 = 0; + WRITE_Q (r, op1); + CC_IIZZ_FP (r); + break; + +case CMPF: + cc = op_cmpfd (op0, 0, op1, 0); + break; +case CMPD: + cc = op_cmpfd (op0, op1, op2, op3); + break; +case CMPG: + cc = op_cmpg (op0, op1, op2, op3); + break; + +case CVTBF: + r = op_cvtifdg (SXTB (op0), NULL, opc); + WRITE_L (r); + CC_IIZZ_FP (r); + break; +case CVTWF: + r = op_cvtifdg (SXTW (op0), NULL, opc); + WRITE_L (r); + CC_IIZZ_FP (r); + break; +case CVTLF: + r = op_cvtifdg (op0, NULL, opc); + WRITE_L (r); + CC_IIZZ_FP (r); + break; +case CVTBD: case CVTBG: + r = op_cvtifdg (SXTB (op0), &rh, opc); + WRITE_Q (r, rh); + CC_IIZZ_FP (r); + break; +case CVTWD: case CVTWG: + r = op_cvtifdg (SXTW (op0), &rh, opc); + WRITE_Q (r, rh); + CC_IIZZ_FP (r); + break; +case CVTLD: case CVTLG: + r = op_cvtifdg (op0, &rh, opc); + WRITE_Q (r, rh); + CC_IIZZ_FP (r); + break; + +case CVTFB: case CVTDB: case CVTGB: + r = op_cvtfdgi (opnd, &temp, opc) & BMASK; + WRITE_B (r); + CC_IIZZ_B (r); + cc = cc | temp; + break; +case CVTFW: case CVTDW: case CVTGW: + r = op_cvtfdgi (opnd, &temp, opc) & WMASK; + WRITE_W (r); + CC_IIZZ_W (r); + cc = cc | temp; + break; +case CVTFL: case CVTDL: case CVTGL: +case CVTRFL: case CVTRDL: case CVTRGL: + r = op_cvtfdgi (opnd, &temp, opc) & LMASK; + WRITE_L (r); + CC_IIZZ_L (r); + cc = cc | temp; + break; + +case CVTFD: + r = op_movfd (op0); + WRITE_Q (r, 0); + CC_IIZZ_FP (r); + break; +case CVTDF: + r = op_cvtdf (opnd); + WRITE_L (r); + CC_IIZZ_FP (r); + break; +case CVTFG: + r = op_cvtfg (opnd, &rh); + WRITE_Q (r, rh); + CC_IIZZ_FP (r); + break; +case CVTGF: + r = op_cvtgf (opnd); + WRITE_L (r); + CC_IIZZ_FP (r); + break; + +case ADDF2: case ADDF3: + r = op_addf (opnd, FALSE); + WRITE_L (r); + CC_IIZZ_FP (r); + break; +case ADDD2: case ADDD3: + r = op_addd (opnd, &rh, FALSE); + WRITE_Q (r, rh); + CC_IIZZ_FP (r); + break; +case ADDG2: case ADDG3: + r = op_addg (opnd, &rh, FALSE); + WRITE_Q (r, rh); + CC_IIZZ_FP (r); + break; +case SUBF2: case SUBF3: + r = op_addf (opnd, TRUE); + WRITE_L (r); + CC_IIZZ_FP (r); + break; +case SUBD2: case SUBD3: + r = op_addd (opnd, &rh, TRUE); + WRITE_Q (r, rh); + CC_IIZZ_FP (r); + break; +case SUBG2: case SUBG3: + r = op_addg (opnd, &rh, TRUE); + WRITE_Q (r, rh); + CC_IIZZ_FP (r); + break; +case MULF2: case MULF3: + r = op_mulf (opnd); + WRITE_L (r); + CC_IIZZ_FP (r); + break; +case MULD2: case MULD3: + r = op_muld (opnd, &rh); + WRITE_Q (r, rh); + CC_IIZZ_FP (r); + break; +case MULG2: case MULG3: + r = op_mulg (opnd, &rh); + WRITE_Q (r, rh); + CC_IIZZ_FP (r); + break; +case DIVF2: case DIVF3: + r = op_divf (opnd); + WRITE_L (r); + CC_IIZZ_FP (r); + break; +case DIVD2: case DIVD3: + r = op_divd (opnd, &rh); + WRITE_Q (r, rh); + CC_IIZZ_FP (r); + break; +case DIVG2: case DIVG3: + r = op_divg (opnd, &rh); + WRITE_Q (r, rh); + CC_IIZZ_FP (r); + break; + +case ACBF: + r = op_addf (opnd + 1, FALSE); /* add + index */ + temp = op_cmpfd (r, 0, op0, 0); /* result : limit */ + WRITE_L (r); /* write result */ + CC_IIZP_FP (r); /* set cc's */ + if ((temp & CC_Z) || ((op1 & FPSIGN)? /* test br cond */ + !(temp & CC_N): (temp & CC_N))) BRANCHW (brdisp); + break; +case ACBD: + r = op_addd (opnd + 2, &rh, FALSE); + temp = op_cmpfd (r, rh, op0, op1); + WRITE_Q (r, rh); + CC_IIZP_FP (r); + if ((temp & CC_Z) || ((op1 & FPSIGN)? /* test br cond */ + !(temp & CC_N): (temp & CC_N))) BRANCHW (brdisp); + break; +case ACBG: + r = op_addg (opnd + 2, &rh, FALSE); + temp = op_cmpg (r, rh, op0, op1); + WRITE_Q (r, rh); + CC_IIZP_FP (r); + if ((temp & CC_Z) || ((op1 & FPSIGN)? /* test br cond */ + !(temp & CC_N): (temp & CC_N))) BRANCHW (brdisp); + break; + +/* EMODF + + op0 = extension + op1 = multiplier + op2 = multiplicand + op3:op4 = integer destination (int.wl) + op5:op6 = floating destination (flt.wl) +*/ + +case EMODF: + r = op_emodf (opnd, &temp, &flg); + if (op5 < 0) Read (op6, L_LONG, WA); + if (op3 >= 0) R[op3] = temp; + else Write (op4, temp, L_LONG, WA); + WRITE_L (r); + CC_IIZZ_FP (r); + if (flg) { V_INTOV; } + break; + +/* EMODD, EMODG + + op0 = extension + op1:op2 = multiplier + op3:op4 = multiplicand + op5:op6 = integer destination (int.wl) + op7:op8 = floating destination (flt.wq) +*/ + +case EMODD: + r = op_emodd (opnd, &rh, &temp, &flg); + if (op7 < 0) Read (op8, L_LONG, WA); + if (op5 >= 0) R[op5] = temp; + else Write (op6, temp, L_LONG, WA); + WRITE_Q (r, rh); + CC_IIZZ_FP (r); + if (flg) { V_INTOV; } + break; + +case EMODG: + r = op_emodg (opnd, &rh, &temp, &flg); + if (op7 < 0) Read (op8, L_LONG, WA); + if (op5 >= 0) R[op5] = temp; + else Write (op6, temp, L_LONG, WA); + WRITE_Q (r, rh); + CC_IIZZ_FP (r); + if (flg) { V_INTOV; } + break; + +/* POLY */ + +case POLYF: + op_polyf (opnd, acc); + CC_IIZZ_FP (R[0]); + break; + +case POLYD: + op_polyd (opnd, acc); + CC_IIZZ_FP (R[0]); + break; + +case POLYG: + op_polyg (opnd, acc); + CC_IIZZ_FP (R[0]); + break; + +/* Operating system instructions */ + +case CHMK: case CHME: case CHMS: case CHMU: + cc = op_chm (opnd, cc, opc); /* CHMx */ + GET_CUR; /* update cur mode */ + SET_IRQL; /* update intreq */ + break; +case REI: + cc = op_rei (acc); /* REI */ + GET_CUR; /* update cur mode */ + SET_IRQL; /* update intreq */ + break; +case LDPCTX: + op_ldpctx (acc); + break; +case SVPCTX: + op_svpctx (acc); + break; +case PROBER: case PROBEW: + cc = (cc & CC_C) | op_probe (opnd, opc & 1); + break; +case MTPR: + cc = (cc & CC_C) | op_mtpr (opnd); + SET_IRQL; /* update intreq */ + break; +case MFPR: + r = op_mfpr (opnd); + WRITE_L (r); + CC_IIZP_L (r); + break; + +/* Emulated instructions */ + +case CVTPL: + opnd[2] = (opnd[2] >= 0)? ~opnd[2]: opnd[3]; +case MOVP: case CMPP3: case CMPP4: case CVTLP: +case CVTPS: case CVTSP: case CVTTP: case CVTPT: +case ADDP4: case ADDP6: case SUBP4: case SUBP6: +case MULP: case DIVP: case ASHP: case CRC: +case MOVTC: case MOVTUC: case MATCHC: case EDITPC: + cc = op_emulate (opnd, cc, opc, acc); + break; +default: + RSVD_INST_FAULT; + break; } /* end case op */ +} /* end for */ +ABORT (STOP_UNKNOWN); +} /* end sim_instr */ + +/* Prefetch buffer routine + + Prefetch buffer state + + ibufl, ibufh = the prefetch buffer + ibcnt = number of bytes available (0, 4, 8) + ppc = physical PC + + The get_istr routines fetches the indicated number of bytes from + the prefetch buffer. Although it is complicated, it is faster + than calling Read on every byte of the instruction stream. + + If the prefetch buffer has enough bytes, the required bytes are + extracted from the prefetch buffer and returned. If it does not + have enough bytes, enough prefetch words are fetched until there + are. A longword is only prefetched if data is needed from it, + so any translation errors are real. +*/ + +int32 get_istr (int32 lnt, int32 acc) +{ +int32 bo = PC & 3; +int32 sc, val, t; + +while ((bo + lnt) > ibcnt) { /* until enuf bytes */ + if ((ppc < 0) || (VA_GETOFF (ppc) == 0)) { /* PPC inv, xpg? */ + ppc = Test ((PC + ibcnt) & ~03, RD, &t); /* xlate PC */ + if (ppc < 0) Read ((PC + ibcnt) & ~03, L_LONG, RA); } + if (ibcnt == 0) ibufl = ReadLP (ppc); /* fill low */ + else ibufh = ReadLP (ppc); /* or high */ + ppc = ppc + 4; /* incr phys PC */ + ibcnt = ibcnt + 4; } /* incr ibuf cnt */ +PC = PC + lnt; /* incr PC */ +if (lnt == L_BYTE) val = (ibufl >> (bo << 3)) & BMASK; /* byte? */ +else if (lnt == L_WORD) { /* word? */ + if (bo == 3) val = ((ibufl >> 24) & 0xFF) | ((ibufh & 0xFF) << 8); + else val = (ibufl >> (bo << 3)) & WMASK; } +else if (bo) { /* unaligned lw? */ + sc = bo << 3; + val = (((ibufl >> sc) & align[bo]) | (((uint32) ibufh) << (32 - sc))); } +else val = ibufl; /* aligned lw */ +if ((bo + lnt) >= 4) { /* retire ibufl? */ + ibufl = ibufh; + ibcnt = ibcnt - 4; } +return val; +} + +/* To do list: + Examine/deposit I/O +*/ + +/* Reset */ + +t_stat cpu_reset (DEVICE *dptr) +{ +mem_err = 0; +crd_err = 0; +PSL = PSL_IS | PSL_IPL1F; +SISR = 0; +ASTLVL = 4; +MSER = 0; +CADR = 0; +mapen = 0; +if (M == NULL) M = calloc (MEMSIZE >> 2, sizeof (int32)); +if (M == NULL) return SCPE_MEM; +pcq_r = find_reg ("PCQ", NULL, dptr); +if (pcq_r) pcq_r -> qptr = 0; +else return SCPE_IERR; +sim_brk_types = sim_brk_dflt = SWMASK ('E'); +return SCPE_OK; +} + +/* Bootstrap */ + +t_stat cpu_boot (int32 unitno) +{ +extern int32 clk_csr; +extern t_stat qba_powerup (void); +extern t_stat sysd_powerup (void); +extern t_stat todr_powerup (void); + +qba_powerup (); +sysd_powerup (); +todr_powerup (); +PC = ROMBASE; +PSL = PSL_IS | PSL_IPL1F; +conpc = 0; +conpsl = PSL_IS | PSL_IPL1F | CON_PWRUP; +return SCPE_OK; +} + +/* Memory examine */ + +t_stat cpu_ex (t_value *vptr, t_addr addr, UNIT *uptr, int32 sw) +{ +int32 st; + +if (vptr == NULL) return SCPE_ARG; +if (sw & SWMASK ('V')) addr = Test (addr, RD, &st); +else addr = addr & PAMASK; +if (ADDR_IS_MEM (addr) || ADDR_IS_CDG (addr) || + ADDR_IS_ROM (addr) || ADDR_IS_NVR (addr)) { + *vptr = (uint32) ReadB (addr); + return SCPE_OK; } +return SCPE_NXM; +} + +/* Memory deposit */ + +t_stat cpu_dep (t_value val, t_addr addr, UNIT *uptr, int32 sw) +{ +int32 st; + +if (sw & SWMASK ('V')) addr = Test (addr, RD, &st); +else addr = addr & PAMASK; +if (ADDR_IS_MEM (addr) || ADDR_IS_CDG (addr) || + ADDR_IS_NVR (addr)) { + WriteB (addr, (int32) val); + return SCPE_OK; } +if (ADDR_IS_ROM (addr)) { + rom_wr (addr, (int32) val, L_BYTE); + return SCPE_OK; } +return SCPE_NXM; +} + +/* Memory allocation */ + +t_stat cpu_set_size (UNIT *uptr, int32 val, char *cptr, void *desc) +{ +int32 mc = 0; +t_addr i, clim; +uint32 *nM = NULL; + +if ((val <= 0) || (val > MAXMEMSIZE)) return SCPE_ARG; +for (i = val; i < MEMSIZE; i = i + 4) mc = mc | M[i >> 2]; +if ((mc != 0) && !get_yn ("Really truncate memory [N]?", FALSE)) + return SCPE_OK; +nM = calloc (val >> 2, sizeof (uint32)); +if (nM == NULL) return SCPE_MEM; +clim = (((t_addr) val) < MEMSIZE)? val: MEMSIZE; +for (i = 0; i < clim; i = i + 4) nM[i >> 2] = M[i >> 2]; +free (M); +M = nM; +MEMSIZE = val; +return SCPE_OK; } + +/* Virtual address translation */ + +t_stat cpu_show_virt (UNIT *uptr, int32 val, char *cptr, void *desc) +{ +t_stat r; +t_addr va, pa; +int32 st; +static const char *mm_str[] = { + "Access control violation", + "Length violation", + "Process PTE access control violation", + "Process PTE length violation", + "Translation not valid", + "Internal error", + "Process PTE translation not valid" }; + +if (cptr == NULL) return SCPE_ARG; +va = (t_addr) get_uint (cptr, 16, 0xFFFFFFFF, &r); +if (r != SCPE_OK) return SCPE_ARG; +pa = Test (va, RD, &st); +if (st == PR_OK) printf ("Virtual %-X = physical %-X\n", va, pa); +else printf ("Virtual %-X: %s\n", va, mm_str[st]); +return SCPE_OK; +} diff --git a/VAX/vax_cpu1.c b/VAX/vax_cpu1.c new file mode 100644 index 00000000..da1ad948 --- /dev/null +++ b/VAX/vax_cpu1.c @@ -0,0 +1,1489 @@ +/* vax_cpu1.c: VAX complex instructions + + Copyright (c) 1998-2002, Robert M Supnik + + Permission is hereby granted, free of charge, to any person obtaining a + copy of this software and associated documentation files (the "Software"), + to deal in the Software without restriction, including without limitation + the rights to use, copy, modify, merge, publish, distribute, sublicense, + and/or sell copies of the Software, and to permit persons to whom the + Software is furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + ROBERT M SUPNIK BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + Except as contained in this notice, the name of Robert M Supnik shall not + be used in advertising or otherwise to promote the sale, use or other dealings + in this Software without prior written authorization from Robert M Supnik. + + 30-Apr-02 RMS Fixed interrupt/exception handler to clear traps + 17-Apr-02 RMS Fixed pos > 31 test in bit fields (should be unsigned) + 14-Apr-02 RMS Fixed prv_mode handling for interrupts (found by Tim Stark) + Fixed PROBEx to mask mode to 2b (found by Kevin Handy) + + This module contains the instruction simulators for + + Field instructions: + - BBS, BBC, BBSSI, BBCCI + - BBSC, BBCC, BBCS, BBSS + - EXTV, EXTZV, CMPV, CMPZV + - FFS, FFC, INSV + + Call/return and push/pop instructions: + - CALLS, CALLG, RET + - PUSHR, POPR + + Queue instructions: + - INSQUE, REMQUE + - INSQHI, INSQTI, REMQHI, REMQTI + + String instructions: + - MOVC3, MOVC5, CMPC3, CMPC5 + - LOCC, SKPC, SCANC, SPANC + + Operating system interface instructions: + - CHMK, CHME, CHMS, CHMU + - PROBER, PROBEW, REI + - MTPR, MFPR + - LDPCTX, SVPCTX + - (interrupt and exception routine) + + Emulated instructions: + - MOVP, CMPP3, CMPP4, ASHP + - ADDP4, ADDP6, SUBP4, SUBP6 + - MULP, DIVP, CVTLP, CVTPL, + - CVTPT, CVTTP, CVTPS, CVTSP + - EDITPC, CRC + - MATCHC, MOVTC, MOVTUC +*/ + +#include "vax_defs.h" + +static const uint8 rcnt[128] = { + 0, 4, 4, 8, 4, 8, 8,12, 4, 8, 8,12, 8,12,12,16, /* 00 - 0F */ + 4, 8, 8,12, 8,12,12,16, 8,12,12,16,12,16,16,20, /* 10 - 1F */ + 4, 8, 8,12, 8,12,12,16, 8,12,12,16,12,16,16,20, /* 20 - 2F */ + 8,12,12,16,12,16,16,20,12,16,16,20,16,20,20,24, /* 30 - 3F */ + 4, 8, 8,12, 8,12,12,16, 8,12,12,16,12,16,16,20, /* 40 - 4F */ + 8,12,12,16,12,16,16,20,12,16,16,20,16,20,20,24, /* 50 - 5F */ + 8,12,12,16,12,16,16,20,12,16,16,20,16,20,20,24, /* 60 - 6F */ +12,16,16,20,16,20,20,24,16,20,20,24,20,24,24,28 /* 70 - 7F */ +}; + +int32 last_chm = 0; + +extern uint32 *M; +extern uint32 byte_mask[33]; +extern int32 R[16]; +extern int32 STK[5]; +extern int32 PSL; +extern int32 SCBB, PCBB, SBR, SLR; +extern int32 P0BR, P0LR, P1BR, P1LR; +extern int32 ASTLVL, SISR, mapen; +extern int32 CADR, MSER; +extern int32 trpirq; +extern int32 p1, p2; +extern int32 conpsl, conpc; +extern int32 fault_PC; +extern int32 pcq[PCQ_SIZE]; +extern int32 pcq_p; +extern int32 in_ie; +extern int32 mchk_va; +extern int32 sim_interval; +extern int32 ibcnt, ppc; +extern int32 cpu_log; +extern FILE *sim_log; + +extern int32 Read (t_addr va, int32 lnt, int32 acc); +extern void Write (t_addr va, int32 val, int32 lnt, int32 acc); +extern int32 Test (t_addr va, int32 acc, int32 *status); +extern int32 ReadLP (t_addr pa); +extern void WriteLP (t_addr pa, int32 val); +extern void set_map_reg (void); +extern void zap_tb (int stb); +extern void zap_tb_ent (t_addr va); +extern t_bool chk_tb_ent (t_addr va); +extern int32 ReadIPR (int32 rg); +extern void WriteIPR (int32 rg, int32 val); +extern jmp_buf save_env; + +/* Branch on bit and no modify + Branch on bit and modify + + opnd[0] = position (pos.rl) + opnd[1] = register number/memory flag + opnd[2] = memory address, if memory + Returns bit to be tested +*/ + +int32 op_bb_n (int32 *opnd, int32 acc) +{ +int32 pos = opnd[0]; +int32 rn = opnd[1]; +int32 ea, by; + +if (rn >= 0) { /* register? */ + if (((uint32) pos) > 31) RSVD_OPND_FAULT; /* pos > 31? fault */ + return (R[rn] >> pos) & 1; } /* get bit */ +ea = opnd[2] + (pos >> 3); /* base byte addr */ +pos = pos & 07; /* pos in byte */ +by = Read (ea, L_BYTE, RA); /* read byte */ +return ((by >> pos) & 1); /* get bit */ +} + +int32 op_bb_x (int32 *opnd, int32 newb, int32 acc) +{ +int32 pos = opnd[0]; +int32 rn = opnd[1]; +int32 ea, by, bit; + +if (rn >= 0) { /* register? */ + if (((uint32) pos) > 31) RSVD_OPND_FAULT; /* pos > 31? fault */ + bit = (R[rn] >> pos) & 1; /* get bit */ + R[rn] = newb? (R[rn] | (1u << pos)): (R[rn] & ~(1u << pos)); + return bit; } +ea = opnd[2] + (pos >> 3); /* base byte addr */ +pos = pos & 07; /* pos in byte */ +by = Read (ea, L_BYTE, WA); /* read byte */ +bit = (by >> pos) & 1; /* get bit */ +by = newb? (by | (1u << pos)): (by & ~(1u << pos)); /* change bit */ +Write (ea, by, L_BYTE, WA); /* rewrite byte */ +return bit; +} + +/* Extract field + + opnd[0] = position (pos.rl) + opnd[1] = size (size.rb) + opnd[2] = register number/memory flag + opnd[3] = register content/memory address + + If the field is in a register, rn + 1 is in vfldrp1 +*/ + +int32 op_extv (int32 *opnd, int32 vfldrp1, int32 acc) +{ +int32 pos = opnd[0]; +int32 size = opnd[1]; +int32 rn = opnd[2]; +uint32 wd = opnd[3]; +int32 ba, wd1; + +if (size == 0) return 0; /* size 0? field = 0 */ +if (size > 32) RSVD_OPND_FAULT; /* size > 32? fault */ +if (rn >= 0) { /* register? */ + if (((uint32) pos) > 31) RSVD_OPND_FAULT; /* pos > 31? fault */ + if (pos) wd = (wd >> pos) | (((uint32) vfldrp1) << (32 - pos)); } +else { ba = wd + (pos >> 3); /* base byte addr */ + pos = (pos & 07) | ((ba & 03) << 3); /* bit offset */ + ba = ba & ~03; /* lw align base */ + wd = Read (ba, L_LONG, RA); /* read field */ + if ((size + pos) > 32) wd1 = Read (ba + 4, L_LONG, RA); + if (pos) wd = (wd >> pos) | (((uint32) wd1) << (32 - pos)); } +return wd & byte_mask[size]; +} + +/* Insert field + + opnd[0] = field (src.rl) + opnd[1] = position (pos.rl) + opnd[2] = size (size.rb) + opnd[3] = register number/memory flag + opnd[4] = register content/memory address + + If the field is in a register, rn + 1 is in vfldrp1 +*/ + +void op_insv (int32 *opnd, int32 vfldrp1, int32 acc) +{ +uint32 ins = opnd[0]; +int32 pos = opnd[1]; +int32 size = opnd[2]; +int32 rn = opnd[3]; +int32 val, mask, ba, wd, wd1; + +if (size == 0) return; /* size = 0? done */ +if (size > 32) RSVD_OPND_FAULT; /* size > 32? fault */ +if (rn >= 0) { /* in registers? */ + if (((uint32) pos) > 31) RSVD_OPND_FAULT; /* pos > 31? fault */ + if ((pos + size) > 32) { /* span two reg? */ + if (rn >= nSP) RSVD_OPND_FAULT; /* if PC, fault */ + mask = byte_mask[pos + size - 32]; /* insert fragment */ + val = ins >> (32 - pos); + R[rnplus1] = (vfldrp1 & ~mask) | (val & mask); } + mask = byte_mask[size] << pos; /* insert field */ + val = ins << pos; + R[rn] = (R[rn] & ~mask) | (val & mask); } +else { ba = opnd[4] + (pos >> 3); /* base byte addr */ + pos = (pos & 07) | ((ba & 03) << 3); /* bit offset */ + ba = ba & ~03; /* lw align base */ + wd = Read (ba, L_LONG, WA); /* read field */ + if ((size + pos) > 32) { /* field span lw? */ + wd1 = Read (ba + 4, L_LONG, WA); /* read 2nd lw */ + mask = byte_mask[pos + size - 32]; /* insert fragment */ + val = ins >> (32 - pos); + Write (ba + 4, (wd1 & ~mask) | (val & mask), L_LONG, WA); } + mask = byte_mask[size] << pos; /* insert field */ + val = ins << pos; + Write (ba, (wd & ~mask) | (val & mask), L_LONG, WA); } +return; +} + +/* Find first */ + +int32 op_ffs (uint32 wd, int32 size) +{ +int32 i; + +for (i = 0; wd; i++, wd = wd >> 1) if (wd & 1) return i; +return size; +} + +#define CALL_DV 0x8000 /* DV set */ +#define CALL_IV 0x4000 /* IV set */ +#define CALL_MBZ 0x3000 /* MBZ */ +#define CALL_MASK 0x0FFF /* mask */ +#define CALL_V_SPA 30 /* SPA */ +#define CALL_M_SPA 03 +#define CALL_V_S 29 /* S flag */ +#define CALL_S (1 << CALL_V_S) +#define CALL_V_MASK 16 +#define CALL_PUSH(n) if ((mask >> (n)) & 1) { \ + tsp = tsp - 4; \ + Write (tsp, R[n], L_LONG, WA); } +#define CALL_GETSPA(x) (((x) >> CALL_V_SPA) & CALL_M_SPA) +#define RET_POP(n) if ((spamask >> (n + CALL_V_MASK)) & 1) { \ + R[n] = Read (tsp, L_LONG, RA); \ + tsp = tsp + 4; } +#define PUSHR_PUSH(n) CALL_PUSH(n) +#define POPR_POP(n) if ((mask >> (n)) & 1) { \ + R[n] = Read (SP, L_LONG, RA); \ + SP = SP + 4; } + +/* CALLG, CALLS + + opnd[0] = argument (arg.rx) + opnd[1] = procedure address (adr.ab) + flg = CALLG (0), CALLS (1) + acc = access mask + + These instructions implement a generalized procedure call and return facility. + The principal data structure involved is the stack frame. + CALLS and CALLG build a stack frame in the following format: + + + +---------------------------------------------------------------+ + | condition handler (initially 0) | + +---+-+-+-----------------------+--------------------+----------+ + |SPA|S|0| entry mask<11:0> | saved PSW<15:5> | 0 0 0 0 0| + +---+-+-+-----------------------+--------------------+----------+ + | saved AP | + +---------------------------------------------------------------+ + | saved FP | + +---------------------------------------------------------------+ + | saved PC | + +---------------------------------------------------------------+ + | saved R0 (...) | + +---------------------------------------------------------------+ + . . + . (according to entry mask<11:0>) . + . . + +---------------------------------------------------------------+ + | saved R11 (...) | + +---------------+-----------------------------------------------+ + | #args (CALLS) | (0-3 bytes needed to align stack) | + +---------------+-----------------------------------------------+ + | | 0 0 0 (CALLS) | + +---------------+-----------------------------------------------+ + + RET expects to find this structure based at the frame pointer (FP). + + For CALLG and CALLS, the entry mask specifies the new settings of + DV and IV, and also which registers are to be saved on entry: + + 15 14 13 12 11 0 + +--+--+-----+----------------------------------+ + |DV|IV| MBZ | register mask | + +--+--+-----+----------------------------------+ + + CALLG/CALLS operation: + + read the procedure entry mask + make sure that the stack frame will be accessible + if CALLS, push the number of arguments onto the stack + align the stack to the next lower longword boundary + push the registers specified by the procedure entry mask + push PC, AP, FP, saved SPA/S0/mask/PSW, condition handler + update PC, SP, FP, AP + update PSW traps, clear condition codes +*/ + +int32 op_call (int32 *opnd, t_bool gs, int32 acc) +{ +int32 addr = opnd[1]; +int32 mask, stklen, tsp, wd; + +mask = Read (addr, L_WORD, RA); /* get proc mask */ +if (mask & CALL_MBZ) RSVD_OPND_FAULT; /* test mbz */ +stklen = rcnt[mask & 077] + rcnt[(mask >> 6) & 077] + (gs? 24: 20); +Read (SP - stklen, L_BYTE, WA); /* wchk stk */ +if (gs) { + Write (SP - 4, opnd[0], L_LONG, WA); /* if S, push #arg */ + SP = SP - 4; } /* stack is valid */ +tsp = SP & ~CALL_M_SPA; /* lw align stack */ +CALL_PUSH (11); /* check mask bits, */ +CALL_PUSH (10); /* push sel reg */ +CALL_PUSH (9); +CALL_PUSH (8); +CALL_PUSH (7); +CALL_PUSH (6); +CALL_PUSH (5); +CALL_PUSH (4); +CALL_PUSH (3); +CALL_PUSH (2); +CALL_PUSH (1); +CALL_PUSH (0); +Write (tsp - 4, PC, L_LONG, WA); /* push PC */ +Write (tsp - 8, FP, L_LONG, WA); /* push AP */ +Write (tsp - 12, AP, L_LONG, WA); /* push FP */ +wd = ((SP & CALL_M_SPA) << CALL_V_SPA) | (gs << CALL_V_S) | + ((mask & CALL_MASK) << CALL_V_MASK) | (PSL & 0xFFE0); +Write (tsp - 16, wd, L_LONG, WA); /* push spa/s/mask/psw */ +Write (tsp - 20, 0, L_LONG, WA); /* push cond hdlr */ +if (gs) AP = SP; /* update AP */ +else AP = opnd[0]; +SP = FP = tsp - 20; /* update FP, SP */ +PSL = (PSL & ~(PSW_DV | PSW_FU | PSW_IV)) | /* update PSW */ + ((mask & CALL_DV)? PSW_DV: 0) | + ((mask & CALL_IV)? PSW_IV: 0); +JUMP (addr + 2); /* new PC */ +return 0; /* new cc's */ +} + +int32 op_ret (int32 acc) +{ +int32 spamask, stklen, newpc, nargs; +int32 tsp = FP; + +spamask = Read (tsp + 4, L_LONG, RA); /* spa/s/mask/psw */ +if (spamask & PSW_MBZ) RSVD_OPND_FAULT; /* test mbz */ +stklen = rcnt[(spamask >> CALL_V_MASK) & 077] + + rcnt[(spamask >> (CALL_V_MASK + 6)) & 077] + ((spamask & CALL_S)? 23: 19); +Read (tsp + stklen, L_BYTE, RA); /* rchk stk end */ +AP = Read (tsp + 8, L_LONG, RA); /* restore AP */ +FP = Read (tsp + 12, L_LONG, RA); /* restore FP */ +newpc = Read (tsp + 16, L_LONG, RA); /* get new PC */ +tsp = tsp + 20; /* update stk ptr */ +RET_POP (0); /* chk mask bits, */ +RET_POP (1); /* pop sel regs */ +RET_POP (2); +RET_POP (3); +RET_POP (4); +RET_POP (5); +RET_POP (6); +RET_POP (7); +RET_POP (8); +RET_POP (9); +RET_POP (10); +RET_POP (11); +SP = tsp + CALL_GETSPA (spamask); /* dealign stack */ +if (spamask & CALL_S) { /* CALLS? */ + nargs = Read (SP, L_LONG, RA); /* read #args */ + SP = SP + 4 + ((nargs & BMASK) << 2); } /* pop arg list */ +PSL = (PSL & ~(PSW_DV | PSW_FU | PSW_IV | PSW_T)) | /* reset PSW */ + (spamask & (PSW_DV | PSW_FU | PSW_IV | PSW_T)); +JUMP (newpc); /* set new PC */ +return spamask & (CC_MASK); /* return cc's */ +} + +/* PUSHR and POPR */ + +void op_pushr (int32 *opnd, int32 acc) +{ +int32 mask = opnd[0] & 0x7FFF; +int32 stklen, tsp; + +if (mask == 0) return; +stklen = rcnt[(mask >> 7) & 0177] + rcnt[mask & 0177] + + ((mask & 0x4000)? 4: 0); +Read (SP - stklen, L_BYTE, WA); /* wchk stk end */ +tsp = SP; /* temp stk ptr */ +PUSHR_PUSH (14); /* check mask bits, */ +PUSHR_PUSH (13); /* push sel reg */ +PUSHR_PUSH (12); +PUSHR_PUSH (11); +PUSHR_PUSH (10); +PUSHR_PUSH (9); +PUSHR_PUSH (8); +PUSHR_PUSH (7); +PUSHR_PUSH (6); +PUSHR_PUSH (5); +PUSHR_PUSH (4); +PUSHR_PUSH (3); +PUSHR_PUSH (2); +PUSHR_PUSH (1); +PUSHR_PUSH (0); +SP = tsp; /* update stk ptr */ +return; +} + +void op_popr (int32 *opnd, int32 acc) +{ +int32 mask = opnd[0] & 0x7FFF; +int32 stklen; + +if (mask == 0) return; +stklen = rcnt[(mask >> 7) & 0177] + rcnt[mask & 0177] + + ((mask & 0x4000)? 4: 0); +Read (SP + stklen - 1, L_BYTE, RA); /* rchk stk end */ +POPR_POP (0); /* check mask bits, */ +POPR_POP (1); /* pop sel regs */ +POPR_POP (2); +POPR_POP (3); +POPR_POP (4); +POPR_POP (5); +POPR_POP (6); +POPR_POP (7); +POPR_POP (8); +POPR_POP (9); +POPR_POP (10); +POPR_POP (11); +POPR_POP (12); +POPR_POP (13); +if (mask & 0x4000) SP = Read (SP, L_LONG, RA); /* if pop SP, no inc */ +return; +} + +/* INSQUE + + opnd[0] = entry address (ent.ab) + opnd[1] = predecessor address (pred.ab) + + Condition codes returned to caller on comparison of (ent):(ent+4). + All writes must be checked before any writes are done. + + Pictorially: + + BEFORE AFTER + + P: S P: E W + P+4: (n/a) P+4: (n/a) + + E: --- E: S W + E+4: --- E+4: P W + + S: (n/a) S: (n/a) + S+4: P S+4: E W + + s+4 must be tested with a read modify rather than a probe, as it + might be misaligned. +*/ + +int32 op_insque (int32 *opnd, int32 acc) +{ +int32 p = opnd[1]; +int32 e = opnd[0]; +int32 s, cc; + +s = Read (p, L_LONG, WA); /* s <- (p), wchk */ +Read (s + 4, L_LONG, WA); /* wchk s+4 */ +Read (e + 4, L_LONG, WA); /* wchk e+4 */ +Write (e, s, L_LONG, WA); /* (e) <- s */ +Write (e + 4, p, L_LONG, WA); /* (e+4) <- p */ +Write (s + 4, e, L_LONG, WA); /* (s+4) <- ent */ +Write (p, e, L_LONG, WA); /* (p) <- e */ +CC_CMP_L (s, p); /* set cc's */ +return cc; +} + +/* REMQUE + + opnd[0] = entry address (ent.ab) + opnd[1:2] = destination address (dst.wl) + + Condition codes returned to caller based on (ent):(ent+4). + All writes must be checked before any writes are done. + + Pictorially: + + BEFORE AFTER + + P: E P: S W + P+4: (n/a) P+4: (n/a) + + E: S W E: S + E+4: P W E+4: P + + S: (n/a) S: (n/a) + S+4: E W S+4: P + +*/ + +int32 op_remque (int32 *opnd, int32 acc) +{ +int32 e = opnd[0]; +int32 s, p, cc; + +s = Read (e, L_LONG, RA); /* s <- (e) */ +p = Read (e + 4, L_LONG, RA); /* p <- (e+4) */ +CC_CMP_L (s, p); /* set cc's */ +if (e != p) { /* queue !empty? */ + Read (s + 4, L_LONG, WA); /* wchk (s+4) */ + if (opnd[1] < 0) Read (opnd[2], L_LONG, WA); /* wchk dest */ + Write (p, s, L_LONG, WA); /* (p) <- s */ + Write (s + 4, p, L_LONG, WA); } /* (s+4) <- p */ +else cc = cc | CC_V; /* else set v */ +if (opnd[1] >= 0) R[opnd[1]] = e; /* store result */ +else Write (opnd[2], e, L_LONG, WA); +return cc; +} + +/* Interlocked insert instructions + + opnd[0] = entry (ent.ab) + opnd[1] = header (hdr.aq) + + Pictorially: + + BEFORE AFTER INSQHI AFTER INSQTI + + H: A-H H: D-H W H: A-H W for interlock + H+4: C-H H+4: C-H H+4: D-H W + + A: B-A A: B-A A: B-A + A+4: H-A A+4: D-A W A+4: H-A + + B: C-B B: C-B B: C-B + B+4: A-B B+4: A-B B+4: A-B + + C: H-C C: H-C C: D-C W + C+4: B-C C+4: B-C C+4: B-C + + D: --- D: A-D W D: H-D W + D+4: --- D+4: H-D W D+4: 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 + QUADWORD aligned. In addition, the header and the entry must + not be equal. +*/ + +int32 op_insqhi (int32 *opnd, int32 acc) +{ +int32 h = opnd[1]; +int32 d = opnd[0]; +int32 a, t; + +if ((h == d) || ((h | d) & 07)) RSVD_OPND_FAULT; /* h, d quad align? */ +Read (d, L_BYTE, WA); /* wchk ent */ +a = Read (h, L_LONG, WA); /* a <- (h), wchk */ +if (a & 06) RSVD_OPND_FAULT; /* chk quad align */ +if (a & 01) return CC_C; /* busy, cc = 0001 */ +Write (h, a | 1, L_LONG, WA); /* get interlock */ +a = a + h; /* abs addr of a */ +if (Test (a, WA, &t) < 0) Write (h, a - h, L_LONG, WA); /* wtst a, rls if err */ +Write (a + 4, d - a, L_LONG, WA); /* (a+4) <- d-a, flt ok */ +Write (d, a - d, L_LONG, WA); /* (d) <- a-d */ +Write (d + 4, h - d, L_LONG, WA); /* (d+4) <- h-d */ +Write (h, d - h, L_LONG, WA); /* (h) <- d-h, rls int */ +return (a == h)? CC_Z: 0; /* Z = 1 if a = h */ +} + +int32 op_insqti (int32 *opnd, int32 acc) +{ +int32 h = opnd[1]; +int32 d = opnd[0]; +int32 a, c, t; + +if ((h == d) || ((h | d) & 07)) RSVD_OPND_FAULT; /* h, d quad align? */ +Read (d, L_BYTE, WA); /* wchk ent */ +a = Read (h, L_LONG, WA); /* a <- (h), wchk */ +if (a == 0) return op_insqhi (opnd, acc); /* if empty, ins hd */ +if (a & 06) RSVD_OPND_FAULT; /* chk quad align */ +if (a & 01) return CC_C; /* busy, cc = 0001 */ +Write (h, a | 1, L_LONG, WA); /* acquire interlock */ +c = Read (h + 4, L_LONG, RA) + h; /* c <- (h+4) + h */ +if (c & 07) { /* c quad aligned? */ + Write (h, a, L_LONG, WA); /* release interlock */ + RSVD_OPND_FAULT; } /* fault */ +if (Test (c, WA, &t) < 0) Write (h, a, L_LONG, WA); /* wtst c, rls if err */ +Write (c, d - c, L_LONG, WA); /* (c) <- d-c, flt ok */ +Write (d, h - d, L_LONG, WA); /* (d) <- h-d */ +Write (d + 4, c - d, L_LONG, WA); /* (d+4) <- c-d */ +Write (h + 4, d - h, L_LONG, WA); /* (h+4) <- d-h */ +Write (h, a, L_LONG, WA); /* release interlock */ +return 0; /* q >= 2 entries */ +} + +/* Interlocked remove instructions + + opnd[0] = header (hdr.aq) + opnd[1:2] = destination address (dst.al) + + Pictorially: + + BEFORE AFTER REMQHI AFTER REMQTI + + H: A-H H: B-H W H: A-H W for interlock + H+4: C-H H+4: C-H H+4: B-H W + + A: B-A A: B-A R A: B-A + A+4: H-A A+4: H-A A+4: H-A + + B: C-B B: C-B B: H-B W + B+4: A-B B+4: H-B W B+4: A-B + + C: H-C C: H-C C: H-C + C+4: B-C C+4: B-C C+4: B-C R + + Note that the queue header and all the entries that are + "touched" in any way must be QUADWORD aligned. In addition, + the header and the destination must not be equal. +*/ + +int32 op_remqhi (int32 *opnd, int32 acc) +{ +int32 h = opnd[0]; +int32 ar, a, b, t; + +if (h & 07) RSVD_OPND_FAULT; /* h quad aligned? */ +if (opnd[1] < 0) { /* mem destination? */ + if (h == opnd[2]) RSVD_OPND_FAULT; /* hdr = dst? */ + Read (opnd[2], L_LONG, WA); } /* wchk dst */ +ar = Read (h, L_LONG, WA); /* ar <- (h) */ +if (ar & 06) RSVD_OPND_FAULT; /* a quad aligned? */ +if (ar & 01) return CC_V | CC_C; /* busy, cc = 0011 */ +a = ar + h; /* abs addr of a */ +if (ar) { /* queue not empty? */ + Write (h, ar | 1, L_LONG, WA); /* acquire interlock */ + if (Test (a, RA, &t) < 0) /* read tst a */ + Write (h, ar, L_LONG, WA); /* release if error */ + b = Read (a, L_LONG, RA) + a; /* b <- (a)+a, flt ok */ + if (b & 07) { /* b quad aligned? */ + Write (h, ar, L_LONG, WA); /* release interlock */ + RSVD_OPND_FAULT; } /* fault */ + if (Test (b, WA, &t) < 0) /* write test b */ + Write (h, ar, L_LONG, WA); /* release if err */ + Write (b + 4, h - b, L_LONG, WA); /* (b+4) <- h-b, flt ok */ + Write (h, b - h, L_LONG, WA); } /* (h) <- b-h, rls int */ +if (opnd[1] >= 0) R[opnd[1]] = a; /* store result */ +else Write (opnd[2], a, L_LONG, WA); +if (ar == 0) return CC_Z | CC_V; /* empty, cc = 0110 */ +return (b == h)? CC_Z: 0; /* if b = h, q empty */ +} + +int32 op_remqti (int32 *opnd, int32 acc) +{ +int32 h = opnd[0]; +int32 ar, b, c, t; + +if (h & 07) RSVD_OPND_FAULT; /* h quad aligned? */ +if (opnd[1] < 0) { /* mem destination? */ + if (h == opnd[2]) RSVD_OPND_FAULT; /* hdr = dst? */ + Read (opnd[2], L_LONG, WA); } /* wchk dst */ +ar = Read (h, L_LONG, WA); /* a <- (h) */ +if (ar & 06) RSVD_OPND_FAULT; /* a quad aligned? */ +if (ar & 01) return CC_V | CC_C; /* busy, cc = 0011 */ +if (ar) { /* queue not empty */ + Write (h, ar | 1, L_LONG, WA); /* acquire interlock */ + c = Read (h + 4, L_LONG, RA); /* c <- (h+4) */ + if (ar == c) { /* single entry? */ + Write (h, ar, L_LONG, WA); /* release interlock */ + return op_remqhi (opnd, acc); } /* treat as remqhi */ + if (c & 07) { /* c quad aligned? */ + Write (h, ar, L_LONG, WA); /* release interlock */ + RSVD_OPND_FAULT; } /* fault */ + c = c + h; /* abs addr of c */ + if (Test (c + 4, RA, &t) < 0) /* read test c+4 */ + Write (h, ar, L_LONG, WA); /* release if error */ + b = Read (c + 4, L_LONG, RA) + c; /* b <- (c+4)+c, flt ok */ + if (b & 07) { /* b quad aligned? */ + Write (h, ar, L_LONG, WA); /* release interlock */ + RSVD_OPND_FAULT; } /* fault */ + if (Test (b, WA, &t) < 0) /* write test b */ + Write (h, ar, L_LONG, WA); /* release if error */ + Write (b, h - b, L_LONG, WA); /* (b) <- h-b */ + Write (h + 4, b - h, L_LONG, WA); /* (h+4) <- b-h */ + Write (h, ar, L_LONG, WA); } /* release interlock */ +else c = h; /* empty, result = h */ +if (opnd[1] >= 0) R[opnd[1]] = c; /* store result */ +else Write (opnd[2], c, L_LONG, WA); +if (ar == 0) return CC_Z | CC_V; /* empty, cc = 0110 */ +return 0; /* q can't be empty */ +} + +/* String instructions */ + +#define MVC_FRWD 0 /* movc state codes */ +#define MVC_BACK 1 +#define MVC_FILL 3 /* must be 3 */ +#define MVC_M_STATE 3 +#define MVC_V_CC 2 +#define STR_V_DPC 24 +#define STR_M_DPC 0xFF +#define STR_V_CHR 16 +#define STR_M_CHR 0xFF +#define STR_LNMASK 0xFFFF +#define STR_GETDPC(x) (((x) >> STR_V_DPC) & STR_M_DPC) +#define STR_GETCHR(x) (((x) >> STR_V_CHR) & STR_M_CHR) +#define STR_PACK(m,x) ((((PC - fault_PC) & STR_M_DPC) << STR_V_DPC) | \ + (((m) & STR_M_CHR) << STR_V_CHR) | ((x) & STR_LNMASK)) + +/* MOVC3, MOVC5 + + if PSL = 0 and MOVC3, + opnd[0] = length + opnd[1] = source address + opnd[2] = dest address + + if PSL = 0 and MOVC5, + opnd[0] = source length + opnd[1] = source address + opnd[2] = fill + opnd[3] = dest length + opnd[4] = dest address + + if PSL = 1, + R0 = delta-PC/fill/initial move length + R1 = current source address + R2 = current move length + R3 = current dest address + R4 = dstlen - srclen (loop count if fill state) + R5 = cc/state +*/ + +int32 op_movc (int32 *opnd, int32 movc5, int32 acc) +{ +int32 i, cc, fill, wd; +int32 j, lnt, mlnt[3]; +static const int32 looplnt[3] = { L_BYTE, L_LONG, L_BYTE }; + +if (PSL & PSL_FPD) { /* FPD set? */ + SETPC (fault_PC + STR_GETDPC (R[0])); /* reset PC */ + fill = STR_GETCHR (R[0]); /* get fill */ + R[2] = R[2] & STR_LNMASK; /* mask lengths */ + if (R[4] > 0) R[4] = R[4] & STR_LNMASK; } +else { R[1] = opnd[1]; /* src addr */ + if (movc5) { /* MOVC5? */ + R[2] = (opnd[0] < opnd[3])? opnd[0]: opnd[3]; + R[3] = opnd[4]; /* dst addr */ + R[4] = opnd[3] - opnd[0]; /* dstlen - srclen */ + fill = opnd[2]; /* set fill */ + CC_CMP_W (opnd[0], opnd[3]); } /* set cc's */ + else { R[2] = opnd[0]; /* mvlen = srclen */ + R[3] = opnd[2]; /* dst addr */ + R[4] = fill = 0; /* no fill */ + cc = CC_Z; } /* set cc's */ + R[0] = STR_PACK (fill, R[2]); /* initial mvlen */ + if (R[2]) { /* any move? */ + if (((uint32) R[1]) < ((uint32) R[3])) { + R[1] = R[1] + R[2]; /* backward, adjust */ + R[3] = R[3] + R[2]; /* addr to end */ + R[5] = MVC_BACK; } /* set state */ + else R[5] = MVC_FRWD; } /* fwd, set state */ + else R[5] = MVC_FILL; /* fill, set state */ + R[5] = R[5] | (cc << MVC_V_CC); /* pack with state */ + PSL = PSL | PSL_FPD; } /* set FPD */ + +/* At this point, + + R0 = delta PC'fill'initial move length + R1 = current src addr + R2 = current move length + R3 = current dst addr + R4 = dst length - src length + R5 = cc'state +*/ + +switch (R[5] & MVC_M_STATE) { /* case on state */ +case MVC_FRWD: /* move forward */ + mlnt[0] = (4 - R[3]) & 3; /* length to align */ + if (mlnt[0] > R[2]) mlnt[0] = R[2]; /* cant exceed total */ + mlnt[1] = (R[2] - mlnt[0]) & ~03; /* aligned length */ + mlnt[2] = R[2] - mlnt[0] - mlnt[1]; /* tail */ + for (i = 0; i < 3; i++) { /* head, align, tail */ + lnt = looplnt[i]; /* length for loop */ + for (j = 0; j < mlnt[i]; j = j + lnt, sim_interval--) { +/* if (sim_interval == 0) ABORT (ABORT_INTR); */ + wd = Read (R[1], lnt, RA); /* read src */ + Write (R[3], wd, lnt, WA); /* write dst */ + R[1] = R[1] + lnt; /* inc src addr */ + R[3] = R[3] + lnt; /* inc dst addr */ + R[2] = R[2] - lnt; } } /* dec move lnt */ + goto FILL; /* check for fill */ +case MVC_BACK: /* move backward */ + mlnt[0] = R[3] & 03; /* length to align */ + if (mlnt[0] > R[2]) mlnt[0] = R[2]; /* cant exceed total */ + mlnt[1] = (R[2] - mlnt[0]) & ~03; /* aligned length */ + mlnt[2] = R[2] - mlnt[0] - mlnt[1]; /* tail */ + for (i = 0; i < 3; i++) { /* head, align, tail */ + lnt = looplnt[i]; /* length for loop */ + for (j = 0; j < mlnt[i]; j = j + lnt, sim_interval--) { +/* if (sim_interval == 0) ABORT (ABORT_INTR); */ + wd = Read (R[1] - lnt, lnt, RA); /* read src */ + Write (R[3] - lnt, wd, lnt, WA); /* write dst */ + R[1] = R[1] - lnt; /* dec src addr */ + R[3] = R[3] - lnt; /* dec dst addr */ + R[2] = R[2] - lnt; } } /* dec move lnt */ + R[1] = R[1] + (R[0] & STR_LNMASK); /* final src addr */ + R[3] = R[3] + (R[0] & STR_LNMASK); /* final dst addr */ +case MVC_FILL: /* fill */ +FILL: + if (R[4] <= 0) break; /* any fill? */ + R[5] = R[5] | MVC_FILL; /* set state */ + mlnt[0] = (4 - R[3]) & 3; /* length to align */ + if (mlnt[0] > R[4]) mlnt[0] = R[4]; /* cant exceed total */ + mlnt[1] = (R[4] - mlnt[0]) & ~03; /* aligned length */ + mlnt[2] = R[4] - mlnt[0] - mlnt[1]; /* tail */ + for (i = 0; i < 3; i++) { /* head, align, tail */ + lnt = looplnt[i]; /* length for loop */ + fill = fill & BMASK; /* fill for loop */ + if (lnt == L_LONG) fill = + (((uint32) fill) << 24) | (fill << 16) | (fill << 8) | fill; + for (j = 0; j < mlnt[i]; j = j + lnt, sim_interval--) { +/* if (sim_interval == 0) ABORT (ABORT_INTR); */ + Write (R[3], fill, lnt, WA); /* write fill */ + R[3] = R[3] + lnt; /* inc dst addr */ + R[4] = R[4] - lnt; } } /* dec fill lnt */ + break; +default: /* bad state */ + RSVD_OPND_FAULT; } /* you lose */ +PSL = PSL & ~PSL_FPD; /* clear FPD */ +cc = (R[5] >> MVC_V_CC) & CC_MASK; /* get cc's */ +R[0] = NEG (R[4]); /* set R0 */ +R[2] = R[4] = R[5] = 0; /* clear reg */ +return cc; +} + +/* CMPC3, CMPC5 + + if PSL = 0 and CMPC3, + opnd[0] = length + opnd[1] = source1 address + opnd[2] = source2 address + + if PSL = 0 and CMPC5, + opnd[0] = source1 length + opnd[1] = source1 address + opnd[2] = fill + opnd[3] = source2 length + opnd[4] = source2 address + + if PSL = 1, + R0 = delta-PC/fill/source1 length + R1 = source1 address + R2 = source2 length + R3 = source2 address +*/ + +int32 op_cmpc (int32 *opnd, int32 cmpc5, int32 acc) +{ +int32 cc, s1, s2, fill; + +if (PSL & PSL_FPD) { /* FPD set? */ + SETPC (fault_PC + STR_GETDPC (R[0])); /* reset PC */ + fill = STR_GETCHR (R[0]); } /* get fill */ +else { R[1] = opnd[1]; /* src1len */ + if (cmpc5) { /* CMPC5? */ + R[2] = opnd[3]; /* get src2 opnds */ + R[3] = opnd[4]; + fill = opnd[2]; } + else { R[2] = opnd[0]; /* src2len = src1len */ + R[3] = opnd[2]; + fill = 0; } + R[0] = STR_PACK (fill, opnd[0]); /* src1len + FPD data */ + PSL = PSL | PSL_FPD; } +R[2] = R[2] & STR_LNMASK; /* mask src2len */ +for (s1 = s2 = 0; ((R[0] | R[2]) & STR_LNMASK) != 0; sim_interval--) { +/* if (sim_interval == 0) ABORT (ABORT_INTR); /* timer event */ + if (R[0] & STR_LNMASK) s1 = Read (R[1], L_BYTE, RA); /* src1? read */ + else s1 = fill; /* no, use fill */ + if (R[2]) s2 = Read (R[3], L_BYTE, RA); /* src2? read */ + else s2 = fill; /* no, use fill */ + if (s1 != s2) break; /* src1 = src2? */ + if (R[0] & STR_LNMASK) { /* if src1, decr */ + R[0] = (R[0] & ~STR_LNMASK) | ((R[0] - 1) & STR_LNMASK); + R[1] = R[1] + 1; } + if (R[2]) { /* if src2, decr */ + R[2] = (R[2] - 1) & STR_LNMASK; + R[3] = R[3] + 1; } } +PSL = PSL & ~PSL_FPD; /* clear FPD */ +CC_CMP_B (s1, s2); /* set cc's */ +R[0] = R[0] & STR_LNMASK; /* clear packup */ +return cc; +} + +/* LOCC, SKPC + + if PSL = 0, + opnd[0] = match character + opnd[1] = source length + opnd[2] = source address + + if PSL = 1, + R0 = delta-PC/match/source length + R1 = source address +*/ + +int32 op_locskp (int32 *opnd, int32 skpc, int32 acc) +{ +int32 c, match; + +if (PSL & PSL_FPD) { /* FPD set? */ + SETPC (fault_PC + STR_GETDPC (R[0])); /* reset PC */ + match = STR_GETCHR (R[0]); } /* get match char */ +else { match = opnd[0]; /* get operands */ + R[0] = STR_PACK (match, opnd[1]); /* src len + FPD data */ + R[1] = opnd[2]; /* src addr */ + PSL = PSL | PSL_FPD; } +for ( ; (R[0] & STR_LNMASK) != 0; sim_interval-- ) { /* loop thru string */ +/* if (sim_interval == 0) ABORT (ABORT_INTR); /* timer event? */ + c = Read (R[1], L_BYTE, RA); /* get src byte */ + if ((c == match) ^ skpc) break; /* match & locc? */ + R[0] = (R[0] & ~STR_LNMASK) | ((R[0] - 1) & STR_LNMASK); + R[1] = R[1] + 1; } /* incr src1adr */ +PSL = PSL & ~PSL_FPD; /* clear FPD */ +R[0] = R[0] & STR_LNMASK; /* clear packup */ +return (R[0]? 0: CC_Z); /* set cc's */ +} + +/* SCANC, SPANC + + if PSL = 0, + opnd[0] = source length + opnd[1] = source address + opnd[2] = table address + opnd[3] = mask + + if PSL = 1, + R0 = delta-PC/char/source length + R1 = source address + R3 = table address +*/ + +int32 op_scnspn (int32 *opnd, int32 spanc, int32 acc) +{ +int32 c, t, mask; + +if (PSL & PSL_FPD) { /* FPD set? */ + SETPC (fault_PC + STR_GETDPC (R[0])); /* reset PC */ + mask = STR_GETCHR (R[0]); } /* get mask */ +else { R[1] = opnd[1]; /* src addr */ + R[3] = opnd[2]; /* tblad */ + mask = opnd[3]; /* mask */ + R[0] = STR_PACK (mask, opnd[0]); /* srclen + FPD data */ + PSL = PSL | PSL_FPD; } +for ( ; (R[0] & STR_LNMASK) != 0; sim_interval-- ) { /* loop thru string */ +/* if (sim_interval == 0) ABORT (ABORT_INTR); /* timer event? */ + c = Read (R[1], L_BYTE, RA); /* get byte */ + t = Read (R[3] + c, L_BYTE, RA); /* get table ent */ + if (((t & mask) != 0) ^ spanc) break; /* test vs instr */ + R[0] = (R[0] & ~STR_LNMASK) | ((R[0] - 1) & STR_LNMASK); + R[1] = R[1] + 1; } +PSL = PSL & ~PSL_FPD; +R[0] = R[0] & STR_LNMASK; /* clear packup */ +R[2] = 0; +return (R[0]? 0: CC_Z); +} + +/* Operating system interfaces */ + +/* Interrupt or exception + + vec = SCB vector + cc = condition codes + ipl = new IPL if interrupt + ei = -1: severe exception + 0: normal exception + 1: interrupt +*/ + +int32 intexc (int32 vec, int32 cc, int32 ipl, int ei) +{ +int32 oldpsl = PSL | cc; +int32 oldcur = PSL_GETCUR (oldpsl); +int32 oldsp = SP; +int32 newpsl; +int32 newpc; +int32 acc; + +in_ie = 1; /* flag int/exc */ +CLR_TRAPS; /* clear traps */ +newpc = ReadLP ((SCBB + vec) & PAMASK); /* read new PC */ +if (ei < 0) newpc = newpc | 1; /* severe? on istk */ +if (newpc & 2) ABORT (STOP_ILLVEC); /* bad flags? */ +if (oldpsl & PSL_IS) newpsl = PSL_IS; /* on int stk? */ +else { STK[oldcur] = SP; /* no, save cur stk */ + if (newpc & 1) { /* to int stk? */ + newpsl = PSL_IS; /* flag */ + SP = IS; } /* new stack */ + else { newpsl = 0; /* to ker stk */ + SP = KSP; } } /* new stack */ +if (ei > 0) PSL = newpsl | (ipl << PSL_V_IPL); /* if int, new IPL */ +else PSL = newpsl | ((newpc & 1)? PSL_IPL1F: (oldpsl & PSL_IPL)) | + (oldcur << PSL_V_PRV); +if (DBG_LOG (LOG_CPU_I)) fprintf (sim_log, + ">>IEX: PC=%08x, PSL=%08x, SP=%08x, VEC=%08x, nPSL=%08x, nSP=%08x\n", + PC, oldpsl, oldsp, vec, PSL, SP); +acc = ACC_MASK (KERN); /* new mode is kernel */ +Write (SP - 4, oldpsl, L_LONG, WA); /* push old PSL */ +Write (SP - 8, PC, L_LONG, WA); /* push old PC */ +SP = SP - 8; /* update stk ptr */ +JUMP (newpc & ~3); /* change PC */ +in_ie = 0; /* out of flows */ +return 0; +} + +/* CHMK, CHME, CHMS, CHMU + + opnd[0] = operand +*/ + +int32 op_chm (int32 *opnd, int32 cc, int32 opc) +{ +int32 mode = opc & PSL_M_MODE; +int32 cur = PSL_GETCUR (PSL); +int32 tsp, newpc, acc, sta; + +if (PSL & PSL_IS) ABORT (STOP_CHMFI); +newpc = ReadLP ((SCBB + SCB_CHMK + (mode << 2)) & PAMASK); +if (cur < mode) mode = cur; /* only inward */ +STK[cur] = SP; /* save stack */ +tsp = STK[mode]; /* get new stk */ +acc = ACC_MASK (mode); /* set new mode */ +if (Test (p2 = tsp - 1, WA, &sta) < 0) { /* probe stk */ + p1 = MM_WRITE | (sta & MM_EMASK); + ABORT ((sta & 4)? ABORT_TNV: ABORT_ACV); } +if (Test (p2 = tsp - 12, WA, &sta) < 0) { + p1 = MM_WRITE | (sta & MM_EMASK); + ABORT ((sta & 4)? ABORT_TNV: ABORT_ACV); } +Write (tsp - 12, SXTW (opnd[0]), L_LONG, WA); /* push argument */ +Write (tsp - 8, PC, L_LONG, WA); /* push PC */ +Write (tsp - 4, PSL | cc, L_LONG, WA); /* push PSL */ +SP = tsp - 12; /* set new stk */ +PSL = (mode << PSL_V_CUR) | (PSL & PSL_IPL) | /* set new PSL */ + (cur << PSL_V_PRV); +last_chm = fault_PC; +JUMP (newpc & ~03); /* set new PC */ +return 0; /* cc = 0 */ +} + +/* REI - return from exception or interrupt + +The lengthiest part of the REI instruction is the validity checking of the PSL +popped off the stack. The new PSL is checked against the following eight rules: + +let tmp = new PSL popped off the stack +let PSL = current PSL + +Rule SRM formulation Comment +---- --------------- ------- + 1 tmp<25:24> GEQ PSL<25:24> tmp GEQ PSL + 2 tmp<26> LEQ PSL<26> tmp LEQ tmp + 3 tmp<26> = 1 => tmp<25:24> = 0 tmp = 1 => tmp = ker + 4 tmp<26> = 1 => tmp<20:16> > 0 tmp = 1 => tmp > 0 + 5 tmp<20:16> > 0 => tmp<25:24> = 0 tmp > 0 => tmp = ker + 6 tmp<25:24> LEQ tmp<23:22> tmp LEQ tmp + 7 tmp<20:16> LEQ PSL<20:16> tmp LEQ PSL + 8 tmp<31,29:28,21,15:8> = 0 tmp = 0 +*/ + +int32 op_rei (int32 acc) +{ +int32 newpc = Read (SP, L_LONG, RA); +int32 newpsl = Read (SP + 4, L_LONG, RA); +int32 newcur = PSL_GETCUR (newpsl); +int32 oldcur = PSL_GETCUR (PSL); +int32 newipl; + +if ((newpsl & PSL_MBZ) || /* rule 8 */ + (newcur < oldcur)) RSVD_OPND_FAULT; /* rule 1 */ +if (newcur) { /* to esu, skip 2,4,7 */ + if ((newpsl & (PSL_IS | PSL_IPL)) || /* rules 3,5 */ + (newcur > PSL_GETPRV (newpsl))) /* rule 6 */ + RSVD_OPND_FAULT; } /* end rei to esu */ +else { /* to k, skip 3,5,6 */ + newipl = PSL_GETIPL (newpsl); /* get new ipl */ + if ((newpsl & PSL_IS) && /* setting IS? */ + (((PSL & PSL_IS) == 0) || (newipl == 0))) /* test rules 2,4 */ + RSVD_OPND_FAULT; /* else skip 2,4 */ + if (newipl > PSL_GETIPL (PSL)) RSVD_OPND_FAULT; /* test rule 7 */ + } /* end if kernel */ +SP = SP + 8; /* pop stack */ +if (PSL & PSL_IS) IS = SP; /* save stack */ +else STK[oldcur] = SP; +if (DBG_LOG (LOG_CPU_R)) fprintf (sim_log, + ">>REI: PC=%08x, PSL=%08x, SP=%08x, nPC=%08x, nPSL=%08x, nSP=%08x\n", + PC, PSL, SP - 8, newpc, newpsl, ((newpsl & IS)? IS: STK[newcur])); +PSL = (PSL & PSL_TP) | (newpsl & ~CC_MASK); /* set new PSL */ +if (PSL & PSL_IS) SP = IS; /* set new stack */ +else { SP = STK[newcur]; /* if ~IS, chk AST */ + if (newcur >= ASTLVL) { + if (DBG_LOG (LOG_CPU_R)) fprintf (sim_log, + ">>REI: AST delivered\n"); + SISR = SISR | SISR_2; } } +JUMP (newpc); /* set new PC */ +return newpsl & CC_MASK; /* set new cc */ +} + +/* LDCPTX - load process context */ + +void op_ldpctx (int32 acc) +{ +int32 newpc, newpsl, pcbpa; + +if (PSL & PSL_CUR) RSVD_INST_FAULT; /* must be kernel */ +pcbpa = PCBB & PAMASK; /* phys address */ +KSP = ReadLP (pcbpa); /* restore stk ptrs */ +ESP = ReadLP (pcbpa + 4); +SSP = ReadLP (pcbpa + 8); +USP = ReadLP (pcbpa + 12); +R[0] = ReadLP (pcbpa + 16); /* restore registers */ +R[1] = ReadLP (pcbpa + 20); +R[2] = ReadLP (pcbpa + 24); +R[3] = ReadLP (pcbpa + 28); +R[4] = ReadLP (pcbpa + 32); +R[5] = ReadLP (pcbpa + 36); +R[6] = ReadLP (pcbpa + 40); +R[7] = ReadLP (pcbpa + 44); +R[8] = ReadLP (pcbpa + 48); +R[9] = ReadLP (pcbpa + 52); +R[10] = ReadLP (pcbpa + 56); +R[11] = ReadLP (pcbpa + 60); +R[12] = ReadLP (pcbpa + 64); +R[13] = ReadLP (pcbpa + 68); +newpc = ReadLP (pcbpa + 72); /* get PC, PSL */ +newpsl = ReadLP (pcbpa + 76); +P0BR = ReadLP (pcbpa + 80); /* restore mem mgt */ +P0LR = ReadLP (pcbpa + 84); +P1BR = ReadLP (pcbpa + 88); +P1LR = ReadLP (pcbpa + 92); +ASTLVL = (P0LR >> 24) & AST_MASK; /* restore AST */ +P0BR = P0BR & BR_MASK; +P0LR = P0LR & LR_MASK; +P1BR = P1BR & BR_MASK; +P1LR = P1LR & LR_MASK; +zap_tb (0); /* clear process TB */ +set_map_reg (); +if (DBG_LOG (LOG_CPU_P)) fprintf (sim_log, + ">>LDP: PC=%08x, PSL=%08x, SP=%08x, nPC=%08x, nPSL=%08x, nSP=%08x\n", + PC, PSL, SP, newpc, newpsl, KSP); +if (PSL & PSL_IS) IS = SP; /* if istk, */ +PSL = PSL & ~PSL_IS; /* switch to kstk */ +SP = KSP - 8; +Write (SP, newpc, L_LONG, WA); /* push PC, PSL */ +Write (SP + 4, newpsl, L_LONG, WA); +return; +} + +/* SVPCTX - save processor context */ + +void op_svpctx (int32 acc) +{ +int32 savpc, savpsl, pcbpa; + +if (PSL & PSL_CUR) RSVD_INST_FAULT; /* must be kernel */ +savpc = Read (SP, L_LONG, RA); /* pop PC, PSL */ +savpsl = Read (SP + 4, L_LONG, RA); +if (DBG_LOG (LOG_CPU_P)) fprintf (sim_log, + ">>SVP: PC=%08x, PSL=%08x, SP=%08x, oPC=%08x, oPSL=%08x\n", + PC, PSL, SP, savpc, savpsl); +if (PSL & PSL_IS) SP = SP + 8; /* int stack? */ +else { KSP = SP + 8; /* pop kernel stack */ + SP = IS; /* switch to int stk */ + if ((PSL & PSL_IPL) == 0) PSL = PSL | PSL_IPL1; /* make IPL > 0 */ + PSL = PSL | PSL_IS; } /* set PSL */ +pcbpa = PCBB & PAMASK; +WriteLP (pcbpa, KSP); /* save stk ptrs */ +WriteLP (pcbpa + 4, ESP); +WriteLP (pcbpa + 8, SSP); +WriteLP (pcbpa + 12, USP); +WriteLP (pcbpa + 16, R[0]); /* save registers */ +WriteLP (pcbpa + 20, R[1]); +WriteLP (pcbpa + 24, R[2]); +WriteLP (pcbpa + 28, R[3]); +WriteLP (pcbpa + 32, R[4]); +WriteLP (pcbpa + 36, R[5]); +WriteLP (pcbpa + 40, R[6]); +WriteLP (pcbpa + 44, R[7]); +WriteLP (pcbpa + 48, R[8]); +WriteLP (pcbpa + 52, R[9]); +WriteLP (pcbpa + 56, R[10]); +WriteLP (pcbpa + 60, R[11]); +WriteLP (pcbpa + 64, R[12]); +WriteLP (pcbpa + 68, R[13]); +WriteLP (pcbpa + 72, savpc); /* save PC, PSL */ +WriteLP (pcbpa + 76, savpsl); +return; +} + +/* PROBER and PROBEW + + opnd[0] = mode + opnd[1] = length + opnd[2] = base address +*/ + +int32 op_probe (int32 *opnd, int32 rw) +{ +int32 mode = opnd[0] & PSL_M_MODE; /* mask mode */ +int32 length = opnd[1]; +int32 ba = opnd[2]; +int32 prv = PSL_GETPRV (PSL); +int32 acc, sta, sta1; + +if (prv > mode) mode = prv; /* maximize mode */ +acc = ACC_MASK (mode) << (rw? TLB_V_WACC: 0); /* set acc mask */ +Test (ba, acc, &sta); /* probe */ +switch (sta) { /* case on status */ +case PR_PTNV: /* pte TNV */ + p1 = MM_PARAM (rw, PR_PTNV); + p2 = ba; + ABORT (ABORT_TNV); /* force TNV */ +case PR_TNV: case PR_OK: /* TNV or ok */ + break; /* continue */ +default: /* other */ + return CC_Z; } /* lose */ +Test (ba + length - 1, acc, &sta1); /* probe end addr */ +switch (sta1) { /* case on status */ +case PR_PTNV: /* pte TNV */ + p1 = MM_PARAM (rw, PR_PTNV); + p2 = ba + length - 1; + ABORT (ABORT_TNV); /* force TNV */ +case PR_TNV: case PR_OK: /* TNV or ok */ + break; /* win */ +default: /* other */ + return CC_Z; } /* lose */ +return 0; +} + + +/* MTPR - move to processor register + + opnd[0] = data + opnd[1] = register number +*/ + +int32 op_mtpr (int32 *opnd) +{ +int32 val = opnd[0]; +int32 prn = opnd[1]; +int32 cc; + +if (PSL & PSL_CUR) RSVD_INST_FAULT; /* must be kernel */ +if (prn > 63) RSVD_OPND_FAULT; /* reg# > 63? fault */ +CC_IIZZ_L (val); /* set cc's */ +switch (prn) { /* case on reg # */ +case MT_KSP: /* KSP */ + if (PSL & PSL_IS) KSP = val; /* on IS? store KSP */ + else SP = val; /* else store SP */ + break; +case MT_ESP: case MT_SSP: case MT_USP: /* ESP, SSP, USP */ + STK[prn] = val; /* store stack */ + break; +case MT_IS: /* IS */ + if (PSL & PSL_IS) SP = val; /* on IS? store SP */ + else IS = val; /* else store IS */ + break; +case MT_P0BR: /* P0BR */ + P0BR = val & BR_MASK; /* lw aligned */ + zap_tb (0); /* clr proc TLB */ + set_map_reg (); + break; +case MT_P0LR: /* P0LR */ + P0LR = val & LR_MASK; + zap_tb (0); /* clr proc TLB */ + set_map_reg (); + break; +case MT_P1BR: /* P1BR */ + P1BR = val & BR_MASK; /* lw aligned */ + zap_tb (0); /* clr proc TLB */ + set_map_reg (); + break; +case MT_P1LR: /* P1LR */ + P1LR = val & LR_MASK; + zap_tb (0); /* clr proc TLB */ + set_map_reg (); + break; +case MT_SBR: /* SBR */ + SBR = val & BR_MASK; /* lw aligned */ + zap_tb (1); /* clr entire TLB */ + set_map_reg (); + break; +case MT_SLR: /* SLR */ + SLR = val & LR_MASK; + zap_tb (1); /* clr entire TLB */ + set_map_reg (); + break; +case MT_SCBB: /* SCBB */ + SCBB = val & BR_MASK; /* lw aligned */ + break; +case MT_PCBB: /* PCBB */ + PCBB = val & BR_MASK; /* lw aligned */ + break; +case MT_IPL: /* IPL */ + PSL = (PSL & ~PSL_IPL) | ((val & PSL_M_IPL) << PSL_V_IPL); + break; +case MT_ASTLVL: /* ASTLVL */ + if (val > AST_MAX) RSVD_OPND_FAULT; /* > 4? fault */ + ASTLVL = val; + break; +case MT_SIRR: /* SIRR */ + if ((val > 0xF) || (val == 0)) RSVD_OPND_FAULT; + SISR = SISR | (1 << val); /* set bit in SISR */ + break; +case MT_SISR: /* SISR */ + SISR = val & SISR_MASK; + break; +case MT_CADR: /* CADR */ + CADR = (val & CADR_RW) | CADR_MBO; + break; +case MT_MSER: /* MSER */ + MSER = MSER & MSER_HM; + break; +case MT_MAPEN: /* MAPEN */ + mapen = val & 1; +case MT_TBIA: /* TBIA */ + zap_tb (1); /* clr entire TLB */ + break; +case MT_TBIS: /* TBIS */ + zap_tb_ent (val); + break; +case MT_SID: +case MT_CONPC: +case MT_CONPSL: + RSVD_OPND_FAULT; /* read only */ +case MT_TBCHK: /* TBCHK */ + if (chk_tb_ent (val)) cc = cc | CC_V; + break; +default: + WriteIPR (prn, val); /* others */ + break; } +return cc; +} + +int32 op_mfpr (int32 *opnd) +{ +int32 prn = opnd[0]; +int32 val; + +if (PSL & PSL_CUR) RSVD_INST_FAULT; /* must be kernel */ +if (prn > 63) RSVD_OPND_FAULT; /* reg# > 63? fault */ +switch (prn) { /* case on reg# */ +case MT_KSP: /* KSP */ + val = (PSL & PSL_IS)? KSP: SP; /* return KSP or SP */ + break; +case MT_ESP: case MT_SSP: case MT_USP: /* ESP, SSP, USP */ + val = STK[prn]; /* return stk ptr */ + break; +case MT_IS: /* IS */ + val = (PSL & PSL_IS)? SP: IS; /* return SP or IS */ + break; +case MT_P0BR: /* P0BR */ + val = P0BR; + break; +case MT_P0LR: /* P0LR */ + val = P0LR; + break; +case MT_P1BR: /* P1BR */ + val = P1BR; + break; +case MT_P1LR: /* P1LR */ + val = P1LR; + break; +case MT_SBR: /* SBR */ + val = SBR; + break; +case MT_SLR: /* SLR */ + val = SLR; + break; +case MT_SCBB: /* SCBB */ + val = SCBB; + break; +case MT_PCBB: /* PCBB */ + val = PCBB; + break; +case MT_IPL: /* IPL */ + val = PSL_GETIPL (PSL); + break; +case MT_ASTLVL: /* ASTLVL */ + val = ASTLVL; + break; +case MT_SISR: /* SISR */ + val = SISR & SISR_MASK; + break; +case MT_CADR: /* CADR */ + val = CADR & 0xFF; + break; +case MT_MSER: /* MSER */ + val = MSER & 0xFF; + break; +case MT_CONPC: /* console PC */ + val = conpc; + break; +case MT_CONPSL: /* console PSL */ + val = conpsl; + break; +case MT_MAPEN: /* MAPEN */ + val = mapen; + break; +case MT_SID: /* SID */ + val = CVAX_SID | CVAX_UREV; + break; +case MT_SIRR: +case MT_TBIA: +case MT_TBIS: +case MT_TBCHK: + RSVD_OPND_FAULT; /* write only */ +default: /* others */ + val = ReadIPR (prn); /* read from SSC */ + break; } +return val; +} + +/* Emulated instructions + + opnd[0:5] = six operands to be pushed (if PSL = 0) + cc = condition codes + opc = opcode + + If FPD is set, push old PC and PSL on stack, vector thru SCB. + If FPD is clear, push opcode, old PC, operands, new PC, and PSL + on stack, vector thru SCB. + In both cases, the exception occurs in the current mode. +*/ + +int32 op_emulate (int32 *opnd, int32 cc, int32 opc, int32 acc) +{ +int32 vec; + +if (PSL & PSL_FPD) { /* FPD set? */ + Read (SP - 1, L_BYTE, WA); /* wchk stack */ + Write (SP - 8, fault_PC, L_LONG, WA); /* push old PC */ + Write (SP - 4, PSL | cc, L_LONG, WA); /* push PSL */ + SP = SP - 8; /* decr stk ptr */ + vec = ReadLP ((SCBB + SCB_EMULFPD) & PAMASK); } +else { Read (SP - 1, L_BYTE, WA); /* wchk stack */ + Write (SP - 48, opc, L_LONG, WA); /* push opcode */ + Write (SP - 44, fault_PC, L_LONG, WA); /* push old PC */ + Write (SP - 40, opnd[0], L_LONG, WA); /* push operands */ + Write (SP - 36, opnd[1], L_LONG, WA); + Write (SP - 32, opnd[2], L_LONG, WA); + Write (SP - 28, opnd[3], L_LONG, WA); + Write (SP - 24, opnd[4], L_LONG, WA); + Write (SP - 20, opnd[5], L_LONG, WA); + Write (SP - 8, PC, L_LONG, WA); /* push cur PC */ + Write (SP - 4, PSL | cc, L_LONG, WA); /* push PSL */ + SP = SP - 48; /* decr stk ptr */ + vec = ReadLP ((SCBB + SCB_EMULATE) & PAMASK); } +PSL = PSL & ~(PSL_TP | PSL_FPD | PSW_DV | PSW_FU | PSW_IV | PSW_T); +JUMP (vec & ~03); /* set new PC */ +return 0; /* set new cc's */ +} diff --git a/VAX/vax_defs.h b/VAX/vax_defs.h new file mode 100644 index 00000000..8e173134 --- /dev/null +++ b/VAX/vax_defs.h @@ -0,0 +1,561 @@ +/* vax_defs.h: VAX architecture definitions file + + Copyright (c) 1998-2002, Robert M Supnik + + Permission is hereby granted, free of charge, to any person obtaining a + copy of this software and associated documentation files (the "Software"), + to deal in the Software without restriction, including without limitation + the rights to use, copy, modify, merge, publish, distribute, sublicense, + and/or sell copies of the Software, and to permit persons to whom the + Software is furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + ROBERT M SUPNIK BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + Except as contained in this notice, the name of Robert M Supnik shall not + be used in advertising or otherwise to promote the sale, use or other dealings + in this Software without prior written authorization from Robert M Supnik. + + The author gratefully acknowledges the help of Stephen Shirron, Antonio + Carlini, and Kevin Peterson in providing specifications for the Qbus VAX's + + 14-Jul-02 RMS Added infinite loop message + 30-Apr-02 RMS Added CLR_TRAPS macro +*/ + +#include "sim_defs.h" +#include + +/* Stops and aborts */ + +#define STOP_HALT 1 /* halt */ +#define STOP_IBKPT 2 /* breakpoint */ +#define STOP_CHMFI 3 /* chg mode IS */ +#define STOP_ILLVEC 4 /* illegal vector */ +#define STOP_INIE 5 /* exc in intexc */ +#define STOP_PPTE 6 /* proc pte in Px */ +#define STOP_UIPL 7 /* undefined IPL */ +#define STOP_UNKNOWN 8 /* unknown reason */ +#define STOP_RQ 9 /* fatal RQ err */ +#define STOP_LOOP 10 /* infinite loop */ +#define STOP_UNKABO 11 /* unknown abort */ +#define ABORT_INTR -1 /* interrupt */ +#define ABORT_MCHK (-SCB_MCHK) /* machine check */ +#define ABORT_RESIN (-SCB_RESIN) /* rsvd instruction */ +#define ABORT_RESAD (-SCB_RESAD) /* rsvd addr mode */ +#define ABORT_RESOP (-SCB_RESOP) /* rsvd operand */ +#define ABORT_ARITH (-SCB_ARITH) /* arithmetic trap */ +#define ABORT_ACV (-SCB_ACV) /* access violation */ +#define ABORT_TNV (-SCB_TNV) /* transl not vaid */ +#define ABORT(x) longjmp (save_env, (x)) /* abort */ +#define RSVD_INST_FAULT ABORT (ABORT_RESIN) +#define RSVD_ADDR_FAULT ABORT (ABORT_RESAD) +#define RSVD_OPND_FAULT ABORT (ABORT_RESOP) +#define FLT_OVFL_FAULT p1 = FLT_OVRFLO, ABORT (ABORT_ARITH) +#define FLT_DZRO_FAULT p1 = FLT_DIVZRO, ABORT (ABORT_ARITH) +#define FLT_UNFL_FAULT p1 = FLT_UNDFLO, ABORT (ABORT_ARITH) +#define MACH_CHECK(cd) p1 = (cd), ABORT (ABORT_MCHK) + +/* Address space */ + +#define PAWIDTH 30 /* phys addr width */ +#define PASIZE (1 << PAWIDTH) /* phys addr size */ +#define PAMASK (PASIZE - 1) /* phys mem mask */ +#define IOPAGE (1 << (PAWIDTH - 1)) /* start of I/O page */ + +/* Architectural constants */ + +#define BMASK 0x000000FF /* byte */ +#define BSIGN 0x00000080 +#define WMASK 0x0000FFFF /* word */ +#define WSIGN 0x00008000 +#define LMASK 0xFFFFFFFF /* longword */ +#define LSIGN 0x80000000 +#define FPSIGN 0x00008000 /* floating point */ +#define L_BYTE 1 /* bytes per */ +#define L_WORD 2 /* data type */ +#define L_LONG 4 +#define L_QUAD 8 +#define NUM_INST 512 /* one byte+two byte */ +#define MAX_SPEC 6 /* max spec/instr */ + +/* Memory management modes */ + +#define KERN 0 +#define EXEC 1 +#define SUPV 2 +#define USER 3 + +/* Register and stack aliases */ + +#define nAP 12 +#define nFP 13 +#define nSP 14 +#define nPC 15 +#define AP R[nAP] +#define FP R[nFP] +#define SP R[nSP] +#define PC R[nPC] +#define RGMASK 0xF +#define rnplus1 ((rn + 1) & RGMASK) +#define KSP STK[KERN] +#define ESP STK[EXEC] +#define SSP STK[SUPV] +#define USP STK[USER] +#define IS STK[4] + +/* PSL, PSW, and condition codes */ + +#define PSL_V_TP 30 /* trace pending */ +#define PSL_TP (1 << PSL_V_TP) +#define PSL_V_FPD 27 /* first part done */ +#define PSL_FPD (1 << PSL_V_FPD) +#define PSL_V_IS 26 /* interrupt stack */ +#define PSL_IS (1 << PSL_V_IS) +#define PSL_V_CUR 24 /* current mode */ +#define PSL_V_PRV 22 /* previous mode */ +#define PSL_M_MODE 0x3 /* mode mask */ +#define PSL_CUR (PSL_M_MODE << PSL_V_CUR) +#define PSL_PRV (PSL_M_MODE << PSL_V_CUR) +#define PSL_V_IPL 16 /* int priority lvl */ +#define PSL_M_IPL 0x1F +#define PSL_IPL (PSL_M_IPL << PSL_V_IPL) +#define PSL_IPL1 (0x01 << PSL_V_IPL) +#define PSL_IPL1F (0x1F << PSL_V_IPL) +#define PSL_MBZ (0xB0200000 | PSW_MBZ) /* must be zero */ +#define PSW_MBZ 0xFF00 /* must be zero */ +#define PSW_DV 0x80 /* dec ovflo enable */ +#define PSW_FU 0x40 /* flt undflo enable */ +#define PSW_IV 0x20 /* int ovflo enable */ +#define PSW_T 0x10 /* trace enable */ +#define CC_N 0x08 /* negative */ +#define CC_Z 0x04 /* zero */ +#define CC_V 0x02 /* overflow */ +#define CC_C 0x01 /* carry */ +#define CC_MASK (CC_N | CC_Z | CC_V | CC_C) +#define PSL_GETCUR(x) (((x) >> PSL_V_CUR) & PSL_M_MODE) +#define PSL_GETPRV(x) (((x) >> PSL_V_PRV) & PSL_M_MODE) +#define PSL_GETIPL(x) (((x) >> PSL_V_IPL) & PSL_M_IPL) + +/* Software interrupt summary register */ + +#define SISR_MASK 0xFFFE +#define SISR_2 (1 << 2) + +/* AST register */ + +#define AST_MASK 7 +#define AST_MAX 4 + +/* Virtual address */ + +#define VA_N_OFF 9 /* offset size */ +#define VA_PAGSIZE (1u << VA_N_OFF) /* page size */ +#define VA_M_OFF ((1u << VA_N_OFF) - 1) /* offset mask */ +#define VA_V_VPN VA_N_OFF /* vpn start */ +#define VA_N_VPN (31 - VA_N_OFF) /* vpn size */ +#define VA_M_VPN ((1u << VA_N_VPN) - 1) /* vpn mask */ +#define VA_S0 (1u << 31) /* S0 space */ +#define VA_P1 (1u << 30) /* P1 space */ +#define VA_N_TBI 12 /* TB index size */ +#define VA_TBSIZE (1u << VA_N_TBI) /* TB size */ +#define VA_M_TBI ((1u << VA_N_TBI) - 1) /* TB index mask */ +#define VA_GETOFF(x) ((x) & VA_M_OFF) +#define VA_GETVPN(x) (((x) >> VA_V_VPN) & VA_M_VPN) +#define VA_GETTBI(x) ((x) & VA_M_TBI) + +/* PTE */ + +#define PTE_V_V 31 /* valid */ +#define PTE_V (1u << PTE_V_V) +#define PTE_V_ACC 27 /* access */ +#define PTE_M_ACC 0xF +#define PTE_V_M 26 /* modified */ +#define PTE_M (1u << PTE_V_M) +#define PTE_GETACC(x) (((x) >> PTE_V_ACC) & PTE_M_ACC) + +/* TLB entry */ + +#define TLB_V_RACC 0 /* rd acc field */ +#define TLB_V_WACC 4 /* wr acc field */ +#define TLB_M_ACC 0xF +#define TLB_RACC (TLB_M_ACC << TLB_V_RACC) +#define TLB_WACC (TLB_M_ACC << TLB_V_WACC) +#define TLB_V_M 8 /* m bit */ +#define TLB_M (1u << TLB_V_M) +#define TLB_N_PFN (PAWIDTH - VA_N_OFF) /* ppfn size */ +#define TLB_M_PFN ((1u << TLB_N_PFN) - 1) /* ppfn mask */ +#define TLB_PFN (TLB_M_PFN << VA_V_VPN) + +/* Traps and interrupt requests */ + +#define TIR_V_IRQL 0 /* int request lvl */ +#define TIR_V_TRAP 5 /* trap requests */ +#define TIR_M_TRAP 07 +#define TIR_TRAP (TIR_M_TRAP << TIR_V_TRAP) +#define TRAP_INTOV (1 << TIR_V_TRAP) /* integer overflow */ +#define TRAP_DIVZRO (2 << TIR_V_TRAP) /* divide by zero */ +#define TRAP_SUBSCR (7 << TIR_V_TRAP) /* subscript range */ +#define SET_TRAP(x) trpirq = (trpirq & PSL_M_IPL) | (x) +#define CLR_TRAPS trpirq = trpirq & ~TIR_TRAP +#define SET_IRQL trpirq = (trpirq & TIR_TRAP) | eval_int () +#define GET_TRAP(x) (((x) >> TIR_V_TRAP) & TIR_M_TRAP) +#define GET_IRQL(x) (((x) >> TIR_V_IRQL) & PSL_M_IPL) + +/* Floating point fault parameters */ + +#define FLT_OVRFLO 0x8 /* flt overflow */ +#define FLT_DIVZRO 0x9 /* flt div by zero */ +#define FLT_UNDFLO 0xA /* flt underflow */ + +/* SCB offsets */ + +#define SCB_MCHK 0x04 /* machine chk */ +#define SCB_KSNV 0x08 /* ker stk invalid */ +#define SCB_PWRFL 0x0C /* power fail */ +#define SCB_RESIN 0x10 /* rsvd/priv instr */ +#define SCB_XFC 0x14 /* XFC instr */ +#define SCB_RESOP 0x18 /* rsvd operand */ +#define SCB_RESAD 0x1C /* rsvd addr mode */ +#define SCB_ACV 0x20 /* ACV */ +#define SCB_TNV 0x24 /* TNV */ +#define SCB_TP 0x28 /* trace pending */ +#define SCB_BPT 0x2C /* BPT instr */ +#define SCB_ARITH 0x34 /* arith fault */ +#define SCB_CHMK 0x40 /* CHMK */ +#define SCB_CHME 0x44 /* CHME */ +#define SCB_CHMS 0x48 /* CHMS */ +#define SCB_CHMU 0x4C /* CHMU */ +#define SCB_CRDERR 0x54 /* CRD err intr */ +#define SCB_MEMERR 0x60 /* mem err intr */ +#define SCB_IPLSOFT 0x80 /* software intr */ +#define SCB_INTTIM 0xC0 /* timer intr */ +#define SCB_EMULATE 0xC8 /* emulation */ +#define SCB_EMULFPD 0xCC /* emulation, FPD */ +#define SCB_CSI 0xF0 /* constor input */ +#define SCB_CSO 0xF4 /* constor output */ +#define SCB_TTI 0xF8 /* console input */ +#define SCB_TTO 0xFC /* console output */ +#define SCB_INTR 0x100 /* hardware intr */ + +#define IPL_MEMERR 0x1D /* mem err IPL */ +#define IPL_CRDERR 0x1A /* CRD err IPL */ + +/* Interrupt and exception types */ + +#define IE_SVE -1 /* severe exception */ +#define IE_EXC 0 /* normal exception */ +#define IE_INT 1 /* interrupt */ + +/* Decode ROM: opcode entry */ + +#define DR_F 0x80 /* FPD ok flag */ +#define DR_NSPMASK 0x07 /* #specifiers */ +#define DR_USPMASK 0x70 /* #spec, sym_ */ + +/* Decode ROM: specifier entry */ + +#define DR_ACMASK 0xC /* type */ +#define DR_LNMASK 0x3 /* length mask */ +#define DR_LNT(x) (1 << (x & DR_LNMASK)) /* disp to lnt */ + +/* Decode ROM: operand type */ + +#define SH0 0x00 /* short literal */ +#define SH1 0x10 +#define SH2 0x20 +#define SH3 0x30 +#define IDX 0x40 /* indexed */ +#define GRN 0x50 /* register */ +#define RGD 0x60 /* register def */ +#define ADC 0x70 /* autodecrement */ +#define AIN 0x80 /* autoincrement */ +#define AID 0x90 /* autoinc def */ +#define BDP 0xA0 /* byte disp */ +#define BDD 0xB0 /* byte disp def */ +#define WDP 0xC0 /* word disp */ +#define WDD 0xD0 /* word disp def */ +#define LDP 0xE0 /* long disp */ +#define LDD 0xF0 /* long disp def */ + +/* Decode ROM: access type and length */ + +#define RB 0x0 /* .rb */ +#define RW 0x1 /* .rw */ +#define RL 0x2 /* .rl */ +#define RQ 0x3 /* .rq */ +#define MB 0x4 /* .mb */ +#define MW 0x5 /* .mw */ +#define ML 0x6 /* .ml */ +#define MQ 0x7 /* .mq */ +#define AB 0x8 /* .ab */ +#define AW 0x9 /* .aw */ +#define AL 0xA /* .al */ +#define AQ 0xB /* .aq */ +#define WB 0xC /* .wb */ +#define WW 0xD /* .ww */ +#define WL 0xE /* .wl */ +#define WQ 0xF /* .wq */ + +/* Special dispatches. + + vb = variable bit field, treated as wb except for register + rf = f_floating, treated as rl except for short literal + rd = d_floating, treated as rl except for short literal + rg = g_floating, treated as rl except for short literal + bw = branch byte displacement + bw = branch word displacement + + The 'underlying' access type and length must be correct for + indexing, which only looks at the low order 4b. rg works because + rq and mq are treated identically. +*/ + +#define VB (0x100|WB) /* .vb */ +#define RF (0x100|RL) /* .rf */ +#define RD (0x100|RQ) /* .rd */ +#define RG (0x100|MQ) /* .rg */ +#define BB (0x1F0|WB) /* byte branch */ +#define BW (0x1F0|WW) /* word branch */ +#define OC (0x1F0|WQ) /* octa, sym_ */ + +/* Probe results and memory management fault codes */ + +#define PR_ACV 0 /* ACV */ +#define PR_LNV 1 /* length viol */ +/* #define PR_PACV 2 /* impossible */ +#define PR_PLNV 3 /* pte len viol */ +#define PR_TNV 4 /* TNV */ +/* #define PR_TB 5 /* impossible */ +#define PR_PTNV 6 /* pte TNV */ +#define PR_OK 7 /* ok */ +#define MM_PARAM(w,p) (((w)? 4: 0) | ((p) & 3)) /* fault param */ + +/* Memory management errors */ + +#define MM_WRITE 4 /* write */ +#define MM_EMASK 3 /* against probe */ + +/* Privileged registers */ + +#define MT_KSP 0 +#define MT_ESP 1 +#define MT_SSP 2 +#define MT_USP 3 +#define MT_IS 4 +#define MT_P0BR 8 +#define MT_P0LR 9 +#define MT_P1BR 10 +#define MT_P1LR 11 +#define MT_SBR 12 +#define MT_SLR 13 +#define MT_PCBB 16 +#define MT_SCBB 17 +#define MT_IPL 18 +#define MT_ASTLVL 19 +#define MT_SIRR 20 +#define MT_SISR 21 +#define MT_ICCS 24 +#define MT_TODR 27 +#define MT_CSRS 28 +#define MT_CSRD 29 +#define MT_CSTS 30 +#define MT_CSTD 31 +#define MT_RXCS 32 +#define MT_RXDB 33 +#define MT_TXCS 34 +#define MT_TXDB 35 +#define MT_CADR 37 +#define MT_MSER 39 +#define MT_CONPC 42 +#define MT_CONPSL 43 +#define MT_IORESET 55 +#define MT_MAPEN 56 +#define MT_TBIA 57 +#define MT_TBIS 58 +#define MT_SID 62 +#define MT_TBCHK 63 + +#define BR_MASK 0xFFFFFFFC +#define LR_MASK 0x003FFFFF + +/* Opcodes */ + +enum opcodes { + HALT, NOP, REI, BPT, RET, RSB, LDPCTX, SVPCTX, + CVTPS, CVTSP, INDEX, CRC, PROBER, PROBEW, INSQUE, REMQUE, + BSBB, BRB, BNEQ, BEQL, BGTR, BLEQ, JSB, JMP, + BGEQ, BLSS, BGTRU, BLEQU, BVC, BVS, BGEQU, BLSSU, + ADDP4, ADDP6, SUBP4, SUBP6, CVTPT, MULP, CVTTP, DIVP, + MOVC3, CMPC3, SCANC, SPANC, MOVC5, CMPC5, MOVTC, MOVTUC, + BSBW, BRW, CVTWL, CVTWB, MOVP, CMPP3, CVTPL, CMPP4, + EDITPC, MATCHC, LOCC, SKPC, MOVZWL, ACBW, MOVAW, PUSHAW, + ADDF2, ADDF3, SUBF2, SUBF3, MULF2, MULF3, DIVF2, DIVF3, + CVTFB, CVTFW, CVTFL, CVTRFL, CVTBF, CVTWF, CVTLF, ACBF, + MOVF, CMPF, MNEGF, TSTF, EMODF, POLYF, CVTFD, + ADAWI = 0x58, INSQHI = 0x5C, INSQTI, REMQHI, REMQTI, + ADDD2, ADDD3, SUBD2, SUBD3, MULD2, MULD3, DIVD2, DIVD3, + CVTDB, CVTDW, CVTDL, CVTRDL, CVTBD, CVTWD, CVTLD, ACBD, + MOVD, CMPD, MNEGD, TSTD, EMODD, POLYD, CVTDF, + ASHL = 0x78, ASHQ, EMUL, EDIV, CLRQ, MOVQ, MOVAQ, PUSHAQ, + ADDB2, ADDB3, SUBB2, SUBB3, MULB2, MULB3, DIVB2, DIVB3, + BISB2, BISB3, BICB2, BICB3, XORB2, XORB3, MNEGB, CASEB, + MOVB, CMPB, MCOMB, BITB, CLRB, TSTB, INCB, DECB, + CVTBL, CVTBW, MOVZBL, MOVZBW, ROTL, ACBB, MOVAB, PUSHAB, + ADDW2, ADDW3, SUBW2, SUBW3, MULW2, MULW3, DIVW2, DIVW3, + BISW2, BISW3, BICW2, BICW3, XORW2, XORW3, MNEGW, CASEW, + MOVW, CMPW, MCOMW, BITW, CLRW, TSTW, INCW, DECW, + BISPSW, BICPSW, POPR, PUSHR, CHMK, CHME, CHMS, CHMU, + ADDL2, ADDL3, SUBL2, SUBL3, MULL2, MULL3, DIVL2, DIVL3, + BISL2, BISL3, BICL2, BICL3, XORL2, XORL3, MNEGL, CASEL, + MOVL, CMPL, MCOML, BITL, CLRL, TSTL, INCL, DECL, + ADWC, SBWC, MTPR, MFPR, MOVPSL, PUSHL, MOVAL, PUSHAL, + BBS, BBC, BBSS, BBCS, BBSC, BBCC, BBSSI, BBCCI, + BLBS, BLBC, FFS, FFC, CMPV, CMPZV, EXTV, EXTZV, + INSV, ACBL, AOBLSS, AOBLEQ, SOBGEQ, SOBGTR, CVTLB, CVTLW, + ASHP, CVTLP, CALLG, CALLS, XFC, CVTGF = 0x133, + ADDG2= 0x140, ADDG3, SUBG2, SUBG3, MULG2, MULG3, DIVG2, DIVG3, + CVTGB, CVTGW, CVTGL, CVTRGL, CVTBG, CVTWG, CVTLG, ACBG, + MOVG, CMPG, MNEGG, TSTG, EMODG, POLYG, CVTFG = 0x199 }; + +/* Repeated operations */ + +#define SXTB(x) (((x) & BSIGN)? ((x) | ~BMASK): ((x) & BMASK)) +#define SXTW(x) (((x) & WSIGN)? ((x) | ~WMASK): ((x) & WMASK)) +#define SXTBW(x) (((x) & BSIGN)? ((x) | (WMASK - BMASK)): ((x) & BMASK)) +#define INTOV if (PSL & PSW_IV) SET_TRAP (TRAP_INTOV) +#define V_INTOV cc = cc | CC_V; INTOV +#define NEG(x) (-((int32) (x))) + +/* Istream access */ + +#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] = fault_PC +#define GET_ISTR(d,l) d = get_istr (l, acc) +#define BRANCHB(d) PCQ_ENTRY, PC = PC + SXTB (d), FLUSH_ISTR +#define BRANCHW(d) PCQ_ENTRY, PC = PC + SXTW (d), FLUSH_ISTR +#define JUMP(d) PCQ_ENTRY, PC = (d), FLUSH_ISTR +#define SETPC(d) PC = (d), FLUSH_ISTR +#define FLUSH_ISTR ibcnt = 0, ppc = -1 + +/* Read and write */ + +#define RA (acc) +#define WA ((acc) << TLB_V_WACC) +#define ACC_MASK(x) (1 << (x)) +#define TLB_ACCR(x) (ACC_MASK (x) << TLB_V_RACC) +#define TLB_ACCW(x) (ACC_MASK (x) << TLB_V_WACC) +#define REF_V 0 +#define REF_P 1 + +/* Condition code macros */ + +#define CC_ZZ1P cc = CC_Z | (cc & CC_C) + +#define CC_IIZZ_B(r) \ + if ((r) & BSIGN) cc = CC_N; \ + else if ((r) == 0) cc = CC_Z; \ + else cc = 0 +#define CC_IIZZ_W(r) \ + if ((r) & WSIGN) cc = CC_N; \ + else if ((r) == 0) cc = CC_Z; \ + else cc = 0 +#define CC_IIZZ_L(r) \ + if ((r) & LSIGN) cc = CC_N; \ + else if ((r) == 0) cc = CC_Z; \ + else cc = 0 +#define CC_IIZZ_Q(rl,rh) \ + if ((rh) & LSIGN) cc = CC_N; \ + else if (((rl) | (rh)) == 0) cc = CC_Z; \ + else cc = 0 +#define CC_IIZZ_FP CC_IIZZ_W + +#define CC_IIZP_B(r) \ + if ((r) & BSIGN) cc = CC_N | (cc & CC_C); \ + else if ((r) == 0) cc = CC_Z | (cc & CC_C); \ + else cc = cc & CC_C +#define CC_IIZP_W(r) \ + if ((r) & WSIGN) cc = CC_N | (cc & CC_C); \ + else if ((r) == 0) cc = CC_Z | (cc & CC_C); \ + else cc = cc & CC_C +#define CC_IIZP_L(r) \ + if ((r) & LSIGN) cc = CC_N | (cc & CC_C); \ + else if ((r) == 0) cc = CC_Z | (cc & CC_C); \ + else cc = cc & CC_C +#define CC_IIZP_Q(rl,rh) \ + if ((rh) & LSIGN) cc = CC_N | (cc & CC_C); \ + else if (((rl) | (rh)) == 0) cc = CC_Z | (cc & CC_C); \ + else cc = cc & CC_C +#define CC_IIZP_FP CC_IIZP_W + +#define V_ADD_B(r,s1,s2) \ + if (((~(s1) ^ (s2)) & ((s1) ^ (r))) & BSIGN) { V_INTOV; } +#define V_ADD_W(r,s1,s2) \ + if (((~(s1) ^ (s2)) & ((s1) ^ (r))) & WSIGN) { V_INTOV; } +#define V_ADD_L(r,s1,s2) \ + if (((~(s1) ^ (s2)) & ((s1) ^ (r))) & LSIGN) { V_INTOV; } +#define C_ADD(r,s1,s2) \ + if (((uint32) r) < ((uint32) s2)) cc = cc | CC_C + +#define CC_ADD_B(r,s1,s2) \ + CC_IIZZ_B (r); \ + V_ADD_B (r, s1, s2); \ + C_ADD (r, s1, s2) +#define CC_ADD_W(r,s1,s2) \ + CC_IIZZ_W (r); \ + V_ADD_W (r, s1, s2); \ + C_ADD (r, s1, s2) +#define CC_ADD_L(r,s1,s2) \ + CC_IIZZ_L (r); \ + V_ADD_L (r, s1, s2); \ + C_ADD (r, s1, s2) + +#define V_SUB_B(r,s1,s2) \ + if ((((s1) ^ (s2)) & (~(s1) ^ (r))) & BSIGN) { V_INTOV; } +#define V_SUB_W(r,s1,s2) \ + if ((((s1) ^ (s2)) & (~(s1) ^ (r))) & WSIGN) { V_INTOV; } +#define V_SUB_L(r,s1,s2) \ + if ((((s1) ^ (s2)) & (~(s1) ^ (r))) & LSIGN) { V_INTOV; } +#define C_SUB(r,s1,s2) \ + if (((uint32) s2) < ((uint32) s1)) cc = cc | CC_C + +#define CC_SUB_B(r,s1,s2) \ + CC_IIZZ_B (r); \ + V_SUB_B (r, s1, s2); \ + C_SUB (r, s1, s2) +#define CC_SUB_W(r,s1,s2) \ + CC_IIZZ_W (r); \ + V_SUB_W (r, s1, s2); \ + C_SUB (r, s1, s2) +#define CC_SUB_L(r,s1,s2) \ + CC_IIZZ_L (r); \ + V_SUB_L (r, s1, s2); \ + C_SUB (r, s1, s2) + +#define CC_CMP_B(s1,s2) \ + if (SXTB (s1) < SXTB (s2)) cc = CC_N; \ + else if ((s1) == (s2)) cc = CC_Z; \ + else cc = 0; \ + if (((uint32) s1) < ((uint32) s2)) cc = cc | CC_C +#define CC_CMP_W(s1,s2) \ + if (SXTW (s1) < SXTW (s2)) cc = CC_N; \ + else if ((s1) == (s2)) cc = CC_Z; \ + else cc = 0; \ + if (((uint32) s1) < ((uint32) s2)) cc = cc | CC_C +#define CC_CMP_L(s1,s2) \ + if ((s1) < (s2)) cc = CC_N; \ + else if ((s1) == (s2)) cc = CC_Z; \ + else cc = 0; \ + if (((uint32) s1) < ((uint32) s2)) cc = cc | CC_C + +/* Model dependent definitions */ + +#include "vaxmod_defs.h" diff --git a/VAX/vax_doc.txt b/VAX/vax_doc.txt new file mode 100644 index 00000000..7d6500b5 --- /dev/null +++ b/VAX/vax_doc.txt @@ -0,0 +1,661 @@ +To: Users +From: Bob Supnik +Subj: VAX Simulator Usage +Date: 15-Jun-2002 + + COPYRIGHT NOTICE + +The following copyright notice applies to both the SIMH source and binary: + + Original code published in 1993-2002, written by Robert M Supnik + Copyright (c) 1993-2002, Robert M Supnik + + Permission is hereby granted, free of charge, to any person obtaining a + copy of this software and associated documentation files (the "Software"), + to deal in the Software without restriction, including without limitation + the rights to use, copy, modify, merge, publish, distribute, sublicense, + and/or sell copies of the Software, and to permit persons to whom the + Software is furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + ROBERT M SUPNIK BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + Except as contained in this notice, the name of Robert M Supnik shall not + be used in advertising or otherwise to promote the sale, use or other dealings + in this Software without prior written authorization from Robert M Supnik. + +This memorandum documents the VAX simulator. + + +1. Simulator Files + +To compile the VAX, you must define USE_INT64 as part of the compilation +command line. + +sim/ sim_defs.h + sim_sock.h + sim_tmxr.h + dec_dz.h + dec_mscp.h + dec_uqssp.h + scp.c + scp_tty.c + sim_rev.c + sim_sock.c + sim_tmxr.c + +sim/vax/ vax_defs.h + vaxmod_defs.h + vax_cpu.c + vax_cpu1.c + vax_fpa.c + vax_io.c + vax_mmu.c + vax_stddev.c + vax_sys.c + +sim/pdp11/ pdp11_dz.c + pdp11_lp.c + pdp11_rl.c + pdp11_rq.c + pdp11_ts.c + +2. VAX Features + +The VAX simulator is configured as follows: + +device simulates +name(s) + +CPU KA655 CPU with 16MB-64MB of memory +TLB translation buffer +ROM read-only memory +NVR non-volatile memory +SYSD system devices +QBA Qbus adapter +PTR,PTP PCV11 paper tape reader/punch +TTI,TTO console terminal +LPT LPV11 line printer +CLK real-time clock +DZ DZV11 8-line terminal multiplexor (up to 4) +RL RLV12/RL01(2) cartridge disk controller with four drives +RQ RQDX3 MSCP controller with four drives +TS TSV11/TSV05 magnetic tape controller with one drive + +The PTR, PTP, LPT, DZ, RL, and TS devices can be set DISABLED. In addition, +most devices support the SET ADDRESS command, which allows the I/O page +address of the device to be changed. + +The VAX simulator implements several unique stop conditions: + + - change mode to interrupt stack + - illegal vector (bits<1:0> = 2 or 3) + - unexpected exception during interrupt or exception + - process PTE in P0 or P1 space instead of system space + - unknown IPL + - infinite loop (BRB/W to self at IPL 1F) + +The VAX supports a simple binary format consisting of a stream of +binary bytes without origin or checksum, for loading memory, the boot +ROM, or the non-volatile memory. + +2.1 CPU and System Devices + +2.2 CPU + +CPU options include the size of main memory and the treatment of the +HALT instruction. + + SET CPU 16M set memory size = 16MB + SET CPU 32M set memory size = 32MB + SET CPU 48M set memory size = 48MB + SET CPU 64M set memory size = 64MB + SET CPU SIMHALT kernel HALT returns to simulator + SET CPU CONHALT kernel HALT returns to boot ROM console + +If memory size is being reduced, and the memory being truncated contains +non-zero data, the simulator asks for confirmation. Data in the truncated +portion of memory is lost. Initial memory size is 16MB. + +Memory can be loaded with a binary byte stream using the LOAD command. +The LOAD command recognizes one switch: + + -o Origin argument follows file name + +The CPU supports the BOOT command and is the only VAX device to do so. + +These switches are recognized when examining or depositing in CPU memory: + + -b examine/deposit bytes + -w examine/deposit words + -d data radix is decimal + -o data radix is octal + -h data radix is hexadecimal + -v interpret address as virtual, current mode + +CPU registers include the visible state of the processor as well as the +control registers for the interrupt system. + + name size comments + + PC 32 program counter + R0..R14 32 R0..R14 + AP 32 alias for R12 + FP 32 alias for R13 + SP 32 alias for R14 + PSL 32 processor status longword + CC 4 condition codes, PSL<3:0> + KSP 32 kernel stack pointer + ESP 32 executive stack pointer + SSP 32 supervisor stack pointer + USP 32 user stack pointer + IS 32 interrupt stack pointer + SCBB 32 system control block base + PCBB 32 process controll block base + P0BR 32 P0 base register + P0LR 22 P0 length register + P1BR 32 P1 base register + P1LR 22 P1 length register + SBR 32 system base register + SLR 22 system length register + SISR 16 software interrupt summary register + ASTLVL 4 AST level register + CADR 8 cache disable register + MSER 8 memory system error register + MAPEN 1 memory management enable flag + TRPIRQ 8 trap/interrupt pending + CRDERR 1 correctible read data error flag + MEMERR 1 memory error flag + PCQ[0:63] 32 PC prior to last PC change or interrupt; + most recent PC change first + WRU 8 interrupt character + +2.1.2 Translation Buffer (TLB) + +The translation buffer consists of two units, representing the system +and user translation buffers, respectively. It has no registers. Each +translation buffer entry consists of two 32b words, as follows: + + word n tag + word n+1 cached PTE + +An invalid entry is indicated by a tag of FFFFFFFF. + +2.1.3 Read-only memory (ROM) + +The boot ROM consists of a single unit, representing the 128KB boot ROM. +It has no registers. The boot ROM is loaded with a binary byte stream +using the LOAD -r command: + + LOAD -r KA655.BIN -- load boot ROM image KA655.BIN + +2.1.4 Non-volatile Memory (NVR) + +The NVR consists of a single unit, representing 1KB of battery-backed up +memory. When the simulator starts, NVR is cleared to 0, and the SSC +battery-low indicator is set. The NVR can be loaded with a binary byte +stream using the LOAD -n command: + + LOAD -n NVR.BIN -- load NVR image NVR.BIN + +Successfully loading an NVR image clears the SSC battery-low indicator. + +2.1.5 System Devices (SYSD) + +The system devices are the facilities implemented in KA655 CPU board, +the CMCTL memory controller, and the SSC system support chip. Note that +the simulation of these devices is incomplete and is intended strictly +to allow the patched bootstrap code to run. The SYSD registers are: + + name size comments + + CMCSR[0:17] 32 CMCTL control and status registers + CACR 8 second-level cache control register + BDR 8 front panel jumper register + BASE 29 SSC base address register + CNF 32 SSC configuration register + BTO 32 SSC bus timeout register + TCSR0 32 SSC timer 0 control/status register + TIR0 32 SSC timer 0 interval register + TNIR0 32 SSC timer 0 next interval register + TIVEC0 9 SSC timer 0 interrupt vector register + TCSR1 32 SSC timer 1 control/status register + TIR1 32 SSC timer 1 interval register + TNIR1 32 SSC timer 1 next interval register + TIVEC1 9 SSC timer 1 interrupt vector register + ADSM0 32 SSC address match 0 address + ADSK0 32 SSC address match 0 mask + ADSM1 32 SSC address match 1 address + ADSK1 32 SSC address match 1 mask + CDGDAT[0:16383] 32 cache diagnostic data store + +2.1.6 Qbus Adapter (QBA) + +The QBA represents the CQBIC Qbus adapter chip. The QBA registers are: + + name size comments + + SCR 16 system configuration register + DSER 8 DMA system error register + MEAR 13 master error address register + SEAR 20 slave error address register + MBR 29 Qbus map base register + IPC 16 interprocessor communications register + IPL17 32 IPL 17 interrupt flags + IPL16 32 IPL 16 interrupt flags + IPL15 32 IPL 15 interrupt flags + IPL14 32 IPL 14 interrupt flags + +2.2 Programmed I/O Devices + +2.2.1 PC11 Paper Tape Reader (PTR) + +The paper tape reader (PTR) reads data from a disk file. The POS +register specifies the number of the next data item to be read. Thus, +by changing POS, the user can backspace or advance the reader. + +The paper tape reader implements these registers: + + name size comments + + BUF 8 last data item processed + CSR 16 control/status register + INT 1 interrupt pending flag + ERR 1 error flag (CSR<15>) + BUSY 1 busy flag (CSR<11>) + DONE 1 device done flag (CSR<7>) + IE 1 interrupt enable flag (CSR<6>) + POS 32 position in the input file + TIME 24 time from I/O initiation to interrupt + STOP_IOE 1 stop on I/O error + +Error handling is as follows: + + error STOP_IOE processed as + + not attached 1 report error and stop + 0 out of tape + + end of file 1 report error and stop + 0 out of tape + + OS I/O error x report error and stop + +2.2.2 PC11 Paper Tape Punch (PTP) + +The paper tape punch (PTP) writes data to a disk file. The POS +register specifies the number of the next data item to be written. +Thus, by by changing POS, the user can backspace or advance the punch. + +The paper tape punch implements these registers: + + name size comments + + BUF 8 last data item processed + CSR 16 control/status register + INT 1 interrupt pending flag + ERR 1 error flag (CSR<15>) + DONE 1 device done flag (CSR<7>) + IE 1 interrupt enable flag (CSR<6>) + POS 32 position in the output file + TIME 24 time from I/O initiation to interrupt + STOP_IOE 1 stop on I/O error + +Error handling is as follows: + + error STOP_IOE processed as + + not attached 1 report error and stop + 0 out of tape + + OS I/O error x report error and stop + +2.2.3 Terminal Input (TTI) + +The terminal input (TTI) polls the console keyboard for input. It +implements these registers: + + name size comments + + BUF 8 last data item processed + CSR 16 control/status register + INT 1 interrupt pending flag + ERR 1 error flag (CSR<15>) + DONE 1 device done flag (CSR<7>) + IE 1 interrupt enable flag (CSR<6>) + POS 32 number of characters input + TIME 24 keyboard polling interval + +2.2.4 Terminal Output (TTO) + +The terminal output (TTO) writes to the simulator console window. It +implements these registers: + + name size comments + + BUF 8 last data item processed + CSR 16 control/status register + INT 1 interrupt pending flag + ERR 1 error flag (CSR<15>) + DONE 1 device done flag (CSR<7>) + IE 1 interrupt enable flag (CSR<6>) + POS 32 number of characters input + TIME 24 time from I/O initiation to interrupt + +2.2.5 Line Printer (LPT) + +The line printer (LPT) writes data to a disk file. The POS register +specifies the number of the next data item to be written. Thus, +by changing POS, the user can backspace or advance the printer. + +The line printer implements these registers: + + name size comments + + BUF 8 last data item processed + CSR 16 control/status register + INT 1 interrupt pending flag + ERR 1 error flag (CSR<15>) + DONE 1 device done flag (CSR<7>) + IE 1 interrupt enable flag (CSR<6>) + POS 32 position in the output file + TIME 24 time from I/O initiation to interrupt + STOP_IOE 1 stop on I/O error + +Error handling is as follows: + + error STOP_IOE processed as + + not attached 1 report error and stop + 0 out of paper + + OS I/O error x report error and stop + +2.2.6 Real-Time Clock (CLK) + +The clock (CLK) implements these registers: + + name size comments + + CSR 16 control/status register + INT 1 interrupt pending flag + IE 1 interrupt enable flag (CSR<6>) + TODR 32 time-of-day register + BLOW 1 TODR battery low indicator + TIME 24 clock frequency + TPS 8 ticks per second (100) + +The real-time clock autocalibrates; the clock interval is adjusted up or +down so that the clock tracks actual elapsed time. + +2.2.7 DZ11 Terminal Multiplexor (DZ) + +The DZ11 is an 8-line terminal multiplexor. Up to 4 DZ11's (32 lines) +are supported. The number of lines can be changed with the command + + SET DZ LINES=n set line count to n + +The line count must be a multiple of 8, with a maximum of 32. + +The terminal lines perform input and output through Telnet sessions +connected to a user-specified port. The ATTACH command specifies +the port to be used: + + ATTACH {-am} DZ set up listening port + +where port is a decimal number between 1 and 65535 that is not being used +for other TCP/IP activities. The optional switch -m turns on the DZ11's +modem controls; the optional switch -a turns on active disconnects +(disconnect session if computer clears Data Terminal Ready). + +Once the DZ is attached and the simulator is running, the DZ will listen +for connections on the specified port. It assumes that the incoming +connections are Telnet connections. The connection remains open until +disconnected by the simulated program, the Telnet client, a SET DZ +DISCONNECT command, or a DETACH DZ command. + +The SHOW DZ CONNECTIONS command displays the current connections to the DZ. +The SHOW DZ STATISTICS command displays statistics for active connections. +The SET DZ DISCONNECT=linenumber disconnects the specified line. + +The DZ11 implements these registers: + + name size comments + + CSR[0:3] 16 control/status register, boards 0-3 + RBUF[0:3] 16 receive buffer, boards 0-3 + LPR[0:3] 16 line parameter register, boards 0-3 + TCR[0:3] 16 transmission control register, boards 0-3 + MSR[0:3] 16 modem status register, boards 0-3 + TDR[0:3] 16 transmit data register, boards 0-3 + SAENB[0:3] 1 silo alarm enabled, boards 0-3 + RXINT 4 receive interrupts, boards 3..0 + TXINT 4 transmit interrupts, boards 3..0 + MDMTCL 1 modem control enabled + AUTODS 1 autodisconnect enabled + +The DZ11 does not support save and restore. All open connections are +lost when the simulator shuts down or the DZ is detached. + +2.3 RLV12/RL01,RL02 Cartridge Disk (RL) + +RLV12 options include the ability to set units write enabled or write locked, +to set the drive size to RL01, RL02, or autosize, and to write a DEC standard +044 compliant bad block table on the last track: + + SET RLn LOCKED set unit n write locked + SET RLn WRITEENABLED set unit n write enabled + SET RLn RL01 set size to RL01 + SET RLn RL02 set size to RL02 + SET RLn AUTOSIZE set size based on file size at attach + SET RLn BADBLOCK write bad block table on last track + +The size options can be used only when a unit is not attached to a file. The +bad block option can be used only when a unit is attached to a file. Units +can also be set ONLINE or OFFLINE. + +The RL11 implements these registers: + + name size comments + + RLCS 16 control/status + RLDA 16 disk address + RLBA 16 memory address + RLBAE 6 memory address extension (RLV12) + RLMP..RLMP2 16 multipurpose register queue + INT 1 interrupt pending flag + ERR 1 error flag (CSR<15>) + DONE 1 device done flag (CSR<7>) + IE 1 interrupt enable flag (CSR<6>) + STIME 24 seek time, per cylinder + RTIME 24 rotational delay + STOP_IOE 1 stop on I/O error + +Error handling is as follows: + + error STOP_IOE processed as + + not attached 1 report error and stop + 0 disk not ready + + end of file x assume rest of disk is zero + + OS I/O error x report error and stop + +2.4 RQDX3 MSCP Disk Controller (RQ) + +The RQ controller simulates the RQDX3 MSCP disk controller. RQ options +include the ability to set units write enabled or write locked, and to +set the drive type to one of eleven disk types: + + SET RQn LOCKED set unit n write locked + SET RQn WRITEENABLED set unit n write enabled + SET RQn RX50 set type to RX50 + SET RQn RX33 set type to RX33 + SET RQn RD51 set type to RD51 + SET RQn RD52 set type to RD52 + SET RQn RD53 set type to RD53 + SET RQn RD54 set type to RD54 + SET RQn RD31 set type to RD31 + SET RQn RA82 set type to RA82 + SET RQn RA72 set type to RA72 + SET RQn RA90 set type to RA90 + SET RQn RA92 set type to RA92 + +The type options can be used only when a unit is not attached to a file. +Units can also be set ONLINE or OFFLINE. + +The RQ controller implements the following special SHOW commands: + + SHOW RQ RINGS show command and response rings + SHOW RQ FREEQ show packet free queue + SHOW RQ RESPQ show packet response queue + SHOW RQ UNITQ show unit queues + SHOW RQ ALL show all ring and queue state + SHOW RQn UNITQ show unit queues for unit n + +The RQ controller implements these registers: + + name size comments + + SA 16 status/address register + S1DAT 16 step 1 init host data + CQBA 22 command queue base address + CQLNT 8 command queue length + CQIDX 8 command queue index + RQBA 22 request queue base address + RQLNT 8 request queue length + RQIDX 8 request queue index + FREE 5 head of free packet list + RESP 5 head of response packet list + PBSY 5 number of busy packets + CFLGS 16 controller flags + CSTA 4 controller state + PERR 9 port error number + CRED 5 host credits + HAT 17 host available timer + HTMO 17 host timeout value + CPKT[0:3] 5 current packet, units 0-3 + PKTQ[0:3] 5 packet queue, units 0-3 + UFLG[0:3] 16 unit flags, units 0-3 + INT 1 interrupt request + ITIME 1 response time for initialization steps + (except for step 4) + QTIME 24 response time for 'immediate' packets + XTIME 24 response time for data transfers + PKTS[33*32] 16 packet buffers, 33W each, + 32 entries + +Error handling is as follows: + + error processed as + + not attached disk not ready + + end of file assume rest of disk is zero + + OS I/O error report error and stop + +2.5 TSV11/TSV05 Magnetic Tape (TS) + +TS options include the ability to make the unit write enabled or write locked. + + SET TS LOCKED set unit write locked + SET TS WRITEENABLED set unit write enabled + +The magnetic tape controller implements these registers: + + name size comments + + TSSR 16 status register + TSBA 16 bus address register + TSDBX 16 data buffer extension register + CHDR 16 command packet header + CADL 16 command packet low address or count + CADH 16 command packet high address + CLNT 16 command packet length + MHDR 16 message packet header + MRFC 16 message packet residual frame count + MXS0 16 message packet extended status 0 + MXS1 16 message packet extended status 1 + MXS2 16 message packet extended status 2 + MXS3 16 message packet extended status 3 + MXS4 16 message packet extended status 4 + WADL 16 write char packet low address + WADH 16 write char packet high address + WLNT 16 write char packet length + WOPT 16 write char packet options + WXOPT 16 write char packet extended options + ATTN 1 attention message pending + BOOT 1 boot request pending + OWNC 1 if set, tape owns command buffer + OWNM 1 if set, tape owns message buffer + TIME 24 delay + POS 32 position + +Error handling is as follows: + + error processed as + + not attached tape not ready + + end of file (read or space) end of physical tape + (write) ignored + + OS I/O error fatal tape error + +2.6 Symbolic Display and Input + +The VAX simulator implements symbolic display and input. Display is +controlled by command line switches: + + -a display as ASCII character + -c display as ASCII string + -m display instruction mnemonics + +Input parsing is controlled by the first character typed in or by command +line switches: + + ' or -a ASCII character + " or -c ASCII string + alphabetic instruction mnemonic + numeric octal number + +Instruction input uses standard VAX assembler syntax. + +The syntax for specifiers is as follows: + +syntax specifier displacement comments + +#s^n, #n 0n - short literal, integer only +[Rn] 4n - indexed, second specifier + follows +Rn 5n - PC illegal +(Rn) 6n - PC illegal +-(Rn) 7n - PC illegal +(Rn)+ 8n - +#i^n, #n 8F n immediate +@(Rn)+ 9n - +@#addr 9F addr absolute +{+/-}b^d(Rn) An {+/-}d byte displacement +b^d AF d - PC byte PC relative +@{+/-}b^d(Rn) Bn {+/-}d byte displacement deferred +@b^d BF d - PC byte PC relative deferred +{+/-}w^d(Rn) Cn {+/-}d word displacement +w^d CF d - PC word PC relative +@{+/-}w^d(Rn) Dn {+/-}d word displacement deferred +@w^d DF d - PC word PC relative deferred +{+/-}l^d(Rn) En {+/-}d long displacement +l^d EF d - PC long PC relative +@{+/-}l^d(Rn) Fn {+/-}d long displacement deferred +@l^d FF d - PC long PC relative deferred + +If no override is given for a literal (s^ or i^) or for a displacement or PC +relative addres (b^, w^, or l^), the simulator chooses the mode automatically. diff --git a/VAX/vax_fpa.c b/VAX/vax_fpa.c new file mode 100644 index 00000000..d0709a3f --- /dev/null +++ b/VAX/vax_fpa.c @@ -0,0 +1,773 @@ +/* vax_fpa.c - VAX floating point accelerator simulator + + Copyright (c) 1998-2002, Robert M Supnik + + Permission is hereby granted, free of charge, to any person obtaining a + copy of this software and associated documentation files (the "Software"), + to deal in the Software without restriction, including without limitation + the rights to use, copy, modify, merge, publish, distribute, sublicense, + and/or sell copies of the Software, and to permit persons to whom the + Software is furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + ROBERT M SUPNIK BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + Except as contained in this notice, the name of Robert M Supnik shall not + be used in advertising or otherwise to promote the sale, use or other dealings + in this Software without prior written authorization from Robert M Supnik. + + 05-Jul-02 RMS Changed internal routine names for C library conflict + 17-Apr-02 RMS Fixed bug in EDIV zero quotient + + This module contains the instruction simulators for + + - 64 bit arithmetic (ASHQ, EMUL, EDIV) + - single precision floating point + - double precision floating point, D and G format + + To make life easier (for me), this module assumes that 64b + integer operations are available. Feel free to rewrite this + in 32b arithmetic... +*/ + +#include "vax_defs.h" +#include + +#define M32 0xFFFFFFFF /* 32b */ +#define ONES 0xFFFFFFFFFFFFFFFF /* 64b */ +#define FD_V_EXP 7 /* f/d exponent */ +#define FD_M_EXP 0xFF +#define FD_BIAS 0x80 /* f/d bias */ +#define FD_EXP (FD_M_EXP << FD_V_EXP) +#define FD_HB (1 << FD_V_EXP) /* f/d hidden bit */ +#define FD_FRACW (0xFFFF & ~(FD_EXP | FPSIGN)) +#define FD_FRACL (FD_FRACW | 0xFFFF0000) /* f/d fraction */ +#define G_V_EXP 4 /* g exponent */ +#define G_M_EXP 0x7FF +#define G_BIAS 0x400 /* g bias */ +#define G_EXP (G_M_EXP << G_V_EXP) +#define G_HB (1 << G_V_EXP) /* g hidden bit */ +#define G_FRACW (0xFFFF & ~(G_EXP | FPSIGN)) +#define G_FRACL (G_FRACW | 0xFFFF0000) /* g fraction */ +#define FD_GETEXP(x) (((x) >> FD_V_EXP) & FD_M_EXP) +#define G_GETEXP(x) (((x) >> G_V_EXP) & G_M_EXP) +#define UNSCRAM(h,l) (((((t_uint64) (h)) << 48) & 0xFFFF000000000000) | \ + ((((t_uint64) (h)) << 16) & 0x0000FFFF00000000) | \ + ((((t_uint64) (l)) << 16) & 0x00000000FFFF0000) | \ + ((((t_uint64) (l)) >> 16) & 0x000000000000FFFF)) +#define CONCAT(h,l) ((((t_uint64) (h)) << 32) | \ + ((uint32) (l))) + +struct ufp { + int32 sign; + int32 exp; + t_uint64 frac; }; + +typedef struct ufp UFP; + +#define UF_NM 0x8000000000000000 /* normalized */ +#define UF_FMSK 0xFFFFFF0000000000 /* F fraction */ +#define UF_FRND 0x0000008000000000 /* F round */ +#define UF_DMSK 0xFFFFFFFFFFFFFF00 /* D fraction */ +#define UF_DRND 0x0000000000000080 /* D round */ +#define UF_GMSK 0xFFFFFFFFFFFFF800 /* G fraction */ +#define UF_GRND 0x0000000000000400 /* G round */ +#define UF_V_NM 63 +#define UF_V_FDHI 40 +#define UF_V_FDLO (UF_V_FDHI - 32) +#define UF_V_GHI 43 +#define UF_V_GLO (UF_V_GHI - 32) +#define UF_GETFDHI(x) (int32) ((((x) >> (16 + UF_V_FDHI)) & FD_FRACW) | \ + (((x) >> (UF_V_FDHI - 16)) & ~0xFFFF)) +#define UF_GETFDLO(x) (int32) ((((x) >> (16 + UF_V_FDLO)) & 0xFFFF) | \ + (((x) << (16 - UF_V_FDLO)) & ~0xFFFF)) +#define UF_GETGHI(x) (int32) ((((x) >> (16 + UF_V_GHI)) & G_FRACW) | \ + (((x) >> (UF_V_GHI - 16)) & ~0xFFFF)) +#define UF_GETGLO(x) (int32) ((((x) >> (16 + UF_V_GLO)) & 0xFFFF) | \ + (((x) << (16 - UF_V_GLO)) & ~0xFFFF)) + +extern int32 R[16]; +extern int32 PSL; +extern int32 p1; +extern jmp_buf save_env; + +extern int32 Read (t_addr va, int32 size, int32 acc); +void unpackf (int32 hi, UFP *a); +void unpackd (int32 hi, int32 lo, UFP *a); +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, t_int64 mask); +void vax_fmul (UFP *a, UFP *b, int32 prec, int32 bias, t_int64 mask); +void vax_fdiv (UFP *b, UFP *a, int32 prec, int32 bias); +void vax_fmod (UFP *a, int32 bias, int32 *intgr, int32 *flg); + +/* Quadword arithmetic shift + + opnd[0] = shift count (cnt.rb) + opnd[1:2] = source (src.rq) + opnd[3:4] = destination (dst.wq) +*/ + +int32 op_ashq (int32 *opnd, int32 *rh, int32 *flg) +{ +t_int64 src, r; +int32 sc = opnd[0]; + +src = CONCAT (opnd[2], opnd[1]); /* build src */ +if (sc & BSIGN) { /* right shift? */ + *flg = 0; /* no ovflo */ + sc = 0x100 - sc; /* |shift| */ + if (sc > 63) r = (opnd[2] & LSIGN)? -1: 0; /* sc > 63? */ + else r = src >> sc; } +else { if (sc > 63) { /* left shift */ + r = 0; /* sc > 63? */ + *flg = (src != 0); } /* ovflo test */ + else { r = src << sc; /* do shift */ + *flg = (src != (r >> sc)); } } /* ovflo test */ +*rh = (int32) (r >> 32); /* hi result */ +return ((int32) r); /* lo result */ +} + +/* Extended multiply subroutine */ + +int32 op_emul (int32 mpy, int32 mpc, int32 *rh) +{ +t_int64 lmpy = mpy; +t_int64 lmpc = mpc; + +lmpy = lmpy * lmpc; +*rh = ((int32) (lmpy >> 32)); +return (int32) lmpy; +} + +/* Extended divide + + opnd[0] = divisor (non-zero) + opnd[1:2] = dividend +*/ + +int32 op_ediv (int32 *opnd, int32 *rh, int32 *flg) +{ +t_int64 ldvd, ldvr; +int32 quo, rem; + +*flg = CC_V; /* assume error */ +*rh = 0; +ldvr = ((opnd[0] & LSIGN)? -opnd[0]: opnd[0]) & M32; /* |divisor| */ +ldvd = CONCAT (opnd[2], opnd[1]); /* 64b dividend */ +if (opnd[2] & LSIGN) ldvd = -ldvd; /* |dividend| */ +if (((ldvd >> 32) & M32) >= ldvr) return opnd[1]; /* divide work? */ +quo = (int32) (ldvd / ldvr); /* do divide */ +rem = (int32) (ldvd % ldvr); +if ((opnd[0] ^ opnd[2]) & LSIGN) { /* result -? */ + quo = -quo; /* negate */ + if (quo && ((quo & LSIGN) == 0)) return opnd[1]; } /* right sign? */ +else if (quo & LSIGN) return opnd[1]; +if (opnd[2] & LSIGN) rem = -rem; /* sign of rem */ +*flg = 0; /* no overflow */ +*rh = rem; /* set rem */ +return quo; /* return quo */ +} + +/* Move/test/move negated floating + + Note that only the high 32b is processed. + If the high 32b is not zero, it is unchanged. +*/ + +int32 op_movfd (int32 val) +{ +if (val & FD_EXP) return val; +if (val & FPSIGN) RSVD_OPND_FAULT; +return 0; +} + +int32 op_mnegfd (int32 val) +{ +if (val & FD_EXP) return (val ^ FPSIGN); +if (val & FPSIGN) RSVD_OPND_FAULT; +return 0; +} + +int32 op_movg (int32 val) +{ +if (val & G_EXP) return val; +if (val & FPSIGN) RSVD_OPND_FAULT; +return 0; +} + +int32 op_mnegg (int32 val) +{ +if (val & G_EXP) return (val ^ FPSIGN); +if (val & FPSIGN) RSVD_OPND_FAULT; +return 0; +} + +/* Compare floating */ + +int32 op_cmpfd (int32 h1, int32 l1, int32 h2, int32 l2) +{ +t_uint64 n1, n2; + +if ((h1 & FD_EXP) == 0) { + if (h1 & FPSIGN) RSVD_OPND_FAULT; + h1 = l1 = 0; } +if ((h2 & FD_EXP) == 0) { + if (h2 & FPSIGN) RSVD_OPND_FAULT; + h2 = l2 = 0; } +if ((h1 ^ h2) & FPSIGN) return ((h1 & FPSIGN)? CC_N: 0); +n1 = UNSCRAM (h1, l1); +n2 = UNSCRAM (h2, l2); +if (n1 == n2) return CC_Z; +return (((n1 < n2) ^ ((h1 & FPSIGN) != 0))? CC_N: 0); +} + +int32 op_cmpg (int32 h1, int32 l1, int32 h2, int32 l2) +{ +t_uint64 n1, n2; + +if ((h1 & G_EXP) == 0) { + if (h1 & FPSIGN) RSVD_OPND_FAULT; + h1 = l1 = 0; } +if ((h2 & G_EXP) == 0) { + if (h2 & FPSIGN) RSVD_OPND_FAULT; + h2 = l2 = 0; } +if ((h1 ^ h2) & FPSIGN) return ((h1 & FPSIGN)? CC_N: 0); +n1 = UNSCRAM (h1, l1); +n2 = UNSCRAM (h2, l2); +if (n1 == n2) return CC_Z; +return (((n1 < n2) ^ ((h1 & FPSIGN) != 0))? CC_N: 0); +} + +/* Integer to floating convert */ + +int32 op_cvtifdg (int32 val, int32 *rh, int32 opc) +{ +UFP a; + +if (val == 0) { + if (rh) *rh = 0; + return 0; } +if (val < 0) { + a.sign = FPSIGN; + val = - val; } +else a.sign = 0; +a.exp = 32 + ((opc & 0x100)? G_BIAS: FD_BIAS); +a.frac = ((t_uint64) val) << (UF_V_NM - 31); +norm (&a); +if (opc & 0x100) return rpackg (&a, rh); +return rpackfd (&a, rh); +} + +/* Floating to integer convert */ + +int32 op_cvtfdgi (int32 *opnd, int32 *flg, int32 opc) +{ +UFP a; +int32 lnt = opc & 03; +int32 ubexp; +static t_uint64 maxv[4] = { 0x7F, 0x7FFF, 0x7FFFFFFF, 0x7FFFFFFF }; + +*flg = 0; +if (opc & 0x100) { + unpackg (opnd[0], opnd[1], &a); + ubexp = a.exp - G_BIAS; } +else { if (opc & 0x20) unpackd (opnd[0], opnd[1], &a); + else unpackf (opnd[0], &a); + ubexp = a.exp - FD_BIAS; } +if ((a.exp == 0) || (ubexp < 0)) return 0; +if (ubexp <= UF_V_NM) { + a.frac = a.frac >> (UF_V_NM - ubexp); /* leave rnd bit */ + if ((opc & 03) == 03) a.frac = a.frac + 1; /* if CVTR, round */ + a.frac = a.frac >> 1; /* now justified */ + if (a.frac > (maxv[lnt] + (a.sign != 0))) *flg = CC_V; } +else { if (ubexp > (UF_V_NM + 32)) return 0; + a.frac = a.frac << (ubexp - UF_V_NM - 1); /* no rnd bit */ + *flg = CC_V; } +return ((int32) (a.sign? (a.frac ^ M32) + 1: a.frac)); +} + +/* Floating to floating convert + F to D is essentially done with MOVFD +*/ + +int32 op_cvtdf (int32 *opnd) +{ +UFP a; + +unpackd (opnd[0], opnd[1], &a); +return rpackfd (&a, NULL); +} + +int32 op_cvtfg (int32 *opnd, int32 *rh) +{ +UFP a; + +unpackf (opnd[0], &a); +a.exp = a.exp - FD_BIAS + G_BIAS; +return rpackg (&a, rh); +} + +int32 op_cvtgf (int32 *opnd) +{ +UFP a; + +unpackg (opnd[0], opnd[1], &a); +a.exp = a.exp - G_BIAS + FD_BIAS; +return rpackfd (&a, NULL); +} + +/* Floating add and subtract */ + +int32 op_addf (int32 *opnd, t_bool sub) +{ +UFP a, b; + +unpackf (opnd[0], &a); /* F format */ +unpackf (opnd[1], &b); +if (sub) a.sign = a.sign ^ FPSIGN; /* sub? -s1 */ +vax_fadd (&a, &b, 0); /* add fractions */ +return rpackfd (&a, NULL); +} + +int32 op_addd (int32 *opnd, int32 *rh, t_bool sub) +{ +UFP a, b; + +unpackd (opnd[0], opnd[1], &a); +unpackd (opnd[2], opnd[3], &b); +if (sub) a.sign = a.sign ^ FPSIGN; /* sub? -s1 */ +vax_fadd (&a, &b, 0); /* add fractions */ +return rpackfd (&a, rh); +} + +int32 op_addg (int32 *opnd, int32 *rh, t_bool sub) +{ +UFP a, b; + +unpackg (opnd[0], opnd[1], &a); +unpackg (opnd[2], opnd[3], &b); +if (sub) a.sign = a.sign ^ FPSIGN; /* sub? -s1 */ +vax_fadd (&a, &b, 0); /* add fractions */ +return rpackg (&a, rh); /* round and pack */ +} + +void vax_fadd (UFP *a, UFP *b, t_int64 mask) +{ +int32 ediff; +UFP t; + +if (a -> exp == 0) { /* s1 = 0? */ + *a = *b; + return; } +if (b -> exp == 0) return; /* s2 = 0? */ +if (a -> exp < b -> exp) { /* s1 < s2? swap */ + t = *a; + *a = *b; + *b = t; } +ediff = a -> exp - b -> exp; /* exp diff */ +if (a -> sign ^ b -> sign) { /* eff sub? */ + if (ediff) { /* exp diff? */ + b -> frac = (ediff > 63)? ONES: /* shift b */ + ((-((t_int64) b -> frac) >> ediff) | + (ONES << (64 - ediff))); /* preserve sign */ + a -> frac = a -> frac + b -> frac; } /* add frac */ + else { if (a -> frac < b -> frac) { /* same, check magn */ + a -> frac = b -> frac - a -> frac; /* b > a */ + a -> sign = b -> sign; } + else a -> frac = a -> frac - b -> frac; } /* a >= b */ + a -> frac = a -> frac & ~mask; + norm (a); } /* normalize */ +else { if (ediff >= 64) b -> frac = 0; + else b -> frac = b -> frac >> ediff; /* add, denorm */ + a -> frac = a -> frac + b -> frac; /* add frac */ + if (a -> frac < b -> frac) { /* chk for carry */ + a -> frac = UF_NM | (a -> frac >> 1); /* shift in carry */ + a -> exp = a -> exp + 1; } /* skip norm */ + a -> frac = a -> frac & ~mask; } +return; +} + +/* Floating multiply + + Note that when the fractions are multiplied, the fraction position + must be adjusted to maintain the right precision. +*/ + +int32 op_mulf (int32 *opnd) +{ +UFP a, b; + +unpackf (opnd[0], &a); /* F format */ +unpackf (opnd[1], &b); +vax_fmul (&a, &b, 24, FD_BIAS, 0); /* do multiply */ +return rpackfd (&a, NULL); /* round and pack */ +} + +int32 op_muld (int32 *opnd, int32 *rh) +{ +UFP a, b; + +unpackd (opnd[0], opnd[1], &a); +unpackd (opnd[2], opnd[3], &b); +vax_fmul (&a, &b, 56, FD_BIAS, 0); /* do multiply */ +return rpackfd (&a, rh); /* round and pack */ +} + +int32 op_mulg (int32 *opnd, int32 *rh) +{ +UFP a, b; + +unpackg (opnd[0], opnd[1], &a); /* G format */ +unpackg (opnd[2], opnd[3], &b); +vax_fmul (&a, &b, 53, G_BIAS, 0); /* do multiply */ +return rpackg (&a, rh); /* round and pack */ +} + +/* Floating multiply - 64b * 64b with cross products + Where is Alpha's UMULH when you need it? +*/ + +void vax_fmul (UFP *a, UFP *b, int32 prec, int32 bias, t_int64 mask) +{ +t_uint64 ah, bh, al, bl, rhi, rlo, rmid1, rmid2; + +if ((a -> exp == 0) || (b -> exp == 0)) { /* zero argument? */ + a -> frac = a -> sign = a -> exp = 0; /* result is zero */ + return; } +a -> sign = a -> sign ^ b -> sign; /* sign of result */ +a -> exp = a -> exp + b -> exp - bias; /* add exponents */ +ah = (a -> frac >> 32) & M32; /* split operands */ +bh = (b -> frac >> 32) & M32; /* into 32b chunks */ +rhi = ah * bh; /* high result */ +if (prec > 32) { /* 64b needed? */ + al = a -> frac & M32; + bl = b -> frac & M32; + rmid1 = ah * bl; + rmid2 = al * bh; + rlo = al * bl; + rhi = rhi + ((rmid1 >> 32) & M32) + ((rmid2 >> 32) & M32); + rmid1 = rlo + (rmid1 << 32); /* add mid1 to lo */ + if (rmid1 < rlo) rhi = rhi + 1; /* carry? incr hi */ + rmid2 = rmid1 + (rmid2 << 32); /* add mid2 to to */ + if (rmid2 < rmid1) rhi = rhi + 1; } /* carry? incr hi */ +a -> frac = rhi & ~mask; /* mask out */ +norm (a); /* normalize */ +return; +} + +/* Floating divide */ + +int32 op_divf (int32 *opnd) +{ +UFP a, b; + +unpackf (opnd[0], &a); /* F format */ +unpackf (opnd[1], &b); +vax_fdiv (&a, &b, 26, FD_BIAS); /* do divide */ +return rpackfd (&b, NULL); /* round and pack */ +} + +int32 op_divd (int32 *opnd, int32 *rh) +{ +UFP a, b; + +unpackd (opnd[0], opnd[1], &a); +unpackd (opnd[2], opnd[3], &b); +vax_fdiv (&a, &b, 58, FD_BIAS); /* do divide */ +return rpackfd (&b, rh); /* round and pack */ +} + +int32 op_divg (int32 *opnd, int32 *rh) +{ +UFP a, b; + +unpackg (opnd[0], opnd[1], &a); /* G format */ +unpackg (opnd[2], opnd[3], &b); +vax_fdiv (&a, &b, 55, G_BIAS); /* do divide */ +return rpackg (&b, rh); /* round and pack */ +} + +/* Floating divide + Needs to develop at least one rounding bit. Since the first + divide step can fail, caller should specify 2 more bits than + the precision of the fraction. +*/ + +void vax_fdiv (UFP *a, UFP *b, int32 prec, int32 bias) +{ +int32 i; +t_uint64 quo = 0; + +if (a -> exp == 0) FLT_DZRO_FAULT; /* divr = 0? */ +if (b -> exp == 0) return; /* divd = 0? */ +b -> sign = b -> sign ^ a -> sign; /* result sign */ +b -> exp = b -> exp - a -> exp + bias + 1; /* unbiased exp */ +a -> frac = a -> frac >> 1; /* allow 1 bit left */ +b -> frac = b -> frac >> 1; +for (i = 0; (i < prec) && b -> frac; i++) { /* divide loop */ + quo = quo << 1; /* shift quo */ + if (b -> frac >= a -> frac) { /* div step ok? */ + b -> frac = b -> frac - a -> frac; /* subtract */ + quo = quo + 1; } /* quo bit = 1 */ + b -> frac = b -> frac << 1; } /* shift divd */ +b -> frac = quo << (UF_V_NM - i + 1); /* shift quo */ +norm (b); /* normalize */ +return; +} + +/* Extended modularize + + One of three floating point instructions dropped from the architecture, + EMOD presents two sets of complications. First, it requires an extended + fraction multiply, with precise (and unusual) truncation conditions. + Second, it has two write operands, a dubious distinction it shares + with EDIV. +*/ + +int32 op_emodf (int32 *opnd, int32 *intgr, int32 *flg) +{ +UFP a, b; + +unpackf (opnd[1], &a); /* unpack operands */ +unpackf (opnd[2], &b); +a.frac = a.frac | (((t_uint64) opnd[0]) << 32); /* extend src1 */ +vax_fmul (&a, &b, 32, FD_BIAS, M32); /* multiply */ +vax_fmod (&a, FD_BIAS, intgr, flg); /* sep int & frac */ +return rpackfd (&a, NULL); /* return frac */ +} + +int32 op_emodd (int32 *opnd, int32 *flo, int32 *intgr, int32 *flg) +{ +UFP a, b; + +unpackd (opnd[1], opnd[2], &a); /* unpack operands */ +unpackd (opnd[3], opnd[4], &b); +a.frac = a.frac | opnd[0]; /* extend src1 */ +vax_fmul (&a, &b, 64, FD_BIAS, 0); /* multiply */ +vax_fmod (&a, FD_BIAS, intgr, flg); /* sep int & frac */ +return rpackfd (&a, flo); /* return frac */ +} + +int32 op_emodg (int32 *opnd, int32 *flo, int32 *intgr, int32 *flg) +{ +UFP a, b; + +unpackg (opnd[1], opnd[2], &a); /* unpack operands */ +unpackg (opnd[3], opnd[4], &b); +a.frac = a.frac | (opnd[0] >> 5); +vax_fmul (&a, &b, 64, G_BIAS, 0); /* multiply */ +vax_fmod (&a, G_BIAS, intgr, flg); /* sep int & frac */ +return rpackg (&a, flo); /* return frac */ +} + +void vax_fmod (UFP *a, int32 bias, int32 *intgr, int32 *flg) +{ +if (a -> exp <= bias) *intgr = 0; /* 0 or <1? int = 0 */ +else if (a -> exp <= (bias + 64)) { /* in range? */ + *intgr = (int32) (a -> frac >> (64 - (a -> exp - bias))); + a -> frac = a -> frac << (a -> exp - bias); } +else *intgr = 0; /* out of range */ +if (a -> sign) *intgr = -*intgr; /* -? comp int */ +if ((a -> exp >= (bias + 32)) || (((a -> sign) != 0) && (*intgr < 0))) + *flg = CC_V; /* test ovflo */ +else *flg = 0; +norm (a); /* normalize */ +return; +} + +/* Polynomial evaluation + The most mis-implemented instruction in the VAX (probably here too). + POLY requires a precise combination of masking versus normalizing + to achieve the desired answer. In particular, both the multiply + and add steps are masked prior to normalization. In addition, + negative small fractions must not be treated as 0 during denorm. +*/ + +void op_polyf (int32 *opnd, int32 acc) +{ +UFP r, a, c; +int32 deg = opnd[1]; +int32 ptr = opnd[2]; +int32 i, wd, res; + +if (deg > 31) RSVD_OPND_FAULT; /* degree > 31? fault */ +unpackf (opnd[0], &a); /* unpack arg */ +wd = Read (ptr, L_LONG, RD); /* get C0 */ +ptr = ptr + 4; +unpackf (wd, &r); /* unpack C0 */ +res = rpackfd (&r, NULL); /* first result */ +for (i = 0; (i < deg) && a.exp; i++) { /* loop */ + unpackf (res, &r); /* unpack result */ + vax_fmul (&r, &a, 32, FD_BIAS, M32); /* r = r * arg */ + wd = Read (ptr, L_LONG, RD); /* get Cnext */ + ptr = ptr + 4; + unpackf (wd, &c); /* unpack Cnext */ + vax_fadd (&r, &c, M32); /* r = r + Cnext */ + res = rpackfd (&r, NULL); } /* round and pack */ +R[0] = res; +R[1] = R[2] = 0; +R[3] = opnd[2] + 4 + (opnd[1] << 2); +return; +} + +void op_polyd (int32 *opnd, int32 acc) +{ +UFP r, a, c; +int32 deg = opnd[2]; +int32 ptr = opnd[3]; +int32 i, wd, wd1, res, resh; + +if (deg > 31) RSVD_OPND_FAULT; /* degree > 31? fault */ +unpackd (opnd[0], opnd[1], &a); /* unpack arg */ +wd = Read (ptr, L_LONG, RD); /* get C0 */ +wd1 = Read (ptr + 4, L_LONG, RD); +ptr = ptr + 8; +unpackd (wd, wd1, &r); /* unpack C0 */ +res = rpackfd (&r, &resh); /* first result */ +for (i = 0; (i < deg) && a.exp; i++) { /* loop */ + unpackd (res, resh, &r); /* unpack result */ + vax_fmul (&r, &a, 32, FD_BIAS, 0); /* r = r * arg */ + wd = Read (ptr, L_LONG, RD); /* get Cnext */ + wd1 = Read (ptr + 4, L_LONG, RD); + ptr = ptr + 8; + unpackd (wd, wd1, &c); /* unpack Cnext */ + vax_fadd (&r, &c, 0); /* r = r + Cnext */ + res = rpackfd (&r, &resh); } /* round and pack */ +R[0] = res; +R[1] = resh; +R[2] = 0; +R[3] = opnd[3] + 4 + (opnd[2] << 2); +return; +} + +void op_polyg (int32 *opnd, int32 acc) +{ +UFP r, a, c; +int32 deg = opnd[2]; +int32 ptr = opnd[3]; +int32 i, wd, wd1, res, resh; + +if (deg > 31) RSVD_OPND_FAULT; /* degree > 31? fault */ +unpackg (opnd[0], opnd[1], &a); /* unpack arg */ +wd = Read (ptr, L_LONG, RD); /* get C0 */ +wd1 = Read (ptr + 4, L_LONG, RD); +ptr = ptr + 8; +unpackg (wd, wd1, &r); /* unpack C0 */ +res = rpackg (&r, &resh); /* first result */ +for (i = 0; (i < deg) && a.exp; i++) { /* loop */ + unpackg (res, resh, &r); /* unpack result */ + vax_fmul (&r, &a, 32, G_BIAS, 0); /* r = r * arg */ + wd = Read (ptr, L_LONG, RD); /* get Cnext */ + wd1 = Read (ptr + 4, L_LONG, RD); + ptr = ptr + 8; + unpackg (wd, wd1, &c); /* unpack Cnext */ + vax_fadd (&r, &c, 0); /* r = r + Cnext */ + res = rpackg (&r, &resh); } /* round and pack */ +R[0] = res; +R[1] = resh; +R[2] = 0; +R[3] = opnd[3] + 4 + (opnd[2] << 2); +return; +} + +/* Support routines */ + +void unpackf (int32 hi, UFP *r) +{ +r -> sign = hi & FPSIGN; /* get sign */ +r -> exp = FD_GETEXP (hi); /* get exponent */ +if (r -> exp == 0) { /* exp = 0? */ + if (r -> sign) RSVD_OPND_FAULT; /* if -, rsvd op */ + r -> frac = 0; /* else 0 */ + return; } +hi = (((hi & FD_FRACW) | FD_HB) << 16) | ((hi >> 16) & 0xFFFF); +r -> frac = ((t_uint64) hi) << (32 + UF_V_FDLO); +return; +} + +void unpackd (int32 hi, int32 lo, UFP *r) +{ +r -> sign = hi & FPSIGN; /* get sign */ +r -> exp = FD_GETEXP (hi); /* get exponent */ +if (r -> exp == 0) { /* exp = 0? */ + if (r -> sign) RSVD_OPND_FAULT; /* if -, rsvd op */ + r -> frac = 0; /* else 0 */ + return; } +hi = (hi & FD_FRACL) | FD_HB; /* canonical form */ +r -> frac = UNSCRAM (hi, lo) << UF_V_FDLO; /* guard bits */ +return; +} + +void unpackg (int32 hi, int32 lo, UFP *r) +{ +r -> sign = hi & FPSIGN; /* get sign */ +r -> exp = G_GETEXP (hi); /* get exponent */ +if (r -> exp == 0) { /* exp = 0? */ + if (r -> sign) RSVD_OPND_FAULT; /* if -, rsvd op */ + r -> frac = 0; /* else 0 */ + return; } +hi = (hi & G_FRACL) | G_HB; /* canonical form */ +r -> frac = UNSCRAM (hi, lo) << UF_V_GLO; /* guard bits */ +return; +} + +void 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}; + +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; +} + +int32 rpackfd (UFP *r, int32 *rh) +{ +if (rh) *rh = 0; /* assume 0 */ +if (r -> frac == 0) return 0; /* result 0? */ +r -> frac = r -> frac + (rh? UF_DRND: UF_FRND); /* round */ +if ((r -> frac & UF_NM) == 0) { /* carry out? */ + r -> frac = r -> frac >> 1; /* renormalize */ + r -> exp = r -> exp + 1; } +if (r -> exp > (int32) FD_M_EXP) FLT_OVFL_FAULT; /* ovflo? fault */ +if (r -> exp <= 0) { /* underflow? */ + if (PSL & PSW_FU) FLT_UNFL_FAULT; /* fault if fu */ + return 0; } /* else 0 */ +if (rh) *rh = UF_GETFDLO (r -> frac); /* get low */ +return r -> sign | (r -> exp << FD_V_EXP) | UF_GETFDHI (r -> frac); +} + +int32 rpackg (UFP *r, int32 *rh) +{ +*rh = 0; /* assume 0 */ +if (r -> frac == 0) return 0; /* result 0? */ +r -> frac = r -> frac + UF_GRND; /* round */ +if ((r -> frac & UF_NM) == 0) { /* carry out? */ + r -> frac = r -> frac >> 1; /* renormalize */ + r -> exp = r -> exp + 1; } +if (r -> exp > (int32) G_M_EXP) FLT_OVFL_FAULT; /* ovflo? fault */ +if (r -> exp <= 0) { /* underflow? */ + if (PSL & PSW_FU) FLT_UNFL_FAULT; /* fault if fu */ + return 0; } /* else 0 */ +if (rh) *rh = UF_GETGLO (r -> frac); /* get low */ +return r -> sign | (r -> exp << G_V_EXP) | UF_GETGHI (r -> frac); +} diff --git a/VAX/vax_io.c b/VAX/vax_io.c new file mode 100644 index 00000000..2d8fb725 --- /dev/null +++ b/VAX/vax_io.c @@ -0,0 +1,719 @@ +/* vax_io.c: VAX Qbus IO simulator + + Copyright (c) 1998-2002, Robert M Supnik + + Permission is hereby granted, free of charge, to any person obtaining a + copy of this software and associated documentation files (the "Software"), + to deal in the Software without restriction, including without limitation + the rights to use, copy, modify, merge, publish, distribute, sublicense, + and/or sell copies of the Software, and to permit persons to whom the + Software is furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + ROBERT M SUPNIK BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + Except as contained in this notice, the name of Robert M Supnik shall not + be used in advertising or otherwise to promote the sale, use or other dealings + in this Software without prior written authorization from Robert M Supnik. + + qba Qbus adapter +*/ + +#include "vax_defs.h" + +/* CQBIC system configuration register */ + +#define CQSCR_POK 0x00008000 /* power ok RO1 */ +#define CQSCR_BHL 0x00004000 /* BHALT enb */ +#define CQSCR_AUX 0x00000400 /* aux mode RONI */ +#define CQSCR_DBO 0x0000000C /* offset NI */ +#define CQSCR_RW (CQSCR_BHL | CQSCR_DBO) +#define CQSCR_MASK (CQSCR_RW | CQSCR_POK | CQSCR_AUX) + +/* CQBIC DMA system error register - W1C */ + +#define CQDSER_BHL 0x00008000 /* BHALT NI */ +#define CQDSER_DCN 0x00004000 /* DC ~OK NI */ +#define CQDSER_MNX 0x00000080 /* master NXM */ +#define CQDSER_MPE 0x00000020 /* master par NI */ +#define CQDSER_SME 0x00000010 /* slv mem err NI */ +#define CQDSER_LST 0x00000008 /* lost err */ +#define CQDSER_TMO 0x00000004 /* no grant NI */ +#define CQDSER_SNX 0x00000001 /* slave NXM */ +#define CQDSER_ERR (CQDSER_MNX | CQDSER_MPE | CQDSER_TMO | CQDSER_SNX) +#define CQDSER_MASK 0x0000C0BD + +/* CQBIC master error address register */ + +#define CQMEAR_MASK 0x00001FFF /* Qbus page */ + +/* CQBIC slave error address register */ + +#define CQSEAR_MASK 0x000FFFFF /* mem page */ + +/* CQBIC map base register */ + +#define CQMBR_MASK 0x1FFF8000 /* 32KB aligned */ + +/* CQBIC IPC register */ + +#define CQIPC_QME 0x00008000 /* Qbus read NXM W1C */ +#define CQIPC_INV 0x00004000 /* CAM inval NIWO */ +#define CQIPC_AHLT 0x00000100 /* aux halt NI */ +#define CQIPC_DBIE 0x00000040 /* dbell int enb NI */ +#define CQIPC_LME 0x00000020 /* local mem enb */ +#define CQIPC_DB 0x00000001 /* doorbell req NI */ +#define CQIPC_W1C CQIPC_QME +#define CQIPC_RW (CQIPC_AHLT | CQIPC_DBIE | CQIPC_LME | CQIPC_DB) +#define CQIPC_MASK (CQIPC_RW | CQIPC_QME ) + +/* CQBIC map entry */ + +#define CQMAP_VLD 0x80000000 /* valid */ +#define CQMAP_PAG 0x000FFFFF /* mem page */ + +int32 int_req[IPL_HLVL] = { 0 }; /* intr, IPL 14-17 */ +int32 cq_scr = 0; /* SCR */ +int32 cq_dser = 0; /* DSER */ +int32 cq_mear = 0; /* MEAR */ +int32 cq_sear = 0; /* SEAR */ +int32 cq_mbr = 0; /* MBR */ +int32 cq_ipc = 0; /* IPC */ +static int_dummy = 0; /* keep save/restore working */ + +extern uint32 *M; +extern UNIT cpu_unit; +extern int32 PSL, SISR, trpirq, mem_err; +extern int32 p1; +extern int32 ssc_bto; +extern jmp_buf save_env; + +extern int32 ReadB (t_addr pa); +extern int32 ReadW (t_addr pa); +extern int32 ReadL (t_addr pa); +extern int32 WriteB (t_addr pa, int32 val); +extern int32 WriteW (t_addr pa, int32 val); +extern int32 WriteL (t_addr pa, int32 val); +extern DIB pt_dib; +extern DIB lpt_dib, dz_dib; +extern DIB rl_dib, rq_dib; +extern DIB ts_dib; +extern FILE *sim_log; + +t_stat dbl_rd (int32 *data, int32 addr, int32 access); +t_stat dbl_wr (int32 data, int32 addr, int32 access); +int32 eval_int (void); +void cq_merr (int32 pa); +void cq_serr (int32 pa); +t_bool dev_conflict (uint32 nba, DIB *curr); +t_stat qba_reset (DEVICE *dptr); +extern int32 rq_inta (void); +extern int32 tmr0_inta (void); +extern int32 tmr1_inta (void); +extern dz_rxinta (void); +extern dz_txinta (void); + +/* Qbus adapter data structures + + qba_dev QBA device descriptor + qba_unit QBA units + qba_reg QBA register list +*/ + +DIB qba_dib = { 1, IOBA_DBL, IOLN_DBL, &dbl_rd, &dbl_wr }; + +UNIT qba_unit = { UDATA (NULL, 0, 0) }; + +REG qba_reg[] = { + { HRDATA (SCR, cq_scr, 16) }, + { HRDATA (DSER, cq_dser, 8) }, + { HRDATA (MEAR, cq_mear, 13) }, + { HRDATA (SEAR, cq_sear, 20) }, + { HRDATA (MBR, cq_mbr, 29) }, + { HRDATA (IPC, cq_ipc, 16) }, + { HRDATA (IPL18, int_dummy, 32), REG_HRO }, + { HRDATA (IPL17, int_req[3], 32), REG_RO }, + { HRDATA (IPL16, int_req[2], 32), REG_RO }, + { HRDATA (IPL15, int_req[1], 32), REG_RO }, + { HRDATA (IPL14, int_req[0], 32), REG_RO }, + { NULL } }; + +DEVICE qba_dev = { + "QBA", &qba_unit, qba_reg, NULL, + 1, 0, 0, 0, 0, 0, + NULL, NULL, &qba_reset, + NULL, NULL, NULL }; + +struct iolink { /* I/O page linkage */ + int32 low; /* low I/O addr */ + int32 high; /* high I/O addr */ + int32 *enb; /* enable flag */ + t_stat (*read)(); /* read routine */ + t_stat (*write)(); }; /* write routine */ + +/* IO page addresses */ + +DIB *dib_tab[] = { + &dz_dib, + &rq_dib, + &rl_dib, + &pt_dib, + &lpt_dib, + &ts_dib, + &qba_dib, + NULL }; + +/* Interrupt request to interrupt action map */ + +int32 (*int_ack[IPL_HLVL][32])() = { /* int ack routines */ + { NULL, NULL, NULL, NULL, /* IPL 14 */ + NULL, NULL, NULL, &tmr0_inta, + &tmr1_inta }, + { &rq_inta, NULL, &dz_rxinta, &dz_txinta, /* IPL 15 */ + NULL, NULL }, + { NULL }, /* IPL 16 */ + { NULL } }; /* IPL 17 */ + +/* Interrupt request to vector map */ + +int32 int_vec[IPL_HLVL][32] = { /* int req to vector */ + { SCB_TTI, SCB_TTO, VEC_PTR, VEC_PTP, /* IPL 14 */ + VEC_LPT, SCB_CSI, SCB_CSO, 0, + 0 }, + { VEC_RQ, VEC_RL, VEC_DZRX, VEC_DZTX, /* IPL 15 */ + VEC_RP, VEC_TS }, + { SCB_INTTIM }, /* IPL 16 */ + { 0 } }; /* IPL 17 */ + +/* The KA65x handles errors in I/O space as follows + + - read: set DSER<7>, latch addr in MEAR, machine check + - write: set DSER<7>, latch addr in MEAR, MEMERR interrupt +*/ + +int32 ReadQb (uint32 pa) +{ +int32 i, val; +DIB *dibp; + +for (i = 0; dibp = dib_tab[i]; i++ ) { + if (dibp -> enb && (pa >= dibp -> ba) && + (pa < (dibp -> ba + dibp -> lnt))) { + dibp -> rd (&val, pa, READ); + return val; } } +cq_merr (pa); +MACH_CHECK (MCHK_READ); +return 0; +} + +void WriteQb (uint32 pa, int32 val, int32 mode) +{ +int32 i; +DIB *dibp; + +for (i = 0; dibp = dib_tab[i]; i++ ) { + if (dibp -> enb && (pa >= dibp -> ba) && + (pa < (dibp -> ba + dibp -> lnt))) { + dibp -> wr (val, pa, mode); + return; } } +cq_merr (pa); +mem_err = 1; +return; +} + +/* ReadIO - read I/O space + + Inputs: + pa = physical address + lnt = length (BWLQ) + Output: + longword of data +*/ + +int32 ReadIO (int32 pa, int32 lnt) +{ +int32 iod; + +iod = ReadQb (pa); /* wd from Qbus */ +if (lnt < L_LONG) iod = iod << ((pa & 2)? 16: 0); /* bw? position */ +else iod = (ReadQb (pa + 2) << 16) | iod; /* lw, get 2nd wd */ +SET_IRQL; +return iod; +} + +/* WriteIO - write I/O space + + Inputs: + pa = physical address + val = data to write, right justified in 32b longword + lnt = length (BWLQ) + Outputs: + none +*/ + +void WriteIO (int32 pa, int32 val, int32 lnt) +{ +if (lnt == L_BYTE) WriteQb (pa, val, WRITEB); +else if (lnt == L_WORD) WriteQb (pa, val, WRITE); +else { WriteQb (pa, val & 0xFFFF, WRITE); + WriteQb (pa + 2, (val >> 16) & 0xFFFF, WRITE); } +SET_IRQL; +return; +} + +/* Find highest priority outstanding interrupt */ + +int32 eval_int (void) +{ +int32 ipl = PSL_GETIPL (PSL); +int32 i, t; + +static const int32 sw_int_mask[IPL_SMAX] = { + 0xFFFE, 0xFFFC, 0xFFF8, 0xFFF0, /* 0 - 3 */ + 0xFFE0, 0xFFC0, 0xFF80, 0xFF00, /* 4 - 7 */ + 0xFE00, 0xFC00, 0xF800, 0xF000, /* 8 - B */ + 0xE000, 0xC000, 0x8000 }; /* C - E */ + +if ((ipl < IPL_MEMERR) && mem_err) return IPL_MEMERR; /* mem err int */ +for (i = IPL_HMAX; i >= IPL_HMIN; i--) { /* chk hwre int */ + if (i <= ipl) return 0; /* at ipl? no int */ + if (int_req[i - IPL_HMIN]) return i; } /* req != 0? int */ +if (ipl >= IPL_SMAX) return 0; /* ipl >= sw max? */ +if ((t = SISR & sw_int_mask[ipl]) == 0) return 0; /* eligible req */ +for (i = IPL_SMAX; i > ipl; i--) { /* check swre int */ + if ((t >> i) & 1) return i; } /* req != 0? int */ +return 0; +} + +/* Return vector for highest priority hardware interrupt at IPL lvl*/ + +int32 get_vector (int32 lvl) +{ +int32 i; +int32 l = lvl - IPL_HMIN; + +for (i = 0; int_req[l] && (i < 32); i++) { + if ((int_req[l] >> i) & 1) { + int_req[l] = int_req[l] & ~(1u << i); + if (int_ack[l][i]) return int_ack[l][i](); + return int_vec[l][i]; } } +return 0; +} + +/* CQBIC registers + + SCR system configuration register + DSER DMA system error register (W1C) + MEAR master error address register (RO) + SEAR slave error address register (RO) + MBR map base register + IPC inter-processor communication register +*/ + +int32 cqbic_rd (int32 pa) +{ +int32 rg = (pa - CQBICBASE) >> 2; + +switch (rg) { +case 0: /* SCR */ + return (cq_scr | CQSCR_POK) & CQSCR_MASK; +case 1: /* DSER */ + return cq_dser & CQDSER_MASK; +case 2: /* MEAR */ + return cq_mear & CQMEAR_MASK; +case 3: /* SEAR */ + return cq_sear & CQSEAR_MASK; +case 4: /* MBR */ + return cq_mbr & CQMBR_MASK; } +return 0; +} + +void cqbic_wr (int32 pa, int32 val, int32 lnt) +{ +int32 nval, rg = (pa - CQBICBASE) >> 2; + +if (lnt < L_LONG) { + int32 sc = (pa & 3) << 3; + int32 mask = (lnt == L_WORD)? 0xFFFF: 0xFF; + int32 t = cqbic_rd (pa); + nval = ((val & mask) << sc) | (t & ~(mask << sc)); + val = val << sc; } +else nval = val; + +switch (rg) { +case 0: /* SCR */ + cq_scr = ((cq_scr & ~CQSCR_RW) | (nval & CQSCR_RW)) & CQSCR_MASK; + break; +case 1: /* DSER */ + cq_dser = (cq_dser & ~val) & CQDSER_MASK; + if (val & CQDSER_SME) cq_ipc = cq_ipc & ~CQIPC_QME; + break; +case 2: case 3: + cq_merr (pa); /* MEAR, SEAR */ + MACH_CHECK (MCHK_WRITE); + break; +case 4: /* MBR */ + cq_mbr = nval & CQMBR_MASK; + break; } +return; +} + +/* IPC can be read as local register or as Qbus I/O + Because of the W1C */ + +int32 cqipc_rd (int32 pa) +{ +return cq_ipc & CQIPC_MASK; /* IPC */ +} + +void cqipc_wr (int32 pa, int32 val, int32 lnt) +{ +int32 nval = val; + +if (lnt < L_LONG) { + int32 sc = (pa & 3) << 3; + nval = val << sc; } + +cq_ipc = cq_ipc & ~(nval & CQIPC_W1C); /* W1C */ +if ((pa & 3) == 0) /* low byte only */ + cq_ipc = ((cq_ipc & ~CQIPC_RW) | (val & CQIPC_RW)) & CQIPC_MASK; +return; +} + +/* I/O page routines */ + +t_stat dbl_rd (int32 *data, int32 addr, int32 access) +{ +*data = cq_ipc & CQIPC_MASK; +return SCPE_OK; +} + +t_stat dbl_wr (int32 data, int32 addr, int32 access) +{ +cqipc_wr (addr, data, (access == WRITEB)? L_BYTE: L_WORD); +return SCPE_OK; +} + +/* CQBIC map read and write (reflects to main memory) + + Read error: set DSER<0>, latch slave address, machine check + Write error: set DSER<0>, latch slave address, memory error interrupt +*/ + +int32 cqmap_rd (int32 pa) +{ +int32 ma = (pa & CQMAPAMASK) + cq_mbr; /* mem addr */ + +if (ADDR_IS_MEM (ma)) return M[ma >> 2]; +cq_serr (ma); /* set err */ +MACH_CHECK (MCHK_READ); /* mcheck */ +return 0; +} + +void cqmap_wr (int32 pa, int32 val, int32 lnt) +{ +int32 ma = (pa & CQMAPAMASK) + cq_mbr; /* mem addr */ + +if (ADDR_IS_MEM (ma)) { + if (lnt < L_LONG) { + int32 sc = (pa & 3) << 3; + int32 mask = (lnt == L_WORD)? 0xFFFF: 0xFF; + int32 t = M[ma >> 2]; + val = ((val & mask) << sc) | (t & ~(mask << sc)); } + M[ma >> 2] = val; } +else { cq_serr (ma); /* error */ + mem_err = 1; } +return; +} + +/* CQBIC Qbus memory read and write (reflects to main memory) + + May give master or slave error, depending on where the failure occurs +*/ + +int32 cqmem_rd (int32 pa) +{ +int32 qa = pa & CQMAMASK; /* Qbus addr */ +t_addr ma; + +if (map_addr (qa, &ma)) return M[ma >> 2]; /* map addr */ +MACH_CHECK (MCHK_READ); /* err? mcheck */ +return 0; +} + +void cqmem_wr (int32 pa, int32 val, int32 lnt) +{ +int32 qa = pa & CQMAMASK; /* Qbus addr */ +t_addr ma; + +if (map_addr (qa, &ma)) { /* map addr */ + if (lnt < L_LONG) { + int32 sc = (pa & 3) << 3; + int32 mask = (lnt == L_WORD)? 0xFFFF: 0xFF; + int32 t = M[ma >> 2]; + val = ((val & mask) << sc) | (t & ~(mask << sc)); } + M[ma >> 2] = val; } +else mem_err = 1; +return; +} + +/* Map an address via the translation map */ + +t_bool map_addr (t_addr qa, t_addr *ma) +{ +int32 qblk = (qa >> VA_V_VPN); /* Qbus blk */ +int32 qmma = ((qblk << 2) & CQMAPAMASK) + cq_mbr; /* map entry */ + +if (ADDR_IS_MEM (qmma)) { /* legit? */ + int32 qmap = M[qmma >> 2]; /* get map */ + if (qmap & CQMAP_VLD) { /* valid? */ + *ma = ((qmap & CQMAP_PAG) << VA_V_VPN) + VA_GETOFF (qa); + if (ADDR_IS_MEM (*ma)) return 1; /* legit addr */ + cq_serr (*ma); /* slave nxm */ + return 0; } + cq_merr (qa); /* master nxm */ + return 0; } +cq_serr (0); /* inv mem */ +return 0; +} + +/* Set master error */ + +void cq_merr (int32 pa) +{ +if (cq_dser & CQDSER_ERR) cq_dser = cq_dser | CQDSER_LST; +cq_dser = cq_dser | CQDSER_MNX; /* master nxm */ +cq_mear = (pa >> VA_V_VPN) & CQMEAR_MASK; /* page addr */ +return; +} + +/* Set slave error */ + +void cq_serr (int32 pa) +{ +if (cq_dser & CQDSER_ERR) cq_dser = cq_dser | CQDSER_LST; +cq_dser = cq_dser | CQDSER_SNX; /* slave nxm */ +cq_sear = (pa >> VA_V_VPN) & CQSEAR_MASK; +return; +} + +/* Reset I/O bus */ + +void ioreset_wr (int32 data) +{ +reset_all (5); /* from qba on... */ +return; +} + +/* Reset CQBIC */ + +t_stat qba_reset (DEVICE *dptr) +{ +int32 i; + +cq_scr = (cq_scr & CQSCR_BHL) | CQSCR_POK; +cq_dser = cq_mear = cq_sear = cq_ipc = 0; +for (i = 0; i < IPL_HLVL; i++) int_req[i] = 0; +return SCPE_OK; +} + +/* Powerup CQBIC */ + +t_stat qba_powerup (void) +{ +cq_mbr = 0; +cq_scr = CQSCR_POK; +return qba_reset (&qba_dev); +} + +/* I/O buffer routines, aligned access + + map_ReadB - fetch byte buffer from memory + map_ReadW - fetch word buffer from memory + map_ReadL - fetch longword buffer from memory + map_WriteB - store byte buffer into memory + map_WriteW - store word buffer into memory + map_WriteL - store longword buffer into memory +*/ + +int32 map_readB (t_addr ba, int32 bc, uint8 *buf) +{ +int32 i; +t_addr ma; + +for (i = ma = 0; i < bc; i++, buf++) { /* by bytes */ + if ((ma & VA_M_OFF) == 0) { /* need map? */ + if (!map_addr (ba + i, &ma) || /* inv or NXM? */ + !ADDR_IS_MEM (ma)) return (bc - i); } + *buf = ReadB (ma); + ma = ma + 1; } +return 0; +} + +int32 map_readW (t_addr ba, int32 bc, uint16 *buf) +{ +int32 i; +t_addr ma; + +ba = ba & ~01; +bc = bc & ~01; +for (i = ma = 0; i < bc; i = i + 2, buf++) { /* by words */ + if ((ma & VA_M_OFF) == 0) { /* need map? */ + if (!map_addr (ba + i, &ma) || /* inv or NXM? */ + !ADDR_IS_MEM (ma)) return (bc - i); } + *buf = ReadW (ma); + ma = ma + 2; } +return 0; +} + +int32 map_readL (t_addr ba, int32 bc, uint32 *buf) +{ +int32 i; +t_addr ma; + +ba = ba & ~03; +bc = bc & ~03; +for (i = ma = 0; i < bc; i = i + 4, buf++) { /* by lw */ + if ((ma & VA_M_OFF) == 0) { /* need map? */ + if (!map_addr (ba + i, &ma) || /* inv or NXM? */ + !ADDR_IS_MEM (ma)) return (bc - i); } + *buf = ReadL (ma); + ma = ma + 4; } +return 0; +} + +int32 map_writeB (t_addr ba, int32 bc, uint8 *buf) +{ +int32 i; +t_addr ma; + +for (i = ma = 0; i < bc; i++, buf++) { /* by bytes */ + if ((ma & VA_M_OFF) == 0) { /* need map? */ + if (!map_addr (ba + i, &ma) || /* inv or NXM? */ + !ADDR_IS_MEM (ma)) return (bc - i); } + WriteB (ma, *buf); + ma = ma + 1; } +return 0; +} + +int32 map_writeW (t_addr ba, int32 bc, uint16 *buf) +{ +int32 i; +t_addr ma; + +ba = ba & ~01; +bc = bc & ~01; +for (i = ma = 0; i < bc; i = i + 2, buf++) { /* by words */ + if ((ma & VA_M_OFF) == 0) { /* need map? */ + if (!map_addr (ba + i, &ma) || /* inv or NXM? */ + !ADDR_IS_MEM (ma)) return (bc - i); } + WriteW (ma, *buf); + ma = ma + 2; } +return 0; +} + +int32 map_writeL (t_addr ba, int32 bc, uint32 *buf) +{ +int32 i; +t_addr ma; + +ba = ba & ~03; +bc = bc & ~03; +for (i = ma = 0; i < bc; i = i + 4, buf++) { /* by lw */ + if ((ma & VA_M_OFF) == 0) { /* need map? */ + if (!map_addr (ba + i, &ma) || /* inv or NXM? */ + !ADDR_IS_MEM (ma)) return (bc - i); } + WriteL (ma, *buf); + ma = ma + 4; } +return 0; +} + +/* Change device number for a device */ + +t_stat set_addr (UNIT *uptr, int32 val, char *cptr, void *desc) +{ +DIB *dibp; +uint32 newba; +t_stat r; + +if (cptr == NULL) return SCPE_ARG; +if ((val == 0) || (desc == NULL)) return SCPE_IERR; +dibp = (DIB *) desc; +newba = (uint32) get_uint (cptr, 16, IOPAGEBASE+IOPAGEMASK, &r); /* get new */ +if ((r != SCPE_OK) || (newba == dibp -> ba)) return r; +if (newba <= IOPAGEBASE) return SCPE_ARG; /* must be > 0 */ +if (newba % ((uint32) val)) return SCPE_ARG; /* check modulus */ +if (dev_conflict (newba, dibp)) return SCPE_OK; +dibp -> ba = newba; /* store */ +return SCPE_OK; +} + +/* Show device address */ + +t_stat show_addr (FILE *st, UNIT *uptr, int32 val, void *desc) +{ +DIB *dibp; + +if (desc == NULL) return SCPE_IERR; +dibp = (DIB *) desc; +if (dibp -> ba <= IOPAGEBASE) return SCPE_IERR; +fprintf (st, "address=%08X", dibp -> ba); +if (dibp -> lnt > 1) + fprintf (st, "-%08X", dibp -> ba + dibp -> lnt - 1); +return SCPE_OK; +} + +/* Enable or disable a device */ + +t_stat set_enbdis (UNIT *uptr, int32 val, char *cptr, void *desc) +{ +int32 i; +DEVICE *dptr; +DIB *dibp; +UNIT *up; + +if (cptr != NULL) return SCPE_ARG; +if ((uptr == NULL) || (desc == NULL)) return SCPE_IERR; +dptr = find_dev_from_unit (uptr); /* find device */ +if (dptr == NULL) return SCPE_IERR; +dibp = (DIB *) desc; +if ((val ^ dibp -> enb) == 0) return SCPE_OK; /* enable chg? */ +if (val) { /* enable? */ + if (dev_conflict (dibp -> ba, dibp)) return SCPE_OK; } +else { /* disable */ + for (i = 0; i < dptr -> numunits; i++) { /* check units */ + up = (dptr -> units) + i; + if ((up -> flags & UNIT_ATT) || sim_is_active (up)) + return SCPE_NOFNC; } } +dibp -> enb = val; +if (dptr -> reset) return dptr -> reset (dptr); +else return SCPE_OK; +} + +/* Test for conflict in device addresses */ + +t_bool dev_conflict (uint32 nba, DIB *curr) +{ +uint32 i, end; +DIB *dibp; + +end = nba + curr -> lnt - 1; /* get end */ +for (i = 0; dibp = dib_tab[i]; i++) { /* loop thru dev */ + if (!dibp -> enb || (dibp == curr)) continue; /* skip disabled */ + if (((nba >= dibp -> ba) && + (nba < (dibp -> ba + dibp -> lnt))) || + ((end >= dibp -> ba) && + (end < (dibp -> ba + dibp -> lnt)))) { + printf ("Device address conflict at %08X\n", dibp -> ba); + if (sim_log) fprintf (sim_log, + "Device number conflict at %08X\n", dibp -> ba); + return TRUE; } } +return FALSE; +} diff --git a/VAX/vax_mmu.c b/VAX/vax_mmu.c new file mode 100644 index 00000000..d27b522a --- /dev/null +++ b/VAX/vax_mmu.c @@ -0,0 +1,534 @@ +/* vax_mm.c - VAX memory management simulator + + Copyright (c) 1998-2002, Robert M Supnik + + Permission is hereby granted, free of charge, to any person obtaining a + copy of this software and associated documentation files (the "Software"), + to deal in the Software without restriction, including without limitation + the rights to use, copy, modify, merge, publish, distribute, sublicense, + and/or sell copies of the Software, and to permit persons to whom the + Software is furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + ROBERT M SUPNIK BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + Except as contained in this notice, the name of Robert M Supnik shall not + be used in advertising or otherwise to promote the sale, use or other dealings + in this Software without prior written authorization from Robert M Supnik. + + This module contains the instruction simulators for + + Read - read virtual + Write - write virtual + ReadL(P) - read aligned physical longword (physical context) + WriteL(P) - write aligned physical longword (physical context) + ReadB(W) - read aligned physical byte (word) + WriteB(W) - write aligned physical byte (word) + Test - test acccess + + zap_tb - clear TB + zap_tb_ent - clear TB entry + chk_tb_ent - check TB entry + set_map_reg - set up working map registers +*/ + +#include "vax_defs.h" +#include + +struct tlbent { + int32 tag; /* tag */ + int32 pte; /* pte */ +}; + +typedef struct tlbent TLBENT; + +extern uint32 *M; +extern uint32 align[4]; +extern int32 PSL; +extern int32 mapen; +extern int32 p1, p2; +extern int32 P0BR, P0LR; +extern int32 P1BR, P1LR; +extern int32 SBR, SLR; +extern int32 SISR; +extern jmp_buf save_env; +extern UNIT cpu_unit; + +int32 p0br, p0lr; /* dynamic copies */ +int32 p1br, p1lr; /* altered per ucode */ +int32 sbr, slr; +extern int32 mchk_va, mchk_ref; /* for mcheck */ +TLBENT stlb[VA_TBSIZE], ptlb[VA_TBSIZE]; +static const int32 insert[4] = { + 0x00000000, 0x000000FF, 0x0000FFFF, 0x00FFFFFF }; +static const int32 cvtacc[16] = { 0, 0, + TLB_ACCW (KERN)+TLB_ACCR (KERN), + TLB_ACCR (KERN), + TLB_ACCW (KERN)+TLB_ACCW (EXEC)+TLB_ACCW (SUPV)+TLB_ACCW (USER)+ + TLB_ACCR (KERN)+TLB_ACCR (EXEC)+TLB_ACCR (SUPV)+TLB_ACCR (USER), + TLB_ACCW (KERN)+TLB_ACCW (EXEC)+TLB_ACCR (KERN)+TLB_ACCR (EXEC), + TLB_ACCW (KERN)+TLB_ACCR (KERN)+TLB_ACCR (EXEC), + TLB_ACCR (KERN)+TLB_ACCR (EXEC), + TLB_ACCW (KERN)+TLB_ACCW (EXEC)+TLB_ACCW (SUPV)+ + TLB_ACCR (KERN)+TLB_ACCR (EXEC)+TLB_ACCR (SUPV), + TLB_ACCW (KERN)+TLB_ACCW (EXEC)+ + TLB_ACCR (KERN)+TLB_ACCR (EXEC)+TLB_ACCR (SUPV), + TLB_ACCW (KERN)+TLB_ACCR (KERN)+TLB_ACCR (EXEC)+TLB_ACCR (SUPV), + TLB_ACCR (KERN)+TLB_ACCR (EXEC)+TLB_ACCR (SUPV), + TLB_ACCW (KERN)+TLB_ACCW (EXEC)+TLB_ACCW (SUPV)+ + TLB_ACCR (KERN)+TLB_ACCR (EXEC)+TLB_ACCR (SUPV)+TLB_ACCR (USER), + TLB_ACCW (KERN)+TLB_ACCW (EXEC)+ + TLB_ACCR (KERN)+TLB_ACCR (EXEC)+TLB_ACCR (SUPV)+TLB_ACCR (USER), + TLB_ACCW (KERN)+ + TLB_ACCR (KERN)+TLB_ACCR (EXEC)+TLB_ACCR (SUPV)+TLB_ACCR (USER), + TLB_ACCR (KERN)+TLB_ACCR (EXEC)+TLB_ACCR (SUPV)+TLB_ACCR (USER) +}; + +t_stat tlb_ex (t_value *vptr, t_addr addr, UNIT *uptr, int32 sw); +t_stat tlb_dep (t_value val, t_addr addr, UNIT *uptr, int32 sw); +t_stat tlb_reset (DEVICE *dptr); + +TLBENT fill (t_addr va, int32 lnt, int32 acc, int32 *stat); +int32 ReadB (t_addr pa); +void WriteB (t_addr pa, int32 val); +int32 ReadW (t_addr pa); +void WriteW (t_addr pa, int32 val); +int32 ReadL (t_addr pa); +void WriteL (t_addr pa, int32 val); +int32 ReadLP (t_addr pa); +void WriteLP (t_addr pa, int32 val); +extern int32 ReadIO (t_addr pa, int32 lnt); +extern void WriteIO (t_addr pa, int32 val, int32 lnt); +extern int32 ReadReg (t_addr pa, int32 lnt); +extern void WriteReg (t_addr pa, int32 val, int32 lnt); + +/* TLB data structures + + tlb_dev pager device descriptor + tlb_unit pager units + pager_reg pager register list +*/ + +UNIT tlb_unit[] = { + { UDATA (NULL, UNIT_FIX, VA_TBSIZE * 2) }, + { UDATA (NULL, UNIT_FIX, VA_TBSIZE * 2) } }; + +REG tlb_reg[] = { + { NULL } }; + +DEVICE tlb_dev = { + "TLB", tlb_unit, tlb_reg, NULL, + 2, 16, VA_N_TBI * 2, 1, 16, 32, + &tlb_ex, &tlb_dep, &tlb_reset, + NULL, NULL, NULL }; + +/* Read and write virtual + + These routines logically fall into three phases: + + 1. Look up the virtual address in the translation buffer, calling + the fill routine on a tag mismatch or access mismatch (invalid + tlb entries have access = 0 and thus always mismatch). The + fill routine handles all errors. If the resulting physical + address is aligned, do an aligned physical read or write. + 2. Test for unaligned across page boundaries. If cross page, look + up the physical address of the second page. If not cross page, + the second physical address is the same as the first. + 3. Using the two physical addresses, do an unaligned read or + write, with three cases: unaligned long, unaligned word within + a longword, unaligned word crossing a longword boundary. +*/ + +/* Read virtual + + Inputs: + va = virtual address + lnt = length code (BWLQ) + acc = access code (KESU) + Output: + returned data, right justified in 32b longword +*/ + +int32 Read (t_addr va, int32 lnt, int32 acc) +{ +int32 vpn, off, tbi, pa; +int32 pa1, bo, sc, wl, wh; +TLBENT xpte; + +mchk_va = va; +if (mapen) { /* mapping on? */ + vpn = VA_GETVPN (va); /* get vpn, offset */ + off = VA_GETOFF (va); + tbi = VA_GETTBI (vpn); + xpte = (va & VA_S0)? stlb[tbi]: ptlb[tbi]; /* access tlb */ + if (((xpte.pte & acc) == 0) || (xpte.tag != vpn) || + ((acc & TLB_WACC) && ((xpte.pte & TLB_M) == 0))) + xpte = fill (va, lnt, acc, NULL); /* fill if needed */ + pa = (xpte.pte & TLB_PFN) | off; } /* get phys addr */ +else pa = va & PAMASK; +if ((pa & (lnt - 1)) == 0) { /* aligned? */ + if (lnt >= L_LONG) return ReadL (pa); /* long, quad? */ + if (lnt == L_WORD) return ReadW (pa); /* word? */ + return ReadB (pa); } /* byte */ +if (mapen && ((off + lnt) > VA_PAGSIZE)) { /* cross page? */ + vpn = VA_GETVPN (va + lnt); /* vpn 2nd page */ + tbi = VA_GETTBI (vpn); + xpte = (va & VA_S0)? stlb[tbi]: ptlb[tbi]; /* access tlb */ + if (((xpte.pte & acc) == 0) || (xpte.tag != vpn) || + ((acc & TLB_WACC) && ((xpte.pte & TLB_M) == 0))) + xpte = fill (va + lnt, lnt, acc, NULL); /* fill if needed */ + pa1 = (xpte.pte & TLB_PFN) | VA_GETOFF (va + 4); } +else pa1 = (pa + 4) & PAMASK; /* not cross page */ +bo = pa & 3; +if (lnt >= L_LONG) { /* lw unaligned? */ + sc = bo << 3; + wl = ReadL (pa); /* read both lw */ + wh = ReadL (pa1); /* extract */ + return (((wl >> sc) & align[bo]) | (wh << (32 - sc))); } +else if (bo == 1) return ((ReadL (pa) >> 8) & WMASK); +else { wl = ReadL (pa); /* word cross lw */ + wh = ReadL (pa1); /* read, extract */ + return (((wl >> 24) & 0xFF) | ((wh & 0xFF) << 8)); } +} + +/* Write virtual + + Inputs: + va = virtual address + val = data to be written, right justified in 32b lw + lnt = length code (BWLQ) + acc = access code (KESU) + Output: + none +*/ + +void Write (t_addr va, int32 val, int32 lnt, int32 acc) +{ +int32 vpn, off, tbi, pa; +int32 pa1, bo, sc, wl, wh; +TLBENT xpte; + +mchk_va = va; +if (mapen) { + vpn = VA_GETVPN (va); + off = VA_GETOFF (va); + tbi = VA_GETTBI (vpn); + xpte = (va & VA_S0)? stlb[tbi]: ptlb[tbi]; /* access tlb */ + if (((xpte.pte & acc) == 0) || (xpte.tag != vpn) || + ((xpte.pte & TLB_M) == 0)) xpte = fill (va, lnt, acc, NULL); + pa = (xpte.pte & TLB_PFN) | off; } +else pa = va & PAMASK; +if ((pa & (lnt - 1)) == 0) { /* aligned? */ + if (lnt >= L_LONG) WriteL (pa, val); /* long, quad? */ + else if (lnt == L_WORD) WriteW (pa, val); /* word? */ + else WriteB (pa, val); /* byte */ + return; } +if (mapen && ((off + lnt) > VA_PAGSIZE)) { + vpn = VA_GETVPN (va + 4); + tbi = VA_GETTBI (vpn); + xpte = (va & VA_S0)? stlb[tbi]: ptlb[tbi]; /* access tlb */ + if (((xpte.pte & acc) == 0) || (xpte.tag != vpn) || + ((xpte.pte & TLB_M) == 0)) + xpte = fill (va + lnt, lnt, acc, NULL); + pa1 = (xpte.pte & TLB_PFN) | VA_GETOFF (va + 4); } +else pa1 = (pa + 4) & PAMASK; +bo = pa & 3; +wl = ReadL (pa); +if (lnt >= L_LONG) { + sc = bo << 3; + wh = ReadL (pa1); + wl = (wl & insert[bo]) | (val << sc); + wh = (wh & ~insert[bo]) | ((val >> (32 - sc)) & insert[bo]); + WriteL (pa, wl); + WriteL (pa1, wh); } +else if (bo == 1) { + wl = (wl & 0xFF0000FF) | (val << 8); + WriteL (pa, wl); } +else { wh = ReadL (pa1); + wl = (wl & 0x00FFFFFF) | (val << 24); + wh = (wh & 0xFFFFFF00) | ((val >> 8) & 0xFF); + WriteL (pa, wl); + WriteL (pa1, wh); } +return; +} + +/* Test access to a byte (VAX PROBEx) */ + +int32 Test (int32 va, int32 acc, int32 *status) +{ +int32 vpn, off, tbi; +TLBENT xpte; + +*status = PR_OK; /* assume ok */ +if (mapen) { /* mapping on? */ + vpn = VA_GETVPN (va); /* get vpn, off */ + off = VA_GETOFF (va); + tbi = VA_GETTBI (vpn); + xpte = (va & VA_S0)? stlb[tbi]: ptlb[tbi]; /* access tlb */ + if ((xpte.pte & acc) && (xpte.tag == vpn)) /* TB hit, acc ok? */ + return (xpte.pte & TLB_PFN) | off; + xpte = fill (va, L_BYTE, acc, status); /* fill TB */ + if (*status == PR_OK) return (xpte.pte & TLB_PFN) | off; + else return -1; } +return va & PAMASK; /* ret phys addr */ +} + +/* Read aligned physical (in virtual context, unless indicated) + + Inputs: + pa = physical address, naturally aligned + Output: + returned data, right justified in 32b longword +*/ + +int32 ReadB (t_addr pa) +{ +int32 dat; + +if (ADDR_IS_MEM (pa)) dat = M[pa >> 2]; +else { mchk_ref = REF_V; + if (ADDR_IS_IO (pa)) dat = ReadIO (pa, L_BYTE); + else dat = ReadReg (pa, L_BYTE); } +return ((dat >> ((pa & 3) << 3)) & BMASK); +} + +int32 ReadW (t_addr pa) +{ +int32 dat; + +if (ADDR_IS_MEM (pa)) dat = M[pa >> 2]; +else { mchk_ref = REF_V; + if (ADDR_IS_IO (pa)) dat = ReadIO (pa, L_WORD); + else dat = ReadReg (pa, L_WORD); } +return ((dat >> ((pa & 2)? 16: 0)) & WMASK); +} + +int32 ReadL (t_addr pa) +{ +if (ADDR_IS_MEM (pa)) return M[pa >> 2]; +mchk_ref = REF_V; +if (ADDR_IS_IO (pa)) return ReadIO (pa, L_LONG); +return ReadReg (pa, L_LONG); +} + +int32 ReadLP (t_addr pa) +{ +if (ADDR_IS_MEM (pa)) return M[pa >> 2]; +mchk_va = pa; +mchk_ref = REF_P; +if (ADDR_IS_IO (pa)) return ReadIO (pa, L_LONG); +return ReadReg (pa, L_LONG); +} + +/* Write aligned physical (in virtual context, unless indicated) + + Inputs: + pa = physical address, naturally aligned + val = data to be written, right justified in 32b longword + Output: + none +*/ + +void WriteB (t_addr pa, int32 val) +{ +if (ADDR_IS_MEM (pa)) { + int32 id = pa >> 2; + int32 sc = (pa & 3) << 3; + int32 mask = 0xFF << sc; + M[id] = (M[id] & ~mask) | (val << sc); } +else { mchk_ref = REF_V; + if (ADDR_IS_IO (pa)) WriteIO (pa, val, L_BYTE); + else WriteReg (pa, val, L_BYTE); } +return; +} + +void WriteW (t_addr pa, int32 val) +{ +if (ADDR_IS_MEM (pa)) { + int32 id = pa >> 2; + M[id] = (pa & 2)? (M[id] & 0xFFFF) | (val << 16): + (M[id] & ~0xFFFF) | val; } +else { mchk_ref = REF_V; + if (ADDR_IS_IO (pa)) WriteIO (pa, val, L_WORD); + else WriteReg (pa, val, L_WORD); } +return; +} + +void WriteL (t_addr pa, int32 val) +{ +if (ADDR_IS_MEM (pa)) M[pa >> 2] = val; +else { mchk_ref = REF_V; + if (ADDR_IS_IO (pa)) WriteIO (pa, val, L_LONG); + else WriteReg (pa, val, L_LONG); } +return; +} + +void WriteLP (t_addr pa, int32 val) +{ +if (ADDR_IS_MEM (pa)) M[pa >> 2] = val; +else { mchk_va = pa; + mchk_ref = REF_P; + if (ADDR_IS_IO (pa)) WriteIO (pa, val, L_LONG); + else WriteReg (pa, val, L_LONG); } +return; +} + +/* TLB fill + + This routine fills the TLB after a tag or access mismatch, or + on a write if pte = 0. It fills the TLB and returns the + pte to the caller. On an error, it aborts directly to the + fault handler in the CPU. + + If called from map (VAX PROBEx), the error status is returned + to the caller, and no fault occurs. +*/ + +#define MM_ERR(param) { \ + if (stat) { *stat = param; return zero_pte; } \ + p1 = MM_PARAM (acc & TLB_WACC, param); \ + p2 = va; \ + ABORT ((param & PR_TNV)? ABORT_TNV: ABORT_ACV); } + +TLBENT fill (t_addr va, int32 lnt, int32 acc, int32 *stat) +{ +int32 ptidx = (((uint32) va) >> 7) & ~03; +int32 tlbpte, ptead, pte, tbi, vpn; +static TLBENT zero_pte = { 0, 0 }; + +if (va & VA_S0) { /* system space? */ + if (ptidx >= slr) MM_ERR (PR_LNV); /* system */ + ptead = sbr + ptidx; } +else { if (va & VA_P1) { /* P1? */ + if (ptidx < p1lr) MM_ERR (PR_LNV); + ptead = p1br + ptidx; } + else { if (ptidx >= p0lr) + MM_ERR (PR_LNV); /* P0 */ + ptead = p0br + ptidx; } + if ((ptead & VA_S0) == 0) + ABORT (STOP_PPTE); /* ppte must be sys */ + vpn = VA_GETVPN (ptead); /* get vpn, tbi */ + tbi = VA_GETTBI (vpn); + if (stlb[tbi].tag != vpn) { /* in sys tlb? */ + ptidx = ((uint32) ptead) >> 7; /* xlate like sys */ + if (ptidx >= slr) MM_ERR (PR_PLNV); + pte = ReadLP (sbr + ptidx); /* get system pte */ + if ((pte & PTE_V) == 0) MM_ERR (PR_PTNV); /* spte TNV? */ + stlb[tbi].tag = vpn; /* set stlb tag */ + stlb[tbi].pte = cvtacc[PTE_GETACC (pte)] | + ((pte << VA_N_OFF) & TLB_PFN); } /* set stlb data */ + ptead = (stlb[tbi].pte & TLB_PFN) | VA_GETOFF (ptead); } +pte = ReadL (ptead); /* read pte */ +tlbpte = cvtacc[PTE_GETACC (pte)] | /* cvt access */ + ((pte << VA_N_OFF) & TLB_PFN); /* set addr */ +if ((tlbpte & acc) == 0) MM_ERR (PR_ACV); /* chk access */ +if ((pte & PTE_V) == 0) MM_ERR (PR_TNV); /* check valid */ +if (acc & TLB_WACC) { /* write? */ + if ((pte & PTE_M) == 0) WriteL (ptead, pte | PTE_M); + tlbpte = tlbpte | TLB_M; } /* set M */ +vpn = VA_GETVPN (va); +tbi = VA_GETTBI (vpn); +if ((va & VA_S0) == 0) { /* process space? */ + ptlb[tbi].tag = vpn; /* store tlb ent */ + ptlb[tbi].pte = tlbpte; + return ptlb[tbi]; } +stlb[tbi].tag = vpn; /* system space */ +stlb[tbi].pte = tlbpte; /* store tlb ent */ +return stlb[tbi]; +} + +/* Utility routines */ + +extern void set_map_reg (void) +{ +p0br = P0BR & ~03; +p1br = (P1BR - 0x800000) & ~03; /* VA<30> >> 7 */ +sbr = (SBR - 0x1000000) & ~03; /* VA<31> >> 7 */ +p0lr = (P0LR << 2); +p1lr = (P1LR << 2) + 0x800000; /* VA<30> >> 7 */ +slr = (SLR << 2) + 0x1000000; /* VA<31> >> 7 */ +return; +} + +/* Zap process (0) or whole (1) tb */ + +void zap_tb (int stb) +{ +int32 i; + +for (i = 0; i < VA_TBSIZE; i++) { + ptlb[i].tag = ptlb[i].pte = -1; + if (stb) stlb[i].tag = stlb[i].pte = -1; } +return; +} + +/* Zap single tb entry corresponding to va */ + +void zap_tb_ent (int32 va) +{ +int32 tbi = VA_GETTBI (VA_GETVPN (va)); + +if (va & VA_S0) stlb[tbi].tag = stlb[tbi].pte = -1; +else ptlb[tbi].tag = ptlb[tbi].pte = -1; +return; +} + +/* Check for tlb entry corresponding to va */ + +t_bool chk_tb_ent (int32 va) +{ +int32 vpn = VA_GETVPN (va); +int32 tbi = VA_GETTBI (vpn); +TLBENT xpte; + +xpte = (va & VA_S0)? stlb[tbi]: ptlb[tbi]; +if (xpte.tag == vpn) return TRUE; +return FALSE; +} + +/* TLB examine */ + +t_stat tlb_ex (t_value *vptr, t_addr addr, UNIT *uptr, int32 sw) +{ +int32 tlbn = uptr - tlb_unit; +int32 idx = addr >> 1; + +if (idx >= VA_TBSIZE) return SCPE_NXM; +if (addr & 1) *vptr = ((uint32) (tlbn? stlb[idx].pte: ptlb[idx].pte)); +else *vptr = ((uint32) (tlbn? stlb[idx].tag: ptlb[idx].tag)); +return SCPE_OK; +} + +/* TLB deposit */ + +t_stat tlb_dep (t_value val, t_addr addr, UNIT *uptr, int32 sw) +{ +int32 tlbn = uptr - tlb_unit; +int32 idx = addr >> 1; + +if (idx >= VA_TBSIZE) return SCPE_NXM; +if (addr & 1) { + if (tlbn) stlb[idx].pte = (int32) val; + else ptlb[idx].pte = (int32) val; } +else { if (tlbn) stlb[idx].tag = (int32) val; + else ptlb[idx].tag = (int32) val; } +return SCPE_OK; +} + +/* TLB reset */ + +t_stat tlb_reset (DEVICE *dptr) +{ +int32 i; + +for (i = 0; i < VA_TBSIZE; i++) + stlb[i].tag = ptlb[i].tag = stlb[i].pte = ptlb[i].pte = -1; +return SCPE_OK; +} diff --git a/VAX/vax_stddev.c b/VAX/vax_stddev.c new file mode 100644 index 00000000..e4c976d1 --- /dev/null +++ b/VAX/vax_stddev.c @@ -0,0 +1,589 @@ +/* vax_stddev.c: VAX standard I/O devices simulator + + Copyright (c) 1998-2002, Robert M Supnik + + Permission is hereby granted, free of charge, to any person obtaining a + copy of this software and associated documentation files (the "Software"), + to deal in the Software without restriction, including without limitation + the rights to use, copy, modify, merge, publish, distribute, sublicense, + and/or sell copies of the Software, and to permit persons to whom the + Software is furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + ROBERT M SUPNIK BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + Except as contained in this notice, the name of Robert M Supnik shall not + be used in advertising or otherwise to promote the sale, use or other dealings + in this Software without prior written authorization from Robert M Supnik. + + ptr paper tape reader + ptp paper tape punch + tti terminal input + tto terminal output + clk line frequency clock + + 30-May-02 RMS Widened POS to 32b + 30-Apr-02 RMS Automatically set TODR to VMS-correct value during boot +*/ + +#include "vax_defs.h" +#include + +#define PTRCSR_IMP (CSR_ERR+CSR_BUSY+CSR_DONE+CSR_IE) /* paper tape reader */ +#define PTRCSR_RW (CSR_IE) +#define PTPCSR_IMP (CSR_ERR + CSR_DONE + CSR_IE) /* paper tape punch */ +#define PTPCSR_RW (CSR_IE) +#define TTICSR_IMP (CSR_DONE + CSR_IE) /* terminal input */ +#define TTICSR_RW (CSR_IE) +#define TTOCSR_IMP (CSR_DONE + CSR_IE) /* terminal output */ +#define TTOCSR_RW (CSR_IE) +#define CLKCSR_IMP (CSR_IE) /* real-time clock */ +#define CLKCSR_RW (CSR_IE) +#define CLK_DELAY 5000 /* 100 Hz */ +#define TMXR_MULT 2 /* 50 Hz */ + +extern int32 int_req[IPL_HLVL]; +int32 ptr_csr = 0; /* control/status */ +int32 ptr_stopioe = 0; /* stop on error */ +int32 ptp_csr = 0; /* control/status */ +int32 ptp_stopioe = 0; /* stop on error */ +int32 tti_csr = 0; /* control/status */ +int32 tto_csr = 0; /* control/status */ +int32 clk_csr = 0; /* control/status */ +int32 clk_tps = 100; /* ticks/second */ +int32 todr_reg = 0; /* TODR register */ +int32 todr_blow = 1; /* TODR battery low */ +int32 tmxr_poll = CLK_DELAY * TMXR_MULT; /* term mux poll */ +int32 tmr_poll = CLK_DELAY; /* pgm timer poll */ + +t_stat pt_rd (int32 *data, int32 PA, int32 access); +t_stat pt_wr (int32 data, int32 PA, int32 access); +t_stat ptr_svc (UNIT *uptr); +t_stat ptp_svc (UNIT *uptr); +t_stat tti_svc (UNIT *uptr); +t_stat tto_svc (UNIT *uptr); +t_stat clk_svc (UNIT *uptr); +t_stat ptr_reset (DEVICE *dptr); +t_stat ptp_reset (DEVICE *dptr); +t_stat tti_reset (DEVICE *dptr); +t_stat tto_reset (DEVICE *dptr); +t_stat clk_reset (DEVICE *dptr); +t_stat ptr_attach (UNIT *uptr, char *ptr); +t_stat ptr_detach (UNIT *uptr); +t_stat ptp_attach (UNIT *uptr, char *ptr); +t_stat ptp_detach (UNIT *uptr); + +/* PTR data structures + + ptr_dev PTR device descriptor + ptr_unit PTR unit descriptor + ptr_reg PTR register list +*/ + +DIB pt_dib = { 1, IOBA_PT, IOLN_PT, &pt_rd, &pt_wr }; + +UNIT ptr_unit = { + UDATA (&ptr_svc, UNIT_SEQ+UNIT_ATTABLE+UNIT_ROABLE, 0), + SERIAL_IN_WAIT }; + +REG ptr_reg[] = { + { HRDATA (BUF, ptr_unit.buf, 8) }, + { HRDATA (CSR, ptr_csr, 16) }, + { FLDATA (INT, int_req[IPL_PTR], INT_V_PTR) }, + { FLDATA (ERR, ptr_csr, CSR_V_ERR) }, + { FLDATA (BUSY, ptr_csr, CSR_V_BUSY) }, + { FLDATA (DONE, ptr_csr, CSR_V_DONE) }, + { FLDATA (IE, ptr_csr, CSR_V_IE) }, + { DRDATA (POS, ptr_unit.pos, 32), PV_LEFT }, + { DRDATA (TIME, ptr_unit.wait, 24), PV_LEFT }, + { FLDATA (STOP_IOE, ptr_stopioe, 0) }, + { NULL } }; + +MTAB ptr_mod[] = { + { MTAB_XTD|MTAB_VDV, 0, "ADDRESS", NULL, + NULL, &show_addr, &pt_dib }, + { MTAB_XTD|MTAB_VDV, 1, NULL, "ENABLED", + &set_enbdis, NULL, &pt_dib }, + { MTAB_XTD|MTAB_VDV, 0, NULL, "DISABLED", + &set_enbdis, NULL, &pt_dib }, + { 0 } }; + +DEVICE ptr_dev = { + "PTR", &ptr_unit, ptr_reg, ptr_mod, + 1, 10, 31, 1, 16, 8, + NULL, NULL, &ptr_reset, + NULL, &ptr_attach, &ptr_detach }; + +/* PTP data structures + + ptp_dev PTP device descriptor + ptp_unit PTP unit descriptor + ptp_reg PTP register list +*/ + +UNIT ptp_unit = { + UDATA (&ptp_svc, UNIT_SEQ+UNIT_ATTABLE, 0), SERIAL_OUT_WAIT }; + +REG ptp_reg[] = { + { HRDATA (BUF, ptp_unit.buf, 8) }, + { HRDATA (CSR, ptp_csr, 16) }, + { FLDATA (INT, int_req[IPL_PTP], INT_V_PTP) }, + { FLDATA (ERR, ptp_csr, CSR_V_ERR) }, + { FLDATA (DONE, ptp_csr, CSR_V_DONE) }, + { FLDATA (IE, ptp_csr, CSR_V_IE) }, + { DRDATA (POS, ptp_unit.pos, 32), PV_LEFT }, + { DRDATA (TIME, ptp_unit.wait, 24), PV_LEFT }, + { FLDATA (STOP_IOE, ptp_stopioe, 0) }, + { NULL } }; + +MTAB ptp_mod[] = { + { MTAB_XTD|MTAB_VDV, 0, "ADDRESS", NULL, + NULL, &show_addr, &pt_dib }, + { MTAB_XTD|MTAB_VDV, 1, NULL, "ENABLED", + &set_enbdis, NULL, &pt_dib }, + { MTAB_XTD|MTAB_VDV, 0, NULL, "DISABLED", + &set_enbdis, NULL, &pt_dib }, + { 0 } }; + +DEVICE ptp_dev = { + "PTP", &ptp_unit, ptp_reg, ptp_mod, + 1, 10, 31, 1, 16, 8, + NULL, NULL, &ptp_reset, + NULL, &ptp_attach, &ptp_detach }; + +/* TTI data structures + + tti_dev TTI device descriptor + tti_unit TTI unit descriptor + tti_reg TTI register list +*/ + +UNIT tti_unit = { UDATA (&tti_svc, 0, 0), KBD_POLL_WAIT }; + +REG tti_reg[] = { + { HRDATA (BUF, tti_unit.buf, 8) }, + { HRDATA (CSR, tti_csr, 16) }, + { FLDATA (INT, int_req[IPL_TTI], INT_V_TTI) }, + { FLDATA (DONE, tti_csr, CSR_V_DONE) }, + { FLDATA (IE, tti_csr, CSR_V_IE) }, + { DRDATA (POS, tti_unit.pos, 32), PV_LEFT }, + { DRDATA (TIME, tti_unit.wait, 24), REG_NZ + PV_LEFT }, + { NULL } }; + +DEVICE tti_dev = { + "TTI", &tti_unit, tti_reg, NULL, + 1, 10, 31, 1, 16, 8, + NULL, NULL, &tti_reset, + NULL, NULL, NULL }; + +/* TTO data structures + + tto_dev TTO device descriptor + tto_unit TTO unit descriptor + tto_reg TTO register list +*/ + +UNIT tto_unit = { UDATA (&tto_svc, 0, 0), SERIAL_OUT_WAIT }; + +REG tto_reg[] = { + { HRDATA (BUF, tto_unit.buf, 8) }, + { HRDATA (CSR, tto_csr, 16) }, + { FLDATA (INT, int_req[IPL_TTO], INT_V_TTO) }, + { FLDATA (DONE, tto_csr, CSR_V_DONE) }, + { FLDATA (IE, tto_csr, CSR_V_IE) }, + { DRDATA (POS, tto_unit.pos, 32), PV_LEFT }, + { DRDATA (TIME, tto_unit.wait, 24), PV_LEFT }, + { NULL } }; + +DEVICE tto_dev = { + "TTO", &tto_unit, tto_reg, NULL, + 1, 10, 31, 1, 16, 8, + NULL, NULL, &tto_reset, + NULL, NULL, NULL }; + +/* CLK data structures + + clk_dev CLK device descriptor + clk_unit CLK unit descriptor + clk_reg CLK register list +*/ + +UNIT clk_unit = { UDATA (&clk_svc, 0, 0), CLK_DELAY }; + +REG clk_reg[] = { + { HRDATA (CSR, clk_csr, 16) }, + { FLDATA (INT, int_req[IPL_CLK], INT_V_CLK) }, + { FLDATA (IE, clk_csr, CSR_V_IE) }, + { DRDATA (TODR, todr_reg, 32), PV_LEFT }, + { FLDATA (BLOW, todr_blow, 0) }, + { DRDATA (TIME, clk_unit.wait, 24), REG_NZ + PV_LEFT }, + { DRDATA (TPS, clk_tps, 8), REG_NZ + PV_LEFT }, + { NULL } }; + +DEVICE clk_dev = { + "CLK", &clk_unit, clk_reg, NULL, + 1, 0, 0, 0, 0, 0, + NULL, NULL, &clk_reset, + NULL, NULL, NULL }; + +/* Paper tape I/O dispatch routine, I/O addresses 17777550-17777577 + + 17777550 ptr CSR + 17777552 ptr buffer + 17777554 ptp CSR + 17777556 ptp buffer + + Note: Word access routines filter out odd addresses. Thus, + an odd address implies an (odd) byte access. +*/ + +t_stat pt_rd (int32 *data, int32 PA, int32 access) +{ +switch ((PA >> 1) & 03) { /* decode PA<2:1> */ +case 00: /* ptr csr */ + *data = ptr_csr & PTRCSR_IMP; + break; +case 01: /* ptr buf */ + ptr_csr = ptr_csr & ~CSR_DONE; + CLR_INT (PTR); + *data = ptr_unit.buf & 0377; + break; +case 02: /* ptp csr */ + *data = ptp_csr & PTPCSR_IMP; + break; +case 03: /* ptp buf */ + *data = ptp_unit.buf; + break; } +return SCPE_OK; +} + +t_stat pt_wr (int32 data, int32 PA, int32 access) +{ +switch ((PA >> 1) & 03) { /* decode PA<2:1> */ +case 00: /* ptr csr */ + if (PA & 1) return SCPE_OK; + if ((data & CSR_IE) == 0) CLR_INT (PTR); + else if (((ptr_csr & CSR_IE) == 0) && (ptr_csr & (CSR_ERR | CSR_DONE))) + SET_INT (PTR); + if (data & CSR_GO) { + ptr_csr = (ptr_csr & ~CSR_DONE) | CSR_BUSY; + CLR_INT (PTR); + if (ptr_unit.flags & UNIT_ATT) /* data to read? */ + sim_activate (&ptr_unit, ptr_unit.wait); + else sim_activate (&ptr_unit, 0); } /* error if not */ + ptr_csr = (ptr_csr & ~PTRCSR_RW) | (data & PTRCSR_RW); + break; +case 01: /* ptr buf */ + break; +case 02: /* ptp csr */ + if (PA & 1) return SCPE_OK; + if ((data & CSR_IE) == 0) CLR_INT (PTP); + else if (((ptp_csr & CSR_IE) == 0) && (ptp_csr & (CSR_ERR | CSR_DONE))) + SET_INT (PTP); + ptp_csr = (ptp_csr & ~PTPCSR_RW) | (data & PTPCSR_RW); + break; +case 03: /* ptp buf */ + if ((PA & 1) == 0) ptp_unit.buf = data & 0377; + ptp_csr = ptp_csr & ~CSR_DONE; + CLR_INT (PTP); + if (ptp_unit.flags & UNIT_ATT) /* file to write? */ + sim_activate (&ptp_unit, ptp_unit.wait); + else sim_activate (&ptp_unit, 0); /* error if not */ + break; } /* end switch PA */ +return SCPE_OK; +} + +/* Clock and terminal MxPR routines + + iccs_rd/wr interval timer + todr_rd/wr time of year clock + rxcs_rd/wr input control/status + rxdb_rd input buffer + txcs_rd/wr output control/status + txdb_wr output buffer +*/ + +int32 iccs_rd (void) +{ +return (clk_csr & CLKCSR_IMP); +} + +int32 todr_rd (void) +{ +return todr_reg; +} + +int32 rxcs_rd (void) +{ +return (tti_csr & TTICSR_IMP); +} + +int32 rxdb_rd (void) +{ +tti_csr = tti_csr & ~CSR_DONE; +CLR_INT (TTI); +return (tti_unit.buf & 0377); +} + +int32 txcs_rd (void) +{ +return (tto_csr & TTOCSR_IMP); +} + +void iccs_wr (int32 data) +{ +if ((data & CSR_IE) == 0) CLR_INT (CLK); +clk_csr = (clk_csr & ~CLKCSR_RW) | (data & CLKCSR_RW); +return; +} + +void todr_wr (int32 data) +{ +todr_reg = data; +if (data) todr_blow = 0; +return; +} + +void rxcs_wr (int32 data) +{ +if ((data & CSR_IE) == 0) CLR_INT (TTI); +else if ((tti_csr & (CSR_DONE + CSR_IE)) == CSR_DONE) + SET_INT (TTI); +tti_csr = (tti_csr & ~TTICSR_RW) | (data & TTICSR_RW); +return; +} + +void txcs_wr (int32 data) +{ +if ((data & CSR_IE) == 0) CLR_INT (TTO); +else if ((tto_csr & (CSR_DONE + CSR_IE)) == CSR_DONE) + SET_INT (TTO); +tto_csr = (tto_csr & ~TTOCSR_RW) | (data & TTOCSR_RW); +return; +} + +void txdb_wr (int32 data) +{ +tto_unit.buf = data & 0377; +tto_csr = tto_csr & ~CSR_DONE; +CLR_INT (TTO); +sim_activate (&tto_unit, tto_unit.wait); +return; +} + +/* Paper tape reader routines + + ptr_svc process event (character ready) + ptr_reset process reset + ptr_attach process attach + ptr_detach process detach +*/ + +t_stat ptr_svc (UNIT *uptr) +{ +int32 temp; + +ptr_csr = (ptr_csr | CSR_ERR) & ~CSR_BUSY; +if (ptr_csr & CSR_IE) SET_INT (PTR); +if ((ptr_unit.flags & UNIT_ATT) == 0) + return IORETURN (ptr_stopioe, SCPE_UNATT); +if ((temp = getc (ptr_unit.fileref)) == EOF) { + if (feof (ptr_unit.fileref)) { + if (ptr_stopioe) printf ("PTR end of file\n"); + else return SCPE_OK; } + else perror ("PTR I/O error"); + clearerr (ptr_unit.fileref); + return SCPE_IOERR; } +ptr_csr = (ptr_csr | CSR_DONE) & ~CSR_ERR; +ptr_unit.buf = temp & 0377; +ptr_unit.pos = ptr_unit.pos + 1; +return SCPE_OK; +} + +t_stat ptr_reset (DEVICE *dptr) +{ +ptr_unit.buf = 0; +ptr_csr = 0; +if ((ptr_unit.flags & UNIT_ATT) == 0) ptr_csr = ptr_csr | CSR_ERR; +CLR_INT (PTR); +sim_cancel (&ptr_unit); +return SCPE_OK; +} + +t_stat ptr_attach (UNIT *uptr, char *cptr) +{ +t_stat reason; + +reason = attach_unit (uptr, cptr); +if ((ptr_unit.flags & UNIT_ATT) == 0) ptr_csr = ptr_csr | CSR_ERR; +else ptr_csr = ptr_csr & ~CSR_ERR; +return reason; +} + +t_stat ptr_detach (UNIT *uptr) +{ +ptr_csr = ptr_csr | CSR_ERR; +return detach_unit (uptr); +} + +/* Paper tape punch routines + + ptp_svc process event (character punched) + ptp_reset process reset + ptp_attach process attach + ptp_detach process detach +*/ + +t_stat ptp_svc (UNIT *uptr) +{ +ptp_csr = ptp_csr | CSR_ERR | CSR_DONE; +if (ptp_csr & CSR_IE) SET_INT (PTP); +if ((ptp_unit.flags & UNIT_ATT) == 0) + return IORETURN (ptp_stopioe, SCPE_UNATT); +if (putc (ptp_unit.buf, ptp_unit.fileref) == EOF) { + perror ("PTP I/O error"); + clearerr (ptp_unit.fileref); + return SCPE_IOERR; } +ptp_csr = ptp_csr & ~CSR_ERR; +ptp_unit.pos = ptp_unit.pos + 1; +return SCPE_OK; +} + +t_stat ptp_reset (DEVICE *dptr) +{ +ptp_unit.buf = 0; +ptp_csr = CSR_DONE; +if ((ptp_unit.flags & UNIT_ATT) == 0) ptp_csr = ptp_csr | CSR_ERR; +CLR_INT (PTP); +sim_cancel (&ptp_unit); /* deactivate unit */ +return SCPE_OK; +} + +t_stat ptp_attach (UNIT *uptr, char *cptr) +{ +t_stat reason; + +reason = attach_unit (uptr, cptr); +if ((ptp_unit.flags & UNIT_ATT) == 0) ptp_csr = ptp_csr | CSR_ERR; +else ptp_csr = ptp_csr & ~CSR_ERR; +return reason; +} + +t_stat ptp_detach (UNIT *uptr) +{ +ptp_csr = ptp_csr | CSR_ERR; +return detach_unit (uptr); +} + +/* Terminal input routines + + tti_svc process event (character ready) + tti_reset process reset +*/ + +t_stat tti_svc (UNIT *uptr) +{ +int32 temp; + +sim_activate (&tti_unit, tti_unit.wait); /* continue poll */ +if ((temp = sim_poll_kbd ()) < SCPE_KFLAG) return temp; /* no char or error? */ +tti_unit.buf = temp & 0377; +tti_unit.pos = tti_unit.pos + 1; +tti_csr = tti_csr | CSR_DONE; +if (tti_csr & CSR_IE) SET_INT (TTI); +return SCPE_OK; +} + +t_stat tti_reset (DEVICE *dptr) +{ +tti_unit.buf = 0; +tti_csr = 0; +CLR_INT (TTI); +sim_activate (&tti_unit, tti_unit.wait); /* activate unit */ +return SCPE_OK; +} + +/* Terminal output routines + + tto_svc process event (character typed) + tto_reset process reset +*/ + +t_stat tto_svc (UNIT *uptr) +{ +int32 temp; + +tto_csr = tto_csr | CSR_DONE; +if (tto_csr & CSR_IE) SET_INT (TTO); +if ((temp = sim_putchar (tto_unit.buf & 0177)) != SCPE_OK) return temp; +tto_unit.pos = tto_unit.pos + 1; +return SCPE_OK; +} + +t_stat tto_reset (DEVICE *dptr) +{ +tto_unit.buf = 0; +tto_csr = CSR_DONE; +CLR_INT (TTO); +sim_cancel (&tto_unit); /* deactivate unit */ +return SCPE_OK; +} + +/* Clock routines + + clk_svc process event (clock tick) + clk_reset process reset + todr_powerup powerup for TODR (get date from system) +*/ + +t_stat clk_svc (UNIT *uptr) +{ +int32 t; + +if (clk_csr & CSR_IE) SET_INT (CLK); +t = sim_rtcn_calb (clk_tps, TMR_CLK); /* calibrate clock */ +sim_activate (&clk_unit, t); /* reactivate unit */ +tmr_poll = t; /* set tmr poll */ +tmxr_poll = t * TMXR_MULT; /* set mux poll */ +if (!todr_blow) todr_reg = todr_reg + 1; /* incr TODR */ +return SCPE_OK; +} + +t_stat clk_reset (DEVICE *dptr) +{ +int32 t; + +clk_csr = 0; +CLR_INT (CLK); +t = sim_rtcn_init (clk_unit.wait, TMR_CLK); /* init timer */ +sim_activate (&clk_unit, t); /* activate unit */ +tmr_poll = t; /* set tmr poll */ +tmxr_poll = t * TMXR_MULT; /* set mux poll */ +return SCPE_OK; +} + +t_stat todr_powerup (void) +{ +uint32 base; +time_t curr; +struct tm *ctm; + +curr = time (NULL); /* get curr time */ +if (curr == (time_t) -1) return SCPE_NOFNC; /* error? */ +ctm = localtime (&curr); /* decompose */ +if (ctm == NULL) return SCPE_NOFNC; /* error? */ +base = (((((ctm -> tm_yday * 24) + /* sec since 1-Jan */ + ctm -> tm_hour) * 60) + + ctm -> tm_min) * 60) + + ctm -> tm_sec; +todr_reg = (base * 100) + 0x10000000; /* cvt to VAX form */ +todr_blow = 0; +return SCPE_OK; +} diff --git a/VAX/vax_sys.c b/VAX/vax_sys.c new file mode 100644 index 00000000..443811fa --- /dev/null +++ b/VAX/vax_sys.c @@ -0,0 +1,1338 @@ +/* vax_sys.c: VAX simulator interface + + Copyright (c) 1998-2002, Robert M Supnik + + Permission is hereby granted, free of charge, to any person obtaining a + copy of this software and associated documentation files (the "Software"), + to deal in the Software without restriction, including without limitation + the rights to use, copy, modify, merge, publish, distribute, sublicense, + and/or sell copies of the Software, and to permit persons to whom the + Software is furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + ROBERT M SUPNIK BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + Except as contained in this notice, the name of Robert M Supnik shall not + be used in advertising or otherwise to promote the sale, use or other dealings + in this Software without prior written authorization from Robert M Supnik. + + 14-Jul-02 RMS Added infinite loop message +*/ + +#include "vax_defs.h" +#include + +extern DEVICE cpu_dev, tlb_dev; +extern DEVICE rom_dev, nvr_dev; +extern DEVICE sysd_dev, qba_dev; +extern DEVICE ptr_dev, ptp_dev; +extern DEVICE tti_dev, tto_dev; +extern DEVICE csi_dev, cso_dev; +extern DEVICE lpt_dev, clk_dev; +extern DEVICE rq_dev, rl_dev; +extern DEVICE ts_dev; +extern DEVICE dz_dev; +extern UNIT cpu_unit; +extern REG cpu_reg[]; +extern uint32 *M; +extern int32 saved_PC; +extern int32 sim_switches; + +extern t_stat fprint_val (FILE *stream, t_value val, int radix, + int width, int format); +extern void WriteB (int32 pa, int32 val); +extern void rom_wr (int32 pa, int32 val, int32 lnt); +t_stat fprint_sym_m (FILE *of, t_addr addr, t_value *val); +int32 fprint_sym_qoimm (FILE *of, t_value *val, int32 vp, int32 lnt); +t_stat parse_sym_m (char *cptr, t_addr addr, t_value *val); +int32 parse_brdisp (char *cptr, t_addr addr, t_value *val, + int32 vp, int32 lnt, t_stat *r); +int32 parse_spec (char *cptr, t_addr addr, t_value *val, + int32 vp, int32 disp, t_stat *r); +char *parse_rnum (char *cptr, int32 *rn); +int32 parse_sym_qoimm (int32 *lit, t_value *val, int32 vp, + int lnt, int32 minus); + +/* 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[] = "VAX"; + +REG *sim_PC = &cpu_reg[0]; + +int32 sim_emax = 60; + +DEVICE *sim_devices[] = { + &cpu_dev, + &tlb_dev, + &rom_dev, + &nvr_dev, + &sysd_dev, + &qba_dev, + &tti_dev, + &tto_dev, + &csi_dev, + &cso_dev, + &clk_dev, + &ptr_dev, + &ptp_dev, + &lpt_dev, + &rq_dev, + &rl_dev, + &ts_dev, + &dz_dev, + NULL }; + +const char *sim_stop_messages[] = { + "Unknown error", + "HALT instruction", + "Breakpoint", + "CHMx on interrupt stack", + "Invalid SCB vector", + "Exception in interrupt or exception", + "Process PTE in P0 or P1 space", + "Interrupt at undefined IPL", + "Unknown error", + "Fatal RQDX3 error", + "Infinite loop", + "Unknown abort code" }; + +/* 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 + -n load NVR + -o for memory, specify origin +*/ + +t_stat sim_load (FILE *fileref, char *cptr, char *fnam, int flag) +{ +t_stat r; +int32 i; +t_addr origin, limit; +extern int32 ssc_cnf; +#define SSCCNF_BLO 0x80000000 + +if (flag) return SCPE_ARG; /* dump? */ +if (sim_switches & SWMASK ('R')) { /* ROM? */ + origin = ROMBASE; + limit = ROMBASE + ROMSIZE; } +else if (sim_switches & SWMASK ('N')) { /* NVR? */ + origin = NVRBASE; + limit = NVRBASE + NVRSIZE; + ssc_cnf = ssc_cnf & ~SSCCNF_BLO; } +else { origin = 0; /* memory */ + limit = cpu_unit.capac; + if (sim_switches & SWMASK ('O')) { /* origin? */ + origin = (int32) get_uint (cptr, 16, 0xFFFFFFFF, &r); + if (r != SCPE_OK) return SCPE_ARG; } } + +while ((i = getc (fileref)) != EOF) { /* read byte stream */ + if (origin >= limit) return SCPE_NXM; /* NXM? */ + if (sim_switches & SWMASK ('R')) /* ROM? */ + rom_wr (origin, i, L_BYTE); /* not writeable */ + else WriteB (origin, i); /* store byte */ + origin = origin + 1; } +return SCPE_OK; +} + +/* Factory bad block table creation routine + + This routine writes a DEC standard 044 compliant bad block table on the + last track of the specified unit. The bad block table consists of 10 + repetitions of the same table, formatted as follows: + + words 0-1 pack id number + words 2-3 cylinder/sector/surface specifications + : + words n-n+1 end of table (-1,-1) + + Inputs: + uptr = pointer to unit + sec = number of sectors per surface + wds = number of words per sector + Outputs: + sta = status code +*/ + +t_stat pdp11_bad_block (UNIT *uptr, int32 sec, int32 wds) +{ +int32 i, da; +int32 *buf; + +if ((sec < 2) || (wds < 16)) return SCPE_ARG; +if ((uptr -> flags & UNIT_ATT) == 0) return SCPE_UNATT; +if (!get_yn ("Overwrite last track? [N]", FALSE)) return SCPE_OK; +da = (uptr -> capac - (sec * wds)) * sizeof (int16); +if (fseek (uptr -> fileref, da, SEEK_SET)) return SCPE_IOERR; +if ((buf = malloc (wds * sizeof (int32))) == NULL) return SCPE_MEM; +buf[0] = 0x12345678; +buf[1] = 0; +for (i = 2; i < wds; i++) buf[i] = 0xFFFFFFFF; +for (i = 0; (i < sec) && (i < 10); i++) + fxwrite (buf, sizeof (int32), wds, uptr -> fileref); +free (buf); +if (ferror (uptr -> fileref)) return SCPE_IOERR; +return SCPE_OK; +} + +/* Dispatch/decoder table + + The first entry contains: + - FPD legal flag (DR_F) + - number of specifiers for decode bits 2:0> + - number of specifiers for unimplemented instructions bits<6:4> + */ + +const uint16 drom[NUM_INST][MAX_SPEC + 1] = { +0, 0, 0, 0, 0, 0, 0, /* HALT */ +0, 0, 0, 0, 0, 0, 0, /* NOP */ +0, 0, 0, 0, 0, 0, 0, /* REI */ +0, 0, 0, 0, 0, 0, 0, /* BPT */ +0, 0, 0, 0, 0, 0, 0, /* RET */ +0, 0, 0, 0, 0, 0, 0, /* RSB */ +0, 0, 0, 0, 0, 0, 0, /* LDPCTX */ +0, 0, 0, 0, 0, 0, 0, /* SVPCTX */ +4+DR_F, RW, AB, RW, AB, 0, 0, /* CVTPS */ +4+DR_F, RW, AB, RW, AB, 0, 0, /* CVTSP */ +6, RL, RL, RL, RL, RL, WL, /* INDEX */ +4+DR_F, AB, RL, RW, AB, 0, 0, /* CRC */ +3, RB, RW, AB, 0, 0, 0, /* PROBER */ +3, RB, RW, AB, 0, 0, 0, /* PROBEW */ +2, AB, AB, 0, 0, 0, 0, /* INSQUE */ +2, AB, WL, 0, 0, 0, 0, /* REMQUE */ +1, BB, 0, 0, 0, 0, 0, /* BSBB */ +1, BB, 0, 0, 0, 0, 0, /* BRB */ +1, BB, 0, 0, 0, 0, 0, /* BNEQ */ +1, BB, 0, 0, 0, 0, 0, /* BEQL */ +1, BB, 0, 0, 0, 0, 0, /* BGTR */ +1, BB, 0, 0, 0, 0, 0, /* BLEQ */ +1, AB, 0, 0, 0, 0, 0, /* JSB */ +1, AB, 0, 0, 0, 0, 0, /* JMP */ +1, BB, 0, 0, 0, 0, 0, /* BGEQ */ +1, BB, 0, 0, 0, 0, 0, /* BLSS */ +1, BB, 0, 0, 0, 0, 0, /* BGTRU */ +1, BB, 0, 0, 0, 0, 0, /* BLEQU */ +1, BB, 0, 0, 0, 0, 0, /* BVC */ +1, BB, 0, 0, 0, 0, 0, /* BVS */ +1, BB, 0, 0, 0, 0, 0, /* BCC */ +1, BB, 0, 0, 0, 0, 0, /* BCS */ +4+DR_F, RW, AB, RW, AB, 0, 0, /* ADDP4 */ +6+DR_F, RW, AB, RW, AB, RW, AB, /* ADDP6 */ +4+DR_F, RW, AB, RW, AB, 0, 0, /* SUBP4 */ +6+DR_F, RW, AB, RW, AB, RW, AB, /* SUBP6 */ +5+DR_F, RW, AB, AB, RW, AB, 0, /* CVTPT */ +6+DR_F, RW, AB, RW, AB, RW, AB, /* MULP6 */ +5+DR_F, RW, AB, AB, RW, AB, 0, /* CVTTP */ +6+DR_F, RW, AB, RW, AB, RW, AB, /* DIVP6 */ +3+DR_F, RW, AB, AB, 0, 0, 0, /* MOVC3 */ +3+DR_F, RW, AB, AB, 0, 0, 0, /* CMPC3 */ +4+DR_F, RW, AB, AB, RB, 0, 0, /* SCANC */ +4+DR_F, RW, AB, AB, RB, 0, 0, /* SPANC */ +5+DR_F, RW, AB, RB, RW, AB, 0, /* MOVC5 */ +5+DR_F, RW, AB, RB, RW, AB, 0, /* CMPC5 */ +6+DR_F, RW, AB, RB, AB, RW, AB, /* MOVTC */ +6+DR_F, RW, AB, RB, AB, RW, AB, /* MOVTUC */ +1, BW, 0, 0, 0, 0, 0, /* BSBW */ +1, BW, 0, 0, 0, 0, 0, /* BRW */ +2, RW, WL, 0, 0, 0, 0, /* CVTWL */ +2, RW, WB, 0, 0, 0, 0, /* CVTWB */ +3+DR_F, RW, AB, AB, 0, 0, 0, /* MOVP */ +3+DR_F, RW, AB, AB, 0, 0, 0, /* CMPP3 */ +3+DR_F, RW, AB, WL, 0, 0, 0, /* CVTPL */ +4+DR_F, RW, AB, RW, AB, 0, 0, /* CMPP4 */ +4+DR_F, RW, AB, AB, AB, 0, 0, /* EDITPC */ +4+DR_F, RW, AB, RW, AB, 0, 0, /* MATCHC */ +3+DR_F, RB, RW, AB, 0, 0, 0, /* LOCC */ +3+DR_F, RB, RW, AB, 0, 0, 0, /* SKPC */ +2, RW, WL, 0, 0, 0, 0, /* MOVZWL */ +4, RW, RW, MW, BW, 0, 0, /* ACBW */ +2, AW, WL, 0, 0, 0, 0, /* MOVAW */ +1, AW, 0, 0, 0, 0, 0, /* PUSHAW */ +2, RF, ML, 0, 0, 0, 0, /* ADDF2 */ +3, RF, RF, WL, 0, 0, 0, /* ADDF3 */ +2, RF, ML, 0, 0, 0, 0, /* SUBF2 */ +3, RF, RF, WL, 0, 0, 0, /* SUBF3 */ +2, RF, ML, 0, 0, 0, 0, /* MULF2 */ +3, RF, RF, WL, 0, 0, 0, /* MULF3 */ +2, RF, ML, 0, 0, 0, 0, /* DIVF2 */ +3, RF, RF, WL, 0, 0, 0, /* DIVF3 */ +2, RF, WB, 0, 0, 0, 0, /* CVTFB */ +2, RF, WW, 0, 0, 0, 0, /* CVTFW */ +2, RF, WL, 0, 0, 0, 0, /* CVTFL */ +2, RF, WL, 0, 0, 0, 0, /* CVTRFL */ +2, RB, WL, 0, 0, 0, 0, /* CVTBF */ +2, RW, WL, 0, 0, 0, 0, /* CVTWF */ +2, RL, WL, 0, 0, 0, 0, /* CVTLF */ +4, RF, RF, ML, BW, 0, 0, /* ACBF */ +2, RF, WL, 0, 0, 0, 0, /* MOVF */ +2, RF, RF, 0, 0, 0, 0, /* CMPF */ +2, RF, WL, 0, 0, 0, 0, /* MNEGF */ +1, RF, 0, 0, 0, 0, 0, /* TSTF */ +5, RF, RB, RF, WL, WL, 0, /* EMODF */ +3, RF, RW, AB, 0, 0, 0, /* POLYF */ +2, RF, WQ, 0, 0, 0, 0, /* CVTFD */ +0, 0, 0, 0, 0, 0, 0, /* reserved */ +2, RW, WW, 0, 0, 0, 0, /* ADAWI */ +0, 0, 0, 0, 0, 0, 0, /* reserved */ +0, 0, 0, 0, 0, 0, 0, /* reserved */ +0, 0, 0, 0, 0, 0, 0, /* reserved */ +2, AB, AQ, 0, 0, 0, 0, /* INSQHI */ +2, AB, AQ, 0, 0, 0, 0, /* INSQTI */ +2, AQ, WL, 0, 0, 0, 0, /* REMQHI */ +2, AQ, WL, 0, 0, 0, 0, /* REMQTI */ +2, RD, MQ, 0, 0, 0, 0, /* ADDD2 */ +3, RD, RD, WQ, 0, 0, 0, /* ADDD3 */ +2, RD, MQ, 0, 0, 0, 0, /* SUBD2 */ +3, RD, RD, WQ, 0, 0, 0, /* SUBD3 */ +2, RD, MQ, 0, 0, 0, 0, /* MULD2 */ +3, RD, RD, WQ, 0, 0, 0, /* MULD3 */ +2, RD, MQ, 0, 0, 0, 0, /* DIVD2 */ +3, RD, RD, WQ, 0, 0, 0, /* DIVD3 */ +2, RD, WB, 0, 0, 0, 0, /* CVTDB */ +2, RD, WW, 0, 0, 0, 0, /* CVTDW */ +2, RD, WL, 0, 0, 0, 0, /* CVTDL */ +2, RD, WL, 0, 0, 0, 0, /* CVTRDL */ +2, RB, WQ, 0, 0, 0, 0, /* CVTBD */ +2, RW, WQ, 0, 0, 0, 0, /* CVTWD */ +2, RL, WQ, 0, 0, 0, 0, /* CVTLD */ +4, RD, RD, MQ, BW, 0, 0, /* ACBD */ +2, RD, WQ, 0, 0, 0, 0, /* MOVD */ +2, RD, RD, 0, 0, 0, 0, /* CMPD */ +2, RD, WQ, 0, 0, 0, 0, /* MNEGD */ +1, RD, 0, 0, 0, 0, 0, /* TSTD */ +5, RD, RB, RD, WL, WQ, 0, /* EMODD */ +3, RD, RW, AB, 0, 0, 0, /* POLYD */ +2, RD, WL, 0, 0, 0, 0, /* CVTDF */ +0, 0, 0, 0, 0, 0, 0, /* reserved */ +3, RB, RL, WL, 0, 0, 0, /* ASHL */ +3, RB, RQ, WQ, 0, 0, 0, /* ASHQ */ +4, RL, RL, RL, WQ, 0, 0, /* EMUL */ +4, RL, RQ, WL, WL, 0, 0, /* EDIV */ +1, WQ, 0, 0, 0, 0, 0, /* CLRQ */ +2, RQ, WQ, 0, 0, 0, 0, /* MOVQ */ +2, AQ, WL, 0, 0, 0, 0, /* MOVAQ */ +1, AQ, 0, 0, 0, 0, 0, /* PUSHAQ */ +2, RB, MB, 0, 0, 0, 0, /* ADDB2 */ +3, RB, RB, WB, 0, 0, 0, /* ADDB3 */ +2, RB, MB, 0, 0, 0, 0, /* SUBB2 */ +3, RB, RB, WB, 0, 0, 0, /* SUBB3 */ +2, RB, MB, 0, 0, 0, 0, /* MULB2 */ +3, RB, RB, WB, 0, 0, 0, /* MULB3 */ +2, RB, MB, 0, 0, 0, 0, /* DIVB2 */ +3, RB, RB, WB, 0, 0, 0, /* DIVB3 */ +2, RB, MB, 0, 0, 0, 0, /* BISB2 */ +3, RB, RB, WB, 0, 0, 0, /* BISB3 */ +2, RB, MB, 0, 0, 0, 0, /* BICB2 */ +3, RB, RB, WB, 0, 0, 0, /* BICB3 */ +2, RB, MB, 0, 0, 0, 0, /* XORB2 */ +3, RB, RB, WB, 0, 0, 0, /* XORB3 */ +2, RB, WB, 0, 0, 0, 0, /* MNEGB */ +3, RB, RB, RB, 0, 0, 0, /* CASEB */ +2, RB, WB, 0, 0, 0, 0, /* MOVB */ +2, RB, RB, 0, 0, 0, 0, /* CMPB */ +2, RB, WB, 0, 0, 0, 0, /* MCOMB */ +2, RB, RB, 0, 0, 0, 0, /* BITB */ +1, WB, 0, 0, 0, 0, 0, /* CLRB */ +1, RB, 0, 0, 0, 0, 0, /* TSTB */ +1, MB, 0, 0, 0, 0, 0, /* INCB */ +1, MB, 0, 0, 0, 0, 0, /* DECB */ +2, RB, WL, 0, 0, 0, 0, /* CVTBL */ +2, RB, WW, 0, 0, 0, 0, /* CVTBW */ +2, RB, WL, 0, 0, 0, 0, /* MOVZBL */ +2, RB, WW, 0, 0, 0, 0, /* MOVZBW */ +3, RB, RL, WL, 0, 0, 0, /* ROTL */ +4, RB, RB, MB, BW, 0, 0, /* ACBB */ +2, AB, WL, 0, 0, 0, 0, /* MOVAB */ +1, AB, 0, 0, 0, 0, 0, /* PUSHAB */ +2, RW, MW, 0, 0, 0, 0, /* ADDW2 */ +3, RW, RW, WW, 0, 0, 0, /* ADDW3 */ +2, RW, MW, 0, 0, 0, 0, /* SUBW2 */ +3, RW, RW, WW, 0, 0, 0, /* SUBW3 */ +2, RW, MW, 0, 0, 0, 0, /* MULW2 */ +3, RW, RW, WW, 0, 0, 0, /* MULW3 */ +2, RW, MW, 0, 0, 0, 0, /* DIVW2 */ +3, RW, RW, WW, 0, 0, 0, /* DIVW3 */ +2, RW, MW, 0, 0, 0, 0, /* BISW2 */ +3, RW, RW, WW, 0, 0, 0, /* BISW3 */ +2, RW, MW, 0, 0, 0, 0, /* BICW2 */ +3, RW, RW, WW, 0, 0, 0, /* BICW3 */ +2, RW, MW, 0, 0, 0, 0, /* XORW2 */ +3, RW, RW, WW, 0, 0, 0, /* XORW3 */ +2, RW, WW, 0, 0, 0, 0, /* MNEGW */ +3, RW, RW, RW, 0, 0, 0, /* CASEW */ +2, RW, WW, 0, 0, 0, 0, /* MOVW */ +2, RW, RW, 0, 0, 0, 0, /* CMPW */ +2, RW, WW, 0, 0, 0, 0, /* MCOMW */ +2, RW, RW, 0, 0, 0, 0, /* BITW */ +1, WW, 0, 0, 0, 0, 0, /* CLRW */ +1, RW, 0, 0, 0, 0, 0, /* TSTW */ +1, MW, 0, 0, 0, 0, 0, /* INCW */ +1, MW, 0, 0, 0, 0, 0, /* DECW */ +1, RW, 0, 0, 0, 0, 0, /* BISPSW */ +1, RW, 0, 0, 0, 0, 0, /* BICPSW */ +1, RW, 0, 0, 0, 0, 0, /* POPR */ +1, RW, 0, 0, 0, 0, 0, /* PUSHR */ +1, RW, 0, 0, 0, 0, 0, /* CHMK */ +1, RW, 0, 0, 0, 0, 0, /* CHME */ +1, RW, 0, 0, 0, 0, 0, /* CHMS */ +1, RW, 0, 0, 0, 0, 0, /* CHMU */ +2, RL, ML, 0, 0, 0, 0, /* ADDL2 */ +3, RL, RL, WL, 0, 0, 0, /* ADDL3 */ +2, RL, ML, 0, 0, 0, 0, /* SUBL2 */ +3, RL, RL, WL, 0, 0, 0, /* SUBL3 */ +2, RL, ML, 0, 0, 0, 0, /* MULL2 */ +3, RL, RL, WL, 0, 0, 0, /* MULL3 */ +2, RL, ML, 0, 0, 0, 0, /* DIVL2 */ +3, RL, RL, WL, 0, 0, 0, /* DIVL3 */ +2, RL, ML, 0, 0, 0, 0, /* BISL2 */ +3, RL, RL, WL, 0, 0, 0, /* BISL3 */ +2, RL, ML, 0, 0, 0, 0, /* BICL2 */ +3, RL, RL, WL, 0, 0, 0, /* BICL3 */ +2, RL, ML, 0, 0, 0, 0, /* XORL2 */ +3, RL, RL, WL, 0, 0, 0, /* XORL3 */ +2, RL, WL, 0, 0, 0, 0, /* MNEGL */ +3, RL, RL, RL, 0, 0, 0, /* CASEL */ +2, RL, WL, 0, 0, 0, 0, /* MOVL */ +2, RL, RL, 0, 0, 0, 0, /* CMPL */ +2, RL, WL, 0, 0, 0, 0, /* MCOML */ +2, RL, RL, 0, 0, 0, 0, /* BITL */ +1, WL, 0, 0, 0, 0, 0, /* CLRL */ +1, RL, 0, 0, 0, 0, 0, /* TSTL */ +1, ML, 0, 0, 0, 0, 0, /* INCL */ +1, ML, 0, 0, 0, 0, 0, /* DECL */ +2, RL, ML, 0, 0, 0, 0, /* ADWC */ +2, RL, ML, 0, 0, 0, 0, /* SBWC */ +2, RL, RL, 0, 0, 0, 0, /* MTPR */ +2, RL, WL, 0, 0, 0, 0, /* MFPR */ +1, WL, 0, 0, 0, 0, 0, /* MOVPSL */ +1, RL, 0, 0, 0, 0, 0, /* PUSHL */ +2, AL, WL, 0, 0, 0, 0, /* MOVAL */ +1, AL, 0, 0, 0, 0, 0, /* PUSHAL */ +3, RL, VB, BB, 0, 0, 0, /* BBS */ +3, RL, VB, BB, 0, 0, 0, /* BBC */ +3, RL, VB, BB, 0, 0, 0, /* BBSS */ +3, RL, VB, BB, 0, 0, 0, /* BBCS */ +3, RL, VB, BB, 0, 0, 0, /* BBSC */ +3, RL, VB, BB, 0, 0, 0, /* BBCC */ +3, RL, VB, BB, 0, 0, 0, /* BBSSI */ +3, RL, VB, BB, 0, 0, 0, /* BBCCI */ +2, RL, BB, 0, 0, 0, 0, /* BLBS */ +2, RL, BB, 0, 0, 0, 0, /* BLBC */ +4, RL, RB, VB, WL, 0, 0, /* FFS */ +4, RL, RB, VB, WL, 0, 0, /* FFC */ +4, RL, RB, VB, RL, 0, 0, /* CMPV */ +4, RL, RB, VB, RL, 0, 0, /* CMPZV */ +4, RL, RB, VB, WL, 0, 0, /* EXTV */ +4, RL, RB, VB, WL, 0, 0, /* EXTZV */ +4, RL, RL, RB, VB, 0, 0, /* INSV */ +4, RL, RL, ML, BW, 0, 0, /* ACBL */ +3, RL, ML, BB, 0, 0, 0, /* AOBLSS */ +3, RL, ML, BB, 0, 0, 0, /* AOBLEQ */ +2, ML, BB, 0, 0, 0, 0, /* SOBGEQ */ +2, ML, BB, 0, 0, 0, 0, /* SOBGTR */ +2, RL, WB, 0, 0, 0, 0, /* CVTLB */ +2, RL, WW, 0, 0, 0, 0, /* CVTLW */ +6+DR_F, RB, RW, AB, RB, RW, AB, /* ASHP */ +3+DR_F, RL, RW, AB, 0, 0, 0, /* CVTLP */ +2, AB, AB, 0, 0, 0, 0, /* CALLG */ +2, RL, AB, 0, 0, 0, 0, /* CALLS */ +0, 0, 0, 0, 0, 0, 0, /* XFC */ +0, 0, 0, 0, 0, 0, 0, /* 0FD */ +0, 0, 0, 0, 0, 0, 0, /* 0FE */ +0, 0, 0, 0, 0, 0, 0, /* 0FF */ +0, 0, 0, 0, 0, 0, 0, /* 100-10F */ +0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, /* 110-11F */ +0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, /* 120-12F */ +0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, /* 130-13F */ +0, 0, 0, 0, 0, 0, 0, +0x20, RD, OC, 0, 0, 0, 0, /* CVTDH */ +2, RG, WL, 0, 0, 0, 0, /* CVTGF */ +0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, +2, RG, MQ, 0, 0, 0, 0, /* ADDG2 */ +3, RG, RG, WQ, 0, 0, 0, /* ADDG3 */ +2, RG, MQ, 0, 0, 0, 0, /* SUBG2 */ +3, RG, RG, WQ, 0, 0, 0, /* SUBG3 */ +2, RG, MQ, 0, 0, 0, 0, /* MULG2 */ +3, RG, RG, WQ, 0, 0, 0, /* MULG3 */ +2, RG, MQ, 0, 0, 0, 0, /* DIVG2 */ +3, RG, RG, WQ, 0, 0, 0, /* DIVG3 */ +2, RG, WB, 0, 0, 0, 0, /* CVTGB */ +2, RG, WW, 0, 0, 0, 0, /* CVTGW */ +2, RG, WL, 0, 0, 0, 0, /* CVTGL */ +2, RG, WL, 0, 0, 0, 0, /* CVTRGL */ +2, RB, WQ, 0, 0, 0, 0, /* CVTBG */ +2, RW, WQ, 0, 0, 0, 0, /* CVTWG */ +2, RL, WQ, 0, 0, 0, 0, /* CVTLG */ +4, RG, RG, MQ, BW, 0, 0, /* ACBG */ +2, RG, WQ, 0, 0, 0, 0, /* MOVG */ +2, RG, RG, 0, 0, 0, 0, /* CMPG */ +2, RG, WQ, 0, 0, 0, 0, /* MNEGG */ +1, RG, 0, 0, 0, 0, 0, /* TSTG */ +5, RG, RW, RG, WL, WQ, 0, /* EMODG */ +3, RG, RW, AB, 0, 0, 0, /* POLYG */ +0x20, RG, OC, 0, 0, 0, 0, /* CVTGH */ +0, 0, 0, 0, 0, 0, 0, /* reserved */ +0, 0, 0, 0, 0, 0, 0, /* reserved */ +0, 0, 0, 0, 0, 0, 0, /* reserved */ +0, 0, 0, 0, 0, 0, 0, /* reserved */ +0, 0, 0, 0, 0, 0, 0, /* reserved */ +0, 0, 0, 0, 0, 0, 0, /* reserved */ +0, 0, 0, 0, 0, 0, 0, /* reserved */ +0, 0, 0, 0, 0, 0, 0, /* reserved */ +0, 0, 0, 0, 0, 0, 0, /* reserved */ +0x20, OC, OC, 0, 0, 0, 0, /* ADDH2 */ +0x30, OC, OC, OC, 0, 0, 0, /* ADDH3 */ +0x20, OC, OC, 0, 0, 0, 0, /* SUBH2 */ +0x30, OC, OC, OC, 0, 0, 0, /* SUBH3 */ +0x20, OC, OC, 0, 0, 0, 0, /* MULH2 */ +0x30, OC, OC, OC, 0, 0, 0, /* MULH3 */ +0x20, OC, OC, 0, 0, 0, 0, /* DIVH2 */ +0x30, OC, OC, OC, 0, 0, 0, /* DIVH3 */ +0x20, OC, WB, 0, 0, 0, 0, /* CVTHB */ +0x20, OC, WW, 0, 0, 0, 0, /* CVTHW */ +0x20, OC, WL, 0, 0, 0, 0, /* CVTHL */ +0x20, OC, WL, 0, 0, 0, 0, /* CVTRHL */ +0x20, RB, OC, 0, 0, 0, 0, /* CVTBH */ +0x20, RW, OC, 0, 0, 0, 0, /* CVTWH */ +0x20, RL, OC, 0, 0, 0, 0, /* CVTLH */ +0x40, OC, OC, OC, BW, 0, 0, /* ACBH */ +0x20, OC, OC, 0, 0, 0, 0, /* MOVH */ +0x20, OC, OC, 0, 0, 0, 0, /* CMPH */ +0x20, OC, OC, 0, 0, 0, 0, /* MNEGH */ +0x10, OC, 0, 0, 0, 0, 0, /* TSTH */ +0x50, OC, RW, OC, WL, OC, 0, /* EMODH */ +0x30, OC, RW, AB, 0, 0, 0, /* POLYH */ +0x20, OC, WQ, 0, 0, 0, 0, /* CVTHG */ +0, 0, 0, 0, 0, 0, 0, /* reserved */ +0, 0, 0, 0, 0, 0, 0, /* reserved */ +0, 0, 0, 0, 0, 0, 0, /* reserved */ +0, 0, 0, 0, 0, 0, 0, /* reserved */ +0, 0, 0, 0, 0, 0, 0, /* reserved */ +0x10, OC, 0, 0, 0, 0, 0, /* CLRO */ +0x20, OC, OC, 0, 0, 0, 0, /* MOVO */ +0x20, OC, WL, 0, 0, 0, 0, /* MOVAO*/ +0x10, OC, 0, 0, 0, 0, 0, /* PUSHAO*/ +0, 0, 0, 0, 0, 0, 0, /* 180-18F */ +0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, /* 190-19F */ +0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, +0x20, RF, OC, 0, 0, 0, 0, /* CVTFH */ +2, RF, WQ, 0, 0, 0, 0, /* CVTFG */ +0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, /* 1A0-1AF */ +0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, /* 1B0-1BF */ +0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, /* 1C0-1CF */ +0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, /* 1D0-1DF */ +0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, /* 1E0-1EF */ +0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, /* 1F0-1FF */ +0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, +0x20, OC, WL, 0, 0, 0, 0, /* CVTHF */ +0x20, OC, WQ, 0, 0, 0, 0, /* CVTHD */ +0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0 }; + +/* Opcode mnemonics table */ + +static const char *opcode[] = { +"HALT", "NOP", "REI", "BPT", "RET", "RSB", "LDPCTX", "SVPCTX", +"CVTPS", "CVTSP", "INDEX", "CRC", "PROBER", "PROBEW", "INSQUE", "REMQUE", +"BSBB", "BRB", "BNEQ", "BEQL", "BGTR", "BLEQ", "JSB", "JMP", +"BGEQ", "BLSS", "BGTRU", "BLEQU", "BVC", "BVS", "BGEQU", "BLSSU", +"ADDP4", "ADDP6", "SUBP4", "SUBP6", "CVTPT", "MULP6", "CVTTP", "DIVP", +"MOVC3", "CMPC3", "SCANC", "SPANC", "MOVC5", "CMPC5", "MOVTC", "MOVTUC", +"BSBW", "BRW", "CVTWL", "CVTWB", "MOVP", "CMPP3", "CVTPL", "CMPP4", +"EDITPC", "MATCHC", "LOCC", "SKPC", "MOVZWL", "ACBW", "MOVAW", "PUSHAW", +"ADDF2", "ADDF3", "SUBF2", "SUBF3", "MULF2", "MULF3", "DIVF2", "DIVF3", +"CVTFB", "CVTFW", "CVTFL", "CVTRFL", "CVTBF", "CVTWF", "CVTLF", "ACBF", +"MOVF", "CMPF", "MNEGF", "TSTF", "EMODF", "POLYF", "CVTFD", NULL, +"ADAWI", NULL, NULL, NULL, "INSQHI", "INSQTI", "REMQHI", "REMQTI", +"ADDD2", "ADDD3", "SUBD2", "SUBD3", "MULD2", "MULD3", "DIVD2", "DIVD3", +"CVTDB", "CVTDW", "CVTDL", "CVTRDL", "CVTBD", "CVTWD", "CVTLD", "ACBD", +"MOVD", "CMPD", "MNEGD", "TSTD", "EMODD", "POLYD", "CVTDF", NULL, +"ASHL", "ASHQ", "EMUL", "EDIV", "CLRQ", "MOVQ", "MOVAQ", "PUSHAQ", +"ADDB2", "ADDB3", "SUBB2", "SUBB3", "MULB2", "MULB3", "DIVB2", "DIVB3", +"BISB2", "BISB3", "BICB2", "BICB3", "XORB2", "XORB3", "MNEGB", "CASEB", +"MOVB", "CMPB", "MCOMB", "BITB", "CLRB", "TSTB", "INCB", "DECB", +"CVTBL", "CVTBW", "MOVZBL", "MOVZBW", "ROTL", "ACBB", "MOVAB", "PUSHAB", +"ADDW2", "ADDW3", "SUBW2", "SUBW3", "MULW2", "MULW3", "DIVW2", "DIVW3", +"BISW2", "BISW3", "BICW2", "BICW3", "XORW2", "XORW3", "MNEGW", "CASEW", +"MOVW", "CMPW", "MCOMW", "BITW", "CLRW", "TSTW", "INCW", "DECW", +"BISPSW", "BICPSW", "POPR", "PUSHR", "CHMK", "CHME", "CHMS", "CHMU", +"ADDL2", "ADDL3", "SUBL2", "SUBL3", "MULL2", "MULL3", "DIVL2", "DIVL3", +"BISL2", "BISL3", "BICL2", "BICL3", "XORL2", "XORL3", "MNEGL", "CASEL", +"MOVL", "CMPL", "MCOML", "BITL", "CLRL", "TSTL", "INCL", "DECL", +"ADWC", "SBWC", "MTPR", "MFPR", "MOVPSL", "PUSHL", "MOVAL", "PUSHAL", +"BBS", "BBC", "BBSS", "BBCS", "BBSC", "BBCC", "BBSSI", "BBCCI", +"BLBS", "BLBC", "FFS", "FFC", "CMPV", "CMPZV", "EXTV", "EXTZV", +"INSV", "ACBL", "AOBLSS", "AOBLEQ", "SOBGEQ", "SOBGTR", "CVTLB", "CVTLW", +"ASHP", "CVTLP", "CALLG", "CALLS", "XFC", NULL, NULL, NULL, +NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, /* 100 - 11F */ +NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, /* 120 - 13F */ +NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +NULL, NULL, "CVTDH", "CVTGF", NULL, NULL, NULL, NULL, +NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +"ADDG2", "ADDG3", "SUBG2", "SUBG3", "MULG2", "MULG3", "DIVG2", "DIVG3", +"CVTGB", "CVTGW", "CVTGL", "CVTRGL", "CVTBG", "CVTWG", "CVTLG", "ACBG", +"MOVG", "CMPG", "MNEGG", "TSTG", "EMODG", "POLYG", "CVTGH", NULL, +NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +"ADDH2", "ADDH3", "SUBH2", "SUBH3", "MULH2", "MULH3", "DIVH2", "DIVH3", +"CVTHB", "CVTHW", "CVTHL", "CVTRHL", "CVTBH", "CVTWH", "CVTLH", "ACBH", +"MOVH", "CMPH", "MNEGH", "TSTH", "EMODH", "POLYH", "CVTHG", NULL, +NULL, NULL, NULL, NULL, "CLRO", "MOVO", "MOVAO", "PUSHAO", +NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, /* 180 - 19F */ +NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +"CVTFH", "CVTFG", NULL, NULL, NULL, NULL, NULL, NULL, +NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, /* 1A0 - 1BF */ +NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, /* 1C0 - 1DF */ +NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, /* 1E0 - 1FF */ +NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +NULL, NULL, NULL, NULL, NULL, NULL, "CVTHF", "CVTHD", +NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL }; + +const char *altcod[] = { +"CLRF", "CLRD", "CLRG", "CLRH", "MOVAF", "MOVAD", "MOVAG", "MOVAH", +"PUSHAF", "PUSHAD", "PUSHAG", "PUSHAH", "BNEQU", "BEQLU", "BCC", "BCS", +NULL }; + +const int32 altop[] = { + 0xD4, 0x7C, 0x7C, 0x17C, 0xDE, 0x7E, 0x7E, 0x17E, + 0xDF, 0x7F, 0x7F, 0x17F, 0x12, 0x13, 0x1E, 0x1F }; + +const char* regname[] = { + "R0", "R1", "R2", "R3", "R4", "R5", "R6", "R7", + "R8", "R9", "R10", "R11", "AP", "FP", "SP", "PC" }; + +#define GETNUM(d,n) for (k = d = 0; k < n; k++) \ + d = d | (((int32) val[vp++]) << (k * 8)) + +/* Symbolic decode + + Inputs: + *of = output stream + addr = current PC + *val = values to decode + *uptr = pointer to unit + sw = switches + Outputs: + return = if >= 0, error code + if < 0, number of extra bytes retired +*/ + +t_stat fprint_sym (FILE *of, t_addr addr, t_value *val, + UNIT *uptr, int32 sw) +{ +int32 c, k, num, vp, lnt, rdx; +t_stat r; + +if (uptr && uptr != &cpu_unit) return SCPE_ARG; /* only for CPU */ +vp = 0; /* init ptr */ +if (sw & SWMASK ('B')) lnt = 1; /* get length */ +else if (sw & SWMASK ('W')) lnt = 2; +else lnt = 4; +if (sw & SWMASK ('D')) rdx = 10; /* get radix */ +else if (sw & SWMASK ('O')) rdx = 8; +else if (sw & SWMASK ('H')) rdx = 16; +else rdx = cpu_dev.dradix; +if ((sw & SWMASK ('A')) || (sw & SWMASK ('C'))) { /* char format? */ + if (sw & SWMASK ('C')) lnt = sim_emax; /* -c -> string */ + if ((val[0] & 0177) == 0) return SCPE_ARG; + while (vp < lnt) { /* print string */ + if ((c = (int32) val[vp++] & 0177) == 0) break; + fprintf (of, (c < 040)? "<%03o>": "%c", c); } + return -(vp - 1); } /* return # chars */ + +if (sw & SWMASK ('M')) { /* inst format? */ + r = fprint_sym_m (of, addr, val); /* decode inst */ + if (r <= 0) return r; } + +GETNUM (num, lnt); /* get number */ +fprint_val (of, (uint32) num, rdx, lnt * 8, PV_RZRO); +return -(vp - 1); +} + +/* Symbolic decode for -m + + Inputs: + of = output stream + addr = current PC + *val = values to decode + Outputs: + return = if >= 0, error code + if < 0, number of extra bytes retired +*/ + +t_stat fprint_sym_m (FILE *of, t_addr addr, t_value *val) +{ +int32 i, k, vp, inst, numspec; +int32 num, spec, rn, disp, index; + +vp = 0; /* init ptr */ +inst = (int32) val[vp++]; /* get opcode */ +if (inst == 0xFD) inst = 0x100 | (int32) val[vp++]; /* 2 byte op? */ +if (opcode[inst] == NULL) return SCPE_ARG; /* defined? */ +numspec = drom[inst][0] & DR_NSPMASK; /* get # spec */ +if (numspec == 0) numspec = (drom[inst][0] & DR_USPMASK) >> 4; +fprintf (of, "%s", opcode[inst]); /* print name */ +for (i = 0; i < numspec; i++) { /* loop thru spec */ + fputc (i? ',': ' ', of); /* separator */ + disp = drom[inst][i + 1]; /* get drom value */ + if (disp == BB) { /* byte br disp? */ + GETNUM (num, 1); + fprintf (of, "%-X", SXTB (num) + addr + vp); } + else if (disp == BW) { /* word br disp? */ + GETNUM (num, 2); + fprintf (of, "%-X", SXTW (num) + addr + vp); } + else { spec = (int32) val[vp++]; /* get specifier */ + if ((spec & 0xF0) == IDX) { /* index? */ + index = spec; /* copy, get next */ + spec = (int32) val[vp++]; } + else index = 0; + rn = spec & 0xF; /* get reg # */ + switch (spec & 0xF0) { /* case on mode */ + case SH0: case SH1: case SH2: case SH3: /* s^# */ + fprintf (of, "#%-X", spec); + break; + case GRN: /* Rn */ + fprintf (of, "%-s", regname[rn]); + break; + case RGD: /* (Rn) */ + fprintf (of, "(%-s)", regname[rn]); + break; + case ADC: /* -(Rn) */ + fprintf (of, "-(%-s)", regname[rn]); + break; + case AIN: /* (Rn)+, #n */ + if (rn != nPC) fprintf (of, "(%-s)+", regname[rn]); + else { if (disp == OC) + vp = fprint_sym_qoimm (of, val, vp, 4); + else if (DR_LNT (disp) == L_QUAD) + vp = fprint_sym_qoimm (of, val, vp, 2); + else { GETNUM (num, DR_LNT (disp)); + fprintf (of, "#%-X", num); } } + break; + case AID: /* @(Rn)+, @#n */ + if (rn != nPC) fprintf (of, "@(%-s)+", regname[rn]); + else { GETNUM (num, 4); + fprintf (of, "@#%-X", num); } + break; + case BDD: /* @b^d(r),@b^n */ + fputc ('@', of); + case BDP: /* b^d(r), b^n */ + GETNUM (num, 1); + if (rn == nPC) fprintf (of, "%-X", addr + vp + SXTB (num)); + else if (num & BSIGN) fprintf (of, "-%-X(%-s)", + -num & BMASK, regname[rn]); + else fprintf (of, "%-X(%-s)", num, regname[rn]); + break; + case WDD: /* @w^d(r),@w^n */ + fputc ('@', of); + case WDP: /* w^d(r), w^n */ + GETNUM (num, 2); + if (rn == nPC) fprintf (of, "%-X", addr + vp + SXTW (num)); + else if (num & WSIGN) fprintf (of, "-%-X(%-s)", + -num & WMASK, regname[rn]); + else fprintf (of, "%-X(%-s)", num, regname[rn]); + break; + case LDD: /* @l^d(r),@l^n */ + fputc ('@', of); + case LDP: /* l^d(r),l^n */ + GETNUM (num, 4); + if (rn == nPC) fprintf (of, "%-X", addr + vp + num); + else if (num & LSIGN) fprintf (of, "-%-X(%-s)", + -num, regname[rn]); + else fprintf (of, "%-X(%-s)", num, regname[rn]); + break; } /* end case */ + if (index) fprintf (of, "[%-s]", regname[index & 0xF]); + } /* end else */ + } /* end for */ +return -(vp - 1); +} + +/* Symbolic decode, quad/octa immediates + + Inputs: + *of = output stream + *val = pointer to input values + vp = current index into val + lnt = number of longwords in immediate + Outputs: + vp = updated index into val +*/ + +int32 fprint_sym_qoimm (FILE *of, t_value *val, int32 vp, int32 lnt) +{ +int32 i, k, startp, num[4]; + +for (i = 0; i < lnt; i++) { GETNUM (num[lnt - 1 - i], 4); } +for (i = startp = 0; i < lnt; i++) { + if (startp) fprintf (of, "%08X", num[i]); + else if (num[i] || (i == (lnt - 1))) { + fprintf (of, "#%-X", num[i]); + startp = 1; } } +return vp; +} + +#define PUTNUM(d,n) for (k = 0; k < n; k++) val[vp++] = (d >> (k * 8)) & 0xFF + +/* Symbolic input + + Inputs: + *cptr = pointer to input string + addr = current PC + *uptr = pointer to unit + *val = pointer to output values + sw = switches + Outputs: + status = > 0 error code + <= 0 -number of extra words +*/ + +t_stat parse_sym (char *cptr, t_addr addr, UNIT *uptr, t_value *val, int32 sw) +{ +int32 k, rdx, lnt, num, vp; +t_stat r; +static const uint32 maxv[5] = { 0, 0xFF, 0xFFFF, 0, 0xFFFFFFFF }; + +if (uptr != &cpu_unit) return SCPE_ARG; /* only for CPU */ +vp = 0; /* init ptr */ +if (sw & SWMASK ('B')) lnt = 1; /* set length */ +else if (sw & SWMASK ('W')) lnt = 2; +else lnt = 4; +if (sw & SWMASK ('D')) rdx = 10; /* set radix */ +else if (sw & SWMASK ('O')) rdx = 8; +else if (sw & SWMASK ('H')) rdx = 16; +else rdx = cpu_dev.dradix; +if ((sw & SWMASK ('A')) || (sw & SWMASK ('C'))) { /* char format? */ + if (sw & SWMASK ('C')) lnt = sim_emax; /* -c -> string */ + if (*cptr == 0) return SCPE_ARG; + while (vp < lnt) { /* get chars */ + if (*cptr == 0) break; + val[vp++] = *cptr++; } + return -(vp - 1); } /* return # chars */ + +r = parse_sym_m (cptr, addr, val); /* try to parse inst */ +if (r <= 0) return r; + +num = (int32) get_uint (cptr, rdx, maxv[lnt], &r); /* get number */ +if (r != SCPE_OK) return r; +PUTNUM (num, lnt); /* store */ +return -(lnt - 1); +} + +/* Symbolic input for -m + + 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 *val) +{ +int32 i, numspec, disp, opc, vp; +t_stat r; +char gbuf[CBUFSIZE]; + +cptr = get_glyph (cptr, gbuf, 0); /* get opcode */ +for (i = 0, opc = -1; (i < NUM_INST) && (opc < 0); i++) { + if (opcode[i] && strcmp (gbuf, opcode[i]) == 0) opc = i; } +if (opc < 0) { /* check alternates */ + for (i = 0; altcod[i] && (opc < 0); i++) { + if (strcmp (gbuf, altcod[i]) == 0) opc = altop[i]; } } +if (opc < 0) return SCPE_ARG; /* undefined? */ +vp = 0; +if (opc >= 0x100) val[vp++] = 0xFD; /* 2 byte? */ +val[vp++] = opc & 0xFF; /* store opcode */ +numspec = drom[opc][0] & DR_NSPMASK; /* get # specifiers */ +if (numspec == 0) numspec = (drom[opc][0] & DR_USPMASK) >> 4; +for (i = 1; i <= numspec; i++) { /* loop thru specs */ + if (i == numspec) cptr = get_glyph (cptr, gbuf, 0); + else cptr = get_glyph (cptr, gbuf, ','); /* get specifier */ + disp = drom[opc][i]; /* get drom value */ + if (disp == BB) vp = parse_brdisp (gbuf, addr, val, vp, 0, &r); + else if (disp == BW) vp = parse_brdisp (gbuf, addr, val, vp, 1, &r); + else vp = parse_spec (gbuf, addr, val, vp, disp, &r); + if (r != SCPE_OK) return r; } +if (*cptr != 0) return SCPE_ARG; +return -(vp - 1); +} + +/* Parse a branch displacement + + Inputs: + cptr = pointer to input buffer + addr = current address + val = pointer to output array + vp = current pointer in output array + lnt = length (0 = byte, 1 = word) + r = pointer to status + Outputs: + vp = updated output pointer +*/ + +int32 parse_brdisp (char *cptr, t_addr addr, t_value *val, int32 vp, + int32 lnt, t_stat *r) +{ +int32 k, dest, num; + +dest = (int32) get_uint (cptr, 16, 0xFFFFFFFF, r); /* get value */ +num = dest - (addr + vp + lnt + 1); /* compute offset */ +if ((num > (lnt? 32767: 127)) || (num < (lnt? -32768: -128))) return SCPE_ARG; +PUTNUM (num, lnt + 1); /* store offset */ +return vp; +} + +/* Parse a specifier + + Inputs: + cptr = pointer to input buffer + addr = current address + val = pointer to output array + vp = current pointer in output array + disp = specifier dispatch + r = pointer to status + Outputs: + vp = updated output pointer +*/ + +#define SP_IND 0x200 /* indirect */ +#define SP_V_FORCE 6 +#define SP_FS 0x040 /* S^ */ +#define SP_FI 0x080 /* I^ */ +#define SP_FB 0x0C0 /* B^ */ +#define SP_FW 0x100 /* W^ */ +#define SP_FL 0x140 /* L^ */ +#define SP_LIT 0x020 /* # */ +#define SP_PLUS 0x010 /* plus */ +#define SP_MINUS 0x008 /* minus */ +#define SP_NUM 0x004 /* number */ +#define SP_IDX 0x002 /* (Rn) */ +#define SP_POSTP 0x001 /* trailing + */ +#define M1C(c,v) if (*cptr == c) { cptr++; fl = fl | v; } +#define SPUTNUM(v,d) if (fl & SP_MINUS) v = -v; PUTNUM (v, d) +#define PARSE_LOSE { *r = SCPE_ARG; return vp; } +#define SEL_LIM(p,m,u) ((fl & SP_PLUS)? (p): ((fl & SP_MINUS)? (m): (u))) + +parse_spec (char *cptr, t_addr addr, t_value *val, int32 vp, int32 disp, t_stat *r) +{ +int32 i, k, litsize, rn, index; +int32 num, dispsize, mode; +int32 lit[4] = { 0 }; +int32 fl = 0; +char c, *tptr; +const char *force[] = { "S^", "I^", "B^", "W^", "L^", NULL }; + +*r = SCPE_OK; /* assume ok */ +M1C ('@', SP_IND); /* look for @ */ +if (tptr = parse_rnum (cptr, &rn)) { /* look for Rn */ + if (*cptr == '[') { /* look for [Rx] */ + cptr = parse_rnum (++cptr, &index); + if ((cptr == NULL) || (*cptr++ != ']')) PARSE_LOSE; + val[vp++] = index | IDX; } + else val[vp++] = rn | GRN | (fl? 1: 0); /* Rn or @Rn */ + if (*tptr != 0) *r = SCPE_ARG; /* must be done */ + return vp; } +for (i = 0; force[i]; i++) { /* look for x^ */ + if (strncmp (cptr, force[i], 2) == 0) { + cptr = cptr + 2; + fl = fl | ((i + 1) << SP_V_FORCE); + break; } } +M1C ('#', SP_LIT); /* look for # */ +M1C ('+', SP_PLUS); /* look for + */ +M1C ('-', SP_MINUS); /* look for - */ +for (litsize = 0;; cptr++) { /* look for mprec int */ + c = *cptr; + if ((c < '0') || (c > 'F') || ((c > '9') && (c < 'A'))) break; + num = (c <= '9')? c - '0': c - 'A' + 10; + fl = fl | SP_NUM; + for (i = 3; i >= 0; i--) { + lit[i] = lit[i] << 4; + if (i > 0) lit[i] = lit[i] | ((lit[i - 1] >> 28) & 0xF); + else lit[i] = lit[i] | num; + if (lit[i] && (i > litsize)) litsize = i; } } +if (*cptr == '(') { /* look for (Rn) */ + cptr = parse_rnum (++cptr, &rn); + if ((cptr == NULL) || (*cptr++ != ')')) PARSE_LOSE; + fl = fl | SP_IDX; } +M1C ('+', SP_POSTP); /* look for + */ +if (*cptr == '[') { /* look for [Rx] */ + cptr = parse_rnum (++cptr, &index); + if ((cptr == NULL) || (*cptr++ != ']')) PARSE_LOSE; + val[vp++] = index | IDX; } +switch (fl) { /* case on state */ +case SP_FS|SP_LIT|SP_NUM: /* S^#n */ +case SP_FS|SP_LIT|SP_PLUS|SP_NUM: /* S^#+n */ + if ((litsize > 0) || (lit[0] & ~0x3F)) PARSE_LOSE; + val[vp++] = lit[0]; + break; +case SP_IDX: /* (Rn) */ + val[vp++] = rn | RGD; + break; +case SP_MINUS|SP_IDX: /* -(Rn) */ + val[vp++] = rn | ADC; + break; +case SP_IDX|SP_POSTP: /* (Rn)+ */ + val[vp++] = rn | AIN; + break; +case SP_LIT|SP_NUM: /* #n */ +case SP_LIT|SP_PLUS|SP_NUM: /* #+n */ + if ((litsize == 0) && ((lit[0] & ~0x3F) == 0)) { + val[vp++] = lit[0]; + break; } +case SP_LIT|SP_MINUS|SP_NUM: /* #-n */ +case SP_FI|SP_LIT|SP_NUM: /* I^#n */ +case SP_FI|SP_LIT|SP_PLUS|SP_NUM: /* I^#+n */ +case SP_FI|SP_LIT|SP_MINUS|SP_NUM: /* I^#-n */ + val[vp++] = nPC | AIN; + disp = (disp == OC)? DR_LNMASK + 1: disp & DR_LNMASK; + switch (disp) { /* case spec lnt */ + case 00: /* check fit */ + if ((litsize > 0) || (lit[0] < 0) || + (lit[0] > SEL_LIM (0x7F, 0x80, 0xFF))) PARSE_LOSE; + SPUTNUM (lit[0], 1); /* store */ + break; + case 01: /* check fit */ + if ((litsize > 0) || (lit[0] < 0) || + (lit[0] > SEL_LIM (0x7FFF, 0x8000, 0xFFFF))) PARSE_LOSE; + SPUTNUM (lit[0], 2); + break; + case 02: /* check 1 lw */ + if (litsize > 0) PARSE_LOSE; + SPUTNUM (lit[0], 4); + break; + case 03: /* check 2 lw */ + if (litsize > 1) PARSE_LOSE; + vp = parse_sym_qoimm (lit, val, vp, 2, fl & SP_MINUS); + break; + case DR_LNMASK + 1: + vp = parse_sym_qoimm (lit, val, vp, 4, fl & SP_MINUS); + break; } /* end case disp */ + break; +case SP_IND|SP_IDX|SP_POSTP: /* @(Rn)+ */ + val[vp++] = rn | AID; + break; +case SP_IND|SP_LIT|SP_NUM: /* @#n */ + if (litsize > 0) PARSE_LOSE; + val[vp++] = nPC | AID; + PUTNUM (lit[0], 4); + break; +case SP_NUM|SP_IDX: /* d(rn) */ +case SP_PLUS|SP_NUM|SP_IDX: /* +d(rn) */ +case SP_MINUS|SP_NUM|SP_IDX: /* -d(rn) */ +case SP_IND|SP_NUM|SP_IDX: /* @d(rn) */ +case SP_IND|SP_PLUS|SP_NUM|SP_IDX: /* @+d(rn) */ +case SP_IND|SP_MINUS|SP_NUM|SP_IDX: /* @-d(rn) */ + if (litsize > 0) PARSE_LOSE; + dispsize = 4; /* find fit for */ + mode = LDP; /* displacement */ + if (lit[0] >= 0) { + if (lit[0] <= SEL_LIM (0x7F, 0x80, 0xFF)) { + dispsize = 1; + mode = BDP; } + else if (lit[0] <= SEL_LIM (0x7FFF, 0x8000, 0xFFFF)) { + dispsize = 2; + mode = WDP; } } + val[vp++] = mode | rn | ((fl & SP_IND)? 1: 0); + SPUTNUM (lit[0], dispsize); + break; +case SP_FB|SP_NUM|SP_IDX: /* B^d(rn) */ +case SP_FB|SP_PLUS|SP_NUM|SP_IDX: /* B^+d(rn) */ +case SP_FB|SP_MINUS|SP_NUM|SP_IDX: /* B^-d(rn) */ +case SP_IND|SP_FB|SP_NUM|SP_IDX: /* @B^d(rn) */ +case SP_IND|SP_FB|SP_PLUS|SP_NUM|SP_IDX: /* @B^+d(rn) */ +case SP_IND|SP_FB|SP_MINUS|SP_NUM|SP_IDX: /* @B^-d(rn) */ + if ((litsize > 0) || (lit[0] < 0) || + (lit[0] > SEL_LIM (0x7F, 0x80, 0xFF))) PARSE_LOSE; + val[vp++] = rn | BDP | ((fl & SP_IND)? 1: 0); + SPUTNUM (lit[0], 1); + break; +case SP_FW|SP_NUM|SP_IDX: /* W^d(rn) */ +case SP_FW|SP_PLUS|SP_NUM|SP_IDX: /* W^+d(rn) */ +case SP_FW|SP_MINUS|SP_NUM|SP_IDX: /* W^-d(rn) */ +case SP_IND|SP_FW|SP_NUM|SP_IDX: /* @W^d(rn) */ +case SP_IND|SP_FW|SP_PLUS|SP_NUM|SP_IDX: /* @W^+d(rn) */ +case SP_IND|SP_FW|SP_MINUS|SP_NUM|SP_IDX: /* @W^-d(rn) */ + if ((litsize > 0) || (lit[0] < 0) || + (lit[0] > SEL_LIM (0x7FFF, 0x8000, 0xFFFF))) PARSE_LOSE; + val[vp++] = rn | WDP | ((fl & SP_IND)? 1: 0); + SPUTNUM (lit[0], 2); + break; +case SP_FL|SP_NUM|SP_IDX: /* L^d(rn) */ +case SP_FL|SP_PLUS|SP_NUM|SP_IDX: /* L^+d(rn) */ +case SP_FL|SP_MINUS|SP_NUM|SP_IDX: /* L^-d(rn) */ +case SP_IND|SP_FL|SP_NUM|SP_IDX: /* @L^d(rn) */ +case SP_IND|SP_FL|SP_PLUS|SP_NUM|SP_IDX: /* @L^+d(rn) */ +case SP_IND|SP_FL|SP_MINUS|SP_NUM|SP_IDX: /* @L^-d(rn) */ + if ((litsize > 0) || (lit[0] < 0)) PARSE_LOSE; + val[vp++] = rn | LDP | ((fl & SP_IND)? 1: 0); + SPUTNUM (lit[0], 2); + break; +case SP_NUM: /* n */ +case SP_IND|SP_NUM: /* @n */ + if (litsize > 0) PARSE_LOSE; + num = lit[0] - (addr + vp + 2); /* fit in byte? */ + if ((num >= -128) && (num <= 127)) { + mode = BDP; + dispsize = 1; } + else { num = lit[0] - (addr + vp + 3); /* fit in word? */ + if ((num >= -32768) && (num <= 32767)) { + mode = WDP; + dispsize = 2; } + else { num = lit[0] - (addr + vp + 5); /* no, use lw */ + mode = LDP; + dispsize = 4; } } + val[vp++] = mode | nPC | ((fl & SP_IND)? 1: 0); + PUTNUM (num, dispsize); + break; +case SP_FB|SP_NUM: /* B^n */ +case SP_IND|SP_FB|SP_NUM: /* @B^n */ + num = lit[0] - (addr + vp + 2); + if ((litsize > 0) || (num > 127) || (num < -128)) PARSE_LOSE; + val[vp++] = nPC | BDP | ((fl & SP_IND)? 1: 0); + PUTNUM (num, 1); + break; +case SP_FW|SP_NUM: /* W^n */ +case SP_IND|SP_FW|SP_NUM: /* @W^n */ + num = lit[0] - (addr + vp + 3); + if ((litsize > 0) || (num > 32767) || (num < -32768)) PARSE_LOSE; + val[vp++] = nPC | WDP | ((fl & SP_IND)? 1: 0); + PUTNUM (num, 2); + break; +case SP_FL|SP_NUM: /* L^n */ +case SP_IND|SP_FL|SP_NUM: /* @L^n */ + num = lit[0] - (addr + vp + 5); + if (litsize > 0) PARSE_LOSE; + val[vp++] = nPC | LDP | ((fl & SP_IND)? 1: 0); + PUTNUM (num, 4); + break; +default: + PARSE_LOSE; } /* end case */ +if (*cptr != 0) *r = SCPE_ARG; /* must be done */ +return vp; +} + +char *parse_rnum (char *cptr, int32 *rn) +{ +int32 i, lnt; +t_value regnum; +char *tptr; + +for (i = 15; i >= 0; i--) { /* chk named reg */ + lnt = strlen (regname[i]); + if (strncmp (cptr, regname[i], lnt) == 0) { + *rn = i; + return cptr + lnt; } } +if (*cptr++ != 'R') return NULL; /* look for R */ +regnum = strtotv (cptr, &tptr, 10); /* look for reg # */ +if ((cptr == tptr) || (regnum > 15)) return NULL; +*rn = (int32) regnum; +return tptr; +} + +int32 parse_sym_qoimm (int32 *lit, t_value *val, int32 vp, int lnt, int32 minus) +{ +int32 i, k, prev; + +for (i = prev = 0; i < lnt; i++) { + if (minus) prev = lit[i] = ~lit[i] + (prev == 0); + PUTNUM (lit[i], 4); } +return vp; +} + diff --git a/VAX/vax_sysdev.c b/VAX/vax_sysdev.c new file mode 100644 index 00000000..6ab803ae --- /dev/null +++ b/VAX/vax_sysdev.c @@ -0,0 +1,1117 @@ +/* vax_sysreg.c: VAX system registers simulator + + Copyright (c) 1998-2002, Robert M Supnik + + Permission is hereby granted, free of charge, to any person obtaining a + copy of this software and associated documentation files (the "Software"), + to deal in the Software without restriction, including without limitation + the rights to use, copy, modify, merge, publish, distribute, sublicense, + and/or sell copies of the Software, and to permit persons to whom the + Software is furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + ROBERT M SUPNIK BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + Except as contained in this notice, the name of Robert M Supnik shall not + be used in advertising or otherwise to promote the sale, use or other dealings + in this Software without prior written authorization from Robert M Supnik. + + This module contains the CVAX system-specific devices implemented in the + CMCTL memory controller and the SSC system support chip. (The architecturally + specified devices are implemented in module vax_stddev.c.) + + rom bootstrap ROM (no registers) + nvr non-volatile ROM (no registers) + csi console storage input + cso console storage output + sysd system devices (SSC miscellany) + + 30-May-02 RMS Widened POS to 32b + 28-Feb-02 RMS Fixed bug, missing end of table (found by Lars Brinkhoff) +*/ + +#include "vax_defs.h" + +/* Console storage control/status */ + +#define CSICSR_IMP (CSR_DONE + CSR_IE) /* console input */ +#define CSICSR_RW (CSR_IE) +#define CSOCSR_IMP (CSR_DONE + CSR_IE) /* console output */ +#define CSOCSR_RW (CSR_IE) + +/* CMCTL configuration registers */ + +#define CMCNF_VLD 0x80000000 /* addr valid */ +#define CMCNF_BA 0x1FF00000 /* base addr */ +#define CMCNF_LOCK 0x00000040 /* lock NI */ +#define CMCNF_SRQ 0x00000020 /* sig req WO */ +#define CMCNF_SIG 0x0000001F /* signature */ +#define CMCNF_RW (CMCNF_VLD | CMCNF_BA) /* read/write */ +#define CMCNF_MASK (CMCNF_RW | CMCNF_SIG) +#define MEM_BANK (1 << 22) /* bank size 4MB */ +#define MEM_SIG 0x17; /* ECC, 4 x 4MB */ + +/* CMCTL error register */ + +#define CMERR_RDS 0x80000000 /* uncorr err NI */ +#define CMERR_FRQ 0x40000000 /* 2nd RDS NI */ +#define CMERR_CRD 0x20000000 /* CRD err NI */ +#define CMERR_PAG 0x1FFFFC00 /* page addr NI */ +#define CMERR_DMA 0x00000100 /* DMA err NI */ +#define CMERR_BUS 0x00000080 /* bus err NI */ +#define CMERR_SYN 0x0000007F /* syndrome NI */ +#define CMERR_W1C (CMERR_RDS | CMERR_FRQ | CMERR_CRD | \ + CMERR_DMA | CMERR_BUS) + +/* CMCTL control/status register */ + +#define CMCSR_PMI 0x00002000 /* PMI speed NI */ +#define CMCSR_CRD 0x00001000 /* enb CRD int NI */ +#define CMCSR_FRF 0x00000800 /* force ref WONI */ +#define CMCSR_DET 0x00000400 /* dis err NI */ +#define CMCSR_FDT 0x00000200 /* fast diag NI */ +#define CMCSR_DCM 0x00000080 /* diag mode NI */ +#define CMCSR_SYN 0x0000007F /* syndrome NI */ +#define CMCSR_MASK (CMCSR_PMI | CMCSR_CRD | CMCSR_DET | \ + CMCSR_FDT | CMCSR_DCM | CMCSR_SYN) + +/* KA655 cache control register */ + +#define CACR_DRO 0x00FFFF00 /* diag bits RO */ +#define CACR_V_DPAR 24 /* data parity */ +#define CACR_FIXED 0x00000040 /* fixed bits */ +#define CACR_CPE 0x00000020 /* parity err W1C */ +#define CACR_CEN 0x00000010 /* enable */ +#define CACR_DPE 0x00000004 /* disable par NI */ +#define CACR_WWP 0x00000002 /* write wrong par NI */ +#define CACR_DIAG 0x00000001 /* diag mode */ +#define CACR_W1C (CACR_CPE) +#define CACR_RW (CACR_CEN | CACR_DPE | CACR_WWP | CACR_DIAG) + +/* SSC base register */ + +#define SSCBASE_MBO 0x20000000 /* must be one */ +#define SSCBASE_RW 0x1FFFFC00 /* base address */ + +/* SSC configuration register */ + +#define SSCCNF_BLO 0x80000000 /* batt low W1C */ +#define SSCCNF_IVD 0x08000000 /* int dsbl NI */ +#define SSCCNF_IPL 0x03000000 /* int IPL NI */ +#define SSCCNF_ROM 0x00F70000 /* ROM param NI */ +#define SSCCNF_CTLP 0x00008000 /* ctrl P enb */ +#define SSCCNF_BAUD 0x00007700 /* baud rates NI */ +#define SSCCNF_ADS 0x00000077 /* addr strb NI */ +#define SSCCNF_W1C SSCCNF_BLO +#define SSCCNF_RW 0x0BF7F777 + +/* SSC timeout register */ + +#define SSCBTO_BTO 0x80000000 /* timeout W1C */ +#define SSCBTO_RWT 0x40000000 /* read/write W1C */ +#define SSCBTO_INTV 0x00FFFFFF /* interval NI */ +#define SSCBTO_W1C (SSCBTO_BTO | SSCBTO_RWT) +#define SSCBTO_RW SSCBTO_INTV + +/* SSC output port */ + +#define SSCOTP_MASK 0x0000000F /* output port */ + +/* SSC timer control/status */ + +#define TMR_CSR_ERR 0x80000000 /* error W1C */ +#define TMR_CSR_DON 0x00000080 /* done W1C */ +#define TMR_CSR_IE 0x00000040 /* int enb */ +#define TMR_CSR_SGL 0x00000020 /* single WO */ +#define TMR_CSR_XFR 0x00000010 /* xfer WO */ +#define TMR_CSR_STP 0x00000004 /* stop */ +#define TMR_CSR_RUN 0x00000001 /* run */ +#define TMR_CSR_W1C (TMR_CSR_ERR | TMR_CSR_DON) +#define TMR_CSR_RW (TMR_CSR_IE | TMR_CSR_STP | TMR_CSR_RUN) + +/* SSC timer intervals */ + +#define TMR_INC 10000 /* usec/interval */ + +/* SSC timer vector */ + +#define TMR_VEC_MASK 0x000003FC /* vector */ + +/* SSC address strobes */ + +#define SSCADS_MASK 0x3FFFFFFC /* match or mask */ + +extern int32 int_req[IPL_HLVL]; +extern UNIT cpu_unit; +extern jmp_buf save_env; +extern int32 p1; +extern int32 sim_switches; +extern int32 MSER; +extern int32 tmr_poll; + +uint32 *rom = NULL; /* boot ROM */ +uint32 *nvr = NULL; /* non-volatile mem */ +int32 csi_csr = 0; /* control/status */ +int32 cso_csr = 0; /* control/status */ +int32 cmctl_reg[CMCTLSIZE >> 2] = { 0 }; /* CMCTL reg */ +int32 ka_cacr = 0; /* KA655 cache ctl */ +int32 ka_bdr = 0x80; /* KA655 boot diag */ +int32 ssc_base = SSCBASE; /* SSC base */ +int32 ssc_cnf = 0; /* SSC conf */ +int32 ssc_bto = 0; /* SSC timeout */ +int32 ssc_otp = 0; /* SSC output port */ +int32 tmr_csr[2] = { 0 }; /* SSC timers */ +uint32 tmr_tir[2] = { 0 }; /* curr interval */ +uint32 tmr_tnir[2] = { 0 }; /* next interval */ +int32 tmr_tivr[2] = { 0 }; /* vector */ +uint32 tmr_inc[2] = { 0 }; /* tir increment */ +uint32 tmr_sav[2] = { 0 }; /* saved inst cnt */ +int32 ssc_adsm[2] = { 0 }; /* addr strobes */ +int32 ssc_adsk[2] = { 0 }; +int32 cdg_dat[CDASIZE >> 2]; /* cache data */ + +t_stat rom_ex (t_value *vptr, t_addr addr, UNIT *uptr, int32 sw); +t_stat rom_dep (t_value val, t_addr addr, UNIT *uptr, int32 sw); +t_stat rom_reset (DEVICE *dptr); +t_stat nvr_ex (t_value *vptr, t_addr addr, UNIT *uptr, int32 sw); +t_stat nvr_dep (t_value val, t_addr addr, UNIT *uptr, int32 sw); +t_stat nvr_reset (DEVICE *dptr); +t_stat csi_reset (DEVICE *dptr); +t_stat cso_reset (DEVICE *dptr); +t_stat cso_svc (UNIT *uptr); +t_stat tmr_svc (UNIT *uptr); +t_stat sysd_reset (DEVICE *dptr); + +int32 rom_rd (int32 pa); +int32 nvr_rd (int32 pa); +void nvr_wr (int32 pa, int32 val, int32 lnt); +int32 csrs_rd (void); +int32 csrd_rd (void); +int32 csts_rd (void); +void csrs_wr (int32 dat); +void csts_wr (int32 dat); +void cstd_wr (int32 dat); +int32 cmctl_rd (int32 pa); +void cmctl_wr (int32 pa, int32 val, int32 lnt); +int32 ka_rd (int32 pa); +void ka_wr (int32 pa, int32 val, int32 lnt); +int32 cdg_rd (int32 pa); +void cdg_wr (int32 pa, int32 val, int32 lnt); +int32 ssc_rd (int32 pa); +void ssc_wr (int32 pa, int32 val, int32 lnt); +int32 tmr_tir_rd (int32 tmr, t_bool interp); +void tmr_csr_wr (int32 tmr, int32 val); +void tmr_sched (int32 tmr); +void tmr_incr (int32 tmr, uint32 inc); +int32 parity (int32 val, int32 odd); + +extern int32 cqmap_rd (int32 pa); +extern void cqmap_wr (int32 pa, int32 val, int32 lnt); +extern int32 cqipc_rd (int32 pa); +extern void cqipc_wr (int32 pa, int32 val, int32 lnt); +extern int32 cqbic_rd (int32 pa); +extern void cqbic_wr (int32 pa, int32 val, int32 lnt); +extern int32 cqmem_rd (int32 pa); +extern void cqmem_wr (int32 pa, int32 val, int32 lnt); +extern int32 iccs_rd (void); +extern int32 todr_rd (void); +extern int32 rxcs_rd (void); +extern int32 rxdb_rd (void); +extern int32 txcs_rd (void); +extern void iccs_wr (int32 dat); +extern void todr_wr (int32 dat); +extern void rxcs_wr (int32 dat); +extern void txcs_wr (int32 dat); +extern void txdb_wr (int32 dat); +extern void ioreset_wr (int32 dat); + +/* ROM data structures + + rom_dev ROM device descriptor + rom_unit ROM units + rom_reg ROM register list +*/ + +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, ROMAWIDTH, 4, 16, 32, + &rom_ex, &rom_dep, &rom_reset, + NULL, NULL, NULL }; + +/* NVR data structures + + nvr_dev NVR device descriptor + nvr_unit NVR units + nvr_reg NVR register list +*/ + +UNIT nvr_unit = + { UDATA (NULL, UNIT_FIX+UNIT_BINK, NVRSIZE) }; + +REG nvr_reg[] = { + { NULL } }; + +DEVICE nvr_dev = { + "NVR", &nvr_unit, nvr_reg, NULL, + 1, 16, NVRAWIDTH, 4, 16, 32, + &nvr_ex, &nvr_dep, &nvr_reset, + NULL, NULL, NULL }; + +/* CSI data structures + + csi_dev CSI device descriptor + csi_unit CSI unit descriptor + csi_reg CSI register list +*/ + +UNIT csi_unit = { UDATA (NULL, 0, 0), KBD_POLL_WAIT }; + +REG csi_reg[] = { + { ORDATA (BUF, csi_unit.buf, 8) }, + { ORDATA (CSR, csi_csr, 16) }, + { FLDATA (INT, int_req[IPL_CSI], INT_V_CSI) }, + { FLDATA (DONE, csi_csr, CSR_V_DONE) }, + { FLDATA (IE, csi_csr, CSR_V_IE) }, + { DRDATA (POS, csi_unit.pos, 32), PV_LEFT }, + { DRDATA (TIME, csi_unit.wait, 24), REG_NZ + PV_LEFT }, + { NULL } }; + +DEVICE csi_dev = { + "CSI", &csi_unit, csi_reg, NULL, + 1, 10, 31, 1, 8, 8, + NULL, NULL, &csi_reset, + NULL, NULL, NULL }; + +/* CSO data structures + + cso_dev CSO device descriptor + cso_unit CSO unit descriptor + cso_reg CSO register list +*/ + +UNIT cso_unit = { UDATA (&cso_svc, UNIT_SEQ+UNIT_ATTABLE, 0), SERIAL_OUT_WAIT }; + +REG cso_reg[] = { + { ORDATA (BUF, cso_unit.buf, 8) }, + { ORDATA (CSR, cso_csr, 16) }, + { FLDATA (INT, int_req[IPL_CSO], INT_V_CSO) }, + { FLDATA (DONE, cso_csr, CSR_V_DONE) }, + { FLDATA (IE, cso_csr, CSR_V_IE) }, + { DRDATA (POS, cso_unit.pos, 32), PV_LEFT }, + { DRDATA (TIME, cso_unit.wait, 24), PV_LEFT }, + { NULL } }; + +DEVICE cso_dev = { + "CSO", &cso_unit, cso_reg, NULL, + 1, 10, 31, 1, 8, 8, + NULL, NULL, &cso_reset, + NULL, NULL, NULL }; + +/* SYSD data structures + + sysd_dev SYSD device descriptor + sysd_unit SYSD units + sysd_reg SYSD register list +*/ + +UNIT sysd_unit[] = { + { UDATA (&tmr_svc, 0, 0) }, + { UDATA (&tmr_svc, 0, 0) } }; + +REG sysd_reg[] = { + { BRDATA (CMCSR, cmctl_reg, 16, 32, CMCTLSIZE >> 2) }, + { HRDATA (CACR, ka_cacr, 8) }, + { HRDATA (BDR, ka_bdr, 8) }, + { HRDATA (BASE, ssc_base, 29) }, + { HRDATA (CNF, ssc_cnf, 32) }, + { HRDATA (BTO, ssc_bto, 32) }, + { HRDATA (OTP, ssc_otp, 4) }, + { HRDATA (TCSR0, tmr_csr[0], 32) }, + { HRDATA (TIR0, tmr_tir[0], 32) }, + { HRDATA (TNIR0, tmr_tnir[0], 32) }, + { HRDATA (TIVEC0, tmr_tivr[0], 9) }, + { HRDATA (TINC0, tmr_inc[0], 32) }, + { HRDATA (TSAV0, tmr_sav[0], 32) }, + { HRDATA (TCSR1, tmr_csr[1], 32) }, + { HRDATA (TIR1, tmr_tir[1], 32) }, + { HRDATA (TNIR1, tmr_tnir[1], 32) }, + { HRDATA (TIVEC1, tmr_tivr[1], 9) }, + { HRDATA (TINC1, tmr_inc[1], 32) }, + { HRDATA (TSAV1, tmr_sav[1], 32) }, + { HRDATA (ADSM0, ssc_adsm[0], 32) }, + { HRDATA (ADSK0, ssc_adsk[0], 32) }, + { HRDATA (ADSM1, ssc_adsm[1], 32) }, + { HRDATA (ADSK1, ssc_adsk[1], 32) }, + { BRDATA (CDGDAT, cdg_dat, 16, 32, CDASIZE >> 2) }, + { NULL } }; + +DEVICE sysd_dev = { + "SYSD", sysd_unit, sysd_reg, NULL, + 2, 16, 16, 1, 16, 8, + NULL, NULL, &sysd_reset, + NULL, NULL, NULL }; + +/* ROM: read only memory - stored in a buffered file + Register space access routines see ROM twice +*/ + +int32 rom_rd (int32 pa) +{ +int32 rg = ((pa - ROMBASE) & ROMAMASK) >> 2; + +return rom[rg]; +} + +void rom_wr (int32 pa, int32 val, int32 lnt) +{ +int32 rg = ((pa - ROMBASE) & ROMAMASK) >> 2; + +if (lnt < L_LONG) { /* byte or word? */ + int32 sc = (pa & 3) << 3; /* merge */ + int32 mask = (lnt == L_WORD)? 0xFFFF: 0xFF; + rom[rg] = ((val & mask) << sc) | (rom[rg] & ~(mask << sc)); } +else rom[rg] = val; +return; +} + +/* ROM examine */ + +t_stat rom_ex (t_value *vptr, t_addr addr, UNIT *uptr, int32 sw) +{ +if ((vptr == NULL) || (addr & 03)) return SCPE_ARG; +if (addr >= ROMSIZE) return SCPE_NXM; +*vptr = rom[addr >> 2]; +return SCPE_OK; +} + +/* ROM deposit */ + +t_stat rom_dep (t_value val, t_addr addr, UNIT *uptr, int32 sw) +{ +if (addr & 03) return SCPE_ARG; +if (addr >= ROMSIZE) return SCPE_NXM; +rom[addr >> 2] = (uint32) val; +return SCPE_OK; +} + +/* ROM reset */ + +t_stat rom_reset (DEVICE *dptr) +{ +if (rom == NULL) rom = calloc (ROMSIZE >> 2, sizeof (int32)); +if (rom == NULL) return SCPE_MEM; +return SCPE_OK; +} + +/* NVR: non-volatile RAM - stored in a buffered file */ + +int32 nvr_rd (int32 pa) +{ +int32 rg = (pa - NVRBASE) >> 2; + +return nvr[rg]; +} + +void nvr_wr (int32 pa, int32 val, int32 lnt) +{ +int32 rg = (pa - NVRBASE) >> 2; + +if (lnt < L_LONG) { /* byte or word? */ + int32 sc = (pa & 3) << 3; /* merge */ + int32 mask = (lnt == L_WORD)? 0xFFFF: 0xFF; + nvr[rg] = ((val & mask) << sc) | (nvr[rg] & ~(mask << sc)); } +else nvr[rg] = val; +return; +} + +/* NVR examine */ + +t_stat nvr_ex (t_value *vptr, t_addr addr, UNIT *uptr, int32 sw) +{ +if ((vptr == NULL) || (addr & 03)) return SCPE_ARG; +if (addr >= NVRSIZE) return SCPE_NXM; +*vptr = nvr[addr >> 2]; +return SCPE_OK; +} + +/* NVR deposit */ + +t_stat nvr_dep (t_value val, t_addr addr, UNIT *uptr, int32 sw) +{ +if (addr & 03) return SCPE_ARG; +if (addr >= NVRSIZE) return SCPE_NXM; +nvr[addr >> 2] = (uint32) val; +return SCPE_OK; +} + +/* NVR reset */ + +t_stat nvr_reset (DEVICE *dptr) +{ +if (nvr == NULL) { + nvr = calloc (NVRSIZE >> 2, sizeof (int32)); + ssc_cnf = ssc_cnf | SSCCNF_BLO; } +if (nvr == NULL) return SCPE_MEM; +return SCPE_OK; +} + +/* CSI: console storage input */ + +int32 csrs_rd (void) +{ +return (csi_csr & CSICSR_IMP); +} + +int32 csrd_rd (void) +{ +csi_csr = csi_csr & ~CSR_DONE; +CLR_INT (CSI); +return (csi_unit.buf & 0377); +} + +void csrs_wr (int32 data) +{ +if ((data & CSR_IE) == 0) CLR_INT (CSI); +else if ((csi_csr & (CSR_DONE + CSR_IE)) == CSR_DONE) + SET_INT (CSI); +csi_csr = (csi_csr & ~CSICSR_RW) | (data & CSICSR_RW); +return; +} + +t_stat csi_reset (DEVICE *dptr) +{ +csi_unit.buf = 0; +csi_csr = 0; +CLR_INT (CSI); +return SCPE_OK; +} + +/* CSO: console storage output */ + +int32 csts_rd (void) +{ +return (cso_csr & CSOCSR_IMP); +} + +void csts_wr (int32 data) +{ +if ((data & CSR_IE) == 0) CLR_INT (CSO); +else if ((cso_csr & (CSR_DONE + CSR_IE)) == CSR_DONE) + SET_INT (CSO); +cso_csr = (cso_csr & ~CSOCSR_RW) | (data & CSOCSR_RW); +return; +} + +void cstd_wr (int32 data) +{ +cso_unit.buf = data & 0377; +cso_csr = cso_csr & ~CSR_DONE; +CLR_INT (CSO); +sim_activate (&cso_unit, cso_unit.wait); +return; +} + +t_stat cso_svc (UNIT *uptr) +{ +cso_csr = cso_csr | CSR_DONE; +if (cso_csr & CSR_IE) SET_INT (CSO); +if ((cso_unit.flags & UNIT_ATT) == 0) return SCPE_OK; +if (putc (cso_unit.buf, cso_unit.fileref) == EOF) { + perror ("CSO I/O error"); + clearerr (cso_unit.fileref); + return SCPE_IOERR; } +cso_unit.pos = cso_unit.pos + 1; +return SCPE_OK; +} + +t_stat cso_reset (DEVICE *dptr) +{ +cso_unit.buf = 0; +cso_csr = CSR_DONE; +CLR_INT (CSO); +sim_cancel (&cso_unit); /* deactivate unit */ +return SCPE_OK; +} + +/* SYSD: SSC access mechanisms and devices + + - IPR space read/write routines + - register space read/write routines + - SSC local register read/write routines + - SSC console storage UART + - SSC timers + - CMCTL local register read/write routines +*/ + +/* Read/write IPR register space + + These routines implement the SSC's response to IPR's which are + sent off the CPU chip for processing. +*/ + +int32 ReadIPR (int32 rg) +{ +int32 val; + +switch (rg) { +case MT_ICCS: /* ICCS */ + val = iccs_rd (); + break; +case MT_CSRS: /* CSRS */ + val = csrs_rd (); + break; +case MT_CSRD: /* CSRD */ + val = csrd_rd (); + break; +case MT_CSTS: /* CSTS */ + val = csts_rd (); + break; +case MT_CSTD: /* CSTD */ + val = 0; + break; +case MT_RXCS: /* RXCS */ + val = rxcs_rd (); + break; +case MT_RXDB: /* RXDB */ + val = rxdb_rd (); + break; +case MT_TXCS: /* TXCS */ + val = txcs_rd (); + break; +case MT_TXDB: /* TXDB */ + val = 0; + break; +case MT_TODR: + val = todr_rd (); + break; +default: + ssc_bto = ssc_bto | SSCBTO_BTO; /* set BTO */ + val = 0; + break; } +return val; +} + +void WriteIPR (int32 rg, int32 val) +{ +switch (rg) { +case MT_ICCS: /* ICCS */ + iccs_wr (val); + break; +case MT_TODR: /* TODR */ + todr_wr (val); + break; +case MT_CSRS: /* CSRS */ + csrs_wr (val); + break; +case MT_CSRD: /* CSRD */ + break; +case MT_CSTS: /* CSTS */ + csts_wr (val); + break; +case MT_CSTD: /* CSTD */ + cstd_wr (val); + break; +case MT_RXCS: /* RXCS */ + rxcs_wr (val); + break; +case MT_RXDB: /* RXDB */ + break; +case MT_TXCS: /* TXCS */ + txcs_wr (val); + break; +case MT_TXDB: /* TXDB */ + txdb_wr (val); + break; +case MT_IORESET: /* IORESET */ + ioreset_wr (val); + break; +default: + ssc_bto = ssc_bto | SSCBTO_BTO; /* set BTO */ + break; } +return; +} + +/* Read/write I/O register space + + These routines are the 'catch all' for address space map. Any + address that doesn't explicitly belong to memory, I/O, or ROM + is given to these routines for processing. +*/ + +struct reglink { /* register linkage */ + int32 low; /* low addr */ + int32 high; /* high addr */ + t_stat (*read)(); /* read routine */ + void (*write)(); }; /* write routine */ + +struct reglink regtable[] = { + { CQMAPBASE, CQMAPBASE+CQMAPSIZE, &cqmap_rd, &cqmap_wr }, + { ROMBASE, ROMBASE+ROMSIZE+ROMSIZE, &rom_rd, NULL }, + { NVRBASE, NVRBASE+NVRSIZE, &nvr_rd, &nvr_wr }, + { CMCTLBASE, CMCTLBASE+CMCTLSIZE, &cmctl_rd, &cmctl_wr }, + { SSCBASE, SSCBASE+SSCSIZE, &ssc_rd, &ssc_wr }, + { KABASE, KABASE+KASIZE, &ka_rd, &ka_wr }, + { CQBICBASE, CQBICBASE+CQBICSIZE, &cqbic_rd, &cqbic_wr }, + { CQIPCBASE, CQIPCBASE+CQIPCSIZE, &cqipc_rd, &cqipc_wr }, + { CQMBASE, CQMBASE+CQMSIZE, &cqmem_rd, &cqmem_wr }, + { CDGBASE, CDGBASE+CDGSIZE, &cdg_rd, &cdg_wr }, + { 0, 0, NULL, NULL } }; + +/* ReadReg - read register space + + Inputs: + pa = physical address + lnt = length (BWLQ) - ignored + Output: + longword of data +*/ + +int32 ReadReg (int32 pa, int32 lnt) +{ +struct reglink *p; + +for (p = ®table[0]; p -> low != 0; p++) { + if ((pa >= p -> low) && (pa < p -> high) && p -> read) + return p -> read (pa); } +ssc_bto = ssc_bto | SSCBTO_BTO | SSCBTO_RWT; +MACH_CHECK (MCHK_READ); +return 0; +} + +/* WriteReg - write register space + + Inputs: + pa = physical address + val = data to write, right justified in 32b longword + lnt = length (BWLQ) + Outputs: + none +*/ + +void WriteReg (int32 pa, int32 val, int32 lnt) +{ +struct reglink *p; + +for (p = ®table[0]; p -> low != 0; p++) { + if ((pa >= p -> low) && (pa < p -> high) && p -> write) { + p -> write (pa, val, lnt); + return; } } +ssc_bto = ssc_bto | SSCBTO_BTO | SSCBTO_RWT; +MACH_CHECK (MCHK_WRITE); +return; +} + +/* CMCTL registers + + CMCTL00 - 15 configure memory banks 00 - 15. Note that they are + here merely to entertain the firmware; the actual configuration + of memory is unaffected by the settings here. + + CMCTL16 - error status register + + CMCTL17 - control/diagnostic status register + + The CMCTL registers are cleared at power up. +*/ + +int32 cmctl_rd (int32 pa) +{ +int32 rg = (pa - CMCTLBASE) >> 2; + +switch (rg) { +default: /* config reg */ + return cmctl_reg[rg] & CMCNF_MASK; +case 16: /* err status */ + return cmctl_reg[rg]; +case 17: /* csr */ + return cmctl_reg[rg] & CMCSR_MASK; } +return 0; +} + +void cmctl_wr (int32 pa, int32 val, int32 lnt) +{ +int32 i, rg = (pa - CMCTLBASE) >> 2; + +if (lnt < L_LONG) { /* LW write only */ + int32 sc = (pa & 3) << 3; /* shift data to */ + val = val << sc; } /* proper location */ +switch (rg) { +default: /* config reg */ + if (val & CMCNF_SRQ) { /* sig request? */ + for (i = rg; i < (rg + 4); i++) { + cmctl_reg[i] = cmctl_reg[i] & ~CMCNF_SIG; + if (ADDR_IS_MEM (i * MEM_BANK)) + cmctl_reg[i] = cmctl_reg[i] | MEM_SIG; } } + cmctl_reg[rg] = (cmctl_reg[rg] & ~CMCNF_RW) | (val & CMCNF_RW); + break; +case 16: /* err status */ + cmctl_reg[rg] = cmctl_reg[rg] & ~(val & CMERR_W1C); + break; +case 17: /* csr */ + cmctl_reg[rg] = val & CMCSR_MASK; + break; } +return; +} + +/* KA655 registers */ + +int32 ka_rd (int32 pa) +{ +int32 rg = (pa - KABASE) >> 2; + +switch (rg) +{ +case 0: /* CACR */ + return ka_cacr; +case 1: /* BDR */ + return ka_bdr; } +return 0; +} + +void ka_wr (int32 pa, int32 val, int32 lnt) +{ +int32 rg = (pa - KABASE) >> 2; + +if ((rg == 0) && ((pa & 3) == 0)) { /* lo byte only */ + ka_cacr = (ka_cacr & ~(val & CACR_W1C)) | CACR_FIXED; + ka_cacr = (ka_cacr & ~CACR_RW) | (val & CACR_RW); } +return; +} + +/* Cache diagnostic space - byte/word merges done in WriteReg */ + +int32 cdg_rd (int32 pa) +{ +int32 t, row = CDG_GETROW (pa); +int32 tag = CDG_GETTAG (pa); +int32 tidx = row >> 1; + +t = cdg_dat[row]; +ka_cacr = ka_cacr & ~CACR_DRO; /* clear diag */ +ka_cacr = ka_cacr | + (parity ((t >> 24) & 0xFF, 1) << (CACR_V_DPAR + 3)) | + (parity ((t >> 16) & 0xFF, 0) << (CACR_V_DPAR + 2)) | + (parity ((t >> 8) & 0xFF, 1) << (CACR_V_DPAR + 1)) | + (parity (t & 0xFF, 0) << CACR_V_DPAR); +return t; +} + +void cdg_wr (int32 pa, int32 val, int32 lnt) +{ +int32 row = CDG_GETROW (pa); + +if (lnt < L_LONG) { /* byte or word? */ + int32 sc = (pa & 3) << 3; /* merge */ + int32 mask = (lnt == L_WORD)? 0xFFFF: 0xFF; + int32 t = cdg_dat[row]; + val = ((val & mask) << sc) | (t & ~(mask << sc)); } +cdg_dat[row] = val; /* store data */ +return; +} + +int32 parity (int32 val, int32 odd) +{ +for ( ; val != 0; val = val >> 1) { + if (val & 1) odd = odd ^ 1; } +return odd; +} + +/* SSC registers - byte/word merges done in WriteReg */ + +int32 ssc_rd (int32 pa) +{ +int32 rg = (pa - SSCBASE) >> 2; + +switch (rg) { +case 0x00: /* base reg */ + return ssc_base; +case 0x04: /* conf reg */ + return ssc_cnf; +case 0x08: /* bus timeout */ + return ssc_bto; +case 0x0C: /* output port */ + return ssc_otp & SSCOTP_MASK; +case 0x1B: /* TODR */ + return todr_rd (); +case 0x1C: /* CSRS */ + return csrs_rd (); +case 0x1D: /* CSRD */ + return csrd_rd (); +case 0x1E: /* CSTS */ + return csts_rd (); +case 0x20: /* RXCS */ + return rxcs_rd (); +case 0x21: /* RXDB */ + return rxdb_rd (); +case 0x22: /* TXCS */ + return txcs_rd (); +case 0x40: /* T0CSR */ + return tmr_csr[0]; +case 0x41: /* T0INT */ + return tmr_tir_rd (0, FALSE); +case 0x42: /* T0NI */ + return tmr_tnir[0]; +case 0x43: /* T0VEC */ + return tmr_tivr[0]; +case 0x44: /* T1CSR */ + return tmr_csr[1]; +case 0x45: /* T1INT */ + return tmr_tir_rd (1, FALSE); +case 0x46: /* T1NI */ + return tmr_tnir[1]; +case 0x47: /* T1VEC */ + return tmr_tivr[1]; +case 0x4C: /* ADS0M */ + return ssc_adsm[0]; +case 0x4D: /* ADS0K */ + return ssc_adsk[0]; +case 0x50: /* ADS1M */ + return ssc_adsm[1]; +case 0x51: /* ADS1K */ + return ssc_adsk[1]; } +return 0; +} + +void ssc_wr (int32 pa, int32 val, int32 lnt) +{ +int32 rg = (pa - SSCBASE) >> 2; + +if (lnt < L_LONG) { /* byte or word? */ + int32 sc = (pa & 3) << 3; /* merge */ + int32 mask = (lnt == L_WORD)? 0xFFFF: 0xFF; + int32 t = ssc_rd (pa); + val = ((val & mask) << sc) | (t & ~(mask << sc)); } + +switch (rg) { +case 0x00: /* base reg */ + ssc_base = (val & SSCBASE_RW) | SSCBASE_MBO; + break; +case 0x04: /* conf reg */ + ssc_cnf = ssc_cnf & ~(val & SSCCNF_W1C); + ssc_cnf = (ssc_cnf & ~SSCCNF_RW) | (val & SSCCNF_RW); + break; +case 0x08: /* bus timeout */ + ssc_bto = ssc_bto & ~(val & SSCBTO_W1C); + ssc_bto = (ssc_bto & ~SSCBTO_RW) | (val & SSCBTO_RW); + break; +case 0x0C: /* output port */ + ssc_otp = val & SSCOTP_MASK; + break; +case 0x1B: /* TODR */ + todr_wr (val); + break; +case 0x1C: /* CSRS */ + csrs_wr (val); + break; +case 0x1E: /* CSTS */ + csts_wr (val); + break; +case 0x1F: /* CSTD */ + cstd_wr (val); + break; +case 0x20: /* RXCS */ + rxcs_wr (val); + break; +case 0x22: /* TXCS */ + txcs_wr (val); + break; +case 0x23: /* TXDB */ + txdb_wr (val); + break; +case 0x40: /* T0CSR */ + tmr_csr_wr (0, val); + break; +case 0x42: /* T0NI */ + tmr_tnir[0] = val; + break; +case 0x43: /* T0VEC */ + tmr_tivr[0] = val & TMR_VEC_MASK; + break; +case 0x44: /* T1CSR */ + tmr_csr_wr (1, val); + break; +case 0x46: /* T1NI */ + tmr_tnir[1] = val; + break; +case 0x47: /* T1VEC */ + tmr_tivr[1] = val & TMR_VEC_MASK; + break; +case 0x4C: /* ADS0M */ + ssc_adsm[0] = val & SSCADS_MASK; + break; +case 0x4D: /* ADS0K */ + ssc_adsk[0] = val & SSCADS_MASK; + break; +case 0x50: /* ADS1M */ + ssc_adsm[1] = val & SSCADS_MASK; + break; +case 0x51: /* ADS1K */ + ssc_adsk[1] = val & SSCADS_MASK; + break; } +return; +} + +/* Programmable timers + + The SSC timers, which increment at 1Mhz, cannot be accurately + simulated due to the overhead that would be required for 1M + clock events per second. Instead, a gross hack is used. When + a timer is started, the clock interval is inspected. + + if (int < 0 and small) then testing timer, count instructions + if (int >= 0 or large) then counting a real interval, schedule + clock events at 100Hz using calibrated line clock delay + + If the interval register is read, then its value between events + is interpolated using the current instruction count versus the + count when the most recent event started. +*/ + +int32 tmr_tir_rd (int32 tmr, t_bool interp) +{ +uint32 delta; + +if (interp || (tmr_csr[tmr] & TMR_CSR_RUN)) { /* interp, running? */ + delta = sim_grtime () - tmr_sav[tmr]; /* delta inst */ + if (delta >= tmr_inc[tmr]) delta = tmr_inc[tmr] - 1; + return tmr_tir[tmr] + delta; } +return tmr_tir[tmr]; +} + +void tmr_csr_wr (int32 tmr, int32 val) +{ +if ((tmr < 0) || (tmr > 1)) return; +if ((val & TMR_CSR_RUN) == 0) { /* clearing run? */ + sim_cancel (&sysd_unit[tmr]); /* cancel timer */ + if (tmr_csr[tmr] & TMR_CSR_RUN) /* run 1 -> 0? */ + tmr_tir[tmr] = tmr_tir_rd (tmr, TRUE); } /* update itr */ +tmr_csr[tmr] = tmr_csr[tmr] & ~(val & TMR_CSR_W1C); /* W1C csr */ +tmr_csr[tmr] = (tmr_csr[tmr] & ~TMR_CSR_RW) | /* new r/w */ + (val & TMR_CSR_RW); +if (val & TMR_CSR_XFR) tmr_tir[tmr] = tmr_tnir[tmr]; /* xfr set? */ +if (val & TMR_CSR_RUN) { /* run? */ + if (val & TMR_CSR_XFR) /* new tir? */ + sim_cancel (&sysd_unit[tmr]); /* stop prev */ + if (!sim_is_active (&sysd_unit[tmr])) /* not running? */ + tmr_sched (tmr); } /* activate */ +else if (val & TMR_CSR_SGL) { /* single step? */ + tmr_incr (tmr, 1); /* incr tmr */ + if (tmr_tir[tmr] == 0) /* if ovflo, */ + tmr_tir[tmr] = tmr_tnir[tmr]; } /* reload tir */ +if ((tmr_csr[tmr] & (TMR_CSR_DON | TMR_CSR_IE)) != /* update int */ + (TMR_CSR_DON | TMR_CSR_IE)) { + if (tmr) CLR_INT (TMR1); + else CLR_INT (TMR0); } +return; +} + +/* Unit service */ + +t_stat tmr_svc (UNIT *uptr) +{ +int32 tmr = uptr - sysd_dev.units; /* get timer # */ + +tmr_incr (tmr, tmr_inc[tmr]); /* incr timer */ +return SCPE_OK; +} + +/* Timer increment */ + +void tmr_incr (int32 tmr, uint32 inc) +{ +uint32 new_tir = tmr_tir[tmr] + inc; /* add incr */ + +if (new_tir < tmr_tir[tmr]) { /* ovflo? */ + tmr_tir[tmr] = 0; /* now 0 */ + if (tmr_csr[tmr] & TMR_CSR_DON) /* done? set err */ + tmr_csr[tmr] = tmr_csr[tmr] | TMR_CSR_ERR; + else tmr_csr[tmr] = tmr_csr[tmr] | TMR_CSR_DON; /* set done */ + if (tmr_csr[tmr] & TMR_CSR_STP) /* stop? */ + tmr_csr[tmr] = tmr_csr[tmr] & ~TMR_CSR_RUN; /* clr run */ + if (tmr_csr[tmr] & TMR_CSR_RUN) { /* run? */ + tmr_tir[tmr] = tmr_tnir[tmr]; /* reload */ + tmr_sched (tmr); } /* reactivate */ + if (tmr_csr[tmr] & TMR_CSR_IE) { /* set int req */ + if (tmr) SET_INT (TMR1); + else SET_INT (TMR0); } } +else { tmr_tir[tmr] = new_tir; /* no, upd tir */ + if (tmr_csr[tmr] & TMR_CSR_RUN) /* still running? */ + tmr_sched (tmr); } /* reactivate */ +return; +} + +/* Timer scheduling */ + +void tmr_sched (int32 tmr) +{ +tmr_sav[tmr] = sim_grtime (); /* save intvl base */ +if (tmr_tir[tmr] > (0xFFFFFFFFu - TMR_INC)) { /* short interval? */ + tmr_inc[tmr] = (~tmr_tir[tmr] + 1); /* inc = interval */ + sim_activate (&sysd_unit[tmr], tmr_inc[tmr]); } +else { tmr_inc[tmr] = TMR_INC; /* usec/interval */ + sim_activate (&sysd_unit[tmr], tmr_poll); } /* use calib clock */ +return; +} + +int32 tmr0_inta (void) +{ +return tmr_tivr[0]; +} + +int32 tmr1_inta (void) +{ +return tmr_tivr[1]; +} + +/* SYSD reset */ + +t_stat sysd_reset (DEVICE *dptr) +{ +int32 i; + +for (i = 0; i < 2; i++) { + tmr_csr[i] = tmr_tnir[i] = tmr_tir[i] = 0; + tmr_inc[i] = tmr_sav[i] = 0; + sim_cancel (&sysd_unit[i]); } +csi_csr = 0; +csi_unit.buf = 0; +sim_cancel (&csi_unit); +CLR_INT (CSI); +cso_csr = CSR_DONE; +cso_unit.buf = 0; +sim_cancel (&cso_unit); +CLR_INT (CSO); +return SCPE_OK; +} + +/* SYSD powerup */ + +t_stat sysd_powerup (void) +{ +int32 i; + +for (i = 0; i < (CMCTLSIZE >> 2); i++) cmctl_reg[i] = 0; +for (i = 0; i < 2; i++) { + tmr_tivr[i] = 0; + ssc_adsm[i] = ssc_adsk[i] = 0; } +ka_cacr = 0; +ka_bdr = 0x80; +ssc_base = SSCBASE; +ssc_cnf = ssc_cnf & SSCCNF_BLO; +ssc_bto = 0; +ssc_otp = 0; +return sysd_reset (&sysd_dev); +} + diff --git a/VAX/vaxmod_defs.h b/VAX/vaxmod_defs.h new file mode 100644 index 00000000..9df63227 --- /dev/null +++ b/VAX/vaxmod_defs.h @@ -0,0 +1,351 @@ +/* vaxmod_defs.h: VAX model-specific definitions file + + Copyright (c) 1998-2002, Robert M Supnik + + Permission is hereby granted, free of charge, to any person obtaining a + copy of this software and associated documentation files (the "Software"), + to deal in the Software without restriction, including without limitation + the rights to use, copy, modify, merge, publish, distribute, sublicense, + and/or sell copies of the Software, and to permit persons to whom the + Software is furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + ROBERT M SUPNIK BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + Except as contained in this notice, the name of Robert M Supnik shall not + be used in advertising or otherwise to promote the sale, use or other dealings + in this Software without prior written authorization from Robert M Supnik. + + 14-Jul-02 RMS Added additional console halt codes + 28-Apr-02 RMS Fixed DZV vector base and number of lines + + This file covers the KA65x ("Mayfair") series of CVAX-based Qbus systems. + + System memory map + + 0000 0000 - 03FF FFFF main memory + 0400 0000 - 0FFF FFFF reserved + 1000 0000 - 13FF FFFF secondary cache diagnostic space + 1400 0000 - 1FFF FFFF reserved + + 2000 0000 - 2000 1FFF Qbus I/O page + 2000 2000 - 2003 FFFF reserved + 2004 0000 - 2005 FFFF ROM space, halt protected + 2006 0000 - 2007 FFFF ROM space, halt unprotected + 2008 0000 - 201F FFFF Local register space + 2020 0000 - 2FFF FFFF reserved + 3000 0000 - 303F FFFF Qbus memory space + 3400 0000 - 3FFF FFFF reserved +*/ + +/* Microcode constructs */ + +#define CVAX_SID (10 << 24) /* system ID */ +#define CVAX_UREV 6 /* ucode revision */ +#define CON_HLTPIN 0x0200 /* external CPU halt */ +#define CON_PWRUP 0x0300 /* powerup code */ +#define CON_HLTINS 0x0600 /* HALT instruction */ +#define CON_BADPSL 0x4000 /* invalid PSL flag */ +#define CON_MAPON 0x8000 /* mapping on flag */ +#define MCHK_TBM_P0 0x05 /* PPTE in P0 */ +#define MCHK_TBM_P1 0x06 /* PPTE in P1 */ +#define MCHK_M0_P0 0x07 /* PPTE in P0 */ +#define MCHK_M0_P1 0x08 /* PPTE in P1 */ +#define MCHK_INTIPL 0x09 /* invalid ireq */ +#define MCHK_READ 0x80 /* read check */ +#define MCHK_WRITE 0x82 /* write check */ + +/* Memory system error register */ + +#define MSER_HM 0x80 /* hit/miss */ +#define MSER_CPE 0x40 /* CDAL par err */ +#define MSER_CPM 0x20 /* CDAL mchk */ + +/* Cache disable register */ + +#define CADR_RW 0xF3 +#define CADR_MBO 0x0C + +/* Memory */ + +#define MAXMEMWIDTH 26 /* max mem addr width */ +#define MAXMEMSIZE (1 << MAXMEMWIDTH) /* max mem size */ +#define MAXMEMMASK (MAXMEMSIZE - 1) /* max mem addr mask */ +#define INITMEMSIZE (1 << 24) /* initial memory size */ +#define MEMSIZE (cpu_unit.capac) +#define ADDR_IS_MEM(x) (((t_addr) (x)) < MEMSIZE) + +/* Cache diagnostic space */ + +#define CDAAWIDTH 16 /* cache dat addr width */ +#define CDASIZE (1u << CDAAWIDTH) /* cache dat length */ +#define CDAMASK (CDASIZE - 1) /* cache dat mask */ +#define CTGAWIDTH 10 /* cache tag addr width */ +#define CTGSIZE (1u << CTGAWIDTH) /* cache tag length */ +#define CTGMASK (CTGSIZE - 1) /* cache tag mask */ +#define CDGSIZE (CDASIZE * CTGSIZE) /* diag addr length */ +#define CDGBASE 0x10000000 /* diag addr base */ +#define CDG_GETROW(x) (((x) & CDAMASK) >> 2) +#define CDG_GETTAG(x) (((x) >> CDAAWIDTH) & CTGMASK) +#define CTG_V (1u << (CTGAWIDTH + 0)) /* tag valid */ +#define CTG_WP (1u << (CTGAWIDTH + 1)) /* wrong parity */ +#define ADDR_IS_CDG(x) ((((t_addr) (x)) >= CDGBASE) && \ + (((t_addr) (x)) < (CDGBASE + CDGSIZE))) + +/* Qbus I/O registers */ + +#define IOPAGEAWIDTH 13 /* IO addr width */ +#define IOPAGESIZE (1u << IOPAGEAWIDTH) /* IO page length */ +#define IOPAGEMASK (IOPAGESIZE - 1) /* IO addr mask */ +#define IOPAGEBASE 0x20000000 /* IO page base */ +#define ADDR_IS_IO(x) ((((t_addr) (x)) >= IOPAGEBASE) && \ + (((t_addr) (x)) < (IOPAGEBASE + IOPAGESIZE))) + +/* Read only memory - appears twice */ + +#define ROMAWIDTH 17 /* ROM addr width */ +#define ROMSIZE (1u << ROMAWIDTH) /* ROM length */ +#define ROMAMASK (ROMSIZE - 1) /* ROM addr mask */ +#define ROMBASE 0x20040000 /* ROM base */ +#define ADDR_IS_ROM(x) ((((t_addr) (x)) >= ROMBASE) && \ + (((t_addr) (x)) < (ROMBASE + ROMSIZE + ROMSIZE))) + +/* Local register space */ + +#define REGAWIDTH 19 /* REG addr width */ +#define REGSIZE (1u << REGAWIDTH) /* REG length */ +#define REGBASE 0x20080000 /* REG addr base */ + +/* KA655 board registers */ + +#define KAAWIDTH 3 /* KA reg width */ +#define KASIZE (1u << KAAWIDTH) /* KA reg length */ +#define KABASE (REGBASE + 0x4000) /* KA650 addr base */ + +/* CQBIC registers */ + +#define CQBICSIZE (5 << 2) /* 5 registers */ +#define CQBICBASE (REGBASE) /* CQBIC addr base */ +#define CQMAPASIZE 15 /* map addr width */ +#define CQMAPSIZE (1u << CQMAPASIZE) /* map length */ +#define CQMAPAMASK (CQMAPSIZE - 1) /* map addr mask */ +#define CQMAPBASE (REGBASE + 0x8000) /* map addr base */ +#define CQIPCSIZE 2 /* 2 bytes only */ +#define CQIPCBASE (REGBASE + 0x1F40) /* ipc reg addr */ + +/* CMCTL registers */ + +#define CMCTLSIZE (18 << 2) /* 18 registers */ +#define CMCTLBASE (REGBASE + 0x100) /* CMCTL addr base */ + +/* SSC registers */ + +#define SSCSIZE 0x150 /* SSC size */ +#define SSCBASE 0x20140000 /* SSC base */ + +/* Non-volatile RAM - 1KB long */ + +#define NVRAWIDTH 10 /* NVR addr width */ +#define NVRSIZE (1u << NVRAWIDTH) /* NVR length */ +#define NVRAMASK (NVRSIZE - 1) /* NVR addr mask */ +#define NVRBASE 0x20140400 /* NVR base */ +#define ADDR_IS_NVR(x) ((((t_addr) (x)) >= NVRBASE) && \ + (((t_addr) (x)) < (NVRBASE + NVRSIZE))) + +/* CQBIC Qbus memory space (seen from CVAX) */ + +#define CQMAWIDTH 22 /* Qmem addr width */ +#define CQMSIZE (1u << CQMAWIDTH) /* Qmem length */ +#define CQMAMASK (CQMSIZE - 1) /* Qmem addr mask */ +#define CQMBASE 0x30000000 /* Qmem base */ + +/* Qbus I/O modes */ + +#define READ 0 /* PDP-11 compatibility */ +#define WRITE (L_WORD) +#define WRITEB (L_BYTE) + +/* Common CSI flags */ + +#define CSR_V_GO 0 /* go */ +#define CSR_V_IE 6 /* interrupt enable */ +#define CSR_V_DONE 7 /* done */ +#define CSR_V_BUSY 11 /* busy */ +#define CSR_V_ERR 15 /* error */ +#define CSR_GO (1u << CSR_V_GO) +#define CSR_IE (1u << CSR_V_IE) +#define CSR_DONE (1u << CSR_V_DONE) +#define CSR_BUSY (1u << CSR_V_BUSY) +#define CSR_ERR (1u << CSR_V_ERR) + +/* IO parameters */ + +#define DZ_MUXES 4 /* max # of muxes */ +#define DZ_LINES 4 /* (DZV) lines per mux */ +#define MT_MAXFR (1 << 16) /* magtape max rec */ + +/* Timers */ + +#define TMR_CLK 0 /* 100Hz clock */ + +/* I/O system definitions */ + +/* Device information block */ + +struct pdp_dib { + uint32 enb; /* enabled */ + uint32 ba; /* base addr */ + uint32 lnt; /* length */ + t_stat (*rd)(int32 *dat, int32 ad, int32 md); + t_stat (*wr)(int32 dat, int32 ad, int32 md); }; + +typedef struct pdp_dib DIB; + +/* I/O page layout */ + +#define IOBA_DZ (IOPAGEBASE + 000100) /* DZ11 */ +#define IOLN_DZ 010 +#define IOBA_RQ (IOPAGEBASE + 012150) /* RQDX3 */ +#define IOLN_RQ 004 +#define IOBA_TS (IOPAGEBASE + 012520) /* TS11 */ +#define IOLN_TS 004 +#define IOBA_RL (IOPAGEBASE + 014400) /* RL11 */ +#define IOLN_RL 012 +#define IOBA_RP (IOPAGEBASE + 016700) /* RP/RM */ +#define IOLN_RP 054 +#define IOBA_DBL (IOPAGEBASE + 017500) /* doorbell */ +#define IOLN_DBL 002 +#define IOBA_LPT (IOPAGEBASE + 017514) /* LP11 */ +#define IOLN_LPT 004 +#define IOBA_PT (IOPAGEBASE + 017550) /* PC11 */ +#define IOLN_PT 010 + +/* The KA65x maintains 4 separate hardware IPL levels, IPL 17 to IPL 14 + Within each IPL, priority is right to left +*/ + +/* IPL 17 */ + +/* IPL 16 */ + +#define INT_V_CLK 0 /* clock */ + +/* IPL 15 */ + +#define INT_V_RQ 0 /* RQDX3 */ +#define INT_V_RL 1 /* RLV12/RL02 */ +#define INT_V_DZRX 2 /* DZ11 */ +#define INT_V_DZTX 3 +#define INT_V_RP 4 /* RP,RM drives */ +#define INT_V_TS 5 /* TS11/TSV05 */ + +/* IPL 14 */ + +#define INT_V_TTI 0 /* console */ +#define INT_V_TTO 1 +#define INT_V_PTR 2 /* PC11 */ +#define INT_V_PTP 3 +#define INT_V_LPT 4 /* LP11 */ +#define INT_V_CSI 5 /* SSC cons UART */ +#define INT_V_CSO 6 +#define INT_V_TMR0 7 /* SSC timers */ +#define INT_V_TMR1 8 + +#define INT_CLK (1u << INT_V_CLK) +#define INT_RQ (1u << INT_V_RQ) +#define INT_RL (1u << INT_V_RL) +#define INT_DZRX (1u << INT_V_DZRX) +#define INT_DZTX (1u << INT_V_DZTX) +#define INT_RP (1u << INT_V_RP) +#define INT_TS (1u << INT_V_TS) +#define INT_TTI (1u << INT_V_TTI) +#define INT_TTO (1u << INT_V_TTO) +#define INT_PTR (1u << INT_V_PTR) +#define INT_PTP (1u << INT_V_PTP) +#define INT_LPT (1u << INT_V_LPT) +#define INT_CSI (1u << INT_V_CSI) +#define INT_CSO (1u << INT_V_CSO) +#define INT_TMR0 (1u << INT_V_TMR0) +#define INT_TMR1 (1u << INT_V_TMR1) + +#define IPL_CLK (0x16 - IPL_HMIN) /* relative IPL */ +#define IPL_RQ (0x15 - IPL_HMIN) +#define IPL_RL (0x15 - IPL_HMIN) +#define IPL_DZRX (0x15 - IPL_HMIN) +#define IPL_DZTX (0x15 - IPL_HMIN) +#define IPL_RP (0x15 - IPL_HMIN) +#define IPL_TS (0x15 - IPL_HMIN) +#define IPL_TTI (0x14 - IPL_HMIN) +#define IPL_TTO (0x14 - IPL_HMIN) +#define IPL_PTR (0x14 - IPL_HMIN) +#define IPL_PTP (0x14 - IPL_HMIN) +#define IPL_LPT (0x14 - IPL_HMIN) +#define IPL_CSI (0x14 - IPL_HMIN) +#define IPL_CSO (0x14 - IPL_HMIN) +#define IPL_TMR0 (0x14 - IPL_HMIN) +#define IPL_TMR1 (0x14 - IPL_HMIN) + +#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 0xF /* highest swre level */ + +#define VEC_Q 0x200 /* Qbus vector offset */ +#define VEC_PTR (VEC_Q + 0070) /* Qbus vectors */ +#define VEC_PTP (VEC_Q + 0074) +#define VEC_RQ (VEC_Q + 0154) +#define VEC_RL (VEC_Q + 0160) +#define VEC_LPT (VEC_Q + 0200) +#define VEC_TS (VEC_Q + 0224) +#define VEC_RP (VEC_Q + 0254) +#define VEC_DZRX (VEC_Q + 0300) +#define VEC_DZTX (VEC_Q + 0304) + +#define IREQ(dv) int_req[IPL_##dv] +#define SET_INT(dv) int_req[IPL_##dv] = int_req[IPL_##dv] | (INT_##dv) +#define CLR_INT(dv) int_req[IPL_##dv] = int_req[IPL_##dv] & ~(INT_##dv) +#define IORETURN(f,v) ((f)? (v): SCPE_OK) /* cond error return */ + +/* Logging */ + +#define LOG_CPU_I 0x001 /* intexc */ +#define LOG_CPU_R 0x002 /* REI */ +#define LOG_CPU_P 0x004 /* context */ +#define LOG_CPU_A 0x008 +#define LOG_RP 0x010 +#define LOG_TS 0x020 +#define LOG_RQ 0x040 + +#define DBG_LOG(x) (sim_log && (cpu_log & (x))) + +/* Function prototypes for I/O */ + +t_bool map_addr (t_addr qa, t_addr *ma); +int32 map_readB (t_addr ba, int32 bc, uint8 *buf); +int32 map_readW (t_addr ba, int32 bc, uint16 *buf); +int32 map_readL (t_addr ba, int32 bc, uint32 *buf); +int32 map_writeB (t_addr ba, int32 bc, uint8 *buf); +int32 map_writeW (t_addr ba, int32 bc, uint16 *buf); +int32 map_writeL (t_addr ba, int32 bc, uint32 *buf); + +/* Macros for PDP-11 compatibility */ + +#define QB 0 /* Q22 native */ +#define UB 1 /* Unibus */ + +#define Map_Addr(a,b) map_addr (a, b) +#define Map_ReadB(a,b,c,d) map_readB (a, b, c) +#define Map_ReadW(a,b,c,d) map_readW (a, b, c) +#define Map_WriteB(a,b,c,d) map_writeB (a, b, c) +#define Map_WriteW(a,b,c,d) map_writeW (a, b, c) +t_stat set_addr (UNIT *uptr, int32 val, char *cptr, void *desc); +t_stat show_addr (FILE *st, UNIT *uptr, int32 val, void *desc); +t_stat set_enbdis (UNIT *uptr, int32 val, char *cptr, void *desc); +t_bool dev_conflict (uint32 nba, DIB *curr); diff --git a/build_mingw.bat b/build_mingw.bat new file mode 100644 index 00000000..c5789784 --- /dev/null +++ b/build_mingw.bat @@ -0,0 +1,80 @@ +rem 18-May-02 rms VT emulation support +rem +rem Compile all of SIMH using MINGW gcc environment +rem Individual simulator sources are in .\simulator_name +rem Individual simulator executables are to .\bin +rem +rem If needed, define the path for the MINGW bin directory. +rem (this should already be set if MINGW was installed correctly) +rem +path c:\mingw\bin;%path% +rem +rem PDP-1 +rem +gcc -O0 -o .\bin\pdp1 -I. -I.\pdp1 scp*.c sim_vt.c .\pdp1\pdp1*.c +rem +rem PDP-11 +rem +gcc -O0 -o .\bin\pdp11 -I. -I.\pdp11 scp*.c sim*.c .\pdp11\pdp11*.c -lm -lwsock32 +rem +rem PDP-8 +rem +gcc -O0 -o .\bin\pdp8 -I. -I.\pdp8 scp*.c sim*.c .\pdp8\pdp8*.c -lm -lwsock32 +rem +rem PDP-4, PDP-7, PDP-9, PDP-15 +rem +gcc -O0 -DPDP4 -o .\bin\pdp4 -I. -I./pdp18b scp*.c sim*.c .\pdp18b\pdp18b*.c -lm -lwsock32 +gcc -O0 -DPDP7 -o .\bin\pdp7 -I. -I./pdp18b scp*.c sim*.c .\pdp18b\pdp18b*.c -lm -lwsock32 +gcc -O0 -DPDP9 -o .\bin\pdp9 -I. -I./pdp18b scp*.c sim*.c .\pdp18b\pdp18b*.c -lm -lwsock32 +gcc -O0 -DPDP15 -o .\bin\pdp15 -I. -I./pdp18b scp*.c sim*.c .\pdp18b\pdp18b*.c -lm -lwsock32 +rem +rem PDP-10 +rem +gcc -O0 -DUSE_INT64 -o .\bin\pdp10 -I. -I.\bin\pdp10 scp*.c sim*.c .\pdp10\pdp10*.c -lm -lwsock32 +rem +rem Nova, Eclipse +rem +gcc -O0 -o .\bin\nova -I. -I.\nova scp*.c sim*.c .\nova\nova*.c -lm -lwsock32 +gcc -O0 -DECLIPSE -o .\bin\eclipse -I. -I.\nova scp*.c sim*.c .\nova\eclipse_cpu.c .\nova\nova_clk.c .\nova\nova_dkp.c .\nova\nova_dsk.c .\nova\nova_lp.c .\nova\nova_mta.c .\nova\nova_plt.c .\nova\nova_pt.c .\nova\nova_sys.c .\nova\nova_tt.c .\nova\nova_tt1.c -lm -lwsock32 +rem +rem Altair +rem +gcc -O0 -o .\bin\altair -I. -I.\altair scp*.c sim_vt.c .\altair\altair*.c +rem +rem AltairZ80 +rem +gcc -O0 -o .\bin\altairz80 -I. -I.\altairz80 scp*.c sim*.c .\altairz80\altair*.c -lwsock32 +rem +rem H316 +rem +gcc -O0 -o .\bin\h316 -I. -I.\h316 scp*.c sim_vt.c .\h316\h316*.c +rem +rem HP2100 +rem +gcc -O0 -o .\bin\hp2100 -I. -I.\hp2100 scp*.c sim*.c .\hp2100\hp2100*.c -lwsock32 +rem +rem IBM 1401 +rem +gcc -O0 -o .\bin\i1401 -I. -I.\i1401 scp*.c sim_vt.c .\i1401\i1401*.c +rem +rem IBM System 3 +rem +gcc -O0 -o .\bin\s3 -I. -I.\s3 scp*.c sim_vt.c .\s3\s3*.c +rem +rem IBM 1130 +rem +gcc -O0 -o .\bin\ibm1130 -I. -I.\ibm1130 scp*.c sim_vt.c .\ibm1130\ibm1130*.c +rem +rem VAX +rem +gcc -O0 -DUSE_INT64 -o .\bin\vax -I. -I.\vax -I.\pdp11 scp*.c sim*.c .\pdp11\pdp11_rl.c .\pdp11\pdp11_rq.c .\pdp11\pdp11_dz.c .\pdp11\pdp11_lp.c .\pdp11\pdp11_ts.c .\vax\vax*.c -lm -lwsock32 +rem +rem GRI +rem +gcc -O0 -o .\bin\gri -I. -I.\gri scp*.c sim_vt.c .\gri\gri*.c +rem +rem Placeholders for future simulators +rem +rem gcc -O0 -o .\bin\sds -I. -I.\sds scp*.c sim*.c .\sds\sds*.c -lm -lwsock32 +rem gcc -O0 -o .\bin\id16 -I. -I.\interdata scp*.c sim*.c .\interdata\id16*.c .\interdata\id_*.c -lwsock32 +rem gcc -O0 -o .\bin\id32 -I. -I.\interdata scp*.c sim*.c .\interdata\id32*.c .\interdata\id_*.c -lwsock32 diff --git a/build_vms.com b/build_vms.com new file mode 100644 index 00000000..af8dec06 --- /dev/null +++ b/build_vms.com @@ -0,0 +1,1112 @@ +$! +$! BUILD_VMS.COM +$! Written By: Robert Alan Byer +$! byer@mail.ourservers.net +$! +$! +$! This script is used to compile and thar various simualtors in the SIMH +$! package for OpenVMS using DEC C v6.0-001. +$! +$! The script accepts the following parameters. +$! +$! P1 ALL Just Build "Everything". +$! ALTAIR Just Build The MITS Altair. +$! ALTAIRZ80 Just Build The MITS Altair Z80. +$! ECLIPSE Just Build The Data General Eclipse. +$! H316 Just Build The Honewell 316/516. +$! HP2100 Just Build The Hewlett-Packard HP-2100. +$! I1401 Just Build The IBM 1401. +$! IBM1130 Just Build The IBM 1130. +$! INTERDATA Just Build The Interdata 4. +$! NOVA Just Build The Data General Nova. +$! PDP1 Just Build The DEC PDP-1. +$! PDP8 Just Build The DEC PDP-8. +$! PDP10 Just Build The DEC PDP-10. +$! PDP11 Just Build The DEC PDP-11. +$! PDP18B Just Build The DEC PDP-4, PDP-7, PDP-9 And PDP-15. +$! S3 Just Build The IBM System 3. +$! SDS Just Build The SDS System. +$! VAX Just Build The DEC VAX. +$! +$! P2 DEBUG Link With Debugger Information. +$! NODEBUG Link Withoug Debugger Information. +$! +$! +$! The defaults are "ALL" and "NODEBUG". +$! +$! +$! Define The Simualtors We Have That We Can Build. +$! +$ SIMH_SIMS = "ALTAIR,ALTAIRZ80,ECLIPSE,H316,HP2100,I1401,IBM1130," + - + "INTERDATA,NOVA,PDP1,PDP8,PDP10,PDP11,PDP18B,S3,SDS,VAX" +$! +$! Check To Make Sure We Have Valid Command Line Parameters. +$! +$ GOSUB CHECK_OPTIONS +$! +$! Check To See If We Are On An AXP Machine. +$! +$ IF (F$GETSYI("CPU").LT.128) +$ THEN +$! +$! We Are On A VAX Machine So Tell The User. +$! +$ WRITE SYS$OUTPUT "Compiling On A VAX Machine." +$! +$! Define The Machine Type. +$! +$ MACHINE_TYPE = "VAX" +$! +$! Else, We Are On An AXP Machine. +$! +$ ELSE +$! +$! We Are On A AXP Machine So Tell The User. +$! +$ WRITE SYS$OUTPUT "Compiling On A AXP Machine." +$! +$! Define The Machine Type. +$! +$ MACHINE_TYPE = "AXP" +$! +$! End Of The Machine Check. +$! +$ ENDIF +$! +$! Define The Compile Command. +$! +$ CC = "CC/PREFIX=ALL/''OPTIMIZE'/''DEBUGGER'" + - + "/NEST=PRIMARY/NAME=(AS_IS,SHORTENED)" +$! +$! Define The SIMH Library Name. +$! +$ SIMHLIB_NAME = "SYS$DISK:[.LIB]SIMH-''MACHINE_TYPE'.OLB" +$! +$! Check To See What We Are To Do. +$! +$ IF (BUILDALL.NES."TRUE") +$ THEN +$! +$! Define The Name Of The Module We Are To Compile. +$! +$ SIMH_MOD_NAME = P1 +$! +$! Check To See If We Are Going To Build The PDP18B Simulators. +$! +$ IF (SIMH_MOD_NAME.EQS."PDP18B") +$ THEN +$! +$! Use The Special Build For PDP18B. +$! +$ GOSUB BUILD_PDP18B_MOD +$! +$! Else... +$! +$ ELSE +$! +$! Build Just What The User Wants Us To Build. +$! +$ GOSUB BUILD_SIMHLIB_MOD +$! +$! That's All, Time To EXIT. +$! +$ EXIT +$! +$! Time To Exit The PDP18B Check. +$! +$ ENDIF +$! +$! Time To End The BUILDALL Check. +$! +$ ENDIF +$! +$! Build The SIMH Library. +$! +$ GOSUB BUILD_SIMHLIB +$! +$! Define A Counter And Set It To "0". +$! +$ SIMH_MOD_COUNTER = 0 +$! +$! Top Of The Loop. +$! +$ NEXT_SIMH_MOD_NAME: +$! +$! O.K, Extract The File Module From The File List. +$! +$ SIMH_MOD_NAME = F$ELEMENT(SIMH_MOD_COUNTER,",",SIMH_SIMS) +$! +$! Check To See If We Are At The End Of The Simulator List. +$! +$ IF (SIMH_MOD_NAME.EQS.",") THEN GOTO SIMH_MOD_DONE +$! +$! Increment The Counter. +$! +$ SIMH_MOD_COUNTER = SIMH_MOD_COUNTER + 1 +$! +$! Check To See If We Are On VAX. +$! +$ IF (MACHINE_TYPE.EQS."VAX") +$ THEN +$! +$! Check To See If We Are Build The PDP10 or VAX Simulator. +$! +$ IF (SIMH_MOD_NAME.EQS."PDP10").OR.(SIMH_MOD_NAME.EQS."VAX") +$ THEN +$! +$! Tell The User We Can't Build PDP10 Or VAX On The VAX +$! Platform. +$! +$ WRITE SYS$OUTPUT "" +$ WRITE SYS$OUTPUT "Due to the use of INT64, the ''SIMH_MOD_NAME' simulator will not be built for the ''MACHINE_TYPE'" +$ WRITE SYS$OUTPUT "platform." +$ WRITE SYS$OUTPUT "" +$! +$! Skip And Go To The Next Simulator. +$! +$ GOTO NEXT_SIMH_MOD_NAME +$! +$! Time To End The PDP10 And VAX Check. +$! +$ ENDIF +$! +$! Time To End The VAX Check. +$! +$ ENDIF +$! +$! Check To See If We Are Going To Build The PDP18B Simulators. +$! +$ IF (SIMH_MOD_NAME.EQS."PDP18B") +$ THEN +$! +$! Use The Special Build For PDP18B. +$! +$ GOSUB BUILD_PDP18B_MOD +$! +$! Else... +$! +$ ELSE +$! +$! Build The Module. +$! +$ GOSUB BUILD_SIMHLIB_MOD +$! +$! Time To End The PDP18D Check. +$! +$ ENDIF +$! +$! Go Back And Get Another Module Name. +$! +$ GOTO NEXT_SIMH_MOD_NAME +$! +$! End Of The Module List. +$! +$ SIMH_MOD_DONE: +$! +$! All Done Building Modules, Time To EXIT. +$! +$ EXIT +$! +$! Build The SYS$DISK:[.LIB]SIMH-xxx.OLB Library. +$! +$ BUILD_SIMHLIB: +$! +$! Define The C INCLUDES We Are To Use. +$! +$ SIMHLIB_INCLUDES = "INCLUDE=(SYS$DISK:[])" +$! +$! Check To See If We Have A SYS$DISK:[.LIB] Dierctory To Put The +$! Library In. +$! +$ IF (F$SEARCH("SYS$DISK:[]LIB.DIR").EQS."") +$ THEN +$! +$! A SYS$DISK:[.LIB] Directory Dosen't Exist So Tell The User We +$! Are Going To Create One. +$! +$ WRITE SYS$OUTPUT "Creating SYS$DISK:[.LIB]" +$! +$! Create The Directory. +$! +$ CREATE/DIRECTORY SYS$DISK:[.LIB] +$! +$! Time To End The SYS$DISK:[.LIB] Directory Check. +$! +$ ENDIF +$! +$! Check To See If We Already Have A SYS$DISK:[.LIB]SIMH-xxx.OLB Library... +$! +$ IF (F$SEARCH(SIMHLIB_NAME).EQS."") +$ THEN +$! +$! Guess Not, Create The Library. +$! +$ LIBRARY/CREATE/OBJECT 'SIMHLIB_NAME' +$! +$! End The Library Check. +$! +$ ENDIF +$! +$! Tell The User What We Are Doing. +$! +$ WRITE SYS$OUTPUT "" +$ WRITE SYS$OUTPUT "Compling The ''SIMHLIB_NAME' Library." +$! +$! Tell The User What Compile Command We Are Going To Use. +$! +$ WRITE SYS$OUTPUT "Using Compile Command: ",CC,"/",SIMHLIB_INCLUDES +$ WRITE SYS$OUTPUT "" +$! +$! Top Of The File Loop. +$! +$ NEXT_SIMHLIB_FILE: +$! +$! Define The List Of Files We Are Going To Compile. +$! +$ SIMHLIB_FILES = F$ELEMENT(0,";",F$ELEMENT(1,"]",F$SEARCH("SYS$DISK:[]*.C",1))) +$! +$! Extract The File Name From The File List. +$! +$ SIMHLIB_FILE_NAME = F$ELEMENT(0,".",SIMHLIB_FILES) +$! +$! Check To See If We Are At The End Of The File List. +$! +$ IF (SIMHLIB_FILE_NAME.EQS."]") THEN GOTO SIMHLIB_FILE_DONE +$! +$! Check To See If We We Are At The SCP.C File. +$! +$ IF (SIMHLIB_FILE_NAME.EQS."SCP") +$ THEN +$! +$! Since We Are At The SCP.C File, Go Back And +$! Get Another One As We Don't Want Add This To The Library. +$! +$ GOTO NEXT_SIMHLIB_FILE +$! +$! Time To End The SCP.C Check. +$! +$ ENDIF +$! +$! Create The Source File Name. +$! +$ SIMHLIB_SOURCE_FILE = "SYS$DISK:[]" + SIMHLIB_FILE_NAME + ".C" +$! +$! Create The Object File Name. +$! +$ SIMHLIB_OBJECT_FILE = "SYS$DISK:[]" + SIMHLIB_FILE_NAME + ".OBJ" +$! +$! Tell The User What We Are Compiling. +$! +$ WRITE SYS$OUTPUT " ",SIMHLIB_SOURCE_FILE +$! +$! Compile The File. +$! +$ CC/'SIMHLIB_INCLUDES'/OBJECT='SIMHLIB_OBJECT_FILE' 'SIMHLIB_SOURCE_FILE' +$! +$! Add It To The Library. +$! +$ LIBRARY/REPLACE/OBJECT 'SIMHLIB_NAME' 'SIMHLIB_OBJECT_FILE' +$! +$! Delete The Object File. +$! +$ DELETE/NOCONFIRM/NOLOG 'SIMHLIB_OBJECT_FILE';* +$! +$! Go Back And Do It Again. +$! +$ GOTO NEXT_SIMHLIB_FILE +$! +$! All Done Compiling. +$! +$ SIMHLIB_FILE_DONE: +$! +$! That's It, Time To Return From Where We Came From. +$! +$ RETURN +$! +$! Build The Libraries And Simulators.. +$! +$ BUILD_SIMHLIB_MOD: +$! +$! Check To See If We Are Going To Build The VAX Simulator. +$! +$ IF (SIMH_MOD_NAME.EQS."VAX") +$ THEN +$! +$! Define The C INCLUDES For The VAX Simulator. +$! +$ SIMHLIB_MOD_INCLUDES = "/INCLUDE=(SYS$DISK:[]," + - + "SYS$DISK:[.''SIMH_MOD_NAME']," + - + "SYS$DISK:[.PDP11])" +$! +$! Else... +$! +$ ELSE +$! +$! Define The Standard C INCLUDES We Are To Use. +$! +$ SIMHLIB_MOD_INCLUDES = "/INCLUDE=(SYS$DISK:[]," + - + "SYS$DISK:[.''SIMH_MOD_NAME'])" +$! +$! Time To End The VAX Check. +$! +$ ENDIF +$! +$! Check To See If We Are Going To Build The Eclipse Simulator. +$! +$ IF (SIMH_MOD_NAME.EQS."ECLIPSE") +$ THEN +$! +$! Define The Module Directory For The Eclipse Simulator. +$! +$ SIMHLIB_MOD_DIR = "SYS$DISK:[.NOVA]" +$! +$! Else... +$! +$ ELSE +$! +$! Define The Module Directory. +$! +$ SIMHLIB_MOD_DIR = "SYS$DISK:[.''SIMH_MOD_NAME']" +$! +$! Time To End The Ecplise Simulator Check. +$! +$ ENDIF +$! +$! Check To See If We Are Going To Build The Eclipse Simulator. +$! +$ IF (SIMH_MOD_NAME.EQS."ECLIPSE") +$ THEN +$! +$! Set The Compiler DEFINES For The Eclipse Simulator. +$! +$ SIMHLIB_MOD_DEFINE = "/DEFINE=(""ECLIPSE=1"")" +$! +$! Else... +$! +$ ELSE +$! +$! Check To See If We Are Going To Build The PDP10 Or VAX Simulator. +$! +$ IF (SIMH_MOD_NAME.EQS."PDP10").OR.(SIMH_MOD_NAME.EQS."VAX") +$ THEN +$! +$! Set The Compiler DEFINES For The PDP10 Simulator. +$! +$ SIMHLIB_MOD_DEFINE = "/DEFINE=(""USE_INT64=1"")" +$! +$! Else... +$! +$ ELSE +$! +$! Set The Compiler Defines For Everything Else. +$! +$ SIMHLIB_MOD_DEFINE = "" +$! +$! Time To End The PDP10 And VAX Simulator Check. +$! +$ ENDIF +$! +$! Time To End The Eclipse Simulator Check. +$! +$ ENDIF +$! +$! Check To See If There Are Any Files In The Module Directory. +$! +$ IF (F$SEARCH("''SIMHLIB_MOD_DIR'*.C").EQS."") +$ THEN +$! +$! There Are No Files To Compile In The Module Directory So +$! RETURN From Where We Came From And Get Another Module Name. +$! +$ RETURN +$! +$! Time To End The File Check. +$! +$ ENDIF +$! +$! Check To See If We Have A SYS$DISK:[.LIB] Dierctory To Put The +$! Library In. +$! +$ IF (F$SEARCH("SYS$DISK:[]LIB.DIR").EQS."") +$ THEN +$! +$! A SYS$DISK:[.LIB] Directory Dosen't Exist So Tell The User We +$! Are Going To Create One. +$! +$ WRITE SYS$OUTPUT "Creating SYS$DISK:[.LIB]" +$! +$! Create The Directory. +$! +$ CREATE/DIRECTORY SYS$DISK:[.LIB] +$! +$! Time To End The SYS$DISK:[.LIB] Directory Check. +$! +$ ENDIF +$! +$! Create The Module Library Name. +$! +$ SIMHLIB_MOD_LIB_NAME = "SYS$DISK:[.LIB]''SIMH_MOD_NAME'-''MACHINE_TYPE'" + - + ".OLB" +$! +$! Check To See If We Already Have A Library... +$! +$ IF (F$SEARCH("''SIMHLIB_MOD_LIB_NAME'").EQS."") +$ THEN +$! +$! Guess Not, Create The Library. +$! +$ LIBRARY/CREATE/OBJECT 'SIMHLIB_MOD_LIB_NAME' +$! +$! End The Library Check. +$! +$ ENDIF +$! +$! Tell The User What We Are Doing. +$! +$ WRITE SYS$OUTPUT "" +$ WRITE SYS$OUTPUT "Compling The ''SIMHLIB_MOD_LIB_NAME' Library." +$! +$! Tell The User What Compile Command We Are Going To Use. +$! +$ WRITE SYS$OUTPUT "Using Compile Command: ",CC,"''SIMHLIB_MOD_INCLUDES'", - + SIMHLIB_MOD_DEFINE +$ WRITE SYS$OUTPUT "" +$! +$! Top Of The File Loop. +$! +$ NEXT_SIMHLIB_MOD_FILE: +$! +$! Check To See If We Are Going To Build Nova. +$! +$ IF (SIMH_MOD_NAME.EQS."NOVA") +$ THEN +$! +$! Since Nova And Eclipse Share The Same Directory We Only Want The +$! Nova Files When We Build Nova. +$! +$ SIMHLIB_MOD_FILES = F$ELEMENT(0,";",F$ELEMENT(1,"]", - + F$SEARCH("''SIMHLIB_MOD_DIR'''SIMH_MOD_NAME'*.C",1))) +$! +$! Else... +$! +$ ELSE +$! +$! Define The List Of Files We Are Going To Compile. +$! +$ SIMHLIB_MOD_FILES = F$ELEMENT(0,";",F$ELEMENT(1,"]", - + F$SEARCH("''SIMHLIB_MOD_DIR'*.C",1))) +$! +$! Time To End The Nova Simulator Check. +$! +$ ENDIF +$! +$! Extract The File Name From The File List. +$! +$ SIMHLIB_MOD_FILE_NAME = F$ELEMENT(0,".",SIMHLIB_MOD_FILES) +$! +$! Check To See If We Are At The End Of The File List. +$! +$ IF (SIMHLIB_MOD_FILE_NAME.EQS."]") THEN GOTO SIMHLIB_MOD_FILE_DONE +$! +$! Check To See If We Building Eclipse. +$! +$ IF (SIMH_MOD_NAME.EQS."ECLIPSE") +$ THEN +$! +$! Check To See If We We Are At The NOVA_CPU.C Or NOVA_TT.C File. +$! +$ IF (SIMHLIB_MOD_FILE_NAME.EQS."NOVA_CPU").OR. - + (SIMHLIB_MOD_FILE_NAME.EQS."NOVA_TT") +$ THEN +$! +$! Since We Building The Eclipse And Are At The Either The NOVA_CPU.C Or +$! NOVA_TT.C File, Go Back And Get Another File As We Don't Want Add +$! These To The Eclipse Library. +$! +$ GOTO NEXT_SIMHLIB_MOD_FILE +$! +$! Time To End The NOVA_CPU.C Check. +$! +$ ENDIF +$! +$! Time To End The Eclipse Check. +$! +$ ENDIF +$! +$! Check To See If We Building IBM 1130 +$! +$ IF (SIMH_MOD_NAME.EQS."IBM1130") +$ THEN +$! +$! Check To See If We We Are At The SYS$DISK:[.IBM1130]SCP.C File. +$! +$ IF (SIMHLIB_MOD_FILE_NAME.EQS."SCP") +$ THEN +$! +$! Since We Are Building The IBM 1130 Without The GUI Front Panel +$! Interface (For Now), Go Back And Get Another File As We Don't +$! Want To Add This To The IBM 1130 Library. +$! +$ GOTO NEXT_SIMHLIB_MOD_FILE +$! +$! Time To End The SYS$DISK:[.IBM1130]SCP.C Check. +$! +$ ENDIF +$! +$! Time To End The IBM 1130 Check. +$! +$ ENDIF +$! +$! Create The Source File Name. +$! +$ SIMHLIB_MOD_SOURCE_FILE = "''SIMHLIB_MOD_DIR'''SIMHLIB_MOD_FILE_NAME'.C" +$! +$! Create The Object File Name. +$! +$ SIMHLIB_MOD_OBJECT_FILE = "''SIMHLIB_MOD_DIR'''SIMHLIB_MOD_FILE_NAME'.OBJ" +$! +$! Tell The User What We Are Compiling. +$! +$ WRITE SYS$OUTPUT " ",SIMHLIB_MOD_SOURCE_FILE +$! +$! Compile The File. +$! +$ CC 'SIMHLIB_MOD_INCLUDES''SIMHLIB_MOD_DEFINE'/OBJECT='SIMHLIB_MOD_OBJECT_FILE' - + 'SIMHLIB_MOD_SOURCE_FILE' +$! +$! Add It To The Library. +$! +$ LIBRARY/REPLACE/OBJECT 'SIMHLIB_MOD_LIB_NAME' 'SIMHLIB_MOD_OBJECT_FILE' +$! +$! Delete The Object File. +$! +$ DELETE/NOCONFIRM/NOLOG 'SIMHLIB_MOD_OBJECT_FILE';* +$! +$! Go Back And Do It Again. +$! +$ GOTO NEXT_SIMHLIB_MOD_FILE +$! +$! All Done Compiling. +$! +$ SIMHLIB_MOD_FILE_DONE: +$! +$! Check To See If We Are Building The VAX Simulator. +$! +$ IF (SIMH_MOD_NAME.EQS."VAX") +$ THEN +$! +$! Define The PDP11 Files We Need To Include In The SYS$DISK:[.LIB]VAX-xxx.OLB +$! Library. +$! +$ SIMH_PDP11_LIST = "PDP11_RL,PDP11_RQ,PDP11_TS,PDP11_DZ,PDP11_LP" +$! +$! Define A Counter And Set It To "0". +$! +$ SIMH_PDP11_COUNTER = 0 +$! +$! Top Of The Loop. +$! +$ NEXT_SIMH_PDP11_NAME: +$! +$! O.K, Extract The PDP11 File From The File List. +$! +$ SIMH_PDP11_FILE_NAME = F$ELEMENT(SIMH_PDP11_COUNTER,",",SIMH_PDP11_LIST) +$! +$! Check To See If We Are At The End Of The PDP11 List. +$! +$ IF (SIMH_PDP11_FILE_NAME.EQS.",") THEN GOTO SIMH_PDP11_FILE_DONE +$! +$! Increment The Counter. +$! +$ SIMH_PDP11_COUNTER = SIMH_PDP11_COUNTER + 1 +$! +$! Create The Source File Name. +$! +$ SIMH_PDP11_SOURCE_FILE = "SYS$DISK:[.PDP11]''SIMH_PDP11_FILE_NAME'.C" +$! +$! Create The Object File Name. +$! +$ SIMH_PDP11_OBJECT_FILE = "SYS$DISK:[.PDP11]''SIMH_PDP11_FILE_NAME'.OBJ" +$! +$! Tell The User What We Are Compiling. +$! +$ WRITE SYS$OUTPUT " ",SIMH_PDP11_SOURCE_FILE +$! +$! Compile The File. +$! +$ CC 'SIMHLIB_MOD_INCLUDES''SIMHLIB_MOD_DEFINE' - + /OBJECT='SIMH_PDP11_OBJECT_FILE' 'SIMH_PDP11_SOURCE_FILE' +$! +$! Add It To The Library. +$! +$ LIBRARY/REPLACE/OBJECT 'SIMHLIB_MOD_LIB_NAME' 'SIMH_PDP11_OBJECT_FILE' +$! +$! Delete The Object File. +$! +$ DELETE/NOCONFIRM/NOLOG 'SIMH_PDP11_OBJECT_FILE';* +$! +$! Go Back And Do It Again. +$! +$ GOTO NEXT_SIMH_PDP11_NAME +$! +$! All Done Compiling. +$! +$ SIMH_PDP11_FILE_DONE: +$! +$! Time To End The VAX Check. +$! +$ ENDIF +$! +$! Display A Blank Line. +$! +$ WRITE SYS$OUTPUT "" +$! +$! Check To See If We Have The SYS$DISK:[.LIB]SIMH-xxx.OLB Library. +$! +$ IF (F$SEARCH("SYS$DISK:[.LIB]SIMH-''MACHINE_TYPE'.OLB").EQS."") +$ THEN +$! +$! Guess Not, So Build The SYS$DISK:[.LIB]SIMH-xxx.OLB Library. +$! +$ GOSUB BUILD_SIMHLIB +$! +$! End The SYS$DISK:[.LIB]SIMH-xxx.OLB Library Check. +$! +$ ENDIF +$! +$! Check To See If We Have A SYS$DISK:[.BIN] Dierctory To Put The +$! Executable In. +$! +$ IF (F$SEARCH("SYS$DISK:[]BIN.DIR").EQS."") +$ THEN +$! +$! A SYS$DISK:[.BIN] Directory Dosen't Exist So Tell The User We +$! Are Going To Create One. +$! +$ WRITE SYS$OUTPUT "Creating SYS$DISK:[.BIN]" +$! +$! Create The Directory. +$! +$ CREATE/DIRECTORY SYS$DISK:[.BIN] +$! +$! Time To End The SYS$DISK:[.BIN] Directory Check. +$! +$ ENDIF +$! +$! Tell The User What We Building. +$! +$ WRITE SYS$OUTPUT "" +$ WRITE SYS$OUTPUT "Building SYS$DISK:[.BIN]''SIMH_MOD_NAME'-''MACHINE_TYPE'.EXE" +$! +$! Compile The SYS$DISK:[]SCP.C File. +$! +$ CC 'SIMHLIB_MOD_INCLUDES''SIMHLIB_MOD_DEFINE' - + /OBJECT=SYS$DISK:[]SCP-'MACHINE_TYPE'.OBJ SYS$DISK:[]SCP.C +$! +$! Link The Simulator. +$! +$ LINK/'DEBUGGER'/'TRACEBACK' - + /EXE=SYS$DISK:[.BIN]'SIMH_MOD_NAME'-'MACHINE_TYPE'.EXE - + SYS$DISK:[]SCP-'MACHINE_TYPE'.OBJ,'SIMHLIB_MOD_LIB_NAME'/LIBRARY, - + 'SIMHLIB_NAME'/LIBRARY +$! +$! Delete The SYS$DISK:[]SCP-xxx.OBJ File. +$! +$ DELETE/NOCONFIRM/NOLOG SYS$DISK:[]SCP*.OBJ*;* +$! +$! Time To Return From Where We Came From. +$! +$ RETURN +$! +$! Build The PDP18B Systems. +$! +$ BUILD_PDP18B_MOD: +$! +$! Define The PDP18B System We Are To Build. +$! +$ SIMH_PDP18B_MODS = "PDP4,PDP7,PDP9,PDP15" +$! +$! Define The Compiler INCLUDES. +$! +$ SIMH_PDP18B_INCLUDE = "/INCLUDE=(SYS$DISK:[],SYS$DISK:[.PDP18B])" +$! +$! Define A Counter And Set It To "0". +$! +$ SIMH_PDP18B_COUNTER = 0 +$! +$! Top Of The Loop. +$! +$ NEXT_SIMH_PDP18B_NAME: +$! +$! O.K, Extract The File Module From The File List. +$! +$ SIMH_PDP18B_NAME = F$ELEMENT(SIMH_PDP18B_COUNTER,",",SIMH_PDP18B_MODS) +$! +$! Check To See If We Are At The End Of The PDP18B List. +$! +$ IF (SIMH_PDP18B_NAME.EQS.",") THEN GOTO SIMH_PDP18B_DONE +$! +$! Increment The Counter. +$! +$ SIMH_PDP18B_COUNTER = SIMH_PDP18B_COUNTER + 1 +$! +$! Define The Compiler DEFINES. +$! +$ SIMH_PDP18B_DEFINE = "/DEFINE=(""''SIMH_PDP18B_NAME'=1"")" +$! +$! Check To See If We Have A SYS$DISK:[.LIB] Dierctory To Put The +$! Library In. +$! +$ IF (F$SEARCH("SYS$DISK:[]LIB.DIR").EQS."") +$ THEN +$! +$! A SYS$DISK:[.LIB] Directory Dosen't Exist So Tell The User We +$! Are Going To Create One. +$! +$ WRITE SYS$OUTPUT "Creating SYS$DISK:[.LIB]" +$! +$! Create The Directory. +$! +$ CREATE/DIRECTORY SYS$DISK:[.LIB] +$! +$! Time To End The SYS$DISK:[.LIB] Directory Check. +$! +$ ENDIF +$! +$! Create The Module Library Name. +$! +$ SIMH_PDP18B_LIB_NAME = "SYS$DISK:[.LIB]''SIMH_PDP18B_NAME'-" + - + "''MACHINE_TYPE'.OLB" +$! +$! Check To See If We Already Have A Library... +$! +$ IF (F$SEARCH(SIMH_PDP18B_LIB_NAME).EQS."") +$ THEN +$! +$! Guess Not, Create The Library. +$! +$ LIBRARY/CREATE/OBJECT 'SIMH_PDP18B_LIB_NAME' +$! +$! End The Library Check. +$! +$ ENDIF +$! +$! Tell The User What We Are Doing. +$! +$ WRITE SYS$OUTPUT "" +$ WRITE SYS$OUTPUT "Compling The ''SIMH_PDP18B_LIB_NAME' Library." +$! +$! Tell The User What Compile Command We Are Going To Use. +$! +$ WRITE SYS$OUTPUT "Using Compile Command: ",CC,SIMH_PDP18B_DEFINE, - + SIMH_PDP18B_INCLUDE +$ WRITE SYS$OUTPUT "" +$! +$! Top Of The File Loop. +$! +$ NEXT_SIMH_PDP18B_FILE: +$! +$! Define The List Of Files We Are Going To Compile. +$! +$ SIMH_PDP18B_FILES = F$ELEMENT(0,";",F$ELEMENT(1,"]",- + F$SEARCH("SYS$DISK:[.PDP18B]*.C",1))) +$! +$! Extract The File Name From The File List. +$! +$ SIMH_PDP18B_FILE_NAME = F$ELEMENT(0,".",SIMH_PDP18B_FILES) +$! +$! Check To See If We Are At The End Of The File List. +$! +$ IF (SIMH_PDP18B_FILE_NAME.EQS."]") THEN GOTO SIMH_PDP18B_FILE_DONE + +$! +$! Create The Source File Name. +$! +$ SIMH_PDP18B_SOURCE_FILE = "SYS$DISK:[.PDP18B]" + SIMH_PDP18B_FILE_NAME + ".C" +$! +$! Create The Object File Name. +$! +$ SIMH_PDP18B_OBJECT_FILE = "SYS$DISK:[.PDP18B]" + SIMH_PDP18B_FILE_NAME + - + ".OBJ" +$! +$! Tell The User What We Are Compiling. +$! +$ WRITE SYS$OUTPUT " ",SIMH_PDP18B_SOURCE_FILE +$! +$! Compile The File. +$! +$ CC 'SIMH_PDP18B_DEFINE''SIMH_PDP18B_INCLUDE' - + /OBJECT='SIMH_PDP18B_OBJECT_FILE' 'SIMH_PDP18B_SOURCE_FILE' +$! +$! Add It To The Library. +$! +$ LIBRARY/REPLACE/OBJECT 'SIMH_PDP18B_LIB_NAME' 'SIMH_PDP18B_OBJECT_FILE' +$! +$! Delete The Object File. +$! +$ DELETE/NOCONFIRM/NOLOG 'SIMH_PDP18B_OBJECT_FILE';* +$! +$! Go Back And Do It Again. +$! +$ GOTO NEXT_SIMH_PDP18B_FILE +$! +$! All Done Compiling. +$! +$ SIMH_PDP18B_FILE_DONE: +$! +$! Display A Blank Line. +$! +$ WRITE SYS$OUTPUT "" +$! +$! Check To See If We Have The SYS$DISK:[.LIB]SIMH-xxx.OLB Library. +$! +$ IF (F$SEARCH("SYS$DISK:[.LIB]SIMH-''MACHINE_TYPE'.OLB").EQS."") +$ THEN +$! +$! Guess Not, So Build The SYS$DISK:[.LIB]SIMH-xxx.OLB Library. +$! +$ GOSUB BUILD_SIMHLIB +$! +$! End The SYS$DISK:[.LIB]SIMH-xxx.OLB Library Check. +$! +$ ENDIF +$! +$! Check To See If We Have A SYS$DISK:[.BIN] Dierctory To Put The +$! Executable In. +$! +$ IF (F$SEARCH("SYS$DISK:[]BIN.DIR").EQS."") +$ THEN +$! +$! A SYS$DISK:[.BIN] Directory Dosen't Exist So Tell The User We +$! Are Going To Create One. +$! +$ WRITE SYS$OUTPUT "Creating SYS$DISK:[.BIN]" +$! +$! Create The Directory. +$! +$ CREATE/DIRECTORY SYS$DISK:[.BIN] +$! +$! Time To End The SYS$DISK:[.BIN] Directory Check. +$! +$ ENDIF +$! +$! Tell The User What We Building. +$! +$ WRITE SYS$OUTPUT "" +$ WRITE SYS$OUTPUT "Building SYS$DISK:[.BIN]''SIMH_PDP18B_NAME'-''MACHINE_TYPE'.EXE" +$! +$! Compile The SYS$DISK:[]SCP.C File. +$! +$ CC 'SIMH_PDP18_MOD_INCLUDES''SIMH_PDP18B_MOD_DEFINE' - + /OBJECT=SYS$DISK:[]SCP-'MACHINE_TYPE'.OBJ SYS$DISK:[]SCP.C +$! +$! Link The Simulator. +$! +$ LINK/'DEBUGGER'/'TRACEBACK' - + /EXE=SYS$DISK:[.BIN]'SIMH_PDP18B_NAME'-'MACHINE_TYPE'.EXE - + SYS$DISK:[]SCP-'MACHINE_TYPE'.OBJ,'SIMH_PDP18B_LIB_NAME'/LIBRARY, - + 'SIMHLIB_NAME'/LIBRARY +$! +$! Delete The SYS$DISK:[]SCP-xxx.OBJ File. +$! +$ DELETE/NOCONFIRM/NOLOG SYS$DISK:[]SCP*.OBJ*;* +$! +$! Go Back And Do The Next PDP18B Module. +$! +$ GOTO NEXT_SIMH_PDP18B_NAME +$! +$! End Of The PDP18B Module List. +$! +$ SIMH_PDP18B_DONE: +$! +$! All Done, Time To Return From Where We Came From. +$! +$ RETURN +$! +$! Check The User's Options. +$! +$ CHECK_OPTIONS: +$! +$! Define A Counter And Set It To "0". +$! +$ SIMH_SIMS_COUNTER = 0 +$! +$! Check To See If We Are To "Just Build Everything." +$! +$ IF (P1.EQS."").OR.(P1.EQS."ALL") +$ THEN +$! +$! P1 Is Blank Or "ALL", So Just Build Everything. +$! +$ BUILDALL = "TRUE" +$! +$! Else +$! +$ ELSE +$! +$! Top Of The Loop. +$! +$ NEXT_SIMH_SIMS: +$! +$! O.K, Extract The File Name From The File List. +$! +$ SIMH_SIMS_NAME = F$ELEMENT(SIMH_SIMS_COUNTER,",",SIMH_SIMS) +$! +$! Check To See If We Are At The End Of The Simulator List. +$! +$ IF (SIMH_SIMS_NAME.EQS.",") THEN GOTO SIMH_SIMS_ERROR +$! +$! Increment The Counter. +$! +$ SIMH_SIMS_COUNTER = SIMH_SIMS_COUNTER + 1 +$! +$! Check To See If P1 Has A Valid Argument. +$! +$ IF (P1.EQS.SIMH_SIMS_NAME) +$ THEN +$! +$! A Valid Argument. +$! +$ BUILDALL = P1 +$! +$! Exit This Routine. +$! +$ GOTO SIMH_CHECK_OPT_DONE +$! +$! Else... +$! +$ ELSE +$! +$! Go Back And Check Agianst The Next Sim In The List. +$! +$ GOTO NEXT_SIMH_SIMS +$! +$! Time To End The Valid Argument Check. +$! +$ ENDIF +$! +$! We Don't Know What The User Entered, So Tell Them. +$! +$ SIMH_SIMS_ERROR: +$! +$! Tell The User We Don't Know What They Want. +$! +$ WRITE SYS$OUTPUT "" +$ WRITE SYS$OUTPUT "The Option ",P1," Is Invalid. The Valid Options Are:" +$ WRITE SYS$OUTPUT "" +$ WRITE SYS$OUTPUT " ALL : Just Build "Everything". +$ WRITE SYS$OUTPUT " ALTAIR : Just Build The MITS Altair." +$ WRITE SYS$OUTPUT " ALTAIRZ80 : Just Build The MITS Altair Z80." +$ WRITE SYS$OUTPUT " ECLIPSE : Just Build The Data General Eclipse." +$ WRITE SYS$OUTPUT " H316 : Just Build The Honewell 316/516." +$ WRITE SYS$OUTPUT " HP2100 : Just Build The Hewlett-Packard HP-3100." +$ WRITE SYS$OUTPUT " I1401 : Just Build The IBM 1401." +$ WRITE SYS$OUTPUT " IBM1130 : Just Build The IBM 1130." +$ WRITE SYS$OUTPUT " INTERDATA : Just Build The Interdata 4." +$ WRITE SYS$OUTPUT " NOVA : Just Build The Data General Nova." +$ WRITE SYS$OUTPUT " PDP1 : Just Build The DEC PDP-1." +$ WRITE SYS$OUTPUT " PDP8 : Just Build The DEC PDP-8." +$ WRITE SYS$OUTPUT " PDP10 : Just Build The DEC PDP-10." +$ WRITE SYS$OUTPUT " PDP11 : Just Build The DEC PDP-11." +$ WRITE SYS$OUTPUT " PDP18B : Just Build The DEC PDP-4, PDP-7, PDP-9 And PDP-15." +$ WRITE SYS$OUTPUT " S3 : Just Build The IBM System 3" +$ WRITE SYS$OUTPUT " SDS : Just Build The SDS System" +$ WRITE SYS$OUTPUT " VAX : Just Build The DEC VAX." +$ WRITE SYS$OUTPUT "" +$! +$! Time To Exit. +$! +$ EXIT +$! +$! Time To End The BUILDALL Check. +$! +$ ENDIF +$ SIMH_CHECK_OPT_DONE: +$! +$! Check To See If We Are To Link Without Debugger Information. +$! +$ IF ((P2.EQS."").OR.(P2.EQS."NODEBUG")) +$ THEN +$! +$! P2 Is Either Blank Or "NODEBUG" So Link Without Debugger Information. +$! +$ DEBUGGER = "NODEBUG" +$! +$! Check To See If We Are On An AXP Machine. +$! +$ IF (F$GETSYI("CPU").LT.128) +$ THEN +$! +$! We Are On A VAX Machine So Use The VAX Optimizations. + +$ OPTIMIZE = "OPTIMIZE" +$! +$! Else... +$! +$ ELSE +$! +$! We Are On A AXP Machine So Use The AXP Optimizations. +$! +$ OPTIMIZE = "OPTIMIZE=(INTRINSICS,INLINE=AUTOMATIC,LEVEL=5,UNROLL=0,TUNE=HOST)/ARCH=HOST" +$! +$! Time To End The Machine Check. +$! +$ ENDIF +$! +$! Set The Link TRACEBACK Option. +$! +$ TRACEBACK = "NOTRACEBACK" +$! +$! Tell The User What They Selected. +$! +$ WRITE SYS$OUTPUT "" +$ WRITE SYS$OUTPUT "Runtime Debugger Won't Be Included At Link." +$! +$! Else... +$! +$ ELSE +$! +$! Check To See If We Are To Link With Debugger Information. +$! +$ IF (P2.EQS."DEBUG") +$ THEN +$! +$! Compile With Debugger Information. +$! +$ DEBUGGER = "DEBUG" +$ OPTIMIZE = "NOOPTIMIZE" +$ TRACEBACK = "TRACEBACK" +$! +$! Tell The User What They Selected. +$! +$ WRITE SYS$OUTPUT "" +$ WRITE SYS$OUTPUT "Runtime Debugger Will Be Included At Link." +$! +$! Else... +$! +$ ELSE +$! +$! Tell The User Entered An Invalid Option.. +$! +$ WRITE SYS$OUTPUT "" +$ WRITE SYS$OUTPUT "The Option ",P2," Is Invalid. The Valid Options Are:" +$ WRITE SYS$OUTPUT "" +$ WRITE SYS$OUTPUT " DEBUG : Link With The Debugger Information." +$ WRITE SYS$OUTPUT " NODEBUG : Link Without The Debugger Information." +$ WRITE SYS$OUTPUT "" +$! +$! Time To EXIT. +$! +$ EXIT +$! +$! Time To End The Valid P2 Check. +$! +$ ENDIF +$! +$! Time To End The P2 Check. +$! +$ ENDIF +$! +$! Time To Return To Where We Were. +$! +$ RETURN diff --git a/dec_dz.h b/dec_dz.h index 8d0473f8..f78efe0e 100644 --- a/dec_dz.h +++ b/dec_dz.h @@ -1,6 +1,6 @@ /* dec_dz.c: DZ11 terminal multiplexor simulator - Copyright (c) 2001, Robert M Supnik + Copyright (c) 2001-2002, Robert M Supnik Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), @@ -28,6 +28,10 @@ dz DZ11 terminal multiplexor + 28-Apr-02 RMS Fixed interrupt acknowledge, fixed SHOW DZ ADDRESS + 14-Jan-02 RMS Added multiboard support + 30-Dec-01 RMS Added show statistics, set disconnect + Removed statistics registers 03-Dec-01 RMS Modified for extended SET/SHOW 09-Nov-01 RMS Added VAX support 20-Oct-01 RMS Moved getchar from sim_tmxr, changed interrupt @@ -52,7 +56,14 @@ #if !defined (DZ_RDX) #define DZ_RDX 8 #endif +#if !defined (DZ_MUXES) +#define DZ_MUXES 1 +#endif +#if !defined (DZ_LINES) +#define DZ_LINES 8 +#endif +#define DZ_MNOMASK (DZ_MUXES - 1) /* mask for mux no */ #define DZ_LNOMASK (DZ_LINES - 1) /* mask for lineno */ #define DZ_LMASK ((1 << DZ_LINES) - 1) /* mask of lines */ #define DZ_SILO_ALM 16 /* silo alarm level */ @@ -112,33 +123,38 @@ extern int32 IREQ (HLVL); extern int32 sim_switches; extern FILE *sim_log; extern int32 tmxr_poll; /* calibrated delay */ -int32 dz_csr = 0; /* csr */ -int32 dz_rbuf = 0; /* rcv buffer */ -int32 dz_lpr = 0; /* line param */ -int32 dz_tcr = 0; /* xmit control */ -int32 dz_msr = 0; /* modem status */ -int32 dz_tdr = 0; /* xmit data */ + +uint16 dz_csr[DZ_MUXES] = { 0 }; /* csr */ +uint16 dz_rbuf[DZ_MUXES] = { 0 }; /* rcv buffer */ +uint16 dz_lpr[DZ_MUXES] = { 0 }; /* line param */ +uint16 dz_tcr[DZ_MUXES] = { 0 }; /* xmit control */ +uint16 dz_msr[DZ_MUXES] = { 0 }; /* modem status */ +uint16 dz_tdr[DZ_MUXES] = { 0 }; /* xmit data */ +uint8 dz_sae[DZ_MUXES] = { 0 }; /* silo alarm enabled */ +uint32 dz_rxi = 0; /* rcv interrupts */ +uint32 dz_txi = 0; /* xmt interrupts */ int32 dz_mctl = 0; /* modem ctrl enabled */ int32 dz_auto = 0; /* autodiscon enabled */ -int32 dz_sa_enb = 1; /* silo alarm enabled */ -int32 dz_enb = 1; /* device enable */ -TMLN dz_ldsc[DZ_LINES] = { /* line descriptors */ - { 0 }, { 0 }, { 0 }, { 0 }, - { 0 }, { 0 }, { 0 }, { 0 } }; -TMXR dz_desc = { /* mux descriptor */ - DZ_LINES, 0, - &dz_ldsc[0], &dz_ldsc[1], &dz_ldsc[2], &dz_ldsc[3], - &dz_ldsc[4], &dz_ldsc[5], &dz_ldsc[6], &dz_ldsc[7] }; +TMLN dz_ldsc[DZ_MUXES * DZ_LINES] = { 0 }; /* line descriptors */ +TMXR dz_desc = { DZ_MUXES * DZ_LINES, 0, NULL }; /* mux descriptor */ +t_stat dz_rd (int32 *data, int32 PA, int32 access); +t_stat dz_wr (int32 data, int32 PA, int32 access); t_stat dz_svc (UNIT *uptr); t_stat dz_reset (DEVICE *dptr); t_stat dz_attach (UNIT *uptr, char *cptr); t_stat dz_detach (UNIT *uptr); -t_stat dz_clear (t_bool flag); -int32 dz_getchar (TMXR *mp); +t_stat dz_clear (int32 dz, t_bool flag); +int32 dz_getc (int32 dz); void dz_update_rcvi (void); void dz_update_xmti (void); -t_stat dz_status (FILE *st, UNIT *uptr, void *desc); +void dz_clr_rxint (int32 dz); +void dz_set_rxint (int32 dz); +void dz_clr_txint (int32 dz); +void dz_set_txint (int32 dz); +t_stat dz_summ (FILE *st, UNIT *uptr, int32 val, void *desc); +t_stat dz_show (FILE *st, UNIT *uptr, int32 val, void *desc); +t_stat dz_setnl (UNIT *uptr, int32 val, char *cptr, void *desc); /* DZ data structures @@ -147,141 +163,150 @@ t_stat dz_status (FILE *st, UNIT *uptr, void *desc); dz_reg DZ register list */ +DIB dz_dib = { 1, IOBA_DZ, IOLN_DZ * DZ_MUXES, &dz_rd, &dz_wr }; + UNIT dz_unit = { UDATA (&dz_svc, UNIT_ATTABLE, 0) }; +REG dz_nlreg = { DRDATA (NLINES, dz_desc.lines, 6), PV_LEFT }; + REG dz_reg[] = { - { GRDATA (CSR, dz_csr, DZ_RDX, 16, 0) }, - { GRDATA (RBUF, dz_rbuf, DZ_RDX, 16, 0) }, - { GRDATA (LPR, dz_lpr, DZ_RDX, 16, 0) }, - { GRDATA (TCR, dz_tcr, DZ_RDX, 16, 0) }, - { GRDATA (MSR, dz_msr, DZ_RDX, 16, 0) }, - { GRDATA (TDR, dz_tdr, DZ_RDX, 16, 0) }, - { FLDATA (SAENB, dz_sa_enb, 0) }, + { BRDATA (CSR, dz_csr, DZ_RDX, 16, DZ_MUXES) }, + { BRDATA (RBUF, dz_rbuf, DZ_RDX, 16, DZ_MUXES) }, + { BRDATA (LPR, dz_lpr, DZ_RDX, 16, DZ_MUXES) }, + { BRDATA (TCR, dz_tcr, DZ_RDX, 16, DZ_MUXES) }, + { BRDATA (MSR, dz_msr, DZ_RDX, 16, DZ_MUXES) }, + { BRDATA (TDR, dz_tdr, DZ_RDX, 16, DZ_MUXES) }, + { BRDATA (SAENB, dz_sae, DZ_RDX, 1, DZ_MUXES) }, + { GRDATA (RXINT, dz_rxi, DZ_RDX, DZ_MUXES, 0) }, + { GRDATA (TXINT, dz_txi, DZ_RDX, DZ_MUXES, 0) }, { FLDATA (MDMCTL, dz_mctl, 0) }, { FLDATA (AUTODS, dz_auto, 0) }, - { DRDATA (RPOS0, dz_ldsc[0].rxcnt, 32), PV_LEFT+REG_RO }, - { DRDATA (TPOS0, dz_ldsc[0].txcnt, 32), PV_LEFT+REG_RO }, - { DRDATA (RPOS1, dz_ldsc[1].rxcnt, 32), PV_LEFT+REG_RO }, - { DRDATA (TPOS1, dz_ldsc[1].txcnt, 32), PV_LEFT+REG_RO }, - { DRDATA (RPOS2, dz_ldsc[2].rxcnt, 32), PV_LEFT+REG_RO }, - { DRDATA (TPOS2, dz_ldsc[2].txcnt, 32), PV_LEFT+REG_RO }, - { DRDATA (RPOS3, dz_ldsc[3].rxcnt, 32), PV_LEFT+REG_RO }, - { DRDATA (TPOS3, dz_ldsc[3].txcnt, 32), PV_LEFT+REG_RO }, - { DRDATA (RPOS4, dz_ldsc[4].rxcnt, 32), PV_LEFT+REG_RO }, - { DRDATA (TPOS4, dz_ldsc[4].txcnt, 32), PV_LEFT+REG_RO }, - { DRDATA (RPOS5, dz_ldsc[5].rxcnt, 32), PV_LEFT+REG_RO }, - { DRDATA (TPOS5, dz_ldsc[5].txcnt, 32), PV_LEFT+REG_RO }, - { DRDATA (RPOS6, dz_ldsc[6].rxcnt, 32), PV_LEFT+REG_RO }, - { DRDATA (TPOS6, dz_ldsc[6].txcnt, 32), PV_LEFT+REG_RO }, - { DRDATA (RPOS7, dz_ldsc[7].rxcnt, 32), PV_LEFT+REG_RO }, - { DRDATA (TPOS7, dz_ldsc[7].txcnt, 32), PV_LEFT+REG_RO }, - { FLDATA (*DEVENB, dz_enb, 0) }, + { GRDATA (DEVADDR, dz_dib.ba, DZ_RDX, 32, 0), REG_HRO }, + { FLDATA (*DEVENB, dz_dib.enb, 0), REG_HRO }, { NULL } }; MTAB dz_mod[] = { - { UNIT_ATT, UNIT_ATT, "line status", NULL, NULL, &dz_status }, - { MTAB_XTD | MTAB_VDV | MTAB_NMO, 0, "LINESTATUS", NULL, - NULL, &dz_status, NULL }, + { UNIT_ATT, UNIT_ATT, "connections", NULL, NULL, &dz_summ }, + { MTAB_XTD | MTAB_VDV, 1, NULL, "DISCONNECT", + &tmxr_dscln, NULL, &dz_desc }, + { MTAB_XTD | MTAB_VDV | MTAB_NMO, 1, "CONNECTIONS", NULL, + NULL, &dz_show, NULL }, + { MTAB_XTD | MTAB_VDV | MTAB_NMO, 0, "STATISTICS", NULL, + NULL, &dz_show, NULL }, + { MTAB_XTD|MTAB_VDV, 010, "ADDRESS", "ADDRESS", + &set_addr, &show_addr, &dz_dib }, + { MTAB_XTD|MTAB_VDV, 1, NULL, "ENABLED", + &set_enbdis, NULL, &dz_dib }, + { MTAB_XTD|MTAB_VDV, 0, NULL, "DISABLED", + &set_enbdis, NULL, &dz_dib }, + { MTAB_XTD | MTAB_VDV | MTAB_VAL, 0, "lines", "LINES", + &dz_setnl, NULL, &dz_nlreg }, { 0 } }; DEVICE dz_dev = { "DZ", &dz_unit, dz_reg, dz_mod, - 1, DZ_RDX, 13, 1, DZ_RDX, 8, + 1, DZ_RDX, 8, 1, DZ_RDX, 8, &tmxr_ex, &tmxr_dep, &dz_reset, NULL, &dz_attach, &dz_detach }; -/* IO dispatch routines, I/O addresses 17760100 - 17760107 */ +/* IO dispatch routines, I/O addresses 177601x0 - 177601x7 */ t_stat dz_rd (int32 *data, int32 PA, int32 access) { +int32 dz = ((PA - dz_dib.ba) >> 3) & DZ_MNOMASK; /* get mux num */ + switch ((PA >> 1) & 03) { /* case on PA<2:1> */ case 00: /* CSR */ - *data = dz_csr = dz_csr & ~CSR_MBZ; + *data = dz_csr[dz] = dz_csr[dz] & ~CSR_MBZ; break; case 01: /* RBUF */ - dz_csr = dz_csr & ~CSR_SA; /* clr silo alarm */ - if (dz_csr & CSR_MSE) { /* scanner on? */ - dz_rbuf = dz_getchar (&dz_desc); /* get top of silo */ - if (!dz_rbuf) dz_sa_enb = 1; /* empty? re-enable */ + dz_csr[dz] = dz_csr[dz] & ~CSR_SA; /* clr silo alarm */ + if (dz_csr[dz] & CSR_MSE) { /* scanner on? */ + dz_rbuf[dz] = dz_getc (dz); /* get top of silo */ + if (!dz_rbuf[dz]) dz_sae[dz] = 1; /* empty? re-enable */ tmxr_poll_rx (&dz_desc); /* poll input */ dz_update_rcvi (); } /* update rx intr */ - else { dz_rbuf = 0; /* no data */ + else { dz_rbuf[dz] = 0; /* no data */ dz_update_rcvi (); } /* no rx intr */ - *data = dz_rbuf; + *data = dz_rbuf[dz]; break; case 02: /* TCR */ - *data = dz_tcr; + *data = dz_tcr[dz]; break; case 03: /* MSR */ - *data = dz_msr; + *data = dz_msr[dz]; break; } return SCPE_OK; } t_stat dz_wr (int32 data, int32 PA, int32 access) { +int32 dz = ((PA - dz_dib.ba) >> 3) & DZ_MNOMASK; /* get mux num */ int32 i, line; TMLN *lp; switch ((PA >> 1) & 03) { /* case on PA<2:1> */ case 00: /* CSR */ - if (access == WRITEB) data = (PA & 1)? - (dz_csr & 0377) | (data << 8): (dz_csr & ~0377) | data; - if (data & CSR_CLR) dz_clear (FALSE); + if (access == WRITEB) data = (PA & 1)? /* byte? merge */ + (dz_csr[dz] & 0377) | (data << 8): + (dz_csr[dz] & ~0377) | data; + if (data & CSR_CLR) dz_clear (dz, FALSE); /* clr? reset */ if (data & CSR_MSE) sim_activate (&dz_unit, tmxr_poll); - else { sim_cancel (&dz_unit); - dz_csr = dz_csr & ~(CSR_SA | CSR_RDONE | CSR_TRDY); } - if ((data & CSR_RIE) == 0) CLR_INT (DZRX); - else if (((dz_csr & CSR_IE) == 0) && /* RIE 0->1? */ - ((dz_csr & CSR_SAE)? (dz_csr & CSR_SA): (dz_csr & CSR_RDONE))) - SET_INT (DZRX); - if ((data & CSR_TIE) == 0) CLR_INT (DZTX); - else if (((dz_csr & CSR_TIE) == 0) && (dz_csr & CSR_TRDY)) - SET_INT (DZTX); - dz_csr = (dz_csr & ~CSR_RW) | (data & CSR_RW); + else dz_csr[dz] &= ~(CSR_SA | CSR_RDONE | CSR_TRDY); + if ((data & CSR_RIE) == 0) dz_clr_rxint (dz); /* RIE = 0? */ + else if (((dz_csr[dz] & CSR_IE) == 0) && /* RIE 0->1? */ + ((dz_csr[dz] & CSR_SAE)? + (dz_csr[dz] & CSR_SA): (dz_csr[dz] & CSR_RDONE))) + dz_set_rxint (dz); + if ((data & CSR_TIE) == 0) dz_clr_txint (dz); /* TIE = 0? */ + else if (((dz_csr[dz] & CSR_TIE) == 0) && (dz_csr[dz] & CSR_TRDY)) + dz_set_txint (dz); + dz_csr[dz] = (dz_csr[dz] & ~CSR_RW) | (data & CSR_RW); break; case 01: /* LPR */ - dz_lpr = data; - line = LPR_GETLN (dz_lpr); /* get line */ - lp = dz_desc.ldsc[line]; /* get line desc */ - if (dz_lpr & LPR_RCVE) lp -> rcve = 1; /* rcv enb? on */ + dz_lpr[dz] = data; + line = (dz * DZ_LINES) + LPR_GETLN (data); /* get line num */ + lp = &dz_ldsc[line]; /* get line desc */ + if (dz_lpr[dz] & LPR_RCVE) lp -> rcve = 1; /* rcv enb? on */ else lp -> rcve = 0; /* else line off */ tmxr_poll_rx (&dz_desc); /* poll input */ dz_update_rcvi (); /* update rx intr */ break; case 02: /* TCR */ - if (access == WRITEB) data = (PA & 1)? - (dz_tcr & 0377) | (data << 8): (dz_tcr & ~0377) | data; + if (access == WRITEB) data = (PA & 1)? /* byte? merge */ + (dz_tcr[dz] & 0377) | (data << 8): + (dz_tcr[dz] & ~0377) | data; if (dz_mctl) { /* modem ctl? */ - dz_msr = dz_msr | ((data & 0177400) & /* dcd |= dtr & ring */ - ((dz_msr & DZ_LMASK) << MSR_V_CD)); - dz_msr = dz_msr & ~(data >> TCR_V_DTR); /* ring = ring & ~dtr */ + dz_msr[dz] |= ((data & 0177400) & /* dcd |= dtr & ring */ + ((dz_msr[dz] & DZ_LMASK) << MSR_V_CD)); + dz_msr[dz] &= ~(data >> TCR_V_DTR); /* ring &= ~dtr */ if (dz_auto) { /* auto disconnect? */ int32 drop; - drop = (dz_tcr & ~data) >> TCR_V_DTR; /* drop = dtr & ~data */ + drop = (dz_tcr[dz] & ~data) >> TCR_V_DTR; /* drop = dtr & ~data */ for (i = 0; i < DZ_LINES; i++) { /* drop hangups */ - lp = dz_desc.ldsc[i]; /* get line desc */ + line = (dz * DZ_LINES) + i; /* get line num */ + lp = &dz_ldsc[line]; /* get line desc */ if (lp -> conn && (drop & (1 << i))) { tmxr_msg (lp -> conn, "\r\nLine hangup\r\n"); tmxr_reset_ln (lp); /* reset line, cdet */ - dz_msr = dz_msr & ~(1 << (i + MSR_V_CD)); + dz_msr[dz] &= ~(1 << (i + MSR_V_CD)); } /* end if drop */ } /* end for */ } /* end if auto */ } /* end if modem */ - dz_tcr = data; + dz_tcr[dz] = data; tmxr_poll_tx (&dz_desc); /* poll output */ dz_update_xmti (); /* update int */ break; case 03: /* TDR */ if (PA & 1) { /* odd byte? */ - dz_tdr = (dz_tdr & 0377) | (data << 8); /* just save */ + dz_tdr[dz] = (dz_tdr[dz] & 0377) | (data << 8); /* just save */ break; } - dz_tdr = data; - if (dz_csr & CSR_MSE) { /* enabled? */ - line = CSR_GETTL (dz_csr); /* get xmit line */ - lp = dz_desc.ldsc[line]; /* get line desc */ - tmxr_putc_ln (lp, dz_tdr & 0177); /* store char */ + dz_tdr[dz] = data; + if (dz_csr[dz] & CSR_MSE) { /* enabled? */ + line = (dz * DZ_LINES) + CSR_GETTL (dz_csr[dz]); + lp = &dz_ldsc[line]; /* get line desc */ + tmxr_putc_ln (lp, dz_tdr[dz] & 0177); /* store char */ tmxr_poll_tx (&dz_desc); /* poll output */ dz_update_xmti (); } /* update int */ break; } @@ -294,18 +319,24 @@ return SCPE_OK; needs to be processed. The polling interval is controlled by the clock simulator, so for most environments, it is calibrated to real time. Typical polling intervals are 50-60 times per second. + + The simulator assumes that software enables all of the multiplexors, + or none of them. */ t_stat dz_svc (UNIT *uptr) { -int32 newln; +int32 dz, t, newln; -if (dz_csr & CSR_MSE) { /* enabled? */ +for (dz = t = 0; dz < DZ_MUXES; dz++) /* check enabled */ + t = t | (dz_csr[dz] & CSR_MSE); +if (t) { /* any enabled? */ newln = tmxr_poll_conn (&dz_desc, uptr); /* poll connect */ if ((newln >= 0) && dz_mctl) { /* got a live one? */ - if (dz_tcr & (1 << (newln + TCR_V_DTR))) /* DTR set? */ - dz_msr = dz_msr | (1 << (newln + MSR_V_CD)); - else dz_msr = dz_msr | (1 << newln); } /* set ring */ + dz = newln / DZ_LINES; /* get mux num */ + if (dz_tcr[dz] & (1 << (newln + TCR_V_DTR))) /* DTR set? */ + dz_msr[dz] |= (1 << (newln + MSR_V_CD)); /* set cdet */ + else dz_msr[dz] |= (1 << newln); } /* set ring */ tmxr_poll_rx (&dz_desc); /* poll input */ dz_update_rcvi (); /* upd rcv intr */ tmxr_poll_tx (&dz_desc); /* poll output */ @@ -314,42 +345,50 @@ if (dz_csr & CSR_MSE) { /* enabled? */ return SCPE_OK; } -/* Get first available character, if any */ +/* Get first available character for mux, if any */ -int32 dz_getchar (TMXR *mp) +int32 dz_getc (int32 dz) { -int32 i, val; +uint32 i, line, c; -for (i = val = 0; (i < mp -> lines) && (val == 0); i++) { /* loop thru lines */ - val = tmxr_getc_ln (mp -> ldsc[i]); /* test for input */ - if (val) val = val | (i << RBUF_V_RLINE); /* or in line # */ +for (i = c = 0; (i < DZ_LINES) && (c == 0); i++) { /* loop thru lines */ + line = (dz * DZ_LINES) + i; /* get line num */ + c = tmxr_getc_ln (&dz_ldsc[line]); /* test for input */ + if (c) c = c | (i << RBUF_V_RLINE); /* or in line # */ } /* end for */ -return val; +return c; } /* Update receive interrupts */ void dz_update_rcvi (void) { -int32 i, scnt; +int32 i, dz, line, scnt[DZ_MUXES]; TMLN *lp; -for (i = scnt = 0; i < DZ_LINES; i++) { /* poll lines */ - lp = dz_desc.ldsc[i]; /* get line desc */ - scnt = scnt + tmxr_rqln (lp); /* sum buffers */ +for (dz = 0; dz < DZ_MUXES; dz++) { /* loop thru muxes */ + scnt[dz] = 0; /* clr input count */ + for (i = 0; i < DZ_LINES; i++) { /* poll lines */ + line = (dz * DZ_LINES) + i; /* get line num */ + lp = &dz_ldsc[line]; /* get line desc */ + scnt[dz] = scnt[dz] + tmxr_rqln (lp); /* sum buffers */ if (dz_mctl && !lp -> conn) /* if disconn */ - dz_msr = dz_msr & ~(1 << (i + MSR_V_CD)); /* reset car det */ + dz_msr[dz] &= ~(1 << (i + MSR_V_CD)); /* reset car det */ } -if (scnt && (dz_csr & CSR_MSE)) { /* input & enabled? */ - dz_csr = dz_csr | CSR_RDONE; /* set done */ - if (dz_sa_enb && (scnt >= DZ_SILO_ALM)) { /* alm enb & cnt hi? */ - dz_csr = dz_csr | CSR_SA; /* set status */ - dz_sa_enb = 0; } } /* disable alarm */ -else dz_csr = dz_csr & ~CSR_RDONE; /* no, clear done */ -if ((dz_csr & CSR_RIE) && /* int enable */ - ((dz_csr & CSR_SAE)? (dz_csr & CSR_SA): (dz_csr & CSR_RDONE))) - SET_INT (DZRX); /* and alm/done? */ -else CLR_INT (DZRX); /* no, clear int */ + } +for (dz = 0; dz < DZ_MUXES; dz++) { /* loop thru muxes */ + if (scnt[dz] && (dz_csr[dz] & CSR_MSE)) { /* input & enabled? */ + dz_csr[dz] |= CSR_RDONE; /* set done */ + if (dz_sae[dz] && (scnt[dz] >= DZ_SILO_ALM)) { /* alm enb & cnt hi? */ + dz_csr[dz] |= CSR_SA; /* set status */ + dz_sae[dz] = 0; } } /* disable alarm */ + else dz_csr[dz] &= ~CSR_RDONE; /* no, clear done */ + if ((dz_csr[dz] & CSR_RIE) && /* int enable */ + ((dz_csr[dz] & CSR_SAE)? + (dz_csr[dz] & CSR_SA): (dz_csr[dz] & CSR_RDONE))) + dz_set_rxint (dz); /* and alm/done? */ + else dz_clr_rxint (dz); /* no, clear int */ + } return; } @@ -357,47 +396,114 @@ return; void dz_update_xmti (void) { -int32 linemask, i, j; +int32 dz, linemask, i, j, line; -linemask = dz_tcr & DZ_LMASK; /* enabled lines */ -dz_csr = dz_csr & ~CSR_TRDY; /* assume not rdy */ -for (i = 0, j = CSR_GETTL (dz_csr); i < DZ_LINES; i++) { - j = (j + 1) & DZ_LNOMASK; - if ((linemask & (1 << j)) && dz_desc.ldsc[j] -> xmte) { - CSR_PUTTL (dz_csr, j); /* update CSR */ - dz_csr = dz_csr | CSR_TRDY; /* set xmt rdy */ +for (dz = 0; dz < DZ_MUXES; dz++) { /* loop thru muxes */ + linemask = dz_tcr[dz] & DZ_LMASK; /* enabled lines */ + dz_csr[dz] &= ~CSR_TRDY; /* assume not rdy */ + j = CSR_GETTL (dz_csr[dz]); /* start at current */ + for (i = 0; i < DZ_LINES; i++) { /* loop thru lines */ + j = (j + 1) & DZ_LNOMASK; /* next line */ + line = (dz * DZ_LINES) + j; /* get line num */ + if ((linemask & (1 << j)) && dz_ldsc[line].xmte) { + CSR_PUTTL (dz_csr[dz], j); /* put ln in csr */ + dz_csr[dz] |= CSR_TRDY; /* set xmt rdy */ break; } } -if ((dz_csr & CSR_TIE) && (dz_csr & CSR_TRDY)) /* ready plus int? */ - SET_INT (DZTX); -else CLR_INT (DZTX); /* no int req */ + if ((dz_csr[dz] & CSR_TIE) && (dz_csr[dz] & CSR_TRDY)) /* ready plus int? */ + dz_set_txint (dz); + else dz_clr_txint (dz); /* no int req */ + } return; } +/* Interrupt routines */ + +void dz_clr_rxint (int32 dz) +{ +dz_rxi = dz_rxi & ~(1 << dz); /* clr mux rcv int */ +if (dz_rxi == 0) CLR_INT (DZRX); /* all clr? */ +else SET_INT (DZRX); /* no, set intr */ +return; +} + +void dz_set_rxint (int32 dz) +{ +dz_rxi = dz_rxi | (1 << dz); /* set mux rcv int */ +SET_INT (DZRX); /* set master intr */ +return; +} + +int32 dz_rxinta (void) +{ +int32 dz; + +for (dz = 0; dz < DZ_MUXES; dz++) { /* find 1st mux */ + if (dz_rxi & (1 << dz)) { + dz_clr_rxint (dz); /* clear intr */ + return (VEC_DZRX + (dz * 010)); } } /* return vector */ +return 0; +} + +void dz_clr_txint (int32 dz) +{ +dz_txi = dz_txi & ~(1 << dz); /* clr mux xmt int */ +if (dz_txi == 0) CLR_INT (DZTX); /* all clr? */ +else SET_INT (DZTX); /* no, set intr */ +return; +} + +void dz_set_txint (int32 dz) +{ +dz_txi = dz_txi | (1 << dz); /* set mux xmt int */ +SET_INT (DZTX); /* set master intr */ +return; +} + +int32 dz_txinta (void) +{ +int32 dz; + +for (dz = 0; dz < DZ_MUXES; dz++) { /* find 1st mux */ + if (dz_txi & (1 << dz)) { + dz_clr_txint (dz); /* clear intr */ + return (VEC_DZTX + (dz * 010)); } } /* return vector */ +return 0; +} + /* Device reset */ -t_stat dz_clear (t_bool flag) +t_stat dz_clear (int32 dz, t_bool flag) { -int32 i; +int32 i, line; -dz_csr = 0; /* clear CSR */ -dz_rbuf = 0; /* silo empty */ -dz_lpr = 0; /* no params */ -if (flag) dz_tcr = 0; /* INIT? clr all */ -else dz_tcr = dz_tcr & ~0377; /* else save dtr */ -dz_tdr = 0; -dz_sa_enb = 1; -CLR_INT (DZRX); -CLR_INT (DZTX); -sim_cancel (&dz_unit); /* no polling */ -for (i = 0; i < DZ_LINES; i++) { - if (!dz_desc.ldsc[i] -> conn) dz_desc.ldsc[i] -> xmte = 1; - dz_desc.ldsc[i] -> rcve = 0; } /* clr rcv enb */ +dz_csr[dz] = 0; /* clear CSR */ +dz_rbuf[dz] = 0; /* silo empty */ +dz_lpr[dz] = 0; /* no params */ +if (flag) dz_tcr[dz] = 0; /* INIT? clr all */ +else dz_tcr[dz] &= ~0377; /* else save dtr */ +dz_tdr[dz] = 0; +dz_sae[dz] = 1; /* alarm on */ +dz_clr_rxint (dz); /* clear int */ +dz_clr_txint (dz); +for (i = 0; i < DZ_LINES; i++) { /* loop thru lines */ + line = (dz * DZ_LINES) + i; + if (!dz_ldsc[line].conn) dz_ldsc[line].xmte = 1;/* set xmt enb */ + dz_ldsc[line].rcve = 0; } /* clr rcv enb */ return SCPE_OK; } t_stat dz_reset (DEVICE *dptr) { -return dz_clear (TRUE); +int32 i; + +for (i = 0; i < (DZ_MUXES * DZ_LINES); i++) /* init mux desc */ + dz_desc.ldsc[i] = &dz_ldsc[i]; +for (i = 0; i < DZ_MUXES; i++) dz_clear (i, TRUE); /* init muxes */ +dz_rxi = dz_txi = 0; /* clr master int */ +CLR_INT (DZRX); +CLR_INT (DZTX); +sim_cancel (&dz_unit); /* stop poll */ +return SCPE_OK; } /* Attach */ @@ -429,19 +535,64 @@ t_stat dz_detach (UNIT *uptr) { return tmxr_detach (&dz_desc, uptr); } + +/* Show summary processor */ -/* Status */ - -t_stat dz_status (FILE *st, UNIT *uptr, void *desc) +t_stat dz_summ (FILE *st, UNIT *uptr, int32 val, void *desc) { -int32 i; +int32 i, t; -fprintf (st, "line status:"); -for (i = 0; (i < DZ_LINES) && (dz_desc.ldsc[i] -> conn == 0); i++) ; -if (i < DZ_LINES) { - for (i = 0; i < DZ_LINES; i++) { - if (dz_desc.ldsc[i] -> conn) - tmxr_fstatus (st, dz_desc.ldsc[i], i); } } -else fprintf (st, " all disconnected"); +for (i = t = 0; i < dz_desc.lines; i++) { /* get num conn */ + if (dz_ldsc[i].conn) t = t + 1; } +if (t == 1) fprintf (st, "1 connection"); +else fprintf (st, "%d connections", t); +return SCPE_OK; +} + +/* SHOW CONN/STAT processor */ + +t_stat dz_show (FILE *st, UNIT *uptr, int32 val, void *desc) +{ +int32 i, t; + +for (i = t = 0; i < dz_desc.lines; i++) { /* loop thru conn */ + if (dz_ldsc[i].conn) { + t = 1; + if (val) tmxr_fconns (st, &dz_ldsc[i], i); + else tmxr_fstats (st, &dz_ldsc[i], i); } } +if (t == 0) fprintf (st, "all disconnected\n"); +return SCPE_OK; +} + +/* SET LINES processor */ + +t_stat dz_setnl (UNIT *uptr, int32 val, char *cptr, void *desc) +{ +int32 newln, i, t; +t_stat r; + +if (cptr == NULL) return SCPE_ARG; +newln = (int32) get_uint (cptr, 10, (DZ_MUXES * DZ_LINES), &r); +if ((r != SCPE_OK) || (newln == dz_desc.lines)) return r; +if ((newln == 0) || (newln % DZ_LINES)) return SCPE_ARG; +if (newln < dz_desc.lines) { + for (i = newln, t = 0; i < dz_desc.lines; i++) t = t | dz_ldsc[i].conn; + if (t && !get_yn ("This will disconnect users; proceed [N]?", FALSE)) + return SCPE_OK; + for (i = newln; i < dz_desc.lines; i++) { + if (dz_ldsc[i].conn) { + tmxr_msg (dz_ldsc[i].conn, "\r\nOperator disconnected line\r\n"); + tmxr_reset_ln (&dz_ldsc[i]); } /* reset line */ + if ((i % DZ_LINES) == (DZ_LINES - 1)) + dz_clear (i / DZ_LINES, TRUE); } /* reset mux */ + dz_dib.lnt = newln; + } +else { + dz_dib.lnt = newln; /* set length */ + if (dev_conflict (dz_dib.ba, &dz_dib)) { /* chk addr conflict */ + dz_dib.lnt = dz_desc.lines; + return SCPE_OK; } + } +dz_desc.lines = newln; return SCPE_OK; } diff --git a/dec_mscp.h b/dec_mscp.h index 59f0d4d7..639db107 100644 --- a/dec_mscp.h +++ b/dec_mscp.h @@ -1,6 +1,6 @@ /* dec_mscp.c: DEC MSCP definitions - Copyright (c) 2001, Robert M Supnik + Copyright (c) 2001-2002, Robert M Supnik Derived from work by Stephen F. Shirron Permission is hereby granted, free of charge, to any person obtaining a diff --git a/dec_uqssp.h b/dec_uqssp.h index 0ea2801e..96b6d08a 100644 --- a/dec_uqssp.h +++ b/dec_uqssp.h @@ -1,6 +1,6 @@ /* dec_uqssp.h: Unibus/Qbus storage systems port definitions file - Copyright (c) 2001, Robert M Supnik + Copyright (c) 2001-2002, Robert M Supnik Derived from work by Stephen F. Shirron Permission is hereby granted, free of charge, to any person obtaining a diff --git a/makefile b/makefile index 4d1a5f85..915ac20b 100644 --- a/makefile +++ b/makefile @@ -1,7 +1,10 @@ # CC Command # -CC = gcc -O2 -lm -I . -#CC = gcc -O0 -g -lm -I . +# Note: -O2 is sometimes broken in GCC when setjump/longjump is being +# used. Try -O2 only with released simulators. +# +CC = gcc -O0 -lm -I . +#CC = gcc -O2 -g -lm -I . @@ -18,32 +21,32 @@ SIM = scp.c scp_tty.c sim_sock.c sim_tmxr.c # PDP1D = PDP1/ PDP1 = ${PDP1D}pdp1_lp.c ${PDP1D}pdp1_cpu.c ${PDP1D}pdp1_stddev.c \ - ${PDP1D}pdp1_sys.c + ${PDP1D}pdp1_sys.c PDP1_OPT = -I ${PDP1D} NOVAD = NOVA/ NOVA = ${NOVAD}nova_sys.c ${NOVAD}nova_cpu.c ${NOVAD}nova_dkp.c \ - ${NOVAD}nova_dsk.c ${NOVAD}nova_lp.c ${NOVAD}nova_mta.c \ - ${NOVAD}nova_plt.c ${NOVAD}nova_pt.c ${NOVAD}nova_clk.c \ - ${NOVAD}nova_tt.c ${NOVAD}nova_tt1.c + ${NOVAD}nova_dsk.c ${NOVAD}nova_lp.c ${NOVAD}nova_mta.c \ + ${NOVAD}nova_plt.c ${NOVAD}nova_pt.c ${NOVAD}nova_clk.c \ + ${NOVAD}nova_tt.c ${NOVAD}nova_tt1.c NOVA_OPT = -I ${NOVAD} ECLIPSE = ${NOVAD}eclipse_cpu.c ${NOVAD}eclipse_tt.c ${NOVAD}nova_sys.c \ - ${NOVAD}nova_dkp.c ${NOVAD}nova_dsk.c ${NOVAD}nova_lp.c \ - ${NOVAD}nova_mta.c ${NOVAD}nova_plt.c ${NOVAD}nova_pt.c \ - ${NOVAD}nova_clk.c ${NOVAD}nova_tt1.c + ${NOVAD}nova_dkp.c ${NOVAD}nova_dsk.c ${NOVAD}nova_lp.c \ + ${NOVAD}nova_mta.c ${NOVAD}nova_plt.c ${NOVAD}nova_pt.c \ + ${NOVAD}nova_clk.c ${NOVAD}nova_tt1.c ECLIPSE_OPT = -I ${NOVAD} -DECLIPSE PDP18BD = PDP18B/ PDP18B = ${PDP18BD}pdp18b_dt.c ${PDP18BD}pdp18b_drm.c ${PDP18BD}pdp18b_cpu.c \ - ${PDP18BD}pdp18b_lp.c ${PDP18BD}pdp18b_mt.c ${PDP18BD}pdp18b_rf.c \ - ${PDP18BD}pdp18b_rp.c ${PDP18BD}pdp18b_stddev.c ${PDP18BD}pdp18b_sys.c \ - ${PDP18BD}pdp18b_tt1.c + ${PDP18BD}pdp18b_lp.c ${PDP18BD}pdp18b_mt.c ${PDP18BD}pdp18b_rf.c \ + ${PDP18BD}pdp18b_rp.c ${PDP18BD}pdp18b_stddev.c ${PDP18BD}pdp18b_sys.c \ + ${PDP18BD}pdp18b_tt1.c PDP4_OPT = -DPDP4 -I ${PDP18BD} PDP7_OPT = -DPDP7 -I ${PDP18BD} PDP9_OPT = -DPDP9 -I ${PDP18BD} @@ -53,195 +56,189 @@ PDP15_OPT = -DPDP15 -I ${PDP18BD} PDP11D = PDP11/ PDP11 = ${PDP11D}pdp11_fp.c ${PDP11D}pdp11_cpu.c ${PDP11D}pdp11_dz.c \ - ${PDP11D}pdp11_cis.c ${PDP11D}pdp11_lp.c ${PDP11D}pdp11_rk.c \ - ${PDP11D}pdp11_rl.c ${PDP11D}pdp11_rp.c ${PDP11D}pdp11_rx.c \ - ${PDP11D}pdp11_stddev.c ${PDP11D}pdp11_sys.c ${PDP11D}pdp11_tc.c \ - ${PDP11D}pdp11_tm.c ${PDP11D}pdp11_ts.c ${PDP11D}pdp11_io.c \ - ${PDP11D}pdp11_rq.c + ${PDP11D}pdp11_cis.c ${PDP11D}pdp11_lp.c ${PDP11D}pdp11_rk.c \ + ${PDP11D}pdp11_rl.c ${PDP11D}pdp11_rp.c ${PDP11D}pdp11_rx.c \ + ${PDP11D}pdp11_stddev.c ${PDP11D}pdp11_sys.c ${PDP11D}pdp11_tc.c \ + ${PDP11D}pdp11_tm.c ${PDP11D}pdp11_ts.c ${PDP11D}pdp11_io.c \ + ${PDP11D}pdp11_rq.c PDP11_OPT = -I ${PDP11D} PDP10D = PDP10/ PDP10 = ${PDP10D}pdp10_fe.c ${PDP10D}pdp10_dz.c ${PDP10D}pdp10_cpu.c \ - ${PDP10D}pdp10_ksio.c ${PDP10D}pdp10_lp20.c ${PDP10D}pdp10_mdfp.c \ - ${PDP10D}pdp10_pag.c ${PDP10D}pdp10_pt.c ${PDP10D}pdp10_rp.c \ - ${PDP10D}pdp10_sys.c ${PDP10D}pdp10_tim.c ${PDP10D}pdp10_tu.c \ - ${PDP10D}pdp10_xtnd.c + ${PDP10D}pdp10_ksio.c ${PDP10D}pdp10_lp20.c ${PDP10D}pdp10_mdfp.c \ + ${PDP10D}pdp10_pag.c ${PDP10D}pdp10_pt.c ${PDP10D}pdp10_rp.c \ + ${PDP10D}pdp10_sys.c ${PDP10D}pdp10_tim.c ${PDP10D}pdp10_tu.c \ + ${PDP10D}pdp10_xtnd.c PDP10_OPT = -DUSE_INT64 -I ${PDP10D} PDP8D = PDP8/ PDP8 = ${PDP8D}pdp8_cpu.c ${PDP8D}pdp8_clk.c ${PDP8D}pdp8_df.c \ - ${PDP8D}pdp8_dt.c ${PDP8D}pdp8_lp.c ${PDP8D}pdp8_mt.c \ - ${PDP8D}pdp8_pt.c ${PDP8D}pdp8_rf.c ${PDP8D}pdp8_rk.c \ - ${PDP8D}pdp8_rx.c ${PDP8D}pdp8_sys.c ${PDP8D}pdp8_tt.c \ - ${PDP8D}pdp8_ttx.c ${PDP8D}pdp8_rl.c + ${PDP8D}pdp8_dt.c ${PDP8D}pdp8_lp.c ${PDP8D}pdp8_mt.c \ + ${PDP8D}pdp8_pt.c ${PDP8D}pdp8_rf.c ${PDP8D}pdp8_rk.c \ + ${PDP8D}pdp8_rx.c ${PDP8D}pdp8_sys.c ${PDP8D}pdp8_tt.c \ + ${PDP8D}pdp8_ttx.c ${PDP8D}pdp8_rl.c PDP8_OPT = -I ${PDP8D} H316D = H316/ H316 = ${H316D}h316_stddev.c ${H316D}h316_lp.c ${H316D}h316_cpu.c \ - ${H316D}h316_sys.c + ${H316D}h316_sys.c H316_OPT = -I ${H316D} HP2100D = HP2100/ -HP2100 = ${HP2100D}hp2100_stddev.c ${HP2100D}hp2100_dp.c ${HP2100D}hp2100_lp.c \ - ${HP2100D}hp2100_mt.c ${HP2100D}hp2100_cpu.c ${HP2100D}hp2100_sys.c +HP2100 = ${HP2100D}hp2100_stddev.c ${HP2100D}hp2100_dp.c ${HP2100D}hp2100_dq.c \ + ${HP2100D}hp2100_dr.c ${HP2100D}hp2100_lp.c ${HP2100D}hp2100_ms.c \ + ${HP2100D}hp2100_mt.c ${HP2100D}hp2100_mux.c ${HP2100D}hp2100_cpu.c \ + ${HP2100D}hp2100_fp.c ${HP2100D}hp2100_sys.c HP2100_OPT = -I ${HP2100D} -ID4D = ID4/ -ID4 = ${ID4D}id4_fp.c ${ID4D}id4_cpu.c ${ID4D}id4_stddev.c ${ID4D}id4_sys.c -ID4_OPT = -I ${ID4D} - - - I1401D = I1401/ I1401 = ${I1401D}i1401_lp.c ${I1401D}i1401_cpu.c ${I1401D}i1401_iq.c \ - ${I1401D}i1401_cd.c ${I1401D}i1401_mt.c ${I1401D}i1401_sys.c + ${I1401D}i1401_cd.c ${I1401D}i1401_mt.c ${I1401D}i1401_dp.c \ + ${I1401D}i1401_sys.c I1401_OPT = -I ${I1401D} VAXD = VAX/ VAX = ${VAXD}vax_cpu1.c ${VAXD}vax_cpu.c ${VAXD}vax_fpa.c ${VAXD}vax_io.c \ - ${VAXD}vax_mmu.c ${VAXD}vax_stddev.c ${VAXD}vax_sys.c \ - ${VAXD}vax_sysdev.c \ - ${PDP11D}pdp11_rl.c ${PDP11D}pdp11_rq.c ${PDP11D}pdp11_ts.c \ - ${PDP11D}pdp11_dz.c ${PDP11D}pdp11_lp.c + ${VAXD}vax_mmu.c ${VAXD}vax_stddev.c ${VAXD}vax_sys.c \ + ${VAXD}vax_sysdev.c \ + ${PDP11D}pdp11_rl.c ${PDP11D}pdp11_rq.c ${PDP11D}pdp11_ts.c \ + ${PDP11D}pdp11_dz.c ${PDP11D}pdp11_lp.c VAX_OPT = -I ${VAXD} -I ${PDP11D} -DUSE_INT64 -SDSD = SDS/ -SDS = ${SDSD}sds_stddev.c ${SDSD}sds_fhd.c ${SDSD}sds_io.c ${SDSD}sds_lp.c \ - ${SDSD}sds_mt.c ${SDSD}sds_rad.c ${SDSD}sds_cpu.c ${SDSD}sds_sys.c -SDS_OPT = -I ${SDSD} - - - S3D = S3/ S3 = ${S3D}s3_cd.c ${S3D}s3_cpu.c ${S3D}s3_disk.c ${S3D}s3_lp.c \ - ${S3D}s3_pkb.c ${S3D}s3_sys.c + ${S3D}s3_pkb.c ${S3D}s3_sys.c S3_OPT = -I ${S3D} ALTAIRD = ALTAIR/ ALTAIR = ${ALTAIRD}altair_sio.c ${ALTAIRD}altair_cpu.c ${ALTAIRD}altair_dsk.c \ - ${ALTAIRD}altair_sys.c + ${ALTAIRD}altair_sys.c ALTAIR_OPT = -I ${ALTAIRD} + +ALTAIRZ80D = AltairZ80/ +ALTAIRZ80 = ${ALTAIRZ80D}altairz80_cpu.c ${ALTAIRZ80D}altairz80_dsk.c \ + ${ALTAIRZ80D}altairz80_sio.c ${ALTAIRZ80D}altairz80_sys.c +ALTAIRZ80_OPT = -I ${ALTAIRZ80D} + + + +GRID = GRI/ +GRI = ${GRID}gri_cpu.c ${GRID}gri_stddev.c ${GRID}gri_sys.c +GRI_OPT = -I ${GRID} + + # # Build everything # all : ${BIN}pdp1 ${BIN}pdp4 ${BIN}pdp7 ${BIN}pdp8 ${BIN}pdp9 ${BIN}pdp15 \ - ${BIN}pdp11 ${BIN}pdp10 ${BIN}vax ${BIN}nova ${BIN}eclipse ${BIN}h316 \ - ${BIN}hp2100 ${BIN}id4 ${BIN}i1401 ${BIN}sds ${BIN}s3 ${BIN}altair + ${BIN}pdp11 ${BIN}pdp10 ${BIN}vax ${BIN}nova ${BIN}eclipse ${BIN}h316 \ + ${BIN}hp2100 ${BIN}i1401 ${BIN}s3 ${BIN}altair \ + ${BIN}altairz80 ${BIN}gri -# -# Make sure subdirectory exists -# -${BIN} : simh_doc.txt - -mkdir ${BIN} - -touch ${BIN} - - # # Individual builds # -${BIN}pdp1 : ${PDP1} ${SIM} ${BIN} - ${CC} ${PDP1} ${SIM} ${PDP1_OPT} -o $@ +${BIN}pdp1 : ${PDP1} ${SIM} + ${CC} ${PDP1} ${SIM} ${PDP1_OPT} -o $@ -${BIN}pdp4 : ${PDP18B} ${SIM} ${BIN} - ${CC} ${PDP18B} ${SIM} ${PDP4_OPT} -o $@ +${BIN}pdp4 : ${PDP18B} ${SIM} + ${CC} ${PDP18B} ${SIM} ${PDP4_OPT} -o $@ -${BIN}pdp7 : ${PDP18B} ${SIM} ${BIN} - ${CC} ${PDP18B} ${SIM} ${PDP7_OPT} -o $@ +${BIN}pdp7 : ${PDP18B} ${SIM} + ${CC} ${PDP18B} ${SIM} ${PDP7_OPT} -o $@ -${BIN}pdp8 : ${PDP8} ${SIM} ${BIN} - ${CC} ${PDP8} ${SIM} ${PDP8_OPT} -o $@ +${BIN}pdp8 : ${PDP8} ${SIM} + ${CC} ${PDP8} ${SIM} ${PDP8_OPT} -o $@ -${BIN}pdp9 : ${PDP18B} ${SIM} ${BIN} - ${CC} ${PDP18B} ${SIM} ${PDP9_OPT} -o $@ +${BIN}pdp9 : ${PDP18B} ${SIM} + ${CC} ${PDP18B} ${SIM} ${PDP9_OPT} -o $@ -${BIN}pdp15 : ${PDP18B} ${SIM} ${BIN} - ${CC} ${PDP18B} ${SIM} ${PDP15_OPT} -o $@ +${BIN}pdp15 : ${PDP18B} ${SIM} + ${CC} ${PDP18B} ${SIM} ${PDP15_OPT} -o $@ -${BIN}pdp10 : ${PDP10} ${SIM} ${BIN} - ${CC} ${PDP10} ${SIM} ${PDP10_OPT} -o $@ +${BIN}pdp10 : ${PDP10} ${SIM} + ${CC} ${PDP10} ${SIM} ${PDP10_OPT} -o $@ -${BIN}pdp11 : ${PDP11} ${SIM} ${BIN} - ${CC} ${PDP11} ${SIM} ${PDP11_OPT} -o $@ +${BIN}pdp11 : ${PDP11} ${SIM} + ${CC} ${PDP11} ${SIM} ${PDP11_OPT} -o $@ -${BIN}vax : ${VAX} ${SIM} ${BIN} - ${CC} ${VAX} ${SIM} ${VAX_OPT} -o $@ +${BIN}vax : ${VAX} ${SIM} + ${CC} ${VAX} ${SIM} ${VAX_OPT} -o $@ -${BIN}nova : ${NOVA} ${SIM} ${BIN} - ${CC} ${NOVA} ${SIM} ${NOVA_OPT} -o $@ +${BIN}nova : ${NOVA} ${SIM} + ${CC} ${NOVA} ${SIM} ${NOVA_OPT} -o $@ -${BIN}eclipse : ${ECLIPSE} ${SIM} ${BIN} - ${CC} ${ECLIPSE} ${SIM} ${ECLIPSE_OPT} -o $@ +${BIN}eclipse : ${ECLIPSE} ${SIM} + ${CC} ${ECLIPSE} ${SIM} ${ECLIPSE_OPT} -o $@ -${BIN}h316 : ${H316} ${SIM} ${BIN} - ${CC} ${H316} ${SIM} ${H316_OPT} -o $@ +${BIN}h316 : ${H316} ${SIM} + ${CC} ${H316} ${SIM} ${H316_OPT} -o $@ -${BIN}hp2100 : ${HP2100} ${SIM} ${BIN} - ${CC} ${HP2100} ${SIM} ${HP2100_OPT} -o $@ +${BIN}hp2100 : ${HP2100} ${SIM} + ${CC} ${HP2100} ${SIM} ${HP2100_OPT} -o $@ -${BIN}id4 : ${ID4} ${SIM} ${BIN} - ${CC} ${ID4} ${SIM} ${ID4_OPT} -o $@ +${BIN}i1401 : ${I1401} ${SIM} + ${CC} ${I1401} ${SIM} ${I1401_OPT} -o $@ -${BIN}i1401 : ${I1401} ${SIM} ${BIN} - ${CC} ${I1401} ${SIM} ${I1401_OPT} -o $@ +${BIN}s3 : ${S3} ${SIM} + ${CC} ${S3} ${SIM} ${S3_OPT} -o $@ - -${BIN}sds : ${SDS} ${SIM} ${BIN} - ${CC} ${SDS} ${SIM} ${SDS_OPT} -o $@ +${BIN}altair : ${ALTAIR} ${SIM} + ${CC} ${ALTAIR} ${SIM} ${ALTAIR_OPT} -o $@ - -${BIN}s3 : ${S3} ${SIM} ${BIN} - ${CC} ${S3} ${SIM} ${S3_OPT} -o $@ +${BIN}altairz80 : ${ALTAIRZ80} ${SIM} + ${CC} ${ALTAIRZ80_OPT} ${ALTAIRZ80} ${SIM} -o $@ -${BIN}altair : ${ALTAIR} ${SIM} ${BIN} - ${CC} ${ALTAIR} ${SIM} ${ALTAIR_OPT} -o $@ +${BIN}gri : ${GRI} ${SIM} + ${CC} ${GRI} ${SIM} ${GRI_OPT} -o $@ diff --git a/mingw_build.bat b/mingw_build.bat deleted file mode 100644 index 6921a1a3..00000000 --- a/mingw_build.bat +++ /dev/null @@ -1,41 +0,0 @@ -rem Compile all of SIMH using MINGW gcc environment -rem Master sources are in c:\sim -rem Individual simulator sources are in c:\sim\simulator_name -rem Mingw system is in C:\Mingw\bin -rem -path c:\mingw\bin;%path -cd c:\sim\pdp1 -gcc -o ..\bin\pdp1 -I.. ..\scp*.c pdp1*.c -cd c:\sim\pdp11 -gcc -o ..\bin\pdp11 -I.. ..\scp*.c ..\sim*.c pdp11*.c -lm -lwsock32 -cd c:\sim\pdp8 -gcc -o ..\bin\pdp8 -I.. ..\scp*.c ..\sim*.c pdp8*.c -lm -lwsock32 -cd c:\sim\pdp18b -gcc -DPDP4 -o ..\bin\pdp4 -I.. ..\scp*.c ..\sim*.c pdp18b*.c -lm -lwsock32 -gcc -DPDP7 -o ..\bin\pdp7 -I.. ..\scp*.c ..\sim*.c pdp18b*.c -lm -lwsock32 -gcc -DPDP9 -o ..\bin\pdp9 -I.. ..\scp*.c ..\sim*.c pdp18b*.c -lm -lwsock32 -gcc -DPDP15 -o ..\bin\pdp15 -I.. ..\scp*.c ..\sim*.c pdp18b*.c -lm -lwsock32 -cd c:\sim\pdp10 -gcc -DUSE_INT64 -o ..\bin\pdp10 -I.. ..\scp*.c ..\sim*.c pdp10*.c -lm -lwsock32 -cd c:\sim\vax -gcc -DUSE_INT64 -o ..\bin\vax -I.. -I. ..\scp*.c ..\sim*.c ..\pdp11\pdp11_rl.c ..\pdp11\pdp11_rq.c ..\pdp11\pdp11_dz.c ..\pdp11\pdp11_lp.c ..\pdp11\pdp11_ts.c vax*.c -lm -lwsock32 -cd c:\sim\nova -gcc -o ..\bin\nova -I.. ..\scp*.c ..\sim*.c nova*.c -lm -lwsock32 -cd c:\sim\altair -gcc -o ..\bin\altair -I.. ..\scp*.c altair*.c -cd c:\sim\h316 -gcc -o ..\bin\h316 -I.. ..\scp*.c h316*.c -cd c:\sim\hp2100 -gcc -o ..\bin\hp2100 -I.. ..\scp*.c hp2100*.c -cd c:\sim\i1401 -gcc -o ..\bin\i1401 -I.. ..\scp*.c i1401*.c -cd c:\sim\id4 -gcc -o ..\bin\id4 -I.. ..\scp*.c id4*.c -cd c:\sim\s3 -gcc -o ..\bin\s3 -I.. ..\scp*.c s3*.c -cd c:\sim\sds -gcc -o ..\bin\sds -I.. ..\scp*.c sds*.c -lm -cd .. - - - diff --git a/scp.c b/scp.c index fd14607f..d3ecbda1 100644 --- a/scp.c +++ b/scp.c @@ -1,6 +1,6 @@ /* scp.c: simulator control program - Copyright (c) 1993-2001, Robert M Supnik + Copyright (c) 1993-2002, Robert M Supnik Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), @@ -23,6 +23,17 @@ be used in advertising or otherwise to promote the sale, use or other dealings in this Software without prior written authorization from Robert M Supnik. + 14-Jul-02 RMS Fixed exit bug in do, added -v switch (from Brian Knittel) + 17-May-02 RMS Fixed bug in fxread/fxwrite error usage (found by + Norm Lastovic) + 02-May-02 RMS Added VT emulation interface, changed {NO}LOG to SET {NO}LOG + 22-Apr-02 RMS Fixed laptop sleep problem in clock calibration, added + magtape record length error (found by Jonathan Engdahl) + 26-Feb-02 RMS Fixed initialization bugs in do_cmd, get_avail + (found by Brian Knittel) + 10-Feb-02 RMS Fixed problem in clock calibration + 06-Jan-02 RMS Moved device enable/disable to simulators + 30-Dec-01 RMS Generalized timer packaged, added circular arrays 19-Dec-01 RMS Fixed DO command bug (found by John Dundas) 07-Dec-01 RMS Implemented breakpoint package 05-Dec-01 RMS Fixed bug in universal register logic @@ -100,8 +111,10 @@ #define SWHIDE (1u << 26) /* enable hiding */ #define SRBSIZ 1024 /* save/restore buffer */ -#define SIM_BRK_INILNT 1024 +#define SIM_BRK_INILNT 16384 /* bpt tbl length */ #define SIM_BRK_ALLTYP 0xFFFFFFFF +#define SIM_NTIMERS 8 /* # timers */ +#define SIM_TMAX 500 /* max timer makeup */ #define UPDATE_SIM_TIME(x) sim_time = sim_time + (x - sim_interval); \ sim_rtime = sim_rtime + ((uint32) (x - sim_interval)); \ x = sim_interval @@ -112,6 +125,7 @@ struct brktab { int32 cnt; char *act; }; + typedef struct brktab BRKTAB; extern char sim_name[]; @@ -131,6 +145,7 @@ extern t_stat ttcmdstate (void); extern t_stat ttclose (void); extern t_stat sim_putchar (int32 out); extern uint32 sim_os_msec (void); +extern int32 sim_vt; UNIT *sim_clock_queue = NULL; int32 sim_interval = 0; int32 sim_switches = 0; @@ -198,10 +213,21 @@ void sim_brk_npc (void); else if (sim_switches & SWMASK ('H')) val = 16; \ else val = dft; -t_stat set_glob (CTAB *tab, char *gbuf, DEVICE *dptr, UNIT *uptr); -t_stat ssh_break (FILE *st, char *cptr, int32 flg); +CTAB *find_ctab (CTAB *tab, char *gbuf); +t_stat set_vt (int32 flag, char *cptr); +t_stat set_logon (int32 flag, char *cptr); +t_stat set_logoff (int32 flag, char *cptr); t_stat set_radix (DEVICE *dptr, UNIT *uptr, int flag); t_stat set_onoff (DEVICE *dptr, UNIT *uptr, int32 flag); +t_stat ssh_break (FILE *st, char *cptr, int32 flg); +t_stat show_config (FILE *st, int32 flag); +t_stat show_queue (FILE *st, int32 flag); +t_stat show_time (FILE *st, int32 flag); +t_stat show_mod_names (FILE *st, int32 flag); +t_stat show_log (FILE *st, int32 flag); +t_stat show_vt (FILE *st, int32 flag); +t_stat show_device (FILE *st, DEVICE *dptr, int32 flag); +t_stat show_unit (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag); t_stat show_all_mods (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flg); t_stat show_one_mod (FILE *st, DEVICE *dptr, UNIT *uptr, MTAB *mptr, int32 flag); int32 get_switches (char *cptr); @@ -214,8 +240,6 @@ void fprint_stopped (FILE *stream, t_stat r); char *read_line (char *ptr, int size, FILE *stream); DEVICE *find_dev (char *ptr); DEVICE *find_unit (char *ptr, UNIT **uptr); -DEVICE *find_dev_from_unit (UNIT *uptr); -REG *find_reg (char *ptr, char **optr, DEVICE *dptr); REG *find_reg_glob (char *ptr, char **optr, DEVICE **gdptr); t_bool qdisable (DEVICE *dptr); t_stat attach_err (UNIT *uptr, t_stat stat); @@ -263,8 +287,6 @@ const char *scp_error_messages[] = { "Subscript out of range", "Command not allowed", "Unit disabled", - "Logging enabled", - "Logging disabled", "Read only operation not allowed", "Invalid switch", "Missing value", @@ -275,7 +297,8 @@ const char *scp_error_messages[] = { "Non-existent register", "Non-existent parameter", "Nested DO commands", - "Internal error" + "Internal error", + "Invalid magtape record length" }; const size_t size_map[] = { sizeof (int8), @@ -319,10 +342,6 @@ t_stat restore_cmd (int flag, char *ptr); t_stat exit_cmd (int flag, char *ptr); t_stat set_cmd (int flag, char *ptr); t_stat show_cmd (int flag, char *ptr); -t_stat enable_cmd (int flag, char *ptr); -t_stat disable_cmd (int flag, char *ptr); -t_stat log_cmd (int flag, char *ptr); -t_stat nolog_cmd (int flag, char *ptr); t_stat brk_cmd (int flag, char *ptr); t_stat do_cmd (int flag, char *ptr); t_stat help_cmd (int flag, char *ptr); @@ -350,10 +369,6 @@ static CTAB cmd_table[] = { { "BYE", &exit_cmd, 0 }, { "SET", &set_cmd, 0 }, { "SHOW", &show_cmd, 0 }, - { "ENABLE", &enable_cmd, 0 }, - { "DISABLE", &disable_cmd, 0 }, - { "LOG", &log_cmd, 0 }, - { "NOLOG", &nolog_cmd, 0 }, { "BREAK", &brk_cmd, SSH_ST }, { "NOBREAK", &brk_cmd, SSH_CL }, { "DO", &do_cmd, 0 }, @@ -424,7 +439,7 @@ do { printf ("sim> "); /* prompt */ } while (stat != SCPE_EXIT); detach_all (0, TRUE); /* close files */ -nolog_cmd (0, NULL); /* close log */ +set_logoff (0, NULL); /* close log */ ttclose (); /* close console */ return 0; } @@ -459,18 +474,20 @@ fprintf (st, "det{ach} detach file from simulated unit\n"); fprintf (st, "sa{ve} save simulator to file\n"); fprintf (st, "rest{ore}|ge{t} restore simulator from file\n"); fprintf (st, "exi{t}|q{uit}|by{e} exit from simulation\n"); +fprintf (st, "set log enable logging to file\n"); +fprintf (st, "set nolog disable logging\n"); +fprintf (st, "set vt enable VT emulation (Windows only)\n"); +fprintf (st, "set novt disable VT emulation (Windows only)\n"); fprintf (st, "set | set device/unit parameter\n"); -fprintf (st, "sh{ow} | show device parameters\n"); fprintf (st, "sh{ow} c{onfiguration} show configuration\n"); fprintf (st, "sh{ow} d{evices} show devices\n"); +fprintf (st, "sh{ow} l{og} show log\n"); fprintf (st, "sh{ow} m{odifiers} show modifiers\n"); fprintf (st, "sh{ow} q{ueue} show event queue\n"); fprintf (st, "sh{ow} t{ime} show simulated time\n"); -fprintf (st, "sh{ow} v{ersion} show simulator version\n"); -fprintf (st, "en{able} enable device\n"); -fprintf (st, "di{sable} disable device\n"); -fprintf (st, "log enable logging to file\n"); -fprintf (st, "nolog disable logging\n"); +fprintf (st, "sh{ow} ve{rsion} show simulator version\n"); +fprintf (st, "sh{ow} vt show VT emulation\n"); +fprintf (st, "sh{ow} | show device parameters\n"); fprintf (st, "do process command file\n"); fprintf (st, "h{elp} type this message\n"); return; @@ -489,14 +506,17 @@ t_stat do_cmd (int flag, char *fcptr) { char *cptr, cbuf[CBUFSIZE], gbuf[CBUFSIZE]; FILE *fpin; -int32 i; -t_stat stat; +int32 i, echo; +t_stat stat = SCPE_OK; +GET_SWITCHES (fcptr, gbuf); /* get switches */ +echo = sim_switches & SWMASK ('V'); /* set echo flag */ if ((fpin = fopen (fcptr, "r")) != NULL) { /* cmd file open? */ do { cptr = read_line (cbuf, CBUFSIZE, fpin); /* get cmd line */ if (cptr == NULL) break; /* exit on eof */ if (*cptr == 0) continue; /* ignore blank */ + if (echo) printf ("do> %s\n", cptr); /* echo cmd? */ if (sim_log) fprintf (sim_log, "do> %s\n", cptr); cptr = get_glyph (cptr, gbuf, 0); /* get command glyph */ if (strcmp (gbuf, "do") == 0) { /* don't recurse */ @@ -508,9 +528,11 @@ if ((fpin = fopen (fcptr, "r")) != NULL) { /* cmd file open? */ break; } } if (stat >= SCPE_BASE) /* error? */ printf ("%s\n", scp_error_messages[stat - SCPE_BASE]); - } while (stat != SCPE_EXIT); + } + while (stat != SCPE_EXIT); fclose (fpin); /* close file */ - return SCPE_OK; } /* end if cmd file */ + return ((stat == SCPE_EXIT)? SCPE_EXIT: SCPE_OK); + } /* end if cmd file */ return SCPE_OPENERR; } @@ -524,7 +546,13 @@ char gbuf[CBUFSIZE], *cvptr; DEVICE *dptr; UNIT *uptr; MTAB *mptr; -CTAB *ctbr; +CTAB *ctbr, *glbr; +static CTAB set_glob_tab[] = { + { "VT", &set_vt, 1 }, + { "NOVT", &set_vt, 0 }, + { "LOG", &set_logon, 0 }, + { "NOLOG", &set_logoff, 0 }, + { NULL, NULL, 0 } }; static CTAB set_dev_tab[] = { { "OCTAL", &set_radix, 8 }, { "DECIMAL", &set_radix, 10 }, @@ -538,6 +566,8 @@ static CTAB set_unit_tab[] = { GET_SWITCHES (cptr, gbuf); /* get switches */ if (*cptr == 0) return SCPE_2FARG; /* must be more */ cptr = get_glyph (cptr, gbuf, 0); /* get glob/dev/unit */ +if (glbr = find_ctab (set_glob_tab, gbuf)) /* global? */ + return glbr -> action (glbr -> arg, cptr); /* do the rest */ if (*cptr == 0) return SCPE_2FARG; /* must be more */ if (dptr = find_dev (gbuf)) { /* device match? */ @@ -554,8 +584,8 @@ if (dptr -> modifiers == NULL) return SCPE_NOPARAM; /* any modifiers? */ while (*cptr != 0) { /* do all mods */ cptr = get_glyph (cptr, gbuf, ','); /* get modifier */ if (cvptr = strchr (gbuf, '=')) *cvptr++ = 0; /* = value? */ - if (set_glob (ctbr, gbuf, dptr, uptr) == SCPE_OK) /* global match? */ - return SCPE_OK; + if (glbr = find_ctab (ctbr, gbuf)) /* global match? */ + return glbr -> action (dptr, uptr, glbr -> arg); for (mptr = dptr -> modifiers; mptr -> mask != 0; mptr++) { if ((mptr -> mstring) && /* match string */ (MATCH_CMD (gbuf, mptr -> mstring) == 0)) { /* matches option? */ @@ -591,13 +621,54 @@ while (*cptr != 0) { /* do all mods */ } /* end while */ return SCPE_OK; /* done all */ } + +/* Match CTAB name */ -t_stat set_glob (CTAB *tab, char *gbuf, DEVICE *dptr, UNIT *uptr) +CTAB *find_ctab (CTAB *tab, char *gbuf) { for (; tab -> name != NULL; tab++) { - if (MATCH_CMD (gbuf, tab -> name) == 0) - return tab -> action (dptr, uptr, tab -> arg); } -return SCPE_NXPAR; + if (MATCH_CMD (gbuf, tab -> name) == 0) return tab; } +return NULL; +} + +/* VT on/off routine */ + +t_stat set_vt (int32 val, char *cptr) +{ +if (sim_vt < 0) return SCPE_NOFNC; /* not possible */ +if (*cptr) return SCPE_2MARG; /* no more args */ +sim_vt = val; +return SCPE_OK; +} + +/* Log on routine */ + +t_stat set_logon (int flag, char *cptr) +{ +char gbuf[CBUFSIZE]; + +if (*cptr == 0) SCPE_2FARG; /* need arg */ +cptr = get_glyph_nc (cptr, gbuf, 0); /* get file name */ +if (*cptr != 0) return SCPE_2MARG; /* now eol? */ +set_logoff (0, NULL); /* close cur log */ +sim_log = fopen (gbuf, "a"); /* open log */ +if (sim_log == NULL) return SCPE_OPENERR; /* error? */ +printf ("Logging to file \"%s\"\n", gbuf); /* start of log */ +fprintf (sim_log, "Logging to file \"%s\"\n", gbuf); +return SCPE_OK; +} + +/* Log off routine */ + +t_stat set_logoff (int flag, char *cptr) +{ +if (cptr && (*cptr != 0)) return SCPE_2MARG; /* now eol? */ +if (sim_log == NULL) return SCPE_OK; /* no log? */ +printf ("Log file closed\n"); +fprintf (sim_log, "Log file closed\n"); /* close log */ +fclose (sim_log); +sim_log = NULL; +return SCPE_OK; } /* Set radix routine */ @@ -632,13 +703,6 @@ DEVICE *dptr; UNIT *uptr; MTAB *mptr; -t_stat show_config (FILE *st, int32 flag); -t_stat show_queue (FILE *st, int32 flag); -t_stat show_time (FILE *st, int32 flag); -t_stat show_mod_names (FILE *st, int32 flag); -t_stat show_device (FILE *st, DEVICE *dptr, int32 flag); -t_stat show_unit (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag); - static CTAB show_table[] = { { "CONFIGURATION", &show_config, 0 }, { "DEVICES", &show_config, 1 }, @@ -646,6 +710,8 @@ static CTAB show_table[] = { { "TIME", &show_time, 0 }, { "MODIFIERS", &show_mod_names, 0 }, { "VERSION", &show_version, 0 }, + { "LOG", &show_log, 0 }, + { "VT", &show_vt, 0 }, { NULL, NULL, 0 } }; GET_SWITCHES (cptr, gbuf); /* test for switches */ @@ -689,7 +755,7 @@ while (*cptr != 0) { /* do all mods */ (mptr -> mask & lvl): (MTAB_VUN & lvl)) && ((mptr -> disp && mptr -> pstring && /* named disp? */ (MATCH_CMD (gbuf, mptr -> pstring) == 0)) || - (((mptr -> mask & MTAB_XTV) == MTAB_XTV) && /* named value? */ + ((mptr -> mask & MTAB_VAL) && /* named value? */ mptr -> mstring && (MATCH_CMD (gbuf, mptr -> mstring) == 0)))) { show_one_mod (stdout, dptr, uptr, mptr, 1); @@ -697,6 +763,7 @@ while (*cptr != 0) { /* do all mods */ break; } /* end if */ } /* end for */ + if (mptr -> mask == 0) return SCPE_ARG; /* any match? */ } /* end while */ return SCPE_OK; } @@ -801,6 +868,21 @@ fprintf (st, "Time: %-16.0f\n", sim_time); return SCPE_OK; } +t_stat show_log (FILE *st, int32 flag) +{ +if (sim_log) fprintf (st, "Logging enabled\n"); +else fprintf (st, "Logging disabled\n"); +return SCPE_OK; +} + +t_stat show_vt (FILE *st, int32 flag) +{ +if (sim_vt < 0) fprintf (st, "VT emulation not available\n"); +else if (sim_vt) fprintf (st, "VT emulation enabled\n"); +else fprintf (st, "VT emulation disabled\n"); +return SCPE_OK; +} + t_stat show_mod_names (FILE *st, int32 flag) { int i, any; @@ -837,14 +919,15 @@ t_stat show_one_mod (FILE *st, DEVICE *dptr, UNIT *uptr, MTAB *mptr, int32 flag) t_value val; if (mptr -> disp) mptr -> disp (st, uptr, mptr -> match, mptr -> desc); -else if ((mptr -> mask & MTAB_XTV) == MTAB_XTV) { +else if ((mptr -> mask & MTAB_XTD) && (mptr -> mask & MTAB_VAL)) { REG *rptr = (REG *) mptr -> desc; fprintf (st, "%s=", mptr -> pstring); val = get_rval (rptr, 0); fprint_val (st, val, rptr -> radix, rptr -> width, rptr -> flags & REG_FMT); } else fputs (mptr -> pstring, st); -if (flag) fputc ('\n', st); +if (flag && !((mptr -> mask & MTAB_XTD) && + (mptr -> mask & MTAB_NMO))) fputc ('\n', st); return SCPE_OK; } @@ -899,104 +982,6 @@ while (*cptr) { return SCPE_OK; } -/* Enable and disable commands and routines - - en[able] enable device - di[sable] disable device -*/ - -t_stat enable_cmd (int flag, char *cptr) -{ -char gbuf[CBUFSIZE]; -DEVICE *dptr; -REG *rptr; - -GET_SWITCHES (cptr, gbuf); /* test for switches */ -if (*cptr == 0) return SCPE_2FARG; /* must be more */ -cptr = get_glyph (cptr, gbuf, 0); /* get next glyph */ -dptr = find_dev (gbuf); /* locate device */ -if (dptr == NULL) return SCPE_NXDEV; /* found it? */ -if (*cptr != 0) return SCPE_2MARG; /* now eol? */ -rptr = find_reg ("*DEVENB", NULL, dptr); /* locate enable */ -if (rptr == NULL) return SCPE_NOFNC; /* found it? */ -put_rval (rptr, 0, 1); /* enable */ -if (dptr -> reset) dptr -> reset (dptr); /* reset */ -return SCPE_OK; -} - -t_stat disable_cmd (int flag, char *cptr) -{ -int32 i; -char gbuf[CBUFSIZE]; -DEVICE *dptr; -UNIT *uptr; -REG *rptr; - -GET_SWITCHES (cptr, gbuf); /* test for switches */ -if (*cptr == 0) return SCPE_2FARG; /* must be more */ -cptr = get_glyph (cptr, gbuf, 0); /* get next glyph */ -dptr = find_dev (gbuf); /* locate device */ -if (dptr == NULL) return SCPE_NXDEV; /* found it? */ -if (*cptr != 0) return SCPE_2MARG; /* now eol? */ -rptr = find_reg ("*DEVENB", NULL, dptr); /* locate enable */ -if (rptr == NULL) return SCPE_NOFNC; /* found it? */ -for (i = 0; i < dptr -> numunits; i++) { /* check units */ - uptr = (dptr -> units) + i; - if (uptr -> flags & UNIT_ATT || sim_is_active (uptr)) - return SCPE_NOFNC; } -put_rval (rptr, 0, 0); /* disable */ -if (dptr -> reset) dptr -> reset (dptr); /* reset */ -return SCPE_OK; -} - -/* Test for disabled device */ - -t_bool qdisable (DEVICE *dptr) -{ -REG *rptr; - -rptr = find_reg ("*DEVENB", NULL, dptr); /* locate enable */ -if (rptr == NULL) return FALSE; /* found it? */ -return (get_rval (rptr, 0)? FALSE: TRUE); /* return flag */ -} - -/* Logging commands - - log filename open log file - nolog close log file -*/ - -t_stat log_cmd (int flag, char *cptr) -{ -char gbuf[CBUFSIZE]; - -GET_SWITCHES (cptr, gbuf); /* test for switches */ -if (*cptr == 0) return (sim_log? SCPE_LOGON: SCPE_LOGOFF); -cptr = get_glyph_nc (cptr, gbuf, 0); /* get file name */ -if (*cptr != 0) return SCPE_2MARG; /* now eol? */ -nolog_cmd (0, NULL); /* close cur log */ -sim_log = fopen (gbuf, "a"); /* open log */ -if (sim_log == NULL) return SCPE_OPENERR; /* error? */ -printf ("Logging to file \"%s\"\n", gbuf); /* start of log */ -fprintf (sim_log, "Logging to file \"%s\"\n", gbuf); -return SCPE_OK; -} - -t_stat nolog_cmd (int flag, char *cptr) -{ -char gbuf[CBUFSIZE]; - -if (cptr) { - GET_SWITCHES (cptr, gbuf); /* test for switches */ - if (*cptr != 0) return SCPE_2MARG; } /* now eol? */ -if (sim_log == NULL) return SCPE_OK; /* no log? */ -printf ("Log file closed\n"); -fprintf (sim_log, "Log file closed\n"); /* close log */ -fclose (sim_log); -sim_log = NULL; -return SCPE_OK; -} - /* Reset command and routines re[set] reset all devices @@ -1118,13 +1103,15 @@ else { /* normal */ return attach_err (uptr, SCPE_NORO); /* no error */ uptr -> fileref = fopen (cptr, "rb"); /* open rd only */ if (uptr -> fileref == NULL) /* open fail? */ - return SCPE_OPENERR; /* yes, error */ + return attach_err (uptr, SCPE_OPENERR); /* yes, error */ uptr -> flags = uptr -> flags | UNIT_RO; /* set rd only */ printf ("%s: unit is read only\n", dptr -> name); } else { /* doesn't exist */ + if (sim_switches & SWMASK ('E')) /* must exist? */ + return attach_err (uptr, SCPE_OPENERR); /* yes, error */ uptr -> fileref = fopen (cptr, "wb+"); /* open new file */ if (uptr -> fileref == NULL) /* open fail? */ - return SCPE_OPENERR; /* yes, error */ + return attach_err (uptr, SCPE_OPENERR); /* yes, error */ printf ("%s: creating new file\n", dptr -> name); } } /* end if null */ } /* end else */ @@ -1134,7 +1121,8 @@ if (uptr -> flags & UNIT_BUFABLE) { /* buffer? */ uptr -> hwmark = fxread (uptr -> filebuf, SZ_D (dptr), uptr -> capac, uptr -> fileref); uptr -> flags = uptr -> flags | UNIT_BUF; } - else if (uptr -> flags & UNIT_MUSTBUF) return SCPE_MEM; } + else if (uptr -> flags & UNIT_MUSTBUF) /* must buf? */ + return attach_err (uptr, SCPE_MEM); } uptr -> flags = uptr -> flags | UNIT_ATT; uptr -> pos = 0; return SCPE_OK; @@ -1332,7 +1320,7 @@ REG *rptr; #define READ_S(xx) if (read_line ((xx), CBUFSIZE, rfile) == NULL) \ { fclose (rfile); return SCPE_IOERR; } -#define READ_I(xx) if (fxread (&xx, sizeof (xx), 1, rfile) <= 0) \ +#define READ_I(xx) if (fxread (&xx, sizeof (xx), 1, rfile) == 0) \ { fclose (rfile); return SCPE_IOERR; } GET_SWITCHES (cptr, buf); /* test for switches */ @@ -1425,8 +1413,8 @@ for ( ;; ) { /* device loop */ if (buf[0] == 0) break; /* last? */ if ((rptr = find_reg (buf, NULL, dptr)) == NULL) { printf ("Invalid register name: %s\n", buf); - fclose (rfile); - return SCPE_INCOMP; } + READ_I (val); /* assume depth=1 */ + continue; } /* and pray! */ mask = width_mask[rptr -> width]; for (i = 0; i < rptr -> depth; i++) { /* loop thru values */ READ_I (val); /* read value */ @@ -1790,6 +1778,9 @@ t_value val; UNIT *uptr; sz = SZ_R (rptr); +if ((rptr -> depth > 1) && (rptr -> flags & REG_CIRC)) { + idx = idx + rptr -> qptr; + if (idx >= rptr -> depth) idx = idx - rptr -> depth; } if ((rptr -> depth > 1) && (rptr -> flags & REG_UNIT)) { uptr = ((UNIT *) rptr -> loc) + idx; val = *((uint32 *) uptr); } @@ -1867,6 +1858,9 @@ UNIT *uptr; if (rptr == sim_PC) sim_brk_npc (); sz = SZ_R (rptr); mask = width_mask[rptr -> width]; +if ((rptr -> depth > 1) && (rptr -> flags & REG_CIRC)) { + idx = idx + rptr -> qptr; + if (idx >= rptr -> depth) idx = idx - rptr -> depth; } if ((rptr -> depth > 1) && (rptr -> flags & REG_UNIT)) { uptr = ((UNIT *) rptr -> loc) + idx; *((uint32 *) uptr) = @@ -1933,8 +1927,8 @@ t_stat get_aval (t_addr addr, DEVICE *dptr, UNIT *uptr) int32 i; t_value mask; t_addr j, loc; -t_stat reason; size_t sz; +t_stat reason = SCPE_OK; if ((dptr == NULL) || (uptr == NULL)) return SCPE_IERR; mask = width_mask[dptr -> dwidth]; @@ -2243,6 +2237,17 @@ for (i = 0; (dptr = sim_devices[i]) != NULL; i++) { if (uptr == (dptr -> units + j)) return dptr; } } return NULL; } + +/* Test for disabled device */ + +t_bool qdisable (DEVICE *dptr) +{ +REG *rptr; + +rptr = find_reg ("*DEVENB", NULL, dptr); /* locate enable */ +if (rptr == NULL) return FALSE; /* found it? */ +return (get_rval (rptr, 0)? FALSE: TRUE); /* return flag */ +} /* find_reg_glob find globally unique register @@ -2569,7 +2574,7 @@ else { UPDATE_SIM_TIME (sim_clock_queue -> time); } /* update sim time */ prvptr = NULL; accum = 0; for (cptr = sim_clock_queue; cptr != NULL; cptr = cptr -> next) { - if (event_time < accum + cptr -> time) break; + if (event_time < (accum + cptr -> time)) break; accum = accum + cptr -> time; prvptr = cptr; } if (prvptr == NULL) { /* insert at head */ @@ -2747,49 +2752,66 @@ return total; sim_rtc_calb calibrate clock */ -static int32 rtc_ticks = 0; /* ticks */ -static uint32 rtc_realtime = 0; /* real time */ -static uint32 rtc_virttime = 0; /* virtual time */ -static uint32 rtc_nextintv = 0; /* next interval */ -static int32 rtc_basedelay = 0; /* base delay */ -static int32 rtc_currdelay = 0; /* current delay */ +static int32 rtc_ticks[SIM_NTIMERS] = { 0 }; /* ticks */ +static uint32 rtc_rtime[SIM_NTIMERS] = { 0 }; /* real time */ +static uint32 rtc_vtime[SIM_NTIMERS] = { 0 }; /* virtual time */ +static uint32 rtc_nxintv[SIM_NTIMERS] = { 0 }; /* next interval */ +static int32 rtc_based[SIM_NTIMERS] = { 0 }; /* base delay */ +static int32 rtc_currd[SIM_NTIMERS] = { 0 }; /* current delay */ extern t_bool rtc_avail; -#define TMAX 500 /* max makeup per sec */ + +int32 sim_rtcn_init (int32 time, int32 tmr) +{ +if ((tmr < 0) || (tmr >= SIM_NTIMERS)) return time; +rtc_rtime[tmr] = sim_os_msec (); +rtc_vtime[tmr] = rtc_rtime[tmr]; +rtc_nxintv[tmr] = 1000; +rtc_ticks[tmr] = 0; +rtc_based[tmr] = time; +rtc_currd[tmr] = time; +return time; +} + +int32 sim_rtcn_calb (int32 ticksper, int32 tmr) +{ +uint32 new_rtime, delta_rtime; +int32 delta_vtime; + +if ((tmr < 0) || (tmr >= SIM_NTIMERS)) return 10000; +rtc_ticks[tmr] = rtc_ticks[tmr] + 1; /* count ticks */ +if (rtc_ticks[tmr] < ticksper) return rtc_currd[tmr]; /* 1 sec yet? */ +rtc_ticks[tmr] = 0; /* reset ticks */ +if (!rtc_avail) return rtc_currd[tmr]; /* no timer? */ +new_rtime = sim_os_msec (); /* wall time */ +if (new_rtime < rtc_rtime[tmr]) { /* time running backwards? */ + rtc_rtime[tmr] = new_rtime; /* reset wall time */ + return rtc_currd[tmr]; } /* can't calibrate */ +delta_rtime = new_rtime - rtc_rtime[tmr]; /* elapsed wtime */ +rtc_rtime[tmr] = new_rtime; /* adv wall time */ +if ((delta_rtime == 0) || (delta_rtime > 30000)) /* gap 0 or too big? */ + return rtc_currd[tmr]; /* can't calibr */ +rtc_based[tmr] = (int32) (((double) rtc_based[tmr] * (double) rtc_nxintv[tmr]) / + ((double) delta_rtime)); /* new base rate */ +rtc_vtime[tmr] = rtc_vtime[tmr] + 1000; /* adv sim time */ +delta_vtime = rtc_vtime[tmr] - rtc_rtime[tmr]; /* gap */ +if (delta_vtime > SIM_TMAX) delta_vtime = SIM_TMAX; /* limit gap */ +else if (delta_vtime < -SIM_TMAX) delta_vtime = -SIM_TMAX; +rtc_nxintv[tmr] = 1000 + delta_vtime; /* next wtime */ +rtc_currd[tmr] = (int32) (((double) rtc_based[tmr] * (double) rtc_nxintv[tmr]) / + 1000.0); /* next delay */ +return rtc_currd[tmr]; +} + +/* Prior interfaces - default to timer 0 */ int32 sim_rtc_init (int32 time) { -rtc_realtime = sim_os_msec (); -rtc_virttime = rtc_realtime; -rtc_nextintv = 1000; -rtc_ticks = 0; -rtc_basedelay = time; -rtc_currdelay = time; -return rtc_currdelay; +return sim_rtcn_init (time, 0); } int32 sim_rtc_calb (int32 ticksper) { -uint32 new_realtime, delta_realtime; -int32 delta_virttime; - -rtc_ticks = rtc_ticks + 1; /* count ticks */ -if (rtc_ticks < ticksper) return rtc_currdelay; /* 1 sec yet? */ -rtc_ticks = 0; /* reset ticks */ -if (!rtc_avail) return rtc_currdelay; /* no timer? */ -new_realtime = sim_os_msec (); /* wall time */ -delta_realtime = new_realtime - rtc_realtime; /* elapsed wtime */ -if (delta_realtime == 0) return rtc_currdelay; /* can't calibr */ -rtc_basedelay = (int32) (((double) rtc_basedelay * (double) rtc_nextintv) / - ((double) delta_realtime)); /* new base rate */ -rtc_realtime = new_realtime; /* adv wall time */ -rtc_virttime = rtc_virttime + 1000; /* adv sim time */ -delta_virttime = rtc_virttime - rtc_realtime; /* gap */ -if (delta_virttime > TMAX) delta_virttime = TMAX; /* limit gap */ -else if (delta_virttime < -TMAX) delta_virttime = -TMAX; -rtc_nextintv = 1000 + delta_virttime; /* next wtime */ -rtc_currdelay = (int32) (((double) rtc_basedelay * (double) rtc_nextintv) / - 1000.0); /* next delay */ -return rtc_currdelay; +return sim_rtcn_calb (ticksper, 0); } /* Breakpoint package. This module replaces the VM-implemented one diff --git a/scp_tty.c b/scp_tty.c index d46159cf..741b386a 100644 --- a/scp_tty.c +++ b/scp_tty.c @@ -1,6 +1,6 @@ /* scp_tty.c: operating system-dependent I/O routines - Copyright (c) 1993-2001, Robert M Supnik + Copyright (c) 1993-2002, Robert M Supnik Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), @@ -23,6 +23,9 @@ be used in advertising or otherwise to promote the sale, use or other dealings in this Software without prior written authorization from Robert M Supnik. + 14-Jul-02 RMS Added Windows priority control from Mark Pizzolato + 20-May-02 RMS Added Windows VT support from Fischer Franz + 01-Feb-02 RMS Added VAX fix from Robert Alan Byer 19-Sep-01 RMS More Mac changes 31-Aug-01 RMS Changed int64 to t_int64 for Windoze 20-Jul-01 RMS Added Macintosh support (from Louis Chretien, Peter Schorn, @@ -56,10 +59,15 @@ int32 sim_int_char = 005; /* interrupt character */ extern FILE *sim_log; -/* VMS routines, from Ben Thomas */ +/* VMS routines, from Ben Thomas, with fixes from Robert Alan Byer */ #if defined (VMS) #define __TTYROUTINES 0 +#if defined(__VAX) +#define sys$assign SYS$ASSIGN +#define sys$qiow SYS$QIOW +#define sys$gettim SYS$GETTIM +#endif #include #include @@ -81,6 +89,7 @@ typedef struct { unsigned int32 dev_status; } IOSB; SENSE_BUF cmd_mode = { 0 }; SENSE_BUF run_mode = { 0 }; +int32 sim_vt = -1; t_stat ttinit (void) { @@ -196,7 +205,9 @@ return quo; #include #include #include +#include "sim_vt.h" static volatile int sim_win_ctlc = 0; +int32 sim_vt = 0; void win_handler (int sig) { @@ -206,18 +217,23 @@ return; t_stat ttinit (void) { +vt_init (); return SCPE_OK; } t_stat ttrunstate (void) { sim_win_ctlc = 0; +if (sim_vt > 0) vt_run (); if ((int) signal (SIGINT, win_handler) == -1) return SCPE_SIGERR; +SetThreadPriority (GetCurrentThread(), THREAD_PRIORITY_BELOW_NORMAL); return SCPE_OK; } t_stat ttcmdstate (void) { +if (sim_vt > 0) vt_cmd (); +SetThreadPriority (GetCurrentThread(), THREAD_PRIORITY_NORMAL); return SCPE_OK; } @@ -234,8 +250,11 @@ if (sim_win_ctlc) { sim_win_ctlc = 0; signal (SIGINT, win_handler); return 003 | SCPE_KFLAG; } -if (!kbhit ()) return SCPE_OK; -c = _getch (); +if (sim_vt > 0) { + c = vt_read (); + if (c == -1) return SCPE_OK; } +else { if (!kbhit ()) return SCPE_OK; + c = _getch (); } if ((c & 0177) == '\b') c = 0177; if ((c & 0177) == sim_int_char) return SCPE_STOP; return c | SCPE_KFLAG; @@ -243,9 +262,9 @@ return c | SCPE_KFLAG; t_stat sim_putchar (int32 c) { -if (c != 0177) { - _putch (c); - if (sim_log) fputc (c, sim_log); } +if (sim_vt > 0) vt_write ((char) c); +else if (c != 0177) _putch (c); +if (sim_log) fputc (c, sim_log); return SCPE_OK; } @@ -263,6 +282,7 @@ return GetTickCount (); #if defined (__OS2__) #define __TTYROUTINES 0 #include +int32 sim_vt = -1; t_stat ttinit (void) { @@ -329,6 +349,7 @@ return 0; #include #include +int32 sim_vt = -1; extern char sim_name[]; extern pSIOUXWin SIOUXTextWindow; static CursHandle iBeamCursorH = NULL; /* contains the iBeamCursor */ @@ -500,6 +521,7 @@ return (uint32) millis; #include #include +int32 sim_vt = -1; struct sgttyb cmdtty,runtty; /* V6/V7 stty data */ struct tchars cmdtchars,runtchars; /* V7 editing */ struct ltchars cmdltchars,runltchars; /* 4.2 BSD editing */ @@ -594,6 +616,7 @@ return msec; #include #include +int32 sim_vt = -1; struct termios cmdtty, runtty; t_stat ttinit (void) diff --git a/sim_defs.h b/sim_defs.h index 4f17e784..be0ea3bb 100644 --- a/sim_defs.h +++ b/sim_defs.h @@ -1,6 +1,6 @@ /* sim_defs.h: simulator definitions - Copyright (c) 1993-2001, Robert M Supnik + Copyright (c) 1993-2002, Robert M Supnik Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), @@ -23,6 +23,9 @@ be used in advertising or otherwise to promote the sale, use or other dealings in this Software without prior written authorization from Robert M Supnik. + 02-May-02 RMS Removed log status codes + 22-Apr-02 RMS Added magtape record length error + 30-Dec-01 RMS Generalized timer package, added circular arrays 07-Dec-01 RMS Added breakpoint package 01-Dec-01 RMS Added read-only unit support, extended SET/SHOW features, improved error messages @@ -146,19 +149,18 @@ typedef int32 t_mtrlnt; /* magtape rec lnt */ #define SCPE_SUB (SCPE_BASE + 24) /* subscript err */ #define SCPE_NOFNC (SCPE_BASE + 25) /* func not imp */ #define SCPE_UDIS (SCPE_BASE + 26) /* unit disabled */ -#define SCPE_LOGON (SCPE_BASE + 27) /* logging enabled */ -#define SCPE_LOGOFF (SCPE_BASE + 28) /* logging disabled */ -#define SCPE_NORO (SCPE_BASE + 29) /* rd only not ok */ -#define SCPE_INVSW (SCPE_BASE + 30) /* invalid switch */ -#define SCPE_MISVAL (SCPE_BASE + 31) /* missing value */ -#define SCPE_2FARG (SCPE_BASE + 32) /* too few arguments */ -#define SCPE_2MARG (SCPE_BASE + 33) /* too many arguments */ -#define SCPE_NXDEV (SCPE_BASE + 34) /* nx device */ -#define SCPE_NXUN (SCPE_BASE + 35) /* nx unit */ -#define SCPE_NXREG (SCPE_BASE + 36) /* nx register */ -#define SCPE_NXPAR (SCPE_BASE + 37) /* nx parameter */ -#define SCPE_NEST (SCPE_BASE + 40) /* nested DO */ -#define SCPE_IERR (SCPE_BASE + 41) /* internal error */ +#define SCPE_NORO (SCPE_BASE + 27) /* rd only not ok */ +#define SCPE_INVSW (SCPE_BASE + 28) /* invalid switch */ +#define SCPE_MISVAL (SCPE_BASE + 29) /* missing value */ +#define SCPE_2FARG (SCPE_BASE + 30) /* too few arguments */ +#define SCPE_2MARG (SCPE_BASE + 31) /* too many arguments */ +#define SCPE_NXDEV (SCPE_BASE + 32) /* nx device */ +#define SCPE_NXUN (SCPE_BASE + 33) /* nx unit */ +#define SCPE_NXREG (SCPE_BASE + 34) /* nx register */ +#define SCPE_NXPAR (SCPE_BASE + 35) /* nx parameter */ +#define SCPE_NEST (SCPE_BASE + 36) /* nested DO */ +#define SCPE_IERR (SCPE_BASE + 37) /* internal error */ +#define SCPE_MTRLNT (SCPE_BASE + 38) /* tape rec lnt error */ #define SCPE_KFLAG 01000 /* tti data flag */ /* Print value format codes */ @@ -257,13 +259,15 @@ struct reg { int32 offset; /* starting bit */ int32 depth; /* save depth */ int32 flags; /* flags */ + int32 qptr; /* circ q ptr */ }; -#define REG_FMT 003 /* see PV_x */ -#define REG_RO 004 /* read only */ -#define REG_HIDDEN 010 /* hidden */ -#define REG_NZ 020 /* must be non-zero */ -#define REG_UNIT 040 /* in unit struct */ +#define REG_FMT 0003 /* see PV_x */ +#define REG_RO 0004 /* read only */ +#define REG_HIDDEN 0010 /* hidden */ +#define REG_NZ 0020 /* must be non-zero */ +#define REG_UNIT 0040 /* in unit struct */ +#define REG_CIRC 0100 /* circular array */ #define REG_HRO (REG_RO | REG_HIDDEN) /* hidden, read only */ /* Command table */ @@ -293,7 +297,6 @@ struct mtab { #define MTAB_VUN 002 /* valid for unit */ #define MTAB_VAL 004 /* takes a value */ #define MTAB_NMO 010 /* only if named */ -#define MTAB_XTV (MTAB_XTD | MTAB_XTD) /* ext with value */ /* Search table */ @@ -356,8 +359,12 @@ char *get_glyph (char *iptr, char *optr, char mchar); char *get_glyph_nc (char *iptr, char *optr, char mchar); t_value get_uint (char *cptr, int radix, t_value max, t_stat *status); t_value strtotv (char *cptr, char **endptr, int radix); +DEVICE *find_dev_from_unit (UNIT *uptr); +REG *find_reg (char *ptr, char **optr, DEVICE *dptr); int32 sim_rtc_init (int32 time); int32 sim_rtc_calb (int32 ticksper); +int32 sim_rtcn_init (int32 time, int32 tmr); +int32 sim_rtcn_calb (int32 time, int32 tmr); t_stat sim_poll_kbd (void); t_stat sim_putchar (int32 out); t_bool sim_brk_test (t_addr bloc, int32 btyp); diff --git a/sim_rev.h b/sim_rev.h index bc327ec8..d801afe5 100644 --- a/sim_rev.h +++ b/sim_rev.h @@ -1,6 +1,6 @@ /* sim_rev.h: simulator revisions and current rev level - Copyright (c) 1993-2001, Robert M Supnik + Copyright (c) 1993-2002, Robert M Supnik Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), @@ -25,13 +25,211 @@ */ #define SIM_MAJOR 2 -#define SIM_MINOR 8 -#define SIM_PATCH 5 +#define SIM_MINOR 9 +#define SIM_PATCH 11 -/* V2.8 revision history +/* V2.9 revision history patch date module(s) and fix(es) + 11 20-Jul-02 i1401_mt.c: on read, end of record stores group mark + without word mark (found by Van Snyder) + + i1401_dp.c: reworked address generation and checking + + vax_cpu.c: added infinite loop detection and halt to + boot ROM option (from Mark Pizzolato) + + vax_fpa.c: changed function names to prevent conflict + with C math library + + pdp11_cpu.c: fixed bug in MMR0 update logic (from + John Dundas) + + pdp18b_stddev.c: added "ASCII mode" for reader and + punch (from Hans Pufal) + + gri_*.c: added GRI-909 simulator + + scp.c: added DO echo, DO exit (from Brian Knittel) + + scp_tty.c: added Windows priority hacking (from + Mark Pizzolato) + + 10 15-Jun-02 scp.c: fixed error checking on calls to fxread/fxwrite + (found by Norm Lastovic) + + scp_tty.c, sim_vt.h, sim_vt.c: added VTxxx emulation + support for Windows (from Fischer Franz) + + sim_sock.c: added OS/2 support (from Holger Veit) + + pdp11_cpu.c: fixed bugs (from John Dundas) + -- added special case for PS<15:12> = 1111 to MFPI + -- removed special case from MTPI + -- added masking of relocation adds + + i1401_cpu.c: + -- added multiply/divide + -- fixed bugs (found by Van Snyder) + o 5 and 7 character H, 7 character doesn't branch + o 8 character NOP + o 1401-like memory dump + + i1401_dp.c: added 1311 disk + + 9 04-May-02 pdp11_rq: fixed bug in polling routine + + 8 03-May-02 scp.c: + -- changed LOG/NOLOG to SET LOG/NOLOG + -- added SHOW LOG + -- added SET VT/NOVT and SHOW VT for VT emulation + + sim_sock.h: changed VMS stropt.h include to ioctl.h + + vax_cpu.c + -- added TODR powerup routine to set date, time on boot + -- fixed exception flows to clear trap request + -- fixed register logging in autoincrement indexed + + vax_stddev.c: added TODR powerup routine + + vax_cpu1.c: fixed exception flows to clear trap request + + 7 30-Apr-02 scp.c: fixed bug in clock calibration when (real) clock + jumps forward due too far (found by Jonathan Engdahl) + + pdp11_cpu.c: fixed bugs, added features (from John Dundas + and Wolfgang Helbig) + -- added HTRAP and BPOK to maintenance register + -- added trap on kernel HALT if MAINT set + -- fixed red zone trap, clear odd address and nxm traps + -- fixed RTS SP, don't increment restored SP + -- fixed TSTSET, write dst | 1 rather than prev R0 | 1 + -- fixed DIV, set N=0,Z=1 on div by zero (J11, 11/70) + -- fixed DIV, set set N=Z=0 on overfow (J11, 11/70) + -- fixed ASH, ASHC, count = -32 used implementation- + dependent 32 bit right shift + -- fixed illegal instruction test to detect 000010 + -- fixed write-only page test + + pdp11_rp.c: fixed SHOW ADDRESS command + + vaxmod_defs.h: fixed DZ vector base and number of lines + + dec_dz.h: + -- fixed interrupt acknowledge routines + -- fixed SHOW ADDRESS command + + all magtape routines: added test for badly formed + record length (suggested by Jonathan Engdahl) + + 6 18-Apr-02 vax_cpu.c: fixed CASEL condition codes + + vax_cpu1.c: fixed vfield pos > 31 test to be unsigned + + vax_fpu.c: fixed EDIV overflow test for 0 quotient + + 5 14-Apr-02 vax_cpu1.c: + -- fixed interrupt, prv_mode set to 0 (found by Tim Stark) + -- fixed PROBEx to mask mode to 2b (found by Kevin Handy) + + 4 1-Apr-02 pdp11_rq.c: fixed bug, reset cleared write protect status + + pdp11_ts.c: fixed bug in residual frame count after space + + 3 15-Mar-02 pdp11_defs.h: changed default model to KDJ11A (11/73) + + pdp11_rq.c: adjusted delays for M+ timing bugs + + hp2100_cpu.c, pdp10_cpu.c, pdp11_cpu.c: tweaked abort + code for ANSI setjmp/longjmp compliance + + hp2100_cpu.c, hp2100_fp.c, hp2100_stddev.c, hp2100_sys.c: + revised to allocate memory dynamically + + 2 01-Mar-02 pdp11_cpu.c: + -- fixed bugs in CPU registers + -- fixed double operand evaluation order for M+ + + pdp11_rq.c: added delays to initialization for + RSX11M+ prior to V4.5 + + 1 20-Feb-02 scp.c: fixed bug in clock calibration when (real) + time runs backwards + + pdp11_rq.c: fixed bug in host timeout logic + + pdp11_ts.c: fixed bug in message header logic + + pdp18b_defs.h, pdp18b_dt.c, pdp18b_sys.c: added + PDP-7 DECtape support + + hp2100_cpu.c: + -- added floating point and DMS + -- fixed bugs in DIV, ASL, ASR, LBT, SBT, CBT, CMW + + hp2100_sys.c: added floating point, DMS + + hp2100_fp.c: added floating point + + ibm1130: added Brian Knittel's IBM 1130 simulator + + 0 30-Jan-02 scp.c: + -- generalized timer package for multiple timers + -- added circular register arrays + -- fixed bugs, line spacing in modifier display + -- added -e switch to attach + -- moved device enable/disable to simulators + + scp_tty.c: VAX specific fix (from Robert Alan Byer) + + sim_tmxr.c, sim_tmxr.h: + -- added tmxr_fstats, tmxr_dscln + -- renamed tmxr_fstatus to tmxr_fconns + + sim_sock.c, sim_sock.h: added VMS support (from + Robert Alan Byer) + + pdp_dz.h, pdp18b_tt1.c, nova_tt1.c: + -- added SET DISCONNECT + -- added SHOW STATISTICS + + pdp8_defs.h: fixed bug in interrupt enable initialization + + pdp8_ttx.c: rewrote as unified multiplexor + + pdp11_cpu.c: fixed calc_MMR1 macro (found by Robert Alan Byer) + + pdp11_stddev.c: fixed bugs in KW11L (found by John Dundas) + + pdp11_rp.c: fixed bug in 18b mode boot + + pdp11 bootable I/O devices: fixed register setup at boot + exit (found by Doug Carman) + + hp2100_cpu.c: + -- fixed DMA register tables (found by Bill McDermith) + -- fixed SZx,SLx,RSS bug (found by Bill McDermith) + -- fixed flop restore logic (found by Bill McDermith) + + hp2100_mt.c: fixed bug on write of last character + + hp2100_dq,dr,ms,mux.c: added new disk, magtape, and terminal + multiplexor controllers + + i1401_cd.c, i1401_mt.c: new zero footprint bootstraps + (from Van Snyder) + + i1401_sys.c: fixed symbolic display of H, NOP with no trailing + word mark (found by Van Snyder) + + most CPUs: + -- replaced OLDPC with PC queue + -- implemented device enable/disable locally + + V2.8 revision history + 5 25-Dec-01 scp.c: fixed bug in DO command (found by John Dundas) pdp10_cpu.c: @@ -162,4 +360,4 @@ patch date module(s) and fix(es) sim_tmxr.c: modified calling sequence for sim_putchar_ln sim_sock.c: added Macintosh sockets support -*/ \ No newline at end of file +*/ diff --git a/sim_sock.c b/sim_sock.c index a515cae9..cb08324a 100644 --- a/sim_sock.c +++ b/sim_sock.c @@ -23,6 +23,8 @@ be used in advertising or otherwise to promote the sale, use or other dealings in this Software without prior written authorization from Robert M Supnik. + 22-May-02 RMS Added OS2 EMX support from Holger Veit + 06-Feb-02 RMS Added VMS support from Robert Alan Byer 16-Sep-01 RMS Added Macintosh support from Peter Schorn 02-Sep-01 RMS Fixed UNIX bugs found by Mirian Lennox and Tom Markson */ @@ -44,7 +46,7 @@ /* First, all the non-implemented versions */ -#if defined (VMS) || defined (__OS2__) +#if defined (__OS2__) && !defined (__EMX__) SOCKET sim_master_sock (int32 port) { @@ -78,7 +80,7 @@ return SOCKET_ERROR; #else /* endif unimpl */ -/* UNIX, Win32, Macintosh (Berkeley socket) routines */ +/* UNIX, Win32, Macintosh, VMS, OS2 (Berkeley socket) routines */ SOCKET sim_master_sock (int32 port) { @@ -129,7 +131,9 @@ SOCKET sim_accept_conn (SOCKET master, UNIT *uptr, uint32 *ipaddr) { int32 sta; #if defined (macintosh) -socklen_t size; +socklen_t size; +#elif defined (__EMX__) +int size; #else size_t size; #endif @@ -190,6 +194,13 @@ unsigned long non_block = 1; return ioctlsocket (sock, FIONBIO, &non_block); /* set nonblocking */ } +#elif defined (VMS) +SOCKET sim_setnonblock (SOCKET sock) +{ +int non_block = 1; + +return ioctl (sock, FIONBIO, &non_block); /* set nonblocking */ +} #else int32 sim_setnonblock (SOCKET sock) { @@ -199,12 +210,12 @@ fl = fcntl (sock, F_GETFL,0); /* get flags */ if (fl == -1) return SOCKET_ERROR; sta = fcntl (sock, F_SETFL, fl | O_NONBLOCK); /* set nonblock */ if (sta == -1) return SOCKET_ERROR; -#if !defined (macintosh) +#if !defined (macintosh) && !defined (__EMX__) sta = fcntl (sock, F_SETOWN, getpid()); /* set ownership */ if (sta == -1) return SOCKET_ERROR; #endif return 0; } -#endif /* endif Win32 */ +#endif /* endif !Win32 */ -#endif /* endif Win32/UNIX/Mac */ +#endif /* endif Win32/UNIX/Mac/VMS */ diff --git a/sim_sock.h b/sim_sock.h index 11e5ad40..94218b74 100644 --- a/sim_sock.h +++ b/sim_sock.h @@ -23,15 +23,16 @@ be used in advertising or otherwise to promote the sale, use or other dealings in this Software without prior written authorization from Robert M Supnik. + 30-Apr-02 RMS Changed VMS stropts include to ioctl + 06-Feb-02 RMS Added VMS support from Robert Alan Byer 16-Sep-01 RMS Added Macintosh support from Peter Schorn */ -#if defined (WIN32) +#if defined (WIN32) /* Windows */ #undef INT_PTR /* hack, hack */ #include -#else +#elif !defined (__OS2__) /* other supported */ #define WSAGetLastError() errno -#if !defined (VMS) && !defined (__OS2__) #include /* for fcntl, getpid */ #include /* for sockets */ #include @@ -39,6 +40,8 @@ #include /* for sockaddr_in */ #include #endif +#if defined (VMS) /* VMS unique */ +#include /* for ioctl */ #endif /* Code uses Windows-specific defs that are undefined for most systems */ diff --git a/sim_tmxr.c b/sim_tmxr.c index 74b963ff..771a67c9 100644 --- a/sim_tmxr.c +++ b/sim_tmxr.c @@ -26,7 +26,8 @@ Based on the original DZ11 simulator by Thord Nilson, as updated by Arthur Krewat. - 03-Dec-01 RMS Changed tmxr_status for extended SET/SHOW + 30-Dec-01 RMS Added tmxr_fstats, tmxr_dscln, renamed tmxr_fstatus + 03-Dec-01 RMS Changed tmxr_fconns for extended SET/SHOW 20-Oct-01 RMS Fixed bugs in read logic (found by Thord Nilson). added tmxr_rqln, tmxr_tqln */ @@ -349,7 +350,7 @@ for (i = 0; i < mp -> lines; i++) { /* loop thru conn */ if (lp -> conn) { tmxr_msg (lp -> conn, "\r\n"); tmxr_msg (lp -> conn, sim_name); - tmxr_msg (lp -> conn, " simulator shutting down... please come back later\r\n\n"); + tmxr_msg (lp -> conn, " simulator shutting down\r\n\n"); tmxr_reset_ln (lp); } /* end if conn */ } /* end for */ sim_close_sock (mp -> master, 1); /* close master socket */ @@ -380,12 +381,11 @@ if (sock) sim_write_sock (sock, msg, strlen (msg)); return; } -/* Print line status */ +/* Print connections - used only in named SHOW command */ -void tmxr_fstatus (FILE *st, TMLN *lp, int32 ln) +void tmxr_fconns (FILE *st, TMLN *lp, int32 ln) { -if (ln >= 0) fprintf (st, "\n line %d: ", ln); -else fprintf (st, "line status: "); +if (ln >= 0) fprintf (st, "line %d: ", ln); if (lp -> conn) { int32 o1, o2, o3, o4, hr, mn, sc; uint32 ctime; @@ -399,7 +399,47 @@ if (lp -> conn) { mn = (ctime / 60) % 60; sc = ctime % 3600; fprintf (st, "IP address %d.%d.%d.%d", o1, o2, o3, o4); - if (ctime) fprintf (st, ", connected %02d:%02d:%02d", hr, mn, sc); } -else fprintf (st, "disconnected"); + if (ctime) fprintf (st, ", connected %02d:%02d:%02d\n", hr, mn, sc); } +else fprintf (st, "line disconnected\n"); return; } + +/* Print statistics - used only in named SHOW command */ + +void tmxr_fstats (FILE *st, TMLN *lp, int32 ln) +{ +static const char *enab = "on"; +static const char *dsab = "off"; + +if (ln >= 0) fprintf (st, "line %d: ", ln); +if (lp -> conn) { + fprintf (st, "input (%s) queued/total = %d/%d, ", + (lp -> rcve? enab: dsab), + lp -> rxbpi - lp -> rxbpr, lp -> rxcnt); + fprintf (st, "output (%s) queued/total = %d/%d\n", + (lp -> xmte? enab: dsab), + lp -> txbpi - lp -> txbpr, lp -> txcnt); } +else fprintf (st, "line disconnected\n"); +return; +} + +/* Disconnect line */ + +t_stat tmxr_dscln (UNIT *uptr, int32 val, char *cptr, void *desc) +{ +TMXR *mp = (TMXR *) desc; +TMLN *lp; +int32 ln; +t_stat r; + +if ((mp == NULL) || (val && (cptr == NULL))) return SCPE_ARG; +if (cptr) { + ln = (int32) get_uint (cptr, 10, mp -> lines - 1, &r); + if (r != SCPE_OK) return SCPE_ARG; } +else ln = 0; +lp = mp -> ldsc[ln]; +if (lp -> conn) { + tmxr_msg (lp -> conn, "\r\nOperator disconnected line\r\n\n"); + tmxr_reset_ln (lp); } +return SCPE_OK; +} diff --git a/sim_tmxr.h b/sim_tmxr.h index 7501b663..20bd6185 100644 --- a/sim_tmxr.h +++ b/sim_tmxr.h @@ -26,6 +26,7 @@ Based on the original DZ11 simulator by Thord Nilson, as updated by Arthur Krewat. + 30-Dec-01 RMS Renamed tmxr_fstatus, added tmxr_fstats 20-Oct-01 RMS Removed tmxr_getchar, formalized buffer guard, added tmxr_rqln, tmxr_tqln */ @@ -75,7 +76,9 @@ t_stat tmxr_detach (TMXR *mp, UNIT *uptr); t_stat tmxr_ex (t_value *vptr, t_addr addr, UNIT *uptr, int32 sw); t_stat tmxr_dep (t_value val, t_addr addr, UNIT *uptr, int32 sw); void tmxr_msg (SOCKET sock, char *msg); -void tmxr_fstatus (FILE *st, TMLN *lp, int32 ln); +void tmxr_fconns (FILE *st, TMLN *lp, int32 ln); +void tmxr_fstats (FILE *st, TMLN *lp, int32 ln); +t_stat tmxr_dscln (UNIT *uptr, int32 val, char *cptr, void *desc); int32 tmxr_rqln (TMLN *lp); int32 tmxr_tqln (TMLN *lp); diff --git a/sim_vt.c b/sim_vt.c new file mode 100644 index 00000000..4534e995 --- /dev/null +++ b/sim_vt.c @@ -0,0 +1,508 @@ +/* sim_vt.c: VT2xx compatible terminal emulator + + Copyright (c) 2002, Robert M Supnik + Written by Fischer Franz and used with his gracious permission + + Permission is hereby granted, free of charge, to any person obtaining a + copy of this software and associated documentation files (the "Software"), + to deal in the Software without restriction, including without limitation + the rights to use, copy, modify, merge, publish, distribute, sublicense, + and/or sell copies of the Software, and to permit persons to whom the + Software is furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + ROBERT M SUPNIK BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + Except as contained in this notice, the name of Robert M Supnik shall not + be used in advertising or otherwise to promote the sale, use or other dealings + in this Software without prior written authorization from Robert M Supnik. + + 13-Apr-02 FF Added Hold-Screen on Pause-Key + Corrected scrolling + Added additional Esc-sequences Erase-Insert-Delete-Char + Corrected decoding + (ESC [ H, ESC [ x H, ESC [ ; y H , ESC [ x ; y H + are all valid sequences) + 15-Mar-02 FF Original version Fischer Franz +*/ + +#include +#include "sim_defs.h" + +#define HOLD 0x1 +#define INSERT 0x2 +#define SCRMAX 64 + +static HANDLE kbdHdl; +static HANDLE scrHdl; +static INPUT_RECORD inBuf; +static DWORD act, mode; +static CONSOLE_SCREEN_BUFFER_INFO screen; +static COORD margin; +static WORD attrib; + +static char *kbd_ptr; +static char *scr_ptr; +static char scr_buf[SCRMAX]; +static uint8 scr_mode; + +struct keyEntry { + uint8 asciiCode; + uint8 scanCode; + char *escSeq; +}; +typedef struct keyEntry KEY; + +typedef void (*scr_func) (); +struct scrEntry { + char last; + scr_func interpret; +}; +typedef struct scrEntry SCR; + +static KEY keyTab[] = { + {0 ,0x3B,"[31~"}, /* F1, mapped to F17 on VT320 */ + {0 ,0x3C,"[32~"}, /* F2, mapped to F18 on VT320 */ + {0 ,0x3D,"[33~"}, /* F3, mapped to F19 on VT320 */ + {0 ,0x3E,"[34~"}, /* F4, mapped to F20 on VT320 */ + {0 ,0x3F,"[17~"}, /* F5, mapped to F6 on VT320 */ + {0 ,0x40,"[18~"}, /* F6, mapped to F7 on VT320 */ + {0 ,0x41,"[19~"}, /* F7, mapped to F8 on VT320 */ + {0 ,0x42,"[20~"}, /* F8, mapped to F9 on VT320 */ + {0 ,0x43,"[23~"}, /* F9, mapped to F11 on VT320 */ + {0 ,0x44,"[24~"}, /* F10,mapped to F12 on VT320 */ + {0 ,0x57,"[25~"}, /* F11,mapped to F13 on VT320 */ + {0 ,0x58,"[26~"}, /* F12,mapped to F14 on VT320 */ + + {0xE0,0x52,"[2~"}, /* INS,mapped to INSERT on VT320 */ + {0xE0,0x53,"[3~"}, /* DEL,mapped to REMOVE in VT320 */ + {0xE0,0x47,"[1~"}, /* HOME, mapped to FIND on VT320 */ + {0xE0,0x4F,"[4~"}, /* END,mapped to SELECT on VT320 */ + {0xE0,0x49,"[5~"}, /* PAGE UP, mapped to PREV on VT320 */ + {0xE0,0x51,"[6~"}, /* PAGE DOWN, mapped to NEXT on VT320 */ + + {0xE0,0x48,"[A"},/* UP */ + {0xE0,0x50,"[B"},/* DOWN */ + {0xE0,0x4D,"[C"},/* RIGHT */ + {0xE0,0x4B,"[D"},/* LEFT */ + + {0xE0,0x45,"OP"},/* NUM, mapped to PF1 on VT320 */ + {0xE0,0x35,"OQ"},/* / , mapped to PF2 on VT320 */ + {'*' ,0x37,"OR"},/* * , mapped to PF3 on VT320 */ + {'-', 0x4A,"OS"},/* / , mapped to PF4 on VT320 */ + + /* The following Keys send Application Keypad-Mode sequences */ + {0 ,0x52,"Op"}, /* KP0 */ + {'0',0x52,"Op"}, /* KP0 */ + {0 ,0x4F,"Oq"}, /* KP1 */ + {'1',0x4F,"Oq"}, /* KP1 */ + {0 ,0x50,"Or"}, /* KP2 */ + {'2',0x50,"Or"}, /* KP2 */ + {0 ,0x51,"Os"}, /* KP3 */ + {'3',0x51,"Os"}, /* KP3 */ + {0 ,0x4B,"Ot"}, /* KP4 */ + {'4',0x4B,"Ot"}, /* KP4 */ + {0 ,0x4C,"Ou"}, /* KP5 */ + {'5',0x4C,"Ou"}, /* KP5 */ + {0 ,0x4D,"Ov"}, /* KP6 */ + {'6',0x4D,"Ov"}, /* KP6 */ + {0 ,0x47,"Ow"}, /* KP7 */ + {'7',0x47,"Ow"}, /* KP7 */ + {0 ,0x48,"Ox"}, /* KP8 */ + {'8',0x48,"Ox"}, /* KP8 */ + {0 ,0x49,"Oy"}, /* KP9 */ + {'9',0x49,"Oy"}, /* KP9 */ + {0 ,0x53,"On"}, /* PERIOD */ + {'.',0x53,"On"}, /* PERIOD */ + {0xE0,0x1C,"OM"}, /* ENTER */ + {'+',0x4E,"Ol"}, /* COMMA */ + {0} /* End of List */ +}; + +int vt_read() { + DWORD cnt = 0; + uint8 sCode, aCode; + KEY *key; + + if (kbd_ptr && *kbd_ptr) { + return (*kbd_ptr++ & 0177); + } + + GetNumberOfConsoleInputEvents(kbdHdl, &cnt); + if (!cnt) return -1; + + ReadConsoleInput(kbdHdl, &inBuf, 1, &act); + + if (inBuf.EventType != KEY_EVENT) return -1; + if (!inBuf.Event.KeyEvent.bKeyDown) return -1; + if (inBuf.Event.KeyEvent.dwControlKeyState & ENHANCED_KEY) inBuf.Event.KeyEvent.uChar.AsciiChar = (uint8)0xE0; + + sCode = (uint8)inBuf.Event.KeyEvent.wVirtualScanCode; + aCode = inBuf.Event.KeyEvent.uChar.AsciiChar; + + if (scr_mode & HOLD) { + scr_mode &= ~HOLD; + return 0x11; + } + if (sCode < 0x37 && aCode != 0 && aCode != 0xE0) return aCode; + if (sCode == 0x45 && aCode == 0) { + scr_mode |= HOLD; + return 0x13; + } + + for (key = keyTab; key->scanCode; key++) { + if (key->asciiCode != aCode || key->scanCode != sCode) continue; + kbd_ptr = key->escSeq; + return 0x1b; + } + + if (aCode != 0 && aCode != 0xE0) return aCode; + return -1; +} + +static void scr_nop () {}; + +static void scr_scroll_up(int from, int to, int lines) { + SMALL_RECT src; + COORD dst; + CHAR_INFO fill; + + dst.X=0; dst.Y=from; + src.Top=from+lines; src.Left=0; src.Bottom=to; src.Right=screen.dwSize.X; + fill.Char.AsciiChar = ' '; + fill.Attributes = attrib; + ScrollConsoleScreenBuffer(scrHdl,&src,0,dst,&fill); +}; +static void scr_scroll_down(int from, int to, int lines) { + SMALL_RECT src; + COORD dst; + CHAR_INFO fill; + + dst.X=0; dst.Y=from+lines; + src.Top=from; src.Left=0; src.Bottom=to-lines; src.Right=screen.dwSize.X; + fill.Char.AsciiChar = ' '; + fill.Attributes = attrib; + ScrollConsoleScreenBuffer(scrHdl,&src,0,dst,&fill); +}; +static void scr_insert_char() { + int nr = atoi(&scr_buf[1]); + SMALL_RECT src; + COORD dst; + CHAR_INFO fill; + + if (!nr) nr = 1; + src.Top=screen.dwCursorPosition.Y; src.Left=screen.dwCursorPosition.X-nr; + src.Bottom=src.Top; src.Right=screen.dwSize.X; + dst.X=src.Left+nr; dst.Y=src.Top; + fill.Char.AsciiChar = ' '; + fill.Attributes = attrib; + ScrollConsoleScreenBuffer(scrHdl,&src,0,dst,&fill); +}; +static void scr_pos_up() { + int nr = atoi(&scr_buf[1]); + if (!nr) nr = 1; + if (screen.dwCursorPosition.Y > nr) screen.dwCursorPosition.Y -= nr; + else screen.dwCursorPosition.Y = 0; + SetConsoleCursorPosition(scrHdl,screen.dwCursorPosition); +}; +static void scr_pos_down() { + int nr = atoi(&scr_buf[1]); + if (!nr) nr = 1; + screen.dwCursorPosition.Y += nr; + if (screen.dwCursorPosition.Y >= margin.Y) screen.dwCursorPosition.Y = margin.Y-1; + SetConsoleCursorPosition(scrHdl,screen.dwCursorPosition); +}; +static void scr_pos_right() { + int nr = atoi(&scr_buf[1]); + if (!nr) nr = 1; + screen.dwCursorPosition.X += nr; + if (screen.dwCursorPosition.X >= screen.dwSize.X) screen.dwCursorPosition.X = screen.dwSize.X-1; + SetConsoleCursorPosition(scrHdl,screen.dwCursorPosition); +}; +static void scr_pos_left() { + int nr = atoi(&scr_buf[1]); + if (!nr) nr = 1; + if (screen.dwCursorPosition.X > nr) screen.dwCursorPosition.X -= nr; + else screen.dwCursorPosition.X = 0; + SetConsoleCursorPosition(scrHdl,screen.dwCursorPosition); +}; +static void scr_pos_cursor() { + int x, y; + if (scr_buf[0] == 'H') return; + x = 1; y = 1; + if (!sscanf(scr_buf,"[%d;%d",&y,&x)) sscanf(scr_buf,"[;%d",&x); + screen.dwCursorPosition.X = x-1; + screen.dwCursorPosition.Y = y-1; + SetConsoleCursorPosition(scrHdl,screen.dwCursorPosition); +}; +static void scr_prev_line() { + scr_scroll_down(margin.X,margin.Y,1); +}; +static void scr_next_line() { + scr_scroll_up(margin.X,margin.Y,1); +}; +static void scr_erase_display() { + int nr = atoi(&scr_buf[1]); + COORD pos; + int len; + + if (nr == 0) { + pos = screen.dwCursorPosition; + len = (screen.dwSize.Y-screen.dwCursorPosition.Y-1)*screen.dwSize.X + + (screen.dwSize.X-screen.dwCursorPosition.X); + } else if (nr == 1) { + pos.X = 0; pos.Y = 0; + len = (screen.dwCursorPosition.Y-1)*screen.dwSize.X + screen.dwCursorPosition.X; + } else if (nr == 2) { + pos.X = 0; pos.Y = 0; + len = screen.dwSize.X*screen.dwSize.Y; + } else { + return; + } + + FillConsoleOutputAttribute(scrHdl,screen.wAttributes,len,pos,&act); + FillConsoleOutputCharacter(scrHdl,' ',len,pos,&act); +}; +static void scr_erase_line() { + int nr = atoi(&scr_buf[1]); + COORD pos; + int len; + + if (nr == 0) { + pos = screen.dwCursorPosition; + len = screen.dwSize.X-screen.dwCursorPosition.X; + } else if (nr == 1) { + pos.X = 0; pos.Y = screen.dwCursorPosition.Y; + len = screen.dwCursorPosition.X; + } else if (nr == 2) { + pos.X = 0; pos.Y = screen.dwCursorPosition.Y; + len = screen.dwSize.X; + } else { + return; + } + + FillConsoleOutputAttribute(scrHdl,screen.wAttributes,len,pos,&act); + FillConsoleOutputCharacter(scrHdl,' ',len,pos,&act); +}; +static void scr_delete_line() { + if (scr_buf[0] == 'M') { + scr_prev_line(); + } else { + int nr = atoi(&scr_buf[1]); + if (!nr) nr = 1; + scr_scroll_up(screen.dwCursorPosition.Y,margin.Y,nr); + } +}; +static void scr_insert_line() { + int nr = atoi(&scr_buf[1]); + if (!nr) nr = 1; + scr_scroll_down(screen.dwCursorPosition.Y,margin.Y,nr); +}; +static void scr_delete_char() { + int nr = atoi(&scr_buf[1]); + SMALL_RECT src; + COORD dst; + CHAR_INFO fill; + + if (!nr) nr = 1; + dst = screen.dwCursorPosition; + src.Top=dst.Y; src.Left=dst.X+nr; src.Bottom=dst.Y; src.Right=screen.dwSize.X; + fill.Char.AsciiChar = ' '; + fill.Attributes = attrib; + ScrollConsoleScreenBuffer(scrHdl,&src,0,dst,&fill); +}; +static void scr_erase_char() { + int nr = atoi(&scr_buf[1]); + COORD pos; + + if (!nr) nr = 1; + pos = screen.dwCursorPosition; + + FillConsoleOutputAttribute(scrHdl,screen.wAttributes,nr,pos,&act); + FillConsoleOutputCharacter(scrHdl,' ',nr,pos,&act); +}; +static void scr_request() { + kbd_ptr = "\033[?6c"; +}; +static void scr_set() { + int nr = atoi(&scr_buf[1]); + if (nr == 4) scr_mode |= INSERT; +}; +static void scr_reset() { + int nr = atoi(&scr_buf[1]); + if (nr == 4) scr_mode &= ~INSERT; +}; +static void scr_attrib() { + int nr = atoi(&scr_buf[1]); + switch (nr) { + case 0: + attrib = screen.wAttributes; + break; + case 1: + attrib = screen.wAttributes | 0x80; + break; + case 7: + attrib = ((screen.wAttributes & 0xf) << 4) | ((screen.wAttributes & 0x7) >> 4); + break; + } +}; +static void scr_report() {}; +static void scr_margin() { + int top, bot; + top = 1; bot = screen.dwSize.Y+1; + if (!sscanf(scr_buf,"[%d;%d",&top,&bot)) sscanf(scr_buf,"[;%d",&bot); + margin.X = top-1; + if (bot != 24) margin.Y = bot-1; + else margin.Y = screen.dwSize.Y; + + screen.dwCursorPosition.X = 0; + screen.dwCursorPosition.Y = 0; + SetConsoleCursorPosition(scrHdl,screen.dwCursorPosition); +}; + +static SCR scrTab[] = { + {'@', scr_insert_char}, + {'A', scr_pos_up}, + {'B', scr_pos_down}, + {'C', scr_pos_right}, + {'D', scr_pos_left}, + {'E', scr_next_line}, + {'H', scr_pos_cursor}, + {'I', scr_prev_line}, + {'J', scr_erase_display}, + {'K', scr_erase_line}, + {'L', scr_insert_line}, + {'M', scr_delete_line}, + {'P', scr_delete_char}, + {'X', scr_erase_char}, + {'Z', scr_request}, + + {'c', scr_request},/* Device attribute request */ + {'f', scr_pos_cursor}, + {'h', scr_set}, /* Set mode */ + {'l', scr_reset}, /* Reset mode */ + {'m', scr_attrib}, /* Display attributes */ + {'n', scr_report}, /* Device report */ + {'r', scr_margin}, + {'=', scr_nop}, /* Set applikation keypad mode */ + {'>', scr_nop}, /* Set numeric keypad mode */ + {0} +}; + +static void scr_char(char c) { + + if (c == 0x8) { /* BS */ + if (screen.dwCursorPosition.X > 0) screen.dwCursorPosition.X--; + } else if (c == 0xa) { /* LF */ + if (screen.dwCursorPosition.Y < margin.Y-1) screen.dwCursorPosition.Y++; + else scr_scroll_up(margin.X,margin.Y,1); + } else if (c == 0xd) { /* CR */ + screen.dwCursorPosition.X = 0; + } else if (c == 0x9) { /* Tab */ + screen.dwCursorPosition.X = (screen.dwCursorPosition.X + 8) & ~7; + if (screen.dwCursorPosition.X >= screen.dwSize.X) screen.dwCursorPosition.X = screen.dwSize.X-1; + } else if (c < ' ') { + return; + } else if (!(scr_mode & INSERT)) { + WriteConsoleOutputCharacter(scrHdl,&c,1,screen.dwCursorPosition,&act); + WriteConsoleOutputAttribute(scrHdl,&attrib,1,screen.dwCursorPosition,&act); + + if (screen.dwCursorPosition.X < screen.dwSize.X) screen.dwCursorPosition.X++; + else if (screen.dwCursorPosition.Y < margin.Y-1) { + screen.dwCursorPosition.X = 0; + screen.dwCursorPosition.Y++; + } else { + scr_scroll_up(margin.X,margin.Y,1); + screen.dwCursorPosition.X = 0; + } + } else { + SMALL_RECT src; + COORD dst; + CHAR_INFO fill; + + src.Top=screen.dwCursorPosition.Y; src.Left=screen.dwCursorPosition.X; + src.Bottom=src.Top; src.Right=screen.dwSize.X; + dst.X=src.Left+1; dst.Y=src.Top; + fill.Char.AsciiChar = ' '; + fill.Attributes = attrib; + ScrollConsoleScreenBuffer(scrHdl,&src,0,dst,&fill); + WriteConsoleOutputCharacter(scrHdl,&c,1,screen.dwCursorPosition,&act); + + if (screen.dwCursorPosition.X < screen.dwSize.X) screen.dwCursorPosition.X++; + else if (screen.dwCursorPosition.Y < margin.Y-1) { + screen.dwCursorPosition.X = 0; + screen.dwCursorPosition.Y++; + } else { + scr_scroll_up(margin.X,margin.Y,1); + screen.dwCursorPosition.X = 0; + } + } + + SetConsoleCursorPosition(scrHdl,screen.dwCursorPosition); +} + +static void check_esc (char c) { + SCR *scr; + + *scr_ptr = c; + if ((scr_ptr - scr_buf) < SCRMAX) scr_ptr++; + for (scr = scrTab; scr->last; scr++) { + if (scr->last != c) continue; + + *scr_ptr = 0; + scr->interpret(); + scr_ptr = 0; + return; + } +} + +void vt_write(char c) { + + if (c != 0x1b && !scr_ptr) { + scr_char(c); + } else if (c == 0x1b) { + scr_ptr = scr_buf; + } else if (c < ' ') { + scr_ptr = 0; + scr_char(c); + } else if (scr_ptr == scr_buf) { + check_esc(c); + } else if (c >= '@') { + check_esc(c); + scr_ptr = 0; + } else { + *scr_ptr = c; + if ((scr_ptr - scr_buf) < SCRMAX) scr_ptr++; + } +} + +void vt_init() { + kbdHdl = GetStdHandle(STD_INPUT_HANDLE); + scrHdl = GetStdHandle(STD_OUTPUT_HANDLE); + + GetConsoleMode(kbdHdl, &mode); + GetConsoleScreenBufferInfo(scrHdl, &screen); + margin.X = 0; margin.Y = screen.dwSize.Y; + attrib = screen.wAttributes; + scr_mode = 0; +} + +void vt_cmd() { + SetConsoleMode(kbdHdl, mode); +} + +void vt_run() { + kbd_ptr = 0; + SetConsoleMode(kbdHdl, 0); + GetConsoleScreenBufferInfo(scrHdl, &screen); + margin.X = 0; margin.Y = screen.dwSize.Y; + attrib = screen.wAttributes; + scr_mode = 0; +} \ No newline at end of file diff --git a/sim_vt.h b/sim_vt.h new file mode 100644 index 00000000..ebe23a75 --- /dev/null +++ b/sim_vt.h @@ -0,0 +1,34 @@ +/* sim_vt.h: VT2xx compatible Terminalemulator + + Copyright (c) 2002, Robert M Supnik + Written by Fischer Franz and used with his gracious permission + + Permission is hereby granted, free of charge, to any person obtaining a + copy of this software and associated documentation files (the "Software"), + to deal in the Software without restriction, including without limitation + the rights to use, copy, modify, merge, publish, distribute, sublicense, + and/or sell copies of the Software, and to permit persons to whom the + Software is furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + ROBERT M SUPNIK BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + Except as contained in this notice, the name of Robert M Supnik shall not + be used in advertising or otherwise to promote the sale, use or other dealings + in this Software without prior written authorization from Robert M Supnik. + + 15-Mar-02 FF Original version Fischer Franz +*/ + +int vt_read (void); +void vt_write (char c); +void vt_init (void); +void vt_cmd (void); +void vt_run (void); diff --git a/simh_doc.txt b/simh_doc.txt index 38e2197c..18c4aa55 100644 --- a/simh_doc.txt +++ b/simh_doc.txt @@ -1,14 +1,14 @@ To: Users From: Bob Supnik -Subj: Simulator Usage, V2.8 -Date: 10-Dec-01 +Subj: Simulator Usage, V2.11 +Date: 15-Jul-2002 COPYRIGHT NOTICE The following copyright notice applies to both the SIMH source and binary: - Original code published in 1993-2001, written by Robert M Supnik - Copyright (c) 1993-2001, Robert M Supnik + Original code published in 1993-2002, written by Robert M Supnik + Copyright (c) 1993-2002, Robert M Supnik Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), @@ -44,11 +44,17 @@ documented in separate, machine-specific memoranda. 1. Compiling And Running A Simulator -The simulators have been tested on VAX VMS, Alpha VMS, Alpha UNIX, Intel -FreeBSD, Intel LINUX, Windows 9x/Me/NT/2000 (Visual C++ and MINGW gcc), -Macintosh 9 and X (CodeWarrior), and OS/2. Porting to other environments -will require changes to the operating system dependent code in scp_tty.c -and scp_sock.c. +The simulators have been tested on VAX VMS, Alpha VMS, Alpha UNIX, +Intel FreeBSD, Intel LINUX, Windows 9x/Me/NT/2000 (Visual C++ and +MINGW gcc), Macintosh 9 and X (CodeWarrior), and OS/2. Porting to +other environments will require changes to the operating system +dependent code in scp_tty.c and scp_sock.c. + +The simulator sources are provided in a zip archive. The sources +originate on a Windows system and have cr-lf at the end of every line. +For use on UNIX or Mac, the sources must be converted to UNIX and MAC +text conventions. This can usually be done with the UNZIP utility +(e.g., unzip -a on UNIX). The simulator sources are organized hierarchically. Source files for the simulator libraries are in the top level directory; source files @@ -84,7 +90,8 @@ Compilation notes: - Simulators supporting multiple terminals require a sockets library. Under UNIX, this library is linked in automatically. Under Visual - C++, wsock32.lib must be added to the library search list. + C++, wsock32.lib must be added to the library search list. Under + OS/2, socket support requires the EMX compiler. Examples: @@ -209,12 +216,13 @@ unstructured binary disk files in the host file system. Before using a simulated unit the user must specify the file to be accessed by that unit. The ATTACH (abbreviation AT) command associates a unit and a file: - sim> ATTACH (cr) + sim> ATTACH (cr) -If the file does not exist, it is created, and an appropriate message -is printed. +If the file does not exist, and the -e switch was not specified, a new +file is created, and an appropriate message is printed. If the -e switch +was specified, a new file is not created, and an error message is printed. -If the -r switch is given, or the file is write protected, ATTACH tries +If the -r switch is specified, or the file is write protected, ATTACH tries to open the file read only. If the file does not exist, or the unit does not support read only operation, an error occurs. Input-only devices, such as paper-tape readers, and devices with write lock switches, @@ -225,7 +233,7 @@ not modified. For Telnet-based terminal emulators, the ATTACH command associates the master unit with a TCP/IP port: - sim> ATTACH (cr) + sim> ATTACH (cr) The port is a decimal number between 1 and 65535 and should not used by standard TCP/IP protocols. @@ -234,7 +242,7 @@ The DETACH (abbreviation DET) command breaks the association between a unit and a file, or between a unit and a port: sim> DETACH ALL(cr) -- detach all units - sim> DETACH (cr) -- detach specified unit + sim> DETACH (cr) -- detach specified unit The EXIT command performs an automatic DETACH ALL. @@ -300,6 +308,8 @@ by commas: address the specified location address1-address2 all locations starting at address1 up to and including address2 + address/length all location starting at address up to + but not including address+length STATE all registers in the device ALL all locations in the unit @@ -398,7 +408,7 @@ A breakpoint is set by the BREAK command: If no type is specified, the simulator-specific default breakpoint type (usually E for execution) is used. As with EXAMINE and DEPOSIT, an address range may be a single address, a range of addresses low-high, or a relative -range of address low/length. Examples of SET BREAK +range of address/length. Examples of BREAK: sim> break -e 200 -- set E break at 200 sim> break 2000/2[2] -- set E breaks at 2000,2001 @@ -423,7 +433,7 @@ or a unit parameter: sim> SET {=} Most parameters are simulator and device specific. Disk drives, for -example, can usually be set write ENABLED or write LOCKED; if a device +example, can usually be set WRITEENABLED or write LOCKED; if a device supports multiple drive types, the SET command can be used to specify the drive type. @@ -433,13 +443,6 @@ All devices recognize the following parameters: DEC sets the data radix = 10 HEX sets the data radix = 16 -Most multi-unit devices allow units to be placed online or offline: - - sim> SET ONLINE - sim> SET OFFLINE - -When a unit is offline, it will not be displayed by SHOW DEVICE. - 3.9 Displaying Parameters and Status The SHOW CONFIGURATION command shows the simulator configuration and the @@ -467,23 +470,39 @@ display a result. 3.10 Altering the Simulated Configuration -For most mass storage, the DISABLE command removes the specified -device from the configuration. A DISABLEd device is invisible to running +In most simulators, the SET DISABLED command removes the specified +device from the configuration. A DISABLED device is invisible to running programs. The device can still be RESET but it cannot be ATTAChed, DETACHed, -or BOOTed. ENABLE restores a disabled device to a configuration. +or BOOTed. SET ENABLED restores a disabled device to a configuration. + +Most multi-unit devices allow units to be placed online or offline: + + sim> SET ONLINE + sim> SET OFFLINE + +When a unit is offline, it will not be displayed by SHOW DEVICE. + +If the host is VMS or UNIX, VT100 terminal emulation for the console window +is built in to the Xterm program. For Windows, VT100 emulation foir the +console window can be enabled or disabled explicitly: + + sim> SET VT -- enable VT emulation + sim> SET NOVT -- disable VT emulation + +VT100 emulation is not presently available on Mac or OS/2 hosts. 3.11 Logging Console Output Output to the console can be logged simultaneously to a file. Logging is enabled by the LOG command: - sim> LOG -- log console output to file + sim> SET LOG -- log console output to file Logging is disabled by the NOLOG command: - sim> NOLOG -- disable logging + sim> SET NOLOG -- disable logging -LOG with no argument displays whether logging is enabled or disabled. +SHOW LOG displays whether logging is enabled or disabled. 3.12 Executing Command Files @@ -491,6 +510,9 @@ The simulator can execute command files with the DO command: sim> DO -- execute commands in file +If the switch -V is specified, the commands in the file are echoed before +they are executed. + 3.13 Exiting The Simulator EXIT (synonyms QUIT and BYE) returns control to the operating system. @@ -576,28 +598,47 @@ console y y y y y paper tape y y y h y card reader - - - - - line printer y y y h y -clock y y y - h +clock y y y - y +extra terminal y y y - y hard disk y y y - h -fixed disk y/both - h - h +fixed disk y - h - h floppy disk y y y - - -DECtape y y - - d -mag tape h y/both y - h +DECtape y y - - y +mag tape h y y - h - system 1401 2100 Id4 PDP-10 H316 + system 1401 2100 PDP-10 H316 VAX device -CPU d y h y h -FPU - - h y - -CIS - - - y - -console h y h y h -paper tape - h h h h -card reader h h - - - -line printer h - - y h -clock - h - y h -hard disk - h - y - +CPU y y y h y +FPU - - y - y +CIS - - y - - +console h y y h y +paper tape - h h h y +card reader y - - - - +line printer y h y h y +clock - h y h y +extra terminal - h y - y +hard disk - h y - y fixed disk - h - - - floppy disk - - - - - DECtape - - - - - -mag tape h h - y - +mag tape y h y - y + + system GRI-909 +device +CPU h +FPU - +CIS - +console h +paper tape h +card reader - +line printer - +clock h +extra terminal - +hard disk - +fixed disk - +floppy disk - +DECtape - +mag tape - legend: y = runs operating system or sample program d = runs diagnostics @@ -605,11 +646,27 @@ legend: y = runs operating system or sample program n = untested - = not applicable -Revision History (covering Rev 1.1 to 2.7) +Revision History (covering Rev 1.1 to 2.9) Starting with Rev 2.7, detailed revision histories can be found in file sim_rev.c. +Rev 2.9, Jan, 02 + Added circular register arrays + Replaced ENABLE/DISABLE with SET ENABLED/DISABLED + Replaced LOG/NOLOG with SET LOG/NOLOG + Generalized the timer calibration package + Added additional routines to the multiplexor library + Added SET DISCONNECT, SHOW STATISTICS commands to multiplexors + Reimplemented PDP-8 TTX as a unified multiplexor + Implemented a PC queue in most simulators + Added VAX simulator + Added GRI-909 simulator + Added Peter Schorn's MITS 8080/Z80 simulator + Added Brian Knittel's IBM 1130 simulator + Added HP2100 DQ, DR, MS, MUX devices + Added SET VT/NOVT commands + Rev 2.8, Dec, 01 Added DO command Added general breakpoint facility @@ -617,8 +674,6 @@ Rev 2.8, Dec, 01 Replaced ADD/REMOVE with SET ONLINE/OFFLINE Added global register name recognition Added unit-based register arrays - Added VAX simulator - Added SDS940 simulator Added Charles Owen's System 3 simulator Added PDP-11 I/O bus map Added PDP-11/VAX RQDX3 @@ -870,12 +925,15 @@ Alan Bawden ITS consulting Winfried Bergmann Linux port testing Phil Budne Solaris port testing Max Burnet PDP information, documentation, and software +Robert Alan Byer VMS socket support and testing James Carpenter LINUX port testing Chip Charlot PDP-11 RT-11, RSTS/E, RSX-11M legal permissions Louis Chrétien Macintosh porting Dave Conroy HP 21xx documentation, PDP-10, PDP-18b debugging L Peter Deutsch PDP-1 LISP software Ethan Dicks PDP-11 2.9 BSD debugging +John Dundas PDP-11 CPU and clock debugging +Jonathan Engdahl PDP-11 device debugging Carl Friend Nova and Interdata documentation, and RDOS software Megan Gentry PDP-11 integer debugging, make file Dave Gesswein PDP-8 and PDP-9.15 documentation, PDP-8 DECtape and @@ -890,8 +948,10 @@ Ken Harrenstein KLH PDP-10 simulator Bill Haygood PDP-8 information, simulator, and software Wolfgang Helbig DZ11 implementation Mark Hittinger PDP-10 debugging +Sellam Ismail GRI-909 documentation Jay Jaeger IBM 1401 information Doug Jones PDP-8 information, simulator, and software +Brian Knittel IBM 1130 simulator Al Kossow HP 21xx, Varian 620, TI 990, Interdata, DEC documentation and software Arthur Krewat DZ11 update for the PDP-10 @@ -900,6 +960,7 @@ Don Lewine Nova documentation and legal permissions Tim Litt PDP-10 hardware documentation and schematics, tape images, and software sources Tim Markson DZ11 debugging +Bill McDermith HP 2100 debugging, 12565A simulator Scott McGregor PDP-11 UNIX legal permissions Jeff Moffatt HP 2100 information, documentation, and software Alec Muffett Solaris port testing @@ -910,6 +971,7 @@ Charles Owen Nova moving head disk debugging, Altair simulator, Sergio Pedraja MINGW environment debugging Derek Peschel PDP-10 debugging Paul Pierce IBM 1401 diagnostics, media recovery +Mark Pizzolato VAX simulator improvements Hans Pufal PDP-10 debugging, PDP-15 bootstrap Bruce Ray Software, documentation, bug fixes, and new devices for the Nova, OS/2 porting @@ -921,6 +983,7 @@ Olaf Seibert NetBSD port testing Brian & Barry Silverman PDP-1 simulator and software Tim Shoppa Nova documentation, RDOS software, PDP-10 and PDP-11 software archive, hosting for SIMH site +Van Snyder IBM 1401 bootstraps Michael Somos PDP-1 debugging Hans-Michael Stahl OS/2 port testing, TERMIOS implementation Tim Stark TS10 PDP-10 simulator @@ -933,6 +996,7 @@ Warren Toomey PDP-11 UNIX software Deb Toivonen DEC documentation Mike Umbricht DEC documentation, H316 documentation and schematics Leendert Van Doorn PDP-11 UNIX V6 debugging, TERMIOS implementation +Holger Veit OS/2 socket support David Waks PDP-8 ESI-X and PDP-7 SIM8 software Tom West Nova documentation Adrian Wise H316 simulator, documentation, and software @@ -947,3 +1011,5 @@ Digital Equipment Corporation Compaq Computer Corporation Mentec Corporation The Santa Cruz Operation +Caldera Corporation + diff --git a/simh_swre.txt b/simh_swre.txt index 8d322072..89e8461d 100644 --- a/simh_swre.txt +++ b/simh_swre.txt @@ -1,7 +1,7 @@ To: Users From: Bob Supnik Subj: Sample Software Packages -Date: 30-Sep-01 +Date: 15-Apr-2002 This memorandum documents the sample software packages available to run with the SIMH simulators. Many of these packages are available under @@ -10,8 +10,8 @@ software. The following copyright notice applies to both the SIMH source and binary: - Original code published in 1993-2001, written by Robert M Supnik - Copyright (c) 1993-2001, Robert M Supnik + Original code published in 1993-2002, written by Robert M Supnik + Copyright (c) 1993-2002, Robert M Supnik Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), @@ -100,7 +100,8 @@ Loading TSS/8 ------------- Note: your environment must have a functioning second Teletype; that is, you cannot -at present run Foreground/Background if your host system is VMS or OS/2. +at present run Foreground/Background if your host system does not support the SIMH +sockets library. - Load the paper-tape bootstrap: @@ -112,7 +113,7 @@ at present run Foreground/Background if your host system is VMS or OS/2. - Assign a TCP/IP port to the Telnet listener for the extra terminals: - sim> attach tti1 -- 4000 typically works + sim> attach ttix -- 4000 typically works - Run the bootstrap: @@ -155,7 +156,7 @@ at present run Foreground/Background if your host system is VMS or OS/2. .R CAT - Other users can log in by connecting, from a Telnet client, to localhost - on the port specified in the attach tti1 command. + on the port specified in the ATTACH TTIX command. 2. PDP-11 @@ -164,12 +165,12 @@ at present run Foreground/Background if your host system is VMS or OS/2. UNIX was first developed on the PDP-7; its first widespread usage was on the PDP-11. UNIX provides a program development and execution environment for assembler and C programs. UNIX V5, V7, V7 for the PDP-11 is provided -under license, as is, without fee, by Santa Cruz Organization (SCO), for -non-commercial use only. Please read the enclosed license agreement for -full terms and conditions. This license must be reproduced with any copy -of the UNIX V5, V6, V7 disk images. My thanks to PUPS, the PDP-11 UNIX -Preservation Society of Australia, which provided the disk images, and to -SCO, which provided the license. +under license, as is, without fee, by Caldera Corportion, for non-commercial +use only. Please read the enclosed license agreement for full terms and +conditions. This license must be reproduced with any copy of the UNIX V5, +V6, V7 disk images. My thanks to PUPS, the PDP-11 UNIX Preservation Society +of Australia, which provided the disk images, and to Caldera, which provided +the license. 2.1.1 UNIX V5 @@ -184,11 +185,12 @@ UNIX V5 is contained on a single RK05 disk image. To boot UNIX: 2.1.2 UNIX V6 -UNIX V6 is contained on three RK05 disk images. To boot UNIX: +UNIX V6 is contained on four RK05 disk images. To boot UNIX: sim> set cpu 18b sim> att rk0 unix0_v6_rk.dsk sim> att rk1 unix1_v6_rk.dsk + sim> att rk2 unix2_v6_rk.dsk sim> att rk3 unix3_v6_rk.dsk sim> boot rk0 @unix @@ -197,9 +199,6 @@ UNIX V6 is contained on three RK05 disk images. To boot UNIX: 2.1.3 UNIX V7 -NOTE: The V7 disk images with V2.3c and later releases are new and -replace the prior versions, which were corrupt. - UNIX V7 is contained on a single RL02 disk image. To boot UNIX: sim> set cpu 18b @@ -260,7 +259,7 @@ distribution pack and generate a new system. This requires mounting a blank pack on RL1. When a blank pack is attached to the simulator, a bad block table must be created with the SET BADBLOCK command. -3. Nova RDOS +3. Nova and Eclipse RDOS RDOS is the Nova's real-time mass storage operating system. It provides a program development and execution environment for assembler, BASIC, and @@ -271,7 +270,7 @@ agreement must be reproduced with any copy of the RDOS disk image. My thanks to Carl Friend, a private collector, who provided the disk image, and to Data General Corporation, which provided the license. -To boot and run RDOS: +To boot and run RDOS for the Nova: sim> att dp0 rdos_d31.dsk sim> set tti dasher @@ -282,6 +281,17 @@ To boot and run RDOS: R list/e +To boot and run RDOS for the Eclipse: + + sim> att dp0 zrdos75.dsk + sim> set tti dasher + sim> boot dp0 + FILENAME? (cr) + DATE (mm/dd/yy)? xx/yy/zz + TIME (hh:mm:ss)? hh:mm:ss + R + list/e + 4. PDP-1 LISP PDP-1 LISP is an interactive interpreter for the Lisp language. It can @@ -377,7 +387,8 @@ execution capabilities. To load and run ADSS/KM-15: 6.3 Advanced Software System/Foreground Background Note: your environment must have a functioning second Teletype; that is, you cannot -at present run Foreground/Background if your host system is VMS or OS/2. +at present run Foreground/Background if your host system does not support the SIMH +sockets library. - Load the paper-tape bootstrap into upper memory: @@ -390,7 +401,7 @@ at present run Foreground/Background if your host system is VMS or OS/2. sim> ex pc PC: 077646 -- Mount the Advanced Software System DECtape image on DECtape unit 0: +- Mount the Foregorund/Background DECtape image on DECtape unit 0: sim> attach dt fb15_32k.dtp @@ -485,7 +496,7 @@ CPU diagnostics. The software and writeup were provided by Charles Owens. -sps1.obj and sps2.obj are the object card decks are the "Symbolic +sps1.obj and sps2.obj are the object card decks for the "Symbolic Programming System", a primitive assembler for the 1401 that predates the better known and more functional Autocoder. @@ -591,11 +602,11 @@ To load and run BASIC: 1.41421 -9. PDP-10 TOPS-10 7.03, TOPS-20 V4.1 +9. PDP-10 TOPS-10 7.03, TOPS-10 7.04, TOPS-20 V4.1 TOPS-10 was the primary time-shared operating system for the PDP-10. TOPS-20 was a popular alternative derived from the BBN TENEX system. -Installation and distribution tapes for TOPS-10 7.03 and TOPS-20 4.1 -are available at http://pdp-10.trailing-edge.com. +Installation and distribution tapes for TOPS-10 7.03, TOPS-10 7.04, +and TOPS-20 4.1 are available at http://pdp-10.trailing-edge.com. [end simh_swre.txt]