当前位置: 首页 > news >正文

数字ic笔试

编写一个单端口 RAM 模块,深度 256、宽度 16bit。

// File: spram_256x16.v
// 单端口 RAM:深度 256、宽度 16bit
// 接口:同步写、同步读(posedge clk)
module spram_256x16 (input  wire        clk,       // 时钟input  wire        we,        // 写使能:1=写入input  wire [7:0]  addr,      // 地址(0~255)input  wire [15:0] din,       // 写数据output reg  [15:0] dout       // 读数据
);// 声明存储体:256 x 16reg [15:0] mem [0:255];// 同步读 & 写(read-first:读优先/旧数据)always @(posedge clk) begin// 先读dout <= mem[addr];// 后写if (we) beginmem[addr] <= din;endendendmodule

上面写法是“读优先(read-first)”:同一拍对同一地址又读又写时,dout 输出的是写入前的旧数据。很多 FPGA/综合器都能据此推断出单端口 Block RAM

TB

// File: tb_spram_256x16.v
`timescale 1ns/1psmodule tb_spram_256x16;reg         clk;reg         we;reg  [7:0]  addr;reg  [15:0] din;wire [15:0] dout;// DUTspram_256x16 dut (.clk (clk),.we  (we),.addr(addr),.din (din),.dout(dout));// 10ns 时钟initial beginclk = 0;forever #5 clk = ~clk;end// 激励initial beginwe   = 0; addr = 0; din = 16'h0000;@(negedge clk);// 写:addr=8'h12 <= 16'hABCDaddr = 8'h12; din = 16'hABCD; we = 1;@(negedge clk);// 停止写we = 0;@(negedge clk);// 读同一地址(同步读,数据在下一个 posedge 后出现在 dout)addr = 8'h12;@(negedge clk);@(negedge clk);$display("Read @0x12 = 0x%h (expect 0xABCD)", dout);// 冲突场景:同拍读写同址,观察 read-first 行为addr = 8'h34; din = 16'h1234; we = 1;  // 写 0x34@(negedge clk);we = 0;@(negedge clk);// 此时已有 0x1234,演示同拍读写addr = 8'h34; din = 16'h5678; we = 1; // 同拍对同址读写@(negedge clk);we = 0;@(negedge clk);$display("Conflict read-first: dout(old)=0x%h (上一拍), mem(new)=0x5678", dout);$finish;end
endmodule

可参数化

如果想展示工程化能力,可把宽度/深度写成参数:

module spram #(parameter AW = 8,            // Address width -> depth = 2^AWparameter DW = 16
)(input  wire           clk,input  wire           we,input  wire [AW-1:0]  addr,input  wire [DW-1:0]  din,output reg  [DW-1:0]  dout
);reg [DW-1:0] mem [0:(1<<AW)-1];always @(posedge clk) begindout <= mem[addr];if (we) mem[addr] <= din;end
endmodule

实现一个 3 级流水线的 16 位加法器

把 16 位分成 5/5/6 位 三段,段与段之间插入寄存器;把进位在段间传递,同时把较低位的部分和用寄存器“对齐”到最后一级再拼接输出。(3 级流水、吞吐 1/cycle,时延 3 cycles)

// File: pipelined_adder16_3stage.v
// 3 级流水 16 位加法器:吞吐=1/cycle,时延=3 cycles
module pipelined_adder16_3stage (input  wire        clk,input  wire        rst_n,       // 同步低有效复位input  wire        valid_in,    // 输入有效input  wire [15:0] a,input  wire [15:0] b,output reg         valid_out,   // 输出有效(=valid_in 延后 3 拍)output reg  [15:0] sum,output reg         cout         // 最高位进位(可选)
);// -------- Stage 0: 低 5 位相加 --------wire [4:0] a0 = a[4:0];wire [4:0] b0 = b[4:0];wire [5:0] add0 = a0 + b0;      // {c0, s0}wire       c0   = add0[5];wire [4:0] s0   = add0[4:0];// 把中/高位在 S0 注册,供后续级使用reg [4:0] a1_r, b1_r;           // 位[9:5]reg [5:0] a2_r1, b2_r1;         // 位[15:10]// 把 S0 的部分和/进位沿流水线对齐reg [4:0] s0_r1, s0_r2;         // s0 需要延两拍到 S2reg       c0_r1;                // 传给下一段reg       vld_r1, vld_r2, vld_r3;// -------- Stage 1: 中 5 位 + c0 --------wire [5:0] add1 = a1_r + b1_r + c0_r1;  // {c1, s1}wire       c1   = add1[5];wire [4:0] s1   = add1[4:0];// 对齐 s1 到 S2reg [4:0] s1_r1;// 把高位在 S1 再注册一次,供 S2 使用reg [5:0] a2_r2, b2_r2;reg       c1_r1;// -------- Stage 2: 高 6 位 + c1 --------wire [6:0] add2 = a2_r2 + b2_r2 + c1_r1;  // {c2, s2}wire       c2   = add2[6];wire [5:0] s2   = add2[5:0];// --------- 时序寄存器 ---------always @(posedge clk) beginif (!rst_n) begin// 复位流水线有效位vld_r1   <= 1'b0; vld_r2 <= 1'b0; vld_r3 <= 1'b0;sum      <= 16'd0; cout   <= 1'b0; valid_out <= 1'b0;// 其它寄存器清零(可省略,视项目复位策略而定)a1_r<=0; b1_r<=0; a2_r1<=0; b2_r1<=0;s0_r1<=0; s0_r2<=0; c0_r1<=0; s1_r1<=0; a2_r2<=0; b2_r2<=0; c1_r1<=0;end else begin// ---------- Stage0 寄存 ----------a1_r   <= a[9:5];b1_r   <= b[9:5];a2_r1  <= a[15:10];b2_r1  <= b[15:10];s0_r1  <= s0;c0_r1  <= c0;vld_r1 <= valid_in;// ---------- Stage1 寄存 ----------s0_r2  <= s0_r1;   // s0 再对齐一拍s1_r1  <= s1;      // s1 对齐到下一级a2_r2  <= a2_r1;   // 把高位继续传递b2_r2  <= b2_r1;c1_r1  <= c1;vld_r2 <= vld_r1;// ---------- Stage2 输出 ----------sum      <= {s2, s1_r1, s0_r2}; // 6 + 5 + 5 = 16cout     <= c2;valid_out<= vld_r2; // 输出有效(延后 3 拍)vld_r3   <= vld_r2; // 供需要更深对齐时使用(可删)endend
endmodule

行为说明

  • 段宽划分:5/5/6(也可 4/6/6 或 8/4/4,根据时序压力选择)。

  • 吞吐量:每拍接受一组 (a,b)

  • 时延valid_out 相比 valid_in 延后 3 个时钟

  • 同周期多组数据互不干扰,因为每级都有寄存器。

  • cout 是 17 位和的最高位,是否需要由题目决定(这里给出,便于完整性)。

TB

// File: tb_pipelined_adder16_3stage.v
`timescale 1ns/1ps
module tb_pipelined_adder16_3stage;reg         clk, rst_n;reg         valid_in;reg  [15:0] a, b;wire        valid_out;wire [15:0] sum;wire        cout;pipelined_adder16_3stage dut (.clk(clk), .rst_n(rst_n),.valid_in(valid_in), .a(a), .b(b),.valid_out(valid_out), .sum(sum), .cout(cout));// 时钟initial begin clk=0; forever #5 clk=~clk; end// 激励integer i;initial beginrst_n = 0; valid_in = 0; a=0; b=0;repeat(3) @(posedge clk);rst_n = 1;// 连续喂入 10 组随机数据,验证吞吐=1/cyclefor (i=0; i<10; i=i+1) begin@(posedge clk);valid_in <= 1;a <= $random; b <= $random;end@(posedge clk) valid_in <= 0;// 观察 valid_out 与 sum(延后 3 拍)repeat(10) @(posedge clk);$finish;end// 参考结果对比(可选)reg [16:0] golden [0:31];// 也可以在 testbench 里排队比对 sum==a+b(注意延 3 拍)
endmodule

  

http://www.dtcms.com/a/390070.html

相关文章:

  • 武汉火影数字|数字展厅设计制作:多媒体数字内容打造
  • LLM模型的参数量估计
  • STM32H743-学习HAL库
  • 一键防范假票入账-发票识别接口-发票查验接口-信息提取
  • RTEMS 控制台驱动
  • flutter在列表页面中通过监听列表滑动偏移量控制页面中某个控件的透明度
  • linux上升级nginx版本
  • WINCC结构变量/公共弹窗
  • 信息化项目验收计划方案书
  • 1.数据库概述和三种主要控制语言
  • 找到nohup启动的程序并杀死
  • 电磁干扰EMI (Electromagnetic Interference)是什么?
  • python提取域名
  • PR工具timing report中setup time的计算过程
  • 低延迟垃圾收集器:挑战“不可能三角”
  • 【测试】发版测试准入准出标准
  • 第一部分:HTML
  • 贪心算法应用:带权任务间隔调度问题详解
  • 视频监控大数据建模分析
  • IP的重要性
  • 远程访问管理爱快路由器
  • 算法 --- 优先级队列(堆)
  • Kindle出现电池感叹号图标和黄灯闪烁怎么办?
  • 摄像头模块在无人机上的应用
  • 深度学习篇GRU---LSTM和RNN的折中方案
  • Doris聚合表和物化视图选型对比
  • 互补色颜色对应的RGB
  • Python定义UDS诊断服务(8):SecurityAccess(0x27)
  • 第1节 工具(剪映剪映小助手)准备及安装(Coze扣子空间剪映小助手教程)
  • 大模型提示词Prompt工程:1-万能公式-完整指南