Verilog设计实例(3)基于Verilog的单端口同步读写RAM设计

写在前面


为什么要写单端口同步读写RAM呢?

没有那么多为什么?就是因为简单、基础,能清晰说明单端口RAM的原理,顺手给出设计,也能说明你的设计基础,作为专题Verilog设计实例中的一员,单端口RAM必然上榜了!

曾经也写过很多类似的博文,在博客首页搜索即可,给出搜索链接:

RAM相关博客

博客首页

好了,那我们开始正文吧。

正文


电路设计

设计代码:

`timescale 1ns / 1ps

// Engineer: Reborn Lee
// Module Name: single_port_syn_ram


module single_port_syn_ram#(
	parameter ADDR_WIDTH = 4,
	parameter DATA_WIDTH = 16,
	parameter DEPTH = 2**ADDR_WIDTH
	)(
	input  i_clk,
	input [ADDR_WIDTH - 1 : 0] addr,
	inout [DATA_WIDTH - 1 : 0] data,
	input cs,
	input wr,
	input oe

    );

    reg [DATA_WIDTH - 1 : 0] mem[0 : DEPTH - 1];
    reg [DATA_WIDTH - 1 : 0] mid_data;

	// write part
	always@(posedge i_clk) begin
		if(cs&wr) begin
			mem[addr] <= data;
		end
	end

	// read part
	always@(posedge i_clk) begin
		if(cs & !wr) begin
			mid_data <= mem[addr];
		end
	end

	assign data = (cs & oe & !wr)? mid_data: 'hz;

endmodule

代码简介

这段代码需要说明的就是这么一句:

	reg [DATA_WIDTH - 1 : 0] mid_data;
	//......
	assign data = (cs & oe & !wr)? mid_data: 'hz;

由于RAM的数据总线是inout类型:

	inout [DATA_WIDTH - 1 : 0] data,

由于才用的是同步读,因此读数据肯定是一个时序电路的行为,也即在always块内进行:

	// read part
	always@(posedge i_clk) begin
		if(cs & !wr) begin
			mid_data <= mem[addr];
		end
	end

inout 类型的端口,不能放入always块内,因此需要一个中间寄存器来过渡;当读使能oe有效时,读出数据放入中间寄存器mid_data中,之后在通过assign连接到inout端口上;如果读使能无效,则将高阻态赋值给inout端口,意味着这里不做处理(悬空),而在其他地方处理,例如作为输入数据写入RAM。
这是因为读使能无效时,应该处于写的状态,写的话需要将该端口总线上的数据data写入RAM:

// write part
	always@(posedge i_clk) begin
		if(cs&wr) begin
			mem[addr] <= data;
		end
	end

此时这个端口作为输入使用的。

总之,这样的处理很关键!

行为仿真

测试文件可以写的很简单,也可以写的稍微复杂点,本文做简单测试:

Testbench设计:

`timescale 1ns / 1ps

// Engineer: Reborn Lee
// Module Name: ram_tb



module ram_tb(

    );

	parameter ADDR_WIDTH = 4;
	parameter DATA_WIDTH = 16;
	parameter DEPTH = 2**ADDR_WIDTH;

	reg i_clk;
	reg [ADDR_WIDTH - 1 : 0] addr;
	wire [DATA_WIDTH - 1 : 0] data;
	reg cs;
	reg wr;
	reg oe;

	reg [DATA_WIDTH-1:0] tb_data;

	//generate system clock
	initial begin
		i_clk = 0;
		forever begin
			# 5 i_clk = ~i_clk;
		end
	end

	assign data = !oe ? tb_data : 'hz;

	initial begin
    {cs, wr, addr, tb_data, oe} = 0;
 
    repeat (2) @ (posedge i_clk);

    //write test
 
    for (integer i = 0; i < 2**ADDR_WIDTH; i= i+1) begin
      repeat (1) @(negedge i_clk) addr = i; wr = 1; cs =1; oe = 0; tb_data = $random;
    end

    //read test
    repeat (2) @ (posedge i_clk);
 
    for (integer i = 0; i < 2**ADDR_WIDTH; i= i+1) begin
      repeat (1) @(posedge i_clk) addr = i; wr = 0; cs = 1; oe = 1;
    end
 
    #20 $finish;
  end

	single_port_syn_ram #(
			.ADDR_WIDTH(ADDR_WIDTH),
			.DATA_WIDTH(DATA_WIDTH),
			.DEPTH(DEPTH)
		) inst_single_port_syn_ram (
			.i_clk (i_clk),
			.addr  (addr),
			.data  (data),
			.cs    (cs),
			.wr    (wr),
			.oe    (oe)
		);

endmodule

注意事项

  • 第一:inout类型的端口,声明为wire;
	wire [DATA_WIDTH - 1 : 0] data;
  • 第二 :在写数据的时候,需要定义中间寄存器 tb_data;
	reg [DATA_WIDTH-1:0] tb_data;
  • 第三:对第二条的解释是,简单来说是因为initial是一个过程块,需要写的数据不可能直接赋值给wire类型的data,需要中间过渡:
	assign data = !oe ? tb_data : 'hz;
  • 第四:注意到下面这条语句了吗?在下降沿给数据以及给地址,这样可以保证数据在上升沿时刻写入RAM;且写入数据为随机数:
//write test
 
    for (integer i = 0; i < 2**ADDR_WIDTH; i= i+1) begin
      repeat (1) @(negedge i_clk) addr = i; wr = 1; cs =1; oe = 0; tb_data = $random;
    end
  • 第五:大家一定要学会这种测试文件的写法,严格控制写入多少个周期或数据,以及读出多少个数据。

仿真波形

写有效:
在这里插入图片描述

读数据:

在这里插入图片描述

交个朋友

个人微信公众号:FPGA LAB,二维码,左下角;
知乎:李锐博恩,二维码右下角。
在这里插入图片描述

FPGA/IC技术交流2020

  • 7
    点赞
  • 51
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 2
    评论
### 回答1: 好的,我可以用中文回答您关于 Verilog HDL 程序设计实例的问题。 Verilog HDL 是一种硬件描述语言,常用于设计数字电路和系统。下面是一个简Verilog HDL 实例,实现一个 4 位加法器。 ``` module adder4 (a, b, cin, sum, cout); input [3:0] a; input [3:0] b; input cin; output [3:0] sum; output cout; wire [3:0] c; wire [3:0] x; assign x = a ^ b; assign c[0] = cin; assign c[1:3] = x[0:2] & (a[1:3] ^ b[1:3]) | a[0:2] & b[0:2]; assign sum = x ^ c; assign cout = c[3]; endmodule ``` 这个加法器有 5 个端口,分别是 `a`、`b`、`cin`、`sum` 和 `cout`。其中 `a` 和 `b` 是两个加数,`cin` 是进位标志,`sum` 是和,`cout` 是进位输出。 在模块内部,我们定义了两个线路 `c` 和 `x`,分别表示进位和异或的结果。然后使用 assign 语句对这些线路进行赋值,得到加法器的输出。最后将这些输出连接到模块的端口上。 这个 Verilog HDL 程序实现了一个简的 4 位加法器,您可以根据需要进行修改和扩展。 ### 回答2: Verilog HDL是一种硬件描述语言,可以用于设计数字电路和系统,包括模拟、综合、仿真和验证。以下是Verilog HDL程序设计实例。 1. D触发器 D触发器是一种基本的数字逻辑器件,用于存储个比特的信息,并在时钟信号的上升沿或下降沿时将其传输。以下是一个D触发器的Verilog HDL代码: module d_ff (input D, CLK, output reg Q); always @(posedge CLK) begin Q <= D; end endmodule 在上述代码中,input D指定D触发器的输入,CLK指定时钟信号的输入,output reg Q指定触发器的输出。始终块使用posedge CLK,也就是时钟信号的上升沿来传输输入值。当时钟信号上升沿到达时,Q被赋值为输入D。 2. 多路选择器 多路选择器是一种用于在多个输入中选择一个输出的数字逻辑器件。以下是一个4:1多路选择器的Verilog HDL代码: module mux_4to1 (input [3:0] IN, input [1:0] SEL, output reg OUT); always @(*) begin case (SEL) 2'b00: OUT <= IN[0]; 2'b01: OUT <= IN[1]; 2'b10: OUT <= IN[2]; 2'b11: OUT <= IN[3]; endcase end endmodule 在上述代码中,input [3:0] IN指定4个输入,input [1:0] SEL指定选择器输入,output reg OUT指定选择器输出。始终块使用case语句,根据SEL的值选择一个输入并将其传递给输出。 3. 加法器 加法器是一种数字逻辑器件,用于执行加法运算。以下是一个4位加法器的Verilog HDL代码: module adder_4bit (input [3:0] A, B, input CIN, output [3:0] SUM, output COUT); assign SUM = A + B + CIN; assign COUT = ((A + B + CIN) > 4'b1111) ? 1'b1 : 1'b0; endmodule 在上述代码中,input [3:0] A, B指定加法器的2个输入,input CIN指定进位输入,output [3:0] SUM指定和输出,output COUT指定进位输出。使用assign语句,将输入与进位相加并将结果赋给SUM,同时计算出COUT的值。 以上是三个常见的Verilog HDL程序设计实例,它们展示了Verilog HDL的核心语法,可以用于设计各种数字电路和系统。 ### 回答3: Verilog HDL是一种硬件描述语言,用于设计数字电路。它与VHDL类似,被广泛应用于芯片设计、系统设计和电路测试等领域。在本文中,我们将介绍一个Verilog HDL程序设计实例,以帮助初学者更好地理解和掌握Verilog HDL的基础知识。 本例子描述的是一个简的两个输入和逻辑门(And Gate)电路设计。And门接收两个输入信号A和B,并将它们进行逻辑“与”运算。当A和B都为1时,输出信号Y为1,否则为0。 下面是Verilog HDL程序设计的步骤: 1. 首先,我们需要定义输入和输出信号的端口,以便与其他电路连接。在这个例子中,我们定义了两个输入端口A和B,一个输出端口Y,如下所示: module and_gate( input A, input B, output Y ); 2. 接下来,我们需要定义And门的行为规则。在这个例子中,And门的行为规则是将输入信号A和B进行逻辑与操作,并将结果赋值给输出信号Y。如下所示: assign Y = A & B; 3. 最后,我们需要将设计代码进行编译和仿真。编译可以用Verilog编译器进行,可以生成一个.bin文件作为仿真的输入文件。仿真可以用VCS等仿真工具进行。以下是编译和仿真的命令示例: // 编译代码 $ vcs -sverilog and_gate.v // 运行仿真 $ ./simv 通过上述步骤,我们就完成了一个简的And门电路的Verilog HDL设计。这个例子虽然简,但是涉及到了Verilog HDL的一些基本概念,包括模块定义、输入输出端口、行为规则和仿真等。初学者可以通过不断练习类似的例子,逐步掌握Verilog HDL的语法和应用。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

李锐博恩

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值