implement the pieces to replicate the bus data transfers for writing data out.

This commit is contained in:
Raphael Jacquot 2019-02-17 12:05:38 +01:00
parent 128921c364
commit 8fc7cde507
5 changed files with 244 additions and 80 deletions

View file

@ -16,6 +16,7 @@
module saturn_alu (
i_clk,
i_reset,
i_cycle_ctr,
i_en_alu_dump,
i_en_alu_prep,
i_en_alu_calc,
@ -26,6 +27,8 @@ module saturn_alu (
o_bus_address,
o_bus_load_pc,
o_bus_load_dp,
o_bus_read_pc,
o_bus_write_dp,
o_bus_nibble_out,
i_push,
@ -61,6 +64,7 @@ module saturn_alu (
input wire [0:0] i_clk;
input wire [0:0] i_reset;
input wire [31:0] i_cycle_ctr;
input wire [0:0] i_en_alu_dump;
input wire [0:0] i_en_alu_prep;
input wire [0:0] i_en_alu_calc;
@ -71,6 +75,8 @@ input wire [0:0] i_stalled;
output reg [19:0] o_bus_address;
output reg [0:0] o_bus_load_pc;
output reg [0:0] o_bus_load_dp;
output reg [0:0] o_bus_read_pc;
output reg [0:0] o_bus_write_dp;
output reg [3:0] o_bus_nibble_out;
input wire [0:0] i_push;
@ -261,7 +267,7 @@ wire do_alu_pc;
wire do_alu_mode;
assign do_busclean = alu_active && i_en_alu_dump;
assign do_alu_init = alu_active && i_en_alu_init && i_ins_alu_op && !alu_run;
assign do_alu_init = alu_active && i_en_alu_init && i_ins_alu_op && !alu_run && !write_done;
assign do_alu_prep = alu_active && i_en_alu_prep && alu_run;
assign do_alu_calc = alu_active && i_en_alu_calc && alu_run;
assign do_alu_save = alu_active && i_en_alu_save && alu_run;
@ -277,7 +283,9 @@ assign do_go_prep = alu_active && i_en_alu_prep && i_ins_test_go;
// the decoder may request the ALU to not stall it
assign o_alu_stall_dec = alu_run && (!i_alu_no_stall || alu_finish || alu_go_test);
assign o_alu_stall_dec = (!no_extra_cycles) ||
(alu_run &&
(!i_alu_no_stall || alu_finish || alu_go_test));
wire alu_start;
wire alu_finish;
@ -309,9 +317,9 @@ assign is_alu_op_test = ((alu_op == `ALU_OP_TEST_EQ) ||
always @(posedge i_clk) begin
`ifdef SIM
if (i_stalled && i_en_alu_dump)
$display("ALU STALLED");
`endif
// if (i_stalled && i_en_alu_dump)
// $display("ALU STALLED");
// `endif
`ifdef ALU_DEBUG_DBG
$display("iad %b | AD %b | ad %b | ADD %b | add %b | ADJ %b | adj %b | ADP %b | adp %b",
@ -376,18 +384,6 @@ always @(posedge i_clk) begin
reg_src2 <= i_reg_src2;
f_last <= i_field_last;
if (is_mem_xfer) begin
`ifdef SIM
$display("ALU_XFER 3: read %b | write %b | mem_reg DAT%b",
is_mem_read, is_mem_write, mem_reg[0]);
$display(".------------------------------------.");
$display("| SHOULD TELL THE BUS CONTROLLER TO |");
$display("| LOAD D0 OR D1 INTO MODULES' DP REG |");
$display("`------------------------------------´");
`endif
// DO SOMETHING TO GET THE BUS CONTROLLER TO SEND OUT
// THE CONTENTS OF D0 OR D1 AS THE DP
end
end
end
@ -398,6 +394,7 @@ end
always @(posedge i_clk) begin
if (do_alu_init) begin
$display("------------------------------------------------- DO_ALU_INIT");
alu_run <= 1;
f_first <= i_field_start;
f_cur <= i_field_start;
@ -552,7 +549,7 @@ always @(posedge i_clk) begin
if (do_alu_calc) begin
`ifdef SIM
if (alu_debug)
$display("ALU_CALC 2: run %b | done %b | stall %b | op %d | f %h | c %h | l %h | dest %d | src1 %h | src2 %h | p_carry %b",
$display("ALU_CALC 2: run %b | done %b | stall %b | op %d | f %h | c %h | l %h | dest %d | psrc1 %h | psrc2 %h | p_carry %b",
alu_run, alu_done, o_alu_stall_dec, alu_op, f_first, f_cur, f_last, reg_dest, p_src1, p_src2, p_carry);
if (alu_debug_jump)
$display("ALU_JUMP 2: run %b | done %b | stall %b | op %d | f %h | c %h | l %h | jbs %5h | jof %5h | jpc %5h | fin %b",
@ -650,15 +647,18 @@ always @(posedge i_clk) begin
`ALU_OP_ADD,
`ALU_OP_CLR_MASK:
case (reg_dest)
`ALU_REG_A: A[f_cur*4+:4] <= c_res1;
`ALU_REG_B: B[f_cur*4+:4] <= c_res1;
`ALU_REG_C: C[f_cur*4+:4] <= c_res1;
`ALU_REG_D: D[f_cur*4+:4] <= c_res1;
`ALU_REG_D0: D0[f_cur*4+:4] <= c_res1;
`ALU_REG_D1: D1[f_cur*4+:4] <= c_res1;
`ALU_REG_ST: ST[f_cur*4+:4] <= c_res1;
`ALU_REG_P: P <= c_res1;
`ALU_REG_HST: HST <= c_res1;
`ALU_REG_A: A[f_cur*4+:4] <= c_res1;
`ALU_REG_B: B[f_cur*4+:4] <= c_res1;
`ALU_REG_C: C[f_cur*4+:4] <= c_res1;
`ALU_REG_D: D[f_cur*4+:4] <= c_res1;
`ALU_REG_D0: D0[f_cur*4+:4] <= c_res1;
`ALU_REG_D1: D1[f_cur*4+:4] <= c_res1;
`ALU_REG_ST: ST[f_cur*4+:4] <= c_res1;
`ALU_REG_P: P <= c_res1;
`ALU_REG_DAT0,
`ALU_REG_DAT1: o_bus_nibble_out <= c_res1;
`ALU_REG_HST: HST <= c_res1;
default: $display("#### ALU_SAVE invalid register %0d for op %0d", reg_dest, alu_op);
endcase
`ALU_OP_RST_BIT,
`ALU_OP_SET_BIT:
@ -733,6 +733,11 @@ wire [0:0] pop_pc;
wire [0:0] reload_pc;
wire [0:0] push_pc;
reg [1:0] extra_cycles;
wire [0:0] no_extra_cycles;
wire [1:0] cycles_to_go;
reg [0:0] write_done;
assign next_pc = (is_alu_op_jump && alu_finish)?jump_pc:PC + 1;
assign goyes_off = {{12{i_imm_value[3]}}, i_imm_value, jump_off[3:0]};
assign goyes_pc = jump_bse + goyes_off;
@ -745,10 +750,17 @@ assign pop_pc = i_pop && i_ins_rtn &&
assign reload_pc = uncond_jmp || pop_pc || just_reset;
assign push_pc = update_pc && i_push && alu_finish;
assign no_extra_cycles = (extra_cycles == 0);
assign cycles_to_go = extra_cycles - 1;
always @(posedge i_clk) begin
if (i_reset) begin
PC <= ~0;
just_reset <= 1;
PC <= ~0;
just_reset <= 1;
extra_cycles <= 0;
o_bus_load_pc <= 0;
o_bus_load_dp <= 0;
o_bus_write_dp <= 0;
end
@ -766,8 +778,74 @@ always @(posedge i_clk) begin
`endif
/*
* updates the PC
*
* Request the D0 or D1 pointers to be loaded to other
* modules through the bus
*
*/
// $display("[!no_ec %b] || ( [run %b] && ( [!nstll %b] || [fin %b] || [test %b] ))",
// !no_extra_cycles, alu_run, !i_alu_no_stall, alu_finish, alu_go_test);
if (do_alu_init) begin
if (is_mem_xfer && !write_done) begin
`ifdef SIM
$display("ALU_XFER 3: read %b | write %b | mem_reg DAT%b",
is_mem_read, is_mem_write, mem_reg[0]);
// $display(".------------------------------------.");
// $display("| SHOULD TELL THE BUS CONTROLLER TO |");
// $display("| LOAD D0 OR D1 INTO MODULES' DP REG |");
// $display("`------------------------------------´");
`endif
// DO SOMETHING TO GET THE BUS CONTROLLER TO SEND OUT
// THE CONTENTS OF D0 OR D1 AS THE DP
case (mem_reg[0])
0: o_bus_address <= D0;
1: o_bus_address <= D1;
endcase
o_bus_load_dp <= 1;
end
end
if (do_busclean && alu_run && !write_done)
if (is_mem_write && !o_bus_write_dp) begin
// $display("ALUWRITE %0d: [%d] setting up write", `PH_ALU_DUMP, i_cycle_ctr);
o_bus_write_dp <= 1;
end
// writing needs one more cycle as the DP_WRITE command
// needs to be send
if (do_alu_save && alu_finish && is_mem_write && (extra_cycles == 0)) begin
// $display("ALUWRITE %0d: [%d] 2 EXTRA CYCLES", `PH_ALU_SAVE, i_cycle_ctr);
extra_cycles <= 2;
write_done <= 1;
end
if (i_en_alu_calc && !no_extra_cycles) begin
// $display("ALUWRITE %0d: [%d] %0d CYCLES TO GO", `PH_ALU_SAVE, i_cycle_ctr, cycles_to_go);
extra_cycles <= cycles_to_go;
if (cycles_to_go == 1) begin
o_bus_write_dp <= 0;
o_bus_read_pc <= 1;
end
end
if (i_en_alu_dump && no_extra_cycles && o_bus_read_pc) begin
// $display("ALUWRITE %0d: [%d] RELEASE DECODER", `PH_ALU_DUMP, i_cycle_ctr);
o_bus_read_pc <= 0;
write_done <= 0;
end
/**
*
* Update the PC.
* Request the new PC be loaded to the other modules through
* the bus if necessary
*
*/
if (do_alu_pc) begin
// $display("DO ALU PC");
`ifdef SIM
@ -778,19 +856,20 @@ always @(posedge i_clk) begin
!o_alu_stall_dec, next_pc, alu_done, alu_finish,
is_alu_op_jump, i_ins_rtn, i_push,
i_imm_value, jump_bse, goyes_off, goyes_pc);
if (reload_pc) begin
$display(".---------------------------------.");
$display("| SHOULD TELL THE BUS CONTROLLER |");
$display("| TO LOAD PC INTO MODULES' PC REG |");
$display("`---------------------------------´");
end
// if (reload_pc) begin
// $display(".---------------------------------.");
// $display("| SHOULD TELL THE BUS CONTROLLER |");
// $display("| TO LOAD PC INTO MODULES' PC REG |");
// $display("`---------------------------------´");
// end
`endif
// if we just came out of reset, simulate a long jump to 0
if (just_reset) begin
$display("ALU_RSET 3: simulating GOVLNG to PC");
// $display("ALU_RSET 3: simulating GOVLNG to PC");
// cancel this signal for good once reset is gone
just_reset <= 0;
just_reset <= 0;
o_bus_read_pc <= 1;
end
// this may do wierd things with C=RSTK...
@ -799,7 +878,7 @@ always @(posedge i_clk) begin
end
if (reload_pc) begin
$display("ALU_PC 3: $$$$ RELOADING PC $$$$");
// $display("ALU_PC 3: $$$$ RELOADING PC $$$$");
o_bus_address <= pop_pc ? RSTK[rstk_ptr-1] : next_pc;
o_bus_load_pc <= 1;
end
@ -819,9 +898,17 @@ always @(posedge i_clk) begin
end
end
// deactivate o_load_pc
if (do_busclean && o_bus_load_pc)
o_bus_load_pc <= 0;
/*
*
* Deactivate the load_pc or load_dp enables on the next clock
*
*/
if (do_busclean && (o_bus_load_pc || o_bus_load_dp)) begin
$display("BUSCLEAN %0d: cleaning the various bus control bits", `PH_ALU_DUMP);
o_bus_load_pc <= 0;
o_bus_load_dp <= 0;
end
end

View file

@ -28,6 +28,8 @@ module saturn_bus_ctrl (
i_address,
i_load_pc,
i_load_dp,
i_read_pc,
i_write_dp,
i_nibble,
o_nibble
);
@ -52,6 +54,8 @@ input wire [19:0] i_alu_pc;
input wire [19:0] i_address;
input wire [0:0] i_load_pc;
input wire [0:0] i_load_dp;
input wire [0:0] i_read_pc;
input wire [0:0] i_write_dp;
input wire [3:0] i_nibble;
output reg [3:0] o_nibble;
@ -84,21 +88,23 @@ initial begin
// $readmemh( "testrom-2.hex", rom);
// $monitor("addr %5h | strb %b | c/d %b | cnt %0d | odata %h | idata %h",
// i_address, o_bus_strobe, o_bus_cmd_data, addr_cnt, o_bus_data, i_bus_data);
// $monitor("MONITOR : strb %b | o_bus_data %h | i_bus_data %h", o_bus_strobe, o_bus_data, i_bus_data);
`endif
end
reg [2:0] addr_cnt;
reg [0:0] send_addr;
reg [3:0] last_cmd;
reg [2:0] addr_cnt;
reg [0:0] send_addr;
reg [19:0] local_pc;
reg [19:0] local_dp;
always @(posedge i_clk) begin
if (i_reset) begin
o_stalled_by_bus <= 0;
o_bus_strobe <= 0;
o_bus_cmd_data <= 1; // 1 is the default level
addr_cnt <= 0;
addr_cnt <= 0;
end
/*
@ -108,35 +114,90 @@ always @(posedge i_clk) begin
*/
if (en_bus_send) begin
/*
* Sending LOAD_PC or LOAD_DP
*/
if (i_load_pc) begin
$display("BUS_SEND %0d: loading pc %h", `PH_BUS_SEND, i_address);
$display("BUS_SEND %0d: [%d] LOAD_PC %h", `PH_BUS_SEND, i_cycle_ctr, i_address);
o_bus_data <= `BUSCMD_LOAD_PC;
last_cmd <= `BUSCMD_LOAD_PC;
end
if (i_load_dp) begin
$display("BUS_SEND %0d: loading dp %h", `PH_BUS_SEND, i_address);
$display("BUS_SEND %0d: [%d] LOAD_DP %h", `PH_BUS_SEND, i_cycle_ctr, i_address);
o_bus_data <= `BUSCMD_LOAD_DP;
last_cmd <= `BUSCMD_LOAD_DP;
end
if (i_load_pc || i_load_dp) begin
o_stalled_by_bus <= 1;
o_bus_cmd_data <= 0;
addr_cnt <= 0;
send_addr <= 1;
o_bus_cmd_data <= 0;
addr_cnt <= 0;
send_addr <= 1;
o_bus_strobe <= 1;
end
// sending address bits
if (send_addr) begin
$display("BUS_SEND %0d: send addr nibble %0d [%h]", `PH_BUS_SEND, addr_cnt, i_address[addr_cnt*4+:4]);
$display("BUS_SEND %0d: [%d] addr[%0d] %h =>",
`PH_BUS_SEND, i_cycle_ctr, addr_cnt, i_address[addr_cnt*4+:4]);
o_bus_data <= i_address[addr_cnt*4+:4];
addr_cnt <= addr_cnt + 1;
o_bus_strobe <= 1;
end
if (!i_read_stall || send_addr)
/*
* send the PC_READ command to restore the instruction flow
* after a data transfer
*/
if (i_read_pc) begin
if (last_cmd != `BUSCMD_PC_READ) begin
$display("BUS_SEND %0d: [%d] PC_READ", `PH_BUS_SEND, i_cycle_ctr);
o_bus_data <= `BUSCMD_PC_READ;
last_cmd <= `BUSCMD_PC_READ;
end
o_bus_strobe <= 1;
end
if ((last_cmd == `BUSCMD_PC_READ) && !i_read_stall)
o_bus_strobe <= 1;
/*
* writing data to the bus,
* send DP_WRITE first if necessary
*/
if (i_write_dp && (addr_cnt == 5)) begin
if (last_cmd != `BUSCMD_DP_WRITE) begin
$display("BUS_SEND %0d: [%d] DP_WRITE", `PH_BUS_SEND, i_cycle_ctr);
o_bus_data <= `BUSCMD_DP_WRITE;
last_cmd <= `BUSCMD_DP_WRITE;
o_bus_strobe <= 1;
end else begin
$display("BUS_SEND %0d: [%d] WRITE %h =>", `PH_BUS_SEND, i_cycle_ctr, i_nibble);
o_bus_data <= i_nibble;
o_bus_strobe <= 1;
end
end
end
if (en_bus_ecmd && send_addr && (addr_cnt == 5)) begin
$display("BUS_ECMD %0d: releasing stall after sending addr", `PH_BUS_ECMD);
case (last_cmd)
`BUSCMD_LOAD_PC: begin
$display("BUS_ECMD %0d: [%d] <= PC_READ mode", `PH_BUS_ECMD, i_cycle_ctr);
last_cmd <= `BUSCMD_PC_READ;
local_pc <= i_address;
end
`BUSCMD_LOAD_DP: begin
$display("BUS_ECMD %0d: [%d] <= DP_READ mode", `PH_BUS_ECMD, i_cycle_ctr);
last_cmd <= `BUSCMD_DP_READ;
local_dp <= i_address;
end
endcase
send_addr <= 0;
o_stalled_by_bus = 0;
end
@ -146,9 +207,15 @@ always @(posedge i_clk) begin
* reading data from the bus
*
*/
if (en_bus_recv && !i_read_stall) begin
$display("BUS_RECV %0d: [%d] nibble %h", `PH_BUS_RECV, i_cycle_ctr, rom[i_alu_pc[`ROMBITS-1:0]]);
o_nibble <= rom[i_alu_pc[`ROMBITS-1:0]];
if (last_cmd == `BUSCMD_PC_READ) begin
$display("BUS_RECV %0d: [%d] <= READ %h", `PH_BUS_RECV, i_cycle_ctr, rom[local_pc[`ROMBITS-1:0]]);
o_nibble <= rom[local_pc[`ROMBITS-1:0]];
local_pc <= local_pc + 1;
end else
$display("BUS_RECV %0d: [%d] UNKNOWN COMMAND %h", `PH_BUS_RECV, i_cycle_ctr, last_cmd);
end
/*

View file

@ -86,6 +86,7 @@ saturn_decoder m_decoder (
.i_en_dbg (ck_debugger),
.i_en_dec (ck_inst_dec),
.i_pc (reg_pc),
.i_bus_load_pc (bus_load_pc),
.i_stalled (dec_stalled),
.i_nibble (bus_nibble_in),
@ -156,6 +157,7 @@ wire [0:0] ins_test_go;
saturn_alu m_alu (
.i_clk (clk),
.i_reset (reset),
.i_cycle_ctr (cycle_ctr),
.i_en_alu_dump (ck_alu_dump),
.i_en_alu_prep (ck_alu_prep),
.i_en_alu_calc (ck_alu_calc),
@ -166,6 +168,8 @@ saturn_alu m_alu (
.o_bus_address (bus_address),
.o_bus_load_pc (bus_load_pc),
.o_bus_load_dp (bus_load_dp),
.o_bus_read_pc (bus_read_pc),
.o_bus_write_dp (bus_write_dp),
.o_bus_nibble_out (bus_nibble_out),
.i_push (push),
@ -204,6 +208,8 @@ saturn_alu m_alu (
wire [19:0] bus_address;
wire [0:0] bus_load_pc;
wire [0:0] bus_load_dp;
wire [0:0] bus_read_pc;
wire [0:0] bus_write_dp;
wire [3:0] bus_nibble_in;
wire [3:0] bus_nibble_out;
@ -241,6 +247,8 @@ saturn_bus_ctrl m_bus_ctrl (
.i_address (bus_address),
.i_load_pc (bus_load_pc),
.i_load_dp (bus_load_dp),
.i_read_pc (bus_read_pc),
.i_write_dp (bus_write_dp),
.i_nibble (bus_nibble_out),
.o_nibble (bus_nibble_in)
);
@ -313,7 +321,6 @@ always @(posedge clk) begin
ck_alu_save <= clk_phase[1:0] == `PH_ALU_SAVE;
cycle_ctr <= cycle_ctr + { {31{1'b0}}, (clk_phase[1:0] == `PH_BUS_SEND) };
// stop after 50 clocks
if (cycle_ctr == (max_cycle + 1)) begin
$display(".-------------------.");
$display("| OUT OF CYCLES |");
@ -340,7 +347,7 @@ always @(posedge clk) begin
clock_end <= 0;
cycle_ctr <= ~0;
max_cycle <= 20;
max_cycle <= 155;
mem_ctrl_stall <= 0;
`ifndef SIM

View file

@ -8,7 +8,8 @@
`include "def-alu.v"
module saturn_decoder(
i_clk, i_reset, i_cycles, i_en_dbg, i_en_dec, i_stalled,
i_clk, i_reset, i_cycles, i_en_dbg, i_en_dec,
i_bus_load_pc, i_stalled,
i_pc, i_nibble,
i_reg_p,
@ -41,26 +42,27 @@ module saturn_decoder(
input wire [0:0] i_clk;
input wire [0:0] i_reset;
input wire [31:0] i_cycles;
input wire i_en_dbg;
input wire i_en_dec;
input wire i_stalled;
input wire [0:0] i_en_dbg;
input wire [0:0] i_en_dec;
input wire [0:0] i_bus_load_pc;
input wire [0:0] i_stalled;
input wire [19:0] i_pc;
input wire [3:0] i_nibble;
input wire [3:0] i_reg_p;
output reg o_inc_pc;
output reg o_push;
output reg o_pop;
output reg o_dec_error;
output reg [0:0] o_inc_pc;
output reg [0:0] o_push;
output reg [0:0] o_pop;
output reg [0:0] o_dec_error;
`ifdef SIM
output reg [0:0] o_unimplemented;
`endif
output reg o_alu_debug;
output reg [0:0] o_alu_debug;
// instructions related outputs
output reg [19:0] o_ins_addr;
output reg o_ins_decoded;
output reg [0:0] o_ins_decoded;
output reg [1:0] o_fields_table;
output reg [3:0] o_field;
@ -76,20 +78,20 @@ output reg [4:0] o_reg_src1;
output reg [4:0] o_reg_src2;
// rtn specific
output reg o_ins_rtn;
output reg o_set_xm;
output reg o_set_carry;
output reg o_test_carry;
output reg o_carry_val;
output reg o_en_intr;
output reg [0:0] o_ins_rtn;
output reg [0:0] o_set_xm;
output reg [0:0] o_set_carry;
output reg [0:0] o_test_carry;
output reg [0:0] o_carry_val;
output reg [0:0] o_en_intr;
// setdec/hex
output reg o_ins_set_mode;
output reg o_mode_dec;
output reg [0:0] o_ins_set_mode;
output reg [0:0] o_mode_dec;
// alu_operations
output reg o_ins_alu_op;
output reg o_ins_test_go;
output reg [0:0] o_ins_alu_op;
output reg [0:0] o_ins_test_go;
/* data used by the debugger
*
@ -434,6 +436,7 @@ always @(posedge i_clk) begin
block_13x <= 1;
4'h4, 4'h5: // DAT[01]=[AC] <field>
begin
o_alu_debug <= 0;
`ifdef SIM
$display("block_1x %h | use table <= %b", i_nibble, i_nibble[0]);
`endif

View file

@ -8,7 +8,7 @@ wire [19:0] new_pc;
assign new_pc = i_pc + 1;
wire run_debugger;
assign run_debugger = !i_reset && i_en_dbg && !i_stalled && !next_nibble;
assign run_debugger = !i_reset && i_en_dbg && !i_stalled && !i_bus_load_pc && !next_nibble;
wire is_short_transfer;
assign is_short_transfer = (o_field_last == 3) &&