ZQH
https://zh.101entj.ru/
(*mark_debug="true", dont_touch="true"*)
// ------- // | | //------ ------ // //======================================================================== //快到慢时钟域 reg en1_100m;//100MHz 一拍 reg en2_5m ;// 5MHz 一拍 reg en1_100m_flag=1'b0; always @(posedge clk_100)begin if(en1_100m) en1_100m_flag<=~en1_100m_flag;//电平翻转 end // reg[1:0] en1_100m_flag_r; always @(posedge clk_5)begin en1_100m_flag_r <= {en1_100m_flag_r[0],en1_100m_flag}; en2_5m <=en1_100m_flag_r[0]^en1_100m_flag_r[1]; end // always @(posedge clk_5)begin en1_100m_flag_r[0] <= en1_100m_flag; en1_100m_flag_r[1] <= en1_100m_flag_r[0]; end // //========================================================================= // reg [5:0] cnt0; wire add_cnt0; wire end_cnt0; always@(posedge clk or negedge rst_n)begin if(rst_n==1'b0)begin cnt0<=0; end else if(add_cnt0)begin if(end_cnt0) cnt0<=0; else cnt0<=cnt0+1; end end assign add_cnt0 = 1; assign end_cnt0 = add_cnt0 && cnt0 == 50-1; // //https://blog.csdn.net/weixin_42790063/article/details/122037633 //延时N个时钟周期 parameter N=4; reg [N-1:0] temp; always @(posedge clk or negedge rst_n) begin if(!rst_n) begin temp <= 0; end else if(in1) begin temp[N-1:0] <= {temp[N-2:0],in1}; end else begin temp[N-1:0] <= {temp[N-2:0],1'b0}; end end assign out1 = temp[N-1]; // //verilog debounce逻辑 //https://wenku.baidu.com/view/1d70ae0ea3116c175f0e7cd184254b35effd1a7c.html?_wkts_=1740637642645&needWelcomeRecommand=1 // module debounce( input wire button,//输入信号 output reg debounced_btn //输出信号 ); // parameter DEBOUNCE_TIME = 'd10; //debounce 延迟时间 // reg [DEBOUNCE_TIME-1:0] cnt; reg btn_state;//输入信号状态 reg btn_prev_state;//前一个输入信号状态 // always@(posedge clk)begin btn_state<=button; btn_prev_state<=btn_state; end // always@(posedge clk)begin if(btn_prev_state!=btn_state) cnt<='d0; else if(cnt<DEBOUNCE_TIME) cnt<=cnt+1'd1; end // always@(posedge clk)begin if(cnt==DEBOUNCE_TIME && btn_state == button) debounced_btn<=button; end // endmodule // //----------------adc_busy 去抖--------- reg [2:0] adc_busy_cnt; always @(posedge clk_50m or negedge clk_50m_rst_n) begin if(~clk_50m_rst_n) adc_busy_cnt <= 'd0; else if(adc_busy && adc_busy_cnt<'d3) adc_busy_cnt <= adc_busy_cnt + 1'b1; else if(~adc_busy && adc_busy_cnt>'d0) adc_busy_cnt <= adc_busy_cnt - 1'b1; end // reg adc_busy_dejitte; always @(posedge clk_50m or negedge clk_50m_rst_n) begin if(~clk_50m_rst_n) adc_busy_dejitte <= 'd0; else if(adc_busy && adc_busy_cnt=='d3) adc_busy_dejitte <= 1'b1; else if(~adc_busy && adc_busy_cnt=='d0) adc_busy_dejitte <= 1'b0; end //------------------------- // // 复位最佳方式:异步复位,同步释放 //原文链接:https://blog.csdn.net/frank_wff/article/details/43226507 // module reset_best(clk,asyn_reset,syn_reset); input clk; input asyn_reset; output syn_reset; // reg rst_s1; reg rst_s2; // always @( posedge clk ,posedge asyn_reset) begin if(asyn_reset) begin rst_s1<=1'b0; rst_s2<=1'b0; end else begin rst_s1<=1'b1; rst_s2<=rst_s1; end end // assign syn_reset=rst_s2; // endmodule //亚稳态 // 1.异步接口 // 2.不同时钟域的信号 // 总结:存在不受本地时钟控制信号,均有可能出现亚稳态 // // 亚稳态解决: // 1.单比特信号解决办法 : // (引入同步机制,防止亚稳态传播) // 2.多比特信号 // 解决办法1:使用FIFO // 解决办法2:用一个使能指示信号(数据流小) // 不正确结构: // 1.组合逻辑环 // 2.组合逻辑当时钟 // 3.组合逻辑当复位 // 4.双沿触发 // 不推荐的结构: // 寄存器输出当时钟 // 寄存器输出当复位 // 时序 // 看波形要点: // 看时钟上升沿前面的输入 // 得到时钟沿后面的输出 // 看时序要点: // 1.找时钟 // 2.确定触发沿 // 3.确定输入 // 4.得到输出 // // 行为描述 // 关键: // 1.重点描述:在XX条件下,值为多少; // 否则在XXX条件下,值为多少。 // (注意:条件要包括所有的情况) // 状态机 // 1.状态 // 2.转移条件 // 3.输出 // 三段式好处 // 可以使用S_state,N_STATE // 时钟 // Tmin = Tco + Tdata + Tsu //状态机必须使用模版,防止漏写endcase // 竞争和冒险 // 解决方法: // 1.D触发器对竞争和冒险不敏感 // 2.组合逻辑输出不要连到时钟与复位 // 3.模块输出需要使用寄存器输出 // //校招Verilog——单bit跨时钟域(脉冲展宽法-握手法) https://www.cnblogs.com/xianyuIC/p/13641683.html // module Sync_Pulse ( input clka, input clkb, input rst_n, input bit_a, output bit_b ); //-------------------------------------------------------- reg req_a; reg ack_a; reg ack_a_r1; reg req_b; reg req_b_r1; //-------------------------------------------------------- //-- a时钟域生成展宽信号 //-------------------------------------------------------- always @(posedge clka or negedge rst_n)begin if(!rst_n)begin req_a <= 1'b0; end else if(bit_a) begin //检测到脉冲 req_a <= 1'b1; //进行展宽 end else if(ack_a_r1) begin //同步到b时钟域后得到应答 req_a <= 1'b0; //展宽使命完成 end end //-------------------------------------------------------- //-- 展宽信号同步到b时钟域 //-------------------------------------------------------- always @(posedge clkb or negedge rst_n)begin if(!rst_n)begin req_b <= 1'b0; req_b_r1 <= 1'b0; end else begin req_b <= req_a; req_b_r1 <= req_b; end end //-------------------------------------------------------- //-- 展宽信号同步回b时钟域,作为应答 //-------------------------------------------------------- always @(posedge clka or negedge rst_n)begin if(!rst_n)begin ack_a <= 1'b0; ack_a_r1 <= 1'b0; end else begin ack_a <= req_b_r1; ack_a_r1 <= ack_a; end end //-------------------------------------------------------- //-- 脉冲信号输出,上升沿检测 //-------------------------------------------------------- assign bit_b = ~req_b_r1 & req_b; endmodule // 只遵从一个规则“用 always 实 // 现的是 reg 型,其他都是 wire 型 // //小数的加减乘法实现 0.2+0.2=0.4 01101 +01101=10001 01101 == 0.2 10001 == 0.4 always@(posedge clk or negedge rst_n)begin if(rst_n==1'b0)begin end else if(a==5'b01101 && b==5'b01101)begin c<=5'b10001; end end Q1 * Q1 = Q2; Q2 * Q3 = Q5; //先乘以1024再除以1024 // // 冒泡排序原理: https://blog.csdn.net/k_kuo_k/article/details/111650681 void buble_sort(int* vec,int len){ //冒泡排序 int i,j; for(i=0;i<len;++i){ for(j=i+1;j<len;++j){ if(vec[i]>vec[j]) swap(&vec[i],&vec[j]); } } } reg [5:0] cnt0; wire add_cnt0; wire end_cnt0; always@(posedge clk or negedge rst_n)begin if(rst_n==1'b0)begin cnt0<=0; end else if(add_cnt0)begin if(end_cnt0) cnt0<=0; else cnt0<=cnt0+1; end end assign add_cnt0 = flag_add; assign end_cnt0 = add_cnt0 && cnt0 == x-1; reg [5:0] cnt1; wire add_cnt1; wire end_cnt1; always@(posedge clk or negedge rst_n)begin if(rst_n==1'b0)begin cnt1<=0; end else if(add_cnt1)begin if(end_cnt1) cnt1<=0; else cnt1<=cnt1+1; end end assign add_cnt1 = end_cnt0; assign end_cnt1 = add_cnt1 && cnt1 == y-1; always @(*)begin x=(len-1)-cnt1; y=(len-1); end always@(posedge clk or negedge rst_n)begin if(rst_n==1'b0)begin vec<=0; end else if(add_cnt0 && vec[cnt0] < vec[cnt0+1])begin vec[cnt0] <=vec[cnt0+1]; vec[cnt0+1]<=vec[cnt0]; end end //----------------------------------------------------- //for循环转verilog for(i=0;i<8;i++){ for(i=0;i<8;j++){ sum += a[i][j]; } } // reg [5:0] cnt0; wire add_cnt0; wire end_cnt0; always@(posedge clk or negedge rst_n)begin if(rst_n==1'b0)begin cnt0<=0; end else if(add_cnt0)begin if(end_cnt0) cnt0<=0; else cnt0<=cnt0+1; end end assign add_cnt0 = flag_add; assign end_cnt0 = add_cnt0 && cnt0 == 8-1; reg [5:0] cnt1; wire add_cnt1; wire end_cnt1; always@(posedge clk or negedge rst_n)begin if(rst_n==1'b0)begin cnt1<=0; end else if(add_cnt1)begin if(end_cnt1) cnt1<=0; else cnt1<=cnt1+1; end end assign add_cnt1 = end_cnt0; assign end_cnt1 = add_cnt1 && cnt1 == 4-1; reg [255:0] a; always@(posedge clk or negedge rst_n)begin if(rst_n==1'b0)begin sum<=0; end else if(add_cnt0) begin //sum <= sum + a[cnt1][cnt0] sum<=sum + a[(cnt1*32+cnt0*8 +8 -1) -:8]; end end //------------------------------------------------ //时序 //1、关键路径:延时最长的路径; //2、一个电路所能运行的最高频率取决于此路径,所以很关键/ // 解决时序违例方法 // Tmin = Tco + Tdata + Tsu // 1.改变时钟频率 // 2.利用时序软件优化 // 3.添加时序约束优化 // 4.选用更先进的FPGA // 5.进行流水线设计//拆分运算步骤 // 6.优化设计 // // 1.当时序违例时,最优先的方法是优化设计 // 2.流水线是FPGA设计的重点技巧,务必熟练掌握 // // 时钟--SKEW--目的地减去源-- // Tskew=TCLK2-TCLK1 // Tmin=Tco + Tdata + Tsu +Tskew // // 关键路径:延时最长的路径 // 时钟解决方法: // 1.优化设计,设计时可以优先,但亦可以利用工具进行优化: // 2.流水线设计 // 3.拆分乘法成加法,把功能不停的拆,直到两个寄存器之间的延时最小--直至最小cmos电路 // //D触发器 --建立时间与保持时间需要满足 //D触发器一亚稳态情景 //1.时序不满足的时候---否则出现亚稳态 --解决流水线 //2.不同时钟域的信号 //3.按键、外部芯片读写等 //4.总结:有可能在时钟上升沿变化的信号,均有可能出现亚稳态 //D触发器-预防亚稳态 //预防亚稳态的方法 //1.对于控制信号,建议用同步机制即打两拍(甚至是三拍) //2.对于数据流,建议用FIFO //3.对于少量,发送可控的数据流,建议通过增加指示信号的方法 always@(posedge clk or negedge rst_n)begin if(rst_n==1'b0)begin Q<='d0; end else begin Q<=D; end end //FPGA三态门结构 inout data; data=wr en?wr_data: 1'bz; rd data =data; // always@(posedge clk or negedge rst_n)begin if(rst_n==1'b0)begin vld_in_ff0<=1'b0; vld_in_ff1<=1'b0; vld_in_ff2<=1'b0; end else begin vld_in_ff0<=vld_in; vld_in_ff1<=vld_in_ff0; vld_in_ff2<=vld_in_ff1; end end assign vld_get = (vld_in_ff1 == 1'b1 && vld_in_ff2== 1'b0); //1.FPGA会自动将上面代码综合成三态门 //三态门只用于智脚中,因此FPGA内部代码不准有x态、Z态: //信号对齐 格式 时序对齐 //时序逻辑的代码一般有两种:同步复位的时序逻辑和异步复位的时序逻辑。 //在同步复位的时序逻辑中复位不是立即有效, //而在时钟上升沿时复位才有效。其代码结构如下: always@(posedge clk )begin//clk稳定 内部 if(rst_n==1'b0)begin //代码语句; end else begin //代码语句; end end //在异步复位的时序逻辑中复位立即有效,与时钟无关。 //其代码结always@(posedge clk or negedge rst_n)begin//clk不稳定 外设、接口 if(rst_n==1'b0)begin //代码语句; end else begin //代码语句; end end构如下: //在 always 语句块中,Verilog 语言支持两种类型的赋值:阻塞赋值和非阻塞赋值。阻塞赋值使用“=”语句;非阻塞赋值使用“<=”语句。 //阻塞赋值:在一个“begin...end”的多行赋值语句,先执行当前行的赋值语句,再执行下一行的赋值语句。 //非阻塞赋值:在一个“begin...end”的多行赋值语句,在同一时间内同时赋值。 // // always @(*)begin r = s?t:u; end //针对时序逻辑的 verilog 设计提出以下建议: //为了教学的方便代码统一采用异步时钟逻辑,建议同学们都采用此结构, //这样设计时只需考虑是用时序逻辑还是组合逻辑结构来进行代码编写即可。在实际工作中请遵从公司的相应规范进行代码设计。 //——————— —————————————————————————————————— // |____________________________________________| // //实现步骤 //请按以下“6步法”实现:t //1、在给出 clk 的波形图上画出输入、输出波形(根据功能要求,画出输入和输出的波形) //2、在给出 clk 的波形图上画出计数器(步 1 中,需要“数多个”的信号,用计数器标出来) //3、确认加1条件、结束条件(加1条件:计数器数什么;结束条件:计数器周期数多少个不同值时用变量法。有多少个计数器,就有多少个。) //4、其它信号变化点条件(其他信号:即输出或内容信号;变化点:0变11变0的点) // // reg [5:0] cnt0; wire add_cnt0; wire end_cnt0; always@(posedge clk or negedge rst_n)begin if(rst_n==1'b0)begin cnt0<=0; end else if(add_cnt0)begin if(end_cnt0) cnt0<=0; else cnt0<=cnt0+1; end end assign add_cnt0 = 1; assign end_cnt0 = add_cnt0 && cnt0 == 50-1; reg [5:0] cnt1; wire add_cnt1; wire end_cnt1; always@(posedge clk or negedge rst_n)begin if(rst_n==1'b0)begin cnt1<=0; end else if(add_cnt1)begin if(end_cnt1) cnt1<=0; else cnt1<=cnt1+1; end end assign add_cnt1 = end_cnt0; assign end_cnt1 = add_cnt1 && cnt1 == 34-1; reg [5:0] cnt2; wire add_cnt2; wire end_cnt2; always@(posedge clk or negedge rst_n)begin if(rst_n==1'b0)begin cnt2<=0; end else if(add_cnt2)begin if(end_cnt2) cnt2<=0; else cnt2<=cnt2+1; end end assign add_cnt2 = 1; assign end_cnt2 = add_cnt2 && cnt2 == 50-1; always@(posedge clk or negedge rst_n)begin if(rst_n==1'b0)begin convst_a<=0; end else if(add_cnt2 && cnt2 == 50-2)begin convst_a<=1; end else if(end_cnt1)begin convst_a<=0; end end assign middle = add_cnt0 && cnt0 == 25-1; always@(posedge clk or negedge rst_n)begin if(rst_n==1'b0)begin adc_sclk<=1; end else if(add_cnt0 && cnt0 == 25-1 && cnt1 >= 1 && cnt1 < 33)begin adc_sclk<=0; end else if(end_cnt0)begin adc_sclk<=1; end end always@(posedge clk or negedge rst_n)begin if(rst_n==1'b0)begin adc_cs<=1; end else if(busy_int)begin adc_cs<=0; end else if(add_cnt0 && cnt0 == 25-1&& cnt1 == 34-1 )begin adc_cs<=1; end end always@(posedge clk or negedge rst_n)begin if(rst_n==1'b0)begin adc_din <=0; end else if(end_cnt0 && cnt1 < 16)begin adc_din <=data[15-cnt1]; end end parameter WRITE = 1'b1; parameter PM = 2'b11; parameter SEQ = 1'b0; parameter SHDOW = 1'b0; parameter RANGE = 1'b0; parameter CODING = 1'b1; wire [15:0] data; assign data = {WRITE,SEQ,1'b0,cnt2,PM,SHDOW,1'b0,RANGE,CODING,4'b0}; always@(posedge clk or negedge rst_n)begin if(rst_n==1'b0)begin dout <=0; end else if(middle && cnt1 >= 1 && cnt1 < 17 )begin dout[16-cnt1] <=adc_dout; end end always@(posedge clk or negedge rst_n)begin if(rst_n==1'b0)begin dout_vld <=0; end else begin dout_vld <=end_cnt2; end end // //******************************FMS********************************* //第一段:同步时序的always模块,格式化描述次态迁移到现态寄存器 always@(posedge clk or negedge rst_n)begin if(rst_n==1'b0)begin state_c <=IDLE; end else begin state_c <=state_n; end end //第二段:组合逻辑的always模块,描述状态转移条件 always@(*)begin case(state_c) IDLE:begin if(idle2s1_start)begin state_n = S1; end else begin state_n = state_c; end end S1:begin if(s12s2_start)begin state_n = S2; end else begin state_n = state_c; end end S2:begin if (s22idl_start)begin state_n = IDLE, end else begin state_n = state_c; end end default:begin state_n = IDLE; end endcase end //第二段:定义状态转移条件。 assign idle2s1_start = state_c==IDLE&&; assign s12s2_start = state_c==Sl &&; assign s22idl_start = state_c==S2 &&; //第四段:设计输出明德扬规范要求一个always设计一个信号, //因此有多少个输出信号,就有多少个always。 // always @(posedge clk or negedge rst n)begin if(!rst_n)begin outl<=1b0; end else if(state_c==Sl)begin outl<=1b1; end else begin outl <=1b0; end end // //计算二进制位宽 function integer clogb2(input integer number); begin for (clogb2=0;number>0;clogb2=clogb2+1;) number =number>>1; end endfunction //---fifo mdy --输出信号为时序逻辑--showhead模式 input data_in_vld; input[DATA_W-1:0]data_in; output [DATA_W-1:0] data_out; always @(*)begin if(wrusedw>=61) wrreq =0: else wrreq = data_in_vld;//组合逻辑 end // fifo ahead#(.DATA W(DATA W),.DEPT W(64))u fifo( .aclr (~rst_n ), .data (data_in), .rdclk (clk_out), .rdreq (rdreq),// .wrclk (clk_in), .wrreq (wrreq),// .q (q), .rdempty(rdempty), .wrusedw(wrusedw) ); //读使能必须判断空状态,并且用组合逻辑产生 //rdreq必须由组合逻辑产生,原因与empty有关 //empty在时钟上升沿后产生; //empty==1时,当拍读使能就不准有效。 //读写隔离规则是指:读控制和写控制是独立的,他们之间除了用FIFO交流信息外,不能有任何信息传递。不能根据FIFO的读状态或者读出的数据来决定写行为,也不能根据FIFO的写状态和写的数据来决定读行为。 //wrusedw与rdusedw区别,都是表示FIFO存有多少个数据,只是时钟域不一样 //第一种情况 assign rdreq =b_rdy==1 && rdempty==0;//组合逻辑 // always@(posedge clk_out or negedge rst_n)begin if(rst_n==1'b0)begin data_out<= 0: end else begin data_out<= q; end end //第二种情况,进来16bit,深度64,输出8bit fifo 还是16bit进16bit出 input data_in_vld; input[DIN_W-1:0]data_in;// reg [DOUT_W-1:0] data_out; reg data_out_vld; reg wrreq; wire rdreq; wire [DIN_W-1:0] q; wire [5:0] wrusedw; reg [5:0] cnt0; wire add_cnt0; wire end_cnt0; always@(posedge clk_out or negedge rst_n)begin if(rst_n==1'b0)begin cnt0<=0; end else if(add_cnt0)begin if(end_cnt0) cnt0<=0; else cnt0<=cnt0+1; end end assign add_cnt0 = b_rdy==1 && rdempty==0; assign end_cnt0 = add_cnt0 && cnt0 == 2-1; assign rdreq = end_cnt0; always@(posedge clk_out or negedge rst_n)begin if(rst_n==1'b0)begin data_out<= 0: end else begin data_out<= q[DIN_W-1-DOUT_W*cnt0 -:DOUT_W]; end end // always@(posedge clk_out or negedge rst_n)begin if(rst_n==1'b0)begin data_out_vld<= 0: end else begin data_out_vld<= add_cnt0; end end // //第三种情况,进来8bit,深度64,输出16bit fifo 是16bit进16bit出 input data_in_vld; input[DIN_W-1:0]data_in;// input data_in_vld;// reg [DOUT_W-1:0] data_out; reg data_out_vld; reg wrreq; reg [DOUT_W-1:0] data; wire rdreq; wire [DIN_W-1:0] q; wire [5:0] wrusedw; reg [0:0] cnt0; wire add_cnt0; wire end_cnt0; always@(posedge clk_in or negedge rst_n)begin if(rst_n==1'b0)begin cnt0<=0; end else if(add_cnt0)begin if(end_cnt0) cnt0<=0; else cnt0<=cnt0+1; end end assign add_cnt0 = data_in_vld; assign end_cnt0 = add_cnt0 && cnt0 == 2-1; // always@(posedge clk_in or negedge rst_n)begin if(rst_n==1'b0)begin wrreq<= 0: end else (wrusedw>=61)begin wrreq<= 0; end else begin wrreq<= end_cnt0; end end // always@(posedge clk_in or negedge rst_n)begin if(rst_n==1'b0)begin data<= 0: end else if(add_cnt0)begin // if(cnt0==0) // data[15:8]<= data_in; // else // data[7:0] <= data_in; // data[15-cnt0*8-:8]<= data_in; data[DOUT_W-1-cnt0*8-:8]<= data_in; end end // assign rdreq = rdempty == 0&& b_rdy == 1; // always@(posedge clk_out or negedge rst_n)begin if(rst_n==1'b0)begin data_out<= 0: end else begin data_out<= q; end end // always@(posedge clk_out or negedge rst_n)begin if(rst n==1’b0)begin data_out_vld<= 0: end else begin data_out_vld<= rdreq; end end // //第四种情况,进来16bit,深度256,输出8bit fifo 是16bit进16bit出 //包文,sop/eop input data_in_vld; assign wrreq = din_vld; assign data ={din_sop,din_eop,din}; reg [0:0] cnt0; wire add_cnt0; wire end_cnt0; always@(posedge clk_out or negedge rst_n)begin if(rst_n==1'b0)begin cnt0<=0; end else if(add_cnt0)begin if(end_cnt0) cnt0<=0; else cnt0<=cnt0+1; end end assign add_cnt0 = rdempty==0 && b_rdy == 1; assign end_cnt0 = add_cnt0 && cnt0 == 2-1; // assign rdreq =end_cnt0; // always@(posedge clk_out or negedge rst_n)begin if(rst_n==1'b0)begin dout_vld<=0; dout_sop<=0; dout_eop<=0; dout <=0; end else begin dout_vld<=add_cnt0; dout_sop<=q[17] && add_cnt0 && cnt0 ==0; dout_eop<=q[16] && end_cnt0; dout <=q[15-cnt0*8-:8]; end end //第五种情况,进来8bit,深度64,输出16bit fifo 是16bit进16bit出 //包文,sop/eop mty input data_in_vld; input[DIN_W-1:0]data_in;// input data_in_vld;// reg [DOUT_W-1:0] data_out; reg data_out_vld; reg wrreq; reg [DOUT_W-1:0] data; wire rdreq; wire [DIN_W-1:0] q; wire [5:0] wrusedw; reg [0:0] cnt0; wire add_cnt0; wire end_cnt0; always@(posedge clk_in or negedge rst_n)begin if(rst_n==1'b0)begin cnt0<=0; end else if(add_cnt0)begin if(end_cnt0) cnt0<=0; else cnt0<=cnt0+1; end end assign add_cnt0 = din_vld; assign end_cnt0 = add_cnt0 && (cnt0 == 2-1 || din_eop); // always@(posedge clk_in or negedge rst_n)begin if(rst_n==1'b0)begin fifo_din<=0; end else if(add_cnt0)begin fifo_din[15-cnt0*8-:8]<= din; end // else if(add_cnt0 &&cnt0 ==1-1)begin // fifo_din[15:8]<=din; // end // else if(add_cnt0 &&cnt0 ==2-1)begin // fifo_din[7:0]<=din; // end end // always@(posedge clk_in or negedge rst_n)begin if(rst_n==1'b0)begin fifo_sop<=0; end else if(din_vld && din_sop) begin fifo_sop<=1; end else if(wrreq) begin fifo_sop<=0; end end // always@(posedge clk_in or negedge rst_n)begin if(rst_n==1'b0)begin fifo_eop<=0; end else begin fifo_sop<=din_eop; end end // always@(posedge clk_in or negedge rst_n)begin if(rst_n==1'b0)begin fifo_mty<=0; end else if(din_eop && add_cnt0 && cnt0 == 1-1)begin fifo_mty<=1; end else begin fifo_sop<=0; end end // assign data = {fifo_sop,fifo_eop,fifo_mty,fifo_din}; // always@(posedge clk_in or negedge rst_n)begin if(rst_n==1'b0)begin wrreq<=0; end else begin wrreq<=end_cnt0; end end // assign rdreq = rdempty==0&& b_rdy==1; // always@(posedge clk_out or negedge rst_n)begin if(rst_n==1'b0)begin dout_vld<=0; dout_sop<=0; dout_eop<=0; dout_mty<=0; dout <=0; end else begin dout_vld<=rdreq ; dout_sop<=q[18] ; dout_eop<=q[17] ; dout_mty<=q[16] ; dout <=q[15:0]; end end //----匹配位宽 function integer clogb2(input integer depth); begin if(depth==0) clogb2=1;// else if(depth!=0) for (clogb2=0;depth>0;clogb2=clogb2+1) depth =depth>>1; end endfunction //---使用案例 parameter DATA_W = 8; parameter DEPT_W =256; parameter DEPT_W_C = clogb2(DEPT_W)-1; output [DEPT_W_C-1:0] rdusedw; // // //DDR3 MIG AXI 配置 assign M_AXI_AWBURST[1:0] = 2'b01; //自增模式 // //Verilog中数据的截取 //Verillog支持指定 bit 位后固定位宽的向量域选择访问。 //[bit + : width] : 从起始 bit 位开始递增,位宽为 width。 //[bit - : width] : 从起始 bit 位开始递减,位宽为 width。 //下面 2 种赋值是等效的 A = data1[31-: 8] ; A = data1[31:24] ; //下面 2 种赋值是等效的 B = data1[0+ : 8] ; B = data1[0:7] ; // //for 作用是复制代码 //理解:将代码展开,再看展开后电路 reg [DIN_WIDTH-1:0] din_array [N-1:0];//N个DIN_WIDTH位存储器 reg [7:0] i; always@(posedge adc_clk or posedge rst)begin if(rst==1'b1)begin for (i=0; i<N; i=i+1)begin din_array[i] <= 'd0; end end else begin din_array[0] <= din;//滑动赋值 for (i=0; i<N-1; i=i+1)begin din_array[i+1] <= din_array[i]; end end end //---------修改版 always@(posedge adc_clk or posedge rst)begin if(rst==1'b1)begin for (i=0; i<N; i=i+1)begin din_array[i] <= 'd0; end end else begin for (i=0; i<N; i=i+1)begin if(i==0) din_array[0] <= din;//滑动赋值 else din_array[i] <= din_array[i-1]; end end end //-----延时--等价 always@(posedge clk_in or negedge rst_n)begin if(rst_n==1'b0)begin data<=0; end else begin data[0]<= din; data[1]<=data[0]; data[2]<=data[1]; data[3]<=data[2]; end end //1.找规律2.一般:data[i]<=data[i-1] 3.例外:i==0时 always@(posedge clk_in or negedge rst_n)begin if(rst_n==1'b0)begin data<=0; end else begin for (i=0; i<4; i=i+1)begin if(i==0) data[i]<=din; else data[i]<=din[i-1]; end end end // always@(posedge clk_in or negedge rst_n)begin if(rst_n==1'b0)begin data<=0; end else begin data[3:0] <= din; data[7:4] <=data[3:0] ; data[11:8] <=data[7:4] ; data[15:12]<=data[11:8]; end end //1.括号范围与i联系起来2.高边界是以4递增,4*i;i-0,为3,所以4*(+1)-1 3.底边界,总是比高边界少4 always@(posedge clk_in or negedge rst_n)begin if(rst_n==1'b0)begin data<=0; end else begin for (i=0; i<4; i=i+1)begin if(i==0) data[4*(i+1)-1 -:4]<=din; else data[4*(i+1)-1 -:4]<=data[4*i-1 -:4]; end end end //XILINX ip dds --频率控制字 = fout_clk*2^(相位位宽)/fin_clk //---------------------bram_ture_dual_port------------------------------------ module bram_ture_dual_port #( parameter C_ADDR_WIDTH = 8, parameter C_DATA_WIDTH = 8 )( input wire clka , input wire wea , input wire [C_ADDR_WIDTH-1:0] addra , input wire [C_DATA_WIDTH-1:0] dina , output reg [C_DATA_WIDTH-1:0] douta , input wire clkb , input wire web , input wire [C_ADDR_WIDTH-1:0] addrb , input wire [C_DATA_WIDTH-1:0] dinb , output reg [C_DATA_WIDTH-1:0] doutb ); //---------------------------------------------------------------------- localparam C_MEM_DEPTH = {C_ADDR_WIDTH{1'b1}}; reg [C_DATA_WIDTH-1:0] mem [C_MEM_DEPTH:0]; integer i; initial begin for(i = 0;i <= C_MEM_DEPTH;i = i+1) mem[i] = 0; end always @(posedge clka) begin if(wea == 1'b1) mem[addra] <= dina; else douta <= mem[addra]; end always @(posedge clkb) begin if(web == 1'b1) mem[addrb] <= dinb; else doutb <= mem[addrb]; end endmodule
波形图规则 观察波形的规则,只要记住在不确定的信号处均选择前面的信号,就一定不会出错 1.360云盘下载地址:tp://yunpan.cnQ7c6Sx9f6fih4 提取码 ecaa 视图模式 i---->编辑模式Esc--->视图模式 视图模式 ctrl +q---->列操作模式 操作完退出--->视图模式 //视图模式 1.搜索命令(*,/,/\/,n.N)2.文件内跳转(gg,G, :100) 3.替换命令(:%s/xxyx/ge::10:100s/xx/y/ge)4.删除复制命令(ctrltc.ctrl y 5.分窗口(:y.:sp,:q) //时序逻辑和组合逻辑写法 明德扬规范要求: (1)时序逻辑的敏感信号必须是:(posedge clk or negedge rst n) (2)组合逻辑写法always@(*) (3)只允许用always,不用assign; (4)一个always里面只允许设计一个输出,但可以有多个输入。 注意要点:a组合逻辑不能作为时钟、复位信号: b.组合逻辑一定要写else,避免生成锁存器 //阻塞赋值和非阻塞赋值 明德扬规范要求: 时序逻辑里面使用非阻塞赋值,即“<=”; 组合逻辑里面使用阻塞赋值,即用“=” 注意要点: 非阻塞赋值必须根据时钟沿触发, 阻塞赋值是无视时钟的。 begin end以及信号的对齐 明德扬规范要求: (1)always、条件之间,必须加begin和end; (2)begin统一在括号后面,end与begin一行开始处对齐,内部内 容空4格开始编写。 (3)模块的信号定义,必须对齐,包括类型、位宽定义、信号名等的对齐; 信号大小写的规范 明德扬规范要求: (1)参数、宏定义,必须大写,信号必须小写: 明德扬规范要求: (1)一个模块只使用一个时钟,该模块中,任何时序逻辑敏感信引中的时钟,必须为该时钟。名称默认为clk; (2)禁止用计数器分频后的信号做其他模块的时钟,而要用改成时钟使能的方式: (3)复位信号默认低电平有效,名称为rst_n; 明德扬规范要求: (1)reg常用来表示用于“always”模块内的指定信号的类型,常代表触发器,在always里面赋值的信号都必须定义为reg类型; (2)wire 类型信号表示线,常用于模块例化等, 注意要点:reg类型在代码综合后可能综合成时序逻辑,也可能是组合逻 辑 明德扬规范要求: (1)输出信号必须是寄存器直接输出,不能用wire类型数据作为的输出---减少亚稳态概率 (2)输入输出的信号声明只能一行写一个,例如:input cIk;input rst n; output key等; 明德扬特色指令: (1)Shixu:输出时序逻辑的模板代码部分; (2)Zuhe:输出组合逻辑的模板代码部分; (3)Module:输出整个模块模板部分代码; (4)Test:输出测试文件的模板部分代码。 注意要点:要严格按照Gvim的破解流程来安装Gvim,否则将不会有明德扬特色命令。 // 组合逻辑 // (1)锁存器的组成特性: // 是有门逻辑资源搭建起来的电平敏感的储器, // 由于电平触发,所以对时钟边沿不敏感; // 相比于寄存器所需的门逻辑资源要少, // 常用于ASIC设计中, // (2)设计缺点: // 1)属于非同步设计,不易于信号控制; // 2)没有边沿触发,输出的信号会有毛刺: // 3)使时序分析变得困难 // (3)避免方法:补全if和case语句,避免条件缺失。 // 规范设计时钟复位信号注意要点 1.因为时钟和复位非常重要, 会影响整个系统的稳定, 因此FPGA对时钟和复位信号经过特别优化: 2.D寄存器的时钟和复位, 均是边缘敏感的, 因此中间信号有可能产生的毛刺, 会不小心触发D寄存器: 3.软件需要分析寄存器之间是否满足时序要求, 这是基于同一时钟来分析的。 内部信号当时钟,会增加分析的困难。 本节视频讲了FPGA开发中时钟和复位设计规范, //主要就是不能拿中间信号当时钟和复位信号。 //----------------Modelism---------------------- //一、时序逻辑的波形观看方法 //要点:时钟上升沿前看输入,时钟上升沿后看输出 //二、组合逻辑的波形观看方法 //要点:输入变输出即刻变 //【时间标尺】 //格式:'timescale 仿真时间单位/时间精度 //举例:timescale lns/100ps 表示时延单位为lns,时延精度为100ps //注意:时间单位>=时间精度 // `timescale 1ns / 1ns module test(); //时钟与复位 reg clk; reg rst_n; //uut的输入信号 reg [3:0] din0; reg din1; //uut的输出信号 wire [3:0] dout0; wire dout1; //时钟周期,单位为ns, parameter CYCLE = 20; //复位时间,此时表示复位3个时钟周期的时间 parameter RST_TIME = 3; //待测试的模块例化 module_name uut( .clk (clk ), .rst_n (rst_n), .din0 (din0 ), .din1 (din1 ), .dout0 (dout0), .dout1 (dout1), ... ); //生成本地时钟50M initial begin clk =0; forever #(CYCLE/2) clk =~clk; end //产生复位信号 initial begin rst_n =1; #2; rst_n =0; #(CYCLE*RST_TIME) rst_n =1; end //输入信号din0赋值方式 initial begin #1; //赋初值 din0 =0; #(CYCLE*10) //开始赋值 end //输入信号din1赋值方式 initial begin #1; //赋初值 din1 =0; #(CYCLE*10) //开始赋值 end //输入信号din initial begin #1; din0 =0; //赋初值 forever #(CYCLE*2) din = ($random)%2; end
`timescale 1ns / 1ps module tb_encoder; parameter CYC = 8, //--->125MHz CYC_60K = 20_0, RST_TIME = 5; // initial begin clk = 0; forever #(CYC/2) clk = ~clk; initial begin clk_60k = 0; forever #(CYC_60K/2) clk_60k = ~clk_60k; end initial fork begin #100; encoder_a=1; forever begin #(CYC_60K/2); encoder_a= ~encoder_a; end end join initial fork begin #150; encoder_b=1; forever begin #(CYC_60K/2); encoder_b= ~encoder_b; end end join // // always @(posedge clk_60k or negedge rst_n) begin // if (~rst_n) encoder_a <= 1'b0; // else encoder_a <= ~encoder_a; // end // always @(negedge clk_60k or negedge rst_n) begin // if (~rst_n) encoder_b <= 1'b0; // else encoder_b <= ~encoder_b; // end
1 //——————— —————————————————————————————————— 2 // |____________________________________________| 3 // 4 //实现步骤 5 //请按以下“6步法”实现:t 6 //1、在给出 clk 的波形图上画出输入、输出波形(根据功能要求,画出输入和输出的波形) 7 //2、在给出 clk 的波形图上画出计数器(步 1 中,需要“数多个”的信号,用计数器标出来) 8 //3、确认加1条件、结束条件(加1条件:计数器数什么;结束条件:计数器周期数多少个不同值时用变量法。有多少个计数器,就有多少个。) 9 //4、其它信号变化点条件(其他信号:即输出或内容信号;变化点:0变11变0的点) 10 // 11 // 12 reg [5:0] cnt0; 13 wire add_cnt0; 14 wire end_cnt0; 15 always@(posedge clk or negedge rst_n)begin 16 if(rst_n==1'b0)begin 17 cnt0<=0; 18 end 19 else if(add_cnt0)begin 20 if(end_cnt0) 21 cnt0<=0; 22 else 23 cnt0<=cnt0+1; 24 end 25 end 26 assign add_cnt0 = 1; 27 assign end_cnt0 = add_cnt0 && cnt0 == 50-1; 28 29 reg [5:0] cnt1; 30 wire add_cnt1; 31 wire end_cnt1; 32 always@(posedge clk or negedge rst_n)begin 33 if(rst_n==1'b0)begin 34 cnt1<=0; 35 end 36 else if(add_cnt1)begin 37 if(end_cnt1) 38 cnt1<=0; 39 else 40 cnt1<=cnt1+1; 41 end 42 end 43 assign add_cnt1 = end_cnt0; 44 assign end_cnt1 = add_cnt1 && cnt1 == 34-1; 45 46 reg [5:0] cnt2; 47 wire add_cnt2; 48 wire end_cnt2; 49 always@(posedge clk or negedge rst_n)begin 50 if(rst_n==1'b0)begin 51 cnt2<=0; 52 end 53 else if(add_cnt2)begin 54 if(end_cnt2) 55 cnt2<=0; 56 else 57 cnt2<=cnt2+1; 58 end 59 end 60 assign add_cnt2 = 1; 61 assign end_cnt2 = add_cnt2 && cnt2 == 50-1; 62 63 always@(posedge clk or negedge rst_n)begin 64 if(rst_n==1'b0)begin 65 convst_a<=0; 66 end 67 else if(add_cnt2 && cnt2 == 50-2)begin 68 convst_a<=1; 69 end 70 else if(end_cnt1)begin 71 convst_a<=0; 72 end 73 end 74 75 assign middle = add_cnt0 && cnt0 == 25-1; 76 always@(posedge clk or negedge rst_n)begin 77 if(rst_n==1'b0)begin 78 adc_sclk<=1; 79 end 80 else if(add_cnt0 && cnt0 == 25-1 && cnt1 >= 1 && cnt1 < 33)begin 81 adc_sclk<=0; 82 end 83 else if(end_cnt0)begin 84 adc_sclk<=1; 85 end 86 end 87 88 always@(posedge clk or negedge rst_n)begin 89 if(rst_n==1'b0)begin 90 adc_cs<=1; 91 end 92 else if(busy_int)begin 93 adc_cs<=0; 94 end 95 else if(add_cnt0 && cnt0 == 25-1&& cnt1 == 34-1 )begin 96 adc_cs<=1; 97 end 98 end 99 100 always@(posedge clk or negedge rst_n)begin 101 if(rst_n==1'b0)begin 102 adc_din <=0; 103 end 104 else if(end_cnt0 && cnt1 < 16)begin 105 adc_din <=data[15-cnt1]; 106 end 107 end 108 109 parameter WRITE = 1'b1; 110 parameter PM = 2'b11; 111 parameter SEQ = 1'b0; 112 parameter SHDOW = 1'b0; 113 parameter RANGE = 1'b0; 114 parameter CODING = 1'b1; 115 116 wire [15:0] data; 117 assign data = {WRITE,SEQ,1'b0,cnt2,PM,SHDOW,1'b0,RANGE,CODING,4'b0}; 118 119 always@(posedge clk or negedge rst_n)begin 120 if(rst_n==1'b0)begin 121 dout <=0; 122 end 123 else if(middle && cnt1 >= 1 && cnt1 < 17 )begin 124 dout[16-cnt1] <=adc_dout; 125 end 126 end 127 128 always@(posedge clk or negedge rst_n)begin 129 if(rst_n==1'b0)begin 130 dout_vld <=0; 131 end 132 else begin 133 dout_vld <=end_cnt2; 134 end 135 end 136 // 137 //******************************FMS********************************* 138 //第一段:同步时序的always模块,格式化描述次态迁移到现态寄存器 139 always@(posedge clk or negedge rst_n)begin 140 if(rst_n==1'b0)begin 141 state_c <=IDLE; 142 end 143 else begin 144 state_c <=state_n; 145 end 146 end 147 //第二段:组合逻辑的always模块,描述状态转移条件 148 always@(*)begin 149 case(state_c) 150 IDLE:begin 151 if(idle2s1_start)begin 152 state_n = S1; 153 end 154 else begin 155 state_n = state_c; 156 end 157 end 158 S1:begin 159 if(s12s2_start)begin 160 state_n = S2; 161 end 162 else begin 163 state_n = state_c; 164 end 165 end 166 S2:begin 167 if (s22idl_start)begin 168 state_n = IDLE, 169 end 170 else begin 171 state_n = state_c; 172 end 173 end 174 default:begin 175 state_n = IDLE; 176 end 177 endcase 178 end 179 //第二段:定义状态转移条件。 180 assign idle2s1_start = state_c==IDLE&&; 181 assign s12s2_start = state_c==Sl &&; 182 assign s22idl_start = state_c==S2 &&; 183 //第四段:设计输出明德扬规范要求一个always设计一个信号, 184 //因此有多少个输出信号,就有多少个always。 185 // 186 always @(posedge clk or negedge rst n)begin 187 if(!rst_n)begin 188 outl<=1b0; 189 end 190 else if(state_c==Sl)begin 191 outl<=1b1; 192 end 193 else begin 194 outl <=1b0; 195 end 196 end 197 // 198 //计算二进制位宽 199 function integer clogb2(input integer number); 200 begin 201 for (clogb2=0;number>0;clogb2=clogb2+1;) 202 number =number>>1; 203 end 204 endfunction 205 // 206 //DDR3 MIG AXI 配置 207 assign M_AXI_AWBURST[1:0] = 2'b01; //自增模式 208 // 209 //Verilog中数据的截取 210 //Verillog支持指定 bit 位后固定位宽的向量域选择访问。 211 //[bit + : width] : 从起始 bit 位开始递增,位宽为 width。 212 //[bit - : width] : 从起始 bit 位开始递减,位宽为 width。 213 //下面 2 种赋值是等效的 214 A = data1[31-: 8] ; 215 A = data1[31:24] ; 216 //下面 2 种赋值是等效的 217 B = data1[0+ : 8] ; 218 B = data1[0:7] ; 219 // 220 // 221 reg [DIN_WIDTH-1:0] din_array [N-1:0];//N个DIN_WIDTH位存储器 222 reg [7:0] i; 223 always@(posedge adc_clk or posedge rst)begin 224 if(rst==1'b1)begin 225 for (i=0; i<N; i=i+1)begin 226 din_array[i] <= 'd0; 227 end 228 end 229 else begin 230 din_array[0] <= din;//滑动赋值 231 for (i=0; i<N-1; i=i+1)begin 232 din_array[i+1] <= din_array[i]; 233 end 234 end 235 end 236 //
posted on 2024-07-19 14:13 taylorrrrrrrrrr 阅读(8) 评论(0) 收藏 举报
浙公网安备 33010602011771号