Mercurial > hg > Members > kono > os9 > sbc09
annotate io.c @ 22:10e33568b38a
clean up
author | Shinji KONO <kono@ie.u-ryukyu.ac.jp> |
---|---|
date | Mon, 09 Jul 2018 14:07:30 +0900 |
parents | 49fac9474858 |
children | 5217f23f2f9e |
rev | line source |
---|---|
9 | 1 /* 6808 Simulator V092 |
2 created 1993,1994 by L.C. Benschop. copyleft (c) 1994-2014 | |
3 by the sbc09 team, see AUTHORS for more details. license: | |
4 GNU General Public License version 2, see LICENSE for more | |
5 details. | |
0 | 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 * | |
7
a6db579d8c11
level 2 rom preparing...
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents:
4
diff
changeset
|
49 * IOPAGE ~ IOPAGE+0x7f |
a6db579d8c11
level 2 rom preparing...
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents:
4
diff
changeset
|
50 * for OS9 level2 |
a6db579d8c11
level 2 rom preparing...
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents:
4
diff
changeset
|
51 * IOPAGE 0xff80 means ioport beging 0xff80 but IOPAGE itself starts 0xff00 |
18 | 52 * 0xfe00-0xff7f, 0xffe0-0xffff can be used as ROM in fixed area |
1 | 53 * |
3 | 54 * IOPAGE + 0x00 ACIA control |
55 * IOPAGE + 0x01 ACIA data | |
1 | 56 * |
7
a6db579d8c11
level 2 rom preparing...
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents:
4
diff
changeset
|
57 * IOPAGE + 0x11 MMU Taskreg 0 system map, 1 user map |
a6db579d8c11
level 2 rom preparing...
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents:
4
diff
changeset
|
58 * IOPAGE + 0x20-0x27 MMU reg system map |
a6db579d8c11
level 2 rom preparing...
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents:
4
diff
changeset
|
59 * IOPAGE + 0x28-0x2f MMU reg user map |
3 | 60 * |
61 * on reset tr==0 and only IOPAGE is valid | |
62 * translatation occur only on non-IOPAGE | |
63 * mem == phymem + 0x70000 | |
64 * phy addr = phymem[ ( mmu[ adr >> 13 ] <<13 ) + (adr & 0x1fff ) ] | |
65 * tr=0 mmu=IOPAGE+0xa0 | |
66 * tr=1 mmu=IOPAGE+0xa8 | |
1 | 67 * |
7
a6db579d8c11
level 2 rom preparing...
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents:
4
diff
changeset
|
68 * IOPAGE + 0x30 Timer control 0x8f start timer/0x80 stop timer/0x04 update date |
a6db579d8c11
level 2 rom preparing...
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents:
4
diff
changeset
|
69 * IOPAGE + 0x31- YY/MM/DD/HH/MM/SS |
a6db579d8c11
level 2 rom preparing...
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents:
4
diff
changeset
|
70 * |
a6db579d8c11
level 2 rom preparing...
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents:
4
diff
changeset
|
71 * IOPAGE + 0x40 Disk control 0x81 read/0x55 write 0 ... ok / 0xff .. error |
a6db579d8c11
level 2 rom preparing...
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents:
4
diff
changeset
|
72 * IOPAGE + 0x41 drive no |
a6db579d8c11
level 2 rom preparing...
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents:
4
diff
changeset
|
73 * IOPAGE + 0x42 LSN2 |
a6db579d8c11
level 2 rom preparing...
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents:
4
diff
changeset
|
74 * IOPAGE + 0x43 LSN1 |
a6db579d8c11
level 2 rom preparing...
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents:
4
diff
changeset
|
75 * IOPAGE + 0x44 LSN0 |
a6db579d8c11
level 2 rom preparing...
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents:
4
diff
changeset
|
76 * IOPAGE + 0x45 ADR2 |
a6db579d8c11
level 2 rom preparing...
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents:
4
diff
changeset
|
77 * IOPAGE + 0x46 ADR1 |
a6db579d8c11
level 2 rom preparing...
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents:
4
diff
changeset
|
78 * |
a6db579d8c11
level 2 rom preparing...
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents:
4
diff
changeset
|
79 * |
1 | 80 */ |
81 | |
82 #define SECSIZE 256 | |
83 | |
19 | 84 |
0 | 85 int timer = 1; |
86 struct termios termsetting; | |
20 | 87 struct termios newterm; |
88 struct itimerval timercontrol; | |
0 | 89 |
20 | 90 int tflags; |
0 | 91 int xmstat; /* 0= no XMODEM transfer, 1=send, 2=receiver */ |
92 unsigned char xmbuf[132]; | |
93 int xidx; | |
94 int acknak; | |
95 int rcvdnak; | |
96 int blocknum; | |
97 | |
98 FILE *infile; | |
99 FILE *xfile; | |
20 | 100 FILE *logfile; |
1 | 101 FILE *disk[] = {0,0}; |
0 | 102 |
9 | 103 #ifdef USE_MMU |
104 extern char *prog ; // for disass | |
11 | 105 extern Byte * mem0(Byte *iphymem, Word adr, Byte *immu) ; |
9 | 106 #endif |
107 | |
20 | 108 extern int bpskip ; |
109 extern int stkskip ; | |
110 extern FILE *logfile; | |
0 | 111 |
1 | 112 void do_timer(int,int); |
113 void do_disk(int,int); | |
4 | 114 void do_mmu(int,int); |
0 | 115 |
116 int char_input(void) { | |
117 int c, w, sum; | |
118 if (!xmstat) { | |
119 if (infile) { | |
120 c = getc(infile); | |
121 if (c == EOF) { | |
122 fclose(infile); | |
123 infile = 0; | |
124 return char_input(); | |
125 } | |
126 if (c == '\n') | |
127 c = '\r'; | |
128 return c; | |
2
31d96e2b364e
add virtual hd option to v09
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents:
1
diff
changeset
|
129 } else { |
31d96e2b364e
add virtual hd option to v09
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents:
1
diff
changeset
|
130 usleep(100); |
0 | 131 return getchar(); |
2
31d96e2b364e
add virtual hd option to v09
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents:
1
diff
changeset
|
132 } |
0 | 133 } else if (xmstat == 1) { |
134 if (xidx) { | |
135 c = xmbuf[xidx++]; | |
136 if (xidx == 132) { | |
137 xidx = 0; | |
138 rcvdnak = EOF; | |
139 acknak = 6; | |
140 } | |
141 } else { | |
142 if ((acknak == 21 && rcvdnak == 21) || (acknak == 6 && rcvdnak == 6)) { | |
143 rcvdnak = 0; | |
144 memset(xmbuf, 0, 132); | |
145 w = fread(xmbuf + 3, 1, 128, xfile); | |
146 if (w) { | |
147 printf("Block %3d transmitted, ", blocknum); | |
148 xmbuf[0] = 1; | |
149 xmbuf[1] = blocknum; | |
150 xmbuf[2] = 255 - blocknum; | |
151 blocknum = (blocknum + 1) & 255; | |
152 sum = 0; | |
153 for (w = 3; w < 131; w++) | |
154 sum = (sum + xmbuf[w]) & 255; | |
155 xmbuf[131] = sum; | |
156 acknak = 6; | |
157 c = 1; | |
158 xidx = 1; | |
159 } else { | |
160 printf("EOT transmitted, "); | |
161 acknak = 4; | |
162 c = 4; | |
163 } | |
164 } else if (rcvdnak == 21) { | |
165 rcvdnak = 0; | |
166 printf("Block %3d retransmitted, ", xmbuf[1]); | |
167 c = xmbuf[xidx++]; /*retransmit the same block */ | |
168 } else | |
169 c = EOF; | |
170 } | |
171 return c; | |
172 } else { | |
173 if (acknak == 4) { | |
174 c = 6; | |
175 acknak = 0; | |
176 fclose(xfile); | |
177 xfile = 0; | |
178 xmstat = 0; | |
179 } else if (acknak) { | |
180 c = acknak; | |
181 acknak = 0; | |
182 } else | |
183 c = EOF; | |
184 if (c == 6) | |
185 printf("ACK\n"); | |
186 if (c == 21) | |
187 printf("NAK\n"); | |
188 return c; | |
189 } | |
190 } | |
191 | |
9 | 192 int do_input(int a) { |
0 | 193 static int c, f = EOF; |
18 | 194 if (a == 0+(IOPAGE&0x1ff)) { |
0 | 195 if (f == EOF) |
196 f = char_input(); | |
197 if (f != EOF) | |
198 c = f; | |
199 return 2 + (f != EOF); | |
18 | 200 } else if (a == 1+(IOPAGE&0x1ff)) { /*data port*/ |
0 | 201 if (f == EOF) |
202 f = char_input(); | |
203 if (f != EOF) { | |
204 c = f; | |
205 f = EOF; | |
206 } | |
207 return c; | |
208 } | |
18 | 209 return mem[(IOPAGE&0xfe00) + a]; |
0 | 210 } |
211 | |
212 void do_output(int a, int c) { | |
213 int i, sum; | |
18 | 214 if (a == 1+(IOPAGE&0x1ff)) { /* ACIA data port,ignore address */ |
0 | 215 if (!xmstat) { |
216 if (logfile && c != 127 && (c >= ' ' || c == '\n')) | |
217 putc(c, logfile); | |
218 putchar(c); | |
219 fflush(stdout); | |
220 } else if (xmstat == 1) { | |
221 rcvdnak = c; | |
222 if (c == 6 && acknak == 4) { | |
223 fclose(xfile); | |
224 xfile = 0; | |
225 xmstat = 0; | |
226 } | |
227 if (c == 6) | |
228 printf("ACK\n"); | |
229 if (c == 21) | |
230 printf("NAK\n"); | |
231 if (c == 24) { | |
232 printf("CAN\n"); | |
233 fclose(xfile); | |
234 xmstat = 0; | |
235 xfile = 0; | |
236 } | |
237 } else { | |
238 if (xidx == 0 && c == 4) { | |
239 acknak = 4; | |
240 printf("EOT received, "); | |
241 } | |
242 xmbuf[xidx++] = c; | |
243 if (xidx == 132) { | |
244 sum = 0; | |
245 for (i = 3; i < 131; i++) | |
246 sum = (sum + xmbuf[i]) & 255; | |
247 if (xmbuf[0] == 1 && xmbuf[1] == 255 - xmbuf[2] | |
248 && sum == xmbuf[131]) | |
249 acknak = 6; | |
250 else | |
251 acknak = 21; | |
252 printf("Block %3d received, ", xmbuf[1]); | |
253 if (blocknum == xmbuf[1]) { | |
254 blocknum = (blocknum + 1) & 255; | |
255 fwrite(xmbuf + 3, 1, 128, xfile); | |
256 } | |
257 xidx = 0; | |
258 } | |
259 } | |
18 | 260 } else if (a >= 0x40+(IOPAGE&0x1ff)) { /* disk */ |
11 | 261 do_disk(a,c); |
18 | 262 } else if (a >= 0x30+(IOPAGE&0x1ff)) { /* timer */ |
11 | 263 do_timer(a,c); |
18 | 264 } else if (a >= 0x10+(IOPAGE&0x1ff)) { /* mmu */ |
4 | 265 do_mmu(a,c); |
0 | 266 } |
267 } | |
268 | |
269 | |
1 | 270 void do_timer(int a, int c) { |
271 struct itimerval timercontrol; | |
18 | 272 if (a==0x30+(IOPAGE&0x1ff) && c==0x8f) { |
1 | 273 timercontrol.it_interval.tv_sec = 0; |
274 timercontrol.it_interval.tv_usec = 20000; | |
275 timercontrol.it_value.tv_sec = 0; | |
276 timercontrol.it_value.tv_usec = 20000; | |
277 setitimer(ITIMER_REAL, &timercontrol, NULL); | |
18 | 278 } else if (a==0x30+(IOPAGE&0x1ff) && c==0x80) { |
1 | 279 timercontrol.it_interval.tv_sec = 0; |
280 timercontrol.it_interval.tv_usec = 0; | |
281 setitimer(ITIMER_REAL, &timercontrol, NULL); | |
18 | 282 } else if (a==0x30+(IOPAGE&0x1ff) && c==0x04) { |
1 | 283 time_t tm = time(0); |
284 struct tm *t = localtime(&tm); | |
7
a6db579d8c11
level 2 rom preparing...
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents:
4
diff
changeset
|
285 mem[IOPAGE+0x31] = t->tm_year; |
a6db579d8c11
level 2 rom preparing...
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents:
4
diff
changeset
|
286 mem[IOPAGE+0x32] = t->tm_mon; |
a6db579d8c11
level 2 rom preparing...
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents:
4
diff
changeset
|
287 mem[IOPAGE+0x33] = t->tm_mday; |
a6db579d8c11
level 2 rom preparing...
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents:
4
diff
changeset
|
288 mem[IOPAGE+0x34] = t->tm_hour; |
a6db579d8c11
level 2 rom preparing...
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents:
4
diff
changeset
|
289 mem[IOPAGE+0x35] = t->tm_min; |
a6db579d8c11
level 2 rom preparing...
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents:
4
diff
changeset
|
290 mem[IOPAGE+0x36] = t->tm_sec; |
1 | 291 } else { |
18 | 292 mem[(IOPAGE&0xfe00)+a]=c; |
1 | 293 } |
294 } | |
295 | |
296 void do_disk(int a, int c) { | |
18 | 297 if (a!=0x40+(IOPAGE&0x1ff)) { |
298 mem[(IOPAGE&0xfe00)+a]=c; | |
1 | 299 return; |
300 } | |
7
a6db579d8c11
level 2 rom preparing...
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents:
4
diff
changeset
|
301 int drv = mem[IOPAGE+0x41]; |
a6db579d8c11
level 2 rom preparing...
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents:
4
diff
changeset
|
302 int lsn = (mem[IOPAGE+0x42]<<16) + (mem[IOPAGE+0x43]<<8) + mem[IOPAGE+0x44]; |
a6db579d8c11
level 2 rom preparing...
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents:
4
diff
changeset
|
303 int buf = (mem[IOPAGE+0x45]<<8) + mem[IOPAGE+0x46]; |
1 | 304 if (drv > 1 || disk[drv]==0) goto error; |
305 if (c==0x81) { | |
306 if (lseek(fileno(disk[drv]),lsn*SECSIZE,SEEK_SET)==-1) goto error; | |
307 if (read(fileno(disk[drv]),&mem[buf],SECSIZE)==-1) goto error; | |
308 } else if (c==0x55) { | |
309 if (lseek(fileno(disk[drv]),lsn*SECSIZE,SEEK_SET)==-1) goto error; | |
310 if (write(fileno(disk[drv]),&mem[buf],SECSIZE)==-1) goto error; | |
311 } | |
7
a6db579d8c11
level 2 rom preparing...
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents:
4
diff
changeset
|
312 mem[IOPAGE+0x40] = 0; |
1 | 313 return; |
314 error : | |
7
a6db579d8c11
level 2 rom preparing...
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents:
4
diff
changeset
|
315 mem[IOPAGE+0x40] = 0xff; |
1 | 316 } |
317 | |
4 | 318 void do_mmu(int a, int c) |
319 { | |
320 #ifdef USE_MMU | |
321 | |
18 | 322 if (a==0x11+(IOPAGE&0x1ff)) { |
13 | 323 if (c&1) { |
324 mmu = phymem+memsize-0x10000+0xffa8; | |
325 } else { | |
4 | 326 mmu = phymem+memsize-0x10000+0xffa0; |
327 } | |
328 } | |
18 | 329 mem[(IOPAGE&0xfe00)+a] = c; // other register such as 0xffa0-0xffaf |
4 | 330 #endif |
331 } | |
332 | |
0 | 333 void timehandler(int sig) { |
334 attention = 1; | |
335 irq = 2; | |
336 signal(SIGALRM, timehandler); | |
337 } | |
338 | |
339 void handler(int sig) { | |
340 escape = 1; | |
341 attention = 1; | |
342 bpskip = 0; | |
343 stkskip = 0; | |
344 } | |
345 | |
20 | 346 void init_term(void) { |
347 tcgetattr(0, &termsetting); | |
348 tflags = fcntl(0, F_GETFL, 0); | |
349 } | |
350 | |
0 | 351 void set_term(char c) { |
352 signal(SIGQUIT, SIG_IGN); | |
353 signal(SIGTSTP, SIG_IGN); | |
354 signal(SIGINT, handler); | |
355 signal(SIGUSR1, handler); | |
356 newterm = termsetting; | |
357 newterm.c_iflag = newterm.c_iflag & ~INLCR & ~ICRNL; | |
358 newterm.c_lflag = newterm.c_lflag & ~ECHO & ~ICANON; | |
359 newterm.c_cc[VTIME] = 0; | |
360 newterm.c_cc[VMIN] = 1; | |
361 newterm.c_cc[VINTR] = escchar; | |
362 tcsetattr(0, TCSAFLUSH, &newterm); | |
363 fcntl(0, F_SETFL, tflags | O_NDELAY); /* Make input from stdin non-blocking */ | |
364 signal(SIGALRM, timehandler); | |
365 timercontrol.it_interval.tv_sec = 0; | |
366 timercontrol.it_interval.tv_usec = 20000; | |
367 timercontrol.it_value.tv_sec = 0; | |
368 timercontrol.it_value.tv_usec = 20000; | |
369 if (timer) | |
370 setitimer(ITIMER_REAL, &timercontrol, NULL); | |
371 } | |
20 | 372 |
373 void restore_term(void) { | |
22 | 374 termsetting.c_iflag = termsetting.c_iflag | INLCR | ICRNL; |
20 | 375 tcsetattr(0, TCSAFLUSH, &termsetting); |
376 fcntl(0, F_SETFL, tflags); | |
377 signal(SIGALRM, SIG_IGN); | |
378 } | |
379 | |
380 | |
381 | |
382 |