数字IC手撕代码-XX公司笔试真题(串并转换控制)
创始人
2024-01-28 06:23:31

 前言: 

        本专栏旨在记录高频笔面试手撕代码题,以备数字前端秋招,本专栏所有文章提供原理分析、代码及波形,所有代码均经过本人验证。

目录如下:

1.数字IC手撕代码-分频器(任意偶数分频)

2.数字IC手撕代码-分频器(任意奇数分频)

3.数字IC手撕代码-分频器(任意小数分频)

4.数字IC手撕代码-异步复位同步释放

5.数字IC手撕代码-边沿检测(上升沿、下降沿、双边沿)

6.数字IC手撕代码-序列检测(状态机写法)

7.数字IC手撕代码-序列检测(移位寄存器写法)

8.数字IC手撕代码-半加器、全加器

9.数字IC手撕代码-串转并、并转串

10.数字IC手撕代码-数据位宽转换器(宽-窄,窄-宽转换)

11.数字IC手撕代码-有限状态机FSM-饮料机

12.数字IC手撕代码-握手信号(READY-VALID)

13.数字IC手撕代码-流水握手(利用握手解决流水线断流、反压问题)

14.数字IC手撕代码-泰凌微笔试真题

15.数字IC手撕代码-平头哥技术终面手撕真题

16.数字IC手撕代码-兆易创新笔试真题

17.数字IC手撕代码-乐鑫科技笔试真题(4倍频)

18.数字IC手撕代码-双端口RAM(dual-port-RAM)

        ...持续更新

为了方便可以收藏导览博客:

数字IC手撕代码-导览目录


目录

题目描述

解题思路

代码

testbench

输出波形


题目描述

        将数据进行串转并处理,输入 3780 个串行比特,每个数据占一个时钟周期,输入共占 3780 个时钟,要求并行输出 63 个 bit,共 60 个时钟输出完.其时序示意图如下: 第 1 个时钟并行输出 0,60,…,3720,做为 bus 整体输出 第 2 个时钟并行输出 1,61,…3721 第 60 个时钟并行输出 59,119,…3779 注意每次并行输出仅占一个时钟周期,60 个时钟周期便输出完. 输出与输入的相对时延关系任意即可。

解题思路

        这道题乍一眼看上去好像很简单,串并转换就行了,但其实涉及到一个单bit数据位置的问题,不仅如此,如果写出来的代码不是“一次性”的,能经得住背靠背传输、以及间断传输的考验的话,代码还是需要写一段把所有情况考虑进去的。

        重新理一下题目的意思,题目是实现一个串并的转换,每周期输入1bit数据,共在3780个周期内完成输入3780个1bit数据。因为并行输出是在串行输入全部完成后进行的,因此我们需要将3780个串行输入存储起来,可以用RAM也可以用寄存器直接存储。并行输出,每次输出63bit,共输出60周期,60*63bit=3780bit。

        这里的关键在于并行输出的相邻bit是跳跃式的,0、60、120...;1、61、121...;因此找到并行输出和串行输入之间的映射关系尤为重要。可以用一个60*63=3780的一维数组data_store去存储输入的串行数据。我的思路是用一个地址addr来索引每次存储在一维数组data_store的位置,然后每63个周期为一个loop,总共有60个loop,在一个loop中,往一维数组里面写入单bit数据,位置分别存放在59,119,179,...,3719,3779。每经过63周期(存完63bit数据),一维数组就右移1bit(左边高bit,右边低bit)。这样子经过62次shift后,第一个写入的单bit数据就会被shift到最低位,一开始写在62位置的bit,会被移位到0位置,一开始写在3779位置的bit,会被移位到3717位置。       最后,在经过60loop之后,3780个单bit数据都输入完了,我们就可以输出高bit数据,把output_valid输出有效信号拉高,同时一周期输出一次63bit,输出60次63bit,完成串行转并行。


reg [5:0] shiftcount;
always @(posedge clk)beginif(data_in_ena && loop_row == 6'd0)begindata_store[addr] <= serial_data;endelse if(data_in_ena && loop_row != 6'd0 && count_row == 6'd0)begindata_store <= {1'b0,data_store[3779:64],serial_data,data_store[62:1]}; //should shift 63 times   60bit shift one times shiftcount <= shiftcount + 1'b1;endelse if(data_in_ena && loop_row != 6'd0 && count_row > 6'd0)begindata_store[addr] <= serial_data;end
endalways @(posedge clk)beginif(!rstn)beginaddr <= 12'd62;shiftcount <= 6'd0;endelse if(data_in_ena && count_row < 59)beginaddr <= 63*count_row+12'd125;  //addr belongs to {62,125,188,...,3779}  endelse if(data_in_ena && count_row == 59)beginaddr <= 12'd62;end
end

代码

            ,input               rstn            ,input               serial_data     ,input               data_in_ena     ,output      [62:0]  parallel_data   ,output  reg         data_out_ena
);reg [3779:0] data_store;
reg [11:0] addr;
reg [62:0] parallel_data_reg;reg [5:0] count_column,count_row; //one column is once parallel_data
reg [5:0] loop_column,loop_row;reg [5:0] output_count;
reg output_valid;always @(posedge clk)begin     //one loop ,save 63 bits data, so count_column belongs to [0,62]if(!rstn)begincount_column <= 6'd0;endelse if(data_in_ena && count_column < 6'd62)begincount_column <= count_column + 1'b1;endelse if(data_in_ena && count_column == 6'd62)begincount_column <= 6'd0;end
endalways @(posedge clk)begin     //count_row belongs to [0,59]if(!rstn)begincount_row <= 6'd0;endelse if(data_in_ena && count_row < 6'd59)begincount_row <= count_row + 1'b1;endelse if(data_in_ena && count_row == 6'd59)begincount_row <= 6'd0;end
endalways @(posedge clk)begin      //loop_column belongs to [0,59]if(!rstn)beginloop_column <= 6'd0;endelse if(count_column == 6'd62 && loop_column < 6'd59)beginloop_column <= loop_column + 1'b1;endelse if(count_column == 6'd62 && loop_column == 6'd59)beginloop_column <= 6'd0;end
endalways @(posedge clk)begin      //loop_row belongs to [0,62]if(!rstn)beginloop_row <= 6'd0;endelse if(count_row == 6'd59 && loop_row < 6'd62)beginloop_row <= loop_row + 1'b1;endelse if(count_row == 6'd59 && loop_row == 6'd62)beginloop_row <= 6'd0;end
endreg [5:0] shiftcount;
always @(posedge clk)beginif(data_in_ena && loop_row == 6'd0)begindata_store[addr] <= serial_data;endelse if(data_in_ena && loop_row != 6'd0 && count_row == 6'd0)begindata_store <= {1'b0,data_store[3779:64],serial_data,data_store[62:1]}; //should shift 63 times   60bit shift one times shiftcount <= shiftcount + 1'b1;endelse if(data_in_ena && loop_row != 6'd0 && count_row > 6'd0)begindata_store[addr] <= serial_data;end
endalways @(posedge clk)beginif(!rstn)beginaddr <= 12'd62;shiftcount <= 6'd0;endelse if(data_in_ena && count_row < 59)beginaddr <= 63*count_row+12'd125;  //addr belongs to {62,125,188,...,3779}  endelse if(data_in_ena && count_row == 59)beginaddr <= 12'd62;end
end//parallel output
genvar i ;
generatefor (i=0;i<=59;i=i+1)beginalways @(posedge clk)beginif(output_valid == 1'b1)begincase(output_count)i:parallel_data_reg <= data_store[i*63+62:i*63];endcaseendendend
endgeneratealways @(posedge clk)beginif(!rstn)beginoutput_valid <= 1'b0;endelse if(count_column == 6'd62 && loop_column == 6'd59)beginoutput_valid <= 1'b1;endelse if(output_valid == 1'b1 && output_count == 6'd59)beginoutput_valid <= 1'b0;end
endalways @(posedge clk)beginif(!rstn)beginoutput_count <= 6'd0;endelse if(output_valid == 1'b1 && output_count < 6'd59)beginoutput_count <= output_count + 1'b1;endelse beginoutput_count <= 6'd0;end
endalways @(posedge clk)begindata_out_ena <= output_valid; //one beat late
endassign parallel_data = parallel_data_reg;endmodule

testbench

module serial_to_parallel_tb();reg clk,rstn;
reg serial_data,data_in_ena;wire [62:0] parallel_data;
wire  data_out_ena;always #5 clk = ~clk;
initial beginclk <= 1'd0;rstn <= 1'd0;serial_data <= 1'b1;#16rstn <= 1'b1;forever beginrepeat(3780)begin#10serial_data <= serial_data + 1'b1;data_in_ena <= 1'b1;endrepeat(60)begin#10data_in_ena <= 1'b0;endend
end
initial begin#100000$finish();
end//dump fsdb 
initial begin $fsdbDumpfile("serial_to_parallel.fsdb");$fsdbDumpvars(0);
end serial_to_parallel u_serial_to_parallel(.clk            (clk)               ,  .rstn           (rstn)              ,.serial_data    (serial_data)       ,.data_in_ena    (data_in_ena)       ,.parallel_data  (parallel_data)     ,.data_out_ena   (data_out_ena)
);endmodule

输出波形

yH5BAAAAAAALAAAAAAOAA4AAAIMhI+py+0Po5y02qsKADs=wAAACH5BAEKAAAALAAAAAABAAEAAAICRAEAOw==

        支持背靠背传输,3780周期输入单bit数据,之后输入有效信号拉低60周期,此时输出有效信号拉高,输出60周期63bit的并行数据。

 

相关内容

热门资讯

埃菲尔铁塔在哪 中国仿建埃菲尔... 2019年4月26日,广西南宁市,街头惊现一座巨型山寨版埃菲尔铁塔,高约20米,白色塔身,造型逼真,...
苗族的传统节日 贵州苗族节日有... 【岜沙苗族芦笙节】岜沙,苗语叫“分送”,距从江县城7.5公里,是世界上最崇拜树木并以树为神的枪手部落...
不用电脑怎么设置苹果铃声 ip... 需要一个app,加上苹果自带的app即可1、手机下载爱思极速版。因为之前换手机搬移数据时店员帮忙整理...
北京的名胜古迹 北京最著名的景... 北京从元代开始,逐渐走上帝国首都的道路,先是成为大辽朝五大首都之一的南京城,随着金灭辽,金代从海陵王...
应用未安装解决办法 平板应用未... ---IT小技术,每天Get一个小技能!一、前言描述苹果IPad2居然不能安装怎么办?与此IPad不...
长白山自助游攻略 吉林长白山游... 昨天介绍了西坡的景点详细请看链接:一个人的旅行,据说能看到长白山天池全凭运气,您的运气如何?今日介绍...
脚上的穴位图 脚面经络图对应的... 人体穴位作用图解大全更清晰直观的标注了各个人体穴位的作用,包括头部穴位图、胸部穴位图、背部穴位图、胳...
世界上最漂亮的人 世界上最漂亮... 此前在某网上,选出了全球265万颜值姣好的女性。从这些数量庞大的女性群体中,人们投票选出了心目中最美...
猫咪吃了塑料袋怎么办 猫咪误食... 你知道吗?塑料袋放久了会长猫哦!要说猫咪对塑料袋的喜爱程度完完全全可以媲美纸箱家里只要一有塑料袋的响...
埃菲尔铁塔在哪 中国仿建埃菲尔... 2019年4月26日,广西南宁市,街头惊现一座巨型山寨版埃菲尔铁塔,高约20米,白色塔身,造型逼真,...
苗族的传统节日 贵州苗族节日有... 【岜沙苗族芦笙节】岜沙,苗语叫“分送”,距从江县城7.5公里,是世界上最崇拜树木并以树为神的枪手部落...
才高八斗的主人公 三顾茅庐的主... 古代君王在建立自己的政治体系之时,大多会采取一些礼贤下士的手段,对于一些有卓越才能的人放低姿态。因为...
北京的名胜古迹 北京最著名的景... 北京从元代开始,逐渐走上帝国首都的道路,先是成为大辽朝五大首都之一的南京城,随着金灭辽,金代从海陵王...