diff --git a/Intel-Systems/common/i8080.c b/Intel-Systems/common/i8080.c index b93d146d..4f22f13a 100644 --- a/Intel-Systems/common/i8080.c +++ b/Intel-Systems/common/i8080.c @@ -1,1401 +1,1401 @@ -/* 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: - i8080.c - add I/O service routines to dev_table - isys80XX_sys.c - add pointer to data structures in sim_devices - system_defs.h - to define devices and addresses assigned to 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; -uint32 port; //port used in any IN/OUT - -/* 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); - uint16 port; - 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 = { - "I8080", //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; -} - - -/* 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 (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 */ - - if (i8080_dev.dctrl & DEBUG_reg) { - dumpregs(); - sim_printf("\n"); - } - - if (sim_interval <= 0) { /* check clock queue */ - if ((reason = sim_process_event())) - break; - } - - if (int_req > 0) { /* interrupt? */ - 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; - } - } - } /* end interrupt */ - - if (sim_brk_summ && - sim_brk_test (PC, SWMASK ('E'))) { /* breakpoint? */ - reason = STOP_IBKPT; /* stop simulation */ - break; - } - - sim_interval--; /* countdown clock */ - PCX = PC; - - 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; - } - - // first instruction decode - 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; - DAR -= getreg(OP & 0x07); - setarith(DAR); - 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; //required - goto loop_end; - } - - if ((OP & 0xF8) == 0x88) { /* ADC */ - A += getreg(OP & 0x07); - if (GET_FLAG(CF)) - A++; - setarith(A); - A &= BYTE_R; //required - goto loop_end; - } - - if ((OP & 0xF8) == 0x90) { /* SUB */ - A -= getreg(OP & 0x07); - setarith(A); - A &= BYTE_R; //required - goto loop_end; - } - - if ((OP & 0xF8) == 0x98) { /* SBB */ - A -= getreg(OP & 0x07); - if (GET_FLAG(CF)) - A--; - setarith(A); - A &= BYTE_R; //required - goto loop_end; - } - - if ((OP & 0xC7) == 0x04) { /* INR */ - DAR = getreg((OP >> 3) & 0x07); - DAR++; - setinc(DAR); - putreg((OP >> 3) & 0x07, DAR); - goto loop_end; - } - - if ((OP & 0xC7) == 0x05) { /* DCR */ - DAR = getreg((OP >> 3) & 0x07); - DAR--; - setinc(DAR); - putreg((OP >> 3) & 0x07, DAR); - goto loop_end; - } - - if ((OP & 0xCF) == 0x03) { /* INX */ - DAR = getpair((OP >> 4) & 0x03); - DAR++; - putpair((OP >> 4) & 0x03, DAR); - goto loop_end; - } - - if ((OP & 0xCF) == 0x0B) { /* DCX */ - DAR = getpair((OP >> 4) & 0x03); - DAR--; - 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; //required - 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); - 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); - setarith(DAR); - break; - - case 0xE6: /* ANI */ - A &= fetch_byte(1); - setlogical(A); - break; - - case 0xEE: /* XRI */ - A ^= fetch_byte(1); - 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(); - put_mbyte(DAR, A); - break; - - case 0x3A: /* LDA */ - DAR = fetch_word(); - A = get_mbyte(DAR); - break; - - case 0x22: /* SHLD */ - DAR = fetch_word(); - put_mword(DAR, HL); - break; - - case 0x2A: /* LHLD */ - DAR = fetch_word(); - HL = get_mword(DAR); - break; - - case 0xEB: /* XCHG */ - DAR = HL; - HL = DE; - HL &= WORD_R; //required - DE = DAR; - break; - - /* Arithmetic Group */ - - case 0xC6: /* ADI */ - A += fetch_byte(1); - setarith(A); - A &= BYTE_R; //required - break; - - case 0xCE: /* ACI */ - A += fetch_byte(1); - if (GET_FLAG(CF)) - A++; - setarith(A); - A &= BYTE_R; //required - break; - - case 0xD6: /* SUI */ - A -= fetch_byte(1); - setarith(A); - A &= BYTE_R; //required - break; - - case 0xDE: /* SBI */ - A -= fetch_byte(1); - if (GET_FLAG(CF)) - A--; - A &= BYTE_R; //required - 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; - break; - - case 0x0F: /* RRC */ - COND_SET_FLAG(A & 0x01, CF); - A = (A >> 1) & 0xFF; - if (GET_FLAG(CF)) - A |= 0x80; - break; - - case 0x17: /* RAL */ - DAR = GET_FLAG(CF); - COND_SET_FLAG(A & 0x80, CF); - A = (A << 1) & 0xFF; - if (DAR) - A |= 0x01; - break; - - case 0x1F: /* RAR */ - DAR = GET_FLAG(CF); - COND_SET_FLAG(A & 0x01, CF); - A = (A >> 1) & 0xFF; - if (DAR) - A |= 0x80; - break; - - case 0x2F: /* CMA */ - A = ~A; - 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; - break; - - case 0xF9: /* SPHL */ - SP = HL; - break; - - case 0xFB: /* EI */ - IM |= IE; - break; - - case 0xF3: /* DI */ - IM &= ~IE; - break; - - case 0xDB: /* IN */ - DAR = fetch_byte(1); - port = DAR; - A = dev_table[DAR].routine(0, 0); - break; - - case 0xD3: /* OUT */ - DAR = fetch_byte(1); - port = DAR; - dev_table[DAR].routine(1, A); - break; - - default: /* undefined opcode */ - if (i8080_unit.flags & UNIT_OPSTOP) { - reason = STOP_OPCODE; - PC--; - } - break; - } -loop_end: - if (GET_XACK(1) == 0) { /* no XACK for instruction fetch */ -// reason = STOP_XACK; -// sim_printf("Stopped for XACK-2 PC=%04X\n", PC); -// continue; - } - } - -/* Simulation halted */ - - saved_PC = PC; - 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 */ - 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 */ - BC = BC & BYTE_R; - 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"); - 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 - working - 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 */ +/* 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: + i8080.c - add I/O service routines to dev_table + isys80XX_sys.c - add pointer to data structures in sim_devices + system_defs.h - to define devices and addresses assigned to 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; +uint32 port; //port used in any IN/OUT + +/* 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); + uint16 port; + 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 = { + "I8080", //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; +} + + +/* 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 (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 */ + + if (i8080_dev.dctrl & DEBUG_reg) { + dumpregs(); + sim_printf("\n"); + } + + if (sim_interval <= 0) { /* check clock queue */ + if ((reason = sim_process_event())) + break; + } + + if (int_req > 0) { /* interrupt? */ + 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; + } + } + } /* end interrupt */ + + if (sim_brk_summ && + sim_brk_test (PC, SWMASK ('E'))) { /* breakpoint? */ + reason = STOP_IBKPT; /* stop simulation */ + break; + } + + sim_interval--; /* countdown clock */ + PCX = PC; + + 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; + } + + // first instruction decode + 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; + DAR -= getreg(OP & 0x07); + setarith(DAR); + 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; //required + goto loop_end; + } + + if ((OP & 0xF8) == 0x88) { /* ADC */ + A += getreg(OP & 0x07); + if (GET_FLAG(CF)) + A++; + setarith(A); + A &= BYTE_R; //required + goto loop_end; + } + + if ((OP & 0xF8) == 0x90) { /* SUB */ + A -= getreg(OP & 0x07); + setarith(A); + A &= BYTE_R; //required + goto loop_end; + } + + if ((OP & 0xF8) == 0x98) { /* SBB */ + A -= getreg(OP & 0x07); + if (GET_FLAG(CF)) + A--; + setarith(A); + A &= BYTE_R; //required + goto loop_end; + } + + if ((OP & 0xC7) == 0x04) { /* INR */ + DAR = getreg((OP >> 3) & 0x07); + DAR++; + setinc(DAR); + putreg((OP >> 3) & 0x07, DAR); + goto loop_end; + } + + if ((OP & 0xC7) == 0x05) { /* DCR */ + DAR = getreg((OP >> 3) & 0x07); + DAR--; + setinc(DAR); + putreg((OP >> 3) & 0x07, DAR); + goto loop_end; + } + + if ((OP & 0xCF) == 0x03) { /* INX */ + DAR = getpair((OP >> 4) & 0x03); + DAR++; + putpair((OP >> 4) & 0x03, DAR); + goto loop_end; + } + + if ((OP & 0xCF) == 0x0B) { /* DCX */ + DAR = getpair((OP >> 4) & 0x03); + DAR--; + 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; //required + 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); + 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); + setarith(DAR); + break; + + case 0xE6: /* ANI */ + A &= fetch_byte(1); + setlogical(A); + break; + + case 0xEE: /* XRI */ + A ^= fetch_byte(1); + 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(); + put_mbyte(DAR, A); + break; + + case 0x3A: /* LDA */ + DAR = fetch_word(); + A = get_mbyte(DAR); + break; + + case 0x22: /* SHLD */ + DAR = fetch_word(); + put_mword(DAR, HL); + break; + + case 0x2A: /* LHLD */ + DAR = fetch_word(); + HL = get_mword(DAR); + break; + + case 0xEB: /* XCHG */ + DAR = HL; + HL = DE; + HL &= WORD_R; //required + DE = DAR; + break; + + /* Arithmetic Group */ + + case 0xC6: /* ADI */ + A += fetch_byte(1); + setarith(A); + A &= BYTE_R; //required + break; + + case 0xCE: /* ACI */ + A += fetch_byte(1); + if (GET_FLAG(CF)) + A++; + setarith(A); + A &= BYTE_R; //required + break; + + case 0xD6: /* SUI */ + A -= fetch_byte(1); + setarith(A); + A &= BYTE_R; //required + break; + + case 0xDE: /* SBI */ + A -= fetch_byte(1); + if (GET_FLAG(CF)) + A--; + A &= BYTE_R; //required + 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; + break; + + case 0x0F: /* RRC */ + COND_SET_FLAG(A & 0x01, CF); + A = (A >> 1) & 0xFF; + if (GET_FLAG(CF)) + A |= 0x80; + break; + + case 0x17: /* RAL */ + DAR = GET_FLAG(CF); + COND_SET_FLAG(A & 0x80, CF); + A = (A << 1) & 0xFF; + if (DAR) + A |= 0x01; + break; + + case 0x1F: /* RAR */ + DAR = GET_FLAG(CF); + COND_SET_FLAG(A & 0x01, CF); + A = (A >> 1) & 0xFF; + if (DAR) + A |= 0x80; + break; + + case 0x2F: /* CMA */ + A = ~A; + 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; + break; + + case 0xF9: /* SPHL */ + SP = HL; + break; + + case 0xFB: /* EI */ + IM |= IE; + break; + + case 0xF3: /* DI */ + IM &= ~IE; + break; + + case 0xDB: /* IN */ + DAR = fetch_byte(1); + port = DAR; + A = dev_table[DAR].routine(0, 0); + break; + + case 0xD3: /* OUT */ + DAR = fetch_byte(1); + port = DAR; + dev_table[DAR].routine(1, A); + break; + + default: /* undefined opcode */ + if (i8080_unit.flags & UNIT_OPSTOP) { + reason = STOP_OPCODE; + PC--; + } + break; + } +loop_end: + if (GET_XACK(1) == 0) { /* no XACK for instruction fetch */ +// reason = STOP_XACK; +// sim_printf("Stopped for XACK-2 PC=%04X\n", PC); +// continue; + } + } + +/* Simulation halted */ + + saved_PC = PC; + 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 */ + 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 */ + BC = BC & BYTE_R; + 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"); + 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 - working + 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/Intel-Systems/common/ioc-cont.c b/Intel-Systems/common/ioc-cont.c index 2570b6cd..df75f1ed 100644 --- a/Intel-Systems/common/ioc-cont.c +++ b/Intel-Systems/common/ioc-cont.c @@ -1,233 +1,233 @@ -/* ioc-cont.c: Intel IPC DBB 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: - - 27 Jun 16 - Original file. - - NOTES: - - -*/ - -#include "system_defs.h" /* system header in system dir */ - -#define DEBUG 0 - -//dbb status flag bits -#define OBF 1 -#define IBF 2 -#define F0 4 -#define CD 8 - -//dbb command codes -#define PACIFY 0x00 //Resets IOC and its devices -#define ERESET 0x01 //Resets device-generated error (not used by standard devices) -#define SYSTAT 0x02 //Returns subsystem status byte to master -#define DSTAT 0x03 //Returns device status byte to master -#define SRQDAK 0x04 //Enables input of device interrupt acknowledge mask from master -#define SRQACK 0x05 //Clears IOC subsystem interrupt request -#define SRQ 0x06 //Tests ability of IOC to forward an interrupt request to the master -#define DECHO 0x07 //Tests ability of IOC to echo data byte sent by master -#define CSMEM 0x08 //Requests IOC to checksum on-board ROM. Returns pass/fail -#define TRAM 0x09 //Requests IOC to test on-board RAM. Returns pass/fail -#define SINT 0x0A //Enables specified device interrupt from IOC -#define CRTC 0x10 //Requests data byte output to the CRT monitor -#define CRTS 0x11 //Returns CRT status byte to master -#define KEYC 0x12 //Requests data byte input from the keyboard -#define KSTC 0x13 //Returns keyboard status byte to master -#define WPBC 0x15 //Enables input of first of five bytes that define current diskette operation -#define WPBCC 0x16 //Enables input of each of four bytes that follow WPBC -#define WDBC 0x17 //Enables input of diskette write bytes from master -#define RDBC 0x19 //Enables output of diskette read bytes to master -#define RRSTS 0x1B //Returns diskette result byte to master -#define RDSTS 0x1C //Returns diskette device status byte to master - -/* external globals */ - -extern uint16 port; //port called in dev_table[port] -extern int32 PCX; - -/* function prototypes */ - -uint8 ioc_cont0(t_bool io, uint8 data); /* ioc_cont*/ -uint8 ioc_cont1(t_bool io, uint8 data); /* ioc_cont*/ -t_stat ioc_cont_reset (DEVICE *dptr, uint16 baseport); - -/* external function prototypes */ - -extern uint16 reg_dev(uint8 (*routine)(t_bool, uint8), uint16, uint8); -extern uint32 saved_PC; /* program counter */ - -/* globals */ - -uint8 dbb_stat; -uint8 dbb_cmd; -uint8 dbb_in; -uint8 dbb_out; - -UNIT ioc_cont_unit[] = { - { UDATA (0, 0, 0) }, /* ioc_cont*/ -}; - -REG ioc_cont_reg[] = { - { HRDATA (CONTROL0, ioc_cont_unit[0].u3, 8) }, /* ioc_cont */ - { NULL } -}; - -DEBTAB ioc_cont_debug[] = { - { "ALL", DEBUG_all }, - { "FLOW", DEBUG_flow }, - { "READ", DEBUG_read }, - { "WRITE", DEBUG_write }, - { "XACK", DEBUG_xack }, - { "LEV1", DEBUG_level1 }, - { "LEV2", DEBUG_level2 }, - { NULL } -}; - -/* address width is set to 16 bits to use devices in 8086/8088 implementations */ - -DEVICE ioc_cont_dev = { - "IOC-CONT", //name - ioc_cont_unit, //units - ioc_cont_reg, //registers - NULL, //modifiers - 1, //numunits - 16, //aradix - 16, //awidth - 1, //aincr - 16, //dradix - 8, //dwidth - NULL, //examine - NULL, //deposit -// &ioc_cont_reset, //reset - NULL, //reset - NULL, //boot - NULL, //attach - NULL, //detach - NULL, //ctxt - 0, //flags - 0, //dctrl - ioc_cont_debug, //debflags - NULL, //msize - NULL //lname -}; - -/* Reset routine */ - -t_stat ioc_cont_reset(DEVICE *dptr, uint16 baseport) -{ - sim_printf(" ioc_cont[%d]: Reset\n", 0); - sim_printf(" ioc_cont[%d]: Registered at %04X\n", 0, baseport); - reg_dev(ioc_cont0, baseport, 0); - reg_dev(ioc_cont1, baseport + 1, 0); - dbb_stat = 0x00; /* clear DBB status */ - return SCPE_OK; -} - -/* I/O instruction handlers, called from the CPU module when an - IN or OUT instruction is issued. -*/ - -/* IOC control port functions */ - -uint8 ioc_cont0(t_bool io, uint8 data) -{ - if (io == 0) { /* read data port */ - if (DEBUG) - sim_printf(" ioc_cont0: read data returned %02X PCX=%04X\n", dbb_out, PCX); - return dbb_out; - } else { /* write data port */ - dbb_in = data; - dbb_stat |= IBF; - if (DEBUG) - sim_printf(" ioc_cont0: write data=%02X port=%02X PCX=%04X\n", dbb_in, port, PCX); - return 0; - } -} - -uint8 ioc_cont1(t_bool io, uint8 data) -{ - int temp; - - if (io == 0) { /* read status port */ - if ((dbb_stat & F0) && (dbb_stat & IBF)) { - temp = dbb_stat; - if (DEBUG) - sim_printf(" ioc_cont1: DBB status read 1 data=%02X PCX=%04X\n", dbb_stat, PCX); - dbb_stat &= ~IBF; //reset IBF flag - return temp; - } - if ((dbb_stat & F0) && (dbb_stat & OBF)) { - temp = dbb_stat; - if (DEBUG) - sim_printf(" ioc_cont1: DBB status read 2 data=%02X PCX=%04X\n", dbb_stat, PCX); - dbb_stat &= ~OBF; //reset OBF flag - return temp; - } - if (dbb_stat & F0) { - temp = dbb_stat; - if (DEBUG) - sim_printf(" ioc_cont1: DBB status read 3 data=%02X PCX=%04X\n", dbb_stat, PCX); - dbb_stat &= ~F0; //reset F0 flag - return temp; - } -// if (DEBUG) -// sim_printf(" ioc_cont1: DBB status read 4 data=%02X PCX=%04X\n", dbb_stat, PCX); - return dbb_stat; - } else { /* write command port */ - dbb_cmd = data; - switch(dbb_cmd){ - case PACIFY: //should delay 100 ms - dbb_stat = 0; - break; - case SYSTAT: - dbb_out = 0; - dbb_stat |= OBF; - dbb_stat &= ~CD; - break; - case CRTS: - dbb_out = 0; - dbb_stat |= F0; - break; - case KSTC: - dbb_out = 0; - dbb_stat |= F0; - break; - case RDSTS: - dbb_out = 0x80; //not ready - dbb_stat |= (F0 | IBF); - break; - default: - sim_printf(" ioc_cont1: Unknown command %02X PCX=%04X\n", dbb_cmd, PCX); - } - if (DEBUG) - sim_printf(" ioc_cont1: DBB command write data=%02X PCX=%04X\n", dbb_cmd, PCX); - return 0; - } -} - -/* end of ioc-cont.c */ +/* ioc-cont.c: Intel IPC DBB 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: + + 27 Jun 16 - Original file. + + NOTES: + + +*/ + +#include "system_defs.h" /* system header in system dir */ + +#define DEBUG 0 + +//dbb status flag bits +#define OBF 1 +#define IBF 2 +#define F0 4 +#define CD 8 + +//dbb command codes +#define PACIFY 0x00 //Resets IOC and its devices +#define ERESET 0x01 //Resets device-generated error (not used by standard devices) +#define SYSTAT 0x02 //Returns subsystem status byte to master +#define DSTAT 0x03 //Returns device status byte to master +#define SRQDAK 0x04 //Enables input of device interrupt acknowledge mask from master +#define SRQACK 0x05 //Clears IOC subsystem interrupt request +#define SRQ 0x06 //Tests ability of IOC to forward an interrupt request to the master +#define DECHO 0x07 //Tests ability of IOC to echo data byte sent by master +#define CSMEM 0x08 //Requests IOC to checksum on-board ROM. Returns pass/fail +#define TRAM 0x09 //Requests IOC to test on-board RAM. Returns pass/fail +#define SINT 0x0A //Enables specified device interrupt from IOC +#define CRTC 0x10 //Requests data byte output to the CRT monitor +#define CRTS 0x11 //Returns CRT status byte to master +#define KEYC 0x12 //Requests data byte input from the keyboard +#define KSTC 0x13 //Returns keyboard status byte to master +#define WPBC 0x15 //Enables input of first of five bytes that define current diskette operation +#define WPBCC 0x16 //Enables input of each of four bytes that follow WPBC +#define WDBC 0x17 //Enables input of diskette write bytes from master +#define RDBC 0x19 //Enables output of diskette read bytes to master +#define RRSTS 0x1B //Returns diskette result byte to master +#define RDSTS 0x1C //Returns diskette device status byte to master + +/* external globals */ + +extern uint16 port; //port called in dev_table[port] +extern int32 PCX; + +/* function prototypes */ + +uint8 ioc_cont0(t_bool io, uint8 data); /* ioc_cont*/ +uint8 ioc_cont1(t_bool io, uint8 data); /* ioc_cont*/ +t_stat ioc_cont_reset (DEVICE *dptr, uint16 baseport); + +/* external function prototypes */ + +extern uint16 reg_dev(uint8 (*routine)(t_bool, uint8), uint16, uint8); +extern uint32 saved_PC; /* program counter */ + +/* globals */ + +uint8 dbb_stat; +uint8 dbb_cmd; +uint8 dbb_in; +uint8 dbb_out; + +UNIT ioc_cont_unit[] = { + { UDATA (0, 0, 0) }, /* ioc_cont*/ +}; + +REG ioc_cont_reg[] = { + { HRDATA (CONTROL0, ioc_cont_unit[0].u3, 8) }, /* ioc_cont */ + { NULL } +}; + +DEBTAB ioc_cont_debug[] = { + { "ALL", DEBUG_all }, + { "FLOW", DEBUG_flow }, + { "READ", DEBUG_read }, + { "WRITE", DEBUG_write }, + { "XACK", DEBUG_xack }, + { "LEV1", DEBUG_level1 }, + { "LEV2", DEBUG_level2 }, + { NULL } +}; + +/* address width is set to 16 bits to use devices in 8086/8088 implementations */ + +DEVICE ioc_cont_dev = { + "IOC-CONT", //name + ioc_cont_unit, //units + ioc_cont_reg, //registers + NULL, //modifiers + 1, //numunits + 16, //aradix + 16, //awidth + 1, //aincr + 16, //dradix + 8, //dwidth + NULL, //examine + NULL, //deposit +// &ioc_cont_reset, //reset + NULL, //reset + NULL, //boot + NULL, //attach + NULL, //detach + NULL, //ctxt + 0, //flags + 0, //dctrl + ioc_cont_debug, //debflags + NULL, //msize + NULL //lname +}; + +/* Reset routine */ + +t_stat ioc_cont_reset(DEVICE *dptr, uint16 baseport) +{ + sim_printf(" ioc_cont[%d]: Reset\n", 0); + sim_printf(" ioc_cont[%d]: Registered at %04X\n", 0, baseport); + reg_dev(ioc_cont0, baseport, 0); + reg_dev(ioc_cont1, baseport + 1, 0); + dbb_stat = 0x00; /* clear DBB status */ + return SCPE_OK; +} + +/* I/O instruction handlers, called from the CPU module when an + IN or OUT instruction is issued. +*/ + +/* IOC control port functions */ + +uint8 ioc_cont0(t_bool io, uint8 data) +{ + if (io == 0) { /* read data port */ + if (DEBUG) + sim_printf("\n ioc_cont0: read data returned %02X PCX=%04X", dbb_out, PCX); + return dbb_out; + } else { /* write data port */ + dbb_in = data; + dbb_stat |= IBF; + if (DEBUG) + sim_printf("\n ioc_cont0: write data=%02X port=%02X PCX=%04X", dbb_in, port, PCX); + return 0; + } +} + +uint8 ioc_cont1(t_bool io, uint8 data) +{ + int temp; + + if (io == 0) { /* read status port */ + if ((dbb_stat & F0) && (dbb_stat & IBF)) { + temp = dbb_stat; + if (DEBUG) + sim_printf("\n ioc_cont1: DBB status read 1 data=%02X PCX=%04X", dbb_stat, PCX); + dbb_stat &= ~IBF; //reset IBF flag + return temp; + } + if ((dbb_stat & F0) && (dbb_stat & OBF)) { + temp = dbb_stat; + if (DEBUG) + sim_printf("\n ioc_cont1: DBB status read 2 data=%02X PCX=%04X", dbb_stat, PCX); + dbb_stat &= ~OBF; //reset OBF flag + return temp; + } + if (dbb_stat & F0) { + temp = dbb_stat; + if (DEBUG) + sim_printf("\n ioc_cont1: DBB status read 3 data=%02X PCX=%04X", dbb_stat, PCX); + dbb_stat &= ~F0; //reset F0 flag + return temp; + } +// if (DEBUG) +// sim_printf(" ioc_cont1: DBB status read 4 data=%02X PCX=%04X\n", dbb_stat, PCX); + return dbb_stat; + } else { /* write command port */ + dbb_cmd = data; + switch(dbb_cmd){ + case PACIFY: //should delay 100 ms + dbb_stat = 0; + break; + case SYSTAT: + dbb_out = 0; + dbb_stat |= OBF; + dbb_stat &= ~CD; + break; + case CRTS: + dbb_out = 0; + dbb_stat |= F0; + break; + case KSTC: + dbb_out = 0; + dbb_stat |= F0; + break; + case RDSTS: + dbb_out = 0x80; //not ready + dbb_stat |= (F0 | IBF); + break; + default: + sim_printf("\n ioc_cont1: Unknown command %02X PCX=%04X", dbb_cmd, PCX); + } + if (DEBUG) + sim_printf("\n ioc_cont1: DBB command write data=%02X PCX=%04X", dbb_cmd, PCX); + return 0; + } +} + +/* end of ioc-cont.c */ diff --git a/Intel-Systems/common/isbc201.c b/Intel-Systems/common/isbc201.c index 1a5fb36f..ddda85d0 100644 --- a/Intel-Systems/common/isbc201.c +++ b/Intel-Systems/common/isbc201.c @@ -1,687 +1,702 @@ -/* isbc201.c: Intel single density disk adapter 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: - - 31 Oct 16 - Original file. - - NOTES: - - This controller will mount 2 SD disk images on drives :F0: and :F1: addressed - at ports 088H to 08FH. - - Registers: - - 078H - Read - Subsystem status - bit 0 - ready status of drive 0 - bit 1 - ready status of drive 1 - bit 2 - state of channel's interrupt FF - bit 3 - controller presence indicator - bit 4 - zero - bit 5 - zero - bit 6 - zero - bit 7 - zero - - 079H - Read - Read result type (bits 2-7 are zero) - 00 - I/O complete with error(unlinked) - 01 - I/O complete with error(linked)(hi 6-bits are block num) - 10 - Result byte contains diskette ready status - 11 - Reserved - 079H - Write - IOPB address low byte. - - 07AH - Write - IOPB address high byte and start operation. - - 07BH - Read - Read result byte - If result type is 00H - bit 0 - deleted record - bit 1 - CRC error - bit 2 - seek error - bit 3 - address error - bit 4 - data overrun/underrun - bit 5 - write protect - bit 6 - write error - bit 7 - not ready - If result type is 10H - bit 0 - zero - bit 1 - zero - bit 2 - zero - bit 3 - zero - bit 4 - zero - bit 5 - zero - bit 6 - drive 0 ready - bit 7 - drive 1 ready - - 07FH - Write - Reset diskette system. - - Operations: - NOP - 0x00 - Seek - 0x01 - Format Track - 0x02 - Recalibrate - 0x03 - Read Data - 0x04 - Verify CRC - 0x05 - Write Data - 0x06 - Write Deleted Data - 0x07 - - IOPB - I/O Parameter Block - Byte 0 - Channel Word - bit 0 - wait - bit 1 - branch on wait - bit 2 - successor bit - bit 3 - data word length (=8-bit, 1=16-bit) - bit 4-5 - interrupt control - 00 - I/O complete interrupt to be issued - 01 - I/O complete interrupts are disabled - 10 - illegal code - 11 - illegal code - bit 6 - randon format sequence - bit 7 - lock override - - Byte 1 - Diskette Instruction - bit 0-2 - operation code - 000 - no operation - 001 - seek - 010 - format track - 011 - recalibrate - 100 - read data - 101 - verify CRC - 110 - write data - 111 - write deleted data - bit 3 - data word length ( same as byte-0, bit-3) - bit 4-5 - unit select - 00 - drive 0 - 01 - drive 1 - 10 - drive 2 - 11 - drive 3 - bit 6-7 - reserved (zero) - - Byte 2 - Number of Records - - Byte 3 - Track Address - - Byte 4 - Sector Address - - Byte 5 - Buffer Low Address - - Byte 6 - Buffer High Address - - Byte 8 - Block Number - - Byte 9 - Next IOPB Lower Address - - Byte 10 - Next IOPB Upper Address - - u3 - - u4 - - u5 - fdc number - u6 - fdd number. - -*/ - -#include "system_defs.h" /* system header in system dir */ - -#define DEBUG 0 - -#define UNIT_V_WPMODE (UNIT_V_UF) /* Write protect */ -#define UNIT_WPMODE (1 << UNIT_V_WPMODE) - -#define FDD_NUM 2 - -//disk controoler operations -#define DNOP 0x00 //disk no operation -#define DSEEK 0x01 //disk seek -#define DFMT 0x02 //disk format -#define DHOME 0x03 //disk home -#define DREAD 0x04 //disk read -#define DVCRC 0x05 //disk verify CRC -#define DWRITE 0x06 //disk write - -//status -#define RDY0 0x01 //FDD 0 ready -#define RDY1 0x02 //FDD 1 ready -#define FDCINT 0x04 //FDC interrupt flag -#define FDCPRE 0x08 //FDC board present - -//result type -#define RERR 0x00 //FDC returned error -#define ROK 0x02 //FDC returned ok - -// If result type is RERR then rbyte is -#define RB0DR 0x01 //deleted record -#define RB0CRC 0x02 //CRC error -#define RB0SEK 0x04 //seek error -#define RB0ADR 0x08 //address error -#define RB0OU 0x10 //data overrun/underrun -#define RB0WP 0x20 //write protect -#define RB0WE 0x40 //write error -#define RB0NR 0x80 //not ready - -// If result type is ROK then rbyte is -#define RB1RD0 0x40 //drive 0 ready -#define RB1RD1 0x80 //drive 1 ready - -/* external globals */ - -extern uint16 port; //port called in dev_table[port] - -/* external function prototypes */ - -extern uint16 reg_dev(uint8 (*routine)(t_bool, uint8), uint16, uint8); -extern uint8 multibus_get_mbyte(uint16 addr); -extern uint16 multibus_get_mword(uint16 addr); -extern void multibus_put_mbyte(uint16 addr, uint8 val); -extern uint8 multibus_put_mword(uint16 addr, uint16 val); - -/* function prototypes */ - -t_stat isbc201_reset(DEVICE *dptr, uint16 base); -void isbc201_reset1(uint8 fdcnum); -t_stat isbc201_attach (UNIT *uptr, CONST char *cptr); -t_stat isbc201_set_mode (UNIT *uptr, int32 val, CONST char *cptr, void *desc); -uint8 isbc201_get_dn(void); -uint8 isbc2010(t_bool io, uint8 data); /* isbc201 0 */ -uint8 isbc2011(t_bool io, uint8 data); /* isbc201 1 */ -uint8 isbc2012(t_bool io, uint8 data); /* isbc201 2 */ -uint8 isbc2013(t_bool io, uint8 data); /* isbc201 3 */ -uint8 isbc2017(t_bool io, uint8 data); /* isbc201 7 */ -void isbc201_diskio(uint8 fdcnum); //do actual disk i/o - -/* globals */ - -int32 isbc201_fdcnum = 0; //actual number of SBC-201 instances + 1 - -typedef struct { //FDD definition - uint8 *buf; - int t0; - int rdy; - uint8 maxsec; - uint8 maxcyl; - } FDDDEF; - -typedef struct { //FDC definition - uint16 baseport; //FDC base port - uint16 iopb; //FDC IOPB - uint8 stat; //FDC status - uint8 rtype; //FDC result type - uint8 rbyte0; //FDC result byte for type 00 - uint8 rbyte1; //FDC result byte for type 10 - uint8 intff; //fdc interrupt FF - FDDDEF fdd[FDD_NUM]; //indexed by the FDD number - } FDCDEF; - -FDCDEF fdc201[4]; //indexed by the isbc-201 instance number - -UNIT isbc201_unit[] = { - { UDATA (0, UNIT_ATTABLE+UNIT_DISABLE, 0), 20 }, - { UDATA (0, UNIT_ATTABLE+UNIT_DISABLE, 0), 20 }, - { UDATA (0, UNIT_ATTABLE+UNIT_DISABLE, 0), 20 }, - { UDATA (0, UNIT_ATTABLE+UNIT_DISABLE, 0), 20 } -}; - -REG isbc201_reg[] = { - { HRDATA (STATUS0, isbc201_unit[0].u3, 8) }, /* isbc201 0 status */ - { HRDATA (RTYP0, isbc201_unit[0].u4, 8) }, /* isbc201 0 result type */ - { HRDATA (RBYT0, isbc201_unit[0].u5, 8) }, /* isbc201 0 result byte */ - { HRDATA (STATUS1, isbc201_unit[1].u3, 8) }, /* isbc201 1 status */ - { HRDATA (RTYP1, isbc201_unit[1].u4, 8) }, /* isbc201 0 result type */ - { HRDATA (RBYT1, isbc201_unit[1].u5, 8) }, /* isbc201 0 result byte */ - { HRDATA (STATUS2, isbc201_unit[2].u3, 8) }, /* isbc201 2 status */ - { HRDATA (RTYP2, isbc201_unit[0].u4, 8) }, /* isbc201 0 result type */ - { HRDATA (R$BYT2, isbc201_unit[2].u5, 8) }, /* isbc201 0 result byte */ - { HRDATA (STATUS3, isbc201_unit[3].u3, 8) }, /* isbc201 3 status */ - { HRDATA (RTYP3, isbc201_unit[3].u4, 8) }, /* isbc201 0 result type */ - { HRDATA (RBYT3, isbc201_unit[3].u5, 8) }, /* isbc201 0 result byte */ - { NULL } -}; - -MTAB isbc201_mod[] = { - { UNIT_WPMODE, 0, "RW", "RW", &isbc201_set_mode }, - { UNIT_WPMODE, UNIT_WPMODE, "WP", "WP", &isbc201_set_mode }, - { 0 } -}; - -DEBTAB isbc201_debug[] = { - { "ALL", DEBUG_all }, - { "FLOW", DEBUG_flow }, - { "READ", DEBUG_read }, - { "WRITE", DEBUG_write }, - { "XACK", DEBUG_xack }, - { "LEV1", DEBUG_level1 }, - { "LEV2", DEBUG_level2 }, - { NULL } -}; - -/* address width is set to 16 bits to use devices in 8086/8088 implementations */ - -DEVICE isbc201_dev = { - "SBC201", //name - isbc201_unit, //units - isbc201_reg, //registers - isbc201_mod, //modifiers - FDD_NUM, //numunits - 16, //aradix - 16, //awidth - 1, //aincr - 16, //dradix - 8, //dwidth - NULL, //examine - NULL, //deposit - NULL, //reset - NULL, //boot - &isbc201_attach, //attach - NULL, //detach - NULL, //ctxt - DEV_DEBUG+DEV_DISABLE+DEV_DIS, //flags - DEBUG_flow + DEBUG_read + DEBUG_write, //dctrl - isbc201_debug, //debflags - NULL, //msize - NULL //lname -}; - -/* Hardware reset routine */ - -t_stat isbc201_reset(DEVICE *dptr, uint16 base) -{ - sim_printf(" iSBC-201 FDC Board"); - if (SBC201_NUM) { - sim_printf(" - Found\n"); - sim_printf(" isbc201-%d: Hardware Reset\n", isbc201_fdcnum); - sim_printf(" isbc201-%d: Registered at %04X\n", isbc201_fdcnum, base); - fdc201[isbc201_fdcnum].baseport = base; - reg_dev(isbc2010, base, isbc201_fdcnum); //read status - reg_dev(isbc2011, base + 1, isbc201_fdcnum); //read rslt type/write IOPB addr-l - reg_dev(isbc2012, base + 2, isbc201_fdcnum); //write IOPB addr-h and start - reg_dev(isbc2013, base + 3, isbc201_fdcnum); //read rstl byte - reg_dev(isbc2017, base + 7, isbc201_fdcnum); //write reset isbc202 - isbc201_reset1(isbc201_fdcnum); - isbc201_fdcnum++; - } else - sim_printf(" - Not Found\n"); - return SCPE_OK; -} - -/* Software reset routine */ - -void isbc201_reset1(uint8 fdcnum) -{ - int32 i; - UNIT *uptr; - - sim_printf(" isbc201-%d: Software Reset\n", fdcnum); - fdc201[fdcnum].stat = 0; //clear status - for (i = 0; i < FDD_NUM; i++) { /* handle all units */ - uptr = isbc201_dev.units + i; - fdc201[fdcnum].stat |= FDCPRE; //set the FDC status - fdc201[fdcnum].rtype = ROK; - if (uptr->capac == 0) { /* if not configured */ - uptr->capac = 0; /* initialize unit */ - uptr->u5 = fdcnum; //fdc device number - uptr->u6 = i; //fdd unit number - uptr->flags |= UNIT_WPMODE; /* set WP in unit flags */ - sim_printf(" isbc201-%d: Configured, Status=%02X Not attached\n", i, fdc201[fdcnum].stat); - } else { - switch(i){ - case 0: - fdc201[fdcnum].stat |= RDY0; //set FDD 0 ready - fdc201[fdcnum].rbyte1 |= RB1RD0; - break; - case 1: - fdc201[fdcnum].stat |= RDY1; //set FDD 1 ready - fdc201[fdcnum].rbyte1 |= RB1RD1; - break; - } - sim_printf(" isbc201-%d: Configured, Status=%02X Attached to %s\n", - i, fdc201[fdcnum].stat, uptr->filename); - } - } -} - -/* isbc202 attach - attach an .IMG file to a FDD */ - -t_stat isbc201_attach (UNIT *uptr, CONST char *cptr) -{ - t_stat r; - FILE *fp; - int32 i, c = 0; - long flen; - uint8 fdcnum, fddnum; - - sim_debug (DEBUG_flow, &isbc201_dev, " isbc201_attach: Entered with cptr=%s\n", cptr); - if ((r = attach_unit (uptr, cptr)) != SCPE_OK) { - sim_printf(" isbc201_attach: Attach error\n"); - return r; - } - fdcnum = uptr->u5; - fddnum = uptr->u6; - fp = fopen(uptr->filename, "rb"); - if (fp == NULL) { - sim_printf(" Unable to open disk image file %s\n", uptr->filename); - sim_printf(" No disk image loaded!!!\n"); - } else { - sim_printf("isbc202: Attach\n"); - fseek(fp, 0, SEEK_END); /* size disk image */ - flen = ftell(fp); - fseek(fp, 0, SEEK_SET); - if (fdc201[fdcnum].fdd[fddnum].buf == NULL) { /* no buffer allocated */ - fdc201[fdcnum].fdd[fddnum].buf = (uint8 *)malloc(flen); - if (fdc201[fdcnum].fdd[fddnum].buf == NULL) { - sim_printf(" isbc201_attach: Malloc error\n"); - fclose(fp); - return SCPE_MEM; - } - } - uptr->capac = flen; - i = 0; - c = fgetc(fp); // copy disk image into buffer - while (c != EOF) { - *(fdc201[fdcnum].fdd[fddnum].buf + i++) = c & 0xFF; - c = fgetc(fp); - } - fclose(fp); - switch(fddnum){ - case 0: - fdc201[fdcnum].stat |= RDY0; //set FDD 0 ready - fdc201[fdcnum].rtype = ROK; - fdc201[fdcnum].rbyte1 |= RB1RD0; - break; - case 1: - fdc201[fdcnum].stat |= RDY1; //set FDD 1 ready - fdc201[fdcnum].rtype = ROK; - fdc201[fdcnum].rbyte1 |= RB1RD1; - break; - } - if (flen == 256256) { /* 8" 256K SSSD */ - fdc201[fdcnum].fdd[fddnum].maxcyl = 77; - fdc201[fdcnum].fdd[fddnum].maxsec = 26; - } - sim_printf(" iSBC-201%d: Configured %d bytes, Attached to %s\n", - fdcnum, uptr->capac, uptr->filename); - } - sim_debug (DEBUG_flow, &isbc201_dev, " isbc201_attach: Done\n"); - return SCPE_OK; -} - -/* isbc202 set mode = Write protect */ - -t_stat isbc201_set_mode (UNIT *uptr, int32 val, CONST char *cptr, void *desc) -{ -// sim_debug (DEBUG_flow, &isbc201_dev, " isbc201_set_mode: Entered with val=%08XH uptr->flags=%08X\n", -// val, uptr->flags); - if (val & UNIT_WPMODE) { /* write protect */ - uptr->flags |= val; - } else { /* read write */ - uptr->flags &= ~val; - } -// sim_debug (DEBUG_flow, &isbc201_dev, " isbc201_set_mode: Done\n"); - return SCPE_OK; -} - -uint8 isbc201_get_dn(void) -{ - int i; - - for (i=0; i= fdc201[i].baseport && port <= fdc201[i].baseport + 7) - return i; - sim_printf("isbc201_get_dn: port %04X not in isbc202 device table\n", port); - return 0xFF; -} - -/* I/O instruction handlers, called from the CPU module when an - IN or OUT instruction is issued. -*/ - -/* ISBC201 control port functions */ - -uint8 isbc2010(t_bool io, uint8 data) -{ - uint8 fdcnum; - - if ((fdcnum = isbc201_get_dn()) != 0xFF) { - if (io == 0) { /* read ststus*/ - if (DEBUG) - sim_printf("\n isbc201-%d: returned status=%02X", - fdcnum, fdc201[fdcnum].stat); - return fdc201[fdcnum].stat; - } - } - return 0; -} - -uint8 isbc2011(t_bool io, uint8 data) -{ - uint8 fdcnum; - - if ((fdcnum = isbc201_get_dn()) != 0xFF) { - if (io == 0) { /* read data port */ - fdc201[fdcnum].intff = 0; //clear interrupt FF - fdc201[fdcnum].stat &= ~FDCINT; - if (DEBUG) - sim_printf("\n isbc201-%d: returned rtype=%02X intff=%02X status=%02X", - fdcnum, fdc201[fdcnum].rtype, fdc201[fdcnum].intff, fdc201[fdcnum].stat); - return fdc201[fdcnum].rtype; - } else { /* write data port */ - fdc201[fdcnum].iopb = data; - if (DEBUG) - sim_printf("\n isbc201-%d: IOPB low=%02X", fdcnum, data); - } - } - return 0; -} - -uint8 isbc2012(t_bool io, uint8 data) -{ - uint8 fdcnum; - - if ((fdcnum = isbc201_get_dn()) != 0xFF) { - if (io == 0) { /* read data port */ - ; - } else { /* write data port */ - fdc201[fdcnum].iopb |= (data << 8); - if (DEBUG) - sim_printf("\n isbc201-%d: data=%02X IOPB=%04X", fdcnum, data, fdc201[fdcnum].iopb); - isbc201_diskio(fdcnum); - if (fdc201[fdcnum].intff) - fdc201[fdcnum].stat |= FDCINT; - } - } - return 0; -} - -uint8 isbc2013(t_bool io, uint8 data) -{ - uint8 fdcnum, rslt; - - if ((fdcnum = isbc201_get_dn()) != 0xFF) { - if (io == 0) { /* read data port */ - switch(fdc201[fdcnum].rtype) { - case 0x00: - rslt = fdc201[fdcnum].rbyte0; - fdc201[fdcnum].rtype = 0x02; //reset error - break; - case 0x02: - rslt = fdc201[fdcnum].rbyte1; - fdc201[fdcnum].rtype = 0x00; //set error - break; - } - if (DEBUG) - sim_printf("\n isbc201-%d: 0x7B returned rtype=%02X result byte=%02X", - fdcnum, fdc201[fdcnum].rtype, rslt); - return rslt; - } else { /* write data port */ - ; //stop diskette operation - } - } - return 0; -} - -uint8 isbc2017(t_bool io, uint8 data) -{ - uint8 fdcnum; - - if ((fdcnum = isbc201_get_dn()) != 0xFF) { - if (io == 0) { /* read data port */ - ; - } else { /* write data port */ - isbc201_reset1(fdcnum); - } - } - return 0; -} - -// perform the actual disk I/O operation - -void isbc201_diskio(uint8 fdcnum) -{ - uint8 cw, di, nr, ta, sa, bn, data, nrptr, c; - uint16 ba, ni; - uint32 dskoff; - uint8 fddnum; - uint32 i; - UNIT *uptr; - FILE *fp; - - //parse the IOPB - cw = multibus_get_mbyte(fdc201[fdcnum].iopb); - di = multibus_get_mbyte(fdc201[fdcnum].iopb + 1); - nr = multibus_get_mbyte(fdc201[fdcnum].iopb + 2); - ta = multibus_get_mbyte(fdc201[fdcnum].iopb + 3); - sa = multibus_get_mbyte(fdc201[fdcnum].iopb + 4); - ba = multibus_get_mword(fdc201[fdcnum].iopb + 5); - bn = multibus_get_mbyte(fdc201[fdcnum].iopb + 7); - ni = multibus_get_mword(fdc201[fdcnum].iopb + 8); - fddnum = (di & 0x30) >> 4; - uptr = isbc201_dev.units + fddnum; - if (DEBUG) { - sim_printf("\n isbc201-%d: isbc201_diskio IOPB=%04X FDD=%02X STAT=%02X", - fdcnum, fdc201[fdcnum].iopb, fddnum, fdc201[fdcnum].stat); - sim_printf("\n isbc201-%d: cw=%02X di=%02X nr=%02X ta=%02X sa=%02X ba=%04X bn=%02X ni=%04X", - fdcnum, cw, di, nr, ta, sa, ba, bn, ni); - } - //check for not ready - switch(fddnum) { - case 0: - if ((fdc201[fdcnum].stat & RDY0) == 0) { - fdc201[fdcnum].rtype = RERR; - fdc201[fdcnum].rbyte0 = RB0NR; - fdc201[fdcnum].intff = 1; //set interrupt FF - sim_printf("\n isbc201-%d: Ready error on drive %d", fdcnum, fddnum); - return; - } - break; - case 1: - if ((fdc201[fdcnum].stat & RDY1) == 0) { - fdc201[fdcnum].rtype = RERR; - fdc201[fdcnum].rbyte0 = RB0NR; - fdc201[fdcnum].intff = 1; //set interrupt FF - sim_printf("\n isbc201-%d: Ready error on drive %d", fdcnum, fddnum); - return; - } - break; - } - //check for address error - if ( - ((di & 0x07) != 0x03) || - (sa > fdc201[fdcnum].fdd[fddnum].maxsec) || - ((sa + nr) > (fdc201[fdcnum].fdd[fddnum].maxsec + 1)) || - (sa == 0) || - (ta > fdc201[fdcnum].fdd[fddnum].maxcyl) - ) { -// sim_printf("\n isbc201-%d: maxsec=%02X maxcyl=%02X", -// fdcnum, fdc201[fdcnum].fdd[fddnum].maxsec, fdc201[fdcnum].fdd[fddnum].maxcyl); - fdc201[fdcnum].rtype = RERR; - fdc201[fdcnum].rbyte0 = RB0ADR; - fdc201[fdcnum].intff = 1; //set interrupt FF - sim_printf("\n isbc201-%d: Address error on drive %d", fdcnum, fddnum); - return; - } - switch (di & 0x07) { - case DNOP: - case DSEEK: - case DHOME: - case DVCRC: - fdc201[fdcnum].rtype = ROK; - fdc201[fdcnum].intff = 1; //set interrupt FF - break; - case DREAD: - nrptr = 0; - while(nrptr < nr) { - //calculate offset into disk image - dskoff = ((ta * fdc201[fdcnum].fdd[fddnum].maxsec) + (sa - 1)) * 128; - if (DEBUG) - sim_printf("\n isbc201-%d: cw=%02X di=%02X nr=%02X ta=%02X sa=%02X ba=%04X bn=%02X ni=%04X dskoff=%06X", - fdcnum, cw, di, nr, ta, sa, ba, bn, ni, dskoff); - for (i=0; i<128; i++) { //copy sector from image to RAM - data = *(fdc201[fdcnum].fdd[fddnum].buf + (dskoff + i)); - multibus_put_mbyte(ba + i, data); - } - sa++; - ba+=0x80; - nrptr++; - } - fdc201[fdcnum].rtype = ROK; - fdc201[fdcnum].intff = 1; //set interrupt FF - break; - case DWRITE: - //check for WP - if(uptr->flags & UNIT_WPMODE) { - fdc201[fdcnum].rtype = RERR; - fdc201[fdcnum].rbyte0 = RB0WP; - fdc201[fdcnum].intff = 1; //set interrupt FF - sim_printf("\n isbc201-%d: Write protect error on drive %d", fdcnum, fddnum); - return; - } - nrptr = 0; - while(nrptr < nr) { - //calculate offset into disk image - dskoff = ((ta * fdc201[fdcnum].fdd[fddnum].maxsec) + (sa - 1)) * 128; - if (DEBUG) - sim_printf("\n isbc201-%d: cw=%02X di=%02X nr=%02X ta=%02X sa=%02X ba=%04X bn=%02X ni=%04X dskoff=%06X", - fdcnum, cw, di, nr, ta, sa, ba, bn, ni, dskoff); - for (i=0; i<128; i++) { //copy sector from image to RAM - data = multibus_get_mbyte(ba + i); - *(fdc201[fdcnum].fdd[fddnum].buf + (dskoff + i)) = data; - } - sa++; - ba+=0x80; - nrptr++; - } - //*** quick fix. Needs more thought! - fp = fopen(uptr->filename, "wb"); // write out modified image - for (i=0; icapac; i++) { - c = *(fdc201[fdcnum].fdd[fddnum].buf + i); - fputc(c, fp); - } - fclose(fp); - fdc201[fdcnum].rtype = ROK; - fdc201[fdcnum].intff = 1; //set interrupt FF - break; - default: - sim_printf("\n isbc201-%d: isbc201_diskio bad di=%02X", fdcnum, di & 0x07); - break; - } -} - -/* end of isbc201.c */ +/* isbc201.c: Intel single density disk adapter 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: + + 31 Oct 16 - Original file. + + NOTES: + + This controller will mount 2 SD disk images on drives :F0: and :F1: addressed + at ports 088H to 08FH. + + Registers: + + 078H - Read - Subsystem status + bit 0 - ready status of drive 0 + bit 1 - ready status of drive 1 + bit 2 - state of channel's interrupt FF + bit 3 - controller presence indicator + bit 4 - zero + bit 5 - zero + bit 6 - zero + bit 7 - zero + + 079H - Read - Read result type (bits 2-7 are zero) + 00 - I/O complete with error(unlinked) + 01 - I/O complete with error(linked)(hi 6-bits are block num) + 10 - Result byte contains diskette ready status + 11 - Reserved + 079H - Write - IOPB address low byte. + + 07AH - Write - IOPB address high byte and start operation. + + 07BH - Read - Read result byte + If result type is 00H + bit 0 - deleted record + bit 1 - CRC error + bit 2 - seek error + bit 3 - address error + bit 4 - data overrun/underrun + bit 5 - write protect + bit 6 - write error + bit 7 - not ready + If result type is 02H and ready has changed + bit 0 - zero + bit 1 - zero + bit 2 - zero + bit 3 - zero + bit 4 - drive 2 ready + bit 5 - drive 3 ready + bit 6 - drive 0 ready + bit 7 - drive 1 ready + else return 0 + + 07FH - Write - Reset diskette system. + + Operations: + NOP - 0x00 + Seek - 0x01 + Format Track - 0x02 + Recalibrate - 0x03 + Read Data - 0x04 + Verify CRC - 0x05 + Write Data - 0x06 + Write Deleted Data - 0x07 + + IOPB - I/O Parameter Block + Byte 0 - Channel Word + bit 0 - wait + bit 1 - branch on wait + bit 2 - successor bit + bit 3 - data word length (=8-bit, 1=16-bit) + bit 4-5 - interrupt control + 00 - I/O complete interrupt to be issued + 01 - I/O complete interrupts are disabled + 10 - illegal code + 11 - illegal code + bit 6 - randon format sequence + bit 7 - lock override + + Byte 1 - Diskette Instruction + bit 0-2 - operation code + 000 - no operation + 001 - seek + 010 - format track + 011 - recalibrate + 100 - read data + 101 - verify CRC + 110 - write data + 111 - write deleted data + bit 3 - data word length ( same as byte-0, bit-3) + bit 4-5 - unit select + 00 - drive 0 + 01 - drive 1 + 10 - drive 2 + 11 - drive 3 + bit 6-7 - reserved (zero) + + Byte 2 - Number of Records + + Byte 3 - Track Address + + Byte 4 - Sector Address + + Byte 5 - Buffer Low Address + + Byte 6 - Buffer High Address + + Byte 8 - Block Number + + Byte 9 - Next IOPB Lower Address + + Byte 10 - Next IOPB Upper Address + + u3 - + u4 - + u5 - fdc number. + u6 - fdd number. + +*/ + +#include "system_defs.h" /* system header in system dir */ + +#define DEBUG 0 + +#define UNIT_V_WPMODE (UNIT_V_UF) /* Write protect */ +#define UNIT_WPMODE (1 << UNIT_V_WPMODE) + +#define FDD_NUM 2 + +//disk controoler operations +#define DNOP 0x00 //disk no operation +#define DSEEK 0x01 //disk seek +#define DFMT 0x02 //disk format +#define DHOME 0x03 //disk home +#define DREAD 0x04 //disk read +#define DVCRC 0x05 //disk verify CRC +#define DWRITE 0x06 //disk write + +//status +#define RDY0 0x01 //FDD 0 ready +#define RDY1 0x02 //FDD 1 ready +#define FDCINT 0x04 //FDC interrupt flag +#define FDCPRE 0x08 //FDC board present + +//result type +#define RERR 0x00 //FDC returned error +#define ROK 0x02 //FDC returned ok + +// If result type is RERR then rbyte is +#define RB0DR 0x01 //deleted record +#define RB0CRC 0x02 //CRC error +#define RB0SEK 0x04 //seek error +#define RB0ADR 0x08 //address error +#define RB0OU 0x10 //data overrun/underrun +#define RB0WP 0x20 //write protect +#define RB0WE 0x40 //write error +#define RB0NR 0x80 //not ready + +// If result type is ROK then rbyte is +#define RB1RD0 0x40 //drive 0 ready +#define RB1RD1 0x80 //drive 1 ready + +/* external globals */ + +extern uint16 port; //port called in dev_table[port] +extern int32 PCX; + +/* external function prototypes */ + +extern uint16 reg_dev(uint8 (*routine)(t_bool, uint8), uint16, uint8); +extern uint8 multibus_get_mbyte(uint16 addr); +extern uint16 multibus_get_mword(uint16 addr); +extern void multibus_put_mbyte(uint16 addr, uint8 val); +extern uint8 multibus_put_mword(uint16 addr, uint16 val); + +/* function prototypes */ + +t_stat isbc201_reset(DEVICE *dptr, uint16 base); +void isbc201_reset1(uint8 fdcnum); +t_stat isbc201_attach (UNIT *uptr, CONST char *cptr); +t_stat isbc201_set_mode (UNIT *uptr, int32 val, CONST char *cptr, void *desc); +uint8 isbc201_get_dn(void); +uint8 isbc2010(t_bool io, uint8 data); /* isbc201 0 */ +uint8 isbc2011(t_bool io, uint8 data); /* isbc201 1 */ +uint8 isbc2012(t_bool io, uint8 data); /* isbc201 2 */ +uint8 isbc2013(t_bool io, uint8 data); /* isbc201 3 */ +uint8 isbc2017(t_bool io, uint8 data); /* isbc201 7 */ +void isbc201_diskio(uint8 fdcnum); //do actual disk i/o + +/* globals */ + +int32 isbc201_fdcnum = 0; //actual number of SBC-201 instances + 1 + +typedef struct { //FDD definition + uint8 *buf; + int t0; + int rdy; + uint8 maxsec; + uint8 maxcyl; + } FDDDEF; + +typedef struct { //FDC definition + uint16 baseport; //FDC base port + uint16 iopb; //FDC IOPB + uint8 stat; //FDC status + uint8 rdychg; //FDC ready changed + uint8 rtype; //FDC result type + uint8 rbyte0; //FDC result byte for type 00 + uint8 rbyte1; //FDC result byte for type 10 + uint8 intff; //fdc interrupt FF + FDDDEF fdd[FDD_NUM]; //indexed by the FDD number + } FDCDEF; + +FDCDEF fdc201[4]; //indexed by the isbc-201 instance number + +UNIT isbc201_unit[] = { + { UDATA (0, UNIT_ATTABLE+UNIT_DISABLE, 0), 20 }, + { UDATA (0, UNIT_ATTABLE+UNIT_DISABLE, 0), 20 }, + { UDATA (0, UNIT_ATTABLE+UNIT_DISABLE, 0), 20 }, + { UDATA (0, UNIT_ATTABLE+UNIT_DISABLE, 0), 20 } +}; + +REG isbc201_reg[] = { + { HRDATA (STATUS0, isbc201_unit[0].u3, 8) }, /* isbc201 0 status */ + { HRDATA (RTYP0, isbc201_unit[0].u4, 8) }, /* isbc201 0 result type */ + { HRDATA (RBYT0, isbc201_unit[0].u5, 8) }, /* isbc201 0 result byte */ + { HRDATA (STATUS1, isbc201_unit[1].u3, 8) }, /* isbc201 1 status */ + { HRDATA (RTYP1, isbc201_unit[1].u4, 8) }, /* isbc201 0 result type */ + { HRDATA (RBYT1, isbc201_unit[1].u5, 8) }, /* isbc201 0 result byte */ + { HRDATA (STATUS2, isbc201_unit[2].u3, 8) }, /* isbc201 2 status */ + { HRDATA (RTYP2, isbc201_unit[0].u4, 8) }, /* isbc201 0 result type */ + { HRDATA (R$BYT2, isbc201_unit[2].u5, 8) }, /* isbc201 0 result byte */ + { HRDATA (STATUS3, isbc201_unit[3].u3, 8) }, /* isbc201 3 status */ + { HRDATA (RTYP3, isbc201_unit[3].u4, 8) }, /* isbc201 0 result type */ + { HRDATA (RBYT3, isbc201_unit[3].u5, 8) }, /* isbc201 0 result byte */ + { NULL } +}; + +MTAB isbc201_mod[] = { + { UNIT_WPMODE, 0, "RW", "RW", &isbc201_set_mode }, + { UNIT_WPMODE, UNIT_WPMODE, "WP", "WP", &isbc201_set_mode }, + { 0 } +}; + +DEBTAB isbc201_debug[] = { + { "ALL", DEBUG_all }, + { "FLOW", DEBUG_flow }, + { "READ", DEBUG_read }, + { "WRITE", DEBUG_write }, + { "XACK", DEBUG_xack }, + { "LEV1", DEBUG_level1 }, + { "LEV2", DEBUG_level2 }, + { NULL } +}; + +/* address width is set to 16 bits to use devices in 8086/8088 implementations */ + +DEVICE isbc201_dev = { + "SBC201", //name + isbc201_unit, //units + isbc201_reg, //registers + isbc201_mod, //modifiers + FDD_NUM, //numunits + 16, //aradix + 16, //awidth + 1, //aincr + 16, //dradix + 8, //dwidth + NULL, //examine + NULL, //deposit + NULL, //reset + NULL, //boot + &isbc201_attach, //attach + NULL, //detach + NULL, //ctxt + DEV_DEBUG+DEV_DISABLE+DEV_DIS, //flags + DEBUG_flow + DEBUG_read + DEBUG_write, //dctrl + isbc201_debug, //debflags + NULL, //msize + NULL //lname +}; + +/* Hardware reset routine */ + +t_stat isbc201_reset(DEVICE *dptr, uint16 base) +{ + sim_printf(" iSBC-201 FDC Board"); + if (SBC201_NUM) { + sim_printf(" - Found\n"); + sim_printf(" isbc201-%d: Hardware Reset\n", isbc201_fdcnum); + sim_printf(" isbc201-%d: Registered at %04X\n", isbc201_fdcnum, base); + fdc201[isbc201_fdcnum].baseport = base; + reg_dev(isbc2010, base, isbc201_fdcnum); //read status + reg_dev(isbc2011, base + 1, isbc201_fdcnum); //read rslt type/write IOPB addr-l + reg_dev(isbc2012, base + 2, isbc201_fdcnum); //write IOPB addr-h and start + reg_dev(isbc2013, base + 3, isbc201_fdcnum); //read rstl byte + reg_dev(isbc2017, base + 7, isbc201_fdcnum); //write reset isbc202 + isbc201_reset1(isbc201_fdcnum); + isbc201_fdcnum++; + } else + sim_printf(" - Not Found\n"); + return SCPE_OK; +} + +/* Software reset routine */ + +void isbc201_reset1(uint8 fdcnum) +{ + int32 i; + UNIT *uptr; + + sim_printf(" isbc201-%d: Software Reset\n", fdcnum); + fdc201[fdcnum].stat = 0; //clear status + for (i = 0; i < FDD_NUM; i++) { /* handle all units */ + uptr = isbc201_dev.units + i; + fdc201[fdcnum].stat |= FDCPRE; //set the FDC status + fdc201[fdcnum].rtype = ROK; + if (uptr->capac == 0) { /* if not configured */ + uptr->capac = 0; /* initialize unit */ + uptr->u5 = fdcnum; //fdc device number + uptr->u6 = i; //fdd unit number + uptr->flags |= UNIT_WPMODE; /* set WP in unit flags */ + sim_printf(" isbc201-%d: Configured, Status=%02X Not attached\n", i, fdc201[fdcnum].stat); + } else { + switch(i){ + case 0: + fdc201[fdcnum].stat |= RDY0; //set FDD 0 ready + fdc201[fdcnum].rbyte1 |= RB1RD0; + fdc201[fdcnum].rdychg = 0; + break; + case 1: + fdc201[fdcnum].stat |= RDY1; //set FDD 1 ready + fdc201[fdcnum].rbyte1 |= RB1RD1; + fdc201[fdcnum].rdychg = 0; + break; + } + sim_printf(" isbc201-%d: Configured, Status=%02X Attached to %s\n", + i, fdc201[fdcnum].stat, uptr->filename); + } + } +} + +/* isbc202 attach - attach an .IMG file to a FDD */ + +t_stat isbc201_attach (UNIT *uptr, CONST char *cptr) +{ + t_stat r; + FILE *fp; + int32 i, c = 0; + long flen; + uint8 fdcnum, fddnum; + + sim_debug (DEBUG_flow, &isbc201_dev, " isbc201_attach: Entered with cptr=%s\n", cptr); + if ((r = attach_unit (uptr, cptr)) != SCPE_OK) { + sim_printf(" isbc201_attach: Attach error\n"); + return r; + } + fdcnum = uptr->u5; + fddnum = uptr->u6; + fp = fopen(uptr->filename, "rb"); + if (fp == NULL) { + sim_printf(" Unable to open disk image file %s\n", uptr->filename); + sim_printf(" No disk image loaded!!!\n"); + } else { + sim_printf("isbc202: Attach\n"); + fseek(fp, 0, SEEK_END); /* size disk image */ + flen = ftell(fp); + fseek(fp, 0, SEEK_SET); + if (flen == -1) { + sim_printf(" isbc201_attach: File error\n"); + return SCPE_IOERR; + } + if (fdc201[fdcnum].fdd[fddnum].buf == NULL) { /* no buffer allocated */ + fdc201[fdcnum].fdd[fddnum].buf = (uint8 *)malloc(flen); + if (fdc201[fdcnum].fdd[fddnum].buf == NULL) { + sim_printf(" isbc201_attach: Malloc error\n"); + return SCPE_MEM; + } + } + uptr->capac = flen; + i = 0; + c = fgetc(fp); // copy disk image into buffer + while (c != EOF) { + *(fdc201[fdcnum].fdd[fddnum].buf + i++) = c & 0xFF; + c = fgetc(fp); + } + fclose(fp); + switch(fddnum){ + case 0: + fdc201[fdcnum].stat |= RDY0; //set FDD 0 ready + fdc201[fdcnum].rtype = ROK; + fdc201[fdcnum].rbyte1 |= RB1RD0; + break; + case 1: + fdc201[fdcnum].stat |= RDY1; //set FDD 1 ready + fdc201[fdcnum].rtype = ROK; + fdc201[fdcnum].rbyte1 |= RB1RD1; + break; + } + if (flen == 256256) { /* 8" 256K SSSD */ + fdc201[fdcnum].fdd[fddnum].maxcyl = 77; + fdc201[fdcnum].fdd[fddnum].maxsec = 26; + } + sim_printf(" iSBC-201%d: Configured %d bytes, Attached to %s\n", + fdcnum, uptr->capac, uptr->filename); + } + sim_debug (DEBUG_flow, &isbc201_dev, " isbc201_attach: Done\n"); + return SCPE_OK; +} + +/* isbc202 set mode = Write protect */ + +t_stat isbc201_set_mode (UNIT *uptr, int32 val, CONST char *cptr, void *desc) +{ +// sim_debug (DEBUG_flow, &isbc201_dev, " isbc201_set_mode: Entered with val=%08XH uptr->flags=%08X\n", +// val, uptr->flags); + if (val & UNIT_WPMODE) { /* write protect */ + uptr->flags |= val; + } else { /* read write */ + uptr->flags &= ~val; + } +// sim_debug (DEBUG_flow, &isbc201_dev, " isbc201_set_mode: Done\n"); + return SCPE_OK; +} + +uint8 isbc201_get_dn(void) +{ + int i; + +// for (i=0; i= fdc201[i].baseport && port <= fdc201[i].baseport + 7) + return i; + sim_printf("isbc201_get_dn: port %04X not in isbc202 device table\n", port); + return 0xFF; +} + +/* I/O instruction handlers, called from the CPU module when an + IN or OUT instruction is issued. +*/ + +/* ISBC201 control port functions */ + +uint8 isbc2010(t_bool io, uint8 data) +{ + uint8 fdcnum; + + if ((fdcnum = isbc201_get_dn()) != 0xFF) { + if (io == 0) { /* read ststus*/ + if (DEBUG) + sim_printf("\n isbc201-%d: 0x78 returned status=%02X PCX=%04X", + fdcnum, fdc201[fdcnum].stat, PCX); + return fdc201[fdcnum].stat; + } + } + return 0; +} + +uint8 isbc2011(t_bool io, uint8 data) +{ + uint8 fdcnum; + + if ((fdcnum = isbc201_get_dn()) != 0xFF) { + if (io == 0) { /* read data port */ + fdc201[fdcnum].intff = 0; //clear interrupt FF + fdc201[fdcnum].stat &= ~FDCINT; + if (DEBUG) + sim_printf("\n isbc201-%d: 0x79 returned rtype=%02X intff=%02X status=%02X PCX=%04X", + fdcnum, fdc201[fdcnum].rtype, fdc201[fdcnum].intff, fdc201[fdcnum].stat, PCX); + return fdc201[fdcnum].rtype; + } else { /* write data port */ + fdc201[fdcnum].iopb = data; + if (DEBUG) + sim_printf("\n isbc201-%d: 0x79 IOPB low=%02X PCX=%04X", + fdcnum, data, PCX); + } + } + return 0; +} + +uint8 isbc2012(t_bool io, uint8 data) +{ + uint8 fdcnum; + + if ((fdcnum = isbc201_get_dn()) != 0xFF) { + if (io == 0) { /* read data port */ + ; + } else { /* write data port */ + fdc201[fdcnum].iopb |= (data << 8); + if (DEBUG) + sim_printf("\n isbc202-%d: 0x7A IOPB=%04X PCX=%04X", + fdcnum, fdc201[fdcnum].iopb, PCX); + isbc201_diskio(fdcnum); + if (fdc201[fdcnum].intff) + fdc201[fdcnum].stat |= FDCINT; + } + } + return 0; +} + +uint8 isbc2013(t_bool io, uint8 data) +{ + uint8 fdcnum; + + if ((fdcnum = isbc201_get_dn()) != 0xFF) { + if (io == 0) { /* read data port */ + if (fdc201[fdcnum].rtype == 0) { + if (DEBUG) + sim_printf("\n isbc201-%d: 0x7B returned rbyte0=%02X PCX=%04X", + fdcnum, fdc201[fdcnum].rbyte0, PCX); + return fdc201[fdcnum].rbyte0; + } else { + if (fdc201[fdcnum].rdychg) { + if (DEBUG) + sim_printf("\n isbc201-%d: 0x7B returned rbyte1=%02X PCX=%04X", + fdcnum, fdc201[fdcnum].rbyte1, PCX); + return fdc201[fdcnum].rbyte1; + } else { + if (DEBUG) + sim_printf("\n isbc201-%d: 0x7B returned rbytex=%02X PCX=%04X", + fdcnum, 0, PCX); + return 0; + } + } + } else { /* write data port */ + ; //stop diskette operation + } + } + return 0; +} + +uint8 isbc2017(t_bool io, uint8 data) +{ + uint8 fdcnum; + + if ((fdcnum = isbc201_get_dn()) != 0xFF) { + if (io == 0) { /* read data port */ + ; + } else { /* write data port */ + isbc201_reset1(fdcnum); + } + } + return 0; +} + +// perform the actual disk I/O operation + +void isbc201_diskio(uint8 fdcnum) +{ + uint8 cw, di, nr, ta, sa, bn, data, nrptr, c; + uint16 ba, ni; + uint32 dskoff; + uint8 fddnum; + uint32 i; + UNIT *uptr; + FILE *fp; + + //parse the IOPB + cw = multibus_get_mbyte(fdc201[fdcnum].iopb); + di = multibus_get_mbyte(fdc201[fdcnum].iopb + 1); + nr = multibus_get_mbyte(fdc201[fdcnum].iopb + 2); + ta = multibus_get_mbyte(fdc201[fdcnum].iopb + 3); + sa = multibus_get_mbyte(fdc201[fdcnum].iopb + 4); + ba = multibus_get_mword(fdc201[fdcnum].iopb + 5); + bn = multibus_get_mbyte(fdc201[fdcnum].iopb + 7); + ni = multibus_get_mword(fdc201[fdcnum].iopb + 8); + fddnum = (di & 0x30) >> 4; + uptr = isbc201_dev.units + fddnum; + if (DEBUG) { + sim_printf("\n isbc201-%d: isbc201_diskio IOPB=%04X FDD=%02X STAT=%02X", + fdcnum, fdc201[fdcnum].iopb, fddnum, fdc201[fdcnum].stat); + sim_printf("\n isbc201-%d: cw=%02X di=%02X nr=%02X ta=%02X sa=%02X ba=%04X bn=%02X ni=%04X", + fdcnum, cw, di, nr, ta, sa, ba, bn, ni); + } + //check for not ready + switch(fddnum) { + case 0: + if ((fdc201[fdcnum].stat & RDY0) == 0) { + fdc201[fdcnum].rtype = RERR; + fdc201[fdcnum].rbyte0 = RB0NR; + fdc201[fdcnum].intff = 1; //set interrupt FF + sim_printf("\n isbc201-%d: Ready error on drive %d", fdcnum, fddnum); + return; + } + break; + case 1: + if ((fdc201[fdcnum].stat & RDY1) == 0) { + fdc201[fdcnum].rtype = RERR; + fdc201[fdcnum].rbyte0 = RB0NR; + fdc201[fdcnum].intff = 1; //set interrupt FF + sim_printf("\n isbc201-%d: Ready error on drive %d", fdcnum, fddnum); + return; + } + break; + } + //check for address error + if ( + ((di & 0x07) != 0x03) || + (sa > fdc201[fdcnum].fdd[fddnum].maxsec) || + ((sa + nr) > (fdc201[fdcnum].fdd[fddnum].maxsec + 1)) || + (sa == 0) || + (ta > fdc201[fdcnum].fdd[fddnum].maxcyl) + ) { +// sim_printf("\n isbc201-%d: maxsec=%02X maxcyl=%02X", +// fdcnum, fdc201[fdcnum].fdd[fddnum].maxsec, fdc201[fdcnum].fdd[fddnum].maxcyl); + fdc201[fdcnum].rtype = RERR; + fdc201[fdcnum].rbyte0 = RB0ADR; + fdc201[fdcnum].intff = 1; //set interrupt FF + sim_printf("\n isbc201-%d: Address error on drive %d", fdcnum, fddnum); + return; + } + switch (di & 0x07) { + case DNOP: + case DSEEK: + case DHOME: + case DVCRC: + fdc201[fdcnum].rtype = ROK; + fdc201[fdcnum].intff = 1; //set interrupt FF + break; + case DREAD: + nrptr = 0; + while(nrptr < nr) { + //calculate offset into disk image + dskoff = ((ta * fdc201[fdcnum].fdd[fddnum].maxsec) + (sa - 1)) * 128; + if (DEBUG) + sim_printf("\n isbc201-%d: cw=%02X di=%02X nr=%02X ta=%02X sa=%02X ba=%04X bn=%02X ni=%04X dskoff=%06X", + fdcnum, cw, di, nr, ta, sa, ba, bn, ni, dskoff); + for (i=0; i<128; i++) { //copy sector from image to RAM + data = *(fdc201[fdcnum].fdd[fddnum].buf + (dskoff + i)); + multibus_put_mbyte(ba + i, data); + } + sa++; + ba+=0x80; + nrptr++; + } + fdc201[fdcnum].rtype = ROK; + fdc201[fdcnum].intff = 1; //set interrupt FF + break; + case DWRITE: + //check for WP + if(uptr->flags & UNIT_WPMODE) { + fdc201[fdcnum].rtype = RERR; + fdc201[fdcnum].rbyte0 = RB0WP; + fdc201[fdcnum].intff = 1; //set interrupt FF + sim_printf("\n isbc201-%d: Write protect error on drive %d", fdcnum, fddnum); + return; + } + nrptr = 0; + while(nrptr < nr) { + //calculate offset into disk image + dskoff = ((ta * fdc201[fdcnum].fdd[fddnum].maxsec) + (sa - 1)) * 128; + if (DEBUG) + sim_printf("\n isbc201-%d: cw=%02X di=%02X nr=%02X ta=%02X sa=%02X ba=%04X bn=%02X ni=%04X dskoff=%06X", + fdcnum, cw, di, nr, ta, sa, ba, bn, ni, dskoff); + for (i=0; i<128; i++) { //copy sector from image to RAM + data = multibus_get_mbyte(ba + i); + *(fdc201[fdcnum].fdd[fddnum].buf + (dskoff + i)) = data; + } + sa++; + ba+=0x80; + nrptr++; + } + //*** quick fix. Needs more thought! + fp = fopen(uptr->filename, "wb"); // write out modified image + for (i=0; icapac; i++) { + c = *(fdc201[fdcnum].fdd[fddnum].buf + i); + fputc(c, fp); + } + fclose(fp); + fdc201[fdcnum].rtype = ROK; + fdc201[fdcnum].intff = 1; //set interrupt FF + break; + default: + sim_printf("\n isbc201-%d: isbc201_diskio bad di=%02X", fdcnum, di & 0x07); + break; + } +} + +/* end of isbc201.c */ diff --git a/Intel-Systems/common/isbc202.c b/Intel-Systems/common/isbc202.c index 5dfd6d8c..1602348a 100644 --- a/Intel-Systems/common/isbc202.c +++ b/Intel-Systems/common/isbc202.c @@ -1,753 +1,779 @@ -/* isbc202.c: Intel double density disk adapter 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: - - 27 Jun 16 - Original file. - - NOTES: - - This controller will mount 4 DD disk images on drives :F0: thru :F3: addressed - at ports 078H to 07FH. - - Registers: - - 078H - Read - Subsystem status - bit 0 - ready status of drive 0 - bit 1 - ready status of drive 1 - bit 2 - state of channel's interrupt FF - bit 3 - controller presence indicator - bit 4 - DD controller presence indicator - bit 5 - ready status of drive 2 - bit 6 - ready status of drive 3 - bit 7 - zero - - 079H - Read - Read result type (bits 2-7 are zero) - 00 - I/O complete with error - 01 - Reserved - 10 - Result byte contains diskette ready status - 11 - Reserved - 079H - Write - IOPB address low byte. - - 07AH - Write - IOPB address high byte and start operation. - - 07BH - Read - Read result byte - If result type is 00H - bit 0 - deleted record - bit 1 - CRC error - bit 2 - seek error - bit 3 - address error - bit 4 - data overrun/underrun - bit 5 - write protect - bit 6 - write error - bit 7 - not ready - If result type is 02H - bit 0 - zero - bit 1 - zero - bit 2 - zero - bit 3 - zero - bit 4 - drive 2 ready - bit 5 - drive 3 ready - bit 6 - drive 0 ready - bit 7 - drive 1 ready - - 07FH - Write - Reset diskette system. - - Operations: - NOP - 0x00 - Seek - 0x01 - Format Track - 0x02 - Recalibrate - 0x03 - Read Data - 0x04 - Verify CRC - 0x05 - Write Data - 0x06 - Write Deleted Data - 0x07 - - IOPB - I/O Parameter Block - Byte 0 - Channel Word - bit 3 - data word length (=8-bit, 1=16-bit) - bit 4-5 - interrupt control - 00 - I/O complete interrupt to be issued - 01 - I/O complete interrupts are disabled - 10 - illegal code - 11 - illegal code - bit 6- randon format sequence - - Byte 1 - Diskette Instruction - bit 0-2 - operation code - 000 - no operation - 001 - seek - 010 - format track - 011 - recalibrate - 100 - read data - 101 - verify CRC - 110 - write data - 111 - write deleted data - bit 3 - data word length ( same as byte-0, bit-3) - bit 4-5 - unit select - 00 - drive 0 - 01 - drive 1 - 10 - drive 2 - 11 - drive 3 - bit 6-7 - reserved (zero) - - Byte 2 - Number of Records - - Byte 4 - Track Address - - Byte 5 - Sector Address - - Byte 6 - Buffer Low Address - - Byte 7 - Buffer High Address - - u3 - - u4 - - u5 - - u6 - fdd number. - -*/ - -#include "system_defs.h" /* system header in system dir */ - -#define DEBUG 0 - -#define UNIT_V_WPMODE (UNIT_V_UF) /* Write protect */ -#define UNIT_WPMODE (1 << UNIT_V_WPMODE) - -#define FDD_NUM 4 - -//disk controoler operations -#define DNOP 0x00 //disk no operation -#define DSEEK 0x01 //disk seek -#define DFMT 0x02 //disk format -#define DHOME 0x03 //disk home -#define DREAD 0x04 //disk read -#define DVCRC 0x05 //disk verify CRC -#define DWRITE 0x06 //disk write - -//status -#define RDY0 0x01 //FDD 0 ready -#define RDY1 0x02 //FDD 1 ready -#define FDCINT 0x04 //FDC interrupt flag -#define FDCPRE 0x08 //FDC board present -#define FDCDD 0x10 //fdc is DD -#define RDY2 0x20 //FDD 2 ready -#define RDY3 0x40 //FDD 3 ready - -//result type -#define RERR 0x00 //FDC returned error -#define ROK 0x02 //FDC returned ok - -// If result type is RERR then rbyte is -#define RB0DR 0x01 //deleted record -#define RB0CRC 0x02 //CRC error -#define RB0SEK 0x04 //seek error -#define RB0ADR 0x08 //address error -#define RB0OU 0x10 //data overrun/underrun -#define RB0WP 0x20 //write protect -#define RB0WE 0x40 //write error -#define RB0NR 0x80 //not ready - -// If result type is ROK then rbyte is -#define RB1RD2 0x10 //drive 2 ready -#define RB1RD3 0x20 //drive 3 ready -#define RB1RD0 0x40 //drive 0 ready -#define RB1RD1 0x80 //drive 1 ready - -/* external globals */ - -extern uint16 port; //port called in dev_table[port] -extern int32 PCX; - -/* external function prototypes */ - -extern uint16 reg_dev(uint8 (*routine)(t_bool, uint8), uint16, uint8); -extern uint8 multibus_get_mbyte(uint16 addr); -extern uint16 multibus_get_mword(uint16 addr); -extern void multibus_put_mbyte(uint16 addr, uint8 val); -extern uint8 multibus_put_mword(uint16 addr, uint16 val); - -/* function prototypes */ - -t_stat isbc202_reset(DEVICE *dptr, uint16 base); -void isbc202_reset1(uint8 fdcnum); -t_stat isbc202_attach (UNIT *uptr, CONST char *cptr); -t_stat isbc202_set_mode (UNIT *uptr, int32 val, CONST char *cptr, void *desc); -uint8 isbc202_get_dn(void); -uint8 isbc2020(t_bool io, uint8 data); /* isbc202 0 */ -uint8 isbc2021(t_bool io, uint8 data); /* isbc202 1 */ -uint8 isbc2022(t_bool io, uint8 data); /* isbc202 2 */ -uint8 isbc2023(t_bool io, uint8 data); /* isbc202 3 */ -uint8 isbc2027(t_bool io, uint8 data); /* isbc202 7 */ -void isbc202_diskio(uint8 fdcnum); //do actual disk i/o - -/* globals */ - -int32 isbc202_fdcnum = 0; //actual number of SBC-202 instances + 1 - -typedef struct { //FDD definition - uint8 *buf; - int t0; - int rdy; - uint8 sec; - uint8 cyl; - uint8 maxsec; - uint8 maxcyl; - } FDDDEF; - -typedef struct { //FDC definition - uint16 baseport; //FDC base port - uint16 iopb; //FDC IOPB - uint8 stat; //FDC status - uint8 rtype; //FDC result type - uint8 rbyte0; //FDC result byte for type 00 - uint8 rbyte1; //FDC result byte for type 10 - uint8 intff; //fdc interrupt FF - FDDDEF fdd[FDD_NUM]; //indexed by the FDD number - } FDCDEF; - -FDCDEF fdc202[4]; //indexed by the isbc-202 instance number - -UNIT isbc202_unit[] = { - { UDATA (0, UNIT_ATTABLE+UNIT_DISABLE, 0), 20 }, - { UDATA (0, UNIT_ATTABLE+UNIT_DISABLE, 0), 20 }, - { UDATA (0, UNIT_ATTABLE+UNIT_DISABLE, 0), 20 }, - { UDATA (0, UNIT_ATTABLE+UNIT_DISABLE, 0), 20 } -}; - -REG isbc202_reg[] = { - { HRDATA (STAT0, fdc202[0].stat, 8) }, /* isbc202 0 status */ - { HRDATA (RTYP0, fdc202[0].rtype, 8) }, /* isbc202 0 result type */ - { HRDATA (RBYT0A, fdc202[0].rbyte0, 8) }, /* isbc202 0 result byte 0 */ - { HRDATA (RBYT0B, fdc202[0].rbyte1, 8) }, /* isbc202 0 result byte 1 */ - { HRDATA (INTFF0, fdc202[0].intff, 8) }, /* isbc202 0 interrupt f/f */ - { HRDATA (STAT1, fdc202[1].stat, 8) }, /* isbc202 1 status */ - { HRDATA (RTYP1, fdc202[1].rtype, 8) }, /* isbc202 1 result type */ - { HRDATA (RBYT1A, fdc202[1].rbyte0, 8) }, /* isbc202 1 result byte 0 */ - { HRDATA (RBYT1B, fdc202[1].rbyte1, 8) }, /* isbc202 1 result byte 1 */ - { HRDATA (INTFF1, fdc202[1].intff, 8) }, /* isbc202 1 interrupt f/f */ - { HRDATA (STAT2, fdc202[2].stat, 8) }, /* isbc202 2 status */ - { HRDATA (RTYP2, fdc202[2].rtype, 8) }, /* isbc202 2 result type */ - { HRDATA (RBYT2A, fdc202[2].rbyte0, 8) }, /* isbc202 2 result byte 0 */ - { HRDATA (RBYT2B, fdc202[0].rbyte1, 8) }, /* isbc202 2 result byte 1 */ - { HRDATA (INTFF2, fdc202[2].intff, 8) }, /* isbc202 2 interrupt f/f */ - { HRDATA (STAT3, fdc202[3].stat, 8) }, /* isbc202 3 status */ - { HRDATA (RTYP3, fdc202[3].rtype, 8) }, /* isbc202 3 result type */ - { HRDATA (RBYT3A, fdc202[3].rbyte0, 8) }, /* isbc202 3 result byte 0 */ - { HRDATA (RBYT3B, fdc202[3].rbyte1, 8) }, /* isbc202 3 result byte 1 */ - { HRDATA (INTFF3, fdc202[0].intff, 8) }, /* isbc202 3 interrupt f/f */ - { NULL } -}; - -MTAB isbc202_mod[] = { - { UNIT_WPMODE, 0, "RW", "RW", &isbc202_set_mode }, - { UNIT_WPMODE, UNIT_WPMODE, "WP", "WP", &isbc202_set_mode }, - { 0 } -}; - -DEBTAB isbc202_debug[] = { - { "ALL", DEBUG_all }, - { "FLOW", DEBUG_flow }, - { "READ", DEBUG_read }, - { "WRITE", DEBUG_write }, - { "XACK", DEBUG_xack }, - { "LEV1", DEBUG_level1 }, - { "LEV2", DEBUG_level2 }, - { NULL } -}; - -/* address width is set to 16 bits to use devices in 8086/8088 implementations */ - -DEVICE isbc202_dev = { - "SBC202", //name - isbc202_unit, //units - isbc202_reg, //registers - isbc202_mod, //modifiers - FDD_NUM, //numunits - 16, //aradix - 16, //awidth - 1, //aincr - 16, //dradix - 8, //dwidth - NULL, //examine - NULL, //deposit - NULL, //reset - NULL, //boot - &isbc202_attach, //attach - NULL, //detach - NULL, //ctxt - DEV_DEBUG+DEV_DISABLE+DEV_DIS, //flags - DEBUG_flow + DEBUG_read + DEBUG_write, //dctrl - isbc202_debug, //debflags - NULL, //msize - NULL //lname -}; - -/* Hardware reset routine */ - -t_stat isbc202_reset(DEVICE *dptr, uint16 base) -{ - sim_printf(" iSBC-202 FDC Board"); - if (SBC202_NUM) { - sim_printf(" - Found\n"); - sim_printf(" isbc202-%d: Hardware Reset\n", isbc202_fdcnum); - sim_printf(" isbc202-%d: Registered at %04X\n", isbc202_fdcnum, base); - fdc202[isbc202_fdcnum].baseport = base; - reg_dev(isbc2020, base, isbc202_fdcnum); //read status - reg_dev(isbc2021, base + 1, isbc202_fdcnum); //read rslt type/write IOPB addr-l - reg_dev(isbc2022, base + 2, isbc202_fdcnum); //write IOPB addr-h and start - reg_dev(isbc2023, base + 3, isbc202_fdcnum); //read rstl byte - reg_dev(isbc2027, base + 7, isbc202_fdcnum); //write reset isbc202 - isbc202_reset1(isbc202_fdcnum); - isbc202_fdcnum++; - } else - sim_printf(" - Not Found\n"); - return SCPE_OK; -} - -/* Software reset routine */ - -void isbc202_reset1(uint8 fdcnum) -{ - int32 i; - UNIT *uptr; - - sim_printf(" isbc202-%d: Software Reset\n", fdcnum); - fdc202[fdcnum].stat = 0; //clear status - for (i = 0; i < FDD_NUM; i++) { /* handle all units */ - uptr = isbc202_dev.units + i; - fdc202[fdcnum].stat |= FDCPRE | FDCDD; //set the FDC status - fdc202[fdcnum].rtype = ROK; - if (uptr->capac == 0) { /* if not configured */ - uptr->u5 = fdcnum; //fdc device number - uptr->u6 = i; //fdd unit number - uptr->flags |= UNIT_WPMODE; /* set WP in unit flags */ - sim_printf(" SBC202%d: Configured, Status=%02X Not attached\n", i, fdc202[fdcnum].stat); - } else { - switch(i){ - case 0: - fdc202[fdcnum].stat |= RDY0; //set FDD 0 ready - fdc202[fdcnum].rbyte1 |= RB1RD0; - break; - case 1: - fdc202[fdcnum].stat |= RDY1; //set FDD 1 ready - fdc202[fdcnum].rbyte1 |= RB1RD1; - break; - case 2: - fdc202[fdcnum].stat |= RDY2; //set FDD 2 ready - fdc202[fdcnum].rbyte1 |= RB1RD2; - break; - case 3: - fdc202[fdcnum].stat |= RDY3; //set FDD 3 ready - fdc202[fdcnum].rbyte1 |= RB1RD3; - break; - } - sim_printf(" SBC202%d: Configured, Status=%02X Attached to %s\n", - i, fdc202[fdcnum].stat, uptr->filename); - } - } -} - -/* isbc202 attach - attach an .IMG file to a FDD */ - -t_stat isbc202_attach (UNIT *uptr, CONST char *cptr) -{ - t_stat r; - FILE *fp; - int32 i, c = 0; - long flen; - uint8 fdcnum, fddnum; - - sim_debug (DEBUG_flow, &isbc202_dev, " isbc202_attach: Entered with cptr=%s\n", cptr); - if ((r = attach_unit (uptr, cptr)) != SCPE_OK) { - sim_printf(" isbc202_attach: Attach error\n"); - return r; - } - fdcnum = uptr->u5; - fddnum = uptr->u6; - fp = fopen(uptr->filename, "rb"); - if (fp == NULL) { - sim_printf(" Unable to open disk image file %s\n", uptr->filename); - sim_printf(" No disk image loaded!!!\n"); - } else { - sim_printf("isbc202: Attach\n"); - fseek(fp, 0, SEEK_END); /* size disk image */ - flen = ftell(fp); - fseek(fp, 0, SEEK_SET); - if (fdc202[fdcnum].fdd[fddnum].buf == NULL) { /* no buffer allocated */ - fdc202[fdcnum].fdd[fddnum].buf = (uint8 *)malloc(flen); - if (fdc202[fdcnum].fdd[fddnum].buf == NULL) { - sim_printf(" isbc202_attach: Malloc error\n"); - fclose(fp); - return SCPE_MEM; - } - } - uptr->capac = flen; - i = 0; - c = fgetc(fp); // copy disk image into buffer - while (c != EOF) { - *(fdc202[fdcnum].fdd[fddnum].buf + i++) = c & 0xFF; - c = fgetc(fp); - } - fclose(fp); - switch(fddnum){ - case 0: - fdc202[fdcnum].stat |= RDY0; //set FDD 0 ready - fdc202[fdcnum].rtype = ROK; - fdc202[fdcnum].rbyte1 |= RB1RD0; - break; - case 1: - fdc202[fdcnum].stat |= RDY1; //set FDD 1 ready - fdc202[fdcnum].rtype = ROK; - fdc202[fdcnum].rbyte1 |= RB1RD1; - break; - case 2: - fdc202[fdcnum].stat |= RDY2; //set FDD 2 ready - fdc202[fdcnum].rtype = ROK; - fdc202[fdcnum].rbyte1 |= RB1RD2; - break; - case 3: - fdc202[fdcnum].stat |= RDY3; //set FDD 3 ready - fdc202[fdcnum].rtype = ROK; - fdc202[fdcnum].rbyte1 |= RB1RD3; - break; - } - if (flen == 512512) { /* 8" 512K SSDD */ - fdc202[fdcnum].fdd[fddnum].maxcyl = 77; - fdc202[fdcnum].fdd[fddnum].maxsec = 52; - fdc202[fdcnum].fdd[fddnum].sec = 1; - fdc202[fdcnum].fdd[fddnum].cyl = 0; - } else - sim_printf(" iSBC-202-%d: Not a DD disk image\n", fdcnum); - - sim_printf(" iSBC-202%d: Configured %d bytes, Attached to %s\n", - fdcnum, uptr->capac, uptr->filename); - } - sim_debug (DEBUG_flow, &isbc202_dev, " isbc202_attach: Done\n"); - return SCPE_OK; -} - -/* isbc202 set mode = Write protect */ - -t_stat isbc202_set_mode (UNIT *uptr, int32 val, CONST char *cptr, void *desc) -{ -// sim_debug (DEBUG_flow, &isbc202_dev, " isbc202_set_mode: Entered with val=%08XH uptr->flags=%08X\n", -// val, uptr->flags); - if (val & UNIT_WPMODE) { /* write protect */ - uptr->flags |= val; - } else { /* read write */ - uptr->flags &= ~val; - } -// sim_debug (DEBUG_flow, &isbc202_dev, " isbc202_set_mode: Done\n"); - return SCPE_OK; -} - -uint8 isbc202_get_dn(void) -{ - int i; - - for (i=0; i= fdc202[i].baseport && port <= fdc202[i].baseport + 7) - return i; - sim_printf("isbc202_get_dn: port %04X not in isbc202 device table\n", port); - return 0xFF; -} - -/* ISBC202 control port functions */ - -uint8 isbc2020(t_bool io, uint8 data) -{ - uint8 fdcnum; - - if ((fdcnum = isbc202_get_dn()) != 0xFF) { - if (io == 0) { /* read ststus*/ - if (DEBUG) - sim_printf("\n isbc202-%d: 0x78 returned status=%02X PCX=%04X", fdcnum, fdc202[fdcnum].stat, PCX); - return fdc202[fdcnum].stat; - } - } - return 0; -} - -uint8 isbc2021(t_bool io, uint8 data) -{ - uint8 fdcnum; - - if ((fdcnum = isbc202_get_dn()) != 0xFF) { - if (io == 0) { /* read data port */ - fdc202[fdcnum].intff = 0; //clear interrupt FF - fdc202[fdcnum].stat &= ~FDCINT; - if (DEBUG) - sim_printf("\n isbc202-%d: 0x79 returned rtype=%02X intff=%02X status=%02X PCX=%04X", - fdcnum, fdc202[fdcnum].rtype, fdc202[fdcnum].intff, fdc202[fdcnum].stat, PCX); - return fdc202[fdcnum].rtype; - } else { /* write data port */ - fdc202[fdcnum].iopb = data; - if (DEBUG) - sim_printf("\n isbc202-%d: 0x79 IOPB low=%02X PCX=%04X", fdcnum, data, PCX); - } - } - return 0; -} - -uint8 isbc2022(t_bool io, uint8 data) -{ - uint8 fdcnum; - - if ((fdcnum = isbc202_get_dn()) != 0xFF) { - if (io == 0) { /* read data port */ - ; - } else { /* write data port */ - fdc202[fdcnum].iopb |= (data << 8); - if (DEBUG) - sim_printf("\n isbc202-%d: 0x7A IOPB=%04X PCX=%04X", fdcnum, fdc202[fdcnum].iopb, PCX); - isbc202_diskio(fdcnum); - if (fdc202[fdcnum].intff) - fdc202[fdcnum].stat |= FDCINT; - } - } - return 0; -} - -uint8 isbc2023(t_bool io, uint8 data) -{ - uint8 fdcnum, rslt; - - if ((fdcnum = isbc202_get_dn()) != 0xFF) { - if (io == 0) { /* read data port */ - if (DEBUG) - sim_printf("\n isbc202-%d: 0x7B returned rtype=%02X result byte=%02X PCX=%04X", - fdcnum, fdc202[fdcnum].rtype, rslt, PCX); - return rslt; - } else { /* write data port */ - ; //stop diskette operation - } - } - return 0; -} - -uint8 isbc2027(t_bool io, uint8 data) -{ - uint8 fdcnum; - - if ((fdcnum = isbc202_get_dn()) != 0xFF) { - if (io == 0) { /* read data port */ - ; - } else { /* write data port */ - isbc202_reset1(fdcnum); - } - } - return 0; -} - -// perform the actual disk I/O operation - -void isbc202_diskio(uint8 fdcnum) -{ - uint8 cw, di, nr, ta, sa, data, nrptr, c; - uint16 ba; - uint32 dskoff; - uint8 fddnum, fmtb; - uint32 i; - UNIT *uptr; - FILE *fp; - //parse the IOPB - cw = multibus_get_mbyte(fdc202[fdcnum].iopb); - di = multibus_get_mbyte(fdc202[fdcnum].iopb + 1); - nr = multibus_get_mbyte(fdc202[fdcnum].iopb + 2); - ta = multibus_get_mbyte(fdc202[fdcnum].iopb + 3); - sa = multibus_get_mbyte(fdc202[fdcnum].iopb + 4); - ba = multibus_get_mword(fdc202[fdcnum].iopb + 5); - fddnum = (di & 0x30) >> 4; - uptr = isbc202_dev.units + fddnum; - if (DEBUG) { - sim_printf("\n isbc202-%d: isbc202_diskio IOPB=%04X FDD=%02X STAT=%02X", - fdcnum, fdc202[fdcnum].iopb, fddnum, fdc202[fdcnum].stat); - sim_printf("\n isbc202-%d: cw=%02X di=%02X nr=%02X ta=%02X sa=%02X ba=%04X", - fdcnum, cw, di, nr, ta, sa, ba); - sim_printf("\n isbc202-%d: maxsec=%02X maxcyl=%02X", - fdcnum, fdc202[fdcnum].fdd[fddnum].maxsec, fdc202[fdcnum].fdd[fddnum].maxcyl); - } - //check for not ready - switch(fddnum) { - case 0: - if ((fdc202[fdcnum].stat & RDY0) == 0) { - fdc202[fdcnum].rtype = RERR; - fdc202[fdcnum].rbyte0 = RB0NR; - fdc202[fdcnum].intff = 1; //set interrupt FF - sim_printf("\n isbc202-%d: Ready error on drive %d", fdcnum, fddnum); - return; - } - break; - case 1: - if ((fdc202[fdcnum].stat & RDY1) == 0) { - fdc202[fdcnum].rtype = RERR; - fdc202[fdcnum].rbyte0 = RB0NR; - fdc202[fdcnum].intff = 1; //set interrupt FF - sim_printf("\n isbc202-%d: Ready error on drive %d", fdcnum, fddnum); - return; - } - break; - case 2: - if ((fdc202[fdcnum].stat & RDY2) == 0) { - fdc202[fdcnum].rtype = RERR; - fdc202[fdcnum].rbyte0 = RB0NR; - fdc202[fdcnum].intff = 1; //set interrupt FF - sim_printf("\n isbc202-%d: Ready error on drive %d", fdcnum, fddnum); - return; - } - break; - case 3: - if ((fdc202[fdcnum].stat & RDY3) == 0) { - fdc202[fdcnum].rtype = RERR; - fdc202[fdcnum].rbyte0 = RB0NR; - fdc202[fdcnum].intff = 1; //set interrupt FF - sim_printf("\n isbc202-%d: Ready error on drive %d", fdcnum, fddnum); - return; - } - break; - } - //check for address error - if ( - ((di & 0x07) != 0x03) && ( - (sa > fdc202[fdcnum].fdd[fddnum].maxsec) || - ((sa + nr) > (fdc202[fdcnum].fdd[fddnum].maxsec + 1)) || - (sa == 0) || - (ta > fdc202[fdcnum].fdd[fddnum].maxcyl) - )) { - if (DEBUG) - sim_printf("\n isbc202-%d: maxsec=%02X maxcyl=%02X", - fdcnum, fdc202[fdcnum].fdd[fddnum].maxsec, fdc202[fdcnum].fdd[fddnum].maxcyl); - fdc202[fdcnum].rtype = RERR; - fdc202[fdcnum].rbyte0 = RB0ADR; - fdc202[fdcnum].intff = 1; //set interrupt FF - sim_printf("\n isbc202-%d: Address error on drive %d", fdcnum, fddnum); - return; - } - switch (di & 0x07) { - case DNOP: - fdc202[fdcnum].rtype = ROK; - fdc202[fdcnum].intff = 1; //set interrupt FF - break; - case DSEEK: - fdc202[fdcnum].fdd[fddnum].sec = sa; - fdc202[fdcnum].fdd[fddnum].cyl = ta; - fdc202[fdcnum].rtype = ROK; - fdc202[fdcnum].intff = 1; //set interrupt FF - break; - case DHOME: - fdc202[fdcnum].fdd[fddnum].sec = sa; - fdc202[fdcnum].fdd[fddnum].cyl = 0; - fdc202[fdcnum].rtype = ROK; - fdc202[fdcnum].intff = 1; //set interrupt FF - break; - case DVCRC: - fdc202[fdcnum].rtype = ROK; - fdc202[fdcnum].intff = 1; //set interrupt FF - break; - case DFMT: - //check for WP - if(uptr->flags & UNIT_WPMODE) { - fdc202[fdcnum].rtype = RERR; - fdc202[fdcnum].rbyte0 = RB0WP; - fdc202[fdcnum].intff = 1; //set interrupt FF - sim_printf("\n isbc202-%d: Write protect error 1 on drive %d", fdcnum, fddnum); - return; - } - fmtb = multibus_get_mbyte(ba); //get the format byte - //calculate offset into disk image - dskoff = ((ta * (uint32)(fdc202[fdcnum].fdd[fddnum].maxsec)) + (sa - 1)) * 128; - for(i=0; i<=((uint32)(fdc202[fdcnum].fdd[fddnum].maxsec) * 128); i++) { - *(fdc202[fdcnum].fdd[fddnum].buf + (dskoff + i)) = fmtb; - } - //*** quick fix. Needs more thought! - fp = fopen(uptr->filename, "wb"); // write out modified image - for (i=0; icapac; i++) { - c = *(fdc202[fdcnum].fdd[fddnum].buf + i); - fputc(c, fp); - } - fclose(fp); - fdc202[fdcnum].rtype = ROK; - fdc202[fdcnum].intff = 1; //set interrupt FF - break; - case DREAD: - nrptr = 0; - while(nrptr < nr) { - //calculate offset into disk image - dskoff = ((ta * fdc202[fdcnum].fdd[fddnum].maxsec) + (sa - 1)) * 128; -// sim_printf("\n isbc202-%d: cw=%02X di=%02X nr=%02X ta=%02X sa=%02X ba=%04X dskoff=%06X", -// fdcnum, cw, di, nr, ta, sa, ba, dskoff); - for (i=0; i<128; i++) { //copy sector from image to RAM - data = *(fdc202[fdcnum].fdd[fddnum].buf + (dskoff + i)); - multibus_put_mbyte(ba + i, data); - } - sa++; - ba+=0x80; - nrptr++; - } - fdc202[fdcnum].rtype = ROK; - fdc202[fdcnum].intff = 1; //set interrupt FF - break; - case DWRITE: - //check for WP - if(uptr->flags & UNIT_WPMODE) { - fdc202[fdcnum].rtype = RERR; - fdc202[fdcnum].rbyte0 = RB0WP; - fdc202[fdcnum].intff = 1; //set interrupt FF - sim_printf("\n isbc202-%d: Write protect error 2 on drive %d", fdcnum, fddnum); - return; - } - nrptr = 0; - while(nrptr < nr) { - //calculate offset into disk image - dskoff = ((ta * fdc202[fdcnum].fdd[fddnum].maxsec) + (sa - 1)) * 128; - // sim_printf("\n isbc202-%d: cw=%02X di=%02X nr=%02X ta=%02X sa=%02X ba=%04X dskoff=%06X", - // fdcnum, cw, di, nr, ta, sa, ba, dskoff); - for (i=0; i<128; i++) { //copy sector from image to RAM - data = multibus_get_mbyte(ba + i); - *(fdc202[fdcnum].fdd[fddnum].buf + (dskoff + i)) = data; - } - sa++; - ba+=0x80; - nrptr++; - } - //*** quick fix. Needs more thought! - fp = fopen(uptr->filename, "wb"); // write out modified image - for (i=0; icapac; i++) { - c = *(fdc202[fdcnum].fdd[fddnum].buf + i); - fputc(c, fp); - } - fclose(fp); - fdc202[fdcnum].rtype = ROK; - fdc202[fdcnum].intff = 1; //set interrupt FF - break; - default: - sim_printf("\n isbc202-%d: isbc202_diskio bad di=%02X", fdcnum, di & 0x07); - break; - } -} - -/* end of isbc202.c */ +/* isbc202.c: Intel double density disk adapter 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: + + 27 Jun 16 - Original file. + + NOTES: + + This controller will mount 4 DD disk images on drives :F0: thru :F3: addressed + at ports 078H to 07FH. + + Registers: + + 078H - Read - Subsystem status + bit 0 - ready status of drive 0 + bit 1 - ready status of drive 1 + bit 2 - state of channel's interrupt FF + bit 3 - controller presence indicator + bit 4 - DD controller presence indicator + bit 5 - ready status of drive 2 + bit 6 - ready status of drive 3 + bit 7 - zero + + 079H - Read - Read result type (bits 2-7 are zero) + 00 - I/O complete with error + 01 - Reserved + 10 - Result byte contains diskette ready status + 11 - Reserved + 079H - Write - IOPB address low byte. + + 07AH - Write - IOPB address high byte and start operation. + + 07BH - Read - Read result byte + If result type is 00H + bit 0 - deleted record + bit 1 - CRC error + bit 2 - seek error + bit 3 - address error + bit 4 - data overrun/underrun + bit 5 - write protect + bit 6 - write error + bit 7 - not ready + If result type is 02H and ready has changed + bit 0 - zero + bit 1 - zero + bit 2 - zero + bit 3 - zero + bit 4 - drive 2 ready + bit 5 - drive 3 ready + bit 6 - drive 0 ready + bit 7 - drive 1 ready + else return 0 + + 07FH - Write - Reset diskette system. + + Operations: + NOP - 0x00 + Seek - 0x01 + Format Track - 0x02 + Recalibrate - 0x03 + Read Data - 0x04 + Verify CRC - 0x05 + Write Data - 0x06 + Write Deleted Data - 0x07 + + IOPB - I/O Parameter Block + Byte 0 - Channel Word + bit 3 - data word length (=8-bit, 1=16-bit) + bit 4-5 - interrupt control + 00 - I/O complete interrupt to be issued + 01 - I/O complete interrupts are disabled + 10 - illegal code + 11 - illegal code + bit 6- randon format sequence + + Byte 1 - Diskette Instruction + bit 0-2 - operation code + 000 - no operation + 001 - seek + 010 - format track + 011 - recalibrate + 100 - read data + 101 - verify CRC + 110 - write data + 111 - write deleted data + bit 3 - data word length ( same as byte-0, bit-3) + bit 4-5 - unit select + 00 - drive 0 + 01 - drive 1 + 10 - drive 2 + 11 - drive 3 + bit 6-7 - reserved (zero) + + Byte 2 - Number of Records + + Byte 4 - Track Address + + Byte 5 - Sector Address + + Byte 6 - Buffer Low Address + + Byte 7 - Buffer High Address + + u3 - + u4 - + u5 - fdc number. + u6 - fdd number. + +*/ + +#include "system_defs.h" /* system header in system dir */ + +#define DEBUG 0 + +#define UNIT_V_WPMODE (UNIT_V_UF) /* Write protect */ +#define UNIT_WPMODE (1 << UNIT_V_WPMODE) + +#define FDD_NUM 4 + +//disk controoler operations +#define DNOP 0x00 //disk no operation +#define DSEEK 0x01 //disk seek +#define DFMT 0x02 //disk format +#define DHOME 0x03 //disk home +#define DREAD 0x04 //disk read +#define DVCRC 0x05 //disk verify CRC +#define DWRITE 0x06 //disk write + +//status +#define RDY0 0x01 //FDD 0 ready +#define RDY1 0x02 //FDD 1 ready +#define FDCINT 0x04 //FDC interrupt flag +#define FDCPRE 0x08 //FDC board present +#define FDCDD 0x10 //fdc is DD +#define RDY2 0x20 //FDD 2 ready +#define RDY3 0x40 //FDD 3 ready + +//result type +#define RERR 0x00 //FDC returned error +#define ROK 0x02 //FDC returned ok + +// If result type is RERR then rbyte is +#define RB0DR 0x01 //deleted record +#define RB0CRC 0x02 //CRC error +#define RB0SEK 0x04 //seek error +#define RB0ADR 0x08 //address error +#define RB0OU 0x10 //data overrun/underrun +#define RB0WP 0x20 //write protect +#define RB0WE 0x40 //write error +#define RB0NR 0x80 //not ready + +// If result type is ROK then rbyte is +#define RB1RD2 0x10 //drive 2 ready +#define RB1RD3 0x20 //drive 3 ready +#define RB1RD0 0x40 //drive 0 ready +#define RB1RD1 0x80 //drive 1 ready + +/* external globals */ + +extern uint16 port; //port called in dev_table[port] +extern int32 PCX; + +/* external function prototypes */ + +extern uint16 reg_dev(uint8 (*routine)(t_bool, uint8), uint16, uint8); +extern uint8 multibus_get_mbyte(uint16 addr); +extern uint16 multibus_get_mword(uint16 addr); +extern void multibus_put_mbyte(uint16 addr, uint8 val); +extern uint8 multibus_put_mword(uint16 addr, uint16 val); + +/* function prototypes */ + +t_stat isbc202_reset(DEVICE *dptr, uint16 base); +void isbc202_reset1(uint8 fdcnum); +t_stat isbc202_attach (UNIT *uptr, CONST char *cptr); +t_stat isbc202_set_mode (UNIT *uptr, int32 val, CONST char *cptr, void *desc); +uint8 isbc202_get_dn(void); +uint8 isbc2020(t_bool io, uint8 data); /* isbc202 0 */ +uint8 isbc2021(t_bool io, uint8 data); /* isbc202 1 */ +uint8 isbc2022(t_bool io, uint8 data); /* isbc202 2 */ +uint8 isbc2023(t_bool io, uint8 data); /* isbc202 3 */ +uint8 isbc2027(t_bool io, uint8 data); /* isbc202 7 */ +void isbc202_diskio(uint8 fdcnum); //do actual disk i/o + +/* globals */ + +int32 isbc202_fdcnum = 0; //actual number of SBC-202 instances + 1 + +typedef struct { //FDD definition + uint8 *buf; + int t0; + int rdy; + uint8 sec; + uint8 cyl; + uint8 maxsec; + uint8 maxcyl; + } FDDDEF; + +typedef struct { //FDC definition + uint16 baseport; //FDC base port + uint16 iopb; //FDC IOPB + uint8 stat; //FDC status + uint8 rdychg; //FDC ready change + uint8 rtype; //FDC result type + uint8 rbyte0; //FDC result byte for type 00 + uint8 rbyte1; //FDC result byte for type 10 + uint8 intff; //fdc interrupt FF + FDDDEF fdd[FDD_NUM]; //indexed by the FDD number + } FDCDEF; + +FDCDEF fdc202[4]; //indexed by the isbc-202 instance number + +UNIT isbc202_unit[] = { + { UDATA (0, UNIT_ATTABLE+UNIT_DISABLE, 0), 20 }, + { UDATA (0, UNIT_ATTABLE+UNIT_DISABLE, 0), 20 }, + { UDATA (0, UNIT_ATTABLE+UNIT_DISABLE, 0), 20 }, + { UDATA (0, UNIT_ATTABLE+UNIT_DISABLE, 0), 20 } +}; + +REG isbc202_reg[] = { + { HRDATA (STAT0, fdc202[0].stat, 8) }, /* isbc202 0 status */ + { HRDATA (RTYP0, fdc202[0].rtype, 8) }, /* isbc202 0 result type */ + { HRDATA (RBYT0A, fdc202[0].rbyte0, 8) }, /* isbc202 0 result byte 0 */ + { HRDATA (RBYT0B, fdc202[0].rbyte1, 8) }, /* isbc202 0 result byte 1 */ + { HRDATA (INTFF0, fdc202[0].intff, 8) }, /* isbc202 0 interrupt f/f */ + { HRDATA (STAT1, fdc202[1].stat, 8) }, /* isbc202 1 status */ + { HRDATA (RTYP1, fdc202[1].rtype, 8) }, /* isbc202 1 result type */ + { HRDATA (RBYT1A, fdc202[1].rbyte0, 8) }, /* isbc202 1 result byte 0 */ + { HRDATA (RBYT1B, fdc202[1].rbyte1, 8) }, /* isbc202 1 result byte 1 */ + { HRDATA (INTFF1, fdc202[1].intff, 8) }, /* isbc202 1 interrupt f/f */ + { HRDATA (STAT2, fdc202[2].stat, 8) }, /* isbc202 2 status */ + { HRDATA (RTYP2, fdc202[2].rtype, 8) }, /* isbc202 2 result type */ + { HRDATA (RBYT2A, fdc202[2].rbyte0, 8) }, /* isbc202 2 result byte 0 */ + { HRDATA (RBYT2B, fdc202[0].rbyte1, 8) }, /* isbc202 2 result byte 1 */ + { HRDATA (INTFF2, fdc202[2].intff, 8) }, /* isbc202 2 interrupt f/f */ + { HRDATA (STAT3, fdc202[3].stat, 8) }, /* isbc202 3 status */ + { HRDATA (RTYP3, fdc202[3].rtype, 8) }, /* isbc202 3 result type */ + { HRDATA (RBYT3A, fdc202[3].rbyte0, 8) }, /* isbc202 3 result byte 0 */ + { HRDATA (RBYT3B, fdc202[3].rbyte1, 8) }, /* isbc202 3 result byte 1 */ + { HRDATA (INTFF3, fdc202[0].intff, 8) }, /* isbc202 3 interrupt f/f */ + { NULL } +}; + +MTAB isbc202_mod[] = { + { UNIT_WPMODE, 0, "RW", "RW", &isbc202_set_mode }, + { UNIT_WPMODE, UNIT_WPMODE, "WP", "WP", &isbc202_set_mode }, + { 0 } +}; + +DEBTAB isbc202_debug[] = { + { "ALL", DEBUG_all }, + { "FLOW", DEBUG_flow }, + { "READ", DEBUG_read }, + { "WRITE", DEBUG_write }, + { "XACK", DEBUG_xack }, + { "LEV1", DEBUG_level1 }, + { "LEV2", DEBUG_level2 }, + { NULL } +}; + +/* address width is set to 16 bits to use devices in 8086/8088 implementations */ + +DEVICE isbc202_dev = { + "SBC202", //name + isbc202_unit, //units + isbc202_reg, //registers + isbc202_mod, //modifiers + FDD_NUM, //numunits + 16, //aradix + 16, //awidth + 1, //aincr + 16, //dradix + 8, //dwidth + NULL, //examine + NULL, //deposit + NULL, //reset + NULL, //boot + &isbc202_attach, //attach + NULL, //detach + NULL, //ctxt + DEV_DEBUG+DEV_DISABLE+DEV_DIS, //flags + DEBUG_flow + DEBUG_read + DEBUG_write, //dctrl + isbc202_debug, //debflags + NULL, //msize + NULL //lname +}; + +/* Hardware reset routine */ + +t_stat isbc202_reset(DEVICE *dptr, uint16 base) +{ + sim_printf(" iSBC-202 FDC Board"); + if (SBC202_NUM) { + sim_printf(" - Found\n"); + sim_printf(" isbc202-%d: Hardware Reset\n", isbc202_fdcnum); + sim_printf(" isbc202-%d: Registered at %04X\n", isbc202_fdcnum, base); + fdc202[isbc202_fdcnum].baseport = base; + reg_dev(isbc2020, base, isbc202_fdcnum); //read status + reg_dev(isbc2021, base + 1, isbc202_fdcnum); //read rslt type/write IOPB addr-l + reg_dev(isbc2022, base + 2, isbc202_fdcnum); //write IOPB addr-h and start + reg_dev(isbc2023, base + 3, isbc202_fdcnum); //read rstl byte + reg_dev(isbc2027, base + 7, isbc202_fdcnum); //write reset isbc202 + isbc202_reset1(isbc202_fdcnum); + isbc202_fdcnum++; + } else + sim_printf(" - Not Found\n"); + return SCPE_OK; +} + +/* Software reset routine */ + +void isbc202_reset1(uint8 fdcnum) +{ + int32 i; + UNIT *uptr; + + sim_printf(" isbc202-%d: Software Reset\n", fdcnum); + fdc202[fdcnum].stat = 0; //clear status + for (i = 0; i < FDD_NUM; i++) { /* handle all units */ + uptr = isbc202_dev.units + i; + fdc202[fdcnum].stat |= FDCPRE | FDCDD; //set the FDC status + fdc202[fdcnum].rtype = ROK; + if (uptr->capac == 0) { /* if not configured */ + uptr->u5 = fdcnum; //fdc device number + uptr->u6 = i; //fdd unit number + uptr->flags |= UNIT_WPMODE; /* set WP in unit flags */ + sim_printf(" SBC202%d: Configured, Status=%02X Not attached\n", i, fdc202[fdcnum].stat); + } else { + switch(i){ + case 0: + fdc202[fdcnum].stat |= RDY0; //set FDD 0 ready + fdc202[fdcnum].rbyte1 |= RB1RD0; + fdc202[fdcnum].rdychg = 0; + break; + case 1: + fdc202[fdcnum].stat |= RDY1; //set FDD 1 ready + fdc202[fdcnum].rbyte1 |= RB1RD1; + fdc202[fdcnum].rdychg = 0; + break; + case 2: + fdc202[fdcnum].stat |= RDY2; //set FDD 2 ready + fdc202[fdcnum].rbyte1 |= RB1RD2; + fdc202[fdcnum].rdychg = 0; + break; + case 3: + fdc202[fdcnum].stat |= RDY3; //set FDD 3 ready + fdc202[fdcnum].rbyte1 |= RB1RD3; + fdc202[fdcnum].rdychg = 0; + break; + } + sim_printf(" SBC202%d: Configured, Status=%02X Attached to %s\n", + i, fdc202[fdcnum].stat, uptr->filename); + } + } +} + +/* isbc202 attach - attach an .IMG file to a FDD */ + +t_stat isbc202_attach (UNIT *uptr, CONST char *cptr) +{ + t_stat r; + FILE *fp; + int32 i, c = 0; + long flen; + uint8 fdcnum, fddnum; + + sim_debug (DEBUG_flow, &isbc202_dev, " isbc202_attach: Entered with cptr=%s\n", cptr); + if ((r = attach_unit (uptr, cptr)) != SCPE_OK) { + sim_printf(" isbc202_attach: Attach error\n"); + return r; + } + fdcnum = uptr->u5; + fddnum = uptr->u6; + fp = fopen(uptr->filename, "rb"); + if (fp == NULL) { + sim_printf(" Unable to open disk image file %s\n", uptr->filename); + sim_printf(" No disk image loaded!!!\n"); + } else { + sim_printf("isbc202: Attach\n"); + fseek(fp, 0, SEEK_END); /* size disk image */ + flen = ftell(fp); + fseek(fp, 0, SEEK_SET); + if (flen == -1) { + sim_printf(" isbc202_attach: File error\n"); + return SCPE_IOERR; + } + if (fdc202[fdcnum].fdd[fddnum].buf == NULL) { /* no buffer allocated */ + fdc202[fdcnum].fdd[fddnum].buf = (uint8 *)malloc(flen); + if (fdc202[fdcnum].fdd[fddnum].buf == NULL) { + sim_printf(" isbc202_attach: Malloc error\n"); + return SCPE_MEM; + } + } + uptr->capac = flen; + i = 0; + c = fgetc(fp); // copy disk image into buffer + while (c != EOF) { + *(fdc202[fdcnum].fdd[fddnum].buf + i++) = c & 0xFF; + c = fgetc(fp); + } + fclose(fp); + switch(fddnum){ + case 0: + fdc202[fdcnum].stat |= RDY0; //set FDD 0 ready + fdc202[fdcnum].rtype = ROK; + fdc202[fdcnum].rbyte1 |= RB1RD0; + break; + case 1: + fdc202[fdcnum].stat |= RDY1; //set FDD 1 ready + fdc202[fdcnum].rtype = ROK; + fdc202[fdcnum].rbyte1 |= RB1RD1; + break; + case 2: + fdc202[fdcnum].stat |= RDY2; //set FDD 2 ready + fdc202[fdcnum].rtype = ROK; + fdc202[fdcnum].rbyte1 |= RB1RD2; + break; + case 3: + fdc202[fdcnum].stat |= RDY3; //set FDD 3 ready + fdc202[fdcnum].rtype = ROK; + fdc202[fdcnum].rbyte1 |= RB1RD3; + break; + } + if (flen == 512512) { /* 8" 512K SSDD */ + fdc202[fdcnum].fdd[fddnum].maxcyl = 77; + fdc202[fdcnum].fdd[fddnum].maxsec = 52; + fdc202[fdcnum].fdd[fddnum].sec = 1; + fdc202[fdcnum].fdd[fddnum].cyl = 0; + } else + sim_printf(" iSBC-202-%d: Not a DD disk image\n", fdcnum); + sim_printf(" iSBC-202%d: Configured %d bytes, Attached to %s\n", + fdcnum, uptr->capac, uptr->filename); + } + sim_debug (DEBUG_flow, &isbc202_dev, " isbc202_attach: Done\n"); + return SCPE_OK; +} + +/* isbc202 set mode = Write protect */ + +t_stat isbc202_set_mode (UNIT *uptr, int32 val, CONST char *cptr, void *desc) +{ +// sim_debug (DEBUG_flow, &isbc202_dev, " isbc202_set_mode: Entered with val=%08XH uptr->flags=%08X\n", +// val, uptr->flags); + if (val & UNIT_WPMODE) { /* write protect */ + uptr->flags |= val; + } else { /* read write */ + uptr->flags &= ~val; + } +// sim_debug (DEBUG_flow, &isbc202_dev, " isbc202_set_mode: Done\n"); + return SCPE_OK; +} + +uint8 isbc202_get_dn(void) +{ + int i; + +// for (i=0; i= fdc202[i].baseport && port <= fdc202[i].baseport + 7) + return i; + sim_printf("isbc202_get_dn: port %04X not in isbc202 device table\n", port); + return 0xFF; +} + +/* ISBC202 control port functions */ + +uint8 isbc2020(t_bool io, uint8 data) +{ + uint8 fdcnum; + + if ((fdcnum = isbc202_get_dn()) != 0xFF) { + if (io == 0) { /* read ststus*/ + if (DEBUG) + sim_printf("\n isbc202-%d: 0x78 returned status=%02X PCX=%04X", + fdcnum, fdc202[fdcnum].stat, PCX); + return fdc202[fdcnum].stat; + } + } + return 0; +} + +uint8 isbc2021(t_bool io, uint8 data) +{ + uint8 fdcnum; + + if ((fdcnum = isbc202_get_dn()) != 0xFF) { + if (io == 0) { /* read data port */ + fdc202[fdcnum].intff = 0; //clear interrupt FF + fdc202[fdcnum].stat &= ~FDCINT; + if (DEBUG) + sim_printf("\n isbc202-%d: 0x79 returned rtype=%02X intff=%02X status=%02X PCX=%04X", + fdcnum, fdc202[fdcnum].rtype, fdc202[fdcnum].intff, fdc202[fdcnum].stat, PCX); + return fdc202[fdcnum].rtype; + } else { /* write data port */ + fdc202[fdcnum].iopb = data; + if (DEBUG) + sim_printf("\n isbc202-%d: 0x79 IOPB low=%02X PCX=%04X", + fdcnum, data, PCX); + } + } + return 0; +} + +uint8 isbc2022(t_bool io, uint8 data) +{ + uint8 fdcnum; + + if ((fdcnum = isbc202_get_dn()) != 0xFF) { + if (io == 0) { /* read data port */ + ; + } else { /* write data port */ + fdc202[fdcnum].iopb |= (data << 8); + if (DEBUG) + sim_printf("\n isbc202-%d: 0x7A IOPB=%04X PCX=%04X", + fdcnum, fdc202[fdcnum].iopb, PCX); + isbc202_diskio(fdcnum); + if (fdc202[fdcnum].intff) + fdc202[fdcnum].stat |= FDCINT; + } + } + return 0; +} + +uint8 isbc2023(t_bool io, uint8 data) +{ + uint8 fdcnum; + + if ((fdcnum = isbc202_get_dn()) != 0xFF) { + if (io == 0) { /* read data port */ + if (fdc202[fdcnum].rtype == 0) { + if (DEBUG) + sim_printf("\n isbc202-%d: 0x7B returned rbyte0=%02X PCX=%04X", + fdcnum, fdc202[fdcnum].rbyte0, PCX); + return fdc202[fdcnum].rbyte0; + } else { + if (fdc202[fdcnum].rdychg) { + if (DEBUG) + sim_printf("\n isbc202-%d: 0x7B returned rbyte1=%02X PCX=%04X", + fdcnum, fdc202[fdcnum].rbyte1, PCX); + return fdc202[fdcnum].rbyte1; + } else { + if (DEBUG) + sim_printf("\n isbc202-%d: 0x7B returned rbytex=%02X PCX=%04X", + fdcnum, 0, PCX); + return 0; + } + } + } else { /* write data port */ + ; //stop diskette operation + } + } + return 0; +} + +uint8 isbc2027(t_bool io, uint8 data) +{ + uint8 fdcnum; + + if ((fdcnum = isbc202_get_dn()) != 0xFF) { + if (io == 0) { /* read data port */ + ; + } else { /* write data port */ + isbc202_reset1(fdcnum); + } + } + return 0; +} + +// perform the actual disk I/O operation + +void isbc202_diskio(uint8 fdcnum) +{ + uint8 cw, di, nr, ta, sa, data, nrptr, c; + uint16 ba; + uint32 dskoff; + uint8 fddnum, fmtb; + uint32 i; + UNIT *uptr; + FILE *fp; + //parse the IOPB + cw = multibus_get_mbyte(fdc202[fdcnum].iopb); + di = multibus_get_mbyte(fdc202[fdcnum].iopb + 1); + nr = multibus_get_mbyte(fdc202[fdcnum].iopb + 2); + ta = multibus_get_mbyte(fdc202[fdcnum].iopb + 3); + sa = multibus_get_mbyte(fdc202[fdcnum].iopb + 4); + ba = multibus_get_mword(fdc202[fdcnum].iopb + 5); + fddnum = (di & 0x30) >> 4; + uptr = isbc202_dev.units + fddnum; + if (DEBUG) { + sim_printf("\n isbc202-%d: isbc202_diskio IOPB=%04X FDD=%02X STAT=%02X", + fdcnum, fdc202[fdcnum].iopb, fddnum, fdc202[fdcnum].stat); + sim_printf("\n isbc202-%d: cw=%02X di=%02X nr=%02X ta=%02X sa=%02X ba=%04X", + fdcnum, cw, di, nr, ta, sa, ba); +// sim_printf("\n isbc202-%d: maxsec=%02X maxcyl=%02X", +// fdcnum, fdc202[fdcnum].fdd[fddnum].maxsec, fdc202[fdcnum].fdd[fddnum].maxcyl); + } + //check for not ready + switch(fddnum) { + case 0: + if ((fdc202[fdcnum].stat & RDY0) == 0) { + fdc202[fdcnum].rtype = RERR; + fdc202[fdcnum].rbyte0 = RB0NR; + fdc202[fdcnum].intff = 1; //set interrupt FF + sim_printf("\n isbc202-%d: Ready error on drive %d", fdcnum, fddnum); + return; + } + break; + case 1: + if ((fdc202[fdcnum].stat & RDY1) == 0) { + fdc202[fdcnum].rtype = RERR; + fdc202[fdcnum].rbyte0 = RB0NR; + fdc202[fdcnum].intff = 1; //set interrupt FF + sim_printf("\n isbc202-%d: Ready error on drive %d", fdcnum, fddnum); + return; + } + break; + case 2: + if ((fdc202[fdcnum].stat & RDY2) == 0) { + fdc202[fdcnum].rtype = RERR; + fdc202[fdcnum].rbyte0 = RB0NR; + fdc202[fdcnum].intff = 1; //set interrupt FF + sim_printf("\n isbc202-%d: Ready error on drive %d", fdcnum, fddnum); + return; + } + break; + case 3: + if ((fdc202[fdcnum].stat & RDY3) == 0) { + fdc202[fdcnum].rtype = RERR; + fdc202[fdcnum].rbyte0 = RB0NR; + fdc202[fdcnum].intff = 1; //set interrupt FF + sim_printf("\n isbc202-%d: Ready error on drive %d", fdcnum, fddnum); + return; + } + break; + } + //check for address error + if ( + ((di & 0x07) != 0x03) && ( + (sa > fdc202[fdcnum].fdd[fddnum].maxsec) || + ((sa + nr) > (fdc202[fdcnum].fdd[fddnum].maxsec + 1)) || + (sa == 0) || + (ta > fdc202[fdcnum].fdd[fddnum].maxcyl) + )) { + if (DEBUG) + sim_printf("\n isbc202-%d: maxsec=%02X maxcyl=%02X", + fdcnum, fdc202[fdcnum].fdd[fddnum].maxsec, fdc202[fdcnum].fdd[fddnum].maxcyl); + fdc202[fdcnum].rtype = RERR; + fdc202[fdcnum].rbyte0 = RB0ADR; + fdc202[fdcnum].intff = 1; //set interrupt FF + sim_printf("\n isbc202-%d: Address error on drive %d", fdcnum, fddnum); + return; + } + switch (di & 0x07) { + case DNOP: + fdc202[fdcnum].rtype = ROK; + fdc202[fdcnum].intff = 1; //set interrupt FF + break; + case DSEEK: + fdc202[fdcnum].fdd[fddnum].sec = sa; + fdc202[fdcnum].fdd[fddnum].cyl = ta; + fdc202[fdcnum].rtype = ROK; + fdc202[fdcnum].intff = 1; //set interrupt FF + break; + case DHOME: + fdc202[fdcnum].fdd[fddnum].sec = sa; + fdc202[fdcnum].fdd[fddnum].cyl = 0; + fdc202[fdcnum].rtype = ROK; + fdc202[fdcnum].intff = 1; //set interrupt FF + break; + case DVCRC: + fdc202[fdcnum].rtype = ROK; + fdc202[fdcnum].intff = 1; //set interrupt FF + break; + case DFMT: + //check for WP + if(uptr->flags & UNIT_WPMODE) { + fdc202[fdcnum].rtype = RERR; + fdc202[fdcnum].rbyte0 = RB0WP; + fdc202[fdcnum].intff = 1; //set interrupt FF + sim_printf("\n isbc202-%d: Write protect error 1 on drive %d", fdcnum, fddnum); + return; + } + fmtb = multibus_get_mbyte(ba); //get the format byte + //calculate offset into disk image + dskoff = ((ta * (uint32)(fdc202[fdcnum].fdd[fddnum].maxsec)) + (sa - 1)) * 128; + for(i=0; i<=((uint32)(fdc202[fdcnum].fdd[fddnum].maxsec) * 128); i++) { + *(fdc202[fdcnum].fdd[fddnum].buf + (dskoff + i)) = fmtb; + } + //*** quick fix. Needs more thought! + fp = fopen(uptr->filename, "wb"); // write out modified image + for (i=0; icapac; i++) { + c = *(fdc202[fdcnum].fdd[fddnum].buf + i); + fputc(c, fp); + } + fclose(fp); + fdc202[fdcnum].rtype = ROK; + fdc202[fdcnum].intff = 1; //set interrupt FF + break; + case DREAD: + nrptr = 0; + while(nrptr < nr) { + //calculate offset into disk image + dskoff = ((ta * fdc202[fdcnum].fdd[fddnum].maxsec) + (sa - 1)) * 128; +// sim_printf("\n isbc202-%d: cw=%02X di=%02X nr=%02X ta=%02X sa=%02X ba=%04X dskoff=%06X", +// fdcnum, cw, di, nr, ta, sa, ba, dskoff); + for (i=0; i<128; i++) { //copy sector from image to RAM + data = *(fdc202[fdcnum].fdd[fddnum].buf + (dskoff + i)); + multibus_put_mbyte(ba + i, data); + } + sa++; + ba+=0x80; + nrptr++; + } + fdc202[fdcnum].rtype = ROK; + fdc202[fdcnum].intff = 1; //set interrupt FF + break; + case DWRITE: + //check for WP + if(uptr->flags & UNIT_WPMODE) { + fdc202[fdcnum].rtype = RERR; + fdc202[fdcnum].rbyte0 = RB0WP; + fdc202[fdcnum].intff = 1; //set interrupt FF + sim_printf("\n isbc202-%d: Write protect error 2 on drive %d", fdcnum, fddnum); + return; + } + nrptr = 0; + while(nrptr < nr) { + //calculate offset into disk image + dskoff = ((ta * fdc202[fdcnum].fdd[fddnum].maxsec) + (sa - 1)) * 128; + // sim_printf("\n isbc202-%d: cw=%02X di=%02X nr=%02X ta=%02X sa=%02X ba=%04X dskoff=%06X", + // fdcnum, cw, di, nr, ta, sa, ba, dskoff); + for (i=0; i<128; i++) { //copy sector from image to RAM + data = multibus_get_mbyte(ba + i); + *(fdc202[fdcnum].fdd[fddnum].buf + (dskoff + i)) = data; + } + sa++; + ba+=0x80; + nrptr++; + } + //*** quick fix. Needs more thought! + fp = fopen(uptr->filename, "wb"); // write out modified image + for (i=0; icapac; i++) { + c = *(fdc202[fdcnum].fdd[fddnum].buf + i); + fputc(c, fp); + } + fclose(fp); + fdc202[fdcnum].rtype = ROK; + fdc202[fdcnum].intff = 1; //set interrupt FF + break; + default: + sim_printf("\n isbc202-%d: isbc202_diskio bad di=%02X", fdcnum, di & 0x07); + break; + } +} + +/* end of isbc202.c */ diff --git a/Intel-Systems/common/isbc208.c b/Intel-Systems/common/isbc208.c index ce205d62..b5612f75 100644 --- a/Intel-Systems/common/isbc208.c +++ b/Intel-Systems/common/isbc208.c @@ -1,1648 +1,1651 @@ -/* isbc208.c: Intel iSBC208 Floppy Disk adapter - - Copyright (c) 2011, William A. Beech - - Permission is hereby granted, free of charge, to any person obtaining a - copy of this software and associated documentation files (the "Software"), - to deal in the Software without restriction, including without limitation - the rights to use, copy, modify, merge, publish, distribute, sublicense, - and/or sell copies of the Software, and to permit persons to whom the - Software is furnished to do so, subject to the following conditions: - - The above copyright notice and this permission notice shall be included in - all copies or substantial portions of the Software. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - WILLIAM A. BEECH BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER - IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - - Except as contained in this notice, the name of William A. Beech shall not be - used in advertising or otherwise to promote the sale, use or other dealings - in this Software without prior written authorization from William A. Beech. - - MODIFICATIONS: - - ?? ??? 11 - Original file. - 24 Apr 15 -- Modified to use simh_debug - - NOTES: - - These functions support a simulated iSBC208 interface to 4 each 8-, 5 1/4-, or - 3 1/2-inch floppy disk drives. Commands are setup with programmed I/O to the - simulated ports of an i8237 DMA controller and an i8272 FDC. Data transfer - to/from the simulated disks is performed directly with the multibus memory. - - The iSBC-208 can be configured for 8- or 16-bit addresses. It defaults to 8-bit - addresses for the 8080/8085 processors. It can be configured for I/O port - addresses with 3-bits (8-bit address) or 11-bits (16-bit address). Default is - 3-bits set to 0. This defines the port offset to be used to determine the actual - port address. Bus priority can be configured for parallel or serial mode. Default is - serial. The multibus interface interrupt can be configured for interrupt 0-7. - Default is none. Since all channel registers in the i8237 are 16-bit, transfers - are done as two 8-bit operations, low- then high-byte. - - Port addressing is as follows (Port offset = 0): - - Port Mode Command Function - - 00 Write Load DMAC Channel 0 Base and Current Address Regsiters - Read Read DMAC Channel 0 Current Address Register - 01 Write Load DMAC Channel 0 Base and Current Word Count Registers - Read Read DMAC Channel 0 Current Word Count Register - 04 Write Load DMAC Channel 2 Base and Current Address Regsiters - Read Read DMAC Channel 2 Current Address Register - 05 Write Load DMAC Channel 2 Base and Current Word Count Registers - Read Read DMAC Channel 2 Current Word Count Register - 06 Write Load DMAC Channel 3 Base and Current Address Regsiters - Read Read DMAC Channel 3 Current Address Register - 07 Write Load DMAC Channel 3 Base and Current Word Count Registers - Read Read DMAC Channel 3 Current Word Count Register - 08 Write Load DMAC Command Register - Read Read DMAC Status Register - 09 Write Load DMAC Request Register - OA Write Set/Reset DMAC Mask Register - OB Write Load DMAC Mode Register - OC Write Clear DMAC First/Last Flip-Flop - 0D Write DMAC Master Clear - OF Write Load DMAC Mask Register - 10 Read Read FDC Status Register - 11 Write Load FDC Data Register - Read Read FDC Data Register - 12 Write Load Controller Auxiliary Port - Read Poll Interrupt Status - 13 Write Controller Reset - 14 Write Load Controller Low-Byte Segment Address Register - 15 Write Load Controller High-Byte Segment Address Register - 20-2F Read/Write Reserved for iSBX Multimodule Board - - Register usage is defined in the following paragraphs. - - Read/Write DMAC Address Registers - - Used to simultaneously load a channel's current-address register and base-address - register with the memory address of the first byte to be transferred. (The Channel - 0 current/base address register must be loaded prior to initiating a diskette read - or write operation.) Since each channel's address registers are 16 bits in length - (64K address range), two "write address register" commands must be executed in - order to load the complete current/base address registers for any channel. - - Read/Write DMAC Word Count Registers - - The Write DMAC Word Count Register command is used to simultaneously load a - channel's current and base word-count registers with the number of bytes - to be transferred during a subsequent DMA operation. Since the word-count - registers are 16-bits in length, two commands must be executed to load both - halves of the registers. - - Write DMAC Command Register - - The Write DMAC Command Register command loads an 8-bit byte into the - DMAC's command register to define the operating characteristics of the - DMAC. The functions of the individual bits in the command register are - defined in the following diagram. Note that only two bits within the - register are applicable to the controller; the remaining bits select - functions that are not supported and, accordingly, must always be set - to zero. - - 7 6 5 4 3 2 1 0 - +---+---+---+---+---+---+---+---+ - | 0 0 0 0 0 0 | - +---+---+---+---+---+---+---+---+ - | | - | +---------- 0 CONTROLLER ENABLE - | 1 CONTROLLER DISABLE - | - +------------------ 0 FIXED PRIORITY - 1 ROTATING PRIORITY - - Read DMAC Status Register Command - - The Read DMAC Status Register command accesses an 8-bit status byte that - identifies the DMA channels that have reached terminal count or that - have a pending DMA request. - - 7 6 5 4 3 2 1 0 - +---+---+---+---+---+---+---+---+ - | 0 0 | - +---+---+---+---+---+---+---+---+ - | | | | | | - | | | | | +-- CHANNEL 0 TC - | | | | +---------- CHANNEL 2 TC - | | | +-------------- CHANNEL 3 TC - | | +------------------ CHANNEL 0 DMA REQUEST - | +-------------------------- CHANNEL 2 DMA REQUEST - +------------------------------ CHANNEL 3 DMA REQUEST - - Write DMAC Request Register - - The data byte associated with the Write DMAC Request Register command - sets or resets a channel's associated request bit within the DMAC's - internal 4-bit request register. - - 7 6 5 4 3 2 1 0 - +---+---+---+---+---+---+---+---+ - | X X X X X | - +---+---+---+---+---+---+---+---+ - | | | - | +---+-- 00 SELECT CHANNEL 0 - | 01 SELECT CHANNEL 1 - | 10 SELECT CHANNEL 2 - | 11 SELECT CHANNEL 3 - | - +---------- 0 RESET REQUEST BIT - 1 SET REQUEST BIT - - Set/Reset DMAC Mask Register - - Prior to a DREQ-initiated DMA transfer, the channel's mask bit must - be reset to enable recognition of the DREQ input. When the transfer - is complete (terminal count reached or external EOP applied) and - the channel is not programmed to autoinitialize, the channel's - mask bit is automatically set (disabling DREQ) and must be reset - prior to a subsequent DMA transfer. All four bits of the mask - register are set (disabling the DREQ inputs) by a DMAC master - clear or controller reset. Additionally, all four bits can be - set/reset by a single Write DMAC Mask Register command. - - - 7 6 5 4 3 2 1 0 - +---+---+---+---+---+---+---+---+ - | X X X X X | - +---+---+---+---+---+---+---+---+ - | | | - | +---+-- 00 SELECT CHANNEL 0 - | 01 SELECT CHANNEL 1 - | 10 SELECT CHANNEL 2 - | 11 SELECT CHANNEL 3 - | - +---------- 0 RESET REQUEST BIT - 1 SET REQUEST BIT - - Write DMAC Mode Register - - The Write DMAC Mode Register command is used to define the - operating mode characteristics for each DMA channel. Each - channel has an internal 6-bit mode register; the high-order - six bits of the associated data byte are written into the - mode register addressed by the two low-order bits. - - - 7 6 5 4 3 2 1 0 - +---+---+---+---+---+---+---+---+ - | | - +---+---+---+---+---+---+---+---+ - | | | | | | | | - | | | | | | +---+-- 00 SELECT CHANNEL 0 - | | | | | | 01 SELECT CHANNEL 1 - | | | | | | 10 SELECT CHANNEL 2 - | | | | | | 11 SELECT CHANNEL 3 - | | | | | | - | | | | +---+---------- 00 VERIFY TRANSFER - | | | | 01 WRITE TRANSFER - | | | | 10 READ TRANSFER - | | | | - | | | +------------------ 0 AUTOINITIALIZE DISABLE - | | | 1 AUTOINITIALIZE ENABLE - | | | - | | +---------------------- 0 ADDRESS INCREMENT - | | 1 ADDRESS DECREMENT - | | - +---+-------------------------- 00 DEMAND MODE - 01 SINGLE MODE - 10 BLOCK MODE - - Clear DMAC First/Last Flip-Flop - - The Clear DMAC First/Last Flip-Flop command initializes - the DMAC's internal first/last flip-flop so that the - next byte written to or re~d from the 16-bit address - or word-count registers is the low-order byte. The - flip-flop is toggled with each register access so that - a second register read or write command accesses the - high-order byte. - - DMAC Master Clear - - The DMAC Master Clear command clears the DMAC's command, status, - request, and temporary registers to zero, initializes the - first/last flip-flop, and sets the four channel mask bits in - the mask register to disable all DMA requests (i.e., the DMAC - is placed in an idle state). - - Write DMAC Mask Register - - The Write DMAC Mask Register command allows all four bits of the - DMAC's mask register to be written with a single command. - - 7 6 5 4 3 2 1 0 - +---+---+---+---+---+---+---+---+ - | X X X X X | - +---+---+---+---+---+---+---+---+ - | | | - | | +-- 0 CLEAR CHANNEL 0 MASK BIT - | | 1 SET CHANNEL 0 MASK BIT - | | - | +---------- 0 CLEAR CHANNEL 2 MASK BIT - | 1 SET CHANNEL 2 MASK BIT - | - +-------------- 0 CLEAR CHANNEL 3 MASK BIT - 1 SET CHANNEL 3 MASK BIT - - Read FDC Status Register - - The Read FDC Status Register command accesses the FDC's main - status register. The individual status register bits are as - follows: - - 7 6 5 4 3 2 1 0 - +---+---+---+---+---+---+---+---+ - | | - +---+---+---+---+---+---+---+---+ - | | | | | | | | - | | | | | | | +-- FDD 0 BUSY - | | | | | | +------ FDD 1 BUSY - | | | | | +---------- FDD 2 BUSY - | | | | +-------------- FDD 3 BUSY - | | | +------------------ FDC BUSY - | | +---------------------- NON-DMA MODE - | +-------------------------- DATA INPUT/OUTPUT - +------------------------------ REQUEST FOR MASTER - - Read/Write FDC Data Register - - The Read and Write FDC Data Register commands are used to write - command and parameter bytes to the FDC in order to specify the - operation to be performed (referred to as the "command phase") - and to read status bytes from the FDC following the operation - (referred to as the "result phase"). During the command and - result phases, the 8-bit data register is actually a series of - 8-bit registers in a stack. Each register is accessed in - sequence; the number of registers accessed and the individual - register contents are defined by the specific disk command. - - Write Controller Auxiliary Port - - The Write Controller Auxiliary Port command is used to set or - clear individual bits within the controller's auxiliary port. - The four low-order port bits are dedicated to auxiliary drive - control functions (jumper links are required to connect the - desired port bit to an available pin on the drive interface - connectors). The most common application for these bits is - the "Motor-On" control function for mini-sized drives. - - 7 6 5 4 3 2 1 0 - +---+---+---+---+---+---+---+---+ - | | - +---+---+---+---+---+---+---+---+ - | | | | | | | | - | | | | +---+---+---+-- DRIVE CONTROL - | | | +------------------ ADDR 20 - | | +---------------------- ADDR 21 - | +-------------------------- ADDR 22 - +------------------------------ ADDR 23 - - Poll Interrupt Status - - The Poll Interrupt Status command presents the interrupt - status of the controller and the two interrupt status - lines dedicated to the iSBX Multimodule board. - 7 6 5 4 3 2 1 0 - +---+---+---+---+---+---+---+---+ - | X X X X X | - +---+---+---+---+---+---+---+---+ - | | | - | | +-- CONTROLLER INTERRUPT - | +------ MULTIMODULE BOARD INTERRUPT 0 - +---------- MULTIMODULE BOARD INTERRUPT 1 - - Controller Reset - - The Controller Reset command is the software reset for the - controller. This command clears the controller's auxiliary - port and segment address register, provides a reset signal - to the iSBX Multimodule board and initializes the bus - controller (releases the bus), the DMAC (clears the internal - registers and masks the DREQ inputs), and the FDC (places - the FDC in an idle state and disables the output control - lines to the diskette drive). - - Write Controller Low- And High-Byte Segment Address Registers - - The Write Controller Low- and High-Byte Address Registers - commands are required when the controller uses 20-bit - addressing (memory address range from 0 to OFFFFFH). These - commands are issued prior to initiating a diskette read or - write operation to specify the 16-bit segment address. - - FDC Commands - - The 8272/D765 is capable of performing 15 different - commands. Each command is initiated by a multibyte transfer - from the processor, and the result after execution of the - command may also be a multibyte transfer back to the processor. - Because of this multibyte interchange of information between - the FDC and the processor, it is convenient to consider each - command as consisting of three phases: - - Command Phase: The FDC receives all information required to - perform a particular operation from the processor. - - Execution Phase: The FDC performs the operation it was - instructed to do. - - Result Phase: After completion of the operation, status - and other housekeeping information are made available - to the processor. - - Not all the FDC commands are supported by this emulation. Only the subset - of commands required to build an operable CP/M BIOS are supported. They are: - - Read - Read specified data from the selected FDD. - - Write - Write specified data to the selected FDD. - - Seek - Move the R/W head to the specified cylinder on the specified FDD. - - Specify - Set the characteristics for all the FDDs. - - Sense Interrupt - Sense change in FDD Ready line or and of Seek/Recalibrate - command. - - Sense Drive - Returns status of all the FDDs. - - Recalibrate - Move the R/W head to cylinder 0 on the specified FDD. - - Format Track - Format the current track on the specified FDD. - - Read ID - Reads the first address mark it finds. - - Simulated Floppy Disk Drives - - The units in this device simulate an 8- or 5 1/4- or 3 1/2 inch drives. The - drives can emulate SSSD, SSDD, and DSDD. Drives can be attached to files up - to 1.44MB in size. Drive configuration is selected when a disk is logged onto - the system. An identity sector or identity byte contains information to - configure the OS drivers for the type of drive to emulate. - - uptr->u3 - - uptr->u4 - - uptr->u5 - - uptr->u6 - unit number (0-FDD_NUM) -*/ - -#include "system_defs.h" - -#define UNIT_V_WPMODE (UNIT_V_UF) /* Write protect */ -#define UNIT_WPMODE (1 << UNIT_V_WPMODE) - -/* master status register definitions */ - -#define RQM 0x80 /* Request for master */ -#define DIO 0x40 /* Data I/O Direction 0=W, 1=R */ -#define NDM 0x20 /* Non-DMA mode */ -#define CB 0x10 /* FDC busy */ -#define D3B 0x08 /* FDD 3 busy */` -#define D2B 0x04 /* FDD 2 busy */` -#define D1B 0x02 /* FDD 1 busy */` -#define D0B 0x01 /* FDD 0 busy */` - -/* status register 0 definitions */ - -#define IC 0xC0 /* Interrupt code */ -#define IC_NORM 0x00 /* normal completion */ -#define IC_ABNORM 0x40 /* abnormal completion */ -#define IC_INVC 0x80 /* invalid command */ -#define IC_RC 0xC0 /* drive not ready */ -#define SE 0x20 /* Seek end */ -#define EC 0x10 /* Equipment check */ -#define NR 0x08 /* Not ready */ -#define HD 0x04 /* Head selected */ -#define US 0x03 /* Unit selected */ -#define US_0 0x00 /* Unit 0 */ -#define US_1 0x01 /* Unit 1 */ -#define US_2 0x02 /* Unit 2 */ -#define US_3 0x03 /* Unit 3 */ - -/* status register 1 definitions */ - -#define EN 0x80 /* End of cylinder */ -#define DE 0x20 /* Data error */ -#define OR 0x10 /* Overrun */ -#define ND 0x04 /* No data */ -#define NW 0x02 /* Not writable */ -#define MA 0x01 /* Missing address mark */ - -/* status register 2 definitions */ - -#define CM 0x40 /* Control mark */ -#define DD 0x20 /* Data error in data field */ -#define WC 0x10 /* Wrong cylinder */ -#define BC 0x02 /* Bad cylinder */ -#define MD 0x01 /* Missing address mark in data field */ - -/* status register 3/fddst definitions */ - -#define FT 0x80 /* Fault */ -#define WP 0x40 /* Write protect */ -#define RDY 0x20 /* Ready */ -#define T0 0x10 /* Track 0 */ -#define TS 0x08 /* Two sided */ -//#define HD 0x04 /* Head selected */ -//#define US 0x03 /* Unit selected */ - -/* FDC command definitions */ - -#define READTRK 0x02 -#define SPEC 0x03 -#define SENDRV 0x04 -#define WRITE 0x05 -#define READ 0x06 -#define HOME 0x07 -#define SENINT 0x08 -#define WRITEDEL 0x09 -#define READID 0x0A -#define READDEL 0x0C -#define FMTTRK 0x0D -#define SEEK 0x0F -#define SCANEQ 0x11 -#define SCANLOEQ 0x19 -#define SCANHIEQ 0x1D - -#define FDD_NUM 4 - -int32 sbc208_devnum = 0; //actual number of 8255 instances + 1 -uint16 sbc208_port[4]; //base port registered to each instance - -/* internal function prototypes */ - -t_stat isbc208_svc (UNIT *uptr); -t_stat isbc208_reset (DEVICE *dptr, uint16 base); -void isbc208_reset1 (void); -t_stat isbc208_attach (UNIT *uptr, CONST char *cptr); -t_stat isbc208_set_mode (UNIT *uptr, int32 val, CONST char *cptr, void *desc); -uint8 isbc208_r0(t_bool io, uint8 data); -uint8 isbc208_r1(t_bool io, uint8 data); -uint8 isbc208_r2(t_bool io, uint8 data); -uint8 isbc208_r3(t_bool io, uint8 data); -uint8 isbc208_r4(t_bool io, uint8 data); -uint8 isbc208_r5(t_bool io, uint8 data); -uint8 isbc208_r6(t_bool io, uint8 data); -uint8 isbc208_r7(t_bool io, uint8 data); -uint8 isbc208_r8(t_bool io, uint8 data); -uint8 isbc208_r9(t_bool io, uint8 data); -uint8 isbc208_rA(t_bool io, uint8 data); -uint8 isbc208_rB(t_bool io, uint8 data); -uint8 isbc208_rC(t_bool io, uint8 data); -uint8 isbc208_rD(t_bool io, uint8 data); -uint8 isbc208_rE(t_bool io, uint8 data); -uint8 isbc208_rF(t_bool io, uint8 data); -uint8 isbc208_r10(t_bool io, uint8 data); -uint8 isbc208_r11(t_bool io, uint8 data); -uint8 isbc208_r12(t_bool io, uint8 data); -uint8 isbc208_r13(t_bool io, uint8 data); -uint8 isbc208_r14(t_bool io, uint8 data); -uint8 isbc208_r15(t_bool io, uint8 data); - -/* external function prototypes */ - -extern void set_irq(int32 int_num); -extern void clr_irq(int32 int_num); -extern uint16 reg_dev(uint8 (*routine)(t_bool, uint8), uint16, uint8); -extern void multibus_put_mbyte(uint16 addr, uint8 val); -extern uint8 multibus_get_mbyte(uint16 addr); - -/* 8237 physical register definitions */ - -uint16 i8237_r0; // 8237 ch 0 address register -uint16 i8237_r1; // 8237 ch 0 count register -uint16 i8237_r2; // 8237 ch 1 address register -uint16 i8237_r3; // 8237 ch 1 count register -uint16 i8237_r4; // 8237 ch 2 address register -uint16 i8237_r5; // 8237 ch 2 count register -uint16 i8237_r6; // 8237 ch 3 address register -uint16 i8237_r7; // 8237 ch 3 count register -uint8 i8237_r8; // 8237 status register -uint8 i8237_r9; // 8237 command register -uint8 i8237_rA; // 8237 mode register -uint8 i8237_rB; // 8237 mask register -uint8 i8237_rC; // 8237 request register -uint8 i8237_rD; // 8237 first/last ff -uint8 i8237_rE; // 8237 -uint8 i8237_rF; // 8237 - -/* 8272 physical register definitions */ -/* 8272 command register stack*/ - -uint8 i8272_w0; // MT+MFM+SK+command -uint8 i8272_w1; // HDS [HDS=H << 2] + DS1 + DS0 -uint8 i8272_w2; // cylinder # (0-XX) -uint8 i8272_w3; // head # (0 or 1) -uint8 i8272_w4; // sector # (1-XX) -uint8 i8272_w5; // number of bytes (128 << N) -uint8 i8272_w6; // End of track (last sector # on cylinder) -uint8 i8272_w7; // Gap length -uint8 i8272_w8; // Data length (when N=0, size to read or write) - -/* 8272 status register stack */ - -uint8 i8272_msr; // main status -uint8 i8272_r0; // ST 0 -uint8 i8272_r1; // ST 1 -uint8 i8272_r2; // ST 2 -uint8 i8272_r3; // ST 3 - -/* iSBC-208 physical register definitions */ - -uint16 isbc208_sr; // isbc-208 segment register -uint8 isbc208_i; // iSBC-208 interrupt register -uint8 isbc208_a; // iSBC-208 auxillary port register - -/* data obtained from analyzing command registers/attached file length */ - -int32 wsp = 0, rsp = 0; // indexes to write and read stacks (8272 data) -int32 cyl; // current cylinder -int32 hed; // current head [ h << 2] -int32 h; // current head -int32 sec; // current sector -int32 drv; // current drive -uint8 cmd, pcmd; // current command -int32 secn; // N 0-128, 1-256, etc -int32 spt; // sectors per track -int32 ssize; // sector size (128 << N) - -uint8 *isbc208_buf[FDD_NUM] = { /* FDD buffer pointers */ - NULL, - NULL, - NULL, - NULL -}; - -int32 fddst[FDD_NUM] = { // in ST3 format - 0, // status of FDD 0 - 0, // status of FDD 1 - 0, // status of FDD 2 - 0 // status of FDD 3 -}; - -int8 maxcyl[FDD_NUM] = { - 0, // last cylinder + 1 of FDD 0 - 0, // last cylinder + 1 of FDD 1 - 0, // last cylinder + 1 of FDD 2 - 0 // last cylinder + 1 of FDD 3 -}; - -/* isbc208 Standard SIMH Device Data Structures - 4 units */ - -UNIT isbc208_unit[] = { - { UDATA (&isbc208_svc, UNIT_ATTABLE+UNIT_DISABLE, 0), 20 }, - { UDATA (&isbc208_svc, UNIT_ATTABLE+UNIT_DISABLE, 0), 20 }, - { UDATA (&isbc208_svc, UNIT_ATTABLE+UNIT_DISABLE, 0), 20 }, - { UDATA (&isbc208_svc, UNIT_ATTABLE+UNIT_DISABLE, 0), 20 } -}; - -REG isbc208_reg[] = { - { HRDATA (CH0ADR, i8237_r0, 16) }, - { HRDATA (CH0CNT, i8237_r1, 16) }, - { HRDATA (CH1ADR, i8237_r2, 16) }, - { HRDATA (CH1CNT, i8237_r3, 16) }, - { HRDATA (CH2ADR, i8237_r4, 16) }, - { HRDATA (CH2CNT, i8237_r5, 16) }, - { HRDATA (CH3ADR, i8237_r6, 16) }, - { HRDATA (CH3CNT, i8237_r7, 16) }, - { HRDATA (STAT37, i8237_r8, 8) }, - { HRDATA (CMD37, i8237_r9, 8) }, - { HRDATA (MODE, i8237_rA, 8) }, - { HRDATA (MASK, i8237_rB, 8) }, - { HRDATA (REQ, i8237_rC, 8) }, - { HRDATA (FF, i8237_rD, 8) }, - { HRDATA (STAT72, i8272_msr, 8) }, - { HRDATA (STAT720, i8272_r0, 8) }, - { HRDATA (STAT721, i8272_r1, 8) }, - { HRDATA (STAT722, i8272_r2, 8) }, - { HRDATA (STAT723, i8272_r3, 8) }, - { HRDATA (CMD720, i8272_w0, 8) }, - { HRDATA (CMD721, i8272_w1, 8) }, - { HRDATA (CMD722, i8272_w2, 8) }, - { HRDATA (CMD723, i8272_w3, 8) }, - { HRDATA (CMD724, i8272_w4, 8) }, - { HRDATA (CMD725, i8272_w5, 8) }, - { HRDATA (CMD726, i8272_w6, 8) }, - { HRDATA (CMD727, i8272_w7, 8) }, - { HRDATA (CMD728, i8272_w8, 8) }, - { HRDATA (FDD0, fddst[0], 8) }, - { HRDATA (FDD1, fddst[1], 8) }, - { HRDATA (FDD2, fddst[2], 8) }, - { HRDATA (FDD3, fddst[3], 8) }, - { HRDATA (SEGREG, isbc208_sr, 8) }, - { HRDATA (AUX, isbc208_a, 8) }, - { HRDATA (INT, isbc208_i, 8) }, - { NULL } -}; - -MTAB isbc208_mod[] = { - { UNIT_WPMODE, 0, "RW", "RW", &isbc208_set_mode }, - { UNIT_WPMODE, UNIT_WPMODE, "WP", "WP", &isbc208_set_mode }, - { 0 } -}; - -DEBTAB isbc208_debug[] = { - { "ALL", DEBUG_all }, - { "FLOW", DEBUG_flow }, - { "READ", DEBUG_read }, - { "WRITE", DEBUG_write }, - { "LEV1", DEBUG_level1 }, - { "LEV2", DEBUG_level2 }, - { "REG", DEBUG_reg }, - { NULL } -}; - -DEVICE isbc208_dev = { - "SBC208", //name - isbc208_unit, //units - isbc208_reg, //registers - isbc208_mod, //modifiers - FDD_NUM, //numunits - 16, //aradix - 32, //awidth - 1, //aincr - 16, //dradix - 8, //dwidth - NULL, //examine - NULL, //deposit -// &isbc208_reset, //deposit - NULL, //deposit - NULL, //boot - &isbc208_attach, //attach - NULL, //detach - NULL, //ctxt - DEV_DEBUG+DEV_DISABLE+DEV_DIS, //flags -// 0, //dctrl - DEBUG_flow + DEBUG_read + DEBUG_write, //dctrl - isbc208_debug, //debflags - NULL, //msize - NULL //lname -}; - -/* Service routines to handle simulator functions */ - -/* service routine - actually does the simulated disk I/O */ - -t_stat isbc208_svc (UNIT *uptr) -{ - uint32 i; - int32 imgadr, data; - int c; - int32 bpt, bpc; - FILE *fp; - - if ((i8272_msr & CB) && cmd && (uptr->u6 == drv)) { /* execution phase */ - sim_debug (DEBUG_flow, &isbc208_dev, "208_svc: Entered execution phase\n"); - switch (cmd) { - case READ: /* 0x06 */ -// sim_printf("READ-e: fddst=%02X", fddst[uptr->u6]); - h = i8272_w3; // h = 0 or 1 - hed = i8272_w3 << 2; // hed = 0 or 4 [h << 2] - sec = i8272_w4; // sector number (1-XX) - secn = i8272_w5; // N (0-5) - spt = i8272_w6; // sectors/track - ssize = 128 << secn; // size of sector (bytes) - bpt = ssize * spt; // bytes/track - bpc = bpt * 2; // bytes/cylinder -// sim_printf(" d=%d h=%d c=%d s=%d\n", drv, h, cyl, sec); - sim_debug (DEBUG_flow, &isbc208_dev, - "208_svc: FDC read: h=%d, hed=%d, sec=%d, secn=%d, spt=%d, ssize=%04X, bpt=%04X, bpc=%04X\n", - h, hed, sec, secn, spt, ssize, bpt, bpc); - sim_debug (DEBUG_flow, &isbc208_dev, - "208_svc: FDC read: d=%d h=%d c=%d s=%d N=%d spt=%d fddst=%02X\n", - drv, h, cyl, sec, secn, spt, fddst[uptr->u6]); - sim_debug (DEBUG_read, &isbc208_dev, "208_svc: FDC read of d=%d h=%d c=%d s=%d\n", - drv, h, cyl, sec); - if ((fddst[uptr->u6] & RDY) == 0) { // drive not ready - i8272_r0 = IC_ABNORM + NR + hed + drv; /* command done - Not ready error*/ - i8272_r3 = fddst[uptr->u6]; - i8272_msr |= (RQM + DIO + CB); /* enter result phase */ - sim_debug (DEBUG_flow, &isbc208_dev, "208_svc: FDC read: Not Ready\n"); - } else { // get image addr for this d, h, c, s - imgadr = (cyl * bpc) + (h * bpt) + ((sec - 1) * ssize); - sim_debug (DEBUG_read, &isbc208_dev, - "208_svc: FDC read: DMA addr=%04X cnt=%04X imgadr=%04X\n", - i8237_r0, i8237_r1, imgadr); - for (i=0; i<=i8237_r1; i++) { /* copy selected sector to memory */ - data = *(isbc208_buf[uptr->u6] + (imgadr + i)); - multibus_put_mbyte(i8237_r0 + i, data); - } -//*** need to step return results IAW table 3-11 in 143078-001 - i8272_w4 = ++sec; /* next sector */ - i8272_r0 = hed + drv; /* command done - no error */ - i8272_r3 = fddst[uptr->u6]; - } - i8272_r1 = 0; - i8272_r2 = 0; - i8272_w2 = cyl; /* generate a current address mark */ - i8272_w3 = h; - if (i8272_w4 > i8272_w6) { // beyond last sector of track? - i8272_w4 = 1; // yes, set to sector 1; - if (h) { // on head one? - i8272_w2++; // yes, step cylinder - h = 0; // back to head 0 - } - } - i8272_w5 = secn; - i8272_msr |= (RQM + DIO + CB); /* enter result phase */ - rsp = wsp = 0; /* reset indexes */ - set_irq(SBC208_INT); /* set interrupt */ -// sim_printf("READ-x: fddst=%02X\n", fddst[uptr->u6]); - break; - case WRITE: /* 0x05 */ -// sim_printf("WRITE-e: fddst=%02X\n", fddst[uptr->u6]); - h = i8272_w3; // h = 0 or 1 - hed = i8272_w3 << 2; // hed = 0 or 4 [h << 2] - sec = i8272_w4; // sector number (1-XX) - secn = i8272_w5; // N (0-5) - spt = i8272_w6; // sectors/track - ssize = 128 << secn; // size of sector (bytes) - bpt = ssize * spt; // bytes/track - bpc = bpt * 2; // bytes/cylinder - sim_debug (DEBUG_flow, &isbc208_dev, - "208_svc: FDC write: hed=%d, sec=%d, secn=%d, spt=%d, ssize=%04X, bpt=%04X, bpc=%04X\n", - hed, sec, secn, spt, ssize, bpt, bpc); - sim_debug (DEBUG_flow, &isbc208_dev, - "208_svc: FDC write: d=%d h=%d c=%d s=%d N=%d spt=%d fddst=%02X\n", - drv, h, cyl, sec, secn, spt, fddst[uptr->u6]); - sim_debug (DEBUG_write, &isbc208_dev, "208_svc: FDC write of d=%d h=%d c=%d s=%d\n", - drv, h, cyl, sec); - i8272_r1 = 0; // clear ST1 - i8272_r2 = 0; // clear ST2 - if ((fddst[uptr->u6] & RDY) == 0) { - i8272_r0 = IC_ABNORM + NR + hed + drv; /* Not ready error*/ - i8272_r3 = fddst[uptr->u6]; - i8272_msr |= (RQM + DIO + CB); /* enter result phase */ - sim_debug (DEBUG_flow, &isbc208_dev, "208_svc: FDC write: Not Ready\n"); -// } else if (fddst[uptr->u6] & WP) { -// i8272_r0 = IC_ABNORM + hed + drv; /* write protect error*/ -// i8272_r1 = NW; // set not writable in ST1 -// i8272_r3 = fddst[uptr->u6] + WP; -// i8272_msr |= (RQM + DIO + CB); /* enter result phase */ -// sim_printf("\nWrite Protected fddst[%d]=%02X\n", uptr->u6, fddst[uptr->u6]); -// if (isbc208_dev.dctrl & DEBUG_flow) -// sim_printf("208_svc: FDC write: Write Protected\n"); - } else { // get image addr for this d, h, c, s - imgadr = (cyl * bpc) + (h * bpt) + ((sec - 1) * ssize); - sim_debug (DEBUG_write, &isbc208_dev, - "208_svc: FDC write: DMA adr=%04X cnt=%04X imgadr=%04X\n", - i8237_r0, i8237_r1, imgadr); - for (i=0; i<=i8237_r1; i++) { /* copy selected memory to image */ - data = multibus_get_mbyte(i8237_r0 + i); - *(isbc208_buf[uptr->u6] + (imgadr + i)) = data; - } - //*** quick fix. Needs more thought! - fp = fopen(uptr->filename, "wb"); // write out modified image - for (i=0; icapac; i++) { - c = *(isbc208_buf[uptr->u6] + i) & 0xFF; - fputc(c, fp); - } - fclose(fp); -//*** need to step return results IAW table 3-11 in 143078-001 - i8272_w2 = cyl; /* generate a current address mark */ - i8272_w3 = hed >> 2; - i8272_w4 = ++sec; /* next sector */ - i8272_w5 = secn; - i8272_r0 = hed + drv; /* command done - no error */ - i8272_r3 = fddst[uptr->u6]; - i8272_msr |= (RQM + DIO + CB); /* enter result phase */ - } - rsp = wsp = 0; /* reset indexes */ - set_irq(SBC208_INT); /* set interrupt */ -// sim_printf("WRITE-x: fddst=%02X\n", fddst[uptr->u6]); - break; - case FMTTRK: /* 0x0D */ - if ((fddst[uptr->u6] & RDY) == 0) { - i8272_r0 = IC_ABNORM + NR + hed + drv; /* Not ready error*/ - i8272_msr |= (RQM + DIO + CB); /* enter result phase */ - sim_debug (DEBUG_flow, &isbc208_dev, "208_svc: Not Ready\n"); - } else if (fddst[uptr->u6] & WP) { - i8272_r0 = IC_ABNORM + hed + drv; /* write protect error*/ - i8272_r3 = fddst[uptr->u6] + WP; - i8272_msr |= (RQM + DIO + CB); /* enter result phase */ - sim_debug (DEBUG_flow, &isbc208_dev, "208_svc: Write Protected\n"); - } else { - ; /* do nothing for now */ - i8272_msr |= (RQM + DIO + CB); /* enter result phase */ - } - rsp = wsp = 0; /* reset indexes */ - set_irq(SBC208_INT); /* set interrupt */ - break; - case SENINT: /* 0x08 */ - i8272_msr |= (RQM + DIO + CB); /* enter result phase */ - i8272_r0 = hed + drv; /* command done - no error */ - i8272_r1 = 0; - i8272_r2 = 0; - rsp = wsp = 0; /* reset indexes */ - clr_irq(SBC208_INT); /* clear interrupt */ - break; - case SENDRV: /* 0x04 */ - sim_debug (DEBUG_flow, &isbc208_dev, "208_svc: FDC sense drive: d=%d fddst=%02X\n", - drv, fddst[uptr->u6]); - i8272_msr |= (RQM + DIO + CB); /* enter result phase */ - i8272_r0 = hed + drv; /* command done - no error */ - i8272_r1 = 0; - i8272_r2 = 0; - i8272_r3 = fddst[drv]; /* drv status */ - rsp = wsp = 0; /* reset indexes */ - break; - case HOME: /* 0x07 */ -// sim_printf("HOME-e: fddst=%02X\n", fddst[uptr->u6]); - sim_debug (DEBUG_flow, &isbc208_dev, "208_svc: FDC home: d=%d fddst=%02X\n", - drv, fddst[uptr->u6]); - if ((fddst[uptr->u6] & RDY) == 0) { - i8272_r0 = IC_ABNORM + NR + hed + drv; /* Not ready error*/ - i8272_r3 = fddst[uptr->u6]; - sim_debug (DEBUG_flow, &isbc208_dev, "208_svc: Not Ready\n"); - } else { - cyl = 0; /* now on cylinder 0 */ - fddst[drv] |= T0; /* set status flag */ - i8272_r0 = SE + hed + drv; /* seek end - no error */ - } - i8272_r1 = 0; - i8272_r2 = 0; - i8272_msr &= ~(RQM + DIO + CB + hed + drv); /* execution phase done*/ - i8272_msr |= RQM; /* enter COMMAND phase */ - rsp = wsp = 0; /* reset indexes */ - set_irq(SBC208_INT); /* set interrupt */ -// sim_printf("HOME-x: fddst=%02X\n", fddst[uptr->u6]); - break; - case SPEC: /* 0x03 */ - fddst[0] |= TS; //*** bad, bad, bad! - fddst[1] |= TS; - fddst[2] |= TS; - fddst[3] |= TS; -// sim_printf("SPEC-e: fddst[%d]=%02X\n", uptr->u6, fddst[uptr->u6]); - sim_debug (DEBUG_flow, &isbc208_dev, - "208_svc: FDC specify: SRT=%d ms HUT=%d ms HLT=%d ms \n", - 16 - (drv >> 4), 16 * (drv & 0x0f), i8272_w2 & 0xfe); - i8272_r0 = hed + drv; /* command done - no error */ - i8272_r1 = 0; - i8272_r2 = 0; - i8272_msr &= ~(RQM + DIO + CB); /* execution phase done*/ - i8272_msr = 0; // force 0 for now, where does 0x07 come from? - i8272_msr |= RQM; /* enter command phase */ - rsp = wsp = 0; /* reset indexes */ -// sim_printf("SPEC-x: fddst[%d]=%02X\n", uptr->u6, fddst[uptr->u6]); - break; - case READID: /* 0x0A */ - if ((fddst[uptr->u6] & RDY) == 0) { - i8272_r0 = IC_RC + NR + hed + drv; /* Not ready error*/ - i8272_r3 = fddst[uptr->u6]; - sim_debug (DEBUG_flow, &isbc208_dev, "208_svc: Not Ready\n"); - } else { - i8272_w2 = cyl; /* generate a valid address mark */ - i8272_w3 = hed >> 2; - i8272_w4 = 1; /* always sector 1 */ - i8272_w5 = secn; - i8272_r0 = hed + drv; /* command done - no error */ - i8272_msr &= ~(RQM + DIO + CB); /* execution phase done*/ - i8272_msr |= RQM; /* enter command phase */ - } - i8272_r1 = 0; - i8272_r2 = 0; - rsp = wsp = 0; /* reset indexes */ - break; - case SEEK: /* 0x0F */ -// sim_printf("SEEK-e: fddst=%02X\n", fddst[uptr->u6]); - sim_debug (DEBUG_flow, &isbc208_dev, "208_svc: FDC seek: d=%d c=%d fddst=%02X\n", - drv, i8272_w2, fddst[uptr->u6]); - if ((fddst[uptr->u6] & RDY) == 0) { /* Not ready? */ - i8272_r0 = IC_ABNORM + NR + hed + drv; /* error*/ - i8272_r3 = fddst[uptr->u6]; - sim_debug (DEBUG_flow, &isbc208_dev, "208_svc: FDC seek: Not Ready\n"); - } else if (i8272_w2 >= maxcyl[uptr->u6]) { - i8272_r0 = IC_ABNORM + RDY + hed + drv; /* seek error*/ - sim_debug (DEBUG_flow, &isbc208_dev, "208_svc: FDC seek: Invalid Cylinder %d\n", i8272_w2); - } else { - i8272_r0 |= SE + hed + drv; /* command done - no error */ - cyl = i8272_w2; /* new cylinder number */ - if (cyl == 0) { /* if cyl 0, set flag */ - fddst[drv] |= T0; /* set T0 status flag */ - i8272_r3 |= T0; - } else { - fddst[drv] &= ~T0; /* clear T0 status flag */ - i8272_r3 &= ~T0; - } - } - i8272_r1 = 0; - i8272_r2 = 0; - i8272_msr &= ~(RQM + DIO + CB + hed + drv); /* execution phase done*/ - i8272_msr |= RQM; /* enter command phase */ - rsp = wsp = 0; /* reset indexes */ -// set_irq(SBC208_INT); /* set interrupt */ -// sim_printf("SEEK-x: fddst=%02X\n", fddst[uptr->u6]); - break; - default: - i8272_msr &= ~(RQM + DIO + CB); /* execution phase done*/ - i8272_msr |= RQM; /* enter command phase */ - i8272_r0 = IC_INVC + hed + drv; /* set bad command error */ - i8272_r1 = 0; - i8272_r2 = 0; - rsp = wsp = 0; /* reset indexes */ - break; - } - pcmd = cmd; /* save for result phase */ - cmd = 0; /* reset command */ - sim_debug (DEBUG_flow, &isbc208_dev, - "208_svc: Exit: msr=%02X ST0=%02X ST1=%02X ST2=%02X ST3=%02X\n", - i8272_msr, i8272_r0, i8272_r1, i8272_r2, i8272_r3); - } - sim_activate (&isbc208_unit[uptr->u6], isbc208_unit[uptr->u6].wait); - return SCPE_OK; -} - -/* Reset routine */ - -t_stat isbc208_reset (DEVICE *dptr, uint16 base) -{ - if (sbc208_devnum > SBC208_NUM) { - sim_printf("sbc208_reset: too many devices!\n"); - return SCPE_MEM; - } - if (SBC202_NUM) { - sim_printf(" SBC208-%d: Hardware Reset\n", sbc208_devnum); - sim_printf(" SBC208-%d: Registered at %04X\n", sbc208_devnum, base); - sbc208_port[sbc208_devnum] = reg_dev(isbc208_r0, SBC208_BASE + 0, sbc208_devnum); - reg_dev(isbc208_r1, SBC208_BASE + 1, sbc208_devnum); - reg_dev(isbc208_r2, SBC208_BASE + 2, sbc208_devnum); - reg_dev(isbc208_r3, SBC208_BASE + 3, sbc208_devnum); - reg_dev(isbc208_r4, SBC208_BASE + 4, sbc208_devnum); - reg_dev(isbc208_r5, SBC208_BASE + 5, sbc208_devnum); - reg_dev(isbc208_r6, SBC208_BASE + 6, sbc208_devnum); - reg_dev(isbc208_r7, SBC208_BASE + 7, sbc208_devnum); - reg_dev(isbc208_r8, SBC208_BASE + 8, sbc208_devnum); - reg_dev(isbc208_r9, SBC208_BASE + 9, sbc208_devnum); - reg_dev(isbc208_rA, SBC208_BASE + 10, sbc208_devnum); - reg_dev(isbc208_rB, SBC208_BASE + 11, sbc208_devnum); - reg_dev(isbc208_rC, SBC208_BASE + 12, sbc208_devnum); - reg_dev(isbc208_rD, SBC208_BASE + 13, sbc208_devnum); - reg_dev(isbc208_rE, SBC208_BASE + 14, sbc208_devnum); - reg_dev(isbc208_rF, SBC208_BASE + 15, sbc208_devnum); - reg_dev(isbc208_r10, SBC208_BASE + 16, sbc208_devnum); - reg_dev(isbc208_r11, SBC208_BASE + 17, sbc208_devnum); - reg_dev(isbc208_r12, SBC208_BASE + 18, sbc208_devnum); - reg_dev(isbc208_r13, SBC208_BASE + 19, sbc208_devnum); - reg_dev(isbc208_r14, SBC208_BASE + 20, sbc208_devnum); - reg_dev(isbc208_r15, SBC208_BASE + 21, sbc208_devnum); - if ((isbc208_dev.flags & DEV_DIS) == 0) - isbc208_reset1(); - sbc208_devnum++; - } else { - sim_printf(" No isbc208 installed\n"); - } - return SCPE_OK; -} - -void isbc208_reset1 (void) -{ - int32 i; - UNIT *uptr; - static int flag = 1; - - if (flag) sim_printf("iSBC 208: Initializing\n"); - for (i = 0; i < FDD_NUM; i++) { /* handle all units */ - uptr = isbc208_dev.units + i; - if (uptr->capac == 0) { /* if not configured */ -// 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! */ - fddst[i] = WP + T0 + i; /* initial drive status */ - uptr->flags |= UNIT_WPMODE; /* set WP in unit flags */ - sim_activate (&isbc208_unit[uptr->u6], isbc208_unit[uptr->u6].wait); - } else { - fddst[i] = RDY + WP + T0 + i; /* initial attach drive status */ -// 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 */ - i8272_msr = RQM; /* 8272 ready for start of command */ - rsp = wsp = 0; /* reset indexes */ - cmd = 0; /* clear command */ - sim_printf(" SBC208-%d: Software Reset\n", sbc208_devnum); - if (flag) { - sim_printf(" 8237 Reset\n"); - sim_printf(" 8272 Reset\n"); - } - flag = 0; -} - -/* isbc208 attach - attach an .IMG file to a FDD */ - -t_stat isbc208_attach (UNIT *uptr, CONST char *cptr) -{ - t_stat r; - FILE *fp; - int32 i, c = 0; - long flen; - - sim_debug (DEBUG_flow, &isbc208_dev, " isbc208_attach: Entered with cptr=%s\n", cptr); - if ((r = attach_unit (uptr, cptr)) != SCPE_OK) { - sim_printf(" isbc208_attach: Attach error\n"); - return r; - } - fp = fopen(uptr->filename, "rb"); - if (fp == NULL) { - sim_printf(" Unable to open disk img file %s\n", uptr->filename); - sim_printf(" No disk image loaded!!!\n"); - } else { - sim_printf("iSBC 208: Attach\n"); - fseek(fp, 0, SEEK_END); /* size disk image */ - flen = ftell(fp); - fseek(fp, 0, SEEK_SET); - if (isbc208_buf[uptr->u6] == NULL) { /* no buffer allocated */ - isbc208_buf[uptr->u6] = (uint8 *)malloc(flen); - if (isbc208_buf[uptr->u6] == NULL) { - sim_printf(" iSBC208_attach: Malloc error\n"); - fclose(fp); - return SCPE_MEM; - } - } - uptr->capac = flen; - i = 0; - c = fgetc(fp); // copy disk image into buffer - while (c != EOF) { - *(isbc208_buf[uptr->u6] + i++) = c & 0xFF; - c = fgetc(fp); - } - fclose(fp); - fddst[uptr->u6] |= RDY; /* set unit ready */ - if (flen == 368640) { /* 5" 360K DSDD */ - maxcyl[uptr->u6] = 40; - fddst[uptr->u6] |= TS; // two sided - } - else if (flen == 737280) { /* 5" 720K DSQD / 3.5" 720K DSDD */ - maxcyl[uptr->u6] = 80; - fddst[uptr->u6] |= TS; // two sided - } - else if (flen == 1228800) { /* 5" 1.2M DSHD */ - maxcyl[uptr->u6] = 80; - fddst[uptr->u6] |= TS; // two sided - } - else if (flen == 1474560) { /* 3.5" 1.44M DSHD */ - maxcyl[uptr->u6] = 80; - fddst[uptr->u6] |= TS; // two sided - } - sim_printf(" Drive-%d: %d bytes of disk image %s loaded, fddst=%02X\n", - uptr->u6, i, uptr->filename, fddst[uptr->u6]); - } - sim_debug (DEBUG_flow, &isbc208_dev, " iSBC208_attach: Done\n"); - return SCPE_OK; -} - -/* isbc208 set mode = 8- or 16-bit data bus */ -/* always 8-bit mode for current simulators */ - -t_stat isbc208_set_mode (UNIT *uptr, int32 val, CONST char *cptr, void *desc) -{ - sim_debug (DEBUG_flow, &isbc208_dev, " isbc208_set_mode: Entered with val=%08XH uptr->flags=%08X\n", - val, uptr->flags); - if (val & UNIT_WPMODE) { /* write protect */ - fddst[uptr->u6] |= WP; - uptr->flags |= val; - } else { /* read write */ - fddst[uptr->u6] &= ~WP; - uptr->flags &= ~val; - } -// sim_printf("fddst[%d]=%02XH uptr->flags=%08X\n", uptr->u6, fddst[uptr->u6], uptr->flags); - sim_debug (DEBUG_flow, &isbc208_dev, " isbc208_set_mode: Done\n"); - return SCPE_OK; -} - -/* I/O instruction handlers, called from the CPU module when an - IN or OUT instruction is issued. - - Each function is passed an 'io' flag, where 0 means a read from - the port, and 1 means a write to the port. On input, the actual - input is passed as the return value, on output, 'data' is written - to the device. -*/ - -uint8 isbc208_r0(t_bool io, uint8 data) -{ - if (io == 0) { /* read current address CH 0 */ - if (i8237_rD) { /* high byte */ - i8237_rD = 0; - sim_debug (DEBUG_reg, &isbc208_dev, "i8237_r0(H) read as %04X\n", i8237_r0); - return (i8237_r0 >> 8); - } else { /* low byte */ - i8237_rD++; - sim_debug (DEBUG_reg, &isbc208_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, &isbc208_dev, "i8237_r0(H) set to %04X\n", i8237_r0); - } else { /* low byte */ - i8237_rD++; - i8237_r0 = data & 0xFF; - sim_debug (DEBUG_reg, &isbc208_dev, "i8237_r0(L) set to %04X\n", i8237_r0); - } - return 0; - } -} - -uint8 isbc208_r1(t_bool io, uint8 data) -{ - if (io == 0) { /* read current word count CH 0 */ - if (i8237_rD) { /* high byte */ - i8237_rD = 0; - sim_debug (DEBUG_reg, &isbc208_dev, "i8237_r1(H) read as %04X\n", i8237_r1); - return (i8237_r1 >> 8); - } else { /* low byte */ - i8237_rD++; - sim_debug (DEBUG_reg, &isbc208_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, &isbc208_dev, "i8237_r1(H) set to %04X\n", i8237_r1); - } else { /* low byte */ - i8237_rD++; - i8237_r1 = data & 0xFF; - sim_debug (DEBUG_reg, &isbc208_dev, "i8237_r1(L) set to %04X\n", i8237_r1); - } - return 0; - } -} - -uint8 isbc208_r2(t_bool io, uint8 data) -{ - if (io == 0) { /* read current address CH 1 */ - if (i8237_rD) { /* high byte */ - i8237_rD = 0; - sim_debug (DEBUG_reg, &isbc208_dev, "i8237_r2(H) read as %04X\n", i8237_r2); - return (i8237_r2 >> 8); - } else { /* low byte */ - i8237_rD++; - sim_debug (DEBUG_reg, &isbc208_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, &isbc208_dev, "i8237_r2(H) set to %04X\n", i8237_r2); - } else { /* low byte */ - i8237_rD++; - i8237_r2 = data & 0xFF; - sim_debug (DEBUG_reg, &isbc208_dev, "i8237_r2(L) set to %04X\n", i8237_r2); - } - return 0; - } -} - -uint8 isbc208_r3(t_bool io, uint8 data) -{ - if (io == 0) { /* read current word count CH 1 */ - if (i8237_rD) { /* high byte */ - i8237_rD = 0; - sim_debug (DEBUG_reg, &isbc208_dev, "i8237_r3(H) read as %04X\n", i8237_r3); - return (i8237_r3 >> 8); - } else { /* low byte */ - i8237_rD++; - sim_debug (DEBUG_reg, &isbc208_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, &isbc208_dev, "i8237_r3(H) set to %04X\n", i8237_r3); - } else { /* low byte */ - i8237_rD++; - i8237_r3 = data & 0xFF; - sim_debug (DEBUG_reg, &isbc208_dev, "i8237_r3(L) set to %04X\n", i8237_r3); - } - return 0; - } -} - -uint8 isbc208_r4(t_bool io, uint8 data) -{ - if (io == 0) { /* read current address CH 2 */ - if (i8237_rD) { /* high byte */ - i8237_rD = 0; - sim_debug (DEBUG_reg, &isbc208_dev, "i8237_r4(H) read as %04X\n", i8237_r4); - return (i8237_r4 >> 8); - } else { /* low byte */ - i8237_rD++; - sim_debug (DEBUG_reg, &isbc208_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, &isbc208_dev, "i8237_r4(H) set to %04X\n", i8237_r4); - } else { /* low byte */ - i8237_rD++; - i8237_r4 = data & 0xFF; - sim_debug (DEBUG_reg, &isbc208_dev, "i8237_r4(L) set to %04X\n", i8237_r4); - } - return 0; - } -} - -uint8 isbc208_r5(t_bool io, uint8 data) -{ - if (io == 0) { /* read current word count CH 2 */ - if (i8237_rD) { /* high byte */ - i8237_rD = 0; - sim_debug (DEBUG_reg, &isbc208_dev, "i8237_r5(H) read as %04X\n", i8237_r5); - return (i8237_r5 >> 8); - } else { /* low byte */ - i8237_rD++; - sim_debug (DEBUG_reg, &isbc208_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, &isbc208_dev, "i8237_r5(H) set to %04X\n", i8237_r5); - } else { /* low byte */ - i8237_rD++; - i8237_r5 = data & 0xFF; - sim_debug (DEBUG_reg, &isbc208_dev, "i8237_r5(L) set to %04X\n", i8237_r5); - } - return 0; - } -} - -uint8 isbc208_r6(t_bool io, uint8 data) -{ - if (io == 0) { /* read current address CH 3 */ - if (i8237_rD) { /* high byte */ - i8237_rD = 0; - sim_debug (DEBUG_reg, &isbc208_dev, "i8237_r6(H) read as %04X\n", i8237_r6); - return (i8237_r6 >> 8); - } else { /* low byte */ - i8237_rD++; - sim_debug (DEBUG_reg, &isbc208_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, &isbc208_dev, "i8237_r6(H) set to %04X\n", i8237_r6); - } else { /* low byte */ - i8237_rD++; - i8237_r6 = data & 0xFF; - sim_debug (DEBUG_reg, &isbc208_dev, "i8237_r6(L) set to %04X\n", i8237_r6); - } - return 0; - } -} - -uint8 isbc208_r7(t_bool io, uint8 data) -{ - if (io == 0) { /* read current word count CH 3 */ - if (i8237_rD) { /* high byte */ - i8237_rD = 0; - sim_debug (DEBUG_reg, &isbc208_dev, "i8237_r7(H) read as %04X\n", i8237_r7); - return (i8237_r7 >> 8); - } else { /* low byte */ - i8237_rD++; - sim_debug (DEBUG_reg, &isbc208_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, &isbc208_dev, "i8237_r7(H) set to %04X\n", i8237_r7); - } else { /* low byte */ - i8237_rD++; - i8237_r7 = data & 0xFF; - sim_debug (DEBUG_reg, &isbc208_dev, "i8237_r7(L) set to %04X\n", i8237_r7); - } - return 0; - } -} - -uint8 isbc208_r8(t_bool io, uint8 data) -{ - if (io == 0) { /* read status register */ - sim_debug (DEBUG_reg, &isbc208_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, &isbc208_dev, "i8237_r9 (command) set to %02X\n", i8237_r9); - return 0; - } -} - -uint8 isbc208_r9(t_bool io, uint8 data) -{ - if (io == 0) { - sim_debug (DEBUG_reg, &isbc208_dev, "Illegal read of isbc208_r9\n"); - return 0; - } else { /* write request register */ - i8237_rC = data & 0xFF; - sim_debug (DEBUG_reg, &isbc208_dev, "i8237_rC (request) set to %02X\n", i8237_rC); - return 0; - } -} - -uint8 isbc208_rA(t_bool io, uint8 data) -{ - if (io == 0) { - sim_debug (DEBUG_reg, &isbc208_dev, "Illegal read of isbc208_rA\n"); - return 0; - } else { /* write single mask register */ - switch(data & 0x03) { - case 0: - if (data & 0x04) - i8237_rB |= 1; - else - i8237_rB &= ~1; - break; - case 1: - if (data & 0x04) - i8237_rB |= 2; - else - i8237_rB &= ~2; - break; - case 2: - if (data & 0x04) - i8237_rB |= 4; - else - i8237_rB &= ~4; - break; - case 3: - if (data & 0x04) - i8237_rB |= 8; - else - i8237_rB &= ~8; - break; - } - sim_debug (DEBUG_reg, &isbc208_dev, "i8237_rB (mask) set to %02X\n", i8237_rB); - return 0; - } -} - -uint8 isbc208_rB(t_bool io, uint8 data) -{ - if (io == 0) { - sim_debug (DEBUG_reg, &isbc208_dev, "Illegal read of isbc208_rB\n"); - return 0; - } else { /* write mode register */ - i8237_rA = data & 0xFF; - sim_debug (DEBUG_reg, &isbc208_dev, "i8237_rA (mode) set to %02X\n", i8237_rA); - return 0; - } -} - -uint8 isbc208_rC(t_bool io, uint8 data) -{ - if (io == 0) { - sim_debug (DEBUG_reg, &isbc208_dev, "Illegal read of isbc208_rC\n"); - return 0; - } else { /* clear byte pointer FF */ - i8237_rD = 0; - sim_debug (DEBUG_reg, &isbc208_dev, "i8237_rD (FF) cleared\n"); - return 0; - } -} - -uint8 isbc208_rD(t_bool io, uint8 data) -{ - if (io == 0) { /* read temporary register */ - sim_debug (DEBUG_reg, &isbc208_dev, "Illegal read of isbc208_rD\n"); - return 0; - } else { /* master clear */ - isbc208_reset1(); - sim_debug (DEBUG_reg, &isbc208_dev, "i8237 master clear\n"); - return 0; - } -} - -uint8 isbc208_rE(t_bool io, uint8 data) -{ - if (io == 0) { - sim_debug (DEBUG_reg, &isbc208_dev, "Illegal read of isbc208_rE\n"); - return 0; - } else { /* clear mask register */ - i8237_rB = 0; - sim_debug (DEBUG_reg, &isbc208_dev, "i8237_rB (mask) cleared\n"); - return 0; - } -} - -uint8 isbc208_rF(t_bool io, uint8 data) -{ - if (io == 0) { - sim_debug (DEBUG_reg, &isbc208_dev, "Illegal read of isbc208_rF\n"); - return 0; - } else { /* write all mask register bits */ - i8237_rB = data & 0x0F; - sim_debug (DEBUG_reg, &isbc208_dev, "i8237_rB (mask) set to %02X\n", i8237_rB); - return 0; - } -} - -uint8 isbc208_r10(t_bool io, uint8 data) -{ - if (io == 0) { /* read FDC status register */ - sim_debug (DEBUG_reg, &isbc208_dev, "i8272_msr read as %02X\n", i8272_msr); - return i8272_msr; - } else { - sim_debug (DEBUG_reg, &isbc208_dev, "Illegal write to isbc208_r10\n"); - return 0; - } -} - -// read/write FDC data register -uint8 isbc208_r11(t_bool io, uint8 data) -{ - if (io == 0) { /* read FDC data register */ - wsp = 0; /* clear write stack index */ - switch (rsp) { /* read from next stack register */ - case 0: - sim_debug (DEBUG_reg, &isbc208_dev, "i8272_r1 read as %02X\n", i8272_r1); - sim_debug (DEBUG_reg, &isbc208_dev, "i8272_r3 read as %02X\n", i8272_r3); - rsp++; /* step read stack index */ - clr_irq(SBC208_INT); /* clear interrupt */ - if (pcmd == SENDRV) { - i8272_msr = RQM; /* result phase SENDRV done */ - return i8272_r1; // SENDRV return ST1 - } - return i8272_r0; /* ST0 */ - case 1: - sim_debug (DEBUG_reg, &isbc208_dev, "i8272_r2 read as %02X\n", i8272_r2); - rsp++; /* step read stack index */ - if (pcmd == SENINT) { - i8272_msr = RQM; /* result phase SENINT done */ - return cyl; // SENINT return current cylinder - } - return i8272_r1; /* ST1 */ - case 2: - sim_debug (DEBUG_reg, &isbc208_dev, "i8272_r3 read as %02X\n", i8272_r3); - rsp++; /* step read stack index */ - return i8272_r2; /* ST2 */ - case 3: - sim_debug (DEBUG_reg, &isbc208_dev, "i8272_w2 read as %02X\n", i8272_w2); - rsp++; /* step read stack index */ - return i8272_w2; /* C - cylinder */ - case 4: - sim_debug (DEBUG_reg, &isbc208_dev, "i8272_w3 read as %02X\n", i8272_w3); - rsp++; /* step read stack index */ - return i8272_w3; /* H - head */ - case 5: - sim_debug (DEBUG_reg, &isbc208_dev, "i8272_w4 read as %02X\n", i8272_w4); - rsp++; /* step read stack index */ - return i8272_w4; /* R - sector */ - case 6: - sim_debug (DEBUG_reg, &isbc208_dev, "i8272_w5 read as %02X\n", i8272_w5); - i8272_msr = RQM; /* result phase ALL OTHERS done */ - return i8272_w5; /* N - sector size*/ - } - } else { /* write FDC data register */ - rsp = 0; /* clear read stack index */ - switch (wsp) { /* write to next stack register */ - case 0: - i8272_w0 = data; /* rws = MT + MFM + SK + cmd */ - cmd = data & 0x1F; /* save the current command */ - sim_debug (DEBUG_reg, &isbc208_dev, "i8272_w0 set to %02X\n", data); - if (cmd == SENINT) { - i8272_msr = CB; /* command phase SENINT done */ - return 0; - } - wsp++; /* step write stack index */ - break; - case 1: - i8272_w1 = data; /* rws = hed + drv */ - if (cmd != SPEC) - drv = data & 0x03; - sim_debug (DEBUG_reg, &isbc208_dev, "i8272_w1 set to %02X\n", data); - if (cmd == HOME || cmd == SENDRV || cmd == READID) { - i8272_msr = CB + hed + drv; /* command phase HOME, READID and SENDRV done */ - return 0; - } - wsp++; /* step write stack index */ - break; - case 2: - i8272_w2 = data; /* rws = C */ - sim_debug (DEBUG_reg, &isbc208_dev, "i8272_w2 set to %02X\n", data); - if (cmd == SPEC || cmd == SEEK) { - i8272_msr = CB + hed + drv; /* command phase SPECIFY and SEEK done */ - return 0; - } - wsp++; /* step write stack index */ - break; - case 3: - i8272_w3 = data; /* rw = H */ - hed = data; - wsp++; /* step write stack index */ - sim_debug (DEBUG_reg, &isbc208_dev, "i8272_w3 set to %02X\n", data); - break; - case 4: - i8272_w4 = data; /* rw = R */ - sec = data; - wsp++; /* step write stack index */ - sim_debug (DEBUG_reg, &isbc208_dev, "i8272_w4 set to %02X\n", data); - break; - case 5: - i8272_w5 = data; /* rw = N */ - sim_debug (DEBUG_reg, &isbc208_dev, "i8272_w5 set to %02X\n", data); - if (cmd == FMTTRK) { - i8272_msr = CB + hed + drv; /* command phase FMTTRK done */ - return 0; - } - wsp++; /* step write stack index */ - break; - case 6: - i8272_w6 = data; /* rw = last sector number */ - wsp++; /* step write stack index */ - sim_debug (DEBUG_reg, &isbc208_dev, "i8272_w6 set to %02X\n", data); - break; - case 7: - i8272_w7 = data; /* rw = gap length */ - wsp++; /* step write stack index */ - sim_debug (DEBUG_reg, &isbc208_dev, "i8272_w7 set to %02X\n", data); - break; - case 8: - i8272_w8 = data; /* rw = bytes to transfer */ - sim_debug (DEBUG_reg, &isbc208_dev, "i8272_w8 set to %02X\n", data); - if (cmd == READ || cmd == WRITE) - i8272_msr = CB + hed + drv; /* command phase all others done */ - break; - } - } - return 0; -} - -uint8 isbc208_r12(t_bool io, uint8 data) -{ - if (io == 0) { /* read interrupt status */ - sim_debug (DEBUG_reg, &isbc208_dev, "isbc208_r12 read as %02X\n", isbc208_i); - return (isbc208_i); - } else { /* write controller auxillary port */ - isbc208_a = data & 0xFF; - sim_debug (DEBUG_reg, &isbc208_dev, "isbc208_r12 set to %02X\n", isbc208_a); - return 0; - } -} - -uint8 isbc208_r13(t_bool io, uint8 data) -{ - if (io == 0) { - sim_debug (DEBUG_reg, &isbc208_dev, "Illegal read of isbc208_r13\n"); - return 0; - } else { /* reset controller */ - isbc208_reset1(); - sim_debug (DEBUG_reg, &isbc208_dev, "isbc208_r13 controller reset\n"); - return 0; - } -} - -uint8 isbc208_r14(t_bool io, uint8 data) -{ - if (io == 0) { - sim_debug (DEBUG_reg, &isbc208_dev, "Illegal read of isbc208_r14\n"); - return 0; - } else { /* Low-Byte Segment Address Register */ - isbc208_sr = data & 0xFF; - sim_debug (DEBUG_reg, &isbc208_dev, "isbc208_sr(L) set to %02X\n", data & 0xFF); - return 0; - } -} - -uint8 isbc208_r15(t_bool io, uint8 data) -{ - if (io == 0) { - sim_debug (DEBUG_reg, &isbc208_dev, "Illegal read of isbc208_r15\n"); - return 0; - } else { /* High-Byte Segment Address Register */ - isbc208_sr |= data << 8; - sim_debug (DEBUG_reg, &isbc208_dev, "isbc208_sr(H) set to %02X\n", data); - return 0; - } -} - -/* end of isbc208.c */ +/* isbc208.c: Intel iSBC208 Floppy Disk adapter + + Copyright (c) 2011, William A. Beech + + Permission is hereby granted, free of charge, to any person obtaining a + copy of this software and associated documentation files (the "Software"), + to deal in the Software without restriction, including without limitation + the rights to use, copy, modify, merge, publish, distribute, sublicense, + and/or sell copies of the Software, and to permit persons to whom the + Software is furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + WILLIAM A. BEECH BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + Except as contained in this notice, the name of William A. Beech shall not be + used in advertising or otherwise to promote the sale, use or other dealings + in this Software without prior written authorization from William A. Beech. + + MODIFICATIONS: + + ?? ??? 11 - Original file. + 24 Apr 15 -- Modified to use simh_debug + + NOTES: + + These functions support a simulated iSBC208 interface to 4 each 8-, 5 1/4-, or + 3 1/2-inch floppy disk drives. Commands are setup with programmed I/O to the + simulated ports of an i8237 DMA controller and an i8272 FDC. Data transfer + to/from the simulated disks is performed directly with the multibus memory. + + The iSBC-208 can be configured for 8- or 16-bit addresses. It defaults to 8-bit + addresses for the 8080/8085 processors. It can be configured for I/O port + addresses with 3-bits (8-bit address) or 11-bits (16-bit address). Default is + 3-bits set to 0. This defines the port offset to be used to determine the actual + port address. Bus priority can be configured for parallel or serial mode. Default is + serial. The multibus interface interrupt can be configured for interrupt 0-7. + Default is none. Since all channel registers in the i8237 are 16-bit, transfers + are done as two 8-bit operations, low- then high-byte. + + Port addressing is as follows (Port offset = 0): + + Port Mode Command Function + + 00 Write Load DMAC Channel 0 Base and Current Address Regsiters + Read Read DMAC Channel 0 Current Address Register + 01 Write Load DMAC Channel 0 Base and Current Word Count Registers + Read Read DMAC Channel 0 Current Word Count Register + 04 Write Load DMAC Channel 2 Base and Current Address Regsiters + Read Read DMAC Channel 2 Current Address Register + 05 Write Load DMAC Channel 2 Base and Current Word Count Registers + Read Read DMAC Channel 2 Current Word Count Register + 06 Write Load DMAC Channel 3 Base and Current Address Regsiters + Read Read DMAC Channel 3 Current Address Register + 07 Write Load DMAC Channel 3 Base and Current Word Count Registers + Read Read DMAC Channel 3 Current Word Count Register + 08 Write Load DMAC Command Register + Read Read DMAC Status Register + 09 Write Load DMAC Request Register + OA Write Set/Reset DMAC Mask Register + OB Write Load DMAC Mode Register + OC Write Clear DMAC First/Last Flip-Flop + 0D Write DMAC Master Clear + OF Write Load DMAC Mask Register + 10 Read Read FDC Status Register + 11 Write Load FDC Data Register + Read Read FDC Data Register + 12 Write Load Controller Auxiliary Port + Read Poll Interrupt Status + 13 Write Controller Reset + 14 Write Load Controller Low-Byte Segment Address Register + 15 Write Load Controller High-Byte Segment Address Register + 20-2F Read/Write Reserved for iSBX Multimodule Board + + Register usage is defined in the following paragraphs. + + Read/Write DMAC Address Registers + + Used to simultaneously load a channel's current-address register and base-address + register with the memory address of the first byte to be transferred. (The Channel + 0 current/base address register must be loaded prior to initiating a diskette read + or write operation.) Since each channel's address registers are 16 bits in length + (64K address range), two "write address register" commands must be executed in + order to load the complete current/base address registers for any channel. + + Read/Write DMAC Word Count Registers + + The Write DMAC Word Count Register command is used to simultaneously load a + channel's current and base word-count registers with the number of bytes + to be transferred during a subsequent DMA operation. Since the word-count + registers are 16-bits in length, two commands must be executed to load both + halves of the registers. + + Write DMAC Command Register + + The Write DMAC Command Register command loads an 8-bit byte into the + DMAC's command register to define the operating characteristics of the + DMAC. The functions of the individual bits in the command register are + defined in the following diagram. Note that only two bits within the + register are applicable to the controller; the remaining bits select + functions that are not supported and, accordingly, must always be set + to zero. + + 7 6 5 4 3 2 1 0 + +---+---+---+---+---+---+---+---+ + | 0 0 0 0 0 0 | + +---+---+---+---+---+---+---+---+ + | | + | +---------- 0 CONTROLLER ENABLE + | 1 CONTROLLER DISABLE + | + +------------------ 0 FIXED PRIORITY + 1 ROTATING PRIORITY + + Read DMAC Status Register Command + + The Read DMAC Status Register command accesses an 8-bit status byte that + identifies the DMA channels that have reached terminal count or that + have a pending DMA request. + + 7 6 5 4 3 2 1 0 + +---+---+---+---+---+---+---+---+ + | 0 0 | + +---+---+---+---+---+---+---+---+ + | | | | | | + | | | | | +-- CHANNEL 0 TC + | | | | +---------- CHANNEL 2 TC + | | | +-------------- CHANNEL 3 TC + | | +------------------ CHANNEL 0 DMA REQUEST + | +-------------------------- CHANNEL 2 DMA REQUEST + +------------------------------ CHANNEL 3 DMA REQUEST + + Write DMAC Request Register + + The data byte associated with the Write DMAC Request Register command + sets or resets a channel's associated request bit within the DMAC's + internal 4-bit request register. + + 7 6 5 4 3 2 1 0 + +---+---+---+---+---+---+---+---+ + | X X X X X | + +---+---+---+---+---+---+---+---+ + | | | + | +---+-- 00 SELECT CHANNEL 0 + | 01 SELECT CHANNEL 1 + | 10 SELECT CHANNEL 2 + | 11 SELECT CHANNEL 3 + | + +---------- 0 RESET REQUEST BIT + 1 SET REQUEST BIT + + Set/Reset DMAC Mask Register + + Prior to a DREQ-initiated DMA transfer, the channel's mask bit must + be reset to enable recognition of the DREQ input. When the transfer + is complete (terminal count reached or external EOP applied) and + the channel is not programmed to autoinitialize, the channel's + mask bit is automatically set (disabling DREQ) and must be reset + prior to a subsequent DMA transfer. All four bits of the mask + register are set (disabling the DREQ inputs) by a DMAC master + clear or controller reset. Additionally, all four bits can be + set/reset by a single Write DMAC Mask Register command. + + + 7 6 5 4 3 2 1 0 + +---+---+---+---+---+---+---+---+ + | X X X X X | + +---+---+---+---+---+---+---+---+ + | | | + | +---+-- 00 SELECT CHANNEL 0 + | 01 SELECT CHANNEL 1 + | 10 SELECT CHANNEL 2 + | 11 SELECT CHANNEL 3 + | + +---------- 0 RESET REQUEST BIT + 1 SET REQUEST BIT + + Write DMAC Mode Register + + The Write DMAC Mode Register command is used to define the + operating mode characteristics for each DMA channel. Each + channel has an internal 6-bit mode register; the high-order + six bits of the associated data byte are written into the + mode register addressed by the two low-order bits. + + + 7 6 5 4 3 2 1 0 + +---+---+---+---+---+---+---+---+ + | | + +---+---+---+---+---+---+---+---+ + | | | | | | | | + | | | | | | +---+-- 00 SELECT CHANNEL 0 + | | | | | | 01 SELECT CHANNEL 1 + | | | | | | 10 SELECT CHANNEL 2 + | | | | | | 11 SELECT CHANNEL 3 + | | | | | | + | | | | +---+---------- 00 VERIFY TRANSFER + | | | | 01 WRITE TRANSFER + | | | | 10 READ TRANSFER + | | | | + | | | +------------------ 0 AUTOINITIALIZE DISABLE + | | | 1 AUTOINITIALIZE ENABLE + | | | + | | +---------------------- 0 ADDRESS INCREMENT + | | 1 ADDRESS DECREMENT + | | + +---+-------------------------- 00 DEMAND MODE + 01 SINGLE MODE + 10 BLOCK MODE + + Clear DMAC First/Last Flip-Flop + + The Clear DMAC First/Last Flip-Flop command initializes + the DMAC's internal first/last flip-flop so that the + next byte written to or re~d from the 16-bit address + or word-count registers is the low-order byte. The + flip-flop is toggled with each register access so that + a second register read or write command accesses the + high-order byte. + + DMAC Master Clear + + The DMAC Master Clear command clears the DMAC's command, status, + request, and temporary registers to zero, initializes the + first/last flip-flop, and sets the four channel mask bits in + the mask register to disable all DMA requests (i.e., the DMAC + is placed in an idle state). + + Write DMAC Mask Register + + The Write DMAC Mask Register command allows all four bits of the + DMAC's mask register to be written with a single command. + + 7 6 5 4 3 2 1 0 + +---+---+---+---+---+---+---+---+ + | X X X X X | + +---+---+---+---+---+---+---+---+ + | | | + | | +-- 0 CLEAR CHANNEL 0 MASK BIT + | | 1 SET CHANNEL 0 MASK BIT + | | + | +---------- 0 CLEAR CHANNEL 2 MASK BIT + | 1 SET CHANNEL 2 MASK BIT + | + +-------------- 0 CLEAR CHANNEL 3 MASK BIT + 1 SET CHANNEL 3 MASK BIT + + Read FDC Status Register + + The Read FDC Status Register command accesses the FDC's main + status register. The individual status register bits are as + follows: + + 7 6 5 4 3 2 1 0 + +---+---+---+---+---+---+---+---+ + | | + +---+---+---+---+---+---+---+---+ + | | | | | | | | + | | | | | | | +-- FDD 0 BUSY + | | | | | | +------ FDD 1 BUSY + | | | | | +---------- FDD 2 BUSY + | | | | +-------------- FDD 3 BUSY + | | | +------------------ FDC BUSY + | | +---------------------- NON-DMA MODE + | +-------------------------- DATA INPUT/OUTPUT + +------------------------------ REQUEST FOR MASTER + + Read/Write FDC Data Register + + The Read and Write FDC Data Register commands are used to write + command and parameter bytes to the FDC in order to specify the + operation to be performed (referred to as the "command phase") + and to read status bytes from the FDC following the operation + (referred to as the "result phase"). During the command and + result phases, the 8-bit data register is actually a series of + 8-bit registers in a stack. Each register is accessed in + sequence; the number of registers accessed and the individual + register contents are defined by the specific disk command. + + Write Controller Auxiliary Port + + The Write Controller Auxiliary Port command is used to set or + clear individual bits within the controller's auxiliary port. + The four low-order port bits are dedicated to auxiliary drive + control functions (jumper links are required to connect the + desired port bit to an available pin on the drive interface + connectors). The most common application for these bits is + the "Motor-On" control function for mini-sized drives. + + 7 6 5 4 3 2 1 0 + +---+---+---+---+---+---+---+---+ + | | + +---+---+---+---+---+---+---+---+ + | | | | | | | | + | | | | +---+---+---+-- DRIVE CONTROL + | | | +------------------ ADDR 20 + | | +---------------------- ADDR 21 + | +-------------------------- ADDR 22 + +------------------------------ ADDR 23 + + Poll Interrupt Status + + The Poll Interrupt Status command presents the interrupt + status of the controller and the two interrupt status + lines dedicated to the iSBX Multimodule board. + 7 6 5 4 3 2 1 0 + +---+---+---+---+---+---+---+---+ + | X X X X X | + +---+---+---+---+---+---+---+---+ + | | | + | | +-- CONTROLLER INTERRUPT + | +------ MULTIMODULE BOARD INTERRUPT 0 + +---------- MULTIMODULE BOARD INTERRUPT 1 + + Controller Reset + + The Controller Reset command is the software reset for the + controller. This command clears the controller's auxiliary + port and segment address register, provides a reset signal + to the iSBX Multimodule board and initializes the bus + controller (releases the bus), the DMAC (clears the internal + registers and masks the DREQ inputs), and the FDC (places + the FDC in an idle state and disables the output control + lines to the diskette drive). + + Write Controller Low- And High-Byte Segment Address Registers + + The Write Controller Low- and High-Byte Address Registers + commands are required when the controller uses 20-bit + addressing (memory address range from 0 to OFFFFFH). These + commands are issued prior to initiating a diskette read or + write operation to specify the 16-bit segment address. + + FDC Commands + + The 8272/D765 is capable of performing 15 different + commands. Each command is initiated by a multibyte transfer + from the processor, and the result after execution of the + command may also be a multibyte transfer back to the processor. + Because of this multibyte interchange of information between + the FDC and the processor, it is convenient to consider each + command as consisting of three phases: + + Command Phase: The FDC receives all information required to + perform a particular operation from the processor. + + Execution Phase: The FDC performs the operation it was + instructed to do. + + Result Phase: After completion of the operation, status + and other housekeeping information are made available + to the processor. + + Not all the FDC commands are supported by this emulation. Only the subset + of commands required to build an operable CP/M BIOS are supported. They are: + + Read - Read specified data from the selected FDD. + + Write - Write specified data to the selected FDD. + + Seek - Move the R/W head to the specified cylinder on the specified FDD. + + Specify - Set the characteristics for all the FDDs. + + Sense Interrupt - Sense change in FDD Ready line or and of Seek/Recalibrate + command. + + Sense Drive - Returns status of all the FDDs. + + Recalibrate - Move the R/W head to cylinder 0 on the specified FDD. + + Format Track - Format the current track on the specified FDD. + + Read ID - Reads the first address mark it finds. + + Simulated Floppy Disk Drives + + The units in this device simulate an 8- or 5 1/4- or 3 1/2 inch drives. The + drives can emulate SSSD, SSDD, and DSDD. Drives can be attached to files up + to 1.44MB in size. Drive configuration is selected when a disk is logged onto + the system. An identity sector or identity byte contains information to + configure the OS drivers for the type of drive to emulate. + + uptr->u3 - + uptr->u4 - + uptr->u5 - + uptr->u6 - unit number (0-FDD_NUM) +*/ + +#include "system_defs.h" + +#define UNIT_V_WPMODE (UNIT_V_UF) /* Write protect */ +#define UNIT_WPMODE (1 << UNIT_V_WPMODE) + +/* master status register definitions */ + +#define RQM 0x80 /* Request for master */ +#define DIO 0x40 /* Data I/O Direction 0=W, 1=R */ +#define NDM 0x20 /* Non-DMA mode */ +#define CB 0x10 /* FDC busy */ +#define D3B 0x08 /* FDD 3 busy */` +#define D2B 0x04 /* FDD 2 busy */` +#define D1B 0x02 /* FDD 1 busy */` +#define D0B 0x01 /* FDD 0 busy */` + +/* status register 0 definitions */ + +#define IC 0xC0 /* Interrupt code */ +#define IC_NORM 0x00 /* normal completion */ +#define IC_ABNORM 0x40 /* abnormal completion */ +#define IC_INVC 0x80 /* invalid command */ +#define IC_RC 0xC0 /* drive not ready */ +#define SE 0x20 /* Seek end */ +#define EC 0x10 /* Equipment check */ +#define NR 0x08 /* Not ready */ +#define HD 0x04 /* Head selected */ +#define US 0x03 /* Unit selected */ +#define US_0 0x00 /* Unit 0 */ +#define US_1 0x01 /* Unit 1 */ +#define US_2 0x02 /* Unit 2 */ +#define US_3 0x03 /* Unit 3 */ + +/* status register 1 definitions */ + +#define EN 0x80 /* End of cylinder */ +#define DE 0x20 /* Data error */ +#define OR 0x10 /* Overrun */ +#define ND 0x04 /* No data */ +#define NW 0x02 /* Not writable */ +#define MA 0x01 /* Missing address mark */ + +/* status register 2 definitions */ + +#define CM 0x40 /* Control mark */ +#define DD 0x20 /* Data error in data field */ +#define WC 0x10 /* Wrong cylinder */ +#define BC 0x02 /* Bad cylinder */ +#define MD 0x01 /* Missing address mark in data field */ + +/* status register 3/fddst definitions */ + +#define FT 0x80 /* Fault */ +#define WP 0x40 /* Write protect */ +#define RDY 0x20 /* Ready */ +#define T0 0x10 /* Track 0 */ +#define TS 0x08 /* Two sided */ +//#define HD 0x04 /* Head selected */ +//#define US 0x03 /* Unit selected */ + +/* FDC command definitions */ + +#define READTRK 0x02 +#define SPEC 0x03 +#define SENDRV 0x04 +#define WRITE 0x05 +#define READ 0x06 +#define HOME 0x07 +#define SENINT 0x08 +#define WRITEDEL 0x09 +#define READID 0x0A +#define READDEL 0x0C +#define FMTTRK 0x0D +#define SEEK 0x0F +#define SCANEQ 0x11 +#define SCANLOEQ 0x19 +#define SCANHIEQ 0x1D + +#define FDD_NUM 4 + +int32 sbc208_devnum = 0; //actual number of 8255 instances + 1 +uint16 sbc208_port[4]; //base port registered to each instance + +/* internal function prototypes */ + +t_stat isbc208_svc (UNIT *uptr); +t_stat isbc208_reset (DEVICE *dptr, uint16 base); +void isbc208_reset1 (void); +t_stat isbc208_attach (UNIT *uptr, CONST char *cptr); +t_stat isbc208_set_mode (UNIT *uptr, int32 val, CONST char *cptr, void *desc); +uint8 isbc208_r0(t_bool io, uint8 data); +uint8 isbc208_r1(t_bool io, uint8 data); +uint8 isbc208_r2(t_bool io, uint8 data); +uint8 isbc208_r3(t_bool io, uint8 data); +uint8 isbc208_r4(t_bool io, uint8 data); +uint8 isbc208_r5(t_bool io, uint8 data); +uint8 isbc208_r6(t_bool io, uint8 data); +uint8 isbc208_r7(t_bool io, uint8 data); +uint8 isbc208_r8(t_bool io, uint8 data); +uint8 isbc208_r9(t_bool io, uint8 data); +uint8 isbc208_rA(t_bool io, uint8 data); +uint8 isbc208_rB(t_bool io, uint8 data); +uint8 isbc208_rC(t_bool io, uint8 data); +uint8 isbc208_rD(t_bool io, uint8 data); +uint8 isbc208_rE(t_bool io, uint8 data); +uint8 isbc208_rF(t_bool io, uint8 data); +uint8 isbc208_r10(t_bool io, uint8 data); +uint8 isbc208_r11(t_bool io, uint8 data); +uint8 isbc208_r12(t_bool io, uint8 data); +uint8 isbc208_r13(t_bool io, uint8 data); +uint8 isbc208_r14(t_bool io, uint8 data); +uint8 isbc208_r15(t_bool io, uint8 data); + +/* external function prototypes */ + +extern void set_irq(int32 int_num); +extern void clr_irq(int32 int_num); +extern uint16 reg_dev(uint8 (*routine)(t_bool, uint8), uint16, uint8); +extern void multibus_put_mbyte(uint16 addr, uint8 val); +extern uint8 multibus_get_mbyte(uint16 addr); + +/* 8237 physical register definitions */ + +uint16 i8237_r0; // 8237 ch 0 address register +uint16 i8237_r1; // 8237 ch 0 count register +uint16 i8237_r2; // 8237 ch 1 address register +uint16 i8237_r3; // 8237 ch 1 count register +uint16 i8237_r4; // 8237 ch 2 address register +uint16 i8237_r5; // 8237 ch 2 count register +uint16 i8237_r6; // 8237 ch 3 address register +uint16 i8237_r7; // 8237 ch 3 count register +uint8 i8237_r8; // 8237 status register +uint8 i8237_r9; // 8237 command register +uint8 i8237_rA; // 8237 mode register +uint8 i8237_rB; // 8237 mask register +uint8 i8237_rC; // 8237 request register +uint8 i8237_rD; // 8237 first/last ff +uint8 i8237_rE; // 8237 +uint8 i8237_rF; // 8237 + +/* 8272 physical register definitions */ +/* 8272 command register stack*/ + +uint8 i8272_w0; // MT+MFM+SK+command +uint8 i8272_w1; // HDS [HDS=H << 2] + DS1 + DS0 +uint8 i8272_w2; // cylinder # (0-XX) +uint8 i8272_w3; // head # (0 or 1) +uint8 i8272_w4; // sector # (1-XX) +uint8 i8272_w5; // number of bytes (128 << N) +uint8 i8272_w6; // End of track (last sector # on cylinder) +uint8 i8272_w7; // Gap length +uint8 i8272_w8; // Data length (when N=0, size to read or write) + +/* 8272 status register stack */ + +uint8 i8272_msr; // main status +uint8 i8272_r0; // ST 0 +uint8 i8272_r1; // ST 1 +uint8 i8272_r2; // ST 2 +uint8 i8272_r3; // ST 3 + +/* iSBC-208 physical register definitions */ + +uint16 isbc208_sr; // isbc-208 segment register +uint8 isbc208_i; // iSBC-208 interrupt register +uint8 isbc208_a; // iSBC-208 auxillary port register + +/* data obtained from analyzing command registers/attached file length */ + +int32 wsp = 0, rsp = 0; // indexes to write and read stacks (8272 data) +int32 cyl; // current cylinder +int32 hed; // current head [ h << 2] +int32 h; // current head +int32 sec; // current sector +int32 drv; // current drive +uint8 cmd, pcmd; // current command +int32 secn; // N 0-128, 1-256, etc +int32 spt; // sectors per track +int32 ssize; // sector size (128 << N) + +uint8 *isbc208_buf[FDD_NUM] = { /* FDD buffer pointers */ + NULL, + NULL, + NULL, + NULL +}; + +int32 fddst[FDD_NUM] = { // in ST3 format + 0, // status of FDD 0 + 0, // status of FDD 1 + 0, // status of FDD 2 + 0 // status of FDD 3 +}; + +int8 maxcyl[FDD_NUM] = { + 0, // last cylinder + 1 of FDD 0 + 0, // last cylinder + 1 of FDD 1 + 0, // last cylinder + 1 of FDD 2 + 0 // last cylinder + 1 of FDD 3 +}; + +/* isbc208 Standard SIMH Device Data Structures - 4 units */ + +UNIT isbc208_unit[] = { + { UDATA (&isbc208_svc, UNIT_ATTABLE+UNIT_DISABLE, 0), 20 }, + { UDATA (&isbc208_svc, UNIT_ATTABLE+UNIT_DISABLE, 0), 20 }, + { UDATA (&isbc208_svc, UNIT_ATTABLE+UNIT_DISABLE, 0), 20 }, + { UDATA (&isbc208_svc, UNIT_ATTABLE+UNIT_DISABLE, 0), 20 } +}; + +REG isbc208_reg[] = { + { HRDATA (CH0ADR, i8237_r0, 16) }, + { HRDATA (CH0CNT, i8237_r1, 16) }, + { HRDATA (CH1ADR, i8237_r2, 16) }, + { HRDATA (CH1CNT, i8237_r3, 16) }, + { HRDATA (CH2ADR, i8237_r4, 16) }, + { HRDATA (CH2CNT, i8237_r5, 16) }, + { HRDATA (CH3ADR, i8237_r6, 16) }, + { HRDATA (CH3CNT, i8237_r7, 16) }, + { HRDATA (STAT37, i8237_r8, 8) }, + { HRDATA (CMD37, i8237_r9, 8) }, + { HRDATA (MODE, i8237_rA, 8) }, + { HRDATA (MASK, i8237_rB, 8) }, + { HRDATA (REQ, i8237_rC, 8) }, + { HRDATA (FF, i8237_rD, 8) }, + { HRDATA (STAT72, i8272_msr, 8) }, + { HRDATA (STAT720, i8272_r0, 8) }, + { HRDATA (STAT721, i8272_r1, 8) }, + { HRDATA (STAT722, i8272_r2, 8) }, + { HRDATA (STAT723, i8272_r3, 8) }, + { HRDATA (CMD720, i8272_w0, 8) }, + { HRDATA (CMD721, i8272_w1, 8) }, + { HRDATA (CMD722, i8272_w2, 8) }, + { HRDATA (CMD723, i8272_w3, 8) }, + { HRDATA (CMD724, i8272_w4, 8) }, + { HRDATA (CMD725, i8272_w5, 8) }, + { HRDATA (CMD726, i8272_w6, 8) }, + { HRDATA (CMD727, i8272_w7, 8) }, + { HRDATA (CMD728, i8272_w8, 8) }, + { HRDATA (FDD0, fddst[0], 8) }, + { HRDATA (FDD1, fddst[1], 8) }, + { HRDATA (FDD2, fddst[2], 8) }, + { HRDATA (FDD3, fddst[3], 8) }, + { HRDATA (SEGREG, isbc208_sr, 8) }, + { HRDATA (AUX, isbc208_a, 8) }, + { HRDATA (INT, isbc208_i, 8) }, + { NULL } +}; + +MTAB isbc208_mod[] = { + { UNIT_WPMODE, 0, "RW", "RW", &isbc208_set_mode }, + { UNIT_WPMODE, UNIT_WPMODE, "WP", "WP", &isbc208_set_mode }, + { 0 } +}; + +DEBTAB isbc208_debug[] = { + { "ALL", DEBUG_all }, + { "FLOW", DEBUG_flow }, + { "READ", DEBUG_read }, + { "WRITE", DEBUG_write }, + { "LEV1", DEBUG_level1 }, + { "LEV2", DEBUG_level2 }, + { "REG", DEBUG_reg }, + { NULL } +}; + +DEVICE isbc208_dev = { + "SBC208", //name + isbc208_unit, //units + isbc208_reg, //registers + isbc208_mod, //modifiers + FDD_NUM, //numunits + 16, //aradix + 32, //awidth + 1, //aincr + 16, //dradix + 8, //dwidth + NULL, //examine + NULL, //deposit +// &isbc208_reset, //deposit + NULL, //deposit + NULL, //boot + &isbc208_attach, //attach + NULL, //detach + NULL, //ctxt + DEV_DEBUG+DEV_DISABLE+DEV_DIS, //flags +// 0, //dctrl + DEBUG_flow + DEBUG_read + DEBUG_write, //dctrl + isbc208_debug, //debflags + NULL, //msize + NULL //lname +}; + +/* Service routines to handle simulator functions */ + +/* service routine - actually does the simulated disk I/O */ + +t_stat isbc208_svc (UNIT *uptr) +{ + uint32 i; + int32 imgadr, data; + int c; + int32 bpt, bpc; + FILE *fp; + + if ((i8272_msr & CB) && cmd && (uptr->u6 == drv)) { /* execution phase */ + sim_debug (DEBUG_flow, &isbc208_dev, "208_svc: Entered execution phase\n"); + switch (cmd) { + case READ: /* 0x06 */ +// sim_printf("READ-e: fddst=%02X", fddst[uptr->u6]); + h = i8272_w3; // h = 0 or 1 + hed = i8272_w3 << 2; // hed = 0 or 4 [h << 2] + sec = i8272_w4; // sector number (1-XX) + secn = i8272_w5; // N (0-5) + spt = i8272_w6; // sectors/track + ssize = 128 << secn; // size of sector (bytes) + bpt = ssize * spt; // bytes/track + bpc = bpt * 2; // bytes/cylinder +// sim_printf(" d=%d h=%d c=%d s=%d\n", drv, h, cyl, sec); + sim_debug (DEBUG_flow, &isbc208_dev, + "208_svc: FDC read: h=%d, hed=%d, sec=%d, secn=%d, spt=%d, ssize=%04X, bpt=%04X, bpc=%04X\n", + h, hed, sec, secn, spt, ssize, bpt, bpc); + sim_debug (DEBUG_flow, &isbc208_dev, + "208_svc: FDC read: d=%d h=%d c=%d s=%d N=%d spt=%d fddst=%02X\n", + drv, h, cyl, sec, secn, spt, fddst[uptr->u6]); + sim_debug (DEBUG_read, &isbc208_dev, "208_svc: FDC read of d=%d h=%d c=%d s=%d\n", + drv, h, cyl, sec); + if ((fddst[uptr->u6] & RDY) == 0) { // drive not ready + i8272_r0 = IC_ABNORM + NR + hed + drv; /* command done - Not ready error*/ + i8272_r3 = fddst[uptr->u6]; + i8272_msr |= (RQM + DIO + CB); /* enter result phase */ + sim_debug (DEBUG_flow, &isbc208_dev, "208_svc: FDC read: Not Ready\n"); + } else { // get image addr for this d, h, c, s + imgadr = (cyl * bpc) + (h * bpt) + ((sec - 1) * ssize); + sim_debug (DEBUG_read, &isbc208_dev, + "208_svc: FDC read: DMA addr=%04X cnt=%04X imgadr=%04X\n", + i8237_r0, i8237_r1, imgadr); + for (i=0; i<=i8237_r1; i++) { /* copy selected sector to memory */ + data = *(isbc208_buf[uptr->u6] + (imgadr + i)); + multibus_put_mbyte(i8237_r0 + i, data); + } +//*** need to step return results IAW table 3-11 in 143078-001 + i8272_w4 = ++sec; /* next sector */ + i8272_r0 = hed + drv; /* command done - no error */ + i8272_r3 = fddst[uptr->u6]; + } + i8272_r1 = 0; + i8272_r2 = 0; + i8272_w2 = cyl; /* generate a current address mark */ + i8272_w3 = h; + if (i8272_w4 > i8272_w6) { // beyond last sector of track? + i8272_w4 = 1; // yes, set to sector 1; + if (h) { // on head one? + i8272_w2++; // yes, step cylinder + h = 0; // back to head 0 + } + } + i8272_w5 = secn; + i8272_msr |= (RQM + DIO + CB); /* enter result phase */ + rsp = wsp = 0; /* reset indexes */ + set_irq(SBC208_INT); /* set interrupt */ +// sim_printf("READ-x: fddst=%02X\n", fddst[uptr->u6]); + break; + case WRITE: /* 0x05 */ +// sim_printf("WRITE-e: fddst=%02X\n", fddst[uptr->u6]); + h = i8272_w3; // h = 0 or 1 + hed = i8272_w3 << 2; // hed = 0 or 4 [h << 2] + sec = i8272_w4; // sector number (1-XX) + secn = i8272_w5; // N (0-5) + spt = i8272_w6; // sectors/track + ssize = 128 << secn; // size of sector (bytes) + bpt = ssize * spt; // bytes/track + bpc = bpt * 2; // bytes/cylinder + sim_debug (DEBUG_flow, &isbc208_dev, + "208_svc: FDC write: hed=%d, sec=%d, secn=%d, spt=%d, ssize=%04X, bpt=%04X, bpc=%04X\n", + hed, sec, secn, spt, ssize, bpt, bpc); + sim_debug (DEBUG_flow, &isbc208_dev, + "208_svc: FDC write: d=%d h=%d c=%d s=%d N=%d spt=%d fddst=%02X\n", + drv, h, cyl, sec, secn, spt, fddst[uptr->u6]); + sim_debug (DEBUG_write, &isbc208_dev, "208_svc: FDC write of d=%d h=%d c=%d s=%d\n", + drv, h, cyl, sec); + i8272_r1 = 0; // clear ST1 + i8272_r2 = 0; // clear ST2 + if ((fddst[uptr->u6] & RDY) == 0) { + i8272_r0 = IC_ABNORM + NR + hed + drv; /* Not ready error*/ + i8272_r3 = fddst[uptr->u6]; + i8272_msr |= (RQM + DIO + CB); /* enter result phase */ + sim_debug (DEBUG_flow, &isbc208_dev, "208_svc: FDC write: Not Ready\n"); +// } else if (fddst[uptr->u6] & WP) { +// i8272_r0 = IC_ABNORM + hed + drv; /* write protect error*/ +// i8272_r1 = NW; // set not writable in ST1 +// i8272_r3 = fddst[uptr->u6] + WP; +// i8272_msr |= (RQM + DIO + CB); /* enter result phase */ +// sim_printf("\nWrite Protected fddst[%d]=%02X\n", uptr->u6, fddst[uptr->u6]); +// if (isbc208_dev.dctrl & DEBUG_flow) +// sim_printf("208_svc: FDC write: Write Protected\n"); + } else { // get image addr for this d, h, c, s + imgadr = (cyl * bpc) + (h * bpt) + ((sec - 1) * ssize); + sim_debug (DEBUG_write, &isbc208_dev, + "208_svc: FDC write: DMA adr=%04X cnt=%04X imgadr=%04X\n", + i8237_r0, i8237_r1, imgadr); + for (i=0; i<=i8237_r1; i++) { /* copy selected memory to image */ + data = multibus_get_mbyte(i8237_r0 + i); + *(isbc208_buf[uptr->u6] + (imgadr + i)) = data; + } + //*** quick fix. Needs more thought! + fp = fopen(uptr->filename, "wb"); // write out modified image + for (i=0; icapac; i++) { + c = *(isbc208_buf[uptr->u6] + i) & 0xFF; + fputc(c, fp); + } + fclose(fp); +//*** need to step return results IAW table 3-11 in 143078-001 + i8272_w2 = cyl; /* generate a current address mark */ + i8272_w3 = hed >> 2; + i8272_w4 = ++sec; /* next sector */ + i8272_w5 = secn; + i8272_r0 = hed + drv; /* command done - no error */ + i8272_r3 = fddst[uptr->u6]; + i8272_msr |= (RQM + DIO + CB); /* enter result phase */ + } + rsp = wsp = 0; /* reset indexes */ + set_irq(SBC208_INT); /* set interrupt */ +// sim_printf("WRITE-x: fddst=%02X\n", fddst[uptr->u6]); + break; + case FMTTRK: /* 0x0D */ + if ((fddst[uptr->u6] & RDY) == 0) { + i8272_r0 = IC_ABNORM + NR + hed + drv; /* Not ready error*/ + i8272_msr |= (RQM + DIO + CB); /* enter result phase */ + sim_debug (DEBUG_flow, &isbc208_dev, "208_svc: Not Ready\n"); + } else if (fddst[uptr->u6] & WP) { + i8272_r0 = IC_ABNORM + hed + drv; /* write protect error*/ + i8272_r3 = fddst[uptr->u6] + WP; + i8272_msr |= (RQM + DIO + CB); /* enter result phase */ + sim_debug (DEBUG_flow, &isbc208_dev, "208_svc: Write Protected\n"); + } else { + ; /* do nothing for now */ + i8272_msr |= (RQM + DIO + CB); /* enter result phase */ + } + rsp = wsp = 0; /* reset indexes */ + set_irq(SBC208_INT); /* set interrupt */ + break; + case SENINT: /* 0x08 */ + i8272_msr |= (RQM + DIO + CB); /* enter result phase */ + i8272_r0 = hed + drv; /* command done - no error */ + i8272_r1 = 0; + i8272_r2 = 0; + rsp = wsp = 0; /* reset indexes */ + clr_irq(SBC208_INT); /* clear interrupt */ + break; + case SENDRV: /* 0x04 */ + sim_debug (DEBUG_flow, &isbc208_dev, "208_svc: FDC sense drive: d=%d fddst=%02X\n", + drv, fddst[uptr->u6]); + i8272_msr |= (RQM + DIO + CB); /* enter result phase */ + i8272_r0 = hed + drv; /* command done - no error */ + i8272_r1 = 0; + i8272_r2 = 0; + i8272_r3 = fddst[drv]; /* drv status */ + rsp = wsp = 0; /* reset indexes */ + break; + case HOME: /* 0x07 */ +// sim_printf("HOME-e: fddst=%02X\n", fddst[uptr->u6]); + sim_debug (DEBUG_flow, &isbc208_dev, "208_svc: FDC home: d=%d fddst=%02X\n", + drv, fddst[uptr->u6]); + if ((fddst[uptr->u6] & RDY) == 0) { + i8272_r0 = IC_ABNORM + NR + hed + drv; /* Not ready error*/ + i8272_r3 = fddst[uptr->u6]; + sim_debug (DEBUG_flow, &isbc208_dev, "208_svc: Not Ready\n"); + } else { + cyl = 0; /* now on cylinder 0 */ + fddst[drv] |= T0; /* set status flag */ + i8272_r0 = SE + hed + drv; /* seek end - no error */ + } + i8272_r1 = 0; + i8272_r2 = 0; + i8272_msr &= ~(RQM + DIO + CB + hed + drv); /* execution phase done*/ + i8272_msr |= RQM; /* enter COMMAND phase */ + rsp = wsp = 0; /* reset indexes */ + set_irq(SBC208_INT); /* set interrupt */ +// sim_printf("HOME-x: fddst=%02X\n", fddst[uptr->u6]); + break; + case SPEC: /* 0x03 */ + fddst[0] |= TS; //*** bad, bad, bad! + fddst[1] |= TS; + fddst[2] |= TS; + fddst[3] |= TS; +// sim_printf("SPEC-e: fddst[%d]=%02X\n", uptr->u6, fddst[uptr->u6]); + sim_debug (DEBUG_flow, &isbc208_dev, + "208_svc: FDC specify: SRT=%d ms HUT=%d ms HLT=%d ms \n", + 16 - (drv >> 4), 16 * (drv & 0x0f), i8272_w2 & 0xfe); + i8272_r0 = hed + drv; /* command done - no error */ + i8272_r1 = 0; + i8272_r2 = 0; +// i8272_msr &= ~(RQM + DIO + CB); /* execution phase done*/ + i8272_msr = 0; // force 0 for now, where does 0x07 come from? + i8272_msr |= RQM; /* enter command phase */ + rsp = wsp = 0; /* reset indexes */ +// sim_printf("SPEC-x: fddst[%d]=%02X\n", uptr->u6, fddst[uptr->u6]); + break; + case READID: /* 0x0A */ + if ((fddst[uptr->u6] & RDY) == 0) { + i8272_r0 = IC_RC + NR + hed + drv; /* Not ready error*/ + i8272_r3 = fddst[uptr->u6]; + sim_debug (DEBUG_flow, &isbc208_dev, "208_svc: Not Ready\n"); + } else { + i8272_w2 = cyl; /* generate a valid address mark */ + i8272_w3 = hed >> 2; + i8272_w4 = 1; /* always sector 1 */ + i8272_w5 = secn; + i8272_r0 = hed + drv; /* command done - no error */ + i8272_msr &= ~(RQM + DIO + CB); /* execution phase done*/ + i8272_msr |= RQM; /* enter command phase */ + } + i8272_r1 = 0; + i8272_r2 = 0; + rsp = wsp = 0; /* reset indexes */ + break; + case SEEK: /* 0x0F */ +// sim_printf("SEEK-e: fddst=%02X\n", fddst[uptr->u6]); + sim_debug (DEBUG_flow, &isbc208_dev, "208_svc: FDC seek: d=%d c=%d fddst=%02X\n", + drv, i8272_w2, fddst[uptr->u6]); + if ((fddst[uptr->u6] & RDY) == 0) { /* Not ready? */ + i8272_r0 = IC_ABNORM + NR + hed + drv; /* error*/ + i8272_r3 = fddst[uptr->u6]; + sim_debug (DEBUG_flow, &isbc208_dev, "208_svc: FDC seek: Not Ready\n"); + } else if (i8272_w2 >= maxcyl[uptr->u6]) { + i8272_r0 = IC_ABNORM + RDY + hed + drv; /* seek error*/ + sim_debug (DEBUG_flow, &isbc208_dev, "208_svc: FDC seek: Invalid Cylinder %d\n", i8272_w2); + } else { + i8272_r0 |= SE + hed + drv; /* command done - no error */ + cyl = i8272_w2; /* new cylinder number */ + if (cyl == 0) { /* if cyl 0, set flag */ + fddst[drv] |= T0; /* set T0 status flag */ + i8272_r3 |= T0; + } else { + fddst[drv] &= ~T0; /* clear T0 status flag */ + i8272_r3 &= ~T0; + } + } + i8272_r1 = 0; + i8272_r2 = 0; + i8272_msr &= ~(RQM + DIO + CB + hed + drv); /* execution phase done*/ + i8272_msr |= RQM; /* enter command phase */ + rsp = wsp = 0; /* reset indexes */ +// set_irq(SBC208_INT); /* set interrupt */ +// sim_printf("SEEK-x: fddst=%02X\n", fddst[uptr->u6]); + break; + default: + i8272_msr &= ~(RQM + DIO + CB); /* execution phase done*/ + i8272_msr |= RQM; /* enter command phase */ + i8272_r0 = IC_INVC + hed + drv; /* set bad command error */ + i8272_r1 = 0; + i8272_r2 = 0; + rsp = wsp = 0; /* reset indexes */ + break; + } + pcmd = cmd; /* save for result phase */ + cmd = 0; /* reset command */ + sim_debug (DEBUG_flow, &isbc208_dev, + "208_svc: Exit: msr=%02X ST0=%02X ST1=%02X ST2=%02X ST3=%02X\n", + i8272_msr, i8272_r0, i8272_r1, i8272_r2, i8272_r3); + } + sim_activate (&isbc208_unit[uptr->u6], isbc208_unit[uptr->u6].wait); + return SCPE_OK; +} + +/* Reset routine */ + +t_stat isbc208_reset (DEVICE *dptr, uint16 base) +{ + if (sbc208_devnum > SBC208_NUM) { + sim_printf("sbc208_reset: too many devices!\n"); + return SCPE_MEM; + } + if (SBC202_NUM) { + sim_printf(" SBC208-%d: Hardware Reset\n", sbc208_devnum); + sim_printf(" SBC208-%d: Registered at %04X\n", sbc208_devnum, base); + sbc208_port[sbc208_devnum] = reg_dev(isbc208_r0, SBC208_BASE + 0, sbc208_devnum); + reg_dev(isbc208_r1, SBC208_BASE + 1, sbc208_devnum); + reg_dev(isbc208_r2, SBC208_BASE + 2, sbc208_devnum); + reg_dev(isbc208_r3, SBC208_BASE + 3, sbc208_devnum); + reg_dev(isbc208_r4, SBC208_BASE + 4, sbc208_devnum); + reg_dev(isbc208_r5, SBC208_BASE + 5, sbc208_devnum); + reg_dev(isbc208_r6, SBC208_BASE + 6, sbc208_devnum); + reg_dev(isbc208_r7, SBC208_BASE + 7, sbc208_devnum); + reg_dev(isbc208_r8, SBC208_BASE + 8, sbc208_devnum); + reg_dev(isbc208_r9, SBC208_BASE + 9, sbc208_devnum); + reg_dev(isbc208_rA, SBC208_BASE + 10, sbc208_devnum); + reg_dev(isbc208_rB, SBC208_BASE + 11, sbc208_devnum); + reg_dev(isbc208_rC, SBC208_BASE + 12, sbc208_devnum); + reg_dev(isbc208_rD, SBC208_BASE + 13, sbc208_devnum); + reg_dev(isbc208_rE, SBC208_BASE + 14, sbc208_devnum); + reg_dev(isbc208_rF, SBC208_BASE + 15, sbc208_devnum); + reg_dev(isbc208_r10, SBC208_BASE + 16, sbc208_devnum); + reg_dev(isbc208_r11, SBC208_BASE + 17, sbc208_devnum); + reg_dev(isbc208_r12, SBC208_BASE + 18, sbc208_devnum); + reg_dev(isbc208_r13, SBC208_BASE + 19, sbc208_devnum); + reg_dev(isbc208_r14, SBC208_BASE + 20, sbc208_devnum); + reg_dev(isbc208_r15, SBC208_BASE + 21, sbc208_devnum); + if ((isbc208_dev.flags & DEV_DIS) == 0) + isbc208_reset1(); + sbc208_devnum++; + } else { + sim_printf(" No isbc208 installed\n"); + } + return SCPE_OK; +} + +void isbc208_reset1 (void) +{ + int32 i; + UNIT *uptr; + static int flag = 1; + + if (flag) sim_printf("iSBC 208: Initializing\n"); + for (i = 0; i < FDD_NUM; i++) { /* handle all units */ + uptr = isbc208_dev.units + i; + if (uptr->capac == 0) { /* if not configured */ +// 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! */ + fddst[i] = WP + T0 + i; /* initial drive status */ + uptr->flags |= UNIT_WPMODE; /* set WP in unit flags */ + sim_activate (&isbc208_unit[uptr->u6], isbc208_unit[uptr->u6].wait); + } else { + fddst[i] = RDY + WP + T0 + i; /* initial attach drive status */ +// 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 */ + i8272_msr = RQM; /* 8272 ready for start of command */ + rsp = wsp = 0; /* reset indexes */ + cmd = 0; /* clear command */ + sim_printf(" SBC208-%d: Software Reset\n", sbc208_devnum); + if (flag) { + sim_printf(" 8237 Reset\n"); + sim_printf(" 8272 Reset\n"); + } + flag = 0; +} + +/* isbc208 attach - attach an .IMG file to a FDD */ + +t_stat isbc208_attach (UNIT *uptr, CONST char *cptr) +{ + t_stat r; + FILE *fp; + int32 i, c = 0; + long flen; + + sim_debug (DEBUG_flow, &isbc208_dev, " isbc208_attach: Entered with cptr=%s\n", cptr); + if ((r = attach_unit (uptr, cptr)) != SCPE_OK) { + sim_printf(" isbc208_attach: Attach error\n"); + return r; + } + fp = fopen(uptr->filename, "rb"); + if (fp == NULL) { + sim_printf(" Unable to open disk img file %s\n", uptr->filename); + sim_printf(" No disk image loaded!!!\n"); + } else { + sim_printf("iSBC 208: Attach\n"); + fseek(fp, 0, SEEK_END); /* size disk image */ + flen = ftell(fp); + fseek(fp, 0, SEEK_SET); + if (flen == -1) { + sim_printf(" isbc208_attach: File error\n"); + return SCPE_IOERR; + } + if (isbc208_buf[uptr->u6] == NULL) { /* no buffer allocated */ + isbc208_buf[uptr->u6] = (uint8 *)malloc(flen); + if (isbc208_buf[uptr->u6] == NULL) { + sim_printf(" iSBC208_attach: Malloc error\n"); + return SCPE_MEM; + } + } + uptr->capac = flen; + i = 0; + c = fgetc(fp); // copy disk image into buffer + while (c != EOF) { + *(isbc208_buf[uptr->u6] + i++) = c & 0xFF; + c = fgetc(fp); + } + fclose(fp); + fddst[uptr->u6] |= RDY; /* set unit ready */ + if (flen == 368640) { /* 5" 360K DSDD */ + maxcyl[uptr->u6] = 40; + fddst[uptr->u6] |= TS; // two sided + } + else if (flen == 737280) { /* 5" 720K DSQD / 3.5" 720K DSDD */ + maxcyl[uptr->u6] = 80; + fddst[uptr->u6] |= TS; // two sided + } + else if (flen == 1228800) { /* 5" 1.2M DSHD */ + maxcyl[uptr->u6] = 80; + fddst[uptr->u6] |= TS; // two sided + } + else if (flen == 1474560) { /* 3.5" 1.44M DSHD */ + maxcyl[uptr->u6] = 80; + fddst[uptr->u6] |= TS; // two sided + } + sim_printf(" Drive-%d: %d bytes of disk image %s loaded, fddst=%02X\n", + uptr->u6, i, uptr->filename, fddst[uptr->u6]); + } + sim_debug (DEBUG_flow, &isbc208_dev, " iSBC208_attach: Done\n"); + return SCPE_OK; +} + +/* isbc208 set mode = 8- or 16-bit data bus */ +/* always 8-bit mode for current simulators */ + +t_stat isbc208_set_mode (UNIT *uptr, int32 val, CONST char *cptr, void *desc) +{ + sim_debug (DEBUG_flow, &isbc208_dev, " isbc208_set_mode: Entered with val=%08XH uptr->flags=%08X\n", + val, uptr->flags); + if (val & UNIT_WPMODE) { /* write protect */ + fddst[uptr->u6] |= WP; + uptr->flags |= val; + } else { /* read write */ + fddst[uptr->u6] &= ~WP; + uptr->flags &= ~val; + } +// sim_printf("fddst[%d]=%02XH uptr->flags=%08X\n", uptr->u6, fddst[uptr->u6], uptr->flags); + sim_debug (DEBUG_flow, &isbc208_dev, " isbc208_set_mode: Done\n"); + return SCPE_OK; +} + +/* I/O instruction handlers, called from the CPU module when an + IN or OUT instruction is issued. + + Each function is passed an 'io' flag, where 0 means a read from + the port, and 1 means a write to the port. On input, the actual + input is passed as the return value, on output, 'data' is written + to the device. +*/ + +uint8 isbc208_r0(t_bool io, uint8 data) +{ + if (io == 0) { /* read current address CH 0 */ + if (i8237_rD) { /* high byte */ + i8237_rD = 0; + sim_debug (DEBUG_reg, &isbc208_dev, "i8237_r0(H) read as %04X\n", i8237_r0); + return (i8237_r0 >> 8); + } else { /* low byte */ + i8237_rD++; + sim_debug (DEBUG_reg, &isbc208_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, &isbc208_dev, "i8237_r0(H) set to %04X\n", i8237_r0); + } else { /* low byte */ + i8237_rD++; + i8237_r0 = data & 0xFF; + sim_debug (DEBUG_reg, &isbc208_dev, "i8237_r0(L) set to %04X\n", i8237_r0); + } + return 0; + } +} + +uint8 isbc208_r1(t_bool io, uint8 data) +{ + if (io == 0) { /* read current word count CH 0 */ + if (i8237_rD) { /* high byte */ + i8237_rD = 0; + sim_debug (DEBUG_reg, &isbc208_dev, "i8237_r1(H) read as %04X\n", i8237_r1); + return (i8237_r1 >> 8); + } else { /* low byte */ + i8237_rD++; + sim_debug (DEBUG_reg, &isbc208_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, &isbc208_dev, "i8237_r1(H) set to %04X\n", i8237_r1); + } else { /* low byte */ + i8237_rD++; + i8237_r1 = data & 0xFF; + sim_debug (DEBUG_reg, &isbc208_dev, "i8237_r1(L) set to %04X\n", i8237_r1); + } + return 0; + } +} + +uint8 isbc208_r2(t_bool io, uint8 data) +{ + if (io == 0) { /* read current address CH 1 */ + if (i8237_rD) { /* high byte */ + i8237_rD = 0; + sim_debug (DEBUG_reg, &isbc208_dev, "i8237_r2(H) read as %04X\n", i8237_r2); + return (i8237_r2 >> 8); + } else { /* low byte */ + i8237_rD++; + sim_debug (DEBUG_reg, &isbc208_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, &isbc208_dev, "i8237_r2(H) set to %04X\n", i8237_r2); + } else { /* low byte */ + i8237_rD++; + i8237_r2 = data & 0xFF; + sim_debug (DEBUG_reg, &isbc208_dev, "i8237_r2(L) set to %04X\n", i8237_r2); + } + return 0; + } +} + +uint8 isbc208_r3(t_bool io, uint8 data) +{ + if (io == 0) { /* read current word count CH 1 */ + if (i8237_rD) { /* high byte */ + i8237_rD = 0; + sim_debug (DEBUG_reg, &isbc208_dev, "i8237_r3(H) read as %04X\n", i8237_r3); + return (i8237_r3 >> 8); + } else { /* low byte */ + i8237_rD++; + sim_debug (DEBUG_reg, &isbc208_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, &isbc208_dev, "i8237_r3(H) set to %04X\n", i8237_r3); + } else { /* low byte */ + i8237_rD++; + i8237_r3 = data & 0xFF; + sim_debug (DEBUG_reg, &isbc208_dev, "i8237_r3(L) set to %04X\n", i8237_r3); + } + return 0; + } +} + +uint8 isbc208_r4(t_bool io, uint8 data) +{ + if (io == 0) { /* read current address CH 2 */ + if (i8237_rD) { /* high byte */ + i8237_rD = 0; + sim_debug (DEBUG_reg, &isbc208_dev, "i8237_r4(H) read as %04X\n", i8237_r4); + return (i8237_r4 >> 8); + } else { /* low byte */ + i8237_rD++; + sim_debug (DEBUG_reg, &isbc208_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, &isbc208_dev, "i8237_r4(H) set to %04X\n", i8237_r4); + } else { /* low byte */ + i8237_rD++; + i8237_r4 = data & 0xFF; + sim_debug (DEBUG_reg, &isbc208_dev, "i8237_r4(L) set to %04X\n", i8237_r4); + } + return 0; + } +} + +uint8 isbc208_r5(t_bool io, uint8 data) +{ + if (io == 0) { /* read current word count CH 2 */ + if (i8237_rD) { /* high byte */ + i8237_rD = 0; + sim_debug (DEBUG_reg, &isbc208_dev, "i8237_r5(H) read as %04X\n", i8237_r5); + return (i8237_r5 >> 8); + } else { /* low byte */ + i8237_rD++; + sim_debug (DEBUG_reg, &isbc208_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, &isbc208_dev, "i8237_r5(H) set to %04X\n", i8237_r5); + } else { /* low byte */ + i8237_rD++; + i8237_r5 = data & 0xFF; + sim_debug (DEBUG_reg, &isbc208_dev, "i8237_r5(L) set to %04X\n", i8237_r5); + } + return 0; + } +} + +uint8 isbc208_r6(t_bool io, uint8 data) +{ + if (io == 0) { /* read current address CH 3 */ + if (i8237_rD) { /* high byte */ + i8237_rD = 0; + sim_debug (DEBUG_reg, &isbc208_dev, "i8237_r6(H) read as %04X\n", i8237_r6); + return (i8237_r6 >> 8); + } else { /* low byte */ + i8237_rD++; + sim_debug (DEBUG_reg, &isbc208_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, &isbc208_dev, "i8237_r6(H) set to %04X\n", i8237_r6); + } else { /* low byte */ + i8237_rD++; + i8237_r6 = data & 0xFF; + sim_debug (DEBUG_reg, &isbc208_dev, "i8237_r6(L) set to %04X\n", i8237_r6); + } + return 0; + } +} + +uint8 isbc208_r7(t_bool io, uint8 data) +{ + if (io == 0) { /* read current word count CH 3 */ + if (i8237_rD) { /* high byte */ + i8237_rD = 0; + sim_debug (DEBUG_reg, &isbc208_dev, "i8237_r7(H) read as %04X\n", i8237_r7); + return (i8237_r7 >> 8); + } else { /* low byte */ + i8237_rD++; + sim_debug (DEBUG_reg, &isbc208_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, &isbc208_dev, "i8237_r7(H) set to %04X\n", i8237_r7); + } else { /* low byte */ + i8237_rD++; + i8237_r7 = data & 0xFF; + sim_debug (DEBUG_reg, &isbc208_dev, "i8237_r7(L) set to %04X\n", i8237_r7); + } + return 0; + } +} + +uint8 isbc208_r8(t_bool io, uint8 data) +{ + if (io == 0) { /* read status register */ + sim_debug (DEBUG_reg, &isbc208_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, &isbc208_dev, "i8237_r9 (command) set to %02X\n", i8237_r9); + return 0; + } +} + +uint8 isbc208_r9(t_bool io, uint8 data) +{ + if (io == 0) { + sim_debug (DEBUG_reg, &isbc208_dev, "Illegal read of isbc208_r9\n"); + return 0; + } else { /* write request register */ + i8237_rC = data & 0xFF; + sim_debug (DEBUG_reg, &isbc208_dev, "i8237_rC (request) set to %02X\n", i8237_rC); + return 0; + } +} + +uint8 isbc208_rA(t_bool io, uint8 data) +{ + if (io == 0) { + sim_debug (DEBUG_reg, &isbc208_dev, "Illegal read of isbc208_rA\n"); + return 0; + } else { /* write single mask register */ + switch(data & 0x03) { + case 0: + if (data & 0x04) + i8237_rB |= 1; + else + i8237_rB &= ~1; + break; + case 1: + if (data & 0x04) + i8237_rB |= 2; + else + i8237_rB &= ~2; + break; + case 2: + if (data & 0x04) + i8237_rB |= 4; + else + i8237_rB &= ~4; + break; + case 3: + if (data & 0x04) + i8237_rB |= 8; + else + i8237_rB &= ~8; + break; + } + sim_debug (DEBUG_reg, &isbc208_dev, "i8237_rB (mask) set to %02X\n", i8237_rB); + return 0; + } +} + +uint8 isbc208_rB(t_bool io, uint8 data) +{ + if (io == 0) { + sim_debug (DEBUG_reg, &isbc208_dev, "Illegal read of isbc208_rB\n"); + return 0; + } else { /* write mode register */ + i8237_rA = data & 0xFF; + sim_debug (DEBUG_reg, &isbc208_dev, "i8237_rA (mode) set to %02X\n", i8237_rA); + return 0; + } +} + +uint8 isbc208_rC(t_bool io, uint8 data) +{ + if (io == 0) { + sim_debug (DEBUG_reg, &isbc208_dev, "Illegal read of isbc208_rC\n"); + return 0; + } else { /* clear byte pointer FF */ + i8237_rD = 0; + sim_debug (DEBUG_reg, &isbc208_dev, "i8237_rD (FF) cleared\n"); + return 0; + } +} + +uint8 isbc208_rD(t_bool io, uint8 data) +{ + if (io == 0) { /* read temporary register */ + sim_debug (DEBUG_reg, &isbc208_dev, "Illegal read of isbc208_rD\n"); + return 0; + } else { /* master clear */ + isbc208_reset1(); + sim_debug (DEBUG_reg, &isbc208_dev, "i8237 master clear\n"); + return 0; + } +} + +uint8 isbc208_rE(t_bool io, uint8 data) +{ + if (io == 0) { + sim_debug (DEBUG_reg, &isbc208_dev, "Illegal read of isbc208_rE\n"); + return 0; + } else { /* clear mask register */ + i8237_rB = 0; + sim_debug (DEBUG_reg, &isbc208_dev, "i8237_rB (mask) cleared\n"); + return 0; + } +} + +uint8 isbc208_rF(t_bool io, uint8 data) +{ + if (io == 0) { + sim_debug (DEBUG_reg, &isbc208_dev, "Illegal read of isbc208_rF\n"); + return 0; + } else { /* write all mask register bits */ + i8237_rB = data & 0x0F; + sim_debug (DEBUG_reg, &isbc208_dev, "i8237_rB (mask) set to %02X\n", i8237_rB); + return 0; + } +} + +uint8 isbc208_r10(t_bool io, uint8 data) +{ + if (io == 0) { /* read FDC status register */ + sim_debug (DEBUG_reg, &isbc208_dev, "i8272_msr read as %02X\n", i8272_msr); + return i8272_msr; + } else { + sim_debug (DEBUG_reg, &isbc208_dev, "Illegal write to isbc208_r10\n"); + return 0; + } +} + +// read/write FDC data register +uint8 isbc208_r11(t_bool io, uint8 data) +{ + if (io == 0) { /* read FDC data register */ + wsp = 0; /* clear write stack index */ + switch (rsp) { /* read from next stack register */ + case 0: + sim_debug (DEBUG_reg, &isbc208_dev, "i8272_r1 read as %02X\n", i8272_r1); + sim_debug (DEBUG_reg, &isbc208_dev, "i8272_r3 read as %02X\n", i8272_r3); + rsp++; /* step read stack index */ + clr_irq(SBC208_INT); /* clear interrupt */ + if (pcmd == SENDRV) { + i8272_msr = RQM; /* result phase SENDRV done */ + return i8272_r1; // SENDRV return ST1 + } + return i8272_r0; /* ST0 */ + case 1: + sim_debug (DEBUG_reg, &isbc208_dev, "i8272_r2 read as %02X\n", i8272_r2); + rsp++; /* step read stack index */ + if (pcmd == SENINT) { + i8272_msr = RQM; /* result phase SENINT done */ + return cyl; // SENINT return current cylinder + } + return i8272_r1; /* ST1 */ + case 2: + sim_debug (DEBUG_reg, &isbc208_dev, "i8272_r3 read as %02X\n", i8272_r3); + rsp++; /* step read stack index */ + return i8272_r2; /* ST2 */ + case 3: + sim_debug (DEBUG_reg, &isbc208_dev, "i8272_w2 read as %02X\n", i8272_w2); + rsp++; /* step read stack index */ + return i8272_w2; /* C - cylinder */ + case 4: + sim_debug (DEBUG_reg, &isbc208_dev, "i8272_w3 read as %02X\n", i8272_w3); + rsp++; /* step read stack index */ + return i8272_w3; /* H - head */ + case 5: + sim_debug (DEBUG_reg, &isbc208_dev, "i8272_w4 read as %02X\n", i8272_w4); + rsp++; /* step read stack index */ + return i8272_w4; /* R - sector */ + case 6: + sim_debug (DEBUG_reg, &isbc208_dev, "i8272_w5 read as %02X\n", i8272_w5); + i8272_msr = RQM; /* result phase ALL OTHERS done */ + return i8272_w5; /* N - sector size*/ + } + } else { /* write FDC data register */ + rsp = 0; /* clear read stack index */ + switch (wsp) { /* write to next stack register */ + case 0: + i8272_w0 = data; /* rws = MT + MFM + SK + cmd */ + cmd = data & 0x1F; /* save the current command */ + sim_debug (DEBUG_reg, &isbc208_dev, "i8272_w0 set to %02X\n", data); + if (cmd == SENINT) { + i8272_msr = CB; /* command phase SENINT done */ + return 0; + } + wsp++; /* step write stack index */ + break; + case 1: + i8272_w1 = data; /* rws = hed + drv */ + if (cmd != SPEC) + drv = data & 0x03; + sim_debug (DEBUG_reg, &isbc208_dev, "i8272_w1 set to %02X\n", data); + if (cmd == HOME || cmd == SENDRV || cmd == READID) { + i8272_msr = CB + hed + drv; /* command phase HOME, READID and SENDRV done */ + return 0; + } + wsp++; /* step write stack index */ + break; + case 2: + i8272_w2 = data; /* rws = C */ + sim_debug (DEBUG_reg, &isbc208_dev, "i8272_w2 set to %02X\n", data); + if (cmd == SPEC || cmd == SEEK) { + i8272_msr = CB + hed + drv; /* command phase SPECIFY and SEEK done */ + return 0; + } + wsp++; /* step write stack index */ + break; + case 3: + i8272_w3 = data; /* rw = H */ + hed = data; + wsp++; /* step write stack index */ + sim_debug (DEBUG_reg, &isbc208_dev, "i8272_w3 set to %02X\n", data); + break; + case 4: + i8272_w4 = data; /* rw = R */ + sec = data; + wsp++; /* step write stack index */ + sim_debug (DEBUG_reg, &isbc208_dev, "i8272_w4 set to %02X\n", data); + break; + case 5: + i8272_w5 = data; /* rw = N */ + sim_debug (DEBUG_reg, &isbc208_dev, "i8272_w5 set to %02X\n", data); + if (cmd == FMTTRK) { + i8272_msr = CB + hed + drv; /* command phase FMTTRK done */ + return 0; + } + wsp++; /* step write stack index */ + break; + case 6: + i8272_w6 = data; /* rw = last sector number */ + wsp++; /* step write stack index */ + sim_debug (DEBUG_reg, &isbc208_dev, "i8272_w6 set to %02X\n", data); + break; + case 7: + i8272_w7 = data; /* rw = gap length */ + wsp++; /* step write stack index */ + sim_debug (DEBUG_reg, &isbc208_dev, "i8272_w7 set to %02X\n", data); + break; + case 8: + i8272_w8 = data; /* rw = bytes to transfer */ + sim_debug (DEBUG_reg, &isbc208_dev, "i8272_w8 set to %02X\n", data); + if (cmd == READ || cmd == WRITE) + i8272_msr = CB + hed + drv; /* command phase all others done */ + break; + } + } + return 0; +} + +uint8 isbc208_r12(t_bool io, uint8 data) +{ + if (io == 0) { /* read interrupt status */ + sim_debug (DEBUG_reg, &isbc208_dev, "isbc208_r12 read as %02X\n", isbc208_i); + return (isbc208_i); + } else { /* write controller auxillary port */ + isbc208_a = data & 0xFF; + sim_debug (DEBUG_reg, &isbc208_dev, "isbc208_r12 set to %02X\n", isbc208_a); + return 0; + } +} + +uint8 isbc208_r13(t_bool io, uint8 data) +{ + if (io == 0) { + sim_debug (DEBUG_reg, &isbc208_dev, "Illegal read of isbc208_r13\n"); + return 0; + } else { /* reset controller */ + isbc208_reset1(); + sim_debug (DEBUG_reg, &isbc208_dev, "isbc208_r13 controller reset\n"); + return 0; + } +} + +uint8 isbc208_r14(t_bool io, uint8 data) +{ + if (io == 0) { + sim_debug (DEBUG_reg, &isbc208_dev, "Illegal read of isbc208_r14\n"); + return 0; + } else { /* Low-Byte Segment Address Register */ + isbc208_sr = data & 0xFF; + sim_debug (DEBUG_reg, &isbc208_dev, "isbc208_sr(L) set to %02X\n", data & 0xFF); + return 0; + } +} + +uint8 isbc208_r15(t_bool io, uint8 data) +{ + if (io == 0) { + sim_debug (DEBUG_reg, &isbc208_dev, "Illegal read of isbc208_r15\n"); + return 0; + } else { /* High-Byte Segment Address Register */ + isbc208_sr |= data << 8; + sim_debug (DEBUG_reg, &isbc208_dev, "isbc208_sr(H) set to %02X\n", data); + return 0; + } +} + +/* end of isbc208.c */ diff --git a/Intel-Systems/common/multibus.c b/Intel-Systems/common/multibus.c index 9cb937f2..23bb66eb 100644 --- a/Intel-Systems/common/multibus.c +++ b/Intel-Systems/common/multibus.c @@ -1,308 +1,307 @@ -/* multibus.c: Multibus I simulator - - Copyright (c) 2010, William A. Beech - - Permission is hereby granted, free of charge, to any person obtaining a - copy of this software and associated documentation files (the "Software"), - to deal in the Software without restriction, including without limitation - the rights to use, copy, modify, merge, publish, distribute, sublicense, - and/or sell copies of the Software, and to permit persons to whom the - Software is furnished to do so, subject to the following conditions: - - The above copyright notice and this permission notice shall be included in - all copies or substantial portions of the Software. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - WILLIAM A. BEECH BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER - IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - - Except as contained in this notice, the name of William A. Beech shall not be - used in advertising or otherwise to promote the sale, use or other dealings - in this Software without prior written authorization from William A. Beech. - - 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: - - This software was written by Bill Beech, Dec 2010, to allow emulation of Multibus - Computer Systems. - -*/ - -#include "system_defs.h" - -int32 mbirq = 0; /* set no multibus interrupts */ - -/* function prototypes */ - -t_stat multibus_svc(UNIT *uptr); -t_stat multibus_reset(DEVICE *dptr); -void set_irq(int32 int_num); -void clr_irq(int32 int_num); -uint8 nulldev(t_bool io, uint8 data); -uint8 reg_dev(uint8 (*routine)(t_bool io, uint8 data), uint16 port, uint8 devnum); -t_stat multibus_reset (DEVICE *dptr); -uint8 multibus_get_mbyte(uint16 addr); -void multibus_put_mbyte(uint16 addr, uint8 val); - -/* external function prototypes */ - -extern t_stat SBC_reset(DEVICE *dptr); /* reset the iSBC80/10 emulator */ -extern uint8 isbc064_get_mbyte(uint16 addr); -extern void isbc064_put_mbyte(uint16 addr, uint8 val); -extern void set_cpuint(int32 int_num); -extern t_stat SBC_reset (DEVICE *dptr); -extern t_stat isbc064_reset (DEVICE *dptr); -extern t_stat isbc201_reset (DEVICE *dptr, uint16); -extern t_stat isbc202_reset (DEVICE *dptr, uint16); -extern t_stat zx200a_reset(DEVICE *dptr, uint16 base); - -/* external globals */ - -extern uint8 xack; /* XACK signal */ -extern int32 int_req; /* i8080 INT signal */ -extern int32 isbc201_fdcnum; -extern int32 isbc202_fdcnum; -extern int32 zx200a_fdcnum; - -/* multibus Standard SIMH Device Data Structures */ - -UNIT multibus_unit = { - UDATA (&multibus_svc, 0, 0), 20 -}; - -REG multibus_reg[] = { - { HRDATA (MBIRQ, mbirq, 32) }, - { HRDATA (XACK, xack, 8) } -}; - -DEBTAB multibus_debug[] = { - { "ALL", DEBUG_all }, - { "FLOW", DEBUG_flow }, - { "READ", DEBUG_read }, - { "WRITE", DEBUG_write }, - { "LEV1", DEBUG_level1 }, - { "LEV2", DEBUG_level2 }, - { NULL } -}; - -DEVICE multibus_dev = { - "MBIRQ", //name - &multibus_unit, //units - multibus_reg, //registers - NULL, //modifiers - 1, //numunits - 16, //aradix - 16, //awidth - 1, //aincr - 16, //dradix - 8, //dwidth - NULL, //examine - NULL, //deposit - &multibus_reset, //reset - NULL, //boot - NULL, //attach - NULL, //detach - NULL, //ctxt - DEV_DEBUG, //flags - 0, //dctrl - multibus_debug, //debflags - NULL, //msize - NULL //lname -}; - -/* Service routines to handle simulator functions */ - -/* service routine - actually does the simulated interrupts */ - -t_stat multibus_svc(UNIT *uptr) -{ - switch (mbirq) { - case INT_1: - set_cpuint(INT_R); - clr_irq(SBC202_INT); /***** bad, bad, bad! */ -// sim_printf("multibus_svc: mbirq=%04X int_req=%04X\n", mbirq, int_req); - break; - default: -// sim_printf("multibus_svc: default mbirq=%04X\n", mbirq); - break; - } - sim_activate (&multibus_unit, multibus_unit.wait); /* continue poll */ - return SCPE_OK; -} - -/* Reset routine */ - -t_stat multibus_reset(DEVICE *dptr) -{ - SBC_reset(NULL); - sim_printf("Initializing The Multibus\n Multibus Boards:\n"); - isbc064_reset(NULL); - isbc201_fdcnum = 0; - isbc201_reset(NULL, SBC201_BASE); - isbc202_fdcnum = 0; - isbc202_reset(NULL, SBC202_BASE); - zx200a_fdcnum = 0; - zx200a_reset(NULL, ZX200A_BASE_DD); - zx200a_reset(NULL, ZX200A_BASE_SD); - sim_activate (&multibus_unit, multibus_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 256 possible -device addresses, if a device is plugged to a port it's routine -address is here, 'nulldev' means no device has been registered. -*/ -struct idev { - uint8 (*routine)(t_bool io, uint8 data); - uint16 port; - uint8 devnum; -}; - -struct idev dev_table[256] = { -{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 000H */ -{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 004H */ -{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 008H */ -{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 00CH */ -{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 010H */ -{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 014H */ -{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 018H */ -{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 01CH */ -{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 020H */ -{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 024H */ -{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 028H */ -{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 02CH */ -{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 030H */ -{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 034H */ -{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 038H */ -{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 03CH */ -{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 040H */ -{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 044H */ -{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 048H */ -{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 04CH */ -{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 050H */ -{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 054H */ -{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 058H */ -{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 05CH */ -{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 060H */ -{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 064H */ -{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 068H */ -{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 06CH */ -{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 070H */ -{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 074H */ -{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 078H */ -{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 07CH */ -{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 080H */ -{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 084H */ -{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 088H */ -{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 08CH */ -{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 090H */ -{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 094H */ -{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 098H */ -{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 09CH */ -{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 0A0H */ -{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 0A4H */ -{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 0A8H */ -{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 0A0H */ -{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 0B0H */ -{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 0B4H */ -{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 0B8H */ -{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 0B0H */ -{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 0C0H */ -{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 0C4H */ -{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 0C8H */ -{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 0CCH */ -{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 0D0H */ -{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 0D4H */ -{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 0D8H */ -{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 0DCH */ -{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 0E0H */ -{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 0E4H */ -{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 0E8H */ -{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 0ECH */ -{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 0F0H */ -{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 0F4H */ -{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 0F8H */ -{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev} /* 0FCH */ -}; - -//uint8 nulldev(t_bool flag, uint8 data, uint8 devnum) -uint8 nulldev(t_bool flag, uint8 data) -{ - SET_XACK(0); /* set no XACK */ - return 0xFF; -} - -//uint8 reg_dev(uint8 (*routine)(t_bool io, uint8 data, uint8 devnum), uint16 port, uint8 devnum) -uint8 reg_dev(uint8 (*routine)(t_bool io, uint8 data), uint16 port, uint8 devnum) -{ - if (dev_table[port].routine != &nulldev) { /* port already assigned */ - if (dev_table[port].routine != routine) - sim_printf(" I/O Port %04X is already assigned\n", port); - } else { - sim_printf(" Port %04X is assigned to dev %04X\n", port, devnum); - dev_table[port].routine = routine; - dev_table[port].devnum = devnum; - } - return 0; -} - -/* get a byte from memory */ - -uint8 multibus_get_mbyte(uint16 addr) -{ - SET_XACK(0); /* set no XACK */ -// sim_printf("multibus_get_mbyte: Cleared XACK for %04X\n", addr); - return isbc064_get_mbyte(addr); -} - -/* get a word from memory */ - -uint16 multibus_get_mword(uint16 addr) -{ - uint16 val; - - val = multibus_get_mbyte(addr); - val |= (multibus_get_mbyte(addr+1) << 8); - return val; -} - -/* put a byte to memory */ - -void multibus_put_mbyte(uint16 addr, uint8 val) -{ - SET_XACK(0); /* set no XACK */ -// sim_printf("multibus_put_mbyte: Cleared XACK for %04X\n", addr); - isbc064_put_mbyte(addr, val); -// sim_printf("multibus_put_mbyte: Done XACK=%dX\n", XACK); -} - -/* put a word to memory */ - -void multibus_put_mword(uint16 addr, uint16 val) -{ - multibus_put_mbyte(addr, val & 0xff); - multibus_put_mbyte(addr+1, val >> 8); -} - -/* end of multibus.c */ - +/* multibus.c: Multibus I simulator + + Copyright (c) 2010, William A. Beech + + Permission is hereby granted, free of charge, to any person obtaining a + copy of this software and associated documentation files (the "Software"), + to deal in the Software without restriction, including without limitation + the rights to use, copy, modify, merge, publish, distribute, sublicense, + and/or sell copies of the Software, and to permit persons to whom the + Software is furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + WILLIAM A. BEECH BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + Except as contained in this notice, the name of William A. Beech shall not be + used in advertising or otherwise to promote the sale, use or other dealings + in this Software without prior written authorization from William A. Beech. + + 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: + + This software was written by Bill Beech, Dec 2010, to allow emulation of Multibus + Computer Systems. + +*/ + +#include "system_defs.h" + +int32 mbirq = 0; /* set no multibus interrupts */ + +/* function prototypes */ + +t_stat multibus_svc(UNIT *uptr); +t_stat multibus_reset(DEVICE *dptr); +void set_irq(int32 int_num); +void clr_irq(int32 int_num); +uint8 nulldev(t_bool io, uint8 data); +uint8 reg_dev(uint8 (*routine)(t_bool io, uint8 data), uint16 port, uint8 devnum); +t_stat multibus_reset (DEVICE *dptr); +uint8 multibus_get_mbyte(uint16 addr); +void multibus_put_mbyte(uint16 addr, uint8 val); + +/* external function prototypes */ + +extern t_stat SBC_reset(DEVICE *dptr); /* reset the iSBC80/10 emulator */ +extern uint8 isbc064_get_mbyte(uint16 addr); +extern void isbc064_put_mbyte(uint16 addr, uint8 val); +extern void set_cpuint(int32 int_num); +extern t_stat SBC_reset (DEVICE *dptr); +extern t_stat isbc064_reset (DEVICE *dptr); +extern t_stat isbc201_reset (DEVICE *dptr, uint16); +extern t_stat isbc202_reset (DEVICE *dptr, uint16); +extern t_stat zx200a_reset(DEVICE *dptr, uint16 base); + +/* external globals */ + +extern uint8 xack; /* XACK signal */ +extern int32 int_req; /* i8080 INT signal */ +extern int32 isbc201_fdcnum; +extern int32 isbc202_fdcnum; +extern int32 zx200a_fdcnum; + +/* multibus Standard SIMH Device Data Structures */ + +UNIT multibus_unit = { + UDATA (&multibus_svc, 0, 0), 20 +}; + +REG multibus_reg[] = { + { HRDATA (MBIRQ, mbirq, 32) }, + { HRDATA (XACK, xack, 8) } +}; + +DEBTAB multibus_debug[] = { + { "ALL", DEBUG_all }, + { "FLOW", DEBUG_flow }, + { "READ", DEBUG_read }, + { "WRITE", DEBUG_write }, + { "LEV1", DEBUG_level1 }, + { "LEV2", DEBUG_level2 }, + { NULL } +}; + +DEVICE multibus_dev = { + "MBIRQ", //name + &multibus_unit, //units + multibus_reg, //registers + NULL, //modifiers + 1, //numunits + 16, //aradix + 16, //awidth + 1, //aincr + 16, //dradix + 8, //dwidth + NULL, //examine + NULL, //deposit + &multibus_reset, //reset + NULL, //boot + NULL, //attach + NULL, //detach + NULL, //ctxt + DEV_DEBUG, //flags + 0, //dctrl + multibus_debug, //debflags + NULL, //msize + NULL //lname +}; + +/* Service routines to handle simulator functions */ + +/* service routine - actually does the simulated interrupts */ + +t_stat multibus_svc(UNIT *uptr) +{ + switch (mbirq) { + case INT_1: + set_cpuint(INT_R); + clr_irq(SBC202_INT); /***** bad, bad, bad! */ +// sim_printf("multibus_svc: mbirq=%04X int_req=%04X\n", mbirq, int_req); + break; + default: +// sim_printf("multibus_svc: default mbirq=%04X\n", mbirq); + break; + } + sim_activate (&multibus_unit, multibus_unit.wait); /* continue poll */ + return SCPE_OK; +} + +/* Reset routine */ + +t_stat multibus_reset(DEVICE *dptr) +{ + SBC_reset(NULL); + sim_printf("Initializing The Multibus\n Multibus Boards:\n"); + isbc064_reset(NULL); + isbc201_fdcnum = 0; + isbc201_reset(NULL, SBC201_BASE); + isbc202_fdcnum = 0; + isbc202_reset(NULL, SBC202_BASE); + zx200a_fdcnum = 0; + zx200a_reset(NULL, ZX200A_BASE); + sim_activate (&multibus_unit, multibus_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 256 possible +device addresses, if a device is plugged to a port it's routine +address is here, 'nulldev' means no device has been registered. +*/ +struct idev { + uint8 (*routine)(t_bool io, uint8 data); + uint16 port; + uint8 devnum; +}; + +struct idev dev_table[256] = { +{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 000H */ +{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 004H */ +{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 008H */ +{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 00CH */ +{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 010H */ +{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 014H */ +{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 018H */ +{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 01CH */ +{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 020H */ +{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 024H */ +{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 028H */ +{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 02CH */ +{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 030H */ +{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 034H */ +{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 038H */ +{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 03CH */ +{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 040H */ +{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 044H */ +{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 048H */ +{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 04CH */ +{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 050H */ +{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 054H */ +{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 058H */ +{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 05CH */ +{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 060H */ +{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 064H */ +{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 068H */ +{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 06CH */ +{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 070H */ +{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 074H */ +{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 078H */ +{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 07CH */ +{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 080H */ +{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 084H */ +{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 088H */ +{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 08CH */ +{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 090H */ +{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 094H */ +{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 098H */ +{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 09CH */ +{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 0A0H */ +{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 0A4H */ +{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 0A8H */ +{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 0A0H */ +{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 0B0H */ +{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 0B4H */ +{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 0B8H */ +{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 0B0H */ +{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 0C0H */ +{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 0C4H */ +{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 0C8H */ +{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 0CCH */ +{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 0D0H */ +{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 0D4H */ +{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 0D8H */ +{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 0DCH */ +{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 0E0H */ +{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 0E4H */ +{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 0E8H */ +{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 0ECH */ +{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 0F0H */ +{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 0F4H */ +{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 0F8H */ +{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev} /* 0FCH */ +}; + +//uint8 nulldev(t_bool flag, uint8 data, uint8 devnum) +uint8 nulldev(t_bool flag, uint8 data) +{ + SET_XACK(0); /* set no XACK */ + return 0xFF; +} + +//uint8 reg_dev(uint8 (*routine)(t_bool io, uint8 data, uint8 devnum), uint16 port, uint8 devnum) +uint8 reg_dev(uint8 (*routine)(t_bool io, uint8 data), uint16 port, uint8 devnum) +{ + if (dev_table[port].routine != &nulldev) { /* port already assigned */ + if (dev_table[port].routine != routine) + sim_printf(" I/O Port %04X is already assigned\n", port); + } else { + sim_printf(" Port %04X is assigned to dev %04X\n", port, devnum); + dev_table[port].routine = routine; + dev_table[port].devnum = devnum; + } + return 0; +} + +/* get a byte from memory */ + +uint8 multibus_get_mbyte(uint16 addr) +{ + SET_XACK(0); /* set no XACK */ +// sim_printf("multibus_get_mbyte: Cleared XACK for %04X\n", addr); + return isbc064_get_mbyte(addr); +} + +/* get a word from memory */ + +uint16 multibus_get_mword(uint16 addr) +{ + uint16 val; + + val = multibus_get_mbyte(addr); + val |= (multibus_get_mbyte(addr+1) << 8); + return val; +} + +/* put a byte to memory */ + +void multibus_put_mbyte(uint16 addr, uint8 val) +{ + SET_XACK(0); /* set no XACK */ +// sim_printf("multibus_put_mbyte: Cleared XACK for %04X\n", addr); + isbc064_put_mbyte(addr, val); +// sim_printf("multibus_put_mbyte: Done XACK=%dX\n", XACK); +} + +/* put a word to memory */ + +void multibus_put_mword(uint16 addr, uint16 val) +{ + multibus_put_mbyte(addr, val & 0xff); + multibus_put_mbyte(addr+1, val >> 8); +} + +/* end of multibus.c */ + diff --git a/Intel-Systems/common/zx200a.c b/Intel-Systems/common/zx200a.c index 4b3dd720..e9043913 100644 --- a/Intel-Systems/common/zx200a.c +++ b/Intel-Systems/common/zx200a.c @@ -1,759 +1,792 @@ -/* zx-200a.c: Intel double density disk adapter 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: - - 28 Jun 16 - Original file. - - NOTES: - - This controller will mount 4 DD disk images on drives :F0: thru :F3: addressed - at ports 078H to 07FH. It also will mount 2 SD disk images on :F4: and :F5: - addressed at ports 088H to 08FH. These are on physical drives :F0: and :F1:. - - Registers: - - 078H - Read - Subsystem status - bit 0 - ready status of drive 0 - bit 1 - ready status of drive 1 - bit 2 - state of channel's interrupt FF - bit 3 - controller presence indicator - bit 4 - DD controller presence indicator - bit 5 - ready status of drive 2 - bit 6 - ready status of drive 3 - bit 7 - zero - - 079H - Read - Read result type (bits 2-7 are zero) - 00 - I/O complete with error - 01 - Reserved - 10 - Result byte contains diskette ready status - 11 - Reserved - 079H - Write - IOPB address low byte. - - 07AH - Write - IOPB address high byte and start operation. - - 07BH - Read - Read result byte - If result type is 00H - bit 0 - deleted record - bit 1 - CRC error - bit 2 - seek error - bit 3 - address error - bit 4 - data overrun/underrun - bit 5 - write protect - bit 6 - write error - bit 7 - not ready - If result type is 02H - bit 0 - zero - bit 1 - zero - bit 2 - zero - bit 3 - zero - bit 4 - drive 2 ready - bit 5 - drive 3 ready - bit 6 - drive 0 ready - bit 7 - drive 1 ready - - 07FH - Write - Reset diskette system. - - Operations: - NOP - 0x00 - Seek - 0x01 - Format Track - 0x02 - Recalibrate - 0x03 - Read Data - 0x04 - Verify CRC - 0x05 - Write Data - 0x06 - Write Deleted Data - 0x07 - - IOPB - I/O Parameter Block - Byte 0 - Channel Word - bit 3 - data word length (=8-bit, 1=16-bit) - bit 4-5 - interrupt control - 00 - I/O complete interrupt to be issued - 01 - I/O complete interrupts are disabled - 10 - illegal code - 11 - illegal code - bit 6- randon format sequence - - Byte 1 - Diskette Instruction - bit 0-2 - operation code - 000 - no operation - 001 - seek - 010 - format track - 011 - recalibrate - 100 - read data - 101 - verify CRC - 110 - write data - 111 - write deleted data - bit 3 - data word length ( same as byte-0, bit-3) - bit 4-5 - unit select - 00 - drive 0 - 01 - drive 1 - 10 - drive 2 - 11 - drive 3 - bit 6-7 - reserved (zero) - - Byte 2 - Number of Records - - Byte 4 - Track Address - - Byte 5 - Sector Address - - Byte 6 - Buffer Low Address - - Byte 7 - Buffer High Address - - u3 - - u4 - - u5 - - u6 - fdd number. -*/ - -#include "system_defs.h" /* system header in system dir */ - -#define DEBUG 0 - -#define UNIT_V_WPMODE (UNIT_V_UF) /* Write protect */ -#define UNIT_WPMODE (1 << UNIT_V_WPMODE) - -#define FDD_NUM 4 - -//disk controoler operations -#define DNOP 0x00 //disk no operation -#define DSEEK 0x01 //disk seek -#define DFMT 0x02 //disk format -#define DHOME 0x03 //disk home -#define DREAD 0x04 //disk read -#define DVCRC 0x05 //disk verify CRC -#define DWRITE 0x06 //disk write - -//status -#define RDY0 0x01 //FDD 0 ready -#define RDY1 0x02 //FDD 1 ready -#define FDCINT 0x04 //FDC interrupt flag -#define FDCPRE 0x08 //FDC board present -#define FDCDD 0x10 //fdc is DD -#define RDY2 0x20 //FDD 2 ready -#define RDY3 0x40 //FDD 3 ready - -//result type -#define RERR 0x00 //FDC returned error -#define ROK 0x02 //FDC returned ok - -// If result type is RERR then rbyte is -#define RB0DR 0x01 //deleted record -#define RB0CRC 0x02 //CRC error -#define RB0SEK 0x04 //seek error -#define RB0ADR 0x08 //address error -#define RB0OU 0x10 //data overrun/underrun -#define RB0WP 0x20 //write protect -#define RB0WE 0x40 //write error -#define RB0NR 0x80 //not ready - -// If result type is ROK then rbyte is -#define RB1RD2 0x10 //drive 2 ready -#define RB1RD3 0x20 //drive 3 ready -#define RB1RD0 0x40 //drive 0 ready -#define RB1RD1 0x80 //drive 1 ready - -/* external function prototypes */ - -extern uint16 reg_dev(uint8 (*routine)(t_bool, uint8), uint16, uint8); -extern uint8 multibus_get_mbyte(uint16 addr); -extern uint16 multibus_get_mword(uint16 addr); -extern void multibus_put_mbyte(uint16 addr, uint8 val); -extern uint8 multibus_put_mword(uint16 addr, uint16 val); - -/* external globals */ - -extern uint16 port; //port called in dev_table[port] - -/* internal function prototypes */ - -t_stat zx200a_reset(DEVICE *dptr, uint16 base); -void zx200a_reset1(uint8); -t_stat zx200a_attach (UNIT *uptr, CONST char *cptr); -t_stat zx200a_set_mode (UNIT *uptr, int32 val, CONST char *cptr, void *desc); -uint8 zx200a0(t_bool io, uint8 data); -uint8 zx200a1(t_bool io, uint8 data); -uint8 zx200a2(t_bool io, uint8 data); -uint8 zx200a3(t_bool io, uint8 data); -uint8 zx200a7(t_bool io, uint8 data); -void zx200a_diskio(uint8 fdcnum); - -/* globals */ - -int32 zx200a_fdcnum = 0; //actual number of SBC-202 instances + 1 - -typedef struct { //FDD definition - uint8 *buf; - int t0; - int rdy; - uint8 maxsec; - uint8 maxcyl; - } FDDDEF; - -typedef struct { //FDC definition - uint16 baseport; //FDC base port - uint16 iopb; //FDC IOPB - uint8 stat; //FDC status - uint8 rtype; //FDC result type - uint8 rbyte0; //FDC result byte for type 00 - uint8 rbyte1; //FDC result byte for type 10 - uint8 intff; //fdc interrupt FF - FDDDEF fdd[FDD_NUM]; //indexed by the FDD number - } FDCDEF; - -FDCDEF zx200a[4]; //indexed by the isbc-202 instance number - -UNIT zx200a_unit[] = { - { UDATA (0, UNIT_ATTABLE+UNIT_DISABLE, 0), 20 }, - { UDATA (0, UNIT_ATTABLE+UNIT_DISABLE, 0), 20 }, - { UDATA (0, UNIT_ATTABLE+UNIT_DISABLE, 0), 20 }, - { UDATA (0, UNIT_ATTABLE+UNIT_DISABLE, 0), 20 } -}; - -REG zx200a_reg[] = { - { HRDATA (STAT0, zx200a[0].stat, 8) }, /* zx200a 0 status */ - { HRDATA (RTYP0, zx200a[0].rtype, 8) }, /* zx200a 0 result type */ - { HRDATA (RBYT0A, zx200a[0].rbyte0, 8) }, /* zx200a 0 result byte 0 */ - { HRDATA (RBYT0B, zx200a[0].rbyte1, 8) }, /* zx200a 0 result byte 1 */ - { HRDATA (INTFF0, zx200a[0].intff, 8) }, /* zx200a 0 interrupt f/f */ - { HRDATA (STAT1, zx200a[1].stat, 8) }, /* zx200a 1 status */ - { HRDATA (RTYP1, zx200a[1].rtype, 8) }, /* zx200a 1 result type */ - { HRDATA (RBYT1A, zx200a[1].rbyte0, 8) }, /* zx200a 1 result byte 0 */ - { HRDATA (RBYT1B, zx200a[1].rbyte1, 8) }, /* zx200a 1 result byte 1 */ - { HRDATA (INTFF1, zx200a[1].intff, 8) }, /* zx200a 1 interrupt f/f */ - { HRDATA (STAT2, zx200a[2].stat, 8) }, /* zx200a 2 status */ - { HRDATA (RTYP2, zx200a[2].rtype, 8) }, /* zx200a 2 result type */ - { HRDATA (RBYT2A, zx200a[2].rbyte0, 8) }, /* zx200a 2 result byte 0 */ - { HRDATA (RBYT2B, zx200a[0].rbyte1, 8) }, /* zx200a 2 result byte 1 */ - { HRDATA (INTFF2, zx200a[2].intff, 8) }, /* zx200a 2 interrupt f/f */ - { HRDATA (STAT3, zx200a[3].stat, 8) }, /* zx200a 3 status */ - { HRDATA (RTYP3, zx200a[3].rtype, 8) }, /* zx200a 3 result type */ - { HRDATA (RBYT3A, zx200a[3].rbyte0, 8) }, /* zx200a 3 result byte 0 */ - { HRDATA (RBYT3B, zx200a[3].rbyte1, 8) }, /* zx200a 3 result byte 1 */ - { HRDATA (INTFF3, zx200a[0].intff, 8) }, /* zx200a 3 interrupt f/f */ - { NULL } -}; - -MTAB zx200a_mod[] = { - { UNIT_WPMODE, 0, "RW", "RW", &zx200a_set_mode }, - { UNIT_WPMODE, UNIT_WPMODE, "WP", "WP", &zx200a_set_mode }, - { 0 } -}; - -DEBTAB zx200a_debug[] = { - { "ALL", DEBUG_all }, - { "FLOW", DEBUG_flow }, - { "READ", DEBUG_read }, - { "WRITE", DEBUG_write }, - { "XACK", DEBUG_xack }, - { "LEV1", DEBUG_level1 }, - { "LEV2", DEBUG_level2 }, - { NULL } -}; - -/* address width is set to 16 bits to use devices in 8086/8088 implementations */ - -DEVICE zx200a_dev = { - "ZX200A", //name - zx200a_unit, //units - zx200a_reg, //registers - NULL, //modifiers - 1, //numunits - 16, //aradix - 16, //awidth - 1, //aincr - 16, //dradix - 8, //dwidth - NULL, //examine - NULL, //deposit -// &zx200a_reset, //reset - NULL, //reset - NULL, //boot - &zx200a_attach, //attach - NULL, //detach - NULL, //ctxt - DEV_DEBUG+DEV_DISABLE+DEV_DIS, //flags - DEBUG_flow + DEBUG_read + DEBUG_write, //dctrl - zx200a_debug, //debflags - NULL, //msize - NULL //lname -}; - -/* I/O instruction handlers, called from the CPU module when an - IN or OUT instruction is issued. -*/ - -/* Service routines to handle simulator functions */ - -/* Reset routine */ - -t_stat zx200a_reset(DEVICE *dptr, uint16 base) -{ - sim_printf(" ZX-200A FDC Board"); - if (ZX200A_NUM) { - sim_printf(" - Found on Port %02X\n", base); - sim_printf(" ZX200A-%d: Hardware Reset\n", zx200a_fdcnum); - sim_printf(" ZX200A-%d: Registered at %04X\n", zx200a_fdcnum, base); - zx200a[zx200a_fdcnum].baseport = base; - reg_dev(zx200a0, base, zx200a_fdcnum); - reg_dev(zx200a1, base + 1, zx200a_fdcnum); - reg_dev(zx200a2, base + 2, zx200a_fdcnum); - reg_dev(zx200a3, base + 3, zx200a_fdcnum); - reg_dev(zx200a7, base + 7, zx200a_fdcnum); - zx200a_unit[zx200a_fdcnum].u3 = 0x00; /* ipc reset */ - zx200a_reset1(zx200a_fdcnum); - zx200a_fdcnum++; - } else - sim_printf(" - Not Found on Port %02X\n", base); - return SCPE_OK; -} - -void zx200a_reset1(uint8 fdcnum) -{ - int32 i; - UNIT *uptr; - - sim_printf(" ZX-200A-%d: Initializing\n", fdcnum); - zx200a[fdcnum].stat = 0; //clear status - for (i = 0; i < FDD_NUM; i++) { /* handle all units */ - uptr = zx200a_dev.units + i; - zx200a[fdcnum].stat |= FDCPRE | FDCDD; //set the FDC status - zx200a[fdcnum].rtype = ROK; - if (uptr->capac == 0) { /* if not configured */ - uptr->capac = 0; /* initialize unit */ - uptr->u4 = 0; - uptr->u5 = fdcnum; //fdc device number - uptr->u6 = i; /* unit number - only set here! */ - uptr->flags |= UNIT_WPMODE; /* set WP in unit flags */ - sim_printf(" ZX-200A%d: Configured, Status=%02X Not attached\n", i, zx200a[fdcnum].stat); - } else { - switch(i){ - case 0: - zx200a[fdcnum].stat |= RDY0; //set FDD 0 ready - zx200a[fdcnum].rbyte1 |= RB1RD0; - break; - case 1: - zx200a[fdcnum].stat |= RDY1; //set FDD 1 ready - zx200a[fdcnum].rbyte1 |= RB1RD1; - break; - case 2: - zx200a[fdcnum].stat |= RDY2; //set FDD 2 ready - zx200a[fdcnum].rbyte1 |= RB1RD2; - break; - case 3: - zx200a[fdcnum].stat |= RDY3; //set FDD 3 ready - zx200a[fdcnum].rbyte1 |= RB1RD3; - break; - } - sim_printf(" ZX-200A%d: Configured, Status=%02X Attached to %s\n", - i, zx200a[fdcnum].stat, uptr->filename); - } - } -} - -/* zx200a attach - attach an .IMG file to a FDD */ - -t_stat zx200a_attach (UNIT *uptr, CONST char *cptr) -{ - t_stat r; - FILE *fp; - int32 i, c = 0; - long flen; - uint8 fdcnum, fddnum; - - sim_debug (DEBUG_flow, &zx200a_dev, " zx200a_attach: Entered with cptr=%s\n", cptr); - if ((r = attach_unit (uptr, cptr)) != SCPE_OK) { - sim_printf(" zx200a_attach: Attach error\n"); - return r; - } - fdcnum = uptr->u5; - fddnum = uptr->u6; - fp = fopen(uptr->filename, "rb"); - if (fp == NULL) { - sim_printf(" Unable to open disk image file %s\n", uptr->filename); - sim_printf(" No disk image loaded!!!\n"); - } else { - sim_printf("zx200a: Attach\n"); - fseek(fp, 0, SEEK_END); /* size disk image */ - flen = ftell(fp); - fseek(fp, 0, SEEK_SET); - if (zx200a[fdcnum].fdd[fddnum].buf == NULL) { /* no buffer allocated */ - zx200a[fdcnum].fdd[fddnum].buf = (uint8 *)malloc(flen); - if (zx200a[fdcnum].fdd[fddnum].buf == NULL) { - sim_printf(" zx200a_attach: Malloc error\n"); - fclose(fp); - return SCPE_MEM; - } - } - uptr->capac = flen; - i = 0; - c = fgetc(fp); // copy disk image into buffer - while (c != EOF) { - *(zx200a[fdcnum].fdd[fddnum].buf + i++) = c & 0xFF; - c = fgetc(fp); - } - fclose(fp); - switch(fddnum){ - case 0: - zx200a[fdcnum].stat |= RDY0; //set FDD 0 ready - zx200a[fdcnum].rtype = ROK; - zx200a[fdcnum].rbyte1 |= RB1RD0; - break; - case 1: - zx200a[fdcnum].stat |= RDY1; //set FDD 1 ready - zx200a[fdcnum].rtype = ROK; - zx200a[fdcnum].rbyte1 |= RB1RD1; - break; - case 2: - zx200a[fdcnum].stat |= RDY2; //set FDD 2 ready - zx200a[fdcnum].rtype = ROK; - zx200a[fdcnum].rbyte1 |= RB1RD2; - break; - case 3: - zx200a[fdcnum].stat |= RDY3; //set FDD 3 ready - zx200a[fdcnum].rtype = ROK; - zx200a[fdcnum].rbyte1 |= RB1RD3; - break; - } - if (flen == 256256) { /* 8" 256K SSSD */ - zx200a[fdcnum].fdd[fddnum].maxcyl = 77; - zx200a[fdcnum].fdd[fddnum].maxsec = 26; - } - else if (flen == 512512) { /* 8" 512K SSDD */ - zx200a[fdcnum].fdd[fddnum].maxcyl = 77; - zx200a[fdcnum].fdd[fddnum].maxsec = 52; - } else - sim_printf(" ZX-200A-%d: Not a known ISIS-II disk image\n", fdcnum); - sim_printf(" ZX-200A-%d: Configured %d bytes, Attached to %s\n", - fdcnum, uptr->capac, uptr->filename); - } - sim_debug (DEBUG_flow, &zx200a_dev, " ZX-200A_attach: Done\n"); - return SCPE_OK; -} - -/* zx200a set mode = Write protect */ - -t_stat zx200a_set_mode (UNIT *uptr, int32 val, CONST char *cptr, void *desc) -{ -// sim_debug (DEBUG_flow, &zx200a_dev, " zx200a_set_mode: Entered with val=%08XH uptr->flags=%08X\n", -// val, uptr->flags); - if (val & UNIT_WPMODE) { /* write protect */ - uptr->flags |= val; - } else { /* read write */ - uptr->flags &= ~val; - } -// sim_debug (DEBUG_flow, &zx200a_dev, " zx200a_set_mode: Done\n"); - return SCPE_OK; -} - -uint8 zx200_get_dn(void) -{ - int i; - - for (i=0; i= zx200a[i].baseport && port <= zx200a[i].baseport + 7) - return i; - sim_printf("zx200_get_dn: port %04X not in zx200 device table\n", port); - return 0xFF; -} - -/* I/O instruction handlers, called from the CPU module when an - IN or OUT instruction is issued. -*/ - -/* zx200a control port functions */ - -uint8 zx200a0(t_bool io, uint8 data) -{ - uint8 fdcnum; - - if ((fdcnum = zx200_get_dn()) != 0xFF) { - if (io == 0) { /* read ststus*/ -// sim_printf("\n ZX200A-%d: returned status=%02X", fdcnum, zx200a[fdcnum].stat); - return zx200a[fdcnum].stat; - } - } - return 0; -} - -uint8 zx200a1(t_bool io, uint8 data) -{ - uint8 fdcnum; - - if ((fdcnum = zx200_get_dn()) != 0xFF) { - if (io == 0) { /* read operation */ - zx200a[fdcnum].intff = 0; //clear interrupt FF - zx200a[fdcnum].stat &= ~FDCINT; - if (DEBUG) - sim_printf("\n ZX-200A1-%d: returned rtype=%02X intff=%02X status=%02X", - fdcnum, zx200a[fdcnum].rtype, zx200a[fdcnum].intff, zx200a[fdcnum].stat); - return zx200a[fdcnum].rtype; - } else { /* write control port */ - zx200a[fdcnum].iopb = data; - if (DEBUG) - sim_printf("\n ZX-200A1-%d: IOPB low=%02X", fdcnum, data); - } - } - return 0; -} - -uint8 zx200a2(t_bool io, uint8 data) -{ - uint8 fdcnum; - - if ((fdcnum = zx200_get_dn()) != 0xFF) { - if (io == 0) { /* read data port */ - ; - } else { /* write data port */ - zx200a[fdcnum].iopb |= (data << 8); - if (DEBUG) - sim_printf("\n zx200a-%d: IOPB=%04X", fdcnum, zx200a[fdcnum].iopb); - zx200a_diskio(fdcnum); - if (zx200a[fdcnum].intff) - zx200a[fdcnum].stat |= FDCINT; - } - } - return 0; -} - -uint8 zx200a3(t_bool io, uint8 data) -{ - uint8 fdcnum, rslt; - - if ((fdcnum = zx200_get_dn()) != 0xFF) { - if (io == 0) { /* read data port */ - switch(zx200a[fdcnum].rtype) { - case 0x00: - rslt = zx200a[fdcnum].rbyte0; - zx200a[fdcnum].rtype = 0x02; //reset error - break; - case 0x02: - rslt = zx200a[fdcnum].rbyte1; - zx200a[fdcnum].rtype = 0x00; //set error - break; - } - if (DEBUG) - sim_printf("\n zx200a-%d: 0x7B returned rtype=%02X result byte=%02X", - fdcnum, zx200a[fdcnum].rtype, rslt); - return rslt; - } else { /* write data port */ - ; //stop diskette operation - } - } - return 0; -} - -/* reset ZX-200A */ -uint8 zx200a7(t_bool io, uint8 data) -{ - uint8 fdcnum; - - if ((fdcnum = zx200_get_dn()) != 0xFF) { - if (io == 0) { /* read data port */ - ; - } else { /* write data port */ - zx200a_reset1(fdcnum); - } - } - return 0; -} - -// perform the actual disk I/O operation - -void zx200a_diskio(uint8 fdcnum) -{ - uint8 cw, di, nr, ta, sa, data, nrptr, c; - uint16 ba; - uint32 dskoff; - uint8 fddnum, fmtb; - uint32 i; - UNIT *uptr; - FILE *fp; - //parse the IOPB - cw = multibus_get_mbyte(zx200a[fdcnum].iopb); - di = multibus_get_mbyte(zx200a[fdcnum].iopb + 1); - nr = multibus_get_mbyte(zx200a[fdcnum].iopb + 2); - ta = multibus_get_mbyte(zx200a[fdcnum].iopb + 3); - sa = multibus_get_mbyte(zx200a[fdcnum].iopb + 4); - ba = multibus_get_mword(zx200a[fdcnum].iopb + 5); - fddnum = (di & 0x30) >> 4; - uptr = zx200a_dev.units + fddnum; - if (DEBUG) { - sim_printf("\n zx200a-%d: zx200a_diskio IOPB=%04X FDD=%02X STAT=%02X", - fdcnum, zx200a[fdcnum].iopb, fddnum, zx200a[fdcnum].stat); - sim_printf("\n zx200a-%d: cw=%02X di=%02X nr=%02X ta=%02X sa=%02X ba=%04X", - fdcnum, cw, di, nr, ta, sa, ba); - sim_printf("\n zx200a-%d: maxsec=%02X maxcyl=%02X", - fdcnum, zx200a[fdcnum].fdd[fddnum].maxsec, zx200a[fdcnum].fdd[fddnum].maxcyl); - } - //check for not ready - switch(fddnum) { - case 0: - if ((zx200a[fdcnum].stat & RDY0) == 0) { - zx200a[fdcnum].rtype = RERR; - zx200a[fdcnum].rbyte0 = RB0NR; - zx200a[fdcnum].intff = 1; //set interrupt FF - sim_printf("\n zx200a-%d: Ready error on drive %d", fdcnum, fddnum); - return; - } - break; - case 1: - if ((zx200a[fdcnum].stat & RDY1) == 0) { - zx200a[fdcnum].rtype = RERR; - zx200a[fdcnum].rbyte0 = RB0NR; - zx200a[fdcnum].intff = 1; //set interrupt FF - sim_printf("\n zx200a-%d: Ready error on drive %d", fdcnum, fddnum); - return; - } - break; - case 2: - if ((zx200a[fdcnum].stat & RDY2) == 0) { - zx200a[fdcnum].rtype = RERR; - zx200a[fdcnum].rbyte0 = RB0NR; - zx200a[fdcnum].intff = 1; //set interrupt FF - sim_printf("\n zx200a-%d: Ready error on drive %d", fdcnum, fddnum); - return; - } - break; - case 3: - if ((zx200a[fdcnum].stat & RDY3) == 0) { - zx200a[fdcnum].rtype = RERR; - zx200a[fdcnum].rbyte0 = RB0NR; - zx200a[fdcnum].intff = 1; //set interrupt FF - sim_printf("\n zx200a-%d: Ready error on drive %d", fdcnum, fddnum); - return; - } - break; - } - //check for address error - if ( - ((di & 0x07) != 0x03) || - (sa > zx200a[fdcnum].fdd[fddnum].maxsec) || - ((sa + nr) > (zx200a[fdcnum].fdd[fddnum].maxsec + 1)) || - (sa == 0) || - (ta > zx200a[fdcnum].fdd[fddnum].maxcyl) - ) { - if (DEBUG) - sim_printf("\n zx200a-%d: maxsec=%02X maxcyl=%02X", - fdcnum, zx200a[fdcnum].fdd[fddnum].maxsec, zx200a[fdcnum].fdd[fddnum].maxcyl); - zx200a[fdcnum].rtype = RERR; - zx200a[fdcnum].rbyte0 = RB0ADR; - zx200a[fdcnum].intff = 1; //set interrupt FF - sim_printf("\n zx200a-%d: Address error on drive %d", fdcnum, fddnum); - return; - } - switch (di & 0x07) { - case DNOP: - case DSEEK: - case DHOME: - case DVCRC: - zx200a[fdcnum].rtype = ROK; - zx200a[fdcnum].intff = 1; //set interrupt FF - break; - case DFMT: - //check for WP - if(uptr->flags & UNIT_WPMODE) { - zx200a[fdcnum].rtype = RERR; - zx200a[fdcnum].rbyte0 = RB0WP; - zx200a[fdcnum].intff = 1; //set interrupt FF - sim_printf("\n zx200a-%d: Write protect error 1 on drive %d", fdcnum, fddnum); - return; - } - fmtb = multibus_get_mbyte(ba); //get the format byte - //calculate offset into disk image - dskoff = ((ta * (uint32)(zx200a[fdcnum].fdd[fddnum].maxsec)) + (sa - 1)) * 128; - for(i=0; i<=((uint32)(zx200a[fdcnum].fdd[fddnum].maxsec) * 128); i++) { - *(zx200a[fdcnum].fdd[fddnum].buf + (dskoff + i)) = fmtb; - } - //*** quick fix. Needs more thought! - fp = fopen(uptr->filename, "wb"); // write out modified image - for (i=0; icapac; i++) { - c = *(zx200a[fdcnum].fdd[fddnum].buf + i); - fputc(c, fp); - } - fclose(fp); - zx200a[fdcnum].rtype = ROK; - zx200a[fdcnum].intff = 1; //set interrupt FF - break; - case DREAD: - nrptr = 0; - while(nrptr < nr) { - //calculate offset into disk image - dskoff = ((ta * zx200a[fdcnum].fdd[fddnum].maxsec) + (sa - 1)) * 128; -// sim_printf("\n zx200a-%d: cw=%02X di=%02X nr=%02X ta=%02X sa=%02X ba=%04X dskoff=%06X", -// fdcnum, cw, di, nr, ta, sa, ba, dskoff); - for (i=0; i<128; i++) { //copy sector from image to RAM - data = *(zx200a[fdcnum].fdd[fddnum].buf + (dskoff + i)); - multibus_put_mbyte(ba + i, data); - } - sa++; - ba+=0x80; - nrptr++; - } - zx200a[fdcnum].rtype = ROK; - zx200a[fdcnum].intff = 1; //set interrupt FF - break; - case DWRITE: - //check for WP - if(uptr->flags & UNIT_WPMODE) { - zx200a[fdcnum].rtype = RERR; - zx200a[fdcnum].rbyte0 = RB0WP; - zx200a[fdcnum].intff = 1; //set interrupt FF - sim_printf("\n zx200a-%d: Write protect error 2 on drive %d", fdcnum, fddnum); - return; - } - nrptr = 0; - while(nrptr < nr) { - //calculate offset into disk image - dskoff = ((ta * zx200a[fdcnum].fdd[fddnum].maxsec) + (sa - 1)) * 128; - // sim_printf("\n zx200a-%d: cw=%02X di=%02X nr=%02X ta=%02X sa=%02X ba=%04X dskoff=%06X", - // fdcnum, cw, di, nr, ta, sa, ba, dskoff); - for (i=0; i<128; i++) { //copy sector from image to RAM - data = multibus_get_mbyte(ba + i); - *(zx200a[fdcnum].fdd[fddnum].buf + (dskoff + i)) = data; - } - sa++; - ba+=0x80; - nrptr++; - } - //*** quick fix. Needs more thought! - fp = fopen(uptr->filename, "wb"); // write out modified image - for (i=0; icapac; i++) { - c = *(zx200a[fdcnum].fdd[fddnum].buf + i); - fputc(c, fp); - } - fclose(fp); - zx200a[fdcnum].rtype = ROK; - zx200a[fdcnum].intff = 1; //set interrupt FF - break; - default: - sim_printf("\n zx200a-%d: zx200a_diskio bad di=%02X", fdcnum, di & 0x07); - break; - } -} - -/* end of zx-200a.c */ +/* zx-200a.c: Intel double density disk adapter 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: + + 28 Jun 16 - Original file. + + NOTES: + + This controller will mount 4 DD disk images on drives :F0: thru :F3: addressed + at ports 078H to 07FH. It also will mount 2 SD disk images on :F4: and :F5: + addressed at ports 088H to 08FH. These are on physical drives :F0: and :F1:. + + Registers: + + 078H - Read - Subsystem status + bit 0 - ready status of drive 0 + bit 1 - ready status of drive 1 + bit 2 - state of channel's interrupt FF + bit 3 - controller presence indicator + bit 4 - DD controller presence indicator + bit 5 - ready status of drive 2 + bit 6 - ready status of drive 3 + bit 7 - zero + + 079H - Read - Read result type (bits 2-7 are zero) + 00 - I/O complete with error + 01 - Reserved + 10 - Result byte contains diskette ready status + 11 - Reserved + 079H - Write - IOPB address low byte. + + 07AH - Write - IOPB address high byte and start operation. + + 07BH - Read - Read result byte + If result type is 00H + bit 0 - deleted record + bit 1 - CRC error + bit 2 - seek error + bit 3 - address error + bit 4 - data overrun/underrun + bit 5 - write protect + bit 6 - write error + bit 7 - not ready + If result type is 02H and ready has changed + bit 0 - zero + bit 1 - zero + bit 2 - zero + bit 3 - zero + bit 4 - drive 2 ready + bit 5 - drive 3 ready + bit 6 - drive 0 ready + bit 7 - drive 1 ready + else return 0 + + 07FH - Write - Reset diskette system. + + Operations: + NOP - 0x00 + Seek - 0x01 + Format Track - 0x02 + Recalibrate - 0x03 + Read Data - 0x04 + Verify CRC - 0x05 + Write Data - 0x06 + Write Deleted Data - 0x07 + + IOPB - I/O Parameter Block + Byte 0 - Channel Word + bit 3 - data word length (=8-bit, 1=16-bit) + bit 4-5 - interrupt control + 00 - I/O complete interrupt to be issued + 01 - I/O complete interrupts are disabled + 10 - illegal code + 11 - illegal code + bit 6- randon format sequence + + Byte 1 - Diskette Instruction + bit 0-2 - operation code + 000 - no operation + 001 - seek + 010 - format track + 011 - recalibrate + 100 - read data + 101 - verify CRC + 110 - write data + 111 - write deleted data + bit 3 - data word length ( same as byte-0, bit-3) + bit 4-5 - unit select + 00 - drive 0 + 01 - drive 1 + 10 - drive 2 + 11 - drive 3 + bit 6-7 - reserved (zero) + + Byte 2 - Number of Records + + Byte 4 - Track Address + + Byte 5 - Sector Address + + Byte 6 - Buffer Low Address + + Byte 7 - Buffer High Address + + u3 - + u4 - + u5 - fdc number. + u6 - fdd number. + + The ZX-200A appears to the multibus system as if there were an iSBC-201 + installed addressed at 0x88-0x8f and an iSBC-202 installed addressed at + 0x78-0x7F. The DD disks are drive 0 - 3. The SD disks are mapped over + DD disks 0 - 1. Thus drive 0 - 1 can be SD or DD, but not both. Drive + 2 - 3 are always DD. +*/ + +#include "system_defs.h" /* system header in system dir */ + +#define DEBUG 0 + +#define UNIT_V_WPMODE (UNIT_V_UF) /* Write protect */ +#define UNIT_WPMODE (1 << UNIT_V_WPMODE) + +#define FDD_NUM 4 + +//disk controoler operations +#define DNOP 0x00 //disk no operation +#define DSEEK 0x01 //disk seek +#define DFMT 0x02 //disk format +#define DHOME 0x03 //disk home +#define DREAD 0x04 //disk read +#define DVCRC 0x05 //disk verify CRC +#define DWRITE 0x06 //disk write + +//status +#define RDY0 0x01 //FDD 0 ready +#define RDY1 0x02 //FDD 1 ready +#define FDCINT 0x04 //FDC interrupt flag +#define FDCPRE 0x08 //FDC board present +#define FDCDD 0x10 //fdc is DD +#define RDY2 0x20 //FDD 2 ready +#define RDY3 0x40 //FDD 3 ready + +//result type +#define RERR 0x00 //FDC returned error +#define ROK 0x02 //FDC returned ok + +// If result type is RERR then rbyte is +#define RB0DR 0x01 //deleted record +#define RB0CRC 0x02 //CRC error +#define RB0SEK 0x04 //seek error +#define RB0ADR 0x08 //address error +#define RB0OU 0x10 //data overrun/underrun +#define RB0WP 0x20 //write protect +#define RB0WE 0x40 //write error +#define RB0NR 0x80 //not ready + +// If result type is ROK then rbyte is +#define RB1RD2 0x10 //drive 2 ready +#define RB1RD3 0x20 //drive 3 ready +#define RB1RD0 0x40 //drive 0 ready +#define RB1RD1 0x80 //drive 1 ready + +/* external function prototypes */ + +extern uint16 reg_dev(uint8 (*routine)(t_bool, uint8), uint16, uint8); +extern uint8 multibus_get_mbyte(uint16 addr); +extern uint16 multibus_get_mword(uint16 addr); +extern void multibus_put_mbyte(uint16 addr, uint8 val); +extern uint8 multibus_put_mword(uint16 addr, uint16 val); + +/* external globals */ + +extern uint16 port; //port called in dev_table[port] +extern int32 PCX; + +/* internal function prototypes */ + +t_stat zx200a_reset(DEVICE *dptr, uint16 base); +void zx200a_reset1(uint8); +t_stat zx200a_attach (UNIT *uptr, CONST char *cptr); +t_stat zx200a_set_mode (UNIT *uptr, int32 val, CONST char *cptr, void *desc); +uint8 zx200a0(t_bool io, uint8 data); +uint8 zx200a1(t_bool io, uint8 data); +uint8 zx200a2(t_bool io, uint8 data); +uint8 zx200a3(t_bool io, uint8 data); +uint8 zx200a7(t_bool io, uint8 data); +void zx200a_diskio(uint8 fdcnum); + +/* globals */ + +int32 zx200a_fdcnum = 0; //actual number of ZX-200A instances + 1 + +typedef struct { //FDD definition + uint8 *buf; + int t0; + int rdy; + uint8 sec; + uint8 cyl; + uint8 maxsec; + uint8 maxcyl; + } FDDDEF; + +typedef struct { //FDC definition + uint16 baseport; //FDC base port + uint16 iopb; //FDC IOPB + uint8 stat; //FDC status + uint8 rdychg; //FDC ready change + uint8 rtype; //FDC result type + uint8 rbyte0; //FDC result byte for type 00 + uint8 rbyte1; //FDC result byte for type 10 + uint8 intff; //fdc interrupt FF + FDDDEF fdd[FDD_NUM]; //indexed by the FDD number + } FDCDEF; + +FDCDEF zx200a[4]; //indexed by the isbc-202 instance number + +UNIT zx200a_unit[] = { + { UDATA (0, UNIT_ATTABLE+UNIT_DISABLE, 0), 20 }, + { UDATA (0, UNIT_ATTABLE+UNIT_DISABLE, 0), 20 }, + { UDATA (0, UNIT_ATTABLE+UNIT_DISABLE, 0), 20 }, + { UDATA (0, UNIT_ATTABLE+UNIT_DISABLE, 0), 20 } +}; + +REG zx200a_reg[] = { + { HRDATA (STAT0, zx200a[0].stat, 8) }, /* zx200a 0 status */ + { HRDATA (RTYP0, zx200a[0].rtype, 8) }, /* zx200a 0 result type */ + { HRDATA (RBYT0A, zx200a[0].rbyte0, 8) }, /* zx200a 0 result byte 0 */ + { HRDATA (RBYT0B, zx200a[0].rbyte1, 8) }, /* zx200a 0 result byte 1 */ + { HRDATA (INTFF0, zx200a[0].intff, 8) }, /* zx200a 0 interrupt f/f */ + { HRDATA (STAT1, zx200a[1].stat, 8) }, /* zx200a 1 status */ + { HRDATA (RTYP1, zx200a[1].rtype, 8) }, /* zx200a 1 result type */ + { HRDATA (RBYT1A, zx200a[1].rbyte0, 8) }, /* zx200a 1 result byte 0 */ + { HRDATA (RBYT1B, zx200a[1].rbyte1, 8) }, /* zx200a 1 result byte 1 */ + { HRDATA (INTFF1, zx200a[1].intff, 8) }, /* zx200a 1 interrupt f/f */ + { HRDATA (STAT2, zx200a[2].stat, 8) }, /* zx200a 2 status */ + { HRDATA (RTYP2, zx200a[2].rtype, 8) }, /* zx200a 2 result type */ + { HRDATA (RBYT2A, zx200a[2].rbyte0, 8) }, /* zx200a 2 result byte 0 */ + { HRDATA (RBYT2B, zx200a[0].rbyte1, 8) }, /* zx200a 2 result byte 1 */ + { HRDATA (INTFF2, zx200a[2].intff, 8) }, /* zx200a 2 interrupt f/f */ + { HRDATA (STAT3, zx200a[3].stat, 8) }, /* zx200a 3 status */ + { HRDATA (RTYP3, zx200a[3].rtype, 8) }, /* zx200a 3 result type */ + { HRDATA (RBYT3A, zx200a[3].rbyte0, 8) }, /* zx200a 3 result byte 0 */ + { HRDATA (RBYT3B, zx200a[3].rbyte1, 8) }, /* zx200a 3 result byte 1 */ + { HRDATA (INTFF3, zx200a[0].intff, 8) }, /* zx200a 3 interrupt f/f */ + { NULL } +}; + +MTAB zx200a_mod[] = { + { UNIT_WPMODE, 0, "RW", "RW", &zx200a_set_mode }, + { UNIT_WPMODE, UNIT_WPMODE, "WP", "WP", &zx200a_set_mode }, + { 0 } +}; + +DEBTAB zx200a_debug[] = { + { "ALL", DEBUG_all }, + { "FLOW", DEBUG_flow }, + { "READ", DEBUG_read }, + { "WRITE", DEBUG_write }, + { "XACK", DEBUG_xack }, + { "LEV1", DEBUG_level1 }, + { "LEV2", DEBUG_level2 }, + { NULL } +}; + +/* address width is set to 16 bits to use devices in 8086/8088 implementations */ + +DEVICE zx200a_dev = { + "ZX200A", //name + zx200a_unit, //units + zx200a_reg, //registers + zx200a_mod, //modifiers + FDD_NUM, //numunits + 16, //aradix + 16, //awidth + 1, //aincr + 16, //dradix + 8, //dwidth + NULL, //examine + NULL, //deposit + NULL, //reset + NULL, //boot + &zx200a_attach, //attach + NULL, //detach + NULL, //ctxt + DEV_DEBUG+DEV_DISABLE+DEV_DIS, //flags + DEBUG_flow + DEBUG_read + DEBUG_write, //dctrl + zx200a_debug, //debflags + NULL, //msize + NULL //lname +}; + +/* I/O instruction handlers, called from the CPU module when an + IN or OUT instruction is issued. +*/ + +/* Service routines to handle simulator functions */ + +/* Reset routine */ + +t_stat zx200a_reset(DEVICE *dptr, uint16 base) +{ + sim_printf(" ZX-200A FDC Board"); + if (ZX200A_NUM) { + sim_printf(" - Found on Port %02X\n", base); + sim_printf(" ZX200A-%d: Hardware Reset\n", zx200a_fdcnum); + sim_printf(" ZX200A-%d: Registered at %04X\n", zx200a_fdcnum, base); + zx200a[zx200a_fdcnum].baseport = base; + reg_dev(zx200a0, base, zx200a_fdcnum); + reg_dev(zx200a1, base + 1, zx200a_fdcnum); + reg_dev(zx200a2, base + 2, zx200a_fdcnum); + reg_dev(zx200a3, base + 3, zx200a_fdcnum); + reg_dev(zx200a7, base + 7, zx200a_fdcnum); + reg_dev(zx200a0, base+16, zx200a_fdcnum); + reg_dev(zx200a1, base+16 + 1, zx200a_fdcnum); + reg_dev(zx200a2, base+16 + 2, zx200a_fdcnum); + reg_dev(zx200a3, base+16 + 3, zx200a_fdcnum); + reg_dev(zx200a7, base+16 + 7, zx200a_fdcnum); + zx200a_reset1(zx200a_fdcnum); + zx200a_fdcnum++; + } else + sim_printf(" - Not Found on Port %02X\n", base); + return SCPE_OK; +} +/* Software reset routine */ + +void zx200a_reset1(uint8 fdcnum) +{ + int32 i; + UNIT *uptr; + + sim_printf(" ZX-200A-%d: Initializing\n", fdcnum); + zx200a[fdcnum].stat = 0; //clear status + for (i = 0; i < FDD_NUM; i++) { /* handle all units */ + uptr = zx200a_dev.units + i; + zx200a[fdcnum].stat |= FDCPRE | FDCDD; //set the FDC status + zx200a[fdcnum].rtype = ROK; + if (uptr->capac == 0) { /* if not configured */ + uptr->u5 = fdcnum; //fdc device number + uptr->u6 = i; /* unit number - only set here! */ + uptr->flags |= UNIT_WPMODE; /* set WP in unit flags */ + sim_printf(" ZX-200A%d: Configured, Status=%02X Not attached\n", i, zx200a[fdcnum].stat); + } else { + switch(i){ + case 0: + zx200a[fdcnum].stat |= RDY0; //set FDD 0 ready + zx200a[fdcnum].rbyte1 |= RB1RD0; + zx200a[fdcnum].rdychg = 0; + break; + case 1: + zx200a[fdcnum].stat |= RDY1; //set FDD 1 ready + zx200a[fdcnum].rbyte1 |= RB1RD1; + zx200a[fdcnum].rdychg = 0; + break; + case 2: + zx200a[fdcnum].stat |= RDY2; //set FDD 2 ready + zx200a[fdcnum].rbyte1 |= RB1RD2; + zx200a[fdcnum].rdychg = 0; + break; + case 3: + zx200a[fdcnum].stat |= RDY3; //set FDD 3 ready + zx200a[fdcnum].rbyte1 |= RB1RD3; + zx200a[fdcnum].rdychg = 0; + break; + } + sim_printf(" ZX-200A%d: Configured, Status=%02X Attached to %s\n", + i, zx200a[fdcnum].stat, uptr->filename); + } + } +} + +/* zx200a attach - attach an .IMG file to a FDD */ + +t_stat zx200a_attach (UNIT *uptr, CONST char *cptr) +{ + t_stat r; + FILE *fp; + int32 i, c = 0; + long flen; + uint8 fdcnum, fddnum; + + sim_debug (DEBUG_flow, &zx200a_dev, " zx200a_attach: Entered with cptr=%s\n", cptr); + if ((r = attach_unit (uptr, cptr)) != SCPE_OK) { + sim_printf(" zx200a_attach: Attach error\n"); + return r; + } + fdcnum = uptr->u5; + fddnum = uptr->u6; + fp = fopen(uptr->filename, "rb"); + if (fp == NULL) { + sim_printf(" Unable to open disk image file %s\n", uptr->filename); + sim_printf(" No disk image loaded!!!\n"); + } else { + sim_printf("zx200a: Attach\n"); + fseek(fp, 0, SEEK_END); /* size disk image */ + flen = ftell(fp); + fseek(fp, 0, SEEK_SET); + if (flen == -1) { + sim_printf(" zx200a_attach: File error\n"); + return SCPE_IOERR; + } + if (zx200a[fdcnum].fdd[fddnum].buf == NULL) { /* no buffer allocated */ + zx200a[fdcnum].fdd[fddnum].buf = (uint8 *)malloc(flen); + if (zx200a[fdcnum].fdd[fddnum].buf == NULL) { + sim_printf(" zx200a_attach: Malloc error\n"); + return SCPE_MEM; + } + } + uptr->capac = flen; + i = 0; + c = fgetc(fp); // copy disk image into buffer + while (c != EOF) { + *(zx200a[fdcnum].fdd[fddnum].buf + i++) = c & 0xFF; + c = fgetc(fp); + } + fclose(fp); + switch(fddnum){ + case 0: + zx200a[fdcnum].stat |= RDY0; //set FDD 0 ready + zx200a[fdcnum].rtype = ROK; + zx200a[fdcnum].rbyte1 |= RB1RD0; + break; + case 1: + zx200a[fdcnum].stat |= RDY1; //set FDD 1 ready + zx200a[fdcnum].rtype = ROK; + zx200a[fdcnum].rbyte1 |= RB1RD1; + break; + case 2: + zx200a[fdcnum].stat |= RDY2; //set FDD 2 ready + zx200a[fdcnum].rtype = ROK; + zx200a[fdcnum].rbyte1 |= RB1RD2; + break; + case 3: + zx200a[fdcnum].stat |= RDY3; //set FDD 3 ready + zx200a[fdcnum].rtype = ROK; + zx200a[fdcnum].rbyte1 |= RB1RD3; + break; + } + if (flen == 256256) { /* 8" 256K SSSD */ + zx200a[fdcnum].fdd[fddnum].maxcyl = 77; + zx200a[fdcnum].fdd[fddnum].maxsec = 26; + zx200a[fdcnum].fdd[fddnum].sec = 1; + zx200a[fdcnum].fdd[fddnum].cyl = 0; + } + else if (flen == 512512) { /* 8" 512K SSDD */ + zx200a[fdcnum].fdd[fddnum].maxcyl = 77; + zx200a[fdcnum].fdd[fddnum].maxsec = 52; + zx200a[fdcnum].fdd[fddnum].sec = 1; + zx200a[fdcnum].fdd[fddnum].cyl = 0; + } else + sim_printf(" ZX-200A-%d: Not a known disk image\n", fdcnum); + sim_printf(" ZX-200A-%d: Configured %d bytes, Attached to %s\n", + fdcnum, uptr->capac, uptr->filename); + } + sim_debug (DEBUG_flow, &zx200a_dev, " ZX-200A_attach: Done\n"); + return SCPE_OK; +} + +/* zx200a set mode = Write protect */ + +t_stat zx200a_set_mode (UNIT *uptr, int32 val, CONST char *cptr, void *desc) +{ +// sim_debug (DEBUG_flow, &zx200a_dev, " zx200a_set_mode: Entered with val=%08XH uptr->flags=%08X\n", +// val, uptr->flags); + if (val & UNIT_WPMODE) { /* write protect */ + uptr->flags |= val; + } else { /* read write */ + uptr->flags &= ~val; + } +// sim_debug (DEBUG_flow, &zx200a_dev, " zx200a_set_mode: Done\n"); + return SCPE_OK; +} + +uint8 zx200_get_dn(void) +{ + int i; + + for (i=0; i= zx200a[i].baseport && port <= zx200a[i].baseport + 7) || + (port >= zx200a[i].baseport+16 && port <= zx200a[i].baseport+16 + 7)) + return i; + sim_printf("zx200_get_dn: port %04X not in zx200 device table\n", port); + return 0xFF; +} + +/* I/O instruction handlers, called from the CPU module when an + IN or OUT instruction is issued. +*/ + +/* zx200a control port functions */ + +uint8 zx200a0(t_bool io, uint8 data) +{ + uint8 fdcnum; + + if ((fdcnum = zx200_get_dn()) != 0xFF) { + if (io == 0) { /* read ststus*/ + if (DEBUG) + sim_printf("\n zx-200a0-%d: 0x78/88 returned status=%02X PCX=%04X", + fdcnum, zx200a[fdcnum].stat, PCX); + return zx200a[fdcnum].stat; + } + } + return 0; +} + +uint8 zx200a1(t_bool io, uint8 data) +{ + uint8 fdcnum; + + if ((fdcnum = zx200_get_dn()) != 0xFF) { + if (io == 0) { /* read operation */ + zx200a[fdcnum].intff = 0; //clear interrupt FF + zx200a[fdcnum].stat &= ~FDCINT; + if (DEBUG) + sim_printf("\n zx-200a1-%d: 0x79/89 returned rtype=%02X intff=%02X status=%02X PCX=%04X", + fdcnum, zx200a[fdcnum].rtype, zx200a[fdcnum].intff, zx200a[fdcnum].stat, PCX); + return zx200a[fdcnum].rtype; + } else { /* write control port */ + zx200a[fdcnum].iopb = data; + if (DEBUG) + sim_printf("\n zx-200a1-%d: 0x79/88 IOPB low=%02X PCX=%04X", + fdcnum, data, PCX); + } + } + return 0; +} + +uint8 zx200a2(t_bool io, uint8 data) +{ + uint8 fdcnum; + + if ((fdcnum = zx200_get_dn()) != 0xFF) { + if (io == 0) { /* read data port */ + ; + } else { /* write data port */ + zx200a[fdcnum].iopb |= (data << 8); + if (DEBUG) + sim_printf("\n zx-200a2-%d: 0x7A/8A IOPB=%04X PCX=%04X", + fdcnum, zx200a[fdcnum].iopb, PCX); + zx200a_diskio(fdcnum); + if (zx200a[fdcnum].intff) + zx200a[fdcnum].stat |= FDCINT; + } + } + return 0; +} + +uint8 zx200a3(t_bool io, uint8 data) +{ + uint8 fdcnum; + + if ((fdcnum = zx200_get_dn()) != 0xFF) { + if (io == 0) { /* read data port */ + if (zx200a[fdcnum].rtype == 0) { + if (DEBUG) + sim_printf("\n zx200a3-%d: 0x7B/8B returned rbyte0=%02X PCX=%04X", + fdcnum, zx200a[fdcnum].rbyte0, PCX); + return zx200a[fdcnum].rbyte0; + } else { + if (zx200a[fdcnum].rdychg) { + if (DEBUG) + sim_printf("\n zx200a3-%d: 0x7B/8B returned rbyte1=%02X PCX=%04X", + fdcnum, zx200a[fdcnum].rbyte1, PCX); + return zx200a[fdcnum].rbyte1; + } else { + if (DEBUG) + sim_printf("\n zx200a3-%d: 0x7B/8B returned rbytex=%02X PCX=%04X", + fdcnum, 0, PCX); + return 0; + } + } + } else { /* write data port */ + ; //stop diskette operation + } + } + return 0; +} + +/* reset ZX-200A */ +uint8 zx200a7(t_bool io, uint8 data) +{ + uint8 fdcnum; + + if ((fdcnum = zx200_get_dn()) != 0xFF) { + if (io == 0) { /* read data port */ + ; + } else { /* write data port */ + zx200a_reset1(fdcnum); + } + } + return 0; +} + +// perform the actual disk I/O operation + +void zx200a_diskio(uint8 fdcnum) +{ + uint8 cw, di, nr, ta, sa, data, nrptr, c; + uint16 ba; + uint32 dskoff; + uint8 fddnum, fmtb; + uint32 i; + UNIT *uptr; + FILE *fp; + //parse the IOPB + cw = multibus_get_mbyte(zx200a[fdcnum].iopb); + di = multibus_get_mbyte(zx200a[fdcnum].iopb + 1); + nr = multibus_get_mbyte(zx200a[fdcnum].iopb + 2); + ta = multibus_get_mbyte(zx200a[fdcnum].iopb + 3); + sa = multibus_get_mbyte(zx200a[fdcnum].iopb + 4); + ba = multibus_get_mword(zx200a[fdcnum].iopb + 5); + fddnum = (di & 0x30) >> 4; + uptr = zx200a_dev.units + fddnum; + if (DEBUG) { + sim_printf("\n zx200a-%d: zx200a_diskio IOPB=%04X FDD=%02X STAT=%02X", + fdcnum, zx200a[fdcnum].iopb, fddnum, zx200a[fdcnum].stat); + sim_printf("\n zx200a-%d: cw=%02X di=%02X nr=%02X ta=%02X sa=%02X ba=%04X", + fdcnum, cw, di, nr, ta, sa, ba); +// sim_printf("\n zx200a-%d: maxsec=%02X maxcyl=%02X", +// fdcnum, zx200a[fdcnum].fdd[fddnum].maxsec, zx200a[fdcnum].fdd[fddnum].maxcyl); + } + //check for not ready + switch(fddnum) { + case 0: + if ((zx200a[fdcnum].stat & RDY0) == 0) { + zx200a[fdcnum].rtype = RERR; + zx200a[fdcnum].rbyte0 = RB0NR; + zx200a[fdcnum].intff = 1; //set interrupt FF + sim_printf("\n zx200a-%d: Ready error on drive %d", fdcnum, fddnum); + return; + } + break; + case 1: + if ((zx200a[fdcnum].stat & RDY1) == 0) { + zx200a[fdcnum].rtype = RERR; + zx200a[fdcnum].rbyte0 = RB0NR; + zx200a[fdcnum].intff = 1; //set interrupt FF + sim_printf("\n zx200a-%d: Ready error on drive %d", fdcnum, fddnum); + return; + } + break; + case 2: + if ((zx200a[fdcnum].stat & RDY2) == 0) { + zx200a[fdcnum].rtype = RERR; + zx200a[fdcnum].rbyte0 = RB0NR; + zx200a[fdcnum].intff = 1; //set interrupt FF + sim_printf("\n zx200a-%d: Ready error on drive %d", fdcnum, fddnum); + return; + } + break; + case 3: + if ((zx200a[fdcnum].stat & RDY3) == 0) { + zx200a[fdcnum].rtype = RERR; + zx200a[fdcnum].rbyte0 = RB0NR; + zx200a[fdcnum].intff = 1; //set interrupt FF + sim_printf("\n zx200a-%d: Ready error on drive %d", fdcnum, fddnum); + return; + } + break; + } + //check for address error + if ( + ((di & 0x07) != 0x03) && ( + (sa > zx200a[fdcnum].fdd[fddnum].maxsec) || + ((sa + nr) > (zx200a[fdcnum].fdd[fddnum].maxsec + 1)) || + (sa == 0) || + (ta > zx200a[fdcnum].fdd[fddnum].maxcyl) + )) { + if (DEBUG) + sim_printf("\n zx200a-%d: maxsec=%02X maxcyl=%02X", + fdcnum, zx200a[fdcnum].fdd[fddnum].maxsec, zx200a[fdcnum].fdd[fddnum].maxcyl); + zx200a[fdcnum].rtype = RERR; + zx200a[fdcnum].rbyte0 = RB0ADR; + zx200a[fdcnum].intff = 1; //set interrupt FF + sim_printf("\n zx200a-%d: Address error on drive %d", fdcnum, fddnum); + return; + } + switch (di & 0x07) { + case DNOP: + case DSEEK: + case DHOME: + case DVCRC: + zx200a[fdcnum].rtype = ROK; + zx200a[fdcnum].intff = 1; //set interrupt FF + break; + case DFMT: + //check for WP + if(uptr->flags & UNIT_WPMODE) { + zx200a[fdcnum].rtype = RERR; + zx200a[fdcnum].rbyte0 = RB0WP; + zx200a[fdcnum].intff = 1; //set interrupt FF + sim_printf("\n zx200a-%d: Write protect error 1 on drive %d", fdcnum, fddnum); + return; + } + fmtb = multibus_get_mbyte(ba); //get the format byte + //calculate offset into disk image + dskoff = ((ta * (uint32)(zx200a[fdcnum].fdd[fddnum].maxsec)) + (sa - 1)) * 128; + for(i=0; i<=((uint32)(zx200a[fdcnum].fdd[fddnum].maxsec) * 128); i++) { + *(zx200a[fdcnum].fdd[fddnum].buf + (dskoff + i)) = fmtb; + } + //*** quick fix. Needs more thought! + fp = fopen(uptr->filename, "wb"); // write out modified image + for (i=0; icapac; i++) { + c = *(zx200a[fdcnum].fdd[fddnum].buf + i); + fputc(c, fp); + } + fclose(fp); + zx200a[fdcnum].rtype = ROK; + zx200a[fdcnum].intff = 1; //set interrupt FF + break; + case DREAD: + nrptr = 0; + while(nrptr < nr) { + //calculate offset into disk image + dskoff = ((ta * zx200a[fdcnum].fdd[fddnum].maxsec) + (sa - 1)) * 128; +// sim_printf("\n zx200a-%d: cw=%02X di=%02X nr=%02X ta=%02X sa=%02X ba=%04X dskoff=%06X", +// fdcnum, cw, di, nr, ta, sa, ba, dskoff); + for (i=0; i<128; i++) { //copy sector from image to RAM + data = *(zx200a[fdcnum].fdd[fddnum].buf + (dskoff + i)); + multibus_put_mbyte(ba + i, data); + } + sa++; + ba+=0x80; + nrptr++; + } + zx200a[fdcnum].rtype = ROK; + zx200a[fdcnum].intff = 1; //set interrupt FF + break; + case DWRITE: + //check for WP + if(uptr->flags & UNIT_WPMODE) { + zx200a[fdcnum].rtype = RERR; + zx200a[fdcnum].rbyte0 = RB0WP; + zx200a[fdcnum].intff = 1; //set interrupt FF + sim_printf("\n zx200a-%d: Write protect error 2 on drive %d", fdcnum, fddnum); + return; + } + nrptr = 0; + while(nrptr < nr) { + //calculate offset into disk image + dskoff = ((ta * zx200a[fdcnum].fdd[fddnum].maxsec) + (sa - 1)) * 128; + // sim_printf("\n zx200a-%d: cw=%02X di=%02X nr=%02X ta=%02X sa=%02X ba=%04X dskoff=%06X", + // fdcnum, cw, di, nr, ta, sa, ba, dskoff); + for (i=0; i<128; i++) { //copy sector from image to RAM + data = multibus_get_mbyte(ba + i); + *(zx200a[fdcnum].fdd[fddnum].buf + (dskoff + i)) = data; + } + sa++; + ba+=0x80; + nrptr++; + } + //*** quick fix. Needs more thought! + fp = fopen(uptr->filename, "wb"); // write out modified image + for (i=0; icapac; i++) { + c = *(zx200a[fdcnum].fdd[fddnum].buf + i); + fputc(c, fp); + } + fclose(fp); + zx200a[fdcnum].rtype = ROK; + zx200a[fdcnum].intff = 1; //set interrupt FF + break; + default: + sim_printf("\n zx200a-%d: zx200a_diskio bad di=%02X", fdcnum, di & 0x07); + break; + } +} + +/* end of zx-200a.c */ diff --git a/Intel-Systems/isys8010/system_defs.h b/Intel-Systems/isys8010/system_defs.h index b70d65f5..5a4a4ae4 100644 --- a/Intel-Systems/isys8010/system_defs.h +++ b/Intel-Systems/isys8010/system_defs.h @@ -1,130 +1,130 @@ -/* system_defs.h: Intel iSBC simulator definitions - - Copyright (c) 2010, William A. Beech - - Permission is hereby granted, free of charge, to any person obtaining a - copy of this software and associated documentation files (the "Software"), - to deal in the Software without restriction, including without limitation - the rights to use, copy, modify, merge, publish, distribute, sublicense, - and/or sell copies of the Software, and to permit persons to whom the - Software is furnished to do so, subject to the following conditions: - - The above copyright notice and this permission notice shall be included in - all copies or substantial portions of the Software. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - William A. Beech BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER - IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - - Except as contained in this notice, the name of William A. Beech shall not be - used in advertising or otherwise to promote the sale, use or other dealings - in this Software without prior written authorization from William A. Beech. - - ?? ??? 10 - Original file. -*/ - -#include -#include -#include "sim_defs.h" /* simulator defns */ - -#define SET_XACK(VAL) (xack = VAL) - -//chip definitions for the iSBC-80/10 -/* set the base I/O address and device count for the 8251s */ -#define I8251_BASE 0xEC -#define I8251_NUM 1 - -/* set the base I/O address and device count for the 8255s */ -#define I8255_BASE_0 0xE4 -#define I8255_BASE_1 0xE8 -#define I8255_NUM 2 - -/* set the base and size for the EPROM on the iSBC 80/10 */ -#define ROM_BASE 0x0000 -#define ROM_SIZE 0x1000 -#define ROM_DISABLE 1 - -/* set the base and size for the RAM on the iSBC 80/10 */ -#define RAM_BASE 0x3C00 -#define RAM_SIZE 0x0400 -#define RAM_DISABLE 1 - -/* set INTR for CPU on the iSBC 80/10 */ -#define INTR INT_1 - -//board definitions for the multibus -/* set the base I/O address for the iSBC 201 */ -#define SBC201_BASE 0x78 -#define SBC201_INT INT_1 -#define SBC201_NUM 0 - -/* set the base I/O address for the iSBC 202 */ -#define SBC202_BASE 0x78 -#define SBC202_INT INT_1 -#define SBC202_NUM 1 - -/* set the base I/O address for the iSBC 208 */ -#define SBC208_BASE 0x40 -#define SBC208_INT INT_1 -#define SBC208_NUM 0 - -/* set the base for the zx-200a disk controller */ -#define ZX200A_BASE_DD 0x78 -#define ZX200A_BASE_SD 0x88 -#define ZX200A_NUM 0 - -/* set the base and size for the iSBC 064 */ -#define SBC064_BASE 0x0000 -#define SBC064_SIZE 0x10000 -#define SBC064_NUM 1 - -/* multibus interrupt definitions */ - -#define INT_0 0x01 -#define INT_1 0x02 -#define INT_2 0x04 -#define INT_3 0x08 -#define INT_4 0x10 -#define INT_5 0x20 -#define INT_6 0x40 -#define INT_7 0x80 - -/* CPU interrupts definitions */ - -#define INT_R 0x200 -#define I75 0x40 -#define I65 0x20 -#define I55 0x10 - -/* Memory */ - -#define MAXMEMSIZE 0x10000 /* 8080 max memory size */ -#define MEMSIZE (i8080_unit.capac) /* 8080 actual memory size */ -#define ADDRMASK (MAXMEMSIZE - 1) /* 8080 address mask */ -#define MEM_ADDR_OK(x) (((uint32) (x)) < MEMSIZE) - -/* debug definitions */ - -#define DEBUG_flow 0x0001 -#define DEBUG_read 0x0002 -#define DEBUG_write 0x0004 -#define DEBUG_level1 0x0008 -#define DEBUG_level2 0x0010 -#define DEBUG_reg 0x0020 -#define DEBUG_asm 0x0040 -#define DEBUG_xack 0x0080 -#define DEBUG_all 0xFFFF - -/* Simulator stop codes */ - -#define STOP_RSRV 1 /* must be 1 */ -#define STOP_HALT 2 /* HALT */ -#define STOP_IBKPT 3 /* breakpoint */ -#define STOP_OPCODE 4 /* Invalid Opcode */ -#define STOP_IO 5 /* I/O error */ -#define STOP_MEM 6 /* Memory error */ -#define STOP_XACK 7 /* XACK error */ - +/* system_defs.h: Intel iSBC simulator definitions + + Copyright (c) 2010, William A. Beech + + Permission is hereby granted, free of charge, to any person obtaining a + copy of this software and associated documentation files (the "Software"), + to deal in the Software without restriction, including without limitation + the rights to use, copy, modify, merge, publish, distribute, sublicense, + and/or sell copies of the Software, and to permit persons to whom the + Software is furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + William A. Beech BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + Except as contained in this notice, the name of William A. Beech shall not be + used in advertising or otherwise to promote the sale, use or other dealings + in this Software without prior written authorization from William A. Beech. + + ?? ??? 10 - Original file. +*/ + +#include +#include +#include "sim_defs.h" /* simulator defns */ + +#define SET_XACK(VAL) (xack = VAL) + +//chip definitions for the iSBC-80/10 +/* set the base I/O address and device count for the 8251s */ +#define I8251_BASE 0xEC +#define I8251_NUM 1 + +/* set the base I/O address and device count for the 8255s */ +#define I8255_BASE_0 0xE4 +#define I8255_BASE_1 0xE8 +#define I8255_NUM 2 + +/* set the base and size for the EPROM on the iSBC 80/10 */ +#define ROM_BASE 0x0000 +#define ROM_SIZE 0x1000 +#define ROM_DISABLE 1 + +/* set the base and size for the RAM on the iSBC 80/10 */ +#define RAM_BASE 0x3C00 +#define RAM_SIZE 0x0400 +#define RAM_DISABLE 1 + +/* set INTR for CPU on the iSBC 80/10 */ +#define INTR INT_1 + +//board definitions for the multibus +/* set the base I/O address for the iSBC 201 */ +#define SBC201_BASE 0x88 +#define SBC201_INT INT_1 +#define SBC201_NUM 1 + +/* set the base I/O address for the iSBC 202 */ +#define SBC202_BASE 0x78 +#define SBC202_INT INT_1 +#define SBC202_NUM 1 + +/* set the base I/O address for the iSBC 208 */ +#define SBC208_BASE 0x40 +#define SBC208_INT INT_1 +#define SBC208_NUM 0 + +/* set the base for the zx-200a disk controller */ +#define ZX200A_BASE 0x78 +#define ZX200A_INT INT_1 +#define ZX200A_NUM 0 + +/* set the base and size for the iSBC 064 */ +#define SBC064_BASE 0x0000 +#define SBC064_SIZE 0x10000 +#define SBC064_NUM 1 + +/* multibus interrupt definitions */ + +#define INT_0 0x01 +#define INT_1 0x02 +#define INT_2 0x04 +#define INT_3 0x08 +#define INT_4 0x10 +#define INT_5 0x20 +#define INT_6 0x40 +#define INT_7 0x80 + +/* CPU interrupts definitions */ + +#define INT_R 0x200 +#define I75 0x40 +#define I65 0x20 +#define I55 0x10 + +/* Memory */ + +#define MAXMEMSIZE 0x10000 /* 8080 max memory size */ +#define MEMSIZE (i8080_unit.capac) /* 8080 actual memory size */ +#define ADDRMASK (MAXMEMSIZE - 1) /* 8080 address mask */ +#define MEM_ADDR_OK(x) (((uint32) (x)) < MEMSIZE) + +/* debug definitions */ + +#define DEBUG_flow 0x0001 +#define DEBUG_read 0x0002 +#define DEBUG_write 0x0004 +#define DEBUG_level1 0x0008 +#define DEBUG_level2 0x0010 +#define DEBUG_reg 0x0020 +#define DEBUG_asm 0x0040 +#define DEBUG_xack 0x0080 +#define DEBUG_all 0xFFFF + +/* Simulator stop codes */ + +#define STOP_RSRV 1 /* must be 1 */ +#define STOP_HALT 2 /* HALT */ +#define STOP_IBKPT 3 /* breakpoint */ +#define STOP_OPCODE 4 /* Invalid Opcode */ +#define STOP_IO 5 /* I/O error */ +#define STOP_MEM 6 /* Memory error */ +#define STOP_XACK 7 /* XACK error */ + diff --git a/Intel-Systems/isys8020/system_defs.h b/Intel-Systems/isys8020/system_defs.h index ce8734d1..db0c9780 100644 --- a/Intel-Systems/isys8020/system_defs.h +++ b/Intel-Systems/isys8020/system_defs.h @@ -1,134 +1,134 @@ -/* system_defs.h: Intel iSBC simulator definitions - - Copyright (c) 2010, William A. Beech - - Permission is hereby granted, free of charge, to any person obtaining a - copy of this software and associated documentation files (the "Software"), - to deal in the Software without restriction, including without limitation - the rights to use, copy, modify, merge, publish, distribute, sublicense, - and/or sell copies of the Software, and to permit persons to whom the - Software is furnished to do so, subject to the following conditions: - - The above copyright notice and this permission notice shall be included in - all copies or substantial portions of the Software. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - William A. Beech BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER - IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - - Except as contained in this notice, the name of William A. Beech shall not be - used in advertising or otherwise to promote the sale, use or other dealings - in this Software without prior written authorization from William A. Beech. - - ?? ??? 10 - Original file. -*/ - -#include -#include -#include "sim_defs.h" /* simulator defns */ - -#define SET_XACK(VAL) (xack = VAL) - -//chip definitions for the iSBC-80/20 -/* set the base I/O address for the 8251 */ -#define I8251_BASE 0xEC -#define I8251_NUM 1 - -/* set the base I/O address for the 8255 */ -#define I8255_BASE_0 0xE4 -#define I8255_BASE_1 0xE8 -#define I8255_NUM 2 - -/* set the base I/O address for the 8259 */ -#define I8259_BASE 0xD8 -#define I8259_NUM 1 - -/* set the base and size for the EPROM on the iSBC 80/20 */ -#define ROM_BASE 0x0000 -#define ROM_SIZE 0x1000 -#define ROM_DISABLE 1 - -/* set the base and size for the RAM on the iSBC 80/20 */ -#define RAM_BASE 0x3C00 -#define RAM_SIZE 0x0400 -#define RAM_DISABLE 1 - -/* set INTR for CPU */ -#define INTR INT_1 - -//board definitions for the multibus -/* set the base I/O address for the iSBC 201 */ -#define SBC201_BASE 0x78 -#define SBC201_INT INT_1 -#define SBC201_NUM 0 - -/* set the base I/O address for the iSBC 202 */ -#define SBC202_BASE 0x78 -#define SBC202_INT INT_1 -#define SBC202_NUM 1 - -/* set the base I/O address for the iSBC 208 */ -#define SBC208_BASE 0x40 -#define SBC208_INT INT_1 -#define SBC208_NUM 0 - -/* set the base for the zx-200a disk controller */ -#define ZX200A_BASE_DD 0x78 -#define ZX200A_BASE_SD 0x88 -#define ZX200A_NUM 0 - -/* set the base and size for the iSBC 064 */ -#define SBC064_BASE 0x0000 -#define SBC064_SIZE 0x10000 -#define SBC064_NUM 1 - -/* multibus interrupt definitions */ - -#define INT_0 0x01 -#define INT_1 0x02 -#define INT_2 0x04 -#define INT_3 0x08 -#define INT_4 0x10 -#define INT_5 0x20 -#define INT_6 0x40 -#define INT_7 0x80 - -/* CPU interrupts definitions */ - -#define INT_R 0x200 -#define I75 0x40 -#define I65 0x20 -#define I55 0x10 - -/* Memory */ - -#define MAXMEMSIZE 0x10000 /* 8080 max memory size */ -#define MEMSIZE (i8080_unit.capac) /* 8080 actual memory size */ -#define ADDRMASK (MAXMEMSIZE - 1) /* 8080 address mask */ -#define MEM_ADDR_OK(x) (((uint32) (x)) < MEMSIZE) - -/* debug definitions */ - -#define DEBUG_flow 0x0001 -#define DEBUG_read 0x0002 -#define DEBUG_write 0x0004 -#define DEBUG_level1 0x0008 -#define DEBUG_level2 0x0010 -#define DEBUG_reg 0x0020 -#define DEBUG_asm 0x0040 -#define DEBUG_xack 0x0080 -#define DEBUG_all 0xFFFF - -/* Simulator stop codes */ - -#define STOP_RSRV 1 /* must be 1 */ -#define STOP_HALT 2 /* HALT */ -#define STOP_IBKPT 3 /* breakpoint */ -#define STOP_OPCODE 4 /* Invalid Opcode */ -#define STOP_IO 5 /* I/O error */ -#define STOP_MEM 6 /* Memory error */ -#define STOP_XACK 7 /* XACK error */ - +/* system_defs.h: Intel iSBC simulator definitions + + Copyright (c) 2010, William A. Beech + + Permission is hereby granted, free of charge, to any person obtaining a + copy of this software and associated documentation files (the "Software"), + to deal in the Software without restriction, including without limitation + the rights to use, copy, modify, merge, publish, distribute, sublicense, + and/or sell copies of the Software, and to permit persons to whom the + Software is furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + William A. Beech BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + Except as contained in this notice, the name of William A. Beech shall not be + used in advertising or otherwise to promote the sale, use or other dealings + in this Software without prior written authorization from William A. Beech. + + ?? ??? 10 - Original file. +*/ + +#include +#include +#include "sim_defs.h" /* simulator defns */ + +#define SET_XACK(VAL) (xack = VAL) + +//chip definitions for the iSBC-80/20 +/* set the base I/O address for the 8251 */ +#define I8251_BASE 0xEC +#define I8251_NUM 1 + +/* set the base I/O address for the 8255 */ +#define I8255_BASE_0 0xE4 +#define I8255_BASE_1 0xE8 +#define I8255_NUM 2 + +/* set the base I/O address for the 8259 */ +#define I8259_BASE 0xD8 +#define I8259_NUM 1 + +/* set the base and size for the EPROM on the iSBC 80/20 */ +#define ROM_BASE 0x0000 +#define ROM_SIZE 0x1000 +#define ROM_DISABLE 1 + +/* set the base and size for the RAM on the iSBC 80/20 */ +#define RAM_BASE 0x3C00 +#define RAM_SIZE 0x0400 +#define RAM_DISABLE 1 + +/* set INTR for CPU */ +#define INTR INT_1 + +//board definitions for the multibus +/* set the base I/O address for the iSBC 201 */ +#define SBC201_BASE 0x78 +#define SBC201_INT INT_1 +#define SBC201_NUM 0 + +/* set the base I/O address for the iSBC 202 */ +#define SBC202_BASE 0x78 +#define SBC202_INT INT_1 +#define SBC202_NUM 1 + +/* set the base I/O address for the iSBC 208 */ +#define SBC208_BASE 0x40 +#define SBC208_INT INT_1 +#define SBC208_NUM 0 + +/* set the base for the zx-200a disk controller */ +#define ZX200A_BASE 0x78 +#define ZX200A_INT INT_1 +#define ZX200A_NUM 0 + +/* set the base and size for the iSBC 064 */ +#define SBC064_BASE 0x0000 +#define SBC064_SIZE 0x10000 +#define SBC064_NUM 1 + +/* multibus interrupt definitions */ + +#define INT_0 0x01 +#define INT_1 0x02 +#define INT_2 0x04 +#define INT_3 0x08 +#define INT_4 0x10 +#define INT_5 0x20 +#define INT_6 0x40 +#define INT_7 0x80 + +/* CPU interrupts definitions */ + +#define INT_R 0x200 +#define I75 0x40 +#define I65 0x20 +#define I55 0x10 + +/* Memory */ + +#define MAXMEMSIZE 0x10000 /* 8080 max memory size */ +#define MEMSIZE (i8080_unit.capac) /* 8080 actual memory size */ +#define ADDRMASK (MAXMEMSIZE - 1) /* 8080 address mask */ +#define MEM_ADDR_OK(x) (((uint32) (x)) < MEMSIZE) + +/* debug definitions */ + +#define DEBUG_flow 0x0001 +#define DEBUG_read 0x0002 +#define DEBUG_write 0x0004 +#define DEBUG_level1 0x0008 +#define DEBUG_level2 0x0010 +#define DEBUG_reg 0x0020 +#define DEBUG_asm 0x0040 +#define DEBUG_xack 0x0080 +#define DEBUG_all 0xFFFF + +/* Simulator stop codes */ + +#define STOP_RSRV 1 /* must be 1 */ +#define STOP_HALT 2 /* HALT */ +#define STOP_IBKPT 3 /* breakpoint */ +#define STOP_OPCODE 4 /* Invalid Opcode */ +#define STOP_IO 5 /* I/O error */ +#define STOP_MEM 6 /* Memory error */ +#define STOP_XACK 7 /* XACK error */ + diff --git a/Intel-Systems/isys8024/system_defs.h b/Intel-Systems/isys8024/system_defs.h index 1a6a2354..ce59c90d 100644 --- a/Intel-Systems/isys8024/system_defs.h +++ b/Intel-Systems/isys8024/system_defs.h @@ -1,138 +1,138 @@ -/* system_defs.h: Intel iSBC simulator definitions - - Copyright (c) 2010, William A. Beech - - Permission is hereby granted, free of charge, to any person obtaining a - copy of this software and associated documentation files (the "Software"), - to deal in the Software without restriction, including without limitation - the rights to use, copy, modify, merge, publish, distribute, sublicense, - and/or sell copies of the Software, and to permit persons to whom the - Software is furnished to do so, subject to the following conditions: - - The above copyright notice and this permission notice shall be included in - all copies or substantial portions of the Software. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - William A. Beech BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER - IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - - Except as contained in this notice, the name of William A. Beech shall not be - used in advertising or otherwise to promote the sale, use or other dealings - in this Software without prior written authorization from William A. Beech. - - ?? ??? 10 - Original file. -*/ - -#include -#include -#include "sim_defs.h" /* simulator defns */ - -#define SET_XACK(VAL) (xack = VAL) - -//chip definitions for the iSBC-80/10 -/* set the base I/O address and device count for the 8251s */ -#define I8251_BASE 0xEC -#define I8251_NUM 1 - -/* set the base I/O address for the 8253/8254 */ -#define I8253_BASE 0xDC -#define I8253_NUM 1 - -/* set the base I/O address and device count for the 8255s */ -#define I8255_BASE_0 0xE4 -#define I8255_BASE_1 0xE8 -#define I8255_NUM 2 - -/* set the base I/O address for the 8259 */ -#define I8259_BASE 0xDA -#define I8259_NUM 1 - -/* set the base and size for the EPROM on the iSBC 80/10 */ -#define ROM_BASE 0x0000 -#define ROM_SIZE 0x1000 -#define ROM_DISABLE 1 - -/* set the base and size for the RAM on the iSBC 80/10 */ -#define RAM_BASE 0xF000 -#define RAM_SIZE 0x1000 -#define RAM_DISABLE 0 - -/* set INTR for CPU on the iSBC 80/10 */ -#define INTR INT_1 - -//board definitions for the multibus -/* set the base I/O address for the iSBC 201 */ -#define SBC201_BASE 0x78 -#define SBC201_INT INT_1 -#define SBC201_NUM 0 - -/* set the base I/O address for the iSBC 202 */ -#define SBC202_BASE 0x78 -#define SBC202_INT INT_1 -#define SBC202_NUM 1 - -/* set the base for the zx-200a disk controller */ -#define ZX200A_BASE_DD 0x78 -#define ZX200A_BASE_SD 0x88 -#define ZX200A_NUM 0 - -/* set the base I/O address for the iSBC 208 */ -#define SBC208_BASE 0x40 -#define SBC208_INT INT_1 -#define SBC208_NUM 0 - -/* set the base and size for the iSBC 064 */ -#define SBC064_BASE 0x0000 -#define SBC064_SIZE 0x10000 -#define SBC064_NUM 1 - -/* multibus interrupt definitions */ - -#define INT_0 0x01 -#define INT_1 0x02 -#define INT_2 0x04 -#define INT_3 0x08 -#define INT_4 0x10 -#define INT_5 0x20 -#define INT_6 0x40 -#define INT_7 0x80 - -/* CPU interrupts definitions */ - -#define INT_R 0x200 -#define I75 0x40 -#define I65 0x20 -#define I55 0x10 - -/* Memory */ - -#define MAXMEMSIZE 0x10000 /* 8080 max memory size */ -#define MEMSIZE (i8080_unit.capac) /* 8080 actual memory size */ -#define ADDRMASK (MAXMEMSIZE - 1) /* 8080 address mask */ -#define MEM_ADDR_OK(x) (((uint32) (x)) < MEMSIZE) - -/* debug definitions */ - -#define DEBUG_flow 0x0001 -#define DEBUG_read 0x0002 -#define DEBUG_write 0x0004 -#define DEBUG_level1 0x0008 -#define DEBUG_level2 0x0010 -#define DEBUG_reg 0x0020 -#define DEBUG_asm 0x0040 -#define DEBUG_xack 0x0080 -#define DEBUG_all 0xFFFF - -/* Simulator stop codes */ - -#define STOP_RSRV 1 /* must be 1 */ -#define STOP_HALT 2 /* HALT */ -#define STOP_IBKPT 3 /* breakpoint */ -#define STOP_OPCODE 4 /* Invalid Opcode */ -#define STOP_IO 5 /* I/O error */ -#define STOP_MEM 6 /* Memory error */ -#define STOP_XACK 7 /* XACK error */ - +/* system_defs.h: Intel iSBC simulator definitions + + Copyright (c) 2010, William A. Beech + + Permission is hereby granted, free of charge, to any person obtaining a + copy of this software and associated documentation files (the "Software"), + to deal in the Software without restriction, including without limitation + the rights to use, copy, modify, merge, publish, distribute, sublicense, + and/or sell copies of the Software, and to permit persons to whom the + Software is furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + William A. Beech BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + Except as contained in this notice, the name of William A. Beech shall not be + used in advertising or otherwise to promote the sale, use or other dealings + in this Software without prior written authorization from William A. Beech. + + ?? ??? 10 - Original file. +*/ + +#include +#include +#include "sim_defs.h" /* simulator defns */ + +#define SET_XACK(VAL) (xack = VAL) + +//chip definitions for the iSBC-80/10 +/* set the base I/O address and device count for the 8251s */ +#define I8251_BASE 0xEC +#define I8251_NUM 1 + +/* set the base I/O address for the 8253/8254 */ +#define I8253_BASE 0xDC +#define I8253_NUM 1 + +/* set the base I/O address and device count for the 8255s */ +#define I8255_BASE_0 0xE4 +#define I8255_BASE_1 0xE8 +#define I8255_NUM 2 + +/* set the base I/O address for the 8259 */ +#define I8259_BASE 0xDA +#define I8259_NUM 1 + +/* set the base and size for the EPROM on the iSBC 80/10 */ +#define ROM_BASE 0x0000 +#define ROM_SIZE 0x1000 +#define ROM_DISABLE 1 + +/* set the base and size for the RAM on the iSBC 80/10 */ +#define RAM_BASE 0xF000 +#define RAM_SIZE 0x1000 +#define RAM_DISABLE 0 + +/* set INTR for CPU on the iSBC 80/10 */ +#define INTR INT_1 + +//board definitions for the multibus +/* set the base I/O address for the iSBC 201 */ +#define SBC201_BASE 0x78 +#define SBC201_INT INT_1 +#define SBC201_NUM 0 + +/* set the base I/O address for the iSBC 202 */ +#define SBC202_BASE 0x78 +#define SBC202_INT INT_1 +#define SBC202_NUM 1 + +/* set the base for the zx-200a disk controller */ +#define ZX200A_BASE 0x78 +#define ZX200A_INT INT_1 +#define ZX200A_NUM 0 + +/* set the base I/O address for the iSBC 208 */ +#define SBC208_BASE 0x40 +#define SBC208_INT INT_1 +#define SBC208_NUM 0 + +/* set the base and size for the iSBC 064 */ +#define SBC064_BASE 0x0000 +#define SBC064_SIZE 0x10000 +#define SBC064_NUM 1 + +/* multibus interrupt definitions */ + +#define INT_0 0x01 +#define INT_1 0x02 +#define INT_2 0x04 +#define INT_3 0x08 +#define INT_4 0x10 +#define INT_5 0x20 +#define INT_6 0x40 +#define INT_7 0x80 + +/* CPU interrupts definitions */ + +#define INT_R 0x200 +#define I75 0x40 +#define I65 0x20 +#define I55 0x10 + +/* Memory */ + +#define MAXMEMSIZE 0x10000 /* 8080 max memory size */ +#define MEMSIZE (i8080_unit.capac) /* 8080 actual memory size */ +#define ADDRMASK (MAXMEMSIZE - 1) /* 8080 address mask */ +#define MEM_ADDR_OK(x) (((uint32) (x)) < MEMSIZE) + +/* debug definitions */ + +#define DEBUG_flow 0x0001 +#define DEBUG_read 0x0002 +#define DEBUG_write 0x0004 +#define DEBUG_level1 0x0008 +#define DEBUG_level2 0x0010 +#define DEBUG_reg 0x0020 +#define DEBUG_asm 0x0040 +#define DEBUG_xack 0x0080 +#define DEBUG_all 0xFFFF + +/* Simulator stop codes */ + +#define STOP_RSRV 1 /* must be 1 */ +#define STOP_HALT 2 /* HALT */ +#define STOP_IBKPT 3 /* breakpoint */ +#define STOP_OPCODE 4 /* Invalid Opcode */ +#define STOP_IO 5 /* I/O error */ +#define STOP_MEM 6 /* Memory error */ +#define STOP_XACK 7 /* XACK error */ + diff --git a/Intel-Systems/isys8030/system_defs.h b/Intel-Systems/isys8030/system_defs.h index 56a5acf1..c6256ac5 100644 --- a/Intel-Systems/isys8030/system_defs.h +++ b/Intel-Systems/isys8030/system_defs.h @@ -1,141 +1,141 @@ -/* system_defs.h: Intel iSBC simulator definitions - - Copyright (c) 2010, William A. Beech - - Permission is hereby granted, free of charge, to any person obtaining a - copy of this software and associated documentation files (the "Software"), - to deal in the Software without restriction, including without limitation - the rights to use, copy, modify, merge, publish, distribute, sublicense, - and/or sell copies of the Software, and to permit persons to whom the - Software is furnished to do so, subject to the following conditions: - - The above copyright notice and this permission notice shall be included in - all copies or substantial portions of the Software. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - William A. Beech BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER - IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - - Except as contained in this notice, the name of William A. Beech shall not be - used in advertising or otherwise to promote the sale, use or other dealings - in this Software without prior written authorization from William A. Beech. - - ?? ??? 10 - Original file. -*/ - -#include -#include -#include "sim_defs.h" /* simulator defns */ - -#define SET_XACK(VAL) (xack = VAL) - -//chip definitions for the iSBC-80/30 -/* set the base I/O address for the 8253/8254 */ -#define I8041_BASE 0xDC -#define I8041_NUM 1 - -/* set the base I/O address and device count for the 8251s */ -#define I8251_BASE 0xEC -#define I8251_NUM 1 - -/* set the base I/O address for the 8253/8254 */ -#define I8253_BASE 0xDC -#define I8253_NUM 1 - -/* set the base I/O address and device count for the 8255s */ -#define I8255_BASE 0xE8 -#define I8255_NUM 1 - -/* set the base I/O address for the 8259 */ -#define I8259_BASE 0xDA -#define I8259_NUM 1 - -/* set the base and size for the EPROM on the iSBC 80/30 */ -#define ROM_BASE 0x0000 -#define ROM_SIZE 0x1000 -#define ROM_DISABLE 1 - -/* set the base and size for the RAM on the iSBC 80/30 */ -#define RAM_BASE 0xF000 -#define RAM_SIZE 0x1000 -#define RAM_DISABLE 0 - -/* set INTR for CPU on the iSBC 80/30 */ -#define INTR INT_1 - -//board definitions for the multibus -/* set the base I/O address for the iSBC 201 */ -#define SBC201_BASE 0x78 -#define SBC201_INT INT_1 -#define SBC201_NUM 0 - -/* set the base I/O address for the iSBC 202 */ -#define SBC202_BASE 0x78 -#define SBC202_INT INT_1 -#define SBC202_NUM 1 - -/* set the base for the zx-200a disk controller */ -#define ZX200A_BASE_DD 0x78 -#define ZX200A_BASE_SD 0x88 -#define ZX200A_NUM 0 - -/* set the base I/O address for the iSBC 208 */ -#define SBC208_BASE 0x40 -#define SBC208_INT INT_1 -#define SBC208_NUM 0 - -/* set the base and size for the iSBC 064 */ -#define SBC064_BASE 0x0000 -#define SBC064_SIZE 0x10000 -#define SBC064_NUM 1 - -/* multibus interrupt definitions */ - -#define INT_0 0x01 -#define INT_1 0x02 -#define INT_2 0x04 -#define INT_3 0x08 -#define INT_4 0x10 -#define INT_5 0x20 -#define INT_6 0x40 -#define INT_7 0x80 - -/* CPU interrupts definitions */ - -#define INT_R 0x200 -#define I75 0x40 -#define I65 0x20 -#define I55 0x10 - -/* Memory */ - -#define MAXMEMSIZE 0x10000 /* 8080 max memory size */ -#define MEMSIZE (i8080_unit.capac) /* 8080 actual memory size */ -#define ADDRMASK (MAXMEMSIZE - 1) /* 8080 address mask */ -#define MEM_ADDR_OK(x) (((uint32) (x)) < MEMSIZE) - -/* debug definitions */ - -#define DEBUG_flow 0x0001 -#define DEBUG_read 0x0002 -#define DEBUG_write 0x0004 -#define DEBUG_level1 0x0008 -#define DEBUG_level2 0x0010 -#define DEBUG_reg 0x0020 -#define DEBUG_asm 0x0040 -#define DEBUG_xack 0x0080 -#define DEBUG_all 0xFFFF - -/* Simulator stop codes */ - -#define STOP_RSRV 1 /* must be 1 */ -#define STOP_HALT 2 /* HALT */ -#define STOP_IBKPT 3 /* breakpoint */ -#define STOP_OPCODE 4 /* Invalid Opcode */ -#define STOP_IO 5 /* I/O error */ -#define STOP_MEM 6 /* Memory error */ -#define STOP_XACK 7 /* XACK error */ - +/* system_defs.h: Intel iSBC simulator definitions + + Copyright (c) 2010, William A. Beech + + Permission is hereby granted, free of charge, to any person obtaining a + copy of this software and associated documentation files (the "Software"), + to deal in the Software without restriction, including without limitation + the rights to use, copy, modify, merge, publish, distribute, sublicense, + and/or sell copies of the Software, and to permit persons to whom the + Software is furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + William A. Beech BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + Except as contained in this notice, the name of William A. Beech shall not be + used in advertising or otherwise to promote the sale, use or other dealings + in this Software without prior written authorization from William A. Beech. + + ?? ??? 10 - Original file. +*/ + +#include +#include +#include "sim_defs.h" /* simulator defns */ + +#define SET_XACK(VAL) (xack = VAL) + +//chip definitions for the iSBC-80/30 +/* set the base I/O address for the 8253/8254 */ +#define I8041_BASE 0xDC +#define I8041_NUM 1 + +/* set the base I/O address and device count for the 8251s */ +#define I8251_BASE 0xEC +#define I8251_NUM 1 + +/* set the base I/O address for the 8253/8254 */ +#define I8253_BASE 0xDC +#define I8253_NUM 1 + +/* set the base I/O address and device count for the 8255s */ +#define I8255_BASE 0xE8 +#define I8255_NUM 1 + +/* set the base I/O address for the 8259 */ +#define I8259_BASE 0xDA +#define I8259_NUM 1 + +/* set the base and size for the EPROM on the iSBC 80/30 */ +#define ROM_BASE 0x0000 +#define ROM_SIZE 0x1000 +#define ROM_DISABLE 1 + +/* set the base and size for the RAM on the iSBC 80/30 */ +#define RAM_BASE 0xF000 +#define RAM_SIZE 0x1000 +#define RAM_DISABLE 0 + +/* set INTR for CPU on the iSBC 80/30 */ +#define INTR INT_1 + +//board definitions for the multibus +/* set the base I/O address for the iSBC 201 */ +#define SBC201_BASE 0x78 +#define SBC201_INT INT_1 +#define SBC201_NUM 0 + +/* set the base I/O address for the iSBC 202 */ +#define SBC202_BASE 0x78 +#define SBC202_INT INT_1 +#define SBC202_NUM 1 + +/* set the base for the zx-200a disk controller */ +#define ZX200A_BASE 0x78 +#define ZX200A_INT INT_1 +#define ZX200A_NUM 0 + +/* set the base I/O address for the iSBC 208 */ +#define SBC208_BASE 0x40 +#define SBC208_INT INT_1 +#define SBC208_NUM 0 + +/* set the base and size for the iSBC 064 */ +#define SBC064_BASE 0x0000 +#define SBC064_SIZE 0x10000 +#define SBC064_NUM 1 + +/* multibus interrupt definitions */ + +#define INT_0 0x01 +#define INT_1 0x02 +#define INT_2 0x04 +#define INT_3 0x08 +#define INT_4 0x10 +#define INT_5 0x20 +#define INT_6 0x40 +#define INT_7 0x80 + +/* CPU interrupts definitions */ + +#define INT_R 0x200 +#define I75 0x40 +#define I65 0x20 +#define I55 0x10 + +/* Memory */ + +#define MAXMEMSIZE 0x10000 /* 8080 max memory size */ +#define MEMSIZE (i8080_unit.capac) /* 8080 actual memory size */ +#define ADDRMASK (MAXMEMSIZE - 1) /* 8080 address mask */ +#define MEM_ADDR_OK(x) (((uint32) (x)) < MEMSIZE) + +/* debug definitions */ + +#define DEBUG_flow 0x0001 +#define DEBUG_read 0x0002 +#define DEBUG_write 0x0004 +#define DEBUG_level1 0x0008 +#define DEBUG_level2 0x0010 +#define DEBUG_reg 0x0020 +#define DEBUG_asm 0x0040 +#define DEBUG_xack 0x0080 +#define DEBUG_all 0xFFFF + +/* Simulator stop codes */ + +#define STOP_RSRV 1 /* must be 1 */ +#define STOP_HALT 2 /* HALT */ +#define STOP_IBKPT 3 /* breakpoint */ +#define STOP_OPCODE 4 /* Invalid Opcode */ +#define STOP_IO 5 /* I/O error */ +#define STOP_MEM 6 /* Memory error */ +#define STOP_XACK 7 /* XACK error */ +