mirror of
https://github.com/sxpert/hp-saturn
synced 2025-01-20 10:26:31 +01:00
entirely rework the DP_WRITE and WRITE_DP case
This commit is contained in:
parent
7d63f0f57a
commit
30d7e6c8df
9 changed files with 570 additions and 207 deletions
|
@ -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
|
383
saturn_alu.v
383
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
|
||||
|
|
|
@ -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
|
||||
|
|
147
saturn_core.v
147
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"
|
||||
|
||||
/******************************************************************************
|
||||
*
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
152
saturn_test_rom.v
Normal 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
|
|
@ -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
|
Loading…
Reference in a new issue