alu coming up nicely, decoder gaining weight

This commit is contained in:
Raphael Jacquot 2019-02-14 14:35:23 +01:00
parent f076cf6fb9
commit fd69407de0
6 changed files with 465 additions and 150 deletions

View file

@ -21,19 +21,25 @@
// logic
`define ALU_OP_AND 5
`define ALU_OP_OR 6
// bit set/reset
`define ALU_OP_RST_BIT 7
`define ALU_OP_SET_BIT 8
// arithmetic
`define ALU_OP_2CMPL 7
`define ALU_OP_1CMPL 8
`define ALU_OP_INC 9
`define ALU_OP_DEC 10
`define ALU_OP_ADD 11
`define ALU_OP_SUB 12
`define ALU_OP_2CMPL 9
`define ALU_OP_1CMPL 10
`define ALU_OP_INC 11
`define ALU_OP_DEC 12
`define ALU_OP_ADD 13
`define ALU_OP_SUB 14
// tests
`define ALU_OP_TEST_EQ 13
`define ALU_OP_TEST_NEQ 14
`define ALU_OP_TEST_EQ 15
`define ALU_OP_TEST_NEQ 16
// relative jump
`define ALU_OP_JMP_REL2 15
`define ALU_OP_JMP_REL3 16
`define ALU_OP_JMP_REL2 17
`define ALU_OP_JMP_REL3 18
`define ALU_OP_JMP_REL4 19
`define ALU_OP_JMP_ABS5 20
// registers

View file

@ -23,3 +23,4 @@
2019-02-13 07:46 48 98.83MHz 13.86ns 2.92ns 241 169.41MHz 4.11ns 1.92ns
2019-02-13 14:53 51 153.35MHz 16.74ns 3.40ns 273 155.47MHz 5.53ns 2.09ns
2019-02-13 23:21 318 113.77MHz 25.44ns 13.97ns 3061 117.75MHz 9.56ns 4.08ns
2019-02-14 09:00 353 118.23MHz 26.00ns 12.28ns 3334 119.40MHz 10.08ns 3.84ns

View file

@ -3,7 +3,14 @@
`include "def-alu.v"
`define ALU_DEBUG
`ifdef SIM
// `define ALU_DEBUG_DBG
`endif
`define ALU_DEBUG 1'b0
`define ALU_DEBUG_DUMP 1'b1
`define ALU_DEBUG_JUMP 1'b0
`define ALU_DEBUG_PC 1'b0
module saturn_alu (
i_clk,
@ -14,6 +21,10 @@ module saturn_alu (
i_en_alu_init,
i_en_alu_save,
i_push,
i_pop,
i_alu_debug,
o_alu_stall_dec,
i_ins_decoded,
@ -41,6 +52,19 @@ input wire [0:0] i_en_alu_calc;
input wire [0:0] i_en_alu_init;
input wire [0:0] i_en_alu_save;
input wire [0:0] i_push;
input wire [0:0] i_pop;
input wire [0:0] i_alu_debug;
wire alu_debug;
wire alu_debug_dump;
wire alu_debug_jump;
wire alu_debug_pc;
assign alu_debug = `ALU_DEBUG || i_alu_debug;
assign alu_debug_dump = `ALU_DEBUG_DUMP || i_alu_debug;
assign alu_debug_jump = `ALU_DEBUG_JUMP || i_alu_debug;
assign alu_debug_pc = `ALU_DEBUG_PC || i_alu_debug;
output wire [0:0] o_alu_stall_dec;
input wire [0:0] i_ins_decoded;
@ -62,6 +86,42 @@ output wire [19:0] o_pc;
assign o_reg_p = P;
assign o_pc = PC;
/* internal registers */
/* copy of arguments */
reg [4:0] alu_op;
reg [4:0] reg_dest;
reg [4:0] reg_src1;
reg [4:0] reg_src2;
reg [3:0] f_start;
reg [3:0] f_last;
/* internal pointers */
reg [3:0] p_src1;
reg [3:0] p_src2;
reg p_carry;
reg [3:0] c_res1;
reg [3:0] c_res2;
reg c_carry;
/* alu status */
reg alu_run;
reg alu_done;
/*
* next PC in case of jump
*/
reg [19:0] jump_bse;
reg [19:0] jump_off;
wire [19:0] jump_pc;
assign jump_pc = (alu_op == `ALU_OP_JMP_ABS5)?jump_off:(jump_bse + jump_off);
reg [2:0] rstk_ptr;
/* public registers */
reg [19:0] PC;
reg [19:0] D0;
@ -84,12 +144,18 @@ reg [3:0] P;
reg [3:0] HST;
reg [15:0] ST;
reg [2:0] rstk_ptr;
reg [19:0] RSTK[0:7];
initial begin
// alu internal control bits
alu_op = 0;
reg_dest = 0;
reg_src1 = 0;
reg_src2 = 0;
f_start = 0;
f_last = 0;
alu_run = 0;
alu_done = 0;
// o_alu_stall_dec = 0;
@ -143,33 +209,26 @@ assign do_alu_save = (!i_reset) && i_en_alu_save && alu_run;
assign do_alu_shpc = (!i_reset) && i_en_alu_dump;
assign do_alu_pc = (!i_reset) && i_en_alu_save;
reg alu_run;
reg alu_done;
wire test_finish;
wire [3:0] f_next;
assign test_finish = f_start == f_last;
assign f_next = (f_start + 1) & 4'hF;
// the decoder may request the ALU to not stall it
assign o_alu_stall_dec = alu_run && (!i_alu_no_stall || alu_finish);
assign o_alu_stall_dec = alu_run && (!i_alu_no_stall || test_finish);
wire alu_start;
wire alu_finish;
wire [3:0] f_next;
reg [4:0] alu_op;
reg [4:0] reg_dest;
reg [4:0] reg_src1;
reg [4:0] reg_src2;
reg [3:0] f_start;
reg [3:0] f_last;
assign alu_start = f_start == 0;
assign alu_finish = f_start == f_last;
assign f_next = (f_start + 1) & 4'hF;
reg [3:0] p_src1;
reg [3:0] p_src2;
reg p_carry;
reg [3:0] c_res1;
reg [3:0] c_res2;
reg c_carry;
/*
* test things on alu_op
*/
wire is_alu_op_jump;
assign is_alu_op_jump = ((alu_op == `ALU_OP_JMP_REL3) ||
(alu_op == `ALU_OP_JMP_REL4) ||
(alu_op == `ALU_OP_JMP_ABS5));
/*
* dump all registers
@ -178,9 +237,18 @@ reg c_carry;
*/
always @(posedge i_clk) begin
if (do_reg_dump) begin
$display("ALU_DUMP 0: run %b | done %b ", alu_run, alu_done);
`ifdef ALU_DEBUG_DBG
$display("iad %b | AD %b | ad %b | ADD %b | add %b | ADJ %b | adj %b | ADP %b | adp %b",
i_alu_debug,
`ALU_DEBUG, i_alu_debug,
`ALU_DEBUG_DUMP, alu_debug_dump,
`ALU_DEBUG_JUMP, alu_debug_jump,
`ALU_DEBUG_PC, alu_debug_pc );
`endif
if (do_reg_dump && alu_debug_dump) begin
`ifdef SIM
$display("ALU_DUMP 0: run %b | done %b", alu_run, alu_done);
// display registers
$display("PC: %05h Carry: %b h: %s rp: %h RSTK7: %05h",
PC, CARRY, DEC?"DEC":"HEX", rstk_ptr, RSTK[7]);
@ -202,10 +270,14 @@ end
always @(posedge i_clk) begin
// this happens in phase 3, right after the instruction decoder (in phase 2) is finished
if (do_alu_init) begin
$display({"ALU_INIT 3: run %b | done %b | stall %b | op %d | s %h | l %h ",
"| ialu %b | dest %d | src1 %d | src2 %d"},
alu_run, alu_done, o_alu_stall_dec, i_alu_op,i_field_start, i_field_last,
i_ins_alu_op, i_reg_dest, i_reg_src1, i_reg_src2);
if (alu_debug)
$display({"ALU_INIT 3: run %b | done %b | stall %b | op %d | s %h | l %h ",
"| ialu %b | dest %d | src1 %d | src2 %d"},
alu_run, alu_done, o_alu_stall_dec, i_alu_op,i_field_start, i_field_last,
i_ins_alu_op, i_reg_dest, i_reg_src1, i_reg_src2);
jump_bse <= PC;
alu_op <= i_alu_op;
reg_dest <= i_reg_dest;
reg_src1 <= i_reg_src1;
@ -227,7 +299,7 @@ always @(posedge i_clk) begin
end
if (do_alu_calc) begin
// $display("ALU_TEST 2: tf %b | nxt %h", test_finish, f_next);
alu_done <= test_finish;
alu_done <= alu_finish;
// f_next <= (f_start + 1) & 4'hF;
end
if (do_alu_save) begin
@ -241,21 +313,28 @@ always @(posedge i_clk) begin
end
`define ALU_DEBUG
`define JUMP_DEBUG
always @(posedge i_clk) begin
if (do_alu_prep) begin
`ifdef ALU_DEBUG
$display("ALU_PREP 1: run %b | done %b | stall %b | op %d | s %h | l %h",
alu_run, alu_done, o_alu_stall_dec, alu_op, f_start, f_last);
`endif
if (alu_debug) begin
`ifdef SIM
$display("ALU_PREP 1: run %b | done %b | stall %b | op %d | s %h | l %h",
alu_run, alu_done, o_alu_stall_dec, alu_op, f_start, f_last);
`endif
end
// setup value for src1
case (alu_op)
`ALU_OP_ZERO: begin end // no source required
`ALU_OP_COPY,
`ALU_OP_JMP_REL3:
`ALU_OP_RST_BIT,
`ALU_OP_SET_BIT,
`ALU_OP_JMP_REL3,
`ALU_OP_JMP_REL4,
`ALU_OP_JMP_ABS5:
case (reg_src1)
`ALU_REG_A: p_src1 <= A [f_start*4+:4];
`ALU_REG_B: p_src1 <= B [f_start*4+:4];
@ -275,14 +354,37 @@ end
always @(posedge i_clk) begin
if (do_alu_calc) begin
`ifdef ALU_DEBUG
$display("ALU_CALC 2: run %b | done %b | stall %b | op %d | s %h | l %h | src1 %h | src2 %h | p_carry %b",
alu_run, alu_done, o_alu_stall_dec, alu_op, f_start, f_last, p_src1, p_src2, p_carry);
`ifdef SIM
if (alu_debug)
$display("ALU_CALC 2: run %b | done %b | stall %b | op %d | s %h | l %h | dest %d | src1 %h | src2 %h | p_carry %b",
alu_run, alu_done, o_alu_stall_dec, alu_op, f_start, f_last, reg_dest, p_src1, p_src2, p_carry);
if (alu_debug_jump)
$display("ALU_JUMP 2: run %b | done %b | stall %b | op %d | s %h | l %h | jbs %5h | jof %5h | jpc %5h | fin %b",
alu_run, alu_done, o_alu_stall_dec, alu_op, f_start, f_last, jump_bse, jump_off, jump_pc, alu_finish);
`endif
case (alu_op)
`ALU_OP_ZERO: c_res1 <= 0;
`ALU_OP_COPY: c_res1 <= p_src1;
`ALU_OP_JMP_REL3,
`ALU_OP_JMP_REL4,
`ALU_OP_JMP_ABS5: if (alu_start)
jump_off <= { 16'b0, p_src1 };
endcase
case (alu_op)
`ALU_OP_ZERO: c_res1 <= 0;
`ALU_OP_COPY,
`ALU_OP_RST_BIT,
`ALU_OP_SET_BIT: c_res1 <= p_src1;
`ALU_OP_JMP_REL3,
`ALU_OP_JMP_REL4,
`ALU_OP_JMP_ABS5: jump_off[f_start*4+:4] <= p_src1;
endcase
case (alu_op)
`ALU_OP_JMP_REL3: if (alu_finish)
jump_off <= { {8{p_src1[3]}}, p_src1, jump_off[7:0] };
`ALU_OP_JMP_REL4: if (alu_finish)
jump_off <= { {4{p_src1[3]}}, p_src1, jump_off[11:0] };
endcase
end
end
@ -290,10 +392,14 @@ end
always @(posedge i_clk) begin
if (do_alu_save) begin
`ifdef ALU_DEBUG
$display({"ALU_SAVE 3: run %b | done %b | stall %b | op %d | s %h | l %h |",
" res1 %h | res2 %h | c_carry %b"},
alu_run, alu_done, o_alu_stall_dec, alu_op,
f_start, f_last, c_res1, c_res2, c_carry);
if (alu_debug)
$display({"ALU_SAVE 3: run %b | done %b | stall %b | op %d | s %h | l %h |",
" dest %d | res1 %h | res2 %h | c_carry %b"},
alu_run, alu_done, o_alu_stall_dec, alu_op,
f_start, f_last, reg_dest, c_res1, c_res2, c_carry);
if (alu_debug_jump)
$display( "ALU_JUMP 3: run %b | done %b | stall %b | op %d | s %h | l %h | bse %5h | jof %5h | jpc %5h | fin %b",
alu_run, alu_done, o_alu_stall_dec, alu_op, f_start, f_last, jump_bse, jump_off, jump_pc, alu_finish);
`endif
case (alu_op)
@ -303,31 +409,49 @@ always @(posedge i_clk) begin
`ALU_REG_C: C [f_start*4+:4] <= c_res1;
`ALU_REG_D0: D0[f_start*4+:4] <= c_res1;
`ALU_REG_D1: D1[f_start*4+:4] <= c_res1;
`ALU_REG_ST: ST[f_start*4+:4] <= c_res1;
`ALU_REG_P: P <= c_res1;
endcase
`ALU_OP_RST_BIT,
`ALU_OP_SET_BIT:
case (reg_dest)
`ALU_REG_ST: ST[c_res1] <= alu_op==`ALU_OP_SET_BIT?1:0;
default:
$display("invalid register for op");
endcase
endcase
end
end
wire [19:0] next_pc;
assign next_pc = PC + 1;
assign next_pc = (is_alu_op_jump && alu_finish)?jump_pc:PC + 1;
always @(posedge i_clk) begin
if (i_reset)
PC <= ~0;
if (do_alu_shpc) begin
// if (!o_alu_stall_dec)
// $display("ALU_SHPC 0: pc %5h", PC);
`ifdef SIM
if (do_alu_shpc && alu_debug_pc) begin
if (!o_alu_stall_dec)
$display("ALU_SHPC 0: pc %5h", PC);
if (o_alu_stall_dec)
$display("ALU_SHPC 0: STALL");
end
`endif
/*
* updates the PC on phase 3 to be ready for the next
* thing to do...
*/
if (do_alu_pc) begin
// if (!o_alu_stall_dec)
// $display("ALU_PC 3: nx %5h", next_pc);
if (!o_alu_stall_dec)
`ifdef SIM
if (alu_debug_pc)
$display("ALU_PC 3: !stl %b | nx %5h | jmp %b | push %b",
!o_alu_stall_dec, next_pc, is_alu_op_jump, i_push);
`endif
if (!o_alu_stall_dec || is_alu_op_jump) begin
PC <= next_pc;
end
end
end

View file

@ -85,7 +85,10 @@ saturn_decoder m_decoder (
.i_reg_p (reg_p),
.o_inc_pc (inc_pc),
.o_push (push),
.o_pop (pop),
.o_dec_error (inv_opcode),
.o_alu_debug (alu_debug),
.o_ins_addr (ins_addr),
.o_ins_decoded (ins_decoded),
@ -112,8 +115,11 @@ saturn_decoder m_decoder (
.o_ins_alu_op (ins_alu_op)
);
wire inc_pc;
wire inv_opcode;
wire [0:0] inc_pc;
wire [0:0] push;
wire [0:0] pop;
wire [0:0] inv_opcode;
wire [0:0] alu_debug;
wire [19:0] ins_addr;
wire ins_decoded;
@ -149,6 +155,10 @@ saturn_alu m_alu (
.i_en_alu_init (en_alu_init),
.i_en_alu_save (en_alu_save),
.i_push (push),
.i_pop (pop),
.i_alu_debug (alu_debug),
.o_alu_stall_dec (alu_stall),
.i_ins_decoded (ins_decoded),
@ -184,13 +194,14 @@ reg [3:0] rom [0:2**20];
reg [3:0] rom [0:2**10];
`endif
// `define DEBUG_CLOCKS
initial
begin
`ifndef SIM
`ifdef SIM
$readmemh("rom-gx-r.hex", rom);
`else
$readmemh( "testrom-2.hex", rom);
// $readmemh( "testrom-2.hex", rom);
`endif
clk_phase = 0;
@ -207,8 +218,8 @@ initial
cycle_ctr = 0;
`ifdef DEBUG_CLOCKS
$monitor("RST %b | CLK %b | CLKP %d | CYCL %d | eRST %b | eDBG %b | eBSND %b | eBRECV %b | eAPR %b | eACALC %b | eINDC %b | eASAVE %b | eINDX %b",
reset, clk, clk_phase, cycle_ctr, en_reset,
$monitor("RST %b | CLK %b | CLKP %d | CYCL %d | PC %5h | eRST %b | eDBG %b | eBSND %b | eBRECV %b | eAPR %b | eACALC %b | eINDC %b | eASAVE %b | eINDX %b",
reset, clk, clk_phase, cycle_ctr, reg_pc, en_reset,
en_debugger, en_bus_send,
en_bus_recv, en_alu_prep,
en_alu_calc, en_inst_dec,
@ -222,13 +233,15 @@ initial
//
//--------------------------------------------------------------------------------------------------
`define PH_BUS_RECV 1
always @(posedge clk) begin
if (!reset) begin
clk_phase <= clk_phase + 1;
en_alu_dump <= clk_phase[1:0] == 0;
en_debugger <= clk_phase[1:0] == 0;
en_bus_send <= clk_phase[1:0] == 0;
en_bus_recv <= clk_phase[1:0] == 1;
en_bus_recv <= clk_phase[1:0] == `PH_BUS_RECV;
en_alu_prep <= clk_phase[1:0] == 1;
en_alu_calc <= clk_phase[1:0] == 2;
en_inst_dec <= clk_phase[1:0] == 2;
@ -253,7 +266,7 @@ always @(posedge clk) begin
en_inst_exec <= 0;
clock_end <= 0;
cycle_ctr <= ~0;
max_cycle <= 1024;
max_cycle <= 40;
`ifndef SIM
led[7:0] <= reg_pc[7:0];
`endif
@ -287,6 +300,7 @@ always @(posedge clk)
end
if (en_bus_recv) begin
if (!stalled) begin
$display("BUS_RECV %1d: [%d] %5h => %1h", `PH_BUS_RECV, cycle_ctr, reg_pc, rom[reg_pc]);
nibble_in <= rom[reg_pc];
end
end

View file

@ -23,6 +23,7 @@ module saturn_decoder(
o_push,
o_pop,
o_dec_error,
o_alu_debug,
o_ins_addr,
o_ins_decoded,
@ -74,6 +75,7 @@ output reg o_inc_pc;
output reg o_push;
output reg o_pop;
output reg o_dec_error;
output reg o_alu_debug;
// instructions related outputs
output reg [19:0] o_ins_addr;
@ -115,7 +117,7 @@ output reg o_ins_alu_op;
output reg [(21*4-1):0] o_dbg_nibbles;
output reg [4:0] o_dbg_nb_nbls;
output reg [63:0] o_mem_load;
output reg [3:0] o_mem_pos;
output reg [4:0] o_mem_pos;
/*
@ -164,7 +166,13 @@ wire is_la_hex;
wire is_lc_hex;
wire disp_nb_nibbles;
assign p_is_dest = (o_reg_dest == `ALU_REG_P);
assign is_load_imm = (o_alu_op ==`ALU_OP_COPY) && (o_reg_src1 == `ALU_REG_IMM);
assign is_load_imm = ((o_alu_op == `ALU_OP_COPY) ||
(o_alu_op == `ALU_OP_RST_BIT) ||
(o_alu_op == `ALU_OP_SET_BIT) ||
(o_alu_op == `ALU_OP_JMP_REL3) ||
(o_alu_op == `ALU_OP_JMP_REL4) ||
(o_alu_op == `ALU_OP_JMP_ABS5))
&& (o_reg_src1 == `ALU_REG_IMM);
assign is_d0_eq = is_load_imm && (o_reg_dest == `ALU_REG_D0);
assign is_d1_eq = is_load_imm && (o_reg_dest == `ALU_REG_D1);
assign is_p_eq = is_load_imm && p_is_dest;
@ -204,38 +212,52 @@ always @(posedge i_clk) begin
end
if (o_ins_alu_op) begin
case (o_reg_dest)
`ALU_REG_A: $write("A");
`ALU_REG_B: $write("B");
`ALU_REG_C:
if (is_lc_hex) $write("LCHEX");
else $write("C");
`ALU_REG_D: $write("D");
`ALU_REG_D0: $write("D0");
`ALU_REG_D1: $write("D1");
`ALU_REG_RSTK: $write("RSTK");
`ALU_REG_R0: $write("R0");
`ALU_REG_R1: $write("R1");
`ALU_REG_R2: $write("R2");
`ALU_REG_R3: $write("R3");
`ALU_REG_R4: $write("R4");
`ALU_REG_DAT0: $write("DAT0");
`ALU_REG_DAT1: $write("DAT1");
`ALU_REG_ST: if (o_alu_op!=`ALU_OP_ZERO) $write("ST");
`ALU_REG_P: $write("P");
default: $write("[dest:%d]", o_reg_dest);
endcase
case (o_alu_op)
`ALU_OP_ZERO: if (o_reg_dest==`ALU_REG_ST) $write("CLRST"); else $write("=0");
`ALU_OP_JMP_REL3: $write("GOTO");
`ALU_OP_JMP_REL4: $write("%s", o_push?"GOSUBL":"GOLONG");
`ALU_OP_JMP_ABS5: $write("%s", o_push?"GOSBVL":"GOVLNG");
default:
case (o_reg_dest)
`ALU_REG_A: $write("A");
`ALU_REG_B: $write("B");
`ALU_REG_C:
if (is_lc_hex) $write("LCHEX");
else $write("C");
`ALU_REG_D: $write("D");
`ALU_REG_D0: $write("D0");
`ALU_REG_D1: $write("D1");
`ALU_REG_RSTK: $write("RSTK");
`ALU_REG_R0: $write("R0");
`ALU_REG_R1: $write("R1");
`ALU_REG_R2: $write("R2");
`ALU_REG_R3: $write("R3");
`ALU_REG_R4: $write("R4");
`ALU_REG_DAT0: $write("DAT0");
`ALU_REG_DAT1: $write("DAT1");
`ALU_REG_ST: if (o_alu_op!=`ALU_OP_ZERO) $write("ST");
`ALU_REG_P: $write("P");
default: $write("[dest:%d]", o_reg_dest);
endcase
endcase
case (o_alu_op)
`ALU_OP_ZERO: if (o_reg_dest==`ALU_REG_ST)
$write("CLRST");
else $write("=0");
`ALU_OP_COPY,
`ALU_OP_AND,
`ALU_OP_OR,
`ALU_OP_INC,
`ALU_OP_DEC,
`ALU_OP_ADD,
`ALU_OP_SUB: if (!is_lc_hex) $write("=");
`ALU_OP_EXCH: begin end
`ALU_OP_SUB,
`ALU_OP_RST_BIT,
`ALU_OP_SET_BIT: if (!is_lc_hex)
$write("=");
`ALU_OP_EXCH,
`ALU_OP_JMP_REL3,
`ALU_OP_JMP_REL4,
`ALU_OP_JMP_ABS5: begin end
default: $write("[op:%d]", o_alu_op);
endcase
@ -271,6 +293,8 @@ always @(posedge i_clk) begin
else $write("(%2d)", o_mem_pos+1);
default: $write("[src1:%d]", o_reg_src1);
endcase
`ALU_OP_RST_BIT: $write("0");
`ALU_OP_SET_BIT: $write("1");
endcase
if ((o_alu_op == `ALU_OP_COPY) && is_short_transfer)
@ -332,19 +356,25 @@ always @(posedge i_clk) begin
else
if (o_field_last < 9) $write("%1d", o_field_last+1);
else $write("%2d", o_field_last+1);
end else begin
if (is_load_imm) begin
if (is_p_eq) begin
if (o_imm_value < 10) $write("\t%1d", o_imm_value);
else $write("\t%2d", o_imm_value);
end else begin
for(nibble_pos=o_mem_pos; nibble_pos!=31; nibble_pos=nibble_pos-1)
$write("%h", o_mem_load[nibble_pos*4+:4]);
end
end
else if (!p_is_dest)
$write("[%h:%h]", o_field_start, o_field_last);
end
// $write("@%b@", is_load_imm);
if (is_load_imm) begin
if (is_p_eq) begin
if (o_imm_value < 10) $write("%1d", o_imm_value);
else $write("%2d", o_imm_value);
end else begin
for(nibble_pos=(o_mem_pos - 1); nibble_pos!=31; nibble_pos=nibble_pos-1)
$write("%h", o_mem_load[nibble_pos*4+:4]);
end
end
else
case (o_reg_dest)
`ALU_REG_P,
`ALU_REG_ST: begin end
default: $write("[%h:%h]", o_field_start, o_field_last);
endcase
$display("\t(%d cycles)", inst_cycles);
end
end
@ -374,9 +404,11 @@ reg block_mem_transfer;
reg block_pointer_arith_const;
reg block_load_p;
reg block_load_c_hex;
reg block_jmp3_cry_set;
reg block_jmp3_cry_clr;
reg block_jmp4;
reg block_jmp2_cry_set;
reg block_jmp2_cry_clr;
reg block_8x;
reg block_80x;
reg go_fields_table;
@ -407,9 +439,11 @@ wire do_block_mem_transfer;
wire do_block_pointer_arith_const;
wire do_block_load_p;
wire do_block_load_c_hex;
wire do_block_jmp3_cry_set;
wire do_block_jmp3_cry_clr;
wire do_block_jmp4;
wire do_block_jmp2_cry_set;
wire do_block_jmp2_cry_clr;
wire do_block_8x;
wire do_block_80x;
assign do_block_0x = do_on_other_nibbles && block_0x;
assign do_block_0Efx = do_on_other_nibbles && block_0Efx;
@ -426,14 +460,25 @@ assign do_block_mem_transfer = do_on_other_nibbles && block_mem_transfer;
assign do_block_pointer_arith_const = do_on_other_nibbles && block_pointer_arith_const;
assign do_block_load_p = do_on_other_nibbles && block_load_p;
assign do_block_load_c_hex = do_on_other_nibbles && block_load_c_hex;
assign do_block_jmp3_cry_set = do_on_other_nibbles && block_jmp3_cry_set;
assign do_block_jmp3_cry_clr = do_on_other_nibbles && block_jmp3_cry_clr;
assign do_block_jmp4 = do_on_other_nibbles && block_jmp4;
assign do_block_jmp2_cry_set = do_on_other_nibbles && block_jmp2_cry_set;
assign do_block_jmp2_cry_clr = do_on_other_nibbles && block_jmp2_cry_clr;
assign do_block_8x = do_on_other_nibbles && block_8x;
assign do_block_80x = do_on_other_nibbles && block_80x;
/*
* subroutines
*/
reg block_load_reg_imm;
reg block_jmp;
reg block_sr_bit;
wire do_load_reg_imm;
wire do_block_jmp;
wire do_block_sr_bit;
assign do_load_reg_imm = do_on_other_nibbles && block_load_reg_imm;
assign do_block_jmp = do_on_other_nibbles && block_jmp;
assign do_block_sr_bit = do_on_other_nibbles && block_sr_bit;
wire in_fields_table;
assign in_fields_table = go_fields_table && !fields_table_done;
@ -459,6 +504,7 @@ always @(posedge i_clk) begin
use_fields_tbl <= 0;
o_inc_pc <= 1;
o_dec_error <= 0;
o_alu_debug <= 0;
o_ins_decoded <= 0;
o_alu_op <= 0;
end
@ -467,15 +513,17 @@ always @(posedge i_clk) begin
/*
* stuff that is always done
*/
$display("DEC_RUN 2: nibble %h", i_nibble);
`ifdef SIM
// $display("DEC_RUN 2: nibble %h", i_nibble);
`endif
o_inc_pc <= 1; // may be set to 0 later
o_dbg_nibbles[dbg_write_pos*4+:4] <= i_nibble;
o_dbg_nb_nbls <= o_dbg_nb_nbls + 1;
end
if (decoder_stalled) begin
$display("DEC_STAL 2:");
end
// if (decoder_stalled) begin
// $display("DEC_STAL 2:");
// end
if (count_cycles) begin
inst_cycles <= inst_cycles + 1;
@ -488,6 +536,7 @@ always @(posedge i_clk) begin
inst_cycles <= 1;
next_nibble <= 1;
use_fields_tbl <= 0;
o_alu_debug <= 0;
o_push <= 0;
o_pop <= 0;
@ -496,7 +545,8 @@ always @(posedge i_clk) begin
// store the address where the instruction starts
o_ins_addr <= i_pc;
// cleanup block variables
// decoder block states
block_0x <= 0;
block_0Efx <= 0;
block_1x <= 0;
@ -508,11 +558,17 @@ always @(posedge i_clk) begin
block_pointer_arith_const <= 0;
block_load_p <= 0;
block_load_c_hex <= 0;
block_jmp3_cry_set <= 0;
block_jmp3_cry_clr <= 0;
block_jmp4 <= 0;
block_jmp2_cry_set <= 0;
block_jmp2_cry_clr <= 0;
block_8x <= 0;
block_80x <= 0;
// decoder subroutine states
block_load_reg_imm <= 0;
block_jmp <= 0;
block_sr_bit <= 0;
// cleanup fields table variables
go_fields_table <= 0;
@ -550,15 +606,16 @@ always @(posedge i_clk) begin
4'h1: block_1x <= 1;
4'h2: block_load_p <= 1;
4'h3: block_load_c_hex <= 1;
4'h4: block_jmp3_cry_set <= 1;
4'h5: block_jmp3_cry_clr <= 1;
4'h4: block_jmp2_cry_set <= 1;
4'h5: block_jmp2_cry_clr <= 1;
4'h6: begin
o_alu_no_stall <= 1;
o_alu_op <= `ALU_OP_JMP_REL3;
mem_load_max <= 2;
o_mem_pos <= 0;
block_jmp4 <= 1;
o_mem_pos <= 0;
block_jmp <= 1;
end
4'h8: block_8x <= 1;
default: begin
`ifdef SIM
$display("DEC_INIT 2: nibble %h not handled", i_nibble);
@ -661,30 +718,34 @@ always @(posedge i_clk) begin
if (do_block_1x) begin
case (i_nibble)
4'h0: begin
4'h0: // save A/C to Rn W
block_save_to_R_W <= 1;
end
4'h1:
4'h1: // restore A/C from Rn W
block_rest_from_R_W <= 1;
4'h2:
4'h2: // exchange A/C with Rn W
block_exch_with_R_W <= 1;
4'h3:
4'h3: // move/exch A/C with Dn A/[0:3]
block_pointer_assign_exch <= 1;
4'h4, 4'h5: begin
4'h4, 4'h5: // DAT[01]=[AC] <field>
begin
block_mem_transfer <= 1;
o_fields_table <= i_nibble[0]?`FT_TABLE_value:`FT_TABLE_f;
use_fields_tbl <= i_nibble[0];
end
4'h6, 4'h7, 4'h8, 4'hC: begin
4'h6, 4'h7,
4'h8, 4'hC: // D[01]=D[01][+-] n+1;
begin
block_pointer_arith_const <= 1;
o_ins_alu_op <= 1;
o_alu_op <= i_nibble[1]?`ALU_OP_ADD:`ALU_OP_SUB;
end
4'h9, 4'hA, 4'hB, 4'hD, 4'hE, 4'hF: begin
4'h9, 4'hA,
4'hB, 4'hD,
4'hE, 4'hF: // D[0]=([245]) <stuff>
begin
mem_load_max <= {1'b0, i_nibble[1], !i_nibble[1], i_nibble[1] && i_nibble[0]};
o_mem_pos <= 0;
block_load_reg_imm <= 1;
// o_ins_alu_op <= 1;
o_alu_no_stall <= 1;
o_alu_op <= `ALU_OP_COPY;
end
@ -749,18 +810,63 @@ always @(posedge i_clk) begin
block_load_c_hex <= 0;
end
if (do_block_jmp3_cry_clr) begin
if (do_block_jmp2_cry_clr) begin
end
if (do_block_jmp4) begin
o_ins_alu_op <= 1;
o_imm_value <= i_nibble;
o_mem_pos <= o_mem_pos + 1;
next_nibble <= mem_load_max != o_mem_pos;
o_ins_decoded <= mem_load_max == o_mem_pos;
if (do_block_8x) begin
$display("block_8x %h | op %d", i_nibble, o_alu_op);
case (i_nibble)
4'h0: //
block_80x <= 1;
4'h4, 4'h5: // ST=[01] n
begin
o_alu_op <= i_nibble[0]?`ALU_OP_SET_BIT:`ALU_OP_RST_BIT;
block_sr_bit <= 1;
end
4'hC, 4'hD,
4'hE, 4'hF: // GOLONG, GOVLNG, GOSUBL, GOSBVL
begin
o_alu_no_stall <= 1;
o_alu_op <= i_nibble[0]?`ALU_OP_JMP_ABS5:`ALU_OP_JMP_REL4;
// is it a gosub ?
o_push <= i_nibble[1];
o_alu_debug <= i_nibble[1];
mem_load_max <= i_nibble[0]?4:3;
o_mem_pos <= 0;
block_jmp <= 1;
// debug for cases not tested
o_alu_debug <= i_nibble[1] || !i_nibble[0];
end
default: begin
$display("block_8x %h error", i_nibble);
o_dec_error <= 1;
end
endcase
block_8x <= 0;
end
if (do_block_80x) begin
$display("block_80x %h | op %d", i_nibble, o_alu_op);
case (i_nibble)
4'hC: // C=P n
begin
o_ins_alu_op <= 1;
o_alu_op <= `ALU_OP_COPY;
o_alu_debug <= 1;
next_nibble <= 0;
o_ins_decoded <= 1;
end
default: begin
$display("block_80x %h error", i_nibble);
o_dec_error <= 1;
end
endcase
block_80x <= 0;
end
// utilities
if (do_load_reg_imm) begin
@ -771,11 +877,31 @@ always @(posedge i_clk) begin
o_ins_alu_op <= 1;
o_imm_value <= i_nibble;
o_mem_load[o_mem_pos*4+:4] <= i_nibble;
o_mem_pos <= o_mem_pos + {3'b000, ((o_mem_pos+1) != mem_load_max)};
o_mem_pos <= o_mem_pos + 1;
next_nibble <= (o_mem_pos+1) != mem_load_max;
o_ins_decoded <= (o_mem_pos+1) == mem_load_max;
end
if (do_block_jmp) begin
$display("do_block_jmp %h", i_nibble);
o_ins_alu_op <= 1;
o_imm_value <= i_nibble;
o_mem_load[o_mem_pos*4+:4] <= i_nibble;
o_mem_pos <= o_mem_pos + 1;
next_nibble <= mem_load_max != o_mem_pos;
o_ins_decoded <= mem_load_max == o_mem_pos;
end
if (do_block_sr_bit) begin
$display("do_block_sr_bit %h", i_nibble);
o_ins_alu_op <= 1;
o_imm_value <= i_nibble;
o_mem_load[3:0] <= i_nibble;
o_mem_pos <= 1;
next_nibble <= 0;
o_ins_decoded <= 1;
end
end
@ -925,6 +1051,32 @@ always @(posedge i_clk) begin
o_reg_dest <= `ALU_REG_C;
o_reg_src1 <= `ALU_REG_IMM;
end
if (do_block_8x) begin
case (i_nibble)
4'h4, 4'h5, 4'h6, 4'h7: begin
o_reg_dest <= `ALU_REG_ST;
o_reg_src1 <= `ALU_REG_IMM;
end
4'hC, 4'hD, 4'hE, 4'hF: begin
o_reg_dest <= 0;
o_reg_src1 <= `ALU_REG_IMM;
o_reg_src2 <= 0;
end
endcase
end
if (do_block_80x) begin
case (i_nibble)
4'hC: begin
o_reg_dest <= `ALU_REG_C;
o_reg_src1 <= `ALU_REG_P;
o_reg_src2 <= 0;
end
endcase
end
end
@ -1069,6 +1221,24 @@ always @(posedge i_clk) begin
o_field_last <= (i_nibble + i_reg_p) & 4'hF;
end
if (do_block_8x) begin
case (i_nibble)
4'hC, 4'hD, 4'hE, 4'hF: begin
o_field_start <= 0;
o_field_last <= i_nibble[3]?4:3;
end
endcase
end
if (do_block_80x) begin
case (i_nibble)
4'hC: begin
o_field_start <= i_nibble;
o_field_last <= i_nibble;
end
endcase
end
/******************************************************************************
*
* set field from a table

View file

@ -1,2 +1,2 @@
3 1 4 5
6 3 0 0
3 F 0 1 2 3 4 5 6 7 8 9 A B C D E F
6 3 2 7 // NOP3