1304 lines
26 KiB
C
1304 lines
26 KiB
C
/*
|
||
* basic pdp-8i behavioral model
|
||
* ment to look and act like the verilog model
|
||
* brad@heeltoe.com
|
||
*/
|
||
|
||
#include <stdio.h>
|
||
#include <stdlib.h>
|
||
#include <signal.h>
|
||
#include <string.h>
|
||
#include <fcntl.h>
|
||
|
||
typedef unsigned char u8;
|
||
typedef unsigned short u12;
|
||
typedef unsigned short u15;
|
||
typedef unsigned int u20;
|
||
typedef unsigned char u3;
|
||
typedef unsigned char u7;
|
||
|
||
u8 binfile[16*1024];
|
||
int binfile_size;
|
||
|
||
#define MEMSIZE (32*1024)
|
||
u12 mem[MEMSIZE];
|
||
|
||
#define RFSIZE (1024*1024)
|
||
u12 rf[RFSIZE];
|
||
int rf_size;
|
||
|
||
int tc_status_a;
|
||
int tc_status_b;
|
||
int tc_err_flag;
|
||
|
||
char tto_buf[1024];
|
||
int tto_buf_count;
|
||
|
||
int kw_flag;
|
||
int kw_clk_en;
|
||
int kw_int_en;
|
||
int kw_int_req;
|
||
int kw_clk;
|
||
int kw_int_count;
|
||
|
||
int d_load = 0;
|
||
int d_fetch = 0;
|
||
int d_decode = 0;
|
||
int d_cycle = 0;
|
||
int d_mem = 0;
|
||
int d_trace = 0;
|
||
int d_dma = 0;
|
||
int d_io = 0;
|
||
|
||
int loadbin(char *fn)
|
||
{
|
||
int f, ch, o;
|
||
int rubout, newfield, state, high, low, done;
|
||
int word, csum;
|
||
u12 origin, field;
|
||
|
||
f = open(fn, O_RDONLY);
|
||
if (f < 0) {
|
||
perror(fn);
|
||
return -1;
|
||
}
|
||
|
||
binfile_size = read(f, binfile, sizeof(binfile));
|
||
|
||
if (d_load) printf("binload: %d bytes\n", binfile_size);
|
||
|
||
done = 0;
|
||
rubout = 0;
|
||
state = 0;
|
||
csum = 0;
|
||
|
||
for (o = 0; o < binfile_size && !done; o++) {
|
||
ch = binfile[o];
|
||
|
||
if (rubout) {
|
||
rubout = 0;
|
||
continue;
|
||
}
|
||
|
||
if (ch == 0377) {
|
||
rubout = 1;
|
||
continue;
|
||
}
|
||
|
||
if (ch > 0200) {
|
||
newfield = (ch & 070) << 9;
|
||
continue;
|
||
}
|
||
|
||
switch (state) {
|
||
case 0:
|
||
/* leader */
|
||
if ((ch != 0) && (ch != 0200)) state = 1;
|
||
high = ch;
|
||
break;
|
||
|
||
case 1:
|
||
/* low byte */
|
||
low = ch;
|
||
state = 2;
|
||
break;
|
||
|
||
case 2:
|
||
/* high with test */
|
||
word = (high << 6) | low;
|
||
if (ch == 0200) {
|
||
if ((csum - word) & 07777) {
|
||
printf("loadbin: checksum error\n");
|
||
}
|
||
done = 1;
|
||
continue;
|
||
}
|
||
csum = csum + low + high;
|
||
if (word >= 010000) {
|
||
origin = word & 07777;
|
||
} else {
|
||
if ((field | origin) >= MEMSIZE) {
|
||
printf("loadbin: too big\n");
|
||
}
|
||
|
||
if (d_load) printf("mem[%o] = %o\n", field|origin, word&07777);
|
||
|
||
mem[field | origin] = word & 07777;
|
||
origin = (origin + 1) & 07777;
|
||
}
|
||
field = newfield;
|
||
high = ch;
|
||
state = 1;
|
||
break;
|
||
}
|
||
}
|
||
|
||
close(f);
|
||
return 0;
|
||
}
|
||
|
||
int loaddisk(char *fn)
|
||
{
|
||
int fd, ret;
|
||
|
||
fd = open(fn, O_RDONLY);
|
||
if (fd < 0) {
|
||
perror(fn);
|
||
return -1;
|
||
}
|
||
|
||
ret = read(fd, rf, sizeof(rf));
|
||
if (ret < 0) {
|
||
perror(fn);
|
||
} else {
|
||
rf_size = ret / 2;
|
||
printf("rf_size %d\n", rf_size);
|
||
ret = 0;
|
||
}
|
||
|
||
close(fd);
|
||
return ret;
|
||
}
|
||
|
||
char *disassem(int pc, int mb)
|
||
{
|
||
static char buf[128];
|
||
char b1[64];
|
||
int i, b[12];
|
||
|
||
for (i = 0; i < 12; i++)
|
||
b[i] = mb & (1 << i);
|
||
|
||
buf[0] = 0;
|
||
|
||
switch ((mb & 07000) >> 9) {
|
||
case 0: sprintf(buf, "and "); goto d;
|
||
case 1: sprintf(buf, "tad "); goto d;;
|
||
case 2: sprintf(buf, "isz "); goto d;;
|
||
case 3: sprintf(buf, "dca "); goto d;;
|
||
case 4: sprintf(buf, "jms "); goto d;;
|
||
case 5: sprintf(buf, "jmp ");
|
||
d:
|
||
if (b[8]) strcat(buf, "I ");
|
||
if (!b[7]) strcat(buf, "Z ");
|
||
sprintf(b1, "%o", mb & 0177);
|
||
strcat(buf, b1);
|
||
break;
|
||
|
||
case 6: sprintf(buf, "iot "); break;
|
||
|
||
case 7:
|
||
if (b[8] == 0) {
|
||
if (b[7]) strcat(buf, "cla ");
|
||
if (b[6]) strcat(buf, "clf ");
|
||
if (b[5]) strcat(buf, "cma ");
|
||
if (b[4]) strcat(buf, "cmla ");
|
||
switch ((mb & 016) >> 1) {
|
||
case 1: strcat(buf, "bsw "); break;
|
||
case 2: strcat(buf, "ral "); break;
|
||
case 3: strcat(buf, "rtl "); break;
|
||
case 4: strcat(buf, "rar "); break;
|
||
case 5: strcat(buf, "rtr "); break;
|
||
}
|
||
if (b[0]) strcat(buf, "iac ");
|
||
} else
|
||
if (b[8] && b[0] == 0) {
|
||
if (b[7]) strcat(buf, "cla ");
|
||
|
||
if (b[6]) strcat(buf, "sma ");
|
||
if (b[5]) strcat(buf, "sza ");
|
||
if (b[4]) strcat(buf, "snl ");
|
||
if (b[3]) strcat(buf, "skp ");
|
||
|
||
if (b[2]) strcat(buf, "osr ");
|
||
if (b[1]) strcat(buf, "hlt ");
|
||
} else {
|
||
if (b[7]) strcat(buf, "cla ");
|
||
if (b[6]) strcat(buf, "mqa ");
|
||
if (b[5]) strcat(buf, "sca ");
|
||
if (b[4]) strcat(buf, "mql ");
|
||
}
|
||
break;
|
||
}
|
||
|
||
return buf;
|
||
}
|
||
|
||
typedef unsigned char wire;
|
||
typedef unsigned char reg;
|
||
|
||
u15 pc;
|
||
u15 fetch_pc;
|
||
u12 ac;
|
||
reg l;
|
||
u3 DF, IF, IB;
|
||
u7 SF;
|
||
reg UF, UB, UI;
|
||
|
||
u12 ma;
|
||
u12 mq;
|
||
|
||
u12 switches;
|
||
wire run;
|
||
wire interrupt;
|
||
wire interrupt_enable;
|
||
//wire interrupt_enable_req;
|
||
wire interrupt_inhibit;
|
||
wire interrupt_cycle;
|
||
wire interrupt_skip;
|
||
|
||
wire UB_pending;
|
||
wire IB_pending;
|
||
wire io_interrupt;
|
||
wire io_skip, skip_condition, pc_incr, pc_skip;
|
||
|
||
int tti_flag;
|
||
int tti_event;
|
||
|
||
int tto_flag;
|
||
int tt_data;
|
||
int tt_countdown;
|
||
|
||
int tti_input_index;
|
||
char tti_data;
|
||
char tti_input[] = "START\r01:01:85\r10:10\r\r\r";
|
||
int tti_input_count = sizeof(tti_input)-1;
|
||
|
||
//int io_cycle_count;
|
||
wire io_data_avail;
|
||
u12 io_data;
|
||
|
||
wire ram_we;
|
||
|
||
u20 rf_da;
|
||
wire rf_done;
|
||
u12 rf_sta;
|
||
int rf_func;
|
||
int rf_int_req;
|
||
int rf_capac = 262144;
|
||
int rf_wlk;
|
||
int rf_burst = 1;
|
||
|
||
#define RFS_PCA 04000 /* photocell status */
|
||
#define RFS_DRE 02000 /* data req enable */
|
||
#define RFS_WLS 01000 /* write lock status */
|
||
#define RFS_EIE 00400 /* error int enable */
|
||
#define RFS_PIE 00200 /* photocell int enb */
|
||
#define RFS_CIE 00100 /* done int enable */
|
||
#define RFS_MEX 00070 /* memory extension */
|
||
#define RFS_DRL 00004 /* data late error */
|
||
#define RFS_NXD 00002 /* non-existent disk */
|
||
#define RFS_PER 00001 /* parity error */
|
||
#define RFS_ERR (RFS_WLS + RFS_DRL + RFS_NXD + RFS_PER)
|
||
|
||
#define RF_WMASK 03777
|
||
|
||
#define RF_WC 07750 /* word count */
|
||
#define RF_MA 07751 /* mem address */
|
||
|
||
#define RF_READ 2
|
||
#define RF_WRITE 4
|
||
|
||
#define INT_RF 1
|
||
|
||
void rf_int_update(void)
|
||
{
|
||
if ((rf_done && (rf_sta & RFS_CIE)) ||
|
||
((rf_sta & RFS_ERR) && (rf_sta & RFS_EIE)) ||
|
||
((rf_sta & RFS_PCA) && (rf_sta & RFS_PIE)))
|
||
{
|
||
if (d_io) printf("set rf_int_req\n");
|
||
rf_int_req |= INT_RF;
|
||
} else {
|
||
if (d_io) printf("clear rf_int_req\n");
|
||
rf_int_req &= ~INT_RF;
|
||
}
|
||
}
|
||
|
||
void rf_go(void)
|
||
{
|
||
unsigned mex, t, pa;
|
||
|
||
mex = (rf_sta & 070) >> 3;
|
||
printf("rf_go! rf_func %o, rf_da %o, wc %o, pa %o\n",
|
||
rf_func, rf_da, mem[RF_WC], (mex << 12) | mem[RF_MA]);
|
||
|
||
do {
|
||
if ((unsigned) rf_da >= rf_size) {
|
||
rf_sta = rf_sta | RFS_NXD;
|
||
break;
|
||
}
|
||
|
||
mem[RF_WC] = (mem[RF_WC] + 1) & 07777;
|
||
mem[RF_MA] = (mem[RF_MA] + 1) & 07777;
|
||
|
||
pa = (mex << 12) | mem[RF_MA];
|
||
|
||
if (rf_func == RF_READ) {
|
||
mem[pa] = rf[rf_da];
|
||
if (d_dma) printf("dma [%o] <- %o\n", pa, mem[pa]);
|
||
} else {
|
||
t = ((rf_da >> 15) & 030) | ((rf_da >> 14) & 07);
|
||
if ((rf_wlk >> t) & 1) /* write locked? */
|
||
rf_sta = rf_sta | RFS_WLS;
|
||
else { /* not locked */
|
||
rf[rf_da] = mem[pa];
|
||
}
|
||
}
|
||
|
||
rf_da = (rf_da + 1) & 03777777; /* incr disk addr */
|
||
} while ((mem[RF_WC] != 0) && (rf_burst != 0)); /* brk if wc, no brst */
|
||
|
||
if ((mem[RF_WC] != 0) && ((rf_sta & RFS_ERR) == 0)) /* more to do? */
|
||
;
|
||
else {
|
||
if (d_io) printf("rf_done!\n");
|
||
rf_done = 1;
|
||
rf_int_update();
|
||
}
|
||
|
||
if (d_io) printf("rf_go done; rf_da %o\n", rf_da);
|
||
}
|
||
|
||
void tti_set_event(void)
|
||
{
|
||
tti_event = 1;
|
||
}
|
||
|
||
void tti_service(void)
|
||
{
|
||
if (tti_input_index < tti_input_count &&
|
||
tti_flag == 0 && tti_event)
|
||
{
|
||
tti_data = tti_input[tti_input_index++];
|
||
tti_event = 0;
|
||
tti_flag = 1;
|
||
io_interrupt = 1;
|
||
}
|
||
}
|
||
|
||
void tto_service(void)
|
||
{
|
||
if (tt_countdown > 0) {
|
||
tt_countdown--;
|
||
if (tt_countdown == 0) {
|
||
|
||
printf("xxx tx_data %o\n", tt_data);
|
||
|
||
tto_flag = 1;
|
||
io_interrupt = 1;
|
||
|
||
{
|
||
int i;
|
||
tto_buf[tto_buf_count++] = tt_data;
|
||
printf("xxx output: ");
|
||
for (i = 0; i < tto_buf_count; i++) {
|
||
char ch = tto_buf[i] & 0177;
|
||
switch (ch) {
|
||
case '\n': printf("\\n"); break;
|
||
case '\r': printf("\\r"); break;
|
||
default: printf("%c", ch & 0177); break;
|
||
}
|
||
}
|
||
printf("\n");
|
||
}
|
||
|
||
}
|
||
} else {
|
||
if (tto_flag && interrupt_enable) {
|
||
printf("tto_flag set; set int\n");
|
||
io_interrupt = 1;
|
||
}
|
||
}
|
||
}
|
||
|
||
unsigned long cycles;
|
||
|
||
void
|
||
execute(void)
|
||
{
|
||
u12 memory_bus, mb;
|
||
wire ir;
|
||
wire and, tad, isz, dca, jms, jmp, iot, opr;
|
||
u12 io_select;
|
||
|
||
cycles++;
|
||
if (cycles >= 300000)
|
||
run = 0;
|
||
|
||
if (kw_clk_en) {
|
||
kw_clk++;
|
||
if (kw_clk > 16000/*125000*/) {
|
||
if (0) printf("kw_clk fired\n");
|
||
kw_clk = 0;
|
||
kw_flag = 1;
|
||
if (kw_int_en) {
|
||
kw_int_req = 1;
|
||
io_interrupt = 1;
|
||
kw_int_count++;
|
||
}
|
||
}
|
||
}
|
||
|
||
tti_service();
|
||
|
||
F0:
|
||
memory_bus = mem[(IF<<12) | pc];
|
||
fetch_pc = pc;
|
||
|
||
interrupt_skip = 0;
|
||
if (interrupt && interrupt_enable &&
|
||
!interrupt_inhibit && !interrupt_cycle)
|
||
{
|
||
printf("xxx %lu interrupt @ %o (UF%d IF%o DF%o)\n",
|
||
cycles, (IF<<12)|pc, UF, IF, DF);
|
||
interrupt_cycle = 1;
|
||
interrupt = 0;
|
||
interrupt_enable = 0;
|
||
mb = 04000;
|
||
memory_bus = mb;
|
||
ir = 4;
|
||
SF = (UF<<6) | (IF<<3) | DF;
|
||
IF = 0;
|
||
DF = 0;
|
||
IB = 0;
|
||
UF = 0;
|
||
UB = 0;
|
||
|
||
if (0) {
|
||
d_trace = 1;
|
||
d_mem = 1;
|
||
d_io = 1;
|
||
}
|
||
} else {
|
||
interrupt_cycle = 0;
|
||
mb = memory_bus;
|
||
}
|
||
|
||
if (d_fetch) {
|
||
printf("\n");
|
||
printf("fetch: if=%o, pc=%04o %04o %s\n", IF, pc, mb, disassem(pc, mb));
|
||
printf(" l=%d ac=%04o\n", l, ac);
|
||
}
|
||
|
||
if (d_trace) {
|
||
#if 0
|
||
printf("pc %04o ir %04o l%o ac %04o ion %d "
|
||
"(%s%s%s%sIF%o DF%o UF%o SF%o IB%o UB%o)\n",
|
||
(IF<<12)|pc, mb, l, ac, interrupt_enable,
|
||
IB_pending ? "i" : "",
|
||
UB_pending ? "u" : "",
|
||
interrupt_enable_req ? "I" : "",
|
||
(IB_pending || UB_pending || interrupt_enable_req) ? " " : "",
|
||
IF, DF, UF, SF, IB, UB);
|
||
#else
|
||
printf("pc %04o ir %04o l%o ac %04o ion %d "
|
||
"(IF%o DF%o UF%o SF%o IB%o UB%o)\n",
|
||
(IF<<12)|pc, mb, l, ac, interrupt_enable,
|
||
IF, DF, UF, SF, IB, UB);
|
||
#endif
|
||
}
|
||
|
||
#define bitmask(l) ((unsigned int)0xffffffff >> (31-(l)))
|
||
#define mb_bit(n) ((mb & (1<<n)) ? 1 : 0)
|
||
#define mb_bits(h,l) ((mb >> l) & bitmask(h-l))
|
||
|
||
ir = (memory_bus >> 9) & 7;
|
||
|
||
and = ir == 0;
|
||
tad = ir == 1;
|
||
isz = ir == 2;
|
||
dca = ir == 3;
|
||
jms = ir == 4;
|
||
jmp = ir == 5;
|
||
iot = ir == 6;
|
||
opr = ir == 7;
|
||
|
||
skip_condition =
|
||
((mb_bit(6) && (ac & 04000)) ||
|
||
(mb_bit(5) && (ac == 0)) ||
|
||
(mb_bit(4) && (l == 1))) ? 1 : 0;
|
||
|
||
pc_incr =
|
||
/* group 1 */
|
||
(opr & !mb_bit(8)) ||
|
||
/* group 2 */
|
||
(opr && (mb_bit(8) && !mb_bit(0)) && (skip_condition == mb_bit(3))) ||
|
||
/* group 3? */
|
||
(opr && (mb_bit(8) && mb_bit(0))) ||
|
||
iot ||
|
||
(!(opr || iot) && !interrupt_cycle);
|
||
|
||
pc_skip =
|
||
(opr && (mb_bit(8) && !mb_bit(0)) && (skip_condition ^ mb_bit(3))) ||
|
||
(iot && (io_skip || interrupt_skip));
|
||
// (iot && mb_bit(0) && io_skip);
|
||
|
||
if (d_decode) {
|
||
printf("and %d tad %d isz %d dca %d jms %d jmp %d ito %d opr %d\n",
|
||
and, tad, isz, dca, jms, jmp, iot, opr);
|
||
printf("skip %d, pc_incr %d, pc_skip %d\n",
|
||
skip_condition, pc_incr, pc_skip);
|
||
|
||
if (0) printf("skip_condition %o; %o %o %o\n",
|
||
skip_condition, mb_bit(3),
|
||
(skip_condition == mb_bit(3)),
|
||
(skip_condition ^ mb_bit(3)));
|
||
}
|
||
|
||
F1:
|
||
if (opr) {
|
||
/* group 1 */
|
||
if (mb_bit(8) == 0) {
|
||
if (mb_bit(7)) ac = 0;
|
||
if (mb_bit(6)) l = 0;
|
||
if (mb_bit(5)) ac = ~ac & 07777;
|
||
if (mb_bit(4)) l = ~l & 1;
|
||
}
|
||
|
||
/* group 2 */
|
||
if (mb_bit(8) && !mb_bit(0)) {
|
||
if (mb_bit(7)) ac = 0;
|
||
}
|
||
|
||
/* group 3 */
|
||
if (mb_bit(8) && mb_bit(0)) {
|
||
if (mb_bit(7)) ac = 0;
|
||
}
|
||
}
|
||
|
||
io_select = (mb >> 3) & 077;
|
||
|
||
if (iot) {
|
||
if (d_cycle) printf("iot; io_select %o\n", io_select);
|
||
|
||
switch (io_select) {
|
||
case 0: // ION, IOF
|
||
switch (mb & 7) {
|
||
case 1: // ION
|
||
if (d_fetch) printf("xxx ints on\n");
|
||
// interrupt_enable_req = 1;
|
||
interrupt_enable = 1;
|
||
interrupt_inhibit = 1;
|
||
break;
|
||
case 2: // IOF
|
||
if (d_fetch) printf("xxx ints off\n");
|
||
interrupt_enable = 0;
|
||
break;
|
||
case 3: /* srq? */
|
||
if (interrupt_enable)
|
||
interrupt_skip = 1;
|
||
break;
|
||
default:
|
||
printf("UNKNOWN IOX %o @ %o\n", mb, pc);
|
||
break;
|
||
}
|
||
break;
|
||
|
||
case 020: case 021: case 022: case 023: // CDF..RMF
|
||
case 024: case 025: case 026: case 027:
|
||
/* KT8/I */
|
||
switch (mb) {
|
||
case 06204:
|
||
if (d_io) printf("CINT\n");
|
||
UI = 0;
|
||
break;
|
||
case 06254:
|
||
if (d_io) printf("SINT\n");
|
||
if (UI)
|
||
io_skip = 1;
|
||
break;
|
||
case 06264:
|
||
if (d_io) printf("CUF\n");
|
||
UB = 0;
|
||
UB_pending = 1;
|
||
IB_pending = 1;
|
||
interrupt_inhibit = 1;
|
||
break;
|
||
case 06274:
|
||
if (d_io) printf("SUF\n");
|
||
UB = 1;
|
||
UB_pending = 1;
|
||
IB_pending = 1;
|
||
interrupt_inhibit = 1;
|
||
break;
|
||
|
||
default:
|
||
if (mb & 1)
|
||
DF = (mb >> 3) & 7; // CDF
|
||
if (mb & 2) {
|
||
IB = (mb >> 3) & 7; // CIF
|
||
interrupt_inhibit = 1;
|
||
IB_pending = 1;
|
||
}
|
||
switch (mb & 7) {
|
||
case 4:
|
||
switch (io_select & 7) {
|
||
case 1: ac = DF << 3; break;// RDF
|
||
case 2: ac = IF << 3; break;// RIF
|
||
case 3: ac = SF; break; // RIB
|
||
case 4: // RMF
|
||
if (d_io) printf("RMF\n");
|
||
UB = (SF >> 6) & 1;
|
||
IB = (SF >> 3) & 7;
|
||
DF = SF & 7;
|
||
IB_pending = 1;
|
||
UB_pending = 1;
|
||
interrupt_inhibit = 1;
|
||
break;
|
||
}
|
||
break;
|
||
}
|
||
break;
|
||
}
|
||
}
|
||
|
||
#if 1
|
||
switch (io_select) {
|
||
case 003:
|
||
/* ignore kie */
|
||
if (mb_bits(2,0) == 5) {
|
||
printf("KIE! %o\n", ac);
|
||
#if 0
|
||
if ((ac & 1)) {
|
||
tti_input_index = 0;
|
||
tti_input_count = 1;
|
||
tti_input[0] = '\r';
|
||
tti_set_event();
|
||
}
|
||
#endif
|
||
break;
|
||
}
|
||
|
||
if (mb_bit(0)) {
|
||
if (tti_input_index == 0 && !tti_flag)
|
||
tti_set_event();
|
||
|
||
if (tti_flag)
|
||
io_skip = 1;
|
||
}
|
||
|
||
if (mb_bit(1)) {
|
||
tti_set_event();
|
||
tti_flag = 0;
|
||
}
|
||
|
||
if (mb_bit(2)) {
|
||
if (tti_input_count > 0) {
|
||
ac = tti_data/* | 0200*/;
|
||
printf("xxx rx input %o (%d/%d)\n",
|
||
tti_data, tti_input_index, tti_input_count);
|
||
}
|
||
}
|
||
|
||
if (mb_bits(2,0) == 0) {
|
||
tti_set_event();
|
||
tti_flag = 0;
|
||
}
|
||
break;
|
||
|
||
case 004:
|
||
if (mb_bit(0)) {
|
||
if (d_io) printf("tls; tt_countdown %d\n", tt_countdown);
|
||
if (tto_flag)
|
||
io_skip = 1;
|
||
}
|
||
if (mb_bit(1)) {
|
||
tto_flag = 0;
|
||
}
|
||
if (mb_bit(2)) {
|
||
tt_data = ac;
|
||
tt_countdown = 98/*100*/;
|
||
tto_flag = 0;
|
||
}
|
||
|
||
if (mb_bits(2,0) == 5) {
|
||
printf("SPI! %o\n", ac);
|
||
}
|
||
break;
|
||
|
||
case 013: /* KW8/I */
|
||
switch (mb_bits(2, 0)) {
|
||
default:
|
||
printf("kw8/i %o?\n", mb);
|
||
break;
|
||
case 1:
|
||
kw_int_en = 1;
|
||
kw_clk_en = 1;
|
||
break;
|
||
case 2:
|
||
kw_flag = 0;
|
||
kw_clk_en = 0;
|
||
kw_int_en = 0;
|
||
printf("CCFF\n");
|
||
break;
|
||
case 3:
|
||
if (d_io) printf("CSCF\n");
|
||
if (kw_flag) {
|
||
io_skip = 1;
|
||
}
|
||
kw_flag = 0;
|
||
break;
|
||
case 6:
|
||
printf("CCEC\n");
|
||
kw_clk_en = 1;
|
||
break;
|
||
case 7:
|
||
printf("CECI\n");
|
||
kw_clk_en = 1;
|
||
kw_int_en = 1;
|
||
break;
|
||
}
|
||
break;
|
||
|
||
case 060:
|
||
if (d_io)
|
||
switch (mb_bits(2,0)) {
|
||
case 1: printf("DCMA\n"); break;
|
||
case 3: printf("DMAR\n"); break;
|
||
case 5: printf("DMAW\n"); break;
|
||
default: printf("RF60 %o\n", mb);
|
||
}
|
||
|
||
if (mb_bit(0)) {
|
||
rf_da = rf_da & ~07777; /* clear DAR<8:19> */
|
||
rf_done = 0; /* clear done */
|
||
rf_sta = rf_sta & ~RFS_ERR; /* clear errors */
|
||
rf_int_update(); /* update int req */
|
||
}
|
||
if (mb_bit(1) || mb_bit(2)) {
|
||
rf_da |= ac & 07777; /* DAR<8:19> |= AC */
|
||
rf_func = mb_bits(2,0) & ~1; /* save function */
|
||
ac = 0; /* clear AC */
|
||
printf("xxx rf_go!\n");
|
||
rf_go();
|
||
}
|
||
break;
|
||
|
||
case 061:
|
||
if (d_io)
|
||
switch (mb_bits(2,0)) {
|
||
case 1: printf("DCIM\n"); break;
|
||
case 5: printf("DIML\n"); break;
|
||
case 6: printf("DIMA\n"); break;
|
||
default: printf("RF61 %o\n", mb);
|
||
}
|
||
|
||
switch (mb_bits(2, 0)) {
|
||
case 1: /* DCIM */
|
||
rf_sta = rf_sta & 07007; /* clear STA<3:8> */
|
||
rf_int_req = 0;
|
||
if (d_io) printf("clear rf_int_req\n");
|
||
break;
|
||
|
||
case 2: /* DSAC */
|
||
// if ((rf_da & RF_WMASK) == GET_POS (rf_time))
|
||
io_skip = 1;
|
||
ac = 0;
|
||
break;
|
||
|
||
case 5: /* DIML */
|
||
if (d_io) printf("DIML\n");
|
||
rf_sta = (rf_sta & 07007) | (ac & 0770);/* STA<3:8> <- AC */
|
||
if (rf_sta & RFS_PIE) { /* photocell int? */
|
||
if (d_io) printf("DIML PIE\n");
|
||
/* generate future int for photocel */
|
||
} else {
|
||
/* cancel furture interrupt */
|
||
if (d_io) printf("DIML !PIE\n");
|
||
}
|
||
rf_int_update(); /* update int req */
|
||
ac = 0;
|
||
break;
|
||
|
||
case 6: /* DIMA */
|
||
ac = rf_sta; /* AC <- STA<0:11> */
|
||
break;
|
||
}
|
||
break;
|
||
|
||
case 062:
|
||
if (d_io)
|
||
switch (mb_bits(2,0)) {
|
||
case 1: printf("DFSE\n"); break;
|
||
case 2: printf("DFSC\n"); break;
|
||
case 3: printf("DISK\n"); break;
|
||
case 6: printf("DMAC\n"); break;
|
||
default: printf("RF62 %o\n", mb);
|
||
}
|
||
|
||
if (mb_bit(0)) { /* DFSE */
|
||
if (rf_sta & RFS_ERR)
|
||
io_skip = 1;
|
||
}
|
||
if (mb_bit(1)) { /* DFSC */
|
||
if (mb_bit(2))
|
||
ac = 0;
|
||
else {
|
||
if (rf_done)
|
||
io_skip = 1;
|
||
}
|
||
}
|
||
if (mb_bit(2)) {
|
||
ac = rf_da & 07777; /* DMAC */
|
||
}
|
||
break;
|
||
|
||
case 064:
|
||
if (d_io)
|
||
switch (mb_bits(2,0)) {
|
||
case 1: printf("DCXA\n"); break;
|
||
case 3: printf("DXAL\n"); break;
|
||
case 5: printf("DXAC\n"); break;
|
||
case 6: printf("DMMT\n"); break;
|
||
default: printf("RF64 %o\n", mb);
|
||
}
|
||
|
||
switch (mb_bits(2,0)) {
|
||
case 1: /* DCXA */
|
||
rf_da = rf_da & 07777; /* clear DAR<0:7> */
|
||
printf("xxx rf_da %o\n", rf_da);
|
||
break;
|
||
|
||
case 3: /* DXAL */
|
||
rf_da = rf_da & 07777; /* clear DAR<0:7> */
|
||
case 2: /* DXAL w/o clear */
|
||
rf_da = rf_da | ((ac & 0377) << 12); /* DAR<0:7> |= AC */
|
||
printf("xxx rf_da %o\n", rf_da);
|
||
ac = 0; /* clear AC */
|
||
break;
|
||
|
||
case 5: /* DXAC */
|
||
ac = 0; /* clear AC */
|
||
case 4: /* DXAC w/o clear */
|
||
ac = ac | ((rf_da >> 12) & 0377); /* AC |= DAR<0:7> */
|
||
break;
|
||
|
||
default:
|
||
// ac = (stop_inst << IOT_V_REASON) + AC;
|
||
break;
|
||
}
|
||
|
||
if ((unsigned) rf_da >= rf_capac) {
|
||
rf_sta = rf_sta | RFS_NXD;
|
||
} else
|
||
rf_sta = rf_sta & ~RFS_NXD;
|
||
rf_int_update();
|
||
break;
|
||
|
||
case 076:
|
||
if (d_io)
|
||
switch (mb_bits(2,0)) {
|
||
case 1: printf("DTRA\n"); break;
|
||
case 2: printf("DCTA\n"); break;
|
||
case 4: printf("DTXA\n"); break;
|
||
default: printf("676x? %o\n", mb);
|
||
}
|
||
|
||
// tc_status_a = 00034;
|
||
// tc_err_flag = 1;
|
||
|
||
if (mb_bit(0)) {
|
||
ac |= (tc_status_a & 01777);
|
||
}
|
||
if (mb_bit(1)) {
|
||
tc_status_a = 0;
|
||
}
|
||
if (mb_bit(2)) {
|
||
tc_status_a |= ac;
|
||
if ((ac & 02000) == 0)
|
||
; /* clear error flags */
|
||
if ((ac & 04000) == 0)
|
||
; /* clear control flag */
|
||
}
|
||
break;
|
||
|
||
case 077:
|
||
if (d_io)
|
||
switch (mb_bits(2,0)) {
|
||
case 1: printf("DTSF\n"); break;
|
||
case 2: printf("DTRB\n"); break;
|
||
default: printf("677x? %o\n", mb);
|
||
}
|
||
|
||
// tc_status_a = 00034;
|
||
// tc_err_flag = 1;
|
||
|
||
switch (mb_bits(2,0)) {
|
||
case 1:
|
||
if (tc_err_flag || 1)
|
||
io_skip = 1;
|
||
break;
|
||
case 2:
|
||
ac |= (tc_status_b & 01777);
|
||
break;
|
||
}
|
||
break;
|
||
}
|
||
|
||
#endif
|
||
}
|
||
|
||
tto_service();
|
||
|
||
if (rf_int_req) {
|
||
io_interrupt = 1;
|
||
}
|
||
|
||
// io_cycle_count++;
|
||
// if (io_cycle_count > 100) {
|
||
// io_cycle_count = 0;
|
||
// io_interrupt = 1;
|
||
// //printf("xxx io_interrupt\n");
|
||
// }
|
||
|
||
if (io_interrupt) {
|
||
interrupt = 1;
|
||
io_interrupt = 0;
|
||
}
|
||
|
||
if (pc_skip || io_skip)
|
||
pc = (pc + 2) & 07777;
|
||
else
|
||
if (pc_incr)
|
||
pc = (pc + 1) & 07777;
|
||
|
||
io_skip = 0;
|
||
|
||
F2:
|
||
if (opr) {
|
||
|
||
ma = (IF<<12) | fetch_pc;
|
||
|
||
// group 3
|
||
if (mb_bit(8) && mb_bit(0))
|
||
switch (mb_bits(6,4)) {
|
||
case 1: mq = ac; break;
|
||
case 2: ac = ac | mq; break;
|
||
// case 5: tmq <= mq; break;
|
||
case 4: ac = mq; break;
|
||
case 5: ac = mq; break;
|
||
}
|
||
}
|
||
|
||
if (iot)
|
||
ma = (IF<<12) | fetch_pc;
|
||
|
||
if (!(opr || iot)) {
|
||
ma = (IF<<12) | ((mb_bit(7) ? (fetch_pc & 07600) : 0) | mb_bits(6,0));
|
||
if (d_cycle) printf("ea if=%o df=%o, pc %o, ma=%05o (bits %o)\n",
|
||
IF, DF, fetch_pc, ma, mb_bits(6,0));
|
||
}
|
||
|
||
#define get_l_ac() ( (l << 12) | ac )
|
||
#define set_l_ac(v) do { unsigned int vv = (v); \
|
||
l = (vv >> 12) & 1; ac = vv & 07777; } while(0);
|
||
|
||
F3:
|
||
if (opr) {
|
||
|
||
// group 1
|
||
if (!mb_bit(8)) {
|
||
if (mb_bit(0)) // IAC
|
||
set_l_ac( get_l_ac() + 1 );
|
||
|
||
switch (mb_bits(3,1)) {
|
||
case 1: // BSW
|
||
set_l_ac( ((get_l_ac() & 077) << 6) |
|
||
((get_l_ac() & 07700) >> 6) );
|
||
break;
|
||
|
||
case 2: // RAL
|
||
//printf("ral\n");
|
||
set_l_ac( ((get_l_ac() & 010000) >> 12) |
|
||
(ac << 1) );
|
||
break;
|
||
|
||
case 3: // RTL
|
||
//printf("rtl\n");
|
||
set_l_ac( ((get_l_ac() & 010000) ? 2 : 0) |
|
||
((get_l_ac() & 004000) ? 1 : 0) |
|
||
(ac << 2) );
|
||
break;
|
||
|
||
case 4: // RAR
|
||
//printf("rar\n");
|
||
set_l_ac( ((ac & 1) << 12) |
|
||
(get_l_ac() >> 1) );
|
||
break;
|
||
|
||
case 5: // RTR
|
||
//printf("rtr\n");
|
||
set_l_ac( ((ac & 1) ? 004000 : 0) |
|
||
((ac & 2) ? 010000 : 0) |
|
||
(get_l_ac() >> 2) );
|
||
break;
|
||
}
|
||
}
|
||
|
||
if (!UF) {
|
||
// group 2
|
||
if (mb_bit(8) & !mb_bit(0)) {
|
||
if (mb_bit(2))
|
||
ac = ac | switches;
|
||
if (mb_bit(1)) {
|
||
printf("halt!\n");
|
||
run = 0;
|
||
}
|
||
}
|
||
}
|
||
|
||
if (UF) {
|
||
// group 2 - user mode (halt & osr)
|
||
if (mb_bit(8) & !mb_bit(0)) {
|
||
if (mb_bit(2))
|
||
UI = 1;
|
||
if (mb_bit(1))
|
||
UI = 1;
|
||
}
|
||
}
|
||
|
||
// group 3
|
||
if (mb_bit(8) && mb_bit(0)) {
|
||
if (mb_bits(7,4) == 016) mq = 0;
|
||
}
|
||
|
||
ir = 0;
|
||
mb = 0;
|
||
goto done;
|
||
}
|
||
|
||
if (iot) {
|
||
ir = 0;
|
||
mb = 0;
|
||
goto done;
|
||
}
|
||
|
||
if (!(opr || iot)) {
|
||
|
||
if (!mb_bit(8) & jmp) {
|
||
pc = ma & 07777;
|
||
ir = 0;
|
||
mb = 0;
|
||
goto done;
|
||
}
|
||
|
||
if (mb_bit(8)) {
|
||
mb = 0;
|
||
goto D0;
|
||
}
|
||
|
||
if (!mb_bit(8) & !jmp) {
|
||
mb = 0;
|
||
goto E0;
|
||
}
|
||
}
|
||
|
||
// DEFER
|
||
|
||
D0:
|
||
memory_bus = mem[ma];
|
||
if (d_cycle) printf("D0: ");
|
||
if (d_mem) printf("mem read [%o] -> %o\n", ma, memory_bus);
|
||
mb = memory_bus;
|
||
|
||
ram_we = 0;
|
||
// auto increment regs
|
||
|
||
if (((ma >> 3) & 0377) == 1) {
|
||
mb++;
|
||
ram_we = 1;
|
||
}
|
||
|
||
if (ram_we) {
|
||
if (d_cycle) printf("D0: ");
|
||
if (d_mem || (ma == 0 && d_trace))
|
||
printf("mem write [%o] <- %o\n", ma, mb);
|
||
mem[ma] = mb & 07777;
|
||
}
|
||
ram_we = 0;
|
||
|
||
if (jms) {
|
||
ma = (IF << 12) | mb;
|
||
|
||
if (IB_pending)
|
||
ma = (IB << 12) | mb;
|
||
} else
|
||
ma = (DF << 12) | mb;
|
||
|
||
|
||
if (jmp) {
|
||
pc = mb & 07777;
|
||
ir = 0;
|
||
mb = 0;
|
||
goto done;
|
||
}
|
||
|
||
if (!jmp) {
|
||
mb = 0;
|
||
}
|
||
|
||
// EXECUTE
|
||
E0:
|
||
mb = mem[ma];
|
||
if (d_cycle) printf("E0: ");
|
||
if (d_mem /*|| (ma == 0 && d_trace)*/)
|
||
printf("mem read [%o] -> %o\n", ma, mb);
|
||
|
||
if (isz) {
|
||
if (mb == 07777) pc++;
|
||
mb++;
|
||
}
|
||
|
||
if (dca)
|
||
mb = ac;
|
||
|
||
if (jms)
|
||
mb = pc;
|
||
|
||
if (isz || dca || jms) {
|
||
ram_we = 1;
|
||
}
|
||
|
||
if (ram_we) {
|
||
if (d_cycle) printf("E0: ");
|
||
if (d_mem /*|| (ma == 0 && d_trace)*/)
|
||
printf("mem write [%o] <- %o\n", ma, mb);
|
||
mem[ma] = mb & 07777;
|
||
}
|
||
ram_we = 0;
|
||
|
||
// note timing here; ma above is different
|
||
|
||
if (!jms)
|
||
ma = (IF << 12) | pc;
|
||
|
||
if (jms)
|
||
ma = ((ma & 070000) << 12) | ((ma & 07777) + 1);
|
||
|
||
if (and)
|
||
ac = ac & mb;
|
||
|
||
if (tad) {
|
||
set_l_ac( get_l_ac() + mb );
|
||
}
|
||
|
||
if (dca)
|
||
ac = 0;
|
||
|
||
if (jms) {
|
||
if (d_fetch) printf("jms - ma %o\n", ma & 07777);
|
||
pc = ma & 07777;
|
||
}
|
||
|
||
ir = 0;
|
||
|
||
done:
|
||
/* defered loading of IF from IB until after next jmp/jms */
|
||
if ((jmp || jms) && IB_pending) {
|
||
//printf("loading IF %o\n", IB);
|
||
IF = IB;
|
||
IB_pending = 0;
|
||
interrupt_inhibit = 0;
|
||
}
|
||
|
||
/* defer setting user flag until after next jmp/jms */
|
||
if ((jmp || jms) && UB_pending) {
|
||
UF = UB;
|
||
UB_pending = 0;
|
||
}
|
||
|
||
#if 0
|
||
/* defer setting of interrupt enable */
|
||
if ((jmp || jms) && interrupt_enable_req) {
|
||
interrupt_enable_req = 0;
|
||
interrupt_enable = 1;
|
||
}
|
||
#endif
|
||
|
||
#if 0
|
||
/* defer setting of interrupt enable */
|
||
if (interrupt_enable_req == 1) {
|
||
interrupt_enable_req = 2;
|
||
} else
|
||
if (interrupt_enable_req == 2) {
|
||
interrupt_enable_req = 0;
|
||
interrupt_enable = 1;
|
||
}
|
||
#endif
|
||
|
||
if (!UB_pending && !IB_pending) {
|
||
switch (interrupt_inhibit) {
|
||
case 1:
|
||
interrupt_inhibit = 2;
|
||
break;
|
||
case 2:
|
||
interrupt_inhibit = 0;
|
||
break;
|
||
}
|
||
}
|
||
}
|
||
|
||
void
|
||
loop(void)
|
||
{
|
||
run = 1;
|
||
|
||
IF = (pc & 070000) >> 12;
|
||
DF = IF;
|
||
pc &= 07777;
|
||
|
||
while (1) {
|
||
if (!run)
|
||
break;
|
||
execute();
|
||
}
|
||
}
|
||
|
||
void sigint_handler(int arg)
|
||
{
|
||
printf("SIGINT @ %lu cycles\n", cycles);
|
||
if (d_trace)
|
||
exit(1);
|
||
|
||
d_trace++;
|
||
}
|
||
|
||
main()
|
||
{
|
||
if (1) {
|
||
// d_load = 1;
|
||
// d_fetch = 1;
|
||
// d_decode = 1;
|
||
// d_cycle = 1;
|
||
d_trace = 1;
|
||
// d_mem = 1;
|
||
// d_dma = 1;
|
||
// d_io = 1;
|
||
}
|
||
|
||
if (1) {
|
||
loadbin("../tss8/tss8_init.bin");
|
||
loaddisk("../tss8/tss8_rf.dsk");
|
||
pc = 024200;
|
||
IB = 2;
|
||
}
|
||
|
||
if (0) {
|
||
loadbin("../images/focal569.bin");
|
||
pc = 0200;
|
||
}
|
||
|
||
signal(SIGINT, sigint_handler);
|
||
|
||
loop();
|
||
}
|
||
|
||
|
||
/*
|
||
* Local Variables:
|
||
* indent-tabs-mode:nil
|
||
* c-basic-offset:4
|
||
* End:
|
||
*/
|