/***************************************************************************/
/*                            DATAPATH SIMULATOR                           */
/*                                                                         */
/*                              By Emily Ezust                             */
/*                                   1993				   */
/*                                                                         */
/*                 Based on Andrew Tanenbaum's hypothetical                */
/*                   Complex Instruction Set Computer                      */
/*                                                                         */
/***************************************************************************/

/***************************************************************/
/*                                                             */
/* Copyright (c) 1995 by Emily Ezust                           */
/*                                                             */
/* This software is hereby licensed for non-commercial use     */
/* only.  It may be freely distributed but it may not be used  */
/* for monetary profit.  Commercial use of this software is    */
/* not permitted without an explicit written agreement with    */
/* the author.                                                 */
/*                                                             */
/***************************************************************/

/* Main module */

#include <stdio.h>
#include <time.h>
#include <stdlib.h>
#include "structs.h"
#include <signal.h>
#include <curses.h>
#include "constants.h"
#define getsyx(y,x)             getyx(stdscr, y, x)

int current_screen ;  /* DP, MENU, EDITOR, DISPLAY */

alu_info alu ; 
int mcp[CONTROL_STORE_SIZE][INST_LENGTH] ;  /* microprogram */
int mc ;   /* microprogram counter */

/* number of bits for each of the INST_LENGTH ints in an instruction */

int ram[RAM_SIZE] ;

int error_found = FALSE ;

int program_size = 0 ;

int scratch[SCRATCH_LENGTH] ;
/* contains registers PC AC SP IR TIR 0 +1 -1 AMASK SMASK A MAR MBR
   and also room for ALU inputs and SHIFTER inputs: ALU-A ALU-B ALU
   SHIFTER */

int mir[INST_LENGTH] ;  /* memory instruction register */

point screen[24][80] ;  /* contains screen information and directions
			   for data flow */

char microcode[MAX_MICROCODE_SIZE][MAX_PSEUDOINST_LENGTH] ;

screg screen_regs[NUM_DATA_POINTS] ;  
/* contains coordinates for on-screen information about contents 
   of registers PC AC SP IR TIR AMK SMK A MAR MBR MIR,
   value in mc, current ALU function, current state of N or
   Z bits (only one is asserted at one time), and the current 
   SHIFTER function.
   Also contains a pointer to where the data is stored (except for
   the last three, which are not updated automatically but rather only
   in special circumstances). 
   NOTE: We recycle PC through MBR constants, not using ZERO, ONE or
   NEG_ONE.*/

int num_inst = 0 ; /* number of microinstructions in microprogram (mcp) */

int rd_asserted = FALSE; /* in conjunction with mem_read(), this keeps 
			    track of whether RD has been asserted. */

int wr_asserted = FALSE ;  /* in conjunction with mem_write(), this keeps
			      track of whether WR has been asserted. */

/* Converting table: Assembly language to Mac-1 decimal and vice versa.
   alpha contains the assembly language mnemonic; numeric contains alpha's
   equivalent Mac-1 decimal opcode. 
   The values are initialized in init_ct. 
   Note "POPX" is used instead of Tanenbaum's instruction "POP". */

table_entry ct[23] = 
{
  {"LODD", 0, 4}, {"STOD", 0, 4}, {"ADDD", 0, 4}, {"SUBD", 0, 4},
  {"JPOS", 0, 4}, {"JZER", 0, 4}, {"JUMP", 0, 4}, {"LOCO", 0, 4},
  {"LODL", 0, 4}, {"STOL", 0, 4}, {"ADDL", 0, 4}, {"SUBL", 0, 4},
  {"JNEG", 0, 4}, {"JNZE", 0, 4}, {"CALL", 0, 4}, {"PSHI", 0, 16}, 
  {"POPI", 0, 16}, {"PUSH", 0, 16}, {"POPX", 0, 16}, {"RETN", 0, 16},
  {"SWAP", 0, 16}, {"INSP", 0, 8}, {"DESP", 0, 8} 
} ;

int M_DELAY = 200 ;
int H_DELAY = 100000 ;
int DELAY = 50000 ;

/* external prototypes */
 /* init.c */
extern void init_screen() ;
extern void init_ct() ;
extern void init_scregs() ;
extern void init_alu() ;
extern void init_pseudo(void) ;


 /* file.c */
extern void load_mic(void) ;
extern void load_program(void) ;
extern void save_mic(void) ;
extern void save_program(void) ;

 /* edit.c */
extern void edit_mcp(void) ;
extern void edit_program(void) ;
extern void edit_register(void) ;
extern void edit_ram(void) ;
 
 /* display.c */
extern void display(int) ;
extern int display_program(void) ;
extern int display_mic(void) ;
extern void display_neg(int) ;
extern void print_code(int, FILE *, int, int) ;
extern void dp_screen(void) ;
extern void menu_screen(void) ;

/* internal prototypes */

void choice_prompt(void) ;
int get_choice(void) ;
void dp_screen(void) ;
void screen_update(void) ;
void data_point_update(int) ;
void update_Data(int) ;
void reset_alu(void) ;
void delay(double) ;
void get_inst(void) ;
void execute_choice(int) ;
void run(int, int) ;
void follow_path(int, int, int, int) ;
void configure();
int row(int, int) ;
int col(int, int) ;
int pow2(int) ;
int nth_bit(int, int, int) ;
int mem_read(void) ;
int mem_write(void) ;
void access_alu(void) ;
void access_shifter(void) ;
void highlight(int, int) ;
void incr_mpc(void) ;
void print_mir() ;
void al_to_mic(char [], int) ;
int read_code(FILE *, int) ;
int table_search_alpha(char []) ;
int table_search_numeric(int) ;
int neg(int) ;
   
main()
{
  int c, i ;
  FILE *fp ;
  int biff_chr, mesg_chr ;

/* some initializations */
  scratch[ZERO] = 0 ;
  scratch[NEG_ONE] = -1 ;
  scratch[ONE] = 1 ;
  scratch[AMASK] = pow2(12) - 1 ;
  scratch[SMASK] = pow2(8) - 1;
  scratch[SP] = DEFAULT_SP ;
  init_alu() ;
  init_screen() ;
  init_scregs() ;
  init_ct() ;
  initscr() ;
  crmode() ;
  signal(SIGINT, exit) ;
  dp_screen() ;
  c = get_choice() ;
  while (c != 99)
    {
      if (current_screen != DP && (c == 5 || c == 6 || c == 3))
	dp_screen() ;
      execute_choice(c) ;
      c = get_choice() ;
    } 

  endwin() ;
  exit(0) ;
}


void choice_prompt() 
{
  move(20,56) ;
  printw("Choice: ") ;
  move(21,56) ;
  printw("0 for menu") ;
  move(20,64) ;
  refresh() ;
}

int get_choice(void)
{
  int bad_choice = FALSE;
  int done = FALSE ;
  int ret ;
 
  while (!done) 
    {
      if (bad_choice) 
		{
		  move(21,56) ;
		  printw("Bad choice. Try again. ") ; 
		  printw("\n") ;
		  move(21,56) ;
		  refresh() ;
		  delay(M_DELAY) ;
		  clrtoeol() ;
		  refresh() ;
		}
      choice_prompt() ;
      scanw("%d", &ret) ;
      bad_choice = ((ret < 0 || ret > 18) && (ret != 99));
      done = !bad_choice ;
    }
  move(20,56) ;
  clrtoeol() ;
  printw("\n") ;
  move(21,56) ;
  clrtoeol() ;
  printw("\n") ;
  refresh() ;
  return ret ;
}

void screen_update() 
{
  int i;
  
  for (i = PC; i < NUM_DATA_POINTS; i++)
    if (i < ZERO || i > NEG_ONE)
      data_point_update(i) ;
}

void data_point_update(int dp)
/* updates a data point onscreen */
{
  int data ;
  
  move(screen_regs[dp].coords->r, screen_regs[dp].coords->c) ;
  if (dp == IR) 
    {
      print_code(IR, stdout, REGS, FALSE) ;
      printw("      ") ;
    }
  else if (dp <= MBR)
    {
      data = scratch[dp] ;
      if (neg(data))
	display_neg(data) ;
      else 
       printw("%-6d", data) ;
    }
  else 
    switch(dp)
      {
      case SCREEN_MIR:
	print_mir() ;
	break;
      case SCREEN_MPC:
	printw("%-6d", mc) ;
	break ;
      case SCREEN_ALU_F:
	switch(*(alu.F)) 
	  {
	  case 0:
	    printw("+") ;
	    break ;
	  case 1:
	    printw("&") ;
	    break ;
	  case 2:
	    printw(" ") ;
	    break ;
	  case 3:
	    printw("~") ;
	  }
	break;
      case SCREEN_ALU_NZ:
	if (alu.Z)
	  printw("z") ;
	else if (alu.N)
	  printw("n") ;
	else printw("+") ;
	break;
      case SCREEN_SHIFTER:
	switch(mir[SH_IND]) 
	  {
	  case 0:
	    printw("==") ;
	    break ;
	  case 1:
	    printw(">>") ;
	    break ;
	  case 2:
	    printw("<<") ;
	  }
      }
}

void update_Data (int Data) 
{
  move(12, 61) ;
  if (neg(Data))
    display_neg(Data) ;
  else 
    printw("%-9d", Data) ;
  refresh() ;
}


void reset_alu(void) 
{
  alu.Z = FALSE ;
  alu.N = FALSE ;
}

void delay(double c) 
{
  clock_t a, b ;

  if (c == M_DELAY)
    system("sleep 3") ;
  else
    {
      a = b = clock() ;
      while (b <= a + c)
	b = clock() ;
    }
}



void get_inst(void) 
{
  /* This function gets the next microinstruction (thirteen integers)
     from the control store and puts it in array mir */

  int *a = &mcp[mc][0] ;
  int i ;

  for (i = 0; i < INST_LENGTH; i++)
    mir[i] = a[i] ;
}


void execute_choice(int choice) 
{
  switch (choice) 
    {
    case 0: /* show menu */
      if (current_screen != MENU)
	menu_screen() ;
      break;
    case 1: /* edit/enter machine-lang */
      edit_program() ; 
      break ;
    case 2: /* edit/enter microcode */
      edit_mcp() ; 
      break;
    case 3: /* edit contents of a register */
      edit_register() ; 
      break ;
    case 4: /* edit contents of ram */
      edit_ram() ; 
      break ;
    case 5: /* runs */
    case 6:
    case 7:
      if (num_inst == 0 && program_size == 0)
	message("You must load the program and the microprogram first.") ;
      else if (num_inst == 0)
	message("You must load the microprogram first.") ;
      else if (program_size == 0)
	message("You must load the program first.") ;
      else
	if (choice == 5) 
	  {
	    message("Running in slow motion.") ; 
	    run(TRUE, program_size) ;
	  }
	else if (choice == 6)
	  {
	    message("Running at full speed.") ; 
	     run(FALSE, program_size) ;
	  }
	else 
	  {
	    int val, c;
	    
	    move(22,0) ;
	    printw("Break point: ") ;
	    scanw("%d", &val) ;
	    move(22,0) ;
	    clrtoeol() ;
	    printw("Run at full or slow speed [f/s]? ") ;
	    c = getch() ;
	    refresh() ;
	    move (22,0) ;
	    clrtoeol() ;
	    dp_screen() ;
	    if (c == 's')
	      {
		message("Running in slow motion.") ; 
		run(TRUE, val) ;
	      }
	    else if (c == 'f') 
	      {
		message("Running at full speed.") ; 
		run(FALSE, val) ;
	      }
	    else
	      message("Invalid choice.")  ;
	  }
      break ;
    case 8: /* display RAM */
      display(RAM) ;
      break ;
    case 9: /* load microprogram from specified file */
      load_mic() ;
      break;
    case 10: /* display microprogram */
      display_mic() ;
      break ;
    case 11: /* save microprogram */
      save_mic() ;
      break;
    case 12: /* unload microprogram */
      num_inst = 0 ;
      message("Microprogram Unloaded.") ;
      break ;
    case 13: /* load program from specified file */ 
      load_program() ;
      break;
    case 14: /* display program */
      display_program() ;
      break ;
    case 15: /* save program */
      save_program() ;
      break ;
    case 16: /* unload program */
      program_size = 0 ;
      message("Program unloaded.") ;
      break ;
    case 17: /* refresh screen */
      dp_screen() ;
      break;
    case 18: /* configure */
      configure() ;
      break;
    case 99:
      break;
    }
}

void run(int flag, int final) 
/* if flag is TRUE, reduced speed. */
{
  int r1, c1, r2, c2 ;

  screen_update() ;
  if (scratch[PC] == final)
    message("Reset PC to where you wish to start and try again.") ; 
  else 
    {
      for (mc = 0; mc < num_inst && scratch[PC] <= final; incr_mpc())
	{ 
	  reset_alu() ;
	  data_point_update(SCREEN_MPC) ;
	  get_inst() ;    /* load mir */
	  data_point_update(SCREEN_MIR) ;
	  r1 = row(mir[B_BUS_IND], TRUE) ; /* internal */
	  c1 = col(mir[B_BUS_IND], 1) ;
	  if (mir[AMUX_IND])  /* from MBR */
	    {
	      r2 = row(MBR, TRUE) ;  /* internal */
	      c2 = col(MBR, 0) ;
	    }
	  else
	    {
	      r2 = row(mir[A_BUS_IND], TRUE) ;
	      c2 = col(mir[A_BUS_IND], 0) ;
	    }
	  follow_path(r1, c1, 0, flag) ;  /* follow B bus */
	  follow_path(r2, c2, 0, flag) ;  /* follow A bus or MBR */
	  if (mem_write())
	    {
	      follow_path(row(MAR, FALSE), col(MAR, 0), 0, flag) ;
	      follow_path(row(MBR, FALSE), col(MBR, 0), 0, flag) ;
	    }
	  else if (mem_read()) 
	    follow_path(21, 54, 0, flag) ;
	}  
      message("Done.") ;       
      refresh() ;
    }
}

void follow_path(int r, int c, int Data, int flag)
{
  if (flag && screen[r][c].highlights)
    highlight(r, c) ;
  if (screen[r][c].store_data)     /* change scratchpad */
    {
      *screen[r][c].reg_ptr = Data & (pow2(16) - 1) ;
      if (screen[r][c].reg_ptr == &scratch[MAR]) 
	scratch[MAR] = scratch[MAR] & (pow2(12) - 1) ;   /* MAR only 12 bits */
      data_point_update(screen[r][c].screg_index) ;
    }
  switch (screen[r][c].circ) 
    {
    case 1:
      access_alu() ;
      data_point_update(SCREEN_ALU_NZ) ;
      break;
    case 2:
      access_shifter() ;
      break;
    case 3:   
      Data = ram[scratch[MAR]] ;
    if (flag)
	message2("Reading from memory: ", ram[scratch[MAR]], "") ;
      update_Data(Data) ;
      break ;
    case 4:
      ram[scratch[MAR]] = Data ;
      if (flag)
	message("Writing to memory.") ; 
    }
  if (screen[r][c].data_changes)    /* look at scratchpad */ 
    {
      Data = *screen[r][c].reg_ptr ;
      update_Data(Data) ;
    }
  move(r, c) ;
  addch('D') ;
  refresh() ;
  move(r, c) ;
  if (flag)
    delay(DELAY) ;
  addch(screen[r][c].chr) ;
  refresh() ;
  if (screen[r][c].take_both_paths)
    {
      follow_path(screen[r][c].next->r, screen[r][c].next->c, Data, flag) ;
      follow_path(screen[r][c].alt->alt->r, screen[r][c].alt->alt->c, 
		  Data, flag) ;
    }
  else if (screen[r][c].alt != NULL && 
	  (screen[r][c].alt->match == mir[screen[r][c].alt->inst_ind]))
    follow_path(screen[r][c].alt->alt->r, screen[r][c].alt->alt->c,
		Data, flag) ;
  else if (screen[r][c].next != NULL)
    follow_path(screen[r][c].next->r, screen[r][c].next->c, Data, flag) ;
}

void configure(void)
{
  move(23,0) ;
  clrtoeol() ;
  printw("Old value: %d", DELAY) ;
  move(22,0) ;
  printw("Enter new value for D's delay (in datapath): ") ;
  refresh() ;
  scanw("%d", &DELAY) ;
  move(22,0) ;
  clrtoeol() ;
  move(23,0) ;
  clrtoeol() ;
  refresh() ;
}

int row(int rg, int internal)
{
  /* internal: 1 if data will remain in CPU;
               0 if data will leave CPU (for example, when WR
	       is asserted, data will leave MBR and the CPU.*/

  if (!internal && (rg == MBR || rg == MAR))
    return 17 ;
  else if (rg == MBR)
    return 16;
  else
    return 10 ;
}

int col(int rg, int bus)
{
  /* bus: 0 = A
          1 = B 
	  2 = C */

  if (rg == MBR)
    return 52 ;
  else if (rg == MAR)
    return 50 ;
  else if (bus == 1) 
    switch(rg) 
      {
      case PC:
	return 5;
      case AC:
	return 9;
      case SP:
	return 13;
      case IR:
	return 17;
      case TIR:
	return 21;
      case ZERO:
	return 25;
      case ONE:
	return 29; 
      case NEG_ONE:
	return 33;
      case AMASK:
	return 37;
      case SMASK:
	return 41;
      case A_REG:
	return 45;
      }
  else if (bus == 0)
    switch(rg) 
      {
      case PC:
	return 3;
      case AC:
	return 7;
      case SP:
	return 11;
      case IR:
	return 15;
      case TIR:
	return 19;
      case ZERO:
	return 23;
      case ONE:
	return 27; 
      case NEG_ONE:
	return 31;
      case AMASK:
	return 35;
      case SMASK:
	return 39;
      case A_REG:
	return 43;
      }
  else  /* C bus */
    switch(rg)
      {
      case PC:
	return 4;
      case AC:
	return 8;
      case SP:
	return 12;
      case IR:
	return 16;
      case TIR:
	return 20;
      case ZERO:
	return 24;
      case ONE:
	return 28; 
      case NEG_ONE:
	return 32;
      case AMASK:
	return 36;
      case SMASK:
	return 40;
      case A_REG:
	return 44;
      }
  message("Error. col called with impossible value") ; 
  exit(0) ;
}

int pow2(int n) 
{
  int i ;
  int ret = 1;
    
  for (i = 1; i <= n; i++)
    ret *= 2 ;

  return ret ;
}
int nth_bit(int num, int n, int lim) 
{
  int mask = pow2(lim - n) ;
  return ( (mask & num)? 1 : 0) ;
}

int mem_read(void)
/* returns true if it is time to make a memory_read */
{
  if (mir[RD_IND])
    if (rd_asserted == TRUE)
      {
	rd_asserted = FALSE ;
	return TRUE ;
      }
    else 
      {
	rd_asserted = TRUE ;
	return FALSE ;
      }
  rd_asserted = FALSE ;
  return FALSE ;
}

int mem_write(void)
/* returns true if it is time to make a memory write */
{
  if (mir[WR_IND])
    if (wr_asserted == TRUE)
      {
	wr_asserted = FALSE ;
	return TRUE ;
      }
    else 
      {
	wr_asserted = TRUE ;
	return FALSE ;
      }
  wr_asserted = FALSE ;
  return FALSE ;
}

void access_alu(void) 
{
  int anti_mask = pow2(16) - 1 ;
  

  switch(*(alu.F))
    {
    case 0:      /* sum */
      scratch[ALU] = scratch[ALU_A] + scratch[ALU_B] ;
      break;
    case 1:      /* bitwise AND */
      scratch[ALU] = scratch[ALU_A] & scratch[ALU_B] ;
      break ;
    case 2:
      scratch[ALU] = scratch[ALU_A] ;
      break ;
    case 3:
      scratch[ALU] = (~scratch[ALU_A]) & anti_mask ;
    } ;
  alu.Z = (scratch[ALU] == 0) ;
  alu.N = ((scratch[ALU] & pow2(15)) == 0? FALSE: TRUE) ;
}

void access_shifter() 
{
  int anti_mask = pow2(16) - 1 ;

  switch (mir[SH_IND]) 
    {
    case 0:
      break ;
    case 1:
      scratch[SHIFTER] = (scratch[SHIFTER] >> 1) & anti_mask ;
      
      break ;
    case 2:
      scratch[SHIFTER] = (scratch[SHIFTER] << 1) & anti_mask ;
      break ;
    case 3:    /* not used */
      break ;
    }
}

void highlight(int r, int c) 
{
  plist *trav ;
  int i, j ;

  standout() ;
  for (trav = screen[r][c].highlights; trav != NULL; trav = trav->next) 
    {
      i = trav->coords->r ;
      j = trav->coords->c ;
      move(i, j) ;
      addch(screen[i][j].chr) ;
    }
  refresh() ;
  delay(H_DELAY) ;
  standend() ;
  for (trav = screen[r][c].highlights; trav != NULL; trav = trav->next) 
    {
      i = trav->coords->r ;
      j = trav->coords->c ;
      move(i, j) ;
      addch(screen[i][j].chr) ;
    }
  refresh() ;
  move(r,c) ;
  refresh() ;
}  

void incr_mpc()
{
  int cond = mir[COND_IND] ;
  
  if ((cond == 1 && alu.N) ||
      (cond == 2 && alu.Z) ||
      (cond == 3))  
    mc = mir[ADDR_IND] ; 
  else 
    mc++ ;
}

void print_mir() 
{
  int i, x, y;
  
  printw("%s", microcode[mc]) ;
  getsyx(y, x);
  for (i = x; i < 50; i++)
    printw(" ") ;
  if (x >= 50)
    for (i = 50; i <= x; i++)
      printw("%c", screen[y][i].chr) ;
}

void al_to_mic(char op[], int addr) 
{
  if (!strcmp(op, "LODD"))
    printw("ac := ram[%d]", addr) ;
  else if (!strcmp(op, "STOD"))
    printw("ram[%d] := ac", addr) ;
  else if (!strcmp(op, "ADDD"))
    printw("ac := ac + ram[%d]", addr) ;
  else if (!strcmp(op, "SUBD"))
    printw("ac := ac - ram[%d]", addr) ;
  else if (!strcmp(op, "JPOS"))
    printw("if ac >= 0 then pc := %d", addr) ;
  else if (!strcmp(op, "JZER"))
    printw("if ac == 0 then pc := %d", addr) ;
  else if (!strcmp(op, "JUMP"))
    printw("pc := %d", addr) ;
  else if (!strcmp(op, "LOCO"))
    printw("ac := %d", addr) ;
  else if (!strcmp(op, "LODL"))
    printw("ac := ram[sp + %d]", addr) ;
  else if (!strcmp(op, "STOL"))
    printw("ram[sp + %d] := ac", addr) ;
  else if (!strcmp(op, "ADDL"))
    printw("ac := ac + ram[sp + %d]", addr) ;
  else if (!strcmp(op, "SUBL"))
    printw("ac := ac - ram[sp + %d]", addr) ;
  else if (!strcmp(op, "JNEG"))
    printw("if ac < 0 then pc := %d", addr) ;
  else if (!strcmp(op, "JNZE"))
    printw("if ac != 0 then pc := %d", addr) ;
  else if (!strcmp(op, "CALL"))
    printw("sp := sp - 1; ram[sp] := pc; pc := %d", addr) ;
  else if (!strcmp(op, "PSHI"))
    printw("sp := sp - 1; ram[sp] := ram[ac]") ;
  else if (!strcmp(op, "POPI"))
    printw("ram[ac] := ram[sp]; sp = sp + 1") ;
  else if (!strcmp(op, "PUSH"))
    printw("sp := sp - 1; ram[sp] := ac") ;
  else if (!strcmp(op, "POPX"))
    printw("ac := ram[sp]; sp := sp + 1") ;
  else if (!strcmp(op, "RETN"))
    printw("pc := ram[sp]; sp := sp + 1") ;
  else if (!strcmp(op, "SWAP"))
    printw("a := ac; ac := sp; sp := a") ;
  else if (!strcmp(op, "INSP"))
    printw("sp := sp + %d", addr) ;
  else if (!strcmp(op, "DESP"))
    printw("sp := sp - %d", addr) ;
  else
	{
	  char msg[100];
	  sprintf(msg, "Error in translation of `%s' and `%d'.", op, addr);
	  message(msg) ; 
	}
}

int read_code(FILE *fp, int translate)  
     /* returns 2^16 if bad input 
	returns 2^17 if no input */
{
  int i = 0, addr = 0;
  char temp[5] ;
  int c ;

  if (fp == stdin)
    for (temp[i++] = getch() ; i < 4 && !(temp[i] == '\n'); i++)
      temp[i] = getch() ;
  else
    for (i = 0; i < 4 && !feof(fp); i++) 
      temp[i] = getc(fp) ;
  if (i < 4)
    return pow2(17) ;
  temp[i] = '\0' ;
  i = table_search_alpha(temp) ;
  if (i < NUM_CODES) 
    {
      if (ct[i].num_bits < 16) 
	{
	  if (fp == stdin)
	    scanw("%d\n", &addr) ;
	  else {
	    fscanf(fp, "%d", &addr) ;
	    while (! ((c = getc(fp)) == '\n' || c == EOF)) ;  
	  }
	  if ((!strcmp(temp, "DESP") || !strcmp(temp, "INSP")) &&
	      addr > 255) 
	    {
	      message("Constant out of range.") ; 
	      return pow2(16) ;
	    }
	  if (addr >= pow2(12)) 
	    {
	      message("Address out of range.") ; 
	      return pow2(16) ;
	    }
	}
      else 
        while (! ((c = getc(fp)) == '\n' || c == EOF)) ;
      if (addr < 0)
	addr = addr & (pow2(12) - 1);
      if (translate) 
	{
	  printw("Microcode equivalent: ") ;
	  al_to_mic(temp, addr) ; 
	}
      return (ct[i].code + addr) ;
    }
  else 
    {
      message("Mnemonic code not found.") ; 
      return pow2(16) ;
    }
}

int table_search_alpha(char alpha[]) 
{
  int i;

  for (i = 0; i < NUM_CODES; i++)
    if (!strcmp(ct[i].alpha, alpha)) 
      return i;
  return 99 ;
}

int table_search_numeric(int code)
{
  int i;
  
  for (i = 0; i < NUM_CODES; i++)
    if (ct[i].code == code)
      return i;
  return 99;
}

int neg(int data) 
/* returns true if the 16-bit data is negative */
{
  return (data & pow2(15)) ;
}

