/* Sx microprogram simulation

   Prabhas Chongstitvatana
   Department of Computer Engineering
   Chulalongkorn University

   17 July 98
   s2 micro mpgm sim		13 Feb 2005
   speed up 10x by event-list   9 July 2006

*/

#include "sx.h"

#define 	PRIVATE		static

char ms[MWIDTH]; 			// one word, micro store
int  mpc, here;				// micro PC

int  dbus,tbus,p1,p2,abus;  // internal bus, alu ports
int  bus,pcin;				// wires
int  clock;

sym mads[100];						// symbol for microads
int mwidth, mawidth, mcwidth, mlen;	// mpgm parameters
PRIVATE int udop[100]; 		// micro rom

int mx[MLEN][MWIDTH];		// micro event-list
int nxt[MLEN];				// next micro address

/* test current ms is set at pos */
PRIVATE int set(int pos ){
	return( ms[pos] == '1' );
}

// lookup name-val pair in mads, 0 not found
PRIVATE int lookup(char *s){
	int i;
	i = 0;
	while(mads[i].name[0] != 0){
		if( eqs(mads[i].name,s) ) return mads[i].val;
		i++;
	}
	printf("not found %s in mads\n",s);
	return 0;
}

// put micro-address into rom : udop[]
void initrom(void){
	udop[icAdd] = lookup("bop");
	udop[icSub] = lookup("bop");
	udop[icMul] = lookup("bop");
	udop[icDiv] = lookup("bop");
	udop[icBand] = lookup("bop");
	udop[icBor] = lookup("bop");
	udop[icBxor] = lookup("bop");
	udop[icNot] = lookup("uop");
	udop[icEq] = lookup("bop");
	udop[icNe] = lookup("bop");
	udop[icLt] = lookup("bop");
	udop[icLe] = lookup("bop");
	udop[icGt] = lookup("bop");
	udop[icGe] = lookup("bop");
	udop[icShl] = lookup("bop");
	udop[icShr] = lookup("bop");
	udop[icLdx] = lookup("ldx");
	udop[icStx] = lookup("stx");
	udop[icRet] = lookup("ret");
	udop[icArray] = lookup("array");
	udop[icEnd] = lookup("end");
	udop[icGet] = lookup("get");
	udop[icPut] = lookup("put");
	udop[icLd] = lookup("ld");
	udop[icSt] = lookup("st");
	udop[icLit] = lookup("lit");
	udop[icJmp] = lookup("jmp");
	udop[icJt] = lookup("jt");
	udop[icJf] = lookup("jf");
	udop[icCall] = lookup("call");
	udop[icSys] = lookup("sys");
	udop[icInc] = lookup("inc");
	udop[icDec] = lookup("dec");
}

// IR bits
int IRop(void)  { return( IR & 255 ); } // bit 7..0
int IRarg(void)  { return( IR >> 8 ); } // signx bit 31..8

/* decode instruction to microprogram address */

PRIVATE int udecode(void){
  int a;
  a = udop[IRop()];
  if( a == 0 ){
	printf("PC %d %d ", PC,IRop());
  	error("undefined opcode");
  }
  return a;
}

PRIVATE int ugoto(void){	/* decode Goto field */
  int i, a = 0, w = 1;
  for(i=mwidth-1; i>=mcwidth; i--){
	if( set(i) )   a += w;
	w += w;
  }
  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) {
	here = mpc;
    clock++;
//	if(clock > 100) break;
//	show();
	m2 = nxt[here];
	k = 0;
	s = mx[here][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[here][k];
	}
	mpc = m2;		// next mpc
	if(mpc == 0) break;
  }
}

// order of events on data path
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
};

// convert one word of ms to mx
void scan1(int a){
	int i, k, s;
	i = 0;
	k = 0;
	while( sig[i] >= 0 ){
		if( set(sig[i]) ){
		   mx[a][k] = sig[i];
		   k++;
		}
		i++;
	}
	mx[a][k] = -1;	// each word is terminated by -1
	nxt[a] = ugoto();
}

PRIVATE void showmx(int a){
	int k;
	k = 0;
	printf("mx %d: ",a);
	while( mx[a][k] >= 0 ){
		printf("%d ", mx[a][k]);
		k++;
	}
	printf("=> %d\n",nxt[a]);
}

void showmxall(void){
	int i;
	for(i=0; i<MLEN; i++)
		showmx(i);
}

