1
0
mirror of https://github.com/aap/pdp6.git synced 2026-01-29 21:31:11 +00:00

re-implemented memory

This commit is contained in:
aap
2016-10-28 17:44:47 +02:00
parent 783eb935de
commit ff8882ab38
4 changed files with 372 additions and 97 deletions

View File

@@ -348,9 +348,9 @@ set_mc_rq(Apr *apr, bool value)
{
apr->mc_rq = value; // 7-9
if(value && (apr->mc_rd || apr->mc_wr))
membus0 |= MEMBUS_RQ_CYC;
apr->membus.c12 |= MEMBUS_RQ_CYC;
else
membus0 &= ~MEMBUS_RQ_CYC;
apr->membus.c12 &= ~MEMBUS_RQ_CYC;
}
void
@@ -358,9 +358,9 @@ set_mc_wr(Apr *apr, bool value)
{
apr->mc_wr = value; // 7-9
if(value)
membus0 |= MEMBUS_WR_RQ;
apr->membus.c12 |= MEMBUS_WR_RQ;
else
membus0 &= ~MEMBUS_WR_RQ;
apr->membus.c12 &= ~MEMBUS_WR_RQ;
set_mc_rq(apr, apr->mc_rq); // 7-9
}
@@ -369,9 +369,9 @@ set_mc_rd(Apr *apr, bool value)
{
apr->mc_rd = value; // 7-9
if(value)
membus0 |= MEMBUS_RD_RQ;
apr->membus.c12 |= MEMBUS_RD_RQ;
else
membus0 &= ~MEMBUS_RD_RQ;
apr->membus.c12 &= ~MEMBUS_RD_RQ;
set_mc_rq(apr, apr->mc_rq); // 7-9
}
@@ -404,15 +404,15 @@ relocate(Apr *apr)
apr->rla += apr->rlr;
// 7-2, 7-10
membus0 &= ~0007777777761LL;
membus0 |= ma_fmc_select ? MEMBUS_MA_FMC_SEL1 : MEMBUS_MA_FMC_SEL0;
membus0 |= (apr->ma&01777) << 4;
membus0 |= ((word)apr->rla&017) << 14;
membus0 |= apr->rla & 0020 ? MEMBUS_MA21_1|MEMBUS_MA21 : MEMBUS_MA21_0;
membus0 |= apr->rla & 0040 ? MEMBUS_MA20_1 : MEMBUS_MA20_0;
membus0 |= apr->rla & 0100 ? MEMBUS_MA19_1 : MEMBUS_MA19_0;
membus0 |= apr->rla & 0200 ? MEMBUS_MA18_1 : MEMBUS_MA18_0;
membus0 |= apr->ma & 01 ? MEMBUS_MA35_1 : MEMBUS_MA35_0;
apr->membus.c12 &= ~0007777777761LL;
apr->membus.c12 |= ma_fmc_select ? MEMBUS_MA_FMC_SEL1 : MEMBUS_MA_FMC_SEL0;
apr->membus.c12 |= (apr->ma&01777) << 4;
apr->membus.c12 |= ((word)apr->rla&017) << 14;
apr->membus.c12 |= apr->rla & 0020 ? MEMBUS_MA21_1|MEMBUS_MA21 : MEMBUS_MA21_0;
apr->membus.c12 |= apr->rla & 0040 ? MEMBUS_MA20_1 : MEMBUS_MA20_0;
apr->membus.c12 |= apr->rla & 0100 ? MEMBUS_MA19_1 : MEMBUS_MA19_0;
apr->membus.c12 |= apr->rla & 0200 ? MEMBUS_MA18_1 : MEMBUS_MA18_0;
apr->membus.c12 |= apr->ma & 01 ? MEMBUS_MA35_1 : MEMBUS_MA35_0;
return ma_ok;
}
@@ -2748,13 +2748,11 @@ pulse(it0){
pulse(mai_addr_ack){
trace("MAI ADDR ACK\n");
nextpulse(apr, mc_addr_ack); // 7-8
curpulse(apr, mc_addr_ack); // 7-8
}
pulse(mai_rd_rs){
trace("MAI RD RS\n");
/* we do this here instead of whenever MC RD is set; 7-6, 7-9 */
apr->mb = membus1;
if(apr->ma == apr->mas)
apr->mi = apr->mb; // 7-7
if(!apr->mc_stop)
@@ -2795,8 +2793,8 @@ pulse(mc_wr_rs){
trace("MC WR RS\n");
if(apr->ma == apr->mas)
apr->mi = apr->mb; // 7-7
membus1 = apr->mb; // 7-8
membus0 |= MEMBUS_WR_RS; // 7-8
apr->membus.c34 |= apr->mb; // 7-8
apr->membus.c12 |= MEMBUS_WR_RS; // 7-8
if(!apr->mc_stop)
nextpulse(apr, mc_rs_t0); // 7-8
}
@@ -3012,6 +3010,16 @@ pulse(key_manual){
nextpulse(apr, kt0); // 5-2
}
void
curpulse(Apr *apr, Pulse *p)
{
if(apr->ncurpulses >= MAXPULSE){
fprint(stderr, "error: too many current pulses\n");
exit(1);
}
apr->clist[apr->ncurpulses++] = p;
}
void
nextpulse(Apr *apr, Pulse *p)
{
@@ -3072,13 +3080,14 @@ aprmain(void *p)
apr->iobus.c12_prev = apr->iobus.c12;
apr->iobus.c34_prev = apr->iobus.c34;
membus0_last = membus0;
apr->membus.c12_prev = apr->membus.c12;
apr->membus.c34_prev = apr->membus.c34;
for(i = 0; i < apr->ncurpulses; i++)
apr->clist[i](apr);
updatebus(&apr->iobus);
membus0_pulse = (membus0_last ^ membus0) & membus0;
updatebus(&apr->membus);
/* This is simplified, we have no IOT RESET,
* IOT INIT SET UP or IOT FINAL SETUP really.
@@ -3126,23 +3135,30 @@ aprmain(void *p)
}
apr->iobus.c34 &= ~(IOBUS_PULSES | IOBUS_IOB_RESET);
/* Pulses to memory */
if(membus0_pulse & (MEMBUS_WR_RS | MEMBUS_RQ_CYC)){
wakemem();
membus0 &= ~MEMBUS_WR_RS;
if(apr->membus.c12_pulse & (MEMBUS_WR_RS | MEMBUS_RQ_CYC)){
wakemem(&apr->membus);
apr->membus.c12 &= ~MEMBUS_WR_RS;
}
/* Pulses from memory */
if(membus0 & MEMBUS_MAI_ADDR_ACK){
membus0 &= ~MEMBUS_MAI_ADDR_ACK;
if(apr->membus.c12 & MEMBUS_MAI_ADDR_ACK){
apr->membus.c12 &= ~MEMBUS_MAI_ADDR_ACK;
apr->extpulse &= ~EXT_NONEXIT_MEM;
nextpulse(apr, mai_addr_ack);
}
if(membus0 & MEMBUS_MAI_RD_RS){
membus0 &= ~MEMBUS_MAI_RD_RS;
if(apr->membus.c12 & MEMBUS_MAI_RD_RS){
apr->membus.c12 &= ~MEMBUS_MAI_RD_RS;
nextpulse(apr, mai_rd_rs);
}
if(apr->mc_rd && apr->membus.c34){
/* 7-6, 7-9 */
apr->mb |= apr->membus.c34;
apr->membus.c34 = 0;
}
/* TODO: do this differently because the
* memory might have been busy. */
if(apr->extpulse & EXT_NONEXIT_MEM){
apr->extpulse &= ~EXT_NONEXIT_MEM;
if(apr->mc_rq && !apr->mc_stop)

View File

@@ -539,6 +539,7 @@ Apr apr;
Tty tty;
Ptr ptr;
Ptp ptp;
Mem *coremems[4];
int
main(int argc, char *argv[])
@@ -660,10 +661,20 @@ main(int argc, char *argv[])
extra_l = e; e += 1;
initapr(&apr);
initmem();
// initmem();
coremems[0] = makecoremem("mem_0");
coremems[1] = makecoremem("mem_1");
coremems[2] = makecoremem("mem_2");
coremems[3] = makecoremem("mem_3");
attachmem(makefastmem(0), 0, &apr.membus, -1);
attachmem(coremems[0], 0, &apr.membus, 0);
attachmem(coremems[1], 0, &apr.membus, 1);
attachmem(coremems[2], 0, &apr.membus, 2);
attachmem(coremems[3], 0, &apr.membus, 3);
inittty(&tty, &apr.iobus);
initptr(&ptr, &apr.iobus);
initptp(&ptp, &apr.iobus);
showmem(&apr.membus);
for(;;){
start = SDL_GetTicks();

301
src/mem.c
View File

@@ -1,16 +1,9 @@
#include "pdp6.h"
#include <ctype.h>
word memory[256*1024];
//hword maxmem = 256*1024;
hword maxmem = 64*1024;
word fmem[16];
word membus0, membus1;
word membus0_last, membus0_pulse;
word *hold;
Membus memterm;
void
readmem(char *file, word *mem, word size)
readmem(const char *file, word *mem, word size)
{
FILE *f;
char buf[100], *s;
@@ -37,62 +30,260 @@ readmem(char *file, word *mem, word size)
fclose(f);
}
void
initmem(void)
{
readmem("../mem", memory, maxmem);
readmem("../fmem", fmem, 16);
}
/* Both functions below are very confusing. I'm sorry.
* The schematics cannot be converted to C in a straightfoward way
* but I tried my best. */
void
dumpmem(void)
/* This is based on the 161C memory */
static int
wakecore(Mem *mem, Membus *bus)
{
hword a;
FILE *f;
bool p2, p3;
CMem *core;
core = mem->module;
if(f = fopen("memdump", "w"), f == nil)
return;
for(a = 0; a < 16; a++)
fprint(f, "%02o: %012llo\n", a, fmem[a]);
for(a = 0; a < maxmem; a++){
if(memory[a]){
fprint(f, "%06o: ", a);
fprint(f, "%012llo\n", memory[a]);
/* If not connected to a bus, find out which to connect to.
* Lower numbers have higher priority but proc 2 and 3 have
* the same priority and requests are alternated between them.
* If no request is made, we should already be connected to a bus */
pthread_mutex_lock(&core->mutex);
if(core->cmc_p_act < 0){
if(mem->bus[0]->c12 & MEMBUS_RQ_CYC)
core->cmc_p_act = 0;
else if(mem->bus[1]->c12 & MEMBUS_RQ_CYC)
core->cmc_p_act = 1;
else{
p2 = !!(mem->bus[2]->c12 & MEMBUS_RQ_CYC);
p3 = !!(mem->bus[3]->c12 & MEMBUS_RQ_CYC);
if(p2 && p3){
if(core->cmc_last_proc == 2)
core->cmc_p_act = 3;
else if(core->cmc_last_proc == 3)
core->cmc_p_act = 2;
}else{
if(p2)
core->cmc_p_act = 2;
else if(p3)
core->cmc_p_act = 3;
else{
pthread_mutex_unlock(&core->mutex);
return 1; /* no request at all? */
}
}
core->cmc_last_proc = core->cmc_p_act;
}
}
fclose(f);
pthread_mutex_unlock(&core->mutex);
/* The executing thread can only service requests from its own processor
* due to synchronization with the processor's pulse cycle. */
if(bus != mem->bus[core->cmc_p_act])
return 1;
if(core->cmc_aw_rq && bus->c12 & MEMBUS_RQ_CYC){
/* accept cycle request */
core->cmc_aw_rq = 0;
//trace(" accepting memory cycle from proc %d\n", core->cmc_p_act);
core->cmb = 0;
core->cma = 0;
core->cma_rd_rq = 0;
core->cma_wr_rq = 0;
core->cmc_pse_sync = 0;
/* strobe address and send acknowledge */
core->cma |= bus->c12>>4 & 037777;
core->cma_rd_rq |= !!(bus->c12 & MEMBUS_RD_RQ);
core->cma_wr_rq |= !!(bus->c12 & MEMBUS_WR_RQ);
//trace(" sending ADDR ACK\n");
bus->c12 |= MEMBUS_MAI_ADDR_ACK;
/* read and send read restart */
if(core->cma_rd_rq){
core->cmb |= core->core[core->cma];
bus->c34 |= core->cmb & FW;
bus->c12 |= MEMBUS_MAI_RD_RS;
//trace(" sending RD RS\n");
if(core->cma_wr_rq)
core->cmb = 0;
else
core->cmc_p_act = -1;
}
core->cmc_pse_sync = 1;
if(!core->cma_wr_rq)
goto end;
}
/* write restart */
if(core->cmc_pse_sync && bus->c12_pulse & MEMBUS_WR_RS){
//trace(" accepting WR RS\n");
core->cmc_p_act = -1;
core->cmb |= bus->c34 & FW;
bus->c34 = 0;
end:
//trace(" writing\n");
core->core[core->cma] = core->cmb;
core->cmc_p_act = -1; /* this seems unnecessary */
core->cmc_aw_rq = 1;
}
//if(core->cmc_p_act < 0)
// trace(" now disconnected from proc\n");
return 0;
}
/* When a cycle is requested we acknowledge the address
* by pulsing the processor through the bus.
* A read is completed immediately and signalled by a second pulse.
* A write is completed on a second call. */
// TODO: implement this properly... according to the manual
void
wakemem(void)
/* This is based on the 162 memory */
static int
wakeff(Mem *mem, Membus *bus)
{
hword a;
if(membus0_pulse & MEMBUS_RQ_CYC){
a = membus0>>4 & 037777;
if(membus0 & MEMBUS_MA21_1) a |= 0040000;
if(membus0 & MEMBUS_MA20_1) a |= 0100000;
if(membus0 & MEMBUS_MA19_1) a |= 0200000;
if(membus0 & MEMBUS_MA18_1) a |= 0400000;
if(a >= maxmem ||
membus0 & MEMBUS_MA_FMC_SEL1 && a >= 16)
return;
FMem *ff;
hword fma;
bool fma_rd_rq, fma_wr_rq;
bool fmc_wr_sel;
ff = mem->module;
membus0 |= MEMBUS_MAI_ADDR_ACK;
hold = membus0 & MEMBUS_MA_FMC_SEL1 ? &fmem[a] : &memory[a];
if(membus0 & MEMBUS_RD_RQ){
membus1 = *hold & FW;
membus0 |= MEMBUS_MAI_RD_RS;
if(!(membus0 & MEMBUS_WR_RQ))
hold = nil;
/* Only respond to one processor */
if(bus != mem->bus[ff->fmc_p_sel])
return 1;
fma_rd_rq = !!(bus->c12 & MEMBUS_RD_RQ);
fma_wr_rq = !!(bus->c12 & MEMBUS_WR_RQ);
if(!ff->fmc_act && bus->c12 & MEMBUS_RQ_CYC){
//trace(" accepting memory cycle from proc %d\n", ff->fmc_p_sel);
ff->fmc_act = 1;
fma = bus->c12>>4 & 017;
//trace(" sending ADDR ACK\n");
bus->c12 |= MEMBUS_MAI_ADDR_ACK;
if(fma_rd_rq){
bus->c34 |= ff->ff[fma] & FW;
bus->c12 |= MEMBUS_MAI_RD_RS;
//trace(" sending RD RS\n");
if(!fma_wr_rq)
goto end;
}
if(fma_wr_rq){
ff->ff[fma] = 0;
ff->fmc_wr = 1;
}
}
if(membus0 & MEMBUS_WR_RS && hold){
*hold = membus1 & FW;
hold = nil;
fmc_wr_sel = ff->fmc_act && !fma_rd_rq;
if(fmc_wr_sel && ff->fmc_wr && bus->c34){
//trace(" writing\n");
ff->ff[fma] |= bus->c34 & FW;
bus->c34 = 0;
}
if(bus->c12_pulse & MEMBUS_WR_RS){
//trace(" accepting WR RS\n");
end:
ff->fmc_act = 0;
ff->fmc_wr = 0;
}
//if(!ff->fmc_act)
// trace(" now available again\n");
return 0;
}
void
wakemem(Membus *bus)
{
int sel;
int nxm;
if(bus->c12 & MEMBUS_MA_FMC_SEL1){
nxm = bus->fmem->wake(bus->fmem, bus);
if(nxm)
goto core;
}else{
core:
sel = 0;
if(bus->c12 & MEMBUS_MA21_1) sel |= 001;
if(bus->c12 & MEMBUS_MA20_1) sel |= 002;
if(bus->c12 & MEMBUS_MA19_1) sel |= 004;
if(bus->c12 & MEMBUS_MA18_1) sel |= 010;
if(bus->cmem[sel])
nxm = bus->cmem[sel]->wake(bus->cmem[sel], bus);
else
nxm = 1;
}
/* TODO: do something when memory didn't respond */
}
/* Allocate a 16k core memory module and
* a memory bus attachment. */
Mem*
makecoremem(const char *file)
{
CMem *core;
Mem *mem;
core = malloc(sizeof(CMem));
memset(core, 0, sizeof(CMem));
core->filename = file;
pthread_mutex_init(&core->mutex, nil);
core->cmc_aw_rq = 1;
core->cmc_p_act = -1;
core->cmc_last_proc = 2;
readmem(core->filename, core->core, 040000);
mem = malloc(sizeof(Mem));
mem->module = core;
mem->bus[0] = &memterm;
mem->bus[1] = &memterm;
mem->bus[2] = &memterm;
mem->bus[3] = &memterm;
mem->wake = wakecore;
return mem;
}
Mem*
makefastmem(int p)
{
FMem *ff;
Mem *mem;
ff = malloc(sizeof(FMem));
memset(ff, 0, sizeof(FMem));
ff->fmc_p_sel = p;
mem = malloc(sizeof(Mem));
mem->module = ff;
mem->bus[0] = &memterm;
mem->bus[1] = &memterm;
mem->bus[2] = &memterm;
mem->bus[3] = &memterm;
mem->wake = wakeff;
return mem;
}
/* Attach mem to bus for processor p.
* If n < 0, it is attached as fast memory,
* else at addresses starting at n<<14. */
void
attachmem(Mem *mem, int p, Membus *bus, int n)
{
if(n < 0)
bus->fmem = mem;
else
bus->cmem[n] = mem;
mem->bus[p] = bus;
}
void
showmem(Membus *bus)
{
int i;
CMem *core;
FMem *ff;
if(bus->fmem){
ff = bus->fmem->module;
printf("fastmem: proc %d\n", ff->fmc_p_sel);
}
for(i = 0; i < 16; i++)
if(bus->cmem[i]){
core = bus->cmem[i]->module;
printf("%06o %06o %s\n", i<<14, (i+1 << 14)-1, core->filename);
}
}

View File

@@ -2,6 +2,9 @@
#include <stdlib.h>
#include <stdint.h>
#include <stdarg.h>
#include <string.h>
#include <assert.h>
#include <pthread.h>
#define nelem(a) (sizeof(a)/sizeof(a[0]))
#define nil NULL
@@ -12,6 +15,7 @@ typedef uint64_t word;
typedef uint32_t hword;
typedef uint32_t u32;
typedef uint16_t u16;
typedef int8_t i8;
typedef uint8_t u8;
typedef unsigned char uchar;
typedef uchar bool;
@@ -106,13 +110,18 @@ enum Opcode {
};
typedef struct Mem Mem;
typedef struct Membus Membus;
typedef struct FMem FMem;
typedef struct CMem CMem;
typedef struct Busdev Busdev;
typedef struct IOBus IOBus;
typedef struct Apr Apr;
/*
* Memory
*/
void initmem(void);
void dumpmem(void);
void wakemem(void);
// 7-2, 7-10
enum {
MEMBUS_MA21 = 0000000000001,
@@ -135,12 +144,61 @@ enum {
MEMBUS_MAI_RD_RS = 0200000000000,
MEMBUS_MAI_ADDR_ACK = 0400000000000,
};
/* 0 is cable 1 & 2 (above bits); 1 is cable 3 & 4 (data) */
extern word membus0, membus1;
/* record the state of membus0 of the last pulse step
* to recognize pulses or edges */
extern word membus0_last, membus0_pulse;
/* A memory module connected to up to 4 Membuses */
struct Mem
{
void *module;
Membus *bus[4];
int (*wake)(Mem *mem, Membus *bus);
};
struct Membus
{
/* c12 are cables 1 and 2, c34 3 and 4.
* c??_prev records the previous state of the bus
* and c??_pulse is used to detect leading edges. */
word c12, c12_prev, c12_pulse;
word c34, c34_prev, c34_pulse;
/* cycle counter to implement NXM timeout */
int numcyc;
Mem *fmem; /* fast memory */
Mem *cmem[16]; /* 16 16k core modules */
};
extern Membus memterm; /* terminator */
void wakemem(Membus *bus);
/* Fast memory 162, 16 words */
struct FMem
{
word ff[16];
i8 fmc_p_sel;
bool fmc_act;
bool fmc_wr;
};
Mem *makefastmem(int p);
/* Core memory 161C, 16k words */
struct CMem
{
const char *filename;
pthread_mutex_t mutex;
word core[040000];
word cmb;
hword cma;
bool cma_rd_rq, cma_wr_rq;
bool cmc_aw_rq;
i8 cmc_p_act;
u8 cmc_last_proc;
bool cmc_pse_sync;
};
Mem *makecoremem(const char *file);
void attachmem(Mem *mem, int p, Membus *bus, int n);
void readmem(const char *file, word *mem, word size);
void showmem(Membus *bus);
/*
* IO bus
@@ -191,7 +249,6 @@ enum {
#define IOB_DATAI (bus->c34 & IOBUS_IOB_DATAI)
/* A peripheral device connected to an IO bus */
typedef struct Busdev Busdev;
struct Busdev
{
void *dev;
@@ -199,7 +256,6 @@ struct Busdev
u8 req;
};
typedef struct IOBus IOBus;
struct IOBus
{
/* c12 are cables 1 and 2, c34 3 and 4.
@@ -222,7 +278,6 @@ void recalc_req(IOBus *bus);
/* Arithmetic Processor 166 */
#define CPA (0000>>2)
#define PI (0004>>2)
typedef struct Apr Apr;
typedef void Pulse(Apr *apr);
#define pulse(p) static void p(Apr *apr)
@@ -230,6 +285,7 @@ typedef void Pulse(Apr *apr);
struct Apr
{
IOBus iobus;
Membus membus;
hword ir;
word mi;
@@ -336,6 +392,7 @@ struct Apr
int ncurpulses, nnextpulses;
};
void initapr(Apr *apr);
void curpulse(Apr *apr, Pulse *p);
void nextpulse(Apr *apr, Pulse *p);
void *aprmain(void *p);