Verilog功能模块——串行数据转并行数据
一. 模塊功能與應(yīng)用場景
模塊功能:接收串行數(shù)據(jù),轉(zhuǎn)為并行數(shù)據(jù)。
應(yīng)用場景:在SPI,Uart等串行協(xié)議接收側(cè)均有應(yīng)用。
二. 模塊框圖與使用說明
有兩種模式(通過參數(shù)SDATA_IS_CONTINUOUS進(jìn)行選擇):
1.數(shù)據(jù)連續(xù)模式,此時sdata_valid指示有效數(shù)據(jù)開始,在并行數(shù)據(jù)接收完成前,后面數(shù)據(jù)均有效。輸入時序如下圖。
2.數(shù)據(jù)不連續(xù)模式,此時sdata_valid指示當(dāng)前數(shù)據(jù)有效。輸入時序如下圖。
注意:
1.sdata與sdata_valid應(yīng)同步有效,且因?yàn)榇a中有同步處理,所以這兩者不需要與sclk的某邊沿同步
2.sdata應(yīng)從最高位開始發(fā)
2.第一組數(shù)據(jù)和第二組數(shù)據(jù)之間的間隔可以為0~N個時鐘周期,即可以連續(xù)發(fā)不間隔,也可以有任意間隔。
三. 模塊代碼
/** @Author : Xu Dakang* @Email : XudaKang_up@qq.com* @Date : 2021-04-24 12:27:11* @LastEditors : Xu Dakang* @LastEditTime : 2021-04-25 21:08:14* @Filename : sdata2pdata.sv* @Description : 輸入串行數(shù)據(jù),輸出并行數(shù)據(jù),實(shí)現(xiàn)串轉(zhuǎn)并 */module sdata2pdata #(parameter PDATA_WIDTH = 24,parameter SDATA_IS_CONTINUOUS = 0 )(output logic [PDATA_WIDTH-1 : 0] pdata,output logic pdata_valid,input logic sdata,input logic sdata_valid,input logic sclk,input logic rstn );//< 輸入信號同步 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ logic sdata_r1; logic sdata_r2; logic sdata_r3; always_ff @(posedge sclk) beginsdata_r1 <= sdata;sdata_r2 <= sdata_r1;sdata_r3 <= sdata_r2; endlogic sdata_valid_r1; logic sdata_valid_r2; always_ff @(posedge sclk) beginsdata_valid_r1 <= sdata_valid;sdata_valid_r2 <= sdata_valid_r1; end //< 輸入信號同步 ------------------------------------------------------------//> 串行數(shù)據(jù)計(jì)數(shù) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ logic [$clog2(PDATA_WIDTH+1)-1 : 0] sdata_cnt;logic sdata_cnt_en; always_ff @(posedge sclk, negedge rstn) beginif (~rstn)sdata_cnt_en <= '0;else if (SDATA_IS_CONTINUOUS)if (sdata_valid_r2 && (sdata_cnt == '0 || sdata_cnt == PDATA_WIDTH - 1 || sdata_cnt == PDATA_WIDTH))sdata_cnt_en <= 1'b1;else if (~sdata_valid_r2 && sdata_cnt == PDATA_WIDTH - 1)sdata_cnt_en <= 1'b0;elsesdata_cnt_en <= sdata_cnt_en;elsesdata_cnt_en <= sdata_valid_r2; endalways_ff @(posedge sclk, negedge rstn) beginif (~rstn)sdata_cnt <= '0;else if (sdata_cnt_en)if (sdata_cnt == PDATA_WIDTH) // 數(shù)據(jù)有效時,一組數(shù)據(jù)剛轉(zhuǎn)換完成,下一組的第一個數(shù)據(jù)來了,計(jì)為1sdata_cnt <= 'b1;else //! 數(shù)據(jù)有效時,一組數(shù)據(jù)還未轉(zhuǎn)換完成,計(jì)數(shù)加1sdata_cnt <= sdata_cnt + 1'b1;else if (sdata_cnt == PDATA_WIDTH) // 一組數(shù)據(jù)轉(zhuǎn)換完成,下一組數(shù)據(jù)沒馬上來,回到0sdata_cnt <= '0;elsesdata_cnt <= sdata_cnt; end //> 串行數(shù)據(jù)計(jì)數(shù) ------------------------------------------------------------//< 生成輸出 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ logic [PDATA_WIDTH-1 : 0] pdata_temp; // pdata的計(jì)算中間值 always_ff @(posedge sclk, negedge rstn) beginif (~rstn)pdata_temp <= '0;else if (sdata_cnt_en)pdata_temp <= {pdata_temp[PDATA_WIDTH-2 : 0], sdata_r3};elsepdata_temp <= pdata_temp; endalways_ff @(posedge sclk, negedge rstn) beginif (~rstn)pdata <= '0;else if (sdata_cnt == PDATA_WIDTH)pdata <= pdata_temp;elsepdata <= pdata; endalways_ff @(posedge sclk, negedge rstn) beginif (~rstn)pdata_valid <= '0;else if (sdata_cnt == PDATA_WIDTH)pdata_valid <= 1'b1;elsepdata_valid <= '0; end //< 生成輸出 ------------------------------------------------------------endmodule四. testbench
/** @Author : Xu Dakang* @Email : XudaKang_up@qq.com* @Date : 2021-04-24 12:27:28* @LastEditors : Xu Dakang* @LastEditTime : 2021-04-25 21:05:02* @Filename : sdata2pdata_tb.sv* @Description : testbench of sdata2pdata */module sdata2pdata_tb ();timeunit 1ns; timeprecision 10ps;localparam PDATA_WIDTH = 5; localparam SDATA_IS_CONTINUOUS = 1;logic [PDATA_WIDTH-1 : 0] pdata; logic pdata_valid;logic sdata; logic sdata_valid; logic sclk; logic rstn;// 實(shí)例化模塊 sdata2pdata #(.PDATA_WIDTH (PDATA_WIDTH),.SDATA_IS_CONTINUOUS (SDATA_IS_CONTINUOUS) ) sdata2pdata_inst(.*);// 產(chǎn)生測試數(shù)據(jù) 最大值 2^PDATA_WIDTH-1 localparam NUM = 15; logic [PDATA_WIDTH-1 : 0] pdata_list [NUM]; initial beginfor (int i = 0; i < NUM; i++) beginpdata_list[i] = {$random()} % (2**PDATA_WIDTH);end end// 生成時鐘 localparam CLKT = 2; initial beginsclk = 0;forever #(CLKT / 2) sclk = ~sclk; end// 數(shù)據(jù)連續(xù)模式 initial beginif (SDATA_IS_CONTINUOUS == 1) beginrstn = 0;sdata_valid = 0;#(CLKT * 2) rstn = 1;for (int i = 0; i < NUM; i++) beginsdata_valid = 1;for (int j = 0; j < PDATA_WIDTH; j++) beginsdata = pdata_list[i][PDATA_WIDTH-1-j];#(CLKT) sdata_valid = 0;end#(CLKT * ({$random} % 3)) ; // 數(shù)據(jù)連續(xù)模式時,可在各組數(shù)據(jù)間插入隨機(jī)時鐘間隔end#(CLKT * 10) $stop;end end// 數(shù)據(jù)不連續(xù)模式 initial beginif (SDATA_IS_CONTINUOUS == 0) beginrstn = 0;sdata_valid = 0;#(CLKT * 2) rstn = 1;for (int i = 0; i < NUM; i++) beginfor (int j = 0; j < PDATA_WIDTH; j++) beginsdata = pdata_list[i][PDATA_WIDTH-1-j];sdata_valid = 1;#CLKT ;sdata_valid = 0;#(CLKT * ({$random} % 3)) ; // 數(shù)據(jù)不連續(xù)模式時,可在同組數(shù)據(jù)間插入隨機(jī)時鐘間隔endsdata_valid = 0;#(CLKT * ({$random} % 3)) ;end#(CLKT * 10) $stop;end endendmodule五. 仿真驗(yàn)證
仿真工具:Vivado 2020.2 Simulator。
數(shù)據(jù)連續(xù)模式,從結(jié)果可以看出,串轉(zhuǎn)并輸出正確。
數(shù)據(jù)不連續(xù)模式,同樣正確。
六. 工程分享
sdata2pdata 串轉(zhuǎn)并模塊 vivado 2020.2工程.7z
鏈接:https://pan.baidu.com/s/1wBCLjYqcjj0HGm_S9O5iOQ
提取碼:j3z4
總結(jié)
以上是生活随笔為你收集整理的Verilog功能模块——串行数据转并行数据的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 自定义Matlab功能函数——10进制整
- 下一篇: ISE简介及其下载 安装 和谐 与 卸载