302 lines
11 KiB
Systemverilog
302 lines
11 KiB
Systemverilog
// Generated by PeakRDL-regblock - A free and open-source SystemVerilog generator
|
|
// https://github.com/SystemRDL/PeakRDL-regblock
|
|
|
|
module verilog6502_io_regs (
|
|
input wire clk,
|
|
input wire rst,
|
|
|
|
taxi_apb_if.slv s_apb,
|
|
|
|
output verilog6502_io_regs_pkg::verilog6502_io_regs__out_t hwif_out
|
|
);
|
|
|
|
//--------------------------------------------------------------------------
|
|
// CPU Bus interface logic
|
|
//--------------------------------------------------------------------------
|
|
logic cpuif_req;
|
|
logic cpuif_req_is_wr;
|
|
logic [11:0] cpuif_addr;
|
|
logic [31:0] cpuif_wr_data;
|
|
logic [31:0] cpuif_wr_biten;
|
|
logic cpuif_req_stall_wr;
|
|
logic cpuif_req_stall_rd;
|
|
|
|
logic cpuif_rd_ack;
|
|
logic cpuif_rd_err;
|
|
logic [31:0] cpuif_rd_data;
|
|
|
|
logic cpuif_wr_ack;
|
|
logic cpuif_wr_err;
|
|
|
|
`ifndef SYNTHESIS
|
|
initial begin
|
|
assert_bad_addr_width: assert($bits(s_apb.paddr) >= verilog6502_io_regs_pkg::VERILOG6502_IO_REGS_MIN_ADDR_WIDTH)
|
|
else $error("Interface address width of %0d is too small. Shall be at least %0d bits", $bits(s_apb.paddr), verilog6502_io_regs_pkg::VERILOG6502_IO_REGS_MIN_ADDR_WIDTH);
|
|
assert_bad_data_width: assert($bits(s_apb.pwdata) == verilog6502_io_regs_pkg::VERILOG6502_IO_REGS_DATA_WIDTH)
|
|
else $error("Interface data width of %0d is incorrect. Shall be %0d bits", $bits(s_apb.pwdata), verilog6502_io_regs_pkg::VERILOG6502_IO_REGS_DATA_WIDTH);
|
|
end
|
|
`endif
|
|
|
|
// Request
|
|
logic is_active;
|
|
always_ff @(posedge clk) begin
|
|
if(rst) begin
|
|
is_active <= '0;
|
|
cpuif_req <= '0;
|
|
cpuif_req_is_wr <= '0;
|
|
cpuif_addr <= '0;
|
|
cpuif_wr_data <= '0;
|
|
cpuif_wr_biten <= '0;
|
|
end else begin
|
|
if(~is_active) begin
|
|
if(s_apb.psel) begin
|
|
is_active <= '1;
|
|
cpuif_req <= '1;
|
|
cpuif_req_is_wr <= s_apb.pwrite;
|
|
cpuif_addr <= {s_apb.paddr[11:2], 2'b0};
|
|
cpuif_wr_data <= s_apb.pwdata;
|
|
for(int i=0; i<4; i++) begin
|
|
cpuif_wr_biten[i*8 +: 8] <= {8{s_apb.pstrb[i]}};
|
|
end
|
|
end
|
|
end else begin
|
|
cpuif_req <= '0;
|
|
if(cpuif_rd_ack || cpuif_wr_ack) begin
|
|
is_active <= '0;
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
// Response
|
|
assign s_apb.pready = cpuif_rd_ack | cpuif_wr_ack;
|
|
assign s_apb.prdata = cpuif_rd_data;
|
|
assign s_apb.pslverr = cpuif_rd_err | cpuif_wr_err;
|
|
|
|
logic cpuif_req_masked;
|
|
|
|
// Read & write latencies are balanced. Stalls not required
|
|
assign cpuif_req_stall_rd = '0;
|
|
assign cpuif_req_stall_wr = '0;
|
|
assign cpuif_req_masked = cpuif_req
|
|
& !(!cpuif_req_is_wr & cpuif_req_stall_rd)
|
|
& !(cpuif_req_is_wr & cpuif_req_stall_wr);
|
|
|
|
//--------------------------------------------------------------------------
|
|
// Address Decode
|
|
//--------------------------------------------------------------------------
|
|
typedef struct {
|
|
logic core_ctrl;
|
|
logic nmi;
|
|
logic reset_brq;
|
|
} decoded_reg_strb_t;
|
|
decoded_reg_strb_t decoded_reg_strb;
|
|
logic decoded_err;
|
|
logic [11:0] decoded_addr;
|
|
logic decoded_req;
|
|
logic decoded_req_is_wr;
|
|
logic [31:0] decoded_wr_data;
|
|
logic [31:0] decoded_wr_biten;
|
|
|
|
always_comb begin
|
|
automatic logic is_valid_addr;
|
|
automatic logic is_valid_rw;
|
|
is_valid_addr = '1; // No valid address check
|
|
is_valid_rw = '1; // No valid RW check
|
|
decoded_reg_strb.core_ctrl = cpuif_req_masked & (cpuif_addr == 12'h0);
|
|
decoded_reg_strb.nmi = cpuif_req_masked & (cpuif_addr == 12'hff8);
|
|
decoded_reg_strb.reset_brq = cpuif_req_masked & (cpuif_addr == 12'hffc);
|
|
decoded_err = '0;
|
|
end
|
|
|
|
// Pass down signals to next stage
|
|
assign decoded_addr = cpuif_addr;
|
|
assign decoded_req = cpuif_req_masked;
|
|
assign decoded_req_is_wr = cpuif_req_is_wr;
|
|
assign decoded_wr_data = cpuif_wr_data;
|
|
assign decoded_wr_biten = cpuif_wr_biten;
|
|
|
|
//--------------------------------------------------------------------------
|
|
// Field logic
|
|
//--------------------------------------------------------------------------
|
|
typedef struct {
|
|
struct {
|
|
struct {
|
|
logic next;
|
|
logic load_next;
|
|
} reset;
|
|
} core_ctrl;
|
|
struct {
|
|
struct {
|
|
logic [15:0] next;
|
|
logic load_next;
|
|
} nmi;
|
|
} nmi;
|
|
struct {
|
|
struct {
|
|
logic [15:0] next;
|
|
logic load_next;
|
|
} reset;
|
|
struct {
|
|
logic [15:0] next;
|
|
logic load_next;
|
|
} brk;
|
|
} reset_brq;
|
|
} field_combo_t;
|
|
field_combo_t field_combo;
|
|
|
|
typedef struct {
|
|
struct {
|
|
struct {
|
|
logic value;
|
|
} reset;
|
|
} core_ctrl;
|
|
struct {
|
|
struct {
|
|
logic [15:0] value;
|
|
} nmi;
|
|
} nmi;
|
|
struct {
|
|
struct {
|
|
logic [15:0] value;
|
|
} reset;
|
|
struct {
|
|
logic [15:0] value;
|
|
} brk;
|
|
} reset_brq;
|
|
} field_storage_t;
|
|
field_storage_t field_storage;
|
|
|
|
// Field: verilog6502_io_regs.core_ctrl.reset
|
|
always_comb begin
|
|
automatic logic [0:0] next_c;
|
|
automatic logic load_next_c;
|
|
next_c = field_storage.core_ctrl.reset.value;
|
|
load_next_c = '0;
|
|
if(decoded_reg_strb.core_ctrl && decoded_req_is_wr) begin // SW write
|
|
next_c = (field_storage.core_ctrl.reset.value & ~decoded_wr_biten[0:0]) | (decoded_wr_data[0:0] & decoded_wr_biten[0:0]);
|
|
load_next_c = '1;
|
|
end
|
|
field_combo.core_ctrl.reset.next = next_c;
|
|
field_combo.core_ctrl.reset.load_next = load_next_c;
|
|
end
|
|
always_ff @(posedge clk) begin
|
|
if(rst) begin
|
|
field_storage.core_ctrl.reset.value <= 1'h1;
|
|
end else begin
|
|
if(field_combo.core_ctrl.reset.load_next) begin
|
|
field_storage.core_ctrl.reset.value <= field_combo.core_ctrl.reset.next;
|
|
end
|
|
end
|
|
end
|
|
assign hwif_out.core_ctrl.reset.value = field_storage.core_ctrl.reset.value;
|
|
// Field: verilog6502_io_regs.nmi.nmi
|
|
always_comb begin
|
|
automatic logic [15:0] next_c;
|
|
automatic logic load_next_c;
|
|
next_c = field_storage.nmi.nmi.value;
|
|
load_next_c = '0;
|
|
if(decoded_reg_strb.nmi && decoded_req_is_wr) begin // SW write
|
|
next_c = (field_storage.nmi.nmi.value & ~decoded_wr_biten[31:16]) | (decoded_wr_data[31:16] & decoded_wr_biten[31:16]);
|
|
load_next_c = '1;
|
|
end
|
|
field_combo.nmi.nmi.next = next_c;
|
|
field_combo.nmi.nmi.load_next = load_next_c;
|
|
end
|
|
always_ff @(posedge clk) begin
|
|
if(rst) begin
|
|
field_storage.nmi.nmi.value <= 16'h200;
|
|
end else begin
|
|
if(field_combo.nmi.nmi.load_next) begin
|
|
field_storage.nmi.nmi.value <= field_combo.nmi.nmi.next;
|
|
end
|
|
end
|
|
end
|
|
assign hwif_out.nmi.nmi.value = field_storage.nmi.nmi.value;
|
|
// Field: verilog6502_io_regs.reset_brq.reset
|
|
always_comb begin
|
|
automatic logic [15:0] next_c;
|
|
automatic logic load_next_c;
|
|
next_c = field_storage.reset_brq.reset.value;
|
|
load_next_c = '0;
|
|
if(decoded_reg_strb.reset_brq && decoded_req_is_wr) begin // SW write
|
|
next_c = (field_storage.reset_brq.reset.value & ~decoded_wr_biten[15:0]) | (decoded_wr_data[15:0] & decoded_wr_biten[15:0]);
|
|
load_next_c = '1;
|
|
end
|
|
field_combo.reset_brq.reset.next = next_c;
|
|
field_combo.reset_brq.reset.load_next = load_next_c;
|
|
end
|
|
always_ff @(posedge clk) begin
|
|
if(rst) begin
|
|
field_storage.reset_brq.reset.value <= 16'h200;
|
|
end else begin
|
|
if(field_combo.reset_brq.reset.load_next) begin
|
|
field_storage.reset_brq.reset.value <= field_combo.reset_brq.reset.next;
|
|
end
|
|
end
|
|
end
|
|
assign hwif_out.reset_brq.reset.value = field_storage.reset_brq.reset.value;
|
|
// Field: verilog6502_io_regs.reset_brq.brk
|
|
always_comb begin
|
|
automatic logic [15:0] next_c;
|
|
automatic logic load_next_c;
|
|
next_c = field_storage.reset_brq.brk.value;
|
|
load_next_c = '0;
|
|
if(decoded_reg_strb.reset_brq && decoded_req_is_wr) begin // SW write
|
|
next_c = (field_storage.reset_brq.brk.value & ~decoded_wr_biten[31:16]) | (decoded_wr_data[31:16] & decoded_wr_biten[31:16]);
|
|
load_next_c = '1;
|
|
end
|
|
field_combo.reset_brq.brk.next = next_c;
|
|
field_combo.reset_brq.brk.load_next = load_next_c;
|
|
end
|
|
always_ff @(posedge clk) begin
|
|
if(rst) begin
|
|
field_storage.reset_brq.brk.value <= 16'h200;
|
|
end else begin
|
|
if(field_combo.reset_brq.brk.load_next) begin
|
|
field_storage.reset_brq.brk.value <= field_combo.reset_brq.brk.next;
|
|
end
|
|
end
|
|
end
|
|
assign hwif_out.reset_brq.brk.value = field_storage.reset_brq.brk.value;
|
|
|
|
//--------------------------------------------------------------------------
|
|
// Write response
|
|
//--------------------------------------------------------------------------
|
|
assign cpuif_wr_ack = decoded_req & decoded_req_is_wr;
|
|
// Writes are always granted with no error response
|
|
assign cpuif_wr_err = '0;
|
|
|
|
//--------------------------------------------------------------------------
|
|
// Readback
|
|
//--------------------------------------------------------------------------
|
|
|
|
logic [11:0] rd_mux_addr;
|
|
assign rd_mux_addr = decoded_addr;
|
|
|
|
logic readback_err;
|
|
logic readback_done;
|
|
logic [31:0] readback_data;
|
|
always_comb begin
|
|
automatic logic [31:0] readback_data_var;
|
|
readback_data_var = '0;
|
|
if(rd_mux_addr == 12'h0) begin
|
|
readback_data_var[0] = field_storage.core_ctrl.reset.value;
|
|
end
|
|
if(rd_mux_addr == 12'hff8) begin
|
|
readback_data_var[31:16] = field_storage.nmi.nmi.value;
|
|
end
|
|
if(rd_mux_addr == 12'hffc) begin
|
|
readback_data_var[15:0] = field_storage.reset_brq.reset.value;
|
|
readback_data_var[31:16] = field_storage.reset_brq.brk.value;
|
|
end
|
|
readback_data = readback_data_var;
|
|
readback_done = decoded_req & ~decoded_req_is_wr;
|
|
readback_err = '0;
|
|
end
|
|
|
|
assign cpuif_rd_ack = readback_done;
|
|
assign cpuif_rd_data = readback_data;
|
|
assign cpuif_rd_err = readback_err;
|
|
endmodule
|