separate the decoder in multiple files, it was becoming unwiedly ;-)

This commit is contained in:
Raphael Jacquot 2019-02-15 10:47:00 +01:00
parent 1f01d9bdb9
commit 25385115e0
7 changed files with 902 additions and 906 deletions

View file

@ -1,27 +1,28 @@
cells speed 1 delay (a) 1 delay 1 arcs speed 2 delay (a) 2 delay 2 cells speed 1 delay (a) 1 delay 1 arcs speed 2 delay (a) 2 delay 2
2019-02-12 07:37 29 490.92MHz 2.68ns 330.14MHz 1.99ns 2019-02-12 07:37 29 490.92MHz 2.68ns 330.14MHz 1.99ns
2019-02-12 07:48 29 490.92MHz 14.34ns 2.20ns 350.39MHz 4.14ns 1.77ns 2019-02-12 07:48 29 490.92MHz 14.34ns 2.20ns 350.39MHz 4.14ns 1.77ns
2019-02-12 08:22 29 490.92MHz 14.34ns 2.68ns 330.58MHz 4.71ns 1.84ns 2019-02-12 08:22 29 490.92MHz 14.34ns 2.68ns 330.58MHz 4.71ns 1.84ns
2019-02-12 08:39 29 490.92MHz 14.10ns 3.16ns 96 335.35MHz 4.46ns 1.93ns 2019-02-12 08:39 29 490.92MHz 14.10ns 3.16ns 96 335.35MHz 4.46ns 1.93ns
2019-02-12 08:48 29 490.92MHz 14.10ns 3.16ns 96 335.35MHz 4.46ns 1.93ns 2019-02-12 08:48 29 490.92MHz 14.10ns 3.16ns 96 335.35MHz 4.46ns 1.93ns
2019-02-12 11:11 29 490.92MHz 14.58ns 2.44ns 96 330.03MHz 4.74ns 2.04ns 2019-02-12 11:11 29 490.92MHz 14.58ns 2.44ns 96 330.03MHz 4.74ns 2.04ns
2019-02-12 12:15 29 468.38MHz 14.34ns 2.68ns 96 330.58MHz 4.74ns 1.97ns 2019-02-12 12:15 29 468.38MHz 14.34ns 2.68ns 96 330.58MHz 4.74ns 1.97ns
2019-02-12 12:48 48 242.95MHz 13.38ns 2.92ns 240 162.44MHz 4.13ns 2.05ns 2019-02-12 12:48 48 242.95MHz 13.38ns 2.92ns 240 162.44MHz 4.13ns 2.05ns
2019-02-12 13:25 48 165.54MHz 14.58ns 3.64ns 240 176.46MHz 4.75ns 2.06ns 2019-02-12 13:25 48 165.54MHz 14.58ns 3.64ns 240 176.46MHz 4.75ns 2.06ns
2019-02-12 13:28 48 142.84MHz 14.34ns 3.40ns 240 168.21MHz 4.71ns 2.31ns 2019-02-12 13:28 48 142.84MHz 14.34ns 3.40ns 240 168.21MHz 4.71ns 2.31ns
2019-02-12 13:38 55 196.93MHz 14.58ns 3.16ns 343 166.53MHz 4.43ns 2.06ns 2019-02-12 13:38 55 196.93MHz 14.58ns 3.16ns 343 166.53MHz 4.43ns 2.06ns
2019-02-12 14:51 50 84.74MHz 13.38ns 3.88ns 271 170.13MHz 4.15ns 2.35ns 2019-02-12 14:51 50 84.74MHz 13.38ns 3.88ns 271 170.13MHz 4.15ns 2.35ns
2019-02-12 15:10 50 84.74MHz 13.38ns 3.88ns 271 170.13MHz 4.15ns 2.35ns 2019-02-12 15:10 50 84.74MHz 13.38ns 3.88ns 271 170.13MHz 4.15ns 2.35ns
2019-02-12 15:39 50 75.52MHz 12.90ns 5.09ns 271 166.53MHz 4.14ns 2.55ns 2019-02-12 15:39 50 75.52MHz 12.90ns 5.09ns 271 166.53MHz 4.14ns 2.55ns
2019-02-12 16:04 48 112.10MHz 14.34ns 2.92ns 241 163.99MHz 4.72ns 2.00ns 2019-02-12 16:04 48 112.10MHz 14.34ns 2.92ns 241 163.99MHz 4.72ns 2.00ns
2019-02-12 17:27 56 142.90MHz 14.34ns 3.40ns 345 160.03MHz 4.95ns 2.25ns 2019-02-12 17:27 56 142.90MHz 14.34ns 3.40ns 345 160.03MHz 4.95ns 2.25ns
2019-02-12 18:00 51 213.36MHz 13.98ns 2.92ns 273 165.43MHz 4.78ns 2.05ns 2019-02-12 18:00 51 213.36MHz 13.98ns 2.92ns 273 165.43MHz 4.78ns 2.05ns
2019-02-12 22:07 49 112.10MHz 14.58ns 3.16ns 241 168.95MHz 4.74ns 1.93ns 2019-02-12 22:07 49 112.10MHz 14.58ns 3.16ns 241 168.95MHz 4.74ns 1.93ns
2019-02-12 22:12 51 138.10MHz 15.06ns 2.92ns 273 154.61MHz 4.78ns 2.00ns 2019-02-12 22:12 51 138.10MHz 15.06ns 2.92ns 273 154.61MHz 4.78ns 2.00ns
2019-02-12 22:20 49 112.10MHz 14.34ns 3.64ns 241 171.50MHz 4.55ns 2.33ns 2019-02-12 22:20 49 112.10MHz 14.34ns 3.64ns 241 171.50MHz 4.55ns 2.33ns
2019-02-12 23:27 55 202.72MHz 13.14ns 4.61ns 344 162.63MHz 4.88ns 2.21ns 2019-02-12 23:27 55 202.72MHz 13.14ns 4.61ns 344 162.63MHz 4.88ns 2.21ns
2019-02-13 07:46 48 98.83MHz 13.86ns 2.92ns 241 169.41MHz 4.11ns 1.92ns 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 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-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 2019-02-14 09:00 353 118.23MHz 26.00ns 12.28ns 3334 119.40MHz 10.08ns 3.84ns
2019-02-14 22:11 403 115.09Mhz 27.38ns 11.32ns 2430 111.51Mhz 12.62ns 3.57ns 2019-02-14 22:11 403 115.09MHz 27.38ns 11.32ns 2430 111.51MHz 12.62ns 3.57ns
2019-02-15 07:14 535 97.16MHz 26.57ns 9.16ns 3073 96.10MHz 13.38ns 3.13ns

View file

@ -105,7 +105,6 @@ saturn_decoder m_decoder (
.o_reg_src1 (reg_src1), .o_reg_src1 (reg_src1),
.o_reg_src2 (reg_src2), .o_reg_src2 (reg_src2),
.o_direction (direction),
.o_ins_rtn (ins_rtn), .o_ins_rtn (ins_rtn),
.o_set_xm (set_xm), .o_set_xm (set_xm),
.o_set_carry (set_carry), .o_set_carry (set_carry),
@ -136,7 +135,6 @@ wire [4:0] reg_dest;
wire [4:0] reg_src1; wire [4:0] reg_src1;
wire [4:0] reg_src2; wire [4:0] reg_src2;
wire direction;
wire ins_rtn; wire ins_rtn;
wire set_xm; wire set_xm;
wire set_carry; wire set_carry;
@ -278,7 +276,7 @@ always @(posedge clk) begin
en_inst_exec <= 0; en_inst_exec <= 0;
clock_end <= 0; clock_end <= 0;
cycle_ctr <= ~0; cycle_ctr <= ~0;
max_cycle <= 100; max_cycle <= 140;
`ifndef SIM `ifndef SIM
led[7:0] <= reg_pc[7:0]; led[7:0] <= reg_pc[7:0];
`endif `endif

View file

@ -8,57 +8,31 @@
`include "def-alu.v" `include "def-alu.v"
module saturn_decoder( module saturn_decoder(
i_clk, i_clk, i_reset, i_cycles, i_en_dbg, i_en_dec, i_stalled,
i_reset, i_pc, i_nibble,
i_cycles,
i_en_dbg,
i_en_dec,
i_stalled,
i_pc,
i_nibble,
i_reg_p, i_reg_p,
o_inc_pc, o_inc_pc, o_push, o_pop,
o_push,
o_pop,
o_dec_error, o_dec_error,
`ifdef SIM `ifdef SIM
o_unimplemented, o_unimplemented,
`endif `endif
o_alu_debug, o_alu_debug,
o_ins_addr, o_ins_addr, o_ins_decoded,
o_ins_decoded,
o_fields_table, o_fields_table, o_field, o_field_valid, o_field_start, o_field_last,
o_field,
o_field_valid,
o_field_start,
o_field_last,
o_imm_value, o_imm_value,
o_alu_op, o_alu_op, o_alu_no_stall, o_reg_dest, o_reg_src1, o_reg_src2,
o_alu_no_stall,
o_reg_dest,
o_reg_src1,
o_reg_src2,
o_direction, o_ins_rtn, o_set_xm, o_en_intr,
o_ins_rtn, o_set_carry, o_test_carry, o_carry_val,
o_set_xm, o_ins_set_mode, o_mode_dec,
o_set_carry,
o_en_intr,
o_test_carry,
o_carry_val,
o_ins_set_mode,
o_mode_dec,
o_ins_alu_op, o_ins_alu_op,
o_dbg_nibbles, o_dbg_nibbles, o_dbg_nb_nbls, o_mem_load, o_mem_pos
o_dbg_nb_nbls,
o_mem_load,
o_mem_pos
); );
/* /*
@ -101,9 +75,6 @@ output reg [4:0] o_reg_dest;
output reg [4:0] o_reg_src1; output reg [4:0] o_reg_src1;
output reg [4:0] o_reg_src2; output reg [4:0] o_reg_src2;
// generic
output reg o_direction;
// rtn specific // rtn specific
output reg o_ins_rtn; output reg o_ins_rtn;
output reg o_set_xm; output reg o_set_xm;
@ -150,262 +121,7 @@ initial begin
`endif `endif
end end
/* `include "saturn_decoder_debugger.v"
* debugger
*
*/
wire [19:0] new_pc;
assign new_pc = i_pc + 1;
wire run_debugger;
assign run_debugger = !i_reset && i_en_dbg && !i_stalled && !next_nibble;
wire is_short_transfer;
assign is_short_transfer = (o_field_last == 3) &&
((o_reg_dest[4:1] == 4'b0010) || (o_reg_src1[4:1] == 4'b0010));
wire p_is_dest;
wire is_load_imm;
wire is_d0_eq;
wire is_d1_eq;
wire is_p_eq;
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_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;
assign is_la_hex = is_load_imm && (o_reg_dest == `ALU_REG_A);
assign is_lc_hex = is_load_imm && (o_reg_dest == `ALU_REG_C);
assign disp_nb_nibbles = is_d0_eq || is_d1_eq;
reg [4:0] nibble_pos;
always @(posedge i_clk) begin
if (run_debugger) begin
/*
* this whole thing is a large print statement
* THIS PART IS NEVER GENERATED
*/
`ifdef SIM
if (o_ins_decoded) begin
$write("DBG[%5d]: ", inst_counter);
$write("%5h ", o_ins_addr);
// $write("[%2d] ", o_dbg_nb_nbls);
for(nibble_pos=0; nibble_pos!=o_dbg_nb_nbls; nibble_pos=nibble_pos+1)
$write("%h", o_dbg_nibbles[nibble_pos*4+:4]);
for(nibble_pos=o_dbg_nb_nbls; nibble_pos!=22; nibble_pos=nibble_pos+1)
$write(" ");
// display decoded instruction
if (o_ins_rtn) begin
$write("RT%s", o_en_intr?"I":"N");
if (o_set_xm) $write("SXM");
if (o_set_carry) $write("%sC", o_carry_val?"S":"C");
end
if (o_ins_set_mode) begin
$write("SET%s", o_mode_dec?"DEC":"HEX");
end
if (o_ins_alu_op) begin
case (o_alu_op)
`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");
`ALU_OP_CLR_MASK:
case (o_reg_dest)
`ALU_REG_HST:
case (o_imm_value)
4'h1: $write("XM=0");
4'h2: $write("SB=0");
4'h4: $write("SR=0");
4'h8: $write("MP=0");
default: begin
$write("CLRHST");
if (o_imm_value != 4'hF) $write("\t%1h", o_imm_value);
end
endcase
default: $write("[VLR_MASK dest:%0d]", o_reg_dest);
endcase
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:%0d]", 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,
`ALU_OP_RST_BIT,
`ALU_OP_SET_BIT: if (!is_lc_hex)
$write("=");
`ALU_OP_2CMPL: $write("=-");
`ALU_OP_EXCH,
`ALU_OP_JMP_REL3,
`ALU_OP_JMP_REL4,
`ALU_OP_JMP_ABS5,
`ALU_OP_CLR_MASK: begin end
default: $write("[op:%0d]", o_alu_op);
endcase
case (o_alu_op)
`ALU_OP_COPY,
`ALU_OP_EXCH,
`ALU_OP_AND,
`ALU_OP_OR,
`ALU_OP_INC,
`ALU_OP_DEC,
`ALU_OP_ADD,
`ALU_OP_SUB,
`ALU_OP_2CMPL:
case (o_reg_src1)
`ALU_REG_A: $write("A");
`ALU_REG_B: $write("B");
`ALU_REG_C: $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: $write("ST");
`ALU_REG_P: $write("P");
`ALU_REG_IMM:
if (disp_nb_nibbles) $write("(%0d)", o_mem_pos);
`ALU_REG_ZERO: $write("0");
default: $write("[src1:%0d]", 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)
$write("S");
if (o_alu_op == `ALU_OP_EXCH)
$write("%s", is_short_transfer?"XS":"EX");
case (o_alu_op)
`ALU_OP_AND,
`ALU_OP_OR,
`ALU_OP_ADD,
`ALU_OP_SUB: begin
case (o_alu_op)
`ALU_OP_AND: $write("&");
`ALU_OP_OR: $write("!");
`ALU_OP_ADD: $write("+");
`ALU_OP_SUB: $write("-");
default: $write("[op:%0d]", o_alu_op);
endcase
case (o_reg_src2)
`ALU_REG_A: $write("A");
`ALU_REG_B: $write("B");
`ALU_REG_C: $write("C");
`ALU_REG_D: $write("D");
`ALU_REG_RSTK: $write("RSTK");
`ALU_REG_IMM: $write("\t%0d", o_imm_value+1);
default: $write("[src2:%0d]", o_reg_src2);
endcase
end
`ALU_OP_INC: $write("+1");
`ALU_OP_DEC: $write("-1");
`ALU_OP_ZERO,
`ALU_OP_COPY,
`ALU_OP_EXCH: begin end
endcase
// if (!((o_reg_dest == `ALU_REG_RSTK) || (o_reg_src1 == `ALU_REG_RSTK) ||
// (o_reg_dest == `ALU_REG_ST) || (o_reg_src1 == `ALU_REG_ST ) ||
// (o_reg_dest == `ALU_REG_P) || (o_reg_src1 == `ALU_REG_P ))) begin
$write("\t");
if (o_field_valid) begin
// $write("[FT%d]", o_fields_table);
if (o_fields_table != `FT_TABLE_value)
case (o_field)
`FT_FIELD_P: $write("P");
`FT_FIELD_WP: $write("WP");
`FT_FIELD_XS: $write("XS");
`FT_FIELD_X: $write("X");
`FT_FIELD_S: $write("S");
`FT_FIELD_M: $write("M");
`FT_FIELD_B: $write("B");
`FT_FIELD_W: $write("W");
`FT_FIELD_A: $write("A");
endcase
else $write("%0d", o_field_last+1);
end else begin
// $write("@%b@", is_load_imm);
if (is_load_imm) begin
if (is_p_eq) $write("%0d", o_imm_value);
else
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
else
case (o_reg_dest)
`ALU_REG_P,
`ALU_REG_ST,
`ALU_REG_HST: begin end
`ALU_REG_C:
if (o_reg_src1 == `ALU_REG_P)
$write("%0d", o_field_start);
default: $write("[%h:%h]", o_field_start, o_field_last);
endcase
end
end
$write("\t(%0d cycles)", inst_cycles);
if (o_unimplemented)
$write("\t%C[1,31mUNIMPLEMENTED%C[0m", 27, 27);
$write("\n");
end
// $display("new [%5h]--------------------------------------------------------------------", new_pc);
`endif
end
end
/****************************************************************************** /******************************************************************************
* *
@ -417,36 +133,6 @@ end
// general variables // general variables
reg use_fields_tbl; reg use_fields_tbl;
reg block_0x;
reg block_0Efx;
reg block_1x;
reg block_save_to_R_W;
reg block_rest_from_R_W;
reg block_exch_with_R_W;
reg block_pointer_assign_exch;
reg block_mem_transfer;
reg block_pointer_arith_const;
reg block_load_p;
reg block_load_c_hex;
reg block_jmp2_cry_set;
reg block_jmp2_cry_clr;
reg block_8x;
reg block_80x;
reg block_80Cx;
reg block_82x;
reg block_Ax;
reg block_Aax;
reg block_Abx;
reg block_Fx;
reg go_fields_table;
/* lots'o-wires to decode common states
*/
wire count_cycles; wire count_cycles;
wire decoder_active; wire decoder_active;
wire decoder_stalled; wire decoder_stalled;
@ -459,73 +145,8 @@ assign decoder_stalled = !i_reset && i_en_dec && i_stalled;
assign do_on_first_nibble = decoder_active && !next_nibble; assign do_on_first_nibble = decoder_active && !next_nibble;
assign do_on_other_nibbles = decoder_active && next_nibble; assign do_on_other_nibbles = decoder_active && next_nibble;
wire do_block_0x; // all regs and wires for the decoder states
wire do_block_0Efx; `include "saturn_decoder_block_vars.v"
wire do_block_1x;
wire do_block_save_to_R_W;
wire do_block_rest_from_R_W;
wire do_block_exch_with_R_W;
wire do_block_Rn_A_C;
wire do_block_pointer_assign_exch;
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_8x;
wire do_block_80x;
wire do_block_80Cx;
wire do_block_82x;
wire do_block_Ax;
wire do_block_Aax;
wire do_block_Abx;
wire do_block_Fx;
assign do_block_0x = do_on_other_nibbles && block_0x;
assign do_block_0Efx = do_on_other_nibbles && block_0Efx;
assign do_block_1x = do_on_other_nibbles && block_1x;
assign do_block_save_to_R_W = do_on_other_nibbles && block_save_to_R_W;
assign do_block_rest_from_R_W = do_on_other_nibbles && block_rest_from_R_W;
assign do_block_exch_with_R_W = do_on_other_nibbles && block_exch_with_R_W;
assign do_block_Rn_A_C = do_on_other_nibbles &&
( block_save_to_R_W ||
block_rest_from_R_W ||
block_exch_with_R_W );
assign do_block_pointer_assign_exch = do_on_other_nibbles && block_pointer_assign_exch;
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_8x = do_on_other_nibbles && block_8x;
assign do_block_80x = do_on_other_nibbles && block_80x;
assign do_block_80Cx = do_on_other_nibbles && block_80Cx;
assign do_block_82x = do_on_other_nibbles && block_82x;
assign do_block_Ax = do_on_other_nibbles && block_Ax;
assign do_block_Aax = do_on_other_nibbles && block_Aax;
assign do_block_Abx = do_on_other_nibbles && block_Abx;
assign do_block_Fx = do_on_other_nibbles && block_Fx;
/*
* 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;
/* /*
* variables specific to a particular use * variables specific to a particular use
@ -640,9 +261,6 @@ always @(posedge i_clk) begin
o_alu_op <= 0; o_alu_op <= 0;
o_alu_no_stall <= 0; o_alu_no_stall <= 0;
// cleanup
o_direction <= 0;
o_ins_rtn <= 0; o_ins_rtn <= 0;
o_set_xm <= 0; o_set_xm <= 0;
o_set_carry <= 0; o_set_carry <= 0;
@ -1080,489 +698,8 @@ always @(posedge i_clk) begin
end end
`include "saturn_decoder_registers.v"
/****************************************************************************** `include "saturn_decoder_fields.v"
*
* set registers from instruction nibble
*
*****************************************************************************/
wire [4:0] reg_ABCD;
wire [4:0] reg_BCAC;
wire [4:0] reg_ABAC;
wire [4:0] reg_BCCD;
wire [4:0] reg_D0D1;
wire [4:0] reg_DAT0DAT1;
wire [4:0] reg_A_C;
assign reg_ABCD = { 3'b000, i_nibble[1:0]};
assign reg_BCAC = { 3'b000, i_nibble[0], !(i_nibble[1] || i_nibble[0])};
assign reg_ABAC = { 3'b000, i_nibble[1] && i_nibble[0], (!i_nibble[1]) && i_nibble[0]};
assign reg_BCCD = { 3'b000, i_nibble[1] || i_nibble[0], (!i_nibble[1]) ^ i_nibble[0]};
// assign reg_D0D1 = { 4'b0010, (i_nibble[0] && i_nibble[1]) || (i_nibble[2] && i_nibble[3])};
assign reg_D0D1 = { 4'b0010, i_nibble[0]};
assign reg_DAT0DAT1 = { 4'b1000, i_nibble[0]};
assign reg_A_C = { 3'b000, i_nibble[2], 1'b0};
always @(posedge i_clk) begin
if (i_reset) begin
o_reg_dest <= 0;
o_reg_src1 <= 0;
o_reg_src2 <= 0;
inval_opcode_regs <= 0;
end
if (do_on_first_nibble) begin
// reset values on instruction decode start
case (i_nibble)
4'h6: begin
o_reg_dest <= 0;
o_reg_src1 <= `ALU_REG_IMM;
o_reg_src2 <= 0;
end
default: begin
o_reg_dest <= 0;
o_reg_src1 <= 0;
o_reg_src2 <= 0;
end
endcase
inval_opcode_regs <= 0;
end
/************************************************************************
*
* set registers for specific instructions
*
************************************************************************/
if (do_block_0x) begin
case (i_nibble)
4'h6: begin
o_reg_dest <= `ALU_REG_RSTK;
o_reg_src1 <= `ALU_REG_C;
end
4'h7: begin
o_reg_dest <= `ALU_REG_C;
o_reg_src1 <= `ALU_REG_RSTK;
end
4'h8: o_reg_dest <= `ALU_REG_ST;
4'h9, 4'hB: begin
o_reg_dest <= `ALU_REG_C;
o_reg_src1 <= `ALU_REG_ST;
end
4'hA: begin
o_reg_dest <= `ALU_REG_ST;
o_reg_src1 <= `ALU_REG_C;
end
4'hC, 4'hD: begin
o_reg_dest <= `ALU_REG_P;
o_reg_src1 <= `ALU_REG_P;
end
default: begin
// inval_opcode_regs <= 1;
end
endcase
end
if (do_block_0Efx && !in_fields_table) begin
o_reg_dest <= i_nibble[2]?reg_BCAC:reg_ABCD;
o_reg_src1 <= i_nibble[2]?reg_BCAC:reg_ABCD;
o_reg_src2 <= i_nibble[2]?reg_ABCD:reg_BCAC;
end
if (do_block_1x) begin
case (i_nibble)
4'h6, 4'h8: begin
o_reg_dest <= `ALU_REG_D0;
o_reg_src1 <= `ALU_REG_D0;
end
4'h7, 4'hC: begin
o_reg_dest <= `ALU_REG_D1;
o_reg_src1 <= `ALU_REG_D1;
end
4'h9, 4'hA, 4'hB: begin
o_reg_dest <= `ALU_REG_D0;
o_reg_src1 <= `ALU_REG_IMM;
end
4'hD, 4'hE, 4'hF: begin
o_reg_dest <= `ALU_REG_D1;
o_reg_src1 <= `ALU_REG_IMM;
end
default: begin end
endcase
end
if (do_block_save_to_R_W) begin
o_reg_dest <= {2'b01, i_nibble[2:0]};
o_reg_src1 <= {3'b000, i_nibble[3]?2'b10:2'b00};
end
if (do_block_rest_from_R_W || do_block_exch_with_R_W) begin
o_reg_dest <= {3'b000, i_nibble[3]?2'b10:2'b00};
o_reg_src1 <= {2'b01, i_nibble[2:0]};
end
if (do_block_pointer_assign_exch) begin
o_reg_dest <= i_nibble[1]?reg_A_C:reg_D0D1;
o_reg_src1 <= i_nibble[1]?reg_D0D1:reg_A_C;
end
if (do_block_mem_transfer) begin
o_reg_dest <= i_nibble[1]?reg_A_C:reg_DAT0DAT1;
o_reg_src1 <= i_nibble[1]?reg_DAT0DAT1:reg_A_C;
end
if (do_block_pointer_arith_const) begin
o_reg_src2 <= `ALU_REG_IMM;
end
if (do_block_load_p) begin
o_reg_dest <= `ALU_REG_P;
o_reg_src1 <= `ALU_REG_IMM;
end
if (do_block_load_c_hex) 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_80Cx) begin
o_reg_dest <= `ALU_REG_C;
o_reg_src1 <= `ALU_REG_P;
o_reg_src2 <= 0;
end
if (do_block_82x) begin
o_reg_dest <= `ALU_REG_HST;
o_reg_src1 <= `ALU_REG_HST;
o_reg_src2 <= `ALU_REG_IMM;
end
if (do_block_Abx) begin
case ({i_nibble[3],i_nibble[2]})
2'b00: begin
o_reg_dest <= reg_ABCD;
o_reg_src1 <= `ALU_REG_ZERO;
end
2'b01: begin
o_reg_dest <= reg_ABCD;
o_reg_src1 <= reg_BCAC;
end
2'b10: begin
o_reg_dest <= reg_BCAC;
o_reg_src1 <= reg_ABCD;
end
2'b11: begin
o_reg_dest <= reg_ABAC;
o_reg_src1 <= reg_BCCD;
end
endcase
o_reg_src2 <= 0;
end
if (do_block_Fx) begin
case (i_nibble)
4'h8, 4'h9, 4'hA, 4'hB: begin
o_reg_dest <= reg_ABCD;
o_reg_src1 <= reg_ABCD;
o_reg_src2 <= 0;
end
endcase
end
end
/******************************************************************************
*
* set fields from instruction nibble
*
*****************************************************************************/
`ifdef SIM
// `define DEBUG_FIELDS_TABLE
`endif
reg fields_table_done;
/* more wires to decode common states.
* can possibly be made less redundant / faster ?
*/
wire do_fields_table;
assign do_fields_table = decoder_active && go_fields_table && !fields_table_done;
wire table_a;
wire table_b;
wire table_f;
wire table_value;
assign table_a = (o_fields_table == `FT_TABLE_a);
assign table_b = (o_fields_table == `FT_TABLE_b);
assign table_f = (o_fields_table == `FT_TABLE_f);
assign table_value = (o_fields_table == `FT_TABLE_value);
wire do_tables_a_f_b;
assign do_tables_a_f_b = do_fields_table && !table_value;
wire table_f_bit_3;
wire [3:0] table_a_f_b_case_value;
assign table_f_bit_3 = table_f && i_nibble[3];
assign table_a_f_b_case_value = {table_f_bit_3, i_nibble[2:0]};
/* value generation for debug
*/
wire table_a_nb_ok;
wire table_b_nb_ok;
wire table_f_cond;
wire table_f_nb_ok;
wire table_a_f_b_nb_ok;
assign table_a_nb_ok = table_a && !i_nibble[3];
assign table_b_nb_ok = table_b && i_nibble[3];
assign table_f_cond = !i_nibble[3] || (i_nibble == 4'hF);
assign table_f_nb_ok = table_f && table_f_cond;
assign table_a_f_b_nb_ok = table_a_nb_ok || table_b_nb_ok || table_f_nb_ok;
/* here we go
*/
always @(posedge i_clk) begin
if (i_reset || do_on_first_nibble) begin
// reset values
fields_table_done <= 0;
o_field <= 0;
o_field_valid <= 0;
case (i_nibble)
4'h6: begin
o_field_start <= 0;
o_field_last <= 2;
end
default: begin
o_field_start <= 0;
o_field_last <= 0;
end
endcase
end
/******************************************************************************
*
* set field for specific instructions
*
*****************************************************************************/
if (do_block_0x) begin
case (i_nibble)
4'h6, 4'h7: begin
// virtual A
o_field_start <= 0;
o_field_last <= 4;
end
4'h8, 4'h9, 4'hA, 4'hB: begin
// ST is 0-3
o_field_start <= 0;
o_field_last <= 3;
end
default: begin end // don't care
endcase
end
if (do_block_1x) begin
o_field_start <= 0;
case (i_nibble)
4'h9, 4'hD: begin
o_field_last <= 1;
end
4'hA, 4'hE: begin
o_field_last <= 3;
end
4'hB, 4'hF: begin
o_field_last <= 4;
end
endcase
end
if (do_block_Rn_A_C) begin
o_field_start <= 0;
o_field_last <= 15;
end
if (do_block_pointer_assign_exch) begin
o_field_start <= 0;
o_field_last <= i_nibble[3]?3:4;
end
if (do_block_mem_transfer && !do_fields_table) begin
o_field <= i_nibble[3]?`FT_FIELD_B:`FT_FIELD_A;
o_field_start <= 0;
o_field_last <= i_nibble[3]?1:4;
o_field_valid <= 1;
end
if (do_block_mem_transfer && do_fields_table && table_value) begin
o_field_start <= 0;
o_field_last <= i_nibble;
o_field_valid <= 1;
end
if (do_block_pointer_arith_const) begin
o_field_start <= 0;
o_field_last <= 4;
end
if (do_block_load_c_hex) begin
o_field_start <= i_reg_p;
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_80Cx) begin
o_field_start <= i_nibble;
o_field_last <= i_nibble;
end
if (do_block_Fx) begin
case (i_nibble)
4'h8, 4'h9, 4'hA, 4'hB: begin
o_field <= `FT_FIELD_A;
o_field_start <= 0;
o_field_last <= 4;
o_field_valid <= 1;
end
endcase
end
/******************************************************************************
*
* set field from a table
*
*
*****************************************************************************/
`ifdef DEBUG_FIELDS_TABLE
if (do_tables_a_f_b) begin
// debug info
$display("====== fields_table | table %h | nibble %b", o_fields_table, i_nibble);
$display("table_a : %b", table_a_nb_ok);
$display("table_b : %b", table_b_nb_ok);
$display("table_f_cond: %b", table_f_cond);
$display("table_f : %b", table_f_nb_ok);
// $display("table_f nbl : %h", {4{o_fields_table == `FT_TABLE_f}} );
//$display("table_f val : %h", table_f_nibble_value);
$display("case nibble : %h", table_a_f_b_case_value);
end
`endif
//
if (do_tables_a_f_b) begin
case (table_a_f_b_case_value)
4'h0: begin
o_field <= `FT_FIELD_P;
o_field_start <= i_reg_p;
o_field_last <= i_reg_p;
`ifdef DEBUG_FIELDS_TABLE
$display("fields_table: field P (%h)", i_reg_p);
`endif
end
4'h1: begin
o_field <= `FT_FIELD_WP;
o_field_start <= 0;
o_field_last <= i_reg_p;
`ifdef DEBUG_FIELDS_TABLE
$display("fields_table: field WP (0-%h)", i_reg_p);
`endif
end
4'h2: begin
o_field <= `FT_FIELD_XS;
o_field_start <= 2;
o_field_last <= 2;
`ifdef DEBUG_FIELDS_TABLE
$display("fields_table: field XS");
`endif
end
4'h3: begin
o_field <= `FT_FIELD_X;
o_field_start <= 0;
o_field_last <= 2;
`ifdef DEBUG_FIELDS_TABLE
$display("fields_table: field X");
`endif
end
4'h4: begin
o_field <= `FT_FIELD_S;
o_field_start <= 15;
o_field_last <= 15;
`ifdef DEBUG_FIELDS_TABLE
$display("fields_table: field S");
`endif
end
4'h5: begin
o_field <= `FT_FIELD_M;
o_field_start <= 3;
o_field_last <= 14;
`ifdef DEBUG_FIELDS_TABLE
$display("fields_table: field M");
`endif
end
4'h6: begin
o_field <= `FT_FIELD_B;
o_field_start <= 0;
o_field_last <= 1;
`ifdef DEBUG_FIELDS_TABLE
$display("fields_table: field B");
`endif
end
4'h7: begin
o_field <= `FT_FIELD_W;
o_field_start <= 0;
o_field_last <= 15;
`ifdef DEBUG_FIELDS_TABLE
$display("fields_table: field W");
`endif
end
4'hF: begin
o_field <= `FT_FIELD_A;
o_field_start <= 0;
o_field_last <= 4;
`ifdef DEBUG_FIELDS_TABLE
$display("fields_table: field A");
`endif
end
default: begin
o_dec_error <= 1;
`ifdef SIM
$display("fields_table: table %h nibble %h not handled", o_fields_table, i_nibble);
`endif
end
endcase
o_field_valid <= 1;
fields_table_done <= 1;
end
end
endmodule endmodule

120
saturn_decoder_block_vars.v Normal file
View file

@ -0,0 +1,120 @@
/*
*
*
*
*
*/
/*
*
* Block vars registers
*
*/
reg block_0x;
wire do_block_0x;
assign do_block_0x = do_on_other_nibbles && block_0x;
reg block_0Efx;
wire do_block_0Efx;
assign do_block_0Efx = do_on_other_nibbles && block_0Efx;
reg block_1x;
wire do_block_1x;
assign do_block_1x = do_on_other_nibbles && block_1x;
reg block_save_to_R_W;
wire do_block_save_to_R_W;
assign do_block_save_to_R_W = do_on_other_nibbles && block_save_to_R_W;
reg block_rest_from_R_W;
wire do_block_rest_from_R_W;
assign do_block_rest_from_R_W = do_on_other_nibbles && block_rest_from_R_W;
reg block_exch_with_R_W;
wire do_block_exch_with_R_W;
assign do_block_exch_with_R_W = do_on_other_nibbles && block_exch_with_R_W;
wire do_block_Rn_A_C;
assign do_block_Rn_A_C = do_on_other_nibbles &&
( block_save_to_R_W ||
block_rest_from_R_W ||
block_exch_with_R_W );
reg block_pointer_assign_exch;
wire do_block_pointer_assign_exch;
assign do_block_pointer_assign_exch = do_on_other_nibbles && block_pointer_assign_exch;
reg block_mem_transfer;
wire do_block_mem_transfer;
assign do_block_mem_transfer = do_on_other_nibbles && block_mem_transfer;
reg block_pointer_arith_const;
wire do_block_pointer_arith_const;
assign do_block_pointer_arith_const = do_on_other_nibbles && block_pointer_arith_const;
reg block_load_p;
wire do_block_load_p;
assign do_block_load_p = do_on_other_nibbles && block_load_p;
reg block_load_c_hex;
wire do_block_load_c_hex;
assign do_block_load_c_hex = do_on_other_nibbles && block_load_c_hex;
reg block_jmp2_cry_set;
reg block_jmp2_cry_clr;
reg block_8x;
wire do_block_8x;
assign do_block_8x = do_on_other_nibbles && block_8x;
reg block_80x;
wire do_block_80x;
assign do_block_80x = do_on_other_nibbles && block_80x;
reg block_80Cx;
wire do_block_80Cx;
assign do_block_80Cx = do_on_other_nibbles && block_80Cx;
reg block_82x;
wire do_block_82x;
assign do_block_82x = do_on_other_nibbles && block_82x;
reg block_Ax;
wire do_block_Ax;
assign do_block_Ax = do_on_other_nibbles && block_Ax;
reg block_Aax;
wire do_block_Aax;
assign do_block_Aax = do_on_other_nibbles && block_Aax;
reg block_Abx;
wire do_block_Abx;
assign do_block_Abx = do_on_other_nibbles && block_Abx;
reg block_Fx;
wire do_block_Fx;
assign do_block_Fx = do_on_other_nibbles && block_Fx;
reg go_fields_table;
/*
* subroutines
*/
reg block_load_reg_imm;
wire do_load_reg_imm;
assign do_load_reg_imm = do_on_other_nibbles && block_load_reg_imm;
reg block_jmp;
wire do_block_jmp;
assign do_block_jmp = do_on_other_nibbles && block_jmp;
reg block_sr_bit;
wire do_block_sr_bit;
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;

257
saturn_decoder_debugger.v Normal file
View file

@ -0,0 +1,257 @@
/*
* debugger
*
*/
wire [19:0] new_pc;
assign new_pc = i_pc + 1;
wire run_debugger;
assign run_debugger = !i_reset && i_en_dbg && !i_stalled && !next_nibble;
wire is_short_transfer;
assign is_short_transfer = (o_field_last == 3) &&
((o_reg_dest[4:1] == 4'b0010) || (o_reg_src1[4:1] == 4'b0010));
wire p_is_dest;
wire is_load_imm;
wire is_d0_eq;
wire is_d1_eq;
wire is_p_eq;
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_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;
assign is_la_hex = is_load_imm && (o_reg_dest == `ALU_REG_A);
assign is_lc_hex = is_load_imm && (o_reg_dest == `ALU_REG_C);
assign disp_nb_nibbles = is_d0_eq || is_d1_eq;
reg [4:0] nibble_pos;
always @(posedge i_clk) begin
if (run_debugger) begin
/*
* this whole thing is a large print statement
* THIS PART IS NEVER GENERATED
*/
`ifdef SIM
if (o_ins_decoded) begin
$write("DBG[%5d]: ", inst_counter);
$write("%5h ", o_ins_addr);
// $write("[%2d] ", o_dbg_nb_nbls);
for(nibble_pos=0; nibble_pos!=o_dbg_nb_nbls; nibble_pos=nibble_pos+1)
$write("%h", o_dbg_nibbles[nibble_pos*4+:4]);
for(nibble_pos=o_dbg_nb_nbls; nibble_pos!=22; nibble_pos=nibble_pos+1)
$write(" ");
// display decoded instruction
if (o_ins_rtn) begin
$write("RT%s", o_en_intr?"I":"N");
if (o_set_xm) $write("SXM");
if (o_set_carry) $write("%sC", o_carry_val?"S":"C");
end
if (o_ins_set_mode) begin
$write("SET%s", o_mode_dec?"DEC":"HEX");
end
if (o_ins_alu_op) begin
case (o_alu_op)
`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");
`ALU_OP_CLR_MASK:
case (o_reg_dest)
`ALU_REG_HST:
case (o_imm_value)
4'h1: $write("XM=0");
4'h2: $write("SB=0");
4'h4: $write("SR=0");
4'h8: $write("MP=0");
default: begin
$write("CLRHST");
if (o_imm_value != 4'hF) $write("\t%1h", o_imm_value);
end
endcase
default: $write("[VLR_MASK dest:%0d]", o_reg_dest);
endcase
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:%0d]", 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,
`ALU_OP_RST_BIT,
`ALU_OP_SET_BIT: if (!is_lc_hex)
$write("=");
`ALU_OP_2CMPL: $write("=-");
`ALU_OP_EXCH,
`ALU_OP_JMP_REL3,
`ALU_OP_JMP_REL4,
`ALU_OP_JMP_ABS5,
`ALU_OP_CLR_MASK: begin end
default: $write("[op:%0d]", o_alu_op);
endcase
case (o_alu_op)
`ALU_OP_COPY,
`ALU_OP_EXCH,
`ALU_OP_AND,
`ALU_OP_OR,
`ALU_OP_INC,
`ALU_OP_DEC,
`ALU_OP_ADD,
`ALU_OP_SUB,
`ALU_OP_2CMPL:
case (o_reg_src1)
`ALU_REG_A: $write("A");
`ALU_REG_B: $write("B");
`ALU_REG_C: $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: $write("ST");
`ALU_REG_P: $write("P");
`ALU_REG_IMM:
if (disp_nb_nibbles) $write("(%0d)", o_mem_pos);
`ALU_REG_ZERO: $write("0");
default: $write("[src1:%0d]", 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)
$write("S");
if (o_alu_op == `ALU_OP_EXCH)
$write("%s", is_short_transfer?"XS":"EX");
case (o_alu_op)
`ALU_OP_AND,
`ALU_OP_OR,
`ALU_OP_ADD,
`ALU_OP_SUB: begin
case (o_alu_op)
`ALU_OP_AND: $write("&");
`ALU_OP_OR: $write("!");
`ALU_OP_ADD: $write("+");
`ALU_OP_SUB: $write("-");
default: $write("[op:%0d]", o_alu_op);
endcase
case (o_reg_src2)
`ALU_REG_A: $write("A");
`ALU_REG_B: $write("B");
`ALU_REG_C: $write("C");
`ALU_REG_D: $write("D");
`ALU_REG_RSTK: $write("RSTK");
`ALU_REG_IMM: $write("\t%0d", o_imm_value+1);
default: $write("[src2:%0d]", o_reg_src2);
endcase
end
`ALU_OP_INC: $write("+1");
`ALU_OP_DEC: $write("-1");
`ALU_OP_ZERO,
`ALU_OP_COPY,
`ALU_OP_EXCH: begin end
endcase
// if (!((o_reg_dest == `ALU_REG_RSTK) || (o_reg_src1 == `ALU_REG_RSTK) ||
// (o_reg_dest == `ALU_REG_ST) || (o_reg_src1 == `ALU_REG_ST ) ||
// (o_reg_dest == `ALU_REG_P) || (o_reg_src1 == `ALU_REG_P ))) begin
$write("\t");
if (o_field_valid) begin
// $write("[FT%d]", o_fields_table);
if (o_fields_table != `FT_TABLE_value)
case (o_field)
`FT_FIELD_P: $write("P");
`FT_FIELD_WP: $write("WP");
`FT_FIELD_XS: $write("XS");
`FT_FIELD_X: $write("X");
`FT_FIELD_S: $write("S");
`FT_FIELD_M: $write("M");
`FT_FIELD_B: $write("B");
`FT_FIELD_W: $write("W");
`FT_FIELD_A: $write("A");
endcase
else $write("%0d", o_field_last+1);
end else begin
// $write("@%b@", is_load_imm);
if (is_load_imm) begin
if (is_p_eq) $write("%0d", o_imm_value);
else
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
else
case (o_reg_dest)
`ALU_REG_P,
`ALU_REG_ST,
`ALU_REG_HST: begin end
`ALU_REG_C:
if (o_reg_src1 == `ALU_REG_P)
$write("%0d", o_field_start);
default: $write("[%h:%h]", o_field_start, o_field_last);
endcase
end
end
$write("\t(%0d cycles)", inst_cycles);
if (o_unimplemented)
$write("\t%C[1,31mUNIMPLEMENTED%C[0m", 27, 27);
$write("\n");
end
// $display("new [%5h]--------------------------------------------------------------------", new_pc);
`endif
end
end

275
saturn_decoder_fields.v Normal file
View file

@ -0,0 +1,275 @@
/******************************************************************************
*
* set fields from instruction nibble
*
*****************************************************************************/
`ifdef SIM
// `define DEBUG_FIELDS_TABLE
`endif
reg fields_table_done;
/* more wires to decode common states.
* can possibly be made less redundant / faster ?
*/
wire do_fields_table;
assign do_fields_table = decoder_active && go_fields_table && !fields_table_done;
wire table_a;
wire table_b;
wire table_f;
wire table_value;
assign table_a = (o_fields_table == `FT_TABLE_a);
assign table_b = (o_fields_table == `FT_TABLE_b);
assign table_f = (o_fields_table == `FT_TABLE_f);
assign table_value = (o_fields_table == `FT_TABLE_value);
wire do_tables_a_f_b;
assign do_tables_a_f_b = do_fields_table && !table_value;
wire table_f_bit_3;
wire [3:0] table_a_f_b_case_value;
assign table_f_bit_3 = table_f && i_nibble[3];
assign table_a_f_b_case_value = {table_f_bit_3, i_nibble[2:0]};
/* value generation for debug
*/
wire table_a_nb_ok;
wire table_b_nb_ok;
wire table_f_cond;
wire table_f_nb_ok;
wire table_a_f_b_nb_ok;
assign table_a_nb_ok = table_a && !i_nibble[3];
assign table_b_nb_ok = table_b && i_nibble[3];
assign table_f_cond = !i_nibble[3] || (i_nibble == 4'hF);
assign table_f_nb_ok = table_f && table_f_cond;
assign table_a_f_b_nb_ok = table_a_nb_ok || table_b_nb_ok || table_f_nb_ok;
/* here we go
*/
always @(posedge i_clk) begin
if (i_reset || do_on_first_nibble) begin
// reset values
fields_table_done <= 0;
o_field <= 0;
o_field_valid <= 0;
case (i_nibble)
4'h6: begin
o_field_start <= 0;
o_field_last <= 2;
end
default: begin
o_field_start <= 0;
o_field_last <= 0;
end
endcase
end
/******************************************************************************
*
* set field for specific instructions
*
*****************************************************************************/
if (do_block_0x) begin
case (i_nibble)
4'h6, 4'h7: begin
// virtual A
o_field_start <= 0;
o_field_last <= 4;
end
4'h8, 4'h9, 4'hA, 4'hB: begin
// ST is 0-3
o_field_start <= 0;
o_field_last <= 3;
end
default: begin end // don't care
endcase
end
if (do_block_1x) begin
o_field_start <= 0;
case (i_nibble)
4'h9, 4'hD: begin
o_field_last <= 1;
end
4'hA, 4'hE: begin
o_field_last <= 3;
end
4'hB, 4'hF: begin
o_field_last <= 4;
end
endcase
end
if (do_block_Rn_A_C) begin
o_field_start <= 0;
o_field_last <= 15;
end
if (do_block_pointer_assign_exch) begin
o_field_start <= 0;
o_field_last <= i_nibble[3]?3:4;
end
if (do_block_mem_transfer && !do_fields_table) begin
o_field <= i_nibble[3]?`FT_FIELD_B:`FT_FIELD_A;
o_field_start <= 0;
o_field_last <= i_nibble[3]?1:4;
o_field_valid <= 1;
end
if (do_block_mem_transfer && do_fields_table && table_value) begin
o_field_start <= 0;
o_field_last <= i_nibble;
o_field_valid <= 1;
end
if (do_block_pointer_arith_const) begin
o_field_start <= 0;
o_field_last <= 4;
end
if (do_block_load_c_hex) begin
o_field_start <= i_reg_p;
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_80Cx) begin
o_field_start <= i_nibble;
o_field_last <= i_nibble;
end
if (do_block_Fx) begin
case (i_nibble)
4'h8, 4'h9, 4'hA, 4'hB: begin
o_field <= `FT_FIELD_A;
o_field_start <= 0;
o_field_last <= 4;
o_field_valid <= 1;
end
endcase
end
/******************************************************************************
*
* set field from a table
*
*
*****************************************************************************/
`ifdef DEBUG_FIELDS_TABLE
if (do_tables_a_f_b) begin
// debug info
$display("====== fields_table | table %h | nibble %b", o_fields_table, i_nibble);
$display("table_a : %b", table_a_nb_ok);
$display("table_b : %b", table_b_nb_ok);
$display("table_f_cond: %b", table_f_cond);
$display("table_f : %b", table_f_nb_ok);
// $display("table_f nbl : %h", {4{o_fields_table == `FT_TABLE_f}} );
//$display("table_f val : %h", table_f_nibble_value);
$display("case nibble : %h", table_a_f_b_case_value);
end
`endif
//
if (do_tables_a_f_b) begin
case (table_a_f_b_case_value)
4'h0: begin
o_field <= `FT_FIELD_P;
o_field_start <= i_reg_p;
o_field_last <= i_reg_p;
`ifdef DEBUG_FIELDS_TABLE
$display("fields_table: field P (%h)", i_reg_p);
`endif
end
4'h1: begin
o_field <= `FT_FIELD_WP;
o_field_start <= 0;
o_field_last <= i_reg_p;
`ifdef DEBUG_FIELDS_TABLE
$display("fields_table: field WP (0-%h)", i_reg_p);
`endif
end
4'h2: begin
o_field <= `FT_FIELD_XS;
o_field_start <= 2;
o_field_last <= 2;
`ifdef DEBUG_FIELDS_TABLE
$display("fields_table: field XS");
`endif
end
4'h3: begin
o_field <= `FT_FIELD_X;
o_field_start <= 0;
o_field_last <= 2;
`ifdef DEBUG_FIELDS_TABLE
$display("fields_table: field X");
`endif
end
4'h4: begin
o_field <= `FT_FIELD_S;
o_field_start <= 15;
o_field_last <= 15;
`ifdef DEBUG_FIELDS_TABLE
$display("fields_table: field S");
`endif
end
4'h5: begin
o_field <= `FT_FIELD_M;
o_field_start <= 3;
o_field_last <= 14;
`ifdef DEBUG_FIELDS_TABLE
$display("fields_table: field M");
`endif
end
4'h6: begin
o_field <= `FT_FIELD_B;
o_field_start <= 0;
o_field_last <= 1;
`ifdef DEBUG_FIELDS_TABLE
$display("fields_table: field B");
`endif
end
4'h7: begin
o_field <= `FT_FIELD_W;
o_field_start <= 0;
o_field_last <= 15;
`ifdef DEBUG_FIELDS_TABLE
$display("fields_table: field W");
`endif
end
4'hF: begin
o_field <= `FT_FIELD_A;
o_field_start <= 0;
o_field_last <= 4;
`ifdef DEBUG_FIELDS_TABLE
$display("fields_table: field A");
`endif
end
default: begin
o_dec_error <= 1;
`ifdef SIM
$display("fields_table: table %h nibble %h not handled", o_fields_table, i_nibble);
`endif
end
endcase
o_field_valid <= 1;
fields_table_done <= 1;
end
end

208
saturn_decoder_registers.v Normal file
View file

@ -0,0 +1,208 @@
/******************************************************************************
*
* set registers from instruction nibble
*
*****************************************************************************/
wire [4:0] reg_ABCD;
wire [4:0] reg_BCAC;
wire [4:0] reg_ABAC;
wire [4:0] reg_BCCD;
wire [4:0] reg_D0D1;
wire [4:0] reg_DAT0DAT1;
wire [4:0] reg_A_C;
assign reg_ABCD = { 3'b000, i_nibble[1:0]};
assign reg_BCAC = { 3'b000, i_nibble[0], !(i_nibble[1] || i_nibble[0])};
assign reg_ABAC = { 3'b000, i_nibble[1] && i_nibble[0], (!i_nibble[1]) && i_nibble[0]};
assign reg_BCCD = { 3'b000, i_nibble[1] || i_nibble[0], (!i_nibble[1]) ^ i_nibble[0]};
// assign reg_D0D1 = { 4'b0010, (i_nibble[0] && i_nibble[1]) || (i_nibble[2] && i_nibble[3])};
assign reg_D0D1 = { 4'b0010, i_nibble[0]};
assign reg_DAT0DAT1 = { 4'b1000, i_nibble[0]};
assign reg_A_C = { 3'b000, i_nibble[2], 1'b0};
always @(posedge i_clk) begin
if (i_reset) begin
o_reg_dest <= 0;
o_reg_src1 <= 0;
o_reg_src2 <= 0;
inval_opcode_regs <= 0;
end
if (do_on_first_nibble) begin
// reset values on instruction decode start
case (i_nibble)
4'h6: begin
o_reg_dest <= 0;
o_reg_src1 <= `ALU_REG_IMM;
o_reg_src2 <= 0;
end
default: begin
o_reg_dest <= 0;
o_reg_src1 <= 0;
o_reg_src2 <= 0;
end
endcase
inval_opcode_regs <= 0;
end
/************************************************************************
*
* set registers for specific instructions
*
************************************************************************/
if (do_block_0x) begin
case (i_nibble)
4'h6: begin
o_reg_dest <= `ALU_REG_RSTK;
o_reg_src1 <= `ALU_REG_C;
end
4'h7: begin
o_reg_dest <= `ALU_REG_C;
o_reg_src1 <= `ALU_REG_RSTK;
end
4'h8: o_reg_dest <= `ALU_REG_ST;
4'h9, 4'hB: begin
o_reg_dest <= `ALU_REG_C;
o_reg_src1 <= `ALU_REG_ST;
end
4'hA: begin
o_reg_dest <= `ALU_REG_ST;
o_reg_src1 <= `ALU_REG_C;
end
4'hC, 4'hD: begin
o_reg_dest <= `ALU_REG_P;
o_reg_src1 <= `ALU_REG_P;
end
default: begin
// inval_opcode_regs <= 1;
end
endcase
end
if (do_block_0Efx && !in_fields_table) begin
o_reg_dest <= i_nibble[2]?reg_BCAC:reg_ABCD;
o_reg_src1 <= i_nibble[2]?reg_BCAC:reg_ABCD;
o_reg_src2 <= i_nibble[2]?reg_ABCD:reg_BCAC;
end
if (do_block_1x) begin
case (i_nibble)
4'h6, 4'h8: begin
o_reg_dest <= `ALU_REG_D0;
o_reg_src1 <= `ALU_REG_D0;
end
4'h7, 4'hC: begin
o_reg_dest <= `ALU_REG_D1;
o_reg_src1 <= `ALU_REG_D1;
end
4'h9, 4'hA, 4'hB: begin
o_reg_dest <= `ALU_REG_D0;
o_reg_src1 <= `ALU_REG_IMM;
end
4'hD, 4'hE, 4'hF: begin
o_reg_dest <= `ALU_REG_D1;
o_reg_src1 <= `ALU_REG_IMM;
end
default: begin end
endcase
end
if (do_block_save_to_R_W) begin
o_reg_dest <= {2'b01, i_nibble[2:0]};
o_reg_src1 <= {3'b000, i_nibble[3]?2'b10:2'b00};
end
if (do_block_rest_from_R_W || do_block_exch_with_R_W) begin
o_reg_dest <= {3'b000, i_nibble[3]?2'b10:2'b00};
o_reg_src1 <= {2'b01, i_nibble[2:0]};
end
if (do_block_pointer_assign_exch) begin
o_reg_dest <= i_nibble[1]?reg_A_C:reg_D0D1;
o_reg_src1 <= i_nibble[1]?reg_D0D1:reg_A_C;
end
if (do_block_mem_transfer) begin
o_reg_dest <= i_nibble[1]?reg_A_C:reg_DAT0DAT1;
o_reg_src1 <= i_nibble[1]?reg_DAT0DAT1:reg_A_C;
end
if (do_block_pointer_arith_const) begin
o_reg_src2 <= `ALU_REG_IMM;
end
if (do_block_load_p) begin
o_reg_dest <= `ALU_REG_P;
o_reg_src1 <= `ALU_REG_IMM;
end
if (do_block_load_c_hex) 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_80Cx) begin
o_reg_dest <= `ALU_REG_C;
o_reg_src1 <= `ALU_REG_P;
o_reg_src2 <= 0;
end
if (do_block_82x) begin
o_reg_dest <= `ALU_REG_HST;
o_reg_src1 <= `ALU_REG_HST;
o_reg_src2 <= `ALU_REG_IMM;
end
if (do_block_Abx) begin
case ({i_nibble[3],i_nibble[2]})
2'b00: begin
o_reg_dest <= reg_ABCD;
o_reg_src1 <= `ALU_REG_ZERO;
end
2'b01: begin
o_reg_dest <= reg_ABCD;
o_reg_src1 <= reg_BCAC;
end
2'b10: begin
o_reg_dest <= reg_BCAC;
o_reg_src1 <= reg_ABCD;
end
2'b11: begin
o_reg_dest <= reg_ABAC;
o_reg_src1 <= reg_BCCD;
end
endcase
o_reg_src2 <= 0;
end
if (do_block_Fx) begin
case (i_nibble)
4'h8, 4'h9, 4'hA, 4'hB: begin
o_reg_dest <= reg_ABCD;
o_reg_src1 <= reg_ABCD;
o_reg_src2 <= 0;
end
endcase
end
end