Add basic project with cpu, ram and rom

This commit is contained in:
Byron Lathi
2024-03-02 22:46:48 -08:00
parent 0a0394ae33
commit 0752220b0e
15 changed files with 1019 additions and 0 deletions

View File

@@ -0,0 +1,257 @@
module super6502_fpga(
input logic i_sysclk, // Controller Clock (100MHz)
input logic i_sdrclk, // t_su and t_wd clock (200MHz)
input logic i_tACclk, // t_ac clock (200MHz)
input clk_cpu,
input button_reset,
input pll_cpu_locked,
output logic pll_cpu_reset,
input i_pll_locked,
output logic o_pll_reset,
input [7:0] i_cpu0_data_from_cpu,
input i_cpu0_sync,
input i_cpu0_rwb,
input logic [15:0] i_cpu0_addr,
output logic [7:0] o_cpu0_data_from_dut,
output logic [7:0] o_cpu0_data_oe,
output logic o_cpu0_irqb,
output logic o_cpu0_nmib,
output logic o_cpu0_rdy,
output logic o_cpu0_reset
);
localparam ADDR_WIDTH = 32;
localparam DATA_WIDTH = 32;
assign pll_cpu_reset = '1;
assign o_pll_reset = '1;
assign o_cpu0_nmib = '1;
assign o_clk_phi2 = clk_cpu;
assign o_cpu0_data_oe = {8{i_cpu0_rwb}};
logic master_reset;
assign master_reset = button_reset;
logic cpu0_AWVALID;
logic cpu0_AWREADY;
logic [ADDR_WIDTH-1:0] cpu0_AWADDR;
logic cpu0_WVALID;
logic cpu0_WREADY;
logic [DATA_WIDTH-1:0] cpu0_WDATA;
logic [DATA_WIDTH/8-1:0] cpu0_WSTRB;
logic cpu0_BVALID;
logic cpu0_BREADY;
logic [1:0] cpu0_BRESP;
logic cpu0_ARVALID;
logic cpu0_ARREADY;
logic [ADDR_WIDTH-1:0] cpu0_ARADDR;
logic cpu0_RVALID;
logic cpu0_RREADY;
logic [DATA_WIDTH-1:0] cpu0_RDATA;
logic [1:0] cpu0_RRESP;
logic ram_awvalid;
logic ram_awready;
logic [ADDR_WIDTH-1:0] ram_awaddr;
logic ram_wvalid;
logic ram_wready;
logic [DATA_WIDTH-1:0] ram_wdata;
logic [DATA_WIDTH/8-1:0] ram_wstrb;
logic ram_bvalid;
logic ram_bready;
logic [1:0] ram_bresp;
logic ram_arvalid;
logic ram_arready;
logic [ADDR_WIDTH-1:0] ram_araddr;
logic ram_rvalid;
logic ram_rready;
logic [DATA_WIDTH-1:0] ram_rdata;
logic [1:0] ram_rresp;
logic rom_awvalid;
logic rom_awready;
logic [ADDR_WIDTH-1:0] rom_awaddr;
logic rom_wvalid;
logic rom_wready;
logic [DATA_WIDTH-1:0] rom_wdata;
logic [DATA_WIDTH/8-1:0] rom_wstrb;
logic rom_bvalid;
logic rom_bready;
logic [1:0] rom_bresp;
logic rom_arvalid;
logic rom_arready;
logic [ADDR_WIDTH-1:0] rom_araddr;
logic rom_rvalid;
logic rom_rready;
logic [DATA_WIDTH-1:0] rom_rdata;
logic [1:0] rom_rresp;
cpu_wrapper u_cpu_wrapper_0(
.i_clk_cpu (clk_cpu),
.i_clk_100 (i_sysclk),
.i_rst (~master_reset),
.o_cpu_rst (o_cpu0_reset),
.o_cpu_rdy (o_cpu0_rdy),
.o_cpu_be (),
.o_cpu_irqb (o_cpu0_irqb),
.o_cpu_nmib (),
.o_cpu_sob (),
.i_cpu_rwb (i_cpu0_rwb),
.i_cpu_sync (i_cpu0_sync),
.i_cpu_vpb ('0),
.i_cpu_mlb ('0),
.i_cpu_addr (i_cpu0_addr),
.i_cpu_data (i_cpu0_data_from_cpu),
.o_cpu_data (o_cpu0_data_from_dut),
.o_AWVALID (cpu0_AWVALID),
.i_AWREADY (cpu0_AWREADY),
.o_AWADDR (cpu0_AWADDR),
.o_WVALID (cpu0_WVALID),
.i_WREADY (cpu0_WREADY),
.o_WDATA (cpu0_WDATA),
.o_WSTRB (cpu0_WSTRB),
.i_BVALID (cpu0_BVALID),
.o_BREADY (cpu0_BREADY),
.i_BRESP (cpu0_BRESP),
.o_ARVALID (cpu0_ARVALID),
.i_ARREADY (cpu0_ARREADY),
.o_ARADDR (cpu0_ARADDR),
.i_RVALID (cpu0_RVALID),
.o_RREADY (cpu0_RREADY),
.i_RDATA (cpu0_RDATA),
.i_RRESP (cpu0_RRESP),
.i_irq('0),
.i_nmi('0)
);
axi_crossbar #(
.N_INITIATORS(1),
.N_TARGETS(2)
) u_crossbar (
.clk(i_sysclk),
.rst(~master_reset),
.ini_araddr ({cpu0_ARADDR }),
.ini_arvalid ({cpu0_ARVALID }),
.ini_arready ({cpu0_ARREADY }),
.ini_rdata ({cpu0_RDATA }),
.ini_rresp ({cpu0_RRESP }),
.ini_rvalid ({cpu0_RVALID }),
.ini_rready ({cpu0_RREADY }),
.ini_awaddr ({cpu0_AWADDR }),
.ini_awready ({cpu0_AWREADY }),
.ini_awvalid ({cpu0_AWVALID }),
.ini_wvalid ({cpu0_WVALID }),
.ini_wready ({cpu0_WREADY }),
.ini_wdata ({cpu0_WDATA }),
.ini_wstrb ({cpu0_WSTRB }),
.ini_bresp ({cpu0_BRESP }),
.ini_bvalid ({cpu0_BVALID }),
.ini_bready ({cpu0_BREADY }),
.tgt_araddr ({ram_araddr, rom_araddr }),
.tgt_arvalid ({ram_arvalid, rom_arvalid }),
.tgt_arready ({ram_arready, rom_arready }),
.tgt_rdata ({ram_rdata, rom_rdata }),
.tgt_rresp ({ram_rresp, rom_rresp }),
.tgt_rvalid ({ram_rvalid, rom_rvalid }),
.tgt_rready ({ram_rready, rom_rready }),
.tgt_awaddr ({ram_awaddr, rom_awaddr }),
.tgt_awvalid ({ram_awvalid, rom_awvalid }),
.tgt_awready ({ram_awready, rom_awready }),
.tgt_wdata ({ram_wdata, rom_wdata }),
.tgt_wvalid ({ram_wvalid, rom_wvalid }),
.tgt_wready ({ram_wready, rom_wready }),
.tgt_wstrb ({ram_wstrb, rom_wstrb }),
.tgt_bresp ({ram_bresp, rom_bresp }),
.tgt_bvalid ({ram_bvalid, rom_bvalid }),
.tgt_bready ({ram_bready, rom_bready })
);
axi4_lite_rom #(
.ROM_SIZE(8),
.ROM_INIT_FILE("init_hex.mem")
) u_rom (
.i_clk(i_sysclk),
.i_rst(~master_reset),
.o_AWREADY(rom_awready),
.o_WREADY(rom_wready),
.o_BVALID(rom_bvalid),
.i_BREADY(rom_bready),
.o_BRESP(rom_bresp),
.i_ARVALID(rom_arvalid),
.o_ARREADY(rom_arready),
.i_ARADDR(rom_araddr),
.i_ARPROT('0),
.o_RVALID(rom_rvalid),
.i_RREADY(rom_rready),
.o_RDATA(rom_rdata),
.o_RRESP(rom_rresp),
.i_AWVALID(rom_awvalid),
.i_AWADDR(rom_awaddr),
.i_AWPROT('0),
.i_WVALID(rom_wvalid),
.i_WDATA(rom_wdata),
.i_WSTRB(rom_wstrb)
);
axi4_lite_ram #(
.RAM_SIZE(9)
) u_ram(
.i_clk(i_sysclk),
.i_rst(~master_reset),
.o_AWREADY(ram_awready),
.o_WREADY(ram_wready),
.o_BVALID(ram_bvalid),
.i_BREADY(ram_bready),
.o_BRESP(ram_bresp),
.i_ARVALID(ram_arvalid),
.o_ARREADY(ram_arready),
.i_ARADDR(ram_araddr),
.i_ARPROT('0),
.o_RVALID(ram_rvalid),
.i_RREADY(ram_rready),
.o_RDATA(ram_rdata),
.o_RRESP(ram_rresp),
.i_AWVALID(ram_awvalid),
.i_AWADDR(ram_awaddr),
.i_AWPROT('0),
.i_WVALID(ram_wvalid),
.i_WDATA(ram_wdata),
.i_WSTRB(ram_wstrb)
);
endmodule

View File

@@ -0,0 +1,391 @@
module cpu_wrapper #(
parameter ADDR_WIDTH = 32,
parameter DATA_WIDTH = 32
)(
/* Clocks and Reset */
input logic i_clk_cpu,
input logic i_clk_100,
input logic i_rst,
/* CPU Control Signals */
output logic o_cpu_rst,
output logic o_cpu_rdy,
output logic o_cpu_be,
output logic o_cpu_irqb,
output logic o_cpu_nmib,
output logic o_cpu_sob,
/* CPU Status Signals */
input logic i_cpu_rwb,
input logic i_cpu_sync,
input logic i_cpu_vpb,
input logic i_cpu_mlb,
/* CPU Address and Data */
input logic [15:0] i_cpu_addr,
input logic [7:0] i_cpu_data,
output logic [7:0] o_cpu_data,
/* AXI4-Lite signals */
output logic o_AWVALID,
input logic i_AWREADY,
output logic [ADDR_WIDTH-1:0] o_AWADDR,
output logic [2:0] o_AWPROT,
output logic o_WVALID,
input logic i_WREADY,
output logic [DATA_WIDTH-1:0] o_WDATA,
output logic [DATA_WIDTH/8-1:0] o_WSTRB,
input logic i_BVALID,
output logic o_BREADY,
input logic [1:0] i_BRESP,
output logic o_ARVALID,
input logic i_ARREADY,
output logic [ADDR_WIDTH-1:0] o_ARADDR,
output logic [2:0] o_ARPROT,
input logic i_RVALID,
output logic o_RREADY,
input logic [DATA_WIDTH-1:0] i_RDATA,
input logic [1:0] i_RRESP,
/* interrupt signals */
input logic i_irq,
input logic i_nmi
);
typedef enum logic [3:0] {
RESET,
IDLE,
ADDR_CONTROL,
READ_VALID,
READ_DATA,
WRITE_VALID,
GET_WRITE_DATA,
WRITE_DATA,
STALL
} state_t;
state_t state, state_next;
logic w_status_empty;
logic w_status_r_en;
logic r_rwb, r_sync, r_vpb, r_mlb;
logic r_rwb_next, r_sync_next, r_vpb_next, r_mlb_next;
logic [15:0] r_addr, r_addr_next;
logic w_write_data_en;
logic [7:0] r_write_data, r_write_data_next;
logic w_write_data_empty;
logic [2:0] counter;
logic w_reset;
always @(posedge i_clk_cpu) begin
if (i_rst) begin
counter <= '1;
end else if (counter) begin
counter <= counter - 3'd1;
end
end
assign w_reset = |counter;
ff_cdc #(
.RESET_VAL(0)
) u_cpu_rst_cdc (
.rst(i_rst),
.clk(i_clk_cpu),
.data_a(~w_reset),
.data_b(o_cpu_rst)
);
ff_cdc u_cpu_irq_cdc (
.rst(i_rst),
.clk(i_clk_cpu),
.data_a(~i_irq),
.data_b(o_cpu_irqb)
);
ff_cdc u_cpu_nmi_cdc (
.rst(i_rst),
.clk(i_clk_cpu),
.data_a(~i_nmi),
.data_b(o_cpu_nmib)
);
// This fifo says it has a bug with back to back writes, but maybe that
// is only for fast -> slow? this is slow -> fast.
// async_fifo #(
// .WIDTH(20),
// .A_SIZE(3)
// ) u_status_addr_fifo (
// .i_rst_a(o_cpu_rst),
// .i_clk_a(i_clk_cpu),
// .i_rst_b(i_rst),
// .i_clk_b(i_clk_100),
// .w_en('1), // investigate this
// .i_data({i_cpu_rwb, i_cpu_sync, i_cpu_vpb, i_cpu_mlb, i_cpu_addr}),
// .o_full(),
// .r_en(w_status_r_en),
// .o_data({r_rwb_next, r_sync_next, r_vpb_next, r_mlb_next, r_addr_next}),
// .o_empty(w_status_empty)
// );
logic [1:0] flag;
assign w_status_empty = ~flag[0];
assign r_rwb_next = i_cpu_rwb;
assign r_sync_next = i_cpu_sync;
assign r_vpb_next = i_cpu_vpb;
assign r_mlb_next = i_cpu_mlb;
assign r_addr_next = i_cpu_addr;
always @(posedge i_clk_100 or posedge i_rst) begin
if (i_rst) begin
flag <= '0;
end else begin
if (i_clk_cpu) begin
if (flag == '0) begin
flag <= 2'h1;
end else if (flag == 2'h1) begin
flag <= 2'h2;
end
end else begin
flag <= '0;
end
end
end
// // This uses inverted clock, remember in sdc?
// async_fifo #(
// .WIDTH(8),
// .A_SIZE(3)
// ) u_write_data_fifo (
// .i_rst_a(o_cpu_rst),
// .i_clk_a(~i_clk_cpu),
// .i_rst_b(i_rst),
// .i_clk_b(i_clk_100),
// .w_en('1),
// .i_data(i_cpu_data),
// .o_full(),
// .r_en(w_write_data_en),
// .o_data(r_write_data_next),
// .o_empty(w_write_data_empty)
// );
// Really bad double flop bus
always @(negedge i_clk_cpu) begin
r_write_data_next <= i_cpu_data;
end
logic [1:0] flag2;
assign w_write_data_empty = ~flag2[0];
always @(posedge i_clk_100 or posedge i_rst) begin
if (i_rst) begin
flag2 <= '0;
end else begin
if (~i_clk_cpu) begin
if (flag2 == '0) begin
flag2 <= 2'h1;
end else if (flag2 == 2'h1) begin
flag2 <= 2'h2;
end
end else begin
flag2 <= '0;
end
end
end
localparam MAX_DELAY = 4;
logic [7:0] cycle_counter;
logic too_late;
logic [2:0] rdy_dly;
logic potential_rdy;
logic did_delay, did_delay_next;
assign potential_rdy = |rdy_dly;
assign too_late = cycle_counter > MAX_DELAY ? 1 : 0;
always_ff @(posedge i_clk_100 or posedge i_rst) begin
if (i_rst) begin
cycle_counter <= '0;
rdy_dly <= '0;
end else begin
if (i_clk_cpu) begin
cycle_counter <= cycle_counter + 1;
end else begin
cycle_counter <= '0;
end
rdy_dly <= {rdy_dly[1:0], too_late};
end
end
logic [7:0] read_data, read_data_next;
assign o_cpu_data = read_data;
always_comb begin
state_next = state;
// Set defaults
o_AWVALID = '0;
o_AWADDR = '0;
o_AWPROT = '0;
o_WVALID = '0;
o_WDATA = '0;
o_WSTRB = '0;
o_BREADY = '0;
o_ARVALID = '0;
o_ARADDR = '0;
o_ARPROT = '0;
o_RREADY = '0;
o_cpu_rdy = '1;
read_data_next = read_data;
did_delay_next = did_delay;
case (state)
RESET: begin
// Is this a CDC violation?
if (i_cpu_addr == 16'hFFFC) begin
state_next = IDLE;
end
end
IDLE: begin
if (~w_status_empty) begin
state_next = ADDR_CONTROL;
end
did_delay_next = '0;
end
ADDR_CONTROL: begin
if (r_rwb) begin
state_next = READ_VALID;
end else begin
state_next = WRITE_VALID;
end
end
READ_VALID: begin
o_ARVALID = '1;
// $display("%x %x %x", o_ARVALID, i_ARREADY, o_ARVALID & i_ARREADY);
if (o_ARVALID & i_ARREADY) begin
// $display("AHHHHHH");
state_next = READ_DATA;
// $display("next state: %x", state_next);
end
o_ARADDR = {r_addr[15:2], 2'b0};
end
READ_DATA: begin
if (potential_rdy) begin
state_next = READ_DATA;
o_cpu_rdy = ~potential_rdy;
did_delay_next = '1;
end
if (i_RVALID) begin
if (did_delay || potential_rdy) begin
state_next = STALL;
end else begin
state_next = IDLE;
end
read_data_next = i_RDATA[8*r_addr[1:0] +: 8];
end
o_RREADY = '1;
end
WRITE_VALID: begin
if (~w_write_data_empty) begin
state_next = WRITE_DATA;
end
end
GET_WRITE_DATA: begin
$error("GET_WRITE_DATA not implemented");
state_next = IDLE;
end
WRITE_DATA: begin
o_AWVALID = '1;
o_AWADDR = {r_addr[15:2], 2'b0};
o_WVALID = '1;
o_WSTRB = 4'b1 << r_addr[1:0];
o_WDATA = r_write_data << 8*r_addr[1:0];
o_BREADY = '1;
if (i_BVALID) begin
state_next = IDLE;
end
end
STALL: begin
// kind of dumb
if (cycle_counter == 1) begin
state_next = IDLE;
end
o_cpu_rdy = ~potential_rdy;
end
default: begin
// $error("Invalid state");
state_next = IDLE;
end
endcase
end
always_ff @(posedge i_clk_100 or posedge i_rst) begin
if (i_rst) begin
r_rwb <= '1; // start as 1 to indicate read.
r_sync <= '0;
r_vpb <= '0;
r_mlb <= '0;
r_addr <= '0;
read_data <= '0;
r_write_data <= '0;
did_delay <= '0;
state <= RESET;
end else begin
if (~w_status_empty) begin
w_status_r_en <= '1;
r_rwb <= r_rwb_next;
r_sync <= r_sync_next;
r_vpb <= r_vpb_next;
r_mlb <= r_mlb_next;
r_addr <= r_addr_next;
end else begin
w_status_r_en <= '0;
end
read_data <= read_data_next;
state <= state_next;
did_delay <= did_delay_next;
r_write_data <= r_write_data_next;
end
end
endmodule