1
0
mirror of https://github.com/rcornwell/sims.git synced 2026-02-13 11:25:18 +00:00

IBM360: Added ECMode PSW, general cleanup.

This commit is contained in:
Richard Cornwell
2019-02-14 19:59:31 -05:00
parent fab49af8eb
commit 025dcfd88e
4 changed files with 367 additions and 252 deletions

View File

@@ -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;

View File

@@ -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);

View File

@@ -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;

View File

@@ -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);