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:
parent
84c38215da
commit
37ed26e6c9
@ -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
|
||||
|
||||
@ -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;
|
||||
}
|
||||
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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 */
|
||||
|
||||
@ -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:
|
||||
|
||||
@ -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 */
|
||||
|
||||
@ -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.
|
||||
|
||||
@ -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;
|
||||
}
|
||||
|
||||
|
||||
@ -114,7 +114,7 @@ DEBTAB crd_debug[] = {
|
||||
|
||||
const char *sim_stop_messages[] = {
|
||||
"Unknown error",
|
||||
"HALT instruction",
|
||||
"Uninterruptable wait",
|
||||
"Breakpoint"
|
||||
};
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user