一、找到源代码的定义
MultiWidthFifo
的源代码定义如下:
class MultiWidthFifo(inW: Int, outW: Int, n: Int) extends Module {
val io = new Bundle {
val in = Decoupled(Bits(width = inW)).flip
val out = Decoupled(Bits(width = outW))
val count = UInt(OUTPUT, log2Up(n + 1))
}
其中:
- •
inW
:输入数据的宽度; - •
outW
:输出数据的宽度; - •
n
:FIFO的深度(针对inW来说的);
二、生成Verilog代码
在diplomacy_final/src/main/scala/empty
目录下创建一个MultiWidthFifo.scala
的文件,内容如下:
package empty
import chisel3._
import chisel3.util._
import freechips.rocketchip.util._
object MultiWidthFIFOMain extends App {
println("Generating the MultiWidthFIFO hardware")
val inputWidth = 16;
val outputWidth = 32;
val deepth = 8
emitVerilog(new MultiWidthFifo(inputWidth, outputWidth, deepth), Array("--target-dir", "generated"))
}
上述代码中:
- •
import freechips.rocketchip.util._
导入了util
文件夹中的所有模块,包括MultiWidthFifo
模块; - • 设置了输入数据宽度为16,输出数据宽度为32;深度为8;
- •
emitVerilog
用于生成Verilog代码;
在deiplomacy_final
的根目录下,执行:
sbt "run empty.MultiWidthFIFOMain"
#可能会出现多个选项,按对应的数字键进行选择,例如:
Multiple main classes detected. Select one to run:
[1] empty.AddMain
[2] empty.AxiMain
[3] empty.MultiWidthFIFOMain
Enter number:
第一次编译执行需要下载很多东西,需要较长的时间。执行成功之后,**在仓库根目录的generated
目录下会出现对应的Verilog文件MultiWidthFifo.v
**,内容如下所示:
module MultiWidthFifo(
input clock,
input reset,
output io_in_ready,
input io_in_valid,
input [15:0] io_in_bits,
input io_out_ready,
output io_out_valid,
output [31:0] io_out_bits,
output [3:0] io_count
);
…
endmodule
三、仿真测试
搭建一个简单的环境,代码如下:
module tb();
/*AUTOREGINPUT*/
// Beginning of automatic reg inputs (for undeclared instantiated-module inputs)
reg [15:0] io_in_bits; // To u_MultiWidthFifo of MultiWidthFifo.v
reg io_in_valid; // To u_MultiWidthFifo of MultiWidthFifo.v
reg io_out_ready; // To u_MultiWidthFifo of MultiWidthFifo.v
// End of automatics
/*AUTOWIRE*/
// Beginning of automatic wires (for undeclared instantiated-module outputs)
wire clk; // From u_clk_gen of clk_gen.v
wire [3:0] io_count; // From u_MultiWidthFifo of MultiWidthFifo.v
wire io_in_ready; // From u_MultiWidthFifo of MultiWidthFifo.v
wire [31:0] io_out_bits; // From u_MultiWidthFifo of MultiWidthFifo.v
wire io_out_valid; // From u_MultiWidthFifo of MultiWidthFifo.v
wire rst_n; // From u_rst_gen of rst_gen.v
wire rst_p; // From u_rst_gen of rst_gen.v
// End of automatics
/* MultiWidthFifo AUTO_TEMPLATE (
.reset(rst_p),
.clock(clk),
);
*/
MultiWidthFifo u_MultiWidthFifo(/*autoinst*/
// Outputs
.io_in_ready (io_in_ready),
.io_out_valid (io_out_valid),
.io_out_bits (io_out_bits[31:0]),
.io_count (io_count[3:0]),
// Inputs
.clock (clk), // Templated
.reset (rst_p), // Templated
.io_in_valid (io_in_valid),
.io_in_bits (io_in_bits[15:0]),
.io_out_ready (io_out_ready));
clk_gen u_clk_gen (
/*AUTOINST*/
// Outputs
.clk (clk));
rst_gen u_rst_gen (
/*AUTOINST*/
// Outputs
.rst_n (rst_n),
.rst_p (rst_p));
dump dump ();
reg [15:0] cnt;
initial begin
// initial input signals
io_in_bits = ‘d0;
io_in_valid = ‘d0;
io_out_ready = ‘d1;
cnt = ‘d1;
wait(!rst_p);
repeat(4) begin
send_data(cnt);
cnt = cnt + 1;
end
end
task send_data;
input [15:0] data;
begin
@(posedge clk);
io_in_bits = data;
io_in_valid = 1’d1;
@(posedge clk);
io_in_valid = 1’d0;
end
endtask
endmodule
// Local Variables:
// verilog-library-directories:(“.” “../../” )
// End:
产生了如下图所示的波形:
可以看出:
- • 输入端口:
- •
io_in_ready
用于控制FIFO在有足够的数据时,是否输出32bit数据,为1表示输出; - •
io_in_valid
和io_in_bits
用于输入数据,这里输入了4个数据,依次为16'd1, 16'd2, 16'd3, 16'd4
;
- •
- • 输出端口:
- •
io_out_valid
用于指示输出的32bit数据有效; - •
io_out_bits
用于输出32bit数据;图中可以看出,由于我们一直将io_in_ready拉高,所以每当有2个16bit数据输入时,都会输出一个32bit的数据; - •
io_count
用于输出FIFO中当前可用的32bit数据的数量;
- •
可以看出,通过使用RocketChip中的IP,可以避免自己编写一些常见的模块。对于学生朋友的一些工作可能有些帮助。
虽然这些IP模块可能在Vivado等官方工具中存在,但是这些厂商的IP核一般不能在不同厂商的FPGA之间使用,所以使用这些开源的代码可以避免平台依赖的问题。
后续将介绍更复杂的IP核的生成,例如AXICrossbar。
没有回复内容