1
0
mirror of https://github.com/aap/pdp6.git synced 2026-02-27 01:10:14 +00:00

emu: implemented a better clock; implemented repeat functionality, no knobs on panel yet

This commit is contained in:
aap
2019-03-09 18:51:44 +01:00
parent cf728d2174
commit 2cf5501709
7 changed files with 220 additions and 38 deletions

View File

@@ -37,7 +37,8 @@ Otherwise you need SDL and pthread.
The cpu (apr), console tty, paper tape and punch,
the data control and DECtape are implemented.
The only things missing from the cpu is the repeat key mechanism.
The panel is missing the repeat delay knobs,
but the functionality is implemented.
## Verilog Simulation
@@ -125,7 +126,7 @@ misc nothing important
## To do
- repeat and maint. switches
- repeat and maint. switches on panel
- improve timing
- implement 340 display
- do more tests

View File

@@ -1,4 +1,4 @@
SRC=emu.c util.c threading.c cmd.c apr.c mem.c tty.c pt.c dc.c dt.c netmem.c ../tools/pdp6common.c
SRC=emu.c apr.c mem.c tty.c pt.c dc.c dt.c netmem.c cmd.c util.c threading.c rtc.c ../tools/pdp6common.c
H=pdp6.h ../tools/pdp6common.h threading.h
# clang
#CFLAGS= -Wno-shift-op-parentheses -Wno-logical-op-parentheses \

View File

@@ -240,6 +240,9 @@ makeapr(int argc, char *argv[])
t = (Task){ nil, aprcycle, apr, 1, 0 };
addtask(t);
apr->clkchan = chancreate(sizeof(int), 1);
apr->rptchan = chancreate(sizeof(int), 1);
return &apr->dev;
}
@@ -3290,9 +3293,25 @@ defpulse(key_go)
defpulse_(kt4)
{
/* low end of ranges. unsure, but not totally off */
static word ranges[6] = {
3400,
41718, // *12.27
602407, // *14.44
6024079, // *10
60240792, // *10
269878748, // *4.48
};
static RtcMsg rpt = { 1, 0, nil, 0 };
if(apr->run && (apr->key_ex_st || apr->key_dep_st))
pulse(apr, &key_go, 0); // 5-2
// TODO check repeat switch
rpt.c = apr->rptchan;
rpt.interval = ranges[apr->speed_range];
/* TODO: is this just a multiplier */
rpt.interval *= 1 + apr->speed_set/100.0f*14.0f;
chansend(rtcchan, &rpt);
}
defpulse(kt3)
@@ -3381,11 +3400,11 @@ updatebus(void *bus)
b->c34_pulse = (b->c34_prev ^ b->c34) & b->c34;
}
#define TIMESTEP (1000.0/60.0)
void
aprstart(Apr *apr)
{
static RtcMsg lineclk = { 1, 1, nil, 1000000000/60 };
int i;
printf("[aprstart]\n");
@@ -3404,8 +3423,10 @@ aprstart(Apr *apr)
apr->iobus.c34 = 0;
pulse(apr, &mr_pwr_clr, 100); // random value
apr->lasttick = getms();
apr->powered = 1;
lineclk.c = apr->clkchan;
chansend(rtcchan, &lineclk);
}
static void
@@ -3423,21 +3444,17 @@ aprcycle(void *p)
}else if(!apr->powered)
aprstart(apr);
/*
if(apr->pulsestepping){
int c;
while(c = getchar(), c != EOF && c != '\n')
if(c == 'x')
apr->pulsestepping = 0;
}
*/
apr->tick = getms();
if(apr->tick-apr->lasttick >= TIMESTEP){
apr->lasttick = apr->lasttick+TIMESTEP;
int foo;
if(channbrecv(apr->clkchan, &foo) == 1){
// printf("tick\n");
apr->cpa_clock_flag = 1;
recalc_cpa_req(apr);
}
if(channbrecv(apr->rptchan, &foo) == 1){
// printf("rpt\n");
if(KEY_MANUAL)
pulse(apr, &kt0a, 1);
}
apr->iobus.c12_prev = apr->iobus.c12;
apr->iobus.c34_prev = apr->iobus.c34;

View File

@@ -35,12 +35,6 @@ struct Element
int active;
};
u32
getms(void)
{
return SDL_GetTicks();
}
SDL_Surface*
mustloadimg(const char *path)
{
@@ -544,12 +538,12 @@ threadmain(int argc, char *argv[])
default:
usage();
}ARGEND;
if(debugfp = fopen(outfile, "w"), debugfp == nil){
fprintf(stderr, "Can't open %s\n", outfile);
exit(1);
}
if(SDL_Init(SDL_INIT_VIDEO) < 0)
err("%s", SDL_GetError());
@@ -638,6 +632,8 @@ threadmain(int argc, char *argv[])
extra_l = e; e += 1;
rtcchan = chancreate(sizeof(RtcMsg), 20);
dofile("init.ini");
apr = (Apr*)getdevice("apr");
tty = (Tty*)getdevice("tty");
@@ -650,6 +646,7 @@ threadmain(int argc, char *argv[])
addtask(t);
threadcreate(simthread, nil);
threadcreate(cmdthread, cmdchans);
threadcreate(rtcthread, nil);
for(;;){
while(SDL_PollEvent(&ev))

View File

@@ -9,13 +9,6 @@
// TODO: get rid of this
void updatepanel(Apr *apr) {}
u32
getms(void)
{
// TODO
return 0;
}
#define KEYPULSE(k) (apr->k && !oldapr.k)
void
@@ -179,12 +172,12 @@ threadmain(int argc, char *argv[])
default:
usage();
}ARGEND;
if(debugfp = fopen(outfile, "w"), debugfp == nil){
fprintf(stderr, "Can't open %s\n", outfile);
exit(1);
}
dofile("init.ini");
apr = (Apr*)getdevice("apr");
ptr = (Ptr*)getdevice("ptr");

View File

@@ -25,7 +25,6 @@ extern int dotrace;
void trace(char *fmt, ...);
void debug(char *fmt, ...);
void err(char *fmt, ...);
u32 getms(void);
void strtolower(char *s);
int hasinput(int fd);
@@ -39,6 +38,7 @@ void cli(FILE *f, Channel **c);
void readcmdchan(void *p);
void *cmdthread(void *);
void *simthread(void *p);
void *rtcthread(void *p);
void dofile(const char *path);
enum {
@@ -100,6 +100,16 @@ struct Task
extern Task *tasks;
void addtask(Task t);
typedef struct RtcMsg RtcMsg;
struct RtcMsg
{
int msg; // 1 - start; 0 - stop
int repeat;
Channel *c;
word interval;
};
extern Channel *rtcchan;
typedef struct Device Device;
struct Device
{
@@ -352,6 +362,9 @@ struct Apr
bool key_ex, key_ex_nxt;
bool key_rd_off, key_rd_on;
bool key_pt_rd, key_pt_wr;
/* knobs */
int speed_range; // 0-5
int speed_set; // 1-100
/* PI */
u8 pio, pir, pih, pi_req;
@@ -426,11 +439,9 @@ struct Apr
bool fc_e_pse;
bool pc_set;
/* needed for the emulation */
double lasttick, tick;
Channel *clkchan, *rptchan;
int extpulse;
bool ia_inh; // this is asserted for some time
int pulsestepping;
/* This could be abstracted away */
TPulse pulses[MAXPULSE];

163
emu/rtc.c Normal file
View File

@@ -0,0 +1,163 @@
#include "pdp6.h"
#include <time.h>
struct timespec
timesub(struct timespec t1, struct timespec t2)
{
struct timespec d;
d.tv_sec = t2.tv_sec - t1.tv_sec;
d.tv_nsec = t2.tv_nsec - t1.tv_nsec;
if(d.tv_nsec < 0){
d.tv_nsec += 1000000000;
d.tv_sec -= 1;
}
return d;
}
struct timespec
timeadd(struct timespec t1, struct timespec t2)
{
struct timespec s;
s.tv_sec = t1.tv_sec + t2.tv_sec;
s.tv_nsec = t1.tv_nsec + t2.tv_nsec;
if(s.tv_nsec >= 1000000000){
s.tv_nsec -= 1000000000;
s.tv_sec += 1;
}
return s;
}
/* is t2 after t1 */
int
timeafter(struct timespec t1, struct timespec t2)
{
if(t1.tv_sec == t2.tv_sec)
return t1.tv_nsec < t2.tv_nsec;
return t1.tv_sec < t2.tv_sec;
}
/* is t2 before t1 */
int
timebefore(struct timespec t1, struct timespec t2)
{
if(t1.tv_sec == t2.tv_sec)
return t1.tv_nsec > t2.tv_nsec;
return t1.tv_sec > t2.tv_sec;
}
typedef struct Clockchan Clockchan;
struct Clockchan
{
int active;
Channel *c;
struct timespec start;
struct timespec timeout;
struct timespec interval;
int repeat;
Clockchan *next;
};
static Clockchan *channels;
Channel *rtcchan;
static Clockchan*
getchan(Channel *c)
{
Clockchan *cc;
for(cc = channels; cc; cc = cc->next)
if(cc->c == c)
return cc;
return nil;
}
static void
rtcstart(Channel *c, word interval, int repeat)
{
Clockchan *cc;
cc = getchan(c);
if(cc == nil){
cc = malloc(sizeof(Clockchan));
memset(cc, 0, sizeof(Clockchan));
cc->next = channels;
channels = cc;
}
cc->active = 1;
cc->c = c;
clock_gettime(CLOCK_REALTIME, &cc->start);
cc->interval.tv_sec = interval / 1000000000;
cc->interval.tv_nsec = interval % 1000000000;
cc->timeout = timeadd(cc->start, cc->interval);
cc->repeat = repeat;
}
static void
rtcstop(Channel *c)
{
Clockchan *cc;
cc = getchan(c);
if(cc)
cc->active = 0;
}
void*
rtcthread(void *p)
{
struct timespec now;
Clockchan *cc;
RtcMsg msg;
int loss;
loss = 0;
for(;;){
clock_gettime(CLOCK_REALTIME, &now);
/* Check all channels for a timeout */
for(cc = channels; cc; cc = cc->next){
if(!cc->active || timebefore(cc->timeout, now))
continue;
/* I *hope* this is ok */
if(channbsend(cc->c, &loss) == 0)
;//printf("missed clock\n");
if(cc->repeat)
cc->timeout = timeadd(cc->timeout, cc->interval);
else
cc->active = 0;
}
if(channbrecv(rtcchan, &msg) == 1){
if(msg.msg == 1)
rtcstart(msg.c, msg.interval, msg.repeat);
else
rtcstop(msg.c);
}
}
}
/*
int
main()
{
long max = 0;
int n = 0x7FFFFFFF;
struct timespec interval = { 0, 500000000 };
struct timespec timeout, now;
clock_gettime(CLOCK_REALTIME, &timeout);
timeout = timeadd(timeout, interval);
while(n--){
clock_gettime(CLOCK_REALTIME, &now);
if(timeafter(timeout, now)){
timeout = timeadd(timeout, interval);
printf("tick\n");
}
}
return 0;
}
*/