diff --git a/history.txt b/history.txt index 9451f58..110fe25 100644 --- a/history.txt +++ b/history.txt @@ -43,3 +43,4 @@ second delay is posedge $glbnet$clk -> 2019-02-17 22:48 1067 69.94MHz 32.87ns 12.77ns 6427 74.33MHz 17.71ns 3.96ns 2019-02-17 23:04 1158 64.11MHz 37.87ns 12.77ns 7149 66.74MHz 19.03ns 4.06ns 2019-02-18 07:45 1128 74.65MHz 36.49ns 13.73ns 7586 75.72MHz 17.57ns 3.99ns +2019-02-19 16:26 1500 64.68MHz 42.16ns 17.32ns 10387 63.05MHz 19.43ns 7.69ns \ No newline at end of file diff --git a/saturn_alu.v b/saturn_alu.v index c7094c5..7f66ede 100644 --- a/saturn_alu.v +++ b/saturn_alu.v @@ -28,7 +28,7 @@ // `define ALU_DEBUG_DBG `endif -`define ALU_DEBUG 1'b0 +`define ALU_DEBUG 1'b1 `define ALU_DEBUG_DUMP 1'b1 `define ALU_DEBUG_JUMP 1'b0 `define ALU_DEBUG_PC 1'b0 @@ -46,15 +46,19 @@ module saturn_alu ( i_stalled, o_bus_address, + i_bus_data_ptr, + o_bus_data_nibl, o_bus_xfr_cnt, + i_bus_nibble_in, + o_bus_nibble_out, + o_bus_pc_read, o_bus_dp_read, o_bus_dp_write, o_bus_load_pc, o_bus_load_dp, o_bus_config, - i_bus_nibble_in, - o_bus_nibble_out, + i_bus_done, i_push, i_pop, @@ -103,30 +107,34 @@ input wire [0:0] i_en_alu_init; input wire [0:0] i_en_alu_save; input wire [0:0] i_stalled; +/* + * I/O to the bus controller + */ + +/* data to and from the bus controller */ output reg [19:0] o_bus_address; +input wire [3:0] i_bus_data_ptr; +output reg [3:0] o_bus_data_nibl; output reg [3:0] o_bus_xfr_cnt; +input wire [3:0] i_bus_nibble_in; +output reg [3:0] o_bus_nibble_out; + +/* control lines to the bus controller */ output reg [0:0] o_bus_pc_read; output reg [0:0] o_bus_dp_read; output reg [0:0] o_bus_dp_write; output reg [0:0] o_bus_load_pc; output reg [0:0] o_bus_load_dp; output reg [0:0] o_bus_config; -input wire [3:0] i_bus_nibble_in; -output reg [3:0] o_bus_nibble_out; +input wire [0:0] i_bus_done; +/* + * lines from the decoder + */ input wire [0:0] i_push; input wire [0:0] i_pop; input wire [0:0] i_alu_debug; -wire alu_debug; -wire alu_debug_dump; -wire alu_debug_jump; -wire alu_debug_pc; -assign alu_debug = `ALU_DEBUG || i_alu_debug; -assign alu_debug_dump = `ALU_DEBUG_DUMP || i_alu_debug; -assign alu_debug_jump = `ALU_DEBUG_JUMP || i_alu_debug; -assign alu_debug_pc = `ALU_DEBUG_PC || i_alu_debug; - output wire [0:0] o_alu_stall_dec; input wire [0:0] i_ins_decoded; @@ -161,10 +169,32 @@ output wire [19:0] o_pc; assign o_reg_p = P; assign o_pc = PC; -/* internal registers */ + +/* + * + * clock phases definitions + * + */ + wire [1:0] phase; assign phase = i_clk_ph + 3; +wire [0:0] phase_0; +wire [0:0] phase_1; +wire [0:0] phase_2; +wire [0:0] phase_3; + +assign phase_0 = (phase == 0); +assign phase_1 = (phase == 1); +assign phase_2 = (phase == 2); +assign phase_3 = (phase == 3); + +/* + * + * internal registers + * + */ + /* copy of arguments */ reg [4:0] alu_op; reg [4:0] reg_dest; @@ -204,8 +234,8 @@ reg [2:0] rstk_ptr; reg [19:0] PC; -reg [19:0] D0; -reg [19:0] D1; +reg [3:0] D0[0:4]; +reg [3:0] D1[0:4]; //reg [63:0] A; reg [3:0] A[0:15]; @@ -231,6 +261,260 @@ reg [19:0] RSTK[0:7]; initial begin end +/****************************************************************************** + * + * ALU debug modes + * + *****************************************************************************/ + + +wire alu_debug; +wire alu_debug_dump; +wire alu_debug_jump; +wire alu_debug_pc; +assign alu_debug = `ALU_DEBUG || i_alu_debug; +assign alu_debug_dump = `ALU_DEBUG_DUMP || i_alu_debug; +assign alu_debug_jump = `ALU_DEBUG_JUMP || i_alu_debug; +assign alu_debug_pc = `ALU_DEBUG_PC || i_alu_debug; + +/****************************************************************************** + * + * states decoding + * + *****************************************************************************/ + +/* + * ALU : modes of operation + * + * - classical alu used for calculations + * - data transfer to and from memory + * - jump calculations + * + */ + + +/* module 1: + * src1 and src2 can only be written here + * address can only be written here + * registers can only be read here + */ + +// the ALU is in memory transfer mode +reg [0:0] f_mode_xfr; + +wire [0:0] mode_xfr; +wire [0:0] mode_set; +wire [0:0] start_in_xfr_mode; + +assign mode_xfr = i_ins_mem_xfr || f_mode_xfr; +assign mode_set = f_mode_xfr; +assign start_in_xfr_mode = phase_3 && i_ins_mem_xfr && !mode_set; + +/* + * wires for all modes + */ + +/* source 1 */ +wire [0:0] src1_A; +wire [0:0] src1_C; +wire [0:0] src1_DAT0; +wire [0:0] src1_DAT1; + +assign src1_A = (i_reg_src1 == `ALU_REG_A); +assign src1_C = (i_reg_src1 == `ALU_REG_C); +assign src1_DAT0 = (i_reg_src1 == `ALU_REG_DAT0); +assign src1_DAT1 = (i_reg_src1 == `ALU_REG_DAT1); + +/* destination */ +wire [0:0] dest_DAT0; +wire [0:0] dest_DAT1; + +assign dest_DAT0 = (i_reg_dest == `ALU_REG_DAT0); +assign dest_DAT1 = (i_reg_dest == `ALU_REG_DAT1); + +/* + * wires specific to the XFR mode + * + * sources of address data used for XFR mode: + * - A [ PC=(A) ] + * - C [ CONFIG, UNCNFG, PC=(C) ] + * - D0 [ DAT0=reg, reg=DAT0 ] + * - D1 [ DAT1=reg, reg=DAT1 ] + */ +reg [3:0] xfr_data[0:15]; +reg [3:0] data_counter; + +// copy the address into the transfer buffer + +wire [0:0] addr_src_A; +wire [0:0] addr_src_C; +wire [0:0] addr_src_D0; +wire [0:0] addr_src_D1; +wire [0:0] addr_src_xfr_0; +wire [0:0] addr_src_xfr_1; +wire [1:0] addr_src_xfr; +wire [1:0] addr_src; +wire [0:0] copy_done; +wire [0:0] copy_address; +wire [0:0] start_load_dp; + +assign addr_src_A = (!f_mode_xfr) && src1_A; +assign addr_src_C = (!f_mode_xfr) && src1_C; +assign addr_src_D0 = ( f_mode_xfr) && (src1_DAT0 || dest_DAT0); +assign addr_src_D1 = ( f_mode_xfr) && (src1_DAT1 || dest_DAT1); +assign addr_src_xfr_0 = !addr_src_A && !addr_src_C && !addr_src_D0 && addr_src_D1; +assign addr_src_xfr_1 = !addr_src_A && !addr_src_C && (addr_src_D0 || addr_src_D1); +assign addr_src_xfr = {addr_src_xfr_1, addr_src_xfr_0}; +assign addr_src = {2{f_mode_xfr}} & addr_src_xfr; +assign copy_done = data_counter == 5; +assign copy_address = f_mode_xfr && !copy_done && !xfr_init_done; +assign start_load_dp = start_in_xfr_mode; + +// now copy the data aligning the first nibble with index 0 of the buffer +// copy nibbles 0-4 at the end so as not to clobber the address set previously +// while the bus controller is sending it + +reg [0:0] xfr_init_done; +reg [0:0] xfr_data_done; +wire [0:0] xfr_data_init; +wire [3:0] xfr_data_ctr; +wire [0:0] xfr_data_copy; +wire [0:0] xfr_copy_done; + +assign xfr_data_init = f_mode_xfr && copy_done && !xfr_init_done && !xfr_data_done && phase_3; +assign xfr_data_ctr = data_counter + i_field_start; +assign xfr_copy_done = xfr_init_done && copy_done && !xfr_data_init && !xfr_data_done; +assign xfr_data_copy = xfr_data_init || xfr_init_done && !xfr_data_done && !copy_done && !xfr_copy_done; + +/* + * sources specific pointers + */ +wire [3:0] src1_ptr; + +assign src1_ptr = ( {4{copy_address}} & data_counter ); + +always @(posedge i_clk) begin + + // initializes modes + if (i_reset) begin + f_mode_xfr <= 0; + data_counter <= 0; + xfr_init_done <= 0; + xfr_data_done <= 0; + end + + // always update the data out to the controller + o_bus_data_nibl <= xfr_data[i_bus_data_ptr]; + + if (start_in_xfr_mode) begin + $display("ALU %0d: [%d] memory transfer started (i_ins_decoded %b)", phase, i_cycle_ctr, i_ins_decoded); + $display("ALU %0d: [%d] addr_src A %b | C %b | D0 %b | D1 %b | b1 %b | b0 %b | src %2b", phase, i_cycle_ctr, + addr_src_A, addr_src_C, addr_src_D0, addr_src_D1, addr_src_xfr_1, addr_src_xfr_0, addr_src); + $display("ALU %0d: [%d] stall the decoder",phase, i_cycle_ctr); + f_mode_xfr <= 1; + end + + if (start_load_dp) begin + o_bus_load_dp <= 1; + end + + if (copy_address) begin + $display("ALU %0d: [%d] copy address f_mode_xfr %b && !copy_done %b && !xfr_init_done %b", phase, i_cycle_ctr, f_mode_xfr, !copy_done, !xfr_init_done); + $write("ALU %0d: [%d] xfr_data[%0d] = ", phase, i_cycle_ctr, data_counter); + case (addr_src) + 2'b00: begin + $display("A[%0d] %h", src1_ptr, A[src1_ptr]); + xfr_data[data_counter] <= A[src1_ptr]; + end + 2'b01: begin + $display("C[%0d] %h", src1_ptr, C[src1_ptr]); + xfr_data[data_counter] <= C[src1_ptr]; + end + 2'b10: begin + $display("D0[%0d] %h", src1_ptr, D0[src1_ptr[2:0]]); + xfr_data[data_counter] <= D0[src1_ptr[2:0]]; + end + 2'b11: begin + $display("D1[%0d] %h", src1_ptr, D1[src1_ptr[2:0]]); + xfr_data[data_counter] <= D1[src1_ptr[2:0]]; + end + default: begin end + endcase + data_counter <= data_counter + 1; + end + + // do not need to update the data counter, which is already at 5 + if (xfr_data_init) begin + $display("ALU %0d: [%d] initialize copy data | s %h | l %h | xdc %h",phase, i_cycle_ctr, i_field_start, i_field_last, xfr_data_ctr); + xfr_init_done <= 1; + end + + if (xfr_data_copy) begin + $display("ALU %0d: [%d] copy data | dc %h | xdc %h | xdd %b",phase, i_cycle_ctr, data_counter, xfr_data_ctr, xfr_data_done); + data_counter <= data_counter + 1; + end + + if (xfr_copy_done) begin + $display("ALU %0d: [%d] xfr_copy_done %h %b %b",phase, i_cycle_ctr, data_counter, xfr_init_done, xfr_data_done); + xfr_init_done <= 0; + xfr_data_done <= 1; + o_bus_load_dp <= 0; + // right on time to start the actual transfer + o_bus_dp_write <= i_xfr_dir_out; + o_bus_dp_read <= !i_xfr_dir_out; + o_bus_xfr_cnt <= (i_field_last - i_field_start); + end + + /* + * reset all things that were changed + */ + if (i_bus_done) begin + $display("ALU %0d: [%d] bus controller is done, cleaning all variables used",phase, i_cycle_ctr); + /* variables for the XFR mode */ + f_mode_xfr <= 0; + data_counter <= 0; + xfr_init_done <= 0; + xfr_data_done <= 0; + + /* bus controller control lines */ + o_bus_dp_write <= 0; + o_bus_dp_read <= 0; + o_bus_xfr_cnt <= 0; + end + +end + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +/* + */ + /* * can the alu function ? */ @@ -249,6 +533,7 @@ assign do_reg_dump = alu_active && i_en_alu_dump && !o_bus_load_pc && assign do_alu_shpc = alu_active && i_en_alu_dump; `endif + wire do_busclean; wire do_alu_init; wire do_alu_prep; @@ -268,7 +553,6 @@ assign do_alu_mode = alu_active && i_en_alu_save && i_ins_set_mode; wire do_go_init; wire do_go_prep; -wire do_go_calc; assign do_go_init = alu_active && i_en_alu_save && i_ins_test_go; assign do_go_prep = alu_active && i_en_alu_prep && i_ins_test_go; @@ -301,10 +585,10 @@ end // the decoder may request the ALU to not stall it wire bus_commands; -assign bus_commands = o_bus_config || o_bus_dp_write ; +assign bus_commands = o_bus_config ; assign o_alu_stall_dec = alu_initializing || - (alu_run && (!i_alu_no_stall || alu_finish || i_ins_mem_xfr)) || + ((alu_run || f_mode_xfr) && (!i_alu_no_stall || alu_finish || i_ins_mem_xfr)) || i_stalled || bus_commands; @@ -397,7 +681,13 @@ always @(posedge i_clk) begin $write("%h", R3[alu_dbg_ctr]); $write(" RSTK2: %5h\n", RSTK[2]); - $write("D0: %h D1: %h R4: ", D0, D1); + $write("D0: "); + for(alu_dbg_ctr=4;alu_dbg_ctr!=31;alu_dbg_ctr=alu_dbg_ctr-1) + $write("%h", D0[alu_dbg_ctr]); + $write(" D1: "); + for(alu_dbg_ctr=4;alu_dbg_ctr!=31;alu_dbg_ctr=alu_dbg_ctr-1) + $write("%h", D1[alu_dbg_ctr]); + $write(" R4: "); for(alu_dbg_ctr=15;alu_dbg_ctr!=31;alu_dbg_ctr=alu_dbg_ctr-1) $write("%h", R4[alu_dbg_ctr]); $write(" RSTK1: %5h\n", RSTK[1]); @@ -548,8 +838,8 @@ always @(posedge i_clk) begin `ALU_REG_R2: p_src1 <= R2[f_cur]; `ALU_REG_R3: p_src1 <= R3[f_cur]; `ALU_REG_R4: p_src1 <= R4[f_cur]; - `ALU_REG_D0: p_src1 <= D0[f_cur*4+:4]; - `ALU_REG_D1: p_src1 <= D1[f_cur*4+:4]; + `ALU_REG_D0: p_src1 <= D0[f_cur[2:0]]; + `ALU_REG_D1: p_src1 <= D1[f_cur[2:0]]; `ALU_REG_P: p_src1 <= P; `ALU_REG_DAT0, `ALU_REG_DAT1: p_src1 <= i_bus_nibble_in; @@ -591,8 +881,8 @@ always @(posedge i_clk) begin `ALU_REG_R2: p_src2 <= R2[f_cur]; `ALU_REG_R3: p_src2 <= R3[f_cur]; `ALU_REG_R4: p_src2 <= R4[f_cur]; - `ALU_REG_D0: p_src2 <= D0[f_cur*4+:4]; - `ALU_REG_D1: p_src2 <= D1[f_cur*4+:4]; + `ALU_REG_D0: p_src2 <= D0[f_cur[2:0]]; + `ALU_REG_D1: p_src2 <= D1[f_cur[2:0]]; `ALU_REG_P: p_src2 <= P; `ALU_REG_HST: p_src2 <= HST; `ALU_REG_IMM: p_src2 <= i_imm_value; @@ -733,8 +1023,6 @@ always @(posedge i_clk) begin alu_initializing <= 1; CARRY <= 0; P <= 0; - D0 <= 0; - D1 <= 0; end if (alu_initializing) begin @@ -742,6 +1030,8 @@ always @(posedge i_clk) begin B[f_cur] <= 0; C[f_cur] <= 0; D[f_cur] <= 0; + D0[f_cur[2:0]] <= 0; + D1[f_cur[2:0]] <= 0; R0[f_cur] <= 0; R1[f_cur] <= 0; R2[f_cur] <= 0; @@ -814,8 +1104,8 @@ always @(posedge i_clk) begin `ALU_REG_R2: R2[f_cur] <= c_res1; `ALU_REG_R3: R3[f_cur] <= c_res1; `ALU_REG_R4: R4[f_cur] <= c_res1; - `ALU_REG_D0: D0[f_cur*4+:4] <= c_res1; - `ALU_REG_D1: D1[f_cur*4+:4] <= c_res1; + `ALU_REG_D0: D0[f_cur[2:0]] <= c_res1; + `ALU_REG_D1: D1[f_cur[2:0]] <= c_res1; `ALU_REG_ST: ST[f_cur*4+:4] <= c_res1; `ALU_REG_P: P <= c_res1; `ALU_REG_DAT0, @@ -849,8 +1139,8 @@ 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_D0: D0[f_cur[2:0]] <= c_res2; + `ALU_REG_D1: D1[f_cur[2:0]] <= 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; @@ -977,8 +1267,8 @@ always @(posedge i_clk) begin if (read_done) begin $display("============================================= old read_done"); - o_bus_load_dp <= 0; - o_bus_dp_read <= 0; + // o_bus_load_dp <= 0; + // o_bus_dp_read <= 0; end /* @@ -992,9 +1282,17 @@ always @(posedge i_clk) begin // tell the bus to start the write cycle // this will take 1 cycle because we need to send the DP_WRITE command - if (do_busclean && alu_run && !write_done && is_mem_write && !o_bus_dp_write) + if (do_busclean && alu_run && !write_done && is_mem_write && !o_bus_dp_write) begin o_bus_dp_write <= 1; - + $display("ALU %0d: %0d nibbles to write", phase, f_last - f_first + 1); + o_bus_xfr_cnt <= f_last - f_first; + end + + // if (do_alu_calc && alu_run && alu_finish && o_bus_dp_write) begin + // $display("ALU %0d: end of write", phase); + // write_done <= 1; + // o_bus_dp_write <= 0; + // end // writing takes 2 more cycles : // - one used up above // - one used down below to restore the PC_READ command @@ -1015,12 +1313,13 @@ always @(posedge i_clk) begin // once the PC_READ command has been sent, remove the stall on the decoder if (i_en_alu_dump && no_extra_cycles && o_bus_pc_read) begin + o_bus_pc_read <= 0; write_done <= 0; end - if (do_busclean && o_bus_load_dp) - o_bus_load_dp <= 0; + // if (do_busclean && o_bus_load_dp) + // o_bus_load_dp <= 0; end @@ -1129,11 +1428,11 @@ always @(posedge i_clk) begin // necessary for the write to memory above // otherwise we get a conflict on o_bus_address - if (setup_load_dp) - case (mem_reg[0]) - 0: o_bus_address <= D0; - 1: o_bus_address <= D1; - endcase + // if (setup_load_dp) + // case (mem_reg[0]) + // 0: o_bus_address <= D0; + // 1: o_bus_address <= D1; + // endcase // this is moved here for access conflicts to o_bus_address if (do_alu_save && (alu_op == `ALU_OP_COPY) && (reg_dest == `ALU_REG_ADDR)) begin diff --git a/saturn_bus_ctrl.v b/saturn_bus_ctrl.v index 619450e..5999b95 100644 --- a/saturn_bus_ctrl.v +++ b/saturn_bus_ctrl.v @@ -44,6 +44,7 @@ module saturn_bus_ctrl ( i_alu_busy, o_stall_alu, + o_bus_done, // bus i/o o_bus_reset, @@ -55,6 +56,8 @@ module saturn_bus_ctrl ( // interface to the rest of the machine i_alu_pc, i_address, + i_data_nibl, + o_data_ptr, i_cmd_load_pc, i_cmd_load_dp, i_read_pc, @@ -77,6 +80,7 @@ input wire [0:0] i_stalled; input wire [0:0] i_alu_busy; output reg [0:0] o_stall_alu; +output reg [0:0] o_bus_done; output reg [0:0] o_bus_reset; input wire [3:0] i_bus_data; @@ -86,6 +90,8 @@ output reg [0:0] o_bus_cmd_data; input wire [19:0] i_alu_pc; input wire [19:0] i_address; +input wire [3:0] i_data_nibl; +output reg [3:0] o_data_ptr; input wire [0:0] i_cmd_load_pc; input wire [0:0] i_cmd_load_dp; input wire [0:0] i_read_pc; @@ -254,7 +260,7 @@ assign cmd_DP_WRITE_0 = phase_0 && cmd_DP_WRITE_TST; // sets cmd_DP_WRITE_F0 assign cmd_DP_WRITE_STR = cmd_DP_WRITE_0; assign cmd_DP_WRITE_US0 = phase_2 && cmd_DP_WRITE_F0 && !cmd_DP_WRITE_F1 && o_stall_alu; // after all nibbles were sent -assign cmd_DP_WRITE_1 = phase_3 && !i_cmd_dp_write && cmd_DP_WRITE_F0 && !cmd_DP_WRITE_F1; // sets cmd_DP_WRITE_F1 +assign cmd_DP_WRITE_1 = phase_3 && (o_data_ptr == i_xfr_cnt) && cmd_DP_WRITE_F0 && !cmd_DP_WRITE_F1; // sets cmd_DP_WRITE_F1 assign cmd_DP_WRITE_US1 = phase_2 && cmd_DP_WRITE_F1; assign cmd_DP_WRITE_C = phase_3 && cmd_DP_WRITE_F1; @@ -304,7 +310,7 @@ wire [0:0] cmd_LOAD_DP_0; wire [0:0] cmd_LOAD_DP_STR; wire [0:0] cmd_LOAD_DP_C; -assign cmd_LOAD_DP_TST = i_cmd_load_dp; +assign cmd_LOAD_DP_TST = i_cmd_load_dp && !cmd_LOAD_DP_F; assign cmd_LOAD_DP_0 = phase_0 && cmd_LOAD_DP_TST; // sets cmd_LOAD_DP_F assign cmd_LOAD_DP_STR = cmd_LOAD_DP_TST; assign cmd_LOAD_DP_C = phase_3 && do_auto_DP_READ_TST; @@ -316,7 +322,7 @@ wire [0:0] do_auto_DP_READ_TST; wire [0:0] do_auto_DP_READ_0; wire [0:0] do_auto_DP_READ_US0; -assign do_auto_DP_READ_TST = cmd_LOAD_DP_F && addr_loop_done && !cmd_DP_READ_F; +assign do_auto_DP_READ_TST = cmd_LOAD_DP_F && addr_loop_done; assign do_auto_DP_READ_0 = phase_1 && do_auto_DP_READ_TST; // does nothing ? assign do_auto_DP_READ_US0 = phase_3 && o_stall_alu && do_auto_DP_READ_TST && cmd_LOAD_DP_F && !(cmd_DP_WRITE_F0); // || cmd_DP_READ_F); @@ -395,10 +401,9 @@ assign do_unstall = o_stall_alu && wire [0:0] do_load_clean; wire [0:0] do_clean; -assign do_load_clean = cmd_LOAD_PC_C; +assign do_load_clean = cmd_LOAD_PC_C || cmd_LOAD_DP_C; assign do_clean = do_read_dp_US2 || cmd_DP_WRITE_C || cmd_CONFIGURE_C || cmd_RESET_C; -reg [2:0] addr_loop_counter; reg [0:0] addr_loop_done; reg [0:0] init_addr_loop; reg [0:0] run_addr_loop; @@ -413,8 +418,8 @@ assign do_init_addr_loop = phase_0 && cmd_LOAD_DP_TST || cmd_CONFIGURE_0); assign do_run_addr_loop = phase_0 && run_addr_loop && !is_loop_finished; -assign will_loop_finish = addr_loop_counter == 4; -assign is_loop_finished = addr_loop_counter == 5; +assign will_loop_finish = o_data_ptr == 4; +assign is_loop_finished = o_data_ptr == 5; assign do_reset_loop_counter = phase_3 && is_loop_finished; /****************************************************************************** @@ -450,6 +455,14 @@ initial begin // i_clk, i_phase, o_stall_alu, i_alu_busy, // i_cmd_dp_write, cmd_LOAD_DP_F, addr_loop_done, do_auto_DP_READ_TST, cmd_DP_WRITE_F0, cmd_DP_WRITE_F1); + /* + * debug dp_read + */ + // $monitor({"BUS - clk %b | ph %0d | osta %b | iabs %b | ", + // "i_cmd_dp_read %b | cmd_LOAD_DP_F %b | addr_loop_done %b | do_auto_DP_READ_TST %b | cmd_DP_WRITE_F0 %b | cnd_DP_WRITE_F1 %b"}, + // i_clk, i_phase, o_stall_alu, i_alu_busy, + // i_cmd_dp_read, cmd_LOAD_DP_F, addr_loop_done, do_auto_DP_READ_TST, cmd_DP_WRITE_F0, cmd_DP_WRITE_F1); + /* debug strobe for reading */ // $monitor({"BUS - clk %b | ph %0d | osta %b | iabs %b | ", @@ -487,14 +500,17 @@ always @(posedge i_clk) begin strobe_on <= 0; o_bus_cmd_data <= 1; // 1 is the default level bus_out_of_reset <= 1; + o_data_ptr <= 0; // local states // address loop init_addr_loop <= 0; run_addr_loop <= 0; - addr_loop_counter <= 0; addr_loop_done <= 0; + // read and write loops + o_data_ptr <= 0; + cmd_PC_READ_F <= 0; cmd_DP_READ_F <= 0; cmd_DP_WRITE_F0 <= 0; @@ -537,8 +553,9 @@ always @(posedge i_clk) begin */ if (cmd_DP_WRITE_0) begin - $display("BUS_CTRL %1d: [%d] DP_WRITE", i_phase, i_cycle_ctr); - cmd_DP_WRITE_F0 <= 1; + $display("BUS_CTRL %1d: [%d] DP_WRITE (%0d nibble to write - ctr %0d)", i_phase, i_cycle_ctr, i_xfr_cnt + 1, o_data_ptr); + cmd_DP_WRITE_F0 <= 1; + o_data_ptr <= 0; last_cmd <= `BUSCMD_DP_WRITE; o_bus_data <= `BUSCMD_DP_WRITE; o_bus_cmd_data <= 0; @@ -556,11 +573,13 @@ always @(posedge i_clk) begin end if (cmd_DP_WRITE_US1) begin - $display("BUS_CTRL %1d: [%d] cmd_DP_WRITE_US1", i_phase, i_cycle_ctr); + $display("BUS_CTRL %1d: [%d] cmd_DP_WRITE_US1 (signal done)", i_phase, i_cycle_ctr); + o_bus_done <= 1; end if (cmd_DP_WRITE_C) begin $display("BUS_CTRL %1d: [%d] cmd_DP_WRITE_C", i_phase, i_cycle_ctr); + o_bus_done <= 0; end /* @@ -611,7 +630,7 @@ always @(posedge i_clk) begin /* automatic DP_READ after LOAD_DP */ if (do_auto_DP_READ_0) begin - $display("BUS_CTRL %1d: [%d] auto DP_READ", i_phase, i_cycle_ctr); + $display("BUS_CTRL %1d: [%d] auto DP_READ (%0d nibble to read - ctr %0d)", i_phase, i_cycle_ctr, i_xfr_cnt + 1, o_data_ptr); cmd_DP_READ_F <= 1; last_cmd <= `BUSCMD_DP_READ; end @@ -666,28 +685,29 @@ always @(posedge i_clk) begin if (do_init_addr_loop) begin // $display("BUS_CTRL %1d: [%d] init addr loop", i_phase, i_cycle_ctr); addr_loop_done <= 0; - addr_loop_counter <= 0; + o_data_ptr <= 0; run_addr_loop <= 1; init_addr_loop <= 0; end if (do_run_addr_loop) begin $write("BUS_CTRL %1d: [%d] ADDR(%0d)-> %h ", - i_phase, i_cycle_ctr, addr_loop_counter, - i_address[addr_loop_counter*4+:4]); + i_phase, i_cycle_ctr, o_data_ptr, + i_data_nibl); if (will_loop_finish) $write("done"); $write("\n"); - o_bus_data <= i_address[addr_loop_counter*4+:4]; + if (LC_load_pc) o_bus_data <= i_address[o_data_ptr*4+:4]; + if (LC_load_dp) o_bus_data <= i_data_nibl; // clean up at the end of loop - addr_loop_counter <= addr_loop_counter + 1; - run_addr_loop <= !will_loop_finish; - addr_loop_done <= will_loop_finish; + o_data_ptr <= o_data_ptr + 1; + run_addr_loop <= !will_loop_finish; + addr_loop_done <= will_loop_finish; end if (do_reset_loop_counter) begin // $display("BUS_CTRL %1d: [%d] reset loop counter", i_phase, i_cycle_ctr); - addr_loop_counter <= 0; + o_data_ptr <= 0; end @@ -703,12 +723,14 @@ always @(posedge i_clk) begin if (do_load_clean) begin $display("BUS_CTRL %1d: [%d] cleanup after load", i_phase, i_cycle_ctr); cmd_LOAD_PC_F <= 0; + cmd_LOAD_DP_F <= 0; + o_data_ptr <= 0; end if (do_clean) begin $display("BUS_CTRL %1d: [%d] cleanup", i_phase, i_cycle_ctr); cmd_PC_READ_F <= 0; - do_read_dp_s <= 0; + cmd_DP_READ_F <= 0; cmd_DP_WRITE_F0 <= 0; cmd_DP_WRITE_F1 <= 0; cmd_CONFIGURE_F0 <= 0; @@ -738,8 +760,9 @@ always @(posedge i_clk) begin end if (do_WRITE_DP_0) begin - $display("BUS_CTRL %1d: [%d] WRITE %h", i_phase, i_cycle_ctr, i_nibble); - o_bus_data <= i_nibble; + $display("BUS_CTRL %1d: [%d] WRITE %h (%0d to go)", i_phase, i_cycle_ctr, i_data_nibl, i_xfr_cnt - o_data_ptr); + o_bus_data <= i_data_nibl; + o_data_ptr <= (o_data_ptr == i_xfr_cnt)?o_data_ptr: o_data_ptr + 1; end if (do_read_stalled_by_alu) begin diff --git a/saturn_core.v b/saturn_core.v index b4db99d..ed28a5d 100644 --- a/saturn_core.v +++ b/saturn_core.v @@ -225,15 +225,19 @@ saturn_alu m_alu ( .i_stalled (alu_stalled), .o_bus_address (alu_bus_address), + .i_bus_data_ptr (ctrl_bus_data_ptr), + .o_bus_data_nibl (alu_bus_data_nibl), .o_bus_xfr_cnt (alu_bus_xfr_cnt), + .i_bus_nibble_in (ctrl_bus_nibble_in), + .o_bus_nibble_out (alu_bus_nibble_out), + .o_bus_load_pc (alu_bus_load_pc), .o_bus_load_dp (alu_bus_load_dp), .o_bus_pc_read (alu_bus_pc_read), .o_bus_dp_read (alu_bus_dp_read), .o_bus_dp_write (alu_bus_dp_write), .o_bus_config (alu_bus_config), - .i_bus_nibble_in (ctrl_bus_nibble_in), - .o_bus_nibble_out (alu_bus_nibble_out), + .i_bus_done (ctrl_bus_done), .i_push (push), .i_pop (pop), @@ -274,6 +278,7 @@ saturn_alu m_alu ( // interconnections wire [19:0] alu_bus_address; +wire [3:0] alu_bus_data_nibl; wire [3:0] alu_bus_xfr_cnt; wire [0:0] alu_bus_pc_read; wire [0:0] alu_bus_dp_read; @@ -282,7 +287,6 @@ wire [0:0] alu_bus_load_pc; wire [0:0] alu_bus_load_dp; wire [0:0] alu_bus_config; -wire [3:0] ctrl_bus_nibble_in; wire [3:0] alu_bus_nibble_out; wire [0:0] alu_stalls_dec; @@ -303,7 +307,9 @@ saturn_bus_ctrl m_bus_ctrl ( .i_cycle_ctr (cycle_ctr), .i_stalled (mem_ctrl_stall), .i_alu_busy (dec_stalled), + .o_stall_alu (bus_stalls_core), + .o_bus_done (ctrl_bus_done), //bus i/o .o_bus_reset (o_bus_reset), @@ -315,6 +321,8 @@ saturn_bus_ctrl m_bus_ctrl ( // interface to the rest of the machine .i_alu_pc (reg_pc), .i_address (alu_bus_address), + .i_data_nibl (alu_bus_data_nibl), + .o_data_ptr (ctrl_bus_data_ptr), .i_cmd_load_pc (alu_bus_load_pc), .i_cmd_load_dp (alu_bus_load_dp), .i_read_pc (alu_bus_pc_read), @@ -331,6 +339,9 @@ saturn_bus_ctrl m_bus_ctrl ( reg [0:0] mem_ctrl_stall; wire [0:0] bus_stalls_core; +wire [0:0] ctrl_bus_done; +wire [3:0] ctrl_bus_data_ptr; +wire [3:0] ctrl_bus_nibble_in; // `define DEBUG_CLOCKS @@ -418,7 +429,7 @@ always @(posedge i_clk) begin clock_end <= 0; cycle_ctr <= ~0; - max_cycle <= 72; + max_cycle <= 30; mem_ctrl_stall <= 0; `ifndef SIM @@ -450,133 +461,7 @@ endmodule `ifdef SIM `include "def-buscmd.v" - -/****************************************************************************** - * - * test rom - * - ****************************************************************************/ - -module test_rom ( - i_phase, - - i_reset, - i_bus_data_in, - o_bus_data_out, - i_bus_strobe, - i_bus_cmd_data -); - -input wire [1:0] i_phase; - -input wire [0:0] i_reset; -input wire [3:0] i_bus_data_in; -output reg [3:0] o_bus_data_out; -input wire [0:0] i_bus_strobe; -input wire [0:0] i_bus_cmd_data; - -reg [31:0] cycles; - -`ifdef SIM -`define ROMBITS 20 -`else -`define ROMBITS 12 -`endif - -reg [3:0] rom [0:2**`ROMBITS-1]; - -reg [19:0] local_pc; -reg [19:0] local_dp; - -reg [3:0] last_bus_cmd; -reg [2:0] addr_c; -wire [0:0] s_load_pc; -wire [0:0] s_load_dp; -wire [0:0] s_pc_read; -wire [0:0] s_dp_read; -wire [0:0] s_dp_write; -assign s_load_pc = (last_bus_cmd == `BUSCMD_LOAD_PC); -assign s_load_dp = (last_bus_cmd == `BUSCMD_LOAD_DP); -assign s_pc_read = (last_bus_cmd == `BUSCMD_PC_READ); -assign s_dp_read = (last_bus_cmd == `BUSCMD_DP_READ); -assign s_dp_write = (last_bus_cmd == `BUSCMD_DP_WRITE); - -initial begin - $readmemh("rom-gx-r.hex", rom, 0, 2**`ROMBITS-1); - // $monitor("rst %b | strb %b | c/d %b | bus_i %h | bus_o %h | last %h | slpc %b | addr_c %0d | lpc %5h | ldp %5h", - // i_reset, i_bus_strobe, i_bus_cmd_data, i_bus_data_in, o_bus_data_out, - // last_bus_cmd, s_load_pc, addr_c, local_pc, local_dp); -end - -always @(posedge i_bus_strobe) begin - - if (i_reset) begin - cycles <= 0; - last_bus_cmd <= `BUSCMD_NOP; - addr_c <= 0; - local_pc <= 0; - local_dp <= 0; - end - - if (!i_reset) - cycles <= cycles + 1; - - - if (!i_bus_cmd_data) begin - - $write("ROM %0d: [%d] COMMAND ", i_phase, cycles); - case (i_bus_data_in) - `BUSCMD_PC_READ: $write("PC_READ"); // 2 - `BUSCMD_DP_WRITE: $write("DP_WRITE"); // 5 - `BUSCMD_LOAD_PC: $write("LOAD_PC"); // 6 - `BUSCMD_LOAD_DP: $write("LOAD_DP"); // 7 - `BUSCMD_CONFIGURE: $write("CONFIGURE (ignore)"); // 8 - `BUSCMD_RESET: $write("RESET (ignore)"); // 15 - endcase - $write(" (%h)\n", i_bus_data_in); - - last_bus_cmd <= i_bus_data_in; - end - - // if (i_bus_cmd_data) begin - // $display("BUS DATA %h", i_bus_data_in); - // end - - if (i_bus_cmd_data && s_load_pc) begin - $display("ROM %0d: [%d] ADDR_IN(%0d) %h => PC [%5h]", i_phase, cycles, addr_c, i_bus_data_in, local_pc); - local_pc[addr_c*4+:4] <= i_bus_data_in; - if (addr_c == 4) $display("ROM : [%d] auto PC_READ [%5h]", cycles, {i_bus_data_in, local_pc[15:0]}); - last_bus_cmd <= (addr_c == 4)?`BUSCMD_PC_READ:last_bus_cmd; - addr_c <= (addr_c == 4)?0:addr_c + 1; - end - - if (i_bus_cmd_data && s_load_dp) begin - $display("ROM %0d: [%d] ADDR_IN(%0d) %h => DP [%5h]", i_phase, cycles, addr_c, i_bus_data_in, local_dp); - local_dp[addr_c*4+:4] <= i_bus_data_in; - if (addr_c == 4) $display("ROM : [%d] auto DP_READ [%5h]", cycles, {i_bus_data_in, local_dp[15:0]}); - last_bus_cmd <= (addr_c == 4)?`BUSCMD_DP_READ:last_bus_cmd; - addr_c <= (addr_c == 4)?0:addr_c + 1; - end - - if (i_bus_cmd_data && s_pc_read) begin - o_bus_data_out <= rom[local_pc]; - $display("ROM %0d: [%d] %h <= PC_READ [%5h]", i_phase, cycles, rom[local_pc], local_pc); - local_pc <= local_pc + 1; - end - - if (i_bus_cmd_data && s_dp_read) begin - o_bus_data_out <= rom[local_dp]; - $display("ROM %0d: [%d] %h <= DP_READ [%5h]", i_phase, cycles, rom[local_dp], local_dp); - local_dp <= local_dp + 1; - end - - if (i_bus_cmd_data && s_dp_write) begin - $display("ROM %0d: [%d] %h => DP_WRITE [%5h] (ignored)", i_phase, cycles, i_bus_data_in, local_dp); - end - -end - -endmodule +`include "saturn_test_rom.v" /****************************************************************************** * diff --git a/saturn_decoder.v b/saturn_decoder.v index d6200d8..506434b 100644 --- a/saturn_decoder.v +++ b/saturn_decoder.v @@ -1,6 +1,6 @@ /* (c) Raphaël Jacquot 2019 - + This file is part of hp_saturn. hp_saturn is free software: you can redistribute it and/or modify @@ -556,21 +556,21 @@ always @(posedge i_clk) begin `endif // o_alu_debug <= 1; o_fields_table <= i_nibble[3]?`FT_TABLE_value:`FT_TABLE_a; - o_alu_op <= `ALU_OP_COPY; + // o_alu_op <= `ALU_OP_COPY; go_fields_table <= use_fields_tbl; use_fields_tbl <= 0; // do not block when we're reading - o_alu_no_stall <= !use_fields_tbl && i_nibble[1]; + // o_alu_no_stall <= !use_fields_tbl && i_nibble[1]; // o_alu_debug <= i_nibble[1]; // set the info about this being a memory transfer - o_ins_mem_xfr <= 1; + o_ins_mem_xfr <= !(use_fields_tbl); o_xfr_dir_out <= !i_nibble[1]; block_15xx <= use_fields_tbl; - o_ins_alu_op <= !(use_fields_tbl); + // o_ins_alu_op <= !(use_fields_tbl); next_nibble <= use_fields_tbl; o_ins_decoded <= !(use_fields_tbl); block_14x_15xx <= 0; @@ -581,8 +581,9 @@ always @(posedge i_clk) begin $display("block_15xx %h", i_nibble); `endif o_alu_debug <= 1; - o_alu_no_stall <= 1; - o_ins_alu_op <= 1; + // o_alu_no_stall <= 1; + // o_ins_alu_op <= 1; + o_ins_mem_xfr <= 1; o_ins_decoded <= 1; next_nibble <= 0; block_15xx <= 0; diff --git a/saturn_decoder_block_8.v b/saturn_decoder_block_8.v index c80545b..d154df3 100644 --- a/saturn_decoder_block_8.v +++ b/saturn_decoder_block_8.v @@ -1,4 +1,6 @@ /* + (c) Raphaël Jacquot 2019 + This file is part of hp_saturn. hp_saturn is free software: you can redistribute it and/or modify diff --git a/saturn_decoder_debugger.v b/saturn_decoder_debugger.v index f71542f..52d8af1 100644 --- a/saturn_decoder_debugger.v +++ b/saturn_decoder_debugger.v @@ -272,7 +272,7 @@ always @(posedge i_clk) begin $write("\t"); if (o_field_valid) begin - // $write("[FT%d]", o_fields_table); + $write("[FT%d]", o_fields_table); if (o_fields_table != `FT_TABLE_value) case (o_field) `FT_FIELD_P: $write("P"); diff --git a/saturn_test_rom.v b/saturn_test_rom.v new file mode 100644 index 0000000..024ede4 --- /dev/null +++ b/saturn_test_rom.v @@ -0,0 +1,152 @@ +/* + (c) Raphaël Jacquot 2019 + + This file is part of hp_saturn. + + hp_saturn is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + any later version. + + hp_saturn is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with Foobar. If not, see . + + */ + +`ifndef _SATURN_TEST_ROM +`define _SATURN_TEST_ROM + +/****************************************************************************** + * + * test rom + * + ****************************************************************************/ + +module test_rom ( + i_phase, + + i_reset, + i_bus_data_in, + o_bus_data_out, + i_bus_strobe, + i_bus_cmd_data +); + +input wire [1:0] i_phase; + +input wire [0:0] i_reset; +input wire [3:0] i_bus_data_in; +output reg [3:0] o_bus_data_out; +input wire [0:0] i_bus_strobe; +input wire [0:0] i_bus_cmd_data; + +reg [31:0] cycles; + +`ifdef SIM +`define ROMBITS 20 +`else +`define ROMBITS 12 +`endif + +reg [3:0] rom [0:2**`ROMBITS-1]; + +reg [19:0] local_pc; +reg [19:0] local_dp; + +reg [3:0] last_bus_cmd; +reg [2:0] addr_c; +wire [0:0] s_load_pc; +wire [0:0] s_load_dp; +wire [0:0] s_pc_read; +wire [0:0] s_dp_read; +wire [0:0] s_dp_write; +assign s_load_pc = (last_bus_cmd == `BUSCMD_LOAD_PC); +assign s_load_dp = (last_bus_cmd == `BUSCMD_LOAD_DP); +assign s_pc_read = (last_bus_cmd == `BUSCMD_PC_READ); +assign s_dp_read = (last_bus_cmd == `BUSCMD_DP_READ); +assign s_dp_write = (last_bus_cmd == `BUSCMD_DP_WRITE); + +initial begin +// $readmemh("rom-gx-r.hex", rom, 0, 2**`ROMBITS-1); + $readmemh("testrom-2.hex", rom, 0, 2**`ROMBITS-1); + // $monitor("rst %b | strb %b | c/d %b | bus_i %h | bus_o %h | last %h | slpc %b | addr_c %0d | lpc %5h | ldp %5h", + // i_reset, i_bus_strobe, i_bus_cmd_data, i_bus_data_in, o_bus_data_out, + // last_bus_cmd, s_load_pc, addr_c, local_pc, local_dp); +end + +always @(posedge i_bus_strobe) begin + + if (i_reset) begin + cycles <= 0; + last_bus_cmd <= `BUSCMD_NOP; + addr_c <= 0; + local_pc <= 0; + local_dp <= 0; + end + + if (!i_reset) + cycles <= cycles + 1; + + + if (!i_bus_cmd_data) begin + + $write("ROM %0d: [%d] COMMAND ", i_phase, cycles); + case (i_bus_data_in) + `BUSCMD_PC_READ: $write("PC_READ"); // 2 + `BUSCMD_DP_WRITE: $write("DP_WRITE"); // 5 + `BUSCMD_LOAD_PC: $write("LOAD_PC"); // 6 + `BUSCMD_LOAD_DP: $write("LOAD_DP"); // 7 + `BUSCMD_CONFIGURE: $write("CONFIGURE (ignore)"); // 8 + `BUSCMD_RESET: $write("RESET (ignore)"); // 15 + endcase + $write(" (%h)\n", i_bus_data_in); + + last_bus_cmd <= i_bus_data_in; + end + + // if (i_bus_cmd_data) begin + // $display("BUS DATA %h", i_bus_data_in); + // end + + if (i_bus_cmd_data && s_load_pc) begin + $display("ROM %0d: [%d] ADDR_IN(%0d) %h => PC [%5h]", i_phase, cycles, addr_c, i_bus_data_in, local_pc); + local_pc[addr_c*4+:4] <= i_bus_data_in; + if (addr_c == 4) $display("ROM : [%d] auto PC_READ [%5h]", cycles, {i_bus_data_in, local_pc[15:0]}); + last_bus_cmd <= (addr_c == 4)?`BUSCMD_PC_READ:last_bus_cmd; + addr_c <= (addr_c == 4)?0:addr_c + 1; + end + + if (i_bus_cmd_data && s_load_dp) begin + $display("ROM %0d: [%d] ADDR_IN(%0d) %h => DP [%5h]", i_phase, cycles, addr_c, i_bus_data_in, local_dp); + local_dp[addr_c*4+:4] <= i_bus_data_in; + if (addr_c == 4) $display("ROM : [%d] auto DP_READ [%5h]", cycles, {i_bus_data_in, local_dp[15:0]}); + last_bus_cmd <= (addr_c == 4)?`BUSCMD_DP_READ:last_bus_cmd; + addr_c <= (addr_c == 4)?0:addr_c + 1; + end + + if (i_bus_cmd_data && s_pc_read) begin + o_bus_data_out <= rom[local_pc]; + $display("ROM %0d: [%d] %h <= PC_READ [%5h]", i_phase, cycles, rom[local_pc], local_pc); + local_pc <= local_pc + 1; + end + + if (i_bus_cmd_data && s_dp_read) begin + o_bus_data_out <= rom[local_dp]; + $display("ROM %0d: [%d] %h <= DP_READ [%5h]", i_phase, cycles, rom[local_dp], local_dp); + local_dp <= local_dp + 1; + end + + if (i_bus_cmd_data && s_dp_write) begin + $display("ROM %0d: [%d] %h => DP_WRITE [%5h] (ignored)", i_phase, cycles, i_bus_data_in, local_dp); + end + +end + +endmodule + +`endif diff --git a/testrom-2.hex b/testrom-2.hex index b450108..c94c96b 100644 --- a/testrom-2.hex +++ b/testrom-2.hex @@ -1,3 +1,3 @@ -2 3 -4 D F -3 1 4 3 \ No newline at end of file +1 B 5 4 3 2 1 +1 4 c +2 0 \ No newline at end of file