Files
fpga6502/src/regs/verilog6502_io_regs.sv
2026-04-18 16:18:57 -07:00

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