天天看点

Verilog7-常用电路(1)能用Verilog 描述的常用电路结构:第六章

文章目录

  • 能用Verilog 描述的常用电路结构:
    • 1、D触发器
    • 2、计数器
    • 3、分频
      • 3.1 奇数倍分频
      • 3.2 偶数倍分频
      • 3.3 小数分频(如1.5倍)
    • 4、多路选择器
    • 5、加法器
      • 5.1 超前进位加法器
    • 6、乘法器
      • 6.1 加法器树乘法器
    • 7、数据比较器
    • 8、数字编码、译码器
    • 9、序列发生器
      • 9.1 序列发生器
      • 9.2伪随机码发生器
    • 10、序列检测器
      • 10.1 状态图(FSM)
      • 两段式状态机
      • 3段式状态机
    • 11、FIFO
    • 12、读存储器数据
    • 13、时钟信号
      • 13.1 占空比50%的时钟信号
      • 13.2 占空比可设置的时钟信号
      • 13.3 产生具有相位偏移的时钟信号
      • 13.3 产生固定数目的时钟信号
    • 14 UDP
  • 第六章
    • 1、加法器树乘法器
    • 2、Wallace树乘法器 —— 专题
    • 3、复数乘法器
    • 4、FIR滤波器
    • 5、RAM
    • 6、ROM
    • 7、FIFO
    • 8、CORDIC算法 —— 专题
    • 9、UART总线
    • 10、SPI接口控制器

能用Verilog 描述的常用电路结构:

1、D触发器

//D触发器,—— 行为级描述
module D(q,d,clk);
    input d,clk;
	output q;
	reg q;
	always @(posedge clk)
        begin
            q<=d;
        end
endmodule
//测试代码,调用写好的模块,给其加激励
`timescale 1ns/1ns

module test;
    reg d,clk;
    wire q;
    D U1(q,d,clk);
    always #10 clk=~clk;		//连续赋值语句,数据流模型
    initial						// 过程赋值语句,只能对reg型
        begin
            clk = 0;
            #20 d=1;
            #20 d=0;
            #20 d=1;
            #20 d=0;
            #20 d=1;
            #20 d=0;
            #20 d=1;
            #200 $finish;
        end
endmodule
            
//8位D触发的移位寄存器
module D(q,d,clk);
    input d,clk;
    output q;
    wire d;
    wire[7:0] q;
    D U2(q[1],q[0],clk);
    D u3(q[2],q[1],clk);
    D u4(q[3],q[2],clk);
    D u5(q[4],q[3],clk);
    D u6(q[5],q[4],clk);
    D u7(q[6],q[5],clk);
    D u8(q[7],q[6],clk);
endmodule

module D(q,d,clk);
    input d,clk;
    output q;
    reg q;
    always @(posedge clk)	//过程赋值语句,只能对reg型
        begin
            q<=d;
        end
endmodule

//测试程序
`timescale 1ns/1ns
module test;
    reg d,clk;
    wire[7:0] q;
    D U1(q,d,clk);
    always #10 clk=~clk;
    initial
        begin
            clk=0;
            #10 d=1;
            #150 d=0;
            #150 d=1;
            #900 $stop;
        end
endmodule
           

2、计数器

//always 描述同步置数,异步清零计数器
module counter(out,data,load,rst,clk);
    output[7:0] out;
    input[7:0] data;
    input load,rst,clk;
    reg[7:0] out;
    always @(posedge clk or rst)
        begin
            if(!rst)
                out=0;
            else if(load)
                out=data;
            else
                out=out+1;
        end
endmodule

//4.1-1 8bit计数器
module counter(count,clk,reset);
    output count;
    input clk,reset;
    reg[7:0] count;
    reg out;
    always @(posedge clk)
        begin
            if(!reset)
            	count<=0;
            else if(count==8'b11111111)
        		count <= 0;
    		else
        		count = count+1;
        end
endmodule  
           

3、分频

3.1 奇数倍分频

3.2 偶数倍分频

3.3 小数分频(如1.5倍)

4、多路选择器

// 多路选择器 —— 4选1数据选择器
module mux(out,data,sel);
    output out;
    input[3:0] data;
    input[1:0 sel;
    reg out;
    always@(data or sel)
        case(sel)
            2'b00:out <= data[0];
            2'b01:out<=data[1];
            2'b10:out<=data[2];
            2'b11:out<=data[3];
            endcase
endmodule
           

5、加法器

//加法器_连续赋值语句实现
module one_bit_fulladder(SUM,C_OUT,A,B,C_IN);
    output SUM,C_OUT;
    input A,B,C_IN;
    begin
    	assign SUM=(A^B)^C_IN;
    	assign C_OUT=(A&B)|(A&C_IN)|(B&C_IN);
    end
endmodule

//加法器_行为描述方式
module one_bit_fulladder(SUM,C_OUT,A,B,C_IN);
    output SUM,C_OUT;
    input A,B,C_IN;
    begin
        assign {C_OUT,SUM}=A+B+C_IN;
    end
endmodule

/行为级描述可以提高设计效率-2输入8bit加法器
module eight_bit_fulladder(SUM,C_OUT,A,B,C_IN);
    output[7:0] SUM;
    output C_OUT;
    input[7:0] A,B;
    input C_IN;
    begin
        assign {C_OUT,SUM}=A+B+C_IN;
    end
endmodule  
           

5.1 超前进位加法器

//超前进位加法器:每级进位由附加的组合电路产生,高位的运算不需要等待低位的运算完成—— 可提高运算速度
//理解:就是将进位公式转化为最基本的表示,使得进位不依赖于求和和前级运算
module four_bits_fast_adder(sum_out,c_out,a,b,c_in);
    output[3:0] sum_out;
    output c_out;
    input[3:0] a,b;
    input c_in;
    wire[4:0] g,p,c;
    assign c[0]=c_in;
    assign g=a&b;
    assign p=a^b;
    assign c[1]=g[0]|(p[0]&c[0]);
    assign c[2]=g[1]|(p[1]&(g[0]|(p[0]&c[0])));
    assign c[3]=g[2]|(p[2]&(g[1]|(p[1]&(g[0]|(p[0]&c[0])))));
    assign c[4]=g[3]|(p[3]&(g[2]|(p2&(g[1]|(p[1]&(g[0]|(p[0]&c[0])))))));
    assign sum_out=p^c[3:0];
    assign c_out=c[4];
endmodule
           

6、乘法器

6.1 加法器树乘法器

  • 乘法器逻辑:类似十进制数相乘
    • 思路:”移位后加“。乘数逐位与被乘数相乘(补0保持位置正确),然后相加
    • 注意:二进制数只有0,1,可以判断乘数的每一位是0或1决定每次乘积的结果(其余位补0,保证乘积位置正确,不发生偏移),然后相加即可
//4位加法器树乘法器
module mul_addtree(a,b,out);
    output[7:0] out;
    input[3:0] a,b;
    wire[7:0] out;
    wire[3:0] stored0,stored1,stored2,stored3;
    wire[3:0] add01,add23;
    //若乘数某一位是1,则乘积为:被乘数置于对应位,其余位补0,保证8位不会错位
    assign stored3=b[3]?{1'b0,a,3'b0}:8'b0;
    assign stored2=b[2]?{2'b0,a,2'b0}:8'b0;
    assign stored1=b[1]?{3'b0,a'1'b0}:8'b0;
    assign stored0=b[0]?{4'b0,a}:8'b0;
    //将乘数逐位相乘的结果相加,得到最终结果
    assign add01=stored1+stored0;
    assign add23=stored3+stored2;
    assign out=add01+add23;
endmodule
//***************测试代码***************
module mul_addtree_tb;
    reg[3:0]a,b;
    wire[7:0]out;
    //模块例化
    mul_addtree U1(.a(a),.b(b),.out(out));
    //测试信号
    initial
        begin
            a=0,b=0;
            repeat(9)
                begin
                    #20 a=a+1;
                b=b+1;
                end
        end
endmodule
           

7、数据比较器

//数据比较器
module four_bits_comp1(F,A,B,C);
    parameter comp_width=4;
    output[2:0] F;
    input[2:0] C;
    input[comp_width-1:0] A;
    input[comp_width-1:0] B;
    reg[2:0] F;
    begin
        always@(A,B,C)
            if(A>B)			F<=3'b100;
        	else if(A<B) 	F=3'b001;
        	else 			F=C;
    end
endmodule
           

8、数字编码、译码器

//数字编码器

           

9、序列发生器

9.1 序列发生器

  • 产生 100111 序列
//反馈移位寄存器
//2^n,六位,n>=3;n=3时有重复,n=4时,1001,0011,0111,1111,1110,1100,产生反馈激励表,得到反馈函数F
module signal_maker(out,clk,load,D);
    parameter M=4;
    output out;
    input clk,load;
    input[M-1:0] D;
    reg[M-1:0] D;
    wire w1;
    always@(posedge clk)
        if(load)
            Q<=D;
    	else
            Q<={Q[M-2:0],w1};
    assign w1=(~Q[3])|(~Q[1]&(~Q[0]))|(Q[3]&(~Q[2]));
    assign out=Q[M-1];
endmodule
           

9.2伪随机码发生器

//4.3-10 伪随机码发生器(N=4)
module signal15(out,clk,load_n,D_load);
    output out;
    input load_n.clk;
    input[3:0] D_load;
    reg[3:0] Q;
    wire F;
    begin
        always@(posedge clk)
            if(~load_n)		Q<=D_load;
        	else			Q<={Q[2:0],F};
        assign F=(Q[1]^Q[0])|(~Q[3]&~Q[2]&~Q[1]&~Q[0]);
        assign out=Q[3];
    end
endmodule
           

10、序列检测器

10.1 状态图(FSM)

//111序列检测器——状态转换图
module checker(Z,X,clk);
    parameter s0=2'b00,s1=2'b01,s2=2'b11,s3=2'b10;
    output Z;
    input X,clk;
    reg[1:0] state,next_state;
    reg Z;
    always @(X,state)
        case(state)
            s0:if(X)
                begin
                    next_state=s1;	//阻塞赋值
                    Z=0;
                end
            else
                begin
                    next_state<=s0;
                    Z=0;
                end
            s1:if(X)
                begin
                	next_state<=s2;
            		Z=0;
                end
            else
                begin
                	next_state<=s0;
            		Z=0;
                end
            s2:if(X)
                begin
                    next_state<=s3;
                    Z=1;
                end
            else
                begin
                    next_state<=s0;
                    Z=0;
                end
            s3:if(X)
                begin
                    next_state<=s3;
                    Z=1;
                end
            else
                begin
                    next_state<=s0;
                    Z=0
                end
        endcase
    always@(posedge clk)
        state<=next_state;
endmodule  
           

两段式状态机

always@(posedge clk or negedge rst_n) begin
    if(!rst_n)
        current_state <= IDLE;
    else
        current_state <= next_state;
end

always@(current_state or x)begin
   next_state = IDLE;
    case(current_state)
        s1:if(...) begin
            next_state = s2;	// 组合逻辑要用阻塞赋值
        	out = 1'b0;			// 一个always块中最好只对一个变量赋值,即建议使用三段式状态机
        end
        else
            ...
            
            ...
    endcase
    
end
           

3段式状态机

always@(posedge clk or negedge rst_n) begin
    if(!rst_n)
        current_state <= IDLE;
    else
        current_state <= next_state;
end

always@(current_state or x) begin
    // next_state = IDLE; 如果下面的状态完整,或有 default,这里不需要再初始化,多余
    case(current_state)
        s1:begin
            if(...)
            	// next_state <= s2;错误
            	next_state = s2;		// 组合逻辑,一定要用阻塞赋值
        	else(...)
                next_state = s3;
        end
        s2:
            ...
        default:
            
            
    endcase
end

/*            
always@(current_state or x) begin
    case(next_state)
        s1:
            out = 1'b0;
         s2:
         	if(x)
            out = 1'b1;
            else
            out = 1'b0;
         default:
             ...
    endcase
end
*/
// 上面的第三段大多数输出out都是0,这样写麻烦
reg out;
always@(posedge clk or negedge rst_n) begin
	if(!rst_n)
		out <= 1'b0;
	else if(current == s2 && x == 1'b1)
		out <= 1'b1;
end
           

三段式状态机设计

  • 三段式always块中,第一个和第三个always模块是同步时序电路,用非阻塞赋值(<=),第二个always模块是组合逻辑always模块,用阻塞赋值(=)
  • 第二部分组合逻辑always模块,敏感列表用always@(*) 或 always@(current_state or x);里面的情况要完整,可用 default 或 next_state 初始化来保证包含完全。
  • 三段式并不是一定要写3个always模块,如果有多个输出,就要更多always模块(一般最好在一个always模块中,只对一个变量赋值)

11、FIFO

  • 同步FIFO:参考《Verilog HDL数字集成电路设计与应用》
  • 异步FIFO:参考 https://www.cnblogs.com/BitArt/archive/2013/04/10/3010073.html

12、读存储器数据

task read_memory;
    input[15:0] address;
    output[31:0] data;
    reg[3:0] counter;
    reg[7:0] temp[1:4];
    begin
        for(counter=1;counter<=4;counter=counter+1)
            temp[counter]=mem[address+counter-1];
        data={temp[1],temp[2],temp[3],temp[4]};  //temp[i]是存储器的第i个寄存器,每个八位
    end
endtask
           

13、时钟信号

13.1 占空比50%的时钟信号

//基于initial语句
module clk1(clk);
    output clk;
    parameter clk_period=10;
    reg clk;
    initial
        begin
            clk=0;
            forever #clk_period clk=~clk;
        end 
endmodule
//基于always语句
module clk2(clk);
    output clk;
    parameter clk_period=10;
    reg clk;
    initial clk=0;		//如果没有对clk初始化,会出现对未知信号取反,导致clk为未知状态
    always #(clk_period/2) clk=~clk;
endmodule
           

13.2 占空比可设置的时钟信号

//通过延时控制占空比转换
module Duty_Cycle(clk);
    output clk;
    parameter High_time=5,low_time=20; //占空比=High_time/(High_time+low_time)
    reg clk;
    always
        begin
            clk=1;
            #High_time;
            clk=0;
            #low_time;
        end
endmodule
           

13.3 产生具有相位偏移的时钟信号

module shift_Duty_Cycle(clk_a,clk_b);
    output clk_a,clk_b;
    parameter High_time=5,Low_time=5,pshift_time=2;
    reg clk_a;
    wire clk_b;
    always
        begin
            clk_a=1;
            #Hign_time;
            clk_a=0;
            #Low_time;
        end
    always #pshift_time clk_b=clk_a;
endmodule
           

13.3 产生固定数目的时钟信号

module fix_num_clk(clk);
    output clk;
    parameter clk_ent=5,clk_period=2;
    reg clk;
    initial begin
        clk=0;
        repeat(clk_cnt)
            #clk_period/2 clk=~clk;
    end
endmodule
           

14 UDP

//时序电路UDP描述_D触发器
primitive D_Edge_FF(Q,Clk,Data);
    output Q;
    reg Q;
    input Data,Clk;
    initial Q=D;
    table
        //Clk Data:Q(Stata):Q(next)
        (01) 0:?:0;
        (01) 1:?:1;
        (0x) 1:1:1;
        (0x) 0:0:0;
        (?0) ?:?:-;	//忽略时钟负边沿
        ? (??):?:-;	//忽略在稳定时钟上的数据变化
    endtable
endprimitive      
           

第六章

1、加法器树乘法器

//加法器树乘法器
module mul_addtree(mul_a,mul_b,mul_out);
    input[3:0] mul_a,mul_b;
    output[7:0] mul_out;
    
    wire[7:0] mul_out;
    wire[7:0] stored0,stored1,stored2,stored3;
    wire[7:0] add01,add23;
    
    assign stored3=mul_b[3]?{1'b0,mul_a,3'b0}:8'b0;
    assign stored2=mul_b[2]?{2'b0,mul_a,2'b0}:8'b0;
    assign stored1=mul_b[1]?{3'b0,mul_a,1'b0}:8'b0;
    assign stored0=mul_b[0]?{4'b0,mul_a}:8'b0;
    assign add01=stored1+stored0;
    assign add23=stored3+stored2;
    assign mul_out=add01+add23;
endmodule
//测试代码
module mul_addtree_tb;
    reg[3:0] mult_a;
    reg[3:0] mult_b;
    wire[7:0] mult_out;
    mul_addtree U1(.mul_a(mult_a),.mul_b(mult_b),.mul_out(mult_out));
    initial
        begin
            mult_a=0;mult_b=0;
            repeat(9)
                begin
                    #20 mult_a=mult_a+1;
                    mult_b=mult_b+1;
                end
        end
endmodule
           
//两级流水线4位加法器树乘法器
//通过在第一级与第二级、第二级与第三级加法器之间插入D触发器——两级流水线
module mul_addtree(clk,clr,mul_a,mul_b,mul_out);
    input clk,clr;
    input[3:0] mul_a,mul_b;
    output[7:0] mul_out;
    
    reg[7:0] add01,add23,mul_out;
    wire[7:0] stored0,stored1,stored2,stored3;
    
    assign stored3=mul_b[3]?{1'b0,mul_a,3'b0}:8'b0;
    assign stored2=mul_b[2]?{2'b0,mul_a,2'b0}:8'b0;
    assign stored1=mul_b[1]?{3'b0,mul_a,1'b0}:8'b0;
    assign stored0=mul_b[0]?{4'b0,mul_a}:8'b0;
    
    always@(posedge clk or negedge clr)
        begin
            if(!clr)
                begin
                    add01<=8'b0;	//非阻塞赋值直接插入寄存器
                    add23<=8'b0;
                    mul_out<=8'b0;
                end
            else
                begin                 
    				add01<=stored1+stored0;
                	add23<=stored3+stored2;
     				mul_out<=add01+add23;
                end
        end
endmodule
           

2、Wallace树乘法器 —— 专题

3、复数乘法器

module complex(a,b,c,d,out_real,out_im);
    input[3:0] a,b,c,d;
    output[7:0] out_real,out_im;
    wire[7:0] sub1,sub2,add1,add2;
    wallace U1(.x(a),.y(c),.out(sub1));
    wallace U1(.x(b),.y(d),.out(sub2));
    wallace U1(.x(a),.y(d),.out(add1));
    wallace U1(.x(b),.y(c),.out(add2));
    assign out_real=sub1-sub2;
    assign out_im=add1+add2;
endmodule

module complex_tb;
    reg[3:0] a,b,c,d;
    wire[8:0] out_real,out_im;
    complex U1(.a(a),.b(b),.c(c),.d(d),.out_real(out_real),.out_im(out_im));
    initial
        begin
            a=2;b=2;c=5;d=4;
            #10
            a=4;b=3;c=2;d=1;
            #10
            a=3;b=2;c=3;d=4;
        end
endmodule
           

4、FIR滤波器

module FIR(Data_out,Data_in,clock,reset);
    output[9:0] Data_out;
    input[3:0] Data_in;
    input clock,reset;
    wire[9:0] Data_out;
    wire[3:0] samples_0,samples_1,samples_2,samples_3,
    samples_4,samples_5,samples_6,samples_7,samples_8;
    shift_register(.Data_in(Data_in),.clock(clock),.reset(reset),
                   .samples_0(samples_0),.samples_1(samples_1),.samples_2(samples_2),
                   .samples_3(samples_3),.samples_4(samples_4),.samples_5(samples_5),
                   .samples_6(samples_6),.samples_7(samples_7),.samples_8(samples_8));
    
    caculator U2(.samples_0(samples_0),.samples_1(samples_1),.samples_2(samples_2),
                 .samples_3(samples_3),.samples_4(samples_4),.samples_5(samples_5),
                 .samples_6(samples_6),.samples_7(samples_7),.samples_8(samples_8),
                 .Data_out(Data_out));
endmodule


           

5、RAM

//单口RAN:只有一套地址总线,读、写操作是分开的
module ram_single(clk,addm,cs_n,we_n,din,dout);
    input clk;
    input[2:0] addm;	//地址信号
    input cs_n;			//片选信号
    input we_n;			//写使能信号
    input[7:0] din;
    output[7:0] dout;
    reg[7:0] dout;
    reg[7:0] raml[7:0];		//8*8寄存器
    always@(posedge clk)
        begin
            if(cs_n)
                dout<=8'bz;
            else if(we_n)
                dout<=raml[addm];
            else
                raml[addm]<=din;
        end
endmodule

module ram_single_tb;
    reg clk,cs_n,we_n;
    reg[2:0] addm;
    reg[7:0] din;
    wire[7:0] dout;
    ram_single U1(.clk(clk),.addm(addm),.cs_n(cs_n),.we_n(we_n),.din(din),.dout(dout));
    initial
        begin
            clk=0;addm=0;cs_n=1;we_n=0;din=0;
            #10		cs_n=0;
            #315 	we_n=1;
        end
    always #10 clk=~clk;
    initial 
        begin
            repeat(7)
                begin
                    #40 addm=addm+1;
                    din=din+1;
                end
            #40
            repeat(7)
                #40 addm=addm+1;
        end
endmodule
           
module ram_dual(q,addr_in,addr_out,d,we,rd,clk1,clk2);
    output[7:0] q;
    input[7:0]	d;
    input[2:0]	addr_in,addr_out;	//读、写地址信号
    input we,rd;	// 读、写使能信号
    input clk1,clk2;	//读、写时钟
    reg[7:0] q;
    reg[7:0] mem[7:0];	//8*8存储器
    always @(posedge clk1)
        begin
        	if(we)
            	mem[addr_in]<=d;
        end
    always@(posedge clk2)
        begin
            if(rd)
                q<=mem[addr_out];
        end
endmodule
   
module ram_dual_tb;
    reg clk1e,clk2,we,rd;
    reg[2:0] addr_in,addr_out;
    reg[7:0] d,q;
    ram_dual U1(.q(q),.addr_in(addr_in),.addr_out(addr_out),.we(we),.rd(rd),
                .clk1(clk1),.clk2(clk2));
    initial
        begin
            clk1=0;clk2=0;we=1;rd=0;addr_in=0;addr_out=0;
            #320 we=0;
            rd=1;
        end
    always
        begin
            #10 clk1=~clk1;clk2=~clk2;
        end
    initial
        begin
            repeat(7)
                begin
                    #40 addr_in=addr_in+1;d=d+1;
                end
            #40 repeat(7)
                #40 addr_out=addr_out+1;
        end
endmodule

           

6、ROM

module rom(dout,clk,addm,cs_n);
    intput clk,cs_n;
    input[2:0] addm;
    output[7:0] dout;
    reg[7:0] dout;
    reg[7:0] rom[7:0];
    initial
        begin
            for
            rom[0]=8'b0;
            rom[1]=8'b0;
            rom[2]=8'b0;
            rom[3]=8'b0;
            rom[4]=8'b0;
            rom[5]=8'b0;
            rom[6]=8'b0;
            rom[7]=8'b0;
        end
    always@(posedge clk)
        begin
            if(cs_n)
                dout<=8'bz;
            else
                dout<=rom[addm];
        end
endmodule

module rom_tb;
    reg clk,cs_n;
    reg[2:0] addm;
    wire[7:0] dout;
    rom U1(.dout(dout),.addm(addm),.clk(clk),.cs_n(cs_n));
    initial
        begin
            clk=0;addm=0;cs_n=0;
        end
    always #10 clk=~clk;
    initial
        begin
            repeat(7)
                #20 addm=addm+1;
        end
endmodule    
           

7、FIFO

//深度为8,位宽为8bit 的FIFO
module FIFO_buffer(clk,rst,write_to_stack,read_from_stack,
                   Data_in,Data_out);
    input clk,rst;
    input write_to_stack,read_from_stack;
    input[7:0] Data_in;
    output[7:0] Data_out;
    wire[7:0] Data_out;
    wire stack_full,stack_empty;
    wire[2:0] addr_in,addr_out;
    FIFO_control U1(.stack_full(stack_full),.stack_empty(stack_empty),
                    .write_to_stack(write_to_stack),.write_ptr(addr_in),
                    .read_from_stack(read_from_stack),.read_ptr(add_out),
                    .clk(clk),.rst(rst));
    ram_dual U2(.q(Data_out),.addr_in(addr_in),.addr_out(addr_out),
                .d(Data_in),.we(write_to_stack),.rd(read_from_stack),
                .clk1(clk),.clk2(clk));
endmodule
module FIFO_control(write_ptr,read_ptr,stack_full,stack_empty,write_to_stack,read_from_stack,clk,rst);
    parameter stack_width=8;
    parameter stack_height=8;
    parameter stack_ptr_width=3;
    output stack_full,stack_empty;
    output[stack_ptr_width-1:0] read_ptr,write_ptr;	//读、写数据地址
    input write_to_stack,read_from_stack,clk,rst;
    reg[stack_ptr_width-1:0] read_ptr,write_ptr;
    reg[stack_ptr_width:0] ptr_gap;		//栈顶
    reg[stack_width-1:0] Data_out;
    reg[stacl_width-1:0] stack[stack_height-1:0];	//stack大小
    //堆栈状态信号,就是列出栈各种状态下,读、写指针的变化
    assign stack_full=(ptr_gap==stack_height);
    assign stack_empty=(ptr_gap == 0);
    always@(posedge clk or posedge rst)
        begin
            if(rst)
                begin
                    Data_out<=0;
                    read_ptr<=0;
                    write_ptr<=0;
                    ptr_gap<=0;
                end
            else if(write_to_stack&&(!stack_full)&&(!read_from_stack))
                begin
                    write_ptr<=write_ptr+1;
                    ptr_gap<=ptr_gap+1;
                end
            else if(!write_to_stack&&(!stack_empty)&&read_from_stack)
                begin
                    read_ptr<=read_ptr+1;
                    ptr_gap<=ptr_gap-1;
                end
            else if(write_to_stack && stack_empty && read_from_stack)
                begin
                    write_ptr<=write_ptr+1;
                    ptr_gap<=ptr_gap+1;
                end
            else if(write_to_stack && stack_full && read_from_stack)
                begin
                    read_ptr<=read_ptr+1;
                    ptr_gap<=ptr_gap-1;
                end
            else if(write_to_stack && read_from_stack && (!stack_full)&&(!stack_empty))
                begin
                    read_ptr<=read_ptr+1;
                    write_ptr<=write_ptr+1;
                end
            end
endmodule
// RAM模块参考双口RAM
module ram_dual(clk1,clk2,we,ed,d,q,addr_in,addr_out);
    output[7:0] q;
    input[7:0] d;
    input[2:0] addr_in,addr_out;
    input we,rd;
    input clk1,clk2;
    reg [7:0] q;
    reg [7:0] mem[7:0];
    always@(posedge clk1)
        begin
            if(we)
                mem[addr_in] <= d;
        end
    
    always@(posedge clk2)
        begin
            if(rd)
                q <= mem[addr_out];
        end
endmodule
    
    

module FIFO_tb;
    reg clk,rst;
    reg[7:0] Data_in;
    reg write_to_stack,read_from_stack;
    wire[7:0] Data_out;
    FIFO_buffer U1(.clk(clk),.rst(rst),.write_to_stack(write_to_stack),
                   .read_from_stack(read_from_stack),Data_in(Data_in),
                   .Data_out(Data_out));
    initial
        begin
            clk=0;rst=1;Data_in=0;write_to_stack=1;read_from_stack=0;
            #5 rst=0;
            #155 write_to_stack=0;
            read_from_stack=1;
        end
    alwasy #10 clk=~clk;
    initial
        begin
            repeat(7)
                #20 Data_in=Data_in+1;
        end
endmodule
           

8、CORDIC算法 —— 专题

9、UART总线

10、SPI接口控制器

//SPI 接收机,完成8bit信号的传输
module SPI(sdout,MISO,sclk,srst,sen,ss_n);
    output[7:0] sdout;
    output ss_n;		//片选信号
    input MISO,sclk,sen,srst;
    reg[2:0] counter;
    reg[7:0] shift_registe;
    reg ss_n;
    always@(posedge clk)
        if(!srst)
            counter<=3'b000;
    else if(sen)
        if(counter==3'b111)
            begin
                counter<=3'b000;
                ss_n<=1'b1;
            end
    	else 
            begin
                counter<=counter+1;
                ss_n<=1'b0;
            end
    else
        counter<=counter;
    always@(posedge sclk)
        if(sen)
            shift_regist<={shift_regist[6:0],MISO};
    	else
            shift_regist<=shift_regist;
    assign sdout=ss_n?shift_regist:8'bzzzzzzzz;
endmodule

module SPI_tb;
    reg MISO,sclk,sen,srst;
    wire[7:0] sdout;
    wire ss_n;
    SPI U1(.sdout(sdout),.MISO(MISO),.sclk(sclk),.srst(srst),
           .sen(sen),.ss_n(ss_n));
    initial 
        begin
            sclk=0;
            srst=0;
            MISO=0;
            sen=0;
            #10 srst=1;
            #10 sen=1;
            #10 sen=0;
            #10 sen=1
            #10 sen=0;
        end
    initial
        begin
            #30 MISo=1;
            #10 MISO=0;
            #10 MISO=1;
            #10 MISO=1;
            #10 MISO=1;
            #10 MISO=0;
            #10 MISO=1;
        end
    always #5 sclk<=~sclk;
endmodule
           

华为手撕代码:序列检测:1011010

  • 类型:
    • Mealy机
      • 重复
      • 不重复
    • Moore机
      • 重复
      • 不重复
  • Verilog表示
    • 直接根据状态转移图,
    • 基于状态化简的结构性描述:卡诺图化简,输出方程和状态方程
    • 抽象描述方式:用移位寄存器检测

继续阅读