type
object REG{ uint i,v; };
array MEM uint [1024];
enum CONTROL { C_Normal, C_Pause, C_Jump, C_Halt };
object II { uint pc,ir,sr,dr; };
object IE { uint pc,sr,dr,aport,bport,imm,ex_op; bool ex_asel,mem_asel,mem_msel,wb_en,wb_dsel; };
object EM { uint dr,result,addr; bool mem_asel,mem_msel,wb_en,wb_dsel; };
object MW { uint dr,result,data; bool wb_en,wb_dsel;};
object FLAGS { bool c,z,s; };

var
uint pc,pc2,pc3;
uint k,k1,k2,op4;
MEM m;
II ii;
IE ie;
EM em;
MW mw;
bool b,b1;
CONTROL c1;
FLAGS fi,fo;
REG r0,r1,r2,r3,r4,r5,r6,r7,r8,r9,rA,rB,rC,rD,rE,rF;

place
PC uint 0; 
Registers REG r0,r1,r2,r3,r4,r5,r6,r7,r8,r9,rA,rB,rC,rD,rE,rF; r0.i=0;r1.i=1;r2.i=2;r3.i=3;r4.i=4;r5.i=5;r6.i=6;r7.i=7;r8.i=8;r9.i=9;rA.i=10;rB.i=11;rC.i=12;rD.i=13;rE.i=14;rF.i=15;
Memory MEM m; m[1]=0x401E; m[2]=0x410A; m[3]=0x3020; m[4]=0x6032; m[5]=0x3062; m[6]=0x3041; m[7]=0x1340; m[8]=0xA008; m[9]=0x1220; m[10]=0x6052; m[11]=0x1653; m[12]=0xEFFB; m[13]=0x3035; m[14]=0x3062; m[15]=0x8FF8; m[16]=0x6070; m[17]=0x7003; m[18]=0x7067; m[19]=0x1200; m[20]=0x1310; m[21]=0xBFEE; m[22]=0x0F00; m[30]=1; m[31]=9; m[32]=2; m[33]=6; m[34]=3; m[35]=4; m[36]=5; m[37]=10; m[38]=7; m[39]=8;
IF_ID  II ii;
ID_EX  IE ie;
EX_MEM EM em;
MEM_WB MW mw;
ID_Enable bool false;
EX_Enable bool false;
MEM_Enable bool false;
WB_Enable bool false;
IF_Ctrl CONTROL C_Normal;
ID_Ctrl CONTROL C_Normal;
EX_Ctrl CONTROL C_Normal;
NewPC uint 0;
Flags FLAGS fi;
MEM_FWD_ID REG r0; r0.i=-1;
MEM_FWD_EX REG r0; r0.i=-1;
WB_FWD_ID  REG r0; r0.i=-1;
WB_FWD_EX  REG r0; r0.i=-1;
transition

IF: IF_Ctrl, PC, NewPC, Memory; ID_Enable, IF_ID, PC, Memory;
C_Halt

pc2
~
C_Pause

pc2
~
c1
pc
pc2
m
c1!=C_Pause
true; if (c1==C_Jump) k=pc2; else k=pc; ii.pc=k; ii.ir=m[k]; b=(ii.ir!=0xf00);\
    ii.sr=-1; ii.dr=-1; k1=ii.ir>>8;\
    if (k1>=16&&k1<0x80) {\
      if (k1>>5==2) ii.dr=(ii.ir>>8)%16; else ii.dr=(ii.ir>>4)%16; \
      if (k1<0x12||(k1>=0x16&&k1<=0x22)||k1==0x30||k1>=0x60) ii.sr=ii.ir%16;\
    }
ii;
pc3; pc3=k+1;
m;
~~

ID: ID_Ctrl, ID_Enable, IF_ID, WB_FWD_ID, MEM_FWD_ID, Registers; EX_Enable, ID_EX, Registers; 
C_Halt
b1
ii
~
C_Pause


r2
r3
~
C_Jump
b1
ii
r2
r3


false;
ie;

~
C_Normal
false
ii
r2
r3


false;
ie;

~
C_Normal
true
ii
r2
r3

(ii.sr==-1 || ii.sr==r2.i) && (ii.dr==-1 || ii.dr==r2.i)
true;
ie; if (ii.dr==r3.i) ie.aport=r3.v; else ie.aport=r2.v;\
    if (ii.sr==r3.i) ie.bport=r3.v; else ie.bport=r2.v;\
    op4=ii.ir>>12; ie.wb_en=(op4>0&&op4<7&&ii.ir>>8!=22); ie.wb_dsel=(op4==6);\
    ie.mem_asel=(ii.ir>>13==3); ie.mem_msel=(op4==7); ie.ex_asel=ie.mem_msel; ie.ex_op=ii.ir>>8;\
    ie.sr=ii.sr; ie.dr=ii.dr; ie.pc=ii.pc;\
    if (ii.ir>>13==2) ie.imm=ii.ir%0x100; else if (op4>=8) { ie.imm=ii.ir%0x1000; if (ie.imm>=0x800) ie.imm=ie.imm-0x1000; }

~
C_Normal
true
ii
r2
r3
r0
(r0.i!=r2.i) && (ii.sr==-1 || ii.sr==r2.i || ii.sr==r0.i) && (ii.dr==-1 || ii.dr==r2.i || ii.dr==r0.i)
true;
ie; if (ii.dr==r3.i) ie.aport=r3.v; else if (ii.dr==r2.i) ie.aport=r2.v; else ie.aport=r0.v;\
    if (ii.sr==r3.i) ie.bport=r3.v; else if (ii.sr==r2.i) ie.bport=r2.v; else ie.bport=r0.v;\
    op4=ii.ir>>12; ie.wb_en=(op4>0&&op4<7&&ii.ir>>8!=22); ie.wb_dsel=(op4==6);\
    ie.mem_asel=(ii.ir>>13==3); ie.mem_msel=(op4==7); ie.ex_asel=ie.mem_msel; ie.ex_op=ii.ir>>8;\
    ie.sr=ii.sr; ie.dr=ii.dr; ie.pc=ii.pc;\
    if (ii.ir>>13==2) ie.imm=ii.ir%0x100; else if (op4>=8) { ie.imm=ii.ir%0x1000; if (ie.imm>=0x800) ie.imm=ie.imm-0x1000; }
r0;
~
C_Normal
true
ii
r2
r3
r0,r1
ii.dr==r0.i && ii.sr==r1.i && r0.i!=r2.i && r1.i!=r2.i
true;
ie; if (ii.dr==r3.i) ie.aport=r3.v; else ie.aport=r0.v;\
    if (ii.sr==r3.i) ie.bport=r3.v; else ie.bport=r1.v;\
    op4=ii.ir>>12; ie.wb_en=(op4>0&&op4<7&&ii.ir>>8!=22); ie.wb_dsel=(op4==6);\
    ie.mem_asel=(ii.ir>>13==3); ie.mem_msel=(op4==7); ie.ex_asel=ie.mem_msel; ie.ex_op=ii.ir>>8;\
    ie.sr=ii.sr; ie.dr=ii.dr; ie.pc=ii.pc;\
    if (ii.ir>>13==2) ie.imm=ii.ir%0x100; else if (op4>=8) { ie.imm=ii.ir%0x1000; if (ie.imm>=0x800) ie.imm=ie.imm-0x1000; }
r0,r1;
~~


EX: EX_Ctrl, EX_Enable, ID_EX, Flags, MEM_FWD_EX, WB_FWD_EX; IF_Ctrl, ID_Ctrl, EX_Ctrl, NewPC, MEM_Enable, EX_MEM, Flags, MEM_FWD_EX, MEM_FWD_ID;
C_Halt
b1
ie
~
C_Pause




r1

C_Normal;
C_Normal;
C_Normal;
0;
false;
em;


r2; r2.i=-1;
~
C_Jump
b1
ie

r0
r1

C_Normal;
C_Normal;
C_Normal;
0;
false;
em;

r2; r2.i=-1;
r2;
~
C_Normal
false
ie

r0
r1

C_Normal;
C_Normal;
C_Normal;
0;
false;
em;

r2; r2.i=-1;
r2;
~
C_Normal
true
ie
fi
r0
r1

c1; c1=C_Normal; if (ie.ex_op==15) c1=C_Halt; else if (ie.mem_asel) c1=C_Pause; else if (ie.ex_op>=0x80)\
    { op4=ie.ex_op>>4; if (op4==8 || op4==10&&fi.z||op4==11&&!fi.z || op4==12&&fi.c||op4==13&&!fi.c || op4==14&&fi.s||op4==15&&!fi.s) c1=C_Jump; }
c1;
c1;
pc2; pc2=ie.pc+ie.imm; k1=ie.aport; k2=ie.bport; k=0;\
    if (ie.dr!=-1) if (ie.dr==r0.i) k1=r0.v; else if (ie.dr==r1.i) k1=r1.v;\
    if (ie.sr!=-1) if (ie.sr==r0.i) k2=r0.v; else if (ie.sr==r1.i) k2=r1.v;\
    if (ie.ex_op<0x20)\
      if (ie.ex_op<0x14)\
        if (ie.ex_op<0x12)\
          if (ie.ex_op<0x11) k=k1+k2; else k=k1-k2;\
        else if (ie.ex_op<0x13) k=k1+1; else k=k1-1;\
      else if (ie.ex_op<0x16)\
             if (ie.ex_op<0x15) { k=k1/2; fo.c=k1%2; } else { k=k1*2; fo.c=k1>>15; }\
           else k=k1-k2;\
    else if (ie.ex_op<0x30)\
           if (ie.ex_op<0x22) if (ie.ex_op<0x21) k=k1&k2; else k=k1|k2;\
           else if (ie.ex_op<0x23) k=k1^k2; else k=~k1;\
         else if (ie.ex_op<0x50) if (ie.ex_op<0x40) k=k2; else k=ie.imm;\
              else if (ie.ex_op<0x60) k=ie.imm<<8; else k=k2; \
    fo.z=(k==0); fo.s=(k>>15)%2;
true;
em; em.mem_asel=ie.mem_asel; em.mem_msel=ie.mem_msel; em.wb_en=ie.wb_en; em.wb_dsel=ie.wb_dsel;\
    em.dr=ie.dr; em.result=k%0x10000; if (ie.ex_asel) em.addr=k1; else em.addr=k2;
fo;
r2; if (em.wb_en && !em.mem_asel) { r2.i=em.dr; r2.v=em.result; } else r2.i=-1;
r2;
~~

MEM: MEM_Enable, EX_MEM, Memory; WB_Enable, MEM_WB, Memory, WB_FWD_ID, WB_FWD_EX;
false
em


false;
mw;

r0; r0.i=-1;
r0;
~
true
em

!em.mem_asel
true;
mw; mw.dr=em.dr; mw.result=em.result; mw.wb_en=em.wb_en; mw.wb_dsel=em.wb_dsel;

r0; if (mw.wb_en) { r0.i=mw.dr; r0.v=mw.result; } else r0.i=-1;
r0;
~
true
em
m
em.mem_asel
true;
mw; mw.dr=em.dr; mw.result=em.result; mw.wb_en=em.wb_en; mw.wb_dsel=em.wb_dsel; if (!em.mem_msel) mw.data=m[em.addr];
m; if (em.mem_msel) m[em.addr]=em.result;
r0; if (mw.wb_en) { r0.i=mw.dr; r0.v=mw.data; } else r0.i=-1;
r0;
~~

WB: WB_Enable, MEM_WB, Registers; Registers;
false
mw
~
true
mw

!mw.wb_en
~
true
mw
r1
mw.wb_en && mw.dr==r1.i
r1; if (mw.wb_dsel) r1.v=mw.data; else r1.v=mw.result;
~~