From bb0654126adfd7974d351be50f63be3e377e354e Mon Sep 17 00:00:00 2001 From: Raphael Jacquot Date: Mon, 2 Sep 2019 13:20:50 +0200 Subject: [PATCH] add more jump code (hairy) --- saturn_bus.v | 2 +- saturn_control_unit.v | 148 +++++++++++++++++++++++++++++++----------- saturn_def_alu.v | 24 +++---- saturn_inst_decoder.v | 112 +++++++++++++++++++++++++++++--- saturn_regs_pc_rstk.v | 29 +++++++-- view | 2 +- 6 files changed, 250 insertions(+), 67 deletions(-) diff --git a/saturn_bus.v b/saturn_bus.v index e8aa6d8..538cf2f 100644 --- a/saturn_bus.v +++ b/saturn_bus.v @@ -237,7 +237,7 @@ always @(posedge i_clk) begin end `ifdef SIM - if (cycle_ctr == 370) begin + if (cycle_ctr == 379) begin bus_halt <= 1'b1; $display("BUS %0d: [%d] enough cycles for now", phase, cycle_ctr); end diff --git a/saturn_control_unit.v b/saturn_control_unit.v index ea06078..1ffa12a 100644 --- a/saturn_control_unit.v +++ b/saturn_control_unit.v @@ -97,13 +97,14 @@ assign o_error = control_unit_error || dec_error; output wire [0:0] o_alu_busy; output wire [0:0] o_exec_unit_busy; assign o_alu_busy = inst_alu_other || alu_start; -assign o_exec_unit_busy = i_bus_busy || - alu_busy || - jump_busy || - rtn_busy || +assign o_exec_unit_busy = i_bus_busy || + alu_busy || + jump_busy || + rtn_busy || + test_jump_busy || mem_read_busy || mem_write_busy || - reset_busy || + reset_busy || config_busy; /* debugger interface */ @@ -219,8 +220,9 @@ wire [0:0] dec_error; wire [0:0] inst_alu = (dec_instr_type == `INSTR_TYPE_ALU); wire [0:0] inst_jump = (dec_instr_type == `INSTR_TYPE_JUMP); wire [0:0] inst_rtn = (dec_instr_type == `INSTR_TYPE_RTN); -wire [0:0] inst_mem_read = (dec_instr_type == `INSTR_TYPE_MEM_READ); -wire [0:0] inst_mem_write = (dec_instr_type == `INSTR_TYPE_MEM_WRITE); +wire [0:0] inst_test_jump = (dec_instr_type == `INSTR_TYPE_TEST_JUMP); +wire [0:0] inst_mem_read = (dec_instr_type == `INSTR_TYPE_MEM_READ); +wire [0:0] inst_mem_write = (dec_instr_type == `INSTR_TYPE_MEM_WRITE); wire [0:0] inst_reset = (dec_instr_type == `INSTR_TYPE_RESET); wire [0:0] inst_config = (dec_instr_type == `INSTR_TYPE_CONFIG); @@ -231,28 +233,35 @@ wire [0:0] reg_dest_p = (dec_alu_reg_dest == `ALU_REG_P); wire [0:0] reg_src_1_a = (dec_alu_reg_src_1 == `ALU_REG_A); wire [0:0] reg_src_1_c = (dec_alu_reg_src_1 == `ALU_REG_C); +wire [0:0] reg_src_1_st = (dec_alu_reg_src_1 == `ALU_REG_ST); wire [0:0] reg_src_1_p = (dec_alu_reg_src_1 == `ALU_REG_P); wire [0:0] reg_src_1_imm = (dec_alu_reg_src_1 == `ALU_REG_IMM); +wire [0:0] reg_src_2_imm = (dec_alu_reg_src_2 == `ALU_REG_IMM); + wire [0:0] aluop_zero = inst_alu && (dec_alu_opcode == `ALU_OP_ZERO); wire [0:0] aluop_copy = inst_alu && (dec_alu_opcode == `ALU_OP_COPY); wire [0:0] aluop_clr_mask = inst_alu && (dec_alu_opcode == `ALU_OP_CLR_MASK); +wire [0:0] aluop_test_bit = inst_alu && (dec_alu_opcode == `ALU_OP_TEST_BIT); -wire [0:0] inst_alu_p_eq_n = aluop_copy && reg_dest_p && reg_src_1_imm; -wire [0:0] inst_alu_c_eq_p_n = aluop_copy && reg_dest_c && reg_src_1_p; -wire [0:0] inst_alu_clrhst_n = aluop_clr_mask && reg_dest_hst && reg_src_1_imm; -wire [0:0] inst_alu_st_eq_01_n = aluop_copy && reg_dest_st && reg_src_1_imm; +wire [0:0] inst_alu_p_eq_n = aluop_copy && reg_dest_p && reg_src_1_imm; +wire [0:0] inst_alu_c_eq_p_n = aluop_copy && reg_dest_c && reg_src_1_p; +wire [0:0] inst_alu_clrhst_n = aluop_clr_mask && reg_dest_hst && reg_src_1_imm; +wire [0:0] inst_alu_st_eq_01_n = aluop_copy && reg_dest_st && reg_src_1_imm; +wire [0:0] inst_alu_st_test_bit = aluop_test_bit && reg_src_1_st && reg_src_2_imm; wire [0:0] inst_alu_other = inst_alu && !(inst_alu_p_eq_n || inst_alu_c_eq_p_n || inst_alu_clrhst_n || - inst_alu_st_eq_01_n + inst_alu_st_eq_01_n || + inst_alu_st_test_bit ); wire [0:0] alu_busy = inst_alu_other || alu_start; wire [0:0] jump_busy = (inst_jump && dec_instr_decoded) || send_reg_PC || just_reset; wire [0:0] rtn_busy = (inst_rtn && dec_instr_decoded) || send_reg_PC; +wire [0:0] test_jump_busy = (inst_test_jump && dec_instr_decoded) || send_reg_PC; wire [0:0] mem_read_busy = inst_mem_read || exec_mem_read; wire [0:0] mem_write_busy = inst_mem_write || exec_mem_write; wire [0:0] reset_busy = inst_reset; @@ -280,6 +289,7 @@ saturn_regs_pc_rstk regs_pc_rstk ( .i_jump_length (dec_jump_length), .i_block_0x (dec_block_0x), .i_push_pc (dec_push_pc), + .i_test_jump (inst_test_jump), .o_current_pc (reg_PC), @@ -356,9 +366,40 @@ reg [3:0] alu_imm_value; wire [0:0] alu_run = alu_calc_run || alu_save_run; wire [0:0] alu_done = alu_calc_done || alu_save_done; -/* - * should we reload the PC after it has been changed - */ +/************************************************************************************************** + * + * wires to pre-calculate ALU operation values + * + *************************************************************************************************/ + +/* alu operation tests */ +`ifdef SIM +wire [0:0] aluop_test_eq = alu_opcode == `ALU_OP_TEST_EQ; +wire [0:0] aluop_test_neq = alu_opcode == `ALU_OP_TEST_NEQ; +wire [0:0] aluop_test = aluop_test_eq || aluop_test_neq; +`endif + +/* addition */ +wire [0:0] op_bin_add_carry = (alu_calc_pos == alu_ptr_begin) ? 1'b0 : alu_calc_carry; +wire [4:0] op_bin_add_res = alu_prep_src_1_val + alu_prep_src_2_val + {3'b000, op_bin_add_carry }; +wire [3:0] op_bin_add_res_value = op_bin_add_res[3:0]; +wire [0:0] op_bin_add_next_carry = op_bin_add_res[4]; +wire [0:0] op_dec_add_sup_9 = op_bin_add_res_value[3] & ( | op_bin_add_res_value[2:1] ); +wire [4:0] op_dec_add_res = op_bin_add_res_value + op_dec_add_sup_9 ? 4'h6 : 4'h0; +wire [3:0] op_dec_add_res_value = op_dec_add_res[3:0]; +wire [0:0] op_dec_add_next_carry = op_bin_add_next_carry | op_dec_add_res[4]; + +/* test not equal */ + +wire [0:0] op_test_neq_carry = (alu_calc_pos == alu_ptr_begin) ? 1'b0 : alu_calc_carry; +wire [0:0] op_test_neq_next_carry = | (alu_prep_src_1_val ^ alu_prep_src_2_val) || op_test_neq_carry; + + +/************************************************************************************************** + * + * read register nibble values for the debugger + * + *************************************************************************************************/ always @(i_dbg_register, i_dbg_reg_ptr) begin case (i_dbg_register) @@ -482,6 +523,7 @@ always @(posedge i_clk) begin if (i_clk_en && control_unit_ready) begin if (i_phases[3] && !i_bus_busy && dec_instr_execute) begin + $display("CTRL %0d: [%d] instr %0d", i_phase, i_cycle_ctr, dec_instr_type); case (dec_instr_type) `INSTR_TYPE_NOP: begin $display("CTRL %0d: [%d] NOP instruction", i_phase, i_cycle_ctr); @@ -524,6 +566,12 @@ always @(posedge i_clk) begin reg_ST[dec_alu_ptr_begin] <= dec_alu_imm_value[0]; end + /* 8[67]x ?ST=[01] n */ + if (inst_alu_st_test_bit) begin + $display("CTRL %0d: [%d] exec : ?ST=%b %h", i_phase, i_cycle_ctr, dec_alu_imm_value[0], dec_alu_ptr_begin); + reg_CARRY <= !(reg_ST[dec_alu_ptr_begin] == dec_alu_imm_value[0]); + end + /* * the general case */ @@ -566,7 +614,8 @@ always @(posedge i_clk) begin reg_alu_mode <= dec_alu_imm_value[0]; end `INSTR_TYPE_JUMP, - `INSTR_TYPE_RTN: + `INSTR_TYPE_RTN, + `INSTR_TYPE_TEST_JUMP: begin if (inst_jump) begin $display("CTRL %0d: [%d] JUMP", i_phase, i_cycle_ctr); @@ -575,7 +624,7 @@ always @(posedge i_clk) begin $display("CTRL %0d: [%d] RTN", i_phase, i_cycle_ctr); case (dec_alu_opcode) `ALU_OP_NOP: begin end - `ALU_OP_SET_CRY: reg_CARRY <= o_alu_imm_value[0]; + `ALU_OP_SET_CRY: reg_CARRY <= dec_alu_imm_value[0]; default: begin $display("CTRL %0d: [%d] alu_opcode for RTN %0d", i_phase, i_cycle_ctr, dec_alu_opcode); @@ -583,8 +632,13 @@ always @(posedge i_clk) begin end endcase end + if (dec_instr_decoded && inst_test_jump) begin + $write("CTRL %0d: [%d] TEST-JUMP (c %b | imm %b) ", i_phase, i_cycle_ctr, reg_CARRY, dec_alu_imm_value[0]); + if (reg_CARRY ^ dec_alu_imm_value[0]) $write("NO-"); + $write("exec\n"); + end - if (dec_instr_decoded) begin + if (dec_instr_decoded && (!inst_test_jump || (inst_test_jump && !(reg_CARRY ^ dec_alu_imm_value[0])))) begin $display("CTRL %0d: [%d] exec : JUMP/RTN reload pc to %5h", i_phase, i_cycle_ctr, reg_PC); bus_program[bus_prog_addr] <= {2'b01, `BUSCMD_LOAD_PC }; bus_prog_addr <= bus_prog_addr + 5'd1; @@ -708,18 +762,23 @@ always @(posedge i_clk) begin $display("ALU_PREP %0d: [%d] b %h | p %h | e %h", i_phase, i_cycle_ctr, alu_ptr_begin, alu_prep_pos, alu_ptr_end); case (dec_alu_reg_src_1) - `ALU_REG_A: alu_prep_src_1_val <= reg_A[alu_prep_pos]; - `ALU_REG_B: alu_prep_src_1_val <= reg_B[alu_prep_pos]; - `ALU_REG_C: alu_prep_src_1_val <= reg_C[alu_prep_pos]; - `ALU_REG_D: alu_prep_src_1_val <= reg_D[alu_prep_pos]; + `ALU_REG_A: alu_prep_src_1_val <= reg_A[alu_prep_pos]; + `ALU_REG_B: alu_prep_src_1_val <= reg_B[alu_prep_pos]; + `ALU_REG_C: alu_prep_src_1_val <= reg_C[alu_prep_pos]; + `ALU_REG_D: alu_prep_src_1_val <= reg_D[alu_prep_pos]; + `ALU_REG_D0: alu_prep_src_1_val <= reg_D0[alu_prep_pos[2:0]]; + `ALU_REG_D1: alu_prep_src_1_val <= reg_D1[alu_prep_pos[2:0]]; default: $display("ALU_PREP %0d: [%d] unhandled src1 register %0d", i_phase, i_cycle_ctr, dec_alu_reg_src_1); endcase case (dec_alu_reg_src_2) - `ALU_REG_A: alu_prep_src_2_val <= reg_A[alu_prep_pos]; - `ALU_REG_B: alu_prep_src_2_val <= reg_B[alu_prep_pos]; - `ALU_REG_C: alu_prep_src_2_val <= reg_C[alu_prep_pos]; - `ALU_REG_D: alu_prep_src_2_val <= reg_D[alu_prep_pos]; + `ALU_REG_A: alu_prep_src_2_val <= reg_A[alu_prep_pos]; + `ALU_REG_B: alu_prep_src_2_val <= reg_B[alu_prep_pos]; + `ALU_REG_C: alu_prep_src_2_val <= reg_C[alu_prep_pos]; + `ALU_REG_D: alu_prep_src_2_val <= reg_D[alu_prep_pos]; + `ALU_REG_D0: alu_prep_src_1_val <= reg_D0[alu_prep_pos[2:0]]; + `ALU_REG_D1: alu_prep_src_1_val <= reg_D1[alu_prep_pos[2:0]]; + `ALU_REG_IMM: alu_prep_src_1_val <= alu_imm_value; `ALU_REG_NONE: begin end default: $display("ALU_PREP %0d: [%d] unhandled src2 register %0d", i_phase, i_cycle_ctr, dec_alu_reg_src_2); endcase @@ -761,11 +820,15 @@ always @(posedge i_clk) begin `ALU_OP_ADD: begin $display("ALU_CALC %0d: [%d] add | s1 %b | s2 %b | c %b | res %b | nc %b", i_phase, i_cycle_ctr, - alu_prep_src_1_val, alu_prep_src_2_val, {3'b0, alu_prep_carry}, - alu_prep_src_1_val + alu_prep_src_2_val + {3'b0, alu_prep_carry}, - alu_prep_src_1_val[3] && alu_prep_src_2_val[3] ); - alu_calc_res_1_val <= alu_prep_src_1_val + alu_prep_src_2_val + {3'b0, alu_prep_carry}; - alu_calc_carry <= alu_prep_src_1_val[3] && alu_prep_src_2_val[3]; + alu_prep_src_1_val, alu_prep_src_2_val, op_bin_add_carry, op_bin_add_res, op_bin_add_next_carry); + alu_calc_res_1_val <= op_bin_add_res_value; + alu_calc_carry <= op_bin_add_next_carry; + end + `ALU_OP_TEST_NEQ: + begin + $display("ALU_CALC %0d: [%d] test_neq | s1 %b | s2 %b | c %b | nc %b", i_phase, i_cycle_ctr, + alu_prep_src_1_val, alu_prep_src_2_val, op_test_neq_carry, op_test_neq_next_carry); + alu_calc_carry <= op_test_neq_next_carry; end default: $display("ALU_CALC %0d: [%d] unhandled opcode %0d", i_phase, i_cycle_ctr, alu_opcode); endcase @@ -793,12 +856,18 @@ always @(posedge i_clk) begin alu_reg_src_1, alu_reg_src_2, alu_reg_dest); case (alu_reg_dest) - `ALU_REG_A: reg_A[alu_save_pos] <= alu_calc_res_1_val; - `ALU_REG_B: reg_B[alu_save_pos] <= alu_calc_res_1_val; - `ALU_REG_C: reg_C[alu_save_pos] <= alu_calc_res_1_val; - `ALU_REG_D: reg_D[alu_save_pos] <= alu_calc_res_1_val; - `ALU_REG_D0: reg_D0[alu_save_pos[2:0]] <= alu_calc_res_1_val; - `ALU_REG_D1: reg_D1[alu_save_pos[2:0]] <= alu_calc_res_1_val; + `ALU_REG_A: reg_A[alu_save_pos] <= alu_calc_res_1_val; + `ALU_REG_B: reg_B[alu_save_pos] <= alu_calc_res_1_val; + `ALU_REG_C: reg_C[alu_save_pos] <= alu_calc_res_1_val; + `ALU_REG_D: reg_D[alu_save_pos] <= alu_calc_res_1_val; + `ALU_REG_D0: reg_D0[alu_save_pos[2:0]] <= alu_calc_res_1_val; + `ALU_REG_D1: reg_D1[alu_save_pos[2:0]] <= alu_calc_res_1_val; + `ALU_REG_NONE: + begin +`ifdef SIM + if (!aluop_test) $display("ALU_SAVE %0d: [%d] dest register %0d not supported for op %0d", i_phase, i_cycle_ctr, alu_reg_dest, alu_opcode); +`endif + end default: $display("ALU_SAVE %0d: [%d] dest register %0d not supported", i_phase, i_cycle_ctr, alu_reg_dest); endcase @@ -816,8 +885,9 @@ always @(posedge i_clk) begin alu_prep_carry <= alu_calc_carry; case (alu_opcode) // this may not be correct, need to check on the HP 49G - `ALU_OP_2CMPL: reg_CARRY <= reg_CARRY || ( | alu_calc_res_1_val); - `ALU_OP_ADD : reg_CARRY <= alu_calc_carry; + `ALU_OP_2CMPL: reg_CARRY <= reg_CARRY || ( | alu_calc_res_1_val); + `ALU_OP_ADD : reg_CARRY <= alu_calc_carry; + `ALU_OP_TEST_NEQ : reg_CARRY <= alu_calc_carry; default: begin end endcase diff --git a/saturn_def_alu.v b/saturn_def_alu.v index bf3c588..1d76562 100644 --- a/saturn_def_alu.v +++ b/saturn_def_alu.v @@ -56,12 +56,13 @@ // tests `define ALU_OP_TEST_EQ 15 `define ALU_OP_TEST_NEQ 16 +`define ALU_OP_TEST_BIT 17 // relative jump -`define ALU_OP_JMP_REL2 17 -`define ALU_OP_JMP_REL3 18 -`define ALU_OP_JMP_REL4 19 -`define ALU_OP_JMP_ABS5 20 -`define ALU_OP_CLR_MASK 21 +`define ALU_OP_JMP_REL2 18 +`define ALU_OP_JMP_REL3 19 +`define ALU_OP_JMP_REL4 20 +`define ALU_OP_JMP_ABS5 21 +`define ALU_OP_CLR_MASK 22 `define ALU_OP_SET_CRY 28 `define ALU_OP_TEST_GO 30 @@ -119,12 +120,13 @@ `define INSTR_TYPE_SET_MODE 2 `define INSTR_TYPE_JUMP 3 `define INSTR_TYPE_RTN 4 -`define INSTR_TYPE_LOAD_LENGTH 5 -`define INSTR_TYPE_LOAD 6 -`define INSTR_TYPE_MEM_READ 7 -`define INSTR_TYPE_MEM_WRITE 8 -`define INSTR_TYPE_CONFIG 9 -`define INSTR_TYPE_RESET 10 +`define INSTR_TYPE_TEST_JUMP 5 +`define INSTR_TYPE_LOAD_LENGTH 6 +`define INSTR_TYPE_LOAD 7 +`define INSTR_TYPE_MEM_READ 8 +`define INSTR_TYPE_MEM_WRITE 9 +`define INSTR_TYPE_CONFIG 10 +`define INSTR_TYPE_RESET 11 `define INSTR_TYPE_NONE 15 diff --git a/saturn_inst_decoder.v b/saturn_inst_decoder.v index f4725ae..3f30d28 100644 --- a/saturn_inst_decoder.v +++ b/saturn_inst_decoder.v @@ -148,6 +148,8 @@ reg [0:0] block_80x; reg [0:0] block_80Cx; reg [0:0] block_82x; reg [0:0] block_84x_85x; +reg [0:0] block_86x_87x; +reg [0:0] block_8Ax; reg [0:0] block_Ax; reg [0:0] block_Aax; reg [0:0] block_Abx; @@ -167,6 +169,7 @@ reg [3:0] load_counter; reg [3:0] load_count; reg [1:0] fields_table; reg [0:0] read_write; +reg [0:0] instr_test; /* * initialization @@ -182,7 +185,7 @@ initial begin o_alu_imm_value = 4'b0; o_alu_opcode = `ALU_OP_NOP; - o_instr_type = 4'd15; + o_instr_type = `INSTR_TYPE_NONE; o_push_pc = 1'd0; o_instr_decoded = 1'b0; o_instr_execute = 1'b0; @@ -208,6 +211,8 @@ initial begin block_80Cx = 1'b0; block_82x = 1'b0; block_84x_85x = 1'b0; + block_86x_87x = 1'b0; + block_8Ax = 1'b0; block_Ax = 1'b0; block_Aax = 1'b0; block_Abx = 1'b0; @@ -224,6 +229,7 @@ initial begin load_counter = 4'd0; load_count = 4'd0; fields_table = `FT_NONE; + instr_test = 1'b0; /* last line of defense */ o_decoder_error = 1'b0; @@ -240,6 +246,23 @@ wire [4:0] regs_BCAC = { 3'b000, i_nibble[0], !(i_nibble[1] | i_nibble[0]) }; wire [4:0] regs_ABAC = { 3'b000, i_nibble[1] & i_nibble[0], !i_nibble[1] & i_nibble[0] }; wire [4:0] regs_BCCD = { 3'b000, i_nibble[1] | i_nibble[0], !i_nibble[1] ^ i_nibble[0] }; +/**************************** + * + * wires for test instructions + * + */ + +wire [0:0] is_instr_alu = (o_instr_type == `INSTR_TYPE_ALU); +wire [0:0] is_aluop_test_eq = (o_alu_opcode == `ALU_OP_TEST_EQ); +wire [0:0] is_aluop_test_neq = (o_alu_opcode == `ALU_OP_TEST_NEQ); +wire [0:0] is_aluop_test_bit = (o_alu_opcode == `ALU_OP_TEST_BIT); + +wire [0:0] is_instr_test_eq = is_instr_alu && is_aluop_test_eq; +wire [0:0] is_instr_test_neq = is_instr_alu && is_aluop_test_neq; +wire [0:0] is_instr_test_bit = is_instr_alu && is_aluop_test_bit; + +wire [0:0] is_instr_test = is_instr_test_eq || is_instr_test_neq || is_instr_test_bit; + /**************************** * * main process @@ -266,6 +289,8 @@ always @(posedge i_clk) begin o_instr_pc <= i_current_pc; /* set the instruction to NOP, to avoid any stray processes */ o_instr_type <= `INSTR_TYPE_NOP; + + /* now, if we had a test instruction previously, we are in rel2 mode now */ end if (i_phases[2] && !decode_started) begin @@ -491,6 +516,16 @@ always @(posedge i_clk) begin o_instr_type <= `INSTR_TYPE_ALU; block_84x_85x <= 1'b1; end + 4'h6, 4'h7: + begin + o_alu_opcode <= `ALU_OP_TEST_BIT; + o_alu_reg_dest <= `ALU_REG_NONE; + o_alu_reg_src_1 <= `ALU_REG_ST; + o_alu_reg_src_2 <= `ALU_REG_IMM; + o_alu_imm_value <= {3'b0, i_nibble[0]}; + block_86x_87x <= 1'b1; + end + 4'hA: block_8Ax <= 1'b1; 4'hD, 4'hF: /* GOVLNG or GOSBVL */ begin o_instr_type <= `INSTR_TYPE_JUMP; @@ -583,6 +618,35 @@ always @(posedge i_clk) begin block_84x_85x <= 1'b0; end + if (block_86x_87x) begin + $display("DECODER %0d: [%d] block_86x_87x test_bit %h", i_phase, i_cycle_ctr, i_nibble); + o_instr_type <= `INSTR_TYPE_ALU; + o_alu_ptr_begin <= i_nibble; + o_alu_ptr_end <= i_nibble; + o_instr_decoded <= 1'b1; + o_instr_execute <= 1'b1; + /* execution is immediate, set this bit */ + instr_test <= 1'b1; + decode_started <= 1'b0; + block_86x_87x <= 1'b0; + end + + if (block_8Ax) begin + o_instr_type <= `INSTR_TYPE_ALU; + o_alu_opcode <= i_nibble[2] ? `ALU_OP_TEST_NEQ : `ALU_OP_TEST_EQ; + o_alu_reg_dest <= `ALU_REG_NONE; + o_alu_reg_src_1 <= i_nibble[3] ? regs_ABCD : regs_BCAC; + o_alu_reg_src_2 <= i_nibble[3] ? `ALU_REG_IMM : regs_ABCD; + o_alu_imm_value <= 4'h0; + o_alu_field <= `FT_FIELD_A; + o_alu_ptr_begin <= 4'h0; + o_alu_ptr_end <= 4'h4; + o_instr_decoded <= 1'b1; + o_instr_execute <= 1'b1; + decode_started <= 1'b0; + block_8Ax <= 1'b0; + end + if (block_Ax) begin $display("DECODER %0d: [%d] block_Ax %h", i_phase, i_cycle_ctr, i_nibble); /* work here is done by the block_FIELDS */ @@ -795,22 +859,51 @@ always @(posedge i_clk) begin end /* o_instr_decoded goes away only when the ALU is not busy anymore */ - if (i_phases[3] && o_instr_decoded) begin - $display("DECODER %0d: [%d] decoder cleanup 1", i_phase, i_cycle_ctr); - o_instr_decoded <= 1'b0; - end + // if (i_phases[3] && o_instr_decoded) begin + // $display("DECODER %0d: [%d] decoder cleanup 2 (test %b)", i_phase, i_cycle_ctr, instr_test); + // o_instr_decoded <= 1'b0; + // if (instr_test) begin + // $display("DECODER %0d: [%d] jump after test", i_phase, i_cycle_ctr); + // instr_test <= 1'b0; + // o_instr_type <= `INSTR_TYPE_TEST_JUMP; + // o_jump_length <= 3'd1; + // jump_counter <= 3'd0; + // o_alu_imm_value <= 4'h1; + // decode_started <= 1'b1; + // o_instr_execute <= 1'b1; + // block_JUMP <= 1'b1; + // end + // end end if (i_clk_en && !i_bus_busy) begin /* decoder cleanup only after the instruction is completely decoded and execution has started */ - if (i_phases[3] && o_instr_decoded) begin - $display("DECODER %0d: [%d] decoder cleanup 2", i_phase, i_cycle_ctr); + if (i_phases[3] && o_instr_decoded && !(& o_instr_type)) begin + $display("DECODER %0d: [%d] decoder cleanup 1 (instr %0d, exec %b, is_test %b)", i_phase, i_cycle_ctr, o_instr_type, o_instr_execute, is_instr_test); fields_table <= `FT_NONE; o_alu_field <= `FT_FIELD_NONE; o_instr_execute <= 1'b0; o_instr_type <= `INSTR_TYPE_NONE; o_push_pc <= 1'b0; + instr_test <= is_instr_test; + end + + + if (i_phases[3] && !i_exec_unit_busy && o_instr_decoded) begin + $display("DECODER %0d: [%d] decoder cleanup 2 (test %b)", i_phase, i_cycle_ctr, instr_test); + o_instr_decoded <= 1'b0; + if (instr_test) begin + $display("DECODER %0d: [%d] jump after test", i_phase, i_cycle_ctr); + instr_test <= 1'b0; + o_instr_type <= `INSTR_TYPE_TEST_JUMP; + o_jump_length <= 3'd1; + jump_counter <= 3'd0; + o_alu_imm_value <= 4'h1; + decode_started <= 1'b1; + o_instr_execute <= 1'b1; + block_JUMP <= 1'b1; + end end end @@ -826,7 +919,7 @@ always @(posedge i_clk) begin o_alu_imm_value <= 4'b0; o_alu_opcode <= `ALU_OP_NOP; - o_instr_type <= 4'd15; + o_instr_type <= `INSTR_TYPE_NONE; o_push_pc <= 1'b0; o_instr_decoded <= 1'b0; o_instr_execute <= 1'b0; @@ -852,6 +945,8 @@ always @(posedge i_clk) begin block_80Cx <= 1'b0; block_82x <= 1'b0; block_84x_85x <= 1'b0; + block_86x_87x <= 1'b0; + block_8Ax <= 1'b0; block_Ax <= 1'b0; block_Aax <= 1'b0; block_Abx <= 1'b0; @@ -868,6 +963,7 @@ always @(posedge i_clk) begin load_counter <= 4'd0; load_count <= 4'd0; fields_table <= `FT_NONE; + instr_test <= 1'b0; /* invalid instruction */ o_decoder_error <= 1'b0; diff --git a/saturn_regs_pc_rstk.v b/saturn_regs_pc_rstk.v index 92bcc9c..9f53686 100644 --- a/saturn_regs_pc_rstk.v +++ b/saturn_regs_pc_rstk.v @@ -36,6 +36,7 @@ module saturn_regs_pc_rstk ( i_jump_length, i_block_0x, i_push_pc, + i_test_jump, o_current_pc, o_reload_pc, @@ -66,6 +67,7 @@ input wire [0:0] i_jump_instr; input wire [2:0] i_jump_length; input wire [0:0] i_block_0x; input wire [0:0] i_push_pc; +input wire [0:0] i_test_jump; output wire [19:0] o_current_pc; output reg [0:0] o_reload_pc; @@ -83,7 +85,7 @@ assign o_reg_rstk_ptr = reg_rstk_ptr; * *************************************************************************************************/ -wire [0:0] do_jump_instr = !just_reset && i_jump_instr; +wire [0:0] do_jump_instr = !just_reset && (i_jump_instr || i_test_jump) ; /* * local variables @@ -103,7 +105,10 @@ wire [0:0] jump_rel4 = i_jump_instr && (i_jump_length == 3'd3); wire [0:0] jump_relative = jump_rel2 || jump_rel3 || jump_rel4; /* this appears to be SLOW */ -wire [0:0] is_rtn = i_phases[2] && i_block_0x && !i_nibble[3] && !i_nibble[2]; +wire [0:0] is_inst_rtn = !i_test_jump && i_block_0x && !i_nibble[3] && !i_nibble[2]; +wire [0:0] is_rtnyes = i_test_jump && !(| jump_next_offset[7:0]); +wire [0:0] do_rtn = i_phases[2] && is_inst_rtn; +wire [0:0] do_rtnyes = i_phases[2] && is_rtnyes; reg [19:0] jump_next_offset; @@ -123,6 +128,7 @@ reg [19:0] reg_PC; reg [2:0] reg_rstk_ptr; reg [19:0] reg_RSTK[0:7]; +reg [19:0] prev_PC; reg [2:0] rstk_ptr_to_push_at; reg [19:0] addr_to_return_to; reg [2:0] rstk_ptr_after_pop; @@ -141,6 +147,11 @@ initial begin addr_to_return_to = 20'b0; rstk_ptr_after_pop = 3'd0; rstk_ptr_to_push_at = 3'd0; + + $monitor ("PC_RSTK %0d: [%d] bus_busy %b | exec_unit_busy %b | j_cnt %h | i_jump %b | do_jmp %b | is_rtnyes %b | block_0x %b | nibble %h | test_jmp %b | offset[7:0] %h", + i_phase, i_cycle_ctr, i_bus_busy, i_exec_unit_busy, + jump_counter, i_jump_instr, do_jump_instr, is_rtnyes, + i_block_0x, i_nibble, i_test_jump, jump_next_offset[7:0]); end /* @@ -181,6 +192,7 @@ always @(posedge i_clk) begin if (i_phases[1] && !just_reset) begin $display("PC_RSTK %0d: [%d] inc_pc %5h => %5h", i_phase, i_cycle_ctr, reg_PC, reg_PC + 20'h00001); + prev_PC <= reg_PC; reg_PC <= reg_PC + 20'h00001; end @@ -195,11 +207,12 @@ always @(posedge i_clk) begin */ if (i_phases[3] && do_jump_instr && !jump_decode) begin `ifdef SIM - $display("PC_RSTK %0d: [%d] start decode jump %0d | jump_base %5h", i_phase, i_cycle_ctr, - i_jump_length, i_push_pc? reg_PC + {{17{1'b0}},(i_jump_length + 3'd1)} : reg_PC); + $display("PC_RSTK %0d: [%d] start decode jump %0d | jump_base %5h (i_test_jump %b)", i_phase, i_cycle_ctr, + i_jump_length, i_push_pc? reg_PC + {{17{1'b0}},(i_jump_length + 3'd1)} : (i_test_jump ? prev_PC : reg_PC), i_test_jump); `endif jump_counter <= 3'd0; - jump_base <= i_push_pc? reg_PC + {{17{1'b0}},(i_jump_length + 3'd1)} : reg_PC; + /* may not be correct for test_jump */ + jump_base <= i_push_pc? reg_PC + {{17{1'b0}},(i_jump_length + 3'd1)} : (i_test_jump ? prev_PC : reg_PC); jump_decode <= 1'b1; rstk_ptr_to_push_at <= (reg_rstk_ptr + 3'o1) & 3'o7; end @@ -235,7 +248,7 @@ always @(posedge i_clk) begin rstk_ptr_after_pop <= (reg_rstk_ptr - 3'o1) & 3'o7; end - if (is_rtn) begin + if (do_rtn || do_rtnyes) begin /* this is an RTN */ reg_PC <= addr_to_return_to; reg_RSTK[reg_rstk_ptr] <= 20'h00000; @@ -243,7 +256,9 @@ always @(posedge i_clk) begin `ifdef SIM $write("PC_RSTK %0d: [%d] RTN", i_phase, i_cycle_ctr); case (i_nibble) - 4'h0: $display("SXM"); + 4'h0: + if (i_test_jump) $display("YES"); + else $display("SXM"); 4'h1: $write("\n"); 4'h2: $display("SC"); 4'h3: $display("CC"); diff --git a/view b/view index fe1a9e7..90cf07f 100755 --- a/view +++ b/view @@ -4,4 +4,4 @@ # -nextpnr-ecp5 --gui --85k --speed 6 --freq 5 --lpf ulx3s_v20.lpf --json z_saturn_test.json +nextpnr-ecp5 --gui --85k --speed 6 --freq 5 --package CABGA381 --lpf ulx3s_v20.lpf --json z_saturn_test.json