Mercurial > hg > Members > kono > os9 > sbc09
annotate io.c @ 3:831ac057ea86
before mmu
author | Shinji KONO <kono@ie.u-ryukyu.ac.jp> |
---|---|
date | Wed, 04 Jul 2018 14:03:56 +0900 |
parents | 31d96e2b364e |
children | 6159cc57d44e |
rev | line source |
---|---|
0 | 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> | |
1 | 37 #include <time.h> |
0 | 38 |
39 #ifdef USE_TERMIOS | |
40 #include <termios.h> | |
41 #endif | |
42 | |
43 #define engine extern | |
44 #include "v09.h" | |
45 | |
1 | 46 /* |
3 | 47 * IO Map ( can be overrupped by ROM ) |
48 * | |
49 * IOPAGE ~ IOPAGE+0xff | |
1 | 50 * |
3 | 51 * IOPAGE + 0x00 ACIA control |
52 * IOPAGE + 0x01 ACIA data | |
1 | 53 * |
3 | 54 * IOPAGE + 0x10 Timer control 0x8f start timer/0x80 stop timer/0x04 update date |
55 * IOPAGE + 0x11- YY/MM/DD/HH/MM/SS | |
1 | 56 * |
3 | 57 * IOPAGE + 0x20 Disk control 0x81 read/0x55 write 0 ... ok / 0xff .. error |
58 * IOPAGE + 0x21 drive no | |
59 * IOPAGE + 0x22 LSN2 | |
60 * IOPAGE + 0x23 LSN1 | |
61 * IOPAGE + 0x24 LSN0 | |
62 * IOPAGE + 0x25 ADR2 | |
63 * IOPAGE + 0x26 ADR1 | |
1 | 64 * |
3 | 65 * IOPAGE + 0x91 MMU Taskreg 0 system map, 1 user map |
66 * IOPAGE + 0xa0-0xa7 MMU reg system map | |
67 * IOPAGE + 0xa8-0xaf MMU reg user map | |
68 * | |
69 * on reset tr==0 and only IOPAGE is valid | |
70 * translatation occur only on non-IOPAGE | |
71 * mem == phymem + 0x70000 | |
72 * phy addr = phymem[ ( mmu[ adr >> 13 ] <<13 ) + (adr & 0x1fff ) ] | |
73 * tr=0 mmu=IOPAGE+0xa0 | |
74 * tr=1 mmu=IOPAGE+0xa8 | |
1 | 75 * |
76 */ | |
77 | |
78 #define SECSIZE 256 | |
79 | |
0 | 80 int tflags; |
81 int timer = 1; | |
82 struct termios termsetting; | |
83 | |
84 int xmstat; /* 0= no XMODEM transfer, 1=send, 2=receiver */ | |
85 unsigned char xmbuf[132]; | |
86 int xidx; | |
87 int acknak; | |
88 int rcvdnak; | |
89 int blocknum; | |
90 | |
91 FILE *logfile; | |
92 FILE *infile; | |
93 FILE *xfile; | |
1 | 94 FILE *disk[] = {0,0}; |
0 | 95 |
96 extern void hexadump( unsigned char *b, int l, int loc, int w); | |
97 extern void disasm(int,int); | |
98 | |
1 | 99 void do_timer(int,int); |
100 void do_disk(int,int); | |
0 | 101 |
102 int char_input(void) { | |
103 int c, w, sum; | |
104 if (!xmstat) { | |
105 if (infile) { | |
106 c = getc(infile); | |
107 if (c == EOF) { | |
108 fclose(infile); | |
109 infile = 0; | |
110 return char_input(); | |
111 } | |
112 if (c == '\n') | |
113 c = '\r'; | |
114 return c; | |
2
31d96e2b364e
add virtual hd option to v09
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents:
1
diff
changeset
|
115 } else { |
31d96e2b364e
add virtual hd option to v09
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents:
1
diff
changeset
|
116 usleep(100); |
0 | 117 return getchar(); |
2
31d96e2b364e
add virtual hd option to v09
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents:
1
diff
changeset
|
118 } |
0 | 119 } else if (xmstat == 1) { |
120 if (xidx) { | |
121 c = xmbuf[xidx++]; | |
122 if (xidx == 132) { | |
123 xidx = 0; | |
124 rcvdnak = EOF; | |
125 acknak = 6; | |
126 } | |
127 } else { | |
128 if ((acknak == 21 && rcvdnak == 21) || (acknak == 6 && rcvdnak == 6)) { | |
129 rcvdnak = 0; | |
130 memset(xmbuf, 0, 132); | |
131 w = fread(xmbuf + 3, 1, 128, xfile); | |
132 if (w) { | |
133 printf("Block %3d transmitted, ", blocknum); | |
134 xmbuf[0] = 1; | |
135 xmbuf[1] = blocknum; | |
136 xmbuf[2] = 255 - blocknum; | |
137 blocknum = (blocknum + 1) & 255; | |
138 sum = 0; | |
139 for (w = 3; w < 131; w++) | |
140 sum = (sum + xmbuf[w]) & 255; | |
141 xmbuf[131] = sum; | |
142 acknak = 6; | |
143 c = 1; | |
144 xidx = 1; | |
145 } else { | |
146 printf("EOT transmitted, "); | |
147 acknak = 4; | |
148 c = 4; | |
149 } | |
150 } else if (rcvdnak == 21) { | |
151 rcvdnak = 0; | |
152 printf("Block %3d retransmitted, ", xmbuf[1]); | |
153 c = xmbuf[xidx++]; /*retransmit the same block */ | |
154 } else | |
155 c = EOF; | |
156 } | |
157 return c; | |
158 } else { | |
159 if (acknak == 4) { | |
160 c = 6; | |
161 acknak = 0; | |
162 fclose(xfile); | |
163 xfile = 0; | |
164 xmstat = 0; | |
165 } else if (acknak) { | |
166 c = acknak; | |
167 acknak = 0; | |
168 } else | |
169 c = EOF; | |
170 if (c == 6) | |
171 printf("ACK\n"); | |
172 if (c == 21) | |
173 printf("NAK\n"); | |
174 return c; | |
175 } | |
176 } | |
177 | |
178 int do_input( a) { | |
179 static int c, f = EOF; | |
180 if (a == 0) { | |
181 if (f == EOF) | |
182 f = char_input(); | |
183 if (f != EOF) | |
184 c = f; | |
185 return 2 + (f != EOF); | |
186 } else if (a == 1) { /*data port*/ | |
187 if (f == EOF) | |
188 f = char_input(); | |
189 if (f != EOF) { | |
190 c = f; | |
191 f = EOF; | |
192 } | |
193 return c; | |
194 } | |
3 | 195 return mem[IOPAGE + a]; |
0 | 196 } |
197 | |
198 void do_output(int a, int c) { | |
199 int i, sum; | |
200 if (a == 1) { /* ACIA data port,ignore address */ | |
201 if (!xmstat) { | |
202 if (logfile && c != 127 && (c >= ' ' || c == '\n')) | |
203 putc(c, logfile); | |
204 putchar(c); | |
205 fflush(stdout); | |
206 } else if (xmstat == 1) { | |
207 rcvdnak = c; | |
208 if (c == 6 && acknak == 4) { | |
209 fclose(xfile); | |
210 xfile = 0; | |
211 xmstat = 0; | |
212 } | |
213 if (c == 6) | |
214 printf("ACK\n"); | |
215 if (c == 21) | |
216 printf("NAK\n"); | |
217 if (c == 24) { | |
218 printf("CAN\n"); | |
219 fclose(xfile); | |
220 xmstat = 0; | |
221 xfile = 0; | |
222 } | |
223 } else { | |
224 if (xidx == 0 && c == 4) { | |
225 acknak = 4; | |
226 printf("EOT received, "); | |
227 } | |
228 xmbuf[xidx++] = c; | |
229 if (xidx == 132) { | |
230 sum = 0; | |
231 for (i = 3; i < 131; i++) | |
232 sum = (sum + xmbuf[i]) & 255; | |
233 if (xmbuf[0] == 1 && xmbuf[1] == 255 - xmbuf[2] | |
234 && sum == xmbuf[131]) | |
235 acknak = 6; | |
236 else | |
237 acknak = 21; | |
238 printf("Block %3d received, ", xmbuf[1]); | |
239 if (blocknum == xmbuf[1]) { | |
240 blocknum = (blocknum + 1) & 255; | |
241 fwrite(xmbuf + 3, 1, 128, xfile); | |
242 } | |
243 xidx = 0; | |
244 } | |
245 } | |
1 | 246 } else if ((a&0xf0) == 0x10) { /* timer */ |
247 do_timer(a,c); | |
248 } else if ((a&0xf0) == 0x20) { /* disk */ | |
249 do_disk(a,c); | |
0 | 250 } |
251 } | |
252 | |
253 void restore_term(void) { | |
254 tcsetattr(0, TCSAFLUSH, &termsetting); | |
255 fcntl(0, F_SETFL, tflags); | |
256 signal(SIGALRM, SIG_IGN); | |
257 } | |
258 | |
259 void do_exit(void) { | |
260 restore_term(); | |
261 exit(0); | |
262 } | |
263 | |
1 | 264 void do_timer(int a, int c) { |
265 struct itimerval timercontrol; | |
266 if (a==0x10 && c==0x8f) { | |
267 timercontrol.it_interval.tv_sec = 0; | |
268 timercontrol.it_interval.tv_usec = 20000; | |
269 timercontrol.it_value.tv_sec = 0; | |
270 timercontrol.it_value.tv_usec = 20000; | |
271 setitimer(ITIMER_REAL, &timercontrol, NULL); | |
272 } else if (a==0x10 && c==0x80) { | |
273 timercontrol.it_interval.tv_sec = 0; | |
274 timercontrol.it_interval.tv_usec = 0; | |
275 setitimer(ITIMER_REAL, &timercontrol, NULL); | |
276 } else if (a==0x10 && c==0x04) { | |
277 time_t tm = time(0); | |
278 struct tm *t = localtime(&tm); | |
279 mem[IOPAGE+0x11] = t->tm_year; | |
280 mem[IOPAGE+0x12] = t->tm_mon; | |
281 mem[IOPAGE+0x13] = t->tm_mday; | |
282 mem[IOPAGE+0x14] = t->tm_hour; | |
283 mem[IOPAGE+0x15] = t->tm_min; | |
284 mem[IOPAGE+0x16] = t->tm_sec; | |
285 } else { | |
286 mem[IOPAGE+a]=c; | |
287 } | |
288 } | |
289 | |
290 void do_disk(int a, int c) { | |
291 if (a!=0x20) { | |
292 mem[IOPAGE+a]=c; | |
293 return; | |
294 } | |
295 int drv = mem[IOPAGE+0x21]; | |
296 int lsn = (mem[IOPAGE+0x22]<<16) + (mem[IOPAGE+0x23]<<8) + mem[IOPAGE+0x24]; | |
297 int buf = (mem[IOPAGE+0x25]<<8) + mem[IOPAGE+0x26]; | |
298 if (drv > 1 || disk[drv]==0) goto error; | |
299 if (c==0x81) { | |
300 if (lseek(fileno(disk[drv]),lsn*SECSIZE,SEEK_SET)==-1) goto error; | |
301 if (read(fileno(disk[drv]),&mem[buf],SECSIZE)==-1) goto error; | |
302 } else if (c==0x55) { | |
303 if (lseek(fileno(disk[drv]),lsn*SECSIZE,SEEK_SET)==-1) goto error; | |
304 if (write(fileno(disk[drv]),&mem[buf],SECSIZE)==-1) goto error; | |
305 } | |
306 mem[IOPAGE+0x20] = 0; | |
307 return; | |
308 error : | |
309 mem[IOPAGE+0x20] = 0xff; | |
310 } | |
311 | |
0 | 312 typedef struct bp { |
313 int address; | |
314 int count; | |
315 struct bp *next; | |
316 } BP, *BPTR; | |
317 | |
318 BPTR breakpoint = 0; | |
319 int bpskip = 0; | |
320 int trskip = 0; | |
321 int stkskip = 0; | |
322 | |
323 int getarg(char *buf, char** next) { | |
324 return strtol(buf,(char**)next,0); | |
325 } | |
326 | |
327 void printhelp(void) | |
328 { | |
329 printf( | |
330 " s [count] one step trace\n" | |
331 " n step over\n" | |
332 " f finish this call (until stack pop)\n" | |
333 " b [adr] set break point\n" | |
334 " l break point list\n" | |
335 " d [n] delte break point list\n" | |
336 " c [count] continue;\n" | |
337 " x [adr] dump\n" | |
338 " xi [adr] disassemble\n" | |
1 | 339 " 0 file disk drive 0 image\n" |
340 " 1 file disk drive 1 image\n" | |
0 | 341 " L file start log to file\n" |
342 " S file set input file\n" | |
343 " X exit\n" | |
344 " q exit\n" | |
345 " U file upload from srecord file \n" | |
346 " D file download to srecord file \n" | |
347 " R do reset\n" | |
348 " h,? print this\n" | |
349 ); | |
350 } | |
351 | |
352 void do_escape(void) { | |
353 char s[80]; | |
354 int adr,skip; | |
355 if (bpskip) { // skip unbreak instruction | |
356 bpskip--; | |
357 for(BPTR b = breakpoint; b ; b=b->next) { | |
358 if (pcreg==b->address) { | |
359 if (b->count) b->count--; | |
360 if (b->count==0) { | |
361 goto restart0; | |
362 } | |
363 } | |
364 } | |
365 return; | |
366 } | |
367 if (stkskip) { // skip until return | |
368 if (sreg < stkskip ) return; | |
369 } | |
370 restart0: | |
371 stkskip = 0; | |
372 restore_term(); | |
373 do_trace(stdout); | |
374 if (trskip>1) { // show trace and step | |
375 trskip--; | |
376 set_term(escchar); | |
377 return; | |
378 } | |
379 restart: | |
380 printf("v09>"); | |
381 fgets(s, 80, stdin); | |
382 if (s[0]) | |
383 s[strlen(s) - 1] = 0; | |
384 switch (s[0]) { | |
385 case 's': // one step trace | |
386 trskip = 1; | |
387 if (s[1]) { | |
388 trskip = getarg(s+1,0); | |
389 } | |
390 bpskip = 0; | |
391 attention = escape = 1; | |
392 break; | |
393 case 'n': // step over | |
394 stkskip = sreg; | |
395 attention = escape = 1; | |
396 break; | |
397 case 'f': // finish this call (until stack pop) | |
398 stkskip = sreg + 2; | |
399 attention = escape = 1; | |
400 break; | |
401 case 'b': // set break point | |
402 { | |
403 BPTR bp = calloc(1,sizeof(BP)); | |
404 bp->next = breakpoint; | |
405 breakpoint = bp; | |
406 bp->count = 1; | |
407 if (s[1]) { | |
408 char *next; | |
409 bp->address = getarg(s+1,&next); | |
410 if (next[0]) { | |
411 bp->count = getarg(next,&next); | |
412 } | |
413 } else { | |
414 bp->address = pcreg; | |
415 } | |
416 } | |
417 bpskip = -1; | |
418 goto restart; | |
419 case 'l': // break point list | |
420 for(BPTR bp = breakpoint; bp ; bp = bp->next) { | |
421 printf("%x %i\n", bp->address, bp->count); | |
422 } | |
423 goto restart; | |
424 case 'd': // delte break point list | |
425 if (s[1]) { | |
426 int trskip = getarg(s+1,0); | |
427 BPTR *prev = &breakpoint; | |
428 for(BPTR bp = breakpoint; bp ; bp = bp->next) { | |
429 if (trskip-- == 0) { | |
430 if (bp) { | |
431 *prev = bp->next; | |
432 } | |
433 break; | |
434 } | |
435 prev = &bp->next; | |
436 } | |
437 } | |
438 goto restart; | |
439 case 'c': // continue; | |
440 bpskip = -1; | |
441 attention = escape = 1; | |
442 if (s[1]) { | |
443 bpskip = getarg(s+1,0); | |
444 } | |
445 break; | |
446 case 'x': // dump | |
447 skip = 1; | |
448 if (s[1]=='i') skip=2; | |
449 if (s[skip]) { | |
450 char *next; | |
451 int adr = getarg(s+skip,&next); | |
452 int len = 32; | |
453 if (next[0]) { | |
454 len = getarg(next,&next); | |
455 } | |
456 if (skip==2) { | |
457 disasm(adr,adr+len); | |
458 } else { | |
459 for(int i=0; len > 0 ; i+=16, len-=16) { | |
460 hexadump(mem+adr+i,len>16?16:len,adr+i,16); | |
461 } | |
462 } | |
463 } else | |
464 disasm(pcreg,pcreg+32); | |
465 goto restart; | |
466 case 'L': | |
467 if (logfile) | |
468 fclose(logfile); | |
469 logfile = 0; | |
470 if (s[1]) { | |
1 | 471 int i=1; while(s[i]==' ') i++; |
472 logfile = fopen(s + i, "w"); | |
0 | 473 } |
474 break; | |
475 case 'S': | |
476 if (infile) | |
477 fclose(infile); | |
478 infile = 0; | |
479 if (s[1]) { | |
1 | 480 int i=1; while(s[i]==' ') i++; |
481 infile = fopen(s + i, "r"); | |
0 | 482 } |
483 break; | |
484 case 'h': | |
485 case '?': | |
486 printhelp(); | |
487 goto restart; | |
488 case 'X': | |
489 case 'q': | |
490 if (!xmstat) | |
491 do_exit(); | |
492 else { | |
493 xmstat = 0; | |
494 fclose(xfile); | |
495 xfile = 0; | |
496 } | |
497 break; | |
1 | 498 case '0': |
499 case '1': | |
500 { FILE **drv = &disk[ s[0]-'0'] ; | |
501 if (*drv) | |
502 fclose(*drv); | |
503 *drv = 0; | |
504 if (s[1]) { | |
505 int i=1; while(s[i]==' ') i++; | |
506 *drv = fopen(s + i, "r+b"); | |
507 if ( *drv == 0 ) { printf("can't open %s\n", &s[i]); } | |
508 } | |
509 } | |
510 break; | |
0 | 511 case 'U': |
512 if (xfile) | |
513 fclose(xfile); | |
514 xfile = 0; | |
515 if (s[1]) { | |
1 | 516 int i=1; while(s[i]==' ') i++; |
517 xfile = fopen(s + i, "rb"); | |
518 if ( xfile == 0 ) { printf("can't open %s\n", &s[i]); } | |
0 | 519 } |
520 if (xfile) | |
521 xmstat = 1; | |
522 else | |
523 xmstat = 0; | |
524 xidx = 0; | |
525 acknak = 21; | |
526 rcvdnak = EOF; | |
527 blocknum = 1; | |
528 break; | |
529 case 'D': | |
530 if (xfile) | |
531 fclose(xfile); | |
532 xfile = 0; | |
533 if (s[1]) { | |
1 | 534 int i=1; while(s[i]==' ') i++; |
535 xfile = fopen(s + i, "wb"); | |
536 if ( xfile == 0 ) { printf("can't open %s\n", &s[i]); } | |
0 | 537 } |
538 if (xfile) | |
539 xmstat = 2; | |
540 else | |
541 xmstat = 0; | |
542 xidx = 0; | |
543 acknak = 21; | |
544 blocknum = 1; | |
545 break; | |
546 case 'R': | |
547 pcreg = (mem[0xfffe] << 8) + mem[0xffff]; | |
548 break; | |
549 } | |
550 if (tracing||breakpoint||trskip||bpskip||stkskip) { attention = escape = 1; } | |
551 else attention = 0; | |
552 set_term(escchar); | |
553 } | |
554 | |
555 void timehandler(int sig) { | |
556 attention = 1; | |
557 irq = 2; | |
558 signal(SIGALRM, timehandler); | |
559 } | |
560 | |
561 void handler(int sig) { | |
562 escape = 1; | |
563 attention = 1; | |
564 bpskip = 0; | |
565 stkskip = 0; | |
566 } | |
567 | |
568 void set_term(char c) { | |
569 struct termios newterm; | |
570 struct itimerval timercontrol; | |
571 signal(SIGQUIT, SIG_IGN); | |
572 signal(SIGTSTP, SIG_IGN); | |
573 signal(SIGINT, handler); | |
574 signal(SIGUSR1, handler); | |
575 tcgetattr(0, &termsetting); | |
576 newterm = termsetting; | |
577 newterm.c_iflag = newterm.c_iflag & ~INLCR & ~ICRNL; | |
578 newterm.c_lflag = newterm.c_lflag & ~ECHO & ~ICANON; | |
579 newterm.c_cc[VTIME] = 0; | |
580 newterm.c_cc[VMIN] = 1; | |
581 newterm.c_cc[VINTR] = escchar; | |
582 tcsetattr(0, TCSAFLUSH, &newterm); | |
583 tflags = fcntl(0, F_GETFL, 0); | |
584 fcntl(0, F_SETFL, tflags | O_NDELAY); /* Make input from stdin non-blocking */ | |
585 signal(SIGALRM, timehandler); | |
586 timercontrol.it_interval.tv_sec = 0; | |
587 timercontrol.it_interval.tv_usec = 20000; | |
588 timercontrol.it_value.tv_sec = 0; | |
589 timercontrol.it_value.tv_usec = 20000; | |
590 if (timer) | |
591 setitimer(ITIMER_REAL, &timercontrol, NULL); | |
592 } |