diff --git a/saturn_alu.v b/saturn_alu.v index aa43bcb..e6bf319 100644 --- a/saturn_alu.v +++ b/saturn_alu.v @@ -61,6 +61,7 @@ module saturn_alu ( i_mode_dec, i_set_xm, i_set_carry, + i_test_carry, i_carry_val, o_reg_p, @@ -123,6 +124,7 @@ input wire [0:0] i_ins_unconfig; input wire [0:0] i_mode_dec; input wire [0:0] i_set_xm; input wire [0:0] i_set_carry; +input wire [0:0] i_test_carry; input wire [0:0] i_carry_val; output wire [3:0] o_reg_p; @@ -197,58 +199,6 @@ reg [19:0] RSTK[0:7]; initial begin - // alu internal control bits - alu_op = 0; - reg_dest = 0; - reg_src1 = 0; - reg_src2 = 0; - f_first = 0; - f_cur = 0; - f_last = 0; - - alu_run = 0; - alu_done = 0; - - p_src1 = 0; - p_src2 = 0; - p_carry = 0; - c_res1 = 0; - c_res2 = 0; - c_carry = 0; - is_zero = 0; -// o_alu_stall_dec = 0; - // processor registers - PC = 0; - - // D0 = 0; - // D1 = 0; - - // A = 0; - // B = 0; - // C = 0; - // D = 0; - - // R0 = 0; - // R1 = 0; - // R2 = 0; - // R3 = 0; - // R4 = 0; - - // CARRY = 0; - // DEC = 0; - // P = 0; - // HST = 0; - // ST = 0; - - rstk_ptr = 0; - // RSTK[0] = 0; - // RSTK[1] = 0; - // RSTK[2] = 0; - // RSTK[3] = 0; - // RSTK[4] = 0; - // RSTK[5] = 0; - // RSTK[6] = 0; - // RSTK[7] = 0; end /* @@ -313,7 +263,7 @@ end // the decoder may request the ALU to not stall it -assign o_alu_stall_dec = (!no_extra_cycles) || +assign o_alu_stall_dec = !no_extra_cycles || alu_initializing || (alu_run && (!i_alu_no_stall || alu_finish || alu_go_test || o_bus_dp_read)); @@ -329,11 +279,11 @@ assign f_next = (f_cur + 1) & 4'hF; * test things on alu_op */ -wire is_alu_op_jump; -assign is_alu_op_jump = ((alu_op == `ALU_OP_JMP_REL3) || - (alu_op == `ALU_OP_JMP_REL4) || - (alu_op == `ALU_OP_JMP_ABS5) || - i_ins_rtn); +wire is_alu_op_unc_jump; +assign is_alu_op_unc_jump = ((alu_op == `ALU_OP_JMP_REL3) || + (alu_op == `ALU_OP_JMP_REL4) || + (alu_op == `ALU_OP_JMP_ABS5) || + i_ins_rtn); wire is_alu_op_test; assign is_alu_op_test = ((alu_op == `ALU_OP_TEST_EQ) || (alu_op == `ALU_OP_TEST_NEQ)); @@ -432,6 +382,15 @@ assign is_mem_xfer = is_mem_read || is_mem_write; assign mem_reg = is_mem_read?i_reg_src1:i_reg_dest; always @(posedge i_clk) begin + + if (i_reset) begin + alu_op <= 0; + reg_dest <= 0; + reg_src1 <= 0; + reg_src2 <= 0; + f_last <= 0; + end + // this happens in phase 3, right after the instruction decoder (in phase 2) is finished if (do_alu_init) begin @@ -458,6 +417,16 @@ end always @(posedge i_clk) begin + if (i_reset) begin + alu_run <= 0; + alu_done <= 0; + f_first <= 0; + f_cur <= 0; + end + + if (alu_initializing) + f_cur <= f_cur + 1; + if (do_alu_init) begin // $display("------------------------------------------------- DO_ALU_INIT"); alu_run <= 1; @@ -493,6 +462,14 @@ end always @(posedge i_clk) begin + + if (i_reset) begin + p_src1 <= 0; + p_src2 <= 0; + p_carry <= 0; + jump_bse <= 0; + end + if (do_alu_prep) begin if (alu_debug) begin `ifdef SIM @@ -511,9 +488,11 @@ always @(posedge i_clk) begin `ALU_OP_RST_BIT, `ALU_OP_SET_BIT, `ALU_OP_2CMPL, + `ALU_OP_DEC, `ALU_OP_ADD, `ALU_OP_TEST_EQ, `ALU_OP_TEST_NEQ, + `ALU_OP_JMP_REL2, `ALU_OP_JMP_REL3, `ALU_OP_JMP_REL4, `ALU_OP_JMP_ABS5, @@ -551,6 +530,8 @@ always @(posedge i_clk) begin `ALU_OP_RST_BIT, `ALU_OP_SET_BIT, `ALU_OP_2CMPL, + `ALU_OP_DEC, + `ALU_OP_JMP_REL2, `ALU_OP_JMP_REL3, `ALU_OP_JMP_REL4, `ALU_OP_JMP_ABS5: begin end // no need for a 2nd operand @@ -584,13 +565,15 @@ always @(posedge i_clk) begin // setup p_carry // $display("fs %h | fs=0 %b | cc %b | npc %b", f_start, (f_start == 0), c_carry, (f_start == 0)?1'b1:c_carry); case (alu_op) - `ALU_OP_2CMPL: p_carry <= alu_start?1'b1:c_carry; - `ALU_OP_ADD: p_carry <= alu_start?0:c_carry; - `ALU_OP_TEST_NEQ: p_carry <= alu_start?0:c_carry; + `ALU_OP_2CMPL: p_carry <= alu_start?1'b1:c_carry; + `ALU_OP_DEC: p_carry <= alu_start?1'b0:c_carry; + `ALU_OP_ADD: p_carry <= alu_start?1'b0:c_carry; + `ALU_OP_TEST_NEQ: p_carry <= alu_start?1'b0:c_carry; endcase // prepare jump base case (alu_op) + `ALU_OP_JMP_REL2, `ALU_OP_JMP_REL3, `ALU_OP_JMP_REL4: begin @@ -609,7 +592,11 @@ end always @(posedge i_clk) begin if (i_reset) begin - c_carry <= 0; + c_res1 <= 0; + c_res2 <= 0; + c_carry <= 0; + is_zero <= 0; + jump_off <= 0; end if (do_alu_calc) begin @@ -622,13 +609,13 @@ always @(posedge i_clk) begin alu_run, alu_done, o_alu_stall_dec, alu_op, f_first, f_cur, f_last, jump_bse, jump_off, jump_pc, alu_finish); `endif - case (alu_op) - `ALU_OP_JMP_REL3, - `ALU_OP_JMP_REL4, - `ALU_OP_JMP_ABS5: - if (alu_start) - jump_off <= { 16'b0, p_src1 }; - endcase + if(alu_start) + case (alu_op) + `ALU_OP_JMP_REL2, + `ALU_OP_JMP_REL3, + `ALU_OP_JMP_REL4, + `ALU_OP_JMP_ABS5: jump_off <= { 16'b0, p_src1 }; + endcase // main case case (alu_op) @@ -641,16 +628,18 @@ always @(posedge i_clk) begin `ALU_OP_COPY, `ALU_OP_RST_BIT, `ALU_OP_SET_BIT: c_res1 <= p_src1; - `ALU_OP_2CMPL: - begin + `ALU_OP_2CMPL: begin c_carry <= (~p_src1 == 4'hf) && p_carry ; c_res1 <= ~p_src1 + {3'b000, p_carry}; is_zero <= ((~p_src1 + {3'b000, p_carry}) == 0) && alu_start?1:is_zero; end + `ALU_OP_DEC: + {c_carry, c_res1} <= p_src1 + 4'b1111 + {4'b0000, p_carry}; `ALU_OP_ADD: {c_carry, c_res1} <= p_src1 + p_src2 + {4'b0000, p_carry}; `ALU_OP_TEST_NEQ: c_carry <= !(p_src1 == p_src2) || p_carry; + `ALU_OP_JMP_REL2: begin end // there is no middle part `ALU_OP_JMP_REL3, `ALU_OP_JMP_REL4, `ALU_OP_JMP_ABS5: jump_off[f_cur*4+:4] <= p_src1; @@ -658,12 +647,12 @@ always @(posedge i_clk) begin default: $display("#### CALC 2 UNHANDLED OPERATION %0d", alu_op); endcase - case (alu_op) - `ALU_OP_JMP_REL3: if (alu_finish) - jump_off <= { {8{p_src1[3]}}, p_src1, jump_off[7:0] }; - `ALU_OP_JMP_REL4: if (alu_finish) - jump_off <= { {4{p_src1[3]}}, p_src1, jump_off[11:0] }; - endcase + if (alu_finish) + case (alu_op) + `ALU_OP_JMP_REL2: jump_off <= { {12{p_src1[3]}}, p_src1, jump_off[3:0] }; + `ALU_OP_JMP_REL3: jump_off <= { {8{p_src1[3]}}, p_src1, jump_off[7:0] }; + `ALU_OP_JMP_REL4: jump_off <= { {4{p_src1[3]}}, p_src1, jump_off[11:0] }; + endcase // $display("-------C- SRC1 %b %h | ~SRC1 %b %h | PC %b | RES1 %b %h | CC %b", // p_src1, p_src1, ~p_src1, ~p_src1, p_carry, @@ -672,13 +661,62 @@ always @(posedge i_clk) begin end if (do_go_init) begin - // $display("GO_INIT 3: imm %h", i_imm_value); + $display("GO_INIT 3: imm %h", i_imm_value); jump_off <= { {16{1'b0}}, i_imm_value}; end end +/****************************************************************************** + * save alu registers after calculations + * + * this is the only place the registers can be updated ! + * + * + * + * + * + * + *****************************************************************************/ + +reg [0:0] alu_initializing; + always @(posedge i_clk) begin + /* + * Initialization of all registers + * This happens at the same time the first LOAD_PC command goes out + * + */ + + if (i_reset) begin + alu_initializing <= 1; + CARRY <= 0; + P <= 0; + D0 <= 0; + D1 <= 0; + end + + if (alu_initializing) begin + A[f_cur] <= 0; + B[f_cur] <= 0; + C[f_cur] <= 0; + D[f_cur] <= 0; + R0[f_cur] <= 0; + R1[f_cur] <= 0; + R2[f_cur] <= 0; + R3[f_cur] <= 0; + R4[f_cur] <= 0; + ST[f_cur] <= 0; + HST[f_cur[1:0]] <= 0; + alu_initializing <= (f_cur != 15); + end + + /* + * + * Debug for some JUMP condition testing + * + */ + if (do_alu_save || do_go_prep) begin if (alu_debug_jump) begin `ifdef SIM @@ -714,10 +752,6 @@ always @(posedge i_clk) begin alu_run, alu_done, o_alu_stall_dec, alu_op, f_first, f_cur, f_last, reg_dest, c_res1, c_res2, p_src1, p_src2, c_carry); - // $display("-------S- SRC1 %b %h | ~SRC1 %b %h | PC %b | RES1 %b %h | CC %b", - // p_src1, p_src1, ~p_src1, ~p_src1, p_carry, - // (~p_src1) + p_carry, (~p_src1) + p_carry, - // (~p_src1) == 4'hf ); end `endif @@ -726,6 +760,7 @@ always @(posedge i_clk) begin `ALU_OP_COPY, `ALU_OP_EXCH, // does the first assign `ALU_OP_2CMPL, + `ALU_OP_DEC, `ALU_OP_ADD, `ALU_OP_CLR_MASK: case (reg_dest) @@ -756,6 +791,7 @@ always @(posedge i_clk) begin endcase `ALU_OP_TEST_EQ, `ALU_OP_TEST_NEQ, + `ALU_OP_JMP_REL2, `ALU_OP_JMP_REL3, `ALU_OP_JMP_REL4, `ALU_OP_JMP_ABS5: begin end // nothing to save, handled by PC management below @@ -772,13 +808,13 @@ always @(posedge i_clk) begin `ALU_REG_B: B[f_cur] <= c_res2; `ALU_REG_C: C[f_cur] <= c_res2; `ALU_REG_D: D[f_cur] <= c_res2; + `ALU_REG_D0: D0[f_cur*4+:4] <= c_res2; + `ALU_REG_D1: D1[f_cur*4+:4] <= c_res2; `ALU_REG_R0: R0[f_cur] <= c_res2; `ALU_REG_R1: R1[f_cur] <= c_res2; `ALU_REG_R2: R2[f_cur] <= c_res2; `ALU_REG_R3: R3[f_cur] <= c_res2; `ALU_REG_R4: R4[f_cur] <= c_res2; - // `ALU_REG_D0: D0[f_start*4+:4] <= c_res2; - // `ALU_REG_D1: D1[f_start*4+:4] <= c_res2; // `ALU_REG_ST: ST[f_start*4+:4] <= c_res2; // `ALU_REG_P: P <= c_res2; // `ALU_REG_HST: HST <= c_res2; @@ -792,6 +828,8 @@ always @(posedge i_clk) begin if (do_alu_save) begin case (alu_op) `ALU_OP_2CMPL: CARRY <= !is_zero; + `ALU_OP_DEC, + `ALU_OP_ADD, `ALU_OP_TEST_EQ, `ALU_OP_TEST_NEQ: CARRY <= c_carry; endcase @@ -964,32 +1002,69 @@ end wire [19:0] next_pc; wire [19:0] goyes_off; wire [19:0] goyes_pc; + +wire [0:0] is_jmp_rel2; +wire [0:0] is_rtn_rel2; +wire [0:0] jmp_carry_test; +wire [0:0] exec_rtn_rel2; +wire [0:0] set_jmp_rel2; +wire [0:0] exec_jmp_rel2; + wire [0:0] update_pc; -wire [0:0] uncond_jmp; +wire [0:0] set_unc_jmp; +wire [0:0] exec_unc_jmp; +wire [0:0] exec_unc_rtn; wire [0:0] pop_pc; wire [0:0] reload_pc; wire [0:0] push_pc; -assign next_pc = (is_alu_op_jump && alu_finish)?jump_pc:PC + 1; assign goyes_off = {{12{i_imm_value[3]}}, i_imm_value, jump_off[3:0]}; assign goyes_pc = jump_bse + goyes_off; +// rtnyes is already handled by i_ins_test_go +assign is_rtn_rel2 = (alu_op == `ALU_OP_JMP_REL2) && (goyes_off == 0); +assign is_jmp_rel2 = (alu_op == `ALU_OP_JMP_REL2) && !(goyes_off == 0); +assign jmp_carry_test = (i_test_carry && (CARRY == i_carry_val)); +assign exec_rtn_rel2 = is_rtn_rel2 && jmp_carry_test && alu_done; +assign set_jmp_rel2 = is_jmp_rel2 && jmp_carry_test && alu_finish; +assign exec_jmp_rel2 = is_jmp_rel2 && jmp_carry_test && alu_done; -assign update_pc = !o_alu_stall_dec || is_alu_op_jump || just_reset; -assign uncond_jmp = is_alu_op_jump && alu_done; -assign pop_pc = i_pop && i_ins_rtn && - ((!i_ins_test_go) || - (i_ins_test_go && c_carry)); -assign reload_pc = uncond_jmp || pop_pc || just_reset; + +assign set_unc_jmp = is_alu_op_unc_jump && alu_finish; +assign exec_unc_jmp = is_alu_op_unc_jump && alu_done; +assign exec_unc_rtn = i_pop && i_ins_rtn; + +assign pop_pc = i_pop && i_ins_rtn && + ((!i_ins_test_go) || + (i_ins_test_go && CARRY)); + +assign next_pc = (set_unc_jmp || set_jmp_rel2)?jump_pc:PC + 1; +assign update_pc = !o_alu_stall_dec || exec_unc_jmp || exec_jmp_rel2 || just_reset; +assign reload_pc = (exec_unc_jmp || pop_pc || just_reset || exec_jmp_rel2); assign push_pc = update_pc && i_push && alu_finish; always @(posedge i_clk) begin + /* + * initializes the PC + * + */ + if (i_reset) begin PC <= ~0; o_bus_load_pc <= 0; + rstk_ptr <= 0; end + /* + * Similarly to the data registers, + * initializes the RSTK while the PC is first loaded + * + */ + if (alu_initializing) + RSTK[f_cur[2:0]] <= 0; + + // necessary for the write to memory above // otherwise we get a conflict on o_bus_address if (setup_load_dp) @@ -1016,16 +1091,18 @@ always @(posedge i_clk) begin `ifdef SIM if (alu_debug_pc) $display({"ALU_PC 3: !stl %b | nx %5h | done %b | fin %b | ", - "jmp %b | ins_rtn %b | push %b | ", - "imm %h | j_bs %h | go_off %h | go_pc %h"}, + "uncjmp %b | ins_rtn %b | push %b | imm %h | ", + "c_test %b | jmpr2 %b | rtn[n]c %b |", + "j_bs %h | go_off %h | go_pc %h | update %b | PC <= %h"}, !o_alu_stall_dec, next_pc, alu_done, alu_finish, - is_alu_op_jump, i_ins_rtn, i_push, - i_imm_value, jump_bse, goyes_off, goyes_pc); + is_alu_op_unc_jump, i_ins_rtn, i_push, i_imm_value, + jmp_carry_test, exec_jmp_rel2, exec_rtn_rel2, + jump_bse, goyes_off, goyes_pc, update_pc, pop_pc ? RSTK[rstk_ptr - 1] : next_pc); `endif // this may do wierd things with C=RSTK... if (update_pc) begin - PC <= pop_pc ? RSTK[rstk_ptr-1] : next_pc; + PC <= pop_pc ? RSTK[rstk_ptr - 1] : next_pc; end if (reload_pc) begin @@ -1066,12 +1143,16 @@ end * ****************************************************************************/ -always @(posedge i_clk) +always @(posedge i_clk) begin + if (i_reset) + DEC <= 0; + // changing calculation modes if (do_alu_mode) begin $display("SETTING MODE TO %s", i_mode_dec?"DEC":"HEX"); DEC <= i_mode_dec; end +end endmodule diff --git a/saturn_bus_ctrl.v b/saturn_bus_ctrl.v index e4934ab..09d1ef8 100644 --- a/saturn_bus_ctrl.v +++ b/saturn_bus_ctrl.v @@ -86,6 +86,16 @@ assign en_bus_ecmd = i_en_bus_ecmd && !i_stalled; * ****************************************************************************/ +// tests on last_cmd + +wire [0:0] last_cmd_pc_read; +wire [0:0] last_cmd_dp_read; +wire [0:0] last_cmd_dp_write; + +assign last_cmd_pc_read = (last_cmd == `BUSCMD_PC_READ); +assign last_cmd_dp_read = (last_cmd == `BUSCMD_DP_READ); +assign last_cmd_dp_write = (last_cmd == `BUSCMD_DP_WRITE); + // declarations reg [0:0] cmd_pc_read_s; @@ -98,7 +108,7 @@ reg [0:0] cmd_reset_s; wire [0:0] addr_s; wire [0:0] do_cmd_pc_read; -wire [0:0] do_display_stalled; +wire [0:0] do_display_stalled; wire [0:0] do_cmd_load_dp; wire [0:0] do_dp_read_data; @@ -108,6 +118,7 @@ wire [0:0] do_pc_read_after_dp_read; wire [0:0] do_cleanup_after_dp_read; wire [0:0] do_cmd_dp_write; +wire [0:0] cmd_dp_write_data; wire [0:0] do_dp_write_data; wire [0:0] do_pc_read_after_dp_write; wire [0:0] cmd_load_dp_dp_write_uc; @@ -122,8 +133,10 @@ wire [0:0] do_pc_read_after_reset; wire [0:0] cmd_reset_sc; wire [0:0] cmd_reset_uc; -wire [0:0] do_unstall; wire [0:0] do_cleanup; +wire [0:0] do_stall; +wire [0:0] do_unstall; +wire [0:0] do_stop_loop; // assigns @@ -138,7 +151,8 @@ assign do_pc_read_after_dp_read = i_read_stall && !i_cmd_dp_read && cmd_load_dp assign do_cleanup_after_dp_read = !i_read_stall && !i_cmd_dp_read && cmd_load_dp_s && !addr_s && dp_read_s; assign do_cmd_dp_write = i_cmd_dp_write && cmd_load_dp_s && addr_s && !cmd_dp_write_s; -assign do_dp_write_data = i_cmd_dp_write && cmd_load_dp_s && addr_s && cmd_dp_write_s; +assign cmd_dp_write_data = i_cmd_dp_write && cmd_load_dp_s && addr_s && cmd_dp_write_s; +assign do_dp_write_data = en_bus_send && cmd_dp_write_data && last_cmd_dp_write; assign do_pc_read_after_dp_write = !i_cmd_dp_write && cmd_load_dp_s && cmd_dp_write_s; assign cmd_load_dp_dp_write_uc = cmd_load_dp_s && cmd_dp_write_s && cmd_pc_read_s; @@ -163,18 +177,28 @@ assign do_display_stalled = en_bus_recv && i_read_stall && !o_stalled_by_ do_dp_read_data || do_pc_read_after_dp_read || do_cmd_dp_write || - do_dp_write_data || + cmd_dp_write_data || do_pc_read_after_dp_write); -assign do_unstall = do_dp_read_data_uc || - cmd_load_dp_dp_write_uc || - cmd_config_uc || - cmd_reset_uc; +assign do_cleanup = en_bus_send && + (do_cleanup_after_dp_read || + cmd_load_dp_dp_write_uc || + cmd_config_uc || + cmd_reset_uc); + +assign do_stall = en_bus_ecmd && + (do_dp_read_data_sc || + cmd_reset_sc || + cmd_config_sc); + +assign do_unstall = en_bus_ecmd && + (do_dp_read_data_uc || + cmd_load_dp_dp_write_uc || + cmd_config_uc || + cmd_reset_uc); + +assign do_stop_loop = en_bus_ecmd && addr_s; -assign do_cleanup = do_cleanup_after_dp_read || - cmd_load_dp_dp_write_uc || - cmd_config_uc || - cmd_reset_uc; /****************************************************************************** * * test rom @@ -184,22 +208,24 @@ assign do_cleanup = do_cleanup_after_dp_read || `ifdef SIM `define ROMBITS 20 `else -`define ROMBITS 16 +`define ROMBITS 12 `endif reg [3:0] rom [0:2**`ROMBITS-1]; -wire [0:0] last_cmd_pc_read; -wire [0:0] last_cmd_dp_read; wire [0:0] do_read_from_bus; wire [0:0] use_pc_as_pointer; +wire [0:0] use_dp_as_pointer; +wire [0:0] do_read_from_bus_with_pc; +wire [0:0] do_read_from_bus_with_dp; wire [`ROMBITS-1:0] read_pointer; -assign last_cmd_pc_read = (last_cmd == `BUSCMD_PC_READ); -assign last_cmd_dp_read = (last_cmd == `BUSCMD_DP_READ); -assign do_read_from_bus = en_bus_recv && (!i_read_stall || do_dp_read_data) && (last_cmd_pc_read || last_cmd_dp_read); -assign use_pc_as_pointer = last_cmd_pc_read ; -assign read_pointer = use_pc_as_pointer?local_pc[`ROMBITS-1:0]:local_dp[`ROMBITS-1:0]; +assign do_read_from_bus = en_bus_recv && (!i_read_stall || do_dp_read_data) && (last_cmd_pc_read || last_cmd_dp_read); +assign use_pc_as_pointer = last_cmd_pc_read; +assign use_dp_as_pointer = last_cmd_dp_read; +assign read_pointer = use_pc_as_pointer?local_pc[`ROMBITS-1:0]:local_dp[`ROMBITS-1:0]; +assign do_read_from_bus_with_pc = do_read_from_bus && use_pc_as_pointer; +assign do_read_from_bus_with_dp = do_read_from_bus && use_dp_as_pointer; /****************************************************************************** * @@ -210,7 +236,7 @@ assign read_pointer = use_pc_as_pointer?local_pc[`ROMBITS-1:0]:local_dp[`RO initial begin // `ifdef SIM $readmemh("rom-gx-r.hex", rom, 0, 2**`ROMBITS-1); - // $readmemh( "testrom-2.hex", rom); +// $readmemh( "testrom-2.hex", rom); `ifdef SIM // $monitor({"o_stalled_by_bus %b | i_read_stall %b | i_cmd_dp_read %b |", @@ -243,6 +269,19 @@ always @(posedge i_clk) begin cmd_reset_s <= 0; end + /* + * reset flags + */ + if (do_cleanup) begin + // $display("--------------------------------------------- BUS STATES CLEANUP"); + cmd_pc_read_s <= 0; + dp_read_s <= 0; + cmd_dp_write_s <= 0; + cmd_load_dp_s <= 0; + cmd_config_s <= 0; + cmd_reset_s <= 0; + end + /* * * sending commands or data to the bus @@ -250,20 +289,6 @@ always @(posedge i_clk) begin */ if (en_bus_send) begin - /* - * reset flags - */ - - if (do_cleanup) begin - // $display("--------------------------------------------- BUS STATES CLEANUP"); - cmd_pc_read_s <= 0; - dp_read_s <= 0; - cmd_dp_write_s <= 0; - cmd_load_dp_s <= 0; - cmd_config_s <= 0; - cmd_reset_s <= 0; - end - /* * send the PC_READ command to restore the instruction flow * after a data transfer @@ -342,46 +367,54 @@ always @(posedge i_clk) begin addr_cnt <= addr_cnt + 1; o_bus_strobe <= 1; end - - /* - * nothing to do for reading data - */ - - /* - * writing data to the bus, - * send DP_WRITE first if necessary - */ - - if (do_dp_write_data) begin - if (last_cmd == `BUSCMD_DP_WRITE) begin - $display("BUS_SEND %0d: [%d] WRITE %h =>", `PH_BUS_SEND, i_cycle_ctr, i_nibble); - o_bus_data <= i_nibble; - o_bus_strobe <= 1; - end - end - end - /* +/****************************************************************************** + * + * writing data to the bus, + * will wait for DP_WRITE to be sent + * + ****************************************************************************/ + + if (do_dp_write_data) begin + $display("BUS_SEND %0d: [%d] WRITE %h =>", `PH_BUS_SEND, i_cycle_ctr, i_nibble); + o_bus_data <= i_nibble; + o_bus_strobe <= 1; + end + + + + + /**************************************************************************** * * reading data from the bus * - */ + ***************************************************************************/ - if (do_read_from_bus) begin + /* + * only display during simulation + */ `ifdef SIM + + if (do_read_from_bus) $display("BUS_RECV %0d: [%d] <= READ(%s) [%5h] %h", `PH_BUS_RECV, i_cycle_ctr, use_pc_as_pointer?"PC":"DP", read_pointer, rom[read_pointer]); + `endif + + if (do_read_from_bus) o_nibble <= rom[read_pointer]; - if (use_pc_as_pointer) local_pc <= local_pc + 1; - else begin - local_dp <= local_dp + 1; - dp_read_s <= 1; - end - end + + + if (do_read_from_bus_with_pc) + local_pc <= local_pc + 1; + + if (do_read_from_bus_with_dp) begin + local_dp <= local_dp + 1; + dp_read_s <= 1; + end if (do_display_stalled) begin $display("BUS_RECV %0d: [%d] STALLED", `PH_BUS_RECV, i_cycle_ctr); @@ -397,28 +430,35 @@ always @(posedge i_clk) begin o_bus_cmd_data <= 1; end +/****************************************************************************** + * + * execute stalling the core by the bus controller + * + *****************************************************************************/ + + if (do_stall) begin + // $display("-------------------------------------- STALL"); + o_stalled_by_bus <= 1; + end + + if (do_unstall) begin + // $display("-------------------------------------- NO - STALL"); + o_stalled_by_bus <= 0; + addr_cnt <= 0; + end + + /* + * reset the adress sending loop + * + */ + + if (do_stop_loop) begin + send_addr <= 0; + end + if (en_bus_ecmd) begin - - // stalling and unstalling stuff - - if (do_dp_read_data_sc || cmd_reset_sc || cmd_config_sc) begin - // $display("-------------------------------------- STALL"); - o_stalled_by_bus <= 1; - end - - if (do_unstall) begin - // $display("-------------------------------------- NO - STALL"); - o_stalled_by_bus <= 0; - addr_cnt <= 0; - end - - if (addr_s) begin - send_addr <= 0; - end - // command automatic switchover - case (last_cmd) `BUSCMD_NOP: begin end `BUSCMD_LOAD_PC, @@ -446,9 +486,6 @@ always @(posedge i_clk) begin `BUSCMD_RESET: begin end default: $display("------------ UNHANDLED BUSCMD %h", last_cmd); endcase - - - end diff --git a/saturn_core.v b/saturn_core.v index 7b5007b..150bcf3 100644 --- a/saturn_core.v +++ b/saturn_core.v @@ -22,23 +22,51 @@ `ifdef SIM module saturn_core ( - input clk, - input reset, - output [0:0] halt, - output [3:0] busstate, - output [11:0] decstate + i_clk, + i_reset, + o_halt, + + i_bus_data_in, + o_bus_data_out, + o_bus_strobe, + o_bus_cmd_data ); + +input wire [0:0] i_clk; +input wire [0:0] i_reset; +output wire [0:0] o_halt; + +input wire [3:0] i_bus_data_in; +output wire [3:0] o_bus_data_out; +output wire [0:0] o_bus_strobe; +output wire [0:0] o_bus_cmd_data; + `else module saturn_core ( - input clk_25mhz, - input [6:0] btn, - output [7:0] led -); -wire clk; -wire reset; + clk_25mhz, + btn, + led, -assign clk = clk_25mhz; -assign reset = btn[1]; + i_bus_data_in, + o_bus_data_out, + o_bus_strobe, + o_bus_cmd_data +); + +input wire [0:0] clk_25mhz; +input wire [6:0] btn; +output reg [7:0] led; + +wire [0:0] i_clk; +wire [0:0] i_reset; + +assign i_clk = clk_25mhz; +assign i_reset = btn[1]; + +input wire [3:0] i_bus_data_in; +output wire [3:0] o_bus_data_out; +output wire [0:0] o_bus_strobe; +output wire [0:0] o_bus_cmd_data; `endif @@ -65,10 +93,6 @@ reg [0:0] clock_end; reg [31:0] cycle_ctr; reg [31:0] max_cycle; -// state machine stuff -wire [0:0] halt; - - // hp48_bus bus_ctrl ( // .strobe (bus_strobe), // .reset (reset), @@ -80,8 +104,8 @@ wire [0:0] halt; // ); saturn_decoder m_decoder ( - .i_clk (clk), - .i_reset (reset), + .i_clk (i_clk), + .i_reset (i_reset), .i_cycles (cycle_ctr), .i_en_dbg (ck_debugger), .i_en_dec (ck_inst_dec), @@ -116,6 +140,7 @@ saturn_decoder m_decoder ( .o_ins_rtn (ins_rtn), .o_set_xm (set_xm), .o_set_carry (set_carry), + .o_test_carry (test_carry), .o_carry_val (carry_val), .o_ins_set_mode (ins_set_mode), .o_mode_dec (mode_dec), @@ -149,6 +174,7 @@ wire [4:0] reg_src2; wire [0:0] ins_rtn; wire [0:0] set_xm; wire [0:0] set_carry; +wire [0:0] test_carry; wire [0:0] carry_val; wire [0:0] ins_set_mode; wire [0:0] mode_dec; @@ -160,8 +186,8 @@ wire [0:0] ins_unconfig; saturn_alu m_alu ( - .i_clk (clk), - .i_reset (reset), + .i_clk (i_clk), + .i_reset (i_reset), .i_cycle_ctr (cycle_ctr), .i_en_alu_dump (ck_alu_dump), .i_en_alu_prep (ck_alu_prep), @@ -207,6 +233,7 @@ saturn_alu m_alu ( .i_mode_dec (mode_dec), .i_set_xm (set_xm), .i_set_carry (set_carry), + .i_test_carry (test_carry), .i_carry_val (carry_val), .o_reg_p (reg_p), @@ -238,8 +265,8 @@ wire [19:0] reg_pc; saturn_bus_ctrl m_bus_ctrl ( // basic stuff - .i_clk (clk), - .i_reset (reset), + .i_clk (i_clk), + .i_reset (i_reset), .i_cycle_ctr (cycle_ctr), .i_en_bus_send (ck_bus_send), .i_en_bus_recv (ck_bus_recv), @@ -249,10 +276,10 @@ saturn_bus_ctrl m_bus_ctrl ( .o_stalled_by_bus (bus_stalls_core), //bus i/o - .i_bus_data (bus_data_in), - .o_bus_data (bus_data_out), - .o_bus_strobe (bus_strobe), - .o_bus_cmd_data (bus_cmd_data), + .i_bus_data (i_bus_data_in), + .o_bus_data (o_bus_data_out), + .o_bus_strobe (o_bus_strobe), + .o_bus_cmd_data (o_bus_cmd_data), // interface to the rest of the machine .i_alu_pc (reg_pc), @@ -271,11 +298,11 @@ saturn_bus_ctrl m_bus_ctrl ( reg [0:0] mem_ctrl_stall; wire [0:0] bus_stalls_core; -// bus to external modules -reg [3:0] bus_data_in; -wire [3:0] bus_data_out; -wire [0:0] bus_strobe; -wire [0:0] bus_cmd_data; +// // bus to external modules +// reg [3:0] bus_data_in; +// wire [3:0] bus_data_out; +// wire [0:0] bus_strobe; +// wire [0:0] bus_cmd_data; // `define DEBUG_CLOCKS @@ -318,8 +345,8 @@ initial begin // //-------------------------------------------------------------------------------------------------- -always @(posedge clk) begin - if (!reset) begin +always @(posedge i_clk) begin + if (!i_reset) begin clk_phase <= clk_phase + 1; ck_debugger <= clk_phase[1:0] == `PH_DEBUGGER; @@ -363,7 +390,7 @@ always @(posedge clk) begin clock_end <= 0; cycle_ctr <= ~0; - max_cycle <= 450; + max_cycle <= 650; mem_ctrl_stall <= 0; `ifndef SIM @@ -382,8 +409,9 @@ wire dec_stalled; wire alu_stalled; assign dec_stalled = alu_stalls_dec || bus_stalls_core; assign alu_stalled = bus_stalls_core; -assign halt = clock_end || inv_opcode; - +`ifdef SIM +assign o_halt = clock_end || inv_opcode; +`endif // Verilator lint_off UNUSED //wire [N-1:0] unused; @@ -394,25 +422,32 @@ endmodule `ifdef SIM module saturn_tb; -reg clk; -reg reset; -wire halt; -wire [3:0] busstate; -wire [11:0] decstate; saturn_core saturn ( - .clk (clk), - .reset (reset), - .halt (halt), - .busstate (busstate), - .decstate (decstate) + .i_clk (clk), + .i_reset (reset), + .o_halt (halt), + .i_bus_data_in (core_bus_data_in), + .o_bus_data_out (core_bus_data_out), + .o_bus_strobe (core_bus_strobe), + .o_bus_cmd_data (core_bus_cmd_data) ); +reg [0:0] clk; +reg [0:0] reset; +wire [0:0] halt; + +reg [3:0] core_bus_data_in; +wire [3:0] core_bus_data_out; +wire [0:0] core_bus_strobe; +wire [0:0] core_bus_cmd_data; + always #10 clk = (clk === 1'b0); initial begin - //$monitor ("c %b | r %b | run %h | dec %h", clk, reset, runstate, decstate); + // $monitor ("c %b | r %b | in %h | out %h | str %b | cd %b", + // clk, reset, core_bus_data_in, core_bus_data_out, core_bus_strobe, core_bus_cmd_data); end initial begin diff --git a/saturn_decoder.v b/saturn_decoder.v index 625ca77..da0bb9d 100644 --- a/saturn_decoder.v +++ b/saturn_decoder.v @@ -191,6 +191,7 @@ always @(posedge i_clk) begin o_ins_set_mode <= 0; o_ins_reset <= 0; o_ins_config <= 0; + o_test_carry <= 0; end if (decoder_active) begin @@ -290,6 +291,7 @@ always @(posedge i_clk) begin // 4xy GOC // 500 RTNNC // 5xy GONC + o_alu_debug <= 1; o_alu_no_stall <= 1; o_alu_op <= `ALU_OP_JMP_REL2; mem_load_max <= 1; @@ -319,6 +321,13 @@ always @(posedge i_clk) begin o_fields_table <= `FT_TABLE_a; block_Ax <= 1; end + 4'hB: begin + go_fields_table <= 1; + // we don't know, safe bet is table a, but could be table b, + // works either way, table is fixed on the next nibble + o_fields_table <= `FT_TABLE_a; + block_Bx <= 1; + end 4'hC: block_Cx <= 1; 4'hD: block_Dx <= 1; 4'hF: block_Fx <= 1; @@ -572,6 +581,15 @@ always @(posedge i_clk) begin `include "saturn_decoder_block_8.v" + /* + * Block Axx + * ra=ra+rb a + * ra=ra-1 a + * ra=0 b + * ra=rb b + * rarbEX b + */ + if (do_block_Ax) begin o_fields_table <= i_nibble[3]?`FT_TABLE_b:`FT_TABLE_a; block_Aax <= !i_nibble[3]; @@ -597,10 +615,67 @@ always @(posedge i_clk) begin block_Abx <= 0; end + + /* + * Block Bxx + * + * + */ + + + if (do_block_Bx) begin + o_fields_table <= i_nibble[3]?`FT_TABLE_b:`FT_TABLE_a; + block_Bax <= !i_nibble[3]; + block_Bbx <= i_nibble[3]; + block_Bx <= 0; + end + + if (do_block_Bax) begin +`ifdef SIM + $display("block_Bax %h", i_nibble); +`endif + o_ins_alu_op <= 1; + case ({i_nibble[3],i_nibble[2]}) + 2'b00: o_alu_op <= `ALU_OP_SUB; + 2'b01: o_alu_op <= `ALU_OP_INC; + 2'b10: o_alu_op <= `ALU_OP_SUB; + 2'b11: o_alu_op <= `ALU_OP_SUB; + endcase + next_nibble <= 0; + o_ins_decoded <= 1; +`ifdef SIM + o_unimplemented <= 0; +`endif + block_Bax <= 0; + end + + if (do_block_Bbx) begin + o_ins_alu_op <= 1; + case ({i_nibble[3],i_nibble[2]}) + 2'b00: o_alu_op <= `ALU_OP_SHL; + 2'b01: o_alu_op <= `ALU_OP_SHR; + 2'b10: o_alu_op <= `ALU_OP_2CMPL; + 2'b11: o_alu_op <= `ALU_OP_1CMPL; + endcase + next_nibble <= 0; + o_ins_decoded <= 1; +`ifdef SIM + o_unimplemented <= 0; +`endif + block_Bbx <= 0; + end + + /* + * Block Cx + * + * + */ + if (do_block_Cx) begin `ifdef SIM $display("block_Cx %h", i_nibble); `endif + // o_alu_debug <= 1; o_fields_table <= `FT_TABLE_f; o_ins_alu_op <= 1; o_alu_op <= (i_nibble[3] && i_nibble[2])?`ALU_OP_DEC:`ALU_OP_ADD; @@ -628,6 +703,10 @@ always @(posedge i_clk) begin end if (do_block_Fx) begin +`ifdef SIM + +`endif + case (i_nibble) 4'h8, 4'h9, 4'hA, 4'hB: // r=-r A begin diff --git a/saturn_decoder_block_vars.v b/saturn_decoder_block_vars.v index 5202a3c..fafc5df 100644 --- a/saturn_decoder_block_vars.v +++ b/saturn_decoder_block_vars.v @@ -109,6 +109,18 @@ reg block_Abx; wire do_block_Abx; assign do_block_Abx = do_on_other_nibbles && block_Abx; +reg block_Bx; +wire do_block_Bx; +assign do_block_Bx = do_on_other_nibbles && block_Bx; + +reg block_Bax; +wire do_block_Bax; +assign do_block_Bax = do_on_other_nibbles && block_Bax; + +reg block_Bbx; +wire do_block_Bbx; +assign do_block_Bbx = do_on_other_nibbles && block_Bbx; + reg block_Cx; wire do_block_Cx; assign do_block_Cx = do_on_other_nibbles && block_Cx; diff --git a/saturn_decoder_debugger.v b/saturn_decoder_debugger.v index dd48797..e0aefd6 100644 --- a/saturn_decoder_debugger.v +++ b/saturn_decoder_debugger.v @@ -222,6 +222,8 @@ always @(posedge i_clk) begin `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_IMM: $write("\t%0d", o_imm_value+1); default: $write("[src2:%0d]", o_reg_src2); diff --git a/saturn_decoder_fields.v b/saturn_decoder_fields.v index f53d893..320d68d 100644 --- a/saturn_decoder_fields.v +++ b/saturn_decoder_fields.v @@ -63,6 +63,11 @@ always @(posedge i_clk) begin o_field <= 0; o_field_valid <= 0; case (i_nibble) + 4'h4, 4'h5: begin // RTNC / GOC / RTNNC / GONC + $display("------------------------------------------------ 4/5xx JUMP setting fields"); + o_field_start <= 0; + o_field_last <= 1; + end 4'h6, 4'h7: begin // GOTO / GOSUB o_field_start <= 0; o_field_last <= 2; diff --git a/saturn_decoder_registers.v b/saturn_decoder_registers.v index 3005681..d2f1d45 100644 --- a/saturn_decoder_registers.v +++ b/saturn_decoder_registers.v @@ -35,7 +35,7 @@ always @(posedge i_clk) begin if (do_on_first_nibble) begin // reset values on instruction decode start case (i_nibble) - 4'h6, 4'h7: begin + 4'h4, 4'h5, 4'h6, 4'h7: begin o_reg_dest <= 0; o_reg_src1 <= `ALU_REG_IMM; o_reg_src2 <= 0; @@ -125,7 +125,8 @@ always @(posedge i_clk) begin if (do_block_13x) begin o_reg_dest <= i_nibble[1]?reg_A_C:reg_D0D1; - o_reg_src1 <= i_nibble[1]?reg_D0D1:reg_A_C; + o_reg_src1 <= i_nibble[2]?`ALU_REG_C:`ALU_REG_A; + o_reg_src2 <= i_nibble[1]?reg_D0D1:0; end if (do_block_14x_15xx) begin @@ -190,29 +191,60 @@ always @(posedge i_clk) begin if (do_block_Abx || do_block_Dx) begin case ({i_nibble[3],i_nibble[2]}) - 2'b00: begin - o_reg_dest <= reg_ABCD; - o_reg_src1 <= `ALU_REG_ZERO; - o_reg_src2 <= 0; - end - 2'b01: begin - o_reg_dest <= reg_ABCD; - o_reg_src1 <= reg_BCAC; - o_reg_src2 <= 0; - end - 2'b10: begin - o_reg_dest <= reg_BCAC; - o_reg_src1 <= reg_ABCD; - o_reg_src2 <= 0; - end - 2'b11: begin // exch - o_reg_dest <= reg_ABAC; - o_reg_src1 <= reg_ABAC; - o_reg_src2 <= reg_BCCD; - end + 2'b00: begin + o_reg_dest <= reg_ABCD; + o_reg_src1 <= `ALU_REG_ZERO; + o_reg_src2 <= 0; + end + 2'b01: begin + o_reg_dest <= reg_ABCD; + o_reg_src1 <= reg_BCAC; + o_reg_src2 <= 0; + end + 2'b10: begin + o_reg_dest <= reg_BCAC; + o_reg_src1 <= reg_ABCD; + o_reg_src2 <= 0; + end + 2'b11: begin // exch + o_reg_dest <= reg_ABAC; + o_reg_src1 <= reg_ABAC; + o_reg_src2 <= reg_BCCD; + end endcase end + if (do_block_Bax) begin + case ({i_nibble[3],i_nibble[2]}) + 2'b00: begin + o_reg_dest <= reg_ABCD; + o_reg_src1 <= reg_ABCD; + o_reg_src2 <= reg_BCAC; + end + 2'b01: begin + o_reg_dest <= reg_ABCD; + o_reg_src1 <= reg_ABCD; + o_reg_src2 <= 0; + end + 2'b10: begin + o_reg_dest <= reg_BCAC; + o_reg_src1 <= reg_BCAC; + o_reg_src2 <= reg_ABCD; + end + 2'b11: begin + o_reg_dest <= reg_ABCD; + o_reg_src1 <= reg_BCAC; + o_reg_src2 <= reg_ABCD; + end + endcase + end + + if (do_block_Bbx) begin + o_reg_dest <= reg_ABCD; + o_reg_src1 <= reg_ABCD; + o_reg_src2 <= 0; + end + if (do_block_Cx) begin case ({i_nibble[3],i_nibble[2]}) 2'b00: begin diff --git a/testrom-2.hex b/testrom-2.hex index cb31a03..b450108 100644 --- a/testrom-2.hex +++ b/testrom-2.hex @@ -1,2 +1,3 @@ -3 4 1 0 0 0 0 -F A // NOP3 \ No newline at end of file +2 3 +4 D F +3 1 4 3 \ No newline at end of file