BUAA-CO-Preview

BUAA-CO-Preview

题目地址

2020

2020 ROIFE

2023

CO 2023 讨论区优质帖汇总 | TripleCamera 的博客

基础知识

存储单位

  • 最基础的存储单位是位(bit);在32位机中,1字节(Byte)= 8位(bit);1字(word)= 4字节(Byte), 1半字 = 2字节
  • 2进制的一个数字占1位,16进制的一个数字表示16种情况,占4位,故一个字节只能存2位16进制数

P0

组合逻辑

2021_T1

4人(1个组长和3个组员)对议题进行投票表决。组长有一票否决权。如果组长一票否决,则议题被否决。如果组长正常投票(同意、反对或者弃权),则统计同意的人数和反对的人数。当同意人数大于反对人数,则议题通过,否则议题被否决。
请设计组合逻辑电路,实现这样子的一个投票表决器

同意 同意 弃权 一票否决
组长信号 00 01 10
组员信号 00 01与11 10

翻译:组长否决or(组员否决>=2)输出0,;组长同意and(组员同意>=2)输出1

可以先做一个统计输入数n个数的原件

  • MAIN:

p1

  • 统计个数的原件:

p2

2023_T1

给定五个8bit输入,输出一个8bit的在五个输入中没出现的最小正整数。例如输入为3,1,0,5,7;则输出为2。

p3

用OR门将所有1塞进一个8bit数中,再用find_low_0找最小未出现1的位即可

2020_T2

信号名 方向 描述
tea[2:0] I 老师给的分数,二进制表示
s1[1:0] I 学生1给的分数
s2[1:0] I 学生2给的分数
total[3:0] O 总得分

当老师给的分数为0时,total为0;否则,total=tea+s1+s2

解析:先加,然后判断tea是否=0, 若=0则输出0,否则输出和。

加法时容易溢出,要先extend再加!!

p4

FSM

相关知识

复位信号

  • 同步复位:复位信号只有在时钟上升沿到来时,才能有效。也就是说,同步复位操作永远发生在时钟上升沿,即便复位信号提前到来,也无法立刻完成复位操作。
  • 异步复位:无论时钟沿是否到来,只要复位信号有效,就对系统进行复位。
  • 若要搭建同步复位信号,应在状态转移时使用多路选择器,无reset信号时,将新状态存入寄存器,否则,将0存入寄存器;
    异步信号只需要使用原件自带的clear引脚即可。
    p5
  • Moore型output与input无关
    p6
  • Mealy型的output与input有关
    p7
  • 均可使用logisim的Combinational Analysis。

2020_T1

摆渡车有两条路线,可以在某一个站换乘,状态机需要输出下一个位置:

line0: 00 -> 11 -> 01 -> 10 -> 00

line1: 01 -> 10 -> 11 -> 01

解析:转移状态时按照转移要求填真值表即可,=但在与splitter连接时需要注意高低位!

本题不需要特殊的输出逻辑,所以没有输出模块,不代表其他题没有输出模块!!

  • Main:

p8

  • 状态转移电路:

p9

2023_T2

p10

输入为2bit方向信号,1bit clk,1bit reset,异步复位。最开始位于1处,根据输入的2bit方向信息前往下一个位置,如果没有(或者撞墙)则停留在当前位置。输出为下一步的位置标号。输出4bit位置信号。Mealy型状态机

解析:初始状态不是0没关系,通过output模块,认为把初始状态设置成0即可。其余的就是打表。

有一点需要注意,hit应该需要第二个reg以保持与状态转移的同步性,否则会比状态转移快一周期!

p11

Logisim_Helper

Arithmetic_library

  • Bit Adder: 确定输入中有几个1。
    东:输入; 西:输出。

p12

  • Bit Finder:
    有多重模式:找最低位1、最高位1、最低位0、最高位0
    东:输入; 西:输出; 南:是否找到目标数。
    p13

P1

组合逻辑

  • 组合电路可以使用 assign(配合三目运算符) =always @(*)实现=
  • 数据类型:
    • wire:导线,不能存储数据。赋值使用 assign语句
    • reg:寄存器,有存储功能,一般在 always块中使用
      不能用 assign赋值;可以“用来建模组合逻辑”??
      mem[0][7:0]:访问 mem 中 0 号寄存器的 7:0 位值
      [bit+: width]:从起始 bit 位开始递增,位宽为 width
      [bit-: width]:从起始 bit 位开始递减,位宽为 width
  • 符号数与 $signed()
    • regwire默认是无符号数,可以用 $signed()转换成有符号数。但若表达式同时存在有符号与无符号数,则转换符失效。
    • $signed()将括号内的表达式结果强制转换为有符号型。
  • 常用语法:
    • assignassign a = b; 其中 awire类型,并且要保证 b已被驱动
      =不能在 always块和 initial块中使用=(也就是说,wire型不能在 always等块中赋值)
    • >>>>>: 分别为逻辑右移与算数右移,逻辑右移将空出的最高位补0,算数右移补符号位。
      1
      2
      3
      4
           a = 4'b1101;
       assign ans = a >> 2; //逻辑右移ans = 4'b0011
       assign ans = a >>> 3;//算数右移ans = 4'b0001
       assign ans = $signed(a) >>> 3;//算数右移 ans =
    • 赋值:组合逻辑要用 =阻塞赋值。
    • 拼接:可以将几个信号的某些位拼接起来
      1
      2
      3
      4
      5
      6
      7
      8
           input [3:0] a;
       input [3:0] b;
       output [7:0] ans;
       
       assign ans = {a[3:2],b};//将a的高2位与b拼接后,放在ans低位
       //a = 4'b1010; b = 4'b1101; ans = 00101101;
       ans = {2{a}};//将2个a拼接在一起后,放在ans低位
       //a = 4'b1010; ans = 0...010101010;
    • 条件语句:
      只能出现在顺序模块中(begin...end
      只有当 case语句覆盖所有情况时才会生成组合逻辑,否则会生成时序逻辑(锁存器),因为需要保存当前状态。
      因此一定不要忘记写 default
      1
      2
      3
      4
      5
      6
      7
      8
      9
           case(data)
           0: out <= 4;
           1: out <= 5;
           2: out <= 2;
           3: begin
               out <= 1;
           end
           default: ;
       endcase

2020_课下_T3

信号名 描述
imm[15:0] 输入16位数字
EOp 00:将imm进行符号扩展至32位
01:将imm进行高位零扩展至32位
10:将imm加载到高位,低位补0

这题好就好在它帮我想起了拼接这种东西

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
always @ (*) begin
case (imm):
2'b00: begin
output = {imm, 16'b0};
output = $signed($signed(output) >>> 16);
end

2'b01: begin
output = {16'b0, imm};
end

2'b10: begin
output = {imm, 16'b0};
end
endcase
end

2020_T1

按照权重,计算得分:np(normal people),一票1分;vip,一票4分;vvip,一票16分。

信号名 方向 描述
np[31:0] I 31个普通人投票
vip[7:0] I 8个vip投票
vvip I 只有一个vvip
res O 大于等于32分,res为1
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
`timescale 1ns / 1ps
module test(
input [31:0] np,
input [7:0] vip,
input vvip,
output reg res
//output reg [31:0] cnt
);
integer i;
reg [31:0] cnt;
always @(*) begin
cnt = 0;
for(i = 0; i < 32; i = i + 1) begin
if(np[i]) cnt = cnt + 1;
end

for(i = 0; i < 8; i = i + 1) begin
if(vip[i]) cnt = cnt + 4;
end

if(vvip == 1) cnt = cnt + 16;

if(cnt >= 32) res = 1;
else res = 0;
end
endmodule

数1的个数即可,需要注意:

  • for循环,if判断等都需要在 always块中使用
  • always @ (*)用的较少,此用法可以当组合逻辑使用
  • 计数器别忘了初始化,否则将恒为 xxx....

时序逻辑

  • always语句块:
1
 always @ (posedge clk or negedge rst_n) //clk到达上升沿或rst_n到达下降沿触发
  • 如果有多个 always块,那么这些快是并行的

  • wire型变量不能在其中被赋值,要想赋值必须定义为 reg

  • 寄存器:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
 //异步复位高电平有效:
 module r1(
     input clk,
     input rst,
     input [3:0] data,
     output [3:0] out
 );
    always @ (posedge clk, posedge rst) begin
        //只要rst到达上升沿,无论clk,都要reset
        if(rst) out <= 4'b0;
        else out <= data;
    end
 endmodule

//异步复位低电平有效:
always @ (posedge clk, negedge rst) begin
if(!rst) //reset
else //do something
end
 
 //同步复位寄存器
 module r2(
     input clk,
     input rst,
     input [3:0] data,
     output reg [3:0] out
 );
     always @ (posedge clk) begin
         //只在clk上升沿判断是否reset
         if (rst) out <= 4'b0;
         else out <= data;
     end
 endmodule
 

FSM

  • 小函数:
1
2
wire isd = (char >= "0" && char <= "9") ? 1 : 0;
//通过三目运算减少码量
  • 可以在status 0中进行初始化,这样当遇到default时直接将status置0,而无须进行其他操作

  • 对于status的初始化: 可以在always块内进行。

  • 基本框架

组合逻辑实现转移,时序逻辑实现复位

可以采用Logisim中构造复位的思路

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
//初始化 + 小函数

//同步复位
always @ (*) begin
//组合逻辑实现状态转移
case(status)
0: next_state = //...
1: next_state = //...
2: next_state = //...
//...
default
endcase
end

always @ (posedge clk) begin
//时序逻辑复位
if(rst) status <= 0;
else status <= next_state
end

always @ (*) begin
// 输出逻辑
end

//-------------------------------

//异步复位
always @ (*) begin
//转移
end

always @ (posedge clk or negedge rst) begin
//rst==0时复位
if(!rst) status <= 0;
else status <= next_status;
end

always @ (*) begin
//输出
end

2020_T3

字符串状态机:

2020.2.2
2020-12.23
2020/3/30

以上均是合法日期表示。

  1. 不能有前导零,08-17不合法
  2. 三种分隔符.-/,且必须保持一致
  3. 注意月份的天数,1~30,不考虑复杂情况
answer
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
`timescale 1ns / 1ps

module test(
input [7:0] char,
input clk,
output reg ans
);
reg [3:0] status;
reg [3:0] cnt;
reg [7:0] r_char;

wire isd = (char >= "0" && char <= "9") ? 1 : 0;
wire isc = (char == "." || char == "-" || char == "/") ? 1 : 0;

always @ (posedge clk) begin

case(status)
3'd0: begin
status <= 0;
cnt <= 0;
r_char <= 0;
if(isd) begin
status <= 3'd1;
cnt <= 1;
end
else status <= 3'd0;
end

3'd1: begin
if(isd) begin
if(cnt < 4) begin
status <= 3'd1;
cnt <= cnt + 1;
end
else status <= 3'd0;
end
else begin
if(isc && cnt == 3'd4) begin
r_char <= char;
cnt <= 0;
status <= 3'd2;
end
else status <= 0;
end
end

3'd2: begin
if(isd && char != "0") begin
status <= 3'd3;
cnt <= 1;
end
else status <= 0;
end

3'd3: begin
if(isd) begin
if(cnt < 2) begin
cnt <= cnt + 1;
status <= 3'd3;
end
else status <= 3'd0;
end
else if(cnt <= 2 && char == r_char) begin
status <= 3'd4;
cnt <= 0;
end
else status <= 3'd0;
end

3'd4: begin
if(isd && char > "0" && char < "3") begin
status <= 3'd5;
cnt <= 1;
end
else status <= 3'd0;
end

3'd5: begin
if(isd) begin
if(cnt < 2) begin
cnt <= cnt + 1;
status <= 3'd5;
end
else status <= 3'd0;
end
else status <= 3'd0;
end
default: status <= 3'd0;
endcase

if(status == 3'd5) ans = 1;
else ans = 0;
end

endmodule

常见错误:

  • 未定义变量就直接使用,ise不会报错,而是将该变量定义为1位宽wire型
    要避免此类错误,可加上 default_nettype none ,这样如果不事先定义,那么编译器就会报错。
  • 在某些语句块中定义局部变量
  • 组合逻辑电路与时序逻辑电路不能混用,组合逻辑不能写在 always块内,否则会导致输出迟滞
  • for循环内部的赋值不能用非阻塞赋值 <=
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
 integer i;
 always @ (posedge clk) begin
     out <= 0;
     for (i = 0; i < 8; i = i + 1)begin
         out <= out + 1
     end
 end
 //这相当于:
 //out <= 0;
 //out <= out + 1;
 //out <= out + 1;
 //out <= out + 1;
 //我们希望这些语句串行执行,但是他们却并行执行了,并且右侧的值均不一样,这会造成矛盾
 
 //可以在时序逻辑中的for循环内用阻塞赋值,或选择组合逻辑。
 always @ (posedge clk) begin
     out = 0;
     for (i = 0; i < 8; i = i + 1) begin
         out = out + 1;
     end
 end
 //or
 always @ (*) begin
    ...
 end

Isim调试技巧

ISim查看中间变量
Instance and Process Name中的uut目录下,选中非顶层模块(如always模块),即可在右侧的Object目录中看到中间变量,右键选择Add to Wave Window,即可将对应信号添加到波形文件中。

作者

OWPETER

发布于

2024-09-12

更新于

2024-12-02

许可协议

评论