diff options
| author | cheapie <cheapiephp@gmail.com> | 2026-11-06 13:22:41 -0600 |
|---|---|---|
| committer | cheapie <cheapiephp@gmail.com> | 2026-11-06 13:24:17 -0600 |
| commit | f1fe00423df3fda0ace4222d9d5e3d1976db3964 (patch) | |
| tree | 0155ad01ad8a2ba1f18ae6cd59f3d0c912088580 | |
| parent | c3ca1afe6ba655b71db048b513801cd3d5acf406 (diff) | |
| download | rvcontroller-f1fe00423df3fda0ace4222d9d5e3d1976db3964.tar rvcontroller-f1fe00423df3fda0ace4222d9d5e3d1976db3964.tar.gz rvcontroller-f1fe00423df3fda0ace4222d9d5e3d1976db3964.tar.bz2 rvcontroller-f1fe00423df3fda0ace4222d9d5e3d1976db3964.tar.xz rvcontroller-f1fe00423df3fda0ace4222d9d5e3d1976db3964.zip | |
Add Zihpm and Zicboz
| -rw-r--r-- | assembly/zicboztest/Makefile | 24 | ||||
| l--------- | assembly/zicboztest/rvcontroller.ld | 1 | ||||
| -rw-r--r-- | assembly/zicboztest/zicboztest.S | 17 | ||||
| -rw-r--r-- | doc/_start_here.txt | 7 | ||||
| -rw-r--r-- | doc/hpm.txt | 11 | ||||
| -rw-r--r-- | rvcontroller.lua | 81 |
6 files changed, 127 insertions, 14 deletions
diff --git a/assembly/zicboztest/Makefile b/assembly/zicboztest/Makefile new file mode 100644 index 0000000..60747f2 --- /dev/null +++ b/assembly/zicboztest/Makefile @@ -0,0 +1,24 @@ +MARCH ?= rv32imacbzicntr_zicond_zicsr_zifencei_zihintpause_zilsd_zclsd_zabha_zacas_zbkb_zbkx_zcb_zcmp_zcmt_zicboz + +.PHONY: all dump load clean + +all: zicboztest.hex + +zicboztest.o: zicboztest.S + riscv32-none-elf-as -I../rvcontroller-libraries -march=${MARCH} -o zicboztest.o zicboztest.S + +zicboztest.elf: zicboztest.o + riscv32-none-elf-ld -T rvcontroller.ld --no-warn-rwx-segments -o zicboztest.elf zicboztest.o + +dump: zicboztest.elf + riscv32-none-elf-objdump -d zicboztest.elf + +zicboztest.hex: zicboztest.elf + riscv32-none-elf-objcopy -O ihex zicboztest.elf zicboztest.hex + +load: zicboztest.hex + bash -c "wl-copy < zicboztest.hex" + +clean: + rm -f zicboztest.hex zicboztest.elf zicboztest.o + diff --git a/assembly/zicboztest/rvcontroller.ld b/assembly/zicboztest/rvcontroller.ld new file mode 120000 index 0000000..bc01402 --- /dev/null +++ b/assembly/zicboztest/rvcontroller.ld @@ -0,0 +1 @@ +../../rvcontroller.ld
\ No newline at end of file diff --git a/assembly/zicboztest/zicboztest.S b/assembly/zicboztest/zicboztest.S new file mode 100644 index 0000000..c9c5289 --- /dev/null +++ b/assembly/zicboztest/zicboztest.S @@ -0,0 +1,17 @@ +li t0,0x4000 +li t1,0xdeadbeef +li t2,0x7000 +1: sw t1,0(t0) +addi t0,t0,4 +andi t3,t0,0xff +bnez t3,2f +li a7,11 +li a0,'.' +ecall +2: blt t0,t2,1b + +li a0,0x5000 +cbo.zero 0(a0) + +li a7,10 +ecall diff --git a/doc/_start_here.txt b/doc/_start_here.txt index de41840..125de5f 100644 --- a/doc/_start_here.txt +++ b/doc/_start_here.txt @@ -5,7 +5,7 @@ RVController is a program for use in Luacontrollers (from the mesecons mod) in L It emulates a single RISC-V hart and a configurable amount (64KiB default) of RAM. Features: -* RV32IMACBZicfilp_Zicntr_Zicond_Zicsr_Zifencei_Zihintpause_Zilsd_Zimop_Zabha_Zacas_Zalasr_Zawrs_Zcb_Zclsd_Zcmop_Zcmp_Zcmt_Zbkb_Zbkx_Xh3bextm_Xh3misa instruction set provides: +* RV32IMACBZicboz_Zicfilp_Zicntr_Zicond_Zicsr_Zifencei_Zihintpause_Zihpm_Zilsd_Zimop_Zabha_Zacas_Zalasr_Zawrs_Zcb_Zclsd_Zcmop_Zcmp_Zcmt_Zbkb_Zbkx_Xh3bextm_Xh3misa instruction set provides: - 32-bit address space - 32 32-bit registers (31 general-purpose + 1 zero register) - Selectable endianness @@ -40,7 +40,8 @@ RVController is intended to be compliant with the following specifications: - Note: Implemented as a 'nop' instruction as memory is always consistent (see note on RVWMO below) * "Zicsr" Extension for Control and Status Register (CSR) Instructions, Version 2.0 * "Zicond" Extension for Integer Conditional Operations, Version 1.0.0 -* "Zicntr" Extension for Counters, Version 2.0 +* "Zicntr" Extension for Base Counters and Timers, Version 2.0 +* "Zihpm" Extension for Hardware Performance Counters, Version 2.0 * "Zimop" Extension for May-Be-Operations, Version 1.0 * "M" Extension for Integer Multiplication and Division, Version 2.0 - Note: This implies the following: @@ -52,6 +53,7 @@ RVController is intended to be compliant with the following specifications: * RVWMO Memory Consistency Model, Version 2.0 - Note: The actual implemented memory model is significantly more strict (memory is always consistent, there is no cache) * "Ztso" Extension for Total Store Ordering, Version 1.0 +* "CMO" Extensions for Base Cache Management Operation ISA, Version 1.0.0 (Zicboz only) * "C" Extension for Compressed Instructions, Version 2.0 - Note: This implies the following: - * "Zca" Extension for Code Size Reduction, Version 1.0.0 @@ -91,3 +93,4 @@ Documentation files: * csr.txt: Control and status registers * mmio.txt: Memory-mapped I/O * instructions.txt: List of all supported instructions, sorted by extension +* hpm.txt: List of counters supported as part of the Zihpm extension diff --git a/doc/hpm.txt b/doc/hpm.txt new file mode 100644 index 0000000..07ae2e1 --- /dev/null +++ b/doc/hpm.txt @@ -0,0 +1,11 @@ +RVController Zihpm Counter List +=============================== + +The following counters are supported as part of the Zihpm extension: + +* hpmcounter3: Number of interrupts serviced +* hpmcounter4: Number of non-interrupt traps handled +* hpmcounter5: Number of digilines messages received (excluding console) +* hpmcounter6: Number of console events received + +The upper word of each of these values is available in the corresponding hpmcounterXXh CSR. diff --git a/rvcontroller.lua b/rvcontroller.lua index 6f97a32..9d9a337 100644 --- a/rvcontroller.lua +++ b/rvcontroller.lua @@ -469,7 +469,7 @@ local function readcsr(address) false, --Zfa false, --Zfh false, --Zfhmin - false, --Zicboz + true, --Zicboz true, --Zicond false, --Zihintntl true, --Zihintpause @@ -514,9 +514,9 @@ local function readcsr(address) true, --Zifencei mem.isa.m, --Zmmul false, --Zibi - false, --supm(?) + false, --supm(S-mode?) true, --Zicntr - false, --Zihpm + true, --Zihpm false, --Zfbfmin false, --Zvfbfmin false, --Zvfbfwma @@ -576,6 +576,11 @@ local function writecsr(address,data) fault = 2 fval = readram(mem.registers.pc,4) return + elseif (address >= 0xc03 and address <= 0xc1f) or (address >= 0xc83 and address < 0xc9f) then + --One of the read-only CSRs from Zihpm + fault = 2 + fval = readram(mem.registers.pc,4) + return elseif address == 0xf11 or address == 0xf12 or address == 0xf13 or address == 0xf14 or address == 0xf15 then --Read-only machine information register fault = 2 @@ -644,6 +649,15 @@ local function writecsr(address,data) end local function trap(reason,val) + if reason >= 0x8000000 then + --Interrupt + mem.csr[0xc03] = (mem.csr[0xc03]+1)%0x100000000 --hpmcounter3 + if mem.csr[0xc03] == 0 then mem.csr[0xc83] = (mem.csr[0xc83]+1)%0x100000000 end --hpmcounter3h + else + --Other + mem.csr[0xc04] = (mem.csr[0xc04]+1)%0x100000000 --hpmcounter4 + if mem.csr[0xc04] == 0 then mem.csr[0xc84] = (mem.csr[0xc84]+1)%0x100000000 end --hpmcounter4h + end local oldreason = reason if mem.mdt then writecsr(0x34b,reason) --mtval2 @@ -1973,6 +1987,15 @@ local operations = { interrupt(1,"checkinterrupt") return false,true end, + cbozero = function(rs1) + local address = getreg(rs1) + address = address - (address%0x100) + if address >= RAM_SIZE then + return trap(7,getreg(rs1)) + end + local segment = address/0x100 + mem.ram[segment] = string.rep(string.char(0),256) + end, } local function runinst(instruction) @@ -2438,11 +2461,22 @@ local function runinst(instruction) end end elseif opcode == 0x0f then - --Memory is always consistent on this implementation, - --so all fences can just turn into NOPs + local immbits = {[0] = bits[20],bits[21],bits[22],bits[23],bits[24],bits[25],bits[26],bits[27],bits[28],bits[29],bits[30],bits[31]} + local imm = implodebits(immbits,12) + local f3 = implodebits({[0] = bits[12],bits[13],bits[14]},3) + local rd = implodebits({[0] = bits[7],bits[8],bits[9],bits[10],bits[11]},5) + local rs1 = implodebits({[0] = bits[15],bits[16],bits[17],bits[18],bits[19]},5) if instruction == 0x0100000f then --pause return false,true + elseif f3 == 0 or f3 == 1 then + --fence, fence.tso, or fence.i + --Memory is always consistent on this implementation, + --so all fences can just turn into NOPs + return false,false + elseif f3 == 2 and rd == 0 and imm == 4 then + --cbo.zero + return operations.cbozero(rs1) end elseif opcode == 0x0b and mem.isa.x then --Custom0 instruction (currently all R-type) @@ -2828,7 +2862,10 @@ local function run(limit) first = false local instruction = readram(mem.registers.pc,4,true) if mem.elp and mem.mlpe then - if instruction%2^12 == 0x017 and mem.registers.pc%4 == 0 and (math.floor(instruction/2^12) == math.floor(getreg(7)/2^12) or math.floor(instruction/2^12) == 0) then + if instruction%2^12 == 0x017 + and mem.registers.pc%4 == 0 + and (math.floor(instruction/2^12) == math.floor(getreg(7)/2^12) + or math.floor(instruction/2^12) == 0) then mem.elp = false else trap(18,2) @@ -2935,6 +2972,14 @@ local csraliases = { minstreth = 0xb82, mseccfg = 0x747, ["h3.misa"] = 0xbf1, + hpmcounter3 = 0xc03, + hpmcounter4 = 0xc04, + hpmcounter5 = 0xc05, + hpmcounter6 = 0xc06, + hpmcounter3h = 0xc83, + hpmcounter4h = 0xc84, + hpmcounter5h = 0xc85, + hpmcounter6h = 0xc86, } if event.type == "program" or event.iid == "reset" then @@ -2969,12 +3014,20 @@ if event.type == "program" or event.iid == "reset" then [0x800] = 0, --Clock Controls [0x801] = 0, --MMIO Base Address [0xbf1] = 0, --h3.misa - [0xc00] = 0, --CYCLE - [0xc01] = 0, --TIME - [0xc02] = 0, --INSTRET - [0xc80] = 0, --CYCLEH - [0xc81] = 0, --TIMEH - [0xc82] = 0, --INSTRETH + [0xc00] = 0, --cycle + [0xc01] = 0, --time + [0xc02] = 0, --instret + [0xc03] = 0, --hpmcounter3 + [0xc04] = 0, --hpmcounter4 + [0xc05] = 0, --hpmcounter5 + [0xc06] = 0, --hpmcounter6 + [0xc80] = 0, --cycleh + [0xc81] = 0, --timeh + [0xc82] = 0, --instreth + [0xc83] = 0, --hpmcounter3h + [0xc84] = 0, --hpmcounter4h + [0xc85] = 0, --hpmcounter5h + [0xc86] = 0, --hpmcounter6h } for i=1,6 do mem.stdout[i] = "" end local mdisp = event.type == "program" and "\nReset: Cold" or "\nReset: Warm" @@ -3259,6 +3312,8 @@ elseif event.channel == "monitorkb" then digiline_send("monitordisp","Unknown command") end elseif event.channel == "stdin" then + mem.csr[0xc06] = (mem.csr[0xc06]+1)%0x100000000 --hpmcounter6 + if mem.csr[0xc06] == 0 then mem.csr[0xc86] = (mem.csr[0xc86]+1)%0x100000000 end --hpmcounter6h if mem.inputwaiting then --Blocking read in progress if mem.inputwaittype == "string" then @@ -3336,6 +3391,8 @@ elseif event.channel == "load" then end end elseif event.type == "digiline" then + mem.csr[0xc05] = (mem.csr[0xc05]+1)%0x100000000 --hpmcounter5 + if mem.csr[0xc05] == 0 then mem.csr[0xc85] = (mem.csr[0xc85]+1)%0x100000000 end --hpmcounter5h --Unrecognized digilines signals get forwarded on to the program event.channel = string.sub(event.channel,1,256) event.msg = string.sub(tostring(event.msg),1,256) |
