///////////////////////////////////////////////////////////////////////////////
module tb();
reg clk=0; always #1 clk<=~clk;
reg en=0;
reg start=0;
reg reset=0;
wire [15:0]pc;
wire [15:0]acc;
top _(clk,en,start,reset,pc,acc);
always@(posedge clk) $strobe("pc=%3d acc=%5d",pc, acc);
initial begin
@(posedge clk); en=1; start=1;
@(posedge clk); start=0;
#120 $finish;
end
endmodule
///////////////////////////////////////////////////////////////////////////////
module memas#(parameter N=10, parameter W=16)
(clk,qA,dA,aA,asA,weA,qB,dB,aB,asB,weB);
input clk;
input [N-1:0] aA;
input [N-1:0] aB;
input [W-1:0] dA;
input [W-1:0] dB;
input asA;
input asB;
input weA;
input weB;
output reg [W-1:0] qA=0;
output reg [W-1:0] qB=0;
reg [W-1:0] ram [2**N-1:0];
reg [N-1:0] aAreg=0, aBreg=0;
wire [N-1:0] aAsel = asA ? aAreg : aA;
wire [N-1:0] aBsel = asB ? aBreg : aB;
always@(posedge clk) aAreg<=aA;
always@(posedge clk) aBreg<=aB;
always@(posedge clk) if(weA) ram[aAsel]<=dA;
always@(posedge clk) if(weB) ram[aBsel]<=dB;
always@(posedge clk) qA<=weA?dA:ram[aAsel];
always@(posedge clk) qB<=weB?dB:ram[aBsel];
integer i;
initial begin
for(i=0;i<2**N;i=i+1)ram[i]=16'h0000;
ram[0000>>1]= 100;
ram[1000>>1]= 0;
ram[1002>>1]= 1;
ram[1004>>1]= 7;
ram[1006>>1]= 1000;
ram[1008>>1]= 1002;
ram[1010>>1]= 1004;
ram[1012>>1]= 1020;
ram[10>>1]= 15<<12 | 1<<11 | 1020 | 0; //CALL R1020, 20
ram[12>>1]= 20;
ram[14>>1]= 2<<12 | 0<<11 | 1000 | 0; //LD R1000
ram[20>>1]= 5<<12 | 0<<11 | 1002 | 0; //ADD R1002
ram[22>>1]= 14<<12 | 1<<11 | 1004 | 0; //LT R1004, 20
ram[24>>1]= 20;
// ram[10>>1]= 15<<12 | 1<<11 | 1012 | 1; //CALL @R1012, 20
// ram[12>>1]= 20;
// ram[14>>1]= 2<<12 | 0<<11 | 1006 | 1; //LD @R1006
// ram[20>>1]= 5<<12 | 0<<11 | 1008 | 1; //ADD @R1008
// ram[22>>1]= 14<<12 | 1<<11 | 1010 | 1; //LT @R1010, 20
// ram[24>>1]= 20;
ram[26>>1]= 0<<12 | 1<<11 | 1020 | 1; //RET R1020
end
endmodule
///////////////////////////////////////////////////////////////////////////////
`define nop_op (cmd[4:1]==0)
`define st_op (cmd[4:1]==1)
`define ld_op (cmd[4:1]==2)
`define com_op (cmd[4:1]==3)
`define neg_op (cmd[4:1]==4)
`define add_op (cmd[4:1]==5)
`define sub_op (cmd[4:1]==6)
`define and_op (cmd[4:1]==7)
`define or_op (cmd[4:1]==8)
`define xor_op (cmd[4:1]==9)
`define asl_op (cmd[4:1]==10)
`define asr_op (cmd[4:1]==11)
`define eq_op (cmd[4:1]==12)
`define ne_op (cmd[4:1]==12)
`define gt_op (cmd[4:1]==13)
`define le_op (cmd[4:1]==13)
`define ge_op (cmd[4:1]==14)
`define lt_op (cmd[4:1]==14)
`define call_op (cmd[4:1]==15)
`define ret_op (cmd[4:0]==1)
`define jcom_op (cmd[0])
///////////////////////////////////////////////////////////////////////////////
//`define cmdJCOM (ret_op||call_op||ne_op||lt_op||le_op)
`define cmdJCOM (`jcom_op)
`define cmdA (`nop_op||`st_op||`add_op||`sub_op||`and_op||`or_op||`xor_op)
`define cmdAN (`eq_op||`ne_op)
`define cmdB (`ld_op||`add_op)
`define cmdBN (`com_op||`neg_op||`sub_op)
`define cmdINT (`gt_op||`ge_op||`lt_op||`le_op)
`define cmdASL (`asl_op)
`define cmdASR (`asr_op)
`define cmdAND (`and_op)
`define cmdOR (`or_op)
`define cmdXOR (`xor_op||`eq_op||`ne_op)
`define cmdC (`neg_op||`sub_op||`eq_op||`ne_op||`ge_op||`lt_op)
`define cmdJCMP (`eq_op||`ne_op||`gt_op||`ge_op||`lt_op||`le_op)
`define cmdCALL (`call_op)
///////////////////////////////////////////////////////////////////////////////
`define INDIR (qA[0])
`define ST (((qA>>12)&15)==1)
`define RS (((qA>>11)&31)==1)
`define LD (`ld_op||`com_op||`neg_op||`add_op||`sub_op||`and_op||`or_op||`xor_op||`asl_op||`asr_op)
`define BR (`eq_op||`ne_op||`gt_op||`le_op||`ge_op||`lt_op||`call_op)
///////////////////////////////////////////////////////////////////////////////
module top(CLOCK_50,en,start,reset,pc,acc);
input CLOCK_50;
input en;
input start;
input reset;
output [15:0]pc;
output [15:0]acc;
core#(10) _0(CLOCK_50,en,start,reset,pc,acc);
endmodule
//----------------------------------
module core#(parameter N=10)(clk,en,start,reset,pc,acc);
input clk;
input en;
input start;
input reset;
output [15:0]pc;
output [15:0]acc;
wire [15:0]qA;
wire [15:0]aA;
wire [15:0]qB;
wire [15:0]dB;
wire [15:0]aB;
wire [15:0]Y;
wire C;
wire asB;
wire weB;
wire wePC;
wire weACC;
wire [4:0]cmd;
wire [4:0] qAcmd=qA[15:11];
wire JCOM;
wire K;
memas#(N,16)_1(clk,qA,0,aA[N:1],0,0,qB,dB,aB[N:1],asB,weB);
fsm _2(clk,K,weACC,wePC,cmd,qAcmd,qA,start,en);
selB _3(JCOM,asB,weB,aB,dB,qA,Y,pc,cmd,K);
rgPC _4(clk,pc,aA,aB,C,wePC,reset,K);
rgACC _5(clk,acc,Y,0,0,weACC);
alu _6(C,Y,acc,qB,cmd,JCOM);
endmodule
//----------------------------------
module selB(JCOM,asB,weB,aB,dB,qA,Y,pc,cmd,K);
output JCOM;
output asB;
output weB;
output [15:0]aB;
output [15:0]dB;
input [15:0]qA;
input [15:0]Y;
input [15:0]pc;
input [4:0]cmd;
input K;
assign JCOM=`cmdJCOM|(K&`INDIR);
assign asB=`call_op;
assign weB=(`st_op||`call_op)|(`ST&K&~`INDIR);
assign aB=K?qA[10:0]:qA;
assign dB=`cmdCALL?pc:Y;
endmodule
//----------------------------------
module rgPC(clk,pc,aA,aB,C,wePC,reset,K);
input clk;
output [15:0]pc;
output [15:0]aA;
input [15:0]aB;
input C;
input wePC;
input reset;
input K;
reg [15:0]pc0=0;
assign pc=pc0+2;
assign aA=C?aB:pc;
always@(posedge clk)begin
if(wePC) pc0<=aA;
if(reset) pc0<=0;
end
endmodule
//----------------------------------
module rgACC(clk,acc,Y,dE,selE,weACC);
input clk;
output reg [15:0]acc=0;
input [15:0]Y;
input [15:0]dE;
input selE;
input weACC;
always@(posedge clk) if(weACC) acc<=selE?dE:Y;
endmodule
//----------------------------------
module fsm(clk,K,weACC,wePC,qcmd,cmd,qA,start,en);
input clk;
output K;
output weACC;
output wePC;
output [4:0]qcmd;
input [4:0]cmd;
input [15:0]qA;
input start;
input en;
reg [2:0]sK=0;
reg [2:0]sweACC=0;
reg [2:0]swePC=0;
reg [9:0]scmd=0;
assign K=sK[0];
assign qcmd=scmd[4:0];
assign weACC=sweACC[0];
assign wePC=swePC[0]|(K&~`INDIR);
always@(posedge clk)begin
sK<=sK>>1;
sweACC<=sweACC>>1;
swePC<=swePC>>1;
scmd<=scmd>>5;
if(K|start)begin
if(`INDIR) begin
if(`LD) sweACC[1]<=1;
if(!`ST & !`RS) scmd[9:5]<=cmd; else scmd[4:0]<=cmd;
if(`BR) sK[2]<=en; else sK[1]<=en;
if(`BR) swePC[1:0]<=3; else swePC[0]<=1;
end else begin
if(`LD) sweACC[0]<=1;
if(!`ST) scmd[4:0]<=cmd;
if(`BR) sK[1]<=en; else sK[0]<=en;
if(`BR) swePC[0]<=1;
end
end
end
endmodule
//----------------------------------
module alu(C,Y,a,b,cmd,JCOM);
output C;
output [15:0]Y;
input [15:0]a;
input [15:0]b;
input [4:0]cmd;
input JCOM;
wire [15:0]qa;
wire [15:0]qs;
wire [15:0]qb;
wire [15:0]qL;
alua _10(qa,a,cmd);
alus _11(qs,a,cmd);
alub _12(qb,qs,b,cmd);
aluL _13(qL,qa,b,cmd);
aluY _14(Y,C,qL,qb,cmd,JCOM);
endmodule
//----------------------------------
module alua(q,a,cmd);
output [15:0]q;
input [15:0]a;
input [4:0]cmd;
assign q =
`cmdA ? a :
`cmdAN ? ~a :
`cmdINT ? a ^ 'h8000 :
0;
endmodule
//----------------------------------
module alus(q,a,cmd);
output [15:0]q;
input [15:0]a;
input [4:0]cmd;
assign q =
`cmdASL ? {a[14:0], 1'b0} :
`cmdASR ? {a[15], a[15:1]} :
0;
endmodule
//----------------------------------
module alub(q,a,b,cmd);
output [15:0]q;
input [15:0]a;
input [15:0]b;
input [4:0]cmd;
assign q =
`cmdB ? b :
`cmdBN ? ~b :
`cmdINT ? b ^ 'h7FFF :
a;
endmodule
//----------------------------------
module aluL(q,a,b,cmd);
output [15:0]q;
input [15:0]a;
input [15:0]b;
input [4:0]cmd;
assign q =
`cmdAND ? a & b :
`cmdOR ? a | b :
`cmdXOR ? a ^ b :
a;
endmodule
//----------------------------------
module aluY(Y,C,a,b,cmd,JCOM);
output [15:0]Y;
output C;
input [15:0]a;
input [15:0]b;
input [4:0]cmd;
input JCOM;
wire [17:0] q = {JCOM, `cmdJCMP, a} + b + `cmdC;
assign Y=q;
assign C=q[17];
endmodule
//----------------------------------