diff --git a/IBM360/ibm360_chan.c b/IBM360/ibm360_chan.c index 2a5fd2c..33790f6 100644 --- a/IBM360/ibm360_chan.c +++ b/IBM360/ibm360_chan.c @@ -269,6 +269,9 @@ writebuff(int chan) { return 0; } +/* + * Load in the next CCW, return 1 if failure, 0 if success. + */ int load_ccw(uint16 chan, int tic_ok) { uint32 word; @@ -358,10 +361,12 @@ loop: ccw_cmd[chan] = 0; irq_pend = 1; } + } if (ccw_flags[chan] & FLAG_PCI) { chan_status[chan] |= STATUS_PCI; + ccw_flags[chan] &= ~FLAG_PCI; irq_pend = 1; - } + sim_debug(DEBUG_CMD, &cpu_dev, "Set PCI %02x\n", chan); } return 0; } @@ -382,25 +387,33 @@ chan_read_byte(uint16 addr, uint8 *data) { if ((ccw_cmd[chan] & 0x1) == 0) { return 1; } + /* Check if finished transfer */ if (chan_byte[chan] == BUFF_CHNEND) return 1; + /* Check if count is zero */ if (ccw_count[chan] == 0) { + /* If not data channing, let device know there will be no + * more data to come + */ if ((ccw_flags[chan] & FLAG_CD) == 0) { chan_status[chan] |= STATUS_CEND; chan_byte[chan] = BUFF_CHNEND; sim_debug(DEBUG_DETAIL, &cpu_dev, "chan_read_end\n"); return 1; } else { + /* If chaining try and start next CCW */ if (load_ccw(chan, 1)) return 1; } } + /* Read in next work if buffer is in empty status */ if (chan_byte[chan] == BUFF_EMPTY) { if (readbuff(chan)) return 1; chan_byte[chan] = ccw_addr[chan] & 0x3; ccw_addr[chan] += 4 - chan_byte[chan]; } + /* Return current byte */ ccw_count[chan]--; byte = (chan_buf[chan] >> (8 * (3 - (chan_byte[chan] & 0x3)))) & 0xff; chan_byte[chan]++; @@ -425,17 +438,23 @@ chan_write_byte(uint16 addr, uint8 *data) { if ((ccw_cmd[chan] & 0x1) != 0) { return 1; } + /* Check if at end of transfer */ if (chan_byte[chan] == BUFF_CHNEND) { if ((ccw_flags[chan] & FLAG_SLI) == 0) { chan_status[chan] |= STATUS_LENGTH; } return 1; } + /* Check if count is zero */ if (ccw_count[chan] == 0) { + /* Flush the buffer if we got anything back. */ if (chan_byte[chan] & BUFF_DIRTY) { if (writebuff(chan)) return 1; } + /* If not data channing, let device know there will be no + * more data to come + */ if ((ccw_flags[chan] & FLAG_CD) == 0) { chan_byte[chan] = BUFF_CHNEND; if ((ccw_flags[chan] & FLAG_SLI) == 0) { @@ -445,9 +464,11 @@ chan_write_byte(uint16 addr, uint8 *data) { sim_debug(DEBUG_DETAIL, &cpu_dev, "chan_write_end\n"); return 1; } + /* Otherwise try and grab next CCW */ if (load_ccw(chan, 1)) return 1; } + /* If we are skipping, just adjust count */ if (ccw_flags[chan] & FLAG_SKIP) { ccw_count[chan]--; chan_byte[chan] = BUFF_EMPTY; @@ -457,6 +478,7 @@ chan_write_byte(uint16 addr, uint8 *data) { ccw_addr[chan]++; return 0; } + /* Check if we need to save what we have */ if (chan_byte[chan] == (BUFF_EMPTY|BUFF_DIRTY)) { if (writebuff(chan)) return 1; @@ -471,6 +493,7 @@ chan_write_byte(uint16 addr, uint8 *data) { return 1; chan_byte[chan] = ccw_addr[chan] & 0x3; } + /* Store it in buffer and adjust pointer */ ccw_count[chan]--; offset = 8 * (chan_byte[chan] & 0x3); mask = 0xff000000 >> offset; @@ -487,6 +510,9 @@ chan_write_byte(uint16 addr, uint8 *data) { return 0; } +/* + * A device wishes to inform the CPU it needs some service. + */ void set_devattn(uint16 addr, uint8 flags) { int chan = find_subchan(addr); @@ -503,6 +529,9 @@ set_devattn(uint16 addr, uint8 flags) { irq_pend = 1; } +/* + * Signal end of transfer by device. + */ void chan_end(uint16 addr, uint8 flags) { int chan = find_subchan(addr); @@ -511,11 +540,13 @@ chan_end(uint16 addr, uint8 flags) { return; sim_debug(DEBUG_DETAIL, &cpu_dev, "chan_end(%x, %x) %x\n", addr, flags, ccw_count[chan]); + /* If PCI flag set, trigger interrupt */ if (ccw_flags[chan] & FLAG_PCI) { chan_status[chan] |= STATUS_PCI; ccw_flags[chan] &= ~FLAG_PCI; irq_pend = 1; } + /* Flush buffer if there was any change */ if (chan_byte[chan] & BUFF_DIRTY) { if (writebuff(chan)) return; @@ -524,6 +555,8 @@ chan_end(uint16 addr, uint8 flags) { chan_status[chan] |= STATUS_CEND; chan_status[chan] |= ((uint16)flags) << 8; ccw_cmd[chan] = 0; + + /* If count not zero and not suppressing length, report error */ if (ccw_count[chan] != 0 && (ccw_flags[chan] & FLAG_SLI) == 0) { sim_debug(DEBUG_DETAIL, &cpu_dev, "chan_end length\n"); chan_status[chan] |= STATUS_LENGTH; @@ -537,9 +570,11 @@ chan_end(uint16 addr, uint8 flags) { ccw_flags[chan] = 0; } + /* If channel is also finished, then skip any more data commands. */ if (chan_status[chan] & (STATUS_DEND|STATUS_CEND)) { chan_byte[chan] = BUFF_NEWCMD; + /* While command has chain data set, continue to skip */ while ((ccw_flags[chan] & FLAG_CD)) { if (load_ccw(chan, 1)) break; @@ -554,6 +589,9 @@ chan_end(uint16 addr, uint8 flags) { irq_pend = 1; } +/* + * Save full csw. + */ int store_csw(uint16 chan) { M[0x40 >> 2] = caw[chan]; @@ -570,8 +608,11 @@ store_csw(uint16 chan) { return chan_dev[chan]; } - -int startio(uint16 addr) { +/* + * Handle SIO instruction. + */ +int +startio(uint16 addr) { int chan = find_subchan(addr); DIB *dibp = dev_unit[addr]; UNIT *uptr; @@ -662,11 +703,14 @@ int startio(uint16 addr) { return 0; } +/* + * Handle TIO instruction. + */ int testio(uint16 addr) { int chan = find_subchan(addr); DIB *dibp = dev_unit[addr]; UNIT *uptr; - uint8 status; + uint16 status; /* Find channel this device is on, if no none return cc=3 */ if (chan < 0 || dibp == 0) @@ -741,6 +785,9 @@ int testio(uint16 addr) { return 0; } +/* + * Handle HIO instruction. + */ int haltio(uint16 addr) { int chan = find_subchan(addr); DIB *dibp = dev_unit[addr]; @@ -768,6 +815,9 @@ int haltio(uint16 addr) { return 0; } +/* + * Handle TCH instruction. + */ int testchan(uint16 channel) { uint16 st = 0; channel >>= 8; @@ -785,6 +835,10 @@ int testchan(uint16 channel) { return 0; } +/* + * Bootstrap a device. Set command to READ IPL, length 24 bytes, suppress + * length warning, and chain command. + */ t_stat chan_boot(uint16 addr, DEVICE *dptyr) { int chan = find_subchan(addr); DIB *dibp = dev_unit[addr]; @@ -821,19 +875,24 @@ t_stat chan_boot(uint16 addr, DEVICE *dptyr) { return SCPE_OK; } -/* Scan all channels and see if one is ready to start or has - interrupt pending. -*/ -uint16 scan_chan(uint8 mask) { +/* + * Scan all channels and see if one is ready to start or has + * interrupt pending. + */ +uint16 +scan_chan(uint16 mask) { int i; int ch; int pend = 0; /* No device */ - int imask = 0x80; + int imask = 0x8000; + /* Quick exit if no pending IRQ's */ if (irq_pend == 0) return 0; irq_pend = 0; + /* Start with channel 0 and work through all channels */ for (i = 0; i < subchannels + channels; i++) { + /* If onto channel 1 or above shift mask */ if (i >= subchannels) imask = imask / 2; @@ -886,7 +945,8 @@ uint16 scan_chan(uint8 mask) { for (pend = 0; pend < MAX_DEV; pend++) { if (dev_status[pend] != 0) { ch = find_subchan(pend); - if (ch >= 0 && ccw_cmd[ch] == 0 && mask & (0x80 >> (pend >> 8))) { + if (ch >= 0 && ccw_cmd[ch] == 0 && + (mask & (0x8000 >> (pend >> 8))) != 0) { irq_pend = 1; M[0x44 >> 2] = (((uint32)dev_status[pend]) << 24); M[0x40>>2] = 0; diff --git a/IBM360/ibm360_com.c b/IBM360/ibm360_com.c index 0c342d9..0af88d7 100644 --- a/IBM360/ibm360_com.c +++ b/IBM360/ibm360_com.c @@ -33,6 +33,7 @@ /* u3 */ #define CMD_RD 0x02 /* Read in data from com line */ #define CMD_WR 0x01 /* Write data to com line */ +#define CMD_NOP 0x03 /* Nop command */ #define CMD_DIAL 0x29 /* Dial call */ #define CMD_BRK 0x0D /* Send break signal */ #define CMD_PREP 0x06 /* Wait for incoming data */ @@ -246,6 +247,8 @@ uint8 coml_startcmd(UNIT *uptr, uint16 chan, uint8 cmd) { switch (cmd & 0x3) { case 0x3: /* Control */ + if (cmd == CMD_NOP) + break; case 0x1: /* Write command */ case 0x2: /* Read command */ uptr->u3 |= cmd; @@ -333,14 +336,14 @@ t_stat coml_srv(UNIT * uptr) if (uptr->u3 & ENAB) { if (tmxr_rqln(&com_ldsc[unit]) > 0) { int32 data = tmxr_getc_ln (&com_ldsc[unit]); - if (ch & SCPE_BREAK) { + if (data & SCPE_BREAK) { uptr->u3 &= ~0xff; chan_end(addr, SNS_CHNEND|SNS_DEVEND|SNS_UNITCHK); return SCPE_OK; } else { ch = sim_tt_inpcvt (data, TT_GET_MODE(uptr->flags) | TTUF_KSR); - ch = com_2741_in[ch & 0x7f]; + ch = com_2741_in[data & 0x7f]; if (chan_write_byte( addr, &ch)) { uptr->u3 &= ~0xff; chan_end(addr, SNS_CHNEND|SNS_DEVEND); diff --git a/IBM360/ibm360_cpu.c b/IBM360/ibm360_cpu.c index d840f8e..497a048 100644 --- a/IBM360/ibm360_cpu.c +++ b/IBM360/ibm360_cpu.c @@ -30,6 +30,7 @@ #define FEAT_STOR (1 << (UNIT_V_UF + 11)) /* No alignment restrictions */ #define FEAT_TIMER (1 << (UNIT_V_UF + 12)) /* Interval timer */ #define FEAT_DAT (1 << (UNIT_V_UF + 13)) /* Dynamic address translation */ +#define FEAT_EFP (1 << (UNIT_V_UF + 14)) /* Extended floating point */ #define EXT_IRQ (1 << (UNIT_V_UF_31)) /* External interrupt */ #define UNIT_V_MSIZE (UNIT_V_UF + 0) /* dummy mask */ @@ -50,9 +51,11 @@ uint32 regs[16]; /* CPU Registers */ uint32 PC; /* Program counter */ uint32 fpregs[8]; /* Floating point registers */ uint32 cregs[16]; /* Control registers /67 or 370 only */ -uint8 sysmsk; /* Interupt mask */ -uint8 sysmskh; /* High order system mask */ +uint16 sysmsk; /* Interupt mask */ +uint8 ext_en; /* Enable external and timer IRQ's */ +uint8 irq_en; /* Enable channel IRQ's */ uint8 st_key; /* Storage key */ +uint8 ec_mode; /* EC mode PSW */ uint8 cc; /* CC */ uint8 ilc; /* Instruction length code */ uint8 pmsk; /* Program mask */ @@ -62,10 +65,7 @@ uint16 irqaddr; /* Address of IRQ vector */ uint16 loading; /* Doing IPL */ uint8 interval_irq = 0; /* Interval timer IRQ */ uint8 dat_en = 0; /* Translate addresses */ -uint32 segtable; /* Address of segment table */ -uint8 seglen; /* Length of segment table */ uint32 tlb[256]; /* Translation look aside buffer */ -uint32 execp_error; /* Translation error */ #define DAT_ENABLE 0x01 /* DAT enabled */ @@ -206,7 +206,7 @@ t_bool build_dev_tab (void); /* Interval timer option */ t_stat rtc_srv(UNIT * uptr); t_stat rtc_reset(DEVICE * dptr); -int32 rtc_tps = 60; +int32 rtc_tps = 300; /* CPU data structures @@ -263,17 +263,22 @@ MTAB cpu_mod[] = { { UNIT_MSIZE, MEMAMOUNT(128), "2M", "2M", &cpu_set_size }, { FEAT_PROT, 0, NULL, "NOPROT", NULL, NULL, NULL, "No Storage protection"}, { FEAT_PROT, FEAT_PROT, "PROT", "PROT", NULL, NULL, NULL, "Storage protection"}, - { FEAT_DEC, 0, NULL, "NODECIMAL", NULL, NULL, NULL}, - { FEAT_DEC, FEAT_DEC, "DECIMAL", "DECIMAL", NULL, NULL, NULL, "Decimal instruction set"}, - { FEAT_FLOAT, 0, NULL, "NOFLOAT", NULL, NULL, NULL}, - { FEAT_FLOAT, FEAT_FLOAT, "FLOAT", "FLOAT", NULL, NULL, NULL, "Floating point instruction"}, - { FEAT_UNIV, FEAT_UNIV, NULL, "UNIV", NULL, NULL, NULL, "Universal instruction"}, - { FEAT_STOR, 0, NULL, "NOSTORE", NULL, NULL, NULL}, + { FEAT_UNIV, FEAT_UNIV, "UNIV", "UNIV", NULL, NULL, NULL, "Universal instruction"}, + { FEAT_UNIV, 0, NULL, "NOUNIV", NULL, NULL, NULL, "Basic instructions"}, + { FEAT_UNIV, FEAT_FLOAT, "FLOAT", "FLOAT", NULL, NULL, NULL, + "Floating point instructions"}, + { FEAT_FLOAT, 0, NULL, "NOFLOAT", NULL, NULL, NULL, "No floating point instructions"}, + { FEAT_UNIV, FEAT_DEC, "DECIMAL", "DECIMAL", NULL, NULL, NULL, "Decimal instruction set"}, + { FEAT_DEC, 0, NULL, "NODECIMAL", NULL, NULL, "No decimal instructions"}, + { FEAT_EFP|FEAT_FLOAT, FEAT_EFP|FEAT_FLOAT, "EFLOAT", "EFLOAT", NULL, NULL, NULL, + "Extended Floating point instruction"}, + { FEAT_EFP, 0, NULL, "NOEFLOAT", NULL, NULL, NULL, "No extended floating point"}, { FEAT_STOR, FEAT_STOR, "STORE", "STORE", NULL, NULL, NULL, "No storage alignment"}, - { FEAT_TIMER, 0, NULL, "NOTIMER", NULL, NULL}, + { FEAT_STOR, 0, NULL, "NOSTORE", NULL, NULL, NULL}, { FEAT_TIMER, FEAT_TIMER, "TIMER", "TIMER", NULL, NULL, NULL, "Interval timer"}, + { FEAT_TIMER, 0, NULL, "NOTIMER", NULL, NULL}, + { FEAT_DAT, FEAT_DAT, "DAT", "DAT", NULL, NULL, NULL, "DAT /67"}, { FEAT_DAT, 0, NULL, "NODAT", NULL, NULL}, - { FEAT_DAT, FEAT_DAT, "DAT", "DAT", NULL, NULL, NULL, "Dat /67"}, { EXT_IRQ, 0, "NOEXT", NULL, NULL, NULL}, { EXT_IRQ, EXT_IRQ, "EXT", "EXT", NULL, NULL, NULL, "External Irq"}, { MTAB_XTD|MTAB_VDV|MTAB_NMO|MTAB_SHP, 0, "HISTORY", "HISTORY", @@ -314,32 +319,49 @@ void post_extirq() { void storepsw(uint32 addr, uint16 ircode) { - uint32 word; - sim_debug(DEBUG_INST, &cpu_dev, "store %02x %d %x PSW=%08x %08x ", addr, ilc, cc, (((uint32)sysmsk) << 24) | - (((uint32)st_key) << 16) | (((uint32)flags) << 16) | ((uint32)ircode), - (((uint32)ilc) << 30) | (((uint32)cc) << 28) | (((uint32)pmsk) << 24) | PC); + uint32 word; + uint32 word2; irqaddr = addr + 0x40; - word = (((uint32)sysmsk) << 24) | - (((uint32)st_key) << 16) | - (((uint32)flags) << 16) | - ((uint32)ircode); + + if (ec_mode) { + /* Generate first word */ + word = (((uint32)dat_en) << 26) | + ((irq_en) ? 1<<25:0) | + ((ext_en) ? 1<<24:0) | + (((uint32)st_key) << 16) | + (((uint32)flags) << 16) | + (((uint32)ilc) << 14) | + (((uint32)cc) << 12) | + (((uint32)pmsk) << 8); + /* Generate second word. */ + word2 = PC; + } else { + /* Generate first word */ + word = ((uint32)(ext_en) << 24) | + ((uint32)(sysmsk & 0xfe00) << 16) | + (((uint32)st_key) << 16) | + (((uint32)flags) << 16) | + ((uint32)ircode); + /* Generate second word. */ + word2 = (((uint32)ilc) << 30) | + (((uint32)cc) << 28) | + (((uint32)pmsk) << 24) | + (PC & AMASK); + } M[addr >> 2] = word; - if (hst_lnt) { - hst_p = hst_p + 1; - if (hst_p >= hst_lnt) - hst_p = 0; - hst[hst_p].pc = addr | HIST_SPW; - hst[hst_p].src1 = word; - } addr += 4; - word = (((uint32)ilc) << 30) | - (((uint32)cc) << 28) | - (((uint32)pmsk) << 24) | - PC; - M[addr >> 2] = word; - if (hst_lnt) { - hst[hst_p].src2 = word; - } + M[addr >> 2] = word2; + /* Update history */ + if (hst_lnt) { + hst_p = hst_p + 1; + if (hst_p >= hst_lnt) + hst_p = 0; + hst[hst_p].pc = addr | HIST_SPW; + hst[hst_p].src1 = word; + hst[hst_p].src2 = word2; + } + sim_debug(DEBUG_INST, &cpu_dev, "store %02x %d %x PSW=%08x %08x\n\r", addr, ilc, + cc, word, word2); irqcode = ircode; } @@ -354,69 +376,73 @@ int TransAddr(uint32 va, uint32 *pa) { /* Check address in range */ va &= AMASK; - if (va >= MEMSIZE) { - storepsw(OPPSW, IRC_ADDR); - return 1; - } if (!dat_en) { - *pa = va; - return 0; + if (va >= MEMSIZE) { + storepsw(OPPSW, IRC_ADDR); + return 1; + } + *pa = va; + return 0; } - seg = (va & SEG_MASK) >> 12; - page = seg & 0xff; + seg = va & SEG_MASK; + page = (seg >> 12) & 0xff; /* Quick check if TLB correct */ entry = tlb[page]; if ((entry & TLB_VALID) != 0 && ((entry ^ seg) & TLB_SEG) == 0) { *pa = (va & 0xfff) | ((entry & TLB_PHY) << 12); + if (va >= MEMSIZE) { + storepsw(OPPSW, IRC_ADDR); + return 1; + } return 0; } /* TLB not correct, try loading correct entry */ seg >>= 8; /* Segment number to word address */ if ((seg >> 4) != 0) { - execp_error = va; - storepsw(OPPSW, IRC_SEG); + cregs[2] = va; + storepsw(OPPSW, IRC_SEG); /* Not valid address */ return 1; } - addr = ((seg & 0xFFF) << 2) + segtable; + addr = ((seg & 0xFFF) << 2) + (cregs[0] & AMASK); /* Ignore high order bits */ addr &= AMASK; if (addr >= MEMSIZE) { - storepsw(OPPSW, IRC_ADDR); - return 1; + storepsw(OPPSW, IRC_ADDR); + return 1; } entry = M[addr >> 2]; /* Check if entry valid and in correct length */ if (entry & PTE_VALID || page > (entry >> 24)) { - storepsw(OPPSW, IRC_PAGE); - execp_error = va; - return 1; + cregs[2] = va; + storepsw(OPPSW, IRC_PAGE); + return 1; } /* Now we need to fetch the actual entry */ addr = (((entry & PTE_ADR) >> 1) + page) << 2; addr &= AMASK; if (addr >= MEMSIZE) { - storepsw(OPPSW, IRC_ADDR); - return 1; + storepsw(OPPSW, IRC_ADDR); + return 1; } entry = M[addr >> 2]; entry >>= (addr & 2) ? 0 : 16; entry &= 0xffff; if ((entry & (PTE_MBZ)) != 0) { + cregs[2] = va; storepsw(OPPSW, IRC_SPEC); - execp_error = va; return 1; } /* Check if entry valid and in correct length */ if (entry & PTE_AVAL) { - storepsw(OPPSW, IRC_PAGE); - execp_error = va; - return 1; + cregs[2] = va; + storepsw(OPPSW, IRC_PAGE); + return 1; } /* Compute correct entry */ @@ -424,6 +450,10 @@ int TransAddr(uint32 va, uint32 *pa) { entry |= (va & TLB_SEG) | TLB_VALID; tlb[page] = entry; *pa = (va & 0xfff) | ((entry & TLB_PHY) << 12); + if (va >= MEMSIZE) { + storepsw(OPPSW, IRC_ADDR); + return 1; + } return 0; } @@ -437,12 +467,9 @@ int ReadFull(uint32 addr, uint32 *data) { int offset; uint8 k; - /* Ignore high order bits */ - addr &= AMASK; - if (addr >= MEMSIZE) { - storepsw(OPPSW, IRC_ADDR); - return 1; - } + /* Validate address */ + if (TransAddr(addr, &addr)) + return 1; offset = addr & 0x3; addr >>= 2; @@ -455,7 +482,6 @@ int ReadFull(uint32 addr, uint32 *data) { } k = key[addr >> 9]; if ((k & 0x8) != 0 && (k & 0xf0) != st_key) { -//fprintf(stderr, "Protstore %08x %x %x\n\r", addr <<2, k ,st_key); storepsw(OPPSW, IRC_PROT); return 1; } @@ -468,10 +494,15 @@ int ReadFull(uint32 addr, uint32 *data) { return 1; } temp = addr + 1; + /* Check if possible next page */ + if ((temp & 0x3ff) == 0) { + if (TransAddr(temp << 2, &temp)) + return 1; + temp >>= 2; + } if ((temp & 0x1ff) == 0 && st_key != 0) { k = key[temp >> 9]; if ((k & 0x8) != 0 && (k & 0xf0) != st_key) { -//fprintf(stderr, "Protstore %08x %x %x\n\r", addr <<2, k ,st_key); storepsw(OPPSW, IRC_PROT); return 1; } @@ -527,16 +558,16 @@ int ReadHalf(uint32 addr, uint32 *data) { int WriteFull(uint32 addr, uint32 data) { int offset; + uint32 pa; + uint32 pa2; uint8 k; - /* Ignore high order bits */ - addr &= AMASK; - if (addr >= MEMSIZE) { - storepsw(OPPSW, IRC_ADDR); - return 1; - } - offset = addr & 0x3; - addr >>= 2; + /* Validate address */ + if (TransAddr(addr, &pa)) + return 1; + + offset = pa & 0x3; + pa >>= 2; /* Check storage key */ if (st_key != 0) { @@ -544,90 +575,75 @@ int WriteFull(uint32 addr, uint32 data) { storepsw(OPPSW, IRC_PROT); return 1; } - k = key[addr >> 9]; + k = key[pa >> 9]; if ((k & 0xf0) != st_key) { -//fprintf(stderr, "Protstore %08x %x %x\n\r", addr <<2, k ,st_key); storepsw(OPPSW, IRC_PROT); return 1; } } + /* Check if we handle unaligned access */ + if (offset != 0) { + if ((cpu_unit.flags & FEAT_STOR) == 0) { + storepsw(OPPSW, IRC_SPEC); + return 1; + } + + /* Check if new page or new protection zone */ + if ((pa & 0x1ff) == 0x1ff) { + /* Validate address */ + if (TransAddr(addr + 4, &pa2)) + return 1; + pa2 >>= 2; + if (st_key != 0) { + k = key[(pa2) >> 9]; + if ((k & 0xf0) != st_key) { + storepsw(OPPSW, IRC_PROT); + return 1; + } + } + } else + pa2 = pa + 1; + } + switch (offset) { case 0: - M[addr] = data; + M[pa] = data; break; case 1: - if ((cpu_unit.flags & FEAT_STOR) == 0) { - storepsw(OPPSW, IRC_SPEC); - return 1; - } - if (((addr & 0x1ff) == 0x1ff) && st_key != 0) { - k = key[(addr + 1) >> 9]; - if ((k & 0xf0) != st_key) { -//fprintf(stderr, "Protstore %08x %x %x\n\r", addr <<2, k ,st_key); - storepsw(OPPSW, IRC_PROT); - return 1; - } - } - M[addr] &= 0xff000000; - M[addr] |= 0xffffff & (data >> 8); - M[addr+1] &= 0xffffff; - M[addr+1] |= 0xff000000 & (data << 24); - break; + M[pa] &= 0xff000000; + M[pa] |= 0xffffff & (data >> 8); + M[pa2] &= 0xffffff; + M[pa2] |= 0xff000000 & (data << 24); + break; case 2: - if ((cpu_unit.flags & FEAT_STOR) == 0) { - storepsw(OPPSW, IRC_SPEC); - return 1; - } - if (((addr & 0x1ff) == 0x1ff) && st_key != 0) { - k = key[(addr + 1) >> 9]; - if ((k & 0xf0) != st_key) { -//fprintf(stderr, "Protstore %08x %x %x\n\r", addr <<2, k ,st_key); - storepsw(OPPSW, IRC_PROT); - return 1; - } - } - M[addr] &= 0xffff0000; - M[addr] |= 0xffff & (data >> 16); - M[addr+1] &= 0xffff; - M[addr+1] |= 0xffff0000 & (data << 16); - break; + M[pa] &= 0xffff0000; + M[pa] |= 0xffff & (data >> 16); + M[pa2] &= 0xffff; + M[pa2] |= 0xffff0000 & (data << 16); + break; case 3: - if ((cpu_unit.flags & FEAT_STOR) == 0) { - storepsw(OPPSW, IRC_SPEC); - return 1; - } - if (((addr & 0x1ff) == 0x1ff) && st_key != 0) { - k = key[(addr + 1) >> 9]; - if ((k & 0xf0) != st_key) { -//fprintf(stderr, "Protstore %08x %x %x\n\r", addr <<2, k ,st_key); - storepsw(OPPSW, IRC_PROT); - return 1; - } - } - M[addr] &= 0xffffff00; - M[addr] |= 0xff & (data >> 24); - M[addr+1] &= 0xff; - M[addr+1] |= 0xffffff00 & (data << 8); - break; + M[pa] &= 0xffffff00; + M[pa] |= 0xff & (data >> 24); + M[pa2] &= 0xff; + M[pa2] |= 0xffffff00 & (data << 8); + break; } return 0; } int WriteByte(uint32 addr, uint32 data) { uint32 mask; + uint32 pa; uint8 k; int offset; - /* Ignore high order bits */ - addr &= AMASK; - if (addr >= MEMSIZE) { - storepsw(OPPSW, IRC_ADDR); + /* Validate address */ + if (TransAddr(addr, &pa)) return 1; - } - offset = 8 * (3 - (addr & 0x3)); - addr >>= 2; + offset = 8 * (3 - (pa & 0x3)); + pa >>= 2; /* Check storage key */ if (st_key != 0) { @@ -635,9 +651,8 @@ int WriteByte(uint32 addr, uint32 data) { storepsw(OPPSW, IRC_PROT); return 1; } - k = key[addr >> 9]; + k = key[pa >> 9]; if ((k & 0xf0) != st_key) { -//fprintf(stderr, "Protstore %08x %x %x\n\r", addr <<2, k ,st_key); storepsw(OPPSW, IRC_PROT); return 1; } @@ -647,77 +662,83 @@ int WriteByte(uint32 addr, uint32 data) { data &= mask; data <<= offset; mask <<= offset; - M[addr] &= ~mask; - M[addr] |= data; + M[pa] &= ~mask; + M[pa] |= data; return 0; } int WriteHalf(uint32 addr, uint32 data) { uint32 mask; uint8 k; + uint32 pa; + uint32 pa2; int offset; int o; - /* Ignore high order bits */ - addr &= AMASK; - if (addr >= MEMSIZE) { - storepsw(OPPSW, IRC_ADDR); + /* Validate address */ + if (TransAddr(addr, &pa)) + return 1; + + offset = pa & 0x3; + pa >>= 2; + + /* Check if we handle unaligned access */ + if ((offset & 1) != 0 && (cpu_unit.flags & FEAT_STOR) == 0) { + storepsw(OPPSW, IRC_SPEC); return 1; } - offset = addr & 0x3; - addr >>= 2; - /* Check storage key */ if (st_key != 0) { if ((cpu_unit.flags & FEAT_PROT) == 0) { storepsw(OPPSW, IRC_PROT); return 1; } - k = key[addr >> 9]; + k = key[pa >> 9]; if ((k & 0xf0) != st_key) { -//fprintf(stderr, "Protstore %08x %x %x\n\r", addr <<2, k ,st_key); storepsw(OPPSW, IRC_PROT); return 1; } } + if (offset == 3) { + /* Check if new page or new protection zone */ + if ((pa & 0x1ff) == 0x1ff) { + /* Validate address */ + if (TransAddr(addr + 4, &pa2)) + return 1; + pa2 >>= 2; + if (st_key != 0) { + k = key[(pa2) >> 9]; + if ((k & 0xf0) != st_key) { + storepsw(OPPSW, IRC_PROT); + return 1; + } + } + } else + pa2 = pa + 1; + } + mask = 0xffff; data &= mask; switch (offset) { case 0: - M[addr] &= ~(mask << 16); - M[addr] |= data << 16; + M[pa] &= ~(mask << 16); + M[pa] |= data << 16; break; case 1: - if ((cpu_unit.flags & FEAT_STOR) == 0) { - storepsw(OPPSW, IRC_SPEC); - return 1; - } - M[addr] &= ~(mask << 8); - M[addr] |= data << 8; + M[pa] &= ~(mask << 8); + M[pa] |= data << 8; break; case 2: - M[addr] &= ~mask; - M[addr] |= data; + M[pa] &= ~mask; + M[pa] |= data; break; case 3: - if ((cpu_unit.flags & FEAT_STOR) == 0) { - storepsw(OPPSW, IRC_SPEC); - return 1; - } - if (((addr & 0x1ff) == 0x1ff) && st_key != 0) { - k = key[(addr + 1) >> 9]; - if ((k & 0xf0) != st_key) { -//fprintf(stderr, "Protstore %08x %x %x\n\r", addr <<2, k ,st_key); - storepsw(OPPSW, IRC_PROT); - return 1; - } - } - M[addr] &= 0xffffff00; - M[addr] |= 0xff & (data >> 8); - M[addr+1] &= 0x00ffffff; - M[addr+1] |= 0xff000000 & (data << 24); + M[pa] &= 0xffffff00; + M[pa] |= 0xff & (data >> 8); + M[pa2] &= 0x00ffffff; + M[pa2] |= 0xff000000 & (data << 24); break; } return 0; @@ -758,6 +779,7 @@ sim_instr(void) sim_activate(&cpu_unit, 100); } interval_irq = 0; + irq_en |= (loading != 0); while (reason == SCPE_OK) { @@ -768,6 +790,7 @@ wait_loop: return reason; } + /* Check if we should see if an IRQ is pending */ irq= scan_chan(sysmsk); if (irq!= 0) { ilc = 0; @@ -782,23 +805,27 @@ wait_loop: goto supress; } - if ((cpu_unit.flags & EXT_IRQ) && (sysmsk & 01)) { - ilc = 0; - cpu_unit.flags &= ~EXT_IRQ; - storepsw(OEPSW, 0x40); - goto supress; - } - - if (interval_irq && (sysmsk & 01)) { - ilc = 0; - interval_irq = 0; - storepsw(OEPSW, 0x80); - goto supress; + /* Check for external interrupts */ + if (ext_en) { + if ((cpu_unit.flags & EXT_IRQ) && (cregs[4] & 0x40) != 0) { + ilc = 0; + cpu_unit.flags &= ~EXT_IRQ; + storepsw(OEPSW, 0x40); + goto supress; + } + + if (interval_irq && (cregs[4] & 0x80) != 0) { + ilc = 0; + interval_irq = 0; + storepsw(OEPSW, 0x80); + goto supress; + } } + /* If we have wait flag or loading, nothing more to do */ if (loading || flags & WAIT) { /* CPU IDLE */ - if (flags & WAIT && sysmsk == 0) + if (flags & WAIT && irq_en == 0 && ext_en == 0) return STOP_HALT; sim_interval--; goto wait_loop; @@ -821,7 +848,8 @@ wait_loop: hst[hst_p].pc = PC | HIST_PC; } - sim_debug(DEBUG_INST, &cpu_dev, "PSW=%08x %08x ", (((uint32)sysmsk) << 24) | + sim_debug(DEBUG_INST, &cpu_dev, "PSW=%08x %08x ", + ((uint32)(ext_en) << 24) | (((uint32)sysmsk & 0xfe00) << 16) | (((uint32)st_key) << 16) | (((uint32)flags) << 16) | ((uint32)irqcode), (((uint32)ilc) << 30) | (((uint32)cc) << 28) | (((uint32)pmsk) << 24) | PC); ilc = 0; @@ -900,7 +928,6 @@ opr: goto supress; } if (reg1 & 0x9) { -//fprintf(stderr, "Spec FP Reg=%x\n\r", reg1); storepsw(OPPSW, IRC_SPEC); goto supress; } @@ -912,7 +939,6 @@ opr: src1h = 0; if (op & 0x40) { if ((op & 0x10) != 0 && (addr1 & 0x3) != 0) { -//fprintf(stderr, "Spec FP Op=%0x Op=%x\n\r", op, addr1); storepsw(OPPSW, IRC_SPEC); goto supress; } @@ -924,11 +950,8 @@ opr: goto supress; } else src2h = 0; -//if ((op & 0xf) > 8) -//fprintf(stderr, "RD FP Op=%0x %08x %08x\n\r", op, src2, src2h); } else { if (reg & 0x9) { -//fprintf(stderr, "Spec FP Reg2=%x\n\r", reg); storepsw(OPPSW, IRC_SPEC); goto supress; } @@ -937,8 +960,6 @@ opr: src2h = fpregs[R2(reg)|1]; else src2h = 0; -//if ((op & 0xf) > 8) -//fprintf(stderr, "RD FP Op=%0x %08x %08x\n\r", op, src2, src2h); } /* All RR opcodes */ } else if ((op & 0xe0) == 0) { @@ -1041,9 +1062,9 @@ opr: } else if (addr1 >= MEMSIZE) { storepsw(OPPSW, IRC_ADDR); } else if (cpu_unit.flags & FEAT_PROT) { - key[addr1 >> 11] = src1 & 0xf8; -//if ((src1 & 0xff) != 0) -//fprintf(stderr, "Protset %08x %02x\n\r", addr1, src1); + if (TransAddr(addr1, &addr2)) + break; + key[addr2 >> 11] = src1 & 0xf8; } break; @@ -1058,8 +1079,10 @@ opr: } else if (addr1 >= MEMSIZE) { storepsw(OPPSW, IRC_ADDR); } else { + if (TransAddr(addr1, &addr2)) + break; dest &= 0xffffff00; - dest |= key[addr1 >> 11]; + dest |= key[addr2 >> 11]; regs[reg1] = dest; } break; @@ -1073,8 +1096,20 @@ opr: storepsw(OPPSW, IRC_PRIV); } else { ReadByte(addr1, &src1); - sysmsk = src1 & 0xff; - irq_pend = 1; + if (ec_mode) { + if (src1 & 0xf0) + storepsw(OPPSW, IRC_SPEC); + dat_en = (src1 > 2) & 3; + irq_en = (src1 & 02) != 0; + ext_en = (src1 & 01) != 0; + } else { + sysmsk = (src1 & 0xfe) << 8; + irq_en = (sysmsk != 0); + ext_en = (src1 & 0x1) != 0; + cregs[6] &= 0x0000ffff; + cregs[6] |= (uint32)(sysmsk) << 16; + irq_pend = 1; + } } break; @@ -1630,13 +1665,10 @@ save_dbl: dest = 0; switch (reg) { case 0x0: /* Segment table address */ - dest = segtable; - break; - case 0x2: /* Translation execption */ - dest = execp_error; - break; - case 0x4: /* Extended mask */ case 0x6: /* Maskes */ + case 0x4: /* Extended mask */ + case 0x2: /* Translation execption */ + dest = cregs[reg]; break; case 0x8: /* Partitioning register */ case 0x9: /* Partitioning register */ @@ -1677,21 +1709,29 @@ save_dbl: for (;;) { if (ReadFull(addr1, &dest)) goto supress; + cregs[reg] = dest; switch (reg) { case 0x0: /* Segment table address */ - if ((dest & 0x3f) != 0) - storepsw(OPPSW, IRC_PRIV); - segtable = dest & AMASK; for (temp = 0; temp < sizeof(tlb)/sizeof(uint32); temp++) tlb[temp] = 0; + if ((dest & 0x3f) != 0) + storepsw(OPPSW, IRC_DATA); break; - case 0x2: /* Translation execption */ - execp_error = dest; + case 0x6: /* Maskes */ + sysmsk = (dest >> 16) & 0xfefe; + cregs[reg] &= 0xfefe0000; + if (sysmsk & 0xfe00) + cregs[reg] |= 0x1000000; + if (sysmsk & 0x00fe) + cregs[reg] |= 0x0010000; break; case 0x4: /* Extended mask */ - case 0x6: /* Maskes */ + ec_mode = (dest & 0x00800000) != 0; + cregs[reg] &= 0xf08000ff; + break; + case 0x2: /* Translation execption */ break; case 0x1: /* Unassigned */ case 0x3: /* Unassigned */ @@ -1705,7 +1745,7 @@ save_dbl: case 0xD: /* Partitioning register */ case 0xE: /* Partitioning register */ case 0xF: /* Unassigned */ - break; + break; } if (reg1 == reg) break; @@ -1736,7 +1776,7 @@ save_dbl: cc = 1; break; } - addr2 = ((addr2 & 0xFFF) << 2) + segtable; + addr2 = ((addr2 & 0xFFF) << 2) + (cregs[0] & AMASK); /* Ignore high order bits */ addr2 &= AMASK; if (addr2 >= MEMSIZE) { @@ -3066,6 +3106,7 @@ fpnorm: case OP_MXR: case OP_MXDR: case OP_MXD: +fprintf(stderr, "Extended op\n\r"); default: storepsw(OPPSW, IRC_OPR); goto supress; @@ -3076,7 +3117,6 @@ fpnorm: hst[hst_p].cc = cc; } -// if ((op & 0xA0) == 0x20) { sim_debug(DEBUG_INST, &cpu_dev, "GR00=%08x GR01=%08x GR02=%08x GR03=%08x\n", regs[0], regs[1], regs[2], regs[3]); @@ -3097,37 +3137,48 @@ fpnorm: "FP04=%08x FP05=%08x FP06=%08x FP07=%08x\n", fpregs[4], fpregs[5], fpregs[6], fpregs[7]); } - // } if (irqaddr != 0) { supress: src1 = M[irqaddr>>2]; - if (hst_lnt) { - hst_p = hst_p + 1; - if (hst_p >= hst_lnt) - hst_p = 0; - hst[hst_p].pc = irqaddr | HIST_LPW; - hst[hst_p].src1 = src1; - } + if (hst_lnt) { + hst_p = hst_p + 1; + if (hst_p >= hst_lnt) + hst_p = 0; + hst[hst_p].pc = irqaddr | HIST_LPW; + hst[hst_p].src1 = src1; + } irqaddr += 4; src2 = M[irqaddr>>2]; - if (hst_lnt) { - hst[hst_p].src2 = src2; - } + if (hst_lnt) { + hst[hst_p].src2 = src2; + } lpsw: - sysmsk = (src1 >> 24) & 0xff; - st_key = (src1 >> 16) & 0xf0; - flags = (src1 >> 16) & 0xf; + if (ec_mode) { + dat_en = (src1 >> 26) & 3; + irq_en = (src1 & 0x2000000) != 0; + cc = (src1 >> 12) & 3; + pmsk = (src1 >> 8) & 0xf; + } else { + cregs[6] = src1 & 0xfe000000; + sysmsk = (cregs[6] >> 16) & 0xfe00; + if (sysmsk) { + cregs[reg] |= 0x1000000; + irq_en = 1; + } else + irq_en = 0; + pmsk = (src2 >> 24) & 0xf; + cc = (src2 >> 28) & 0x3; + } irqaddr = 0; - pmsk = (src2 >> 24) & 0xf; - cc = (src2 >> 28) & 0x3; + ext_en = (src1 & 0x1000000) != 0; + st_key = (src1 >> 16) & 0xf0; + flags = (src1 >> 16) & 0xf; PC = src2 & AMASK; irq_pend = 1; - sim_debug(DEBUG_INST, &cpu_dev, "PSW=%08x %08x ", - (((uint32)sysmsk) << 24) | (((uint32)st_key) << 16) | - (((uint32)flags) << 16) | ((uint32)irqcode), - (((uint32)ilc) << 30) | (((uint32)cc) << 28) | - (((uint32)pmsk) << 24) | PC); + sim_debug(DEBUG_INST, &cpu_dev, "PSW=%08x %08x ", src1, src2); + if (dat_en & 0x2) + storepsw(OPPSW, IRC_SPEC); } sim_interval--; } @@ -3445,6 +3496,7 @@ t_stat cpu_reset (DEVICE *dptr) if (M == NULL) return SCPE_MEM; } + cregs[4] = 0xff; return SCPE_OK; } @@ -3461,7 +3513,7 @@ rtc_srv(UNIT * uptr) sim_debug(DEBUG_INST, &cpu_dev, "TIMER IRQ %08x\n\r", M[0x50>>2]); interval_irq = 1; } - M[0x50>>2] -= 0x40; + M[0x50>>2] -= 0x100; sim_debug(DEBUG_INST, &cpu_dev, "TIMER = %08x\n", M[0x50>>2]); } return SCPE_OK; diff --git a/IBM360/ibm360_defs.h b/IBM360/ibm360_defs.h index 0ed9555..7604ee2 100644 --- a/IBM360/ibm360_defs.h +++ b/IBM360/ibm360_defs.h @@ -326,7 +326,7 @@ int startio(uint16 addr) ; int testio(uint16 addr); int haltio(uint16 addr); int testchan(uint16 channel); -uint16 scan_chan(uint8 mask); +uint16 scan_chan(uint16 mask); t_stat chan_boot(uint16 addr, DEVICE *dptr); t_stat chan_set_devs(); t_stat set_dev_addr(UNIT * uptr, int32 val, CONST char *cptr, void *desc);