mirror of
https://github.com/livingcomputermuseum/UniBone.git
synced 2026-02-19 22:06:12 +00:00
698 lines
14 KiB
C
698 lines
14 KiB
C
#include "11.h"
|
|
#include "ka11.h"
|
|
|
|
#include "gpios.hpp" // ARM_DEBUG_PIN*
|
|
|
|
void unibone_grant_interrupts(void) ;
|
|
int unibone_dato(unsigned addr, unsigned data);
|
|
int unibone_datob(unsigned addr, unsigned data);
|
|
int unibone_dati(unsigned addr, unsigned *data);
|
|
void unibone_prioritylevelchange(uint8_t level);
|
|
void unibone_bus_init(unsigned pulsewidth_ms) ;
|
|
|
|
|
|
int
|
|
dati_bus(Bus *bus)
|
|
{
|
|
unsigned int data;
|
|
if(!unibone_dati(bus->addr, &data))
|
|
return 1;
|
|
bus->data = data;
|
|
return 0;
|
|
}
|
|
|
|
int
|
|
dato_bus(Bus *bus)
|
|
{
|
|
return !unibone_dato(bus->addr, bus->data);
|
|
}
|
|
|
|
int
|
|
datob_bus(Bus *bus)
|
|
{
|
|
return !unibone_datob(bus->addr, bus->data);
|
|
}
|
|
|
|
void
|
|
levelchange(word psw)
|
|
{
|
|
unibone_prioritylevelchange(psw>>5);
|
|
}
|
|
|
|
|
|
|
|
|
|
enum {
|
|
PSW_PR = 0340,
|
|
PSW_T = 020,
|
|
PSW_N = 010,
|
|
PSW_Z = 004,
|
|
PSW_V = 002,
|
|
PSW_C = 001,
|
|
};
|
|
|
|
enum {
|
|
TRAP_STACK = 1,
|
|
TRAP_PWR = 2,
|
|
TRAP_BR7 = 4,
|
|
TRAP_BR6 = 010,
|
|
TRAP_BR5 = 040,
|
|
TRAP_BR4 = 0100,
|
|
TRAP_CSTOP = 01000 // can't happen?
|
|
};
|
|
|
|
#define ISSET(f) ((cpu->psw&(f)) != 0)
|
|
|
|
enum {
|
|
STATE_HALTED = 0,
|
|
STATE_RUNNING = 1,
|
|
STATE_WAITING = 2
|
|
};
|
|
|
|
word
|
|
sgn(word w)
|
|
{
|
|
return (w>>15)&1;
|
|
}
|
|
|
|
word
|
|
sxt(byte b)
|
|
{
|
|
return (word)(int8_t)b;
|
|
}
|
|
|
|
static uint32
|
|
ubxt(word a)
|
|
{
|
|
return (a&0160000)==0160000 ? a|0600000 : a;
|
|
}
|
|
|
|
void
|
|
tracestate(KA11 *cpu)
|
|
{
|
|
(void)cpu;
|
|
trace(" R0 %06o R1 %06o R2 %06o R3 %06o R4 %06o R5 %06o R6 %06o R7 %06o\n"
|
|
" 10 %06o 11 %06o 12 %06o 13 %06o 14 %06o 15 %06o 16 %06o 17 %06o\n"
|
|
" BA %06o IR %06o PSW %03o\n"
|
|
,
|
|
cpu->r[0], cpu->r[1], cpu->r[2], cpu->r[3],
|
|
cpu->r[4], cpu->r[5], cpu->r[6], cpu->r[7],
|
|
cpu->r[8], cpu->r[9], cpu->r[10], cpu->r[11],
|
|
cpu->r[12], cpu->r[13], cpu->r[14], cpu->r[15],
|
|
cpu->ba, cpu->ir, cpu->psw);
|
|
}
|
|
|
|
void
|
|
printstate(KA11 *cpu)
|
|
{
|
|
(void)cpu;
|
|
printf(" R0 %06o R1 %06o R2 %06o R3 %06o R4 %06o R5 %06o R6 %06o R7 %06o\n"
|
|
" 10 %06o 11 %06o 12 %06o 13 %06o 14 %06o 15 %06o 16 %06o 17 %06o\n"
|
|
" BA %06o IR %06o PSW %03o\n"
|
|
,
|
|
cpu->r[0], cpu->r[1], cpu->r[2], cpu->r[3],
|
|
cpu->r[4], cpu->r[5], cpu->r[6], cpu->r[7],
|
|
cpu->r[8], cpu->r[9], cpu->r[10], cpu->r[11],
|
|
cpu->r[12], cpu->r[13], cpu->r[14], cpu->r[15],
|
|
cpu->ba, cpu->ir, cpu->psw);
|
|
}
|
|
|
|
// only to be called from ka11_condstep() thread
|
|
void
|
|
ka11_reset(KA11 *cpu)
|
|
{
|
|
Busdev *bd;
|
|
|
|
cpu->traps = 0;
|
|
cpu->external_intr = 0;
|
|
cpu->mutex = PTHREAD_MUTEX_INITIALIZER ;
|
|
|
|
for(bd = cpu->bus->devs; bd; bd = bd->next)
|
|
bd->reset(bd->dev);
|
|
}
|
|
|
|
int
|
|
dati(KA11 *cpu, int b)
|
|
{
|
|
trace("dati %06o:\n", cpu->ba);
|
|
if(!b && cpu->ba&1)
|
|
goto be;
|
|
|
|
/* internal registers */
|
|
if((cpu->ba&0177400) == 0177400){
|
|
switch(cpu->ba&0377){
|
|
case 0170: case 0171:
|
|
cpu->bus->data = cpu->sw;
|
|
goto ok;
|
|
case 0376: case 0377:
|
|
cpu->bus->data = cpu->psw;
|
|
goto ok;
|
|
|
|
/* respond but don't return real data */
|
|
case 0147:
|
|
cpu->bus->data = 0;
|
|
goto ok;
|
|
}
|
|
}
|
|
|
|
cpu->bus->addr = ubxt(cpu->ba)&~1;
|
|
if(dati_bus(cpu->bus))
|
|
goto be;
|
|
ok:
|
|
trace("%06o\n", cpu->bus->data);
|
|
cpu->be = 0;
|
|
return 0;
|
|
be:
|
|
trace("BE\n");
|
|
cpu->be++;
|
|
return 1;
|
|
}
|
|
|
|
int
|
|
dato(KA11 *cpu, int b)
|
|
{
|
|
trace("dato %06o %06o %d\n", cpu->ba, cpu->bus->data, b);
|
|
if(!b && cpu->ba&1)
|
|
goto be;
|
|
|
|
/* internal registers */
|
|
if((cpu->ba&0177400) == 0177400){
|
|
switch(cpu->ba&0377){
|
|
case 0170: case 0171:
|
|
/* can't write switches */
|
|
goto ok;
|
|
case 0376: case 0377:
|
|
/* writes 0 for the odd byte.
|
|
I think this is correct. */
|
|
cpu->psw = cpu->bus->data;
|
|
levelchange(cpu->psw);
|
|
goto ok;
|
|
}
|
|
}
|
|
|
|
if(b){
|
|
cpu->bus->addr = ubxt(cpu->ba);
|
|
if(datob_bus(cpu->bus))
|
|
goto be;
|
|
}else{
|
|
cpu->bus->addr = ubxt(cpu->ba)&~1;
|
|
if(dato_bus(cpu->bus))
|
|
goto be;
|
|
}
|
|
ok:
|
|
cpu->be = 0;
|
|
return 0;
|
|
be:
|
|
cpu->be++;
|
|
return 1;
|
|
}
|
|
|
|
static void
|
|
svc(KA11 *cpu, Bus *bus)
|
|
{
|
|
int l;
|
|
Busdev *bd;
|
|
static int brtraps[4] = { TRAP_BR4, TRAP_BR5, TRAP_BR6, TRAP_BR7 };
|
|
for(l = 0; l < 4; l++){
|
|
cpu->br[l].bg = nil;
|
|
cpu->br[l].dev = nil;
|
|
}
|
|
cpu->traps &= ~(TRAP_BR4|TRAP_BR5|TRAP_BR6|TRAP_BR7);
|
|
for(bd = bus->devs; bd; bd = bd->next){
|
|
l = bd->svc(bus, bd->dev);
|
|
if(l >= 4 && l <= 7 && cpu->br[l-4].bg == nil){
|
|
cpu->br[l-4].bg = bd->bg;
|
|
cpu->br[l-4].dev = bd->dev;
|
|
cpu->traps |= brtraps[l-4];
|
|
}
|
|
}
|
|
}
|
|
|
|
static int
|
|
addrop(KA11 *cpu, int m, int b)
|
|
{
|
|
int r;
|
|
int ai;
|
|
r = m&7;
|
|
m >>= 3;
|
|
ai = 1 + (!b || (r&6)==6 || m&1);
|
|
if(m == 0){
|
|
assert(0);
|
|
return 0;
|
|
}
|
|
switch(m&6){
|
|
case 0: // REG
|
|
cpu->b = cpu->ba = cpu->r[r];
|
|
return 0; // this already is mode 1
|
|
case 2: // INC
|
|
cpu->ba = cpu->r[r];
|
|
cpu->b = cpu->r[r] = cpu->r[r] + ai;
|
|
break;
|
|
case 4: // DEC
|
|
cpu->b = cpu->ba = cpu->r[r]-ai;
|
|
if(r == 6 && (cpu->ba&~0377) == 0) cpu->traps |= TRAP_STACK;
|
|
cpu->r[r] = cpu->ba;
|
|
break;
|
|
case 6: // INDEX
|
|
cpu->ba = cpu->r[7];
|
|
cpu->r[7] += 2;
|
|
if(dati(cpu, 0)) return 1;
|
|
cpu->b = cpu->ba = cpu->bus->data + cpu->r[r];
|
|
break;
|
|
}
|
|
if(m&1){
|
|
if(dati(cpu, 0)) return 1;
|
|
cpu->b = cpu->ba = cpu->bus->data;
|
|
}
|
|
return 0;
|
|
|
|
}
|
|
|
|
static int
|
|
fetchop(KA11 *cpu, int t, int m, int b)
|
|
{
|
|
int r;
|
|
r = m&7;
|
|
if((m&070) == 0)
|
|
cpu->r[t] = cpu->r[r];
|
|
else{
|
|
if(dati(cpu, b)) return 1;
|
|
cpu->r[t] = cpu->bus->data;
|
|
if(b && cpu->ba&1) cpu->r[t] = cpu->r[t]>>8;
|
|
}
|
|
if(b) cpu->r[t] = sxt(cpu->r[t]);
|
|
return 0;
|
|
}
|
|
|
|
static int
|
|
readop(KA11 *cpu, int t, int m, int b)
|
|
{
|
|
return !(addrop(cpu, m, b) == 0 && fetchop(cpu, t, m, b) == 0);
|
|
}
|
|
|
|
static int
|
|
writedest(KA11 *cpu, word v, int b)
|
|
{
|
|
int d;
|
|
if((cpu->ir & 070) == 0){
|
|
d = cpu->ir & 7;
|
|
if(b) SETMASK(cpu->r[d], v, 0377);
|
|
else cpu->r[d] = v;
|
|
}else{
|
|
if(cpu->ba&1) v <<= 8;
|
|
cpu->bus->data = v;
|
|
if(dato(cpu, b)) return 1;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
static void
|
|
setnz(KA11 *cpu, word w)
|
|
{
|
|
cpu->psw &= ~(PSW_N|PSW_Z);
|
|
if(w & 0100000) cpu->psw |= PSW_N;
|
|
if(w == 0) cpu->psw |= PSW_Z;
|
|
}
|
|
|
|
void
|
|
step(KA11 *cpu)
|
|
{
|
|
uint by;
|
|
uint br;
|
|
uint b;
|
|
uint c;
|
|
uint src, dst, sf, df, sm, dm;
|
|
word mask, sign;
|
|
int inhov;
|
|
byte oldpsw;
|
|
|
|
// printf("fetch from %06o\n", cpu->r[7]);
|
|
// printstate(cpu);
|
|
|
|
#define SP cpu->r[6]
|
|
#define PC cpu->r[7]
|
|
#define SR cpu->r[010]
|
|
#define DR cpu->r[011]
|
|
#define TV cpu->r[012]
|
|
#define BA cpu->ba
|
|
#define PSW cpu->psw
|
|
|
|
#define RD_B if(sm != 0) if(readop(cpu, 010, src, by)) goto be;\
|
|
if(dm != 0) if(readop(cpu, 011, dst, by)) goto be;\
|
|
if(sm == 0) fetchop(cpu, 010, src, by);\
|
|
if(dm == 0) fetchop(cpu, 011, dst, by)
|
|
#define RD_U if(dm != 0) if(readop(cpu, 011, dst, by)) goto be;\
|
|
if(dm == 0) fetchop(cpu, 011, dst, by);\
|
|
SR = DR
|
|
#define WR if(writedest(cpu, b, by)) goto be
|
|
#define NZ setnz(cpu, b)
|
|
#define SVC goto service
|
|
#define TRAP(v) TV = v; goto trap
|
|
#define CLC cpu->psw &= ~PSW_C
|
|
#define CLV cpu->psw &= ~PSW_V
|
|
#define CLCV cpu->psw &= ~(PSW_V|PSW_C)
|
|
#define SEV cpu->psw |= PSW_V
|
|
#define SEC cpu->psw |= PSW_C
|
|
#define C if(b & 0200000) SEC
|
|
#define NC if((b & 0200000) == 0) SEC
|
|
#define BXT if(by) b = sxt(b)
|
|
#define BR PC += br
|
|
#define CBR(c) if(((c)>>(cpu->psw&017)) & 1) BR
|
|
#define PUSH SP -= 2; if(!inhov && (SP&~0377) == 0) cpu->traps |= TRAP_STACK
|
|
#define POP SP += 2
|
|
#define OUT(a,d) cpu->ba = (a); cpu->bus->data = (d); if(dato(cpu, 0)) goto be
|
|
#define IN(d) if(dati(cpu, 0)) goto be; d = cpu->bus->data
|
|
#define INA(a,d) cpu->ba = a; if(dati(cpu, 0)) goto be; d = cpu->bus->data
|
|
#define TR(m) trace("%06o "#m"\n", PC-2)
|
|
#define TRB(m) trace("%06o "#m"%s\n", PC-2, by ? "B" : "")
|
|
|
|
oldpsw = PSW;
|
|
INA(PC, cpu->ir);
|
|
PC += 2; /* don't increment on bus error! */
|
|
by = !!(cpu->ir&B15);
|
|
br = sxt(cpu->ir)<<1;
|
|
src = cpu->ir>>6 & 077;
|
|
sf = src & 7;
|
|
sm = src>>3 & 7;
|
|
dst = cpu->ir & 077;
|
|
df = dst & 7;
|
|
dm = dst>>3 & 7;
|
|
if(by) mask = M8, sign = B7;
|
|
else mask = M16, sign = B15;
|
|
|
|
inhov = 0;
|
|
/* Binary */
|
|
switch(cpu->ir & 0170000){
|
|
case 0110000: case 0010000: TRB(MOV);
|
|
RD_B; CLV;
|
|
b = SR; NZ;
|
|
if(dm==0) cpu->r[df] = SR;
|
|
else writedest(cpu, SR, by);
|
|
SVC;
|
|
case 0120000: case 0020000: TRB(CMP);
|
|
RD_B; CLCV;
|
|
b = SR + W(~DR) + 1; NC; BXT;
|
|
if(sgn((SR ^ DR) & ~(DR ^ b))) SEV;
|
|
NZ; SVC;
|
|
case 0130000: case 0030000: TRB(BIT);
|
|
RD_B; CLV;
|
|
b = DR & SR;
|
|
NZ; SVC;
|
|
case 0140000: case 0040000: TRB(BIC);
|
|
RD_B; CLV;
|
|
b = DR & ~SR;
|
|
NZ; WR; SVC;
|
|
case 0150000: case 0050000: TRB(BIS);
|
|
RD_B; CLV;
|
|
b = DR | SR;
|
|
NZ; WR; SVC;
|
|
case 0060000: TR(ADD);
|
|
by = 0; RD_B; CLCV;
|
|
b = SR + DR; C;
|
|
if(sgn(~(SR ^ DR) & (DR ^ b))) SEV;
|
|
NZ; WR; SVC;
|
|
case 0160000: TR(SUB);
|
|
by = 0; RD_B; CLCV;
|
|
b = DR + W(~SR) + 1; NC;
|
|
if(sgn((SR ^ DR) & (DR ^ b))) SEV;
|
|
NZ; WR; SVC;
|
|
|
|
/* Reserved instructions */
|
|
case 0170000: case 0070000: goto ri;
|
|
}
|
|
|
|
/* Unary */
|
|
switch(cpu->ir & 0007700){
|
|
case 0005000: TRB(CLR);
|
|
RD_U; CLCV;
|
|
b = 0;
|
|
NZ; WR; SVC;
|
|
case 0005100: TRB(COM);
|
|
RD_U; CLV; SEC;
|
|
b = W(~SR);
|
|
NZ; WR; SVC;
|
|
case 0005200: TRB(INC);
|
|
RD_U; CLV;
|
|
b = W(SR+1); BXT;
|
|
if(sgn(~SR&b)) SEV;
|
|
NZ; WR; SVC;
|
|
case 0005300: TRB(DEC);
|
|
RD_U; CLV;
|
|
b = W(SR+~0); BXT;
|
|
if(sgn(SR&~b)) SEV;
|
|
NZ; WR; SVC;
|
|
case 0005400: TRB(NEG);
|
|
RD_U; CLCV;
|
|
b = W(~SR+1); BXT; if(b) SEC;
|
|
if(sgn(b&SR)) SEV;
|
|
NZ; WR; SVC;
|
|
case 0005500: TRB(ADC);
|
|
RD_U; c = ISSET(PSW_C); CLCV;
|
|
b = SR + c; C; BXT;
|
|
if(sgn(~SR&b)) SEV;
|
|
NZ; WR; SVC;
|
|
case 0005600: TRB(SBC);
|
|
RD_U; c = !ISSET(PSW_C)-1; CLCV;
|
|
b = W(SR+c); if(c && SR == 0) SEC; BXT;
|
|
if(sgn(SR&~b)) SEV;
|
|
NZ; WR; SVC;
|
|
case 0005700: TRB(TST);
|
|
RD_U; CLCV;
|
|
b = SR;
|
|
NZ; SVC;
|
|
|
|
case 0006000: TRB(ROR);
|
|
RD_U; c = ISSET(PSW_C); CLCV;
|
|
b = (SR&mask) >> 1; if(c) b |= sign; if(SR & 1) SEC; BXT;
|
|
if((PSW>>3^PSW)&1) SEV;
|
|
NZ; WR; SVC;
|
|
case 0006100: TRB(ROL);
|
|
RD_U; c = ISSET(PSW_C); CLCV;
|
|
b = (SR<<1) & mask; if(c) b |= 1; if(SR & B15) SEC; BXT;
|
|
if((PSW>>3^PSW)&1) SEV;
|
|
NZ; WR; SVC;
|
|
case 0006200: TRB(ASR);
|
|
RD_U; c = ISSET(PSW_C); CLCV;
|
|
b = W(SR>>1) | SR&B15; if(SR & 1) SEC; BXT;
|
|
if((PSW>>3^PSW)&1) SEV;
|
|
NZ; WR; SVC;
|
|
case 0006300: TRB(ASL);
|
|
RD_U; CLCV;
|
|
b = W(SR<<1); if(SR & B15) SEC; BXT;
|
|
if((PSW>>3^PSW)&1) SEV;
|
|
NZ; WR; SVC;
|
|
|
|
case 0006400:
|
|
case 0006500:
|
|
case 0006600:
|
|
case 0006700:
|
|
goto ri;
|
|
|
|
}
|
|
|
|
switch(cpu->ir & 0107400){
|
|
case 0004000:
|
|
case 0004400: TR(JSR);
|
|
if(dm == 0) goto ill;
|
|
if(addrop(cpu, dst, 0)) goto be;
|
|
DR = cpu->b;
|
|
PUSH; OUT(SP, cpu->r[sf]);
|
|
cpu->r[sf] = PC; PC = DR;
|
|
SVC;
|
|
case 0104000: TR(EMT); TRAP(030);
|
|
case 0104400: TR(TRAP); TRAP(034);
|
|
}
|
|
|
|
/* Branches */
|
|
switch(cpu->ir & 0103400){
|
|
case 0000400: TR(BR); BR; SVC;
|
|
case 0001000: TR(BNE); CBR(0x0F0F); SVC;
|
|
case 0001400: TR(BEQ); CBR(0xF0F0); SVC;
|
|
case 0002000: TR(BGE); CBR(0xCC33); SVC;
|
|
case 0002400: TR(BLT); CBR(0x33CC); SVC;
|
|
case 0003000: TR(BGT); CBR(0x0C03); SVC;
|
|
case 0003400: TR(BLE); CBR(0xF3FC); SVC;
|
|
case 0100000: TR(BPL); CBR(0x00FF); SVC;
|
|
case 0100400: TR(BMI); CBR(0xFF00); SVC;
|
|
case 0101000: TR(BHI); CBR(0x0505); SVC;
|
|
case 0101400: TR(BLOS); CBR(0xFAFA); SVC;
|
|
case 0102000: TR(BVC); CBR(0x3333); SVC;
|
|
case 0102400: TR(BVS); CBR(0xCCCC); SVC;
|
|
case 0103000: TR(BCC); CBR(0x5555); SVC;
|
|
case 0103400: TR(BCS); CBR(0xAAAA); SVC;
|
|
}
|
|
|
|
// Hope we caught all instructions we meant to
|
|
assert((cpu->ir & 0177400) == 0);
|
|
|
|
/* Misc */
|
|
switch(cpu->ir & 0300){
|
|
case 0100: TR(JMP);
|
|
if(dm == 0) goto ill;
|
|
if(addrop(cpu, dst, 0)) goto be;
|
|
PC = cpu->b;
|
|
SVC;
|
|
case 0200:
|
|
switch(cpu->ir&070){
|
|
case 000: TR(RTS);
|
|
BA = SP; POP;
|
|
PC = cpu->r[df];
|
|
IN(cpu->r[df]);
|
|
SVC;
|
|
case 010: case 020: case 030:
|
|
goto ri;
|
|
case 040: case 050: TR(CCC); PSW &= ~(cpu->ir&017); SVC;
|
|
case 060: case 070: TR(SEC); PSW |= cpu->ir&017; SVC;
|
|
}
|
|
case 0300: TR(SWAB);
|
|
RD_U; CLC;
|
|
b = WD(DR & 0377, (DR>>8) & 0377);
|
|
NZ; WR; SVC;
|
|
}
|
|
|
|
/* Operate */
|
|
switch(cpu->ir & 7){
|
|
case 0: TR(HALT); cpu->state = STATE_HALTED; return;
|
|
case 1: TR(WAIT); cpu->state = STATE_WAITING; return;
|
|
case 2: TR(RTI);
|
|
BA = SP; POP; IN(PC);
|
|
BA = SP; POP; IN(PSW);
|
|
levelchange(cpu->psw) ;
|
|
SVC;
|
|
case 3: TR(BPT); TRAP(014);
|
|
case 4: TR(IOT); TRAP(020);
|
|
case 5: TR(RESET); ka11_reset(cpu); unibone_bus_init(10) ; SVC;
|
|
}
|
|
|
|
// All other instructions should be reserved now
|
|
|
|
ri: TRAP(010);
|
|
ill: TRAP(4);
|
|
be: if(cpu->be > 1){
|
|
printf("double bus error, HALT\n");
|
|
cpu->state = STATE_HALTED;
|
|
return;
|
|
}
|
|
trace("bus error at %06o\n", cpu->ba);
|
|
TRAP(4);
|
|
|
|
trap:
|
|
trace("TRAP %o\n", TV);
|
|
PUSH; OUT(SP, PSW);
|
|
PUSH; OUT(SP, PC);
|
|
INA(TV, PC);
|
|
INA(TV+2, PSW);
|
|
levelchange(PSW);
|
|
/* no trace trap after a trap */
|
|
oldpsw = PSW;
|
|
|
|
tracestate(cpu);
|
|
return; // TODO: is this correct?
|
|
// SVC;
|
|
|
|
service:
|
|
{
|
|
// external interrupt from parallel threads?
|
|
pthread_mutex_lock(&cpu->mutex) ;
|
|
bool external_intr = cpu->external_intr ;
|
|
word external_intrvec = cpu->external_intrvec ;
|
|
cpu->external_intr = 0 ;
|
|
pthread_mutex_unlock(&cpu->mutex) ;
|
|
if (external_intr){
|
|
TRAP(external_intrvec);
|
|
}
|
|
}
|
|
|
|
|
|
c = PSW >> 5;
|
|
if(oldpsw & PSW_T){
|
|
oldpsw &= ~PSW_T;
|
|
TRAP(014);
|
|
}else if(cpu->traps & TRAP_STACK){
|
|
cpu->traps &= ~TRAP_STACK;
|
|
inhov = 1;
|
|
TRAP(4);
|
|
}else if(cpu->traps & TRAP_PWR){
|
|
cpu->traps &= ~TRAP_PWR;
|
|
TRAP(024);
|
|
}else if(c < 7 && cpu->traps & TRAP_BR7){
|
|
cpu->traps &= ~TRAP_BR7;
|
|
TRAP(cpu->br[3].bg(cpu->br[3].dev));
|
|
}else if(c < 6 && cpu->traps & TRAP_BR6){
|
|
cpu->traps &= ~TRAP_BR6;
|
|
TRAP(cpu->br[2].bg(cpu->br[2].dev));
|
|
}else if(c < 5 && cpu->traps & TRAP_BR5){
|
|
cpu->traps &= ~TRAP_BR5;
|
|
TRAP(cpu->br[1].bg(cpu->br[1].dev));
|
|
}else if(c < 4 && cpu->traps & TRAP_BR4){
|
|
cpu->traps &= ~TRAP_BR4;
|
|
TRAP(cpu->br[0].bg(cpu->br[0].dev));
|
|
}else
|
|
// TODO? console stop
|
|
/* fetch next instruction */
|
|
return;
|
|
}
|
|
|
|
// to be called from parallel threads to signal asnyc intr
|
|
// (unibusadapter worker thread)
|
|
void
|
|
ka11_setintr(KA11 *cpu, unsigned vec)
|
|
{
|
|
pthread_mutex_lock(&cpu->mutex) ;
|
|
cpu->external_intr = true;
|
|
cpu->external_intrvec = vec;
|
|
trace("INTR vec=%03o\n", vec) ;
|
|
if (cpu->state == STATE_WAITING) // atomically
|
|
cpu->state = STATE_RUNNING ;
|
|
pthread_mutex_unlock(&cpu->mutex) ;
|
|
}
|
|
|
|
// only to be called from ka11_condstep() thread
|
|
|
|
void
|
|
ka11_pwrdown(KA11 *cpu)
|
|
{
|
|
cpu->traps |= TRAP_PWR;
|
|
}
|
|
|
|
// only to be called from ka11_condstep() thread
|
|
// if locked, will lock DATI and unibus adapter()!
|
|
void
|
|
ka11_pwrup(KA11 *cpu)
|
|
{
|
|
INA(024, PC);
|
|
INA(024+2, PSW);
|
|
return ;
|
|
be:
|
|
trace("BE\n");
|
|
cpu->be++ ;
|
|
}
|
|
|
|
void
|
|
ka11_condstep(KA11 *cpu)
|
|
{
|
|
if(cpu->state == STATE_RUNNING || cpu->state == STATE_WAITING)
|
|
// GRANT Interrupts before opcode fetch, or when CPU is on WAIT
|
|
unibone_grant_interrupts() ;
|
|
|
|
if((cpu->state == STATE_RUNNING) ||
|
|
(cpu->state == STATE_WAITING && cpu->traps)){
|
|
cpu->state = STATE_RUNNING;
|
|
// external_intr WAIT handled atomically in ka11_setintr() !
|
|
|
|
svc(cpu, cpu->bus);
|
|
step(cpu);
|
|
}
|
|
}
|
|
|
|
void
|
|
run(KA11 *cpu)
|
|
{
|
|
cpu->state = STATE_RUNNING;
|
|
while(cpu->state != STATE_HALTED){
|
|
ka11_condstep(cpu);
|
|
}
|
|
|
|
printstate(cpu);
|
|
}
|