• 中国科学院大学数字集成电路作业开源——时序逻辑与存储器章节


    中国科学院大学数字集成电路作业开源——第6-8章

    1、基础概念问题

    1.1 请简要描述Mealy状态机与Moore状态机的特性及它们之间的联系?

    Moore状态机:输出仅仅与当前状态有关;

    Mealy状态机:输出不仅取决于当前状态,还和输入有关;

    Mealy和Moore机之间可以相互转化,对于每个Mealy机,都有一个等价的Moore机,Moore机状态的上限为所对应的Mealy机状态的数量和输出数量的乘积。

    1.2 请简要描述SRAM的特点以及实际应用中与寄存器堆逻辑的优缺点比较?

    SRAM的特点是工作速度快,只要电源不撤除,写入SRAM的信息就不会消失,不需要刷新电路,同时在读出时不破坏原来存放的信息,一经写入可多次读出,但集成度较低,功耗较大。

    寄存器堆逻辑实现上更为简单,但性能远不如工艺优化后的SRAM。而SRAM性能虽强,但是实现上略微复杂。

    1.3 请简要描述门控时钟常见电路结构以及适用范围?

    门控时钟电路结构包括直接将控制信号与时钟信号进行与操作(会产生毛刺,因此实际中很少使用)

    img

    基于锁存器的时钟门控方案(常用于ASIC设计)

    img

    基于触发器的时钟门控方案(常用于FPGA设计)

    img

    1.4 请简要描述AHB总线与APB总线的基本特性以及在实际SoC系统中它们的适用场合?

    AHB(Advanced High-performance Bus), 为高速总线,一般用来连接高速外设。APB (Advanced Peripheral Bus) 为低速总线,一般用来接低速外设。

    在SoC系统中,AHB总线会挂载ARM处理器,RAM,DMA控制器等设备,通过AHB2APB Bridge与APB总线连接,APB上挂在UART,Timer等低速设备。

    img

    2 基于Verilog HDL进行逻辑电路设计

    2.1平方根计算

    设计一个时序逻辑电路,计算32位非负整数的平方根。对于输入x,计算y = floor(sqrt(x)),即y是平方后不超过x的最大非负整数。例如:

    l 输入x = 256,输出y = 16

    l 输入x = 255,输出y = 15

    l 输入x = 2147483648,输出y = 46340

    l 输入x = 4294967295,输出y = 65535

    顶层模块名为sqrt_u32,输入输出功能定义:

    名称 方向 位宽 描述
    clk I 1 系统时钟
    rst_n I 1 系统异步复位,低电平有效
    vld_in I 1 输入数据有效指示
    x I 32 输入被开方数据
    vld_out O 1 输出数据有效指示
    y O 16 输出结果数据

    设计要求:

    l Verilog实现代码可综合,给出综合以及仿真结果。

    l 能够处理多组数据输入,且从数据输入到结果输出延迟周期数尽量少。

    设计思路:

    一开始想到的思路是cordic算法或者牛顿迭代法,测试后发现的问题是:对于32位数的输入,cordic算法会存在不能收敛的问题(c语言测试,16次迭代,0-4的输入可以精确的开方,更大的数可以通过归一化然后处理,一直到256都能正确工作,但测试到32位的时候发现数据小的部分已经算不对了,如果非要用cordic的话就得写很复杂的小数位数转换逻辑了,所以我最后还是放弃了)牛顿迭代法中要用到除法,但我不想调用除法器ip,最后采用了逐次逼近法(其实可以理解成逆向的牛顿迭代)

    逐次逼近算法流程如图 所示,首先数据输入data[7:0],接着设置实验值D_z[3:0]和确定值D_q[3:0],然后按照从高往低的顺序,依次将每一位置1(如D_z[3]置1),再将实验值平方后与输入数据比较,若实验值的平方大于输入值(D_z^2 > data),则此位为0(D_q[3]为0),反之(D_z^2 ≤ data)此位为1(D_q[3]为1);以此迭代到最后一位。

    可见,如果是n bit的数据,那么需要n/2次迭代,每次计算如果一个周期,则需要n/2个周期。

    借鉴:https://blog.csdn.net/qq_39507748/article/details/115468883

    img

    代码实现:

    module sqrt_u32 (
        input clk,
        input rst_n,
        input vld_in,
        input [31:0] x,
        output reg vld_out,
        output reg [16:0] y
    );
        parameter d_width = 32;
        parameter q_width = 16;
    
        reg     [d_width-1:0] D     [q_1]; 
        reg     [q_width-1:0] Q_z   [q_1]; 
        reg     [q_width-1:0] Q_q   [q_1]; 
        reg     valid_flag          [q_1]; 
    
        always@(posedge clk or negedge  rst_n)
            begin
                if(!rst_n)
                    begin
                        D[q_width] <= 0;
                        Q_z[q_width] <= 0;
                        Q_q[q_width] <= 0;
                        valid_flag[q_width] <= 0;
                    end
                else if(vld_in)
                    begin
                        D[q_width] <= x; 
                        Q_z[q_width] <= {1'b1,{(q_width-1){1'b0}}}; 
                        Q_q[q_width] <= 0; 
                        valid_flag[q_width] <= 1;
                    end
                else
                    begin
                        D[q_width] <= 0;
                        Q_z[q_width] <= 0;
                        Q_q[q_width] <= 0;
                        valid_flag[q_width] <= 0;
                    end
            end
    
            generate
                genvar i; 
                    for(i=q_width-1;i>=1;i=i-1)
                        begin:U
                            always@(posedge clk or negedge  rst_n)
                                begin
                                    if(!rst_n)
                                        begin
                                            D[i] <= 0;
                                            Q_z[i] <= 0;
                                            Q_q[i] <= 0;
                                            valid_flag[i] <= 0;
                                        end
                                    else    if(valid_flag[i+1])
                                        begin
                                            if(Q_z[i+1]*Q_z[i+1] > D[i+1])
                                                begin
                                                    Q_z[i] <= {Q_q[i+1][q_width-1:i],1'b1,{{i-1}{1'b0}}};
                                                    Q_q[i] <= Q_q[i+1];
                                                end
                                            else
                                                begin
                                                    Q_z[i] <= {Q_z[i+1][q_width-1:i],1'b1,{{i-1}{1'b0}}};
                                                    Q_q[i] <= Q_z[i+1];
                                                end
                                            D[i] <= D[i+1];
                                            valid_flag[i] <= 1;
                                        end
                                    else
                                        begin
                                            valid_flag[i] <= 0;
                                            D[i] <= 0;
                                            Q_q[i] <= 0;
                                            Q_z[i] <= 0;
                                        end
                                end
                        end
            endgenerate
    
            always@(posedge clk or negedge  rst_n) 
                begin
                    if(!rst_n)
                        begin
                            y <= 0;
                            vld_out <= 0;
                        end
                    else    if(valid_flag[1])
                        begin
                            if(Q_z[1]*Q_z[1] > D[1])
                                begin
                                    y <= Q_q[1];
                                    vld_out <= 1;
                                end
                            else
                                begin
                                    y <= {Q_q[1][q_width-1:1],Q_z[1][0]};
                                    vld_out <= 1;
                                end
                        end
                    else
                        begin
                            y <= 0;
                            vld_out <= 0;
                        end
                end
    
    endmodule
    
    

    testbench

    module testbench ();
        
        reg clk,rst_n,vld_in;
        reg [31:0] x;
        wire vld_out;
        wire [15:0] y;
    
        initial begin
            clk <= 1'b0;
            rst_n <= 1'b0;
            vld_in <= 1'b0;
            x <= 0;
            #30
            rst_n <= 1'b1;
            vld_in <= 1'b1;
            x <= 256;
            #20
            x <= 255;
            #20
            x <= 2147483648;
            #20 
            x <= 4294967295;
        end
    
        always #10 clk <= ~clk;
    
        sqrt_u32 u_sqrt_u32(
            .clk(clk),
            .rst_n(rst_n),
            .vld_in(vld_in),
            .x(x),
            .vld_out(vld_out),
            .y(y)
        );
    
    endmodule
    

    仿真结果:

    结果距离输入延迟了16个周期

    img

    img

    输出值

    输入值img

    2.2数据排序

    设计一个时序逻辑电路,对输入32个8位无符号整数从小到大进行排序(若存在多个数据值相等,则不分先后,见例子)。例如:

    l 输入32个数据依次为:31, 29, 27, 25, 23, 21, 19, 17, 15, 13, 11, 9, 7, 5, 3, 1, 2, 2, 4, 4, 4, 4, 8, 16, 8, 16, 32, 32, 0, 10, 20, 30

    l 输出32个数据依次为:0, 1, 2, 2, 3, 4, 4, 4, 4, 5, 7, 8, 8, 9, 10, 11, 13, 15, 16, 16, 17, 19, 20, 21, 23, 25, 27, 29, 30, 31, 32, 32

    顶层模块名为sort_32_u8,输入输出功能定义:

    名称 方向 位宽 描述
    clk I 1 系统时钟
    rst_n I 1 系统异步复位,低电平有效
    vld_in I 1 输入数据有效指示
    din_0, din_1, … …, din_31 I 8 输入数据0,输入数据1,……, 输入数据31
    vld_out O 1 输出数据有效指示
    dout_0, dout_1, … …, dout_31 O 8 输出数据0,输出数据1,……, 输出数据31

    注:din_0 ~ din_31共32个输入端口,dout_0~ dout_31共32个输出端口。输出数据dout_0 ~ dout_31的值从小到大排列。

    设计要求:

    l Verilog实现代码可综合,给出综合以及仿真结果。

    l 逻辑资源和延迟需要做权衡,使得数据输入到结果输出延迟周期数尽量少。

    设计思路:

    原先的思路是使用双调排序,但双调排序只能排单调增和单调减的,题目里面的有重复数的情况调不了。

    采用冒泡排序,导致排序时间非常长,消耗资源比较少,不符合题目要求的延迟尽可能小。本来想再写个全比较排序,但别的作业太多了,姑且算了,其实逻辑也挺简单的。

    冒泡实际上就是两层循环反复比较,循环变量换成计数器就行了,使用了状态机进行控制。

    参考:http://www.manongjc.com/detail/19-ezdqhndvpyqmqjx.html

    代码实现:

    module sort_32_u8 (
        input clk,
        input rst_n,
        input vld_in,
        input [7:0] din_0,din_1,din_2,din_3,din_4,din_5,din_6,din_7,din_8,din_9,din_10,din_11,din_12,din_13,din_14,din_15,din_16,din_17,din_18,din_19,din_20,din_21,din_22,din_23,din_24,din_25,din_26,din_27,din_28,din_29,din_30,din_31,    
        output reg vld_out,
        output [7:0] dout_0,dout_1,dout_2,dout_3,dout_4,dout_5,dout_6,dout_7,dout_8,dout_9,dout_10,dout_11,dout_12,dout_13,dout_14,dout_15,dout_16,dout_17,dout_18,dout_19,dout_20,dout_21,dout_22,dout_23,dout_24,dout_25,dout_26,dout_27,dout_28,dout_29,dout_30,dout_31
    );
    
        parameter s_rst = 2'b00;
        parameter s_load = 2'b01;
        parameter s_sort = 2'b10;
        parameter s_out = 2'b11;
    
        reg [4:0] cnt_i,turn;
        reg [7:0] data_fifo [31:0];
        reg [1:0] cur_state,next_state;
        reg reset,load_data,swap;
    
        always @(posedge clk or negedge rst_n) begin
            if(rst_n == 1'b0) begin
                cur_state <= s_rst;
            end
            else begin
                cur_state <= next_state;
            end
        end
    
        always @(posedge clk) begin
            if(reset == 1'b1) begin
                data_fifo[0]  <= 0;
                data_fifo[1]  <= 0;
                data_fifo[2]  <= 0;
                data_fifo[3]  <= 0;
                data_fifo[4]  <= 0;
                data_fifo[5]  <= 0;
                data_fifo[6]  <= 0;
                data_fifo[7]  <= 0;
                data_fifo[8]  <= 0;
                data_fifo[9]  <= 0;
                data_fifo[10] <= 0;
                data_fifo[11] <= 0;
                data_fifo[12] <= 0;
                data_fifo[13] <= 0;
                data_fifo[14] <= 0;
                data_fifo[15] <= 0;
                data_fifo[16] <= 0;
                data_fifo[17] <= 0;
                data_fifo[18] <= 0;
                data_fifo[19] <= 0;
                data_fifo[20] <= 0;
                data_fifo[21] <= 0;
                data_fifo[22] <= 0;
                data_fifo[23] <= 0;
                data_fifo[24] <= 0;
                data_fifo[25] <= 0;
                data_fifo[26] <= 0;
                data_fifo[27] <= 0;
                data_fifo[28] <= 0;
                data_fifo[29] <= 0;
                data_fifo[30] <= 0;
                data_fifo[31] <= 0;
                turn <= 0;
                cnt_i <= 0;
            end
            else if(load_data == 1'b1) begin
                data_fifo[0]  <=  din_0;
                data_fifo[1]  <=  din_1;
                data_fifo[2]  <=  din_2;
                data_fifo[3]  <=  din_3;
                data_fifo[4]  <=  din_4;
                data_fifo[5]  <=  din_5;
                data_fifo[6]  <=  din_6;
                data_fifo[7]  <=  din_7;
                data_fifo[8]  <=  din_8;
                data_fifo[9]  <=  din_9;
                data_fifo[10] <= din_10;
                data_fifo[11] <= din_11;
                data_fifo[12] <= din_12;
                data_fifo[13] <= din_13;
                data_fifo[14] <= din_14;
                data_fifo[15] <= din_15;
                data_fifo[16] <= din_16;
                data_fifo[17] <= din_17;
                data_fifo[18] <= din_18;
                data_fifo[19] <= din_19;
                data_fifo[20] <= din_20;
                data_fifo[21] <= din_21;
                data_fifo[22] <= din_22;
                data_fifo[23] <= din_23;
                data_fifo[24] <= din_24;
                data_fifo[25] <= din_25;
                data_fifo[26] <= din_26;
                data_fifo[27] <= din_27;
                data_fifo[28] <= din_28;
                data_fifo[29] <= din_29;
                data_fifo[30] <= din_30;
                data_fifo[31] <= din_31;
    
                turn <= 31;
                cnt_i <= 0;
            end
            else if(swap == 1'b1) begin
                if(cnt_i < turn) begin
                    cnt_i <= cnt_i + 1;
                    if(data_fifo[cnt_i+1] < data_fifo[cnt_i]) begin
                        data_fifo[cnt_i+1] <= data_fifo[cnt_i];
                        data_fifo[cnt_i] <= data_fifo[cnt_i+1];
                    end
                end
                else begin
                    cnt_i <= 1;
                    turn <= turn - 1;
                    if(data_fifo[1] < data_fifo[0]) begin
                        data_fifo[1] <= data_fifo[0];
                        data_fifo[0] <= data_fifo[1];
                    end
                end
            end
        end
    
        always @(cnt_i,cur_state,turn,vld_in) begin
            next_state <= s_rst;
            case (cur_state)
                s_rst : begin
                    reset <= 1'b1;
                    vld_out <= 1'b0;
                    next_state <= s_load;
                end 
                s_load : begin
                    reset <= 1'b0;
                    if(vld_in == 1'b1) begin
                        load_data <= 1'b1;
                        vld_out <= 1'b0;
                        next_state <= s_sort;
                    end
                    else begin
                        next_state <= s_load;
                    end
                end
                s_sort : begin
                    swap <= 1'b1;
                    load_data <= 1'b0;
                    if(turn == 1 && cnt_i ==1 ) begin
                        next_state <= s_out;
                        vld_out <= 1'b1;
                    end
                    else begin
                        next_state <= s_sort;
                    end
                end
                s_out : begin
                    next_state <= s_load;
                    swap <= 1'b0;
                end
                default : begin
                    next_state <= s_rst;
                end
            endcase
        end
    
        assign dout_0  =  data_fifo[0];
        assign dout_1  =  data_fifo[1];
        assign dout_2  =  data_fifo[2];
        assign dout_3  =  data_fifo[3];
        assign dout_4  =  data_fifo[4];
        assign dout_5  =  data_fifo[5];
        assign dout_6  =  data_fifo[6];
        assign dout_7  =  data_fifo[7];
        assign dout_8  =  data_fifo[8];
        assign dout_9  =  data_fifo[9];
        assign dout_10 = data_fifo[10];
        assign dout_11 = data_fifo[11];
        assign dout_12 = data_fifo[12];
        assign dout_13 = data_fifo[13];
        assign dout_14 = data_fifo[14];
        assign dout_15 = data_fifo[15];
        assign dout_16 = data_fifo[16];
        assign dout_17 = data_fifo[17];
        assign dout_18 = data_fifo[18];
        assign dout_19 = data_fifo[19];
        assign dout_20 = data_fifo[20];
        assign dout_21 = data_fifo[21];
        assign dout_22 = data_fifo[22];
        assign dout_23 = data_fifo[23];
        assign dout_24 = data_fifo[24];
        assign dout_25 = data_fifo[25];
        assign dout_26 = data_fifo[26];
        assign dout_27 = data_fifo[27];
        assign dout_28 = data_fifo[28];
        assign dout_29 = data_fifo[29];
        assign dout_30 = data_fifo[30];
        assign dout_31 = data_fifo[31];
        
    endmodule
    
    

    testbench

    module testbench ();
        
        reg clk,rst_n,vld_in;
        reg [7:0] din_0,din_1,din_2,din_3,din_4,din_5,din_6,din_7,din_8,din_9,din_10,din_11,din_12,din_13,din_14,din_15,din_16,din_17,din_18,din_19,din_20,din_21,din_22,din_23,din_24,din_25,din_26,din_27,din_28,din_29,din_30,din_31;    
        wire vld_out;
        wire [7:0] dout_0,dout_1,dout_2,dout_3,dout_4,dout_5,dout_6,dout_7,dout_8,dout_9,dout_10,dout_11,dout_12,dout_13,dout_14,dout_15,dout_16,dout_17,dout_18,dout_19,dout_20,dout_21,dout_22,dout_23,dout_24,dout_25,dout_26,dout_27,dout_28,dout_29,dout_30,dout_31;
    
        initial begin
            rst_n <= 1'b0;
            clk <= 1'b0;
            vld_in <= 1'b0;
            din_0  <= 31;
            din_1  <= 29;
            din_2  <= 27;
            din_3  <= 25;
            din_4  <= 23;
            din_5  <= 21;
            din_6  <= 19;
            din_7  <= 17;
            din_8  <= 15;
            din_9  <= 13;
            din_10 <= 11;
            din_11 <= 9;
            din_12 <= 7;
            din_13 <= 5;
            din_14 <= 3;
            din_15 <= 1;
            din_16 <= 2;
            din_17 <= 2;
            din_18 <= 4;
            din_19 <= 4; 
            din_20 <= 4; 
            din_21 <= 4; 
            din_22 <= 8;
            din_23 <= 16;
            din_24 <= 8; 
            din_25 <= 16;
            din_26 <= 32;
            din_27 <= 32;
            din_28 <= 0; 
            din_29 <= 10;
            din_30 <= 20;
            din_31 <= 30;
            #30
            rst_n <= 1'b1;
            vld_in <= 1'b1;
            #20
            vld_in <= 1'b0;
        end
    
        always #10 clk <= ~clk;
    
        sort_32_u8 u_sort(
            clk,
            rst_n,
            vld_in,
            din_0,din_1,din_2,din_3,din_4,din_5,din_6,din_7,din_8,din_9,din_10,din_11,din_12,din_13,din_14,din_15,din_16,din_17,din_18,din_19,din_20,din_21,din_22,din_23,din_24,din_25,din_26,din_27,din_28,din_29,din_30,din_31,
            vld_out,
            dout_0,dout_1,dout_2,dout_3,dout_4,dout_5,dout_6,dout_7,dout_8,dout_9,dout_10,dout_11,dout_12,dout_13,dout_14,dout_15,dout_16,dout_17,dout_18,dout_19,dout_20,dout_21,dout_22,dout_23,dout_24,dout_25,dout_26,dout_27,dout_28,dout_29,dout_30,dout_31
        );
    
    endmodule
    

    仿真结果:

    花了将近500个周期排序(真的太慢了,我选算法的没注意到要求延迟周期尽可能少)

    dout_15到dout_31

    img

    dout_0到dout_19

    img

    2.3 矩阵扫描

    如图所示,ZigZag扫描就是将8x8的矩阵块按照箭头运动方向重新排列(从1开始到64结束):

    img


    设计一个时序逻辑电路,对输入64个整数(按照行优先方式构成8x8的矩阵块)按照ZigZag扫描方式依次输出。例如:

    l 输入64个数据依次为:1, 2, 3, 4, ..., 61, 62, 63, 64

    l 输出64个数据依次为:1, 2, 9, 17, 10, 3, ..., 62, 55, 48, 56, 63, 64

    顶层模块名为mat_scan,输入输出功能定义:

    名称 方向 位宽 描述
    clk I 1 系统时钟
    rst_n I 1 系统异步复位,低电平有效
    vld_in I 1 输入数据有效指示
    din I 10 输入数据
    vld_out O 1 输出数据有效指示
    dout O 10 输出数据

    注:每组输入数据连续64个周期输入,即vld_in连续64个时钟周期有效;每组输出数据连续64个周期输出,即vld_out连续64个时钟周期有效。

    设计要求:

    l Verilog实现代码可综合,给出综合以及仿真结果。

    l 使用SRAM缓存输入数据,SRAM使用bit数尽量少。

    l 从数据输入到结果输出延迟周期数尽量少。

    设计思路:

    用sram存64个数,输入的时候地址顺序增加,读出的时候用状态机实现zigzag要求的顺序对应的地址变化。(我查了一下zigzag自动扫描的c语言实现,感觉在verilog里面实现太困难,所以就这样暴力解决了)

    代码实现:

    module mat_scan (
        input clk,
        input rst_n,
        input vld_in,
        input [9:0] din,
        output reg vld_out,
        output [9:0] dout
    );
    
        reg cs_n, w_en, r_en;
        reg [5:0] addr;
    
        always @(posedge clk or negedge rst_n) begin
            if (rst_n == 1'b0) begin
                addr <= 6'b11_1111;
                cs_n <= 1'b1;
                w_en <= 1'b0;
                r_en <= 1'b0;
                vld_out <= 1'b0;
            end
            else if (vld_in) begin
                w_en <= 1'b1;
                cs_n <= 1'b0;
                addr <= addr + 1'b1;
            end
            else begin
                vld_out <= 1'b1;
                r_en <= 1'b1;
                case (addr)
                    6'b11_1111 : addr <= 6'b00_0000;
                    6'b00_0000 : addr <= 6'b00_0001;
                    6'b00_0001 : addr <= 6'b00_1000;
                    6'b00_1000 : addr <= 6'b01_0000;
                    6'b01_0000 : addr <= 6'b00_1001;
                    6'b00_1001 : addr <= 6'b00_0010;
                    6'b00_0010 : addr <= 6'b00_0011;
                    6'b00_0011 : addr <= 6'b00_1010;
                    6'b00_1010 : addr <= 6'b01_0001;
                    6'b01_0001 : addr <= 6'b01_1000;
                    6'b01_1000 : addr <= 6'b10_0000;
                    6'b10_0000 : addr <= 6'b01_1001;
                    6'b01_1001 : addr <= 6'b01_0010;
                    6'b01_0010 : addr <= 6'b00_1011;
                    6'b00_1011 : addr <= 6'b00_0100;
                    6'b00_0100 : addr <= 6'b00_0101;
                    6'b00_0101 : addr <= 6'b00_1100;
                    6'b00_1100 : addr <= 6'b01_0011;
                    6'b01_0011 : addr <= 6'b01_1010;
                    6'b01_1010 : addr <= 6'b10_0001;
                    6'b10_0001 : addr <= 6'b10_1000;
                    6'b10_1000 : addr <= 6'b11_0000;
                    6'b11_0000 : addr <= 6'b10_1001;
                    6'b10_1001 : addr <= 6'b10_0010;
                    6'b10_0010 : addr <= 6'b01_1011;
                    6'b01_1011 : addr <= 6'b01_0100;
                    6'b01_0100 : addr <= 6'b00_1101;
                    6'b00_1101 : addr <= 6'b00_0110;
                    6'b00_0110 : addr <= 6'b00_0111;
                    6'b00_0111 : addr <= 6'b00_1110;
                    6'b00_1110 : addr <= 6'b01_0101;
                    6'b01_0101 : addr <= 6'b01_1100;
                    6'b01_1100 : addr <= 6'b10_0011;
                    6'b10_0011 : addr <= 6'b10_1010;
                    6'b10_1010 : addr <= 6'b11_0001;
                    6'b11_0001 : addr <= 6'b11_1000;
                    6'b11_1000 : addr <= 6'b11_1001;
                    6'b11_1001 : addr <= 6'b11_0010;
                    6'b11_0010 : addr <= 6'b10_1011;
                    6'b10_1011 : addr <= 6'b10_0100;
                    6'b10_0100 : addr <= 6'b01_1101;
                    6'b01_1101 : addr <= 6'b01_0110;
                    6'b01_0110 : addr <= 6'b00_1111;
                    6'b00_1111 : addr <= 6'b01_0111;
                    6'b01_0111 : addr <= 6'b01_1110;
                    6'b01_1110 : addr <= 6'b10_0101;
                    6'b10_0101 : addr <= 6'b10_1100;
                    6'b10_1100 : addr <= 6'b11_0011;
                    6'b11_0011 : addr <= 6'b11_1010;
                    6'b11_1010 : addr <= 6'b11_1011;
                    6'b11_1011 : addr <= 6'b11_0100;
                    6'b11_0100 : addr <= 6'b10_1101;
                    6'b10_1101 : addr <= 6'b10_0110;
                    6'b10_0110 : addr <= 6'b01_1111;
                    6'b01_1111 : addr <= 6'b10_0111;
                    6'b10_0111 : addr <= 6'b10_1110;
                    6'b10_1110 : addr <= 6'b11_0101;
                    6'b11_0101 : addr <= 6'b11_1100;
                    6'b11_1100 : addr <= 6'b11_1101;
                    6'b11_1101 : addr <= 6'b11_0110;
                    6'b11_0110 : addr <= 6'b10_1111;
                    6'b10_1111 : addr <= 6'b11_0111;
                    6'b11_0111 : addr <= 6'b11_1110;
                    6'b11_1110 : addr <= 6'b11_1111;
                endcase
            end
        end
    
        sram #(
            .ADDR_DEPTH(6),
            .DATA_WIDTH(10),
            .DATA_DEPTH(64)
        ) u_sram (
            .clk(clk),
            .rst_n(rst_n),
            .cs_n(cs_n),
            .w_en(w_en),
            .r_en(r_en),
            .addr(addr),
            .din(din),
            .dout(dout)
        );
    
    endmodule
    
    

    sram

    module sram #(
        parameter ADDR_DEPTH = 4,
        parameter DATA_WIDTH = 8,
        parameter DATA_DEPTH = 16
    )(
        input clk,
        input rst_n,
        input cs_n,
        input w_en,
        input r_en,
        input [ADDR_DEPTH-1:0] addr,
        input [DATA_WIDTH-1:0] din,
        output reg [DATA_WIDTH-1:0] dout
    );
        
        reg [DATA_WIDTH-1:0] mem [DATA_DEPTH-1:0];
        integer i;
    
        always @(posedge clk or negedge rst_n) begin
            if (rst_n == 1'b0) begin
                for (i = 0; i < DATA_DEPTH; i=i+1) begin
                    mem[i] <= (1'b0 << (DATA_WIDTH-1));
                end
            end
            else if (w_en == 1'b1 && cs_n == 1'b0) begin
                mem[addr] <= din;
            end
        end
    
        always @(posedge clk or negedge rst_n) begin
            if (rst_n == 1'b0) begin
                dout <= (1'b0 << (DATA_WIDTH-1));
            end
            else if (r_en == 1'b1 && cs_n == 1'b0) begin
                dout <= mem[addr];
            end
            else begin
                dout <= dout;
            end
        end
    
    endmodule
    
    

    testbench

    module testbench ();
        reg clk, rst_n, vld_in;
        reg [9:0] din;
        wire vld_out;
        wire [9:0] dout;
    
        initial begin
            clk <= 1'b0;
            rst_n <= 1'b0;
            din <= 10'b00_0000_0000;
            vld_in <= 1'b0;
            #20
            rst_n <= 1'b1;
            vld_in <= 1'b1;
            #1290
            vld_in <= 1'b0;
        end
    
        always #10 clk <= ~clk;
    
        always @(posedge clk) begin
            if (vld_in == 1'b1) begin
               din <= din + 1'b1;
            end
        end
    
        mat_scan u_mat_scan(
            .clk(clk),
            .rst_n(rst_n),
            .vld_in(vld_in),
            .din(din),
            .vld_out(vld_out),
            .dout(dout)
        );
    
    endmodule
    

    仿真结果:

    先顺序递增的将1-64放到SRAM里面去

    img

    输出的地址用状态机实现,从而搞定zigzag扫描

    img

    img

    2.4 AHB-SRAM控制器

    设计一个基于AHB从接口的单端口SRAM控制器,实现SRAM存储器与AHB总线的数据信息交换,将AHB总线上的读写操作转换成标准SRAM读写操作。

    SRAM大小为4096x32-bit,AHB接口数据大小固定为32-bit,AHB接口地址范围为0x00000000 – 0x00003FFC。AHB接口能够实现单次或突发模式的数据读写操作。

    顶层模块名为sram_ctr_ahb,输入输出功能定义:

    名称 方向 位宽 描述
    hclk I 1 系统时钟
    hresetn I 1 系统异步复位,低电平有效
    hwrite I 1 写有效
    htrans I 2 当前传输类型
    hsize I 3 当前传输大小
    haddr I 32 读写地址
    hburst I 3 当前突发类型
    hwdata I 32 写数据
    hready O 1 传输完成指示
    hresp O 2 传输响应
    hrdata O 32 读数据
    sram_csn O 1 SRAM片选,低电平有效
    sram_wen O 1 SRAM写使能,低电平有效
    sram_a O 12 SRAM读写地址
    sram_d O 32 SRAM写数据
    sram_q I 32 SRAM读数据

    注:仿真时SRAM时钟与hclk相同,SRAM可以用FPGA的单端口SRAM IP核仿真模型或者使用单端口SRAM行为级模型代替。

    设计要求:

    设计要求:

    l Verilog实现代码可综合,给出综合以及仿真结果。

    仿真时应给出各种典型情况下的数据读写接口信号波形。

    设计思路:

    作为实际设计并跑过完整ARM SoC的人,我觉得其实这里的输入激励应该由一个ARM CPU或者别的CPU来生成,但是没有这个条件就只能手写了。

    在我做ARM SoC时,一个经验之谈是给ARM核写代码的时候(C语言),经常int_8/uint_8,int_16/uint_16或者int_32/int_32这些声明了位宽的变量

    例如当时写的外设的寄存器表(基地址+偏移量)

    img

    所以很现实的就是存储器的hsize要支持8位,16位和32位(更大的我写的时候没用到)

    一个我想多数人意识不到的问题是CPU访存是以字节(Byte)为单位的,即8bit。所以如果存储器的数据宽度和总线宽度对齐,是32位的话,就必须得考虑访存地址在haddr上左移的问题。如果直接是32位的访存,那么haddr就必须左移两位,16位的访存就得左移一位,8位不用移位。或者就是直接用8位宽度的存储器,如果要32位数的话就连续读4个数出来放到总线上,16位数就连续读2个数放到总线上。我用了前者(32位宽的存储器)

    代码实现:

    module sram_ctr_ahb (
        input hclk,
        input hresetn,
        input hwrite,
        input [1:0] htrans,
        input [2:0] hsize,
        input [31:0] haddr,
        input [2:0] hburst,
        input [31:0] hwdata,
        output reg hready,
        output reg [1:0] hresp,
        output reg [31:0] hrdata,
        output reg sram_csn,
        output reg sram_wen,
        output reg [11:0] sram_a,
        output reg [31:0] sram_d,
        input [31:0] sram_q
    );
    
        reg [31:0] hwdata_mask;
    
        always @(posedge hclk or negedge hresetn) begin
            if(hresetn == 1'b0) begin
                hwdata_mask <= 0;
                hready <= 1'b1;
                hresp <= 2'b0;
                hrdata <= 0;
                sram_csn <= 1'b0;
                sram_wen <= 1'b0;
                sram_a <= 0;
                sram_d <= 0;
            end
            else begin
                sram_wen <= hwrite & htrans[1];
                sram_a <= haddr[13:2];
            end
        end
    
        always @(posedge hclk or negedge hresetn) begin
             if(hresetn == 1'b0) begin
                hrdata <= 0;
                sram_d <= 0;
            end
            else begin
                case (hsize[1:0])
                    2'b10: hwdata_mask <=  32'hFFFFFFFF;                        // Word write
                    2'b01: hwdata_mask <= (32'h0000FFFF << (16 * haddr[1]));    // Halfword write
                    2'b00: hwdata_mask <= (32'h000000FF << (8 * haddr[1:0]));   // Byte write
                    default: hwdata_mask <= 32'hFFFFFFFF;            
                endcase
                sram_d <= (hwdata & hwdata_mask) | (hrdata & ~hwdata_mask);
                hrdata <= sram_q;
            end
        end
    
    endmodule
    
    

    sram

    module sram #(
        parameter ADDR_DEPTH = 4,
        parameter DATA_WIDTH = 8,
        parameter DATA_DEPTH = 16
    )(
        input clk,
        input rst_n,
        input cs_n,
        input w_en,
        input [ADDR_DEPTH-1:0] addr,
        input [DATA_WIDTH-1:0] din,
        output reg [DATA_WIDTH-1:0] dout
    );
        
        reg [DATA_WIDTH-1:0] mem [DATA_DEPTH-1:0];
        integer i;
    
        always @(posedge clk or negedge rst_n) begin
            if (rst_n == 1'b0) begin
                for (i = 0; i < DATA_DEPTH; i=i+1) begin
                    mem[i] <= (1'b0 << (DATA_WIDTH-1));
                end
            end
            else if (w_en == 1'b1 && cs_n == 1'b0) begin
                mem[addr] <= din;
            end
        end
    
        always @(posedge clk or negedge rst_n) begin
            if (rst_n == 1'b0) begin
                dout <= (1'b0 << (DATA_WIDTH-1));
            end
            else if (cs_n == 1'b0) begin
                dout <= mem[addr];
            end
        end
    
    endmodule
    
    

    testbench

    module testbench ();
        
        reg hclk;
        reg hresetn;
        reg hwrite;
        reg [1:0] htrans;
        reg [2:0] hsize;
        reg [31:0] haddr;
        reg [2:0] hburst;
        reg [31:0] hwdata;
        wire hready;
        wire [1:0] hresp;
        wire [31:0] hrdata;
        wire sram_csn;
        wire sram_wen;
        wire [11:0] sram_a;
        wire [31:0] sram_d;
        wire [31:0] sram_q;
    
        initial begin
            hclk <= 1'b0;
            hresetn <= 1'b0;
            hwrite <= 1'b0;
            htrans <= 2'b00;
            hsize <= 3'b000;
            haddr <= 32'h00000000;
            hburst <= 3'b000;
            hwdata <= 32'h00000000;
            #20
            hresetn <= 1'b1;
            hwrite <= 1'b1;
            htrans <= 2'b10;
            hsize <= 3'b010;
            #20
            haddr <= 32'hfffffffc;
            hwdata <= 32'h20211212;
            #20
            hsize <= 3'b001;
            haddr <= 32'hfffffffE;
            hwdata <= 32'habcd0000;
            #20
            hsize <= 3'b000;
            haddr <= 32'hffffffff;
            hwdata <= 32'h59000000;
            #20
            hwrite <= 1'b0;
        end
    
        always #10 hclk <= ~hclk;
    
        sram_ctr_ahb u_sram_ctrl_ahb(
            .hclk(hclk),
            .hresetn(hresetn),
            .hwrite(hwrite),
            .htrans(htrans),
            .hsize(hsize),
            .haddr(haddr),
            .hburst(hburst),
            .hwdata(hwdata),
            .hready(hready),
            .hresp(hresp),
            .hrdata(hrdata),
            .sram_csn(sram_csn),
            .sram_wen(sram_wen),
            .sram_a(sram_a),
            .sram_d(sram_d),
            .sram_q(sram_q)
        );
    
        sram #(
            .ADDR_DEPTH(12),
            .DATA_WIDTH(32),
            .DATA_DEPTH(4096)
        ) u_sram (
            .clk(hclk),
            .rst_n(hresetn),
            .cs_n(sram_csn),
            .w_en(sram_wen),
            .addr(sram_a),
            .din(sram_d),
            .dout(sram_q)
        );
    
    endmodule
    

    仿真结果:

    写三个数(hwdata)(位宽不同),地址分别是fffffffc,fffffffe,ffffffff

    img

    单口sram,sram_wen取消后开始读这三个数(hrdata)

    img

  • 相关阅读:
    第 12 章 Docker Swarm
    第 1 章 虚拟化
    第 0 章 写在最前面
    第 11 章 日志管理
    第 11 章 日志管理
    第 11 章 日志管理
    第 11 章 日志管理
    第 11 章 日志管理
    第 11 章 日志管理
    第 11 章 日志管理
  • 原文地址:https://www.cnblogs.com/sasasatori/p/15887797.html
Copyright © 2020-2023  润新知