diff --git a/IBMPC-Systems/common/i8008.c b/IBMPC-Systems/common/i8008.c new file mode 100644 index 00000000..48b30c86 --- /dev/null +++ b/IBMPC-Systems/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(); + sim_printf("\n"); + } + + if (sim_interval <= 0) { /* check clock queue */ + if (reason = sim_process_event()) + break; + } + sim_interval--; /* countdown clock */ + + if (int_req > 0) { /* interrupt? */ +// sim_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; +// sim_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(); + sim_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) +{ + sim_printf(" A=%02X B=%02X C=%02X D=%04X E=%02X H=%04X L=%02X\n", + A, B, C, D, E, H, L); + sim_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 */ + sim_printf("OP=%02X %04X %s", val, PC, opcode[val]); + break; + case 1: /* byte operand fetch */ + sim_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 */ + sim_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'); + sim_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 */ + sim_printf ("%d Bytes loaded.\n", cnt); + return (SCPE_OK); +} + +/* Symbolic output + + Inputs: + *of = output stream + addr = current PC + *val = pointer to values + *uptr = pointer to unit + sw = switches + Outputs: + status = error code +*/ + +t_stat fprint_sym (FILE *of, t_addr addr, t_value *val, + UNIT *uptr, int32 sw) +{ + int32 cflag, c1, c2, inst, adr; + + cflag = (uptr == NULL) || (uptr == &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/IBMPC-Systems/common/i8080.c b/IBMPC-Systems/common/i8080.c new file mode 100644 index 00000000..3d0f5ccc --- /dev/null +++ b/IBMPC-Systems/common/i8080.c @@ -0,0 +1,1445 @@ +/* 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 */ +uint8 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 uint8 get_mbyte(uint16 addr); +extern uint16 get_mword(uint16 addr); +extern void put_mbyte(uint16 addr, uint8 val); +extern void put_mword(uint16 addr, uint16 val); +extern int32 sim_int_char; +extern uint32 sim_brk_types, sim_brk_dflt, sim_brk_summ; /* breakpoint info */ + + +struct idev { + uint8 (*routine)(t_bool, uint8, uint8); + uint8 devnum; +}; + +/* 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 */ +const 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, 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) + sim_printf("CPU = 8085\n"); + else + sim_printf("CPU = 8080\n"); + } + /* Main instruction fetch/decode loop */ + + while (reason == 0) { /* loop until halted */ + + saved_PC = PC; + +// if (PC == 0x1000) { /* turn on debugging */ +// i8080_dev.dctrl = DEBUG_asm + DEBUG_reg; +// reason = STOP_HALT; +// } + if (i8080_dev.dctrl & DEBUG_reg) { + dumpregs(); + sim_printf("\n"); + } + + if (sim_interval <= 0) { /* check clock queue */ + if ((reason = sim_process_event())) + break; + } + sim_interval--; /* countdown clock */ + + if (int_req > 0) { /* interrupt? */ +// sim_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; +// sim_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(); + sim_printf("\n"); + } + IR = OP = fetch_byte(0); /* instruction fetch */ + + if (GET_XACK(1) == 0) { /* no XACK for instruction fetch */ + reason = STOP_XACK; + sim_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; +// sim_printf("\nEI: pc=%04X", PC - 1); + break; + + case 0xF3: /* DI */ + IM &= ~IE; +// sim_printf("\nDI: pc=%04X", PC - 1); + break; + + case 0xDB: /* IN */ + DAR = fetch_byte(1); + A = dev_table[DAR].routine(0, 0, dev_table[DAR].devnum); + A &= BYTE_R; +// sim_printf("\n%04X\tIN\t%02X\t;devnum=%d", PC - 1, DAR, dev_table[DAR].devnum); + break; + + case 0xD3: /* OUT */ + DAR = fetch_byte(1); + dev_table[DAR].routine(1, A, dev_table[DAR].devnum); +// sim_printf("\n%04X\tOUT\t%02X\t;devnum=%d", PC - 1, DAR, dev_table[DAR].devnum); + 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; + sim_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) +{ + sim_printf(" A=%02X BC=%04X DE=%04X HL=%04X SP=%04X IM=%02X XACK=%d\n", + A, BC, DE, HL, SP, IM, xack); + sim_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 */ + sim_printf("OP=%02X %04X %s", val, PC, opcode[val]); + break; + case 1: /* byte operand fetch */ + sim_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 */ + sim_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 */ +// sim_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 */ +// sim_printf("reg=%04X val=%04X\n", reg, val); + BC = BC & BYTE_R; +// sim_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'); + sim_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, CONST char *cptr, CONST 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 */ + sim_printf ("%d Bytes loaded.\n", cnt); + return (SCPE_OK); +} + +/* Symbolic output + + Inputs: + *of = output stream + addr = current PC + *val = pointer to values + *uptr = pointer to unit + sw = switches + Outputs: + status = error code +*/ + +t_stat fprint_sym (FILE *of, t_addr addr, t_value *val, + UNIT *uptr, int32 sw) +{ + int32 cflag, c1, c2, inst, adr; + + cflag = (uptr == NULL) || (uptr == &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, "%02X", 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, "%04X", 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 (CONST 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); +} + +/* end of i8080.c */ diff --git a/IBMPC-Systems/common/i8088.c b/IBMPC-Systems/common/i8088.c new file mode 100644 index 00000000..73934076 --- /dev/null +++ b/IBMPC-Systems/common/i8088.c @@ -0,0 +1,4750 @@ +/* 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. + + 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 "system_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 & ADDRMASK16) /* increment IP one byte */ +#define INC_IP2 ((IP += 2) & ADDRMASK16) /* 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 0x01 = int, 0x02 = NMI*/ +uint16 port; //port called in dev_table[port] +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 function prototypes */ +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 */ +void set_cpuint(int32 int_num); +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 */ + +/* memory read and write absolute address routines */ +extern uint8 get_mbyte(uint32 addr); +extern uint16 get_mword(uint32 addr); +extern void put_mbyte(uint32 addr, uint8 val); +extern void put_mword(uint32 addr, uint16 val); + +extern int32 sim_int_char; +extern uint32 sim_brk_types, sim_brk_dflt, sim_brk_summ; /* breakpoint info */ + +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 = { + "8088", //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 +// DEBUG_reg+DEBUG_asm, //dctrl + DEBUG_asm, //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", +"60 ", "61 ", "62 ", "63 ", /* 0x60 */ +"64 ", "65 ", "66 ", "67 ", +"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", +"80 ", "81 ", "82 ", "83 ", /* 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," +"C0 ", "C1 ", "RET ", "RET ", /* 0xC0 */ +"LES ", "LDS ", "MOV ", "MOV ", +"C8 ", "C9 ", "RET ", "RET", +"INT 3", "INT ", "INTO", "IRET", +"SHL ", "D1 ", "SHR ", "D3 ", /* 0xD0 */ +"AAM", "AAD", "D6 ", "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", "F1 ", "REPNZ", "REPZ", /* 0xF0 */ +"HLT", "CMC", "F6 ", "F7 ", +"CLC", "STC", "CLI", "STI", +"CLD", "STD", "FE ", "FF " + }; + +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 +}; + +void set_cpuint(int32 int_num) +{ + int_req |= int_num; +} + + +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) + sim_printf("\n"); + + 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 */ + + /* The Big Instruction Decode Switch */ + + switch (IR) { + + /* instructions in numerical order */ + + 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 */ + 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_smword(seg_reg, EA, VAL); /* store result *** */ + } else { /* RM is second register */ + VAL = adc_word(get_rword(REG), get_rword(RM)); /* do operation */ + put_rword(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_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 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_rword(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_smword(seg_reg, EA, VAL); /* store result *** */ + } else { /* RM is second register */ + VAL = adc_word(get_rword(REG), get_rword(RM)); /* do operation */ + put_rword(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_rword(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_smword(seg_reg, EA, VAL); /* store result *** */ + } else { /* RM is second register */ + VAL = sbb_word(get_rword(REG), get_rword(RM)); /* do operation */ + put_rword(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_rword(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_smword(seg_reg, EA, VAL); /* store result *** */ + } else { /* RM is second register */ + VAL = and_word(get_rword(REG), get_rword(RM)); /* do operation */ + put_rword(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_rword(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_smword(seg_reg, EA, VAL); /* store result *** */ + } else { /* RM is second register */ + VAL = sub_word(get_rword(REG), get_rword(RM)); /* do operation */ + put_rword(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_rword(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_smword(seg_reg, EA, VAL); /* store result *** */ + } else { /* RM is second register */ + VAL = xor_word(get_rword(REG), get_rword(RM)); /* do operation */ + put_rword(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_rword(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_smword(seg_reg, EA, VAL); /* store result *** */ + } else { /* RM is second register */ + VAL = xor_word(get_rword(REG), get_rword(RM)); /* do operation */ + put_rword(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: /* INT0 */ + 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 = sign_ext(OFF); + 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 = sign_ext(OFF); + 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 = sign_ext(OFF); + OFF += (int16)IP; + CX -= 1; + if (CX != 0) /* CX != 0 */ + IP = OFF; + break; + + case 0xE3: /* JCXZ label */ + OFF = fetch_byte(1); + OFF = sign_ext(OFF); + OFF += (int16)IP; + if (CX == 0) /* CX != 0 */ + IP = OFF; + break; + + case 0xE4: /* IN AL, port8 */ + OFF = fetch_byte(1); + port = OFF; + AL = dev_table[OFF].routine(0, 0); + break; + + case 0xE5: /* IN AX, port8 */ + OFF = fetch_byte(1); + port = OFF; + AH = dev_table[OFF].routine(0, 0); + AL = dev_table[OFF+1].routine(0, 0); + break; + + case 0xE6: /* OUT AL, port8 */ + OFF = fetch_byte(1); + port = OFF; + dev_table[OFF].routine(1, AL); + //sim_printf("OUT AL: OFF=%04X\n", OFF); + break; + + case 0xE7: /* OUT AX, port8 */ + OFF = fetch_byte(1); + port = OFF; + 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 */ + port = DX; + AL = dev_table[DX].routine(0, 0); + break; + + case 0xED: /* IN AX,DX */ + port = DX; + AH = dev_table[DX].routine(0, 0); + AL = dev_table[DX+1].routine(0, 0); + break; + + case 0xEE: /* OUT AL,DX */ + port = DX; + dev_table[DX].routine(1, AL); + break; + + case 0xEF: /* OUT AX,DX */ + port = 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; + } + if (i8088_dev.dctrl & DEBUG_reg) { + sim_printf("\nRegs: 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); + sim_printf("Segs: CS=%04X DS=%04X ES=%04X SS=%04X Flags: %04X\n", CS, DS, ES, SS, PSW); + } + } +/* 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 */ +// sim_printf("%04X:%04X %02X", CS, IP, val); + if (i8088_dev.dctrl & DEBUG_asm) + sim_printf("%04X:%04X %s", CS, IP, opcode[val]); + break; + case 1: /* byte operand fetch */ + if (i8088_dev.dctrl & DEBUG_asm) + sim_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) + sim_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) + sim_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 algorithms 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(SEG_SS, SP, val >> 8); + SP--; + put_smbyte(SEG_SS, SP, val & 0xFF); +} + +/* pop word primitive */ +uint16 pop_word(void) +{ + register uint16 res; + + //sim_printf("pop_word: entered SS=%04X SP=%04X\n", get_rword(SEG_SS), SP); + res = get_smbyte(SEG_SS, SP); + SP++; + //sim_printf("pop_word: first byte=%04X SS=%04X SP=%04X\n", res, get_rword(SEG_SS), SP); + res |= (get_smbyte(SEG_SS, SP) << 8); + SP++; + //sim_printf("pop_word: val=%04X SS=%04X SP=%04X\n", res, get_rword(SEG_SS), 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); + //sim_printf("get_smbyte: seg=%04X addr=%04X abs_addr=%05X val=%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); + //sim_printf("put_smbyte: seg=%04X addr=%04X abs_addr=%08X val=%02X\n", + //get_rword(segreg), addr, 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'); + sim_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. +*/ + +t_stat sim_load (FILE *fileref, const char *cptr, const 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 */ + sim_printf ("%d Bytes loaded.\n", cnt); + return (SCPE_OK); +} + +/* Symbolic output + + Inputs: + *of = output stream + addr = current PC + *val = pointer to values + *uptr = pointer to unit + sw = switches + Outputs: + status = error code +*/ + +t_stat fprint_sym (FILE *of, t_addr addr, t_value *val, + UNIT *uptr, int32 sw) +{ + int32 cflag, c1, c2, inst, adr; + + cflag = (uptr == NULL) || (uptr == &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 +*/ + +t_stat parse_sym (const 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 == &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); +} + +/* end of i8088.c */ + diff --git a/IBMPC-Systems/common/i8237.c b/IBMPC-Systems/common/i8237.c new file mode 100644 index 00000000..2db649c7 --- /dev/null +++ b/IBMPC-Systems/common/i8237.c @@ -0,0 +1,872 @@ +/* i8237.c: Intel 8237 DMA adapter + + Copyright (c) 2016, 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. + + MODIFICATIONS: + + 11 Jul 16 - Original file. + + NOTES: + + + 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 + 0A Write Set/Reset DMAC Mask Register + 0B Write Load DMAC Mode Register + 0C Write Clear DMAC First/Last Flip-Flop + 0D Write DMAC Master Clear + 0F Write Load DMAC Mask Register + + 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 + +*/ + +#include "system_defs.h" + +/* external globals */ + +extern uint16 port; //port called in dev_table[port] + +/* globals */ + +int32 i8237_devnum = 0; //actual number of 8253 instances + 1 +uint16 i8237_port[4]; //base port registered to each instance + +/* internal function prototypes */ + +t_stat i8237_svc (UNIT *uptr); +t_stat i8237_reset (DEVICE *dptr, uint16 base); +void i8237_reset1 (void); +t_stat i8237_set_mode (UNIT *uptr, int32 val, CONST char *cptr, void *desc); +uint8 i8237_r0x(t_bool io, uint8 data); +uint8 i8237_r1x(t_bool io, uint8 data); +uint8 i8237_r2x(t_bool io, uint8 data); +uint8 i8237_r3x(t_bool io, uint8 data); +uint8 i8237_r4x(t_bool io, uint8 data); +uint8 i8237_r5x(t_bool io, uint8 data); +uint8 i8237_r6x(t_bool io, uint8 data); +uint8 i8237_r7x(t_bool io, uint8 data); +uint8 i8237_r8x(t_bool io, uint8 data); +uint8 i8237_r9x(t_bool io, uint8 data); +uint8 i8237_rAx(t_bool io, uint8 data); +uint8 i8237_rBx(t_bool io, uint8 data); +uint8 i8237_rCx(t_bool io, uint8 data); +uint8 i8237_rDx(t_bool io, uint8 data); +uint8 i8237_rEx(t_bool io, uint8 data); +uint8 i8237_rFx(t_bool io, uint8 data); + +/* external function prototypes */ + +extern uint16 reg_dev(uint8 (*routine)(t_bool, uint8), uint16); + +/* 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 +uint8 i8237_rE; // 8237 +uint8 i8237_rF; // 8237 + +/* i8237 physical register definitions */ + +uint16 i8237_sr; // isbc-208 segment register +uint8 i8237_i; // iSBC-208 interrupt register +uint8 i8237_a; // iSBC-208 auxillary port register + +/* i8237 Standard SIMH Device Data Structures - 1 unit */ + +UNIT i8237_unit[] = { + { UDATA (0, 0, 0) ,20 }, /* i8237 0 */ + { UDATA (0, 0, 0) ,20 }, /* i8237 1 */ + { UDATA (0, 0, 0) ,20 }, /* i8237 2 */ + { UDATA (0, 0, 0) ,20 } /* i8237 3 */ +}; + + +REG i8237_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 (SEGREG, i8237_sr, 8) }, + { HRDATA (AUX, i8237_a, 8) }, + { HRDATA (INT, i8237_i, 8) }, + { NULL } +}; + +MTAB i8237_mod[] = { + { 0 } +}; + +DEBTAB i8237_debug[] = { + { "ALL", DEBUG_all }, + { "FLOW", DEBUG_flow }, + { "READ", DEBUG_read }, + { "WRITE", DEBUG_write }, + { "LEV1", DEBUG_level1 }, + { "LEV2", DEBUG_level2 }, + { "REG", DEBUG_reg }, + { NULL } +}; + +DEVICE i8237_dev = { + "8237", //name + i8237_unit, //units + i8237_reg, //registers + i8237_mod, //modifiers + 1, //numunits + 16, //aradix + 32, //awidth + 1, //aincr + 16, //dradix + 8, //dwidth + NULL, //examine + NULL, //deposit +// &i8237_reset, //deposit + NULL, //reset + NULL, //boot + NULL, //attach + NULL, //detach + NULL, //ctxt + DEV_DEBUG+DEV_DISABLE+DEV_DIS, //flags + 0, //dctrl +// DEBUG_flow + DEBUG_read + DEBUG_write, //dctrl + i8237_debug, //debflags + NULL, //msize + NULL //lname +}; + +/* Service routines to handle simulator functions */ + +/* service routine - actually does the simulated DMA */ + +t_stat i8237_svc(UNIT *uptr) +{ + sim_printf("uptr=%08X\n", uptr); + sim_activate (&i8237_unit[uptr->u6], i8237_unit[uptr->u6].wait); + return SCPE_OK; +} + +/* Reset routine */ + +t_stat i8237_reset(DEVICE *dptr, uint16 base) +{ + if (i8237_devnum > I8237_NUM) { + sim_printf("i8237_reset: too many devices!\n"); + return SCPE_MEM; + } + i8237_port[i8237_devnum] = reg_dev(i8237_r0x, base); + reg_dev(i8237_r1x, base + 1); + reg_dev(i8237_r2x, base + 2); + reg_dev(i8237_r3x, base + 3); + reg_dev(i8237_r4x, base + 4); + reg_dev(i8237_r5x, base + 5); + reg_dev(i8237_r6x, base + 6); + reg_dev(i8237_r7x, base + 7); + reg_dev(i8237_r8x, base + 8); + reg_dev(i8237_r9x, base + 9); + reg_dev(i8237_rAx, base + 10); + reg_dev(i8237_rBx, base + 11); + reg_dev(i8237_rCx, base + 12); + reg_dev(i8237_rDx, base + 13); + reg_dev(i8237_rEx, base + 14); + reg_dev(i8237_rFx, base + 15); + sim_printf(" 8237 Reset\n"); + sim_printf(" 8237: Registered at %03X\n", base); + sim_activate (&i8237_unit[i8237_devnum], i8237_unit[i8237_devnum].wait); /* activate unit */ + if ((i8237_dev.flags & DEV_DIS) == 0) + i8237_reset1(); + i8237_devnum++; + return SCPE_OK; +} + +uint8 i8237_get_dn(void) +{ + int i; + + for (i=0; i=i8237_port[i] && port <= i8237_port[i] + 16) + return i; + sim_printf("i8237_get_dn: port %03X not in 8237 device table\n", port); + return 0xFF; +} + +void i8237_reset1(void) +{ + int32 i; + UNIT *uptr; + static int flag = 1; + + for (i = 0; i < 1; i++) { /* handle all units */ + uptr = i8237_dev.units + i; + if (uptr->capac == 0) { /* if not configured */ +// sim_printf(" SBC208%d: Not configured\n", i); +// if (flag) { +// sim_printf(" ALL: \"set isbc208 en\"\n"); +// sim_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! */ + sim_activate (&i8237_unit[uptr->u6], i8237_unit[uptr->u6].wait); + } else { +// sim_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 */ +} + + +/* i8237 set mode = 8- or 16-bit data bus */ +/* always 8-bit mode for current simulators */ + +t_stat i8237_set_mode(UNIT *uptr, int32 val, CONST char *cptr, void *desc) +{ + sim_debug (DEBUG_flow, &i8237_dev, " i8237_set_mode: Entered with val=%08XH uptr->flags=%08X\n", val, uptr->flags); + sim_debug (DEBUG_flow, &i8237_dev, " i8237_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. +*/ + +uint8 i8237_r0x(t_bool io, uint8 data) +{ + uint8 devnum; + + if ((devnum = i8237_get_dn()) != 0xFF) { + if (io == 0) { /* read current address CH 0 */ + if (i8237_rD) { /* high byte */ + i8237_rD = 0; + sim_debug (DEBUG_reg, &i8237_dev, "i8237_r0(H) read as %04X\n", i8237_r0); + return (i8237_r0 >> 8); + } else { /* low byte */ + i8237_rD++; + sim_debug (DEBUG_reg, &i8237_dev, "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); + sim_debug (DEBUG_reg, &i8237_dev, "i8237_r0(H) set to %04X\n", i8237_r0); + } else { /* low byte */ + i8237_rD++; + i8237_r0 = data & 0xFF; + sim_debug (DEBUG_reg, &i8237_dev, "i8237_r0(L) set to %04X\n", i8237_r0); + } + return 0; + } + } +} + +uint8 i8237_r1x(t_bool io, uint8 data) +{ + uint8 devnum; + + if ((devnum = i8237_get_dn()) != 0xFF) { + if (io == 0) { /* read current word count CH 0 */ + if (i8237_rD) { /* high byte */ + i8237_rD = 0; + sim_debug (DEBUG_reg, &i8237_dev, "i8237_r1(H) read as %04X\n", i8237_r1); + return (i8237_r1 >> 8); + } else { /* low byte */ + i8237_rD++; + sim_debug (DEBUG_reg, &i8237_dev, "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); + sim_debug (DEBUG_reg, &i8237_dev, "i8237_r1(H) set to %04X\n", i8237_r1); + } else { /* low byte */ + i8237_rD++; + i8237_r1 = data & 0xFF; + sim_debug (DEBUG_reg, &i8237_dev, "i8237_r1(L) set to %04X\n", i8237_r1); + } + return 0; + } + } +} + +uint8 i8237_r2x(t_bool io, uint8 data) +{ + uint8 devnum; + + if ((devnum = i8237_get_dn()) != 0xFF) { + if (io == 0) { /* read current address CH 1 */ + if (i8237_rD) { /* high byte */ + i8237_rD = 0; + sim_debug (DEBUG_reg, &i8237_dev, "i8237_r2(H) read as %04X\n", i8237_r2); + return (i8237_r2 >> 8); + } else { /* low byte */ + i8237_rD++; + sim_debug (DEBUG_reg, &i8237_dev, "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); + sim_debug (DEBUG_reg, &i8237_dev, "i8237_r2(H) set to %04X\n", i8237_r2); + } else { /* low byte */ + i8237_rD++; + i8237_r2 = data & 0xFF; + sim_debug (DEBUG_reg, &i8237_dev, "i8237_r2(L) set to %04X\n", i8237_r2); + } + return 0; + } + } +} + +uint8 i8237_r3x(t_bool io, uint8 data) +{ + uint8 devnum; + + if ((devnum = i8237_get_dn()) != 0xFF) { + if (io == 0) { /* read current word count CH 1 */ + if (i8237_rD) { /* high byte */ + i8237_rD = 0; + sim_debug (DEBUG_reg, &i8237_dev, "i8237_r3(H) read as %04X\n", i8237_r3); + return (i8237_r3 >> 8); + } else { /* low byte */ + i8237_rD++; + sim_debug (DEBUG_reg, &i8237_dev, "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); + sim_debug (DEBUG_reg, &i8237_dev, "i8237_r3(H) set to %04X\n", i8237_r3); + } else { /* low byte */ + i8237_rD++; + i8237_r3 = data & 0xFF; + sim_debug (DEBUG_reg, &i8237_dev, "i8237_r3(L) set to %04X\n", i8237_r3); + } + return 0; + } + } +} + +uint8 i8237_r4x(t_bool io, uint8 data) +{ + uint8 devnum; + + if ((devnum = i8237_get_dn()) != 0xFF) { + if (io == 0) { /* read current address CH 2 */ + if (i8237_rD) { /* high byte */ + i8237_rD = 0; + sim_debug (DEBUG_reg, &i8237_dev, "i8237_r4(H) read as %04X\n", i8237_r4); + return (i8237_r4 >> 8); + } else { /* low byte */ + i8237_rD++; + sim_debug (DEBUG_reg, &i8237_dev, "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); + sim_debug (DEBUG_reg, &i8237_dev, "i8237_r4(H) set to %04X\n", i8237_r4); + } else { /* low byte */ + i8237_rD++; + i8237_r4 = data & 0xFF; + sim_debug (DEBUG_reg, &i8237_dev, "i8237_r4(L) set to %04X\n", i8237_r4); + } + return 0; + } + } +} + +uint8 i8237_r5x(t_bool io, uint8 data) +{ + uint8 devnum; + + if ((devnum = i8237_get_dn()) != 0xFF) { + if (io == 0) { /* read current word count CH 2 */ + if (i8237_rD) { /* high byte */ + i8237_rD = 0; + sim_debug (DEBUG_reg, &i8237_dev, "i8237_r5(H) read as %04X\n", i8237_r5); + return (i8237_r5 >> 8); + } else { /* low byte */ + i8237_rD++; + sim_debug (DEBUG_reg, &i8237_dev, "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); + sim_debug (DEBUG_reg, &i8237_dev, "i8237_r5(H) set to %04X\n", i8237_r5); + } else { /* low byte */ + i8237_rD++; + i8237_r5 = data & 0xFF; + sim_debug (DEBUG_reg, &i8237_dev, "i8237_r5(L) set to %04X\n", i8237_r5); + } + return 0; + } + } +} + +uint8 i8237_r6x(t_bool io, uint8 data) +{ + uint8 devnum; + + if ((devnum = i8237_get_dn()) != 0xFF) { + if (io == 0) { /* read current address CH 3 */ + if (i8237_rD) { /* high byte */ + i8237_rD = 0; + sim_debug (DEBUG_reg, &i8237_dev, "i8237_r6(H) read as %04X\n", i8237_r6); + return (i8237_r6 >> 8); + } else { /* low byte */ + i8237_rD++; + sim_debug (DEBUG_reg, &i8237_dev, "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); + sim_debug (DEBUG_reg, &i8237_dev, "i8237_r6(H) set to %04X\n", i8237_r6); + } else { /* low byte */ + i8237_rD++; + i8237_r6 = data & 0xFF; + sim_debug (DEBUG_reg, &i8237_dev, "i8237_r6(L) set to %04X\n", i8237_r6); + } + return 0; + } + } +} + +uint8 i8237_r7x(t_bool io, uint8 data) +{ + uint8 devnum; + + if ((devnum = i8237_get_dn()) != 0xFF) { + if (io == 0) { /* read current word count CH 3 */ + if (i8237_rD) { /* high byte */ + i8237_rD = 0; + sim_debug (DEBUG_reg, &i8237_dev, "i8237_r7(H) read as %04X\n", i8237_r7); + return (i8237_r7 >> 8); + } else { /* low byte */ + i8237_rD++; + sim_debug (DEBUG_reg, &i8237_dev, "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); + sim_debug (DEBUG_reg, &i8237_dev, "i8237_r7(H) set to %04X\n", i8237_r7); + } else { /* low byte */ + i8237_rD++; + i8237_r7 = data & 0xFF; + sim_debug (DEBUG_reg, &i8237_dev, "i8237_r7(L) set to %04X\n", i8237_r7); + } + return 0; + } + } +} + +uint8 i8237_r8x(t_bool io, uint8 data) +{ + uint8 devnum; + + if ((devnum = i8237_get_dn()) != 0xFF) { + if (io == 0) { /* read status register */ + sim_debug (DEBUG_reg, &i8237_dev, "i8237_r8 (status) read as %02X\n", i8237_r8); + return (i8237_r8); + } else { /* write command register */ + i8237_r9 = data & 0xFF; + sim_debug (DEBUG_reg, &i8237_dev, "i8237_r9 (command) set to %02X\n", i8237_r9); + return 0; + } + } +} + +uint8 i8237_r9x(t_bool io, uint8 data) +{ + uint8 devnum; + + if ((devnum = i8237_get_dn()) != 0xFF) { + if (io == 0) { + sim_debug (DEBUG_reg, &i8237_dev, "Illegal read of i8237_r9\n"); + return 0; + } else { /* write request register */ + i8237_rC = data & 0xFF; + sim_debug (DEBUG_reg, &i8237_dev, "i8237_rC (request) set to %02X\n", i8237_rC); + return 0; + } + } +} + +uint8 i8237_rAx(t_bool io, uint8 data) +{ + uint8 devnum; + + if ((devnum = i8237_get_dn()) != 0xFF) { + if (io == 0) { + sim_debug (DEBUG_reg, &i8237_dev, "Illegal read of i8237_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; + } + sim_debug (DEBUG_reg, &i8237_dev, "i8237_rB (mask) set to %02X\n", i8237_rB); + return 0; + } + } +} + +uint8 i8237_rBx(t_bool io, uint8 data) +{ + uint8 devnum; + + if ((devnum = i8237_get_dn()) != 0xFF) { + if (io == 0) { + sim_debug (DEBUG_reg, &i8237_dev, "Illegal read of i8237_rB\n"); + return 0; + } else { /* write mode register */ + i8237_rA = data & 0xFF; + sim_debug (DEBUG_reg, &i8237_dev, "i8237_rA (mode) set to %02X\n", i8237_rA); + return 0; + } + } +} + +uint8 i8237_rCx(t_bool io, uint8 data) +{ + uint8 devnum; + + if ((devnum = i8237_get_dn()) != 0xFF) { + if (io == 0) { + sim_debug (DEBUG_reg, &i8237_dev, "Illegal read of i8237_rC\n"); + return 0; + } else { /* clear byte pointer FF */ + i8237_rD = 0; + sim_debug (DEBUG_reg, &i8237_dev, "i8237_rD (FF) cleared\n"); + return 0; + } + } +} + +uint8 i8237_rDx(t_bool io, uint8 data) +{ + uint8 devnum; + + if ((devnum = i8237_get_dn()) != 0xFF) { + if (io == 0) { /* read temporary register */ + sim_debug (DEBUG_reg, &i8237_dev, "Illegal read of i8237_rD\n"); + return 0; + } else { /* master clear */ + i8237_reset1(); + sim_debug (DEBUG_reg, &i8237_dev, "i8237 master clear\n"); + return 0; + } + } +} + +uint8 i8237_rEx(t_bool io, uint8 data) +{ + uint8 devnum; + + if ((devnum = i8237_get_dn()) != 0xFF) { + if (io == 0) { + sim_debug (DEBUG_reg, &i8237_dev, "Illegal read of i8237_rE\n"); + return 0; + } else { /* clear mask register */ + i8237_rB = 0; + sim_debug (DEBUG_reg, &i8237_dev, "i8237_rB (mask) cleared\n"); + return 0; + } + } +} + +uint8 i8237_rFx(t_bool io, uint8 data) +{ + uint8 devnum; + + if ((devnum = i8237_get_dn()) != 0xFF) { + if (io == 0) { + sim_debug (DEBUG_reg, &i8237_dev, "Illegal read of i8237_rF\n"); + return 0; + } else { /* write all mask register bits */ + i8237_rB = data & 0x0F; + sim_debug (DEBUG_reg, &i8237_dev, "i8237_rB (mask) set to %02X\n", i8237_rB); + return 0; + } + } +} + +/* end of i8237.c */ diff --git a/IBMPC-Systems/common/i8251.c b/IBMPC-Systems/common/i8251.c new file mode 100644 index 00000000..4bf4a366 --- /dev/null +++ b/IBMPC-Systems/common/i8251.c @@ -0,0 +1,318 @@ +/* i8251.c: Intel 8251 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. + + MODIFICATIONS: + + ?? ??? 10 - Original file. + 16 Dec 12 - Modified to use isbc_80_10.cfg file to set base and size. + 24 Apr 15 -- Modified to use simh_debug + + NOTES: + + 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. +*/ + +#include "system_defs.h" + +/* external globals */ + +extern uint16 port; + +#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 uint16 reg_dev(uint8 (*routine)(t_bool, uint8), uint16); + +/* function prototypes */ + +t_stat i8251_svc (UNIT *uptr); +t_stat i8251_reset (DEVICE *dptr, uint16 base); +void i8251_reset1(uint8 devnum); +uint8 i8251_get_dn(void); +uint8 i8251s(t_bool io, uint8 data); +uint8 i8251d(t_bool io, uint8 data); + +/* globals */ + +int32 i8251_devnum = 0; //initially, no 8251 instances +uint16 i8251_port[4]; //base port assigned to each 8251 instance + +/* i8251 Standard I/O Data Structures */ +/* up to 1 i8251 devices */ + +UNIT i8251_unit = { + { UDATA (&i8251_svc, 0, 0), KBD_POLL_WAIT }, + { UDATA (&i8251_svc, 0, 0), KBD_POLL_WAIT }, + { UDATA (&i8251_svc, 0, 0), KBD_POLL_WAIT }, + { UDATA (&i8251_svc, 0, 0), KBD_POLL_WAIT } +}; + +REG i8251_reg[4] = { + { HRDATA (DATA0, i8251_unit[0].buf, 8) }, + { HRDATA (STAT0, i8251_unit[0].u3, 8) }, + { HRDATA (MODE0, i8251_unit[0].u4, 8) }, + { HRDATA (CMD0, i8251_unit[0].u5, 8) }, + { HRDATA (DATA1, i8251_unit[1].buf, 8) }, + { HRDATA (STAT1, i8251_unit[1].u3, 8) }, + { HRDATA (MODE1, i8251_unit[1].u4, 8) }, + { HRDATA (CMD1, i8251_unit[1].u5, 8) }, + { HRDATA (DATA2, i8251_unit[2].buf, 8) }, + { HRDATA (STAT2, i8251_unit[2].u3, 8) }, + { HRDATA (MODE2, i8251_unit[2].u4, 8) }, + { HRDATA (CMD2, i8251_unit[2].u5, 8) }, + { HRDATA (DATA3, i8251_unit[3].buf, 8) }, + { HRDATA (STAT3, i8251_unit[3].u3, 8) }, + { HRDATA (MOD3E, i8251_unit[3].u4, 8) }, + { HRDATA (CMD3, i8251_unit[3].u5, 8) }, + { NULL } +}; + +DEBTAB i8251_debug[] = { + { "ALL", DEBUG_all }, + { "FLOW", DEBUG_flow }, + { "READ", DEBUG_read }, + { "WRITE", DEBUG_write }, + { "XACK", DEBUG_xack }, + { "LEV1", DEBUG_level1 }, + { "LEV2", DEBUG_level2 }, + { NULL } +}; + +MTAB i8251_mod[] = { + { UNIT_ANSI, 0, "TTY", "TTY", NULL }, + { UNIT_ANSI, UNIT_ANSI, "ANSI", "ANSI", NULL }, + { 0 } +}; + +/* address width is set to 16 bits to use devices in 8086/8088 implementations */ + +DEVICE i8251_dev = { + "8251", //name + i8251_unit, //units + i8251_reg, //registers + i8251_mod, //modifiers + 1, //numunits + 16, //aradix + 16, //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 + i8251_debug, //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, uint16 base) +{ + if (i8251_devnum >= I8251_NUM) { + sim_printf("8251_reset: too many devices!\n"); + return 0; + } + i8251_port[i8251_devnum] = reg_dev(i8251d, base); + reg_dev(i8251s, base + 1); + i8251_reset1(i8251_devnum); + sim_printf(" 8251-%d: Registered at %04X\n", i8251_devnum, base); + sim_activate (&i8251_unit[i8251_devnum], i8251_unit[i8251_devnum].wait); /* activate unit */ + i8259_devnum++; + return SCPE_OK; +} + +void i8251_reset1(uint8 devnum) +{ + 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; + sim_printf(" 8251-%d: Reset\n", devnum); +} + +uint8 i8251_get_dn(void) +{ + int i; + + for (i=0; i=i8251_port[i] && port <= i8251_port[i] + 1) + return i; + sim_printf("i8251_get_dn: port %03X not in 8251 device table\n", port); + return 0xFF; +} + +/* I/O instruction handlers, called from the CPU module when an + IN or OUT instruction is issued. +*/ + +uint8 i8251s(t_bool io, uint8 data) +{ + uint8 devnum; + + if ((devnum = i8259_get_dn()) != 0xFF) { + if (io == 0) { /* read status port */ + return i8251_unit[devnum].u3; + } else { /* write status port */ + if (i8251_unit[devnum].u6) { /* if mode, set cmd */ + i8251_unit[devnum].u5 = data; + sim_printf(" 8251-%d: Command Instruction=%02X\n", devnum, data); + if (data & SD) /* reset port! */ + i8251_reset1(devnum); + } else { /* set mode */ + i8251_unit[devnum].u4 = data; + sim_printf(" 8251-%d: Mode Instruction=%02X\n", devnum, data); + i8251_unit[devnum].u6 = 1; /* set cmd received */ + } + } + } + return 0; +} + +uint8 i8251d(t_bool io, uint8 data) +{ + uint8 devnum; + + if ((devnum = i8259_get_dn()) != 0xFF) { + if (io == 0) { /* read data port */ + i8251_unit[devnum].u3 &= ~RXR; + return (i8251_unit[devnum].buf); + } else { /* write data port */ + sim_putchar(data); + } + } + return 0; +} + +/* end of i8251.c */ diff --git a/IBMPC-Systems/common/i8253.c b/IBMPC-Systems/common/i8253.c new file mode 100644 index 00000000..4ed10bd0 --- /dev/null +++ b/IBMPC-Systems/common/i8253.c @@ -0,0 +1,235 @@ +/* i8253.c: Intel i8253 PIT 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. + + MODIFICATIONS: + + ?? ??? 10 - Original file. + 16 Dec 12 - Modified to use isbc_80_10.cfg file to set base and size. + 24 Apr 15 -- Modified to use simh_debug + + NOTES: + +*/ + +#include "system_defs.h" + +/* external function prototypes */ + +extern uint16 reg_dev(uint8 (*routine)(t_bool, uint8), uint16); + +/* external globals */ + +extern uint16 port; //port called in dev_table[port] + +/* globals */ + +int32 i8253_devnum = 0; //actual number of 8253 instances + 1 +uint16 i8253_port[4]; //base port registered to each instance + +/* function prototypes */ + +t_stat i8253_svc (UNIT *uptr); +t_stat i8253_reset (DEVICE *dptr, uint16 base); +uint8 i8253_get_dn(void); +uint8 i8253t0(t_bool io, uint8 data); +uint8 i8253t1(t_bool io, uint8 data); +uint8 i8253t2(t_bool io, uint8 data); +uint8 i8253c(t_bool io, uint8 data); + +/* i8253 Standard I/O Data Structures */ +/* up to 4 i8253 devices */ + +UNIT i8253_unit[] = { + { UDATA (&i8253_svc, 0, 0), 20 }, + { UDATA (&i8253_svc, 0, 0), 20 }, + { UDATA (&i8253_svc, 0, 0), 20 }, + { UDATA (&i8253_svc, 0, 0), 20 } +}; + +REG i8253_reg[] = { + { HRDATA (T0, i8253_unit[0].u3, 8) }, + { HRDATA (T1, i8253_unit[0].u4, 8) }, + { HRDATA (T2, i8253_unit[0].u5, 8) }, + { HRDATA (CMD, i8253_unit[0].u6, 8) }, + { HRDATA (T0, i8253_unit[1].u3, 8) }, + { HRDATA (T1, i8253_unit[1].u4, 8) }, + { HRDATA (T2, i8253_unit[1].u5, 8) }, + { HRDATA (CMD, i8253_unit[1].u6, 8) }, + { NULL } +}; + +DEBTAB i8253_debug[] = { + { "ALL", DEBUG_all }, + { "FLOW", DEBUG_flow }, + { "READ", DEBUG_read }, + { "WRITE", DEBUG_write }, + { "LEV1", DEBUG_level1 }, + { "LEV2", DEBUG_level2 }, + { NULL } +}; + +MTAB i8253_mod[] = { + { 0 } +}; + +/* address width is set to 16 bits to use devices in 8086/8088 implementations */ + +DEVICE i8253_dev = { + "8251", //name + i8253_unit, //units + i8253_reg, //registers + i8253_mod, //modifiers + 1, //numunits + 16, //aradix + 16, //awidth + 1, //aincr + 16, //dradix + 8, //dwidth + NULL, //examine + NULL, //deposit +// &i8253_reset, //reset + NULL, //reset + NULL, //boot + NULL, //attach + NULL, //detach + NULL, //ctxt + 0, //flags + 0, //dctrl + i8253_debug, //debflags + NULL, //msize + NULL //lname +}; + +/* Service routines to handle simulator functions */ + +/* i8253_svc - actually gets char & places in buffer */ + +t_stat i8253_svc (UNIT *uptr) +{ + int32 temp; + + sim_activate (&i8253_unit[0], i8253_unit[0].wait); /* continue poll */ + return SCPE_OK; +} + +/* Reset routine */ + +t_stat i8253_reset (DEVICE *dptr, uint16 port) +{ + if (i8253_devnum > I8253_NUM) { + sim_printf("i8253_reset: too many devices!\n"); + return SCPE_MEM; + } + i8253_port[i8253_devnum] = reg_dev(i8253t0, port); + reg_dev(i8253t1, port + 1); + reg_dev(i8253t2, port + 2); + reg_dev(i8253c, port + 3); + i8253_unit[i8253_devnum].u3 = 0; /* status */ + i8253_unit[i8253_devnum].u4 = 0; /* mode instruction */ + i8253_unit[i8253_devnum].u5 = 0; /* command instruction */ + i8253_unit[i8253_devnum].u6 = 0; + sim_printf(" 8253-%d: Reset\n", i8253_devnum); + sim_printf(" 8253-%d: Registered at %03X\n", i8253_devnum, port); + sim_activate (&i8253_unit[i8253_devnum], i8253_unit[i8253_devnum].wait); /* activate unit */ + i8253_devnum++; + return SCPE_OK; +} + +uint8 i8253_get_dn(void) +{ + int i; + + for (i=0; i=i8253_port[i] && port <= i8253_port[i] + 3) + return i; + sim_printf("i8253_get_dn: port %03X not in 8253 device table\n", port); + return 0xFF; +} + +/* I/O instruction handlers, called from the CPU module when an + IN or OUT instruction is issued. +*/ + +uint8 i8253t0(t_bool io, uint8 data) +{ + uint8 devnum; + + if ((devnum = i8253_get_dn()) != 0xFF) { + if (io == 0) { /* read data port */ + i8253_unit[devnum].u3 = data; + return 0; + } else { /* write data port */ + return i8253_unit[devnum].u3; + } + } + return 0; +} + +uint8 i8253t1(t_bool io, uint8 data) +{ + uint8 devnum; + + if ((devnum = i8253_get_dn()) != 0xFF) { + if (io == 0) { /* read data port */ + i8253_unit[devnum].u4 = data; + return 0; + } else { /* write data port */ + return i8253_unit[devnum].u4; + } + } + return 0; +} + +uint8 i8253t2(t_bool io, uint8 data) +{ + uint8 devnum; + + if ((devnum = i8253_get_dn()) != 0xFF) { + if (io == 0) { /* read data port */ + i8253_unit[devnum].u5 = data; + return 0; + } else { /* write data port */ + return i8253_unit[devnum].u5; + } + } + return 0; +} + +uint8 i8253c(t_bool io, uint8 data) +{ + uint8 devnum; + + if ((devnum = i8253_get_dn()) != 0xFF) { + if (io == 0) { /* read status port */ + i8253_unit[devnum].u6 = data; + return 0; + } else { /* write data port */ + return i8253_unit[devnum].u6; + } + } + return 0; +} + +/* end of i8253.c */ diff --git a/IBMPC-Systems/common/i8255.c b/IBMPC-Systems/common/i8255.c new file mode 100644 index 00000000..d3545cbe --- /dev/null +++ b/IBMPC-Systems/common/i8255.c @@ -0,0 +1,288 @@ +/* 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. + + MODIFICATIONS: + + ?? ??? 10 - Original file. + 16 Dec 12 - Modified to use isbc_80_10.cfg file to set base and size. + 24 Apr 15 -- Modified to use simh_debug + + NOTES: + + 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. + + This program simulates up to 4 i8255 devices. It handles 2 i8255 + devices on the iSBC 80/10 SBC. Other devices could be on other + multibus boards in the simulated system. +*/ + +#include "system_defs.h" /* system header in system dir */ + +/* external globals */ + +extern uint16 port; //port called in dev_table[port] + +/* function prototypes */ + +t_stat i8255_reset (DEVICE *dptr, uint16 base); +uint8 i8255_get_dn(void); +uint8 i8255s(t_bool io, uint8 data); +uint8 i8255a(t_bool io, uint8 data); +uint8 i8255b(t_bool io, uint8 data); +uint8 i8255c(t_bool io, uint8 data); + +/* external function prototypes */ + +extern uint16 reg_dev(uint8 (*routine)(t_bool, uint8), uint16); + +/* globals */ + +int32 i8255_devnum = 0; //actual number of 8255 instances + 1 +uint16 i8255_port[4]; //base port registered to each instance + +/* these bytes represent the input and output to/from a port instance */ + +uint8 i8255_A[4]; //port A byte I/O +uint8 i8255_B[4]; //port B byte I/O +uint8 i8255_C[4]; //port C byte I/O + +/* i8255 Standard I/O Data Structures */ +/* up to 4 i8255 devices */ + +UNIT i8255_unit[] = { + { UDATA (0, 0, 0) }, /* i8255 0 */ + { UDATA (0, 0, 0) }, /* i8255 1 */ + { UDATA (0, 0, 0) }, /* i8255 2 */ + { UDATA (0, 0, 0) } /* i8255 3 */ +}; + +REG i8255_reg[] = { + { HRDATA (CS0, i8255_unit[0].u3, 8) }, /* i8255 0 */ + { HRDATA (A0, i8255_A[0], 8) }, + { HRDATA (B0, i8255_B[0], 8) }, + { HRDATA (C0, i8255_C[0], 8) }, + { HRDATA (CS1, i8255_unit[1].u3, 8) }, /* i8255 1 */ + { HRDATA (A1, i8255_A[1], 8) }, + { HRDATA (B1, i8255_B[1], 8) }, + { HRDATA (C1, i8255_C[1], 8) }, + { HRDATA (CS2, i8255_unit[2].u3, 8) }, /* i8255 2 */ + { HRDATA (A2, i8255_A[2], 8) }, + { HRDATA (B2, i8255_B[2], 8) }, + { HRDATA (C2, i8255_C[2], 8) }, + { HRDATA (CS3, i8255_unit[3].u3, 8) }, /* i8255 3 */ + { HRDATA (A3, i8255_A[3], 8) }, + { HRDATA (B3, i8255_B[3], 8) }, + { HRDATA (C3, i8255_C[3], 8) }, + { NULL } +}; + +DEBTAB i8255_debug[] = { + { "ALL", DEBUG_all }, + { "FLOW", DEBUG_flow }, + { "READ", DEBUG_read }, + { "WRITE", DEBUG_write }, + { "LEV1", DEBUG_level1 }, + { "LEV2", DEBUG_level2 }, + { NULL } +}; + +/* address width is set to 16 bits to use devices in 8086/8088 implementations */ + +DEVICE i8255_dev = { + "8255", //name + i8255_unit, //units + i8255_reg, //registers + NULL, //modifiers + 1, //numunits + 16, //aradix + 16, //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 +}; + +/* Reset routine */ + +t_stat i8255_reset (DEVICE *dptr, uint16 base) +{ + if (i8255_devnum > I8255_NUM) { + sim_printf("i8255_reset: too many devices!\n"); + return SCPE_MEM; + } + i8255_port[i8255_devnum] = reg_dev(i8255a, base); + reg_dev(i8255b, base + 1); + reg_dev(i8255c, base + 2); + reg_dev(i8255s, base + 3); + i8255_unit[i8255_devnum].u3 = 0x9B; /* control */ + i8255_A[i8255_devnum] = 0xFF; /* Port A */ + i8255_B[i8255_devnum] = 0xFF; /* Port B */ + i8255_C[i8255_devnum] = 0xFF; /* Port C */ + sim_printf(" 8255-%d: Reset\n", i8255_devnum); + sim_printf(" 8255-%d: Registered at %03X\n", i8255_devnum, base); + i8255_devnum++; + return SCPE_OK; +} + +uint8 i8255_get_dn(void) +{ + int i; + + for (i=0; i=i8255_port[i] && port <= i8255_port[i] + 3) + return i; + sim_printf("i8255_get_dn: port %03X not in 8255 device table\n", port); + return 0xFF; +} + +/* I/O instruction handlers, called from the CPU module when an + IN or OUT instruction is issued. +*/ + +/* i8255 functions */ + +uint8 i8255s(t_bool io, uint8 data) +{ + uint8 bit; + uint8 devnum; + + if ((devnum = i8255_get_dn()) != 0xFF) { + if (io == 0) { /* read status port */ + return i8255_unit[devnum].u3; + } else { /* write status port */ + if (data & 0x80) { /* mode instruction */ + i8255_unit[devnum].u3 = data; + sim_printf(" 8255-%d: Mode Instruction=%02X\n", devnum, data); + if (data & 0x64) + sim_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_C[devnum] |= (0x01 << bit); + } else { /* reset bit */ + i8255_C[devnum] &= ~(0x01 << bit); + } + } + } + } + return 0; +} + +uint8 i8255a(t_bool io, uint8 data) +{ + uint8 devnum; + + if ((devnum = i8255_get_dn()) != 0xFF) { + if (io == 0) { /* read data port */ + //return (i8255_unit[devnum].u4); + return (i8255_A[devnum]); + } else { /* write data port */ + i8255_A[devnum] = data; + sim_printf(" 8255-%d: Port A = %02X\n", devnum, data); + } + } + return 0; +} + +uint8 i8255b(t_bool io, uint8 data) +{ + uint8 devnum; + + if ((devnum = i8255_get_dn()) != 0xFF) { + if (io == 0) { /* read data port */ + return (i8255_B[devnum]); + } else { /* write data port */ + i8255_B[devnum] = data; + sim_printf(" 8255-%d: Port B = %02X\n", devnum, data); + } + } + return 0; +} + +uint8 i8255c(t_bool io, uint8 data) +{ + uint8 devnum; + + if ((devnum = i8255_get_dn()) != 0xFF) { + if (io == 0) { /* read data port */ + return (i8255_C[devnum]); + } else { /* write data port */ + i8255_C[devnum] = data; + sim_printf(" 8255-%d: Port C = %02X\n", devnum, data); + } + } + return 0; +} + +/* end of i8255.c */ diff --git a/IBMPC-Systems/common/i8259.c b/IBMPC-Systems/common/i8259.c new file mode 100644 index 00000000..641f0f74 --- /dev/null +++ b/IBMPC-Systems/common/i8259.c @@ -0,0 +1,263 @@ +/* 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. + + NOTES: + + This software was written by Bill Beech, 24 Jan 13, to allow emulation of + more complex Computer Systems. + + This program simulates up to 4 i8259 devices. + + u3 = IRR + u4 = ISR + u5 = IMR +*/ + +#include "system_defs.h" /* system header in system dir */ + +/* external globals */ + +extern uint16 port; //port called in dev_table[port] + +/* function prototypes */ + +void i8259_dump(uint8 devnum); +t_stat i8259_reset (DEVICE *dptr, uint16 base); +uint8 i8259_get_dn(void); +uint8 i8259a(t_bool io, uint8 data); +uint8 i8259b(t_bool io, uint8 data); + +/* external function prototypes */ + +extern uint16 reg_dev(uint8 (*routine)(t_bool, uint8), uint16); + +/* globals */ + +int32 i8259_devnum = 0; //initially, no 8259 instances +uint16 i8259_port[4]; //base port assigned to each 8259 instance +uint8 i8259_ints[4]; //8 interrupt inputs for each 8259 instance + +uint8 i8259_icw1[4]; +uint8 i8259_icw2[4]; +uint8 i8259_icw3[4]; +uint8 i8259_icw4[4]; +uint8 i8259_ocw1[4]; +uint8 i8259_ocw2[4]; +uint8 i8259_ocw3[4]; +uint8 icw_num0 = 1, icw_num1 = 1; + +/* i8259 Standard I/O Data Structures */ +/* up to 4 i8259 devices */ + +UNIT i8259_unit[] = { + { UDATA (0, 0, 0) }, /* i8259 0 */ + { UDATA (0, 0, 0) }, /* i8259 1 */ + { UDATA (0, 0, 0) }, /* i8259 2 */ + { UDATA (0, 0, 0) } /* i8259 3 */ +}; + +REG i8259_reg[] = { + { HRDATA (IRR0, i8259_unit[0].u3, 8) }, /* i8259 0 */ + { HRDATA (ISR0, i8259_unit[0].u4, 8) }, + { HRDATA (IMR0, i8259_unit[0].u5, 8) }, + { HRDATA (IRR1, i8259_unit[1].u3, 8) }, /* i8259 0 */ + { HRDATA (ISR1, i8259_unit[1].u4, 8) }, + { HRDATA (IMR1, i8259_unit[1].u5, 8) }, + { HRDATA (IRR2, i8259_unit[2].u3, 8) }, /* i8259 2 */ + { HRDATA (ISR2, i8259_unit[2].u4, 8) }, + { HRDATA (IMR2, i8259_unit[2].u5, 8) }, + { HRDATA (IRR3, i8259_unit[3].u3, 8) }, /* i8259 3 */ + { HRDATA (ISR3, i8259_unit[3].u4, 8) }, + { HRDATA (IMR3, i8259_unit[3].u5, 8) }, + { NULL } +}; + +DEBTAB i8259_debug[] = { + { "ALL", DEBUG_all }, + { "FLOW", DEBUG_flow }, + { "READ", DEBUG_read }, + { "WRITE", DEBUG_write }, + { "LEV1", DEBUG_level1 }, + { "LEV2", DEBUG_level2 }, + { NULL } +}; + +/* address width is set to 16 bits to use devices in 8086/8088 implementations */ + +DEVICE i8259_dev = { + "8259", //name + i8259_unit, //units + i8259_reg, //registers + NULL, //modifiers + 1, //numunits + 16, //aradix + 16, //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 +}; + +void i8259_dump(uint8 devnum) +{ + sim_printf("Device %d\n", devnum); + sim_printf(" IRR = %02X\n", i8259_unit[devnum].u3); + sim_printf(" ISR = %02X\n", i8259_unit[devnum].u4); + sim_printf(" IMR = %02X\n", i8259_unit[devnum].u5); + sim_printf(" ICW1 = %02X\n", i8259_icw1[devnum]); + sim_printf(" ICW2 = %02X\n", i8259_icw2[devnum]); + sim_printf(" ICW3 = %02X\n", i8259_icw3[devnum]); + sim_printf(" ICW4 = %02X\n", i8259_icw4[devnum]); + sim_printf(" OCW1 = %02X\n", i8259_ocw1[devnum]); + sim_printf(" OCW2 = %02X\n", i8259_ocw2[devnum]); + sim_printf(" OCW3 = %02X\n", i8259_ocw3[devnum]); +} + +/* Reset routine */ + +t_stat i8259_reset (DEVICE *dptr, uint16 base) +{ + if (i8259_devnum > I8259_NUM) { + sim_printf("i8259_reset: too many devices!\n"); + return SCPE_MEM; + } + i8259_port[i8259_devnum] = reg_dev(i8259a, base); + reg_dev(i8259b, base + 1); + i8259_unit[i8259_devnum].u3 = 0x00; /* IRR */ + i8259_unit[i8259_devnum].u4 = 0x00; /* ISR */ + i8259_unit[i8259_devnum].u5 = 0x00; /* IMR */ + sim_printf(" 8259-%d: Reset\n", i8259_devnum); + sim_printf(" 8259-%d: Registered at %03X\n", i8259_devnum, base); + i8259_devnum++; + return SCPE_OK; +} + +uint8 i8259_get_dn(void) +{ + int i; + + for (i=0; i=i8259_port[i] && port <= i8259_port[i] + 2) + return i; + sim_printf("i8259_get_dn: port %03X not in 8259 device table\n", port); + return 0xFF; +} + +/* I/O instruction handlers, called from the CPU module when an + IN or OUT instruction is issued. +*/ + + +uint8 i8259a(t_bool io, uint8 data) +{ + uint8 devnum; + + if ((devnum = i8259_get_dn()) != 0xFF) { + if (io == 0) { /* read data port */ + if ((i8259_ocw3[devnum] & 0x03) == 0x02) + return (i8259_unit[devnum].u3); /* IRR */ + if ((i8259_ocw3[devnum] & 0x03) == 0x03) + return (i8259_unit[devnum].u4); /* ISR */ + } else { /* write data port */ + if (data & 0x10) { + icw_num0 = 1; + } + if (icw_num0 == 1) { + i8259_icw1[devnum] = data; /* ICW1 */ + i8259_unit[devnum].u5 = 0x00; /* clear IMR */ + i8259_ocw3[devnum] = 0x02; /* clear OCW3, Sel IRR */ + } else { + switch (data & 0x18) { + case 0: /* OCW2 */ + i8259_ocw2[devnum] = data; + break; + case 8: /* OCW3 */ + i8259_ocw3[devnum] = data; + break; + default: + sim_printf("8259a-%d: OCW Error %02X\n", devnum, data); + break; + } + } + sim_printf("8259a-%d: data = %02X\n", devnum, data); + icw_num0++; /* step ICW number */ + } + } + //i8259_dump(devnum); + return 0; +} + +uint8 i8259b(t_bool io, uint8 data) +{ + uint8 devnum; + + if ((devnum = i8259_get_dn()) != 0xFF) { + if (io == 0) { /* read data port */ + if ((i8259_ocw3[devnum] & 0x03) == 0x02) + return (i8259_unit[devnum].u3); /* IRR */ + if ((i8259_ocw3[devnum] & 0x03) == 0x03) + return (i8259_unit[devnum].u4); /* ISR */ + } else { /* write data port */ + if (data & 0x10) { + icw_num1 = 1; + } + if (icw_num1 == 1) { + i8259_icw1[devnum] = data; /* ICW1 */ + i8259_unit[devnum].u5 = 0x00; /* clear IMR */ + i8259_ocw3[devnum] = 0x02; /* clear OCW3, Sel IRR */ + } else { + switch (data & 0x18) { + case 0: /* OCW2 */ + i8259_ocw2[devnum] = data; + break; + case 8: /* OCW3 */ + i8259_ocw3[devnum] = data; + break; + default: + sim_printf("8259b-%d: OCW Error %02X\n", devnum, data); + break; + } + } + sim_printf("8259b-%d: data = %02X\n", devnum, data); + icw_num1++; /* step ICW number */ + } + } + //i8259_dump(devnum); + return 0; +} + +/* end of i8259.c */ diff --git a/IBMPC-Systems/common/i8273.c b/IBMPC-Systems/common/i8273.c new file mode 100644 index 00000000..aa91fcf4 --- /dev/null +++ b/IBMPC-Systems/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 = { + "8273", //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 */ + sim_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; + sim_printf("8273 Reset\n"); + } else if (i8273_unit.u6) { + i8273_unit.u5 = data; + sim_printf("8273 Command Instruction=%02X\n", data); + } else { + i8273_unit.u4 = data; + sim_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/IBMPC-Systems/common/i8274.c b/IBMPC-Systems/common/i8274.c new file mode 100644 index 00000000..357352f3 --- /dev/null +++ b/IBMPC-Systems/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; + sim_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; + sim_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; + } + sim_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! */ + sim_printf("8274 Reset\n"); + } else if (i8274_unit.u6) { + i8274_unit.u5 = data; + sim_printf("8274 Command Instruction=%02X\n", data); + } else { + i8274_unit.u4 = data; + sim_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/IBMPC-Systems/common/ipata.c b/IBMPC-Systems/common/ipata.c new file mode 100644 index 00000000..715f61f4 --- /dev/null +++ b/IBMPC-Systems/common/ipata.c @@ -0,0 +1,206 @@ +/* iPATA.c: Intel i8255 PIO adapter for PATA HD + + 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. + + NOTES: + + 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. This is an extension of the i8255.c file to support + an emulated PATA IDE Hard Disk Drive. + + 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. + + The Second 8255 on the iSBC 80/10 is used to connect to the IDE PATA + Hard Disk Drive. Pins are defined as shown below: + + PA[0..7] High data byte + PB[0..7] Low data byte + PC[0..2] Register select + PC[3..4] CSFX select + PC[5] Read register + PC[6] Write register +*/ + +#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; + sim_printf("PATA: 8255 Mode Instruction=%02X\n", data); + if (data & 0x64) + sim_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 */ + sim_printf("PATA: 8255 Read Port A = %02X\n", pata_unit[0].u4); + return (pata_unit[0].u4); + } else { /* write data port */ + pata_unit[0].u4 = data; + sim_printf("PATA: 8255 Write Port A = %02X\n", data); + } + return 0; +} + +int32 patab(int32 io, int32 data) +{ + if (io == 0) { /* read data port */ + sim_printf("PATA: 8255 Read Port B = %02X\n", pata_unit[0].u5); + return (pata_unit[0].u5); + } else { /* write data port */ + pata_unit[0].u5 = data; + sim_printf("PATA: 8255 Write Port B = %02X\n", data); + } + return 0; +} + +int32 patac(int32 io, int32 data) +{ + if (io == 0) { /* read data port */ + sim_printf("PATA: 8255 Read Port C = %02X\n", pata_unit[0].u6); + return (pata_unit[0].u6); + } else { /* write data port */ + pata_unit[0].u6 = data; + sim_printf("PATA: 8255 Write 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); + sim_printf(" PATA: Reset\n"); + return SCPE_OK; +} + diff --git a/IBMPC-Systems/common/pata.c b/IBMPC-Systems/common/pata.c new file mode 100644 index 00000000..0d68d4d9 --- /dev/null +++ b/IBMPC-Systems/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, int32), 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; + sim_printf("PATA: 8255 Mode Instruction=%02X\n", data); + if (data & 0x64) + sim_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; + sim_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; + sim_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; + sim_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); + sim_printf(" PATA: Reset\n"); + return SCPE_OK; +} + diff --git a/IBMPC-Systems/common/pcbus.c b/IBMPC-Systems/common/pcbus.c new file mode 100644 index 00000000..0309d5ee --- /dev/null +++ b/IBMPC-Systems/common/pcbus.c @@ -0,0 +1,465 @@ +/* pcbus.c: PC bus simulator + + Copyright (c) 2016, 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. + + MODIFICATIONS: + + 11 Jul 16 - Original file. + + NOTES: + + This software was written by Bill Beech, Jul 2016, to allow emulation of PC XT + Computer Systems. + +*/ + +#include "system_defs.h" + +int32 mbirq = 0; /* set no interrupts */ + +/* function prototypes */ + +t_stat xtbus_svc(UNIT *uptr); +t_stat xtbus_reset(DEVICE *dptr); +void set_irq(int32 int_num); +void clr_irq(int32 int_num); +uint8 nulldev(t_bool io, uint8 data); +uint16 reg_dev(uint8 (*routine)(t_bool io, uint8 data), uint16 port); +void dump_dev_table(void); +t_stat xtbus_reset (DEVICE *dptr); +uint8 xtbus_get_mbyte(uint32 addr); +void xtbus_put_mbyte(uint32 addr, uint8 val); + +/* external function prototypes */ + +extern t_stat SBC_reset(DEVICE *dptr); /* reset the PC XT simulator */ +extern void set_cpuint(int32 int_num); + +/* external globals */ + +extern int32 int_req; /* i8088 INT signal */ +extern uint16 port; //port called in dev_table[port] + +/* Standard SIMH Device Data Structures */ + +UNIT xtbus_unit = { + UDATA (&xtbus_svc, 0, 0), 20 +}; + +REG xtbus_reg[] = { + { HRDATA (MBIRQ, mbirq, 32) }, +}; + +DEBTAB xtbus_debug[] = { + { "ALL", DEBUG_all }, + { "FLOW", DEBUG_flow }, + { "READ", DEBUG_read }, + { "WRITE", DEBUG_write }, + { "LEV1", DEBUG_level1 }, + { "LEV2", DEBUG_level2 }, + { NULL } +}; + +DEVICE xtbus_dev = { + "PCBUS", //name + &xtbus_unit, //units + xtbus_reg, //registers + NULL, //modifiers + 1, //numunits + 16, //aradix + 16, //awidth + 1, //aincr + 16, //dradix + 8, //dwidth + NULL, //examine + NULL, //deposit + &xtbus_reset, //reset + NULL, //boot + NULL, //attach + NULL, //detach + NULL, //ctxt + DEV_DEBUG, //flags + 0, //dctrl + xtbus_debug, //debflags + NULL, //msize + NULL //lname +}; + +/* Service routines to handle simulator functions */ + +/* service routine - actually does the simulated interrupts */ + +t_stat xtbus_svc(UNIT *uptr) +{ + switch (mbirq) { + case INT_1: + set_cpuint(INT_R); + sim_printf("xtbus_svc: mbirq=%04X int_req=%04X\n", mbirq, int_req); + break; + default: + //sim_printf("xtbus_svc: default mbirq=%04X\n", mbirq); + break; + } + sim_activate (&xtbus_unit, xtbus_unit.wait); /* continue poll */ + return SCPE_OK; +} + +/* Reset routine */ + +t_stat xtbus_reset(DEVICE *dptr) +{ + SBC_reset(NULL); + sim_printf(" Xtbus: Reset\n"); + sim_activate (&xtbus_unit, xtbus_unit.wait); /* activate unit */ + return SCPE_OK; +} + +void set_irq(int32 int_num) +{ + mbirq |= int_num; + sim_printf("set_irq: int_num=%04X mbirq=%04X\n", int_num, mbirq); +} + +void clr_irq(int32 int_num) +{ + mbirq &= ~int_num; + sim_printf("clr_irq: int_num=%04X mbirq=%04X\n", int_num, mbirq); +} + +/* This is the I/O configuration table. There are 1024 possible +device addresses, if a device is plugged to a port it's routine +address is here, 'nulldev' means no device has been registered. +The actual 808X can address 65,536 I/O ports but the IBM only uses +the first 1024. */ + +struct idev { + uint8 (*routine)(t_bool io, uint8 data); +}; + +struct idev dev_table[1024] = { +{&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 */ +{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 100H */ +{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 104H */ +{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 108H */ +{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 10CH */ +{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 110H */ +{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 114H */ +{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 118H */ +{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 11CH */ +{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 120H */ +{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 124H */ +{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 128H */ +{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 12CH */ +{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 130H */ +{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 134H */ +{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 138H */ +{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 13CH */ +{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 140H */ +{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 144H */ +{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 148H */ +{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 14CH */ +{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 150H */ +{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 154H */ +{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 158H */ +{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 15CH */ +{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 160H */ +{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 164H */ +{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 168H */ +{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 16CH */ +{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 170H */ +{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 174H */ +{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 178H */ +{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 17CH */ +{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 180H */ +{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 184H */ +{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 188H */ +{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 18CH */ +{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 190H */ +{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 194H */ +{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 198H */ +{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 19CH */ +{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 1A0H */ +{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 1A4H */ +{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 1A8H */ +{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 1A0H */ +{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 1B0H */ +{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 1B4H */ +{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 1B8H */ +{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 1B0H */ +{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 1C0H */ +{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 1C4H */ +{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 1C8H */ +{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 1CCH */ +{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 1D0H */ +{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 1D4H */ +{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 1D8H */ +{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 1DCH */ +{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 1E0H */ +{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 1E4H */ +{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 1E8H */ +{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 1ECH */ +{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 1F0H */ +{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 1F4H */ +{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 1F8H */ +{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 1FCH */ +{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 200H */ +{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 204H */ +{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 208H */ +{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 20CH */ +{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 210H */ +{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 214H */ +{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 218H */ +{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 21CH */ +{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 220H */ +{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 224H */ +{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 228H */ +{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 22CH */ +{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 230H */ +{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 234H */ +{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 238H */ +{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 23CH */ +{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 240H */ +{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 244H */ +{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 248H */ +{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 24CH */ +{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 250H */ +{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 254H */ +{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 258H */ +{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 25CH */ +{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 260H */ +{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 264H */ +{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 268H */ +{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 26CH */ +{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 270H */ +{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 274H */ +{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 278H */ +{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 27CH */ +{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 280H */ +{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 284H */ +{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 288H */ +{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 28CH */ +{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 290H */ +{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 294H */ +{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 298H */ +{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 29CH */ +{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 2A0H */ +{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 2A4H */ +{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 2A8H */ +{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 2A0H */ +{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 2B0H */ +{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 2B4H */ +{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 2B8H */ +{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 2B0H */ +{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 2C0H */ +{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 2C4H */ +{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 2C8H */ +{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 2CCH */ +{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 2D0H */ +{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 2D4H */ +{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 2D8H */ +{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 2DCH */ +{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 2E0H */ +{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 2E4H */ +{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 2E8H */ +{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 2ECH */ +{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 2F0H */ +{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 2F4H */ +{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 2F8H */ +{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 2FCH */ +{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 300H */ +{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 304H */ +{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 308H */ +{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 30CH */ +{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 310H */ +{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 314H */ +{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 318H */ +{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 31CH */ +{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 320H */ +{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 324H */ +{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 328H */ +{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 32CH */ +{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 330H */ +{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 334H */ +{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 338H */ +{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 33CH */ +{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 340H */ +{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 344H */ +{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 348H */ +{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 34CH */ +{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 350H */ +{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 354H */ +{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 358H */ +{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 35CH */ +{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 360H */ +{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 364H */ +{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 368H */ +{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 36CH */ +{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 370H */ +{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 374H */ +{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 378H */ +{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 37CH */ +{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 380H */ +{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 384H */ +{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 388H */ +{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 38CH */ +{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 390H */ +{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 394H */ +{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 398H */ +{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 39CH */ +{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 3A0H */ +{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 3A4H */ +{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 3A8H */ +{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 3A0H */ +{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 3B0H */ +{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 3B4H */ +{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 3B8H */ +{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 3B0H */ +{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 3C0H */ +{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 3C4H */ +{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 3C8H */ +{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 3CCH */ +{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 3D0H */ +{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 3D4H */ +{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 3D8H */ +{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 3DCH */ +{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 3E0H */ +{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 3E4H */ +{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 3E8H */ +{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 3ECH */ +{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 3F0H */ +{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 3F4H */ +{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 3F8H */ +{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev} /* 3FCH */ +}; + +uint8 nulldev(t_bool flag, uint8 data) +{ + sim_printf("xtbus: I/O Port %03X is not assigned io=%d data=%02X\n", + port, flag, data); + if (flag == 0) /* if we got here, no valid I/O device */ + return 0xFF; +} + +uint16 reg_dev(uint8 (*routine)(t_bool io, uint8 data), uint16 port) +{ + if (dev_table[port].routine != &nulldev) { /* port already assigned */ + sim_printf("xtbus: I/O Port %03X is already assigned\n", port); + } else { + sim_printf("Port %03X is assigned\n", port); + dev_table[port].routine = routine; + } + //dump_dev_table(); + return port; +} + +void dump_dev_table(void) +{ + int i; + + for (i=0; i<1024; i++) { + if (dev_table[i].routine != &nulldev) { /* assigned port */ + sim_printf("Port %03X is assigned\n", i); + } + } +} + +/* get a byte from bus */ + +uint8 xtbus_get_mbyte(uint32 addr) +{ + return 0xFF; +} + +/* put a byte to bus */ + +void xtbus_put_mbyte(uint32 addr, uint8 val) +{ + ; +} + +/* end of pcbus.c */ + diff --git a/IBMPC-Systems/common/pceprom.c b/IBMPC-Systems/common/pceprom.c new file mode 100644 index 00000000..cc02a4cd --- /dev/null +++ b/IBMPC-Systems/common/pceprom.c @@ -0,0 +1,177 @@ +/* pceprom.c: Intel EPROM simulator for 8-bit SBCs + + Copyright (c) 2016, 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. + + MODIFICATIONS: + + 11 Jul 16 - Original file. + + NOTES: + + These functions support a simulated ROM devices on aPC XT SBC. + This allows the attachment of the device to a binary file containing the EPROM + code image. Unit will support a single 2764, 27128, 27256, or 27512 type EPROM. +*/ + +#include "system_defs.h" + +/* function prototypes */ + +t_stat EPROM_attach (UNIT *uptr, CONST char *cptr); +t_stat EPROM_reset (DEVICE *dptr, uint32 base, uint32 size); +uint8 EPROM_get_mbyte(uint32 addr); + +/* external function prototypes */ + +/* 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 }, + { "LEV1", DEBUG_level1 }, + { "LEV2", DEBUG_level2 }, + { NULL } +}; + +DEVICE EPROM_dev = { + "EPROM", //name + &EPROM_unit, //units + NULL, //registers + NULL, //modifiers + 1, //numunits + 16, //aradix + 16, //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, CONST char *cptr) +{ + uint16 j; + int c; + FILE *fp; + t_stat r; + + sim_debug (DEBUG_flow, &EPROM_dev, "EPROM_attach: cptr=%s\n", cptr); + if ((r = attach_unit (uptr, cptr)) != SCPE_OK) { + sim_debug (DEBUG_flow, &EPROM_dev, "EPROM_attach: Error\n"); + return r; + } + sim_debug (DEBUG_read, &EPROM_dev, "\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) { + sim_debug (DEBUG_flow, &EPROM_dev, "EPROM_attach: Malloc error\n"); + return SCPE_MEM; + } + } + sim_debug (DEBUG_read, &EPROM_dev, "\tOpen file %s\n", EPROM_unit.filename); + fp = fopen(EPROM_unit.filename, "rb"); /* open EPROM file */ + if (fp == NULL) { + sim_printf("EPROM: Unable to open ROM file %s\n", EPROM_unit.filename); + sim_printf("\tNo ROM image loaded!!!\n"); + return SCPE_OK; + } + sim_debug (DEBUG_read, &EPROM_dev, "\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) { + sim_printf("\tImage is too large - Load truncated!!!\n"); + break; + } + } + sim_printf("\tImage size=%05X unit_capac=%05X\n", j, EPROM_unit.capac); + sim_debug (DEBUG_read, &EPROM_dev, "\tClose file\n"); + fclose(fp); + sim_printf("EPROM: %d bytes of ROM image %s loaded\n", j, EPROM_unit.filename); + sim_debug (DEBUG_flow, &EPROM_dev, "EPROM_attach: Done\n"); + return SCPE_OK; +} + +/* EPROM reset */ + +t_stat EPROM_reset (DEVICE *dptr, uint32 base, uint32 size) +{ + sim_debug (DEBUG_flow, &EPROM_dev, " EPROM_reset: base=%05X size=%05X\n", base, size); + if ((EPROM_unit.flags & UNIT_ATT) == 0) { /* if unattached */ + EPROM_unit.capac = size; /* set EPROM size */ + EPROM_unit.u3 = base; /* set EPROM base addr */ + sim_debug (DEBUG_flow, &EPROM_dev, "Done1\n"); + sim_printf(" EPROM: Available [%05X-%05XH]\n", + base, size); + return SCPE_OK; + } else + sim_printf("EPROM: No file attached\n"); + sim_debug (DEBUG_flow, &EPROM_dev, "Done2\n"); + return SCPE_OK; +} + +/* get a byte from memory */ + +uint8 EPROM_get_mbyte(uint32 addr) +{ + uint8 val; + uint32 romoff; + + romoff = addr - EPROM_unit.u3; + sim_debug (DEBUG_read, &EPROM_dev, "EPROM_get_mbyte: addr=%05X romoff=%05X\n", addr, romoff); + if (romoff < EPROM_unit.capac) { + val = *((uint8 *)EPROM_unit.filebuf + romoff); + sim_debug (DEBUG_read, &EPROM_dev, " val=%02X\n", val); + return (val & 0xFF); + } + sim_debug (DEBUG_read, &EPROM_dev, " Out of range\n"); + return 0xFF; +} + +/* end of pceprom.c */ diff --git a/IBMPC-Systems/common/pcram8.c b/IBMPC-Systems/common/pcram8.c new file mode 100644 index 00000000..93c13be7 --- /dev/null +++ b/IBMPC-Systems/common/pcram8.c @@ -0,0 +1,152 @@ +/* pcram8.c: Intel RAM simulator for 8-bit SBCs + + Copyright (c) 2016, 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. + + MODIFICATIONS: + + 11 Jul 16 - Original file. + + NOTES: + + These functions support a simulated RAM devices on a PC XT SBC. +*/ + +#include "system_defs.h" + +/* function prototypes */ + +t_stat RAM_svc (UNIT *uptr); +t_stat RAM_reset (DEVICE *dptr, uint32 base, uint32 size); +uint8 RAM_get_mbyte(uint32 addr); +void RAM_put_mbyte(uint32 addr, uint8 val); + +/* external function prototypes */ + +extern UNIT i8255_unit[]; + +/* 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 }, + { "LEV1", DEBUG_level1 }, + { "LEV2", DEBUG_level2 }, + { NULL } +}; + +DEVICE RAM_dev = { + "RAM", //name + &RAM_unit, //units + NULL, //registers + NULL, //modifiers + 1, //numunits + 16, //aradix + 16, //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, uint32 base, uint32 size) +{ + sim_debug (DEBUG_flow, &RAM_dev, " RAM_reset: base=%05X size=%05X\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) { + sim_debug (DEBUG_flow, &RAM_dev, "RAM_set_size: Malloc error\n"); + return SCPE_MEM; + } + } + sim_printf(" RAM: Available [%05X-%05XH]\n", + RAM_unit.u3, + RAM_unit.u3 + RAM_unit.capac - 1); + sim_debug (DEBUG_flow, &RAM_dev, "RAM_reset: Done\n"); + return SCPE_OK; +} + +/* get a byte from memory */ + +uint8 RAM_get_mbyte(uint32 addr) +{ + uint8 val; + + if (i8255_unit[0].u5 & 0x02) { /* enable RAM */ + sim_debug (DEBUG_read, &RAM_dev, "RAM_get_mbyte: addr=%04X\n", addr); + if ((addr >= RAM_unit.u3) && ((uint32) addr < (RAM_unit.u3 + RAM_unit.capac))) { + val = *((uint8 *)RAM_unit.filebuf + (addr - RAM_unit.u3)); + sim_debug (DEBUG_read, &RAM_dev, " val=%04X\n", val); + return (val & 0xFF); + } + sim_debug (DEBUG_read, &RAM_dev, " Out of range\n"); + return 0xFF; + } + sim_debug (DEBUG_read, &RAM_dev, " RAM disabled\n"); + return 0xFF; +} + +/* put a byte to memory */ + +void RAM_put_mbyte(uint32 addr, uint8 val) +{ + if (i8255_unit[0].u5 & 0x02) { /* enable RAM */ + sim_debug (DEBUG_write, &RAM_dev, "RAM_put_mbyte: addr=%04X, val=%02X\n", addr, val); + if ((addr >= RAM_unit.u3) && ((uint32)addr < RAM_unit.u3 + RAM_unit.capac)) { + *((uint8 *)RAM_unit.filebuf + (addr - RAM_unit.u3)) = val & 0xFF; + sim_debug (DEBUG_write, &RAM_dev, "\n"); + return; + } + sim_debug (DEBUG_write, &RAM_dev, " Out of range\n"); + return; + } + sim_debug (DEBUG_write, &RAM_dev, " RAM disabled\n"); +} + +/* end of pcram8.c */ diff --git a/IBMPC-Systems/ibmpc/ibmpc.c b/IBMPC-Systems/ibmpc/ibmpc.c new file mode 100644 index 00000000..9beabe66 --- /dev/null +++ b/IBMPC-Systems/ibmpc/ibmpc.c @@ -0,0 +1,203 @@ +/* ibmpcxt.c: IBM PC Processor simulator + + Copyright (c) 2016, 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. + + MODIFICATIONS: + + 11 Jul 16 - Original file. + + NOTES: + + This software was written by Bill Beech, Jul 2016, to allow emulation of IBM PC + Computer Systems. +*/ + +#include "system_defs.h" + +int32 nmiflg = 0; //mask NMI off +uint8 dmapagreg0, dmapagreg1, dmapagreg2, dmapagreg3; +extern uint16 port; //port called in dev_table[port] + +/* function prototypes */ + +uint8 get_mbyte(uint32 addr); +uint16 get_mword(uint32 addr); +void put_mbyte(uint32 addr, uint8 val); +void put_mword(uint32 addr, uint16 val); +t_stat SBC_reset (DEVICE *dptr, uint16 base); +uint8 enbnmi(t_bool io, uint8 data); +uint8 dmapag(t_bool io, uint8 data); +uint8 dmapag0(t_bool io, uint8 data); +uint8 dmapag1(t_bool io, uint8 data); +uint8 dmapag2(t_bool io, uint8 data); +uint8 dmapag3(t_bool io, uint8 data); + +/* external function prototypes */ + +extern t_stat i8088_reset (DEVICE *dptr); /* reset the 8088 emulator */ +extern uint8 xtbus_get_mbyte(uint32 addr); +extern void xtbus_put_mbyte(uint32 addr, uint8 val); +extern uint8 EPROM_get_mbyte(uint32 addr); +extern uint8 RAM_get_mbyte(uint32 addr); +extern void RAM_put_mbyte(uint32 addr, uint8 val); +extern UNIT i8255_unit[]; +extern UNIT EPROM_unit; +extern UNIT RAM_unit; +extern t_stat i8237_reset (DEVICE *dptr, uint16 base); +extern t_stat i8253_reset (DEVICE *dptr, uint16 base); +extern t_stat i8255_reset (DEVICE *dptr, uint16 base); +extern t_stat i8259_reset (DEVICE *dptr, uint16 base); +extern t_stat EPROM_reset (DEVICE *dptr, uint32 base, uint32 size); +extern t_stat RAM_reset (DEVICE *dptr, uint32 base, uint32 size); +extern uint16 reg_dev(uint8 (*routine)(t_bool, uint8), uint16); + +/* SBC reset routine */ + +t_stat SBC_reset (DEVICE *dptr, uint16 base) +{ + sim_printf("Initializing IBM PC:\n"); + i8088_reset (NULL); + i8237_reset (NULL, I8237_BASE_0); + i8253_reset (NULL, I8253_BASE_0); + i8255_reset (NULL, I8255_BASE_0); + i8259_reset (NULL, I8259_BASE_0); + EPROM_reset (NULL, ROM_BASE, ROM_SIZE); + RAM_reset (NULL, RAM_BASE, RAM_SIZE); + reg_dev(enbnmi, NMI_BASE); + reg_dev(dmapag0, DMAPAG_BASE_0); + reg_dev(dmapag1, DMAPAG_BASE_1); + reg_dev(dmapag2, DMAPAG_BASE_2); + reg_dev(dmapag3, DMAPAG_BASE_3); + return SCPE_OK; +} + +uint8 dmapag0(t_bool io, uint8 data) +{ + if (io == 0) { /* read data port */ + ; + } else { /* write data port */ + dmapagreg0 = data; + //sim_printf("dmapag0: dmapagreg0=%04X\n", data); + } +} + +uint8 dmapag1(t_bool io, uint8 data) +{ + if (io == 0) { /* read data port */ + ; + } else { /* write data port */ + dmapagreg1 = data; + //sim_printf("dmapag1: dmapagreg1=%04X\n", data); + } +} + +uint8 dmapag2(t_bool io, uint8 data) +{ + if (io == 0) { /* read data port */ + ; + } else { /* write data port */ + dmapagreg2 = data; + //sim_printf("dmapag2: dmapagreg2=%04X\n", data); + } +} + +uint8 dmapag3(t_bool io, uint8 data) +{ + //sim_printf("dmapag3: entered\n"); + if (io == 0) { /* read data port */ + ; + } else { /* write data port */ + dmapagreg3 = data; + //sim_printf("dmapag3: dmapagreg3=%04X\n", data); + } +} + +uint8 enbnmi(t_bool io, uint8 data) +{ + if (io == 0) { /* read data port */ + ; + } else { /* write data port */ + if (data & 0x80) { + nmiflg = 1; + //sim_printf("enbnmi: NMI enabled\n"); + } else { + nmiflg = 0; + //sim_printf("enbnmi: NMI disabled\n"); + } + } +} + +/* get a byte from memory - handle RAM, ROM, I/O, and pcbus memory */ + +uint8 get_mbyte(uint32 addr) +{ + /* if local EPROM handle it */ + if ((addr >= EPROM_unit.u3) && ((uint32)addr < (EPROM_unit.u3 + EPROM_unit.capac))) { + sim_printf("Write to R/O memory address %05X - ignored\n", addr); + return EPROM_get_mbyte(addr); + } + /* if local RAM handle it */ + if ((addr >= RAM_unit.u3) && ((uint32)addr < (RAM_unit.u3 + RAM_unit.capac))) { + return RAM_get_mbyte(addr); + } + /* otherwise, try the pcbus */ + return xtbus_get_mbyte(addr); +} + +/* get a word from memory - handle RAM, ROM, I/O, and pcbus memory */ + +uint16 get_mword(uint32 addr) +{ + uint16 val; + + val = get_mbyte(addr); + val |= (get_mbyte(addr+1) << 8); + return val; +} + +/* put a byte to memory - handle RAM, ROM, I/O, and pcbus memory */ + +void put_mbyte(uint32 addr, uint8 val) +{ + /* if local EPROM handle it */ + if ((addr >= EPROM_unit.u3) && ((uint32)addr <= (EPROM_unit.u3 + EPROM_unit.capac))) { + sim_printf("Write to R/O memory address %04X - ignored\n", addr); + return; + } /* if local RAM handle it */ + if ((i8255_unit[0].u5 & 0x02) && (addr >= RAM_unit.u3) && ((uint32)addr <= (RAM_unit.u3 + RAM_unit.capac))) { + RAM_put_mbyte(addr, val); + return; + } /* otherwise, try the pcbus */ + xtbus_put_mbyte(addr, val); +} + +/* put a word to memory - handle RAM, ROM, I/O, and pcbus memory */ + +void put_mword(uint32 addr, uint16 val) +{ + put_mbyte(addr, val & 0xff); + put_mbyte(addr+1, val >> 8); +} + +/* end of ibmpc.c */ diff --git a/IBMPC-Systems/ibmpc/ibmpc_sys.c b/IBMPC-Systems/ibmpc/ibmpc_sys.c new file mode 100644 index 00000000..df51ce62 --- /dev/null +++ b/IBMPC-Systems/ibmpc/ibmpc_sys.c @@ -0,0 +1,97 @@ +/* ibmpcxt_sys.c: IBM 5160 simulator + + Copyright (c) 2016, 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. + + 11 Jul 16 - Original file. +*/ + +#include "system_defs.h" + +extern DEVICE i8088_dev; +extern REG i8088_reg[]; +extern DEVICE i8237_dev; +extern DEVICE i8253_dev; +extern DEVICE i8255_dev; +extern DEVICE i8259_dev; +extern DEVICE EPROM_dev; +extern DEVICE RAM_dev; +extern DEVICE xtbus_dev; + +/* bit patterns to manipulate 8-bit ports */ + +#define i82XX_bit_0 0x01 //bit 0 of a port +#define i82XX_bit_1 0x02 //bit 1 of a port +#define i82XX_bit_2 0x04 //bit 2 of a port +#define i82XX_bit_3 0x08 //bit 3 of a port +#define i82XX_bit_4 0x10 //bit 4 of a port +#define i82XX_bit_5 0x20 //bit 5 of a port +#define i82XX_bit_6 0x40 //bit 6 of a port +#define i82XX_bit_7 0x80 //bit 7 of a port + +#define i82XX_nbit_0 ~i8255_bit_0 //bit 0 of a port +#define i82XX_nbit_1 ~i8255_bit_1 //bit 1 of a port +#define i82XX_nbit_2 ~i8255_bit_3 //bit 2 of a port +#define i82XX_nbit_3 ~i8255_bit_3 //bit 3 of a port +#define i82XX_nbit_4 ~i8255_bit_4 //bit 4 of a port +#define i82XX_nbit_5 ~i8255_bit_5 //bit 5 of a port +#define i82XX_nbit_6 ~i8255_bit_6 //bit 6 of a port +#define i82XX_nbit_7 ~i8255_bit_7 //bit 7 of a port + +/* 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[] = "IBM PC"; + +REG *sim_PC = &i8088_reg[0]; + +int32 sim_emax = 4; + +DEVICE *sim_devices[] = { + &i8088_dev, + &EPROM_dev, + &RAM_dev, + &i8237_dev, + &i8253_dev, + &i8255_dev, + &i8259_dev, + &xtbus_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/IBMPC-Systems/ibmpc/system_defs.h b/IBMPC-Systems/ibmpc/system_defs.h new file mode 100644 index 00000000..8968cc26 --- /dev/null +++ b/IBMPC-Systems/ibmpc/system_defs.h @@ -0,0 +1,111 @@ +/* system_defs.h: IBM PC 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. + + 11 Jul 16 - Original file. +*/ + +#include +#include +#include "sim_defs.h" /* simulator defns */ + +/* set the base I/O address and device count for the 8237 */ +#define I8237_BASE_0 0x000 +#define I8237_NUM 1 + +/* set the base I/O address and device count for the 8253 */ +#define I8253_BASE_0 0x040 +#define I8253_BASE_1 0x100 +#define I8253_NUM 2 + +/* set the base I/O address and device count for the 8255 */ +#define I8255_BASE_0 0x060 +#define I8255_NUM 1 + +/* set the base I/O address and device count for the 8259 */ +#define I8259_BASE_0 0x020 +#define I8259_NUM 1 + +/* set the base I/O address for the NMI mask */ +#define NMI_BASE 0x0A0 + +/* set the base I/O address and device count for the DMA page registers */ +#define DMAPAG_BASE_0 0x080 +#define DMAPAG_BASE_1 0x081 +#define DMAPAG_BASE_2 0x082 +#define DMAPAG_BASE_3 0x083 +#define DMAPAG_NUM 4 + +/* set the base and size for the EPROM on the IBM PC */ +#define ROM_BASE 0xFE000 +#define ROM_SIZE 0x02000 + +/* set the base and size for the RAM on the IBM PC */ +#define RAM_BASE 0x00000 +#define RAM_SIZE 0x40000 + +/* set INTR for CPU on the 8088 */ +#define INT_R INT_1 + +/* xtbus 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 + +/* Memory */ + +#define ADDRMASK16 0xFFFF +#define ADDRMASK20 0xFFFFF +#define MAXMEMSIZE20 0xFFFFF /* 8080 max memory size */ + +#define MEMSIZE (i8088_unit.capac) /* 8088 actual memory size */ +#define ADDRMASK (MAXMEMSIZE - 1) /* 8088 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_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 */ +