entirely rework the DP_WRITE and WRITE_DP case

This commit is contained in:
Raphael Jacquot 2019-02-21 16:55:08 +01:00
parent 7d63f0f57a
commit 30d7e6c8df
9 changed files with 570 additions and 207 deletions

View file

@ -43,3 +43,4 @@ second delay is posedge $glbnet$clk -> <async>
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

View file

@ -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

View file

@ -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

View file

@ -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"
/******************************************************************************
*

View file

@ -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;

View file

@ -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

View file

@ -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");

152
saturn_test_rom.v Normal file
View file

@ -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 <https://www.gnu.org/licenses/>.
*/
`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

View file

@ -1,3 +1,3 @@
2 3
4 D F
3 1 4 3
1 B 5 4 3 2 1
1 4 c
2 0