1
0
mirror of https://github.com/aap/pdp6.git synced 2026-01-11 23:53:31 +00:00
aap.pdp6/emu/rtc.c
2021-04-15 20:35:15 +02:00

170 lines
2.9 KiB
C

#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;
threadname("rtc");
struct timespec slp = { 0, 1*1000*1000 }; // 1ms
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);
}
// make this thread sleep a bit
nanosleep(&slp, nil);
}
}
/*
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;
}
*/