Skip to content

Commit

Permalink
update running led
Browse files Browse the repository at this point in the history
  • Loading branch information
kevin56348 committed Nov 4, 2024
1 parent 8705ef6 commit 443b9cf
Show file tree
Hide file tree
Showing 6 changed files with 85 additions and 24 deletions.
2 changes: 2 additions & 0 deletions docs/module/decoder_and_alu_help.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@

> by 袁汉青 计科233
!> 来自助教的提醒:请勿抄袭,违纪者严肃处理!

## CPU译码器是干什么的?

答:CPU译码模块负责将取指阶段从存储器中读取的指令进行解析,转换成计算机内部可以直接执行的微操作或控制信号。
Expand Down
50 changes: 50 additions & 0 deletions docs/module/running_led_var_speed.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
# 变速流水灯

> by 孙皓,张溪延,刘海强,胡璟晨曦
!> 来自助教的提醒:请勿抄袭,违纪者严肃处理!

## 必要知识

1. 100 MHz = $1\times 10^8$ Hz,即每秒的频率为 $ 1\times10^8 $ 次,一次的周期的时间为 $1\times10^{-8}$ s
2. EGO1搭载100MHz的时钟芯片;时钟clk连接的管脚是P17。
3. 在Verilog中直接使用数值,要标明其二进制下的位宽与进制,如十进制下的`10`,应该写为`4'd10`,其中`4``10`转化为二进制下的位宽,这个数字可以大于等于`4`,但一定不能小于`4`,因为`10`的二进制是`1010`,位宽为`4``d`为十进制,`10`为所表示的数值
4. 分频是将高频信号转为低频信号的过程,由于一个时钟的频率极快,人眼无法捕捉变化,因此我们要将频率变小,也就是将流水灯的变化速度变为人眼可捕捉的范围,我们采用计数器进行分频,对于每个周期进行一次计数,当计数达到指定数值输出高电平,以给出的分频器代码为例,其原理可以理解为将原来的一动一变,变成 $10001\times 10001$ 动一变(注意判断条件虽然是 $counter\_first/second==10000$,但实际上循环了 $10001$ 次)
值得一提的是,在上面的代码中,分频器被拆分为`counter_first``counter_second`两个循环,这是因为 $10001\times 10001=100020001$ 这个数字十分庞大,如果单用一个循环,要使用一个27位宽的reg扮演迭代器的角色,而位宽越大,其性能越差,所以将其拆分为两个14位宽的迭代器`counter_first``counter_second`
5. Verilog中的除法要求为整数,所有变量默认无符号,进行减法操作注意溢出. ***注意,如无极特殊情况,请勿使用verilog的除法运算。***

6. `rst`复位信号通常以`rst_n`的形式出现,即平常置于高电平,当为低电平时复位,这主要是为了降低噪声,提高安全性.

## 实验过程

首先必须要注意的是,cg平台上“流水灯的相关模块”和“按部就班”的流水灯代码是不足以完成本次实验的要求的,我们必须对原有代码做适当修改。实验的要求如下:

但是,若是您先把代码照搬再上板,那么可供操控的开关只有“复位”和“更改方向”两个。显而易见,既无法控制移动速度,也不能按照开关的“开闭数目”控制方向。因此,按照要求修改代码,似乎成为了我们的首要任务。

我们分析“按部就班”的流水灯可以知道,此处给出的移动速度公式的正负号,充当了彼处的变量`dir``sw0`)的功能。也就是说,在方向上我们只需要判断“sum(‘1’处的开关数量) - 4”是否大于零就好。不过,此处就产生了一个坑点:在做加法器实验时我们知道,Verilog里的变量是默认无符号的,于是我们需要将其先进行强制类型转换再比较。够了吗?还不够。

因为一个无符号变量即使减4之后也总是正,再去强制类型转换是无意义的,因此需要在定义时就要定义为有符号数。下图代码仅供参考:

当然,你也可以直接用默认的无符号数与4进行大小比较,不再过多赘述。
8位`ops`代表了8个拨片开关,于是4位的有符号`wire``dir`就充当了移动速度的分子,也决定了移动方向(移动方向目前没有做明确规定,因此只要表现出反向,是正是负对应谁是随您喜欢的)。但是,假若您从一开始就将高电平开关数量和4进行比较,就省去了这些麻烦。
之后的过程无需赘述,无非是对给出的代码做修改和填空。如果您稍观察过`ctl`模块,应该会注意到分支语句是省略“ $\$signed(dir) == 0$ ”的。因为在时序电路中,如果敏感事件不发生时,状态保持——这恰恰满足了移动速度=0的要求。

如果用原来的时钟,小灯的移动速度就是 $1\times 10^8$ . 很可惜,人类目前并没有进化到每秒能处理100M帧的肉眼,因此我们需要进行分频,计数大小为 $9999\times 9999$(倍数为 $10000\times 10000$)。这样我们就会惊喜地发现,时钟目前的周期正好是1s(带着惊喜去计算一下也能得到相同的结果)——在不加干预的情况下,板上的小灯的移动速度就是1。倘若现在要将移动速度变成1/8呢?答案就显而易见:变成 $10000\times 10000\times 8$ 动一变。
这样我们的终级目标就浮出水面了:将移动速度变成t/8,就要将分频的频率变成原来的 $10000\times 10000\times 8/t$。这里的t就是上文dir的绝对值,而且绝对不会出现小数和除数为0的情况。为了保险,您可以运用三目运算符先转换一下再去运算。

这里还有两点容易失足掉坑:其一是( $\times 8 / un\_dir$)的操作只需要在`cnt_first`, `cnt_second`其中一个进行操作就好,不然就是平方倍。其二是由于`cnt_first`, `cnt_second`只有14位,直接放大8倍是一定会溢出的;这里我建议将位宽开得大一点。但是,乘除法运算在FPGA里本身较复杂,且占用时间空间都比较大。为了快速稳定地得到期望的结果,您不妨将普通的乘法改为左移三位;当然,你也可以只用一个循环完成,不再过多赘述。

最后,关于顶层模块,请务必要将声明的变量和实例化一一对应且不重不漏——大部分网表生成失败都是这个原因!如果还是失败的话,请尝试将一些底层模块不在括号里声明的变量重新在顶层声明一遍或者再检查是否有将数组声明成单个变量的情况。

在紧张刺激的综合上板的过程中,也有一些可能会卡住进度的情况。

+ 直接在Verilog代码上修改时间精度和最小时间单位会出现一些不可预料的情况,并且如果各个模块时间不统一,大概率得不到想要的结果。
+ I/O Ports只能在您生成网表后才能在Window栏中找到。

如果管脚匹配错误,生成比特流时会直接报错。

+ 关于Reset是否保留的问题,如果没有规定,应该是自便的。这里我用匹配了旁边的S2开关,除了需要一直按着以外,没有别的坏处。
+ 您的拨片开关可以选择8个或者16个。
+ 如果您仔细阅读过底层模块就会发现:给定的复位开关rst似乎和上课时的复位代码正好相反。原本的if( !rst )变成了if( rst )——但为什么波形和在板子上的操作和课上的代码一致呢?答案就隐藏在顶层模块中。

如果您觉得这样写别扭,请将仿真模块中的rst一并改掉——或者为了巩固复位的知识,您可以将这些rst的正负进行各种排列组合,再去观察它们之间有什么不同。
4 changes: 2 additions & 2 deletions docs/module/sequence_logic_help.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@

> by 陈欣杰 计科224
!> 来自助教的提醒:请勿抄袭,违纪者严肃处理!

## 主要功能

- 8个数码管全部具有显示和写入双模式
Expand Down Expand Up @@ -297,5 +299,3 @@
> 全部代码
[https://github.com/Xinjie-Chen/Digital-Logic/tree/main/lab3](https://github.com/Xinjie-Chen/Digital-Logic/tree/main/lab3)

!> 来自助教的提醒:请勿抄袭,违纪者严肃处理!
2 changes: 2 additions & 0 deletions docs/module/smart_of_asking_question.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
# 提问的智慧

[![PRs Welcome](https://img.shields.io/badge/PRs-welcome-brightgreen.svg?style=flat-square)](https://github.com/ryanhanwu/How-To-Ask-Questions-The-Smart-Way/pulls)

***本文为原仓库为 ryanhanwu 的How-To-Ask-Questions-The-Smart-Way***
Expand All @@ -18,6 +19,7 @@ Copyleft 2001 by D.H.Grand(nOBODY/Ginux), 2010 by Gasolin, 2015 by Ryan Wu
协助指出翻译问题,**[发 issue](https://github.com/ryanhanwu/How-To-Ask-Questions-The-Smart-Way/issues/new),或直接[发 pull request](https://github.com/ryanhanwu/How-To-Ask-Questions-The-Smart-Way/compare) 给我。**

## 目录

- [提问的智慧](#提问的智慧)
- [目录](#目录)
- [声明](#声明)
Expand Down
41 changes: 23 additions & 18 deletions docs/module/uart.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
# UART与简易电子秤

## 实验目的

在本次实验中,大家将会深入了解一种在设备间交流时如鱼得水的硬件通信协议:Universal Asynchronous Receiver/Transmitter,简称 UART。这不仅是一种硬件通信协议,更像是设备间的无声对话。UART 的独到之处在于它的异步特性——它不需要使用时钟信号连接两个设备,只需靠着 Transmitter(Tx)和 Receiver(Rx)两个信号就能愉快地交换信息。就像在闲聊时无需约定时间一样自在,UART 让设备之间的对话变得轻松而高效。我们将通过本实验,揭秘这种看似简单却大有玄机的通信协议,探索其基本的收发机制。

因此,本实验的目的是学习UART的简单应用;掌握实验平台的外部功能模块在数字系统设计中的应用,以及通信协议的使用。并深入地理解UART协议,并基于UART协议实现一个具有计价、累加与清零功能的简易电子秤。
Expand All @@ -10,7 +11,9 @@
![波形图](../pic.asset/uart_diag.png)

## 实验内容

1. 参照 UART 手册,以及提供的代码实现一个 UART 收发模块,其端口定义如下:

```verilog
module uartAdapter(
input wire clk ,
Expand All @@ -23,6 +26,7 @@
output wire rvalid
);
```
+ 该模块包含三个子模块`uart_pll`、`uartTransmitter`和`uartReceiver`。`uartTransmitter`和`uartReceiver`端口定义如下:
```verilog
Expand All @@ -42,24 +46,24 @@
output reg rvalid
);
```
+ uartAdapter模块需要做到如下要求:
- **16** 倍过采样
- 波特率 **19200**
- **8** 个数据位
- **无**奇偶校验位
- **1** 位停止位
- 滤波(如实现接收功能可以考虑)
- 在wvalid为高时,接收此时的wvalid并通过tx输出
- 在你完成一次传输时,将收到的数据通过rdata传出,并拉高rvalid一周期
+ **16** 倍过采样
+ 波特率 **19200**
+ **8** 个数据位
+ **无**奇偶校验位
+ **1** 位停止位
+ 滤波(如实现接收功能可以考虑)
+ 在wvalid为高时,接收此时的wvalid并通过tx输出
+ 在你完成一次传输时,将收到的数据通过rdata传出,并拉高rvalid一周期
+ 当然,从零开始实现一个UART收发模块的难度对于大家可能会略有些高。为了让大家在能够深入理解UART协议的同时,不用花太多的时间在写各种琐碎而基础的代码或是与UART无关错误的debug上,在收到了若干同学提出的宝贵建议后,我们决定**将本次实验所用到的UART收发模块的参考代码直接提供给大家**,大家如果不愿意从零写起,直接使用我们给出的代码即可。
+ 备注:
1. 大家在使用我们提供的参考代码中的模块时,可能会发现缺少了一些相关代码,这可能是我们~~有意为之~~*不小心删除的*,请大家根据对UART的理解自行填补。
2. 大家在填补完成代码后,可能会发现,虽然填补的代码理论上应当是完全正确的,但该收发模块并不能正常工作。这~~亦是我们有意为之~~*可能是我们不小心写错的*,请大家根据对UART的理解,从代码中找到粗心的我们留下的错误,并将其改正。
3. 这些要求与提供的资料是基本对应的,因此可以大大简化难度。
4. 我们在提供的`UART_Receiver.v`中部分实现性能~~不小心~~变差了,如果**有能力以及相关意愿**可以**尝试**更改。(我们推荐对龙芯杯有兴趣的同学尝试,经过修改,整体的**W**orst **N**egative **S**lack(WNS)会大幅降低。经测试,在150MHz时钟下至少可以做到WNS为1.960)
2. 通过已给出的外设控制模块使用正确的UART收发模块,完成上板通信测试。
Expand All @@ -69,7 +73,6 @@
+ 通过尝试使用串口令电脑与EGO1进行通信。文件包中提供了指令序列。
+ 设计具有开放性,鼓励设计实现自己的输入输出控制逻辑和显示效果。也可自行实现帧协议,或补全提供文件中的帧协议。
3. 实现简易电子秤
实现一个具有基础功能的电子秤,具体要求如下:
Expand Down Expand Up @@ -98,50 +101,50 @@
total: 11.00$
**********Vanity Fair's Balance**********
```
+
?> 很遗憾我的文学素养并不高,无法为大家解释“Vanity Fair's Balance”是什么(补充:Vanity Fair译为名利场,源于班扬的《天路历程》,Balance事实上是天平。——Kevin)。但无论怎样,像以上这样具有较高可读性的输出格式比“AC03 0026 0302 0006”要好太多不是吗?具体的输出格式实现,大家可以自由发挥。
+ 为你的电子秤增加更多功能
?> 实验4.1所实现的只是一些最基础的要求(虽然这并不意味着难度也很低)。在本实验中,我们希望你们能为你们的电子秤添加更多功能,例如可变长数据帧、去皮、大数显示优化(例如2000012.34可以简略显示为2M,你可以选择的字头有k,M,G,T,P等)、多个可切换的历史总价、撤销功能等。具体添加什么功能,我们不作约束。
## 实验要求
1. 在实验报告中提交系统级设计模块图、设计代码、激励程序(不必须包含所有模块的)、仿真波形结果截图(与激励配套)、板级实测验证结果照片。其中,系统级设计模块图要求给出整个系统的数据输出信号,系统内各个子模块的输入输出信号和模块间的连接关系(不需要画出数码管/LED灯/按键等,给出其信号名及位宽即可)。
1. 在实验报告中提交系统级设计模块图、设计代码、激励程序(不必须包含所有模块的)、仿真波形结果截图(与激励配套)、板级实测验证结果照片。其中,系统级设计模块图要求给出整个系统的数据输出信号,系统内各个子模块的输入输出信号和模块间的连接关系(不需要画出数码管/LED灯/按键等,给出其信号名及位宽即可)。
2. 提交实验报告和所有源程序文件的压缩包。
## 附录 A
### 代码及IP
[UART Receiver.v](codes/uart/UART_Receiver.v ':ignore ')
[UART Transmitter.v](codes/uart/UART_Transmitter.v ':ignore ')
[Frame Adapter.v](codes/uart/frameAdapter.v ':ignore ')
### 相关软件
[XCOM.exe](codes/uart/XCOM_V2.6.exe ':ignore ')
[XCOM配置文件(流水学号)](codes/uart/UART_TEST.ini ':ignore ')
### UART规范
![格式](../pic.asset/uart_form.png)
![分频表](../pic.asset/uart_clk_divisor.png)
[KeyStone Architecture Literature Number: SPRUGP1 Universal Asynchronous Receiver/Transmitter (UART) User Guide](appendix/uart_doc.pdf ':ignore ')
### UART模块框图
![顶层模块框图](../pic.asset/uart.svg)
### 控制协议及相关说明
帧定义
```
3 2 1 0
Expand All @@ -156,6 +159,7 @@
```
帧 (一个更简单的实现, **这个模块在提供的文件中已经实现**)
```
3 2 1 0
1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0
Expand All @@ -179,6 +183,7 @@
接收端将会按照以上规则进行处理,因此在发送时,请注意发送的信息*有时需要进行转义*。
### PLL IP核的使用
请依照以下步骤进行IP核心的例化:
![](../pic.asset/ip_gen_pll_1.png)
Expand All @@ -193,4 +198,4 @@
![](../pic.asset/ip_gen_pll_6.png)
在例化完成后,可以将IP核视为一个普通模块进行使用。其名称即为例化时的`Component Name`,在本例子中,即为`clk_wiz_0`;其输入输出端口可见例化时的`IP Symbol`部分,左侧为输入,右侧为输出。
在例化完成后,可以将IP核视为一个普通模块进行使用。其名称即为例化时的`Component Name`,在本例子中,即为`clk_wiz_0`;其输入输出端口可见例化时的`IP Symbol`部分,左侧为输入,右侧为输出。
10 changes: 6 additions & 4 deletions docs/module/unsigned_multiplier.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,9 @@

> by Zakilim
### 无符号乘法运算基础
!> 来自助教的提醒:请勿抄袭,违纪者严肃处理!

## 无符号乘法运算基础

在考虑乘法器的设计之前,我们首先可以考虑乘法的运算。在10进制下,我们往往会用下面的方式计算乘法
$$
Expand Down Expand Up @@ -45,7 +47,7 @@ $$
$$
可以看到,采用二进制竖式运算,较之十进制其实更简单,实际上是一种加法和移位的组合运算。

### 循环移位乘法器
## 循环移位乘法器

正如前文给出的公式$xy = \sum_{k=0}^{w-1}(x\times y_k2^k)$

Expand Down Expand Up @@ -101,10 +103,10 @@ return sum

每次选择乘积寄存器的**32位与被乘数相加**,根据**最低位的为01**判断是否需要写入乘积寄存器当中,(也就是决定加还是不加),然后整体右移,(加法时记得保留进位)。当乘积寄存器右移32位以后,乘积寄存器当中就存放了64位的无符号乘积,此时初始状态下存放的被乘数在32位移位中就逐渐被抛掉了。这种乘法器的设计比较节约寄存器的大小,如果觉得实现较为困难,也可以单独建立一个乘数寄存器来存放乘数控制电路。

### 阵列乘法器
## 阵列乘法器

前面的循环移位乘法器需要多个时钟周期才能完成,事实上,我们也可以采用组合逻辑实现,既然乘法不过是加法与移位的组合,那么对于一个n位数,只要有n个n位加法器同时工作,就可以在一个周期内计算出结果。一个n位加法器需要n个全加器实现,那么n位阵列乘法器,就需要n*n个全加器组和到一起,其中一种电路实现描述如下

![image-20211122114256851](../pic.asset/image-20211122114256851.png)

事实上,在这个过程中,还可以通过超前进位加法器来加速运算。
事实上,在这个过程中,还可以通过超前进位加法器来加速运算。

0 comments on commit 443b9cf

Please sign in to comment.