├── README.md
├── doc
├── plan.md
└── report.md
├── game
└── main.s
├── img
├── game.jpg
├── game_demo.gif
└── 模块图.png
└── src
├── SEG7_LUT.v
├── addr_check.v
├── addr_decode.v
├── async.v
├── data_loader.v
├── defines.vh
├── exe.v
├── exp_exe.v
├── exp_handle.v
├── exp_if.v
├── mem_controller.v
├── mmu.v
├── regfile.v
├── sram_io.v
├── thinpad_top.v
├── uart_io.v
└── vga.v
/README.md:
--------------------------------------------------------------------------------
1 | Thinpad RISC-V CPU
2 | ---------------
3 |
4 | 2020年秋季学期,计算机组成原理大作业,基于RISC-V指令集的多周期CPU。
5 |
6 | [支持](./doc/plan.md)功能:
7 |
8 | - 19 条基本指令和 3 条附加指令
9 | - 异常、中断
10 | - MMU
11 | - ....
12 |
13 |
14 |
15 | ## Game Demo
16 |
17 | 汇编语言编写的迷宫游戏,运行于硬件语言实现的CPU上
18 |
19 |
20 |
21 | ## Developers
22 |
23 | [乐阳](https://github.com/yueyang2000)
24 |
25 | [黄翘楚](https://github.com/huangqc2000)
26 |
27 | [张鹤潇](https://github.com/zhanghx0905)
28 |
29 | #### 附
30 |
31 | 代码中包含中文注释,编码为utf-8,在Windows版Vivado下可能出现乱码问题。
32 | 请用别的代码编辑器打开文件,并将编码改为GBK。
33 |
--------------------------------------------------------------------------------
/doc/plan.md:
--------------------------------------------------------------------------------
1 | # 基础指令:19条
2 |
3 | ### 运算指令
4 |
5 | ```
6 | ADD 0000000SSSSSsssss000ddddd0110011
7 | reg[rd] = reg[rs1] + reg[rs2]
8 | pc += 4
9 |
10 | AND 0000000SSSSSsssss111ddddd0110011
11 | reg[rd] = reg[rs1] & reg[rs2]
12 | pc += 4
13 |
14 | OR 0000000SSSSSsssss110ddddd0110011
15 | reg[rd] = reg[rs1] | reg[rs2]
16 | pc += 4
17 |
18 | XOR 0000000SSSSSsssss100ddddd0110011
19 | reg[rd] = reg[rs1] ^ reg[rs2]
20 | pc += 4
21 |
22 | ADDI iiiiiiiiiiiisssss000ddddd0010011
23 | reg[rd] = reg[rs1] + ext_imm
24 | pc += 4
25 |
26 | ANDI iiiiiiiiiiiisssss111ddddd0010011
27 | reg[rd] = reg[rs1] & ext_imm
28 | pc += 4
29 |
30 | ORI iiiiiiiiiiiisssss110ddddd0010011
31 | reg[rd] = reg[rs1] | ext_imm
32 | pc += 4
33 |
34 | SLLI 0000000iiiiisssss001ddddd0010011
35 | reg[rd] = reg[rs1] << imm5
36 | pc += 4
37 |
38 | SRLI 0000000iiiiisssss101ddddd0010011
39 | reg[rd] = reg[rs1] >> imm5
40 | pc += 4
41 | ```
42 |
43 | ### 跳转与PC
44 |
45 | ```
46 | JAL iiiiiiiiiiiiiiiiiiiiddddd1101111
47 | reg[rd] = pc + 4
48 | pc = pc + ext_{imm20, 0}
49 |
50 | JALR iiiiiiiiiiiisssss000ddddd1100111
51 | reg[rd] = pc + 4
52 | pc = {(reg[rs1] + ext_imm)[31:1], 0}
53 |
54 |
55 | BEQ iiiiiiiSSSSSsssss000iiiii1100011
56 | immB = {imm[12:1], 0}
57 | pc = (reg[rs1] == reg[rs2])? pc + immB:pc+4
58 |
59 | BNE iiiiiiiSSSSSsssss001iiiii1100011
60 | immB = {imm[12:1], 0}
61 | pc = (reg[rs1] != reg[rs2])? pc + immB:pc+4
62 | ```
63 |
64 | ### 高20位运算
65 |
66 | ```
67 | AUIPC iiiiiiiiiiiiiiiiiiiiddddd0010111
68 | reg[rd] = {imm20, 8'b0} + pc
69 | pc = pc + 4
70 |
71 | LUI iiiiiiiiiiiiiiiiiiiiddddd0110111
72 | reg[rd] = {imm20, 8'b0}
73 | pc = pc + 4
74 | ```
75 |
76 | ### 访存指令
77 |
78 | ```
79 | LB iiiiiiiiiiiisssss000ddddd0000011
80 | reg[rd] = ext(mem[reg[rs1]+ext_imm12][7:0])
81 | pc = pc + 4
82 |
83 | LW iiiiiiiiiiiisssss010ddddd0000011
84 | reg[rd] = mem[reg[rs1]+ext_imm12]
85 | pc = pc + 4
86 |
87 | SB iiiiiiiSSSSSsssss000iiiii0100011
88 | mem[reg[rs1]+ext_imm12] = reg[rs2][7:0]
89 | pc = pc + 4
90 |
91 | SW iiiiiiiSSSSSsssss010iiiii0100011
92 | mem[reg[rs1]+ext_imm12] = reg[rs2]
93 | pc = pc + 4
94 | ```
95 |
96 | ### 额外指令
97 |
98 | ```
99 | CTZ rd, rs
100 | // The ctz operation counts the number of 0 bits at the LSB end of the argument.
101 |
102 | CLZ rd, rs
103 | // The clz operation counts the number of 0 bits at the MSB end of the argument.
104 |
105 | MIN rd, rs1, rs2
106 | // return the smaller one
107 | ```
108 |
109 |
110 |
111 | # 中断与异常
112 |
113 | - 记录M模式与U模式
114 |
115 | ### 同步异常
116 |
117 | - 访存异常
118 | - ebreak
119 | - ecall
120 | - 指令非法,比如
121 | - 地址不对齐异常
122 |
123 | ### 异步中断
124 |
125 | - 外设请求,当前程序保存现场,处理中断,再恢复现场。
126 | - 中断不能嵌套
127 |
128 | ### 有关寄存器
129 |
130 | - mtvec:处理异常的程序入口;高30位base,低2位mode
131 | - mode = 0,则所有异常、中断响应时跳转到base指示的pc
132 | - mode = 1,狭义异常发生时去base,狭义中断发生跳到base + 4*cause,cause对应中断的异常编号。
133 | - mcause:高1位是中断域,低31位为异常编号域。组合表示,12种中断和16种异常
134 | - mepc
135 | - 出现中断时,mepc为下一条未执行指令
136 | - 出现异常时,mepc为下一条更新为当前发生异常的指令PC。(由软件防止异常死循环)
137 | - mtval
138 | - 由存储器访问产生的异常,将访问地址存入
139 | - 由非法指令造成的异常,把非法指令存入
140 | - mstatus
141 | - 机器模式状态寄存器,有很多位。。。
142 | - MIE为1时响应中断,MIE为0时不响应(由于已经在处理某个异常)
143 | - 发生异常时:
144 | - MPIE域保存异常发生前的MIE值,异常结束后恢复MIE
145 | - MIE值被更新为0
146 | - MPP被更新为异常发生前的模式,为了异常处理结束后恢复
147 |
148 |
149 |
150 | ### 有关指令
151 |
152 | - mret
153 | - pc = mepc
154 | - 更新mstatus:MIE = MPIE, MPIE = 1
155 |
156 | - csrrc:
157 |
158 | ```
159 | CSRRC ccccccccccccsssss011ddddd1110011
160 | t = CSRs[csr]; CSRs[csr] = t &~x[rs1]; x[rd] = t
161 |
162 | CSRRS ccccccccccccsssss010ddddd1110011
163 | t = CSRs[csr]; CSRs[csr] = t | x[rs1]; x[rd] = t
164 |
165 | CSRRW ccccccccccccsssss001ddddd1110011
166 | t = CSRs[csr]; CSRs[csr] = x[rs1]; x[rd] = t
167 |
168 | EBREAK 00000000000100000000000001110011
169 | 断点异常,mcause编号为3
170 |
171 | ECALL 00000000000000000000000001110011
172 | 环境调用,U-mode为8,M-mode为11
173 |
174 | MRET 00110000001000000000000001110011
175 | 将 pc 设置为 CSRs[mepc],
176 | 将特权级设置成CSRs[mstatus].MPP
177 | CSRs[mstatus].MIE 置成 CSRs[mstatus].MPIE, 并且将CSRs[mstatus].MPIE 为 1
178 | 如果支持用户模式,则将 CSR [mstatus].MPP 设置为 0。
179 | ```
180 |
181 |
182 |
183 | ### 异常种类列举
184 |
185 |
186 |
187 | module exp_handle
188 |
189 | 内含csr寄存器,根据exp_if, exp_exe检查到的异常进行处理
190 |
191 |
192 |
193 | module exp_exe
194 |
195 | invalid, mem_addr, mem_rd, mem_wr, exp_op
196 |
197 |
198 |
199 | module exp_if
200 |
201 | new_pc
202 |
203 |
204 |
205 |
206 |
207 | - 指令地址未对齐
208 | - mcause = 0
209 | - IF阶段发生
210 | - 指令地址越界
211 | - mcause = 1
212 | - 界 0x80000000~0x807FFFFF
213 | - 用new_pc检查以上两种,IF阶段检查
214 | - 译码错误 exe检查
215 | - mcause = 2
216 | - 用instvalid检查,注意exe模块要添加更多的译码检查
217 | - 断点ebreak, mcause = 3
218 | - 直接送异常处理模块
219 | - load地址未对齐
220 | - mcause = 4
221 | - lw发生
222 | - load地址越界
223 | - mcause = 5
224 | - save地址未对齐 mcause = 6
225 | - save地址越界 mcause = 7
226 | - 以上全部在exe阶段检查完
227 | - ecall
228 | - U mode: mcause = 8
229 | - S mode: mcause = 9
230 | - M mode: mcause = 11
231 | - 12, 13, 15:页缺失
232 |
233 |
--------------------------------------------------------------------------------
/doc/report.md:
--------------------------------------------------------------------------------
1 | # RISC-V指令集处理器
2 |
3 | 乐阳 黄翘楚 张鹤潇
4 |
5 | ## 实验目标概述
6 |
7 | 本次实验中,我们完成了一个支持**中断异常**和**页表**的多周期CPU,还完成了一些附加的演示功能。工程的全部内容如下:
8 |
9 | - RISC-V多周期CPU,时钟频率为50M。
10 | - 实现了19条基础指令和3条扩展指令,(为了编程方便)又多实现了几条RISC-32I的指令。
11 | - 实现了`csrrc, csrrs, csrrw, ebreak, ecall, mret`等与异常相关的语句和`mtvec, mtval, mepc, mcause, mstatus`几个专用寄存器。
12 | - 实现了监控程序可能发生的12种异常,包括三种页缺失异常。异常号为`0,1,2,3,4,5,6,7,8,12,13,15`。
13 | - 实现了用户态地址映射和`satp`寄存器。可以稳定运行完整版的监控程序。
14 | - 实现了VGA显示驱动功能,用BRAM作为VGA渲染的缓冲区,并将BRAM的地址映射到监控程序地址空间的一部分。
15 | - 用汇编语言编写了一个走迷宫小游戏,代码达两百余行。用户可以按动实验板上的按钮`btn0~btn4`(上下左右)操纵画面中的物块移动,走向迷宫的终点。软件程序负责计算渲染画面,通过地址映射写入缓冲区BRAM中。
16 |
17 | ## 主要模块设计与实现
18 |
19 | ### 硬件部分
20 |
21 | 各主要模块说明如下
22 |
23 | ```
24 | thinpad_top.v: 顶层模块,含多周期CPU的状态机
25 | defines.vh: 定义了本次实验要用到的一些常量
26 | regfile.v: 通用寄存器组模块
27 | mem_controller.v: 访存控制模块,综合SRAM、串口、VGA、按钮的访问,同时包含页表的查看与虚实地址转换。
28 | data_loader.v:
29 | uart_io.v: 多周期读写串口驱动模块
30 | sram_io.v: 多周期读写SRAM驱动模块
31 | addr_check.v: 检查地址是否合法
32 | addr_decode.v: 判断访存的地址来自哪一个外设(SRAM、串口、VGA、按钮)
33 | exe.v: 集译码和执行于一体,从指令机器码生成各种控制信号
34 | vga.v: VGA控制模块,从BRAM中读取显示的数据
35 | exp_if.v: 取指阶段的异常检测模块
36 | exp_exe.v: 译码执行阶段的异常检测模块
37 | exp_handle.v: 异常处理模块,负责处理各种同步异常,以及执行与异常相关的指令,也负责管理CSR寄存器组
38 | ```
39 |
40 | 数据通路图大致为:
41 |
42 |
43 |
44 | #### CPU状态机
45 |
46 | 多周期CPU状态机实现在顶层模块`thinpad_top`中,可以大致分为如下几个状态:
47 |
48 | 1. 取指状态:如果pc地址合法则执行取指,转移至译码执行状态;否则监测到取指异常,进入异常处理状态。
49 | 2. 译码执行状态:将取得的指令送入`exe`模块,产生访存、写回、跳转的控制信号。在该阶段监测其余所有异常,发生异常则转异常处理状态(遇到异常相关的语句也进入异常处理状态),否则进入访存状态。
50 | 3. 访存状态:根据译码执行状态产生的控制信号进行访存操作,访存完毕后转写回状态。(不需要访存则直接转写回)
51 | 4. 写回状态:根据译码执行阶段产生的写回控制信号执行寄存器组的写回操作。更新pc,转取指状态,当前语句执行完毕。
52 | 5. 异常处理状态:进入本状态由两种可能,运行中的代码抛出了异常,或当前语句为csr寄存器操作或`ebreak, ecall, mret`之一。本状态中会处理以上两种情况,维护CSR寄存器,在发生异常跳转时更新pc。
53 |
54 | #### 译码执行模块
55 |
56 | 译码执行实现在`exe`模块中,寄存器组模块为`regfile`。
57 |
58 | 本组实现的CPU将译码和执行集成到一个模块、在一个周期内执行完。我们这样设计是基于如下考量:
59 |
60 | - RISC-V指令集中源寄存器、目的寄存器、op_code等字段的位置是固定的,译码开销很小。
61 | - 译码结果与执行的行为直接相关,额外添加ALU模块和有关控制信号十分冗余。
62 | - 从机器码直接生成访存、写回控制信号,代码实现更加简洁。
63 |
64 | 将译码执行合二为一的一个问题是在该周期内时序存在风险,我们的解决办法是译码和执行是**并行**完成的。由于机器码中各域的位置固定,因此可以在译码之前将所有可能的指令结果计算出来。例如下面的代码给出了部分指令的执行结果。
65 |
66 | ```verilog
67 | wire[`DataBus] add_result = reg1_data_i + reg2_data_i;
68 | wire[`DataBus] ori_result = reg1_data_i | immI;
69 | wire[`DataBus] srl_result = reg1_data_i >> reg2_data_i[4:0];
70 | wire[`DataBus] slli_result = reg1_data_i << shamt;
71 | wire[`DataBus] b_addr = pc + immB;
72 | wire[`DataBus] jal_addr = pc + immJ;
73 | wire[`DataBus] jalr_addr= reg1_data_i + immI;
74 | ```
75 |
76 | 我们的程序可以在50M时钟下稳定运行,说明我们的优化还是有效果的。
77 |
78 | 而译码则相当于一个选择器,选用适当的执行结果来生成访存、写回控制信号。在译码时,按照`opcode`、`funct3`和`funct7`执行**完全匹配**,严格检测译码错误。
79 |
80 | 译码执行模块生成的控制信号规范如下:
81 |
82 | ```verilog
83 | output reg instValid, // 译码是否正确
84 | output reg branch, // 是否要分支跳转
85 | output reg[`InstAddrBus] branch_addr, // (如果需要)跳转到的地址
86 |
87 | output reg mem_rd, //是否要读内存
88 | output reg mem_wr, // 是否要写内存
89 | output reg[`DataBus] mem_wr_data, // 写内存的数据
90 | output reg[`DataAddrBus] mem_addr, // 读写内存的地址
91 | output reg[3:0] ram_be_n, // 字节使能
92 |
93 | output reg wb, // 是否要写回寄存器
94 | output wire[`RegAddrBus] wb_reg_addr, // 写回寄存器的地址
95 | output reg[`DataBus] wb_data, // 写回寄存器的数据
96 | ```
97 |
98 | 这些信号负责驱动后续的访存、写回阶段。
99 |
100 | #### 访存控制模块
101 |
102 | 访存控制模块`mem_controller`集成了SRAM、串口、VGA、按钮的读写。CPU访存时只与该模块交互,而不需要知道地址具体对应哪种外设。当CPU需要读内存时,拉低读使能`oen`,等待一些周期后即可从`data_out`信号中读取数据;CPU需要写内存时,拉低写使能`wen`,等待写操作完毕后继续执行。
103 |
104 | 在`mem_controller`内部,有一些访存的辅助模块,包括
105 |
106 | - sram_io:SRAM控制信号的驱动模块,对于base_ram和ext_ram各有一个实例。
107 |
108 | - uart_io:CPLD串口控制信号驱动模块
109 |
110 | - addr_decode:分辨访存地址属于哪一个外设。产生信号`mem_use`,可能的取值如下:
111 |
112 | ```verilog
113 | `define USE_VGA 2'b00
114 | `define USE_BASE 2'b01
115 | `define USE_EXT 2'b10
116 | `define USE_UART 2'b11
117 | ```
118 |
119 | - data_loader:生成读操作需要返回的数据,需要处理`lb`和`lw`的区别以及来自不同外设的输出。
120 |
121 | 读写UART只有两个合法的地址,`UART_DATA_ADDR`和`UART_STATUS_ADDR`,访问前者进入uart读写逻辑,访问后者则返回`uart_dataready`。
122 |
123 | #### 异常检测与异常处理
124 |
125 | 在取指令和译码执行两个阶段检测异常的发生,两个异常检测模块为`exp_if`和`exp_exe`。前者检查的主要是取指令时地址未对齐或非法或页缺失。后者可能发生读取、存储相关的地址未对齐或非法或页缺失,此外还有译码错误。监测到异常后,生成两个控制信号`exception`和`exp_code`,前者表明是否发生异常,后者代表该异常的号码。
126 |
127 | 为了实现方便,对于CSR寄存器操作和`ebreak, ecall, mret`指令也会交给异常处理模块`exp_handle`来处理。
128 |
129 | `exp_handle`模块会根据控制信号`exception`和`exp_code`生成异常相关的控制信号,同时更新CSR寄存器。控制信号主要有:
130 |
131 | ```verilog
132 | output reg ebranch, // 是否有异常跳转
133 | output reg[`InstAddrBus] ebranch_addr, // 异常跳转地址
134 |
135 | output reg wb_reg, // 是否写回通用寄存器
136 | output wire[`RegAddrBus] wb_reg_addr, // 写回寄存器地址
137 | output reg[`DataBus] wb_reg_data, // 写回寄存器数据
138 | ```
139 |
140 | 专用寄存器实现了`mtvec, mtval, mepc, mcause, mstatus`。
141 |
142 | #### 虚拟地址映射
143 |
144 | 完整版的监控程序支持在程序处于用户模式时,启用虚拟地址映射,我们使用全局共享的控制信号`sv32_en`来控制是否启用映射。在启用映射时,每次`mem_controller`访存操作前都需要先获得物理地址。
145 |
146 | 为了实现方便,`satp`和其他专用寄存器一样都存放在`exp_handle`模块中。`mem_controller`在访存时需要查看`satp`的值来访问页表,具体流程为
147 |
148 | 1. 收到一个访存请求,若`sv32_en`为1则计算偏移量查看一级页表;否则直接设置物理地址为访存地址,直接进入正常读写流程。
149 | 2. 获得一级页表项,查看其读、写、执行三位是否都是0,若是则再查二级页表;否则用实页号和偏移量拼成物理地址,进入正常读写流程。
150 | 3. 获得二级页表项,用实页号和偏移量拼成物理地址,进入正常读写流程。
151 |
152 | #### VGA显示
153 |
154 | 创建了一个深度为2^19的双口RAM用于VGA的渲染缓冲区,并将这段存储空间映射到了从`0x20`开头的监控程序地址中。这段地址空间只可以写不能读,读RAM的接口留给VGA的驱动模块。
155 |
156 | ### 软件部分
157 |
158 | 我们使用汇编语言编写了一个迷宫小游戏,代码在文件`main.s`中。
159 |
160 | #### 显示逻辑
161 |
162 | 将VGA输出划分成32*24个小格,以小格为单位进行显示。编写`renderSquare`模块,可以将某一小块渲染成某种染色。
163 |
164 | #### 控制逻辑
165 |
166 | 将实验板上四个按钮映射到一个地址,汇编程序只需要`lb`就能获得当前按钮的状态。
167 |
168 | #### 游戏流程
169 |
170 | 首先渲染背景以及终点,游戏地图储存在汇编程序的`BACKGROUND`中,可以进行修改。使用两个寄存器`a5, a6`记录人物的当前位置(初始化为0,0),进入`renderPerson`模块渲染人物。之后进入忙等待阶段,直到有按钮被按下。当有按钮被按下后根据不同的按钮改变当前任务的位置,根据人物新位置重绘当前人物,并通过记数等待一段时间(模拟游戏帧效果),然后重新进入忙等待阶段等待下一个操作。如果当前人物到了终点则通过ecall在终端输出SUCCESS并退出程序。
171 |
172 | ## 汇编小游戏
173 |
174 |
详情见小游戏演示视频。
175 |
176 | ## 实验心得体会
177 |
178 | 由于有lab3 4 5的铺垫,本次大实验完成的还是十分顺利的。
179 |
180 | 选择多周期CPU直接将工作量减少到1/3甚至更少,也比较容易调试。基础功能我们只花了两个晚上就调通了,而且几乎没有参考别的代码。异常处理的工作量大致与基础功能相当。在不考虑性能的情况下,页表的实现相对容易,只需要在原有的访存逻辑上略作修改。编写汇编游戏程序反而成为了一个挺难完成的工作,直观感受上甚至”比造机本身更困难“。
181 |
182 | 本着”不内卷“的精神,我们没有再继续推进其他的拓展功能,换取了三个星期充足的睡眠,我想这也不错。
183 |
184 | ## 小组分工
185 |
186 | 乐阳:整体架构设计与接线,CPU状态机模块,访存模块
187 |
188 | 黄翘楚:译码执行模块,调试框架设计,异常处理模块,汇编小游戏
189 |
190 | 张鹤潇:译码执行模块,代码调试
191 |
192 |
--------------------------------------------------------------------------------
/game/main.s:
--------------------------------------------------------------------------------
1 | # s9 0x20000000 s11 0x80100000 x4 返回地址
2 | BACKGROUND:
3 | .long 0b00000000000000111111111110000000
4 | .long 0b00000000000000111111111110000000
5 | .long 0b11111110000000111111111110000000
6 | .long 0b11111110000000111111111110000111
7 | .long 0b11111110000000111111111110000111
8 | .long 0b11111110000000111111111110000111
9 | .long 0b11111110000000111111111110000111
10 | .long 0b11111110000000111111111110000111
11 | .long 0b11111110000000111111111110000111
12 | .long 0b11111110000000000000011110000111
13 | .long 0b11111110000000000000011110000111
14 | .long 0b11111111111111000000011110000111
15 | .long 0b11111111111111000000011110000111
16 | .long 0b11111111111111000000011110000111
17 | .long 0b11100000000000000000011110000111
18 | .long 0b11100000000000000000011110000111
19 | .long 0b11100000000000000000011110000111
20 | .long 0b11100001111111111111111110000111
21 | .long 0b11100001111111111111111110000111
22 | .long 0b11100001111111111111111110000111
23 | .long 0b11100001111111111111111110000111
24 | .long 0b11100001111111111111111110000111
25 | .long 0b11100000000000000000000000000111
26 | .long 0b11100000000000000000000000000111
27 | .long 0b11100000000000000000000000000111
28 | renderBackground:
29 | auipc s11, 0x0
30 | addi s11, s11, -0x64 # 背景起始地址
31 | mv s10, s11 # s11不可变 s10可以变
32 | mv x4, ra
33 | li s9, 0x20000000
34 | li a5, 0
35 | li a6, 0
36 | li a0, 0x0
37 | li a3, 32 # 最大列数
38 | li a4, 24 # 最大行数
39 | LINE: # a0是行 a1是列
40 | lw t0, 0(s10) # t0是本行01串
41 | li a1, 0x0
42 | li t2, 0x1f
43 | SQUARE:
44 | sub t3, t2, a1 # t3 = t2 - a1 表示要右移的位数
45 | srl t4, t0, t3
46 | andi t4, t4, 0x1
47 | li a2, 0xff # 确定颜色
48 | bne t4, zero, COLOR_CONTINUE
49 | li a2, 0x0
50 | COLOR_CONTINUE:
51 | sw a0, -4(sp)
52 | sw a1, -8(sp)
53 | sw a2, -12(sp)
54 | sw t0, -16(sp)
55 | sw t1, -20(sp)
56 | sw t2, -24(sp)
57 | sw s1, -28(sp)
58 | sw s2, -32(sp)
59 | sw s3, -36(sp)
60 | sw s8, -40(sp)
61 | # sw ra, -44(sp)
62 | jal renderSquare
63 | lw a0, -4(sp)
64 | lw a1, -8(sp)
65 | lw a2, -12(sp)
66 | lw t0, -16(sp)
67 | lw t1, -20(sp)
68 | lw t2, -24(sp)
69 | lw s1, -28(sp)
70 | lw s2, -32(sp)
71 | lw s3, -36(sp)
72 | lw s8, -40(sp)
73 | # lw ra, -44(sp)
74 | # 一个方格画完
75 | addi a1, a1, 0x1
76 | bne a1, a3, SQUARE
77 | # 一行画完
78 | addi a0, a0, 0x1
79 | addi s10, s10, 0x4
80 | bne a0, a4, LINE
81 | jal renderPerson # renderBackground 结束
82 | jal renderEnd
83 | j OPERATION
84 | mul25: # a0 = a0*25
85 | slli t0, a0, 4
86 | slli t1, a0, 3
87 | add t0, t0, t1
88 | add t0, t0, a0
89 | mv a0, t0
90 | ret
91 | # 需要保存的有 a0,a1,a2,t0,t1,t2,s1,s2,s3,s8,ra
92 | renderSquare:# 参数 a0:行, a1:列, a2: 颜色
93 | # s3 = a0*20000 + s9, 每次加800
94 | # s1 = a1*25, 每次加1
95 | mv s8, ra
96 | jal mul25 # a0 = a0*25
97 | jal mul25 # a0 = a0*25
98 | slli s3, a0, 5 # s3 = a0*20000
99 | add s3, s3, s9 # s3 = a0*20000 + s9
100 | mv a0, a1 # a0 = a1
101 | jal mul25
102 | mv s1, a0 # s1 = a1*25
103 | li t2, 25 # t2 = 25
104 | li t0, 0 # t0是小行号
105 | L1:
106 | li t1, 0 # t1是小列号 0~24
107 | add s2, s3, s1 #本行开头
108 | L2:
109 | sb a2, 0(s2)
110 | addi t1, t1, 1
111 | addi s2, s2, 1
112 | bne t1, t2, L2 # branch if t1!=25
113 | L2_end:
114 | addi s3, s3, 800
115 | addi t0, t0, 1
116 | bne t0, t2, L1 # branch if t0!=25
117 | mv ra, s8
118 | ret
119 | renderPerson: # a5, a6存当前位置
120 | mv a0, a5
121 | mv a1, a6
122 | li a2, 0b11000000
123 | mv s10, ra
124 | jal renderSquare
125 | mv ra, s10
126 | ret
127 | OPERATION:
128 | li t0, 0x20075300
129 | .TESTO:
130 | lw t1, 0(t0)
131 | beq t1, zero, .TESTO # 忙等待
132 | # 进入不同操作
133 | andi t2, t1, 0x1
134 | bne t2, zero, OP_R
135 | andi t2, t1, 0x2
136 | bne t2, zero, OP_L
137 | andi t2, t1, 0x4
138 | bne t2, zero, OP_D
139 | andi t2, t1, 0x8
140 | bne t2, zero, OP_U
141 | OP_R:
142 | mv t0, a5
143 | mv t1, a6
144 | li t2, 31
145 | beq a6, t2, OPERATION_DONE # 右侧不能越界
146 | li t2, 30
147 | slli t3, t0, 0x2
148 | add t3, t3, s11
149 | lw t3, 0(t3)
150 | sub t4, t2, t1
151 | srl t5, t3, t4
152 | andi t5, t5, 0x1
153 | bne t5, zero, OPERATION_DONE # 右侧有墙
154 | # 可以向右移动了 先将本块涂黑
155 | mv a0, a5
156 | mv a1, a6
157 | li a2, 0x0
158 | jal renderSquare
159 | # 更新a5 a6
160 | addi a6, a6, 0x1
161 | j OPERATION_DONE
162 | OP_L:
163 | mv t0, a5
164 | mv t1, a6
165 | li t2, 0
166 | beq a6, t2, OPERATION_DONE # 左侧不能越界
167 | li t2, 32
168 | slli t3, t0, 0x2
169 | add t3, t3, s11
170 | lw t3, 0(t3)
171 | sub t4, t2, t1
172 | srl t5, t3, t4
173 | andi t5, t5, 0x1
174 | bne t5, zero, OPERATION_DONE # 左侧有墙
175 | # 可以向左移动了 先将本块涂黑
176 | mv a0, a5
177 | mv a1, a6
178 | li a2, 0x0
179 | jal renderSquare
180 | # 更新a5 a6
181 | addi a6, a6, -0x1
182 | j OPERATION_DONE
183 | OP_U:
184 | mv t0, a5
185 | mv t1, a6
186 | li t2, 0
187 | beq a5, t2, OPERATION_DONE # 上侧不能越界
188 | li t2, 31
189 | slli t3, t0, 0x2
190 | add t3, t3, s11
191 | addi t3, t3, -0x4
192 | lw t3, 0(t3)
193 | sub t4, t2, t1
194 | srl t5, t3, t4
195 | andi t5, t5, 0x1
196 | bne t5, zero, OPERATION_DONE # 上侧有墙
197 | # 可以向上移动了 先将本块涂黑
198 | mv a0, a5
199 | mv a1, a6
200 | li a2, 0x0
201 | jal renderSquare
202 | # 更新a5 a6
203 | addi a5, a5, -0x1
204 | j OPERATION_DONE
205 | OP_D:
206 | mv t0, a5
207 | mv t1, a6
208 | li t2, 23
209 | beq a5, t2, OPERATION_DONE # 下侧不能越界
210 | li t2, 31
211 | slli t3, t0, 0x2
212 | add t3, t3, s11
213 | addi t3, t3, 0x4
214 | lw t3, 0(t3)
215 | sub t4, t2, t1
216 | srl t5, t3, t4
217 | andi t5, t5, 0x1
218 | bne t5, zero, OPERATION_DONE # 下侧有墙
219 | # 可以向下移动了 先将本块涂黑
220 | mv a0, a5
221 | mv a1, a6
222 | li a2, 0x0
223 | jal renderSquare
224 | # 更新a5 a6
225 | addi a5, a5, 0x1
226 | j OPERATION_DONE
227 | OPERATION_DONE: # 操作结束 重新renderPerson
228 | jal renderPerson
229 | JUDGE_ROW:
230 | bne a5, zero, JUDGE_FAIL
231 | JUDGE_COL:
232 | li t0, 31
233 | beq a6, t0, SUCCESS
234 | JUDGE_FAIL:
235 | li t0, 0x0
236 | li t1, 0x0000ffff
237 | WATING_LOOP:
238 | addi t0, t0, 1
239 | bne t0, t1, WATING_LOOP
240 | j OPERATION
241 | SUCCESS:
242 | li s0, 30 # 系统调用号
243 | li a0, 0x53
244 | ecall
245 | li a0, 0x55
246 | ecall
247 | li a0, 0x43
248 | ecall
249 | li a0, 0x43
250 | ecall
251 | li a0, 0x45
252 | ecall
253 | li a0, 0x53
254 | ecall
255 | li a0, 0x53
256 | ecall
257 | li a0, 0x21
258 | ecall
259 | mv ra, x4
260 | ret
261 | renderEnd:
262 | li a0, 0
263 | li a1, 31
264 | li a2, 0b00111000
265 | mv s10, ra
266 | jal renderSquare
267 | mv ra, s10
268 | ret
269 |
--------------------------------------------------------------------------------
/img/game.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yueyang2000/riscv-cpu/92b0568dc9a2ad6a7fbdd2a1216109b9e723078d/img/game.jpg
--------------------------------------------------------------------------------
/img/game_demo.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yueyang2000/riscv-cpu/92b0568dc9a2ad6a7fbdd2a1216109b9e723078d/img/game_demo.gif
--------------------------------------------------------------------------------
/img/模块图.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yueyang2000/riscv-cpu/92b0568dc9a2ad6a7fbdd2a1216109b9e723078d/img/模块图.png
--------------------------------------------------------------------------------
/src/SEG7_LUT.v:
--------------------------------------------------------------------------------
1 | module SEG7_LUT ( oSEG1,iDIG );
2 | input wire[3:0] iDIG;
3 | output wire[7:0] oSEG1;
4 | reg [6:0] oSEG;
5 |
6 | always @(iDIG)
7 | begin
8 | case(iDIG)
9 | 4'h1: oSEG = 7'b1110110; // ---t----
10 | 4'h2: oSEG = 7'b0100001; // | |
11 | 4'h3: oSEG = 7'b0100100; // lt rt
12 | 4'h4: oSEG = 7'b0010110; // | |
13 | 4'h5: oSEG = 7'b0001100; // ---m----
14 | 4'h6: oSEG = 7'b0001000; // | |
15 | 4'h7: oSEG = 7'b1100110; // lb rb
16 | 4'h8: oSEG = 7'b0000000; // | |
17 | 4'h9: oSEG = 7'b0000110; // ---b----
18 | 4'ha: oSEG = 7'b0000010;
19 | 4'hb: oSEG = 7'b0011000;
20 | 4'hc: oSEG = 7'b1001001;
21 | 4'hd: oSEG = 7'b0110000;
22 | 4'he: oSEG = 7'b0001001;
23 | 4'hf: oSEG = 7'b0001011;
24 | 4'h0: oSEG = 7'b1000000;
25 | endcase
26 | end
27 |
28 | assign oSEG1 = {~oSEG,1'b0};
29 |
30 | endmodule
31 |
--------------------------------------------------------------------------------
/src/addr_check.v:
--------------------------------------------------------------------------------
1 | `include "defines.vh"
2 | module addr_check(
3 | input wire sv32_en,
4 | input wire[`DataAddrBus] mem_addr,
5 | output wire err,
6 |
7 | input wire mem_rd,
8 | input wire mem_wr,
9 | input wire mem_if
10 | );
11 |
12 | wire mem_acc_fault = mem_addr > 32'h807fffff ? 1'b1 : mem_addr < 32'h10000000 ? 1'b1 : mem_addr <= 32'h10000008 ? 1'b0 :
13 | mem_addr < 32'h80000000 ? 1'b1 : 1'b0;
14 |
15 | wire t1 = mem_addr >= 32'h0 && mem_addr <= 32'h002FFFFF && (mem_if || mem_rd);
16 | wire t2 = mem_addr >= 32'h7FC10000 && mem_addr <= 32'h7FFFFFFF && (mem_wr || mem_rd);
17 | wire t3 = mem_addr >= 32'h80000000 && mem_addr <= 32'h80000FFF && (mem_if || mem_rd);
18 | wire t4 = mem_addr >= 32'h80100000 && mem_addr <= 32'h80100FFF && (mem_if || mem_rd);
19 | wire is_uart = 32'h10000000 <= mem_addr && 32'h10000008 >= mem_addr;
20 | wire is_vga = 32'h20000000 <= mem_addr && mem_addr <= 32'h20075300;
21 | assign err = (is_vga | is_uart ) ? 1'b0 : sv32_en ? ~(t1 | t2 | t3 | t4) : mem_acc_fault;
22 |
23 | endmodule
--------------------------------------------------------------------------------
/src/addr_decode.v:
--------------------------------------------------------------------------------
1 | `include "defines.vh"
2 |
3 | module addr_decode(
4 | input wire[`DataAddrBus] mem_addr,
5 | output reg[1:0] mem_use,
6 | output reg[19:0] ram_addr
7 | );
8 |
9 |
10 | localparam UART_ADDR_PERFIX = 32'h10000000;
11 | localparam VGA_ADDR_PERFIX = 8'h20;
12 | wire[`DataAddrBus] mem_addr_sub = mem_addr - 24'h400000;
13 |
14 | always @(*) begin
15 | mem_use <= `USE_BASE;
16 | // address of lab5 start from 0x0
17 | // address of kernel start from 0x80000000
18 | if(mem_addr[31:3] == UART_ADDR_PERFIX[31:3])
19 | mem_use <= `USE_UART;
20 | else if(mem_addr[31:24] == VGA_ADDR_PERFIX)
21 | mem_use <= `USE_VGA;
22 | else begin
23 | if(mem_addr[23:22] == 2'b00) begin
24 | mem_use <= `USE_BASE;
25 | ram_addr <= mem_addr[21:2];
26 | end
27 | else begin
28 | mem_use <= `USE_EXT;
29 | ram_addr <= mem_addr_sub[21:2];
30 | end
31 | end
32 | end
33 |
34 | endmodule
35 |
--------------------------------------------------------------------------------
/src/async.v:
--------------------------------------------------------------------------------
1 | ////////////////////////////////////////////////////////
2 | // RS-232 RX and TX module
3 | // (c) fpga4fun.com & KNJN LLC - 2003 to 2016
4 |
5 | // The RS-232 settings are fixed
6 | // TX: 8-bit data, 2 stop, no-parity
7 | // RX: 8-bit data, 1 stop, no-parity (the receiver can accept more stop bits of course)
8 |
9 | //`define SIMULATION // in this mode, TX outputs one bit per clock cycle
10 | // and RX receives one bit per clock cycle (for fast simulations)
11 |
12 | ////////////////////////////////////////////////////////
13 |
14 | module async_transmitter(
15 | input wire clk,
16 | input wire TxD_start,
17 | input wire [7:0] TxD_data,
18 | output wire TxD,
19 | output wire TxD_busy
20 | );
21 |
22 | // Assert TxD_start for (at least) one clock cycle to start transmission of TxD_data
23 | // TxD_data is latched so that it doesn't have to stay valid while it is being sent
24 |
25 | parameter ClkFrequency = 25000000; // 25MHz
26 | parameter Baud = 115200;
27 |
28 | // generate
29 | // if(ClkFrequency> 1);
52 |
53 | case(TxD_state)
54 | 4'b0000: if(TxD_start) TxD_state <= 4'b0100;
55 | 4'b0100: if(BitTick) TxD_state <= 4'b1000; // start bit
56 | 4'b1000: if(BitTick) TxD_state <= 4'b1001; // bit 0
57 | 4'b1001: if(BitTick) TxD_state <= 4'b1010; // bit 1
58 | 4'b1010: if(BitTick) TxD_state <= 4'b1011; // bit 2
59 | 4'b1011: if(BitTick) TxD_state <= 4'b1100; // bit 3
60 | 4'b1100: if(BitTick) TxD_state <= 4'b1101; // bit 4
61 | 4'b1101: if(BitTick) TxD_state <= 4'b1110; // bit 5
62 | 4'b1110: if(BitTick) TxD_state <= 4'b1111; // bit 6
63 | 4'b1111: if(BitTick) TxD_state <= 4'b0010; // bit 7
64 | 4'b0010: if(BitTick) TxD_state <= 4'b0000; // stop1
65 | //4'b0011: if(BitTick) TxD_state <= 4'b0000; // stop2
66 | default: if(BitTick) TxD_state <= 4'b0000;
67 | endcase
68 | end
69 |
70 | assign TxD = (TxD_state<4) | (TxD_state[3] & TxD_shift[0]); // put together the start, data and stop bits
71 | endmodule
72 |
73 |
74 | ////////////////////////////////////////////////////////
75 | module async_receiver(
76 | input wire clk,
77 | input wire RxD,
78 | output reg RxD_data_ready,
79 | input wire RxD_clear,
80 | output reg [7:0] RxD_data // data received, valid only (for one clock cycle) when RxD_data_ready is asserted
81 | );
82 |
83 | parameter ClkFrequency = 25000000; // 25MHz
84 | parameter Baud = 115200;
85 |
86 | parameter Oversampling = 8; // needs to be a power of 2
87 | // we oversample the RxD line at a fixed rate to capture each RxD data bit at the "right" time
88 | // 8 times oversampling by default, use 16 for higher quality reception
89 |
90 | // generate
91 | // if(ClkFrequency>log2) log2=log2+1; end endfunction
136 | localparam l2o = log2(Oversampling);
137 | reg [l2o-2:0] OversamplingCnt = 0;
138 | always @(posedge clk) if(OversamplingTick) OversamplingCnt <= (RxD_state==0) ? 1'd0 : OversamplingCnt + 1'd1;
139 | wire sampleNow = OversamplingTick && (OversamplingCnt==Oversampling/2-1);
140 | `endif
141 |
142 | // now we can accumulate the RxD bits in a shift-register
143 | always @(posedge clk)
144 | case(RxD_state)
145 | 4'b0000: if(~RxD_bit) RxD_state <= `ifdef SIMULATION 4'b1000 `else 4'b0001 `endif; // start bit found?
146 | 4'b0001: if(sampleNow) RxD_state <= 4'b1000; // sync start bit to sampleNow
147 | 4'b1000: if(sampleNow) RxD_state <= 4'b1001; // bit 0
148 | 4'b1001: if(sampleNow) RxD_state <= 4'b1010; // bit 1
149 | 4'b1010: if(sampleNow) RxD_state <= 4'b1011; // bit 2
150 | 4'b1011: if(sampleNow) RxD_state <= 4'b1100; // bit 3
151 | 4'b1100: if(sampleNow) RxD_state <= 4'b1101; // bit 4
152 | 4'b1101: if(sampleNow) RxD_state <= 4'b1110; // bit 5
153 | 4'b1110: if(sampleNow) RxD_state <= 4'b1111; // bit 6
154 | 4'b1111: if(sampleNow) RxD_state <= 4'b0010; // bit 7
155 | 4'b0010: if(sampleNow) RxD_state <= 4'b0000; // stop bit
156 | default: RxD_state <= 4'b0000;
157 | endcase
158 |
159 | always @(posedge clk)
160 | if(sampleNow && RxD_state[3]) RxD_data <= {RxD_bit, RxD_data[7:1]};
161 |
162 | //reg RxD_data_error = 0;
163 | always @(posedge clk)
164 | begin
165 | if(RxD_clear)
166 | RxD_data_ready <= 0;
167 | else
168 | RxD_data_ready <= RxD_data_ready | (sampleNow && RxD_state==4'b0010 && RxD_bit); // make sure a stop bit is received
169 | //RxD_data_error <= (sampleNow && RxD_state==4'b0010 && ~RxD_bit); // error if a stop bit is not received
170 | end
171 |
172 | `ifdef SIMULATION
173 | assign RxD_idle = 0;
174 | `else
175 | reg [l2o+1:0] GapCnt = 0;
176 | always @(posedge clk) if (RxD_state!=0) GapCnt<=0; else if(OversamplingTick & ~GapCnt[log2(Oversampling)+1]) GapCnt <= GapCnt + 1'h1;
177 | assign RxD_idle = GapCnt[l2o+1];
178 | always @(posedge clk) RxD_endofpacket <= OversamplingTick & ~GapCnt[l2o+1] & &GapCnt[l2o:0];
179 | `endif
180 |
181 | endmodule
182 |
183 |
184 | ////////////////////////////////////////////////////////
185 | // dummy module used to be able to raise an assertion in Verilog
186 | //module ASSERTION_ERROR();
187 | //endmodule
188 |
189 |
190 | ////////////////////////////////////////////////////////
191 | module BaudTickGen(
192 | input wire clk, enable,
193 | output wire tick // generate a tick at the specified baud rate * oversampling
194 | );
195 | parameter ClkFrequency = 25000000;
196 | parameter Baud = 115200;
197 | parameter Oversampling = 1;
198 |
199 | function integer log2(input integer v); begin log2=0; while(v>>log2) log2=log2+1; end endfunction
200 | localparam AccWidth = log2(ClkFrequency/Baud)+8; // +/- 2% max timing error over a byte
201 | reg [AccWidth:0] Acc = 0;
202 | localparam ShiftLimiter = log2(Baud*Oversampling >> (31-AccWidth)); // this makes sure Inc calculation doesn't overflow
203 | localparam Inc = ((Baud*Oversampling << (AccWidth-ShiftLimiter))+(ClkFrequency>>(ShiftLimiter+1)))/(ClkFrequency>>ShiftLimiter);
204 | always @(posedge clk) if(enable) Acc <= Acc[AccWidth-1:0] + Inc[AccWidth:0]; else Acc <= Inc[AccWidth:0];
205 | assign tick = Acc[AccWidth];
206 | endmodule
207 |
208 |
209 | ////////////////////////////////////////////////////////
210 |
--------------------------------------------------------------------------------
/src/data_loader.v:
--------------------------------------------------------------------------------
1 | `include "defines.vh"
2 |
3 | module data_loader(
4 | input wire[3:0] ram_be_n,
5 | input wire[1:0] mem_use,
6 | input wire[`DataBus] data_base_out,
7 | input wire[`DataBus] data_ext_out,
8 | input wire[7:0] uart_rd,
9 | output reg[`DataBus] data_to_load
10 | );
11 |
12 | wire[`DataBus] data = (mem_use == `USE_BASE)? data_base_out:data_ext_out;
13 | reg sign;
14 | wire[23:0] ext = sign ? 24'hffffff : 24'h0;
15 | always @(*)begin
16 | sign <= 0;
17 | data_to_load <= 32'b0;
18 | if (mem_use == `USE_UART) begin
19 | sign <= uart_rd[7];
20 | data_to_load <= {ext, uart_rd};
21 | end
22 | else begin
23 | case(ram_be_n)
24 | `BE_WORD: begin
25 | data_to_load <= data;
26 | end
27 | `BE_BYTE_0: begin
28 | sign <= data[7];
29 | data_to_load <= {ext, data[7:0]};
30 | end
31 | `BE_BYTE_1: begin
32 | sign <= data[15];
33 | data_to_load <= {ext, data[15:8]};
34 | end
35 | `BE_BYTE_2: begin
36 | sign <= data[23];
37 | data_to_load <= {ext, data[23:16]};
38 | end
39 | `BE_BYTE_3: begin
40 | sign <= data[31];
41 | data_to_load <= {ext, data[31:24]};
42 | end
43 | endcase
44 | end
45 | end
46 |
47 | endmodule
--------------------------------------------------------------------------------
/src/defines.vh:
--------------------------------------------------------------------------------
1 | `define True 1'b1
2 | `define False 1'b0
3 | `define ZeroWord 32'b0
4 |
5 | `define RstEnable 1'b1
6 | `define RstDisable 1'b0
7 | `define WriteEnable 1'b1
8 | `define WriteDisable 1'b0
9 | `define ReadEnable 1'b1
10 | `define ReadDisable 1'b0
11 |
12 | `define RegAddrBus 4:0
13 | `define RegBus 31:0
14 | `define RegNum 32
15 |
16 | `define InstAddrBus 31:0
17 | `define InstBus 31:0
18 | `define InstValid 1'b1
19 | `define InstInvalid 1'b0
20 |
21 | `define DataAddrBus 31:0
22 | `define DataBus 31:0
23 |
24 | `define OP_ARITH 7'b0110011
25 | `define OP_ARITH_I 7'b0010011
26 | `define OP_JAL 7'b1101111
27 | `define OP_JALR 7'b1100111
28 | `define OP_BRANCH 7'b1100011
29 | `define OP_AUIPC 7'b0010111
30 | `define OP_LUI 7'b0110111
31 | `define OP_LOAD 7'b0000011
32 | `define OP_STORE 7'b0100011
33 | `define OP_SYS 7'b1110011
34 |
35 | // funct3 of arith instructions
36 | `define ARITH_ADD 3'b000
37 | `define ARITH_SLL 3'b001
38 | `define ARITH_SLT 3'b010
39 | `define ARITH_SLTU 3'b011
40 | `define ARITH_XOR 3'b100
41 | `define ARITH_SRL 3'b101
42 | `define ARITH_OR 3'b110
43 | `define ARITH_AND 3'b111
44 |
45 | // funct3 of jalr
46 | `define JALR_FUNCT3 3'b000
47 |
48 | // funct7 of arith instructions
49 | `define ARITH_ADD_FUNCT7 7'b0000000
50 | `define ARITH_AND_FUNCT7 7'b0000000
51 | `define ARITH_OR_FUNCT7 7'b0000000
52 | `define ARITH_XOR_FUNCT7 7'b0000000
53 | `define ARITH_SUB_FUNCT7 7'b0100000
54 | `define ARITH_MIN_FUNCT7 7'b0000101
55 | `define ARITH_SRL_FUNCT7 7'b0000000
56 |
57 | // clz ctz prefix
58 | `define CLZ_PREFIX 12'b011000000000
59 | `define CTZ_PREFIX 12'b011000000001
60 |
61 | // funct3 of branch instructions
62 | `define BRANCH_BEQ 3'b000
63 | `define BRANCH_BNE 3'b001
64 | `define BRANCH_BLT 3'b100
65 | `define BRANCH_BGE 3'b101
66 | `define BRANCH_BLTU 3'b110
67 | `define BRANCH_BGEU 3'b111
68 |
69 | // funct3 of Load/Store instructions
70 | `define LS_B 3'b000
71 | `define LS_H 3'b001
72 | `define LS_W 3'b010
73 | `define LS_BU 3'b100
74 | `define LS_HU 3'b101
75 |
76 | // state machine for cpu
77 | `define StateBus 3:0
78 | `define STATE_BOOT 4'b0000
79 | `define STATE_IF 4'b0001
80 | `define STATE_EXE 4'b0010
81 | `define STATE_MEM 4'b0011
82 | `define STATE_WB 4'b0100
83 | `define STATE_EXP 4'b0101
84 |
85 | `define USE_VGA 2'b00
86 | `define USE_BASE 2'b01
87 | `define USE_EXT 2'b10
88 | `define USE_UART 2'b11
89 |
90 | `define START_ADDR 32'h80000000
91 | // `define START_ADDR 32'h0
92 | // uart
93 | `define UART_DATA_ADDR 32'h10000000
94 | `define UART_STATUS_ADDR 32'h10000005
95 | `define BE_WORD 4'b0000
96 | `define BE_BYTE_0 4'b1110
97 | `define BE_BYTE_1 4'b1101
98 | `define BE_BYTE_2 4'b1011
99 | `define BE_BYTE_3 4'b0111
100 |
101 | // exp_code
102 | `define ExpBus 3:0
103 | `define exp_inst_addr_mis 4'b0000
104 | `define exp_inst_acc_fault 4'b0001
105 | `define exp_inst_illegal 4'b0010
106 | `define exp_break 4'b0011
107 | `define exp_load_addr_mis 4'b0100
108 | `define exp_load_acc_fault 4'b0101
109 | `define exp_store_addr_mis 4'b0110
110 | `define exp_store_acc_fault 4'b0111
111 | `define exp_ecall_u 4'b1000
112 | `define exp_ecall_s 4'b1001
113 | `define exp_ecall_m 4'b1011
114 | `define exp_inst_page_fault 4'b1100
115 | `define exp_load_page_fault 4'b1101
116 | `define exp_store_page_fault 4'b1111
117 |
118 | // three type of issue for exp_handle
119 | `define EXP_NONE 2'b00
120 | `define EXP_ERR 2'b01
121 | `define EXP_OP 2'b10
122 |
123 | //ebreak ecall mret prefix
124 | `define EBREAK_PREFIX 25'b0000000000010000000000000
125 | `define ECALL_PREFIX 25'b0000000000000000000000000
126 | `define MRET_PREFIX 25'b0011000000100000000000000
127 |
128 | // csr registers
129 | `define CsrAddrBus 11:0
130 | `define CSR_MSTATUS 12'h300
131 | `define CSR_MTVEC 12'h305
132 | `define CSR_MSCRATCH 12'h340
133 | `define CSR_MEPC 12'h341
134 | `define CSR_MCAUSE 12'h342
135 | `define CSR_MTVAL 12'h343
136 | `define CSR_SATP 12'h180
137 | // csr reg map
138 | `define MTVEC 3'b000
139 | `define MCAUSE 3'b001
140 | `define MEPC 3'b010
141 | `define MTVAL 3'b011
142 | `define MSTATUS 3'b100
143 | `define MSCRATCH 3'b101
144 | `define SATP 3'b110
145 | `define NO_CSR 3'b111
146 | // funct3 of exception
147 | `define EXP_CSRRC 3'b011
148 | `define EXP_CSRRS 3'b010
149 | `define EXP_CSRRW 3'b001
150 |
151 | // mode
152 | `define U_MODE 2'b00
153 | `define S_MODE 2'b01
154 | `define M_MODE 2'b11
155 |
156 | `define BTN_ADDR 32'h20075300
--------------------------------------------------------------------------------
/src/exe.v:
--------------------------------------------------------------------------------
1 | `include "defines.vh"
2 |
3 | module exe(
4 | input wire[`InstAddrBus] pc,
5 | input wire[`InstBus] inst,
6 | input wire[`RegBus] reg1_data_i,
7 | input wire[`RegBus] reg2_data_i,
8 | output wire[`RegAddrBus] reg1_addr_o,
9 | output wire[`RegAddrBus] reg2_addr_o,
10 | output reg instValid,
11 |
12 | output reg branch,// 是否要分支跳转
13 | output reg[`InstAddrBus] branch_addr, // 跳转到的地址
14 |
15 | output reg mem_rd, //是否要读内存
16 |
17 | output reg mem_wr, // 是否要写内存
18 | output reg[`DataBus] mem_wr_data,
19 | output reg[`DataAddrBus] mem_addr,
20 |
21 | output reg wb, // 是否要写回
22 | output wire[`RegAddrBus] wb_reg_addr,
23 | output reg[`DataBus] wb_data,
24 |
25 | output reg[3:0] ram_be_n
26 | );
27 |
28 |
29 | wire[6:0] op = inst[6:0];
30 | assign reg1_addr_o = inst[19:15]; // rs1
31 | assign reg2_addr_o =inst[24:20]; // rs2
32 | assign wb_reg_addr = inst[11:7]; // rd
33 |
34 | wire[11:0] rawI = inst[31:20];
35 | wire[19:0] extI = rawI[11] ? 20'hfffff: 20'h0;
36 | wire[`RegBus] immI = {extI, rawI};
37 |
38 |
39 | wire[4:0] shamt = inst[24:20]; // SLLI SRLI 移位立即数
40 |
41 | wire[11:0] rawS = {inst[31:25], inst[11:7]};
42 | wire[19:0] extS = rawS[11] ? 20'hfffff: 20'h0;
43 | wire[`RegBus] immS = {extS, rawS};
44 |
45 | wire[12:0] rawB = {inst[31], inst[7], inst[30 : 25], inst[11 : 8], 1'b0};
46 | wire[18:0] extB = rawB[12] ? 19'hfffff: 19'h0;
47 | wire[`RegBus] immB = {extB, rawB};
48 |
49 | wire[`RegBus] immU = {inst[31:12], 12'b0};
50 |
51 | wire[20:0] rawJ = {inst[31], inst[19:12], inst[20], inst[30:21], 1'b0};
52 | wire[10:0] extJ = rawJ[20] ? 11'hffff: 11'h0;
53 | wire[`RegBus] immJ = {extJ, rawJ};
54 |
55 | wire [2:0] funct3 = inst[14:12];
56 | wire [6:0] funct7 = inst[31:25];
57 |
58 | wire[1:0] mem_addr_offset = mem_addr - { mem_addr[31:2], 2'b0 };
59 |
60 | wire[`DataBus] clz_result = reg1_data_i[31] ? 0 : reg1_data_i[30] ? 1 : reg1_data_i[29] ? 2 :
61 | reg1_data_i[28] ? 3 : reg1_data_i[27] ? 4 : reg1_data_i[26] ? 5 :
62 | reg1_data_i[25] ? 6 : reg1_data_i[24] ? 7 : reg1_data_i[23] ? 8 :
63 | reg1_data_i[22] ? 9 : reg1_data_i[21] ? 10 : reg1_data_i[20] ? 11 :
64 | reg1_data_i[19] ? 12 : reg1_data_i[18] ? 13 : reg1_data_i[17] ? 14 :
65 | reg1_data_i[16] ? 15 : reg1_data_i[15] ? 16 : reg1_data_i[14] ? 17 :
66 | reg1_data_i[13] ? 18 : reg1_data_i[12] ? 19 : reg1_data_i[11] ? 20 :
67 | reg1_data_i[10] ? 21 : reg1_data_i[9] ? 22 : reg1_data_i[8] ? 23 :
68 | reg1_data_i[7] ? 24 : reg1_data_i[6] ? 25 : reg1_data_i[5] ? 26 :
69 | reg1_data_i[4] ? 27 : reg1_data_i[3] ? 28 : reg1_data_i[2] ? 29 :
70 | reg1_data_i[1] ? 30 : reg1_data_i[0] ? 31 : 32;
71 | wire[`DataBus] ctz_result = reg1_data_i[0] ? 0 : reg1_data_i[1] ? 1 : reg1_data_i[2] ? 2 :
72 | reg1_data_i[3] ? 3 : reg1_data_i[4] ? 4 : reg1_data_i[5] ? 5 :
73 | reg1_data_i[6] ? 6 : reg1_data_i[7] ? 7 : reg1_data_i[8] ? 8 :
74 | reg1_data_i[9] ? 9 : reg1_data_i[10] ? 10 : reg1_data_i[11] ? 11 :
75 | reg1_data_i[12] ? 12 : reg1_data_i[13] ? 13 : reg1_data_i[14] ? 14 :
76 | reg1_data_i[15] ? 15 : reg1_data_i[16] ? 16 : reg1_data_i[17] ? 17 :
77 | reg1_data_i[18] ? 18 : reg1_data_i[19] ? 19 : reg1_data_i[20] ? 20 :
78 | reg1_data_i[21] ? 21 : reg1_data_i[22] ? 22 : reg1_data_i[23] ? 23 :
79 | reg1_data_i[24] ? 24 : reg1_data_i[25] ? 25 : reg1_data_i[26] ? 26 :
80 | reg1_data_i[27] ? 27 : reg1_data_i[28] ? 28 : reg1_data_i[29] ? 29 :
81 | reg1_data_i[30] ? 30 : reg1_data_i[31] ? 31 : 32;
82 | wire[`RegBus] min_result = {reg1_data_i[31], reg2_data_i[31]} == 2'b01 ? reg2_data_i : {reg1_data_i[31], reg2_data_i[31]} == 2'b10 ? reg1_data_i :
83 | reg1_data_i < reg2_data_i ? reg1_data_i : reg2_data_i;
84 |
85 |
86 | wire[`DataBus] add_result = reg1_data_i + reg2_data_i;
87 | wire[`DataBus] sub_result = reg1_data_i - reg2_data_i;
88 | wire[`DataBus] and_result = reg1_data_i & reg2_data_i;
89 | wire[`DataBus] or_result = reg1_data_i | reg2_data_i;
90 | wire[`DataBus] xor_result = reg1_data_i ^ reg2_data_i;
91 | wire[`DataBus] srl_result = reg1_data_i >> reg2_data_i[4:0];
92 | wire[`DataBus] ori_result = reg1_data_i | immI;
93 | wire[`DataBus] addi_result = reg1_data_i + immI;
94 | wire[`DataBus] andi_result = reg1_data_i & immI;
95 | wire[`DataBus] slli_result = reg1_data_i << shamt;
96 | wire[`DataBus] srli_result = reg1_data_i >> shamt;
97 | wire[`DataBus] b_addr = pc + immB;
98 | wire[`DataBus] jal_addr = pc + immJ;
99 | wire[`DataBus] jalr_addr= reg1_data_i + immI;
100 | wire[`DataBus] auipc_addr = pc + immU;
101 | wire[`DataBus] load_addr = reg1_data_i + immI;
102 | wire[`DataBus] store_addr = reg1_data_i + immS;
103 | wire[`DataBus] store_byte0 = {24'b0, reg2_data_i[7:0]};
104 | wire[`DataBus] store_byte1 = {16'b0, reg2_data_i[7:0], 8'b0};
105 | wire[`DataBus] store_byte2 = {8'b0, reg2_data_i[7:0], 16'b0};
106 | wire[`DataBus] store_byte3 = {reg2_data_i[7:0], 24'b0};
107 |
108 | always @(*) begin
109 | instValid <= 1;
110 | mem_rd <= 0;
111 | mem_wr <= 0;
112 | mem_wr_data <= 0;
113 | mem_addr <= 0;
114 | wb <= 0;
115 | wb_data <= 0;
116 | branch <= 0;
117 | branch_addr <= 0;
118 | ram_be_n <= 4'b0000;
119 | case (op)
120 | `OP_ARITH: begin
121 | wb <= 1;
122 | case(funct3)
123 | `ARITH_ADD: begin
124 | if(funct7 == `ARITH_SUB_FUNCT7) begin
125 | wb_data <= sub_result; // SUB
126 | end
127 | else if(funct7 == `ARITH_ADD_FUNCT7)begin
128 | wb_data <= add_result; // ADD
129 | end
130 | else begin
131 | instValid <= 0;
132 | end
133 | end
134 | `ARITH_AND: begin
135 | if(funct7 == `ARITH_AND_FUNCT7) begin
136 | wb_data <= and_result;
137 | end
138 | else begin
139 | instValid <= 0;
140 | end
141 | end
142 | `ARITH_OR: begin
143 | if(funct7 == `ARITH_OR_FUNCT7) begin
144 | wb_data <= or_result;
145 | end
146 | else begin
147 | instValid <= 0;
148 | end
149 | end
150 | `ARITH_XOR: begin
151 | if(funct7 == `ARITH_MIN_FUNCT7)begin
152 | wb_data <= min_result;
153 | end
154 | else if (funct7 == `ARITH_XOR_FUNCT7)begin
155 | wb_data <= xor_result;
156 | end
157 | else begin
158 | instValid <= 0;
159 | end
160 | end
161 | `ARITH_SRL: begin
162 | if(funct7 == `ARITH_SRL_FUNCT7)begin
163 | wb_data <= srl_result;
164 | end
165 | else begin
166 | instValid <= 0;
167 | end
168 | end
169 | default:
170 | instValid <= 0;
171 | endcase
172 | end
173 | `OP_ARITH_I: begin
174 | wb <= 1;
175 | case(funct3)
176 | `ARITH_OR: begin
177 | wb_data <= ori_result;
178 | end
179 | `ARITH_ADD: begin
180 | wb_data <= addi_result;
181 | end
182 | `ARITH_AND: begin
183 | wb_data <= andi_result;
184 | end
185 | `ARITH_SLL: begin
186 | if(inst[31:20] == `CLZ_PREFIX) begin
187 | wb_data <= clz_result;
188 | end
189 | else if(inst[31:20] == `CTZ_PREFIX)begin
190 | wb_data <= ctz_result;
191 | end
192 | else begin
193 | wb_data <= slli_result;
194 | end
195 | end
196 | `ARITH_SRL: begin
197 | wb_data <= srli_result;
198 | end
199 | default:
200 | instValid <= 0;
201 | endcase
202 | end
203 | `OP_BRANCH: begin
204 | case(funct3)
205 | `BRANCH_BEQ: begin
206 | if(reg1_data_i == reg2_data_i) begin
207 | branch <= 1;
208 | branch_addr <= b_addr;
209 | end
210 | end
211 | `BRANCH_BNE: begin
212 | if(reg1_data_i != reg2_data_i) begin
213 | branch <= 1;
214 | branch_addr <= b_addr;
215 | end
216 | end
217 | default:
218 | instValid <= 0;
219 | endcase
220 | end
221 | `OP_JAL: begin
222 | wb <= 1;
223 | wb_data <= pc + 4;
224 | branch <= 1;
225 | branch_addr <= jal_addr;
226 | end
227 | `OP_JALR: begin
228 | if(funct3 == `JALR_FUNCT3) begin
229 | wb <= 1;
230 | wb_data <= pc + 4;
231 | branch <= 1;
232 | branch_addr <= jalr_addr; // 应该是取高31位拼0,但是由于RAM读取的时候忽略低两位,因此没必要去拼0
233 | end
234 | else begin
235 | instValid <= 0;
236 | end
237 | end
238 | `OP_LUI: begin
239 | wb <= 1;
240 | wb_data <= immU;
241 | end
242 | `OP_AUIPC: begin
243 | wb <= 1;
244 | wb_data <= auipc_addr;
245 | end
246 | `OP_LOAD: begin
247 | wb <= 1;
248 | mem_rd <= 1;
249 | mem_addr <= load_addr;
250 | case(funct3)
251 | `LS_W: begin
252 | ram_be_n <= `BE_WORD;
253 | end
254 | `LS_B: begin
255 | case(mem_addr_offset)
256 | 2'b0:begin
257 | ram_be_n <= `BE_BYTE_0;
258 | end
259 | 2'b01:begin
260 | ram_be_n <= `BE_BYTE_1;
261 | end
262 | 2'b10:begin
263 | ram_be_n <= `BE_BYTE_2;
264 | end
265 | 2'b11:begin
266 | ram_be_n <= `BE_BYTE_3;
267 | end
268 | endcase
269 | end
270 | default:
271 | instValid <= 0;
272 | endcase
273 | end
274 | `OP_STORE: begin
275 | mem_wr <= 1;
276 | mem_addr <=store_addr;
277 | case (funct3)
278 | `LS_W:begin
279 | ram_be_n <= `BE_WORD;
280 | mem_wr_data <= reg2_data_i;
281 | end
282 | `LS_B: begin
283 | case(mem_addr_offset)
284 | 2'b0:begin
285 | ram_be_n <= `BE_BYTE_0;
286 | mem_wr_data <= store_byte0;
287 | end
288 | 2'b01:begin
289 | ram_be_n <= `BE_BYTE_1;
290 | mem_wr_data <= store_byte1;
291 | end
292 | 2'b10:begin
293 | ram_be_n <= `BE_BYTE_2;
294 | mem_wr_data <= store_byte2;
295 | end
296 | 2'b11:begin
297 | ram_be_n <= `BE_BYTE_3;
298 | mem_wr_data <= store_byte3;
299 | end
300 | endcase
301 | end
302 | default:
303 | instValid <= 0;
304 | endcase
305 | end
306 | `OP_SYS:begin //交给exp_handle去处理
307 | instValid <= 1;
308 | end
309 | default:
310 | instValid <= 0;
311 | endcase
312 | end
313 |
314 | endmodule
315 |
--------------------------------------------------------------------------------
/src/exp_exe.v:
--------------------------------------------------------------------------------
1 | `include "defines.vh"
2 | // exe阶段的异常检查
3 | module exp_exe(
4 | input wire[`InstBus] inst,
5 | input wire instValid,
6 | input wire mem_rd,
7 | input wire mem_wr,
8 | input wire[3:0] ram_be_n, // determine lw
9 | input wire[`DataBus] mem_addr,
10 | output reg[1:0] exception,
11 | output reg[`ExpBus] exp_code,
12 | input wire sv32_en
13 | );
14 |
15 | wire err;
16 | addr_check _addr_check(
17 | .sv32_en(sv32_en),
18 | .mem_addr(mem_addr),
19 | .err(err),
20 | .mem_rd(mem_rd),
21 | .mem_wr(mem_wr),
22 | .mem_if(1'b0)
23 | );
24 |
25 | wire[6:0] op = inst[6:0];
26 | //是否为 CSRRC CSRRS CSRRW
27 | wire csr_op = inst[14:12] == 3'b011 ? 1'b1 : inst[14:12] == 3'b010 ? 1'b1 : inst[14:12] == 3'b001 ? 1'b1 : 1'b0;
28 | wire is_sfence = (inst[31:25] == 7'b0001001) && (inst[14:7] == 8'b0);
29 |
30 | //是否为 EBREAK ECALL MRET
31 | wire other_op = inst[31:7] == `EBREAK_PREFIX ? 1'b1 : inst[31:7] == `ECALL_PREFIX ? 1'b1 : inst[31:7] == `MRET_PREFIX ? 1'b1 : 1'b0;
32 | wire mem_acc_fault = mem_addr > 32'h807fffff ? 1'b1 : mem_addr < 32'h10000000 ? 1'b1 : mem_addr <= 32'h10000008 ? 1'b0 :
33 | mem_addr < 32'h80000000 ? 1'b1 : 1'b0;
34 | always @(*) begin
35 | exp_code <= 4'b1110; // exp_code that does not count
36 | exception <= `EXP_ERR; // default: exception happened
37 | if(op == `OP_SYS) begin
38 | if(is_sfence || csr_op || other_op)
39 | exception <= `EXP_OP;
40 | else begin
41 | exception <= `EXP_ERR;
42 | exp_code <= `exp_inst_illegal;
43 | end
44 | end
45 | else begin
46 | // 以此类推,确定exp_code和exception的值
47 | if (!instValid) begin
48 | exp_code <= `exp_inst_illegal;
49 | end
50 | else if(err)begin
51 | if(mem_rd) begin
52 | if(sv32_en)
53 | exp_code <= `exp_load_page_fault;
54 | else
55 | exp_code <= `exp_load_acc_fault;
56 | end
57 | else if(mem_wr) begin
58 | if(sv32_en)
59 | exp_code <= `exp_store_page_fault;
60 | else
61 | exp_code <= `exp_store_acc_fault;
62 | end
63 | else
64 | exception <= `EXP_NONE;
65 | end
66 | else if(mem_addr[1:0] != 2'b00 && ram_be_n == `BE_WORD) begin
67 | if(mem_rd)
68 | exp_code <= `exp_load_addr_mis;
69 | else if(mem_wr)
70 | exp_code <= `exp_store_addr_mis;
71 | else
72 | exception <= `EXP_NONE;
73 | end
74 | else begin
75 | exception <= `EXP_NONE;
76 | end
77 | end
78 | end
79 |
80 | endmodule
--------------------------------------------------------------------------------
/src/exp_handle.v:
--------------------------------------------------------------------------------
1 | `include "defines.vh"
2 | module exp_handle(
3 | input wire clk,
4 | input wire rst,
5 | input wire [1:0] exception,
6 | input wire[`ExpBus] exp_code,
7 | input wire[`InstBus] inst,
8 | input wire[`InstAddrBus] pc,
9 | input wire[`DataAddrBus] mem_addr,
10 | input wire csr_we,
11 |
12 | input wire[`DataBus] reg_data_i,
13 | output wire[`RegAddrBus] reg_addr_o,
14 |
15 | output reg ebranch,
16 | output reg[`InstAddrBus] ebranch_addr,
17 |
18 | output reg wb_reg,
19 | output wire[`RegAddrBus] wb_reg_addr,
20 | output reg[`DataBus] wb_reg_data,
21 |
22 | output wire sv32_en,
23 | output wire[21:0] satp_ppn
24 | );
25 | assign satp_ppn = csr[`SATP][21:0];
26 | assign sv32_en = csr[`SATP][31] && curr_mode == `U_MODE;
27 | assign reg_addr_o = inst[19:15];
28 | wire [2:0] funct3 = inst[14:12];
29 | assign wb_reg_addr = inst[11:7];
30 | // 0-mtvec 1-mcause 2-mepc 3-mtval 4-mstatus 5-mscratch
31 | reg[`RegBus] csr[0:7];
32 | reg[1:0] curr_mode;
33 | reg[1:0] curr_mode_to_write;
34 | wire[`CsrAddrBus] csr_addr = inst[31:20];
35 | wire[2:0] csr_addr_map = is_mtvec ? `MTVEC : is_mcause ? `MCAUSE : is_mepc ? `MEPC :
36 | is_mtval ? `MTVAL : is_mstatus ? `MSTATUS : is_mscratch ? `MSCRATCH : is_satp? `SATP: `NO_CSR;
37 | wire is_ebreak = inst[31:7] == `EBREAK_PREFIX;
38 | wire is_ecall = inst[31:7] == `ECALL_PREFIX;
39 | wire is_mret = inst[31:7] == `MRET_PREFIX;
40 | wire is_mtvec = csr_addr == `CSR_MTVEC;
41 | wire is_mcause = csr_addr == `CSR_MCAUSE;
42 | wire is_mepc = csr_addr == `CSR_MEPC;
43 | wire is_mtval = csr_addr == `CSR_MTVAL;
44 | wire is_mstatus = csr_addr == `CSR_MSTATUS;
45 | wire is_mscratch = csr_addr == `CSR_MSCRATCH;
46 | wire is_satp = csr_addr == `CSR_SATP;
47 | wire[`RegBus] mstatus_update = {csr_to_write[`MSTATUS][31:13], curr_mode, csr_to_write[`MSTATUS][10:0]};
48 |
49 | // 异常处理后csr寄存器的新值
50 | reg[`RegBus] csr_to_write[0:7];
51 |
52 | // sfence.vma
53 | wire is_sfence = (inst[31:25] == 7'b0001001) && (inst[14:7] == 8'b0);
54 |
55 | always @(*) begin
56 | // 默认不做任何更新
57 | csr_to_write[`SATP] <= csr[`SATP];
58 | csr_to_write[`MTVEC] <= csr[`MTVEC];
59 | csr_to_write[`MCAUSE] <= csr[`MCAUSE];
60 | csr_to_write[`MEPC] <= csr[`MEPC];
61 | csr_to_write[`MTVAL] <= csr[`MTVAL];
62 | csr_to_write[`MSTATUS] <= csr[`MSTATUS];
63 | csr_to_write[`MSCRATCH] <= csr[`MSCRATCH];
64 | curr_mode_to_write <= curr_mode;
65 |
66 | ebranch <= 0;
67 | ebranch_addr <= 0;
68 | wb_reg <= 0;
69 | wb_reg_data <= 0;
70 | if (exception == `EXP_OP) begin
71 | ebranch <= 0;
72 | // ecall 只实现了U模式的30:sys_putc
73 | if(funct3 == `EXP_CSRRC) begin
74 | csr_to_write[csr_addr_map] <= csr[csr_addr_map] & (~reg_data_i);
75 | wb_reg <= 1;
76 | wb_reg_data <= csr[csr_addr_map];
77 | end
78 | else if(funct3 == `EXP_CSRRS) begin
79 | csr_to_write[csr_addr_map] <= csr[csr_addr_map] | reg_data_i;
80 | wb_reg <= 1;
81 | wb_reg_data <= csr[csr_addr_map];
82 | end
83 | else if(funct3 == `EXP_CSRRW) begin
84 | csr_to_write[csr_addr_map] <= reg_data_i;
85 | wb_reg <= 1;
86 | wb_reg_data <= csr[csr_addr_map];
87 | end
88 | else if(is_sfence) begin
89 | // do nothing
90 | ebranch <= 0;
91 | end
92 | else if(is_ebreak) begin
93 | ebranch <= 1;
94 | ebranch_addr <= csr[`MTVEC];
95 | csr_to_write[`MCAUSE] <= `exp_break;
96 | csr_to_write[`MEPC] <= pc;
97 | csr_to_write[`MSTATUS] <= mstatus_update;
98 | curr_mode_to_write <= `M_MODE;
99 | end
100 | else if(is_ecall) begin
101 | ebranch <= 1;
102 | ebranch_addr <= csr[`MTVEC];
103 | csr_to_write[`MCAUSE] <= `exp_ecall_u;
104 | csr_to_write[`MEPC] <= pc;
105 | csr_to_write[`MSTATUS] <= mstatus_update;
106 | curr_mode_to_write <= `M_MODE;
107 | end
108 | else if(is_mret) begin
109 | ebranch <= 1;
110 | ebranch_addr <= csr[`MEPC];
111 | curr_mode_to_write <= csr[`MSTATUS][12:11];
112 | end
113 | else begin
114 | ebranch <= 1;
115 | ebranch_addr <= csr[`MTVEC];
116 | csr_to_write[`MCAUSE] <= `exp_inst_illegal;
117 | csr_to_write[`MTVAL] <= inst;
118 | csr_to_write[`MEPC] <= pc;
119 | csr_to_write[`MSTATUS] <= mstatus_update;
120 | curr_mode_to_write <= `M_MODE;
121 | end
122 | end
123 | else begin
124 | // EXP_ERR
125 | // 这些都是fatal
126 | ebranch <= 1;
127 | ebranch_addr <= csr[`MTVEC];
128 | csr_to_write[`MCAUSE] <= exp_code;
129 | csr_to_write[`MSTATUS] <= mstatus_update;
130 | curr_mode_to_write <= `M_MODE;
131 | case(exp_code)
132 | `exp_inst_addr_mis:begin
133 | csr_to_write[`MTVAL] <= pc;
134 | end
135 | `exp_inst_acc_fault:begin
136 | csr_to_write[`MTVAL] <= pc;
137 | end
138 | `exp_inst_illegal:begin
139 | csr_to_write[`MTVAL] <= inst;
140 | end
141 | `exp_load_addr_mis:begin
142 | csr_to_write[`MTVAL] <= mem_addr;
143 | end
144 | `exp_load_acc_fault:begin
145 | csr_to_write[`MTVAL] <= mem_addr;
146 | end
147 | `exp_store_addr_mis:begin
148 | csr_to_write[`MTVAL] <= mem_addr;
149 | end
150 | `exp_store_acc_fault:begin
151 | csr_to_write[`MTVAL] <= mem_addr;
152 | end
153 | `exp_inst_page_fault:begin
154 | csr_to_write[`MTVAL] <= pc;
155 | end
156 | `exp_load_page_fault:begin
157 | csr_to_write[`MTVAL] <= mem_addr;
158 | end
159 | `exp_store_page_fault:begin
160 | csr_to_write[`MTVAL] <= mem_addr;
161 | end
162 | endcase
163 | csr_to_write[`MEPC] <= pc;
164 | end
165 | end
166 |
167 | always @(posedge clk or posedge rst) begin
168 | if(rst) begin
169 | csr[`SATP] <= `ZeroWord;
170 | csr[`MTVEC] <= `ZeroWord;
171 | csr[`MCAUSE] <= `ZeroWord;
172 | csr[`MEPC] <= `ZeroWord;
173 | csr[`MTVAL] <= `ZeroWord;
174 | // M-mode启动
175 | curr_mode <= `M_MODE;
176 | csr[`MSTATUS] <= `ZeroWord;
177 | csr[`MSCRATCH] <= `ZeroWord;
178 | end
179 | else if(csr_we) begin
180 | csr[`SATP] <= csr_to_write[`SATP];
181 | csr[`MTVEC] <= csr_to_write[`MTVEC];
182 | csr[`MCAUSE] <= csr_to_write[`MCAUSE];
183 | csr[`MEPC] <= csr_to_write[`MEPC];
184 | csr[`MTVAL] <= csr_to_write[`MTVAL];
185 | csr[`MSTATUS] <= csr_to_write[`MSTATUS];
186 | csr[`MSCRATCH] <= csr_to_write[`MSCRATCH];
187 | curr_mode <= curr_mode_to_write;
188 | end
189 | end
190 | endmodule
--------------------------------------------------------------------------------
/src/exp_if.v:
--------------------------------------------------------------------------------
1 | `include "defines.vh"
2 | // if 阶段的异常检查
3 | module exp_if(
4 | input wire[`InstAddrBus] if_addr,
5 | input wire[1:0] curr_mode,
6 | input wire sv32_en,
7 | output reg[1:0] exception,
8 | output reg[`ExpBus] exp_code
9 | );
10 |
11 | wire err;
12 | addr_check _addr_check(
13 | .sv32_en(sv32_en),
14 | .mem_addr(if_addr),
15 | .err(err),
16 | .mem_rd(1'b0),
17 | .mem_wr(1'b0),
18 | .mem_if(1'b1)
19 | );
20 | // wire inst_acc_fault = if_addr > 32'h807fffff ? 1'b1 : if_addr < 32'h80000000 ? 1'b1 : 1'b0;
21 |
22 | always @(*) begin
23 | exception <= `EXP_NONE; // default no exception
24 | exp_code <= 4'b1110; // exp_code that does not count
25 | // add code to determine whether if addr is valid
26 | if(err) begin
27 | exception <= `EXP_ERR;
28 | if(~sv32_en)
29 | exp_code <= `exp_inst_acc_fault;
30 | else
31 | exp_code <= `exp_inst_page_fault;
32 | end
33 | else if (if_addr[1:0]!= 2'b00) begin
34 | exception <= `EXP_ERR;
35 | exp_code <= `exp_inst_addr_mis;
36 | end
37 | end
38 |
39 | endmodule
--------------------------------------------------------------------------------
/src/mem_controller.v:
--------------------------------------------------------------------------------
1 | `include "defines.vh"
2 | module mem_controller(
3 | input wire clk,
4 | input wire rst,
5 | //BaseRAM信号
6 | inout wire[31:0] base_ram_data, //BaseRAM数据,低8位与CPLD串口控制器共享
7 | output wire[19:0] base_ram_addr, //BaseRAM地址
8 | output wire[3:0] base_ram_be_n, //BaseRAM字节使能,低有效。如果不使用字节使能,请保持为0
9 | output wire base_ram_ce_n, //BaseRAM片选,低有效
10 | output wire base_ram_oe_n, //BaseRAM读使能,低有效
11 | output wire base_ram_we_n, //BaseRAM写使能,低有效
12 |
13 | //ExtRAM信号
14 | inout wire[31:0] ext_ram_data, //ExtRAM数据
15 | output wire[19:0] ext_ram_addr, //ExtRAM地址
16 | output wire[3:0] ext_ram_be_n, //ExtRAM字节使能,低有效。如果不使用字节使能,请保持为0
17 | output wire ext_ram_ce_n, //ExtRAM片选,低有效
18 | output wire ext_ram_oe_n, //ExtRAM读使能,低有效
19 | output wire ext_ram_we_n, //ExtRAM写使能,低有效
20 |
21 | //CPLD串口控制器信号
22 | output wire uart_rdn, //读串口信号,低有效
23 | output wire uart_wrn, //写串口信号,低有效
24 | input wire uart_dataready, //串口数据准备好
25 | input wire uart_tbre, //发送数据标志
26 | input wire uart_tsre, //数据发送完毕标志
27 |
28 | // cpu 控制读写逻辑信号
29 | input wire oen,
30 | input wire wen,
31 | input wire[3:0] ram_be_n,
32 | input wire[`DataAddrBus] mem_addr,
33 | input wire[`DataBus] data_in,
34 | output reg[`DataBus] data_out,
35 | output wire done,
36 |
37 | input wire sv32_en,
38 | input wire[21:0] satp_ppn,
39 |
40 | // gram控制信号
41 | output reg gram_we_n,
42 | output reg[7:0] gram_wr_data,
43 | output wire[18:0] gram_wr_addr,
44 | input wire[3:0] touch_btn
45 | );
46 | // ===== 串口 =====
47 | reg oe_uart_n, we_uart_n;
48 | reg[7:0] data_uart_in;
49 | wire[7:0] data_uart_out;
50 | wire uart_done;
51 | uart_io _uart_io(
52 | .clk(clk),
53 | .rst(rst),
54 | .oen(oe_uart_n),
55 | .wen(we_uart_n),
56 | .data_in(data_uart_in),
57 | .data_out(data_uart_out),
58 | .done(uart_done),
59 | .base_ram_data_wire(base_ram_data),
60 | .uart_rdn(uart_rdn),
61 | .uart_wrn(uart_wrn),
62 | .uart_dataready(uart_dataready),
63 | .uart_tbre(uart_tbre),
64 | .uart_tsre(uart_tsre)
65 | );
66 | // ===== 存储设备 =====
67 | wire[`DataBus] data_base_out;
68 | wire base_done;
69 | reg oe_base_n, we_base_n;
70 | reg[19:0] base_address; // 喂给base_ram的地址
71 | assign base_ram_addr = base_address;
72 | reg[`DataBus] data_base_in;
73 | reg[3:0] base_ram_be_reg;
74 | assign base_ram_be_n = base_ram_be_reg;
75 | sram_io base_ram_io(
76 | .clk(clk),
77 | .rst(rst),
78 | .oen(oe_base_n),
79 | .wen(we_base_n),
80 | .data_in(data_base_in),
81 | .data_out(data_base_out),
82 | .done(base_done),
83 | .ram_data_wire(base_ram_data),
84 | .ram_ce_n(base_ram_ce_n),
85 | .ram_oe_n(base_ram_oe_n),
86 | .ram_we_n(base_ram_we_n)
87 | );
88 |
89 | wire[`DataBus] data_ext_out;
90 | wire ext_done;
91 | reg oe_ext_n, we_ext_n;
92 | reg[19:0] ext_address; // 喂给ext_ram的地址
93 | assign ext_ram_addr = ext_address;
94 | reg[`DataBus] data_ext_in;
95 | reg[3:0] ext_ram_be_reg;
96 | assign ext_ram_be_n = ext_ram_be_reg;
97 | sram_io ext_ram_io(
98 | .clk(clk),
99 | .rst(rst),
100 | .oen(oe_ext_n),
101 | .wen(we_ext_n),
102 | .data_in(data_ext_in),
103 | .data_out(data_ext_out),
104 | .done(ext_done),
105 | .ram_data_wire(ext_ram_data),
106 | .ram_ce_n(ext_ram_ce_n),
107 | .ram_oe_n(ext_ram_oe_n),
108 | .ram_we_n(ext_ram_we_n)
109 | );
110 |
111 | wire [1:0] mem_use;
112 | wire [19:0] ram_addr;
113 | addr_decode _addr_decode(
114 | .mem_addr(phy_addr),
115 | .mem_use(mem_use),
116 | .ram_addr(ram_addr)
117 | );
118 | // 包含字节使能的判断,符号扩展
119 | wire[`DataBus] data_to_load;
120 | wire[7:0] uart_status = {2'b0, 1'b1, 4'b0, uart_dataready};
121 | data_loader _data_loader(
122 | .ram_be_n(ram_be_n),
123 | .mem_use(mem_use),
124 | .data_base_out(data_base_out),
125 | .data_ext_out(data_ext_out),
126 | .uart_rd(data_uart_out),
127 | .data_to_load(data_to_load)
128 | );
129 |
130 | // // 用户态地址映射(硬编码)
131 | // wire[`DataAddrBus] phy_addr;
132 | // mmu _mmu(
133 | // .sv32_en(sv32_en),
134 | // .addr_i(mem_addr),
135 | // .addr_o(phy_addr)
136 | // );
137 |
138 | // 用户态地址映射(查页表)
139 | reg[`DataAddrBus] phy_addr;
140 |
141 | // 低19位用于gram地址映射
142 | assign gram_wr_addr = mem_addr[18:0];
143 |
144 | wire[`DataAddrBus] page1_addr = {satp_ppn[19:0], mem_addr[31:22], 2'b0};
145 | wire[`DataBus] page_entry = data_base_out;
146 | wire is_uart = 32'h10000000 <= mem_addr && 32'h10000008 >= mem_addr;
147 | wire is_vga = 32'h20000000 <= mem_addr && mem_addr <= 32'h20075300;
148 | reg[2:0] state;
149 | localparam STATE_IDLE = 3'b000;
150 | localparam STATE_READ = 3'b001;
151 | localparam STATE_WRITE = 3'b010;
152 | localparam STATE_START = 3'b011;
153 | localparam STATE_PAGE_1 = 3'b100;
154 | localparam STATE_PAGE_2 = 3'b101;
155 | localparam STATE_PAGE_3 = 3'b110;
156 | localparam STATE_DONE = 3'b111;
157 | assign done = state == STATE_DONE;
158 |
159 | always @(posedge clk or posedge rst) begin
160 | if(rst) begin
161 | state <= STATE_IDLE;
162 | {oe_base_n, we_base_n} <= 2'b11;
163 | {oe_ext_n, we_ext_n} <= 2'b11;
164 | {oe_uart_n, we_uart_n} <= 2'b11;
165 |
166 | base_address <= 20'b0;
167 | ext_address <= 20'b0;
168 | data_base_in <= 32'b0;
169 | data_ext_in <= 32'b0;
170 | base_ram_be_reg <= 4'b0;
171 | ext_ram_be_reg <= 4'b0;
172 | data_uart_in <= 32'b0;
173 |
174 | phy_addr <= 32'b0;
175 |
176 | gram_we_n <= 1'b1;
177 | gram_wr_data <= 8'b0;
178 | end
179 | else begin
180 | case(state)
181 | STATE_IDLE: begin
182 | if(~oen | ~wen) begin
183 | if(sv32_en && ~is_uart && ~is_vga) begin
184 | // 需要映射,先查一级页表
185 | state <= STATE_PAGE_1;
186 | // 注意这里是sram地址
187 | base_address <= page1_addr[21:2];
188 | oe_base_n <= 1'b0;
189 | end
190 | else begin
191 | phy_addr <= mem_addr;
192 | state <= STATE_START;
193 | end
194 | end
195 | end
196 | STATE_PAGE_1: begin
197 | if(base_done) begin
198 | oe_base_n <= 1'b1;
199 | if(page_entry[3:1] != 3'b0) begin
200 | phy_addr <= {page_entry[29:10], mem_addr[11:0]};
201 | state <= STATE_START;
202 | end
203 | else begin
204 | // is not leaf, keep reading
205 | state <= STATE_PAGE_2;
206 | // 注意这里是sram地址
207 | base_address <= {page_entry[29:10], mem_addr[21:12]};
208 | end
209 | end
210 | end
211 | STATE_PAGE_2: begin
212 | oe_base_n <= 1'b0;
213 | state <= STATE_PAGE_3;
214 | end
215 | STATE_PAGE_3: begin
216 | if(base_done) begin
217 | oe_base_n <= 1'b1;
218 | phy_addr <= {page_entry[29:10], mem_addr[11:0]};
219 | state <= STATE_START;
220 | end
221 | end
222 | STATE_START: begin
223 | if (~oen) begin
224 | case(mem_use)
225 | `USE_BASE: begin
226 | base_address <= ram_addr;
227 | oe_base_n <= 1'b0;
228 | state <= STATE_READ;
229 | end
230 | `USE_EXT: begin
231 | ext_address <= ram_addr;
232 | oe_ext_n <= 1'b0;
233 | state <= STATE_READ;
234 | end
235 | `USE_UART: begin
236 | if(mem_addr == `UART_DATA_ADDR) begin
237 | // 读串口数据寄存器
238 | oe_uart_n <= 1'b0;
239 | state <= STATE_READ;
240 | end
241 | else if(mem_addr == `UART_STATUS_ADDR) begin
242 | // 读串口状态寄存器
243 | data_out <= uart_status;
244 | state <= STATE_DONE;
245 | end
246 | else begin
247 | state <= STATE_DONE;
248 | end
249 | end
250 | `USE_VGA: begin
251 | // only BTN can be read
252 | if(mem_addr == `BTN_ADDR) begin
253 | data_out <= {4'b0, touch_btn};
254 | state <= STATE_DONE;
255 | end
256 | else begin
257 | state <= STATE_DONE;
258 | end
259 | end
260 | endcase
261 | end
262 | else if(~wen) begin
263 | case(mem_use)
264 | `USE_BASE: begin
265 | base_address <= ram_addr;
266 | base_ram_be_reg <= ram_be_n;
267 | we_base_n <= 1'b0;
268 | data_base_in <= data_in;
269 | state <= STATE_WRITE;
270 | end
271 | `USE_EXT: begin
272 | ext_address <= ram_addr;
273 | ext_ram_be_reg <= ram_be_n;
274 | we_ext_n <= 1'b0;
275 | data_ext_in <= data_in;
276 | state <= STATE_WRITE;
277 | end
278 | `USE_UART: begin
279 | if(mem_addr == `UART_DATA_ADDR) begin
280 | we_uart_n <= 1'b0;
281 | case (ram_be_n)
282 | `BE_BYTE_0:
283 | data_uart_in <= data_in[7:0];
284 | `BE_BYTE_1:
285 | data_uart_in <= data_in[15:8];
286 | `BE_BYTE_2:
287 | data_uart_in <= data_in[23:16];
288 | `BE_BYTE_3:
289 | data_uart_in <= data_in[31:24];
290 | default:
291 | data_uart_in <= 8'hzz;
292 | endcase
293 | state <= STATE_WRITE;
294 | end
295 | else begin
296 | state <= STATE_DONE;
297 | end
298 | end
299 | `USE_VGA: begin
300 | // write gram
301 | gram_we_n <= 1'b0;
302 | case (ram_be_n)
303 | `BE_BYTE_0:
304 | gram_wr_data <= data_in[7:0];
305 | `BE_BYTE_1:
306 | gram_wr_data <= data_in[15:8];
307 | `BE_BYTE_2:
308 | gram_wr_data <= data_in[23:16];
309 | `BE_BYTE_3:
310 | gram_wr_data <= data_in[31:24];
311 | default:
312 | gram_wr_data <= 8'hzz;
313 | endcase
314 | state <= STATE_WRITE;
315 | end
316 | endcase
317 | end
318 | end
319 | STATE_READ: begin
320 | case(mem_use)
321 | `USE_BASE: begin
322 | if(base_done) begin
323 | oe_base_n <= 1'b1;
324 | base_ram_be_reg <= 4'b0;
325 | data_out <= data_to_load;
326 | state <= STATE_DONE;
327 | end
328 | end
329 | `USE_EXT: begin
330 | if(ext_done) begin
331 | oe_ext_n <= 1'b1;
332 | ext_ram_be_reg <= 4'b0;
333 | data_out <= data_to_load;
334 | state <= STATE_DONE;
335 | end
336 | end
337 | `USE_UART: begin
338 | if(uart_done) begin
339 | oe_uart_n<= 1'b1;
340 | data_out <= data_to_load;
341 | state <= STATE_DONE;
342 | end
343 | end
344 | `USE_VGA: begin
345 | // this case will never be reached
346 | state <= STATE_DONE;
347 | end
348 | endcase
349 | end
350 | STATE_WRITE: begin
351 | case(mem_use)
352 | `USE_BASE: begin
353 | if(base_done) begin
354 | we_base_n <= 1'b1;
355 | base_ram_be_reg <= 4'b0;
356 | state <= STATE_DONE;
357 | end
358 | end
359 | `USE_EXT: begin
360 | if(ext_done) begin
361 | we_ext_n <= 1'b1;
362 | ext_ram_be_reg <= 4'b0;
363 | state <= STATE_DONE;
364 | end
365 | end
366 | `USE_UART: begin
367 | if(uart_done) begin
368 | we_uart_n<= 1'b1;
369 | state <= STATE_DONE;
370 | end
371 | end
372 | `USE_VGA: begin
373 | // should be finished by now
374 | gram_we_n <= 1'b1;
375 | state <= STATE_DONE;
376 | end
377 | endcase
378 | end
379 | STATE_DONE: begin
380 | state <= STATE_IDLE;
381 | end
382 | endcase
383 | end
384 | end
385 |
386 | endmodule
--------------------------------------------------------------------------------
/src/mmu.v:
--------------------------------------------------------------------------------
1 | `include "defines.vh"
2 |
3 | module mmu(
4 | input wire sv32_en,
5 | input wire[`DataAddrBus] addr_i,
6 | output wire[`DataAddrBus] addr_o
7 | );
8 |
9 | wire t1 = addr_i >= 32'h0 && addr_i <= 32'h002FFFFF;
10 | wire t2 = addr_i >= 32'h7FC10000 && addr_i <= 32'h7FFFFFFF;
11 | wire t3 = addr_i >= 32'h80000000 && addr_i <= 32'h80000FFF;
12 | wire t4 = addr_i >= 32'h80100000 && addr_i <= 32'h80100FFF;
13 | wire is_uart = 32'h10000000 <= addr_i && 32'h10000008 >= addr_i;
14 | assign addr_o = is_uart? addr_i :t1? addr_i + 32'h80100000 : t2? addr_i + 32'h007F0000 : addr_i;
15 |
16 | endmodule
--------------------------------------------------------------------------------
/src/regfile.v:
--------------------------------------------------------------------------------
1 | `include "defines.vh"
2 |
3 | module regfile(
4 | input wire clk,
5 | input wire rst,
6 |
7 | input wire we,
8 | input wire[`RegAddrBus] waddr,
9 | input wire[`RegBus] wdata,
10 |
11 | input wire[`RegAddrBus] raddr1,
12 | output wire[`RegBus] rdata1,
13 |
14 | input wire[`RegAddrBus] raddr2,
15 | output wire[`RegBus] rdata2,
16 |
17 | input wire[`RegAddrBus] raddr3,
18 | output wire[`RegBus] rdata3
19 | );
20 | reg[`RegBus] regs[0:`RegNum-1];
21 |
22 |
23 | assign rdata1 = regs[raddr1];
24 | assign rdata2 = regs[raddr2];
25 | assign rdata3 = regs[raddr3];
26 |
27 | always @ (posedge clk) begin
28 | if (rst == `RstDisable) begin
29 | if ((we == `WriteEnable) && (waddr != 0))
30 | regs[waddr] <= wdata;
31 | end else begin
32 | regs[0] <= `ZeroWord;
33 | regs[1] <= `ZeroWord;
34 | regs[2] <= `ZeroWord;
35 | regs[3] <= `ZeroWord;
36 | regs[4] <= `ZeroWord;
37 | regs[5] <= `ZeroWord;
38 | regs[6] <= `ZeroWord;
39 | regs[7] <= `ZeroWord;
40 | regs[8] <= `ZeroWord;
41 | regs[9] <= `ZeroWord;
42 | regs[10] <= `ZeroWord;
43 | regs[11] <= `ZeroWord;
44 | regs[12] <= `ZeroWord;
45 | regs[13] <= `ZeroWord;
46 | regs[14] <= `ZeroWord;
47 | regs[15] <= `ZeroWord;
48 | regs[16] <= `ZeroWord;
49 | regs[17] <= `ZeroWord;
50 | regs[18] <= `ZeroWord;
51 | regs[19] <= `ZeroWord;
52 | regs[20] <= `ZeroWord;
53 | regs[21] <= `ZeroWord;
54 | regs[22] <= `ZeroWord;
55 | regs[23] <= `ZeroWord;
56 | regs[24] <= `ZeroWord;
57 | regs[25] <= `ZeroWord;
58 | regs[26] <= `ZeroWord;
59 | regs[27] <= `ZeroWord;
60 | regs[28] <= `ZeroWord;
61 | regs[29] <= `ZeroWord;
62 | regs[30] <= `ZeroWord;
63 | regs[31] <= `ZeroWord;
64 | end
65 | end
66 | endmodule
--------------------------------------------------------------------------------
/src/sram_io.v:
--------------------------------------------------------------------------------
1 | `timescale 1ns / 1ps
2 | module sram_io(
3 | input wire clk,
4 | input wire rst,
5 | input wire oen,
6 | input wire wen,
7 | input wire[31:0] data_in,
8 | output reg[31:0] data_out,
9 | output wire done,
10 |
11 | inout wire[31:0] ram_data_wire,
12 | output wire ram_ce_n, //RAM片选,低有效
13 | output wire ram_oe_n, //RAM读使能,低有效
14 | output wire ram_we_n //RAM写使能,低有效
15 | );
16 |
17 | reg data_z;
18 | assign ram_data_wire = data_z ? 32'bz : data_in;
19 |
20 | localparam STATE_IDLE = 3'b000;
21 | localparam STATE_READ_0 = 3'b001;
22 | localparam STATE_READ_1 = 3'b010;
23 | localparam STATE_READ_2 = 3'b011;
24 | localparam STATE_WRITE_0 = 3'b100;
25 | localparam STATE_WRITE_1 = 3'b101;
26 | localparam STATE_WRITE_2 = 3'b110;
27 | localparam STATE_DONE = 3'b111;
28 |
29 | reg[2:0] state;
30 | assign done = state == STATE_DONE;
31 |
32 | reg ram_ce_n_flag;
33 | reg ram_oe_n_flag;
34 | reg ram_we_n_flag;
35 |
36 | assign ram_ce_n = ram_ce_n_flag;
37 | assign ram_oe_n = ram_oe_n_flag;
38 | assign ram_we_n = ram_we_n_flag;
39 |
40 | always @(posedge clk or posedge rst) begin
41 | if (rst) begin
42 | state = STATE_IDLE;
43 | ram_ce_n_flag = 1'b1;
44 | ram_we_n_flag = 1'b1;
45 | ram_oe_n_flag = 1'b1;
46 | data_z <= 1'b1;
47 | end
48 | else begin
49 | case (state)
50 | STATE_IDLE: begin
51 | if (~oen) begin
52 | data_z <= 1'b1;
53 | state <= STATE_READ_0;
54 | end
55 | else if (~wen) begin
56 | data_z <= 1'b0;
57 | state <= STATE_WRITE_0;
58 | end
59 | end
60 | STATE_READ_0: begin
61 | state <= STATE_READ_1;
62 | ram_oe_n_flag = 1'b0;
63 | ram_ce_n_flag = 1'b0;
64 | end
65 | STATE_READ_1: begin
66 | state <= STATE_READ_2;
67 | end
68 | STATE_READ_2: begin
69 | state <= STATE_DONE;
70 | ram_oe_n_flag = 1'b1;
71 | ram_ce_n_flag = 1'b1;
72 | data_out <= ram_data_wire;
73 | end
74 | STATE_WRITE_0: begin
75 | state <= STATE_WRITE_1;
76 | ram_we_n_flag = 1'b0;
77 | ram_ce_n_flag = 1'b0;
78 | end
79 | STATE_WRITE_1: begin
80 | state <= STATE_WRITE_2;
81 | end
82 | STATE_WRITE_2: begin
83 | state <= STATE_DONE;
84 | ram_we_n_flag = 1'b1;
85 | ram_ce_n_flag = 1'b1;
86 | end
87 | STATE_DONE: begin
88 | data_z <= 1'b1;
89 | if (oen&wen) begin
90 | state <= STATE_IDLE;
91 | end
92 | end
93 | endcase
94 | end
95 | end
96 | endmodule
97 |
--------------------------------------------------------------------------------
/src/thinpad_top.v:
--------------------------------------------------------------------------------
1 | `default_nettype none
2 |
3 | module thinpad_top(
4 | input wire clk_50M, //50MHz 时钟输入
5 | input wire clk_11M0592, //11.0592MHz 时钟输入(备用,可不用)
6 |
7 | input wire clock_btn, //BTN5手动时钟按钮开关,带消抖电路,按下时为1
8 | input wire reset_btn, //BTN6手动复位按钮开关,带消抖电路,按下时为1
9 |
10 | input wire[3:0] touch_btn, //BTN1~BTN4,按钮开关,按下时为1
11 | input wire[31:0] dip_sw, //32位拨码开关,拨到“ON”时为1
12 | output wire[15:0] leds, //16位LED,输出时1点亮
13 | output wire[7:0] dpy0, //数码管低位信号,包括小数点,输出1点亮
14 | output wire[7:0] dpy1, //数码管高位信号,包括小数点,输出1点亮
15 |
16 | //CPLD串口控制器信号
17 | output wire uart_rdn, //读串口信号,低有效
18 | output wire uart_wrn, //写串口信号,低有效
19 | input wire uart_dataready, //串口数据准备好
20 | input wire uart_tbre, //发送数据标志
21 | input wire uart_tsre, //数据发送完毕标志
22 |
23 | //BaseRAM信号
24 | inout wire[31:0] base_ram_data, //BaseRAM数据,低8位与CPLD串口控制器共享
25 | output wire[19:0] base_ram_addr, //BaseRAM地址
26 | output wire[3:0] base_ram_be_n, //BaseRAM字节使能,低有效。如果不使用字节使能,请保持为0
27 | output wire base_ram_ce_n, //BaseRAM片选,低有效
28 | output wire base_ram_oe_n, //BaseRAM读使能,低有效
29 | output wire base_ram_we_n, //BaseRAM写使能,低有效
30 |
31 | //ExtRAM信号
32 | inout wire[31:0] ext_ram_data, //ExtRAM数据
33 | output wire[19:0] ext_ram_addr, //ExtRAM地址
34 | output wire[3:0] ext_ram_be_n, //ExtRAM字节使能,低有效。如果不使用字节使能,请保持为0
35 | output wire ext_ram_ce_n, //ExtRAM片选,低有效
36 | output wire ext_ram_oe_n, //ExtRAM读使能,低有效
37 | output wire ext_ram_we_n, //ExtRAM写使能,低有效
38 |
39 | //直连串口信号
40 | output wire txd, //直连串口发送端
41 | input wire rxd, //直连串口接收端
42 |
43 | //Flash存储器信号,参考 JS28F640 芯片手册
44 | output wire [22:0]flash_a, //Flash地址,a0仅在8bit模式有效,16bit模式无意义
45 | inout wire [15:0]flash_d, //Flash数据
46 | output wire flash_rp_n, //Flash复位信号,低有效
47 | output wire flash_vpen, //Flash写保护信号,低电平时不能擦除、烧写
48 | output wire flash_ce_n, //Flash片选信号,低有效
49 | output wire flash_oe_n, //Flash读使能信号,低有效
50 | output wire flash_we_n, //Flash写使能信号,低有效
51 | output wire flash_byte_n, //Flash 8bit模式选择,低有效。在使用flash的16位模式时请设为1
52 |
53 | //USB 控制器信号,参考 SL811 芯片手册
54 | output wire sl811_a0,
55 | //inout wire[7:0] sl811_d, //USB数据线与网络控制器的dm9k_sd[7:0]共享
56 | output wire sl811_wr_n,
57 | output wire sl811_rd_n,
58 | output wire sl811_cs_n,
59 | output wire sl811_rst_n,
60 | output wire sl811_dack_n,
61 | input wire sl811_intrq,
62 | input wire sl811_drq_n,
63 |
64 | //网络控制器信号,参考 DM9000A 芯片手册
65 | output wire dm9k_cmd,
66 | inout wire[15:0] dm9k_sd,
67 | output wire dm9k_iow_n,
68 | output wire dm9k_ior_n,
69 | output wire dm9k_cs_n,
70 | output wire dm9k_pwrst_n,
71 | input wire dm9k_int,
72 |
73 | //图像输出信号
74 | output wire[2:0] video_red, //红色像素,3位
75 | output wire[2:0] video_green, //绿色像素,3位
76 | output wire[1:0] video_blue, //蓝色像素,2位
77 | output wire video_hsync, //行同步(水平同步)信号
78 | output wire video_vsync, //场同步(垂直同步)信号
79 | output wire video_clk, //像素时钟输出
80 | output wire video_de //行数据有效信号,用于区分消隐区
81 | );
82 |
83 |
84 | // PLL分频示例
85 | wire locked, clk_10M, clk_40M;
86 | pll_example clock_gen
87 | (
88 | // Clock in ports
89 | .clk_in1(clk_50M), // 外部时钟输入
90 | // Clock out ports
91 | .clk_out1(clk_10M), // 时钟输出1,频率在IP配置界面中设置
92 | .clk_out2(clk_40M), // 时钟输出2,频率在IP配置界面中设置
93 | // Status and control signals
94 | .reset(reset_btn), // PLL复位输入
95 | .locked(locked) // PLL锁定指示输出,"1"表示时钟稳定,
96 | // 后级电路复位信号应当由它生成(见下)
97 | );
98 |
99 | reg reset_of_clk40M;
100 | // 异步复位,同步释放,将locked信号转为后级电路的复位reset_of_clk10M
101 | always@(posedge clk_40M or negedge locked) begin
102 | if(~locked) reset_of_clk40M <= 1'b1;
103 | else reset_of_clk40M <= 1'b0;
104 | end
105 |
106 | // wire clk = clk_40M;
107 | // wire rst = reset_of_clk40M;
108 | wire clk = clk_50M;
109 | wire rst = reset_btn;
110 |
111 | // ===== 存储相关 =====
112 | reg mem_oe_n, mem_we_n;
113 | reg[`DataBus] mem_data_in;
114 | wire[`DataBus] mem_data_out;
115 | reg[`DataAddrBus] mem_data_addr;
116 | wire mem_done;
117 | reg[3:0] mem_ram_be_n;
118 | mem_controller _mem_controller(
119 | .clk(clk),
120 | .rst(rst),
121 | .base_ram_data(base_ram_data),
122 | .base_ram_addr(base_ram_addr),
123 | .base_ram_be_n(base_ram_be_n),
124 | .base_ram_ce_n(base_ram_ce_n),
125 | .base_ram_oe_n(base_ram_oe_n),
126 | .base_ram_we_n(base_ram_we_n),
127 | .ext_ram_data(ext_ram_data),
128 | .ext_ram_addr(ext_ram_addr),
129 | .ext_ram_be_n(ext_ram_be_n),
130 | .ext_ram_ce_n(ext_ram_ce_n),
131 | .ext_ram_oe_n(ext_ram_oe_n),
132 | .ext_ram_we_n(ext_ram_we_n),
133 | .uart_rdn(uart_rdn),
134 | .uart_wrn(uart_wrn),
135 | .uart_dataready(uart_dataready),
136 | .uart_tbre(uart_tbre),
137 | .uart_tsre(uart_tsre),
138 |
139 | .oen(mem_oe_n),
140 | .wen(mem_we_n),
141 | .ram_be_n(mem_ram_be_n),
142 | .mem_addr(mem_data_addr),
143 | .data_in(mem_data_in),
144 | .data_out(mem_data_out),
145 | .done(mem_done),
146 |
147 | .sv32_en(sv32_en),
148 | .satp_ppn(satp_ppn),
149 |
150 | .gram_we_n(gram_we_n),
151 | .gram_wr_data(gram_wr_data),
152 | .gram_wr_addr(gram_wr_addr),
153 | .touch_btn(touch_btn)
154 | );
155 |
156 |
157 |
158 | reg reg_we;
159 | reg[`DataBus] reg_wdata;
160 | reg[`RegAddrBus] reg_waddr;
161 | wire[`RegAddrBus] reg1_addr;
162 | wire[`DataBus] reg1_data;
163 | wire[`RegAddrBus] reg2_addr;
164 | wire[`DataBus] reg2_data;
165 | // 为异常处理模块准备
166 | wire[`RegAddrBus] reg3_addr;
167 | wire[`DataBus] reg3_data;
168 |
169 | regfile _regfile(
170 | .clk(clk),
171 | .rst(rst),
172 | .we(reg_we),
173 | .waddr(reg_waddr),
174 | .wdata(reg_wdata),
175 | .raddr1(reg1_addr),
176 | .rdata1(reg1_data),
177 | .raddr2(reg2_addr),
178 | .rdata2(reg2_data),
179 | .raddr3(reg3_addr),
180 | .rdata3(reg3_data)
181 | );
182 |
183 |
184 | wire instValid, branch, mem_rd, mem_wr, wb;
185 | wire[`InstAddrBus] branch_addr;
186 | wire[`DataBus] mem_wr_data;
187 | wire[`DataAddrBus] mem_addr;
188 | wire[`RegAddrBus] wb_reg_addr;
189 | wire[`DataBus] wb_data;
190 | wire[3:0] ram_be_n;
191 | exe _exe(
192 | .pc(pc),
193 | .inst(inst),
194 | .reg1_data_i(reg1_data),
195 | .reg2_data_i(reg2_data),
196 | .reg1_addr_o(reg1_addr),
197 | .reg2_addr_o(reg2_addr),
198 | .instValid(instValid),
199 | .branch(branch),
200 | .branch_addr(branch_addr),
201 | .mem_rd(mem_rd),
202 | .mem_wr(mem_wr),
203 | .mem_wr_data(mem_wr_data),
204 | .mem_addr(mem_addr),
205 | .wb(wb),
206 | .wb_reg_addr(wb_reg_addr),
207 | .wb_data(wb_data),
208 | .ram_be_n(ram_be_n)
209 | );
210 |
211 |
212 | // ===== 异常处理相关 =====
213 | wire[1:0] exception_if;
214 | wire[`ExpBus] exp_code_if;
215 | exp_if _exp_if(
216 | .if_addr(new_pc),
217 | .exception(exception_if),
218 | .exp_code(exp_code_if),
219 | .sv32_en(sv32_en)
220 | );
221 |
222 | wire[1:0] exception_exe;
223 | wire[`ExpBus] exp_code_exe;
224 | exp_exe _exp_exe(
225 | .inst(inst),
226 | .instValid(instValid),
227 | .mem_rd(mem_rd),
228 | .mem_wr(mem_wr),
229 | .ram_be_n(ram_be_n),
230 | .mem_addr(mem_addr),
231 | .exception(exception_exe),
232 | .exp_code(exp_code_exe),
233 | .sv32_en(sv32_en)
234 | );
235 |
236 | reg[1:0] exception_handle;
237 | reg[`ExpBus] exp_code_handle;
238 | wire ebranch;
239 | wire[`InstAddrBus] ebranch_addr;
240 | wire exp_wb_reg;
241 | wire[`RegAddrBus] exp_wb_reg_addr;
242 | wire[`DataBus] exp_wb_reg_data;
243 | reg csr_we;
244 | wire sv32_en;
245 | wire[21:0] satp_ppn;
246 | exp_handle _exp_handle(
247 | .clk(clk),
248 | .rst(rst),
249 | .exception(exception_handle),
250 | .exp_code(exp_code_handle),
251 | .inst(inst),
252 | .pc(pc),
253 | .mem_addr(mem_addr),
254 | .csr_we(csr_we),
255 |
256 | .reg_data_i(reg3_data),
257 | .reg_addr_o(reg3_addr),
258 |
259 | .ebranch(ebranch),
260 | .ebranch_addr(ebranch_addr),
261 |
262 | .wb_reg(exp_wb_reg),
263 | .wb_reg_addr(exp_wb_reg_addr),
264 | .wb_reg_data(exp_wb_reg_data),
265 |
266 | .sv32_en(sv32_en),
267 | .satp_ppn(satp_ppn)
268 | );
269 |
270 | wire gram_we_n;
271 | wire[18:0] gram_rd_addr;
272 | wire[7:0] gram_rd_data;
273 | wire[18:0] gram_wr_addr;
274 | wire[7:0] gram_wr_data;
275 | gram _gram (
276 | // write ports
277 | .clka(clk), // input wire clka
278 | .ena(1'b1), // input wire ena
279 | .wea(~gram_we_n), // input wire [0 : 0] wea
280 | .addra(gram_wr_addr), // input wire [18 : 0] addra
281 | .dina(gram_wr_data), // input wire [7 : 0] dina
282 |
283 | // read ports
284 | .clkb(clk), // input wire clkb
285 | .enb(1'b1), // input wire enb
286 | .addrb(gram_rd_addr), // input wire [18 : 0] addrb
287 | .doutb(gram_rd_data) // output wire [7 : 0] doutb
288 | );
289 |
290 |
291 | wire[11:0] hdata;
292 | wire[11:0] vdata;
293 | assign video_red = gram_rd_data[2:0];
294 | assign video_green = gram_rd_data[5:3];
295 | assign video_blue = gram_rd_data[7:6];
296 | assign video_clk = clk;
297 | vga #(.WIDTH(12), .HSIZE(800), .HFP(856), .HSP(976), .HMAX(1040),
298 | .VSIZE(600), .VFP(637), .VSP(643), .VMAX(666), .HSPP(1), .VSPP(1)) vga800x600at75 (
299 | .rst(rst),
300 | .clk(clk),
301 | .hdata(hdata),
302 | .vdata(vdata),
303 | .hsync(video_hsync),
304 | .vsync(video_vsync),
305 | .data_enable(video_de),
306 | .addr(gram_rd_addr)
307 | );
308 |
309 | // ===== 状态机 =====
310 |
311 | // program counter
312 | reg [`InstAddrBus] pc;
313 | reg [`InstAddrBus] new_pc;
314 | // instruction
315 | reg [`InstBus] inst;
316 | reg [`StateBus] state;
317 |
318 | always@(posedge clk or posedge rst) begin
319 | if(rst)begin
320 | pc <= `START_ADDR;
321 | new_pc <= `START_ADDR;
322 | state <= `STATE_BOOT;
323 | inst <= 32'b0;
324 | {mem_we_n, mem_oe_n} <= 2'b11;
325 | mem_data_addr <= 32'b0;
326 | {csr_we, reg_we} <= 2'b00;
327 | reg_wdata <= `ZeroWord;
328 | reg_waddr <= 0;
329 | exp_code_handle <= 0;
330 | exception_handle <= 0;
331 | mem_ram_be_n <= 4'b0;
332 | end
333 | else begin
334 | case (state)
335 | `STATE_BOOT: begin
336 | mem_data_addr <= pc;
337 | mem_oe_n <= 1'b0;
338 | state <= `STATE_EXE;
339 | end
340 | `STATE_IF: begin
341 | {csr_we, reg_we} <= 2'b00; // 新周期开始前可以写reg
342 | pc <= new_pc; // 错了也要更新到new_pc
343 | if (exception_if != `EXP_NONE) begin
344 | exp_code_handle <= exp_code_if;
345 | exception_handle <= exception_if;
346 | state <= `STATE_EXP;
347 | end
348 | else begin
349 | mem_data_addr <= new_pc;
350 | mem_ram_be_n <= 4'b0;
351 | mem_oe_n <= 1'b0;
352 | state <= `STATE_EXE;
353 | end
354 | end
355 | `STATE_EXE: begin
356 | // EXE阶段及以后不允许修改pc和inst的值
357 | // 保证控制信号稳定
358 | if(mem_done) begin
359 | mem_oe_n <= 1'b1;
360 | inst <= mem_data_out;
361 | state <= `STATE_MEM;
362 | end
363 | end
364 | `STATE_MEM: begin
365 | new_pc <= branch? branch_addr: pc + 4;
366 | if(exception_exe != `EXP_NONE) begin
367 | exp_code_handle <= exp_code_exe;
368 | exception_handle <= exception_exe;
369 | state <= `STATE_EXP;
370 | end
371 | else begin
372 | if (mem_rd) begin
373 | mem_oe_n <= 1'b0;
374 | // 名字取的不太好
375 | mem_ram_be_n <= ram_be_n;
376 | mem_data_addr <= mem_addr;
377 | state <= `STATE_WB;
378 | end
379 | else if(mem_wr) begin
380 | // 写的时候需要赋值字节使能
381 | mem_we_n <= 1'b0;
382 | mem_ram_be_n <= ram_be_n;
383 | mem_data_addr <= mem_addr;
384 | mem_data_in <= mem_wr_data;
385 | state <= `STATE_WB;
386 | end
387 | else begin
388 | // 如果没有访存那就直接写回
389 | // 写回!
390 | if (wb) begin
391 | reg_we <= 1'b1;
392 | reg_waddr <= wb_reg_addr;
393 | reg_wdata <= wb_data;
394 | end
395 | state <= `STATE_IF;
396 | end
397 | end
398 | end
399 | `STATE_WB: begin
400 | // 其实是访存的收尾阶段
401 | if(mem_done) begin
402 | {mem_oe_n, mem_we_n} <= 2'b11;
403 | if(mem_rd) begin
404 | reg_we <= 1'b1;
405 | reg_waddr <= wb_reg_addr;
406 | reg_wdata <= mem_data_out;
407 | end
408 | state <= `STATE_IF;
409 | end
410 | end
411 | `STATE_EXP: begin
412 | new_pc <= ebranch ? ebranch_addr : pc + 4;
413 | // 做异常写回
414 | if(exp_wb_reg) begin
415 | reg_we <= 1'b1;
416 | reg_waddr <= exp_wb_reg_addr;
417 | reg_wdata <= exp_wb_reg_data;
418 | end
419 | // 无论如何都更新csr寄存器
420 | csr_we <= 1'b1;
421 | state <= `STATE_IF;
422 | end
423 | endcase
424 | end
425 | end
426 | endmodule
427 |
428 |
--------------------------------------------------------------------------------
/src/uart_io.v:
--------------------------------------------------------------------------------
1 | `timescale 1ns / 1ps
2 | module uart_io(
3 | input wire clk,
4 | input wire rst,
5 | input wire oen,
6 | input wire wen,
7 | input wire[7:0] data_in,
8 | output reg[7:0] data_out,
9 | output wire done,
10 |
11 | inout wire[31:0] base_ram_data_wire,
12 |
13 | output reg uart_rdn,
14 | output reg uart_wrn,
15 | input wire uart_dataready,
16 | input wire uart_tbre,
17 | input wire uart_tsre
18 | );
19 |
20 | reg[7:0] ram_data;
21 | reg data_z;
22 | assign base_ram_data_wire = data_z ? 32'bz : { 24'h000000, ram_data};
23 |
24 | localparam STATE_IDLE = 3'b000;
25 | localparam STATE_READ_0 = 3'b001;
26 | localparam STATE_READ_1 = 3'b010;
27 | localparam STATE_WRITE_0 = 3'b011;
28 | localparam STATE_WRITE_1 = 3'b100;
29 | localparam STATE_WRITE_2 = 3'b101;
30 | localparam STATE_WRITE_3 = 3'b110;
31 | localparam STATE_DONE = 3'b111;
32 |
33 | reg[2:0] state;
34 | assign done = state == STATE_DONE;
35 |
36 | always @(posedge clk or posedge rst) begin
37 | if (rst) begin
38 | { uart_rdn, uart_wrn } <= 2'b11;
39 | data_z <= 1'b1;
40 | state <= STATE_IDLE;
41 | end
42 | else begin
43 | case (state)
44 | STATE_IDLE: begin
45 | if (~oen) begin
46 | data_z <= 1'b1;
47 | state <= STATE_READ_0;
48 | end
49 | else if (~wen) begin
50 | data_z <= 1'b0;
51 | ram_data <= data_in;
52 | state <= STATE_WRITE_0;
53 | end
54 | end
55 | STATE_READ_0: begin
56 | if (uart_dataready) begin
57 | uart_rdn <= 1'b0;
58 | state <= STATE_READ_1;
59 | end
60 | end
61 | STATE_READ_1: begin
62 | data_out <= base_ram_data_wire[7:0];
63 | uart_rdn <= 1'b1;
64 | state <= STATE_DONE;
65 | end
66 | STATE_WRITE_0: begin
67 | uart_wrn <= 1'b0;
68 | state <= STATE_WRITE_1;
69 | end
70 | STATE_WRITE_1: begin
71 | uart_wrn <= 1'b1;
72 | state <= STATE_WRITE_2;
73 | end
74 | STATE_WRITE_2: begin
75 | if (uart_tbre)
76 | state <= STATE_WRITE_3;
77 | end
78 | STATE_WRITE_3: begin
79 | if (uart_tsre)
80 | state <= STATE_DONE;
81 | end
82 | STATE_DONE: begin
83 | data_z <= 1'b1;
84 | if (oen&wen) begin
85 | state <= STATE_IDLE;
86 | { uart_rdn, uart_wrn } <= 2'b11;
87 | end
88 | end
89 | endcase
90 | end
91 | end
92 | endmodule
93 |
--------------------------------------------------------------------------------
/src/vga.v:
--------------------------------------------------------------------------------
1 | `timescale 1ns / 1ps
2 | //
3 | // WIDTH: bits in register hdata & vdata
4 | // HSIZE: horizontal size of visible field
5 | // HFP: horizontal front of pulse
6 | // HSP: horizontal stop of pulse
7 | // HMAX: horizontal max size of value
8 | // VSIZE: vertical size of visible field
9 | // VFP: vertical front of pulse
10 | // VSP: vertical stop of pulse
11 | // VMAX: vertical max size of value
12 | // HSPP: horizontal synchro pulse polarity (0 - negative, 1 - positive)
13 | // VSPP: vertical synchro pulse polarity (0 - negative, 1 - positive)
14 | //
15 | module vga
16 | #(parameter WIDTH = 0, HSIZE = 0, HFP = 0, HSP = 0, HMAX = 0, VSIZE = 0, VFP = 0, VSP = 0, VMAX = 0, HSPP = 0, VSPP = 0)
17 | (
18 | input wire rst,
19 | input wire clk,
20 | output wire hsync,
21 | output wire vsync,
22 | output reg [WIDTH - 1:0] hdata,
23 | output reg [WIDTH - 1:0] vdata,
24 | output reg[18:0] addr,
25 | output wire data_enable
26 | );
27 |
28 | // hdata
29 | always @ (posedge rst or posedge clk)
30 | begin
31 | if(rst) begin
32 | hdata <= 0;
33 | end
34 | else begin
35 | if (hdata == (HMAX - 1))
36 | hdata <= 0;
37 | else
38 | hdata <= hdata + 1;
39 | end
40 | end
41 |
42 | // vdata
43 | always @ (posedge rst or posedge clk)
44 | begin
45 | if(rst) begin
46 | vdata <= 0;
47 | end
48 | else begin
49 | if (hdata == (HMAX - 1))
50 | begin
51 | if (vdata == (VMAX - 1))
52 | vdata <= 0;
53 | else
54 | vdata <= vdata + 1;
55 | end
56 | end
57 | end
58 |
59 | // addr
60 | always @ (posedge rst or posedge clk)
61 | begin
62 | if(rst) begin
63 | addr <= 0;
64 | end
65 | else begin
66 | if (addr >= 480000) begin
67 | addr <= 0;
68 | end
69 | else if(data_enable) begin
70 | addr <= addr + 1;
71 | end
72 | end
73 | end
74 |
75 | // hsync & vsync & blank
76 | assign hsync = ((hdata >= HFP) && (hdata < HSP)) ? HSPP : !HSPP;
77 | assign vsync = ((vdata >= VFP) && (vdata < VSP)) ? VSPP : !VSPP;
78 | assign data_enable = ((hdata < HSIZE) & (vdata < VSIZE));
79 |
80 | endmodule
--------------------------------------------------------------------------------