├── 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 | modules 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 | game详情见小游戏演示视频。 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 --------------------------------------------------------------------------------