/***************************************************************************/
/*                            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.                                                 */
/*                                                             */
/***************************************************************/


/* editors module */

#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
#include <curses.h>
#include "constants.h"
#include "structs.h"

extern int mcp[CONTROL_STORE_SIZE][INST_LENGTH];
extern int num_inst ;
extern int program_size ;
extern int ram[RAM_SIZE] ;
extern int current_screen ;
extern int scratch[SCRATCH_LENGTH] ;

int mcp_bits[INST_LENGTH] =  {1,2,2,2,1,1,1,1,1,4,4,4,8} ;  

extern void init_coord_array() ;
extern void dp_screen() ;
extern int pow2(int) ;
extern int read_code(FILE *, int) ;


int prog_index()
{
  int index ;
  int ok = TRUE ;
  
  while (TRUE) 
    {
      if (!ok)
		message("Bad index. Try again.") ;
      ok = TRUE ;
      move(2,13) ;
      clrtoeol() ;
      refresh() ;
      scanw("%d", &index) ;
	  /*      getch() ;  */
      ok = index <= program_size ;
      if (index == program_size) 
		program_size++ ;
      if (ok)
		return index ;
      refresh() ;
    }
}

int mcp_index()
{
  int index ;
  int ok = TRUE ;
  
  while (TRUE) 
    {
      if (!ok)
	message("Control store location out of range.") ;
      ok = TRUE ;
      move(2,18) ;
      scanw("%d", &index) ;
      ok = index <= num_inst ;
      if (index == num_inst) 
	num_inst++ ;
      if (ok)
	return index ;
    }
}

void A_edit_screen(void) 
{
  current_screen = EDITOR ;
  clear() ;
  printw("                          PROGRAM EDITOR") ;
  printw("\n\nInstruction #") ;
  printw("\nOld:") ;
  printw("\n") ;
  printw("\nNew:") ;
  printw("\n") ;
  printw("\n") ;
  printw("\n===============================================================================") ;
  printw("\nLODD x: Load direct      LODL x: Load local      POPI  : Pop indirect          ") ;
  printw("\nSTOD x: Store direct     STOL x: Store local     PUSH  : Push onto stack       ") ;
  printw("\nADDD x: Add direct       ADDL x: Add local       POPX  : Pop from stack        ") ;
  printw("\nSUBD x: Subtract direct  SUBL x: Subtract local  RETN  : Return                ") ;
  printw("\nJPOS x: Jump positive    JNEG x: Jump negative   SWAP  : Swap AC, SP           ") ;
  printw("\nJZER x: Jump zero        JNZE x: Jump not zero   INSP y: Increment SP          ") ;
  printw("\nJUMP x: Jump             CALL x: Call procedure  DESP y: Decrement SP          ") ;
  printw("\nLOCO x: Load constant    PSHI  : Push indirect                                 ") ;
  printw("\n===============================================================================") ;
  printw("\nCOMMAND:") ;
  printw("\n") ;
  printw("\n0: Return to simulator      2: Display program") ;
  printw("\n1: Edit an instruction      3. Display contents of RAM at specific location") ;
  refresh();
}

void M_edit_screen(void)
{
  current_screen = EDITOR ;
  clear() ;
  printw("                           MICROPROGRAM EDITOR") ;
  printw("\n") ;
  printw("\nMicroinstruction #") ;
  printw("\nOld:") ;
  printw("\n") ;
  printw("\n     |___|___|___|___|  |___|___|___|___|___|  |____|____|____|_________|") ;
  printw("\n       A   C   A   S      M   M   R   W   E       C    B    A    ADDR") ;
  printw("\n       M   O   L   H      B   A   D   R   N") ;
  printw("\n       U   N   U   F      R   R           C") ;
  printw("\n       X   D       T") ;
  printw("\n") ;
  printw("\n  AMUX         COND             ALU         SHIFTER      MBR, MAR, RD, WR, ENC ") ;
  printw("\n  ^^^^         ^^^^             ^^^         ^^^^^^^      ^^^^^^^^^^^^^^^^^^^^^ ") ;
  printw("\n0 = A latch  0 = No jump      0 = A + B   0 = No shift      0 = No") ;
  printw("\n1 = MBR      1 = Jump if N    1 = A & B   1 = >>            1 = Yes") ;
  printw("\n             2 = Jump if Z    2 = A       2 = <<") ;
  printw("\n             3 = Jump always  3 = ~A      3 = (not used)") ;
  printw("\n") ;
  printw("\n===============================================================================") ;
  printw("\nCOMMAND:") ;
  printw("\n") ;
  printw("\n0: Return to Simulator              2: Display microprogram") ;
  printw("\n1: Edit a microinstruction") ;
  printw("\n") ;
  refresh() ;
}

void edit_mcp(void) 
{
  int i, j, c, temp, command = 1;
  int ok;
  pair coord_array[13] ;

  init_coord_array(coord_array) ;
  M_edit_screen() ;
  while (command) 
    {
      move(19,9) ;
      clrtoeol() ;
      refresh() ;
      scanw("%d", &command) ;
      if (command == 0)
	dp_screen() ;
      else if (command == 1) 
	{
	  move(2,18) ;
	  clrtoeol() ;
	  refresh() ;
	  i = mcp_index() ;
	  move(3,4) ;
	  clrtoeol() ;
	  for (j = 0; j < INST_LENGTH; j++)
	    {
	      move(coord_array[j].r - 1, coord_array[j].c) ;
	      printw("%d", mcp[i][j]);
	      refresh() ;
	    }
	  move(coord_array[0].r, 0) ;
	  clrtoeol() ;
	  for (j = 0 ; j < INST_LENGTH; j++) 
	    {
	      ok = FALSE ;
	      while (!ok) 
		{
		  ok = TRUE ;
		  move(coord_array[j].r, coord_array[j].c) ;
		  refresh() ;
		  c = getch() ; 
		  if (c != '\n') 
		    {
		      ungetc(c, stdin) ;
		      scanw("%d", &temp) ;
		      if (temp >= pow2(mcp_bits[j])) 
			{
			  ok = FALSE ;
			  message("Bad number. Try again.") ;
			}
		      else
			mcp[i][j] = temp ;
		    }
		  else 
		    {
		      move(coord_array[j].r, coord_array[j].c) ;
		      printw("%d", mcp[i][j]) ;
		      refresh() ;
		    }
		}
	    }
	}
      else if (command == 2)  
	{
	  display_mic() ;
/*	  getch() ; */
	  if (current_screen != EDITOR)
	    M_edit_screen() ;
	}
    }
}

void edit_program(void) 
{
  int i, temp, command = 1;
  int done ;

  A_edit_screen() ;
  while (command) 
    {
      move(18,9) ;
      clrtoeol() ;
      refresh() ;
      scanw("%d", &command) ;
      if (command == 0)
	dp_screen() ;
      else if (command == 1) 
	{
	  i = prog_index() ;
	  if (i < program_size) 
	    {
	      move(4,0) ;
	      clrtoeol() ;
	      move(3,5) ;
	      clrtoeol() ;
	      print_code(i, stdout, RAM, TRUE) ;  /* old */
	      refresh() ;
	      move(6,0) ;
	      clrtoeol() ;
	      move(5,5) ;
	      clrtoeol() ;
	      refresh() ;
	      temp = read_code(stdin, TRUE) ;
	      if (temp >= pow2(16)) 
		message("Bad code.") ;
	      else
		ram[i] = temp ;
	    }
	  else
	    message("Bad index") ;
	}
      else if (command == 2)  
	{
	  display_program() ;
	  refresh() ;
	  if (current_screen != EDITOR)
	    A_edit_screen() ;
	}
      else if (command == 3) 
	display(RAM) ;
    }
}

void edit_register(void)
{
  int val, rg ;
  char str[5] ;
  int ok = TRUE ;
  
  move(22,0) ;
  clrtoeol() ;
  printw("Edit which register? ") ;
  refresh() ;
  scanw("%s", str) ;
  move(22,0) ;
  clrtoeol() ;
  refresh() ;
  if (!strcmp("PC", str))
    rg = PC ;
  else if (!strcmp("AC", str))
    rg = AC;
  else if (!strcmp("SP", str))
    rg = SP ;
  else if (!strcmp("IR", str))
    rg = IR ;
  else if (!strcmp("TIR", str))
    rg = TIR ;
  else if (!strcmp("A", str))
    rg = A_REG ;
  else 
    {
      ok = FALSE ;
      message("Illegal register.") ;
    }
  if (ok)
    {
      move(23,0) ;
      clrtoeol() ;
      printw("Old value: ") ;
      refresh() ;
      if (rg == IR)
	print_code(IR, stdout, REGS, FALSE) ;
      else if (neg(scratch[rg]))
	display_neg(scratch[rg]) ;
      else
	printw("%d", scratch[rg]); 
      refresh() ;
      move(22,0) ;
      if (rg == IR) 
	{
	  printw("Enter new instruction (assembly language): ") ;
	  val = read_code(stdin, FALSE) ;
	  if (val == pow2(16)) 
	    {
	      message("Illegal instruction.") ;
	      val = scratch[IR] ;
	    }
	}
      else 
	{
	  printw("Enter new value (decimal): ") ;
	  refresh() ;
	  scanw("%d", &val) ;
	  if (val < 0)
	    val = val & (pow2(16) - 1) ;
	}
      scratch[rg] = val ;
      data_point_update(rg) ;
      move(22,0) ;
      clrtoeol() ;
      move(23,0) ;
      clrtoeol() ;
      refresh() ;
    }
}

void edit_ram() 
{
  int temp, i ;
  
  move(22,0) ;
  clrtoeol() ;
  printw("Enter RAM location to edit: ") ;
  refresh() ;
  scanw("%d", &i) ;
  move(22,0) ;
  clrtoeol() ;
  move(23,0) ;
  if (i <= program_size) 
    {
      if (i == program_size)
	program_size++ ;
      printw("Old: ") ;
      print_code(i, stdout, RAM, FALSE) ;  /* old */
      clrtoeol() ;
      refresh() ;
      move(22,0);
      printw("New: ") ;
      temp = read_code(stdin, FALSE) ;
      refresh() ;
      if (temp >= pow2(16)) 
	message("Bad code.") ;
      else
	ram[i] = temp ;
    }
  else 
    {
      printw("Old value: %d", ((neg(ram[i]))? 
			       ram[i] & (pow2(16) - 1): ram[i])) ;
      move(22,0) ;
      clrtoeol() ;
      printw("New value: ") ;
      refresh() ;
      scanw("%d", &temp) ;
      temp = temp & (pow2(16) - 1) ;
      ram[i] = temp ;
    }
  move(22,0) ;
  clrtoeol() ;
  move(23,0) ;
  clrtoeol() ;
  refresh() ;
}
