├── .clang-format ├── .gitignore ├── AUTHORS ├── LICENSE ├── Makefile ├── README.md ├── emu-rv32i.c └── test1.c /.clang-format: -------------------------------------------------------------------------------- 1 | BasedOnStyle: Chromium 2 | Language: Cpp 3 | MaxEmptyLinesToKeep: 3 4 | IndentCaseLabels: false 5 | AllowShortIfStatementsOnASingleLine: false 6 | AllowShortCaseLabelsOnASingleLine: false 7 | AllowShortLoopsOnASingleLine: false 8 | DerivePointerAlignment: false 9 | PointerAlignment: Right 10 | SpaceAfterCStyleCast: true 11 | TabWidth: 4 12 | UseTab: Never 13 | IndentWidth: 4 14 | BreakBeforeBraces: Linux 15 | AccessModifierOffset: -4 16 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | emu-rv32i 2 | test1 3 | -------------------------------------------------------------------------------- /AUTHORS: -------------------------------------------------------------------------------- 1 | rv32emu is maintained by National Cheng Kung University, based on the 2 | following efforts: 3 | 4 | Fabrice Bellard - original code of RISC-V emulator: 5 | https://bellard.org/tinyemu/ 6 | 7 | Frank Buss - simplified emulator for RV32I capable of passing compliance tests: 8 | https://gist.github.com/FrankBuss/c974e59826d33e21d7cad54491ab50e8 9 | 10 | Alexander Shabarshin - maintainer of this nedoPC-5 project: 11 | https://gitlab.com/nedopc/npc5 12 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2019 National Cheng Kung University, Taiwan 2 | Copyright (c) 2018 Alexander Shabarshin 3 | Copyright (c) 2018 Frank Buss 4 | Copyright (c) 2016-2017 Fabrice Bellard 5 | 6 | Permission is hereby granted, free of charge, to any person obtaining a copy 7 | of this software and associated documentation files (the "Software"), to deal 8 | in the Software without restriction, including without limitation the rights 9 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | copies of the Software, and to permit persons to whom the Software is 11 | furnished to do so, subject to the following conditions: 12 | 13 | The above copyright notice and this permission notice shall be included in 14 | all copies or substantial portions of the Software. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 19 | THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | THE SOFTWARE. 23 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | BINS = emu-rv32i test1 2 | 3 | CROSS_COMPILE = riscv-none-embed- 4 | RV32I_CFLAGS = -march=rv32i -mabi=ilp32 -O3 -nostdlib 5 | 6 | CFLAGS = -O3 -Wall -std=gnu99 7 | LDFLAGS = -lelf 8 | 9 | all: $(BINS) 10 | 11 | emu-rv32i: emu-rv32i.c 12 | $(CC) $(CFLAGS) -o $@ $< $(LDFLAGS) 13 | 14 | test1: test1.c 15 | $(CROSS_COMPILE)gcc $(RV32I_CFLAGS) -o $@ $< 16 | 17 | check: $(BINS) 18 | ./emu-rv32i test1 19 | 20 | clean: 21 | $(RM) $(BINS) 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # RISC-V RV32I[MA] emulator with ELF support 2 | 3 | This is a RISC-V emulator for the RV32I architecture, based on [TinyEMU](https://bellard.org/tinyemu/) 4 | and stripped down for RV32I only. 5 | 6 | Requires libelf-dev: 7 | ```shell 8 | $ sudo apt-get install libelf-dev 9 | ``` 10 | 11 | How to compile it: 12 | ```shell 13 | $ gcc -O3 -Wall emu-rv32i.c -o emu-rv32i -lelf 14 | ``` 15 | 16 | Run RV32I compliance tests. 17 | Assume `emu-rv32i` in `$PATH` environment variable. 18 | ```shell 19 | $ git clone https://github.com/riscv/riscv-compliance 20 | $ cd riscv-compliance 21 | $ make RISCV_PREFIX=riscv-none-embed- RISCV_DEVICE=rv32i TARGET_SIM=emu-rv32i variant 22 | ``` 23 | 24 | Compiling and running simple code: 25 | ```shell 26 | $ riscv32-unknown-elf-gcc -O3 -nostdlib test1.c -o test1 27 | ``` 28 | 29 | or 30 | ```shell 31 | $ riscv64-unknown-elf-gcc -march=rv32i -mabi=ilp32 -O3 -nostdlib test1.c -o test1 32 | ``` 33 | 34 | then 35 | ```shell 36 | $ ./emu-rv32i test1 37 | Hello RISC-V! 38 | ``` 39 | 40 | RV32M and RV32A instructions may be enabled by commenting `#define STRICT_RV32I`. 41 | 42 | ## How to build RISC-V toolchain from scratch 43 | 44 | https://github.com/riscv/riscv-gnu-toolchain 45 | 46 | 64-bit universal version (riscv64-unknown-elf-* that can build 32-bit code too): 47 | ```shell 48 | $ ./configure --prefix=/opt/riscv 49 | $ make 50 | ``` 51 | 52 | 32-bit version (riscv32-unknown-elf-*): 53 | ```shell 54 | $ ./configure --prefix=/opt/riscv32 --with-arch=rv32i --with-abi=ilp32 55 | $ make 56 | ``` 57 | -------------------------------------------------------------------------------- /emu-rv32i.c: -------------------------------------------------------------------------------- 1 | /* 2 | * A minimalist RISC-V emulator for the RV32I architecture. 3 | * 4 | * rv32emu is freely redistributable under the MIT License. See the file 5 | * "LICENSE" for information on usage and redistribution of this file. 6 | */ 7 | 8 | #define XLEN 32 9 | 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | 22 | /* uncomment this for an instruction trace and other debug outputs */ 23 | // #define DEBUG_OUTPUT 24 | // #define DEBUG_EXTRA 25 | 26 | #define STRICT_RV32I 27 | #define FALSE (0) 28 | #define TRUE (-1) 29 | 30 | #ifdef DEBUG_EXTRA 31 | 32 | uint32_t minmemr, maxmemr, minmemw, maxmemw; 33 | 34 | #define STATS_NUM 64 35 | 36 | unsigned int stats[STATS_NUM], top[5], itop[5]; 37 | 38 | char statnames[64][16] = { 39 | "LUI", "AUIPC", "JAL", "JALR", "BEQ", "BNE", "BLT", 40 | "BGE", "BLTU", "BGEU", "LB", "LH", "LW", "LBU", 41 | "LHU", "SB", "SH", "SW", "ADDI", "SLTI", "SLTIU", 42 | "XORI", "ORI", "ANDI", "SLLI", "SRLI", "SRAI", "ADD", 43 | "SUB", "SLL", "SLT", "SLTU", "XOR", "SRL", "SRA", 44 | "OR", "AND", "FENCE", "FENCE.I", "ECALL", "EBREAK", "CSRRW", 45 | "CSRRS", "CSRRC", "CSRRWI", "CSRRSI", "CSRRCI", "LI*", "MUL", 46 | "MULH", "MULHSU", "MULHU", "DIV", "DIVU", "REM", "REMU", 47 | "LR.W", "SC.W", "URET", "SRET", "MRET", "WFI", "SFENCE.VMA", 48 | ""}; 49 | 50 | void init_stats(void) 51 | { 52 | for (int i = 0; i < STATS_NUM; i++) 53 | stats[i] = 0; 54 | minmemr = minmemw = ~0; 55 | maxmemr = maxmemw = 0; 56 | } 57 | 58 | void print_stats(uint64_t total) 59 | { 60 | printf("\nInstructions Stat:\n"); 61 | top[0] = top[1] = top[2] = top[3] = top[4] = stats[0]; 62 | itop[0] = itop[1] = itop[2] = itop[3] = itop[4] = 0; 63 | for (int i = 0; i < STATS_NUM; i++) { 64 | if (stats[i] > top[0]) { 65 | top[4] = top[3]; 66 | itop[4] = itop[3]; 67 | top[3] = top[2]; 68 | itop[3] = itop[2]; 69 | top[2] = top[1]; 70 | itop[2] = itop[1]; 71 | top[1] = top[0]; 72 | itop[1] = itop[0]; 73 | top[0] = stats[i]; 74 | itop[0] = i; 75 | } else if (stats[i] > top[1]) { 76 | top[4] = top[3]; 77 | itop[4] = itop[3]; 78 | top[3] = top[2]; 79 | itop[3] = itop[2]; 80 | top[2] = top[1]; 81 | itop[2] = itop[1]; 82 | top[1] = stats[i]; 83 | itop[1] = i; 84 | } else if (stats[i] > top[2]) { 85 | top[4] = top[3]; 86 | itop[4] = itop[3]; 87 | top[3] = top[2]; 88 | itop[3] = itop[2]; 89 | top[2] = stats[i]; 90 | itop[2] = i; 91 | } else if (stats[i] > top[3]) { 92 | top[4] = top[3]; 93 | itop[4] = itop[3]; 94 | top[3] = stats[i]; 95 | itop[3] = i; 96 | } else if (stats[i] > top[4]) { 97 | top[4] = stats[i]; 98 | itop[4] = i; 99 | } 100 | if (stats[i]) { 101 | if (i < 63) 102 | printf("%s\t= %u\n", statnames[i], stats[i]); 103 | else 104 | printf("[%i] = %u\n", i, stats[i]); 105 | } 106 | } 107 | printf("\nFive Most Frequent:\n"); 108 | for (int j = 0; j < 5; j++) { 109 | printf("%i) %s\t= %u (%2.2lf%%)\n", j + 1, statnames[itop[j]], top[j], 110 | top[j] * 100.0 / (double) total); 111 | } 112 | printf("\nMemory Reading Area %x...%x\n", minmemr, maxmemr); 113 | if (minmemw + 1) 114 | printf("Memory Writing Area %x...%x\n", minmemw, maxmemw); 115 | else 116 | printf("Memory Writing Area NONE\n"); 117 | } 118 | 119 | #endif 120 | 121 | #ifdef DEBUG_OUTPUT 122 | #define debug_out(...) printf(__VA_ARGS__) 123 | #else 124 | #define debug_out(...) 125 | #endif 126 | 127 | /* memory mapped registers */ 128 | #define MTIME_ADDR 0x40000000 129 | #define MTIMECMP_ADDR 0x40000008 130 | #define UART_TX_ADDR 0x40002000 131 | 132 | /* emulate RAM */ 133 | #define RAM_SIZE 0x10000 134 | uint8_t ram[RAM_SIZE]; 135 | 136 | /* special memory mapped registers */ 137 | uint64_t mtime; 138 | uint64_t mtimecmp; 139 | 140 | /* virtual start address for index 0 in the ram array */ 141 | uint32_t ram_start; 142 | 143 | /* program entry point */ 144 | uint32_t start; 145 | 146 | /* last byte of the memory initialized and temporary value */ 147 | uint32_t ram_last = 0; 148 | uint32_t ram_curr = 0; 149 | 150 | /* used when called from the compliance tests */ 151 | uint32_t begin_signature = 0; 152 | uint32_t end_signature = 0; 153 | 154 | /* is set to false to exit the emulator */ 155 | int machine_running = TRUE; 156 | 157 | /* privilege levels */ 158 | #define PRV_U 0 159 | #define PRV_S 1 160 | #define PRV_H 2 161 | #define PRV_M 3 162 | 163 | /* CPU state */ 164 | uint32_t pc; 165 | uint32_t next_pc; 166 | uint32_t insn; 167 | uint32_t reg[32]; 168 | 169 | uint8_t priv = PRV_M; /* see PRV_x */ 170 | uint8_t fs; /* MSTATUS_FS value */ 171 | uint8_t mxl; /* MXL field in MISA register */ 172 | 173 | uint64_t jump_counter = 0, backward_counter = 0, forward_counter = 0, 174 | true_counter = 0, false_counter = 0; 175 | 176 | uint64_t insn_counter = 0; 177 | int pending_exception; /* used during MMU exception handling */ 178 | uint32_t pending_tval; 179 | 180 | /* CSRs */ 181 | uint32_t mstatus; 182 | uint32_t mtvec; 183 | uint32_t mscratch; 184 | uint32_t mepc; 185 | uint32_t mcause; 186 | uint32_t mtval; 187 | uint32_t mhartid; /* ro */ 188 | uint32_t misa; 189 | uint32_t mie; 190 | uint32_t mip; 191 | uint32_t medeleg; 192 | uint32_t mideleg; 193 | uint32_t mcounteren; 194 | 195 | uint32_t stvec; 196 | uint32_t sscratch; 197 | uint32_t sepc; 198 | uint32_t scause; 199 | uint32_t stval; 200 | uint32_t satp; 201 | uint32_t scounteren; 202 | uint32_t load_res; /* for atomic LR/SC */ 203 | 204 | /* exception causes */ 205 | #define CAUSE_MISALIGNED_FETCH 0x0 206 | #define CAUSE_FAULT_FETCH 0x1 207 | #define CAUSE_ILLEGAL_INSTRUCTION 0x2 208 | #define CAUSE_BREAKPOINT 0x3 209 | #define CAUSE_MISALIGNED_LOAD 0x4 210 | #define CAUSE_FAULT_LOAD 0x5 211 | #define CAUSE_MISALIGNED_STORE 0x6 212 | #define CAUSE_FAULT_STORE 0x7 213 | #define CAUSE_USER_ECALL 0x8 214 | #define CAUSE_SUPERVISOR_ECALL 0x9 215 | #define CAUSE_HYPERVISOR_ECALL 0xa 216 | #define CAUSE_MACHINE_ECALL 0xb 217 | #define CAUSE_FETCH_PAGE_FAULT 0xc 218 | #define CAUSE_LOAD_PAGE_FAULT 0xd 219 | #define CAUSE_STORE_PAGE_FAULT 0xf 220 | #define CAUSE_INTERRUPT ((uint32_t) 1 << 31) 221 | 222 | /* misa CSR */ 223 | #define MCPUID_SUPER (1 << ('S' - 'A')) 224 | #define MCPUID_USER (1 << ('U' - 'A')) 225 | #define MCPUID_I (1 << ('I' - 'A')) 226 | #define MCPUID_M (1 << ('M' - 'A')) 227 | #define MCPUID_A (1 << ('A' - 'A')) 228 | #define MCPUID_F (1 << ('F' - 'A')) 229 | #define MCPUID_D (1 << ('D' - 'A')) 230 | #define MCPUID_Q (1 << ('Q' - 'A')) 231 | #define MCPUID_C (1 << ('C' - 'A')) 232 | 233 | #define MIP_USIP (1 << 0) 234 | #define MIP_SSIP (1 << 1) 235 | #define MIP_HSIP (1 << 2) 236 | #define MIP_MSIP (1 << 3) 237 | #define MIP_UTIP (1 << 4) 238 | #define MIP_STIP (1 << 5) 239 | #define MIP_HTIP (1 << 6) 240 | #define MIP_MTIP (1 << 7) 241 | #define MIP_UEIP (1 << 8) 242 | #define MIP_SEIP (1 << 9) 243 | #define MIP_HEIP (1 << 10) 244 | #define MIP_MEIP (1 << 11) 245 | 246 | /* mstatus CSR */ 247 | #define MSTATUS_SPIE_SHIFT 5 248 | #define MSTATUS_MPIE_SHIFT 7 249 | #define MSTATUS_SPP_SHIFT 8 250 | #define MSTATUS_MPP_SHIFT 11 251 | #define MSTATUS_FS_SHIFT 13 252 | #define MSTATUS_UXL_SHIFT 32 253 | #define MSTATUS_SXL_SHIFT 34 254 | 255 | #define MSTATUS_UIE (1 << 0) 256 | #define MSTATUS_SIE (1 << 1) 257 | #define MSTATUS_HIE (1 << 2) 258 | #define MSTATUS_MIE (1 << 3) 259 | #define MSTATUS_UPIE (1 << 4) 260 | #define MSTATUS_SPIE (1 << MSTATUS_SPIE_SHIFT) 261 | #define MSTATUS_HPIE (1 << 6) 262 | #define MSTATUS_MPIE (1 << MSTATUS_MPIE_SHIFT) 263 | #define MSTATUS_SPP (1 << MSTATUS_SPP_SHIFT) 264 | #define MSTATUS_HPP (3 << 9) 265 | #define MSTATUS_MPP (3 << MSTATUS_MPP_SHIFT) 266 | #define MSTATUS_FS (3 << MSTATUS_FS_SHIFT) 267 | #define MSTATUS_XS (3 << 15) 268 | #define MSTATUS_MPRV (1 << 17) 269 | #define MSTATUS_SUM (1 << 18) 270 | #define MSTATUS_MXR (1 << 19) 271 | #define MSTATUS_UXL_MASK ((uint64_t) 3 << MSTATUS_UXL_SHIFT) 272 | #define MSTATUS_SXL_MASK ((uint64_t) 3 << MSTATUS_SXL_SHIFT) 273 | 274 | static inline int ctz32(uint32_t val) 275 | { 276 | #if defined(__GNUC__) && __GNUC__ >= 4 277 | return val ? __builtin_ctz(val) : 32; 278 | #else 279 | /* Binary search for the trailing one bit. */ 280 | int cnt; 281 | cnt = 0; 282 | if (!(val & 0x0000FFFFUL)) { 283 | cnt += 16; 284 | val >>= 16; 285 | } 286 | if (!(val & 0x000000FFUL)) { 287 | cnt += 8; 288 | val >>= 8; 289 | } 290 | if (!(val & 0x0000000FUL)) { 291 | cnt += 4; 292 | val >>= 4; 293 | } 294 | if (!(val & 0x00000003UL)) { 295 | cnt += 2; 296 | val >>= 2; 297 | } 298 | if (!(val & 0x00000001UL)) { 299 | cnt++; 300 | val >>= 1; 301 | } 302 | if (!(val & 0x00000001UL)) { 303 | cnt++; 304 | } 305 | return cnt; 306 | #endif 307 | } 308 | 309 | #define SSTATUS_MASK0 \ 310 | (MSTATUS_UIE | MSTATUS_SIE | MSTATUS_UPIE | MSTATUS_SPIE | MSTATUS_SPP | \ 311 | MSTATUS_FS | MSTATUS_XS | MSTATUS_SUM | MSTATUS_MXR) 312 | #define SSTATUS_MASK SSTATUS_MASK0 313 | 314 | 315 | #define MSTATUS_MASK \ 316 | (MSTATUS_UIE | MSTATUS_SIE | MSTATUS_MIE | MSTATUS_UPIE | MSTATUS_SPIE | \ 317 | MSTATUS_MPIE | MSTATUS_SPP | MSTATUS_MPP | MSTATUS_FS | MSTATUS_MPRV | \ 318 | MSTATUS_SUM | MSTATUS_MXR) 319 | 320 | /* cycle and insn counters */ 321 | #define COUNTEREN_MASK ((1 << 0) | (1 << 2)) 322 | 323 | /* return the complete mstatus with the SD bit */ 324 | uint32_t get_mstatus(uint32_t mask) 325 | { 326 | uint32_t val; 327 | int sd; 328 | val = mstatus | (fs << MSTATUS_FS_SHIFT); 329 | val &= mask; 330 | sd = 331 | ((val & MSTATUS_FS) == MSTATUS_FS) | ((val & MSTATUS_XS) == MSTATUS_XS); 332 | if (sd) 333 | val |= (uint32_t) 1 << (XLEN - 1); 334 | return val; 335 | } 336 | 337 | void set_mstatus(uint32_t val) 338 | { 339 | fs = (val >> MSTATUS_FS_SHIFT) & 3; 340 | 341 | uint32_t mask = MSTATUS_MASK & ~MSTATUS_FS; 342 | mstatus = (mstatus & ~mask) | (val & mask); 343 | } 344 | 345 | void invalid_csr(uint32_t *pval, uint32_t csr) 346 | { 347 | /* the 'time' counter is usually emulated */ 348 | if (csr != 0xc01 && csr != 0xc81) { 349 | debug_out("csr_read: invalid CSR=0x%x\n", csr); 350 | } 351 | *pval = 0; 352 | } 353 | 354 | /* return -1 if invalid CSR. 0 if OK. 'will_write' indicate that the 355 | csr will be written after (used for CSR access check) */ 356 | int csr_read(uint32_t *pval, uint32_t csr, int will_write) 357 | { 358 | uint32_t val; 359 | 360 | #ifdef DEBUG_EXTRA 361 | printf("csr_read: csr=0x%03x %i\n", csr, will_write); 362 | #endif 363 | 364 | if (((csr & 0xc00) == 0xc00) && will_write) 365 | return -1; /* read-only CSR */ 366 | if (priv < ((csr >> 8) & 3)) 367 | return -1; /* not enough priviledge */ 368 | 369 | switch (csr) { 370 | case 0xc00: /* cycle */ 371 | case 0xc02: /* instret */ 372 | { 373 | uint32_t counteren; 374 | if (priv < PRV_M) { 375 | if (priv < PRV_S) 376 | counteren = scounteren; 377 | else 378 | counteren = mcounteren; 379 | if (((counteren >> (csr & 0x1f)) & 1) == 0) { 380 | invalid_csr(pval, csr); 381 | return -1; 382 | } 383 | } 384 | } 385 | val = (int64_t) insn_counter; 386 | break; 387 | case 0xc80: /* cycleh */ 388 | case 0xc82: /* instreth */ 389 | { 390 | uint32_t counteren; 391 | if (priv < PRV_M) { 392 | if (priv < PRV_S) 393 | counteren = scounteren; 394 | else 395 | counteren = mcounteren; 396 | if (((counteren >> (csr & 0x1f)) & 1) == 0) { 397 | invalid_csr(pval, csr); 398 | return -1; 399 | } 400 | } 401 | } 402 | val = insn_counter >> 32; 403 | break; 404 | 405 | case 0x100: 406 | val = get_mstatus(SSTATUS_MASK); 407 | break; 408 | case 0x104: /* sie */ 409 | val = mie & mideleg; 410 | break; 411 | case 0x105: 412 | val = stvec; 413 | break; 414 | case 0x106: 415 | val = scounteren; 416 | break; 417 | case 0x140: 418 | val = sscratch; 419 | break; 420 | case 0x141: 421 | val = sepc; 422 | break; 423 | case 0x142: 424 | val = scause; 425 | break; 426 | case 0x143: 427 | val = stval; 428 | break; 429 | case 0x144: /* sip */ 430 | val = mip & mideleg; 431 | break; 432 | case 0x180: 433 | val = satp; 434 | break; 435 | case 0x300: 436 | val = get_mstatus((uint32_t) -1); 437 | break; 438 | case 0x301: 439 | val = misa; 440 | val |= (uint32_t) mxl << (XLEN - 2); 441 | break; 442 | case 0x302: 443 | val = medeleg; 444 | break; 445 | case 0x303: 446 | val = mideleg; 447 | break; 448 | case 0x304: 449 | val = mie; 450 | break; 451 | case 0x305: 452 | val = mtvec; 453 | break; 454 | case 0x306: 455 | val = mcounteren; 456 | break; 457 | case 0x340: 458 | val = mscratch; 459 | break; 460 | case 0x341: 461 | val = mepc; 462 | break; 463 | case 0x342: 464 | val = mcause; 465 | break; 466 | case 0x343: 467 | val = mtval; 468 | break; 469 | case 0x344: 470 | val = mip; 471 | break; 472 | case 0xb00: /* mcycle */ 473 | case 0xb02: /* minstret */ 474 | val = (int64_t) insn_counter; 475 | break; 476 | case 0xb80: /* mcycleh */ 477 | case 0xb82: /* minstreth */ 478 | val = insn_counter >> 32; 479 | break; 480 | case 0xf14: 481 | val = mhartid; 482 | break; 483 | default: 484 | invalid_csr(pval, csr); 485 | /* return -1; */ 486 | return 0; 487 | } 488 | 489 | #ifdef DEBUG_EXTRA 490 | printf("csr_read: csr=0x%03x --> 0x%08x\n", csr, val); 491 | #endif 492 | 493 | *pval = val; 494 | return 0; 495 | } 496 | 497 | /* return -1 if invalid CSR, 0 if OK, 1 if the interpreter loop must be 498 | exited (e.g. XLEN was modified), 2 if TLBs have been flushed. */ 499 | int csr_write(uint32_t csr, uint32_t val) 500 | { 501 | uint32_t mask; 502 | #ifdef DEBUG_EXTRA 503 | printf("csr_write: csr=0x%03x val=0x%08x\n", csr, val); 504 | #endif 505 | switch (csr) { 506 | case 0x100: /* sstatus */ 507 | set_mstatus((mstatus & ~SSTATUS_MASK) | (val & SSTATUS_MASK)); 508 | break; 509 | case 0x104: /* sie */ 510 | mask = mideleg; 511 | mie = (mie & ~mask) | (val & mask); 512 | break; 513 | case 0x105: 514 | stvec = val & ~3; 515 | break; 516 | case 0x106: 517 | scounteren = val & COUNTEREN_MASK; 518 | break; 519 | case 0x140: 520 | sscratch = val; 521 | break; 522 | case 0x141: 523 | sepc = val & ~1; 524 | break; 525 | case 0x142: 526 | scause = val; 527 | break; 528 | case 0x143: 529 | stval = val; 530 | break; 531 | case 0x144: /* sip */ 532 | mask = mideleg; 533 | mip = (mip & ~mask) | (val & mask); 534 | break; 535 | case 0x180: /* no ASID implemented */ 536 | { 537 | int new_mode; 538 | new_mode = (val >> 31) & 1; 539 | satp = (val & (((uint32_t) 1 << 22) - 1)) | (new_mode << 31); 540 | } 541 | return 2; 542 | 543 | case 0x300: 544 | set_mstatus(val); 545 | break; 546 | case 0x301: /* misa */ 547 | break; 548 | case 0x302: 549 | mask = (1 << (CAUSE_STORE_PAGE_FAULT + 1)) - 1; 550 | medeleg = (medeleg & ~mask) | (val & mask); 551 | break; 552 | case 0x303: 553 | mask = MIP_SSIP | MIP_STIP | MIP_SEIP; 554 | mideleg = (mideleg & ~mask) | (val & mask); 555 | break; 556 | case 0x304: 557 | mask = MIP_MSIP | MIP_MTIP | MIP_SSIP | MIP_STIP | MIP_SEIP; 558 | mie = (mie & ~mask) | (val & mask); 559 | break; 560 | case 0x305: 561 | mtvec = val & ~3; 562 | break; 563 | case 0x306: 564 | mcounteren = val & COUNTEREN_MASK; 565 | break; 566 | case 0x340: 567 | mscratch = val; 568 | break; 569 | case 0x341: 570 | mepc = val & ~1; 571 | break; 572 | case 0x342: 573 | mcause = val; 574 | break; 575 | case 0x343: 576 | mtval = val; 577 | break; 578 | case 0x344: 579 | mask = MIP_SSIP | MIP_STIP; 580 | mip = (mip & ~mask) | (val & mask); 581 | break; 582 | default: 583 | return 0; 584 | /* return -1; */ 585 | } 586 | return 0; 587 | } 588 | 589 | void handle_sret() 590 | { 591 | int spp, spie; 592 | spp = (mstatus >> MSTATUS_SPP_SHIFT) & 1; 593 | /* set the IE state to previous IE state */ 594 | spie = (mstatus >> MSTATUS_SPIE_SHIFT) & 1; 595 | mstatus = (mstatus & ~(1 << spp)) | (spie << spp); 596 | /* set SPIE to 1 */ 597 | mstatus |= MSTATUS_SPIE; 598 | /* set SPP to U */ 599 | mstatus &= ~MSTATUS_SPP; 600 | priv = spp; 601 | next_pc = sepc; 602 | } 603 | 604 | void handle_mret() 605 | { 606 | int mpp, mpie; 607 | mpp = (mstatus >> MSTATUS_MPP_SHIFT) & 3; 608 | /* set the IE state to previous IE state */ 609 | mpie = (mstatus >> MSTATUS_MPIE_SHIFT) & 1; 610 | mstatus = (mstatus & ~(1 << mpp)) | (mpie << mpp); 611 | /* set MPIE to 1 */ 612 | mstatus |= MSTATUS_MPIE; 613 | /* set MPP to U */ 614 | mstatus &= ~MSTATUS_MPP; 615 | priv = mpp; 616 | next_pc = mepc; 617 | } 618 | 619 | void raise_exception(uint32_t cause, uint32_t tval) 620 | { 621 | int deleg; 622 | 623 | /* exit for Zephyr applications */ 624 | if (cause == CAUSE_ILLEGAL_INSTRUCTION) { 625 | debug_out("raise_exception: illegal instruction 0x%x 0x%x\n", cause, 626 | tval); 627 | machine_running = FALSE; 628 | return; 629 | } 630 | 631 | if (priv <= PRV_S) { 632 | /* delegate the exception to the supervisor priviledge */ 633 | if (cause & CAUSE_INTERRUPT) 634 | deleg = (mideleg >> (cause & (XLEN - 1))) & 1; 635 | else 636 | deleg = (medeleg >> cause) & 1; 637 | } else { 638 | deleg = 0; 639 | } 640 | 641 | if (deleg) { 642 | scause = cause; 643 | sepc = pc; 644 | stval = tval; 645 | mstatus = (mstatus & ~MSTATUS_SPIE) | 646 | (((mstatus >> priv) & 1) << MSTATUS_SPIE_SHIFT); 647 | mstatus = (mstatus & ~MSTATUS_SPP) | (priv << MSTATUS_SPP_SHIFT); 648 | mstatus &= ~MSTATUS_SIE; 649 | priv = PRV_S; 650 | next_pc = stvec; 651 | } else { 652 | mcause = cause; 653 | mepc = pc; 654 | mtval = tval; 655 | mstatus = (mstatus & ~MSTATUS_MPIE) | 656 | (((mstatus >> priv) & 1) << MSTATUS_MPIE_SHIFT); 657 | mstatus = (mstatus & ~MSTATUS_MPP) | (priv << MSTATUS_MPP_SHIFT); 658 | mstatus &= ~MSTATUS_MIE; 659 | priv = PRV_M; 660 | next_pc = mtvec; 661 | } 662 | } 663 | 664 | uint32_t get_pending_irq_mask() 665 | { 666 | uint32_t pending_ints, enabled_ints; 667 | 668 | pending_ints = mip & mie; 669 | if (pending_ints == 0) 670 | return 0; 671 | 672 | enabled_ints = 0; 673 | switch (priv) { 674 | case PRV_M: 675 | if (mstatus & MSTATUS_MIE) 676 | enabled_ints = ~mideleg; 677 | break; 678 | case PRV_S: 679 | enabled_ints = ~mideleg; 680 | if (mstatus & MSTATUS_SIE) 681 | enabled_ints |= mideleg; 682 | break; 683 | default: 684 | case PRV_U: 685 | enabled_ints = -1; 686 | break; 687 | } 688 | return pending_ints & enabled_ints; 689 | } 690 | 691 | int raise_interrupt() 692 | { 693 | uint32_t mask; 694 | int irq_num; 695 | 696 | mask = get_pending_irq_mask(); 697 | if (mask == 0) 698 | return 0; 699 | irq_num = ctz32(mask); 700 | raise_exception(irq_num | CAUSE_INTERRUPT, 0); 701 | return -1; 702 | } 703 | 704 | /* read 32-bit instruction from memory by PC */ 705 | 706 | uint32_t get_insn32(uint32_t pc) 707 | { 708 | #ifdef DEBUG_EXTRA 709 | if (pc && pc < minmemr) 710 | minmemr = pc; 711 | if (pc + 3 > maxmemr) 712 | maxmemr = pc + 3; 713 | #endif 714 | uint32_t ptr = pc - ram_start; 715 | if (ptr > RAM_SIZE) 716 | return 1; 717 | uint8_t *p = ram + ptr; 718 | return p[0] | (p[1] << 8) | (p[2] << 16) | (p[3] << 24); 719 | } 720 | 721 | /* read 8-bit data from memory */ 722 | 723 | int target_read_u8(uint8_t *pval, uint32_t addr) 724 | { 725 | #ifdef DEBUG_EXTRA 726 | if ((addr >> 28) != 4 && addr < minmemr) 727 | minmemr = addr; 728 | if (addr > maxmemr) 729 | maxmemr = addr; 730 | #endif 731 | addr -= ram_start; 732 | if (addr > RAM_SIZE) { 733 | *pval = 0; 734 | printf("illegal read 8, PC: 0x%08x, address: 0x%08x\n", pc, 735 | addr + ram_start); 736 | return 1; 737 | } else { 738 | uint8_t *p = ram + addr; 739 | *pval = p[0]; 740 | } 741 | return 0; 742 | } 743 | 744 | /* read 16-bit data from memory */ 745 | 746 | int target_read_u16(uint16_t *pval, uint32_t addr) 747 | { 748 | #ifdef DEBUG_EXTRA 749 | if ((addr >> 28) != 4 && addr < minmemr) 750 | minmemr = addr; 751 | if (addr + 1 > maxmemr) 752 | maxmemr = addr + 1; 753 | #endif 754 | if (addr & 1) { 755 | pending_exception = CAUSE_MISALIGNED_LOAD; 756 | pending_tval = addr; 757 | return 1; 758 | } 759 | addr -= ram_start; 760 | if (addr > RAM_SIZE) { 761 | *pval = 0; 762 | printf("illegal read 16, PC: 0x%08x, address: 0x%08x\n", pc, 763 | addr + ram_start); 764 | return 1; 765 | } else { 766 | uint8_t *p = ram + addr; 767 | *pval = p[0] | (p[1] << 8); 768 | } 769 | return 0; 770 | } 771 | 772 | /* read 32-bit data from memory */ 773 | 774 | int target_read_u32(uint32_t *pval, uint32_t addr) 775 | { 776 | #ifdef DEBUG_EXTRA 777 | if ((addr >> 28) != 4 && addr < minmemr) 778 | minmemr = addr; 779 | if (addr + 3 > maxmemr) 780 | maxmemr = addr + 3; 781 | #endif 782 | if (addr & 3) { 783 | pending_exception = CAUSE_MISALIGNED_LOAD; 784 | pending_tval = addr; 785 | return 1; 786 | } 787 | if (addr == MTIMECMP_ADDR) { 788 | *pval = (uint32_t) mtimecmp; 789 | } else if (addr == MTIMECMP_ADDR + 4) { 790 | *pval = (uint32_t)(mtimecmp >> 32); 791 | } else if (addr == MTIME_ADDR) { 792 | *pval = (uint32_t) mtime; 793 | } else if (addr == MTIME_ADDR + 4) { 794 | *pval = (uint32_t)(mtime >> 32); 795 | } else { 796 | addr -= ram_start; 797 | if (addr > RAM_SIZE) { 798 | *pval = 0; 799 | printf("illegal read 32, PC: 0x%08x, address: 0x%08x\n", pc, 800 | addr + ram_start); 801 | return 1; 802 | } else { 803 | uint8_t *p = ram + addr; 804 | *pval = p[0] | (p[1] << 8) | (p[2] << 16) | (p[3] << 24); 805 | } 806 | } 807 | return 0; 808 | } 809 | 810 | /* write 8-bit data to memory */ 811 | 812 | int target_write_u8(uint32_t addr, uint8_t val) 813 | { 814 | #ifdef DEBUG_EXTRA 815 | if ((addr >> 28) != 4 && addr < minmemw) 816 | minmemw = addr; 817 | if (addr > maxmemw) 818 | maxmemw = addr; 819 | #endif 820 | if (addr == UART_TX_ADDR) { 821 | /* test for UART output, compatible with QEMU */ 822 | printf("%c", val); 823 | } else { 824 | addr -= ram_start; 825 | if (addr > RAM_SIZE - 1) { 826 | printf("illegal write 8, PC: 0x%08x, address: 0x%08x\n", pc, 827 | addr + ram_start); 828 | return 1; 829 | } else { 830 | uint8_t *p = ram + addr; 831 | p[0] = val & 0xff; 832 | } 833 | } 834 | return 0; 835 | } 836 | 837 | /* write 16-bit data to memory */ 838 | 839 | int target_write_u16(uint32_t addr, uint16_t val) 840 | { 841 | #ifdef DEBUG_EXTRA 842 | if ((addr >> 28) != 4 && addr < minmemw) 843 | minmemw = addr; 844 | if (addr + 1 > maxmemw) 845 | maxmemw = addr + 1; 846 | #endif 847 | if (addr & 1) { 848 | pending_exception = CAUSE_MISALIGNED_STORE; 849 | pending_tval = addr; 850 | return 1; 851 | } 852 | addr -= ram_start; 853 | if (addr > RAM_SIZE - 2) { 854 | printf("illegal write 16, PC: 0x%08x, address: 0x%08x\n", pc, 855 | addr + ram_start); 856 | return 1; 857 | } else { 858 | uint8_t *p = ram + addr; 859 | p[0] = val & 0xff; 860 | p[1] = (val >> 8) & 0xff; 861 | } 862 | return 0; 863 | } 864 | 865 | /* write 32-bit data to memory */ 866 | 867 | int target_write_u32(uint32_t addr, uint32_t val) 868 | { 869 | #ifdef DEBUG_EXTRA 870 | if ((addr >> 28) != 4 && addr < minmemw) 871 | minmemw = addr; 872 | if (addr + 3 > maxmemw) 873 | maxmemw = addr + 3; 874 | #endif 875 | if (addr & 3) { 876 | pending_exception = CAUSE_MISALIGNED_STORE; 877 | pending_tval = addr; 878 | return 1; 879 | } 880 | if (addr == MTIMECMP_ADDR) { 881 | mtimecmp = (mtimecmp & 0xffffffff00000000ll) | val; 882 | mip &= ~MIP_MTIP; 883 | } else if (addr == MTIMECMP_ADDR + 4) { 884 | mtimecmp = (mtimecmp & 0xffffffffll) | (((uint64_t) val) << 32); 885 | mip &= ~MIP_MTIP; 886 | } else { 887 | addr -= ram_start; 888 | if (addr > RAM_SIZE - 4) { 889 | printf("illegal write 32, PC: 0x%08x, address: 0x%08x\n", pc, 890 | addr + ram_start); 891 | return 1; 892 | } else { 893 | uint8_t *p = ram + addr; 894 | p[0] = val & 0xff; 895 | p[1] = (val >> 8) & 0xff; 896 | p[2] = (val >> 16) & 0xff; 897 | p[3] = (val >> 24) & 0xff; 898 | } 899 | } 900 | return 0; 901 | } 902 | 903 | #ifndef STRICT_RV32I 904 | 905 | int32_t div32(int32_t a, int32_t b) 906 | { 907 | if (b == 0) { 908 | return -1; 909 | } else if (a == ((int32_t) 1 << (XLEN - 1)) && b == -1) { 910 | return a; 911 | } else { 912 | return a / b; 913 | } 914 | } 915 | 916 | uint32_t divu32(uint32_t a, uint32_t b) 917 | { 918 | if (b == 0) { 919 | return -1; 920 | } 921 | return a / b; 922 | } 923 | 924 | int32_t rem32(int32_t a, int32_t b) 925 | { 926 | if (b == 0) { 927 | return a; 928 | } else if (a == ((int32_t) 1 << (XLEN - 1)) && b == -1) { 929 | return 0; 930 | } 931 | return a % b; 932 | } 933 | 934 | uint32_t remu32(uint32_t a, uint32_t b) 935 | { 936 | if (b == 0) { 937 | return a; 938 | } 939 | return a % b; 940 | } 941 | 942 | static uint32_t mulh32(int32_t a, int32_t b) 943 | { 944 | return ((int64_t) a * (int64_t) b) >> 32; 945 | } 946 | 947 | static uint32_t mulhsu32(int32_t a, uint32_t b) 948 | { 949 | return ((int64_t) a * (int64_t) b) >> 32; 950 | } 951 | 952 | static uint32_t mulhu32(uint32_t a, uint32_t b) 953 | { 954 | return ((int64_t) a * (int64_t) b) >> 32; 955 | } 956 | 957 | #endif 958 | 959 | #ifdef DEBUG_EXTRA 960 | 961 | /* dumps all registers, useful for in-depth debugging */ 962 | 963 | static void dump_regs() 964 | { 965 | printf("\nRegisters:\n"); 966 | printf("x0 zero: %08x\n", reg[0]); 967 | printf("x1 ra: %08x\n", reg[1]); 968 | printf("x2 sp: %08x\n", reg[2]); 969 | printf("x3 gp: %08x\n", reg[3]); 970 | printf("x4 tp: %08x\n", reg[4]); 971 | printf("x5 t0: %08x\n", reg[5]); 972 | printf("x6 t1: %08x\n", reg[6]); 973 | printf("x7 t2: %08x\n", reg[7]); 974 | printf("x8 s0: %08x\n", reg[8]); 975 | printf("x9 s1: %08x\n", reg[9]); 976 | printf("x10 a0: %08x\n", reg[10]); 977 | printf("x11 a1: %08x\n", reg[11]); 978 | printf("x12 a2: %08x\n", reg[12]); 979 | printf("x13 a3: %08x\n", reg[13]); 980 | printf("x14 a4: %08x\n", reg[14]); 981 | printf("x15 a5: %08x\n", reg[15]); 982 | printf("x16 a6: %08x\n", reg[16]); 983 | printf("x17 a7: %08x\n", reg[17]); 984 | printf("x18 s2: %08x\n", reg[18]); 985 | printf("x19 s3: %08x\n", reg[19]); 986 | printf("x20 s4: %08x\n", reg[20]); 987 | printf("x21 s5: %08x\n", reg[21]); 988 | printf("x22 s6: %08x\n", reg[22]); 989 | printf("x23 s7: %08x\n", reg[23]); 990 | printf("x24 s8: %08x\n", reg[24]); 991 | printf("x25 s9: %08x\n", reg[25]); 992 | printf("x26 s10: %08x\n", reg[26]); 993 | printf("x27 s11: %08x\n", reg[27]); 994 | printf("x28 t3: %08x\n", reg[28]); 995 | printf("x29 t4: %08x\n", reg[29]); 996 | printf("x30 t5: %08x\n", reg[30]); 997 | printf("x31 t6: %08x\n", reg[31]); 998 | } 999 | 1000 | #endif 1001 | 1002 | void execute_instruction() 1003 | { 1004 | uint32_t opcode, rd, rs1, rs2, funct3; 1005 | int32_t imm, cond, err; 1006 | uint32_t addr, val = 0, val2; 1007 | 1008 | opcode = insn & 0x7f; 1009 | rd = (insn >> 7) & 0x1f; 1010 | rs1 = (insn >> 15) & 0x1f; 1011 | rs2 = (insn >> 20) & 0x1f; 1012 | 1013 | switch (opcode) { 1014 | case 0x37: /* lui */ 1015 | 1016 | #ifdef DEBUG_EXTRA 1017 | debug_out(">>> LUI\n"); 1018 | stats[0]++; 1019 | #endif 1020 | if (rd != 0) 1021 | reg[rd] = (int32_t)(insn & 0xfffff000); 1022 | break; 1023 | 1024 | case 0x17: /* auipc */ 1025 | 1026 | #ifdef DEBUG_EXTRA 1027 | debug_out(">>> AUIPC\n"); 1028 | stats[1]++; 1029 | #endif 1030 | if (rd != 0) 1031 | reg[rd] = (int32_t)(pc + (int32_t)(insn & 0xfffff000)); 1032 | break; 1033 | 1034 | case 0x6f: /* jal */ 1035 | 1036 | #ifdef DEBUG_EXTRA 1037 | debug_out(">>> JAL\n"); 1038 | stats[2]++; 1039 | #endif 1040 | imm = ((insn >> (31 - 20)) & (1 << 20)) | ((insn >> (21 - 1)) & 0x7fe) | 1041 | ((insn >> (20 - 11)) & (1 << 11)) | (insn & 0xff000); 1042 | imm = (imm << 11) >> 11; 1043 | if (rd != 0) 1044 | reg[rd] = pc + 4; 1045 | next_pc = (int32_t)(pc + imm); 1046 | if (next_pc > pc) 1047 | forward_counter++; 1048 | else 1049 | backward_counter++; 1050 | jump_counter++; 1051 | break; 1052 | 1053 | case 0x67: /* jalr */ 1054 | 1055 | #ifdef DEBUG_EXTRA 1056 | debug_out(">>> JALR\n"); 1057 | stats[3]++; 1058 | #endif 1059 | imm = (int32_t) insn >> 20; 1060 | val = pc + 4; 1061 | next_pc = (int32_t)(reg[rs1] + imm) & ~1; 1062 | if (rd != 0) 1063 | reg[rd] = val; 1064 | if (next_pc > pc) 1065 | forward_counter++; 1066 | else 1067 | backward_counter++; 1068 | jump_counter++; 1069 | break; 1070 | 1071 | case 0x63: /* BRANCH */ 1072 | 1073 | funct3 = (insn >> 12) & 7; 1074 | switch (funct3 >> 1) { 1075 | case 0: /* beq/bne */ 1076 | #ifdef DEBUG_EXTRA 1077 | if (!(funct3 & 1)) { 1078 | debug_out(">>> BEQ\n"); 1079 | stats[4]++; 1080 | } else { 1081 | debug_out(">>> BNE\n"); 1082 | stats[5]++; 1083 | } 1084 | #endif 1085 | cond = (reg[rs1] == reg[rs2]); 1086 | break; 1087 | case 2: /* blt/bge */ 1088 | #ifdef DEBUG_EXTRA 1089 | if (!(funct3 & 1)) { 1090 | debug_out(">>> BLT\n"); 1091 | stats[6]++; 1092 | } else { 1093 | debug_out(">>> BGE\n"); 1094 | stats[7]++; 1095 | } 1096 | #endif 1097 | cond = ((int32_t) reg[rs1] < (int32_t) reg[rs2]); 1098 | break; 1099 | case 3: /* bltu/bgeu */ 1100 | #ifdef DEBUG_EXTRA 1101 | if (!(funct3 & 1)) { 1102 | debug_out(">>> BLTU\n"); 1103 | stats[8]++; 1104 | } else { 1105 | debug_out(">>> BGEU\n"); 1106 | stats[9]++; 1107 | } 1108 | #endif 1109 | cond = (reg[rs1] < reg[rs2]); 1110 | break; 1111 | default: 1112 | raise_exception(CAUSE_ILLEGAL_INSTRUCTION, insn); 1113 | return; 1114 | } 1115 | cond ^= (funct3 & 1); 1116 | if (cond) { 1117 | imm = ((insn >> (31 - 12)) & (1 << 12)) | 1118 | ((insn >> (25 - 5)) & 0x7e0) | ((insn >> (8 - 1)) & 0x1e) | 1119 | ((insn << (11 - 7)) & (1 << 11)); 1120 | imm = (imm << 19) >> 19; 1121 | next_pc = (int32_t)(pc + imm); 1122 | if (next_pc > pc) 1123 | forward_counter++; 1124 | else 1125 | backward_counter++; 1126 | jump_counter++; 1127 | true_counter++; 1128 | break; 1129 | } else 1130 | false_counter++; 1131 | break; 1132 | 1133 | case 0x03: /* LOAD */ 1134 | 1135 | funct3 = (insn >> 12) & 7; 1136 | imm = (int32_t) insn >> 20; 1137 | addr = reg[rs1] + imm; 1138 | switch (funct3) { 1139 | case 0: /* lb */ 1140 | { 1141 | #ifdef DEBUG_EXTRA 1142 | debug_out(">>> LB\n"); 1143 | stats[10]++; 1144 | #endif 1145 | uint8_t rval; 1146 | if (target_read_u8(&rval, addr)) { 1147 | raise_exception(pending_exception, pending_tval); 1148 | return; 1149 | } 1150 | val = (int8_t) rval; 1151 | } break; 1152 | 1153 | case 1: /* lh */ 1154 | { 1155 | #ifdef DEBUG_EXTRA 1156 | debug_out(">>> LH\n"); 1157 | stats[11]++; 1158 | #endif 1159 | uint16_t rval; 1160 | if (target_read_u16(&rval, addr)) { 1161 | raise_exception(pending_exception, pending_tval); 1162 | return; 1163 | } 1164 | val = (int16_t) rval; 1165 | } break; 1166 | 1167 | case 2: /* lw */ 1168 | { 1169 | #ifdef DEBUG_EXTRA 1170 | debug_out(">>> LW\n"); 1171 | stats[12]++; 1172 | #endif 1173 | uint32_t rval; 1174 | if (target_read_u32(&rval, addr)) { 1175 | raise_exception(pending_exception, pending_tval); 1176 | return; 1177 | } 1178 | val = (int32_t) rval; 1179 | } break; 1180 | 1181 | case 4: /* lbu */ 1182 | { 1183 | #ifdef DEBUG_EXTRA 1184 | debug_out(">>> LBU\n"); 1185 | stats[13]++; 1186 | #endif 1187 | uint8_t rval; 1188 | if (target_read_u8(&rval, addr)) { 1189 | raise_exception(pending_exception, pending_tval); 1190 | return; 1191 | } 1192 | val = rval; 1193 | } break; 1194 | 1195 | case 5: /* lhu */ 1196 | { 1197 | #ifdef DEBUG_EXTRA 1198 | debug_out(">>> LHU\n"); 1199 | stats[14]++; 1200 | #endif 1201 | uint16_t rval; 1202 | if (target_read_u16(&rval, addr)) { 1203 | raise_exception(pending_exception, pending_tval); 1204 | return; 1205 | } 1206 | val = rval; 1207 | } break; 1208 | 1209 | default: 1210 | raise_exception(CAUSE_ILLEGAL_INSTRUCTION, insn); 1211 | return; 1212 | } 1213 | if (rd != 0) 1214 | reg[rd] = val; 1215 | break; 1216 | 1217 | case 0x23: /* STORE */ 1218 | 1219 | funct3 = (insn >> 12) & 7; 1220 | imm = rd | ((insn >> (25 - 5)) & 0xfe0); 1221 | imm = (imm << 20) >> 20; 1222 | addr = reg[rs1] + imm; 1223 | val = reg[rs2]; 1224 | switch (funct3) { 1225 | case 0: /* sb */ 1226 | #ifdef DEBUG_EXTRA 1227 | debug_out(">>> SB\n"); 1228 | stats[15]++; 1229 | #endif 1230 | if (target_write_u8(addr, val)) { 1231 | raise_exception(pending_exception, pending_tval); 1232 | return; 1233 | } 1234 | break; 1235 | 1236 | case 1: /* sh */ 1237 | #ifdef DEBUG_EXTRA 1238 | debug_out(">>> SH\n"); 1239 | stats[16]++; 1240 | #endif 1241 | if (target_write_u16(addr, val)) { 1242 | raise_exception(pending_exception, pending_tval); 1243 | return; 1244 | } 1245 | break; 1246 | 1247 | case 2: /* sw */ 1248 | #ifdef DEBUG_EXTRA 1249 | debug_out(">>> SW\n"); 1250 | stats[17]++; 1251 | #endif 1252 | if (target_write_u32(addr, val)) { 1253 | raise_exception(pending_exception, pending_tval); 1254 | return; 1255 | } 1256 | break; 1257 | 1258 | default: 1259 | raise_exception(CAUSE_ILLEGAL_INSTRUCTION, insn); 1260 | return; 1261 | } 1262 | break; 1263 | 1264 | case 0x13: /* OP-IMM */ 1265 | 1266 | funct3 = (insn >> 12) & 7; 1267 | imm = (int32_t) insn >> 20; 1268 | switch (funct3) { 1269 | case 0: /* addi */ 1270 | #ifdef DEBUG_EXTRA 1271 | debug_out(">>> ADDI\n"); 1272 | stats[18]++; 1273 | if (rs1 == 0) 1274 | stats[47]++; /* li */ 1275 | #endif 1276 | val = (int32_t)(reg[rs1] + imm); 1277 | break; 1278 | case 1: /* slli */ 1279 | #ifdef DEBUG_EXTRA 1280 | debug_out(">>> SLLI\n"); 1281 | stats[24]++; 1282 | #endif 1283 | if ((imm & ~(XLEN - 1)) != 0) { 1284 | raise_exception(CAUSE_ILLEGAL_INSTRUCTION, insn); 1285 | return; 1286 | } 1287 | val = (int32_t)(reg[rs1] << (imm & (XLEN - 1))); 1288 | break; 1289 | case 2: /* slti */ 1290 | #ifdef DEBUG_EXTRA 1291 | debug_out(">>> SLTI\n"); 1292 | stats[19]++; 1293 | #endif 1294 | val = (int32_t) reg[rs1] < (int32_t) imm; 1295 | break; 1296 | case 3: /* sltiu */ 1297 | #ifdef DEBUG_EXTRA 1298 | debug_out(">>> SLTIU\n"); 1299 | stats[20]++; 1300 | #endif 1301 | val = reg[rs1] < (uint32_t) imm; 1302 | break; 1303 | case 4: /* xori */ 1304 | #ifdef DEBUG_EXTRA 1305 | debug_out(">>> XORI\n"); 1306 | stats[21]++; 1307 | #endif 1308 | val = reg[rs1] ^ imm; 1309 | break; 1310 | case 5: /* srli/srai */ 1311 | if ((imm & ~((XLEN - 1) | 0x400)) != 0) { 1312 | raise_exception(CAUSE_ILLEGAL_INSTRUCTION, insn); 1313 | return; 1314 | } 1315 | if (imm & 0x400) { 1316 | #ifdef DEBUG_EXTRA 1317 | debug_out(">>> SRAI\n"); 1318 | stats[26]++; 1319 | #endif 1320 | val = (int32_t) reg[rs1] >> (imm & (XLEN - 1)); 1321 | } else { 1322 | #ifdef DEBUG_EXTRA 1323 | debug_out(">>> SRLI\n"); 1324 | stats[25]++; 1325 | #endif 1326 | val = (int32_t)((uint32_t) reg[rs1] >> (imm & (XLEN - 1))); 1327 | } 1328 | break; 1329 | case 6: /* ori */ 1330 | #ifdef DEBUG_EXTRA 1331 | debug_out(">>> ORI\n"); 1332 | stats[22]++; 1333 | #endif 1334 | val = reg[rs1] | imm; 1335 | break; 1336 | case 7: /* andi */ 1337 | #ifdef DEBUG_EXTRA 1338 | debug_out(">>> ANDI\n"); 1339 | stats[23]++; 1340 | #endif 1341 | val = reg[rs1] & imm; 1342 | break; 1343 | } 1344 | if (rd != 0) 1345 | reg[rd] = val; 1346 | break; 1347 | 1348 | case 0x33: /* OP */ 1349 | 1350 | imm = insn >> 25; 1351 | val = reg[rs1]; 1352 | val2 = reg[rs2]; 1353 | #ifndef STRICT_RV32I 1354 | if (imm == 1) { 1355 | funct3 = (insn >> 12) & 7; 1356 | switch (funct3) { 1357 | case 0: /* mul */ 1358 | #ifdef DEBUG_EXTRA 1359 | debug_out(">>> MUL\n"); 1360 | stats[48]++; 1361 | #endif 1362 | val = (int32_t)((int32_t) val * (int32_t) val2); 1363 | break; 1364 | case 1: /* mulh */ 1365 | #ifdef DEBUG_EXTRA 1366 | debug_out(">>> MULH\n"); 1367 | stats[49]++; 1368 | #endif 1369 | val = (int32_t) mulh32(val, val2); 1370 | break; 1371 | case 2: /* mulhsu */ 1372 | #ifdef DEBUG_EXTRA 1373 | debug_out(">>> MULHSU\n"); 1374 | stats[50]++; 1375 | #endif 1376 | val = (int32_t) mulhsu32(val, val2); 1377 | break; 1378 | case 3: /* mulhu */ 1379 | #ifdef DEBUG_EXTRA 1380 | debug_out(">>> MULHU\n"); 1381 | stats[51]++; 1382 | #endif 1383 | val = (int32_t) mulhu32(val, val2); 1384 | break; 1385 | case 4: /* div */ 1386 | #ifdef DEBUG_EXTRA 1387 | debug_out(">>> DIV\n"); 1388 | stats[52]++; 1389 | #endif 1390 | val = div32(val, val2); 1391 | break; 1392 | case 5: /* divu */ 1393 | #ifdef DEBUG_EXTRA 1394 | debug_out(">>> DIVU\n"); 1395 | stats[53]++; 1396 | #endif 1397 | val = (int32_t) divu32(val, val2); 1398 | break; 1399 | case 6: /* rem */ 1400 | #ifdef DEBUG_EXTRA 1401 | debug_out(">>> REM\n"); 1402 | stats[54]++; 1403 | #endif 1404 | val = rem32(val, val2); 1405 | break; 1406 | case 7: /* remu */ 1407 | #ifdef DEBUG_EXTRA 1408 | debug_out(">>> REMU\n"); 1409 | stats[55]++; 1410 | #endif 1411 | val = (int32_t) remu32(val, val2); 1412 | break; 1413 | default: 1414 | raise_exception(CAUSE_ILLEGAL_INSTRUCTION, insn); 1415 | return; 1416 | } 1417 | } else 1418 | #endif 1419 | { 1420 | if (imm & ~0x20) { 1421 | raise_exception(CAUSE_ILLEGAL_INSTRUCTION, insn); 1422 | return; 1423 | } 1424 | funct3 = ((insn >> 12) & 7) | ((insn >> (30 - 3)) & (1 << 3)); 1425 | switch (funct3) { 1426 | case 0: /* add */ 1427 | #ifdef DEBUG_EXTRA 1428 | debug_out(">>> ADD\n"); 1429 | stats[27]++; 1430 | #endif 1431 | val = (int32_t)(val + val2); 1432 | break; 1433 | case 0 | 8: /* sub */ 1434 | #ifdef DEBUG_EXTRA 1435 | debug_out(">>> SUB\n"); 1436 | stats[28]++; 1437 | #endif 1438 | val = (int32_t)(val - val2); 1439 | break; 1440 | case 1: /* sll */ 1441 | #ifdef DEBUG_EXTRA 1442 | debug_out(">>> SLL\n"); 1443 | stats[29]++; 1444 | #endif 1445 | val = (int32_t)(val << (val2 & (XLEN - 1))); 1446 | break; 1447 | case 2: /* slt */ 1448 | #ifdef DEBUG_EXTRA 1449 | debug_out(">>> SLT\n"); 1450 | stats[30]++; 1451 | #endif 1452 | val = (int32_t) val < (int32_t) val2; 1453 | break; 1454 | case 3: /* sltu */ 1455 | #ifdef DEBUG_EXTRA 1456 | debug_out(">>> SLTU\n"); 1457 | stats[31]++; 1458 | #endif 1459 | val = val < val2; 1460 | break; 1461 | case 4: /* xor */ 1462 | #ifdef DEBUG_EXTRA 1463 | debug_out(">>> XOR\n"); 1464 | stats[32]++; 1465 | #endif 1466 | val = val ^ val2; 1467 | break; 1468 | case 5: /* srl */ 1469 | #ifdef DEBUG_EXTRA 1470 | debug_out(">>> SRL\n"); 1471 | stats[33]++; 1472 | #endif 1473 | val = (int32_t)((uint32_t) val >> (val2 & (XLEN - 1))); 1474 | break; 1475 | case 5 | 8: /* sra */ 1476 | #ifdef DEBUG_EXTRA 1477 | debug_out(">>> SRA\n"); 1478 | stats[34]++; 1479 | #endif 1480 | val = (int32_t) val >> (val2 & (XLEN - 1)); 1481 | break; 1482 | case 6: /* or */ 1483 | #ifdef DEBUG_EXTRA 1484 | debug_out(">>> OR\n"); 1485 | stats[35]++; 1486 | #endif 1487 | val = val | val2; 1488 | break; 1489 | case 7: /* and */ 1490 | #ifdef DEBUG_EXTRA 1491 | debug_out(">>> AND\n"); 1492 | stats[36]++; 1493 | #endif 1494 | val = val & val2; 1495 | break; 1496 | default: 1497 | raise_exception(CAUSE_ILLEGAL_INSTRUCTION, insn); 1498 | return; 1499 | } 1500 | } 1501 | if (rd != 0) 1502 | reg[rd] = val; 1503 | break; 1504 | 1505 | case 0x73: /* SYSTEM */ 1506 | 1507 | funct3 = (insn >> 12) & 7; 1508 | imm = insn >> 20; 1509 | if (funct3 & 4) 1510 | val = rs1; 1511 | else 1512 | val = reg[rs1]; 1513 | funct3 &= 3; 1514 | switch (funct3) { 1515 | case 1: /* csrrw & csrrwi */ 1516 | #ifdef DEBUG_EXTRA 1517 | if ((insn >> 12) & 4) { 1518 | debug_out(">>> CSRRWI\n"); 1519 | stats[44]++; 1520 | } else { 1521 | debug_out(">>> CSRRW\n"); 1522 | stats[41]++; 1523 | } 1524 | #endif 1525 | if (csr_read(&val2, imm, TRUE)) { 1526 | raise_exception(CAUSE_ILLEGAL_INSTRUCTION, insn); 1527 | return; 1528 | } 1529 | val2 = (int32_t) val2; 1530 | err = csr_write(imm, val); 1531 | if (err < 0) { 1532 | raise_exception(CAUSE_ILLEGAL_INSTRUCTION, insn); 1533 | return; 1534 | } 1535 | if (rd != 0) 1536 | reg[rd] = val2; 1537 | if (err > 0) { 1538 | /* pc = pc + 4; */ 1539 | } 1540 | break; 1541 | 1542 | case 2: /* csrrs & csrrsi */ 1543 | case 3: /* csrrc & csrrci */ 1544 | if (csr_read(&val2, imm, (rs1 != 0))) { 1545 | raise_exception(CAUSE_ILLEGAL_INSTRUCTION, insn); 1546 | return; 1547 | } 1548 | val2 = (int32_t) val2; 1549 | #ifdef DEBUG_EXTRA 1550 | switch ((insn >> 12) & 7) { 1551 | case 2: 1552 | debug_out(">>> CSRRS\n"); 1553 | stats[42]++; 1554 | break; 1555 | case 3: 1556 | debug_out(">>> CSRRC\n"); 1557 | stats[43]++; 1558 | break; 1559 | case 6: 1560 | debug_out(">>> CSRRSI\n"); 1561 | stats[45]++; 1562 | break; 1563 | case 7: 1564 | debug_out(">>> CSRRCI\n"); 1565 | stats[46]++; 1566 | break; 1567 | } 1568 | #endif 1569 | if (rs1 != 0) { 1570 | if (funct3 == 2) { 1571 | val = val2 | val; 1572 | } else { 1573 | val = val2 & ~val; 1574 | } 1575 | err = csr_write(imm, val); 1576 | if (err < 0) { 1577 | raise_exception(CAUSE_ILLEGAL_INSTRUCTION, insn); 1578 | return; 1579 | } 1580 | } else { 1581 | err = 0; 1582 | } 1583 | if (rd != 0) 1584 | reg[rd] = val2; 1585 | break; 1586 | 1587 | case 0: 1588 | switch (imm) { 1589 | case 0x000: /* ecall */ 1590 | #ifdef DEBUG_EXTRA 1591 | debug_out(">>> ECALL\n"); 1592 | stats[39]++; 1593 | #endif 1594 | if (insn & 0x000fff80) { 1595 | raise_exception(CAUSE_ILLEGAL_INSTRUCTION, insn); 1596 | return; 1597 | } 1598 | /* 1599 | * compliance test specific: if bit 0 of gp (x3) is 0, it is a 1600 | * syscall, otherwise it is the program end, with the exit code 1601 | * in the bits 31:1 1602 | */ 1603 | if (begin_signature) { 1604 | if (reg[3] & 1) { 1605 | debug_out("program end, result: %04x\n", reg[3] >> 1); 1606 | machine_running = FALSE; 1607 | return; 1608 | 1609 | } else { 1610 | debug_out("syscall: %04x\n", reg[3]); 1611 | raise_exception(CAUSE_USER_ECALL + priv, 0); 1612 | } 1613 | } else { 1614 | /* on real hardware, an exception is raised, the I-ECALL-01 1615 | * compliance test tests this as well */ 1616 | raise_exception(CAUSE_USER_ECALL + priv, 0); 1617 | return; 1618 | } 1619 | break; 1620 | 1621 | case 0x001: /* ebreak */ 1622 | #ifdef DEBUG_EXTRA 1623 | debug_out(">>> EBREAK\n"); 1624 | stats[40]++; 1625 | #endif 1626 | if (insn & 0x000fff80) { 1627 | raise_exception(CAUSE_ILLEGAL_INSTRUCTION, insn); 1628 | return; 1629 | } 1630 | raise_exception(CAUSE_BREAKPOINT, 0); 1631 | return; 1632 | 1633 | case 0x102: /* sret */ 1634 | { 1635 | #ifdef DEBUG_EXTRA 1636 | debug_out(">>> SRET\n"); 1637 | stats[59]++; 1638 | #endif 1639 | if ((insn & 0x000fff80) || (priv < PRV_S)) { 1640 | raise_exception(CAUSE_ILLEGAL_INSTRUCTION, insn); 1641 | return; 1642 | } 1643 | handle_sret(); 1644 | return; 1645 | } break; 1646 | 1647 | case 0x105: /* wfi */ 1648 | #ifdef DEBUG_EXTRA 1649 | debug_out(">>> WFI\n"); 1650 | stats[61]++; 1651 | #endif 1652 | /* wait for interrupt: it is allowed to execute it as nop */ 1653 | break; 1654 | 1655 | case 0x302: /* mret */ 1656 | { 1657 | #ifdef DEBUG_EXTRA 1658 | debug_out(">>> MRET\n"); 1659 | stats[60]++; 1660 | #endif 1661 | if ((insn & 0x000fff80) || (priv < PRV_M)) { 1662 | raise_exception(CAUSE_ILLEGAL_INSTRUCTION, insn); 1663 | return; 1664 | } 1665 | handle_mret(); 1666 | return; 1667 | } break; 1668 | 1669 | default: 1670 | if ((imm >> 5) == 0x09) { 1671 | #ifdef DEBUG_EXTRA 1672 | debug_out(">>> SFENCE.VMA\n"); 1673 | stats[62]++; 1674 | #endif 1675 | /* sfence.vma */ 1676 | if ((insn & 0x00007f80) || (priv == PRV_U)) { 1677 | raise_exception(CAUSE_ILLEGAL_INSTRUCTION, insn); 1678 | return; 1679 | } 1680 | } else { 1681 | raise_exception(CAUSE_ILLEGAL_INSTRUCTION, insn); 1682 | return; 1683 | } 1684 | break; 1685 | } 1686 | break; 1687 | 1688 | default: 1689 | raise_exception(CAUSE_ILLEGAL_INSTRUCTION, insn); 1690 | return; 1691 | } 1692 | break; 1693 | 1694 | case 0x0f: /* MISC-MEM */ 1695 | 1696 | funct3 = (insn >> 12) & 7; 1697 | switch (funct3) { 1698 | case 0: /* fence */ 1699 | #ifdef DEBUG_EXTRA 1700 | debug_out(">>> FENCE\n"); 1701 | stats[37]++; 1702 | #endif 1703 | if (insn & 0xf00fff80) { 1704 | raise_exception(CAUSE_ILLEGAL_INSTRUCTION, insn); 1705 | return; 1706 | } 1707 | break; 1708 | 1709 | case 1: /* fence.i */ 1710 | #ifdef DEBUG_EXTRA 1711 | debug_out(">>> FENCE.I\n"); 1712 | stats[38]++; 1713 | #endif 1714 | if (insn != 0x0000100f) { 1715 | raise_exception(CAUSE_ILLEGAL_INSTRUCTION, insn); 1716 | return; 1717 | } 1718 | break; 1719 | 1720 | default: 1721 | raise_exception(CAUSE_ILLEGAL_INSTRUCTION, insn); 1722 | return; 1723 | } 1724 | break; 1725 | 1726 | #ifndef STRICT_RV32I 1727 | 1728 | case 0x2f: /* AMO */ 1729 | 1730 | funct3 = (insn >> 12) & 7; 1731 | switch (funct3) { 1732 | case 2: { 1733 | uint32_t rval; 1734 | 1735 | addr = reg[rs1]; 1736 | funct3 = insn >> 27; 1737 | switch (funct3) { 1738 | case 2: /* lr.w */ 1739 | #ifdef DEBUG_EXTRA 1740 | debug_out(">>> LR.W\n"); 1741 | stats[56]++; 1742 | #endif 1743 | if (rs2 != 0) { 1744 | raise_exception(CAUSE_ILLEGAL_INSTRUCTION, insn); 1745 | return; 1746 | } 1747 | if (target_read_u32(&rval, addr)) { 1748 | raise_exception(pending_exception, pending_tval); 1749 | return; 1750 | } 1751 | val = (int32_t) rval; 1752 | load_res = addr; 1753 | break; 1754 | 1755 | case 3: /* sc.w */ 1756 | #ifdef DEBUG_EXTRA 1757 | debug_out(">>> SC.W\n"); 1758 | stats[57]++; 1759 | #endif 1760 | if (load_res == addr) { 1761 | if (target_write_u32(addr, reg[rs2])) { 1762 | raise_exception(pending_exception, pending_tval); 1763 | return; 1764 | } 1765 | val = 0; 1766 | } else { 1767 | val = 1; 1768 | } 1769 | break; 1770 | 1771 | case 1: /* amiswap.w */ 1772 | case 0: /* amoadd.w */ 1773 | case 4: /* amoxor.w */ 1774 | case 0xc: /* amoand.w */ 1775 | case 0x8: /* amoor.w */ 1776 | case 0x10: /* amomin.w */ 1777 | case 0x14: /* amomax.w */ 1778 | case 0x18: /* amominu.w */ 1779 | case 0x1c: /* amomaxu.w */ 1780 | 1781 | #ifdef DEBUG_EXTRA 1782 | debug_out(">>> AM...\n"); 1783 | stats[63]++; 1784 | #endif 1785 | if (target_read_u32(&rval, addr)) { 1786 | raise_exception(pending_exception, pending_tval); 1787 | return; 1788 | } 1789 | val = (int32_t) rval; 1790 | val2 = reg[rs2]; 1791 | switch (funct3) { 1792 | case 1: /* amiswap.w */ 1793 | break; 1794 | case 0: /* amoadd.w */ 1795 | val2 = (int32_t)(val + val2); 1796 | break; 1797 | case 4: /* amoxor.w */ 1798 | val2 = (int32_t)(val ^ val2); 1799 | break; 1800 | case 0xc: /* amoand.w */ 1801 | val2 = (int32_t)(val & val2); 1802 | break; 1803 | case 0x8: /* amoor.w */ 1804 | val2 = (int32_t)(val | val2); 1805 | break; 1806 | case 0x10: /* amomin.w */ 1807 | if ((int32_t) val < (int32_t) val2) 1808 | val2 = (int32_t) val; 1809 | break; 1810 | case 0x14: /* amomax.w */ 1811 | if ((int32_t) val > (int32_t) val2) 1812 | val2 = (int32_t) val; 1813 | break; 1814 | case 0x18: /* amominu.w */ 1815 | if ((uint32_t) val < (uint32_t) val2) 1816 | val2 = (int32_t) val; 1817 | break; 1818 | case 0x1c: /* amomaxu.w */ 1819 | if ((uint32_t) val > (uint32_t) val2) 1820 | val2 = (int32_t) val; 1821 | break; 1822 | default: 1823 | raise_exception(CAUSE_ILLEGAL_INSTRUCTION, insn); 1824 | return; 1825 | } 1826 | if (target_write_u32(addr, val2)) { 1827 | raise_exception(pending_exception, pending_tval); 1828 | return; 1829 | } 1830 | break; 1831 | default: 1832 | raise_exception(CAUSE_ILLEGAL_INSTRUCTION, insn); 1833 | return; 1834 | } 1835 | } break; 1836 | default: 1837 | raise_exception(CAUSE_ILLEGAL_INSTRUCTION, insn); 1838 | return; 1839 | } 1840 | if (rd != 0) 1841 | reg[rd] = val; 1842 | break; 1843 | 1844 | #endif 1845 | 1846 | default: 1847 | raise_exception(CAUSE_ILLEGAL_INSTRUCTION, insn); 1848 | return; 1849 | } 1850 | } 1851 | 1852 | /* returns realtime in nanoseconds */ 1853 | int64_t get_clock() 1854 | { 1855 | struct timespec ts; 1856 | clock_gettime(CLOCK_MONOTONIC, &ts); 1857 | return ts.tv_sec * 1000000000LL + ts.tv_nsec; 1858 | } 1859 | 1860 | 1861 | void riscv_cpu_interp_x32() 1862 | { 1863 | /* we use a single execution loop to keep a simple control flow for 1864 | * emscripten */ 1865 | while (machine_running) { 1866 | #if 1 1867 | /* update timer, assuming 10 MHz clock (100 ns period) for the mtime 1868 | * counter */ 1869 | mtime = get_clock() / 100ll; 1870 | 1871 | /* for reproducible debug runs, you can use a fixed fixed increment per 1872 | * instruction */ 1873 | #else 1874 | mtime += 10; 1875 | #endif 1876 | /* default value for next PC is next instruction, can be changed by 1877 | * branches or exceptions */ 1878 | next_pc = pc + 4; 1879 | 1880 | /* test for timer interrupt */ 1881 | if (mtimecmp <= mtime) { 1882 | mip |= MIP_MTIP; 1883 | } 1884 | if ((mip & mie) != 0 && (mstatus & MSTATUS_MIE)) { 1885 | raise_interrupt(); 1886 | } else { 1887 | /* normal instruction execution */ 1888 | insn = get_insn32(pc); 1889 | insn_counter++; 1890 | 1891 | debug_out("[%08x]=%08x, mtime: %lx, mtimecmp: %lx\n", pc, insn, 1892 | mtime, mtimecmp); 1893 | execute_instruction(); 1894 | } 1895 | 1896 | /* test for misaligned fetches */ 1897 | if (next_pc & 3) { 1898 | raise_exception(CAUSE_MISALIGNED_FETCH, next_pc); 1899 | } 1900 | 1901 | /* update current PC */ 1902 | pc = next_pc; 1903 | } 1904 | 1905 | debug_out("done interp %lx int=%x mstatus=%lx prv=%d\n", 1906 | (uint64_t) insn_counter, mip & mie, (uint64_t) mstatus, priv); 1907 | } 1908 | 1909 | int main(int argc, char **argv) 1910 | { 1911 | #ifdef DEBUG_OUTPUT 1912 | FILE *fo; 1913 | char *po, hex_file[100]; 1914 | #endif 1915 | 1916 | /* automatic STDOUT flushing, no fflush needed */ 1917 | setvbuf(stdout, NULL, _IONBF, 0); 1918 | 1919 | /* parse command line */ 1920 | const char *elf_file = NULL; 1921 | const char *signature_file = NULL; 1922 | for (int i = 1; i < argc; i++) { 1923 | char *arg = argv[i]; 1924 | if (arg == strstr(arg, "+signature=")) { 1925 | signature_file = arg + 11; 1926 | } else if (arg[0] != '-') { 1927 | elf_file = arg; 1928 | } 1929 | } 1930 | if (elf_file == NULL) { 1931 | printf("missing ELF file\n"); 1932 | return 1; 1933 | } 1934 | 1935 | for (uint32_t u = 0; u < RAM_SIZE; u++) 1936 | ram[u] = 0; 1937 | 1938 | 1939 | #ifdef DEBUG_EXTRA 1940 | init_stats(); 1941 | #endif 1942 | 1943 | 1944 | /* open ELF file */ 1945 | elf_version(EV_CURRENT); 1946 | int fd = open(elf_file, O_RDONLY); 1947 | if (fd == -1) { 1948 | printf("can't open file %s\n", elf_file); 1949 | return 1; 1950 | } 1951 | Elf *elf = elf_begin(fd, ELF_C_READ, NULL); 1952 | 1953 | /* scan for symbol table */ 1954 | Elf_Scn *scn = NULL; 1955 | GElf_Shdr shdr; 1956 | while ((scn = elf_nextscn(elf, scn)) != NULL) { 1957 | gelf_getshdr(scn, &shdr); 1958 | if (shdr.sh_type == SHT_SYMTAB) { 1959 | Elf_Data *data = elf_getdata(scn, NULL); 1960 | int count = shdr.sh_size / shdr.sh_entsize; 1961 | for (int i = 0; i < count; i++) { 1962 | GElf_Sym sym; 1963 | gelf_getsym(data, i, &sym); 1964 | char *name = elf_strptr(elf, shdr.sh_link, sym.st_name); 1965 | if (strcmp(name, "begin_signature") == 0) { 1966 | begin_signature = sym.st_value; 1967 | } 1968 | if (strcmp(name, "end_signature") == 0) { 1969 | end_signature = sym.st_value; 1970 | } 1971 | 1972 | /* for compliance test */ 1973 | if (strcmp(name, "_start") == 0) { 1974 | start = sym.st_value; 1975 | } 1976 | 1977 | /* for zephyr */ 1978 | if (strcmp(name, "__reset") == 0) { 1979 | start = sym.st_value; 1980 | } 1981 | if (strcmp(name, "__irq_wrapper") == 0) { 1982 | mtvec = sym.st_value; 1983 | } 1984 | } 1985 | } 1986 | } 1987 | 1988 | /* set .text section as the base address */ 1989 | scn = NULL; 1990 | size_t shstrndx; 1991 | elf_getshdrstrndx(elf, &shstrndx); 1992 | while ((scn = elf_nextscn(elf, scn)) != NULL) { 1993 | gelf_getshdr(scn, &shdr); 1994 | const char *name = elf_strptr(elf, shstrndx, shdr.sh_name); 1995 | 1996 | if (shdr.sh_type == SHT_PROGBITS) { 1997 | if (strcmp(name, ".text") == 0) { 1998 | ram_start = shdr.sh_addr; 1999 | break; 2000 | } 2001 | } 2002 | } 2003 | 2004 | debug_out("begin_signature: 0x%08x\n", begin_signature); 2005 | debug_out("end_signature: 0x%08x\n", end_signature); 2006 | debug_out("ram_start: 0x%08x\n", ram_start); 2007 | debug_out("entry point: 0x%08x\n", start); 2008 | 2009 | /* scan for program */ 2010 | scn = NULL; 2011 | while ((scn = elf_nextscn(elf, scn)) != NULL) { 2012 | gelf_getshdr(scn, &shdr); 2013 | 2014 | /* filter NULL address sections and .bss */ 2015 | if (shdr.sh_addr && shdr.sh_type != SHT_NOBITS) { 2016 | Elf_Data *data = elf_getdata(scn, NULL); 2017 | if (shdr.sh_addr >= ram_start) { 2018 | for (size_t i = 0; i < shdr.sh_size; i++) { 2019 | ram_curr = shdr.sh_addr + i - ram_start; 2020 | if (ram_curr >= RAM_SIZE) { 2021 | debug_out( 2022 | "memory pointer outside of range 0x%08x (section " 2023 | "at address 0x%08x)\n", 2024 | ram_curr, (uint32_t) shdr.sh_addr); 2025 | /* break; */ 2026 | } else { 2027 | ram[ram_curr] = ((uint8_t *) data->d_buf)[i]; 2028 | if (ram_curr > ram_last) 2029 | ram_last = ram_curr; 2030 | } 2031 | } 2032 | } else { 2033 | debug_out("ignoring section at address 0x%08x\n", 2034 | (uint32_t) shdr.sh_addr); 2035 | } 2036 | } 2037 | } 2038 | 2039 | /* close ELF file */ 2040 | elf_end(elf); 2041 | close(fd); 2042 | 2043 | #ifdef DEBUG_OUTPUT 2044 | printf("codesize: 0x%08x (%i)\n", ram_last + 1, ram_last + 1); 2045 | strcpy(hex_file, elf_file); 2046 | po = strrchr(hex_file, '.'); 2047 | if (po != NULL) 2048 | *po = 0; 2049 | strcat(hex_file, ".mem"); 2050 | fo = fopen(hex_file, "wt"); 2051 | if (fo != NULL) { 2052 | for (uint32_t u = 0; u <= ram_last; u++) { 2053 | fprintf(fo, "%02X ", ram[u]); 2054 | if ((u & 15) == 15) 2055 | fprintf(fo, "\n"); 2056 | } 2057 | fprintf(fo, "\n"); 2058 | fclose(fo); 2059 | } 2060 | #if 1 2061 | fo = fopen("rom.v", "wt"); 2062 | if (fo != NULL) { 2063 | fprintf(fo, "module rom(addr,data);\n"); 2064 | uint32_t romsz = (ram_start & 0xFFFF) + ram_last + 1; 2065 | printf("codesize with offset: %i\n", romsz); 2066 | if (romsz >= 32768) 2067 | fprintf(fo, "input [15:0] addr;\n"); 2068 | else if (romsz >= 16384) 2069 | fprintf(fo, "input [14:0] addr;\n"); 2070 | else if (romsz >= 8192) 2071 | fprintf(fo, "input [13:0] addr;\n"); 2072 | else if (romsz >= 4096) 2073 | fprintf(fo, "input [12:0] addr;\n"); 2074 | else if (romsz >= 2048) 2075 | fprintf(fo, "input [11:0] addr;\n"); 2076 | else if (romsz >= 1024) 2077 | fprintf(fo, "input [10:0] addr;\n"); 2078 | else if (romsz >= 512) 2079 | fprintf(fo, "input [9:0] addr;\n"); 2080 | else if (romsz >= 256) 2081 | fprintf(fo, "input [8:0] addr;\n"); 2082 | else 2083 | fprintf(fo, "input [7:0] addr;\n"); 2084 | fprintf(fo, 2085 | "output reg [7:0] data;\nalways @(addr) begin\n case(addr)\n"); 2086 | for (uint32_t u = 0; u <= ram_last; u++) { 2087 | fprintf(fo, " %i : data = 8'h%02X;\n", (ram_start & 0xFFFF) + u, 2088 | ram[u]); 2089 | } 2090 | fprintf(fo, 2091 | " default: data = 8'h01; // invalid instruction\n " 2092 | "endcase\nend\nendmodule\n"); 2093 | fclose(fo); 2094 | } 2095 | #endif 2096 | #endif 2097 | 2098 | uint64_t ns1 = get_clock(); 2099 | 2100 | /* run program in emulator */ 2101 | pc = start; 2102 | reg[2] = ram_start + RAM_SIZE; 2103 | riscv_cpu_interp_x32(); 2104 | 2105 | uint64_t ns2 = get_clock(); 2106 | 2107 | /* write signature */ 2108 | if (signature_file) { 2109 | FILE *sf = fopen(signature_file, "w"); 2110 | int size = end_signature - begin_signature; 2111 | for (int i = 0; i < size / 16; i++) { 2112 | for (int j = 0; j < 16; j++) { 2113 | fprintf(sf, "%02x", ram[begin_signature + 15 - j - ram_start]); 2114 | } 2115 | begin_signature += 16; 2116 | fprintf(sf, "\n"); 2117 | } 2118 | fclose(sf); 2119 | } 2120 | 2121 | #ifdef DEBUG_EXTRA 2122 | dump_regs(); 2123 | print_stats(insn_counter); 2124 | #endif 2125 | 2126 | #if 1 2127 | printf("\n"); 2128 | printf(">>> Execution time: %llu ns\n", (long long unsigned) ns2 - ns1); 2129 | printf(">>> Instruction count: %llu (IPS=%llu)\n", 2130 | (long long unsigned) insn_counter, 2131 | (long long) insn_counter * 1000000000LL / (ns2 - ns1)); 2132 | printf(">>> Jumps: %llu (%2.2lf%%) - %llu forwards, %llu backwards\n", 2133 | (long long unsigned) jump_counter, 2134 | jump_counter * 100.0 / insn_counter, 2135 | (long long unsigned) forward_counter, 2136 | (long long unsigned) backward_counter); 2137 | printf(">>> Branching T=%llu (%2.2lf%%) F=%llu (%2.2lf%%)\n", 2138 | (long long unsigned) true_counter, 2139 | true_counter * 100.0 / (true_counter + false_counter), 2140 | (long long unsigned) false_counter, 2141 | false_counter * 100.0 / (true_counter + false_counter)); 2142 | printf("\n"); 2143 | #endif 2144 | return 0; 2145 | } 2146 | -------------------------------------------------------------------------------- /test1.c: -------------------------------------------------------------------------------- 1 | /* 2 | riscv64-unknown-elf-gcc -march=rv32i -mabi=ilp32 -O3 -nostdlib test1.c -o test1 3 | */ 4 | void _start() 5 | { 6 | volatile char* tx = (volatile char*) 0x40002000; 7 | const char* hello = "Hello RISC-V!\n"; 8 | while (*hello) { 9 | *tx = *hello; 10 | hello++; 11 | } 12 | } 13 | --------------------------------------------------------------------------------