mirror of
https://github.com/PiMaker/rvc.git
synced 2025-02-16 06:50:05 +00:00
support for all necessary CSRs, privilege modes, traps, atomics
...plus some cleanups and debug improvements (single-step mode) All tests specified in test.sh now pass! This pretty much means full compliance with the RV32I base spec, M and A extensions, as well as correct machine, supervisor and user mode traps/switches. Next up is the SV32 MMU and external devices (UART, CLINT timer).
This commit is contained in:
parent
64e2d0b45c
commit
cf50244181
3
.gitmodules
vendored
3
.gitmodules
vendored
@ -4,3 +4,6 @@
|
|||||||
[submodule "riscv-tests"]
|
[submodule "riscv-tests"]
|
||||||
path = riscv-tests
|
path = riscv-tests
|
||||||
url = https://github.com/riscv/riscv-tests
|
url = https://github.com/riscv/riscv-tests
|
||||||
|
[submodule "riscv-rust"]
|
||||||
|
path = riscv-rust
|
||||||
|
url = https://github.com/takahirox/riscv-rust
|
||||||
|
1
riscv-rust
Submodule
1
riscv-rust
Submodule
@ -0,0 +1 @@
|
|||||||
|
Subproject commit b4895fc56b16815d622b088d188ac65d640d25ab
|
20
src/cpu.h
20
src/cpu.h
@ -6,15 +6,29 @@
|
|||||||
#include "types.h"
|
#include "types.h"
|
||||||
#include "mem.h"
|
#include "mem.h"
|
||||||
#include "emu.h"
|
#include "emu.h"
|
||||||
|
#include "csr.h"
|
||||||
|
|
||||||
cpu_t cpu_init(uint8_t *mem) {
|
cpu_t cpu_init(uint8_t *mem) {
|
||||||
cpu_t ret;
|
cpu_t ret;
|
||||||
ret.clock = 0;
|
ret.clock = 0;
|
||||||
for (unsigned char i = 0; i < 32; i++) {
|
for (uint i = 0; i < 32; i++) {
|
||||||
ret.xreg[i] = 0;
|
ret.xreg[i] = 0;
|
||||||
}
|
}
|
||||||
|
ret.xreg[0xb] = 0x1020; // linux?
|
||||||
ret.pc = 0x80000000;
|
ret.pc = 0x80000000;
|
||||||
ret.mem = mem;
|
ret.mem = mem;
|
||||||
|
ret.reservation_en = false;
|
||||||
|
|
||||||
|
init_csrs(&ret);
|
||||||
|
|
||||||
|
ret.debug_single_step =
|
||||||
|
#ifdef SINGLE_STEP
|
||||||
|
true
|
||||||
|
#else
|
||||||
|
false
|
||||||
|
#endif
|
||||||
|
;
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -33,9 +47,7 @@ void cpu_dump(cpu_t *cpu) {
|
|||||||
|
|
||||||
void cpu_tick(cpu_t *cpu) {
|
void cpu_tick(cpu_t *cpu) {
|
||||||
cpu->clock++;
|
cpu->clock++;
|
||||||
|
emulate(cpu);
|
||||||
uint ins_raw = mem_get_word(cpu, cpu->pc);
|
|
||||||
emulate(cpu, ins_raw);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
139
src/csr.h
139
src/csr.h
@ -1,17 +1,142 @@
|
|||||||
#ifndef CSR_H
|
#ifndef CSR_H
|
||||||
#define CSR_H
|
#define CSR_H
|
||||||
|
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include <stdio.h>
|
||||||
#include "types.h"
|
#include "types.h"
|
||||||
|
#include "trap.h"
|
||||||
|
|
||||||
uint get_csr(uint addr) {
|
const uint CSR_USTATUS = 0x000;
|
||||||
// TODO
|
const uint CSR_UIE = 0x004;
|
||||||
printf("CSR read: %x\n", addr);
|
const uint CSR_UTVEC = 0x005;
|
||||||
return 0;
|
const uint _CSR_USCRATCH = 0x040;
|
||||||
|
const uint CSR_UEPC = 0x041;
|
||||||
|
const uint CSR_UCAUSE = 0x042;
|
||||||
|
const uint CSR_UTVAL = 0x043;
|
||||||
|
const uint _CSR_UIP = 0x044;
|
||||||
|
const uint CSR_SSTATUS = 0x100;
|
||||||
|
const uint CSR_SEDELEG = 0x102;
|
||||||
|
const uint CSR_SIDELEG = 0x103;
|
||||||
|
const uint CSR_SIE = 0x104;
|
||||||
|
const uint CSR_STVEC = 0x105;
|
||||||
|
const uint _CSR_SSCRATCH = 0x140;
|
||||||
|
const uint CSR_SEPC = 0x141;
|
||||||
|
const uint CSR_SCAUSE = 0x142;
|
||||||
|
const uint CSR_STVAL = 0x143;
|
||||||
|
const uint CSR_SIP = 0x144;
|
||||||
|
const uint CSR_SATP = 0x180;
|
||||||
|
const uint CSR_MSTATUS = 0x300;
|
||||||
|
const uint CSR_MISA = 0x301;
|
||||||
|
const uint CSR_MEDELEG = 0x302;
|
||||||
|
const uint CSR_MIDELEG = 0x303;
|
||||||
|
const uint CSR_MIE = 0x304;
|
||||||
|
const uint CSR_MTVEC = 0x305;
|
||||||
|
const uint _CSR_MSCRATCH = 0x340;
|
||||||
|
const uint CSR_MEPC = 0x341;
|
||||||
|
const uint CSR_MCAUSE = 0x342;
|
||||||
|
const uint CSR_MTVAL = 0x343;
|
||||||
|
const uint CSR_MIP = 0x344;
|
||||||
|
const uint _CSR_PMPCFG0 = 0x3a0;
|
||||||
|
const uint _CSR_PMPADDR0 = 0x3b0;
|
||||||
|
const uint _CSR_MCYCLE = 0xb00;
|
||||||
|
const uint CSR_CYCLE = 0xc00;
|
||||||
|
const uint CSR_TIME = 0xc01;
|
||||||
|
const uint _CSR_INSERT = 0xc02;
|
||||||
|
const uint CSR_MHARTID = 0xf14;
|
||||||
|
|
||||||
|
bool has_csr_access_privilege(cpu_t *cpu, uint addr) {
|
||||||
|
uint privilege = (addr >> 8) & 0x3;
|
||||||
|
return privilege <= cpu->csr.privilege;
|
||||||
}
|
}
|
||||||
|
|
||||||
void set_csr(uint addr, uint val) {
|
// SSTATUS, SIE, and SIP are subsets of MSTATUS, MIE, and MIP
|
||||||
// TODO
|
uint read_csr_raw(cpu_t *cpu, uint address) {
|
||||||
printf("CSR write: %x <- %x\n", addr, val);
|
switch (address) {
|
||||||
|
case CSR_SSTATUS: return cpu->csr.data[CSR_MSTATUS] & 0x000de162;
|
||||||
|
case CSR_SIE: return cpu->csr.data[CSR_MIE] & 0x222;
|
||||||
|
case CSR_SIP: return cpu->csr.data[CSR_MIP] & 0x222;
|
||||||
|
case CSR_CYCLE: return cpu->clock;
|
||||||
|
case CSR_MHARTID: return 0; // this has to be 0, always
|
||||||
|
/* case CSR_TIME => self.mmu.get_clint().read_mtime(), */
|
||||||
|
default: return cpu->csr.data[address & 0xffff];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void write_csr_raw(cpu_t *cpu, uint address, uint value) {
|
||||||
|
switch (address) {
|
||||||
|
case CSR_SSTATUS:
|
||||||
|
cpu->csr.data[CSR_MSTATUS] &= !0x000de162;
|
||||||
|
cpu->csr.data[CSR_MSTATUS] |= value & 0x000de162;
|
||||||
|
/* self.mmu.update_mstatus(self.read_csr_raw(CSR_MSTATUS)); */
|
||||||
|
break;
|
||||||
|
case CSR_SIE:
|
||||||
|
cpu->csr.data[CSR_MIE] &= !0x222;
|
||||||
|
cpu->csr.data[CSR_MIE] |= value & 0x222;
|
||||||
|
break;
|
||||||
|
case CSR_SIP:
|
||||||
|
cpu->csr.data[CSR_MIP] &= !0x222;
|
||||||
|
cpu->csr.data[CSR_MIP] |= value & 0x222;
|
||||||
|
break;
|
||||||
|
case CSR_MIDELEG:
|
||||||
|
cpu->csr.data[address] = value & 0x666; // from qemu
|
||||||
|
break;
|
||||||
|
/* case CSR_MSTATUS: */
|
||||||
|
/* cpu->csr.data[address] = value; */
|
||||||
|
/* self.mmu.update_mstatus(self.read_csr_raw(CSR_MSTATUS)); */
|
||||||
|
/* break; */
|
||||||
|
/* CSR_TIME => { */
|
||||||
|
/* self.mmu.get_mut_clint().write_mtime(value); */
|
||||||
|
/* }, */
|
||||||
|
default: cpu->csr.data[address] = value; break;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
uint get_csr(cpu_t *cpu, uint address, ins_ret *ret) {
|
||||||
|
if (has_csr_access_privilege(cpu, address)) {
|
||||||
|
uint r = read_csr_raw(cpu, address);
|
||||||
|
#ifdef VERBOSE
|
||||||
|
printf("CSR read @%03x = %08x\n", address, r);
|
||||||
|
#endif
|
||||||
|
return r;
|
||||||
|
} else {
|
||||||
|
ret->trap.en = true;
|
||||||
|
ret->trap.type = trap_IllegalInstruction;
|
||||||
|
ret->trap.value = cpu->pc;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void set_csr(cpu_t *cpu, uint address, uint value, ins_ret *ret) {
|
||||||
|
#ifdef VERBOSE
|
||||||
|
printf("CSR write @%03x = %08x\n", address, value);
|
||||||
|
#endif
|
||||||
|
if (has_csr_access_privilege(cpu, address)) {
|
||||||
|
bool read_only = ((address >> 10) & 0x3) == 0x3;
|
||||||
|
if (read_only) {
|
||||||
|
ret->trap.en = true;
|
||||||
|
ret->trap.type = trap_IllegalInstruction;
|
||||||
|
ret->trap.value = cpu->pc;
|
||||||
|
} else {
|
||||||
|
write_csr_raw(cpu, address, value);
|
||||||
|
if (address == CSR_SATP) {
|
||||||
|
// TODO: update MMU addressing mode
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
ret->trap.en = true;
|
||||||
|
ret->trap.type = trap_IllegalInstruction;
|
||||||
|
ret->trap.value = cpu->pc;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void init_csrs(cpu_t *cpu) {
|
||||||
|
cpu->csr.privilege = PRIV_MACHINE;
|
||||||
|
for (uint i = 0; i < 4096; i++) {
|
||||||
|
cpu->csr.data[i] = 0;
|
||||||
|
}
|
||||||
|
// RV32AIMSU
|
||||||
|
cpu->csr.data[CSR_MISA] = 0b01000000000101000001000100000001;
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
181
src/emu.h
181
src/emu.h
@ -6,6 +6,7 @@
|
|||||||
#include "types.h"
|
#include "types.h"
|
||||||
#include "ins.h"
|
#include "ins.h"
|
||||||
#include "mem.h"
|
#include "mem.h"
|
||||||
|
#include "trap.h"
|
||||||
#include "csr.h"
|
#include "csr.h"
|
||||||
|
|
||||||
#define AS_SIGNED(val) (*(int32_t*)&val)
|
#define AS_SIGNED(val) (*(int32_t*)&val)
|
||||||
@ -16,10 +17,8 @@ const uint ONE = 1;
|
|||||||
#define DEF(name, fmt_t, code) \
|
#define DEF(name, fmt_t, code) \
|
||||||
void emu_##name(cpu_t *cpu, uint ins_word, ins_ret *ret, fmt_t ins) { code }
|
void emu_##name(cpu_t *cpu, uint ins_word, ins_ret *ret, fmt_t ins) { code }
|
||||||
|
|
||||||
#define NOT_IMPL { printf("Unimplemented instruction: %08x\n", ins_word); exit(3); }
|
|
||||||
|
|
||||||
#define WR_RD(code) { ret->write_reg = ins.rd; ret->write_val = AS_UNSIGNED(code); }
|
#define WR_RD(code) { ret->write_reg = ins.rd; ret->write_val = AS_UNSIGNED(code); }
|
||||||
#define WR_PC(code) { ret->pc_write = 1; ret->pc_val = code; }
|
#define WR_PC(code) { ret->pc_val = code; }
|
||||||
#define WR_CSR(code) { ret->csr_write = ins.csr; ret->csr_val = code; }
|
#define WR_CSR(code) { ret->csr_write = ins.csr; ret->csr_val = code; }
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -32,20 +31,54 @@ DEF(add, FormatR, { // rv32i
|
|||||||
DEF(addi, FormatI, { // rv32i
|
DEF(addi, FormatI, { // rv32i
|
||||||
WR_RD(AS_SIGNED(cpu->xreg[ins.rs1]) + AS_SIGNED(ins.imm));
|
WR_RD(AS_SIGNED(cpu->xreg[ins.rs1]) + AS_SIGNED(ins.imm));
|
||||||
})
|
})
|
||||||
|
DEF(amoswap_w, FormatR, { // rv32a
|
||||||
|
uint tmp = mem_get_word(cpu, cpu->xreg[ins.rs1]);
|
||||||
|
mem_set_word(cpu, cpu->xreg[ins.rs1], cpu->xreg[ins.rs2]);
|
||||||
|
WR_RD(tmp)
|
||||||
|
})
|
||||||
DEF(amoadd_w, FormatR, { // rv32a
|
DEF(amoadd_w, FormatR, { // rv32a
|
||||||
NOT_IMPL
|
uint tmp = mem_get_word(cpu, cpu->xreg[ins.rs1]);
|
||||||
|
mem_set_word(cpu, cpu->xreg[ins.rs1], cpu->xreg[ins.rs2] + tmp);
|
||||||
|
WR_RD(tmp)
|
||||||
|
})
|
||||||
|
DEF(amoxor_w, FormatR, { // rv32a
|
||||||
|
uint tmp = mem_get_word(cpu, cpu->xreg[ins.rs1]);
|
||||||
|
mem_set_word(cpu, cpu->xreg[ins.rs1], cpu->xreg[ins.rs2] ^ tmp);
|
||||||
|
WR_RD(tmp)
|
||||||
})
|
})
|
||||||
DEF(amoand_w, FormatR, { // rv32a
|
DEF(amoand_w, FormatR, { // rv32a
|
||||||
NOT_IMPL
|
uint tmp = mem_get_word(cpu, cpu->xreg[ins.rs1]);
|
||||||
})
|
mem_set_word(cpu, cpu->xreg[ins.rs1], cpu->xreg[ins.rs2] & tmp);
|
||||||
DEF(amomaxu_w, FormatR, { // rv32a
|
WR_RD(tmp)
|
||||||
NOT_IMPL
|
|
||||||
})
|
})
|
||||||
DEF(amoor_w, FormatR, { // rv32a
|
DEF(amoor_w, FormatR, { // rv32a
|
||||||
NOT_IMPL
|
uint tmp = mem_get_word(cpu, cpu->xreg[ins.rs1]);
|
||||||
|
mem_set_word(cpu, cpu->xreg[ins.rs1], cpu->xreg[ins.rs2] | tmp);
|
||||||
|
WR_RD(tmp)
|
||||||
})
|
})
|
||||||
DEF(amoswap_w, FormatR, { // rv32a
|
DEF(amomin_w, FormatR, { // rv32a
|
||||||
NOT_IMPL
|
uint tmp = mem_get_word(cpu, cpu->xreg[ins.rs1]);
|
||||||
|
uint sec = cpu->xreg[ins.rs2];
|
||||||
|
mem_set_word(cpu, cpu->xreg[ins.rs1], AS_SIGNED(sec) < AS_SIGNED(tmp) ? sec : tmp);
|
||||||
|
WR_RD(tmp)
|
||||||
|
})
|
||||||
|
DEF(amomax_w, FormatR, { // rv32a
|
||||||
|
uint tmp = mem_get_word(cpu, cpu->xreg[ins.rs1]);
|
||||||
|
uint sec = cpu->xreg[ins.rs2];
|
||||||
|
mem_set_word(cpu, cpu->xreg[ins.rs1], AS_SIGNED(sec) > AS_SIGNED(tmp) ? sec : tmp);
|
||||||
|
WR_RD(tmp)
|
||||||
|
})
|
||||||
|
DEF(amominu_w, FormatR, { // rv32a
|
||||||
|
uint tmp = mem_get_word(cpu, cpu->xreg[ins.rs1]);
|
||||||
|
uint sec = cpu->xreg[ins.rs2];
|
||||||
|
mem_set_word(cpu, cpu->xreg[ins.rs1], sec < tmp ? sec : tmp);
|
||||||
|
WR_RD(tmp)
|
||||||
|
})
|
||||||
|
DEF(amomaxu_w, FormatR, { // rv32a
|
||||||
|
uint tmp = mem_get_word(cpu, cpu->xreg[ins.rs1]);
|
||||||
|
uint sec = cpu->xreg[ins.rs2];
|
||||||
|
mem_set_word(cpu, cpu->xreg[ins.rs1], sec > tmp ? sec : tmp);
|
||||||
|
WR_RD(tmp)
|
||||||
})
|
})
|
||||||
DEF(and, FormatR, { // rv32i
|
DEF(and, FormatR, { // rv32i
|
||||||
WR_RD(cpu->xreg[ins.rs1] & cpu->xreg[ins.rs2])
|
WR_RD(cpu->xreg[ins.rs1] & cpu->xreg[ins.rs2])
|
||||||
@ -87,19 +120,29 @@ DEF(bne, FormatB, { // rv32i
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
DEF(csrrc, FormatCSR, { // system
|
DEF(csrrc, FormatCSR, { // system
|
||||||
WR_CSR(ins.value & (~cpu->xreg[ins.rs]));
|
uint rs = cpu->xreg[ins.rs];
|
||||||
|
if (rs != 0) {
|
||||||
|
WR_CSR(ins.value & ~rs);
|
||||||
|
}
|
||||||
WR_RD(ins.value)
|
WR_RD(ins.value)
|
||||||
})
|
})
|
||||||
DEF(csrrci, FormatCSR, { // system
|
DEF(csrrci, FormatCSR, { // system
|
||||||
WR_CSR(ins.value & (~ins.rs));
|
if (ins.rs != 0) {
|
||||||
|
WR_CSR(ins.value & (~ins.rs));
|
||||||
|
}
|
||||||
WR_RD(ins.value)
|
WR_RD(ins.value)
|
||||||
})
|
})
|
||||||
DEF(csrrs, FormatCSR, { // system
|
DEF(csrrs, FormatCSR, { // system
|
||||||
WR_CSR(ins.value | cpu->xreg[ins.rs]);
|
uint rs = cpu->xreg[ins.rs];
|
||||||
|
if (rs != 0) {
|
||||||
|
WR_CSR(ins.value | rs);
|
||||||
|
}
|
||||||
WR_RD(ins.value)
|
WR_RD(ins.value)
|
||||||
})
|
})
|
||||||
DEF(csrrsi, FormatCSR, { // system
|
DEF(csrrsi, FormatCSR, { // system
|
||||||
WR_CSR(ins.value | ins.rs);
|
if (ins.rs != 0) {
|
||||||
|
WR_CSR(ins.value | ins.rs);
|
||||||
|
}
|
||||||
WR_RD(ins.value)
|
WR_RD(ins.value)
|
||||||
})
|
})
|
||||||
DEF(csrrw, FormatCSR, { // system
|
DEF(csrrw, FormatCSR, { // system
|
||||||
@ -136,7 +179,7 @@ DEF(divu, FormatR, { // rv32m
|
|||||||
WR_RD(result)
|
WR_RD(result)
|
||||||
})
|
})
|
||||||
DEF(ebreak, FormatEmpty, { // system
|
DEF(ebreak, FormatEmpty, { // system
|
||||||
NOT_IMPL
|
// unnecessary?
|
||||||
})
|
})
|
||||||
DEF(ecall, FormatEmpty, { // system
|
DEF(ecall, FormatEmpty, { // system
|
||||||
if (cpu->xreg[17] == 93) {
|
if (cpu->xreg[17] == 93) {
|
||||||
@ -146,7 +189,15 @@ DEF(ecall, FormatEmpty, { // system
|
|||||||
exit(status);
|
exit(status);
|
||||||
}
|
}
|
||||||
|
|
||||||
NOT_IMPL
|
ret->trap.en = true;
|
||||||
|
ret->trap.value = cpu->pc;
|
||||||
|
if (cpu->csr.privilege == PRIV_USER) {
|
||||||
|
ret->trap.type = trap_EnvironmentCallFromUMode;
|
||||||
|
} else if (cpu->csr.privilege == PRIV_SUPERVISOR) {
|
||||||
|
ret->trap.type = trap_EnvironmentCallFromSMode;
|
||||||
|
} else { // PRIV_MACHINE
|
||||||
|
ret->trap.type = trap_EnvironmentCallFromMMode;
|
||||||
|
}
|
||||||
})
|
})
|
||||||
DEF(fence, FormatEmpty, { // rv32i
|
DEF(fence, FormatEmpty, { // rv32i
|
||||||
// skip
|
// skip
|
||||||
@ -179,7 +230,11 @@ DEF(lhu, FormatI, { // rv32i
|
|||||||
WR_RD(tmp)
|
WR_RD(tmp)
|
||||||
})
|
})
|
||||||
DEF(lr_w, FormatR, { // rv32a
|
DEF(lr_w, FormatR, { // rv32a
|
||||||
NOT_IMPL
|
uint addr = cpu->xreg[ins.rs1];
|
||||||
|
uint tmp = mem_get_word(cpu, addr);
|
||||||
|
cpu->reservation_en = true;
|
||||||
|
cpu->reservation_addr = addr;
|
||||||
|
WR_RD(tmp)
|
||||||
})
|
})
|
||||||
DEF(lui, FormatU, { // rv32i
|
DEF(lui, FormatU, { // rv32i
|
||||||
WR_RD(ins.imm)
|
WR_RD(ins.imm)
|
||||||
@ -190,7 +245,17 @@ DEF(lw, FormatI, { // rv32i
|
|||||||
WR_RD(tmp)
|
WR_RD(tmp)
|
||||||
})
|
})
|
||||||
DEF(mret, FormatEmpty, { // system
|
DEF(mret, FormatEmpty, { // system
|
||||||
// skip ? FIXME
|
uint newpc = get_csr(cpu, CSR_MEPC, ret);
|
||||||
|
if (!ret->trap.en) {
|
||||||
|
uint status = read_csr_raw(cpu, CSR_MSTATUS);
|
||||||
|
uint mpie = (status >> 7) & 1;
|
||||||
|
uint mpp = (status >> 11) & 0x3;
|
||||||
|
uint mprv = mpp == PRIV_MACHINE ? ((status >> 17) & 1) : 0;
|
||||||
|
uint new_status = (status & ~0x21888) | (mprv << 17) | (mpie << 3) | (1 << 7);
|
||||||
|
write_csr_raw(cpu, CSR_MSTATUS, new_status);
|
||||||
|
cpu->csr.privilege = mpp;
|
||||||
|
WR_PC(newpc)
|
||||||
|
}
|
||||||
})
|
})
|
||||||
DEF(mul, FormatR, { // rv32m
|
DEF(mul, FormatR, { // rv32m
|
||||||
uint tmp = AS_SIGNED(cpu->xreg[ins.rs1]) * AS_SIGNED(cpu->xreg[ins.rs2]);
|
uint tmp = AS_SIGNED(cpu->xreg[ins.rs1]) * AS_SIGNED(cpu->xreg[ins.rs2]);
|
||||||
@ -243,7 +308,15 @@ DEF(sb, FormatS, { // rv32i
|
|||||||
mem_set_byte(cpu, cpu->xreg[ins.rs1] + ins.imm, cpu->xreg[ins.rs2]);
|
mem_set_byte(cpu, cpu->xreg[ins.rs1] + ins.imm, cpu->xreg[ins.rs2]);
|
||||||
})
|
})
|
||||||
DEF(sc_w, FormatR, { // rv32a
|
DEF(sc_w, FormatR, { // rv32a
|
||||||
NOT_IMPL
|
// I'm pretty sure this is not it chief, but it does the trick for now
|
||||||
|
uint addr = cpu->xreg[ins.rs1];
|
||||||
|
if (cpu->reservation_en && cpu->reservation_addr == addr) {
|
||||||
|
mem_set_word(cpu, addr, cpu->xreg[ins.rs2]);
|
||||||
|
cpu->reservation_en = false;
|
||||||
|
WR_RD(ZERO)
|
||||||
|
} else {
|
||||||
|
WR_RD(ONE)
|
||||||
|
}
|
||||||
})
|
})
|
||||||
DEF(sfence_vma, FormatEmpty, { // system
|
DEF(sfence_vma, FormatEmpty, { // system
|
||||||
// skip
|
// skip
|
||||||
@ -298,7 +371,17 @@ DEF(srai, FormatR, { // rv32i
|
|||||||
cpu->xreg[ins.rs1] >> shamt)
|
cpu->xreg[ins.rs1] >> shamt)
|
||||||
})
|
})
|
||||||
DEF(sret, FormatEmpty, { // system
|
DEF(sret, FormatEmpty, { // system
|
||||||
NOT_IMPL
|
uint newpc = get_csr(cpu, CSR_SEPC, ret);
|
||||||
|
if (!ret->trap.en) {
|
||||||
|
uint status = read_csr_raw(cpu, CSR_SSTATUS);
|
||||||
|
uint spie = (status >> 5) & 1;
|
||||||
|
uint spp = (status >> 8) & 1;
|
||||||
|
uint mprv = spp == PRIV_MACHINE ? ((status >> 17) & 1) : 0;
|
||||||
|
uint new_status = (status & ~0x20122) | (mprv << 17) | (spie << 1) | (1 << 5);
|
||||||
|
write_csr_raw(cpu, CSR_SSTATUS, new_status);
|
||||||
|
cpu->csr.privilege = spp;
|
||||||
|
WR_PC(newpc)
|
||||||
|
}
|
||||||
})
|
})
|
||||||
DEF(srl, FormatR, { // rv32i
|
DEF(srl, FormatR, { // rv32i
|
||||||
WR_RD(cpu->xreg[ins.rs1] >> cpu->xreg[ins.rs2])
|
WR_RD(cpu->xreg[ins.rs1] >> cpu->xreg[ins.rs2])
|
||||||
@ -314,10 +397,10 @@ DEF(sw, FormatS, { // rv32i
|
|||||||
mem_set_word(cpu, cpu->xreg[ins.rs1] + ins.imm, cpu->xreg[ins.rs2]);
|
mem_set_word(cpu, cpu->xreg[ins.rs1] + ins.imm, cpu->xreg[ins.rs2]);
|
||||||
})
|
})
|
||||||
DEF(uret, FormatEmpty, { // system
|
DEF(uret, FormatEmpty, { // system
|
||||||
NOT_IMPL
|
// unnecessary?
|
||||||
})
|
})
|
||||||
DEF(wfi, FormatEmpty, { // system
|
DEF(wfi, FormatEmpty, { // system
|
||||||
NOT_IMPL
|
// no-op is valid here, so skip
|
||||||
})
|
})
|
||||||
DEF(xor, FormatR, { // rv32i
|
DEF(xor, FormatR, { // rv32i
|
||||||
WR_RD(cpu->xreg[ins.rs1] ^ cpu->xreg[ins.rs2])
|
WR_RD(cpu->xreg[ins.rs1] ^ cpu->xreg[ins.rs2])
|
||||||
@ -343,7 +426,7 @@ DEF(xori, FormatI, { // rv32i
|
|||||||
}
|
}
|
||||||
ins_ret ins_select(cpu_t *cpu, uint ins_word) {
|
ins_ret ins_select(cpu_t *cpu, uint ins_word) {
|
||||||
uint ins_masked;
|
uint ins_masked;
|
||||||
ins_ret ret = ins_ret_noop();
|
ins_ret ret = ins_ret_noop(cpu);
|
||||||
|
|
||||||
FormatR ins_FormatR = parse_FormatR(ins_word);
|
FormatR ins_FormatR = parse_FormatR(ins_word);
|
||||||
FormatI ins_FormatI = parse_FormatI(ins_word);
|
FormatI ins_FormatI = parse_FormatI(ins_word);
|
||||||
@ -356,7 +439,7 @@ ins_ret ins_select(cpu_t *cpu, uint ins_word) {
|
|||||||
|
|
||||||
if ((ins_word & 0x00000073) == 0x00000073) {
|
if ((ins_word & 0x00000073) == 0x00000073) {
|
||||||
// could be CSR instruction
|
// could be CSR instruction
|
||||||
ins_FormatCSR.value = get_csr(ins_FormatCSR.csr);
|
ins_FormatCSR.value = get_csr(cpu, ins_FormatCSR.csr, &ret);
|
||||||
}
|
}
|
||||||
|
|
||||||
ins_masked = ins_word & 0x0000007f;
|
ins_masked = ins_word & 0x0000007f;
|
||||||
@ -399,11 +482,15 @@ ins_ret ins_select(cpu_t *cpu, uint ins_word) {
|
|||||||
}
|
}
|
||||||
ins_masked = ins_word & 0xf800707f;
|
ins_masked = ins_word & 0xf800707f;
|
||||||
switch (ins_masked) {
|
switch (ins_masked) {
|
||||||
RUN(amoadd_w, 0x0000202f, ins_FormatR)
|
|
||||||
RUN(amoand_w, 0x6000202f, ins_FormatR)
|
|
||||||
RUN(amomaxu_w, 0xe000202f, ins_FormatR)
|
|
||||||
RUN(amoor_w, 0x4000202f, ins_FormatR)
|
|
||||||
RUN(amoswap_w, 0x0800202f, ins_FormatR)
|
RUN(amoswap_w, 0x0800202f, ins_FormatR)
|
||||||
|
RUN(amoadd_w, 0x0000202f, ins_FormatR)
|
||||||
|
RUN(amoxor_w, 0x2000202f, ins_FormatR)
|
||||||
|
RUN(amoand_w, 0x6000202f, ins_FormatR)
|
||||||
|
RUN(amoor_w, 0x4000202f, ins_FormatR)
|
||||||
|
RUN(amomin_w, 0x8000202f, ins_FormatR)
|
||||||
|
RUN(amomax_w, 0xa000202f, ins_FormatR)
|
||||||
|
RUN(amominu_w, 0xc000202f, ins_FormatR)
|
||||||
|
RUN(amomaxu_w, 0xe000202f, ins_FormatR)
|
||||||
RUN(sc_w, 0x1800202f, ins_FormatR)
|
RUN(sc_w, 0x1800202f, ins_FormatR)
|
||||||
}
|
}
|
||||||
ins_masked = ins_word & 0xf9f0707f;
|
ins_masked = ins_word & 0xf9f0707f;
|
||||||
@ -452,26 +539,40 @@ ins_ret ins_select(cpu_t *cpu, uint ins_word) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
printf("Invalid instruction: %08x\n", ins_word);
|
printf("Invalid instruction: %08x\n", ins_word);
|
||||||
exit(2);
|
ret.trap.en = true;
|
||||||
|
ret.trap.type = trap_IllegalInstruction;
|
||||||
|
ret.trap.value = cpu->pc;
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void emulate(cpu_t *cpu, uint ins_word) {
|
void emulate(cpu_t *cpu) {
|
||||||
ins_ret ret = ins_select(cpu, ins_word);
|
uint ins_word = 0;
|
||||||
|
ins_ret ret;
|
||||||
|
if ((cpu->pc & 0x3) == 0) {
|
||||||
|
ins_word = mem_get_word(cpu, cpu->pc);
|
||||||
|
ret = ins_select(cpu, ins_word);
|
||||||
|
|
||||||
if (ret.pc_write > 0) {
|
if (ret.csr_write && !ret.trap.en) {
|
||||||
cpu->pc = ret.pc_val;
|
set_csr(cpu, ret.csr_write, ret.csr_val, &ret);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!ret.trap.en && ret.write_reg < 32 && ret.write_reg > 0) {
|
||||||
|
cpu->xreg[ret.write_reg] = ret.write_val;
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
cpu->pc += 4;
|
ret = ins_ret_noop(cpu);
|
||||||
|
ret.trap.en = true;
|
||||||
|
ret.trap.type = trap_InstructionAddressMisaligned;
|
||||||
|
ret.trap.value = cpu->pc;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ret.write_reg < 32 && ret.write_reg > 0) {
|
if (ret.trap.en) {
|
||||||
cpu->xreg[ret.write_reg] = ret.write_val;
|
handle_trap(cpu, &ret, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ret.csr_write) {
|
// ret.pc_val should be set to pc+4 by default
|
||||||
set_csr(ret.csr_write, ret.csr_val);
|
cpu->pc = ret.pc_val;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
/* #define VERBOSE */
|
/* #define VERBOSE */
|
||||||
|
/* #define SINGLE_STEP */
|
||||||
|
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
@ -46,6 +47,12 @@ int main(int argc, char *argv[]) {
|
|||||||
#ifdef VERBOSE
|
#ifdef VERBOSE
|
||||||
cpu_dump(&cpu);
|
cpu_dump(&cpu);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
if (cpu.debug_single_step) {
|
||||||
|
fflush(stdout);
|
||||||
|
fflush(stdin);
|
||||||
|
while(getchar()!='\n');
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
144
src/trap.h
Normal file
144
src/trap.h
Normal file
@ -0,0 +1,144 @@
|
|||||||
|
#ifndef TRAP_H
|
||||||
|
#define TRAP_H
|
||||||
|
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include "types.h"
|
||||||
|
|
||||||
|
#define PRIV_USER 0
|
||||||
|
#define PRIV_SUPERVISOR 1
|
||||||
|
#define PRIV_MACHINE 3
|
||||||
|
|
||||||
|
static const uint interrupt_offset = 0x80000000;
|
||||||
|
const uint trap_InstructionAddressMisaligned = 0;
|
||||||
|
const uint trap_InstructionAccessFault = 1;
|
||||||
|
const uint trap_IllegalInstruction = 2;
|
||||||
|
const uint trap_Breakpoint = 3;
|
||||||
|
const uint trap_LoadAddressMisaligned = 4;
|
||||||
|
const uint trap_LoadAccessFault = 5;
|
||||||
|
const uint trap_StoreAddressMisaligned = 6;
|
||||||
|
const uint trap_StoreAccessFault = 7;
|
||||||
|
const uint trap_EnvironmentCallFromUMode = 8;
|
||||||
|
const uint trap_EnvironmentCallFromSMode = 9;
|
||||||
|
const uint trap_EnvironmentCallFromMMode = 11;
|
||||||
|
const uint trap_InstructionPageFault = 12;
|
||||||
|
const uint trap_LoadPageFault = 13;
|
||||||
|
const uint trap_StorePageFault = 15;
|
||||||
|
const uint trap_UserSoftwareInterrupt = interrupt_offset + 0;
|
||||||
|
const uint trap_SupervisorSoftwareInterrupt = interrupt_offset + 1;
|
||||||
|
const uint trap_MachineSoftwareInterrupt = interrupt_offset + 3;
|
||||||
|
const uint trap_UserTimerInterrupt = interrupt_offset + 4;
|
||||||
|
const uint trap_SupervisorTimerInterrupt = interrupt_offset + 5;
|
||||||
|
const uint trap_MachineTimerInterrupt = interrupt_offset + 7;
|
||||||
|
const uint trap_UserExternalInterrupt = interrupt_offset + 8;
|
||||||
|
const uint trap_SupervisorExternalInterrupt = interrupt_offset + 9;
|
||||||
|
const uint trap_MachineExternalInterrupt = interrupt_offset + 11;
|
||||||
|
|
||||||
|
// include after trap_ definitions
|
||||||
|
#include "csr.h"
|
||||||
|
|
||||||
|
// returns true if IRQ was handled or !is_interrupt
|
||||||
|
bool handle_trap(cpu_t *cpu, ins_ret *ret, bool is_interrupt) {
|
||||||
|
trap t = ret->trap;
|
||||||
|
uint current_privilege = cpu->csr.privilege;
|
||||||
|
|
||||||
|
uint mdeleg = read_csr_raw(cpu, is_interrupt ? CSR_MIDELEG : CSR_MEDELEG);
|
||||||
|
uint sdeleg = read_csr_raw(cpu, is_interrupt ? CSR_SIDELEG : CSR_SEDELEG);
|
||||||
|
uint pos = t.type & 0xFFFF;
|
||||||
|
|
||||||
|
uint new_privilege = ((mdeleg >> pos) & 1) == 0 ?
|
||||||
|
PRIV_MACHINE : (((sdeleg >> pos) & 1) == 0 ?
|
||||||
|
PRIV_SUPERVISOR : PRIV_USER);
|
||||||
|
|
||||||
|
uint mstatus = read_csr_raw(cpu, CSR_MSTATUS);
|
||||||
|
uint sstatus = read_csr_raw(cpu, CSR_SSTATUS);
|
||||||
|
uint current_status = current_privilege == PRIV_MACHINE ?
|
||||||
|
mstatus : (current_privilege == PRIV_SUPERVISOR ?
|
||||||
|
sstatus : read_csr_raw(cpu, CSR_USTATUS));
|
||||||
|
|
||||||
|
// check if IRQ should be ignored
|
||||||
|
if (is_interrupt) {
|
||||||
|
uint ie = new_privilege == PRIV_MACHINE ?
|
||||||
|
read_csr_raw(cpu, CSR_MIE) : (new_privilege == PRIV_SUPERVISOR ?
|
||||||
|
read_csr_raw(cpu, CSR_SIE) : read_csr_raw(cpu, CSR_UIE));
|
||||||
|
|
||||||
|
uint current_mie = (current_status >> 3) & 1;
|
||||||
|
uint current_sie = (current_status >> 1) & 1;
|
||||||
|
uint current_uie = current_status & 1;
|
||||||
|
|
||||||
|
uint msie = (ie >> 3) & 1;
|
||||||
|
uint ssie = (ie >> 1) & 1;
|
||||||
|
uint usie = ie & 1;
|
||||||
|
|
||||||
|
uint mtie = (ie >> 7) & 1;
|
||||||
|
uint stie = (ie >> 5) & 1;
|
||||||
|
uint utie = (ie >> 4) & 1;
|
||||||
|
|
||||||
|
uint meie = (ie >> 11) & 1;
|
||||||
|
uint seie = (ie >> 9) & 1;
|
||||||
|
uint ueie = (ie >> 8) & 1;
|
||||||
|
|
||||||
|
if (new_privilege < current_privilege) {
|
||||||
|
return false;
|
||||||
|
} else if (new_privilege == current_privilege) {
|
||||||
|
if (current_privilege == PRIV_MACHINE && current_mie == 0) {
|
||||||
|
return false;
|
||||||
|
} else if (current_privilege == PRIV_SUPERVISOR && current_sie == 0) {
|
||||||
|
return false;
|
||||||
|
} else if (current_privilege == PRIV_USER && current_uie == 0) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#define MASK(trap, val) case trap: if (val == 0) { return false; } else { break; }
|
||||||
|
switch (t.type) {
|
||||||
|
MASK(trap_UserSoftwareInterrupt, usie)
|
||||||
|
MASK(trap_SupervisorSoftwareInterrupt, ssie)
|
||||||
|
MASK(trap_MachineSoftwareInterrupt, msie)
|
||||||
|
MASK(trap_UserTimerInterrupt, utie)
|
||||||
|
MASK(trap_SupervisorTimerInterrupt, stie)
|
||||||
|
MASK(trap_MachineTimerInterrupt, mtie)
|
||||||
|
MASK(trap_UserExternalInterrupt, ueie)
|
||||||
|
MASK(trap_SupervisorExternalInterrupt, seie)
|
||||||
|
MASK(trap_MachineExternalInterrupt, meie)
|
||||||
|
}
|
||||||
|
#undef MASK
|
||||||
|
}
|
||||||
|
|
||||||
|
// should be handled, do that now
|
||||||
|
cpu->csr.privilege = new_privilege;
|
||||||
|
|
||||||
|
uint csr_epc_addr = new_privilege == PRIV_MACHINE ? CSR_MEPC : (new_privilege == PRIV_SUPERVISOR ? CSR_SEPC : CSR_UEPC);
|
||||||
|
uint csr_cause_addr = new_privilege == PRIV_MACHINE ? CSR_MCAUSE : (new_privilege == PRIV_SUPERVISOR ? CSR_SCAUSE : CSR_UCAUSE);
|
||||||
|
uint csr_tval_addr = new_privilege == PRIV_MACHINE ? CSR_MTVAL : (new_privilege == PRIV_SUPERVISOR ? CSR_STVAL : CSR_UTVAL);
|
||||||
|
uint csr_tvec_addr = new_privilege == PRIV_MACHINE ? CSR_MTVEC : (new_privilege == PRIV_SUPERVISOR ? CSR_STVEC : CSR_UTVEC);
|
||||||
|
|
||||||
|
write_csr_raw(cpu, csr_epc_addr, cpu->pc);
|
||||||
|
write_csr_raw(cpu, csr_cause_addr, t.type);
|
||||||
|
write_csr_raw(cpu, csr_tval_addr, t.value);
|
||||||
|
ret->pc_val = read_csr_raw(cpu, csr_tvec_addr);
|
||||||
|
|
||||||
|
if ((ret->pc_val & 0x3) != 0) {
|
||||||
|
// vectored handler
|
||||||
|
ret->pc_val = (ret->pc_val & ~0x3) + 4*pos;
|
||||||
|
}
|
||||||
|
|
||||||
|
// NOTE: No user mode interrupt/exception handling!
|
||||||
|
if (new_privilege == PRIV_MACHINE) {
|
||||||
|
uint mie = (mstatus >> 3) & 1;
|
||||||
|
uint new_status = (mstatus & !0x1888) | (mie << 7) | (current_privilege << 11);
|
||||||
|
write_csr_raw(cpu, CSR_MSTATUS, new_status);
|
||||||
|
} else { // PRIV_SUPERVISOR
|
||||||
|
uint sie = (sstatus >> 3) & 1;
|
||||||
|
uint new_status = (sstatus & !0x122) | (sie << 5) | ((current_privilege & 1) << 8);
|
||||||
|
write_csr_raw(cpu, CSR_SSTATUS, new_status);
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef VERBOSE
|
||||||
|
printf("trap: type=%08x value=%08x (IRQ: %d) moved PC from @%08x to @%08x\n", t.type, t.value, is_interrupt, cpu->pc, ret->pc_val);
|
||||||
|
#endif
|
||||||
|
/* cpu->debug_single_step = true; */
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
31
src/types.h
31
src/types.h
@ -2,35 +2,54 @@
|
|||||||
#define TYPES_H
|
#define TYPES_H
|
||||||
|
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
#include <stdbool.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
typedef uint32_t uint;
|
typedef uint32_t uint;
|
||||||
typedef uint32_t uint;
|
typedef uint32_t uint;
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
uint32_t clock;
|
uint data[4096];
|
||||||
uint32_t xreg[32];
|
uint privilege;
|
||||||
uint32_t pc;
|
} csr_state;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
uint clock;
|
||||||
|
uint xreg[32];
|
||||||
|
uint pc;
|
||||||
uint8_t *mem;
|
uint8_t *mem;
|
||||||
|
csr_state csr;
|
||||||
|
|
||||||
|
bool reservation_en;
|
||||||
|
uint reservation_addr;
|
||||||
|
|
||||||
|
bool debug_single_step;
|
||||||
} cpu_t;
|
} cpu_t;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
bool en;
|
||||||
|
uint type;
|
||||||
|
uint value;
|
||||||
|
} trap;
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
uint write_reg;
|
uint write_reg;
|
||||||
uint write_val;
|
uint write_val;
|
||||||
uint pc_write;
|
|
||||||
uint pc_val;
|
uint pc_val;
|
||||||
uint csr_write;
|
uint csr_write;
|
||||||
uint csr_val;
|
uint csr_val;
|
||||||
|
trap trap;
|
||||||
} ins_ret;
|
} ins_ret;
|
||||||
|
|
||||||
ins_ret ins_ret_noop() {
|
ins_ret ins_ret_noop(cpu_t *cpu) {
|
||||||
ins_ret ret;
|
ins_ret ret;
|
||||||
memset(&ret, 0, sizeof(ins_ret));
|
memset(&ret, 0, sizeof(ins_ret));
|
||||||
|
ret.pc_val = cpu->pc + 4;
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint sign_extend(uint x, uint b) {
|
uint sign_extend(uint x, uint b) {
|
||||||
uint m = 1U << (b - 1);
|
uint m = ((uint)1) << (b - 1);
|
||||||
return (x ^ m) - m;
|
return (x ^ m) - m;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
34
test.sh
34
test.sh
@ -4,17 +4,22 @@ echo "==== Building rvc ===="
|
|||||||
make clean
|
make clean
|
||||||
intercept-build make
|
intercept-build make
|
||||||
|
|
||||||
|
CLEAN="$2"
|
||||||
|
|
||||||
function run_test {
|
function run_test {
|
||||||
pushd ./riscv-tests/isa
|
pushd ./riscv-tests/isa
|
||||||
|
|
||||||
# rm "$1"
|
# rm "$1"
|
||||||
# rm "$1.text"
|
# rm "$1.text"
|
||||||
make "$1"
|
if [ ! -f "$1" ] || [ -n "$CLEAN" ]; then
|
||||||
|
make "$1"
|
||||||
|
fi
|
||||||
|
|
||||||
# riscv64-unknown-elf-objcopy -j .text.init -O binary "$1" "$1.text"
|
# riscv64-unknown-elf-objcopy -j .text.init -O binary "$1" "$1.text"
|
||||||
|
|
||||||
popd
|
popd
|
||||||
|
|
||||||
|
echo "Running: ./rvc \"./riscv-tests/isa/$1\""
|
||||||
timeout 5s ./rvc "./riscv-tests/isa/$1"
|
timeout 5s ./rvc "./riscv-tests/isa/$1"
|
||||||
|
|
||||||
if [ $? -gt 0 ]; then
|
if [ $? -gt 0 ]; then
|
||||||
@ -71,18 +76,19 @@ rv32um-p-mulhsu
|
|||||||
rv32um-p-mulhu
|
rv32um-p-mulhu
|
||||||
rv32um-p-rem
|
rv32um-p-rem
|
||||||
rv32um-p-remu
|
rv32um-p-remu
|
||||||
#rv32ua-p-amoadd_w
|
rv32ua-p-lrsc
|
||||||
#rv32ua-p-amoand_w
|
rv32ua-p-amoadd_w
|
||||||
#rv32ua-p-amomaxu_w
|
rv32ua-p-amoand_w
|
||||||
#rv32ua-p-amomax_w
|
rv32ua-p-amomaxu_w
|
||||||
#rv32ua-p-amominu_w
|
rv32ua-p-amomax_w
|
||||||
#rv32ua-p-amomin_w
|
rv32ua-p-amominu_w
|
||||||
#rv32ua-p-amoor_w
|
rv32ua-p-amomin_w
|
||||||
#rv32ua-p-amoswap_w
|
rv32ua-p-amoor_w
|
||||||
#rv32ua-p-amoxor_w
|
rv32ua-p-amoswap_w
|
||||||
#rv32mi-p-mcsr
|
rv32ua-p-amoxor_w
|
||||||
#rv32mi-p-csr
|
rv32mi-p-mcsr
|
||||||
#rv32si-p-csr"
|
rv32mi-p-csr
|
||||||
|
rv32si-p-csr"
|
||||||
for t in $TESTS; do
|
for t in $TESTS; do
|
||||||
if [[ "$t" =~ ^# ]]; then continue; fi
|
if [[ "$t" =~ ^# ]]; then continue; fi
|
||||||
echo
|
echo
|
||||||
@ -96,5 +102,5 @@ rv32um-p-remu
|
|||||||
elif [ -n "$1" ]; then
|
elif [ -n "$1" ]; then
|
||||||
run_test "$1"
|
run_test "$1"
|
||||||
else
|
else
|
||||||
echo "./test.sh (all|rv32ui-p-foo...)"
|
echo "./test.sh (all|rv32ui-p-foo...) [--clean]"
|
||||||
fi
|
fi
|
||||||
|
Loading…
Reference in New Issue
Block a user