refactor: 迁出文档

This commit is contained in:
Liphen 2024-03-10 14:44:32 +08:00
parent f7fb3c4677
commit 4fddbe5a3d
102 changed files with 0 additions and 9556 deletions

Binary file not shown.

Before

Width:  |  Height:  |  Size: 28 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 16 KiB

View File

@ -1,75 +0,0 @@
# AXI
## 信号
信号包含 AR读请求通道、R读响应通道、AW写请求通道、W写数据通道、B写响应通道
所有以 A 开头的信号都是包含地址信息的通道,如 AR 就是发送读地址的通道AW 就是发生写地址的通道
### 信号宽度
下图为 PUA CPU 的 RISC V 64 实现中的 AXI 信号宽度
| 信号 | 宽度 | 功能 | 备注 |
| :-------: | :--: | :--------------: | :------: |
| AXI_ID | 4 | ID 号 | |
| AXI_ADDR | 32 | 地址 | |
| AXI_DATA | 64 | 数据 | |
| AXI_STRB | 8 | 字节选通位 | |
| AXI_RESP | 2 | 操作的结果 | |
| AXI_LEN | 8 | 传输长度(拍数) | |
| AXI_SIZE | 3 | (每拍)传输大小 | |
| AXI_BURST | 2 | 传输类型 | 固定为 1 |
| AXI_LOCK | 2 | 原子锁 | 固定为 0 |
| AXI_CACHE | 4 | Cache 属性 | 固定为 0 |
| AXI_PROT | 3 | 保护属性 | 固定为 0 |
### size 信号
axi 中的 size 决定了每一拍要取的数据长度
下图是 size 取值和传输数据大小的对应关系
| AxSIZE | Label | Meaning |
| :----: | :---: | :--------------------: |
| 0b000 | 1 | 1 byte per transfer |
| 0b001 | 2 | 2 bytes per transfer |
| 0b010 | 4 | 4 bytes per transfer |
| 0b011 | 8 | 8 bytes per transfer |
| 0b100 | 16 | 16 bytes per transfer |
| 0b101 | 32 | 32 bytes per transfer |
| 0b110 | 64 | 64 bytes per transfer |
| 0b111 | 128 | 128 bytes per transfer |
对于 ICache 来说,指令长度是 32bit
- 当处于 uncached 段时 size 应该是 b010一拍取 4 字节
- 处于 cached 段时应该和 AXI_DATA_WID 一致,这样可以保证最大量的取数据,应该是 $\rm log_2(AXI\_DATA\_WID/8)$
- 比如 AXI_DATA_WID 为 64 时,$\rm log_2(64 / 8) = 3$,正好对应表里的 size 值 b011
- AXI_DATA_WID 为 32 时,$\rm log_2(32 / 8) = 2$,对应表中的值 b010
### len 信号
用于控制传输的拍数,它的值就是需要传输的拍数减一
- 想传输 16 拍,那么设置 len 为 15此时一共会得到$\rm (len+1)\times2^{size}$ 个 bytes 的数据
### burst 信号
用于控制传输类型
我们的实现中固定为 1为 1 时是 INCR 类型,对于这种突发类型,每次传输的地址是上一次传输地址的增量。增量值取决于事务大小。设置为 1 的行为最简单
## 结构
我们 CPU 的访存结构如下图所示
我们可以看到 ICache 和 DCache 都和 Cache-AXI Interface 发生了交互,最后 Cache-AXI Interface 和 AXI CrossBar 间就只有一条数据线交互了
其中 ICache 只用于取指,所以只会使用到 AXI 的 AR 和 R而 DCache 包含 load 和 store 两种操作,所以会用到所有 5 个通道
Cache-AXI Interface 的作用就是在 ICache 和 DCache 的发出的两个读请求AR中选择一个并且把读响应R正确的发送到对应的 Cache 中;而对于 AW、W、B 只需要全部和 DCache 交互就行了;其实可以简单理解成通过 Cache-AXI Interface 这个转换桥将 CPU 从哈佛架构转为了冯诺依曼架构
![CrossBar](axi.assets/CrossBar.png)
![CPUtoCrossBar](axi.assets/CPUtoCrossBar.png)

View File

@ -1,262 +0,0 @@
# 目录
## 《数字逻辑与计算机结构》目录
### 一、概述
### 二、数据表示
### 三、数字逻辑基础
### 四、组合逻辑电路
### 五、同步时序电路
### 六、运算方法和运算器
### 七、指令系统
### 九、简单处理器
- 中断和例外
- 了解虚实地址转换TLB MMU 模块
### 十、流水线处理器
- 这里有必要介绍下分布式控制流水线和集中式控制流水线
- 介绍下流水线缓存应该会存什么东西
- 介绍每一级应该干什么
- 流水线怎么做到精确例外
### 八、存储器
- Cache 的机制
### 十一、 系统互连与输入输出
- AXI 总线协议
- MMIO
## 《数字逻辑与计算机结构实验指导书》目录
### 数字电路设计实验(上册)
#### 一、FPGA 设计与 Verilog HDL 硬件描述语言
#### 二、Vivado 开发平台
#### 三、HDU-X01 开发板及实验流程
#### 实验 1 译码器设计实验
#### 实验 2 多路选择器和数据分配器设计实验
#### 实验 3 全加器与超前进位电路设计实验
#### 实验 4 多功能 ALU 设计实验
#### 实验 5 通用寄存器堆设计实验
---
### 计算机结构设计实验(下册)
#### 一、RISC-V 体系结构与指令系统
#### 二、Chisel 语法简介
#### 三、开发环境和差分测试
#### 四、RV64I 单周期处理器设计实验
1. 实现 R 型运算指令的处理器设计实验
2. 实现 I 型运算指令的处理器设计实验
3. 实现 U 型运算指令的处理器设计实验
4. 实现 I 型和 S 型访存指令的处理器设计实验
5. 实现 J 型无条件转移指令的处理器设计实验
6. 实现 B 型条件转移指令的处理器设计实验
---
#### 五、流水线处理器设计实验
##### 1 实现 R 型运算类指令的理想流水线设计实验
###### 实验目的
1. 掌握 R 型运算类指令的数据通路
2. 掌握经典单发射五级流水线的设计方法
3. 掌握流水线 CPU 设计的编程基本框架
###### 实验原理和方法
1. 实现经典的单发射五级流水,这样比较简单
2. 提供一个已经实现了 add 指令的五级流水线
3. 使用没有数据相关的测试集对其处理器进行测试,用于验证指令的正确性
###### 实验要求
1. 根据本实验提供的五级流水线编程框架,在流水线 CPU 中添加以下指令ADD、SLL、SLT 、SLTU、XOR 、SRL 、OR、AND 、SUB 、SRA
2. 通过本实验提供的所有测试用例
###### 实验步骤
1. 如何打开工程文件进行编程
2. 如何使用模拟器进行仿真
3. 如何提交测评
###### 思考题
1.
##### 2 实现 I 型和 U 型运算类指令的理想流水线设计实验
###### 实验目的
1. 掌握 I 型和 U 型运算类指令的数据通路
2. 掌握在五级流水线中添加 I 型和 U 型指令的方法
---
使用没有数据相关的测试集对其处理器进行测试,用于验证指令的正确性
##### 3 实现乘除法指令的理想流水线设计实验
###### 实验目的
1. 掌握乘法指令和除法指令的数据通路
2. 掌握在执行级中添加乘除法运算部件 MDU 的方法
3. 掌握在五级流水线中实现乘法指令和除法指令的方法
---
实现 M 拓展,在 exe 级增加 FU 选择
##### 4 实现访存指令的理想流水线设计实验
###### 实验目的
1. 掌握访存指令的数据通路
2. 掌握在访存级中添加访存部件 LSU 的方法
3. 掌握在五级流水线中实现访存指令的方法
---
在 mem 级增加 lsu
##### 5 实现转移指令的理想流水线设计实验
###### 实验目的
1. 掌握转移指令的数据通路
2. 掌握在执行级中添加转移控制部件 BRU 的方法
3. 掌握在五级流水线中实现转移指令的方法
---
转移指令可以设计在 id 级也可以实现在 exe 级
##### 6 气泡流水线设计实验
###### 实验目的
1. 掌握各种流水线冲突的概念
2. 掌握插入气泡解决各种冲突的原理
3. 学习判断流水线冲突的逻辑单元的设计方法
###### 实验原理与方法
1. 流水线冲突的基本概念与流水线的控制方法
- 冲突
- 数据相关
- 结构相关
- 控制相关
- 控制
- 集中式
- 分布式
2. 流水线冲突的判断与气泡解决方法
- 数据冲突
- 写后写
- **写后读**:对于顺序单发射流水线来说,仅这种情况会发生冲突
- 读后读
- 读后写
###### 实验要求
###### 实验步骤
###### 思考题
当发现译码级的源操作数和执行级、访存级、写回级目的寄存器一致时,通过阻塞译码级来解决数据冲突
保证后一级无法运行时,前一级也无法运行,即可完成阻塞
##### 7 使用数据前递解决冲突的流水线设计实验
- 数据前递的方式
- 数据前递来源有执行级和写回级,目前还没实现访存级
- 是否实现乘除法指令?
- 乘除法指令周期数一般会大于一,要考虑阻塞
- 也可以实现为简单的单周期乘除法,只是处理器频率上不去,但是没了阻塞的问题
完成数据相关处理后,使用有数据相关的数据集进行测试
##### 8 实现 CSR 指令的流水线设计实验
- 实现 M 模式
- 增加 CSR 指令
- 在 exe 级增加 fu 选择
##### 9 例外和中断的支持
- 可以先实现 ecall、eret、ebreak 指令,再实现别的例外
- 实现 M 和 U 模式
- 截止这里应该已经完成了 RV64 的 I、M、Zicsr 指令集
##### 10 支持 AXI 总线的流水线互连设计实验
- 将现有的 sram 接口改为类 sram 接口
- 再设计一个类 sram 转 AXI 协议转换桥
- 通过 AXI 随机延迟验证
##### 11 流水线 CPU 访存提速设计实验
- 先设计 cache 模块
- 然后实现 icache调整总线接口
- 实现 fence.i 指令
- 跑性能测试程序
##### 12 流水线 CPU 分支预测设计实验
##### 13 动态顺序双发射流水线设计实验
##### 14 支持虚实地址转换的超标量流水线设计实验
- 增加 MMU、TLB实现虚实地址转换使用 SV39 标准
- 增加 S 相关的 CSR
- 增加 S 模式
- 运行操作系统
##### 15 从RISC-V 核到 LongArch 核的架构移植实验
#### 六、模拟器设计实验

Binary file not shown.

Binary file not shown.

File diff suppressed because it is too large Load Diff

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 14 KiB

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 20 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 31 KiB

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 14 KiB

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 20 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 31 KiB

View File

@ -1,63 +0,0 @@
# 全加器
## 一、实验介绍
加法器是 ALU算术逻辑部件的核心组成部分它执行数字系统中最常见的运算——加法。减法可以看作是将被减数与取负后的减数进行加法运算。因此加法器不仅能够执行加法还可以同时实现减法运算。此外通过移位相加的算法加法器还可以实现乘法运算。因此可以说加法器是计算机中最繁忙的部件之一。
本实验介绍如何使用 Verilog 编写全加器。
## 二、实验目的
1. 理解全加器的原理和功能。
2. 学会使用 Verilog 结构建模方式描述全加器的行为。
3. 掌握 Verilog 仿真工具的使用,验证全加器的正确性。
## 三、实验要求
1. 使用 Verilog 结构建模的方式描述全加器的行为。
2. 通过所有测试点。
## 四、实验步骤
### 1. 框图
<img src="全加器.assets/全加器.svg" style="zoom:150%;" />
- `A``B` 是输入端口,表示要相加的两个二进制位。
- `Cin` 是进位输入端口,表示上一位的进位。
- `S` 也就是 `Sum` 是输出端口,表示相加结果的当前位。
- `Cout` 是进位输出端口,表示相加结果的进位。
### 2. 电路图
![](全加器.assets/全加器电路图.svg)
### 3. 真值表
![](全加器.assets/全加器真值表.png)
### 4. 顶层模块
```verilog
module FullAdder (
input wire A,
input wire B,
input wire Cin,
output wire S,
output wire Cout
);
// TODO你的代码实现
endmodule
```
在上述代码中,顶层模块名为 `FullAdder`,它有五个端口:
- `A``B` 是输入端口,表示要相加的两个二进制位。
- `Cin` 是进位输入端口,表示上一位的进位。
- `S` 是输出端口,表示相加结果的当前位。
- `Cout` 是进位输出端口,表示相加结果的进位。
请使用结构建模的方式完成代码,完成全加器的设计。

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 44 KiB

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 44 KiB

View File

@ -1,72 +0,0 @@
# 加减法器
## 一、实验介绍
加减法器Adder/Subtractor是一种用于执行加法和减法运算的部件。它可以根据输入信号的控制来确定是执行加法还是减法操作。
在加法模式下,加减法器将两个输入数相加,并输出它们的和。加法器通常由多个加法位组成,每个加法位负责处理对应位上的相加运算,并生成该位的和值和进位信号。进位信号作为下一位相加运算的输入。
在减法模式下,加减法器将一个输入数减去另一个输入数,并输出它们的差。减法操作可以通过将减数取反(取反码)并加 1 来实现。因此,减法器通常包含一个取反器(或称为“反相器”)用于取反减数,并将结果输入到一个加法器中进行相加运算。
加减法器可以通过控制信号来选择加法或减法模式。通常使用一个控制位,称为"Borrow"或"Subtract",来切换加减法模式。当"Borrow"或"Subtract"位为 0 时,加减法器处于加法模式;当该位为 1 时,加减法器处于减法模式。
加减法器在数字电路和计算机系统中广泛应用是实现算术运算的基本组件。它们在处理器、算术逻辑单元ALU、计算器和其他数值处理应用中扮演着重要的角色。
## 二、实验目的
1. 理解加减法器的原理和功能。
2. 学会使用 Verilog 描述加减法器的行为。
3. 掌握 Verilog 仿真工具的使用,验证加减法器的正确性。
## 三、实验要求
1. 使用 Verilog 描述加减法器的行为。
2. 通过所有测试点。
## 四、实验步骤
下面以一个 4 位二进制的加减法器为例子:
### 1. 框图
![](加减法器.assets/加减法器.svg)
- $A$ 、$B$ 是两个 4 位二进制数的输入端,$Y$ 是输出端为计算结果。
- $Cin$ 表示最低位的进位输入,$Cout$是最高位的进位输出。
- $\overline{Add}/Sub$ 是加减法器的模式选择端口,当输入 0 时为加法运算,输入 1 时为减法运算。
- $ZF\left (ZeroFlag\right)$是零标志,当运算结果$Y$为 0 时,$ZF$输出 1反之为 0。
- $CF\left(CarryFlag\right)$是进位/标志,$CF$有两个含义:
- 当进行加法运算时,当作进位标志,表明无符号运算发生溢出。此时若$Cout=1$,则$CF=1$;若$Cout=0$,则$CF=0$。
- 当进行减法运算时,当作借位标志,表明不够减。此时若$Cout=1$,则$CF=0$;若$Cout=0$,则$CF=1$。
### 2. 顶层模块
```verilog
module Adder_Subtractor(
input [3: 0] A,
input [3: 0] B,
input Cin,
input Mode,
output [3: 0] Y,
output Cout,
output ZF,
output CF
);
// TODO: 你的代码实现
endmodule
```
在上述代码中,顶层模块名为`Adder_Subtractor`,它有八个端口:
- $A$ 、$B$ 是两个 4 位二进制数的输入端,$Y$ 是输出端为计算结果。
- $Cin$ 表示最低位的进位输入,$Cout$是最高位的进位输出。
- $Mode$是加减法器的模式选择端口,当输入 0 时为加法运算,输入 1 时为减法运算。
- $ZF\left (ZeroFlag\right)$是零标志,当运算结果$Y$为 0 时,$ZF$输出 1反之为 0。
- $CF\left(CarryFlag\right)$是进位/标志,$CF$有两个含义:
- 当进行加法运算时,当作进位标志,表明无符号运算发生溢出。此时若$Cout=1$,则$CF=1$;若$Cout=0$,则$CF=0$。
- 当进行减法运算时,当作借位标志,表明不够减。此时若$Cout=1$,则$CF=0$;若$Cout=0$,则$CF=1$。
请补充代码,完成 4 位二进制加减法器的设计。

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 32 KiB

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 32 KiB

View File

@ -1,67 +0,0 @@
# 多路数据选择器
## 一、实验介绍
多路数据选择器Multiplexer简称 MUX是一种数字电路组件用于从多个输入数据信号中选择一个输出数据信号。它根据选择信号的值将其中一个输入信号传递到输出。一个有 2*n* 输入端的数据选择器有 _n_ 个可选择的输入-输出线路,可以通过控制端来选择其中一个信号被选择作为输出。
本实验介绍如何使用 Verilog 编写多路数据选择器。
## 二、实验目的
1. 理解多路数据选择器的原理和功能。
2. 学会使用 Verilog 描述多路数据选择器的行为。
3. 掌握 Verilog 仿真工具的使用,验证多路数据选择器的正确性。
## 三、实验要求
1. 使用 Verilog 描述多路数据选择器的行为。
2. 通过所有测试点。
## 四、实验步骤
这里我们以四选一多路选择器举例:
### 1. 框图
<img src="多路数据选择器.assets/框图.svg" style="zoom:150%;" />
- `A` 、`B` 、`C` 和 `D`是输入端口,表示输入的数据。
- `S` 是选择端口,用于选择输入的数据。
- `Y` 是输出端口,输出被选中的数据。
### 2. 真值表
<img src="多路数据选择器.assets/真值表.png" style="zoom:;" />
在 S 分别取 0、1、2、3 的时候 Y 分别输出 A、B、C、D 的值。
### 3. 顶层模块
```verilog
module Mux4 #(
parameter DATA_WIDTH = 8,
parameter SELECT_WIDTH = $clog2(4) // $clog2(x)返回大于等于log2(x)的最小整数
) (
input wire [DATA_WIDTH - 1: 0] A,
input wire [DATA_WIDTH - 1: 0] B,
input wire [DATA_WIDTH - 1: 0] C,
input wire [DATA_WIDTH - 1: 0] D,
input wire [SELECT_WIDTH - 1: 0] S,
output reg [DATA_WIDTH - 1: 0] Y
);
// TODO你的代码实现
endmodule
```
在上述代码中,顶层模块名为 `Mux4`,它有四个端口:
- `A` 、`B` 、`C` 和 `D`是输入端口,表示输入的数据。
- `S` 是选择端口,用于选择输入的数据。
- `Y` 是输出端口,输出被选中的数据。
其中我们使用了参数化的设计,这有利于我们对模块进行高效的拓展。
请补充代码,完成多路数据选择器的设计,使得多路数据选择器的行为满足真值表。

View File

@ -1,19 +0,0 @@
# 标题
## 一、实验介绍
## 二、实验目的
## 三、实验要求
## 四、实验步骤
### 1. 框图
### 2. 真值表
### 3. 顶层模块
在上述代码中,顶层模块名为 `Adder_Subtractor`,它有八个端口:
请补充代码,完成 4 位二进制加减法器的设计。

View File

@ -1,676 +0,0 @@
<mxfile host="65bd71144e">
<diagram id="rebtU5tXmGY_HIzhLKTE" name="认识Verilog">
<mxGraphModel dx="696" dy="571" grid="1" gridSize="10" guides="1" tooltips="1" connect="1" arrows="1" fold="1" page="1" pageScale="1" pageWidth="1169" pageHeight="827" background="#ffffff" math="0" shadow="0">
<root>
<mxCell id="0"/>
<mxCell id="1" parent="0"/>
<mxCell id="7ks481zEIm87HgxM2ex8-72" value="" style="group" parent="1" vertex="1" connectable="0">
<mxGeometry x="530" y="360" width="360" height="410" as="geometry"/>
</mxCell>
<mxCell id="7ks481zEIm87HgxM2ex8-44" style="edgeStyle=orthogonalEdgeStyle;rounded=0;html=1;exitX=0;exitY=0.5;exitDx=0;exitDy=0;strokeColor=#000000;strokeWidth=3;fontSize=17;fontColor=#000000;startArrow=none;startFill=0;endArrow=none;endFill=0;" parent="7ks481zEIm87HgxM2ex8-72" source="7ks481zEIm87HgxM2ex8-47" edge="1">
<mxGeometry relative="1" as="geometry">
<mxPoint x="80" y="30" as="targetPoint"/>
</mxGeometry>
</mxCell>
<mxCell id="7ks481zEIm87HgxM2ex8-45" style="edgeStyle=orthogonalEdgeStyle;rounded=0;html=1;exitX=0.25;exitY=1;exitDx=0;exitDy=0;strokeColor=#000000;strokeWidth=3;fontSize=17;fontColor=#000000;startArrow=none;startFill=0;endArrow=none;endFill=0;" parent="7ks481zEIm87HgxM2ex8-72" source="7ks481zEIm87HgxM2ex8-47" edge="1">
<mxGeometry relative="1" as="geometry">
<mxPoint y="119.90476190476193" as="targetPoint"/>
</mxGeometry>
</mxCell>
<mxCell id="7ks481zEIm87HgxM2ex8-46" style="edgeStyle=orthogonalEdgeStyle;rounded=0;html=1;exitX=0.75;exitY=1;exitDx=0;exitDy=0;strokeColor=#000000;strokeWidth=3;fontSize=17;fontColor=#000000;startArrow=none;startFill=0;endArrow=none;endFill=0;" parent="7ks481zEIm87HgxM2ex8-72" source="7ks481zEIm87HgxM2ex8-47" edge="1">
<mxGeometry relative="1" as="geometry">
<mxPoint y="179.90476190476193" as="targetPoint"/>
</mxGeometry>
</mxCell>
<mxCell id="7ks481zEIm87HgxM2ex8-47" value="MUX" style="shape=trapezoid;perimeter=trapezoidPerimeter;whiteSpace=wrap;html=1;fixedSize=1;labelBackgroundColor=none;strokeColor=#000000;strokeWidth=3;fontSize=17;fontColor=#000000;fillColor=none;rotation=90;" parent="7ks481zEIm87HgxM2ex8-72" vertex="1">
<mxGeometry x="20" y="120" width="120" height="60" as="geometry"/>
</mxCell>
<mxCell id="7ks481zEIm87HgxM2ex8-48" value="0" style="text;strokeColor=none;align=center;fillColor=none;html=1;verticalAlign=middle;whiteSpace=wrap;rounded=0;labelBackgroundColor=none;strokeWidth=3;fontSize=17;fontColor=#000000;" parent="7ks481zEIm87HgxM2ex8-72" vertex="1">
<mxGeometry x="40" y="106" width="40" height="30" as="geometry"/>
</mxCell>
<mxCell id="7ks481zEIm87HgxM2ex8-49" value="1" style="text;strokeColor=none;align=center;fillColor=none;html=1;verticalAlign=middle;whiteSpace=wrap;rounded=0;labelBackgroundColor=none;strokeWidth=3;fontSize=17;fontColor=#000000;" parent="7ks481zEIm87HgxM2ex8-72" vertex="1">
<mxGeometry x="40" y="166" width="40" height="30" as="geometry"/>
</mxCell>
<mxCell id="7ks481zEIm87HgxM2ex8-50" value="W0" style="text;strokeColor=none;align=center;fillColor=none;html=1;verticalAlign=middle;whiteSpace=wrap;rounded=0;labelBackgroundColor=none;strokeWidth=3;fontSize=17;fontColor=#000000;" parent="7ks481zEIm87HgxM2ex8-72" vertex="1">
<mxGeometry y="90" width="40" height="30" as="geometry"/>
</mxCell>
<mxCell id="7ks481zEIm87HgxM2ex8-51" value="W1" style="text;strokeColor=none;align=center;fillColor=none;html=1;verticalAlign=middle;whiteSpace=wrap;rounded=0;labelBackgroundColor=none;strokeWidth=3;fontSize=17;fontColor=#000000;" parent="7ks481zEIm87HgxM2ex8-72" vertex="1">
<mxGeometry x="2" y="151" width="40" height="30" as="geometry"/>
</mxCell>
<mxCell id="7ks481zEIm87HgxM2ex8-52" value="S0" style="text;strokeColor=none;align=center;fillColor=none;html=1;verticalAlign=middle;whiteSpace=wrap;rounded=0;labelBackgroundColor=none;strokeWidth=3;fontSize=17;fontColor=#000000;" parent="7ks481zEIm87HgxM2ex8-72" vertex="1">
<mxGeometry x="60" width="40" height="30" as="geometry"/>
</mxCell>
<mxCell id="7ks481zEIm87HgxM2ex8-53" value="out0" style="text;strokeColor=none;align=center;fillColor=none;html=1;verticalAlign=middle;whiteSpace=wrap;rounded=0;labelBackgroundColor=none;strokeWidth=3;fontSize=17;fontColor=#000000;" parent="7ks481zEIm87HgxM2ex8-72" vertex="1">
<mxGeometry x="130" y="121" width="40" height="30" as="geometry"/>
</mxCell>
<mxCell id="7ks481zEIm87HgxM2ex8-54" style="edgeStyle=orthogonalEdgeStyle;rounded=0;html=1;exitX=0;exitY=0.5;exitDx=0;exitDy=0;strokeColor=#000000;strokeWidth=3;fontSize=17;fontColor=#000000;startArrow=none;startFill=0;endArrow=oval;endFill=1;" parent="7ks481zEIm87HgxM2ex8-72" source="7ks481zEIm87HgxM2ex8-57" edge="1">
<mxGeometry relative="1" as="geometry">
<mxPoint x="80" y="58" as="targetPoint"/>
<Array as="points">
<mxPoint x="80" y="270"/>
<mxPoint x="120" y="270"/>
<mxPoint x="120" y="58"/>
</Array>
</mxGeometry>
</mxCell>
<mxCell id="7ks481zEIm87HgxM2ex8-55" style="edgeStyle=orthogonalEdgeStyle;rounded=0;html=1;exitX=0.25;exitY=1;exitDx=0;exitDy=0;strokeColor=#000000;strokeWidth=3;fontSize=17;fontColor=#000000;startArrow=none;startFill=0;endArrow=none;endFill=0;" parent="7ks481zEIm87HgxM2ex8-72" source="7ks481zEIm87HgxM2ex8-57" edge="1">
<mxGeometry relative="1" as="geometry">
<mxPoint y="319.9047619047619" as="targetPoint"/>
</mxGeometry>
</mxCell>
<mxCell id="7ks481zEIm87HgxM2ex8-56" style="edgeStyle=orthogonalEdgeStyle;rounded=0;html=1;exitX=0.75;exitY=1;exitDx=0;exitDy=0;strokeColor=#000000;strokeWidth=3;fontSize=17;fontColor=#000000;startArrow=none;startFill=0;endArrow=none;endFill=0;" parent="7ks481zEIm87HgxM2ex8-72" source="7ks481zEIm87HgxM2ex8-57" edge="1">
<mxGeometry relative="1" as="geometry">
<mxPoint y="379.9047619047619" as="targetPoint"/>
</mxGeometry>
</mxCell>
<mxCell id="7ks481zEIm87HgxM2ex8-57" value="MUX" style="shape=trapezoid;perimeter=trapezoidPerimeter;whiteSpace=wrap;html=1;fixedSize=1;labelBackgroundColor=none;strokeColor=#000000;strokeWidth=3;fontSize=17;fontColor=#000000;fillColor=none;rotation=90;" parent="7ks481zEIm87HgxM2ex8-72" vertex="1">
<mxGeometry x="20" y="320" width="120" height="60" as="geometry"/>
</mxCell>
<mxCell id="7ks481zEIm87HgxM2ex8-58" value="0" style="text;strokeColor=none;align=center;fillColor=none;html=1;verticalAlign=middle;whiteSpace=wrap;rounded=0;labelBackgroundColor=none;strokeWidth=3;fontSize=17;fontColor=#000000;" parent="7ks481zEIm87HgxM2ex8-72" vertex="1">
<mxGeometry x="40" y="306" width="40" height="30" as="geometry"/>
</mxCell>
<mxCell id="7ks481zEIm87HgxM2ex8-59" value="1" style="text;strokeColor=none;align=center;fillColor=none;html=1;verticalAlign=middle;whiteSpace=wrap;rounded=0;labelBackgroundColor=none;strokeWidth=3;fontSize=17;fontColor=#000000;" parent="7ks481zEIm87HgxM2ex8-72" vertex="1">
<mxGeometry x="40" y="366" width="40" height="30" as="geometry"/>
</mxCell>
<mxCell id="7ks481zEIm87HgxM2ex8-60" value="W2" style="text;strokeColor=none;align=center;fillColor=none;html=1;verticalAlign=middle;whiteSpace=wrap;rounded=0;labelBackgroundColor=none;strokeWidth=3;fontSize=17;fontColor=#000000;" parent="7ks481zEIm87HgxM2ex8-72" vertex="1">
<mxGeometry y="290" width="40" height="30" as="geometry"/>
</mxCell>
<mxCell id="7ks481zEIm87HgxM2ex8-61" value="W3" style="text;strokeColor=none;align=center;fillColor=none;html=1;verticalAlign=middle;whiteSpace=wrap;rounded=0;labelBackgroundColor=none;strokeWidth=3;fontSize=17;fontColor=#000000;" parent="7ks481zEIm87HgxM2ex8-72" vertex="1">
<mxGeometry x="2" y="351" width="40" height="30" as="geometry"/>
</mxCell>
<mxCell id="7ks481zEIm87HgxM2ex8-62" value="out1" style="text;strokeColor=none;align=center;fillColor=none;html=1;verticalAlign=middle;whiteSpace=wrap;rounded=0;labelBackgroundColor=none;strokeWidth=3;fontSize=17;fontColor=#000000;" parent="7ks481zEIm87HgxM2ex8-72" vertex="1">
<mxGeometry x="130" y="320" width="40" height="30" as="geometry"/>
</mxCell>
<mxCell id="7ks481zEIm87HgxM2ex8-63" style="edgeStyle=orthogonalEdgeStyle;rounded=0;html=1;exitX=0;exitY=0.5;exitDx=0;exitDy=0;strokeColor=#000000;strokeWidth=3;fontSize=17;fontColor=#000000;startArrow=none;startFill=0;endArrow=none;endFill=0;" parent="7ks481zEIm87HgxM2ex8-72" source="7ks481zEIm87HgxM2ex8-67" edge="1">
<mxGeometry relative="1" as="geometry">
<mxPoint x="140" y="30" as="targetPoint"/>
<Array as="points">
<mxPoint x="270" y="110"/>
<mxPoint x="140" y="110"/>
</Array>
</mxGeometry>
</mxCell>
<mxCell id="7ks481zEIm87HgxM2ex8-64" style="edgeStyle=orthogonalEdgeStyle;rounded=0;html=1;exitX=0.5;exitY=0;exitDx=0;exitDy=0;strokeColor=#000000;strokeWidth=3;fontSize=17;fontColor=#000000;startArrow=none;startFill=0;endArrow=none;endFill=0;" parent="7ks481zEIm87HgxM2ex8-72" source="7ks481zEIm87HgxM2ex8-67" edge="1">
<mxGeometry relative="1" as="geometry">
<mxPoint x="340" y="250.90476190476193" as="targetPoint"/>
</mxGeometry>
</mxCell>
<mxCell id="7ks481zEIm87HgxM2ex8-65" style="edgeStyle=orthogonalEdgeStyle;rounded=0;html=1;exitX=0.25;exitY=1;exitDx=0;exitDy=0;strokeColor=#000000;strokeWidth=3;fontSize=17;fontColor=#000000;startArrow=none;startFill=0;endArrow=none;endFill=0;entryX=0.5;entryY=0;entryDx=0;entryDy=0;" parent="7ks481zEIm87HgxM2ex8-72" source="7ks481zEIm87HgxM2ex8-67" target="7ks481zEIm87HgxM2ex8-47" edge="1">
<mxGeometry relative="1" as="geometry">
<mxPoint x="190" y="220.90476190476193" as="targetPoint"/>
</mxGeometry>
</mxCell>
<mxCell id="7ks481zEIm87HgxM2ex8-66" style="edgeStyle=orthogonalEdgeStyle;rounded=0;html=1;exitX=0.75;exitY=1;exitDx=0;exitDy=0;strokeColor=#000000;strokeWidth=3;fontSize=17;fontColor=#000000;startArrow=none;startFill=0;endArrow=none;endFill=0;entryX=0.5;entryY=0;entryDx=0;entryDy=0;" parent="7ks481zEIm87HgxM2ex8-72" source="7ks481zEIm87HgxM2ex8-67" target="7ks481zEIm87HgxM2ex8-57" edge="1">
<mxGeometry relative="1" as="geometry">
<mxPoint x="190" y="280.9047619047619" as="targetPoint"/>
</mxGeometry>
</mxCell>
<mxCell id="7ks481zEIm87HgxM2ex8-67" value="MUX" style="shape=trapezoid;perimeter=trapezoidPerimeter;whiteSpace=wrap;html=1;fixedSize=1;labelBackgroundColor=none;strokeColor=#000000;strokeWidth=3;fontSize=17;fontColor=#000000;fillColor=none;rotation=90;" parent="7ks481zEIm87HgxM2ex8-72" vertex="1">
<mxGeometry x="210" y="221" width="120" height="60" as="geometry"/>
</mxCell>
<mxCell id="7ks481zEIm87HgxM2ex8-68" value="0" style="text;strokeColor=none;align=center;fillColor=none;html=1;verticalAlign=middle;whiteSpace=wrap;rounded=0;labelBackgroundColor=none;strokeWidth=3;fontSize=17;fontColor=#000000;" parent="7ks481zEIm87HgxM2ex8-72" vertex="1">
<mxGeometry x="230" y="207" width="40" height="30" as="geometry"/>
</mxCell>
<mxCell id="7ks481zEIm87HgxM2ex8-69" value="1" style="text;strokeColor=none;align=center;fillColor=none;html=1;verticalAlign=middle;whiteSpace=wrap;rounded=0;labelBackgroundColor=none;strokeWidth=3;fontSize=17;fontColor=#000000;" parent="7ks481zEIm87HgxM2ex8-72" vertex="1">
<mxGeometry x="230" y="267" width="40" height="30" as="geometry"/>
</mxCell>
<mxCell id="7ks481zEIm87HgxM2ex8-70" value="S1" style="text;strokeColor=none;align=center;fillColor=none;html=1;verticalAlign=middle;whiteSpace=wrap;rounded=0;labelBackgroundColor=none;strokeWidth=3;fontSize=17;fontColor=#000000;" parent="7ks481zEIm87HgxM2ex8-72" vertex="1">
<mxGeometry x="120" width="40" height="30" as="geometry"/>
</mxCell>
<mxCell id="7ks481zEIm87HgxM2ex8-71" value="out" style="text;strokeColor=none;align=center;fillColor=none;html=1;verticalAlign=middle;whiteSpace=wrap;rounded=0;labelBackgroundColor=none;strokeWidth=3;fontSize=17;fontColor=#000000;" parent="7ks481zEIm87HgxM2ex8-72" vertex="1">
<mxGeometry x="320" y="221" width="40" height="30" as="geometry"/>
</mxCell>
<mxCell id="7ks481zEIm87HgxM2ex8-74" value="" style="group" parent="1" vertex="1" connectable="0">
<mxGeometry x="30" y="414" width="480" height="380" as="geometry"/>
</mxCell>
<mxCell id="QMG38J2CW0rPUgtdJ5ai-17" style="edgeStyle=orthogonalEdgeStyle;rounded=0;html=1;exitX=0;exitY=0.75;exitDx=0;exitDy=0;exitPerimeter=0;strokeColor=#000000;strokeWidth=3;endArrow=none;endFill=0;" parent="7ks481zEIm87HgxM2ex8-74" source="QMG38J2CW0rPUgtdJ5ai-18" edge="1">
<mxGeometry relative="1" as="geometry">
<mxPoint x="60" y="235" as="targetPoint"/>
</mxGeometry>
</mxCell>
<mxCell id="QMG38J2CW0rPUgtdJ5ai-18" value="AND" style="verticalLabelPosition=middle;shadow=0;dashed=0;align=center;html=1;verticalAlign=middle;shape=mxgraph.electrical.logic_gates.logic_gate;operation=and;fillColor=none;strokeColor=#000000;strokeWidth=3;fontColor=#000000;fontSize=20;fontStyle=1;labelPosition=center;" parent="7ks481zEIm87HgxM2ex8-74" vertex="1">
<mxGeometry x="190" y="190" width="100" height="60" as="geometry"/>
</mxCell>
<mxCell id="QMG38J2CW0rPUgtdJ5ai-20" style="edgeStyle=orthogonalEdgeStyle;rounded=0;html=1;exitX=0;exitY=0.25;exitDx=0;exitDy=0;exitPerimeter=0;strokeColor=#000000;strokeWidth=3;endArrow=none;endFill=0;" parent="7ks481zEIm87HgxM2ex8-74" source="QMG38J2CW0rPUgtdJ5ai-22" edge="1">
<mxGeometry relative="1" as="geometry">
<mxPoint x="60" y="335" as="targetPoint"/>
</mxGeometry>
</mxCell>
<mxCell id="QMG38J2CW0rPUgtdJ5ai-21" style="edgeStyle=orthogonalEdgeStyle;rounded=0;html=1;exitX=0;exitY=0.75;exitDx=0;exitDy=0;exitPerimeter=0;strokeColor=#000000;strokeWidth=3;endArrow=oval;endFill=1;" parent="7ks481zEIm87HgxM2ex8-74" source="QMG38J2CW0rPUgtdJ5ai-22" edge="1">
<mxGeometry relative="1" as="geometry">
<mxPoint x="140" y="50" as="targetPoint"/>
<Array as="points">
<mxPoint x="90" y="365"/>
<mxPoint x="90" y="50"/>
</Array>
</mxGeometry>
</mxCell>
<mxCell id="QMG38J2CW0rPUgtdJ5ai-22" value="AND" style="verticalLabelPosition=middle;shadow=0;dashed=0;align=center;html=1;verticalAlign=middle;shape=mxgraph.electrical.logic_gates.logic_gate;operation=and;fillColor=none;strokeColor=#000000;strokeWidth=3;fontSize=20;fontStyle=1;fontColor=#000000;labelPosition=center;" parent="7ks481zEIm87HgxM2ex8-74" vertex="1">
<mxGeometry x="190" y="320" width="100" height="60" as="geometry"/>
</mxCell>
<mxCell id="QMG38J2CW0rPUgtdJ5ai-23" value="&lt;font color=&quot;#000000&quot; style=&quot;font-size: 20px;&quot;&gt;OR&lt;/font&gt;" style="verticalLabelPosition=middle;shadow=0;dashed=0;align=center;html=1;verticalAlign=middle;shape=mxgraph.electrical.logic_gates.logic_gate;operation=or;strokeColor=#000000;strokeWidth=3;fillColor=none;fontStyle=1;fontSize=20;labelPosition=center;" parent="7ks481zEIm87HgxM2ex8-74" vertex="1">
<mxGeometry x="320" y="250" width="100" height="60" as="geometry"/>
</mxCell>
<mxCell id="QMG38J2CW0rPUgtdJ5ai-16" style="edgeStyle=orthogonalEdgeStyle;html=1;exitX=1;exitY=0.5;exitDx=0;exitDy=0;exitPerimeter=0;entryX=0;entryY=0.25;entryDx=0;entryDy=0;entryPerimeter=0;rounded=0;strokeColor=#000000;strokeWidth=3;endArrow=none;endFill=0;" parent="7ks481zEIm87HgxM2ex8-74" source="QMG38J2CW0rPUgtdJ5ai-18" target="QMG38J2CW0rPUgtdJ5ai-23" edge="1">
<mxGeometry relative="1" as="geometry"/>
</mxCell>
<mxCell id="QMG38J2CW0rPUgtdJ5ai-19" style="edgeStyle=orthogonalEdgeStyle;rounded=0;html=1;exitX=1;exitY=0.5;exitDx=0;exitDy=0;exitPerimeter=0;entryX=0;entryY=0.75;entryDx=0;entryDy=0;entryPerimeter=0;strokeColor=#000000;strokeWidth=3;endArrow=none;endFill=0;" parent="7ks481zEIm87HgxM2ex8-74" source="QMG38J2CW0rPUgtdJ5ai-22" target="QMG38J2CW0rPUgtdJ5ai-23" edge="1">
<mxGeometry relative="1" as="geometry"/>
</mxCell>
<mxCell id="QMG38J2CW0rPUgtdJ5ai-24" style="edgeStyle=orthogonalEdgeStyle;rounded=0;html=1;exitX=1;exitY=0.5;exitDx=0;exitDy=0;exitPerimeter=0;entryX=0;entryY=0.25;entryDx=0;entryDy=0;entryPerimeter=0;strokeColor=#000000;strokeWidth=3;endArrow=none;endFill=0;" parent="7ks481zEIm87HgxM2ex8-74" source="QMG38J2CW0rPUgtdJ5ai-26" target="QMG38J2CW0rPUgtdJ5ai-18" edge="1">
<mxGeometry relative="1" as="geometry"/>
</mxCell>
<mxCell id="QMG38J2CW0rPUgtdJ5ai-25" style="edgeStyle=orthogonalEdgeStyle;rounded=0;html=1;exitX=0;exitY=0.5;exitDx=0;exitDy=0;exitPerimeter=0;strokeColor=#000000;strokeWidth=3;endArrow=none;endFill=0;" parent="7ks481zEIm87HgxM2ex8-74" source="QMG38J2CW0rPUgtdJ5ai-26" edge="1">
<mxGeometry relative="1" as="geometry">
<mxPoint x="140" y="10" as="targetPoint"/>
</mxGeometry>
</mxCell>
<mxCell id="QMG38J2CW0rPUgtdJ5ai-26" value="" style="verticalLabelPosition=middle;shadow=0;dashed=0;align=center;html=1;verticalAlign=middle;shape=mxgraph.electrical.logic_gates.inverter_2;strokeColor=#000000;strokeWidth=3;fillColor=none;rotation=90;fontColor=#000000;labelPosition=center;fontStyle=1;fontSize=15;" parent="7ks481zEIm87HgxM2ex8-74" vertex="1">
<mxGeometry x="90" y="100" width="100" height="60" as="geometry"/>
</mxCell>
<mxCell id="QMG38J2CW0rPUgtdJ5ai-27" value="&lt;font color=&quot;#000000&quot; style=&quot;font-size: 24px;&quot;&gt;S&lt;/font&gt;" style="text;strokeColor=none;align=center;fillColor=none;html=1;verticalAlign=middle;whiteSpace=wrap;rounded=0;strokeWidth=3;fontStyle=1;fontSize=24;" parent="7ks481zEIm87HgxM2ex8-74" vertex="1">
<mxGeometry x="130" width="60" height="30" as="geometry"/>
</mxCell>
<mxCell id="QMG38J2CW0rPUgtdJ5ai-28" value="&lt;font color=&quot;#000000&quot;&gt;in0&lt;/font&gt;" style="text;strokeColor=none;align=center;fillColor=none;html=1;verticalAlign=middle;whiteSpace=wrap;rounded=0;strokeWidth=3;fontStyle=1;fontSize=24;" parent="7ks481zEIm87HgxM2ex8-74" vertex="1">
<mxGeometry y="220" width="60" height="30" as="geometry"/>
</mxCell>
<mxCell id="QMG38J2CW0rPUgtdJ5ai-29" value="&lt;font color=&quot;#000000&quot;&gt;in1&lt;/font&gt;" style="text;strokeColor=none;align=center;fillColor=none;html=1;verticalAlign=middle;whiteSpace=wrap;rounded=0;strokeWidth=3;fontStyle=1;fontSize=24;" parent="7ks481zEIm87HgxM2ex8-74" vertex="1">
<mxGeometry y="320" width="60" height="30" as="geometry"/>
</mxCell>
<mxCell id="QMG38J2CW0rPUgtdJ5ai-30" value="&lt;font color=&quot;#000000&quot;&gt;out&lt;/font&gt;" style="text;strokeColor=none;align=center;fillColor=none;html=1;verticalAlign=middle;whiteSpace=wrap;rounded=0;strokeWidth=3;fontStyle=1;fontSize=24;" parent="7ks481zEIm87HgxM2ex8-74" vertex="1">
<mxGeometry x="420" y="265" width="60" height="30" as="geometry"/>
</mxCell>
<mxCell id="QMG38J2CW0rPUgtdJ5ai-31" value="&lt;font color=&quot;#000000&quot; style=&quot;font-size: 17px;&quot;&gt;NOT&lt;/font&gt;" style="text;strokeColor=none;align=center;fillColor=none;html=1;verticalAlign=middle;whiteSpace=wrap;rounded=0;strokeWidth=3;fontStyle=1;fontSize=17;" parent="7ks481zEIm87HgxM2ex8-74" vertex="1">
<mxGeometry x="110" y="93" width="60" height="30" as="geometry"/>
</mxCell>
<mxCell id="7ks481zEIm87HgxM2ex8-75" value="" style="group" parent="1" vertex="1" connectable="0">
<mxGeometry x="370" y="20" width="170" height="160" as="geometry"/>
</mxCell>
<mxCell id="QwQY3PDaorP3m9qOKkc0-16" style="edgeStyle=orthogonalEdgeStyle;rounded=0;html=1;exitX=0;exitY=0.5;exitDx=0;exitDy=0;strokeColor=#000000;strokeWidth=3;fontSize=17;fontColor=#000000;startArrow=none;startFill=0;endArrow=none;endFill=0;" parent="7ks481zEIm87HgxM2ex8-75" source="QwQY3PDaorP3m9qOKkc0-20" edge="1">
<mxGeometry relative="1" as="geometry">
<mxPoint x="79.80952380952385" as="targetPoint"/>
</mxGeometry>
</mxCell>
<mxCell id="QwQY3PDaorP3m9qOKkc0-17" style="edgeStyle=orthogonalEdgeStyle;rounded=0;html=1;exitX=0.5;exitY=0;exitDx=0;exitDy=0;strokeColor=#000000;strokeWidth=3;fontSize=17;fontColor=#000000;startArrow=none;startFill=0;endArrow=none;endFill=0;" parent="7ks481zEIm87HgxM2ex8-75" source="QwQY3PDaorP3m9qOKkc0-20" edge="1">
<mxGeometry relative="1" as="geometry">
<mxPoint x="150" y="99.90476190476193" as="targetPoint"/>
</mxGeometry>
</mxCell>
<mxCell id="QwQY3PDaorP3m9qOKkc0-18" style="edgeStyle=orthogonalEdgeStyle;rounded=0;html=1;exitX=0.25;exitY=1;exitDx=0;exitDy=0;strokeColor=#000000;strokeWidth=3;fontSize=17;fontColor=#000000;startArrow=none;startFill=0;endArrow=none;endFill=0;" parent="7ks481zEIm87HgxM2ex8-75" source="QwQY3PDaorP3m9qOKkc0-20" edge="1">
<mxGeometry relative="1" as="geometry">
<mxPoint y="69.90476190476193" as="targetPoint"/>
</mxGeometry>
</mxCell>
<mxCell id="QwQY3PDaorP3m9qOKkc0-19" style="edgeStyle=orthogonalEdgeStyle;rounded=0;html=1;exitX=0.75;exitY=1;exitDx=0;exitDy=0;strokeColor=#000000;strokeWidth=3;fontSize=17;fontColor=#000000;startArrow=none;startFill=0;endArrow=none;endFill=0;" parent="7ks481zEIm87HgxM2ex8-75" source="QwQY3PDaorP3m9qOKkc0-20" edge="1">
<mxGeometry relative="1" as="geometry">
<mxPoint y="129.90476190476193" as="targetPoint"/>
</mxGeometry>
</mxCell>
<mxCell id="QwQY3PDaorP3m9qOKkc0-20" value="MUX" style="shape=trapezoid;perimeter=trapezoidPerimeter;whiteSpace=wrap;html=1;fixedSize=1;labelBackgroundColor=none;strokeColor=#000000;strokeWidth=3;fontSize=17;fontColor=#000000;fillColor=none;rotation=90;" parent="7ks481zEIm87HgxM2ex8-75" vertex="1">
<mxGeometry x="20" y="70" width="120" height="60" as="geometry"/>
</mxCell>
<mxCell id="QwQY3PDaorP3m9qOKkc0-21" value="0" style="text;strokeColor=none;align=center;fillColor=none;html=1;verticalAlign=middle;whiteSpace=wrap;rounded=0;labelBackgroundColor=none;strokeWidth=3;fontSize=17;fontColor=#000000;" parent="7ks481zEIm87HgxM2ex8-75" vertex="1">
<mxGeometry x="40" y="56" width="40" height="30" as="geometry"/>
</mxCell>
<mxCell id="QwQY3PDaorP3m9qOKkc0-22" value="1" style="text;strokeColor=none;align=center;fillColor=none;html=1;verticalAlign=middle;whiteSpace=wrap;rounded=0;labelBackgroundColor=none;strokeWidth=3;fontSize=17;fontColor=#000000;" parent="7ks481zEIm87HgxM2ex8-75" vertex="1">
<mxGeometry x="40" y="116" width="40" height="30" as="geometry"/>
</mxCell>
<mxCell id="QwQY3PDaorP3m9qOKkc0-23" value="in0" style="text;strokeColor=none;align=center;fillColor=none;html=1;verticalAlign=middle;whiteSpace=wrap;rounded=0;labelBackgroundColor=none;strokeWidth=3;fontSize=17;fontColor=#000000;" parent="7ks481zEIm87HgxM2ex8-75" vertex="1">
<mxGeometry y="40" width="40" height="30" as="geometry"/>
</mxCell>
<mxCell id="QwQY3PDaorP3m9qOKkc0-24" value="in1" style="text;strokeColor=none;align=center;fillColor=none;html=1;verticalAlign=middle;whiteSpace=wrap;rounded=0;labelBackgroundColor=none;strokeWidth=3;fontSize=17;fontColor=#000000;" parent="7ks481zEIm87HgxM2ex8-75" vertex="1">
<mxGeometry x="2" y="101" width="40" height="30" as="geometry"/>
</mxCell>
<mxCell id="QwQY3PDaorP3m9qOKkc0-25" value="s" style="text;strokeColor=none;align=center;fillColor=none;html=1;verticalAlign=middle;whiteSpace=wrap;rounded=0;labelBackgroundColor=none;strokeWidth=3;fontSize=17;fontColor=#000000;" parent="7ks481zEIm87HgxM2ex8-75" vertex="1">
<mxGeometry x="80" width="40" height="30" as="geometry"/>
</mxCell>
<mxCell id="QwQY3PDaorP3m9qOKkc0-26" value="out" style="text;strokeColor=none;align=center;fillColor=none;html=1;verticalAlign=middle;whiteSpace=wrap;rounded=0;labelBackgroundColor=none;strokeWidth=3;fontSize=17;fontColor=#000000;" parent="7ks481zEIm87HgxM2ex8-75" vertex="1">
<mxGeometry x="130" y="71" width="40" height="30" as="geometry"/>
</mxCell>
<mxCell id="7ks481zEIm87HgxM2ex8-76" value="" style="group" parent="1" vertex="1" connectable="0">
<mxGeometry x="20" y="40" width="330" height="150" as="geometry"/>
</mxCell>
<mxCell id="2" value="&lt;font color=&quot;#000000&quot;&gt;and1&lt;/font&gt;" style="verticalLabelPosition=bottom;shadow=0;dashed=0;align=center;html=1;verticalAlign=top;shape=mxgraph.electrical.logic_gates.logic_gate;operation=and;fillColor=none;strokeColor=#000000;strokeWidth=3;fontStyle=1;movable=1;resizable=1;rotatable=1;deletable=1;editable=1;connectable=1;" parent="7ks481zEIm87HgxM2ex8-76" vertex="1">
<mxGeometry x="40" width="100" height="60" as="geometry"/>
</mxCell>
<mxCell id="3" value="&lt;font color=&quot;#000000&quot;&gt;and2&lt;/font&gt;" style="verticalLabelPosition=bottom;shadow=0;dashed=0;align=center;html=1;verticalAlign=top;shape=mxgraph.electrical.logic_gates.logic_gate;operation=and;fillColor=none;strokeColor=#000000;strokeWidth=3;fontStyle=1;movable=1;resizable=1;rotatable=1;deletable=1;editable=1;connectable=1;" parent="7ks481zEIm87HgxM2ex8-76" vertex="1">
<mxGeometry x="40" y="90" width="100" height="60" as="geometry"/>
</mxCell>
<mxCell id="4" value="and3" style="verticalLabelPosition=bottom;shadow=0;dashed=0;align=center;html=1;verticalAlign=top;shape=mxgraph.electrical.logic_gates.logic_gate;operation=and;fillColor=none;strokeColor=#000000;strokeWidth=3;fontColor=#000000;fontStyle=1;movable=1;resizable=1;rotatable=1;deletable=1;editable=1;connectable=1;" parent="7ks481zEIm87HgxM2ex8-76" vertex="1">
<mxGeometry x="190" y="43" width="100" height="60" as="geometry"/>
</mxCell>
<mxCell id="6" style="edgeStyle=orthogonalEdgeStyle;html=1;exitX=1;exitY=0.5;exitDx=0;exitDy=0;exitPerimeter=0;entryX=0;entryY=0.25;entryDx=0;entryDy=0;entryPerimeter=0;strokeColor=#000000;rounded=0;strokeWidth=3;endArrow=none;endFill=0;movable=1;resizable=1;rotatable=1;deletable=1;editable=1;connectable=1;" parent="7ks481zEIm87HgxM2ex8-76" source="2" target="4" edge="1">
<mxGeometry relative="1" as="geometry"/>
</mxCell>
<mxCell id="7" style="edgeStyle=orthogonalEdgeStyle;rounded=0;html=1;exitX=1;exitY=0.5;exitDx=0;exitDy=0;exitPerimeter=0;entryX=0;entryY=0.75;entryDx=0;entryDy=0;entryPerimeter=0;strokeColor=#000000;strokeWidth=3;endArrow=none;endFill=0;movable=1;resizable=1;rotatable=1;deletable=1;editable=1;connectable=1;" parent="7ks481zEIm87HgxM2ex8-76" source="3" target="4" edge="1">
<mxGeometry relative="1" as="geometry"/>
</mxCell>
<mxCell id="8" value="a" style="text;strokeColor=none;align=center;fillColor=none;html=1;verticalAlign=middle;whiteSpace=wrap;rounded=0;strokeWidth=3;fontColor=#000000;fontStyle=1;movable=1;resizable=1;rotatable=1;deletable=1;editable=1;connectable=1;" parent="7ks481zEIm87HgxM2ex8-76" vertex="1">
<mxGeometry width="60" height="30" as="geometry"/>
</mxCell>
<mxCell id="9" value="b" style="text;strokeColor=none;align=center;fillColor=none;html=1;verticalAlign=middle;whiteSpace=wrap;rounded=0;strokeWidth=3;fontColor=#000000;fontStyle=1;movable=1;resizable=1;rotatable=1;deletable=1;editable=1;connectable=1;" parent="7ks481zEIm87HgxM2ex8-76" vertex="1">
<mxGeometry y="30" width="60" height="30" as="geometry"/>
</mxCell>
<mxCell id="11" value="c" style="text;strokeColor=none;align=center;fillColor=none;html=1;verticalAlign=middle;whiteSpace=wrap;rounded=0;strokeWidth=3;fontColor=#000000;fontStyle=1;movable=1;resizable=1;rotatable=1;deletable=1;editable=1;connectable=1;" parent="7ks481zEIm87HgxM2ex8-76" vertex="1">
<mxGeometry y="90" width="60" height="30" as="geometry"/>
</mxCell>
<mxCell id="12" value="d" style="text;strokeColor=none;align=center;fillColor=none;html=1;verticalAlign=middle;whiteSpace=wrap;rounded=0;strokeWidth=3;fontColor=#000000;fontStyle=1;movable=1;resizable=1;rotatable=1;deletable=1;editable=1;connectable=1;" parent="7ks481zEIm87HgxM2ex8-76" vertex="1">
<mxGeometry y="120" width="60" height="30" as="geometry"/>
</mxCell>
<mxCell id="13" value="y1" style="text;strokeColor=none;align=center;fillColor=none;html=1;verticalAlign=middle;whiteSpace=wrap;rounded=0;strokeWidth=3;fontColor=#000000;fontStyle=1;movable=1;resizable=1;rotatable=1;deletable=1;editable=1;connectable=1;" parent="7ks481zEIm87HgxM2ex8-76" vertex="1">
<mxGeometry x="110" width="60" height="30" as="geometry"/>
</mxCell>
<mxCell id="15" value="y2" style="text;strokeColor=none;align=center;fillColor=none;html=1;verticalAlign=middle;whiteSpace=wrap;rounded=0;strokeWidth=3;fontColor=#000000;fontStyle=1;movable=1;resizable=1;rotatable=1;deletable=1;editable=1;connectable=1;" parent="7ks481zEIm87HgxM2ex8-76" vertex="1">
<mxGeometry x="110" y="90" width="60" height="30" as="geometry"/>
</mxCell>
<mxCell id="16" value="y" style="text;strokeColor=none;align=center;fillColor=none;html=1;verticalAlign=middle;whiteSpace=wrap;rounded=0;strokeWidth=3;fontColor=#000000;fontStyle=1;movable=1;resizable=1;rotatable=1;deletable=1;editable=1;connectable=1;" parent="7ks481zEIm87HgxM2ex8-76" vertex="1">
<mxGeometry x="270" y="57" width="60" height="30" as="geometry"/>
</mxCell>
</root>
</mxGraphModel>
</diagram>
<diagram id="5C8ZGqh4Hf1FeQuMz4j9" name="全加器">
<mxGraphModel dx="696" dy="571" grid="1" gridSize="10" guides="1" tooltips="1" connect="1" arrows="1" fold="1" page="1" pageScale="1" pageWidth="1169" pageHeight="827" background="#ffffff" math="0" shadow="0">
<root>
<mxCell id="0"/>
<mxCell id="1" parent="0"/>
<mxCell id="gzdv8FFXtKBTtcGOgYej-1" value="" style="group" parent="1" vertex="1" connectable="0">
<mxGeometry x="100" y="410" width="609" height="336" as="geometry"/>
</mxCell>
<mxCell id="gzdv8FFXtKBTtcGOgYej-2" style="edgeStyle=orthogonalEdgeStyle;rounded=0;html=1;exitX=0;exitY=0.25;exitDx=0;exitDy=0;exitPerimeter=0;strokeWidth=3;endArrow=none;endFill=0;" parent="gzdv8FFXtKBTtcGOgYej-1" source="gzdv8FFXtKBTtcGOgYej-3" edge="1">
<mxGeometry relative="1" as="geometry">
<mxPoint x="52" y="134.75862068965523" as="targetPoint"/>
</mxGeometry>
</mxCell>
<mxCell id="gzdv8FFXtKBTtcGOgYej-3" value="XOR" style="verticalLabelPosition=middle;shadow=0;dashed=0;align=center;html=1;verticalAlign=middle;shape=mxgraph.electrical.logic_gates.logic_gate;operation=xor;labelBackgroundColor=none;strokeColor=#000000;strokeWidth=3;fontColor=#000000;fillColor=none;fontStyle=1;labelPosition=center;" parent="gzdv8FFXtKBTtcGOgYej-1" vertex="1">
<mxGeometry x="122" y="120" width="100" height="60" as="geometry"/>
</mxCell>
<mxCell id="gzdv8FFXtKBTtcGOgYej-4" style="edgeStyle=orthogonalEdgeStyle;rounded=0;html=1;exitX=0;exitY=0.25;exitDx=0;exitDy=0;exitPerimeter=0;strokeWidth=3;endArrow=oval;endFill=1;" parent="gzdv8FFXtKBTtcGOgYej-1" source="gzdv8FFXtKBTtcGOgYej-6" edge="1">
<mxGeometry relative="1" as="geometry">
<mxPoint x="262" y="46" as="targetPoint"/>
</mxGeometry>
</mxCell>
<mxCell id="gzdv8FFXtKBTtcGOgYej-5" style="edgeStyle=orthogonalEdgeStyle;rounded=0;html=1;exitX=0;exitY=0.75;exitDx=0;exitDy=0;exitPerimeter=0;strokeWidth=3;endArrow=oval;endFill=1;" parent="gzdv8FFXtKBTtcGOgYej-1" source="gzdv8FFXtKBTtcGOgYej-6" edge="1">
<mxGeometry relative="1" as="geometry">
<mxPoint x="212" y="15.999999999999886" as="targetPoint"/>
</mxGeometry>
</mxCell>
<mxCell id="gzdv8FFXtKBTtcGOgYej-6" value="AND" style="verticalLabelPosition=middle;shadow=0;dashed=0;align=center;html=1;verticalAlign=middle;shape=mxgraph.electrical.logic_gates.logic_gate;operation=and;labelBackgroundColor=none;strokeColor=#000000;strokeWidth=3;fontColor=#000000;fillColor=none;labelPosition=center;fontStyle=1" parent="gzdv8FFXtKBTtcGOgYej-1" vertex="1">
<mxGeometry x="282" y="206" width="100" height="60" as="geometry"/>
</mxCell>
<mxCell id="gzdv8FFXtKBTtcGOgYej-7" value="OR" style="verticalLabelPosition=middle;shadow=0;dashed=0;align=center;html=1;verticalAlign=middle;shape=mxgraph.electrical.logic_gates.logic_gate;operation=or;labelBackgroundColor=none;strokeColor=#000000;strokeWidth=3;fontColor=#000000;fillColor=none;fontStyle=1;labelPosition=center;" parent="gzdv8FFXtKBTtcGOgYej-1" vertex="1">
<mxGeometry x="442" y="61" width="100" height="60" as="geometry"/>
</mxCell>
<mxCell id="gzdv8FFXtKBTtcGOgYej-8" style="edgeStyle=orthogonalEdgeStyle;rounded=0;html=1;exitX=1;exitY=0.5;exitDx=0;exitDy=0;exitPerimeter=0;entryX=0;entryY=0.25;entryDx=0;entryDy=0;entryPerimeter=0;strokeColor=#000000;strokeWidth=3;fontColor=#000000;startArrow=none;startFill=0;endArrow=none;endFill=0;" parent="gzdv8FFXtKBTtcGOgYej-1" source="gzdv8FFXtKBTtcGOgYej-6" target="gzdv8FFXtKBTtcGOgYej-7" edge="1">
<mxGeometry relative="1" as="geometry">
<Array as="points">
<mxPoint x="402" y="236"/>
<mxPoint x="402" y="76"/>
</Array>
</mxGeometry>
</mxCell>
<mxCell id="gzdv8FFXtKBTtcGOgYej-9" style="edgeStyle=orthogonalEdgeStyle;rounded=0;html=1;exitX=0;exitY=0.25;exitDx=0;exitDy=0;exitPerimeter=0;strokeWidth=3;endArrow=oval;endFill=1;" parent="gzdv8FFXtKBTtcGOgYej-1" source="gzdv8FFXtKBTtcGOgYej-12" edge="1">
<mxGeometry relative="1" as="geometry">
<mxPoint x="102" y="166" as="targetPoint"/>
</mxGeometry>
</mxCell>
<mxCell id="gzdv8FFXtKBTtcGOgYej-10" style="edgeStyle=orthogonalEdgeStyle;rounded=0;html=1;exitX=0;exitY=0.75;exitDx=0;exitDy=0;exitPerimeter=0;strokeWidth=3;endArrow=oval;endFill=1;" parent="gzdv8FFXtKBTtcGOgYej-1" source="gzdv8FFXtKBTtcGOgYej-12" edge="1">
<mxGeometry relative="1" as="geometry">
<mxPoint x="72" y="136" as="targetPoint"/>
</mxGeometry>
</mxCell>
<mxCell id="gzdv8FFXtKBTtcGOgYej-11" style="edgeStyle=orthogonalEdgeStyle;rounded=0;html=1;exitX=1;exitY=0.5;exitDx=0;exitDy=0;exitPerimeter=0;entryX=0;entryY=0.75;entryDx=0;entryDy=0;entryPerimeter=0;strokeWidth=3;endArrow=none;endFill=0;" parent="gzdv8FFXtKBTtcGOgYej-1" source="gzdv8FFXtKBTtcGOgYej-12" target="gzdv8FFXtKBTtcGOgYej-7" edge="1">
<mxGeometry relative="1" as="geometry">
<Array as="points">
<mxPoint x="442" y="306"/>
</Array>
</mxGeometry>
</mxCell>
<mxCell id="gzdv8FFXtKBTtcGOgYej-12" value="AND" style="verticalLabelPosition=middle;shadow=0;dashed=0;align=center;html=1;verticalAlign=middle;shape=mxgraph.electrical.logic_gates.logic_gate;operation=and;labelBackgroundColor=none;strokeColor=#000000;strokeWidth=3;fontColor=#000000;fillColor=none;labelPosition=center;fontStyle=1" parent="gzdv8FFXtKBTtcGOgYej-1" vertex="1">
<mxGeometry x="122" y="276" width="100" height="60" as="geometry"/>
</mxCell>
<mxCell id="gzdv8FFXtKBTtcGOgYej-13" style="edgeStyle=orthogonalEdgeStyle;rounded=0;html=1;exitX=1;exitY=0.5;exitDx=0;exitDy=0;exitPerimeter=0;strokeWidth=3;endArrow=none;endFill=0;" parent="gzdv8FFXtKBTtcGOgYej-1" source="gzdv8FFXtKBTtcGOgYej-15" edge="1">
<mxGeometry relative="1" as="geometry">
<mxPoint x="541.9999999999998" y="30.470588235294144" as="targetPoint"/>
</mxGeometry>
</mxCell>
<mxCell id="gzdv8FFXtKBTtcGOgYej-14" style="edgeStyle=orthogonalEdgeStyle;rounded=0;html=1;exitX=0;exitY=0.25;exitDx=0;exitDy=0;exitPerimeter=0;strokeWidth=3;endArrow=none;endFill=0;" parent="gzdv8FFXtKBTtcGOgYej-1" source="gzdv8FFXtKBTtcGOgYej-15" edge="1">
<mxGeometry relative="1" as="geometry">
<mxPoint x="52" y="16.35294117647061" as="targetPoint"/>
</mxGeometry>
</mxCell>
<mxCell id="gzdv8FFXtKBTtcGOgYej-15" value="XOR" style="verticalLabelPosition=middle;shadow=0;dashed=0;align=center;html=1;verticalAlign=middle;shape=mxgraph.electrical.logic_gates.logic_gate;operation=xor;labelBackgroundColor=none;strokeColor=#000000;strokeWidth=3;fontColor=#000000;fillColor=none;fontStyle=1;labelPosition=center;" parent="gzdv8FFXtKBTtcGOgYej-1" vertex="1">
<mxGeometry x="282" y="1" width="100" height="60" as="geometry"/>
</mxCell>
<mxCell id="gzdv8FFXtKBTtcGOgYej-16" style="edgeStyle=orthogonalEdgeStyle;rounded=0;html=1;exitX=1;exitY=0.5;exitDx=0;exitDy=0;exitPerimeter=0;entryX=0;entryY=0.75;entryDx=0;entryDy=0;entryPerimeter=0;strokeWidth=3;endArrow=none;endFill=0;" parent="gzdv8FFXtKBTtcGOgYej-1" source="gzdv8FFXtKBTtcGOgYej-3" target="gzdv8FFXtKBTtcGOgYej-15" edge="1">
<mxGeometry relative="1" as="geometry">
<Array as="points">
<mxPoint x="242" y="150"/>
<mxPoint x="242" y="46"/>
</Array>
</mxGeometry>
</mxCell>
<mxCell id="gzdv8FFXtKBTtcGOgYej-17" value="Cin" style="text;html=1;strokeColor=none;fillColor=none;align=center;verticalAlign=middle;whiteSpace=wrap;rounded=0;fontStyle=1;fontSize=25;" parent="gzdv8FFXtKBTtcGOgYej-1" vertex="1">
<mxGeometry width="60" height="30" as="geometry"/>
</mxCell>
<mxCell id="gzdv8FFXtKBTtcGOgYej-18" value="A" style="text;html=1;strokeColor=none;fillColor=none;align=center;verticalAlign=middle;whiteSpace=wrap;rounded=0;fontStyle=1;fontSize=25;" parent="gzdv8FFXtKBTtcGOgYej-1" vertex="1">
<mxGeometry y="120" width="60" height="30" as="geometry"/>
</mxCell>
<mxCell id="gzdv8FFXtKBTtcGOgYej-19" value="" style="edgeStyle=orthogonalEdgeStyle;rounded=0;html=1;exitX=0;exitY=0.75;exitDx=0;exitDy=0;exitPerimeter=0;strokeWidth=3;endArrow=none;endFill=0;" parent="gzdv8FFXtKBTtcGOgYej-1" source="gzdv8FFXtKBTtcGOgYej-3" target="gzdv8FFXtKBTtcGOgYej-20" edge="1">
<mxGeometry relative="1" as="geometry">
<mxPoint x="52" y="165.1034482758621" as="targetPoint"/>
<mxPoint x="122" y="165" as="sourcePoint"/>
</mxGeometry>
</mxCell>
<mxCell id="gzdv8FFXtKBTtcGOgYej-20" value="&lt;span style=&quot;&quot;&gt;B&lt;/span&gt;" style="text;html=1;strokeColor=none;fillColor=none;align=center;verticalAlign=middle;whiteSpace=wrap;rounded=0;fontStyle=1;fontSize=25;" parent="gzdv8FFXtKBTtcGOgYej-1" vertex="1">
<mxGeometry y="150" width="60" height="30" as="geometry"/>
</mxCell>
<mxCell id="gzdv8FFXtKBTtcGOgYej-21" value="S" style="text;html=1;strokeColor=none;fillColor=none;align=center;verticalAlign=middle;whiteSpace=wrap;rounded=0;fontStyle=1;fontSize=25;" parent="gzdv8FFXtKBTtcGOgYej-1" vertex="1">
<mxGeometry x="529" y="15" width="60" height="30" as="geometry"/>
</mxCell>
<mxCell id="gzdv8FFXtKBTtcGOgYej-22" value="Cout" style="text;html=1;strokeColor=none;fillColor=none;align=center;verticalAlign=middle;whiteSpace=wrap;rounded=0;fontStyle=1;fontSize=25;" parent="gzdv8FFXtKBTtcGOgYej-1" vertex="1">
<mxGeometry x="549" y="76" width="60" height="30" as="geometry"/>
</mxCell>
<mxCell id="gzdv8FFXtKBTtcGOgYej-23" value="" style="group" parent="1" vertex="1" connectable="0">
<mxGeometry x="100" y="80" width="100" height="183" as="geometry"/>
</mxCell>
<mxCell id="wTAwAFIw4sOWHSdyWEut-2" style="edgeStyle=none;html=1;exitX=0.25;exitY=0;exitDx=0;exitDy=0;fontColor=#000000;startArrow=block;startFill=1;endArrow=none;endFill=0;strokeColor=#000000;rounded=0;strokeWidth=2;" parent="gzdv8FFXtKBTtcGOgYej-23" source="wTAwAFIw4sOWHSdyWEut-1" edge="1">
<mxGeometry relative="1" as="geometry">
<mxPoint x="30" y="22" as="targetPoint"/>
</mxGeometry>
</mxCell>
<mxCell id="wTAwAFIw4sOWHSdyWEut-3" style="edgeStyle=none;html=1;exitX=0.5;exitY=0;exitDx=0;exitDy=0;fontColor=#000000;endArrow=none;rounded=0;strokeColor=#000000;startArrow=block;startFill=1;endFill=0;strokeWidth=2;" parent="gzdv8FFXtKBTtcGOgYej-23" source="wTAwAFIw4sOWHSdyWEut-1" edge="1">
<mxGeometry relative="1" as="geometry">
<mxPoint x="50" y="22" as="targetPoint"/>
</mxGeometry>
</mxCell>
<mxCell id="wTAwAFIw4sOWHSdyWEut-4" style="edgeStyle=none;html=1;exitX=0.75;exitY=0;exitDx=0;exitDy=0;fontColor=#000000;endArrow=none;rounded=0;strokeColor=#000000;startArrow=block;startFill=1;endFill=0;strokeWidth=2;" parent="gzdv8FFXtKBTtcGOgYej-23" source="wTAwAFIw4sOWHSdyWEut-1" edge="1">
<mxGeometry relative="1" as="geometry">
<mxPoint x="70" y="22" as="targetPoint"/>
</mxGeometry>
</mxCell>
<mxCell id="wTAwAFIw4sOWHSdyWEut-5" style="edgeStyle=none;rounded=0;html=1;exitX=0.25;exitY=1;exitDx=0;exitDy=0;strokeColor=#000000;fontColor=#000000;startArrow=none;startFill=0;endArrow=block;endFill=1;strokeWidth=2;" parent="gzdv8FFXtKBTtcGOgYej-23" source="wTAwAFIw4sOWHSdyWEut-1" edge="1">
<mxGeometry relative="1" as="geometry">
<mxPoint x="30" y="162" as="targetPoint"/>
</mxGeometry>
</mxCell>
<mxCell id="wTAwAFIw4sOWHSdyWEut-6" style="edgeStyle=none;rounded=0;html=1;exitX=0.75;exitY=1;exitDx=0;exitDy=0;strokeColor=#000000;fontColor=#000000;startArrow=none;startFill=0;endArrow=block;endFill=1;strokeWidth=2;" parent="gzdv8FFXtKBTtcGOgYej-23" source="wTAwAFIw4sOWHSdyWEut-1" edge="1">
<mxGeometry relative="1" as="geometry">
<mxPoint x="70" y="162" as="targetPoint"/>
</mxGeometry>
</mxCell>
<mxCell id="wTAwAFIw4sOWHSdyWEut-1" value="FA" style="whiteSpace=wrap;html=1;aspect=fixed;fillColor=none;strokeColor=#000000;strokeWidth=3;fontColor=#000000;fontStyle=1" parent="gzdv8FFXtKBTtcGOgYej-23" vertex="1">
<mxGeometry x="10" y="52" width="80" height="80" as="geometry"/>
</mxCell>
<mxCell id="wTAwAFIw4sOWHSdyWEut-7" value="A" style="text;html=1;strokeColor=none;fillColor=none;align=center;verticalAlign=middle;whiteSpace=wrap;rounded=0;labelBackgroundColor=none;strokeWidth=3;fontColor=#000000;fontStyle=1" parent="gzdv8FFXtKBTtcGOgYej-23" vertex="1">
<mxGeometry width="60" height="30" as="geometry"/>
</mxCell>
<mxCell id="wTAwAFIw4sOWHSdyWEut-8" value="B" style="text;html=1;strokeColor=none;fillColor=none;align=center;verticalAlign=middle;whiteSpace=wrap;rounded=0;labelBackgroundColor=none;strokeWidth=3;fontColor=#000000;fontStyle=1" parent="gzdv8FFXtKBTtcGOgYej-23" vertex="1">
<mxGeometry x="20" width="60" height="30" as="geometry"/>
</mxCell>
<mxCell id="wTAwAFIw4sOWHSdyWEut-9" value="Cin" style="text;html=1;strokeColor=none;fillColor=none;align=center;verticalAlign=middle;whiteSpace=wrap;rounded=0;labelBackgroundColor=none;strokeWidth=3;fontColor=#000000;fontStyle=1" parent="gzdv8FFXtKBTtcGOgYej-23" vertex="1">
<mxGeometry x="40" width="60" height="30" as="geometry"/>
</mxCell>
<mxCell id="wTAwAFIw4sOWHSdyWEut-10" value="S" style="text;html=1;strokeColor=none;fillColor=none;align=center;verticalAlign=middle;whiteSpace=wrap;rounded=0;labelBackgroundColor=none;strokeWidth=3;fontColor=#000000;fontStyle=1" parent="gzdv8FFXtKBTtcGOgYej-23" vertex="1">
<mxGeometry y="153" width="60" height="30" as="geometry"/>
</mxCell>
<mxCell id="wTAwAFIw4sOWHSdyWEut-11" value="Cout" style="text;html=1;strokeColor=none;fillColor=none;align=center;verticalAlign=middle;whiteSpace=wrap;rounded=0;labelBackgroundColor=none;strokeWidth=3;fontColor=#000000;fontStyle=1" parent="gzdv8FFXtKBTtcGOgYej-23" vertex="1">
<mxGeometry x="40" y="153" width="60" height="30" as="geometry"/>
</mxCell>
</root>
</mxGraphModel>
</diagram>
<diagram id="E8JmcAeOklZgZ2l8eJsL" name="多路数据选择器">
<mxGraphModel dx="696" dy="571" grid="1" gridSize="10" guides="1" tooltips="1" connect="1" arrows="1" fold="1" page="1" pageScale="1" pageWidth="1169" pageHeight="827" math="0" shadow="0">
<root>
<mxCell id="0"/>
<mxCell id="1" parent="0"/>
<mxCell id="uB0_w7AT7cy0_k-z_mVM-15" value="" style="group" parent="1" vertex="1" connectable="0">
<mxGeometry x="47" y="90" width="326" height="195" as="geometry"/>
</mxCell>
<mxCell id="uB0_w7AT7cy0_k-z_mVM-1" value="MUX" style="shape=trapezoid;perimeter=trapezoidPerimeter;whiteSpace=wrap;html=1;fixedSize=1;rotation=90;strokeWidth=3;fontStyle=1;fontSize=22;" parent="uB0_w7AT7cy0_k-z_mVM-15" vertex="1">
<mxGeometry x="103" y="30" width="120" height="60" as="geometry"/>
</mxCell>
<mxCell id="uB0_w7AT7cy0_k-z_mVM-2" value="" style="endArrow=blockThin;html=1;rounded=0;strokeColor=#000000;fontFamily=Helvetica;fontSize=15;fontColor=#000000;endFill=1;strokeWidth=3;" parent="uB0_w7AT7cy0_k-z_mVM-15" edge="1">
<mxGeometry width="50" height="50" relative="1" as="geometry">
<mxPoint x="63" y="16" as="sourcePoint"/>
<mxPoint x="133" y="16" as="targetPoint"/>
</mxGeometry>
</mxCell>
<mxCell id="uB0_w7AT7cy0_k-z_mVM-3" value="" style="endArrow=blockThin;html=1;rounded=0;strokeColor=#000000;fontFamily=Helvetica;fontSize=15;fontColor=#000000;endFill=1;strokeWidth=3;" parent="uB0_w7AT7cy0_k-z_mVM-15" edge="1">
<mxGeometry width="50" height="50" relative="1" as="geometry">
<mxPoint x="63" y="45" as="sourcePoint"/>
<mxPoint x="132.99999999999994" y="45" as="targetPoint"/>
</mxGeometry>
</mxCell>
<mxCell id="uB0_w7AT7cy0_k-z_mVM-4" value="" style="endArrow=blockThin;html=1;rounded=0;strokeColor=#000000;fontFamily=Helvetica;fontSize=15;fontColor=#000000;endFill=1;strokeWidth=3;" parent="uB0_w7AT7cy0_k-z_mVM-15" edge="1">
<mxGeometry width="50" height="50" relative="1" as="geometry">
<mxPoint x="63" y="72" as="sourcePoint"/>
<mxPoint x="132.99999999999994" y="72" as="targetPoint"/>
</mxGeometry>
</mxCell>
<mxCell id="uB0_w7AT7cy0_k-z_mVM-5" value="" style="endArrow=blockThin;html=1;rounded=0;strokeColor=#000000;fontFamily=Helvetica;fontSize=15;fontColor=#000000;endFill=1;strokeWidth=3;" parent="uB0_w7AT7cy0_k-z_mVM-15" edge="1">
<mxGeometry width="50" height="50" relative="1" as="geometry">
<mxPoint x="63" y="100" as="sourcePoint"/>
<mxPoint x="132.99999999999994" y="100" as="targetPoint"/>
</mxGeometry>
</mxCell>
<mxCell id="uB0_w7AT7cy0_k-z_mVM-7" value="" style="endArrow=blockThin;html=1;rounded=0;strokeColor=#000000;fontFamily=Helvetica;fontSize=15;fontColor=#000000;endFill=1;strokeWidth=3;" parent="uB0_w7AT7cy0_k-z_mVM-15" edge="1">
<mxGeometry width="50" height="50" relative="1" as="geometry">
<mxPoint x="193" y="59.81" as="sourcePoint"/>
<mxPoint x="262.99999999999994" y="59.81" as="targetPoint"/>
</mxGeometry>
</mxCell>
<mxCell id="uB0_w7AT7cy0_k-z_mVM-8" value="" style="endArrow=blockThin;html=1;rounded=0;strokeColor=#000000;fontFamily=Helvetica;fontSize=15;fontColor=#000000;endFill=1;strokeWidth=3;entryX=1;entryY=0.5;entryDx=0;entryDy=0;" parent="uB0_w7AT7cy0_k-z_mVM-15" target="uB0_w7AT7cy0_k-z_mVM-1" edge="1">
<mxGeometry width="50" height="50" relative="1" as="geometry">
<mxPoint x="163" y="170" as="sourcePoint"/>
<mxPoint x="197.99999999999994" y="150" as="targetPoint"/>
</mxGeometry>
</mxCell>
<mxCell id="uB0_w7AT7cy0_k-z_mVM-9" value="[7:0] A" style="text;html=1;align=center;verticalAlign=middle;resizable=0;points=[];autosize=1;strokeColor=none;fillColor=none;fontSize=15;fontStyle=1" parent="uB0_w7AT7cy0_k-z_mVM-15" vertex="1">
<mxGeometry width="70" height="30" as="geometry"/>
</mxCell>
<mxCell id="uB0_w7AT7cy0_k-z_mVM-10" value="[7:0] B" style="text;html=1;align=center;verticalAlign=middle;resizable=0;points=[];autosize=1;strokeColor=none;fillColor=none;fontSize=15;fontStyle=1" parent="uB0_w7AT7cy0_k-z_mVM-15" vertex="1">
<mxGeometry y="30" width="70" height="30" as="geometry"/>
</mxCell>
<mxCell id="uB0_w7AT7cy0_k-z_mVM-11" value="[7:0] C" style="text;html=1;align=center;verticalAlign=middle;resizable=0;points=[];autosize=1;strokeColor=none;fillColor=none;fontSize=15;fontStyle=1" parent="uB0_w7AT7cy0_k-z_mVM-15" vertex="1">
<mxGeometry y="57" width="70" height="30" as="geometry"/>
</mxCell>
<mxCell id="uB0_w7AT7cy0_k-z_mVM-12" value="[7:0] D" style="text;html=1;align=center;verticalAlign=middle;resizable=0;points=[];autosize=1;strokeColor=none;fillColor=none;fontSize=15;fontStyle=1" parent="uB0_w7AT7cy0_k-z_mVM-15" vertex="1">
<mxGeometry y="84" width="70" height="30" as="geometry"/>
</mxCell>
<mxCell id="uB0_w7AT7cy0_k-z_mVM-13" value="[7:0] Y" style="text;html=1;align=center;verticalAlign=middle;resizable=0;points=[];autosize=1;strokeColor=none;fillColor=none;fontSize=15;fontStyle=1" parent="uB0_w7AT7cy0_k-z_mVM-15" vertex="1">
<mxGeometry x="256" y="44" width="70" height="30" as="geometry"/>
</mxCell>
<mxCell id="uB0_w7AT7cy0_k-z_mVM-14" value="[1:0] S" style="text;html=1;align=center;verticalAlign=middle;resizable=0;points=[];autosize=1;strokeColor=none;fillColor=none;fontSize=15;fontStyle=1" parent="uB0_w7AT7cy0_k-z_mVM-15" vertex="1">
<mxGeometry x="128" y="165" width="70" height="30" as="geometry"/>
</mxCell>
</root>
</mxGraphModel>
</diagram>
<diagram id="AdvlFsg3ZpSJXzzAPVCX" name="译码器">
<mxGraphModel dx="480" dy="394" grid="1" gridSize="10" guides="1" tooltips="1" connect="1" arrows="1" fold="1" page="1" pageScale="1" pageWidth="1169" pageHeight="827" math="1" shadow="0">
<root>
<mxCell id="0"/>
<mxCell id="1" parent="0"/>
<mxCell id="8LwFoKWnl6urZ68ISw2w-2" style="edgeStyle=none;html=1;exitX=0;exitY=0.25;exitDx=0;exitDy=0;fontSize=18;strokeWidth=3;rounded=0;endArrow=none;endFill=0;" edge="1" parent="1" source="8LwFoKWnl6urZ68ISw2w-1">
<mxGeometry relative="1" as="geometry">
<mxPoint x="210" y="198" as="targetPoint"/>
</mxGeometry>
</mxCell>
<mxCell id="8LwFoKWnl6urZ68ISw2w-3" style="edgeStyle=none;rounded=0;html=1;exitX=0;exitY=0.5;exitDx=0;exitDy=0;strokeWidth=3;fontSize=18;endArrow=none;endFill=0;" edge="1" parent="1" source="8LwFoKWnl6urZ68ISw2w-1">
<mxGeometry relative="1" as="geometry">
<mxPoint x="210" y="239.8571428571429" as="targetPoint"/>
</mxGeometry>
</mxCell>
<mxCell id="8LwFoKWnl6urZ68ISw2w-4" style="edgeStyle=none;rounded=0;html=1;exitX=0;exitY=0.75;exitDx=0;exitDy=0;strokeWidth=3;fontSize=18;endArrow=none;endFill=0;" edge="1" parent="1" source="8LwFoKWnl6urZ68ISw2w-1">
<mxGeometry relative="1" as="geometry">
<mxPoint x="210" y="282.71428571428567" as="targetPoint"/>
</mxGeometry>
</mxCell>
<mxCell id="8LwFoKWnl6urZ68ISw2w-1" value="Decoder" style="rounded=0;whiteSpace=wrap;html=1;strokeWidth=3;fontStyle=1;fontSize=18;" vertex="1" parent="1">
<mxGeometry x="300" y="155" width="120" height="170" as="geometry"/>
</mxCell>
<mxCell id="8LwFoKWnl6urZ68ISw2w-10" style="edgeStyle=none;html=1;exitX=0;exitY=0.25;exitDx=0;exitDy=0;fontSize=18;strokeWidth=3;rounded=0;endArrow=none;endFill=0;" edge="1" parent="1">
<mxGeometry relative="1" as="geometry">
<mxPoint x="420" y="230.5" as="targetPoint"/>
<mxPoint x="510" y="230" as="sourcePoint"/>
</mxGeometry>
</mxCell>
<mxCell id="8LwFoKWnl6urZ68ISw2w-11" style="edgeStyle=none;html=1;exitX=0;exitY=0.25;exitDx=0;exitDy=0;fontSize=18;strokeWidth=3;rounded=0;endArrow=none;endFill=0;" edge="1" parent="1">
<mxGeometry relative="1" as="geometry">
<mxPoint x="420" y="250.5" as="targetPoint"/>
<mxPoint x="510" y="250" as="sourcePoint"/>
</mxGeometry>
</mxCell>
<mxCell id="8LwFoKWnl6urZ68ISw2w-12" style="edgeStyle=none;html=1;exitX=0;exitY=0.25;exitDx=0;exitDy=0;fontSize=18;strokeWidth=3;rounded=0;endArrow=none;endFill=0;" edge="1" parent="1">
<mxGeometry relative="1" as="geometry">
<mxPoint x="420" y="210.5" as="targetPoint"/>
<mxPoint x="510" y="210" as="sourcePoint"/>
</mxGeometry>
</mxCell>
<mxCell id="8LwFoKWnl6urZ68ISw2w-13" style="edgeStyle=none;html=1;exitX=0;exitY=0.25;exitDx=0;exitDy=0;fontSize=18;strokeWidth=3;rounded=0;endArrow=none;endFill=0;" edge="1" parent="1">
<mxGeometry relative="1" as="geometry">
<mxPoint x="420" y="270.5" as="targetPoint"/>
<mxPoint x="510" y="270" as="sourcePoint"/>
</mxGeometry>
</mxCell>
<mxCell id="8LwFoKWnl6urZ68ISw2w-14" style="edgeStyle=none;html=1;exitX=0;exitY=0.25;exitDx=0;exitDy=0;fontSize=18;strokeWidth=3;rounded=0;endArrow=none;endFill=0;" edge="1" parent="1">
<mxGeometry relative="1" as="geometry">
<mxPoint x="420" y="190.5" as="targetPoint"/>
<mxPoint x="510" y="190" as="sourcePoint"/>
</mxGeometry>
</mxCell>
<mxCell id="8LwFoKWnl6urZ68ISw2w-15" style="edgeStyle=none;html=1;exitX=0;exitY=0.25;exitDx=0;exitDy=0;fontSize=18;strokeWidth=3;rounded=0;endArrow=none;endFill=0;" edge="1" parent="1">
<mxGeometry relative="1" as="geometry">
<mxPoint x="420" y="290.5" as="targetPoint"/>
<mxPoint x="510" y="290" as="sourcePoint"/>
</mxGeometry>
</mxCell>
<mxCell id="8LwFoKWnl6urZ68ISw2w-16" style="edgeStyle=none;html=1;exitX=0;exitY=0.25;exitDx=0;exitDy=0;fontSize=18;strokeWidth=3;rounded=0;endArrow=none;endFill=0;" edge="1" parent="1">
<mxGeometry relative="1" as="geometry">
<mxPoint x="420" y="310.5" as="targetPoint"/>
<mxPoint x="510" y="310" as="sourcePoint"/>
</mxGeometry>
</mxCell>
<mxCell id="8LwFoKWnl6urZ68ISw2w-17" style="edgeStyle=none;html=1;exitX=0;exitY=0.25;exitDx=0;exitDy=0;fontSize=18;strokeWidth=3;rounded=0;endArrow=none;endFill=0;" edge="1" parent="1">
<mxGeometry relative="1" as="geometry">
<mxPoint x="420" y="170.5" as="targetPoint"/>
<mxPoint x="510" y="170" as="sourcePoint"/>
</mxGeometry>
</mxCell>
<mxCell id="8LwFoKWnl6urZ68ISw2w-18" value="$$A$$" style="text;html=1;align=center;verticalAlign=middle;resizable=0;points=[];autosize=1;strokeColor=none;fillColor=none;fontSize=18;fontStyle=1" vertex="1" parent="1">
<mxGeometry x="152" y="177" width="80" height="40" as="geometry"/>
</mxCell>
<mxCell id="8LwFoKWnl6urZ68ISw2w-19" value="$$B$$" style="text;html=1;align=center;verticalAlign=middle;resizable=0;points=[];autosize=1;strokeColor=none;fillColor=none;fontSize=18;fontStyle=1" vertex="1" parent="1">
<mxGeometry x="152" y="219" width="80" height="40" as="geometry"/>
</mxCell>
<mxCell id="8LwFoKWnl6urZ68ISw2w-20" value="$$C$$" style="text;html=1;align=center;verticalAlign=middle;resizable=0;points=[];autosize=1;strokeColor=none;fillColor=none;fontSize=18;fontStyle=1" vertex="1" parent="1">
<mxGeometry x="152" y="263" width="80" height="40" as="geometry"/>
</mxCell>
<mxCell id="8LwFoKWnl6urZ68ISw2w-21" value="$$Y_0$$" style="text;html=1;align=center;verticalAlign=middle;resizable=0;points=[];autosize=1;strokeColor=none;fillColor=none;fontSize=18;fontStyle=1" vertex="1" parent="1">
<mxGeometry x="485" y="150" width="100" height="40" as="geometry"/>
</mxCell>
<mxCell id="8LwFoKWnl6urZ68ISw2w-22" value="$$Y_1$$" style="text;html=1;align=center;verticalAlign=middle;resizable=0;points=[];autosize=1;strokeColor=none;fillColor=none;fontSize=18;fontStyle=1" vertex="1" parent="1">
<mxGeometry x="485" y="170" width="100" height="40" as="geometry"/>
</mxCell>
<mxCell id="8LwFoKWnl6urZ68ISw2w-23" value="$$Y_2$$" style="text;html=1;align=center;verticalAlign=middle;resizable=0;points=[];autosize=1;strokeColor=none;fillColor=none;fontSize=18;fontStyle=1" vertex="1" parent="1">
<mxGeometry x="485" y="190" width="100" height="40" as="geometry"/>
</mxCell>
<mxCell id="8LwFoKWnl6urZ68ISw2w-24" value="$$Y_3$$" style="text;html=1;align=center;verticalAlign=middle;resizable=0;points=[];autosize=1;strokeColor=none;fillColor=none;fontSize=18;fontStyle=1" vertex="1" parent="1">
<mxGeometry x="485" y="210" width="100" height="40" as="geometry"/>
</mxCell>
<mxCell id="8LwFoKWnl6urZ68ISw2w-25" value="$$Y_4$$" style="text;html=1;align=center;verticalAlign=middle;resizable=0;points=[];autosize=1;strokeColor=none;fillColor=none;fontSize=18;fontStyle=1" vertex="1" parent="1">
<mxGeometry x="485" y="230" width="100" height="40" as="geometry"/>
</mxCell>
<mxCell id="8LwFoKWnl6urZ68ISw2w-26" value="$$Y_5$$" style="text;html=1;align=center;verticalAlign=middle;resizable=0;points=[];autosize=1;strokeColor=none;fillColor=none;fontSize=18;fontStyle=1" vertex="1" parent="1">
<mxGeometry x="485" y="250" width="100" height="40" as="geometry"/>
</mxCell>
<mxCell id="8LwFoKWnl6urZ68ISw2w-27" value="$$Y_6$$" style="text;html=1;align=center;verticalAlign=middle;resizable=0;points=[];autosize=1;strokeColor=none;fillColor=none;fontSize=18;fontStyle=1" vertex="1" parent="1">
<mxGeometry x="485" y="270" width="100" height="40" as="geometry"/>
</mxCell>
<mxCell id="8LwFoKWnl6urZ68ISw2w-28" value="$$Y_7$$" style="text;html=1;align=center;verticalAlign=middle;resizable=0;points=[];autosize=1;strokeColor=none;fillColor=none;fontSize=18;fontStyle=1" vertex="1" parent="1">
<mxGeometry x="485" y="290" width="100" height="40" as="geometry"/>
</mxCell>
</root>
</mxGraphModel>
</diagram>
<diagram id="X1Z5Mt0qpq97yQyyeKMR" name="加减法器">
<mxGraphModel dx="696" dy="571" grid="1" gridSize="10" guides="1" tooltips="1" connect="1" arrows="1" fold="1" page="1" pageScale="1" pageWidth="1169" pageHeight="827" math="1" shadow="0">
<root>
<mxCell id="0"/>
<mxCell id="1" parent="0"/>
<mxCell id="U6ciwknIUaB1TWmNj2xK-3" style="edgeStyle=orthogonalEdgeStyle;html=1;exitX=0;exitY=0.25;exitDx=0;exitDy=0;fontColor=default;endArrow=block;endFill=1;strokeWidth=3;rounded=0;" parent="1" source="U6ciwknIUaB1TWmNj2xK-2" edge="1">
<mxGeometry relative="1" as="geometry">
<mxPoint x="220" y="298" as="targetPoint"/>
</mxGeometry>
</mxCell>
<mxCell id="U6ciwknIUaB1TWmNj2xK-4" style="edgeStyle=orthogonalEdgeStyle;rounded=0;html=1;exitX=0;exitY=0.5;exitDx=0;exitDy=0;strokeWidth=3;fontColor=default;endArrow=block;endFill=1;" parent="1" source="U6ciwknIUaB1TWmNj2xK-2" edge="1">
<mxGeometry relative="1" as="geometry">
<mxPoint x="220" y="335.1428571428571" as="targetPoint"/>
</mxGeometry>
</mxCell>
<mxCell id="U6ciwknIUaB1TWmNj2xK-5" style="edgeStyle=orthogonalEdgeStyle;rounded=0;html=1;exitX=0;exitY=0.75;exitDx=0;exitDy=0;strokeWidth=3;fontColor=default;endArrow=block;endFill=1;" parent="1" source="U6ciwknIUaB1TWmNj2xK-2" edge="1">
<mxGeometry relative="1" as="geometry">
<mxPoint x="220" y="372.28571428571433" as="targetPoint"/>
</mxGeometry>
</mxCell>
<mxCell id="U6ciwknIUaB1TWmNj2xK-6" style="edgeStyle=orthogonalEdgeStyle;rounded=0;html=1;exitX=1;exitY=0.25;exitDx=0;exitDy=0;strokeWidth=3;fontColor=default;endArrow=none;endFill=0;startArrow=block;startFill=1;" parent="1" source="U6ciwknIUaB1TWmNj2xK-2" edge="1">
<mxGeometry relative="1" as="geometry">
<mxPoint x="570" y="297.42857142857144" as="targetPoint"/>
</mxGeometry>
</mxCell>
<mxCell id="U6ciwknIUaB1TWmNj2xK-7" style="edgeStyle=orthogonalEdgeStyle;rounded=0;html=1;exitX=1;exitY=0.75;exitDx=0;exitDy=0;strokeWidth=3;fontColor=default;endArrow=none;endFill=0;startArrow=block;startFill=1;" parent="1" source="U6ciwknIUaB1TWmNj2xK-2" edge="1">
<mxGeometry relative="1" as="geometry">
<mxPoint x="570" y="372.28571428571433" as="targetPoint"/>
</mxGeometry>
</mxCell>
<mxCell id="U6ciwknIUaB1TWmNj2xK-2" value="&lt;span style=&quot;font-family: Arial, Helvetica, sans-serif; font-size: 14px; text-align: left; background-color: rgb(255, 255, 255);&quot;&gt;Adder&lt;/span&gt;&lt;span style=&quot;font-family: Arial, Helvetica, sans-serif; font-size: 14px; text-align: left; background-color: rgb(255, 255, 255);&quot;&gt;/Subtracter&lt;/span&gt;" style="whiteSpace=wrap;html=1;aspect=fixed;fontStyle=1;fontColor=default;strokeWidth=4;" parent="1" vertex="1">
<mxGeometry x="320" y="260" width="150" height="150" as="geometry"/>
</mxCell>
<mxCell id="U6ciwknIUaB1TWmNj2xK-9" value="" style="shape=flexArrow;endArrow=classic;html=1;rounded=0;strokeWidth=3;fontColor=default;exitX=0.5;exitY=0;exitDx=0;exitDy=0;" parent="1" edge="1">
<mxGeometry width="50" height="50" relative="1" as="geometry">
<mxPoint x="395" y="262" as="sourcePoint"/>
<mxPoint x="395" y="182" as="targetPoint"/>
</mxGeometry>
</mxCell>
<mxCell id="U6ciwknIUaB1TWmNj2xK-10" value="" style="shape=flexArrow;endArrow=classic;html=1;rounded=0;strokeWidth=3;fontColor=default;exitX=0.5;exitY=0;exitDx=0;exitDy=0;" parent="1" edge="1">
<mxGeometry width="50" height="50" relative="1" as="geometry">
<mxPoint x="370" y="490" as="sourcePoint"/>
<mxPoint x="370" y="410" as="targetPoint"/>
</mxGeometry>
</mxCell>
<mxCell id="U6ciwknIUaB1TWmNj2xK-11" value="" style="shape=flexArrow;endArrow=classic;html=1;rounded=0;strokeWidth=3;fontColor=default;exitX=0.5;exitY=0;exitDx=0;exitDy=0;" parent="1" edge="1">
<mxGeometry width="50" height="50" relative="1" as="geometry">
<mxPoint x="430" y="490" as="sourcePoint"/>
<mxPoint x="430" y="410" as="targetPoint"/>
</mxGeometry>
</mxCell>
<mxCell id="U6ciwknIUaB1TWmNj2xK-13" value="$$Cout$$" style="text;html=1;align=center;verticalAlign=middle;resizable=0;points=[];autosize=1;strokeColor=none;fillColor=none;fontColor=default;strokeWidth=1;fontStyle=1;fontSize=16;" parent="1" vertex="1">
<mxGeometry x="146" y="282" width="100" height="30" as="geometry"/>
</mxCell>
<mxCell id="U6ciwknIUaB1TWmNj2xK-15" value="$$Cin$$" style="text;html=1;align=center;verticalAlign=middle;resizable=0;points=[];autosize=1;strokeColor=none;fillColor=none;fontColor=default;strokeWidth=1;fontStyle=1;fontSize=16;" parent="1" vertex="1">
<mxGeometry x="548" y="280" width="80" height="30" as="geometry"/>
</mxCell>
<mxCell id="U6ciwknIUaB1TWmNj2xK-16" value="$$ZF$$" style="text;html=1;align=center;verticalAlign=middle;resizable=0;points=[];autosize=1;strokeColor=none;fillColor=none;fontColor=default;strokeWidth=1;fontStyle=1;fontSize=16;" parent="1" vertex="1">
<mxGeometry x="156" y="320" width="80" height="30" as="geometry"/>
</mxCell>
<mxCell id="U6ciwknIUaB1TWmNj2xK-17" value="$$CF$$" style="text;html=1;align=center;verticalAlign=middle;resizable=0;points=[];autosize=1;strokeColor=none;fillColor=none;fontColor=default;strokeWidth=1;fontStyle=1;fontSize=16;" parent="1" vertex="1">
<mxGeometry x="155" y="360" width="80" height="30" as="geometry"/>
</mxCell>
<mxCell id="U6ciwknIUaB1TWmNj2xK-19" value="$$\overline{Add}/Sub$$" style="text;html=1;align=center;verticalAlign=middle;resizable=0;points=[];autosize=1;strokeColor=none;fillColor=none;fontColor=default;strokeWidth=1;fontStyle=1;fontSize=16;" parent="1" vertex="1">
<mxGeometry x="512" y="357" width="200" height="30" as="geometry"/>
</mxCell>
<mxCell id="U6ciwknIUaB1TWmNj2xK-22" value="$$\left[3:0\right]\,A$$" style="text;html=1;align=center;verticalAlign=middle;resizable=0;points=[];autosize=1;strokeColor=none;fillColor=none;fontColor=default;strokeWidth=1;fontStyle=1;fontSize=16;" parent="1" vertex="1">
<mxGeometry x="270" y="492" width="180" height="30" as="geometry"/>
</mxCell>
<mxCell id="U6ciwknIUaB1TWmNj2xK-23" value="$$\left[3:0\right]\,B$$" style="text;html=1;align=center;verticalAlign=middle;resizable=0;points=[];autosize=1;strokeColor=none;fillColor=none;fontColor=default;strokeWidth=1;fontStyle=1;fontSize=16;" parent="1" vertex="1">
<mxGeometry x="340" y="492" width="180" height="30" as="geometry"/>
</mxCell>
<mxCell id="U6ciwknIUaB1TWmNj2xK-24" value="$$\left[3:0\right]\,Y$$" style="text;html=1;align=center;verticalAlign=middle;resizable=0;points=[];autosize=1;strokeColor=none;fillColor=none;fontColor=default;strokeWidth=1;fontStyle=1;fontSize=16;" parent="1" vertex="1">
<mxGeometry x="300" y="150" width="180" height="30" as="geometry"/>
</mxCell>
</root>
</mxGraphModel>
</diagram>
</mxfile>

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 11 KiB

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 14 KiB

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 24 KiB

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 16 KiB

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 11 KiB

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 14 KiB

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 24 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 82 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 56 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 60 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 18 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 67 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 23 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 29 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 53 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 51 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 16 KiB

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 12 KiB

View File

@ -1,875 +0,0 @@
# 认识 Verilog
> 数字电路学习资料
>
> - [数字电路与计算机体系结构 open in new window](https://pages.hmc.edu/harris/ddca/ddcarv.html) 1-5 章节
> - [Verilog 在线学习网站 open in new window](https://hdlbits.01xz.net/wiki/Main_Page),推荐边看书边练手
> - [中科大的 Verilog OJ 平台 open in new window](https://verilogoj.ustc.edu.cn/oj/)(需要注册并登录),推荐边看书边练手
> - 《CPU 设计实战- 汪文祥 & 邢金璋》第 3 章节
## 一、什么是 Verilog
[Verilog](https://zh.wikipedia.org/wiki/Verilog#%E5%8F%91%E5%B1%95%E5%8E%86%E5%8F%B2) 是一种**硬件描述语言**,用于描述和设计数字电路。它是一种结构化的编程语言,用于描述电子系统的行为和结构,以实现硬件设计和验证。
Verilog 是一种并发执行的语言可以描述并行运行的硬件电路。Verilog 中的模块可以以并行的方式执行,模块内的语句可以同时进行计算。相比 C 语言等非硬件描述的编程语言是一种顺序执行的语言,语句按照顺序逐步执行。因此,同学们在编写 Verilog 时,需要将原先 C 语言的一些思想抛弃,投入并行的怀抱。
## 二、面向硬件电路的设计思维方式
1. **并行和并发思维**: 硬件电路是并行执行的,多个电路元件可以同时工作。因此,在硬件设计中,需要考虑如何利用并行性和并发性,以实现高效的电路功能。
2. **抽象和模块化思维**: 硬件设计通常涉及复杂的电路结构和功能,因此,将电路设计分解为可管理的模块是很重要的。通过抽象和模块化思维,可以将复杂的电路问题分解为更小的部分,并逐步解决每个模块的设计和验证。
3. **时序和同步思维**: 时序是硬件设计中至关重要的概念。在考虑电路的功能时,需要仔细考虑元件之间的时序关系,包括时钟信号、触发器和时序逻辑等。同步思维强调设计中的时钟域和同步约束,确保电路的正确时序行为。
4. **优化和资源利用思维**: 硬件资源是有限的,因此,在设计电路时需要考虑如何优化资源的使用。这包括选择合适的元件、减少功耗、提高性能和资源共享等方面的思考。优化和资源利用思维可以帮助设计出更高效、更紧凑的电路。
5. **可靠性和容错思维**: 硬件电路通常要求高度可靠,能够在各种条件下正常工作。因此,设计时需要考虑如何处理异常情况、提供容错机制和错误检测、纠正等。可靠性和容错思维可以帮助设计出更稳定和可靠的电路。
6. **测试和验证思维**: 在硬件设计中,测试和验证是关键步骤,用于验证电路的正确性和性能。测试和验证思维强调设计过程中的测试计划、测试向量生成、仿真和验证技术等。通过充分考虑测试和验证,可以提高电路设计的质量和可靠性。
在本课程中,同学需要掌握的面向硬件电路的设计思维方式的核心实际上就是“**数据通路Datapath+控制逻辑Control Logic**”。**大家一定要先将电路设计想清楚,再开始写代码。我们建议采取“自顶向下、模块划分、逐层细化”的设计步骤。下**当大家已经想好了硬件的大致结构图,写代码实际上就是把结构图里的线一根根实现的过程。
## 三、Verilog 程序的基本结构
此处假设大家已经有了 C 语言的基础,那么通过阅读代码其实是学习另一门语言最方便的途径。
Verilog 是区分大小写的。格式自由,可以在一行内编写,也可跨多行编写。每个语句必须以分号为结束符。空白符(换行、制表、空格)都没有实际的意义,在编译阶段可忽略。适当的进行换行和缩进有利于代码的阅读。
下面是实现二选一数据选择器的一个简单的例子。同时我也将介绍 Verilog 的三种建模方式。
<img src="认识Verilog.assets/MUX2.svg" style="zoom:150%;" />
<img src="认识Verilog.assets/MUX2门电路.svg" />
```verilog
// 数据流建模
module Mux2 (
input s,
input in0, in1, // 可以把功能类似的输入信号放在一起,这样写更清晰
output out
);
assign out = in0 & ~s | in1 & s; // 将逻辑表达式直接写成赋值语句,这是数据流最典型的特点
endmodule
// 结构建模
module Mux2(
input s,
input in0, in1,
output out
);
wire sl_n;
wire out0, out1;
not gate0(sl_n, s); // 此处实例化了多个名字为gate的门模块通过连接各个模块进行建模
and gate1(out0, in0, sl_n); // 第一个变量为输出,其他变量为输入
and gate2(out1, in1, s); // not、and、or这些都是Verilog已经实现的门模块
or gate3(out, out0, out1);
endmodule
// 行为建模
// 写法一
module Mux2(
input s,
input in0,
input in1,
output reg y // 此处定义的y为reg类型在always语句中只有reg类型才能被赋值
);
always @( * ) begin
if (s == 0) begin // begin和end就相当于C语言中大括号的作用
y = in0;
end
else begin
y = in1;
end
end
endmodule
// 写法二
module Mux2 (
input s,
input in0, in1, // 可以把功能类似的输入信号放在一起,这样写更清晰
output out
);
assign out = s ? in1 : in0; // 这个写法很类似数据流建模,但是我们更多的对行为进行描述
endmodule
```
上面的代码简明的描述了一个两路的数据选择器的实现。
我们已经成功实现了一个二选一数据选择器,我们可以基于他实现一个四选一数据选择器。
![](认识Verilog.assets/MUX4.svg)
当 s1 和 s0 分别为 00、01、10、11 时可以分别选择 w0、w1、w2、w3。
```verilog
module Mux4 (
input [1: 0] s, // 定义了一个两位宽的s使得可以其可以选择四路
input [3: 0] w, // 定义了一个四位宽的w表示4个输入
output out
);
wire out0, out1;
// 下面实例化了三个我们之前实现了的Mux2模块通过这样的组合最终实现我们Mux4的功能
Mux2 mux_1(.s(s[0]), .in1(w[0]), .in2(w[1]), .out(out0));
Mux2 mux_2(.s(s[0]), .in1(w[2]), .in2(w[3]), .out(out1));
Mux2 mux_fin(.s(s[1]), .in1(out0), .in2(out1), .out(out));
endmodule
```
## 四、Verilog 的数据类型
基本数据类型包括了 wire 类型和 reg 类型。我们这里只介绍几种常用的数据类型,想了解更多的类型可以自己上网查阅。
下面我们也以实例进行介绍。
### 整数常量
整数常量的格式如下:
![整数常量](认识Verilog.assets/整数常量.png)
例子如:
```verilog
assign a = (b == 8'b00100101) ? 0 : 1;
```
其中 `8'b00100101`就是整数常量;当没有指定位宽时,综合器会自己自动判断位宽;当没有指定进制时,默认为十进制。
### wire 类型
wire 类型代表了在硬件电路中的连线,其特征就是输出的值紧随着输入值的变化而变化。
```verilog
wire a; // 定义了一个单位宽wire类型的信号
wire b;
wire c;
assign c = a & b; // 定义了一个单位宽wire类型c其值为a和b的与
```
c 的值会伴随着 a、b 的变化瞬间发生变化。
### reg 类型
reg 数据类型会放到过程语句中(例如 always通过过程赋值语句进行赋值。reg 类型不一定必然会对应到硬件的寄存器,综合的时候会依据实际的情况使用连线或者寄存器来完成 reg 数据类型的功能。
```verilog
reg a; // 定义了一个单位宽的reg类型的信号
always @(posedge clock) begin
a <= ~a; // 每当一个clock的上跳沿来时a会取反
end
```
a 的值只会在 clock 上跳沿来时发生变化,当 clock 不变时a 的值也不会发生变化。
```verilog
module Mux2(
input s,
input in0,
input in1,
output reg y // 此处定义的y为reg类型在always语句中只有reg类型才能被赋值
);
always @( * ) begin
if (s == 0) begin // begin和end就相当于C语言中大括号的作用
y = in0;
end
else begin
y = in1;
end
end
endmodule
```
这是我们之前见过的行为建模的 Mux此处的 y 虽然我们定义的是 reg 类型最后经过综合后y 实际上是线网类型,毕竟我们的 Mux 是组合逻辑电路,怎么会包含寄存器呢。
### 向量
wire 类型的向量:
```verilog
wire [7: 0] a; // 通过这种写法可以定义一个8位宽的信号
wire [7: 0] b;
wire [15: 0] c;
wire [3: 0] d;
wire f;
assign c = {a, b}; // 使用大括号可以将两种信号进行拼接此时a为c的高8位b位c的低8位
assign d = a[3: 0]; // 使用冒号可以对信号进行切片此时d为a的低4位
assign f = a[2]; // 此时f为a的第三位
```
reg 类型的向量:
```verilog
reg [7: 0] cnt;
// 在clock和rst发生变化时对cnt进行赋值
always @(posedge clock or posedge rst) begin
if (rst) begin
cnt <= 0; // 重置cnt
end
else begin
cnt <= cnt + 1; // cnt自增
end
end
```
### 数组
在 Verilog 中允许声明 reg, wire 等类型及其向量类型的数组。
数组维数没有限制。线网数组也可以用于连接实例模块的端口。数组中的每个元素都可以作为一个标量或者向量,以同样的方式来使用,形如:**<数组名>[<下标>]**。
数组的定义:
```verilog
reg [3: 0] counter [3: 0] ; // 由4个4bit计数器组成的数组
wire [7: 0] addr_bus [3: 0] ; // 由4个8bit wire型变量组成的数组
wire data_bit[7: 0][5: 0] ; // 声明1bit wire型变量的二维数组
reg [31: 0] data_4d[11: 0][3: 0][3: 0][255: 0] ; // 声明4维的32bit数据变量数组
```
数组的赋值:
```verilog
counter[3] = 4'hF ; // 将数组counter中第4个元素的值赋值为4bit 十六进制数F等效于counter[3][3:0] = 4'hF即可省略宽度;
assign addr_bus[0] = 8'b0 ; // 将数组addr_bus中第一个元素的值赋值为0
assign data_bit[0][1] = 1'b1; // 将数组data_bit的第1行第2列的元素赋值为1这里不能省略第二个访问标号即 assign data_bit[0] = 1'b1; 是非法的。
data_4d[0][0][0][0][15: 0] = 15'd3 ; // 将数组data_4d中标号为[0][0][0][0]的寄存器单元的15~0bit赋值为3
```
### 参数
参数可以使得我们的模块更具有拓展性,下面是一个简单的例子:
```verilog
module Mux4 #(
parameter DATA_WIDTH = 8,
parameter SEL_WIDTH = $clog2(4) // $clog2(x)返回大于等于log2(x)的最小整数
) (
input wire [DATA_WIDTH - 1: 0] A,
input wire [DATA_WIDTH - 1: 0] B,
input wire [DATA_WIDTH - 1: 0] C,
input wire [DATA_WIDTH - 1: 0] D,
input wire [SEL_WIDTH - 1: 0] Sel,
output reg [DATA_WIDTH - 1: 0] Y
);
always @ ( * )
case (Sel)
2'b00:
Y = A;
2'b01:
Y = B;
2'b10:
Y = C;
2'b11:
Y = D;
endcase
endmodule
```
## 五、Verilog 的运算符
Verilog 提供了一系列运算符,用于在硬件描述中执行各种算术、逻辑和位操作。以下是 Verilog 中常见的运算符类型:
1. 算术运算符:
- `+`:加法运算符。
- `-`:减法运算符。
- `*`:乘法运算符。
- `/`:除法运算符。
- `%`:取模(取余)运算符。
注:`*`, `/`, `%`一般不用在电路设计中,因为他们会被综合器综合成一个时序很差的电路,大大影响硬件性能。
2. 位操作运算符:
- `&`:按位与运算符。
- `|`:按位或运算符。
- `^`按位异或XOR运算符。
- `~`:按位取反运算符。
- `<<`:左移运算符。
- `>>`:右移运算符。
3. 逻辑运算符:
- `&&`:逻辑与运算符。
- `||`:逻辑或运算符。
- `!`:逻辑非运算符。
4. 比较运算符:
- `==`:等于运算符。
- `!=`:不等于运算符。
- `>`:大于运算符。
- `<`:小于运算符。
- `>=`:大于等于运算符。
- `<=`:小于等于运算符。
5. 赋值运算符:
- `=`:非阻塞赋值运算符。
- `<=`:阻塞赋值运算符。
6. 条件运算符:
- `? :`:条件运算符 (ternary operator),也称为三元运算符。例如:`a ? b : c` 表示如果 `a` 为真,则结果为 `b`,否则结果为 `c`
此外Verilog 还提供了其他运算符,如拼接运算符 `{}`, 重复运算符 `{}`, 范围运算符 `[]` 等,用于位操作和信号处理。
```verilog
wire [7: 0] a;
wire [31: 0] b;
wire [3: 0] c;
wire [7: 0] d;
// 重复运算的例子
assign b = {4{a}}; // 等价于b = {a, a, a, a}b由a重复4次组成
// 拼接运算的例子
assign a = {d[7: 4], c}; // a的高4位为d的高4位低4位为c
```
上面只是 Verilog 中一些常见的运算符类型,根据具体需求和应用,可能会使用更多的运算符。请在编写代码时参考 Verilog 语言规范以获取完整的运算符列表和详细的语法规则。
### 运算符优先级
| 运算符 | 优先级 |
| :------------------------: | :----: |
| \+, \-, \!, \~(一元操作) | 最高 |
| \*\* | |
| \*, /, % | |
| \+, \-(二元操作) | |
| \<\<, \>\>, \<\<\<, \>\>\> | |
| \<, \<\=, \>, \>\= | |
| \=\=, \!\=, \=\=\=, \!\=\= | |
| \&, \~\& | |
| \^, \^\~, \~\^ | |
| \|, \~\| | |
| \&\& | |
| \|\| | |
| ? : | 最低 |
需要注意的是Verilog 中的运算符可能具有不同的优先级和结合性。
```verilog
assign res[31: 0] = a[31: 0] + b[0] && c[0]; // 其结果是1bit的结果
assign res[31: 0] = (a[31: 0] + b[0]) && c[0]; // 这两个语句等效
```
为了确保表达式的正确求值,可以使用括号来明确运算符的优先级和结合性。
## 六、Verilog 的赋值语句
赋值语句可以说是任何一门编程语言的最基本的部分。在 Verilog 中,赋值语句包括了持续赋值语句和过程赋值语句。持续赋值语句在过程外使用,与过程语句并行执行。过程赋值语句在过程内使用,串行执行,用于描述过程的功能。
### 持续赋值语句
在 Verilog 中使用 assign 作为持续赋值语句使用,**用于对 wire 类型的变量进行赋值**。其对应的硬件也非常好理解,即通过对输出进行赋值,当输入变化的时候,经过一定的延迟,输出就会按照 assign 所描述的那样发生变化。
例如:
```verilog
assign out = in0 & in1;
```
在这个例子中,输入 in0 和 in1输出 out 都是 wire 类型的变量。当两个输入的任意一个发生变化的时候,输出 out 都会发生变化。
当然,这样的一个变化不会是立即的,而是需要经过一定的延迟,因为任何一种电路都会有延迟。
在一个模块中,可以有多个 assign 的持续赋值语句,这些持续赋值都是**并行执行**的,一旦赋值语句中的任何信号发生变化,那么这个赋值语句的输出信号(赋值等号的左边那个信号)就会跟着变化。
一个模块的持续赋值语句和前面所说的 always 过程语句都是可以出现多次的,他们之间的执行关系也是并行的,对应于电路上的信号值的变化。不同的是 assign 持续赋值语句由于表达能力的限制,只能反映一些简单的变化,而 always 过程语句则可以复杂很多,用以描述复杂的输出信号和输入信号的关系。
### 过程赋值语句
在过程里面的赋值语句被称为是过程赋值语句,一般用来对 reg 类型的变量进行赋值。
在 always 里使用的语句就是过程赋值语句,**只有 reg 类型的变量才能在 always 语句中被赋值**。
过程赋值语句分为两种类型,一个是非阻塞赋值语句(\<=),一个是阻塞赋值语句(=)。大家一定要注意对这两种赋值语句的区分,很多的 bug 可能就是过程赋值语句写错导致的。下面向大家介绍一下他们的区别:
#### 1. 非阻塞赋值语句(\<=
非阻塞赋值语句在赋值语句出现的地方不是立即发生的,而是等到整个过程块结束的时候才发生。由于不是立即发生的,在过程内的描述中,仿佛这条语句不存在一样,因此被称为是非阻塞的。只是在过程的最后会执行所有的非阻塞赋值语句,在这个执行的过程中,所有的右值会维持原来的值不变。
```verilog
module example (
input clk,
input rst,
input in,
output reg result
);
reg a, b;
always @(posedge clk, posedge rst) begin
if (rst) begin
a <= 0;
b <= 0;
result <= 0;
end
else begin
a <= in;
b <= a;
result <= b;
end
end
endmodule
```
在这串代码中,经过 rst 重置a、b、result 的值为 0。
此时若在 clk 上跳沿来时,输入 in 为 1 的值此时a、b 和 result 会**同步被赋值**分别为 1、0、0下一拍输入 in 为 0此时 a、b 和 result 分别为 0、1、0。这个模块相当于实现了一个延迟输出的功能每个 in 信号要经过 3 个 clk 后才能传递出来。
大家需要好好思考一下同步赋值。这和 C 语言里的串行运行的概念十分不同。
再看下面这个例子可能更加容易理解:
```verilog
reg a, b;
always@(posedge clk) begin
a <= b;
b <= a;
end
```
这串代码实现的功能是,每个 clk 上跳沿来时a 和 b 的值会互相交换;假如 a 和 b 分别为 0 和 1当 clk 上跳沿来时a、b 会被赋值为 1 和 0
#### 2. 阻塞赋值语句(=
阻塞赋值语句在赋值语句出现的地方就立即完成赋值操作,左值立刻发生变化。一个块语句中存在多条阻塞赋值语句的话,这些阻塞赋值语句会按照先后顺序关系,一条一条的执行,前面的赋值语句没有执行完,后面的赋值语句不会执行。这样的一种行为模式,就跟网络 IO 编程中的阻塞函数调用方式一样,一定要完成函数执行之后,这个函数调用才会退出。
下面再来看看和刚刚类似的例子:
```verilog
module example (
input clk,
input rst,
input in,
output reg result
);
reg a, b;
always @(posedge clk, posedge rst) begin
if (rst) begin
a <= 0;
b <= 0;
result <= 0;
end
else begin // 只对这里的赋值语句进行了修改
a = in;
b = a;
result = b;
end
end
endmodule
```
我们将非阻塞赋值语句改成阻塞赋值语句后,此处的赋值操作是串行赋值的。当 clk 上跳沿来时a 先赋值为 in等 a 赋值完后b 赋值为 a 的值也就是 inresult 同理也赋值为 in 的值。此处的赋值顺序就和 C 语言中语句的执行顺序一致。
```verilog
reg a, b;
always@(posedge clk) begin
a = b;
b = a;
end
```
使用阻塞赋值语句我们就不能实现之前那样交换信号值的功能了。a 和 b 的值会一直相等。
#### 3. 建议
always 语句块有两种形式:
```verilog
// 时序逻辑
always@(posedge ...) begin
...
end
// 组合逻辑
always@( * ) begin
...
end
```
我们建议**在时序逻辑电路中只使用非阻塞赋值语句(\<=)进行赋值,在组合逻辑电路中只使用阻塞赋值语句(=)进行赋值**,这样可以大大减小出 bug 的几率。
## 七、Verilog 的过程语句
以 always 为标志的是 Veilog 的过程语句,其有两种形式:
```verilog
// 时序逻辑
always@(posedge ...) begin
...
end
// 组合逻辑
always@( * ) begin
...
end
```
在时序逻辑中使用 posedge 或 negedge 表示上跳沿触发或下跳沿触发。
我们建议在编写的代码中尽量只使用一种触发类型,如上跳沿触发或者下跳沿触发。混用两种触发类型会大大降低硬件的性能。
### 条件语句
beginend 就类似于 C 语言中的大括号,用于表示一个语句块。
条件语句在组合逻辑或者时序逻辑中都可以使用。
#### 1. if 语句
```verilog
module Mux4(
input [1: 0] s,
input in0,
input in1,
input in2,
input in3,
output reg y
);
always @( * ) begin
if (s == 0) begin
y = in0;
end
else if (s == 1) begin
y = in1;
end
else if (s == 2) begin
y = in2;
end
else begin
y = in3;
end
end
endmodule
```
#### 2. case 语句
```verilog
module Mux4(
input [1: 0] s,
input in0,
input in1,
input in2,
input in3,
output reg y
);
always @( * ) begin
case (s)
0:
y = in0;
1:
y = in1;
2:
y = in2;
3:
y = in3;
default:
y = 1'bx; // 默认输出高阻态
endcase
end
endmodule
```
### 循环语句
循环语句的用法和 C 语言类似:
```verilog
module adder(
input [7: 0] a, b,
input cin,
output reg [7: 0] sum,
output reg cout
);
reg c;
integer i;
always @ ( * ) begin
c = cin;
// 利用for循环实现重复的赋值语句
for (i = 0; i < 8; i = i + 1 ) begin
{c, sum[i]} = a[i] + b[i] + c;
end
cout = c;
end
endmodule
```
## 八、Verilog 的建模方式
下面我想更详细得向大家介绍一下 Verilog 经典的三种建模方式,大家只需要稍加了解即可,因为在我们实际编写代码时,需要灵活的选用各种方法,没必要将他们分的那么开,在不同的场景不同的方法各有优势。
### 1. 数据流建模
数据流建模是基于信号传输和逻辑运算的思想,通过描述信号之间的流动和逻辑关系来建立数字电路的模型。在 Verilog 中,可以使用连续赋值语句来实现数据流建模。
数据流建模中的连续赋值语句使用赋值操作符 `=`,将右侧的表达式的值赋给左侧的信号。这种赋值是连续进行的,即当右侧的信号发生变化时,左侧的信号会立即更新。
以下是一个简单的 Verilog 模块,使用数据流建模方式描述一个 2 输入 AND 门的功能:
```verilog
module AndGate(
input wire a, // wire可以省略
input wire b,
output wire y
);
assign y = a & b; // 使用assign语句对wire类型的变量进行赋值
endmodule
```
在上述代码中,`a`和 `b`是输入信号,`y`是输出信号。`assign`语句将 `y`赋值为 `a & b`,表示 `y`的值等于 `a``b`的逻辑与运算结果。
**在数据流建模中,信号之间的连接关系可以使用逻辑运算符和位运算符来描述。**常见的逻辑运算符包括与(`&`)、或(`|`)、非(`~`)等,而位运算符包括位与(`&`)、位或(`|`)、位异或(`^`)等。
通过使用 Verilog 的数据流建模,设计人员可以方便地描述和模拟数字电路的行为,从而实现功能验证和性能评估。
### 2. 结构建模
在 Verilog 中,可以使用实例化和端口连接的方式来实现结构建模。通过实例化,可以将已定义的模块实例化为具体的组件,并在实例化过程中连接各个组件的输入和输出端口。
**结构建模的特征就是模块的逐级实例化,有点像搭积木,先设计一个小的模块,再逐渐搭出大的模块。**
![结构建模](认识Verilog.assets/电路图.svg)
以下是一个简单的 Verilog 模块,使用结构建模方式描述一个 2 输入 AND 门的功能:
```verilog
module AndGate(
input wire a,
input wire b,
input wire c,
input wire d,
output wire y
);
wire y1, y2;
// 下面实例化了3个与门
and and1(y1, a, b); // and是Verilog中的关键字and1是实例名y1是输出端口a和b是输入端口
and and2(y2, c, d);
and and3(y, y1, y2);
endmodule
```
在上述代码中,我们使用 Verilog 自带的门语句实例化了 3 个与门,这种方式实现了一个 4 输入的与门。我们还可以通过这种方式,实例化两个已经实现的 4 输入与门,将其拼接得到一个 8 输入的与门。代码类似下面这样。接着你又可以实现一个 16 输入的与门……
```verilog
module AndGate8(
input wire a,
input wire b,
input wire c,
input wire d,
input wire e,
input wire f,
input wire g,
input wire h,
output wire y
);
wire y1, y2;
AndGate and1(.a(a), .b(b), .c(c), .d(d), .y(y1)); // 将已经实现的模块AndGate实例化
AndGate and2(.a(e), .b(f), .c(g), .d(h), .y(y2)); // .a(e)表示将模块AndGate的输入端口a与当前模块的输入端口e相连
and and3(y, y1, y2);
endmodule
```
通过结构建模,可以将数字电路分解为多个模块,并在层次结构中进行连接。这种模块化的设计方式使得电路的描述更加清晰和可维护,并且方便进行功能验证和调试。
除了实例化和端口连接Verilog 还提供了其他的结构建模方式,如使用连接运算符 `{}`进行信号连接,使用 `wire``reg`声明中间信号等。这些方法可以根据具体的设计需求和设计风格进行选择和组合使用。
通过使用 Verilog 的结构建模,设计人员可以将数字电路按照模块化和层次化的方式进行描述,提高设计的可读性和可维护性,同时也方便进行功能验证和性能评估。
### 3. 行为建模
相比于前两种建模方式,行为建模用于描述数字电路的功能和操作,而不关注电路的具体结构和连线细节。它着重于描述电路的行为,包括组合逻辑和时序逻辑。对于复杂的硬件逻辑设计来说,使用行为级描述更为妥当,即直接描述出硬件所需要完成的功能,而不需要考虑这些硬件具体是如何实现的。具体如何实现交给 EDA 综合软件去做。
Verilog 的行为建模可以分为两种类型:组合逻辑行为建模和时序逻辑行为建模。
1. 组合逻辑行为建模:
组合逻辑行为建模用于描述电路中的组合逻辑部分,其中输出仅依赖于当前的输入。在组合逻辑行为建模中,可以使用 `always`块和 `assign`语句。
以下是使用组合逻辑行为建模实现的一个二选一的数据选择器,当 `sel`为 0 时 `y`的输出等于 `a``sel`为 1 时为 `b`
```verilog
module Mux2to1(
input wire a,
input wire b,
input wire sel,
output wire y
);
reg f; // f是寄存器类型的输出信号在always语句块中只有reg类型可以被赋值
always @( * ) begin
case (sel)
1'b0:
f = a; // 注意此处的赋值是使用等号的,与时序逻辑中的小于等于号不同
1'b1:
f = b;
default:
f = 1'bx; // 默认情况下,输出为未知(高阻态)
endcase
end
assign y = f;
endmodule
```
2. 时序逻辑行为建模:
时序逻辑行为建模用于描述电路中的时序逻辑部分,其中输出不仅依赖于当前的输入,还依赖于过去的输入或电路内部的状态。在时序逻辑行为建模中,可以使用 `always`块和时序控制语句(如 `if`语句、`case`语句等)。
以下是一个使用时序逻辑行为建模的例子,描述了一个简单的时序电路,其中输出取决于当前输入和过去的输入:
```verilog
module SequentialLogic(
input wire clk,
input wire reset,
input wire data,
output reg q // 也可以直接将输出定义为reg类型
);
always @(posedge clk, posedge reset) // 注意此处括号内与组合逻辑行为建模的不同
begin
if (reset) // 当时钟信号clk上升沿到来时如果reset为高电平则将输出q赋值为低电平
q <= 1'b0; // 注意此处使用小于等于号
else // 否则将输出q赋值为输入data的值。
q <= data;
end
endmodule
```
通过行为建模,设计人员可以更直观地描述数字电路的功能和操作,不需要关注具体的电路结构和连线细节。行为建模适用于功能验证、仿真和高层次的电路描述。
### 4. 总结
结构建模直接描述了硬件电路的结构,最为具体,但是不够抽象。数据流建模更加接近传统的逻辑设计,抽象程度中等。行为级描述只需要抽象描述一个硬件的功能单元完成什么样的功能即可,不需要说明硬件是如何构造的,最为抽象。在实际的设计过程中,这三种方式可以互相混合使用,针对不同的电路可以选择不同的描述方式。
## 九、Verilog 的仿真
这里我推荐使用 iverilog 搭配 gtkwave 进行 Verilog 的仿真。其他的仿真工具还有 varilator、vivado 等,大家可以自行学习。
### 一个简单的仿真例子
大家先在 vscode 中安装 [digital ide](https://digital-eda.github.io/DIDE-doc-Cn/#/?id=digital-ide-version-030) 插件,按里面的要求完成相关配置。你还需要安装 [iverilog](http://bleyer.org/icarus/) 安装时会提醒你安装 gtkwave且安装时可以一键加入环境变量十分方便。
![插件名](认识Verilog.assets/插件名.png)
在安装完后点击左栏中的 Digital-IDE 图标。
![图标](认识Verilog.assets/图标.png)
此时右下角会弹出这样的选项框,我们点击 Yes。如果没弹出来我们可以重启 vscode 试试。
![弹框](认识Verilog.assets/弹框.png)
此时我们的文件目录被更新成这样:
![文件目录](认识Verilog.assets/文件目录.png)
你可以按照插件文档修改 property.json 文件进行个性化配置。这里我就按默认进行示例展示:
我们在 src 中添加我们的 Verilog 代码。这里我们用四输入与门进行简单的实例。
![实例代码](认识Verilog.assets/实例代码.png)
按下 F1 输入 testbench
![生成testbench](认识Verilog.assets/生成testbench.png)
选中需要生成的模块:
![模块选择](认识Verilog.assets/模块选择.png)
也可以右键快速生成:
![右键生成](认识Verilog.assets/右键生成.png)
这时生成的 testbench 会被添加到 sim 文件夹中:
![sim文件夹](认识Verilog.assets/sim文件夹.png)
删去无用的信号,将 testbench.v 修改成我们需要的测试代码。
```verilog
module testbench();
parameter MAIN_FRE = 100; // unit MHz
reg sys_clk = 0;
reg sys_rst = 1;
reg [3: 0] test_data = 0; // 我们有4个输入因此设置4位宽的test_data
always begin
#(500 / MAIN_FRE) sys_clk = ~sys_clk;
end
always begin
#50 sys_rst = 0;
end
always @(posedge sys_clk) begin
if (sys_rst)
test_data = 0;
else
test_data = test_data + 1;
end
// Instance
// outports wire
wire y;
AndGate4 u_AndGate4(
.a ( test_data[0] ), // 四输入的与门每个输入为test_data的一位
.b ( test_data[1] ),
.c ( test_data[2] ),
.d ( test_data[3] ),
.y ( y )
);
initial begin
$dumpfile("wave.vcd");
$dumpvars(0, testbench);
#50000 $finish;
end
endmodule //TOP
```
修改完代码之后,我们右键选择仿真按钮:
![右键仿真](认识Verilog.assets/右键仿真.png)
这时当前文件夹下会生成 wave.vcd 文件。
![波形文件](认识Verilog.assets/波形文件.png)
此时我们需要使用 gtkwave 工具将该文件打开。在终端中输入 `gtkwave.exe user/sim/wave.vcd` 此时系统会使用 gtkwave 软件打开该波形文件。
![打开波形文件](认识Verilog.assets/打开波形文件.png)
我们观察波形可以发现只有在 a、b、c、d 均为 1 时y 才为 1可见我们与门的实现是正确的。
![波形图](认识Verilog.assets/波形图.png)
### 其他
当输入信号很多的时候,上面的那种写法肯定不合适了,因此还需要大家自己查阅资料,拓展一下这方面的知识
## 十、Verilog 的一些建议和提醒
Verilog 是一种可以用于仿真的语言,其中只有一部分可以被综合,一定要注意切勿将仿真相关的语句写入代码中。
经过仿真的例子大家应该简单了解了 [digital ide](https://digital-eda.github.io/DIDE-doc-Cn/#/?id=digital-ide-version-030) 插件的便利之处。大家可以仔细阅读配置文件,配置好编程环境,所谓工欲善其事必先利其器,好的工具能大大加速开发效率。

Binary file not shown.

Before

Width:  |  Height:  |  Size: 133 KiB

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 40 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 133 KiB

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 40 KiB

View File

@ -1,65 +0,0 @@
# 译码器
## 一、实验介绍
译码器Decoder是一种数字电路组件用于将输入的编码信息转换为相应的输出信号。它的作用是解码输入信号根据输入的编码模式选择并激活相应的输出线路。
译码器的工作原理是根据输入编码的模式选择并激活相应的输出线路。例如,一个 3-8 译码器接收 3 位二进制编码作为输入,根据输入编码的不同,选择并激活对应的输出线路。具体来说,如果输入编码为 `000`,那么译码器将激活输出线路 0如果输入编码为 `001`,则激活输出线路 1依此类推。
译码器广泛应用于数字系统和计算机中的多种场景,包括:
- 存储器访问:在存储系统中,译码器用于选择要读取或写入的存储单元。根据存储器地址的编码,译码器激活对应的存储单元。
- 显示驱动:在数码管显示或 LED 显示中,译码器用于将输入的数字编码转换为相应的数码管段或 LED 灯的亮灭控制信号。
- 地址解码:在计算机系统中,译码器用于将指令地址编码解码为特定的控制信号,以选择执行特定操作的电路路径。
- 数据选择和交换:在数据通路中,译码器用于选择不同的数据输入或输出路径,根据控制信号将数据流动到特定的目标。
## 二、实验目的
1. 理解译码器的原理和功能。
2. 学会使用 Verilog 描述译码器的行为。
3. 掌握 Verilog 仿真工具的使用,验证译码器的正确性。
## 三、实验要求
1. 使用 Verilog 描述译码器的行为。
2. 通过所有测试点。
## 四、实验步骤
这里我们以 3-8 译码器为例子:
### 1. 框图
![](译码器.assets/译码器.svg)
- $A$ 、 $B$ 、 $C$ 是译码器的三个输入信号。
- $Y_0$ ~ $Y_7$ 是译码器的八个输出信号。
- $Y$ 的输出是二进制序列 $ABC$ 的十进制表示:当 $ABC$ 为 011 时对应的 $Y_3$ 输出为 1 其他为 0。
### 2. 真值表
![](译码器.assets/真值表.png)
### 3. 顶层模块
```verilog
module Decoder3_8(
input wire A,
input wire B,
input wire C,
output wire [7: 0] Y
);
// TODO你的代码实现
endmodule
```
在上述代码中,顶层模块名为 `Decoder3_8`,它有四个端口:
- $A$ 、 $B$ 、 $C$ 是译码器的三个输入信号。
- $Y_0$ ~ $Y_7$ 是译码器的八个输出信号。
- $Y$ 的输出是二进制序列 $ABC$ 的十进制表示:当 $ABC$ 为 011 时对应的 $Y_3$ 输出为 1 其他为 0。
请补充代码,完成 3-8 译码器的设计。

View File

@ -1,32 +0,0 @@
# 超前进位加法器
## 一、实验介绍
超前进位加法器Carry Lookahead AdderCLA是一种用于高速加法运算的电路结构。它利用了逻辑门级联的方式通过预先计算进位信号从而在加法过程中减少了级联延迟提高了运算速度。
传统的加法器(如全加器)是通过级联连接的方式计算加法结果,每个加法位需要等待前一位的进位信号传递过来才能开始计算。这种级联的方式导致了延迟的累积,影响了整体的性能。
超前进位加法器通过预先计算进位信号来解决这个问题。它在每一位上都有一个预先计算的电路块,用于判断该位上的加法是否会产生进位。这些预先计算的进位信号可以并行生成,并在加法器的输入端进行传递。这样,在加法过程中,每个加法位都可以立即进行计算,而不需要等待进位信号的传递,从而减少了级联延迟。
超前进位加法器的主要优点是速度快,特别适用于需要高速运算的场景,如高性能计算、数字信号处理等。然而,其缺点是电路复杂度较高,需要更多的逻辑门和电路资源。
本实验介绍如何使用 Verilog 编写超前进位加法器。
## 二、实验目的
1. 理解超前进位加法器的原理和功能。
2. 学会使用 Verilog 描述超前进位加法器的行为。
3. 掌握 Verilog 仿真工具的使用,验证超前进位加法器的正确性。
## 三、实验要求
1. 使用 Verilog 描述超前进位加法器的行为。
2. 通过所有测试点。
## 四、实验步骤
### 1. 框图
### 2. 真值表
### 3. 顶层模块

Binary file not shown.

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 26 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 8.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 25 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 57 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 18 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 17 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 24 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 34 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 38 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 36 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 23 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 19 KiB

View File

@ -1,662 +0,0 @@
#import "../template/template.typ": *
#import "@preview/tablex:0.0.7": *
// Take a look at the file `template.typ` in the file panel
// to customize this template and discover how it works.
#show: project.with(
title: "实验九 实现R型运算类指令的理想流水线设计实验",
authors: (
"Xi Lifeng",
),
)
#show math.equation: set text(font: "Linux Libertine")
#set par(justify: true, first-line-indent: 2em)
#show heading: it => {
it
par()[#text(size:0.5em)[#h(0.0em)]]
}
#show list: set list(indent: 1em)
#show enum: set enum(indent: 1em)
// 缩进控制
#let indent = h(2em)
#let noindent = h(-2em)
#let fakepar = par()[#text(size:0.5em)[#h(0.0em)]]
#let dir_name = "这里填开发环境名称"
#let soc_freq = "100MHz"
#let inst_ram_date_wid = 32
#let paddr_wid = 32
= 实验目的
+ 掌握R型运算类指令的数据通路
+ 掌握经典单发射五级流水线的设计方法
+ 掌握流水线CPU设计的编程基本框架
= 实验原理与实验内容
== 单周期与流水线
=== 结构差异
RISC-V单周期CPU设计实现简单控制器部分是纯组合逻辑电路但该CPU所有指令执行时间均是一个相同的周期即以速度最慢的指令作为设计其时钟周期的依据。如@单周期CPU 所示单周期CPU的时钟频率取决于数据通路中的关键路径最长路径所以单周期CPU效率较低性能不佳现代处理器中已不再采用单周期方式取而代之的是多周期设计方式。而多周期CPU设计中流水线CPU设计是目前的主流技术。
#fakepar
#figure(
image("image/image-20240107161239749.png"),
caption: "单周期CPU"
)<单周期CPU>
#figure(
image("image/image-20240107150508299.png"),
caption: "单周期CPU逻辑划分"
)<单周期CPU逻辑划分>
#fakepar
将电路流水线化的初衷是缩短时序器件之间组合逻辑关键路径的时延,在不降低电路处理吞吐率的情况下提升电路的时钟频率。从电路设计最终的实现形式来看,是将一段组合逻辑按照功能划分为若干阶段,在各功能阶段的组合逻辑之间插入时序器件(通常是触发器),前一阶段的组合逻辑输出接入时序器件的输入,后一阶段的组合逻辑输入来自这些时序器件的输出。
而将电路流水化最困难的地方是决定将单周期CPU中的组合逻辑划分为多少个阶段以及各个阶段包含哪些功能。这个设计决策需要结合CPU产品的性能含主频、功耗、面积指标以及具体采用的工艺特性来完成。对于教学而言这部分设计涉及的内容过多、过细、过深因此本实验将直接采用经典的单发射五级流水线划分。所划分的五级流水从前往后依次为取指阶段Fetch、译码阶段Decode、执行阶段Execute、访存阶段Memory和写回阶段WriteBack
+ 取指阶段的主要功能是将指令取回。
+ 译码阶段的主要功能是解析指令生成控制信号并读取通用寄存器堆生成源操作数。
+ 执行阶段的主要功能是对源操作数进行算术逻辑类指令的运算或者访存指令的地址计算。
+ 访存阶段的主要功能是取回访存的结果。
+ 写回阶段的主要功能是将结果写入通用寄存器堆。
#indent 结合以上流水线阶段的划分方案将单周期CPU的数据通路拆分为五段如@单周期CPU逻辑划分 所示),并在各段之间加入触发器作为流水线缓存,@五级流水线CPU逻辑结构 展示了RISC-V流水线的逻辑结构。
#fakepar
#figure(
image("image/image-20240108174346298.png"),
caption: "五级流水线CPU逻辑结构"
)<五级流水线CPU逻辑结构>
#fakepar
所有部件采用同一个系统时钟clock来进行同步每到来一个时钟clock各段逻辑功能部件处理完毕的数据会被锁存到下一级的流水线缓存中作为下一段的输入数据指令执行进入下一阶段。clock的频率取决于流水线缓存两级间的最大逻辑延迟。
=== 性能差异
#fakepar
#figure(
image("image/image-20240107201217987.png"),
caption: "单周期CPU时空图"
)<单周期CPU时空图>
#figure(
image("image/image-20240107193813519.png"),
caption: "五级流水线CPU时空图"
)<五级流水线CPU时空图>
#fakepar
@单周期CPU时空图 给出了RISC-V单周期CPU的时空图可以看到每条指令执行需要5个时钟周期即$5 Delta t$。1个时钟周期是1个$Delta t$也就是每5个$Delta t$可以提交1条指令单周期CPU的IPC是0.2。算出运行n条指令花费的总时间为$n dot 5 Delta t$。@五级流水线CPU时空图 给出了RISC-V理想的五级流水线CPU时空图。在理想情况下当流水线满载运行时每个时钟周期流水线可以提交1条指令也就是CPU的IPC为1。流水线完成n条指令的总时间为$4 dot Delta t + n dot Delta t$。当n趋近于$infinity$时相比单周期CPU执行n条指令花费的时间五级流水线的加速比$lim_(n->oo)S_p=frac(5 n dot Delta t, 4 dot Delta t + n dot Delta t)=5$即理想的五级流水线CPU的执行效率是单周期CPU的5倍。
== 数据通路设计
=== 设计的基本方法
在计算机结构设计实验中需要设计实现的CPU也是一个数字逻辑电路其设计应该遵循数字逻辑电路设计的一般性方法。CPU不但要完成运算也要维持自身的状态所以CPU一定是既有组合逻辑电路又有时序逻辑电路的。CPU输入的、运算的、存储的、输出的数据都在组合逻辑电路和时序逻辑电路上流转这些逻辑电路被称为数据通路Datapath。因此要设计CPU这个数字逻辑电路首要的工作就是设计数据通路。同时因为数据通路中会有多路选择器、时序逻辑器件所以还要有相应的控制信号产生这些控制信号的逻辑被称为控制逻辑。所以从宏观的视角来看设计一个CPU就是设计“数据通路+控制逻辑”。
#fakepar
#figure(
image("image/image-20240107213744736.png"),
caption: "理想的五级流水线CPU数据与控制信号传递图"
)<理想的五级流水线CPU数据与控制信号传递图>
#fakepar
根据指令系统规范中的定义设计出“数据通路+控制逻辑”的基本方法是:对指令系统中定义的指令逐条进行功能分解,得到一系列操作和操作的对象。显然,这些操作和操作的对象必然对应其各自的数据通路,又因为指令间存在一些相同或相近的操作和操作对象,所以可以只设计一套数据通路供多个指令公用。对于确实存在差异无法共享数据通路的情况,只能各自设计一套,再用多路选择器从中选择出所需的结果。遵循这个一般性方法,下面具体介绍如何分析指令的功能以及如何设计出数据通路。@理想的五级流水线CPU数据与控制信号传递图 展示了RISC-V理想的五级流水线CPU数据与控制信号传递图。
=== 以ADD指令为例
以ADD指令为例分析一下该指令需要哪些数据通路部件。
首先执行指令的前提是需要得到ADD这条指令需要使用这条指令对应的PC作为虚拟地址进行虚实地址转换得到访问指令SRAM的物理地址。这意味着需要的数据通路部件有取指单元、虚实地址转换部件和指令SRAM。下面先对这部分的数据通路进行实现。
#noindent #strong(text(12pt, red)[前端])
#let unitcnt = counter("unitcnt")
#let unitcnt_inc = {
unitcnt.step()
unitcnt.display()
}
#noindent #text(fill: blue)[#unitcnt_inc取指单元]
因为实现的是一个64位的处理器所以PC的指令宽度是64比特。用一组64位的触发器来存放PC。后面为了行文简洁在不会导致混淆的情况下用pc代表这组用于存放PC的64位触发器。由于处理器使用到了SRAM进行数据的存取而SRAM的特性是一次读数操作需要跨越两个时钟周期第一个时钟周期向RAM发出读使能和读地址第二个时钟周期RAM才能返回读结果。因此发送给指令SRAM的地址应该是下一条指令的PC也就是pc_next而目前的实验设计pc_next的大小将一直等于pc+4这里的4代表寻址4个字节即一条指令的宽度因此pc_next和pc之间只是组合逻辑的关系。
#fakepar
#figure(
image("image/image-20240109155256358.png"),
caption: "取指单元及指令RAM"
)<取指单元及指令RAM>
#fakepar
pc的输出将送到指令SRAM中用于获取指令由于指令SRAM的地址宽度只有#paddr_wid 位因此只有pc的低#paddr_wid 会被使用。目前来看PC的输入有两个一个是复位值0x80000000由于发送给指令SRAM的是pc_next所以pc的真正复位值其实是0x80000000-0x4一个是复位撤销之后pc_next的值。
因为取指单元只会对内存进行读操作因此inst_sram_en只要在reset无效时使能即可而inst_sram_wen应该恒为低电平。@取指单元及指令RAM 展示了取指单元的结构。
#noindent #text(fill: blue)[#unitcnt_inc虚实地址转换]
任何时候CPU上运行的程序中出现的地址都是虚地址而CPU本身访问内存、I/O所用的地址都是物理地址因此需要对CPU发出的虚拟地址进行转换使用物理地址进行访存。在实现RISC-V的S模式之前目前实现的CPU的虚拟地址与物理地址之间使用直接映射的方式即物理地址的值等于虚拟地址的值。因此虚实地址转换部件目前可以先省略。
#noindent #text(fill: blue)[#unitcnt_inc指令RAM]
得到取指所需的物理地址后接下来需要将该地址送往内存。实验采用片上的RAM作为内存并且将RAM进一步分拆为指令RAM和数据RAM两块物理上独立的RAM以简化设计。
指令RAM输出的#inst_ram_date_wid 位数据就是指令码。实验实现的CPU采用小尾端的寻址所以指令RAM输出的#inst_ram_date_wid 位数据与指令系统规范中的定义的字节顺序是一致的,不需要做任何字节序调整。
@取指单元及指令RAM 展示了指令RAM的结构。指令RAM保留了写接口这样的接口设计是为了和之后的AXI的设计保持一致性。
#noindent #text(fill: blue)[#unitcnt_inc指令队列]
取指单元/译码单元之间的流水线缓存称为指令队列。指令队列之前的阶段称为前端,指令队列之后的阶段称为后端。
当取指单元一次取指的数量大于译码单元可以解码的数量时,又或是后端流水线发生暂停时,取指单元可以继续取指,多余的指令可以在指令队列中排队等待,而不用暂停取指。因此指令队列部件的实现可以解耦前后端。
#fakepar
#figure(
image("image/image-20240124134556170.png"),
caption: "指令队列"
)<指令队列>
#fakepar
如@指令队列 所示指令队列的实现是一个深度为depth的寄存器组每个寄存器中保存一个叫做data的数据包
#footnote[这里的数据包指chisel中由Bundle实现的一个数据结构]
目前需要保存指令的内容以及指令的PC这两个数据宽度应该和data的宽度一致。出队指针和入队指针都是一个宽度为$log_2 lr(("depth"), size: #50%)$的寄存器。使用出队指针指示队列的头部入队指针指示队列的尾部。由取指单元发送的数据存入入队指针指示的寄存器出队指针指示的寄存器保存的数据发送到译码单元中。目前实现的是理想流水线因此每一个clock的上跳沿来临时入队指针和出队指针都应该加1发生reset时两个指针都应该置为0。
#noindent #strong(text(12pt, fill: red)[后端])
前端部分已经成功取得指令接下来需要通过译码识别出这条指令为ADD指令并产生相应的控制信号。
#noindent #text(fill: blue)[#unitcnt_inc译码单元]
译码单元要完成指令译码和源操作数的准备这两个操作,指令译码由译码器完成,源操作数通过访问通用寄存器堆获得。
a译码器
首先需要明白译码器是如何解码不同指令的。RISC-V有6种指令格式如@RISC-V指令格式 所示。译码器根据指令的opcode段识别出指令的格式再进行下一步的译码。
#fakepar
#figure(
tablex(
columns: 33,
align: center + horizon,
repeat-header: true,
header-rows: 1,
auto-lines: false,
vlinex(x:0, start:1), vlinex(x:7, start:1), vlinex(x:12, start:1), vlinex(x:17, start:1), vlinex(x:20, start:1), vlinex(x:25, start:1), vlinex(x:32, start:1),
cellx(align: left, colspan: 6)[31], cellx(align: right)[25], cellx(align: left, colspan: 4)[24], cellx(align: right)[20], cellx(align: left, colspan: 4)[19], cellx(align: right)[15], cellx(align: left, colspan: 2)[14], cellx(align: right)[12], cellx(align: left, colspan: 4)[11], cellx(align: right)[7], cellx(align: left, colspan: 6)[6], cellx(align: right)[0], [],
hlinex(end:32),
colspanx(7, inset:(x: 5em))[funct7], colspanx(5, inset:(x: 2em))[rs2], colspanx(5, inset:(x: 2em))[rs1], colspanx(3)[funct3], colspanx(5, inset:(x: 2em))[rd], colspanx(7, inset:(x: 1.5em))[opcode], [R-type],
hlinex(end:32),
colspanx(12)[imm[11:0]], colspanx(5)[rs1], colspanx(3)[funct3], colspanx(5)[rd], colspanx(7)[opcode], [I-type],
hlinex(end:32),
colspanx(7)[imm[15:5]], colspanx(5)[rs2], colspanx(5)[rs1], colspanx(3)[funct3], colspanx(5)[imm[4:0]], colspanx(7)[opcode], [S-type],
hlinex(end:32),
colspanx(7)[imm[12|10:5]], colspanx(5)[rs2], colspanx(5)[rs1], colspanx(3)[funct3], colspanx(5)[imm[4:1|11]], colspanx(7)[opcode], [B-type],
hlinex(end:32),
colspanx(20)[imm[31:12]], colspanx(5)[rd], colspanx(7)[opcode], [U-type],
hlinex(end:32),
colspanx(20)[imm[20|10:1|11|19:12]], colspanx(5)[rd], colspanx(7)[opcode], [J-type],
hlinex(end:32),
),
caption: "RISC-V指令格式",
kind: table
)<RISC-V指令格式>
#fakepar
本实验只需要实现R型的运算指令。@R型运算指令 展示了RV64中所有R型运算指令。先分析非字指令不难发现R型运算指令的opcode是0110011再通过func3区别各指令的运算类型其中ADD和SUB、SRL和SRA的func3一致再由func7的第6位进行区分。而字指令的分析也和非字指令的分析一致。
#fakepar
#[
#show figure: set block(breakable: true)
#figure(
tablex(
columns: 33,
align: center + horizon,
repeat-header: true,
header-rows: 1,
auto-lines: false,
map-cells: cell => {
if (cell.x == 32) {
cell.content = {
set align(left)
cell.content
}
}
cell
},
vlinex(x:0, start:1), vlinex(x:6, start:1), vlinex(x:7, start:1), vlinex(x:12, start:1), vlinex(x:17, start:1), vlinex(x:20, start:1), vlinex(x:25, start:1), vlinex(x:32, start:1),
cellx(align: left, colspan: 6)[31], cellx(align: right)[25], cellx(align: left, colspan: 4)[24], cellx(align: right)[20], cellx(align: left, colspan: 4)[19], cellx(align: right)[15], cellx(align: left, colspan: 2)[14], cellx(align: right)[12], cellx(align: left, colspan: 4)[11], cellx(align: right)[7], cellx(align: left, colspan: 6)[6], cellx(align: right)[0], [],
hlinex(end:32),
colspanx(7, inset:(x: 5em))[0000000],
colspanx(5, inset:(x: 2em))[rs2],
colspanx(5, inset:(x: 2em))[rs1],
colspanx(3)[000],
colspanx(5, inset:(x: 2em))[rd],
colspanx(7, inset:(x: 1.5em))[0110011], [ADD],
hlinex(end:32),
colspanx(7, inset:(x: 5em))[0100000],
colspanx(5, inset:(x: 2em))[rs2],
colspanx(5, inset:(x: 2em))[rs1],
colspanx(3)[000],
colspanx(5, inset:(x: 2em))[rd],
colspanx(7, inset:(x: 1.5em))[0110011], [SUB],
hlinex(end:32),
colspanx(7, inset:(x: 5em))[0000000],
colspanx(5, inset:(x: 2em))[rs2],
colspanx(5, inset:(x: 2em))[rs1],
colspanx(3)[001],
colspanx(5, inset:(x: 2em))[rd],
colspanx(7, inset:(x: 1.5em))[0110011], [SLL],
hlinex(end:32),
colspanx(7, inset:(x: 5em))[0000000],
colspanx(5, inset:(x: 2em))[rs2],
colspanx(5, inset:(x: 2em))[rs1],
colspanx(3)[010],
colspanx(5, inset:(x: 2em))[rd],
colspanx(7, inset:(x: 1.5em))[0110011], [SLT],
hlinex(end:32),
colspanx(7, inset:(x: 5em))[0000000],
colspanx(5, inset:(x: 2em))[rs2],
colspanx(5, inset:(x: 2em))[rs1],
colspanx(3)[011],
colspanx(5, inset:(x: 2em))[rd],
colspanx(7, inset:(x: 1.5em))[0110011], [SLTU],
hlinex(end:32),
colspanx(7, inset:(x: 5em))[0000000],
colspanx(5, inset:(x: 2em))[rs2],
colspanx(5, inset:(x: 2em))[rs1],
colspanx(3)[100],
colspanx(5, inset:(x: 2em))[rd],
colspanx(7, inset:(x: 1.5em))[0110011], [XOR],
hlinex(end:32),
colspanx(7, inset:(x: 5em))[0000000],
colspanx(5, inset:(x: 2em))[rs2],
colspanx(5, inset:(x: 2em))[rs1],
colspanx(3)[101],
colspanx(5, inset:(x: 2em))[rd],
colspanx(7, inset:(x: 1.5em))[0110011], [SRL],
hlinex(end:32),
colspanx(7, inset:(x: 5em))[0100000],
colspanx(5, inset:(x: 2em))[rs2],
colspanx(5, inset:(x: 2em))[rs1],
colspanx(3)[101],
colspanx(5, inset:(x: 2em))[rd],
colspanx(7, inset:(x: 1.5em))[0110011], [SRA],
hlinex(end:32),
colspanx(7, inset:(x: 5em))[0000000],
colspanx(5, inset:(x: 2em))[rs2],
colspanx(5, inset:(x: 2em))[rs1],
colspanx(3)[110],
colspanx(5, inset:(x: 2em))[rd],
colspanx(7, inset:(x: 1.5em))[0110011], [OR],
hlinex(end:32),
colspanx(7, inset:(x: 5em))[0000000],
colspanx(5, inset:(x: 2em))[rs2],
colspanx(5, inset:(x: 2em))[rs1],
colspanx(3)[111],
colspanx(5, inset:(x: 2em))[rd],
colspanx(7, inset:(x: 1.5em))[0110011], [AND],
hlinex(end:32),
colspanx(7, inset:(x: 5em))[0000000],
colspanx(5, inset:(x: 2em))[rs2],
colspanx(5, inset:(x: 2em))[rs1],
colspanx(3)[000],
colspanx(5, inset:(x: 2em))[rd],
colspanx(7, inset:(x: 1.5em))[0111011], [ADDW],
hlinex(end:32),
colspanx(7, inset:(x: 5em))[0100000],
colspanx(5, inset:(x: 2em))[rs2],
colspanx(5, inset:(x: 2em))[rs1],
colspanx(3)[000],
colspanx(5, inset:(x: 2em))[rd],
colspanx(7, inset:(x: 1.5em))[0111011], [SUBW],
hlinex(end:32),
colspanx(7, inset:(x: 5em))[0000000],
colspanx(5, inset:(x: 2em))[rs2],
colspanx(5, inset:(x: 2em))[rs1],
colspanx(3)[001],
colspanx(5, inset:(x: 2em))[rd],
colspanx(7, inset:(x: 1.5em))[0111011], [SLLW],
hlinex(end:32),
colspanx(7, inset:(x: 5em))[0000000],
colspanx(5, inset:(x: 2em))[rs2],
colspanx(5, inset:(x: 2em))[rs1],
colspanx(3)[101],
colspanx(5, inset:(x: 2em))[rd],
colspanx(7, inset:(x: 1.5em))[0111011], [SRLW],
hlinex(end:32),
colspanx(7, inset:(x: 5em))[0100000],
colspanx(5, inset:(x: 2em))[rs2],
colspanx(5, inset:(x: 2em))[rs1],
colspanx(3)[101],
colspanx(5, inset:(x: 2em))[rd],
colspanx(7, inset:(x: 1.5em))[0111011], [SRAW],
hlinex(end:32),
),
caption: "R型运算指令",
kind: table
)<R型运算指令>
]
#fakepar
R型运算指令都是三地址指令每条指令都有两个源操作数以及一个目的操作数。记源操作数1为src1源操作数2为src2。因此译码器中要产生的控制信号如下
- src1_rensrc1 是否需要读通用寄存器堆
- src1_raddrsrc1 的通用寄存器堆读地址
- src2_rensrc2 是否需要读通用寄存器堆
- src2_raddrsrc2 的通用寄存器堆读地址
- op指令的操作类型
- reg_wen是否需要写回通用寄存器堆
- reg_waddr通用寄存器堆的写地址
#indent 接下来阅读手册,根据手册对指令功能的定义对各控制信号进行赋值。@ADD指令定义 展示了ADD指令的定义。
#figure(
image("image/image-20240124141127010.png"),
caption: "ADD指令定义"
)<ADD指令定义>
#fakepar
ADD指令的源操作数都来自通用寄存器堆因此src1_ren和src2_ren都为1src1_raddr对应指令的19至15位src2_raddr对应指令的24至20位。ADD指令需要写回通用寄存器堆因此reg_wen为1reg_waddr对应指令的11至7位。因为目前要实现的指令都在执行单元的ALU中进行运算因此只需要将op设置正确就能完成指令的区分。op的设置有多种方法下面介绍两种
1. 简单的方法:
#indent 直接将指令从0开始按顺序编号如ADD为1、SUB为2、SLL为3……
2. 稍微复杂一些的方法:
#indent 观察指令格式进行op的设计比如非字指令的opcode一致仅func3以及func7的第6位有区别那么可以将这几位进行拼接由于ADD又有ADD和ADDW的区别因此可以再加一位进行字指令的区分因此ADD的op可以设计为00000。按这种思路SRAW的op就是11101。
不同的op设计对于FUFunctionUnit功能部件内部的解码会有一定的影响好的编码设计可以大大提升硬件性能。
b通用寄存器堆
完成了控制信号的生成接下来需要准备源操作数也就是访问通用寄存器堆相比SRAM这种存储类型通用寄存器堆的访问都是当拍完成。通用寄存器堆可以实现在译码单元内部也可以直接实现在CPU内部作为一个独立模块两者没有什么太大的区别。
@译码单元 展示了译码单元的结构译码器将从指令队列获得的指令进行译码产生了相关的控制信号将所有的控制信号打包成info数据包与寄存器堆读回的源操作数组成的src_info数据包以及指令队列获得的pc一起打包成一个data数据包发送至下一级流水线缓存。
#fakepar
#figure(
image("image/image-20240125134200367.png"),
caption: "译码单元"
)<译码单元>
#fakepar
#noindent #text(fill: blue)[#unitcnt_inc执行级缓存]
译码单元/执行单元这两级间的缓存称为执行级缓存,将缓存的名称归到它的输出对应的那一个流水阶段。这样子命名可以与仿真波形调试时的观察习惯保持一致,即除了触发器时钟采样边沿附近那段建立保持时间(当采用零延迟仿真时,这段时间可以看作瞬时、无穷小)外,触发器中存储的内容都是与它输出那一级流水的组合逻辑相关联的,如执行单元中运行的指令实际上是译码单元/执行单元这两级缓存中存储的数据。后面流水线级间缓存也将统一采用这种标识的方式。
#fakepar
#figure(
image("image/image-20240111132343570.png"),
caption: "执行级缓存"
)<执行级缓存>
#fakepar
@执行级缓存 展示了执行级缓存的结构。执行级缓存内部有一个用于保存上一级传来的data数据包的寄存器在每个clock的上跳沿更新寄存器内容。寄存器保存的内容直接传往下一级。
#noindent #text(fill: blue)[#unitcnt_inc执行单元]
在执行单元中,指令需要在这里完成运算指令结果的计算。
#fakepar
#figure(
image("image/image-20240125134816118.png"),
caption: "执行单元"
)<执行单元>
#fakepar
@执行单元 展示了执行单元的结构R型运算指令只需要使用ALU这一个部件即可ALU部件已经在数字电路实验中学习过。将执行级缓存传来的data数据包包内包括info数据包和src_info数据包发送至ALU中。ALU可以通过info数据包内op的区别进行不同的计算操作而源操作数在src_info数据包中。ALU将运算结果reg_wdata打包到rd_info数据包中和pc以及info数据包内的reg_wen、reg_waddr一块打包成新的data数据包发送至访存级缓存。
#noindent #text(fill: blue)[#unitcnt_inc访存级缓存]
#fakepar
#figure(
image("image/image-20240111135906222.png"),
caption: "访存级缓存"
)<访存级缓存>
#fakepar
@访存级缓存 展示了访存级缓存的结构。访存级缓存的结构与执行级缓存结构一致。
#noindent #text(fill: blue)[#unitcnt_inc访存单元]
#fakepar
#figure(
image("image/image-20240111150330436.png"),
caption: "访存单元"
)<访存单元>
#fakepar
ADD指令并不需要访问内存因此在该流水级什么也不做只需要将上一级缓存内的data数据包传到下一级缓存中即可。@访存单元 展示了访存单元的结构。将data_sram_en和data_sram_wen置为0对于data_sram_addr、data_sram_wdata以及data_sram_rdata这三个信号就不需要理会了在chisel语言中可以使用DontCare对data_sram_addr和data_sram_wdata进行赋值
#noindent #text(fill: blue)[#unitcnt_inc写回级缓存]
#fakepar
#figure(
image("image/image-20240111140744667.png", width: 88%),
caption: "写回级缓存"
)<写回级缓存>
#fakepar
@写回级缓存 展示了写回级缓存的结构。写回级缓存的结构与访存级缓存结构一致。
#noindent #text(fill: blue)[#unitcnt_inc写回单元]
ADD指令需要写回通用寄存器堆因此需要在写回级访问通用寄存器堆。将data数据包解包将info数据包内的reg_wen、reg_waddr和reg_wdata发送至通用寄存器堆同时这些信号还需要与pc一起发往CPU的外部作为debug信号。
#fakepar
#figure(
image("image/image-20240111143829812.png", width: 90%),
caption: "写回单元"
)<写回单元>
#fakepar
== 开发环境的组织与结构
整个CPU设计开发环境#dir_name的目录结构及各主要部分的功能如下所示。其中只有标黑色的部分是需要自行开发的其余部分均为开发环境框架代码已经设计完毕。
// #fakepar
// #figure(
TODO增加目录结构图
// caption: "开发环境目录结构"
// )<开发环境目录结构>
// #fakepar
=== 验证所用的计算机硬件系统
单纯实现一个CPU没有什么实用价值通常需要基于CPU搭建一个计算机硬件系统。本实验也是基于CPU搭建一个计算机硬件系统然后通过在这个计算机硬件系统上运行测试程序来完成CPU的功能验证。
在引入AXI总线接口设计之前实验将采用一个简单的计算机硬件系统。这个硬件系统将通过FPGA开发板实现。其核心是在FPGA芯片上实现的一个片上系统System On ChipSoC。这个SoC芯片通过引脚连接电路板上的时钟晶振、复位电路以及LED灯、数码管、按键等外设接口设备。SoC芯片内部也是一个小系统其顶层为SoC_Lite内部结构如@基于myCPU的简单Soc结构 所示对应的RTL代码均位于mycpu_verify/rtl/目录下。只需重点关注SoC_Lite这个小系统。可以看到SoC_Lite的核心是实验将要实现的CPU——myCPU。这个CPU与指令RAMInst Sram和数据RAMData Sram进行交互完成取指和访存的功能。除此之外这个小系统中还包含PLL、Peripherals等模块。
#fakepar
#figure(
image("image/image-20240111160016125.png"),
caption: "基于myCPU的简单Soc结构"
)<基于myCPU的简单Soc结构>
#fakepar
在数据通路分析中已经阐述了指令RAM和数据RAM与CPU之间的关系。这里简单解释一下PLL、Peripherals以及myCPU与Data Sram、Peripherals之间的二选一功能。
开发板上给FPGA芯片提供的时钟来自时钟晶振主频是#soc_freq。如果直接使用这个时钟作为SoC_Lite中各个模块的时钟则意味着myCPU的主频至少要能达到#soc_freq。对于初学者来说这可能是个比较严格的要求因此实验添加了一个PLL IP将其输出时钟作为myCPU的时钟输入。这个PLL以#soc_freq 输入时钟作为参考时钟,输出时钟频率可以配置为低于#soc_freq。
myCPU通过访问Peripherals部件来驱动板上的LED灯、数码管接收外部按键的输入。其操控的原理如下外部的LED灯、数码管以及按键都是通过导线直接连接到FPGA的引脚上的通过控制FPGA输出引脚上的电平的高、低就可以控制LED灯和数码管。同样也可以通过观察FPGA输入引脚上电平的变化来判断一个按键是否按下。这些FPGA引脚又进一步连接到Peripherals部件中某些寄存器的某些位上所以myCPU可以通过写Peripherals部件寄存器控制输出引脚的电平来控制LED灯和数码管也可以通过读Peripherals部件寄存器来知晓连接到按键的引脚是高电平还是低电平。
myCPU和dram、Peripherals之间有一个“一分二”部件。这是因为在RISC-V指令系统架构下所有I/O设备的寄存器都是采用Memory Mapped方式访问的这里实现的Peripherals也不例外。MemoryMapped访问方式意味I/O设备中的寄存器各自有一个唯一内存编址所以CPU可以通过load、store 指令对其进行访问。不过dram作为内存也是通过load、store指令进行访问的。对于一条load或store指令来说如何知晓它访问的是Peripherals还是dram在设计SoC的时候可以用地址对其进行区分相当于存在一个数据选择器其根据地址选择数据。因此在设计SoC的数据通路时就需要在这里引入一个“一分二”部件它的选择控制信号是通过对访存的地址范围进行判断而得到的。
这里要提醒是因为整个SoC_Lite的设计都要实现到FPGA芯片中所以在进行综合实现的时候所需选择的顶层应该是SoC_Lite而不是设计实现的myCPU。
=== 验证所用的计算机仿真系统
由于上板的限制条件很多,这里再介绍软件的仿真方法,其运行效果与上板仿真几乎无异,但效率更高且更加方便。
TODO仿真结构
=== myCPU的顶层接口
为了使设计的CPU能够直接集成到本平台所提供的CPU实验环境中这里要对CPU的顶层接口做出明确的规定。myCPU顶层接口信号的详细定义如@差分测试框架接口 以及@myCPU顶层接口信号的描述 所示。只要设计的CPU符合这样的顶层接口就可以接入的差分测试框架中使用。
#fakepar
#figure(
image("image/image-20240111165434087.png", width: 80%),
caption: "差分测试框架接口"
)<差分测试框架接口>
#fakepar
#[
#show figure: set block(breakable: true)
#figure(
tablex(
columns: (auto, auto, 5em, auto),
align: center + horizon,
auto-vlines: false,
repeat-header: true,
header-rows: 1,
map-cells: cell => {
if (cell.x == 3 or cell.x == 0) and cell.y > 0 {
cell.content = {
set align(left)
cell.content
}
}
cell
},
/* --- header --- */
[名称], [宽度], [方向], [描述],
/* -------------- */
colspanx(3)[], text(red)[时钟与复位],
[clock], [1], [input], [时钟信号来自PLL部件的输出],
[reset], [1], [input], [复位信号,高电平同步复位],
colspanx(3)[], text(red)[指令端访存接口],
[inst_sram_en], [1], [output], [RAM使能信号高电平有效],
[inst_sram_wen], [#{inst_ram_date_wid/8}], [output], [RAM字节写使能信号高电平有效],
[inst_sram_addr], [#paddr_wid], [output], [RAM读写地址字节寻址],
[inst_sram_wdata], [#inst_ram_date_wid], [output], [RAM写数据],
[inst_sram_rdata], [#inst_ram_date_wid], [input], [读数据],
colspanx(3)[], text(red)[数据端访存接口],
[data_sram_en], [1], [output], [RAM使能信号高电平有效],
[data_sram_wen], [8], [output], [RAM字节写使能信号高电平有效],
[data_sram_addr], [#paddr_wid], [output], [RAM读写地址字节寻址],
[data_sram_wdata], [64], [output], [RAM写数据],
[data_sram_rdata], [64], [input], [读数据],
colspanx(3)[], text(red)[debug信号供验证平台使用],
[debug_wb_pc], [64], [output], [写回级PC需要将PC从取指级逐级传至写回级],
[debug_wb_rf_wen], [1], [output], [写回级写通用寄存器堆的写使能],
[debug_wb_rf_wnum], [5], [output], [写回级写通用寄存器堆的寄存器号],
[debug_wb_rf_wdata], [64], [output], [写回级写通用寄存器堆的写数据],
),
caption: "myCPU顶层接口信号的描述",
kind:table
)<myCPU顶层接口信号的描述>
]
#fakepar
== 差分测试
在介绍如何对CPU进行差分测试前先了解下如何对数字逻辑电路的进行功能验证。
#fakepar
#figure(
image("image/image-20240111151739011.png", width: 60%),
caption: "功能验证框架"
)<功能验证框架>
#fakepar
数字逻辑电路的功能验证的作用是检查所设计的数字逻辑电路在功能上是否符合设计目标。简单来说就是检查设计的电路功能是否正确。这里所说的功能验证与软件开发里的功能测试的意图是一样的。但是要注意这里使用了“验证”Verification这个词这是为了避免和本领域另一个概念“测试”Test相混淆。在集成电路设计领域测试通常指检查生产出的电路没有物理上的缺陷和偏
差,能够正常体现设计所期望的电路行为和电气特性。
所谓数字电路的功能仿真验证,就是用(软件模拟)仿真的方式而非电路实测的方式进行电路的功能验证。@功能验证框架 给出了数字电路功能仿真验证的基本框架。
在这个基本框架中给待验证电路DUT一些特定的输入激励然后观察DUT的输出结果是否和预期一致。这个过程很类似与程序编程里的OJOnline Judge测试通过输入不同的测试数据得到不同的运行结果比对运行结果进行判断程序的正确性。
对CPU设计进行功能仿真验证时沿用的依然是上面的思路但是在输入激励和输出结果检查方面的具体处理方式与简单的数字逻辑电路设计有区别。对简单数字逻辑电路进行功能仿真验证时通常是产生一系列变化的激励信号输入到被验证电路的输入端口上然后观察电路输出端口的信号以判断结果是否符合预期。对于CPU来说其输入/输出端口只有时钟、复位和I/O采用这种直接驱动和观察输入/输出端口的方式,验证效率太低。
框架采用测试程序作为CPU功能验证的激励即输入激励是一段测试指令序列这个指令序列通常是用汇编语言或C语言编写、用编译器编译出来的机器代码。通过观察测试程序的执行结果是否符合预期来判断CPU功能是否正确。这样做可以大幅度提高验证的效率但是验证过程中出错后定位出错点的调试难度也相应提升了。为了解决这个问题框架在myCPU每条指令写寄存器的时候将myCPU中的PC和写寄存器的信息同实现之前的模拟器的PC以及写寄存器信号进行比对如果不一样那么立刻报错并停止仿真。
= 实验要求
+ 根据本实验提供的五级流水线编程框架,在流水线 CPU 中添加以下指令ADD、SUB、SLL、SLT、SLTU、XOR、SRL、SRA、OR、AND、ADDW、SUBW、SLLW、SRLW、SRLW、SRAW。
+ 通过本实验提供的所有仿真验证测试用例
+ 通过本实验提供的所有板级验证测试用例
+ 撰写实验报告.撰写报告时要求叙述以下内容,以及你对本实验的思考与探索。
#[
#set enum(numbering: "a")
+ 选择需要实现的指令中的一条,按照你自己的理解,逐步介绍其数据通路设计的思路以及实现过程
+ 尝试自己绘制一幅属于自己的数据通路图。(注意:以后数据通路的添加都需要在该图上继续增加,因此打一个好的地基很重要,现在偷懒之后还是需要补的!)
+ TODO增加更多内容
]
= 实验步骤
+ 实验平台的使用
+ 如何上板
+ 如何打开工程文件进行编程
+ 如何使用模拟器进行仿真
+ 如何提交测评
= 思考与探索
+ RISC-V 指令集是定长指令集吗是变长指令集riscv-spec-20191213的第8页有详细描述
+ RV64 和 RV32 的 R 型运算指令是否有区别?(指令格式无区别,但运算数据的长度有区别)
+ SLT 和 SLTU 这类比较指令的实现是为了什么目的,比如是为了实现什么样的目标才有了这类指令?(方便实现大数计算的进位操作)
+ SLL、SRL 和 SRA 这三条指令在 src2 高 63 至 6 位不全为 0 的时候,指令的执行结果是什么?(手册规定只需要看 src2 低 6 位即可,高位忽略)
+ RISC-V 的运算指令有进行运算结果的溢出判断吗,为什么要这样设计?可以对比 MIPS 指令集进行说明(无溢出判断,相比 MIPS 少了 ADDU 等不判断溢出的指令,应该是为了节省指令编码空间,况且溢出判断可以用软件实现)
+ 为什么并不是所有的R型计算指令都有对应的字指令
+ 请问差分测试框架只有这些debug信号就够了吗假如有的指令不写回通用寄存器堆呢这时框架又该如何发现问题即使是跳转指令或是访存指令当时未写回寄存器堆但仍然会影响之后的指令执行结果只是我们发现问题的时间晚了一些但不影响问题的发现
+ 当前处理器采用的是哈佛结构还是冯诺依曼结构?
+ 谈谈你在实验中碰到了哪些问题?又是如何解决的?

View File

@ -1,189 +0,0 @@
# 实现 R 型运算类指令的理想流水线设计实验
## 实验目的
1. 掌握 R 型运算类指令的数据通路
2. 掌握经典单发射五级流水线的设计方法
3. 掌握流水线 CPU 设计的编程基本框架
## 实验原理与实验内容
### 单周期与流水线
#### 结构差异
RISC-V 单周期 CPU 设计实现简单,控制器部分是纯组合逻辑电路,但该 CPU 所有指令执行时间均是一个相同的周期,即以速度最慢的指令作为设计其时钟周期的依据。如图 9.1 所示,单周期 CPU 的时钟频率取决于数据通路中的关键路径(最长路径),所以单周期 CPU 效率较低,性能不佳,现代处理器中已不再采用单周期方式,取而代之的是多周期设计方式。而多周期 CPU 设计中流水线 CPU 设计是目前的主流技术。
![图 9.1 单周期CPU](image/image-20240107161239749.png)
![图 9.2 单周期CPU逻辑划分](image/image-20240107150508299.png)
将电路流水线化的初衷是缩短时序器件之间组合逻辑关键路径的时延,在不降低电路处理吞吐率的情况下提升电路的时钟频率。从电路设计最终的实现形式来看,是将一段组合逻辑按照功能划分为若干阶段,在各功能阶段的组合逻辑之间插入时序器件(通常是触发器),前一阶段的组合逻辑输出接入时序器件的输入,后一阶段的组合逻辑输入来自这些时序器件的输出。
而将电路流水化最困难的地方是决定将单周期 CPU 中的组合逻辑划分为多少个阶段以及各个阶段包含哪些功能。这个设计决策需要结合 CPU 产品的性能含主频、功耗、面积指标以及具体采用的工艺特性来完成。对于初学者而言这部分设计涉及的内容过多、过细、过深因此我们将直接采用经典的单发射五级流水线划分。所划分的五级流水从前往后依次为取指阶段Fetch、译码阶段Decode、执行阶段Execute、访存阶段Memory和写回阶段WriteBack
1. 取指阶段的主要功能是将指令取回。
2. 译码阶段的主要功能是解析指令生成控制信号并读取通用寄存器堆生成源操作数。
3. 执行阶段的主要功能是对源操作数进行算术逻辑类指令的运算或者访存指令的地址计算。
4. 访存阶段的主要功能是取回访存的结果。
5. 写回阶段的主要功能是将结果写入通用寄存器堆。
结合这个流水线阶段的划分方案,我们将单周期 CPU 的数据通路拆分为五段(如图 9.2 所示),并在各段之间加入触发器作为流水线缓存,图 9.3 展示了 RISC-V 流水线的逻辑架构。
![图 9.3 五级流水线CPU](image/image-20240108174346298.png)
所有部件采用同一个系统时钟 clock 来同步,每到来一个时钟 clock各段逻辑功能部件处理完毕的数据会锁存到下一级的流水线缓存中作为下一段的输入数据指令执行进入下一阶段。clock 频率的取决于流水线缓存两级间的最大逻辑延迟。
#### 性能差异
![图 9.4 单周期流水线CPU时空图](image/image-20240107201217987.png)
![图 9.5 理想的五级流水线CPU时空图](image/image-20240107193813519.png)
图 9.4 给出了 RISC-V 单周期 CPU 的时空图,可以看到,每条指令执行需要 5 个时钟周期,即 $\rm 5\Delta t$。1 个时钟周期是 1 个 $\rm \Delta t$ ,也就是每 5 个 $\rm \Delta t$ 可以提交 1 条指令,单周期 CPU 的 IPC 是 0.2。算出运行 n 条指令花费的总时间为 $\rm n\times 5\Delta t$ 。
图 9.5 给出了 RISC-V 理想的五级流水线 CPU 时空图。在理想情况下,当流水线满载运行时,每个时钟周期流水线可以提交 1 条指令,也就是 CPU 的 IPC 为 1。流水线完成 n 条指令的总时间为 $\rm (4+n)\times \Delta t$ 。
当 n 趋近于 $\rm \infty$ 时,相比单周期 CPU 执行 n 条指令花费的时间,五级流水线的加速比 $\rm \lim_{n \to \infty}S_p=\frac{5n\times \Delta t}{(4+n)\times \Delta t}=5$ ,即理想的五级流水线 CPU 的执行效率是单周期 CPU 的 5 倍。
### 数据通路设计
#### 设计的基本方法
经过之前的数字电路设计实验的学习,你应该掌握了数字逻辑电路设计的一般性方法。在计算机结构设计实验中,我们要设计的 CPU 也是一个数字逻辑电路它的设计也应该遵循数字逻辑电路设计的一般性方法。CPU 不但要完成运算,也要维持自身的状态,所以 CPU 这个数字逻辑电路一定是既有组合逻辑电路又有时序逻辑电路的。CPU 输入的、运算的、存储的、输出的数据都在组合逻辑电路和时序逻辑电路上流转我们常称这些逻辑电路为数据通路Datapath。因此要设计 CPU 这个数字逻辑电路,首要的工作就是设计数据通路。同时,因为数据通路中会有多路选择器、时序逻辑器件,所以还要有相应的控制信号,产生这些控制信号的逻辑称为控制逻辑。所以,从宏观的视角来看,设计一个 CPU 就是设计它的“数据通路+控制逻辑”。
![图 9.5 理想的五级流水线 CPU 数据与控制信号传递图](image/image-20240107213744736.png)
根据指令系统规范中的定义设计出“数据通路+控制逻辑”的基本方法是:对指令系统中定义的指令逐条进行功能分解,得到一系列操作和操作的对象。显然,这些操作和操作的对象必然对应其各自的数据通路,又因为指令间存在一些相同或相近的操作和操作对象,所以我们可以只设计一套数据通路供多个指令公用。对于确实存在差异无法共享数据通路的情况,只能各自设计一套,再用多路选择器从中选择出所需的结果。接下来,我们将遵循这个一般性方法,具体介绍如何分析指令的功能以及如何设计出数据通路。图 9.5 展示了 RISC-V 理想的五级流水线 CPU 数据与控制信号传递图。
#### 以 ADD 指令为例
我们来分析一下 ADD 指令需要哪些数据通路部件。
首先,我们需要得到 ADD 这条指令:需要使用这条指令对应的 PC 作为虚拟地址进行虚实地址转换,得到访问指令 SRAM 的物理地址。这意味着需要的数据通路部件有:取指单元、虚实地址转换部件和指令 SRAM。我们先对这部分的数据通路进行实现。
##### 前端
1取指单元
因为实现的是一个 64 位的处理器,所以 PC 的指令宽度是 64 比特。我们用一组 64 位的触发器来存放 PC。后面为了行文简洁在不会导致混淆的情况下我们用 pc 代表这组用于存放 PC 的 64 位触发器。)由于我们的处理器使用到了 SRAM 进行数据的存取,而 SRAM 的特性是一次读数操作需要跨越两个时钟周期,第一个时钟周期向 RAM 发出读使能和读地址,第二个时钟周期 RAM 才能返回读结果。因此我们发送给指令 SRAM 的地址应该是下一拍的 PC也就是 pc_next而目前的实验设计 pc_next 的大小将一直等于 pc+4这里的 4 代表寻址 4 个字节,即一条指令的宽度),因此 pc_next 和 pc 之间只是组合逻辑的关系。
![图 9.6 取指单元](image/image-20240109155256358.png)
pc 的输出将送到指令 SRAM 中用于获取指令,由于我们的指令 SRAM 的地址宽度只有 32 位,因此只有 pc 的低 32 会被使用。目前来看PC 的输入有两个,一个是复位值 0x80000000由于发送给指令 SRAM 的是 pc_next所以 pc 的真正复位值其实是 0x80000000-0x4一个是复位撤销之后 pc_next 的值。
因为取指单元只会对内存进行读操作,因此 inst_sram_en 只要在 reset 无效时使能即可,而 inst_sram_wen 应该恒为低电平。图 9.6 展示了取指单元的结构。
2虚实地址转换
任何时候 CPU 上运行的程序中出现的地址都是虚地址,而 CPU 本身访问内存、I/O 所用的地址都是物理地址,因此我们需要对 CPU 发出的虚拟地址进行转换,使用物理地址进行访存。在实现 RISC-V 的 S 模式之前,目前我们实现的 CPU 的虚拟地址与物理地址之间使用直接映射的方式,即物理地址的值等于虚拟地址的值。因此虚实地址转换部件目前可以先省略。
3指令 RAM
得到取指所需的物理地址后,接下来就要将该地址送往内存。我们采用片上的 RAM 作为内存,并且将 RAM 进一步分拆为指令 RAM 和数据 RAM 两块物理上独立的 RAM 以简化设计。
指令 RAM 输出的 32 位数据就是指令码。本书中我们实现的 CPU 采用小尾端的寻址,所以指令 RAM 输出的 32 位数据与指令系统规范中的定义的字节顺序是一致的,不需要做任何字节序调整。
4指令队列
我们将 Fetch/Decode 之间的流水线缓存称为指令队列。我们将指令队列之前的阶段称为前端,将指令队列之后的阶段称为后端。当取指单元一次取指的数量大于译码单元可以解码的数量时,又或是后端流水线发生暂停时,取指单元可以继续取指,多余的指令可以在指令队列中排队等待,而不用暂停取指。通过指令队列这个部件可以解耦前后端。
![image-20240124134556170](image/image-20240124134556170.png)
如图 9.7 所示,指令队列的实现是一个深度为 depth 的寄存器组,每个寄存器中保存一个叫做 data 的数据包(目前我们需要保存指令的内容以及指令的 PC 这两个数据),宽度应该和 data 的宽度一致。出队指针和入队指针都是一个宽度为 $\rm log_2(depth)$的寄存器。我们使用出队指针指示队列的头部,入队指针指示队列的尾部。由取指单元发送的数据存入入队指针指示的寄存器;出队指针指示的寄存器保存的数据发送到译码单元中。目前我们实现的是理想流水线,因此每一个 clock 我们的入队指针和出队指针都应该加 1发生 reset 时,两个指针都应该置为 0。
##### 后端
前端部分我们已经成功取得指令,接下来我们需要通过译码识别出这条指令为 ADD 指令,并产生相应的控制信号。
5译码单元
译码单元要完成指令译码和源操作数的准备这两个操作,指令译码由译码器完成,源操作数通过访问通用寄存器堆获得。
a译码器
首先我们要明白译码器是如何解码不同指令的。RISC-V 有 6 种指令格式,如图 9.8 所示。译码器根据指令的 opcode 段识别出指令的格式,再进行下一步的译码。
在本实验中,我们只需要实现 R 型的运算指令。图 9.9 展示了 RV64 中所有 R 型运算指令。我们先分析非字指令不难发现R 型运算指令的 opcode 是 0110011再通过 func3 区别各指令的运算类型,其中 ADD 和 SUB、SRL 和 SRA 的 func3 一致,再由 func7 的第 6 位进行区分。而字指令的分析也和非字指令的分析一致。
![图 9.9 R型运算指令](image/image-20240109161753616.png)
R 型运算指令都是三地址指令,每条指令都有两个源操作数以及一个目的操作数。我们记源操作数 1 为 src1源操作数 2 为 src2。
因此译码器中要产生的控制信号如下:
- src1_rensrc1 是否需要读通用寄存器堆
- src1_raddrsrc1 的通用寄存器堆读地址
- src2_rensrc2 是否需要读通用寄存器堆
- src2_raddrsrc2 的通用寄存器堆读地址
- op指令的操作类型
- reg_wen是否需要写回通用寄存器堆
- reg_waddr通用寄存器堆的写地址
接下来我们应该阅读手册,根据手册对指令功能的定义对各控制信号进行赋值。图 9.10 展示了 ADD 指令的定义。
![image-20240124141127010](image/image-20240124141127010.png)
ADD 指令的源操作数都来自通用寄存器堆,因此 src1_ren 和 src2_ren 都为 1src1_raddr 对应指令的 19 至 15 位src2_raddr 对应指令的 24 至 20 位。
ADD 指令需要写回通用寄存器堆,因此 reg_wen 为 1reg_waddr 对应指令的 11 至 7 位。
因为目前我们要实现的指令都在执行单元的 ALU 中进行运算,因此只需要将 op 设置正确就能完成指令的区分。op 的设置有多种方法,下面介绍两种:
1. 简单的方法:
直接将指令从 0 开始按顺序编号,如 ADD 为 1、SUB 为 2、SLL 为 3 ……
2. 稍微复杂一些的方法:
观察指令格式进行 op 的设计,比如非字指令的 opcode 一致,仅 func3 以及 func7 的第 6 位有区别,那么我们可以将这几位进行拼接,由于 ADD 又有 ADD 和 ADDW 的区别,因此我们可以再加一位进行字指令的区分,因此 ADD 的 op 可以设计为 0 0 000。按这种思路SRAW 的 op 就是 1 1 101。
不同的 op 设计对于 FUFunction Unit功能部件内部的解码会有一定的影响我们等下在 ALU 的设计中会进行介绍。
完成了控制信号的生成,接下来我们需要准备源操作数,也就是访问通用寄存器堆,相比 SRAM 这种存储类型,通用寄存器堆的访问都是当拍完成。
![image-20240125134200367](image/image-20240125134200367.png)
图 9.11 展示了译码单元的结构,译码器将从指令队列获得的指令进行译码,产生了相关的控制信号,与寄存器堆读回的源操作数以及指令队列获得的 pc 一起打包成一个 data 数据包发送至下一级流水线缓存。
![image-20240111132343570](image/image-20240111132343570.png)
![image-20240125134816118](image/image-20240125134816118.png)
![image-20240111135906222](image/image-20240111135906222.png)
![image-20240111150330436](image/image-20240111150330436.png)
![image-20240111140744667](image/image-20240111140744667.png)
![image-20240111143829812](image/image-20240111143829812.png)
### 差分测试
![image-20240111151739011](image/image-20240111151739011.png)
![image-20240111160016125](image/image-20240111160016125.png)
![image-20240111165434087](image/image-20240111165434087.png)
## 实验要求
1. 根据本实验提供的五级流水线编程框架,在流水线 CPU 中添加以下指令ADD、SLL、SLT 、SLTU、XOR 、SRL 、OR、AND 、SUB 、SRA
2. 通过本实验提供的所有测试用例
## 实验步骤
1. 如何打开工程文件进行编程
2. 如何使用模拟器进行仿真
3. 如何提交测评
## 思考与探索
1. RISC-V 指令集是定长指令集吗?(否,实现 C 拓展后会有压缩指令)
2. RV64 和 RV32 的 R 型运算指令是否有区别?(指令格式无区别,但运算数据的长度有区别)
3. SLT 和 SLTU 这类比较指令的实现是为了什么目的,比如是为了实现什么样的目标才有了这类指令?(方便实现大数计算的进位操作)
4. SLL、SRL 和 SRA 这三条指令在 src2 高 63 至 6 位不全为 0 的时候,指令的执行结果是什么?(手册规定只需要看 src2 低 6 位即可,高位忽略)
5. RISC-V 的运算指令有进行运算结果的溢出判断吗,为什么要这样设计?可以对比 MIPS 指令集进行说明(无溢出判断,相比 MIPS 少了 ADDU 等不判断溢出的指令,应该是为了节省指令编码空间,况且溢出判断可以用软件实现)

Binary file not shown.

Before

Width:  |  Height:  |  Size: 24 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 32 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 46 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 36 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 50 KiB

View File

@ -1,335 +0,0 @@
#import "../template/template.typ": *
#import "@preview/tablex:0.0.7": *
// Take a look at the file `template.typ` in the file panel
// to customize this template and discover how it works.
#show: project.with(
title: "实验十 实现I型U型运算类指令的理想流水线设计实验",
authors: (
"Xi Lifeng",
),
)
#show math.equation: set text(font: "Linux Libertine")
#set par(justify: true, first-line-indent: 2em)
#show heading: it => {
it
par()[#text(size:0.5em)[#h(0.0em)]]
}
#show list: set list(indent: 1em)
#show enum: set enum(indent: 1em)
// 缩进控制
#let indent = h(2em)
#let noindent = h(-2em)
#let fakepar = par()[#text(size:0.5em)[#h(0.0em)]]
= 实验目的
+ 掌握I型和U型运算类指令的数据通路
+ 掌握在五级流水线中添加I型和U型指令的方法
= 实验原理与实验内容
== I型与U型运算类指令列表
#fakepar
#figure(
tablex(
columns: 33,
align: center + horizon,
repeat-header: true,
header-rows: 1,
auto-lines: false,
vlinex(x:0, start:1), vlinex(x:7, start:1), vlinex(x:12, start:1), vlinex(x:17, start:1), vlinex(x:20, start:1), vlinex(x:25, start:1), vlinex(x:32, start:1),
cellx(align: left, colspan: 6)[31], cellx(align: right)[25], cellx(align: left, colspan: 4)[24], cellx(align: right)[20], cellx(align: left, colspan: 4)[19], cellx(align: right)[15], cellx(align: left, colspan: 2)[14], cellx(align: right)[12], cellx(align: left, colspan: 4)[11], cellx(align: right)[7], cellx(align: left, colspan: 6)[6], cellx(align: right)[0], [],
hlinex(end:32),
colspanx(7, inset:(x: 5em))[funct7], colspanx(5, inset:(x: 2em))[rs2], colspanx(5, inset:(x: 2em))[rs1], colspanx(3)[funct3], colspanx(5, inset:(x: 2em))[rd], colspanx(7, inset:(x: 1.5em))[opcode], [R-type],
hlinex(end:32),
colspanx(12)[imm[11:0]], colspanx(5)[rs1], colspanx(3)[funct3], colspanx(5)[rd], colspanx(7)[opcode], [I-type],
hlinex(end:32),
colspanx(7)[imm[15:5]], colspanx(5)[rs2], colspanx(5)[rs1], colspanx(3)[funct3], colspanx(5)[imm[4:0]], colspanx(7)[opcode], [S-type],
hlinex(end:32),
colspanx(7)[imm[12|10:5]], colspanx(5)[rs2], colspanx(5)[rs1], colspanx(3)[funct3], colspanx(5)[imm[4:1|11]], colspanx(7)[opcode], [B-type],
hlinex(end:32),
colspanx(20)[imm[31:12]], colspanx(5)[rd], colspanx(7)[opcode], [U-type],
hlinex(end:32),
colspanx(20)[imm[20|10:1|11|19:12]], colspanx(5)[rd], colspanx(7)[opcode], [J-type],
hlinex(end:32),
),
caption: "RISC-V指令格式",
kind: table
)<RISC-V指令格式>
#figure(
tablex(
columns: 33,
align: center + horizon,
repeat-header: true,
header-rows: 1,
auto-lines: false,
map-cells: cell => {
if (cell.x == 32) {
cell.content = {
set align(left)
cell.content
}
}
cell
},
vlinex(x:0, start:1), vlinex(x:6, start:1), vlinex(x:7, start:1), vlinex(x:12, start:1), vlinex(x:17, start:1), vlinex(x:20, start:1), vlinex(x:25, start:1), vlinex(x:32, start:1),
cellx(align: left, colspan: 5)[31], cellx(align: right)[26], [25], cellx(align: left, colspan: 4)[24], cellx(align: right)[20], cellx(align: left, colspan: 4)[19], cellx(align: right)[15], cellx(align: left, colspan: 2)[14], cellx(align: right)[12], cellx(align: left, colspan: 4)[11], cellx(align: right)[7], cellx(align: left, colspan: 6)[6], cellx(align: right)[0], [],
hlinex(end:32),
colspanx(12, inset:(x:7em))[imm[11:0]], colspanx(5, inset:(x:2em))[rs1], colspanx(3)[000], colspanx(5, inset:(x:2em))[rd], colspanx(7)[0010011], [ADDI],
hlinex(end:32),
colspanx(12, inset:(x:7em))[imm[11:0]], colspanx(5, inset:(x:2em))[rs1], colspanx(3)[010], colspanx(5, inset:(x:2em))[rd], colspanx(7)[0010011], [SLTI],
hlinex(end:32),
colspanx(12, inset:(x:7em))[imm[11:0]], colspanx(5, inset:(x:2em))[rs1], colspanx(3)[011], colspanx(5, inset:(x:2em))[rd], colspanx(7)[0010011], [SLTIU],
hlinex(end:32),
colspanx(12, inset:(x:7em))[imm[11:0]], colspanx(5, inset:(x:2em))[rs1], colspanx(3)[100], colspanx(5, inset:(x:2em))[rd], colspanx(7)[0010011], [XORI],
hlinex(end:32),
colspanx(12, inset:(x:7em))[imm[11:0]], colspanx(5, inset:(x:2em))[rs1], colspanx(3)[110], colspanx(5, inset:(x:2em))[rd], colspanx(7)[0010011], [ORI],
hlinex(end:32),
colspanx(12, inset:(x:7em))[imm[11:0]], colspanx(5, inset:(x:2em))[rs1], colspanx(3)[111], colspanx(5, inset:(x:2em))[rd], colspanx(7)[0010011], [ANDI],
hlinex(end:32),
colspanx(6, inset:(x:3.5em))[000000], colspanx(6, inset:(x:3.5em))[shamt], colspanx(5, inset:(x:2em))[rs1], colspanx(3)[001], colspanx(5, inset:(x:2em))[rd], colspanx(7)[0010011], [SLLI],
hlinex(end:32),
colspanx(6, inset:(x:3.5em))[000000], colspanx(6, inset:(x:3.5em))[shamt], colspanx(5, inset:(x:2em))[rs1], colspanx(3)[101], colspanx(5, inset:(x:2em))[rd], colspanx(7)[0010011], [SRLI],
hlinex(end:32),
colspanx(6, inset:(x:3.5em))[010000], colspanx(6, inset:(x:3.5em))[shamt], colspanx(5, inset:(x:2em))[rs1], colspanx(3)[101], colspanx(5, inset:(x:2em))[rd], colspanx(7)[0010011], [SRAI],
hlinex(end:32),
colspanx(12, inset:(x:7em))[imm[11:0]], colspanx(5, inset:(x:2em))[rs1], colspanx(3)[000], colspanx(5, inset:(x:2em))[rd], colspanx(7)[0011011], [ADDIW],
hlinex(end:32),
colspanx(7, inset:(x:4em))[0000000], colspanx(5, inset:(x:3em))[shamt], colspanx(5, inset:(x:2em))[rs1], colspanx(3)[001], colspanx(5, inset:(x:2em))[rd], colspanx(7)[0011011], [SLLIW],
hlinex(end:32),
colspanx(7, inset:(x:4em))[0000000], colspanx(5, inset:(x:3em))[shamt], colspanx(5, inset:(x:2em))[rs1], colspanx(3)[101], colspanx(5, inset:(x:2em))[rd], colspanx(7)[0011011], [SRLIW],
hlinex(end:32),
colspanx(7, inset:(x:4em))[0100000], colspanx(5, inset:(x:3em))[shamt], colspanx(5, inset:(x:2em))[rs1], colspanx(3)[101], colspanx(5, inset:(x:2em))[rd], colspanx(7)[0011011], [SRAIW],
hlinex(end:32),
),
caption: "I型运算类指令",
kind: table
)<I型运算类指令>
#figure(
tablex(
columns: 33,
align: center + horizon,
repeat-header: true,
header-rows: 1,
auto-lines: false,
map-cells: cell => {
if (cell.x == 32) {
cell.content = {
set align(left)
cell.content
}
}
cell
},
vlinex(x:0, start:1), vlinex(x:6, start:1), vlinex(x:7, start:1), vlinex(x:12, start:1), vlinex(x:17, start:1), vlinex(x:20, start:1), vlinex(x:25, start:1), vlinex(x:32, start:1),
cellx(align: left, colspan: 19)[31], cellx(align: right)[12], cellx(align: left, colspan: 4)[11], cellx(align: right)[7], cellx(align: left, colspan: 6)[6], cellx(align: right)[0], [],
hlinex(end:32),
colspanx(20, inset:(x:12.4em))[imm[31:12]], colspanx(5, inset:(x:2.1em))[rd], colspanx(7)[0110111], [LUI],
hlinex(end:32),
colspanx(20, inset:(x:12.4em))[imm[31:12]], colspanx(5, inset:(x:2.1em))[rd], colspanx(7)[0010111], [AUIPC],
hlinex(end:32),
),
caption: "U型运算类指令",
kind: table
)<U型运算类指令>
#fakepar
本实验需要在实验九的基础上继续增加两类运算类指令分别是I型以及U型运算指令其指令格式如@I型运算类指令 和@U型运算类指令 所示。
== 以ADDI指令为例
在实验九的实验中已经实现了R型运算类指令的数据通路通过阅读RISC-V手册不难发现本实验需要实现的运算类指令与实验九中实现的指令功能十分相似都是对两个操作数进行运算将结果写入目的寄存器中唯一的区别在于实验九的两个源操作数均来自通用寄存器堆而本实验的源操作数还可能来自指令的立即数字段或是当前指令对应的PC值。
下面以ADDI指令为例介绍如何在实验九的基础上完成数据通路的功能升级。@ADD指令定义 和@ADDI指令定义 展示了手册对ADD和ADDI指令的定义。
#fakepar
#figure(
image("image/image-20240123172829004.png"),
caption: "ADD指令定义"
)<ADD指令定义>
#figure(
image("image/image-20240123172626822.png"),
caption: "ADDI指令定义"
)<ADDI指令定义>
#fakepar
对比手册对ADD和ADDI指令的定义可以发现两者的区别在于ADDI指令将源操作数2替换为了符号拓展的立即数。因此可以复用实验九的大部分数据通路。
#let unitcnt = counter("unitcnt")
#let unitcnt_inc = {
unitcnt.step()
unitcnt.display()
}
#noindent #strong(text(12pt, red)[前端])
前端包括取指单元以及指令队列等部件,只负责指令的取回,因此无需进行修改。
#noindent #strong(text(12pt, red)[后端])
// #noindent #text(fill: blue)[#unitcnt_inc译码单元]
@支持R型运算类指令的译码单元 展示了目前已支持R型运算类指令的译码单元。两个源操作数被打包成src_info数据包发往执行单元。src_info数据包内包含src1_data和src2_data这两个源操作数其被发往执行单元的ALU中进行相应的计算。ALU只会将两个源操作数根据不同的op进行不同的运算输出最终结果。因此大部分R型计算指令的数据通路可以被复用只需将译码单元中src2_data的值的来源从通用寄存器堆替换为经过符号拓展的立即数的值并且还需将译码得到的op值设置的足够精巧这样就可以不必改动后续数据通路并实现数据通路的复用。
综上所述,需要改动的地方有三点:
#[
+ 需要使用指令的立即数字段说明译码器需要译码生成imm信号。
+ 源操作数来源的增加意味着需要实现一个数据选择器使得src2_data可以选择数据来自于通用寄存器堆还是立即数。
+ 对于op的设计我们只需要将ADDI指令的op设置的与ADD的op一致即可使ALU对ADDI指令也执行和ADD指令一样的操作。
]
#fakepar
#figure(
image("../lab09/image/image-20240125134200367.png", width: 90%),
caption: "支持R型运算类指令的译码单元"
)<支持R型运算类指令的译码单元>
#fakepar
#[
#show figure: set block(breakable: true)
#figure(
tablex(
columns: (1em, 10em, 20em),
align: left + horizon,
repeat-header: true,
header-rows: 1,
auto-lines: false,
hlinex(y:0),
hlinex(y:1),
hlinex(y:11),
map-cells: cell => {
if (cell.y == 0) {
cell.content = {
set align(center)
cell.content
}
}
cell
},
[], [信号名], [含义],
colspanx(2)[], text(red)[已经实现的信号],
[], [src1_ren], [src1 是否需要读通用寄存器堆],
[], [src1_raddr], [src1 的通用寄存器堆读地址],
[], [src2_ren], [src2 是否需要读通用寄存器堆],
[], [src2_raddr], [src2 的通用寄存器堆读地址],
[], [op], [指令的操作类型],
[], [reg_wen], [是否需要写回通用寄存器堆],
[], [reg_waddr], [通用寄存器堆的写地址],
colspanx(2)[], text(red)[需要增加的信号],
[], [imm], [立即数]
),
caption: "译码信号",
kind: table
)<译码信号>
]
#fakepar
已实现R型运算指令的处理器译码器产生的控制信号如@译码信号 所示。对于数据选择器的选择端可以使用src2_ren进行控制数据的选择。对于ADD指令而言src2_ren为1此时需要选择来自通用寄存器堆的src2_rdata数据对于ADDI指令而言src2_ren为0此时选择来自译码器的imm数据。因此只需要译码器进行修改使得立即数指令译码得到的src2_ren为0即可。同时译码器需要将指令的立即数字段也就是31至20位进行符号拓展作为imm信号输出到数据选择器的选择端。
#fakepar
#figure(
image("image/image-20240125155402479.png"),
caption: "支持ADDI指令的译码单元"
)<支持ADDI指令的译码单元>
#fakepar
修改完成的译码单元数据通路如@支持ADDI指令的译码单元 所示。数据选择器根据src2_ren选择数据得到src2_data。译码单元将src2_data和从通用寄存器读取到的src1_rdata一起打包成src_info数据包并与pc以及info数据包#footnote()[info数据包内包含op、reg_wen和reg_waddr]一块打包成data数据包发往下一级。
当data数据包来到执行单元后由于ADDI指令的op与ADD指令的op一致ALU会对ADDI指令的src1_data和src2_data同样进行ADD操作得到计算结果reg_wdata。数据继续向后流动经过访存级最后在写回级更新通用寄存器堆。
= 实验要求
+ 在实验九的基础上继续实验使CPU支持@I型运算类指令 和@U型运算类指令 中所列出的所有指令。
+ 通过本实验提供的所有仿真验证测试用例
+ 通过本实验提供的所有板级验证测试用例
+ 撰写实验报告:撰写报告时要求叙述以下内容,以及你对本实验的思考与探索。
#[
#set enum(numbering: "a")
+ 选择@U型运算类指令 中列出的其中一条指令,按照你自己的理解,逐步介绍其数据通路设计的思路以及实现过程。
+ 更新上一实验中绘制完成的数据通路图。
+ 谈谈你对数据通路复用的理解。
]
+ TODO增加更多内容
= 实验步骤
+ 实验步骤参见实验九的实验步骤部分
+ 提醒与建议
#[
#set enum(numbering: "a")
+ 实验的关键在于正确的在译码单元对源操作数进行选择。需要注意的是AUIPC指令的两个操作数分别是当前指令的PC和立即数LUI指令只有一个源操作数但也相当于是0与立即数进行运算。
+ 在chisel中有多种数据选择器类型如Mux、MuxCase、MuxLookup、Mux1H等请参考chisel教程章节选择适合的数据选择器。
+ 当reg_ren为0时建议将reg_raddr置为0防止CPU出现意想不到的状况。
]
= 思考与探索
+ 为什么在RISC-V指令中没有SUBI指令
+ 观察@U型运算类指令 中指令的imm字段为什么imm字段的长度被设计为20位请问这样设计可以和哪些指令搭配使用并发挥什么样的效果
+ 谈谈你在实验中碰到了哪些问题?又是如何解决的?

View File

@ -1,11 +0,0 @@
![image-20240123134117946](image/image-20240123134117946.png)
![image-20240123134317947](image/image-20240123134317947.png)
![image-20240123134347792](image/image-20240123134347792.png)
![image-20240123172829004](image/image-20240123172829004.png)
![image-20240123172626822](image/image-20240123172626822.png)
![image-20240125155402479](image/image-20240125155402479.png)

View File

@ -1,20 +0,0 @@
// The project function defines how your document looks.
// It takes your content and some metadata and formats it.
// Go ahead and customize it to your liking!
#let project(title: "", authors: (), body) = {
// Set the document's basic properties.
set document(author: authors, title: title)
set page(numbering: "1", number-align: center)
set text(10.5pt, font: ("Times New Roman", "SimSun"), lang: "zh")
set heading(numbering: "1.1")
// Title row.
align(center)[
#block(text(weight: 700, 1.75em, title))
]
// Main body.
set par(justify: true)
body
}

Some files were not shown because too many files have changed in this diff Show More