mirror of
https://github.com/Polprzewodnikowy/SummerCart64.git
synced 2024-11-25 15:16:53 +01:00
246 lines
6.0 KiB
Systemverilog
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
|