如何使用OSERDESE2原语实现多个dds合成一个波形
- 要实现一个高频波形的数字呈现时,可以将其拆分成4个甚至8个相同频率不同初始相位的低频波形,多个低频dds生成的波形使用OSERDESE2原语合成最终的高频波形,这样占用了更多资源,但是降低了运行速度。
- 如图所示彩色的波形由四个不同颜色构成,一共由36个点构成一个完整的正弦波。当使用一个dds生成时,必然运行时钟频率要求更高。当我们将其拆成四个小的波形,每个波形由9个点构成,相当于四分之一倍低频频率的dds;或者说在原本单位周期要完成36个点的计算,现在只需要完成9个点的计算,只不过这样的计算模块有四个。相当于同样一件事原先交给一个人完成,那他就需要焦头烂额地在固定周期内完成工作;如果将工作拆成4个小任务交由四个人分别完成,那么每个人的压力就会很小,工作也会很悠闲。这种方式通常称为面积换速度。
- 在FPGA(Field-Programmable Gate Array)中,“面积”(Area)、“功耗”(Power)和"速度"(Performance)是 FPGA 设计的关键指标,通常被称为 “Area, Power, Speed”(APS)三角。
- 面积(Area): 指的是 FPGA 芯片上被设计电路占据的物理空间。在FPGA中,资源包括逻辑单元(Lookup
Tables)、寄存器、布线资源等。更大的面积通常表示能够容纳更多的逻辑元素,但也可能会增加功耗和成本。 - 功耗(Power): FPGA 设计中的功耗是指电路在运行时所消耗的电能。功耗与 FPGA
设计的电路结构、时钟频率、电压等因素有关。在一些功耗敏感的应用中,需要设计者在满足性能要求的前提下尽量降低功耗。 - 速度(Speed): 在 FPGA
设计中,速度通常指的是电路在运行时的时钟频率。更高的时钟频率允许电路更快地执行操作,但同时也可能增加功耗和面积。 - 这三个指标之间存在权衡关系,通常被描述为 “Area, Power, Speed” 三角。设计者需要在这三者之间做出取舍,根据具体的应用需求和设计约束做出权衡。例如,提高时钟频率可能会导致更大的功耗,而减小面积可能会限制电路的复杂性。
OSERDESE2原语的应用
如下方程序所示:
`timescale 1ns / 1ps
///////////////////////////////////////////////////////////////////////
// Company:
// Engineer: jiangquan
//
// Design Name:
// Module Name: txdata_oserd_e2
// Project Name:
// Target Devices: Kintex-7
// Tool Versions: Vivado 2019.1
// Description:
// OSERDESE2,DAC data output interface
//
// Dependencies:
//
// Revision:
// Revision 0.01 - File Created
// Create Date: 2021/03/09
// Additional Comments:
//
//
// Revision 0.02 - File update
// Update Date: year/mounth/date
// Additional Comments:
//
//
///////////////////////////////////////////////////////////////////////
module txdata_oserd_e2 #(
parameter BUS_W = 8'd16,
parameter SERD_W = 4'd4,
parameter DCI_SEQ = 5'b01010, // DCI SEQUENCE: 0 1 0 1 0
parameter SERD_MD = "DDR", // DDR Mode support Data_Width:2,4,6,8,10,14
// SDR Mode support Data_Width:2,3,4,5,6,7,8
parameter DAT_W = 8'd224 //14 * BUS_W
)
(
// Global Clock And Reset
input i_rst,
input i_tx_clk,
input i_tx_clkdiv,
// dac external interface
output [15:0] o_tx_dout_p,
output [15:0] o_tx_dout_n,
output o_tx_dci_p,
output o_tx_dci_n,
// dac fpga internal interface
input [223:0] i_tx_data
);
//====================================================================//
//-------------------------- 变量声明 --------------------------------//
//====================================================================//
wire dci_sf1;
wire dci_sf2;
wire [BUS_W -1 : 0] dat_sf1;
wire [BUS_W -1 : 0] dat_sf2;
wire [BUS_W -1 : 0] tx_dout;
wire tx_dci;
wire [BUS_W -1 : 0] tx_d1;
wire [BUS_W -1 : 0] tx_d2;
wire [BUS_W -1 : 0] tx_d3;
wire [BUS_W -1 : 0] tx_d4;
wire [BUS_W -1 : 0] tx_d5;
wire [BUS_W -1 : 0] tx_d6;
wire [BUS_W -1 : 0] tx_d7;
wire [BUS_W -1 : 0] tx_d8;
wire [BUS_W -1 : 0] tx_d9;
wire [BUS_W -1 : 0] tx_d10;
wire [BUS_W -1 : 0] tx_d11;
wire [BUS_W -1 : 0] tx_d12;
wire [BUS_W -1 : 0] tx_d13;
wire [BUS_W -1 : 0] tx_d14;
//====================================================================//
//------------------------- 核心逻辑 -----------------------------//
//====================================================================//
assign tx_d1 = i_tx_data[ BUS_W -1 : 0 ];
assign tx_d2 = i_tx_data[ 2*BUS_W -1 : BUS_W ];
assign tx_d3 = i_tx_data[ 3*BUS_W -1 : 2*BUS_W ];
assign tx_d4 = i_tx_data[ 4*BUS_W -1 : 3*BUS_W ];
assign tx_d5 = i_tx_data[ 5*BUS_W -1 : 4*BUS_W ];
assign tx_d6 = i_tx_data[ 6*BUS_W -1 : 5*BUS_W ];
assign tx_d7 = i_tx_data[ 7*BUS_W -1 : 6*BUS_W ];
assign tx_d8 = i_tx_data[ 8*BUS_W -1 : 7*BUS_W ];
assign tx_d9 = i_tx_data[ 9*BUS_W -1 : 8*BUS_W ];
assign tx_d10 = i_tx_data[10*BUS_W -1 : 9*BUS_W ];
assign tx_d11 = i_tx_data[11*BUS_W -1 : 10*BUS_W ];
assign tx_d12 = i_tx_data[12*BUS_W -1 : 11*BUS_W ];
assign tx_d13 = i_tx_data[13*BUS_W -1 : 12*BUS_W ];
assign tx_d14 = i_tx_data[14*BUS_W -1 : 13*BUS_W ];
/////////////////////////////////////
// Sync Reset to CLKDIV
(* KEEP="TRUE" *)wire sync_rst;
reg [3:0] rst_cnt;
always @(posedge i_tx_clkdiv or posedge i_rst)begin
if(i_rst)
rst_cnt <= 0;
else
if(rst_cnt == 4'b1000)
rst_cnt <= rst_cnt;
else
rst_cnt <= rst_cnt + 1;
end // eng always
assign sync_rst = rst_cnt[1];
/////////////////////////////////////
// DCI
generate
if(SERD_W > 8)
begin:width_expansion_mode
OSERDESE2 #(
.DATA_RATE_OQ ( SERD_MD ), // DDR, SDR
.DATA_RATE_TQ ( "DDR" ), // DDR, BUF, SDR
.DATA_WIDTH ( SERD_W ), // Parallel data width (2-8,10,14)
.INIT_OQ ( DCI_SEQ[0] ),
.INIT_TQ ( 1'b0 ),
.SERDES_MODE ( "MASTER" ), // MASTER, SLAVE
.SRVAL_OQ ( 1'b0 ),
.SRVAL_TQ ( 1'b0 ),
.TBYTE_CTL ( "FALSE" ), // Enable tristate byte operation (FALSE, TRUE)
.TBYTE_SRC ( "FALSE" ), // Tristate byte source (FALSE, TRUE)
.TRISTATE_WIDTH ( 4 )
)
u_oserdes1_dci (
.OFB ( ),
.OQ ( tx_dci ),
// SHIFTOUT1 / SHIFTOUT2: 1-bit (each) output: Data output expansion (1-bit each)
.SHIFTOUT1 ( ),
.SHIFTOUT2 ( ),
.TBYTEOUT ( ),
.TFB ( ),
.TQ ( ),
.CLK ( i_tx_clk ),
.CLKDIV ( i_tx_clkdiv ),
// D1 - D8: 1-bit (each) input: Parallel data inputs (1-bit each)
.D1 ( DCI_SEQ[1] ),
.D2 ( DCI_SEQ[2] ),
.D3 ( DCI_SEQ[3] ),
.D4 ( DCI_SEQ[4] ),
.D5 ( DCI_SEQ[1] ),
.D6 ( DCI_SEQ[2] ),
.D7 ( DCI_SEQ[3] ),
.D8 ( DCI_SEQ[4] ),
.OCE ( 1'b1 ),
.RST ( sync_rst ),
// SHIFTIN1 / SHIFTIN2: 1-bit (each) input: Data input expansion (1-bit each)
.SHIFTIN1 ( dci_sf1 ),
.SHIFTIN2 ( dci_sf2 ),
// T1 - T4: 1-bit (each) input: Parallel 3-state inputs
.T1 ( 1'b0 ),
.T2 ( 1'b0 ),
.T3 ( 1'b0 ),
.T4 ( 1'b0 ),
.TBYTEIN ( 1'b0 ),
.TCE ( 1'b0 )
);
OSERDESE2 #(
.DATA_RATE_OQ ( SERD_MD ), // DDR, SDR
.DATA_RATE_TQ ( "DDR" ), // DDR, BUF, SDR
.DATA_WIDTH ( SERD_W ), // Parallel data width (2-8,10,14)
.INIT_OQ ( DCI_SEQ[0] ),
.INIT_TQ ( 1'b0 ),
.SERDES_MODE ( "SLAVE" ), // MASTER, SLAVE
.SRVAL_OQ ( 1'b0 ),
.SRVAL_TQ ( 1'b0 ),
.TBYTE_CTL ( "FALSE" ), // Enable tristate byte operation (FALSE, TRUE)
.TBYTE_SRC ( "FALSE" ), // Tristate byte source (FALSE, TRUE)
.TRISTATE_WIDTH ( 4 )
)
u_oserdes2_dci (
.OFB ( ),
.OQ ( ),
// SHIFTOUT1 / SHIFTOUT2: 1-bit (each) output: Data output expansion (1-bit each)
.SHIFTOUT1 ( dci_sf1 ),
.SHIFTOUT2 ( dci_sf2 ),
.TBYTEOUT ( ),
.TFB ( ),
.TQ ( ),
.CLK ( i_tx_clk ),
.CLKDIV ( i_tx_clkdiv ),
// D1 - D8: 1-bit (each) input: Parallel data inputs (1-bit each)
.D1 ( ),
.D2 ( ),
.D3 ( DCI_SEQ[1] ),
.D4 ( DCI_SEQ[2] ),
.D5 ( DCI_SEQ[3] ),
.D6 ( DCI_SEQ[4] ),
.D7 ( DCI_SEQ[1] ),
.D8 ( DCI_SEQ[2] ),
.OCE ( 1'b1 ),
.RST ( sync_rst ),
// SHIFTIN1 / SHIFTIN2: 1-bit (each) input: Data input expansion (1-bit each)
.SHIFTIN1 ( 1'b0 ),
.SHIFTIN2 ( 1'b0 ),
// T1 - T4: 1-bit (each) input: Parallel 3-state inputs
.T1 ( 1'b0 ),
.T2 ( 1'b0 ),
.T3 ( 1'b0 ),
.T4 ( 1'b0 ),
.TBYTEIN ( 1'b0 ),
.TCE ( 1'b0 )
);
OBUFDS #(
.IOSTANDARD ( "LVDS" ), // Specify the output I/O standard
.SLEW ( "FAST" ) // "SLOW"
)
u_obufds_dci(
.I ( tx_dci ), // Buffer input
.O ( o_tx_dci_p ), // Diff_p output (connect directly to top-level port)
.OB ( o_tx_dci_n ) // Diff_n output (connect directly to top-level port)
);
end //
else
begin:normal_mode
OSERDESE2 #(
.DATA_RATE_OQ ( SERD_MD ), // DDR, SDR
.DATA_RATE_TQ ( "DDR" ), // DDR, BUF, SDR
.DATA_WIDTH ( SERD_W ), // Parallel data width (2-8,10,14)
.INIT_OQ ( DCI_SEQ[0] ),
.INIT_TQ ( 1'b0 ),
.SERDES_MODE ( "MASTER" ), // MASTER, SLAVE
.SRVAL_OQ ( 1'b0 ),
.SRVAL_TQ ( 1'b0 ),
.TBYTE_CTL ( "FALSE" ), // Enable tristate byte operation (FALSE, TRUE)
.TBYTE_SRC ( "FALSE" ), // Tristate byte source (FALSE, TRUE)
.TRISTATE_WIDTH ( 1 )
)
u_oserdes_dci (
.OFB ( ),
.OQ ( tx_dci ),
// SHIFTOUT1 / SHIFTOUT2: 1-bit (each) output: Data output expansion (1-bit each)
.SHIFTOUT1 ( ),
.SHIFTOUT2 ( ),
.TBYTEOUT ( ),
.TFB ( ),
.TQ ( ),
.CLK ( i_tx_clk ),
.CLKDIV ( i_tx_clkdiv ),
// D1 - D8: 1-bit (each) input: Parallel data inputs (1-bit each)
.D1 ( DCI_SEQ[1] ),
.D2 ( DCI_SEQ[2] ),
.D3 ( DCI_SEQ[3] ),
.D4 ( DCI_SEQ[4] ),
.D5 ( DCI_SEQ[1] ),
.D6 ( DCI_SEQ[2] ),
.D7 ( DCI_SEQ[3] ),
.D8 ( DCI_SEQ[4] ),
.OCE ( 1'b1 ),
.RST ( sync_rst ),
// SHIFTIN1 / SHIFTIN2: 1-bit (each) input: Data input expansion (1-bit each)
.SHIFTIN1 ( 1'b0 ),
.SHIFTIN2 ( 1'b0 ),
// T1 - T4: 1-bit (each) input: Parallel 3-state inputs
.T1 ( 1'b0 ),
.T2 ( 1'b0 ),
.T3 ( 1'b0 ),
.T4 ( 1'b0 ),
.TBYTEIN ( 1'b0 ),
.TCE ( 1'b0 )
);
OBUFDS #(
.IOSTANDARD ( "LVDS" ), // Specify the output I/O standard
.SLEW ( "FAST" ) // "SLOW"
)
u_obufds_dci(
.I ( tx_dci ), // Buffer input
.O ( o_tx_dci_p ), // Diff_p output (connect directly to top-level port)
.OB ( o_tx_dci_n ) // Diff_n output (connect directly to top-level port)
);
end
endgenerate
// DATA
genvar DAT_GEN;
generate
if(SERD_W > 8)
begin:width_expansion_mode
for (DAT_GEN = 0; DAT_GEN < BUS_W; DAT_GEN = DAT_GEN + 1)
begin: u_dat_gen
OSERDESE2 #(
.DATA_RATE_OQ ( SERD_MD ), // DDR, SDR
.DATA_RATE_TQ ( "DDR" ), // DDR, BUF, SDR
.DATA_WIDTH ( SERD_W ), // Parallel data width (2-8,10,14)
.INIT_OQ ( 1'b0 ),
.INIT_TQ ( 1'b0 ),
.SERDES_MODE ( "MASTER" ), // MASTER, SLAVE
.SRVAL_OQ ( 1'b0 ),
.SRVAL_TQ ( 1'b0 ),
.TBYTE_CTL ( "FALSE" ), // Enable tristate byte operation (FALSE, TRUE)
.TBYTE_SRC ( "FALSE" ), // Tristate byte source (FALSE, TRUE)
.TRISTATE_WIDTH ( 1 )
)
u_oserdes1_dat (
.OFB ( ),
.OQ ( tx_dout[DAT_GEN] ),
// SHIFTOUT1 / SHIFTOUT2: 1-bit (each) output: Data output expansion (1-bit each)
.SHIFTOUT1 ( ),
.SHIFTOUT2 ( ),
.TBYTEOUT ( ),
.TFB ( ),
.TQ ( ),
.CLK ( i_tx_clk ),
.CLKDIV ( i_tx_clkdiv ),
// D1 - D8: 1-bit (each) input: Parallel data inputs (1-bit each)
.D1 ( tx_d1[DAT_GEN] ),
.D2 ( tx_d2[DAT_GEN] ),
.D3 ( tx_d3[DAT_GEN] ),
.D4 ( tx_d4[DAT_GEN] ),
.D5 ( tx_d5[DAT_GEN] ),
.D6 ( tx_d6[DAT_GEN] ),
.D7 ( tx_d7[DAT_GEN] ),
.D8 ( tx_d8[DAT_GEN] ),
.OCE ( 1'b1 ),
.RST ( sync_rst ),
// SHIFTIN1 / SHIFTIN2: 1-bit (each) input: Data input expansion (1-bit each)
.SHIFTIN1 ( dat_sf1[DAT_GEN] ),
.SHIFTIN2 ( dat_sf2[DAT_GEN] ),
// T1 - T4: 1-bit (each) input: Parallel 3-state inputs
.T1 ( 1'b0 ),
.T2 ( 1'b0 ),
.T3 ( 1'b0 ),
.T4 ( 1'b0 ),
.TBYTEIN ( 1'b0 ),
.TCE ( 1'b0 )
);
OSERDESE2 #(
.DATA_RATE_OQ ( SERD_MD ), // DDR, SDR
.DATA_RATE_TQ ( "DDR" ), // DDR, BUF, SDR
.DATA_WIDTH ( SERD_W ), // Parallel data width (2-8,10,14)
.INIT_OQ ( 1'b0 ),
.INIT_TQ ( 1'b0 ),
.SERDES_MODE ( "SLAVE" ), // MASTER, SLAVE
.SRVAL_OQ ( 1'b0 ),
.SRVAL_TQ ( 1'b0 ),
.TBYTE_CTL ( "FALSE" ), // Enable tristate byte operation (FALSE, TRUE)
.TBYTE_SRC ( "FALSE" ), // Tristate byte source (FALSE, TRUE)
.TRISTATE_WIDTH ( 1 )
)
u_oserdes2_dat (
.OFB ( ),
.OQ ( ),
// SHIFTOUT1 / SHIFTOUT2: 1-bit (each) output: Data output expansion (1-bit each)
.SHIFTOUT1 ( dat_sf1[DAT_GEN] ),
.SHIFTOUT2 ( dat_sf2[DAT_GEN] ),
.TBYTEOUT ( ),
.TFB ( ),
.TQ ( ),
.CLK ( i_tx_clk ),
.CLKDIV ( i_tx_clkdiv ),
// D1 - D8: 1-bit (each) input: Parallel data inputs (1-bit each)
.D1 ( ),
.D2 ( ),
.D3 ( tx_d9 [DAT_GEN] ),
.D4 ( tx_d10[DAT_GEN] ),
.D5 ( tx_d11[DAT_GEN] ),
.D6 ( tx_d12[DAT_GEN] ),
.D7 ( tx_d13[DAT_GEN] ),
.D8 ( tx_d14[DAT_GEN] ),
.OCE ( 1'b1 ),
.RST ( sync_rst ),
// SHIFTIN1 / SHIFTIN2: 1-bit (each) input: Data input expansion (1-bit each)
.SHIFTIN1 ( 1'b0 ),
.SHIFTIN2 ( 1'b0 ),
// T1 - T4: 1-bit (each) input: Parallel 3-state inputs
.T1 ( 1'b0 ),
.T2 ( 1'b0 ),
.T3 ( 1'b0 ),
.T4 ( 1'b0 ),
.TBYTEIN ( 1'b0 ),
.TCE ( 1'b0 )
);
OBUFDS #(
.IOSTANDARD ( "LVDS" ), // Specify the output I/O standard
.SLEW ( "FAST" ) // "SLOW"
)
u_obufds_dat(
.I ( tx_dout [DAT_GEN] ),
.O ( o_tx_dout_p[DAT_GEN] ),
.OB ( o_tx_dout_n[DAT_GEN] )
);
end
end
else
begin:normal_mode
for (DAT_GEN = 0; DAT_GEN < BUS_W; DAT_GEN = DAT_GEN + 1)
begin: u_dat_gen
OSERDESE2 #(
.DATA_RATE_OQ ( SERD_MD ), // DDR, SDR
.DATA_RATE_TQ ( "DDR" ), // DDR, BUF, SDR
.DATA_WIDTH ( SERD_W ), // Parallel data width (2-8,10,14)
.INIT_OQ ( 1'b0 ),
.INIT_TQ ( 1'b0 ),
.SERDES_MODE ( "MASTER" ), // MASTER, SLAVE
.SRVAL_OQ ( 1'b0 ),
.SRVAL_TQ ( 1'b0 ),
.TBYTE_CTL ( "FALSE" ), // Enable tristate byte operation (FALSE, TRUE)
.TBYTE_SRC ( "FALSE" ), // Tristate byte source (FALSE, TRUE)
.TRISTATE_WIDTH ( 1 )
)
u_oserdes_dat (
.OFB ( ),
.OQ ( tx_dout[DAT_GEN] ),
// SHIFTOUT1 / SHIFTOUT2: 1-bit (each) output: Data output expansion (1-bit each)
.SHIFTOUT1 ( ),
.SHIFTOUT2 ( ),
.TBYTEOUT ( ),
.TFB ( ),
.TQ ( ),
.CLK ( i_tx_clk ),
.CLKDIV ( i_tx_clkdiv ),
// D1 - D8: 1-bit (each) input: Parallel data inputs (1-bit each)
.D1 ( tx_d1[DAT_GEN] ),
.D2 ( tx_d2[DAT_GEN] ),
.D3 ( tx_d3[DAT_GEN] ),
.D4 ( tx_d4[DAT_GEN] ),
.D5 ( tx_d5[DAT_GEN] ),
.D6 ( tx_d6[DAT_GEN] ),
.D7 ( tx_d7[DAT_GEN] ),
.D8 ( tx_d8[DAT_GEN] ),
.OCE ( 1'b1 ),
.RST ( sync_rst ),
// SHIFTIN1 / SHIFTIN2: 1-bit (each) input: Data input expansion (1-bit each)
.SHIFTIN1 ( 1'b0 ),
.SHIFTIN2 ( 1'b0 ),
// T1 - T4: 1-bit (each) input: Parallel 3-state inputs
.T1 ( 1'b0 ),
.T2 ( 1'b0 ),
.T3 ( 1'b0 ),
.T4 ( 1'b0 ),
.TBYTEIN ( 1'b0 ),
.TCE ( 1'b0 )
);
OBUFDS #(
.IOSTANDARD ( "LVDS" ), // Specify the output I/O standard
.SLEW ( "FAST" ) // "SLOW"
)
u_obufds_dat(
.I ( tx_dout [DAT_GEN] ),
.O ( o_tx_dout_p[DAT_GEN] ),
.OB ( o_tx_dout_n[DAT_GEN] )
);
end
end
endgenerate
/////////////////////////////////////
endmodule
此程序实现了多DDS模块生成数据在多个通道进行的,并转串的合并输出。需要理解以下两点:
- 理解generate模块复用例化
- OSERDESE2 原语
详细的OSERDESE2 原语解释请自行查阅,如xilinx原语详解及仿真——OSERDESE2
generate的使用方法如Verilog中generate的用法
注意事项
- 使用OSERDESE2原语的时候,是将四个低频dds的数据合成一个,那么合成模块就是将四个dds的值一次穿插,其最终的输出频率无法降低,和使用一个dds输出波形时所用的时钟频率一致或至少其一半,但无法降低至每个小dds的低频率去运行。如果硬件如DAC无法在这么高的频率下输出,那么还是无法合成高频率的波形。也就是说此方法只是为了减轻系统计算庞大数据时候的速度压力,最终合成波形的频率上限是由硬件条件尤其是DAC决定的。
- OSERDESE2原语可以做到时钟上升沿和下降沿都输出数据,利用ddr模式可以生成两倍频率的数据。如10MHz的波形用一个dds实现,如果44个点为一个周期,那么时钟频率为440Mhz,而利用OSERDESE2原语只需要220MHz就可以合成。
- 再考虑多少个dds合成一个最终的波形时,不仅限于4个或者8,具体根据实际情况考量,可以利用OSERDESE2原语的级联做到14个DDS合成一个。
- 此程序使用的是8个dds的数据,但最终选出其第1、3、5、7个dds进行波形合成,第2、4、6、8个dds并未进行计算,但是在OSERDESE2模块里仍然按照8个通道去合并的。如果8个dds的数据全部并转串输出,那么最终波形一个周期就由11个点组成,而现在这种四个11/8个dds合成的波形,每个周期其实只有5或6个点。这里只是阐述D1、D2通道的数据为何一样,详细可查看此文:DDS的步进值计算。
代码要点文章来源:https://www.toymoban.com/news/detail-800875.html
- 此代码里虽然使用了ddr模式,但是时钟上升沿和下降沿的数据是一样的,等同于仍然是每个时钟上升沿才输出一次。
- 虽然D1-D8通道全部使用了,但D1和D2、D3和D4、D5和D6、D7和D8的数据是一样的。
- 要注意并转串是倒着输出的,因此最终输出的结果等于是D7通道的第一个数据排第1输出,D5通道的第一个数据排在第2个输出,D3排第3,D1排第4;然后是D7通道的第二个数据,依次类推。
- 在如下图所示程序里 ,tx_d1值得不是数组,而是一个变量,这里不是利用数组的多维元素进行拼接,而是tx_d1这个变量的某一位进行generate的模块复用。要知道的是这些复用的模块是同时进行的,也就是单位时钟周期内,tx_d1这个变量的每一位都赋值成功了
D1 ( tx_d1[DAT_GEN] ),
.D2 ( tx_d2[DAT_GEN] ),
.D3 ( tx_d3[DAT_GEN] ),
.D4 ( tx_d4[DAT_GEN] ),
.D5 ( tx_d5[DAT_GEN] ),
.D6 ( tx_d6[DAT_GEN] ),
.D7 ( tx_d7[DAT_GEN] ),
.D8 ( tx_d8[DAT_GEN] ),
.OCE ( 1'b1 ),
.RST ( sync_rst ),
- 如下表所示,复用的模块对每一位单独进行赋值,每个模块都是并行同时进行赋值的;也就是同一时间输出端tx_dout的A、B、C、D变量就已经赋值完成了,再依次按照AABBCCDD顺序输出即可。
切勿理解为tx_dout[15:0]=0000 0000 0000 000A0 。
文章来源地址https://www.toymoban.com/news/detail-800875.html
到了这里,关于使用OSERDESE2原语实现多个dds合成一个波形,达到面积换速度的目的的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!