diff --git a/saturn_alu.v b/saturn_alu.v index ff46406..5bf17d1 100644 --- a/saturn_alu.v +++ b/saturn_alu.v @@ -16,6 +16,7 @@ module saturn_alu ( i_clk, i_reset, + i_cycle_ctr, i_en_alu_dump, i_en_alu_prep, i_en_alu_calc, @@ -26,6 +27,8 @@ module saturn_alu ( o_bus_address, o_bus_load_pc, o_bus_load_dp, + o_bus_read_pc, + o_bus_write_dp, o_bus_nibble_out, i_push, @@ -61,6 +64,7 @@ module saturn_alu ( input wire [0:0] i_clk; input wire [0:0] i_reset; +input wire [31:0] i_cycle_ctr; input wire [0:0] i_en_alu_dump; input wire [0:0] i_en_alu_prep; input wire [0:0] i_en_alu_calc; @@ -71,6 +75,8 @@ input wire [0:0] i_stalled; output reg [19:0] o_bus_address; output reg [0:0] o_bus_load_pc; output reg [0:0] o_bus_load_dp; +output reg [0:0] o_bus_read_pc; +output reg [0:0] o_bus_write_dp; output reg [3:0] o_bus_nibble_out; input wire [0:0] i_push; @@ -261,7 +267,7 @@ wire do_alu_pc; wire do_alu_mode; assign do_busclean = alu_active && i_en_alu_dump; -assign do_alu_init = alu_active && i_en_alu_init && i_ins_alu_op && !alu_run; +assign do_alu_init = alu_active && i_en_alu_init && i_ins_alu_op && !alu_run && !write_done; assign do_alu_prep = alu_active && i_en_alu_prep && alu_run; assign do_alu_calc = alu_active && i_en_alu_calc && alu_run; assign do_alu_save = alu_active && i_en_alu_save && alu_run; @@ -277,7 +283,9 @@ assign do_go_prep = alu_active && i_en_alu_prep && i_ins_test_go; // the decoder may request the ALU to not stall it -assign o_alu_stall_dec = alu_run && (!i_alu_no_stall || alu_finish || alu_go_test); +assign o_alu_stall_dec = (!no_extra_cycles) || + (alu_run && + (!i_alu_no_stall || alu_finish || alu_go_test)); wire alu_start; wire alu_finish; @@ -309,9 +317,9 @@ assign is_alu_op_test = ((alu_op == `ALU_OP_TEST_EQ) || always @(posedge i_clk) begin `ifdef SIM - if (i_stalled && i_en_alu_dump) - $display("ALU STALLED"); -`endif +// if (i_stalled && i_en_alu_dump) +// $display("ALU STALLED"); +// `endif `ifdef ALU_DEBUG_DBG $display("iad %b | AD %b | ad %b | ADD %b | add %b | ADJ %b | adj %b | ADP %b | adp %b", @@ -376,18 +384,6 @@ always @(posedge i_clk) begin reg_src2 <= i_reg_src2; f_last <= i_field_last; - if (is_mem_xfer) begin -`ifdef SIM - $display("ALU_XFER 3: read %b | write %b | mem_reg DAT%b", - is_mem_read, is_mem_write, mem_reg[0]); - $display(".------------------------------------."); - $display("| SHOULD TELL THE BUS CONTROLLER TO |"); - $display("| LOAD D0 OR D1 INTO MODULES' DP REG |"); - $display("`------------------------------------´"); -`endif - // DO SOMETHING TO GET THE BUS CONTROLLER TO SEND OUT - // THE CONTENTS OF D0 OR D1 AS THE DP - end end end @@ -398,6 +394,7 @@ end always @(posedge i_clk) begin if (do_alu_init) begin + $display("------------------------------------------------- DO_ALU_INIT"); alu_run <= 1; f_first <= i_field_start; f_cur <= i_field_start; @@ -552,7 +549,7 @@ always @(posedge i_clk) begin if (do_alu_calc) begin `ifdef SIM if (alu_debug) - $display("ALU_CALC 2: run %b | done %b | stall %b | op %d | f %h | c %h | l %h | dest %d | src1 %h | src2 %h | p_carry %b", + $display("ALU_CALC 2: run %b | done %b | stall %b | op %d | f %h | c %h | l %h | dest %d | psrc1 %h | psrc2 %h | p_carry %b", alu_run, alu_done, o_alu_stall_dec, alu_op, f_first, f_cur, f_last, reg_dest, p_src1, p_src2, p_carry); if (alu_debug_jump) $display("ALU_JUMP 2: run %b | done %b | stall %b | op %d | f %h | c %h | l %h | jbs %5h | jof %5h | jpc %5h | fin %b", @@ -650,15 +647,18 @@ always @(posedge i_clk) begin `ALU_OP_ADD, `ALU_OP_CLR_MASK: case (reg_dest) - `ALU_REG_A: A[f_cur*4+:4] <= c_res1; - `ALU_REG_B: B[f_cur*4+:4] <= c_res1; - `ALU_REG_C: C[f_cur*4+:4] <= c_res1; - `ALU_REG_D: D[f_cur*4+:4] <= c_res1; - `ALU_REG_D0: D0[f_cur*4+:4] <= c_res1; - `ALU_REG_D1: D1[f_cur*4+:4] <= c_res1; - `ALU_REG_ST: ST[f_cur*4+:4] <= c_res1; - `ALU_REG_P: P <= c_res1; - `ALU_REG_HST: HST <= c_res1; + `ALU_REG_A: A[f_cur*4+:4] <= c_res1; + `ALU_REG_B: B[f_cur*4+:4] <= c_res1; + `ALU_REG_C: C[f_cur*4+:4] <= c_res1; + `ALU_REG_D: D[f_cur*4+:4] <= c_res1; + `ALU_REG_D0: D0[f_cur*4+:4] <= c_res1; + `ALU_REG_D1: D1[f_cur*4+:4] <= c_res1; + `ALU_REG_ST: ST[f_cur*4+:4] <= c_res1; + `ALU_REG_P: P <= c_res1; + `ALU_REG_DAT0, + `ALU_REG_DAT1: o_bus_nibble_out <= c_res1; + `ALU_REG_HST: HST <= c_res1; + default: $display("#### ALU_SAVE invalid register %0d for op %0d", reg_dest, alu_op); endcase `ALU_OP_RST_BIT, `ALU_OP_SET_BIT: @@ -733,6 +733,11 @@ wire [0:0] pop_pc; wire [0:0] reload_pc; wire [0:0] push_pc; +reg [1:0] extra_cycles; +wire [0:0] no_extra_cycles; +wire [1:0] cycles_to_go; +reg [0:0] write_done; + 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; @@ -745,10 +750,17 @@ assign pop_pc = i_pop && i_ins_rtn && assign reload_pc = uncond_jmp || pop_pc || just_reset; assign push_pc = update_pc && i_push && alu_finish; +assign no_extra_cycles = (extra_cycles == 0); +assign cycles_to_go = extra_cycles - 1; + always @(posedge i_clk) begin if (i_reset) begin - PC <= ~0; - just_reset <= 1; + PC <= ~0; + just_reset <= 1; + extra_cycles <= 0; + o_bus_load_pc <= 0; + o_bus_load_dp <= 0; + o_bus_write_dp <= 0; end @@ -766,8 +778,74 @@ always @(posedge i_clk) begin `endif /* - * updates the PC + * + * Request the D0 or D1 pointers to be loaded to other + * modules through the bus + * */ + + + // $display("[!no_ec %b] || ( [run %b] && ( [!nstll %b] || [fin %b] || [test %b] ))", + // !no_extra_cycles, alu_run, !i_alu_no_stall, alu_finish, alu_go_test); + + + if (do_alu_init) begin + if (is_mem_xfer && !write_done) begin +`ifdef SIM + $display("ALU_XFER 3: read %b | write %b | mem_reg DAT%b", + is_mem_read, is_mem_write, mem_reg[0]); + // $display(".------------------------------------."); + // $display("| SHOULD TELL THE BUS CONTROLLER TO |"); + // $display("| LOAD D0 OR D1 INTO MODULES' DP REG |"); + // $display("`------------------------------------´"); +`endif + // DO SOMETHING TO GET THE BUS CONTROLLER TO SEND OUT + // THE CONTENTS OF D0 OR D1 AS THE DP + case (mem_reg[0]) + 0: o_bus_address <= D0; + 1: o_bus_address <= D1; + endcase + o_bus_load_dp <= 1; + end + end + + if (do_busclean && alu_run && !write_done) + if (is_mem_write && !o_bus_write_dp) begin + // $display("ALUWRITE %0d: [%d] setting up write", `PH_ALU_DUMP, i_cycle_ctr); + o_bus_write_dp <= 1; + end + + // writing needs one more cycle as the DP_WRITE command + // needs to be send + if (do_alu_save && alu_finish && is_mem_write && (extra_cycles == 0)) begin + // $display("ALUWRITE %0d: [%d] 2 EXTRA CYCLES", `PH_ALU_SAVE, i_cycle_ctr); + extra_cycles <= 2; + write_done <= 1; + end + + if (i_en_alu_calc && !no_extra_cycles) begin + // $display("ALUWRITE %0d: [%d] %0d CYCLES TO GO", `PH_ALU_SAVE, i_cycle_ctr, cycles_to_go); + extra_cycles <= cycles_to_go; + if (cycles_to_go == 1) begin + o_bus_write_dp <= 0; + o_bus_read_pc <= 1; + end + end + + if (i_en_alu_dump && no_extra_cycles && o_bus_read_pc) begin + // $display("ALUWRITE %0d: [%d] RELEASE DECODER", `PH_ALU_DUMP, i_cycle_ctr); + o_bus_read_pc <= 0; + write_done <= 0; + end + + /** + * + * Update the PC. + * Request the new PC be loaded to the other modules through + * the bus if necessary + * + */ + if (do_alu_pc) begin // $display("DO ALU PC"); `ifdef SIM @@ -778,19 +856,20 @@ always @(posedge i_clk) begin !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); - if (reload_pc) begin - $display(".---------------------------------."); - $display("| SHOULD TELL THE BUS CONTROLLER |"); - $display("| TO LOAD PC INTO MODULES' PC REG |"); - $display("`---------------------------------´"); - end + // if (reload_pc) begin + // $display(".---------------------------------."); + // $display("| SHOULD TELL THE BUS CONTROLLER |"); + // $display("| TO LOAD PC INTO MODULES' PC REG |"); + // $display("`---------------------------------´"); + // end `endif // if we just came out of reset, simulate a long jump to 0 if (just_reset) begin - $display("ALU_RSET 3: simulating GOVLNG to PC"); + // $display("ALU_RSET 3: simulating GOVLNG to PC"); // cancel this signal for good once reset is gone - just_reset <= 0; + just_reset <= 0; + o_bus_read_pc <= 1; end // this may do wierd things with C=RSTK... @@ -799,7 +878,7 @@ always @(posedge i_clk) begin end if (reload_pc) begin - $display("ALU_PC 3: $$$$ RELOADING PC $$$$"); + // $display("ALU_PC 3: $$$$ RELOADING PC $$$$"); o_bus_address <= pop_pc ? RSTK[rstk_ptr-1] : next_pc; o_bus_load_pc <= 1; end @@ -819,9 +898,17 @@ always @(posedge i_clk) begin end end - // deactivate o_load_pc - if (do_busclean && o_bus_load_pc) - o_bus_load_pc <= 0; + /* + * + * Deactivate the load_pc or load_dp enables on the next clock + * + */ + + if (do_busclean && (o_bus_load_pc || o_bus_load_dp)) begin + $display("BUSCLEAN %0d: cleaning the various bus control bits", `PH_ALU_DUMP); + o_bus_load_pc <= 0; + o_bus_load_dp <= 0; + end end diff --git a/saturn_bus_ctrl.v b/saturn_bus_ctrl.v index 6055c51..3af9da5 100644 --- a/saturn_bus_ctrl.v +++ b/saturn_bus_ctrl.v @@ -28,6 +28,8 @@ module saturn_bus_ctrl ( i_address, i_load_pc, i_load_dp, + i_read_pc, + i_write_dp, i_nibble, o_nibble ); @@ -52,6 +54,8 @@ input wire [19:0] i_alu_pc; input wire [19:0] i_address; input wire [0:0] i_load_pc; input wire [0:0] i_load_dp; +input wire [0:0] i_read_pc; +input wire [0:0] i_write_dp; input wire [3:0] i_nibble; output reg [3:0] o_nibble; @@ -84,21 +88,23 @@ initial begin // $readmemh( "testrom-2.hex", rom); // $monitor("addr %5h | strb %b | c/d %b | cnt %0d | odata %h | idata %h", // i_address, o_bus_strobe, o_bus_cmd_data, addr_cnt, o_bus_data, i_bus_data); + +// $monitor("MONITOR : strb %b | o_bus_data %h | i_bus_data %h", o_bus_strobe, o_bus_data, i_bus_data); `endif end -reg [2:0] addr_cnt; - -reg [0:0] send_addr; - +reg [3:0] last_cmd; +reg [2:0] addr_cnt; +reg [0:0] send_addr; reg [19:0] local_pc; +reg [19:0] local_dp; always @(posedge i_clk) begin if (i_reset) begin o_stalled_by_bus <= 0; o_bus_strobe <= 0; o_bus_cmd_data <= 1; // 1 is the default level - addr_cnt <= 0; + addr_cnt <= 0; end /* @@ -108,35 +114,90 @@ always @(posedge i_clk) begin */ if (en_bus_send) begin + /* + * Sending LOAD_PC or LOAD_DP + */ + if (i_load_pc) begin - $display("BUS_SEND %0d: loading pc %h", `PH_BUS_SEND, i_address); + $display("BUS_SEND %0d: [%d] LOAD_PC %h", `PH_BUS_SEND, i_cycle_ctr, i_address); o_bus_data <= `BUSCMD_LOAD_PC; + last_cmd <= `BUSCMD_LOAD_PC; end if (i_load_dp) begin - $display("BUS_SEND %0d: loading dp %h", `PH_BUS_SEND, i_address); + $display("BUS_SEND %0d: [%d] LOAD_DP %h", `PH_BUS_SEND, i_cycle_ctr, i_address); o_bus_data <= `BUSCMD_LOAD_DP; + last_cmd <= `BUSCMD_LOAD_DP; end if (i_load_pc || i_load_dp) begin o_stalled_by_bus <= 1; - o_bus_cmd_data <= 0; - addr_cnt <= 0; - send_addr <= 1; + o_bus_cmd_data <= 0; + addr_cnt <= 0; + send_addr <= 1; + o_bus_strobe <= 1; end + // sending address bits if (send_addr) begin - $display("BUS_SEND %0d: send addr nibble %0d [%h]", `PH_BUS_SEND, addr_cnt, i_address[addr_cnt*4+:4]); + $display("BUS_SEND %0d: [%d] addr[%0d] %h =>", + `PH_BUS_SEND, i_cycle_ctr, addr_cnt, i_address[addr_cnt*4+:4]); o_bus_data <= i_address[addr_cnt*4+:4]; addr_cnt <= addr_cnt + 1; + o_bus_strobe <= 1; end - if (!i_read_stall || send_addr) + /* + * send the PC_READ command to restore the instruction flow + * after a data transfer + */ + + if (i_read_pc) begin + if (last_cmd != `BUSCMD_PC_READ) begin + $display("BUS_SEND %0d: [%d] PC_READ", `PH_BUS_SEND, i_cycle_ctr); + o_bus_data <= `BUSCMD_PC_READ; + last_cmd <= `BUSCMD_PC_READ; + end + o_bus_strobe <= 1; + end + + if ((last_cmd == `BUSCMD_PC_READ) && !i_read_stall) + o_bus_strobe <= 1; + + /* + * writing data to the bus, + * send DP_WRITE first if necessary + */ + + if (i_write_dp && (addr_cnt == 5)) begin + if (last_cmd != `BUSCMD_DP_WRITE) begin + $display("BUS_SEND %0d: [%d] DP_WRITE", `PH_BUS_SEND, i_cycle_ctr); + o_bus_data <= `BUSCMD_DP_WRITE; + last_cmd <= `BUSCMD_DP_WRITE; o_bus_strobe <= 1; + end else 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 if (en_bus_ecmd && send_addr && (addr_cnt == 5)) begin - $display("BUS_ECMD %0d: releasing stall after sending addr", `PH_BUS_ECMD); + case (last_cmd) + `BUSCMD_LOAD_PC: begin + $display("BUS_ECMD %0d: [%d] <= PC_READ mode", `PH_BUS_ECMD, i_cycle_ctr); + last_cmd <= `BUSCMD_PC_READ; + local_pc <= i_address; + end + `BUSCMD_LOAD_DP: begin + $display("BUS_ECMD %0d: [%d] <= DP_READ mode", `PH_BUS_ECMD, i_cycle_ctr); + last_cmd <= `BUSCMD_DP_READ; + local_dp <= i_address; + end + endcase send_addr <= 0; o_stalled_by_bus = 0; end @@ -146,9 +207,15 @@ always @(posedge i_clk) begin * reading data from the bus * */ + + if (en_bus_recv && !i_read_stall) begin - $display("BUS_RECV %0d: [%d] nibble %h", `PH_BUS_RECV, i_cycle_ctr, rom[i_alu_pc[`ROMBITS-1:0]]); - o_nibble <= rom[i_alu_pc[`ROMBITS-1:0]]; + if (last_cmd == `BUSCMD_PC_READ) begin + $display("BUS_RECV %0d: [%d] <= READ %h", `PH_BUS_RECV, i_cycle_ctr, rom[local_pc[`ROMBITS-1:0]]); + o_nibble <= rom[local_pc[`ROMBITS-1:0]]; + local_pc <= local_pc + 1; + end else + $display("BUS_RECV %0d: [%d] UNKNOWN COMMAND %h", `PH_BUS_RECV, i_cycle_ctr, last_cmd); end /* diff --git a/saturn_core.v b/saturn_core.v index 198e382..fee3c1a 100644 --- a/saturn_core.v +++ b/saturn_core.v @@ -86,6 +86,7 @@ saturn_decoder m_decoder ( .i_en_dbg (ck_debugger), .i_en_dec (ck_inst_dec), .i_pc (reg_pc), + .i_bus_load_pc (bus_load_pc), .i_stalled (dec_stalled), .i_nibble (bus_nibble_in), @@ -156,6 +157,7 @@ wire [0:0] ins_test_go; saturn_alu m_alu ( .i_clk (clk), .i_reset (reset), + .i_cycle_ctr (cycle_ctr), .i_en_alu_dump (ck_alu_dump), .i_en_alu_prep (ck_alu_prep), .i_en_alu_calc (ck_alu_calc), @@ -166,6 +168,8 @@ saturn_alu m_alu ( .o_bus_address (bus_address), .o_bus_load_pc (bus_load_pc), .o_bus_load_dp (bus_load_dp), + .o_bus_read_pc (bus_read_pc), + .o_bus_write_dp (bus_write_dp), .o_bus_nibble_out (bus_nibble_out), .i_push (push), @@ -204,6 +208,8 @@ saturn_alu m_alu ( wire [19:0] bus_address; wire [0:0] bus_load_pc; wire [0:0] bus_load_dp; +wire [0:0] bus_read_pc; +wire [0:0] bus_write_dp; wire [3:0] bus_nibble_in; wire [3:0] bus_nibble_out; @@ -241,6 +247,8 @@ saturn_bus_ctrl m_bus_ctrl ( .i_address (bus_address), .i_load_pc (bus_load_pc), .i_load_dp (bus_load_dp), + .i_read_pc (bus_read_pc), + .i_write_dp (bus_write_dp), .i_nibble (bus_nibble_out), .o_nibble (bus_nibble_in) ); @@ -313,7 +321,6 @@ always @(posedge clk) begin ck_alu_save <= clk_phase[1:0] == `PH_ALU_SAVE; cycle_ctr <= cycle_ctr + { {31{1'b0}}, (clk_phase[1:0] == `PH_BUS_SEND) }; - // stop after 50 clocks if (cycle_ctr == (max_cycle + 1)) begin $display(".-------------------."); $display("| OUT OF CYCLES |"); @@ -340,7 +347,7 @@ always @(posedge clk) begin clock_end <= 0; cycle_ctr <= ~0; - max_cycle <= 20; + max_cycle <= 155; mem_ctrl_stall <= 0; `ifndef SIM diff --git a/saturn_decoder.v b/saturn_decoder.v index f98cf99..31ef048 100644 --- a/saturn_decoder.v +++ b/saturn_decoder.v @@ -8,7 +8,8 @@ `include "def-alu.v" module saturn_decoder( - i_clk, i_reset, i_cycles, i_en_dbg, i_en_dec, i_stalled, + i_clk, i_reset, i_cycles, i_en_dbg, i_en_dec, + i_bus_load_pc, i_stalled, i_pc, i_nibble, i_reg_p, @@ -41,26 +42,27 @@ module saturn_decoder( input wire [0:0] i_clk; input wire [0:0] i_reset; input wire [31:0] i_cycles; -input wire i_en_dbg; -input wire i_en_dec; -input wire i_stalled; +input wire [0:0] i_en_dbg; +input wire [0:0] i_en_dec; +input wire [0:0] i_bus_load_pc; +input wire [0:0] i_stalled; input wire [19:0] i_pc; input wire [3:0] i_nibble; input wire [3:0] i_reg_p; -output reg o_inc_pc; -output reg o_push; -output reg o_pop; -output reg o_dec_error; +output reg [0:0] o_inc_pc; +output reg [0:0] o_push; +output reg [0:0] o_pop; +output reg [0:0] o_dec_error; `ifdef SIM output reg [0:0] o_unimplemented; `endif -output reg o_alu_debug; +output reg [0:0] o_alu_debug; // instructions related outputs output reg [19:0] o_ins_addr; -output reg o_ins_decoded; +output reg [0:0] o_ins_decoded; output reg [1:0] o_fields_table; output reg [3:0] o_field; @@ -76,20 +78,20 @@ output reg [4:0] o_reg_src1; output reg [4:0] o_reg_src2; // rtn specific -output reg o_ins_rtn; -output reg o_set_xm; -output reg o_set_carry; -output reg o_test_carry; -output reg o_carry_val; -output reg o_en_intr; +output reg [0:0] o_ins_rtn; +output reg [0:0] o_set_xm; +output reg [0:0] o_set_carry; +output reg [0:0] o_test_carry; +output reg [0:0] o_carry_val; +output reg [0:0] o_en_intr; // setdec/hex -output reg o_ins_set_mode; -output reg o_mode_dec; +output reg [0:0] o_ins_set_mode; +output reg [0:0] o_mode_dec; // alu_operations -output reg o_ins_alu_op; -output reg o_ins_test_go; +output reg [0:0] o_ins_alu_op; +output reg [0:0] o_ins_test_go; /* data used by the debugger * @@ -434,6 +436,7 @@ always @(posedge i_clk) begin block_13x <= 1; 4'h4, 4'h5: // DAT[01]=[AC] begin + o_alu_debug <= 0; `ifdef SIM $display("block_1x %h | use table <= %b", i_nibble, i_nibble[0]); `endif diff --git a/saturn_decoder_debugger.v b/saturn_decoder_debugger.v index cf70531..03ee9a0 100644 --- a/saturn_decoder_debugger.v +++ b/saturn_decoder_debugger.v @@ -8,7 +8,7 @@ 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; +assign run_debugger = !i_reset && i_en_dbg && !i_stalled && !i_bus_load_pc && !next_nibble; wire is_short_transfer; assign is_short_transfer = (o_field_last == 3) &&