# You may have to edit this file to delete header lines produced by # mailers or news systems from this file (all lines before these shell # comments you are currently reading). # To install this software on a UNIX system: # 1) create a directory (e.g. with the shell command mkdir stuff) # 2) change to that directory (e.g. with the command cd stuff), # 3) direct the remainder of this text to sh (e.g. sh < ../savedmail). # This will make sh create files in the new directory; it will do # nothing else (if you're paranoid, you should scan the following text # to verify this before you follow these directions). Then read README # in the new directory for additional instructions. cat > Makefile <<\xxxxxxxxxx # make a Hawk emulator # Author: Douglas W. Jones # # Instructions: # # 1, configure your emulator by editing this file, as directed below # 2, make compiler=cc curse=<-Llinker options> # 3, make clean to remove compilation temporaries ########################################################################## # # Machine Configuration Section: # # In effect, the skeleton of the emulator is an bus, into which you # plug option boards for I/O devices and other machine components. # # RULE: To select an option, follow the directions. # If, on real hardware, you'd have to jumper something on the # circuit board, then you must edit the source file for the # option and select the jumperable feature there. #---- exactly one of the following definitions must be uncommented # the Hawk cpu cpu = cpu.o #---- exactly one of the following definition pairs must be uncommented # the Hawk console console = console.o showop.o conslib = $(curse) -lcurses -ltermcap #---- exactly one of the following definition pairs must be uncommented # the Hawk ROM initializer powerup = powerup.o #---- Memory; on a real machine, the amount of memory can be selected # as any multiple of 0x10000 up to 0xFFFF0000 (a highly unlikely upper # limit). This emulator does not allow for non-contiguous memory fields. # The memory size is specified in bytes! #---- exactly one of the following definitions must be uncommented MEMORY = -DMAXMEM=0x20000 -DMAXROM=0x10000 ########################################################################## # # Patch together the list of object files and the list of compiler # options from the above options = $(MEMORY) objects = $(cpu) $(console) $(powerup) libraries = $(conslib) ########################################################################## # # Override make's complex understanding of file suffixes and make sure # that all c compiles use the options we've set up. .SUFFIXES: .o .c .c.o: $(compiler) -c -O $(options) $*.c ########################################################################## # # Actual makefile dependencies for the emulator # # Note that, since this makefile contains the option settings, # it references itself! hawk: $(objects) $(compiler) -o hawk $(objects) $(libraries) $(objects): bus.h Makefile ########################################################################## # # Secondary utilities # make clean to delete the object files, saving disk space clean: rm -f *.o xxxxxxxxxx cat > README <<\xxxxxxxxxx Distribution bundle for the Hawk emulator Author: Douglas W. Jones, University of Iowa, Iowa City, IA 52242, USA Copyright: All of the files included here may be redistributed freely so long as the original author is given complete credit for his work. Makefile -- used to make the emulator (includes brief instructions) README -- this file bus.h -- the "communication bus" between emulator components console.c -- the console interface for the emulator cpu.c -- the emulator CPU powerup.c -- code needed to "power up" the emulator (including a SMAL loader) showop.c -- support for symbolic dumps of Hawk object code xxxxxxxxxx cat > bus.h <<\xxxxxxxxxx /* File: bus.h Author: Douglas Jones, Dept. of Comp. Sci., U. of Iowa, Iowa City, IA 52242. Date: Aug 1996 Language: C (UNIX) Purpose: Declarations of bus lines shared by the hawk CPU and peripherals. This is not, strictly speaking, a real bus layout, but rather, it is a set of declarations driven by the needs of system emulation. Constraints: When included in the main program, MAIN must be defined. When included elsewhere, MAIN must not be defined. */ /* The following trick puts extern on definitions if not in the main program */ #ifdef MAIN #define EXTERN #else #define EXTERN extern #endif /*********************/ /* Hawk data formats */ /*********************/ #define WORD unsigned long #define HALF unsigned int #define BYTE unsigned char /******************************************/ /* Utility information needed by emulator */ /******************************************/ /* maximum length of a sensible file name */ #define NAME_LENGTH 120 /* count of memory cycles; cycles is incremented with every memory reference and causes console interrupts. the sum cycles+morecycles is the true cycle count. */ EXTERN WORD cycles; EXTERN WORD morecycles; /* memory address compared with pc to stop cpu at breakpoints */ EXTERN WORD breakpoint; /*****************************************************/ /* Globals that really aren't really part of the bus */ /*****************************************************/ EXTERN char * progname; /* name of program itself (argv[0]) */ /**********/ /* Memory */ /**********/ /* This emulator does not allow for non-contiguous memory fields. Memory runs from 0 to MAXMEM-1; MAXMEM should be a multiple of 0x10000, and should never be as great as 0xFFFF0000 (a highly unlikely limitation). Memory from location 0 to MAXROM-1 is read-only and may not be modified at run-time; MAXROM should be a multiple of 0x10000. */ /* MAXMEM is specified in bytes and provided by Makefile */ /* MAXROM is specified in bytes and provided by Makefile */ /* note that memory is word addressable */ EXTERN WORD m[ MAXMEM >> 2 ]; /* memory mapped I/O owns the top 16 meg of the address space */ #define IOSPACE 0xFF000000UL /* the memory mapped display device -- give it a megabyte */ #define DISPBASE 0xFF000000UL #define DISPLIMIT 0xFF0FFFFFUL /* the minimalist keyboard */ #define KBDBASE 0xFF100000UL #define KBDLIMIT 0xFF10000FUL /* allow for an IBM PC style I/O address space is addressed in the last 256Kb so that least sig 2 bits of address are ignored, and next 16 bits are the 16 bit address of a PC-style in or out command */ /******************/ /* Trap Vectoring */ /******************/ /* All trap addresses must be less than MAXMEM! */ #define RESTART_TRAP 0x00000000UL /* on powerup */ #define BUS_TRAP 0x00000010UL /* illegal physical address */ #define INSTRUCTION_TRAP 0x00000020UL /* illegal opcode */ #define PRIV_TRAP 0x00000030UL /* privilege violation */ /*******************************/ /* Generally visible registers */ /*******************************/ /* All of the following are visible outside the CPU in some context or another, either to some I/O device or to the front panel. */ EXTERN WORD r[16]; /* the general purpose registers */ EXTERN WORD pc; /* the program counter */ EXTERN WORD psw; /* the processor status word */ EXTERN WORD tpc; /* saved pc after a trap */ EXTERN WORD tma; /* saved memory address after a trap */ EXTERN WORD tsv; /* trap save location */ /* PSW fields */ #define N 0x00000008UL #define Z 0x00000004UL #define V 0x00000002UL #define C 0x00000001UL #define CC (N|V|Z|C) #define CBITS 0x0000FF00UL #define LEVEL 0xF0000000UL #define OLEVEL 0x0F000000UL xxxxxxxxxx cat > console.c <<\xxxxxxxxxx /* File: console.c Author: Douglas Jones, Dept. of Comp. Sci., U. of Iowa, Iowa City, IA 52242. Date: Mar. 6, 1996 Revised: Feb. 27, 2002 - replace BCDGET with EX3ADJ instruction Revised: Mar. 1, 2002 - add SSQADJ Revised: Mar. 13, 2002 - add BTRUNC Revised: Apr. 23, 2002 - strip out showop() into showop.c Language: C (UNIX) with -lcurses option Purpose: Hawk Emulator console support; */ #include "bus.h" #include #include /*#include */ /***************** * screen layout * *****************/ /* title location */ #define titley 1 #define titlex 1 /* number location */ #define numbery 1 #define numberx 36 /* pc location */ #define pcy 3 #define pcx 3 /* dump location */ #define dumpy 3 #define dumpx 45 /* menu location */ #define menuy 12 #define menux 1 /* memory mapped display location */ #define dispy 14 #define dispx 0 /********************* * memory addressing * *********************/ /* relative memory addresses of memory mapped output display; these are relative to DISPBASE the start address for the entire display and apply only within the procedures dispwrite and dispread. */ #define DISPLINES 0 #define DISPCOLS 4 #define DISPSTART 0x100 /* relative memory addresses of memory mapped keyboard interface; these are relative to KBDBASE the start address for the entire keyboard and apply only within the procedures kbdwrite and kbdread. */ #define KBDDATA 0 #define KBDSTAT 4 /******************** * console controls * ********************/ /* basic machine state */ int running = FALSE; int broken = FALSE; /* frequency of console update when running */ WORD recycle; /* cycle count value seen at time of break */ WORD breakcycles = 0; /* number being entered */ WORD number = 0; /* dump controls */ WORD dump_addr = 0; #define DATAMODE 0 #define CODEMODE 1 WORD dump_mode = CODEMODE; /* menu to display */ #define NUM_MENUS 7 WORD which_menu = 1; /************************* * Symbolic Dump Support * *************************/ /******************* * console display * *******************/ static void title() /* put title on screen */ { move(titley, titlex); printw("HAWK EMULATOR"); move(pcy - 1, pcx); printw("/------------------CPU------------------\\"); if (COLS < (dumpx + 18)) return; /* no space on screen */ move(dumpy - 1, dumpx); printw(" /----MEMORY----\\"); } static void status() /* display CPU status on screen */ { char n,z,v,c; int i; n = z = v = c = '0'; if (psw & N) n = '1'; if (psw & Z) z = '1'; if (psw & V) v = '1'; if (psw & C) c = '1'; move(pcy, pcx); /* 0123456789012345 */ printw("PC: %08lX", pc); /* PC: 00000000 */ move(pcy + 1, pcx); printw("PSW: %08lX", psw); /* PSW: 00000000 */ move(pcy + 2, pcx); printw("NZVC: %c %c %c %c", n, z, v, c); /* NZVC: 0 0 0 0 */ for (i = 1; i < 8; i++) { move(pcy + i, pcx + 15); printw("R%1X: %08lX", i, r[i]); } for (i = 8; i < 16; i++) { move(pcy + (i - 8), pcx + 29); printw("R%1X: %08lX", i, r[i]); } } static void dump() /* display memory on screen */ { unsigned int i; if (COLS < (dumpx + 18)) return; /* no space on screen */ if (dump_mode == DATAMODE) { /* do a hex dump */ dump_addr &= 0x00FFFFFCUL; for (i = 0; i < 8; i += 1) { WORD addr = dump_addr + (i<<2); move(dumpy + i, dumpx); if (addr == (pc & 0xFFFFFFFCUL)) { if (addr == (breakpoint & 0xFFFFFFFCUL)) { addstr("-*"); } else { addstr("->"); } } else { if (addr == (breakpoint & 0xFFFFFFFCUL)) { addstr(" *"); } else { addstr(" "); } } if (addr < MAXMEM) { WORD data = m[addr>>2]; printw("%06lX: %08lX", addr&0x00FFFFFFUL, data); if (COLS >= (dumpx + 25)) { int i; addch(' '); for (i = 0; i < 4; i++) { char ch = (data>>(i<<3)) & 0x7F; if (ch < ' ') ch = ' '; addch(ch); } } } else { printw("%06lX: --------", addr & 0x00FFFFFFUL); } clrtoeol(); } } else { /* dump_mode == CODEMODE */ WORD addr; int pcnotseen = TRUE; int trial = 0; do { addr = dump_addr + trial; for (i = 0; i < 8; i += 1) { addr &= 0x00FFFFFEUL; move(dumpy + i, dumpx); if (addr == pc) { if (addr == breakpoint) { addstr("-*"); } else { addstr("->"); } pcnotseen = FALSE; } else { if (addr == breakpoint) { addstr(" *"); } else { addstr(" "); } } if (addr < MAXMEM) { printw("%06lX: ", addr&0x00FFFFFFUL); addr += showop(addr); } else { printw("%06lX: --", addr&0x00FFFFFFUL); addr += 2; } clrtoeol(); } trial += 2; } while (((dump_addr+trial) <= pc) && (pc < addr) && pcnotseen); } } static void shownum() /* display the accumulated number */ { move(numbery, numberx); if (number == 0) { addstr(" "); } else { printw("%08lX", number); } } static void menu() /* display console status */ { static char * menus[]= { " RUNNING control c - halt", "**HALTED** r(run) s(step) q(quit) ?(help)", "**HALTED** i(iterate until pc=here)" " n(run next instruction or call) ?(help)", "**HALTED** 0-9/A-F(enter n) m(show m[n])" " +-(adjust n) ?(help)", "**HALTED** t(toggle memory display) ?(help)", "**HALTED** 0-9/A-F(enter n) p(run until pc=n) ?(help)", "**HALTED** 0-9/A-F(enter n)" " z(set screen update interval to n) ?(help)" }; move(menuy, menux); if (running) { which_menu = 0; } addstr(menus[which_menu]); clrtoeol(); refresh(); } /******************************** * memory mapped output display * ********************************/ static int dispend; /* the end address of the display memory */ static int dispcols; /* the number of displayed columns */ void dispwrite(addr,val) WORD addr; /* relative to display's address range */ WORD val; /* word to display */ { if (addr >= (DISPBASE + DISPSTART)) { if (addr >= dispend) { return; } else { int relad = addr - (DISPBASE + DISPSTART); int x = dispx + relad % dispcols; int y = dispy + relad / dispcols; char c0 = val & 0x7F; char c1 = (val >> 8) & 0x7F; char c2 = (val >>16) & 0x7F; char c3 = (val >>24) & 0x7F; move(y, x); if (c0 >= ' ') {addch(c0);} else {addch(c0|'@');} if (c1 >= ' ') {addch(c1);} else {addch(c1|'@');} if (c2 >= ' ') {addch(c2);} else {addch(c2|'@');} if (c3 >= ' ') {addch(c3);} else {addch(c3|'@');} return; } } else { return; } } WORD dispread(addr) WORD addr; /* relative to display's address range */ { if (addr >= (DISPBASE + DISPSTART)) { if (addr >= dispend) { return 0xFFFFFFFF; } else { int relad = addr - (DISPBASE + DISPSTART); int x = dispx + relad % dispcols; int y = dispy + relad / dispcols; unsigned char c0,c1,c2,c3; move(y, x); c0 = inch(); move(y, x+1); c1 = inch(); move(y, x+2); c2 = inch(); move(y, x+3); c3 = inch(); return (c3 << 24) | (c2 << 16) | (c1 << 8) | c0; } } else if (addr == (DISPBASE + DISPLINES)) { return (LINES - dispy) - 1; } else if (addr == (DISPBASE + DISPCOLS)) { return COLS; } else { return 0xFFFFFFFF; } } /************************** * memory mapped keyboard * **************************/ static WORD kbdbuf = 0UL; /* most recent character read from keyboard */ static int kbdstat = 0; /* keyboard status bits follow */ #define KBDRDY 0x01 /* keyboard ready */ #define KBDERR 0x40 /* keyboard error */ #define KBDIE 0x80 /* keyboard interrupt enable */ static void kbdpoll() /* call whenever there is a need to poll the keyboard for input */ { int ch; ch = getch(); if (ch == ERR) return; kbdbuf = ch & 0xFF; if ((kbdstat & KBDRDY) == 0) { kbdstat |= KBDRDY; } else { /* overrun error */ kbdstat |= KBDERR; } } void kbdwrite(addr,val) WORD addr; /* relative to keyboard's address range */ WORD val; /* word to display */ { if (addr == (KBDBASE + KBDDATA)) { /* no obvious function */ } else if (addr == (KBDBASE + KBDSTAT)) { kbdstat &= ~KBDIE; kbdstat |= val & KBDIE; /* enable or disable interrupt, all else unchanged */ } } WORD kbdread(addr) WORD addr; /* relative to display's address range */ { if (addr == (KBDBASE + KBDDATA)) { kbdstat = 0; /* force next status poll to fail */ return kbdbuf; } else if (addr == (KBDBASE + KBDSTAT)) { morecycles += cycles; /* be nice ... */ cycles = 0; /* let output echo and keyboard poll */ return kbdstat; } } /******************** * console function * ********************/ static void console_stop() /* shutdown */ { signal(SIGINT, SIG_IGN); mvcur(0, COLS-1, LINES-1, 0); endwin(); /* curses wrapup */ exit(0); } static void console_sig(int sigraised) /* control C or other events that stop run */ { /* sigraised is ignored! */ signal(SIGINT, console_sig); breakcycles = cycles; cycles = 0; running = FALSE; broken = TRUE; } void console_startup() /* startup, called from main */ { initscr(); cbreak(); noecho(); clear(); /* curses startup */ signal(SIGINT, console_sig); title(); menu(); breakpoint = 0x00000000UL; recycle = 8; dispcols = COLS - dispx; dispend = DISPBASE + (DISPSTART + (((LINES - dispy)-1) * (dispcols))); } void console() /* console, called from main when countdown < 0 or halt */ { if (dump_mode == CODEMODE) { if (dump_addr > (pc + 16)) { dump_addr = pc - 4; } else if (dump_addr > pc ) { dump_addr = pc; } else if ((dump_addr + 16) <= pc) { dump_addr = pc - 4; } } dump(); status(); if (pc == breakpoint) { running = FALSE; which_menu = 1; } if (running) { cycles -= recycle; morecycles += recycle; kbdpoll(); refresh(); return; } if (broken) { cycles = breakcycles; which_menu = 1; touchwin(stdscr); refresh(); broken = FALSE; } menu(); for (;;) { int ch; nodelay(stdscr, FALSE); ch = getch(); /* if the character is a digit, accumulate it */ if ((ch >= '0') && (ch <= '9')) { number = (number << 4) | (ch & 0xF); shownum(); refresh(); } else if ((ch >= 'A') && (ch <= 'F')) { number = (number << 4) | (ch + (10 - 'A')); shownum(); refresh(); } else if ((ch >= 'a') && (ch <= 'f')) { number = (number << 4) | (ch + (10 - 'a')); shownum(); refresh(); } else switch (ch) { /* else it's not a digit */ case 'r': /* run command */ breakpoint = 0; running = TRUE; menu(); morecycles += (recycle + cycles); cycles = -recycle; nodelay(stdscr, TRUE); return; case 's': /* single step command */ breakpoint = 0; morecycles += cycles; cycles = 0; nodelay(stdscr, TRUE); return; case 'p': /* set breakpoint = number and run command */ breakpoint = number & 0xFFFFFFFEUL; running = TRUE; number = 0; shownum(); menu(); refresh(); morecycles += (recycle + cycles); cycles = -recycle; nodelay(stdscr, TRUE); return; case 'i': /* (iterate) set breakpoint = pc and run command */ breakpoint = pc; running = TRUE; menu(); morecycles += (cycles+recycle); cycles = -recycle; nodelay(stdscr, TRUE); return; case 'n': /* (next) execute one instruction or one call */ if (pc < MAXMEM) { HALF ir; /* fetch to see if instruction is a call */ if (pc & 2) { ir = m[pc>>2] >> 16; } else { ir = m[pc>>2]; } if ( ((ir & 0xF0F0) == 0xF0B0) && ((ir & 0x0F00) != 0x0000)) { /* JSRS */ breakpoint = pc + 2; running = TRUE; menu(); morecycles += (cycles+recycle); cycles = -recycle; nodelay(stdscr, TRUE); return; } if ( ((ir & 0xF0F0) == 0xF030) && ((ir & 0x0F00) != 0x0000)) { /* JSR */ breakpoint = pc + 4; running = TRUE; menu(); morecycles += (cycles+recycle); cycles = -recycle; nodelay(stdscr, TRUE); return; } } /* if not JSR or JSRS, treat it as single step */ breakpoint = 0; morecycles += cycles; cycles = 0; nodelay(stdscr, TRUE); return; case 'z': /* set execution speed */ if ((number > 0)&&(number <= 131072)) { recycle = number; number = 0; shownum(); refresh(); } break; case 'q': /* quit command */ console_stop(); case 'm': /* memory dump command */ dump_addr = number; number = 0; shownum(); dump(); refresh(); break; case 't': /* toggle memory dump mode command */ if (dump_mode == DATAMODE) { dump_mode = CODEMODE; } else { dump_mode = DATAMODE; } dump(); refresh(); break; case '+': /* increment dumped memory command */ if (dump_mode == DATAMODE) { dump_addr += 0x0010UL; } else { dump_addr += 0x0008UL; } dump(); refresh(); break; case '-': /* decrement dumped memory command */ if (dump_mode == DATAMODE) { dump_addr -= 0x0010UL; } else { dump_addr -= 0x0008UL; } dump(); refresh(); break; case '?': /* help command */ which_menu++; if (which_menu >= NUM_MENUS) which_menu = 1; menu(); break; } } } xxxxxxxxxx cat > cpu.c <<\xxxxxxxxxx /* File: cpu.c Author: Douglas Jones, Dept. of Comp. Sci., U. of Iowa, Iowa City, IA 52242. Date: Mar. 6, 1996 Revised: Feb. 27, 2002 - replace BCDGET with EX3ADJ instruction Revised: Mar. 1, 2002 - change condcodes after ADDSR and ADDSRU, add SSQADJ Revised: Mar. 13, 2002 - add BTRUNC Revised: July 18, 2002 - replace *ADJ with ADJUST, recode B* branches Revised: July 22, 2002 - MOVESL added. Revised: July 25, 2002 - recode Fxxx opcodes, add LOADL, STOREC Language: C (UNIX) Purpose: Hawk instruction set emulator */ /* First, declare that this is a main program */ #define MAIN #include "bus.h" /************************************************************/ /* Declarations of machine components not included in bus.h */ /************************************************************/ static WORD irb; /* instruction register buffer */ static HALF ir; /* the instruction register */ /* ir fields */ #define OP ((ir >> 12) & 0xF) #define DST ((ir >> 8) & 0xF) #define S1 ((ir >> 4) & 0xF) #define OP1 ((ir >> 4) & 0xF) #define S2 ((ir ) & 0xF) #define SRC ((ir ) & 0xF) #define X ((ir ) & 0xF) #define OP2 ((ir ) & 0xF) #define CONST ((ir ) & 0xFF) static WORD ea; /* the effective address */ static WORD snoop; /* the snooping address (LOADL,STOREC) */ /* the following is logically part of psw, but is computationally expensive, so is not packed except when needed */ static WORD carries; /* the carry bits from the adder */ /**********************/ /* Arithmetic Support */ /**********************/ /* sign extend byte to word */ #define SXTB(x) { \ if (x & 0x00000080UL) \ x |= 0xFFFFFF00UL; \ else \ x &= 0x000000FFUL; \ } /* sign extend halfword to word */ #define SXTH(x) { \ if (x & 0x00008000UL) \ x |= 0xFFFF0000UL; \ else \ x &= 0x0000FFFFUL; \ } /* add (a macro so you can redefine it if overflow is trapped) */ #define ADDTO(x,y) x += y; /* add with carry setting condition codes */ /* here, s is the sum discounting carries into each bit position, the sign bit of tells if the signs of the operands differed, the sign bit of o asks if signs of the operands are the same and the sign of result is different, and the sign of c gives carry out of sign */ #define ADDTOCC(x,yy,cin) { \ WORD y = yy; \ WORD s = (x ^ y); \ WORD c,v; \ x += (y + (cin)); \ carries = s ^ x; \ v = ~s & (x ^ y); \ c = v ^ carries; \ psw &= ~(CC | CBITS); \ if (x & 0x80000000UL) psw |= N; \ if (x == 0x00000000UL) psw |= Z;\ if (v & 0x80000000UL) psw |= V; \ if (c & 0x80000000UL) psw |= C; \ } /* pack up the psw */ /* this puts any fields of the PSW that should be part of the word into position so inspection of the word shows nice things. The primary problem is to put carries into CBITS. */ #define PACKPSW { \ WORD srcbit = 0x00000010UL; \ WORD dstbit = 0x00000100UL; \ while (srcbit) { \ if (carries & srcbit) { \ psw |= dstbit; \ } \ srcbit <<= 4; \ dstbit <<= 1; \ } \ if (psw & C) psw |= dstbit; \ } #define UNPACKPSW { \ WORD dstbit = 0x00000010UL; \ WORD srcbit = 0x00000100UL; \ while (dstbit) { \ if (psw & srcbit) { \ carries |= dstbit;\ } \ dstbit <<= 4; \ srcbit <<= 1; \ } \ } /* set condition codes for operations not involving the adder */ #define SETCC(x) { \ psw &= ~(CC | CBITS); \ carries = 0; \ if (x & 0x80000000UL) psw |= N; \ if (x == 0x00000000UL) psw |= Z;\ /* V and C get reset */ \ } /* set C condition code for load operations that detect null bytes */ #define SETNULLS(x) { \ if (!(x & 0x000000FFUL)) { psw |= C; } \ if (!(x & 0x0000FF00UL)) { psw |= C; } \ if (!(x & 0x00FF0000UL)) { psw |= C; } \ if (!(x & 0xFF000000UL)) { psw |= C; } \ } /* condition evaluation */ #define COND(x) (cctab[psw & CC] & (1 << x)) #define T 0x0001 #define NS 0x0002 #define ZS 0x0004 #define VS 0x0008 #define CS 0x0010 #define LT 0x0020 #define LE 0x0040 #define LEU 0x0080 /* --- 0x0100 */ #define NR 0x0200 #define ZR 0x0400 #define VR 0x0800 #define CR 0x1000 #define GE 0x2000 #define GT 0x4000 #define GTU 0x8000 static unsigned int cctab[16] = { /* .... */ ( T | NR | ZR | VR | CR | GE | GT | LEU ), /* ...C */ ( T | NR | ZR | VR | CS | GE | GT | GTU ), /* ..V. */ ( T | NR | ZR | VS | CR | LT | LE | LEU ), /* ..VC */ ( T | NR | ZR | VS | CS | LT | LE | GTU ), /* .Z.. */ ( T | NR | ZS | VR | CR | GE | LE | LEU ), /* .Z.C */ ( T | NR | ZS | VR | CS | GE | LE | LEU ), /* .ZV. */ ( T | NR | ZS | VS | CR | LT | LE | LEU ), /* .ZVC */ ( T | NR | ZS | VS | CS | LT | LE | LEU ), /* N... */ ( T | NS | ZR | VR | CR | LT | LE | LEU ), /* N..C */ ( T | NS | ZR | VR | CS | LT | LE | GTU ), /* N.V. */ ( T | NS | ZR | VS | CR | GE | GT | LEU ), /* N.VC */ ( T | NS | ZR | VS | CS | GE | GT | GTU ), /* NZ.. */ ( T | NS | ZS | VR | CR | LT | LE | LEU ), /* NZ.C */ ( T | NS | ZS | VR | CS | LT | LE | LEU ), /* NZV. */ ( T | NS | ZS | VS | CR | GE | LE | LEU ), /* NZVC */ ( T | NS | ZS | VS | CS | GE | LE | LEU ) }; /********************/ /* Input Output Bus */ /********************/ static WORD input( addr ) WORD addr; { if ((addr >= DISPBASE) && (addr <= DISPLIMIT)) { return dispread( addr ); } else if ((addr >= KBDBASE) && (addr <= KBDLIMIT)) { return kbdread( addr ); } return 0xAAAAAAAA; } static void output( addr, value ) WORD addr, value; { if ((addr >= DISPBASE) && (addr <= DISPLIMIT)) { dispwrite( addr, value ); } else if ((addr >= KBDBASE) && (addr <= KBDLIMIT)) { kbdwrite( addr, value ); } } /*******************************/ /* Instruction Execution Cycle */ /*******************************/ WORD lastpc; /* the value of PC used to fetch the current instruction */ #define TRAP( vector ) { \ tpc = lastpc; \ pc = vector; \ psw &= ~OLEVEL; \ psw |= (psw >> 4) & OLEVEL; \ psw &= ~LEVEL; \ } #define FETCHW { \ if (pc >= MAXMEM) { /* fetch is illegal */ \ tma = pc; \ TRAP( BUS_TRAP ); \ } \ /* fetch is legal */ \ irb = m[(int)(pc >> 2)]; \ cycles++; \ } #define FETCH(r) { /* r = m[pc](halfword); pc += 2 */ \ if (pc & 0x2) { /* odd halfword */ \ r = irb >> 16; \ pc += 2; \ FETCHW; /* fetch next instr */ \ } else { /* even halfword */ \ r = irb & 0xFFFF; \ pc += 2; \ } \ } #define LOAD(dst) { /* setup to load from memory */ \ if (ea >= MAXMEM) { /* load outside memory */ \ if (ea < IOSPACE) { \ tma = ea; \ TRAP( BUS_TRAP ); \ FETCHW; \ continue; \ } \ dst = input( ea ); \ } else { /* load is normal */ \ dst = m[ea >> 2]; \ } \ cycles++; \ } #define STORE(src) { /* setup to store to memory */ \ if (ea == snoop) snoop |= 1; \ if (ea >= MAXMEM) { /* store outside memory */ \ if (ea < IOSPACE) { \ tma = ea; \ TRAP( BUS_TRAP ); \ FETCHW; \ continue; \ } \ output( ea, src ); \ } else if (ea < MAXROM) { /* store is illegal */\ tma = ea; \ TRAP( BUS_TRAP ); \ FETCHW; \ continue; \ } else { /* store is normal */ \ m[ea >> 2] = src; \ } \ cycles++; \ } main(argc,argv) int argc; char **argv; { powerup(argc,argv); console_startup(); cycles = 0; FETCHW; /* fetch the first 2 instructions */ for (;;) { if ((!(cycles & 0x80000000UL)) || (pc == breakpoint)) { PACKPSW; console(); } lastpc = pc; FETCH(ir); r[0] = 0UL; /* force R0 to 0 before each instr */ /*********************************** * in all of the following cases, * * normal exit is by continue, * * meaning fetch the next instr, * * while abnormal exit is by break * ***********************************/ switch (OP) { /* decode the instruction */ case 0xF: /* memory reference formats */ switch (OP1) { /* decode secondary opcode field */ case 0xF: /* MOVE */ /* DST == 0 should be illegal, may reassign */ r[0] = pc; r[DST] = r[X]; continue; case 0xE: /* MOVECC */ r[0] = pc; r[DST] = r[X]; SETCC(r[DST]); SETNULLS(r[DST]); continue; case 0xD: /* LOADS */ /* dst == 0 should be illegal, may reassign */ r[0] = pc; ea = r[X] & 0xFFFFFFFCUL; LOAD(r[DST]); continue; case 0xC: /* LOADSCC */ r[0] = pc; ea = r[X] & 0xFFFFFFFCUL; LOAD(r[DST]); SETCC(r[DST]); SETNULLS(r[DST]); continue; case 0xB: /* JSRS */ r[0] = pc; ea = r[X]; r[DST] = pc; pc = ea; FETCHW; continue; case 0xA: /* STORES */ r[0] = pc; ea = r[X] & 0xFFFFFFFCUL; r[0] = 0; STORE(r[DST]); continue; case 0x9: /* -- LOADL, LOADSCC with added snooping */ r[0] = pc; ea = r[X] & 0xFFFFFFFCUL; snoop = ea; LOAD(r[DST]); SETCC(r[DST]); SETNULLS(r[DST]); continue; case 0x8: /* -- STOREC, STORES with snoop-driven fail */ r[0] = pc; ea = r[X] & 0xFFFFFFFCUL; r[0] = 0; psw &= ~(CC | CBITS); if (ea == snoop) { STORE(r[DST]); } else { psw |= V; } continue; case 0x7: /* LEA */ /* DST == 0 should be illegal, may reassign */ FETCH(ea); SXTH(ea); r[0] = pc; ADDTO(ea,r[X]); r[DST] = ea; continue; case 0x6: /* LEACC */ FETCH(ea); SXTH(ea); r[0] = pc; ADDTOCC(ea,r[X],0); r[DST] = ea; continue; case 0x5: /* LOAD */ /* DST == 0 should be illegal? addresscheck? */ FETCH(ea); SXTH(ea); r[0] = pc; ADDTO(ea,r[X]); ea &= 0xFFFFFFFCUL; LOAD(r[DST]); continue; case 0x4: /* LOADCC */ FETCH(ea); SXTH(ea); r[0] = pc; ADDTO(ea,r[X]); ea &= 0xFFFFFFFCUL; LOAD(r[DST]); SETCC(r[DST]); SETNULLS(r[DST]); continue; case 0x3: /* JSR */ FETCH(ea); SXTH(ea); r[0] = pc; ADDTO(ea,r[X]); r[DST] = pc; pc = ea; FETCHW; continue; case 0x2: /* STORE */ FETCH(ea); SXTH(ea); r[0] = pc; ADDTO(ea,r[X]); ea &= 0xFFFFFFFCUL; r[0] = 0; STORE(r[DST]); continue; case 0x1: /* -- */ case 0x0: /* -- */ break; } /* only traps get here */ break; case 0xE: /* LIL */ /* DST == 0 should be illegal, may become new instr */ ea = CONST; SXTB(ea); FETCH(r[DST]); r[DST] |= ea << 16; continue; case 0xD: /* LIS */ /* DST == 0 should be illegal, may become new instr */ r[DST] = CONST; SXTB(r[DST]); continue; case 0xC: /* ORIS */ /* DST == 0 should be illegal, may become new instr */ r[DST] <<= 8; r[DST] |= CONST; continue; case 0xB: /* MOVESL */ /* S1 == 0 should be illegal, may become new instr */ { int shift = ((S2 - 1) & 0xF) + 1; WORD s = r[S1]; WORD c = s >> (32 - shift); /* "carry" bits */ WORD v = s >> (31 - shift); /* "sign" bits */ r[DST] = s << shift; SETCC(r[DST]); if (c & 1) psw |= C; if (v) { /* v not 0000 (shift+1 bits) */ if (((v + 1) >> (shift + 1)) == 0) { /* v not 1111 (shift+1 bits) */ psw |= V; } } } continue; case 0xA: /* ADDSL */ /* DST == 0 should be illegal, may become new instr */ { int shift = (S2 - 1) & 0xF; WORD d = r[DST]; WORD c = d & ~(0x7FFFFFFFUL >> shift); WORD vm = 0x7FFFFFFFUL >> (shift + 1); WORD v = d & ~vm; d <<= (shift + 1); ADDTOCC(d,r[S1],0); r[DST] = d; if (c) psw |= C; if (v) v = (v + vm + 1) & vm; if (v) psw |= V; } continue; case 0x9: /* ADDSR */ { int shift = ((S2 - 1) & 0xF) + 1; WORD d = r[DST]; WORD v; WORD c; WORD m = 0x8FFFFFFFUL >> (shift - 1); ADDTOCC(d,r[S1],0); v = d & ~(0xFFFFFFFFUL << shift); c = d & (0x00000001UL << (shift - 1)); d >>= shift; if (psw & N) { if (psw & V) { /* neg and ovf */ d &= m; /* make positive */ } else { /* neg and no ovf */ d |= ~m;/* make negative */ } } else { if (psw & V) { /* pos and ovf */ d |= ~m;/* make negative */ } else { /* pos and no ovf */ d &= m; /* make positive */ } } SETCC(d); r[DST] = d; if (v) psw |= V; if (c) psw |= C; } continue; case 0x8: /* ADDSRU */ { int shift = ((S2 - 1) & 0xF) + 1; WORD d = r[DST]; WORD v; WORD c; WORD m = 0x7FFFFFFFUL >> (shift - 1); ADDTOCC(d,r[S1],0); v = d & ~(0xFFFFFFFFUL << shift); c = d & (0x00000001UL << (shift - 1)); d >>= shift; d &= m; if (psw & C) { d += (m + 1); } SETCC(d); r[DST] = d; if (v) psw |= V; if (c) psw |= C; } continue; case 0x7: /* STUFFB */ /* DST == 0 should be illegal, may become new instr */ { int d = DST; int shift = ((int)(r[S2] & 3)) << 3; WORD mask = ~(0x000000FFUL << shift); r[d] = (r[d] & mask) | ((r[S1] & 0x000000FFUL) << shift); } continue; case 0x6: /* STUFFH */ /* DST == 0 should be illegal, may become new instr */ { int d = DST; int shift = ((int)(r[S2] & 2)) << 3; WORD mask = ~(0x0000FFFFUL << shift); r[d] = (r[d] & mask) | ((r[S1] & 0x0000FFFFUL) << shift); } continue; case 0x5: /* EXTB */ /* S1 == 0 should be illegal, may become new instr */ { int shift = ((int)(r[S2] & 3)) << 3; WORD src = r[S1]; WORD mask = 0xFFFFFFFFUL >> (24-shift); WORD discard = src & ~mask; WORD signs = src & ~(mask >> 1); r[DST] = (src >> shift) & 0x000000FFUL; SETCC(r[DST]); if (discard) psw |= C; if (signs) signs = ~signs & ~(mask >> 1); if (signs) psw |= V; } continue; case 0x4: /* EXTH */ /* S1 == 0 should be illegal, may become new instr */ { int shift = ((int)(r[S2] & 2)) << 3; WORD src = r[S1]; WORD mask = 0xFFFFFFFFUL >> (24-shift); WORD discard = src & ~mask; WORD signs = src & ~(mask >> 1); r[DST] = (src >> shift) & 0x0000FFFFUL; SETCC(r[DST]); if (discard) psw |= C; if (signs) signs = ~signs & ~(mask >> 1); if (signs) psw |= V; } continue; case 0x3: /* ADD */ /* S1,S2 == 0 should be illegal, may reuse */ { WORD dst = r[S1]; ADDTOCC(dst,r[S2],0); r[DST] = dst; } continue; case 0x2: /* SUB */ /* S2 == 0 should be illegal, may reuse */ { WORD dst = r[S1]; ADDTOCC(dst,~r[S2],1); r[DST] = dst; } continue; case 0x1: /* Two register format */ switch (OP1) { /* decode secondary opcode field */ case 0xF: /* TRUNC */ /* DST == 0 should be illegal, may reuse */ { int s = (SRC - 1) & 0xF; WORD m = 0xFFFFFFFFUL << s; WORD d = r[DST]; WORD g = d & m; WORD c = d & (m<<1); d &= ~(m<<1); SETCC(d); r[DST] = d; if (c) psw |= C; if (g) g = (~g) & m; if (g) psw |= V; } continue; case 0xE: /* SXT */ /* DST == 0 should be illegal, may reuse */ { int s = (SRC - 1) & 0xF; WORD m = 0xFFFFFFFFUL << s; WORD d = r[DST]; WORD g = d & m; WORD c = d & (m<<1); if (d&((~m)+1)) { /* negative */ d |= m; } else { /* positive */ d &= ~m; } SETCC(d); r[DST] = d; if (c) psw |= C; if (g) g = (~g) & m; if (g) psw |= V; } continue; case 0xD: /* BTRUNC */ /* DST == 0 should be illegal, may reuse */ { int s = ((SRC - 1) & 0xF) + 1; WORD ms = 0xFFFFFFFFUL << s; WORD d = r[DST] & ~ms; ADDTO(pc, d << 1); FETCHW; } continue; case 0xC: /* ADDSI */ /* DST == 0 should be illegal, may reuse */ { WORD src = SRC; if (src & 0x8) src |= 0xFFFFFFF0UL; ADDTOCC(r[DST], src, 0); } continue; case 0xB: /* AND */ /* SRC or DST == 0 should be illegal, reuse */ r[DST] &= r[SRC]; SETCC(r[DST]); continue; case 0xA: /* OR */ /* SRC or DST == 0 should be illegal, reuse */ r[DST] |= r[SRC]; SETCC(r[DST]); continue; case 0x9: /* EQU */ /* DST == 0 should be illegal, reuse */ r[DST] = ~(r[DST] ^ r[SRC]); SETCC(r[DST]); continue; case 0x8: /* -- */ break; case 0x7: /* ADDC */ { int nz = (psw & Z); ADDTOCC(r[DST], r[SRC], psw & C); if (nz) psw &= ~Z; } continue; case 0x6: /* SUBB */ { int nz = (psw & Z); ADDTOCC(r[DST], ~r[SRC], psw & C); if (nz) psw &= ~Z; } continue; case 0x5: /* ADJUST */ /* DST == 0 should be illegal, reuse */ { WORD src = 0; /* effective source */ switch (SRC) { /* decode source */ case 0x0: /* */ case 0x1: /* */ break; case 0x2: /* BCD */ src = (carries>>1) & 0x08888888UL; if (psw & C) src |= 0x80000000UL; src = (src >> 1)|(src >> 2); src = (~src) + 1; /* subtract 6 from digits that didn't produce carry */ break; case 0x3: /* EX3 */ src = (carries>>1) & 0x08888888UL; if (psw & C) src |= 0x80000000UL; src |= src >> 2 ; src |= ((src << 1) | 1); src ^= 0xCCCCCCCCUL; /* either add or subtract 3 to make correct excess-3 */ break; case 0x4: /* CMSB */ if (psw & C) src = 0x80000000UL; break; case 0x5: /* SSQ */ if ((psw & N) && (psw & V)) src = 0x00000001UL; break; case 0x6: /* */ case 0x7: /* */ case 0x8: /* */ case 0x9: /* */ case 0xA: /* */ case 0xB: /* */ case 0xC: /* */ case 0xD: /* */ case 0xE: /* */ case 0xF: /* */ break; } if (DST != 0) { ADDTO(r[DST],src); } } continue; case 0x4: /* -- */ case 0x3: /* -- reserved for coprocessor get */ case 0x2: /* -- reserved for coprocessor set */ break; case 0x1: /* CPUGET */ if ((psw & LEVEL) == LEVEL) { TRAP( PRIV_TRAP ); FETCHW; continue; } { WORD dst; switch (SRC) { /* decode source */ case 0x0: /* PSW */ PACKPSW; dst = psw; break; case 0x1: /* TPC */ dst = tpc; break; case 0x2: /* TMA */ dst = tma; break; case 0x3: /* TSV */ dst = tsv; break; case 0x4: /* -- */ case 0x5: /* -- */ case 0x6: /* -- */ case 0x7: /* -- */ break; case 0x8: /* CYC */ dst = cycles + morecycles; break; case 0x9: /* -- */ case 0xA: /* -- */ case 0xB: /* -- */ case 0xC: /* -- */ case 0xD: /* -- */ case 0xE: /* -- */ case 0xF: /* -- */ break; } if (DST != 0) { r[DST] = dst; } else { pc = dst; psw &= ~LEVEL; psw |= (psw << 4) & LEVEL; psw &= OLEVEL; FETCHW; } } continue; /* control never reaches here */ case 0x0: /* CPUSET */ if ((psw & LEVEL) == LEVEL) { TRAP( PRIV_TRAP ); FETCHW; continue; } switch (SRC) { /* decode terenary opcode */ case 0x0: /* PSWSET */ psw = r[DST]; UNPACKPSW; continue; case 0x1: /* TPCSET */ tpc = r[DST]; continue; case 0x2: /* TMASET */ tma = r[DST]; continue; case 0x3: /* TSVSET */ tsv = r[DST]; continue; case 0x4: /* -- */ case 0x5: /* -- */ case 0x6: /* -- */ case 0x7: /* -- */ continue; case 0x8: /* CYCSET */ morecycles = r[DST]; cycles = 0; continue; case 0x9: /* -- */ case 0xA: /* -- */ case 0xB: /* -- */ case 0xC: /* -- */ case 0xD: /* -- */ case 0xE: /* -- */ case 0xF: /* -- */ continue; } /* control never reaches here */ } /* only traps get here */ break; case 0x0: /* Bcc */ /* CONST == 0xFF should be illegal, may be reused */ if (COND(DST)) { ea = CONST; SXTB(ea); ADDTO(pc, ea << 1); FETCHW; } continue; } /* only traps get here */ tma = 0; TRAP( INSTRUCTION_TRAP ); FETCHW; } } xxxxxxxxxx cat > powerup.c <<\xxxxxxxxxx /* File: powerup.c Author: Douglas Jones, Dept. of Comp. Sci., U. of Iowa, Iowa City, IA 52242. Date: Mar. 6, 1996 Language: C (UNIX) Purpose: Hawk Emulator Power-On support; parses command line arguments and loads object file. */ #include "bus.h" #include static FILE *f = NULL; /************************************** * error diagnostic output for loader * **************************************/ static void diagnose(c) int c; /* put c to stderr for diagnostic */ { if (c < 0) { fputs("EOF", stderr); } else if (c < ' ') { putc('^', stderr); putc(c + '@', stderr); } else if (c > 0x7F) { putc('+', stderr); putc(c - 0x7F, stderr); } else { putc(c, stderr); } } static void wipeout() { fputs(" in object file **\n", stderr); exit(-1); /* error */ } /********** * loader * **********/ static WORD lc = 0UL; /* the location counter */ static WORD rb = 0UL; /* the relocation base */ static void getcheck(c) int c; /* get char from SMAL32 object file and verify that it's c */ { int ch = getc(f); if (ch != c) { fputs("** found '", stderr); diagnose(c); fputs("' where '", stderr); diagnose(ch); fputs("' expected", stderr); wipeout(); } } static WORD load_value() /* parse a load value from SMAL32 object file, up through EOL */ { int ch = getc(f); if (ch == '#') { WORD value = 0UL; ch = getc(f); do { if ((ch >= '0')&&(ch <= '9')) { value = (value << 4) | (ch - '0'); } else if ((ch >= 'A')&&(ch <= 'F')) { value = (value << 4) | (ch - ('A' - 10)); } else { fputs("** found '", stderr); diagnose(ch); fputs("' where hex digit expected", stderr); wipeout(); } ch = getc(f); } while ((ch != '\n') && (ch != '+')); if (ch == '+') { getcheck('R'); getcheck('\n'); value += rb; } else if (ch != '\n') { fputs("** found '", stderr); diagnose(ch); fputs("' where EOL expected", stderr); wipeout(); } return value; } else if (ch == ' ') { getcheck('R'); getcheck('\n'); return rb; } else { fputs("** found '", stderr); diagnose(ch); fputs("' where load value expected", stderr); wipeout(); } } static void storebyte(loc,val) WORD loc, val; /* store BYTE val in m[loc] */ { WORD a = loc >> 2; int s = (loc & 0x00000003UL) << 3; WORD w; if (loc >= MAXMEM) { fputs("** invalid load address", stderr); wipeout(); } w = m[a]; w = (w & ~(0x000000FFUL << s)) | ((val & 0x000000FFUL) << s); m[a] = w; } static void load() /* load a SMAL32 object file */ { int ch; ch = getc(f); while (ch != EOF) { if (ch == 'W') { WORD w = load_value(); storebyte(lc, w ); storebyte(lc + 1, w >> 8); storebyte(lc + 2, w >> 16); storebyte(lc + 3, w >> 24); lc += 4; } else if (ch == 'H') { WORD h = load_value(); storebyte(lc, h ); storebyte(lc + 1, h >> 8); lc += 2; } else if (ch == 'B') { WORD b = load_value(); storebyte(lc, b ); lc += 1; } else if (ch == '.') { getcheck('='); lc = load_value(); } else if (ch == 'R') { getcheck('='); getcheck('.'); getcheck('\n'); rb = lc; } else if (ch == 'S') { pc = load_value(); if (pc & 0x00000001UL) { fputs("** odd start address", stderr); wipeout(); } } else { fputs("** found '", stderr); diagnose(ch); fputs("' where load directive expected", stderr); wipeout(); } ch = getc(f); } } void powerup(argc,argv) int argc; char **argv; { int i; for (i = 1; i < argc; i++) { /* for each argument */ if (argv[i][0] == '-') { fputs("** invalid command line argument **\n", stderr); exit(-1); /* error */ } else { f = fopen(argv[i], "r"); if (f == NULL) { fputs("** cannot open object file '", stderr); fputs(argv[i], stderr); fputs("' **\n", stderr); exit(-1); /* error */ } load(); fclose(f); f = NULL; } } } xxxxxxxxxx cat > showop.c <<\xxxxxxxxxx /* File: showop.c Author: Douglas Jones, Dept. of Comp. Sci., U. of Iowa, Iowa City, IA 52242. Date: Apr. 23, 2002 Revised: July 25, 2002 - matches revisions to cpu.c Language: C (UNIX) with -lcurses option Purpose: Hawk Emulator, disassembler for HAWK opcodes */ #include "bus.h" #include /**************************** * HAWK instruction formats * ****************************/ #define ILLEGAL 0 #define LONGMEM 1 #define XLONG 2 #define SHORTMEM 3 #define XSHORT 4 #define LONGIMM 5 #define SHORTIMM 6 #define BRANCH 7 #define THREEREG 8 #define SHIFT 9 #define XSHIFT 10 #define TWOREG 11 #define XTWOREG 12 #define SPECREG 13 #define ONEREG 14 #define NOREG 15 /******************************* * disassemble one instruction * *******************************/ int showop( a ) WORD a; /* decode the opcode in m[a] and output it; returns address increment */ { char *name = NULL; /* the textual name of the instruction */ int form = ILLEGAL; /* the instruction format */ HALF ir, next = 0; /* the memory location and its successor */ /* fetch the instruction */ if (a & 2) { ir = m[a>>2] >> 16; } else { ir = m[a>>2]; } /* decode the instruciton, for its name and format */ switch ((ir >> 12) & 0xF) { case 0xF: /* memory reference formats */ switch ((ir >> 4) & 0xF) { /* decode secondary opcode field */ case 0xF: name = "MOVE "; form = SHORTMEM; break; case 0xE: if ((ir & 0x0F00) == 0) { name = "TESTR "; form = XSHORT; break; } name = "MOVECC "; form = SHORTMEM; break; case 0xD: name = "LOADS "; form = SHORTMEM; break; case 0xC: if ((ir & 0x0F00) == 0) { name = "TESTS "; form = XSHORT; break; } name = "LOADSCC "; form = SHORTMEM; break; case 0xB: if ((ir & 0x0F00) == 0) { name = "JUMPS "; form = XSHORT; break; } name = "JSRS "; form = SHORTMEM; break; case 0xA: name = "STORES "; form = SHORTMEM; break; case 0x9: name = "LOADL "; form = SHORTMEM; break; case 0x8: name = "STOREC "; form = SHORTMEM; break; case 0x7: name = "LEA "; form = LONGMEM; break; case 0x6: if ((ir & 0x0F00) == 0) { name = "CMPI "; form = XLONG; break; } name = "ADDI "; form = LONGMEM; break; case 0x5: name = "LOAD "; form = LONGMEM; break; case 0x4: if ((ir & 0x0F00) == 0) { name = "TEST "; form = XLONG; break; } name = "LOADCC "; form = LONGMEM; break; case 0x3: if ((ir & 0x0F00) == 0) { name = "JUMP "; form = XLONG; break; } name = "JSR "; form = LONGMEM; break; case 0x2: name = "STORE "; form = LONGMEM; break; case 0x1: break; case 0x0: break; } break; case 0xE: name = "LIL "; form = LONGIMM; break; case 0xD: name = "LIS "; form = SHORTIMM; break; case 0xC: name = "ORIS "; form = SHORTIMM; break; case 0xB: name = "MOVESL "; form = SHIFT; break; case 0xA: if ((ir & 0x00F0) == 0) { name = "SL "; form = XSHIFT; break; } name = "ADDSL "; form = SHIFT; break; case 0x9: if ((ir & 0x00F0) == 0) { name = "SR "; form = XSHIFT; break; } name = "ADDSR "; form = SHIFT; break; case 0x8: if ((ir & 0x00F0) == 0) { name = "SRU "; form = XSHIFT; break; } name = "ADDSRU "; form = SHIFT; break; case 0x7: name = "STUFFB "; form = THREEREG; break; case 0x6: name = "STUFFH "; form = THREEREG; break; case 0x5: name = "EXTB "; form = THREEREG; break; case 0x4: name = "EXTH "; form = THREEREG; break; case 0x3: name = "ADD "; form = THREEREG; break; case 0x2: if ((ir & 0x00F0) == 0) { name = "NEG "; form = TWOREG; break; } else if ((ir & 0x0F00) == 0) { name = "CMP "; form = XTWOREG; break; } name = "SUB "; form = THREEREG; break; case 0x1: /* Two register format */ switch ((ir >> 4) & 0xF) { /* decode secondary opcode field */ case 0xF: name = "TRUNC "; form = SPECREG; break; case 0xE: name = "SXT "; form = SPECREG; break; case 0xD: name = "BTRUNC "; form = SPECREG; break; case 0xC: name = "ADDSI "; form = SPECREG; break; case 0xB: name = "AND "; form = TWOREG; break; case 0xA: name = "OR "; form = TWOREG; break; case 0x9: if ((ir & 0xF) == 0) { name = "NOT "; form = ONEREG; break; } name = "EQU "; form = TWOREG; break; case 0x8: break; case 0x7: name = "ADDC "; form = TWOREG; break; case 0x6: name = "SUBB "; form = TWOREG; break; case 0x5: name = "ADJUST "; form = SPECREG; break; case 0x4: break; case 0x3: break; /* reserved for coprocessor */ case 0x2: break; /* reserved for coprocessor */ case 0x1: if (ir == 0x1011) { name = "RTT "; form = NOREG; break; } name = "CPUGET "; form = SPECREG; break; case 0x0: name = "CPUSET "; form = SPECREG; break; } break; case 0x0: /* Bcc */ switch ((ir >> 8) & 0xF) { /* decode condition field */ case 0xF: name = "BGTU "; form = BRANCH; break; case 0xE: name = "BGT "; form = BRANCH; break; case 0xD: name = "BGE "; form = BRANCH; break; case 0xC: name = "BCR "; form = BRANCH; break; case 0xB: name = "BVR "; form = BRANCH; break; case 0xA: name = "BNE "; form = BRANCH; break; case 0x9: name = "BNR "; form = BRANCH; break; case 0x8: break; case 0x7: name = "BLEU "; form = BRANCH; break; case 0x6: name = "BLE "; form = BRANCH; break; case 0x5: name = "BLT "; form = BRANCH; break; case 0x4: name = "BCS "; form = BRANCH; break; case 0x3: name = "BVS "; form = BRANCH; break; case 0x2: name = "BEQ "; form = BRANCH; break; case 0x1: name = "BNS "; form = BRANCH; break; case 0x0: if (ir == 0x0000) { name = "NOP "; form = NOREG; break; } name = "BR "; form = BRANCH; break; } break; } /* fetch the next locaton, if needed */ if ((form == LONGMEM) || (form == LONGIMM)) { if (a & 2) { /* ir was in the odd half */ next = m[(a + 2) >> 2] & 0xFFFFUL; } else { /* ir was in the even half */ next = (m[a >> 2] >> 16) & 0xFFFFUL; } } /* display it, depending on the format */ if (form != ILLEGAL) { addstr(name); switch (form) { case LONGMEM: if (ir & 0xF) { /* indexed */ printw("R%1X,R%1X,#%04X", (ir>>8)&0xF, ir & 0xF, next); } else { /* pc relative */ WORD dst = next; if (next & 0x8000) dst |= 0xFFFF0000UL; dst += a + 4; printw("R%1X,#%06lX", (ir>>8)&0xF, dst); } break; case XLONG: if (ir & 0xF) { /* indexed */ printw("R%1X,#%04X", ir & 0xF, next); } else { /* pc relative */ WORD dst = next; if (next & 0x8000) dst |= 0xFFFF0000UL; dst += a + 4; printw("#%06lX", dst); } break; case SHORTMEM: printw("R%1X,R%1X", (ir >> 8) & 0xF, ir & 0xF); break; case XSHORT: printw("R%1X", ir & 0xF); break; case LONGIMM: printw("R%1X,#%06X", (ir>>8)&0xF,((ir&0xFF)<<16)|next); break; case SHORTIMM: printw("R%1X,#%02X", (ir >> 8) & 0xF, ir & 0xFF); break; case BRANCH: { WORD dst = (ir & 0xFF); if (ir & 0x80) dst |= 0xFFFFFF00UL; dst = (dst << 1) + (a + 2); printw("#%06lX", dst); } break; case THREEREG: printw("R%1X,R%1X,R%1X",(ir>>8)&0xF,(ir>>4)&0xF,ir&0xF); break; case SHIFT: printw("R%1X,R%1X,#%1X",(ir>>8)&0xF,(ir>>4)&0xF,ir&0xF); break; case XSHIFT: printw("R%1X,#%1X",(ir>>8)&0xF,ir&0xF); break; case TWOREG: printw("R%1X,R%1X", (ir >> 8) & 0xF, ir & 0xF); break; case XTWOREG: printw("R%1X,R%1X", (ir >> 4) & 0xF, ir & 0xF); break; case SPECREG: printw("R%1X,#%1X", (ir >> 8) & 0xF, ir & 0xF); break; case ONEREG: printw("R%1X", (ir >> 8) & 0xF); case NOREG: break; } } else { /* illegal */ printw("#%04X", ir & 0x0000FFFFUL); } /* return instruction size */ if ((form == LONGMEM) || (form == LONGIMM) || (form == XLONG)) { return 4; } else { return 2; } } xxxxxxxxxx