Mercurial > hg > Members > kono > os9 > sbc09
view io.c @ 19:84b28178c82f
level2 shell worked
disk can't be read
author | Shinji KONO <kono@ie.u-ryukyu.ac.jp> |
---|---|
date | Mon, 09 Jul 2018 01:59:17 +0900 |
parents | e3b08716aa53 |
children | 49fac9474858 |
line wrap: on
line source
/* 6808 Simulator V092 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> #include <time.h> #ifdef USE_TERMIOS #include <termios.h> #endif #define engine extern #include "v09.h" /* * IO Map ( can be overrupped by ROM ) * * IOPAGE ~ IOPAGE+0x7f * for OS9 level2 * IOPAGE 0xff80 means ioport beging 0xff80 but IOPAGE itself starts 0xff00 * 0xfe00-0xff7f, 0xffe0-0xffff can be used as ROM in fixed area * * IOPAGE + 0x00 ACIA control * IOPAGE + 0x01 ACIA data * * IOPAGE + 0x11 MMU Taskreg 0 system map, 1 user map * IOPAGE + 0x20-0x27 MMU reg system map * IOPAGE + 0x28-0x2f MMU reg user map * * on reset tr==0 and only IOPAGE is valid * translatation occur only on non-IOPAGE * mem == phymem + 0x70000 * phy addr = phymem[ ( mmu[ adr >> 13 ] <<13 ) + (adr & 0x1fff ) ] * tr=0 mmu=IOPAGE+0xa0 * tr=1 mmu=IOPAGE+0xa8 * * IOPAGE + 0x30 Timer control 0x8f start timer/0x80 stop timer/0x04 update date * IOPAGE + 0x31- YY/MM/DD/HH/MM/SS * * IOPAGE + 0x40 Disk control 0x81 read/0x55 write 0 ... ok / 0xff .. error * IOPAGE + 0x41 drive no * IOPAGE + 0x42 LSN2 * IOPAGE + 0x43 LSN1 * IOPAGE + 0x44 LSN0 * IOPAGE + 0x45 ADR2 * IOPAGE + 0x46 ADR1 * * */ #define SECSIZE 256 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; FILE *disk[] = {0,0}; extern void hexadump( unsigned char *b, int l, int loc, int w); extern int disasm(int,int); #ifdef USE_MMU extern char *prog ; // for disass extern Byte * mem0(Byte *iphymem, Word adr, Byte *immu) ; #endif void do_timer(int,int); void do_disk(int,int); void do_mmu(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 { usleep(100); 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(int a) { static int c, f = EOF; if (a == 0+(IOPAGE&0x1ff)) { if (f == EOF) f = char_input(); if (f != EOF) c = f; return 2 + (f != EOF); } else if (a == 1+(IOPAGE&0x1ff)) { /*data port*/ if (f == EOF) f = char_input(); if (f != EOF) { c = f; f = EOF; } return c; } return mem[(IOPAGE&0xfe00) + a]; } void do_output(int a, int c) { int i, sum; if (a == 1+(IOPAGE&0x1ff)) { /* 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; } } } else if (a >= 0x40+(IOPAGE&0x1ff)) { /* disk */ do_disk(a,c); } else if (a >= 0x30+(IOPAGE&0x1ff)) { /* timer */ do_timer(a,c); } else if (a >= 0x10+(IOPAGE&0x1ff)) { /* mmu */ do_mmu(a,c); } } 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); } void do_timer(int a, int c) { struct itimerval timercontrol; if (a==0x30+(IOPAGE&0x1ff) && c==0x8f) { timercontrol.it_interval.tv_sec = 0; timercontrol.it_interval.tv_usec = 20000; timercontrol.it_value.tv_sec = 0; timercontrol.it_value.tv_usec = 20000; setitimer(ITIMER_REAL, &timercontrol, NULL); } else if (a==0x30+(IOPAGE&0x1ff) && c==0x80) { timercontrol.it_interval.tv_sec = 0; timercontrol.it_interval.tv_usec = 0; setitimer(ITIMER_REAL, &timercontrol, NULL); } else if (a==0x30+(IOPAGE&0x1ff) && c==0x04) { time_t tm = time(0); struct tm *t = localtime(&tm); mem[IOPAGE+0x31] = t->tm_year; mem[IOPAGE+0x32] = t->tm_mon; mem[IOPAGE+0x33] = t->tm_mday; mem[IOPAGE+0x34] = t->tm_hour; mem[IOPAGE+0x35] = t->tm_min; mem[IOPAGE+0x36] = t->tm_sec; } else { mem[(IOPAGE&0xfe00)+a]=c; } } void do_disk(int a, int c) { if (a!=0x40+(IOPAGE&0x1ff)) { mem[(IOPAGE&0xfe00)+a]=c; return; } int drv = mem[IOPAGE+0x41]; int lsn = (mem[IOPAGE+0x42]<<16) + (mem[IOPAGE+0x43]<<8) + mem[IOPAGE+0x44]; int buf = (mem[IOPAGE+0x45]<<8) + mem[IOPAGE+0x46]; if (drv > 1 || disk[drv]==0) goto error; if (c==0x81) { if (lseek(fileno(disk[drv]),lsn*SECSIZE,SEEK_SET)==-1) goto error; if (read(fileno(disk[drv]),&mem[buf],SECSIZE)==-1) goto error; } else if (c==0x55) { if (lseek(fileno(disk[drv]),lsn*SECSIZE,SEEK_SET)==-1) goto error; if (write(fileno(disk[drv]),&mem[buf],SECSIZE)==-1) goto error; } mem[IOPAGE+0x40] = 0; return; error : mem[IOPAGE+0x40] = 0xff; } void do_mmu(int a, int c) { #ifdef USE_MMU if (a==0x11+(IOPAGE&0x1ff)) { if (c&1) { mmu = phymem+memsize-0x10000+0xffa8; } else { mmu = phymem+memsize-0x10000+0xffa0; } } mem[(IOPAGE&0xfe00)+a] = c; // other register such as 0xffa0-0xffaf #endif } 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" #ifdef USE_MMU " xp [adr] dump physical memory\n" #endif " xi [adr] disassemble\n" " 0 file disk drive 0 image\n" " 1 file disk drive 1 image\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(); #ifdef USE_MMU Byte *phyadr = mem0(phymem,pcreg,mmu); prog = (char*)phyadr - pcreg; #endif 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[1]=='p') 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 && s[1]=='i') { Word end = adr + len; while(adr < end) { #ifdef USE_MMU Byte *phyadr = mem0(phymem,adr,mmu); prog = (char*)phyadr - adr ; if (phyadr > phymem+memsize) goto restart; #endif int len = adr+16<end? 16 : end-adr -1 ; adr = disasm(adr,adr+len); } } else { #ifdef USE_MMU for(int i=0; len > 0 ; i+=16, len-=16) { if (skip==2 && s[1]=='p') { if (adr+i > memsize) goto restart; hexadump(phymem+adr+i,len>16?16:len,adr+i,16); } else { Byte *phyadr = mem0(phymem,adr+i,mmu); if (phyadr > phymem+memsize) goto restart; hexadump(phyadr,len>16?16:len,adr+i,16); } } #else for(int i=0; len > 0 ; i+=16, len-=16) { hexadump(mem+adr+i,len>16?16:len,adr+i,16); } #endif } } else disasm(pcreg,pcreg+32); goto restart; case 'L': if (logfile) fclose(logfile); logfile = 0; if (s[1]) { int i=1; while(s[i]==' ') i++; logfile = fopen(s + i, "w"); } break; case 'S': if (infile) fclose(infile); infile = 0; if (s[1]) { int i=1; while(s[i]==' ') i++; infile = fopen(s + i, "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 '0': case '1': { FILE **drv = &disk[ s[0]-'0'] ; if (*drv) fclose(*drv); *drv = 0; if (s[1]) { int i=1; while(s[i]==' ') i++; *drv = fopen(s + i, "r+b"); if ( *drv == 0 ) { printf("can't open %s\n", &s[i]); } } } break; case 'U': if (xfile) fclose(xfile); xfile = 0; if (s[1]) { int i=1; while(s[i]==' ') i++; xfile = fopen(s + i, "rb"); if ( xfile == 0 ) { printf("can't open %s\n", &s[i]); } } 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]) { int i=1; while(s[i]==' ') i++; xfile = fopen(s + i, "wb"); if ( xfile == 0 ) { printf("can't open %s\n", &s[i]); } } if (xfile) xmstat = 2; else xmstat = 0; xidx = 0; acknak = 21; blocknum = 1; break; case 'R': pcreg = (mem[0xfffe] << 8) + mem[0xffff]; bpskip = 0; attention = escape = 1; 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); }