Mercurial > hg > Members > kono > os9 > sbc09
comparison io.c @ 0:9a224bd9b45f
os9 emulation
author | Shinji KONO <kono@ie.u-ryukyu.ac.jp> |
---|---|
date | Mon, 02 Jul 2018 02:12:31 +0900 |
parents | |
children | 3c736a81b886 |
comparison
equal
deleted
inserted
replaced
-1:000000000000 | 0:9a224bd9b45f |
---|---|
1 /* 6809 Simulator V09. | |
2 | |
3 created 1993,1994 by L.C. Benschop. | |
4 copyleft (c) 1994-2014 by the sbc09 team, see AUTHORS for more details. | |
5 license: GNU General Public License version 2, see LICENSE for more details. | |
6 | |
7 This program simulates a 6809 processor. | |
8 | |
9 System dependencies: short must be 16 bits. | |
10 char must be 8 bits. | |
11 long must be more than 16 bits. | |
12 arrays up to 65536 bytes must be supported. | |
13 machine must be twos complement. | |
14 Most Unix machines will work. For MSODS you need long pointers | |
15 and you may have to malloc() the mem array of 65536 bytes. | |
16 | |
17 Define BIG_ENDIAN if you have a big-endian machine (680x0 etc) | |
18 | |
19 Special instructions: | |
20 SWI2 writes char to stdout from register B. | |
21 SWI3 reads char from stdout to register B, sets carry at EOF. | |
22 (or when no key available when using term control). | |
23 SWI retains its normal function. | |
24 CWAI and SYNC stop simulator. | |
25 | |
26 */ | |
27 | |
28 #include<stdio.h> | |
29 #include<stdlib.h> | |
30 #include<ctype.h> | |
31 #include<signal.h> | |
32 #include<sys/time.h> | |
33 | |
34 #include <unistd.h> | |
35 #include <fcntl.h> | |
36 #include <string.h> | |
37 | |
38 #ifdef USE_TERMIOS | |
39 #include <termios.h> | |
40 #endif | |
41 | |
42 #define engine extern | |
43 #include "v09.h" | |
44 | |
45 int tflags; | |
46 int timer = 1; | |
47 struct termios termsetting; | |
48 | |
49 int xmstat; /* 0= no XMODEM transfer, 1=send, 2=receiver */ | |
50 unsigned char xmbuf[132]; | |
51 int xidx; | |
52 int acknak; | |
53 int rcvdnak; | |
54 int blocknum; | |
55 | |
56 FILE *logfile; | |
57 FILE *infile; | |
58 FILE *xfile; | |
59 | |
60 extern void hexadump( unsigned char *b, int l, int loc, int w); | |
61 extern void disasm(int,int); | |
62 | |
63 | |
64 int char_input(void) { | |
65 int c, w, sum; | |
66 if (!xmstat) { | |
67 if (infile) { | |
68 c = getc(infile); | |
69 if (c == EOF) { | |
70 fclose(infile); | |
71 infile = 0; | |
72 return char_input(); | |
73 } | |
74 if (c == '\n') | |
75 c = '\r'; | |
76 return c; | |
77 } else | |
78 return getchar(); | |
79 } else if (xmstat == 1) { | |
80 if (xidx) { | |
81 c = xmbuf[xidx++]; | |
82 if (xidx == 132) { | |
83 xidx = 0; | |
84 rcvdnak = EOF; | |
85 acknak = 6; | |
86 } | |
87 } else { | |
88 if ((acknak == 21 && rcvdnak == 21) || (acknak == 6 && rcvdnak == 6)) { | |
89 rcvdnak = 0; | |
90 memset(xmbuf, 0, 132); | |
91 w = fread(xmbuf + 3, 1, 128, xfile); | |
92 if (w) { | |
93 printf("Block %3d transmitted, ", blocknum); | |
94 xmbuf[0] = 1; | |
95 xmbuf[1] = blocknum; | |
96 xmbuf[2] = 255 - blocknum; | |
97 blocknum = (blocknum + 1) & 255; | |
98 sum = 0; | |
99 for (w = 3; w < 131; w++) | |
100 sum = (sum + xmbuf[w]) & 255; | |
101 xmbuf[131] = sum; | |
102 acknak = 6; | |
103 c = 1; | |
104 xidx = 1; | |
105 } else { | |
106 printf("EOT transmitted, "); | |
107 acknak = 4; | |
108 c = 4; | |
109 } | |
110 } else if (rcvdnak == 21) { | |
111 rcvdnak = 0; | |
112 printf("Block %3d retransmitted, ", xmbuf[1]); | |
113 c = xmbuf[xidx++]; /*retransmit the same block */ | |
114 } else | |
115 c = EOF; | |
116 } | |
117 return c; | |
118 } else { | |
119 if (acknak == 4) { | |
120 c = 6; | |
121 acknak = 0; | |
122 fclose(xfile); | |
123 xfile = 0; | |
124 xmstat = 0; | |
125 } else if (acknak) { | |
126 c = acknak; | |
127 acknak = 0; | |
128 } else | |
129 c = EOF; | |
130 if (c == 6) | |
131 printf("ACK\n"); | |
132 if (c == 21) | |
133 printf("NAK\n"); | |
134 return c; | |
135 } | |
136 } | |
137 | |
138 int do_input( a) { | |
139 static int c, f = EOF; | |
140 if (a == 0) { | |
141 if (f == EOF) | |
142 f = char_input(); | |
143 if (f != EOF) | |
144 c = f; | |
145 return 2 + (f != EOF); | |
146 } else if (a == 1) { /*data port*/ | |
147 if (f == EOF) | |
148 f = char_input(); | |
149 if (f != EOF) { | |
150 c = f; | |
151 f = EOF; | |
152 } | |
153 return c; | |
154 } | |
155 return 0; | |
156 } | |
157 | |
158 void do_output(int a, int c) { | |
159 int i, sum; | |
160 if (a == 1) { /* ACIA data port,ignore address */ | |
161 if (!xmstat) { | |
162 if (logfile && c != 127 && (c >= ' ' || c == '\n')) | |
163 putc(c, logfile); | |
164 putchar(c); | |
165 fflush(stdout); | |
166 } else if (xmstat == 1) { | |
167 rcvdnak = c; | |
168 if (c == 6 && acknak == 4) { | |
169 fclose(xfile); | |
170 xfile = 0; | |
171 xmstat = 0; | |
172 } | |
173 if (c == 6) | |
174 printf("ACK\n"); | |
175 if (c == 21) | |
176 printf("NAK\n"); | |
177 if (c == 24) { | |
178 printf("CAN\n"); | |
179 fclose(xfile); | |
180 xmstat = 0; | |
181 xfile = 0; | |
182 } | |
183 } else { | |
184 if (xidx == 0 && c == 4) { | |
185 acknak = 4; | |
186 printf("EOT received, "); | |
187 } | |
188 xmbuf[xidx++] = c; | |
189 if (xidx == 132) { | |
190 sum = 0; | |
191 for (i = 3; i < 131; i++) | |
192 sum = (sum + xmbuf[i]) & 255; | |
193 if (xmbuf[0] == 1 && xmbuf[1] == 255 - xmbuf[2] | |
194 && sum == xmbuf[131]) | |
195 acknak = 6; | |
196 else | |
197 acknak = 21; | |
198 printf("Block %3d received, ", xmbuf[1]); | |
199 if (blocknum == xmbuf[1]) { | |
200 blocknum = (blocknum + 1) & 255; | |
201 fwrite(xmbuf + 3, 1, 128, xfile); | |
202 } | |
203 xidx = 0; | |
204 } | |
205 } | |
206 } | |
207 } | |
208 | |
209 void restore_term(void) { | |
210 tcsetattr(0, TCSAFLUSH, &termsetting); | |
211 fcntl(0, F_SETFL, tflags); | |
212 signal(SIGALRM, SIG_IGN); | |
213 } | |
214 | |
215 void do_exit(void) { | |
216 restore_term(); | |
217 exit(0); | |
218 } | |
219 | |
220 typedef struct bp { | |
221 int address; | |
222 int count; | |
223 struct bp *next; | |
224 } BP, *BPTR; | |
225 | |
226 BPTR breakpoint = 0; | |
227 int bpskip = 0; | |
228 int trskip = 0; | |
229 int stkskip = 0; | |
230 | |
231 int getarg(char *buf, char** next) { | |
232 return strtol(buf,(char**)next,0); | |
233 } | |
234 | |
235 void printhelp(void) | |
236 { | |
237 printf( | |
238 " s [count] one step trace\n" | |
239 " n step over\n" | |
240 " f finish this call (until stack pop)\n" | |
241 " b [adr] set break point\n" | |
242 " l break point list\n" | |
243 " d [n] delte break point list\n" | |
244 " c [count] continue;\n" | |
245 " x [adr] dump\n" | |
246 " xi [adr] disassemble\n" | |
247 " L file start log to file\n" | |
248 " S file set input file\n" | |
249 " X exit\n" | |
250 " q exit\n" | |
251 " U file upload from srecord file \n" | |
252 " D file download to srecord file \n" | |
253 " R do reset\n" | |
254 " h,? print this\n" | |
255 ); | |
256 } | |
257 | |
258 void do_escape(void) { | |
259 char s[80]; | |
260 int adr,skip; | |
261 if (bpskip) { // skip unbreak instruction | |
262 bpskip--; | |
263 for(BPTR b = breakpoint; b ; b=b->next) { | |
264 if (pcreg==b->address) { | |
265 if (b->count) b->count--; | |
266 if (b->count==0) { | |
267 goto restart0; | |
268 } | |
269 } | |
270 } | |
271 return; | |
272 } | |
273 if (stkskip) { // skip until return | |
274 if (sreg < stkskip ) return; | |
275 } | |
276 restart0: | |
277 stkskip = 0; | |
278 restore_term(); | |
279 do_trace(stdout); | |
280 if (trskip>1) { // show trace and step | |
281 trskip--; | |
282 set_term(escchar); | |
283 return; | |
284 } | |
285 restart: | |
286 printf("v09>"); | |
287 fgets(s, 80, stdin); | |
288 if (s[0]) | |
289 s[strlen(s) - 1] = 0; | |
290 switch (s[0]) { | |
291 case 's': // one step trace | |
292 trskip = 1; | |
293 if (s[1]) { | |
294 trskip = getarg(s+1,0); | |
295 } | |
296 bpskip = 0; | |
297 attention = escape = 1; | |
298 break; | |
299 case 'n': // step over | |
300 stkskip = sreg; | |
301 attention = escape = 1; | |
302 break; | |
303 case 'f': // finish this call (until stack pop) | |
304 stkskip = sreg + 2; | |
305 attention = escape = 1; | |
306 break; | |
307 case 'b': // set break point | |
308 { | |
309 BPTR bp = calloc(1,sizeof(BP)); | |
310 bp->next = breakpoint; | |
311 breakpoint = bp; | |
312 bp->count = 1; | |
313 if (s[1]) { | |
314 char *next; | |
315 bp->address = getarg(s+1,&next); | |
316 if (next[0]) { | |
317 bp->count = getarg(next,&next); | |
318 } | |
319 } else { | |
320 bp->address = pcreg; | |
321 } | |
322 } | |
323 bpskip = -1; | |
324 goto restart; | |
325 case 'l': // break point list | |
326 for(BPTR bp = breakpoint; bp ; bp = bp->next) { | |
327 printf("%x %i\n", bp->address, bp->count); | |
328 } | |
329 goto restart; | |
330 case 'd': // delte break point list | |
331 if (s[1]) { | |
332 int trskip = getarg(s+1,0); | |
333 BPTR *prev = &breakpoint; | |
334 for(BPTR bp = breakpoint; bp ; bp = bp->next) { | |
335 if (trskip-- == 0) { | |
336 if (bp) { | |
337 *prev = bp->next; | |
338 } | |
339 break; | |
340 } | |
341 prev = &bp->next; | |
342 } | |
343 } | |
344 goto restart; | |
345 case 'c': // continue; | |
346 bpskip = -1; | |
347 attention = escape = 1; | |
348 if (s[1]) { | |
349 bpskip = getarg(s+1,0); | |
350 } | |
351 break; | |
352 case 'x': // dump | |
353 skip = 1; | |
354 if (s[1]=='i') skip=2; | |
355 if (s[skip]) { | |
356 char *next; | |
357 int adr = getarg(s+skip,&next); | |
358 int len = 32; | |
359 if (next[0]) { | |
360 len = getarg(next,&next); | |
361 } | |
362 if (skip==2) { | |
363 disasm(adr,adr+len); | |
364 } else { | |
365 for(int i=0; len > 0 ; i+=16, len-=16) { | |
366 hexadump(mem+adr+i,len>16?16:len,adr+i,16); | |
367 } | |
368 } | |
369 } else | |
370 disasm(pcreg,pcreg+32); | |
371 goto restart; | |
372 case 'L': | |
373 if (logfile) | |
374 fclose(logfile); | |
375 logfile = 0; | |
376 if (s[1]) { | |
377 logfile = fopen(s + 1, "w"); | |
378 } | |
379 break; | |
380 case 'S': | |
381 if (infile) | |
382 fclose(infile); | |
383 infile = 0; | |
384 if (s[1]) { | |
385 infile = fopen(s + 1, "r"); | |
386 } | |
387 break; | |
388 case 'h': | |
389 case '?': | |
390 printhelp(); | |
391 goto restart; | |
392 case 'X': | |
393 case 'q': | |
394 if (!xmstat) | |
395 do_exit(); | |
396 else { | |
397 xmstat = 0; | |
398 fclose(xfile); | |
399 xfile = 0; | |
400 } | |
401 break; | |
402 case 'U': | |
403 if (xfile) | |
404 fclose(xfile); | |
405 xfile = 0; | |
406 if (s[1]) { | |
407 xfile = fopen(s + 1, "rb"); | |
408 } | |
409 if (xfile) | |
410 xmstat = 1; | |
411 else | |
412 xmstat = 0; | |
413 xidx = 0; | |
414 acknak = 21; | |
415 rcvdnak = EOF; | |
416 blocknum = 1; | |
417 break; | |
418 case 'D': | |
419 if (xfile) | |
420 fclose(xfile); | |
421 xfile = 0; | |
422 if (s[1]) { | |
423 xfile = fopen(s + 1, "wb"); | |
424 } | |
425 if (xfile) | |
426 xmstat = 2; | |
427 else | |
428 xmstat = 0; | |
429 xidx = 0; | |
430 acknak = 21; | |
431 blocknum = 1; | |
432 break; | |
433 case 'R': | |
434 pcreg = (mem[0xfffe] << 8) + mem[0xffff]; | |
435 break; | |
436 } | |
437 if (tracing||breakpoint||trskip||bpskip||stkskip) { attention = escape = 1; } | |
438 else attention = 0; | |
439 set_term(escchar); | |
440 } | |
441 | |
442 void timehandler(int sig) { | |
443 attention = 1; | |
444 irq = 2; | |
445 signal(SIGALRM, timehandler); | |
446 } | |
447 | |
448 void handler(int sig) { | |
449 escape = 1; | |
450 attention = 1; | |
451 bpskip = 0; | |
452 stkskip = 0; | |
453 } | |
454 | |
455 void set_term(char c) { | |
456 struct termios newterm; | |
457 struct itimerval timercontrol; | |
458 signal(SIGQUIT, SIG_IGN); | |
459 signal(SIGTSTP, SIG_IGN); | |
460 signal(SIGINT, handler); | |
461 signal(SIGUSR1, handler); | |
462 tcgetattr(0, &termsetting); | |
463 newterm = termsetting; | |
464 newterm.c_iflag = newterm.c_iflag & ~INLCR & ~ICRNL; | |
465 newterm.c_lflag = newterm.c_lflag & ~ECHO & ~ICANON; | |
466 newterm.c_cc[VTIME] = 0; | |
467 newterm.c_cc[VMIN] = 1; | |
468 newterm.c_cc[VINTR] = escchar; | |
469 tcsetattr(0, TCSAFLUSH, &newterm); | |
470 tflags = fcntl(0, F_GETFL, 0); | |
471 fcntl(0, F_SETFL, tflags | O_NDELAY); /* Make input from stdin non-blocking */ | |
472 signal(SIGALRM, timehandler); | |
473 timercontrol.it_interval.tv_sec = 0; | |
474 timercontrol.it_interval.tv_usec = 20000; | |
475 timercontrol.it_value.tv_sec = 0; | |
476 timercontrol.it_value.tv_usec = 20000; | |
477 if (timer) | |
478 setitimer(ITIMER_REAL, &timercontrol, NULL); | |
479 } |