From 2cf55017090093a3c3c5a2a27503bc12ae1dcfa7 Mon Sep 17 00:00:00 2001 From: aap Date: Sat, 9 Mar 2019 18:51:44 +0100 Subject: [PATCH] emu: implemented a better clock; implemented repeat functionality, no knobs on panel yet --- README.md | 5 +- emu/Makefile | 2 +- emu/apr.c | 49 +++++++++----- emu/main_panel.c | 11 ++-- emu/main_serial.c | 9 +-- emu/pdp6.h | 19 ++++-- emu/rtc.c | 163 ++++++++++++++++++++++++++++++++++++++++++++++ 7 files changed, 220 insertions(+), 38 deletions(-) create mode 100644 emu/rtc.c diff --git a/README.md b/README.md index 43abbe5..a581c05 100644 --- a/README.md +++ b/README.md @@ -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 diff --git a/emu/Makefile b/emu/Makefile index 13c0c11..eb0b74d 100644 --- a/emu/Makefile +++ b/emu/Makefile @@ -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 \ diff --git a/emu/apr.c b/emu/apr.c index 7d1a6c1..f1e5576 100644 --- a/emu/apr.c +++ b/emu/apr.c @@ -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; diff --git a/emu/main_panel.c b/emu/main_panel.c index 0407e8f..3b7183d 100644 --- a/emu/main_panel.c +++ b/emu/main_panel.c @@ -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)) diff --git a/emu/main_serial.c b/emu/main_serial.c index f63262a..b7bd684 100644 --- a/emu/main_serial.c +++ b/emu/main_serial.c @@ -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"); diff --git a/emu/pdp6.h b/emu/pdp6.h index fc23476..92ef5f6 100644 --- a/emu/pdp6.h +++ b/emu/pdp6.h @@ -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]; diff --git a/emu/rtc.c b/emu/rtc.c new file mode 100644 index 0000000..d8ac682 --- /dev/null +++ b/emu/rtc.c @@ -0,0 +1,163 @@ +#include "pdp6.h" +#include + +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; +} +*/