// Sx microprogram simulation

#include "sx.h"
#include "sxbit.h"			// signal and rom definition

#define 	PRIVATE		static

int  TS, FP, SP, NX, FF, IR, PC, Z, S, M[MAXMEM];
int  mpc;					// micro PC
int  dbus,tbus,p1,p2,abus;  // internal bus, alu ports
int  bus,pcin;				// wires
int  clock, ninst, runflag;

// int udop[], mw[], mx[], nxt[]  are defined in sxbit.h

// IR bits
int IRop(void)  { return( IR & 255 ); } // bit 7..0
int IRarg(void)  { return( IR >> 8 ); } // signx bit 31..8

/* alu operation input : a, b
 affect condition code Z,S
 carry and overflow are not implemented

 order of operand  ts = ff op ts
 ff is the first operand !
 */
int alu(int op, int a, int b){
  int t;
  switch(op) {
  case icAdd: t = b + a; break;
  case icSub: t = b - a; break;  // ordering!
  case icMul: t = b * a; break;
  case icDiv: t = b / a; break;
  case icBand: t = b & a; break;
  case icBor: t = b | a; break;
  case icBxor: t = b ^ a; break;
  case icNot: t = ! a; break;
  case icShl: t = b << a; break;
  case icShr: t = b >> a; break;
  case icEq: t = b == a; break;
  case icNe: t = b != a; break;
  case icLt: t = b < a; break;
  case icLe: t = b <= a; break;
  case icGt: t = b > a; break;
  case icGe: t = b >= a; break;
  case icInc: t = a + 1; break;
  case icDec: t = a - 1; break;
  case FSUB: t = a - b; break;
  case FP1: t = a; break;
  case FP2: t = b; break;
  case FZ: t = a == 0; break;
  }
  if( t == 0 ) Z = 1; else Z = 0;
  if( t < 0 )  S = 1; else S = 0;
  return t;
}

// decode instruction to microprogram address
PRIVATE int udecode(void){
  int a;
  a = udop[IRop()];
  if( a == 0 )
    error("undefined opcode");
  return a;
}

// run3 is the new event-list simulator
// run event of each field
// execute one instruction (a number of microstep)
void run3(void){
  int m2, k, s;
  while(1) {
    clock++;
    m2 = nxt[mpc];
    k = mw[mpc];		// begin of each event-list
    s = mx[k];
    while( s >= 0 ){	//  for all events in one word
        switch(s){		//  for each event
        case s_x_ts: 	p1 = TS; break;
        case s_x_fp: 	p1 = FP; break;
        case s_x_sp: 	p1 = SP; break;
        case s_x_nx: 	p1 = NX; break;
        case s_y_ff: 	p2 = FF; break;
        case s_y_arg:	p2 = IRarg(); break;

        case s_alu_add: tbus = alu(icAdd,p1,p2); break;
        case s_alu_sub: tbus = alu(FSUB,p1,p2); break;
        case s_alu_inc: tbus = alu(icInc,p1,p2); break;
        case s_alu_dec: tbus = alu(icDec,p1,p2); break;
        case s_alu_z:   tbus = alu(FZ,p1,p2); break;
        case s_alu_eq:  tbus = alu(icEq,p1,p2); break;
        case s_alu_p1:  tbus = alu(FP1,p1,p2); break;
        case s_alu_p2:  tbus = alu(FP2,p1,p2); break;
        case s_alu_op:  tbus = alu(IRop(),p1,p2); break;

        case s_a_pc: 	abus = PC; break;
        case s_a_tbus:  abus = tbus; break;
        case s_d_ts:	dbus = TS; break;
        case s_d_fp:	dbus = FP; break;
        case s_mR: 	    dbus = M[abus]; break;
        case s_mW:		M[abus] = dbus; break;

        case s_b_tbus:	bus = tbus; break;
        case s_b_dbus:	bus = dbus; break;
        case s_b_pc:	bus = PC; break;
        case s_j_pc1: 	pcin = PC + 1; break;
        case s_j_pcarg: pcin = PC + IRarg(); break;
        case s_j_tbus: 	pcin = tbus; break;

        case s_lpc: 	PC = pcin; break;
        case s_lir: 	IR = dbus; break;
        case s_lts: 	TS = bus; break;
        case s_lfp:		FP = bus; break;
        case s_lsp: 	SP = bus; break;
        case s_lnx:		NX = bus; break;
        case s_lff:		FF = bus; break;

        case s_ifT: 	m2 = (Z == 0) ? m2 : mpc+1; break;
        case s_ifF: 	m2 = (Z == 1) ? m2 : mpc+1; break;
        case s_decode:	m2 = udecode(); break;
        case s_trap:	trap(IRop(),IRarg()); break;
        }
        k++;
        s = mx[k];
    }
    mpc = m2;		// next mpc
    if(mpc == 0) break;
  }
}
/*
// order of events on data path, use in "sxgen"
PRIVATE int sig[] = {
    s_x_ts, s_x_fp, s_x_sp, s_x_nx, s_y_ff, s_y_arg,
    s_alu_add, s_alu_sub, s_alu_inc, s_alu_dec, s_alu_z,
    s_alu_eq, s_alu_p1, s_alu_p2, s_alu_op,
    s_a_pc, s_a_tbus, s_d_fp, s_d_ts,
    s_mR, s_mW, s_b_dbus, s_b_tbus, s_b_pc,
    s_j_pc1, s_j_pcarg, s_j_tbus,
    s_lpc, s_lir, s_lts, s_lfp, s_lsp, s_lnx, s_lff,
    s_ifT, s_ifF, s_decode, s_trap, -1
};
*/
