├── .gitignore ├── CMakeLists.txt ├── LICENSE ├── README.md ├── demo_code_editor.pro ├── docs ├── image-20241209202527750.png ├── image-20241209202725326.png ├── image-20241209202929850.png ├── image-20241209204455520.png ├── image-20241209205043792.png ├── image-20241209205316029.png ├── image-20241209205433050.png ├── image-20241209205747664.png ├── image-20241209205951004.png ├── image-20241209210105185.png ├── image-20241209210155902.png ├── image-20241209210552458.png ├── image-20241209210556295.png ├── image-20241209210726156.png ├── image-20241209211234562.png ├── image-20241209211329516.png ├── image-20241209211345279.png ├── image-20241209211601507.png ├── image-20241209211713826.png ├── image-20241209211835283.png ├── image-20241209211907692.png ├── image-20241209212002167.png ├── image-20241209212038038.png ├── image-20241209212103875.png ├── image-20241209212328783.png ├── image-20241209212343230.png └── image-20241209215013564.png ├── include ├── device │ ├── npc.h │ ├── reg.h │ ├── timer.h │ ├── vga.h │ └── vmem.h ├── main.h ├── monitor │ ├── monitor.h │ ├── sdb │ │ ├── expr.h │ │ ├── sdb.h │ │ └── watchpoint.h │ └── tools │ │ ├── difftest.h │ │ └── ftrace.h ├── ui │ ├── codeeditor.h │ ├── csrmonitor.h │ ├── filesystemmodel.h │ ├── gprmonitor.h │ ├── highlighter.h │ ├── instmonitor.h │ ├── mainwindow.h │ ├── memviewer.h │ ├── splitterlayout.h │ └── treeview.h └── utils │ ├── common.h │ ├── disasm.h │ └── utils.h ├── res ├── code.qrc ├── config │ └── keywords.txt ├── images.qrc └── images │ ├── bold.png │ ├── breakpoint.png │ ├── copy.png │ ├── create.png │ ├── cut.png │ ├── edit_redo.png │ ├── edit_undo.png │ ├── exit.png │ ├── font.png │ ├── info.png │ ├── italic.png │ ├── logo.ico │ ├── new.png │ ├── open.png │ ├── paste.png │ ├── pencil.png │ ├── print.png │ ├── runtocomp.png │ ├── save.png │ ├── save_as.png │ ├── start_debug.png │ ├── step.png │ ├── step_func.png │ ├── stop_debug.png │ ├── triggerbp.png │ └── underline.png ├── src ├── CMakeLists.txt ├── device │ ├── npc.cpp │ ├── reg.cpp │ ├── timer.cpp │ ├── vga.cpp │ └── vmem.cpp ├── main.cpp ├── monitor │ ├── monitor.cpp │ ├── sdb │ │ ├── expr.cpp │ │ ├── sdb.cpp │ │ └── watchpoint.cpp │ └── tools │ │ ├── difftest.cpp │ │ └── ftrace.cpp ├── ui │ ├── codeeditor.cpp │ ├── csrmonitor.cpp │ ├── filesystemmodel.cpp │ ├── gprmonitor.cpp │ ├── highlighter.cpp │ ├── instmonitor.cpp │ ├── mainwindow.cpp │ ├── memviewer.cpp │ ├── splitterlayout.cpp │ └── treeview.cpp ├── utils │ └── disasm.cpp └── vsrc │ ├── ALU.v │ ├── BU.v │ ├── CMakeLists.txt │ ├── CPU.v │ ├── CU.v │ ├── IDU.v │ ├── IFU.v │ ├── PC.v │ └── REF.v └── ui └── mainwindow.ui /.gitignore: -------------------------------------------------------------------------------- 1 | *.* 2 | * 3 | !*/ 4 | !CMakeLists.txt 5 | !*.h 6 | !*.cpp 7 | !*.png 8 | !.gitignore 9 | !README.md 10 | !demo_code_editor.pro 11 | !/bin 12 | !/build 13 | 14 | -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.5.1) 2 | cmake_policy(SET CMP0071 NEW) 3 | project(IDE) 4 | 5 | ## Set compiler to use c++ 11 features 6 | set(CMAKE_CXX_STANDARD 14) 7 | set(CMAKE_CXX_EXTENSIONS OFF) 8 | set(CMAKE_CXX_STANDARD_REQUIRED ON) 9 | 10 | set(CMAKE_DISABLE_IN_SOURCE_BUILD ON) 11 | set(CMAKE_DISABLE_SOURCE_CHANGES ON) 12 | set(OpenGL_GL_PREFERENCE LEGACY) 13 | set(CMAKE_EXPORT_COMPILE_COMMANDS ON) 14 | 15 | add_subdirectory(src) 16 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # YSYX_IDE 2 | 3 | ## 1 概述 4 | 5 | ​ 该IDE是一个集成开发和调试平台,专为嵌入式系统和硬件设计提供强大的支持。当前功能包括代码编辑、指令单步调试、源码单步调试、指令内存追踪、寄存器监视以及内存查看等,能够精确控制和分析程序执行,帮助开发人员快速定位问题。同时,IDE还支持NPC设计调试与仿真,能够结合NEMU进行差分测试,定位错误指令的实现,并提供对定时器、串口、VGA等外设的集成仿真,进一步增强系统验证能力。在未来的规划中,IDE将进一步解耦与NPC和NEMU的紧密结合,提升其通用性与灵活性,并实现源码编译、仿真调试与自定义外设测试的无缝集成。此外,IDE还将支持根据设计的电路进行布局(Layout),提供完整的硬件开发生命周期支持,从仿真到物理设计,全面优化芯片开发与验证的效率。 6 | 7 | image-20241209215013564 8 | 9 | ## 2 功能简介 10 | 11 | ### 2.1 代码编辑/调试(基于NEMU) 12 | 13 | #### 2.1.1 概述 14 | 15 | ​ 该功能是基于“一生一芯”项目的NEMU模拟器,旨在为开发人员提供一个集成的开发与调试平台。通过NEMU作为核心,该IDE支持代码编辑与调试功能,包括指令级单步执行、源码级单步执行、内存与寄存器追踪、以及动态内存查看等。开发人员可以在可视化模拟环境中精确控制程序的执行,全面监控程序的内存访问和寄存器状态,实时分析指令执行流。 16 | 17 | #### 2.1.2 UI框架 18 | 19 | ##### (1)整体框架 20 | 21 | image-20241209204455520 22 | 23 | ##### (2)编辑调试页面 24 | 25 | image-20241209202527750 26 | 27 | ##### (3)外设页面 28 | 29 | image-20241209202929850 30 | 31 | #### 2.1.3 功能介绍与使用 32 | 33 | ##### (1)模式选择 34 | 35 | ​ 支持多种调试模式的切换,以适应不同的开发和调试需求。 36 | 37 | * 批次处理模式(Batch Mode)允许开发人员以自动化方式执行多个测试案例或仿真任务,适用于大规模验证和回归测试,能够快速评估系统的稳定性和性能。 38 | 39 | image-20241209205043792 40 | 41 | * SDB调试模式(SDB Debugging Mode)基于标准调试协议,提供了与外部调试工具(如GDB)兼容的调试接口,使开发者能够在远程或嵌入式设备上进行精确的指令级调试。 42 | 43 | image-20241209205316029 44 | 45 | * IDE调试模式(IDE Debugging Mode)则为用户提供全面的图形化调试界面,支持指令单步执行、源码追踪、寄存器和内存监控等功能,增强了开发人员对程序执行过程的可视化和互动控制。通过这些模式的切换,用户可以灵活地在不同的调试环境中工作,满足从开发、调试到验证的多样化需求。 46 | 47 | image-20241209205433050 48 | 49 | ##### (2)单步调试 50 | 51 | ​ 在调试过程中提供了灵活的指令级单步执行功能。在SDB调试模式下,开发人员可以选择逐条执行指令,精准控制程序执行的每一步,或者选择直接运行到程序结束,用于高效地验证程序的执行流程和结果。与之不同,在IDE调试模式中,开发人员可以通过图形化界面上的按钮触发指令单步执行或代码运行,操作更加直观。在指令单步调试时,IDE不仅提供指令级执行控制,还能够实时同步显示源码,确保开发人员能够准确跟踪每个汇编指令与源代码行之间的对应关系。这种同步功能使得调试过程中的代码行为和指令执行紧密结合,有助于深入分析程序逻辑和查找潜在错误。 52 | 53 | image-20241209205747664 54 | 55 | ##### (3)查看内存 56 | 57 | ​ 内存查看功能支持在不同调试模式下进行灵活的内存访问。在SDB调试模式下,开发人员可以通过调试指令直接访问和查看内存内容,这种方式适用于低级别调试和远程调试场景,允许开发者精准地指定内存地址进行查看,分析内存中的数据结构和执行状态。而在IDE调试模式中,内存查看功能通过集成的内存查看器提供更加直观和交互式的体验,开发人员可以实时浏览内存中的具体内容。内存查看器支持地址偏移、动态更新,帮助开发人员快速定位内存泄漏、越界访问等问题,提升调试效率和准确性。 58 | 59 | image-20241209205951004 60 | 61 | ##### (4)指令内存监视 62 | 63 | ​ 指令内存追踪功能,可以精确记录和追踪程序执行的每一条指令及其对应的内存操作。通过对指令执行流的细致追踪,IDE能够实时显示当前执行到的指令地址和内存访问情况,帮助开发人员深入分析程序的执行过程。在差分测试阶段,指令内存追踪能够提供详细的执行路径信息,便于定位潜在的错误或异常行为。这种指令级的追踪能力对于提高调试精度、确保系统稳定性和进行性能分析至关重要,有助于开发人员快速识别和修复问题。 64 | 65 | image-20241209210105185 66 | 67 | ##### (5)寄存器监视 68 | 69 | ​ 寄存器监视功能,能够实时追踪和显示寄存器中的数据变化。通过精确监控寄存器的值,开发人员可以直观地了解每个时钟周期内寄存器状态的变动,特别是在指令执行、数据传输和控制信号变化时。寄存器监视不仅支持单个寄存器的跟踪,还能够显示寄存器组或特定功能寄存器(如程序计数器、标志寄存器等)的状态,帮助开发人员分析指令执行对寄存器值的影响。在调试过程中,寄存器监视功能可用于定位数据传递错误、控制逻辑异常以及执行流问题,确保开发人员对硬件状态的全面理解,进而提升系统的稳定性和可靠性。 70 | 71 | image-20241209210155902 72 | 73 | ##### (6)支持断点 74 | 75 | ​ 支持断点功能,允许开发人员在调试过程中设置特定的程序执行中断点。当程序执行到设定的断点位置时,IDE会自动暂停程序的执行,等待用户的进一步操作。这种机制使得开发人员能够精确控制程序的执行流,进行细粒度的分析与调试。通过暂停功能,用户可以检查当前程序状态、查看寄存器和内存的内容,或者执行单步调试等操作,以便深入分析程序行为并及时定位潜在问题。断点功能对于精确控制程序执行和分析复杂的逻辑路径具有重要意义,尤其是在处理调试复杂算法、系统交互或硬件仿真时。 76 | 77 | image-20241209210556295 78 | 79 | image-20241209210726156 80 | 81 | ### 2.2 NPC设计/调试/仿真(基于NPC) 82 | 83 | #### 2.2.1 概述 84 | 85 | ​ 该IDE不仅支持传统的代码编辑和调试功能,还扩展了对NPC设计的调试与仿真支持。在NPC调试过程中,IDE能够结合NEMU模拟器进行差分测试,通过对比NPC设计与预期行为的执行差异,快速定位错误指令的实现。在差分测试中,IDE会自动跟踪和记录NPC设计中每条指令的执行路径,并与NEMU模拟器的输出进行对比,准确发现执行过程中不一致的地方。此功能使得开发人员能够高效地识别设计中的逻辑错误、指令不匹配或资源冲突,并提供详细的调试信息,有助于加速NPC设计的验证与修正。通过这些功能,IDE为NPC设计提供了一个全面的调试环境,提升了设计验证的精度和效率。 86 | 87 | image-20241209211345279 88 | 89 | #### 2.2.2 功能介绍与使用 90 | 91 | ##### (1)NPC调试 92 | 93 | ​ 在NPC调试过程中,IDE能够结合NEMU模拟器进行差分测试,通过对比NPC设计与预期行为的执行差异,快速定位错误指令的实现。在差分测试中,IDE会自动跟踪和记录NPC设计中每条指令的执行路径,并与NEMU模拟器的输出进行对比,准确发现执行过程中不一致的地方。此功能使得开发人员能够高效地识别设计中的逻辑错误、指令不匹配或资源冲突,并提供详细的调试信息,有助于加速NPC设计的验证与修正。 94 | 95 | ##### (2)外设支持 96 | 97 | ​ NPC设计调试仿真功能扩展了对外设的支持,使开发人员能够在芯片设计中集成并测试各种外设。目前,IDE支持定时器、串口输出和VGA等常见外设功能,其中VGA的输出可通过集成的NVBoard显示进行实时可视化。通过这种方式,开发人员可以直观地查看和验证芯片与外设之间的交互。未来,IDE将进一步优化界面,以支持用户自定义外围电路的设计与仿真测试。通过这一功能,开发人员能够在调试阶段灵活地测试和验证自定义外设与芯片设计的兼容性,确保系统的功能和性能满足设计要求。该功能显著提升了系统集成和验证的效率。 98 | 99 | image-20241209211234562 100 | 101 | ## 3 环境搭建与编译使用 102 | 103 | ### 3.1 环境搭建 104 | 105 | #### (1) 安装cmake 106 | 107 | ```bash 108 | sudo apt-get install cmake 109 | ``` 110 | 111 | #### (2) 安装RISCV编译器 112 | 113 | ```bash 114 | sudo apt install gcc-riscv64-linux-gnu 115 | sudo apt install g++-riscv64-linux-gnu 116 | ``` 117 | 118 | #### (3) 安装LLVM 119 | 120 | > :heavy_exclamation_mark:注意`Ubuntu22.04`只支持`llvm-13`及以下,`Ubuntu24.04`不受此限制。 121 | > 122 | > 如果不是安装的`llvm-13`版本,需要修改`${InstallationPath}/IDE/src/vsec/CMakeLists.txt` 123 | > 124 | > ![image-20241209212328783](docs/image-20241209212328783.png) 125 | > 126 | > ![image-20241209212343230](docs/image-20241209212343230.png) 127 | 128 | ```bash 129 | sudo apt-get install llvm-13 llvm-13-dev 130 | ``` 131 | 132 | #### (4) Verilator 133 | 134 | * 命令行安装 135 | 136 | ```bash 137 | sudo apt-get install verilator 138 | ``` 139 | 140 | * 源码安装(本项目使用的版本是v5.008) 141 | 142 | ```bash 143 | # Prerequisites: 144 | #sudo apt-get install git help2man perl python3 make autoconf g++ flex bison ccache 145 | #sudo apt-get install libgoogle-perftools-dev numactl perl-doc 146 | #sudo apt-get install libfl2 # Ubuntu only (ignore if gives error) 147 | #sudo apt-get install libfl-dev # Ubuntu only (ignore if gives error) 148 | #sudo apt-get install zlibc zlib1g zlib1g-dev # Ubuntu only (ignore if gives error) 149 | 150 | git clone https://github.com/verilator/verilator # Only first time 151 | 152 | # Every time you need to build: 153 | unsetenv VERILATOR_ROOT # For csh; ignore error if on bash 154 | unset VERILATOR_ROOT # For bash 155 | cd verilator 156 | git pull # Make sure git repository is up-to-date 157 | git tag # See what versions exist 158 | #git checkout master # Use development branch (e.g. recent bug fixes) 159 | #git checkout stable # Use most recent stable release 160 | #git checkout v{version} # Switch to specified release version 161 | 162 | autoconf # Create ./configure script 163 | ./configure # Configure and create Makefile 164 | make -j `nproc` # Build Verilator itself (if error, try just 'make') 165 | sudo make install 166 | ``` 167 | 168 | #### (5) 安装Qt 169 | 170 | ```bash 171 | sudo apt-get install build-essential 172 | sudo apt-get install qtbase5-dev qtchooser qt5-qmake qtbase5-dev-tools 173 | sudo apt-get install qt5* 174 | ``` 175 | 176 | #### (6) 其他依赖库 177 | 178 | ```bash 179 | sudo apt-get install libreadline-dev # a library used later 180 | sudo apt-get install ccache 181 | ``` 182 | 183 | ### 3.2 项目编译 184 | 185 | #### (1)克隆仓库 186 | 187 | ```bash 188 | git@github.com:1932287243/NPC_IDE.git 189 | ``` 190 | 191 | #### (2)导航到项目目录 192 | 193 | ```bash 194 | cd ${InstallationPath}/IDE 195 | ``` 196 | 197 | #### (3)编译项目 198 | 199 | ```bash 200 | mkdir bin build 201 | pushd build 202 | cmake .. 203 | make 204 | popd 205 | ``` 206 | 207 | ### 3.3 项目运行 208 | 209 | #### (1)导出环境变量 210 | 211 | > 可以追加在`~/.bashrc`文件最后,以便每次启动终端可以直接导出环境变量 212 | 213 | ```bash 214 | export IDE_HOME=${YSYX Installation Path}/ysyx-workbench/IDE 215 | ``` 216 | 217 | #### (2)修改相关文件 218 | 219 | > :exclamation: 由于目前只支持调试NPC,暂不支持NEMU调试。且NPC代码和IDE未实现解耦。还需修改如下: 220 | 221 | * 修改“一生一芯”项目中`Abstract Mochine`目录中`${YSYX Installation Path}/ysyx-workbench/abstract-machine/scrips/platform/npc.mk`文件使其在`am-kernels`文件下编译运行测试代码时,能够直接启动IDE进行调试。 222 | 223 | ```makefile 224 | NEMUFLAGS += -l $(shell dirname $(IMAGE).elf)/npc-log.txt 225 | NEMUFLAGS += -f $(IMAGE).elf 226 | NEMUFLAGS += -d $(NEMU_HOME)/build/riscv32-nemu-interpreter-so 227 | NEMUFLAGS += -m 1 228 | 229 | # 1: display IDE, but don't SDB 230 | # 2: don't display IDE, but display SDB --include:difftest、show instruction、sdb、wp、ftrace 231 | # 3: display IDE and SDB 232 | # 4: batch mode --Only executing programs 233 | 234 | # $(MAKE) -C $(NPC_HOME) run ARGS="$(NEMUFLAGS)" IMG=$(IMAGE).bin 235 | run: image 236 | $(IDE_HOME)/bin/IDE $(NEMUFLAGS) -i $(IMAGE).bin 237 | 238 | image: $(IMAGE).elf 239 | @$(OBJDUMP) -d $(IMAGE).elf > $(IMAGE).txt 240 | @echo + OBJCOPY "->" $(IMAGE_REL).bin 241 | @$(OBJCOPY) -S --set-section-flags .bss=alloc,contents -O binary $(IMAGE).elf $(IMAGE).bin 242 | ``` 243 | 244 | * 若想调试自己的NPC代码(否则不作任何修改),只需要将自己NPC代码拷贝到`${IDE Installation Path}/src/vsrc`目录下,拷贝前需要提前删除该目录下所有的verilog代码文件。在代码拷贝完成之后,还需要修改顶层文件的模块名,以及通过寄存器模块名来满足IDE(目前还仅限于自己代码测试,未解耦,故需要如此),需要修改的文件如下 245 | 246 | * 顶层模块 247 | 248 | ![image-20241209211835283](docs/image-20241209211835283.png) 249 | 250 | * 寄存器模块 251 | 252 | ![image-20241209211713826](docs/image-20241209211713826.png) 253 | 254 | * pc名 255 | 256 | ![image-20241209211907692](docs/image-20241209211907692.png) 257 | 258 | * 其他 259 | 260 | image-20241209212002167 261 | 262 | image-20241209212103875 263 | 264 | * 修改完需要重新编译(未修改则不需要) 265 | 266 | #### (3)运行 267 | 268 | * 模式一:批处理模式 269 | 270 | 修改`npc.mk`文件即可(详细过程见第二章) 271 | 272 | * 模式二:SDB调试模式详细 273 | 274 | 修改`npc.mk`文件即可(详细过程见第二章) 275 | 276 | * 模式三:IDE调试模式 277 | 278 | 修改`npc.mk`文件即可(详细过程见第二章) 279 | 280 | ## 4 未来规划 281 | 282 | ### 4.1 IDE解耦 283 | 284 | 在未来的版本规划中,该IDE将进行重要的架构优化,目标是将IDE与当前实现的NPC和NEMU解耦。这一改进将使得IDE在仿真与调试过程中更加灵活和模块化,便于用户将自定义设计的芯片与IDE无缝集成进行仿真与调试。通过解耦,IDE将能够独立于具体的NPC实现,支持更广泛的硬件设计和仿真需求,提升其适应性和可扩展性。此举不仅简化了对不同芯片设计的仿真流程,还使得开发人员能够更加便捷地测试和调试不同硬件架构与外设的组合,进一步增强系统验证与调试的效率。 285 | 286 | ### 4.2 IDE实现C/C++源码编译 287 | 288 | 未来将实现源码编译与测试的集成,开发人员将能够直接在IDE内部进行源码的编译和仿真调试,无需再切换到`am-kernel`目录下执行独立的命令进行操作。这一功能的实现将大大简化开发流程,提高开发效率,使得调试和验证过程更加高效和流畅。此外,该改进为后续实现自定义代码测试奠定基础,开发人员可以在IDE中直接编写、编译、运行和调试自定义代码,支持快速迭代和实时调试,进一步提升系统开发的灵活性与便捷性。 289 | 290 | ### 4.3 实现代码跳转(目前还没有思路) 291 | 292 | 在未来的规划中,该IDE将增强单步调试功能,使得当程序执行跨越多个源文件时,调试器能够智能地跳转到对应文件和行号的源码位置。这一功能的实现将提升代码调试的可操作性与直观性,特别是在涉及多文件、模块化或库依赖的复杂项目中。通过自动跳转到相关的源代码位置,开发人员能够更高效地理解和分析代码的执行流程,减少手动查找代码文件和行号的时间,从而加速调试和错误定位的过程。 293 | 294 | ### 4.4 搭建外围仿真电路(基于QNodes) 295 | 296 | 在未来的规划中,该IDE将支持基于用户自定义设计的芯片,搭建并仿真测试外围电路。这一功能将为硬件设计者提供一个完整的开发和验证环境,用户可以在虚拟仿真平台中集成并验证各种外围电路(如传感器、外设接口等),确保芯片与外围系统的兼容性与稳定性。通过这种集成仿真,开发人员能够在芯片设计阶段提前发现潜在的硬件交互问题,优化电路设计,提升系统的整体性能和可靠性。该功能将极大增强IDE在硬件设计与验证中的作用,提供更加灵活和高效的开发流程。 297 | 298 | ### 4.5 根据仿真电路进行Layout(目前没想好怎么做) 299 | 300 | 未来将扩展支持根据前面设计的仿真电路进行布局(Layout)。这一功能将使得开发人员能够在芯片设计的后期阶段,根据电路仿真结果,生成精确的物理布局。通过集成布局工具,IDE能够根据电路图、元件规格和信号连接自动或手动布置芯片内部的各个模块和线路,并生成布局文件。 301 | 302 | ## 5 开源仓库位置 303 | 304 | ```bash 305 | git@github.com:1932287243/NPC_IDE.git 306 | ``` 307 | 308 | 309 | 310 | -------------------------------------------------------------------------------- /demo_code_editor.pro: -------------------------------------------------------------------------------- 1 | QT += core gui 2 | 3 | greaterThan(QT_MAJOR_VERSION, 4): QT += widgets 4 | 5 | CONFIG += c++11 6 | 7 | qtHaveModule(printsupport): QT+=printsupport 8 | 9 | # You can make your code fail to compile if it uses deprecated APIs. 10 | # In order to do so, uncomment the following line. 11 | #DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0 12 | INCLUDEPATH += $$PWD/include 13 | 14 | SOURCES += \ 15 | src/main.cpp \ 16 | src/mainwindow.cpp \ 17 | src/mycodeeditor.cpp \ 18 | src/myfilesystemmodel.cpp \ 19 | src/myhighlighter.cpp \ 20 | src/mysplitterlayout.cpp \ 21 | src/mytextedit.cpp \ 22 | src/mytexteditbycode.cpp \ 23 | src/mytreeview.cpp 24 | 25 | HEADERS += \ 26 | include/mainwindow.h \ 27 | include/mycodeeditor.h \ 28 | include/myfilesystemmodel.h \ 29 | include/myhighlighter.h \ 30 | include/mysplitterlayout.h \ 31 | include/mytextedit.h \ 32 | include/mytexteditbycode.h \ 33 | include/mytreeview.h 34 | 35 | FORMS += \ 36 | ui/mainwindow.ui \ 37 | ui/mytextedit.ui 38 | 39 | # Default rules for deployment. 40 | qnx: target.path = /tmp/$${TARGET}/bin 41 | else: unix:!android: target.path = /opt/$${TARGET}/bin 42 | !isEmpty(target.path): INSTALLS += target 43 | 44 | RESOURCES += \ 45 | res/code.qrc \ 46 | res/images.qrc 47 | 48 | RC_ICONS = res/images/logo.ico 49 | -------------------------------------------------------------------------------- /docs/image-20241209202527750.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/1932287243/NPC_IDE/2f4b6dc154a16e34a5dd2bf9fad5dc7cb49ddbd7/docs/image-20241209202527750.png -------------------------------------------------------------------------------- /docs/image-20241209202725326.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/1932287243/NPC_IDE/2f4b6dc154a16e34a5dd2bf9fad5dc7cb49ddbd7/docs/image-20241209202725326.png -------------------------------------------------------------------------------- /docs/image-20241209202929850.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/1932287243/NPC_IDE/2f4b6dc154a16e34a5dd2bf9fad5dc7cb49ddbd7/docs/image-20241209202929850.png -------------------------------------------------------------------------------- /docs/image-20241209204455520.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/1932287243/NPC_IDE/2f4b6dc154a16e34a5dd2bf9fad5dc7cb49ddbd7/docs/image-20241209204455520.png -------------------------------------------------------------------------------- /docs/image-20241209205043792.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/1932287243/NPC_IDE/2f4b6dc154a16e34a5dd2bf9fad5dc7cb49ddbd7/docs/image-20241209205043792.png -------------------------------------------------------------------------------- /docs/image-20241209205316029.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/1932287243/NPC_IDE/2f4b6dc154a16e34a5dd2bf9fad5dc7cb49ddbd7/docs/image-20241209205316029.png -------------------------------------------------------------------------------- /docs/image-20241209205433050.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/1932287243/NPC_IDE/2f4b6dc154a16e34a5dd2bf9fad5dc7cb49ddbd7/docs/image-20241209205433050.png -------------------------------------------------------------------------------- /docs/image-20241209205747664.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/1932287243/NPC_IDE/2f4b6dc154a16e34a5dd2bf9fad5dc7cb49ddbd7/docs/image-20241209205747664.png -------------------------------------------------------------------------------- /docs/image-20241209205951004.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/1932287243/NPC_IDE/2f4b6dc154a16e34a5dd2bf9fad5dc7cb49ddbd7/docs/image-20241209205951004.png -------------------------------------------------------------------------------- /docs/image-20241209210105185.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/1932287243/NPC_IDE/2f4b6dc154a16e34a5dd2bf9fad5dc7cb49ddbd7/docs/image-20241209210105185.png -------------------------------------------------------------------------------- /docs/image-20241209210155902.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/1932287243/NPC_IDE/2f4b6dc154a16e34a5dd2bf9fad5dc7cb49ddbd7/docs/image-20241209210155902.png -------------------------------------------------------------------------------- /docs/image-20241209210552458.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/1932287243/NPC_IDE/2f4b6dc154a16e34a5dd2bf9fad5dc7cb49ddbd7/docs/image-20241209210552458.png -------------------------------------------------------------------------------- /docs/image-20241209210556295.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/1932287243/NPC_IDE/2f4b6dc154a16e34a5dd2bf9fad5dc7cb49ddbd7/docs/image-20241209210556295.png -------------------------------------------------------------------------------- /docs/image-20241209210726156.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/1932287243/NPC_IDE/2f4b6dc154a16e34a5dd2bf9fad5dc7cb49ddbd7/docs/image-20241209210726156.png -------------------------------------------------------------------------------- /docs/image-20241209211234562.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/1932287243/NPC_IDE/2f4b6dc154a16e34a5dd2bf9fad5dc7cb49ddbd7/docs/image-20241209211234562.png -------------------------------------------------------------------------------- /docs/image-20241209211329516.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/1932287243/NPC_IDE/2f4b6dc154a16e34a5dd2bf9fad5dc7cb49ddbd7/docs/image-20241209211329516.png -------------------------------------------------------------------------------- /docs/image-20241209211345279.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/1932287243/NPC_IDE/2f4b6dc154a16e34a5dd2bf9fad5dc7cb49ddbd7/docs/image-20241209211345279.png -------------------------------------------------------------------------------- /docs/image-20241209211601507.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/1932287243/NPC_IDE/2f4b6dc154a16e34a5dd2bf9fad5dc7cb49ddbd7/docs/image-20241209211601507.png -------------------------------------------------------------------------------- /docs/image-20241209211713826.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/1932287243/NPC_IDE/2f4b6dc154a16e34a5dd2bf9fad5dc7cb49ddbd7/docs/image-20241209211713826.png -------------------------------------------------------------------------------- /docs/image-20241209211835283.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/1932287243/NPC_IDE/2f4b6dc154a16e34a5dd2bf9fad5dc7cb49ddbd7/docs/image-20241209211835283.png -------------------------------------------------------------------------------- /docs/image-20241209211907692.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/1932287243/NPC_IDE/2f4b6dc154a16e34a5dd2bf9fad5dc7cb49ddbd7/docs/image-20241209211907692.png -------------------------------------------------------------------------------- /docs/image-20241209212002167.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/1932287243/NPC_IDE/2f4b6dc154a16e34a5dd2bf9fad5dc7cb49ddbd7/docs/image-20241209212002167.png -------------------------------------------------------------------------------- /docs/image-20241209212038038.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/1932287243/NPC_IDE/2f4b6dc154a16e34a5dd2bf9fad5dc7cb49ddbd7/docs/image-20241209212038038.png -------------------------------------------------------------------------------- /docs/image-20241209212103875.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/1932287243/NPC_IDE/2f4b6dc154a16e34a5dd2bf9fad5dc7cb49ddbd7/docs/image-20241209212103875.png -------------------------------------------------------------------------------- /docs/image-20241209212328783.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/1932287243/NPC_IDE/2f4b6dc154a16e34a5dd2bf9fad5dc7cb49ddbd7/docs/image-20241209212328783.png -------------------------------------------------------------------------------- /docs/image-20241209212343230.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/1932287243/NPC_IDE/2f4b6dc154a16e34a5dd2bf9fad5dc7cb49ddbd7/docs/image-20241209212343230.png -------------------------------------------------------------------------------- /docs/image-20241209215013564.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/1932287243/NPC_IDE/2f4b6dc154a16e34a5dd2bf9fad5dc7cb49ddbd7/docs/image-20241209215013564.png -------------------------------------------------------------------------------- /include/device/npc.h: -------------------------------------------------------------------------------- 1 | #ifndef __NPC_H__ 2 | #define __NPC_H__ 3 | 4 | #include "verilated.h" 5 | #include "VCPU.h" 6 | #include "VCPU___024root.h" 7 | 8 | #include "vga.h" 9 | #include 10 | 11 | QT_BEGIN_NAMESPACE 12 | namespace Ui { class NPC; } 13 | QT_END_NAMESPACE 14 | 15 | extern uint32_t inst_from_npc; 16 | 17 | class NPC: public QThread 18 | { 19 | Q_OBJECT 20 | public: 21 | NPC( int argc, char **argv, QObject* parent = nullptr); 22 | ~NPC(); 23 | VCPU* cpu; 24 | NPCVGA *npc_vga; 25 | 26 | bool stop_flag; // 监视点触发,引起中断 27 | bool debug_flag; 28 | bool diff_result; 29 | void init_npc(); 30 | void exec(uint32_t n); 31 | 32 | public slots: 33 | 34 | protected: 35 | void run() override; 36 | 37 | private: 38 | int argc; 39 | char **argv; 40 | int quit_flag; 41 | char logbuf[128]; 42 | uint32_t last_pc; 43 | uint32_t cur_inst; 44 | 45 | void single_cycle(); 46 | void reset(int n); 47 | bool checkMemBreakpointTrigger(); 48 | bool checkRegBreakpointTrigger(); 49 | 50 | signals: 51 | void sendNPCInfoToUI(unsigned int pc); 52 | void sendRegInfo(unsigned int *reg_val); 53 | void destroyWindow(); 54 | void sendDiffError(); 55 | void updateMemory(unsigned int addr, unsigned int * vmem); 56 | }; 57 | 58 | #endif -------------------------------------------------------------------------------- /include/device/reg.h: -------------------------------------------------------------------------------- 1 | #ifndef __REG_H__ 2 | #define __REG_H__ 3 | 4 | #include 5 | #include 6 | 7 | class RISCV32Register; 8 | 9 | extern RISCV32Register *riscv32_reg; 10 | 11 | class RISCV32Register 12 | { 13 | public: 14 | 15 | // 寄存器名称数组 16 | const char *gpr_name[32] = { 17 | "$0", "ra", "sp", "gp", "tp", "t0", "t1", "t2", 18 | "fp", "s1", "a0", "a1", "a2", "a3", "a4", "a5", 19 | "a6", "a7", "s2", "s3", "s4", "s5", "s6", "s7", 20 | "s8", "s9", "s10", "s11", "t3", "t4", "t5", "t6" 21 | }; 22 | 23 | uint32_t gpr[32] = {0}; // 通用寄存器数组,初始化为0 24 | uint32_t pc; // 程序计数器 25 | uint32_t csr[9]; // 控制状态寄存器 26 | 27 | RISCV32Register(); 28 | ~RISCV32Register(); 29 | uint32_t getGPRValue(std::string regName); 30 | void setGPRValue(std::string regName, uint32_t value); 31 | void initReg(uint32_t value); 32 | void printReg(); 33 | void modifyReg(uint32_t index, uint32_t value); 34 | }; 35 | 36 | #endif -------------------------------------------------------------------------------- /include/device/timer.h: -------------------------------------------------------------------------------- 1 | #ifndef __TIMER_H__ 2 | #define __TIMER_H__ 3 | 4 | #include 5 | 6 | class NPCTimer 7 | { 8 | public: 9 | NPCTimer(); 10 | ~NPCTimer(); 11 | static uint64_t now_time; 12 | static uint64_t get_time(); 13 | private: 14 | static uint64_t boot_time; 15 | static uint64_t get_time_internal(); 16 | }; 17 | #endif -------------------------------------------------------------------------------- /include/device/vga.h: -------------------------------------------------------------------------------- 1 | #ifndef __NPCVGA_H__ 2 | #define __NPCVGA_H__ 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | class NPCVGA:public QThread 9 | { 10 | Q_OBJECT 11 | public: 12 | NPCVGA(uint32_t w = 400, uint32_t h = 300, QObject* parent = nullptr); 13 | ~NPCVGA(); 14 | static uint32_t sync_signal; 15 | static uint32_t screen_width; 16 | static uint32_t screen_height; 17 | static uint32_t *vmem; 18 | bool stop_flag; 19 | void stop(); 20 | 21 | protected: 22 | void run() override; 23 | 24 | private: 25 | void convertToRGB(const uint32_t* src, uint8_t* dest, uint32_t pixelCount); 26 | 27 | signals: 28 | void sendVGAInfoToUI(const QImage &image); 29 | 30 | }; 31 | 32 | #endif 33 | -------------------------------------------------------------------------------- /include/device/vmem.h: -------------------------------------------------------------------------------- 1 | #ifndef __VMEM_H__ 2 | #define __VMEM_H__ 3 | 4 | #include 5 | 6 | class Vmem; 7 | 8 | extern Vmem *vmem; 9 | 10 | class Vmem 11 | { 12 | public: 13 | Vmem(); 14 | ~Vmem(); 15 | uint8_t *mem_addr; 16 | void init_mem(); 17 | void free_mem(); 18 | }; 19 | 20 | #endif -------------------------------------------------------------------------------- /include/main.h: -------------------------------------------------------------------------------- 1 | #ifndef __MAIN_H__ 2 | #define __MAIN_H__ 3 | 4 | #include "mainwindow.h" 5 | #include "npc.h" 6 | #include "monitor.h" 7 | 8 | class MainWindow; 9 | class NPC; 10 | class Monitor; 11 | 12 | extern MainWindow *ui; 13 | extern NPC *mNPC; 14 | extern Monitor *monitor; 15 | extern int mode_sel; 16 | 17 | enum DisplayMode { 18 | DISPLAY_IDE_ONLY = 1, // 1: display IDE, but don't SDB 19 | DISPLAY_SDB_ONLY = 2, // 2: don't display IDE, but display SDB 20 | DISPLAY_BOTH = 3, // 3: display IDE and SDB 21 | BATCH_MODE = 4 // 4: batch mode 22 | }; 23 | 24 | #endif -------------------------------------------------------------------------------- /include/monitor/monitor.h: -------------------------------------------------------------------------------- 1 | #ifndef MONITOR_H 2 | #define MONITOR_H 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | #include "sdb/sdb.h" 9 | #include "tools/ftrace.h" 10 | #include "tools/difftest.h" 11 | 12 | class SDB; 13 | class Ftrace; 14 | class DiffTest; 15 | 16 | class Monitor:public QThread 17 | { 18 | Q_OBJECT 19 | public: 20 | Monitor(std::string log_file, std::string elf_file, std::string diff_so_file, std::string img_file); 21 | ~Monitor(); 22 | DiffTest *difftest; 23 | Ftrace *ftrace; 24 | SDB *sdb; 25 | int image_size; 26 | int inst_num; 27 | bool stop_flag; 28 | void init_monitor(int argc, char* argv[]); 29 | void stop(); 30 | 31 | 32 | protected: 33 | void run() override; 34 | 35 | private: 36 | // Data members 37 | int argc; 38 | char **argv; 39 | std::string log_file; 40 | std::string elf_file; 41 | std::string diff_so_file; 42 | std::string img_file; 43 | FILE* log_fp; 44 | 45 | // Member functions 46 | void welcome() const; 47 | 48 | void initLog(); 49 | 50 | long loadImage(); 51 | 52 | void initDifftest(long img_size) const; 53 | 54 | signals: 55 | void destroyWindow(); 56 | 57 | }; 58 | 59 | #endif // MONITOR_H 60 | -------------------------------------------------------------------------------- /include/monitor/sdb/expr.h: -------------------------------------------------------------------------------- 1 | #ifndef __EXPR_H__ 2 | #define __EXPR_H__ 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | // #include "common.h" 9 | #include 10 | 11 | #define __FOR_TEST__ 12 | 13 | class EXPR 14 | { 15 | public: 16 | enum TokenType { 17 | TK_NOTYPE = 256, TK_ADD, TK_SUB, TK_MULT, TK_DIV, TK_EQ, TK_NEQ, TK_AND, TK_OR, 18 | TK_DEREF, TK_INTEGER, TK_HEX, TK_REG, TK_L_BRACKET, TK_R_BRACKET 19 | }; 20 | 21 | struct Token { 22 | int type; 23 | std::string str; 24 | }; 25 | 26 | EXPR(); 27 | ~EXPR(); 28 | void initExpr(); 29 | uint32_t evaluate(const std::string &expression, bool &success); 30 | 31 | private: 32 | struct Rule { 33 | std::string regex; 34 | int tokenType; 35 | }; 36 | 37 | std::vector rules; // 38 | std::vector regexPatterns; // 正则表达式对象 39 | std::vector tokens; 40 | int parenthesesNum = 0; 41 | bool sub_flag = false; 42 | 43 | void initRules(); 44 | // 初始化正则表达式, 用于匹配输入表达式中的不同类型的符号和数值。 45 | void initRegex(); 46 | // 词法分析:匹配表达式中的数字和符号 47 | bool tokenize(const std::string &expression); 48 | // 处理得到token 49 | bool handleToken(Token &token); 50 | // 递归寻找表达式里面的括号 51 | void recursionCheck(int p, int q); 52 | // 检查在tokens中p和q索引处的左右括号是否一对 53 | bool checkParentheses(int p, int q); 54 | // 在寻找主操作符号的时候找到优先级最低的操作符号 55 | int getPrecedence(int type); 56 | // 找到主操作符号 57 | int findMainOperator(int p, int q); 58 | uint32_t eval(int p, int q); 59 | }; 60 | #endif -------------------------------------------------------------------------------- /include/monitor/sdb/sdb.h: -------------------------------------------------------------------------------- 1 | #ifndef __SDB_H__ 2 | #define __SDB_H__ 3 | 4 | #include 5 | #include 6 | #include "expr.h" 7 | #include "watchpoint.h" 8 | 9 | class EXPR; 10 | class WatchPointManager; 11 | 12 | class SDB 13 | { 14 | public: 15 | SDB(); 16 | ~SDB(); 17 | void init_sdb(); // init sdb 18 | int sdb_mainloop(); // sdb cmd 19 | int skip_batch_flag; 20 | EXPR *expr; 21 | WatchPointManager *watchpoint; 22 | bool stop_flag; 23 | 24 | private: 25 | int cmd_help(char *args); // help cmd 26 | void cmd_q(char *args); // quit cmd 27 | int cmd_d(char *args); // delete monitor point 28 | int cmd_w(char *args); // set monitor point 29 | int cmd_p(char *args); // expression evaluation 30 | int cmd_x(char *args); // Scan Memory 31 | int cmd_info(char *args); // Print register status and monitoring point information 32 | int cmd_si(char *args); // Single step execution 33 | int cmd_c(char *args); // continue to operate 34 | int executeCommand(const std::string& cmd, char* args); 35 | char* rl_gets(); 36 | char *line_read; 37 | 38 | std::vector> cmd_table; 39 | 40 | }; 41 | 42 | #endif 43 | -------------------------------------------------------------------------------- /include/monitor/sdb/watchpoint.h: -------------------------------------------------------------------------------- 1 | #ifndef __WATCHPOINTMANAGER_H__ 2 | #define __WATCHPOINTMANAGER_H__ 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | #define NR_WP 32 // 定义观察点池大小 11 | 12 | class WatchPoint { 13 | public: 14 | int NO; // 观察点编号 15 | bool enb = false; // 是否启用 16 | std::string expr; // 表达式 17 | WatchPoint* next = nullptr; // 指向下一个观察点的指针 18 | 19 | WatchPoint() : NO(0), enb(false), expr(""), next(nullptr) {} 20 | 21 | }; 22 | 23 | class WatchPointManager { 24 | public: 25 | // bool stop_flag; 26 | WatchPointManager(); 27 | ~WatchPointManager(); 28 | void initPool(); 29 | 30 | WatchPoint* newWatchPoint(); 31 | WatchPoint* head; // 已使用观察点链表头指针 32 | 33 | void freeWatchPoint(WatchPoint* wp); 34 | 35 | bool freeWatchPointByNo(int w_no); 36 | 37 | void printWatchPoints() const; 38 | 39 | // protected: 40 | // void run() override; 41 | 42 | private: 43 | WatchPoint wp_pool[NR_WP]; // 观察点池 44 | WatchPoint* free_; // 空闲观察点链表头指针 45 | 46 | }; 47 | #endif -------------------------------------------------------------------------------- /include/monitor/tools/difftest.h: -------------------------------------------------------------------------------- 1 | #ifndef DIFFTEST_H 2 | #define DIFFTEST_H 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | #include 9 | 10 | struct RISCV32_CPUState { 11 | uint32_t gpr[32] = {0}; // 通用寄存器 12 | uint32_t pc = 0; // 程序计数器 13 | uint32_t csr[9] = {0}; // 控制状态寄存器 14 | }; 15 | 16 | class DiffTest { 17 | private: 18 | void* handle = nullptr; 19 | 20 | // 函数指针 21 | using MemCpyFunc = void (*)(uint32_t, void*, size_t, bool); 22 | using RegCpyFunc = void (*)(void*, bool); 23 | using ExecFunc = void (*)(uint64_t); 24 | using RaiseIntrFunc = void (*)(uint64_t); 25 | using InitFunc = void (*)(int); 26 | 27 | MemCpyFunc ref_difftest_memcpy = nullptr; 28 | RegCpyFunc ref_difftest_regcpy = nullptr; 29 | ExecFunc ref_difftest_exec = nullptr; 30 | RaiseIntrFunc ref_difftest_raise_intr = nullptr; 31 | size_t img_size; 32 | uint8_t* mem_addr; 33 | 34 | public: 35 | DiffTest() ; 36 | 37 | ~DiffTest(); 38 | 39 | RISCV32_CPUState cpu; // 当前 CPU 状态 40 | 41 | void initDifftest(const std::string& ref_so_file, size_t img_size, uint8_t* mem_addr); 42 | 43 | bool checkRegisters(const RISCV32_CPUState& ref_r, uint32_t pc) const; 44 | 45 | bool step(uint32_t pc, int inst_skip_flag); 46 | }; 47 | 48 | #endif // DIFFTEST_H 49 | 50 | -------------------------------------------------------------------------------- /include/monitor/tools/ftrace.h: -------------------------------------------------------------------------------- 1 | #ifndef FTRACE_H 2 | #define FTRACE_H 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | class Ftrace { 9 | public: 10 | struct FuncSym { 11 | char func_name[20]; 12 | uint32_t func_addr; 13 | uint32_t func_size; 14 | }; 15 | 16 | Ftrace() : elf_fp(nullptr), func_sym_num(0) {} 17 | 18 | ~Ftrace() { 19 | std::cout << "delete ftrace\n"; 20 | if (elf_fp) { 21 | fclose(elf_fp); 22 | } 23 | } 24 | int func_sym_num; 25 | std::vector func_sym_tab; 26 | std::string src; 27 | 28 | void initFtrace(const std::string &elf_file); 29 | int instTotal(const std::string &elf_file); 30 | void getSourceCode(const std::string &elf_file); 31 | 32 | private: 33 | FILE *elf_fp; 34 | 35 | Elf32_Ehdr ehdr; 36 | Elf32_Shdr symtab_shdr; 37 | Elf32_Shdr strtab_shdr; 38 | 39 | void parseElfSymbols(const std::string &filename); 40 | void getElfHeader(); 41 | void getElfSection(); 42 | void getElfSymbols(); 43 | }; 44 | 45 | #endif // FTRACE_H -------------------------------------------------------------------------------- /include/ui/codeeditor.h: -------------------------------------------------------------------------------- 1 | #ifndef CODEEDITOR_H 2 | #define CODEEDITOR_H 3 | 4 | #include "highlighter.h" 5 | 6 | #include 7 | #include 8 | 9 | class LineNumberWidget; 10 | 11 | class CodeEditor : public QPlainTextEdit 12 | { 13 | Q_OBJECT 14 | public: 15 | explicit CodeEditor(QWidget *parent = nullptr,QFont font=QFont("Consolas",14)); 16 | 17 | ~CodeEditor(); 18 | 19 | void lineNumberWidgetPaintEvent(QPaintEvent * event); 20 | void lineNumberWidgetMousePressEvent(QMouseEvent *event); 21 | void lineNumberWidgetWheelEvent(QWheelEvent *event); 22 | 23 | void removeLastHighlights(int lineNumber); 24 | void highlightLine(int lineNumber, QColor color); 25 | 26 | bool saveFile(); 27 | bool saveAsFile(); 28 | 29 | void setFileName(QString fileName); 30 | QString getFileName(); 31 | 32 | void setAllFont(QFont font); 33 | 34 | bool checkSaved(); 35 | 36 | private slots: 37 | void highlightCurrentLine(); 38 | void updateLineNumberWidget(QRect rect, int dy); 39 | void updateLineNumberWidgetWidth(); 40 | void updateSaveState(); 41 | 42 | void insertCompletion(const QString &completion); 43 | 44 | protected: 45 | void resizeEvent(QResizeEvent *event) override; 46 | void keyPressEvent(QKeyEvent * event) override; 47 | 48 | private: 49 | void initConnection(); 50 | void initHighlighter(); 51 | void initCompleter(); 52 | int getLineNumberWidgetWidth(); 53 | 54 | 55 | LineNumberWidget * lineNumberWidget; 56 | Highlighter * mHighlighter; 57 | 58 | QString mFileName; 59 | bool isSaved = false; 60 | QCompleter * mCompleter; 61 | 62 | signals: 63 | 64 | }; 65 | 66 | class LineNumberWidget :public QWidget{ 67 | public: 68 | explicit LineNumberWidget(CodeEditor *editor=nullptr):QWidget(editor){ 69 | codeEditor=editor; 70 | } 71 | 72 | protected: 73 | void paintEvent(QPaintEvent *event) override{ 74 | //把绘制任务提交给CodeEditor 75 | codeEditor->lineNumberWidgetPaintEvent(event); 76 | } 77 | void mousePressEvent(QMouseEvent *event) override{ 78 | //把鼠标点击任务提交给CodeEditor 79 | codeEditor->lineNumberWidgetMousePressEvent(event); 80 | } 81 | 82 | void wheelEvent(QWheelEvent *event) override{ 83 | //把滚轮任务提交给CodeEditor 84 | codeEditor->lineNumberWidgetWheelEvent(event); 85 | } 86 | 87 | private: 88 | CodeEditor *codeEditor; 89 | }; 90 | 91 | #endif // CodeEditor_H 92 | -------------------------------------------------------------------------------- /include/ui/csrmonitor.h: -------------------------------------------------------------------------------- 1 | #ifndef __CSRMONITOR_H__ 2 | #define __CSRMONITOR_H__ 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | class CSRMonitor:public QTableWidget 9 | { 10 | public: 11 | CSRMonitor(); 12 | ~CSRMonitor(); 13 | void initCSRMonitor(); 14 | 15 | QList> csr_breakpoint; 16 | 17 | public slots: 18 | void receiveCSRValue(unsigned int *csr_val); 19 | 20 | private: 21 | int last_csr_pos; 22 | 23 | private slots: 24 | void setCSRBreakpoint(int row, int column); 25 | 26 | }; 27 | 28 | #endif -------------------------------------------------------------------------------- /include/ui/filesystemmodel.h: -------------------------------------------------------------------------------- 1 | #ifndef FILESYSTEMMODEL_H 2 | #define FILESYSTEMMODEL_H 3 | 4 | #include 5 | #include 6 | 7 | class FileSystemModel : public QFileSystemModel 8 | { 9 | Q_OBJECT 10 | public: 11 | explicit FileSystemModel(QObject *parent = nullptr); 12 | 13 | protected: 14 | Qt::ItemFlags flags(const QModelIndex &index) const override; 15 | 16 | int columnCount(const QModelIndex &parent = QModelIndex()) const override; 17 | 18 | bool setData(const QModelIndex &index, const QVariant &value, int role = Qt::EditRole) override; 19 | }; 20 | 21 | #endif // FileSystemModel_H 22 | -------------------------------------------------------------------------------- /include/ui/gprmonitor.h: -------------------------------------------------------------------------------- 1 | #ifndef __GPRMONITOR_H__ 2 | #define __GPRMONITOR_H__ 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | #include 9 | #include 10 | 11 | class GPRMonitor:public QWidget 12 | { 13 | public: 14 | GPRMonitor(QWidget *parent); 15 | ~GPRMonitor(); 16 | void initGPRMonitor(); 17 | QList> gpr_breakpoint; 18 | QTableWidget *gprTableWidget; 19 | void setFont(QString fontFamily, int fontSize); 20 | 21 | public slots: 22 | void receiveGPRValue(unsigned int *gpr_val); 23 | 24 | private: 25 | int last_gpr_pos; 26 | QLabel *title_label; 27 | void initLabel(); 28 | void initTableWidget(); 29 | 30 | private slots: 31 | void setGPRBreakpoint(int row, int column); 32 | 33 | }; 34 | 35 | #endif -------------------------------------------------------------------------------- /include/ui/highlighter.h: -------------------------------------------------------------------------------- 1 | #ifndef HIGHLIGHTER_H 2 | #define HIGHLIGHTER_H 3 | 4 | #include 5 | #include 6 | 7 | class Highlighter: public QSyntaxHighlighter 8 | { 9 | public: 10 | explicit Highlighter(QTextDocument *parent = nullptr,QString fontFamily="Consolas",int fontSize=14); 11 | void setFont(QFont font); 12 | protected: 13 | void highlightBlock(const QString &text) ; 14 | 15 | private: 16 | 17 | QString mFontFamily ; 18 | int mFontSize ; 19 | 20 | struct HighlightRule{ 21 | QRegExp pattern; 22 | QTextCharFormat format; 23 | }; 24 | 25 | QVector highlightRules; 26 | 27 | void initFormat(); 28 | 29 | void addNormalTextFormat(); 30 | void addNumberFormat(); 31 | void addStringFormat(); 32 | void addCommentFormat(); 33 | 34 | void addMultiLineCommentFormat(const QString &text); 35 | 36 | void addKeywordsFromat(); 37 | void addClassNameFormat(); 38 | void addFunctionFormat(); 39 | }; 40 | 41 | #endif // Highlighter_H 42 | -------------------------------------------------------------------------------- /include/ui/instmonitor.h: -------------------------------------------------------------------------------- 1 | #ifndef __INSTMONITOR_H__ 2 | #define __INSTMONITOR_H__ 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | class InstMonitor:public QWidget 11 | { 12 | Q_OBJECT 13 | public: 14 | InstMonitor(QWidget *parent); 15 | ~InstMonitor(); 16 | void InitInstMonitor(unsigned int * vmem, int inst_num); 17 | void setFont(QString fontFamily, int fontSize); 18 | 19 | QList> mem_breakpoint; 20 | 21 | public slots: 22 | void receiveNPCInfo(unsigned int pc); 23 | void setMemBreakpoint(int row, int column); 24 | void receiveDiffError(); 25 | 26 | private: 27 | unsigned int * vmem; 28 | int inst_num; 29 | uint32_t last_pc; 30 | QLabel *instMemLabel; 31 | QTableWidget *instTableWidget; 32 | 33 | void initTitle(); 34 | void initTableWidget(); 35 | 36 | }; 37 | 38 | #endif -------------------------------------------------------------------------------- /include/ui/mainwindow.h: -------------------------------------------------------------------------------- 1 | #ifndef MAINWINDOW_H 2 | #define MAINWINDOW_H 3 | 4 | #include 5 | #include "QSettings" 6 | #include 7 | #include 8 | 9 | #include "filesystemmodel.h" 10 | #include "codeeditor.h" 11 | #include "splitterlayout.h" 12 | 13 | QT_BEGIN_NAMESPACE 14 | namespace Ui { class MainWindow; } 15 | QT_END_NAMESPACE 16 | 17 | class MainWindow : public QMainWindow 18 | { 19 | Q_OBJECT 20 | 21 | public: 22 | MainWindow( int argc, char **argv, QWidget *parent = nullptr); 23 | ~MainWindow(); 24 | 25 | SplitterLayout *mSplitterLayout ; 26 | 27 | void saveSuccessAction( CodeEditor * codeEditor); 28 | void addFolder(QString filePath); 29 | void init(unsigned int * vmem_addr, int inst_num); 30 | 31 | protected: 32 | void closeEvent(QCloseEvent *event); 33 | 34 | public slots: 35 | void onDestroyWindow(); 36 | 37 | private slots: 38 | void on_new_file_triggered(); 39 | 40 | void on_open_dir_triggered(); 41 | 42 | void on_save_file_triggered(); 43 | 44 | void on_save_as_triggered(); 45 | 46 | void on_paste_triggered(); 47 | 48 | void on_cut_triggered(); 49 | 50 | void on_copy_triggered(); 51 | 52 | void on_font_triggered(); 53 | 54 | void on_about_triggered(); 55 | 56 | void on_undo_triggered(); 57 | 58 | void on_redo_triggered(); 59 | 60 | void on_exit_triggered(); 61 | 62 | void on_print_triggered(); 63 | 64 | void on_clear_history_triggered(); 65 | 66 | void onFinishCreateTab(const QString &filePath); 67 | 68 | void onItemClicked(QListWidgetItem *item); 69 | 70 | void receiveImageFromNPC(const QImage &image); 71 | 72 | void exec(); 73 | 74 | void execOne(); 75 | 76 | void isDebugMode(bool checked); 77 | 78 | private: 79 | Ui::MainWindow *ui; 80 | 81 | QSettings * mSettings; 82 | QString mFontFamily; 83 | int mFontSize; 84 | 85 | QString mDir="E:/"; 86 | 87 | void initMenu(); 88 | void initFont(); 89 | void initAction(int tabCount); 90 | 91 | void on_open_rencent_file(); 92 | void saveHistory(QString path); 93 | QList getHistory(); 94 | 95 | void createTab(QString fileName); 96 | 97 | void setTreeViewModel(); 98 | 99 | 100 | }; 101 | #endif // MAINWINDOW_H 102 | -------------------------------------------------------------------------------- /include/ui/memviewer.h: -------------------------------------------------------------------------------- 1 | #ifndef __MEMVIEWER_H__ 2 | #define __MEMVIEWER_H__ 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | class MemViewer:public QWidget 12 | { 13 | public: 14 | MemViewer(QWidget *parent); 15 | ~MemViewer(); 16 | void initVMem(uint8_t * vmem); 17 | void setFont(QString fontFamily="Consolas",int fontSize=14); 18 | 19 | private slots: 20 | void findDataMemToUI(); 21 | 22 | private: 23 | QLabel *dataMemLabel; 24 | 25 | QLabel *start_address; 26 | QLineEdit *addressLineEdit; 27 | QLabel *offset; 28 | QLineEdit *offsetLineEdit; 29 | QPushButton *dataMemFindbutton; 30 | 31 | QTableWidget * dataMemTableWidget; 32 | 33 | uint8_t * vmem_addr; 34 | 35 | void InitTableWidget(); 36 | QLabel * initLabel(QString name); 37 | }; 38 | 39 | #endif -------------------------------------------------------------------------------- /include/ui/splitterlayout.h: -------------------------------------------------------------------------------- 1 | #ifndef SPLITTERLAYOUT_H 2 | #define SPLITTERLAYOUT_H 3 | 4 | #include "treeview.h" 5 | 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | 20 | #include "disasm.h" 21 | #include "instmonitor.h" 22 | #include "gprmonitor.h" 23 | #include "memviewer.h" 24 | 25 | class InstMonitor; 26 | class GPRMonitor; 27 | class MemViewer; 28 | 29 | class SplitterLayout : public QSplitter 30 | { 31 | Q_OBJECT 32 | public: 33 | explicit SplitterLayout(QWidget * parent =nullptr,QString dir="E:/",QString fontFamily="Consolas",int fontSize=14); 34 | 35 | TreeView * getTreeView(); 36 | 37 | QLabel *getLabel(); 38 | 39 | QTabWidget *getTabWidget(); 40 | 41 | void setDir(const QString &dir); 42 | 43 | void setFont(const QFont &font); 44 | 45 | void splitterlayoutInit(unsigned int * vmem, int inst_num); 46 | 47 | void showSourceFromElf(QString src); 48 | 49 | void showSrcMapInst(int line_num); 50 | 51 | GPRMonitor *gprWidget; 52 | InstMonitor *instMemWidget; 53 | MemViewer *dataMemLayoutWidget; 54 | 55 | QList> srcMapInst; 56 | 57 | public slots: 58 | void createTab(const QString &filePath); 59 | void onTabWidgetCloseRequested(int index); 60 | 61 | private slots: 62 | void onDataChanged(const QString &preFilePath,const QString &filePath); 63 | 64 | signals: 65 | void finishCreateTab(const QString &filePath); 66 | 67 | private: 68 | QLabel * createLabel(); 69 | 70 | QVBoxLayout * createVLayout(QWidget * parent); 71 | 72 | QTabWidget * createTabWidget(); 73 | 74 | TreeView * createTreeView(); 75 | 76 | QString mFontFamily; 77 | int mFontSize; 78 | QString mDir; 79 | int last_lineNumber; 80 | 81 | QRegularExpressionValidator *validator; 82 | QPushButton *dataMemFindbutton; 83 | QSplitter *instMemSplitter; // 创建一个 指令内存 QSplitter 84 | QSplitter *dataMemSplitter; // 创建一个 数据内存 QSplitter 85 | QSplitter *regSplitter; // 创建一个 寄存器 QSplitter 86 | 87 | QLabel *pathLabel ; 88 | QLabel *instMemLabel ; 89 | QLabel *dataMemLabel ; 90 | QLabel *regLabel ; 91 | 92 | TreeView * mTreeView ; 93 | QVBoxLayout * mVLayout; 94 | QVBoxLayout * instMemVLayout; 95 | QVBoxLayout * dataMemVLayout; 96 | QHBoxLayout * dataInputHLayout; 97 | 98 | QVBoxLayout * regVLayout; 99 | QTabWidget * fileLabelTabWidget; 100 | 101 | CodeEditor * debugEditor; 102 | 103 | }; 104 | 105 | #endif // SplitterLayout_H 106 | -------------------------------------------------------------------------------- /include/ui/treeview.h: -------------------------------------------------------------------------------- 1 | #ifndef TREEVIEW_H 2 | #define TREEVIEW_H 3 | 4 | #include "filesystemmodel.h" 5 | 6 | #include 7 | #include 8 | #include 9 | 10 | class TreeView : public QTreeView 11 | { 12 | Q_OBJECT 13 | public: 14 | explicit TreeView(QWidget * parent=nullptr,QString dir="E:/"); 15 | 16 | void newFile(); 17 | 18 | void setDir(const QString &dir); 19 | 20 | private slots: 21 | void showCustomContextMenu(const QPoint &pos); 22 | void onTreeViewDoubleClicked(const QModelIndex &index); 23 | void onModelDataChanged(const QModelIndex &index); 24 | 25 | signals: 26 | void createTab(const QString &filePath); 27 | void onDataChanged(const QString &preFilePath,const QString &filePath); 28 | 29 | private: 30 | QString mFontFamily; 31 | int mFontSize; 32 | FileSystemModel * mFileSystemModel ; 33 | 34 | QString mDir; 35 | QString preFilePath; 36 | 37 | 38 | void setTreeViewModel(); 39 | 40 | }; 41 | 42 | #endif // TreeView_H 43 | -------------------------------------------------------------------------------- /include/utils/common.h: -------------------------------------------------------------------------------- 1 | #ifndef __COMMON_H__ 2 | #define __COMMON_H__ 3 | 4 | #include 5 | 6 | #endif 7 | -------------------------------------------------------------------------------- /include/utils/disasm.h: -------------------------------------------------------------------------------- 1 | #ifndef __DISASM_H__ 2 | #define __DISASM_H__ 3 | 4 | #include "common.h" 5 | 6 | extern "C" { 7 | extern void init_disasm(const char *triple); 8 | extern void disassemble(char *str, int size, uint64_t pc, uint8_t *code, int nbyte); 9 | } 10 | #endif 11 | -------------------------------------------------------------------------------- /include/utils/utils.h: -------------------------------------------------------------------------------- 1 | #ifndef __UTILS_H__ 2 | #define __UTILS_H__ 3 | 4 | #include 5 | 6 | #define log_write(...) IFDEF(CONFIG_TARGET_NATIVE_ELF, \ 7 | do { \ 8 | extern FILE* log_fp; \ 9 | extern long inst_s_log_fp;\ 10 | extern bool update_inst_file;\ 11 | extern bool start_record_inst;\ 12 | extern bool update_mem_log;\ 13 | extern bool log_enable(); \ 14 | if (log_enable()) { \ 15 | if(update_inst_file==true)\ 16 | fseek(log_fp, inst_s_log_fp, SEEK_SET);\ 17 | if(update_mem_log==true)\ 18 | fseek(log_fp, inst_s_log_fp, SEEK_SET);\ 19 | fprintf(log_fp, __VA_ARGS__); \ 20 | fflush(log_fp); \ 21 | if(start_record_inst==false||update_mem_log==true)\ 22 | inst_s_log_fp=ftell(log_fp);\ 23 | } \ 24 | } while (0) \ 25 | ) 26 | 27 | #define _Log(...) \ 28 | do { \ 29 | printf(__VA_ARGS__); \ 30 | log_write(__VA_ARGS__); \ 31 | } while (0) 32 | 33 | #define Assert(cond, format, ...) \ 34 | do { \ 35 | if (!(cond)) { \ 36 | fprintf(stderr, format "\n", ## __VA_ARGS__); \ 37 | assert(cond); \ 38 | } \ 39 | } while (0) 40 | 41 | #define Perror(cond, format, ...) \ 42 | Assert(cond, format ": %s", ## __VA_ARGS__, strerror(errno)) 43 | 44 | #define panic(...) Assert(0, __VA_ARGS__) 45 | 46 | 47 | #endif -------------------------------------------------------------------------------- /res/code.qrc: -------------------------------------------------------------------------------- 1 | 2 | 3 | config/keywords.txt 4 | 5 | 6 | -------------------------------------------------------------------------------- /res/config/keywords.txt: -------------------------------------------------------------------------------- 1 | alignas 2 | alignof 3 | andb 4 | and_eqb 5 | asma 6 | auto 7 | bitandb 8 | bitorb 9 | bool 10 | break 11 | case 12 | catch 13 | char 14 | char8_tc 15 | char16_t 16 | char32_t 17 | class 18 | complb 19 | conceptc 20 | const 21 | const_cast 22 | constevalc 23 | constexpr 24 | constinitc 25 | continue 26 | co_awaitc 27 | co_returnc 28 | co_yieldc 29 | decltype 30 | default 31 | delete 32 | do 33 | double 34 | dynamic_cast 35 | else 36 | enum 37 | explicit 38 | exportc 39 | extern 40 | false 41 | float 42 | for 43 | friend 44 | goto 45 | if 46 | inline 47 | int 48 | long 49 | mutable 50 | namespace 51 | new 52 | noexcept 53 | notb 54 | not_eqb 55 | nullptr 56 | operator 57 | orb 58 | or_eqb 59 | private 60 | protected 61 | public 62 | register reinterpret_cast 63 | requiresc 64 | return 65 | short 66 | signed 67 | sizeof 68 | static 69 | static_assert 70 | static_cast 71 | struct 72 | switch 73 | template 74 | this 75 | thread_local 76 | throw 77 | true 78 | try 79 | typedef 80 | typeid 81 | typename 82 | union 83 | unsigned 84 | using 85 | using 86 | virtual 87 | void 88 | volatile 89 | wchar_t 90 | while 91 | xorb 92 | xor_eqb 93 | abstract 94 | assert 95 | boolean 96 | break 97 | byte 98 | case 99 | catch 100 | char 101 | class 102 | continue 103 | default 104 | do 105 | double 106 | else 107 | enum 108 | extends 109 | final 110 | finally 111 | float 112 | for 113 | if 114 | implements 115 | import 116 | int 117 | interface 118 | instanceof 119 | long 120 | native 121 | new 122 | package 123 | private 124 | protected 125 | public 126 | return 127 | short 128 | static 129 | strictfp 130 | super 131 | switch 132 | synchronized 133 | this 134 | throw 135 | throws 136 | transient 137 | try 138 | void 139 | volatile 140 | while 141 | -------------------------------------------------------------------------------- /res/images.qrc: -------------------------------------------------------------------------------- 1 | 2 | 3 | images/bold.png 4 | images/copy.png 5 | images/create.png 6 | images/cut.png 7 | images/edit_redo.png 8 | images/edit_undo.png 9 | images/exit.png 10 | images/font.png 11 | images/info.png 12 | images/italic.png 13 | images/new.png 14 | images/open.png 15 | images/paste.png 16 | images/pencil.png 17 | images/print.png 18 | images/save.png 19 | images/save_as.png 20 | images/underline.png 21 | images/breakpoint.png 22 | images/triggerbp.png 23 | images/runtocomp.png 24 | images/step.png 25 | images/step_func.png 26 | images/start_debug.png 27 | images/stop_debug.png 28 | 29 | 30 | -------------------------------------------------------------------------------- /res/images/bold.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/1932287243/NPC_IDE/2f4b6dc154a16e34a5dd2bf9fad5dc7cb49ddbd7/res/images/bold.png -------------------------------------------------------------------------------- /res/images/breakpoint.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/1932287243/NPC_IDE/2f4b6dc154a16e34a5dd2bf9fad5dc7cb49ddbd7/res/images/breakpoint.png -------------------------------------------------------------------------------- /res/images/copy.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/1932287243/NPC_IDE/2f4b6dc154a16e34a5dd2bf9fad5dc7cb49ddbd7/res/images/copy.png -------------------------------------------------------------------------------- /res/images/create.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/1932287243/NPC_IDE/2f4b6dc154a16e34a5dd2bf9fad5dc7cb49ddbd7/res/images/create.png -------------------------------------------------------------------------------- /res/images/cut.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/1932287243/NPC_IDE/2f4b6dc154a16e34a5dd2bf9fad5dc7cb49ddbd7/res/images/cut.png -------------------------------------------------------------------------------- /res/images/edit_redo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/1932287243/NPC_IDE/2f4b6dc154a16e34a5dd2bf9fad5dc7cb49ddbd7/res/images/edit_redo.png -------------------------------------------------------------------------------- /res/images/edit_undo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/1932287243/NPC_IDE/2f4b6dc154a16e34a5dd2bf9fad5dc7cb49ddbd7/res/images/edit_undo.png -------------------------------------------------------------------------------- /res/images/exit.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/1932287243/NPC_IDE/2f4b6dc154a16e34a5dd2bf9fad5dc7cb49ddbd7/res/images/exit.png -------------------------------------------------------------------------------- /res/images/font.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/1932287243/NPC_IDE/2f4b6dc154a16e34a5dd2bf9fad5dc7cb49ddbd7/res/images/font.png -------------------------------------------------------------------------------- /res/images/info.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/1932287243/NPC_IDE/2f4b6dc154a16e34a5dd2bf9fad5dc7cb49ddbd7/res/images/info.png -------------------------------------------------------------------------------- /res/images/italic.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/1932287243/NPC_IDE/2f4b6dc154a16e34a5dd2bf9fad5dc7cb49ddbd7/res/images/italic.png -------------------------------------------------------------------------------- /res/images/logo.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/1932287243/NPC_IDE/2f4b6dc154a16e34a5dd2bf9fad5dc7cb49ddbd7/res/images/logo.ico -------------------------------------------------------------------------------- /res/images/new.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/1932287243/NPC_IDE/2f4b6dc154a16e34a5dd2bf9fad5dc7cb49ddbd7/res/images/new.png -------------------------------------------------------------------------------- /res/images/open.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/1932287243/NPC_IDE/2f4b6dc154a16e34a5dd2bf9fad5dc7cb49ddbd7/res/images/open.png -------------------------------------------------------------------------------- /res/images/paste.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/1932287243/NPC_IDE/2f4b6dc154a16e34a5dd2bf9fad5dc7cb49ddbd7/res/images/paste.png -------------------------------------------------------------------------------- /res/images/pencil.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/1932287243/NPC_IDE/2f4b6dc154a16e34a5dd2bf9fad5dc7cb49ddbd7/res/images/pencil.png -------------------------------------------------------------------------------- /res/images/print.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/1932287243/NPC_IDE/2f4b6dc154a16e34a5dd2bf9fad5dc7cb49ddbd7/res/images/print.png -------------------------------------------------------------------------------- /res/images/runtocomp.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/1932287243/NPC_IDE/2f4b6dc154a16e34a5dd2bf9fad5dc7cb49ddbd7/res/images/runtocomp.png -------------------------------------------------------------------------------- /res/images/save.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/1932287243/NPC_IDE/2f4b6dc154a16e34a5dd2bf9fad5dc7cb49ddbd7/res/images/save.png -------------------------------------------------------------------------------- /res/images/save_as.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/1932287243/NPC_IDE/2f4b6dc154a16e34a5dd2bf9fad5dc7cb49ddbd7/res/images/save_as.png -------------------------------------------------------------------------------- /res/images/start_debug.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/1932287243/NPC_IDE/2f4b6dc154a16e34a5dd2bf9fad5dc7cb49ddbd7/res/images/start_debug.png -------------------------------------------------------------------------------- /res/images/step.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/1932287243/NPC_IDE/2f4b6dc154a16e34a5dd2bf9fad5dc7cb49ddbd7/res/images/step.png -------------------------------------------------------------------------------- /res/images/step_func.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/1932287243/NPC_IDE/2f4b6dc154a16e34a5dd2bf9fad5dc7cb49ddbd7/res/images/step_func.png -------------------------------------------------------------------------------- /res/images/stop_debug.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/1932287243/NPC_IDE/2f4b6dc154a16e34a5dd2bf9fad5dc7cb49ddbd7/res/images/stop_debug.png -------------------------------------------------------------------------------- /res/images/triggerbp.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/1932287243/NPC_IDE/2f4b6dc154a16e34a5dd2bf9fad5dc7cb49ddbd7/res/images/triggerbp.png -------------------------------------------------------------------------------- /res/images/underline.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/1932287243/NPC_IDE/2f4b6dc154a16e34a5dd2bf9fad5dc7cb49ddbd7/res/images/underline.png -------------------------------------------------------------------------------- /src/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # find_package(Qt5 COMPONENTS Core Gui REQUIRED) 2 | find_package(Qt5 REQUIRED COMPONENTS Core Widgets Gui OpenGL) 3 | # 查找PrintSupport库 4 | find_package(Qt5 COMPONENTS PrintSupport) 5 | 6 | find_package(verilator HINTS $ENV{VERILATOR_ROOT} ${VERILATOR_ROOT}) 7 | if (NOT verilator_FOUND) 8 | message(FATAL_ERROR "Verilator was not found. Either install it, or set the VERILATOR_ROOT environment variable") 9 | endif() 10 | 11 | 12 | # 启用自动处理选项 13 | set(CMAKE_AUTOUIC ON) 14 | set(CMAKE_AUTOMOC ON) 15 | set(CMAKE_AUTORCC ON) 16 | # set_property(SOURCE ${QRC_FILES} ${UI_FILES} PROPERTY SKIP_AUTOGEN ON) 17 | set(CMAKE_AUTOUIC_SEARCH_PATHS ${CMAKE_SOURCE_DIR}/ui ${CMAKE_SOURCE_DIR}/res) 18 | 19 | # 指定 UI 文件所在的目录 20 | set(UI_FILES 21 | ${PROJECT_SOURCE_DIR}/ui/mainwindow.ui 22 | ${PROJECT_SOURCE_DIR}/ui/textedit.ui 23 | ) 24 | 25 | # 指定资源文件所在的目录 26 | set(QRC_FILES 27 | ${PROJECT_SOURCE_DIR}/res/images.qrc 28 | ${PROJECT_SOURCE_DIR}/res/code.qrc 29 | ${PROJECT_SOURCE_DIR}/res/resources.qrc 30 | ) 31 | 32 | set(SOURCE_DEVICE_DIR "${PROJECT_SOURCE_DIR}/src/device") 33 | file(GLOB SOURCE_DEVICE_FILES "${SOURCE_DEVICE_DIR}/*.cpp") 34 | 35 | set(SOURCE_MONITOR_DIR "${PROJECT_SOURCE_DIR}/src/monitor") 36 | file(GLOB SOURCE_MONITOR_FILES "${SOURCE_MONITOR_DIR}/*.cpp") 37 | 38 | set(SOURCE_SDB_DIR "${PROJECT_SOURCE_DIR}/src/monitor/sdb") 39 | file(GLOB SOURCE_SDB_FILES "${SOURCE_SDB_DIR}/*.cpp") 40 | 41 | set(SOURCE_TOOLS_DIR "${PROJECT_SOURCE_DIR}/src/monitor/tools") 42 | file(GLOB SOURCE_TOOLS_FILES "${SOURCE_TOOLS_DIR}/*.cpp") 43 | 44 | set(SOURCE_UI_DIR "${PROJECT_SOURCE_DIR}/src/ui") 45 | file(GLOB SOURCE_UI_FILES "${SOURCE_UI_DIR}/*.cpp") 46 | 47 | set(SOURCE_UTILS_DIR "${PROJECT_SOURCE_DIR}/src/utils") 48 | file(GLOB SOURCE_UTILS_FILES "${SOURCE_UTILS_DIR}/*.cpp") 49 | 50 | # set(SOURCE_QTNODES_DIR "${PROJECT_SOURCE_DIR}/thirdpkg/QtNodes/src") 51 | # file(GLOB SOURCE_QTNODES_FILES "${SOURCE_QTNODES_DIR}/*.cpp") 52 | set(SOURCE_FILES ${PROJECT_SOURCE_DIR}/src/main.cpp 53 | ${SOURCE_UTILS_FILES} 54 | ${SOURCE_UI_FILES} 55 | ${SOURCE_SDB_FILES} 56 | ${SOURCE_TOOLS_FILES} 57 | ${SOURCE_MONITOR_FILES} 58 | ${SOURCE_DEVICE_FILES}) 59 | 60 | set(INCLUDE_UI_DIR "${PROJECT_SOURCE_DIR}/include/ui") 61 | file(GLOB INCLUDE_UI_FILES "${INCLUDE_UI_DIR}/*.h") 62 | 63 | set(INCLUDE_MONITOR_DIR "${PROJECT_SOURCE_DIR}/include/monitor") 64 | file(GLOB INCLUDE_MONITOR_FILES "${INCLUDE_MONITOR_DIR}/*.h") 65 | 66 | set(INCLUDE_SDB_DIR "${PROJECT_SOURCE_DIR}/include/monitor/sdb") 67 | file(GLOB INCLUDE_SDB_FILES "${INCLUDE_SDB_DIR}/*.h") 68 | 69 | set(INCLUDE_TOOLS_DIR "${PROJECT_SOURCE_DIR}/include/monitor/tools") 70 | file(GLOB INCLUDE_TOOLS_FILES "${INCLUDE_TOOLS_DIR}/*.h") 71 | 72 | set(INCLUDE_UTILS_DIR "${PROJECT_SOURCE_DIR}/include/utils") 73 | file(GLOB INCLUDE_UTILS_FILES "${INCLUDE_UTILS_DIR}/*.h") 74 | 75 | set(INCLUDE_DEVICE_DIR "${PROJECT_SOURCE_DIR}/include/device") 76 | file(GLOB INCLUDE_DEVICE_FILES "${INCLUDE_DEVICE_DIR}/*.h") 77 | 78 | # message(${INCLUDE_UTILS_FILES}) 79 | 80 | set(INCLUDE_FILES ${PROJECT_SOURCE_DIR}/include/main.h 81 | ${INCLUDE_UTILS_FILES} 82 | ${INCLUDE_UI_FILES} 83 | ${INCLUDE_MONITOR_FILES} 84 | ${INCLUDE_TOOLS_FILES} 85 | ${INCLUDE_SDB_FILES} 86 | ${INCLUDE_DEVICE_FILES}) 87 | 88 | add_subdirectory(vsrc) 89 | 90 | -------------------------------------------------------------------------------- /src/device/npc.cpp: -------------------------------------------------------------------------------- 1 | #include "main.h" 2 | #include "timer.h" 3 | #include "reg.h" 4 | #include "vmem.h" 5 | #include "disasm.h" 6 | 7 | static int trap_flag = 0; 8 | static int abort_flag = 0; 9 | static int inst_skip_flag = 0; 10 | 11 | uint32_t inst_from_npc; 12 | 13 | extern "C" void trap( int flag) 14 | { 15 | trap_flag = flag; 16 | } 17 | 18 | extern "C" void npc_state ( int flag, unsigned int inst_to_sdb) 19 | { 20 | abort_flag = flag; 21 | inst_from_npc = inst_to_sdb; 22 | } 23 | 24 | 25 | extern "C" int pmem_read(int raddr) { 26 | // 总是读取地址为`raddr & ~0x3u`的4字节返回 27 | 28 | // printf("raddr = %d\n", raddr); 29 | if(raddr == 0xa0000048) // 获取当前时间 30 | { 31 | inst_skip_flag = 1; // 差分测试跳过 32 | return (uint32_t)(NPCTimer::now_time); 33 | } 34 | if(raddr == 0xa000004c) 35 | { 36 | inst_skip_flag = 1; // 差分测试跳过 37 | NPCTimer::now_time = NPCTimer::get_time(); 38 | return (uint32_t)((NPCTimer::now_time) >> 32); 39 | } 40 | 41 | if(raddr == 0xa0000100) 42 | { 43 | return (uint32_t)((NPCVGA::screen_width << 16) | NPCVGA::screen_height); // 获取宽高 44 | } 45 | 46 | if(raddr<0x80000000 || raddr > 0x88000000) // 在一个时钟周期内多次访问内存 47 | { 48 | // 触发异常:未完成 49 | // printf("Address out of bounds:addr=0x%08x\n", raddr); 50 | return 0; 51 | } 52 | // printf("addr=0x%08x\tval=0x%08x\n", raddr, ((uint32_t *)vmem->mem_addr)[(raddr&(~0x3u) - 0x80000000u)/4]); 53 | return ((uint32_t *)vmem->mem_addr)[(raddr&(~0x3u) - 0x80000000u)/4]; 54 | } 55 | 56 | extern "C" void pmem_write(int waddr, int wdata, char wmask) { 57 | // 总是往地址为`waddr & ~0x3u`的4字节按写掩码`wmask`写入`wdata` 58 | // `wmask`中每比特表示`wdata`中1个字节的掩码, 59 | // 如`wmask = 0x3`代表只写入最低2个字节, 内存中的其它字节保持不变 60 | 61 | if(waddr == 0xa00003f8) 62 | { 63 | inst_skip_flag = 1; // 差分测试跳过 64 | putchar(wdata); 65 | fflush(stdout); //强制刷新缓冲区 66 | return; 67 | } 68 | 69 | if(waddr == 0xa0000104) // 控制同步信号 70 | { 71 | NPCVGA::sync_signal = wdata; 72 | return; 73 | } 74 | 75 | if((waddr >= 0xa1000000) && (waddr <= (0xa1000000+NPCVGA::screen_width*NPCVGA::screen_height*4))) 76 | { 77 | memcpy((NPCVGA::vmem+(waddr-0xa1000000)/4), &wdata, 4); 78 | return; 79 | } 80 | 81 | if(waddr<0x80000000 || waddr > 0x88000000) // 在一个时钟周期内多次访问内存 82 | { 83 | // 触发异常:未完成 84 | printf("Address out of bounds:addr=0x%08x\n", waddr); 85 | return; 86 | } 87 | 88 | switch (wmask){ 89 | case 0b00001111: 90 | memcpy(vmem->mem_addr+(waddr&(~0x3u)-0x80000000), &wdata, 4); 91 | break; 92 | case 0b00001100: 93 | // printf("sh1100:\taddr = 0x%08x\t val = 0x%08x\n", waddr, wdata); 94 | // printf("old = 0x%08x\n", ((uint32_t *)mem_addr)[(waddr&(~0x3u)-0x80000000)/4]); 95 | memcpy(vmem->mem_addr+(waddr&(~0x3u)-0x80000000)+2, &wdata, 2); 96 | // printf("new = 0x%08x\n", ((uint32_t *)mem_addr)[(waddr&(~0x3u)-0x80000000)/4]); 97 | break; 98 | case 0b00000011: 99 | memcpy(vmem->mem_addr+(waddr&(~0x3u)-0x80000000), &wdata, 2); 100 | break; 101 | case 0b00000001: 102 | memcpy(vmem->mem_addr+(waddr-0x80000000), &wdata, 1); 103 | break; 104 | case 0b00000010: 105 | memcpy(vmem->mem_addr+(waddr-0x80000000), &wdata, 1); 106 | break; 107 | case 0b00000100: 108 | memcpy(vmem->mem_addr+(waddr-0x80000000), &wdata, 1); 109 | break; 110 | case 0b00001000: 111 | memcpy(vmem->mem_addr+(waddr-0x80000000), &wdata, 1); 112 | break; 113 | default: 114 | break; 115 | } 116 | } 117 | 118 | NPC::NPC(int argc, char **argv, QObject *parent) 119 | : QThread(parent) 120 | , argc(argc) 121 | , argv(argv) 122 | { 123 | cpu = new VCPU; 124 | npc_vga = new NPCVGA(400, 300); //创建显示 125 | npc_vga->start(); //启动显示线程 126 | 127 | last_pc = 0x80000000; 128 | riscv32_reg->pc = last_pc; 129 | stop_flag = false; 130 | debug_flag = false; 131 | for (int i = 0; i < 32; ++i) { 132 | riscv32_reg->gpr[i] = static_cast(cpu->rootp->CPU__DOT__reg_file__DOT__rf[i]); 133 | } 134 | 135 | for (int i = 0; i < 9; ++i) { 136 | riscv32_reg->csr[i] = static_cast(cpu->rootp->CPU__DOT__csr_file__DOT__csrf[i]); 137 | } 138 | } 139 | 140 | NPC::~NPC(){ 141 | // Final model cleanup 142 | cpu->final(); 143 | npc_vga->stop(); // 请求线程退出 144 | npc_vga->wait(); // 等待线程退出 145 | delete npc_vga; 146 | delete cpu; 147 | } 148 | 149 | void NPC::single_cycle() { 150 | cpu->clk = 0; cpu->eval(); 151 | cpu->clk = 1; cpu->eval(); 152 | } 153 | 154 | void NPC::reset(int n) { 155 | cpu->rst = 1; 156 | while (n -- > 0) single_cycle(); 157 | cpu->rst = 0; 158 | } 159 | 160 | void NPC::exec(uint32_t n){ 161 | bool success; 162 | if(trap_flag == 0){ 163 | for(int i=0; iinst = ((uint32_t *)vmem->mem_addr)[(cpu->pc - 0x80000000)/4]; 166 | single_cycle(); 167 | if(debug_flag) 168 | { 169 | // 判断是否是批处理模式 170 | if(mode_sel != BATCH_MODE) 171 | { 172 | char *p = logbuf; 173 | p += snprintf(p, sizeof(logbuf), "0x%08x:", last_pc); 174 | int j; 175 | uint8_t *inst = (uint8_t *)&inst_from_npc; 176 | for (j = 0; j < 4; j++) { 177 | p += snprintf(p, 4, " %02x", inst[j]); 178 | } 179 | memset(p, ' ', 1); 180 | p += 1; 181 | disassemble(p, logbuf + sizeof(logbuf) - p, last_pc, (uint8_t *)&inst_from_npc, 4); 182 | // printf("%s\n",logbuf); 183 | std::cout << logbuf << std::endl; 184 | 185 | if(mode_sel == DISPLAY_IDE_ONLY || mode_sel == DISPLAY_BOTH ) 186 | emit sendNPCInfoToUI(last_pc); 187 | 188 | // copy cpu state 189 | riscv32_reg->pc = cpu->pc; 190 | for (int i = 0; i < 32; ++i) { 191 | riscv32_reg->gpr[i] = static_cast(cpu->rootp->CPU__DOT__reg_file__DOT__rf[i]); 192 | } 193 | for (int i = 0; i < 9; ++i) { 194 | riscv32_reg->csr[i] = static_cast(cpu->rootp->CPU__DOT__csr_file__DOT__csrf[i]); 195 | // printf("0x%08x\t", cpu.csr[i]); 196 | } 197 | 198 | if(mode_sel == DISPLAY_IDE_ONLY || mode_sel == DISPLAY_BOTH ) 199 | emit sendRegInfo( riscv32_reg->gpr); 200 | 201 | // difftest 202 | diff_result = monitor->difftest->step(cpu->pc, inst_skip_flag); 203 | if(diff_result==false) 204 | { 205 | printf("diff error\n"); 206 | // emit sendDiffError(); 207 | return; 208 | } 209 | } 210 | 211 | // inst_skip_flag = 0; 212 | if(mode_sel == DISPLAY_IDE_ONLY || mode_sel == DISPLAY_BOTH) 213 | { 214 | // last_pc = cpu->pc; 215 | if(checkMemBreakpointTrigger()) 216 | return; 217 | if(checkRegBreakpointTrigger()) 218 | return; 219 | } 220 | 221 | last_pc = cpu->pc; 222 | 223 | if(mode_sel != BATCH_MODE) 224 | { 225 | // 判断是否触发监视点 226 | WatchPoint* temp = monitor->sdb->watchpoint->head; 227 | while (temp != nullptr) 228 | { 229 | if(monitor->sdb->expr->evaluate(temp->expr, success)) 230 | { 231 | std::cout << "\033[;41mMonitoring point trigger !!!\033[0m\n"; 232 | std::cout << "\t\033[;32mNO:" << temp->NO << "\tEXPR:" << temp->expr << "\033[0m\n"; 233 | return; 234 | } 235 | temp = temp->next; 236 | } 237 | } 238 | } 239 | if(trap_flag||abort_flag){ 240 | if(trap_flag == 1) 241 | printf("\033[1;32mHIT GOOD TRAP\033[0m\n"); 242 | else if(abort_flag == 1) 243 | printf("\033[1;31mHIT BAD TRAP\033[0m\n"); 244 | break; 245 | } 246 | } 247 | } 248 | else{ 249 | printf("Program execution has ended. To restart the program, exit NPC and run again.\n"); 250 | } 251 | } 252 | 253 | void NPC::init_npc() 254 | { 255 | init_disasm("riscv32-pc-linux-gnu"); 256 | reset(5); 257 | } 258 | 259 | void NPC::run() 260 | { 261 | exec(-1); 262 | // if(mode_sel == DISPLAY_IDE_ONLY || mode_sel == DISPLAY_BOTH || mode_sel == BATCH_MODE) 263 | // emit destroyWindow(); 264 | } 265 | 266 | //判断是否触发内存的断点 267 | bool NPC::checkMemBreakpointTrigger() 268 | { 269 | // std::cout << ui->mSplitterLayout->mem_breakpoint.size() << std::endl; 270 | for(int i = 0; i < ui->mSplitterLayout->instMemWidget->mem_breakpoint.size(); ++i){ 271 | QPair pair = ui->mSplitterLayout->instMemWidget->mem_breakpoint.at(i); 272 | if(last_pc == (0x80000000 + pair.first*4)){ 273 | last_pc = cpu->pc; 274 | emit sendDiffError(); 275 | return true; 276 | } 277 | } 278 | return false; 279 | } 280 | 281 | //判断是否触发寄存器的断点 282 | bool NPC::checkRegBreakpointTrigger() 283 | { 284 | for(int i = 0; i < ui->mSplitterLayout->gprWidget->gpr_breakpoint.size(); ++i){ 285 | QPair pair = ui->mSplitterLayout->gprWidget->gpr_breakpoint.at(i); 286 | QTableWidgetItem *item_reg = ui->mSplitterLayout->gprWidget->gprTableWidget->item(pair.first, pair.second+1); 287 | if (item_reg) { 288 | QString text = item_reg->text(); 289 | bool ok; 290 | uint32_t value = text.toUInt(&ok, 16); 291 | if(value != static_cast(cpu->rootp->CPU__DOT__reg_file__DOT__rf[pair.first*8+pair.second/2])){ 292 | last_pc = cpu->pc; 293 | return true; 294 | } 295 | } 296 | } 297 | return false; 298 | } -------------------------------------------------------------------------------- /src/device/reg.cpp: -------------------------------------------------------------------------------- 1 | #include "reg.h" 2 | 3 | RISCV32Register *riscv32_reg = new RISCV32Register; 4 | 5 | RISCV32Register::RISCV32Register() 6 | { 7 | 8 | } 9 | 10 | RISCV32Register::~RISCV32Register() 11 | { 12 | std::cout << "delete reg\n"; 13 | } 14 | 15 | // 根据寄存器名获取寄存器值 16 | uint32_t RISCV32Register::getGPRValue(std::string regName) { 17 | if(regName == "pc") 18 | return pc; 19 | 20 | for (int i = 0; i < 32; ++i) { 21 | if (regName == gpr_name[i]) { 22 | return gpr[i]; 23 | } 24 | } 25 | std::cerr << "Error: Register name not found!" << std::endl; 26 | return 0; 27 | } 28 | 29 | // 修改寄存器值 30 | void RISCV32Register::setGPRValue(std::string regName, uint32_t value) { 31 | for (int i = 0; i < 32; ++i) { 32 | if (regName==gpr_name[i]) { 33 | gpr[i] = value; 34 | return; 35 | } 36 | } 37 | std::cerr << "Error: Register name not found!" << std::endl; 38 | } 39 | 40 | // 初始化所有寄存器 41 | void RISCV32Register::initReg(uint32_t value) { 42 | for (int i = 0; i < 32; ++i) { 43 | gpr[i] = value; 44 | } 45 | } 46 | 47 | // 打印所有寄存器的值 48 | void RISCV32Register::printReg() { 49 | for (int i = 0; i < 32; ++i) { 50 | std::cout << gpr_name[i] << ": " << gpr[i] << std::endl; 51 | } 52 | } 53 | 54 | // 修改指定位置的寄存器(按顺序修改) 55 | void RISCV32Register::modifyReg(uint32_t index, uint32_t value) { 56 | if (index < 32) { 57 | gpr[index] = value; 58 | } else { 59 | std::cerr << "Error: Invalid register index!" << std::endl; 60 | } 61 | } -------------------------------------------------------------------------------- /src/device/timer.cpp: -------------------------------------------------------------------------------- 1 | #include "timer.h" 2 | 3 | extern "C" 4 | { 5 | #include // 引入时间相关的头文件 6 | } 7 | 8 | uint64_t NPCTimer::boot_time = 0; 9 | uint64_t NPCTimer::now_time = 0; 10 | 11 | NPCTimer::NPCTimer() 12 | { 13 | 14 | } 15 | NPCTimer::~NPCTimer() 16 | { 17 | 18 | } 19 | 20 | uint64_t NPCTimer::get_time_internal() { 21 | struct timeval now; 22 | gettimeofday(&now, nullptr); 23 | uint64_t us = now.tv_sec * 1000000 + now.tv_usec; 24 | return us; 25 | } 26 | 27 | uint64_t NPCTimer::get_time() { 28 | if (boot_time == 0) boot_time = get_time_internal(); 29 | uint64_t now = get_time_internal(); 30 | return now - boot_time; 31 | } 32 | -------------------------------------------------------------------------------- /src/device/vga.cpp: -------------------------------------------------------------------------------- 1 | #include "vga.h" 2 | #include 3 | 4 | uint32_t NPCVGA::sync_signal = 0; 5 | uint32_t NPCVGA::screen_width = 400; 6 | uint32_t NPCVGA::screen_height = 300; 7 | uint32_t* NPCVGA::vmem = nullptr; 8 | 9 | NPCVGA::NPCVGA(uint32_t w, uint32_t h, QObject* parent) 10 | :QThread(parent) 11 | { 12 | screen_width = w; 13 | screen_height = h; 14 | vmem = new uint32_t[screen_width*screen_height]; 15 | stop_flag = false; 16 | // memset(NPCVGA::vmem, 220, sizeof(int)*screen_width*screen_height); 17 | } 18 | 19 | NPCVGA::~NPCVGA() 20 | { 21 | std::cout << "VGA" << std::endl; 22 | delete []vmem; 23 | } 24 | 25 | 26 | void NPCVGA::convertToRGB(const uint32_t* src, uint8_t* dest, uint32_t pixelCount) 27 | { 28 | for (uint32_t i = 0; i < pixelCount; ++i) { 29 | // 从源数组中获取每个像素的 4 字节 ARGB (0xAARRGGBB) 30 | uint32_t pixel = src[i]; 31 | 32 | // 将其转换为 3 字节 RGB (0xRRGGBB) 33 | uint8_t red = (pixel >> 16) & 0xFF; // 提取红色通道 34 | uint8_t green = (pixel >> 8) & 0xFF; // 提取绿色通道 35 | uint8_t blue = pixel & 0xFF; // 提取蓝色通道 36 | 37 | // 3 字节存储在目标内存中 38 | dest[i * 3] = red; 39 | dest[i * 3 + 1] = green; 40 | dest[i * 3 + 2] = blue; 41 | } 42 | } 43 | 44 | void NPCVGA::stop() { 45 | stop_flag = true; // 设置停止标志 46 | } 47 | 48 | void NPCVGA::run() 49 | { 50 | while(1) 51 | { 52 | if(stop_flag) 53 | break; 54 | if(sync_signal != 0) 55 | { 56 | // 为目标数据分配内存 (每个像素 3 字节) 57 | uint8_t* dest = new uint8_t[screen_width*screen_height*3]; 58 | // 调用函数转换 ARGB -> RGB 59 | convertToRGB(vmem, dest, screen_width*screen_height); 60 | QImage image(dest, screen_width, screen_height, QImage::Format_RGB888); 61 | //发送图片到前端 62 | sync_signal = 0; 63 | emit sendVGAInfoToUI(image); 64 | // 释放目标内存 65 | delete[] dest; 66 | } 67 | } 68 | 69 | } 70 | 71 | -------------------------------------------------------------------------------- /src/device/vmem.cpp: -------------------------------------------------------------------------------- 1 | #include "vmem.h" 2 | #include 3 | #include 4 | 5 | #define CONFIG_MBASE 0x80000000 6 | #define CONFIG_MSIZE 0x8000000 7 | #define PMEM_LEFT ((uint32_t)CONFIG_MBASE) 8 | #define PMEM_RIGHT ((uint32_t)CONFIG_MBASE + CONFIG_MSIZE - 1) 9 | 10 | Vmem *vmem = new Vmem; 11 | 12 | Vmem::Vmem() 13 | { 14 | } 15 | 16 | Vmem::~Vmem() 17 | { 18 | std::cout << "delete memory" << std::endl; 19 | free(mem_addr); 20 | } 21 | 22 | void Vmem::init_mem() { 23 | mem_addr = (uint8_t *)malloc(CONFIG_MSIZE); 24 | assert(mem_addr); 25 | memset(mem_addr, 0, CONFIG_MSIZE); 26 | // mem_addr =pmem; 27 | printf("physical memory area [ 0x%08x , 0x%08x ]\n", PMEM_LEFT, PMEM_RIGHT); 28 | } 29 | 30 | void Vmem::free_mem() 31 | { 32 | free(mem_addr); 33 | } 34 | -------------------------------------------------------------------------------- /src/main.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include "main.h" 5 | #include "vmem.h" 6 | #include "reg.h" 7 | 8 | MainWindow *ui = nullptr; 9 | NPC *mNPC = nullptr; 10 | Monitor *monitor = nullptr; 11 | 12 | int mode_sel; 13 | std::string log_file; 14 | std::string elf_file; 15 | std::string diff_so_file; 16 | std::string img_file; 17 | 18 | void parseArgs(int argc, char* argv[]) { 19 | const struct option table[] = { 20 | {"mode", required_argument, nullptr, 'm'}, 21 | {"log", required_argument, nullptr, 'l'}, 22 | {"diff", required_argument, nullptr, 'd'}, 23 | {"ftrace", required_argument, nullptr, 'f'}, 24 | {"image", required_argument, nullptr, 'i'}, 25 | {"help", no_argument, nullptr, 'h'}, 26 | {nullptr, 0, nullptr, 0}, 27 | }; 28 | int opt; 29 | while ((opt = getopt_long(argc, argv, "-hl:d:f:m:i:", table, nullptr)) != -1) { 30 | switch (opt) { 31 | case 'l': log_file = optarg; break; 32 | case 'd': diff_so_file = optarg; break; 33 | case 'f': elf_file = optarg; break; 34 | case 'i': img_file = optarg; break; 35 | case 'm': mode_sel = std::stoi(optarg); break; 36 | default: 37 | std::printf("Usage: %s [OPTION...] IMAGE [args]\n\n", argv[0]); 38 | std::printf("\t-l,--log=FILE output log to FILE\n"); 39 | std::printf("\t-d,--diff=REF_SO run DiffTest with reference REF_SO\n"); 40 | std::printf("\t-f,--ftrace=FILE output function trace log to FILE\n"); 41 | std::printf("\t-i,--image=image_file location of iamge file\n"); 42 | std::printf("\t-m,--mode=NUM 1:display IDE, but don't SDB;\n\ 43 | 2: don't display IDE, but display SDB; \n\ 44 | 3: display IDE and SDB \n\ 45 | 4: batch mode \n"); 46 | std::printf("\n"); 47 | std::exit(0); 48 | } 49 | } 50 | } 51 | 52 | int main(int argc, char *argv[]) 53 | { 54 | parseArgs(argc, argv); 55 | 56 | mNPC = new NPC(argc, argv); 57 | mNPC->init_npc(); 58 | 59 | // std::cout << "is_batch_mode=" << is_batch_mode << std::endl; 60 | std::cout << "mode_sel=" << mode_sel << std::endl; 61 | // std::cout << "log_file=" << log_file << std::endl; 62 | // std::cout << "elf_file=" << elf_file << std::endl; 63 | // std::cout << "diff_so_file" << diff_so_file << std::endl; 64 | // std::cout << "img_file=" << img_file << std::endl; 65 | 66 | monitor = new Monitor(log_file, elf_file, diff_so_file, img_file); 67 | monitor->init_monitor(argc, argv); 68 | 69 | if(mode_sel == DISPLAY_SDB_ONLY || mode_sel == DISPLAY_BOTH){ 70 | monitor->start(); 71 | mNPC->debug_flag = true; 72 | if(mode_sel == DISPLAY_SDB_ONLY) 73 | while(!monitor->stop_flag); 74 | } 75 | 76 | if(mode_sel == BATCH_MODE) // batch mode 77 | { 78 | mNPC->exec(-1); 79 | } 80 | 81 | if(mode_sel == DISPLAY_IDE_ONLY || mode_sel == DISPLAY_BOTH){ 82 | QApplication a(argc, argv); 83 | ui = new MainWindow(argc, argv); 84 | ui->init((unsigned int *)vmem->mem_addr, monitor->inst_num); 85 | 86 | QObject::connect(mNPC->npc_vga, SIGNAL(sendVGAInfoToUI(const QImage &)), ui, SLOT(receiveImageFromNPC(const QImage &))); 87 | QObject::connect(mNPC, &NPC::sendRegInfo, ui->mSplitterLayout->gprWidget, &GPRMonitor::receiveGPRValue); 88 | QObject::connect(mNPC, &NPC::sendNPCInfoToUI, ui->mSplitterLayout->instMemWidget, &InstMonitor::receiveNPCInfo); 89 | QObject::connect(mNPC, &NPC::destroyWindow, ui, &MainWindow::onDestroyWindow); 90 | QObject::connect(monitor, &Monitor::destroyWindow, ui, &MainWindow::onDestroyWindow); 91 | QObject::connect(mNPC, &NPC::sendDiffError, ui->mSplitterLayout->instMemWidget, &InstMonitor::receiveDiffError); 92 | ui->show(); 93 | a.exec(); 94 | } 95 | 96 | delete vmem; 97 | delete riscv32_reg; 98 | delete mNPC; 99 | delete monitor; 100 | exit(0); 101 | 102 | return 0; 103 | } 104 | 105 | -------------------------------------------------------------------------------- /src/monitor/monitor.cpp: -------------------------------------------------------------------------------- 1 | #include "main.h" 2 | #include "vmem.h" 3 | #include "reg.h" 4 | 5 | Monitor::Monitor(std::string log_file, std::string elf_file, std::string diff_so_file, std::string img_file): 6 | log_file(log_file), 7 | elf_file(elf_file), 8 | diff_so_file(diff_so_file), 9 | img_file(img_file) 10 | { 11 | difftest = new DiffTest; 12 | ftrace = new Ftrace; 13 | sdb = new SDB; 14 | stop_flag = false; 15 | } 16 | 17 | Monitor::~Monitor() 18 | { 19 | delete ftrace; 20 | delete difftest; 21 | delete sdb; 22 | } 23 | 24 | void Monitor::welcome() const { 25 | std::printf("Welcome to \33[1;33mriscv32e\33[0m-NPC!\n"); 26 | std::printf("For help, type \"help\"\n"); 27 | } 28 | 29 | void Monitor::initLog() { 30 | log_fp = stdout; 31 | if (!log_file.empty()) { 32 | log_fp = std::fopen(log_file.c_str(), "w"); 33 | assert(log_fp && "Cannot open log file"); 34 | } 35 | std::printf("Log is written to %s\n", log_file.empty() ? "stdout" : log_file.c_str()); 36 | } 37 | 38 | long Monitor::loadImage() { 39 | if (img_file.empty()) { 40 | std::printf("No image is given. Use the default built-in image.\n"); 41 | return 4096; // Default image size 42 | } 43 | 44 | FILE* fp = std::fopen(img_file.c_str(), "rb"); 45 | if (!fp) { 46 | std::printf("Cannot open '%s'\n", img_file.c_str()); 47 | return -1; 48 | } 49 | 50 | std::fseek(fp, 0, SEEK_END); 51 | long size = std::ftell(fp); 52 | std::printf("The image is %s, size = %ld\n", img_file.c_str(), size); 53 | image_size = size; 54 | std::fseek(fp, 0, SEEK_SET); 55 | 56 | assert(vmem->mem_addr); 57 | int ret = std::fread(vmem->mem_addr, size, 1, fp); 58 | assert(ret == 1); 59 | 60 | std::fclose(fp); 61 | return size; 62 | } 63 | 64 | void Monitor::init_monitor(int argc, char* argv[]) { 65 | // Parse arguments 66 | // parseArgs(argc, argv); 67 | 68 | // Open the log file 69 | initLog(); 70 | 71 | // Initialize elf file and fetch instruction numbers 72 | ftrace->initFtrace(elf_file); 73 | inst_num = ftrace->instTotal(elf_file); 74 | ftrace->getSourceCode(elf_file); 75 | 76 | // std::cout << "inst_num=" << inst_num << std::endl; 77 | // for(int i=0; ifunc_sym_num; i++) 78 | // { 79 | // std::cout << ftrace->func_sym_tab[i].func_name << std::endl; 80 | // } 81 | 82 | // Initialize memory 83 | vmem->init_mem(); 84 | 85 | // Load image into memory 86 | loadImage(); 87 | 88 | // Initialize differential testing 89 | difftest->initDifftest(diff_so_file.c_str(), image_size, vmem->mem_addr); 90 | 91 | // Initialize simple debugger 92 | sdb->init_sdb(); 93 | 94 | // Display welcome message 95 | welcome(); 96 | } 97 | 98 | void Monitor::stop() 99 | { 100 | sdb->stop_flag = true; 101 | } 102 | 103 | void Monitor::run() 104 | { 105 | 106 | int ret = sdb->sdb_mainloop(); 107 | if(ret == -1) 108 | { 109 | if(mode_sel == DISPLAY_SDB_ONLY) 110 | { 111 | stop_flag = true; 112 | } 113 | 114 | if(mode_sel == DISPLAY_IDE_ONLY || mode_sel == DISPLAY_BOTH || mode_sel == BATCH_MODE) 115 | emit destroyWindow(); 116 | } 117 | } 118 | 119 | 120 | -------------------------------------------------------------------------------- /src/monitor/sdb/expr.cpp: -------------------------------------------------------------------------------- 1 | #include "sdb/expr.h" 2 | #include "reg.h" 3 | 4 | EXPR::EXPR() 5 | { 6 | 7 | } 8 | EXPR::~EXPR() 9 | { 10 | std::cout << "delete expr" << std::endl; 11 | } 12 | 13 | uint32_t EXPR::evaluate(const std::string &expression, bool &success) 14 | { 15 | parenthesesNum = 0; 16 | tokens.clear(); 17 | 18 | if (!tokenize(expression)) { 19 | success = false; 20 | return 0; 21 | } 22 | 23 | recursionCheck(0, tokens.size() - 1); 24 | 25 | return eval(0, tokens.size() - 1); 26 | return 0; 27 | } 28 | 29 | void EXPR::initExpr() 30 | { 31 | initRules(); 32 | initRegex(); 33 | } 34 | 35 | void EXPR::initRules() 36 | { 37 | rules = { 38 | {"0x[0-9a-f]+", TK_HEX}, // Hex 39 | {"[0-9][0-9]*", TK_INTEGER}, // Integer 40 | {"\\$[A-Za-z0-9]{1,3}", TK_REG}, // Register 41 | {" +", TK_NOTYPE}, // Spaces 42 | {"\\+", TK_ADD}, // Plus 43 | {"-{1}", TK_SUB}, // Subtraction 44 | {"\\*", TK_MULT}, // Multiplication 45 | {"/", TK_DIV}, // Division 46 | {"\\(", TK_L_BRACKET}, // Left Bracket 47 | {"\\)", TK_R_BRACKET}, // Right Bracket 48 | {"==", TK_EQ}, // Equal 49 | {"!=", TK_NEQ}, // Not Equal 50 | {"&&", TK_AND}, // And 51 | {"\\|\\|", TK_OR} // Or 52 | }; 53 | } 54 | 55 | // 初始化正则表达式, 用于匹配输入表达式中的不同类型的符号和数值。 56 | void EXPR::initRegex() 57 | { 58 | for (const auto &rule : rules) { 59 | regexPatterns.emplace_back(std::regex(rule.regex, std::regex_constants::extended)); 60 | } 61 | } 62 | 63 | // 词法分析:匹配表达式中的数字和符号 64 | bool EXPR::tokenize(const std::string &expression) 65 | { 66 | size_t position = 0; 67 | while (position < expression.length()) { 68 | bool matched = false; 69 | for (size_t i = 0; i < regexPatterns.size(); i++) { 70 | std::smatch match; 71 | if (std::regex_search(expression.begin() + position, expression.end(), match, regexPatterns[i]) && match.position(0) == 0) { 72 | std::string tokenStr = match.str(0); 73 | position += tokenStr.length(); 74 | if (rules[i].tokenType != TK_NOTYPE) { 75 | Token token = {rules[i].tokenType, tokenStr}; 76 | if(handleToken(token)) 77 | tokens.push_back(token); 78 | } 79 | matched = true; 80 | break; 81 | } 82 | } 83 | if (!matched) { 84 | std::cerr << "No match at position " << position << ": " << expression.substr(position) << std::endl; 85 | return false; 86 | } 87 | } 88 | return true; 89 | } 90 | 91 | // 处理得到token 92 | bool EXPR::handleToken(Token &token) { 93 | std::string token_val = token.str; 94 | token.str.clear(); 95 | switch (token.type) { 96 | case TK_INTEGER:{ 97 | token.type = TK_INTEGER; 98 | if(sub_flag){ 99 | token.str = "-" + token_val; 100 | sub_flag = false; 101 | } 102 | else{ 103 | token.str = token_val; 104 | } 105 | break; 106 | } 107 | case TK_HEX:{ 108 | token.type = TK_HEX; 109 | token.str = token_val; 110 | break; 111 | } 112 | case TK_REG:{ 113 | token.type = TK_REG; 114 | token.str = token_val; 115 | break; 116 | } 117 | // case TK_DEREF:{ 118 | // token.type = TK_DEREF; 119 | // token.str = token.str; 120 | // break; 121 | // } 122 | case TK_ADD:{ 123 | token.type = TK_ADD; 124 | break; 125 | } 126 | case TK_SUB:{ 127 | token.type = TK_SUB; 128 | if (!tokens.empty() && (tokens.back().type == TK_INTEGER || tokens.back().type == TK_R_BRACKET)) { 129 | token.type = TK_SUB; 130 | } else { 131 | sub_flag = true; 132 | return false; 133 | } 134 | break; 135 | } 136 | case TK_MULT:{ 137 | if (!tokens.empty() && (tokens.back().type == TK_INTEGER || tokens.back().type == TK_R_BRACKET)) { 138 | token.type = TK_MULT; 139 | } else { 140 | token.type = TK_DEREF; 141 | } 142 | break; 143 | } 144 | case TK_DIV:{ 145 | token.type = TK_DIV; 146 | break; 147 | } 148 | case TK_L_BRACKET:{ 149 | token.type = TK_L_BRACKET; 150 | break; 151 | } 152 | case TK_R_BRACKET:{ 153 | token.type = TK_R_BRACKET; 154 | break; 155 | } 156 | case TK_EQ:{ 157 | token.type = TK_EQ; 158 | break; 159 | } 160 | case TK_NEQ:{ 161 | token.type = TK_NEQ; 162 | break; 163 | } 164 | case TK_AND:{ 165 | token.type = TK_AND; 166 | break; 167 | } 168 | case TK_OR:{ 169 | token.type = TK_OR; 170 | break; 171 | } 172 | case TK_NOTYPE:{ 173 | token.type = TK_NOTYPE; 174 | break; 175 | } 176 | default: printf("regex no type!!!\n"); 177 | } 178 | return true; 179 | } 180 | 181 | // 递归寻找表达式里面的括号 182 | void EXPR::recursionCheck(int p, int q) 183 | { 184 | for (int i = p; i <= q; i++) { 185 | if (tokens[i].type == TK_L_BRACKET) { 186 | recursionCheck(i + 1, q); 187 | for (int j = i; j <= q; j++) { 188 | if (tokens[j].type == TK_R_BRACKET && tokens[j].str.empty()) { 189 | parenthesesNum++; 190 | tokens[i].str = std::to_string(parenthesesNum); 191 | tokens[j].str = std::to_string(parenthesesNum); 192 | return; 193 | } 194 | } 195 | } 196 | } 197 | } 198 | 199 | // 检查在tokens中p和q索引处的左右括号是否一对 200 | bool EXPR::checkParentheses(int p, int q) { 201 | // test 202 | // for(int i=0; iTK_NOTYPE && tokens[i].type q) 271 | { 272 | /* Bad expression */ 273 | // throw std::invalid_argument("Bad expression"); 274 | std::cout << "\033[;41mBad expression\033[0m\n"; 275 | return 0; 276 | } 277 | else if (p == q) 278 | { 279 | /* Single token. 280 | * For now this token should be a number. 281 | * Return the value of the number. 282 | */ 283 | if(tokens[p].type == TK_INTEGER) 284 | return std::stoi(tokens[p].str);//std::atoi(tokens[p].str); 285 | else if (tokens[p].type == TK_HEX) 286 | return std::stoul(tokens[p].str, nullptr, 16);//(uint32_t)strtol(tokens[p].str, NULL, 16); 287 | else if (tokens[p].type == TK_REG) 288 | { 289 | return riscv32_reg->getGPRValue(tokens[p].str.substr(1)); 290 | } 291 | else 292 | std::cout << "Expression error" << std::endl; 293 | } 294 | else if (checkParentheses(p, q) == true) 295 | { 296 | /* The expression is surrounded by a matched pair of parentheses. 297 | * If that is the case, just throw away the parentheses. 298 | */ 299 | return eval(p + 1, q - 1); 300 | } 301 | else 302 | { 303 | int op; 304 | op = findMainOperator(p, q); 305 | if(tokens[op].type!=TK_DEREF) 306 | val1 = eval(p, op - 1); 307 | val2 = eval(op + 1, q); 308 | 309 | switch (tokens[op].type) { 310 | case TK_ADD: return val1 + val2; 311 | case TK_SUB: return val1 - val2; 312 | case TK_MULT: return val1 * val2; 313 | case TK_DIV: return val1 / val2; 314 | case TK_EQ: return val1 == val2; 315 | case TK_NEQ: return val1 != val2; 316 | case TK_AND: return val1 && val2; 317 | case TK_OR: return val1 || val2; 318 | case TK_DEREF: std::cout << "read memory failed" << std::endl;//printf("read memory failed\n"); 319 | default: throw std::invalid_argument("Unknown operator");//assert(0); 320 | } 321 | } 322 | return 0; 323 | } 324 | 325 | -------------------------------------------------------------------------------- /src/monitor/sdb/sdb.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | #include "sdb/sdb.h" 7 | #include "vmem.h" 8 | #include "reg.h" 9 | #include "main.h" 10 | 11 | SDB::SDB():cmd_table{ 12 | {"help", "Display information about all supported commands"}, 13 | {"c", "Continue the execution of the program"}, 14 | {"q", "Exit NEMU"}, 15 | {"si", "Step into N instructions"}, 16 | {"info", "Display info about registers or watchpoints"}, 17 | {"x", "Inspect memory at address"}, 18 | {"p", "Evaluate an expression"}, 19 | {"w", "Set a watchpoint"}, 20 | {"d", "Delete a watchpoint"} 21 | } 22 | { 23 | expr = new EXPR; 24 | line_read = nullptr; 25 | watchpoint = new WatchPointManager; 26 | stop_flag = false; 27 | } 28 | 29 | SDB::~SDB() 30 | { 31 | delete expr; 32 | delete watchpoint; 33 | } 34 | 35 | /* We use the `readline' library to provide more flexibility to read from stdin. */ 36 | char* SDB::rl_gets() { 37 | if (line_read) { 38 | free(line_read); 39 | line_read = nullptr; 40 | } 41 | line_read = readline("(npc-sdb)"); 42 | if (line_read && *line_read) add_history(line_read); 43 | return line_read; 44 | } 45 | 46 | int SDB::cmd_c(char *args) { 47 | mNPC->exec(-1); 48 | return 0; 49 | } 50 | 51 | int SDB::cmd_si(char *args) { 52 | /* extract the first argument */ 53 | char *arg = strtok(args, " "); 54 | int step_num; 55 | if (arg == NULL) 56 | { 57 | step_num = 1; 58 | printf("USAGE: si N\n"); 59 | } 60 | else 61 | { 62 | step_num = atoi(args); 63 | mNPC->exec(step_num); 64 | } 65 | return 0; 66 | } 67 | 68 | int SDB::cmd_info(char *args) { 69 | /* extract the first argument */ 70 | char *arg = strtok(args, " "); 71 | if (arg == NULL) 72 | { 73 | printf("info SUBCMD\n"); 74 | return 0; 75 | } 76 | else if(*arg == 'r') 77 | { 78 | extern VCPU* top; 79 | for(int i=0; i<4; i++) 80 | { 81 | for(int j=0; j<8; j++) 82 | { 83 | printf("%s=0x%08x\t", riscv32_reg->gpr_name[i], riscv32_reg->gpr[8*i+j]); 84 | } 85 | printf("\n"); 86 | } 87 | } 88 | else if(*arg == 'w') 89 | { 90 | watchpoint->printWatchPoints(); 91 | } 92 | return 0; 93 | } 94 | 95 | int SDB::cmd_x(char *args) { 96 | uint32_t pmem_val; 97 | uint32_t base_addr; 98 | uint32_t pmem_addr; 99 | bool success; 100 | char *arg = args ? strtok(args, " "): nullptr; 101 | char* expr_ptr = arg ? strtok(nullptr, " ") : nullptr; 102 | 103 | if(arg==nullptr || expr_ptr==nullptr) 104 | { 105 | printf("Usage:x N EXPR\n"); 106 | return 0; 107 | } 108 | else 109 | { 110 | int num = atoi(arg); 111 | base_addr = expr->evaluate(expr_ptr, success); 112 | if(base_addr < 0x80000000) 113 | { 114 | std::cout << "physical memory area [ 0x80000000 , 0x87ffffff ] \n"; 115 | return 0; 116 | } 117 | uint32_t i; 118 | uint32_t j; 119 | for(i=0; imem_addr[pmem_addr-0x80000000+j]; 127 | printf("%02x\t", pmem_val); 128 | } 129 | printf("\n"); 130 | } 131 | } 132 | return 0; 133 | } 134 | 135 | int SDB::cmd_p(char *args) { 136 | uint32_t val; 137 | if(args == NULL) 138 | { 139 | printf("Usage:p EXPR\n"); 140 | } 141 | else 142 | { 143 | bool success; 144 | val = expr->evaluate(args, success); 145 | printf("\033[41;32mval=0x%08x\033[0m\n", val); 146 | } 147 | return 0; 148 | } 149 | 150 | int SDB::cmd_w(char *args) { 151 | if(args == NULL) 152 | { 153 | printf("Usage:w EXPR\n"); 154 | } 155 | else 156 | { 157 | WatchPoint *wp; 158 | wp = watchpoint->newWatchPoint(); 159 | wp->expr = args; 160 | std::cout << "\033[41mID:" << wp->NO << "\tEXPR:" << args << "\033[0m\n"; 161 | } 162 | return 0; 163 | } 164 | 165 | int SDB::cmd_d(char *args) { 166 | if(args == nullptr) 167 | { 168 | printf("Usage:d N\n"); 169 | } 170 | else 171 | { 172 | char *arg = strtok(args, " "); 173 | int w_num = atoi(arg); 174 | watchpoint->freeWatchPointByNo(w_num); 175 | } 176 | return 0; 177 | } 178 | 179 | 180 | void SDB::cmd_q(char *args) { 181 | return; 182 | } 183 | 184 | int SDB::cmd_help(char *args) { 185 | if (!args) { 186 | for (const auto& cmd : cmd_table) { 187 | std::cout << cmd.first << " - " << cmd.second << "\n"; 188 | } 189 | } else { 190 | for (const auto& cmd : cmd_table) { 191 | if (cmd.first == args) { 192 | std::cout << cmd.first << " - " << cmd.second << "\n"; 193 | return 0; 194 | } 195 | } 196 | std::cout << "Unknown command: " << args << "\n"; 197 | } 198 | return 0; 199 | } 200 | 201 | int SDB::sdb_mainloop() { 202 | if(mode_sel == DISPLAY_IDE_ONLY || mode_sel == DISPLAY_BOTH) 203 | { 204 | fd_set readfds; 205 | struct timeval timeout; 206 | char* input; 207 | bool show_start = true; 208 | 209 | // 设置超时时间 210 | timeout.tv_sec = 0; 211 | timeout.tv_usec = 500000; // 500毫秒 212 | 213 | // 清空文件描述符集合,并设置stdin(标准输入)为监听目标 214 | FD_ZERO(&readfds); 215 | FD_SET(STDIN_FILENO, &readfds); 216 | 217 | while (true) { 218 | // 使用 select 来检测标准输入是否有数据 219 | int ret = select(STDIN_FILENO + 1, &readfds, NULL, NULL, &timeout); 220 | 221 | if (ret == -1) { 222 | perror("select failed"); 223 | break; 224 | } 225 | else if (ret > 0) { 226 | 227 | std::string line; 228 | 229 | char* line_read = readline(""); 230 | 231 | if (!line_read) break; 232 | char* cmd = strtok(line_read, " "); 233 | char* args = cmd ? strtok(nullptr, "") : nullptr; 234 | if (cmd){ 235 | if(executeCommand(cmd, args)==-1) 236 | { 237 | return -1; 238 | } 239 | } 240 | show_start = true; 241 | } 242 | else { 243 | if(stop_flag) 244 | { 245 | std::cout << "No input available, doing other work..." << std::endl; 246 | break; 247 | } 248 | if(show_start) 249 | { 250 | std::cout << "(npc-sdb) "<< std::flush; 251 | show_start = false; 252 | } 253 | } 254 | 255 | // 每次循环都需要重新设置文件描述符集合 256 | FD_ZERO(&readfds); 257 | FD_SET(STDIN_FILENO, &readfds); 258 | } 259 | } 260 | 261 | if(mode_sel == DISPLAY_SDB_ONLY) 262 | { 263 | while (true) { 264 | char* line = rl_gets(); 265 | if (!line) break; 266 | char* cmd = strtok(line, " "); 267 | char* args = cmd ? strtok(nullptr, "") : nullptr; 268 | if (cmd){ 269 | if(executeCommand(cmd, args)==-1) 270 | { 271 | return -1; 272 | } 273 | } 274 | } 275 | } 276 | return 0; 277 | } 278 | 279 | int SDB::executeCommand(const std::string& cmd, char* args) { 280 | if (cmd == "help") { 281 | cmd_help(args); 282 | } else if (cmd == "c") { 283 | cmd_c(args); 284 | } else if (cmd == "q") { 285 | cmd_q(args); 286 | return -1; 287 | } else if (cmd == "si"){ 288 | cmd_si(args); 289 | } else if (cmd == "info"){ 290 | cmd_info(args); 291 | } else if (cmd == "x"){ 292 | cmd_x(args); 293 | } else if (cmd == "p"){ 294 | cmd_p(args); 295 | } else if (cmd == "w"){ 296 | cmd_w(args); 297 | } else if (cmd == "d"){ 298 | cmd_d(args); 299 | }else { 300 | std::cout << "Unknown command: " << cmd << "\n"; 301 | } 302 | return 0; 303 | } 304 | 305 | void SDB::init_sdb() { 306 | expr->initExpr(); 307 | watchpoint->initPool(); 308 | } 309 | -------------------------------------------------------------------------------- /src/monitor/sdb/watchpoint.cpp: -------------------------------------------------------------------------------- 1 | #include "sdb/watchpoint.h" 2 | #include "main.h" 3 | 4 | WatchPointManager::WatchPointManager(): free_(nullptr), head(nullptr) { 5 | initPool(); 6 | // stop_flag = false; 7 | } 8 | 9 | WatchPointManager::~WatchPointManager(){ 10 | std::cout << "delete wp" << std::endl; 11 | } 12 | 13 | void WatchPointManager::initPool() { 14 | for (int i = 0; i < NR_WP; i++) { 15 | wp_pool[i].NO = i; 16 | wp_pool[i].next = (i == NR_WP - 1 ? nullptr : &wp_pool[i + 1]); 17 | } 18 | head = nullptr; 19 | free_ = wp_pool; 20 | } 21 | 22 | WatchPoint* WatchPointManager::newWatchPoint() { 23 | if (free_ == nullptr) { 24 | assert(false && "No free watch points available!"); 25 | } 26 | 27 | WatchPoint* new_wp = free_; 28 | free_ = free_->next; // 从空闲链表中取出 29 | 30 | if (head == nullptr) { 31 | head = new_wp; 32 | } else { 33 | WatchPoint* temp = head; 34 | while (temp->next != nullptr) { 35 | temp = temp->next; 36 | } 37 | temp->next = new_wp; 38 | } 39 | 40 | new_wp->next = nullptr; // 新观察点的 next 设为 nullptr 41 | return new_wp; 42 | } 43 | 44 | void WatchPointManager::freeWatchPoint(WatchPoint* wp) 45 | { 46 | if (head == nullptr || wp == nullptr) { 47 | return; 48 | } 49 | // 如果要释放的是头节点 50 | if (head == wp) { 51 | head = head->next; 52 | } 53 | else { 54 | WatchPoint* temp = head; 55 | WatchPoint* prev = nullptr; 56 | while (temp != nullptr && temp != wp) { 57 | prev = temp; 58 | temp = temp->next; 59 | } 60 | if (temp == wp) { 61 | prev->next = temp->next; // 从链表中移除 62 | } 63 | } 64 | 65 | // 清空观察点数据并加入空闲链表 66 | wp->enb = false; 67 | wp->expr.clear(); 68 | wp->next = free_; 69 | free_ = wp; 70 | } 71 | 72 | bool WatchPointManager::freeWatchPointByNo(int w_no) 73 | { 74 | WatchPoint* temp = head; 75 | while (temp != nullptr) 76 | { 77 | if (temp->NO == w_no) 78 | { 79 | freeWatchPoint(temp); 80 | return true; 81 | } 82 | temp = temp->next; 83 | } 84 | return false; 85 | } 86 | 87 | void WatchPointManager::printWatchPoints() const 88 | { 89 | std::cout << "\033[41mNum\tType\tEnb\tExpr\033[0m\n"; 90 | WatchPoint* temp = head; 91 | while (temp != nullptr) 92 | { 93 | std::cout << temp->NO << "\twp\t" 94 | << temp->enb << "\t" 95 | << temp->expr << "\n"; 96 | temp = temp->next; 97 | } 98 | } 99 | 100 | // void WatchPointManager::run() 101 | // { 102 | // uint32_t val; 103 | // bool success; 104 | 105 | // while (true) 106 | // { 107 | // if(stop_flag) // 停止线程 108 | // { 109 | // std::cout<<"stop wp\n"; 110 | // break; 111 | // } 112 | 113 | // WatchPoint* temp = head; 114 | // while (temp != nullptr) 115 | // { 116 | // if(monitor->sdb->expr->evaluate(temp->expr, success)) 117 | // { 118 | // std::cout << "\033[;41mNO:" << temp->NO << "|EXPR:" << temp->expr << "\033[0m\t"; 119 | // mNPC->stop_flag = true; 120 | // stop_flag = true; 121 | // break; 122 | // } 123 | // temp = temp->next; 124 | // } 125 | 126 | // } 127 | 128 | // } -------------------------------------------------------------------------------- /src/monitor/tools/difftest.cpp: -------------------------------------------------------------------------------- 1 | #include "tools/difftest.h" 2 | #include "reg.h" 3 | 4 | DiffTest::DiffTest() 5 | { 6 | cpu.pc = riscv32_reg->pc; 7 | for (int i = 0; i < 32; i++) { 8 | cpu.gpr[i] = riscv32_reg->gpr[i]; 9 | } 10 | } 11 | 12 | DiffTest::~DiffTest() 13 | { 14 | std::cout << "difftest" << std::endl; 15 | if (handle) { 16 | dlclose(handle); 17 | } 18 | } 19 | 20 | void DiffTest::initDifftest(const std::string& ref_so_file, size_t img_size, uint8_t* mem_addr) 21 | { 22 | this->img_size = img_size; 23 | this->mem_addr = mem_addr; 24 | assert(!ref_so_file.empty()); 25 | 26 | handle = dlopen(ref_so_file.c_str(), RTLD_LAZY); 27 | assert(handle); 28 | 29 | ref_difftest_memcpy = (MemCpyFunc)dlsym(handle, "difftest_memcpy"); 30 | ref_difftest_regcpy = (RegCpyFunc)dlsym(handle, "difftest_regcpy"); 31 | ref_difftest_exec = (ExecFunc)dlsym(handle, "difftest_exec"); 32 | ref_difftest_raise_intr = (RaiseIntrFunc)dlsym(handle, "difftest_raise_intr"); 33 | auto ref_difftest_init = (InitFunc)dlsym(handle, "difftest_init"); 34 | 35 | assert(ref_difftest_memcpy && ref_difftest_regcpy && ref_difftest_exec && ref_difftest_raise_intr && ref_difftest_init); 36 | 37 | std::cout << "Differential testing: \033[1;31mON\033[0m\n"; 38 | std::cout << "The result of every instruction will be compared with " << ref_so_file 39 | << ". This will help you a lot for debugging but also significantly reduce the performance. " 40 | "If it is not necessary, you can turn it off in menuconfig.\n"; 41 | 42 | ref_difftest_init(0); 43 | ref_difftest_memcpy(0x80000000, mem_addr, img_size, true); 44 | ref_difftest_regcpy(&cpu, true); 45 | } 46 | 47 | bool DiffTest::checkRegisters(const RISCV32_CPUState& ref_r, uint32_t pc) const 48 | { 49 | if (pc != ref_r.pc) { 50 | std::cout << "pc=0x" << std::hex << pc << "\tref_pc=0x" << ref_r.pc << std::dec << "\n"; 51 | return false; 52 | } 53 | 54 | for (int i = 0; i < 32; i++) { 55 | if (ref_r.gpr[i] != riscv32_reg->gpr[i]) { 56 | std::cout << "\033[1;31mreg" << i << ":dut=0x" << std::hex << riscv32_reg->gpr[i] 57 | << "\tref=0x" << ref_r.gpr[i] << "\033[0m\n" 58 | << std::dec; 59 | return false; 60 | } 61 | } 62 | 63 | return true; 64 | } 65 | 66 | bool DiffTest::step(uint32_t pc, int inst_skip_flag) 67 | { 68 | RISCV32_CPUState ref_r; 69 | 70 | if (inst_skip_flag) { 71 | // 差分测试跳过 72 | ref_difftest_memcpy(0x80000000, mem_addr, img_size, true); 73 | ref_difftest_regcpy(&cpu, true); 74 | return true; 75 | } 76 | 77 | ref_difftest_exec(1); 78 | ref_difftest_regcpy(&ref_r, false); 79 | 80 | return checkRegisters(ref_r, pc); 81 | } 82 | 83 | 84 | -------------------------------------------------------------------------------- /src/monitor/tools/ftrace.cpp: -------------------------------------------------------------------------------- 1 | #include "tools/ftrace.h" 2 | #include 3 | 4 | #include 5 | #include 6 | 7 | void Ftrace::initFtrace(const std::string &elf_file) 8 | { 9 | elf_fp = stdout; 10 | if (!elf_file.empty()) { 11 | elf_fp = fopen(elf_file.c_str(), "rb"); 12 | if (elf_fp == nullptr) { 13 | std::cerr << "Cannot open '" << elf_file << "'" << std::endl; 14 | std::cout << "*****************" << std::endl; 15 | } 16 | } 17 | std::cout << "elf file:" << (elf_file.empty() ? "stdout" : elf_file) << std::endl; 18 | parseElfSymbols(elf_file); 19 | } 20 | 21 | int Ftrace::instTotal(const std::string &elf_file) 22 | { 23 | char cmd[512]; 24 | char buffer[128]; 25 | int inst_num = 0; 26 | // 使用 sprintf 格式化命令 27 | sprintf(cmd, 28 | "riscv64-linux-gnu-objdump -d %s |" 29 | "sed -n -r '/^800[0-9a-f]{5}/p' |" 30 | "awk '{print $2}' |" 31 | "sed -n '/^[0-9a-f]/p' |" 32 | "wc -l", 33 | elf_file.c_str()); 34 | 35 | FILE *fp = popen(cmd, "r"); 36 | if (fp == nullptr) { 37 | std::cerr << "popen elf file error" << std::endl; 38 | return 0; 39 | } 40 | 41 | if (fgets(buffer, sizeof(buffer), fp) != nullptr) { 42 | inst_num = std::atoi(buffer); 43 | std::cout << "Total number of Instructions: " << inst_num << std::endl; 44 | } 45 | 46 | pclose(fp); 47 | return inst_num; 48 | } 49 | 50 | void Ftrace::getSourceCode(const std::string &elf_file) 51 | { 52 | char cmd[512]; 53 | // 创建一个管道,通过该管道读取外部命令的输出 54 | std::array buffer; 55 | // std::string result; 56 | // // 使用 sprintf 格式化命令 57 | sprintf(cmd, 58 | "riscv64-linux-gnu-objdump -d -S %s", 59 | elf_file.c_str()); 60 | 61 | // 执行命令,并通过管道读取命令输出 62 | std::shared_ptr pipe(popen(cmd, "r"), pclose); 63 | if (!pipe) { 64 | throw std::runtime_error("popen failed!"); 65 | } 66 | // 读取命令输出 67 | while (fgets(buffer.data(), buffer.size(), pipe.get()) != nullptr) { 68 | src += buffer.data(); 69 | } 70 | 71 | // 查找 "80000000" 的位置 72 | size_t pos = src.find("80000000"); 73 | 74 | // 如果找到了 "80000000" 75 | if (pos != std::string::npos) { 76 | // 截取从 "80000000" 开始的部分 77 | src = src.substr(pos); 78 | // 输出结果 79 | // std::cout << src << std::endl; 80 | } else { 81 | std::cout << "未找到指定字符串" << std::endl; 82 | } 83 | 84 | return; 85 | } 86 | 87 | void Ftrace::getElfHeader() { 88 | if (fread(&ehdr, 1, sizeof(ehdr), elf_fp) != sizeof(ehdr)) { 89 | fclose(elf_fp); 90 | std::cerr << "fread error" << std::endl; 91 | return; 92 | } 93 | 94 | if (ehdr.e_ident[EI_MAG0] != ELFMAG0 || ehdr.e_ident[EI_MAG1] != ELFMAG1 || 95 | ehdr.e_ident[EI_MAG2] != ELFMAG2 || ehdr.e_ident[EI_MAG3] != ELFMAG3) { 96 | fclose(elf_fp); 97 | std::cerr << "Not an ELF file" << std::endl; 98 | return; 99 | } 100 | } 101 | 102 | void Ftrace::getElfSection() { 103 | Elf32_Off shoff = ehdr.e_shoff; 104 | uint16_t shnum = ehdr.e_shnum; 105 | uint16_t shentsize = ehdr.e_shentsize; 106 | bool found_symtab = false; 107 | bool found_strtab = false; 108 | 109 | for (int i = 0; i < shnum; i++) { 110 | Elf32_Shdr shdr; 111 | fseek(elf_fp, shoff + i * shentsize, SEEK_SET); 112 | 113 | if (fread(&shdr, 1, sizeof(shdr), elf_fp) != sizeof(shdr)) { 114 | fclose(elf_fp); 115 | std::cerr << "fread error" << std::endl; 116 | return; 117 | } 118 | 119 | if (shdr.sh_type == SHT_SYMTAB) { 120 | symtab_shdr = shdr; 121 | found_symtab = true; 122 | } else if (shdr.sh_type == SHT_STRTAB && !found_strtab) { 123 | strtab_shdr = shdr; 124 | found_strtab = true; 125 | } 126 | 127 | if (found_symtab && found_strtab) 128 | break; 129 | } 130 | 131 | if (!found_symtab || !found_strtab) { 132 | std::cerr << "Symbol table or string table not found in the ELF file" << std::endl; 133 | return; 134 | } 135 | } 136 | 137 | void Ftrace::getElfSymbols() { 138 | std::vector strtab(strtab_shdr.sh_size); 139 | 140 | fseek(elf_fp, strtab_shdr.sh_offset, SEEK_SET); 141 | if (fread(strtab.data(), 1, strtab_shdr.sh_size, elf_fp) != strtab_shdr.sh_size) { 142 | std::cerr << "fread strtab error" << std::endl; 143 | return; 144 | } 145 | 146 | int num_symbols = symtab_shdr.sh_size / symtab_shdr.sh_entsize; 147 | Elf32_Sym sym; 148 | 149 | for (int i = 0; i < num_symbols; i++) { 150 | fseek(elf_fp, symtab_shdr.sh_offset + i * sizeof(sym), SEEK_SET); 151 | if (fread(&sym, 1, sizeof(sym), elf_fp) != sizeof(sym)) { 152 | std::cerr << "fread symtab error" << std::endl; 153 | return; 154 | } 155 | 156 | if (ELF32_ST_TYPE(sym.st_info) != STT_FUNC) 157 | continue; 158 | 159 | FuncSym func_sym{}; 160 | strncpy(func_sym.func_name, &strtab[sym.st_name], 20); 161 | func_sym.func_addr = sym.st_value; 162 | func_sym.func_size = sym.st_size; 163 | func_sym_tab.push_back(func_sym); 164 | func_sym_num++; 165 | } 166 | } 167 | 168 | void Ftrace::parseElfSymbols(const std::string &filename) { 169 | if(elf_fp == nullptr) 170 | std::cout << "elf_fp is null" << std::endl; 171 | if (filename.empty()) { 172 | std::cerr << "Invalid filename" << std::endl; 173 | return; 174 | } 175 | 176 | elf_fp = fopen(filename.c_str(), "rb"); 177 | if (elf_fp == nullptr) { 178 | std::cerr << "Cannot open ELF file" << std::endl; 179 | return; 180 | } 181 | 182 | getElfHeader(); 183 | getElfSection(); 184 | getElfSymbols(); 185 | 186 | fclose(elf_fp); 187 | elf_fp = nullptr; 188 | } 189 | -------------------------------------------------------------------------------- /src/ui/codeeditor.cpp: -------------------------------------------------------------------------------- 1 | #include "codeeditor.h" 2 | #include "highlighter.h" 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | #include 13 | 14 | CodeEditor::CodeEditor(QWidget *parent,QFont font) 15 | : QPlainTextEdit(parent) 16 | , lineNumberWidget(0) 17 | , mHighlighter(0) 18 | , mCompleter(0) 19 | { 20 | lineNumberWidget = new LineNumberWidget(this); 21 | 22 | //绑定 23 | initConnection(); 24 | 25 | //高亮 26 | initHighlighter(); 27 | 28 | //设置completor 29 | initCompleter(); 30 | 31 | 32 | //设置字体 33 | setAllFont(font); 34 | 35 | //行高亮 36 | highlightCurrentLine(); 37 | 38 | //设置边距 39 | updateLineNumberWidgetWidth(); 40 | 41 | //不自动换行 42 | setLineWrapMode(QPlainTextEdit::NoWrap); 43 | 44 | //去掉边框 45 | setFrameShape(QPlainTextEdit::NoFrame); 46 | 47 | } 48 | 49 | CodeEditor::~CodeEditor() 50 | { 51 | // qDebug() << "CodeEditor" ; 52 | delete lineNumberWidget; 53 | } 54 | 55 | void CodeEditor::initConnection() 56 | { 57 | //cursor 58 | connect(this,SIGNAL(cursorPositionChanged()),this,SLOT(highlightCurrentLine())); 59 | 60 | //textChanged 61 | connect(this,SIGNAL(textChanged()),this,SLOT(updateSaveState())); 62 | 63 | //blockCount 64 | connect(this,SIGNAL(blockCountChanged(int)),this,SLOT(updateLineNumberWidgetWidth())); 65 | 66 | //updateRequest 67 | connect(this,SIGNAL(updateRequest(QRect,int)),this,SLOT(updateLineNumberWidget(QRect,int))); 68 | } 69 | 70 | void CodeEditor::setAllFont(QFont font) 71 | { 72 | this->setFont(font); 73 | mHighlighter->setFont(font); 74 | mHighlighter->rehighlight(); 75 | mCompleter->popup()->setFont(font); 76 | viewport()->update(); 77 | lineNumberWidget->update(); 78 | updateLineNumberWidgetWidth(); 79 | } 80 | 81 | bool CodeEditor::checkSaved() 82 | { 83 | return isSaved; 84 | } 85 | 86 | void CodeEditor::initHighlighter() 87 | { 88 | mHighlighter = new Highlighter(document()); 89 | } 90 | 91 | void CodeEditor::initCompleter() 92 | { 93 | mCompleter = new QCompleter(); 94 | 95 | QStringList list; 96 | list<<"int"<<"init"<<"void"<<"while"<<"completer"<<"abstract"<<"apple"; 97 | list.sort(Qt::CaseInsensitive); 98 | 99 | QStringListModel * model = new QStringListModel(list,mCompleter); 100 | 101 | mCompleter->setModel(model); 102 | mCompleter->setModelSorting(QCompleter::CaseInsensitivelySortedModel); 103 | mCompleter->setWrapAround(false); 104 | 105 | mCompleter->setWidget(this); 106 | mCompleter->setCompletionMode(QCompleter::PopupCompletion); 107 | 108 | connect(mCompleter,SIGNAL(activated(const QString &)),this,SLOT(insertCompletion(const QString &))); 109 | } 110 | 111 | int CodeEditor::getLineNumberWidgetWidth() 112 | { 113 | //获取宽度(合适) 114 | return 8+QString::number(blockCount()+1).length()*fontMetrics().horizontalAdvance(QChar('0')); 115 | } 116 | 117 | 118 | void CodeEditor::highlightCurrentLine() 119 | { 120 | QList extraSelections; 121 | 122 | QTextEdit::ExtraSelection selection; 123 | selection.format.setBackground(QColor(0,100,100,20)); 124 | selection.format.setProperty(QTextFormat::FullWidthSelection,true); 125 | selection.cursor =textCursor(); 126 | 127 | extraSelections.append(selection); 128 | setExtraSelections(extraSelections); 129 | 130 | } 131 | 132 | void CodeEditor::updateLineNumberWidget(QRect rect, int dy) 133 | { 134 | if(dy) 135 | lineNumberWidget->scroll(0,dy); 136 | else 137 | lineNumberWidget->update(0,rect.y(),getLineNumberWidgetWidth(),rect.height()); 138 | } 139 | 140 | void CodeEditor::updateLineNumberWidgetWidth() 141 | { 142 | //设置边距 143 | setViewportMargins(getLineNumberWidgetWidth(),0,0,0); 144 | } 145 | 146 | void CodeEditor::updateSaveState() 147 | { 148 | //更新保存状态 149 | isSaved = false; 150 | } 151 | 152 | void CodeEditor::insertCompletion(const QString &completion) 153 | { 154 | QTextCursor cursor = textCursor(); 155 | 156 | 157 | 158 | int length =completion.length()-mCompleter->completionPrefix().length(); 159 | 160 | cursor.movePosition(QTextCursor::Left); 161 | cursor.movePosition(QTextCursor::EndOfWord); 162 | 163 | cursor.insertText(completion.right(length)); 164 | 165 | setTextCursor(cursor); 166 | } 167 | 168 | void CodeEditor::resizeEvent(QResizeEvent *event) 169 | { 170 | QPlainTextEdit::resizeEvent(event); 171 | lineNumberWidget->setGeometry(0,0,getLineNumberWidgetWidth(),contentsRect().height()); 172 | } 173 | 174 | void CodeEditor::keyPressEvent(QKeyEvent *event) 175 | { 176 | switch(event->key()){ 177 | case Qt::Key_ParenLeft: 178 | textCursor().insertText(")"); 179 | break; 180 | case Qt::Key_BracketLeft: 181 | textCursor().insertText("]"); 182 | break; 183 | case Qt::Key_BraceLeft: 184 | textCursor().insertText("}"); 185 | break; 186 | case Qt::Key_QuoteDbl: 187 | textCursor().insertText("\""); 188 | break; 189 | case Qt::Key_Apostrophe: 190 | textCursor().insertText("'"); 191 | break; 192 | case Qt::Key_Enter: 193 | case Qt::Key_Backtab: 194 | case Qt::Key_Return: 195 | case Qt::Key_Escape: 196 | case Qt::Key_Tab: 197 | if(mCompleter->popup()->isVisible()){ 198 | event->ignore(); 199 | return; 200 | } 201 | } 202 | //Alt + C 203 | bool isShortCut = (event->modifiers()&Qt::AltModifier)&&event->key()==Qt::Key_C; 204 | 205 | if(!isShortCut) 206 | QPlainTextEdit::keyPressEvent(event); 207 | 208 | if(event->key()==Qt::Key_ParenLeft|| 209 | event->key()==Qt::Key_BracketLeft|| 210 | event->key()==Qt::Key_BraceLeft|| 211 | event->key()==Qt::Key_QuoteDbl|| 212 | event->key()==Qt::Key_Apostrophe){ 213 | QTextCursor cursor = textCursor(); 214 | cursor.movePosition(QTextCursor::Left); 215 | setTextCursor(cursor); 216 | } 217 | 218 | QTextCursor cursor = textCursor(); 219 | cursor.select(QTextCursor::WordUnderCursor); 220 | QString prefix = cursor.selectedText(); 221 | QString endSign = "~!@#$%^&*()_-+=\\/,.。;??‘'\"{}[]<>"; 222 | if(!isShortCut&&(endSign.contains(event->text().right(1))||prefix.length()<2)){ 223 | mCompleter->popup()->hide(); 224 | return; 225 | } 226 | 227 | if(mCompleter->completionPrefix()!=prefix){ 228 | mCompleter->setCompletionPrefix(prefix); 229 | mCompleter->popup()->setCurrentIndex(mCompleter->completionModel()->index(0,0)); 230 | } 231 | QRect rect = cursorRect(); 232 | rect.setWidth(mCompleter->popup()->sizeHintForColumn(0)+mCompleter->popup()->verticalScrollBar()->sizeHint().width()); 233 | 234 | mCompleter->complete(rect); 235 | } 236 | 237 | void CodeEditor::lineNumberWidgetPaintEvent(QPaintEvent *event) 238 | { 239 | QPainter painter(lineNumberWidget); 240 | //绘制行号区域 241 | painter.fillRect(event->rect(),QColor(100,100,100,10)); 242 | 243 | //拿到block 244 | QTextBlock block = firstVisibleBlock(); 245 | 246 | //拿到行号 247 | int blockNumber =block.blockNumber(); 248 | 249 | //拿到当前的block的top 250 | int cursorTop = blockBoundingGeometry(textCursor().block()).translated(contentOffset()).top(); 251 | 252 | //拿到block的top 253 | int top = blockBoundingGeometry(block).translated(contentOffset()).top(); 254 | 255 | //拿到block的bottom 256 | int bottom = top +blockBoundingRect(block).height(); 257 | 258 | while(block.isValid()&&top<=event->rect().bottom()){ 259 | //设置画笔颜色 260 | painter.setPen(cursorTop==top?Qt::black:Qt::gray); 261 | //绘制文字 262 | painter.drawText(0,top,getLineNumberWidgetWidth()-3,bottom-top,Qt::AlignRight,QString::number(blockNumber+1)); 263 | 264 | //拿到下一个block 265 | block = block.next(); 266 | 267 | top = bottom; 268 | bottom = top +blockBoundingRect(block).height(); 269 | blockNumber++; 270 | } 271 | } 272 | 273 | void CodeEditor::lineNumberWidgetMousePressEvent(QMouseEvent *event) 274 | { 275 | setTextCursor(QTextCursor(document()->findBlockByLineNumber(event->y()/fontMetrics().height()+verticalScrollBar()->value()))); 276 | } 277 | 278 | void CodeEditor::lineNumberWidgetWheelEvent(QWheelEvent *event) 279 | { 280 | if(event->orientation()==Qt::Horizontal){ 281 | horizontalScrollBar()->setValue(horizontalScrollBar()->value()-event->delta()); 282 | }else { 283 | verticalScrollBar()->setValue(verticalScrollBar()->value()-event->delta()); 284 | } 285 | event->accept(); 286 | } 287 | 288 | bool CodeEditor::saveFile() 289 | { 290 | QString fileName; 291 | if(mFileName.isEmpty()){ 292 | fileName =QFileDialog::getSaveFileName(this,"保存文件"); 293 | mFileName =fileName; 294 | }else{ 295 | fileName =mFileName; 296 | } 297 | QFile file(fileName); 298 | if(!file.open(QIODevice::WriteOnly|QFile::Text)){ 299 | QMessageBox::warning(this,"警告","无法保存文件:"+file.errorString()); 300 | return false; 301 | } 302 | QTextStream out(&file); 303 | 304 | out<textCursor(); 342 | 343 | // // 移动到指定行 344 | // // QTextBlock block = this->document()->findBlockByNumber(lineNumber - 1); // lineNumber is 1-based 345 | // cursor.setPosition(this->document()->findBlockByNumber(lineNumber).position()); 346 | // this->setTextCursor(cursor); 347 | // this->ensureCursorVisible(); 348 | // // // 设置光标到该行的起始位置 349 | // // cursor.setPosition(block.position()); 350 | // // cursor.movePosition(QTextCursor::EndOfBlock, QTextCursor::KeepAnchor); 351 | 352 | // // 设置该行的背景色 353 | // QTextCharFormat format; 354 | // format.setBackground(color); 355 | 356 | // // 应用格式 357 | // cursor.mergeCharFormat(format); 358 | 359 | 360 | // 获取指定行的 QTextBlock 361 | QTextBlock block = this->document()->findBlockByNumber(lineNumber); 362 | if (!block.isValid()) { 363 | qDebug() << "Invalid block at line" << lineNumber; 364 | return; 365 | } 366 | 367 | // 设置光标位置到该行的起始位置 368 | QTextCursor cursor(block); 369 | this->setTextCursor(cursor); 370 | 371 | // 设置整行的背景颜色 372 | QTextBlockFormat blockFormat; 373 | blockFormat.setBackground(color); // 设置背景颜色 374 | 375 | // 设置当前行的格式 376 | cursor.mergeBlockFormat(blockFormat); 377 | 378 | // 确保光标所在行可见 379 | this->ensureCursorVisible(); 380 | } 381 | 382 | // 取消所有行的高亮 383 | void CodeEditor::removeLastHighlights(int lineNumber) 384 | { 385 | // 获取指定行的 QTextBlock 386 | QTextBlock block = this->document()->findBlockByNumber(lineNumber); 387 | if (!block.isValid()) { 388 | qDebug() << "Invalid block at line" << lineNumber; 389 | return; 390 | } 391 | 392 | // 设置光标位置到该行的起始位置 393 | QTextCursor cursor(block); 394 | this->setTextCursor(cursor); 395 | 396 | // 恢复默认背景颜色,即清除背景颜色 397 | QTextBlockFormat blockFormat; 398 | blockFormat.setBackground(Qt::transparent); // 设置背景为透明,恢复默认背景 399 | 400 | // 应用格式 401 | cursor.mergeBlockFormat(blockFormat); 402 | 403 | // 确保光标所在行可见 404 | this->ensureCursorVisible(); 405 | } -------------------------------------------------------------------------------- /src/ui/csrmonitor.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include "csrmonitor.h" 4 | 5 | 6 | CSRMonitor::CSRMonitor() 7 | { 8 | // 设置行数和列数 9 | this->setRowCount(2); 10 | this->setColumnCount(8); 11 | // this->setFont(QFont(mFontFamily,mFontSize)); 12 | this->setEditTriggers(QAbstractItemView::NoEditTriggers); 13 | 14 | this->horizontalHeader()->setSectionResizeMode(QHeaderView::Stretch); 15 | this->verticalHeader()->setSectionResizeMode(QHeaderView::Stretch); 16 | // 禁用选择功能 17 | this->setSelectionMode(QAbstractItemView::NoSelection); 18 | // this->horizontalHeader()->hide(); 19 | this->verticalHeader()->hide(); 20 | this->setHorizontalHeaderLabels(QStringList() << "Name" << "Value" << "Name" << "Value" << \ 21 | "Name" << "Value" << "Name" << "Value" ); 22 | // 设置水平表头的高度 23 | this->horizontalHeader()->setFixedHeight(50); // 设置表头高度为 50 像素 24 | QFont headerFontReg = this->horizontalHeader()->font(); 25 | headerFontReg.setPointSize(16); // 设置字体大小 26 | this->horizontalHeader()->setFont(headerFontReg); 27 | 28 | 29 | // 设置样式表,使鼠标悬浮时高亮 30 | this->setStyleSheet( 31 | "QTableWidget::item:hover {" 32 | " background-color: lightblue;" // 悬浮时的背景色 33 | "}" 34 | ); 35 | 36 | connect(this, &QTableWidget::cellDoubleClicked, this, &CSRMonitor::setCSRBreakpoint); 37 | } 38 | 39 | CSRMonitor::~CSRMonitor() 40 | { 41 | 42 | } 43 | 44 | void CSRMonitor::initCSRMonitor() 45 | { 46 | const QString reg[] = { 47 | "mstatus", "mip", "mie", "mcause", "mtvec", "mtval", "mepc", "mscratch", 48 | }; 49 | 50 | for(int i=0; i<8; i++) 51 | { 52 | QTableWidgetItem *item_name = new QTableWidgetItem(reg[i]); 53 | item_name->setTextAlignment(Qt::AlignCenter); // 文本居中 54 | this->setItem(i/4, i%4*2, item_name); 55 | 56 | QString val = QString("%1").arg(0, 8, 16, QChar('0')).toUpper(); 57 | QTableWidgetItem *item_val = new QTableWidgetItem("0x"+val); 58 | item_val->setTextAlignment(Qt::AlignCenter); // 文本居中 59 | // item_val->setBackground(QColor(Qt::red)); 60 | this->setItem(i/4, i%4*2+1, item_val); 61 | this->setRowHeight(i, 30); 62 | } 63 | } 64 | 65 | void CSRMonitor::receiveCSRValue(unsigned int *csr_val) 66 | { 67 | QTableWidgetItem *item_clear = this->item(last_csr_pos/8, last_csr_pos%8*2+1); 68 | item_clear->setBackground(QColor(Qt::white)); 69 | 70 | for(int i=0; i<8; i++) 71 | { 72 | QTableWidgetItem *item_color = this->item(i/8, i%8*2+1); 73 | if (item_color) 74 | { 75 | QString text = item_color->text(); 76 | bool ok; 77 | uint32_t value = text.toUInt(&ok, 16); 78 | if (ok) 79 | { 80 | if(value != csr_val[i]) 81 | { 82 | last_csr_pos = i; 83 | QString val = QString("%1").arg(csr_val[i], 8, 16, QChar('0')).toUpper(); 84 | item_color->setText("0x"+val); 85 | item_color->setBackground(QColor(Qt::green)); // 设置背景为绿色 86 | item_color->setTextAlignment(Qt::AlignCenter); // 文本居中 87 | } 88 | } 89 | else 90 | { 91 | std::cout << "Conversion failed!\n"; 92 | } 93 | } 94 | else 95 | { 96 | std::cout << "Item not found\n"; 97 | } 98 | } 99 | } 100 | 101 | void CSRMonitor::setCSRBreakpoint(int row, int column) 102 | { 103 | if(column%2==0) 104 | { 105 | for(int i = 0; i <= csr_breakpoint.size(); ++i) 106 | { 107 | QPair pair = csr_breakpoint.at(i); 108 | if(pair.first == row && pair.second == column) 109 | { 110 | csr_breakpoint.removeAt(i); 111 | QTableWidgetItem *item_reg = this->item(row, column); 112 | item_reg->setBackground(QColor(Qt::white)); 113 | return; 114 | } 115 | } 116 | csr_breakpoint.append(qMakePair(row, column)); 117 | QTableWidgetItem *item_reg = this->item(row, column); 118 | item_reg->setBackground(QColor(Qt::blue)); 119 | } 120 | } -------------------------------------------------------------------------------- /src/ui/filesystemmodel.cpp: -------------------------------------------------------------------------------- 1 | #include "filesystemmodel.h" 2 | 3 | FileSystemModel::FileSystemModel(QObject *parent) : QFileSystemModel(parent) 4 | { 5 | 6 | } 7 | 8 | Qt::ItemFlags FileSystemModel::flags(const QModelIndex &index) const 9 | { 10 | Q_UNUSED(index); 11 | return Qt::ItemIsEditable|Qt::ItemIsSelectable|Qt::ItemIsEnabled; 12 | } 13 | 14 | int FileSystemModel::columnCount(const QModelIndex &parent) const 15 | { 16 | Q_UNUSED(parent); 17 | //只显示一列 18 | return 1; 19 | } 20 | 21 | bool FileSystemModel::setData(const QModelIndex &index, const QVariant &value, int role) 22 | { 23 | if(value==fileName(index)) return true; 24 | QFileSystemModel::setData(index,value,role); 25 | emit dataChanged(index,index); 26 | return true; 27 | } 28 | -------------------------------------------------------------------------------- /src/ui/gprmonitor.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include "gprmonitor.h" 5 | 6 | GPRMonitor::GPRMonitor(QWidget *parent) 7 | :QWidget(parent) 8 | { 9 | 10 | last_gpr_pos = 0; 11 | 12 | initLabel(); 13 | initTableWidget(); 14 | 15 | QVBoxLayout * regVLayout = new QVBoxLayout(this); 16 | regVLayout->addWidget(title_label); 17 | regVLayout->addWidget(gprTableWidget); 18 | regVLayout->setMargin(0); 19 | regVLayout->setSpacing(0); 20 | 21 | connect(gprTableWidget, &QTableWidget::cellDoubleClicked, this, &GPRMonitor::setGPRBreakpoint); 22 | } 23 | 24 | GPRMonitor::~GPRMonitor() 25 | { 26 | 27 | } 28 | 29 | void GPRMonitor::setFont(QString fontFamily, int fontSize) 30 | { 31 | title_label->setFont(QFont(fontFamily, fontSize)); 32 | gprTableWidget->setFont(QFont(fontFamily, fontSize)); 33 | } 34 | 35 | void GPRMonitor::initLabel() 36 | { 37 | title_label = new QLabel(this); 38 | title_label->setIndent(5); 39 | title_label->setMinimumHeight(25); 40 | 41 | QPalette palette; 42 | palette.setColor(QPalette::Background,QColor(250,250,250)); 43 | title_label->setPalette(palette); 44 | title_label->setAutoFillBackground(true); 45 | 46 | title_label->setText("Register Monitor"); 47 | title_label->setAlignment(Qt::AlignCenter); 48 | title_label->setMaximumHeight(50); 49 | } 50 | 51 | void GPRMonitor::initTableWidget() 52 | { 53 | gprTableWidget = new QTableWidget(this); 54 | // 设置行数和列数 55 | gprTableWidget->setRowCount(4); 56 | gprTableWidget->setColumnCount(16); 57 | 58 | gprTableWidget->setEditTriggers(QAbstractItemView::NoEditTriggers); 59 | 60 | gprTableWidget->horizontalHeader()->setSectionResizeMode(QHeaderView::Stretch); 61 | gprTableWidget->verticalHeader()->setSectionResizeMode(QHeaderView::Stretch); 62 | // 禁用选择功能 63 | gprTableWidget->setSelectionMode(QAbstractItemView::NoSelection); 64 | // gprTableWidget->horizontalHeader()->hide(); 65 | gprTableWidget->verticalHeader()->hide(); 66 | gprTableWidget->setHorizontalHeaderLabels(QStringList() << "Name" << "Value" << "Name" << "Value" << \ 67 | "Name" << "Value" << "Name" << "Value" << \ 68 | "Name" << "Value" << "Name" << "Value" << \ 69 | "Name" << "Value" << "Name" << "Value"); 70 | // 设置水平表头的高度 71 | gprTableWidget->horizontalHeader()->setFixedHeight(50); // 设置表头高度为 50 像素 72 | QFont headerFontReg = gprTableWidget->horizontalHeader()->font(); 73 | headerFontReg.setPointSize(16); // 设置字体大小 74 | gprTableWidget->horizontalHeader()->setFont(headerFontReg); 75 | 76 | 77 | // 设置样式表,使鼠标悬浮时高亮 78 | gprTableWidget->setStyleSheet( 79 | "QTableWidget::item:hover {" 80 | " background-color: lightblue;" // 悬浮时的背景色 81 | "}" 82 | ); 83 | } 84 | 85 | void GPRMonitor::initGPRMonitor() 86 | { 87 | const QString reg[] = { 88 | "$0", "ra", "sp", "gp", "tp", "t0", "t1", "t2", 89 | "fp", "s1", "a0", "a1", "a2", "a3", "a4", "a5", 90 | "a6", "a7", "s2", "s3", "s4", "s5", "s6", "s7", 91 | "s8", "s9", "s10", "s11", "t3", "t4", "t5", "t6" 92 | }; 93 | 94 | for(int i=0; i<32; i++) 95 | { 96 | QTableWidgetItem *item_name = new QTableWidgetItem(reg[i]); 97 | item_name->setTextAlignment(Qt::AlignCenter); // 文本居中 98 | gprTableWidget->setItem(i/8, i%8*2, item_name); 99 | 100 | QString val = QString("%1").arg(0, 8, 16, QChar('0')).toUpper(); 101 | QTableWidgetItem *item_val = new QTableWidgetItem("0x"+val); 102 | item_val->setTextAlignment(Qt::AlignCenter); // 文本居中 103 | // item_val->setBackground(QColor(Qt::red)); 104 | gprTableWidget->setItem(i/8, i%8*2+1, item_val); 105 | gprTableWidget->setRowHeight(i, 30); 106 | } 107 | } 108 | 109 | void GPRMonitor::receiveGPRValue(unsigned int *gpr_val) 110 | { 111 | QTableWidgetItem *item_clear = gprTableWidget->item(last_gpr_pos/8, last_gpr_pos%8*2+1); 112 | item_clear->setBackground(QColor(Qt::white)); 113 | 114 | for(int i=0; i<32; i++) 115 | { 116 | QTableWidgetItem *item_color = gprTableWidget->item(i/8, i%8*2+1); 117 | if (item_color) 118 | { 119 | QString text = item_color->text(); 120 | bool ok; 121 | uint32_t value = text.toUInt(&ok, 16); 122 | if (ok) 123 | { 124 | if(value != gpr_val[i]) 125 | { 126 | last_gpr_pos = i; 127 | QString val = QString("%1").arg(gpr_val[i], 8, 16, QChar('0')).toUpper(); 128 | item_color->setText("0x"+val); 129 | item_color->setBackground(QColor(Qt::green)); // 设置背景为绿色 130 | item_color->setTextAlignment(Qt::AlignCenter); // 文本居中 131 | } 132 | } 133 | else 134 | { 135 | std::cout << "Conversion failed!\n"; 136 | } 137 | } 138 | else 139 | { 140 | std::cout << "Item not found\n"; 141 | } 142 | } 143 | } 144 | 145 | void GPRMonitor::setGPRBreakpoint(int row, int column) 146 | { 147 | if(column%2==0) 148 | { 149 | for(int i = 0; i <= gpr_breakpoint.size(); ++i) 150 | { 151 | QPair pair = gpr_breakpoint.at(i); 152 | if(pair.first == row && pair.second == column) 153 | { 154 | gpr_breakpoint.removeAt(i); 155 | QTableWidgetItem *item_reg = gprTableWidget->item(row, column); 156 | item_reg->setBackground(QColor(Qt::white)); 157 | return; 158 | } 159 | } 160 | gpr_breakpoint.append(qMakePair(row, column)); 161 | QTableWidgetItem *item_reg = gprTableWidget->item(row, column); 162 | item_reg->setBackground(QColor(Qt::blue)); 163 | } 164 | } -------------------------------------------------------------------------------- /src/ui/highlighter.cpp: -------------------------------------------------------------------------------- 1 | #include "highlighter.h" 2 | 3 | #include 4 | 5 | 6 | Highlighter::Highlighter(QTextDocument *parent, QString fontFamily, int fontSize): QSyntaxHighlighter(parent) 7 | { 8 | mFontFamily =fontFamily; 9 | mFontSize = fontSize; 10 | 11 | 12 | initFormat(); 13 | 14 | } 15 | 16 | void Highlighter::initFormat() 17 | { 18 | //对于普通文本 19 | addNormalTextFormat(); 20 | 21 | //对于数字 22 | addNumberFormat(); 23 | 24 | //对于字符串 25 | addStringFormat(); 26 | 27 | //对于注释 28 | addCommentFormat(); 29 | 30 | //对于关键字/保留字 31 | addKeywordsFromat(); 32 | 33 | //对于类名 34 | addClassNameFormat(); 35 | 36 | //对于方法/函数 37 | addFunctionFormat(); 38 | } 39 | void Highlighter::setFont(QFont font) 40 | { 41 | mFontFamily = font.family(); 42 | mFontSize = font.pointSize(); 43 | } 44 | 45 | 46 | void Highlighter::addNormalTextFormat() 47 | { 48 | HighlightRule rule; 49 | rule.pattern = QRegExp("[a-z0-9A-Z]+"); 50 | 51 | QTextCharFormat normalTextFormat; 52 | 53 | normalTextFormat.setForeground(QColor(0,0,0)); 54 | 55 | rule.format = normalTextFormat; 56 | 57 | highlightRules.append(rule); 58 | } 59 | 60 | void Highlighter::addNumberFormat() 61 | { 62 | HighlightRule rule; 63 | rule.pattern = QRegExp("\\b\\d+|\\d+\\.\\d+\\b"); 64 | 65 | QTextCharFormat numberFormat; 66 | 67 | numberFormat.setForeground(QColor(250,80,50)); 68 | 69 | rule.format = numberFormat; 70 | 71 | highlightRules.append(rule); 72 | } 73 | 74 | void Highlighter::addStringFormat() 75 | { 76 | QTextCharFormat stringFormat; 77 | 78 | stringFormat.setForeground(QColor(0,180,180)); 79 | 80 | 81 | HighlightRule rule; 82 | 83 | rule.format = stringFormat; 84 | 85 | //'' 86 | rule.pattern = QRegExp("'[^']*'"); 87 | highlightRules.append(rule); 88 | 89 | //"" 90 | rule.pattern = QRegExp("\"[^\"]*\""); 91 | highlightRules.append(rule); 92 | 93 | //`` 94 | rule.pattern = QRegExp("`[^`]*`"); 95 | highlightRules.append(rule); 96 | 97 | } 98 | 99 | void Highlighter::addCommentFormat() 100 | { 101 | QTextCharFormat commnetFormat; 102 | 103 | commnetFormat.setForeground(Qt::darkGreen); 104 | commnetFormat.setFontItalic(true); 105 | 106 | 107 | HighlightRule rule; 108 | 109 | rule.format = commnetFormat; 110 | 111 | // //dada 112 | rule.pattern = QRegExp("\\/\\/.*$"); 113 | highlightRules.append(rule); 114 | } 115 | 116 | void Highlighter::addMultiLineCommentFormat(const QString &text) 117 | { 118 | setCurrentBlockState(0); 119 | 120 | // /* 121 | QRegExp commentStartRegExp("/\\*"); 122 | // */ 123 | QRegExp commentEndRegExp("\\*/"); 124 | 125 | //高亮格式 126 | QTextCharFormat multiLineCommentFormat; 127 | multiLineCommentFormat.setForeground(Qt::darkGreen); 128 | multiLineCommentFormat.setFontItalic(true); 129 | 130 | int startIndex = 0; 131 | if(previousBlockState()!=1) 132 | startIndex= commentStartRegExp.indexIn(text); 133 | 134 | while(startIndex>=0){ 135 | int endIndex = commentEndRegExp.indexIn(text,startIndex); 136 | int commentLength = 0; 137 | if(endIndex==-1){//没有结束位置 138 | setCurrentBlockState(1); 139 | commentLength = text.length()-startIndex; 140 | }else{//有结束位置 141 | commentLength = endIndex-startIndex+commentEndRegExp.matchedLength(); 142 | } 143 | //设置格式 144 | setFormat(startIndex, 145 | commentLength, 146 | multiLineCommentFormat); 147 | startIndex = commentStartRegExp.indexIn(text,commentLength+startIndex); 148 | } 149 | } 150 | 151 | void Highlighter::addKeywordsFromat() 152 | { 153 | QFile file(":/config/config/keywords.txt"); 154 | QTextStream keywordsStream(&file); 155 | 156 | HighlightRule rule ; 157 | QTextCharFormat keywordsFormat; 158 | keywordsFormat.setForeground(Qt::darkYellow); 159 | rule.format = keywordsFormat; 160 | 161 | if(file.open(QIODevice::ReadOnly|QIODevice::Text)){ 162 | keywordsStream.seek(0); 163 | QString line ; 164 | while (!keywordsStream.atEnd()) { 165 | line = keywordsStream.readLine(); 166 | if(line!=""){ 167 | rule.pattern = QRegExp("\\b"+line+"\\b"); 168 | highlightRules.append(rule); 169 | } 170 | } 171 | file.close(); 172 | } 173 | } 174 | 175 | void Highlighter::addClassNameFormat() 176 | { 177 | HighlightRule rule; 178 | 179 | QTextCharFormat classNameFormat; 180 | classNameFormat.setForeground(QColor(150,20,100)); 181 | classNameFormat.setFontWeight(99); 182 | 183 | rule.format = classNameFormat; 184 | 185 | rule.pattern = QRegExp("\\b[A-Z]+\\w*"); 186 | highlightRules.append(rule); 187 | } 188 | 189 | void Highlighter::addFunctionFormat() 190 | { 191 | HighlightRule rule; 192 | 193 | QTextCharFormat functionFormat; 194 | functionFormat.setForeground(QColor(200,0,150)); 195 | 196 | rule.format = functionFormat; 197 | 198 | rule.pattern = QRegExp("\\w+\\("); 199 | highlightRules.append(rule); 200 | rule.pattern = QRegExp("\\)"); 201 | highlightRules.append(rule); 202 | } 203 | 204 | 205 | 206 | //按行来传入的 207 | void Highlighter::highlightBlock(const QString &text) 208 | { 209 | QRegExp regExp; 210 | foreach (const HighlightRule &rule, highlightRules) { 211 | regExp=rule.pattern; 212 | int index = regExp.indexIn(text); 213 | while(index>=0){ 214 | int length =regExp.matchedLength(); 215 | QTextCharFormat format = rule.format; 216 | format.setFont(QFont(mFontFamily,mFontSize)); 217 | setFormat(index,length,format); 218 | index = regExp.indexIn(text,index+length); 219 | } 220 | } 221 | 222 | //对于多行注释 223 | addMultiLineCommentFormat(text); 224 | } 225 | 226 | 227 | -------------------------------------------------------------------------------- /src/ui/instmonitor.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include "instmonitor.h" 5 | #include "disasm.h" 6 | 7 | InstMonitor::InstMonitor(QWidget *parent) 8 | :QWidget(parent) 9 | { 10 | last_pc = 0x80000000; 11 | 12 | initTitle(); 13 | initTableWidget(); 14 | 15 | QVBoxLayout * instMemVLayout = new QVBoxLayout(this); 16 | instMemVLayout->setMargin(0); 17 | instMemVLayout->setSpacing(0); 18 | 19 | instMemVLayout->addWidget(instMemLabel); 20 | instMemVLayout->addWidget(instTableWidget); 21 | 22 | connect(instTableWidget, &QTableWidget::cellDoubleClicked, this, &InstMonitor::setMemBreakpoint); 23 | } 24 | 25 | InstMonitor::~InstMonitor() 26 | { 27 | 28 | } 29 | 30 | void InstMonitor::initTitle() 31 | { 32 | instMemLabel = new QLabel(this); 33 | 34 | instMemLabel->setIndent(5); 35 | instMemLabel->setMinimumHeight(25); 36 | 37 | QPalette palette; 38 | palette.setColor(QPalette::Background,QColor(250,250,250)); 39 | instMemLabel->setPalette(palette); 40 | instMemLabel->setAutoFillBackground(true); 41 | 42 | instMemLabel->setText("Instruct Memory Monitor"); 43 | instMemLabel->setAlignment(Qt::AlignCenter); 44 | instMemLabel->setMaximumHeight(50); 45 | } 46 | 47 | void InstMonitor::initTableWidget() 48 | { 49 | instTableWidget = new QTableWidget(this); 50 | 51 | instTableWidget->setColumnCount(4); 52 | // 53 | instTableWidget->setEditTriggers(QAbstractItemView::NoEditTriggers); 54 | // 设置表格显示网格线 55 | instTableWidget->setShowGrid(false); 56 | // 禁用选择功能 57 | instTableWidget->setSelectionMode(QAbstractItemView::NoSelection); 58 | instTableWidget->horizontalHeader()->setSectionResizeMode(QHeaderView::Stretch); 59 | // instTableWidget->verticalHeader()->setSectionResizeMode(QHeaderView::Stretch); 60 | 61 | // 设置表头标签 62 | instTableWidget->setHorizontalHeaderLabels(QStringList() << "" << "Addr" << "Value" << "Asm"); 63 | // 设置水平表头的高度 64 | instTableWidget->horizontalHeader()->setFixedHeight(50); // 设置表头高度为 50 像素 65 | instTableWidget->horizontalHeader()->setSectionResizeMode(0, QHeaderView::ResizeToContents); 66 | // instTableWidget->horizontalHeader()->resizeSection(1, QHeaderView::ResizeToContents); 67 | 68 | QFont headerFontMem = instTableWidget->horizontalHeader()->font(); 69 | headerFontMem.setPointSize(16); // 设置字体大小 70 | instTableWidget->horizontalHeader()->setFont(headerFontMem); 71 | 72 | // 设置样式表,使鼠标悬浮时高亮 73 | instTableWidget->setStyleSheet( 74 | "QTableWidget::item:hover {" 75 | " background-color: lightblue;" // 悬浮时的背景色 76 | "}" 77 | "QTableWidget::item:selected {" 78 | " background-color: white;" // 取消单击后的高亮 79 | " color:black;" 80 | "}" 81 | ); 82 | } 83 | 84 | void InstMonitor::setFont(QString fontFamily, int fontSize) 85 | { 86 | instTableWidget->setFont(QFont(fontFamily,fontSize+3)); 87 | instMemLabel->setFont(QFont(fontFamily,fontSize+6)); 88 | } 89 | 90 | void InstMonitor::InitInstMonitor(unsigned int * vmem, int inst_num) 91 | { 92 | int i = 0; 93 | instTableWidget->setRowCount(inst_num);// 设置行数 94 | while(1) 95 | { 96 | if(i==inst_num) 97 | break; 98 | QString addr = QString::number(0x80000000+i*4, 16).toUpper(); 99 | QTableWidgetItem *item_pc = new QTableWidgetItem("0x"+addr); 100 | item_pc->setTextAlignment(Qt::AlignCenter); // 文本居中 101 | instTableWidget->setItem(i, 1, item_pc); 102 | 103 | QString inst = QString("%1").arg(vmem[i], 8, 16, QChar('0')).toUpper(); 104 | QTableWidgetItem *item_inst = new QTableWidgetItem("0x"+inst); 105 | item_inst->setTextAlignment(Qt::AlignCenter); // 文本居中 106 | instTableWidget->setItem(i, 2, item_inst); 107 | 108 | char p[50]; 109 | disassemble(p, 50, 0x80000000+i*4, (uint8_t *)&vmem[i], 4); 110 | QTableWidgetItem *item_asm = new QTableWidgetItem(p); 111 | item_asm->setTextAlignment(Qt::AlignCenter); // 文本居中 112 | instTableWidget->setItem(i, 3, item_asm); 113 | instTableWidget->setRowHeight(i, 50); 114 | i++; 115 | } 116 | } 117 | 118 | // receive pc values and set the monitor to highlight the corresponding pc values 119 | void InstMonitor::receiveNPCInfo(unsigned int pc) 120 | { 121 | for (int col = 1; col < instTableWidget->columnCount(); ++col) { 122 | QTableWidgetItem *item = instTableWidget->item((last_pc-0x80000000)/4, col); 123 | if (item) { 124 | item->setBackground(QColor(Qt::white)); // 设置背景为白色 125 | } 126 | } 127 | for (int col = 1; col < instTableWidget->columnCount(); ++col) { 128 | QTableWidgetItem *item = instTableWidget->item((pc-0x80000000)/4, col); 129 | if (item) { 130 | item->setBackground(QColor(Qt::green)); 131 | instTableWidget->scrollToItem(item, QAbstractItemView::PositionAtCenter); 132 | } 133 | } 134 | last_pc = pc; 135 | } 136 | 137 | void InstMonitor::setMemBreakpoint(int row, int column) 138 | { 139 | for(int i = 0; i <= mem_breakpoint.size(); ++i) 140 | { 141 | QPair pair = mem_breakpoint.at(i); 142 | if(pair.first == row && pair.second == column) 143 | { 144 | mem_breakpoint.removeAt(i); 145 | // 获取指定单元格中的QWidge 146 | QWidget* cellWidget = instTableWidget->cellWidget(row, 0); 147 | if (cellWidget) { 148 | QLabel* label = qobject_cast(cellWidget); 149 | if (label) { 150 | label->clear(); 151 | } 152 | // std::cout << row << std::endl; 153 | // delete label; 154 | } 155 | else { 156 | std::cout << "Failed to load image!"; 157 | } 158 | return; 159 | } 160 | } 161 | mem_breakpoint.append(qMakePair(row, column)); 162 | 163 | QPixmap pixmap(":/images/images/breakpoint.png"); // 使用qrc中的路径 164 | // 调整图片的大小为tablewidget的高,保持图像的长宽比 165 | pixmap = pixmap.scaled(instTableWidget->rowHeight(row), instTableWidget->rowHeight(row), Qt::KeepAspectRatio); 166 | // 创建一个QLabel并设置标签文本 167 | QLabel *label = new QLabel; 168 | label->setPixmap(pixmap); // 将图片显示在QLabel上 169 | // 将QLabel放置到指定的单元格 170 | instTableWidget->setCellWidget(row, 0, label); 171 | 172 | // if (!pixmap.isNull()) { 173 | // // 获取指定单元格中的QWidget 174 | // QWidget* cellWidget = this->cellWidget(row, 0); 175 | // if (cellWidget) { 176 | // QLabel* label = qobject_cast(cellWidget); 177 | // if (label) { 178 | // label->setPixmap(pixmap); // 将图片显示在QLabel上 179 | // } 180 | // } 181 | // } 182 | // else { 183 | // std::cout << "Failed to load image!"; 184 | // } 185 | } 186 | 187 | void InstMonitor::receiveDiffError() 188 | { 189 | QPixmap pixmap(":/images/images/triggerbp.png"); // 使用qrc中的路径 190 | // 调整图片的大小为tablewidget的高,保持图像的长宽比 191 | pixmap = pixmap.scaled(instTableWidget->rowHeight(0), instTableWidget->rowHeight(0), Qt::KeepAspectRatio); 192 | 193 | if (!pixmap.isNull()) { 194 | // 获取指定单元格中的QWidget 195 | QWidget* cellWidget = instTableWidget->cellWidget((last_pc-0x80000000)/4, 0); 196 | if (cellWidget) { 197 | QLabel* label = qobject_cast(cellWidget); 198 | if (label) { 199 | label->setPixmap(pixmap); // 将图片显示在QLabel上 200 | } 201 | } 202 | } 203 | else { 204 | std::cout << "Failed to load image!"; 205 | } 206 | } 207 | -------------------------------------------------------------------------------- /src/ui/mainwindow.cpp: -------------------------------------------------------------------------------- 1 | #include "mainwindow.h" 2 | #include "ui_mainwindow.h" 3 | 4 | #include "main.h" 5 | #include "reg.h" 6 | 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | 17 | #if defined(QT_PRINTSUPPORT_LIB) 18 | #include 19 | #if QT_CONFIG(printer) 20 | #if QT_CONFIG(printdialog) 21 | #include 22 | #endif 23 | #include 24 | #endif 25 | #endif 26 | 27 | MainWindow::MainWindow(int argc, char **argv, QWidget *parent) 28 | : QMainWindow(parent) 29 | , ui(new Ui::MainWindow) 30 | , mFontFamily("Consolas") 31 | , mFontSize(14) 32 | , mSplitterLayout(0) 33 | { 34 | ui->setupUi(this); 35 | mSettings = new QSettings("settings.ini",QSettings::IniFormat); 36 | mDir = mSettings->value("config/dir","E:/").toString(); 37 | 38 | //初始化菜单 39 | initMenu(); 40 | 41 | //初始化字体 42 | initFont(); 43 | 44 | //初始化动作 45 | initAction(0); 46 | 47 | mSplitterLayout = new SplitterLayout(this,mDir,mFontFamily,mFontSize); 48 | 49 | connect(mSplitterLayout,SIGNAL(finishCreateTab(const QString &)),this,SLOT(onFinishCreateTab(const QString &))); 50 | connect(ui->actionruntocomp, &QAction::triggered, this, &MainWindow::exec); 51 | connect(ui->actionstep, &QAction::triggered, this, &MainWindow::execOne); 52 | connect(ui->debug, &QAction::toggled, this, &MainWindow::isDebugMode); 53 | 54 | // 创建一个布局并将 QSplitter 添加到布局中 55 | QVBoxLayout *layout = new QVBoxLayout(ui->page); 56 | layout->addWidget(mSplitterLayout); 57 | 58 | connect(ui->listWidget, &QListWidget::itemClicked, this, &MainWindow::onItemClicked); 59 | 60 | #if !QT_CONFIG(printer) 61 | ui->print->setEnabled(false); 62 | #endif 63 | 64 | } 65 | 66 | MainWindow::~MainWindow() 67 | { 68 | 69 | } 70 | 71 | void MainWindow::initFont(){ 72 | mFontFamily = mSettings->value("config/font_family","Consolas").toString(); 73 | mFontSize = mSettings->value("config/font_size",14).toInt(); 74 | } 75 | 76 | void MainWindow::initAction(int tabCount) 77 | { 78 | bool valid =tabCount>0; 79 | ui->save_file->setEnabled(valid); 80 | ui->save_as->setEnabled(valid); 81 | ui->copy->setEnabled(valid); 82 | ui->paste->setEnabled(valid); 83 | ui->cut->setEnabled(valid); 84 | ui->undo->setEnabled(valid); 85 | ui->redo->setEnabled(valid); 86 | ui->actionstep->setEnabled(valid); 87 | ui->actionstepfunc->setEnabled(valid); 88 | } 89 | 90 | //初始化菜单 91 | void MainWindow::initMenu() 92 | { 93 | //获取Menu 94 | QMenu * recent = this->findChild("recent"); 95 | //获取Action 96 | QList chLists =recent->children(); 97 | foreach(QObject * ch,chLists){ 98 | QAction *action = (QAction *)ch; 99 | //清空子菜单Action 100 | recent->removeAction(action); 101 | } 102 | 103 | QList lists = getHistory(); 104 | 105 | 106 | for(int i=lists.size()-1 ;i>=0;i--){ 107 | //生成子菜单Action 108 | recent->addAction(lists[i],this,&MainWindow::on_open_rencent_file); 109 | } 110 | 111 | if(lists.size()>0){ 112 | recent->addAction("清除历史记录",this,&MainWindow::on_clear_history_triggered,QKeySequence("Ctrl+Alt+Shift+C")); 113 | } 114 | 115 | } 116 | 117 | 118 | //获取历史记录 119 | QList MainWindow::getHistory(){ 120 | //打开开始读 121 | int size =mSettings->beginReadArray("history"); 122 | 123 | //创建返回对象 124 | QList lists; 125 | for(int i = 0;isetArrayIndex(i); 127 | QString path = mSettings->value("path").toString(); 128 | lists.append(path); 129 | } 130 | //关闭读 131 | mSettings->endArray(); 132 | 133 | return lists; 134 | } 135 | 136 | 137 | //保存打开历史记录 138 | void MainWindow::saveHistory(QString path){ 139 | 140 | //获取历史 141 | QList lists = getHistory(); 142 | foreach(QString str,lists){ 143 | if(str==path){ 144 | lists.removeOne(str); 145 | } 146 | } 147 | lists.append(path); 148 | 149 | //打开开始写入 150 | mSettings->beginWriteArray("history"); 151 | for(int i =0;isetArrayIndex(i); 153 | //保存字符串 154 | mSettings->setValue("path",lists[i]); 155 | } 156 | 157 | //关闭开始写入 158 | mSettings->endArray(); 159 | } 160 | 161 | void MainWindow::receiveImageFromNPC(const QImage &image) 162 | { 163 | QPixmap pix = QPixmap::fromImage(image).scaled(ui->label_2->size()); 164 | ui->label_2->setPixmap(pix); 165 | } 166 | 167 | //新建文件 168 | void MainWindow::on_new_file_triggered() 169 | { 170 | mSplitterLayout->getTreeView()->newFile(); 171 | 172 | } 173 | 174 | 175 | //打开最近文件 176 | void MainWindow::on_open_rencent_file() 177 | { 178 | mSplitterLayout->createTab(((QAction *)sender())->text()); 179 | } 180 | 181 | //打开文件 182 | void MainWindow::on_open_dir_triggered() 183 | { 184 | QString dirFromSetttings = mSettings->value("dir",mDir).toString(); 185 | QString dir = QFileDialog::getExistingDirectory(this,"选择文件夹",dirFromSetttings,QFileDialog::ShowDirsOnly); 186 | if(dir.isEmpty()) return; 187 | mSettings->setValue("config/dir",dir); 188 | mDir = dir; 189 | mSplitterLayout->setDir(mDir); 190 | // setTreeViewModel(); 191 | mSplitterLayout->getLabel()->setText(mDir); 192 | } 193 | 194 | 195 | //保存文件 196 | void MainWindow::on_save_file_triggered() 197 | { 198 | //把保存交给CodeEditor 199 | CodeEditor *codeEditor = (CodeEditor* )mSplitterLayout->getTabWidget()->currentWidget(); 200 | if(codeEditor){ 201 | if(codeEditor->saveFile()){ 202 | saveSuccessAction(codeEditor); 203 | } 204 | } 205 | } 206 | 207 | //另存为 208 | void MainWindow::on_save_as_triggered() 209 | { 210 | //把另存为交给CodeEditor 211 | CodeEditor *codeEditor = (CodeEditor* )mSplitterLayout->getTabWidget()->currentWidget(); 212 | if(codeEditor){ 213 | if(codeEditor->saveAsFile()){ 214 | saveSuccessAction(codeEditor); 215 | } 216 | } 217 | } 218 | 219 | //复制 220 | void MainWindow::on_copy_triggered() 221 | { 222 | //把复制交给CodeEditor 223 | CodeEditor *codeEditor = (CodeEditor* )mSplitterLayout->getTabWidget()->currentWidget(); 224 | if(codeEditor){ 225 | codeEditor->copy(); 226 | } 227 | } 228 | 229 | //粘贴 230 | void MainWindow::on_paste_triggered() 231 | { 232 | //把粘贴交给CodeEditor 233 | CodeEditor *codeEditor = (CodeEditor* )mSplitterLayout->getTabWidget()->currentWidget(); 234 | if(codeEditor){ 235 | codeEditor->paste(); 236 | } 237 | } 238 | 239 | //剪切 240 | void MainWindow::on_cut_triggered() 241 | { 242 | //把剪切交给CodeEditor 243 | CodeEditor *codeEditor = (CodeEditor* )mSplitterLayout->getTabWidget()->currentWidget(); 244 | if(codeEditor){ 245 | codeEditor->cut(); 246 | } 247 | } 248 | 249 | //撤销 250 | void MainWindow::on_undo_triggered() 251 | { 252 | //把撤销交给CodeEditor 253 | CodeEditor *codeEditor = (CodeEditor* )mSplitterLayout->getTabWidget()->currentWidget(); 254 | if(codeEditor){ 255 | codeEditor->undo(); 256 | } 257 | } 258 | 259 | //取消撤销 260 | void MainWindow::on_redo_triggered() 261 | { 262 | //把取消撤销交给CodeEditor 263 | CodeEditor *codeEditor = (CodeEditor* )mSplitterLayout->getTabWidget()->currentWidget(); 264 | if(codeEditor){ 265 | codeEditor->redo(); 266 | } 267 | } 268 | 269 | //字体 270 | void MainWindow::on_font_triggered() 271 | { 272 | bool fontSelected; 273 | QFont font = QFontDialog::getFont(&fontSelected,QFont(mFontFamily,mFontSize),this); 274 | if(fontSelected){ 275 | mSplitterLayout->setFont(QFont(font.family(),font.pointSize())); 276 | mSettings->setValue("config/font_family",font.family()); 277 | mSettings->setValue("config/font_size",font.pointSize()); 278 | } 279 | } 280 | 281 | //打印 282 | void MainWindow::on_print_triggered() 283 | { 284 | //把打印交给CodeEditor 285 | CodeEditor *codeEditor = (CodeEditor* )mSplitterLayout->getTabWidget()->currentWidget(); 286 | if(codeEditor){ 287 | #if defined(QT_PRINTSUPPORT_LIB) && QT_CONFIG(printer) 288 | QPrinter printDev; 289 | #if QT_CONFIG(printdialog) 290 | QPrintDialog dialog(&printDev,this); 291 | if(dialog.exec()==QDialog::Rejected) 292 | return; 293 | #endif 294 | codeEditor->print(&printDev); 295 | #endif 296 | } 297 | } 298 | 299 | //关于 300 | void MainWindow::on_about_triggered() 301 | { 302 | QMessageBox::about(this,"This is a IDE","this is a IDE, welcom to use"); 303 | } 304 | 305 | 306 | //退出 307 | void MainWindow::on_exit_triggered() 308 | { 309 | monitor->stop(); 310 | onDestroyWindow(); 311 | } 312 | 313 | 314 | void MainWindow::on_clear_history_triggered() 315 | { 316 | mSettings->remove("history"); 317 | initMenu(); 318 | } 319 | 320 | void MainWindow::saveSuccessAction( CodeEditor * codeEditor) 321 | { 322 | QString fileName = codeEditor->getFileName(); 323 | //保存历史 324 | saveHistory(fileName); 325 | //设置tab标题 326 | mSplitterLayout->getTabWidget()->setTabText(mSplitterLayout->getTabWidget()->currentIndex(),fileName); 327 | //初始化菜单 328 | initMenu(); 329 | } 330 | 331 | 332 | void MainWindow::closeEvent(QCloseEvent *event) 333 | { 334 | monitor->stop(); 335 | 336 | if(mSplitterLayout->getTabWidget()->count()>0){ 337 | if(mSplitterLayout->getTabWidget()->count() == 1) 338 | { 339 | // 获取当前选中的 tab 的索引 340 | int currentIndex = mSplitterLayout->getTabWidget()->currentIndex(); 341 | // 获取当前 tab 标签上的文本 342 | QString currentTabLabel = mSplitterLayout->getTabWidget()->tabText(currentIndex); 343 | if(currentTabLabel == "Debugging") 344 | { 345 | onDestroyWindow(); 346 | return; 347 | 348 | } 349 | } 350 | QMessageBox::question(this, 351 | "warnning", 352 | "Are you sure you want to close the unsaved files?", 353 | QMessageBox::Yes|QMessageBox::No)==QMessageBox::Yes?event->accept():event->ignore(); 354 | } 355 | onDestroyWindow(); 356 | } 357 | 358 | void MainWindow::onFinishCreateTab(const QString &filePath) 359 | { 360 | saveHistory(filePath); 361 | initMenu(); 362 | initAction(mSplitterLayout->getTabWidget()->count()); 363 | } 364 | 365 | void MainWindow::onItemClicked(QListWidgetItem *item) 366 | { 367 | Q_UNUSED(item) 368 | 369 | // 判断点击了哪一个 QListWidget 370 | if (ui->listWidget->currentRow() != -1) 371 | { 372 | ui->stackedWidget->setCurrentIndex(ui->listWidget->currentRow()); 373 | } 374 | } 375 | 376 | void MainWindow::onDestroyWindow() 377 | { 378 | this->deleteLater(); 379 | } 380 | 381 | void MainWindow::init(unsigned int * vmem_addr, int inst_num) 382 | { 383 | mSplitterLayout->splitterlayoutInit(vmem_addr, inst_num); 384 | mSplitterLayout->showSourceFromElf(QString::fromStdString(monitor->ftrace->src)); 385 | } 386 | 387 | void MainWindow::exec() 388 | { 389 | // mNPC->exec(-1); 390 | mNPC->start(); 391 | } 392 | 393 | void MainWindow::execOne() 394 | { 395 | for(int i = 0; i < mSplitterLayout->srcMapInst.size(); ++i){ 396 | 397 | QPair pair = mSplitterLayout->srcMapInst.at(i); 398 | if(pair.second == riscv32_reg->pc) 399 | { 400 | mSplitterLayout->showSrcMapInst(pair.first+1); 401 | } 402 | } 403 | mNPC->exec(1); 404 | } 405 | 406 | void MainWindow::isDebugMode(bool checked) 407 | { 408 | if(checked) 409 | { 410 | mNPC->debug_flag = true; 411 | qDebug() << "debug"; 412 | ui->actionstep->setEnabled(true); 413 | ui->actionstepfunc->setEnabled(true); 414 | } 415 | else 416 | { 417 | mNPC->debug_flag = false; 418 | qDebug() << "no debug"; 419 | ui->actionstep->setEnabled(false); 420 | ui->actionstepfunc->setEnabled(false); 421 | } 422 | } -------------------------------------------------------------------------------- /src/ui/memviewer.cpp: -------------------------------------------------------------------------------- 1 | #include "memviewer.h" 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | MemViewer::MemViewer(QWidget *parent): 8 | QWidget(parent) 9 | { 10 | // 设置正则表达式验证器,允许输入整数和以0x开头的十六进制数 11 | QRegularExpression regex("^(0x[0-9A-Fa-f]+|[0-9]+)$"); // 允许以 0x 开头的十六进制数和十进制整数 12 | QRegularExpressionValidator *validator = new QRegularExpressionValidator(regex, this); 13 | 14 | dataMemLabel = initLabel("Data Memory Monitor"); 15 | dataMemLabel ->setAlignment(Qt::AlignCenter); 16 | dataMemLabel ->setMaximumHeight(50); 17 | 18 | // QWidget * dataMemLayoutWidget = new QWidget(parent); 19 | QWidget * dataInputLayoutWidget = new QWidget(); 20 | QHBoxLayout * dataInputHLayout = new QHBoxLayout(dataInputLayoutWidget); 21 | dataInputHLayout->setMargin(0); 22 | dataInputHLayout->setSpacing(0); 23 | 24 | start_address =initLabel("Start Address:"); 25 | start_address ->setAlignment(Qt::AlignCenter); 26 | start_address ->setMaximumHeight(50); 27 | 28 | addressLineEdit = new QLineEdit(); 29 | addressLineEdit ->setPlaceholderText("0x80000000"); 30 | addressLineEdit->setValidator(validator); 31 | QFont fontAddr = addressLineEdit->font(); 32 | fontAddr.setPointSize(16); // 设置字体大小为 14 33 | addressLineEdit->setFont(fontAddr); 34 | addressLineEdit->setMinimumHeight(30); // 设置最小高度为 30 像素 35 | 36 | offset =initLabel("Offset:"); 37 | offset ->setAlignment(Qt::AlignCenter); 38 | offset ->setMaximumHeight(50); 39 | 40 | offsetLineEdit = new QLineEdit(); 41 | offsetLineEdit ->setPlaceholderText("10"); 42 | offsetLineEdit->setValidator(validator); 43 | QFont fontOffset = offsetLineEdit->font(); 44 | fontOffset.setPointSize(16); // 设置字体大小为 14 45 | offsetLineEdit->setFont(fontOffset); 46 | offsetLineEdit->setMinimumHeight(30); // 设置最小高度为 30 像素 47 | 48 | dataMemFindbutton = new QPushButton("Find"); 49 | dataMemFindbutton->setMinimumHeight(30); 50 | 51 | dataInputHLayout->addWidget(start_address); 52 | dataInputHLayout->addWidget(addressLineEdit); 53 | dataInputHLayout->addWidget(offset); 54 | dataInputHLayout->addWidget(offsetLineEdit); 55 | dataInputHLayout->addWidget(dataMemFindbutton); 56 | 57 | QVBoxLayout * dataMemVLayout = new QVBoxLayout(this); 58 | dataMemVLayout->setMargin(0); 59 | dataMemVLayout->setSpacing(0); 60 | 61 | //data memory table 62 | dataMemTableWidget = new QTableWidget(); 63 | InitTableWidget(); 64 | 65 | dataMemVLayout->addWidget(dataMemLabel); 66 | dataMemVLayout->addWidget(dataInputLayoutWidget); 67 | dataMemVLayout->addWidget(dataMemTableWidget); 68 | connect(dataMemFindbutton, &QPushButton::clicked, this, &MemViewer::findDataMemToUI); 69 | } 70 | 71 | MemViewer::~MemViewer() 72 | { 73 | 74 | } 75 | 76 | QLabel * MemViewer::initLabel(QString name) 77 | { 78 | QLabel * label = new QLabel(); 79 | //设置label 80 | label->setText(name); 81 | label->setIndent(5); 82 | label->setMinimumHeight(25); 83 | QPalette palette; 84 | palette.setColor(QPalette::Background,QColor(250,250,250)); 85 | label->setPalette(palette); 86 | label->setAutoFillBackground(true); 87 | return label; 88 | } 89 | 90 | void MemViewer::InitTableWidget() 91 | { 92 | dataMemTableWidget->setRowCount(10);// 设置行数和列数 93 | dataMemTableWidget->setColumnCount(5); 94 | dataMemTableWidget->setEditTriggers(QAbstractItemView::NoEditTriggers); 95 | // 设置表格显示网格线 96 | dataMemTableWidget->setShowGrid(false); 97 | // 禁用选择功能 98 | // this->setSelectionMode(QAbstractItemView::NoSelection); 99 | dataMemTableWidget->horizontalHeader()->setSectionResizeMode(QHeaderView::Stretch); 100 | // this->verticalHeader()->setSectionResizeMode(QHeaderView::Stretch); 101 | 102 | // 设置表头标签 103 | dataMemTableWidget->setHorizontalHeaderLabels(QStringList() << "Addr" << "0" << "1" << "2" << "3"); 104 | // 设置水平表头的高度 105 | dataMemTableWidget->horizontalHeader()->setFixedHeight(50); // 设置表头高度为 50 像素 106 | QFont headerFontMem = dataMemTableWidget->horizontalHeader()->font(); 107 | headerFontMem.setPointSize(16); // 设置字体大小 108 | dataMemTableWidget->horizontalHeader()->setFont(headerFontMem); 109 | } 110 | 111 | void MemViewer::initVMem(uint8_t * vmem) 112 | { 113 | vmem_addr = vmem; 114 | } 115 | 116 | void MemViewer::setFont(QString fontFamily, int fontSize) 117 | { 118 | dataMemTableWidget->setFont(QFont(fontFamily, fontSize)); 119 | dataMemLabel->setFont(QFont(fontFamily,fontSize)); 120 | start_address->setFont(QFont(fontFamily,fontSize)); 121 | offset->setFont(QFont(fontFamily,fontSize)); 122 | } 123 | 124 | void MemViewer::findDataMemToUI() 125 | { 126 | QString temp = addressLineEdit->text(); 127 | temp.remove(0, 2); 128 | bool ok; 129 | unsigned int addr_val = temp.toUInt(&ok, 16); 130 | temp = offsetLineEdit->text(); 131 | unsigned int offset = temp.toUInt(); 132 | dataMemTableWidget->setRowCount(offset); 133 | unsigned int start_addr = (addr_val - 0x80000000)/2; 134 | if(addr_val < 0x80000000 || addr_val > 0x88000000) 135 | { 136 | QMessageBox::critical(nullptr, "Error", "physical memory area [ 0x80000000 , 0x88000000 ]"); 137 | return; 138 | } 139 | for(int i=0; isetTextAlignment(Qt::AlignCenter); // 文本居中 144 | 145 | dataMemTableWidget->setItem(i, 0, item_addr); 146 | for(int j=1; j<5; j++) 147 | { 148 | QString mem_dat = QString("%1").arg(vmem_addr[start_addr+i*4+(j-1)], 2, 16, QChar('0')).toUpper(); 149 | QTableWidgetItem *item_dat = new QTableWidgetItem(mem_dat); 150 | item_dat->setTextAlignment(Qt::AlignCenter); // 文本居中 151 | dataMemTableWidget->setItem(i, j, item_dat); 152 | } 153 | dataMemTableWidget->setRowHeight(i, 30); 154 | } 155 | } -------------------------------------------------------------------------------- /src/ui/splitterlayout.cpp: -------------------------------------------------------------------------------- 1 | #include "codeeditor.h" 2 | #include "splitterlayout.h" 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | SplitterLayout::SplitterLayout(QWidget *parent,QString dir,QString fontFamily,int fontSize ) 9 | :QSplitter(parent) 10 | ,mFontFamily(fontFamily) 11 | ,mFontSize(fontSize) 12 | ,mDir(dir) 13 | 14 | { 15 | last_lineNumber = 0; 16 | 17 | //file directory tree 18 | pathLabel = createLabel(); 19 | mTreeView =createTreeView(); 20 | QWidget * vLayoutWidget = new QWidget(this); 21 | mVLayout =createVLayout(vLayoutWidget); 22 | mVLayout->addWidget(pathLabel); 23 | mVLayout->addWidget(mTreeView); 24 | 25 | //instruct memory tablewidget 26 | instMemWidget = new InstMonitor(this); 27 | dataMemLayoutWidget = new MemViewer(this); 28 | dataMemSplitter = new QSplitter(Qt::Vertical); 29 | 30 | dataMemSplitter ->addWidget(instMemWidget); 31 | dataMemSplitter ->addWidget(dataMemLayoutWidget); 32 | dataMemSplitter ->setHandleWidth(0); 33 | 34 | instMemSplitter = new QSplitter(Qt::Horizontal); 35 | // file edit region 36 | fileLabelTabWidget =createTabWidget(); 37 | instMemSplitter->addWidget(fileLabelTabWidget); 38 | instMemSplitter->addWidget(dataMemSplitter); 39 | instMemSplitter->setHandleWidth(0); 40 | 41 | gprWidget = new GPRMonitor(this); 42 | 43 | regSplitter = new QSplitter(Qt::Vertical); 44 | regSplitter->addWidget(instMemSplitter); 45 | regSplitter->addWidget(gprWidget); 46 | regSplitter->setHandleWidth(0); 47 | 48 | instMemSplitter->setStretchFactor(0,250); 49 | instMemSplitter->setStretchFactor(1,1); 50 | dataMemSplitter->setStretchFactor(0,5); 51 | dataMemSplitter->setStretchFactor(1,2); 52 | regSplitter->setStretchFactor(0,5); 53 | regSplitter->setStretchFactor(1,2); 54 | 55 | addWidget(vLayoutWidget); 56 | addWidget(regSplitter); 57 | //设置分割比距比例 58 | QList sizeLists; 59 | sizeLists<<1000<<4000; 60 | setSizes(sizeLists); 61 | setHandleWidth(0); 62 | } 63 | 64 | void SplitterLayout::createTab(const QString &filePath) 65 | { 66 | QFile file(filePath); 67 | if(!file.open(QIODevice::ReadOnly|QFile::Text)){ 68 | QMessageBox::warning(this,"警告","无法打开此文件:"+file.errorString()); 69 | return; 70 | } 71 | 72 | QTextStream in(&file); 73 | QString text = in.readAll(); 74 | 75 | 76 | int tabCount= fileLabelTabWidget->count(); 77 | for(int index =0;indextabText(index); 79 | if(fileLabelTabWidget->tabText(index)==filePath){ 80 | return; 81 | } 82 | } 83 | 84 | //创建对象 85 | CodeEditor * codeEditor = new CodeEditor(this,QFont(mFontFamily,mFontSize)); 86 | codeEditor->setPlainText(text); 87 | 88 | //设置文件名 89 | codeEditor->setFileName(filePath); 90 | //添加tab 91 | fileLabelTabWidget->addTab(codeEditor,filePath); 92 | //设置当前索引 93 | fileLabelTabWidget->setCurrentIndex(fileLabelTabWidget->count()-1); 94 | 95 | file.close(); 96 | 97 | emit finishCreateTab(filePath); 98 | 99 | } 100 | 101 | #include 102 | #include 103 | 104 | void SplitterLayout::showSourceFromElf(QString src) 105 | { 106 | int line_num = 0; 107 | // 按行分割字符串 108 | QStringList lines = src.split("\n"); 109 | // 正则表达式匹配以数字开头的行 110 | QRegExp regex("^[0-9a-fA-F]{8}.*"); 111 | 112 | // 筛选不匹配的行 113 | QStringList filteredLines; 114 | 115 | for (int i = 0; i < lines.size(); ++i) { 116 | if (!regex.exactMatch(lines[i])) { 117 | if((lines.size()>(i+1)) && (!lines[i].trimmed().isEmpty()) && regex.exactMatch(lines[i+1])) 118 | { 119 | bool ok; 120 | QString firstEightChars = lines[i+1].left(8); 121 | firstEightChars = QString("0x%1").arg(firstEightChars); 122 | // qDebug() << firstEightChars; 123 | unsigned int addr_val = firstEightChars.toUInt(&ok, 16); 124 | srcMapInst.append(qMakePair(line_num, addr_val)); 125 | } 126 | 127 | line_num += 1; 128 | filteredLines.append(lines[i]); 129 | } 130 | } 131 | 132 | // 将过滤后的行重新连接为一个字符串 133 | QString filteredText = filteredLines.join("\n"); 134 | 135 | 136 | //创建对象 137 | debugEditor = new CodeEditor(this,QFont(mFontFamily,mFontSize)); 138 | debugEditor->setPlainText(filteredText); 139 | debugEditor->setReadOnly(true); 140 | //设置文件名 141 | debugEditor->setFileName("Debugging"); 142 | //添加tab 143 | fileLabelTabWidget->addTab(debugEditor,"Debugging"); 144 | //设置当前索引 145 | fileLabelTabWidget->setCurrentIndex(fileLabelTabWidget->count()-1); 146 | } 147 | 148 | void SplitterLayout::onDataChanged(const QString &preFilePath,const QString &filePath) 149 | { 150 | int count = fileLabelTabWidget->count(); 151 | for(int i = 0; itabText(i)){ 153 | fileLabelTabWidget->setTabText(i,filePath); 154 | CodeEditor * codeEditor =( CodeEditor *) fileLabelTabWidget->widget(i); 155 | if(codeEditor) 156 | codeEditor->setFileName(filePath); 157 | return; 158 | } 159 | } 160 | } 161 | 162 | TreeView *SplitterLayout::getTreeView() 163 | { 164 | return mTreeView; 165 | } 166 | 167 | QLabel *SplitterLayout::getLabel() 168 | { 169 | return pathLabel; 170 | } 171 | 172 | QTabWidget *SplitterLayout::getTabWidget() 173 | { 174 | return fileLabelTabWidget; 175 | } 176 | 177 | void SplitterLayout::setDir(const QString &dir) 178 | { 179 | mDir = dir; 180 | mTreeView->setDir(dir); 181 | pathLabel->setText(dir); 182 | } 183 | 184 | void SplitterLayout::setFont(const QFont &font) 185 | { 186 | mFontFamily = font.family(); 187 | mFontSize =font.pointSize(); 188 | pathLabel->setFont(QFont(mFontFamily,mFontSize)); 189 | instMemWidget->setFont(mFontFamily, mFontSize); 190 | gprWidget->setFont(mFontFamily,mFontSize); 191 | 192 | CodeEditor * codeEditor = (CodeEditor *)fileLabelTabWidget->currentWidget(); 193 | if(codeEditor) 194 | codeEditor->setAllFont(QFont(mFontFamily,mFontSize)); 195 | } 196 | 197 | 198 | QLabel *SplitterLayout::createLabel() 199 | { 200 | QLabel * label = new QLabel(this); 201 | //设置label 202 | label->setFont(QFont(mFontFamily,mFontSize)); 203 | label->setText(mDir); 204 | label->setIndent(5); 205 | label->setMinimumHeight(25); 206 | 207 | QPalette palette; 208 | palette.setColor(QPalette::Background,QColor(250,250,250)); 209 | label->setPalette(palette); 210 | label->setAutoFillBackground(true); 211 | 212 | return label; 213 | } 214 | 215 | TreeView *SplitterLayout::createTreeView() 216 | { 217 | TreeView * treeView = new TreeView(this,mDir); 218 | 219 | treeView->setFrameShape(QFrame::NoFrame); 220 | 221 | connect(treeView,SIGNAL(createTab(const QString &)),this,SLOT(createTab(const QString &))); 222 | 223 | connect(treeView,SIGNAL(onDataChanged(const QString & ,const QString &)),this,SLOT(onDataChanged(const QString & ,const QString &))); 224 | 225 | return treeView; 226 | } 227 | 228 | 229 | QVBoxLayout *SplitterLayout::createVLayout(QWidget *parent) 230 | { 231 | QVBoxLayout * vLayout = new QVBoxLayout(parent); 232 | 233 | vLayout->setMargin(0); 234 | vLayout->setSpacing(0); 235 | 236 | return vLayout; 237 | } 238 | 239 | QTabWidget *SplitterLayout::createTabWidget() 240 | { 241 | QTabWidget * tabWidget = new QTabWidget(this); 242 | 243 | tabWidget->setTabsClosable(true); 244 | tabWidget->setMovable(true); 245 | tabWidget->setDocumentMode(true); 246 | 247 | connect(tabWidget,SIGNAL(tabCloseRequested(int)),this,SLOT(onTabWidgetCloseRequested(int))); 248 | return tabWidget; 249 | } 250 | 251 | void SplitterLayout::onTabWidgetCloseRequested(int index) 252 | { 253 | CodeEditor * codeEditor = (CodeEditor*)fileLabelTabWidget->currentWidget(); 254 | if(!codeEditor->checkSaved()){ 255 | QMessageBox::StandardButton btn = QMessageBox::question(this,"警告","您还没有保存文档!是否保存?",QMessageBox::Yes|QMessageBox::No|QMessageBox::Cancel); 256 | 257 | if(btn ==QMessageBox::Yes){ 258 | if(codeEditor->saveFile()){ 259 | fileLabelTabWidget->setTabText(fileLabelTabWidget->currentIndex(),codeEditor->getFileName()); 260 | } 261 | return; 262 | }else if(btn ==QMessageBox::Cancel) 263 | return; 264 | } 265 | fileLabelTabWidget->removeTab(index); 266 | emit finishCreateTab(codeEditor->getFileName()); 267 | delete codeEditor; 268 | } 269 | 270 | void SplitterLayout::splitterlayoutInit(unsigned int * vmem, int inst_num) 271 | { 272 | instMemWidget->InitInstMonitor(vmem, inst_num); 273 | instMemWidget->setFont(mFontFamily, mFontSize); 274 | 275 | dataMemLayoutWidget->initVMem((uint8_t *)vmem); 276 | dataMemLayoutWidget->setFont(mFontFamily, mFontSize); 277 | 278 | gprWidget->initGPRMonitor(); 279 | gprWidget->setFont(mFontFamily, mFontSize); 280 | } 281 | 282 | void SplitterLayout::showSrcMapInst(int line_num) 283 | { 284 | qDebug() << line_num; 285 | // 取消所有行的高亮 286 | debugEditor->removeLastHighlights(last_lineNumber); 287 | debugEditor->highlightLine(line_num, Qt::green); 288 | last_lineNumber = line_num; 289 | } 290 | -------------------------------------------------------------------------------- /src/ui/treeview.cpp: -------------------------------------------------------------------------------- 1 | #include "codeeditor.h" 2 | #include "treeview.h" 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | 14 | TreeView::TreeView(QWidget * parent,QString dir) 15 | :QTreeView(parent) 16 | ,mFontFamily("Consolas") 17 | ,mFontSize(14) 18 | ,mFileSystemModel(0) 19 | ,mDir(dir) 20 | { 21 | //设置model 22 | setTreeViewModel(); 23 | 24 | //隐藏header 25 | setHeaderHidden(true); 26 | 27 | //设置右键菜单 28 | setContextMenuPolicy(Qt::CustomContextMenu); 29 | 30 | //添加connect 31 | //添加右键信号事件 32 | connect(this,SIGNAL(customContextMenuRequested(const QPoint &)),this,SLOT(showCustomContextMenu(const QPoint &))); 33 | 34 | //取消双击编辑 35 | setEditTriggers(QTreeView::NoEditTriggers); 36 | 37 | //绑定双击事件 38 | connect(this,SIGNAL(doubleClicked(const QModelIndex &)),this,SLOT(onTreeViewDoubleClicked(const QModelIndex &))); 39 | 40 | 41 | } 42 | 43 | void TreeView::newFile() 44 | { 45 | QModelIndex index = currentIndex(); 46 | QString filePath = mFileSystemModel->filePath(index); 47 | if(!mFileSystemModel->isDir(index)){ 48 | filePath = filePath.left(filePath.length()-mFileSystemModel->fileName(index).length()); 49 | } 50 | if(filePath.isEmpty()) return; 51 | QString fileName = filePath+(filePath.endsWith("/")?"":"/")+"新建文件"+QDateTime::currentDateTime().toString("yyyy-MM-dd hh-mm-ss")+".xjy"; 52 | QFile file(fileName); 53 | if(!file.open(QIODevice::ReadWrite)){ 54 | QMessageBox::critical(this,"失败","创建新文件失败!可能没有权限或文件已经存在!"); 55 | } 56 | file.close(); 57 | 58 | emit createTab(fileName); 59 | } 60 | 61 | void TreeView::setDir(const QString &dir) 62 | { 63 | mDir=dir; 64 | setTreeViewModel(); 65 | } 66 | 67 | //设置model 68 | void TreeView::setTreeViewModel() 69 | { 70 | if(mFileSystemModel) { 71 | delete mFileSystemModel; 72 | } 73 | //创建Model 74 | mFileSystemModel = new FileSystemModel(); 75 | //设置根目录 76 | mFileSystemModel->setRootPath(mDir); 77 | //设置Model 78 | setModel(mFileSystemModel); 79 | 80 | //设置根目录 81 | setRootIndex(mFileSystemModel->index(mDir)); 82 | 83 | //绑定dataChanged 84 | connect(mFileSystemModel,SIGNAL(dataChanged(const QModelIndex &, const QModelIndex &, const QVector &)),this,SLOT(onModelDataChanged(const QModelIndex &))); 85 | 86 | } 87 | 88 | //treeview的右键事件 89 | void TreeView::showCustomContextMenu(const QPoint &pos) 90 | { 91 | QModelIndex index = indexAt(pos); 92 | QClipboard * clipboard =QApplication::clipboard(); 93 | QMenu menu(this); 94 | if(mFileSystemModel->isDir(index)){ 95 | qDebug()<< mFileSystemModel->filePath(index); 96 | //文件路径 97 | QString filePath = mFileSystemModel->filePath(index); 98 | if(filePath.isEmpty()) filePath = mDir; 99 | menu.addAction("新建文件(New File)",this,[=](){ 100 | QString fileName = filePath+(filePath.endsWith("/")?"":"/")+"新建文件"+QDateTime::currentDateTime().toString("yyyy-MM-dd hh-mm-ss")+".xjy"; 101 | QFile file(fileName); 102 | if(!file.open(QIODevice::ReadWrite)){ 103 | QMessageBox::critical(this,"失败","创建新文件失败!可能没有权限或文件已经存在!"); 104 | } 105 | file.close(); 106 | }); 107 | menu.addAction("新建文件夹(New Folder)",this,[=](){ 108 | QDir dir(filePath); 109 | QString dirName = "新建文件夹"+QDateTime::currentDateTime().toString("yyyy-MM-dd hh-mm-ss"); 110 | if(!dir.exists(dirName)) 111 | dir.mkdir(dirName); 112 | 113 | }); 114 | 115 | menu.addSeparator(); 116 | 117 | menu.addAction("重命名文件夹(Rename Dir)",this,[=](){ 118 | //编辑节点 119 | edit(index); 120 | }); 121 | }else{ 122 | qDebug()<< mFileSystemModel->filePath(index); 123 | menu.addAction("重命名(Rename File)",this,[=](){ 124 | //编辑节点 125 | edit(index); 126 | preFilePath =mFileSystemModel->filePath(index); 127 | }); 128 | menu.addAction("删除文件(Remove File)",this,[=](){ 129 | //删除文件 130 | //文件名称 131 | QString fileName = mFileSystemModel->fileName(index); 132 | //文件路径 133 | QString filePath = mFileSystemModel->filePath(index); 134 | if(QMessageBox::Yes==QMessageBox::question(this,"是否删除","请确认是否删除文件:\n "+fileName+"\n此操作不可恢复!",QMessageBox::Yes|QMessageBox::No)){ 135 | //删除 136 | if(!QFile::remove(filePath)) 137 | QMessageBox::critical(this,"失败","删除文件:\n "+fileName+"\n失败!可能没有权限或文件不存在!"); 138 | } 139 | }); 140 | 141 | menu.addSeparator(); 142 | menu.addAction("复制文件名(Copy File Name)",this,[=](){ 143 | //复制文件名 144 | clipboard->setText(mFileSystemModel->fileName(index)); 145 | 146 | }); 147 | } 148 | 149 | menu.addAction("复制全路径(Copy Full Path)",this,[=](){ 150 | //复制全路径 151 | clipboard->setText(mFileSystemModel->filePath(index)); 152 | }); 153 | 154 | menu.addSeparator(); 155 | 156 | QString filePath =mFileSystemModel->filePath(index); 157 | if(!mFileSystemModel->isDir(index)) filePath = filePath.left(filePath.length()-mFileSystemModel->fileName(index).length()); 158 | 159 | menu.addAction("在文件资源管理器中显示(Show In Explorer)",this,[=](){ 160 | //在文件资源管理器中显示 161 | QDesktopServices::openUrl(QUrl(filePath)); 162 | }); 163 | 164 | menu.addAction("打开命令提示符(Open CMD)",this,[=](){ 165 | //打开命令提示符 166 | QProcess * process = new QProcess(this); 167 | process->startDetached("cmd",QStringList()<<"/c"<<"cd "+filePath+" && start cmd"); 168 | delete process; 169 | }); 170 | 171 | menu.exec(QCursor::pos()); 172 | } 173 | 174 | void TreeView::onTreeViewDoubleClicked(const QModelIndex &index) 175 | { 176 | //打开文件操作 177 | //判断是否是文件 178 | if(!mFileSystemModel->isDir(index)){ 179 | QString filePath = mFileSystemModel->filePath(index); 180 | emit createTab(filePath); 181 | } 182 | } 183 | 184 | void TreeView::onModelDataChanged(const QModelIndex &index) 185 | { 186 | if(!mFileSystemModel->isDir(index)) 187 | if(!preFilePath.isEmpty()){ 188 | 189 | QString filePath = mFileSystemModel->filePath(index); 190 | emit onDataChanged(preFilePath,filePath); 191 | 192 | return; 193 | } 194 | setTreeViewModel(); 195 | } 196 | -------------------------------------------------------------------------------- /src/utils/disasm.cpp: -------------------------------------------------------------------------------- 1 | #if defined(__GNUC__) && !defined(__clang__) 2 | #pragma GCC diagnostic push 3 | #pragma GCC diagnostic ignored "-Wmaybe-uninitialized" 4 | #endif 5 | #include "disasm.h" 6 | #include "llvm/MC/MCAsmInfo.h" 7 | #include "llvm/MC/MCContext.h" 8 | #include "llvm/MC/MCDisassembler/MCDisassembler.h" 9 | #include "llvm/MC/MCInstPrinter.h" 10 | #if LLVM_VERSION_MAJOR >= 14 11 | #include "llvm/MC/TargetRegistry.h" 12 | #if LLVM_VERSION_MAJOR >= 15 13 | #include "llvm/MC/MCSubtargetInfo.h" 14 | #endif 15 | #else 16 | #include "llvm/Support/TargetRegistry.h" 17 | #endif 18 | #include "llvm/Support/TargetSelect.h" 19 | 20 | #if defined(__GNUC__) && !defined(__clang__) 21 | #pragma GCC diagnostic pop 22 | #endif 23 | 24 | #if LLVM_VERSION_MAJOR < 11 25 | #error Please use LLVM with major version >= 11 26 | #endif 27 | 28 | using namespace llvm; 29 | 30 | static llvm::MCDisassembler *gDisassembler = nullptr; 31 | static llvm::MCSubtargetInfo *gSTI = nullptr; 32 | static llvm::MCInstPrinter *gIP = nullptr; 33 | 34 | extern "C" void init_disasm(const char *triple) { 35 | llvm::InitializeAllTargetInfos(); 36 | llvm::InitializeAllTargetMCs(); 37 | llvm::InitializeAllAsmParsers(); 38 | llvm::InitializeAllDisassemblers(); 39 | 40 | std::string errstr; 41 | std::string gTriple(triple); 42 | 43 | llvm::MCInstrInfo *gMII = nullptr; 44 | llvm::MCRegisterInfo *gMRI = nullptr; 45 | auto target = llvm::TargetRegistry::lookupTarget(gTriple, errstr); 46 | if (!target) { 47 | llvm::errs() << "Can't find target for " << gTriple << ": " << errstr << "\n"; 48 | assert(0); 49 | } 50 | 51 | MCTargetOptions MCOptions; 52 | gSTI = target->createMCSubtargetInfo(gTriple, "", ""); 53 | std::string isa = target->getName(); 54 | if (isa == "riscv32" || isa == "riscv64") { 55 | gSTI->ApplyFeatureFlag("+m"); 56 | gSTI->ApplyFeatureFlag("+a"); 57 | gSTI->ApplyFeatureFlag("+c"); 58 | gSTI->ApplyFeatureFlag("+f"); 59 | gSTI->ApplyFeatureFlag("+d"); 60 | } 61 | gMII = target->createMCInstrInfo(); 62 | gMRI = target->createMCRegInfo(gTriple); 63 | auto AsmInfo = target->createMCAsmInfo(*gMRI, gTriple, MCOptions); 64 | #if LLVM_VERSION_MAJOR >= 13 65 | auto llvmTripleTwine = Twine(triple); 66 | auto llvmtriple = llvm::Triple(llvmTripleTwine); 67 | auto Ctx = new llvm::MCContext(llvmtriple,AsmInfo, gMRI, nullptr); 68 | #else 69 | auto Ctx = new llvm::MCContext(AsmInfo, gMRI, nullptr); 70 | #endif 71 | gDisassembler = target->createMCDisassembler(*gSTI, *Ctx); 72 | gIP = target->createMCInstPrinter(llvm::Triple(gTriple), 73 | AsmInfo->getAssemblerDialect(), *AsmInfo, *gMII, *gMRI); 74 | gIP->setPrintImmHex(true); 75 | gIP->setPrintBranchImmAsAddress(true); 76 | if (isa == "riscv32" || isa == "riscv64") 77 | gIP->applyTargetSpecificCLOption("no-aliases"); 78 | } 79 | 80 | extern "C" void disassemble(char *str, int size, uint64_t pc, uint8_t *code, int nbyte) { 81 | MCInst inst; 82 | llvm::ArrayRef arr(code, nbyte); 83 | uint64_t dummy_size = 0; 84 | gDisassembler->getInstruction(inst, dummy_size, arr, pc, llvm::nulls()); 85 | 86 | std::string s; 87 | raw_string_ostream os(s); 88 | gIP->printInst(&inst, pc, "", *gSTI, os); 89 | 90 | int skip = s.find_first_not_of('\t'); 91 | const char *p = s.c_str() + skip; 92 | assert((int)s.length() - skip < size); 93 | strcpy(str, p); 94 | } 95 | -------------------------------------------------------------------------------- /src/vsrc/ALU.v: -------------------------------------------------------------------------------- 1 | module ALU( 2 | input [31:0] rs1,rs2, 3 | input [3:0] func, 4 | output reg [31:0] ALUout 5 | ); 6 | 7 | wire signed [31:0] signed_a; 8 | wire signed [31:0] signed_b; 9 | wire signed [31:0] signed_1; 10 | wire signed [31:0] signed_0; 11 | assign signed_a = rs1; 12 | assign signed_b = rs2; 13 | assign signed_1 = 32'h1; 14 | assign signed_0 = 32'h0; 15 | 16 | always@(*)begin 17 | case(func) 18 | 4'b0000: ALUout = rs1 + rs2; 19 | 4'b1000: ALUout = rs1 - rs2; 20 | 4'b0001: ALUout = rs1 << rs2[4:0]; 21 | 4'b0010: ALUout = signed_a < signed_b ? 1 : 0; 22 | 4'b0011: ALUout = rs1 < rs2 ? 1 : 0; 23 | 4'b0100: ALUout = rs1 ^ rs2; 24 | 4'b0101: ALUout = rs1 >> rs2[4:0]; 25 | 4'b1101: ALUout = signed_a >>> rs2[4:0]; 26 | 4'b0110: ALUout = rs1 | rs2; 27 | 4'b0111: ALUout = rs1 & rs2; 28 | 4'b1001: ALUout = rs2; 29 | 4'b1010: ALUout = rs1; 30 | 4'b1011: ALUout = 32'h0; 31 | 4'b1100: ALUout = 32'h0; 32 | 4'b1110: ALUout = rs2; 33 | 4'b1111: ALUout = 32'h0; 34 | endcase 35 | end 36 | endmodule -------------------------------------------------------------------------------- /src/vsrc/BU.v: -------------------------------------------------------------------------------- 1 | module BU( 2 | input [31:0] rs1, 3 | input [31:0] rs2, 4 | input [2:0] Type, 5 | output reg BrE 6 | ); 7 | wire signed [31:0] signed_rs1; 8 | wire signed [31:0] signed_rs2; 9 | wire unsigned [31:0] unsigned_rs1; 10 | wire unsigned [31:0] unsigned_rs2; 11 | 12 | assign signed_rs1 = rs1; 13 | assign signed_rs2 = rs2; 14 | assign unsigned_rs1 = rs1; 15 | assign unsigned_rs2 = rs2; 16 | always@(*)begin 17 | case(Type) 18 | 3'b010: BrE = signed_rs1 == signed_rs2; 19 | 3'b011: BrE = signed_rs1 != signed_rs2; 20 | 3'b100: BrE = signed_rs1 < signed_rs2; 21 | 3'b101: BrE = signed_rs1 >= signed_rs2; 22 | 3'b110: BrE = unsigned_rs1 < unsigned_rs2; 23 | 3'b111: BrE = unsigned_rs1 >= unsigned_rs2; 24 | default:BrE = 1'b0; 25 | endcase 26 | end 27 | endmodule -------------------------------------------------------------------------------- /src/vsrc/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # cmake_policy(SET CMP0079 OLD) 2 | add_executable(IDE 3 | ${SOURCE_FILES} 4 | ${INCLUDE_FILES} 5 | ${QRC_FILES} 6 | ${UI_FILES} 7 | ) 8 | 9 | # message(${SOURCES_FILES}) 10 | # message(${INCLUDE_FILES}) 11 | # 添加编译器标志(例如,来自 llvm-config) 12 | execute_process( 13 | COMMAND llvm-config-13 --cxxflags 14 | OUTPUT_VARIABLE LLVM_CXX_FLAGS 15 | OUTPUT_STRIP_TRAILING_WHITESPACE 16 | ) 17 | # message(${LLVM_CXX_FLAGS}) 18 | 19 | target_compile_options(IDE PRIVATE ${LLVM_CXX_FLAGS} -fPIE) 20 | 21 | execute_process( 22 | COMMAND llvm-config-13 --includedir 23 | OUTPUT_VARIABLE LLVM_INCLUDE 24 | OUTPUT_STRIP_TRAILING_WHITESPACE 25 | ) 26 | 27 | target_include_directories(IDE PRIVATE ${PROJECT_SOURCE_DIR}/include 28 | ${PROJECT_SOURCE_DIR}/include/ui 29 | ${PROJECT_SOURCE_DIR}/include/monitor 30 | ${PROJECT_SOURCE_DIR}/include/utils 31 | ${PROJECT_SOURCE_DIR}/include/device 32 | ${LLVM_INCLUDE}) 33 | # Qt5::Widgets 34 | target_link_libraries(IDE PRIVATE Qt5::Core Qt5::Gui) 35 | 36 | if(Qt5PrintSupport_FOUND) 37 | target_link_libraries(IDE PRIVATE Qt5::PrintSupport) 38 | endif() 39 | 40 | # 获取 llvm-config 的库 41 | execute_process( 42 | COMMAND llvm-config-13 --libs 43 | OUTPUT_VARIABLE LLVM_LIBS 44 | OUTPUT_STRIP_TRAILING_WHITESPACE 45 | ) 46 | # message(${LLVM_LIBS}) 47 | # 添加链接库 48 | target_link_libraries(IDE PRIVATE 49 | readline 50 | ${LLVM_LIBS} # 链接来自 llvm-config 的库 51 | ) 52 | 53 | verilate(IDE 54 | INCLUDE_DIRS ${PROJECT_SOURCE_DIR}/src/vsrc 55 | SOURCES CPU.v 56 | VERILATOR_ARGS -O3 --x-assign fast --x-initial fast --noassert --trace) 57 | set(EXECUTABLE_OUTPUT_PATH ${PROJECT_SOURCE_DIR}/bin) 58 | 59 | # file(APPEND "${PROJECT_SOURCE_DIR}/build/Makefile" "Your custom command here\n") 60 | -------------------------------------------------------------------------------- /src/vsrc/CPU.v: -------------------------------------------------------------------------------- 1 | module CPU( 2 | input clk, 3 | input rst, 4 | input [31:0] inst, 5 | output [31:0] pc 6 | ); 7 | 8 | wire [1:0] rf_wr_sel; 9 | reg [31:0] rf_wd; 10 | wire rf_wr_en; 11 | wire csrf_wr_en; 12 | wire [1:0] csr_inst_sel; 13 | reg [31:0] csr_in_val; 14 | wire [4:0] rs1,rs2,rd; 15 | wire [31:0] rf_rd1,rf_rd2,csrv; 16 | wire [31:0] rf_rd2_temp; 17 | wire [31:0] pc_plus4; 18 | wire do_jump; 19 | wire JUMP; 20 | 21 | wire [31:0] imm_out; 22 | 23 | wire [2:0] comp_ctrl; 24 | wire BrE; 25 | 26 | wire alu_a_sel; 27 | wire alu_b_sel; 28 | wire [31:0] alu_a,alu_b,alu_out; 29 | wire [3:0] alu_ctrl; 30 | 31 | wire [2:0] dm_rd_ctrl; 32 | wire [1:0] dm_wr_ctrl; 33 | wire [31:0] dm_dout; 34 | 35 | always@(*) 36 | begin 37 | case(csr_inst_sel) 38 | 2'b00: csr_in_val = 32'h0; 39 | 2'b01: csr_in_val = rf_rd1; 40 | 2'b10: csr_in_val = alu_out; 41 | 2'b11: csr_in_val = pc; 42 | default:csr_in_val = 32'h0; 43 | endcase 44 | end 45 | 46 | always@(*) 47 | begin 48 | case(rf_wr_sel) 49 | 2'b00: rf_wd = 32'h0; 50 | 2'b01: rf_wd = pc_plus4; 51 | 2'b10: begin if(csr_inst_sel==2'b10) rf_wd = csrv; else rf_wd = alu_out; end 52 | 2'b11: rf_wd = dm_dout; 53 | default:rf_wd = 32'h0; 54 | endcase 55 | end 56 | 57 | assign pc_plus4 = pc + 32'h4; 58 | assign JUMP = BrE || do_jump; 59 | assign alu_a = alu_a_sel ? rf_rd1 : pc ; 60 | assign alu_b = alu_b_sel ? imm_out : rf_rd2_temp ; //gai 61 | assign rf_rd2_temp = rf_rd2 | csrv; 62 | 63 | 64 | IFU inst_fetch_unit( 65 | .inst_in (inst), 66 | .inst_out () 67 | ); 68 | 69 | IDU idu( 70 | .inst (inst), 71 | .is_csr (csrf_wr_en), 72 | .rd (rd), 73 | .rs1 (rs1), 74 | .rs2 (rs2), 75 | .imm (imm_out) 76 | ); 77 | 78 | REF #(5,32) reg_file( 79 | .clk (clk), 80 | .wdata (rf_wd), 81 | .rd (rd), 82 | .wen (rf_wr_en), 83 | .rs1 (rs1), 84 | .rs2 (rs2), 85 | .rd1 (rf_rd1), 86 | .rd2 (rf_rd2) 87 | ); 88 | 89 | CSR #(5,32) csr_file( 90 | .clk (clk), 91 | .inst (inst), 92 | .wdata (csr_in_val), 93 | .wen (rf_wr_en), 94 | .imm (imm_out), 95 | .csrv (csrv) 96 | ); 97 | 98 | ALU alu( 99 | .rs1 (alu_a), 100 | .rs2 (alu_b), 101 | .func (alu_ctrl), 102 | .ALUout (alu_out) 103 | ); 104 | 105 | BU bu( 106 | .rs1 (rf_rd1), 107 | .rs2 (rf_rd2), 108 | .Type (comp_ctrl), 109 | .BrE (BrE) 110 | ); 111 | 112 | PC pc0( 113 | .clk (clk), 114 | .rst (rst), 115 | .JUMP (JUMP), 116 | .JUMP_PC (alu_out), 117 | .pc (pc) 118 | ); 119 | 120 | CU cu( 121 | .inst (inst), 122 | .rf_wr_en (rf_wr_en), 123 | .csrf_wr_en (csrf_wr_en), 124 | .csr_inst_sel (csr_inst_sel), 125 | .rf_wr_sel (rf_wr_sel), 126 | .do_jump (do_jump), 127 | .BrType (comp_ctrl), 128 | .alu_a_sel (alu_a_sel), 129 | .alu_b_sel (alu_b_sel), 130 | .alu_ctrl (alu_ctrl), 131 | .dm_rd_ctrl (dm_rd_ctrl), 132 | .dm_wr_ctrl (dm_wr_ctrl) 133 | ); 134 | 135 | MEM mem0( 136 | .clk (clk), 137 | .dm_rd_ctrl (dm_rd_ctrl), 138 | .dm_wr_ctrl (dm_wr_ctrl), 139 | .dm_addr (alu_out), 140 | .dm_din (rf_rd2), 141 | .dm_dout (dm_dout) 142 | ); 143 | 144 | endmodule -------------------------------------------------------------------------------- /src/vsrc/CU.v: -------------------------------------------------------------------------------- 1 | import "DPI-C" function void npc_state(input int flag, input int inst_to_sdb); 2 | module CU( 3 | input [31:0] inst, 4 | output rf_wr_en, 5 | output csrf_wr_en, 6 | output reg [1:0] csr_inst_sel, 7 | output reg [1:0] rf_wr_sel, 8 | output do_jump, 9 | output reg [2:0] BrType, 10 | output alu_a_sel, 11 | output alu_b_sel, 12 | output reg [3:0] alu_ctrl, 13 | output reg [2:0] dm_rd_ctrl, 14 | output reg [1:0] dm_wr_ctrl 15 | ); 16 | 17 | wire [6:0] opcode; 18 | wire [2:0] funct3; 19 | wire [6:0] funct7; 20 | 21 | wire is_lui; 22 | wire is_auipc; 23 | wire is_jal; 24 | wire is_jalr; 25 | wire is_beq; 26 | wire is_bne; 27 | wire is_blt; 28 | wire is_bge; 29 | wire is_bltu; 30 | wire is_bgeu; 31 | wire is_lb; 32 | wire is_lh; 33 | wire is_lw; 34 | wire is_lbu; 35 | wire is_lhu; 36 | wire is_sb; 37 | wire is_sh; 38 | wire is_sw; 39 | wire is_addi; 40 | wire is_slti; 41 | wire is_sltiu; 42 | wire is_xori; 43 | wire is_ori; 44 | wire is_andi; 45 | wire is_slli; 46 | wire is_srli; 47 | wire is_srai; 48 | wire is_add; 49 | wire is_sub; 50 | wire is_sll; 51 | wire is_slt; 52 | wire is_sltu; 53 | wire is_xor; 54 | wire is_srl; 55 | wire is_sra; 56 | wire is_or; 57 | wire is_and; 58 | 59 | wire is_add_type; 60 | wire is_u_type; 61 | wire is_jump_type; 62 | wire is_b_type; 63 | wire is_r_type; 64 | wire is_i_type; 65 | wire is_s_type; 66 | 67 | wire is_csrrw; 68 | wire is_csrrs; 69 | wire is_csrrc; 70 | wire is_csrwi; 71 | wire is_csrsi; 72 | wire is_csrci; 73 | wire is_csr; 74 | 75 | wire is_ecall; 76 | wire is_mret; 77 | assign opcode = inst[6:0]; 78 | assign funct7 = inst[31:25]; 79 | assign funct3 = inst[14:12]; 80 | 81 | assign is_lui = (opcode == 7'h37) ; 82 | assign is_auipc= (opcode == 7'h17) ; 83 | assign is_jal = (opcode == 7'h6F) ; 84 | assign is_jalr = (opcode == 7'h67) && (funct3 ==3'h0) ; 85 | assign is_beq = (opcode == 7'h63) && (funct3 ==3'h0) ; 86 | assign is_bne = (opcode == 7'h63) && (funct3 ==3'h1) ; 87 | assign is_blt = (opcode == 7'h63) && (funct3 ==3'h4) ; 88 | assign is_bge = (opcode == 7'h63) && (funct3 ==3'h5) ; 89 | assign is_bltu = (opcode == 7'h63) && (funct3 ==3'h6) ; 90 | assign is_bgeu = (opcode == 7'h63) && (funct3 ==3'h7) ; 91 | assign is_lb = (opcode == 7'h03) && (funct3 ==3'h0) ; 92 | assign is_lh = (opcode == 7'h03) && (funct3 ==3'h1) ; 93 | assign is_lw = (opcode == 7'h03) && (funct3 ==3'h2) ; 94 | assign is_lbu = (opcode == 7'h03) && (funct3 ==3'h4) ; 95 | assign is_lhu = (opcode == 7'h03) && (funct3 ==3'h5) ; 96 | assign is_sb = (opcode == 7'h23) && (funct3 ==3'h0) ; 97 | assign is_sh = (opcode == 7'h23) && (funct3 ==3'h1) ; 98 | assign is_sw = (opcode == 7'h23) && (funct3 ==3'h2) ; 99 | assign is_addi = (opcode == 7'h13) && (funct3 ==3'h0) ; 100 | assign is_slti = (opcode == 7'h13) && (funct3 ==3'h2) ; 101 | assign is_sltiu= (opcode == 7'h13) && (funct3 ==3'h3) ; 102 | assign is_xori = (opcode == 7'h13) && (funct3 ==3'h4) ; 103 | assign is_ori = (opcode == 7'h13) && (funct3 ==3'h6) ; 104 | assign is_andi = (opcode == 7'h13) && (funct3 ==3'h7) ; 105 | assign is_slli = (opcode == 7'h13) && (funct3 ==3'h1) && (funct7 == 7'h00); 106 | assign is_srli = (opcode == 7'h13) && (funct3 ==3'h5) && (funct7 == 7'h00); 107 | assign is_srai = (opcode == 7'h13) && (funct3 ==3'h5) && (funct7 == 7'h20); 108 | assign is_add = (opcode == 7'h33) && (funct3 ==3'h0) && (funct7 == 7'h00); 109 | assign is_sub = (opcode == 7'h33) && (funct3 ==3'h0) && (funct7 == 7'h20); 110 | assign is_sll = (opcode == 7'h33) && (funct3 ==3'h1) && (funct7 == 7'h00); 111 | assign is_slt = (opcode == 7'h33) && (funct3 ==3'h2) && (funct7 == 7'h00); 112 | assign is_sltu = (opcode == 7'h33) && (funct3 ==3'h3) && (funct7 == 7'h00); 113 | assign is_xor = (opcode == 7'h33) && (funct3 ==3'h4) && (funct7 == 7'h00); 114 | assign is_srl = (opcode == 7'h33) && (funct3 ==3'h5) && (funct7 == 7'h00); 115 | assign is_sra = (opcode == 7'h33) && (funct3 ==3'h5) && (funct7 == 7'h20); 116 | assign is_or = (opcode == 7'h33) && (funct3 ==3'h6) && (funct7 == 7'h00); 117 | assign is_and = (opcode == 7'h33) && (funct3 ==3'h7) && (funct7 == 7'h00); 118 | 119 | assign is_csrrw = (opcode == 7'h73) && (funct3 ==3'h1); 120 | assign is_csrrs = (opcode == 7'h73) && (funct3 ==3'h2); 121 | assign is_csrrc = (opcode == 7'h73) && (funct3 ==3'h3); 122 | assign is_csrwi = (opcode == 7'h73) && (funct3 ==3'h5); 123 | assign is_csrsi = (opcode == 7'h73) && (funct3 ==3'h6); 124 | assign is_csrci = (opcode == 7'h73) && (funct3 ==3'h7); 125 | 126 | assign is_ecall = (inst == 32'b00000000000000000000000001110011); 127 | assign is_mret = (inst == 32'b00110000001000000000000001110011); 128 | 129 | assign is_csr = is_csrrw | is_csrrs | is_csrrc | is_csrwi | is_csrsi | is_csrci; 130 | 131 | assign is_add_type = is_auipc | is_jal | is_jalr | is_b_type | is_s_type 132 | | is_lb | is_lh | is_lw | is_lbu | is_lhu | is_add | is_addi ; 133 | assign is_u_type = is_lui | is_auipc ; 134 | assign is_jump_type= is_jal ; 135 | assign is_b_type = is_beq | is_bne | is_blt | is_bge | is_bltu | is_bgeu ; 136 | assign is_r_type = is_add | is_sub | is_sll | is_slt | is_sltu | is_xor 137 | | is_srl | is_sra | is_or | is_and ; 138 | assign is_i_type = is_jalr | is_lb | is_lh | is_lw | is_lbu | is_lhu 139 | | is_addi | is_slti | is_sltiu | is_xori | is_ori | is_andi 140 | | is_slli | is_srli | is_srai ; 141 | assign is_s_type = is_sb | is_sh | is_sw ; 142 | always @(*)begin 143 | if(is_u_type|is_jump_type|is_i_type|is_r_type|is_s_type|is_b_type|is_csr|is_ecall|is_mret) 144 | npc_state(0, inst); 145 | else 146 | npc_state(1, inst); 147 | end 148 | assign csrf_wr_en = is_csr | is_mret | is_ecall; 149 | 150 | always@(*) 151 | begin 152 | if(is_csrrw) 153 | csr_inst_sel = 2'b01; 154 | else if(is_csrrs) 155 | csr_inst_sel = 2'b10; 156 | else if(is_ecall) 157 | csr_inst_sel = 2'b11; 158 | else 159 | csr_inst_sel = 2'b00; 160 | end 161 | 162 | //rf_wr_en 163 | assign rf_wr_en = is_u_type | is_jump_type | is_i_type| is_r_type|is_csr|is_ecall|is_mret; 164 | //[1:0]rf_wr_sel 165 | always@(*) 166 | begin 167 | if(is_jal | is_jalr) 168 | rf_wr_sel = 2'b01; 169 | else if(is_r_type | is_u_type | is_addi | is_slti | is_sltiu | is_xori | is_ori | is_andi 170 | | is_slli | is_srli | is_srai | is_csr) 171 | rf_wr_sel = 2'b10; 172 | else if(is_lb | is_lh | is_lw | is_lbu | is_lhu ) 173 | rf_wr_sel = 2'b11; 174 | else 175 | rf_wr_sel = 2'b00; 176 | end 177 | 178 | //do_jump 179 | assign do_jump = (is_jal|is_jalr|is_ecall|is_mret)?1:0; 180 | 181 | //[2:0]BrType 182 | always@(*) 183 | begin 184 | if(is_beq) 185 | BrType = 3'b010; 186 | else if(is_bne) 187 | BrType = 3'b011; 188 | else if(is_blt) 189 | BrType = 3'b100; 190 | else if(is_bge) 191 | BrType = 3'b101; 192 | else if(is_bltu) 193 | BrType = 3'b110; 194 | else if(is_bgeu) 195 | BrType = 3'b111; 196 | else 197 | BrType = 3'b000; 198 | end 199 | 200 | //alu_a_sel 201 | assign alu_a_sel = (is_r_type|is_i_type|is_s_type|is_csrrs)?1:0; 202 | 203 | //alu_b_sel 204 | assign alu_b_sel = (is_r_type|is_csrrs|is_ecall|is_mret)?0:1; 205 | 206 | //alu_ctrl 207 | always@(*) 208 | begin 209 | if(is_add_type) 210 | alu_ctrl = 4'b0000; 211 | else if(is_sub) 212 | alu_ctrl = 4'b1000; 213 | else if(is_sll|is_slli) 214 | alu_ctrl = 4'b0001; 215 | else if(is_srl|is_srli) 216 | alu_ctrl = 4'b0101; 217 | else if(is_sra|is_srai) 218 | alu_ctrl = 4'b1101; 219 | else if(is_slt|is_slti) 220 | alu_ctrl = 4'b0010; 221 | else if(is_sltu|is_sltiu) 222 | alu_ctrl = 4'b0011; 223 | else if(is_xori|is_xor) 224 | alu_ctrl = 4'b0100; 225 | else if(is_ori|is_or|is_csrrs) 226 | alu_ctrl = 4'b0110; 227 | else if(is_andi|is_and) 228 | alu_ctrl = 4'b0111; 229 | else if(is_lui) 230 | alu_ctrl = 4'b1110; 231 | else if(is_ecall | is_mret) 232 | alu_ctrl = 4'b1001; 233 | else if(is_csrrw) 234 | alu_ctrl = 4'b1010; 235 | else 236 | alu_ctrl = 4'b1111; 237 | end 238 | 239 | //[2:0]dm_rd_ctrl 240 | always@(*) 241 | begin 242 | if(is_lb) 243 | dm_rd_ctrl = 3'b001; 244 | else if(is_lbu) 245 | dm_rd_ctrl = 3'b010; 246 | else if(is_lh) 247 | dm_rd_ctrl = 3'b011; 248 | else if(is_lhu) 249 | dm_rd_ctrl = 3'b100; 250 | else if(is_lw) 251 | dm_rd_ctrl = 3'b101; 252 | else 253 | dm_rd_ctrl = 3'b000; 254 | end 255 | 256 | //[1:0]dm_wr_ctrl 257 | always@(*) 258 | begin 259 | if(is_sb) 260 | dm_wr_ctrl = 2'b01; 261 | else if(is_sh) 262 | dm_wr_ctrl = 2'b10; 263 | else if(is_sw) 264 | dm_wr_ctrl = 2'b11; 265 | else 266 | dm_wr_ctrl = 2'b00; 267 | end 268 | endmodule -------------------------------------------------------------------------------- /src/vsrc/IDU.v: -------------------------------------------------------------------------------- 1 | module imm( 2 | input [31:0] inst, 3 | output reg [31:0] out 4 | ); 5 | wire [6:0] opcode; 6 | assign opcode= inst[6:0]; 7 | //立即数扩展 8 | always@(*) 9 | begin 10 | case(opcode) 11 | 7'b0010111: out = {inst[31:12],{12{1'b0}}}; 12 | 7'b0110111: out = {inst[31:12],{12{1'b0}}}; 13 | 7'b1100011: out = {{19{inst[31]}},inst[31],inst[7],inst[30:25],inst[11:8],1'b0}; 14 | 7'b1101111: out = {{11{inst[31]}},inst[31], inst[19:12], inst[20], inst[30:21], {1'b0}}; 15 | 7'b1100111: out = {{20{inst[31]}}, inst[31:20]}; 16 | 7'b0000011: out = {{20{inst[31]}}, inst[31:20]}; 17 | 7'b0100011: out = {{20{inst[31]}}, inst[31:25], inst[11:7]}; 18 | 7'b0010011: out = {{20{inst[31]}}, inst[31:20]}; 19 | 7'b1110011: out = {{20{1'b0}}, inst[31:20]}; 20 | default: out = 32'h0; 21 | endcase 22 | end 23 | endmodule 24 | 25 | module IDU( 26 | input [31:0] inst, 27 | input is_csr, 28 | output reg [4:0] rd, 29 | output reg [4:0] rs1, 30 | output reg [4:0] rs2, 31 | output [31:0] imm); 32 | 33 | always@(*)begin 34 | rd = inst[11:7]; 35 | rs1 = inst[19:15]; 36 | if(is_csr) 37 | rs2 = 5'h0; 38 | else 39 | rs2 = inst[24:20]; 40 | end 41 | 42 | imm imm1( 43 | .inst(inst), 44 | .out(imm)); 45 | 46 | endmodule //decode -------------------------------------------------------------------------------- /src/vsrc/IFU.v: -------------------------------------------------------------------------------- 1 | import "DPI-C" function void trap(input int flag); 2 | module IFU( 3 | input [31:0] inst_in, 4 | output [31:0] inst_out); 5 | 6 | assign inst_out = inst_in; 7 | always@(*)begin 8 | if(inst_out == 32'b000000000001_00000_000_00000_1110011) 9 | trap(1); 10 | else 11 | trap(0); 12 | end 13 | endmodule //fetch -------------------------------------------------------------------------------- /src/vsrc/PC.v: -------------------------------------------------------------------------------- 1 | module PC( 2 | input clk, 3 | input rst, 4 | input JUMP, 5 | input [31:0] JUMP_PC, 6 | output reg [31:0] pc); 7 | wire [31:0] pc_plus4; 8 | assign pc_plus4 = pc + 32'h4; 9 | //计算PC 10 | always@(posedge clk or posedge rst) 11 | begin 12 | if(rst) 13 | pc<=32'h80000000; 14 | else if(JUMP) 15 | pc<=JUMP_PC; 16 | else 17 | pc<=pc_plus4; 18 | end 19 | endmodule -------------------------------------------------------------------------------- /src/vsrc/REF.v: -------------------------------------------------------------------------------- 1 | module REF #(ADDR_WIDTH = 1, DATA_WIDTH = 1) ( 2 | input clk, 3 | input [DATA_WIDTH-1:0] wdata, 4 | input [ADDR_WIDTH-1:0] rd, 5 | input wen, 6 | input [ADDR_WIDTH-1:0] rs1,rs2, 7 | output [DATA_WIDTH-1:0] rd1, rd2 8 | ); 9 | 10 | reg [DATA_WIDTH-1:0] rf [2**ADDR_WIDTH-1:0]; 11 | 12 | always @(posedge clk) begin 13 | rf[0] <= 32'h0; 14 | if (wen && (rd!=5'd0)) begin 15 | rf[rd] <= wdata; 16 | end 17 | end 18 | 19 | assign rd1 = rf[rs1]; 20 | assign rd2 = rf[rs2]; 21 | 22 | endmodule 23 | --------------------------------------------------------------------------------