1
0
mirror of https://github.com/rcornwell/sims.git synced 2026-04-03 12:22:52 +00:00

IBM360: Added VMAssist to speed up VM/370.

This commit is contained in:
Richard Cornwell
2021-07-03 14:43:56 -04:00
parent 1fe4c4703d
commit 4c18051018
6 changed files with 839 additions and 23 deletions

View File

@@ -1,6 +1,6 @@
/* ibm360_cpu.c: ibm 360 cpu simulator.
Copyright (c) 2019-2020, Richard Cornwell
Copyright (c) 2019-2021, Richard Cornwell
Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the "Software"),
@@ -242,6 +242,9 @@ int timer_tics; /* Interval Timer is ever 3 tics */
#define Q360 (cpu_unit[0].flags & FEAT_370) == 0
#define Q370 (cpu_unit[0].flags & FEAT_370) != 0
#define QVMA ((cpu_unit[0].flags & (FEAT_370|FEAT_VMA)) == (FEAT_370|FEAT_VMA) && \
((cregs[6] & 0xc0000000) == 0x80000000))
int hst_lnt;
int hst_p;
struct InstHistory
@@ -277,6 +280,16 @@ void dec_srp(int op, uint32 addr1, uint8 len1, uint32 addr2, uint8 len2);
void dec_add(int op, uint32 addr1, uint8 len1, uint32 addr2, uint8 len2);
void dec_mul(int op, uint32 addr1, uint8 len1, uint32 addr2, uint8 len2);
void dec_div(int op, uint32 addr1, uint8 len1, uint32 addr2, uint8 len2);
extern int vma_370(int reg, uint32 addr1);
extern int vma_ssm(uint32 addr1);
extern int vma_lpsw(uint32 addr1);
extern int vma_stssk(uint32 src1, uint32 addr1);
extern int vma_stisk(uint8 reg1, uint32 addr1);
extern int vma_stsvc(uint8 reg);
extern int vma_lra(uint8 reg, uint32 addr1);
extern int vma_stnsm(uint8 reg, uint32 addr1);
extern int vma_stosm(uint8 reg, uint32 addr1);
extern int vma_stctl(uint8 reg, uint32 addr1);
void check_tod_irq();
t_bool build_dev_tab (void);
@@ -365,6 +378,8 @@ MTAB cpu_mod[] = {
{ 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_VMA, FEAT_VMA, "VMA", "VMA", NULL, NULL, NULL, "Enable VM Assists"},
{ FEAT_VMA, 0, NULL, "NOVMA", NULL, NULL},
{ EXT_IRQ, 0, "NOEXT", NULL, NULL, NULL},
{ EXT_IRQ, EXT_IRQ, "EXT", "EXT", NULL, NULL, NULL,
"SET CPU EXT causes external interrupt"},
@@ -377,16 +392,20 @@ 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, DEV_DEBUG, 0, cpu_debug,
NULL, NULL, &cpu_help, NULL, NULL, &cpu_description
};
void post_extirq() {
void
post_extirq()
{
cpu_unit[0].flags |= EXT_IRQ;
}
void storepsw(uint32 addr, uint16 ircode) {
void
storepsw(uint32 addr, uint16 ircode)
{
uint32 word;
uint32 word2;
irqaddr = addr + 0x40;
@@ -508,7 +527,9 @@ void storepsw(uint32 addr, uint16 ircode) {
/*
* Translate an address from virtual to physical.
*/
int TransAddr(uint32 va, uint32 *pa) {
int
TransAddr(uint32 va, uint32 *pa)
{
uint32 seg;
uint32 page;
uint32 entry;
@@ -640,7 +661,9 @@ int TransAddr(uint32 va, uint32 *pa) {
* and alignment restrictions. Return 1 if failure, 0 if
* success.
*/
int ReadFull(uint32 addr, uint32 *data) {
int
ReadFull(uint32 addr, uint32 *data)
{
uint32 pa;
int offset;
@@ -713,7 +736,9 @@ int ReadFull(uint32 addr, uint32 *data) {
* and alignment restrictions. Return 1 if failure, 0 if
* success.
*/
int ReadByte(uint32 addr, uint32 *data) {
int
ReadByte(uint32 addr, uint32 *data)
{
if (ReadFull(addr & (~0x3), data))
return 1;
@@ -727,7 +752,9 @@ int ReadByte(uint32 addr, uint32 *data) {
* and alignment restrictions. Return 1 if failure, 0 if
* success.
*/
int ReadHalf(uint32 addr, uint32 *data) {
int
ReadHalf(uint32 addr, uint32 *data)
{
/* Check if unaligned access */
if (addr & 0x1) {
@@ -766,7 +793,9 @@ int ReadHalf(uint32 addr, uint32 *data) {
* and alignment restrictions. Return 1 if failure, 0 if
* success.
*/
int WriteFull(uint32 addr, uint32 data) {
int
WriteFull(uint32 addr, uint32 data)
{
int offset;
uint32 pa;
uint32 pa2;
@@ -877,7 +906,9 @@ int WriteFull(uint32 addr, uint32 data) {
* and alignment restrictions. Return 1 if failure, 0 if
* success.
*/
int WriteByte(uint32 addr, uint32 data) {
int
WriteByte(uint32 addr, uint32 data)
{
uint32 mask;
uint32 pa;
int offset;
@@ -934,7 +965,9 @@ int WriteByte(uint32 addr, uint32 data) {
* and alignment restrictions. Return 1 if failure, 0 if
* success.
*/
int WriteHalf(uint32 addr, uint32 data) {
int
WriteHalf(uint32 addr, uint32 data)
{
uint32 mask;
uint32 pa;
uint32 pa2;
@@ -1492,6 +1525,9 @@ opr:
storepsw(OPPSW, IRC_OPR);
goto supress;
} else if (flags & PROBLEM) {
/* Try to do quick SSK */
if (QVMA && vma_stssk(src1, addr1))
break;
storepsw(OPPSW, IRC_PRIV);
goto supress;
} else if ((addr1 & 0xF) != 0) {
@@ -1513,6 +1549,9 @@ opr:
if ((cpu_unit[0].flags & FEAT_PROT) == 0) {
storepsw(OPPSW, IRC_PROT);
} if (flags & PROBLEM) {
/* Try to do quick ISK */
if (QVMA && vma_stisk(reg1, addr1))
break;
storepsw(OPPSW, IRC_PRIV);
} else if ((addr1 & 0xF) != 0) {
storepsw(OPPSW, IRC_SPEC);
@@ -1530,11 +1569,19 @@ opr:
break;
case OP_SVC:
/* Try to do quick SVC */
if ((flags & PROBLEM) != 0 && \
(cpu_unit[0].flags & (FEAT_370|FEAT_VMA)) == (FEAT_370|FEAT_VMA) && \
(cregs[6] & 0x88000000) == MSIGN && vma_stsvc(reg))
break;
storepsw(OSPSW, reg);
break;
case OP_SSM:
if (flags & PROBLEM) {
if ((flags & PROBLEM)) {
sim_debug(DEBUG_VMA, &cpu_dev, "SSM CR6 %08x\n", cregs[6]);
if (QVMA && vma_ssm(addr1))
break;
storepsw(OPPSW, IRC_PRIV);
goto supress;
} else {
@@ -1580,6 +1627,8 @@ opr:
case OP_LPSW:
if (flags & PROBLEM) {
if (QVMA && vma_lpsw(addr1))
break;
storepsw(OPPSW, IRC_PRIV);
goto supress;
} else if ((addr1 & 0x7) != 0) {
@@ -2343,6 +2392,9 @@ save_dbl:
if ((cpu_unit[0].flags & FEAT_DAT) == 0) {
storepsw(OPPSW, IRC_OPR);
} else if (flags & PROBLEM) {
/* Try to do quick LRA */
if (QVMA && vma_lra(reg, addr1))
break;
storepsw(OPPSW, IRC_PRIV);
} else {
uint32 seg;
@@ -2383,7 +2435,7 @@ save_dbl:
/* Check if over end of table */
if ((page >> pte_len_shift) >= addr2) {
cc = 3;
regs[reg1] = addr1;
regs[reg1] = addr2;
per_mod |= 1 << reg1;
break;
}
@@ -2982,6 +3034,9 @@ save_dbl:
goto supress;
}
if (reg != 5 && flags & PROBLEM) {
/* Try to do quick IPK */
if (QVMA && vma_370(reg, addr1))
break;
storepsw(OPPSW, IRC_PRIV);
goto supress;
}
@@ -3104,7 +3159,7 @@ save_dbl:
storepsw(OPPSW, IRC_OPR);
goto supress;
}
regs[2] = (regs[2] & 0xffffff00) | st_key;
regs[2] = (regs[2] & 0xffffff00) | (st_key & 0xf0);
break;
case 0xd: /* PTLB */
if ((cpu_unit[0].flags & FEAT_DAT) == 0) {
@@ -3145,6 +3200,9 @@ save_dbl:
case OP_STNSM:
if (Q370) {
if (flags & PROBLEM) {
/* Try to do quick STNSM */
if (QVMA && vma_stnsm(reg, addr1))
break;
storepsw(OPPSW, IRC_PRIV);
goto supress;
}
@@ -3190,6 +3248,9 @@ save_dbl:
case OP_STOSM:
if (Q370) {
if (flags & PROBLEM) {
/* Try to do quick STOSM */
if (QVMA && vma_stosm(reg, addr1))
break;
storepsw(OPPSW, IRC_PRIV);
goto supress;
}
@@ -3343,6 +3404,9 @@ save_dbl:
sysmsk = irq_en ? (dest >> 16) : 0;
irq_pend = 1;
break;
case 0x6: /* Assist function */
sim_debug(DEBUG_VMA, &cpu_dev, "set CR6 %08x\n", dest);
break;
case 0x3: /* Unassigned */
case 0x4: /* Unassigned */
case 0x5: /* Unassigned */
@@ -3372,6 +3436,9 @@ save_dbl:
} else if ((cpu_unit[0].flags & FEAT_DAT) == 0) {
storepsw(OPPSW, IRC_OPR);
} else if (flags & PROBLEM) {
/* Try to do quick STCLT */
if (QVMA && vma_stctl(reg, addr1))
break;
storepsw(OPPSW, IRC_PRIV);
} else {
reg = R2(reg);
@@ -5434,8 +5501,8 @@ lpsw:
dat_en = 0;
irq_en = (sysmsk != 0);
per_en = 0;
pmsk = (src2 >> 24) & 0xf;
cc = (src2 >> 28) & 0x3;
pmsk = (src2 >> 24) & 0xf;
}
irq_pend = 1;
st_key = (src1 >> 16) & 0xf0;
@@ -5827,10 +5894,11 @@ dec_div(int op, uint32 addr1, uint8 len1, uint32 addr2, uint8 len2)
dec_store(a, addr1, len, sa);
}
/* Reset */
t_stat cpu_reset (DEVICE *dptr)
t_stat
cpu_reset (DEVICE *dptr)
{
int i;
@@ -5941,7 +6009,8 @@ check_tod_irq()
/* Memory examine */
t_stat cpu_ex (t_value *vptr, t_addr exta, UNIT *uptr, int32 sw)
t_stat
cpu_ex (t_value *vptr, t_addr exta, UNIT *uptr, int32 sw)
{
uint32 addr = (uint32) exta;
uint32 byte;
@@ -6016,7 +6085,8 @@ t_stat cpu_ex (t_value *vptr, t_addr exta, UNIT *uptr, int32 sw)
/* Memory deposit */
t_stat cpu_dep (t_value val, t_addr exta, UNIT *uptr, int32 sw)
t_stat
cpu_dep (t_value val, t_addr exta, UNIT *uptr, int32 sw)
{
uint32 addr = (uint32) exta;
uint32 offset = 8 * (3 - (addr & 0x3));
@@ -6092,7 +6162,8 @@ t_stat cpu_dep (t_value val, t_addr exta, UNIT *uptr, int32 sw)
/* Memory allocation */
t_stat cpu_set_size (UNIT *uptr, int32 val, CONST char *cptr, void *desc)
t_stat
cpu_set_size (UNIT *uptr, int32 val, CONST char *cptr, void *desc)
{
int32 mc = 0;
int32 i, clim;
@@ -6228,7 +6299,8 @@ 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)
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);

View File

@@ -105,7 +105,8 @@ typedef struct dib {
#define FEAT_DAT (1 << (UNIT_V_UF + 5)) /* Dynamic address translation */
#define FEAT_EFP (1 << (UNIT_V_UF + 6)) /* Extended floating point */
#define FEAT_370 (1 << (UNIT_V_UF + 7)) /* Is a 370 */
#define EXT_IRQ (1 << (UNIT_V_UF + 8)) /* External interrupt */
#define FEAT_VMA (1 << (UNIT_V_UF + 8)) /* Enable VM assists */
#define EXT_IRQ (1 << (UNIT_V_UF + 9)) /* External interrupt */
/* low addresses */
#define IPSW 0x00 /* IPSW */
@@ -367,8 +368,10 @@ extern const uint8 ebcdic_to_ascii[256];
#define DEBUG_IRQ 0x0000100 /* Show IRQ requests */
#define DEBUG_CDATA 0x0000200 /* Show channel data */
#define DEBUG_TRACE 0x0000400 /* Show instruction trace */
#define DEBUG_VMA 0x0000800 /* Show VM Assist functions */
extern DEBTAB dev_debug[];
extern DEBTAB cpu_debug[];
extern DEBTAB crd_debug[];
extern DEVICE cpu_dev;

View File

@@ -96,9 +96,19 @@ DEBTAB dev_debug[] = {
{"DETAIL", DEBUG_DETAIL, "Show details about device"},
{"EXP", DEBUG_EXP, "Show exception information"},
{"POS", DEBUG_POS, "Dasd positioning information"},
{0, 0}
};
/* Simulator debug controls */
DEBTAB cpu_debug[] = {
{"CMD", DEBUG_CMD, "Show command execution to devices"},
{"DATA", DEBUG_DATA, "Show data transfers"},
{"DETAIL", DEBUG_DETAIL, "Show details about device"},
{"EXP", DEBUG_EXP, "Show exception information"},
{"INST", DEBUG_INST, "Show instruction execution"},
{"CDATA", DEBUG_CDATA, "Show channel data"},
{"TRACE", DEBUG_TRACE, "Show instruction history"},
{"VMA", DEBUG_VMA, "Show assist history"},
{0, 0}
};

731
IBM360/ibm360_vma.c Normal file
View File

@@ -0,0 +1,731 @@
/* ibm360_vma.c: ibm 360 Virtual Memory Assists for VM/370.
Copyright (c) 2021, 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 */
extern uint32 *M;
extern uint8 key[MAXMEMSIZE / 2048];
extern uint32 PC; /* Program counter */
extern uint32 regs[16]; /* CPU Registers */
extern uint32 cregs[16]; /* Control registers /67 or 370 only */
extern uint8 cc; /* CC */
extern uint8 pmsk; /* Program mask */
extern uint8 st_key; /* Storage key */
extern uint8 per_en; /* PER mode enable */
#define AMASK 0x00ffffff /* Mask address bits */
#define MSIGN 0x80000000 /* Minus sign */
#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)
extern int ReadFull(uint32 addr, uint32 *data);
extern int ReadByte(uint32 addr, uint32 *data);
extern int ReadHalf(uint32 addr, uint32 *data);
extern int WriteFull(uint32 addr, uint32 data);
extern int WriteByte(uint32 addr, uint32 data);
extern int WriteHalf(uint32 addr, uint32 data);
/* Handle VM Assists for RRB instructions
* return 0 if assist could not be completed. Return 1 if successful */
int
vma_rrb(uint32 addr1)
{
uint32 micblok;
uint32 micrseg;
uint32 page;
uint32 seg;
uint32 segpage;
uint32 pagswp;
uint32 swpflg;
uint32 pagcore;
uint32 micvpsw;
uint32 vpsw;
uint8 stk;
sim_debug(DEBUG_VMA, &cpu_dev, "RRB check %08x\n", addr1);
/* Check if enabled */
if ((cregs[6] & 0xe0000000) != MSIGN)
return 0;
micblok = (cregs[6] & 0xfffff8) >> 2;
/* Fetch SEGPAGE */
micrseg = M[micblok];
sim_debug(DEBUG_VMA, &cpu_dev, "Micrseg %08x\n", micrseg);
if (micrseg & 0x2)
return 0;
/* Compute address to operate on */
page = addr1 >> 12;
if (micrseg & 0x1) {
seg = page >> 7;
page &= 0x7f;
} else {
seg = page >> 4;
page &= 0xf;
}
segpage = M[((micrseg & AMASK) >> 2) + seg];
sim_debug(DEBUG_VMA, &cpu_dev, "Segpage %08x s=%x p=%x\n", segpage, seg, page);
if ((segpage >> 24) <= (addr1 >> 20))
return 0;
pagswp = M[((segpage & AMASK) >> 2) - 1];
sim_debug(DEBUG_VMA, &cpu_dev, "pagswp %08x\n", pagswp);
swpflg = M[((pagswp + (8 * page)) & AMASK) >> 2];
sim_debug(DEBUG_VMA, &cpu_dev, "swpflg %08x\n", swpflg);
pagcore = M[((segpage + (2 * page)) & AMASK) >> 2];
sim_debug(DEBUG_VMA, &cpu_dev, "pagcore %08x\n", pagcore);
/* Get key value */
if (addr1 & 0x800) {
stk = swpflg & 0xfe;
} else {
stk = (swpflg >> 8) & 0xfe;
}
sim_debug(DEBUG_VMA, &cpu_dev, "stk %02x\n", stk);
/* Check if page is valid */
if ((page & 0x1) == 0)
pagcore >>= 16;
if ((pagcore & 0xe) == 0) {
pagcore &= 0xfff0;
pagcore <<= 8;
pagcore |= addr1 & 0x800;
stk |= key[pagcore>>11] & 0x6;
key[pagcore>>11] &= 0xfb; /* Clear reference bit */
sim_debug(DEBUG_VMA, &cpu_dev, "real addr %08x %02x\n", pagcore, stk);
}
/* Clear virtual reference bits */
if (addr1 & 0x800) {
swpflg &= 0xfcfffffb;
} else {
swpflg & 0xf3fffbff;
}
M[((pagswp + (8 * page)) & AMASK) >> 2] = swpflg;
/* Update the CC */
cc = (stk >> 1) & 03;
return 1;
}
/* Handle VM Assists for B2 instructions
* return 0 if assist could not be completed. Return 1 if successful */
int
vma_370(int reg, uint32 addr1)
{
uint32 micvpsw;
uint32 micseg;
uint32 vpsw;
uint32 page;
uint32 seg;
sim_debug(DEBUG_VMA, &cpu_dev, "B2%02x %08x check\n", reg, addr1);
switch(reg) {
default:
case 0x2: /* STIDP */
case 0x3: /* STIDC */
case 0x4: /* SCK */
case 0x5: /* STCK */
case 0x6: /* SCKC */
case 0x7: /* STCKC */
break;
case 0x8: /* SPT */
break;
case 0x9: /* STPT */
break;
case 0xd: /* PTLB */
break;
case 0xa: /* SPKA */
if ((cpu_unit[0].flags & FEAT_PROT) == 0) {
break;
}
if (cregs[6] & 0x10000000)
break;
micvpsw = M[((cregs[6] & 0xfffff8) >> 2) + 2];
vpsw = M[(micvpsw & AMASK) >> 2];
sim_debug(DEBUG_VMA, &cpu_dev, "VPSW %08x\n", vpsw);
vpsw &= 0xff0fffff;
vpsw |= (0xf0 & addr1) << 16;
M[micvpsw & AMASK] = vpsw;
st_key = 0xf0 & addr1;
sim_debug(DEBUG_VMA, &cpu_dev, "New VPSW %08x New key %02x \n", vpsw, st_key);
return 1;
case 0xb: /* IPK */
if ((cpu_unit[0].flags & FEAT_PROT) == 0) {
break;
}
if (cregs[6] & 0x10000000)
break;
micvpsw = M[((cregs[6] & 0xfffff8) >> 2) + 2];
vpsw = M[(micvpsw & AMASK) >> 2];
sim_debug(DEBUG_VMA, &cpu_dev, "VPSW %08x\n", vpsw);
regs[2] = (regs[2] & 0xffffff00) | ((vpsw >> 16) & 0xf0);
sim_debug(DEBUG_VMA, &cpu_dev, "Reg2 %08x\n", regs[2]);
return 1;
case 0x13: /* RRB */
return vma_rrb(addr1);
}
return 0;
}
/* Handle VM Assists for SSM instructions
* return 0 if assist could not be completed. Return 1 if successful */
int
vma_ssm(uint32 addr1)
{
uint32 micblok;
uint32 miccreg;
uint32 micvpsw;
uint32 vpsw;
uint32 temp;
int flags;
sim_debug(DEBUG_VMA, &cpu_dev, "SSM check %08x\n", addr1);
micblok = (cregs[6] & 0xfffff8) >> 2;
/* Check if function enabled */
if ((cregs[6] & 0x01000000) != 0) {
miccreg = M[micblok + 5];
sim_debug(DEBUG_VMA, &cpu_dev, "SSM micacf %08x\n", miccreg);
if ((miccreg & 0x00800000) == 0)
return 0;
}
/* Fetch Virtual Cr 0 */
miccreg = M[micblok + 1];
sim_debug(DEBUG_VMA, &cpu_dev, "SSM miccreg %08x\n", miccreg);
temp = M[(miccreg & AMASK) >> 2];
if ((temp & 0x40000000) != 0)
return 0;
/* Fetch the virtual PSW */
micvpsw = M[micblok + 2];
vpsw = M[(micvpsw & AMASK) >> 2];
/* Fetch new mask */
if (ReadByte(addr1, &temp))
return 0;
sim_debug(DEBUG_VMA, &cpu_dev, "VPSW %08x d=%08x\n", vpsw, temp);
flags = vpsw >> 24;
flags ^= temp;
if (vpsw & 0x80000) {
/* If bits are not zero, exit */
if (temp & 0xb8)
return 0;
/* Check if DAT or PER changed */
if (flags & 0x44)
return 0;
/* Check if IRQ pending and enable interrupt */
if ((micvpsw & MSIGN) && (flags & temp & 0x3) != 0)
return 0;
} else {
/* Check if IRQ pending and enable interrupt */
if ((micvpsw & MSIGN) && (flags & temp) != 0)
return 0;
}
vpsw &= 0xffffff;
vpsw |= temp << 24;
M[(micvpsw & AMASK) >> 2] = vpsw;
sim_debug(DEBUG_VMA, &cpu_dev, "new VPSW %08x\n", vpsw);
return 1;
}
/* Handle VM Assists for LPSW instructions
* return 0 if assist could not be completed. Return 1 if successful */
int
vma_lpsw(uint32 addr1)
{
uint32 micblok;
uint32 miccreg;
uint32 micvpsw;
uint32 vpsw;
uint32 vpsw2;
uint32 npsw1;
uint32 npsw2;
sim_debug(DEBUG_VMA, &cpu_dev, "LPSW check %08x\n", addr1);
/* Quick check to exit */
if (per_en || (addr1 & 0x7) != 0)
return 0;
/* Check if function enabled */
micblok = (cregs[6] & 0xfffff8) >> 2;
/* Fetch new PSW */
if (ReadFull(addr1, &npsw1))
return 0;
if (ReadFull(addr1 + 4, &npsw2))
return 0;
sim_debug(DEBUG_VMA, &cpu_dev, "new %08x %08x\n", npsw1, npsw2);
/* New PSW has WAIT or invalid ECmode bits */
if ((npsw1 & 0x20000) != 0)
return 0;
if ((npsw1 & 0x80000) != 0 &&
((npsw1 & 0xf800c0ff) != 0 || (npsw2 & 0xff000000) != 0))
return 0;
/* Fetch the virtual PSW */
micvpsw = (M[micblok + 2] & AMASK) >> 2;
vpsw = M[micvpsw];
sim_debug(DEBUG_VMA, &cpu_dev, "VPSW %08x %08x\n", vpsw, M[micvpsw + 1]);
/* Check if old PSW has PER set */
if ((vpsw & 0x40080000) == 0x40080000)
return 0;
/* Check if PSW changing BC/EC mode */
if (((vpsw ^ npsw1) & 0x80000) != 0)
return 0;
/* Check for interrupt */
if (npsw1 & 0x80000) { /* EC Mode */
/* Check if DAT changed */
if (((npsw1 ^ vpsw) & 0x04000000) != 0)
return 0;
/* Check if IRQ pending and enable interrupt */
if ((M[micblok + 2] & MSIGN) && (npsw1 & 0x3000000) != 0
&& ((vpsw ^ npsw1) & npsw1 & 0x3000000) != 0)
return 0;
pmsk = (npsw1 >> 8) & 0xf;
cc = (npsw1 >> 12) & 3;
} else {
/* Check if IRQ pending and enable interrupt */
if ((M[micblok + 2] & MSIGN) && (((vpsw ^ npsw1) & npsw1) & 0xff000000) != 0)
return 0;
pmsk = (npsw2 >> 24) & 0xf;
cc = (npsw2 >> 28) & 0x3;
}
M[micvpsw] = npsw1;
M[micvpsw + 1] = npsw2;
st_key = (npsw1 >> 16) & 0xf0;
/* Set CR6 to new problem state */
if (npsw1 & 0x10000)
cregs[6] |= 0x40000000;
else
cregs[6] &= 0xbfffffff;
PC = npsw2 & AMASK;
sim_debug(DEBUG_VMA, &cpu_dev, "new VPSW %08x %08x\n", npsw1, cregs[6]);
return 1;
}
/* Handle VM Assists for SSK instructions
* return 0 if assist could not be completed. Return 1 if successful */
int
vma_stssk(uint32 src1, uint32 addr1)
{
uint32 micblok;
uint32 micrseg;
uint32 page;
uint32 seg;
uint32 segpage;
uint32 pagswp;
uint32 swpflg;
uint32 pagcore;
uint8 stk;
sim_debug(DEBUG_VMA, &cpu_dev, "SSK check %08x %08x\n", src1, addr1);
/* Check if enabled */
if ((cregs[6] & 0xe0000000) != MSIGN || (src1 & 0xf) != 0)
return 0;
micblok = (cregs[6] & 0xfffff8) >> 2;
/* Fetch SEGPAGE */
micrseg = M[micblok];
sim_debug(DEBUG_VMA, &cpu_dev, "Micrseg %08x\n", micrseg);
if (micrseg & 0x2)
return 0;
/* Compute address to operate on */
page = addr1 >> 12;
if (micrseg & 0x1) {
seg = page >> 7;
page &= 0x7f;
} else {
seg = page >> 4;
page &= 0xf;
}
segpage = M[((micrseg & AMASK) >> 2) + seg];
sim_debug(DEBUG_VMA, &cpu_dev, "Segpage %08x s=%x p=%x\n", segpage, seg, page);
if ((segpage >> 24) <= (addr1 >> 20))
return 0;
pagswp = M[((segpage & AMASK) >> 2) - 1];
sim_debug(DEBUG_VMA, &cpu_dev, "pagswp %08x\n", pagswp);
swpflg = M[((pagswp + (8 * page)) & AMASK) >> 2];
sim_debug(DEBUG_VMA, &cpu_dev, "swpflg %08x\n", swpflg);
pagcore = M[((segpage + (2 * page)) & AMASK) >> 2];
sim_debug(DEBUG_VMA, &cpu_dev, "pagcore %08x\n", pagcore);
/* Check if page is valid */
if ((page & 0x1) == 0)
pagcore >>= 16;
if (pagcore & 0xe)
return 0;
pagcore &= 0xfff0;
pagcore <<= 8;
pagcore |= addr1 & 0x800;
stk = key[pagcore>>11];
sim_debug(DEBUG_VMA, &cpu_dev, "real addr %08x %02x\n", pagcore, stk);
key[pagcore>>11] = (stk & 0xf) | (src1 & 0xf0);
if (addr1 & 0x800) {
swpflg = (swpflg & 0xfcffff00) | (((uint32)stk & 0x6) << 25) | (src1 & 0xff);
} else {
swpflg = (swpflg & 0xf3ff00ff) | (((uint32)stk & 0x6) << 23) | ((src1 & 0xff) << 8);
}
sim_debug(DEBUG_VMA, &cpu_dev, "swpflg %08x\n", swpflg);
M[((pagswp + (8 * page)) & AMASK) >> 2] = swpflg;
return 1;
}
/* Handle VM Assists for ISK instructions
* return 0 if assist could not be completed. Return 1 if successful */
int
vma_stisk(uint8 reg1, uint32 addr1)
{
uint32 micblok;
uint32 micrseg;
uint32 page;
uint32 seg;
uint32 segpage;
uint32 pagswp;
uint32 swpflg;
uint32 pagcore;
uint32 micvpsw;
uint32 vpsw;
uint8 stk;
sim_debug(DEBUG_VMA, &cpu_dev, "ISK check %02x %08x\n", reg1, addr1);
/* Check if enabled */
if ((cregs[6] & 0xe0000000) != MSIGN)
return 0;
micblok = (cregs[6] & 0xfffff8) >> 2;
/* Fetch SEGPAGE */
micrseg = M[micblok];
sim_debug(DEBUG_VMA, &cpu_dev, "Micrseg %08x\n", micrseg);
if (micrseg & 0x2)
return 0;
/* Compute address to operate on */
page = addr1 >> 12;
if (micrseg & 0x1) {
seg = page >> 7;
page &= 0x7f;
} else {
seg = page >> 4;
page &= 0xf;
}
segpage = M[((micrseg & AMASK) >> 2) + seg];
sim_debug(DEBUG_VMA, &cpu_dev, "Segpage %08x s=%x p=%x\n", segpage, seg, page);
if ((segpage >> 24) <= (addr1 >> 20))
return 0;
pagswp = M[((segpage & AMASK) >> 2) - 1];
sim_debug(DEBUG_VMA, &cpu_dev, "pagswp %08x\n", pagswp);
swpflg = M[((pagswp + (8 * page)) & AMASK) >> 2];
sim_debug(DEBUG_VMA, &cpu_dev, "swpflg %08x\n", swpflg);
pagcore = M[((segpage + (2 * page)) & AMASK) >> 2];
sim_debug(DEBUG_VMA, &cpu_dev, "pagcore %08x\n", pagcore);
/* Get key value */
if (addr1 & 0x800) {
stk = swpflg & 0xfe;
} else {
stk = (swpflg >> 8) & 0xfe;
}
sim_debug(DEBUG_VMA, &cpu_dev, "stk %02x\n", stk);
/* Check if page is valid */
if ((page & 0x1) == 0)
pagcore >>= 16;
if ((pagcore & 0xe) == 0) {
pagcore &= 0xfff0;
pagcore <<= 8;
pagcore |= addr1 & 0x800;
stk |= key[pagcore>>11] & 0x6;
sim_debug(DEBUG_VMA, &cpu_dev, "real addr %08x %02x\n", pagcore, stk);
}
/* Fetch the virtual PSW */
micvpsw = (M[micblok + 2] & AMASK) >> 2;
vpsw = M[micvpsw];
sim_debug(DEBUG_VMA, &cpu_dev, "VPSW %08x %08x\n", vpsw, M[micvpsw + 1]);
if ((vpsw & 0x80000) == 0) { /* BC Mode */
stk &= 0xf0;
}
regs[reg1] = (regs[reg1] & 0xffffff00) | (uint32)stk;
return 1;
}
/* Handle VM Assists for SVC instructions
* return 0 if assist could not be completed. Return 1 if successful */
int
vma_stsvc(uint8 reg)
{
uint32 micblok;
uint32 micrseg;
uint32 micvpsw;
uint32 segpage;
uint32 pagcore;
uint32 psa;
uint32 vpsw;
uint32 npsw1;
uint32 npsw2;
sim_debug(DEBUG_VMA, &cpu_dev, "SVC check %02x\n", reg);
if (per_en || reg == 76)
return 0;
micblok = (cregs[6] & 0xfffff8) >> 2;
/* Fetch the virtual PSW */
micvpsw = (M[micblok + 2] & AMASK) >> 2;
vpsw = M[micvpsw];
sim_debug(DEBUG_VMA, &cpu_dev, "VPSW %08x %08x\n", vpsw, M[micvpsw + 1]);
/* Check if old PSW has PER set */
if ((vpsw & 0x40080000) == 0x40080000)
return 0;
/* Fetch SEGPAGE */
micrseg = M[micblok];
segpage = M[(micrseg & AMASK) >> 2];
sim_debug(DEBUG_VMA, &cpu_dev, "Segpage %08x\n", segpage);
pagcore = M[(segpage & AMASK) >> 2];
sim_debug(DEBUG_VMA, &cpu_dev, "pagcore %08x\n", pagcore);
psa = pagcore >> 16;
sim_debug(DEBUG_VMA, &cpu_dev, "psa %08x\n", psa);
/* determine if page is valid */
/* Check if 4k or 2k paging */
if ((micrseg & 02) != 0) {
/* 2K paging */
if (psa & 0x6)
return 0;
psa &= 0xfff8;
psa <<= 7;
} else {
/* 4K paging */
if (psa & 0xe)
return 0;
psa &= 0xfff0;
psa <<= 8;
}
/* PSA now points correctly */
npsw1 = M[(psa + 0x60) >> 2];
npsw2 = M[(psa + 0x64) >> 2];
sim_debug(DEBUG_VMA, &cpu_dev, "new PSW %08x %08x\n", npsw1, npsw2);
/* New PSW has WAIT or invalid ECmode bits */
if ((npsw1 & 0x20000) != 0)
return 0;
if ((npsw1 & 0x80000) != 0 &&
((npsw1 & 0xf800c0ff) != 0 || (npsw2 & 0xff000000) != 0))
return 0;
/* Check if PSW changing BC/EC mode */
if (((vpsw ^ npsw1) & 0x80000) != 0)
return 0;
/* Check for interrupt */
if (npsw1 & 0x80000) {
/* Check if DAT changed */
if (((npsw1 ^ vpsw) & 0x04000000) != 0)
return 0;
/* Check if IRQ pending and enable interrupt */
if ((M[micblok + 2] & MSIGN) && (npsw1 & 0x3000000) != 0
&& ((vpsw ^ npsw1) & npsw1 & 0x3000000) != 0)
return 0;
} else {
/* Check if IRQ pending and enable interrupt */
if ((M[micblok + 2] & MSIGN) && (((vpsw ^ npsw1) & npsw1) & 0xff000000) != 0)
return 0;
}
/* Construct old PSW */
if (vpsw & 0x80000) {
uint32 temp1;
/* Generate first word */
temp1 = (vpsw & 0xff0f0f00) |
(((uint32)st_key) << 16) |
(((uint32)cc) << 12) |
(((uint32)pmsk) << 8);
/* Save old PSW */
M[(psa + 0x20) >> 2] = temp1;
M[(psa + 0x24) >> 2] = PC & AMASK;
M[(psa + 0x88) >> 2] = (1 << 17) | reg;
sim_debug(DEBUG_VMA, &cpu_dev, "Old PSW %08x %08x\n", temp1, PC);
} else {
uint32 temp1;
uint32 temp2;
/* Generate first word */
temp1 = (vpsw & 0xff0f0000) |
(((uint32)st_key) << 16) |
((uint32)reg);
/* Generate second word. */
temp2 = (((uint32)1) << 30) |
(((uint32)cc) << 28) |
(((uint32)pmsk) << 24) |
(PC & AMASK);
/* Save old PSW */
M[(psa + 0x20) >> 2] = temp1;
M[(psa + 0x24) >> 2] = temp2;
sim_debug(DEBUG_VMA, &cpu_dev, "Old PSW %08x %08x\n", temp1, temp2);
}
/* Set machine for new PSW */
M[micvpsw] = npsw1;
M[micvpsw + 1] = npsw2;
if (npsw1 & 0x80000) {
pmsk = (npsw1 >> 8) & 0xf;
cc = (npsw1 >> 12) & 3;
} else {
pmsk = (npsw2 >> 24) & 0xf;
cc = (npsw2 >> 28) & 0x3;
}
st_key = (npsw1 >> 16) & 0xf0;
/* Set CR6 to new problem state */
if (npsw1 & 0x10000)
cregs[6] |= 0x40000000;
else
cregs[6] &= 0xbfffffff;
PC = npsw2 & AMASK;
key[psa >> 11] |= 0x6;
sim_debug(DEBUG_VMA, &cpu_dev, "new VPSW %08x %08x %08x\n", npsw1, npsw2, cregs[6]);
return 1;
}
/* Handle VM Assists for LRA instructions
* return 0 if assist could not be completed. Return 1 if successful */
int
vma_lra(uint8 reg, uint32 addr1)
{
sim_debug(DEBUG_VMA, &cpu_dev, "LRA check %02x %08x\n", reg, addr1);
return 0;
}
/* Handle VM Assists for STNSM instructions
* return 0 if assist could not be completed. Return 1 if successful */
int
vma_stnsm(uint8 reg, uint32 addr1)
{
uint32 micblok;
uint32 miccreg;
uint32 micvpsw;
uint32 vpsw;
uint32 temp;
int flags;
sim_debug(DEBUG_VMA, &cpu_dev, "STNSM check %02x %08x\n", reg, addr1);
micblok = (cregs[6] & 0xfffff8) >> 2;
/* Check if function enabled */
if ((cregs[6] & 0x01000000) != 0) {
miccreg = M[micblok + 5];
sim_debug(DEBUG_VMA, &cpu_dev, "SSM micacf %08x\n", miccreg);
if ((miccreg & 0x00800000) == 0)
return 0;
}
/* Fetch Virtual Cr 0 */
miccreg = M[micblok + 1];
sim_debug(DEBUG_VMA, &cpu_dev, "SSM miccreg %08x\n", miccreg);
temp = M[(miccreg & AMASK) >> 2];
/* Fetch the virtual PSW */
micvpsw = M[micblok + 2];
vpsw = M[(micvpsw & AMASK) >> 2];
/* Don't allow change of PER or DAT */
if (vpsw & 0x80000 && (reg & 0x44) != 0x44)
return 0;
/* Update Mask */
temp = (vpsw >> 24) & 0xff;
vpsw &= ((uint32)reg << 24) | 0xffffff;
sim_debug(DEBUG_VMA, &cpu_dev, "VPSW %08x d=%08x\n", vpsw, temp);
/* Save old mask in addr1 */
if (WriteByte(addr1, temp))
return 0;
M[(micvpsw & AMASK) >> 2] = vpsw;
sim_debug(DEBUG_VMA, &cpu_dev, "new VPSW %08x\n", vpsw);
return 1;
}
/* Handle VM Assists for STOSM instructions
* return 0 if assist could not be completed. Return 1 if successful */
int
vma_stosm(uint8 reg, uint32 addr1)
{
uint32 micblok;
uint32 miccreg;
uint32 micvpsw;
uint32 vpsw;
uint32 temp;
int flags;
sim_debug(DEBUG_VMA, &cpu_dev, "STOSM check %02x %08x\n", reg, addr1);
micblok = (cregs[6] & 0xfffff8) >> 2;
/* Check if function enabled */
if ((cregs[6] & 0x01000000) != 0) {
miccreg = M[micblok + 5];
sim_debug(DEBUG_VMA, &cpu_dev, "SSM micacf %08x\n", miccreg);
if ((miccreg & 0x00800000) == 0)
return 0;
}
/* Fetch Virtual Cr 0 */
miccreg = M[micblok + 1];
sim_debug(DEBUG_VMA, &cpu_dev, "SSM miccreg %08x\n", miccreg);
temp = M[(miccreg & AMASK) >> 2];
if ((temp & 0x40000000) != 0)
return 0;
/* Fetch the virtual PSW */
micvpsw = M[micblok + 2];
vpsw = M[(micvpsw & AMASK) >> 2];
flags = (vpsw >> 24) ^ reg;
if (vpsw & 0x80000) {
/* Don't allow change of PER or DAT */
if ((flags & 0xfc) != 0x0)
return 0;
/* If enabling an interrupt and one pending, abort */
if ((micvpsw & MSIGN) && (flags & reg & 0x3) != 0)
return 0;
} else {
/* Check if IRQ pending and enable interrupt */
if ((vpsw & MSIGN) && ((flags & reg) & 0xff) != 0)
return 0;
}
/* Save old mask */
temp = (vpsw >> 24) & 0xff;
/* Update Mask */
vpsw |= ((uint32)reg << 24);
sim_debug(DEBUG_VMA, &cpu_dev, "VPSW %08x d=%08x\n", vpsw, temp);
if (WriteByte(addr1, temp))
return 0;
M[(micvpsw & AMASK) >> 2] = vpsw;
sim_debug(DEBUG_VMA, &cpu_dev, "new VPSW %08x\n", vpsw);
return 1;
}
/* Handle VM Assists for STCTL instructions
* return 0 if assist could not be completed. Return 1 if successful */
int
vma_stctl(uint8 reg, uint32 addr1)
{
int reg1 = R1(reg);
uint32 miccreg;
uint32 micblok;
sim_debug(DEBUG_VMA, &cpu_dev, "STCL check %02x %08x\n", reg, addr1);
if ((addr1 & 0x3) != 0)
return 0;
micblok = (cregs[6] & 0xfffff8) >> 2;
/* Check if function enabled */
if ((cregs[6] & 0x01000000) != 0) {
miccreg = M[micblok + 5];
sim_debug(DEBUG_VMA, &cpu_dev, "STCL micacf %08x\n", miccreg);
if ((miccreg & 0x00800000) == 0)
return 0;
}
/* Point to CR0 */
miccreg = M[micblok + 1];
reg = R2(reg);
for (;;) {
uint32 temp;
temp = M[miccreg + reg1];
if (WriteFull(addr1, temp))
return 0;
if (reg1 == reg)
break;
reg1++;
reg1 &= 0xf;
addr1 += 4;
} ;
return 1;
}

Binary file not shown.

View File

@@ -2064,7 +2064,7 @@ IBM360D = ${SIMHD}/IBM360
IBM360 = ${IBM360D}/ibm360_cpu.c ${IBM360D}/ibm360_sys.c ${IBM360D}/ibm360_con.c \
${IBM360D}/ibm360_chan.c ${IBM360D}/ibm360_cdr.c ${IBM360D}/ibm360_cdp.c \
${IBM360D}/ibm360_mt.c ${IBM360D}/ibm360_lpr.c ${IBM360D}/ibm360_dasd.c \
${IBM360D}/ibm360_com.c ${IBM360D}/ibm360_scom.c
${IBM360D}/ibm360_com.c ${IBM360D}/ibm360_scom.c ${IBM360D}/ibm360_vma.c
IBM360_OPT = -I $(IBM360D) -DIBM360 -DUSE_64BIT -DUSE_SIM_CARD
IBM360_OPT32 = -I $(IBM360D) -DIBM360 -DUSE_SIM_CARD