//----------------------------------------------------------------------
// Simple microcode simulator
// W. J. Dally - 11/26/01
//----------------------------------------------------------------------
#include <Stdio.h>
#include <stdlib.h>
//----------------------------------------------------------------------
// defines for microcode assembler
//----------------------------------------------------------------------
#define MAXWORDS (1<<11)        // maximum size of microcode
#define BYTES_PER_LINE 8
//----------------------------------------------------------------------
#define PCSHIFT 3
#define CONDCOUNT 8
//------
#define OUT 0 
#define JUMP 1
//----------------------------------------------------------------------
unsigned code[MAXWORDS]	;	// microcode array
int pc = 0 ;                    // current program counter
int out = 0 ;                   // output register
int f = 0 ;
int a = 0 ; 
int b = 0 ;
int n = 0 ;                     // cycle count
//----------------------------------------------------------------------
// loads code from stdin - assumes simple hex format - 8 bytes to the line
//----------------------------------------------------------------------
void load_microcode() {
  int i, j, a, d, done ;
  FILE *fp ;
  done = 0 ;
  fp=fopen("code.txt","r") ;
  if(fp==NULL) exit(1) ;
  do {
    j = fscanf(fp,"%x",&a) ; // get address
    if((j==0) || (j == EOF)) break ;
    for(i=0;i<BYTES_PER_LINE;i++) {
      j = fscanf(fp,"%x",&d) ; // get data byte
      if(j==0) { done = 1 ; break ;}
      code[a+i] = d ;
    }
  } while(!done || !feof(fp)) ;
}
//----------------------------------------------------------------------
void reset() {
  n = f = a = b = pc = out = 0 ;
}
//----------------------------------------------------------------------
void help() {
  printf("a,b,f - toggle input, c-cycle, r-reset, ?,h-help, q-quit\n") ;
}
//----------------------------------------------------------------------
  int inst ;
  int addr ;
//----------------------------------------------------------------------
void do_addr() {
  addr = (pc<<PCSHIFT)+(f<<2)+(a<<1)+b ;
  inst = code[addr] ;
}
//----------------------------------------------------------------------
void do_cycle() {
  do_addr() ;
  if((inst>>7)&1) {
    pc = (inst & 0x7f)<<1 ;
  } else {
    out = (inst & 0x7f)<<1 ;
    pc = pc+1 ;
  }
}
//----------------------------------------------------------------------
void print_light(int x) {
  switch(x) {
  case 0 : printf("___") ; break ;
  case 1 : printf("R  ") ; break ;
  case 2 : printf("Y  ") ; break ;
  case 3 : printf("RY ") ; break ;
  case 4 : printf("G  ") ; break ;
  case 5 : printf("GR ") ; break ;
  case 6 : printf("GY ") ; break ;
  case 7 : printf("GRY") ; break ;
  }
}
//----------------------------------------------------------------------
void print_state() {
  int i ;
  do_addr() ;
  printf("%2d f=%x a=%x b=%x | pc=%02x out=%02x addr=%03x inst=%02x | ",
          n,f,a,b,pc,out,addr,inst) ;
  printf("A=") ; print_light((out>>4)&7) ; 
  printf(" B=") ; print_light((out>>1)&7) ;
  // for(i=0;i<BYTES_PER_LINE;i++) printf("%02X ",code[addr+i]) ;
  printf("\n") ;
}
//----------------------------------------------------------------------
void main(){
  int done, no_print ;
  char c ;
  load_microcode() ;
  reset() ;
  help() ;
  done = 0 ; no_print = 0 ;
  do {
    if(!no_print) print_state() ;
    no_print = 0 ;
    //c = getchar() ;
    c = getc(stdin) ;
    switch(c) {
    case 'a' : a = (~a & 1) ; break ;
    case 'b' : b = (~b & 1) ; break ;
    case 'f' : f = (~f & 1) ; break ;
    case 'c' : do_cycle() ; break ;
    case 'r' : reset() ; break ;
    case 'q' : done = 1 ; break ;
    case 'h' :
    case '?' : help() ; break ;
    default: no_print = 1 ; break ; // to ignore crlf
    }
  } while(!done) ;
}
//----------------------------------------------------------------------

