1
0
mirror of https://github.com/rcornwell/sims.git synced 2026-02-13 03:15:02 +00:00
Files
rcornwell.sims/IBM360/ibm360_cpu.c

2236 lines
71 KiB
C
Raw Blame History

This file contains invisible Unicode characters
This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/* ibm360_cpu.c: ibm 360 cpu simulator.
Copyright (c) 2017, Richard Cornwell
Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the "Software"),
to deal in the Software without restriction, including without limitation
the rights to use, copy, modify, merge, publish, distribute, sublicense,
and/or sell copies of the Software, and to permit persons to whom the
Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
RICHARD CORNWELL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#include "ibm360_defs.h" /* simulator defns */
#define FEAT_PROT (1 << (UNIT_V_UF + 8)) /* Storage protection feature */
#define FEAT_DEC (1 << (UNIT_V_UF + 9)) /* Decimal instruction set */
#define FEAT_FLOAT (1 << (UNIT_V_UF + 10)) /* Floating point instruction set */
#define FEAT_UNIV (3 << (UNIT_V_UF + 9)) /* All instructions */
#define FEAT_STOR (1 << (UNIT_V_UF + 11)) /* No alignment restrictions */
#define FEAT_TIMER (1 << (UNIT_V_UF + 12)) /* Interval timer */
#define EXT_IRQ (1 << (UNIT_V_UF_31)) /* External interrupt */
#define UNIT_V_MSIZE (UNIT_V_UF + 0) /* dummy mask */
#define UNIT_MSIZE (0xff << UNIT_V_MSIZE)
#define MEMAMOUNT(x) (x << UNIT_V_MSIZE)
#define TMR_RTC 0
#define HIST_MAX 5000000
#define HIST_MIN 64
#define HIST_PC 0x1000000
#define HIST_SPW 0x2000000
#define HIST_LPW 0x4000000
uint32 *M = NULL;
uint8 key[MAXMEMSIZE/2048];
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 st_key; /* Storage key */
uint8 cc; /* CC */
uint8 ilc; /* Instruction length code */
uint8 pmsk; /* Program mask */
uint16 irqcode; /* Interupt code */
uint8 flags; /* Misc flags */
uint16 irqaddr; /* Address of IRQ vector */
uint16 loading; /* Doing IPL */
uint8 interval_irq = 0; /* Interval timer IRQ */
#define ASCII 0x08 /* ASCII/EBCDIC mode */
#define MCHECK 0x04 /* Machine check flag */
#define WAIT 0x02
#define PROBLEM 0x01 /* Problem state */
#define FIXOVR 0x08 /* Fixed point overflow */
#define DECOVR 0x04 /* Decimal overflow */
#define EXPOVR 0x02 /* Exponent overflow */
#define SIGMSK 0x01 /* Significance */
/* low addresses */
#define IPSW 0x00 /* IPSW */
#define ICCW1 0x08 /* ICCW1 */
#define ICCW2 0x10 /* ICCW2 */
#define OEPSW 0x18 /* External old PSW */
#define OSPSW 0x20 /* Supervisior call old PSW */
#define OPPSW 0x28 /* Program old PSW */
#define OMPSW 0x30 /* Machine check PSW */
#define OIOPSW 0x38 /* IO old PSW */
#define CSW 0x40 /* CSW */
#define CAW 0x48 /* CAW */
#define TIMER 0x50 /* timer */
#define NEPSW 0x58 /* External new PSW */
#define NSPSW 0x60 /* SVC new PSW */
#define NPPSW 0x68 /* Program new PSW */
#define NMPSW 0x70 /* Machine Check PSW */
#define NIOPSW 0x78 /* IOPSW */
#define DIAGAREA 0x80 /* Diag scan area. */
#define IRC_OPR 0x0001 /* Operations exception */
#define IRC_PRIV 0x0002 /* Privlege violation */
#define IRC_EXEC 0x0003 /* Execution */
#define IRC_PROT 0x0004 /* Protection violation */
#define IRC_ADDR 0x0005 /* Address error */
#define IRC_SPEC 0x0006 /* Specification error */
#define IRC_DATA 0x0007 /* Data exception */
#define IRC_FIXOVR 0x0008 /* Fixed point overflow */
#define IRC_FIXDIV 0x0009 /* Fixed point divide */
#define IRC_DECOVR 0x000a /* Decimal overflow */
#define IRC_DECDIV 0x000b /* Decimal divide */
#define IRC_EXPOVR 0x000c /* Exponent overflow */
#define IRC_EXPUND 0x000d /* Exponent underflow */
#define IRC_SIGNIF 0x000e /* Significance error */
#define IRC_FPDIV 0x000f /* Floating pointer divide */
#define AMASK 0x00ffffff /* Mask address bits */
#define MSIGN 0x80000000 /* Minus sign */
#define MMASK 0x00ffffff /* Mantissa mask */
#define EMASK 0x7f000000 /* Exponent mask */
#define XMASK 0x0fffffff /* Working FP mask */
#define CMASK 0xf0000000 /* Carry mask */
#define R1(x) (((x)>>4) & 0xf)
#define R2(x) ((x) & 0xf)
#define B1(x) (((x) >> 12) & 0xf)
#define D1(x) ((x) & 0xfff)
#define X2(x) R2(x)
int hst_lnt;
int hst_p;
struct InstHistory
{
uint32 pc;
uint32 addr1;
uint32 addr2;
uint32 src1;
uint32 src2;
uint32 dest;
uint16 inst[3];
uint8 op;
uint8 reg;
uint8 cc;
};
struct InstHistory *hst = NULL;
/* Forward and external declarations */
t_stat cpu_ex (t_value *vptr, t_addr addr, UNIT *uptr, int32 sw);
t_stat cpu_dep (t_value val, t_addr addr, UNIT *uptr, int32 sw);
t_stat cpu_reset (DEVICE *dptr);
t_stat cpu_set_size (UNIT *uptr, int32 val, CONST char *cptr, void *desc);
t_stat cpu_set_hist (UNIT *uptr, int32 val, CONST char *cptr, void *desc);
t_stat cpu_show_hist (FILE *st, UNIT *uptr, int32 val, CONST void *desc);
t_stat cpu_help (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag,
const char *cptr);
const char *cpu_description (DEVICE *dptr);
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;
/* CPU data structures
cpu_dev CPU device descriptor
cpu_unit CPU unit
cpu_reg CPU register list
cpu_mod CPU modifier list
*/
UNIT cpu_unit = { UDATA (&rtc_srv, UNIT_BINK, MAXMEMSIZE) };
REG cpu_reg[] = {
{ HRDATA (PC, PC, 24) },
{ HRDATA (R0, regs[00], 32) }, /* addr in memory */
{ HRDATA (R1, regs[01], 32) }, /* modified at exit */
{ HRDATA (R2, regs[02], 32) }, /* to SCP */
{ HRDATA (R3, regs[03], 32) },
{ HRDATA (R4, regs[04], 32) },
{ HRDATA (R5, regs[05], 32) },
{ HRDATA (R6, regs[06], 32) },
{ HRDATA (R7, regs[07], 32) },
{ HRDATA (R8, regs[010], 32) },
{ HRDATA (R9, regs[011], 32) },
{ HRDATA (R10, regs[012], 32) },
{ HRDATA (R11, regs[013], 32) },
{ HRDATA (R12, regs[014], 32) },
{ HRDATA (R13, regs[015], 32) },
{ HRDATA (R14, regs[016], 32) },
{ HRDATA (R15, regs[017], 32) },
{ BRDATA (R, regs, 16, 32, 017) },
{ NULL }
};
MTAB cpu_mod[] = {
{ MTAB_XTD|MTAB_VDV, 0, "IDLE", "IDLE", &sim_set_idle, &sim_show_idle },
{ MTAB_XTD|MTAB_VDV, 0, NULL, "NOIDLE", &sim_clr_idle, NULL },
{ UNIT_MSIZE, MEMAMOUNT(1), "16K", "16K", &cpu_set_size },
{ UNIT_MSIZE, MEMAMOUNT(2), "32K", "32K", &cpu_set_size },
{ UNIT_MSIZE, MEMAMOUNT(4), "64K", "64K", &cpu_set_size },
{ UNIT_MSIZE, MEMAMOUNT(8), "128K", "128K", &cpu_set_size },
{ UNIT_MSIZE, MEMAMOUNT(12), "196K", "196K", &cpu_set_size },
{ UNIT_MSIZE, MEMAMOUNT(16), "256K", "256K", &cpu_set_size },
{ UNIT_MSIZE, MEMAMOUNT(32), "512K", "512K", &cpu_set_size },
{ 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_STOR, FEAT_STOR, "STORE", "STORE", NULL, NULL, NULL, "No storage alignment"},
{ FEAT_TIMER, 0, NULL, "NOTIMER", NULL, NULL},
{ FEAT_TIMER, FEAT_TIMER, "TIMER", "TIMER", NULL, NULL, NULL, "Interval timer"},
{ 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",
&cpu_set_hist, &cpu_show_hist },
{ 0 }
};
DEVICE cpu_dev = {
"CPU", &cpu_unit, cpu_reg, cpu_mod,
1, 16, 24, 1, 16, 8,
&cpu_ex, &cpu_dep, &cpu_reset, NULL, NULL, NULL,
NULL, DEV_DEBUG, 0, dev_debug,
// NULL, NULL, &cpu_help, NULL, NULL, &cpu_description
};
#if 0 /* 370 Operators */
MVCL 0e
CLCL 0f
STNSM ac SI
STOSM ad SI
SIGP ae RS
MC af SI
LRA B1 RX
spec B2 S
STCTL B6 RS
LCTL B7 RS
CS BA RS
CDS bb RS
CLM bd RS
STCM BE RS
ICM BF RS
#endif
void post_extirq() {
cpu_unit.flags |= EXT_IRQ;
}
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);
irqaddr = addr + 0x40;
word = (((uint32)sysmsk) << 24) |
(((uint32)st_key) << 16) |
(((uint32)flags) << 16) |
((uint32)ircode);
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;
}
irqcode = ircode;
}
/*
* Read a full word from memory, checking protection
* and alignment restrictions. Return 1 if failure, 0 if
* success.
*/
int ReadFull(uint32 addr, uint32 *data) {
uint32 temp;
int offset;
uint8 k;
/* Ignore high order bits */
addr &= AMASK;
if (addr >= MEMSIZE) {
storepsw(OPPSW, IRC_ADDR);
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 >> 10];
if ((k & 0x8) != 0 && (k & 0xf0) != st_key) {
storepsw(OPPSW, IRC_PROT);
return 1;
}
}
if (offset != 0) {
if ((cpu_unit.flags & FEAT_STOR) == 0) {
storepsw(OPPSW, IRC_SPEC);
return 1;
}
temp = M[addr];
}
*data = M[addr];
sim_debug(DEBUG_DATA, &cpu_dev, "rd fu %08x %08x ", addr<<2, *data);
return 0;
}
int ReadByte(uint32 addr, uint32 *data) {
if (ReadFull(addr & (~0x3), data))
return 1;
*data >>= 8 * (3 - (addr & 0x3));
*data &= 0xff;
sim_debug(DEBUG_DATA, &cpu_dev, "rd by %08x %08x ", addr, *data);
return 0;
}
int ReadHalf(uint32 addr, uint32 *data) {
if (addr & 0x1) {
storepsw(OPPSW, IRC_SPEC);
return 1;
}
if (ReadFull(addr & (~0x3), data))
return 1;
*data >>= (addr & 2) ? 0 : 16;
*data &= 0xffff;
if (*data & 0x8000)
*data |= 0xffff0000;
sim_debug(DEBUG_DATA, &cpu_dev, "rd hf %08x %08x ", addr, *data);
return 0;
}
int WriteFull(uint32 addr, uint32 data) {
int offset;
uint8 k;
/* Ignore high order bits */
addr &= AMASK;
if (addr >= MEMSIZE) {
storepsw(OPPSW, IRC_ADDR);
return 1;
}
sim_debug(DEBUG_DATA, &cpu_dev, "wr fu %08x %08x ", addr, data);
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 >> 10];
if ((k & 0xf0) != st_key) {
storepsw(OPPSW, IRC_PROT);
return 1;
}
}
switch (offset) {
case 0:
M[addr] = data;
break;
case 1:
if ((cpu_unit.flags & FEAT_STOR) == 0) {
storepsw(OPPSW, IRC_SPEC);
return 1;
}
M[addr] &= 0xff000000;
M[addr] |= 0xffffff & (data >> 8);
M[addr+1] &= 0xffffff;
M[addr+1] |= 0xff000000 & (data << 24);
break;
case 2:
if ((cpu_unit.flags & FEAT_STOR) == 0) {
storepsw(OPPSW, IRC_SPEC);
return 1;
}
M[addr] &= 0xffff0000;
M[addr] |= 0xffff & (data >> 16);
M[addr+1] &= 0xffff;
M[addr+1] |= 0xffff0000 & (data << 16);
break;
case 3:
if ((cpu_unit.flags & FEAT_STOR) == 0) {
storepsw(OPPSW, IRC_SPEC);
return 1;
}
M[addr] &= 0xffffff00;
M[addr] |= 0xff & (data >> 24);
M[addr+1] &= 0xff;
M[addr+1] |= 0xffffff00 & (data << 8);
break;
}
return 0;
}
int WriteByte(uint32 addr, uint32 data) {
uint32 mask;
uint8 k;
int offset;
/* Ignore high order bits */
addr &= AMASK;
if (addr >= MEMSIZE) {
storepsw(OPPSW, IRC_ADDR);
return 1;
}
sim_debug(DEBUG_DATA, &cpu_dev, "wr by %08x %02x ", addr, data);
offset = 8 * (3 - (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 >> 10];
if ((k & 0xf0) != st_key) {
storepsw(OPPSW, IRC_PROT);
return 1;
}
}
mask = 0xff;
data &= mask;
data <<= offset;
mask <<= offset;
M[addr] &= ~mask;
M[addr] |= data;
return 0;
}
int WriteHalf(uint32 addr, uint32 data) {
uint32 mask;
uint8 k;
int offset;
int o;
/* Ignore high order bits */
addr &= AMASK;
if (addr >= MEMSIZE) {
storepsw(OPPSW, IRC_ADDR);
return 1;
}
sim_debug(DEBUG_DATA, &cpu_dev, "wr hf %08x %04x ", addr, data);
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 >> 10];
if ((k & 0xf0) != st_key) {
storepsw(OPPSW, IRC_PROT);
return 1;
}
}
mask = 0xffff;
data &= mask;
switch (offset) {
case 0:
M[addr] &= ~(mask << 16);
M[addr] |= 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;
break;
case 2:
M[addr] &= ~mask;
M[addr] |= data;
break;
case 3:
if ((cpu_unit.flags & FEAT_STOR) == 0) {
storepsw(OPPSW, IRC_SPEC);
return 1;
}
M[addr] &= 0xffffff00;
M[addr] |= 0xff & (data >> 8);
M[addr+1] &= 0x00ffffff;
M[addr+1] |= 0xff000000 & (data << 24);
break;
}
return 0;
}
t_stat
sim_instr(void)
{
t_stat reason;
uint32 src1;
uint32 src1h;
uint32 src2;
uint32 src2h;
uint32 dest;
uint32 addr1;
uint32 addr2;
uint8 op;
uint8 fill;
uint8 reg;
uint8 reg1;
uint16 irq;
int e1, e2;
int temp, temp2;
t_uint64 t64;
t_uint64 t64a;
uint16 ops[3];
reason = SCPE_OK;
ilc = 0;
/* Enable timer if option set */
if (cpu_unit.flags & FEAT_TIMER) {
sim_activate(&cpu_unit, 100);
}
interval_irq = 0;
while (reason == SCPE_OK) {
wait_loop:
if (sim_interval <= 0) {
reason = sim_process_event();
if (reason != SCPE_OK)
return reason;
}
irq= scan_chan(sysmsk);
if (irq!= 0) {
ilc = 0;
if (loading) {
irqcode = irq;
(void)WriteHalf(0x2, irq);
loading = 0;
irqaddr = 0;
} else
storepsw(OIOPSW, irq);
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;
}
if (loading || flags & WAIT) {
/* CPU IDLE */
if (flags & WAIT && sysmsk == 0)
return STOP_HALT;
sim_interval--;
goto wait_loop;
}
if (sim_brk_summ && sim_brk_test(PC, SWMASK('E'))) {
return STOP_IBKPT;
}
if (PC & 1) {
ilc = 0;
storepsw(OPPSW, IRC_SPEC);
goto supress;
}
if (hst_lnt) {
hst_p = hst_p + 1;
if (hst_p >= hst_lnt)
hst_p = 0;
hst[hst_p].pc = PC | HIST_PC;
}
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);
ilc = 0;
if (ReadHalf(PC, &dest))
goto supress;
ops[0] = dest;
ilc = 1;
if (hst_lnt)
hst[hst_p].inst[0] = ops[0];
PC += 2;
reg = (uint8)(ops[0] & 0xff);
reg1 = R1(reg);
op = (uint8)(ops[0] >> 8);
/* Check if RX, RR, SI, RS, SS opcode */
if (op & 0xc0) {
if (ReadHalf(PC, &dest))
goto supress;
ops[1] = dest;
ilc = 2;
PC += 2;
if (hst_lnt)
hst[hst_p].inst[1] = ops[1];
/* Check if SS */
if ((op & 0xc0) == 0xc0) {
if (ReadHalf(PC, &dest))
goto supress;;
ops[2] = dest;
PC += 2;
ilc = 3;
if (hst_lnt)
hst[hst_p].inst[2] = ops[2];
}
}
if (sim_deb && (cpu_dev.dctrl & DEBUG_INST)) {
sim_debug(DEBUG_INST, &cpu_dev, "%d INST=%04x", ilc, ops[0]);
if (ops[0] & 0xc000) {
sim_debug(DEBUG_INST, &cpu_dev, "%04x", ops[1]);
if ((ops[0] & 0xc000) == 0xc000)
sim_debug(DEBUG_INST, &cpu_dev, "%04x", ops[2]);
else
sim_debug(DEBUG_INST, &cpu_dev, " ");
} else
sim_debug(DEBUG_INST, &cpu_dev, " ");
sim_debug(DEBUG_INST, &cpu_dev, " ");
fprint_inst(sim_deb, ops);
}
/* Add in history here */
opr:
/* If RX or RS or SS SI etc compute first address */
if (op & 0xc0) {
uint32 temp;
temp = B1(ops[1]);
addr1 = D1(ops[1]);
if (temp)
addr1 = (addr1 + regs[temp]) & AMASK;
/* Handle RX type operands */
if ((op & 0x80) == 0 && X2(reg) != 0)
addr1 = (addr1 + regs[X2(reg)]) & AMASK;
/* Check if SS */
if ((op & 0xc0) == 0xc0) {
temp = B1(ops[2]);
addr2 = D1(ops[2]);
if (temp)
addr2 = (addr2 + regs[temp]) & AMASK;
}
}
/* Check if floating point */
if ((op & 0xA0) == 0x20) {
if ((cpu_unit.flags & FEAT_FLOAT) == 0) {
storepsw(OPPSW, IRC_OPR);
goto supress;
}
if (reg1 & 0x9) {
storepsw(OPPSW, IRC_SPEC);
goto supress;
}
/* Load operands */
src1 = fpregs[reg1];
src1h = fpregs[reg1|1];
if (op & 0x40) {
if ((op & 0x10) != 0 && (addr1 & 0x7) != 0) {
storepsw(OPPSW, IRC_SPEC);
goto supress;
}
if (ReadFull(addr1, &src2))
goto supress;
if (op & 0x10) {
if (ReadFull(addr1+ 4, &src2h))
goto supress;
} else
src2h = 0;
} else {
if (reg & 0x9) {
storepsw(OPPSW, IRC_SPEC);
goto supress;
}
src2 = fpregs[reg];
src2h = fpregs[reg|1];
}
/* All RR opcodes */
} else if ((op & 0xe0) == 0) {
src1 = regs[reg1];
dest = src2 = regs[R2(reg)];
addr1 = dest & AMASK;
/* All RX integer ops */
} else if ((op & 0xe0) == 0x40) {
dest = src1 = regs[reg1];
/* Read half word if 010010xx or 01001100 */
if ((op & 0x1c) == 0x08 || op == OP_MH) {
if (ReadHalf(addr1, &src2))
goto supress;
/* Read full word if 0101xxx and not xxxx00xx (ST) */
} else if ((op & 0x10) && (op & 0x0c) != 0) {
if (ReadFull(addr1, &src2))
goto supress;
} else
src2 = addr1;
}
if (hst_lnt) {
hst[hst_p].op = op;
hst[hst_p].reg = reg;
hst[hst_p].addr1 = addr1;
hst[hst_p].addr2 = addr2;
hst[hst_p].src1 = src1;
hst[hst_p].src2 = src2;
}
sim_debug(DEBUG_INST, &cpu_dev, "\n");
/* Preform opcode */
switch (op) {
case OP_SPM:
dest = src1;
pmsk = (src1 >> 24) & 0xf;
cc = (src1 >> 28) & 0x3;
break;
case OP_BALR:
case OP_BAL:
dest = (((uint32)ilc) << 30) |
((uint32)(cc & 03) << 28) |
(((uint32)pmsk) << 24) | PC;
if (op != OP_BALR || R2(reg) != 0)
PC = addr1 & AMASK;
regs[reg1] = dest;
break;
case OP_BCTR:
case OP_BCT:
dest = src1 - 1;
if (dest != 0 && (op != OP_BCTR || R2(reg) != 0))
PC = addr1 & AMASK;
regs[reg1] = dest;
break;
case OP_BCR:
case OP_BC:
dest = src1;
if (((0x8 >> cc) & reg1) != 0 && (op != OP_BCR || R2(reg) != 0))
PC = addr1 & AMASK;
break;
case OP_BXH:
reg = R2(reg);
src1 = regs[reg|1];
dest = regs[reg1] = regs[reg1] + regs[reg];
if ((int32)dest > (int32)src1)
PC = addr1 & AMASK;
break;
case OP_BXLE:
reg = R2(reg);
src1 = regs[reg|1];
dest = regs[reg1] = regs[reg1] + regs[reg];
if ((int32)dest <= (int32)src1)
PC = addr1 & AMASK;
break;
case OP_SSK:
dest = src1;
if ((cpu_unit.flags & FEAT_PROT) == 0) {
storepsw(OPPSW, IRC_OPR);
} else if (flags & PROBLEM) {
storepsw(OPPSW, IRC_PRIV);
} else if ((addr1 & 0xF) != 0) {
storepsw(OPPSW, IRC_SPEC);
} else if (addr1 >= MEMSIZE) {
storepsw(OPPSW, IRC_ADDR);
} else if (cpu_unit.flags & FEAT_PROT) {
key[addr1 >> 12] = src1 & 0xf8;
}
break;
case OP_ISK:
dest = src1;
if ((cpu_unit.flags & FEAT_PROT) == 0) {
storepsw(OPPSW, IRC_PROT);
} if (flags & PROBLEM) {
storepsw(OPPSW, IRC_PRIV);
} else if ((addr1 & 0xF) != 0) {
storepsw(OPPSW, IRC_SPEC);
} else if (addr1 >= MEMSIZE) {
storepsw(OPPSW, IRC_ADDR);
} else {
dest &= 0xffffff00;
dest |= key[addr1 >> 12];
regs[reg1] = dest;
}
break;
case OP_SVC:
storepsw(OSPSW, reg);
break;
case OP_SSM:
if (flags & PROBLEM) {
storepsw(OPPSW, IRC_PRIV);
} else {
ReadByte(addr1, &src1);
sysmsk = src1 & 0xff;
irq_pend = 1;
}
break;
case OP_LPSW:
if (flags & PROBLEM) {
storepsw(OPPSW, IRC_PRIV);
} else if ((addr1 & 0x7) != 0) {
storepsw(OPPSW, IRC_SPEC);
} else {
if (ReadFull(addr1, &src1))
goto supress;
if (ReadFull(addr1+4, &src2))
goto supress;
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;
hst[hst_p].src2 = src2;
}
goto lpsw;
}
break;
case OP_SIO:
if (flags & PROBLEM)
storepsw(OPPSW, IRC_PRIV);
else
cc = startio(addr1);
break;
case OP_TIO:
if (flags & PROBLEM)
storepsw(OPPSW, IRC_PRIV);
else
cc = testio(addr1);
break;
case OP_HIO:
if (flags & PROBLEM)
storepsw(OPPSW, IRC_PRIV);
else
cc = haltio(addr1);
break;
case OP_TCH:
if (flags & PROBLEM)
storepsw(OPPSW, IRC_PRIV);
else
cc = testchan(addr1);
break;
case OP_DIAG:
if (flags & PROBLEM)
storepsw(OPPSW, IRC_PRIV);
else
storepsw(OMPSW, reg);
break;
case OP_LPR:
if ((dest & MSIGN) == 0)
goto set_cc;
/* Fall through */
case OP_LCR:
if (dest == MSIGN)
goto set_cc3;
dest = -dest;
/* Fall through */
case OP_LTR:
set_cc:
regs[reg1] = dest;
cc = (dest & MSIGN) ? 1 : (dest == 0) ? 0 : 2;
break;
case OP_LNR:
if ((dest & MSIGN) == 0)
dest = -dest;
goto set_cc;
case OP_LA:
case OP_L:
case OP_LH:
case OP_LR:
dest = src2;
regs[reg1] = dest;
break;
case OP_C:
case OP_CR:
case OP_CH:
dest = src1;
cc = 0;
if ((int32)(src1) > (int32)(src2))
cc = 2;
else if (src1 != src2)
cc = 1;
break;
case OP_S:
case OP_SR:
case OP_SH:
src2 = -src2;
/* Fall through */
case OP_A:
case OP_AR:
case OP_AH:
dest = src1 + src2;
src1 = (src1 & MSIGN) != 0;
src2 = (src2 & MSIGN) != 0;
if ((src1 && src2 && (dest & MSIGN) == 0) ||
(!src1 && !src2 && (dest & MSIGN) != 0)) {
set_cc3:
regs[reg1] = dest;
cc = 3;
if (pmsk & FIXOVR)
storepsw(OPPSW, IRC_FIXOVR);
break;
}
goto set_cc;
case OP_SL:
case OP_SLR:
src2 = -src2;
/* Fall through */
case OP_AL:
case OP_ALR:
dest = src1 + src2;
cc = 0;
if ((uint32)dest < (uint32)src1)
cc |= 2;
if (dest != 0)
cc |= 1;
regs[reg1] = dest;
break;
case OP_CL:
case OP_CLR:
dest = src1;
cc = 0;
if ((uint32)(src1) > (uint32)(src2))
cc = 2;
else if (src1 != src2)
cc = 1;
break;
case OP_M:
case OP_MR:
if (reg1 & 1) {
storepsw(OPPSW, IRC_SPEC);
break;
}
src1 = regs[reg1|1];
case OP_MH:
fill = 0;
if (src1 & MSIGN) {
fill = 1;
src1 = -src1;
}
if (src2 & MSIGN) {
fill ^= 1;
src2 = -src2;
}
dest = 0;
if (src1 != 0 || src2 != 0) {
for (reg = 32; reg > 0; reg--) {
if (src1 & 1)
dest += src2;
src1 >>= 1;
if (dest & 1)
src1 |= MSIGN;
dest >>= 1;
}
}
if (fill) {
dest ^= 0xffffffff;
src1 ^= 0xffffffff;
if (src1 == 0xfffffff)
dest ++;
src1++;
}
if (op != OP_MH) {
regs[reg1|1] = src1;
regs[reg1] = dest;
} else {
regs[reg1] = src1;
}
break;
case OP_D:
case OP_DR:
if (reg1 & 1) {
storepsw(OPPSW, IRC_SPEC);
break;
}
fill = 0;
dest = src2;
src2 = regs[reg1|1];
src1 = regs[reg1];
if (dest == 0) {
storepsw(OPPSW, IRC_FIXDIV);
break;
}
t64 = (((t_uint64)src1) << 32) | ((t_uint64)src2);
if (src1 & MSIGN) {
fill = 3;
t64 = -t64;
}
if (dest & MSIGN) {
fill ^= 1;
dest = -dest;
}
t64a = t64 % (t_uint64)dest;
t64 = t64 / (t_uint64)dest;
if ((t64 & 0xffffffff80000000) != 0) {
storepsw(OPPSW, IRC_FIXDIV);
break;
}
src1 = (uint32)t64;
src2 = (uint32)t64a;
#if 0
if (src2 & MSIGN) {
fill = 3;
src2 ^= 0xffffffff;
src1 ^= 0xffffffff;
if (src1 == 0xfffffff)
src2 ++;
src1++;
}
if (dest & MSIGN) {
fill ^= 1;
dest = -dest;
}
src2 <<= 1;
if (src1 & MSIGN)
src2 |= 1;
src1 <<= 1;
for (reg = 0; reg < 32; reg++) {
int f = 0;
if (src1 < dest) {
src1 = src1 - dest;
f = 1;
}
src2 <<= 1;
src2 |= f;
if (src1 & MSIGN)
src2 |= 1;
src1 <<= 1;
}
#endif
if (fill & 1)
src1 = -src1;
if (fill & 2)
src2 = -src2;
regs[reg1] = src2;
regs[reg1|1] = src1;
break;
case OP_NR:
case OP_N:
dest = src1 & src2;
cc = (dest == 0) ? 0 : 1;
regs[reg1] = dest;
break;
case OP_OR:
case OP_O:
dest = src1 | src2;
cc = (dest == 0) ? 0 : 1;
regs[reg1] = dest;
break;
case OP_XR:
case OP_X:
dest = src1 ^ src2;
cc = (dest == 0) ? 0 : 1;
regs[reg1] = dest;
break;
case OP_MVI:
src1 = reg;
/* Fall through */
case OP_STC:
WriteByte(addr1, src1);
break;
case OP_NI:
if (ReadByte(addr1, &dest))
break;
if (hst_lnt)
hst[hst_p].src1 = dest;
dest &= reg;
char_save:
cc = (dest == 0) ? 0 : 1;
WriteByte(addr1, dest);
break;
case OP_OI:
if (ReadByte(addr1, &dest))
break;
if (hst_lnt)
hst[hst_p].src1 = dest;
dest |= reg;
goto char_save;
case OP_XI:
if (ReadByte(addr1, &dest))
break;
if (hst_lnt)
hst[hst_p].src1 = dest;
dest ^= reg;
goto char_save;
case OP_CLI:
if (ReadByte(addr1, &dest))
break;
if (hst_lnt)
hst[hst_p].src1 = dest;
dest &= 0xff;
cc = (dest == reg) ? 0 : (dest < reg) ? 1 : 2;
break;
case OP_IC:
if (ReadByte(addr1, &dest))
break;
dest = (src1 & 0xffffff00) | (dest & 0xff);
regs[reg1] = dest;
break;
case OP_ST:
dest = src1;
WriteFull(addr1, dest);
break;
case OP_STH:
dest = src1;
WriteHalf(addr1, dest);
break;
case OP_TS:
dest = 0xff;
if (ReadByte(addr1, &src1))
break;
if (hst_lnt)
hst[hst_p].src1 = src1;
cc = (src1 & 0x80) ? 1 : 0;
WriteByte(addr1, dest);
break;
case OP_TM:
if (ReadByte(addr1, &dest))
break;
if (hst_lnt)
hst[hst_p].src1 = dest;
dest &= reg;
if (dest != 0) {
if (reg == dest)
cc = 3;
else
cc = 1;
} else
cc = 0;
break;
case OP_SRL:
dest = regs[reg1];
if (hst_lnt)
hst[hst_p].src1 = dest;
dest = ((uint32)dest) >> (addr1 & 0x3f);
regs[reg1] = dest;
break;
case OP_SLL:
dest = regs[reg1];
if (hst_lnt)
hst[hst_p].src1 = dest;
dest = ((uint32)dest) << (addr1 & 0x3f);
regs[reg1] = dest;
break;
case OP_SRA:
dest = regs[reg1];
if (hst_lnt)
hst[hst_p].src1 = dest;
dest = (int32)dest >> (addr1 & 0x3f);
goto set_cc;
case OP_SLA:
dest = regs[reg1];
if (hst_lnt)
hst[hst_p].src1 = dest;
src2 = dest & MSIGN;
dest &= ~MSIGN;
addr1 &= 0x3f;
cc = 0;
while (addr1 > 0) {
dest <<= 1;
if ((dest & MSIGN) != src2)
cc = 3;
addr1--;
}
dest |= src2;
if (cc == 3)
goto set_cc3;
else
goto set_cc;
break;
case OP_SRDL:
if (reg & 1)
storepsw(OPPSW, IRC_SPEC);
else {
src1 = regs[reg1];
src1h = regs[reg1|1];
if (hst_lnt) {
hst[hst_p].src1 = src1;
hst[hst_p].src2 = src1h;
}
addr1 &= 0x3f;
while(addr1 > 0) {
src1h >>= 1;
if (src1 & 1)
src1h |= MSIGN;
src1 >>= 1;
addr1--;
}
regs[reg1|1] = src1h;
regs[reg1] = src1;
dest = src1;
}
break;
case OP_SLDL:
if (reg & 1)
storepsw(OPPSW, IRC_SPEC);
else {
src1 = regs[reg1];
src1h = regs[reg1|1];
if (hst_lnt) {
hst[hst_p].src1 = src1;
hst[hst_p].src2 = src1h;
}
addr1 &= 0x3f;
while(addr1 > 0) {
src1 <<= 1;
if (src1h & MSIGN)
src1 |= 1;
src1h <<= 1;
addr1--;
}
regs[reg1|1] = src1h;
regs[reg1] = src1;
dest = src1;
}
break;
case OP_SLDA:
if (reg & 1)
storepsw(OPPSW, IRC_SPEC);
else {
src1 = regs[reg1];
src1h = regs[reg1|1];
if (hst_lnt) {
hst[hst_p].src1 = src1;
hst[hst_p].src2 = src1h;
}
dest = src1 & MSIGN;
addr1 &= 0x3f;
cc = 0;
while(addr1 > 0) {
src1 <<= 1;
if ((src1 & MSIGN) != dest)
cc = 3;
if (src1h & MSIGN)
src1 |= 1;
src1h <<= 1;
addr1--;
}
save_dbl:
regs[reg1|1] = src1h;
regs[reg1] = src1;
dest = src1;
if (cc != 3 && (src1 | src1h) != 0)
cc = (src1 & MSIGN) ? 1 : 2;
if (cc == 3 && (pmsk & FIXOVR))
storepsw(OPPSW, IRC_FIXOVR);
}
break;
case OP_SRDA:
if (reg & 1)
storepsw(OPPSW, IRC_SPEC);
else {
src1 = regs[reg1];
src1h = regs[reg1|1];
dest = src1 & MSIGN;
addr1 &= 0x3f;
cc = 0;
while(addr1 > 0) {
src1h >>= 1;
if (src1 & 1)
src1h |= MSIGN;
src1 >>= 1;
src1 |= dest;
addr1--;
}
goto save_dbl;
}
break;
case OP_STM:
reg &= 0xf;
for (;;) {
if (WriteFull(addr1, regs[reg1]))
goto supress;
if (reg1 == reg)
break;
reg1++;
reg1 &= 0xf;
addr1 += 4;
} ;
break;
case OP_LM:
reg &= 0xf;
for (;;) {
if (ReadFull(addr1, &regs[reg1]))
goto supress;
if (reg1 == reg)
break;
reg1++;
reg1 &= 0xf;
addr1 += 4;
};
break;
case OP_NC:
case OP_OC:
case OP_XC:
cc = 0;
/* Fall through */
case OP_MVN:
case OP_MVZ:
case OP_MVC:
do {
if (ReadByte(addr2, &src1))
break;
if (op != OP_MVC) {
if (ReadByte(addr1, &dest))
break;
switch(op) {
case OP_MVZ: dest = (dest & 0x0f) | (src1 & 0xf0); break;
case OP_MVN: dest = (dest & 0xf0) | (src1 & 0x0f); break;
case OP_NC: dest &= src1; if (dest != 0) cc = 1; break;
case OP_OC: dest |= src1; if (dest != 0) cc = 1; break;
case OP_XC: dest ^= src1; if (dest != 0) cc = 1; break;
}
} else {
dest = src1;
}
if (WriteByte(addr1, dest))
break;
addr1++;
addr2++;
reg--;
} while (reg != 0xff);
break;
case OP_CLC:
cc = 0;
do {
if (ReadByte(addr1, &src1))
break;
if (ReadByte(addr2, &src2))
break;
if (src1 != src2) {
dest = src1 - src2;
cc = (dest & MSIGN) ? 1 : (dest == 0) ? 0 : 2;
break;
}
addr1++;
addr2++;
reg--;
} while(reg != 0xff);
break;
case OP_TR:
do {
if (ReadByte(addr1, &src1))
break;
if (ReadByte(addr2 + (src1 & 0xff), &dest))
break;
if (WriteByte(addr1, dest))
break;
addr1++;
reg--;
} while (reg != 0xff);
break;
case OP_TRT:
cc = 0;
do {
if (ReadByte(addr1, &src1))
break;
if (ReadByte(addr2 + (src1 & 0xff), &dest))
break;
if (dest != 0) {
regs[1] &= 0xff000000;
regs[1] |= addr1 & AMASK;
regs[2] &= 0xffffff00;
regs[2] |= dest & 0xff;
cc = (reg == 0) ? 2 : 1;
break;
}
addr1++;
reg--;
} while(reg != 0xff);
break;
case OP_PACK:
reg &= 0xf;
addr2 += reg;
addr1 += reg1;
/* Flip first location */
if (ReadByte(addr2, &dest))
break;
dest = ((dest >> 4) & 0xf) | ((dest << 4) & 0xf0);
if (WriteByte(addr1, dest))
break;
addr1--;
addr2--;
dest = 0;
while(reg != 0 && reg1 != 0) {
if (ReadByte(addr2, &dest))
goto supress;
dest &= 0xf;
addr2--;
reg--;
if (reg != 0) {
if (ReadByte(addr2, &src1))
goto supress;
dest |= (src1 << 4) & 0xf0;
addr2--;
reg--;
}
if (WriteByte(addr1, dest))
goto supress;
addr1--;
reg1--;
};
dest = 0;
while(reg1 != 0) {
if (WriteByte(addr1, dest))
break;
addr1--;
reg1--;
};
break;
case OP_UNPK:
reg &= 0xf;
addr2 += reg;
addr1 += reg1;
if (ReadByte(addr2, &dest))
break;
dest = ((dest >> 4) & 0xf) | ((dest << 4) & 0xf0);
if (WriteByte(addr1, dest))
break;
addr1--;
addr2--;
src2 = (flags & ASCII)? 0x50 : 0xf0;
while(reg != 0 && reg1 != 0) {
if (ReadByte(addr2, &dest))
goto supress;
addr2--;
reg--;
src1 = (dest & 0xf) | src2;
if (WriteByte(addr1, src1))
goto supress;
addr1--;
reg1--;
if (reg1 != 0) {
src1 = ((dest >> 4) & 0xf) | src2;
if (WriteByte(addr1, src1))
goto supress;
addr1--;
reg1--;
}
};
while(reg1 != 0) {
if (WriteByte(addr1, src2))
break;
addr1--;
reg1--;
};
break;
case OP_MVO:
reg &= 0xf;
addr2 += reg;
addr1 += reg1;
if (ReadByte(addr1, &dest))
break;
if (ReadByte(addr2, &src1))
break;
addr2--;
dest = (dest & 0xf) | ((src1 << 4) & 0xf0);
WriteByte(addr1, dest);
addr1--;
while(reg1 != 0) {
dest = (src1 >> 4) & 0xf;
if (reg != 0) {
if (ReadByte(addr2, &src1))
break;
addr2--;
reg--;
} else
src1 = 0;
dest |= (src1 << 4) & 0xf0;
if (WriteByte(addr1, dest))
break;
reg1--;
addr1--;
};
break;
case OP_CVB:
if (ReadFull(addr1, &src1))
break;
if (ReadFull(addr1+4, &src1h))
break;
fill = src1h & 0xf; /* Save away sign */
if (fill < 0xA) {
storepsw(OPPSW, IRC_DATA);
break;
}
if (fill == 0xB || fill == 0xD)
fill = 1;
else
fill = 0;
dest = 0;
/* Convert upper first */
for(temp = 28; temp >= 0; temp-=4) {
int d = (src1 >> temp) & 0xf;
if (d > 0xA) {
storepsw(OPPSW, IRC_DATA);
break;
}
dest = (dest * 10) + d;
}
/* Convert lower */
for(temp = 28; temp > 0; temp-=4) {
int d = (src1h >> temp) & 0xf;
if (d > 0xA) {
storepsw(OPPSW, IRC_DATA);
break;
}
dest = (dest * 10) + d;
}
if (dest & MSIGN) {
storepsw(OPPSW, IRC_FIXDIV);
break;
}
if (fill)
dest = -dest;
regs[reg1] = dest;
break;
case OP_CVD:
dest = regs[reg1];
src1 = 0;
src1h = 0;
if (dest & MSIGN) {
dest = -dest;
fill = 1;
} else
fill = 0;
temp = 4;
while (dest != 0) {
int d = dest % 10;
dest /= 10;
if (temp > 32)
src1 |= (d << (temp - 32));
else
src1h |= (d << temp);
temp += 4;
}
if (fill) {
src1h |= ((flags & ASCII)? 0xb : 0xd);
} else {
src1h |= ((flags & ASCII)? 0xa : 0xc);
}
if (WriteFull(addr1, src1))
break;
WriteFull(addr1+4, src1h);
break;
case OP_ED:
case OP_EDMK:
if (ReadByte(addr1, &src1))
break;
fill = src1;
addr1++;
src2 = 0;
src1 = 1;
cc = 0;
while(reg != 0) {
uint8 t;
uint32 temp;
if (ReadByte(addr1, &temp))
break;
t = temp;
if (src1) {
if (ReadByte(addr2, &dest))
break;
addr2--;
reg --;
}
if (t == 0x21) {
src2 = 1;
t = 0x20;
if (op == OP_EDMK)
regs[1] = addr1;
}
if (t == 0x20) {
if (src2 || (dest >> (4*src1)) & 0xf) {
t = (dest >> (4*src1)) & 0xf;
t |= (flags & ASCII)?0x5:0xf;
if (!src2) {
src2 = 1;
if (op == OP_EDMK)
regs[1] = addr1;
}
if (t & 0xf)
cc = 2;
} else
t = fill;
if (WriteByte(addr1, t))
break;
} else if (t == 0x22) {
src2 = 0;
t = fill;
if (WriteByte(addr1, t))
break;
}
addr1--;
reg --;
src1 = !src1;
};
dest &= 0xf;
if (cc != 0 && (dest == 0xd || dest == 0xb))
cc = 1;
break;
case OP_EX:
if (addr1 & 1) {
storepsw(OPPSW, IRC_SPEC);
break;
}
if (ReadHalf(addr1, &dest))
break;
ops[0] = dest;
if (reg1) {
ops[0] |= src1 & 0xff;
}
reg = ops[0] & 0xff;
reg1 = R1(reg);
op = ops[0] >> 8;
if (hst_lnt) {
hst[hst_p].cc = cc;
hst_p = hst_p + 1;
if (hst_p >= hst_lnt)
hst_p = 0;
hst[hst_p].pc = addr1 | HIST_PC;
hst[hst_p].inst[0] = ops[0];
}
addr1 += 2;
if (op == OP_EX)
storepsw(OPPSW, IRC_EXEC);
/* Check if RX, RR, SI, RS, SS opcode */
else {
if (op & 0xc0) {
if (ReadHalf(addr1, &dest))
break;
ops[1] = dest;
addr1+=2;
/* Check if SS */
if ((op & 0xc0) == 0xc0) {
if(ReadHalf(addr1, &dest))
break;
ops[2] = dest;
}
if (hst_lnt) {
hst[hst_p].inst[1] = ops[1];
hst[hst_p].inst[2] = ops[2];
}
}
goto opr;
}
break;
/* Floating Half register */
case OP_HDR:
src2h >>= 1;
if (src2 & 1)
src2h |= MSIGN;
/* Fall through */
case OP_HER:
src2 = (src2 & (EMASK|MSIGN)) | ((src2 & MMASK) >> 1);
/* Fall through */
/* Floating Load register */
case OP_LER:
case OP_LDR:
case OP_LE:
case OP_LD:
if ((op & 0x10) == 0)
fpregs[reg1|1] = src2h;
fpregs[reg1] = src2;
break;
/* Floating Load register change sign */
case OP_LPDR:
case OP_LNDR:
case OP_LTDR:
case OP_LCDR:
case OP_LPER:
case OP_LNER:
case OP_LTER:
case OP_LCER:
if ((op & 0x2) == 0) /* LP, LT */
src2 &= ~MSIGN;
if ((op & 0x1)) /* LN, LC */
src2 ^= MSIGN;
cc = 0;
src1 = src2 & MMASK;
if ((op & 0x10) == 0) {
fpregs[reg1|1] = src2h;
src1 |= src2h;
}
if (src1 != 0)
cc = (src2 & MSIGN) ? 1 : 2;
fpregs[reg1] = src2;
break;
/* Floating Store register */
case OP_STD:
if (WriteFull(addr1 + 4, src1h))
break;
/* Fall through */
case OP_STE:
WriteFull(addr1, src1);
break;
/* Floating Compare */
case OP_CE: /* 79 */
case OP_CD: /* 69 */
case OP_CER: /* 39 */
case OP_CDR: /* 29 */
/* Floating Subtract */
case OP_SE: /* 7B */
case OP_SD: /* 6B */
case OP_SW: /* 6F */
case OP_SU: /* 7F */
case OP_SER: /* 3B */
case OP_SDR: /* 2B */
case OP_SWR: /* 2F */
case OP_SUR: /* 3F */
src2 ^= MSIGN;
/* Fall through */
/* Floating Add */
case OP_AE: /* 7A */
case OP_AD: /* 6A */
case OP_AW: /* 6E */
case OP_AU: /* 7E */
case OP_AER: /* 3A */
case OP_ADR: /* 2A */
case OP_AWR: /* 2E */
case OP_AUR: /* 3E */
/* Extract numbers and adjust */
e1 = (src1 & EMASK) >> 24;
e2 = (src2 & EMASK) >> 24;
fill = 0;
if (src1 & MSIGN)
fill |= 1;
if (src2 & MSIGN)
fill |= 2;
/* Create gaurd digit */
src1 = ((src1 & MMASK) << 4) | ((src1h >> 28) & 0xf);
src2 = ((src2 & MMASK) << 4) | ((src2h >> 28) & 0xf);
src1h &= XMASK;
src2h &= XMASK;
/* Shift src2 right if src1 larger expo - expo */
while (e1 > e2) {
src2h >>= 4;
src2h |= (src2 & 0xf) << 24;
src2 >>= 4;
e2 ++;
}
/* Shift src1 right if src2 larger expo - expo */
while (e2 > e1) {
src1h >>= 4;
src1h |= (src1 & 0xf) << 24;
src1 >>= 4;
e1 ++;
}
/* Exponents should be equal now. */
/* Add results */
if (fill == 2 || fill == 1) {
/* Different signs do subtract */
src1 ^= XMASK;
src1h ^= XMASK;
src1h++;
if (src1 & CMASK) {
src1++;
src1h &= XMASK;
}
src1h += src2h;
if (src1h & CMASK) {
src1 += ((src1h >> 28) & 0xf);
src1h &= XMASK;
}
src1 += src2;
if (src1 & CMASK)
src1 ^= CMASK;
else {
fill ^= 2;
src1 ^= XMASK;
src1h ^= XMASK;
src1h++;
if (src1 & CMASK) {
src1++;
src1h &= XMASK;
}
}
} else {
src1h += src2h;
if (src1h & CMASK) {
src1 += ((src1h >> 28) & 0xf);
src1h &= XMASK;
}
src1 += src2;
}
/* If src1 not normal shift left + expo */
if (src1 & CMASK) {
src1h >>= 4;
src1h |= (src1 & 0xf) << 24;
src1 >>= 4;
e1 ++;
}
/* Compute sign of result */
cc = 0;
if ((src1h | src1) != 0)
cc = (temp & 2) ? 1 : 2;
/* Set condition codes */
/* If (op & 0xF) == 0x9, compare */
if ((op & 0xF) == 0x9) /* Compare operator */
break; /* All done */
/* If (op & 0xE) != 0xE, normalize */
if ((op & 0xE) != 0xE && cc != 0) { /* Normalize operator */
while ((src1 & EMASK) == 0) {
src1 = (src1 << 4) | ((src1h >> 24) & 0xf);
src1h <<= 4;
src1h &= XMASK;
e1 --;
}
}
/* Store result */
src1h |= (src1 & 0xf) << 28;
src1 >>= 4;
/* If exp < 0, underflow */
/* If exp > 64 overflow */
src1 |= (e1 << 24) & EMASK;
if (fill & 2)
src1 |= MSIGN;
if ((op & 0x10) == 0) {
fpregs[reg1|1] = src2h;
src1 |= src2h;
}
fpregs[reg1] = src2;
break;
/* Multiply */
case OP_MDR:
case OP_MER:
case OP_ME:
case OP_MD:
/* Divide */
case OP_DER:
case OP_DDR:
case OP_DD:
case OP_DE:
/* Decimal operations */
case OP_CP:
case OP_SP:
case OP_ZAP:
case OP_AP:
/* Get sign of second operand */
/* If op & 1 flip sign */
/* Get sign of first operand */
/* Compute sign of result */
case OP_MP:
case OP_DP:
storepsw(OPPSW, IRC_OPR);
goto supress;
break;
/* Extended precision load round */
case OP_LRER:
case OP_LRDR:
case OP_SXR:
case OP_AXR:
case OP_MXR:
case OP_MXDR:
case OP_MXD:
default:
storepsw(OPPSW, IRC_OPR);
goto supress;
}
if (hst_lnt) {
hst[hst_p].dest = dest;
hst[hst_p].cc = cc;
}
sim_debug(DEBUG_INST, &cpu_dev, "GR00=%08x GR01=%08x GR02=%08x GR03=%08x\n", regs[0], regs[1], regs[2], regs[3]);
sim_debug(DEBUG_INST, &cpu_dev, "GR04=%08x GR05=%08x GR06=%08x GR07=%08x\n", regs[4], regs[5], regs[6], regs[7]);
sim_debug(DEBUG_INST, &cpu_dev, "GR08=%08x GR09=%08x GR10=%08x GR11=%08x\n", regs[8], regs[9], regs[10], regs[11]);
sim_debug(DEBUG_INST, &cpu_dev, "GR12=%08x GR13=%08x GR14=%08x GR15=%08x\n", regs[12], regs[13], regs[14], regs[15]);
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;
}
irqaddr += 4;
src2 = M[irqaddr>>2];
if (hst_lnt) {
hst[hst_p].src2 = src2;
}
lpsw:
sysmsk = (src1 >> 24) & 0xff;
st_key = (src1 >> 16) & 0xf0;
flags = (src1 >> 16) & 0xf;
irqaddr = 0;
pmsk = (src2 >> 24) & 0xf;
cc = (src2 >> 28) & 0x3;
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_interval--;
}
}
/* Reset */
t_stat cpu_reset (DEVICE *dptr)
{
st_key = cc = pmsk = irqcode = flags = irqaddr = loading = 0;
chan_set_devs();
if (M == NULL) { /* first time init? */
sim_brk_types = sim_brk_dflt = SWMASK ('E');
M = (uint32 *) calloc (((uint32) MEMSIZE) >> 2, sizeof (uint32));
if (M == NULL)
return SCPE_MEM;
}
return SCPE_OK;
}
/* Interval timer routines */
t_stat
rtc_srv(UNIT * uptr)
{
if (cpu_unit.flags & FEAT_TIMER) {
int32 t;
t = sim_rtcn_calb (rtc_tps, TMR_RTC);
sim_activate_after(uptr, 1000000/rtc_tps);
if ((M[0x50>>2] & 0xfffffc00) == 0) {
sim_debug(DEBUG_INST, &cpu_dev, "TIMER IRQ %08x\n\r", M[0x50>>2]);
interval_irq = 1;
}
M[0x50>>2] -= 0x40;
sim_debug(DEBUG_INST, &cpu_dev, "TIMER = %08x\n", M[0x50>>2]);
}
return SCPE_OK;
}
/* Memory examine */
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));
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;
}
/* 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;
/* 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;
val = val >> UNIT_V_MSIZE;
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 = (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;
cpu_unit.flags &= ~UNIT_MSIZE;
cpu_unit.flags |= val / (16 * 1024);
reset_all (0);
return SCPE_OK;
}
/* Handle execute history */
/* Set history */
t_stat
cpu_set_hist(UNIT * uptr, int32 val, CONST char *cptr, void *desc)
{
int32 i, lnt;
t_stat r;
if (cptr == NULL) {
for (i = 0; i < hst_lnt; i++)
hst[i].pc = 0;
hst_p = 0;
return SCPE_OK;
}
lnt = (int32) get_uint(cptr, 10, HIST_MAX, &r);
if ((r != SCPE_OK) || (lnt && (lnt < HIST_MIN)))
return SCPE_ARG;
hst_p = 0;
if (hst_lnt) {
free(hst);
hst_lnt = 0;
hst = NULL;
}
if (lnt) {
hst = (struct InstHistory *)calloc(sizeof(struct InstHistory), lnt);
if (hst == NULL)
return SCPE_MEM;
hst_lnt = lnt;
}
return SCPE_OK;
}
/* Show history */
t_stat
cpu_show_hist(FILE * st, UNIT * uptr, int32 val, CONST void *desc)
{
int32 k, di, lnt;
const char *cptr = (const char *) desc;
t_stat r;
t_value sim_eval;
struct InstHistory *h;
if (hst_lnt == 0)
return SCPE_NOFNC; /* enabled? */
if (cptr) {
lnt = (int32) get_uint(cptr, 10, hst_lnt, &r);
if ((r != SCPE_OK) || (lnt == 0))
return SCPE_ARG;
} else
lnt = hst_lnt;
di = hst_p - lnt; /* work forward */
if (di < 0)
di = di + hst_lnt;
fprintf(st, "PC A1 A2 D1 D2 RESULT CC\n\n");
for (k = 0; k < lnt; k++) { /* print specified */
h = &hst[(++di) % hst_lnt]; /* entry pointer */
if (h->pc & HIST_PC) { /* instruction? */
int i;
fprintf(st, "%06x %06x %06x %08x %08x %08x %1x %04x ",
h->pc & PAMASK, h->addr1 & PAMASK, h->addr2 & PAMASK,
h->src1, h->src2, h->dest, h->cc, h->inst[0]);
if ((h->op & 0xc0) != 0)
fprintf(st, "%04x ", h->inst[1]);
else
fprintf(st, " ");
if ((h->op & 0xc0) == 0xc0)
fprintf(st, "%04x ", h->inst[2]);
else
fprintf(st, " ");
fprintf(st, " ");
fprint_inst(st, h->inst);
fputc('\n', st); /* end line */
} /* end else instruction */
if (h->pc & HIST_LPW) { /* load PSW */
int i;
fprintf(st, " LPSW %06x %08x %08x\n", h->pc & PAMASK, h->src1, h->src2);
} /* end else instruction */
if (h->pc & HIST_SPW) { /* load PSW */
int i;
fprintf(st, " SPSW %06x %08x %08x\n", h->pc & PAMASK, h->src1, h->src2);
} /* end else instruction */
} /* end for */
return SCPE_OK;
}
t_stat cpu_help(FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, const char *cptr)
{
fprintf(st, "IBM360 CPU\n\n");
fprint_set_help(st, dptr);
fprint_show_help(st, dptr);
return SCPE_OK;
}
const char *
cpu_description (DEVICE *dptr)
{
return "IBM 360 CPU";
}