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);
+}