SummerCart64/fw/rtl/n64/n64_cic.sv
2024-05-03 17:51:20 +02:00

246 lines
6.0 KiB
Systemverilog

module n64_cic (
input clk,
input reset,
n64_scb.cic n64_scb,
input n64_reset,
input n64_cic_clk,
inout n64_cic_dq,
input n64_si_clk
);
// Input/output synchronization
logic [1:0] n64_reset_ff;
logic [1:0] n64_cic_clk_ff;
logic [1:0] n64_cic_dq_ff;
logic [1:0] n64_si_clk_ff;
always_ff @(posedge clk) begin
n64_reset_ff <= {n64_reset_ff[0], n64_reset};
n64_cic_clk_ff <= {n64_cic_clk_ff[0], n64_cic_clk};
n64_cic_dq_ff <= {n64_cic_dq_ff[0], n64_cic_dq};
n64_si_clk_ff <= {n64_si_clk_ff[0], n64_si_clk};
end
logic cic_reset;
logic cic_clk;
logic cic_dq;
logic si_clk;
always_comb begin
cic_reset = n64_reset_ff[1];
cic_clk = n64_cic_clk_ff[1];
cic_dq = n64_cic_dq_ff[1];
si_clk = n64_si_clk_ff[1];
end
logic cic_dq_out;
logic cic_dq_oe;
always_ff @(posedge clk) begin
cic_dq_oe <= ~cic_dq_out;
end
assign n64_cic_dq = cic_dq_oe ? 1'b0 : 1'bZ;
// Timer (divider and counter)
logic last_si_clk;
always_ff @(posedge clk) begin
last_si_clk <= si_clk;
end
logic si_clk_rising_edge;
always_comb begin
si_clk_rising_edge = cic_reset && !last_si_clk && si_clk;
end
logic [7:0] timer_divider;
logic [11:0] timer_counter;
logic timer_start;
logic timer_clear;
logic timer_elapsed;
const bit [11:0] TIMEOUT_500MS = 12'd3815; // (62_500_000 / 32 / 256 / 2) = ~500 ms
always_ff @(posedge clk) begin
if (si_clk_rising_edge) begin
timer_divider <= timer_divider + 1'd1;
end
if (si_clk_rising_edge && (&timer_divider) && (timer_counter > 12'd0)) begin
timer_counter <= timer_counter - 1'd1;
if (timer_counter == 12'd1) begin
timer_elapsed <= 1'b1;
end
end
if (timer_start) begin
timer_divider <= 8'd0;
timer_counter <= TIMEOUT_500MS;
timer_elapsed <= 1'b0;
end
if (timer_clear) begin
timer_divider <= 8'd0;
timer_counter <= 12'd0;
timer_elapsed <= 1'b0;
end
end
// SERV RISC-V CPU
logic [31:0] ibus_addr;
logic ibus_cycle;
logic [31:0] ibus_rdata;
logic ibus_ack;
logic [31:0] dbus_addr;
logic [31:0] dbus_wdata;
logic [3:0] dbus_wmask;
logic dbus_write;
logic dbus_cycle;
logic [31:0] dbus_rdata;
logic dbus_ack;
logic [31:0] ext_rs1;
logic [31:0] ext_rs2;
logic [2:0] ext_funct3;
logic mdu_valid;
serv_rf_top #(
.RESET_PC(32'h8000_0000),
.PRE_REGISTER(0),
.WITH_CSR(0)
) serv_rf_top_inst (
.clk(clk),
.i_rst(reset),
.i_timer_irq(1'b0),
.o_ibus_adr(ibus_addr),
.o_ibus_cyc(ibus_cycle),
.i_ibus_rdt(ibus_rdata),
.i_ibus_ack(ibus_ack),
.o_dbus_adr(dbus_addr),
.o_dbus_dat(dbus_wdata),
.o_dbus_sel(dbus_wmask),
.o_dbus_we(dbus_write) ,
.o_dbus_cyc(dbus_cycle),
.i_dbus_rdt(dbus_rdata),
.i_dbus_ack(dbus_ack),
.o_ext_rs1(ext_rs1),
.o_ext_rs2(ext_rs2),
.o_ext_funct3(ext_funct3),
.i_ext_rd(32'd0),
.i_ext_ready(1'b0),
.o_mdu_valid(mdu_valid)
);
// CPU memory
logic [8:0] ram_addr;
logic [31:0] ram [0:511];
logic [31:0] ram_output;
assign ram_addr = ibus_cycle ? ibus_addr[10:2] : dbus_addr[10:2];
assign ibus_rdata = ram_output;
always_ff @(posedge clk) begin
ram_output <= ram[ram_addr];
ibus_ack <= ibus_cycle && !ibus_ack;
end
initial begin
$readmemh("../../../sw/cic/build/cic.mem", ram);
end
// Bus controller
always_ff @(posedge clk) begin
timer_start <= 1'b0;
timer_clear <= 1'b0;
n64_scb.cic_invalid_region <= 1'b0;
dbus_ack <= dbus_cycle && !dbus_ack;
if (dbus_cycle && dbus_write) begin
case (dbus_addr[31:30])
2'b10: begin
if (dbus_wmask[0]) ram[ram_addr][7:0] <= dbus_wdata[7:0];
if (dbus_wmask[1]) ram[ram_addr][15:8] <= dbus_wdata[15:8];
if (dbus_wmask[2]) ram[ram_addr][23:16] <= dbus_wdata[23:16];
if (dbus_wmask[3]) ram[ram_addr][31:24] <= dbus_wdata[31:24];
end
2'b11: begin
case (dbus_addr[3:2])
2'b10: begin
n64_scb.cic_invalid_region <= dbus_wdata[6];
timer_clear <= dbus_wdata[5];
timer_start <= dbus_wdata[4];
cic_dq_out <= dbus_wdata[0];
end
2'b11: begin
n64_scb.cic_debug <= dbus_wdata[3:0];
end
endcase
end
endcase
end
if (reset) begin
n64_scb.cic_debug <= 3'd0;
end
if (reset || !cic_reset) begin
cic_dq_out <= 1'b1;
end
end
always_comb begin
dbus_rdata = 32'd0;
case (dbus_addr[31:30])
2'b10: begin
dbus_rdata = ram_output;
end
2'b11: begin
case (dbus_addr[3:2])
2'b00: dbus_rdata = {
n64_scb.cic_disabled,
n64_scb.cic_64dd_mode,
n64_scb.cic_region,
n64_scb.cic_seed,
n64_scb.cic_checksum[47:32]
};
2'b01: dbus_rdata = n64_scb.cic_checksum[31:0];
2'b10: dbus_rdata = {
28'd0,
timer_elapsed,
cic_reset,
cic_clk,
cic_dq
};
2'b11: dbus_rdata = {28'd0, n64_scb.cic_debug};
endcase
end
endcase
end
endmodule