0%

FPGA系统设计之AHB总线

本节主要介绍了AHB协议的基本传输时序,并以基于简单AHB的SRAM读写实验加强理解。

AHB协议的基本介绍

  • Advanced High-performance Bus(先进高性能总线)是一种适用于高性能可综合设计的总线接口

  • 最常见的AHB slaver是内部存储器设备、外部存储器接口和高带宽外设

  • 虽然低带宽外设可以作为AHB slaver,但出于系统性能原因,它们通常在APB上,AHB和APB之间的连接是使用APB桥完成的

    image-20241115230820046
  • 其分为地址阶段和数据阶段,支持2级流水线操作

  • AHB总线组成(以AHB5(在AHB-lite上的改进)为例):

    • 单layer:

      • 分配给每个slave的地址空间最小地址空间为1KB,故master的设计不会执行地址范围超过1KB的增量传输

      image-20241115231418880

    • 多layer:

      image-20241115231448284

AHB协议的基本传输时序

  • 传输时序建议直接看AHB官方手册,这里只能粘贴一些基本的时序,具体理解还得自己上手操作

1.基础传输

  • 两个传输阶段:
    • 地址阶段:一个时钟周期,用于准备好地址
    • 数据阶段:一个或多个时钟周期,用于数据的读写

1.1 写操作

  • 无等待:

    image-20241115231918595
  • 有等待:

    image-20241115231957611

1.2 读操作

  • 无等待:

    image-20241115232046236

  • 有等待:

    image-20241115232025085

1.3 读写操作

image-20241115232257127

2.传输类型(HTRANS)

  • IDLE(0b00):Master无数据传输,slave回复HRESP=0并忽略传输

  • BUSY(0b01):Master忙碌,在burst传输中间插入BUSY,请求传输延缓。slave回复HRESP=0并忽略传输

  • NONSEQ(0b10):表明是单次传输或者是burst传输(≈连续传输)的第一个传输,下一个传输的地址和控制信号与之前的无关系

  • SEQ(0b11):下一个传输的地址和控制信号与之前的有关系:下一个传输的地址=上一个地址+HSIZE的字节数(或者循环加上HSIZE的字节数)

    image-20241115233056582

3.传输大小(HSIZE)

  • HSIZE对应的传输数据位宽:$2^{HSIZE}byte=8*2^{HSIZE}bit$
image-20241115233149391

4.突发操作(HBURST)

  • 循环突发(Wrapping burst)对应的地址计算方式:首先计算总传输数据大小,然后将当前位置除以总传输数据大小,若不能整除则以当前地址传输数据,否则将当前地址减去总传输数据大小,作为传输地址。

  • HTRANS决定传输的模式(主要还是看突发还是非突发),那么HBURST就决定怎么个突发规则,而HSIZE则决定在该突发规则下,地址递增的值

    image-20241115233530441

4.1 Four-beat wrapping burst, WRAP4

  • 其中4代表突发成功传输的个数为4,而在这4个数未传输完成时,HSIZE不能改变

image-20241115234234227

4.2 Four-beat incrementing burst, INCR4

image-20241115234319720

4.3 Eight-beat wrapping burst, WRAP8

image-20241115234427324

4.4 Eight-beat incrementing burst, INCR8

image-20241115234449316

4.5 Undefined length bursts, INCR

image-20241115234521328


基于AHB总线的简单SRAM读写实验

  • 设计顶层框图:

    image-20241115235342978
  • sram_interface框图:

    image-20241115235415940

1.源代码

  • sram_top.v

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    module sram_top(
    // AHB Signal
    input HCLK,
    input HRESETn,
    input HSEL ,
    input [1:0] HTRANS,
    input [2:0] HBURST,
    input [2:0] HSIZE ,
    input HWRITE,
    input [15:0] HADDR ,
    input [31:0] HWDATA,

    output HREADY,
    output [1:0] HRESP ,
    output [31:0] HRDATA
    );


    // Wires Between SRAM_interface and SRAM_core
    wire SRAM_WEN_BANK0;
    wire SRAM_WEN_BANK1;
    wire [12:0] SRAM_ADDR ;
    wire [3:0] SRAM_CSN_BANK0;
    wire [3:0] SRAM_CSN_BANK1;
    wire [31:0] SRAM_WDATA ;

    wire [7:0] SRAM0_q;
    wire [7:0] SRAM1_q;
    wire [7:0] SRAM2_q;
    wire [7:0] SRAM3_q;
    wire [7:0] SRAM4_q;
    wire [7:0] SRAM5_q;
    wire [7:0] SRAM6_q;
    wire [7:0] SRAM7_q;

    /*————————————————————————————————————————————————————————————————————————*\
    / SRAM Interface Instantiation \
    \*————————————————————————————————————————————————————————————————————————*/
    sram_interface u_interface(
    //---------------AHB SIGNAL--------------
    //in
    .iHCLK (HCLK ),
    .iHRESETn(HRESETn),
    .iHSEL (HSEL ),
    .iHBURST (HBURST ),
    .iHWRITE (HWRITE ),
    .iHTRANS (HTRANS ),
    .iHSIZE (HSIZE ),
    .iHWDATA (HWDATA ),
    .iHADDR (HADDR ),
    //out
    .oHRESP (HRESP ),
    .oHREADY (HREADY ),
    .oHRDATA (HRDATA ),
    //--------------SRAM SIGNAL--------------
    //in
    .iSRAM0_q(SRAM0_q),
    .iSRAM1_q(SRAM1_q),
    .iSRAM2_q(SRAM2_q),
    .iSRAM3_q(SRAM3_q),
    .iSRAM4_q(SRAM4_q),
    .iSRAM5_q(SRAM5_q),
    .iSRAM6_q(SRAM6_q),
    .iSRAM7_q(SRAM7_q),
    //out
    .oSRAM_WEN_BANK0(SRAM_WEN_BANK0),
    .oSRAM_WEN_BANK1(SRAM_WEN_BANK1),
    .oSRAM_CSN_BANK0(SRAM_CSN_BANK0),
    .oSRAM_CSN_BANK1(SRAM_CSN_BANK1),
    .oSRAM_ADDR (SRAM_ADDR),
    .oSRAM_WDATA (SRAM_WDATA)
    );
    /*————————————————————————————————————————————————————————————————————————*\
    / SRAM Core Instantiation \
    \*————————————————————————————————————————————————————————————————————————*/
    sram_core u_core(
    //----------- From AHB ------------
    .iHCLK (HCLK ),
    //--------- From Interface ---------
    .iSRAM_WEN_BANK0 (SRAM_WEN_BANK0),
    .iSRAM_WEN_BANK1(SRAM_WEN_BANK1),
    .iSRAM_ADDR (SRAM_ADDR ),
    .iSRAM_CSN_BANK0(SRAM_CSN_BANK0),
    .iSRAM_CSN_BANK1(SRAM_CSN_BANK1),
    .iSRAM_WDATA (SRAM_WDATA ),
    //---------- To Interface ---------
    .oSRAM0_q (SRAM0_q),
    .oSRAM1_q (SRAM1_q),
    .oSRAM2_q (SRAM2_q),
    .oSRAM3_q (SRAM3_q),
    .oSRAM4_q (SRAM4_q),
    .oSRAM5_q (SRAM5_q),
    .oSRAM6_q (SRAM6_q),
    .oSRAM7_q (SRAM7_q)
    );

    endmodule
  • sram_interface.v

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    module sram_interface(
    //---------------AHB SIGNAL--------------
    //in
    input iHCLK ,
    input iHRESETn,
    input iHSEL ,
    input iHWRITE ,
    input [2 : 0] iHBURST ,
    input [1 : 0] iHTRANS ,
    input [2 : 0] iHSIZE ,
    input [31 : 0] iHWDATA ,
    input [15 : 0] iHADDR ,
    //out
    output [1 : 0] oHRESP ,
    output oHREADY ,
    output [31 : 0] oHRDATA ,

    //--------------SRAM SIGNAL--------------
    //in
    input [7 : 0] iSRAM0_q,
    input [7 : 0] iSRAM1_q,
    input [7 : 0] iSRAM2_q,
    input [7 : 0] iSRAM3_q,
    input [7 : 0] iSRAM4_q,
    input [7 : 0] iSRAM5_q,
    input [7 : 0] iSRAM6_q,
    input [7 : 0] iSRAM7_q,
    //out
    output oSRAM_WEN_BANK0,
    output oSRAM_WEN_BANK1,
    output [3 : 0] oSRAM_CSN_BANK0,
    output [3 : 0] oSRAM_CSN_BANK1,
    output [12 : 0] oSRAM_ADDR,
    output [31 : 0] oSRAM_WDATA
    );

    /*————————————————————————————————————————————————————————————————————————*\
    / AHB Signal Register \
    \*————————————————————————————————————————————————————————————————————————*/
    reg iHSEL_r ;
    reg iHWRITE_r ;
    reg iHWRITE_2r;
    reg [2 : 0] iHBURST_r ;
    reg [1 : 0] iHTRANS_r ;
    reg [2 : 0] iHSIZE_r ;
    reg [31 : 0] iHWDATA_r ;
    reg [15 : 0] iHADDR_r ;
    reg [15 : 0] iHADDR_2r ;

    always@(posedge iHCLK) begin
    if(!iHRESETn) begin
    iHSEL_r <= 1'b0;
    iHWRITE_r <= 1'b0;
    iHWRITE_2r <= 1'b0;
    iHBURST_r <= 3'b0;
    iHTRANS_r <= 2'b0;
    iHSIZE_r <= 3'b0;
    iHWDATA_r <= 32'b0;
    iHADDR_r <= 16'b0;
    iHADDR_2r <= 16'b0;
    end
    else begin
    iHSEL_r <= iHSEL;
    iHWRITE_r <= iHWRITE;
    iHWRITE_2r <= iHWRITE_r;
    iHBURST_r <= iHBURST;
    iHTRANS_r <= iHTRANS;
    iHSIZE_r <= iHSIZE;
    iHWDATA_r <= iHWDATA;
    iHADDR_r <= iHADDR;
    iHADDR_2r <= iHADDR_r;
    end
    end

    /*————————————————————————————————————————————————————————————————————————*\
    / AHB BUS → Interface → SRAM Core \
    \*————————————————————————————————————————————————————————————————————————*/
    // SRAM Write Enable
    assign oSRAM_WEN_BANK0 = ( iHWRITE_r == 1'b1 && iHADDR_r[15] == 1'b0) ? 1'b1 : 1'b0;
    assign oSRAM_WEN_BANK1 = ( iHWRITE_r == 1'b1 && iHADDR_r[15] == 1'b1) ? 1'b1 : 1'b0;

    // SRAM Bank CSN select for read ↓ select for write ↓
    assign oSRAM_CSN_BANK0 = ( iHADDR_r[15] == 1'b0 || (iHADDR[15] == 1'b0 && iHWRITE == 1'b0) ) ? 4'b1111 : 4'b0000;
    assign oSRAM_CSN_BANK1 = ( iHADDR_r[15] == 1'b1 || (iHADDR[15] == 1'b1 && iHWRITE == 1'b0) ) ? 4'b1111 : 4'b0000;

    // SRAM Addr
    wire [12 : 0] SRAM_WRITE_ADDR;
    wire [12 : 0] SRAM_READ_ADDR;
    assign SRAM_WRITE_ADDR = iHADDR_r[14 : 2]; // WRITE:addr have to wait a T , sent together with data to SRAM_CORE
    assign SRAM_READ_ADDR = iHADDR [14 : 2]; // READ :addr send to MEM at once
    assign oSRAM_ADDR = (iHWRITE_r == 1'b1) ? SRAM_WRITE_ADDR : SRAM_READ_ADDR;

    // SRAM Write Data
    assign oSRAM_WDATA = iHWDATA;
    /*————————————————————————————————————————————————————————————————————————*\
    / AHB BUS ← Interface ← SRAM Core \
    \*————————————————————————————————————————————————————————————————————————*/
    // response to AHB MASTER
    assign oHREADY = (iHSEL_r == 1'b1 && (iHWRITE_r == 1'b1 || iHWRITE_2r == 1'b0)) ? 1'b1 : 1'b0 ;
    assign oHRESP = (iHSEL_r == 1'b1) ? 2'b00 : 2'b01; //OKAY = 2'b00

    // sram read data
    assign oHRDATA = (iHSEL_r == 1'b1 && iHWRITE_r == 1'b0 && iHADDR_r[15] == 1'b0) ? {iSRAM3_q, iSRAM2_q, iSRAM1_q, iSRAM0_q}:
    (iHSEL_r == 1'b1 && iHWRITE_r == 1'b0 && iHADDR_r[15] == 1'b1) ? {iSRAM7_q, iSRAM6_q, iSRAM5_q, iSRAM4_q}:
    32'bz;

    endmodule
  • sram_core.v

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    module sram_core(
    // From AHB
    input iHCLK ,

    // From sram_interface
    input iSRAM_WEN_BANK0,
    input iSRAM_WEN_BANK1,
    input [12 : 0] iSRAM_ADDR ,
    input [3 : 0] iSRAM_CSN_BANK0,
    input [3 : 0] iSRAM_CSN_BANK1,
    input [31 : 0] iSRAM_WDATA ,

    // To sram_interface
    output [7 : 0] oSRAM0_q,
    output [7 : 0] oSRAM1_q,
    output [7 : 0] oSRAM2_q,
    output [7 : 0] oSRAM3_q,
    output [7 : 0] oSRAM4_q,
    output [7 : 0] oSRAM5_q,
    output [7 : 0] oSRAM6_q,
    output [7 : 0] oSRAM7_q
    );

    /*————————————————————————————————————————————————————————————————————————*\
    / BANK 0 Instantiation \
    \*————————————————————————————————————————————————————————————————————————*/
    sram_bist u_bank0_sram0 (
    // Function Mode IO
    .iSRAM_CLK (iHCLK ),
    .iSRAM_CSN (iSRAM_CSN_BANK0[0]),
    .iSRAM_WEN (iSRAM_WEN_BANK0 ),
    .iSRAM_ADDR (iSRAM_ADDR ), //13 bits SRAM ADDR
    .iSRAM_WDATA(iSRAM_WDATA[7:0] ),
    .oSRAM_RDATA(oSRAM0_q )
    );
    sram_bist u_bank0_sram1 (
    // Function Mode IO
    .iSRAM_CLK (iHCLK ),
    .iSRAM_CSN (iSRAM_CSN_BANK0[1]),
    .iSRAM_WEN (iSRAM_WEN_BANK0 ),
    .iSRAM_ADDR (iSRAM_ADDR ), //13 bits SRAM ADDR
    .iSRAM_WDATA(iSRAM_WDATA[15:8] ),
    .oSRAM_RDATA(oSRAM1_q )
    );
    sram_bist u_bank0_sram2 (
    // Function Mode IO
    .iSRAM_CLK (iHCLK ),
    .iSRAM_CSN (iSRAM_CSN_BANK0[2]),
    .iSRAM_WEN (iSRAM_WEN_BANK0 ),
    .iSRAM_ADDR (iSRAM_ADDR ), //13 bits SRAM ADDR
    .iSRAM_WDATA(iSRAM_WDATA[23:16]),
    .oSRAM_RDATA(oSRAM2_q )
    );
    sram_bist u_bank0_sram3 (
    // Function Mode IO
    .iSRAM_CLK (iHCLK ),
    .iSRAM_CSN (iSRAM_CSN_BANK0[3]),
    .iSRAM_WEN (iSRAM_WEN_BANK0 ),
    .iSRAM_ADDR (iSRAM_ADDR ), //13 bits SRAM ADDR
    .iSRAM_WDATA(iSRAM_WDATA[31:24]),
    .oSRAM_RDATA(oSRAM3_q )
    );

    /*————————————————————————————————————————————————————————————————————————*\
    / BANK 1 Instantiation \
    \*————————————————————————————————————————————————————————————————————————*/
    sram_bist u_bank1_sram4 (
    // Function Mode IO
    .iSRAM_CLK (iHCLK ),
    .iSRAM_CSN (iSRAM_CSN_BANK1[0]),
    .iSRAM_WEN (iSRAM_WEN_BANK1 ),
    .iSRAM_ADDR (iSRAM_ADDR ), //13 bits SRAM ADDR
    .iSRAM_WDATA(iSRAM_WDATA[7:0] ),
    .oSRAM_RDATA(oSRAM4_q )
    );
    sram_bist u_bank1_sram5 (
    // Function Mode IO
    .iSRAM_CLK (iHCLK ),
    .iSRAM_CSN (iSRAM_CSN_BANK1[1]),
    .iSRAM_WEN (iSRAM_WEN_BANK1 ),
    .iSRAM_ADDR (iSRAM_ADDR ), //13 bits SRAM ADDR
    .iSRAM_WDATA(iSRAM_WDATA[15:8] ),
    .oSRAM_RDATA(oSRAM5_q )
    );
    sram_bist u_bank1_sram6 (
    // Function Mode IO
    .iSRAM_CLK (iHCLK ),
    .iSRAM_CSN (iSRAM_CSN_BANK1[2]),
    .iSRAM_WEN (iSRAM_WEN_BANK1 ),
    .iSRAM_ADDR (iSRAM_ADDR ), //13 bits SRAM ADDR
    .iSRAM_WDATA(iSRAM_WDATA[23:16]),
    .oSRAM_RDATA(oSRAM6_q )
    );
    sram_bist u_bank1_sram7 (
    // Function Mode IO
    .iSRAM_CLK (iHCLK ),
    .iSRAM_CSN (iSRAM_CSN_BANK1[3]),
    .iSRAM_WEN (iSRAM_WEN_BANK1 ),
    .iSRAM_ADDR (iSRAM_ADDR ), //13 bits SRAM ADDR
    .iSRAM_WDATA(iSRAM_WDATA[31:24]),
    .oSRAM_RDATA(oSRAM7_q )
    );

    endmodule

2.Testbench

  • sram_tb.v

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    128
    129
    130
    131
    132
    133
    134
    135
    136
    137
    138
    139
    140
    141
    142
    143
    144
    145
    146
    147
    148
    149
    150
    151
    152
    153
    154
    155
    156
    157
    158
    159
    160
    161
    162
    163
    164
    165
    166
    167
    168
    169
    170
    171
    172
    173
    174
    175
    176
    177
    178
    179
    180
    181
    182
    183
    184
    185
    186
    187
    188
    189
    190
    191
    192
    193
    194
    195
    196
    197
    198
    199
    200
    201
    202
    203
    204
    205
    206
    207
    module sram_tb #(
    //HRESP
    parameter OKAY = 2'b00 ,
    parameter ERROR = 2'b01 ,
    parameter SPLIT = 2'b10 ,
    parameter RETRY = 2'b11 ,
    //HTRANS
    parameter IDLE = 2'b00 ,
    parameter BUSY = 2'b01 ,
    parameter SEQ = 2'b10 ,
    parameter NONSEQ = 2'b11 ,
    //HSIZE
    parameter BYTE = 3'b000 ,
    parameter WORD = 3'b001 ,
    parameter DWORD = 3'b010 ,
    //HBURST
    parameter SINGLE = 3'b000 ,
    parameter INCR = 3'b001 ,
    parameter WRAP4 = 3'b010 ,
    parameter INCR4 = 3'b011 ,
    parameter WARP8 = 3'b100 ,
    parameter INCR8 = 3'b101 ,
    parameter WARP16 = 3'b110 ,
    parameter INCR16 = 3'b111

    )();

    // input output declaration
    reg HCLK;
    reg HRESETn;
    reg HSEL ;
    reg [1:0] HTRANS;
    reg [2:0] HBURST;
    reg [2:0] HSIZE ;
    reg HWRITE;
    reg [15:0] HADDR ;
    reg [31:0] HWDATA;
    wire HREADY;
    wire [1:0] HRESP ;
    wire [31:0] HRDATA;

    // top module instantion
    sram_top u_test(
    .HCLK (HCLK ),
    .HRESETn(HRESETn),
    .HSEL (HSEL ),
    .HTRANS (HTRANS ),
    .HBURST (HBURST ),
    .HSIZE (HSIZE ),
    .HWRITE (HWRITE ),
    .HADDR (HADDR ),
    .HWDATA (HWDATA ),
    .HREADY (HREADY ),
    .HRESP (HRESP ),
    .HRDATA (HRDATA )
    );

    // Excitation Vector Generation
    initial begin
    forever #10 HCLK = ~HCLK; //50Mhz
    end

    initial begin
    HCLK = 0;
    HRESETn = 0;

    /*————————————————————————————————————————————————————————————————————————*\
    / Testbench for FUNC Mode \
    \*————————————————————————————————————————————————————————————————————————*/

    HRESETn = 0;

    HSEL <= 0;
    HTRANS <= 3'b111;
    HBURST <= 2'b11;
    HSIZE <= 3'b111;
    HWRITE <= 1'b0;
    HADDR <= 16'h0000; //HADDR[1:0] have to be 2'b00 ( 4n )
    HWDATA <= 32'h0;

    #51 HRESETn = 1;
    //-------------------------WRITE MEM---------------
    @(posedge HCLK);
    // write control0
    HSEL <= 1;
    HTRANS <= NONSEQ;
    HBURST <= SINGLE;
    HSIZE <= WORD;
    HWRITE <= 1'b1;
    HADDR <= 16'h0000;

    @(posedge HCLK);
    // data0 → mem(0x0000)
    HWDATA <= 32'h11223344;
    // write control 1
    HWRITE <= 1'b1;
    HADDR <= 16'h0004;


    @(posedge HCLK);
    // data1 → mem(0x0004)
    HWDATA <= 32'h55667788;
    // write control 2
    HWRITE <= 1'b1;
    HADDR <= 16'h0008;


    @(posedge HCLK);
    // data2 → mem(0x0008)
    HWDATA <= 32'h99AABBCC;
    //// write control 3
    //HWRITE = 1'b1;
    //HADDR = 16'h000C;

    @(posedge HCLK);
    // data3 → mem(0x000C)
    HWDATA <= 32'hAAAAAAAA;
    // write control 4
    HWRITE <= 1'b1;
    HADDR <= 16'h0010;

    @(posedge HCLK);
    // data4 → mem(0x0010)
    HWDATA <= 32'hBBBBBBBB;
    // write control 5
    HWRITE <= 1'b1;
    HADDR <= 16'h0014;


    @(posedge HCLK);
    // data5 → mem(0x0014)
    HWDATA <= 32'hCCCCCCCC;
    // write control 6
    HWRITE <= 1'b1;
    HADDR <= 16'h8000;

    @(posedge HCLK);
    // data6 → mem(0x8000)
    HWDATA <= 32'hDDDDDDDD;
    // write control 7
    HWRITE <= 1'b1;
    HADDR <= 16'h8004;

    @(posedge HCLK);
    // data7 → mem(0x8004)
    HWDATA <= 32'hEEEEEEEE;
    // write control 8
    HWRITE <= 1'b1;
    HADDR <= 16'h8008;

    @(posedge HCLK);
    // data8 → mem(0x8008)
    HWDATA <= 32'hFFFFFFFF;
    // read control 0
    HWRITE <= 1'b0;
    HADDR <= 16'h0000;

    //--------------READ MEM----------------
    @(posedge HCLK);
    // MASTER FINDS HREADY=0, SO MASTER WAITS

    @(posedge HCLK);
    // read control 1
    HWRITE <= 1'b0;
    HADDR <= 16'h0004;
    HWDATA <= 32'h00000000; // to test if hwdata will work when HWRTIE = 0

    @(posedge HCLK);
    // read control 2
    HWRITE <= 1'b0;
    HADDR <= 16'h0008;

    @(posedge HCLK);
    // read control 3
    HWRITE <= 1'b0;
    HADDR <= 16'h000C;

    @(posedge HCLK);
    // read control 4
    HWRITE <= 1'b0;
    HADDR <= 16'h0010;

    @(posedge HCLK);
    // read control 5
    HWRITE <= 1'b0;
    HADDR <= 16'h0014;

    @(posedge HCLK);
    // read control 6
    HWRITE <= 1'b0;
    HADDR <= 16'h8000;

    @(posedge HCLK);
    // read control 7
    HWRITE <= 1'b0;
    HADDR <= 16'h8004;

    @(posedge HCLK);
    // read control 8
    HWRITE <= 1'b0;
    HADDR <= 16'h8008;

    #100
    $finish();
    end

    endmodule

3.仿真结果

  • AHB interface相关

    image-20241116000137915

  • sram_interface中的控制信号与sram_core interface的对应关系,即AHB接口如何对应到sram_core的接口

    image-20241116000412855

    • HREADY信号之所以要拉低一拍的原因是:由于读数据用的是HADDR地址,而写数据用的是HADDR_r地址,地址其实时在连续输入的,但当由写切换到读状态时,此时虽然读写都使能(读bank0,写bank1),但只有一根地址线,其中bank1 HADDR_r以及对应的HWDATA被写入,而bank0读到的是HADDR_r的数据,并且它此时真正要读的地址HADDR并没有被打1拍缓存(这是由于在设计模块时,设计的就是直接读HADDR而不是HADDR_r),所以在读写切换的时刻到下一个clk这段时间的读地址丢失了,因为此时真正的读HADDR和写HADDR_r同时存在了,但sram_core地址线上选择的是写HADDR_r,这就导致在这一拍的读HADDR没有被采集到,所以才要拉低HREADY告诉master再拉高一次刚刚丢失的读HADDR
  • 其次,在HADDR映射到SRAM_ADDR时,只取了HADDR的$[14:2]$,这样做的原因是:当总线地址HADDR的值在0x0000—0x7FFF之间时代表地址指向BANK0,而在0x8000—0xFFFF之间时代表地址指向BANK1,故HADDR[15]只是用来指示是bank0还是bank1的,又因为每次传输的HSIZE都是32bit(4Byte),故地址只会出现0x0000、0x0004、0x0008、0x000c、0x0010等情况,然后仔细观察一下就会发现,0(0b0000)、4(0b0100)、8(0b1000)、c(0b1100)的低2bit都为0,它们代表的是每4byte的起始地址。可以认为$HADDR[1:0]$代表的是每4byte为一组,这组数据每个字节的索引,而真正每4byte去索引的实际是$HADDR[14:2]$,可以看到前述加粗部分正好是0、1、2、3这样子的index,正好对应SRAM的address。

    1
    2
    3
    4
    5
    6
    // SRAM Addr
    wire [12 : 0] SRAM_WRITE_ADDR;
    wire [12 : 0] SRAM_READ_ADDR;
    assign SRAM_WRITE_ADDR = iHADDR_r[14 : 2]; // WRITE:addr have to wait a T , sent together with data to SRAM_CORE
    assign SRAM_READ_ADDR = iHADDR [14 : 2]; // READ :addr send to MEM at once
    assign oSRAM_ADDR = (iHWRITE_r == 1'b1) ? SRAM_WRITE_ADDR : SRAM_READ_ADDR;

Reference

欢迎来到ssy的世界