diff --git a/MDS-800/MDS-800/Mds-800.cfg b/MDS-800/MDS-800/Mds-800.cfg new file mode 100644 index 00000000..3db17a13 --- /dev/null +++ b/MDS-800/MDS-800/Mds-800.cfg @@ -0,0 +1,44 @@ +/* mds-800.cfg: Intel mds-800 simulator definitions + + This file holds the configuration for the mds-800 + boards I/O and Memory. + + Copyright (c) 2015, William A. Beech + + Permission is hereby granted, free of charge, to any person obtaining a + copy of this software and associated documentation files (the "Software"), + to deal in the Software without restriction, including without limitation + the rights to use, copy, modify, merge, publish, distribute, sublicense, + and/or sell copies of the Software, and to permit persons to whom the + Software is furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + William A. Beech BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + Except as contained in this notice, the name of William A. Beech shall not be + used in advertising or otherwise to promote the sale, use or other dealings + in this Software without prior written authorization from William A. Beech. + + 16 Dec 12 - Original file + 08 Apr 15 - Modified to be mds-800.cfg file to set base and size. + Changed tabs to spaces + +*/ + +/* set the base I/O address for the iSBC 208 */ +#define SBC208_BASE 0x40 + +/* configure interrupt request line */ +#define SBC208_INT INT_1 + +/* set the base and size for the iSBC 064 */ +#define SBC064_BASE 0x0000 +#define SBC064_SIZE 0x10000 + diff --git a/MDS-800/MDS-800/Mds-800.txt b/MDS-800/MDS-800/Mds-800.txt new file mode 100644 index 00000000..e63bdd6e --- /dev/null +++ b/MDS-800/MDS-800/Mds-800.txt @@ -0,0 +1,211 @@ +Altair 8800 Simulator +===================== + +1. Background. + + The MITS (Micro Instrumentation and Telemetry Systems) Altair 8800 +was announced on the January 1975 cover of Popular Electronics, which +boasted you could buy and build this powerful computer kit for only $397. +The kit consisted at that time of only the parts to build a case, power +supply, card cage (18 slots), CPU card, and memory card with 256 *bytes* of +memory. Still, thousands were ordered within the first few months after the +announcement, starting the personal computer revolution as we know it today. + + Many laugh at the small size of the that first kit, noting there +were no peripherals and the 256 byte memory size. But the computer was an +open system, and by 1977 MITS and many other small startups had added many +expansion cards to make the Altair quite a respectable little computer. The +"Altair Bus" that made this possible was soon called the S-100 Bus, later +adopted as an industry standard, and eventually became the IEE-696 Bus. + +2. Hardware + + We are simulating a fairly "loaded" Altair 8800 from about 1977, +with the following configuration: + + device simulates + name(s) + + CPU Altair 8800 with Intel 8080 CPU board, 62KB + of RAM, 2K of EPROM with start boot ROM. + 2SIO MITS 88-2SIO Dual Serial Interface Board. Port 1 + is assumed to be connected to a serial "glass + TTY" that is your terminal running the Simulator. + PTR Paper Tape Reader attached to port 2 of the + 2SIO board. + PTP Paper Tape Punch attached to port 2 of the + 2SIO board. This also doubles as a printer + port. + DSK MITS 88-DISK Floppy Disk controller with up + to eight drives. + +2.1 CPU + + We have 2 CPU options that were not present on the original +machine but are useful in the simulator. We also allow you to select +memory sizes, but be aware that some sample software requires the full +64K (i.e. CP/M) and the MITS Disk Basic and Altair DOS require about +a minimum of 24K. + + SET CPU 8080 Simulates the 8080 CPU (normal) + SET CPU Z80 Simulates the later Z80 CPU [At the present time + this is not fully implemented and is not to be + trusted with real Z80 software] + SET CPU ITRAP Causes the simulator to halt if an invalid 8080 + Opcode is detected. + SET CPU NOITRAP Does not stop on an invalid Opcode. This is + how the real 8080 works. + SET CPU 4K + SET CPU 8K + SET CPU 12K + SET CPU 16K + ...... + SET CPU 64K All these set various CPU memory configurations. + The 2K EPROM at the high end of memory is always + present and will always boot. + +The BOOT EPROM card starts at address 177400. Jumping to this address +will always boot drive 0 of the floppy controller. If no valid bootable +software is present there the machine crashes. This is historically +accurate behavior. + +The real 8080, on receiving a HLT (Halt) instruction, freezes the processor +and only an interrupt or CPU hardware reset will restore it. The simulator +is alot nicer, it will halt but send you back to the simulator command line. + +CPU Registers include the following: + + name size comments + + PC 16 The Program Counter + A 8 The accumulator + BC 16 The BC register pair. Register B is the high + 8 bits, C is the lower 8 bits + DE 16 The DE register pair. D is the top 8 bits, E is + the bottom. + HL 16 The HL register pair. H is top, L is bottom. + C 1 Carry flag. + Z 1 Zero Flag. + AC 1 Auxillary Carry flag. + P 1 Parity flag. + S 1 Sign flag. + SR 16 The front panel switches. + BREAK 16 Breakpoint address (377777 to disable). + WRU 8 The interrupt character. This starts as 005 + (ctrl-E) but some Altair software uses this + keystroke so best to change this to something + exotic such as 035 (which is Ctl-]). + + +2.2 The Serial I/O Card (2SIO) + + This simple programmed I/O device provides 2 serial ports to the +outside world, which could be hardware jumpered to support RS-232 plugs or a +TTY current loop interface. The standard I/O addresses assigned by MITS +was 20-21 (octal) for the first port, and 22-23 (octal) for the second. +We follow this standard in the Simulator. + + The simulator directs I/O to/from the first port to the screen. The +second port reads from an attachable "tape reader" file on input, and writes +to an attachable "punch file" on output. These files are considered a +simple stream of 8-bit bytes. + +2.3 The 88-DISK controller. + + The MITS 88-DISK is a simple programmed I/O interface to the MITS +8-inch floppy drive, which was basically a Pertec FD-400 with a power +supply and buffer board builtin. The controller supports neither interrupts +nor DMA, so floppy access required the sustained attention of the CPU. +The standard I/O addresses were 10, 11, and 12 (octal), and we follow the +standard. Details on controlling this hardware are in the altair_dsk.c +source file. + + +3. Sample Software + + Running an Altair in 1977 you would be running either MITS Disk +Extended BASIC, or the brand new and sexy CP/M Operating System from Digital +Research. Or possibly, you ordered Altair DOS back when it was promised in +1975, and are still waiting for it to be delivered in early 1977. + + We have samples of all three for you to check out. We can't go into +the details of how they work, but we'll give you a few hints. + + +3.1 CP/M Version 2.2 + + This version is my own port of the standard CP/M to the Altair. +There were some "official" versions but I don't have them. None were +endorsed or sold by MITS to my knowledge, however. + To boot CP/M: + + sim> attach dsk0 altcpm.dsk + sim> go 177400 + 62K CP/M VERSION 2.2 (ALTAIR 8800) + A>DIR + + CP/M feels like DOS, sort of. DIR will work. I have included all +the standard CP/M utilities, plus a few common public-domain ones. I also +include the sources to the customized BIOS and some other small programs. +TYPE will print an ASCII file. DUMP will dump a binary one. LS is a better +DIR than DIR. ASM will assemble .ASM files to Hex, LOAD will "load" them to +binary format (.COM). ED is a simple editor, #A command will bring the +source file to the buffer, T command will "type" lines, L will move lines, +E exits the editor. 20L20T will move down 20 lines, and type 20. Very +DECish. DDT is the debugger, SUBMIT is a batch-type command processor. +A sample batch file that will assemble and write out the bootable CP/M +image (on drive A) is "SYSGEN.SUB". To run it, type "SUBMIT SYSGEN". + + +3.2 MITS Disk Extended BASIC Version 4.1 + + This was the commonly used software for serious users of the Altair +computer. It is a powerful (but slow) BASIC with some extended commands to +allow it to access and manage the disk. There was no operating system it +ran under. To boot: + + sim> attach dsk0 mbasic.dsk + sim> go 177400 + + MEMORY SIZE? [return] + LINEPRINTER? C [return] + HIGHEST DISK NUMBER? 0 [return] (3 here = 4 drive system) + NUMBER OF FILES? 3 [return] + NUMBER OF RANDOM FILES? 2 [return] + + 44297 BYTES FREE + ALTAIR BASIC REV. 4.1 + [DISK EXTENDED VERSION] + COPYRIGHT 1977 BY MITS INC. + OK + mount 0 + OK + files + + +3.3 Altair DOS Version 1.0 + + This was long promised but not delivered until it was almost +irrelevant. A short attempted tour will reveal it to be a dog, far inferior +to CP/M. To boot: + + sim> attach dsk0 altdos.dsk + sim> go 177400 + + MEMORY SIZE? 64 [return] + INTERRUPTS? N [return] + HIGHEST DISK NUMBER? 0 [return] (3 here = 4 drive system) + HOW MANY DISK FILES? 3 [return] + HOW MANY RANDOM FILES? 2 [return] + + 056769 BYTES AVAILABLE + DOS MONITOR VER 1.0 + COPYRIGHT 1977 BY MITS INC + .mnt 0 + + .dir 0 + + + + + diff --git a/MDS-800/MDS-800/Mds-800.vsd b/MDS-800/MDS-800/Mds-800.vsd new file mode 100644 index 00000000..a0acb997 Binary files /dev/null and b/MDS-800/MDS-800/Mds-800.vsd differ diff --git a/MDS-800/MDS-800/functional description.vsd b/MDS-800/MDS-800/functional description.vsd new file mode 100644 index 00000000..a6fd1978 Binary files /dev/null and b/MDS-800/MDS-800/functional description.vsd differ diff --git a/MDS-800/MDS-800/mds-800_sys.c b/MDS-800/MDS-800/mds-800_sys.c new file mode 100644 index 00000000..fa346ccb --- /dev/null +++ b/MDS-800/MDS-800/mds-800_sys.c @@ -0,0 +1,81 @@ +/* system_80_10_sys.c: multibus system interface + + Copyright (c) 2010, William A. Beech + + Permission is hereby granted, free of charge, to any person obtaining a + copy of this software and associated documentation files (the "Software"), + to deal in the Software without restriction, including without limitation + the rights to use, copy, modify, merge, publish, distribute, sublicense, + and/or sell copies of the Software, and to permit persons to whom the + Software is furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + William A. Beech BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + Except as contained in this notice, the name of William A. Beech shall not be + used in advertising or otherwise to promote the sale, use or other dealings + in this Software without prior written authorization from William A. Beech. + + ?? ??? 10 - Original file. + 16 Dec 12 - Modified to use isbc_80_10.cfg file to set base and size. + 08 Apr 15 - Modified to use mds-800.cfg file to set base and size. + Changed tabs to spaces + +*/ + +#include "system_defs.h" + +extern DEVICE i8080_dev; +extern REG i8080_reg[]; +extern DEVICE i8251_dev; +extern DEVICE i8255_dev; +extern DEVICE EPROM_dev; +extern DEVICE RAM_dev; +extern DEVICE multibus_dev; +extern DEVICE isbc208_dev; +extern DEVICE isbc064_dev; + +/* SCP data structures + + sim_name simulator name string + sim_PC pointer to saved PC register descriptor + sim_emax number of words needed for examine + sim_devices array of pointers to simulated devices + sim_stop_messages array of pointers to stop messages +*/ + +char sim_name[] = "Intel MDS-800"; + +REG *sim_PC = &i8080_reg[0]; + +int32 sim_emax = 4; + +DEVICE *sim_devices[] = { + &i8080_dev, + &EPROM_dev, + &RAM_dev, + &i8251_dev, + &i8255_dev, + &multibus_dev, + &isbc064_dev, + &isbc208_dev, + NULL +}; + +const char *sim_stop_messages[] = { + "Unknown error", + "Unknown I/O Instruction", + "HALT instruction", + "Breakpoint", + "Invalid Opcode", + "Invalid Memory", + "XACK Error" +}; + diff --git a/MDS-800/MDS-800/system_defs.h b/MDS-800/MDS-800/system_defs.h new file mode 100644 index 00000000..4892355c --- /dev/null +++ b/MDS-800/MDS-800/system_defs.h @@ -0,0 +1,84 @@ +/* system_defs.h: Intel iSBC simulator definitions + + Copyright (c) 2010, William A. Beech + + Permission is hereby granted, free of charge, to any person obtaining a + copy of this software and associated documentation files (the "Software"), + to deal in the Software without restriction, including without limitation + the rights to use, copy, modify, merge, publish, distribute, sublicense, + and/or sell copies of the Software, and to permit persons to whom the + Software is furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + William A. Beech BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + Except as contained in this notice, the name of William A. Beech shall not be + used in advertising or otherwise to promote the sale, use or other dealings + in this Software without prior written authorization from William A. Beech. + + ?? ??? 10 - Original file. + 16 Dec 12 - Modified to use isbc_80_10.cfg file to set base and size. + 08 Apr 15 - Modified to use mds-800.cfg file to set base and size. + Changed tabs to spaces + +*/ + +#include +#include +#include "mds-800.cfg" /* Intel System 80/10 configuration */ +#include "sim_defs.h" /* simulator defns */ + +/* multibus interrupt definitions */ + +#define INT_0 0x01 +#define INT_1 0x02 +#define INT_2 0x04 +#define INT_3 0x08 +#define INT_4 0x10 +#define INT_5 0x20 +#define INT_6 0x40 +#define INT_7 0x80 + +/* CPU interrupts definitions */ + +#define INT_R 0x200 +#define I75 0x40 +#define I65 0x20 +#define I55 0x10 + +/* Memory */ + +#define MAXMEMSIZE 0x10000 /* 8080 max memory size */ +#define MEMSIZE (i8080_unit.capac) /* 8080 actual memory size */ +#define ADDRMASK (MAXMEMSIZE - 1) /* 8080 address mask */ +#define MEM_ADDR_OK(x) (((uint32) (x)) < MEMSIZE) + +/* debug definitions */ + +#define DEBUG_flow 0x0001 +#define DEBUG_read 0x0002 +#define DEBUG_write 0x0004 +#define DEBUG_level1 0x0008 +#define DEBUG_level2 0x0010 +#define DEBUG_reg 0x0020 +#define DEBUG_asm 0x0040 +#define DEBUG_xack 0x0080 +#define DEBUG_all 0xFFFF + +/* Simulator stop codes */ + +#define STOP_RSRV 1 /* must be 1 */ +#define STOP_HALT 2 /* HALT */ +#define STOP_IBKPT 3 /* breakpoint */ +#define STOP_OPCODE 4 /* Invalid Opcode */ +#define STOP_IO 5 /* I/O error */ +#define STOP_MEM 6 /* Memory error */ +#define STOP_XACK 7 /* XACK error */ + diff --git a/MDS-800/System_80-10/System_80-10.txt b/MDS-800/System_80-10/System_80-10.txt new file mode 100644 index 00000000..e63bdd6e --- /dev/null +++ b/MDS-800/System_80-10/System_80-10.txt @@ -0,0 +1,211 @@ +Altair 8800 Simulator +===================== + +1. Background. + + The MITS (Micro Instrumentation and Telemetry Systems) Altair 8800 +was announced on the January 1975 cover of Popular Electronics, which +boasted you could buy and build this powerful computer kit for only $397. +The kit consisted at that time of only the parts to build a case, power +supply, card cage (18 slots), CPU card, and memory card with 256 *bytes* of +memory. Still, thousands were ordered within the first few months after the +announcement, starting the personal computer revolution as we know it today. + + Many laugh at the small size of the that first kit, noting there +were no peripherals and the 256 byte memory size. But the computer was an +open system, and by 1977 MITS and many other small startups had added many +expansion cards to make the Altair quite a respectable little computer. The +"Altair Bus" that made this possible was soon called the S-100 Bus, later +adopted as an industry standard, and eventually became the IEE-696 Bus. + +2. Hardware + + We are simulating a fairly "loaded" Altair 8800 from about 1977, +with the following configuration: + + device simulates + name(s) + + CPU Altair 8800 with Intel 8080 CPU board, 62KB + of RAM, 2K of EPROM with start boot ROM. + 2SIO MITS 88-2SIO Dual Serial Interface Board. Port 1 + is assumed to be connected to a serial "glass + TTY" that is your terminal running the Simulator. + PTR Paper Tape Reader attached to port 2 of the + 2SIO board. + PTP Paper Tape Punch attached to port 2 of the + 2SIO board. This also doubles as a printer + port. + DSK MITS 88-DISK Floppy Disk controller with up + to eight drives. + +2.1 CPU + + We have 2 CPU options that were not present on the original +machine but are useful in the simulator. We also allow you to select +memory sizes, but be aware that some sample software requires the full +64K (i.e. CP/M) and the MITS Disk Basic and Altair DOS require about +a minimum of 24K. + + SET CPU 8080 Simulates the 8080 CPU (normal) + SET CPU Z80 Simulates the later Z80 CPU [At the present time + this is not fully implemented and is not to be + trusted with real Z80 software] + SET CPU ITRAP Causes the simulator to halt if an invalid 8080 + Opcode is detected. + SET CPU NOITRAP Does not stop on an invalid Opcode. This is + how the real 8080 works. + SET CPU 4K + SET CPU 8K + SET CPU 12K + SET CPU 16K + ...... + SET CPU 64K All these set various CPU memory configurations. + The 2K EPROM at the high end of memory is always + present and will always boot. + +The BOOT EPROM card starts at address 177400. Jumping to this address +will always boot drive 0 of the floppy controller. If no valid bootable +software is present there the machine crashes. This is historically +accurate behavior. + +The real 8080, on receiving a HLT (Halt) instruction, freezes the processor +and only an interrupt or CPU hardware reset will restore it. The simulator +is alot nicer, it will halt but send you back to the simulator command line. + +CPU Registers include the following: + + name size comments + + PC 16 The Program Counter + A 8 The accumulator + BC 16 The BC register pair. Register B is the high + 8 bits, C is the lower 8 bits + DE 16 The DE register pair. D is the top 8 bits, E is + the bottom. + HL 16 The HL register pair. H is top, L is bottom. + C 1 Carry flag. + Z 1 Zero Flag. + AC 1 Auxillary Carry flag. + P 1 Parity flag. + S 1 Sign flag. + SR 16 The front panel switches. + BREAK 16 Breakpoint address (377777 to disable). + WRU 8 The interrupt character. This starts as 005 + (ctrl-E) but some Altair software uses this + keystroke so best to change this to something + exotic such as 035 (which is Ctl-]). + + +2.2 The Serial I/O Card (2SIO) + + This simple programmed I/O device provides 2 serial ports to the +outside world, which could be hardware jumpered to support RS-232 plugs or a +TTY current loop interface. The standard I/O addresses assigned by MITS +was 20-21 (octal) for the first port, and 22-23 (octal) for the second. +We follow this standard in the Simulator. + + The simulator directs I/O to/from the first port to the screen. The +second port reads from an attachable "tape reader" file on input, and writes +to an attachable "punch file" on output. These files are considered a +simple stream of 8-bit bytes. + +2.3 The 88-DISK controller. + + The MITS 88-DISK is a simple programmed I/O interface to the MITS +8-inch floppy drive, which was basically a Pertec FD-400 with a power +supply and buffer board builtin. The controller supports neither interrupts +nor DMA, so floppy access required the sustained attention of the CPU. +The standard I/O addresses were 10, 11, and 12 (octal), and we follow the +standard. Details on controlling this hardware are in the altair_dsk.c +source file. + + +3. Sample Software + + Running an Altair in 1977 you would be running either MITS Disk +Extended BASIC, or the brand new and sexy CP/M Operating System from Digital +Research. Or possibly, you ordered Altair DOS back when it was promised in +1975, and are still waiting for it to be delivered in early 1977. + + We have samples of all three for you to check out. We can't go into +the details of how they work, but we'll give you a few hints. + + +3.1 CP/M Version 2.2 + + This version is my own port of the standard CP/M to the Altair. +There were some "official" versions but I don't have them. None were +endorsed or sold by MITS to my knowledge, however. + To boot CP/M: + + sim> attach dsk0 altcpm.dsk + sim> go 177400 + 62K CP/M VERSION 2.2 (ALTAIR 8800) + A>DIR + + CP/M feels like DOS, sort of. DIR will work. I have included all +the standard CP/M utilities, plus a few common public-domain ones. I also +include the sources to the customized BIOS and some other small programs. +TYPE will print an ASCII file. DUMP will dump a binary one. LS is a better +DIR than DIR. ASM will assemble .ASM files to Hex, LOAD will "load" them to +binary format (.COM). ED is a simple editor, #A command will bring the +source file to the buffer, T command will "type" lines, L will move lines, +E exits the editor. 20L20T will move down 20 lines, and type 20. Very +DECish. DDT is the debugger, SUBMIT is a batch-type command processor. +A sample batch file that will assemble and write out the bootable CP/M +image (on drive A) is "SYSGEN.SUB". To run it, type "SUBMIT SYSGEN". + + +3.2 MITS Disk Extended BASIC Version 4.1 + + This was the commonly used software for serious users of the Altair +computer. It is a powerful (but slow) BASIC with some extended commands to +allow it to access and manage the disk. There was no operating system it +ran under. To boot: + + sim> attach dsk0 mbasic.dsk + sim> go 177400 + + MEMORY SIZE? [return] + LINEPRINTER? C [return] + HIGHEST DISK NUMBER? 0 [return] (3 here = 4 drive system) + NUMBER OF FILES? 3 [return] + NUMBER OF RANDOM FILES? 2 [return] + + 44297 BYTES FREE + ALTAIR BASIC REV. 4.1 + [DISK EXTENDED VERSION] + COPYRIGHT 1977 BY MITS INC. + OK + mount 0 + OK + files + + +3.3 Altair DOS Version 1.0 + + This was long promised but not delivered until it was almost +irrelevant. A short attempted tour will reveal it to be a dog, far inferior +to CP/M. To boot: + + sim> attach dsk0 altdos.dsk + sim> go 177400 + + MEMORY SIZE? 64 [return] + INTERRUPTS? N [return] + HIGHEST DISK NUMBER? 0 [return] (3 here = 4 drive system) + HOW MANY DISK FILES? 3 [return] + HOW MANY RANDOM FILES? 2 [return] + + 056769 BYTES AVAILABLE + DOS MONITOR VER 1.0 + COPYRIGHT 1977 BY MITS INC + .mnt 0 + + .dir 0 + + + + + diff --git a/MDS-800/System_80-10/System_80-10.vsd b/MDS-800/System_80-10/System_80-10.vsd new file mode 100644 index 00000000..7f4a87f5 Binary files /dev/null and b/MDS-800/System_80-10/System_80-10.vsd differ diff --git a/MDS-800/System_80-10/functional description.vsd b/MDS-800/System_80-10/functional description.vsd new file mode 100644 index 00000000..a6fd1978 Binary files /dev/null and b/MDS-800/System_80-10/functional description.vsd differ diff --git a/MDS-800/System_80-10/system_80_10.cfg b/MDS-800/System_80-10/system_80_10.cfg new file mode 100644 index 00000000..d38d3529 --- /dev/null +++ b/MDS-800/System_80-10/system_80_10.cfg @@ -0,0 +1,41 @@ +/* system_80_10.cfg: Intel System 80/10 simulator definitions + + This file holds the configuration for the System 80/10 + boards I/O and Memory. + + Copyright (c) 2010, William A. Beech + + Permission is hereby granted, free of charge, to any person obtaining a + copy of this software and associated documentation files (the "Software"), + to deal in the Software without restriction, including without limitation + the rights to use, copy, modify, merge, publish, distribute, sublicense, + and/or sell copies of the Software, and to permit persons to whom the + Software is furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + William A. Beech BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + Except as contained in this notice, the name of William A. Beech shall not be + used in advertising or otherwise to promote the sale, use or other dealings + in this Software without prior written authorization from William A. Beech. + + 16 Dec 12 - Original file +*/ + +/* set the base I/O address for the iSBC 208 */ +#define SBC208_BASE 0x40 + +/* configure interrupt request line */ +#define SBC208_INT INT_1 + +/* set the base and size for the iSBC 064 */ +#define SBC064_BASE 0x0000 +#define SBC064_SIZE 0x10000 + diff --git a/MDS-800/System_80-10/system_80_10_sys.c b/MDS-800/System_80-10/system_80_10_sys.c new file mode 100644 index 00000000..21128265 --- /dev/null +++ b/MDS-800/System_80-10/system_80_10_sys.c @@ -0,0 +1,78 @@ +/* system_80_10_sys.c: multibus system interface + + Copyright (c) 2010, William A. Beech + + Permission is hereby granted, free of charge, to any person obtaining a + copy of this software and associated documentation files (the "Software"), + to deal in the Software without restriction, including without limitation + the rights to use, copy, modify, merge, publish, distribute, sublicense, + and/or sell copies of the Software, and to permit persons to whom the + Software is furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + William A. Beech BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + Except as contained in this notice, the name of William A. Beech shall not be + used in advertising or otherwise to promote the sale, use or other dealings + in this Software without prior written authorization from William A. Beech. + + ?? ??? 10 - Original file. + 16 Dec 12 - Modified to use isbc_80_10.cfg file to set base and size. +*/ + +#include "system_defs.h" + +extern DEVICE i8080_dev; +extern REG i8080_reg[]; +extern DEVICE i8251_dev; +extern DEVICE i8255_dev; +extern DEVICE EPROM_dev; +extern DEVICE RAM_dev; +extern DEVICE multibus_dev; +extern DEVICE isbc208_dev; +extern DEVICE isbc064_dev; + +/* SCP data structures + + sim_name simulator name string + sim_PC pointer to saved PC register descriptor + sim_emax number of words needed for examine + sim_devices array of pointers to simulated devices + sim_stop_messages array of pointers to stop messages +*/ + +char sim_name[] = "Intel System 80/10"; + +REG *sim_PC = &i8080_reg[0]; + +int32 sim_emax = 4; + +DEVICE *sim_devices[] = { + &i8080_dev, + &EPROM_dev, + &RAM_dev, + &i8251_dev, + &i8255_dev, + &multibus_dev, + &isbc064_dev, + &isbc208_dev, + NULL +}; + +const char *sim_stop_messages[] = { + "Unknown error", + "Unknown I/O Instruction", + "HALT instruction", + "Breakpoint", + "Invalid Opcode", + "Invalid Memory", + "XACK Error" +}; + diff --git a/MDS-800/System_80-10/system_defs.h b/MDS-800/System_80-10/system_defs.h new file mode 100644 index 00000000..9ee659da --- /dev/null +++ b/MDS-800/System_80-10/system_defs.h @@ -0,0 +1,81 @@ +/* system_defs.h: Intel iSBC simulator definitions + + Copyright (c) 2010, William A. Beech + + Permission is hereby granted, free of charge, to any person obtaining a + copy of this software and associated documentation files (the "Software"), + to deal in the Software without restriction, including without limitation + the rights to use, copy, modify, merge, publish, distribute, sublicense, + and/or sell copies of the Software, and to permit persons to whom the + Software is furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + William A. Beech BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + Except as contained in this notice, the name of William A. Beech shall not be + used in advertising or otherwise to promote the sale, use or other dealings + in this Software without prior written authorization from William A. Beech. + + ?? ??? 10 - Original file. + 16 Dec 12 - Modified to use isbc_80_10.cfg file to set base and size. +*/ + +#include +#include +#include "system_80_10.cfg" /* Intel System 80/10 configuration */ +#include "sim_defs.h" /* simulator defns */ + +/* multibus interrupt definitions */ + +#define INT_0 0x01 +#define INT_1 0x02 +#define INT_2 0x04 +#define INT_3 0x08 +#define INT_4 0x10 +#define INT_5 0x20 +#define INT_6 0x40 +#define INT_7 0x80 + +/* CPU interrupts definitions */ + +#define INT_R 0x200 +#define I75 0x40 +#define I65 0x20 +#define I55 0x10 + +/* Memory */ + +#define MAXMEMSIZE 0x10000 /* 8080 max memory size */ +#define MEMSIZE (i8080_unit.capac) /* 8080 actual memory size */ +#define ADDRMASK (MAXMEMSIZE - 1) /* 8080 address mask */ +#define MEM_ADDR_OK(x) (((uint32) (x)) < MEMSIZE) + +/* debug definitions */ + +#define DEBUG_flow 0x0001 +#define DEBUG_read 0x0002 +#define DEBUG_write 0x0004 +#define DEBUG_level1 0x0008 +#define DEBUG_level2 0x0010 +#define DEBUG_reg 0x0020 +#define DEBUG_asm 0x0040 +#define DEBUG_xack 0x0080 +#define DEBUG_all 0xFFFF + +/* Simulator stop codes */ + +#define STOP_RSRV 1 /* must be 1 */ +#define STOP_HALT 2 /* HALT */ +#define STOP_IBKPT 3 /* breakpoint */ +#define STOP_OPCODE 4 /* Invalid Opcode */ +#define STOP_IO 5 /* I/O error */ +#define STOP_MEM 6 /* Memory error */ +#define STOP_XACK 7 /* XACK error */ + diff --git a/MDS-800/common/i8008.c b/MDS-800/common/i8008.c new file mode 100644 index 00000000..6a840d90 --- /dev/null +++ b/MDS-800/common/i8008.c @@ -0,0 +1,2002 @@ +/* i8008.c: Intel 8008 CPU simulator + + Copyright (c) 2011, William A. Beech + + Permission is hereby granted, free of charge, to any person obtaining a + copy of this software and associated documentation files (the "Software"), + to deal in the Software without restriction, including without limitation + the rights to use, copy, modify, merge, publish, distribute, sublicense, + and/or sell copies of the Software, and to permit persons to whom the + Software is furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + WILLIAM A. BEECH BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + Except as contained in this notice, the name of William A. Beech shall not be + used in advertising or otherwise to promote the sale, use or other dealings + in this Software without prior written authorization from William A. Beech. + + cpu 8008 CPU + + The register state for the 8008 CPU is: + + A<0:7> Accumulator + B<0:7> B Register + C<0:7> C Register + D<0:7> D Register + E<0:7> E Register + H<0:7> H Register + L<0:7> L Register + PC<0:13> Program counter + + The 8008 is an 8-bit CPU, which uses 14-bit registers to address + up to 16KB of memory. + + The 57 basic instructions come in 1, 2, and 3-byte flavors. + + This routine is the instruction decode routine for the 8008. + 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: + + HLT instruction + I/O error in I/O simulator + Invalid OP code (if ITRAP is set on CPU) + + 2. Interrupts. + There are 8 possible levels of interrupt, and in effect they + do a hardware CALL instruction to one of 8 possible low + memory addresses. + + 3. Non-existent memory. On the 8008, reads to non-existent memory + return 0FFh, 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: + + 15 Feb 15 - Original file. + +*/ + +#include "system_defs.h" + +#define UNIT_V_OPSTOP (UNIT_V_UF) /* Stop on Invalid OP? */ +#define UNIT_OPSTOP (1 << UNIT_V_OPSTOP) +#define UNIT_V_TRACE (UNIT_V_UF+1) /* Trace switch */ +#define UNIT_TRACE (1 << UNIT_V_TRACE) + +/* register masks */ +#define BYTE_R 0xFF +#define WORD_R14 0x3FFF + +/* storage for the rest of the registers */ +uint32 A = 0; /* accumulator */ +uint32 B = 0; /* B register */ +uint32 C = 0; /* C register */ +uint32 D = 0; /* D register */ +uint32 E = 0; /* E register */ +uint32 H = 0; /* H register */ +uint32 L = 0; /* L register */ +uint32 CF = 0; /* C - carry flag */ +uint32 PF = 0; /* P - parity flag */ +uint32 ZF = 0; /* Z - zero flag */ +uint32 SF = 0; /* S - sign flag */ +uint32 SP = 0; /* stack frame pointer */ +uint32 saved_PC = 0; /* program counter */ +uint32 int_req = 0; /* Interrupt request */ + +int32 PCX; /* External view of PC */ +int32 PC; +UNIT *uptr; + +/* function prototypes */ +void store_m(unit32 val); +unit32 fetch_m(void); +void set_cpuint(int32 int_num); +void dumpregs(void); +int32 fetch_byte(int32 flag); +int32 fetch_word(void); +uint16 pop_word(void); +void push_word(uint16 val); +void setflag4(int32 reg); +void setlogical(int32 reg); +void setinc(int32 reg); +int32 getreg(int32 reg); +void putreg(int32 reg, int32 val); +int32 getpair(int32 reg); +int32 getpush(int32 reg); +void putpush(int32 reg, int32 data); +void putpair(int32 reg, int32 val); +void parity(int32 reg); +int32 cond(int32 con); +t_stat i8008_ex (t_value *vptr, t_addr addr, UNIT *uptr, int32 sw); +t_stat i8008_dep (t_value val, t_addr addr, UNIT *uptr, int32 sw); +t_stat i8008_reset (DEVICE *dptr); + +/* external function prototypes */ + +extern t_stat i8008_reset (DEVICE *dptr); +extern int32 get_mbyte(int32 addr); +extern int32 get_mword(int32 addr); +extern void put_mbyte(int32 addr, int32 val); +extern void put_mword(int32 addr, int32 val); +extern int32 sim_int_char; +extern uint32 sim_brk_types, sim_brk_dflt, sim_brk_summ; /* breakpoint info */ + + +struct idev { + int32 (*routine)(); +}; + +/* This is the I/O configuration table. There are 256 possible +device addresses, if a device is plugged to a port it's routine +address is here, 'nulldev' means no device is available +*/ + +extern struct idev dev_table[]; + +/* CPU data structures + + i8008_dev CPU device descriptor + i8008_unit CPU unit descriptor + i8008_reg CPU register list + i8008_mod CPU modifiers list +*/ + +UNIT i8008_unit = { UDATA (NULL, 0, 65535) }; /* default 8008 */ + +REG i8008_reg[] = { + { HRDATA (PC, saved_PC, 16) }, /* must be first for sim_PC */ + { HRDATA (A, A, 8) }, + { HRDATA (B, B, 8) }, + { HRDATA (C, C, 8) }, + { HRDATA (D, D, 8) }, + { HRDATA (E, E, 8) }, + { HRDATA (H, H, 8) }, + { HRDATA (L, L, 8) }, + { HRDATA (CF, CF, 1) }, + { HRDATA (PF, PF, 1) }, + { HRDATA (ZF, SF, 1) }, + { HRDATA (SF, SF, 1) }, + { HRDATA (INTR, int_req, 32) }, + { HRDATA (WRU, sim_int_char, 8) }, + { NULL } +}; + +MTAB i8008_mod[] = { + { UNIT_OPSTOP, 0, "ITRAP", "ITRAP", NULL }, + { UNIT_OPSTOP, UNIT_OPSTOP, "NOITRAP", "NOITRAP", NULL }, + { UNIT_TRACE, 0, "NOTRACE", "NOTRACE", NULL }, + { UNIT_TRACE, UNIT_TRACE, "TRACE", "TRACE", NULL }, + { 0 } +}; + +DEBTAB i8008_debug[] = { + { "ALL", DEBUG_all }, + { "FLOW", DEBUG_flow }, + { "READ", DEBUG_read }, + { "WRITE", DEBUG_write }, + { "LEV1", DEBUG_level1 }, + { "LEV2", DEBUG_level2 }, + { "REG", DEBUG_reg }, + { "ASM", DEBUG_asm }, + { NULL } +}; + +DEVICE i8008_dev = { + "CPU", //name + &i8008_unit, //units + i8008_reg, //registers + i8008_mod, //modifiers + 1, //numunits + 16, //aradix + 16, //awidth + 1, //aincr + 16, //dradix + 8, //dwidth + &i8008_ex, //examine + &i8008_dep, //deposit +// &i8008_reset, //reset + NULL, //reset + NULL, //boot + NULL, //attach + NULL, //detach + NULL, //ctxt + DEV_DEBUG, //flags + 0, //dctrl + i8008_debug, //debflags + NULL, //msize + NULL //lname +}; + +/* tables for the disassembler */ +char *opcode[] = { +"*HLT", "*HLT", "RLC", "RFC", /* 0x00 */ +"ADI ", "RST 0", "LAI ,", "RET", +"INB", "DCB", "RRC", "RFZ", +"ACI ", "RST 1", "LBI ", "*RET", +"INC", "DCC", "RAL", "RFS", /* 0x10 */ +"SUI ", "RST 2", "LCI ", "*RET", +"IND", "DCD", "RAR", "RFP", +"SBI ", "RST 3", "LDI ", "*RET", +"INE", "DCE", "???", "RTC", /* 0x20 */ +"NDI ", "RST 4", "LEI ", "*RET", +"INH", "DCH", "???", "RTZ", +"XRI ", "RST 5", "LHI ", "*RET", +"INL", "DCL", "???", "RTS", /* 0x30 */ +"ORI ", "RST 6", "LLI ", "*RET", +"???", "???", "???", "RTP", +"CPI ", "RST 7", "LMI ", "*RET", +"JFC ", "INP ", "CFC ", "INP ", /* 0x40 */ +"JMP ", "INP ", "CAL ", "INP ", +"JFZ ", "INP ", "CFZ ", "INP ", +"*JMP ", "INP ", "*CAL ", "INP ", +"JFS", "OUT ", "CFS ", "OUT ", /* 0x50 */ +"*JMP ", "OUT ", "*CAL ", "OUT ", +"JFP ", "OUT ", "CFP ", "OUT ", +"*JMP ", "OUT ", "*CAL ", "OUT ", +"JTC ", "OUT ", "CTC ", "OUT ", /* 0x60 */ +"*JMP ", "OUT ", "*CAL ", "OUT ", +"JTZ ", "OUT ", "CTZ", "OUT ", +"*JMP ", "OUT ", "*CAL", "OUT ", +"JTS ", "OUT ", "CTS ", "OUT ", /* 0x70 */ +"*JMP ", "OUT ", "*CAL ", "OUT ", +"JTP ", "OUT ", "CTP", "OUT ", +"*JMP ", "OUT ", "*CAL ", "OUT ", +"ADA", "ADB", "ADC", "ADD", /* 0x80 */ +"ADE", "ADH", "ADL", "ADM", +"ACA", "ACB", "ACC", "ACD", +"ACE", "ACH", "ACL", "ACM", +"SUA", "SUB", "SUC", "SUD", /* 0x90 */ +"SUE", "SUH", "SUL", "SUM", +"SBA", "SBB", "SBC", "SBD", +"SBE", "SBH", "SBL", "SBM", +"NDA", "NDB", "NDC", "NDD", /* 0xA0 */ +"NDE", "NDH", "NDL", "NDM", +"XRA", "XRB", "XRC", "XRD", +"XRE", "XRH", "XRL", "XRM", +"ORA", "ORB", "ORC", "ORD", /* 0xB0 */ +"ORE", "ORH", "ORL", "ORM", +"CPA", "CPB", "CPC", "CPD", +"CPE", "CPH", "CPL", "CPM", +"NOP", "LAB", "LAC", "LAD", /* 0xC0 */ +"LAE", "LAH", "LAL", "LAM", +"LBA", "LBB", "LBC", "LBD", +"LBE", "LBH ", "LBL", "LBM", +"LCA", "LCB", "LCC", "LCD", /* 0xD0 */ +"LCE", "LCH", "LCL", "LCM", +"LDA", "LDB", "LDC", "LDD", +"LDE", "LDH", "LDL", "LDM", +"LEA", "LEB", "LEC", "LED", /* 0xE0 */ +"LEE", "LEH", "LEL", "LEM", +"LHA", "LHB", "LHC", "LHD", +"LHE", "LHH", "LHL", "LHM", +"LLA", "LLB", "LLC", "LLD", /* 0xF0 */ +"LLE", "LLH", "LLL", "LLM", +"LMA", "LMB", "LMC", "LMD", +"LME", "LMH", "LML", "HLT", + }; + +int32 oplen[256] = { +/* + 0 1 2 3 4 5 6 7 8 9 A B C D E F */ + 1, 1, 1, 1, 2, 1, 2, 1, 1, 1, 1, 1, 2, 1, 2, 1, /* 0X */ + 1, 1, 1, 1, 2, 1, 2, 1, 1, 1, 1, 1, 2, 1, 2, 1, /* 1X */ + 1, 1, 0, 1, 2, 1, 2, 1, 1, 1, 1, 1, 2, 1, 2, 1, /* 2X */ + 1, 1, 0, 1, 2, 1, 2, 1, 0, 0, 0, 1, 2, 1, 2, 1, /* 3X */ + 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, /* 4X */ + 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, /* 5X */ + 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, /* 6X */ + 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, /* 7X */ + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 8X */ + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 9X */ + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* AX */ + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* BX */ + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* CX */ + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* DX */ + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* EX */ + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 /* FX */ +}; + +uint16 stack_frame[7]; /* processor stack frame */ + +void set_cpuint(int32 int_num) +{ + int_req |= int_num; +} + +/* instruction simulator */ +int32 sim_instr (void) +{ + extern int32 sim_interval; + uint32 IR, OP, DAR, reason, hi, lo, i, adr, val; + + PC = saved_PC & WORD_R14; /* load local PC */ + reason = 0; + + uptr = i8008_dev.units; + + /* Main instruction fetch/decode loop */ + + while (reason == 0) { /* loop until halted */ + +// if (PC == 0x1000) { /* turn on debugging */ +// i8008_dev.dctrl = DEBUG_asm + DEBUG_reg; +// reason = STOP_HALT; +// } + if (i8008_dev.dctrl & DEBUG_reg) { + dumpregs(); + printf("\n"); + } + + if (sim_interval <= 0) { /* check clock queue */ + if (reason = sim_process_event()) + break; + } + sim_interval--; /* countdown clock */ + + if (int_req > 0) { /* interrupt? */ +// printf("\ni8008: int_req=%04X", int_req); + ; + } else { /* 8008 */ + if (IE) { /* enabled? */ + push_word(PC); /* do an RST 7 */ + PC = 0x0038; + int_req &= ~INT_R; +// printf("\ni8008: int_req=%04X", int_req); + } + } /* end interrupt */ + + if (sim_brk_summ && + sim_brk_test (PC, SWMASK ('E'))) { /* breakpoint? */ + reason = STOP_IBKPT; /* stop simulation */ + break; + } + + PCX = PC; + + if (uptr->flags & UNIT_TRACE) { + dumpregs(); + printf("\n"); + } + IR = OP = fetch_byte(0); /* instruction fetch */ + + if (OP == 0x00 || OP == 0x01 || OP == 0xFF) { /* HLT Instruction*/ + reason = STOP_HALT; + PC--; + continue; + } + + /* The Big Instruction Decode Switch */ + + switch (IR) { + + case 0x02: /* RLC */ + if (A & 0x80) + CF = 1; + else + CF = 0; + A = (A << 1) & 0xFF; + if (CF) + A |= 0x01; + A &= BYTE_R; + break; + + case 0x03: /* RFC */ + if (CF) + ; + else + PC = pop_word(); + break; + + case 0x04: /* ADI */ + A += fetch_byte(1); + setflag3(A); + A &= BYTE_R; + break; + + case 0x05: /* RST 0 */ + case 0x0D: /* RST 1 */ + case 0x15: /* RST 2 */ + case 0x1D: /* RST 3 */ + case 0x25: /* RST 4 */ + case 0x2D: /* RST 5 */ + case 0x35: /* RST 6 */ + case 0x3D: /* RST 7 */ + val = fetch_byte(); + push_word(PC); + PC = val << 3; + break; + + case 0x06: /* LAI */ + A = fetch_byte(1); + A &= BYTE_R; + break; + + case 0x07: /* RET */ + PC = pop_word(); + break; + + case 0x08: /* INB */ + B++; + setflag3(B); + B &= BYTE_R; + break; + + case 0x09: /* DCB */ + B--; + setflag3(B); + B &= BYTE_R; + break; + + case 0x0A: /* RRC */ + if (A & 0x01) + CF = 1; + else + CF = 0; + A = (A >> 1) & 0xFF; + if (CF) + A |= 0x80; + A &= BYTE_R; + break; + + case 0x0B: /* RFZ */ + if (ZF) + ; + else + PC = pop_word(); + break; + + case 0x0C: /* ACI */ + A += fetch_byte(1); + if (CF) + A++; + setflag3(A); + A &= BYTE_R; + break; + + case 0x0E: /* LBI */ + B = fetch_byte(1); + B &= BYTE_R; + break; + + case 0x0F: /* *RET */ + PC = pop_word(); + break; + + case 0x10: /* INC */ + C++; + setflag3(C); + C &= BYTE_R; + break; + + case 0x11: /* DCC */ + C--; + setflag3(C); + C &= BYTE_R; + break; + + case 0x12: /* RAL */ + if (A & 0x80) + CF = 1; + else + CF = 0; + A = (A << 1) & 0xFF; + if (CF) + A |= 0x01; + A &= BYTE_R; + break; + + case 0x13: /* RFS */ + if (SF) + ; + else + PC = pop_word(); + break; + + case 0x14: /* SUI */ + A -= fetch_byte(1); + setflag3(A); + A &= BYTE_R; + break; + + case 0x16: /* LCI */ + C = fetch_byte(1); + C &= BYTE_R; + break; + + case 0x17: /* *RET */ + PC = pop_word(); + break; + + case 0x18: /* IND */ + D++; + setflag3(D); + D &= BYTE_R; + break; + + case 0x19: /* DCD */ + D--; + setflag3(D); + D &= BYTE_R; + break; + + case 0x1A: /* RAR */ + if (A & 0x01) + CF = 1; + else + CF = 0; + A = (A >> 1) & 0xFF; + if (CF) + A |= 0x80; + A &= BYTE_R; + break; + + case 0x1B: /* RFP */ + if (PF) + ; + else + PC = pop_word(); + break; + + case 0x1C: /* SBI */ + A -= fetch_byte(1); + if (CF) + A--; + setflag3(A); + A &= BYTE_R; + break; + + case 0x1E: /* LDI */ + D = fetch_byte(1); + D &= BYTE_R; + break; + + case 0x1F: /* *RET */ + PC = pop_word(); + break; + + case 0x20: /* INE */ + E++; + setflag3(E); + E &= BYTE_R; + break; + + case 0x21: /* DCE */ + E--; + setflag3(E); + E &= BYTE_R; + break; + + case 0x23: /* RTC */ + if (CF) + PC = pop_word(); + break; + + case 0x24: /* NDI */ + A &= fetch_byte(1); + setflag3(A); + A &= BYTE_R; + break; + + case 0x26: /* LEI */ + E = fetch_byte(1); + E &= BYTE_R; + break; + + case 0x27: /* *RET */ + PC = pop_word(); + break; + + case 0x28: /* INH */ + H++; + setflag3(H); + H &= BYTE_R; + break; + + case 0x29: /* DCH */ + H--; + setflag3(H); + H &= BYTE_R; + break; + + case 0x2B: /* RTZ */ + if (ZF) + PC = pop_word(); + break; + + case 0x2C: /* XRI */ + A ^= fetch_byte(1); + setflag3(A); + break; + + case 0x2E: /* LHI */ + H = fetch_byte(1); + H &= BYTE_R; + break; + + case 0x2F: /* *RET */ + PC = pop_word(); + break; + + case 0x30: /* INL */ + L++; + setflag3(L); + L &= BYTE_R; + break; + + case 0x31: /* DCL */ + L--; + setflag3(L); + L &= BYTE_R; + break; + + case 0x33: /* RTS */ + if (SF) + PC = pop_word(); + break; + + case 0x34: /* ORI */ + A |= fetch_byte(1); + setflag3(A); + A &= BYTE_R; + break; + + case 0x36: /* LLI */ + L = fetch_byte(1); + L &= BYTE_R; + break; + + case 0x37: /* *RET */ + PC = pop_word(); + break; + + case 0x3B: /* RTP */ + if (PF) + PC = pop_word(); + break; + + case 0x3C: /* CPI */ + DAR = A; + DAR -= fetch_byte(1); + setflag3(DAR); + break; + + case 0x3E: /* LMI */ + val = fetch_byte(1); + store_m(val); + break; + + case 0x3F: /* *RET */ + PC = pop_word(); + break; + + case 0x40: /* JFC */ + DAR = fetch_word(); + if (CF) + ; + else + PC = DAR; + break; + + case 0x41: /* INP 0 */ + case 0x43: /* INP 1 */ + case 0x45: /* INP 2 */ + case 0x47: /* INP 3 */ + case 0x49: /* INP 4 */ + case 0x4B: /* INP 5 */ + case 0x4D: /* INP 6 */ + case 0x4F: /* INP 7 */ + /**** fix me! */ + break; + + case 0x42: /* CFC */ + adr = fetch_word(); + if (CF) + ; + else { + push_word(PC); + PC = adr; + } + break; + + case 0x44: /* JMP */ + PC = fetch_word(); + break; + + case 0x46: /* CAL */ + adr = fetch_word(); + push_word(PC); + PC = adr; + break; + + case 0x48: /* JFZ */ + DAR = fetch_word(); + if (ZF) + ; + else + PC = DAR; + break; + + case 0x4A: /* CFZ */ + adr = fetch_word(); + if (ZF) + ; + else { + push_word(PC); + PC = adr; + } + break; + + case 0x4C: /* *JMP */ + PC = fetch_word(); + break; + + case 0x4E: /* *CAL */ + adr = fetch_word(); + push_word(PC); + PC = adr; + break; + + case 0x50: /* JFS */ + DAR = fetch_word(); + if (SF) + ; + else + PC = DAR; + break; + + case 0x51: /* OUT 8 */ + case 0x53: /* OUT 9 */ + case 0x55: /* OUT 10 */ + case 0x57: /* OUT 11 */ + case 0x59: /* OUT 12 */ + case 0x5B: /* OUT 13 */ + case 0x5D: /* OUT 14 */ + case 0x5E: /* OUT 15 */ + case 0x61: /* OUT 16 */ + case 0x63: /* OUT 17 */ + case 0x65: /* OUT 18 */ + case 0x67: /* OUT 19 */ + case 0x69: /* OUT 20 */ + case 0x6B: /* OUT 21 */ + case 0x6D: /* OUT 22 */ + case 0x6E: /* OUT 23 */ + case 0x71: /* OUT 24 */ + case 0x73: /* OUT 25 */ + case 0x75: /* OUT 26 */ + case 0x77: /* OUT 27 */ + case 0x79: /* OUT 28 */ + case 0x7B: /* OUT 29 */ + case 0x7D: /* OUT 30 */ + case 0x7E: /* OUT 31 */ + /**** fix me! */ + break; + + case 0x52: /* CFS */ + adr = fetch_word(); + if (SF) + ; + else { + push_word(PC); + PC = adr; + } + break; + + case 0x54: /* *JMP */ + PC = fetch_word(); + break; + + case 0x56: /* *CAL */ + adr = fetch_word(); + push_word(PC); + PC = adr; + break; + + case 0x58: /* JFP */ + DAR = fetch_word(); + if (PF) + ; + else + PC = DAR; + break; + + case 0x5A: /* CFP */ + adr = fetch_word(); + if (PF) + ; + else { + push_word(PC); + PC = adr; + } + break; + + case 0x5C: /* *JMP */ + PC = fetch_word(); + break; + + case 0x5E: /* *CAL */ + adr = fetch_word(); + push_word(PC); + PC = adr; + break; + + case 0x60: /* JTC */ + DAR = fetch_word(); + if (CF) + PC = DAR; + break; + + case 0x62: /* CTC */ + adr = fetch_word(); + if (CF) { + push_word(PC); + PC = adr; + } + break; + + case 0x64: /* *JMP */ + PC = fetch_word(); + break; + + case 0x66: /* *CAL */ + adr = fetch_word(); + push_word(PC); + PC = adr; + break; + + case 0x68: /* JTZ */ + DAR = fetch_word(); + if (ZF) + PC = DAR; + break; + + case 0x6A: /* CTZ */ + adr = fetch_word(); + if (ZF) { + push_word(PC); + PC = adr; + } + break; + + case 0x6C: /* *JMP */ + PC = fetch_word(); + break; + + case 0x6E: /* *CAL */ + adr = fetch_word(); + push_word(PC); + PC = adr; + break; + + case 0x70: /* JTS */ + DAR = fetch_word(); + if (SF) + PC = DAR; + break; + + case 0x72: /* CTS */ + adr = fetch_word(); + if (SF) { + push_word(PC); + PC = adr; + } + break; + + case 0x74: /* *JMP */ + PC = fetch_word(); + break; + + case 0x76: /* *CAL */ + adr = fetch_word(); + push_word(PC); + PC = adr; + break; + + case 0x78: /* JTP */ + DAR = fetch_word(); + if (PF) + PC = DAR; + break; + + case 0x7A: /* CTP */ + adr = fetch_word(); + if (PF) { + push_word(PC); + PC = adr; + } + break; + + case 0x7C: /* *JMP */ + PC = fetch_word(); + break; + + case 0x7E: /* *CAL */ + adr = fetch_word(); + push_word(PC); + PC = adr; + break; + + case 0x80: /* ADA */ + A += A; + setflag4(A); + A &= BYTE_R; + break; + + case 0x81: /* ADB */ + A += B; + setflag4(A); + A &= BYTE_R; + break; + + case 0x82: /* ADC */ + A += C; + setflag4(A); + A &= BYTE_R; + break; + + case 0x83: /* ADD */ + A += D; + setflag4(A); + A &= BYTE_R; + break; + + case 0x84: /* ADE */ + A += E; + setflag4(A); + A &= BYTE_R; + break; + + case 0x85: /* ADH */ + A += H; + setflag4(A); + A &= BYTE_R; + break; + + case 0x86: /* ADL */ + A += L; + setflag4(A); + A &= BYTE_R; + break; + + case 0x87: /* ADM */ + A += fetch_m(); + setflag4(A); + A &= BYTE_R; + break; + + case 0x88: /* ACA */ + A += A; + if (CF) + A++; + setflag4(A); + A &= BYTE_R; + break; + + case 0x89: /* ACB */ + A += B; + if (CF) + A++; + setflag4(A); + A &= BYTE_R; + break; + + case 0x8A: /* ACC */ + A += C; + if (CF) + A++; + setflag4(A); + A &= BYTE_R; + break; + + case 0x8B: /* ACD */ + A += D; + if (CF) + A++; + setflag4(A); + A &= BYTE_R; + break; + + case 0x8C: /* ACE */ + A += E; + if (CF) + A++; + setflag4(A); + A &= BYTE_R; + break; + + case 0x8D: /* ACH */ + A += H; + if (CF) + A++; + setflag4(A); + A &= BYTE_R; + break; + + case 0x8E: /* ACL */ + A += L; + if (CF) + A++; + setflag4(A); + A &= BYTE_R; + break; + + case 0x8F: /* ACM */ + A += fetch_m(); + if (CF) + A++; + setflag4(A); + A &= BYTE_R; + break; + + case 0x90: /* SUA */ + A -= A; + setflag4(A); + A &= BYTE_R; + break; + + case 0x91: /* SUB */ + A -= B; + setflag4(A); + A &= BYTE_R; + break; + + case 0x92: /* SUC */ + A -= C; + setflag4(A); + A &= BYTE_R; + break; + + case 0x93: /* SUD */ + A -= D; + setflag4(A); + A &= BYTE_R; + break; + + case 0x94: /* SUE */ + A -= E; + setflag4(A); + A &= BYTE_R; + break; + + case 0x95: /* SUH */ + A -= H; + setflag4(A); + A &= BYTE_R; + break; + + case 0x96: /* SUL */ + A -= L; + setflag4(A); + A &= BYTE_R; + break; + + case 0x97: /* SUM */ + A -= fetch_m(); + setflag4(A); + A &= BYTE_R; + break; + + case 0x98: /* SBA */ + A -= A; + if (CF) + A--; + setflag4(A); + A &= BYTE_R; + break; + + case 0x99: /* SBB */ + A -= B; + if (CF) + A--; + setflag4(A); + A &= BYTE_R; + break; + + case 0x9A: /* SBC */ + A -= C; + if (CF) + A--; + setflag4(A); + A &= BYTE_R; + break; + + case 0x9B: /* SBD */ + A -= D; + if (CF) + A--; + setflag4(A); + A &= BYTE_R; + break; + + case 0x9C: /* SBE */ + A -= E; + if (CF) + A--; + setflag4(A); + A &= BYTE_R; + break; + + case 0x9D: /* SBH */ + A -= H; + if (CF) + A--; + setflag4(A); + A &= BYTE_R; + break; + + case 0x9E: /* SBL */ + A -= L; + if (CF) + A--; + setflag4(A); + A &= BYTE_R; + break; + + case 0x9F: /* SBM */ + A -= fetch_m(); + if (CF) + A - ; + setflag4(A); + A &= BYTE_R; + break; + + case 0xA0: /* NDA */ + A &= A; + setflag4(A); + A &= BYTE_R; + break; + + case 0xA1: /* NDB */ + A &= B; + setflag4(A); + A &= BYTE_R; + break; + + case 0xA2: /* NDC */ + A &= C; + setflag4(A); + A &= BYTE_R; + break; + + case 0xA3: /* NDD */ + A &= D; + setflag4(A); + A &= BYTE_R; + break; + + case 0xA4: /* NDE */ + A &= E; + setflag4(A); + A &= BYTE_R; + break; + + case 0xA5: /* NDH */ + A &= H; + setflag4(A); + A &= BYTE_R; + break; + + case 0xA6: /* NDL */ + A &= L; + setflag4(A); + A &= BYTE_R; + break; + + case 0xA7: /* NDM */ + A &= fetch_m(); + setflag4(A); + A &= BYTE_R; + break; + + case 0xA8: /* XRA */ + A ^= A; + setflag4(A); + A &= BYTE_R; + break; + + case 0xA9: /* XRB */ + A ^= B; + setflag4(A); + A &= BYTE_R; + break; + + case 0xAA: /* XRC */ + A ^= C; + setflag4(A); + A &= BYTE_R; + break; + + case 0xAB: /* XRD */ + A ^= D; + setflag4(A); + A &= BYTE_R; + break; + + case 0xAC: /* XRE */ + A ^= E; + setflag4(A); + A &= BYTE_R; + break; + + case 0xAD: /* XRH */ + A ^= H; + setflag4(A); + A &= BYTE_R; + break; + + case 0xAE: /* XRL */ + A ^= L; + setflag4(A); + A &= BYTE_R; + break; + + case 0xAF: /* XRM */ + A |= fetch_m(); + setflag4(A); + A &= BYTE_R; + break; + + case 0xB0: /* ORA */ + A |= A; + setflag4(A); + A &= BYTE_R; + break; + + case 0xB1: /* ORB */ + A |= B; + setflag4(A); + A &= BYTE_R; + break; + + case 0xB2: /* ORC */ + A |= C; + setflag4(A); + A &= BYTE_R; + break; + + case 0xB3: /* ORD */ + A |= D; + setflag4(A); + A &= BYTE_R; + break; + + case 0xB4: /* ORE */ + A |= E; + setflag4(A); + A &= BYTE_R; + break; + + case 0xB5: /* ORH */ + A |= H; + setflag4(A); + A &= BYTE_R; + break; + + case 0xB6: /* ORL */ + A |= L; + setflag4(A); + A &= BYTE_R; + break; + + case 0xB7: /* ORM */ + A |= fetch_m(); + setflag4(A); + A &= BYTE_R; + break; + + case 0xB8: /* CPA */ + DAR -= A; + setflag4(DAR); + A &= BYTE_R; + break; + + case 0xB9: /* CPB */ + DAR -= B; + setflag4(DAR); + A &= BYTE_R; + break; + + case 0xBA: /* CPC */ + DAR -= C; + setflag4(DAR); + A &= BYTE_R; + break; + + case 0xBB: /* CPD */ + DAR -= D; + setflag4(DAR); + A &= BYTE_R; + break; + + case 0xBC: /* CPE */ + DAR -= E; + setflag4(DAR); + A &= BYTE_R; + break; + + case 0xBD: /* CPH */ + DAR -= H; + setflag4(DAR); + A &= BYTE_R; + break; + + case 0xBE: /* CPL */ + DAR -= L; + setflag4(DAR); + A &= BYTE_R; + break; + + case 0xBF: /* CPM */ + DAR -= fetch_m(); + setflag4(DAR); + A &= BYTE_R; + break; + + case 0xC0: /* NOP */ + break; + + case 0xC1: /* LAB */ + A = B; + A &= BYTE_R; + break; + + case 0xC2: /* LAC */ + A = C; + A &= BYTE_R; + break; + + case 0xC3: /* LAD */ + A = D; + A &= BYTE_R; + break; + + case 0xC4: /* LAE */ + A = E; + A &= BYTE_R; + break; + + case 0xC5: /* LAH */ + A = H; + A &= BYTE_R; + break; + + case 0xC6: /* LAL */ + A = L; + A &= BYTE_R; + break; + + case 0xC7: /* LAM */ + A = FETCH_M(); + A &= BYTE_R; + break; + + case 0xC8: /* LBA */ + B = A; + B &= BYTE_R; + break; + + case 0xC9: /* LBB */ + B = B; + B &= BYTE_R; + break; + + case 0xCA: /* LBC */ + B = C; + B &= BYTE_R; + break; + + case 0xCB: /* LBD */ + B = D; + B &= BYTE_R; + break; + + case 0xCC: /* LBE */ + B = E; + B &= BYTE_R; + break; + + case 0xCD: /* LBH */ + B = H; + B &= BYTE_R; + break; + + case 0xCE: /* LBL */ + B = L; + B &= BYTE_R; + break; + + case 0xCF: /* LBM */ + B = FETCH_M(); + B &= BYTE_R; + break; + + case 0xD0: /* LCA */ + C = A; + C &= BYTE_R; + break; + + case 0xD1: /* LCB */ + C = B; + C &= BYTE_R; + break; + + case 0xD2: /* LCC */ + C = C; + C &= BYTE_R; + break; + + case 0xD3: /* LCD */ + C = D; + C &= BYTE_R; + break; + + case 0xD4: /* LCE */ + C = E; + C &= BYTE_R; + break; + + case 0xD5: /* LCH */ + C = H; + C &= BYTE_R; + break; + + case 0xD6: /* LCL */ + C = L; + C &= BYTE_R; + break; + + case 0xD7: /* LCM */ + C = FETCH_M(); + C &= BYTE_R; + break; + + case 0xD8: /* LDA */ + D = A; + D &= BYTE_R; + break; + + case 0xD9: /* LDB */ + D = B; + D &= BYTE_R; + break; + + case 0xDA: /* LDC */ + D = C; + D &= BYTE_R; + break; + + case 0xDB: /* LDD */ + D = D; + D &= BYTE_R; + break; + + case 0xDC: /* LDE */ + D = E; + D &= BYTE_R; + break; + + case 0xDD: /* LDH */ + D = H; + D &= BYTE_R; + break; + + case 0xDE: /* LDL */ + D = L; + D &= BYTE_R; + break; + + case 0xDF: /* LDM */ + D = FETCH_M(); + D &= BYTE_R; + break; + + case 0xE0: /* LEA */ + E = A; + E &= BYTE_R; + break; + + case 0xE1: /* LEB */ + E = B; + E &= BYTE_R; + break; + + case 0xE2: /* LEC */ + E = C; + E &= BYTE_R; + break; + + case 0xE3: /* LED */ + E = D; + E &= BYTE_R; + break; + + case 0xE4: /* LEE */ + E = E; + E &= BYTE_R; + break; + + case 0xE5: /* LEH */ + E = H; + E &= BYTE_R; + break; + + case 0xE6: /* LEL */ + E = L; + E &= BYTE_R; + break; + + case 0xE7: /* LEM */ + E = FETCH_M(); + E &= BYTE_R; + break; + + case 0xE8: /* LHA */ + H = A; + H &= BYTE_R; + break; + + case 0xE9: /* LHB */ + H = B; + H &= BYTE_R; + break; + + case 0xEA: /* LHC */ + H = C; + H &= BYTE_R; + break; + + case 0xEB: /* LHD */ + H = D; + H &= BYTE_R; + break; + + case 0xEC: /* LHE */ + H = E; + H &= BYTE_R; + break; + + case 0xED: /* LHH */ + H = H; + H &= BYTE_R; + break; + + case 0xEE: /* LHL */ + H = L; + H &= BYTE_R; + break; + + case 0xEF: /* LHM */ + H = FETCH_M(); + H &= BYTE_R; + break; + + case 0xF0: /* LLA */ + L = A; + L &= BYTE_R; + break; + + case 0xF1: /* LLB */ + L = B; + L &= BYTE_R; + break; + + case 0xF2: /* LLC */ + L = C; + L &= BYTE_R; + break; + + case 0xF3: /* LLD */ + L = D; + L &= BYTE_R; + break; + + case 0xF4: /* LLE */ + L = E; + L &= BYTE_R; + break; + + case 0xF5: /* LLH */ + L = H; + L &= BYTE_R; + break; + + case 0xF6: /* LLL */ + L = L; + L &= BYTE_R; + break; + + case 0xF7: /* LLM */ + L = FETCH_M(); + L &= BYTE_R; + break; + + case 0xF8: /* LMA */ + store_m(A); + break; + + case 0xF9: /* LMB */ + store_m(B); + break; + + case 0xFA: /* LMC */ + store_m(C); + break; + + case 0xFB: /* LMD */ + store_m(D); + break; + + case 0xFC: /* LME */ + store_m(E); + break; + + case 0xFD: /* LMH */ + store_m(H); + break; + + case 0xFE: /* LML */ + store_m(L); + break; + + case 0xFF: /* LMM */ + val = FETCH_M(); + store_m(val); + break; + + default: /* undefined opcode */ + if (i8008_unit.flags & UNIT_OPSTOP) { + reason = STOP_OPCODE; + PC--; + } + break; + } + } + +/* Simulation halted */ + + saved_PC = PC; + return reason; +} + +/* store byte to (HL) */ +void store_m(uint32 val) +{ + DAR = (H << 8) + L; + DAR &= WORD_R14; + ret get_mword(DAR); +} + +/* get byte from (HL) */ +uint32 fetch_m(void) +{ + DAR = (H << 8) + L; + DAR &= WORD_R14; + put_mword(DAR, val); +} + +/* dump the registers */ +void dumpregs(void) +{ + printf(" A=%02X B=%02X C=%02X D=%04X E=%02X H=%04X L=%02X\n", + A, B, C, D, E, H, L); + printf(" CF=%d ZF=%d SF=%d PF=%d\n", + CF, ZF, SF, PF); +} + +/* fetch an instruction or byte */ +int32 fetch_byte(int32 flag) +{ + uint32 val; + + val = get_mbyte(PC) & 0xFF; /* fetch byte */ + if (i8008_dev.dctrl & DEBUG_asm || uptr->flags & UNIT_TRACE) { /* display source code */ + switch (flag) { + case 0: /* opcode fetch */ + printf("OP=%02X %04X %s", val, PC, opcode[val]); + break; + case 1: /* byte operand fetch */ + printf("0%02XH", val); + break; + } + } + PC = (PC + 1) & ADDRMASK; /* increment PC */ + val &= BYTE_R; + return val; +} + +/* fetch a word */ +int32 fetch_word(void) +{ + uint16 val; + + val = get_mbyte(PC) & BYTE_R; /* fetch low byte */ + val |= get_mbyte(PC + 1) << 8; /* fetch high byte */ + if (i8008_dev.dctrl & DEBUG_asm || uptr->flags & UNIT_TRACE) /* display source code */ + printf("0%04XH", val); + PC = (PC + 2) & ADDRMASK; /* increment PC */ + val &= WORD_R14; + return val; +} + +/* push a word to the stack frame */ +void push_word(uint16 val) +{ + stack_frame[SP] = val; + SP++; + if (SP == 8) + SP = 0; +} + +/* pop a word from the stack frame */ +uint16 pop_word(void) +{ + SP--; + if (SP < 0) + SP = 7; + return stack_frame[SP]; +} + + +/* Set the arry, ign, ero and verflow flags following + an operation on 'reg'. +*/ + +void setflag4(int32 reg) +{ + if (reg & 0x100) + CF = 1; + else + CF = 0; + if (reg & 0x80) + SF = 0; + else + SF = 1; + if ((reg & BYTE_R) == 0) + ZF = 1; + else + ZF = 0; + parity(reg); +} + +/* Set the arry, ign and ero flags following + an operation on 'reg'. +*/ + +void setflag3(int32 reg) +{ + CF = 0; + if (reg & 0x80) + SF = 0; + else + SF = 1; + if ((reg & BYTE_R) == 0) + ZF = 1; + else + ZF = 0; + parity(reg); +} + +/* Set the Parity (PF) flag based on parity of 'reg', i.e., number +of bits on even: PF=1, else PF=0 +*/ + +void parity(int32 reg) +{ + int32 bc = 0; + + if (reg & 0x01) bc++; + if (reg & 0x02) bc++; + if (reg & 0x04) bc++; + if (reg & 0x08) bc++; + if (reg & 0x10) bc++; + if (reg & 0x20) bc++; + if (reg & 0x40) bc++; + if (reg & 0x80) bc++; + if (bc & 0x01) + PF = 0; + else + PF = 1; +} + + + +/* Reset routine */ + +t_stat i8008_reset (DEVICE *dptr) +{ + int i; + + CF = SF = ZF = PF = 0; + saved_PC = 0; + int_req = 0; + for (i = 0; i < 7; i++) + stack_frame[i] = 0; + sim_brk_types = sim_brk_dflt = SWMASK ('E'); + printf(" 8008: Reset\n"); + return SCPE_OK; +} + +/* Memory examine */ + +t_stat i8008_ex (t_value *vptr, t_addr addr, UNIT *uptr, int32 sw) +{ + if (addr >= MEMSIZE) + return SCPE_NXM; + if (vptr != NULL) + *vptr = get_mbyte(addr); + return SCPE_OK; +} + +/* Memory deposit */ + +t_stat i8008_dep (t_value val, t_addr addr, UNIT *uptr, int32 sw) +{ + if (addr >= MEMSIZE) + return SCPE_NXM; + put_mbyte(addr, val); + return SCPE_OK; +} + +/* This is the binary loader. The input file is considered to be + a string of literal bytes with no special format. The load + starts at the current value of the PC. +*/ + +int32 sim_load (FILE *fileref, char *cptr, char *fnam, int flag) +{ + int32 i, addr = 0, cnt = 0; + + if ((*cptr != 0) || (flag != 0)) return SCPE_ARG; + addr = saved_PC; + while ((i = getc (fileref)) != EOF) { + put_mbyte(addr, i); + addr++; + cnt++; + } /* end while */ + printf ("%d Bytes loaded.\n", cnt); + return (SCPE_OK); +} + +/* Symbolic output + + Inputs: + *of = output stream + addr = current PC + *val = pointer to values + *uptr = pointer to unit + sw = switches + Outputs: + status = error code +*/ + +t_stat fprint_sym (FILE *of, t_addr addr, t_value *val, + UNIT *uptr, int32 sw) +{ + int32 cflag, c1, c2, inst, adr; + + cflag = (uptr == NULL) || (uptr == &i8008_unit); + c1 = (val[0] >> 8) & 0x7F; + c2 = val[0] & 0x7F; + if (sw & SWMASK ('A')) { + fprintf (of, (c2 < 0x20)? "<%02X>": "%c", c2); + return SCPE_OK; + } + if (sw & SWMASK ('C')) { + fprintf (of, (c1 < 0x20)? "<%02X>": "%c", c1); + fprintf (of, (c2 < 0x20)? "<%02X>": "%c", c2); + return SCPE_OK; + } + if (!(sw & SWMASK ('M'))) return SCPE_ARG; + inst = val[0]; + fprintf (of, "%s", opcode[inst]); + if (oplen[inst] == 2) { + if (strchr(opcode[inst], ' ') != NULL) + fprintf (of, ","); + else fprintf (of, " "); + fprintf (of, "%h", val[1]); + } + if (oplen[inst] == 3) { + adr = val[1] & 0xFF; + adr |= (val[2] << 8) & 0xff00; + if (strchr(opcode[inst], ' ') != NULL) + fprintf (of, ","); + else fprintf (of, " "); + fprintf (of, "%h", adr); + } + return -(oplen[inst] - 1); +} + +/* Symbolic input + + Inputs: + *cptr = pointer to input string + addr = current PC + *uptr = pointer to unit + *val = pointer to output values + sw = switches + Outputs: + status = error status +*/ + +t_stat parse_sym (char *cptr, t_addr addr, UNIT *uptr, t_value *val, int32 sw) +{ + int32 cflag, i = 0, j, r; + char gbuf[CBUFSIZE]; + + cflag = (uptr == NULL) || (uptr == &i8008_unit); + while (isspace (*cptr)) cptr++; /* absorb spaces */ + if ((sw & SWMASK ('A')) || ((*cptr == '\'') && cptr++)) { /* ASCII char? */ + if (cptr[0] == 0) return SCPE_ARG; /* must have 1 char */ + val[0] = (uint32) cptr[0]; + return SCPE_OK; + } + if ((sw & SWMASK ('C')) || ((*cptr == '"') && cptr++)) { /* ASCII string? */ + if (cptr[0] == 0) return SCPE_ARG; /* must have 1 char */ + val[0] = ((uint32) cptr[0] << 8) + (uint32) cptr[1]; + return SCPE_OK; + } + +/* An instruction: get opcode (all characters until null, comma, + or numeric (including spaces). +*/ + + while (1) { + if (*cptr == ',' || *cptr == '\0' || + isdigit(*cptr)) + break; + gbuf[i] = toupper(*cptr); + cptr++; + i++; + } + +/* Allow for RST which has numeric as part of opcode */ + + if (toupper(gbuf[0]) == 'R' && + toupper(gbuf[1]) == 'S' && + toupper(gbuf[2]) == 'T') { + gbuf[i] = toupper(*cptr); + cptr++; + i++; + } + +/* kill trailing spaces if any */ + gbuf[i] = '\0'; + for (j = i - 1; gbuf[j] == ' '; j--) { + gbuf[j] = '\0'; + } + +/* find opcode in table */ + for (j = 0; j < 256; j++) { + if (strcmp(gbuf, opcode[j]) == 0) + break; + } + if (j > 255) /* not found */ + return SCPE_ARG; + + val[0] = j; /* store opcode */ + if (oplen[j] < 2) /* if 1-byter we are done */ + return SCPE_OK; + if (*cptr == ',') cptr++; + cptr = get_glyph(cptr, gbuf, 0); /* get address */ + sscanf(gbuf, "%o", &r); + if (oplen[j] == 2) { + val[1] = r & 0xFF; + return (-1); + } + val[1] = r & 0xFF; + val[2] = (r >> 8) & 0xFF; + return (-2); +} diff --git a/MDS-800/common/i8080.c b/MDS-800/common/i8080.c new file mode 100644 index 00000000..890fbc6a --- /dev/null +++ b/MDS-800/common/i8080.c @@ -0,0 +1,1438 @@ +/* i8080.c: Intel 8080/8085 CPU simulator + + Copyright (c) 1997-2005, Charles E. Owen + + Permission is hereby granted, free of charge, to any person obtaining a + copy of this software and associated documentation files (the "Software"), + to deal in the Software without restriction, including without limitation + the rights to use, copy, modify, merge, publish, distribute, sublicense, + and/or sell copies of the Software, and to permit persons to whom the + Software is furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + CHARLES E. OWEN BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + Except as contained in this notice, the name of Charles E. Owen shall not be + used in advertising or otherwise to promote the sale, use or other dealings + in this Software without prior written authorization from Charles E. Owen. + + This software was modified by Bill Beech, Nov 2010, to allow emulation of Intel + iSBC Single Board Computers. + + Copyright (c) 2011, William A. Beech + + Permission is hereby granted, free of charge, to any person obtaining a + copy of this software and associated documentation files (the "Software"), + to deal in the Software without restriction, including without limitation + the rights to use, copy, modify, merge, publish, distribute, sublicense, + and/or sell copies of the Software, and to permit persons to whom the + Software is furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + WILLIAM A. BEECH BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + Except as contained in this notice, the name of William A. Beech shall not be + used in advertising or otherwise to promote the sale, use or other dealings + in this Software without prior written authorization from William A. Beech. + + cpu 8080 CPU + + 08 Oct 02 RMS Tied off spurious compiler warnings + 23 Nov 10 WAB Modified for iSBC emulation + 04 Dec 12 WAB Added 8080 interrupts + 14 Dec 12 WAB Added 8085 interrupts + + The register state for the 8080 CPU is: + + A<0:7> Accumulator + BC<0:15> BC Register Pair + DE<0:15> DE Register Pair + HL<0:15> HL Register Pair + PSW<0:7> Program Status Word (Flags) + PC<0:15> Program counter + SP<0:15> Stack Pointer + + The 8080 is an 8-bit CPU, which uses 16-bit registers to address + up to 64KB of memory. + + The 78 basic instructions come in 1, 2, and 3-byte flavors. + + This routine is the instruction decode routine for the 8080. + It is called from the simulator control program to execute + instructions in simulated memory, starting at the simulated PC. + It runs until 'reason' is set non-zero. + + General notes: + + 1. Reasons to stop. The simulator can be stopped by: + + HALT instruction + I/O error in I/O simulator + Invalid OP code (if ITRAP is set on CPU) + + 2. Interrupts. + There are 8 possible levels of interrupt, and in effect they + do a hardware CALL instruction to one of 8 possible low + memory addresses. + + 3. Non-existent memory. On the 8080, reads to non-existent memory + return 0FFh, 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: + + altair_cpu.c add I/O service routines to dev_table + altair_sys.c add pointer to data structures in sim_devices + + ?? ??? 11 - Original file. + 16 Dec 12 - Modified to use isbc_80_10.cfg file to set base and size. + 20 Dec 12 - Modified for basic interrupt function. + 03 Mar 13 - Added trace function. + 04 Mar 13 - Modified all instructions to truncate the affected register + at the end of the routine. + 17 Mar 13 - Modified to enable/disable trace based on start and stop + addresses. + +*/ + +#include "system_defs.h" + +#define UNIT_V_OPSTOP (UNIT_V_UF) /* Stop on Invalid OP? */ +#define UNIT_OPSTOP (1 << UNIT_V_OPSTOP) +#define UNIT_V_8085 (UNIT_V_UF+1) /* 8080/8085 switch */ +#define UNIT_8085 (1 << UNIT_V_8085) +#define UNIT_V_TRACE (UNIT_V_UF+2) /* Trace switch */ +#define UNIT_TRACE (1 << UNIT_V_TRACE) + +/* Flag values to set proper positions in PSW */ +#define CF 0x01 +#define PF 0x04 +#define AF 0x10 +#define ZF 0x40 +#define SF 0x80 + +/* Macros to handle the flags in the PSW + 8080 has bit #1 always set. This is (not well) documented behavior. */ +#define PSW_ALWAYS_ON (0x02) /* for 8080 */ +#define PSW_MSK (CF|PF|AF|ZF|SF) +#define TOGGLE_FLAG(FLAG) (PSW ^= FLAG) +#define SET_FLAG(FLAG) (PSW |= FLAG) +#define CLR_FLAG(FLAG) (PSW &= ~FLAG) +#define GET_FLAG(FLAG) (PSW & FLAG) +#define COND_SET_FLAG(COND,FLAG) \ + if (COND) SET_FLAG(FLAG); else CLR_FLAG(FLAG) + +#define SET_XACK(VAL) (xack = VAL) +#define GET_XACK(FLAG) (xack &= FLAG) + +/* values for IM bits */ +#define ITRAP 0x100 +#define SID 0x80 +#define SOD 0x80 +#define SDE 0x40 +#define R75 0x10 +#define IE 0x08 +#define MSE 0x08 +#define M75 0x04 +#define M65 0x02 +#define M55 0x01 + +/* register masks */ +#define BYTE_R 0xFF +#define WORD_R 0xFFFF + +/* storage for the rest of the registers */ +uint32 PSW = 0; /* program status word */ +uint32 A = 0; /* accumulator */ +uint32 BC = 0; /* BC register pair */ +uint32 DE = 0; /* DE register pair */ +uint32 HL = 0; /* HL register pair */ +uint32 SP = 0; /* Stack pointer */ +uint32 saved_PC = 0; /* program counter */ +uint32 IM = 0; /* Interrupt Mask Register */ +uint32 xack = 0; /* XACK signal */ +uint32 int_req = 0; /* Interrupt request */ + +int32 PCX; /* External view of PC */ +int32 PC; +UNIT *uptr; + +/* function prototypes */ +void set_cpuint(int32 int_num); +void dumpregs(void); +int32 fetch_byte(int32 flag); +int32 fetch_word(void); +uint16 pop_word(void); +void push_word(uint16 val); +void setarith(int32 reg); +void setlogical(int32 reg); +void setinc(int32 reg); +int32 getreg(int32 reg); +void putreg(int32 reg, int32 val); +int32 getpair(int32 reg); +int32 getpush(int32 reg); +void putpush(int32 reg, int32 data); +void putpair(int32 reg, int32 val); +void parity(int32 reg); +int32 cond(int32 con); +t_stat i8080_ex (t_value *vptr, t_addr addr, UNIT *uptr, int32 sw); +t_stat i8080_dep (t_value val, t_addr addr, UNIT *uptr, int32 sw); +t_stat i8080_reset (DEVICE *dptr); + +/* external function prototypes */ + +extern t_stat i8080_reset (DEVICE *dptr); +extern int32 get_mbyte(int32 addr); +extern int32 get_mword(int32 addr); +extern void put_mbyte(int32 addr, int32 val); +extern void put_mword(int32 addr, int32 val); +extern int32 sim_int_char; +extern uint32 sim_brk_types, sim_brk_dflt, sim_brk_summ; /* breakpoint info */ + + +struct idev { + int32 (*routine)(); +}; + +/* This is the I/O configuration table. There are 256 possible +device addresses, if a device is plugged to a port it's routine +address is here, 'nulldev' means no device is available +*/ + +extern struct idev dev_table[]; + +/* CPU data structures + + i8080_dev CPU device descriptor + i8080_unit CPU unit descriptor + i8080_reg CPU register list + i8080_mod CPU modifiers list +*/ + +UNIT i8080_unit = { UDATA (NULL, 0, 65535) }; /* default 8080 */ + +REG i8080_reg[] = { + { HRDATA (PC, saved_PC, 16) }, /* must be first for sim_PC */ + { HRDATA (PSW, PSW, 8) }, + { HRDATA (A, A, 8) }, + { HRDATA (BC, BC, 16) }, + { HRDATA (DE, DE, 16) }, + { HRDATA (HL, HL, 16) }, + { HRDATA (SP, SP, 16) }, + { HRDATA (IM, IM, 8) }, + { HRDATA (XACK, xack, 8) }, + { HRDATA (INTR, int_req, 32) }, + { HRDATA (WRU, sim_int_char, 8) }, + { NULL } +}; + +MTAB i8080_mod[] = { + { UNIT_8085, 0, "8080", "8080", NULL }, + { UNIT_8085, UNIT_8085, "8085", "8085", NULL }, + { UNIT_OPSTOP, 0, "ITRAP", "ITRAP", NULL }, + { UNIT_OPSTOP, UNIT_OPSTOP, "NOITRAP", "NOITRAP", NULL }, + { UNIT_TRACE, 0, "NOTRACE", "NOTRACE", NULL }, + { UNIT_TRACE, UNIT_TRACE, "TRACE", "TRACE", NULL }, + { 0 } +}; + +DEBTAB i8080_debug[] = { + { "ALL", DEBUG_all }, + { "FLOW", DEBUG_flow }, + { "READ", DEBUG_read }, + { "WRITE", DEBUG_write }, + { "LEV1", DEBUG_level1 }, + { "LEV2", DEBUG_level2 }, + { "REG", DEBUG_reg }, + { "ASM", DEBUG_asm }, + { NULL } +}; + +DEVICE i8080_dev = { + "CPU", //name + &i8080_unit, //units + i8080_reg, //registers + i8080_mod, //modifiers + 1, //numunits + 16, //aradix + 16, //awidth + 1, //aincr + 16, //dradix + 8, //dwidth + &i8080_ex, //examine + &i8080_dep, //deposit +// &i8080_reset, //reset + NULL, //reset + NULL, //boot + NULL, //attach + NULL, //detach + NULL, //ctxt + DEV_DEBUG, //flags + 0, //dctrl + i8080_debug, //debflags + NULL, //msize + NULL //lname +}; + +/* tables for the disassembler */ +char *opcode[] = { +"NOP", "LXI B,", "STAX B", "INX B", /* 0x00 */ +"INR B", "DCR B", "MVI B,", "RLC", +"???", "DAD B", "LDAX B", "DCX B", +"INR C", "DCR C", "MVI C,", "RRC", +"???", "LXI D,", "STAX D", "INX D", /* 0x10 */ +"INR D", "DCR D", "MVI D,", "RAL", +"???", "DAD D", "LDAX D", "DCX D", +"INR E", "DCR E", "MVI E,", "RAR", +"RIM", "LXI H,", "SHLD ", "INX H", /* 0x20 */ +"INR H", "DCR H", "MVI H,", "DAA", +"???", "DAD H", "LHLD ", "DCX H", +"INR L", "DCR L", "MVI L", "CMA", +"SIM", "LXI SP,", "STA ", "INX SP", /* 0x30 */ +"INR M", "DCR M", "MVI M,", "STC", +"???", "DAD SP", "LDA ", "DCX SP", +"INR A", "DCR A", "MVI A,", "CMC", +"MOV B,B", "MOV B,C", "MOV B,D", "MOV B,E", /* 0x40 */ +"MOV B,H", "MOV B,L", "MOV B,M", "MOV B,A", +"MOV C,B", "MOV C,C", "MOV C,D", "MOV C,E", +"MOV C,H", "MOV C,L", "MOV C,M", "MOV C,A", +"MOV D,B", "MOV D,C", "MOV D,D", "MOV D,E", /* 0x50 */ +"MOV D,H", "MOV D,L", "MOV D,M", "MOV D,A", +"MOV E,B", "MOV E,C", "MOV E,D", "MOV E,E", +"MOV E,H", "MOV E,L", "MOV E,M", "MOV E,A", +"MOV H,B", "MOV H,C", "MOV H,D", "MOV H,E", /* 0x60 */ +"MOV H,H", "MOV H,L", "MOV H,M", "MOV H,A", +"MOV L,B", "MOV L,C", "MOV L,D", "MOV L,E", +"MOV L,H", "MOV L,L", "MOV L,M", "MOV L,A", +"MOV M,B", "MOV M,C", "MOV M,D", "MOV M,E", /* 0x70 */ +"MOV M,H", "MOV M,L", "HLT", "MOV M,A", +"MOV A,B", "MOV A,C", "MOV A,D", "MOV A,E", +"MOV A,H", "MOV A,L", "MOV A,M", "MOV A,A", +"ADD B", "ADD C", "ADD D", "ADD E", /* 0x80 */ +"ADD H", "ADD L", "ADD M", "ADD A", +"ADC B", "ADC C", "ADC D", "ADC E", +"ADC H", "ADC L", "ADC M", "ADC A", +"SUB B", "SUB C", "SUB D", "SUB E", /* 0x90 */ +"SUB H", "SUB L", "SUB M", "SUB A", +"SBB B", "SBB C", "SBB D", "SBB E", +"SBB H", "SBB L", "SBB M", "SBB A", +"ANA B", "ANA C", "ANA D", "ANA E", /* 0xA0 */ +"ANA H", "ANA L", "ANA M", "ANA A", +"XRA B", "XRA C", "XRA D", "XRA E", +"XRA H", "XRA L", "XRA M", "XRA A", +"ORA B", "ORA C", "ORA D", "ORA E", /* 0xB0 */ +"ORA H", "ORA L", "ORA M", "ORA A", +"CMP B", "CMP C", "CMP D", "CMP E", +"CMP H", "CMP L", "CMP M", "CMP A", +"RNZ", "POP B", "JNZ ", "JMP ", /* 0xC0 */ +"CNZ ", "PUSH B", "ADI ", "RST 0", +"RZ", "RET", "JZ ", "???", +"CZ ", "CALL ", "ACI ", "RST 1", +"RNC", "POP D", "JNC ", "OUT ", /* 0xD0 */ +"CNC ", "PUSH D", "SUI ", "RST 2", +"RC", "???", "JC ", "IN ", +"CC ", "???", "SBI ", "RST 3", +"RPO", "POP H", "JPO ", "XTHL", /* 0xE0 */ +"CPO ", "PUSH H", "ANI ", "RST 4", +"RPE", "PCHL", "JPE ", "XCHG", +"CPE ", "???", "XRI ", "RST 5", +"RP", "POP PSW", "JP ", "DI", /* 0xF0 */ +"CP ", "PUSH PSW", "ORI ", "RST 6", +"RM", "SPHL", "JM ", "EI", +"CM ", "???", "CPI ", "RST 7", + }; + +int32 oplen[256] = { +1,3,1,1,1,1,2,1,0,1,1,1,1,1,2,1, +0,3,1,1,1,1,2,1,0,1,1,1,1,1,2,1, +1,3,3,1,1,1,2,1,0,1,3,1,1,1,2,1, +1,3,3,1,1,1,2,1,0,1,3,1,1,1,2,1, +1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, +1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, +1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, +1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, +1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, +1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, +1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, +1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, +1,1,3,3,3,1,2,1,1,1,3,0,3,3,2,1, +1,1,3,2,3,1,2,1,1,0,3,2,3,0,2,1, +1,1,3,1,3,1,2,1,1,1,3,1,3,0,2,1, +1,1,3,1,3,1,2,1,1,1,3,1,3,0,2,1 }; + +void set_cpuint(int32 int_num) +{ + int_req |= int_num; +} + +//FILE *fpd; + +/* instruction simulator */ +int32 sim_instr (void) +{ + extern int32 sim_interval; + uint32 IR, OP, DAR, reason, hi, lo, i, adr; + + PC = saved_PC & WORD_R; /* load local PC */ + reason = 0; + + uptr = i8080_dev.units; + if (i8080_dev.dctrl & DEBUG_flow) { + if (uptr->flags & UNIT_8085) + printf("CPU = 8085\n"); + else + printf("CPU = 8080\n"); + } + /* Main instruction fetch/decode loop */ + + while (reason == 0) { /* loop until halted */ + +// if (PC == 0x1000) { /* turn on debugging */ +// i8080_dev.dctrl = DEBUG_asm + DEBUG_reg; +// reason = STOP_HALT; +// } + if (i8080_dev.dctrl & DEBUG_reg) { + dumpregs(); + printf("\n"); + } + + if (sim_interval <= 0) { /* check clock queue */ + if (reason = sim_process_event()) + break; + } + sim_interval--; /* countdown clock */ + + if (int_req > 0) { /* interrupt? */ +// printf("\ni8080: int_req=%04X IM=%04X", int_req, IM); + if (uptr->flags & UNIT_8085) { /* 8085 */ + if (int_req & ITRAP) { /* int */ + push_word(PC); + PC = 0x0024; + int_req &= ~ITRAP; + } else if (IM & IE) { + if (int_req & I75 && IM & M75) { /* int 7.5 */ + push_word(PC); + PC = 0x003C; + int_req &= ~I75; + } else if (int_req & I65 && IM & M65) { /* int 6.5 */ + push_word(PC); + PC = 0x0034; + int_req &= ~I65; + } else if (int_req & I55 && IM & M55) { /* int 5.5 */ + push_word(PC); + PC = 0x002C; + int_req &= ~I55; + } else if (int_req & INT_R) { /* intr */ + push_word(PC); /* do an RST 7 */ + PC = 0x0038; + int_req &= ~INT_R; + } + } + } else { /* 8080 */ + if (IM & IE) { /* enabled? */ + push_word(PC); /* do an RST 7 */ + PC = 0x0038; + int_req &= ~INT_R; +// printf("\ni8080: int_req=%04X", int_req); + } + } + } /* end interrupt */ + + if (sim_brk_summ && + sim_brk_test (PC, SWMASK ('E'))) { /* breakpoint? */ + reason = STOP_IBKPT; /* stop simulation */ + break; + } + + PCX = PC; + +// fprintf(fpd, "%04X\n", PC); +// fflush(fpd); + + if (uptr->flags & UNIT_TRACE) { + dumpregs(); + printf("\n"); + } + IR = OP = fetch_byte(0); /* instruction fetch */ + + if (GET_XACK(1) == 0) { /* no XACK for instruction fetch */ + reason = STOP_XACK; + printf("Stopped for XACK-1 PC=%04X\n", --PC); + continue; + } + + if (OP == 0x76) { /* HLT Instruction*/ + reason = STOP_HALT; + PC--; + continue; + } + + /* Handle below all operations which refer to registers or + register pairs. After that, a large switch statement + takes care of all other opcodes */ + + if ((OP & 0xC0) == 0x40) { /* MOV */ + DAR = getreg(OP & 0x07); + putreg((OP >> 3) & 0x07, DAR); + goto loop_end; + } + + if ((OP & 0xC7) == 0x06) { /* MVI */ + putreg((OP >> 3) & 0x07, fetch_byte(1)); + goto loop_end; + } + + if ((OP & 0xCF) == 0x01) { /* LXI */ + DAR = fetch_word(); + putpair((OP >> 4) & 0x03, DAR); + goto loop_end; + } + + if ((OP & 0xEF) == 0x0A) { /* LDAX */ + DAR = getpair((OP >> 4) & 0x03); + putreg(7, get_mbyte(DAR)); + goto loop_end; + } + + if ((OP & 0xEF) == 0x02) { /* STAX */ + DAR = getpair((OP >> 4) & 0x03); + put_mbyte(DAR, getreg(7)); + goto loop_end; + } + + if ((OP & 0xF8) == 0xB8) { /* CMP */ + DAR = A & 0xFF; + DAR -= getreg(OP & 0x07); + setarith(DAR); + DAR &= BYTE_R; + goto loop_end; + } + + if ((OP & 0xC7) == 0xC2) { /* JMP */ + adr = fetch_word(); + if (cond((OP >> 3) & 0x07)) + PC = adr; + goto loop_end; + } + + if ((OP & 0xC7) == 0xC4) { /* CALL */ + adr = fetch_word(); + if (cond((OP >> 3) & 0x07)) { + push_word(PC); + PC = adr; + } + goto loop_end; + } + + if ((OP & 0xC7) == 0xC0) { /* RET */ + if (cond((OP >> 3) & 0x07)) { + PC = pop_word(); + } + goto loop_end; + } + + if ((OP & 0xC7) == 0xC7) { /* RST */ + push_word(PC); + PC = OP & 0x38; + goto loop_end; + } + + if ((OP & 0xCF) == 0xC5) { /* PUSH */ + DAR = getpush((OP >> 4) & 0x03); + push_word(DAR); + goto loop_end; + } + + if ((OP & 0xCF) == 0xC1) { /* POP */ + DAR = pop_word(); + putpush((OP >> 4) & 0x03, DAR); + goto loop_end; + } + + if ((OP & 0xF8) == 0x80) { /* ADD */ + A += getreg(OP & 0x07); + setarith(A); + A &= BYTE_R; + goto loop_end; + } + + if ((OP & 0xF8) == 0x88) { /* ADC */ + A += getreg(OP & 0x07); + if (GET_FLAG(CF)) + A++; + setarith(A); + A &= BYTE_R; + goto loop_end; + } + + if ((OP & 0xF8) == 0x90) { /* SUB */ + A -= getreg(OP & 0x07); + setarith(A); + A &= BYTE_R; + goto loop_end; + } + + if ((OP & 0xF8) == 0x98) { /* SBB */ + A -= getreg(OP & 0x07); + if (GET_FLAG(CF)) + A--; + setarith(A); + A &= BYTE_R; + goto loop_end; + } + + if ((OP & 0xC7) == 0x04) { /* INR */ + DAR = getreg((OP >> 3) & 0x07); + DAR++; + setinc(DAR); +// DAR &= BYTE_R; + putreg((OP >> 3) & 0x07, DAR); + goto loop_end; + } + + if ((OP & 0xC7) == 0x05) { /* DCR */ + DAR = getreg((OP >> 3) & 0x07); + DAR--; + setinc(DAR); +// DAR &= BYTE_R; + putreg((OP >> 3) & 0x07, DAR); + goto loop_end; + } + + if ((OP & 0xCF) == 0x03) { /* INX */ + DAR = getpair((OP >> 4) & 0x03); + DAR++; +// DAR &= WORD_R; + putpair((OP >> 4) & 0x03, DAR); + goto loop_end; + } + + if ((OP & 0xCF) == 0x0B) { /* DCX */ + DAR = getpair((OP >> 4) & 0x03); + DAR--; +// DAR &= WORD_R; + putpair((OP >> 4) & 0x03, DAR); + goto loop_end; + } + + if ((OP & 0xCF) == 0x09) { /* DAD */ + HL += getpair((OP >> 4) & 0x03); + COND_SET_FLAG(HL & 0x10000, CF); + HL &= WORD_R; + goto loop_end; + } + + if ((OP & 0xF8) == 0xA0) { /* ANA */ + A &= getreg(OP & 0x07); + setlogical(A); + goto loop_end; + } + + if ((OP & 0xF8) == 0xA8) { /* XRA */ + A ^= getreg(OP & 0x07); + setlogical(A); + A &= BYTE_R; + goto loop_end; + } + + if ((OP & 0xF8) == 0xB0) { /* ORA */ + A |= getreg(OP & 0x07); + setlogical(A); + goto loop_end; + } + + /* The Big Instruction Decode Switch */ + + switch (IR) { + + /* 8085 instructions only */ + case 0x20: /* RIM */ + if (i8080_unit.flags & UNIT_8085) { /* 8085 */ + A = IM; + } else { /* 8080 */ + reason = STOP_OPCODE; + PC--; + } + break; + + case 0x30: /* SIM */ + if (i8080_unit.flags & UNIT_8085) { /* 8085 */ + if (A & MSE) { + IM &= 0xF8; + IM |= A & 0x07; + } + if (A & I75) { /* reset RST 7.5 FF */ + } + } else { /* 8080 */ + reason = STOP_OPCODE; + PC--; + } + break; + + /* Logical instructions */ + + case 0xFE: /* CPI */ + DAR = A; + DAR -= fetch_byte(1); +// DAR &= BYTE_R; + setarith(DAR); + break; + + case 0xE6: /* ANI */ + A &= fetch_byte(1); + setlogical(A); + break; + + case 0xEE: /* XRI */ + A ^= fetch_byte(1); +// DAR &= BYTE_R; + setlogical(A); + break; + + case 0xF6: /* ORI */ + A |= fetch_byte(1); + setlogical(A); + break; + + /* Jump instructions */ + + case 0xC3: /* JMP */ + PC = fetch_word(); + break; + + case 0xE9: /* PCHL */ + PC = HL; + break; + + case 0xCD: /* CALL */ + adr = fetch_word(); + push_word(PC); + PC = adr; + break; + + case 0xC9: /* RET */ + PC = pop_word(); + break; + + /* Data Transfer Group */ + + case 0x32: /* STA */ + DAR = fetch_word(); + DAR &= WORD_R; + put_mbyte(DAR, A); + break; + + case 0x3A: /* LDA */ + DAR = fetch_word(); + DAR &= WORD_R; + A = get_mbyte(DAR); + break; + + case 0x22: /* SHLD */ + DAR = fetch_word(); + DAR &= WORD_R; + put_mword(DAR, HL); + break; + + case 0x2A: /* LHLD */ + DAR = fetch_word(); + DAR &= WORD_R; + HL = get_mword(DAR); + break; + + case 0xEB: /* XCHG */ + DAR = HL; + HL = DE; + HL &= WORD_R; + DE = DAR; + DE &= WORD_R; + break; + + /* Arithmetic Group */ + + case 0xC6: /* ADI */ + A += fetch_byte(1); + setarith(A); + A &= BYTE_R; + break; + + case 0xCE: /* ACI */ + A += fetch_byte(1); + if (GET_FLAG(CF)) + A++; + setarith(A); + A &= BYTE_R; + break; + + case 0xD6: /* SUI */ + A -= fetch_byte(1); + setarith(A); + A &= BYTE_R; + break; + + case 0xDE: /* SBI */ + A -= fetch_byte(1); + if (GET_FLAG(CF)) + A--; + setarith(A); + A &= BYTE_R; + break; + + case 0x27: /* DAA */ + DAR = A & 0x0F; + if (DAR > 9 || GET_FLAG(AF)) { + DAR += 6; + A &= 0xF0; + A |= DAR & 0x0F; + COND_SET_FLAG(DAR & 0x10, AF); + } + DAR = (A >> 4) & 0x0F; + if (DAR > 9 || GET_FLAG(AF)) { + DAR += 6; + if (GET_FLAG(AF)) DAR++; + A &= 0x0F; + A |= (DAR << 4); + } + COND_SET_FLAG(DAR & 0x10, CF); + COND_SET_FLAG(A & 0x80, SF); + COND_SET_FLAG((A & 0xFF) == 0, ZF); + parity(A); + break; + + case 0x07: /* RLC */ + COND_SET_FLAG(A & 0x80, CF); + A = (A << 1) & 0xFF; + if (GET_FLAG(CF)) + A |= 0x01; + A &= BYTE_R; + break; + + case 0x0F: /* RRC */ + COND_SET_FLAG(A & 0x01, CF); + A = (A >> 1) & 0xFF; + if (GET_FLAG(CF)) + A |= 0x80; + A &= BYTE_R; + break; + + case 0x17: /* RAL */ + DAR = GET_FLAG(CF); + COND_SET_FLAG(A & 0x80, CF); + A = (A << 1) & 0xFF; + if (DAR) + A |= 0x01; + A &= BYTE_R; + break; + + case 0x1F: /* RAR */ + DAR = GET_FLAG(CF); + COND_SET_FLAG(A & 0x01, CF); + A = (A >> 1) & 0xFF; + if (DAR) + A |= 0x80; + A &= BYTE_R; + break; + + case 0x2F: /* CMA */ + A = ~A; + A &= BYTE_R; + break; + + case 0x3F: /* CMC */ + TOGGLE_FLAG(CF); + break; + + case 0x37: /* STC */ + SET_FLAG(CF); + break; + + /* Stack, I/O & Machine Control Group */ + + case 0x00: /* NOP */ + break; + + case 0xE3: /* XTHL */ + DAR = pop_word(); + push_word(HL); + HL = DAR; + HL &= WORD_R; + break; + + case 0xF9: /* SPHL */ + SP = HL; + break; + + case 0xFB: /* EI */ + IM |= IE; +// printf("\nEI: pc=%04X", PC - 1); + break; + + case 0xF3: /* DI */ + IM &= ~IE; +// printf("\nDI: pc=%04X", PC - 1); + break; + + case 0xDB: /* IN */ + DAR = fetch_byte(1); + A = dev_table[DAR].routine(0, 0); + A &= BYTE_R; + break; + + case 0xD3: /* OUT */ + DAR = fetch_byte(1); + dev_table[DAR].routine(1, A); + break; + + default: /* undefined opcode */ + if (i8080_unit.flags & UNIT_OPSTOP) { + reason = STOP_OPCODE; + PC--; + } + break; + } +loop_end: + if (GET_XACK(1) == 0) { /* no XACK for instruction fetch */ + reason = STOP_XACK; + printf("Stopped for XACK-2 PC=%04X\n", --PC); + continue; + } + + } + +/* Simulation halted */ + + saved_PC = PC; +// fclose(fpd); + return reason; +} + +/* dump the registers */ +void dumpregs(void) +{ + printf(" A=%02X BC=%04X DE=%04X HL=%04X SP=%04X IM=%02X XACK=%d\n", + A, BC, DE, HL, SP, IM, xack); + printf(" CF=%d ZF=%d AF=%d SF=%d PF=%d\n", + GET_FLAG(CF) ? 1 : 0, + GET_FLAG(ZF) ? 1 : 0, + GET_FLAG(AF) ? 1 : 0, + GET_FLAG(SF) ? 1 : 0, + GET_FLAG(PF) ? 1 : 0); +} +/* fetch an instruction or byte */ +int32 fetch_byte(int32 flag) +{ + uint32 val; + + val = get_mbyte(PC) & 0xFF; /* fetch byte */ + if (i8080_dev.dctrl & DEBUG_asm || uptr->flags & UNIT_TRACE) { /* display source code */ + switch (flag) { + case 0: /* opcode fetch */ + printf("OP=%02X %04X %s", val, PC, opcode[val]); + break; + case 1: /* byte operand fetch */ + printf("0%02XH", val); + break; + } + } + PC = (PC + 1) & ADDRMASK; /* increment PC */ + val &= BYTE_R; + return val; +} + +/* fetch a word */ +int32 fetch_word(void) +{ + uint16 val; + + val = get_mbyte(PC) & BYTE_R; /* fetch low byte */ + val |= get_mbyte(PC + 1) << 8; /* fetch high byte */ + if (i8080_dev.dctrl & DEBUG_asm || uptr->flags & UNIT_TRACE) /* display source code */ + printf("0%04XH", val); + PC = (PC + 2) & ADDRMASK; /* increment PC */ + val &= WORD_R; + return val; +} + +/* push a word to the stack */ +void push_word(uint16 val) +{ + SP--; + put_mbyte(SP, (val >> 8)); + SP--; + put_mbyte(SP, val & 0xFF); +} + +/* pop a word from the stack */ +uint16 pop_word(void) +{ + register uint16 res; + + res = get_mbyte(SP); + SP++; + res |= get_mbyte(SP) << 8; + SP++; + return res; +} + +/* Test an 8080 flag condition and return 1 if true, 0 if false */ +int32 cond(int32 con) +{ + switch (con) { + case 0: /* NZ */ + if (GET_FLAG(ZF) == 0) return 1; + break; + case 1: /* Z */ + if (GET_FLAG(ZF)) return 1; + break; + case 2: /* NC */ + if (GET_FLAG(CF) == 0) return 1; + break; + case 3: /* C */ + if (GET_FLAG(CF)) return 1; + break; + case 4: /* PO */ + if (GET_FLAG(PF) == 0) return 1; + break; + case 5: /* PE */ + if (GET_FLAG(PF)) return 1; + break; + case 6: /* P */ + if (GET_FLAG(SF) == 0) return 1; + break; + case 7: /* M */ + if (GET_FLAG(SF)) return 1; + break; + default: + break; + } + return 0; +} + +/* Set the arry, ign, ero and

arity flags following + an arithmetic operation on 'reg'. +*/ + +void setarith(int32 reg) +{ + COND_SET_FLAG(reg & 0x100, CF); + COND_SET_FLAG(reg & 0x80, SF); + COND_SET_FLAG((reg & BYTE_R) == 0, ZF); + CLR_FLAG(AF); + parity(reg); +} + +/* Set the arry, ign, ero amd

arity flags following + a logical (bitwise) operation on 'reg'. +*/ + +void setlogical(int32 reg) +{ + CLR_FLAG(CF); + COND_SET_FLAG(reg & 0x80, SF); + COND_SET_FLAG((reg & BYTE_R) == 0, ZF); + CLR_FLAG(AF); + parity(reg); +} + +/* Set the Parity (P) flag based on parity of 'reg', i.e., number + of bits on even: P=0200000, else P=0 +*/ + +void parity(int32 reg) +{ + int32 bc = 0; + + if (reg & 0x01) bc++; + if (reg & 0x02) bc++; + if (reg & 0x04) bc++; + if (reg & 0x08) bc++; + if (reg & 0x10) bc++; + if (reg & 0x20) bc++; + if (reg & 0x40) bc++; + if (reg & 0x80) bc++; + if (bc & 0x01) + CLR_FLAG(PF); + else + SET_FLAG(PF); +} + +/* Set the ign, ero amd

arity flags following + an INR/DCR operation on 'reg'. +*/ + +void setinc(int32 reg) +{ + COND_SET_FLAG(reg & 0x80, SF); + COND_SET_FLAG((reg & BYTE_R) == 0, ZF); + parity(reg); +} + +/* Get an 8080 register and return it */ +int32 getreg(int32 reg) +{ + switch (reg) { + case 0: /* reg B */ + // printf("reg=%04X BC=%04X ret=%04X\n", + // reg, BC, (BC >>8) & 0xff); + return ((BC >>8) & BYTE_R); + case 1: /* reg C */ + return (BC & BYTE_R); + case 2: /* reg D */ + return ((DE >>8) & BYTE_R); + case 3: /* reg E */ + return (DE & BYTE_R); + case 4: /* reg H */ + return ((HL >>8) & BYTE_R); + case 5: /* reg L */ + return (HL & BYTE_R); + case 6: /* reg M */ + return (get_mbyte(HL)); + case 7: /* reg A */ + return (A); + default: + break; + } + return 0; +} + +/* Put a value into an 8-bit 8080 register from memory */ +void putreg(int32 reg, int32 val) +{ + switch (reg) { + case 0: /* reg B */ +// printf("reg=%04X val=%04X\n", reg, val); + BC = BC & BYTE_R; +// printf("BC&0x00ff=%04X val<<8=%04X\n", BC, val<<8); + BC = BC | (val <<8); + break; + case 1: /* reg C */ + BC = BC & 0xFF00; + BC = BC | val; + break; + case 2: /* reg D */ + DE = DE & BYTE_R; + DE = DE | (val <<8); + break; + case 3: /* reg E */ + DE = DE & 0xFF00; + DE = DE | val; + break; + case 4: /* reg H */ + HL = HL & BYTE_R; + HL = HL | (val <<8); + break; + case 5: /* reg L */ + HL = HL & 0xFF00; + HL = HL | val; + break; + case 6: /* reg M */ + put_mbyte(HL, val); + break; + case 7: /* reg A */ + A = val & BYTE_R; + default: + break; + } +} + +/* Return the value of a selected register pair */ +int32 getpair(int32 reg) +{ + switch (reg) { + case 0: /* reg BC */ + return (BC); + case 1: /* reg DE */ + return (DE); + case 2: /* reg HL */ + return (HL); + case 3: /* reg SP */ + return (SP); + default: + break; + } + return 0; +} + +/* Return the value of a selected register pair, in PUSH + format where 3 means A & flags, not SP */ +int32 getpush(int32 reg) +{ + int32 stat; + + switch (reg) { + case 0: /* reg BC */ + return (BC); + case 1: /* reg DE */ + return (DE); + case 2: /* reg HL */ + return (HL); + case 3: /* reg (A << 8) | PSW */ + stat = A << 8 | PSW; + return (stat); + default: + break; + } + return 0; +} + + +/* Place data into the indicated register pair, in PUSH + format where 3 means A& flags, not SP */ +void putpush(int32 reg, int32 data) +{ + switch (reg) { + case 0: /* reg BC */ + BC = data; + break; + case 1: /* reg DE */ + DE = data; + break; + case 2: /* reg HL */ + HL = data; + break; + case 3: /* reg (A << 8) | PSW */ + A = (data >> 8) & BYTE_R; + PSW = data & BYTE_R; + break; + default: + break; + } +} + + +/* Put a value into an 8080 register pair */ +void putpair(int32 reg, int32 val) +{ + switch (reg) { + case 0: /* reg BC */ + BC = val; + break; + case 1: /* reg DE */ + DE = val; + break; + case 2: /* reg HL */ + HL = val; + break; + case 3: /* reg SP */ + SP = val; + break; + default: + break; + } +} + +/* Reset routine */ + +t_stat i8080_reset (DEVICE *dptr) +{ + PSW = PSW_ALWAYS_ON; + CLR_FLAG(CF); + CLR_FLAG(ZF); + saved_PC = 0; + int_req = 0; + IM = 0; + sim_brk_types = sim_brk_dflt = SWMASK ('E'); + printf(" 8080: Reset\n"); +// fpd = fopen("trace.txt", "w"); + return SCPE_OK; +} + +/* Memory examine */ + +t_stat i8080_ex (t_value *vptr, t_addr addr, UNIT *uptr, int32 sw) +{ + if (addr >= MEMSIZE) + return SCPE_NXM; + if (vptr != NULL) + *vptr = get_mbyte(addr); + return SCPE_OK; +} + +/* Memory deposit */ + +t_stat i8080_dep (t_value val, t_addr addr, UNIT *uptr, int32 sw) +{ + if (addr >= MEMSIZE) + return SCPE_NXM; + put_mbyte(addr, val); + return SCPE_OK; +} + +/* This is the binary loader. The input file is considered to be + a string of literal bytes with no special format. The load + starts at the current value of the PC. +*/ + +int32 sim_load (FILE *fileref, char *cptr, char *fnam, int flag) +{ + int32 i, addr = 0, cnt = 0; + + if ((*cptr != 0) || (flag != 0)) return SCPE_ARG; + addr = saved_PC; + while ((i = getc (fileref)) != EOF) { + put_mbyte(addr, i); + addr++; + cnt++; + } /* end while */ + printf ("%d Bytes loaded.\n", cnt); + return (SCPE_OK); +} + +/* Symbolic output + + Inputs: + *of = output stream + addr = current PC + *val = pointer to values + *uptr = pointer to unit + sw = switches + Outputs: + status = error code +*/ + +t_stat fprint_sym (FILE *of, t_addr addr, t_value *val, + UNIT *uptr, int32 sw) +{ + int32 cflag, c1, c2, inst, adr; + + cflag = (uptr == NULL) || (uptr == &i8080_unit); + c1 = (val[0] >> 8) & 0x7F; + c2 = val[0] & 0x7F; + if (sw & SWMASK ('A')) { + fprintf (of, (c2 < 0x20)? "<%02X>": "%c", c2); + return SCPE_OK; + } + if (sw & SWMASK ('C')) { + fprintf (of, (c1 < 0x20)? "<%02X>": "%c", c1); + fprintf (of, (c2 < 0x20)? "<%02X>": "%c", c2); + return SCPE_OK; + } + if (!(sw & SWMASK ('M'))) return SCPE_ARG; + inst = val[0]; + fprintf (of, "%s", opcode[inst]); + if (oplen[inst] == 2) { + if (strchr(opcode[inst], ' ') != NULL) + fprintf (of, ","); + else fprintf (of, " "); + fprintf (of, "%h", val[1]); + } + if (oplen[inst] == 3) { + adr = val[1] & 0xFF; + adr |= (val[2] << 8) & 0xff00; + if (strchr(opcode[inst], ' ') != NULL) + fprintf (of, ","); + else fprintf (of, " "); + fprintf (of, "%h", adr); + } + return -(oplen[inst] - 1); +} + +/* Symbolic input + + Inputs: + *cptr = pointer to input string + addr = current PC + *uptr = pointer to unit + *val = pointer to output values + sw = switches + Outputs: + status = error status +*/ + +t_stat parse_sym (char *cptr, t_addr addr, UNIT *uptr, t_value *val, int32 sw) +{ + int32 cflag, i = 0, j, r; + char gbuf[CBUFSIZE]; + + cflag = (uptr == NULL) || (uptr == &i8080_unit); + while (isspace (*cptr)) cptr++; /* absorb spaces */ + if ((sw & SWMASK ('A')) || ((*cptr == '\'') && cptr++)) { /* ASCII char? */ + if (cptr[0] == 0) return SCPE_ARG; /* must have 1 char */ + val[0] = (uint32) cptr[0]; + return SCPE_OK; + } + if ((sw & SWMASK ('C')) || ((*cptr == '"') && cptr++)) { /* ASCII string? */ + if (cptr[0] == 0) return SCPE_ARG; /* must have 1 char */ + val[0] = ((uint32) cptr[0] << 8) + (uint32) cptr[1]; + return SCPE_OK; + } + +/* An instruction: get opcode (all characters until null, comma, + or numeric (including spaces). +*/ + + while (1) { + if (*cptr == ',' || *cptr == '\0' || + isdigit(*cptr)) + break; + gbuf[i] = toupper(*cptr); + cptr++; + i++; + } + +/* Allow for RST which has numeric as part of opcode */ + + if (toupper(gbuf[0]) == 'R' && + toupper(gbuf[1]) == 'S' && + toupper(gbuf[2]) == 'T') { + gbuf[i] = toupper(*cptr); + cptr++; + i++; + } + +/* Allow for 'MOV' which is only opcode that has comma in it. */ + + if (toupper(gbuf[0]) == 'M' && + toupper(gbuf[1]) == 'O' && + toupper(gbuf[2]) == 'V') { + gbuf[i] = toupper(*cptr); + cptr++; + i++; + gbuf[i] = toupper(*cptr); + cptr++; + i++; + } + +/* kill trailing spaces if any */ + gbuf[i] = '\0'; + for (j = i - 1; gbuf[j] == ' '; j--) { + gbuf[j] = '\0'; + } + +/* find opcode in table */ + for (j = 0; j < 256; j++) { + if (strcmp(gbuf, opcode[j]) == 0) + break; + } + if (j > 255) /* not found */ + return SCPE_ARG; + + val[0] = j; /* store opcode */ + if (oplen[j] < 2) /* if 1-byter we are done */ + return SCPE_OK; + if (*cptr == ',') cptr++; + cptr = get_glyph(cptr, gbuf, 0); /* get address */ + sscanf(gbuf, "%o", &r); + if (oplen[j] == 2) { + val[1] = r & 0xFF; + return (-1); + } + val[1] = r & 0xFF; + val[2] = (r >> 8) & 0xFF; + return (-2); +} diff --git a/MDS-800/common/i8088.c b/MDS-800/common/i8088.c new file mode 100644 index 00000000..3a7bf3bd --- /dev/null +++ b/MDS-800/common/i8088.c @@ -0,0 +1,4746 @@ +/* i8088.c: Intel 8086/8088 CPU simulator + + Copyright (C) 1991 Jim Hudgens + + The file is part of GDE. + + GDE is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 1, or (at your option) + any later version. + + GDE is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GDE; see the file COPYING. If not, write to + the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + + This software was modified by Bill Beech, Mar 2011, from the software GDE + of Jim Hudgens as provided with the SIMH AltairZ80 emulation package. + I modified it to allow emulation of Intel iSBC Single Board Computers. + + Copyright (c) 2011, William A. Beech + + Permission is hereby granted, free of charge, to any person obtaining a + copy of this software and associated documentation files (the "Software"), + to deal in the Software without restriction, including without limitation + the rights to use, copy, modify, merge, publish, distribute, sublicense, + and/or sell copies of the Software, and to permit persons to whom the + Software is furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + WILLIAM A. BEECH BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + Except as contained in this notice, the name of William A. Beech shall not be + used in advertising or otherwise to promote the sale, use or other dealings + in this Software without prior written authorization from William A. Beech. + + cpu 8088 CPU + + 17 Mar 11 WAB Original code + + The register state for the 8088 CPU is: + + AX<0:15> AH/AL Register Pair + BX<0:15> BH/BL Register Pair + CX<0:15> CH/CL Register Pair + DX<0:15> DH/DL Register Pair + SI<0:15> Source Index Register + DI<0:15> Destination Index Register + BP<0:15> Base Pointer + SP<0:15> Stack Pointer + CS<0:15> Code Segment Register + DS<0:15> Date Segment Register + SS<0:15> Stack Segment Register + ES<0:15> Extra Segment Register + IP<0:15> Program Counter + + PSW<0:15> Program Status Word - Contains the following flags: + + AF Auxillary Flag + CF Carry Flag + OF Overflow Flag + SF Sign Flag + PF Parity Flag + ZF Zero Flag + DF Direction Flag + IF Interrupt Enable Flag + TF Trap Flag + + in bit positions: + 15 8 7 0 + |--|--|--|--|OF|DF|IF|TF|SF|ZF|--|AF|--|PF|--|CF| + + The 8088 is an 8-bit CPU, which uses 16-bit offset and segment registers + in combination with a dedicated adder to address up to 1MB of memory directly. + The offset register is added to the segment register shifted left 4 places + to obtain the 20-bit address. + + The CPU utilizes two separate processing units - the Execution Unit (EU) and + the Bus Interface Unit (BIU). The EU executes instructions. The BIU fetches + instructions, reads operands and writes results. The two units can operate + independently of one another and are able, under most circumstances, to + extensively overlap instruction fetch with execution. + + The BIUs of the 8086 and 8088 are functionally identical, but are implemented + differently to match the structure and performance characteristics of their + respective buses. + + The almost 300 instructions come in 1, 2, 3, 4, 5, 6 and 7-byte flavors. + + This routine is the simulator for the 8088. It is called from the + simulator control program to execute instructions in simulated memory, + starting at the simulated IP. It runs until 'reason' is set non-zero. + + General notes: + + 1. Reasons to stop. The simulator can be stopped by: + + HALT instruction + I/O error in I/O simulator + Invalid OP code (if ITRAP is set on CPU) + + 2. Interrupts. + There are 256 possible levels of interrupt, and in effect they + do a hardware CALL instruction to one of 256 possible low + memory addresses. + + 3. Non-existent memory. On the 8088, reads to non-existent memory + return 0FFh, and writes are ignored. + + Some algorithms were pulled from the GDE Dos/IP Emulator by Jim Hudgens + +*/ +/* + This algorithm was pulled from the GDE Dos/IP Emulator by Jim Hudgens + +CARRY CHAIN CALCULATION. + This represents a somewhat expensive calculation which is + apparently required to emulate the setting of the OF and + AF flag. The latter is not so important, but the former is. + The overflow flag is the XOR of the top two bits of the + carry chain for an addition (similar for subtraction). + Since we do not want to simulate the addition in a bitwise + manner, we try to calculate the carry chain given the + two operands and the result. + + So, given the following table, which represents the + addition of two bits, we can derive a formula for + the carry chain. + + a b cin r cout + 0 0 0 0 0 + 0 0 1 1 0 + 0 1 0 1 0 + 0 1 1 0 1 + 1 0 0 1 0 + 1 0 1 0 1 + 1 1 0 0 1 + 1 1 1 1 1 + + Construction of table for cout: + + ab + r \ 00 01 11 10 + |------------------ + 0 | 0 1 1 1 + 1 | 0 0 1 0 + + By inspection, one gets: cc = ab + r'(a + b) + + That represents alot of operations, but NO CHOICE.... + +BORROW CHAIN CALCULATION. + The following table represents the + subtraction of two bits, from which we can derive a formula for + the borrow chain. + + a b bin r bout + 0 0 0 0 0 + 0 0 1 1 1 + 0 1 0 1 1 + 0 1 1 0 1 + 1 0 0 1 0 + 1 0 1 0 0 + 1 1 0 0 0 + 1 1 1 1 1 + + Construction of table for cout: + + ab + r \ 00 01 11 10 + |------------------ + 0 | 0 1 0 0 + 1 | 1 1 1 0 + + By inspection, one gets: bc = a'b + r(a' + b) + + Segment register selection and overrides are handled as follows: + If there is a segment override, the register number is stored + in seg_ovr. If there is no override, seg_ovr is zero. Seg_ovr + is set to zero after each instruction except segment override + instructions. + + Get_ea sets the value of seg_reg to the override if present + otherwise to the default value for the registers used in the + effective address calculation. + + The get/put_smword/byte routines use the register number in + seg_reg to obtain the segment value to calculate the absolute + memory address for the operation. + */ + +#include +#include "multibus_defs.h" + +#define UNIT_V_OPSTOP (UNIT_V_UF) /* Stop on Invalid OP? */ +#define UNIT_OPSTOP (1 << UNIT_V_OPSTOP) +#define UNIT_V_CHIP (UNIT_V_UF+1) /* 8088 or 8086 */ +#define UNIT_CHIP (1 << UNIT_V_CHIP) + +/* Flag values to set proper positions in PSW */ +#define CF 0x0001 +#define PF 0x0004 +#define AF 0x0010 +#define ZF 0x0040 +#define SF 0x0080 +#define TF 0x0100 +#define IF 0x0200 +#define DF 0x0400 +#define OF 0x0800 + +/* Macros to handle the flags in the PSW + 8088 has top 4 bits of the flags set to 1 + also, bit#1 is set. This is (not well) documented behavior. */ +#define PSW_ALWAYS_ON (0xF002) /* for 8086 */ +#define PSW_MSK (CF|PF|AF|ZF|SF|TF|IF|DF|OF) +#define TOGGLE_FLAG(FLAG) (PSW ^= FLAG) +#define SET_FLAG(FLAG) (PSW |= FLAG) +#define CLR_FLAG(FLAG) (PSW &= ~FLAG) +#define GET_FLAG(FLAG) (PSW & FLAG) +#define CONDITIONAL_SET_FLAG(COND,FLAG) \ + if (COND) SET_FLAG(FLAG); else CLR_FLAG(FLAG) + +/* union of byte and word registers */ +union { + uint8 b[2]; /* two bytes */ + uint16 w; /* one word */ +} A, B, C, D; /* storage for AX, BX, CX and DX */ + +/* macros for byte registers */ +#define AH (A.b[1]) +#define AL (A.b[0]) +#define BH (B.b[1]) +#define BL (B.b[0]) +#define CH (C.b[1]) +#define CL (C.b[0]) +#define DH (D.b[1]) +#define DL (D.b[0]) + +/* macros for word registers */ +#define AX (A.w) +#define BX (B.w) +#define CX (C.w) +#define DX (D.w) + +/* macros for handling IP and SP */ +#define INC_IP1 (++IP & ADDRMASK20) /* increment IP one byte */ +#define INC_IP2 ((IP += 2) & ADDRMASK20) /* increment IP two bytes */ + +/* storage for the rest of the registers */ +int32 DI; /* Source Index Register */ +int32 SI; /* Destination Index Register */ +int32 BP; /* Base Pointer Register */ +int32 SP; /* Stack Pointer Register */ +int32 CS; /* Code Segment Register */ +int32 DS; /* Data Segment Register */ +int32 SS; /* Stack Segment Register */ +int32 ES; /* Extra Segment Register */ +int32 IP; /* Program Counter */ +int32 PSW; /* Program Status Word (Flags) */ +int32 saved_PC = 0; /* saved program counter */ +int32 int_req = 0; /* Interrupt request */ +int32 chip = 0; /* 0 = 8088 chip, 1 = 8086 chip */ +#define CHIP_8088 0 /* processor types */ +#define CHIP_8086 1 +#define CHIP_80188 2 +#define CHIP_80186 3 +#define CHIP_80286 4 + +int32 seg_ovr = 0; /* segment override register */ +int32 seg_reg = 0; /* segment register to use for EA */ +#define SEG_NONE 0 /* segmenr override register values */ +#define SEG_CS 8 +#define SEG_DS 9 +#define SEG_ES 10 +#define SEG_SS 11 + +int32 PCX; /* External view of IP */ + +/* handle prefix instructions */ +uint32 sysmode = 0; /* prefix flags */ +#define SYSMODE_SEG_DS_SS 0x01 +#define SYSMODE_SEGOVR_CS 0x02 +#define SYSMODE_SEGOVR_DS 0x04 +#define SYSMODE_SEGOVR_ES 0x08 +#define SYSMODE_SEGOVR_SS 0x10 +#define SYSMODE_SEGMASK (SYSMODE_SEG_DS_SS | SYSMODE_SEGOVR_CS | \ + SYSMODE_SEGOVR_DS | SYSMODE_SEGOVR_ES | SYSMODE_SEGOVR_SS) +#define SYSMODE_PREFIX_REPE 0x20 +#define SYSMODE_PREFIX_REPNE 0x40 + +/* function prototypes */ +int32 sign_ext(int32 val); +int32 fetch_byte(int32 flag); +int32 fetch_word(void); +int32 parity(int32 val); +void i86_intr_raise(uint8 num); +uint32 get_rbyte(uint32 reg); +uint32 get_rword(uint32 reg); +void put_rbyte(uint32 reg, uint32 val); +void put_rword(uint32 reg, uint32 val); +uint32 get_ea(uint32 mrr); +void set_segreg(uint32 reg); +void get_mrr_dec(uint32 mrr, uint32 *mod, uint32 *reg, uint32 *rm); + +/* emulator primitives */ +uint8 aad_word(uint16 d); +uint16 aam_word(uint8 d); +uint8 adc_byte(uint8 d, uint8 s); +uint16 adc_word(uint16 d, uint16 s); +uint8 add_byte(uint8 d, uint8 s); +uint16 add_word(uint16 d, uint16 s); +uint8 and_byte(uint8 d, uint8 s); +uint16 cmp_word(uint16 d, uint16 s); +uint8 cmp_byte(uint8 d, uint8 s); +uint16 and_word(uint16 d, uint16 s); +uint8 dec_byte(uint8 d); +uint16 dec_word(uint16 d); +void div_byte(uint8 s); +void div_word(uint16 s); +void idiv_byte(uint8 s); +void idiv_word(uint16 s); +void imul_byte(uint8 s); +void imul_word(uint16 s); +uint8 inc_byte(uint8 d); +uint16 inc_word(uint16 d); +void mul_byte(uint8 s); +void mul_word(uint16 s); +uint8 neg_byte(uint8 s); +uint16 neg_word(uint16 s); +uint8 not_byte(uint8 s); +uint16 not_word(uint16 s); +uint8 or_byte(uint8 d, uint8 s); +uint16 or_word(uint16 d, uint16 s); +void push_word(uint16 val); +uint16 pop_word(void); +uint8 rcl_byte(uint8 d, uint8 s); +uint16 rcl_word(uint16 d, uint16 s); +uint8 rcr_byte(uint8 d, uint8 s); +uint16 rcr_word(uint16 d, uint16 s); +uint8 rol_byte(uint8 d, uint8 s); +uint16 rol_word(uint16 d, uint16 s); +uint8 ror_byte(uint8 d, uint8 s); +uint16 ror_word(uint16 d, uint16 s); +uint8 shl_byte(uint8 d, uint8 s); +uint16 shl_word(uint16 d, uint16 s); +uint8 shr_byte(uint8 d, uint8 s); +uint16 shr_word(uint16 d, uint16 s); +uint8 sar_byte(uint8 d, uint8 s); +uint16 sar_word(uint16 d, uint16 s); +uint8 sbb_byte(uint8 d, uint8 s); +uint16 sbb_word(uint16 d, uint16 s); +uint8 sub_byte(uint8 d, uint8 s); +uint16 sub_word(uint16 d, uint16 s); +void test_byte(uint8 d, uint8 s); +void test_word(uint16 d, uint16 s); +uint8 xor_byte(uint8 d, uint8 s); +uint16 xor_word(uint16 d, uint16 s); +int32 get_smbyte(int32 segreg, int32 addr); +int32 get_smword(int32 segreg, int32 addr); +void put_smbyte(int32 segreg, int32 addr, int32 val); +void put_smword(int32 segreg, int32 addr, int32 val); + +/* simulator routines */ +int32 sim_instr(void); +t_stat i8088_reset (DEVICE *dptr); +t_stat i8088_ex (t_value *vptr, t_addr addr, UNIT *uptr, int32 sw); +t_stat i8088_dep (t_value val, t_addr addr, UNIT *uptr, int32 sw); + +/* external references */ +//extern t_stat i8088_reset (DEVICE *dptr); + +/* Multibus memory read and write absolute address routines */ +extern int32 get_mbyte(int32 addr); +extern int32 get_mword(int32 addr); +extern void put_mbyte(int32 addr, int32 val); +extern void put_mword(int32 addr, int32 val); + +extern int32 sim_int_char; +extern int32 sim_brk_types, sim_brk_dflt, sim_brk_summ; /* breakpoint info */ + +/* This is the I/O configuration table. There are 65536 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)(); +}; +extern struct idev dev_table[]; + +/* 8088 CPU data structures + + i8088_dev CPU device descriptor + i8088_unit CPU unit descriptor + i8088_reg CPU register list + i8088_mod CPU modifiers list +*/ + +UNIT i8088_unit = { UDATA (NULL, 0, 0) }; + +REG i8088_reg[] = { + { HRDATA (IP, saved_PC, 16) }, /* must be first for sim_PC */ + { HRDATA (AX, AX, 16) }, + { HRDATA (BX, BX, 16) }, + { HRDATA (CX, CX, 16) }, + { HRDATA (DX, DX, 16) }, + { HRDATA (DI, DI, 16) }, + { HRDATA (SI, SI, 16) }, + { HRDATA (BP, BP, 16) }, + { HRDATA (SP, SP, 16) }, + { HRDATA (CS, CS, 16) }, + { HRDATA (DS, DS, 16) }, + { HRDATA (SS, SS, 16) }, + { HRDATA (ES, ES, 16) }, + { HRDATA (PSW, PSW, 16) }, + { HRDATA (WRU, sim_int_char, 8) }, + { NULL } +}; + +MTAB i8088_mod[] = { + { UNIT_CHIP, UNIT_CHIP, "8086", "8086", NULL }, + { UNIT_CHIP, 0, "8088", "8088", NULL }, + { UNIT_OPSTOP, UNIT_OPSTOP, "ITRAP", "ITRAP", NULL }, + { UNIT_OPSTOP, 0, "NOITRAP", "NOITRAP", NULL }, + { 0 } +}; + +DEBTAB i8088_debug[] = { + { "ALL", DEBUG_all }, + { "FLOW", DEBUG_flow }, + { "READ", DEBUG_read }, + { "WRITE", DEBUG_write }, + { "LEV1", DEBUG_level1 }, + { "LEV2", DEBUG_level2 }, + { "REG", DEBUG_reg }, + { "ASM", DEBUG_asm }, + { NULL } +}; + +DEVICE i8088_dev = { + "CPU", //name + &i8088_unit, //units + i8088_reg, //registers + i8088_mod, //modifiers + 1, //numunits + 16, //aradix + 20, //awidth + 1, //aincr + 16, //dradix + 8, //dwidth + &i8088_ex, //examine + &i8088_dep, //deposit + &i8088_reset, //reset + NULL, //boot + NULL, //attach + NULL, //detach + NULL, //ctxt + DEV_DEBUG, //flags + 0, //dctrl + i8088_debug, //debflags + NULL, //msize + NULL //lname +}; + +uint8 xor_3_tab[] = { 0, 1, 1, 0 }; + +int32 IP; + +static const char *opcode[] = { +"ADD ", "ADD ", "ADD ", "ADD ", /* 0x00 */ +"ADD AL,", "ADD AX,", "PUSH ES", "POP ES", +"OR ", "OR ", "OR ", "OR ", +"OR AL,", "OR AX,", "PUSH CS", "???", +"ADC ", "ADC ", "ADC ", "ADC ", /* 0x10 */ +"ADC AL,", "ADC AX,", "PUSH SS", "RPOP SS", +"SBB ", "SBB ", "SBB ", "SBB ", +"SBB AL,", "SBB AX,", "PUSH DS", "POP DS", +"AND ", "AND ", "AND ", "AND ", /* 0x20 */ +"AND AL,", "AND AX,", "ES:", "DAA", +"SUB ", "SUB ", "SUB ", "SUB ", +"SUB AL,", "SUB AX,", "CS:", "DAS", +"XOR ", "XOR ", "XOR ", "XOR ", /* 0x30 */ +"XOR AL,", "XOR AX,", "SS:", "AAA", +"CMP ", "CMP ", "CMP ", "CMP ", +"CMP AL,", "CMP AX,", "DS:", "AAS", +"INC AX", "INC CX", "INC DX", "INC BX", /* 0x40 */ +"INC SP", "INC BP", "INC SI", "INC DI", +"DEC AX", "DEC CX", "DEC DX", "DEC BX", +"DEC SP", "DEC BP", "DEC SI", "DEC DI", +"PUSH AX", "PUSH CX", "PUSH DX", "PUSH BX", /* 0x50 */ +"PUSH SP", "PUSH BP", "PUSH SI", "PUSH DI", +"POP AX", "POP CX", "POP DX", "POP BX", +"POP SP", "POP BP", "POP SI", "POP DI", +"???", "???", "???", "???", /* 0x60 */ +"???", "???", "???", "???", +"PUSH ", "IMUL ", "PUSH ", "IMUL ", +"INSB", "INSW", "OUTSB", "OUTSW", +"JO ", "JNO ", "JC ", "JNC", /* 0x70 */ +"JZ ", "JNZ ", "JNA ", "JA", +"JS ", "JNS ", "JP ", "JNP ", +"JL ", "JNL ", "JLE ", "JNLE", +"???", "???", "???", "???", /* 0x80 */ +"TEST ", "TEST ", "XCHG ", "XCHG ", +"MOV ", "MOV ", "MOV ", "MOV ", +"MOV ", "LEA ", "MOV ", "POP ", +"NOP", "XCHG AX,CX", "XCHG AX,DX", "XCHG AX,BX",/* 0x90 */ +"XCHG AX,SP", "XCHG AX,BP", "XCHG AX,SI", "XCHG AX,DI", +"CBW", "CWD", "CALL ", "WAIT", +"PUSHF", "POPF", "SAHF", "LAHF", +"MOV AL,", "MOV AX,", "MOV ", "MOV ", /* 0xA0 */ +"MOVSB", "MOVSW", "CMPSB", "CMPSW", +"TEST AL,", "TEST AX,", "STOSB", "STOSW", +"LODSB", "LODSW", "SCASB", "SCASW", +"MOV AL,", "MOV CL,", "MOV DL,", "MOV BL,", /* 0xB0 */ +"MOV AH,", "MOV CH,", "MOV DH,", "MOV BH,", +"MOV AX,", "MOV CX,", "MOV DX,", "MOV BX,", +"MOV SP,", "MOV BP,", "MOV SI,", "MOV DI," +" ", " ", "RET ", "RET ", /* 0xC0 */ +"LES ", "LDS ", "MOV ", "MOV ", +"???", "???", "RET ", "RET", +"INT 3", "INT ", "INTO", "IRET", +" ", " ", " ", " ", /* 0xD0 */ +"AAM", "AAD", "???", "XLATB", +"ESC ", "ESC ", "ESC ", "ESC ", +"ESC ", "ESC ", "ESC ", "ESC ", +"LOOPNZ ", "LOOPZ ", "LOOP", "JCXZ", /* 0xE0 */ +"IN AL,", "IN AX,", "OUT ", "OUT ", +"CALL ", "JMP ", "JMP ", "JMP ", +"IN AL,DX", "IN AX,DX", "OUT DX,AL", "OUT DX,AX", +"LOCK", "???", "REPNZ", "REPZ", /* 0xF0 */ +"HLT", "CMC", " ", " ", +"CLC", "STC", "CLI", "STI", +"CLD", "STD", "???", "???" + }; + +int32 oplen[256] = { +1,3,1,1,1,1,2,1,0,1,1,1,1,1,2,1, +0,3,1,1,1,1,2,1,0,1,1,1,1,1,2,1, +0,3,3,1,1,1,2,1,0,1,3,1,1,1,2,1, +0,3,3,1,1,1,2,1,0,1,3,1,1,1,2,1, +1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, +1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, +1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, +1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, +1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, +1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, +1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, +1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, +1,1,3,3,3,1,2,1,1,1,3,0,3,3,2,1, +1,1,3,2,3,1,2,1,1,0,3,2,3,0,2,1, +1,1,3,1,3,1,2,1,1,1,3,1,3,0,2,1, +1,1,3,1,3,1,2,1,1,1,3,1,3,0,2,1 +}; + +int32 sim_instr (void) +{ + extern int32 sim_interval; + int32 IR, OP, DAR, reason, hi, lo, carry, i, adr; + int32 MRR, REG, EA, MOD, RM, DISP, VAL, DATA, OFF, SEG, INC, VAL1; + + IP = saved_PC & ADDRMASK16; /* load local IP */ + reason = 0; /* clear stop reason */ + + /* Main instruction fetch/decode loop */ + + while (reason == 0) { /* loop until halted */ + if (i8088_dev.dctrl & DEBUG_asm) + printf("\n"); + if (i8088_dev.dctrl & DEBUG_reg) { + printf("Regs: AX=%04X BX=%04X CX=%04X DX=%04X SP=%04X BP=%04X SI=%04X DI=%04X IP=%04X\n", + AX, BX, CX, DX, SP, BP, SI, DI, IP); + printf("Segs: CS=%04X DS=%04X ES=%04X SS=%04X ", CS, DS, ES, SS); + printf("Flags: %04X\n", PSW); + } + + if (sim_interval <= 0) { /* check clock queue */ + if (reason = sim_process_event ()) break; + } + sim_interval--; /* countdown clock */ + + if (int_req > 0) { /* interrupt? */ + + /* 8088 interrupts not implemented yet. */ + + } /* end interrupt */ + + if (sim_brk_summ && + sim_brk_test (IP, SWMASK ('E'))) { /* breakpoint? */ + reason = STOP_IBKPT; /* stop simulation */ + break; + } + + + PCX = IP; + IR = OP = fetch_byte(0); /* fetch instruction */ + + + + /* Handle below all operations which refer to registers or + register pairs. After that, a large switch statement + takes care of all other opcodes */ + + /* data transfer instructions */ + + /* arithmetic instructions */ + + /* bit manipulation instructions */ + /* string manipulation instructions */ + /* control transfer instructions */ + /* processor control instructions */ + /* The Big Instruction Decode Switch */ + + switch (IR) { + + /* data transfer instructions */ + /* arithmetic instructions */ + + case 0x00: /* ADD byte - REG = REG + (EA) */ + MRR = fetch_byte(1); + get_mrr_dec(MRR, &MOD, ®, &RM); + if (MOD != 0x3) { /* based, indexed, or based indexed addressing */ /* based, indexed, or based indexed addressing */ + EA = get_ea(MRR); /* get effective address */ + VAL = add_byte(get_rbyte(REG), get_smbyte(seg_reg, EA)); /* do operation */ + put_rbyte(REG, VAL); /* store result */ + } else { /* RM is second register */ + VAL = add_byte(get_rbyte(REG), get_rbyte(RM)); /* do operation */ + put_rbyte(REG, VAL); /* store result */ + } + break; + + case 0x01: /* ADD word - (EA) = (EA) + REG */ + MRR = fetch_byte(1); + get_mrr_dec(MRR, &MOD, ®, &RM); + if (MOD != 0x3) { /* based, indexed, or based indexed addressing */ + EA = get_ea(MRR); /* get effective address */ + VAL = add_word(get_rword(REG), get_smword(seg_reg, EA)); /* do operation */ + put_smword(seg_reg, EA, VAL); /* store result */ + } else { /* RM is second register */ + VAL = add_word(get_rword(REG), get_rword(RM)); /* do operation */ + put_rword(REG, VAL); /* store result */ + } + break; + + case 0x02: /* ADD byte - REG = REG + (EA) */ + MRR = fetch_byte(1); + get_mrr_dec(MRR, &MOD, ®, &RM); + if (MOD != 0x3) { /* based, indexed, or based indexed addressing */ + EA = get_ea(MRR); /* get effective address */ + VAL = add_byte(get_rbyte(REG), get_smbyte(seg_reg, EA)); /* do operation */ + put_rbyte(REG, VAL); /* store result */ + } else { /* RM is second register */ + VAL = add_byte(get_rbyte(REG), get_rbyte(RM)); /* do operation */ + put_rbyte(REG, VAL); /* store result */ + } + break; + + case 0x03: /* ADD word - (EA) = (EA) + REG */ + MRR = fetch_byte(1); + get_mrr_dec(MRR, &MOD, ®, &RM); + if (MOD != 0x3) { /* based, indexed, or based indexed addressing */ + EA = get_ea(MRR); /* get effective address */ + VAL = adc_word(get_rword(REG), get_smword(seg_reg, EA)); /* do operation */ + put_smbyte(seg_reg, EA, VAL); /* store result */ + } else { /* RM is second register */ + VAL = adc_word(get_rword(REG), get_rword(RM)); /* do operation */ + put_rbyte(REG, VAL); /* store result */ + } + break; + + case 0x04: /* ADD byte - AL = AL + DATA */ + DATA = fetch_byte(1); + VAL = add_byte(AL, DATA); /* do operation */ + AL = VAL; /* store result */ + break; + + case 0x05: /* ADD word - (EA) = (EA) + REG */ + DATA = fetch_word(); + VAL = add_word(AX, DATA); /* do operation */ + AX = VAL; /* store result */ + break; + + case 0x06: /* PUSH ES */ + push_word(ES); + break; + + case 0x07: /* POP ES */ + ES = pop_word(); + break; + + case 0x08: /* OR byte - REG = REG OR (EA) */ + MRR = fetch_byte(1); + get_mrr_dec(MRR, &MOD, ®, &RM); + if (MOD != 0x3) { /* based, indexed, or based indexed addressing */ + EA = get_ea(MRR); /* get effective address */ + VAL = or_byte(get_rbyte(REG), get_smbyte(seg_reg, EA)); /* do operation */ + put_rbyte(REG, VAL); /* store result */ + } else { /* RM is second register */ + VAL = or_byte(get_rbyte(REG), get_rbyte(RM)); /* do operation */ + put_rbyte(REG, VAL); /* store result */ + } + break; + + case 0x09: /* OR word - (EA) = (EA) OR REG */ + MRR = fetch_byte(1); + get_mrr_dec(MRR, &MOD, ®, &RM); + if (MOD != 0x3) { /* based, indexed, or based indexed addressing */ + EA = get_ea(MRR); /* get effective address */ + VAL = or_word(get_rword(REG), get_smword(seg_reg, EA)); /* do operation */ + put_smword(seg_reg, EA, VAL); /* store result */ + } else { /* RM is second register */ + VAL = or_word(get_rword(REG), get_rword(RM)); /* do operation */ + put_rword(REG, VAL); /* store result */ + } + break; + + case 0x0A: /* OR byte - REG = REG OR (EA) */ + MRR = fetch_byte(1); + get_mrr_dec(MRR, &MOD, ®, &RM); + if (MOD != 0x3) { /* based, indexed, or based indexed addressing */ + EA = get_ea(MRR); /* get effective address */ + VAL = or_byte(get_rbyte(REG), get_smbyte(seg_reg, EA)); /* do operation */ + put_rbyte(REG, VAL); /* store result */ + } else { /* RM is second register */ + VAL = or_byte(get_rbyte(REG), get_rbyte(RM)); /* do operation */ + put_rbyte(REG, VAL); /* store result */ + } + break; + + case 0x0B: /* OR word - (EA) = (EA) OR REG */ + MRR = fetch_byte(1); + get_mrr_dec(MRR, &MOD, ®, &RM); + if (MOD != 0x3) { /* based, indexed, or based indexed addressing */ + EA = get_ea(MRR); /* get effective address */ + VAL = or_word(get_rword(REG), get_smword(seg_reg, EA)); /* do operation */ + put_smbyte(seg_reg, EA, VAL); /* store result */ + } else { /* RM is second register */ + VAL = or_word(get_rword(REG), get_rword(RM)); /* do operation */ + put_rbyte(REG, VAL); /* store result */ + } + break; + + case 0x0C: /* OR byte - AL = AL OR DATA */ + DATA = fetch_byte(1); + VAL = or_byte(AL, DATA); /* do operation */ + AL = VAL; /* store result */ + break; + + case 0x0D: /* OR word - (EA) = (EA) OR REG */ + DATA = fetch_word(); + VAL = or_word(AX, DATA); /* do operation */ + AX = VAL; /* store result */ + break; + + case 0x0E: /* PUSH CS */ + push_word(CS); + break; + + /* 0x0F - Not implemented on 8086/8088 */ + + case 0x10: /* ADC byte - REG = REG + (EA) + CF */ + MRR = fetch_byte(1); + get_mrr_dec(MRR, &MOD, ®, &RM); + if (MOD != 0x3) { /* based, indexed, or based indexed addressing */ + EA = get_ea(MRR); /* get effective address */ + VAL = adc_byte(get_rbyte(REG), get_smbyte(seg_reg, EA)); /* do operation */ + put_rbyte(REG, VAL); /* store result */ + } else { /* RM is second register */ + VAL = adc_byte(get_rbyte(REG), get_rbyte(RM)); /* do operation */ + put_rbyte(REG, VAL); /* store result */ + } + break; + + case 0x11: /* ADC word - (EA) = (EA) + REG + CF */ + MRR = fetch_byte(1); + get_mrr_dec(MRR, &MOD, ®, &RM); + if (MOD != 0x3) { /* based, indexed, or based indexed addressing */ + EA = get_ea(MRR); /* get effective address */ + VAL = adc_word(get_rword(REG), get_smword(seg_reg, EA)); /* do operation */ + put_smword(seg_reg, EA, VAL); /* store result */ + } else { /* RM is second register */ + VAL = adc_word(get_rword(REG), get_rword(RM)); /* do operation */ + put_rbyte(REG, VAL); /* store result */ + } + break; + + case 0x12: /* ADC byte - REG = REG + (EA) + CF */ + MRR = fetch_byte(1); + get_mrr_dec(MRR, &MOD, ®, &RM); + if (MOD != 0x3) { /* based, indexed, or based indexed addressing */ + EA = get_ea(MRR); /* get effective address */ + VAL = adc_byte(get_rbyte(REG), get_smbyte(seg_reg, EA)); /* do operation */ + put_rbyte(REG, VAL); /* store result */ + } else { /* RM is second register */ + VAL = adc_byte(get_rbyte(REG), get_rbyte(RM)); /* do operation */ + put_rbyte(REG, VAL); /* store result */ + } + break; + + case 0x13: /* ADC word - (EA) = (EA) + REG + CF */ + MRR = fetch_byte(1); + get_mrr_dec(MRR, &MOD, ®, &RM); + if (MOD != 0x3) { /* based, indexed, or based indexed addressing */ + EA = get_ea(MRR); /* get effective address */ + VAL = adc_word(get_rword(REG), get_smword(seg_reg, EA)); /* do operation */ + put_smbyte(seg_reg, EA, VAL); /* store result */ + } else { /* RM is second register */ + VAL = adc_word(get_rword(REG), get_rword(RM)); /* do operation */ + put_rbyte(REG, VAL); /* store result */ + } + break; + + case 0x14: /* ADC byte - AL = AL + DATA + CF */ + DATA = fetch_byte(1); + VAL = adc_byte(AL, DATA); /* do operation */ + AL = VAL; /* store result */ + break; + + case 0x15: /* ADC word - (EA) = (EA) + REG + CF */ + DATA = fetch_word(); + VAL = adc_word(AX, DATA); /* do operation */ + AX = VAL; /* store result */ + break; + + case 0x16: /* PUSH SS */ + push_word(SS); + break; + + case 0x17: /* POP SS */ + SS = pop_word(); + break; + + case 0x18: /* SBB byte - REG = REG - (EA) - CF */ + MRR = fetch_byte(1); + get_mrr_dec(MRR, &MOD, ®, &RM); + if (MOD != 0x3) { /* based, indexed, or based indexed addressing */ + EA = get_ea(MRR); /* get effective address */ + VAL = sbb_byte(get_rbyte(REG), get_smbyte(seg_reg, EA)); /* do operation */ + put_rbyte(REG, VAL); /* store result */ + } else { /* RM is second register */ + VAL = sbb_byte(get_rbyte(REG), get_rbyte(RM)); /* do operation */ + put_rbyte(REG, VAL); /* store result */ + } + break; + + case 0x19: /* SBB word - (EA) = (EA) - REG - CF */ + MRR = fetch_byte(1); + get_mrr_dec(MRR, &MOD, ®, &RM); + if (MOD != 0x3) { /* based, indexed, or based indexed addressing */ + EA = get_ea(MRR); /* get effective address */ + VAL = sbb_word(get_rword(REG), get_smword(seg_reg, EA)); /* do operation */ + put_smword(seg_reg, EA, VAL); /* store result */ + } else { /* RM is second register */ + VAL = sbb_word(get_rword(REG), get_rword(RM)); /* do operation */ + put_rbyte(REG, VAL); /* store result */ + } + break; + + case 0x1A: /* SBB byte - REG = REG - (EA) - CF */ + MRR = fetch_byte(1); + get_mrr_dec(MRR, &MOD, ®, &RM); + if (MOD != 0x3) { /* based, indexed, or based indexed addressing */ + EA = get_ea(MRR); /* get effective address */ + VAL = sbb_byte(get_rbyte(REG), get_smbyte(seg_reg, EA)); /* do operation */ + put_rbyte(REG, VAL); /* store result */ + } else { /* RM is second register */ + VAL = sbb_byte(get_rbyte(REG), get_rbyte(RM)); /* do operation */ + put_rbyte(REG, VAL); /* store result */ + } + break; + + case 0x1B: /* SBB word - (EA) = (EA) - REG - CF */ + MRR = fetch_byte(1); + get_mrr_dec(MRR, &MOD, ®, &RM); + if (MOD != 0x3) { /* based, indexed, or based indexed addressing */ + EA = get_ea(MRR); /* get effective address */ + VAL = sbb_word(get_rword(REG), get_smword(seg_reg, EA)); /* do operation */ + put_smbyte(seg_reg, EA, VAL); /* store result */ + } else { /* RM is second register */ + VAL = sbb_word(get_rword(REG), get_rword(RM)); /* do operation */ + put_rbyte(REG, VAL); /* store result */ + } + break; + + case 0x1C: /* SBB byte - AL = AL - DATA - CF */ + DATA = fetch_byte(1); + VAL = sbb_byte(AL, DATA); /* do operation */ + AL = VAL; /* store result */ + break; + + case 0x1D: /* SBB word - (EA) = (EA) - REG - CF */ + DATA = fetch_word(); + VAL = sbb_word(AX, DATA); /* do operation */ + AX = VAL; /* store result */ + break; + + case 0x1E: /* PUSH DS */ + push_word(DS); + break; + + case 0x1F: /* POP DS */ + DS = pop_word(); + break; + + case 0x20: /* AND byte - REG = REG AND (EA) */ + MRR = fetch_byte(1); + get_mrr_dec(MRR, &MOD, ®, &RM); + if (MOD != 0x3) { /* based, indexed, or based indexed addressing */ + EA = get_ea(MRR); /* get effective address */ + VAL = and_byte(get_rbyte(REG), get_smbyte(seg_reg, EA)); /* do operation */ + put_rbyte(REG, VAL); /* store result */ + } else { /* RM is second register */ + VAL = and_byte(get_rbyte(REG), get_rbyte(RM)); /* do operation */ + put_rbyte(REG, VAL); /* store result */ + } + break; + + case 0x21: /* AND word - (EA) = (EA) AND REG */ + MRR = fetch_byte(1); + get_mrr_dec(MRR, &MOD, ®, &RM); + if (MOD != 0x3) { /* based, indexed, or based indexed addressing */ + EA = get_ea(MRR); /* get effective address */ + VAL = and_word(get_rword(REG), get_smword(seg_reg, EA)); /* do operation */ + put_smword(seg_reg, EA, VAL); /* store result */ + } else { /* RM is second register */ + VAL = and_word(get_rword(REG), get_rword(RM)); /* do operation */ + put_rbyte(REG, VAL); /* store result */ + } + break; + + case 0x22: /* AND byte - REG = REG AND (EA) */ + MRR = fetch_byte(1); + get_mrr_dec(MRR, &MOD, ®, &RM); + if (MOD != 0x3) { /* based, indexed, or based indexed addressing */ + EA = get_ea(MRR); /* get effective address */ + VAL = and_byte(get_rbyte(REG), get_smbyte(seg_reg, EA)); /* do operation */ + put_rbyte(REG, VAL); /* store result */ + } else { /* RM is second register */ + VAL = and_byte(get_rbyte(REG), get_rbyte(RM)); /* do operation */ + put_rbyte(REG, VAL); /* store result */ + } + break; + + case 0x23: /* AND word - (EA) = (EA) AND REG */ + MRR = fetch_byte(1); + get_mrr_dec(MRR, &MOD, ®, &RM); + if (MOD != 0x3) { /* based, indexed, or based indexed addressing */ + EA = get_ea(MRR); /* get effective address */ + VAL = and_word(get_rword(REG), get_smword(seg_reg, EA)); /* do operation */ + put_smbyte(seg_reg, EA, VAL); /* store result */ + } else { /* RM is second register */ + VAL = and_word(get_rword(REG), get_rword(RM)); /* do operation */ + put_rbyte(REG, VAL); /* store result */ + } + break; + + case 0x24: /* AND byte - AL = AL AND DATA */ + DATA = fetch_byte(1); + VAL = and_byte(AL, DATA); /* do operation */ + AL = VAL; /* store result */ + break; + + case 0x25: /* AND word - (EA) = (EA) AND REG */ + DATA = fetch_word(); + VAL = and_word(AX, DATA); /* do operation */ + AX = VAL; /* store result */ + break; + + case 0x26: /* ES: - segment override prefix */ + seg_ovr = SEG_ES; + sysmode |= SYSMODE_SEGOVR_ES; + break; + + case 0x27: /* DAA */ + if (((AL & 0xF) > 9) || GET_FLAG(AF)) { + AL += 6; + SET_FLAG(AF); + } + if ((AL > 0x9F) || GET_FLAG(CF)) { + AL += 0x60; + SET_FLAG(CF); + } + break; + + case 0x28: /* SUB byte - REG = REG - (EA) */ + MRR = fetch_byte(1); + get_mrr_dec(MRR, &MOD, ®, &RM); + if (MOD != 0x3) { /* based, indexed, or based indexed addressing */ + EA = get_ea(MRR); /* get effective address */ + VAL = sub_byte(get_rbyte(REG), get_smbyte(seg_reg, EA)); /* do operation */ + put_rbyte(REG, VAL); /* store result */ + } else { /* RM is second register */ + VAL = sub_byte(get_rbyte(REG), get_rbyte(RM)); /* do operation */ + put_rbyte(REG, VAL); /* store result */ + } + break; + + case 0x29: /* SUB word - (EA) = (EA) - REG */ + MRR = fetch_byte(1); + get_mrr_dec(MRR, &MOD, ®, &RM); + if (MOD != 0x3) { /* based, indexed, or based indexed addressing */ + EA = get_ea(MRR); /* get effective address */ + VAL = sub_word(get_rword(REG), get_smword(seg_reg, EA)); /* do operation */ + put_smword(seg_reg, EA, VAL); /* store result */ + } else { /* RM is second register */ + VAL = sub_word(get_rword(REG), get_rword(RM)); /* do operation */ + put_rbyte(REG, VAL); /* store result */ + } + break; + + case 0x2A: /* SUB byte - REG = REG - (EA) */ + MRR = fetch_byte(1); + get_mrr_dec(MRR, &MOD, ®, &RM); + if (MOD != 0x3) { /* based, indexed, or based indexed addressing */ + EA = get_ea(MRR); /* get effective address */ + VAL = sub_byte(get_rbyte(REG), get_smbyte(seg_reg, EA)); /* do operation */ + put_rbyte(REG, VAL); /* store result */ + } else { /* RM is second register */ + VAL = sub_byte(get_rbyte(REG), get_rbyte(RM)); /* do operation */ + put_rbyte(REG, VAL); /* store result */ + } + break; + + case 0x2B: /* SUB word - (EA) = (EA) - REG */ + MRR = fetch_byte(1); + get_mrr_dec(MRR, &MOD, ®, &RM); + if (MOD != 0x3) { /* based, indexed, or based indexed addressing */ + EA = get_ea(MRR); /* get effective address */ + VAL = sub_word(get_rword(REG), get_smword(seg_reg, EA)); /* do operation */ + put_smbyte(seg_reg, EA, VAL); /* store result */ + } else { /* RM is second register */ + VAL = sub_word(get_rword(REG), get_rword(RM)); /* do operation */ + put_rbyte(REG, VAL); /* store result */ + } + break; + + case 0x2C: /* SUB byte - AL = AL - DATA */ + DATA = fetch_byte(1); + VAL = sub_byte(AL, DATA); /* do operation */ + AL = VAL; /* store result */ + break; + + case 0x2D: /* SUB word - (EA) = (EA) - REG */ + DATA = fetch_word(); + VAL = sub_word(AX, DATA); /* do operation */ + AX = VAL; /* store result */ + break; + + case 0x2E: /* DS: - segment override prefix */ + seg_ovr = SEG_DS; + sysmode |= SYSMODE_SEGOVR_DS; + break; + + case 0x2F: /* DAS */ + if (((AL & 0xF) > 9) || GET_FLAG(AF)) { + AL -= 6; + SET_FLAG(AF); + } + if ((AL > 0x9F) || GET_FLAG(CF)) { + AL -= 0x60; + SET_FLAG(CF); + } + break; + + case 0x30: /* XOR byte - REG = REG XOR (EA) */ + MRR = fetch_byte(1); + get_mrr_dec(MRR, &MOD, ®, &RM); + if (MOD != 0x3) { /* based, indexed, or based indexed addressing */ + EA = get_ea(MRR); /* get effective address */ + VAL = xor_byte(get_rbyte(REG), get_smbyte(seg_reg, EA)); /* do operation */ + put_rbyte(REG, VAL); /* store result */ + } else { /* RM is second register */ + VAL = xor_byte(get_rbyte(REG), get_rbyte(RM)); /* do operation */ + put_rbyte(REG, VAL); /* store result */ + } + break; + + case 0x31: /* XOR word - (EA) = (EA) XOR REG */ + MRR = fetch_byte(1); + get_mrr_dec(MRR, &MOD, ®, &RM); + if (MOD != 0x3) { /* based, indexed, or based indexed addressing */ + EA = get_ea(MRR); /* get effective address */ + VAL = xor_word(get_rword(REG), get_smword(seg_reg, EA)); /* do operation */ + put_smword(seg_reg, EA, VAL); /* store result */ + } else { /* RM is second register */ + VAL = xor_word(get_rword(REG), get_rword(RM)); /* do operation */ + put_rbyte(REG, VAL); /* store result */ + } + break; + + case 0x32: /* XOR byte - REG = REG XOR (EA) */ + MRR = fetch_byte(1); + get_mrr_dec(MRR, &MOD, ®, &RM); + if (MOD != 0x3) { /* based, indexed, or based indexed addressing */ + EA = get_ea(MRR); /* get effective address */ + VAL = xor_byte(get_rbyte(REG), get_smbyte(seg_reg, EA)); /* do operation */ + put_rbyte(REG, VAL); /* store result */ + } else { /* RM is second register */ + VAL = xor_byte(get_rbyte(REG), get_rbyte(RM)); /* do operation */ + put_rbyte(REG, VAL); /* store result */ + } + break; + + case 0x33: /* XOR word - (EA) = (EA) XOR REG */ + MRR = fetch_byte(1); + get_mrr_dec(MRR, &MOD, ®, &RM); + if (MOD != 0x3) { /* based, indexed, or based indexed addressing */ + EA = get_ea(MRR); /* get effective address */ + VAL = xor_word(get_rword(REG), get_smword(seg_reg, EA)); /* do operation */ + put_smbyte(seg_reg, EA, VAL); /* store result */ + } else { /* RM is second register */ + VAL = xor_word(get_rword(REG), get_rword(RM)); /* do operation */ + put_rbyte(REG, VAL); /* store result */ + } + break; + + case 0x34: /* XOR byte - AL = AL XOR DATA */ + DATA = fetch_byte(1); + VAL = xor_byte(AL, DATA); /* do operation */ + AL = VAL; /* store result */ + break; + + case 0x35: /* XOR word - (EA) = (EA) XOR REG */ + DATA = fetch_word(); + VAL = xor_word(AX, DATA); /* do operation */ + AX = VAL; /* store result */ + break; + + case 0x36: /* SS: - segment override prefix */ + seg_ovr = SEG_SS; + sysmode |= SYSMODE_SEGOVR_SS; + break; + + case 0x37: /* AAA */ + if (((AL & 0xF) > 9) || GET_FLAG(AF)) { + AL += 6; + AH++; + SET_FLAG(AF); + } + CONDITIONAL_SET_FLAG(GET_FLAG(AF), CF); + AL &= 0xF; + break; + + case 0x38: /* CMP byte - CMP (REG, (EA)) */ + MRR = fetch_byte(1); + get_mrr_dec(MRR, &MOD, ®, &RM); + if (MOD != 0x3) { /* based, indexed, or based indexed addressing */ + EA = get_ea(MRR); /* get effective address */ + VAL = xor_byte(get_rbyte(REG), get_smbyte(seg_reg, EA)); /* do operation */ + put_rbyte(REG, VAL); /* store result */ + } else { /* RM is second register */ + VAL = xor_byte(get_rbyte(REG), get_rbyte(RM)); /* do operation */ + put_rbyte(REG, VAL); /* store result */ + } + break; + + case 0x39: /* CMP word - CMP ((EA), REG) */ + MRR = fetch_byte(1); + get_mrr_dec(MRR, &MOD, ®, &RM); + if (MOD != 0x3) { /* based, indexed, or based indexed addressing */ + EA = get_ea(MRR); /* get effective address */ + VAL = xor_word(get_rword(REG), get_smword(seg_reg, EA)); /* do operation */ + put_smword(seg_reg, EA, VAL); /* store result */ + } else { /* RM is second register */ + VAL = xor_word(get_rword(REG), get_rword(RM)); /* do operation */ + put_rbyte(REG, VAL); /* store result */ + } + break; + + case 0x3A: /* CMP byte - CMP (REG, (EA)) */ + MRR = fetch_byte(1); + get_mrr_dec(MRR, &MOD, ®, &RM); + if (MOD != 0x3) { /* based, indexed, or based indexed addressing */ + EA = get_ea(MRR); /* get effective address */ + VAL = xor_byte(get_rbyte(REG), get_smbyte(seg_reg, EA)); /* do operation */ + put_rbyte(REG, VAL); /* store result */ + } else { /* RM is second register */ + VAL = xor_byte(get_rbyte(REG), get_rbyte(RM)); /* do operation */ + put_rbyte(REG, VAL); /* store result */ + } + break; + + case 0x3B: /* CMP word - CMP ((EA), REG) */ + MRR = fetch_byte(1); + get_mrr_dec(MRR, &MOD, ®, &RM); + if (MOD != 0x3) { /* based, indexed, or based indexed addressing */ + EA = get_ea(MRR); /* get effective address */ + VAL = xor_word(get_rword(REG), get_smword(seg_reg, EA)); /* do operation */ + put_smbyte(seg_reg, EA, VAL); /* store result */ + } else { /* RM is second register */ + VAL = xor_word(get_rword(REG), get_rword(RM)); /* do operation */ + put_rbyte(REG, VAL); /* store result */ + } + break; + + case 0x3C: /* CMP byte - CMP (AL, DATA) */ + DATA = fetch_byte(1); + VAL = xor_byte(AL, DATA); /* do operation */ + AL = VAL; /* store result */ + break; + + case 0x3D: /* CMP word - CMP ((EA), REG) */ + DATA = fetch_word(); + VAL = xor_word(AX, DATA); /* do operation */ + AX = VAL; /* store result */ + break; + + case 0x3E: /* DS: - segment override prefix */ + seg_ovr = SEG_DS; + sysmode |= SYSMODE_SEGOVR_DS; + break; + + case 0x3F: /* AAS */ + if (((AL & 0xF) > 9) || GET_FLAG(AF)) { + AL -= 6; + AH--; + SET_FLAG(AF); + } + CONDITIONAL_SET_FLAG(GET_FLAG(AF), CF); + AL &= 0xF; + break; + + case 0x40: /* INC AX */ + AX = inc_word(AX); + break; + + case 0x41: /* INC CX */ + CX = inc_word(CX); + break; + + case 0x42: /* INC DX */ + DX = inc_word(DX); + break; + + case 0x43: /* INC BX */ + BX = inc_word(BX); + break; + + case 0x44: /* INC SP */ + SP = inc_word(SP); + break; + + case 0x45: /* INC BP */ + BP = inc_word(BP); + break; + + case 0x46: /* INC SI */ + SI = inc_word(SI); + break; + + case 0x47: /* INC DI */ + DI = inc_word(DI); + break; + + case 0x48: /* DEC AX */ + AX = dec_word(AX); + break; + + case 0x49: /* DEC CX */ + CX = dec_word(CX); + break; + + case 0x4A: /* DEC DX */ + DX = dec_word(DX); + break; + + case 0x4B: /* DEC BX */ + BX = dec_word(BX); + break; + + case 0x4C: /* DEC SP */ + SP = dec_word(SP); + break; + + case 0x4D: /* DEC BP */ + BP = dec_word(BP); + break; + + case 0x4E: /* DEC SI */ + SI = dec_word(SI); + break; + + case 0x4F: /* DEC DI */ + DI = dec_word(DI); + break; + + case 0x50: /* PUSH AX */ + push_word(AX); + break; + + case 0x51: /* PUSH CX */ + push_word(CX); + break; + + case 0x52: /* PUSH DX */ + push_word(DX); + break; + + case 0x53: /* PUSH BX */ + push_word(BX); + break; + + case 0x54: /* PUSH SP */ + push_word(SP); + break; + + case 0x55: /* PUSH BP */ + push_word(BP); + break; + + case 0x56: /* PUSH SI */ + push_word(SI); + break; + + case 0x57: /* PUSH DI */ + push_word(DI); + break; + + case 0x58: /* POP AX */ + AX = pop_word(); + break; + + case 0x59: /* POP CX */ + CX = pop_word(); + break; + + case 0x5A: /* POP DX */ + DX = pop_word(); + break; + + case 0x5B: /* POP BX */ + BX = pop_word(); + break; + + case 0x5C: /* POP SP */ + SP = pop_word(); + break; + + case 0x5D: /* POP BP */ + BP = pop_word(); + break; + + case 0x5E: /* POP SI */ + SI = pop_word(); + break; + + case 0x5F: /* POP DI */ + DI = pop_word(); + break; + + /* 0x60 - 0x6F - Not implemented on 8086/8088 */ + + case 0x70: /* JO short label */ + /* jump to byte offset if overflow flag is set */ + OFF = sign_ext(fetch_byte(1)); + EA = (IP + OFF) & ADDRMASK16; + if (GET_FLAG(OF)) + IP = EA; + break; + + case 0x71: /* JNO short label */ + /* jump to byte offset if overflow flag is clear */ + OFF = sign_ext(fetch_byte(1)); + EA = (IP + OFF) & ADDRMASK16; + if (!GET_FLAG(OF)) + IP = EA; + break; + + case 0x72: /* JB/JNAE/JC short label */ + /* jump to byte offset if carry flag is set. */ + OFF = sign_ext(fetch_byte(1)); + EA = (IP + OFF) & ADDRMASK16; + if (GET_FLAG(CF)) + IP = EA; + break; + + case 0x73: /* JNB/JAE/JNC short label */ + /* jump to byte offset if carry flsg is clear */ + OFF = sign_ext(fetch_byte(1)); + EA = (IP + OFF) & ADDRMASK16; + if (!GET_FLAG(CF)) + IP = EA; + break; + + case 0x74: /* JE/JZ short label */ + /* jump to byte offset if zero flag is set */ + OFF = sign_ext(fetch_byte(1)); + EA = (IP + OFF) & ADDRMASK16; + if (GET_FLAG(ZF)) + IP = EA; + break; + + case 0x75: /* JNE/JNZ short label */ + /* jump to byte offset if zero flag is clear */ + OFF = sign_ext(fetch_byte(1)); + EA = (IP + OFF) & ADDRMASK16; + if (!GET_FLAG(ZF)) + IP = EA; + break; + + case 0x76: /* JBE/JNA short label */ + /* jump to byte offset if carry flag is set or if the zero + flag is set. */ + OFF = sign_ext(fetch_byte(1)); + EA = (IP + OFF) & ADDRMASK16; + if (GET_FLAG(CF) || GET_FLAG(ZF)) + IP = EA; + break; + + case 0x77: /* JNBE/JA short label */ + /* jump to byte offset if carry flag is clear and if the zero + flag is clear */ + OFF = sign_ext(fetch_byte(1)); + EA = (IP + OFF) & ADDRMASK16; + if (!(GET_FLAG(CF) || GET_FLAG(ZF))) + IP = EA; + break; + + case 0x78: /* JS short label */ + /* jump to byte offset if sign flag is set */ + OFF = sign_ext(fetch_byte(1)); + EA = (IP + OFF) & ADDRMASK16; + if (GET_FLAG(SF)) + IP = EA; + break; + + case 0x79: /* JNS short label */ + /* jump to byte offset if sign flag is clear */ + OFF = sign_ext(fetch_byte(1)); + EA = (IP + OFF) & ADDRMASK16; + if (!GET_FLAG(SF)) + IP = EA; + break; + + case 0x7A: /* JP/JPE short label */ + /* jump to byte offset if parity flag is set (even) */ + OFF = sign_ext(fetch_byte(1)); + EA = (IP + OFF) & ADDRMASK16; + if (GET_FLAG(PF)) + IP = EA; + break; + + case 0x7B: /* JNP/JPO short label */ + /* jump to byte offset if parity flsg is clear (odd) */ + OFF = sign_ext(fetch_byte(1)); + EA = (IP + OFF) & ADDRMASK16; + if (!GET_FLAG(PF)) + IP = EA; + break; + + case 0x7C: /* JL/JNGE short label */ + /* jump to byte offset if sign flag not equal to overflow flag. */ + OFF = sign_ext(fetch_byte(1)); + EA = (IP + OFF) & ADDRMASK16; + if ((GET_FLAG(SF) != 0) ^ (GET_FLAG(OF) != 0)) + IP = EA; + break; + + case 0x7D: /* JNL/JGE short label */ + /* jump to byte offset if sign flag equal to overflow flag. */ + OFF = sign_ext(fetch_byte(1)); + EA = (IP + OFF) & ADDRMASK16; + if ((GET_FLAG(SF) != 0) == (GET_FLAG(OF) != 0)) + IP = EA; + break; + + case 0x7E: /* JLE/JNG short label */ + /* jump to byte offset if sign flag not equal to overflow flag + or the zero flag is set */ + OFF = sign_ext(fetch_byte(1)); + EA = (IP + OFF) & ADDRMASK16; + if (((GET_FLAG(SF) != 0) ^ (GET_FLAG(OF) != 0)) || GET_FLAG(ZF)) + IP = EA; + break; + + case 0x7F: /* JNLE/JG short label */ + /* jump to byte offset if sign flag equal to overflow flag. + and the zero flag is clear*/ + OFF = sign_ext(fetch_byte(1)); + EA = (IP + OFF) & ADDRMASK16; + if (((GET_FLAG(SF) != 0) == (GET_FLAG(OF) != 0)) || !GET_FLAG(ZF)) + IP = EA; + break; + + case 0x80: /* byte operands */ + MRR = fetch_byte(1); + get_mrr_dec(MRR, &MOD, ®, &RM); + if (MOD != 0x3) { /* based, indexed, or based indexed addressing */ + EA = get_ea(MRR); /* get effective address */ + DATA = fetch_byte(1); /* must be done after DISP is collected */ + switch(REG) { + case 0: + VAL = add_byte(get_smbyte(seg_reg, EA), DATA); /* ADD mem8, immed8 */ + break; + case 1: + VAL = or_byte(get_smbyte(seg_reg, EA), DATA); /* OR mem8, immed8 */ + break; + case 2: + VAL = adc_byte(get_smbyte(seg_reg, EA), DATA); /* ADC mem8, immed8 */ + break; + case 3: + VAL = sbb_byte(get_smbyte(seg_reg, EA), DATA); /* SBB mem8, immed8 */ + break; + case 4: + VAL = and_byte(get_smbyte(seg_reg, EA), DATA); /* AND mem8, immed8 */ + break; + case 5: + VAL = sub_byte(get_smbyte(seg_reg, EA), DATA); /* SUB mem8, immed8 */ + break; + case 6: + VAL = xor_byte(get_smbyte(seg_reg, EA), DATA); /* XOR mem8, immed8 */ + break; + case 7: + VAL = cmp_byte(get_smbyte(seg_reg, EA), DATA); /* CMP mem8, immed8 */ + break; + } + put_rbyte(EA, VAL); /* store result */ + } else { /* RM is second register */ + switch(REG) { + case 0: + VAL = add_byte(get_rbyte(RM), DATA); /* ADD REG8, immed8 */ + break; + case 1: + VAL = or_byte(get_rbyte(RM), DATA); /* OR REG8, immed8 */ + break; + case 2: + VAL = adc_byte(get_rbyte(RM), DATA); /* ADC REG8, immed8 */ + break; + case 3: + VAL = sbb_byte(get_rbyte(RM), DATA); /* SBB REG8, immed8 */ + break; + case 4: + VAL = and_byte(get_rbyte(RM), DATA); /* AND REG8, immed8 */ + break; + case 5: + VAL = sub_byte(get_rbyte(RM), DATA); /* SUB REG8, immed8 */ + break; + case 6: + VAL = xor_byte(get_rbyte(RM), DATA); /* XOR REG8, immed8 */ + break; + case 7: + VAL = cmp_byte(get_rbyte(RM), DATA); /* CMP REG8, immed8 */ + break; + } + put_rbyte(REG, VAL); /* store result */ + } + break; + + case 0x81: /* word operands */ + MRR = fetch_byte(1); + get_mrr_dec(MRR, &MOD, ®, &RM); + if (MOD != 0x3) { /* based, indexed, or based indexed addressing */ + EA = get_ea(MRR); /* get effective address */ + DATA = fetch_byte(1) << 8; /* must be done after DISP is collected */ + DATA |= fetch_byte(1); + switch(REG) { + case 0: + VAL = add_word(get_smword(seg_reg, EA), DATA); /* ADD mem16, immed16 */ + break; + case 1: + VAL = or_word(get_smword(seg_reg, EA), DATA); /* OR mem16, immed16 */ + break; + case 2: + VAL = adc_word(get_smword(seg_reg, EA), DATA); /* ADC mem16, immed16 */ + break; + case 3: + VAL = sbb_word(get_smword(seg_reg, EA), DATA); /* SBB mem16, immed16 */ + break; + case 4: + VAL = and_word(get_smword(seg_reg, EA), DATA); /* AND mem16, immed16 */ + break; + case 5: + VAL = sub_word(get_smword(seg_reg, EA), DATA); /* SUB mem16, immed16 */ + break; + case 6: + VAL = xor_word(get_smword(seg_reg, EA), DATA); /* XOR mem16, immed16 */ + break; + case 7: + VAL = cmp_word(get_smword(seg_reg, EA), DATA); /* CMP mem16, immed16 */ + break; + } + put_rword(EA, VAL); /* store result */ + } else { /* RM is second register */ + switch(REG) { + case 0: + VAL = add_word(get_rword(RM), DATA); /* ADD reg16, immed16 */ + break; + case 1: + VAL = or_word(get_rword(RM), DATA); /* OR reg16, immed16 */ + break; + case 2: + VAL = adc_word(get_rword(RM), DATA); /* ADC reg16, immed16 */ + break; + case 3: + VAL = sbb_word(get_rword(RM), DATA); /* SBB reg16, immed16 */ + break; + case 4: + VAL = and_word(get_rword(RM), DATA); /* AND reg16, immed16 */ + break; + case 5: + VAL = sub_word(get_rword(RM), DATA); /* SUB reg16, immed16 */ + break; + case 6: + VAL = xor_word(get_rword(RM), DATA); /* XOR reg16, immed16 */ + break; + case 7: + VAL = cmp_word(get_rword(RM), DATA); /* CMP reg16, immed16 */ + break; + } + put_rword(RM, VAL); /* store result */ + } + break; + + case 0x82: /* byte operands */ + MRR = fetch_byte(1); + get_mrr_dec(MRR, &MOD, ®, &RM); + if (MOD != 0x3) { /* based, indexed, or based indexed addressing */ + EA = get_ea(MRR); /* get effective address */ + DATA = fetch_byte(1); /* must be done after DISP is collected */ + switch(REG) { + case 0: + VAL = add_byte(get_smbyte(seg_reg, EA), DATA); /* ADD mem8, immed8 */ + break; + case 2: + VAL = adc_byte(get_smbyte(seg_reg, EA), DATA); /* ADC mem8, immed8 */ + break; + case 3: + VAL = sbb_byte(get_smbyte(seg_reg, EA), DATA); /* SBB mem8, immed8 */ + break; + case 5: + VAL = sub_byte(get_smbyte(seg_reg, EA), DATA); /* SUB mem8, immed8 */ + break; + case 7: + VAL = cmp_byte(get_smbyte(seg_reg, EA), DATA); /* CMP mem8, immed8 */ + break; + default: /* bad opcodes */ + reason = STOP_OPCODE; + IP -= 2; + break; + } + put_rbyte(EA, VAL); /* store result */ + } else { /* RM is second register */ + switch(REG) { + case 0: + VAL = add_byte(get_rbyte(RM), DATA); /* ADD reg8, immed8 */ + break; + case 2: + VAL = adc_byte(get_rbyte(RM), DATA); /* ADC reg8, immed8 */ + break; + case 3: + VAL = sbb_byte(get_rbyte(RM), DATA); /* SBB reg8, immed8 */ + break; + case 5: + VAL = sub_byte(get_rbyte(RM), DATA); /* SUB reg8, immed8 */ + break; + case 7: + VAL = cmp_byte(get_rbyte(RM), DATA); /* CMP reg8, immed8 */ + break; + default: /* bad opcodes */ + reason = STOP_OPCODE; + IP -= 2; + break; + } + put_rbyte(REG, VAL); /* store result */ + } + break; + + case 0x83: /* word operands */ + MRR = fetch_byte(1); + get_mrr_dec(MRR, &MOD, ®, &RM); + if (MOD != 0x3) { /* based, indexed, or based indexed addressing */ + EA = get_ea(MRR); /* get effective address */ + DATA = fetch_byte(1) << 8; /* must be done after DISP is collected */ + if (DATA & 0x80) + DATA |= 0xFF00; + else + DATA &= 0xFF; + switch(REG) { + case 0: + VAL = add_word(get_smword(seg_reg, EA), DATA); /* ADD mem16, immed8-SX */ + break; + case 2: + VAL = adc_word(get_smword(seg_reg, EA), DATA); /* ADC mem16, immed8-SX */ + break; + case 3: + VAL = sbb_word(get_smword(seg_reg, EA), DATA); /* SBB mem16, immed8-SX */ + break; + case 5: + VAL = sub_word(get_smword(seg_reg, EA), DATA); /* SUB mem16, immed8-SX */ + break; + case 7: + VAL = cmp_word(get_smword(seg_reg, EA), DATA); /* CMP mem16, immed8-SX */ + break; + default: /* bad opcodes */ + reason = STOP_OPCODE; + IP -= 2; + break; + } + put_rword(EA, VAL); /* store result */ + } else { /* RM is second register */ + switch(REG) { + case 0: + VAL = add_word(get_rword(RM), DATA); /* ADD reg16, immed8-SX */ + break; + case 2: + VAL = adc_word(get_rword(RM), DATA); /* ADC reg16, immed8-SX */ + break; + case 3: + VAL = sbb_word(get_rword(RM), DATA); /* SBB reg16, immed8-SX */ + break; + case 5: + VAL = sub_word(get_rword(RM), DATA); /* CUB reg16, immed8-SX */ + break; + case 7: + VAL = cmp_word(get_rword(RM), DATA); /* CMP reg16, immed8-SX */ + break; + default: /* bad opcodes */ + reason = STOP_OPCODE; + IP -= 2; + break; + } + put_rword(RM, VAL); /* store result */ + } + break; + + case 0x84: + MRR = fetch_byte(1); + get_mrr_dec(MRR, &MOD, ®, &RM); + if (MOD != 0x3) { /* based, indexed, or based indexed addressing */ + EA = get_ea(MRR); /* get effective address */ + test_byte(get_smbyte(seg_reg, EA),get_rbyte(REG)); /* TEST mem8, reg8 */ + } else { + test_byte(get_rbyte(REG),get_rbyte(RM)); /* TEST reg8, reg8 */ + } + break; + + case 0x85: + MRR = fetch_byte(1); + get_mrr_dec(MRR, &MOD, ®, &RM); + if (MOD != 0x3) { /* based, indexed, or based indexed addressing */ + EA = get_ea(MRR); /* get effective address */ + test_word(get_smword(seg_reg, EA),get_rword(REG)); /* TEST mem16, reg16 */ + } else { + test_word(get_rword(REG),get_rword(RM)); /* TEST reg16, reg16 */ + } + break; + + case 0x86: + MRR = fetch_byte(1); + get_mrr_dec(MRR, &MOD, ®, &RM); + if (MOD != 0x3) { /* based, indexed, or based indexed addressing */ + EA = get_ea(MRR); /* get effective address */ + VAL = get_rbyte(REG);/* XCHG mem8, reg8 */ + put_rbyte(REG, get_smbyte(seg_reg, EA)); + put_smbyte(seg_reg, EA, VAL); + } else { + VAL = get_rbyte(RM);/* XCHG reg8, reg8 */ + put_rbyte(RM, get_rbyte(REG)); + put_rbyte(REG, VAL); + } + break; + + case 0x87: + MRR = fetch_byte(1); + get_mrr_dec(MRR, &MOD, ®, &RM); + if (MOD != 0x3) { /* based, indexed, or based indexed addressing */ + EA = get_ea(MRR); /* get effective address */ + VAL = get_rword(REG);/* XCHG mem16, reg16 */ + put_rword(REG, get_smword(seg_reg, EA)); + put_smword(seg_reg, EA, VAL); + } else { + VAL = get_rword(RM);/* XCHG reg16, reg16 */ + put_rword(RM, get_rword(REG)); + put_rword(REG, VAL); + } + break; + + case 0x88: + MRR = fetch_byte(1); + get_mrr_dec(MRR, &MOD, ®, &RM); + if (MOD != 0x3) { /* based, indexed, or based indexed addressing */ + EA = get_ea(MRR); /* get effective address */ + put_smbyte(seg_reg, EA, get_rbyte(REG)); /* MOV mem8, reg8 */ + } else + put_rbyte(REG, get_rbyte(RM)); /* MOV reg8, reg8 */ + break; + + case 0x89: + MRR = fetch_byte(1); + get_mrr_dec(MRR, &MOD, ®, &RM); + if (MOD != 0x3) { /* based, indexed, or based indexed addressing */ + EA = get_ea(MRR); /* get effective address */ + put_smword(seg_reg, EA, get_rword(REG)); /* MOV mem16, reg16 */ + } else + put_rword(REG, get_rword(RM)); /* MOV reg16, reg16 */ + break; + + case 0x8A: + MRR = fetch_byte(1); + get_mrr_dec(MRR, &MOD, ®, &RM); + if (MOD != 0x3) { /* based, indexed, or based indexed addressing */ + EA = get_ea(MRR); /* get effective address */ + put_rbyte(REG, get_smbyte(seg_reg, EA)); /* MOV reg8, mem8 */ + } else + put_rbyte(REG, get_rbyte(RM)); /* MOV reg8, reg8 */ + break; + + case 0x8B: + MRR = fetch_byte(1); + get_mrr_dec(MRR, &MOD, ®, &RM); + if (MOD != 0x3) { /* based, indexed, or based indexed addressing */ + EA = get_ea(MRR); /* get effective address */ + put_rword(REG, get_smword(seg_reg, EA)); /* MOV reg16, mem16 */ + } else + put_rword(REG, get_rword(RM)); /* MOV reg16, reg16 */ + break; + + case 0x8C: + MRR = fetch_byte(1); + get_mrr_dec(MRR, &MOD, ®, &RM); + if (MOD != 0x3) { /* based, indexed, or based indexed addressing */ + EA = get_ea(MRR); /* get effective address */ + switch(REG) { + case 0: /* MOV mem16, ES */ + put_smword(seg_reg, EA, ES); + break; + case 1: /* MOV mem16, CS */ + put_smword(seg_reg, EA, CS); + break; + case 2: /* MOV mem16, SS */ + put_smword(seg_reg, EA, SS); + break; + case 3: /* MOV mem16, DS */ + put_smword(seg_reg, EA, DS); + break; + default: /* bad opcodes */ + reason = STOP_OPCODE; + IP -= 2; + break; + } + } else { + switch(REG) { + case 0: /* MOV reg16, ES */ + put_rword(RM, ES); + break; + case 1: /* MOV reg16, CS */ + put_rword(RM, CS); + break; + case 2: /* MOV reg16, SS */ + put_rword(RM, SS); + break; + case 3: /* MOV reg16, DS */ + put_rword(RM, DS); + break; + default: /* bad opcodes */ + reason = STOP_OPCODE; + IP -= 2; + break; + } + } + break; + + case 0x8D: + MRR = fetch_byte(1); + get_mrr_dec(MRR, &MOD, ®, &RM); + if (MOD != 0x3) { /* based, indexed, or based indexed addressing */ + EA = get_ea(MRR); /* get effective address */ + put_rword(REG, EA); /* LEA reg16, mem16 */ + } else { + reason = STOP_OPCODE; + IP -= 2; + } + break; + + case 0x8E: + MRR = fetch_byte(1); + get_mrr_dec(MRR, &MOD, ®, &RM); + if (MOD != 0x3) { /* based, indexed, or based indexed addressing */ + EA = get_ea(MRR); /* get effective address */ + switch(REG) { + case 0: /* MOV ES, mem16 */ + ES = get_smword(seg_reg, EA); + break; + case 1: /* MOV CS, mem16 */ + CS = get_smword(seg_reg, EA); + break; + case 2: /* MOV SS, mem16 */ + SS = get_smword(seg_reg, EA); + break; + case 3: /* MOV DS, mem16 */ + DS = get_smword(seg_reg, EA); + break; + default: /* bad opcodes */ + reason = STOP_OPCODE; + IP -= 2; + break; + } + } else { + switch(REG) { + case 0: /* MOV ES, reg16 */ + ES = get_rword(RM); + break; + case 1: /* MOV CS, reg16 */ + CS = get_rword(RM); + break; + case 2: /* MOV SS, reg16 */ + SS = get_rword(RM); + break; + case 3: /* MOV DS, reg16 */ + DS = get_rword(RM); + break; + default: /* bad opcodes */ + reason = STOP_OPCODE; + IP -= 2; + break; + } + } + break; + + case 0x8f: + MRR = fetch_byte(1); + get_mrr_dec(MRR, &MOD, ®, &RM); + if (MOD != 0x3) { /* based, indexed, or based indexed addressing */ + EA = get_ea(MRR); /* get effective address */ + put_smword(seg_reg, EA, pop_word()); + } else { + reason = STOP_OPCODE; + IP -= 2; + } + break; + + case 0x90: /* NOP */ + break; + + case 0x91: /* XCHG AX, CX */ + VAL = AX; + AX = CX; + CX = VAL; + break; + + case 0x92: /* XCHG AX, DX */ + VAL = AX; + AX = DX; + DX = VAL; + break; + + case 0x93: /* XCHG AX, BX */ + VAL = AX; + AX = BX; + BX = VAL; + break; + + case 0x94: /* XCHG AX, SP */ + VAL = AX; + AX = SP; + SP = VAL; + break; + + case 0x95: /* XCHG AX, BP */ + VAL = AX; + AX = BP; + BP = VAL; + break; + + case 0x96: /* XCHG AX, SI */ + VAL = AX; + AX = SI; + SI = VAL; + break; + + case 0x97: /* XCHG AX, DI */ + VAL = AX; + AX = DI; + DI = VAL; + break; + + case 0x98: /* cbw */ + if (AL & 0x80) + AH = 0xFF; + else + AH = 0; + break; + + case 0x99: /* cbw */ + if (AX & 0x8000) + DX = 0xffff; + else + DX = 0x0; + break; + + case 0x9A: /* CALL FAR proc */ + OFF = fetch_word(); /* do operation */ + SEG = fetch_word(); + push_word(CS); + CS = SEG; + push_word(IP); + IP = OFF; + break; + + case 0x9B: /* WAIT */ + break; + + case 0x9C: /* PUSHF */ + VAL = PSW; + VAL &= PSW_MSK; + VAL |= PSW_ALWAYS_ON; + push_word(VAL); + break; + + case 0x9D: /* POPF */ + PSW = pop_word(); + break; + + case 0x9E: /* SAHF */ + PSW &= 0xFFFFFF00; + PSW |= AH; + break; + + case 0x9F: /* LAHF */ + AH = PSW & 0xFF; + AH |= 0x2; + break; + + case 0xA0: /* MOV AL, mem8 */ + OFF = fetch_word(); + set_segreg(SEG_DS); /* to allow segment override */ + AL = get_smbyte(seg_reg, OFF); + break; + + case 0xA1: /* MOV AX, mem16 */ + OFF = fetch_word(); + set_segreg(SEG_DS); /* to allow segment override */ + AX = get_smword(seg_reg, OFF); + break; + + case 0xA2: /* MOV mem8, AL */ + OFF = fetch_word(); + set_segreg(SEG_DS); /* to allow segment override */ + put_smbyte(seg_reg, OFF, AL); + break; + + case 0xA3: /* MOV mem16, AX */ + OFF = fetch_word(); + set_segreg(SEG_DS); /* to allow segment override */ + put_smword(seg_reg, OFF, AX); + break; + + case 0xA4: /* MOVS dest-str8, src-str8 */ + if (GET_FLAG(DF)) /* down */ + INC = -1; + else + INC = 1; + while (CX != 0) { + VAL = get_smbyte(seg_reg, SI); + put_smbyte(ES, DI, VAL); + CX--; + SI += INC; + DI += INC; + } + break; + + case 0xA5: /* MOVS dest-str16, src-str16 */ + if (GET_FLAG(DF)) /* down */ + INC = -2; + else + INC = 2; + while (CX != 0) { + VAL = get_smword(seg_reg, SI); + put_smword(ES, DI, VAL); + CX--; + SI += INC; + DI += INC; + } + break; + + case 0xA6: /* CMPS dest-str8, src-str8 */ + if (GET_FLAG(DF)) /* down */ + INC = -1; + else + INC = 1; + while (CX != 0) { + VAL = get_smbyte(seg_reg, SI); + VAL1 = get_smbyte(ES, DI); + cmp_byte(VAL, VAL1); + CX--; + SI += INC; + DI += INC; + if (GET_FLAG(ZF) == 0) + break; + } + break; + + case 0xA7: /* CMPS dest-str16, src-str16 */ + if (GET_FLAG(DF)) /* down */ + INC = -2; + else + INC = 2; + while (CX != 0) { + VAL = get_smword(seg_reg, SI); + VAL1 = get_smword(ES, DI); + cmp_word(VAL, VAL1); + CX--; + SI += INC; + DI += INC; + if (GET_FLAG(ZF) == 0) + break; + } + break; + + case 0xA8: /* TEST AL, immed8 */ + VAL = fetch_byte(1); + test_byte(AL, VAL); + break; + + case 0xA9: /* TEST AX, immed8 */ + VAL = fetch_word(); + test_word(AX, VAL); + break; + + case 0xAA: /* STOS dest-str8 */ + if (GET_FLAG(DF)) /* down */ + INC = -1; + else + INC = 1; + if (sysmode & (SYSMODE_PREFIX_REPE | SYSMODE_PREFIX_REPNE)) { + while (CX != 0) { + put_smbyte(ES, DI, AL); + CX--; + DI += INC; + } + sysmode &= ~(SYSMODE_PREFIX_REPE | SYSMODE_PREFIX_REPNE); + } else { + put_smbyte(ES, DI, AL); + DI += INC; + } + break; + + case 0xAB: /* STOS dest-str16 */ + if (GET_FLAG(DF)) /* down */ + INC = -1; + else + INC = 1; + if (sysmode & (SYSMODE_PREFIX_REPE | SYSMODE_PREFIX_REPNE)) { + while (CX != 0) { + put_smword(ES, DI, AX); + CX--; + DI += INC; + } + sysmode &= ~(SYSMODE_PREFIX_REPE | SYSMODE_PREFIX_REPNE); + } else { + put_smword(ES, DI, AL); + DI += INC; + } + break; + + case 0xAC: /* LODS dest-str8 */ + if (GET_FLAG(DF)) /* down */ + INC = -1; + else + INC = 1; + set_segreg(SEG_DS); /* allow overrides */ + if (sysmode & (SYSMODE_PREFIX_REPE | SYSMODE_PREFIX_REPNE)) { + while (CX != 0) { + AL = get_smbyte(seg_reg, SI); + CX--; + SI += INC; + } + sysmode &= ~(SYSMODE_PREFIX_REPE | SYSMODE_PREFIX_REPNE); + } else { + AL = get_smbyte(seg_reg, SI); + SI += INC; + } + break; + + case 0xAD: /* LODS dest-str16 */ + if (GET_FLAG(DF)) /* down */ + INC = -1; + else + INC = 1; + set_segreg(SEG_DS); /* allow overrides */ + if (sysmode & (SYSMODE_PREFIX_REPE | SYSMODE_PREFIX_REPNE)) { + while (CX != 0) { + AX = get_smword(seg_reg, SI); + CX--; + SI += INC; + } + sysmode &= ~(SYSMODE_PREFIX_REPE | SYSMODE_PREFIX_REPNE); + } else { + AX = get_smword(seg_reg, SI); + SI += INC; + } + break; + + case 0xAE: /* SCAS dest-str8 */ + if (GET_FLAG(DF)) /* down */ + INC = -1; + else + INC = 1; + if (sysmode & (SYSMODE_PREFIX_REPE | SYSMODE_PREFIX_REPNE)) { + while (CX != 0) { + VAL = get_smbyte(ES, DI); + cmp_byte(AL, VAL); + CX--; + DI += INC; + if (GET_FLAG(ZF) == 0) + break; + } + sysmode &= ~(SYSMODE_PREFIX_REPE | SYSMODE_PREFIX_REPNE); + } else { + VAL = get_smbyte(ES, DI); + cmp_byte(AL, VAL); + DI += INC; + } + break; + + case 0xAF: /* SCAS dest-str16 */ + if (GET_FLAG(DF)) /* down */ + INC = -2; + else + INC = 2; + if (sysmode & (SYSMODE_PREFIX_REPE | SYSMODE_PREFIX_REPNE)) { + while (CX != 0) { + VAL = get_smword(ES, DI); + cmp_word(AX, VAL); + CX--; + DI += INC; + if (GET_FLAG(ZF) == 0) + break; + } + sysmode &= ~(SYSMODE_PREFIX_REPE | SYSMODE_PREFIX_REPNE); + } else { + VAL = get_smword(ES, DI); + cmp_byte(AL, VAL); + DI += INC; + } + break; + + case 0xB0: /* MOV AL,immed8 */ + AL = fetch_byte(1); + break; + + case 0xB1: /* MOV CL,immed8 */ + CL = fetch_byte(1); + break; + + case 0xB2: /* MOV DL,immed8 */ + DL = fetch_byte(1); + break; + + case 0xB3: /* MOV BL,immed8 */ + BL = fetch_byte(1); + break; + + case 0xB4: /* MOV AH,immed8 */ + AH = fetch_byte(1); + break; + + case 0xB5: /* MOV CH,immed8 */ + CH = fetch_byte(1); + break; + + case 0xB6: /* MOV DH,immed8 */ + DH = fetch_byte(1); + break; + + case 0xB7: /* MOV BH,immed8 */ + BH = fetch_byte(1); + break; + + case 0xB8: /* MOV AX,immed16 */ + AX = fetch_word(); + break; + + case 0xB9: /* MOV CX,immed16 */ + CX = fetch_word(); + break; + + case 0xBA: /* MOV DX,immed16 */ + DX = fetch_word(); + break; + + case 0xBB: /* MOV BX,immed16 */ + BX = fetch_word(); + break; + + case 0xBC: /* MOV SP,immed16 */ + SP = fetch_word(); + break; + + case 0xBD: /* MOV BP,immed16 */ + BP = fetch_word(); + break; + + case 0xBE: /* MOV SI,immed16 */ + SI = fetch_word(); + break; + + case 0xBF: /* MOV DI,immed16 */ + DI = fetch_word(); + break; + + /* 0xC0 - 0xC1 - Not implemented on 8086/8088 */ + + case 0xC2: /* RET immed16 (intrasegment) */ + OFF = fetch_word(); + IP = pop_word(); + SP += OFF; + break; + + case 0xC3: /* RET (intrasegment) */ + IP = pop_word(); + break; + + case 0xC4: + MRR = fetch_byte(1); + get_mrr_dec(MRR, &MOD, ®, &RM); + if (MOD != 0x3) { /* based, indexed, or based indexed addressing */ + EA = get_ea(MRR); /* get effective address */ + put_rword(REG, get_smword(seg_reg, EA)); /* LES mem16 */ + ES = get_smword(seg_reg, EA + 2); + } else { +// put_rword(REG, get_rword(RM)); /* LES reg16 */ +// ES = get_rword(RM) + 2; + /* not defined for 8086 */ + reason = STOP_OPCODE; + IP -= 2; + } + break; + + case 0xC5: + MRR = fetch_byte(1); + get_mrr_dec(MRR, &MOD, ®, &RM); + if (MOD != 0x3) { /* based, indexed, or based indexed addressing */ + EA = get_ea(MRR); /* get effective address */ + put_rword(REG, get_smword(seg_reg, EA)); /* LDS mem16 */ + DS = get_smword(seg_reg, EA + 2); + } else { +// put_rword(REG, get_rword(RM)); /* LDS reg16 */ +// DS = get_rword(RM) + 2; + /* not defined for 8086 */ + reason = STOP_OPCODE; + IP -= 2; + } + break; + + case 0xC6: + MRR = fetch_byte(1); + get_mrr_dec(MRR, &MOD, ®, &RM); + if (REG) { /* has to be 0 */ + reason = STOP_OPCODE; + IP -= 2; + } + if (MOD != 0x3) { /* based, indexed, or based indexed addressing */ + EA = get_ea(MRR); /* get effective address */ + DATA = fetch_byte(1); /* has to be after DISP */ + put_smbyte(seg_reg, EA, DATA); /* MOV mem8, immed8 */ + } else { + put_rbyte(RM, DATA); /* MOV reg8, immed8 */ + } + break; + + case 0xC7: + MRR = fetch_byte(1); + get_mrr_dec(MRR, &MOD, ®, &RM); + if (REG) { /* has to be 0 */ + reason = STOP_OPCODE; + IP -= 2; + } + if (MOD != 0x3) { /* based, indexed, or based indexed addressing */ + EA = get_ea(MRR); /* get effective address */ + DATA = get_mword(IP); /* has to be after DISP */ + put_smword(seg_reg, EA, DATA); /* MOV mem16, immed16 */ + } else { + put_rword(RM, DATA); /* MOV reg16, immed16 */ + } + break; + + /* 0xC8 - 0xC9 - Not implemented on 8086/8088 */ + + case 0xCA: /* RET immed16 (intersegment) */ + OFF = fetch_word(); + IP = pop_word(); + CS = pop_word(); + SP += OFF; + break; + + case 0xCB: /* RET (intersegment) */ + IP = pop_word(); + CS = pop_word(); + break; + + case 0xCC: /* INT 3 */ + push_word(PSW); + CLR_FLAG(IF); + CLR_FLAG(TF); + push_word(CS); + push_word(IP); + CS = get_mword(14); + IP = get_mword(12); + break; + + case 0xCD: /* INT immed8 */ + OFF = fetch_byte(1); + push_word(PSW); + CLR_FLAG(IF); + CLR_FLAG(TF); + push_word(CS); + push_word(IP); + CS = get_mword((OFF * 4) + 2); + IP = get_mword(OFF * 4); + break; + + case 0xCE: /* INTO */ + push_word(PSW); + CLR_FLAG(IF); + CLR_FLAG(TF); + push_word(CS); + push_word(IP); + CS = get_mword(18); + IP = get_mword(16); + break; + + case 0xCF: /* IRET */ + IP = pop_word(); + CS = pop_word(); + PSW = pop_word(); + break; + + case 0xD0: + MRR = fetch_byte(1); + get_mrr_dec(MRR, &MOD, ®, &RM); + if (MOD != 0x3) { /* based, indexed, or based indexed addressing */ + EA = get_ea(MRR); /* get effective address */ + switch(REG) { + case 0: + VAL = rol_byte(get_smbyte(seg_reg, EA), 1); /* ROL mem8, 1 */ + break; + case 1: + VAL = ror_byte(get_smbyte(seg_reg, EA), 1); /* ROR mem8, 1 */ + break; + case 2: + VAL = rcl_byte(get_smbyte(seg_reg, EA), 1); /* RCL mem8, 1 */ + break; + case 3: + VAL = rcr_byte(get_smbyte(seg_reg, EA), 1); /* RCR mem8, 1 */ + break; + case 4: + VAL = shl_byte(get_smbyte(seg_reg, EA), 1); /* SAL/SHL mem8, 1 */ + break; + case 5: + VAL = shr_byte(get_smbyte(seg_reg, EA), 1); /* SHR mem8, 1 */ + break; + case 7: + VAL = sar_byte(get_smbyte(seg_reg, EA), 1); /* SAR mem8, 1 */ + break; + default: /* bad opcodes */ + reason = STOP_OPCODE; + IP -= 2; + break; + } + put_rbyte(EA, VAL); /* store result */ + } else { /* RM is second register */ + switch(REG) { + case 0: + VAL = rol_byte(get_rbyte(RM), 1); /* RCL reg8, 1 */ + break; + case 1: + VAL = ror_byte(get_rbyte(RM), 1); /* ROR reg8, 1 */ + break; + case 2: + VAL = rcl_byte(get_rbyte(RM), 1); /* RCL reg8, 1 */ + break; + case 3: + VAL = rcr_byte(get_rbyte(RM), 1); /* RCR reg8, 1 */ + break; + case 4: + VAL = shl_byte(get_rbyte(RM), 1); /* SHL/SAL reg8, 1*/ + break; + case 5: + VAL = shr_byte(get_rbyte(RM), 1); /* SHR reg8, 1 */ + break; + case 7: + VAL = sar_byte(get_rbyte(RM), 1); /* SAR reg8, 1 */ + break; + default: /* bad opcodes */ + reason = STOP_OPCODE; + IP -= 2; + break; + } + put_rbyte(RM, VAL); /* store result */ + } + break; + + case 0xD1: + MRR = fetch_byte(1); + get_mrr_dec(MRR, &MOD, ®, &RM); + if (MOD != 0x3) { /* based, indexed, or based indexed addressing */ + EA = get_ea(MRR); /* get effective address */ + switch(REG) { + case 0: + VAL = rol_word(get_smword(seg_reg, EA), 1); /* ROL mem16, 1 */ + break; + case 1: + VAL = ror_word(get_smword(seg_reg, EA), 1); /* ROR mem16, 1 */ + break; + case 2: + VAL = rcl_word(get_smword(seg_reg, EA), 1); /* RCL mem16, 1 */ + break; + case 3: + VAL = rcr_word(get_smword(seg_reg, EA), 1); /* RCR mem16, 1 */ + break; + case 4: + VAL = shl_word(get_smword(seg_reg, EA), 1); /* SAL/SHL mem16, 1 */ + break; + case 5: + VAL = shr_word(get_smword(seg_reg, EA), 1); /* SHR mem16, 1 */ + break; + case 7: + VAL = sar_word(get_smword(seg_reg, EA), 1); /* SAR mem16, 1 */ + break; + default: /* bad opcodes */ + reason = STOP_OPCODE; + IP -= 2; + break; + } + put_rword(EA, VAL); /* store result */ + } else { /* RM is second register */ + switch(REG) { + case 0: + VAL = rol_word(get_rword(RM), 1); /* RCL reg16, 1 */ + break; + case 1: + VAL = ror_word(get_rword(RM), 1); /* ROR reg16, 1 */ + break; + case 2: + VAL = rcl_word(get_rword(RM), 1); /* RCL reg16, 1 */ + break; + case 3: + VAL = rcr_word(get_rword(RM), 1); /* RCR reg16, 1 */ + break; + case 4: + VAL = shl_word(get_rword(RM), 1); /* SHL/SAL reg16, 1 */ + break; + case 5: + VAL = shr_word(get_rword(RM), 1); /* SHR reg16, 1 */ + break; + case 7: + VAL = sar_word(get_rword(RM), 1); /* SAR reg16, 1 */ + break; + default: /* bad opcodes */ + reason = STOP_OPCODE; + IP -= 2; + break; + } + put_rbyte(RM, VAL); /* store result */ + } + break; + + case 0xD2: + MRR = fetch_byte(1); + get_mrr_dec(MRR, &MOD, ®, &RM); + if (MOD != 0x3) { /* based, indexed, or based indexed addressing */ + EA = get_ea(MRR); /* get effective address */ + switch(REG) { + case 0: + VAL = rol_byte(get_smbyte(seg_reg, EA), CL); /* ROL mem8, CL */ + break; + case 1: + VAL = ror_byte(get_smbyte(seg_reg, EA), CL); /* ROR mem8, CL */ + break; + case 2: + VAL = rcl_byte(get_smbyte(seg_reg, EA), CL); /* RCL mem8, CL */ + break; + case 3: + VAL = rcr_byte(get_smbyte(seg_reg, EA), CL); /* RCR mem8, CL */ + break; + case 4: + VAL = shl_byte(get_smbyte(seg_reg, EA), CL); /* SAL/SHL mem8, CL */ + break; + case 5: + VAL = shr_byte(get_smbyte(seg_reg, EA), CL); /* SHR mem8, CL */ + break; + case 7: + VAL = sar_byte(get_smbyte(seg_reg, EA), CL); /* SAR mem8, CL */ + break; + default: /* bad opcodes */ + reason = STOP_OPCODE; + IP -= 2; + break; + } + put_rbyte(EA, VAL); /* store result */ + } else { /* RM is second register */ + switch(REG) { + case 0: + VAL = rol_byte(get_rbyte(RM), CL); /* RCL reg8, CL */ + break; + case 1: + VAL = ror_byte(get_rbyte(RM), CL); /* ROR reg8, CL */ + break; + case 2: + VAL = rcl_byte(get_rbyte(RM), CL); /* RCL reg8, CL */ + break; + case 3: + VAL = rcr_byte(get_rbyte(RM), CL); /* RCR reg8, CL */ + break; + case 4: + VAL = shl_byte(get_rbyte(RM), CL); /* SHL/SAL reg8, CL*/ + break; + case 5: + VAL = shr_byte(get_rbyte(RM), CL); /* SHR reg8, CL */ + break; + case 7: + VAL = sar_byte(get_rbyte(RM), CL); /* SAR reg8, CL */ + break; + default: /* bad opcodes */ + reason = STOP_OPCODE; + IP -= 2; + break; + } + put_rbyte(RM, VAL); /* store result */ + } + break; + + case 0xD3: + MRR = fetch_byte(1); + get_mrr_dec(MRR, &MOD, ®, &RM); + if (MOD != 0x3) { /* based, indexed, or based indexed addressing */ + EA = get_ea(MRR); /* get effective address */ + switch(REG) { + case 0: + VAL = rol_word(get_smword(seg_reg, EA), CL); /* ROL mem16, CL */ + break; + case 1: + VAL = ror_word(get_smword(seg_reg, EA), CL); /* ROR mem16, CL */ + break; + case 2: + VAL = rcl_word(get_smword(seg_reg, EA), CL); /* RCL mem16, CL */ + break; + case 3: + VAL = rcr_word(get_smword(seg_reg, EA), CL); /* RCR mem16, CL */ + break; + case 4: + VAL = shl_word(get_smword(seg_reg, EA), CL); /* SAL/SHL mem16, CL */ + break; + case 5: + VAL = shr_word(get_smword(seg_reg, EA), CL); /* SHR mem16, CL */ + break; + case 7: + VAL = sar_word(get_smword(seg_reg, EA), CL); /* SAR mem16, CL */ + break; + default: /* bad opcodes */ + reason = STOP_OPCODE; + IP -= 2; + break; + } + put_rword(EA, VAL); /* store result */ + } else { /* RM is second register */ + switch(REG) { + case 0: + VAL = rol_word(get_rword(RM), CL); /* RCL reg16, CL */ + break; + case 1: + VAL = ror_word(get_rword(RM), CL); /* ROR reg16, CL */ + break; + case 2: + VAL = rcl_word(get_rword(RM), CL); /* RCL reg16, CL */ + break; + case 3: + VAL = rcr_word(get_rword(RM), CL); /* RCR reg16, CL */ + break; + case 4: + VAL = shl_word(get_rword(RM), CL); /* SHL/SAL reg16, CL */ + break; + case 5: + VAL = shr_word(get_rword(RM), CL); /* SHR reg16, CL */ + break; + case 7: + VAL = sar_word(get_rword(RM), CL); /* SAR reg16, CL */ + break; + default: /* bad opcodes */ + reason = STOP_OPCODE; + IP -= 2; + break; + } + put_rbyte(RM, VAL); /* store result */ + } + break; + + case 0xD4: /* AAM */ + VAL = fetch_word(); + if (VAL != 10) { + reason = STOP_OPCODE; + IP -= 2; + } + /* note the type change here --- returning AL and AH in AX. */ + AX = aam_word(AL); + break; + + case 0xD5: /* AAD */ + VAL = fetch_word(); + if (VAL != 10) { + reason = STOP_OPCODE; + IP -= 2; + } + AX = aad_word(AX); + break; + + /* 0xD6 - Not implemented on 8086/8088 */ + + case 0xD7: /* XLAT */ + OFF = BX + (uint8)AL; + AL = get_smbyte(SEG_CS, OFF); + break; + + case 0xD8: /* ESC */ + case 0xD9: + case 0xDA: + case 0xDB: + case 0xDC: + case 0xDD: + case 0xDE: + case 0xDF: + /* for now, do nothing, NOP for 8088 */ + break; + + case 0xE0: /* LOOPNE label */ + OFF = fetch_byte(1); + OFF += (int16)IP; + CX -= 1; + if (CX != 0 && !GET_FLAG(ZF)) /* CX != 0 and !ZF */ + IP = OFF; + break; + + case 0xE1: /* LOOPE label */ + OFF = fetch_byte(1); + OFF += (int16)IP; + CX -= 1; + if (CX != 0 && GET_FLAG(ZF)) /* CX != 0 and ZF */ + IP = OFF; + break; + + case 0xE2: /* LOOP label */ + OFF = fetch_byte(1); + OFF += (int16)IP; + CX -= 1; + if (CX != 0) /* CX != 0 */ + IP = OFF; + break; + + case 0xE3: /* JCXZ label */ + OFF = fetch_byte(1); + OFF += (int16)IP; + if (CX == 0) /* CX != 0 */ + IP = OFF; + break; + + case 0xE4: /* IN AL,immed8 */ + OFF = fetch_byte(1); + AL = dev_table[OFF].routine(0, 0); + break; + + case 0xE5: /* IN AX,immed8 */ + OFF = fetch_byte(1); + AH = dev_table[OFF].routine(0, 0); + AL = dev_table[OFF+1].routine(0, 0); + break; + + case 0xE6: /* OUT AL,immed8 */ + OFF = fetch_byte(1); + dev_table[OFF].routine(1, AL); + break; + + case 0xE7: /* OUT AX,immed8 */ + OFF = fetch_byte(1); + dev_table[OFF].routine(1, AH); + dev_table[OFF+1].routine(1, AL); + break; + + case 0xE8: /* CALL NEAR proc */ + OFF = fetch_word(); + push_word(IP); + IP = (OFF + IP) & ADDRMASK16; + break; + + case 0xE9: /* JMP NEAR label */ + OFF = fetch_word(); + IP = (OFF + IP) & ADDRMASK16; + break; + + case 0xEA: /* JMP FAR label */ + OFF = fetch_word(); + SEG = fetch_word(); + CS = SEG; + IP = OFF; + break; + + case 0xEB: /* JMP short-label */ + OFF = fetch_byte(1); + if (OFF & 0x80) /* if negative, sign extend */ + OFF |= 0XFF00; + IP = (IP + OFF) & ADDRMASK16; + break; + + case 0xEC: /* IN AL,DX */ + AL = dev_table[DX].routine(0, 0); + break; + + case 0xED: /* IN AX,DX */ + AH = dev_table[DX].routine(0, 0); + AL = dev_table[DX+1].routine(0, 0); + break; + + case 0xEE: /* OUT AL,DX */ + dev_table[DX].routine(1, AL); + break; + + case 0xEF: /* OUT AX,DX */ + dev_table[DX].routine(1, AH); + dev_table[DX+1].routine(1, AL); + break; + + case 0xF0: /* LOCK */ + /* do nothing for now */ + break; + + /* 0xF1 - Not implemented on 8086/8088 */ + + case 0xF2: /* REPNE/REPNZ */ + sysmode |= SYSMODE_PREFIX_REPNE; + break; + + case 0xF3: /* REP/REPE/REPZ */ + sysmode |= SYSMODE_PREFIX_REPE; + break; + + case 0xF4: /* HLT */ + reason = STOP_HALT; + IP--; + break; + + case 0xF5: /* CMC */ + TOGGLE_FLAG(CF); + break; + + case 0xF6: + MRR = fetch_byte(1); + get_mrr_dec(MRR, &MOD, ®, &RM); + if (MOD != 0x3) { /* based, indexed, or based indexed addressing */ + EA = get_ea(MRR); /* get effective address */ + switch(REG) { + case 0: /* TEST mem8, immed8 */ + DATA = fetch_byte(1); + test_byte(get_smbyte(seg_reg, EA), DATA); + break; + case 2: /* NOT mem8 */ + VAL = not_byte(get_smbyte(seg_reg, EA)); + put_smbyte(seg_reg, EA, VAL); /* store result */ + break; + case 3: /* NEG mem8 */ + VAL = neg_byte(get_smbyte(seg_reg, EA)); + put_smbyte(seg_reg, EA, VAL); /* store result */ + break; + case 4: /* MUL mem8 */ + mul_byte(get_smbyte(seg_reg, EA)); + break; + case 5: /* IMUL mem8 */ + imul_byte(get_smbyte(seg_reg, EA)); + break; + case 6: /* DIV mem8 */ + div_byte(get_smbyte(seg_reg, EA)); + break; + case 7: /* IDIV mem8 */ + idiv_byte(get_smbyte(seg_reg, EA)); + break; + default: /* bad opcode */ + reason = STOP_OPCODE; + IP -= 2; + break; + } + } else { /* RM is second register */ + switch(REG) { + case 0: /* TEST reg8, immed8 */ + DATA = fetch_byte(1); + test_byte(get_rbyte(RM), DATA); + break; + case 2: /* NOT reg8 */ + VAL = not_byte(get_rbyte(RM)); + put_rbyte(RM, VAL); /* store result */ + break; + case 3: /* NEG reg8 */ + VAL = neg_byte(get_rbyte(RM)); + put_rbyte(RM, VAL); /* store result */ + break; + case 4: /* MUL reg8 */ + mul_byte(get_rbyte(RM)); + break; + case 5: /* IMUL reg8 */ + imul_byte(get_rbyte(RM)); + break; + case 6: /* DIV reg8 */ + div_byte(get_rbyte(RM)); + break; + case 7: /* IDIV reg8 */ + idiv_byte(get_rbyte(RM)); + break; + default: /* bad opcode */ + reason = STOP_OPCODE; + IP -= 2; + break; + } + put_rbyte(RM, VAL); /* store result */ + } + break; + + case 0xF7: + MRR = fetch_byte(1); + get_mrr_dec(MRR, &MOD, ®, &RM); + if (MOD != 0x3) { /* based, indexed, or based indexed addressing */ + EA = get_ea(MRR); /* get effective address */ + switch(REG) { + case 0: /* TEST mem16, immed16 */ + DATA = fetch_word(); + test_word(get_smword(seg_reg, EA), DATA); + break; + case 2: /* NOT mem16 */ + VAL = not_word(get_smword(seg_reg, EA)); + put_smword(seg_reg, EA, VAL); /* store result */ + break; + case 3: /* NEG mem16 */ + VAL = neg_word(get_smword(seg_reg, EA)); + put_smword(seg_reg, EA, VAL); /* store result */ + break; + case 4: /* MUL mem16 */ + mul_word(get_smword(seg_reg, EA)); + break; + case 5: /* IMUL mem16 */ + imul_word(get_smword(seg_reg, EA)); + break; + case 6: /* DIV mem16 */ + div_word(get_smword(seg_reg, EA)); + break; + case 7: /* IDIV mem16 */ + idiv_word(get_smword(seg_reg, EA)); + break; + default: /* bad opcode */ + reason = STOP_OPCODE; + IP -= 2; + break; + } + } else { /* RM is second register */ + switch(REG) { + case 0: /* TEST reg16, immed16 */ + DATA = fetch_word(); + test_word(get_rword(RM), DATA); + break; + case 2: /* NOT reg16 */ + VAL = not_word(get_rword(RM)); + put_rword(RM, VAL); /* store result */ + break; + case 3: /* NEG reg16 */ + VAL = neg_word(get_rword(RM)); + put_rword(RM, VAL); /* store result */ + break; + case 4: /* MUL reg16 */ + mul_word(get_rword(RM)); + break; + case 5: /* IMUL reg16 */ + imul_word(get_rword(RM)); + break; + case 6: /* DIV reg16 */ + div_word(get_rword(RM)); + break; + case 7: /* IDIV reg16 */ + idiv_word(get_rword(RM)); + break; + default: /* bad opcode */ + reason = STOP_OPCODE; + IP -= 2; + break; + } + put_rbyte(RM, VAL); /* store result */ + } + break; + + case 0xF8: /* CLC */ + CLR_FLAG(CF); + break; + + case 0xF9: /* STC */ + SET_FLAG(CF); + break; + + case 0xFA: /* CLI */ + CLR_FLAG(IF); + break; + + case 0xFB: /* STI */ + SET_FLAG(IF); + break; + + case 0xFC: /* CLD */ + CLR_FLAG(DF); + break; + + case 0xFD: /* STD */ + SET_FLAG(DF); + break; + + case 0xFE: + MRR = fetch_byte(1); + get_mrr_dec(MRR, &MOD, ®, &RM); + if (MOD != 0x3) { /* based, indexed, or based indexed addressing */ + EA = get_ea(MRR); /* get effective address */ + switch(REG) { + case 0: /* INC mem16 */ + VAL = inc_byte(get_smbyte(seg_reg, EA)); /* do operation */ + put_smbyte(seg_reg, EA, VAL); /* store result */ + break; + case 1: /* DEC mem16 */ + VAL = dec_byte(get_smbyte(seg_reg, EA)); /* do operation */ + put_smbyte(seg_reg, EA, VAL); /* store result */ + break; + default: /* bad opcodes */ + reason = STOP_OPCODE; + IP -= 2; + break; + } + } else { /* RM is second register */ + switch(REG) { + case 0: + VAL = inc_byte(get_rbyte(RM)); /* do operation */ + put_rbyte(RM, VAL); /* store result */ + break; + case 1: + VAL = dec_byte(get_rbyte(RM)); /* do operation */ + put_rbyte(RM, VAL); /* store result */ + break; + default: /* bad opcodes */ + reason = STOP_OPCODE; + IP -= 2; + break; + } + put_rbyte(RM, VAL); /* store result */ + } + break; + + case 0xFF: + MRR = fetch_byte(1); + get_mrr_dec(MRR, &MOD, ®, &RM); + if (MOD != 0x3) { /* based, indexed, or based indexed addressing */ + EA = get_ea(MRR); /* get effective address */ + switch(REG) { + case 0: /* INC mem16 */ + VAL = inc_word(get_smword(seg_reg, EA)); /* do operation */ + put_smword(seg_reg, EA, VAL); /* store result */ + break; + case 1: /* DEC mem16 */ + VAL = dec_word(get_smword(seg_reg, EA)); /* do operation */ + put_smword(seg_reg, EA, VAL); /* store result */ + break; + case 2: /* CALL NEAR mem16 */ + OFF = get_smword(SEG_CS, EA); /* do operation */ + push_word(IP); + IP = OFF; + break; + case 3: /* CALL FAR mem16 */ + OFF = get_smword(SEG_CS, EA); /* do operation */ + SEG = get_smword(SEG_CS, EA + 2); + push_word(CS); + CS = SEG; + push_word(IP); + IP = OFF; + break; + case 4: /* JMP NEAR mem16 */ + OFF = get_smword(SEG_CS, EA); /* do operation */ + IP = OFF; + break; + case 5: /* JMP FAR mem16 */ + OFF = get_smword(SEG_CS, EA); /* do operation */ + SEG = get_smword(SEG_CS, EA + 2); + CS = SEG; + IP = OFF; + break; + case 6: /* PUSH mem16 */ + VAL = get_smword(seg_reg, EA); /* do operation */ + push_word(VAL); + break; + case 7: /* bad opcode */ + reason = STOP_OPCODE; + IP -= 2; + break; + } + } else { /* RM is second register */ + switch(REG) { + case 2: /* CALL NEAR reg16 */ + OFF = get_rword(RM); /* do operation */ + push_word(IP); + IP = OFF; + break; + case 4: /* JMP NEAR reg16 */ + OFF = get_rword(RM); /* do operation */ + IP = OFF; + break; + default: /* bad opcode */ + reason = STOP_OPCODE; + IP -= 2; + break; + } + put_rbyte(RM, VAL); /* store result */ + } + break; + + + default: +// if (i8088_unit.flags & UNIT_OPSTOP) { + reason = STOP_OPCODE; + IP--; +// } + break; + } + /* not segment override */ + if ((IR == 0x26) || (IR == 0x2E) || (IR == 0x36) || (IR == 0x3E)) { + seg_ovr = SEG_NONE; /* clear segment override */ + sysmode &= 0x0000001E; /* clear flags */ + sysmode |= 0x00000001; + } + } + +/* Simulation halted */ + + saved_PC = IP; + return reason; +} + +/* emulation subfunctions */ + +int32 sign_ext(int32 val) +{ + int32 res; + + res = val; + if (val & 0x80) + res |= 0xFF00; + return res; +} + + +int32 fetch_byte(int32 flag) +{ + uint8 val; + + val = get_smbyte(SEG_CS, IP) & 0xFF; /* fetch byte */ + if (i8088_dev.dctrl & DEBUG_asm) { /* display source code */ + switch (flag) { + case 0: /* opcode fetch */ +// printf("%04X:%04X %s", CS, IP, opcode[val]); + printf("%04X:%04X %02X", CS, IP, val); + break; + case 1: /* byte operand fetch */ + printf(" %02X", val); + break; + } + } + IP = INC_IP1; /* increment IP */ + return val; +} + +int32 fetch_word(void) +{ + uint16 val; + + val = get_smbyte(SEG_CS, IP) & 0xFF; /* fetch low byte */ + val |= get_smbyte(SEG_CS, IP + 1) << 8; /* fetch high byte */ + if (i8088_dev.dctrl & DEBUG_asm) +// printf("0%04XH", val); + printf(" %04X", val); + IP = INC_IP2; /* increment IP */ + return val; +} + +/* calculate parity on a 8- or 16-bit value */ + +int32 parity(int32 val) +{ + int32 bc = 0; + + if (val & 0x0001) bc++; + if (val & 0x0002) bc++; + if (val & 0x0004) bc++; + if (val & 0x0008) bc++; + if (val & 0x0010) bc++; + if (val & 0x0020) bc++; + if (val & 0x0040) bc++; + if (val & 0x0080) bc++; + if (val & 0x0100) bc++; + if (val & 0x0200) bc++; + if (val & 0x0400) bc++; + if (val & 0x0800) bc++; + if (val & 0x1000) bc++; + if (val & 0x2000) bc++; + if (val & 0x4000) bc++; + if (val & 0x8000) bc++; + return bc & 1; +} + +void i86_intr_raise(uint8 num) +{ + /* do nothing for now */ +} + +/* return byte register */ + +uint32 get_rbyte(uint32 reg) +{ + uint32 val; + + switch(reg) { + case 0: val = AL; break; + case 1: val = CL; break; + case 2: val = DL; break; + case 3: val = BL; break; + case 4: val = AH; break; + case 5: val = CH; break; + case 6: val = DH; break; + case 7: val = BH; break; + } + return val; +} + +/* return word register - added segment registers as 8-11 */ + +uint32 get_rword(uint32 reg) +{ + uint32 val; + + switch(reg) { + case 0: val = AX; break; + case 1: val = CX; break; + case 2: val = DX; break; + case 3: val = BX; break; + case 4: val = SP; break; + case 5: val = BP; break; + case 6: val = SI; break; + case 7: val = DI; break; + case 8: val = CS; break; + case 9: val = DS; break; + case 10: val = ES; break; + case 11: val = SS; break; + } + return val; +} + +/* set byte register */ + +void put_rbyte(uint32 reg, uint32 val) +{ + val &= 0xFF; /* force byte */ + switch(reg){ + case 0: AL = val; break; + case 1: CL = val; break; + case 2: DL = val; break; + case 3: BL = val; break; + case 4: AH = val; break; + case 5: CH = val; break; + case 6: DH = val; break; + case 7: BH = val; break; + } +} + +/* set word register */ + +void put_rword(uint32 reg, uint32 val) +{ + val &= 0xFFFF; /* force word */ + switch(reg){ + case 0: AX = val; break; + case 1: CX = val; break; + case 2: DX = val; break; + case 3: BX = val; break; + case 4: SP = val; break; + case 5: BP = val; break; + case 6: SI = val; break; + case 7: DI = val; break; + } +} + +/* set seg_reg as required for EA */ + +void set_segreg(uint32 reg) +{ + if (seg_ovr) + seg_reg = seg_ovr; + else + seg_ovr = reg; +} + +/* return effective address from mrr - also set seg_reg */ + +uint32 get_ea(uint32 mrr) +{ + uint32 MOD, REG, RM, DISP, EA; + + get_mrr_dec(mrr, &MOD, ®, &RM); + switch(MOD) { + case 0: /* DISP = 0 */ + DISP = 0; + switch(RM) { + case 0: + EA = BX + SI; + set_segreg(SEG_DS); + break; + case 1: + EA = BX + DI; + set_segreg(SEG_DS); + break; + case 2: + EA = BP + SI; + set_segreg(SEG_SS); + break; + case 3: + EA = BP + DI; + set_segreg(SEG_SS); + break; + case 4: + EA = SI; + set_segreg(SEG_DS); + break; + case 5: + EA = DI; + set_segreg(SEG_ES); + break; + case 6: + DISP = fetch_word(); + EA = DISP; + set_segreg(SEG_DS); + break; + case 7: + EA = BX; + set_segreg(SEG_DS); + break; + } + break; + case 1: /* DISP is byte */ + DISP = fetch_byte(1); + switch(RM) { + case 0: + EA = BX + SI + DISP; + set_segreg(SEG_DS); + break; + case 1: + EA = BX + DI + DISP; + set_segreg(SEG_DS); + break; + case 2: + EA = BP + SI + DISP; + set_segreg(SEG_SS); + break; + case 3: + EA = BP + DI + DISP; + set_segreg(SEG_SS); + break; + case 4: + EA = SI + DISP; + set_segreg(SEG_DS); + break; + case 5: + EA = DI + DISP; + set_segreg(SEG_ES); + break; + case 6: + EA = BP + DISP; + set_segreg(SEG_SS); + break; + case 7: + EA = BX + DISP; + set_segreg(SEG_DS); + break; + } + break; + case 2: /* DISP is word */ + DISP = fetch_word(); + switch(RM) { + case 0: + EA = BX + SI + DISP; + set_segreg(SEG_DS); + break; + case 1: + EA = BX + DI + DISP; + set_segreg(SEG_DS); + break; + case 2: + EA = BP + SI + DISP; + set_segreg(SEG_SS); + break; + case 3: + EA = BP + DI + DISP; + set_segreg(SEG_SS); + break; + case 4: + EA = SI + DISP; + set_segreg(SEG_DS); + break; + case 5: + EA = DI + DISP; + set_segreg(SEG_ES); + break; + case 6: + EA = BP + DISP; + set_segreg(SEG_SS); + break; + case 7: + EA = BX + DISP; + set_segreg(SEG_SS); + break; + } + break; + case 3: /* RM is register field */ + break; + } + if (i8088_dev.dctrl & DEBUG_level1) + printf("get_ea: MRR=%02X MOD=%02X REG=%02X R/M=%02X DISP=%04X EA=%04X\n", + mrr, MOD, REG, RM, DISP, EA); + return EA; +} +/* return mod, reg and rm field from mrr */ + +void get_mrr_dec(uint32 mrr, uint32 *mod, uint32 *reg, uint32 *rm) +{ + *mod = (mrr >> 6) & 0x3; + *reg = (mrr >> 3) & 0x7; + *rm = mrr & 0x7; +} + +/* + Most of the primitive algorythms were pulled from the GDE Dos/IP Emulator by Jim Hudgens +*/ + +/* aad primitive */ +uint8 aad_word(uint16 d) +{ + uint16 VAL; + uint8 HI, LOW; + + HI = (d >> 8) & 0xFF; + LOW = d & 0xFF; + VAL = LOW + 10 * HI; + CONDITIONAL_SET_FLAG(VAL & 0x80, SF); + CONDITIONAL_SET_FLAG(VAL == 0, ZF); + CONDITIONAL_SET_FLAG(parity(VAL & 0xFF), PF); + return (uint8) VAL; +} + +/* aam primitive */ +uint16 aam_word(uint8 d) +{ + uint16 VAL, HI; + + HI = d / 10; + VAL = d % 10; + VAL |= (HI << 8); + CONDITIONAL_SET_FLAG(VAL & 0x80, SF); + CONDITIONAL_SET_FLAG(VAL == 0, ZF); + CONDITIONAL_SET_FLAG(parity(VAL & 0xFF), PF); + return VAL; +} + +/* add with carry byte primitive */ +uint8 adc_byte(uint8 d, uint8 s) +{ + register uint16 res; + register uint16 cc; + + if (GET_FLAG(CF)) + res = 1 + d + s; + else + res = d + s; + /* set the flags based on the result */ + CONDITIONAL_SET_FLAG(res & 0x0100, CF); + CONDITIONAL_SET_FLAG((res & 0xff) == 0, ZF); + CONDITIONAL_SET_FLAG(res & 0x80, SF); + CONDITIONAL_SET_FLAG(parity(res & 0xff), PF); + /* calculate the carry chain SEE NOTE AT TOP.*/ + cc = (s & d) | ((~res) & (s | d)); + /* set the flags based on the carry chain */ + CONDITIONAL_SET_FLAG(xor_3_tab[(cc >> 6) & 0x3], OF); + CONDITIONAL_SET_FLAG(cc & 0x08, AF); + return (uint8) res; +} + +/* add with carry word primitive */ +uint16 adc_word(uint16 d, uint16 s) +{ + register uint32 res; + register uint32 cc; + + if (GET_FLAG(CF)) + res = 1 + d + s; + else + res = d + s; + /* set the flags based on the result */ + CONDITIONAL_SET_FLAG(res & 0x10000, CF); + CONDITIONAL_SET_FLAG((res & 0xFFFF) == 0, ZF); + CONDITIONAL_SET_FLAG(res & 0x8000, SF); + CONDITIONAL_SET_FLAG(parity(res & 0xFF), PF); + /* calculate the carry chain SEE NOTE AT TOP.*/ + cc = (s & d) | ((~res) & (s | d)); + /* set the flags based on the carry chain */ + CONDITIONAL_SET_FLAG(xor_3_tab[(cc >> 14) & 0x3], OF); + CONDITIONAL_SET_FLAG(cc & 0x08, AF); + return res; +} + +/* add byte primitive */ +uint8 add_byte(uint8 d, uint8 s) +{ + register uint16 res; + register uint16 cc; + + res = d + s; + /* set the flags based on the result */ + CONDITIONAL_SET_FLAG(res & 0x0100, CF); + CONDITIONAL_SET_FLAG((res & 0xFF) == 0, ZF); + CONDITIONAL_SET_FLAG(res & 0x80, SF); + CONDITIONAL_SET_FLAG(parity(res & 0xFF), PF); + /* calculate the carry chain SEE NOTE AT TOP.*/ + cc = (s & d) | ((~res) & (s | d)); + /* set the flags based on the carry chain */ + CONDITIONAL_SET_FLAG(xor_3_tab[(cc >> 6) & 0x3], OF); + CONDITIONAL_SET_FLAG(cc & 0x08, AF); + return (uint8) res; +} + +/* add word primitive */ +uint16 add_word(uint16 d, uint16 s) +{ + register uint32 res; + register uint32 cc; + + res = d + s; + /* set the flags based on the result */ + CONDITIONAL_SET_FLAG(res & 0x10000, CF); + CONDITIONAL_SET_FLAG((res & 0xFFFF) == 0, ZF); + CONDITIONAL_SET_FLAG(res & 0x8000, SF); + CONDITIONAL_SET_FLAG(parity(res & 0xff), PF); + /* calculate the carry chain SEE NOTE AT TOP.*/ + cc = (s & d) | ((~res) & (s | d)); + /* set the flags based on the carry chain */ + CONDITIONAL_SET_FLAG(xor_3_tab[(cc >> 14) & 0x3], OF); + CONDITIONAL_SET_FLAG(cc & 0x08, AF); + return res; +} + +/* and byte primitive */ +uint8 and_byte(uint8 d, uint8 s) +{ + register uint8 res; + res = d & s; + + /* clear flags */ + CLR_FLAG(OF); + CLR_FLAG(CF); + /* set the flags based on the result */ + CONDITIONAL_SET_FLAG(res & 0x80, SF); + CONDITIONAL_SET_FLAG(res == 0, ZF); + CONDITIONAL_SET_FLAG(parity(res), PF); + return res; +} + +/* and word primitive */ +uint16 and_word(uint16 d, uint16 s) +{ + register uint16 res; + res = d & s; + + /* clear flags */ + CLR_FLAG(OF); + CLR_FLAG(CF); + /* set the flags based on the result */ + CONDITIONAL_SET_FLAG(res & 0x8000, SF); + CONDITIONAL_SET_FLAG(res == 0, ZF); + CONDITIONAL_SET_FLAG(parity(res & 0xFF), PF); + return res; +} + +/* cmp byte primitive */ +uint8 cmp_byte(uint8 d, uint8 s) +{ + register uint32 res; + register uint32 bc; + + res = d - s; + /* clear flags */ + CLR_FLAG(CF); + /* set the flags based on the result */ + CONDITIONAL_SET_FLAG(res & 0x80, SF); + CONDITIONAL_SET_FLAG((res & 0xFF)==0, ZF); + CONDITIONAL_SET_FLAG(parity(res & 0xFF), PF); + /* calculate the borrow chain. See note at top */ + bc= (res&(~d|s))|(~d&s); + /* set flags based on borrow chain */ + CONDITIONAL_SET_FLAG(bc & 0x80, CF); + CONDITIONAL_SET_FLAG(xor_3_tab[(bc >> 6) & 0x3], OF); + CONDITIONAL_SET_FLAG(bc & 0x8, AF); + return d; /* long story why this is needed. Look at opcode + 0x80 in ops.c, for an idea why this is necessary.*/ +} + +/* cmp word primitive */ +uint16 cmp_word(uint16 d, uint16 s) +{ + register uint32 res; + register uint32 bc; + + res = d - s; + /* set the flags based on the result */ + CONDITIONAL_SET_FLAG(res & 0x8000, SF); + CONDITIONAL_SET_FLAG((res & 0xFFFF) == 0, ZF); + CONDITIONAL_SET_FLAG(parity(res & 0xFF), PF); + /* calculate the borrow chain. See note at top */ + bc = (res & (~d | s)) | (~d &s); + /* set flags based on borrow chain */ + CONDITIONAL_SET_FLAG(bc & 0x8000, CF); + CONDITIONAL_SET_FLAG(xor_3_tab[(bc >> 14) & 0x3], OF); + CONDITIONAL_SET_FLAG(bc & 0x8, AF); + return d; /* long story why this is needed. Look at opcode + 0x80 in ops.c, for an idea why this is necessary.*/ +} + +/* dec byte primitive */ +uint8 dec_byte(uint8 d) +{ + register uint32 res; + register uint32 bc; + + res = d - 1; + /* set the flags based on the result */ + CONDITIONAL_SET_FLAG(res & 0x80, SF); + CONDITIONAL_SET_FLAG((res & 0xff)==0, ZF); + CONDITIONAL_SET_FLAG(parity(res & 0xff), PF); + /* calculate the borrow chain. See note at top */ + /* based on sub_byte, uses s=1. */ + bc = (res & (~d | 1)) | (~d & 1); + /* carry flag unchanged */ + /* set flags based on borrow chain */ + CONDITIONAL_SET_FLAG(xor_3_tab[(bc >> 6) & 0x3], OF); + CONDITIONAL_SET_FLAG(bc & 0x8, AF); + return res; +} + +/* dec word primitive */ +uint16 dec_word(uint16 d) +{ + register uint32 res; + register uint32 bc; + + res = d - 1; + /* set the flags based on the result */ + CONDITIONAL_SET_FLAG(res & 0x8000, SF); + CONDITIONAL_SET_FLAG((res & 0xffff) == 0, ZF); + CONDITIONAL_SET_FLAG(parity(res & 0xff), PF); + /* calculate the borrow chain. See note at top */ + /* based on the sub_byte routine, with s==1 */ + bc = (res & (~d | 1)) | (~d & 1); + /* carry flag unchanged */ + /* set flags based on borrow chain */ + CONDITIONAL_SET_FLAG(xor_3_tab[(bc >> 14) & 0x3], OF); + CONDITIONAL_SET_FLAG(bc & 0x8, AF); + return res; +} + +/* div byte primitive */ +void div_byte(uint8 s) +{ + uint32 dvd, dvs, div, mod; + + dvs = s; + dvd = AX; + if (s == 0) { + i86_intr_raise(0); + return; + } + div = dvd / dvs; + mod = dvd % dvs; + if (abs(div) > 0xFF) { + i86_intr_raise(0); + return; + } + /* Undef --- Can't hurt */ + CLR_FLAG(SF); + CONDITIONAL_SET_FLAG(div == 0, ZF); + AL = (uint8)div; + AH = (uint8)mod; +} + +/* div word primitive */ +void div_word(uint16 s) +{ + uint32 dvd, dvs, div, mod; + + dvd = DX; + dvd = (dvd << 16) | AX; + dvs = s; + if (dvs == 0) { + i86_intr_raise(0); + return; + } + div = dvd / dvs; + mod = dvd % dvs; + if (abs(div) > 0xFFFF) { + i86_intr_raise(0); + return; + } + /* Undef --- Can't hurt */ + CLR_FLAG(SF); + CONDITIONAL_SET_FLAG(div == 0, ZF); + AX = div; + DX = mod; +} + +/* idiv byte primitive */ +void idiv_byte(uint8 s) +{ + int32 dvd, div, mod; + + dvd = (int16)AX; + if (s == 0) { + i86_intr_raise(0); + return; + } + div = dvd / (int8)s; + mod = dvd % (int8)s; + if (abs(div) > 0x7F) { + i86_intr_raise(0); + return; + } + /* Undef --- Can't hurt */ + CONDITIONAL_SET_FLAG(div & 0x80, SF); + CONDITIONAL_SET_FLAG(div == 0, ZF); + AL = (int8)div; + AH = (int8)mod; +} + +/* idiv word primitive */ +void idiv_word(uint16 s) +{ + int32 dvd, dvs, div, mod; + + dvd = DX; + dvd = (dvd << 16) | AX; + if (s == 0) { + i86_intr_raise(0); + return; + } + dvs = (int16)s; + div = dvd / dvs; + mod = dvd % dvs; + if (abs(div) > 0x7FFF) { + i86_intr_raise(0); + return; + } + /* Undef --- Can't hurt */ + CONDITIONAL_SET_FLAG(div & 0x8000, SF); + CONDITIONAL_SET_FLAG(div == 0, ZF); + AX = div; + DX = mod; +} + +/* imul byte primitive */ +void imul_byte(uint8 s) +{ + int16 res; + + res = (int8)AL * (int8)s; + AX = res; + /* Undef --- Can't hurt */ + CONDITIONAL_SET_FLAG(res & 0x8000, SF); + CONDITIONAL_SET_FLAG(res == 0, ZF); + if ( AH == 0 || AH == 0xFF) { + CLR_FLAG(CF); + CLR_FLAG(OF); + } else { + SET_FLAG(CF); + SET_FLAG(OF); + } +} + +/* imul word primitive */ +void imul_word(uint16 s) +{ + int32 res; + + res = (int16)AX * (int16)s; + AX = res & 0xFFFF; + DX = (res >> 16) & 0xFFFF; + /* Undef --- Can't hurt */ + CONDITIONAL_SET_FLAG(res & 0x80000000, SF); + CONDITIONAL_SET_FLAG(res == 0, ZF); + if (DX == 0 || DX == 0xFFFF) { + CLR_FLAG(CF); + CLR_FLAG(OF); + } else { + SET_FLAG(CF); + SET_FLAG(OF); + } +} + +/* inc byte primitive */ +uint8 inc_byte(uint8 d) +{ + register uint32 res; + register uint32 cc; + + res = d + 1; + /* set the flags based on the result */ + CONDITIONAL_SET_FLAG((res & 0xFF) == 0, ZF); + CONDITIONAL_SET_FLAG(res & 0x80, SF); + CONDITIONAL_SET_FLAG(parity(res & 0xFF), PF); + /* calculate the carry chain SEE NOTE AT TOP.*/ + cc = ((1 & d) | (~res)) & (1 | d); + /* set the flags based on the carry chain */ + CONDITIONAL_SET_FLAG(xor_3_tab[(cc >> 6) & 0x3], OF); + CONDITIONAL_SET_FLAG(cc & 0x8, AF); + return res; +} + +/* inc word primitive */ +uint16 inc_word(uint16 d) +{ + register uint32 res; + register uint32 cc; + + res = d + 1; + /* set the flags based on the result */ + CONDITIONAL_SET_FLAG((res & 0xFFFF) == 0, ZF); + CONDITIONAL_SET_FLAG(res & 0x8000, SF); + CONDITIONAL_SET_FLAG(parity(res & 0xff), PF); + /* calculate the carry chain SEE NOTE AT TOP.*/ + cc = (1 & d) | ((~res) & (1 | d)); + /* set the flags based on the carry chain */ + CONDITIONAL_SET_FLAG(xor_3_tab[(cc >> 14) & 0x3], OF); + CONDITIONAL_SET_FLAG(cc & 0x8, AF); + return res ; +} + +/* mul byte primitive */ +void mul_byte(uint8 s) +{ + uint16 res; + + res = AL * s; + AX = res; + /* Undef --- Can't hurt */ + CLR_FLAG(SF); + CONDITIONAL_SET_FLAG(res == 0, ZF); + if (AH == 0) { + CLR_FLAG(CF); + CLR_FLAG(OF); + } else { + SET_FLAG(CF); + SET_FLAG(OF); + } +} + +/* mul word primitive */ +void mul_word(uint16 s) +{ + uint32 res; + + res = AX * s; + /* Undef --- Can't hurt */ + CLR_FLAG(SF); + CONDITIONAL_SET_FLAG(res == 0, ZF); + AX = res & 0xFFFF; + DX = (res >> 16) & 0xFFFF; + if (DX == 0) { + CLR_FLAG(CF); + CLR_FLAG(OF); + } else { + SET_FLAG(CF); + SET_FLAG(OF); + } +} + +/* neg byte primitive */ +uint8 neg_byte(uint8 s) +{ + register uint8 res; + register uint8 bc; + + CONDITIONAL_SET_FLAG(s != 0, CF); + res = -s; + CONDITIONAL_SET_FLAG((res & 0xff) == 0, ZF); + CONDITIONAL_SET_FLAG(res & 0x80, SF); + CONDITIONAL_SET_FLAG(parity(res), PF); + /* calculate the borrow chain --- modified such that d=0. */ + bc= res | s; + CONDITIONAL_SET_FLAG(xor_3_tab[(bc >> 6) & 0x3], OF); + CONDITIONAL_SET_FLAG(bc & 0x8, AF); + return res; +} + +/* neg word primitive */ +uint16 neg_word(uint16 s) +{ + register uint16 res; + register uint16 bc; + + CONDITIONAL_SET_FLAG(s != 0, CF); + res = -s; + CONDITIONAL_SET_FLAG((res & 0xFFFF) == 0, ZF); + CONDITIONAL_SET_FLAG(res & 0x8000, SF); + CONDITIONAL_SET_FLAG(parity(res & 0xFF), PF); + /* calculate the borrow chain --- modified such that d=0 */ + bc= res | s; + CONDITIONAL_SET_FLAG(xor_3_tab[(bc >> 6) & 0x3], OF); + CONDITIONAL_SET_FLAG(bc & 0x8, AF); + return res; +} + +/* not byte primitive */ +uint8 not_byte(uint8 s) +{ + return ~s; +} + +/* not word primitive */ +uint16 not_word(uint16 s) +{ + return ~s; +} + +/* or byte primitive */ +uint8 or_byte(uint8 d, uint8 s) +{ + register uint8 res; + + res = d | s; + /* clear flags */ + CLR_FLAG(OF); + CLR_FLAG(CF); + /* set the flags based on the result */ + CONDITIONAL_SET_FLAG(res & 0x80, SF); + CONDITIONAL_SET_FLAG(res == 0, ZF); + CONDITIONAL_SET_FLAG(parity(res), PF); + return res; +} + +/* or word primitive */ +uint16 or_word(uint16 d, uint16 s) +{ + register uint16 res; + + res = d | s; + /* clear flags */ + CLR_FLAG(OF); + CLR_FLAG(CF); + /* set the flags based on the result */ + CONDITIONAL_SET_FLAG(res & 0x8000, SF); + CONDITIONAL_SET_FLAG(res == 0, ZF); + CONDITIONAL_SET_FLAG(parity(res & 0xFF), PF); + return res; +} + +/* push word primitive */ +void push_word(uint16 val) +{ + SP--; + put_smbyte(SS, SP, val >> 8); + SP--; + put_smbyte(SS, SP, val & 0xFF); +} + +/* pop word primitive */ +uint16 pop_word(void) +{ + register uint16 res; + + res = get_smbyte(SS, SP); + SP++; + res |= (get_smbyte(SS, SP) << 8); + SP++; + return res; +} + +/* rcl byte primitive */ +uint8 rcl_byte(uint8 d, uint8 s) +{ + register uint32 res, cnt, mask, cf; + + res = d; + if ((cnt = s % 9)) + { + cf = (d >> (8-cnt)) & 0x1; + res = (d << cnt) & 0xFF; + mask = (1<<(cnt-1)) - 1; + res |= (d >> (9-cnt)) & mask; + if (GET_FLAG(CF)) + res |= 1 << (cnt-1); + CONDITIONAL_SET_FLAG(cf, CF); + CONDITIONAL_SET_FLAG(cnt == 1 && xor_3_tab[cf + ((res >> 6) & 0x2)], OF); + } + return res & 0xFF; +} + +/* rcl word primitive */ +uint16 rcl_word(uint16 d, uint16 s) +{ + register uint32 res, cnt, mask, cf; + + res = d; + if ((cnt = s % 17)) + { + cf = (d >> (16-cnt)) & 0x1; + res = (d << cnt) & 0xFFFF; + mask = (1<<(cnt-1)) - 1; + res |= (d >> (17-cnt)) & mask; + if (GET_FLAG(CF)) + res |= 1 << (cnt-1); + CONDITIONAL_SET_FLAG(cf, CF); + CONDITIONAL_SET_FLAG(cnt == 1 && xor_3_tab[cf + ((res >> 14) & 0x2)], OF); + } + return res & 0xFFFF; +} + +/* rcr byte primitive */ +uint8 rcr_byte(uint8 d, uint8 s) +{ + uint8 res, cnt; + uint8 mask, cf, ocf = 0; + + res = d; + + if ((cnt = s % 9)) { + if (cnt == 1) { + cf = d & 0x1; + ocf = GET_FLAG(CF) != 0; + } else + cf = (d >> (cnt - 1)) & 0x1; + mask = (1 <<( 8 - cnt)) - 1; + res = (d >> cnt) & mask; + res |= (d << (9-cnt)); + if (GET_FLAG(CF)) + res |= 1 << (8 - cnt); + CONDITIONAL_SET_FLAG(cf, CF); + if (cnt == 1) + CONDITIONAL_SET_FLAG(xor_3_tab[ocf + ((d >> 6) & 0x2)], OF); + } + return res; +} + +/* rcr word primitive */ +uint16 rcr_word(uint16 d, uint16 s) +{ + uint16 res, cnt; + uint16 mask, cf, ocf = 0; + + res = d; + if ((cnt = s % 17)) { + if (cnt == 1) { + cf = d & 0x1; + ocf = GET_FLAG(CF) != 0; + } else + cf = (d >> (cnt-1)) & 0x1; + mask = (1 <<( 16 - cnt)) - 1; + res = (d >> cnt) & mask; + res |= (d << (17 - cnt)); + if (GET_FLAG(CF)) + res |= 1 << (16 - cnt); + CONDITIONAL_SET_FLAG(cf, CF); + if (cnt == 1) + CONDITIONAL_SET_FLAG(xor_3_tab[ocf + ((d >> 14) & 0x2)], OF); + } + return res; +} + +/* rol byte primitive */ +uint8 rol_byte(uint8 d, uint8 s) +{ + register uint32 res, cnt, mask; + + res =d; + + if ((cnt = s % 8)) { + res = (d << cnt); + mask = (1 << cnt) - 1; + res |= (d >> (8-cnt)) & mask; + CONDITIONAL_SET_FLAG(res & 0x1, CF); + CONDITIONAL_SET_FLAG(cnt == 1 && xor_3_tab[(res & 0x1) + ((res >> 6) & 0x2)], OF); + } + return res & 0xFF; +} + +/* rol word primitive */ +uint16 rol_word(uint16 d, uint16 s) +{ + register uint32 res, cnt, mask; + + res = d; + if ((cnt = s % 16)) { + res = (d << cnt); + mask = (1 << cnt) - 1; + res |= (d >> (16 - cnt)) & mask; + CONDITIONAL_SET_FLAG(res & 0x1, CF); + CONDITIONAL_SET_FLAG(cnt == 1 && xor_3_tab[(res & 0x1) + ((res >> 14) & 0x2)], OF); + } + return res&0xFFFF; +} + +/* ror byte primitive */ +uint8 ror_byte(uint8 d, uint8 s) +{ + register uint32 res, cnt, mask; + + res = d; + if ((cnt = s % 8)) { + res = (d << (8-cnt)); + mask = (1 << (8-cnt)) - 1; + res |= (d >> (cnt)) & mask; + CONDITIONAL_SET_FLAG(res & 0x80, CF); + CONDITIONAL_SET_FLAG(cnt == 1 && xor_3_tab[(res >> 6) & 0x3], OF); + } + return res & 0xFF; +} + +/* ror word primitive */ +uint16 ror_word(uint16 d, uint16 s) +{ + register uint32 res, cnt, mask; + + res = d; + if ((cnt = s % 16)) { + res = (d << (16-cnt)); + mask = (1 << (16-cnt)) - 1; + res |= (d >> (cnt)) & mask; + CONDITIONAL_SET_FLAG(res & 0x8000, CF); + CONDITIONAL_SET_FLAG(cnt == 1 && xor_3_tab[(res >> 14) & 0x3], OF); + } + return res & 0xFFFF; +} + +/* shl byte primitive */ +uint8 shl_byte(uint8 d, uint8 s) +{ + uint32 cnt, res, cf; + + if (s < 8) { + cnt = s % 8; + if (cnt > 0) { + res = d << cnt; + cf = d & (1 << (8 - cnt)); + CONDITIONAL_SET_FLAG(cf, CF); + CONDITIONAL_SET_FLAG((res & 0xFF)==0, ZF); + CONDITIONAL_SET_FLAG(res & 0x80, SF); + CONDITIONAL_SET_FLAG(parity(res & 0xFF), PF); + } else + res = (uint8) d; + if (cnt == 1) + CONDITIONAL_SET_FLAG((((res & 0x80) == 0x80) ^ + (GET_FLAG( CF) != 0)), OF); + else + CLR_FLAG(OF); + } else { + res = 0; + CONDITIONAL_SET_FLAG((s == 8) && (d & 1), CF); + CLR_FLAG(OF); + CLR_FLAG(SF); + CLR_FLAG(PF); + SET_FLAG(ZF); + } + return res & 0xFF; +} + +/* shl word primitive */ +uint16 shl_word(uint16 d, uint16 s) +{ + uint32 cnt, res, cf; + + if (s < 16) { + cnt = s % 16; + if (cnt > 0) { + res = d << cnt; + cf = d & (1<<(16-cnt)); + CONDITIONAL_SET_FLAG(cf, CF); + CONDITIONAL_SET_FLAG((res & 0xFFFF) == 0, ZF); + CONDITIONAL_SET_FLAG(res & 0x8000, SF); + CONDITIONAL_SET_FLAG(parity(res & 0xFF), PF); + } else + res = (uint16) d; + if (cnt == 1) + CONDITIONAL_SET_FLAG((((res & 0x8000) == 0x8000) ^ + (GET_FLAG(CF) != 0)), OF); + else + CLR_FLAG(OF); + } else { + res = 0; + CONDITIONAL_SET_FLAG((s == 16) && (d & 1), CF); + CLR_FLAG(OF); + SET_FLAG(ZF); + CLR_FLAG(SF); + CLR_FLAG(PF); + } + return res & 0xFFFF; +} + +/* shr byte primitive */ +uint8 shr_byte(uint8 d, uint8 s) +{ + uint32 cnt, res, cf, mask; + + if (s < 8) { + cnt = s % 8; + if (cnt > 0) { + mask = (1 << (8 - cnt)) - 1; + cf = d & (1 << (cnt - 1)); + res = (d >> cnt) & mask; + CONDITIONAL_SET_FLAG(cf, CF); + CONDITIONAL_SET_FLAG((res & 0xFF) == 0, ZF); + CONDITIONAL_SET_FLAG(res & 0x80, SF); + CONDITIONAL_SET_FLAG(parity(res & 0xFF), PF); + } else + res = (uint8) d; + if (cnt == 1) + CONDITIONAL_SET_FLAG(xor_3_tab[(res >> 6) & 0x3], OF); + else + CLR_FLAG(OF); + } else { + res = 0; + CONDITIONAL_SET_FLAG((s == 8) && (d & 0x80), CF); + CLR_FLAG(OF); + SET_FLAG(ZF); + CLR_FLAG(SF); + CLR_FLAG(PF); + } + return res & 0xFF; +} + +/* shr word primitive */ +uint16 shr_word(uint16 d, uint16 s) +{ + uint32 cnt, res, cf, mask; + + res = d; + if (s < 16) { + cnt = s % 16; + if (cnt > 0) { + mask = (1 << (16 - cnt)) - 1; + cf = d & (1 << (cnt - 1)); + res = (d >> cnt) & mask; + CONDITIONAL_SET_FLAG(cf, CF); + CONDITIONAL_SET_FLAG((res & 0xFFFF) == 0, ZF); + CONDITIONAL_SET_FLAG(res & 0x8000, SF); + CONDITIONAL_SET_FLAG(parity(res & 0xFF), PF); + } else + res = d; + if (cnt == 1) + CONDITIONAL_SET_FLAG(xor_3_tab[(res >> 14) & 0x3], OF); + else + CLR_FLAG(OF); + } else { + res = 0; + CONDITIONAL_SET_FLAG((s == 16) && (d & 0x8000), CF); + CLR_FLAG(OF); + SET_FLAG(ZF); + CLR_FLAG(SF); + CLR_FLAG(PF); + } + return res & 0xFFFF; +} + +/* sar byte primitive */ +uint8 sar_byte(uint8 d, uint8 s) +{ + uint32 cnt, res, cf, mask, sf; + + res = d; + sf = d & 0x80; + cnt = s % 8; + if (cnt > 0 && cnt < 8) { + mask = (1 << (8 - cnt)) - 1; + cf = d & (1 << (cnt -1 )); + res = (d >> cnt) & mask; + CONDITIONAL_SET_FLAG(cf, CF); + if (sf) + res |= ~mask; + CONDITIONAL_SET_FLAG((res & 0xFF)==0, ZF); + CONDITIONAL_SET_FLAG(parity(res & 0xFF), PF); + CONDITIONAL_SET_FLAG(res & 0x80, SF); + } else if (cnt >= 8) { + if (sf) { + res = 0xFF; + SET_FLAG(CF); + CLR_FLAG(ZF); + SET_FLAG(SF); + SET_FLAG(PF); + } else { + res = 0; + CLR_FLAG(CF); + SET_FLAG(ZF); + CLR_FLAG(SF); + CLR_FLAG(PF); + } + } + return res & 0xFF; +} + +/* sar word primitive */ +uint16 sar_word(uint16 d, uint16 s) +{ + uint32 cnt, res, cf, mask, sf; + + sf = d & 0x8000; + cnt = s % 16; + res = d; + if (cnt > 0 && cnt < 16) { + mask = (1 << (16 - cnt)) - 1; + cf = d & (1 << (cnt - 1)); + res = (d >> cnt) & mask; + CONDITIONAL_SET_FLAG(cf, CF); + if (sf) + res |= ~mask; + CONDITIONAL_SET_FLAG((res & 0xFFFF) == 0, ZF); + CONDITIONAL_SET_FLAG(res & 0x8000, SF); + CONDITIONAL_SET_FLAG(parity(res & 0xFF), PF); + } else if (cnt >= 16) { + if (sf) { + res = 0xFFFF; + SET_FLAG(CF); + CLR_FLAG(ZF); + SET_FLAG(SF); + SET_FLAG(PF); + } else { + res = 0; + CLR_FLAG(CF); + SET_FLAG(ZF); + CLR_FLAG(SF); + CLR_FLAG(PF); + } + } + return res & 0xFFFF; +} + +/* sbb byte primitive */ +uint8 sbb_byte(uint8 d, uint8 s) +{ + register uint32 res; + register uint32 bc; + + if (GET_FLAG(CF)) + res = d - s - 1; + else + res = d - s; + /* set the flags based on the result */ + CONDITIONAL_SET_FLAG(res & 0x80, SF); + CONDITIONAL_SET_FLAG((res & 0xFF) == 0, ZF); + CONDITIONAL_SET_FLAG(parity(res & 0xFF), PF); + /* calculate the borrow chain. See note at top */ + bc= (res&(~d|s))|(~d&s); + /* set flags based on borrow chain */ + CONDITIONAL_SET_FLAG(bc & 0x80, CF); + CONDITIONAL_SET_FLAG(xor_3_tab[(bc >> 6) & 0x3], OF); + CONDITIONAL_SET_FLAG(bc & 0x8, AF); +// return res & 0x0FF; + return (uint8) res; +} + +/* sbb word primitive */ +uint16 sbb_word(uint16 d, uint16 s) +{ + register uint32 res; + register uint32 bc; + + if (GET_FLAG(CF)) + res = d - s - 1; + else + res = d - s; + /* set the flags based on the result */ + CONDITIONAL_SET_FLAG(res & 0x8000, SF); + CONDITIONAL_SET_FLAG((res & 0xFFFF) == 0, ZF); + CONDITIONAL_SET_FLAG(parity(res & 0xFF), PF); + /* calculate the borrow chain. See note at top */ + bc= (res&(~d|s))|(~d&s); + /* set flags based on borrow chain */ + CONDITIONAL_SET_FLAG(bc & 0x8000, CF); + CONDITIONAL_SET_FLAG(xor_3_tab[(bc >> 14) & 0x3], OF); + CONDITIONAL_SET_FLAG(bc & 0x8, AF); +// return res & 0xFFFF; + return (uint16) res; +} + +/* sub byte primitive */ +uint8 sub_byte(uint8 d, uint8 s) +{ + register uint32 res; + register uint32 bc; + + res = d - s; + /* set the flags based on the result */ + CONDITIONAL_SET_FLAG(res & 0x80, SF); + CONDITIONAL_SET_FLAG((res & 0xFF) == 0, ZF); + CONDITIONAL_SET_FLAG(parity(res & 0xFF), PF); + /* calculate the borrow chain. See note at top */ + bc= (res&(~d|s))|(~d&s); + /* set flags based on borrow chain */ + CONDITIONAL_SET_FLAG(bc & 0x80, CF); + CONDITIONAL_SET_FLAG(xor_3_tab[(bc >> 6) & 0x3], OF); + CONDITIONAL_SET_FLAG(bc & 0x8, AF); +// return res & 0xff; + return (uint8) res; +} + +/* sub word primitive */ +uint16 sub_word(uint16 d, uint16 s) +{ + register uint32 res; + register uint32 bc; + + res = d - s; + /* set the flags based on the result */ + CONDITIONAL_SET_FLAG(res &0x8000, SF); + CONDITIONAL_SET_FLAG((res &0xFFFF) == 0, ZF); + CONDITIONAL_SET_FLAG(parity(res & 0xFF), PF); + /* calculate the borrow chain. See note at top */ + bc= (res&(~d|s))|(~d&s); + /* set flags based on borrow chain */ + CONDITIONAL_SET_FLAG(bc & 0x8000, CF); + CONDITIONAL_SET_FLAG(xor_3_tab[(bc >> 14) & 0x3], OF); + CONDITIONAL_SET_FLAG(bc & 0x8, AF); +// return res & 0xffff; + return (uint16) res; +} + +/* test byte primitive */ +void test_byte(uint8 d, uint8 s) +{ + register uint32 res; + + res = d & s; + CLR_FLAG(OF); + CONDITIONAL_SET_FLAG(res & 0x80, SF); + CONDITIONAL_SET_FLAG(res == 0, ZF); + CONDITIONAL_SET_FLAG(parity(res & 0xFF), PF); + /* AF == dont care*/ + CLR_FLAG(CF); +} + +/* test word primitive */ +void test_word(uint16 d, uint16 s) +{ + register uint32 res; + + res = d & s; + CLR_FLAG(OF); + CONDITIONAL_SET_FLAG(res & 0x8000, SF); + CONDITIONAL_SET_FLAG(res == 0, ZF); + CONDITIONAL_SET_FLAG(parity(res & 0xff), PF); + /* AF == dont care*/ + CLR_FLAG(CF); +} + +/* xor byte primitive */ +uint8 xor_byte(uint8 d, uint8 s) +{ + register uint8 res; + res = d ^ s; + + /* clear flags */ + CLR_FLAG(OF); + CLR_FLAG(CF); + /* set the flags based on the result */ + CONDITIONAL_SET_FLAG(res & 0x80, SF); + CONDITIONAL_SET_FLAG(res == 0, ZF); + CONDITIONAL_SET_FLAG(parity(res), PF); + return res; +} + +/* xor word primitive */ +uint16 xor_word(uint16 d, uint16 s) +{ + register uint16 res; + + res = d ^ s; + /* clear flags */ + CLR_FLAG(OF); + CLR_FLAG(CF); + /* set the flags based on the result */ + CONDITIONAL_SET_FLAG(res & 0x8000, SF); + CONDITIONAL_SET_FLAG(res == 0, ZF); + CONDITIONAL_SET_FLAG(parity(res & 0xFF), PF); + return res; +} + +/* memory routines. These use the segment register (segreg) value and offset + (addr) to calculate the proper source or destination memory address */ + +/* get a byte from memory */ + +int32 get_smbyte(int32 segreg, int32 addr) +{ + int32 abs_addr, val; + + abs_addr = addr + (get_rword(segreg) << 4); + val = get_mbyte(abs_addr); +// printf("get_smbyte: seg=%04X addr=%04X abs_addr=%08X get_mbyte=%02X\n", +// get_rword(segreg), addr, abs_addr, val); + return val; +} + +/* get a word from memory using addr and segment register */ + +int32 get_smword(int32 segreg, int32 addr) +{ + int32 val; + + val = get_smbyte(segreg, addr); + val |= (get_smbyte(segreg, addr+1) << 8); + return val; +} + +/* put a byte to memory using addr and segment register */ + +void put_smbyte(int32 segreg, int32 addr, int32 val) +{ + int32 abs_addr; + + abs_addr = addr + (get_rword(segreg) << 4); + put_mbyte(abs_addr, val); +} + +/* put a word to memory using addr and segment register */ + +void put_smword(int32 segreg, int32 addr, int32 val) +{ + put_smbyte(segreg, addr, val); + put_smbyte(segreg, addr+1, val << 8); +} + +/* Reset routine using addr and segment register */ + +t_stat i8088_reset (DEVICE *dptr) +{ + PSW = 0; + CS = 0xFFFF; + DS = 0; + SS = 0; + ES = 0; + saved_PC = 0; + int_req = 0; + sim_brk_types = sim_brk_dflt = SWMASK ('E'); + printf(" 8088 Reset\n"); + return SCPE_OK; +} + +/* Memory examine */ + +t_stat i8088_ex (t_value *vptr, t_addr addr, UNIT *uptr, int32 sw) +{ + if (addr >= MAXMEMSIZE20) + return SCPE_NXM; + if (vptr != NULL) + *vptr = get_mbyte(addr); + return SCPE_OK; +} + +/* Memory deposit */ + +t_stat i8088_dep (t_value val, t_addr addr, UNIT *uptr, int32 sw) +{ + if (addr >= MAXMEMSIZE20) + return SCPE_NXM; + put_mbyte(addr, val); + return SCPE_OK; +} + +/* This is the binary loader. The input file is considered to be + a string of literal bytes with no special format. The load + starts at the current value of the PC. +*/ + +int32 sim_load (FILE *fileref, char *cptr, char *fnam, int flag) +{ + int32 i, addr = 0, cnt = 0; + + if ((*cptr != 0) || (flag != 0)) return SCPE_ARG; + addr = saved_PC; + while ((i = getc (fileref)) != EOF) { + put_mbyte(addr, i); + addr++; + cnt++; + } /* end while */ + printf ("%d Bytes loaded.\n", cnt); + return (SCPE_OK); +} + +/* Symbolic output + + Inputs: + *of = output stream + addr = current PC + *val = pointer to values + *uptr = pointer to unit + sw = switches + Outputs: + status = error code +*/ + +int32 fprint_sym (FILE *of, int32 addr, uint32 *val, + UNIT *uptr, int32 sw) +{ + int32 cflag, c1, c2, inst, adr; + + cflag = (uptr == NULL) || (uptr == &i8088_unit); + c1 = (val[0] >> 8) & 0177; + c2 = val[0] & 0177; + if (sw & SWMASK ('A')) { + fprintf (of, (c2 < 040)? "<%02X>": "%c", c2); + return SCPE_OK; + } + if (sw & SWMASK ('C')) { + fprintf (of, (c1 < 040)? "<%02X>": "%c", c1); + fprintf (of, (c2 < 040)? "<%02X>": "%c", c2); + return SCPE_OK; + } + if (!(sw & SWMASK ('M'))) return SCPE_ARG; + inst = val[0]; + fprintf (of, "%s", opcode[inst]); + if (oplen[inst] == 2) { + if (strchr(opcode[inst], ' ') != NULL) + fprintf (of, ","); + else fprintf (of, " "); + fprintf (of, "%h", val[1]); + } + if (oplen[inst] == 3) { + adr = val[1] & 0xFF; + adr |= (val[2] << 8) & 0xff00; + if (strchr(opcode[inst], ' ') != NULL) + fprintf (of, ","); + else fprintf (of, " "); + fprintf (of, "%h", adr); + } + return -(oplen[inst] - 1); +} + +/* Symbolic input + + Inputs: + *cptr = pointer to input string + addr = current PC + *uptr = pointer to unit + *val = pointer to output values + sw = switches + Outputs: + status = error status +*/ + +int32 parse_sym (char *cptr, int32 addr, UNIT *uptr, uint32 *val, int32 sw) +{ + int32 cflag, i = 0, j, r; + char gbuf[CBUFSIZE]; + + cflag = (uptr == NULL) || (uptr == &i8088_unit); + while (isspace (*cptr)) cptr++; /* absorb spaces */ + if ((sw & SWMASK ('A')) || ((*cptr == '\'') && cptr++)) { /* ASCII char? */ + if (cptr[0] == 0) return SCPE_ARG; /* must have 1 char */ + val[0] = (uint32) cptr[0]; + return SCPE_OK; + } + if ((sw & SWMASK ('C')) || ((*cptr == '"') && cptr++)) { /* ASCII string? */ + if (cptr[0] == 0) return SCPE_ARG; /* must have 1 char */ + val[0] = ((uint32) cptr[0] << 8) + (uint32) cptr[1]; + return SCPE_OK; + } + +/* An instruction: get opcode (all characters until null, comma, + or numeric (including spaces). +*/ + + while (1) { + if (*cptr == ',' || *cptr == '\0' || + isdigit(*cptr)) + break; + gbuf[i] = toupper(*cptr); + cptr++; + i++; + } + +/* Allow for RST which has numeric as part of opcode */ + + if (toupper(gbuf[0]) == 'R' && + toupper(gbuf[1]) == 'S' && + toupper(gbuf[2]) == 'T') { + gbuf[i] = toupper(*cptr); + cptr++; + i++; + } + +/* Allow for 'MOV' which is only opcode that has comma in it. */ + + if (toupper(gbuf[0]) == 'M' && + toupper(gbuf[1]) == 'O' && + toupper(gbuf[2]) == 'V') { + gbuf[i] = toupper(*cptr); + cptr++; + i++; + gbuf[i] = toupper(*cptr); + cptr++; + i++; + } + +/* kill trailing spaces if any */ + gbuf[i] = '\0'; + for (j = i - 1; gbuf[j] == ' '; j--) { + gbuf[j] = '\0'; + } + +/* find opcode in table */ + for (j = 0; j < 256; j++) { + if (strcmp(gbuf, opcode[j]) == 0) + break; + } + if (j > 255) /* not found */ + return SCPE_ARG; + + val[0] = j; /* store opcode */ + if (oplen[j] < 2) /* if 1-byter we are done */ + return SCPE_OK; + if (*cptr == ',') cptr++; + cptr = get_glyph(cptr, gbuf, 0); /* get address */ + sscanf(gbuf, "%o", &r); + if (oplen[j] == 2) { + val[1] = r & 0xFF; + return (-1); + } + val[1] = r & 0xFF; + val[2] = (r >> 8) & 0xFF; + return (-2); +} diff --git a/MDS-800/common/i8251.c b/MDS-800/common/i8251.c new file mode 100644 index 00000000..b1092b37 --- /dev/null +++ b/MDS-800/common/i8251.c @@ -0,0 +1,252 @@ +/* i8251.c: Intel i8251 UART adapter + + Copyright (c) 2010, William A. Beech + + Permission is hereby granted, free of charge, to any person obtaining a + copy of this software and associated documentation files (the "Software"), + to deal in the Software without restriction, including without limitation + the rights to use, copy, modify, merge, publish, distribute, sublicense, + and/or sell copies of the Software, and to permit persons to whom the + Software is furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + WILLIAM A. BEECH BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + Except as contained in this notice, the name of William A. Beech shall not be + used in advertising or otherwise to promote the sale, use or other dealings + in this Software without prior written authorization from William A. Beech. + + These functions support a simulated i8251 interface device on an iSBC. + The device had one physical I/O port which could be connected + to any serial I/O device that would connect to a current loop, + RS232, or TTY interface. Available baud rates were jumper + selectable for each port from 110 to 9600. + + All I/O is via programmed I/O. The i8251 has a status port + and a data port. + + The simulated device does not support synchronous mode. The simulated device + supports a select from I/O space and one address line. The data port is at the + lower address and the status/command port is at the higher. + + A write to the status port can select some options for the device: + + Asynchronous Mode Instruction + 7 6 5 4 3 2 1 0 + +---+---+---+---+---+---+---+---+ + | S2 S1 EP PEN L2 L1 B2 B1| + +---+---+---+---+---+---+---+---+ + + Baud Rate Factor + B2 0 1 0 1 + B1 0 0 1 1 + sync 1X 16X 64X + mode + + Character Length + L2 0 1 0 1 + L1 0 0 1 1 + 5 6 7 8 + bits bits bits bits + + EP - A 1 in this bit position selects even parity. + PEN - A 1 in this bit position enables parity. + + Number of Stop Bits + S2 0 1 0 1 + S1 0 0 1 1 + invalid 1 1.5 2 + bit bits bits + + Command Instruction Format + 7 6 5 4 3 2 1 0 + +---+---+---+---+---+---+---+---+ + | EH IR RTS ER SBRK RxE DTR TxE| + +---+---+---+---+---+---+---+---+ + + TxE - A 1 in this bit position enables transmit. + DTR - A 1 in this bit position forces *DTR to zero. + RxE - A 1 in this bit position enables receive. + SBRK - A 1 in this bit position forces TxD to zero. + ER - A 1 in this bit position resets the error bits + RTS - A 1 in this bit position forces *RTS to zero. + IR - A 1 in this bit position returns the 8251 to Mode Instruction Format. + EH - A 1 in this bit position enables search for sync characters. + + A read of the status port gets the port status: + + Status Read Format + 7 6 5 4 3 2 1 0 + +---+---+---+---+---+---+---+---+ + |DSR SD FE OE PE TxE RxR TxR| + +---+---+---+---+---+---+---+---+ + + TxR - A 1 in this bit position signals transmit ready to receive a character. + RxR - A 1 in this bit position signals receiver has a character. + TxE - A 1 in this bit position signals transmitter has no more characters to transmit. + PE - A 1 in this bit signals a parity error. + OE - A 1 in this bit signals an transmit overrun error. + FE - A 1 in this bit signals a framing error. + SD - A 1 in this bit position returns the 8251 to Mode Instruction Format. + DSR - A 1 in this bit position signals *DSR is at zero. + + A read from the data port gets the typed character, a write + to the data port writes the character to the device. + + ?? ??? 10 - Original file. + 16 Dec 12 - Modified to use isbc_80_10.cfg file to set base and size. +*/ + +#include "system_defs.h" + +#define UNIT_V_ANSI (UNIT_V_UF + 0) /* ANSI mode */ +#define UNIT_ANSI (1 << UNIT_V_ANSI) + +#define TXR 0x01 +#define RXR 0x02 +#define TXE 0x04 +#define SD 0x40 + +extern int32 reg_dev(int32 (*routine)(), int32 port); + +/* function prototypes */ + +t_stat i8251_svc (UNIT *uptr); +t_stat i8251_reset (DEVICE *dptr, int32 base); +int32 i8251s(int32 io, int32 data); +int32 i8251d(int32 io, int32 data); +void i8251_reset1(void); +/* i8251 Standard I/O Data Structures */ + +UNIT i8251_unit = { + UDATA (&i8251_svc, 0, 0), KBD_POLL_WAIT +}; + +REG i8251_reg[] = { + { HRDATA (DATA, i8251_unit.buf, 8) }, + { HRDATA (STAT, i8251_unit.u3, 8) }, + { HRDATA (MODE, i8251_unit.u4, 8) }, + { HRDATA (CMD, i8251_unit.u5, 8) }, + { NULL } +}; + +MTAB i8251_mod[] = { + { UNIT_ANSI, 0, "TTY", "TTY", NULL }, + { UNIT_ANSI, UNIT_ANSI, "ANSI", "ANSI", NULL }, + { 0 } +}; + +DEVICE i8251_dev = { + "8251", //name + &i8251_unit, //units + i8251_reg, //registers + i8251_mod, //modifiers + 1, //numunits + 10, //aradix + 31, //awidth + 1, //aincr + 16, //dradix + 8, //dwidth + NULL, //examine + NULL, //deposit +// &i8251_reset, //reset + NULL, //reset + NULL, //boot + NULL, //attach + NULL, //detach + NULL, //ctxt + 0, //flags + 0, //dctrl + NULL, //debflags + NULL, //msize + NULL //lname +}; + +/* Service routines to handle simulator functions */ + +/* i8251_svc - actually gets char & places in buffer */ + +t_stat i8251_svc (UNIT *uptr) +{ + int32 temp; + + sim_activate (&i8251_unit, i8251_unit.wait); /* continue poll */ + if ((temp = sim_poll_kbd ()) < SCPE_KFLAG) + return temp; /* no char or error? */ + i8251_unit.buf = temp & 0xFF; /* Save char */ + i8251_unit.u3 |= RXR; /* Set status */ + + /* Do any special character handling here */ + + i8251_unit.pos++; + return SCPE_OK; +} + +/* Reset routine */ + +t_stat i8251_reset (DEVICE *dptr, int32 base) +{ + reg_dev(i8251d, base); + reg_dev(i8251s, base + 1); + reg_dev(i8251d, base + 2); + reg_dev(i8251s, base + 3); + i8251_reset1(); + printf(" 8251: Registered at %02X\n", base); + sim_activate (&i8251_unit, i8251_unit.wait); /* activate unit */ + return SCPE_OK; +} + +/* I/O instruction handlers, called from the CPU module when an + IN or OUT instruction is issued. +*/ + +int32 i8251s(int32 io, int32 data) +{ +// printf("\nio=%d data=%04X\n", io, data); + if (io == 0) { /* read status port */ + return i8251_unit.u3; + } else { /* write status port */ + if (i8251_unit.u6) { /* if mode, set cmd */ + i8251_unit.u5 = data; + printf("8251: Command Instruction=%02X\n", data); + if (data & SD) /* reset port! */ + i8251_reset1(); + } else { /* set mode */ + i8251_unit.u4 = data; + printf("8251: Mode Instruction=%02X\n", data); + i8251_unit.u6 = 1; /* set cmd received */ + } + return (0); + } +} + +int32 i8251d(int32 io, int32 data) +{ + if (io == 0) { /* read data port */ + i8251_unit.u3 &= ~RXR; + return (i8251_unit.buf); + } else { /* write data port */ + sim_putchar(data); + } + return 0; +} + +void i8251_reset1(void) +{ + i8251_unit.u3 = TXR + TXE; /* status */ + i8251_unit.u4 = 0; /* mode instruction */ + i8251_unit.u5 = 0; /* command instruction */ + i8251_unit.u6 = 0; + i8251_unit.buf = 0; + i8251_unit.pos = 0; + printf(" 8251: Reset\n"); +} + +/* end of i8251.c */ diff --git a/MDS-800/common/i8255.c b/MDS-800/common/i8255.c new file mode 100644 index 00000000..b0b3e79b --- /dev/null +++ b/MDS-800/common/i8255.c @@ -0,0 +1,459 @@ +/* i8255.c: Intel i8255 PIO adapter + + Copyright (c) 2010, William A. Beech + + Permission is hereby granted, free of charge, to any person obtaining a + copy of this software and associated documentation files (the "Software"), + to deal in the Software without restriction, including without limitation + the rights to use, copy, modify, merge, publish, distribute, sublicense, + and/or sell copies of the Software, and to permit persons to whom the + Software is furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + WILLIAM A. BEECH BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + Except as contained in this notice, the name of William A. Beech shall not be + used in advertising or otherwise to promote the sale, use or other dealings + in this Software without prior written authorization from William A. Beech. + + These functions support a simulated i8255 interface device on an iSBC. + The device has threee physical 8-bit I/O ports which could be connected + to any parallel I/O device. + + All I/O is via programmed I/O. The i8255 has a control port (PIOS) + and three data ports (PIOA, PIOB, and PIOC). + + The simulated device supports a select from I/O space and two address lines. + The data ports are at the lower addresses and the control port is at + the highest. + + A write to the control port can configure the device: + + Control Word + +---+---+---+---+---+---+---+---+ + | D7 D6 D5 D4 D3 D2 D1 D0| + +---+---+---+---+---+---+---+---+ + + Group B + D0 Port C (lower) 1-Input, 0-Output + D1 Port B 1-Input, 0-Output + D2 Mode Selection 0-Mode 0, 1-Mode 1 + + Group A + D3 Port C (upper) 1-Input, 0-Output + D4 Port A 1-Input, 0-Output + D5-6 Mode Selection 00-Mode 0, 01-Mode 1, 1X-Mode 2 + + D7 Mode Set Flag 1=Active, 0=Bit Set + + Mode 0 - Basic Input/Output + Mode 1 - Strobed Input/Output + Mode 2 - Bidirectional Bus + + Bit Set - D7=0, D3:1 select port C bit, D0 1=set, 0=reset + + A read to the data ports gets the current port value, a write + to the data ports writes the character to the device. + + *** Need to modify so that multiple devices can be registered and + used. + + ?? ??? 10 - Original file. + 16 Dec 12 - Modified to use isbc_80_10.cfg file to set base and size. +*/ + +#include "system_defs.h" /* system header in system dir */ +#define i8255_DEV 4 /* number of devices */ + +/* function prototypes */ + +int32 i8255s0(int32 io, int32 data); +int32 i8255a0(int32 io, int32 data); +int32 i8255b0(int32 io, int32 data); +int32 i8255c0(int32 io, int32 data); +int32 i8255s1(int32 io, int32 data); +int32 i8255a1(int32 io, int32 data); +int32 i8255b1(int32 io, int32 data); +int32 i8255c1(int32 io, int32 data); +int32 i8255s2(int32 io, int32 data); +int32 i8255a2(int32 io, int32 data); +int32 i8255b2(int32 io, int32 data); +int32 i8255c2(int32 io, int32 data); +int32 i8255s3(int32 io, int32 data); +int32 i8255a3(int32 io, int32 data); +int32 i8255b3(int32 io, int32 data); +int32 i8255c3(int32 io, int32 data); +t_stat i8255_reset (DEVICE *dptr, int32 base); + +/* external function prototypes */ + +extern int32 reg_dev(int32 (*routine)(), int32 port); + +/* globals */ + +int32 i8255_cnt = 0; +uint8 i8255_base[i8255_DEV]; + +/* i8255 Standard I/O Data Structures */ + +UNIT i8255_unit[] = { + { UDATA (0, 0, 0) }, + { UDATA (0, 0, 0) }, + { UDATA (0, 0, 0) }, + { UDATA (0, 0, 0) } +}; + +DEBTAB i8255_debug[] = { + { "ALL", DEBUG_all }, + { "FLOW", DEBUG_flow }, + { "READ", DEBUG_read }, + { "WRITE", DEBUG_write }, + { "XACK", DEBUG_xack }, + { "LEV1", DEBUG_level1 }, + { "LEV2", DEBUG_level2 }, + { NULL } +}; + +REG i8255_reg[] = { + { HRDATA (CONTROL0, i8255_unit[0].u3, 8) }, + { HRDATA (PORTA0, i8255_unit[0].u4, 8) }, + { HRDATA (PORTB0, i8255_unit[0].u5, 8) }, + { HRDATA (PORTC0, i8255_unit[0].u6, 8) }, + { HRDATA (CONTROL1, i8255_unit[1].u3, 8) }, + { HRDATA (PORTA1, i8255_unit[1].u4, 8) }, + { HRDATA (PORTB1, i8255_unit[1].u5, 8) }, + { HRDATA (PORTC1, i8255_unit[1].u6, 8) }, + { HRDATA (CONTROL1, i8255_unit[2].u3, 8) }, + { HRDATA (PORTA1, i8255_unit[2].u4, 8) }, + { HRDATA (PORTB1, i8255_unit[2].u5, 8) }, + { HRDATA (PORTC1, i8255_unit[2].u6, 8) }, + { HRDATA (CONTROL1, i8255_unit[3].u3, 8) }, + { HRDATA (PORTA1, i8255_unit[3].u4, 8) }, + { HRDATA (PORTB1, i8255_unit[3].u5, 8) }, + { HRDATA (PORTC1, i8255_unit[3].u6, 8) }, + { NULL } +}; + +DEVICE i8255_dev = { + "8255", //name + i8255_unit, //units + i8255_reg, //registers + NULL, //modifiers + 1, //numunits + 16, //aradix + 32, //awidth + 1, //aincr + 16, //dradix + 8, //dwidth + NULL, //examine + NULL, //deposit +// &i8255_reset, //reset + NULL, //reset + NULL, //boot + NULL, //attach + NULL, //detach + NULL, //ctxt + 0, //flags + 0, //dctrl + i8255_debug, //debflags + NULL, //msize + NULL //lname +}; + +/* I/O instruction handlers, called from the CPU module when an + IN or OUT instruction is issued. +*/ + +int32 i8255s0(int32 io, int32 data) +{ + int32 bit; + + if (io == 0) { /* read status port */ + return i8255_unit[0].u3; + } else { /* write status port */ + if (data & 0x80) { /* mode instruction */ + i8255_unit[0].u3 = data; + printf("8255-0: Mode Instruction=%02X\n", data); + if (data & 0x64) + printf(" Mode 1 and 2 not yet implemented\n"); + } else { /* bit set */ + bit = (data & 0x0E) >> 1; /* get bit number */ + if (data & 0x01) { /* set bit */ + i8255_unit[0].u6 |= (0x01 << bit); + } else { /* reset bit */ + i8255_unit[0].u6 &= ~(0x01 << bit); + } + } + } + return 0; +} + +int32 i8255a0(int32 io, int32 data) +{ + if (io == 0) { /* read data port */ + return (i8255_unit[0].u4); + } else { /* write data port */ + i8255_unit[0].u4 = data; + printf("8255-0: Port A = %02X\n", data); + } + return 0; +} + +int32 i8255b0(int32 io, int32 data) +{ + if (io == 0) { /* read data port */ + return (i8255_unit[0].u5); + } else { /* write data port */ + i8255_unit[0].u5 = data; + printf("8255-0: Port B = %02X\n", data); + } + return 0; +} + +int32 i8255c0(int32 io, int32 data) +{ + if (io == 0) { /* read data port */ + return (i8255_unit[0].u6); + } else { /* write data port */ + i8255_unit[0].u6 = data; + printf("8255-0: Port C = %02X\n", data); + } + return 0; +} + +int32 i8255s1(int32 io, int32 data) +{ + int32 bit; + + if (io == 0) { /* read status port */ + return i8255_unit[1].u3; + } else { /* write status port */ + if (data & 0x80) { /* mode instruction */ + i8255_unit[1].u3 = data; + printf("8255-1: Mode Instruction=%02X\n", data); + if (data & 0x64) + printf(" Mode 1 and 2 not yet implemented\n"); + } else { /* bit set */ + bit = (data & 0x0E) >> 1; /* get bit number */ + if (data & 0x01) { /* set bit */ + i8255_unit[1].u6 |= (0x01 << bit); + } else { /* reset bit */ + i8255_unit[1].u6 &= ~(0x01 << bit); + } + } + } + return 0; +} + +int32 i8255a1(int32 io, int32 data) +{ + if (io == 0) { /* read data port */ + return (i8255_unit[1].u4); + } else { /* write data port */ + i8255_unit[1].u4 = data; + printf("8255-1: Port A = %02X\n", data); + } + return 0; +} + +int32 i8255b1(int32 io, int32 data) +{ + if (io == 0) { /* read data port */ + return (i8255_unit[1].u5); + } else { /* write data port */ + i8255_unit[1].u5 = data; + printf("8255-1: Port B = %02X\n", data); + } + return 0; +} + +int32 i8255c1(int32 io, int32 data) +{ + if (io == 0) { /* read data port */ + return (i8255_unit[1].u6); + } else { /* write data port */ + i8255_unit[1].u6 = data; + printf("8255-1: Port C = %02X\n", data); + } + return 0; +} + +int32 i8255s2(int32 io, int32 data) +{ + int32 bit; + + if (io == 0) { /* read status port */ + return i8255_unit[2].u3; + } else { /* write status port */ + if (data & 0x80) { /* mode instruction */ + i8255_unit[2].u3 = data; + printf("8255-2: Mode Instruction=%02X\n", data); + if (data & 0x64) + printf(" Mode 1 and 2 not yet implemented\n"); + } else { /* bit set */ + bit = (data & 0x0E) >> 1; /* get bit number */ + if (data & 0x01) { /* set bit */ + i8255_unit[2].u6 |= (0x01 << bit); + } else { /* reset bit */ + i8255_unit[2].u6 &= ~(0x01 << bit); + } + } + } + return 0; +} + +int32 i8255a2(int32 io, int32 data) +{ + if (io == 0) { /* read data port */ + return (i8255_unit[2].u4); + } else { /* write data port */ + i8255_unit[2].u4 = data; + printf("8255-2: Port A = %02X\n", data); + } + return 0; +} + +int32 i8255b2(int32 io, int32 data) +{ + if (io == 0) { /* read data port */ + return (i8255_unit[2].u5); + } else { /* write data port */ + i8255_unit[2].u5 = data; + printf("8255-2: Port B = %02X\n", data); + } + return 0; +} + +int32 i8255c2(int32 io, int32 data) +{ + if (io == 0) { /* read data port */ + return (i8255_unit[2].u6); + } else { /* write data port */ + i8255_unit[2].u6 = data; + printf("8255-2: Port C = %02X\n", data); + } + return 0; +} + +int32 i8255s3(int32 io, int32 data) +{ + int32 bit; + + if (io == 0) { /* read status port */ + return i8255_unit[3].u3; + } else { /* write status port */ + if (data & 0x80) { /* mode instruction */ + i8255_unit[3].u3 = data; + printf("8255-3: Mode Instruction=%02X\n", data); + if (data & 0x64) + printf("\n Mode 1 and 2 not yet implemented\n"); + } else { /* bit set */ + bit = (data & 0x0E) >> 1; /* get bit number */ + if (data & 0x01) { /* set bit */ + i8255_unit[3].u6 |= (0x01 << bit); + } else { /* reset bit */ + i8255_unit[3].u6 &= ~(0x01 << bit); + } + } + } + return 0; +} + +int32 i8255a3(int32 io, int32 data) +{ + if (io == 0) { /* read data port */ + return (i8255_unit[3].u4); + } else { /* write data port */ + i8255_unit[3].u4 = data; + printf("8255-3: Port A = %02X\n", data); + } + return 0; +} + +int32 i8255b3(int32 io, int32 data) +{ + if (io == 0) { /* read data port */ + return (i8255_unit[3].u5); + } else { /* write data port */ + i8255_unit[3].u5 = data; + printf("8255-3: Port B = %02X\n", data); + } + return 0; +} + +int32 i8255c3(int32 io, int32 data) +{ + if (io == 0) { /* read data port */ + return (i8255_unit[3].u6); + } else { /* write data port */ + i8255_unit[3].u6 = data; + printf("8255-3: Port C = %02X\n", data); + } + return 0; +} + +/* Reset routine */ + +t_stat i8255_reset (DEVICE *dptr, int32 base) +{ + switch (i8255_cnt) { + case 0: + reg_dev(i8255a0, base); + reg_dev(i8255b0, base + 1); + reg_dev(i8255c0, base + 2); + reg_dev(i8255s0, base + 3); + i8255_unit[0].u3 = 0x9B; /* control */ + i8255_unit[0].u4 = 0xFF; /* Port A */ + i8255_unit[0].u5 = 0xFF; /* Port B */ + i8255_unit[0].u6 = 0xFF; /* Port C */ + printf(" 8255-0: Reset\n"); + break; + case 1: + reg_dev(i8255a1, base); + reg_dev(i8255b1, base + 1); + reg_dev(i8255c1, base + 2); + reg_dev(i8255s1, base + 3); + i8255_unit[1].u3 = 0x9B; /* control */ + i8255_unit[1].u4 = 0xFF; /* Port A */ + i8255_unit[1].u5 = 0xFF; /* Port B */ + i8255_unit[1].u6 = 0xFF; /* Port C */ + printf(" 8255-1: Reset\n"); + break; + case 2: + reg_dev(i8255a2, base); + reg_dev(i8255b2, base + 1); + reg_dev(i8255c2, base + 2); + reg_dev(i8255s2, base + 3); + i8255_unit[2].u3 = 0x9B; /* control */ + i8255_unit[2].u4 = 0xFF; /* Port A */ + i8255_unit[2].u5 = 0xFF; /* Port B */ + i8255_unit[2].u6 = 0xFF; /* Port C */ + printf(" 8255-2: Reset\n"); + break; + case 3: + reg_dev(i8255a3, base); + reg_dev(i8255b3, base + 1); + reg_dev(i8255c3, base + 2); + reg_dev(i8255s3, base + 3); + i8255_unit[3].u3 = 0x9B; /* control */ + i8255_unit[3].u4 = 0xFF; /* Port A */ + i8255_unit[3].u5 = 0xFF; /* Port B */ + i8255_unit[3].u6 = 0xFF; /* Port C */ + printf(" 8255-3: Reset\n"); + break; + default: + printf(" 8255: Bad device\n"); + } + printf(" 8255-%d: Registered at %02X\n", i8255_cnt, base); + i8255_cnt++; + return SCPE_OK; +} + +/* end of i8255.c */ diff --git a/MDS-800/common/i8259.c b/MDS-800/common/i8259.c new file mode 100644 index 00000000..8b319261 --- /dev/null +++ b/MDS-800/common/i8259.c @@ -0,0 +1,304 @@ +/* i8259.c: Intel i8259 PIC adapter + + Copyright (c) 2010, William A. Beech + + Permission is hereby granted, free of charge, to any person obtaining a + copy of this software and associated documentation files (the "Software"), + to deal in the Software without restriction, including without limitation + the rights to use, copy, modify, merge, publish, distribute, sublicense, + and/or sell copies of the Software, and to permit persons to whom the + Software is furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + WILLIAM A. BEECH BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + Except as contained in this notice, the name of William A. Beech shall not be + used in advertising or otherwise to promote the sale, use or other dealings + in this Software without prior written authorization from William A. Beech. + + These functions support a simulated i8259 interface device on an iSBC. + 24 Jan 13 - Original file. +*/ + +#include "system_defs.h" /* system header in system dir */ +#define i8259_DEV 2 /* number of devices */ + +/* function prototypes */ + +int32 i8259a0(int32 io, int32 data); +int32 i8259b0(int32 io, int32 data); +int32 i8259a1(int32 io, int32 data); +int32 i8259b1(int32 io, int32 data); +void i8259_dump(int32 dev); +t_stat i8259_reset (DEVICE *dptr, int32 base); + +/* external function prototypes */ + +extern int32 reg_dev(int32 (*routine)(), int32 port); + +/* globals */ + +int32 i8259_cnt = 0; +uint8 i8259_base[i8259_DEV]; +uint8 i8259_icw1[i8259_DEV]; +uint8 i8259_icw2[i8259_DEV]; +uint8 i8259_icw3[i8259_DEV]; +uint8 i8259_icw4[i8259_DEV]; +uint8 i8259_ocw1[i8259_DEV]; +uint8 i8259_ocw2[i8259_DEV]; +uint8 i8259_ocw3[i8259_DEV]; +int32 icw_num0 = 1, icw_num1 = 1; + +/* i8255 Standard I/O Data Structures */ + +UNIT i8259_unit[] = { + { UDATA (0, 0, 0) }, + { UDATA (0, 0, 0) } +}; + +DEBTAB i8259_debug[] = { + { "ALL", DEBUG_all }, + { "FLOW", DEBUG_flow }, + { "READ", DEBUG_read }, + { "WRITE", DEBUG_write }, + { "XACK", DEBUG_xack }, + { "LEV1", DEBUG_level1 }, + { "LEV2", DEBUG_level2 }, + { NULL } +}; + +REG i8259_reg[] = { + { HRDATA (IRR0, i8259_unit[0].u3, 8) }, + { HRDATA (ISR0, i8259_unit[0].u4, 8) }, + { HRDATA (IMR0, i8259_unit[0].u5, 8) }, + { HRDATA (IRR1, i8259_unit[1].u3, 8) }, + { HRDATA (ISR1, i8259_unit[1].u4, 8) }, + { HRDATA (IMR1, i8259_unit[1].u5, 8) }, + { NULL } +}; + +DEVICE i8259_dev = { + "8259", //name + i8259_unit, //units + i8259_reg, //registers + NULL, //modifiers + 1, //numunits + 16, //aradix + 32, //awidth + 1, //aincr + 16, //dradix + 8, //dwidth + NULL, //examine + NULL, //deposit +// &i8259_reset, //reset + NULL, //reset + NULL, //boot + NULL, //attach + NULL, //detach + NULL, //ctxt + 0, //flags + 0, //dctrl + i8259_debug, //debflags + NULL, //msize + NULL //lname +}; + +/* I/O instruction handlers, called from the CPU module when an + IN or OUT instruction is issued. +*/ + +int32 i8259a0(int32 io, int32 data) +{ + int32 bit; + + if (io == 0) { /* read data port */ + if ((i8259_ocw3[0] & 0x03) == 0x02) + return (i8259_unit[0].u3); /* IRR */ + if ((i8259_ocw3[0] & 0x03) == 0x03) + return (i8259_unit[0].u4); /* ISR */ + } else { /* write data port */ + if (data & 0x10) { + icw_num0 = 1; + } + if (icw_num0 == 1) { + i8259_icw1[0] = data; /* ICW1 */ + i8259_unit[0].u5 = 0x00; /* clear IMR */ + i8259_ocw3[0] = 0x02; /* clear OCW3, Sel IRR */ + } else { + switch (data & 0x18) { + case 0: /* OCW2 */ + i8259_ocw2[0] = data; + break; + case 8: /* OCW3 */ + i8259_ocw3[0] = data; + break; + default: + printf("8259b-0: OCW Error %02X\n", data); + break; + } + } + printf("8259a-0: data = %02X\n", data); + icw_num0++; /* step ICW number */ + } + i8259_dump(0); + return 0; +} + +int32 i8259b0(int32 io, int32 data) +{ + if (io == 0) { /* read data port */ + return (i8259_unit[0].u5); /* IMR */ + } else { /* write data port */ + if (icw_num0 >= 2 && icw_num0 < 5) { /* ICW mode */ + switch (icw_num0) { + case 2: /* ICW2 */ + i8259_icw2[0] = data; + break; + case 3: /* ICW3 */ + i8259_icw3[0] = data; + break; + case 4: /* ICW4 */ + if (i8259_icw1[0] & 0x01) + i8259_icw4[0] = data; + else + printf("8259b-0: ICW4 not enabled - data=%02X\n", data); + break; + default: + printf("8259b-0: ICW Error %02X\n", data); + break; + } + icw_num0++; + } else { + i8259_ocw1[0] = data; /* OCW0 */ + } + } + i8259_dump(0); + return 0; +} + +int32 i8259a1(int32 io, int32 data) +{ + int32 bit; + + if (io == 0) { /* read data port */ + if ((i8259_ocw3[1] & 0x03) == 0x02) + return (i8259_unit[1].u3); /* IRR */ + if ((i8259_ocw3[1] & 0x03) == 0x03) + return (i8259_unit[1].u4); /* ISR */ + } else { /* write data port */ + if (data & 0x10) { + icw_num1 = 1; + } + if (icw_num1 == 1) { + i8259_icw1[1] = data; /* ICW1 */ + i8259_unit[1].u5 = 0x00; /* clear IMR */ + i8259_ocw3[1] = 0x02; /* clear OCW3, Sel IRR */ + } else { + switch (data & 0x18) { + case 0: /* OCW2 */ + i8259_ocw2[1] = data; + break; + case 8: /* OCW3 */ + i8259_ocw3[1] = data; + break; + default: + printf("8259b-1: OCW Error %02X\n", data); + break; + } + } + printf("8259a-1: data = %02X\n", data); + icw_num1++; /* step ICW number */ + } + i8259_dump(1); + return 0; +} + +int32 i8259b1(int32 io, int32 data) +{ + if (io == 0) { /* read data port */ + return (i8259_unit[1].u5); /* IMR */ + } else { /* write data port */ + if (icw_num1 >= 2 && icw_num1 < 5) { /* ICW mode */ + switch (icw_num1) { + case 2: /* ICW2 */ + i8259_icw2[1] = data; + break; + case 3: /* ICW3 */ + i8259_icw3[1] = data; + break; + case 4: /* ICW4 */ + if (i8259_icw1[1] & 0x01) + i8259_icw4[1] = data; + else + printf("8259b-1: ICW4 not enabled - data=%02X\n", data); + break; + default: + printf("8259b-1: ICW Error %02X\n", data); + break; + } + icw_num1++; + } else { + i8259_ocw1[1] = data; /* OCW0 */ + } + } + i8259_dump(1); + return 0; +} + +void i8259_dump(int32 dev) +{ + printf("Device %d\n", dev); + printf(" IRR = %02X\n", i8259_unit[dev].u3); + printf(" ISR = %02X\n", i8259_unit[dev].u4); + printf(" IMR = %02X\n", i8259_unit[dev].u5); + printf(" ICW1 = %02X\n", i8259_icw1[dev]); + printf(" ICW2 = %02X\n", i8259_icw2[dev]); + printf(" ICW3 = %02X\n", i8259_icw3[dev]); + printf(" ICW4 = %02X\n", i8259_icw4[dev]); + printf(" OCW1 = %02X\n", i8259_ocw1[dev]); + printf(" OCW2 = %02X\n", i8259_ocw2[dev]); + printf(" OCW3 = %02X\n", i8259_ocw3[dev]); +} + +/* Reset routine */ + +t_stat i8259_reset (DEVICE *dptr, int32 base) +{ + switch (i8259_cnt) { + case 0: + reg_dev(i8259a0, base); + reg_dev(i8259b0, base + 1); + reg_dev(i8259a0, base + 2); + reg_dev(i8259b0, base + 3); + i8259_unit[0].u3 = 0x00; /* IRR */ + i8259_unit[0].u4 = 0x00; /* ISR */ + i8259_unit[0].u5 = 0x00; /* IMR */ + printf(" 8259-0: Reset\n"); + break; + case 1: + reg_dev(i8259a1, base); + reg_dev(i8259b1, base + 1); + reg_dev(i8259a1, base + 2); + reg_dev(i8259b1, base + 3); + i8259_unit[1].u3 = 0x00; /* IRR */ + i8259_unit[1].u4 = 0x00; /* ISR */ + i8259_unit[1].u5 = 0x00; /* IMR */ + printf(" 8259-1: Reset\n"); + break; + default: + printf(" 8259: Bad device\n"); + break; + } + printf(" 8259-%d: Registered at %02X\n", i8259_cnt, base); + i8259_cnt++; + return SCPE_OK; +} + +/* end of i8259.c */ diff --git a/MDS-800/common/i8273.c b/MDS-800/common/i8273.c new file mode 100644 index 00000000..c51e3066 --- /dev/null +++ b/MDS-800/common/i8273.c @@ -0,0 +1,252 @@ +/* i8273.c: Intel i8273 UART adapter + + Copyright (c) 2011, William A. Beech + + Permission is hereby granted, free of charge, to any person obtaining a + copy of this software and associated documentation files (the "Software"), + to deal in the Software without restriction, including without limitation + the rights to use, copy, modify, merge, publish, distribute, sublicense, + and/or sell copies of the Software, and to permit persons to whom the + Software is furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + WILLIAM A. BEECH BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + Except as contained in this notice, the name of William A. Beech shall not be + used in advertising or otherwise to promote the sale, use or other dealings + in this Software without prior written authorization from William A. Beech. + + These functions support a simulated i8273 interface device on an iSBC. + The device had one physical I/O port which could be connected + to any serial I/O device that would connect to a current loop, + RS232, or TTY interface. Available baud rates were jumper + selectable for each port from 110 to 9600. + + All I/O is via programmed I/O. The i8273 has a status port + and a data port. + + The simulated device does not support synchronous mode. The simulated device + supports a select from I/O space and one address line. The data port is at the + lower address and the status/command port is at the higher. + + A write to the status port can select some options for the device: + + Asynchronous Mode Instruction + +---+---+---+---+---+---+---+---+ + | S2 S1 EP PEN L2 L1 B2 B1| + +---+---+---+---+---+---+---+---+ + + Baud Rate Factor + B2 0 1 0 1 + B1 0 0 1 1 + sync 1X 16X 64X + mode + + Character Length + L2 0 1 0 1 + L1 0 0 1 1 + 5 6 7 8 + bits bits bits bits + + EP - A 1 in this bit position selects even parity. + PEN - A 1 in this bit position enables parity. + + Number of Stop Bits + S2 0 1 0 1 + S1 0 0 1 1 + invalid 1 1.5 2 + bit bits bits + + Command Instruction Format + +---+---+---+---+---+---+---+---+ + | EH IR RTS ER SBRK RxE DTR TxE| + +---+---+---+---+---+---+---+---+ + + TxE - A 1 in this bit position enables transmit. + DTR - A 1 in this bit position forces *DTR to zero. + RxE - A 1 in this bit position enables receive. + SBRK - A 1 in this bit position forces TxD to zero. + ER - A 1 in this bit position resets the error bits + RTS - A 1 in this bit position forces *RTS to zero. + IR - A 1 in this bit position returns the 8251 to Mode Instruction Format. + EH - A 1 in this bit position enables search for sync characters. + + A read of the status port gets the port status: + + Status Read Format + +---+---+---+---+---+---+---+---+ + |DSR SD FE OE PE TxE RxR TxR| + +---+---+---+---+---+---+---+---+ + + TxR - A 1 in this bit position signals transmit ready to receive a character. + RxR - A 1 in this bit position signals receiver has a character. + TxE - A 1 in this bit position signals transmitter has no more characters to transmit. + PE - A 1 in this bit signals a parity error. + OE - A 1 in this bit signals an transmit overrun error. + FE - A 1 in this bit signals a framing error. + SD - A 1 in this bit position returns the 8251 to Mode Instruction Format. + DSR - A 1 in this bit position signals *DSR is at zero. + + A read to the data port gets the buffered character, a write + to the data port writes the character to the device. + +*/ + +#include + +#include "multibus_defs.h" + +#define UNIT_V_ANSI (UNIT_V_UF + 0) /* ANSI mode */ +#define UNIT_ANSI (1 << UNIT_V_ANSI) + +uint8 + wr0 = 0, /* command register */ + wr1 = 0, /* enable register */ + wr2 = 0, /* CH A mode register */ + /* CH B interrups vector */ + wr3 = 0, /* configuration register 1 */ + wr4 = 0, /* configuration register 2 */ + wr5 = 0, /* configuration register 3 */ + wr6 = 0, /* sync low byte */ + wr7 = 0, /* sync high byte */ + rr0 = 0, /* status register */ + rr1 = 0, /* error register */ + rr2 = 0; /* read interrupt vector */ + +/* function prototypes */ + +t_stat i8273_reset (DEVICE *dptr); + +/* i8273 Standard I/O Data Structures */ + +UNIT i8273_unit = { UDATA (NULL, 0, 0), KBD_POLL_WAIT }; + +REG i8273_reg[] = { + { HRDATA (WR0, wr0, 8) }, + { HRDATA (WR1, wr1, 8) }, + { HRDATA (WR2, wr2, 8) }, + { HRDATA (WR3, wr3, 8) }, + { HRDATA (WR4, wr4, 8) }, + { HRDATA (WR5, wr5, 8) }, + { HRDATA (WR6, wr6, 8) }, + { HRDATA (WR7, wr7, 8) }, + { HRDATA (RR0, rr0, 8) }, + { HRDATA (RR0, rr1, 8) }, + { HRDATA (RR0, rr2, 8) }, + { NULL } +}; +MTAB i8273_mod[] = { + { UNIT_ANSI, 0, "TTY", "TTY", NULL }, + { UNIT_ANSI, UNIT_ANSI, "ANSI", "ANSI", NULL }, + { 0 } +}; + +DEBTAB i8273_debug[] = { + { "ALL", DEBUG_all }, + { "FLOW", DEBUG_flow }, + { "READ", DEBUG_read }, + { "WRITE", DEBUG_write }, + { "LEV1", DEBUG_level1 }, + { "LEV2", DEBUG_level2 }, + { NULL } +}; + +DEVICE i8273_dev = { + "8251", //name + &i8273_unit, //units + i8273_reg, //registers + i8273_mod, //modifiers + 1, //numunits + 16, //aradix + 32, //awidth + 1, //aincr + 16, //dradix + 8, //dwidth + NULL, //examine + NULL, //deposit + i8273_reset, //reset + NULL, //boot + NULL, //attach + NULL, //detach + NULL, //ctxt + DEV_DEBUG, //flags + 0, //dctrl + i8273_debug, //debflags + NULL, //msize + NULL //lname +}; + +/* Service routines to handle simulator functions */ + +/* Reset routine */ + +t_stat i8273_reset (DEVICE *dptr) +{ + wr0 = 0; /* command register */ + wr1 = 0; /* enable register */ + wr2 = 0; /* CH A mode register */ + /* CH B interrups vector */ + wr3 = 0; /* configuration register 1 */ + wr4 = 0; /* configuration register 2 */ + wr5 = 0; /* configuration register 3 */ + wr6 = 0; /* sync low byte */ + wr7 = 0; /* sync high byte */ + rr0 = 0; /* status register */ + rr1 = 0; /* error register */ + rr2 = 0; /* read interrupt vector */ + printf(" 8273 Reset\n"); + return SCPE_OK; +} + +/* I/O instruction handlers, called from the CPU module when an + IN or OUT instruction is issued. + + Each function is passed an 'io' flag, where 0 means a read from + the port, and 1 means a write to the port. On input, the actual + input is passed as the return value, on output, 'data' is written + to the device. +*/ + +int32 i8273s(int32 io, int32 data) +{ + if (io == 0) { /* read status port */ + return i8273_unit.u3; + } else { /* write status port */ + if (data == 0x40) { /* reset port! */ + i8273_unit.u3 = 0x05; /* status */ + i8273_unit.u4 = 0; /* mode instruction */ + i8273_unit.u5 = 0; /* command instruction */ + i8273_unit.u6 = 0; + i8273_unit.buf = 0; + i8273_unit.pos = 0; + printf("8273 Reset\n"); + } else if (i8273_unit.u6) { + i8273_unit.u5 = data; + printf("8273 Command Instruction=%02X\n", data); + } else { + i8273_unit.u4 = data; + printf("8273 Mode Instruction=%02X\n", data); + i8273_unit.u6++; + } + return (0); + } +} + +int32 i8273d(int32 io, int32 data) +{ + if (io == 0) { /* read data port */ + i8273_unit.u3 &= 0xFD; + return (i8273_unit.buf); + } else { /* write data port */ + sim_putchar(data); + } + return 0; +} + diff --git a/MDS-800/common/i8274.c b/MDS-800/common/i8274.c new file mode 100644 index 00000000..a6749a02 --- /dev/null +++ b/MDS-800/common/i8274.c @@ -0,0 +1,351 @@ +/* i8274.c: Intel i8274 MPSC adapter + + Copyright (c) 2011, William A. Beech + + Permission is hereby granted, free of charge, to any person obtaining a + copy of this software and associated documentation files (the "Software"), + to deal in the Software without restriction, including without limitation + the rights to use, copy, modify, merge, publish, distribute, sublicense, + and/or sell copies of the Software, and to permit persons to whom the + Software is furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + WILLIAM A. BEECH BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + Except as contained in this notice, the name of William A. Beech shall not be + used in advertising or otherwise to promote the sale, use or other dealings + in this Software without prior written authorization from William A. Beech. + + These functions support a simulated i8274 interface device on an iSBC. + The device had two physical I/O ports which could be connected + to any serial I/O device that would connect to an RS232 interface. + + All I/O is via programmed I/O. The i8274 has a status port + and a data port. + + The simulated device does not support synchronous mode. The simulated device + supports a select from I/O space and two address lines. The data port is at the + lower address and the status/command port is at the higher address for each + channel. + + Minimum simulation is provided for this device. Channel A is used as a + console port for the iSBC-88/45 + + A write to the status port can select some options for the device: + + Asynchronous Mode Instruction + +---+---+---+---+---+---+---+---+ + | S2 S1 EP PEN L2 L1 B2 B1| + +---+---+---+---+---+---+---+---+ + + Baud Rate Factor + B2 0 1 0 1 + B1 0 0 1 1 + sync 1X 16X 64X + mode + + Character Length + L2 0 1 0 1 + L1 0 0 1 1 + 5 6 7 8 + bits bits bits bits + + EP - A 1 in this bit position selects even parity. + PEN - A 1 in this bit position enables parity. + + Number of Stop Bits + S2 0 1 0 1 + S1 0 0 1 1 + invalid 1 1.5 2 + bit bits bits + + Command Instruction Format + +---+---+---+---+---+---+---+---+ + | EH IR RTS ER SBRK RxE DTR TxE| + +---+---+---+---+---+---+---+---+ + + TxE - A 1 in this bit position enables transmit. + DTR - A 1 in this bit position forces *DTR to zero. + RxE - A 1 in this bit position enables receive. + SBRK - A 1 in this bit position forces TxD to zero. + ER - A 1 in this bit position resets the error bits + RTS - A 1 in this bit position forces *RTS to zero. + IR - A 1 in this bit position returns the 8251 to Mode Instruction Format. + EH - A 1 in this bit position enables search for sync characters. + + A read of the status port gets the port status: + + Status Read Format + +---+---+---+---+---+---+---+---+ + |DSR SD FE OE PE TxE RxR TxR| + +---+---+---+---+---+---+---+---+ + + TxR - A 1 in this bit position signals transmit ready to receive a character. + RxR - A 1 in this bit position signals receiver has a character. + TxE - A 1 in this bit position signals transmitter has no more characters to transmit. + PE - A 1 in this bit signals a parity error. + OE - A 1 in this bit signals an transmit overrun error. + FE - A 1 in this bit signals a framing error. + SD - A 1 in this bit position returns the 8251 to Mode Instruction Format. + DSR - A 1 in this bit position signals *DSR is at zero. + + A read to the data port gets the buffered character, a write + to the data port writes the character to the device. + +*/ + +#include + +#include "multibus_defs.h" + +#define UNIT_V_ANSI (UNIT_V_UF + 0) /* ANSI mode */ +#define UNIT_ANSI (1 << UNIT_V_ANSI) + +/* register definitions */ +/* channel A */ +uint8 wr0a = 0, /* command register */ + wr1a = 0, /* enable register */ + wr2a = 0, /* mode register */ + wr3a = 0, /* configuration register 1 */ + wr4a = 0, /* configuration register 2 */ + wr5a = 0, /* configuration register 3 */ + wr6a = 0, /* sync low byte */ + wr7a = 0, /* sync high byte */ + rr0a = 0, /* status register */ + rr1a = 0, /* error register */ + rr2a = 0; /* read interrupt vector */ +/* channel B */ +uint8 wr0b = 0, /* command register */ + wr1b = 0, /* enable register */ + wr2b = 0, /* CH B interrups vector */ + wr3b = 0, /* configuration register 1 */ + wr4b = 0, /* configuration register 2 */ + wr5b = 0, /* configuration register 3 */ + wr6b = 0, /* sync low byte */ + wr7b = 0, /* sync high byte */ + rr0b = 0, /* status register */ + rr1b = 0, /* error register */ + rr2b = 0; /* read interrupt vector */ + +/* function prototypes */ + +t_stat i8274_svc (UNIT *uptr); +t_stat i8274_reset (DEVICE *dptr); +int32 i8274As(int32 io, int32 data); +int32 i8274Ad(int32 io, int32 data); +int32 i8274Bs(int32 io, int32 data); +int32 i8274Bd(int32 io, int32 data); + +/* i8274 Standard I/O Data Structures */ + +UNIT i8274_unit = { UDATA (NULL, 0, 0), KBD_POLL_WAIT }; + +REG i8274_reg[] = { + { HRDATA (WR0A, wr0a, 8) }, + { HRDATA (WR1A, wr1a, 8) }, + { HRDATA (WR2A, wr2a, 8) }, + { HRDATA (WR3A, wr3a, 8) }, + { HRDATA (WR4A, wr4a, 8) }, + { HRDATA (WR5A, wr5a, 8) }, + { HRDATA (WR6A, wr6a, 8) }, + { HRDATA (WR7A, wr7a, 8) }, + { HRDATA (RR0A, rr0a, 8) }, + { HRDATA (RR0A, rr1a, 8) }, + { HRDATA (RR0A, rr2a, 8) }, + { HRDATA (WR0B, wr0b, 8) }, + { HRDATA (WR1B, wr1b, 8) }, + { HRDATA (WR2B, wr2b, 8) }, + { HRDATA (WR3B, wr3b, 8) }, + { HRDATA (WR4B, wr4b, 8) }, + { HRDATA (WR5B, wr5b, 8) }, + { HRDATA (WR6B, wr6b, 8) }, + { HRDATA (WR7B, wr7b, 8) }, + { HRDATA (RR0B, rr0b, 8) }, + { HRDATA (RR0B, rr1b, 8) }, + { HRDATA (RR0B, rr2b, 8) }, + { NULL } +}; +MTAB i8274_mod[] = { + { UNIT_ANSI, 0, "TTY", "TTY", NULL }, + { UNIT_ANSI, UNIT_ANSI, "ANSI", "ANSI", NULL }, + { 0 } +}; + +DEBTAB i8274_debug[] = { + { "ALL", DEBUG_all }, + { "FLOW", DEBUG_flow }, + { "READ", DEBUG_read }, + { "WRITE", DEBUG_write }, + { "LEV1", DEBUG_level1 }, + { "LEV2", DEBUG_level2 }, + { NULL } +}; + +DEVICE i8274_dev = { + "8274", //name + &i8274_unit, //units + i8274_reg, //registers + i8274_mod, //modifiers + 1, //numunits + 16, //aradix + 32, //awidth + 1, //aincr + 16, //dradix + 8, //dwidth + NULL, //examine + NULL, //deposit + i8274_reset, //reset + NULL, //boot + NULL, //attach + NULL, //detach + NULL, //ctxt + DEV_DEBUG, //flags + 0, //dctrl + i8274_debug, //debflags + NULL, //msize + NULL //lname +}; + +/* Service routines to handle simulator functions */ + +/* service routine - actually gets char & places in buffer in CH A*/ + +t_stat i8274_svc (UNIT *uptr) +{ + int32 temp; + + sim_activate (&i8274_unit, i8274_unit.wait); /* continue poll */ + if ((temp = sim_poll_kbd ()) < SCPE_KFLAG) + return temp; /* no char or error? */ + i8274_unit.buf = temp & 0xFF; /* Save char */ + rr0a |= 0x01; /* Set rx char ready */ + + /* Do any special character handling here */ + + i8274_unit.pos++; + return SCPE_OK; +} + +/* Reset routine */ + +t_stat i8274_reset (DEVICE *dptr) +{ + wr0a = wr1a = wr2a = wr3a = wr4a = wr5a = wr6a = wr7a = rr0a = rr1a = rr2a = 0; + wr0b = wr1b = wr2b = wr3b = wr4b = wr5b = wr6b = wr7b = rr0b = rr1b = rr2b = 0; + printf(" 8274 Reset\n"); + return SCPE_OK; +} + +/* I/O instruction handlers, called from the CPU module when an + IN or OUT instruction is issued. + + Each function is passed an 'io' flag, where 0 means a read from + the port, and 1 means a write to the port. On input, the actual + input is passed as the return value, on output, 'data' is written + to the device. + + The 8274 contains 2 separate channels, A and B. +*/ + +/* channel A command/status */ +int32 i8274As(int32 io, int32 data) +{ + if (io == 0) { /* read status port */ + switch(wr0a & 0x7) { + case 0: /* rr0a */ + return rr0a; + case 1: /* rr1a */ + return rr1a; + case 2: /* rr1a */ + return rr2a; + } + return 0; /* bad register select */ + } else { /* write status port */ + switch(wr0a & 0x7) { + case 0: /* wr0a */ + wr0a = data; + if ((wr0a & 0x38) == 0x18) { /* channel reset */ + wr0a = wr1a = wr2a = wr3a = wr4a = wr5a = 0; + wr6a = wr7a = rr0a = rr1a = rr2a = 0; + printf("8274 Channel A reset\n"); + } + break; + case 1: /* wr1a */ + wr1a = data; + break; + case 2: /* wr2a */ + wr2a = data; + break; + case 3: /* wr3a */ + wr3a = data; + break; + case 4: /* wr4a */ + wr4a = data; + break; + case 5: /* wr5a */ + wr5a = data; + break; + case 6: /* wr6a */ + wr6a = data; + break; + case 7: /* wr7a */ + wr7a = data; + break; + } + printf("8274 Command WR%dA=%02X\n", wr0a & 0x7, data); + return 0; + } +} + +/* channel A data */ +int32 i8274Ad(int32 io, int32 data) +{ + if (io == 0) { /* read data port */ + rr0a &= 0xFE; + return (i8274_unit.buf); + } else { /* write data port */ + sim_putchar(data); + } + return 0; +} + +/* channel B command/status */ +int32 i8274Bs(int32 io, int32 data) +{ + if (io == 0) { /* read status port */ + return i8274_unit.u3; + } else { /* write status port */ + if (data == 0x40) { /* reset port! */ + printf("8274 Reset\n"); + } else if (i8274_unit.u6) { + i8274_unit.u5 = data; + printf("8274 Command Instruction=%02X\n", data); + } else { + i8274_unit.u4 = data; + printf("8274 Mode Instruction=%02X\n", data); + i8274_unit.u6++; + } + return (0); + } +} + +/* channel B data */ +int32 i8274Bd(int32 io, int32 data) +{ + if (io == 0) { /* read data port */ + i8274_unit.u3 &= 0xFD; + return (i8274_unit.buf); + } else { /* write data port */ + sim_putchar(data); + } + return 0; +} + +/* end of i8274.c */ \ No newline at end of file diff --git a/MDS-800/common/iSBC80-10.c b/MDS-800/common/iSBC80-10.c new file mode 100644 index 00000000..27a4a796 --- /dev/null +++ b/MDS-800/common/iSBC80-10.c @@ -0,0 +1,143 @@ +/* iSBC80-10.c: Intel iSBC 80/10 Processor simulator + + Copyright (c) 2010, William A. Beech + + Permission is hereby granted, free of charge, to any person obtaining a + copy of this software and associated documentation files (the "Software"), + to deal in the Software without restriction, including without limitation + the rights to use, copy, modify, merge, publish, distribute, sublicense, + and/or sell copies of the Software, and to permit persons to whom the + Software is furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + WILLIAM A. BEECH BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + Except as contained in this notice, the name of William A. Beech shall not be + used in advertising or otherwise to promote the sale, use or other dealings + in this Software without prior written authorization from William A. Beech. + + This software was written by Bill Beech, Dec 2010, to allow emulation of Multibus + Computer Systems. + + ?? ??? 10 - Original file. +*/ + +#include "system_defs.h" + +/* set the base I/O address for the first 8255 */ +#define I8255_BASE_0 0xE4 + +/* set the base I/O address for the second 8255 */ +#define I8255_BASE_1 0xE8 + +/* set the base I/O address for the 8251 */ +#define I8251_BASE 0xEC + +/* set the base and size for the EPROM on the iSBC 80/10 */ +#define ROM_SIZE 0x1000 + +/* set the base and size for the RAM on the iSBC 80/10 */ +#define RAM_BASE 0x3C00 +#define RAM_SIZE 0x0400 + +/* set INTR for CPU */ +#define INTR INT_1 + +/* function prototypes */ + +int32 get_mbyte(int32 addr); +int32 get_mword(int32 addr); +void put_mbyte(int32 addr, int32 val); +void put_mword(int32 addr, int32 val); +t_stat SBC_reset (DEVICE *dptr); + +/* external function prototypes */ + +extern t_stat i8080_reset (DEVICE *dptr); /* reset the 8080 emulator */ +extern int32 multibus_get_mbyte(int32 addr); +extern void multibus_put_mbyte(int32 addr, int32 val); +extern int32 EPROM_get_mbyte(int32 addr); +extern int32 RAM_get_mbyte(int32 addr); +extern void RAM_put_mbyte(int32 addr, int32 val); +extern UNIT i8255_unit; +extern UNIT EPROM_unit; +extern UNIT RAM_unit; +extern t_stat i8255_reset (DEVICE *dptr, int32 base); +extern t_stat i8251_reset (DEVICE *dptr, int32 base); +extern t_stat pata_reset (DEVICE *dptr, int32 base); +extern t_stat EPROM_reset (DEVICE *dptr, int32 size); +extern t_stat RAM_reset (DEVICE *dptr, int32 base, int32 size); + +/* SBC reset routine */ + +t_stat SBC_reset (DEVICE *dptr) +{ + printf("Initializing iSBC-80/10:\n"); + i8080_reset (NULL); + i8255_reset (NULL, I8255_BASE_0); + i8255_reset (NULL, I8255_BASE_1); + i8251_reset (NULL, I8251_BASE); + EPROM_reset (NULL, ROM_SIZE); + RAM_reset (NULL, RAM_BASE, RAM_SIZE); + return SCPE_OK; +} + +/* get a byte from memory - handle RAM, ROM, I/O, and Multibus memory */ + +int32 get_mbyte(int32 addr) +{ + int32 val, org, len; + + /* if local EPROM handle it */ + if ((i8255_unit.u5 & 0x01) && (addr >= EPROM_unit.u3) && (addr < (EPROM_unit.u3 + EPROM_unit.capac))) { + return EPROM_get_mbyte(addr); + } /* if local RAM handle it */ + if ((i8255_unit.u5 & 0x02) && (addr >= RAM_unit.u3) && (addr < (RAM_unit.u3 + RAM_unit.capac))) { + return RAM_get_mbyte(addr); + } /* otherwise, try the multibus */ + return multibus_get_mbyte(addr); +} + +/* get a word from memory */ + +int32 get_mword(int32 addr) +{ + int32 val; + + val = get_mbyte(addr); + val |= (get_mbyte(addr+1) << 8); + return val; +} + +/* put a byte to memory - handle RAM, ROM, I/O, and Multibus memory */ + +void put_mbyte(int32 addr, int32 val) +{ + /* if local EPROM handle it */ + if ((i8255_unit.u5 & 0x01) && (addr >= EPROM_unit.u3) && (addr <= (EPROM_unit.u3 + EPROM_unit.capac))) { + printf("Write to R/O memory address %04X - ignored\n", addr); + return; + } /* if local RAM handle it */ + if ((i8255_unit.u5 & 0x02) && (addr >= RAM_unit.u3) && (addr <= (RAM_unit.u3 + RAM_unit.capac))) { + RAM_put_mbyte(addr, val); + return; + } /* otherwise, try the multibus */ + multibus_put_mbyte(addr, val); +} + +/* put a word to memory */ + +void put_mword(int32 addr, int32 val) +{ + put_mbyte(addr, val); + put_mbyte(addr+1, val >> 8); +} + +/* end of iSBC80-10.c */ diff --git a/MDS-800/common/iSBC80-20.c b/MDS-800/common/iSBC80-20.c new file mode 100644 index 00000000..b9af2024 --- /dev/null +++ b/MDS-800/common/iSBC80-20.c @@ -0,0 +1,149 @@ +/* iSBC80-20.c: Intel iSBC 80/30 Processor simulator + + Copyright (c) 2010, William A. Beech + + Permission is hereby granted, free of charge, to any person obtaining a + copy of this software and associated documentation files (the "Software"), + to deal in the Software without restriction, including without limitation + the rights to use, copy, modify, merge, publish, distribute, sublicense, + and/or sell copies of the Software, and to permit persons to whom the + Software is furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + WILLIAM A. BEECH BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + Except as contained in this notice, the name of William A. Beech shall not be + used in advertising or otherwise to promote the sale, use or other dealings + in this Software without prior written authorization from William A. Beech. + + This software was written by Bill Beech, Dec 2010, to allow emulation of Multibus + Computer Systems. + + ?? ??? 10 - Original file. +*/ + +#include "system_defs.h" + +/* set the base I/O address for the 8259 */ +#define I8259_BASE 0xD8 + +/* set the base I/O address for the first 8255 */ +#define I8255_BASE_0 0xE4 + +/* set the base I/O address for the second 8255 */ +#define I8255_BASE_1 0xE8 + +/* set the base I/O address for the 8251 */ +#define I8251_BASE 0xEC + +/* set the base and size for the EPROM on the iSBC 80/20 */ +#define ROM_SIZE 0x1000 + +/* set the base and size for the RAM on the iSBC 80/20 */ +#define RAM_BASE 0x3C00 +#define RAM_SIZE 0x0400 + +/* set INTR for CPU */ +#define INTR INT_1 + +/* function prototypes */ + +int32 get_mbyte(int32 addr); +int32 get_mword(int32 addr); +void put_mbyte(int32 addr, int32 val); +void put_mword(int32 addr, int32 val); +t_stat i80_10_reset (DEVICE *dptr); + +/* external function prototypes */ + +extern t_stat i8080_reset (DEVICE *dptr); /* reset the 8080 emulator */ +extern int32 multibus_get_mbyte(int32 addr); +extern void multibus_put_mbyte(int32 addr, int32 val); +extern int32 EPROM_get_mbyte(int32 addr); +extern int32 RAM_get_mbyte(int32 addr); +extern void RAM_put_mbyte(int32 addr, int32 val); +extern UNIT i8255_unit; +extern UNIT EPROM_unit; +extern UNIT RAM_unit; +extern t_stat i8251_reset (DEVICE *dptr, int32 base); +extern t_stat i8255_reset (DEVICE *dptr, int32 base); +extern t_stat i8259_reset (DEVICE *dptr, int32 base); +extern t_stat pata_reset (DEVICE *dptr, int32 base); +extern t_stat EPROM_reset (DEVICE *dptr, int32 size); +extern t_stat RAM_reset (DEVICE *dptr, int32 base, int32 size); + +/* CPU reset routine + put here to cause a reset of the entire iSBC system */ + +t_stat SBC_reset (DEVICE *dptr) +{ + printf("Initializing iSBC-80/20\n"); + i8080_reset(NULL); + i8259_reset(NULL, I8259_BASE); + i8255_reset(NULL, I8255_BASE_0); + i8255_reset(NULL, I8255_BASE_1); + i8251_reset(NULL, I8251_BASE); + EPROM_reset(NULL, ROM_SIZE); + RAM_reset(NULL, RAM_BASE, RAM_SIZE); + return SCPE_OK; +} + +/* get a byte from memory - handle RAM, ROM and Multibus memory */ + +int32 get_mbyte(int32 addr) +{ + int32 val, org, len; + + /* if local EPROM handle it */ + if ((i8255_unit.u6 & 0x01) && (addr >= EPROM_unit.u3) && (addr < (EPROM_unit.u3 + EPROM_unit.capac))) { + return EPROM_get_mbyte(addr); + } /* if local RAM handle it */ + if ((i8255_unit.u6 & 0x02) && (addr >= RAM_unit.u3) && (addr < (RAM_unit.u3 + RAM_unit.capac))) { + return RAM_get_mbyte(addr); + } /* otherwise, try the multibus */ + return multibus_get_mbyte(addr); +} + +/* get a word from memory */ + +int32 get_mword(int32 addr) +{ + int32 val; + + val = get_mbyte(addr); + val |= (get_mbyte(addr+1) << 8); + return val; +} + +/* put a byte to memory - handle RAM, ROM and Multibus memory */ + +void put_mbyte(int32 addr, int32 val) +{ + /* if local EPROM handle it */ + if ((i8255_unit.u6 & 0x01) && (addr >= EPROM_unit.u3) && (addr <= (EPROM_unit.u3 + EPROM_unit.capac))) { + printf("Write to R/O memory address %04X - ignored\n", addr); + return; + } /* if local RAM handle it */ + if ((i8255_unit.u6 & 0x02) && (addr >= RAM_unit.u3) && (addr <= (RAM_unit.u3 + RAM_unit.capac))) { + RAM_put_mbyte(addr, val); + return; + } /* otherwise, try the multibus */ + multibus_put_mbyte(addr, val); +} + +/* put a word to memory */ + +void put_mword(int32 addr, int32 val) +{ + put_mbyte(addr, val); + put_mbyte(addr+1, val >> 8); +} + +/* end of iSBC80-10.c */ diff --git a/MDS-800/common/iSBC80-30.c b/MDS-800/common/iSBC80-30.c new file mode 100644 index 00000000..a48d72d6 --- /dev/null +++ b/MDS-800/common/iSBC80-30.c @@ -0,0 +1,149 @@ +/* iSBC80-30.c: Intel iSBC 80/30 Processor simulator + + Copyright (c) 2010, William A. Beech + + Permission is hereby granted, free of charge, to any person obtaining a + copy of this software and associated documentation files (the "Software"), + to deal in the Software without restriction, including without limitation + the rights to use, copy, modify, merge, publish, distribute, sublicense, + and/or sell copies of the Software, and to permit persons to whom the + Software is furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + WILLIAM A. BEECH BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + Except as contained in this notice, the name of William A. Beech shall not be + used in advertising or otherwise to promote the sale, use or other dealings + in this Software without prior written authorization from William A. Beech. + + This software was written by Bill Beech, Dec 2010, to allow emulation of Multibus + Computer Systems. + + ?? ??? 10 - Original file. +*/ + +#include "system_defs.h" + +/* set the base I/O address for the 8259 */ +#define I8259_BASE 0xD8 + +/* set the base I/O address for the first 8255 */ +#define I8255_BASE_0 0xE4 + +/* set the base I/O address for the second 8255 */ +#define I8255_BASE_1 0xE8 + +/* set the base I/O address for the 8251 */ +#define I8251_BASE 0xEC + +/* set the base and size for the EPROM on the iSBC 80/20 */ +#define ROM_SIZE 0x1000 + +/* set the base and size for the RAM on the iSBC 80/20 */ +#define RAM_BASE 0x3C00 +#define RAM_SIZE 0x0400 + +/* set INTR for CPU */ +#define INTR INT_1 + +/* function prototypes */ + +int32 get_mbyte(int32 addr); +int32 get_mword(int32 addr); +void put_mbyte(int32 addr, int32 val); +void put_mword(int32 addr, int32 val); +t_stat i80_10_reset (DEVICE *dptr); + +/* external function prototypes */ + +extern t_stat i8080_reset (DEVICE *dptr); /* reset the 8080 emulator */ +extern int32 multibus_get_mbyte(int32 addr); +extern void multibus_put_mbyte(int32 addr, int32 val); +extern int32 EPROM_get_mbyte(int32 addr); +extern int32 RAM_get_mbyte(int32 addr); +extern void RAM_put_mbyte(int32 addr, int32 val); +extern UNIT i8255_unit; +extern UNIT EPROM_unit; +extern UNIT RAM_unit; +extern t_stat i8251_reset (DEVICE *dptr, int32 base); +extern t_stat i8255_reset (DEVICE *dptr, int32 base); +extern t_stat i8259_reset (DEVICE *dptr, int32 base); +extern t_stat pata_reset (DEVICE *dptr, int32 base); +extern t_stat EPROM_reset (DEVICE *dptr, int32 size); +extern t_stat RAM_reset (DEVICE *dptr, int32 base, int32 size); + +/* CPU reset routine + put here to cause a reset of the entire iSBC system */ + +t_stat SBC_reset (DEVICE *dptr) +{ + printf("Initializing iSBC-80/20\n"); + i8080_reset(NULL); + i8259_reset(NULL, I8259_BASE); + i8255_reset(NULL, I8255_BASE_0); + i8255_reset(NULL, I8255_BASE_1); + i8251_reset(NULL, I8251_BASE); + EPROM_reset(NULL, ROM_SIZE); + RAM_reset(NULL, RAM_BASE, RAM_SIZE); + return SCPE_OK; +} + +/* get a byte from memory - handle RAM, ROM and Multibus memory */ + +int32 get_mbyte(int32 addr) +{ + int32 val, org, len; + + /* if local EPROM handle it */ + if ((i8255_unit.u6 & 0x01) && (addr >= EPROM_unit.u3) && (addr < (EPROM_unit.u3 + EPROM_unit.capac))) { + return EPROM_get_mbyte(addr); + } /* if local RAM handle it */ + if ((i8255_unit.u6 & 0x02) && (addr >= RAM_unit.u3) && (addr < (RAM_unit.u3 + RAM_unit.capac))) { + return RAM_get_mbyte(addr); + } /* otherwise, try the multibus */ + return multibus_get_mbyte(addr); +} + +/* get a word from memory */ + +int32 get_mword(int32 addr) +{ + int32 val; + + val = get_mbyte(addr); + val |= (get_mbyte(addr+1) << 8); + return val; +} + +/* put a byte to memory - handle RAM, ROM and Multibus memory */ + +void put_mbyte(int32 addr, int32 val) +{ + /* if local EPROM handle it */ + if ((i8255_unit.u6 & 0x01) && (addr >= EPROM_unit.u3) && (addr <= (EPROM_unit.u3 + EPROM_unit.capac))) { + printf("Write to R/O memory address %04X - ignored\n", addr); + return; + } /* if local RAM handle it */ + if ((i8255_unit.u6 & 0x02) && (addr >= RAM_unit.u3) && (addr <= (RAM_unit.u3 + RAM_unit.capac))) { + RAM_put_mbyte(addr, val); + return; + } /* otherwise, try the multibus */ + multibus_put_mbyte(addr, val); +} + +/* put a word to memory */ + +void put_mword(int32 addr, int32 val) +{ + put_mbyte(addr, val); + put_mbyte(addr+1, val >> 8); +} + +/* end of iSBC80-10.c */ diff --git a/MDS-800/common/ieprom.c b/MDS-800/common/ieprom.c new file mode 100644 index 00000000..6555f24f --- /dev/null +++ b/MDS-800/common/ieprom.c @@ -0,0 +1,201 @@ +/* iEPROM.c: Intel EPROM simulator for 8-bit SBCs + + Copyright (c) 2010, William A. Beech + + Permission is hereby granted, free of charge, to any person obtaining a + copy of this software and associated documentation files (the "Software"), + to deal in the Software without restriction, including without limitation + the rights to use, copy, modify, merge, publish, distribute, sublicense, + and/or sell copies of the Software, and to permit persons to whom the + Software is furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + WILLIAM A. BEECH BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + Except as contained in this notice, the name of William A. Beech shall not be + used in advertising or otherwise to promote the sale, use or other dealings + in this Software without prior written authorization from William A. Beech. + + These functions support a simulated i2732 EPROM device on an iSBC. This + allows the attachment of the device to a binary file containing the EPROM + code. + + Unit will support a single 2708, 2716, 2732 and 2764 EPROM type. + + ?? ??? 10 - Original file. + 16 Dec 12 - Modified to use isbc_80_10.cfg file to set base and size. +*/ + +#include "system_defs.h" + +#define SET_XACK(VAL) (xack = VAL) + +/* function prototypes */ + +t_stat EPROM_attach (UNIT *uptr, char *cptr); +t_stat EPROM_reset (DEVICE *dptr, int32 size); +int32 EPROM_get_mbyte(int32 addr); + +extern UNIT i8255_unit; +extern uint8 xack; /* XACK signal */ + +/* SIMH EPROM Standard I/O Data Structures */ + +UNIT EPROM_unit = { + UDATA (NULL, UNIT_ATTABLE+UNIT_BINK+UNIT_ROABLE+UNIT_RO, 0), 0 +}; + +DEBTAB EPROM_debug[] = { + { "ALL", DEBUG_all }, + { "FLOW", DEBUG_flow }, + { "READ", DEBUG_read }, + { "WRITE", DEBUG_write }, + { "XACK", DEBUG_xack }, + { "LEV1", DEBUG_level1 }, + { "LEV2", DEBUG_level2 }, + { NULL } +}; + +DEVICE EPROM_dev = { + "EPROM", //name + &EPROM_unit, //units + NULL, //registers + NULL, //modifiers + 1, //numunits + 16, //aradix + 32, //awidth + 1, //aincr + 16, //dradix + 8, //dwidth + NULL, //examine + NULL, //deposit +// &EPROM_reset, //reset + NULL, //reset + NULL, //boot + &EPROM_attach, //attach + NULL, //detach + NULL, //ctxt + DEV_DEBUG, //flags + 0, //dctrl + EPROM_debug, //debflags + NULL, //msize + NULL //lname +}; + +/* global variables */ + +/* EPROM functions */ + +/* EPROM attach */ + +t_stat EPROM_attach (UNIT *uptr, char *cptr) +{ + int j, c; + FILE *fp; + t_stat r; + + if (EPROM_dev.dctrl & DEBUG_flow) + printf("EPROM_attach: cptr=%s\n", cptr); + if ((r = attach_unit (uptr, cptr)) != SCPE_OK) { + if (EPROM_dev.dctrl & DEBUG_flow) + printf("EPROM_attach: Error\n"); + return r; + } + if (EPROM_dev.dctrl & DEBUG_read) + printf("\tAllocate buffer\n"); + if (EPROM_unit.filebuf == NULL) { /* no buffer allocated */ + EPROM_unit.filebuf = malloc(EPROM_unit.capac); /* allocate EPROM buffer */ + if (EPROM_unit.filebuf == NULL) { + if (EPROM_dev.dctrl & DEBUG_flow) + printf("EPROM_attach: Malloc error\n"); + return SCPE_MEM; + } + } + if (EPROM_dev.dctrl & DEBUG_read) + printf("\tOpen file %s\n", EPROM_unit.filename); + fp = fopen(EPROM_unit.filename, "rb"); /* open EPROM file */ + if (fp == NULL) { + printf("EPROM: Unable to open ROM file %s\n", EPROM_unit.filename); + printf("\tNo ROM image loaded!!!\n"); + return SCPE_OK; + } + if (EPROM_dev.dctrl & DEBUG_read) + printf("\tRead file\n"); + j = 0; /* load EPROM file */ + c = fgetc(fp); + while (c != EOF) { + *(uint8 *)(EPROM_unit.filebuf + j++) = c & 0xFF; + c = fgetc(fp); + if (j >= EPROM_unit.capac) { + printf("\tImage is too large - Load truncated!!!\n"); + break; + } + } + if (EPROM_dev.dctrl & DEBUG_read) + printf("\tClose file\n"); + fclose(fp); + printf("EPROM: %d bytes of ROM image %s loaded\n", j, EPROM_unit.filename); + if (EPROM_dev.dctrl & DEBUG_flow) + printf("EPROM_attach: Done\n"); + return SCPE_OK; +} + +/* EPROM reset */ + +t_stat EPROM_reset (DEVICE *dptr, int32 size) +{ + t_stat r; + +// if (EPROM_dev.dctrl & DEBUG_flow) /* entry message */ + printf(" EPROM_reset: base=0000 size=%04X\n", size); + if ((EPROM_unit.flags & UNIT_ATT) == 0) { /* if unattached */ + EPROM_unit.capac = size; /* set EPROM size to 0 */ + if (EPROM_dev.dctrl & DEBUG_flow) /* exit message */ + printf("Done1\n"); +// printf(" EPROM: Available [%04X-%04XH]\n", +// 0, EPROM_unit.capac - 1); + return SCPE_OK; + } + if ((EPROM_unit.flags & UNIT_ATT) == 0) { + printf("EPROM: No file attached\n"); + } + if (EPROM_dev.dctrl & DEBUG_flow) /* exit message */ + printf("Done2\n"); + return SCPE_OK; +} + +/* get a byte from memory */ + +int32 EPROM_get_mbyte(int32 addr) +{ + int32 val; + + if (i8255_unit.u6 & 0x01) { /* EPROM enabled */ + if (EPROM_dev.dctrl & DEBUG_read) + printf("EPROM_get_mbyte: addr=%04X\n", addr); + if ((addr >= 0) && (addr < EPROM_unit.capac)) { + SET_XACK(1); /* good memory address */ + if (EPROM_dev.dctrl & DEBUG_xack) + printf("EPROM_get_mbyte: Set XACK for %04X\n", addr); + val = *(uint8 *)(EPROM_unit.filebuf + addr); + if (EPROM_dev.dctrl & DEBUG_read) + printf(" val=%04X\n", val); + return (val & 0xFF); + } + if (EPROM_dev.dctrl & DEBUG_read) + printf(" EPROM Disabled\n"); + return 0xFF; + } + if (EPROM_dev.dctrl & DEBUG_read) + printf(" Out of range\n"); + return 0xFF; +} + +/* end of iEPROM.c */ diff --git a/MDS-800/common/ijedec.c b/MDS-800/common/ijedec.c new file mode 100644 index 00000000..ffc2ffbe --- /dev/null +++ b/MDS-800/common/ijedec.c @@ -0,0 +1,486 @@ +/* iJEDEC.c: Intel JEDEC Universal Site simulator for SBCs + + Copyright (c) 2011, William A. Beech + + Permission is hereby granted, free of charge, to any person obtaining a + copy of this software and associated documentation files (the "Software"), + to deal in the Software without restriction, including without limitation + the rights to use, copy, modify, merge, publish, distribute, sublicense, + and/or sell copies of the Software, and to permit persons to whom the + Software is furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + WILLIAM A. BEECH BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + Except as contained in this notice, the name of William A. Beech shall not be + used in advertising or otherwise to promote the sale, use or other dealings + in this Software without prior written authorization from William A. Beech. + + These functions support a simulated i2732 JEDEC device on an iSBC. This + allows the attachment of the device to a binary file containing the JEDEC + code. + + Unit will support 8, 16 and 32 KB EPROMs as well as 8 and 16 KB static + RAMs in the JEDEC sockets. Units must be configured for 8KB for 8KB + SRAM and 32KB for 32KB SRAM. If configured for 16KB, SRAM cannot be + configured. Size is set by configuring the top JEDEC site for an EPROM. + Size and spacing for the other JEDEC units is derived from the top JEDEC + site configuration. Changing the top JEDEC site will clear the + configuration of all other JEDEC sites. The JEDEC driver can be set for + either 8- or 16bit data access. + + The top JEDEC site can only be configured to contain an EPROM. + It contains the reset address for the 8088, 8086, 80188, 80186, + and 80286. + + For illustration 8-bit mode - 4 Sites - configured for 8KB chips + + +--------+ 0xFFFFF + | | + | jedec3 | Only ROM + | | + +--------+ 0xFE000 + + +--------+ 0xFDFFF + | | + | jedec2 | RAM/ROM + | | + +--------+ 0xFC000 + + +--------+ 0xFBFFF + | | + | jedec1 | RAM/ROM + | | + +--------+ 0xFA000 + + +--------+ 0xF9FFF + | | + | jedec0 | RAM/ROM + | | + +--------+ 0xF8000 + + For illustration 16-bit mode - 4 Sites - configured for 8KB chips + + Odd data byte Even data byte + High data byte Low data byte + +--------+ 0xFFFFF +--------+ 0xFFFFE + | | | | + | jedec3 | Only ROM | jedec2 | Only ROM + | | | | + +--------+ 0xFC001 +--------+ 0xFC000 + + +--------+ 0xFBFFF +--------+ 0xFBFFE + | | | | + | jedec3 | RAM/ROM | jedec2 | RAM/ROM + | | | | + +--------+ 0xF8001 +--------+ 0xF8000 + + uptr->filename - ROM image file attached to unit + uptr->capac - unit capacity in bytes + uptr->u3 - unit base address + uptr->u4 - unit device type {none|8krom|16krom|32krom|8kram|32kram} + uptr->u5 - unit flags - ROM or RAM, 8 or 16BIT (top unit only) + uptr->u6 - unit number +*/ + +#include + +#include "multibus_defs.h" + +#define JEDEC_NUM 4 + +#define UNIT_V_DMODE (UNIT_V_UF) /* data bus mode */ +#define UNIT_DMODE (1 << UNIT_V_DMODE) +#define UNIT_V_MSIZE (UNIT_V_UF+1) /* Memory Size */ +#define UNIT_MSIZE (1 << UNIT_V_MSIZE) +#define UNIT_NONE 0 /* No device */ +#define UNIT_8KROM 1 /* 8KB ROM */ +#define UNIT_16KROM 2 /* 16KB ROM */ +#define UNIT_32KROM 3 /* 32KB ROM */ +#define UNIT_8KRAM 4 /* 8KB RAM */ +#define UNIT_32KRAM 5 /* 32KB RAM */ + +#define RAM 0x00000001 +#define D16BIT 0x00000002 + +/* function prototypes */ + +t_stat JEDEC_set_size (UNIT *uptr, int32 val, char *cptr, void *desc); +t_stat JEDEC_set_mode (UNIT *uptr, int32 val, char *cptr, void *desc); +t_stat JEDEC_attach (UNIT *uptr, char *cptr); +t_stat JEDEC_reset (DEVICE *dptr); +int32 JEDEC_get_mbyte(int32 addr); +void JEDEC_put_mbyte(int32 addr, int32 val); + +/* SIMH JEDEC Standard I/O Data Structures */ + +UNIT JEDEC_unit[] = { + { UDATA (NULL, UNIT_ATTABLE+UNIT_BINK+UNIT_ROABLE+UNIT_RO, 0),0 }, + { UDATA (NULL, UNIT_ATTABLE+UNIT_BINK+UNIT_ROABLE+UNIT_RO, 0),0 }, + { UDATA (NULL, UNIT_ATTABLE+UNIT_BINK+UNIT_ROABLE+UNIT_RO, 0),0 }, + { UDATA (NULL, UNIT_ATTABLE+UNIT_BINK+UNIT_ROABLE+UNIT_RO, 0),0 } +}; + +MTAB JEDEC_mod[] = { + { UNIT_DMODE, 0, "8-Bit", "8B", &JEDEC_set_mode }, + { UNIT_DMODE, UNIT_DMODE, "16-Bit", "16B", &JEDEC_set_mode }, + { UNIT_MSIZE, UNIT_NONE, "Not configured", "NONE", &JEDEC_set_size }, + { UNIT_MSIZE, UNIT_8KROM, "8KB ROM", "8KROM", &JEDEC_set_size }, + { UNIT_MSIZE, UNIT_16KROM, "16KB ROM", "16KROM", &JEDEC_set_size }, + { UNIT_MSIZE, UNIT_32KROM, "32KB ROM", "32KROM", &JEDEC_set_size }, + { UNIT_MSIZE, UNIT_8KRAM, "8KB RAM", "8KRAM", &JEDEC_set_size }, + { UNIT_MSIZE, UNIT_32KRAM, "32KB RAM", "32KRAM", &JEDEC_set_size }, + { 0 } +}; + +DEBTAB JEDEC_debug[] = { + { "ALL", DEBUG_all }, + { "FLOW", DEBUG_flow }, + { "READ", DEBUG_read }, + { "WRITE", DEBUG_write }, + { "LEV1", DEBUG_level1 }, + { "LEV2", DEBUG_level2 }, + { NULL } +}; + +DEVICE JEDEC_dev = { + "JEDEC", //name + JEDEC_unit, //units + NULL, //registers + JEDEC_mod, //modifiers + JEDEC_NUM, //numunits + 16, //aradix + 32, //awidth + 1, //aincr + 16, //dradix + 8, //dwidth + NULL, //examine + NULL, //deposit + &JEDEC_reset, //reset + NULL, //boot + &JEDEC_attach, //attach + NULL, //detach + NULL, //ctxt + DEV_DEBUG, //flags + 0, //dctrl + JEDEC_debug, //debflags + NULL, //msize + NULL //lname +}; + +/* global variables */ + +uint8 *JEDEC_buf[JEDEC_NUM] = { /* JEDEC buffer pointers */ + NULL, + NULL, + NULL, + NULL +}; + +/* JEDEC functions */ + +/* JEDEC attach - force JEDEC reset at completion */ + +t_stat JEDEC_attach (UNIT *uptr, char *cptr) +{ + t_stat r; + + if (JEDEC_dev.dctrl & DEBUG_flow) + printf("\tJEDEC_attach: Entered with cptr=%s\n", cptr); + if ((r = attach_unit (uptr, cptr)) != SCPE_OK) { + if (JEDEC_dev.dctrl & DEBUG_flow) + printf("\tJEDEC_attach: Error\n"); + return r; + } + if (JEDEC_dev.dctrl & DEBUG_flow) + printf("\tJEDEC_attach: Done\n"); + return (JEDEC_reset (NULL)); +} + +/* JEDEC set mode = 8- or 16-bit data bus */ + +t_stat JEDEC_set_mode (UNIT *uptr, int32 val, char *cptr, void *desc) +{ + UNIT *uptr1; + + if (JEDEC_dev.dctrl & DEBUG_flow) + printf("\tJEDEC_set_mode: Entered with val=%08XH, unit=%d\n", val, uptr->u6); + uptr1 = JEDEC_dev.units + JEDEC_NUM - 1; /* top unit holds this configuration */ + if (val) { /* 16-bit mode */ + uptr1->u5 |= D16BIT; + } else { /* 8-bit mode */ + uptr1->u5 &= ~D16BIT; + } + if (JEDEC_dev.dctrl & DEBUG_flow) + printf("JEDEC%d->u5=%08XH\n", JEDEC_NUM - 1, uptr1->u5); + printf("\tJEDEC_set_mode: Done\n"); +} + +/* JEDEC set type = none, 8krom, 16krom, 32krom, 8kram or 32kram */ + +t_stat JEDEC_set_size (UNIT *uptr, int32 val, char *cptr, void *desc) +{ + uint32 i, basadr; + UNIT *uptr1; + + if (JEDEC_dev.dctrl & DEBUG_flow) + printf("\tJEDEC_set_size: Entered with val=%d, unit=%d\n", val, uptr->u6); + uptr1 = JEDEC_dev.units + JEDEC_NUM - 1; /* top unit holds u5 configuration */ + uptr->u4 = val; + switch(val) { + case UNIT_NONE: + uptr->capac = 0; + uptr->u5 &= ~RAM; /* ROM */ + if (uptr->u6 == JEDEC_NUM - 1) {/* top unit ? */ + uptr->u3 = 0; /* base address */ + printf("JEDEC site size set to 8KB\n"); + for (i = 0; i < JEDEC_NUM-1; i++) { /* clear all units but last unit */ + uptr1 = JEDEC_dev.units + i; + uptr1->capac = 0; + } + } + break; + case UNIT_8KROM: + uptr->capac = 0x2000; + uptr1->u5 &= ~RAM; /* ROM */ + basadr = 0x100000 - (uptr->capac * JEDEC_NUM); + printf("JEDEC site base address = %06XH\n", basadr); + if (uptr->u6 == JEDEC_NUM - 1) {/* top unit ? */ + uptr->u3 = basadr + (uptr->capac * uptr->u6); /* base address */ + printf("JEDEC site size set to 8KB\n"); + for (i = 0; i < JEDEC_NUM-1; i++) { /* clear all units but last unit */ + uptr1 = JEDEC_dev.units + i; + uptr1->capac = 0; + } + } else { + if (uptr1->capac != uptr->capac) { + uptr->capac = 0; + printf("JEDEC site size precludes use of this device\n"); + } + } + break; + case UNIT_16KROM: + uptr->capac = 0x4000; + uptr1->u5 &= ~RAM; /* ROM */ + basadr = 0x100000 - (uptr->capac * JEDEC_NUM); + printf("JEDEC site base address = %06XH\n", basadr); + if (uptr->u6 == JEDEC_NUM - 1) {/* top unit ? */ + uptr->u3 = basadr + (uptr->capac * uptr->u6); /* base address */ + printf("JEDEC site size set to 16KB\n"); + for (i = 0; i < JEDEC_NUM-1; i++) { /* clear all units but last unit */ + uptr1 = JEDEC_dev.units + i; + uptr1->capac = 0; + } + } else { + if (uptr1->capac != uptr->capac) { + uptr->capac = 0; + printf("JEDEC site size precludes use of this device\n"); + } + } + break; + case UNIT_32KROM: + uptr->capac = 0x8000; + uptr1->u5 &= ~RAM; /* ROM */ + basadr = 0x100000 - (uptr->capac * JEDEC_NUM); + printf("JEDEC site base address = %06XH\n", basadr); + if (uptr->u6 == JEDEC_NUM - 1) {/* top unit ? */ + uptr->u3 = basadr + (uptr->capac * uptr->u6); /* base address */ + printf("JEDEC site size set to 32KB\n"); + for (i = 0; i < JEDEC_NUM-1; i++) { /* clear all units but last unit */ + uptr1 = JEDEC_dev.units + i; + uptr1->capac = 0; + } + } else { + if (uptr1->capac != uptr->capac) { + uptr->capac = 0; + printf("JEDEC site size precludes use of this device\n"); + } + } + break; + case UNIT_8KRAM: + uptr->capac = 0x2000; + if (uptr->u6 == JEDEC_NUM - 1) {/* top unit ? */ + printf("JEDEC%d cannot be SRAM\n", uptr->u6); + } else { + if (uptr1->capac != uptr->capac) { + uptr->capac = 0; + printf("JEDEC site size precludes use of this device\n"); + } else { + uptr->u5 |= RAM; /* RAM */ + } + } + break; + case UNIT_32KRAM: + uptr->capac = 0x8000; + if (uptr->u6 == JEDEC_NUM - 1) {/* top unit ? */ + printf("JEDEC%d cannot be SRAM\n", uptr->u6); + } else { + if (uptr1->capac != uptr->capac) { + uptr->capac = 0; + printf("JEDEC site size precludes use of this device\n"); + } else { + uptr->u5 |= RAM; /* RAM */ + } + } + break; + default: + if (JEDEC_dev.dctrl & DEBUG_flow) + printf("\tJEDEC_set_size: Error\n"); + return SCPE_ARG; + } + if (JEDEC_buf[uptr->u6]) { /* any change requires a new buffer */ + free (JEDEC_buf[uptr->u6]); + JEDEC_buf[uptr->u6] = NULL; + } + if (JEDEC_dev.dctrl & DEBUG_flow) { + printf("\tJEDEC%d->capac=%04XH\n", uptr->u6, uptr->capac); + printf("\tJEDEC%d->u3[Base addr]=%06XH\n", uptr->u6, uptr->u3); + printf("\tJEDEC%d->u4[val]=%06XH\n", uptr->u6, uptr->u4); + printf("\tJEDEC%d->u5[Flags]=%06XH\n", uptr->u6, uptr->u5); + printf("\tJEDEC%d->u6[unit #]=%06XH\n", uptr->u6, uptr->u6); + uptr1 = JEDEC_dev.units + JEDEC_NUM - 1; /* top unit holds u5 configuration */ + printf("\tJEDEC%d->u5[Flags]=%06XH\n", JEDEC_NUM - 1, uptr1->u5); + printf("\tJEDEC_set_size: Done\n"); + } + return SCPE_OK; +} + +/* JEDEC reset */ + +t_stat JEDEC_reset (DEVICE *dptr) +{ + int32 i, j, c; + FILE *fp; + t_stat r; + UNIT *uptr; + static int flag = 1; + + if (JEDEC_dev.dctrl & DEBUG_flow) + printf("\tJEDEC_reset: Entered\n"); + for (i = 0; i < JEDEC_NUM; i++) { /* handle all umits */ + uptr = JEDEC_dev.units + i; + if (uptr->capac == 0) { /* if not configured */ + printf(" JEDEC%d: Not configured\n", i); + if (flag) { + printf(" ALL: \"set JEDEC3 None | 8krom | 16krom | 32krom | 8kram | 32kram\"\n"); + printf(" EPROM: \"att JEDEC3 \"\n"); + flag = 0; + } + uptr->capac = 0; + /* assume 8KB in base address calculation */ + uptr->u3 = 0xF8000 + (0x2000 * i); /* base address */ + uptr->u4 = 0; /* None */ + uptr->u5 = 0; /* RO */ + uptr->u6 = i; /* unit number - only set here! */ + } + if (uptr->capac) { /* if configured */ + printf(" JEDEC%d: Initializing %2XKB %s [%04X-%04XH]\n", + i, + uptr->capac / 0x400, + uptr->u5 ? "Ram" : "Rom", + uptr->u3, + uptr->u3 + uptr->capac - 1); + if (JEDEC_buf[uptr->u6] == NULL) {/* no buffer allocated */ + JEDEC_buf[uptr->u6] = malloc(uptr->capac); + if (JEDEC_buf[uptr->u6] == NULL) { + if (JEDEC_dev.dctrl & DEBUG_flow) + printf("\tJEDEC_reset: Malloc error\n"); + return SCPE_MEM; + } + } + if ((uptr->u5 & 0x0001) == 0) { /* ROM - load file */ + fp = fopen(uptr->filename, "rb"); + if (fp == NULL) { + printf("\tUnable to open ROM file %s\n", uptr->filename); + printf("\tNo ROM image loaded!!!\n"); + } else { + j = 0; + c = fgetc(fp); + while (c != EOF) { + *(JEDEC_buf[uptr->u6] + j++) = c & 0xFF; + c = fgetc(fp); + if (j >= JEDEC_unit[uptr->u6].capac) { + printf("\tImage is too large - Load truncated!!!\n"); + break; + } + } + fclose(fp); + printf("\t%d bytes of ROM image %s loaded\n", j, uptr->filename); + } + } + } + } + if (JEDEC_dev.dctrl & DEBUG_flow) + printf("\tJEDEC_reset: Done\n"); + return SCPE_OK; +} + +/* I/O instruction handlers, called from the CPU module when an + JEDEC memory read or write is issued. + + Need to fix for hi/low memory operations +*/ + +/* get a byte from memory */ + +int32 JEDEC_get_mbyte(int32 addr) +{ + int32 i, val, org, len; + UNIT *uptr; + + if (JEDEC_dev.dctrl & DEBUG_read) + printf("\tJEDEC_get_mbyte: Entered\n"); + for (i = 0; i < JEDEC_NUM; i++) { /* test all umits for address */ + uptr = JEDEC_dev.units + i; + org = uptr->u3; + len = uptr->capac - 1; + if ((addr >= org) && (addr <= org + len)) { + if (JEDEC_dev.dctrl & DEBUG_read) + printf("\tJEDEC%d Addr=%06XH Org=%06XH Len=%06XH\n", i, addr, org, len); + val = *(JEDEC_buf[uptr->u6] + (addr - org)); + if (JEDEC_dev.dctrl & DEBUG_read) + printf("\tJEDEC_get_mbyte: Exit with [%0XH]\n", val & 0xFF); + return (val & 0xFF); + } + } + if (JEDEC_dev.dctrl & DEBUG_read) + printf("\tJEDEC_get_mbyte: Exit - Out of range\n", addr); + return 0xFF; +} + +/* put a byte into memory */ + +void JEDEC_put_mbyte(int32 addr, int32 val) +{ + int32 i, org, len, type; + UNIT *uptr; + + if (JEDEC_dev.dctrl & DEBUG_write) + printf("\tJEDEC_put_mbyte: Entered\n"); + for (i = 0; i < JEDEC_NUM; i++) { /* test all umits for address */ + uptr = JEDEC_dev.units + i; + org = uptr->u3; + len = uptr->capac - 1; + if ((addr >= org) && (addr < org + len)) { + if (JEDEC_dev.dctrl & DEBUG_write) + printf("\tJEDEC%d Org=%06XH Len=%06XH\n", i, org, len); + if (uptr->u5 & RAM) { /* can't write to ROM */ + *(JEDEC_buf[uptr->u6] + (addr - org)) = val & 0xFF; + if (JEDEC_dev.dctrl & DEBUG_write) + printf("\tJEDEC_put_mbyte: Exit with [%06XH]=%02XH\n", addr, val); + } else + printf("\tJEDEC_put_mbyte: Write to ROM ignored\n"); + } + } + if (JEDEC_dev.dctrl & DEBUG_write) + printf("\tJEDEC_put_mbyte: Exit - Out of range\n"); +} + +/* end of iJEDEC.c */ diff --git a/MDS-800/common/iram16.c b/MDS-800/common/iram16.c new file mode 100644 index 00000000..7b663e47 --- /dev/null +++ b/MDS-800/common/iram16.c @@ -0,0 +1,203 @@ +/* iram.c: Intel RAM simulator for 16-bit SBCs + + Copyright (c) 2011, William A. Beech + + Permission is hereby granted, free of charge, to any person obtaining a + copy of this software and associated documentation files (the "Software"), + to deal in the Software without restriction, including without limitation + the rights to use, copy, modify, merge, publish, distribute, sublicense, + and/or sell copies of the Software, and to permit persons to whom the + Software is furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + William A. Beech BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + Except as contained in this notice, the name of William A. Beech shall not be + used in advertising or otherwise to promote the sale, use or other dealings + in this Software without prior written authorization from William A. Beech. + + These functions support a simulated RAM device in low memory on an iSBC. These + SBCs do not have the capability to switch off this RAM. In most cases a portion + of the RAM is dual-ported so it also appears in the multibus memory map at + a configurable location. + + Unit will support 16K SRAM sizes. + +*/ + +#include + +#include "multibus_defs.h" + +#define UNIT_V_RSIZE (UNIT_V_UF) /* RAM Size */ +#define UNIT_RSIZE (0x1 << UNIT_V_RSIZE) +#define UNIT_NONE (0) /* No unit */ +#define UNIT_16K (1) /* 16KB */ + +/* function prototypes */ + +t_stat RAM_svc (UNIT *uptr); +t_stat RAM_set_size (UNIT *uptr, int32 val, char *cptr, void *desc); +t_stat RAM_reset (DEVICE *dptr); +int32 RAM_get_mbyte(int32 addr); +void RAM_put_mbyte(int32 addr, int32 val); + +/* SIMH RAM Standard I/O Data Structures */ + +UNIT RAM_unit = { UDATA (NULL, UNIT_BINK, 0), KBD_POLL_WAIT }; + +MTAB RAM_mod[] = { + { UNIT_RSIZE, UNIT_NONE, "None", "none", &RAM_set_size }, + { UNIT_RSIZE, UNIT_16K, "16KB", "16KB", &RAM_set_size }, + { 0 } +}; + +DEBTAB RAM_debug[] = { + { "ALL", DEBUG_all }, + { "FLOW", DEBUG_flow }, + { "READ", DEBUG_read }, + { "WRITE", DEBUG_write }, + { "LEV1", DEBUG_level1 }, + { "LEV2", DEBUG_level2 }, + { NULL } +}; + +DEVICE RAM_dev = { + "RAM", //name + &RAM_unit, //units + NULL, //registers + RAM_mod, //modifiers + 1, //numunits + 16, //aradix + 32, //awidth + 1, //aincr + 16, //dradix + 8, //dwidth + NULL, //examine + NULL, //deposit + &RAM_reset, //reset + NULL, //boot + NULL, //attach + NULL, //detach + NULL, //ctxt + DEV_DEBUG, //flags + 0, //dctrl + RAM_debug, //debflags + NULL, //msize + NULL //lname +}; + +/* global variables */ + +uint8 *RAM_buf = NULL; /* RAM buffer pointer */ + +/* RAM functions */ + +/* RAM set size = none or 16KB */ + +t_stat RAM_set_size (UNIT *uptr, int32 val, char *cptr, void *desc) +{ + if (RAM_dev.dctrl & DEBUG_flow) + printf("RAM_set_size: val=%d\n", val); + if ((val < UNIT_NONE) || (val > UNIT_16K)) { + if (RAM_dev.dctrl & DEBUG_flow) + printf("RAM_set_size: Size error\n"); + return SCPE_ARG; + } + RAM_unit.capac = 0x4000 * val; /* set size */ + RAM_unit.u3 = 0x0000; /* base is 0 */ + RAM_unit.u4 = val; /* save val */ + if (RAM_buf) { /* if changed, allocate new buffer */ + free (RAM_buf); + RAM_buf = NULL; + } + if (RAM_dev.dctrl & DEBUG_flow) + printf("RAM_set_size: Done\n"); + return (RAM_reset (NULL)); /* force reset after reconfig */ +} + +/* RAM reset */ + +t_stat RAM_reset (DEVICE *dptr) +{ + int j; + FILE *fp; + + if (RAM_dev.dctrl & DEBUG_flow) + printf("RAM_reset: \n"); + if (RAM_unit.capac == 0) { /* if undefined */ + printf(" RAM: defaulted for 16KB\n"); + printf(" \"set RAM 16KB\"\n"); + RAM_unit.capac = 0x4000; + RAM_unit.u3 = 0; + RAM_unit.u4 = 1; + } + printf(" RAM: Initializing [%04X-%04XH]\n", + RAM_unit.u3, + RAM_unit.u3 + RAM_unit.capac - 1); + if (RAM_buf == NULL) { /* no buffer allocated */ + RAM_buf = malloc(RAM_unit.capac); + if (RAM_buf == NULL) { + if (RAM_dev.dctrl & DEBUG_flow) + printf("RAM_reset: Malloc error\n"); + return SCPE_MEM; + } + } + if (RAM_dev.dctrl & DEBUG_flow) + printf("RAM_reset: Done\n"); + return SCPE_OK; +} + +/* I/O instruction handlers, called from the CPU module when an + RAM memory read or write is issued. +*/ + +/* get a byte from memory */ + +int32 RAM_get_mbyte(int32 addr) +{ + int32 val, org, len; + + org = RAM_unit.u3; + len = RAM_unit.capac - 1; + if (RAM_dev.dctrl & DEBUG_read) + printf("RAM_get_mbyte: addr=%04X", addr); + if ((addr >= org) && (addr <= org + len)) { + val = *(RAM_buf + (addr - org)); + if (RAM_dev.dctrl & DEBUG_read) + printf(" val=%04X\n", val); + return (val & 0xFF); + } + if (RAM_dev.dctrl & DEBUG_read) + printf(" Out of range\n", addr); + return 0xFF; +} + +/* put a byte to memory */ + +void RAM_put_mbyte(int32 addr, int32 val) +{ + int32 org, len; + + org = RAM_unit.u3; + len = RAM_unit.capac - 1; + if (RAM_dev.dctrl & DEBUG_write) + printf("RAM_put_mbyte: addr=%04X, val=%02X", addr, val); + if ((addr >= org) && (addr < org + len)) { + *(RAM_buf + (addr - org)) = val & 0xFF; + if (RAM_dev.dctrl & DEBUG_write) + printf("\n"); + return; + } + if (RAM_dev.dctrl & DEBUG_write) + printf(" Out of range\n", val); +} + +/* end of iram.c */ diff --git a/MDS-800/common/iram8.c b/MDS-800/common/iram8.c new file mode 100644 index 00000000..46d2a4b4 --- /dev/null +++ b/MDS-800/common/iram8.c @@ -0,0 +1,168 @@ +/* iRAM8.c: Intel RAM simulator for 8-bit SBCs + + Copyright (c) 2011, William A. Beech + + Permission is hereby granted, free of charge, to any person obtaining a + copy of this software and associated documentation files (the "Software"), + to deal in the Software without restriction, including without limitation + the rights to use, copy, modify, merge, publish, distribute, sublicense, + and/or sell copies of the Software, and to permit persons to whom the + Software is furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + WILLIAM A. BEECH BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + Except as contained in this notice, the name of William A. Beech shall not be + used in advertising or otherwise to promote the sale, use or other dealings + in this Software without prior written authorization from William A. Beech. + + These functions support a simulated i8111 or 8102 RAM device on an iSBC. + + ?? ??? 11 - Original file. + 16 Dec 12 - Modified to use isbc_80_10.cfg file to set base and size. +*/ + +#include "system_defs.h" + +#define SET_XACK(VAL) (xack = VAL) + +/* function prototypes */ + +t_stat RAM_svc (UNIT *uptr); +t_stat RAM_reset (DEVICE *dptr, int32 base, int32 size); +int32 RAM_get_mbyte(int32 addr); +void RAM_put_mbyte(int32 addr, int32 val); + +extern UNIT i8255_unit; +extern uint8 xack; /* XACK signal */ + +/* SIMH RAM Standard I/O Data Structures */ + +UNIT RAM_unit = { UDATA (NULL, UNIT_BINK, 0), KBD_POLL_WAIT }; + +DEBTAB RAM_debug[] = { + { "ALL", DEBUG_all }, + { "FLOW", DEBUG_flow }, + { "READ", DEBUG_read }, + { "WRITE", DEBUG_write }, + { "XACK", DEBUG_xack }, + { "LEV1", DEBUG_level1 }, + { "LEV2", DEBUG_level2 }, + { NULL } +}; + +DEVICE RAM_dev = { + "RAM", //name + &RAM_unit, //units + NULL, //registers + NULL, //modifiers + 1, //numunits + 16, //aradix + 32, //awidth + 1, //aincr + 16, //dradix + 8, //dwidth + NULL, //examine + NULL, //deposit +// &RAM_reset, //reset + NULL, //reset + NULL, //boot + NULL, //attach + NULL, //detach + NULL, //ctxt + DEV_DEBUG, //flags + 0, //dctrl + RAM_debug, //debflags + NULL, //msize + NULL //lname +}; + +/* global variables */ + +/* RAM functions */ + +/* RAM reset */ + +t_stat RAM_reset (DEVICE *dptr, int32 base, int32 size) +{ +// if (RAM_dev.dctrl & DEBUG_flow) + printf(" RAM_reset: base=%04X size=%04X\n", base, size-1); + if (RAM_unit.capac == 0) { /* if undefined */ + RAM_unit.capac = size; + RAM_unit.u3 = base; + } + if (RAM_unit.filebuf == NULL) { /* no buffer allocated */ + RAM_unit.filebuf = malloc(RAM_unit.capac); + if (RAM_unit.filebuf == NULL) { + if (RAM_dev.dctrl & DEBUG_flow) + printf("RAM_set_size: Malloc error\n"); + return SCPE_MEM; + } + } +// printf(" RAM: Available [%04X-%04XH]\n", +// RAM_unit.u3, +// RAM_unit.u3 + RAM_unit.capac - 1); + if (RAM_dev.dctrl & DEBUG_flow) + printf("RAM_reset: Done\n"); + return SCPE_OK; +} + +/* get a byte from memory */ + +int32 RAM_get_mbyte(int32 addr) +{ + int32 val; + + if (i8255_unit.u6 & 0x02) { /* enable RAM */ + if (RAM_dev.dctrl & DEBUG_read) + printf("RAM_get_mbyte: addr=%04X\n", addr); + if ((addr >= RAM_unit.u3) && (addr < (RAM_unit.u3 + RAM_unit.capac))) { + SET_XACK(1); /* good memory address */ + if (RAM_dev.dctrl & DEBUG_xack) + printf("RAM_get_mbyte: Set XACK for %04X\n", addr); + val = *(uint8 *)(RAM_unit.filebuf + (addr - RAM_unit.u3)); + if (RAM_dev.dctrl & DEBUG_read) + printf(" val=%04X\n", val); + return (val & 0xFF); + } + if (RAM_dev.dctrl & DEBUG_read) + printf(" RAM disabled\n"); + return 0xFF; + } + if (RAM_dev.dctrl & DEBUG_read) + printf(" Out of range\n"); + return 0xFF; +} + +/* put a byte to memory */ + +void RAM_put_mbyte(int32 addr, int32 val) +{ + if (i8255_unit.u6 & 0x02) { /* enable RAM */ + if (RAM_dev.dctrl & DEBUG_write) + printf("RAM_put_mbyte: addr=%04X, val=%02X\n", addr, val); + if ((addr >= RAM_unit.u3) && (addr < RAM_unit.u3 + RAM_unit.capac)) { + SET_XACK(1); /* good memory address */ + if (RAM_dev.dctrl & DEBUG_xack) + printf("RAM_put_mbyte: Set XACK for %04X\n", addr); + *(uint8 *)(RAM_unit.filebuf + (addr - RAM_unit.u3)) = val & 0xFF; + if (RAM_dev.dctrl & DEBUG_write) + printf("\n"); + return; + } + if (RAM_dev.dctrl & DEBUG_write) + printf(" RAM disabled\n"); + return; + } + if (RAM_dev.dctrl & DEBUG_write) + printf(" Out of range\n"); +} + +/* end of iRAM8.c */ diff --git a/MDS-800/common/isbc064.c b/MDS-800/common/isbc064.c new file mode 100644 index 00000000..4e7c18ca --- /dev/null +++ b/MDS-800/common/isbc064.c @@ -0,0 +1,202 @@ +/* isbc064.c: Intel iSBC064 64K Byte Memory Card + + Copyright (c) 2011, William A. Beech + + Permission is hereby granted, free of charge, to any person obtaining a + copy of this software and associated documentation files (the "Software"), + to deal in the Software without restriction, including without limitation + the rights to use, copy, modify, merge, publish, distribute, sublicense, + and/or sell copies of the Software, and to permit persons to whom the + Software is furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + WILLIAM A. BEECH BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + Except as contained in this notice, the name of William A. Beech shall not be + used in advertising or otherwise to promote the sale, use or other dealings + in this Software without prior written authorization from William A. Beech. + + These functions support a simulated isbc016, isbc032, isbc048 and isbc064 + memory card on an Intel multibus system. + + ?? ??? 11 - Original file. + 16 Dec 12 - Modified to use system_80_10.cfg file to set base and size. + +*/ + +#include "system_defs.h" + +#define SET_XACK(VAL) (xack = VAL) + +/* prototypes */ + +t_stat isbc064_reset (DEVICE *dptr); +int32 isbc064_get_mbyte(int32 addr); +int32 isbc064_get_mword(int32 addr); +void isbc064_put_mbyte(int32 addr, int32 val); +void isbc064_put_mword(int32 addr, int32 val); + +extern uint8 xack; /* XACK signal */ + +/* isbc064 Standard I/O Data Structures */ + +UNIT isbc064_unit = { + UDATA (NULL, UNIT_FIX+UNIT_DISABLE+UNIT_BINK, 65536), KBD_POLL_WAIT +}; + +DEBTAB isbc064_debug[] = { + { "ALL", DEBUG_all }, + { "FLOW", DEBUG_flow }, + { "READ", DEBUG_read }, + { "WRITE", DEBUG_write }, + { "XACK", DEBUG_xack }, + { "LEV1", DEBUG_level1 }, + { "LEV2", DEBUG_level2 }, + { NULL } +}; + +DEVICE isbc064_dev = { + "SBC064", //name + &isbc064_unit, //units + NULL, //registers + NULL, //modifiers + 1, //numunits + 16, //aradix + 8, //awidth + 1, //aincr + 16, //dradix + 8, //dwidth + NULL, //examine + NULL, //deposite + &isbc064_reset, //reset + NULL, //boot + NULL, //attach + NULL, //detach + NULL, //ctxt + DEV_DEBUG+DEV_DISABLE+DEV_DIS, //flags + 0, //dctrl + isbc064_debug, //debflags + NULL, //msize + NULL //lname +}; + +/* iSBC064 globals */ + +/* Reset routine */ + +t_stat isbc064_reset (DEVICE *dptr) +{ + if (isbc064_dev.dctrl & DEBUG_flow) + printf("isbc064_reset: "); + if ((isbc064_dev.flags & DEV_DIS) == 0) { + isbc064_unit.capac = SBC064_SIZE; + isbc064_unit.u3 = SBC064_BASE; + printf("iSBC 064: Available[%04X-%04XH]\n", + isbc064_unit.u3, + isbc064_unit.u3 + isbc064_unit.capac - 1); + } + if (isbc064_unit.filebuf == NULL) { + isbc064_unit.filebuf = malloc(isbc064_unit.capac); + if (isbc064_unit.filebuf == NULL) { + if (isbc064_dev.dctrl & DEBUG_flow) + printf("isbc064_reset: Malloc error\n"); + return SCPE_MEM; + } + } + if (isbc064_dev.dctrl & DEBUG_flow) + printf("isbc064_reset: Done\n"); + return SCPE_OK; +} + +/* get a byte from memory */ + +int32 isbc064_get_mbyte(int32 addr) +{ + int32 val, org, len; + int i = 0; + + if ((isbc064_dev.flags & DEV_DIS) == 0) { + org = isbc064_unit.u3; + len = isbc064_unit.capac; + if (isbc064_dev.dctrl & DEBUG_read) + printf("isbc064_get_mbyte: addr=%04X", addr); + if (isbc064_dev.dctrl & DEBUG_read) + printf("isbc064_put_mbyte: org=%04X, len=%04X\n", org, len); + if ((addr >= org) && (addr < (org + len))) { + SET_XACK(1); /* good memory address */ + if (isbc064_dev.dctrl & DEBUG_xack) + printf("isbc064_get_mbyte: Set XACK for %04X\n", addr); + val = *(uint8 *)(isbc064_unit.filebuf + (addr - org)); + if (isbc064_dev.dctrl & DEBUG_read) + printf(" val=%04X\n", val); + return (val & 0xFF); + } else { + if (isbc064_dev.dctrl & DEBUG_read) + printf(" Out of range\n"); + return 0xFF; /* multibus has active high pullups */ + } + } + if (isbc064_dev.dctrl & DEBUG_read) + printf(" Disabled\n"); + return 0xFF; /* multibus has active high pullups */ +} + +/* get a word from memory */ + +int32 isbc064_get_mword(int32 addr) +{ + int32 val; + + val = isbc064_get_mbyte(addr); + val |= (isbc064_get_mbyte(addr+1) << 8); + return val; +} + +/* put a byte into memory */ + +void isbc064_put_mbyte(int32 addr, int32 val) +{ + int32 org, len; + int i = 0; + + if ((isbc064_dev.flags & DEV_DIS) == 0) { + org = isbc064_unit.u3; + len = isbc064_unit.capac; + if (isbc064_dev.dctrl & DEBUG_write) + printf("isbc064_put_mbyte: addr=%04X, val=%02X\n", addr, val); + if (isbc064_dev.dctrl & DEBUG_write) + printf("isbc064_put_mbyte: org=%04X, len=%04X\n", org, len); + if ((addr >= org) && (addr < (org + len))) { + SET_XACK(1); /* good memory address */ + if (isbc064_dev.dctrl & DEBUG_xack) + printf("isbc064_put_mbyte: Set XACK for %04X\n", addr); + *(uint8 *)(isbc064_unit.filebuf + (addr - org)) = val & 0xFF; + if (isbc064_dev.dctrl & DEBUG_xack) + printf("isbc064_put_mbyte: Return\n"); + return; + } else { + if (isbc064_dev.dctrl & DEBUG_write) + printf(" Out of range\n"); + return; + } + } + if (isbc064_dev.dctrl & DEBUG_write) + printf("isbc064_put_mbyte: Disabled\n"); +} + +/* put a word into memory */ + +void isbc064_put_mword(int32 addr, int32 val) +{ + isbc064_put_mbyte(addr, val); + isbc064_put_mbyte(addr+1, val << 8); +} + +/* end of isbc064.c */ diff --git a/MDS-800/common/isbc064b.c b/MDS-800/common/isbc064b.c new file mode 100644 index 00000000..c23c5e6a --- /dev/null +++ b/MDS-800/common/isbc064b.c @@ -0,0 +1,256 @@ +/* isbc064.c: Intel iSBC064 64K Byte Memory Card + + Copyright (c) 2011, William A. Beech + + Permission is hereby granted, free of charge, to any person obtaining a + copy of this software and associated documentation files (the "Software"), + to deal in the Software without restriction, including without limitation + the rights to use, copy, modify, merge, publish, distribute, sublicense, + and/or sell copies of the Software, and to permit persons to whom the + Software is furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + WILLIAM A. BEECH BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + Except as contained in this notice, the name of William A. Beech shall not be + used in advertising or otherwise to promote the sale, use or other dealings + in this Software without prior written authorization from William A. Beech. + + These functions support a simulated isbc016, isbc032, isbc048 and isbc064 memory card + on an Intel multibus system. + + */ + +#include + +#include "multibus_defs.h" + +#define UNIT_V_MSIZE (UNIT_V_UF) /* Memory Size */ +#define UNIT_MSIZE (1 << UNIT_V_MSIZE) +#define UNIT_V_MBASE (UNIT_V_UF+1) /* Memory Base */ +#define UNIT_MBASE (1 << UNIT_V_MBASE) + +/* prototypes */ + +t_stat isbc064_reset (DEVICE *dptr); +t_stat isbc064_set_size (UNIT *uptr, int32 val, char *cptr, void *desc); +t_stat isbc064_set_base (UNIT *uptr, int32 val, char *cptr, void *desc); +int32 isbc064_get_mbyte(int32 addr); +int32 isbc064_get_mword(int32 addr); +void isbc064_put_mbyte(int32 addr, int32 val); +void isbc064_put_mword(int32 addr, int32 val); + +/* isbc064 Standard I/O Data Structures */ + +UNIT isbc064_unit = { UDATA (NULL, UNIT_FIX+UNIT_DISABLE+UNIT_BINK, 65536), KBD_POLL_WAIT }; + +MTAB isbc064_mod[] = { + { UNIT_MSIZE, 16384, NULL, "16K", &isbc064_set_size }, + { UNIT_MSIZE, 32768, NULL, "32K", &isbc064_set_size }, + { UNIT_MSIZE, 49152, NULL, "48K", &isbc064_set_size }, + { UNIT_MSIZE, 65535, NULL, "64K", &isbc064_set_size }, + { UNIT_MBASE, 0, NULL, "B0K", &isbc064_set_base }, + { UNIT_MBASE, 16384, NULL, "B16K", &isbc064_set_base }, + { UNIT_MBASE, 32768, NULL, "B32K", &isbc064_set_base }, + { UNIT_MBASE, 49152, NULL, "B48K", &isbc064_set_base }, + { 0 } +}; + +DEBTAB isbc064_debug[] = { + { "ALL", DEBUG_all }, + { "FLOW", DEBUG_flow }, + { "READ", DEBUG_read }, + { "WRITE", DEBUG_write }, + { "LEV1", DEBUG_level1 }, + { "LEV2", DEBUG_level2 }, + { NULL } +}; + +DEVICE isbc064_dev = { + "SBC064", //name + &isbc064_unit, //units + NULL, //registers + isbc064_mod, //modifiers + 1, //numunits + 16, //aradix + 8, //awidth + 1, //aincr + 16, //dradix + 8, //dwidth + NULL, //examine + NULL, //deposite + &isbc064_reset, //reset + NULL, //boot + NULL, //attach + NULL, //detach + NULL, //ctxt + DEV_DEBUG+DEV_DISABLE+DEV_DIS, //flags + 0, //dctrl + isbc064_debug, //debflags + NULL, //msize + NULL //lname +}; + +/* iSBC064 globals */ + +uint8 *MB_buf = NULL; //pointer to memory buffer + +/* Set memory size routine */ + +t_stat isbc064_set_size (UNIT *uptr, int32 val, char *cptr, void *desc) +{ + int32 mc = 0; + uint32 i; + + if (isbc064_dev.dctrl & DEBUG_flow) + printf("isbc064_set_size: val=%04X\n", val); + if ((val <= 0) || (val > MAXMEMSIZE)) { + if (isbc064_dev.dctrl & DEBUG_flow) + printf("isbc064_set_size: Memory size error\n"); + return SCPE_ARG; + } + isbc064_unit.capac = val; + for (i = isbc064_unit.capac; i < MAXMEMSIZE; i++) + isbc064_put_mbyte(i, 0); + isbc064_unit.capac = val; + isbc064_unit.u3 = 0; + if (MB_buf) { + free (MB_buf); + MB_buf = NULL; + } + if (isbc064_dev.dctrl & DEBUG_flow) + printf("isbc064_set_size: Done\n"); + return SCPE_OK; +} + +/* Set memory base address routine */ + +t_stat isbc064_set_base (UNIT *uptr, int32 val, char *cptr, void *desc) +{ + if (isbc064_dev.dctrl & DEBUG_flow) + printf("isbc064_set_base: val=%04X\n", val); + if ((val <= 0) || (val > MAXMEMSIZE) || ((val & 07777) != 0)) { + if (isbc064_dev.dctrl & DEBUG_flow) + printf("isbc064_set_base: Base address error\n"); + return SCPE_ARG; + } + isbc064_unit.u3 = val; + if (MB_buf) { + free (MB_buf); + MB_buf = NULL; + } + if (isbc064_dev.dctrl & DEBUG_flow) + printf("isbc064_set_base: Done\n"); + return (isbc064_reset (NULL)); +} + +/* Reset routine */ + +t_stat isbc064_reset (DEVICE *dptr) +{ + if (isbc064_dev.dctrl & DEBUG_flow) + printf("isbc064_reset: \n"); + if ((isbc064_dev.flags & DEV_DIS) == 0) { + printf("Initializing %s [%04X-%04XH]\n", "iSBC-064", + isbc064_unit.u3, + isbc064_unit.u3 + isbc064_unit.capac - 1); + if (MB_buf == NULL) { + MB_buf = malloc(isbc064_unit.capac); + if (MB_buf == NULL) { + if (isbc064_dev.dctrl & DEBUG_flow) + printf("isbc064_reset: Malloc error\n"); + return SCPE_MEM; + } + } + } + if (isbc064_dev.dctrl & DEBUG_flow) + printf("isbc064_reset: Done\n"); + return SCPE_OK; +} + +/* I/O instruction handlers, called from the CPU module when an + external memory read or write is issued. +*/ + +/* get a byte from memory */ + +int32 isbc064_get_mbyte(int32 addr) +{ + int32 val, org, len; + int i = 0; + + if ((isbc064_dev.flags & DEV_DIS) == 0) { + org = isbc064_unit.u3; + len = isbc064_unit.capac - 1; + if (isbc064_dev.dctrl & DEBUG_read) + printf("isbc064_get_mbyte: addr=%04X", addr); + if ((addr >= org) && (addr <= org + len)) { + val = *(MB_buf + (addr - org)); + if (isbc064_dev.dctrl & DEBUG_read) + printf(" val=%04X\n", val); + return (val & 0xFF); + } else { + if (isbc064_dev.dctrl & DEBUG_read) + printf(" Out of range\n"); + return 0xFF; /* multibus has active high pullups */ + } + } + if (isbc064_dev.dctrl & DEBUG_read) + printf(" Disabled\n"); + return 0xFF; /* multibus has active high pullups */ +} + +/* get a word from memory */ + +int32 isbc064_get_mword(int32 addr) +{ + int32 val; + + val = isbc064_get_mbyte(addr); + val |= (isbc064_get_mbyte(addr+1) << 8); + return val; +} + +/* put a byte into memory */ + +void isbc064_put_mbyte(int32 addr, int32 val) +{ + int32 org, len, type; + int i = 0; + + if ((isbc064_dev.flags & DEV_DIS) == 0) { + org = isbc064_unit.u3; + len = isbc064_unit.capac - 1; + if (isbc064_dev.dctrl & DEBUG_write) + printf("isbc064_put_mbyte: addr=%04X, val=%02X", addr, val); + if ((addr >= org) && (addr < org + len)) { + *(MB_buf + (addr - org)) = val & 0xFF; + if (isbc064_dev.dctrl & DEBUG_write) + printf("\n"); + return; + } else { + if (isbc064_dev.dctrl & DEBUG_write) + printf(" Out of range\n"); + return; + } + } + if (isbc064_dev.dctrl & DEBUG_write) + printf("isbc064_put_mbyte: Disabled\n"); +} + +/* put a word into memory */ + +void isbc064_put_mword(int32 addr, int32 val) +{ + isbc064_put_mbyte(addr, val); + isbc064_put_mbyte(addr+1, val << 8); +} + +/* end of isbc064.c */ diff --git a/MDS-800/common/isbc064x.c b/MDS-800/common/isbc064x.c new file mode 100644 index 00000000..2685ec5f --- /dev/null +++ b/MDS-800/common/isbc064x.c @@ -0,0 +1,205 @@ +/* isbc064.c: Intel iSBC064 64K Byte Memory Card + + Copyright (c) 2011, William A. Beech + + Permission is hereby granted, free of charge, to any person obtaining a + copy of this software and associated documentation files (the "Software"), + to deal in the Software without restriction, including without limitation + the rights to use, copy, modify, merge, publish, distribute, sublicense, + and/or sell copies of the Software, and to permit persons to whom the + Software is furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + WILLIAM A. BEECH BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + Except as contained in this notice, the name of William A. Beech shall not be + used in advertising or otherwise to promote the sale, use or other dealings + in this Software without prior written authorization from William A. Beech. + + These functions support a simulated isbc016, isbc032, isbc048 and isbc064 + memory card on an Intel multibus system. + + ?? ??? 11 - Original file. + 16 Dec 12 - Modified to use system_80_10.cfg file to set base and size. + +*/ + +#include +#include "multibus_defs.h" + +#define SET_XACK(VAL) (XACK = VAL) + +/* prototypes */ + +t_stat isbc064_reset (DEVICE *dptr); +int32 isbc064_get_mbyte(int32 addr); +int32 isbc064_get_mword(int32 addr); +void isbc064_put_mbyte(int32 addr, int32 val); +void isbc064_put_mword(int32 addr, int32 val); + +extern uint8 XACK; /* XACK signal */ + +/* isbc064 Standard I/O Data Structures */ + +UNIT isbc064_unit = { + UDATA (NULL, UNIT_FIX+UNIT_DISABLE+UNIT_BINK, 65536), KBD_POLL_WAIT +}; + +DEBTAB isbc064_debug[] = { + { "ALL", DEBUG_all }, + { "FLOW", DEBUG_flow }, + { "READ", DEBUG_read }, + { "WRITE", DEBUG_write }, + { "XACK", DEBUG_xack }, + { "LEV1", DEBUG_level1 }, + { "LEV2", DEBUG_level2 }, + { NULL } +}; + +DEVICE isbc064_dev = { + "SBC064", //name + &isbc064_unit, //units + NULL, //registers + NULL, //modifiers + 1, //numunits + 16, //aradix + 8, //awidth + 1, //aincr + 16, //dradix + 8, //dwidth + NULL, //examine + NULL, //deposite + &isbc064_reset, //reset + NULL, //boot + NULL, //attach + NULL, //detach + NULL, //ctxt + DEV_DEBUG+DEV_DISABLE+DEV_DIS, //flags + 0, //dctrl + isbc064_debug, //debflags + NULL, //msize + NULL //lname +}; + +/* iSBC064 globals */ + +/* Reset routine */ + +t_stat isbc064_reset (DEVICE *dptr) +{ + if (isbc064_dev.dctrl & DEBUG_flow) + printf("isbc064_reset: \n"); + if ((isbc064_dev.flags & DEV_DIS) == 0) { + if (isbc064_dev.dctrl & DEBUG_flow) + printf("isbc064_reset: Size=%04X\n", isbc064_unit.capac - 1); + if (isbc064_dev.dctrl & DEBUG_flow) + printf("isbc064_reset: Base address=%04X\n", isbc064_unit.u3); + printf("iSBC 064: Available[%04X-%04XH]\n", + isbc064_unit.u3, + isbc064_unit.u3 + isbc064_unit.capac - 1); + } + if (isbc064_unit.filebuf == NULL) { + isbc064_unit.filebuf = malloc(isbc064_unit.capac); + if (isbc064_unit.filebuf == NULL) { + if (isbc064_dev.dctrl & DEBUG_flow) + printf("isbc064_reset: Malloc error\n"); + return SCPE_MEM; + } + } + if (isbc064_dev.dctrl & DEBUG_flow) + printf("isbc064_reset: Done\n"); + return SCPE_OK; +} + +/* get a byte from memory */ + +int32 isbc064_get_mbyte(int32 addr) +{ + int32 val, org, len; + int i = 0; + + if ((isbc064_dev.flags & DEV_DIS) == 0) { + org = isbc064_unit.u3; + len = isbc064_unit.capac; + if (isbc064_dev.dctrl & DEBUG_read) + printf("isbc064_get_mbyte: addr=%04X", addr); + if (isbc064_dev.dctrl & DEBUG_read) + printf("isbc064_put_mbyte: org=%04X, len=%04X\n", org, len); + if ((addr >= org) && (addr < (org + len))) { + SET_XACK(1); /* good memory address */ + if (isbc064_dev.dctrl & DEBUG_xack) + printf("isbc064_get_mbyte: Set XACK for %04X\n", addr); + val = *(uint8 *)(isbc064_unit.filebuf + (addr - org)); + if (isbc064_dev.dctrl & DEBUG_read) + printf(" val=%04X\n", val); + return (val & 0xFF); + } else { + if (isbc064_dev.dctrl & DEBUG_read) + printf(" Out of range\n"); + return 0xFF; /* multibus has active high pullups */ + } + } + if (isbc064_dev.dctrl & DEBUG_read) + printf(" Disabled\n"); + return 0xFF; /* multibus has active high pullups */ +} + +/* get a word from memory */ + +int32 isbc064_get_mword(int32 addr) +{ + int32 val; + + val = isbc064_get_mbyte(addr); + val |= (isbc064_get_mbyte(addr+1) << 8); + return val; +} + +/* put a byte into memory */ + +void isbc064_put_mbyte(int32 addr, int32 val) +{ + int32 org, len; + int i = 0; + + if ((isbc064_dev.flags & DEV_DIS) == 0) { + org = isbc064_unit.u3; + len = isbc064_unit.capac; + if (isbc064_dev.dctrl & DEBUG_write) + printf("isbc064_put_mbyte: addr=%04X, val=%02X\n", addr, val); + if (isbc064_dev.dctrl & DEBUG_write) + printf("isbc064_put_mbyte: org=%04X, len=%04X\n", org, len); + if ((addr >= org) && (addr < (org + len))) { + SET_XACK(1); /* good memory address */ + if (isbc064_dev.dctrl & DEBUG_xack) + printf("isbc064_put_mbyte: Set XACK for %04X\n", addr); + *(uint8 *)(isbc064_unit.filebuf + (addr - org)) = val & 0xFF; + if (isbc064_dev.dctrl & DEBUG_xack) + printf("isbc064_put_mbyte: Return\n"); + return; + } else { + if (isbc064_dev.dctrl & DEBUG_write) + printf(" Out of range\n"); + return; + } + } + if (isbc064_dev.dctrl & DEBUG_write) + printf("isbc064_put_mbyte: Disabled\n"); +} + +/* put a word into memory */ + +void isbc064_put_mword(int32 addr, int32 val) +{ + isbc064_put_mbyte(addr, val); + isbc064_put_mbyte(addr+1, val << 8); +} + +/* end of isbc064.c */ diff --git a/MDS-800/common/isbc208.c b/MDS-800/common/isbc208.c new file mode 100644 index 00000000..349820bc --- /dev/null +++ b/MDS-800/common/isbc208.c @@ -0,0 +1,1699 @@ +/* isbc208.c: Intel iSBC208 Floppy Disk adapter + + Copyright (c) 2011, William A. Beech + + Permission is hereby granted, free of charge, to any person obtaining a + copy of this software and associated documentation files (the "Software"), + to deal in the Software without restriction, including without limitation + the rights to use, copy, modify, merge, publish, distribute, sublicense, + and/or sell copies of the Software, and to permit persons to whom the + Software is furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + WILLIAM A. BEECH BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + Except as contained in this notice, the name of William A. Beech shall not be + used in advertising or otherwise to promote the sale, use or other dealings + in this Software without prior written authorization from William A. Beech. + + These functions support a simulated iSBC208 interface to 4 each 8-, 5 1/4-, or + 3 1/2-inch floppy disk drives. Commands are setup with programmed I/O to the + simulated ports of an i8237 DMA controller and an i8272 FDC. Data transfer + to/from the simulated disks is performed directly with the multibus memory. + + The iSBC-208 can be configured for 8- or 16-bit addresses. It defaults to 8-bit + addresses for the 8080/8085 processors. It can be configured for I/O port + addresses with 3-bits (8-bit address) or 11-bits (16-bit address). Default is + 3-bits set to 0. This defines the port offset to be used to determine the actual + port address. Bus priority can be configured for parallel or serial mode. Default is + serial. The multibus interface interrupt can be configured for interrupt 0-7. + Default is none. Since all channel registers in the i8237 are 16-bit, transfers + are done as two 8-bit operations, low- then high-byte. + + Port addressing is as follows (Port offset = 0): + + Port Mode Command Function + + 00 Write Load DMAC Channel 0 Base and Current Address Regsiters + Read Read DMAC Channel 0 Current Address Register + 01 Write Load DMAC Channel 0 Base and Current Word Count Registers + Read Read DMAC Channel 0 Current Word Count Register + 04 Write Load DMAC Channel 2 Base and Current Address Regsiters + Read Read DMAC Channel 2 Current Address Register + 05 Write Load DMAC Channel 2 Base and Current Word Count Registers + Read Read DMAC Channel 2 Current Word Count Register + 06 Write Load DMAC Channel 3 Base and Current Address Regsiters + Read Read DMAC Channel 3 Current Address Register + 07 Write Load DMAC Channel 3 Base and Current Word Count Registers + Read Read DMAC Channel 3 Current Word Count Register + 08 Write Load DMAC Command Register + Read Read DMAC Status Register + 09 Write Load DMAC Request Register + OA Write Set/Reset DMAC Mask Register + OB Write Load DMAC Mode Register + OC Write Clear DMAC First/Last Flip-Flop + 0D Write DMAC Master Clear + OF Write Load DMAC Mask Register + 10 Read Read FDC Status Register + 11 Write Load FDC Data Register + Read Read FDC Data Register + 12 Write Load Controller Auxiliary Port + Read Poll Interrupt Status + 13 Write Controller Reset + 14 Write Load Controller Low-Byte Segment Address Register + 15 Write Load Controller High-Byte Segment Address Register + 20-2F Read/Write Reserved for iSBX Multimodule Board + + Register usage is defined in the following paragraphs. + + Read/Write DMAC Address Registers + + Used to simultaneously load a channel's current-address register and base-address + register with the memory address of the first byte to be transferred. (The Channel + 0 current/base address register must be loaded prior to initiating a diskette read + or write operation.) Since each channel's address registers are 16 bits in length + (64K address range), two "write address register" commands must be executed in + order to load the complete current/base address registers for any channel. + + Read/Write DMAC Word Count Registers + + The Write DMAC Word Count Register command is used to simultaneously load a + channel's current and base word-count registers with the number of bytes + to be transferred during a subsequent DMA operation. Since the word-count + registers are 16-bits in length, two commands must be executed to load both + halves of the registers. + + Write DMAC Command Register + + The Write DMAC Command Register command loads an 8-bit byte into the + DMAC's command register to define the operating characteristics of the + DMAC. The functions of the individual bits in the command register are + defined in the following diagram. Note that only two bits within the + register are applicable to the controller; the remaining bits select + functions that are not supported and, accordingly, must always be set + to zero. + + 7 6 5 4 3 2 1 0 + +---+---+---+---+---+---+---+---+ + | 0 0 0 0 0 0 | + +---+---+---+---+---+---+---+---+ + | | + | +---------- 0 CONTROLLER ENABLE + | 1 CONTROLLER DISABLE + | + +------------------ 0 FIXED PRIORITY + 1 ROTATING PRIORITY + + Read DMAC Status Register Command + + The Read DMAC Status Register command accesses an 8-bit status byte that + identifies the DMA channels that have reached terminal count or that + have a pending DMA request. + + 7 6 5 4 3 2 1 0 + +---+---+---+---+---+---+---+---+ + | 0 0 | + +---+---+---+---+---+---+---+---+ + | | | | | | + | | | | | +-- CHANNEL 0 TC + | | | | +---------- CHANNEL 2 TC + | | | +-------------- CHANNEL 3 TC + | | +------------------ CHANNEL 0 DMA REQUEST + | +-------------------------- CHANNEL 2 DMA REQUEST + +------------------------------ CHANNEL 3 DMA REQUEST + + Write DMAC Request Register + + The data byte associated with the Write DMAC Request Register command + sets or resets a channel's associated request bit within the DMAC's + internal 4-bit request register. + + 7 6 5 4 3 2 1 0 + +---+---+---+---+---+---+---+---+ + | X X X X X | + +---+---+---+---+---+---+---+---+ + | | | + | +---+-- 00 SELECT CHANNEL 0 + | 01 SELECT CHANNEL 1 + | 10 SELECT CHANNEL 2 + | 11 SELECT CHANNEL 3 + | + +---------- 0 RESET REQUEST BIT + 1 SET REQUEST BIT + + Set/Reset DMAC Mask Register + + Prior to a DREQ-initiated DMA transfer, the channel's mask bit must + be reset to enable recognition of the DREQ input. When the transfer + is complete (terminal count reached or external EOP applied) and + the channel is not programmed to autoinitialize, the channel's + mask bit is automatically set (disabling DREQ) and must be reset + prior to a subsequent DMA transfer. All four bits of the mask + register are set (disabling the DREQ inputs) by a DMAC master + clear or controller reset. Additionally, all four bits can be + set/reset by a single Write DMAC Mask Register command. + + + 7 6 5 4 3 2 1 0 + +---+---+---+---+---+---+---+---+ + | X X X X X | + +---+---+---+---+---+---+---+---+ + | | | + | +---+-- 00 SELECT CHANNEL 0 + | 01 SELECT CHANNEL 1 + | 10 SELECT CHANNEL 2 + | 11 SELECT CHANNEL 3 + | + +---------- 0 RESET REQUEST BIT + 1 SET REQUEST BIT + + Write DMAC Mode Register + + The Write DMAC Mode Register command is used to define the + operating mode characteristics for each DMA channel. Each + channel has an internal 6-bit mode register; the high-order + six bits of the associated data byte are written into the + mode register addressed by the two low-order bits. + + + 7 6 5 4 3 2 1 0 + +---+---+---+---+---+---+---+---+ + | | + +---+---+---+---+---+---+---+---+ + | | | | | | | | + | | | | | | +---+-- 00 SELECT CHANNEL 0 + | | | | | | 01 SELECT CHANNEL 1 + | | | | | | 10 SELECT CHANNEL 2 + | | | | | | 11 SELECT CHANNEL 3 + | | | | | | + | | | | +---+---------- 00 VERIFY TRANSFER + | | | | 01 WRITE TRANSFER + | | | | 10 READ TRANSFER + | | | | + | | | +------------------ 0 AUTOINITIALIZE DISABLE + | | | 1 AUTOINITIALIZE ENABLE + | | | + | | +---------------------- 0 ADDRESS INCREMENT + | | 1 ADDRESS DECREMENT + | | + +---+-------------------------- 00 DEMAND MODE + 01 SINGLE MODE + 10 BLOCK MODE + + Clear DMAC First/Last Flip-Flop + + The Clear DMAC First/Last Flip-Flop command initializes + the DMAC's internal first/last flip-flop so that the + next byte written to or re~d from the 16-bit address + or word-count registers is the low-order byte. The + flip-flop is toggled with each register access so that + a second register read or write command accesses the + high-order byte. + + DMAC Master Clear + + The DMAC Master Clear command clears the DMAC's command, status, + request, and temporary registers to zero, initializes the + first/last flip-flop, and sets the four channel mask bits in + the mask register to disable all DMA requests (i.e., the DMAC + is placed in an idle state). + + Write DMAC Mask Register + + The Write DMAC Mask Register command allows all four bits of the + DMAC's mask register to be written with a single command. + + 7 6 5 4 3 2 1 0 + +---+---+---+---+---+---+---+---+ + | X X X X X | + +---+---+---+---+---+---+---+---+ + | | | + | | +-- 0 CLEAR CHANNEL 0 MASK BIT + | | 1 SET CHANNEL 0 MASK BIT + | | + | +---------- 0 CLEAR CHANNEL 2 MASK BIT + | 1 SET CHANNEL 2 MASK BIT + | + +-------------- 0 CLEAR CHANNEL 3 MASK BIT + 1 SET CHANNEL 3 MASK BIT + + Read FDC Status Register + + The Read FDC Status Register command accesses the FDC's main + status register. The individual status register bits are as + follows: + + 7 6 5 4 3 2 1 0 + +---+---+---+---+---+---+---+---+ + | | + +---+---+---+---+---+---+---+---+ + | | | | | | | | + | | | | | | | +-- FDD 0 BUSY + | | | | | | +------ FDD 1 BUSY + | | | | | +---------- FDD 2 BUSY + | | | | +-------------- FDD 3 BUSY + | | | +------------------ FDC BUSY + | | +---------------------- NON-DMA MODE + | +-------------------------- DATA INPUT/OUTPUT + +------------------------------ REQUEST FOR MASTER + + Read/Write FDC Data Register + + The Read and Write FDC Data Register commands are used to write + command and parameter bytes to the FDC in order to specify the + operation to be performed (referred to as the "command phase") + and to read status bytes from the FDC following the operation + (referred to as the "result phase"). During the command and + result phases, the 8-bit data register is actually a series of + 8-bit registers in a stack. Each register is accessed in + sequence; the number of registers accessed and the individual + register contents are defined by the specific disk command. + + Write Controller Auxiliary Port + + The Write Controller Auxiliary Port command is used to set or + clear individual bits within the controller's auxiliary port. + The four low-order port bits are dedicated to auxiliary drive + control functions (jumper links are required to connect the + desired port bit to an available pin on the drive interface + connectors). The most common application for these bits is + the "Motor-On" control function for mini-sized drives. + + 7 6 5 4 3 2 1 0 + +---+---+---+---+---+---+---+---+ + | | + +---+---+---+---+---+---+---+---+ + | | | | | | | | + | | | | +---+---+---+-- DRIVE CONTROL + | | | +------------------ ADDR 20 + | | +---------------------- ADDR 21 + | +-------------------------- ADDR 22 + +------------------------------ ADDR 23 + + Poll Interrupt Status + + The Poll Interrupt Status command presents the interrupt + status of the controller and the two interrupt status + lines dedicated to the iSBX Multimodule board. + 7 6 5 4 3 2 1 0 + +---+---+---+---+---+---+---+---+ + | X X X X X | + +---+---+---+---+---+---+---+---+ + | | | + | | +-- CONTROLLER INTERRUPT + | +------ MULTIMODULE BOARD INTERRUPT 0 + +---------- MULTIMODULE BOARD INTERRUPT 1 + + Controller Reset + + The Controller Reset command is the software reset for the + controller. This command clears the controller's auxiliary + port and segment address register, provides a reset signal + to the iSBX Multimodule board and initializes the bus + controller (releases the bus), the DMAC (clears the internal + registers and masks the DREQ inputs), and the FDC (places + the FDC in an idle state and disables the output control + lines to the diskette drive). + + Write Controller Low- And High-Byte Segment Address Registers + + The Write Controller Low- and High-Byte Address Registers + commands are required when the controller uses 20-bit + addressing (memory address range from 0 to OFFFFFH). These + commands are issued prior to initiating a diskette read or + write operation to specify the 16-bit segment address. + + FDC Commands + + The 8272/D765 is capable of performing 15 different + commands. Each command is initiated by a multibyte transfer + from the processor, and the result after execution of the + command may also be a multibyte transfer back to the processor. + Because of this multibyte interchange of information between + the FDC and the processor, it is convenient to consider each + command as consisting of three phases: + + Command Phase: The FDC receives all information required to + perform a particular operation from the processor. + + Execution Phase: The FDC performs the operation it was + instructed to do. + + Result Phase: After completion of the operation, status + and other housekeeping information are made available + to the processor. + + Not all the FDC commands are supported by this emulation. Only the subset + of commands required to build an operable CP/M BIOS are supported. They are: + + Read - Read specified data from the selected FDD. + + Write - Write specified data to the selected FDD. + + Seek - Move the R/W head to the specified cylinder on the specified FDD. + + Specify - Set the characteristics for all the FDDs. + + Sense Interrupt - Sense change in FDD Ready line or and of Seek/Recalibrate + command. + + Sense Drive - Returns status of all the FDDs. + + Recalibrate - Move the R/W head to cylinder 0 on the specified FDD. + + Format Track - Format the current track on the specified FDD. + + Read ID - Reads the first address mark it finds. + + Simulated Floppy Disk Drives + + The units in this device simulate an 8- or 5 1/4- or 3 1/2 inch drives. The + drives can emulate SSSD, SSDD, and DSDD. Drives can be attached to files up + to 1.44MB in size. Drive configuration is selected when a disk is logged onto + the system. An identity sector or identity byte contains information to + configure the OS drivers for the type of drive to emulate. + + uptr->u3 - + uptr->u4 - + uptr->u5 - + uptr->u6 - unit number (0-FDD_NUM) + + ?? ??? 11 - Original file. + 16 Dec 12 - Modified to use system_80_10.cfg file to set I/O base address. +*/ + +#include "system_defs.h" + +#define UNIT_V_WPMODE (UNIT_V_UF) /* Write protect */ +#define UNIT_WPMODE (1 << UNIT_V_WPMODE) + +/* master status register definitions */ +#define RQM 0x80 /* Request for master */ +#define DIO 0x40 /* Data I/O Direction 0=W, 1=R */ +#define NDM 0x20 /* Non-DMA mode */ +#define CB 0x10 /* FDC busy */ +#define D3B 0x08 /* FDD 3 busy */` +#define D2B 0x04 /* FDD 2 busy */` +#define D1B 0x02 /* FDD 1 busy */` +#define D0B 0x01 /* FDD 0 busy */` + +/* status register 0 definitions */ +#define IC 0xC0 /* Interrupt code */ +#define IC_NORM 0x00 /* normal completion */ +#define IC_ABNORM 0x40 /* abnormal completion */ +#define IC_INVC 0x80 /* invalid command */ +#define IC_RC 0xC0 /* drive not ready */ +#define SE 0x20 /* Seek end */ +#define EC 0x10 /* Equipment check */ +#define NR 0x08 /* Not ready */ +#define HD 0x04 /* Head selected */ +#define US 0x03 /* Unit selected */ +#define US_0 0x00 /* Unit 0 */ +#define US_1 0x01 /* Unit 1 */ +#define US_2 0x02 /* Unit 2 */ +#define US_3 0x03 /* Unit 3 */ + +/* status register 1 definitions */ +#define EN 0x80 /* End of cylinder */ +#define DE 0x20 /* Data error */ +#define OR 0x10 /* Overrun */ +#define ND 0x04 /* No data */ +#define NW 0x02 /* Not writable */ +#define MA 0x01 /* Missing address mark */ + +/* status register 2 definitions */ +#define CM 0x40 /* Control mark */ +#define DD 0x20 /* Data error in data field */ +#define WC 0x10 /* Wrong cylinder */ +#define BC 0x02 /* Bad cylinder */ +#define MD 0x01 /* Missing address mark in data field */ + +/* status register 3/fddst definitions */ +#define FT 0x80 /* Fault */ +#define WP 0x40 /* Write protect */ +#define RDY 0x20 /* Ready */ +#define T0 0x10 /* Track 0 */ +#define TS 0x08 /* Two sided */ +//#define HD 0x04 /* Head selected */ +//#define US 0x03 /* Unit selected */ + +/* FDC command definitions */ +#define READTRK 0x02 +#define SPEC 0x03 +#define SENDRV 0x04 +#define WRITE 0x05 +#define READ 0x06 +#define HOME 0x07 +#define SENINT 0x08 +#define WRITEDEL 0x09 +#define READID 0x0A +#define READDEL 0x0C +#define FMTTRK 0x0D +#define SEEK 0x0F +#define SCANEQ 0x11 +#define SCANLOEQ 0x19 +#define SCANHIEQ 0x1D + +#define FDD_NUM 4 + +/* internal function prototypes */ + +t_stat isbc208_svc (UNIT *uptr); +t_stat isbc208_reset (DEVICE *dptr); +void isbc208_reset1 (void); +t_stat isbc208_attach (UNIT *uptr, char *cptr); +t_stat isbc208_set_mode (UNIT *uptr, int32 val, char *cptr, void *desc); +int32 isbc208_r0(int32 io, int32 data); +int32 isbc208_r1(int32 io, int32 data); +int32 isbc208_r2(int32 io, int32 data); +int32 isbc208_r3(int32 io, int32 data); +int32 isbc208_r4(int32 io, int32 data); +int32 isbc208_r5(int32 io, int32 data); +int32 isbc208_r6(int32 io, int32 data); +int32 isbc208_r7(int32 io, int32 data); +int32 isbc208_r8(int32 io, int32 data); +int32 isbc208_r9(int32 io, int32 data); +int32 isbc208_rA(int32 io, int32 data); +int32 isbc208_rB(int32 io, int32 data); +int32 isbc208_rC(int32 io, int32 data); +int32 isbc208_rD(int32 io, int32 data); +int32 isbc208_rE(int32 io, int32 data); +int32 isbc208_rF(int32 io, int32 data); +int32 isbc208_r10(int32 io, int32 data); +int32 isbc208_r11(int32 io, int32 data); +int32 isbc208_r12(int32 io, int32 data); +int32 isbc208_r13(int32 io, int32 data); +int32 isbc208_r14(int32 io, int32 data); +int32 isbc208_r15(int32 io, int32 data); + +/* external function prototypes */ + +extern void set_irq(int32 int_num); +extern void clr_irq(int32 int_num); +extern int32 reg_dev(int32 (*routine)(), int32 port); +extern void multibus_put_mbyte(int32 addr, int32 val); +extern int32 multibus_get_mbyte(int32 addr); + +/* 8237 physical register definitions */ +uint16 i8237_r0; // 8237 ch 0 address register +uint16 i8237_r1; // 8237 ch 0 count register +uint16 i8237_r2; // 8237 ch 1 address register +uint16 i8237_r3; // 8237 ch 1 count register +uint16 i8237_r4; // 8237 ch 2 address register +uint16 i8237_r5; // 8237 ch 2 count register +uint16 i8237_r6; // 8237 ch 3 address register +uint16 i8237_r7; // 8237 ch 3 count register +uint8 i8237_r8; // 8237 status register +uint8 i8237_r9; // 8237 command register +uint8 i8237_rA; // 8237 mode register +uint8 i8237_rB; // 8237 mask register +uint8 i8237_rC; // 8237 request register +uint8 i8237_rD; // 8237 first/last ff + +/* 8272 physical register definitions */ +/* 8272 command register stack*/ +uint8 i8272_w0; // MT+MFM+SK+command +uint8 i8272_w1; // HDS [HDS=H << 2] + DS1 + DS0 +uint8 i8272_w2; // cylinder # (0-XX) +uint8 i8272_w3; // head # (0 or 1) +uint8 i8272_w4; // sector # (1-XX) +uint8 i8272_w5; // number of bytes (128 << N) +uint8 i8272_w6; // End of track (last sector # on cylinder) +uint8 i8272_w7; // Gap length +uint8 i8272_w8; // Data length (when N=0, size to read or write) + +/* 8272 status register stack */ +uint8 i8272_msr; // main status +uint8 i8272_r0; // ST 0 +uint8 i8272_r1; // ST 1 +uint8 i8272_r2; // ST 2 +uint8 i8272_r3; // ST 3 + +/* iSBC-208 physical register definitions */ +uint16 isbc208_sr; // isbc-208 segment register +uint8 isbc208_i; // iSBC-208 interrupt register +uint8 isbc208_a; // iSBC-208 auxillary port register + +/* data obtained from analyzing command registers/attached file length */ +int32 wsp = 0, rsp = 0; // indexes to write and read stacks (8272 data) +int32 cyl; // current cylinder +int32 hed; // current head [ h << 2] +int32 h; // current head +int32 sec; // current sector +int32 drv; // current drive +uint8 cmd, pcmd; // current command +int32 secn; // N 0-128, 1-256, etc +int32 spt; // sectors per track +int32 ssize; // sector size (128 << N) + +uint8 *isbc208_buf[FDD_NUM] = { /* FDD buffer pointers */ + NULL, + NULL, + NULL, + NULL +}; + +int32 fddst[FDD_NUM] = { // in ST3 format + 0, // status of FDD 0 + 0, // status of FDD 1 + 0, // status of FDD 2 + 0 // status of FDD 3 +}; + +int8 maxcyl[FDD_NUM] = { + 0, // last cylinder + 1 of FDD 0 + 0, // last cylinder + 1 of FDD 1 + 0, // last cylinder + 1 of FDD 2 + 0 // last cylinder + 1 of FDD 3 +}; + +/* isbc208 Standard SIMH Device Data Structures - 4 units */ +UNIT isbc208_unit[] = { + { UDATA (&isbc208_svc, UNIT_ATTABLE+UNIT_DISABLE, 0), 20 }, + { UDATA (&isbc208_svc, UNIT_ATTABLE+UNIT_DISABLE, 0), 20 }, + { UDATA (&isbc208_svc, UNIT_ATTABLE+UNIT_DISABLE, 0), 20 }, + { UDATA (&isbc208_svc, UNIT_ATTABLE+UNIT_DISABLE, 0), 20 } +}; + +REG isbc208_reg[] = { + { HRDATA (CH0ADR, i8237_r0, 16) }, + { HRDATA (CH0CNT, i8237_r1, 16) }, + { HRDATA (CH1ADR, i8237_r2, 16) }, + { HRDATA (CH1CNT, i8237_r3, 16) }, + { HRDATA (CH2ADR, i8237_r4, 16) }, + { HRDATA (CH2CNT, i8237_r5, 16) }, + { HRDATA (CH3ADR, i8237_r6, 16) }, + { HRDATA (CH3CNT, i8237_r7, 16) }, + { HRDATA (STAT37, i8237_r8, 8) }, + { HRDATA (CMD37, i8237_r9, 8) }, + { HRDATA (MODE, i8237_rA, 8) }, + { HRDATA (MASK, i8237_rB, 8) }, + { HRDATA (REQ, i8237_rC, 8) }, + { HRDATA (FF, i8237_rD, 8) }, + { HRDATA (STAT72, i8272_msr, 8) }, + { HRDATA (STAT720, i8272_r0, 8) }, + { HRDATA (STAT721, i8272_r1, 8) }, + { HRDATA (STAT722, i8272_r2, 8) }, + { HRDATA (STAT723, i8272_r3, 8) }, + { HRDATA (CMD720, i8272_w0, 8) }, + { HRDATA (CMD721, i8272_w1, 8) }, + { HRDATA (CMD722, i8272_w2, 8) }, + { HRDATA (CMD723, i8272_w3, 8) }, + { HRDATA (CMD724, i8272_w4, 8) }, + { HRDATA (CMD725, i8272_w5, 8) }, + { HRDATA (CMD726, i8272_w6, 8) }, + { HRDATA (CMD727, i8272_w7, 8) }, + { HRDATA (CMD728, i8272_w8, 8) }, + { HRDATA (FDD0, fddst[0], 8) }, + { HRDATA (FDD1, fddst[1], 8) }, + { HRDATA (FDD2, fddst[2], 8) }, + { HRDATA (FDD3, fddst[3], 8) }, + { HRDATA (SEGREG, isbc208_sr, 8) }, + { HRDATA (AUX, isbc208_a, 8) }, + { HRDATA (INT, isbc208_i, 8) }, + { NULL } +}; + +MTAB isbc208_mod[] = { + { UNIT_WPMODE, 0, "RW", "RW", &isbc208_set_mode }, + { UNIT_WPMODE, UNIT_WPMODE, "WP", "WP", &isbc208_set_mode }, + { 0 } +}; + +DEBTAB isbc208_debug[] = { + { "ALL", DEBUG_all }, + { "FLOW", DEBUG_flow }, + { "READ", DEBUG_read }, + { "WRITE", DEBUG_write }, + { "LEV1", DEBUG_level1 }, + { "LEV2", DEBUG_level2 }, + { "REG", DEBUG_reg }, + { NULL } +}; + +DEVICE isbc208_dev = { + "SBC208", //name + isbc208_unit, //units + isbc208_reg, //registers + isbc208_mod, //modifiers + FDD_NUM, //numunits + 16, //aradix + 32, //awidth + 1, //aincr + 16, //dradix + 8, //dwidth + NULL, //examine + NULL, //deposit + &isbc208_reset, //deposit + NULL, //boot + &isbc208_attach, //attach + NULL, //detach + NULL, //ctxt + DEV_DEBUG+DEV_DISABLE+DEV_DIS, //flags + 0, //dctrl +// DEBUG_flow + DEBUG_read + DEBUG_write, //dctrl + isbc208_debug, //debflags + NULL, //msize + NULL //lname +}; + +/* Service routines to handle simulator functions */ + +/* service routine - actually does the simulated disk I/O */ + +t_stat isbc208_svc (UNIT *uptr) +{ + int32 i, imgadr, data; + int c; + int32 bpt, bpc; + FILE *fp; + + if ((i8272_msr & CB) && cmd && (uptr->u6 == drv)) { /* execution phase */ + if (isbc208_dev.dctrl & DEBUG_flow) + printf("isbc208_svc: Entered execution phase\n"); + switch (cmd) { + case READ: /* 0x06 */ +// printf("READ-e: fddst=%02X", fddst[uptr->u6]); + h = i8272_w3; // h = 0 or 1 + hed = i8272_w3 << 2; // hed = 0 or 4 [h << 2] + sec = i8272_w4; // sector number (1-XX) + secn = i8272_w5; // N (0-5) + spt = i8272_w6; // sectors/track + ssize = 128 << secn; // size of sector (bytes) + bpt = ssize * spt; // bytes/track + bpc = bpt * 2; // bytes/cylinder +// printf(" d=%d h=%d c=%d s=%d\n", drv, h, cyl, sec); + if (isbc208_dev.dctrl & DEBUG_flow) { + printf("isbc208_svc: FDC read: h=%d, hed=%d, sec=%d, secn=%d, spt=%d, ssize=%04X, bpt=%04X, bpc=%04X\n", + h, hed, sec, secn, spt, ssize, bpt, bpc); + printf("isbc208_svc: FDC read: d=%d h=%d c=%d s=%d N=%d spt=%d fddst=%02X\n", + drv, h, cyl, sec, secn, spt, fddst[uptr->u6]); + printf("\nFDC read of d=%d h=%d c=%d s=%d", + drv, h, cyl, sec); + } + if ((fddst[uptr->u6] & RDY) == 0) { // drive not ready + i8272_r0 = IC_ABNORM + NR + hed + drv; /* command done - Not ready error*/ + i8272_r3 = fddst[uptr->u6]; + i8272_msr |= (RQM + DIO + CB); /* enter result phase */ + if (isbc208_dev.dctrl & DEBUG_flow) + printf("isbc208_svc: FDC read: Not Ready\n"); + } else { // get image addr for this d, h, c, s + imgadr = (cyl * bpc) + (h * bpt) + ((sec - 1) * ssize); + if (isbc208_dev.dctrl & DEBUG_flow) + printf("isbc208_svc: FDC read: DMA addr=%04X cnt=%04X imgadr=%04X\n", + i8237_r0, i8237_r1, imgadr); + for (i=0; i<=i8237_r1; i++) { /* copy selected sector to memory */ + data = *(isbc208_buf[uptr->u6] + (imgadr + i)); + multibus_put_mbyte(i8237_r0 + i, data); + } +//*** need to step return results IAW table 3-11 in 143078-001 + i8272_w4 = ++sec; /* next sector */ + i8272_r0 = hed + drv; /* command done - no error */ + i8272_r3 = fddst[uptr->u6]; + } + i8272_r1 = 0; + i8272_r2 = 0; + i8272_w2 = cyl; /* generate a current address mark */ + i8272_w3 = h; + if (i8272_w4 > i8272_w6) { // beyond last sector of track? + i8272_w4 = 1; // yes, set to sector 1; + if (h) { // on head one? + i8272_w2++; // yes, step cylinder + h = 0; // back to head 0 + } + } + i8272_w5 = secn; + i8272_msr |= (RQM + DIO + CB); /* enter result phase */ + rsp = wsp = 0; /* reset indexes */ + set_irq(SBC208_INT); /* set interrupt */ +// printf("READ-x: fddst=%02X\n", fddst[uptr->u6]); + break; + case WRITE: /* 0x05 */ +// printf("WRITE-e: fddst=%02X\n", fddst[uptr->u6]); + h = i8272_w3; // h = 0 or 1 + hed = i8272_w3 << 2; // hed = 0 or 4 [h << 2] + sec = i8272_w4; // sector number (1-XX) + secn = i8272_w5; // N (0-5) + spt = i8272_w6; // sectors/track + ssize = 128 << secn; // size of sector (bytes) + bpt = ssize * spt; // bytes/track + bpc = bpt * 2; // bytes/cylinder + if (isbc208_dev.dctrl & DEBUG_flow) + printf("isbc208_svc: FDC write: hed=%d, sec=%d, secn=%d, spt=%d, ssize=%04X, bpt=%04X, bpc=%04X\n", + hed, sec, secn, spt, ssize, bpt, bpc); + if (isbc208_dev.dctrl & DEBUG_flow) + printf("isbc208_svc: FDC write: d=%d h=%d c=%d s=%d N=%d spt=%d fddst=%02X\n", + drv, h, cyl, sec, secn, spt, fddst[uptr->u6]); + i8272_r1 = 0; // clear ST1 + i8272_r2 = 0; // clear ST2 + if ((fddst[uptr->u6] & RDY) == 0) { + i8272_r0 = IC_ABNORM + NR + hed + drv; /* Not ready error*/ + i8272_r3 = fddst[uptr->u6]; + i8272_msr |= (RQM + DIO + CB); /* enter result phase */ + if (isbc208_dev.dctrl & DEBUG_flow) + printf("isbc208_svc: FDC write: Not Ready\n"); +// } else if (fddst[uptr->u6] & WP) { +// i8272_r0 = IC_ABNORM + hed + drv; /* write protect error*/ +// i8272_r1 = NW; // set not writable in ST1 +// i8272_r3 = fddst[uptr->u6] + WP; +// i8272_msr |= (RQM + DIO + CB); /* enter result phase */ +// printf("\nWrite Protected fddst[%d]=%02X\n", uptr->u6, fddst[uptr->u6]); +// if (isbc208_dev.dctrl & DEBUG_flow) +// printf("isbc208_svc: FDC write: Write Protected\n"); + } else { // get image addr for this d, h, c, s + imgadr = (cyl * bpc) + (h * bpt) + ((sec - 1) * ssize); + if (isbc208_dev.dctrl & DEBUG_flow) + printf("isbc208_svc: FDC write: DMA adr=%04X cnt=%04X imgadr=%04X\n", + i8237_r0, i8237_r1, imgadr); + for (i=0; i<=i8237_r1; i++) { /* copy selected memory to image */ + data = multibus_get_mbyte(i8237_r0 + i); + *(isbc208_buf[uptr->u6] + (imgadr + i)) = data; + } + //*** quick fix. Needs more thought! + fp = fopen(uptr->filename, "wb"); // write out modified image + for (i=0; icapac; i++) { + c = *(isbc208_buf[uptr->u6] + i) & 0xFF; + fputc(c, fp); + } + fclose(fp); +//*** need to step return results IAW table 3-11 in 143078-001 + i8272_w2 = cyl; /* generate a current address mark */ + i8272_w3 = hed >> 2; + i8272_w4 = ++sec; /* next sector */ + i8272_w5 = secn; + i8272_r0 = hed + drv; /* command done - no error */ + i8272_r3 = fddst[uptr->u6]; + i8272_msr |= (RQM + DIO + CB); /* enter result phase */ + } + rsp = wsp = 0; /* reset indexes */ + set_irq(SBC208_INT); /* set interrupt */ +// printf("WRITE-x: fddst=%02X\n", fddst[uptr->u6]); + break; + case FMTTRK: /* 0x0D */ + if ((fddst[uptr->u6] & RDY) == 0) { + i8272_r0 = IC_ABNORM + NR + hed + drv; /* Not ready error*/ + i8272_msr |= (RQM + DIO + CB); /* enter result phase */ + if (isbc208_dev.dctrl & DEBUG_flow) + printf("isbc208_svc: Not Ready\n"); + } else if (fddst[uptr->u6] & WP) { + i8272_r0 = IC_ABNORM + hed + drv; /* write protect error*/ + i8272_r3 = fddst[uptr->u6] + WP; + i8272_msr |= (RQM + DIO + CB); /* enter result phase */ + if (isbc208_dev.dctrl & DEBUG_flow) + printf("isbc208_svc: Write Protected\n"); + } else { + ; /* do nothing for now */ + i8272_msr |= (RQM + DIO + CB); /* enter result phase */ + } + rsp = wsp = 0; /* reset indexes */ + set_irq(SBC208_INT); /* set interrupt */ + break; + case SENINT: /* 0x08 */ + i8272_msr |= (RQM + DIO + CB); /* enter result phase */ + i8272_r0 = hed + drv; /* command done - no error */ + i8272_r1 = 0; + i8272_r2 = 0; + rsp = wsp = 0; /* reset indexes */ + clr_irq(SBC208_INT); /* clear interrupt */ + break; + case SENDRV: /* 0x04 */ + if (isbc208_dev.dctrl & DEBUG_flow) + printf("isbc208_svc: FDC sense drive of disk=%d fddst=%02X\n", drv, fddst[uptr->u6]); + i8272_msr |= (RQM + DIO + CB); /* enter result phase */ + i8272_r0 = hed + drv; /* command done - no error */ + i8272_r1 = 0; + i8272_r2 = 0; + i8272_r3 = fddst[drv]; /* drv status */ + rsp = wsp = 0; /* reset indexes */ + break; + case HOME: /* 0x07 */ +// printf("HOME-e: fddst=%02X\n", fddst[uptr->u6]); + if (isbc208_dev.dctrl & DEBUG_flow) + printf("isbc208_svc: FDC home: disk=%d fddst=%02X\n", drv, fddst[uptr->u6]); + if ((fddst[uptr->u6] & RDY) == 0) { + i8272_r0 = IC_ABNORM + NR + hed + drv; /* Not ready error*/ + i8272_r3 = fddst[uptr->u6]; + if (isbc208_dev.dctrl & DEBUG_flow) + printf("isbc208_svc: Not Ready\n"); + } else { + cyl = 0; /* now on cylinder 0 */ + fddst[drv] |= T0; /* set status flag */ + i8272_r0 = SE + hed + drv; /* seek end - no error */ + } + i8272_r1 = 0; + i8272_r2 = 0; + i8272_msr &= ~(RQM + DIO + CB + hed + drv); /* execution phase done*/ + i8272_msr |= RQM; /* enter COMMAND phase */ + rsp = wsp = 0; /* reset indexes */ + set_irq(SBC208_INT); /* set interrupt */ +// printf("HOME-x: fddst=%02X\n", fddst[uptr->u6]); + break; + case SPEC: /* 0x03 */ + fddst[0] |= TS; //*** bad, bad, bad! + fddst[1] |= TS; + fddst[2] |= TS; + fddst[3] |= TS; +// printf("SPEC-e: fddst[%d]=%02X\n", uptr->u6, fddst[uptr->u6]); + if (isbc208_dev.dctrl & DEBUG_flow) + printf("isbc208_svc: FDC specify SRT=%d ms HUT=%d ms HLT=%d ms \n", + 16 - (drv >> 4), 16 * (drv & 0x0f), i8272_w2 & 0xfe); + i8272_r0 = hed + drv; /* command done - no error */ + i8272_r1 = 0; + i8272_r2 = 0; + i8272_msr &= ~(RQM + DIO + CB); /* execution phase done*/ + i8272_msr = 0; // force 0 for now, where does 0x07 come from? + i8272_msr |= RQM; /* enter command phase */ + rsp = wsp = 0; /* reset indexes */ +// printf("SPEC-x: fddst[%d]=%02X\n", uptr->u6, fddst[uptr->u6]); + break; + case READID: /* 0x0A */ + if ((fddst[uptr->u6] & RDY) == 0) { + i8272_r0 = IC_RC + NR + hed + drv; /* Not ready error*/ + i8272_r3 = fddst[uptr->u6]; + if (isbc208_dev.dctrl & DEBUG_flow) + printf("isbc208_svc: Not Ready\n"); + } else { + i8272_w2 = cyl; /* generate a valid address mark */ + i8272_w3 = hed >> 2; + i8272_w4 = 1; /* always sector 1 */ + i8272_w5 = secn; + i8272_r0 = hed + drv; /* command done - no error */ + i8272_msr &= ~(RQM + DIO + CB); /* execution phase done*/ + i8272_msr |= RQM; /* enter command phase */ + } + i8272_r1 = 0; + i8272_r2 = 0; + rsp = wsp = 0; /* reset indexes */ + break; + case SEEK: /* 0x0F */ +// printf("SEEK-e: fddst=%02X\n", fddst[uptr->u6]); + if (isbc208_dev.dctrl & DEBUG_flow) + printf("isbc208_svc: FDC seek: disk=%d cyl=%d fddst=%02X\n", drv, i8272_w2, fddst[uptr->u6]); + if ((fddst[uptr->u6] & RDY) == 0) { /* Not ready? */ + i8272_r0 = IC_ABNORM + NR + hed + drv; /* error*/ + i8272_r3 = fddst[uptr->u6]; + if (isbc208_dev.dctrl & DEBUG_flow) + printf("isbc208_svc: FDC seek: Not Ready\n"); + } else if (i8272_w2 >= maxcyl[uptr->u6]) { + i8272_r0 = IC_ABNORM + RDY + hed + drv; /* seek error*/ + if (isbc208_dev.dctrl & DEBUG_flow) + printf("isbc208_svc: FDC seek: Invalid Cylinder %d\n", i8272_w2); + } else { + i8272_r0 |= SE + hed + drv; /* command done - no error */ + cyl = i8272_w2; /* new cylinder number */ + if (cyl == 0) { /* if cyl 0, set flag */ + fddst[drv] |= T0; /* set T0 status flag */ + i8272_r3 |= T0; + } else { + fddst[drv] &= ~T0; /* clear T0 status flag */ + i8272_r3 &= ~T0; + } + } + i8272_r1 = 0; + i8272_r2 = 0; + i8272_msr &= ~(RQM + DIO + CB + hed + drv); /* execution phase done*/ + i8272_msr |= RQM; /* enter command phase */ + rsp = wsp = 0; /* reset indexes */ +// set_irq(SBC208_INT); /* set interrupt */ +// printf("SEEK-x: fddst=%02X\n", fddst[uptr->u6]); + break; + default: + i8272_msr &= ~(RQM + DIO + CB); /* execution phase done*/ + i8272_msr |= RQM; /* enter command phase */ + i8272_r0 = IC_INVC + hed + drv; /* set bad command error */ + i8272_r1 = 0; + i8272_r2 = 0; + rsp = wsp = 0; /* reset indexes */ + break; + } + pcmd = cmd; /* save for result phase */ + cmd = 0; /* reset command */ + if (isbc208_dev.dctrl & DEBUG_flow) + printf("isbc208_svc: Exit: RSLT0 msr=%02X ST0=%02X ST1=%02X ST2=%02X ST3=%02X\n", + i8272_msr, i8272_r0, i8272_r1, i8272_r2, i8272_r3); + } + sim_activate (&isbc208_unit[uptr->u6], isbc208_unit[uptr->u6].wait); + return SCPE_OK; +} + +// read/write FDC data register +int32 isbc208_r11(int32 io, int32 data) +{ + if (io == 0) { /* read FDC data register */ + wsp = 0; /* clear write stack index */ + switch (rsp) { /* read from next stack register */ + case 0: + if (isbc208_dev.dctrl & DEBUG_reg) { + printf("i8272_r1 read as %02X\n", i8272_r1); + printf("i8272_r3 read as %02X\n", i8272_r3); + } + rsp++; /* step read stack index */ + clr_irq(SBC208_INT); /* clear interrupt */ + if (pcmd == SENDRV) { + i8272_msr = RQM; /* result phase SENDRV done */ + return i8272_r1; // SENDRV return ST1 + } + return i8272_r0; /* ST0 */ + case 1: + if (isbc208_dev.dctrl & DEBUG_reg) + printf("i8272_r2 read as %02X\n", i8272_r2); + rsp++; /* step read stack index */ + if (pcmd == SENINT) { + i8272_msr = RQM; /* result phase SENINT done */ + return cyl; // SENINT return current cylinder + } + return i8272_r1; /* ST1 */ + case 2: + if (isbc208_dev.dctrl & DEBUG_reg) + printf("i8272_r3 read as %02X\n", i8272_r3); + rsp++; /* step read stack index */ + return i8272_r2; /* ST2 */ + case 3: + if (isbc208_dev.dctrl & DEBUG_reg) + printf("i8272_w2 read as %02X\n", i8272_w2); + rsp++; /* step read stack index */ + return i8272_w2; /* C - cylinder */ + case 4: + if (isbc208_dev.dctrl & DEBUG_reg) + printf("i8272_w3 read as %02X\n", i8272_w3); + rsp++; /* step read stack index */ + return i8272_w3; /* H - head */ + case 5: + if (isbc208_dev.dctrl & DEBUG_reg) + printf("i8272_w4 read as %02X\n", i8272_w4); + rsp++; /* step read stack index */ + return i8272_w4; /* R - sector */ + case 6: + if (isbc208_dev.dctrl & DEBUG_reg) + printf("i8272_w5 read as %02X\n", i8272_w5); + i8272_msr = RQM; /* result phase ALL OTHERS done */ + return i8272_w5; /* N - sector size*/ + } + } else { /* write FDC data register */ + rsp = 0; /* clear read stack index */ + switch (wsp) { /* write to next stack register */ + case 0: + i8272_w0 = data; /* rws = MT + MFM + SK + cmd */ + cmd = data & 0x1F; /* save the current command */ + if (isbc208_dev.dctrl & DEBUG_reg) + printf("i8272_w0 set to %02X\n", data); + if (cmd == SENINT) { + i8272_msr = CB; /* command phase SENINT done */ + return 0; + } + wsp++; /* step write stack index */ + break; + case 1: + i8272_w1 = data; /* rws = hed + drv */ + if (cmd != SPEC) + drv = data & 0x03; + if (isbc208_dev.dctrl & DEBUG_reg) + printf("i8272_w1 set to %02X\n", data); + if (cmd == HOME || cmd == SENDRV || cmd == READID) { + i8272_msr = CB + hed + drv; /* command phase HOME, READID and SENDRV done */ + return 0; + } + wsp++; /* step write stack index */ + break; + case 2: + i8272_w2 = data; /* rws = C */ + if (isbc208_dev.dctrl & DEBUG_reg) + printf("i8272_w2 set to %02X\n", data); + if (cmd == SPEC || cmd == SEEK) { + i8272_msr = CB + hed + drv; /* command phase SPECIFY and SEEK done */ + return 0; + } + wsp++; /* step write stack index */ + break; + case 3: + i8272_w3 = data; /* rw = H */ + hed = data; + wsp++; /* step write stack index */ + if (isbc208_dev.dctrl & DEBUG_reg) + printf("i8272_w3 set to %02X\n", data); + break; + case 4: + i8272_w4 = data; /* rw = R */ + sec = data; + wsp++; /* step write stack index */ + if (isbc208_dev.dctrl & DEBUG_reg) + printf("i8272_w4 set to %02X\n", data); + break; + case 5: + i8272_w5 = data; /* rw = N */ + if (isbc208_dev.dctrl & DEBUG_reg) + printf("i8272_w5 set to %02X\n", data); + if (cmd == FMTTRK) { + i8272_msr = CB + hed + drv; /* command phase FMTTRK done */ + return 0; + } + wsp++; /* step write stack index */ + break; + case 6: + i8272_w6 = data; /* rw = last sector number */ + wsp++; /* step write stack index */ + if (isbc208_dev.dctrl & DEBUG_reg) + printf("i8272_w6 set to %02X\n", data); + break; + case 7: + i8272_w7 = data; /* rw = gap length */ + wsp++; /* step write stack index */ + if (isbc208_dev.dctrl & DEBUG_reg) + printf("i8272_w7 set to %02X\n", data); + break; + case 8: + i8272_w8 = data; /* rw = bytes to transfer */ + if (isbc208_dev.dctrl & DEBUG_reg) + printf("i8272_w8 set to %02X\n", data); + if (cmd == READ || cmd == WRITE) + i8272_msr = CB + hed + drv; /* command phase all others done */ + break; + } + return 0; + } +} + +/* Reset routine */ + +t_stat isbc208_reset (DEVICE *dptr) +{ + reg_dev(isbc208_r0, SBC208_BASE + 0); + reg_dev(isbc208_r1, SBC208_BASE + 1); + reg_dev(isbc208_r2, SBC208_BASE + 2); + reg_dev(isbc208_r3, SBC208_BASE + 3); + reg_dev(isbc208_r4, SBC208_BASE + 4); + reg_dev(isbc208_r5, SBC208_BASE + 5); + reg_dev(isbc208_r6, SBC208_BASE + 6); + reg_dev(isbc208_r7, SBC208_BASE + 7); + reg_dev(isbc208_r8, SBC208_BASE + 8); + reg_dev(isbc208_r9, SBC208_BASE + 9); + reg_dev(isbc208_rA, SBC208_BASE + 10); + reg_dev(isbc208_rB, SBC208_BASE + 11); + reg_dev(isbc208_rC, SBC208_BASE + 12); + reg_dev(isbc208_rD, SBC208_BASE + 13); + reg_dev(isbc208_rE, SBC208_BASE + 14); + reg_dev(isbc208_rF, SBC208_BASE + 15); + reg_dev(isbc208_r10, SBC208_BASE + 16); + reg_dev(isbc208_r11, SBC208_BASE + 17); + reg_dev(isbc208_r12, SBC208_BASE + 18); + reg_dev(isbc208_r13, SBC208_BASE + 19); + reg_dev(isbc208_r14, SBC208_BASE + 20); + reg_dev(isbc208_r15, SBC208_BASE + 21); + if ((isbc208_dev.flags & DEV_DIS) == 0) + isbc208_reset1(); + return SCPE_OK; +} + +void isbc208_reset1 (void) +{ + int32 i; + UNIT *uptr; + static int flag = 1; + + if (flag) printf("iSBC 208: Initializing\n"); + for (i = 0; i < FDD_NUM; i++) { /* handle all units */ + uptr = isbc208_dev.units + i; + if (uptr->capac == 0) { /* if not configured */ +// printf(" SBC208%d: Not configured\n", i); +// if (flag) { +// printf(" ALL: \"set isbc208 en\"\n"); +// printf(" EPROM: \"att isbc2080 \"\n"); +// flag = 0; +// } + uptr->capac = 0; /* initialize unit */ + uptr->u3 = 0; + uptr->u4 = 0; + uptr->u5 = 0; + uptr->u6 = i; /* unit number - only set here! */ + fddst[i] = WP + T0 + i; /* initial drive status */ + uptr->flags |= UNIT_WPMODE; /* set WP in unit flags */ + sim_activate (&isbc208_unit[uptr->u6], isbc208_unit[uptr->u6].wait); + } else { + fddst[i] = RDY + WP + T0 + i; /* initial attach drive status */ +// printf(" SBC208%d: Configured, Attached to %s\n", i, uptr->filename); + } + } + i8237_r8 = 0; /* status */ + i8237_r9 = 0; /* command */ + i8237_rB = 0x0F; /* mask */ + i8237_rC = 0; /* request */ + i8237_rD = 0; /* first/last FF */ + i8272_msr = RQM; /* 8272 ready for start of command */ + rsp = wsp = 0; /* reset indexes */ + cmd = 0; /* clear command */ + if (flag) { + printf(" 8237 Reset\n"); + printf(" 8272 Reset\n"); + } + flag = 0; +} + +/* isbc208 attach - attach an .IMG file to a FDD */ + +t_stat isbc208_attach (UNIT *uptr, char *cptr) +{ + t_stat r; + FILE *fp; + int32 i, c = 0; + long flen; + + if (isbc208_dev.dctrl & DEBUG_flow) + printf(" isbc208_attach: Entered with cptr=%s\n", cptr); + if ((r = attach_unit (uptr, cptr)) != SCPE_OK) { + printf(" isbc208_attach: Attach error\n"); + return r; + } + fp = fopen(uptr->filename, "rb"); + if (fp == NULL) { + printf(" Unable to open disk img file %s\n", uptr->filename); + printf(" No disk image loaded!!!\n"); + } else { + printf("iSBC 208: Attach\n"); + fseek(fp, 0, SEEK_END); /* size disk image */ + flen = ftell(fp); + fseek(fp, 0, SEEK_SET); + if (isbc208_buf[uptr->u6] == NULL) { /* no buffer allocated */ + isbc208_buf[uptr->u6] = malloc(flen); + if (isbc208_buf[uptr->u6] == NULL) { + printf(" iSBC208_attach: Malloc error\n"); + return SCPE_MEM; + } + } + uptr->capac = flen; + i = 0; + c = fgetc(fp); // copy disk image into buffer + while (c != EOF) { + *(isbc208_buf[uptr->u6] + i++) = c & 0xFF; + c = fgetc(fp); + } + fclose(fp); + fddst[uptr->u6] |= RDY; /* set unit ready */ + if (flen == 368640) { /* 5" 360K DSDD */ + maxcyl[uptr->u6] = 40; + fddst[uptr->u6] |= TS; // two sided + } + else if (flen == 737280) { /* 5" 720K DSQD / 3.5" 720K DSDD */ + maxcyl[uptr->u6] = 80; + fddst[uptr->u6] |= TS; // two sided + } + else if (flen == 1228800) { /* 5" 1.2M DSHD */ + maxcyl[uptr->u6] = 80; + fddst[uptr->u6] |= TS; // two sided + } + else if (flen == 1474560) { /* 3.5" 1.44M DSHD */ + maxcyl[uptr->u6] = 80; + fddst[uptr->u6] |= TS; // two sided + } + printf(" Drive-%d: %d bytes of disk image %s loaded, fddst=%02X\n", + uptr->u6, i, uptr->filename, fddst[uptr->u6]); + } + if (isbc208_dev.dctrl & DEBUG_flow) + printf(" iSBC208_attach: Done\n"); + return SCPE_OK; +} + +/* isbc208 set mode = 8- or 16-bit data bus */ + +t_stat isbc208_set_mode (UNIT *uptr, int32 val, char *cptr, void *desc) +{ + UNIT *uptr1; + + if (isbc208_dev.dctrl & DEBUG_flow) + printf(" isbc208_set_mode: Entered with val=%08XH uptr->flags=%08X\n", + val, uptr->flags); + if (val & UNIT_WPMODE) { /* write protect */ + fddst[uptr->u6] |= WP; + uptr->flags |= val; + } else { /* read write */ + fddst[uptr->u6] &= ~WP; + uptr->flags &= ~val; + } +// printf("fddst[%d]=%02XH uptr->flags=%08X\n", uptr->u6, fddst[uptr->u6], uptr->flags); + if (isbc208_dev.dctrl & DEBUG_flow) + printf(" isbc208_set_mode: Done\n"); + return SCPE_OK; +} + +/* I/O instruction handlers, called from the CPU module when an + IN or OUT instruction is issued. + + Each function is passed an 'io' flag, where 0 means a read from + the port, and 1 means a write to the port. On input, the actual + input is passed as the return value, on output, 'data' is written + to the device. +*/ + +int32 isbc208_r0(int32 io, int32 data) +{ + if (io == 0) { /* read current address CH 0 */ + if (i8237_rD) { /* high byte */ + i8237_rD = 0; + if (isbc208_dev.dctrl & DEBUG_reg) + printf("i8237_r0(H) read as %04X\n", i8237_r0); + return (i8237_r0 >> 8); + } else { /* low byte */ + i8237_rD++; + if (isbc208_dev.dctrl & DEBUG_reg) + printf("i8237_r0(L) read as %04X\n", i8237_r0); + return (i8237_r0 & 0xFF); + } + } else { /* write base & current address CH 0 */ + if (i8237_rD) { /* high byte */ + i8237_rD = 0; + i8237_r0 |= (data << 8); + if (isbc208_dev.dctrl & DEBUG_reg) + printf("i8237_r0(H) set to %04X\n", i8237_r0); + } else { /* low byte */ + i8237_rD++; + i8237_r0 = data & 0xFF; + if (isbc208_dev.dctrl & DEBUG_reg) + printf("i8237_r0(L) set to %04X\n", i8237_r0); + } + return 0; + } +} + +int32 isbc208_r1(int32 io, int32 data) +{ + if (io == 0) { /* read current word count CH 0 */ + if (i8237_rD) { /* high byte */ + i8237_rD = 0; + if (isbc208_dev.dctrl & DEBUG_reg) + printf("i8237_r1(H) read as %04X\n", i8237_r1); + return (i8237_r1 >> 8); + } else { /* low byte */ + i8237_rD++; + if (isbc208_dev.dctrl & DEBUG_reg) + printf("i8237_r1(L) read as %04X\n", i8237_r1); + return (i8237_r1 & 0xFF); + } + } else { /* write base & current address CH 0 */ + if (i8237_rD) { /* high byte */ + i8237_rD = 0; + i8237_r1 |= (data << 8); + if (isbc208_dev.dctrl & DEBUG_reg) + printf("i8237_r1(H) set to %04X\n", i8237_r1); + } else { /* low byte */ + i8237_rD++; + i8237_r1 = data & 0xFF; + if (isbc208_dev.dctrl & DEBUG_reg) + printf("i8237_r1(L) set to %04X\n", i8237_r1); + } + return 0; + } +} + +int32 isbc208_r2(int32 io, int32 data) +{ + if (io == 0) { /* read current address CH 1 */ + if (i8237_rD) { /* high byte */ + i8237_rD = 0; + if (isbc208_dev.dctrl & DEBUG_reg) + printf("i8237_r2(H) read as %04X\n", i8237_r2); + return (i8237_r2 >> 8); + } else { /* low byte */ + i8237_rD++; + if (isbc208_dev.dctrl & DEBUG_reg) + printf("i8237_r2(L) read as %04X\n", i8237_r2); + return (i8237_r2 & 0xFF); + } + } else { /* write base & current address CH 1 */ + if (i8237_rD) { /* high byte */ + i8237_rD = 0; + i8237_r2 |= (data << 8); + if (isbc208_dev.dctrl & DEBUG_reg) + printf("i8237_r2(H) set to %04X\n", i8237_r2); + } else { /* low byte */ + i8237_rD++; + i8237_r2 = data & 0xFF; + if (isbc208_dev.dctrl & DEBUG_reg) + printf("i8237_r2(L) set to %04X\n", i8237_r2); + } + return 0; + } +} + +int32 isbc208_r3(int32 io, int32 data) +{ + if (io == 0) { /* read current word count CH 1 */ + if (i8237_rD) { /* high byte */ + i8237_rD = 0; + if (isbc208_dev.dctrl & DEBUG_reg) + printf("i8237_r3(H) read as %04X\n", i8237_r3); + return (i8237_r3 >> 8); + } else { /* low byte */ + i8237_rD++; + if (isbc208_dev.dctrl & DEBUG_reg) + printf("i8237_r3(L) read as %04X\n", i8237_r3); + return (i8237_r3 & 0xFF); + } + } else { /* write base & current address CH 1 */ + if (i8237_rD) { /* high byte */ + i8237_rD = 0; + i8237_r3 |= (data << 8); + if (isbc208_dev.dctrl & DEBUG_reg) + printf("i8237_r3(H) set to %04X\n", i8237_r3); + } else { /* low byte */ + i8237_rD++; + i8237_r3 = data & 0xFF; + if (isbc208_dev.dctrl & DEBUG_reg) + printf("i8237_r3(L) set to %04X\n", i8237_r3); + } + return 0; + } +} + +int32 isbc208_r4(int32 io, int32 data) +{ + if (io == 0) { /* read current address CH 2 */ + if (i8237_rD) { /* high byte */ + i8237_rD = 0; + if (isbc208_dev.dctrl & DEBUG_reg) + printf("i8237_r4(H) read as %04X\n", i8237_r4); + return (i8237_r4 >> 8); + } else { /* low byte */ + i8237_rD++; + if (isbc208_dev.dctrl & DEBUG_reg) + printf("i8237_r4(L) read as %04X\n", i8237_r4); + return (i8237_r4 & 0xFF); + } + } else { /* write base & current address CH 2 */ + if (i8237_rD) { /* high byte */ + i8237_rD = 0; + i8237_r4 |= (data << 8); + if (isbc208_dev.dctrl & DEBUG_reg) + printf("i8237_r4(H) set to %04X\n", i8237_r4); + } else { /* low byte */ + i8237_rD++; + i8237_r4 = data & 0xFF; + if (isbc208_dev.dctrl & DEBUG_reg) + printf("i8237_r4(L) set to %04X\n", i8237_r4); + } + return 0; + } +} + +int32 isbc208_r5(int32 io, int32 data) +{ + if (io == 0) { /* read current word count CH 2 */ + if (i8237_rD) { /* high byte */ + i8237_rD = 0; + if (isbc208_dev.dctrl & DEBUG_reg) + printf("i8237_r5(H) read as %04X\n", i8237_r5); + return (i8237_r5 >> 8); + } else { /* low byte */ + i8237_rD++; + if (isbc208_dev.dctrl & DEBUG_reg) + printf("i8237_r5(L) read as %04X\n", i8237_r5); + return (i8237_r5 & 0xFF); + } + } else { /* write base & current address CH 2 */ + if (i8237_rD) { /* high byte */ + i8237_rD = 0; + i8237_r5 |= (data << 8); + if (isbc208_dev.dctrl & DEBUG_reg) + printf("i8237_r5(H) set to %04X\n", i8237_r5); + } else { /* low byte */ + i8237_rD++; + i8237_r5 = data & 0xFF; + if (isbc208_dev.dctrl & DEBUG_reg) + printf("i8237_r5(L) set to %04X\n", i8237_r5); + } + return 0; + } +} + +int32 isbc208_r6(int32 io, int32 data) +{ + if (io == 0) { /* read current address CH 3 */ + if (i8237_rD) { /* high byte */ + i8237_rD = 0; + if (isbc208_dev.dctrl & DEBUG_reg) + printf("i8237_r6(H) read as %04X\n", i8237_r6); + return (i8237_r6 >> 8); + } else { /* low byte */ + i8237_rD++; + if (isbc208_dev.dctrl & DEBUG_reg) + printf("i8237_r6(L) read as %04X\n", i8237_r6); + return (i8237_r6 & 0xFF); + } + } else { /* write base & current address CH 3 */ + if (i8237_rD) { /* high byte */ + i8237_rD = 0; + i8237_r6 |= (data << 8); + if (isbc208_dev.dctrl & DEBUG_reg) + printf("i8237_r6(H) set to %04X\n", i8237_r6); + } else { /* low byte */ + i8237_rD++; + i8237_r6 = data & 0xFF; + if (isbc208_dev.dctrl & DEBUG_reg) + printf("i8237_r6(L) set to %04X\n", i8237_r6); + } + return 0; + } +} + +int32 isbc208_r7(int32 io, int32 data) +{ + if (io == 0) { /* read current word count CH 3 */ + if (i8237_rD) { /* high byte */ + i8237_rD = 0; + if (isbc208_dev.dctrl & DEBUG_reg) + printf("i8237_r7(H) read as %04X\n", i8237_r7); + return (i8237_r7 >> 8); + } else { /* low byte */ + i8237_rD++; + if (isbc208_dev.dctrl & DEBUG_reg) + printf("i8237_r7(L) read as %04X\n", i8237_r7); + return (i8237_r7 & 0xFF); + } + } else { /* write base & current address CH 3 */ + if (i8237_rD) { /* high byte */ + i8237_rD = 0; + i8237_r7 |= (data << 8); + if (isbc208_dev.dctrl & DEBUG_reg) + printf("i8237_r7(H) set to %04X\n", i8237_r7); + } else { /* low byte */ + i8237_rD++; + i8237_r7 = data & 0xFF; + if (isbc208_dev.dctrl & DEBUG_reg) + printf("i8237_r7(L) set to %04X\n", i8237_r7); + } + return 0; + } +} + +int32 isbc208_r8(int32 io, int32 data) +{ + if (io == 0) { /* read status register */ + if (isbc208_dev.dctrl & DEBUG_reg) + printf("i8237_r8 (status) read as %02X\n", i8237_r8); + return (i8237_r8); + } else { /* write command register */ + i8237_r9 = data & 0xFF; + if (isbc208_dev.dctrl & DEBUG_reg) + printf("i8237_r9 (command) set to %02X\n", i8237_r9); + return 0; + } +} + +int32 isbc208_r9(int32 io, int32 data) +{ + if (io == 0) { + if (isbc208_dev.dctrl & DEBUG_reg) + printf("Illegal read of isbc208_r9\n"); + return 0; + } else { /* write request register */ + i8237_rC = data & 0xFF; + if (isbc208_dev.dctrl & DEBUG_reg) + printf("i8237_rC (request) set to %02X\n", i8237_rC); + return 0; + } +} + +int32 isbc208_rA(int32 io, int32 data) +{ + if (io == 0) { + if (isbc208_dev.dctrl & DEBUG_reg) + printf("Illegal read of isbc208_rA\n"); + return 0; + } else { /* write single mask register */ + switch(data & 0x03) { + case 0: + if (data & 0x04) + i8237_rB |= 1; + else + i8237_rB &= ~1; + break; + case 1: + if (data & 0x04) + i8237_rB |= 2; + else + i8237_rB &= ~2; + break; + case 2: + if (data & 0x04) + i8237_rB |= 4; + else + i8237_rB &= ~4; + break; + case 3: + if (data & 0x04) + i8237_rB |= 8; + else + i8237_rB &= ~8; + break; + } + if (isbc208_dev.dctrl & DEBUG_reg) + printf("i8237_rB (mask) set to %02X\n", i8237_rB); + return 0; + } +} + +int32 isbc208_rB(int32 io, int32 data) +{ + if (io == 0) { + if (isbc208_dev.dctrl & DEBUG_reg) + printf("Illegal read of isbc208_rB\n"); + return 0; + } else { /* write mode register */ + i8237_rA = data & 0xFF; + if (isbc208_dev.dctrl & DEBUG_reg) + printf("i8237_rA (mode) set to %02X\n", i8237_rA); + return 0; + } +} + +int32 isbc208_rC(int32 io, int32 data) +{ + if (io == 0) { + if (isbc208_dev.dctrl & DEBUG_reg) + printf("Illegal read of isbc208_rC\n"); + return 0; + } else { /* clear byte pointer FF */ + i8237_rD = 0; + if (isbc208_dev.dctrl & DEBUG_reg) + printf("i8237_rD (FF) cleared\n"); + return 0; + } +} + +int32 isbc208_rD(int32 io, int32 data) +{ + if (io == 0) { /* read temporary register */ + if (isbc208_dev.dctrl & DEBUG_reg) + printf("Illegal read of isbc208_rD\n"); + return 0; + } else { /* master clear */ + isbc208_reset1(); + if (isbc208_dev.dctrl & DEBUG_reg) + printf("i8237 master clear\n"); + return 0; + } +} + +int32 isbc208_rE(int32 io, int32 data) +{ + if (io == 0) { + if (isbc208_dev.dctrl & DEBUG_reg) + printf("Illegal read of isbc208_rE\n"); + return 0; + } else { /* clear mask register */ + i8237_rB = 0; + if (isbc208_dev.dctrl & DEBUG_reg) + printf("i8237_rB (mask) cleared\n"); + return 0; + } +} + +int32 isbc208_rF(int32 io, int32 data) +{ + if (io == 0) { + if (isbc208_dev.dctrl & DEBUG_reg) + printf("Illegal read of isbc208_rF\n"); + return 0; + } else { /* write all mask register bits */ + i8237_rB = data & 0x0F; + if (isbc208_dev.dctrl & DEBUG_reg) + printf("i8237_rB (mask) set to %02X\n", i8237_rB); + return 0; + } +} + +int32 isbc208_r10(int32 io, int32 data) +{ + if (io == 0) { /* read FDC status register */ + if (isbc208_dev.dctrl & DEBUG_reg) + printf("i8272_msr read as %02X\n", i8272_msr); + return i8272_msr; + } else { + if (isbc208_dev.dctrl & DEBUG_reg) + printf("Illegal write to isbc208_r10\n"); + return 0; + } +} + +int32 isbc208_r12(int32 io, int32 data) +{ + if (io == 0) { /* read interrupt status */ + if (isbc208_dev.dctrl & DEBUG_reg) + printf("isbc208_r12 read as %02X\n", isbc208_i); + return (isbc208_i); + } else { /* write controller auxillary port */ + isbc208_a = data & 0xFF; + if (isbc208_dev.dctrl & DEBUG_reg) + printf("isbc208_r12 set to %02X\n", isbc208_a); + return 0; + } +} + +int32 isbc208_r13(int32 io, int32 data) +{ + if (io == 0) { + if (isbc208_dev.dctrl & DEBUG_reg) + printf("Illegal read of isbc208_r13\n"); + return 0; + } else { /* reset controller */ + isbc208_reset1(); + if (isbc208_dev.dctrl & DEBUG_reg) + printf("isbc208_r13 controller reset\n"); + return 0; + } +} + +int32 isbc208_r14(int32 io, int32 data) +{ + if (io == 0) { + if (isbc208_dev.dctrl & DEBUG_reg) + printf("Illegal read of isbc208_r14\n"); + return 0; + } else { /* Low-Byte Segment Address Register */ + isbc208_sr = data & 0xFF; + if (isbc208_dev.dctrl & DEBUG_reg) + printf("isbc208_sr(L) set to %02X\n", data & 0xFF); + return 0; + } +} + +int32 isbc208_r15(int32 io, int32 data) +{ + if (io == 0) { + if (isbc208_dev.dctrl & DEBUG_reg) + printf("Illegal read of isbc208_r15\n"); + return 0; + } else { /* High-Byte Segment Address Register */ + isbc208_sr |= data << 8; + if (isbc208_dev.dctrl & DEBUG_reg) + printf("isbc208_sr(H) set to %02X\n", data); + return 0; + } +} + +/* end of isbc208.c */ diff --git a/MDS-800/common/multibus.c b/MDS-800/common/multibus.c new file mode 100644 index 00000000..6821103a --- /dev/null +++ b/MDS-800/common/multibus.c @@ -0,0 +1,288 @@ +/* multibus.c: Multibus I simulator + + Copyright (c) 2010, William A. Beech + + Permission is hereby granted, free of charge, to any person obtaining a + copy of this software and associated documentation files (the "Software"), + to deal in the Software without restriction, including without limitation + the rights to use, copy, modify, merge, publish, distribute, sublicense, + and/or sell copies of the Software, and to permit persons to whom the + Software is furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + WILLIAM A. BEECH BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + Except as contained in this notice, the name of William A. Beech shall not be + used in advertising or otherwise to promote the sale, use or other dealings + in this Software without prior written authorization from William A. Beech. + + This software was written by Bill Beech, Dec 2010, to allow emulation of Multibus + Computer Systems. + + ?? ??? 10 - Original file. + 16 Dec 12 - Modified to use isbc_80_10.cfg file to set base and size. +*/ + +#include "system_defs.h" + +#define SET_XACK(VAL) (xack = VAL) + +int32 mbirq = 0; /* set no multibus interrupts */ + +/* function prototypes */ + +t_stat multibus_svc(UNIT *uptr); +t_stat multibus_reset(DEVICE *dptr); +void set_irq(int32 int_num); +void clr_irq(int32 int_num); +int32 nulldev(int32 io, int32 data); +int32 reg_dev(int32 (*routine)(), int32 port); +t_stat multibus_reset (DEVICE *dptr); +int32 multibus_get_mbyte(int32 addr); +int32 multibus_get_mword(int32 addr); +void multibus_put_mbyte(int32 addr, int32 val); +void multibus_put_mword(int32 addr, int32 val); + +/* external function prototypes */ + +extern t_stat SBC_reset(DEVICE *dptr); /* reset the iSBC80/10 emulator */ +extern int32 isbc064_get_mbyte(int32 addr); +extern void isbc064_put_mbyte(int32 addr, int32 val); +extern void set_cpuint(int32 int_num); +extern t_stat SBC_reset (DEVICE *dptr); +extern t_stat isbc064_reset (DEVICE *dptr); +extern t_stat isbc208_reset (DEVICE *dptr); + +/* external globals */ + +extern uint8 xack; /* XACK signal */ +extern int32 int_req; /* i8080 INT signal */ + +/* multibus Standard SIMH Device Data Structures */ + +UNIT multibus_unit = { + UDATA (&multibus_svc, 0, 0), 20 +}; + +REG multibus_reg[] = { + { HRDATA (MBIRQ, mbirq, 32) }, + { HRDATA (XACK, xack, 8) } +}; + +DEBTAB multibus_debug[] = { + { "ALL", DEBUG_all }, + { "FLOW", DEBUG_flow }, + { "READ", DEBUG_read }, + { "WRITE", DEBUG_write }, + { "LEV1", DEBUG_level1 }, + { "LEV2", DEBUG_level2 }, + { NULL } +}; + +DEVICE multibus_dev = { + "MBIRQ", //name + &multibus_unit, //units + multibus_reg, //registers + NULL, //modifiers + 1, //numunits + 16, //aradix + 32, //awidth + 1, //aincr + 16, //dradix + 8, //dwidth + NULL, //examine + NULL, //deposit + &multibus_reset, //reset + NULL, //boot + NULL, //attach + NULL, //detach + NULL, //ctxt + DEV_DEBUG, //flags + 0, //dctrl + multibus_debug, //debflags + NULL, //msize + NULL //lname +}; + +/* Service routines to handle simulator functions */ + +/* service routine - actually does the simulated interrupts */ + +t_stat multibus_svc(UNIT *uptr) +{ + switch (mbirq) { + case INT_1: + set_cpuint(INT_R); + clr_irq(SBC208_INT); /***** bad, bad, bad! */ +// printf("multibus_svc: mbirq=%04X int_req=%04X\n", mbirq, int_req); + break; + default: +// printf("multibus_svc: default mbirq=%04X\n", mbirq); + break; + } + sim_activate (&multibus_unit, multibus_unit.wait); /* continue poll */ +} + +/* Reset routine */ + +t_stat multibus_reset(DEVICE *dptr) +{ + SBC_reset(NULL); + isbc064_reset(NULL); + isbc208_reset(NULL); + printf(" Multibus: Reset\n"); + sim_activate (&multibus_unit, multibus_unit.wait); /* activate unit */ + return SCPE_OK; +} + +void set_irq(int32 int_num) +{ + mbirq |= int_num; +// printf("set_irq: int_num=%04X mbirq=%04X\n", int_num, mbirq); +} + +void clr_irq(int32 int_num) +{ + mbirq &= ~int_num; +// printf("clr_irq: int_num=%04X mbirq=%04X\n", int_num, mbirq); +} + +/* This is the I/O configuration table. There are 256 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}, /* 000H */ +{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 004H */ +{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 008H */ +{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 00CH */ +{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 010H */ +{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 014H */ +{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 018H */ +{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 01CH */ +{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 020H */ +{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 024H */ +{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 028H */ +{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 02CH */ +{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 030H */ +{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 034H */ +{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 038H */ +{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 03CH */ +{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 040H */ +{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 044H */ +{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 048H */ +{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 04CH */ +{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 050H */ +{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 054H */ +{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 058H */ +{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 05CH */ +{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 060H */ +{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 064H */ +{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 068H */ +{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 06CH */ +{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 070H */ +{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 074H */ +{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 078H */ +{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 07CH */ +{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 080H */ +{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 084H */ +{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 088H */ +{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 08CH */ +{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 090H */ +{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 094H */ +{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 098H */ +{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 09CH */ +{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 0A0H */ +{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 0A4H */ +{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 0A8H */ +{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 0A0H */ +{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 0B0H */ +{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 0B4H */ +{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 0B8H */ +{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 0B0H */ +{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 0C0H */ +{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 0C4H */ +{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 0C8H */ +{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 0CCH */ +{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 0D0H */ +{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 0D4H */ +{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 0D8H */ +{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 0DCH */ +{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 0E0H */ +{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 0E4H */ +{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 0E8H */ +{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 0ECH */ +{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 0F0H */ +{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 0F4H */ +{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 0F8H */ +{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev} /* 0FCH */ +}; + +int32 nulldev(int32 flag, int32 data) +{ + SET_XACK(0); /* set no XACK */ + if (flag == 0) /* if we got here, no valid I/O device */ + return (0xFF); + return 0; +} + +int32 reg_dev(int32 (*routine)(), int32 port) +{ + if (dev_table[port].routine != &nulldev) { /* port already assigned */ +// printf("Multibus: I/O Port %02X is already assigned\n", port); + } else { +// printf("Port %02X is assigned\n", port); + dev_table[port].routine = routine; + } +} + +/* get a byte from memory */ + +int32 multibus_get_mbyte(int32 addr) +{ + SET_XACK(0); /* set no XACK */ +// printf("multibus_get_mbyte: Cleared XACK for %04X\n", addr); + return isbc064_get_mbyte(addr); +} + +/* get a word from memory */ + +int32 multibus_get_mword(int32 addr) +{ + int32 val; + + val = multibus_get_mbyte(addr); + val |= (multibus_get_mbyte(addr+1) << 8); + return val; +} + +/* put a byte to memory */ + +void multibus_put_mbyte(int32 addr, int32 val) +{ + SET_XACK(0); /* set no XACK */ +// printf("multibus_put_mbyte: Cleared XACK for %04X\n", addr); + isbc064_put_mbyte(addr, val); +// printf("multibus_put_mbyte: Done XACK=%dX\n", XACK); +} + +/* put a word to memory */ + +void multibus_put_mword(int32 addr, int32 val) +{ + multibus_put_mbyte(addr, val); + multibus_put_mbyte(addr+1, val << 8); +} + + diff --git a/MDS-800/common/pata.c b/MDS-800/common/pata.c new file mode 100644 index 00000000..5648bf5c --- /dev/null +++ b/MDS-800/common/pata.c @@ -0,0 +1,193 @@ +/* i8255.c: Intel i8255 PIO adapter + + Copyright (c) 2010, William A. Beech + + Permission is hereby granted, free of charge, to any person obtaining a + copy of this software and associated documentation files (the "Software"), + to deal in the Software without restriction, including without limitation + the rights to use, copy, modify, merge, publish, distribute, sublicense, + and/or sell copies of the Software, and to permit persons to whom the + Software is furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + WILLIAM A. BEECH BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + Except as contained in this notice, the name of William A. Beech shall not be + used in advertising or otherwise to promote the sale, use or other dealings + in this Software without prior written authorization from William A. Beech. + + These functions support a simulated i8255 interface device on an iSBC. + The device has threee physical 8-bit I/O ports which could be connected + to any parallel I/O device. + + All I/O is via programmed I/O. The i8255 has a control port (PIOS) + and three data ports (PIOA, PIOB, and PIOC). + + The simulated device supports a select from I/O space and two address lines. + The data ports are at the lower addresses and the control port is at + the highest. + + A write to the control port can configure the device: + + Control Word + +---+---+---+---+---+---+---+---+ + | D7 D6 D5 D4 D3 D2 D1 D0| + +---+---+---+---+---+---+---+---+ + + Group B + D0 Port C (lower) 1-Input, 0-Output + D1 Port B 1-Input, 0-Output + D2 Mode Selection 0-Mode 0, 1-Mode 1 + + Group A + D3 Port C (upper) 1-Input, 0-Output + D4 Port A 1-Input, 0-Output + D5-6 Mode Selection 00-Mode 0, 01-Mode 1, 1X-Mode 2 + + D7 Mode Set Flag 1=Active, 0=Bit Set + + Mode 0 - Basic Input/Output + Mode 1 - Strobed Input/Output + Mode 2 - Bidirectional Bus + + Bit Set - D7=0, D3:1 select port C bit, D0 1=set, 0=reset + + A read to the data ports gets the current port value, a write + to the data ports writes the character to the device. + + ?? ??? 10 - Original file. + 16 Dec 12 - Modified to use isbc_80_10.cfg file to set base and size. +*/ + +#include "system_defs.h" + +extern int32 reg_dev(int32 (*routine)(), int32 port); + +/* function prototypes */ + +t_stat pata_reset (DEVICE *dptr, int32 base); + +/* i8255 Standard I/O Data Structures */ + +UNIT pata_unit[] = { + { UDATA (0, 0, 0) } +}; + +REG pata_reg[] = { + { HRDATA (CONTROL0, pata_unit[0].u3, 8) }, + { HRDATA (PORTA0, pata_unit[0].u4, 8) }, + { HRDATA (PORTB0, pata_unit[0].u5, 8) }, + { HRDATA (PORTC0, pata_unit[0].u6, 8) }, + { NULL } +}; + +DEVICE pata_dev = { + "PATA", //name + pata_unit, //units + pata_reg, //registers + NULL, //modifiers + 1, //numunits + 16, //aradix + 32, //awidth + 1, //aincr + 16, //dradix + 8, //dwidth + NULL, //examine + NULL, //deposit +// &pata_reset, //reset + NULL, //reset + NULL, //boot + NULL, //attach + NULL, //detach + NULL, //ctxt + 0, //flags + 0, //dctrl + NULL, //debflags + NULL, //msize + NULL //lname +}; + +/* I/O instruction handlers, called from the CPU module when an + IN or OUT instruction is issued. +*/ + +int32 patas(int32 io, int32 data) +{ + int32 bit; + + if (io == 0) { /* read status port */ + return pata_unit[0].u3; + } else { /* write status port */ + if (data & 0x80) { /* mode instruction */ + pata_unit[0].u3 = data; + printf("PATA: 8255 Mode Instruction=%02X\n", data); + if (data & 0x64) + printf(" Mode 1 and 2 not yet implemented\n"); + } else { /* bit set */ + bit = (data & 0x0E) >> 1; /* get bit number */ + if (data & 0x01) { /* set bit */ + pata_unit[0].u6 |= (0x01 << bit); + } else { /* reset bit */ + pata_unit[0].u6 &= ~(0x01 << bit); + } + } + } + return 0; +} + +int32 pataa(int32 io, int32 data) +{ + if (io == 0) { /* read data port */ + return (pata_unit[0].u4); + } else { /* write data port */ + pata_unit[0].u4 = data; + printf("PATA: 8255 Port A = %02X\n", data); + } + return 0; +} + +int32 patab(int32 io, int32 data) +{ + if (io == 0) { /* read data port */ + return (pata_unit[0].u5); + } else { /* write data port */ + pata_unit[0].u5 = data; + printf("PATA: 8255 Port B = %02X\n", data); + } + return 0; +} + +int32 patac(int32 io, int32 data) +{ + if (io == 0) { /* read data port */ + return (pata_unit[0].u6); + } else { /* write data port */ + pata_unit[0].u6 = data; + printf("PATA: 8255 Port C = %02X\n", data); + } + return 0; +} + +/* Reset routine */ + +t_stat pata_reset (DEVICE *dptr, int32 base) +{ + pata_unit[0].u3 = 0x9B; /* control */ + pata_unit[0].u4 = 0xFF; /* Port A */ + pata_unit[0].u5 = 0xFF; /* Port B */ + pata_unit[0].u6 = 0xFF; /* Port C */ + reg_dev(pataa, base); + reg_dev(patab, base + 1); + reg_dev(patac, base + 2); + reg_dev(patas, base + 3); + printf(" PATA: Reset\n"); + return SCPE_OK; +} + diff --git a/MDS-800/makefile b/MDS-800/makefile new file mode 100644 index 00000000..4e65edcd --- /dev/null +++ b/MDS-800/makefile @@ -0,0 +1,1382 @@ +# +# This GNU make makefile has been tested on: +# Linux (x86 & Sparc & PPC) +# OS X +# Solaris (x86 & Sparc) (gcc and Sun C) +# OpenBSD +# NetBSD +# FreeBSD +# HP-UX +# AIX +# Windows (MinGW & cygwin) +# Linux x86 targeting Android (using agcc script) +# +# Android targeted builds should invoke GNU make with GCC=agcc on +# the command line. +# +# In general, the logic below will detect and build with the available +# features which the host build environment provides. +# +# Dynamic loading of libpcap is the preferred default behavior if pcap.h +# is available at build time. Support to statically linking against libpcap +# is deprecated and may be removed in the future. Static linking against +# libpcap can be enabled if GNU make is invoked with USE_NETWORK=1 on the +# command line. +# +# Some platforms may not have vendor supplied libpcap available. HP-UX is +# one such example. The packages which are available for this platform +# install include files and libraries in user specified directories. In +# order for this makefile to locate where these components may have been +# installed, gmake should be invoked with LPATH=/usr/lib:/usr/local/lib +# defined (adjusted as needed depending on where they may be installed). +# +# The default build will build compiler optimized binaries. +# If debugging is desired, then GNU make can be invoked with +# DEBUG=1 on the command line. +# +# OSX and other environments may have the LLVM (clang) compiler +# installed. If you want to build with the clang compiler, invoke +# make with GCC=clang. +# +# Internal ROM support can be disabled if GNU make is invoked with +# DONT_USE_ROMS=1 on the command line. +# +# Asynchronous I/O support can be disabled if GNU make is invoked with +# NOASYNCH=1 on the command line. +# +# For linting (or other code analyzers) make may be invoked similar to: +# +# make GCC=cppcheck CC_OUTSPEC= LDFLAGS= CFLAGS_G="--enable=all --template=gcc" CC_STD=--std=c99 +# +# CC Command (and platform available options). (Poor man's autoconf) +# +ifeq (old,$(shell gmake --version /dev/null 2>&1 | grep 'GNU Make' | awk '{ if ($$3 < "3.81") {print "old"} }')) + GMAKE_VERSION = $(shell gmake --version /dev/null 2>&1 | grep 'GNU Make' | awk '{ print $$3 }') + $(warning *** Warning *** GNU Make Version $(GMAKE_VERSION) is too old to) + $(warning *** Warning *** fully process this makefile) +endif +# building the pdp11, or any vax simulator could use networking support +BUILD_SINGLE := $(MAKECMDGOALS) $(BLANK_SUFFIX) +ifneq (,$(or $(findstring pdp11,$(MAKECMDGOALS)),$(findstring vax,$(MAKECMDGOALS)),$(findstring all,$(MAKECMDGOALS)))) + NETWORK_USEFUL = true + ifneq (,$(or $(findstring microvax1,$(MAKECMDGOALS)),$(findstring microvax2,$(MAKECMDGOALS)))) + VIDEO_USEFUL = true + endif + ifneq (,$(findstring all,$(MAKECMDGOALS))$(word 2,$(MAKECMDGOALS))) + BUILD_MULTIPLE = s + VIDEO_USEFUL = true + endif +else + ifeq ($(MAKECMDGOALS),) + # default target is all + NETWORK_USEFUL = true + VIDEO_USEFUL = true + BUILD_MULTIPLE = s + BUILD_SINGLE := all $(BUILD_SINGLE) + endif +endif +ifeq ($(WIN32),) #*nix Environments (&& cygwin) + ifeq ($(GCC),) + GCC = gcc + endif + OSTYPE = $(shell uname) + # OSNAME is used in messages to indicate the source of libpcap components + OSNAME = $(OSTYPE) + ifeq (SunOS,$(OSTYPE)) + TEST = /bin/test + else + TEST = test + endif + ifeq (CYGWIN,$(findstring CYGWIN,$(OSTYPE))) # uname returns CYGWIN_NT-n.n-ver + OSTYPE = cygwin + OSNAME = windows-build + endif + ifeq (,$(shell $(GCC) -v /dev/null 2>&1 | grep 'clang')) + GCC_VERSION = $(shell $(GCC) -v /dev/null 2>&1 | grep 'gcc version' | awk '{ print $$3 }') + COMPILER_NAME = GCC Version: $(GCC_VERSION) + ifeq (,$(GCC_VERSION)) + ifeq (SunOS,$(OSTYPE)) + ifneq (,$(shell $(GCC) -V 2>&1 | grep 'Sun C')) + SUNC_VERSION = $(shell $(GCC) -V 2>&1 | grep 'Sun C') + COMPILER_NAME = $(wordlist 2,10,$(SUNC_VERSION)) + endif + endif + ifeq (HP-UX,$(OSTYPE)) + ifneq (,$(shell what `which $(firstword $(GCC)) 2>&1`| grep -i compiler)) + COMPILER_NAME = $(strip $(shell what `which $(firstword $(GCC)) 2>&1` | grep -i compiler)) + endif + endif + endif + else + ifeq (Apple,$(shell $(GCC) -v /dev/null 2>&1 | grep 'Apple' | awk '{ print $$1 }')) + COMPILER_NAME = $(shell $(GCC) -v /dev/null 2>&1 | grep 'Apple' | awk '{ print $$1 " " $$2 " " $$3 " " $$4 }') + CLANG_VERSION = $(word 4,$(COMPILER_NAME)) + else + COMPILER_NAME = $(shell $(GCC) -v /dev/null 2>&1 | grep 'clang version' | awk '{ print $$1 " " $$2 " " $$3 }') + CLANG_VERSION = $(word 3,$(COMPILER_NAME)) + ifeq (,$(findstring .,$(CLANG_VERSION))) + COMPILER_NAME = $(shell $(GCC) -v /dev/null 2>&1 | grep 'clang version' | awk '{ print $$1 " " $$2 " " $$3 " " $$4 }') + CLANG_VERSION = $(word 4,$(COMPILER_NAME)) + endif + endif + endif + ifeq (git-repo,$(shell if $(TEST) -d ./.git; then echo git-repo; fi)) + ifeq (need-hooks,$(shell if $(TEST) ! -e ./.git/hooks/post-checkout; then echo need-hooks; fi)) + $(info *** Installing git hooks in local repository ***) + GIT_HOOKS += $(shell /bin/cp './Visual Studio Projects/git-hooks/post-commit' ./.git/hooks/) + GIT_HOOKS += $(shell /bin/cp './Visual Studio Projects/git-hooks/post-checkout' ./.git/hooks/) + GIT_HOOKS += $(shell /bin/cp './Visual Studio Projects/git-hooks/post-merge' ./.git/hooks/) + GIT_HOOKS += $(shell ./.git/hooks/post-checkout) + ifneq (,$(strip $(GIT_HOOKS))) + $(info *** Warning - Error installing git hooks *** $(GIT_HOOKS)) + endif + endif + endif + LTO_EXCLUDE_VERSIONS = + PCAPLIB = pcap + ifeq (agcc,$(findstring agcc,$(GCC))) # Android target build? + OS_CCDEFS = -D_GNU_SOURCE + ifeq (,$(NOASYNCH)) + OS_CCDEFS += -DSIM_ASYNCH_IO + endif + OS_LDFLAGS = -lm + else # Non-Android Builds + INCPATH:=/usr/include + LIBPATH:=/usr/lib + OS_CCDEFS = -D_GNU_SOURCE + GCC_OPTIMIZERS_CMD = $(GCC) -v --help 2>&1 + GCC_WARNINGS_CMD = $(GCC) -v --help 2>&1 + LD_ELF = $(shell echo | $(GCC) -E -dM - | grep __ELF__) + ifeq (Darwin,$(OSTYPE)) + OSNAME = OSX + LIBEXT = dylib + INCPATH:=$(shell $(GCC) -x c -v -E /dev/null 2>&1 | grep -A 10 '> search starts here' | grep '^ ' | grep -v 'framework directory' | tr -d '\n') + ifeq (incopt,$(shell if $(TEST) -d /opt/local/include; then echo incopt; fi)) + INCPATH += /opt/local/include + OS_CCDEFS += -I/opt/local/include + endif + ifeq (libopt,$(shell if $(TEST) -d /opt/local/lib; then echo libopt; fi)) + LIBPATH += /opt/local/lib + OS_LDFLAGS += -L/opt/local/lib + endif + ifeq (libXt,$(shell if $(TEST) -d /usr/X11/lib; then echo libXt; fi)) + LIBPATH += /usr/X11/lib + OS_LDFLAGS += -L/usr/X11/lib + endif + else + ifeq (Linux,$(OSTYPE)) + LIBPATH := $(sort $(foreach lib,$(shell /sbin/ldconfig -p | grep ' => /' | sed 's/^.* => //'),$(dir $(lib)))) + LIBEXT = so + else + ifeq (SunOS,$(OSTYPE)) + OSNAME = Solaris + LIBPATH := $(shell crle | grep 'Default Library Path' | awk '{ print $$5 }' | sed 's/:/ /g') + LIBEXT = so + OS_LDFLAGS += -lsocket -lnsl + ifeq (incsfw,$(shell if $(TEST) -d /opt/sfw/include; then echo incsfw; fi)) + INCPATH += /opt/sfw/include + OS_CCDEFS += -I/opt/sfw/include + endif + ifeq (libsfw,$(shell if $(TEST) -d /opt/sfw/lib; then echo libsfw; fi)) + LIBPATH += /opt/sfw/lib + OS_LDFLAGS += -L/opt/sfw/lib -R/opt/sfw/lib + endif + OS_CCDEFS += -D_LARGEFILE_SOURCE + else + ifeq (cygwin,$(OSTYPE)) + # use 0readme_ethernet.txt documented Windows pcap build components + INCPATH += ../windows-build/winpcap/WpdPack/include + LIBPATH += ../windows-build/winpcap/WpdPack/lib + PCAPLIB = wpcap + LIBEXT = a + else + ifneq (,$(findstring AIX,$(OSTYPE))) + OS_LDFLAGS += -lm -lrt + ifeq (incopt,$(shell if $(TEST) -d /opt/freeware/include; then echo incopt; fi)) + INCPATH += /opt/freeware/include + OS_CCDEFS += -I/opt/freeware/include + endif + ifeq (libopt,$(shell if $(TEST) -d /opt/freeware/lib; then echo libopt; fi)) + LIBPATH += /opt/freeware/lib + OS_LDFLAGS += -L/opt/freeware/lib + endif + else + ifeq (,$(findstring NetBSD,$(OSTYPE))) + ifneq (no ldconfig,$(findstring no ldconfig,$(shell which ldconfig 2>&1))) + LDSEARCH :=$(shell ldconfig -r | grep 'search directories' | awk '{print $$3}' | sed 's/:/ /g') + endif + ifneq (,$(LDSEARCH)) + LIBPATH := $(LDSEARCH) + else + ifeq (,$(strip $(LPATH))) + $(info *** Warning ***) + $(info *** Warning *** The library search path on your $(OSTYPE) platform can't be) + $(info *** Warning *** determined. This should be resolved before you can expect) + $(info *** Warning *** to have fully working simulators.) + $(info *** Warning ***) + $(info *** Warning *** You can specify your library paths via the LPATH environment) + $(info *** Warning *** variable.) + $(info *** Warning ***) + else + LIBPATH = $(subst :, ,$(LPATH)) + OS_LDFLAGS += $(patsubst %,-L%,$(LIBPATH)) + endif + endif + endif + endif + ifeq (usrpkglib,$(shell if $(TEST) -d /usr/pkg/lib; then echo usrpkglib; fi)) + LIBPATH += /usr/pkg/lib + INCPATH += /usr/pkg/include + OS_LDFLAGS += -L/usr/pkg/lib -R/usr/pkg/lib + endif + ifeq (/usr/local/lib,$(findstring /usr/local/lib,$(LIBPATH))) + INCPATH += /usr/local/include + OS_CCDEFS += -I/usr/local/include + endif + ifneq (,$(findstring NetBSD,$(OSTYPE))$(findstring FreeBSD,$(OSTYPE))$(findstring AIX,$(OSTYPE))) + LIBEXT = so + else + ifeq (HP-UX,$(OSTYPE)) + ifeq (ia64,$(shell uname -m)) + LIBEXT = so + else + LIBEXT = sl + endif + OS_CCDEFS += -D_HPUX_SOURCE -D_LARGEFILE64_SOURCE + OS_LDFLAGS += -Wl,+b: + NO_LTO = 1 + else + LIBEXT = a + endif + endif + endif + endif + endif + endif + # Some gcc versions don't support LTO, so only use LTO when the compiler is known to support it + ifeq (,$(NO_LTO)) + ifneq (,$(GCC_VERSION)) + ifeq (,$(shell $(GCC) -v /dev/null 2>&1 | grep '\-\-enable-lto')) + LTO_EXCLUDE_VERSIONS += $(GCC_VERSION) + endif + endif + endif + endif + $(info lib paths are: $(LIBPATH)) + $(info include paths are: $(INCPATH)) + find_lib = $(strip $(firstword $(foreach dir,$(strip $(LIBPATH)),$(wildcard $(dir)/lib$(1).$(LIBEXT))))) + find_include = $(strip $(firstword $(foreach dir,$(strip $(INCPATH)),$(wildcard $(dir)/$(1).h)))) + ifneq (,$(call find_lib,m)) + OS_LDFLAGS += -lm + $(info using libm: $(call find_lib,m)) + endif + ifneq (,$(call find_lib,rt)) + OS_LDFLAGS += -lrt + $(info using librt: $(call find_lib,rt)) + endif + ifneq (,$(call find_include,pthread)) + ifneq (,$(call find_lib,pthread)) + OS_CCDEFS += -DUSE_READER_THREAD + ifeq (,$(NOASYNCH)) + OS_CCDEFS += -DSIM_ASYNCH_IO + endif + OS_LDFLAGS += -lpthread + $(info using libpthread: $(call find_lib,pthread) $(call find_include,pthread)) + else + LIBEXTSAVE := $(LIBEXT) + LIBEXT = a + ifneq (,$(call find_lib,pthread)) + OS_CCDEFS += -DUSE_READER_THREAD + ifeq (,$(NOASYNCH)) + OS_CCDEFS += -DSIM_ASYNCH_IO + endif + OS_LDFLAGS += -lpthread + $(info using libpthread: $(call find_lib,pthread) $(call find_include,pthread)) + endif + LIBEXT = $(LIBEXTSAVE) + endif + endif + ifneq (,$(call find_include,dlfcn)) + ifneq (,$(call find_lib,dl)) + OS_CCDEFS += -DHAVE_DLOPEN=$(LIBEXT) + OS_LDFLAGS += -ldl + $(info using libdl: $(call find_lib,dl) $(call find_include,dlfcn)) + else + ifneq (,$(findstring BSD,$(OSTYPE))$(findstring AIX,$(OSTYPE))) + OS_CCDEFS += -DHAVE_DLOPEN=so + $(info using libdl: $(call find_include,dlfcn)) + else + ifneq (,$(call find_lib,dld)) + OS_CCDEFS += -DHAVE_DLOPEN=$(LIBEXT) + OS_LDFLAGS += -ldld + $(info using libdld: $(call find_lib,dld) $(call find_include,dlfcn)) + endif + endif + endif + endif + ifneq (,$(call find_include,glob)) + OS_CCDEFS += -DHAVE_GLOB + else + ifneq (,$(call find_include,fnmatch)) + OS_CCDEFS += -DHAVE_FNMATCH + endif + endif + ifneq (,$(VIDEO_USEFUL)) + ifneq (,$(call find_include,SDL2/SDL)) + ifneq (,$(call find_lib,SDL2)) + OS_CCDEFS += -DHAVE_LIBSDL -I$(dir $(call find_include,SDL2/SDL)) + OS_LDFLAGS += -lSDL2 + VIDEO_FEATURES = - video capabilities provided by libSDL2 (Simple Directmedia Layer) + $(info using libSDL2: $(call find_lib,SDL2) $(call find_include,SDL2/SDL)) + ifeq (Darwin,$(OSTYPE)) + OS_LDFLAGS += -lobjc -framework cocoa + endif + endif + else + ifneq (,$(call find_include,SDL/SDL)) + ifneq (,$(call find_lib,SDL)) + OS_CCDEFS += -DHAVE_LIBSDL -I$(dir $(call find_include,SDL/SDL)) + OS_LDFLAGS += -lSDL + VIDEO_FEATURES = - video capabilities provided by libSDL (Simple Directmedia Layer) + $(info using libSDL: $(call find_lib,SDL) $(call find_include,SDL/SDL)) + ifeq (Darwin,$(OSTYPE)) + OS_LDFLAGS += -lobjc -framework cocoa + endif + endif + endif + endif + ifeq (,$(findstring HAVE_LIBSDL,$(OS_CCDEFS))) + $(info *** Warning ***) + $(info *** Warning *** The simulator$(BUILD_MULTIPLE) you are building could provide more) + $(info *** Warning *** functionality if video support were available on your system.) + $(info *** Warning *** Install the development components of libSDL packaged by your) + $(info *** Warning *** operating system distribution and rebuild your simulator to) + $(info *** Warning *** enable this extra functionality.) + $(info *** Warning ***) + endif + endif + ifneq (,$(NETWORK_USEFUL)) + ifneq (,$(call find_include,pcap)) + ifneq (,$(shell grep 'pcap/pcap.h' $(call find_include,pcap) | grep include)) + PCAP_H_PATH = $(dir $(call find_include,pcap))pcap/pcap.h + else + PCAP_H_PATH = $(call find_include,pcap) + endif + ifneq (,$(shell grep pcap_compile $(PCAP_H_PATH) | grep const)) + BPF_CONST_STRING = -DBPF_CONST_STRING + endif + NETWORK_CCDEFS += -DHAVE_PCAP_NETWORK -I$(dir $(call find_include,pcap)) $(BPF_CONST_STRING) + NETWORK_LAN_FEATURES += PCAP + ifneq (,$(call find_lib,$(PCAPLIB))) + ifneq ($(USE_NETWORK),) # Network support specified on the GNU make command line + NETWORK_CCDEFS += -DUSE_NETWORK + $(info *** Warning ***) + $(info *** Warning *** Statically linking against libpcap is provides no measurable) + $(info *** Warning *** benefits over dynamically linking libpcap.) + $(info *** Warning ***) + $(info *** Warning *** Support for linking this way is currently deprecated and may be removed) + $(info *** Warning *** in the future.) + $(info *** Warning ***) + ifeq (cygwin,$(OSTYPE)) + # cygwin has no ldconfig so explicitly specify pcap object library + NETWORK_LDFLAGS = -L$(dir $(call find_lib,$(PCAPLIB))) -Wl,-R,$(dir $(call find_lib,$(PCAPLIB))) -l$(PCAPLIB) + else + NETWORK_LDFLAGS = -l$(PCAPLIB) + endif + $(info using libpcap: $(call find_lib,$(PCAPLIB)) $(call find_include,pcap)) + NETWORK_FEATURES = - static networking support using $(OSNAME) provided libpcap components + else # default build uses dynamic libpcap + NETWORK_CCDEFS += -DUSE_SHARED + $(info using libpcap: $(call find_include,pcap)) + NETWORK_FEATURES = - dynamic networking support using $(OSNAME) provided libpcap components + endif + else + LIBEXTSAVE := $(LIBEXT) + LIBEXT = a + ifneq (,$(call find_lib,$(PCAPLIB))) + NETWORK_CCDEFS += -DUSE_NETWORK + NETWORK_LDFLAGS := -L$(dir $(call find_lib,$(PCAPLIB))) -l$(PCAPLIB) + NETWORK_FEATURES = - static networking support using $(OSNAME) provided libpcap components + $(info using libpcap: $(call find_lib,$(PCAPLIB)) $(call find_include,pcap)) + endif + LIBEXT = $(LIBEXTSAVE) + endif + else + # On non-Linux platforms, we'll still try to provide deprecated support for libpcap in /usr/local + INCPATHSAVE := $(INCPATH) + ifeq (,$(findstring Linux,$(OSTYPE))) + # Look for package built from tcpdump.org sources with default install target (or cygwin winpcap) + INCPATH += /usr/local/include + PCAP_H_FOUND = $(call find_include,pcap) + endif + ifneq (,$(strip $(PCAP_H_FOUND))) + ifneq (,$(shell grep 'pcap/pcap.h' $(call find_include,pcap) | grep include)) + PCAP_H_PATH = $(dir $(call find_include,pcap))pcap/pcap.h + else + PCAP_H_PATH = $(call find_include,pcap) + endif + ifneq (,$(shell grep pcap_compile $(PCAP_H_PATH) | grep const)) + BPF_CONST_STRING = -DBPF_CONST_STRING + endif + LIBEXTSAVE := $(LIBEXT) + # first check if binary - shared objects are available/installed in the linker known search paths + ifneq (,$(call find_lib,$(PCAPLIB))) + NETWORK_CCDEFS = -DUSE_SHARED -I$(dir $(call find_include,pcap)) $(BPF_CONST_STRING) + NETWORK_FEATURES = - dynamic networking support using libpcap components from www.tcpdump.org and locally installed libpcap.$(LIBEXT) + $(info using libpcap: $(call find_include,pcap)) + else + LIBPATH += /usr/local/lib + LIBEXT = a + ifneq (,$(call find_lib,$(PCAPLIB))) + $(info using libpcap: $(call find_lib,$(PCAPLIB)) $(call find_include,pcap)) + ifeq (cygwin,$(OSTYPE)) + NETWORK_CCDEFS = -DUSE_NETWORK -DHAVE_PCAP_NETWORK -I$(dir $(call find_include,pcap)) $(BPF_CONST_STRING) + NETWORK_LDFLAGS = -L$(dir $(call find_lib,$(PCAPLIB))) -Wl,-R,$(dir $(call find_lib,$(PCAPLIB))) -l$(PCAPLIB) + NETWORK_FEATURES = - static networking support using libpcap components located in the cygwin directories + else + NETWORK_CCDEFS := -DUSE_NETWORK -DHAVE_PCAP_NETWORK -isystem -I$(dir $(call find_include,pcap)) $(BPF_CONST_STRING) $(call find_lib,$(PCAPLIB)) + NETWORK_FEATURES = - networking support using libpcap components from www.tcpdump.org + $(info *** Warning ***) + $(info *** Warning *** $(BUILD_SINGLE)Simulator$(BUILD_MULTIPLE) being built with networking support using) + $(info *** Warning *** libpcap components from www.tcpdump.org.) + $(info *** Warning *** Some users have had problems using the www.tcpdump.org libpcap) + $(info *** Warning *** components for simh networking. For best results, with) + $(info *** Warning *** simh networking, it is recommended that you install the) + $(info *** Warning *** libpcap-dev (or libpcap-devel) package from your $(OSNAME) distribution) + $(info *** Warning ***) + $(info *** Warning *** Building with the components manually installed from www.tcpdump.org) + $(info *** Warning *** is officially deprecated. Attempting to do so is unsupported.) + $(info *** Warning ***) + endif + else + $(error using libpcap: $(call find_include,pcap) missing $(PCAPLIB).$(LIBEXT)) + endif + NETWORK_LAN_FEATURES += PCAP + endif + LIBEXT = $(LIBEXTSAVE) + else + INCPATH = $(INCPATHSAVE) + $(info *** Warning ***) + $(info *** Warning *** $(BUILD_SINGLE)Simulator$(BUILD_MULTIPLE) are being built WITHOUT) + $(info *** Warning *** libpcap networking support) + $(info *** Warning ***) + $(info *** Warning *** To build simulator(s) with libpcap networking support you) + $(info *** Warning *** should read 0readme_ethernet.txt and follow the instructions) + $(info *** Warning *** regarding the needed libpcap development components for your) + $(info *** Warning *** $(OSTYPE) platform) + $(info *** Warning ***) + endif + endif + # Consider other network connections + ifneq (,$(call find_lib,vdeplug)) + # libvdeplug requires the use of the OS provided libpcap + ifeq (,$(findstring usr/local,$(NETWORK_CCDEFS))) + ifneq (,$(call find_include,libvdeplug)) + # Provide support for vde networking + NETWORK_CCDEFS += -DHAVE_VDE_NETWORK + NETWORK_LAN_FEATURES += VDE + ifeq (,$(findstring USE_NETWORK,$(NETWORK_CCDEFS))$(findstring USE_SHARED,$(NETWORK_CCDEFS))) + NETWORK_CCDEFS += -DUSE_NETWORK + endif + ifeq (Darwin,$(OSTYPE)) + NETWORK_LDFLAGS += -lvdeplug -L$(dir $(call find_lib,vdeplug)) + else + NETWORK_LDFLAGS += -lvdeplug -Wl,-R,$(dir $(call find_lib,vdeplug)) -L$(dir $(call find_lib,vdeplug)) + endif + $(info using libvdeplug: $(call find_lib,vdeplug) $(call find_include,libvdeplug)) + endif + endif + endif + ifeq (,$(findstring HAVE_VDE_NETWORK,$(NETWORK_CCDEFS))) + # Support is available on Linux for libvdeplug. Advise on its usage + ifneq (,$(findstring Linux,$(OSTYPE))) + ifneq (,$(findstring USE_NETWORK,$(NETWORK_CCDEFS))$(findstring USE_SHARED,$(NETWORK_CCDEFS))) + $(info *** Warning ***) + $(info *** Warning *** $(BUILD_SINGLE)Simulator$(BUILD_MULTIPLE) are being built with) + $(info *** Warning *** minimal libpcap networking support) + $(info *** Warning ***) + endif + $(info *** Warning *** Simulators on your $(OSNAME) platform can also be built with) + $(info *** Warning *** extended LAN Ethernet networking support by using VDE Ethernet.) + $(info *** Warning ***) + $(info *** Warning *** To build simulator(s) with extended networking support you) + $(info *** Warning *** should read 0readme_ethernet.txt and follow the instructions) + $(info *** Warning *** regarding the needed libvdeplug components for your $(OSNAME)) + $(info *** Warning *** platform) + $(info *** Warning ***) + endif + endif + ifneq (,$(call find_include,linux/if_tun)) + # Provide support for Tap networking on Linux + NETWORK_CCDEFS += -DHAVE_TAP_NETWORK + NETWORK_LAN_FEATURES += TAP + ifeq (,$(findstring USE_NETWORK,$(NETWORK_CCDEFS))$(findstring USE_SHARED,$(NETWORK_CCDEFS))) + NETWORK_CCDEFS += -DUSE_NETWORK + endif + endif + ifeq (bsdtuntap,$(shell if $(TEST) -e /usr/include/net/if_tun.h -o -e /Library/Extensions/tap.kext; then echo bsdtuntap; fi)) + # Provide support for Tap networking on BSD platforms (including OS X) + NETWORK_CCDEFS += -DHAVE_TAP_NETWORK -DHAVE_BSDTUNTAP + NETWORK_LAN_FEATURES += TAP + ifeq (,$(findstring USE_NETWORK,$(NETWORK_CCDEFS))$(findstring USE_SHARED,$(NETWORK_CCDEFS))) + NETWORK_CCDEFS += -DUSE_NETWORK + endif + endif + ifeq (,$(findstring USE_NETWORK,$(NETWORK_CCDEFS))$(findstring USE_SHARED,$(NETWORK_CCDEFS))$(findstring HAVE_VDE_NETWORK,$(NETWORK_CCDEFS))) + NETWORK_CCDEFS += -DUSE_NETWORK + NETWORK_FEATURES = - WITHOUT Local LAN networking support + $(info *** Warning ***) + $(info *** Warning *** $(BUILD_SINGLE)Simulator$(BUILD_MULTIPLE) are being built WITHOUT LAN networking support) + $(info *** Warning ***) + $(info *** Warning *** To build simulator(s) with networking support you should read) + $(info *** Warning *** 0readme_ethernet.txt and follow the instructions regarding the) + $(info *** Warning *** needed libpcap components for your $(OSTYPE) platform) + $(info *** Warning ***) + endif + NETWORK_OPT = $(NETWORK_CCDEFS) + endif + ifneq (binexists,$(shell if $(TEST) -e BIN; then echo binexists; fi)) + MKDIRBIN = mkdir -p BIN + endif + ifeq (commit-id-exists,$(shell if $(TEST) -e .git-commit-id; then echo commit-id-exists; fi)) + GIT_COMMIT_ID=$(shell cat .git-commit-id) + else + ifeq (,$(shell grep 'define SIM_GIT_COMMIT_ID' sim_rev.h | grep 'Format:')) + GIT_COMMIT_ID=$(shell grep 'define SIM_GIT_COMMIT_ID' sim_rev.h | awk '{ print $$3 }') + endif + endif +else + #Win32 Environments (via MinGW32) + GCC = gcc + ifeq (XP,$(findstring XP,$(shell ver))) + GCC_Path := C:\MinGW\bin\ + else + GCC_Path := $(dir $(shell where gcc.exe)) + endif + ifeq (rename-build-support,$(shell if exist ..\windows-build-windows-build echo rename-build-support)) + FIXED_BUILD := $(shell move ..\windows-build-windows-build ..\windows-build >NUL) + endif + GCC_VERSION = $(word 3,$(shell $(GCC) --version)) + COMPILER_NAME = GCC Version: $(GCC_VERSION) + LTO_EXCLUDE_VERSIONS = 4.5.2 + ifeq (pthreads,$(shell if exist ..\windows-build\pthreads\Pre-built.2\include\pthread.h echo pthreads)) + PTHREADS_CCDEFS = -DUSE_READER_THREAD -DPTW32_STATIC_LIB -I../windows-build/pthreads/Pre-built.2/include + ifeq (,$(NOASYNCH)) + PTHREADS_CCDEFS += -DSIM_ASYNCH_IO + endif + PTHREADS_LDFLAGS = -lpthreadGC2 -L..\windows-build\pthreads\Pre-built.2\lib + else + ifeq (pthreads,$(shell if exist $(dir $(GCC_Path))..\include\pthread.h echo pthreads)) + PTHREADS_CCDEFS = -DUSE_READER_THREAD + ifeq (,$(NOASYNCH)) + PTHREADS_CCDEFS += -DSIM_ASYNCH_IO + endif + PTHREADS_LDFLAGS = -lpthread + endif + endif + ifeq (pcap,$(shell if exist ..\windows-build\winpcap\Wpdpack\include\pcap.h echo pcap)) + NETWORK_LDFLAGS = + NETWORK_OPT = -DUSE_SHARED -I../windows-build/winpcap/Wpdpack/include -I$(GCC_Path)..\include\ddk + NETWORK_FEATURES = - dynamic networking support using windows-build provided libpcap components + else + ifeq (pcap,$(shell if exist $(dir $(GCC_Path))..\include\pcap.h echo pcap)) + NETWORK_LDFLAGS = + NETWORK_OPT = -DUSE_SHARED -I$(GCC_Path)..\include\ddk + NETWORK_FEATURES = - dynamic networking support using libpcap components found in the MinGW directories + endif + endif + ifneq (,$(VIDEO_USEFUL)) + ifeq (libSDL,$(shell if exist ..\windows-build\libSDL\SDL2-2.0.0\include\SDL.h echo libSDL)) + OS_CCDEFS += -DHAVE_LIBSDL -I..\windows-build\libSDL\SDL2-2.0.0\include + OS_LDFLAGS += -lSDL2 -L..\windows-build\libSDL\SDL2-2.0.0\lib + VIDEO_FEATURES = - video capabilities provided by libSDL2 (Simple Directmedia Layer) + else + $(info ***********************************************************************) + $(info ***********************************************************************) + $(info ** This build could produce simulators with video capabilities. **) + $(info ** However, the required files to achieve this can't be found on **) + $(info ** this system. Download the file: **) + $(info ** https://github.com/simh/windows-build/archive/windows-build.zip **) + $(info ** Refer to the file: **) + $(info ** "Visual Studio Projects\0ReadMe_Projects.txt" for where to place **) + $(info ** the 'windows-build' folder extracted from that zip file. **) + $(info ***********************************************************************) + $(info ***********************************************************************) + $(info .) + endif + endif + OS_CCDEFS += -fms-extensions $(PTHREADS_CCDEFS) + OS_LDFLAGS += -lm -lwsock32 -lwinmm $(PTHREADS_LDFLAGS) + EXE = .exe + ifneq (binexists,$(shell if exist BIN echo binexists)) + MKDIRBIN = if not exist BIN mkdir BIN + endif + ifneq ($(USE_NETWORK),) + NETWORK_OPT += -DUSE_SHARED + endif + ifneq (,$(shell if exist .git-commit-id type .git-commit-id)) + GIT_COMMIT_ID=$(shell if exist .git-commit-id type .git-commit-id) + else + ifeq (,$(shell findstr /C:"define SIM_GIT_COMMIT_ID" sim_rev.h | findstr Format)) + GIT_COMMIT_ID=$(shell for /F "tokens=3" %%i in ("$(shell findstr /C:"define SIM_GIT_COMMIT_ID" sim_rev.h)") do echo %%i) + endif + endif +endif +ifneq (,$(GIT_COMMIT_ID)) + CFLAGS_GIT = -DSIM_GIT_COMMIT_ID=$(GIT_COMMIT_ID) +endif +ifneq ($(DEBUG),) + CFLAGS_G = -g -ggdb -g3 + CFLAGS_O = -O0 + BUILD_FEATURES = - debugging support +else + ifneq (clang,$(findstring clang,$(COMPILER_NAME))) + CFLAGS_O = -O2 + else + ifeq (Darwin,$(OSTYPE)) + CFLAGS_O += -O4 -fno-strict-overflow -flto -fwhole-program + else + CFLAGS_O := -O2 -fno-strict-overflow + endif + endif + LDFLAGS_O = + GCC_MAJOR_VERSION = $(firstword $(subst ., ,$(GCC_VERSION))) + ifneq (3,$(GCC_MAJOR_VERSION)) + ifeq (,$(GCC_OPTIMIZERS_CMD)) + GCC_OPTIMIZERS_CMD = $(GCC) --help=optimizers + endif + GCC_OPTIMIZERS = $(shell $(GCC_OPTIMIZERS_CMD)) + endif + ifneq (,$(findstring $(GCC_VERSION),$(LTO_EXCLUDE_VERSIONS))) + NO_LTO = 1 + endif + ifneq (,$(findstring -finline-functions,$(GCC_OPTIMIZERS))) + CFLAGS_O += -finline-functions + endif + ifneq (,$(findstring -fgcse-after-reload,$(GCC_OPTIMIZERS))) + CFLAGS_O += -fgcse-after-reload + endif + ifneq (,$(findstring -fpredictive-commoning,$(GCC_OPTIMIZERS))) + CFLAGS_O += -fpredictive-commoning + endif + ifneq (,$(findstring -fipa-cp-clone,$(GCC_OPTIMIZERS))) + CFLAGS_O += -fipa-cp-clone + endif + ifneq (,$(findstring -funsafe-loop-optimizations,$(GCC_OPTIMIZERS))) + CFLAGS_O += -fno-unsafe-loop-optimizations + endif + ifneq (,$(findstring -fstrict-overflow,$(GCC_OPTIMIZERS))) + CFLAGS_O += -fno-strict-overflow + endif + ifeq (,$(NO_LTO)) + ifneq (,$(findstring -flto,$(GCC_OPTIMIZERS))) + CFLAGS_O += -flto -fwhole-program + LDFLAGS_O += -flto -fwhole-program + endif + endif + BUILD_FEATURES = - compiler optimizations and no debugging support +endif +ifneq (3,$(GCC_MAJOR_VERSION)) + ifeq (,$(GCC_WARNINGS_CMD)) + GCC_WARNINGS_CMD = $(GCC) --help=warnings + endif + ifneq (,$(findstring -Wunused-result,$(shell $(GCC_WARNINGS_CMD)))) + CFLAGS_O += -Wno-unused-result + endif +endif +ifneq (clean,$(MAKECMDGOALS)) + BUILD_FEATURES := $(BUILD_FEATURES). $(COMPILER_NAME) + $(info ***) + $(info *** $(BUILD_SINGLE)Simulator$(BUILD_MULTIPLE) being built with:) + $(info *** $(BUILD_FEATURES).) + ifneq (,$(NETWORK_FEATURES)) + $(info *** $(NETWORK_FEATURES).) + endif + ifneq (,$(NETWORK_LAN_FEATURES)) + $(info *** - Local LAN packet transports: $(NETWORK_LAN_FEATURES)) + endif + ifneq (,$(VIDEO_FEATURES)) + $(info *** $(VIDEO_FEATURES).) + endif + ifneq (,$(GIT_COMMIT_ID)) + $(info ***) + $(info *** git commit id is $(GIT_COMMIT_ID).) + endif + $(info ***) +endif +ifneq ($(DONT_USE_ROMS),) + ROMS_OPT = -DDONT_USE_INTERNAL_ROM +else + BUILD_ROMS = ${BIN}BuildROMs${EXE} +endif +ifneq ($(DONT_USE_READER_THREAD),) + NETWORK_OPT += -DDONT_USE_READER_THREAD +endif + +ifeq (HP-UX,$(OSTYPE)) + CC_STD = -std=gnu99 +else + ifeq (,$(SUNC_VERSION)) + CC_STD = -std=c99 + endif +endif +CC_OUTSPEC = -o $@ +CC := $(GCC) $(CC_STD) -U__STRICT_ANSI__ $(CFLAGS_G) $(CFLAGS_O) $(CFLAGS_GIT) -DSIM_COMPILER="$(COMPILER_NAME)" -I . $(OS_CCDEFS) $(ROMS_OPT) +LDFLAGS := $(OS_LDFLAGS) $(NETWORK_LDFLAGS) $(LDFLAGS_O) + +# +# Common Libraries +# +BIN = BIN/ +SIM = scp.c sim_console.c sim_fio.c sim_timer.c sim_sock.c \ + sim_tmxr.c sim_ether.c sim_tape.c sim_disk.c sim_serial.c \ + sim_video.c + +DISPLAYD = display +ifeq ($(WIN32),) + ifeq (x11,$(shell if $(TEST) -e /usr/include/X11/Intrinsic.h ; then echo x11; fi)) + DISPLAYL = ${DISPLAYD}/display.c $(DISPLAYD)/x11.c + DISPLAYVT = ${DISPLAYD}/vt11.c + DISPLAY_OPT = -DUSE_DISPLAY -I/usr/X11/include -lXt -lX11 -lm + else + DISPLAYL = + DISPLAYVT = + DISPLAY_OPT = + endif +else + DISPLAYL = ${DISPLAYD}/display.c $(DISPLAYD)/win32.c + DISPLAYVT = ${DISPLAYD}/vt11.c + DISPLAY_OPT = -DUSE_DISPLAY -lgdi32 +endif + +# +# Emulator source files and compile time options +# +PDP1D = PDP1 +PDP1 = ${PDP1D}/pdp1_lp.c ${PDP1D}/pdp1_cpu.c ${PDP1D}/pdp1_stddev.c \ + ${PDP1D}/pdp1_sys.c ${PDP1D}/pdp1_dt.c ${PDP1D}/pdp1_drm.c \ + ${PDP1D}/pdp1_clk.c ${PDP1D}/pdp1_dcs.c ${PDP1D}/pdp1_dpy.c ${DISPLAYL} +PDP1_OPT = -I ${PDP1D} $(DISPLAY_OPT) + + +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_qty.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_qty.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_rb.c ${PDP18BD}/pdp18b_tt1.c ${PDP18BD}/pdp18b_fpp.c +PDP4_OPT = -DPDP4 -I ${PDP18BD} +PDP7_OPT = -DPDP7 -I ${PDP18BD} +PDP9_OPT = -DPDP9 -I ${PDP18BD} +PDP15_OPT = -DPDP15 -I ${PDP18BD} + + +PDP11D = PDP11 +PDP11 = ${PDP11D}/pdp11_fp.c ${PDP11D}/pdp11_cpu.c ${PDP11D}/pdp11_dz.c \ + ${PDP11D}/pdp11_cis.c ${PDP11D}/pdp11_lp.c ${PDP11D}/pdp11_rk.c \ + ${PDP11D}/pdp11_rl.c ${PDP11D}/pdp11_rp.c ${PDP11D}/pdp11_rx.c \ + ${PDP11D}/pdp11_stddev.c ${PDP11D}/pdp11_sys.c ${PDP11D}/pdp11_tc.c \ + ${PDP11D}/pdp11_tm.c ${PDP11D}/pdp11_ts.c ${PDP11D}/pdp11_io.c \ + ${PDP11D}/pdp11_rq.c ${PDP11D}/pdp11_tq.c ${PDP11D}/pdp11_pclk.c \ + ${PDP11D}/pdp11_ry.c ${PDP11D}/pdp11_pt.c ${PDP11D}/pdp11_hk.c \ + ${PDP11D}/pdp11_xq.c ${PDP11D}/pdp11_xu.c ${PDP11D}/pdp11_vh.c \ + ${PDP11D}/pdp11_rh.c ${PDP11D}/pdp11_tu.c ${PDP11D}/pdp11_cpumod.c \ + ${PDP11D}/pdp11_cr.c ${PDP11D}/pdp11_rf.c ${PDP11D}/pdp11_dl.c \ + ${PDP11D}/pdp11_ta.c ${PDP11D}/pdp11_rc.c ${PDP11D}/pdp11_kg.c \ + ${PDP11D}/pdp11_ke.c ${PDP11D}/pdp11_dc.c ${PDP11D}/pdp11_dmc.c \ + ${PDP11D}/pdp11_kmc.c ${PDP11D}/pdp11_dup.c ${PDP11D}/pdp11_rs.c \ + ${PDP11D}/pdp11_vt.c ${PDP11D}/pdp11_io_lib.c $(DISPLAYL) $(DISPLAYVT) +PDP11_OPT = -DVM_PDP11 -I ${PDP11D} ${NETWORK_OPT} $(DISPLAY_OPT) + + +VAXD = VAX +VAX = ${VAXD}/vax_cpu.c ${VAXD}/vax_cpu1.c ${VAXD}/vax_fpa.c ${VAXD}/vax_io.c \ + ${VAXD}/vax_cis.c ${VAXD}/vax_octa.c ${VAXD}/vax_cmode.c \ + ${VAXD}/vax_mmu.c ${VAXD}/vax_stddev.c ${VAXD}/vax_sysdev.c \ + ${VAXD}/vax_sys.c ${VAXD}/vax_syscm.c ${VAXD}/vax_syslist.c \ + ${PDP11D}/pdp11_rl.c ${PDP11D}/pdp11_rq.c ${PDP11D}/pdp11_ts.c \ + ${PDP11D}/pdp11_dz.c ${PDP11D}/pdp11_lp.c ${PDP11D}/pdp11_tq.c \ + ${PDP11D}/pdp11_xq.c ${PDP11D}/pdp11_vh.c ${PDP11D}/pdp11_cr.c \ + ${PDP11D}/pdp11_io_lib.c +VAX_OPT = -DVM_VAX -DUSE_INT64 -DUSE_ADDR64 -I ${VAXD} -I ${PDP11D} ${NETWORK_OPT} + + +VAX610 = ${VAXD}/vax_cpu.c ${VAXD}/vax_cpu1.c ${VAXD}/vax_fpa.c \ + ${VAXD}/vax_cis.c ${VAXD}/vax_octa.c ${VAXD}/vax_cmode.c \ + ${VAXD}/vax_mmu.c ${VAXD}/vax_sys.c ${VAXD}/vax_syscm.c \ + ${VAXD}/vax610_stddev.c ${VAXD}/vax610_sysdev.c ${VAXD}/vax610_io.c \ + ${VAXD}/vax610_syslist.c ${VAXD}/vax610_mem.c ${VAXD}/vax_vc.c \ + ${VAXD}/vax_lk.c ${VAXD}/vax_vs.c ${VAXD}/vax_2681.c \ + ${PDP11D}/pdp11_rl.c ${PDP11D}/pdp11_rq.c ${PDP11D}/pdp11_ts.c \ + ${PDP11D}/pdp11_dz.c ${PDP11D}/pdp11_lp.c ${PDP11D}/pdp11_tq.c \ + ${PDP11D}/pdp11_xq.c ${PDP11D}/pdp11_vh.c ${PDP11D}/pdp11_cr.c \ + ${PDP11D}/pdp11_io_lib.c +VAX610_OPT = -DVM_VAX -DVAX_610 -DUSE_INT64 -DUSE_ADDR64 -DUSE_SIM_VIDEO -I ${VAXD} -I ${PDP11D} ${NETWORK_OPT} + +VAX630 = ${VAXD}/vax_cpu.c ${VAXD}/vax_cpu1.c ${VAXD}/vax_fpa.c \ + ${VAXD}/vax_cis.c ${VAXD}/vax_octa.c ${VAXD}/vax_cmode.c \ + ${VAXD}/vax_mmu.c ${VAXD}/vax_sys.c ${VAXD}/vax_syscm.c \ + ${VAXD}/vax_watch.c ${VAXD}/vax630_stddev.c ${VAXD}/vax630_sysdev.c \ + ${VAXD}/vax630_io.c ${VAXD}/vax630_syslist.c ${VAXD}/vax_vc.c \ + ${VAXD}/vax_lk.c ${VAXD}/vax_vs.c ${VAXD}/vax_2681.c \ + ${PDP11D}/pdp11_rl.c ${PDP11D}/pdp11_rq.c ${PDP11D}/pdp11_ts.c \ + ${PDP11D}/pdp11_dz.c ${PDP11D}/pdp11_lp.c ${PDP11D}/pdp11_tq.c \ + ${PDP11D}/pdp11_xq.c ${PDP11D}/pdp11_vh.c ${PDP11D}/pdp11_cr.c \ + ${PDP11D}/pdp11_io_lib.c +VAX620_OPT = -DVM_VAX -DVAX_620 -DUSE_INT64 -DUSE_ADDR64 -I ${VAXD} -I ${PDP11D} ${NETWORK_OPT} +VAX630_OPT = -DVM_VAX -DVAX_630 -DUSE_INT64 -DUSE_ADDR64 -DUSE_SIM_VIDEO -I ${VAXD} -I ${PDP11D} ${NETWORK_OPT} + + +VAX730 = ${VAXD}/vax_cpu.c ${VAXD}/vax_cpu1.c ${VAXD}/vax_fpa.c \ + ${VAXD}/vax_cis.c ${VAXD}/vax_octa.c ${VAXD}/vax_cmode.c \ + ${VAXD}/vax_mmu.c ${VAXD}/vax_sys.c ${VAXD}/vax_syscm.c \ + ${VAXD}/vax730_stddev.c ${VAXD}/vax730_sys.c \ + ${VAXD}/vax730_mem.c ${VAXD}/vax730_uba.c ${VAXD}/vax730_rb.c \ + ${VAXD}/vax730_syslist.c \ + ${PDP11D}/pdp11_rl.c ${PDP11D}/pdp11_rq.c ${PDP11D}/pdp11_ts.c \ + ${PDP11D}/pdp11_dz.c ${PDP11D}/pdp11_lp.c ${PDP11D}/pdp11_tq.c \ + ${PDP11D}/pdp11_xu.c ${PDP11D}/pdp11_ry.c ${PDP11D}/pdp11_cr.c \ + ${PDP11D}/pdp11_hk.c ${PDP11D}/pdp11_vh.c ${PDP11D}/pdp11_dmc.c \ + ${PDP11D}/pdp11_dup.c ${PDP11D}/pdp11_io_lib.c +VAX730_OPT = -DVM_VAX -DVAX_730 -DUSE_INT64 -DUSE_ADDR64 -I VAX -I ${PDP11D} ${NETWORK_OPT} + + +VAX750 = ${VAXD}/vax_cpu.c ${VAXD}/vax_cpu1.c ${VAXD}/vax_fpa.c \ + ${VAXD}/vax_cis.c ${VAXD}/vax_octa.c ${VAXD}/vax_cmode.c \ + ${VAXD}/vax_mmu.c ${VAXD}/vax_sys.c ${VAXD}/vax_syscm.c \ + ${VAXD}/vax750_stddev.c ${VAXD}/vax750_cmi.c \ + ${VAXD}/vax750_mem.c ${VAXD}/vax750_uba.c ${VAXD}/vax7x0_mba.c \ + ${VAXD}/vax750_syslist.c \ + ${PDP11D}/pdp11_rl.c ${PDP11D}/pdp11_rq.c ${PDP11D}/pdp11_ts.c \ + ${PDP11D}/pdp11_dz.c ${PDP11D}/pdp11_lp.c ${PDP11D}/pdp11_tq.c \ + ${PDP11D}/pdp11_xu.c ${PDP11D}/pdp11_ry.c ${PDP11D}/pdp11_cr.c \ + ${PDP11D}/pdp11_hk.c ${PDP11D}/pdp11_rp.c ${PDP11D}/pdp11_tu.c \ + ${PDP11D}/pdp11_vh.c ${PDP11D}/pdp11_dmc.c ${PDP11D}/pdp11_dup.c \ + ${PDP11D}/pdp11_io_lib.c +VAX750_OPT = -DVM_VAX -DVAX_750 -DUSE_INT64 -DUSE_ADDR64 -I VAX -I ${PDP11D} ${NETWORK_OPT} + + +VAX780 = ${VAXD}/vax_cpu.c ${VAXD}/vax_cpu1.c ${VAXD}/vax_fpa.c \ + ${VAXD}/vax_cis.c ${VAXD}/vax_octa.c ${VAXD}/vax_cmode.c \ + ${VAXD}/vax_mmu.c ${VAXD}/vax_sys.c ${VAXD}/vax_syscm.c \ + ${VAXD}/vax780_stddev.c ${VAXD}/vax780_sbi.c \ + ${VAXD}/vax780_mem.c ${VAXD}/vax780_uba.c ${VAXD}/vax7x0_mba.c \ + ${VAXD}/vax780_fload.c ${VAXD}/vax780_syslist.c \ + ${PDP11D}/pdp11_rl.c ${PDP11D}/pdp11_rq.c ${PDP11D}/pdp11_ts.c \ + ${PDP11D}/pdp11_dz.c ${PDP11D}/pdp11_lp.c ${PDP11D}/pdp11_tq.c \ + ${PDP11D}/pdp11_xu.c ${PDP11D}/pdp11_ry.c ${PDP11D}/pdp11_cr.c \ + ${PDP11D}/pdp11_rp.c ${PDP11D}/pdp11_tu.c ${PDP11D}/pdp11_hk.c \ + ${PDP11D}/pdp11_vh.c ${PDP11D}/pdp11_dmc.c ${PDP11D}/pdp11_dup.c \ + ${PDP11D}/pdp11_io_lib.c +VAX780_OPT = -DVM_VAX -DVAX_780 -DUSE_INT64 -DUSE_ADDR64 -I VAX -I ${PDP11D} ${NETWORK_OPT} + + +VAX8600 = ${VAXD}/vax_cpu.c ${VAXD}/vax_cpu1.c ${VAXD}/vax_fpa.c \ + ${VAXD}/vax_cis.c ${VAXD}/vax_octa.c ${VAXD}/vax_cmode.c \ + ${VAXD}/vax_mmu.c ${VAXD}/vax_sys.c ${VAXD}/vax_syscm.c \ + ${VAXD}/vax860_stddev.c ${VAXD}/vax860_sbia.c \ + ${VAXD}/vax860_abus.c ${VAXD}/vax780_uba.c ${VAXD}/vax7x0_mba.c \ + ${VAXD}/vax860_syslist.c \ + ${PDP11D}/pdp11_rl.c ${PDP11D}/pdp11_rq.c ${PDP11D}/pdp11_ts.c \ + ${PDP11D}/pdp11_dz.c ${PDP11D}/pdp11_lp.c ${PDP11D}/pdp11_tq.c \ + ${PDP11D}/pdp11_xu.c ${PDP11D}/pdp11_ry.c ${PDP11D}/pdp11_cr.c \ + ${PDP11D}/pdp11_rp.c ${PDP11D}/pdp11_tu.c ${PDP11D}/pdp11_hk.c \ + ${PDP11D}/pdp11_vh.c ${PDP11D}/pdp11_dmc.c ${PDP11D}/pdp11_dup.c \ + ${PDP11D}/pdp11_io_lib.c +VAX8600_OPT = -DVM_VAX -DVAX_860 -DUSE_INT64 -DUSE_ADDR64 -I VAX -I ${PDP11D} ${NETWORK_OPT} + + +PDP10D = PDP10 +PDP10 = ${PDP10D}/pdp10_fe.c ${PDP11D}/pdp11_dz.c ${PDP10D}/pdp10_cpu.c \ + ${PDP10D}/pdp10_ksio.c ${PDP10D}/pdp10_lp20.c ${PDP10D}/pdp10_mdfp.c \ + ${PDP10D}/pdp10_pag.c ${PDP10D}/pdp10_rp.c ${PDP10D}/pdp10_sys.c \ + ${PDP10D}/pdp10_tim.c ${PDP10D}/pdp10_tu.c ${PDP10D}/pdp10_xtnd.c \ + ${PDP11D}/pdp11_pt.c ${PDP11D}/pdp11_ry.c ${PDP11D}/pdp11_cr.c \ + ${PDP11D}/pdp11_dup.c ${PDP11D}/pdp11_dmc.c ${PDP11D}/pdp11_kmc.c +PDP10_OPT = -DVM_PDP10 -DUSE_INT64 -I ${PDP10D} -I ${PDP11D} + + +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_tsc.c \ + ${PDP8D}/pdp8_td.c ${PDP8D}/pdp8_ct.c ${PDP8D}/pdp8_fpp.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_mt.c ${H316D}/h316_fhd.c \ + ${H316D}/h316_dp.c ${H316D}/h316_rtc.c ${H316D}/h316_imp.c \ + ${H316D}/h316_hi.c ${H316D}/h316_mi.c ${H316D}/h316_udp.c +H316_OPT = -I ${H316D} -D VM_IMPTIP + + +HP2100D = HP2100 +HP2100 = ${HP2100D}/hp2100_stddev.c ${HP2100D}/hp2100_dp.c ${HP2100D}/hp2100_dq.c \ + ${HP2100D}/hp2100_dr.c ${HP2100D}/hp2100_lps.c ${HP2100D}/hp2100_ms.c \ + ${HP2100D}/hp2100_mt.c ${HP2100D}/hp2100_mux.c ${HP2100D}/hp2100_cpu.c \ + ${HP2100D}/hp2100_fp.c ${HP2100D}/hp2100_sys.c ${HP2100D}/hp2100_lpt.c \ + ${HP2100D}/hp2100_ipl.c ${HP2100D}/hp2100_ds.c ${HP2100D}/hp2100_cpu0.c \ + ${HP2100D}/hp2100_cpu1.c ${HP2100D}/hp2100_cpu2.c ${HP2100D}/hp2100_cpu3.c \ + ${HP2100D}/hp2100_cpu4.c ${HP2100D}/hp2100_cpu5.c ${HP2100D}/hp2100_cpu6.c \ + ${HP2100D}/hp2100_cpu7.c ${HP2100D}/hp2100_fp1.c ${HP2100D}/hp2100_baci.c \ + ${HP2100D}/hp2100_mpx.c ${HP2100D}/hp2100_pif.c ${HP2100D}/hp2100_di.c \ + ${HP2100D}/hp2100_di_da.c ${HP2100D}/hp_disclib.c +HP2100_OPT = -DHAVE_INT64 -I ${HP2100D} + + +I1401D = I1401 +I1401 = ${I1401D}/i1401_lp.c ${I1401D}/i1401_cpu.c ${I1401D}/i1401_iq.c \ + ${I1401D}/i1401_cd.c ${I1401D}/i1401_mt.c ${I1401D}/i1401_dp.c \ + ${I1401D}/i1401_sys.c +I1401_OPT = -I ${I1401D} + + +I1620D = I1620 +I1620 = ${I1620D}/i1620_cd.c ${I1620D}/i1620_dp.c ${I1620D}/i1620_pt.c \ + ${I1620D}/i1620_tty.c ${I1620D}/i1620_cpu.c ${I1620D}/i1620_lp.c \ + ${I1620D}/i1620_fp.c ${I1620D}/i1620_sys.c +I1620_OPT = -I ${I1620D} + + +I7094D = I7094 +I7094 = ${I7094D}/i7094_cpu.c ${I7094D}/i7094_cpu1.c ${I7094D}/i7094_io.c \ + ${I7094D}/i7094_cd.c ${I7094D}/i7094_clk.c ${I7094D}/i7094_com.c \ + ${I7094D}/i7094_drm.c ${I7094D}/i7094_dsk.c ${I7094D}/i7094_sys.c \ + ${I7094D}/i7094_lp.c ${I7094D}/i7094_mt.c ${I7094D}/i7094_binloader.c +I7094_OPT = -DUSE_INT64 -I ${I7094D} + + +IBM1130D = Ibm1130 +IBM1130 = ${IBM1130D}/ibm1130_cpu.c ${IBM1130D}/ibm1130_cr.c \ + ${IBM1130D}/ibm1130_disk.c ${IBM1130D}/ibm1130_stddev.c \ + ${IBM1130D}/ibm1130_sys.c ${IBM1130D}/ibm1130_gdu.c \ + ${IBM1130D}/ibm1130_gui.c ${IBM1130D}/ibm1130_prt.c \ + ${IBM1130D}/ibm1130_fmt.c ${IBM1130D}/ibm1130_ptrp.c \ + ${IBM1130D}/ibm1130_plot.c ${IBM1130D}/ibm1130_sca.c \ + ${IBM1130D}/ibm1130_t2741.c +IBM1130_OPT = -I ${IBM1130D} +ifneq ($(WIN32),) +IBM1130_OPT += -DGUI_SUPPORT -lgdi32 +endif + + +ID16D = Interdata +ID16 = ${ID16D}/id16_cpu.c ${ID16D}/id16_sys.c ${ID16D}/id_dp.c \ + ${ID16D}/id_fd.c ${ID16D}/id_fp.c ${ID16D}/id_idc.c ${ID16D}/id_io.c \ + ${ID16D}/id_lp.c ${ID16D}/id_mt.c ${ID16D}/id_pas.c ${ID16D}/id_pt.c \ + ${ID16D}/id_tt.c ${ID16D}/id_uvc.c ${ID16D}/id16_dboot.c ${ID16D}/id_ttp.c +ID16_OPT = -I ${ID16D} + + +ID32D = Interdata +ID32 = ${ID32D}/id32_cpu.c ${ID32D}/id32_sys.c ${ID32D}/id_dp.c \ + ${ID32D}/id_fd.c ${ID32D}/id_fp.c ${ID32D}/id_idc.c ${ID32D}/id_io.c \ + ${ID32D}/id_lp.c ${ID32D}/id_mt.c ${ID32D}/id_pas.c ${ID32D}/id_pt.c \ + ${ID32D}/id_tt.c ${ID32D}/id_uvc.c ${ID32D}/id32_dboot.c ${ID32D}/id_ttp.c +ID32_OPT = -I ${ID32D} + + +S3D = S3 +S3 = ${S3D}/s3_cd.c ${S3D}/s3_cpu.c ${S3D}/s3_disk.c ${S3D}/s3_lp.c \ + ${S3D}/s3_pkb.c ${S3D}/s3_sys.c +S3_OPT = -I ${S3D} + + +ALTAIRD = ALTAIR +ALTAIR = ${ALTAIRD}/altair_sio.c ${ALTAIRD}/altair_cpu.c ${ALTAIRD}/altair_dsk.c \ + ${ALTAIRD}/altair_sys.c +ALTAIR_OPT = -I ${ALTAIRD} + + +ALTAIRZ80D = AltairZ80 +ALTAIRZ80 = ${ALTAIRZ80D}/altairz80_cpu.c ${ALTAIRZ80D}/altairz80_cpu_nommu.c \ + ${ALTAIRZ80D}/altairz80_dsk.c ${ALTAIRZ80D}/disasm.c \ + ${ALTAIRZ80D}/altairz80_sio.c ${ALTAIRZ80D}/altairz80_sys.c \ + ${ALTAIRZ80D}/altairz80_hdsk.c ${ALTAIRZ80D}/altairz80_net.c \ + ${ALTAIRZ80D}/flashwriter2.c ${ALTAIRZ80D}/i86_decode.c \ + ${ALTAIRZ80D}/i86_ops.c ${ALTAIRZ80D}/i86_prim_ops.c \ + ${ALTAIRZ80D}/i8272.c ${ALTAIRZ80D}/insnsd.c ${ALTAIRZ80D}/altairz80_mhdsk.c \ + ${ALTAIRZ80D}/mfdc.c ${ALTAIRZ80D}/n8vem.c ${ALTAIRZ80D}/vfdhd.c \ + ${ALTAIRZ80D}/s100_disk1a.c ${ALTAIRZ80D}/s100_disk2.c ${ALTAIRZ80D}/s100_disk3.c \ + ${ALTAIRZ80D}/s100_fif.c ${ALTAIRZ80D}/s100_mdriveh.c \ + ${ALTAIRZ80D}/s100_mdsad.c ${ALTAIRZ80D}/s100_selchan.c \ + ${ALTAIRZ80D}/s100_ss1.c ${ALTAIRZ80D}/s100_64fdc.c \ + ${ALTAIRZ80D}/s100_scp300f.c ${ALTAIRZ80D}/sim_imd.c \ + ${ALTAIRZ80D}/wd179x.c ${ALTAIRZ80D}/s100_hdc1001.c \ + ${ALTAIRZ80D}/s100_if3.c ${ALTAIRZ80D}/s100_adcs6.c \ + ${ALTAIRZ80D}/m68kcpu.c ${ALTAIRZ80D}/m68kdasm.c \ + ${ALTAIRZ80D}/m68kopac.c ${ALTAIRZ80D}/m68kopdm.c \ + ${ALTAIRZ80D}/m68kopnz.c ${ALTAIRZ80D}/m68kops.c ${ALTAIRZ80D}/m68ksim.c +ALTAIRZ80_OPT = -I ${ALTAIRZ80D} + + +GRID = GRI +GRI = ${GRID}/gri_cpu.c ${GRID}/gri_stddev.c ${GRID}/gri_sys.c +GRI_OPT = -I ${GRID} + + +LGPD = LGP +LGP = ${LGPD}/lgp_cpu.c ${LGPD}/lgp_stddev.c ${LGPD}/lgp_sys.c +LGP_OPT = -I ${LGPD} + + +SDSD = SDS +SDS = ${SDSD}/sds_cpu.c ${SDSD}/sds_drm.c ${SDSD}/sds_dsk.c ${SDSD}/sds_io.c \ + ${SDSD}/sds_lp.c ${SDSD}/sds_mt.c ${SDSD}/sds_mux.c ${SDSD}/sds_rad.c \ + ${SDSD}/sds_stddev.c ${SDSD}/sds_sys.c +SDS_OPT = -I ${SDSD} + +SWTP6800D = swtp6800/swtp6800 +SWTP6800C = swtp6800/common +SWTP6800MP-A = ${SWTP6800C}/mp-a.c ${SWTP6800C}/m6800.c ${SWTP6800C}/m6810.c \ + ${SWTP6800C}/bootrom.c ${SWTP6800C}/dc-4.c ${SWTP6800C}/mp-s.c ${SWTP6800D}/mp-a_sys.c \ + ${SWTP6800C}/mp-b2.c ${SWTP6800C}/mp-8m.c +SWTP6800MP-A2 = ${SWTP6800C}/mp-a2.c ${SWTP6800C}/m6800.c ${SWTP6800C}/m6810.c \ + ${SWTP6800C}/bootrom.c ${SWTP6800C}/dc-4.c ${SWTP6800C}/mp-s.c ${SWTP6800D}/mp-a2_sys.c \ + ${SWTP6800C}/mp-b2.c ${SWTP6800C}/mp-8m.c ${SWTP6800C}/i2716.c +SWTP6800_OPT = -I ${SWTP6800D} + +TX0D = TX-0 +TX0 = ${TX0D}/tx0_cpu.c ${TX0D}/tx0_dpy.c ${TX0D}/tx0_stddev.c \ + ${TX0D}/tx0_sys.c ${TX0D}/tx0_sys_orig.c ${DISPLAYL} +TX0_OPT = -I ${TX0D} $(DISPLAY_OPT) + + +SSEMD = SSEM +SSEM = ${SSEMD}/ssem_cpu.c ${SSEMD}/ssem_sys.c +SSEM_OPT = -I ${SSEMD} + +System_80-10D = Intel/System_80-10 +iCOMMOND = Intel/common +System_80-10 = ${iCOMMOND}/i8251.c ${iCOMMOND}/i8255.c ${iCOMMOND}/i8080.c \ + ${iCOMMOND}/multibus.c ${iCOMMOND}/iSBC80-10.c \ + ${System_80-10D}/system_80_10_sys.c ${iCOMMOND}/isbc208.c \ + ${iCOMMOND}/isbc064.c ${iCOMMOND}/ieprom.c ${iCOMMOND}/iram8.c +System_80-10_OPT = -I ${System_80-10D} + + +System_80-20D = Intel/System_80-20 +iCOMMOND = Intel/common +System_80-20 = ${iCOMMOND}/i8251.c ${iCOMMOND}/i8255.c ${iCOMMOND}/i8080.c \ + ${iCOMMOND}/multibus.c ${iCOMMOND}/iSBC80-20.c \ + ${System_80-20D}/system_80_20_sys.c ${iCOMMOND}/isbc208.c \ + ${iCOMMOND}/isbc064.c ${iCOMMOND}/ieprom.c ${iCOMMOND}/iram8.c \ + ${iCOMMOND}/i8259.c +System_80-20_OPT = -I ${System_80-20D} + + +System_80-30D = Intel/System_80-30 +iCOMMOND = Intel/common +System_80-30 = ${iCOMMOND}/i8251.c ${iCOMMOND}/i8255.c ${iCOMMOND}/i8080.c \ + ${iCOMMOND}/multibus.c ${iCOMMOND}/iSBC80-20.c \ + ${System_80-30D}/system_80_30_sys.c ${iCOMMOND}/isbc208.c \ + ${iCOMMOND}/isbc064.c ${iCOMMOND}/ieprom.c ${iCOMMOND}/iram8.c \ + ${iCOMMOND}/i8259.c +System_80-30_OPT = -I ${System_80-30D} + + +# +# Build everything +# +#ALL = pdp1 pdp4 pdp7 pdp8 pdp9 pdp15 pdp11 pdp10 +# vax microvax3900 microvax1 rtvax1000 microvax2 vax730 vax750 vax780 vax8600 +# nova eclipse hp2100 i1401 i1620 s3 altair altairz80 gri +## swtp6800mp-a swtp6800mp-a2 tx-0 ssem +ALL = System_80-10 + +all : ${ALL} + +clean : +ifeq ($(WIN32),) + ${RM} -r ${BIN} +else + if exist BIN\*.exe del /q BIN\*.exe + if exist BIN rmdir BIN +endif + +${BIN}BuildROMs${EXE} : + ${MKDIRBIN} +ifeq (agcc,$(findstring agcc,$(firstword $(CC)))) + gcc $(wordlist 2,1000,${CC}) sim_BuildROMs.c $(CC_OUTSPEC) +else + ${CC} sim_BuildROMs.c $(CC_OUTSPEC) +endif +ifeq ($(WIN32),) + $@ + ${RM} $@ + ifeq (Darwin,$(OSTYPE)) # remove Xcode's debugging symbols folder too + ${RM} -rf $@.dSYM + endif +else + $(@D)\$(@F) + del $(@D)\$(@F) +endif + +# +# Individual builds +# +System_80-10 : ${BIN}System_80-10${EXE} + +${BIN}System_80-10${EXE} : ${System_80-10} ${SIM} + ${MKDIRBIN} + ${CC} ${System_80-10} ${SIM} ${System_80-10_OPT} -o $@ ${LDFLAGS} + +System_80-20 : ${BIN}System_80-20${EXE} + +${BIN}System_80-20${EXE} : ${System_80-20} ${SIM} + ${MKDIRBIN} + ${CC} ${System_80-20} ${SIM} ${System_80-20_OPT} -o $@ ${LDFLAGS} + +System_80-30 : ${BIN}System_80-30${EXE} + +${BIN}System_80-30${EXE} : ${System_80-30} ${SIM} + ${MKDIRBIN} + ${CC} ${System_80-30} ${SIM} ${System_80-30_OPT} -o $@ ${LDFLAGS} + +pdp1 : ${BIN}pdp1${EXE} + +${BIN}pdp1${EXE} : ${PDP1} ${SIM} + ${MKDIRBIN} + ${CC} ${PDP1} ${SIM} ${PDP1_OPT} $(CC_OUTSPEC) ${LDFLAGS} + +pdp4 : ${BIN}pdp4${EXE} + +${BIN}pdp4${EXE} : ${PDP18B} ${SIM} + ${MKDIRBIN} + ${CC} ${PDP18B} ${SIM} ${PDP4_OPT} $(CC_OUTSPEC) ${LDFLAGS} + +pdp7 : ${BIN}pdp7${EXE} + +${BIN}pdp7${EXE} : ${PDP18B} ${SIM} + ${MKDIRBIN} + ${CC} ${PDP18B} ${SIM} ${PDP7_OPT} $(CC_OUTSPEC) ${LDFLAGS} + +pdp8 : ${BIN}pdp8${EXE} + +${BIN}pdp8${EXE} : ${PDP8} ${SIM} + ${MKDIRBIN} + ${CC} ${PDP8} ${SIM} ${PDP8_OPT} $(CC_OUTSPEC) ${LDFLAGS} + +pdp9 : ${BIN}pdp9${EXE} + +${BIN}pdp9${EXE} : ${PDP18B} ${SIM} + ${MKDIRBIN} + ${CC} ${PDP18B} ${SIM} ${PDP9_OPT} $(CC_OUTSPEC) ${LDFLAGS} + +pdp15 : ${BIN}pdp15${EXE} + +${BIN}pdp15${EXE} : ${PDP18B} ${SIM} + ${MKDIRBIN} + ${CC} ${PDP18B} ${SIM} ${PDP15_OPT} $(CC_OUTSPEC) ${LDFLAGS} + +pdp10 : ${BIN}pdp10${EXE} + +${BIN}pdp10${EXE} : ${PDP10} ${SIM} + ${MKDIRBIN} + ${CC} ${PDP10} ${SIM} ${PDP10_OPT} $(CC_OUTSPEC) ${LDFLAGS} + +pdp11 : ${BIN}pdp11${EXE} + +${BIN}pdp11${EXE} : ${PDP11} ${SIM} + ${MKDIRBIN} + ${CC} ${PDP11} ${SIM} ${PDP11_OPT} $(CC_OUTSPEC) ${LDFLAGS} + +vax : microvax3900 + +microvax3900 : ${BIN}microvax3900${EXE} + +${BIN}microvax3900${EXE} : ${VAX} ${SIM} ${BUILD_ROMS} + ${MKDIRBIN} + ${CC} ${VAX} ${SIM} ${VAX_OPT} $(CC_OUTSPEC) ${LDFLAGS} +ifeq ($(WIN32),) + cp ${BIN}microvax3900${EXE} ${BIN}vax${EXE} +else + copy $(@D)\microvax3900${EXE} $(@D)\vax${EXE} +endif + +microvax1 : ${BIN}microvax1${EXE} + +${BIN}microvax1${EXE} : ${VAX610} ${SIM} ${BUILD_ROMS} + ${MKDIRBIN} + ${CC} ${VAX610} ${SIM} ${VAX610_OPT} -o $@ ${LDFLAGS} + +rtvax1000 : ${BIN}rtvax1000${EXE} + +${BIN}rtvax1000${EXE} : ${VAX630} ${SIM} ${BUILD_ROMS} + ${MKDIRBIN} + ${CC} ${VAX630} ${SIM} ${VAX620_OPT} -o $@ ${LDFLAGS} + +microvax2 : ${BIN}microvax2${EXE} + +${BIN}microvax2${EXE} : ${VAX630} ${SIM} ${BUILD_ROMS} + ${MKDIRBIN} + ${CC} ${VAX630} ${SIM} ${VAX630_OPT} -o $@ ${LDFLAGS} + +vax730 : ${BIN}vax730${EXE} + +${BIN}vax730${EXE} : ${VAX730} ${SIM} ${BUILD_ROMS} + ${MKDIRBIN} + ${CC} ${VAX730} ${SIM} ${VAX730_OPT} -o $@ ${LDFLAGS} + +vax750 : ${BIN}vax750${EXE} + +${BIN}vax750${EXE} : ${VAX750} ${SIM} ${BUILD_ROMS} + ${MKDIRBIN} + ${CC} ${VAX750} ${SIM} ${VAX750_OPT} -o $@ ${LDFLAGS} + +vax780 : ${BIN}vax780${EXE} + +${BIN}vax780${EXE} : ${VAX780} ${SIM} ${BUILD_ROMS} + ${MKDIRBIN} + ${CC} ${VAX780} ${SIM} ${VAX780_OPT} $(CC_OUTSPEC) ${LDFLAGS} + +vax8600 : ${BIN}vax8600${EXE} + +${BIN}vax8600${EXE} : ${VAX8600} ${SIM} ${BUILD_ROMS} + ${MKDIRBIN} + ${CC} ${VAX8600} ${SIM} ${VAX8600_OPT} $(CC_OUTSPEC) ${LDFLAGS} + +nova : ${BIN}nova${EXE} + +${BIN}nova${EXE} : ${NOVA} ${SIM} + ${MKDIRBIN} + ${CC} ${NOVA} ${SIM} ${NOVA_OPT} $(CC_OUTSPEC) ${LDFLAGS} + +eclipse : ${BIN}eclipse${EXE} + +${BIN}eclipse${EXE} : ${ECLIPSE} ${SIM} + ${MKDIRBIN} + ${CC} ${ECLIPSE} ${SIM} ${ECLIPSE_OPT} $(CC_OUTSPEC) ${LDFLAGS} + +h316 : ${BIN}h316${EXE} + +${BIN}h316${EXE} : ${H316} ${SIM} + ${MKDIRBIN} + ${CC} ${H316} ${SIM} ${H316_OPT} $(CC_OUTSPEC) ${LDFLAGS} + +hp2100 : ${BIN}hp2100${EXE} + +${BIN}hp2100${EXE} : ${HP2100} ${SIM} + ${MKDIRBIN} + ${CC} ${HP2100} ${SIM} ${HP2100_OPT} $(CC_OUTSPEC) ${LDFLAGS} + +i1401 : ${BIN}i1401${EXE} + +${BIN}i1401${EXE} : ${I1401} ${SIM} + ${MKDIRBIN} + ${CC} ${I1401} ${SIM} ${I1401_OPT} $(CC_OUTSPEC) ${LDFLAGS} + +i1620 : ${BIN}i1620${EXE} + +${BIN}i1620${EXE} : ${I1620} ${SIM} + ${MKDIRBIN} + ${CC} ${I1620} ${SIM} ${I1620_OPT} $(CC_OUTSPEC) ${LDFLAGS} + +i7094 : ${BIN}i7094${EXE} + +${BIN}i7094${EXE} : ${I7094} ${SIM} + ${MKDIRBIN} + ${CC} ${I7094} ${SIM} ${I7094_OPT} $(CC_OUTSPEC) ${LDFLAGS} + +ibm1130 : ${BIN}ibm1130${EXE} + +${BIN}ibm1130${EXE} : ${IBM1130} + ${MKDIRBIN} +ifneq ($(WIN32),) + windres ${IBM1130D}/ibm1130.rc $(BIN)ibm1130.o + ${CC} ${IBM1130} ${SIM} ${IBM1130_OPT} $(BIN)ibm1130.o $(CC_OUTSPEC) ${LDFLAGS} + del BIN\ibm1130.o +else + ${CC} ${IBM1130} ${SIM} ${IBM1130_OPT} $(CC_OUTSPEC) ${LDFLAGS} +endif + +s3 : ${BIN}s3${EXE} + +${BIN}s3${EXE} : ${S3} ${SIM} + ${MKDIRBIN} + ${CC} ${S3} ${SIM} ${S3_OPT} $(CC_OUTSPEC) ${LDFLAGS} + +altair : ${BIN}altair${EXE} + +${BIN}altair${EXE} : ${ALTAIR} ${SIM} + ${MKDIRBIN} + ${CC} ${ALTAIR} ${SIM} ${ALTAIR_OPT} $(CC_OUTSPEC) ${LDFLAGS} + +altairz80 : ${BIN}altairz80${EXE} + +${BIN}altairz80${EXE} : ${ALTAIRZ80} ${SIM} + ${MKDIRBIN} + ${CC} ${ALTAIRZ80} ${SIM} ${ALTAIRZ80_OPT} $(CC_OUTSPEC) ${LDFLAGS} + +gri : ${BIN}gri${EXE} + +${BIN}gri${EXE} : ${GRI} ${SIM} + ${MKDIRBIN} + ${CC} ${GRI} ${SIM} ${GRI_OPT} $(CC_OUTSPEC) ${LDFLAGS} + +lgp : ${BIN}lgp${EXE} + +${BIN}lgp${EXE} : ${LGP} ${SIM} + ${MKDIRBIN} + ${CC} ${LGP} ${SIM} ${LGP_OPT} $(CC_OUTSPEC) ${LDFLAGS} + +id16 : ${BIN}id16${EXE} + +${BIN}id16${EXE} : ${ID16} ${SIM} + ${MKDIRBIN} + ${CC} ${ID16} ${SIM} ${ID16_OPT} $(CC_OUTSPEC) ${LDFLAGS} + +id32 : ${BIN}id32${EXE} + +${BIN}id32${EXE} : ${ID32} ${SIM} + ${MKDIRBIN} + ${CC} ${ID32} ${SIM} ${ID32_OPT} $(CC_OUTSPEC) ${LDFLAGS} + +sds : ${BIN}sds${EXE} + +${BIN}sds${EXE} : ${SDS} ${SIM} + ${MKDIRBIN} + ${CC} ${SDS} ${SIM} ${SDS_OPT} $(CC_OUTSPEC) ${LDFLAGS} + +swtp6800mp-a : ${BIN}swtp6800mp-a${EXE} + +${BIN}swtp6800mp-a${EXE} : ${SWTP6800MP-A} ${SIM} ${BUILD_ROMS} + ${MKDIRBIN} + ${CC} ${SWTP6800MP-A} ${SIM} ${SWTP6800_OPT} $(CC_OUTSPEC) ${LDFLAGS} + +swtp6800mp-a2 : ${BIN}swtp6800mp-a2${EXE} + +${BIN}swtp6800mp-a2${EXE} : ${SWTP6800MP-A2} ${SIM} ${BUILD_ROMS} + ${MKDIRBIN} + ${CC} ${SWTP6800MP-A2} ${SIM} ${SWTP6800_OPT} $(CC_OUTSPEC) ${LDFLAGS} + +tx-0 : ${BIN}tx-0${EXE} + +${BIN}tx-0${EXE} : ${TX0} ${SIM} + ${MKDIRBIN} + ${CC} ${TX0} ${SIM} ${TX0_OPT} $(CC_OUTSPEC) ${LDFLAGS} + +ssem : ${BIN}ssem${EXE} + +${BIN}ssem${EXE} : ${SSEM} ${SIM} + ${MKDIRBIN} + ${CC} ${SSEM} ${SIM} ${SSEM_OPT} $(CC_OUTSPEC) ${LDFLAGS} +