1
0
mirror of https://github.com/rcornwell/sims.git synced 2026-01-23 10:58:12 +00:00

IBM360: Changes to help MTS D4.0 to run.

Misc debugging changes.
    Add support for TCH channel controller on /67
    Fix bug in M,MR,MH instructions.
    Extend channel address to include channel controller.
    Add support to examine or deposit virtual addresses.
This commit is contained in:
G Helffrich 2020-08-30 21:43:38 -04:00 committed by Richard Cornwell
parent 84c38215da
commit 37ed26e6c9
9 changed files with 234 additions and 89 deletions

View File

@ -210,7 +210,7 @@ cdp_srv(UNIT *uptr) {
if (chan_read_byte(addr, &ch)) {
uptr->CMD |= CDP_CARD;
} else {
sim_debug(DEBUG_DATA, &cdp_dev, "%d: Char < %02o\n", u, ch);
sim_debug(DEBUG_DATA, &cdp_dev, "%d: Char < %02x\n", u, ch);
image[uptr->COL++] = sim_ebcdic_to_hol(ch);
if (uptr->COL == 80) {
uptr->CMD |= CDP_CARD;
@ -230,15 +230,11 @@ cdp_srv(UNIT *uptr) {
t_stat
cdp_attach(UNIT * uptr, CONST char *file)
{
t_stat r;
if ((r = sim_card_attach(uptr, file)) != SCPE_OK)
return r;
if (uptr->up7 == 0) {
uptr->up7 = calloc(80, sizeof(uint16));
uptr->SNS = 0;
}
return SCPE_OK;
return sim_card_attach(uptr, file);
}
t_stat

View File

@ -199,6 +199,7 @@ cdr_srv(UNIT *uptr) {
chan_write_byte(addr, &ch);
chan_end(addr, SNS_CHNEND|SNS_DEVEND);
uptr->CMD &= ~(CDR_CMDMSK);
uptr->SNS = 0;
return SCPE_OK;
}

View File

@ -373,7 +373,7 @@ loop:
chan_status[chan] &= 0xff;
chan_status[chan] |= dibp->start_cmd(uptr, chan, ccw_cmd[chan]) << 8;
if (chan_status[chan] & (STATUS_ATTN|STATUS_CHECK|STATUS_EXPT)) {
sim_debug(DEBUG_DETAIL, &cpu_dev, "Channel %03x abort %04x\n",
sim_debug(DEBUG_DETAIL, &cpu_dev, "Channel %03x abort %04x\n",
chan, chan_status[chan]);
chan_status[chan] |= STATUS_CEND;
ccw_flags[chan] = 0;
@ -385,6 +385,8 @@ loop:
chan_status[chan] |= STATUS_CEND;
ccw_cmd[chan] = 0;
irq_pend = 1;
if ((ccw_flags[chan] & (FLAG_CD|FLAG_CC)) == 0)
return 1; /* No chain? Give imm. SIO response. */
}
}
if (ccw_flags[chan] & FLAG_PCI) {
@ -732,7 +734,7 @@ startio(uint16 addr) {
if (ccw_cmd[chan] != 0 ||
(ccw_flags[chan] & (FLAG_CD|FLAG_CC)) != 0 ||
chan_status[chan] != 0) {
sim_debug(DEBUG_CMD, &cpu_dev, "SIO %x %x %08x cc=2\n", addr, chan,
sim_debug(DEBUG_CMD, &cpu_dev, "SIO %x %x %08x cc=2\n", addr, chan,
chan_status[chan]);
return 2;
}
@ -951,6 +953,8 @@ int haltio(uint16 addr) {
M[0x44 >> 2] = (((uint32)chan_status[chan]) << 16) |
(M[0x44 >> 2] & 0xffff);
key[0] |= 0x6;
sim_debug(DEBUG_EXP, &cpu_dev, "Channel store csw %02x %08x\n",
chan, M[0x44 >> 2]);
}
return cc;
}
@ -961,6 +965,7 @@ int haltio(uint16 addr) {
M[0x44 >> 2] = (((uint32)chan_status[chan]) << 16) |
(M[0x44 >> 2] & 0xffff);
key[0] |= 0x6;
sim_debug(DEBUG_EXP, &cpu_dev, "Channel store csw %02x %08x\n", chan, M[0x44 >> 2]);
return 1;
}
@ -969,8 +974,37 @@ int haltio(uint16 addr) {
*/
int testchan(uint16 channel) {
uint16 st = 0;
channel >>= 8;
if (channel == 0 || channel == 4)
uint8 cc = 0;
/* 360 Principles of Operation says, "Bit positions 21-23 of the
sum formed by the addition of the content of register B1 and the
content of the D1 field identify the channel to which the
instruction applies. Bit positions 24-31 of the address are ignored.
/67 Functional Characteristics do not mention any changes in basic or
extended control mode of the TCH instruction behaviour.
However, historic /67 code for MTS suggests that bits 19-20 of the
address indicate the channel controller which should be used to query
the channel.
Original testchan code did not recognize the channel controller (CC) part
of the address and treats the query as referring to a channel # like so:
CC = 0 channel# 0 1 2 3 4 5 6
CC = 1 " 8 9 10 11 12 13 14
CC = 2 " 16 17 18 19 20 21 22
CC = 3 " 24 25 26 27 28 29 30
which may interfere with subchannel mapping.
For the nonce, TCH only indicates that channels connected to CC 0 & 1 are
attached. Channels 0, 4, 8 (0 on CC 1) & 12 (4 on CC 1) are multiplexer
channels. */
cc = (channel >> 11) & 0x03;
channel = (channel >> 8) & 0x0f;
if (cc > 1 || channel > channels) {
sim_debug(DEBUG_CMD, &cpu_dev, "TCH CC %x %x cc=3\n", cc, channel);
return 3;
}
if (channel == 0 || channel == 4 || channel == 8 || channel == 12)
return 0;
if (channel > channels)
return 3;

View File

@ -272,7 +272,7 @@ uint8 coml_startcmd(UNIT *uptr, uint16 chan, uint8 cmd) {
switch (cmd & 0x3) {
case 0x3: /* Control */
if (cmd == CMD_NOP)
if ((cmd == CMD_NOP) || (cmd & 0x8) != 0)
return SNS_CHNEND|SNS_DEVEND;
case 0x2: /* Read command */
case 0x1: /* Write command */

View File

@ -245,6 +245,7 @@ con_srv(UNIT *uptr) {
chan_write_byte(addr, &ch);
chan_end(addr, SNS_CHNEND|SNS_DEVEND);
uptr->CMD &= ~(CON_MSK);
uptr->SNS = 0;
break;
case CON_WR:

View File

@ -26,7 +26,7 @@
The IBM 360 supported 32 bit memory and 16 32 bit registers. Optionally
it could have 4 64 bit floating point registers. Optionally the machine
could also process packed decimal numbers directly. There was also a
64 bit processor status word. Up to 16MB of memory could be supported,
64 bit processor status word. Up to 16MB of memory could be supported,
however 1MB or less was much more common. 8MB being the practical max.
Instructions ranged from 2 bytes to up to 6 bytes. In the following formats:
@ -363,7 +363,8 @@ MTAB cpu_mod[] = {
{ FEAT_DAT, FEAT_DAT, "DAT", "DAT", NULL, NULL, NULL, "DAT /67"},
{ FEAT_DAT, 0, NULL, "NODAT", NULL, NULL},
{ EXT_IRQ, 0, "NOEXT", NULL, NULL, NULL},
{ EXT_IRQ, EXT_IRQ, "EXT", "EXT", NULL, NULL, NULL, "External Irq"},
{ EXT_IRQ, EXT_IRQ, "EXT", "EXT", NULL, NULL, NULL,
"SET CPU EXT causes external interrupt"},
{ MTAB_XTD|MTAB_VDV|MTAB_NMO|MTAB_SHP, 0, "HISTORY", "HISTORY",
&cpu_set_hist, &cpu_show_hist },
{ 0 }
@ -474,7 +475,7 @@ void storepsw(uint32 addr, uint16 ircode) {
hst[hst_p].src2 = word2;
hst[hst_p].addr1 = ircode;
}
sim_debug(DEBUG_INST, &cpu_dev, "store %02x %d %x %03x PSW=%08x %08x\n\r", addr, ilc,
sim_debug(DEBUG_INST, &cpu_dev, "store %02x %d %x %03x PSW=%08x %08x\n", addr, ilc,
cc, ircode, word, word2);
irqcode = ircode;
}
@ -1606,28 +1607,28 @@ opr:
if (flags & PROBLEM)
storepsw(OPPSW, IRC_PRIV);
else
cc = startio(addr1 & 0xfff);
cc = startio(addr1 & 0x1fff);
break;
case OP_TIO:
if (flags & PROBLEM)
storepsw(OPPSW, IRC_PRIV);
else
cc = testio(addr1 & 0xfff);
cc = testio(addr1 & 0x1fff);
break;
case OP_HIO:
if (flags & PROBLEM)
storepsw(OPPSW, IRC_PRIV);
else
cc = haltio(addr1 & 0xfff);
cc = haltio(addr1 & 0x1fff);
break;
case OP_TCH:
if (flags & PROBLEM)
storepsw(OPPSW, IRC_PRIV);
else
cc = testchan(addr1 & 0xfff);
cc = testchan(addr1 & 0x1fff);
break;
case OP_DIAG:
@ -1737,6 +1738,15 @@ set_cc3:
}
src1 = regs[reg1|1];
case OP_MH:
#ifdef USE_64BIT
src1L = (((t_int64) ((t_uint64)src1 << 32)) >> 32) * (int32)src2;
if (op != OP_MH) {
STDBL(reg1, src1L);
} else {
regs[reg1] = (uint32)(src1L & FMASK);
per_mod |= 1 << reg1;
}
#else
fill = 0;
if (src1 & MSIGN) {
@ -1747,17 +1757,6 @@ set_cc3:
fill ^= 1;
src2 = NEG(src2);
}
#ifdef USE_64BIT
src1L = ((t_uint64)src1) * ((t_uint64)src2);
if (fill)
src1L = NEG(src1L);
if (op != OP_MH) {
STDBL(reg1, src1L);
} else {
regs[reg1] = (uint32)(src1L & FMASK);
per_mod |= 1 << reg1;
}
#else
src1h = 0;
if (src1 != 0 || src2 != 0) {
for (reg = 32; reg > 0; reg--) {
@ -2267,7 +2266,7 @@ save_dbl:
goto supress;
cregs[reg1] = dest;
sim_debug(DEBUG_INST, &cpu_dev,
"Loading: CR %x %06x %08x IC=%08x %x\n\r",
"Loading: CR %x %06x %08x IC=%08x %x\n",
reg1, addr1, dest, PC, reg);
switch (reg1) {
case 0x0: /* Segment table address */
@ -3275,7 +3274,7 @@ save_dbl:
goto supress;
cregs[reg1] = dest;
sim_debug(DEBUG_INST, &cpu_dev,
"Loading: CR %x %06x %08x IC=%08x %x\n\r",
"Loading: CR %x %06x %08x IC=%08x %x\n",
reg1, addr1, dest, PC, reg);
switch (reg1) {
case 0x0: /* General control register */
@ -3324,6 +3323,10 @@ save_dbl:
~page_mask) & AMASK) >> page_shift;
intval_en = ((dest & 0x400) != 0);
tod_en = ((dest & 0x800) != 0);
for (temp = 0;
temp < sizeof(tlb)/sizeof(uint32);
temp++)
tlb[temp] = 0;
break;
case 0x1: /* Segment table address and length */
seg_addr = dest & AMASK;
@ -5901,73 +5904,181 @@ check_tod_irq()
t_stat cpu_ex (t_value *vptr, t_addr exta, UNIT *uptr, int32 sw)
{
uint32 addr = (uint32) exta;
uint32 byte;
uint32 offset = 8 * (3 - (addr & 0x3));
uint32 addr = (uint32) exta;
uint32 byte;
uint32 offset = 8 * (3 - (addr & 0x3));
if (vptr == NULL)
return SCPE_ARG;
/* Ignore high order bits */
addr &= AMASK;
if (addr >= MEMSIZE)
return SCPE_NXM;
addr >>= 2;
byte = M[addr] >> offset;
byte &= 0xff;
*vptr = byte;
return SCPE_OK;
if (vptr == NULL)
return SCPE_ARG;
if (sw & SWMASK ('V')) {
/* Virtual address, simulate LRA */
uint32 seg;
uint32 page;
uint32 entry;
uint32 addr1, addr2;
if ((cpu_unit[0].flags & FEAT_DAT) == 0)
return SCPE_NXM;
/* Segment number to word address */
addr1 = addr & AMASK;
seg = (addr1 >> seg_shift) & seg_mask;
page = (addr1 >> page_shift) & page_index;
if (seg > seg_len)
return SCPE_NXM;
addr2 = (((seg << 2) + seg_addr) & AMASK);
if (addr2 >= MEMSIZE)
return SCPE_NXM;
/* Check if entry valid */
entry = M[addr2 >> 2];
if (entry & PTE_VALID)
return SCPE_NXM;
if ((cpu_unit[0].flags & FEAT_370) != 0) {
addr2 = (entry >> 28) + 1;
/* Check if over end of table */
if ((page >> pte_len_shift) > addr2)
return SCPE_NXM;
} else {
addr2 = (entry >> 24);
if (page > addr2)
return SCPE_NXM;
}
/* Now we need to fetch the actual entry */
addr2 = (entry & PTE_ADR) + (page << 1);
addr2 &= AMASK;
if (addr2 >= MEMSIZE)
return SCPE_NXM;
entry = M[addr2 >> 2];
entry >>= (addr2 & 2) ? 0 : 16;
entry &= 0xffff;
/* Check if entry valid */
if (entry & pte_avail)
return SCPE_NXM;
addr = (addr1 & page_mask) | ((entry & 0xfff8) << 8);
}
/* Real address, just return it, but ignore high order bits */
addr &= AMASK;
if (addr >= MEMSIZE)
return SCPE_NXM;
addr >>= 2;
byte = M[addr] >> offset;
byte &= 0xff;
*vptr = byte;
return SCPE_OK;
}
/* Memory deposit */
t_stat cpu_dep (t_value val, t_addr exta, UNIT *uptr, int32 sw)
{
uint32 addr = (uint32) exta;
uint32 offset = 8 * (3 - (addr & 0x3));
uint32 word;
uint32 mask;
uint32 addr = (uint32) exta;
uint32 offset = 8 * (3 - (addr & 0x3));
uint32 word;
uint32 mask;
/* Ignore high order bits */
addr &= AMASK;
if (addr >= MEMSIZE)
return SCPE_NXM;
addr >>= 2;
mask = 0xff << offset;
word = M[addr];
word &= ~mask;
word |= (val & 0xff) << offset;
M[addr] = word;
return SCPE_OK;
if (sw & SWMASK ('V')) {
/* Virtual address, simulate LRA */
uint32 seg;
uint32 page;
uint32 entry;
uint32 addr1, addr2;
if ((cpu_unit[0].flags & FEAT_DAT) == 0)
return SCPE_NXM;
/* Segment number to word address */
addr1 = addr & AMASK;
seg = (addr1 >> seg_shift) & seg_mask;
page = (addr1 >> page_shift) & page_index;
if (seg > seg_len)
return SCPE_NXM;
addr2 = (((seg << 2) + seg_addr) & AMASK);
if (addr2 >= MEMSIZE)
return SCPE_NXM;
/* Check if entry valid */
entry = M[addr2 >> 2];
if (entry & PTE_VALID)
return SCPE_NXM;
if ((cpu_unit[0].flags & FEAT_370) != 0) {
addr2 = (entry >> 28) + 1;
/* Check if over end of table */
if ((page >> pte_len_shift) > addr2)
return SCPE_NXM;
} else {
addr2 = (entry >> 24);
if (page > addr2)
return SCPE_NXM;
}
/* Now we need to fetch the actual entry */
addr2 = (entry & PTE_ADR) + (page << 1);
addr2 &= AMASK;
if (addr2 >= MEMSIZE)
return SCPE_NXM;
entry = M[addr2 >> 2];
entry >>= (addr2 & 2) ? 0 : 16;
entry &= 0xffff;
/* Check if entry valid */
if (entry & pte_avail)
return SCPE_NXM;
addr = (addr1 & page_mask) | ((entry & 0xfff8) << 8);
}
/* Ignore high order bits */
addr &= AMASK;
if (addr >= MEMSIZE)
return SCPE_NXM;
addr >>= 2;
mask = 0xff << offset;
word = M[addr];
word &= ~mask;
word |= (val & 0xff) << offset;
M[addr] = word;
return SCPE_OK;
}
/* Memory allocation */
t_stat cpu_set_size (UNIT *uptr, int32 val, CONST char *cptr, void *desc)
{
int32 mc = 0;
int32 i, clim;
uint32 *nM = NULL;
int32 max = MEMSIZE >> 2;
int32 mc = 0;
int32 i, clim;
uint32 *nM = NULL;
int32 max = MEMSIZE >> 2;
val = 16 * 1024 * val;
if ((val <= 0) || (val > MAXMEMSIZE))
return SCPE_ARG;
for (i = val>>2; i < max; i++)
mc = mc | M[i];
if ((mc != 0) && !get_yn ("Really truncate memory [N]?", FALSE))
return SCPE_OK;
nM = (uint32 *) calloc (val >> 2, sizeof (uint32));
if (nM == NULL)
return SCPE_MEM;
clim = ((t_addr)val < MEMSIZE)? val >> 2: max;
for (i = 0; i < clim; i++)
nM[i] = M[i];
free (M);
M = nM;
fprintf(stderr, "Mem size=%x\n\r", val);
MEMSIZE = val;
reset_all (0);
return SCPE_OK;
val = 16 * 1024 * val;
if ((val <= 0) || (val > MAXMEMSIZE))
return SCPE_ARG;
for (i = val>>2; i < max; i++)
mc = mc | M[i];
if ((mc != 0) && !get_yn ("Really truncate memory [N]?", FALSE))
return SCPE_OK;
nM = (uint32 *) calloc (val >> 2, sizeof (uint32));
if (nM == NULL)
return SCPE_MEM;
clim = ((t_addr)val < MEMSIZE)? val >> 2: max;
for (i = 0; i < clim; i++)
nM[i] = M[i];
free (M);
M = nM;
fprintf(stderr, "Mem size=%x\n\r", val);
MEMSIZE = val;
reset_all (0);
return SCPE_OK;
}
/* Handle execute history */

View File

@ -47,7 +47,7 @@
384 - +6 0x1xx - 0x6xx
Channels 1,2,3,5,6 are selector channels.
Devices on channel 0 below number of subchannels have there own
Devices on channel 0 below number of subchannels have their own
virtual channel.
Devices on channel 0 above the number of subchannels are mapped in
groups of 16 into channels 0 to n.

View File

@ -197,7 +197,7 @@ print_line(UNIT * uptr)
/* Print out buffer */
sim_fwrite(&out, 1, i, uptr->fileref);
uptr->pos += i;
sim_debug(DEBUG_DETAIL, &lpr_dev, "%s", out);
sim_debug(DEBUG_DETAIL, &lpr_dev, "%s\n", out);
}
if (l < 4) {
@ -343,9 +343,10 @@ lpr_srv(UNIT *uptr) {
int u = (uptr - lpr_unit);
int cmd = (uptr->CMD & 0x7);
int l = (uptr->CMD >> 3) & 0x1f;
uint8 ch;
if (cmd == 4) {
uint8 ch = uptr->SNS;
ch = uptr->SNS;
uptr->CMD &= ~(LPR_CMDMSK);
chan_write_byte(addr, &ch);
chan_end(addr, SNS_DEVEND|SNS_CHNEND);
@ -355,6 +356,7 @@ lpr_srv(UNIT *uptr) {
if (cmd == 7) {
uptr->CMD &= ~(LPR_FULL|LPR_CMDMSK);
uptr->POS = 0;
chan_read_byte(addr, &ch);
chan_end(addr, SNS_DEVEND|SNS_CHNEND);
return SCPE_OK;
}
@ -366,19 +368,19 @@ lpr_srv(UNIT *uptr) {
else
uptr->CMD |= LPR_DATCHK;
uptr->CMD &= ~(LPR_CMDMSK);
chan_read_byte(addr, &ch);
chan_end(addr, SNS_DEVEND|SNS_CHNEND);
return SCPE_OK;
}
/* Handle UCS Load */
if ((uptr->CMD & 0xf7) == 0xf3) {
uint8 ch;
for (l = 0; l < 240; l++) {
if(chan_read_byte(addr, &ch))
break;
}
chan_end(addr, SNS_DEVEND|SNS_CHNEND);
uptr->CMD &= ~(LPR_CMDMSK);
chan_end(addr, SNS_DEVEND|SNS_CHNEND);
return SCPE_OK;
}

View File

@ -114,7 +114,7 @@ DEBTAB crd_debug[] = {
const char *sim_stop_messages[] = {
"Unknown error",
"HALT instruction",
"Uninterruptable wait",
"Breakpoint"
};