乐鑫科技2020数字芯片

摘抄至数字芯片实验室
1、设计一个序列信号发生器电路,能在CLK信号作用下周期性输出“0010110111”的序列信号
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
2、设计一个自动饮料售卖机,共有两种饮料,其中饮料A每个10分钱,饮料B每个5分钱,硬币有5分和10分两种,并考虑找零。要求用状态机实现,定义状态,画出状态转移图,并用Verilog完整描述该模块
在这里插入图片描述

module machine(
    input clk ,
    input rst_n ,
    input[2:0] button,            //button[0]   --coin_in ;button[1]   --drink_in ;button[2]-- coin_out 
    input  coin_in ,            //0  --5 fen ;1 --10 fen
    outputreg  coin_out ,       //0  --0 fen ;1 --5 fen
    input  drink_in ,           //0  --5 fen drink ;1 --10 fen drink
    outputreg drink_out       //0  --5 fen drink ;1 --10 fen drink
 
);
 
parameter[1:0]  IDLE = 2'b00 ,  S0 = 2'b01 ,  S1 = 2'b10 ,  S2 = 2'b11 ;
reg[1:0] current_state, next_state ;
 
always@(posedge clk ornegedge rst_n) begin
    if(!rst_n) begin
        current_state <= IDLE ;
    end
    elsebegin
        current_state <= next_state ;
 
    end
end
 
reg  coin_in_reg ,drink_in_reg ;
always@(posedge clk ornegedge rst_n) begin
    if(!rst_n) begin
        coin_out <= 0 ;
        drink_out <= 0 ;
 
        coin_in_reg  <= 0 ;
        drink_in_reg <= 0 ;
    end
    elsebegin
        case(current_state)
            IDLE :begin
                coin_out <= 0 ;
                drink_out <= 0 ;
                drink_in_reg <= 0 ;
                if(button[0]) begin
                    coin_in_reg <=  coin_in ;
                end
                elsebegin
                    coin_in_reg <= 0 ;
                end
            end
            S0 :begin
                coin_out <= 0 ;
                drink_out <= 0 ;
                if(button[1]) begin
                    drink_in_reg <= drink_in;
                end
                elsebegin
                    drink_in_reg <= 0 ;
  
                end
            end
            S1 :begin
                coin_out <= 0 ;
                if(coin_in_reg>= drink_in_reg) drink_out <= drink_in_reg ;
                else                            drink_out <= 1'b0 ;
            end
            S2 :begin
                drink_out <= 0 ;
                drink_in_reg <= 0 ;
                if(button[0]) begin
                    coin_in_reg <=  coin_in ;
                end
                elsebegin
                    coin_in_reg <= 0 ;
                end
                if(coin_in_reg> drink_in_reg) coin_out <= 1'b1 ;
                else                           coin_out <= 1'b0 ;
            end
        endcase
    end
end
 
always@(*) begin
    next_state = IDLE ;
    case(current_state)
        IDLE : begin
            if(button[0]) begin
                next_state = S0 ;
            end
            elsebegin
                next_state = IDLE ;
            end
        end
        S0   : begin
            if(button[1]) begin
                next_state = S1 ;
            end
        end
        S1   : begin
            if(button[2]) begin
                next_state = S2 ;
            end
        end
        S2   : begin
            if(button[0]) begin
                next_state = S0 ;
            end
        end
    endcase
end
 
endmodule
module  machine_tb;
    reg clk ;
    reg rst_n ;
    reg[2:0] button ;
    reg coin_in ;
    wire coin_out ;
    reg drink_in ;
    wire drink_out ;
 
initialbegin
    clk = 0 ;
    rst_n = 1 ;
    button = 0 ;
    coin_in = 0 ;
    drink_in = 0 ;
    #20    rst_n = 0 ;
    #20    rst_n = 1 ;
    #30
 
    @(posedge clk ) #1
    button[0] = 1 ;
    coin_in = 1 ;
    @(posedge clk ) #1
    button[0] = 0 ;
    coin_in = 0 ;
    button[1] = 1 ;
    drink_in = 0 ; 
    @(posedge clk ) #1
    button[1] = 0 ;
    drink_in = 0 ; 
    button[2] = 1 ;
 
    @(posedge clk ) #1
    button[2] = 0 ;
    button[0] = 1 ;
    coin_in = 1 ;
    @(posedge clk ) #1
    button[0] = 0 ;
    coin_in = 0 ;

    button[1] = 1 ;
    drink_in = 1 ; 
    @(posedge clk ) #1
    button[1] = 0 ;
    drink_in = 0 ; 
    button[2] = 1 ;
 
end
 
always #10 clk = ~clk;
 
machine machine(
    .clk(clk) ,
    .rst_n(rst_n)  ,
    .button(button) ,          
    .coin_in(coin_in)  ,          
    .coin_out(coin_out) ,     
    .drink_in(drink_in) ,           
    .drink_out(drink_out)    
 
);
 
endmodule

1、 用户必须按照投币-买饮料-找零的顺序依次操作

2、 每轮购买操作中,用户只能投币一次,不然会发生吞币!(哈哈~~~)

3、 投币大小不能比购买饮料的价格小
在这里插入图片描述
3、请实现对(1011001)2的序列检测功能,模块每拍并行输入2bit,且顺序为高位先输入,当检测到序列,输出一拍高电平脉冲。请用Verilog描述该模块。
相当于检测10_11_00_1X
在这里插入图片描述

module sequence_checker_2bit(
    input clk  ,
    input rst_n,
    input[1:0] sequence_in ,
    outputreg pulse_out
);
 
parameter[2:0] IDLE = 3'b000 ,S0= 3'b001,S1= 3'b010,S2= 3'b011,S3= 3'b100  ;
 
reg[2:0] current_state,next_state ;
 
reg pulse_out_reg ;
always@(posedge clk ornegedge rst_n) begin
    if(!rst_n) begin
        current_state <= 0 ;
        pulse_out <= 0 ;
    end
    elsebegin
        current_state <= next_state ;
        pulse_out <= pulse_out_reg ;
    end
end
 
always@(*) begin
    next_state = IDLE;
    case(current_state)
        IDLE : begin
           if(sequence_in == 2'b10) next_state =S0;
            pulse_out_reg = 0 ;
        end
        S0 : begin
            if(sequence_in == 2'b11) next_state =S1;
            pulse_out_reg = 0 ;
 
        end
        S1 : begin
            if(sequence_in == 2'b00) next_state =S2;
            pulse_out_reg = 0 ;
 
        end
        S2 : begin
            if(sequence_in == 2'b10 || sequence_in == 2'b11)  begin
                next_state = S3;
                pulse_out_reg = 1 ;
            end
        end
        S3 : begin
            if(sequence_in == 2'b10) next_state =S0;
            else next_state =IDLE;
            pulse_out_reg = 0 ;
 
        end
    endcase
end
 
endmodule
module  sequence_checker_2bit_tb ;
    reg clk  ;
    reg rst_n ;
    reg[1:0]  sequence_in ;
    wire pulse_out ;
 
initialbegin
    clk = 0 ;
    rst_n = 1 ;
    sequence_in = 2'b00 ;
    #20 rst_n = 0;
    #20 rst_n = 1 ;
    @(posedge clk) #1  sequence_in = 2'b10 ;
    @(posedge clk) #1  sequence_in = 2'b11 ;
    @(posedge clk) #1  sequence_in = 2'b00 ;
    @(posedge clk) #1  sequence_in = 2'b10 ;
 
    @(posedge clk) #1
    @(posedge clk) #1
 
    @(posedge clk) #1  sequence_in = 2'b10 ;
    @(posedge clk) #1  sequence_in = 2'b11 ;
    @(posedge clk) #1  sequence_in = 2'b00 ;
    @(posedge clk) #1  sequence_in = 2'b11 ;
 
end
 
always #10 clk = ~clk;
 
sequence_checker_2bitsequence_checker_2bit(
    .clk(clk) ,
    .rst_n(rst_n),
    .sequence_in(sequence_in) ,
    .pulse_out(pulse_out)
);
 
endmodule

在这里插入图片描述
4、请基于f = 100Hz的Clock设计一个数字时钟,用Verilog实现以下功能

 1、产生时、分、秒的计时

2、可通过3个按键来设置时、分、秒值
module clock(
    input clk ,
    input rst_n ,
    input hour_set,
    input[4:0] hour_set_value,
 
    input minute_set,
    input[5:0]minute_set_value ,
 
    input second_set ,
    input  [5:0]second_set_value ,
 
    output[5:0] second_out ,
    output[5:0] minute_out ,
    output[4:0] hour_out
);
 
    reg[5:0] second_reg ;
    reg[5:0] minute_reg ;
    reg[4:0] hour_reg ;
    always@(posedge clk ornegedge rst_n ) begin
        if(!rst_n) begin
            second_reg <= 0 ;
        end
        elseif(second_set)second_reg <= second_set_value ;
        elseif(second_reg == 59) second_reg<= 0;
        else second_reg<= second_reg +1 ;
    end
 
    always@(posedge clk ornegedge rst_n ) begin
        if(!rst_n) begin
            minute_reg <= 0 ;
        end
        elseif(minute_set)minute_reg <= minute_set_value ;
        elseif(minute_reg == 59 &&second_reg == 59) minute_reg <= 0;
        elseif(second_reg == 59) minute_reg<= minute_reg +1 ;
    end
 
    always@(posedge clk ornegedge rst_n ) begin
        if(!rst_n) begin
            hour_reg <= 0 ;
        end
        elseif(hour_set)hour_reg <= hour_set_value ;
        elseif(hour_reg == 23 &&minute_reg == 59 && second_reg == 59)   hour_reg <= 0;
        elseif(minute_reg == 59 &&second_reg == 59 ) hour_reg <= hour_reg +1 ;
    end   
 
assign second_out=  second_reg ;
assign minute_out=   minute_reg;
assign hour_out =   hour_reg;
endmodule

```c
module  clock_tb ;
    reg clk ;
    reg rst_n ;
    reg hour_set ;
    reg[4:0] hour_set_value;
    reg minute_set ;
    reg[5:0]minute_set_value;
    reg second_set ;
    reg[5:0]second_set_value;
 
    wire[5:0]second_out  ;
    wire[5:0]minute_out  ;
    wire[4:0] hour_out  ;
 
initialbegin
    clk = 0 ;
    rst_n = 1 ;
    hour_set = 0 ;
    hour_set_value = 0;
    minute_set = 0 ;
    minute_set_value = 0;
    second_set = 0 ;
    second_set_value = 0;
    #10 rst_n = 0 ;
    #10 rst_n = 1 ;
 
    @(posedge clk ) #1
 
        hour_set = 1 ;
        hour_set_value= 10 ;
        minute_set = 1 ;
        minute_set_value = 10 ;
        second_set= 1 ;
        second_set_value = 10 ;
    @(posedge clk ) #1
        hour_set = 0 ;
        hour_set_value= 0 ;
        minute_set = 0 ;
        minute_set_value = 0 ;
        second_set= 0 ;
        second_set_value = 0 ;
 
end
 
    always #5 clk =~clk ;
 
 clock clock(
    .clk(clk) ,
    .rst_n(rst_n) ,
    .hour_set(hour_set) ,
    .hour_set_value(hour_set_value) ,
 
    .minute_set(minute_set),
    .minute_set_value(minute_set_value) ,
 
    .second_set(second_set),
    .second_set_value(second_set_value) ,
 
    .second_out(second_out) ,
    .minute_out(minute_out) ,
    .hour_out(hour_out)
);
 
endmodule

在这里插入图片描述
5、矩阵键盘
参考文章:

https://www.cnblogs.com/yuphone/archive/2010/11/09/1783623.html
6、将一个串行执行的C语言算法转化为单拍完成的并行可综合verilog。
C语言源码如下:

unsignedcharcal_table_high_first(unsignedcharvalue)
{
    unsigned char i ;
unsigned  char checksum = value ; 
    for (i=8;i>0;--i)
    {
        if (check_sum& 0x80)
        {
            check_sum = (check_sum<<1) ^ 0x31;
        }
        else
        {
            check_sum = (check_sum << 1);
        }
    }
    return check_sum;
}

算法C语言实现:

#include<stdio.h>
int main(){
    unsignedchar cal_table_high_first(unsignedcharvalue); 
    unsignedchar data;
    for (unsignedchar i = 0; i < 16;++i)
    {
         data= cal_table_high_first(i);
         printf("value =0x%0x:check_sum=0x%0x  \n", i, data);
    }
    getchar();
}
 
 
 
unsignedchar cal_table_high_first(unsignedcharvalue)
{
    unsignedchar i;
    unsigned  char check_sum = value;
    for (i = 8; i > 0;--i)
    {
         if (check_sum &0x80)
         {
             check_sum= (check_sum << 1) ^ 0x31;
         }
         else
         {
             check_sum= (check_sum << 1);
         }
    }
    return check_sum;
}

输出结果:

value =0x0:check_sum=0x0
value =0x1:check_sum=0x31
value =0x2:check_sum=0x62
value =0x3:check_sum=0x53
value =0x4:check_sum=0xc4
value =0x5:check_sum=0xf5
value =0x6:check_sum=0xa6
value =0x7:check_sum=0x97
value =0x8:check_sum=0xb9
value =0x9:check_sum=0x88
value =0xa:check_sum=0xdb
value =0xb:check_sum=0xea
value =0xc:check_sum=0x7d
value =0xd:check_sum=0x4c
value =0xe:check_sum=0x1f
value =0xf:check_sum=0x2e

C语言作为参考模型,用于后续Verilog的功能仿真。

该算法逻辑如下:

输入一个8bit的数,首先判断最高位是否为1,如果为1则左移一位,并且和8‘b00110001异或;如果最高位不为1则左移一位。此过程执行8次。
在这里插入图片描述
根据上述结果,可以用verilog描述。

module loop1(
   input clk,
   input rst_n,
   input [7:0] check_sum,
   output reg [7:0] check_sum_o
);
//reg [7:0] check_sum_o;
always @ (posedge clk or negedge rst_n)
       if(!rst_n)
              begin
                     check_sum_o<= 8'h0;
              end
       else
              begin
                     check_sum_o[7]<= check_sum[3]^check_sum[2]^check_sum[5];
                     check_sum_o[6]<= check_sum[2]^check_sum[1]^check_sum[4]^check_sum[7];
                     check_sum_o[5]<= check_sum[1]^check_sum[7]^check_sum[0]^check_sum[3]^check_sum[6];
                     check_sum_o[4]<= check_sum[7]^check_sum[0]^check_sum[3]^check_sum[6];
                     check_sum_o[3]<= check_sum[3]^check_sum[7]^check_sum[6];
                     check_sum_o[2]<= check_sum[2]^check_sum[6]^check_sum[5];
                     check_sum_o[1]<= check_sum[1]^check_sum[5]^check_sum[4]^check_sum[7];
                     check_sum_o[0]<= check_sum[0]^check_sum[4]^check_sum[3]^check_sum[6];
              end
      
endmodule

testbench


module loop1_tb;
reg clk;
reg rst_n;
reg [7:0] check_sum;
wire [7:0] check_sum_o;
always #1 clk=~clk;
initial
begin
clk = 0;
rst_n = 0;
#10
rst_n = 1;
for (check_sum=0;check_sum<16;check_sum=check_sum+1)
       begin
       #2
        //check_sum = i;
        $display ("check_sum = %h",check_sum_o);
        if (check_sum == 15) $stop;
       end
//$stop;
end
loop1 loop1_i1(
       .clk(clk),
       .rst_n(rst_n),
       .check_sum(check_sum),
       .check_sum_o(check_sum_o)
);
endmodule

loop2.v的实现和loop1.v类似,只是代码量更少。

module loop2(
   input clk,
   input rst_n,
   input [7:0] check_sum,
   output  reg [7:0] check_sum_o
);
integer i;
//reg [7:0] check_sum_o;
reg [7:0] ccc;
always @ (posedge clk or negedge rst_n)
       if(!rst_n)
              begin
                     check_sum_o= 8'h0;
              end
       else
              begin
           ccc = check_sum;
                     for(i=0;i<8;i=i+1)
                begin
                    ccc ={ccc[6:0],1'b0}^({8{ccc[7]}} & 8'h31);
                end
           check_sum_o = ccc;
              end
      
endmodule

其实也可以将C语言函数封装成Verilog的function,然后在在单周期内进行赋值。

module loop3(
   input clk,
   input rst_n,
   input [7:0] check_sum,
   output  reg [7:0] check_sum_o
 
);
 
integer i;
 
function [7:0] cal_table_high_first;
       input[7:0] value;
       reg[7:0] ccc ;
       reg[7:0] flag ;
              begin
                                   ccc= value;
                                   for(i=0;i<8;i=i+1)
                                          begin
                                                 flag= ccc & 8'h80 ;
                                                 if(flag!= 0 ) ccc = (ccc <<1) ^ 8'h31 ;
                                                 elseccc = (ccc <<1)  ;
                                         
                                          end
                                   cal_table_high_first= ccc;
              end
 
endfunction
 
always @ (posedge clk or negedge rst_n)
       if(!rst_n)
              begin
                     check_sum_o= 8'h0;
              end
       else
              begin
                    check_sum_o<= cal_table_high_first(check_sum) ;
              end
      
endmodule

综上,loop1.v和loop2.v的主要贡献是解开了算法实现的if-else判断。至于loop3.v中,将C语言描述的功能封装成fucntion,直接单周期完成赋值的实现方式在逻辑综合后是否增加了if-else判断语句的硬件开销不在本文讨论范围内。

这和设计者施加的时序约束和综合工具算法有关

  • 1
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值