1
0
mirror of https://github.com/aap/pdp6.git synced 2026-02-08 01:11:56 +00:00
Files
aap.pdp6/fe6/6/real6.c
2019-12-05 00:31:20 +01:00

773 lines
13 KiB
C
Executable File

#include "../fe.h"
#include <unistd.h>
#include <fcntl.h>
#include <sys/mman.h>
#define H2F_BASE (0xC0000000)
#define PERIPH_BASE (0xFC000000)
#define PERIPH_SPAN (0x04000000)
#define PERIPH_MASK (PERIPH_SPAN - 1)
#define LWH2F_BASE (0xFF200000)
/* Memory mapped PDP-6 interface */
enum
{
/* The more important keys, switches and lights */
REG6_CTL1_DN = 0,
REG6_CTL1_UP = 1,
MM6_START = 1,
MM6_READIN = 2,
MM6_INSTCONT = 4,
MM6_MEMCONT = 010,
MM6_INSTSTOP = 020,
MM6_MEMSTOP = 040,
MM6_STOP = MM6_INSTSTOP|MM6_MEMSTOP,
MM6_RESET = 0100,
MM6_EXEC = 0200,
MM6_ADRSTOP = 0400,
/* lights - read only */
MM6_RUN = 01000,
MM6_MCSTOP = 02000,
MM6_PWR = 04000,
/* Less important keys and switches */
REG6_CTL2_DN = 2,
REG6_CTL2_UP = 3,
MM6_THISDEP = 1,
MM6_NEXTDEP = 2,
MM6_THISEX = 4,
MM6_NEXTEX = 010,
MM6_READEROFF = 020,
MM6_READERON = 040,
MM6_FEEDPUNCH = 0100,
MM6_FEEDREAD = 0200,
MM6_REPEAT = 0400,
MM6_MEMDIS = 01000,
/* Maintenance switches */
REG6_MAINT_DN = 4,
REG6_MAINT_UP = 5,
/* switches and knobs */
REG6_DSLT = 6,
REG6_DSRT = 7,
REG6_MAS = 010,
REG6_REPEAT = 011,
/* lights */
REG6_IR = 012,
REG6_MILT = 013,
REG6_MIRT = 014,
REG6_PC = 015,
REG6_MA = 016,
REG6_PI = 017,
REG6_MBLT = 020,
REG6_MBRT = 021,
REG6_ARLT = 022,
REG6_ARRT = 023,
REG6_MQLT = 024,
REG6_MQRT = 025,
REG6_FF1 = 026,
REG6_FF2 = 027,
REG6_FF3 = 030,
REG6_FF4 = 031,
REG6_MMU = 032,
REG6_TTY = 033,
REG6_PTP = 034,
REG6_PTR = 035,
REG6_PTR_LT = 036,
REG6_PTR_RT = 037,
REG6_DIS1 = 040,
REG6_DIS2 = 041,
REG6_DIS3 = 042,
};
enum {
FEREG_REQ = 0,
FEREG_PTR,
FEREG_PTP,
FEREG_DIS
};
static u64 *h2f_base;
static u32 *virtual_base;
static u32 *getLWH2Faddr(u32 offset)
{
return (u32*)((u32)virtual_base - PERIPH_BASE + (LWH2F_BASE+offset));
}
static u64 *getH2Faddr(u32 offset)
{
return (u64*)((u32)h2f_base + offset);
}
static int memfd;
static volatile u32 *h2f_cmemif, *h2f_cmemif2;
static volatile u32 *h2f_fmemif, *h2f_fmemif2;
static volatile u32 *h2f_apr;
static volatile u32 *h2f_fe;
static volatile u32 *h2f_csl;
static volatile u32 *h2f_lw_led_addr;
static volatile u32 *h2f_lw_sw_addr;
void
deposit(hword a, word w)
{
/*
if(a < 01000000){
h2f_cmemif[0] = a & RT;
h2f_cmemif[1] = w & RT;
h2f_cmemif[2] = (w >> 18) & RT;
}else if(a < 01000020){
h2f_fmemif[0] = a & 017;
h2f_fmemif[1] = w & RT;
h2f_fmemif[2] = (w >> 18) & RT;
}else if(a < 01000040){
h2f_fmemif2[0] = a & 017 | 01000000;
h2f_fmemif2[1] = w & RT;
h2f_fmemif2[2] = (w >> 18) & RT;
}else if(a >= 02000000 && a < 03000000){
h2f_cmemif2[0] = a & RT;
h2f_cmemif2[1] = w & RT;
h2f_cmemif2[2] = (w >> 18) & RT;
*/
if(a < 020){
h2f_fmemif[0] = a & 017;
h2f_fmemif[1] = w & RT;
h2f_fmemif[2] = (w >> 18) & RT;
}else if(a < 01000020){
void dep64(u32, u64);
if(0 && a < 01000){
printf("dep %o %llo\r\n", a, w);
fflush(stdout);
}
// dep64(a, w);
h2f_cmemif[0] = a & RT;
h2f_cmemif[1] = w & RT;
h2f_cmemif[2] = (w >> 18) & RT;
}else switch(a){
case APR_DS:
h2f_apr[REG6_DSLT] = w>>18 & RT;
h2f_apr[REG6_DSRT] = w & RT;
break;
case APR_MAS:
h2f_apr[REG6_MAS] = w & RT;
break;
case APR_RPT:
h2f_apr[REG6_REPEAT] = w;
break;
#ifdef TEST
case APR_CTL1_DN:
h2f_apr[REG6_CTL1_DN] = w;
break;
case APR_CTL1_UP:
h2f_apr[REG6_CTL1_UP] = w;
break;
case APR_CTL2_DN:
h2f_apr[REG6_CTL2_DN] = w;
break;
case APR_CTL2_UP:
h2f_apr[REG6_CTL2_UP] = w;
break;
case PTR_FE:
h2f_fe[FEREG_PTR] = w;
break;
#endif
case 01001000:
*h2f_lw_led_addr = w;
break;
}
// usleep(5);
}
word
examine(hword a)
{
u64 w;
w = 0;
/*
if(a < 01000000){
h2f_cmemif[0] = a & RT;
w = h2f_cmemif[2] & RT;
w <<= 18;
w |= h2f_cmemif[1] & RT;
}else if(a < 01000020){
h2f_fmemif[0] = a & 017;
w = h2f_fmemif[2] & RT;
w <<= 18;
w |= h2f_fmemif[1] & RT;
}else if(a < 01000040){
h2f_fmemif2[0] = a & 017 | 01000000;
w = h2f_fmemif2[2] & RT;
w <<= 18;
w |= h2f_fmemif2[1] & RT;
}else if(a >= 02000000 && a < 03000000){
h2f_cmemif2[0] = a & RT;
w = h2f_cmemif2[2] & RT;
w <<= 18;
w |= h2f_cmemif2[1] & RT;
*/
if(a < 020){
h2f_fmemif[0] = a & 017;
w = h2f_fmemif[2] & RT;
w <<= 18;
w |= h2f_fmemif[1] & RT;
}else if(a < 01000020){
//u64 ex64(u32);
// w = ex64(a);
h2f_cmemif[0] = a & RT;
w = h2f_cmemif[2] & RT;
w <<= 18;
w |= h2f_cmemif[1] & RT;
}else switch(a){
case APR_DS:
w = h2f_apr[REG6_DSLT];
w <<= 18;
w |= h2f_apr[REG6_DSRT] & RT;
return w;
case APR_MAS:
w = h2f_apr[REG6_MAS];
break;
case APR_RPT:
w = h2f_apr[REG6_REPEAT];
break;
case APR_IR:
return h2f_apr[REG6_IR];
case APR_MI:
w = h2f_apr[REG6_MILT];
w <<= 18;
w |= h2f_apr[REG6_MIRT] & RT;
return w;
case APR_PC:
return h2f_apr[REG6_PC];
case APR_MA:
return h2f_apr[REG6_MA];
case APR_PIO:
return h2f_apr[REG6_PI]>>1 & 0177;
case APR_PIR:
return h2f_apr[REG6_PI]>>8 & 0177;
case APR_PIH:
return h2f_apr[REG6_PI]>>15 & 0177;
case APR_PION:
return h2f_apr[REG6_PI] & 1;
case APR_RUN:
return !!(h2f_apr[REG6_CTL1_DN] & MM6_RUN);
case APR_STOP:
return !!(h2f_apr[REG6_CTL1_DN] & MM6_MCSTOP);
#ifdef TEST
case APR_CTL1_DN:
return h2f_apr[REG6_CTL1_DN];
case APR_CTL1_UP:
return h2f_apr[REG6_CTL1_UP];
case APR_CTL2_DN:
return h2f_apr[REG6_CTL2_DN];
case APR_CTL2_UP:
return h2f_apr[REG6_CTL2_UP];
case APR_MB:
w = h2f_apr[REG6_MBLT];
w <<= 18;
w |= h2f_apr[REG6_MBRT] & RT;
return w;
case APR_AR:
w = h2f_apr[REG6_ARLT];
w <<= 18;
w |= h2f_apr[REG6_ARRT] & RT;
return w;
case APR_MQ:
w = h2f_apr[REG6_MQLT];
w <<= 18;
w |= h2f_apr[REG6_MQRT] & RT;
return w;
case TTY_TTI:
return (h2f_apr[REG6_TTY]>>9) & 0377;
case TTY_ST:
return h2f_apr[REG6_TTY] & 0177;
case PTR_PTR:
w = h2f_apr[REG6_PTR_LT];
w <<= 18;
w |= h2f_apr[REG6_PTR_RT] & RT;
return w;
case PTR_ST:
return h2f_apr[REG6_PTR] & 0177;
case FE_REQ:
return h2f_fe[FEREG_REQ];
#endif
case 01001000:
w = *h2f_lw_led_addr;
break;
case 01001001:
w = *h2f_lw_sw_addr;
break;
}
return w;
}
static void set_ta(hword a)
{
h2f_apr[REG6_MAS] = a & RT;
}
static void set_td(word d)
{
h2f_apr[REG6_DSLT] = d>>18 & RT;
h2f_apr[REG6_DSRT] = d & RT;
}
static void keydown(u32 k)
{
h2f_apr[REG6_CTL1_DN] = k;
if(k & MM6_INSTSTOP)
usleep(1000); // wait for AT1 INH to go down
}
static void keyup(u32 k)
{
h2f_apr[REG6_CTL1_UP] = k;
}
static void keytoggle(u32 k) {
keydown(k);
usleep(1000); // TODO: maybe don't sleep? or different duration?
keyup(k);
}
int isrunning(void)
{
return !!(h2f_apr[REG6_CTL1_DN] & MM6_RUN);
}
int isstopped(void)
{
return !!(h2f_apr[REG6_CTL1_DN] & MM6_MCSTOP);
}
static void waithalt(void)
{
int i;
for(i = 0; i < 10; i++){
if(!isrunning())
return;
usleep(100);
}
keytoggle(MM6_INSTSTOP);
for(i = 0; i < 10; i++){
if(!isrunning())
return;
usleep(100);
}
typestr("not halted!!!\r\n");
}
static void waitmemstop(void)
{
int i;
if(!isrunning())
return;
for(i = 0; i < 20; i++){
if(isstopped())
return;
usleep(100);
}
typestr("not stopped!!!\r\n");
}
static int run;
static int memstop;
#define X if(0)
void
cpu_start(hword a)
{
X typestr("<GO>\r\n");
cpu_stopinst();
X run = 0;
keyup(MM6_STOP | MM6_ADRSTOP);
set_ta(a);
keytoggle(MM6_START);
X run = 1;
X memstop = 0;
}
void
cpu_readin(hword a)
{
X typestr("<READIN>\r\n");
cpu_stopinst();
X run = 0;
keyup(MM6_STOP | MM6_ADRSTOP);
set_ta(a);
keytoggle(MM6_READIN);
X run = 1;
X memstop = 0;
}
void
cpu_setpc(hword a)
{
X typestr("<SETPC>\r\n");
cpu_stopinst();
X run = 0;
keydown(MM6_MEMSTOP);
keyup(MM6_ADRSTOP);
set_ta(a);
keytoggle(MM6_START);
X run = 1;
X memstop = 0;
waitmemstop();
X memstop = 1;
keyup(MM6_MEMSTOP);
keytoggle(MM6_INSTSTOP);
X run = 0;
h2f_apr[REG6_CTL2_DN] = MM6_THISEX;
usleep(1000);
h2f_apr[REG6_CTL2_UP] = MM6_THISEX;
usleep(1000);
X memstop = 0;
}
void
cpu_stopinst(void)
{
X typestr("<STOPINST>\r\n");
if(!isrunning())
return;
// TODO: what if memory stop?
keytoggle(MM6_INSTSTOP);
waithalt();
X run = 0;
}
void
cpu_stopmem(void)
{
X typestr("<STOPMEM>\r\n");
if(!isrunning() || isstopped())
return;
keydown(MM6_MEMSTOP);
waitmemstop();
X memstop = 1;
keyup(MM6_MEMSTOP);
}
static void
togglecont(void)
{
if(isstopped()){
keytoggle(MM6_MEMCONT);
X memstop = 0;
}else{
keytoggle(MM6_INSTCONT);
X memstop = 0;
X run = 1;
}
}
void
cpu_cont(void)
{
X typestr("<CONT>\r\n");
if(isrunning())
return;
keyup(MM6_STOP);
togglecont();
}
void
cpu_nextinst(void)
{
X typestr("<NEXTINST>\r\n");
if(isrunning() && !isstopped())
err("?R? ");
keydown(MM6_INSTSTOP);
X run = 0;
togglecont();
waithalt();
X run = 0;
keyup(MM6_INSTSTOP);
}
void
cpu_nextmem(void)
{
X typestr("<NEXTMEM>\r\n");
if(isrunning() && !isstopped())
err("?R? ");
keydown(MM6_MEMSTOP);
togglecont();
waitmemstop();
X memstop = 1;
keyup(MM6_MEMSTOP);
}
void
cpu_exec(word inst)
{
X typestr("<EXEC>\r\n");
if(isrunning())
err("?R? ");
set_td(inst);
keytoggle(MM6_EXEC);
}
void
cpu_ioreset(void)
{
X typestr("<RESET>\r\n");
if(isrunning())
err("?R? ");
keytoggle(MM6_RESET);
typestr("\r\n");
}
#include "flags.inc"
void
prflags(const char *fmt, u8 flags)
{
static const char *l = ".#";
printf(fmt,
l[!!(flags&0200)], l[!!(flags&0100)],
l[!!(flags&040)], l[!!(flags&020)],
l[!!(flags&010)], l[!!(flags&04)],
l[!!(flags&02)], l[!!(flags&01)]);
}
void
prdis(void)
{
u32 dis1, dis2, dis3;
dis1 = h2f_apr[REG6_DIS1];
dis2 = h2f_apr[REG6_DIS2];
dis3 = h2f_apr[REG6_DIS3];
printf("\r\nDIS\r\n");
printf("BR/%06o\r\n", dis1);
printf("X/%04o Y/%04o BRM/%03o S/%02o I/%o SZ/%o MODE/%o\r\n",
dis2&01777, (dis2>>10)&01777, (dis2>>20)&0177,
(dis3>>8)&017, (dis3>>5)&7, (dis3>>3)&3, dis3&7);
printf("DATA REQ/%o STOP/%o EDGE/%o LP/%o LP ON/%o LP FIND/%o\r\n",
!!(dis3 & 04000000),
!!(dis3 & 0400000),
!!(dis3 & 02000000),
!!(dis3 & 040000),
!!(dis3 & 020000),
!!(dis3 & 010000));
printf("MOVE/%o HALT/%o\r\n",
!!(dis3 & 0200000),
!!(dis3 & 0100000));
dis3 = h2f_apr[REG6_DIS3+1];
printf("%X\r\n", dis3);
}
void
cpu_printflags(void)
{
u32 ff1, ff2, ff3, ff4;
u32 ctl1, pi;
ff1 = h2f_apr[REG6_FF1];
ff2 = h2f_apr[REG6_FF2];
ff3 = h2f_apr[REG6_FF3];
ff4 = h2f_apr[REG6_FF4];
ctl1 = h2f_apr[REG6_CTL1_DN];
pi = h2f_apr[REG6_PI];
printf("\r\n");
prflags(ff0str, ff1>>24);
prflags(ff1str, ff1>>16);
prflags(ff2str, ff1>>8);
prflags(ff3str, ff1);
prflags(ff4str, ff2>>24);
prflags(ff5str, ff2>>16);
prflags(ff6str, ff2>>8);
prflags(ff7str, ff2);
prflags(ff8str, ff3>>24);
prflags(ff9str, ff3>>16);
prflags(ff10str, ff3>>8);
prflags(ff11str, ff3);
prflags(ff12str, ff4>>24);
prflags(ff13str, ff4>>16);
printf("PIH/%03o PIR/%03o PIO/%03o PI ACTIVE/%o\r\n",
pi>>15 & 0177, pi>>8 & 0177, pi>>1 & 0177, !!(pi & 1));
printf("RUN/%o MEM STOP/%o\r\n",
!!(ctl1 & MM6_RUN), !!(ctl1 & MM6_MCSTOP));
prdis();
fflush(stdout);
}
static void
svc_ptr(void)
{
int fd;
u8 c;
fd = devtab[DEV_PTR].fd;
if(fd < 0)
return;
if(read(fd, &c, 1) == 1){
printf("%d%d%d%d%d%d%d%d -> PTR\r\n",
!!(c&0200), !!(c&0100), !!(c&040), !!(c&020), !!(c&010),
!!(c&04), !!(c&02), !!(c&01));
fflush(stdout);
h2f_fe[FEREG_PTR] = c;
}
}
static void
svc_ptp(void)
{
int fd;
u8 c;
c = h2f_fe[FEREG_PTP];
printf("PTP <- %d%d%d%d%d%d%d%d\r\n",
!!(c&0200), !!(c&0100), !!(c&040), !!(c&020), !!(c&010),
!!(c&04), !!(c&02), !!(c&01));
fflush(stdout);
fd = devtab[DEV_PTP].fd;
if(fd < 0)
return;
write(fd, &c, 1);
}
int dis_fd = -1;
static void
svc_dis(void)
{
u32 pnt;
pnt = h2f_fe[FEREG_DIS];
if((pnt & 0x80000000) == 0)
return;
if(dis_fd >= 0)
write(dis_fd, &pnt, 4);
/*
else{
printf("%X\r\n", pnt);
fflush(stdout);
}
*/
}
void
fe_svc(void)
{
u32 req;
req = h2f_fe[FEREG_REQ];
if(req & 1) svc_ptr();
if(req & 2) svc_ptp();
// if(req & 4) svc_dis();
svc_dis();
}
void*
wcsl_thread(void *arg)
{
u32 ctl;
while(readn(dis_fd, &ctl, 4) == 0){
// printf("%o\r\n", ctl);
// fflush(stdout);
h2f_csl[ctl>>24] = ctl;
}
}
void
initcrt(const char *host)
{
dis_fd = dial(host, 3400);
if(dis_fd >= 0){
printf("display connected\n");
threadcreate(wcsl_thread, nil);
}
}
void
init6(void)
{
if((memfd = open("/dev/mem", (O_RDWR | O_SYNC))) == -1) {
fprintf(stderr, "ERROR: could not open /dev/mem...\n");
exit(1);
}
virtual_base = (u32*)mmap(nil, PERIPH_SPAN,
(PROT_READ | PROT_WRITE), MAP_SHARED, memfd, PERIPH_BASE);
if(virtual_base == MAP_FAILED) {
fprintf(stderr, "ERROR: mmap() failed...\n");
close(memfd);
exit(1);
}
h2f_base = (u64*)mmap(nil, 0x100000,
(PROT_READ | PROT_WRITE), MAP_SHARED, memfd, H2F_BASE);
if(h2f_base == MAP_FAILED) {
fprintf(stderr, "ERROR: mmap() failed...\n");
close(memfd);
exit(1);
}
h2f_cmemif = getLWH2Faddr(0x10000);
h2f_cmemif2 = getLWH2Faddr(0x20000);
h2f_fmemif = getLWH2Faddr(0x10010);
h2f_fmemif2 = getLWH2Faddr(0x20010);
// enable sdram bridge (???)
*(u32*)((u8*)virtual_base + 0x5080) = 0xFFFF;
h2f_apr = getLWH2Faddr(0x10100);
h2f_fe = getLWH2Faddr(0x20000);
h2f_csl = getLWH2Faddr(0x30000);
h2f_lw_sw_addr = getLWH2Faddr(0x10020);
h2f_lw_led_addr = getLWH2Faddr(0x10040);
// testshit();
}
void
deinit6(void)
{
if(munmap(virtual_base, PERIPH_SPAN) != 0) {
fprintf(stderr, "ERROR: munmap() failed...\n");
close(memfd);
exit(1);
}
close(memfd);
}