diff --git a/zh/basic/SoCComputerSystem.md b/zh/basic/SoCComputerSystem.md
index fd53d42..e7f42a0 100644
--- a/zh/basic/SoCComputerSystem.md
+++ b/zh/basic/SoCComputerSystem.md
@@ -452,7 +452,7 @@ ysyxSoC可以通过AXI的`resp`信号传递相关的错误信息.
第二步是依次从各个内存区间中读出数据, 并检查是否与之前写入的数据一致.
可分别通过8位, 16位, 32位, 64位的写入方式重复上述过程.
-:::todo[通过mem-test测试内存访问]
+:::warning[通过mem-test测试内存访问]
在`am-kernels`中编写一个新的程序`mem-test`, 完成上述内存测试功能.
如果检查数据时发现不一致, 就通过`halt()`结束`mem-test`的运行.
@@ -467,7 +467,7 @@ ysyxSoC可以通过AXI的`resp`信号传递相关的错误信息.
:::
-:::question[智能的链接过程]
+:::info[智能的链接过程]
你已经在klib中实现了`printf()`, 但如果没有在`mem-test`中调用`printf()`,
链接后的可执行文件确实不包含`printf()`的代码.
这种智能的链接方式能够在存储器空间有限的情况下避免生成不必要的代码,
@@ -476,7 +476,7 @@ ysyxSoC可以通过AXI的`resp`信号传递相关的错误信息.
:::
-:::comment[真实的内存访问测试程序]
+:::info[真实的内存访问测试程序]
事实上, 上述测试方法并不能较为全面地测试各种访存问题.
真实的内存测试程序通常会采用更复杂的模式来测试内存的读写, 可以覆盖多种故障,
例如[memtest86](https://en.wikipedia.org/wiki/Memtest86).
@@ -542,7 +542,7 @@ SECTIONS {
其中`>`后表示VMA在的存储器区间, `AT>`后表示LMA所在的存储器区间.
上述链接脚本表示, 代码段将链接到MROM空间, 同时也位于MROM空间.
-:::todo[通过bootloader将数据段加载到内存]
+:::warning[通过bootloader将数据段加载到内存]
根据上述内容, 在TRM调用`main()`函数前, 将数据段加载到SRAM, 从而支持后续代码写入全局变量.
如果你的实现正确, 你应该能成功运行`cpu-tests`中除`hello-str`外的所有测试.
@@ -562,7 +562,7 @@ SECTIONS {
支持全局变量的写入操作后, 只要MROM和SRAM能装下的可计算程序, 理论上都能运行.
最后我们来讨论`putch()`的实现.
-:::todo[实现putch()]
+:::warning[实现putch()]
仿照上文的`char-test`, 通过向UART16550写入字符, 实现`putch()`的功能.
实现后运行`hello`程序, 如果你的实现正确, 你将看到NPC输出若干字符.
@@ -571,7 +571,7 @@ SECTIONS {
:::
-:::todo[观察NPC输出的行为]
+:::warning[观察NPC输出的行为]
尝试修改`hello.c`的代码, 增加或减少字符串的长度, 观察NPC输出字符串的行为.
根据你的观察, 你猜测原因可能是什么?
@@ -603,7 +603,7 @@ SECTIONS {
它表示波特率是115200, 字符长度是8位, 不带校验位, 1位停止位.
1. 按需设置中断, 不过NPC目前不支持中断, 因此可不设置
-:::todo[正确实现串口的初始化]
+:::warning[正确实现串口的初始化]
你需要在TRM中添加代码, 设置串口的除数寄存器.
由于ysyxSoC本质上还是一个仿真环境, 没有串口接收端, 也没有电气特性的概念,
因此目前可随意设置上述除数, 不必担心误码率的问题.
@@ -618,7 +618,7 @@ SECTIONS {
为了解决这个问题, 我们需要在向串口写入字符之前, 保证其发送队列一定有空闲位置可以写入.
这可以通过查询串口的状态寄存器实现: 软件可以轮询相关寄存器, 直到确保写入的字符不会丢失为止.
-:::todo[输出前轮询串口的状态寄存器]
+:::warning[输出前轮询串口的状态寄存器]
你需要修改`putch()`的代码, 在输出前先查询串口发送队列的情况.
具体如何查询, 同样地, 你可以RTFM了解UART IP的功能,
也可以RTFSC, 结合UART16550寄存器的RTL实现, 帮助你理解相关的功能.
@@ -653,7 +653,7 @@ U盘的本质就是一块USB接口的flash存储器, 外加一个MCU.
### flash的存储单元
-:::hint[建设中]
+:::tip[建设中]
本小节无编程任务, 感兴趣的同学可以先阅读课件或观看B站录播.
:::
@@ -696,7 +696,7 @@ flash控制器检查该事务的属性, 发现是读事务, 则生成相应的
一段时间后, flash控制器得到从flash颗粒中读出的数据,
便将这些数据作为总线事务的回复传送给CPU, CPU的LSU接收到读结果后, load指令继续执行.
-:::todo[RTFSC理解从flash中读出数据的过程]
+:::warning[RTFSC理解从flash中读出数据的过程]
ysyxSoC包含了上述过程的代码实现, 并且将flash存储空间映射到CPU的地址空间`0x3000_0000~0x3fff_ffff`.
你需要先在`ysyxSoC/perip/spi/rtl/spi_top_apb.v`中定义宏`FAST_FLASH`, 然后尝试结合代码理解上述过程.
@@ -707,7 +707,7 @@ ysyxSoC包含了上述过程的代码实现, 并且将flash存储空间映射到
:::
-:::todo[从flash中读出数据]
+:::warning[从flash中读出数据]
理解从flash中读出数据的过程后, 接下来就可以通过代码测试这一过程了:
1. 在仿真环境中定义一个代表flash存储空间的数组
1. 在仿真环境初始化时, 往上述数组写入若干内容
@@ -781,7 +781,7 @@ SPI驱动程序在与slave通信之前, 先设置`SS`寄存器来选择目标sla
SPI驱动程序可以轮询SPI master的状态寄存器, 当状态标志为"忙碌"时则等待,
直到状态标志为"空闲"为止, 此时可从接收数据寄存器中读出slave的回复.
-:::todo[实现基于SPI协议的位翻转模块]
+:::warning[实现基于SPI协议的位翻转模块]
为了熟悉并测试SPI的基本流程, 我们来编写一个简单的位翻转模块bitrev.
该模块接收一个8位的数据, 然后输出该数据的位翻转结果,
也即, 将输入数据的第0位与第7位交换, 第1位与第6位交换...
@@ -842,7 +842,7 @@ SPI传输过程的细节较多, 你很可能需要RTFM和RTFSC帮助你理解其
:::
-:::todo[通过SPI总线从flash中读出数据]
+:::warning[通过SPI总线从flash中读出数据]
尝试编写一个AM程序, 在其中实现一个原型为`uint32_t flash_read(uint32_t addr)`的函数,
注意这个`flash_read()`函数和上文中提到的同名的DPI-C接口函数不同.
此处的`flash_read()`函数通过驱动SPI master, 读出flash颗粒中起始地址为`addr`的32位内容.
@@ -868,7 +868,7 @@ SPI传输过程的细节较多, 你很可能需要RTFM和RTFSC帮助你理解其
:::
-:::todo[从flash中加载程序并执行]
+:::warning[从flash中加载程序并执行]
尝试将上文提到的`char-test`程序存放到flash颗粒中,
编写测试程序, 通过`flash_read()`将`char-test`从flash读入到SRAM的某个地址中,
然后跳转到该地址执行`char-test`.
@@ -905,7 +905,7 @@ flash存储空间`0x3000_0000~0x3fff_ffff`都映射到
也即, `spi_top_apb.v`模块中的APB端口能接收上述两段地址空间的请求,
你可以通过检查APB的目标地址区分它们.
-:::todo[通过XIP方式访问flash]
+:::warning[通过XIP方式访问flash]
综上所述, 实现XIP方式的大致过程如下:
1. 检查APB请求的目标地址, 若目标地址落在SPI master的地址空间, 则正常访问并回复
1. 若目标地址落在flash存储空间, 则进入XIP模式.
@@ -926,13 +926,13 @@ flash存储空间`0x3000_0000~0x3fff_ffff`都映射到
:::
-:::todo[通过XIP方式执行flash中的程序]
+:::warning[通过XIP方式执行flash中的程序]
将上文提到的`char-test`程序存放到flash颗粒中,
编写测试程序, 跳转到flash中执行`char-test`.
:::
-:::todo[用flash替代MROM]
+:::warning[用flash替代MROM]
确认可以从flash中取指执行后, 我们就可以用flash完全替代MROM来存放第一个程序了.
修改PC的复位值, 使NPC复位后从flash中取出第一条指令.
你还需要进行一系列修改来适配这一改动, 包括...
@@ -944,19 +944,19 @@ flash存储空间`0x3000_0000~0x3fff_ffff`都映射到
:::
-:::question[coremark要跑好久啊]
+:::info[coremark要跑好久啊]
如果允许你动手, 你会如何减少coremark的运行时间呢?
Hint: RTFSC
:::
-:::question[尝试在flash上执行flash_read()函数]
+:::info[尝试在flash上执行flash_read()函数]
你可能会发现错误, 请尝试分析为什么会出现这个错误.
:::
-:::todo[添加学号CSR并输出学号]
+:::warning[添加学号CSR并输出学号]
为了标识不同同学的NPC, 我们可以在CSR的标识寄存器中设置自己的学号.
具体地, 你可以在NPC中添加如下两个CSR:
* `mvendorid` - 从中读出`ysyx`的ASCII码, 即`0x79737978`
@@ -967,7 +967,7 @@ Hint: RTFSC
:::
-:::option[通过中断等待SPI master传输完成]
+:::info[通过中断等待SPI master传输完成]
我们刚才的XIP实现是通过轮询的方式不断查询SPI master的传输是否完成,
事实上, SPI master还支持中断通知模式, 设置控制寄存器的`IE`位后,
SPI master在传输结束后将会发出中断信号,
@@ -1087,7 +1087,7 @@ PSRAM控制器会将接收到的总线事务翻译成发往PSRAM颗粒的命令.
ysyxSoC已经将PSRAM颗粒与PSRAM控制器相连, 但未提供PSRAM颗粒相关的代码,
为了在ysyxSoC中使用PSRAM, 你还需要实现PSRAM颗粒的仿真行为模型.
-:::todo[实现PSRAM颗粒的仿真行为模型]
+:::warning[实现PSRAM颗粒的仿真行为模型]
你需要实现IS66WVS4M8ALL颗粒的仿真行为模型.
你只需要实现SPI Mode的`Qual IO Read`和`Quad IO Write`两种命令即可,
它们的命令编码分别为`EBh`和`38h`, PSRAM控制器也只会向PSRAM颗粒发送这两种命令.
@@ -1127,7 +1127,7 @@ ysyxSoC已经将PSRAM颗粒与PSRAM控制器相连, 但未提供PSRAM颗粒相
如果slave支持QPI协议, 它将提供一个切换到QPI模式的命令,
master可以发送该命令将slave切换到QPI模式, 然后使用QPI协议与其通信.
-:::todo[使用QPI协议访问PSRAM颗粒]
+:::warning[使用QPI协议访问PSRAM颗粒]
尝试为PSRAM颗粒添加QPI模式以及进入QPI模式的命令, 然后修改PSRAM控制器的代码,
使其复位后先通过电路逻辑向PSRAM颗粒发送进入QPI模式的命令,
后续则使用QPI模式与PSRAM颗粒进行通信.
@@ -1140,7 +1140,7 @@ master可以发送该命令将slave切换到QPI模式, 然后使用QPI协议与
有了PSRAM的支持, 我们就可以尝试把数据段分配在PSRAM, 从而支持运行更大的程序.
-:::todo[在ysyxSoC上运行microbench]
+:::warning[在ysyxSoC上运行microbench]
之前我们把数据段和堆区分配在8KB的SRAM中, 而运行microbench所需要的内存大于8KB,
因此有不少子项无法运行. 将数据段和堆区分配在4MB的PSRAM后,
你应该能看到microbench可以成功运行test规模的所有测试.
@@ -1172,7 +1172,7 @@ master可以发送该命令将slave切换到QPI模式, 然后使用QPI协议与
不难想到, 那就是bootloader! 也即, 我们需要扩展bootloader的功能,
将程序的代码和数据全部加载到SRAM中, 然后跳转到SRAM执行.
-:::todo[完整测试PSRAM的访问]
+:::warning[完整测试PSRAM的访问]
扩展bootloader的功能, 把`mem-test`完全加载到SRAM, 然后再执行`mem-test`.
一些提示如下:
1. 你还需要将只读数据段一同加载到SRAM,
@@ -1190,7 +1190,7 @@ SRAM的访问速度虽然快, 但其容量并不大, 无法存放大部分程序
完整测试PSRAM的访问后, 我们也可以考虑让bootload将程序完全加载到PSRAM中,
从而提升程序执行的效率.
-:::todo[通过bootloader将程序加载到PSRAM中执行]
+:::warning[通过bootloader将程序加载到PSRAM中执行]
你已经通过bootloader将`mem-test`加载到SRAM中了, 因此要将程序加载到PSRAM中并不难.
不过为了充分利用SRAM, 我们可以把栈分配在SRAM中, 来提升函数调用和访问局部变量的效率.
@@ -1199,7 +1199,7 @@ SRAM的访问速度虽然快, 但其容量并不大, 无法存放大部分程序
:::
-:::todo[在PSRAM上执行RT-Thread]
+:::warning[在PSRAM上执行RT-Thread]
目前PSRAM的容量已经足够运行RT-Thread了.
尝试通过bootloader将RT-Thread加载到PSRAM中执行.
:::
@@ -1214,7 +1214,7 @@ FSBL(first stage bootloader)和SSBL(second stage bootloader)两部分.
然后SSBL负责将接下来需要运行的程序从flash加载到PSRAM中, 然后跳转到程序并执行.
事实上, SSBL的代码并不大, 因此我们可以让FSBL将SSBL加载到SRAM中执行, 从而让SSBL执行得更快.
-:::todo[实现bootloader的二级加载过程]
+:::warning[实现bootloader的二级加载过程]
按照上述功能实现FSBL和SSBL.
为了得知SSBL在flash中的范围, 你可能需要将SSBL单独放在一个节中,
具体可以参考`start.S`中的相关代码.
@@ -1280,7 +1280,7 @@ DRAM颗粒的存储阵列是一个多维结构, 从逻辑上看由若干个矩
还需要先将已激活的当前行的信息写回存储单元,
这个过程称为预充电(precharge).
-:::comment[DRAM颗粒的物理实现]
+:::info[DRAM颗粒的物理实现]
考虑到物理实现的限制, 走线过长会引入较大延迟.
因此从物理实现的角度来看, DRAM颗粒的一个存储体还会进一步划分成多个子阵列(subarray).
不过这些子阵列的结构和访问方式对颗粒外部是透明的,
@@ -1345,7 +1345,7 @@ SDRAM控制器会将接收到的总线事务翻译成发往SDRAM颗粒的命令,
ysyxSoC已经将SDRAM颗粒与SDRAM控制器相连, 但未提供SDRAM颗粒相关的代码,
为了在ysyxSoC中使用SDRAM, 你还需要实现SDRAM颗粒的仿真行为模型.
-:::todo[实现SDRAM颗粒的仿真行为模型]
+:::warning[实现SDRAM颗粒的仿真行为模型]
你需要实现MT48LC16M16A2颗粒的仿真行为模型.
具体地, 你需要实现SDRAM控制器会发送的命令,
其中PRECHARGE和AUTO REFRESH命令与存储单元的电气特性相关,
@@ -1363,14 +1363,14 @@ ysyxSoC已经将SDRAM颗粒与SDRAM控制器相连, 但未提供SDRAM颗粒相
:::
-:::todo[完整测试SDRAM的访问]
+:::warning[完整测试SDRAM的访问]
在进一步将程序加载到SDRAM中执行之前,
我们还是先通过`mem-test`测试对上述SDRAM颗粒所有存储空间的访问.
完成这个测试需要花费约1小时.
:::
-:::todo[将程序加载到SDRAM中执行]
+:::warning[将程序加载到SDRAM中执行]
让bootloader将程序加载到SDRAM中并执行.
在这之后, 尝试在SDRAM上执行microbench和RT-Thread.
:::
@@ -1428,7 +1428,7 @@ ysyxSoC已经将SDRAM颗粒与SDRAM控制器相连, 但未提供SDRAM颗粒相
[MTA9ASF51272PZ manual]: https://www.micron.com/-/media/client/global/documents/products/data-sheet/modules/parity_rdimm/asf9c512x72pz.pdf
-:::todo[将SDRAM控制器的数据位宽扩展到32位]
+:::warning[将SDRAM控制器的数据位宽扩展到32位]
实例化2个SDRAM颗粒的子模块, 模拟对2个SDRAM颗粒进行位扩展的场景.
为此, 你需要修改以下内容:
* SDRAM总线接口中部分信号的位宽
@@ -1453,7 +1453,7 @@ ysyxSoC已经将SDRAM颗粒与SDRAM控制器相连, 但未提供SDRAM颗粒相
引脚数量的增长与存储容量呈对数关系, 和位扩展相比开销并不大.
但从直觉上看, 字扩展不能直接提升访存带宽, 我们会在后面章节中继续讨论这个问题.
-:::todo[对SDRAM控制器进行字扩展]
+:::warning[对SDRAM控制器进行字扩展]
实例化总计4个SDRAM颗粒的子模块, 其中两对SDRAM颗粒之间进行位扩展,
再对位扩展之后的结果进行字扩展. 你还需要修改SDRAM总线接口和控制器的内部实现.
@@ -1513,7 +1513,7 @@ git pull origin master
:::
-:::todo[通过程序实现NVBoard上的流水灯效果]
+:::warning[通过程序实现NVBoard上的流水灯效果]
你需要进行以下工作:
1. 在GPIO控制器中实现用于驱动LED灯的寄存器.
具体地, 如果你选择Verilog, 你需要在`ysyxSoC/perip/gpio/gpio_top_apb.v`中实现相应代码;
@@ -1527,7 +1527,7 @@ git pull origin master
:::
-:::todo[通过程序读入拨码开关的状态]
+:::warning[通过程序读入拨码开关的状态]
与LED灯类似, 让程序读出读出拨码开关的状态.
你可以在程序中设置一个16位二进制的密码,
程序一开始启动时将不断查询拨码开关的状态,
@@ -1535,7 +1535,7 @@ git pull origin master
:::
-:::todo[通过程序在7段数码管上展示学号]
+:::warning[通过程序在7段数码管上展示学号]
在学号CSR中读出学号, 并将其转化成8个十六进制数, 分别用于驱动8个7段数码管.
:::
@@ -1554,7 +1554,7 @@ NVBoard中的这个除数不支持运行时配置, 但可以通过修改代码
1. 修改`divisor`成员的初值
1. 调用`set_divisor()`函数来设置
-:::todo[将串口的TX引脚接入NVBoard]
+:::warning[将串口的TX引脚接入NVBoard]
你只需要修改NVBoard约束文件, 即可将串口的TX引脚绑定到NVBoard的串口终端上.
关于如何绑定, 你可以参考NVBoard提供的示例.
由于串口控制器已经接入ysyxSoC了, 你无需再修改RTL代码.
@@ -1583,7 +1583,7 @@ git pull origin master
:::
-:::todo[通过NVBoard测试串口的输入功能]
+:::warning[通过NVBoard测试串口的输入功能]
绑定串口的RX引脚并在IOE中添加上述抽象寄存器后, 运行`am-tests`中的按键测试,
测试其能否通过UART的RX端口获得按键信息.
@@ -1610,7 +1610,7 @@ make init
:::
-:::todo[通过串口在RT-Thread中键入命令]
+:::warning[通过串口在RT-Thread中键入命令]
为此, 我们需要让RT-Thread调用刚才实现的IOE功能.
修改BSP中的串口输入功能, 使其在读完内置字符串后, 通过IOE从UART RX中获取字符.
:::
@@ -1627,7 +1627,7 @@ ysyxSoC集成了一个APB总线接口的PS2键盘控制器, 并将其映射到CP
| `0x0` | 8位数据, 读出键盘扫描码, 如无按键信息, 则读出`0` |
| 其他 | 保留 |
-:::todo[让riscv32e-ysyxSoC从NVBoard读取键盘按键]
+:::warning[让riscv32e-ysyxSoC从NVBoard读取键盘按键]
你需要进行以下工作:
1. 实现PS2键盘控制器.
如果你选择Verilog, 你需要在`ysyxSoC/perip/ps2/ps2_top_apb.v`中实现相应代码;
@@ -1652,14 +1652,14 @@ ysyxSoC集成了一个APB总线接口的VGA控制器, 并将其映射到CPU的
NVBoard提供的VGA屏幕分辨率是`640x480`.
不过ysyxSoC没有提供VGA控制器内部的具体实现, 你需要实现它.
-:::todo[复习VGA的工作原理]
+:::warning[复习VGA的工作原理]
如果你在预学习阶段的数字电路实验中没有接触过VGA的相关内容,
我们建议你先完成[相关的实验内容](https://nju-projectn.github.io/dlco-lecture-note/exp/08.html),
从而理解VGA的工作原理, 否则你可能会在设计VGA控制器的时候遇到困难.
:::
-:::todo[让riscv32e-ysyxSoC将像素信息输出到NVBoard]
+:::warning[让riscv32e-ysyxSoC将像素信息输出到NVBoard]
你需要进行以下工作:
1. 实现VGA控制器, 它将不断地将帧缓冲的内容通过VGA的物理接口输出到屏幕上.
如果你选择Verilog, 你需要在`ysyxSoC/perip/vga/vga_top_apb.v`中实现相应代码;
@@ -1677,7 +1677,7 @@ NVBoard提供的VGA屏幕分辨率是`640x480`.
:::
-:::question[更实际的帧缓冲实现方案]
+:::info[更实际的帧缓冲实现方案]
通常, 帧缓冲一般是在内存中分配, 通过配置VGA控制器中的部分寄存器,
可以让VGA控制器从内存中读取像素信息.
@@ -1685,7 +1685,7 @@ NVBoard提供的VGA屏幕分辨率是`640x480`.
:::
-:::todo[通过NVBoard展示游戏]
+:::warning[通过NVBoard展示游戏]
尝试在NVBoard上运行打字游戏和超级玛丽等游戏.
当然, 这应该会非常卡, 我们后续的工作就是在微结构层次优化系统的性能.
:::
@@ -1715,7 +1715,7 @@ git pull origin master
:::
-:::todo[通过RT-Thread运行其他AM程序]
+:::warning[通过RT-Thread运行其他AM程序]
参考PA4阶段1中的选做任务"在RT-Thread上运行AM程序",
尝试在`riscv32e-ysyxsoc`中通过RT-Thread启动超级玛丽等其他AM程序.
:::
@@ -1780,7 +1780,7 @@ ysyxSoC将这段空间映射到CPU的地址空间`0xc000_0000~0xffff_ffff`.
也即, 我们可以充分利用FPGA的可编程性,
通过更新FPGA的比特流文件, 将不同的设备接入到这段地址空间中.
-:::todo[通过ChipLink访问对端芯片的资源]
+:::warning[通过ChipLink访问对端芯片的资源]
ysyxSoC默认未打开ChipLink, 因此你需要在`ysyxSoC/src/SoC.scala`的`Config`对象中
将`hasChipLink`变量修改为`true`, 重新生成`ysySoCFull.v`并仿真即可.
diff --git a/zh/preliminary/CompletePA1.md b/zh/preliminary/CompletePA1.md
new file mode 100644
index 0000000..a0a9add
--- /dev/null
+++ b/zh/preliminary/CompletePA1.md
@@ -0,0 +1,45 @@
+---
+sidebar_position: 6
+---
+# 完成PA1
+
+南京大学"计算机系统基础"课程实验PA是国内首个也是目前唯一一个模拟器教学实验.
+我们将PA引入到"一生一芯"中, 主要有以下考虑:
+* PA承担了系统能力培养的绝大部分任务:
+ 从硬件模拟器, ISA, 运行时环境, 到自制OS, 库函数, 应用程序,
+ 可以让你深刻认识到程序如何在计算机上运行的每一处细节
+ * 如果你选择直接在RTL实现的处理器上构建系统软件, 你首先需要保证你的处理器是对的:
+ 如果你的流水线在某个极端场景下和总线交互有问题, 你的自制OS和复杂应用程序(例如仙剑)都跑不起来.
+ 相对地, 正确实现一个模拟器, 比正确实现RTL要容易得多
+* 模拟器是处理器测试验证的一个重要组件:
+ 我们希望大家可以理解模拟器中的每一处细节, 需要的时候可以自行对它进行定制,
+ 而不是把它当作一个和自己没有关系的外部工具
+
+
+:::info["计算机系统基础"理论课课程资源]
+在完成PA的过程中, 如果你需要补充一些理论课的知识,
+可以参考袁春风老师在中国大学MOOC上开设的课程: [上][mooc1], [中][mooc2], [下][mooc3]
+:::
+[mooc1]: https://www.icourse163.org/course/NJU-1001625001
+[mooc2]: https://www.icourse163.org/course/NJU-1001964032
+[mooc3]: https://www.icourse163.org/course/NJU-1002532004
+
+:::warning[阅读PA讲义中的FAQ(常见问题)]
+在做PA之前, 我们强烈建议大家阅读[PA讲义中的FAQ][PA FAQ], 从而对PA有更多的了解.
+:::
+[PA FAQ]: ../../ics-pa/FAQ.html
+
+:::warning[完成PA1]
+根据PA讲义完成相关内容(ISA选择默认的`riscv32`), 包括如下内容:
+* [基础设施:简易调试器][gdb]
+* [表达式求值][expr]
+* [监视点][watchpoint]
+* 完成PA1的必答题
+直到你看到如下提示框:
+#### flag::温馨提示
+PA1到此结束...
+:::
+
+
diff --git a/zh/preliminary/DigitalCircuitBasicExperiment.md b/zh/preliminary/DigitalCircuitBasicExperiment.md
new file mode 100644
index 0000000..7caad23
--- /dev/null
+++ b/zh/preliminary/DigitalCircuitBasicExperiment.md
@@ -0,0 +1,143 @@
+---
+sidebar_position: 5
+---
+# 数字电路基础实验
+
+
+数字电路是"一生一芯"的前导课程, 我们列出了一些需要大家掌握的知识点,
+大家不仅需要知道它们的概念, 还需要学会使用硬件描述语言来实现其中的电路模块.
+* 信息的二进制编码
+* 组合逻辑设计: 多路选择器, 译码器, 优先编码器, 加法器, 比较器
+* 时序逻辑设计: 时钟, D触发器, 计数器, SRAM和DRAM, 有限状态机, 时序分析
+
+:::info[数字电路学习资料]
+* [数字电路与计算机体系结构][book] 1-5章节
+* [Verilog在线学习网站][hdlbits],推荐边看书边练手
+* [中科大的Verilog OJ平台][ustc verilog oj](需要注册并登录),推荐边看书边练手
+* Verilog高级数字系统设计技术与案例分析
+:::
+[book]: https://pages.hmc.edu/harris/ddca/ddcarv.html
+
+:::info[Chisel学习资料]
+建议按照如下顺序学习:
+1. [Chisel Bootcamp][bootcamp]是一个很不错的chisel教程, 还支持在线运行chisel代码,
+你可以一边编写chisel代码一边学习. 其中
+ * 第1章是scala入门
+ * 第2章是chisel基础
+ * 第3章是scala高级特性和chisel的混合使用
+ * 第4章是FIRRTL后端相关内容
+你需要完成前两章的学习, 同时我们强烈建议你学习第3章.
+第4章和本课程没有直接关系, 可以作为课外阅读材料.
+1. [Chisel Users Guide][users guide]比较系统地整理了chisel的特性, 也是不错的入门教程.
+1. [Chisel小抄][cheatsheet]简明地列出了chisel语言的大部分用法.
+1. [Digital Design with Chisel][chisel textbook]是一本结合数字逻辑设计和Chisel的参考书.
+1. [Chisel API][api]详细地列出了chisel库的所有API供参考.
+
+然后尝试使用Chisel来完成上述数字电路实验,
+你只需要把编译出的verilog代码接入verilator和NVBoard就可以了.
+
+欢迎加入Chisel交流群(微信扫描下方二维码联系助教进群)
+
+
你需要完成"CPU数据通路"之前的大部分实验内容, 除了以下例外
+> * "在线测试"的内容需要加入相关课程才能完成, 目前可以忽略
+> * 计数器和时钟: 由于仿真环境下无法提供精确的时钟,
+> 时钟部分的实验难以准确进行, 因此可作为阅读材料进行了解
+> * 寄存器组及存储器: 讲义中建议通过工具相关的IP核实现存储器,
+> 但仿真环境下不存在这样的IP核, 无法开展实验, 因此可作为阅读材料进行了解
+> * VGA接口控制器实现:对于初学verilog的同学来说项目内容偏多,如果学有余力可以做完
+> * 关于"CPU数据通路"及其后续内容, "一生一芯"将会有所改动, 因此在预学习阶段无需完成 -->
+> 以下部分是**必做题**:
+> * 实验一 选择器
+> * 实验二 译码器和编码器
+> * 实验三 加法器与ALU
+> * 实验六 移位寄存器及桶形移位器
+> * 实验七 状态机及键盘输入
+>
+> 其他内容作为了解可以选做,在预学习部分不作规定。 有了NVBoard之后, 你就可以把它当作FPGA来使用, 用它来实现需要FPGA支持的实验内容.
+
+[dlco]: https://nju-projectn.github.io/dlco-lecture-note/index.html
+
+:::warning[评估电路综合后的时序]
+我们提供了一个基于开源EDA的综合后时序评估项目.
+这个项目通过[开源RTL综合器yosys][yosys]对RTL设计进行综合, 并映射到一个45nm的[开源工艺库nangate45][nangate45],
+然后将综合得到的网表文件和工艺库中的标准单元信息文件输入到[开源静态时序分析工具iSTA][ista]中,
+iSTA将快速评估RTL设计中的时序路径, 并给出时序余量最少的若干条路径, 供RTL设计者参考,
+关于报告如何阅读, 可以参考[这个教程][ista-tutorial].
+通过上述方式, RTL设计者可快速得知RTL设计的时序情况, 并对RTL设计进行快速迭代.
+
+你可以通过以下命令克隆该项目, 具体操作方式请阅读项目中的README.
+```bash
+git clone git@github.com:OSCPU/yosys-sta.git
+```
+
+尝试用上述项目评估你的数字电路实验.
+:::
+:::danger[评估过程中遇到问题]
+如果在运行时遇到bug,可到`yosys-sta`仓库的Issue中报告问题,并提供如下信息:
+* 相应的RTL设计
+* sdc文件
+* yosys生成的网表文件
+* iEDA的版本号, 可通过命令`echo exit | ./bin/iEDA -v`获取
+:::
+[yosys]: https://yosyshq.net/yosys
+[nangate45]: https://mflowgen.readthedocs.io/en/latest/stdlib-freepdk45.html
+[ista]: https://github.com/OSCC-Project/iEDA/tree/master/src/operation/iSTA
+[ista-tutorial]: https://ieda.oscc.cc/tools/ieda-tools/ista.html
+
+:::info[开源EDA工具的局限性]
+当然, 上面的评估项目也不是完美的, 至少从目前来说有以下缺陷:
+* 开源综合器yosys的综合质量不高, 根据开源EDA团队的评估工作,
+ 对于某RTL设计, yosys综合出的标准单元面积是商业综合器的1.8倍,
+ 商业综合器综合出的电路频率是153.8MHz, 而yosys综合出的电路频率只有52MHz
+* nangate45是一个面向学术研究的工艺库, 其中标准单元的数量和质量也与商业工艺库有一定差距
+* nangate45不能用于流片, 没有工厂将其用于产线中
+
+不过, 在综合后时序评估这一场景中, 上述缺陷不会造成明显的影响:
+即使yosys的综合质量不高, 我们也可以通过综合结果的相对提升, 来指导RTL优化的方向.
+:::
+
+:::info[所以学习"一生一芯"还需要FPGA吗?]
+基本上不需要了:
+* 从准确度来说, yosys的综合流程是面向ASIC设计的, 相比于FPGA流程, 其原理和报告的准确度都更适合"一生一芯".
+* 从时间来说, FPGA的主要作用是仿真加速, 也就是说, 如果仿真任务并不需要花费很长时间来完成, 使用FPGA的优势并不明显.
+ 事实上, 从仿真流程来看, 当以下不等式成立时, FPGA的优势才能体现出来:
+ ```
+ FPGA_syn_time + FPGA_impl_time + FPGA_run_time < verilator_compile_time + verilator_run_time
+ ```
+ `FPGA_syn_time + FPGA_impl_time`通常达到小时量级, 而`verilator_compile_time`通常能在数分钟内完成,
+ 因此, 只有当`verilator_run_time`达到小时量级, 上述不等式才有可能成立.
+ 不过在"一生一芯"的学习中, 你很难遇到需要小时量级的时间才能完成的仿真任务.
+ 而当你遇到这样的任务时, 我们也会对FPGA的评估过程提出更高的要求.
+ 我们会在后续讲义中继续讨论这个问题.
+* 从调试难度来说, FPGA的调试手段很有限, 只能在时间和空间均受限的条件下抓取底层的波形信息;
+ 相反, 软件仿真则灵活很多, 我们可以借助很多软件方法来从多方面提升调试的效率.
+:::
\ No newline at end of file
diff --git a/zh/preliminary/HowToAskSmartQuestion.md b/zh/preliminary/HowToAskSmartQuestion.md
index 6f59278..89342d9 100644
--- a/zh/preliminary/HowToAskSmartQuestion.md
+++ b/zh/preliminary/HowToAskSmartQuestion.md
@@ -5,26 +5,24 @@ sidebar_position: 1
[ysyx-forum]: https://ysyx.oscc.cc/forum/
-:::tip[填写通识问卷]
+:::warning[填写通识问卷]
在开始预学习的第一个任务之前,请大家认真阅读官网[《报名参与》](https://ysyx.oscc.cc/signup/)和[《常见问题》](https://ysyx.oscc.cc/project/faq.html)两部分内容,并填写[《“一生一芯”通识问卷》](https://www.wenjuan.pub/s/UZBZJv6ci37/#)。**注意:通识问卷可以重做很多次,只有达到100分才能申请入学答辩。**
:::
-
-:::tip[阅读"提问的智慧"和"别像弱智一样提问", 编写读后感]
+:::warning[阅读"提问的智慧"和"别像弱智一样提问", 编写读后感]
你在预学习中的第一个任务, 就是现在仔细阅读[提问的智慧][how to ask]和[别像弱智一样提问][stop ask]这两篇文章,
结合自己过去提问和被提问的经历,
写一篇不少于800字的读后感, 谈谈你对"好的提问"以及"通过STFW和RTFM独立解决问题"的看法.
->
+
我们设置这道题并不是为了故意浪费大家的时间, 也不是为了禁止大家提出任何问题,
而是为了让大家知道"什么是正确的". 当你愿意为这些"正确的做法"去努力,
并且尝试用专业的方式提出问题的时候, 你就已经迈出了成为"成为专业人士"的第一步.
:::
-
[how to ask]: https://github.com/ryanhanwu/How-To-Ask-Questions-The-Smart-Way/blob/master/README-zh_CN.md
[stop ask]: https://github.com/tangx/Stop-Ask-Questions-The-Stupid-Ways/blob/master/README.md
-:::tip[大佬三连: STFW, RTFM, RTFSC]
+:::warning[大佬三连: STFW, RTFM, RTFSC]
尝试在上述文章中寻找并理解这三个缩写的含义.
->
+
你可能会觉得字母F冒犯了你, 但事实上这个字母的含义从来都不是重点,
它只是反映出这三个缩写背后的传奇色彩而更容易被大家记住而已.
例如, RTFSC起源于Linux之父Linus Torvalds在1991年4月1日回复邮件中的第一句话,
@@ -35,18 +33,19 @@ sidebar_position: 1
:::
[minix]: https://cacm.acm.org/magazines/2016/3/198874-lessons-learned-from-30-years-of-minix/fulltext
-:::warning[与其说是学会提问, 倒不如说是学会不提问]
+
+:::danger[与其说是学会提问, 倒不如说是学会不提问]
很多同学不多不少都会抱有这样的观点:
我向大佬请教, 大佬告诉我答案, 我就学习了.
->
+
但你是否想过, 将来你进入公司, 你的领导让你尝试一个技术方案;
或者是将来你进入学校的课题组, 你的导师让你探索一个新课题.
你可能会觉得: 到时候身边肯定有厉害的同事, 或者有师兄师姐来带我.
但实际情况是, 同事也要完成他的KPI, 师兄师姐也要做他们自己的课题,
没有人愿意被你一天到晚追着询问, 总有一天没有大佬告诉你答案, 你将要如何完成任务?
->
+
如果你觉得自己搞不定, 你很可能缺少独立解决问题的能力.
->
+
但幸运的是, 这种能力是可以训练出来的.
你身边的大佬之所以成为了大佬, 是因为他们比你更早地锻炼出独立解决问题的能力:
当你还在向他们请教一个很傻的问题的时候, 他们早就解决过无数个奇葩问题了.
@@ -57,7 +56,7 @@ sidebar_position: 1
(当然一些由于框架代码缺陷导致的问题除外).
:::
-:::warning[我是一个很享受帮助别人的大佬]
+:::danger[我是一个很享受帮助别人的大佬]
以南京大学令人闻风丧胆的PA实验为例, 我们见过太多这样的情况了:
每年学期开始的时候, 总有那么几位上一届的热心师兄在群里无微不至地解答新手同学的各种提问,
这些新手同学也确实在残酷的PA训练中感受到热心师兄为他们遮风挡雨的温暖.
@@ -70,21 +69,21 @@ sidebar_position: 1
也许是他们突然觉得自己给新手同学提供的帮助其实帮不了他们.
但不管怎样, 那些新手同学已经无法独立完成PA的训练了,
因为他们将会面对比学期开始更困难的问题.
->
+
所以, 我们并不否认你在帮助同学的时候给你带来的成就感,
但我们认为, 有很多更严肃的问题需要思考:
一个同学来提问, 如果说这个问题只是表象的话, 你能摸索出更本质的问题吗?
->
+
当一个同学不来询问你就无法解决问题的时候, 你之前所做的真的是在帮助他吗?
->
+
更重要地, 你能为这些同学的将来负责吗?
->
+
如果要问"你希望这位同学成长为什么样子", 我想大家的目标都是一致的:
希望他将来能成为可以独当一面的专业人士.
-但同时你也需要认识到学习的规律: 这是需要长期接受专业训练的.
+但同时你也需要认识到学习的规律: 这是需要长期接受专业训练的
如果你仅仅把问题的答案告诉他, 他就可以成为专业人士,
那该如何对得起长年累月奋斗在一线的广大资深工程师们流下的汗水?
->
+
因此, 你每一次直接把答案告诉他,
直接帮他们解决问题, 都是在剥夺他接受专业训练的机会.
相反, 如果你真的希望能帮助他, 你可以尝试在不影响他训练的情况下指出他缺少的观念和技能,
@@ -93,8 +92,8 @@ sidebar_position: 1
这对你和他来说都不容易, 但学习本身就是一件需要付出的事情:
如果你让他很方便地获得问题的答案, 那他就不能从解决这个问题的过程中收获应有的训练.
:::
-
-:::info[提问渠道]
+:::info[提问渠道
+]
* 群里沟通(推荐),比较积极的同学有希望发展为助教
* 私聊助教(助教也有其他工作任务可能无法及时回复)
:::
diff --git a/zh/preliminary/LinuxSystemInstallationAndBasicUsage.md b/zh/preliminary/LinuxSystemInstallationAndBasicUsage.md
new file mode 100644
index 0000000..19f7d6d
--- /dev/null
+++ b/zh/preliminary/LinuxSystemInstallationAndBasicUsage.md
@@ -0,0 +1,117 @@
+---
+sidebar_position: 2
+---
+# Linux系统安装和基本使用
+
+:::warning[安装一个Linux操作系统]
+我们复用PA讲义的内容, 请大家根据[PA0][pa0]安装Linux操作系统.
+:::
+[pa0]: ../../../ics-pa/PA0.html
+
+:::warning[获取"一生一芯"框架代码]
+当你阅读PA0讲义, 并进行到获取PA框架代码的部分, 将会有提示框请你返回到此处的讲义内容.
+
+首先请你在github上添加一个ssh key, 具体操作请STFW.
+然后通过以下命令获取"一生一芯"的框架代码:
+```
+git clone -b master git@github.com:OSCPU/ysyx-workbench.git
+```
+获取后, 你就可以回到PA讲义的相应位置, 继续阅读了.
+不过你还需要注意:
+* 请把`ysyx-workbench`作为PA讲义中的项目目录, 即将PA讲义中的`ics2022`看成是`ysyx-workbench`
+* 修改`ysyx-workbench/Makefile`中的学号和姓名时, 学号可先不修改, 等到大家完成预学习之后再修改
+
+这种来回跳转的做法可能会给你带来一些麻烦, 但我们之所以这样做, 是希望把文档看作代码来管理:
+我们希望做到类似`"一生一芯"讲义调用PA讲义`的效果,
+因此我们在PA讲义中尽可能少地提到"一生一芯", 而把"一生一芯"的相关内容都放到"一生一芯"本身的讲义中.
+如果不遵守这条原则, 不仅会使我们维护讲义时感到困难, 而且大家阅读讲义时也不知道应该到哪里寻找相关的内容.
+:::
+
+:::danger[安装系统是独立解决问题的最简单的训练]
+如果你是第一次安装并使用Linux, 你可能会遇到非常多的问题.
+不用担心, 因为全世界都在使用Linux, 因此你遇到的问题, 很大概率别人也遇到过,
+在互联网上搜索关键字, 很大概率就能找到解决方案.
+:::
+
+:::danger[树立正确的价值观, 接受最大程度的训练]
+事实上, 你总能耍些小聪明来绕过这些训练, 例如
+* 直接使用别人提供的虚拟机镜像或者一键安装配置的脚本, 瞬间完成本小节的任务
+* 在网上搜到了所谓的PA攻略, 心里暗暗窃喜
+* 找大佬要到了关键代码或者往期代码, 美言曰学习
+
+有同学会觉得, "凭什么不能参考别人的攻略和代码? 我都看懂了啊!"
+但从训练的角度来说, "看懂"和"自己独立完成"的效果是天差地别的
+你知道大佬为什么要这样做, 而不是那样做吗?
+大佬踩过了多少坑, 这些坑背后是什么道理, 你能看出来吗?
+相比于这些几乎躺倒就可以得到的"好处", 你更应该去想一下, 这会让你失去什么.
+"能抄对也是本事"这种主动降低自己要求的观点, 并不符合我们所提倡的价值观.
+
+事实上, 如果你是初学者, 这些小聪明会给你的训练带来毁灭性的伤害:
+* 你参考了这些在这个阶段不应该参考的内容, 它们就会成为你学习的上界,
+ 因为你几乎不清楚它们哪里不好, 从而使得你几乎不会做得比它们更好
+* 而且这会让你产生"我学得很好, 我善于学习"的错觉, 你就不会去尝试, 也不知道如何才能做得更好
+* 更严重地, 你现在得不到应有的训练, 但将来总要面对那些没有攻略或者参考代码的新问题, 你自然也就无法解决它们
+
+但说实话, 助教团队几乎不存在有效的方法来禁止大家耍这些小聪明.
+其实, 这更多是需要大家发自内心去认可和执行的
+当你搜到了一些所谓攻略的时候, 你心里应该想到"阅读它们会降低训练的效果",
+然后你主动拒绝它们的诱惑, 坚持自己独立完成实验内容.
+这和大家自觉遵守学术诚信是很类似的:
+你心里清楚考试作弊是不对的, 然后自发地独立完成考试题目.
+
+事实上, 学术诚信远远不止考试不作弊,
+我们推荐大家阅读一下[MIT对学术诚信的诠释][integrity],
+尤其是[关于写代码的学术诚信][coding integrity].
+在这里, 我们引用其中的一些示例说法(当然我们还是建议大家阅读原版的英文描述):
+* 当讲义要求"实现X"的时候, 你必须在不复用任何外部资源的情况下独立实现X
+* 分享代码和交换测试用例都是不合适的
+
+你也许会觉得这些奇葩的要求颠覆了你的三观,
+但这些准则归根到底是为了让你可以获得预期的训练效果:
+不要忘记你是在通过学习提升自己的能力, 而不是交付项目.
+如果你能够坚持下来, 你就能成为真正的专业人士.
+:::
+[integrity]: http://integrity.mit.edu/
+[coding integrity]: http://integrity.mit.edu/handbook/writing-code
+
+:::info[我能否使用其它Linux发行版?]
+我们不会强制规定必须使用什么样的Linux发行版,
+因此经常有同学提出类似"使用xxx发行版是否会对实验造成影响"的问题.
+首先请阅读PA0中关于发行版的提示,
+除此之外, 我们大概率无法给出确切的答复, 因为我们大概率没用过.
+
+事实上, 如果你决定使用其它发行版, 你就应该做好解决新问题的准备.
+:::
+
+:::info[Linux零基础用户入门]
+我们给大家推荐由中国科学技术大学 Linux 用户协会发起的[Linux101][Linux101], 大家可以挑选自己感兴趣的部分阅读.
+:::
+
+[Linux101]: https://101.ustclug.org/
+
+:::info[命令行的艺术]
+[The Art of Command Line][cmd]这篇文章总结了很多常用的命令行工具, 也值得大家去阅读.
+:::
+[cmd]: https://github.com/jlevy/the-art-of-command-line
+
+
+
+:::warning[学习Linux基本使用]
+我们给大家墙裂推荐MIT的Linux工具使用系列课程: [The Missing Semester of Your CS Education][missing]中文版.
+通过学习这些课程, 你将会了解到如何使用Linux中的工具来方便地完成各种任务,
+这将大大提升你的工作效率.
+
+**必做题**:
+* 课程概览与shell
+* Shell工具和脚本
+* 编辑器 (Vim)
+* 数据整理
+* 命令行环境
+* 版本控制(Git)
+
+包括阅读讲义并完成课后习题.
+此外, [B站上][missing bilibili]有这门公开课的视频供大家参考.
+:::
+
+[missing]: https://missing-semester-cn.github.io/
+[missing bilibili]: https://www.bilibili.com/video/BV1x7411H7wa
diff --git a/zh/preliminary/RecapCLanguage.md b/zh/preliminary/RecapCLanguage.md
new file mode 100644
index 0000000..0613b7a
--- /dev/null
+++ b/zh/preliminary/RecapCLanguage.md
@@ -0,0 +1,39 @@
+---
+sidebar_position: 3
+---
+# 复习C语言
+
+C语言几乎是开发系统软件的不二选择,
+而且考虑到参加"一生一芯"的不少同学就读的是非计算机专业,
+C语言对大家来说学习的门槛也比较低.
+大家需要掌握如下内容: 递归, 指针, 链表,
+并且能够独立写出正确的程序(而不是在百度上搜一个所谓的示例代码).
+
+:::info[一些推荐的C语言学习资料]
+* [Linux C编程一站式学习][linux c]
+* [The C programming language (2nd Edition)][c]:
+ 真正的C语言之父是这本书的作者[Dennis M. Ritchie][ritchie], 而不是谭浩强
+* [C Coding Standard][c coding standard]
+* [SEI CERT C Coding Standard][cert c]
+* [Learn C the hard way]中文版
+:::
+[linux c]: http://akaedu.github.io/book/
+[c]: http://cslabcms.nju.edu.cn/problem_solving/images/c/cc/The_C_Programming_Language_%282nd_Edition_Ritchie_Kernighan%29.pdf
+[c coding standard]: https://users.ece.cmu.edu/~eno/coding/CCodingStandard.html
+[cert c]: https://wiki.sei.cmu.edu/confluence/display/c/SEI+CERT+C+Coding+Standard
+[ritchie]: http://en.wikipedia.org/wiki/Dennis_Ritchie
+[Learn C the hard way]: https://wizardforcel.gitbooks.io/lcthw/content/preface.html
+
+:::info[还需要掌握一些简单的C++基础]
+verilator会编译出C++文件, 但你并不需要了解复杂的C++语法,
+你只需要了解一些类(class)的基本使用方法就可以了.
+单从这一点来看, 网上的很多资料都可以满足你的需求.
+:::
+
+:::warning[C语言入门必做题]
+[Learn C the hard way] 练习0到练习18, 练习32,练习33,练习42,练习44
+需要完成编程算法以及附加题.
+* 这是入学答辩的一部分,如果你在某些地方被卡住,可以通过RTFW或咨询助教
+* 参考资料使用上文提到的学习资料
+:::
+[Learn C the hard way]: https://wizardforcel.gitbooks.io/lcthw/content/preface.html
diff --git a/zh/preliminary/SetupVerilatorSimulationEnvironment.md b/zh/preliminary/SetupVerilatorSimulationEnvironment.md
new file mode 100644
index 0000000..3ad1a91
--- /dev/null
+++ b/zh/preliminary/SetupVerilatorSimulationEnvironment.md
@@ -0,0 +1,285 @@
+---
+sidebar_position: 4
+---
+# 搭建verilator仿真环境
+
+verilator是一款开源的verilog仿真工具, 在"一生一芯"项目中,
+你将会使用它来进行RTL功能仿真, 从而验证你编写的RTL代码.
+
+框架代码默认提供了一个`npc`目录,
+这里的`npc`是`New Processor Core`的含义, 将来大家就会在这个目录下设计自己的处理器.
+不过为了设置一个环境变量`NPC_HOME`, 你需要运行如下命令:
+> ```bash
+> cd ysyx-workbench
+> bash init.sh npc
+> ```
+这个环境变量会在将来使用.
+`npc`目录下有一些简单的文件:
+```
+ysyx-workbench/npc
+├── csrc
+│ └── main.cpp
+├── Makefile
+└── vsrc
+ └── example.v
+```
+目前这三个文件几乎都是空文件,
+在这一小节中, 我们将会引导大家搭建verilator仿真环境,
+并编写两个简单的数字电路模块来进行仿真.
+
+:::danger[竟然连仿真框架都没有, 真寒酸]
+我们之所以设置这部分的实验内容, 是为了让大家知道,
+项目里面的所有细节都是和大家有关系的.
+
+在以前的课程实验当中, 大家不多不少都会觉得,
+框架理所应当是由助教来提供的, 做实验就是在指定的地方写上相应的代码,
+其它都是无关的代码/文件, 大家不需要关心.
+事实上, 这样的实验方案是很危险的, 这不仅不能将你训练成真正的专业人士,
+反而会使得你无法在真正的项目中存活下来:
+1. 遇到系统性的bug, 肯定调不出来, 因为连调用你代码的模块你都觉得跟你没关系,
+更别说可以清晰地认识到整个项目的架构和其中的每一处细节了
+1. 离开了讲义, 就什么都做不了, 因为你总是在等别人像这些讲义一样清楚地告诉你接下来应该做什么怎么做,
+而不是站在项目的角度去切实分析现在应该做什么
+
+一个很现实的场景是, 以后你到了企业或者进入课题组, 不会再有讲义和框架代码照顾你,
+你的老板说一句"来试试verilator", 你就要自己把verilator跑起来,
+写一份使用报告, 在下周的组会上给老板汇报工作.
+
+因此, 我们希望给大家提供更真实的训练: 给出一个目标,
+让大家学会对目标进行分解, 并通过自身的技能一步步达成这个目标.
+搭建verilator仿真框架其实是一个很容易实现的目标, 因此作为一项小试牛刀的训练, 也是非常合适的.
+:::
+:::tip[如果你想使用Chisel]
+请运行以下命令:
+```bash
+cd ysyx-workbench
+bash init.sh npc-chisel
+```
+上述命令会将`npc`目录中的文件换成一个Chisel开发环境, 具体介绍可以阅读其中的`README.md`.
+
+本小节主要关注verilator的使用方法, 即使你想用Chisel进行开发,
+我们也建议你按照讲义内容使用verilog先走一遍流程.
+:::
+## STFW + RTFM
+
+事不宜迟, 我们马上开始.
+
+:::warning[认识verilator]
+你很可能是第一次听说过verilator这个工具, 这是很正常的.
+然后你就会想进一步了解verilator的各种信息, 这也是很正常的.
+但如果你的第一反应是去问人, 这就不恰当了.
+事实上, verilator这个工具在仿真领域已经非常有名, 以至于你可以很容易在互联网上搜索到它的相关信息.
+你需要通过STFW找到它的官方网站, 然后阅读一下相关的介绍.
+:::
+找到官网并且阅读过相关介绍之后, 接下来就是通过运行来体会一下了.
+不过在这之前, 我们还需要安装它.
+
+:::warning[安装verilator]
+在官网中找到安装verilator的步骤, 然后按照从git安装的相应步骤进行操作.
+我们之所以不采用`apt-get`安装, 是因为其版本较老.
+此外, 为了统一版本, 你需要通过git安装`5.008`的版本.
+为此, 你还需要进行一些简单的git操作, 如果你对此感到生疏, 你可能需要寻找一些git教程来学习.
+另外, 你最好在`ysyx-workbench/`之外的目录进行这一操作,
+否则git将会追踪到verilator的源代码, 从而占用不必要的磁盘空间.
+
+安装成功后, 运行以下命令来检查安装是否成功,以及版本是否正确。
+```bash
+verilator --version
+```
+:::
+
+:::warning[运行示例]
+verilator手册中包含一个C++的示例, 你需要在手册中找到这个示例, 然后按照示例的步骤进行操作.
+:::
+## 示例: 双控开关
+
+手册中的示例非常简单, 甚至算不上是一个真正的电路模块.
+接下来我们编写一个真正的电路模块, 双控开关, 来进行测试.
+编写如下的verilog代码:
+```verilog
+module top(
+ input a,
+ input b,
+ output f
+);
+ assign f = a ^ b;
+endmodule
+```
+双控开关的一个应用是通过两个开关(`a`和`b`)联合控制同一盏灯的亮灭(`f`).
+和手册中的示例不同, 这个模块有输入输出端口.
+为了驱动输入端口, 并从输出端口获得结果,
+我们需要对C++文件中的`while`循环进行修改:
+```c
+// 以下为伪代码
+
+#include
+#include
+#include
+
+while (???) {
+ int a = rand() & 1;
+ int b = rand() & 1;
+ top->a = a;
+ top->b = b;
+ top->eval();
+ printf("a = %d, b = %d, f = %d\n", a, b, top->f);
+ assert(top->f == (a ^ b));
+}
+```
+在一次循环中, 代码将会随机生成两个1比特信号, 用来驱动两个输入端口,
+然后通过`eval()`函数更新电路的状态, 这样我们就可以读取输出端口的值并打印.
+为了自动检查结果是否正确, 我们通过`assert()`语句对输出结果进行检查.
+
+:::warning[对双控开关模块进行仿真]
+尝试在verilator中对双控开关模块进行仿真.
+由于顶层模块名与手册中的示例有所不同, 你还需要对C++文件进行一些相应的修改.
+此外, 这个项目没有指示仿真结束的语句, 为了退出仿真, 你需要键入`Ctrl+C`.
+:::
+
+:::tip[上述代码是什么意思?]
+如果你不知道应该如何修改, 说明你还不太熟悉C程序的编写,
+你应该先回到上一小节复习C语言.
+:::
+
+:::warning[理解RTL仿真的行为]
+阅读verilator编译出的C++代码, 然后结合verilog代码, 尝试理解仿真器进行仿真的时候都发生了什么.
+:::
+## 打印并查看波形
+
+查看波形文件是RTL调试的常用手段之一.
+verilator支持波形的生成, 你可以通过开源的波形查看工具GTKWave来查看波形.
+
+:::warning[生成波形并查看]
+verilator手册中已经介绍了波形生成的方法, 你需要阅读手册找到相关内容,
+然后按照手册中的步骤生成波形文件, 并通过
+```bash
+apt-get install gtkwave
+```
+安装GTKWave来查看波形.
+:::
+
+:::tip[手册这么多内容, 怎么找?]
+尝试一下键入`Ctrl+F`.
+:::
+
+:::danger[不要长时间生成波形]
+波形文件一般会占用较多的磁盘空间, 长时间生成波形可能会导致磁盘空间耗尽, 从而导致系统崩溃.
+:::
+
+:::tip[生成FST格式的波形]
+FST格式的波形文件大致是VCD格式的1/50, 但它仅能被GTKWave支持.
+尽管如此, 我们还是推荐你使用它.
+:::
+## 编写Makefile
+
+:::warning[一键仿真]
+反复键入编译运行的命令是很不方便的, 尝试为`npc/Makefile`编写规则`sim`,
+实现一键仿真, 如键入`make sim`即可进行上述仿真.
+:::
+
+:::danger[注意保留git追踪的命令]
+框架代码已经在`npc/Makefile`中提供了一条默认的`sim`规则,
+它已经包含用于git追踪的命令`$(call git_commit, "sim RTL")`,
+在编写Makefile的时候注意不要修改这一命令, 否则会影响开发跟踪的功能,
+而这是记录"一生一芯"成果原创性的重要依据.
+因此在编写Makefile并运行之后, 你也需要确认git是否已经正确追踪了仿真的记录.
+:::
+## 接入NVBoard
+
+[NVBoard][nvboard](NJU Virtual Board)是南京大学开发的, 用于教学的虚拟FPGA板卡项目,
+可以在RTL仿真环境中提供一个虚拟板卡的界面, 支持拨码开关, LED灯, VGA显示等功能,
+在速度要求不高的场景下可完全替代真实的FPGA板卡(毕竟不是每人身边都有一块FPGA).
+通过以下命令获取NVBoard的代码:
+```bash
+cd ysyx-workbench
+bash init.sh nvboard
+```
+
+[nvboard]: https://github.com/NJU-ProjectN/nvboard.git
+
+:::warning[运行NVBoard示例]
+阅读NVBoard项目的介绍, 尝试运行NVBoard项目中提供的示例.
+:::
+
+:::tip[不知道NVBoard如何工作?]
+试试从`make`命令开始, 看看一切是如何发生的.
+通过前面的学习, 你已经掌握了足够的知识背景去理解NVBoard如何工作了:
+包括Makefile的使用, C语言和C++中类的基本用法.
+现在就试试阅读代码(Makefile也是代码), 看看示例中的verilog顶层端口,
+约束文件, 以及NVBoard是如何建立联系的.
+:::
+
+:::warning[在NVBoard上实现双控开关]
+阅读NVBoard项目的说明, 然后仿照该示例下的C++文件和Makefile, 修改你的C++文件,
+为双控开关的输入输出分配引脚, 并修改`npc/Makefile`使其接入NVBoard.
+:::
+
+:::info[NVBoard的故事]
+NVBoard虽然是南京大学的教学项目, 但它却与参加"一生一芯"的各位有着一种特殊的联系:
+在第三期"一生一芯"的流片名单当中有两位特殊的同学, 他们报名的时候还只是大一,
+而其中一位同学sjr就是NVBoard的第一作者.
+
+事实上, 也正是sjr同学在参加"一生一芯"时锻炼出的独立解决问题的能力和自信,
+帮助他成功开发NVBoard项目.
+如今NVBoard项目又反过来帮助"一生一芯"改进学习效果,
+NVBoard承载的除了虚拟FPGA板卡的功能之外, 还有"一生一芯"秉承的独立解决问题的理念.
+
+这些离你其实并不遥远, 当你愿意自主学习而不再等着别人给你答案的时候, 你的未来也会充满无限的可能.
+:::
+## 示例: 流水灯
+(如果该段示例代码理解困难,可以先进行[数字电路基础实验部分](DigitalCircuitBasicExperiment.md)!)
+
+流水灯是按照顺序依次亮起和熄灭的一组灯, 以下是流水灯的一个参考实现:
+```verilog
+module light(
+ input clk,
+ input rst,
+ output reg [15:0] led
+);
+ reg [31:0] count;
+ always @(posedge clk) begin
+ if (rst) begin led <= 1; count <= 0; end
+ else begin
+ if (count == 0) led <= {led[14:0], led[15]};
+ count <= (count >= 5000000 ? 32'b0 : count + 1);
+ end
+ end
+endmodule
+```
+这里的输出信号led的每一位对应虚拟板卡的一个led灯.
+由于代码中包含需要进行复位的时序逻辑部件, 我们需要对verilator的仿真代码进行修改:
+```c
+// 以下为伪代码
+
+void single_cycle() {
+ top->clk = 0; top->eval();
+ top->clk = 1; top->eval();
+}
+
+void reset(int n) {
+ top->rst = 1;
+ while (n -- > 0) single_cycle();
+ top->rst = 0;
+}
+
+...
+reset(10); // 复位10个周期
+while(???) {
+ ...
+ single_cycle();
+ ...
+}
+```
+
+:::warning[将流水灯接入NVBoard]
+编写流水灯模块, 然后接入NVBoard并分配引脚.
+如果你的实现正确, 你将看到灯从右端往左端依次亮起并熄灭.
+:::
+
+:::warning[理解RTL仿真的行为(2)]
+阅读verilator编译出的C++代码, 然后结合verilog代码,
+尝试理解仿真器是如何对时序逻辑电路进行仿真的.
+:::
+:::info[verilator进阶学习]
+[请点击这里](https://www.itsembedded.com/)
+:::
diff --git a/zh/preliminary/SubmitDefense.md b/zh/preliminary/SubmitDefense.md
new file mode 100644
index 0000000..953bfcf
--- /dev/null
+++ b/zh/preliminary/SubmitDefense.md
@@ -0,0 +1,50 @@
+---
+sidebar_position: 7
+---
+# 提交入学答辩申请
+
+:::info[如果你感受到了独立解决问题的快乐]
+恭喜你!
+
+因为这不仅意味着你的能力得到了肉眼可见的提升,
+更重要的是你的内心也在变强, 和之前相比没那么害怕解决未知问题了.
+这种心态的转变是至关重要的, 因为接下来还有无数的未知困难等着你去解决 :)
+:::
+
+:::warning[补充读后感]
+我们在预学习的一开始请你仔细阅读[提问的智慧][how to ask]和[别像弱智一样提问][stop ask]这两篇文章,
+并编写了不少于800字的读后感.
+请你结合自己完成预学习的经历, 进一步补充完善这篇读后感,
+谈谈自己是如何通过这两篇文章中提倡的方法独立解决问题的.
+:::
+[how to ask]: https://github.com/ryanhanwu/How-To-Ask-Questions-The-Smart-Way/blob/master/README-zh_CN.md
+[stop ask]: https://github.com/tangx/Stop-Ask-Questions-The-Stupid-Ways/blob/master/README.md
+
+:::warning[完成所有必做题]
+* Linux系统安装和基本使用习题
+* C语言习题
+* 数字电路习题
+* verilator接入NVBoard
+* PA1
+* 评估电路综合后的时序
+:::
+:::warning[提交入学答辩申请]
+##### 申请答辩
+* 填写 [第六期“一生一芯”--申请答辩](https://docs.qq.com/sheet/DT0ZPSGZNZk1FWVFS?tab=BB08J2&u=7e80683417974ca19ee2fd0fed634f56)进行申请后,扫描表内所附二维码加入答辩微信群等待助教发布答辩通知。答辩开始时间为周六上午九点半(通常一到两周一次)。
+##### 答辩前准备
+* [通识问卷](https://www.wenjuan.pub/s/UZBZJv6ci37/#)通过(达到100分)并将截图附于答辩申请表中;将学习记录及读后感权限设为“所有人可查看”。
+* 设备检查:摄像头、麦克风。
+* 证件检查:需要准备身份证明证件(能证明本人身份,一般为学生卡、学生证、录取通知书、毕业证书、工牌、驾驶证等)。
+* 项目环境检查:能够运行预学习所需的代码。
+* **确保代码清晰,禁止手机录屏。**
+##### 答辩流程
+1. 答辩前,根据群内通知提前进入指定会议室等候;
+2. 答辩过程中,打开摄像头,并对项目进行屏幕共享;
+3. 答辩结束,若为首次答辩,答辩人念承诺书后离开会议。
+##### 答辩后流程
+* 关注“一生一芯”公众号,答辩通过名单将于答辩后第一个周一下午六点前于该公众号公布。
+* 通过答辩的同学填写个人信息收集表以便寄送入学大礼包以及入学通知书。
+* **入学答辩未通过的同学,助教会给出学习建议,同学需在确认自己到达入学答辩要求后再次申请答辩。再次申请入学答辩的同学,助教会检查学习记录,若进度不满足入学答辩要求,助教可拒绝答辩。**
+##### 最终解释权
+* 答辩结果的最终解释权归“一生一芯”项目组所有。
+:::
\ No newline at end of file