简单的实例
一、APB3
简介
该例子将会展示定义APB3类的语句。
规范
ARM关于APB3的端口规范如下:
信号名称 | 类型 | 驱动端 | 描述 |
---|---|---|---|
PADDR | UInt(位宽 bits) | Master | 字节为单位的地址 |
PSEL | Bits(selWidth) | Master | 每个从端1bit |
PENABLE | Bool | Master | |
PWRITE | Bool | Master | |
PWDATA | Bits(dataWidth bits) | Master | |
PREADY | Bool | Slave | |
PRDATA | Bits(dataWidth bits) | Slave | |
PSLVERROR | Bool | Slave | 可选 |
- 实现
上述规范说明APB3总线有许多可能的配置。为了实现多样的配置,我们可以在Scala中定义一个配置类:
case class Apb3Config(
addressWidth : Int,
dataWidth : Int,
selWidth : Int = 1,
useSlaveError : Boolean = true
)
随后我们可以定义用来表示硬件总线的APB3类:
case class Apb3(config: Apb3Config) extends Bundle with IMasterSlave {
val PADDR = UInt(config.addressWidth bits)
val PSEL = Bits(config.selWidth bits)
val PENABLE = Bool()
val PREADY = Bool()
val PWRITE = Bool()
val PWDATA = Bits(config.dataWidth bits)
val PRDATA = Bits(config.dataWidth bits)
val PSLVERROR = if(config.useSlaveError) Bool else null
override def asMaster(): Unit = {
out(PADDR,PSEL,PENABLE,PWRITE,PWDATA)
in(PREADY,PRDATA)
if(config.useSlaveError) in(PSLVERROR)
}
}
应用(Usage)
val apbConfig = Apb3Config( addressWidth = 16, dataWidth = 32, selWidth = 1, useSlaveError = false ) val io = new Bundle{ val apb = slave(Apb3(apbConfig)) } io.apb.PREADY := True when(io.apb.PSEL(0) && io.apb.PENABLE){ //... }
上述代码比较简陋,个人编写了一个简单的APB3的Slave端总线挂一个寄存堆的代码,如下:
package Apb3 import spinal.core._ import spinal.lib._ // 使用IMasterSlave需要调用lib库 import scala.math._ class Apb3Slave extends Component{ case class APB3Config(addressWidth: Int, dataWidth: Int, selWidth : Int, useSlaveError : Boolean) // APB3总线的参数配置 case class APB3 (val config: APB3Config) extends Bundle with IMasterSlave { val PADDR = UInt(config.addressWidth bits) val PSEL = Bits(config.selWidth bits) val PENABLE = Bool val PREADY = Bool val PWRITE = Bool val PWDATA = Bits(config.dataWidth bits) val PRDATA = Bits(config.dataWidth bits) val PSLVERROR = if(config.useSlaveError) Bool() else null // 只有当配置中的useSlaveError为真时才生成该端口 override def asMaster() : Unit = { out(PADDR,PSEL,PENABLE,PWRITE,PWDATA) in(PREADY,PRDATA) if(config.useSlaveError) in(PSLVERROR) } // 使用asMaster的好处在于,asSlave直接就默认是Master端口的反面 } val apbConfig = APB3Config(addressWidth = 4,dataWidth = 32,selWidth = 1,useSlaveError = false) // 用户配置参数 val io = new Bundle{ val slaveBus = slave(APB3(apbConfig)) // 定义总线的slave端 //val masterBus = master(APB3(apbConfig))// 定义总线的master端,不知道为何,用asMater定义,无法使用io.masterBus.PADDR表述 } io.slaveBus.PREADY := True val num = pow(2, io.slaveBus.config.addressWidth) val mem = Mem(Bits(io.slaveBus.config.dataWidth bits), num.toInt) mem.write( enable = io.slaveBus.PSEL(0) && io.slaveBus.PWRITE, address = io.slaveBus.PADDR, data = io.slaveBus.PWDATA ) io.slaveBus.PRDATA := mem.readSync( enable = io.slaveBus.PSEL(0) && io.slaveBus.PENABLE, address = io.slaveBus.PADDR ) } object Apb3SlaveInst { def main(args: Array[String]) { SpinalVerilog(new Apb3Slave) } }
生成的Verilog代码为:
// Generator : SpinalHDL v1.6.0 git head : 73c8d8e2b86b45646e9d0b2e729291f2b65e6be3 // Component : Apb3Slave module Apb3Slave ( input [3:0] io_slaveBus_PADDR, input [0:0] io_slaveBus_PSEL, input io_slaveBus_PENABLE, output io_slaveBus_PREADY, input io_slaveBus_PWRITE, input [31:0] io_slaveBus_PWDATA, output [31:0] io_slaveBus_PRDATA, input clk, input reset ); reg [31:0] _zz_mem_port1; wire _zz_mem_port; wire _zz_io_slaveBus_PRDATA; reg [31:0] mem [0:15]; assign _zz_mem_port = (io_slaveBus_PSEL[0] && io_slaveBus_PWRITE); always @(posedge clk) begin if(_zz_mem_port) begin mem[io_slaveBus_PADDR] <= io_slaveBus_PWDATA; end end always @(posedge clk) begin if(_zz_io_slaveBus_PRDATA) begin _zz_mem_port1 <= mem[io_slaveBus_PADDR]; end end assign io_slaveBus_PREADY = 1'b1; assign _zz_io_slaveBus_PRDATA = (io_slaveBus_PSEL[0] && io_slaveBus_PENABLE); assign io_slaveBus_PRDATA = _zz_mem_port1; endmodule
二、进位加法器(Carry Adder)
该示例定义了一个具有输入a
和b
以及result
输出的组件。在任何时候,结果都是a
和b
(组合逻辑)的和。这个求和是由进位加法器完成的。
class CarryAdder(size : Int) extends Component{
val io = new Bundle{
val a = in UInt(size bits)
val b = in UInt(size bits)
val result = out UInt(size bits) //result = a + b
}
var c = False //Carry, like a VHDL variable
for (i <- 0 until size) {
//Create some intermediate value in the loop scope.
val a = io.a(i)
val b = io.b(i)
//The carry adder's asynchronous logic
io.result(i) := a ^ b ^ c
c \= (a & b) | (a & c) | (b & c); //variable assignment
}
}
object CarryAdderProject {
def main(args: Array[String]) {
SpinalVhdl(new CarryAdder(4))
}
}
会生成如下代码:
// Generator : SpinalHDL v1.6.0 git head : 73c8d8e2b86b45646e9d0b2e729291f2b65e6be3
// Component : CarryAdder
module CarryAdder (
input [3:0] io_a,
input [3:0] io_b,
output reg [3:0] io_result
);
reg c_4;
reg c_3;
reg c_2;
reg c_1;
wire c;
wire _zz_c_1;
wire _zz_c_1_1;
wire _zz_c_2;
wire _zz_c_2_1;
wire _zz_c_3;
wire _zz_c_3_1;
wire _zz_c_4;
wire _zz_c_4_1;
always @(*) begin
c_4 = c_3;
c_4 = (((_zz_c_4 && _zz_c_4_1) || (_zz_c_4 && c_3)) || (_zz_c_4_1 && c_3));
end
always @(*) begin
c_3 = c_2;
c_3 = (((_zz_c_3 && _zz_c_3_1) || (_zz_c_3 && c_2)) || (_zz_c_3_1 && c_2));
end
always @(*) begin
c_2 = c_1;
c_2 = (((_zz_c_2 && _zz_c_2_1) || (_zz_c_2 && c_1)) || (_zz_c_2_1 && c_1));
end
always @(*) begin
c_1 = c;
c_1 = (((_zz_c_1 && _zz_c_1_1) || (_zz_c_1 && c)) || (_zz_c_1_1 && c));
end
assign c = 1'b0;
assign _zz_c_1 = io_a[0];
assign _zz_c_1_1 = io_b[0];
always @(*) begin
io_result[0] = ((_zz_c_1 ^ _zz_c_1_1) ^ c);
io_result[1] = ((_zz_c_2 ^ _zz_c_2_1) ^ c_1);
io_result[2] = ((_zz_c_3 ^ _zz_c_3_1) ^ c_2);
io_result[3] = ((_zz_c_4 ^ _zz_c_4_1) ^ c_3);
end
assign _zz_c_2 = io_a[1];
assign _zz_c_2_1 = io_b[1];
assign _zz_c_3 = io_a[2];
assign _zz_c_3_1 = io_b[2];
assign _zz_c_4 = io_a[3];
assign _zz_c_4_1 = io_b[3];
endmodule
三、颜色求和(Color Summing)
首先,定义一个带有加法的Color Bundle
。
case class Color(channelWidth: Int) extends Bundle {
val r = UInt(channelWidth bits)
val g = UInt(channelWidth bits)
val b = UInt(channelWidth bits)
def +(that: Color): Color = {
val result = Color(channelWidth)
result.r := this.r + that.r
result.g := this.g + that.g
result.b := this.b + that.b
return result
}
def clear(): Color ={
this.r := 0
this.g := 0
this.b := 0
this
}
}
然后,定义一个带source
输入(颜色向量)和输出result
(source
输入之和)的组件。
class ColorSumming(sourceCount: Int, channelWidth: Int) extends Component {
val io = new Bundle {
val sources = in Vec(Color(channelWidth), sourceCount)
val result = out(Color(channelWidth))
}
var sum = Color(channelWidth)
sum.clear()
for (i <- 0 to sourceCount - 1) {
sum \= sum + io.sources(i)
}
io.result := sum
}
总的SpinalHDL代码为:
package ColorSumming
import spinal.core._
import spinal.lib._
case class Color(channelWidth: Int) extends Bundle {
val r = UInt(channelWidth bits)
val g = UInt(channelWidth bits)
val b = UInt(channelWidth bits)
def +(that: Color): Color = {
val result = Color(channelWidth)
result.r := this.r + that.r
result.g := this.g + that.g
result.b := this.b + that.b
return result
}
def clear(): Color ={
this.r := 0
this.g := 0
this.b := 0
this
}
}
class ColorSumming(sourceCount: Int, channelWidth: Int) extends Component {
val io = new Bundle {
val sources = in Vec(Color(channelWidth), sourceCount)
val result = out(Color(channelWidth))
}
var sum = Color(channelWidth)
sum.clear()
for (i <- 0 to sourceCount - 1) {
sum \= sum + io.sources(i)
}
io.result := sum
}
object ColorSummingInst {
def main(args: Array[String]) {
SpinalVerilog(new ColorSumming(3, 4))
}
}
生成的Verilog代码为:
// Generator : SpinalHDL v1.6.0 git head : 73c8d8e2b86b45646e9d0b2e729291f2b65e6be3
// Component : ColorSumming
module ColorSumming (
input [3:0] io_sources_0_r,
input [3:0] io_sources_0_g,
input [3:0] io_sources_0_b,
input [3:0] io_sources_1_r,
input [3:0] io_sources_1_g,
input [3:0] io_sources_1_b,
input [3:0] io_sources_2_r,
input [3:0] io_sources_2_g,
input [3:0] io_sources_2_b,
output [3:0] io_result_r,
output [3:0] io_result_g,
output [3:0] io_result_b
);
reg [3:0] _zz_io_result_r;
reg [3:0] _zz_io_result_g;
reg [3:0] _zz_io_result_b;
reg [3:0] _zz_io_result_r_1;
reg [3:0] _zz_io_result_g_1;
reg [3:0] _zz_io_result_b_1;
reg [3:0] _zz_io_result_r_2;
reg [3:0] _zz_io_result_g_2;
reg [3:0] _zz_io_result_b_2;
wire [3:0] sum_r;
wire [3:0] sum_g;
wire [3:0] sum_b;
always @(*) begin
_zz_io_result_r = _zz_io_result_r_1;
_zz_io_result_r = (_zz_io_result_r_1 + io_sources_2_r);
end
always @(*) begin
_zz_io_result_g = _zz_io_result_g_1;
_zz_io_result_g = (_zz_io_result_g_1 + io_sources_2_g);
end
always @(*) begin
_zz_io_result_b = _zz_io_result_b_1;
_zz_io_result_b = (_zz_io_result_b_1 + io_sources_2_b);
end
always @(*) begin
_zz_io_result_r_1 = _zz_io_result_r_2;
_zz_io_result_r_1 = (_zz_io_result_r_2 + io_sources_1_r);
end
always @(*) begin
_zz_io_result_g_1 = _zz_io_result_g_2;
_zz_io_result_g_1 = (_zz_io_result_g_2 + io_sources_1_g);
end
always @(*) begin
_zz_io_result_b_1 = _zz_io_result_b_2;
_zz_io_result_b_1 = (_zz_io_result_b_2 + io_sources_1_b);
end
always @(*) begin
_zz_io_result_r_2 = sum_r;
_zz_io_result_r_2 = (sum_r + io_sources_0_r);
end
always @(*) begin
_zz_io_result_g_2 = sum_g;
_zz_io_result_g_2 = (sum_g + io_sources_0_g);
end
always @(*) begin
_zz_io_result_b_2 = sum_b;
_zz_io_result_b_2 = (sum_b + io_sources_0_b);
end
assign sum_r = 4'b0000;
assign sum_g = 4'b0000;
assign sum_b = 4'b0000;
assign io_result_r = _zz_io_result_r;
assign io_result_g = _zz_io_result_g;
assign io_result_b = _zz_io_result_b;
endmodule
四、带清除的计数器(Counter with clear)
本例定义了一个具有clear
输入和value
输出的组件。每个时钟周期输出的value
都是递增的,但是当clear
值很高时,value
被清除。
class Counter(width : Int) extends Component{
val io = new Bundle{
val clear = in Bool()
val value = out UInt(width bits)
}
val register = Reg(UInt(width bits)) init(0)
register := register + 1
when(io.clear){
register := 0
}
io.value := register
}
五、锁相环黑盒与复位控制器(PLL BlackBox and reset controller)
假设用户需要定义一个TopLevel
组件来例化一个PLLBlackBox
,并且利用它建立一个新的时钟域应用到设计中。同时用户可能需要将外部的异步复位逻辑应用到该时钟域中,与一个同步复位资源连接。
本小章中需要导入如下库:
import spinal.core._
import spinal.lib._
锁相环黑盒定义(The PLL BlackBox definition)
下述代码展示了如何定义锁相环
BlackBox
:class PLL extends BlackBox{ val io = new Bundle{ val clkIn = in Bool() val clkOut = out Bool() val isLocked = out Bool() } noIoPrefix() }
其会生成如下VHDL代码:
component PLL is port( clkIn : in std_logic; clkOut : out std_logic; isLocked : out std_logic ); end component;
顶层定义(TopLevel definition)
下述例子展示了如何定义个人的
TopLevel
来例化锁相环,建立新clockdomain
并且将异步复位的输入连接至同步复位端口:class TopLevel extends Component{ val io = new Bundle { val aReset = in Bool() val clk100Mhz = in Bool() val result = out UInt(4 bits) } // 创建一个Area来管理所有时钟和复位 val clkCtrl = new Area { //例化并驱动PLL val pll = new PLL pll.io.clkIn := io.clk100Mhz //建立新时钟域'core' val coreClockDomain = ClockDomain.internal( name = "core", frequency = FixedFrequency(200 MHz) // 该频率要求可以被使用 ) // 通过coreClockDomain用户来做某些计算 //驱动coreClockDomain的时钟和复位 coreClockDomain.clock := pll.io.clkOut coreClockDomain.reset := ResetCtrl.asyncAssertSyncDeassert( input = io.aReset || ! pll.io.isLocked, clockDomain = coreClockDomain ) } //建立clkCtrl.coreClockDomain下的ClockingArea val core = new ClockingArea(clkCtrl.coreClockDomain){ val counter = Reg(UInt(4 bits)) init(0) counter := counter + 1 io.result := counter } }
会生成如下Verilog代码:
// Generator : SpinalHDL v1.6.0 git head : 73c8d8e2b86b45646e9d0b2e729291f2b65e6be3 // Component : MyTopLevel module MyTopLevel ( input io_aReset, input io_clk100Mhz, output [3:0] io_result ); wire clkCtrl_pll_clkOut; wire clkCtrl_pll_isLocked; wire bufferCC_1_io_dataOut; wire core_clk; wire core_reset; wire _zz_1; reg [3:0] core_counter; PLL clkCtrl_pll ( .clkIn (io_clk100Mhz ), //i .clkOut (clkCtrl_pll_clkOut ), //o .isLocked (clkCtrl_pll_isLocked ) //o ); BufferCC bufferCC_1 ( .io_dataIn (1'b0 ), //i .io_dataOut (bufferCC_1_io_dataOut ), //o .core_clk (core_clk ), //i ._zz_1 (_zz_1 ) //i ); assign core_clk = clkCtrl_pll_clkOut; assign _zz_1 = (io_aReset || (! clkCtrl_pll_isLocked)); assign core_reset = bufferCC_1_io_dataOut; assign io_result = core_counter; always @(posedge core_clk or posedge core_reset) begin if(core_reset) begin core_counter <= 4'b0000; end else begin core_counter <= (core_counter + 4'b0001); end end endmodule module BufferCC ( input io_dataIn, output io_dataOut, input core_clk, input _zz_1 ); (* async_reg = "true" *) reg buffers_0; (* async_reg = "true" *) reg buffers_1; assign io_dataOut = buffers_1; always @(posedge core_clk or posedge _zz_1) begin if(_zz_1) begin buffers_0 <= 1'b1; buffers_1 <= 1'b1; end else begin buffers_0 <= io_dataIn; buffers_1 <= buffers_0; end end endmodule
六、RGB转灰度图
假设要建立一个可以将RGB图转化成灰度图并存到外部Memory的组件。
IO名称 | 方向 | 描述 |
---|---|---|
clear | in | 清除所有内部寄存器 |
r,g,b | in | 颜色输入 |
wr | out | 写存储 |
address | out | 存储地址,每周期增加 |
data | out | 存储数据,灰度等级 |
class RgbToGray extends Component{
val io = new Bundle{
val clear = in Bool()
val r,g,b = in UInt(8 bits)
val wr = out Bool()
val address = out UInt(16 bits)
val data = out UInt(8 bits)
}
def coef(value : UInt,by : Float) : UInt = (value * U((255*by).toInt,8 bits) >> 8)
val gray = RegNext(
coef(io.r,0.3f) +
coef(io.g,0.4f) +
coef(io.b,0.3f)
)
val address = CounterFreeRun(stateCount = 1 << 16)
io.address := address
io.wr := True
io.data := gray
when(io.clear){
gray := 0
address.clear()
io.wr := False
}
}
生成的Verilog如下:
// Generator : SpinalHDL v1.6.0 git head : 73c8d8e2b86b45646e9d0b2e729291f2b65e6be3
// Component : RgbToGray
module RgbToGray (
input io_clear,
input [7:0] io_r,
input [7:0] io_g,
input [7:0] io_b,
output reg io_wr,
output [15:0] io_address,
output [7:0] io_data,
input clk,
input reset
);
wire [7:0] _zz_gray;
wire [7:0] _zz_gray_1;
wire [15:0] _zz_gray_2;
wire [7:0] _zz_gray_3;
wire [15:0] _zz_gray_4;
wire [7:0] _zz_gray_5;
wire [15:0] _zz_gray_6;
wire [15:0] _zz_address_valueNext;
wire [0:0] _zz_address_valueNext_1;
reg [7:0] gray;
wire address_willIncrement;
reg address_willClear;
reg [15:0] address_valueNext;
reg [15:0] address_value;
wire address_willOverflowIfInc;
wire address_willOverflow;
assign _zz_gray = (_zz_gray_1 + _zz_gray_3);
assign _zz_gray_1 = (_zz_gray_2 >>> 8);
assign _zz_gray_2 = (io_r * 8'h4c);
assign _zz_gray_3 = (_zz_gray_4 >>> 8);
assign _zz_gray_4 = (io_g * 8'h66);
assign _zz_gray_5 = (_zz_gray_6 >>> 8);
assign _zz_gray_6 = (io_b * 8'h4c);
assign _zz_address_valueNext_1 = address_willIncrement;
assign _zz_address_valueNext = {15'd0, _zz_address_valueNext_1};
always @(*) begin
address_willClear = 1'b0;
if(io_clear) begin
address_willClear = 1'b1;
end
end
assign address_willOverflowIfInc = (address_value == 16'hffff);
assign address_willOverflow = (address_willOverflowIfInc && address_willIncrement);
always @(*) begin
address_valueNext = (address_value + _zz_address_valueNext);
if(address_willClear) begin
address_valueNext = 16'h0;
end
end
assign address_willIncrement = 1'b1;
assign io_address = address_value;
always @(*) begin
io_wr = 1'b1;
if(io_clear) begin
io_wr = 1'b0;
end
end
assign io_data = gray;
always @(posedge clk) begin
gray <= (_zz_gray + _zz_gray_5);
if(io_clear) begin
gray <= 8'h0;
end
end
always @(posedge clk or posedge reset) begin
if(reset) begin
address_value <= 16'h0;
end else begin
address_value <= address_valueNext;
end
end
endmodule
七、正弦ROM(Sinus rom)
假设用户需要生成一个正弦波以及其滤波后的形式。
参数名称 | 类型 | 描述 |
---|---|---|
resolutionWidth | Int | 表述数值的比特位宽 |
sampleCount | Int | 一个正弦周期的采样点数 |
IO名称 | 方向 | 类型 | 描述 |
---|---|---|---|
sin | out | SInt(resolutionWidth bits) | 描述正弦波的输出 |
sinFiltred | out | SInt(resolutionWidth bits) | 描述滤波后正弦波的输出 |
定义一个Component
class TopLevel(resolutionWidth : Int,sampleCount : Int) extends Component {
val io = new Bundle {
val sin = out SInt(resolutionWidth bits)
val sinFiltred = out SInt(resolutionWidth bits)
}
// 这里写逻辑实现
}
为了在sin
输出端口输出正弦波,需要定义一个包含了正弦波一个周期内所有采样点的ROM。随后可以利用相位计数器读取ROM并生成正弦波。
//定义生成ROM的函数
def sinTable = for(sampleIndex <- 0 until sampleCount) yield {
val sinValue = Math.sin(2 * Math.PI * sampleIndex / sampleCount)
S((sinValue * ((1<<resolutionWidth)/2-1)).toInt,resolutionWidth bits)
}
val rom = Mem(SInt(resolutionWidth bits),initialContent = sinTable)
val phase = Reg(UInt(log2Up(sampleCount) bits)) init(0)
phase := phase + 1
io.sin := rom.readSync(phase)
随后生成sinFiltered
,例如可以使用一个一阶低通滤波器:
io.sinFiltred := RegNext(io.sinFiltred - (io.sinFiltred >> 5) + (io.sin >> 5)) init(0)
完整代码如下:
class TopLevel(resolutionWidth : Int,sampleCount : Int) extends Component {
val io = new Bundle {
val sin = out SInt(resolutionWidth bits)
val sinFiltred = out SInt(resolutionWidth bits)
}
def sinTable = for(sampleIndex <- 0 until sampleCount) yield {
val sinValue = Math.sin(2 * Math.PI * sampleIndex / sampleCount)
S((sinValue * ((1<<resolutionWidth)/2-1)).toInt,resolutionWidth bits)
}
val rom = Mem(SInt(resolutionWidth bits),initialContent = sinTable)
val phase = Reg(UInt(log2Up(sampleCount) bits)) init(0)
phase := phase + 1
io.sin := rom.readSync(phase)
io.sinFiltred := RegNext(io.sinFiltred - (io.sinFiltred >> 5) + (io.sin >> 5)) init(0)
}
设置位宽为16,采样数为32,生成的Verilog为:
// Generator : SpinalHDL v1.6.0 git head : 73c8d8e2b86b45646e9d0b2e729291f2b65e6be3
// Component : MyTopLevel
module MyTopLevel (
output [15:0] io_sin,
output [15:0] io_sinFiltred,
input clk,
input reset
);
reg [15:0] _zz_rom_port0;
wire _zz_rom_port;
wire _zz_io_sin;
wire [15:0] _zz__zz_io_sinFiltred;
wire [15:0] _zz__zz_io_sinFiltred_1;
wire [10:0] _zz__zz_io_sinFiltred_2;
wire [15:0] _zz__zz_io_sinFiltred_3;
wire [10:0] _zz__zz_io_sinFiltred_4;
reg [4:0] phase;
reg [15:0] _zz_io_sinFiltred;
reg [15:0] rom [0:31];
assign _zz__zz_io_sinFiltred = ($signed(io_sinFiltred) - $signed(_zz__zz_io_sinFiltred_1));
assign _zz__zz_io_sinFiltred_2 = (io_sinFiltred >>> 5);
assign _zz__zz_io_sinFiltred_1 = {{5{_zz__zz_io_sinFiltred_2[10]}}, _zz__zz_io_sinFiltred_2};
assign _zz__zz_io_sinFiltred_4 = (io_sin >>> 5);
assign _zz__zz_io_sinFiltred_3 = {{5{_zz__zz_io_sinFiltred_4[10]}}, _zz__zz_io_sinFiltred_4};
assign _zz_io_sin = 1'b1;
initial begin
$readmemb("MyTopLevel.v_toplevel_rom.bin",rom);
end
always @(posedge clk) begin
if(_zz_io_sin) begin
_zz_rom_port0 <= rom[phase];
end
end
assign io_sin = _zz_rom_port0;
assign io_sinFiltred = _zz_io_sinFiltred;
always @(posedge clk or posedge reset) begin
if(reset) begin
phase <= 5'h0;
_zz_io_sinFiltred <= 16'h0;
end else begin
phase <= (phase + 5'h01);
_zz_io_sinFiltred <= ($signed(_zz__zz_io_sinFiltred) + $signed(_zz__zz_io_sinFiltred_3));
end
end
endmodule
其中ROM的Binary文件为:
0000000000000000
0001100011111000
0011000011111011
0100011100011100
0101101010000001
0110101001101100
0111011001000000
0111110110001001
0111111111111111
0111110110001001
0111011001000000
0110101001101100
0101101010000001
0100011100011100
0011000011111011
0001100011111000
0000000000000000
1110011100001000
1100111100000101
1011100011100100
1010010101111111
1001010110010100
1000100111000000
1000001001110111
1000000000000001
1000001001110111
1000100111000000
1001010110010100
1010010101111111
1011100011100100
1100111100000101
1110011100001000