module bridge_rtl (
input wire hclk,
input wire hresetn,
input wire hselapb,
input wire hwrite,
input wire [1:0] htrans,
input wire [31:0] haddr,
input wire [31:0] hwdata,
input wire [31:0] prdata,
input wire pready, // APB ready
input wire pslverr, // APB error
output reg [31:0] paddr,
output reg [31:0] pwdata,
output reg psel,
output reg penable,
output reg pwrite,
output reg hresp,
output reg hready,
output reg [31:0] hrdata
);
// State encoding
parameter IDLE = 3'b000;
parameter READ = 3'b001;
parameter RENABLE = 3'b010;
parameter WWAIT = 3'b011;
parameter WRITE = 3'b100;
parameter WENABLE = 3'b101;
reg [2:0] present_state, next_state;
reg [31:0] haddr_temp, hwdata_temp;
reg hwrite_temp;
reg valid;
// Valid AHB transfer detect
always @(*) begin
if (hselapb && (htrans == 2'b10 || htrans == 2'b11)) // NONSEQ or SEQ
valid = 1'b1;
else
valid = 1'b0;
end
// Sequential state update
always @(posedge hclk or negedge hresetn) begin
if (!hresetn)
present_state <= IDLE;
else
present_state <= next_state;
end
// FSM outputs and next state logic
always @(*) begin
// defaults
psel = 1'b0;
penable = 1'b0;
pwrite = 1'b0;
paddr = 32'b0;
pwdata = 32'b0;
hready = 1'b1;
hresp = 1'b0;
hrdata = 32'b0;
next_state = present_state;
case (present_state)
// -----------------------------------
IDLE: begin
if (valid && !hwrite) next_state = READ;
else if (valid && hwrite) next_state = WWAIT;
else next_state = IDLE;
end
// -----------------------------------
READ: begin
psel = 1'b1;
paddr = haddr;
pwrite = 1'b0;
penable = 1'b0;
hready = 1'b0;
next_state = RENABLE;
end
RENABLE: begin
psel = 1'b1;
penable = 1'b1;
pwrite = 1'b0;
paddr = haddr;
hrdata = prdata;
if (pready) begin
hready = 1'b1;
hresp = pslverr;
if (valid && !hwrite) next_state = READ;
else if (valid && hwrite) next_state = WWAIT;
else next_state = IDLE;
end else begin
hready = 1'b0;
next_state = RENABLE;
end
end
// -----------------------------------
WWAIT: begin
haddr_temp = haddr;
hwdata_temp = hwdata;
hwrite_temp = hwrite;
hready = 1'b0;
next_state = WRITE;
end
WRITE: begin
psel = 1'b1;
paddr = haddr_temp;
pwdata = hwdata_temp;
pwrite = 1'b1;
penable = 1'b0;
hready = 1'b0;
next_state = WENABLE;
end
WENABLE: begin
psel = 1'b1;
penable = 1'b1;
pwrite = 1'b1;
paddr = haddr_temp;
pwdata = hwdata_temp;
if (pready) begin
hready = 1'b1;
hresp = pslverr;
if (valid && !hwrite) next_state = READ;
else if (valid && hwrite) next_state = WWAIT;
else next_state = IDLE;
end else begin
hready = 1'b0;
next_state = WENABLE;
end
end
endcase
end
endmodule
module tb_bridge_rtl;
reg hclk;
reg hresetn;
reg hselapb;
reg hwrite;
reg [1:0] htrans;
reg [31:0] haddr;
reg [31:0] hwdata;
wire [31:0] hrdata;
wire hready;
wire hresp;
// APB side signals
wire [31:0] paddr, pwdata;
wire psel, penable, pwrite;
reg [31:0] prdata;
reg pready;
reg pslverr;
// DUT instantiation
bridge_rtl dut (
.hclk(hclk),
.hresetn(hresetn),
.hselapb(hselapb),
.hwrite(hwrite),
.htrans(htrans),
.haddr(haddr),
.hwdata(hwdata),
.prdata(prdata),
.pready(pready),
.pslverr(pslverr),
.paddr(paddr),
.pwdata(pwdata),
.psel(psel),
.penable(penable),
.pwrite(pwrite),
.hresp(hresp),
.hready(hready),
.hrdata(hrdata)
);
// Clock gen
initial begin
hclk = 0;
forever #5 hclk = ~hclk; // 100 MHz clock
end
// Simple APB slave: just one register
reg [31:0] apb_reg;
always @(posedge hclk) begin
if (psel && penable && pwrite && pready) begin
apb_reg <= pwdata; // Write to register
end
end
always @(*) begin
if (psel && !pwrite) begin
prdata = apb_reg; // Read back register
end else begin
prdata = 32'hDEAD_BEEF; // Default
end
end
// Stimulus
initial begin
// Init
hresetn = 0;
hselapb =0;
hwrite = 0;
htrans = 2'b00;
haddr = 32'b0;
hwdata = 32'b0;
pready = 1;
pslverr = 0;
apb_reg = 32'h12345678;
// Apply reset
#20 hresetn = 1;
// -------------------------------
// AHB WRITE transaction
// -------------------------------
@(posedge hclk);
hselapb = 1;
htrans = 2'b10; // NONSEQ
hwrite = 1;
haddr = 32'h0000_0004;
hwdata = 32'hA5A5_F00D;
@(posedge hclk);
hselapb = 0; // deassert after single beat
htrans = 2'b00;
// Wait for APB completion
repeat(4) @(posedge hclk);
// -------------------------------
// AHB READ transaction
// -------------------------------
@(posedge hclk);
hselapb = 1;
htrans = 2'b10; // NONSEQ
hwrite = 0;
haddr = 32'h0000_0004;
@(posedge hclk);
hselapb = 0;
htrans = 2'b00;
// Wait for read data
repeat(4) @(posedge hclk);
// -------------------------------
// End sim
// -------------------------------
$display("APB register value = %h", apb_reg);
$display("Read data from HRDATA = %h", hrdata);
$finish;
end
endmodule