大家好,最近汇总了2021年oppo哲库招聘手撕代码题目,本文章一共含有以下几个题目:

一,使用握手信号实现跨时钟域数据传输(verilog)

二,自动售卖机(verilog)

三,序列发生器(verilog)

四,根据RTL图编写Verilog程序(verilog)

下面对各自题目分别进行解析:

一,使用握手信号实现跨时钟域数据传输(verilog)

1)题目

分别编写一个数据发送模块和一个数据接收模块,模块的时钟信号分别为clk_a,clk_b。两个时钟的频率不相同。数据发送模块循环发送0-7,在每个数据传输完成之后,间隔5个时钟,发送下一个数据。请在两个模块之间添加必要的握手信号,保证数据传输不丢失。
    模块的接口信号图如下:

图1:接口图

其中:
data_req表示数据请求接受信号。当data_out发出时,该信号拉高,在确认数据被成功接收之前,保持为高,期间data应该保持不变,等待接收端接收数据。当数据接收端检测到data_req为高,表示该时刻的信号data有效,保存数据,并拉高data_ack。当数据发送端检测到data_ack,表示上一个发送的数据已经被接收。撤销data_req,然后可以改变数据data。等到下次发送时,再一次拉高data_req。

其中:

clk_a:发送端时钟信号

clk_b:接收端时钟信号

rst_n:复位信号,低电平有效

data_ack:数据接收确认信号

data:发送的数据

data_req:请求接收数据

2)解题逻辑

所谓握手信号即加入一些指示信号,在两个模块间确认数据已经被接受之后再进行下一个数据的传输。一般来说,发送端随数据发出一个数据有效信号,或者称为数据请求接受信号data_req,接收端在data_req有效时,采集数据data,进行缓存或者其他处理,所以要保证在data_req有效期间,也就是还没收到data_ack确认信号之前,传输的数据data不能发生变化。然后接收端发送一个数据确认信号data_ack,告知发送端,数据已经接受,可以开始下一个数据的传输,发送端在接收到data_ack之后,撤销data_req,并可以改变数据,为下一步传输做准备。

①首先是数据发送端,发送数据的标志是data_req拉高,在data_req拉高期间,data需要保持不变,一直到接收端完成数据的接收,即接收端发送data_ack确认信号。所以取data_ack的上升沿信号作为data_req撤销和data_out改变的指示信号。

②同时在data_ack有效之后,开始计数五个时钟,之后发送新的数据,也就是再一次拉高data_req.

③接收端的逻辑较为简单,首先是探测data_req的电平,如果data_req为高,表示有数据正在传输,则保存该时刻的数据,然后拉高data_ack告知发送端数据已经接收,直到发送端撤销data_req。

3)代码:

其中:

shakehand_tx是发送模块;

shakehand_rx是发送模块;

shakehand_top是顶层模块,负责将上述两个模块端口连接;

shakehand_top_TB是shakehand_top的仿真文件;

`timescale 1ns / 1ps
/
module shakehand_tx(input clk_a,input rst_n,input data_ack,output reg [3:0]data,output reg data_req,output [3:0] cnt);reg data_ack_r1,data_ack_r2;
always@(posedge clk_a or negedge rst_n)
beginif(rst_n==0)begindata_ack_r1 <= 1'b0;data_ack_r2 <= 1'b0;endelsebegindata_ack_r1 <= data_ack;data_ack_r2 <= data_ack_r1;end
endalways@(posedge clk_a or negedge rst_n)
beginif(rst_n==0 || (data == 4'd8))begindata <= 4'b0;         endelseif(data_ack_r1 && !data_ack_r2 )begindata<= data +1'b1 ;end    elsebegindata<= data   ;end
endreg [3:0] cnt=4'd0 ;
always@(posedge clk_a or negedge rst_n)
beginif(rst_n==0 || (data_ack_r1 && !data_ack_r2) )cnt <= 4'b0;else  if( data_req==1'b1) //捕捉上升沿              cnt<= cnt   ;               else                cnt<= cnt + 1'b1;endalways@(posedge clk_a or negedge rst_n)
beginif(rst_n==0 ||(data_ack_r1 && !data_ack_r2)  )       data_req <= 1'b0;          else    if(cnt ==4'd4)           data_req<= 1'b1  ;             else            data_req<= data_req ;       endendmodule

下面是rx:

`timescale 1ns / 1ps
///
module shakehand_rx(input clk_b,input rst_n,output reg data_ack,input [3:0]data,input data_req,output [3:0] data_reg);
reg [3:0] data_reg=4'd0;
reg data_req_r1,data_req_r2;
always@(posedge clk_b or negedge rst_n)
beginif(rst_n==0)begindata_req_r1 <= 1'b0;data_req_r2 <= 1'b0;endelsebegindata_req_r1 <= data_req;data_req_r2 <= data_req_r1;end
endalways@(posedge clk_b or negedge rst_n)
beginif(rst_n==0)begindata_ack <= 1'b0;data_reg <= 4'd0;endelse if(data_req_r1 && !data_req_r2)begindata_ack <= 1'b1;data_reg <= data;end  elsebegindata_ack <= 1'b0;data_reg <= data_reg;end
endendmodule

下面是top:

`timescale 1ns / 1ps
/
module shakehand_top(
input sys_clk,
input rst_n,
output [3:0] data,
output data_ack,
output data_req,
output [3:0] cnt,
output [3:0] data_reg,
output clk_a,
output clk_b);
reg [15:0] cnt_clk=16'd0;
always@(posedge sys_clk or negedge rst_n)
beginif(rst_n==0 || cnt_clk ==16'b0000_0000_1111_1111) cnt_clk <= 16'd0;else cnt_clk <= cnt_clk + 1'b1;
endreg  clk_a = 1'd0;
reg  clk_b = 1'd0;
always@(posedge sys_clk or negedge rst_n)
beginif(rst_n==0 || cnt_clk[2:0] ==3'd4) clk_a <= 1'd0;else if(cnt_clk[2:0] == 3'd0) clk_a <= 1'b1;    else clk_a <= clk_a;
endalways@(posedge sys_clk or negedge rst_n)
beginif(rst_n==0 || cnt_clk[3:0] ==4'd8) clk_b <= 1'd0;else if(cnt_clk[3:0] == 4'd0)clk_b <= 1'b1;    elseclk_b <= clk_b;
end   wire [3:0] data;
wire data_req;
wire data_ack;
wire [3:0] cnt;
wire [3:0] data_reg;
shakehand_tx myshakehand_tx
(.clk_a(clk_a),         //input.rst_n(rst_n),           //input.data_ack(data_ack), //input.data(data),         //output.data_req(data_req),    //output.cnt(cnt));shakehand_rx myshakehand_rx
(.clk_b(clk_b),         //input.rst_n(rst_n),           //input.data_ack(data_ack),//output.data(data),             //input.data_req(data_req),     //input.data_reg(data_reg));endmodule

下面是TB:

`timescale 1ns / 1psmodule shakehand_top_TB;// Inputsreg sys_clk;reg rst_n;// Outputswire [3:0] data;wire data_ack;wire data_req;wire [3:0] cnt;wire [3:0] data_reg;wire clk_a;wire clk_b;// Instantiate the Unit Under Test (UUT)shakehand_top uut (.sys_clk(sys_clk), .rst_n(rst_n), .data(data), .data_ack(data_ack), .data_req(data_req), .cnt(cnt), .data_reg(data_reg),.clk_a(clk_a),.clk_b(clk_b));initial begin// Initialize Inputssys_clk = 0;rst_n = 0;// Wait 100 ns for global reset to finish#100;rst_n = 1;forever begin#500 sys_clk = ~sys_clk;end// Add stimulus hereendendmodule

4)仿真结果:

图3:仿真结果

为了说明结果,对图3进行放大得到图4:

图4:放大图

下面对图4进行解释:

①在A时刻,clk_a下cnt计数到4开始传输数据,data_req变1;

②在B时刻,clk_b下的data_ack捕捉到data_req则data_ack变1,开始接受数据,所以data_reg变1;

③在C时刻,clk_a下的data_req变0则表示结束本次传输,cnt开始从0计数准备下一次传输。同时,clk_b下的data_ack变0,表示传输结束。

二、自动售卖机

1)题目

请设计状态机电路,实现自动售卖机功能,A饮料5元钱,B饮料10元钱,售卖机可接收投币5元钱和10元钱,每次投币只可买一种饮料,考虑找零的情况。电路的接口如下图所示。

图5:自动售卖机电路接口

①sel为选择信号,用来选择购买饮料的种类,sel=0,表示购买A饮料,sel=1,表示购买B饮料;sel信号会先于din信号有效,且在购买一种饮料时值不变。

②din表示投币输入,din=0表示未投币,din=1表示投币5元,din=2表示投币10元,不会出现din=3的情况;

③drinks_out表示饮料输出,drinks_out=0表示没有饮料输出,drinks_out=1表示输出A饮料,drinks_out=2表示输出B饮料,不出现drinks_out =3的情况,输出有效仅保持一个时钟周期;④change_out表示找零输出,change_out=0表示没有找零,change_out=1表示找零5元,输出有效仅保持一个时钟周期。

2)解题思路

这个题目有一个特殊情况,就是当你选择B饮料并投了5元时,应该是没有饮料输出,并且没有找零,该状态会维持直到你下次继续投币。

3)代码

`timescale 1ns / 1ps
//
//请设计状态机电路,实现自动售卖机功能,A饮料5元钱,B饮料10元钱,
//售卖机可接收投币5元钱和10元钱,每次投币只可买一种饮料,考虑找零的情况。
//电路的接口如下图所示。sel信号会先于din信号有效,且在购买一种饮料时值不变。
//sel=0,表示购买A饮料,sel=1,表示购买B饮料;
//din=0表示未投币,din=1表示投币5元,din=2表示投币10元,不会出现din=3的情况;
//drinks_out=0表示没有饮料输出,drinks_out=1表示输出A饮料,drinks_out=2表示输出B饮料,
//不出现drinks_out =3的情况,输出有效仅保持一个时钟周期;
//change_out=0表示没有找零,change_out=1表示找零5元,输出有效仅保持一个时钟周期。
//
//
module vending(input                clk   ,input                rst_n ,input                sel   ,//sel=0,5$dranks,sel=1,10&=$drinksinput          [1:0] din   ,//din=1,input 5$,din=2,input 10$output   reg   [1:0] drinks_out,output   reg         change_out,output [2:0] state,output [2:0] state_next   );
parameter A=3'd0;//A表示sel=0,din=0,drinks_out=0,change_out=0 没有进钱,也没找零,表示默认状态
parameter B=3'd1;//B表示sel=0,din=1,drinks_out=1,change_out=0
parameter C=3'd2;//C表示sel=0,din=2,drinks_out=1,change_out=1
parameter D=3'd3;//D表示sel=1,din=1,drinks_out=0,change_out=0 该状态未完成
parameter E=3'd4;//E表示sel=1,din=2,drinks_out=2,change_out=0
parameter F=3'd5;//在D情况下 F表示sel=1,din=2,drinks_out=2,change_out=1reg [2:0] state;
reg [2:0] state_next;
always@(posedge clk or negedge rst_n)
beginif(rst_n==0)state <= A;elsestate <= state_next;
end
//----------------------------------
always@(*)
begincase(state)A: drinks_out <= 2'd0;B: drinks_out <= 2'd1;C: drinks_out <= 2'd1;D: drinks_out <= 2'd0;E: drinks_out <= 2'd2;F: drinks_out <= 2'd2;default: drinks_out <= 2'd0;endcase
end
//----------------------------------
always@(*)
begincase(state)A: change_out <= 1'd0;B: change_out <= 1'd0;C: change_out <= 1'd1;D: change_out <= 1'd0;E: change_out <= 1'd0;F: change_out <= 1'd1;default: change_out <= 1'd0;endcase
end
//---------------------------------------
always@(*)
begincase(state)A: begincase({sel,din})3'b000:state_next <= A;3'b001:state_next <= B;3'b010:state_next <= C;3'b100:state_next <= A;3'b101:state_next <= D;3'b110:state_next <= E;default: state_next <= A;                endcase         endB: begincase({sel,din})3'b000:state_next <= A;3'b001:state_next <= B;3'b010:state_next <= C;3'b100:state_next <= A;3'b101:state_next <= D;3'b110:state_next <= E;default: state_next <= A;             endcase         endC: begincase({sel,din})3'b000:state_next <= A;3'b001:state_next <= B;3'b010:state_next <= C;3'b100:state_next <= A;3'b101:state_next <= D;3'b110:state_next <= E;default: state_next <= A;             endcase         endD: begincase({sel,din})  //特殊情况                  3'b100:state_next <= D;3'b101:state_next <= E;3'b110:state_next <= F;default: state_next <= A;               endcase         endE: begincase({sel,din})3'b000:state_next <= A;3'b001:state_next <= B;3'b010:state_next <= C;3'b100:state_next <= A;3'b101:state_next <= D;3'b110:state_next <= E;default: state_next <= A;             endcase         endF: begincase({sel,din})3'b000:state_next <= A;3'b001:state_next <= B;3'b010:state_next <= C;3'b100:state_next <= A;3'b101:state_next <= D;3'b110:state_next <= E;default: state_next <= A;             endcase         endendcaseendendmodule

仿真代码:

`timescale 1ns / 1ps//module vending_TB;// Inputsreg clk;reg rst_n;reg sel;reg [1:0] din;// Outputswire [1:0] drinks_out;wire change_out;
wire [2:0] state;
wire [2:0] state_next ;// Instantiate the Unit Under Test (UUT)vending uut (.clk(clk), .rst_n(rst_n), .sel(sel), .din(din), .drinks_out(drinks_out), .change_out(change_out),.state(state),.state_next(state_next));initial begin// Initialize Inputsclk = 0;rst_n = 0;sel = 0;din = 0;
//forever begin #500 clk=~clk; end //1Mhz // Wait 100 ns for global reset to finish#100;rst_n =1;#200 sel = 0;       din = 0;#200   sel = 0;       din = 1;#200   sel = 0;       din = 2;#200   sel = 1;       din = 0;#200   sel = 1;       din = 2;   #200    sel = 1;       din = 1;#20    sel = 1;       din = 0;#20    sel = 1;       din = 1;// Add stimulus hereendalways #10 clk = ~clk;
endmodule

4)仿真结果:

图6

三、序列产生器

1)题目

编写一个模块,实现循环输出序列001011。模块的接口信号图如下:

图7

2)解题思路

使用计数器cnt表示输出序列位置,并使用判断语句对不同位置进行赋值。

3)代码

`timescale 1ns / 1ps
//
// 编写一个模块,实现循环输出序列001011。
//
//
module sequence(input       clk,input       rst_n,output reg    data,output [3:0] cnt);
reg [3:0] cnt=4'b0;
always@(posedge clk or negedge rst_n)
beginif(rst_n==0 || cnt == 4'd5) cnt<=4'b0;else cnt <= cnt + 1'b1 ;
endalways@(posedge clk or negedge rst_n)
beginif(rst_n==0 || cnt==4'd0 || cnt == 4'd1 || cnt == 4'd3 )  data <= 1'b0 ;else   data <= 1'b1 ;
endendmodule

仿真代码:

`timescale 1ns / 1ps/module sequence_TB;// Inputsreg clk;reg rst_n;// Outputswire data;wire [3:0] cnt;// Instantiate the Unit Under Test (UUT)sequence uut (.clk(clk), .rst_n(rst_n), .data(data),.cnt(cnt));initial begin// Initialize Inputsclk = 0;rst_n = 0;// Wait 100 ns for global reset to finish#100;rst_n =1'b1 ;forever #500 clk=~clk;// Add stimulus hereendendmodule

4)仿真结果:

图8:仿真结果

解释:

①在A时刻计数器是0,则在B时刻data产生了第一个0;

②以此类推。

四、根据RTL写verilog

1)题目:

根据以下RTL图,使用 Verilog HDL语言编写代码,实现相同的功能,并编写testbench验证功能。

图9

2)解题思路

观察题目给出的RTL图,主要的器件是两个D触发器,一个与门。D触发器含有异步复位信号,且为低电平有效。data_in输入到D触发器,D触发器的输出Q是前一时刻的data_in,即data_in打一拍得到data_in_reg。与门表示data_out = data_in && !data_in_reg。再通过一个D触发器输出,这样子处理使data_in上升沿出现的时候,data_out保持一个时钟的高电平。由此可见,RTL实现了求data_in上升沿的功能。

3)代码

`timescale 1ns / 1psmodule RTL(input clk,input rst_n,input data_in,output reg data_out);reg data_in_reg=1'b0;
always@(posedge clk or negedge rst_n)
beginif(rst_n==0)data_in_reg <= 1'b0 ;elsedata_in_reg <= data_in ;
endalways@(posedge clk or negedge rst_n)
beginif(rst_n==0)data_out <= 1'b0 ;else data_out <= data_in  &&  !data_in_reg ;  endendmodule

仿真代码:

`timescale 1ns / 1ps///module RTL_TB;// Inputsreg clk;reg rst_n;reg data_in;// Outputswire data_out;// Instantiate the Unit Under Test (UUT)RTL uut (.clk(clk), .rst_n(rst_n), .data_in(data_in), .data_out(data_out));initial begin// Initialize Inputsclk = 0;rst_n = 0;data_in = 0;// Wait 100 ns for global reset to finish#100;rst_n = 1; #10000 data_in = 1;forever  #500 begin clk=~clk ;end// Add stimulus hereendalways  #1000 begin data_in=~data_in ;end
endmodule

4)仿真结果:

图10​​​​

解释:

在A时刻data_in出现上升沿,在B时刻data_out输出1.

2021年oppo哲库数字IC岗位手撕代码真题(含:握手信号、自动售卖机、序列发生器、根据RTL写verilog)相关推荐

  1. 数字IC面试手撕代码(一)

    1.最近看别人有面试说遇到这样一个问题.用状态机实现类似序列检测的题目:生成01011011101111-依次类推.针对这个问题,我设计如下的三段式状态机代码,用了4个状态,2个计数器. 设计之初,本 ...

  2. 数字IC秋招手撕代码(二)50%占空比的三分频

    数字IC秋招手撕代码(二)50%占空比的三分频 题目 设计思路 与逻辑分频 代码 或逻辑分频 代码 异或逻辑分频 代码 题目 用verilog实现三分频电路,要求输出50%占空比 设计思路 如果不限制 ...

  3. 数字IC手撕代码---百题斩

    前言: 本篇导览目录,用来索引笔者写的其他手撕代码文章 本专栏旨在记录高频笔面试手撕代码题,以备数字前端秋招,本专栏所有文章提供原理分析.代码及波形,所有代码均经过本人验证. 目录如下: 1.数字IC ...

  4. 数字IC-1.10 手撕代码之整数乘法和二范数(Verilog HDL数字加减法练习好帮手)

    目 录 1.数字加减法运算 .绝对值.被乘数或被除数为2^n的乘除运算-归纳 2.二范数开根号代码实战 out = (a*a + b*b)^1/2  : JPL近似法 3.整数乘法代码实战 out = ...

  5. 【数字IC手撕代码】Verilog奇数分频|题目|原理|设计|仿真(三分频,五分频,奇数分频及特殊占空比)

    芯片设计验证社区·芯片爱好者聚集地·硬件相关讨论社区·数字verifier星球 四社区联合力荐!近500篇数字IC精品文章收录! [数字IC精品文章收录]学习路线·基础知识·总线·脚本语言·芯片求职· ...

  6. 【数字IC手撕代码】Verilog偶数分频|题目|原理|设计|仿真(二分频,四分频,六分频,八分频,偶数分频及特殊占空比)

    芯片设计验证社区·芯片爱好者聚集地·硬件相关讨论社区·数字verifier星球 四社区联合力荐!近500篇数字IC精品文章收录! [数字IC精品文章收录]学习路线·基础知识·总线·脚本语言·芯片求职· ...

  7. 【数字IC手撕代码】Verilog固定优先级仲裁器|题目|原理|设计|仿真

    芯片设计验证社区·芯片爱好者聚集地·硬件相关讨论社区·数字verifier星球 四社区联合力荐!近500篇数字IC精品文章收录! [数字IC精品文章收录]学习路线·基础知识·总线·脚本语言·芯片求职· ...

  8. 【数字IC手撕代码】Verilog自动售卖饮料机|题目|原理|设计|仿真

    芯片设计验证社区·芯片爱好者聚集地·硬件相关讨论社区·数字verifier星球 四社区联合力荐!近500篇数字IC精品文章收录! [数字IC精品文章收录]学习路线·基础知识·总线·脚本语言·芯片求职· ...

  9. 【数字IC手撕代码】Verilog半整数分频|题目|原理|设计|仿真

    芯片设计验证社区·芯片爱好者聚集地·硬件相关讨论社区·数字verifier星球 四社区联合力荐!近500篇数字IC精品文章收录! [数字IC精品文章收录]学习路线·基础知识·总线·脚本语言·芯片求职· ...

最新文章

  1. javascript原型对象、原型链、构造函数
  2. Java数字反转(编程题)
  3. 干货 | 你还在群发吗?高效查出哪些微信好友删除了你
  4. “数据中国”路在何方?答:在“数据中国加速计划”
  5. 【高斯和拉普拉斯为什么分别对应L2和L1?】差分隐私系统学习记录(五)
  6. GolVe向量化做文本分类
  7. 2019全球PostgreSQL生态报告出炉,PG为何从RDBMS中脱颖而出?丨文末送书
  8. Android下拉状态栏图标错了,小米手机怎么改状态栏的图标,并且把下拉的状态栏弄透明...
  9. 人脸识别的Python库
  10. Spring依赖处理过程源码分析
  11. SendMessage 函数
  12. 添加.MSPX文件(VISTA下)
  13. pip不是内部命令问题
  14. 微型计算机原理与接口周荷琴,微型计算机原理与接口技术周荷琴
  15. 重庆市谷歌卫星地图下载
  16. ttest求pvalue_excle如何计算t的值,TTEST 在EXCEL计算出的结果是t还是p值,用哪一个公式在excel中计算出t值和p值是多少...
  17. 程序存储器 指令寄存器 程序计数器 地址寄存器
  18. 网易云音乐web/网页版无法播放问题
  19. 不用PS也能设计出精美图片?这几个强大的在线设计网站了解一下~
  20. matlab 多项式相减,matlab多项式计算与数据处理

热门文章

  1. Spring Security3十五日研究
  2. harry-通过刺激战场来学习python的字典用法
  3. docker逃逸到宿主机
  4. 谈谈 CTO 如何做好技术管理?
  5. 语音增强--卡尔曼滤波介绍及MATLAB实现
  6. 我建议大学生看一下阿凡达2,对离校后很有帮助
  7. 总结的一些微信API接口
  8. C语言判断26个字母元音辅音
  9. Linux Shell编程学习笔记(2)
  10. Reflect的用法赶紧学起来