Mercurial > hg > Members > kono > os9 > sbc09
diff 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 |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/io.c Mon Jul 02 02:12:31 2018 +0900 @@ -0,0 +1,479 @@ +/* 6809 Simulator V09. + + created 1993,1994 by L.C. Benschop. + copyleft (c) 1994-2014 by the sbc09 team, see AUTHORS for more details. + license: GNU General Public License version 2, see LICENSE for more details. + + This program simulates a 6809 processor. + + System dependencies: short must be 16 bits. + char must be 8 bits. + long must be more than 16 bits. + arrays up to 65536 bytes must be supported. + machine must be twos complement. + Most Unix machines will work. For MSODS you need long pointers + and you may have to malloc() the mem array of 65536 bytes. + + Define BIG_ENDIAN if you have a big-endian machine (680x0 etc) + + Special instructions: + SWI2 writes char to stdout from register B. + SWI3 reads char from stdout to register B, sets carry at EOF. + (or when no key available when using term control). + SWI retains its normal function. + CWAI and SYNC stop simulator. + +*/ + +#include<stdio.h> +#include<stdlib.h> +#include<ctype.h> +#include<signal.h> +#include<sys/time.h> + +#include <unistd.h> +#include <fcntl.h> +#include <string.h> + +#ifdef USE_TERMIOS +#include <termios.h> +#endif + +#define engine extern +#include "v09.h" + +int tflags; +int timer = 1; +struct termios termsetting; + +int xmstat; /* 0= no XMODEM transfer, 1=send, 2=receiver */ +unsigned char xmbuf[132]; +int xidx; +int acknak; +int rcvdnak; +int blocknum; + +FILE *logfile; +FILE *infile; +FILE *xfile; + +extern void hexadump( unsigned char *b, int l, int loc, int w); +extern void disasm(int,int); + + +int char_input(void) { + int c, w, sum; + if (!xmstat) { + if (infile) { + c = getc(infile); + if (c == EOF) { + fclose(infile); + infile = 0; + return char_input(); + } + if (c == '\n') + c = '\r'; + return c; + } else + return getchar(); + } else if (xmstat == 1) { + if (xidx) { + c = xmbuf[xidx++]; + if (xidx == 132) { + xidx = 0; + rcvdnak = EOF; + acknak = 6; + } + } else { + if ((acknak == 21 && rcvdnak == 21) || (acknak == 6 && rcvdnak == 6)) { + rcvdnak = 0; + memset(xmbuf, 0, 132); + w = fread(xmbuf + 3, 1, 128, xfile); + if (w) { + printf("Block %3d transmitted, ", blocknum); + xmbuf[0] = 1; + xmbuf[1] = blocknum; + xmbuf[2] = 255 - blocknum; + blocknum = (blocknum + 1) & 255; + sum = 0; + for (w = 3; w < 131; w++) + sum = (sum + xmbuf[w]) & 255; + xmbuf[131] = sum; + acknak = 6; + c = 1; + xidx = 1; + } else { + printf("EOT transmitted, "); + acknak = 4; + c = 4; + } + } else if (rcvdnak == 21) { + rcvdnak = 0; + printf("Block %3d retransmitted, ", xmbuf[1]); + c = xmbuf[xidx++]; /*retransmit the same block */ + } else + c = EOF; + } + return c; + } else { + if (acknak == 4) { + c = 6; + acknak = 0; + fclose(xfile); + xfile = 0; + xmstat = 0; + } else if (acknak) { + c = acknak; + acknak = 0; + } else + c = EOF; + if (c == 6) + printf("ACK\n"); + if (c == 21) + printf("NAK\n"); + return c; + } +} + +int do_input( a) { + static int c, f = EOF; + if (a == 0) { + if (f == EOF) + f = char_input(); + if (f != EOF) + c = f; + return 2 + (f != EOF); + } else if (a == 1) { /*data port*/ + if (f == EOF) + f = char_input(); + if (f != EOF) { + c = f; + f = EOF; + } + return c; + } + return 0; +} + +void do_output(int a, int c) { + int i, sum; + if (a == 1) { /* ACIA data port,ignore address */ + if (!xmstat) { + if (logfile && c != 127 && (c >= ' ' || c == '\n')) + putc(c, logfile); + putchar(c); + fflush(stdout); + } else if (xmstat == 1) { + rcvdnak = c; + if (c == 6 && acknak == 4) { + fclose(xfile); + xfile = 0; + xmstat = 0; + } + if (c == 6) + printf("ACK\n"); + if (c == 21) + printf("NAK\n"); + if (c == 24) { + printf("CAN\n"); + fclose(xfile); + xmstat = 0; + xfile = 0; + } + } else { + if (xidx == 0 && c == 4) { + acknak = 4; + printf("EOT received, "); + } + xmbuf[xidx++] = c; + if (xidx == 132) { + sum = 0; + for (i = 3; i < 131; i++) + sum = (sum + xmbuf[i]) & 255; + if (xmbuf[0] == 1 && xmbuf[1] == 255 - xmbuf[2] + && sum == xmbuf[131]) + acknak = 6; + else + acknak = 21; + printf("Block %3d received, ", xmbuf[1]); + if (blocknum == xmbuf[1]) { + blocknum = (blocknum + 1) & 255; + fwrite(xmbuf + 3, 1, 128, xfile); + } + xidx = 0; + } + } + } +} + +void restore_term(void) { + tcsetattr(0, TCSAFLUSH, &termsetting); + fcntl(0, F_SETFL, tflags); + signal(SIGALRM, SIG_IGN); +} + +void do_exit(void) { + restore_term(); + exit(0); +} + +typedef struct bp { + int address; + int count; + struct bp *next; +} BP, *BPTR; + +BPTR breakpoint = 0; +int bpskip = 0; +int trskip = 0; +int stkskip = 0; + +int getarg(char *buf, char** next) { + return strtol(buf,(char**)next,0); +} + +void printhelp(void) +{ + printf( + " s [count] one step trace\n" + " n step over\n" + " f finish this call (until stack pop)\n" + " b [adr] set break point\n" + " l break point list\n" + " d [n] delte break point list\n" + " c [count] continue;\n" + " x [adr] dump\n" + " xi [adr] disassemble\n" + " L file start log to file\n" + " S file set input file\n" + " X exit\n" + " q exit\n" + " U file upload from srecord file \n" + " D file download to srecord file \n" + " R do reset\n" + " h,? print this\n" + ); +} + +void do_escape(void) { + char s[80]; + int adr,skip; + if (bpskip) { // skip unbreak instruction + bpskip--; + for(BPTR b = breakpoint; b ; b=b->next) { + if (pcreg==b->address) { + if (b->count) b->count--; + if (b->count==0) { + goto restart0; + } + } + } + return; + } + if (stkskip) { // skip until return + if (sreg < stkskip ) return; + } +restart0: + stkskip = 0; + restore_term(); + do_trace(stdout); + if (trskip>1) { // show trace and step + trskip--; + set_term(escchar); + return; + } +restart: + printf("v09>"); + fgets(s, 80, stdin); + if (s[0]) + s[strlen(s) - 1] = 0; + switch (s[0]) { + case 's': // one step trace + trskip = 1; + if (s[1]) { + trskip = getarg(s+1,0); + } + bpskip = 0; + attention = escape = 1; + break; + case 'n': // step over + stkskip = sreg; + attention = escape = 1; + break; + case 'f': // finish this call (until stack pop) + stkskip = sreg + 2; + attention = escape = 1; + break; + case 'b': // set break point + { + BPTR bp = calloc(1,sizeof(BP)); + bp->next = breakpoint; + breakpoint = bp; + bp->count = 1; + if (s[1]) { + char *next; + bp->address = getarg(s+1,&next); + if (next[0]) { + bp->count = getarg(next,&next); + } + } else { + bp->address = pcreg; + } + } + bpskip = -1; + goto restart; + case 'l': // break point list + for(BPTR bp = breakpoint; bp ; bp = bp->next) { + printf("%x %i\n", bp->address, bp->count); + } + goto restart; + case 'd': // delte break point list + if (s[1]) { + int trskip = getarg(s+1,0); + BPTR *prev = &breakpoint; + for(BPTR bp = breakpoint; bp ; bp = bp->next) { + if (trskip-- == 0) { + if (bp) { + *prev = bp->next; + } + break; + } + prev = &bp->next; + } + } + goto restart; + case 'c': // continue; + bpskip = -1; + attention = escape = 1; + if (s[1]) { + bpskip = getarg(s+1,0); + } + break; + case 'x': // dump + skip = 1; + if (s[1]=='i') skip=2; + if (s[skip]) { + char *next; + int adr = getarg(s+skip,&next); + int len = 32; + if (next[0]) { + len = getarg(next,&next); + } + if (skip==2) { + disasm(adr,adr+len); + } else { + for(int i=0; len > 0 ; i+=16, len-=16) { + hexadump(mem+adr+i,len>16?16:len,adr+i,16); + } + } + } else + disasm(pcreg,pcreg+32); + goto restart; + case 'L': + if (logfile) + fclose(logfile); + logfile = 0; + if (s[1]) { + logfile = fopen(s + 1, "w"); + } + break; + case 'S': + if (infile) + fclose(infile); + infile = 0; + if (s[1]) { + infile = fopen(s + 1, "r"); + } + break; + case 'h': + case '?': + printhelp(); + goto restart; + case 'X': + case 'q': + if (!xmstat) + do_exit(); + else { + xmstat = 0; + fclose(xfile); + xfile = 0; + } + break; + case 'U': + if (xfile) + fclose(xfile); + xfile = 0; + if (s[1]) { + xfile = fopen(s + 1, "rb"); + } + if (xfile) + xmstat = 1; + else + xmstat = 0; + xidx = 0; + acknak = 21; + rcvdnak = EOF; + blocknum = 1; + break; + case 'D': + if (xfile) + fclose(xfile); + xfile = 0; + if (s[1]) { + xfile = fopen(s + 1, "wb"); + } + if (xfile) + xmstat = 2; + else + xmstat = 0; + xidx = 0; + acknak = 21; + blocknum = 1; + break; + case 'R': + pcreg = (mem[0xfffe] << 8) + mem[0xffff]; + break; + } + if (tracing||breakpoint||trskip||bpskip||stkskip) { attention = escape = 1; } + else attention = 0; + set_term(escchar); +} + +void timehandler(int sig) { + attention = 1; + irq = 2; + signal(SIGALRM, timehandler); +} + +void handler(int sig) { + escape = 1; + attention = 1; + bpskip = 0; + stkskip = 0; +} + +void set_term(char c) { + struct termios newterm; + struct itimerval timercontrol; + signal(SIGQUIT, SIG_IGN); + signal(SIGTSTP, SIG_IGN); + signal(SIGINT, handler); + signal(SIGUSR1, handler); + tcgetattr(0, &termsetting); + newterm = termsetting; + newterm.c_iflag = newterm.c_iflag & ~INLCR & ~ICRNL; + newterm.c_lflag = newterm.c_lflag & ~ECHO & ~ICANON; + newterm.c_cc[VTIME] = 0; + newterm.c_cc[VMIN] = 1; + newterm.c_cc[VINTR] = escchar; + tcsetattr(0, TCSAFLUSH, &newterm); + tflags = fcntl(0, F_GETFL, 0); + fcntl(0, F_SETFL, tflags | O_NDELAY); /* Make input from stdin non-blocking */ + signal(SIGALRM, timehandler); + timercontrol.it_interval.tv_sec = 0; + timercontrol.it_interval.tv_usec = 20000; + timercontrol.it_value.tv_sec = 0; + timercontrol.it_value.tv_usec = 20000; + if (timer) + setitimer(ITIMER_REAL, &timercontrol, NULL); +}