8 typedef struct SimTimeout {
9 struct { struct SimTimeout *back, *next; } l;
13 typedef void SimEventFn(void);
18 static SimEventFn se_timestamp, se_timerevent, se_command;
19 static SimEventFn se_serial, se_serial_detcompr, se_samedet, se_eof;
21 static SimTimeout *simtimeouts;
24 #define DETSAVES (1<<DETSAVESLN2) /* encoded in letters so must be <=26 ! */
26 static FILE *simoutput;
27 static FILE *siminput;
28 static char *sevent_buf;
29 static size_t sevent_buflen;
30 static int sevent_lno;
31 static Byte sevent_lastdet[DETSAVES][2];
33 static SimEventFn *sevent_type;
34 static char *sevent_data;
35 static struct timeval sevent_abst;
37 #define PICMSG_DETECT_01 (PICMSG_DETECT0^PICMSG_DETECT1)
39 /*---------- writing simulation log ----------*/
41 static Byte simlog_lastdet[DETSAVES][2];
42 static uint32_t simlog_detcompr_lcongx;
44 void simlog_ccb(char *m, size_t l, void *u) {
46 if (!simoutput || simoutput==stdout) return;
48 r= fwrite(m,1,l,simoutput);
50 assert(ferror(simoutput));
51 diee("copy output to simulation log");
54 void simlogv(const char *fmt, va_list al) {
55 if (simoutput==stdout) ouvprintf(fmt,al);
56 else if (simoutput) vfprintf(simoutput,fmt,al);
58 void simlog(const char *fmt, ...) {
64 void simlog_flush(void) {
65 if (simoutput==stdout) obc_tryflush(&cmdi.out);
67 if (ferror(simoutput) || fflush(simoutput))
68 diee("write simulation log");
71 void simlog_serial(const Byte *data, int length) {
77 db0= data[0] & ~PICMSG_DETECT_01;
79 is_det= PICMSG_DETECT0_P(db0) && length==2 && !((db1=data[1]) & 0x80);
82 for (i=0; i<DETSAVES; i++)
83 if (simlog_lastdet[i][0]==db0 && simlog_lastdet[i][1]==db1) {
84 simlog("%c\n", ((data[0] & PICMSG_DETECT_01) ? 'A' : 'a') + i);
88 /* not found, choose a slot to replace */
89 simlog_detcompr_lcongx += 5; /* WP Linear_congruential_generator */
90 simlog_detcompr_lcongx *= 69069; /* values are those also used by GCC */
91 i= (simlog_detcompr_lcongx >> (30 - DETSAVESLN2)) &
92 ((1UL << DETSAVESLN2)-1);
93 simlog_lastdet[i][0]= db0;
94 simlog_lastdet[i][1]= db1;
95 simlog("picioh in detcompr%c", 'A' + i);
97 simlog("picioh in suppressed");
99 while (length--) simlog(" %02x",*data++);
103 void simlog_open(const char *fn) {
106 if (!fn) fn= "+realtime.log";
107 if (!strcmp(fn,"-")) {
108 simoutput= stdout; /* we don't really use this - see vsimlog */
111 if (r && errno!=ENOENT && errno!=EPERM)
112 diee("unlink old simulation log %s",fn);
113 simoutput= fopen(fn,"w");
114 if (!simoutput) diee("open simulation log %s",fn);
118 /*---------- simulation input stream parser ----------*/
120 static void simbad(const char *how) __attribute__((noreturn));
121 static void simbad(const char *how) {
122 die("simulation failed (line %d, in `%s'): %s", sevent_lno, sevent_buf, how);
125 static void sevent(void) {
135 gr= getline(&sevent_buf,&sevent_buflen,siminput);
136 if (feof(siminput)) { sevent_type= se_eof; return; }
137 if (ferror(siminput)) diee("read simulation input failed");
139 assert(sevent_buf[gr-1]=='\n');
142 if (gr==2 && CTYPE(isalpha,sevent_buf[0])) {
143 sevent_type= se_samedet;
144 sevent_data= &sevent_buf[0];
148 #define IF_ET(pfx, et) \
149 if (!strncmp(pfx, sevent_buf, sizeof(pfx)-1) \
150 && (sevent_type=(et), p=sevent_buf+sizeof(pfx)-1))
152 IF_ET("command-in ", se_command) {
156 IF_ET("picioh in detcompr", se_serial_detcompr) {
160 IF_ET("picioh in ", se_serial) {
162 if (!p) simbad("missing space after `in'");
166 IF_ET("timer-event ", se_timerevent) {
170 IF_ET("timestamp ", se_timestamp) {
173 r= sscanf(p,"%ld.%ld%n", &sevent_abst.tv_sec, &sevent_abst.tv_usec, &n);
174 if (r<2 || !(n==-1 || !p[n])) simbad("unparseable timestamp");
180 /*---------- hooks for eventhelp ----------*/
182 void sim_toev_start(TimeoutEvent *toev) {
183 SimTimeout *s= mmalloc(sizeof(*s));
185 DLIST1_PREPEND(simtimeouts,s,l);
188 static void sim_toev_remove(SimTimeout *s) {
189 DLIST1_REMOVE(simtimeouts,s,l);
193 void sim_toev_stop(TimeoutEvent *toev) {
195 for (s=simtimeouts; !(s->toev==toev); s=s->l.next);
199 void sim_mgettimeofday(struct timeval *tv) {
202 if (sevent_type==se_timestamp)
205 fprintf(stderr,"simulation warning -"
206 " mgettimeofday desynched at line %d\n", sevent_lno);
209 /*---------- simulation events ----------*/
211 static void se_timestamp(void) { }
213 static void se_timerevent(void) {
218 delim= strchr(sevent_data,'.');
219 if (!delim) simbad("missing `.' in timer event name");
222 for (s=simtimeouts; s; s=simtimeouts->l.next) {
224 if (!strcmp(toev->pclass, sevent_data) &&
225 !strcmp(toev->pinst, delim+1))
228 *delim='.'; simbad("timeout event not found");
232 toev_callback(0, sevent_abst, toev);
235 static int unhex(const char *str, Byte *buf, int buf_len) {
241 for (p=str, buf_used=0;
245 if (!(c[0]= *p++)) break;
246 if (!(c[1]= *p++)) simbad("odd number of hex digits");
248 if (buf_used==buf_len) simbad("serial_buf overrun");
250 buf[buf_used++]= strtoul(c,&ep,16);
251 if (*ep) simbad("bad hex");
256 static void se_serial(void) {
259 buf_used= serial_buf.l;
260 buf_used += unhex(sevent_data, serial_buf.d + buf_used,
261 sizeof(serial_buf.d) - buf_used);
262 serial_indata_process(buf_used);
265 static void serial_detevent(Byte m[2], Byte or_m0) {
267 buf_used= serial_buf.l+2;
268 if (buf_used > sizeof(serial_buf.d)) simbad("serial_buf det overrun");
269 serial_buf.d[serial_buf.l]= m[0] | or_m0;
270 serial_buf.d[serial_buf.l+1]= m[1];
271 serial_indata_process(buf_used);
274 static void se_serial_detcompr(void) {
277 i= *sevent_data++ - 'A';
278 if (i<0 || i>=DETSAVES) simbad("detcompr bad slot specifier");
279 l= unhex(sevent_data, sevent_lastdet[i], 2);
280 if (l!=2) simbad("detcompr wrong message length");
281 serial_detevent(sevent_lastdet[i],0);
282 sevent_lastdet[i][0] &= ~PICMSG_DETECT_01;
284 static void se_samedet(void) {
286 i= *sevent_data - 'a';
287 d= *sevent_data < 'a'; /* A is before a */
289 if (i<0 || i>=DETSAVES || !sevent_lastdet[i][0]) simbad("detsame bad slot");
290 serial_detevent(sevent_lastdet[i], d ? PICMSG_DETECT_01 : 0);
293 static void se_command(void) {
295 ps.remain= sevent_data;
298 cmdi.doline(&ps,&cmdi);
301 static void se_eof(void) {
305 /*---------- core ----------*/
307 void sim_initialise(const char *logduplicate) {
308 obc_init_core(&cmdi.out);
309 serial_fd= open("/dev/null",O_WRONLY);
310 if (serial_fd<0) diee("open /dev/null for dummy serial");
311 siminput= fopen(simulate,"r");
312 if (!siminput) diee("open simulation input %s",simulate);
314 simlog_open(logduplicate);
324 obc_tryflush(&cmdi.out);