Skip to content

Commit

Permalink
update: 240405 ver1
Browse files Browse the repository at this point in the history
  • Loading branch information
V1CeVersaa committed Apr 5, 2024
1 parent 1c0c0d5 commit a33bbda
Show file tree
Hide file tree
Showing 5 changed files with 208 additions and 10 deletions.
5 changes: 5 additions & 0 deletions docs/Computer Science/Programming Basis/tmux.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
# Tmux Cheatsheet

!!! info "What is tmux?"
tmux’s authors describe it as a terminal multiplexer. Behind this fancy term hides a simple concept: Within one terminal window you can open multiple windows and split-views (called "panes" in tmux lingo). Each pane will contain its own, independently running shell instance (bash, zsh, whatever you're using). This allows you to have multiple terminal commands and applications running side by side without the need to open multiple terminal emulator windows.

76 changes: 75 additions & 1 deletion docs/Computer Science/System/CSAPP/Chapter3.md
Original file line number Diff line number Diff line change
@@ -1 +1,75 @@
# Chapter 3 Machine-Level Representation of Programs
# Chapter 3 Machine-Level Representation of Programs

!!! info "CMU 15-213"
这里使用的 x86-64 汇编的形式是 AT&T 语法,而不是 Intel 语法。AT&T 语法与 Intel 语法的区别在于操作数的顺序,AT&T 语法是 `source, destination`,而 Intel 语法是 `destination, source`。这种描述的语法会用在 Linux 系统之中,但是当我们阅读 Intel 和 Microsoft 的代码与文档的时候,就要换换脑筋了。


??? info "Tools: Disassembler"



??? info "Tools: GNU Debugger/GDB"

## 3.5 Arithmetic and Logical Operations

## 3.6 Control

### 3.6.1 Conditional Codes

除了整数寄存器,CPU 还维护着一组**单个位****条件码/Conditional Code** 寄存器,他们描述了最近一次算术或者逻辑操作的结果。这些条件码寄存器包括:

- **CF/Carry Flag**:进位标志。如果最近一次的操作导致了一个无符号数的溢出,这也就是进位,那么 CF 就会被设置为 1。
- **ZF/Zero Flag**:零标志。如果最近一次的操作的结果为 0,那么 ZF 就会被设置为 1。
- **SF/Sign Flag**:符号标志。如果最近一次的操作的结果为负数,那么 SF 就会被设置为 1。
- **OF/Overflow Flag**:溢出标志。如果最近一次的操作导致了一个有符号数/补码的溢出,那么 OF 就会被设置为 1。

以算数操作 `t = a + b` 举例,设置条件码的操作与逻辑类似于下面的 C 代码:

- CF:`(unsigned) t < (unsigned) a`
- ZF:`t == 0`
- SF:`t < 0`
- OF:`((a < 0 ) == (b < 0)) && ((a < 0) != (t < 0))`

除了 `leaq` 指令类以外——因为 `leaq` 是用来完成地址计算的——所有操作都会**隐式的**设置操作码。对于逻辑操作而言,进位标志与溢出标志都会被设置成 `0`。对于移位操作,进位标志被设置成为最后一个被移出的位,溢出标志设置成 `0`. `inc``dec` 指令会会设置溢出标志和零标志,但是不会改变进位标志。

`cmp``test`指令类会设置条件码,但是不会改变目的寄存器的值。`cmp`指令会计算第二个操作数减去第一个操作数的结果,但是不会存储结果。`test`指令会计算两个操作数的按位与,但是不会存储结果。

### 3.6.2 Accessing the Conditional Codes

条件码一般不会直接读取,常用的使用方法有三种:

- 根据条件码的某种组合,将一个字节设置为 0 或者 1,这类指令就是 `set` 指令。
- 可以条件跳转到程序的某个其他的部分。
- 可以有条件地传送数据。

### 3.6.3 Jump Instructions

`jmp` 指令会导致程序执行切换到程序中的一个全新的位置,这些跳转的目的地通常用一个标号来标识。`jmp` 指令可以是直接跳转,亦即跳转目标是作为指令的一部分编码的,直接在跳转指令后边跟上一个标号作为跳转目标;也可以是间接跳转,亦即跳转目标是从寄存器或者内存之中读出来的。我们还允许有条件的跳转,这就可以对程序进行控制。

### 3.6.4 Implementing Conditional Branches

#### 3.6.4.1 Conditional Control

#### 3.6.4.2 Conditional Move

实现条件操作的传统方法就是通过使用**控制**的条件转移,当条件满足的时候,就沿着一条路径进行运行,不满足就使用另一种路径。这种策略简单而通用,但是在现代计算机上可能很低效,原因就是现代计算机使用**流水线/Pipelining**来获得高性能,流水线中,每条指令的处理都被分为了多个小阶段,每个阶段执行操作的一小个部分,通过重叠连续指令的方法来获得高性能,比如在取一条指令的同时,执行前面一条指令的算数运算。要做到这一点,就需要实现确定要执行的指令序列,这样才能保持整个流水线充满了指令,进而保持最优的性能。

一旦遇到条件跳转了(也就是分支),流水线处理器就会采用**分支预测**,猜测每条跳转指令是否会执行,猜对了还好,猜错了就会遇到招致很严重的惩罚,会浪费大约 15~30 个时钟周期,程序性能会大幅下降。为了减少这种性能损失,除了不断提升分支预测的正确率之外,现代处理器会使用**条件传送**指令,这种指令会根据条件码的值来决定是否传送数据,这样就可以避免分支预测错误的惩罚,并且极大避免随机情况下分支预测的错误。

但是条件传送也不总是好的,下面三种情况会让条件传送变得难办:

- 两个计算都很难办,比如对于:`val = Test(x) ? Hard1(x) : Hard2(x);`,这样我们就要算两个很难算的东西,反而更加浪费时间;
- 计算有可能出错,比如对于:`val = p ? *p : 0;`,这样就有可能会出现段错误;
- 计算有副作用,比如对于:`val = x > 0 ? x*=7 : x+=13;`,这样算出来的结果就不对了。

所以我们的编译器(gcc)当分支的计算比较简单(至少多算一个花费的时间要比预测错误惩罚低)、比较安全并且没有副作用的时候,才会使用条件传送进行优化。

### 3.6.5 Loop

??? info "Aside: Reverse engineer loops"



### 3.6.6 Switch

## 3.7 Procedures
6 changes: 6 additions & 0 deletions docs/Computer Science/System/Lab Record/ZJU System I.md
Original file line number Diff line number Diff line change
Expand Up @@ -325,5 +325,11 @@ if-else 必须在always块中使用,并且输出必须是reg类型。但是在

endmodule
```
=== "RTFSC"

读源码,还没读,咕咕咕

## 7 计数器 & 定时器



129 changes: 120 additions & 9 deletions docs/Computer Science/System/Verilog.md
Original file line number Diff line number Diff line change
Expand Up @@ -47,15 +47,13 @@ Verilog 这种硬件描述语言都基于基本的硬件逻辑之上,因此 Ve

### 2.2 标识符与变量类型

- **`wire`**
用于声明线网型数据。`wire` 本质上对应着一根没有任何其他逻辑的导线,仅仅将输入自身的信号原封不动地传递到输出端。该类型数据用来表示以 `assign` 语句内赋值的组合逻辑信号,其默认初始值是 Z(高阻态)。
**`wire`**用于声明线网型数据。`wire` 本质上对应着一根没有任何其他逻辑的导线,仅仅将输入自身的信号原封不动地传递到输出端。该类型数据用来表示以 `assign` 语句内赋值的组合逻辑信号,其默认初始值是 Z(高阻态)。

`wire` 是 Verilog 的**默认数据类型**。也就是说,对于没有显式声明类型的信号,Verilog 一律将其默认为 `wire` 类型。
`wire` 是 Verilog 的**默认数据类型**。也就是说,对于没有显式声明类型的信号,Verilog 一律将其默认为 `wire` 类型。

- **`reg`**
用于声明在 `always` 语句内部进行赋值操作的信号。一般而言,`reg` 型变量对应着一种存储单元,可以在赋值之间存储数据,其默认初始值是 X(未知状态)。为了避免可能的错误,凡是在 `always` 语句内部被赋值的信号,都应该被定义成 `reg` 类型。
**`reg`**用于声明在 `always` 语句内部进行赋值操作的信号。一般而言,`reg` 型变量对应着一种存储单元,可以在赋值之间存储数据,其默认初始值是 X(未知状态)。为了避免可能的错误,凡是在 `always` 语句内部被赋值的信号,都应该被定义成 `reg` 类型。

如果 `always` 描述的是组合逻辑,那么 `reg` 就会综合成一根线,如果 `always` 描述的是时序逻辑,那么 `reg` 才会综合成一个寄存器/触发器。
如果 `always` 描述的是组合逻辑,那么 `reg` 就会综合成一根线,如果 `always` 描述的是时序逻辑,那么 `reg` 才会综合成一个寄存器/触发器。

### 2.3 运算符

Expand Down Expand Up @@ -103,19 +101,132 @@ module example #(

除了直接使用信号作为敏感变量,Verilog 还支持通过使用 `posedge``negedge` 关键字将电平变化作为敏感变量。其中 `posedge` 对应上升沿,`negedge` 对应下降沿。我们将电平从低电平变成高电平的时刻称为**上升沿**,从高电平变为低电平的时刻称为**下降沿**.

```Verilog
always@(posedge clk) // 上升沿触发
always@(negedge clk) // 下降沿触发
always@(posedge clk or negedge rstn) // 上升沿触发和下降沿复位
always@(posedge clk or posedge rstn) // 上升沿触发和上升沿复位
```
实际上 `reg` 的触发边沿和复位电平是由寄存器本身的电气特性决定的,比如 FPGA 的触发器一般是上升沿触发和高电平复位。但是我们可以通过给 `clk``rstn` 经过非门在连接到 `reg` 的方式实现所谓的下降沿触发和低电平复位(将非门和 `reg` 看成一个整体的话)。


#### 2.5.3 阻塞赋值与非阻塞赋值

- 阻塞赋值

阻塞赋值是顺序执行的,即下一条语句执行前,当前语句一定会执行完毕。这与 C 语言的赋值思想是一致的。阻塞赋值语句使用等号 = 作为赋值符。
阻塞赋值是**顺序执行**,即下一条语句执行前,当前语句一定会执行完毕。这与 C 语言的赋值思想是一致的。阻塞赋值语句使用等号 `=` 作为赋值符。

- 非阻塞赋值

非阻塞赋值属于并行执行语句,即下一条语句的执行和当前语句的执行是同时进行的,它不会阻塞位于同一个语句块中后面语句的执行。非阻塞赋值语句使用小于等于号 <= 作为赋值符。
非阻塞赋值属于**并行执行**语句,即下一条语句的执行和当前语句的执行是同时进行的,它不会阻塞位于同一个语句块中后面语句的执行,并且相互之间没有依赖关系。非阻塞赋值语句使用小于等于号 `<=` 作为赋值符。

#### 2.5.4 `generate` 语句


### 2.6 元件的 Verilog 实现

#### 2.6.x 触发器

最简单的触发器塞了两个寄存器和一根输入的线,在时钟上升沿的时候,将输入的值非阻塞地赋给第一个寄存器,在时钟下降沿的时候,将第一个寄存器的值非阻塞地赋给第二个寄存器。

```verilog
wire data;
reg a, b;
always @(posedge clk) begin
a <= data;
end
always @(negedge clk) begin
b <= a;
end
```

#### 2.6.x+1 使能寄存器

某些寄存器会有一个额外的**使能引脚**EN,只有当 `EN=1` 的时候,寄存器才会载入输入信号,相应的 Verilog 语法如下:

```verilog
reg a;
always @(posedge clk) begin
if(EN) begin
a <= data;
end
end
```

!!! info
我们之前将 `always@(*)` 的时候,`if` 是需要搭配 `else` 使用的,不然会导致环路错误,但是这里不需要,因为 `always@(*)` 综合得到的电路是用 `wire` 搭建的,它只是借用了 `reg``always` 块语法而已。但是 `always@(posedge clk)` 得到的电路使用真实的寄存器搭建的,是不会形成环路问题的。

#### 2.6.x+2 寄存器的初始化

=== "异步初始化"

```verilog
reg a; //高电平异步复位寄存器
always@(posedge clk or posedge rst) begin
if(rst) begin
a <= INTIAL_VALUE;
end else if(wen)begin
a <= data;
end
end

reg b; //低电平异步复位寄存器
always@(posedge clk or negedge rstn)begin
if(~rstn)begin
b <= INTIAL_VALUE;
end else if(wen)begin
b <= data;
end
end
```

这段代码对应的寄存器是异步复位寄存器,这类寄存器除了有时钟输入 `clk`、使能输入 `CE`、数据输入 `data` 之外,还会有一个额外的输入引脚 `rst/rstn`。这个引脚如果输入 `0` 则寄存器会被复位,则该寄存器是低电平异步复位,复位引脚标注为 `rstn`;这个引脚如果输入 `1` 则寄存器会被复位,则该寄存器是高电平异步复位,复位引脚标注为 `rst`。

由于复位操作不需要等待时钟信号为上升沿,只要有复位信号就可以立即复位,所以复位操作是异步的。

=== "同步初始化"

```verilog
reg a;//高电平同步复位寄存器
always@(posedge clk)begin
if(rst)begin
a <= INTIAL_VALUE;
end else if(wen)begin
a <= data;
end
end

reg a;//低电平同步复位寄存器
always@(posedge clk)begin
if(~rstn)begin
a <= INTIAL_VALUE;
end else if(wen)begin
a <= data;
end
end
```

这段对应的是同步复位寄存器,对于高电平同步复位寄存器来说,没有显式的异步复位引脚,只有时钟信号 `clk`,复位信号 `rst` 会在时钟上升沿的时候生效,所以复位操作是同步的。

同步复位寄存器更像是一个带有多路选择器的使能寄存器,还是对于高电平同步复位寄存器来说,使能信号 `CE` 接的是 `rst | wen`,这样只有在复位信号 `rst` 为 `1` 或者写使能信号 `wen` 为 `1` 的时候,寄存器才会被写入。复位信号 `rst` 作为选择子对写入值进行选择,当 `rst` 为 `1` 的时候,选择初始值 `INTIAL_VALUE`,当 `rst` 为 `0` 的时候,选择输入数据 `data`。

=== "FPGA 初始化"

FPGA 的复位信号 `rstn` 由 FPGA 芯片的 C12 引脚引入。当 vivado 将 bitstream 下载到 FPGA 板之后,`rstn` 信号会先保持一段时间的 `0`,使得所有的寄存器可以被充分初始化,然后 `rstn `信号变为 `1` 且一直保持不变,这样所有的寄存器就从初始化阶段进入工作阶段,开始载入数据。

FPGA 进入工作阶段后,我们也可以按开发板的 reset 按钮,让 `rstn` 再次输入 `0`,重新复位所有寄存器的值。

```Verilog
set_property -dict {PACKAGE_PIN C12 IOSTANDARD LVCMOS33} [get_ports rstn]
```

因为 FPGA 板的 `rstn` 在初始化阶段是低电平,所以该信号只能直接用于复位低电平复位寄存器。对于高电平复位的寄存器可以将 `rstn` 取反,然后用 `rst` 作为复位信号。
```Verilog
wire rst;
assign rst = ~rstn;
```

## Chapter 3 SystemVerilog 高级语法

### 3.1 `logic``bit`
Expand Down Expand Up @@ -164,7 +275,7 @@ end
### 3.5 `queue` 队列

??? info "ZJU System 1"
`queue` 语法仅用于仿真,不要用它实现电路,但是作为基本数据结构辅助还是很好的,
`queue` 语法仅用于仿真,不要用它实现电路,但是作为基本数据结构辅助还是很好的,

### 3.6 结构

Expand Down
2 changes: 2 additions & 0 deletions mkdocs.yml
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,7 @@ markdown_extensions:
custom_checkbox: true
- pymdownx.highlight:
anchor_linenums: true
linenums: true
line_spans: __span
pygments_lang_class: true
- pymdownx.arithmatex:
Expand Down Expand Up @@ -124,6 +125,7 @@ nav:
- Git: Computer Science/Programming Basis/Git.md
- GNU Make: Computer Science/Programming Basis/GNU Make.md
- Linux: Computer Science/Programming Basis/Linux.md
- Tmux Cheatsheet: Computer Science/Programming Basis/tmux.md
- Regular Expression: Computer Science/Programming Basis/Regular Expression.md
- MIT Missing Semester: Computer Science/Programming Basis/MIT Missing Semester.md
- Programing language:
Expand Down

0 comments on commit a33bbda

Please sign in to comment.