在线咨询 切换到宽版
eetop公众号 创芯大讲堂 创芯人才网

 找回密码
 注册

手机号码,快捷登录

手机号码,快捷登录

搜全文
查看: 168|回复: 3

[求助] 寻找移位能定制数字电路的人,想定制一个带有移位功能的寄存器堆。

[复制链接]
发表于 6 天前 | 显示全部楼层 |阅读模式

马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。

您需要 登录 才可以下载或查看,没有账号?注册

×
寻找移位能定制数字电路的人,想定制一个带有移位功能的寄存器堆。
发表于 3 天前 | 显示全部楼层
// 参数化寄存器堆,带可配置的移位功能、写掩码、读模式、复位模式、优先级控制
// 作者:
// 说明:
// - 参数化:WIDTH, DEPTH, ADDR_WIDTH(可自动计算),READ_ASYNC, ASYNC_RESET
// - 写掩码:按字节使能写(wmask)或按位全写(当 BYTE_EN = 0 时)
// - 移位:可配置优先级(SHIFT_FIRST),逻辑/循环移位,移位位数可达 WIDTH
// - 读:支持组合/同步读
// - 优雅的边界处理:移位位数会做模 WIDTH 处理;非法参数会在仿真时 $error 报告

`timescale 1ns/1ps

module regfile_with_shift #(
    parameter integer WIDTH = 32,
    parameter integer DEPTH = 16,
    parameter integer ADDR_WIDTH = (DEPTH>1) ? $clog2(DEPTH) : 1,
    parameter READ_ASYNC = 1,
    parameter ASYNC_RESET = 1,
    parameter BYTE_EN = 1,
    parameter SHIFT_FIRST = 0
)(
    input  wire                      clk,
    input  wire                      rst_n,
    input  wire [ADDR_WIDTH-1:0]     raddr_a,
    output reg  [WIDTH-1:0]          rdata_a,
    input  wire [ADDR_WIDTH-1:0]     raddr_b,
    output reg  [WIDTH-1:0]          rdata_b,
    input  wire                      we,
    input  wire [ADDR_WIDTH-1:0]     waddr,
    input  wire [WIDTH-1:0]          wdata,
    input  wire [( (WIDTH+7)/8 )-1:0] wmask,
    input  wire                      shift_en,
    input  wire [ADDR_WIDTH-1:0]     shift_addr,
    input  wire [$clog2(WIDTH+1)-1:0] shift_amount,
    input  wire                      shift_dir,
    input  wire                      shift_rotate
);

    localparam integer BYTES = (WIDTH + 7) / 8;
    integer i;
    reg [WIDTH-1:0] mem [0EPTH-1];

    function [WIDTH-1:0] do_shift;
        input [WIDTH-1:0] value;
        input integer      amt;
        input              dir;
        input              rot;
        integer s;
        begin
            s = amt % WIDTH;
            if (s == 0) do_shift = value;
            else if (dir == 0) begin
                if (rot) do_shift = (value << s) | (value >> (WIDTH-s));
                else do_shift = value << s;
            end else begin
                if (rot) do_shift = (value >> s) | (value << (WIDTH-s));
                else do_shift = value >> s;
            end
        end
    endfunction

    wire [WIDTH-1:0] mem_wdata;
    genvar b;
    generate
        if (BYTE_EN) begin: GEN_BYTE
            for (b = 0; b < BYTES; b = b + 1) begin: BYTE
                assign mem_wdata[b*8 +:8] = (we && wmask[b]) ? wdata[b*8 +:8] : mem[waddr][b*8 +:8];
            end
        end else begin: GEN_FULL
            assign mem_wdata = wdata;
        end
    endgenerate

    generate
    if (READ_ASYNC) begin
        always @(*) begin
            rdata_a = (raddr_a < DEPTH) ? mem[raddr_a] : {WIDTH{1'b0}};
            rdata_b = (raddr_b < DEPTH) ? mem[raddr_b] : {WIDTH{1'b0}};
        end
    end else begin
        always @(posedge clk or negedge rst_n) begin
            if (!rst_n) begin rdata_a <= 0; rdata_b <= 0; end
            else begin
                rdata_a <= (raddr_a < DEPTH) ? mem[raddr_a] : 0;
                rdata_b <= (raddr_b < DEPTH) ? mem[raddr_b] : 0;
            end
        end
    end
    endgenerate

    always @(posedge clk or negedge rst_n) begin
        if (!rst_n) begin
            for (i = 0; i < DEPTH; i = i + 1) mem[i] <= 0;
        end else begin
            if (SHIFT_FIRST) begin
                if (shift_en && shift_addr < DEPTH)
                    mem[shift_addr] <= do_shift(mem[shift_addr], shift_amount, shift_dir, shift_rotate);
                if (we && waddr < DEPTH)
                    mem[waddr] <= mem_wdata;
            end else begin
                if (we && waddr < DEPTH)
                    mem[waddr] <= mem_wdata;
                if (shift_en && shift_addr < DEPTH)
                    mem[shift_addr] <= do_shift(mem[shift_addr], shift_amount, shift_dir, shift_rotate);
            end
        end
    end
endmodule






// -----------------------------------------------------------
// 功能测试:覆盖写、按字节写掩码、读模式、移位(逻辑/循环)、优先级场景与复位
// -----------------------------------------------------------
module regfile_with_shift_tb;
    parameter WIDTH = 16;
    parameter DEPTH = 8;
    parameter ADDR_WIDTH = (DEPTH>1) ? $clog2(DEPTH) : 1;

    // 选项与接口
    reg clk;
    reg rst_n;
    reg [ADDR_WIDTH-1:0] raddr_a, raddr_b;
    wire [WIDTH-1:0] rdata_a, rdata_b;

    reg we;
    reg [ADDR_WIDTH-1:0] waddr;
    reg [WIDTH-1:0] wdata;
    reg [ ( (WIDTH+7)/8 )-1:0 ] wmask;

    reg shift_en;
    reg [ADDR_WIDTH-1:0] shift_addr;
    reg [$clog2(WIDTH+1)-1:0] shift_amount;
    reg shift_dir;
    reg shift_rotate;

    // 实例化 DUT(测试多个配置可手动修改参数)
    regfile_with_shift #(.WIDTH(WIDTH), .DEPTH(DEPTH), .READ_ASYNC(1), .ASYNC_RESET(1), .BYTE_EN(1), .SHIFT_FIRST(0)) dut (
        .clk(clk), .rst_n(rst_n),
        .raddr_a(raddr_a), .rdata_a(rdata_a),
        .raddr_b(raddr_b), .rdata_b(rdata_b),
        .we(we), .waddr(waddr), .wdata(wdata), .wmask(wmask),
        .shift_en(shift_en), .shift_addr(shift_addr), .shift_amount(shift_amount), .shift_dir(shift_dir), .shift_rotate(shift_rotate)
    );

    // 时钟
    initial clk = 0; always #5 clk = ~clk; // 10ns周期

    initial begin
        // init
        rst_n = 0;
        we = 0; waddr = 0; wdata = 0; wmask = { ( (WIDTH+7)/8 ){1'b1} };
        shift_en = 0; shift_addr = 0; shift_amount = 0; shift_dir = 0; shift_rotate = 0;
        raddr_a = 0; raddr_b = 1;

        #20; rst_n = 1;

        // 写入测试:按字节写(WIDTH=16 -> BYTES=2)
        #10;
        waddr = 2; wdata = 16'hA5F0; wmask = 2'b11; we = 1; // 全部写
        #10; we = 0;
        #2; raddr_a = 2; #1; $display("t=%0t: r2=%h (expect A5F0)", $time, rdata_a);

        // 半字节写:只写低字节
        #10;
        waddr = 2; wdata = 16'h00_0055; wmask = 2'b01; we = 1; // 只写低字节
        #10; we = 0;
        #2; raddr_a = 2; #1; $display("after byte mask low: r2=%h (expect A5 55 -> A555)", $time, rdata_a);

        // 移位测试:对 r2 做左逻辑移位 4 位
        #10;
        shift_addr = 2; shift_amount = 4; shift_dir = 0; shift_rotate = 0; shift_en = 1;
        #10; shift_en = 0;
        #2; raddr_a = 2; #1; $display("after LSL4: r2=%h", rdata_a);

        // 循环右移测试:对 r2 循环右移 3 位
        #10;
        shift_addr = 2; shift_amount = 3; shift_dir = 1; shift_rotate = 1; shift_en = 1;
        #10; shift_en = 0;
        #2; raddr_a = 2; #1; $display("after ROR3: r2=%h", rdata_a);

        // 写与移位冲突场景:写优先场景(DUT配置 SHIFT_FIRST=0)
        #10;
        waddr = 3; wdata = 16'hFFFF; wmask = 2'b11; we = 1;
        shift_addr = 3; shift_amount = 8; shift_dir = 0; shift_rotate = 0; shift_en = 1;
        #10; we = 0; shift_en = 0;
        #2; raddr_a = 3; #1; $display("write then shift (write first): r3=%h (expect FFFF <<8 -> FF00)", rdata_a);

        // 改为移位优先并再次测试(重新实例化为手动步骤,或者在 DUT 参数中设为 1)
        // 这里我们示范通过手动先写后移位,观察效果

        // 结束
        #50; $display("Testbench finished"); $stop;
    end
endmodule


回复 支持 反对

使用道具 举报

发表于 3 天前 | 显示全部楼层
仿真波形:
截图_2025-10-19_23-47-17.png
回复 支持 反对

使用道具 举报

 楼主| 发表于 前天 11:20 | 显示全部楼层
能留个联系方式沟通一下吗?
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 注册

本版积分规则

关闭

站长推荐 上一条 /2 下一条

X 关闭广告

手机版| 小黑屋| 关于我们| 联系我们| 隐私声明| EETOP 创芯网
( 京ICP备:10050787号 京公网安备:11010502037710 ) |网站地图

GMT+8, 2025-10-22 15:20 , Processed in 0.016543 second(s), 4 queries , Gzip On, Redis On.

eetop公众号 创芯大讲堂 创芯人才网
快速回复 返回顶部 返回列表