diff --git a/history.txt b/history.txt index 9594315..ce88e68 100644 --- a/history.txt +++ b/history.txt @@ -1,27 +1,28 @@ 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: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: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 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: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: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 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: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 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 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: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-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-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 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: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 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 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: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 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 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 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: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 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 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 -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 \ No newline at end of file diff --git a/saturn_core.v b/saturn_core.v index 676df53..a6a17c9 100644 --- a/saturn_core.v +++ b/saturn_core.v @@ -105,7 +105,6 @@ saturn_decoder m_decoder ( .o_reg_src1 (reg_src1), .o_reg_src2 (reg_src2), - .o_direction (direction), .o_ins_rtn (ins_rtn), .o_set_xm (set_xm), .o_set_carry (set_carry), @@ -136,7 +135,6 @@ wire [4:0] reg_dest; wire [4:0] reg_src1; wire [4:0] reg_src2; -wire direction; wire ins_rtn; wire set_xm; wire set_carry; @@ -278,7 +276,7 @@ always @(posedge clk) begin en_inst_exec <= 0; clock_end <= 0; cycle_ctr <= ~0; - max_cycle <= 100; + max_cycle <= 140; `ifndef SIM led[7:0] <= reg_pc[7:0]; `endif diff --git a/saturn_decoder.v b/saturn_decoder.v index 00ef924..e87358d 100644 --- a/saturn_decoder.v +++ b/saturn_decoder.v @@ -8,57 +8,31 @@ `include "def-alu.v" module saturn_decoder( - i_clk, - i_reset, - i_cycles, - i_en_dbg, - i_en_dec, - i_stalled, - i_pc, - i_nibble, + i_clk, i_reset, i_cycles, i_en_dbg, i_en_dec, i_stalled, + i_pc, i_nibble, i_reg_p, - o_inc_pc, - o_push, - o_pop, + o_inc_pc, o_push, o_pop, o_dec_error, `ifdef SIM o_unimplemented, `endif o_alu_debug, - o_ins_addr, - o_ins_decoded, + o_ins_addr, o_ins_decoded, - o_fields_table, - o_field, - o_field_valid, - o_field_start, - o_field_last, + o_fields_table, o_field, o_field_valid, o_field_start, o_field_last, o_imm_value, - o_alu_op, - o_alu_no_stall, - o_reg_dest, - o_reg_src1, - o_reg_src2, + o_alu_op, o_alu_no_stall, o_reg_dest, o_reg_src1, o_reg_src2, - o_direction, - o_ins_rtn, - o_set_xm, - o_set_carry, - o_en_intr, - o_test_carry, - o_carry_val, - o_ins_set_mode, - o_mode_dec, + o_ins_rtn, o_set_xm, o_en_intr, + o_set_carry, o_test_carry, o_carry_val, + o_ins_set_mode, o_mode_dec, o_ins_alu_op, - o_dbg_nibbles, - o_dbg_nb_nbls, - o_mem_load, - o_mem_pos + o_dbg_nibbles, 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_src2; -// generic -output reg o_direction; - // rtn specific output reg o_ins_rtn; output reg o_set_xm; @@ -150,262 +121,7 @@ initial begin `endif end -/* - * 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 +`include "saturn_decoder_debugger.v" /****************************************************************************** * @@ -417,36 +133,6 @@ end // general variables 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 decoder_active; 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_other_nibbles = decoder_active && next_nibble; -wire do_block_0x; -wire do_block_0Efx; -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; +// all regs and wires for the decoder states +`include "saturn_decoder_block_vars.v" /* * variables specific to a particular use @@ -640,9 +261,6 @@ always @(posedge i_clk) begin o_alu_op <= 0; o_alu_no_stall <= 0; - // cleanup - o_direction <= 0; - o_ins_rtn <= 0; o_set_xm <= 0; o_set_carry <= 0; @@ -1080,489 +698,8 @@ always @(posedge i_clk) begin end - -/****************************************************************************** -* -* 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 +`include "saturn_decoder_registers.v" +`include "saturn_decoder_fields.v" endmodule \ No newline at end of file diff --git a/saturn_decoder_block_vars.v b/saturn_decoder_block_vars.v new file mode 100644 index 0000000..82603e8 --- /dev/null +++ b/saturn_decoder_block_vars.v @@ -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; diff --git a/saturn_decoder_debugger.v b/saturn_decoder_debugger.v new file mode 100644 index 0000000..723b358 --- /dev/null +++ b/saturn_decoder_debugger.v @@ -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 diff --git a/saturn_decoder_fields.v b/saturn_decoder_fields.v new file mode 100644 index 0000000..5cef539 --- /dev/null +++ b/saturn_decoder_fields.v @@ -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 diff --git a/saturn_decoder_registers.v b/saturn_decoder_registers.v new file mode 100644 index 0000000..02c0775 --- /dev/null +++ b/saturn_decoder_registers.v @@ -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