我认识的AHB2APB桥

一、代码

AHB总线代码见我认识的AHB - Holybanban - 博客园

1.1 AHB2APB桥的接口

module ahb2apb1 #(
    parameter ADDR_WIDTH    = 32    ,
    parameter DATA_WIDTH    = 32    
)(
//system
    input  wire                     PCLK        ,
    input  wire                     PRESETn     ,
//apb slave
    output wire [ADDR_WIDTH-1:0]    PADDR       ,
    output wire                     PSEL1       ,
    output wire                     PSEL2       ,
    output wire                     PENABLE     ,
    output wire                     PWRITE      ,
    output wire [DATA_WIDTH-1:0]    PWDATA      ,
    input  wire                     PREADYIN1   ,
    input  wire                     PREADYIN2   ,
    input  wire [DATA_WIDTH-1:0]    PRDATAIN1   ,
    input  wire [DATA_WIDTH-1:0]    PRDATAIN2   ,
//ahb master
    input  wire                     HSELx       ,
    input  wire [ADDR_WIDTH-1:0]    HADDR       ,
    input  wire [1:0]               HTRANS      ,
    input  wire                     HWRITE      ,
    input  wire [2:0]               HSIZE       ,
    input  wire [2:0]               HBURST      ,
    input  wire [DATA_WIDTH-1:0]    HWDATA      ,
    output wire [DATA_WIDTH-1:0]    PRDATAOUT   ,
    output wire                     PREADYOUT   
`ifdef RARELY_USED_SIGNAL
    output wire [2:0]               PPROT       ,
    output wire                     PNSE        ,
    output wire [DATA_WIDTH/8-1:0]  PSTRB       ,
    output wire                     PWAKEUP     ,
    output wire [31:0]              PAUSER      ,
    output wire [DATA_WIDTH/2-1:0]  PWUSER      ,
    input  wire                     PSLVERR     ,
    input  wire [DATA_WIDTH/2-1:0]  PRUSER      ,
    input  wire [31:0]              PBUSER
`endif
);

1.2 AHB2APB1

目前只能适配AHB的Single读写传输,后续会加入AHB2APB2,作为AHB总线的第二个桥从机。

`timescale 1ns/1ps
/*
 * Address Space
 * subordinate1 0x0000_0000~0x0000_ffff
 * subordinate2 0x0001_0000~0x0001_ffff
 */
module ahb2apb1 #(
    parameter ADDR_WIDTH    = 32    ,
    parameter DATA_WIDTH    = 32    
)(
//system
    input  wire                     PCLK        ,
    input  wire                     PRESETn     ,
//apb slave
    output wire [ADDR_WIDTH-1:0]    PADDR       ,
    output wire                     PSEL1       ,
    output wire                     PSEL2       ,
    output wire                     PENABLE     ,
    output wire                     PWRITE      ,
    output wire [DATA_WIDTH-1:0]    PWDATA      ,
    input  wire                     PREADYIN1   ,
    input  wire                     PREADYIN2   ,
    input  wire [DATA_WIDTH-1:0]    PRDATAIN1   ,
    input  wire [DATA_WIDTH-1:0]    PRDATAIN2   ,
//ahb master
    input  wire                     HSELx       ,
    input  wire [ADDR_WIDTH-1:0]    HADDR       ,
    input  wire [1:0]               HTRANS      ,
    input  wire                     HWRITE      ,
    input  wire [2:0]               HSIZE       ,
    input  wire [2:0]               HBURST      ,
    input  wire [DATA_WIDTH-1:0]    HWDATA      ,
    output wire [DATA_WIDTH-1:0]    PRDATAOUT   ,
    output wire                     PREADYOUT   
`ifdef RARELY_USED_SIGNAL
    output wire [2:0]               PPROT       ,
    output wire                     PNSE        ,
    output wire [DATA_WIDTH/8-1:0]  PSTRB       ,
    output wire                     PWAKEUP     ,
    output wire [31:0]              PAUSER      ,
    output wire [DATA_WIDTH/2-1:0]  PWUSER      ,
    input  wire                     PSLVERR     ,
    input  wire [DATA_WIDTH/2-1:0]  PRUSER      ,
    input  wire [31:0]              PBUSER
`endif
);
localparam IDLE   = 2'b00;
localparam SETUP  = 2'b01;
localparam ACCESS = 2'b10;

localparam BUSY   = 2'b01;
localparam NONSEQ = 2'b10;
localparam SEQ    = 2'b11;
/*********************************************************/
reg [ADDR_WIDTH-1:0] haddr_d;
reg                  hwrite_d;

always @(posedge PCLK or negedge PRESETn) if(!PRESETn) #1 haddr_d  <= 32'd0; else #1 haddr_d  <= HADDR;
always @(posedge PCLK or negedge PRESETn) if(!PRESETn) #1 hwrite_d <=  1'b0; else #1 hwrite_d <= HWRITE;

reg [ADDR_WIDTH-1:0] paddr_d;
reg                  pwrite_d;
reg [DATA_WIDTH-1:0] pwdata_d;

always @(posedge PCLK or negedge PRESETn) if(!PRESETn) #1 paddr_d  <= 32'd0; else #1 paddr_d  <= PADDR;
always @(posedge PCLK or negedge PRESETn) if(!PRESETn) #1 pwrite_d <=  1'b0; else #1 pwrite_d <= PWRITE;
always @(posedge PCLK or negedge PRESETn) if(!PRESETn) #1 pwdata_d <= 32'd0; else #1 pwdata_d <= PWDATA;
/*********************************************************/
reg [1:0] state;
reg [1:0] nextstate;

always @(*) begin
    case(state)
        IDLE:   if(HTRANS == NONSEQ && PREADYOUT && HSELx) nextstate = SETUP;
                else                                       nextstate = IDLE;
        SETUP:                                             nextstate = ACCESS;
        ACCESS: if(HTRANS == IDLE && PREADYOUT)            nextstate = IDLE;
                else                                       nextstate = ACCESS;
        default:                                           nextstate = IDLE;
    endcase
end

always @(posedge PCLK or negedge PRESETn) if(!PRESETn) #1 state <= IDLE; else #1 state <= nextstate;
/*********************************************************/
wire                  preadyin = ({PSEL2, PSEL1} == 2'b01) ? PREADYIN1 :
                                 ({PSEL2, PSEL1} == 2'b10) ? PREADYIN2 : 1'b1;
wire [DATA_WIDTH-1:0] prdatain = ({PSEL2, PSEL1} == 2'b01) ? PRDATAIN1 :
                                 ({PSEL2, PSEL1} == 2'b10) ? PRDATAIN2 : 32'd0;
/*********************************************************/
assign PADDR     = (state == SETUP)             ? haddr_d  : paddr_d;
assign PSEL1     = (state == IDLE)              ? 1'b0     :
                   (PADDR[31:16] == 16'h0000)   ? 1'b1     : 1'b0;
assign PSEL2     = (state == IDLE)              ? 1'b0     :
                   (PADDR[31:16] == 16'h0001)   ? 1'b1     : 1'b0;
assign PWRITE    = (state == SETUP)             ? hwrite_d : pwrite_d;
assign PWDATA    = (state == SETUP)             ? HWDATA   : pwdata_d;
assign PENABLE   = (state == ACCESS);
assign PREADYOUT = (state == IDLE)              ? 1'b1     :
                   (state == SETUP)             ? 1'b0     : preadyin;
assign PRDATAOUT = (state == ACCESS && !PWRITE) ? prdatain : 32'd0;

endmodule

1.3 Subordinate1

作为APB1总线的从机1,有3个等待周期

`timescale 1ns/1ps
module subordinate1 #(
    parameter DATA_WIDTH    = 32    ,
    parameter ADDR_WIDTH    = 32
)(
    input  wire                     PCLK        ,
    input  wire                     PRESETn     ,

    input  wire [ADDR_WIDTH-1:0]    PADDR       ,
    input  wire                     PSELx       ,
    input  wire                     PENABLE     ,
    input  wire                     PWRITE      ,
    input  wire [DATA_WIDTH-1:0]    PWDATA      ,

    output wire                     PREADYOUT   ,
    output wire [DATA_WIDTH-1:0]    PRDATAOUT
);
localparam IDLE   = 3'b000;
localparam STAGE1 = 3'b001;
localparam STAGE2 = 3'b010;
localparam STAGE3 = 3'b011;
localparam STAGE4 = 3'b100;

reg [2:0] state;
reg [2:0] nextstate;

always @(*) begin
    case(state) 
        IDLE:   if(PSELx) nextstate = STAGE1;
                else      nextstate = IDLE; 
        STAGE1:           nextstate = STAGE2;
        STAGE2:           nextstate = STAGE3;
        STAGE3:           nextstate = STAGE4;
        STAGE4:           nextstate = IDLE;
        default:          nextstate = IDLE;
    endcase
end

always @(posedge PCLK or negedge PRESETn) if(!PRESETn) #1 state <= IDLE; else #1 state <= nextstate;

reg [DATA_WIDTH-1:0] reg0; //addr = 0
reg [DATA_WIDTH-1:0] reg1; //addr = 4
reg [DATA_WIDTH-1:0] reg2; //addr = 8
reg [DATA_WIDTH-1:0] reg3; //addr = c
reg [DATA_WIDTH-1:0] reg4; //addr = 10
reg [DATA_WIDTH-1:0] reg5; //addr = 14
reg [DATA_WIDTH-1:0] reg6; //addr = 18
reg [DATA_WIDTH-1:0] reg7; //addr = 1c

always @(posedge PCLK or negedge PRESETn) begin
    if(!PRESETn)                                                #1 reg0 <= 32'd0;
    else if(state == STAGE4 && PWRITE && PADDR[15:0] == 16'h0)  #1 reg0 <= PWDATA;
    else                                                        #1 reg0 <= reg0;
end

always @(posedge PCLK or negedge PRESETn) begin
    if(!PRESETn)                                                #1 reg1 <= 32'd0;
    else if(state == STAGE4 && PWRITE && PADDR[15:0] == 16'h4)  #1 reg1 <= PWDATA;
    else                                                        #1 reg1 <= reg1;
end

always @(posedge PCLK or negedge PRESETn) begin
    if(!PRESETn)                                                #1 reg2 <= 32'd0;
    else if(state == STAGE4 && PWRITE && PADDR[15:0] == 16'h8)  #1 reg2 <= PWDATA;
    else                                                        #1 reg2 <= reg2;
end

always @(posedge PCLK or negedge PRESETn) begin
    if(!PRESETn)                                                #1 reg3 <= 32'd0;
    else if(state == STAGE4 && PWRITE && PADDR[15:0] == 16'hc)  #1 reg3 <= PWDATA;
    else                                                        #1 reg3 <= reg3;
end

always @(posedge PCLK or negedge PRESETn) begin
    if(!PRESETn)                                                #1 reg4 <= 32'd0;
    else if(state == STAGE4 && PWRITE && PADDR[15:0] == 16'h10) #1 reg4 <= PWDATA;
    else                                                        #1 reg4 <= reg4;
end

always @(posedge PCLK or negedge PRESETn) begin
    if(!PRESETn)                                                #1 reg5 <= 32'd0;
    else if(state == STAGE4 && PWRITE && PADDR[15:0] == 16'h14) #1 reg5 <= PWDATA;
    else                                                        #1 reg5 <= reg5;
end

always @(posedge PCLK or negedge PRESETn) begin
    if(!PRESETn)                                                #1 reg6 <= 32'd0;
    else if(state == STAGE4 && PWRITE && PADDR[15:0] == 16'h18) #1 reg6 <= PWDATA;
    else                                                        #1 reg6 <= reg6;
end

always @(posedge PCLK or negedge PRESETn) begin
    if(!PRESETn)                                                #1 reg7 <= 32'd0;
    else if(state == STAGE4 && PWRITE && PADDR[15:0] == 16'h1c) #1 reg7 <= PWDATA;
    else                                                        #1 reg7 <= reg7;
end

assign PRDATAOUT = (state == STAGE4 && !PWRITE && PADDR[15:0] == 16'h0)  ? reg0 :
                   (state == STAGE4 && !PWRITE && PADDR[15:0] == 16'h4)  ? reg1 :
                   (state == STAGE4 && !PWRITE && PADDR[15:0] == 16'h8)  ? reg2 :
                   (state == STAGE4 && !PWRITE && PADDR[15:0] == 16'hc)  ? reg3 :
                   (state == STAGE4 && !PWRITE && PADDR[15:0] == 16'h10) ? reg4 :
                   (state == STAGE4 && !PWRITE && PADDR[15:0] == 16'h14) ? reg5 :
                   (state == STAGE4 && !PWRITE && PADDR[15:0] == 16'h18) ? reg6 :
                   (state == STAGE4 && !PWRITE && PADDR[15:0] == 16'h1c) ? reg7 : 32'd0;

assign PREADYOUT = (state == IDLE || state == STAGE4);

endmodule

1.4 Subordinate2

作为APB1总线的从机2,无等待周期

`timescale 1ns/1ps
module subordinate2 #(
    parameter DATA_WIDTH    = 32    ,
    parameter ADDR_WIDTH    = 32
)(
    input  wire                     PCLK        ,
    input  wire                     PRESETn     ,

    input  wire [ADDR_WIDTH-1:0]    PADDR       ,
    input  wire                     PSELx       ,
    input  wire                     PENABLE     ,
    input  wire                     PWRITE      ,
    input  wire [DATA_WIDTH-1:0]    PWDATA      ,

    output wire                     PREADYOUT   ,
    output wire [DATA_WIDTH-1:0]    PRDATAOUT
);
localparam IDLE   = 3'b000;
localparam STAGE1 = 3'b001;

reg [2:0] state;
reg [2:0] nextstate;

always @(*) begin
    case(state) 
        IDLE:   if(PSELx) nextstate = STAGE1;
                else      nextstate = IDLE;
        STAGE1:           nextstate = IDLE;
        default:          nextstate = IDLE;
    endcase
end

always @(posedge PCLK or negedge PRESETn) if(!PRESETn) #1 state <= IDLE; else #1 state <= nextstate;

reg [DATA_WIDTH-1:0] reg0; //addr = 0
reg [DATA_WIDTH-1:0] reg1; //addr = 4
reg [DATA_WIDTH-1:0] reg2; //addr = 8
reg [DATA_WIDTH-1:0] reg3; //addr = c
reg [DATA_WIDTH-1:0] reg4; //addr = 10
reg [DATA_WIDTH-1:0] reg5; //addr = 14
reg [DATA_WIDTH-1:0] reg6; //addr = 18
reg [DATA_WIDTH-1:0] reg7; //addr = 1c

always @(posedge PCLK or negedge PRESETn) begin
    if(!PRESETn)                                                #1 reg0 <= 32'd0;
    else if(state == STAGE1 && PWRITE && PADDR[15:0] == 16'h0)  #1 reg0 <= PWDATA;
    else                                                        #1 reg0 <= reg0;
end

always @(posedge PCLK or negedge PRESETn) begin
    if(!PRESETn)                                                #1 reg1 <= 32'd0;
    else if(state == STAGE1 && PWRITE && PADDR[15:0] == 16'h4)  #1 reg1 <= PWDATA;
    else                                                        #1 reg1 <= reg1;
end

always @(posedge PCLK or negedge PRESETn) begin
    if(!PRESETn)                                                #1 reg2 <= 32'd0;
    else if(state == STAGE1 && PWRITE && PADDR[15:0] == 16'h8)  #1 reg2 <= PWDATA;
    else                                                        #1 reg2 <= reg2;
end

always @(posedge PCLK or negedge PRESETn) begin
    if(!PRESETn)                                                #1 reg3 <= 32'd0;
    else if(state == STAGE1 && PWRITE && PADDR[15:0] == 16'hc)  #1 reg3 <= PWDATA;
    else                                                        #1 reg3 <= reg3;
end

always @(posedge PCLK or negedge PRESETn) begin
    if(!PRESETn)                                                #1 reg4 <= 32'd0;
    else if(state == STAGE1 && PWRITE && PADDR[15:0] == 16'h10) #1 reg4 <= PWDATA;
    else                                                        #1 reg4 <= reg4;
end

always @(posedge PCLK or negedge PRESETn) begin
    if(!PRESETn)                                                #1 reg5 <= 32'd0;
    else if(state == STAGE1 && PWRITE && PADDR[15:0] == 16'h14) #1 reg5 <= PWDATA;
    else                                                        #1 reg5 <= reg5;
end

always @(posedge PCLK or negedge PRESETn) begin
    if(!PRESETn)                                                #1 reg6 <= 32'd0;
    else if(state == STAGE1 && PWRITE && PADDR[15:0] == 16'h18) #1 reg6 <= PWDATA;
    else                                                        #1 reg6 <= reg6;
end

always @(posedge PCLK or negedge PRESETn) begin
    if(!PRESETn)                                                #1 reg7 <= 32'd0;
    else if(state == STAGE1 && PWRITE && PADDR[15:0] == 16'h1c) #1 reg7 <= PWDATA;
    else                                                        #1 reg7 <= reg7;
end

assign PRDATAOUT = (state == STAGE1 && !PWRITE && PADDR[15:0] == 16'h0)  ? reg0 :
                   (state == STAGE1 && !PWRITE && PADDR[15:0] == 16'h4)  ? reg1 :
                   (state == STAGE1 && !PWRITE && PADDR[15:0] == 16'h8)  ? reg2 :
                   (state == STAGE1 && !PWRITE && PADDR[15:0] == 16'hc)  ? reg3 :
                   (state == STAGE1 && !PWRITE && PADDR[15:0] == 16'h10) ? reg4 :
                   (state == STAGE1 && !PWRITE && PADDR[15:0] == 16'h14) ? reg5 :
                   (state == STAGE1 && !PWRITE && PADDR[15:0] == 16'h18) ? reg6 :
                   (state == STAGE1 && !PWRITE && PADDR[15:0] == 16'h1c) ? reg7 : 32'd0;

assign PREADYOUT = (state == IDLE || state == STAGE1);

endmodule

1.5 Decoder

`timescale 1ns/1ps
module decoder #(
    parameter ADDR_WIDTH    = 32
)(
    input  wire [ADDR_WIDTH-1:0]    HADDR   ,
    output wire                     HSEL1   ,
    output wire                     HSEL2   ,
    output wire                     HSELD 
);

/*
 * Address Space
 * ahb2apb1 0x0000_0000~0x0001_ffff 64KB
 * ahb2apb2 0x0002_0000~0x0003_ffff 64KB
 */
reg hsel1;
reg hsel2;
reg hseld;

always @(*) begin
    case(HADDR[31:16])
        16'h0000, 16'h0001:
            {hseld, hsel2, hsel1} = 3'b001;
        16'h0002, 16'h0003:
            {hseld, hsel2, hsel1} = 3'b010;
        default:
            {hseld, hsel2, hsel1} = 3'b100;
    endcase
end

assign HSEL1 = hsel1;
assign HSEL2 = hsel2;
assign HSELD = hseld;

endmodule

1.6 Testbench

`timescale 1ns/1ps
module testbench;

localparam DATA_WIDTH   =   32;
localparam ADDR_WIDTH   =   32;
//size
localparam BYTE         =   3'd0;
localparam HALFWORD     =   3'd1;
localparam WORD         =   3'd2;
//burst
localparam SINGLE       =   3'd0;
localparam INCR         =   3'd1;
localparam WRAP4        =   3'd2;
localparam INCR4        =   3'd3;
localparam WRAP8        =   3'd4;
localparam INCR8        =   3'd5;
localparam WRAP16       =   3'd6;
localparam INCR16       =   3'd7;

//ahb
reg                     HCLK        ;
reg                     HRESETn     ;
wire [ADDR_WIDTH-1:0]   HADDR       ;
wire [2:0]              HBURST      ;
wire [2:0]              HSIZE       ;
wire [1:0]              HTRANS      ;
wire [DATA_WIDTH-1:0]   HWDATA      ;
wire                    HWRITE      ;
reg                     cmd_start   ;
reg  [DATA_WIDTH-1:0]   cmd_wdata   ;
reg  [ADDR_WIDTH-1:0]   cmd_addr    ;
reg                     cmd_write   ;
reg  [2:0]              cmd_size    ;
reg  [2:0]              cmd_burst   ;
reg  [3:0]              cmd_length  ;
reg                     cmd_busy    ;
reg                     cmd_stop    ;
wire [DATA_WIDTH-1:0]   cmd_rdata   ;
wire                    cmd_error   ;
wire                    cmd_ready   ;
//decoder
wire                    HSEL1       ;
wire                    HSEL2       ;
//ahb2apb1
wire [ADDR_WIDTH-1:0]   PADDR       ;
wire                    PSEL1       ;
wire                    PSEL2       ;
wire                    PENABLE     ;
wire                    PWRITE      ;
wire [DATA_WIDTH-1:0]   PWDATA      ;
wire [DATA_WIDTH-1:0]   PRDATAOUT1  ;
wire                    PREADYOUT1  ;
//sub1
wire                    S_PREADYOUT1;
wire [DATA_WIDTH-1:0]   S_PRDATAOUT1;
//sub2
wire                    S_PREADYOUT2;
wire [DATA_WIDTH-1:0]   S_PRDATAOUT2;
//multiplexor
reg  [DATA_WIDTH-1:0]   HRDATA      ;
reg                     HREADY      ;
//rstn_sync
wire                    HRESETn_s   ;

rstn_sync u_rstn_sync(
    .clk_i          (HCLK)          ,
    .rstn_async_i   (HRESETn)       ,
    .rstn_sync_o    (HRESETn_s)
);

ahb #(
    .DATA_WIDTH     (DATA_WIDTH)    ,
    .ADDR_WIDTH     (ADDR_WIDTH)
)u_ahb(
    .HCLK           (HCLK)          ,
    .HRESETn        (HRESETn_s)     ,
    .HADDR          (HADDR)         ,
    .HBURST         (HBURST)        ,
    .HSIZE          (HSIZE)         ,
    .HTRANS         (HTRANS)        ,
    .HWDATA         (HWDATA)        ,
    .HWRITE         (HWRITE)        ,
    .HRDATA         (HRDATA)        ,
    .HREADY         (HREADY)        ,
    .HRESP          ()              ,
    .cmd_start      (cmd_start)     ,
    .cmd_wdata      (cmd_wdata)     ,
    .cmd_addr       (cmd_addr)      ,
    .cmd_write      (cmd_write)     ,
    .cmd_size       (cmd_size)      ,
    .cmd_burst      (cmd_burst)     ,
    .cmd_length     (cmd_length)    ,
    .cmd_busy       (cmd_busy)      ,
    .cmd_stop       (cmd_stop)      ,
    .cmd_rdata      (cmd_rdata)     ,
    .cmd_error      (cmd_error)     ,
    .cmd_ready      (cmd_ready)
);

decoder #(
    .ADDR_WIDTH     (ADDR_WIDTH)    
)u_decoder(
    .HADDR          (HADDR)         ,
    .HSEL1          (HSEL1)         ,
    .HSEL2          (HSEL2)         ,
    .HSELD          ()
);

ahb2apb1 #(
    .DATA_WIDTH     (DATA_WIDTH)    ,
    .ADDR_WIDTH     (ADDR_WIDTH)
)u_ahb2apb1(
    .PCLK           (HCLK)          ,
    .PRESETn        (HRESETn_s)     ,
    .PADDR          (PADDR)         ,
    .PSEL1          (PSEL1)         ,
    .PSEL2          (PSEL2)         ,
    .PENABLE        (PENABLE)       ,
    .PWRITE         (PWRITE)        ,
    .PWDATA         (PWDATA)        ,
    .PREADYIN1      (S_PREADYOUT1)  ,
    .PREADYIN2      (S_PREADYOUT2)  ,
    .PRDATAIN1      (S_PRDATAOUT1)  ,
    .PRDATAIN2      (S_PRDATAOUT2)  ,
    .HSELx          (HSEL1)         ,
    .HADDR          (HADDR)         ,
    .HTRANS         (HTRANS)        ,
    .HWRITE         (HWRITE)        ,
    .HSIZE          (HSIZE)         ,
    .HBURST         (HBURST)        ,
    .HWDATA         (HWDATA)        ,
    .PRDATAOUT      (PRDATAOUT1)    ,
    .PREADYOUT      (PREADYOUT1)
);

subordinate1 #(
    .DATA_WIDTH     (DATA_WIDTH)    ,
    .ADDR_WIDTH     (ADDR_WIDTH)
)u_subordinate1(
    .PCLK           (HCLK)          ,
    .PRESETn        (HRESETn_s)     ,
    .PADDR          (PADDR)         ,
    .PSELx          (PSEL1)         ,
    .PENABLE        (PENABLE)       ,
    .PWRITE         (PWRITE)        ,
    .PWDATA         (PWDATA)        ,
    .PREADYOUT      (S_PREADYOUT1)  ,
    .PRDATAOUT      (S_PRDATAOUT1)
);

subordinate2 #(
    .DATA_WIDTH     (DATA_WIDTH)    ,
    .ADDR_WIDTH     (ADDR_WIDTH)
)u_subordinate2(
    .PCLK           (HCLK)          ,
    .PRESETn        (HRESETn_s)     ,
    .PADDR          (PADDR)         ,
    .PSELx          (PSEL2)         ,
    .PENABLE        (PENABLE)       ,
    .PWRITE         (PWRITE)        ,
    .PWDATA         (PWDATA)        ,
    .PREADYOUT      (S_PREADYOUT2)  ,
    .PRDATAOUT      (S_PRDATAOUT2)
);

multiplexor #(
    .DATA_WIDTH     (DATA_WIDTH)    
)u_multiplexor(
    .HCLK           (HCLK)          ,
    .HRESETn        (HRESETn_s)     ,
    .HSEL1          (HSEL1)         ,
    .HSEL2          (HSEL2)         ,
    .HSELD          ()              ,
    .HREADYIN1      (PREADYOUT1)    ,
    .HRDATAIN1      (PRDATAOUT1)    ,
    .HRESPIN1       ()              ,
    .HREADYIN2      ()              ,
    .HRDATAIN2      ()              ,
    .HRESPIN2       ()              ,
    .HREADYIND      ()              ,
    .HRDATAIND      ()              ,
    .HRESPIND       ()              ,
    .HRDATAOUT      (HRDATA)        ,
    .HREADYOUT      (HREADY)        ,
    .HRESPOUT       ()
);

initial begin
    $fsdbDumpfile("ahb2apb.fsdb");
    $fsdbDumpvars(0, testbench);
end

parameter TIMEOUT = 100000;

always #10 HCLK = ~HCLK;

initial begin
    HCLK        = 1'b0;
    HRESETn     = 1'b1;
    cmd_start   = 1'b0;
    cmd_wdata   =  'd0;
    cmd_addr    =  'd0;
    cmd_write   = 1'b0;
    cmd_size    = 3'd0;
    cmd_burst   = 3'd0;
    cmd_length  = 4'd0;
    cmd_stop    = 1'b0;
    cmd_busy    = 1'b0;
    #55 HRESETn = 1'b0;
    #50 HRESETn = 1'b1;

    fork begin
        #(TIMEOUT);
        $finish(2);
    end join_none

    repeat(10) @(posedge HCLK);

    Single_Write(32'h0000_0000, 32'd100);
    Single_Write(32'h0001_0000, 32'd200); 
    Single_Read(32'h0000_0000);
    Single_Read(32'h0001_0000);
    //Single_Read(32'h0001_0000);
    /*case2(32'h0000_0000, 32'd0);
    case2(32'h0001_0000, 32'd0);
    case3(32'h0000_0000);
    case3(32'h0001_0000);*/
    /*case4(32'h0000_001c, WRAP8);
    case5(32'h0000_0004, WRAP8);
    case4(32'h0001_0014, WRAP8);
    case5(32'h0001_0008, WRAP4);*/
    repeat(10) @(posedge HCLK);

    $finish;
end

task Single_Write(input [ADDR_WIDTH-1:0] addr, input [DATA_WIDTH-1:0] data); //Single write
    @(posedge HCLK) #1;
    cmd_start = 1'b1;
    @(posedge HCLK) #1;
    cmd_start = 1'b0;
    cmd_size  = WORD;
    cmd_burst = SINGLE;
    cmd_write = 1;
    cmd_addr  = addr;
    @(posedge HCLK) #1;
    cmd_wdata = data;
    cmd_size  = $urandom();
    cmd_burst = $urandom();
    cmd_write = $urandom();
    cmd_addr  = $urandom();
    @(posedge HCLK) #1;
    cmd_wdata = $urandom();
    #1 wait(HREADY);
endtask

task Single_Read(input [ADDR_WIDTH-1:0] addr); //Single read
    @(posedge HCLK) #1;
    cmd_start = 1'b1;
    @(posedge HCLK) #1;
    cmd_start = 1'b0;
    cmd_size  = WORD;
    cmd_burst = SINGLE;
    cmd_write = 0;
    cmd_addr  = addr;
    @(posedge HCLK) #1;
    cmd_wdata = $urandom();
    cmd_size  = $urandom();
    cmd_burst = $urandom();
    cmd_write = $urandom();
    cmd_addr  = $urandom();
    @(posedge HCLK) #1;
    #1 wait(HREADY);
endtask

task case2(input [ADDR_WIDTH-1:0] addr, input [DATA_WIDTH-1:0] data);//Incr write
    @(posedge HCLK) #1;
    cmd_start = 1'b1;
    @(posedge HCLK) #1;
    cmd_start = 1'b0;
    cmd_size  = WORD;
    cmd_burst = INCR;
    cmd_write = 1;
    cmd_addr  = addr;

    #1 wait(HREADY);                  //write reg0
    @(posedge HCLK) #1;
    cmd_wdata = $urandom(); 

    #1 wait(HREADY);                  //write reg1
    @(posedge HCLK) #1;
    cmd_wdata = $urandom();

    #1 wait(HREADY);                  //write reg2
    @(posedge HCLK) #1;
    cmd_wdata = $urandom();

    #1 wait(HREADY);                  //write reg3
    @(posedge HCLK) #1;
    cmd_wdata = $urandom();

    #1 wait(HREADY);                  //write reg4
    @(posedge HCLK) #1;
    cmd_wdata = $urandom();

    #1 wait(HREADY);                  //write reg5
    @(posedge HCLK) #1;
    cmd_wdata = $urandom();

    #1 wait(HREADY);                  //write reg6
    @(posedge HCLK) #1;
    cmd_wdata = $urandom();

    #1 wait(HREADY); cmd_stop = 1'b1; //write reg7
    @(posedge HCLK) #1;
    cmd_stop = 1'b0;
    cmd_wdata = $urandom();

    #1 wait(HREADY);
endtask

task case3(input [ADDR_WIDTH-1:0] addr);//Incr read
    @(posedge HCLK) #1;
    cmd_start = 1'b1;
    @(posedge HCLK) #1;
    cmd_start = 1'b0;
    cmd_size  = WORD;
    cmd_burst = INCR;
    cmd_write = 0;
    cmd_addr  = addr;

    #1 wait(HREADY);                  //read reg0
    @(posedge HCLK) #1;

    #1 wait(HREADY);                  //read reg1
    @(posedge HCLK) #1;

    #1 wait(HREADY);                  //read reg2
    @(posedge HCLK) #1;

    #1 wait(HREADY);                  //read reg3
    @(posedge HCLK) #1;

    #1 wait(HREADY);                  //read reg4
    @(posedge HCLK) #1;

    #1 wait(HREADY);                  //read reg5
    @(posedge HCLK) #1;

    #1 wait(HREADY);                  //read reg6
    @(posedge HCLK) #1;

    #1 wait(HREADY); cmd_stop = 1'b1; //read reg7
    @(posedge HCLK) #1;
    cmd_stop = 1'b0;

    #1 wait(HREADY);
endtask

task case4(input [ADDR_WIDTH-1:0] addr, input [2:0] burst);//INCR4... write
    @(posedge HCLK) #1;
    cmd_start = 1'b1;
    @(posedge HCLK) #1;
    cmd_start = 1'b0;
    cmd_size  = WORD;
    cmd_burst = burst;
    cmd_write = 1;
    cmd_addr  = addr;

    case(cmd_burst)
        INCR4, WRAP4:
            repeat(4) begin
                #1 wait(HREADY);                  
                @(posedge HCLK) #1;
                cmd_wdata = $urandom(); 
            end
        INCR8, WRAP8:
            repeat(8) begin
                #1 wait(HREADY);                  
                @(posedge HCLK) #1;
                cmd_wdata = $urandom(); 
            end
        INCR16, WRAP16:
            repeat(16) begin
                #1 wait(HREADY);                  
                @(posedge HCLK) #1;
                cmd_wdata = $urandom(); 
            end
    endcase

    #1 wait(HREADY);
endtask

task case5(input [ADDR_WIDTH-1:0] addr, input [2:0] burst);//INCR4... read
    @(posedge HCLK) #1;
    cmd_start = 1'b1;
    @(posedge HCLK) #1;
    cmd_start = 1'b0;
    cmd_size  = WORD;
    cmd_burst = burst;
    cmd_write = 0;
    cmd_addr  = addr;

    case(cmd_burst)
        INCR4, WRAP4:
            repeat(4) begin
                #1 wait(HREADY);                  
                @(posedge HCLK) #1;
            end
        INCR8, WRAP8:
            repeat(8) begin
                #1 wait(HREADY);                  
                @(posedge HCLK) #1;
            end
        INCR16, WRAP16:
            repeat(16) begin
                #1 wait(HREADY);                  
                @(posedge HCLK) #1;
            end
    endcase

    #1 wait(HREADY);
endtask

endmodule

二、仿真

2.1 Single Write和Single Read

image

posted @ 2025-12-19 17:11  Holybanban  阅读(0)  评论(0)    收藏  举报