mirror of
https://github.com/openhwgroup/cvw.git
synced 2025-06-28 17:43:09 -04:00
Exercise solutions
This commit is contained in:
parent
0fabccf384
commit
b01fe7a38b
16 changed files with 686 additions and 0 deletions
77
examples/exercises/11p6/11p6.S
Normal file
77
examples/exercises/11p6/11p6.S
Normal file
|
@ -0,0 +1,77 @@
|
||||||
|
.section .text.init
|
||||||
|
.globl rvtest_entry_point
|
||||||
|
|
||||||
|
rvtest_entry_point:
|
||||||
|
|
||||||
|
# set up PMP so all of memory is accessible and we don't trap when entering supervisor mode
|
||||||
|
# Define region 0 to cover all addresses as RWX
|
||||||
|
nop
|
||||||
|
csrw pmpcfg0, 0xF # configure PMP0 to TOR RWX
|
||||||
|
li t0, 0xFFFFFFFF
|
||||||
|
csrw pmpaddr0, t0 # configure PMP0 top of range to 0xFFFFFFFF to allow all 32-bit addresses
|
||||||
|
|
||||||
|
# switch to supervisor mode
|
||||||
|
# Set mstatus.MPP to 01, set MPEC to a trampoline address where supervisor should begin, do mret
|
||||||
|
la t0, supervisorstart
|
||||||
|
csrw mepc, t0 # set address for supervisor code to starting
|
||||||
|
li t0, 1
|
||||||
|
slli t1, t0, 11 # 1 in bit 11
|
||||||
|
csrs mstatus, t1
|
||||||
|
slli t1, t0, 12 # 1 in bit 12
|
||||||
|
csrc mstatus, t1 # change mstatus.MPP to 01 (for supervisor mode)
|
||||||
|
mret # enter supervisor mode at supervisorstart
|
||||||
|
nop
|
||||||
|
|
||||||
|
supervisorstart:
|
||||||
|
la t0, pagetable # get address of root page table
|
||||||
|
srli t0, t0, 12 # extract PPN of root page table
|
||||||
|
li t1, 1
|
||||||
|
slli t1, t1, 31 # 1 in bit 31
|
||||||
|
or t0, t0, t1 # satp value to enable SV32 with root page table
|
||||||
|
csrw satp, t0 # enable virtual memory
|
||||||
|
|
||||||
|
# now we are execuiting on virtual page 0x80000, which is also physical page 0x80000
|
||||||
|
li t0, 0x90000300
|
||||||
|
li t1, 42
|
||||||
|
sw t1, 0(t0)
|
||||||
|
|
||||||
|
|
||||||
|
la t0, testcode # address of a routine to run
|
||||||
|
lui t1, 0x10000
|
||||||
|
add t0, t0, t1 # address of testcode on virtual page 0x90000
|
||||||
|
jr t0 # jump to the testcode on Virtual page 0x90000,
|
||||||
|
# which still points to same code on physical page 0x80000
|
||||||
|
nop # shouldn't be executed
|
||||||
|
|
||||||
|
testcode:
|
||||||
|
li t0, 42 # do something
|
||||||
|
|
||||||
|
write_tohost:
|
||||||
|
la s1, tohost # terminate with write tohost
|
||||||
|
li t0, 1 # 1 for success, 3 for failure
|
||||||
|
sw t0, 0(s1) # send success code
|
||||||
|
sw zero, 4(s1) # not obvious why Sail isn't terminating unless this write is done
|
||||||
|
|
||||||
|
self_loop:
|
||||||
|
j self_loop
|
||||||
|
|
||||||
|
tohost:
|
||||||
|
.word 0
|
||||||
|
|
||||||
|
.data
|
||||||
|
|
||||||
|
|
||||||
|
.align 16
|
||||||
|
# root (L1) Page table situated at 0x80010000
|
||||||
|
pagetable:
|
||||||
|
.space 2048 # skip over addresses below 0x80000000
|
||||||
|
.4byte 0x20004401 # VPN1 = 512 (VA = 0x80000000) points to L0 page table at 80011000
|
||||||
|
.space 252 # skip over addresses below 0x90000000
|
||||||
|
.4byte 0x20004401 # VPN 576 (VA = 0x90000000) points to L0 page table at 0x80011000
|
||||||
|
|
||||||
|
.align 12
|
||||||
|
# L0 page table situated at 0x80011000
|
||||||
|
.4byte 0x200000CF # VPN 0 points to physical kilopage at 0x80000000 with Dirty, Access, XWR, Valid
|
||||||
|
|
||||||
|
|
||||||
|
|
17
examples/exercises/11p6/Makefile
Normal file
17
examples/exercises/11p6/Makefile
Normal file
|
@ -0,0 +1,17 @@
|
||||||
|
TARGET = 11p6
|
||||||
|
|
||||||
|
$(TARGET).elf.objdump: $(TARGET).elf
|
||||||
|
riscv64-unknown-elf-objdump -D $(TARGET).elf > $(TARGET).elf.objdump
|
||||||
|
|
||||||
|
$(TARGET).elf: $(TARGET).S Makefile
|
||||||
|
riscv64-unknown-elf-gcc -g -o $(TARGET) -march=rv32i_zicsr -mabi=ilp32 -mcmodel=medany \
|
||||||
|
-nostartfiles -T../../link/link.ld $(TARGET).S -o $(TARGET).elf
|
||||||
|
|
||||||
|
# simulate in lockstep with ImperasDV
|
||||||
|
sim: $(TARGET).elf.objdump
|
||||||
|
wsim rv32gc $(TARGET).elf --lockstepverbose
|
||||||
|
|
||||||
|
clean:
|
||||||
|
rm -f $(TARGET).elf*
|
||||||
|
|
||||||
|
|
9
examples/exercises/8p3/8p3.S
Normal file
9
examples/exercises/8p3/8p3.S
Normal file
|
@ -0,0 +1,9 @@
|
||||||
|
.section .text.init
|
||||||
|
.globl rvtest_entry_point
|
||||||
|
|
||||||
|
rvtest_entry_point:
|
||||||
|
li t0, 32 # 1 in bit 5
|
||||||
|
csrs mstatush, t0 # set bit 5 (mstatush.MBE)
|
||||||
|
|
||||||
|
self_loop:
|
||||||
|
j self_loop
|
17
examples/exercises/8p3/Makefile
Normal file
17
examples/exercises/8p3/Makefile
Normal file
|
@ -0,0 +1,17 @@
|
||||||
|
TARGET = 8p3
|
||||||
|
|
||||||
|
$(TARGET).elf.objdump: $(TARGET).elf
|
||||||
|
riscv64-unknown-elf-objdump -D $(TARGET).elf > $(TARGET).elf.objdump
|
||||||
|
|
||||||
|
$(TARGET).elf: $(TARGET).S Makefile
|
||||||
|
riscv64-unknown-elf-gcc -g -o $(TARGET) -march=rv32i_zicsr -mabi=ilp32 -mcmodel=medany \
|
||||||
|
-nostartfiles -T../../link/link.ld $(TARGET).S -o $(TARGET).elf
|
||||||
|
|
||||||
|
# simulate in lockstep with ImperasDV
|
||||||
|
sim: $(TARGET).elf.objdump
|
||||||
|
wsim rv32gc $(TARGET).elf --lockstepverbose
|
||||||
|
|
||||||
|
clean:
|
||||||
|
rm -f $(TARGET).elf*
|
||||||
|
|
||||||
|
|
20
examples/exercises/8p4/8p4.S
Normal file
20
examples/exercises/8p4/8p4.S
Normal file
|
@ -0,0 +1,20 @@
|
||||||
|
.section .text.init
|
||||||
|
.globl rvtest_entry_point
|
||||||
|
|
||||||
|
rvtest_entry_point:
|
||||||
|
csrr a0, cycle # read cycle register before computation
|
||||||
|
|
||||||
|
# add up numbers from 1 to 10. Place result in s0
|
||||||
|
li s0, 0 # initialize sum to 0 in s0
|
||||||
|
li s1, 1 # initialize loop variable i to 1 in s1
|
||||||
|
li t0, 10 # temporary for maximum number
|
||||||
|
loop:
|
||||||
|
add s0, s0, s1 # sum = sum + i
|
||||||
|
addi s1, s1, 1 # i = i + 1
|
||||||
|
ble s1, t0, loop # repeat while i <= 10
|
||||||
|
|
||||||
|
csrr a1, cycle # read cycle register after computation
|
||||||
|
sub a0, a1, a0 # compute difference in a0
|
||||||
|
|
||||||
|
self_loop:
|
||||||
|
j self_loop
|
17
examples/exercises/8p4/Makefile
Normal file
17
examples/exercises/8p4/Makefile
Normal file
|
@ -0,0 +1,17 @@
|
||||||
|
TARGET = 8p4
|
||||||
|
|
||||||
|
$(TARGET).elf.objdump: $(TARGET).elf
|
||||||
|
riscv64-unknown-elf-objdump -D $(TARGET).elf > $(TARGET).elf.objdump
|
||||||
|
|
||||||
|
$(TARGET).elf: $(TARGET).S Makefile
|
||||||
|
riscv64-unknown-elf-gcc -g -o $(TARGET) -march=rv32i_zicsr -mabi=ilp32 -mcmodel=medany \
|
||||||
|
-nostartfiles -T../../link/link.ld $(TARGET).S -o $(TARGET).elf
|
||||||
|
|
||||||
|
# simulate in lockstep with ImperasDV
|
||||||
|
sim: $(TARGET).elf.objdump
|
||||||
|
wsim rv32gc $(TARGET).elf --lockstepverbose
|
||||||
|
|
||||||
|
clean:
|
||||||
|
rm -f $(TARGET).elf*
|
||||||
|
|
||||||
|
|
29
examples/exercises/8p5/8p5.S
Normal file
29
examples/exercises/8p5/8p5.S
Normal file
|
@ -0,0 +1,29 @@
|
||||||
|
.section .text.init
|
||||||
|
.globl rvtest_entry_point
|
||||||
|
|
||||||
|
rvtest_entry_point:
|
||||||
|
|
||||||
|
# set up trap trap_handler
|
||||||
|
la t0, trap_handler # address of trap trap_handler
|
||||||
|
csrw mtvec, t0 # mtvec = pointer to trap handler
|
||||||
|
la t0, trapstack # address of trap stack
|
||||||
|
csrw mscratch, t0 # mscratch = pointer to trap stack
|
||||||
|
|
||||||
|
lw t0, 1(zero) # cause access or misaligned load fault to invoke trap handler
|
||||||
|
|
||||||
|
self_loop:
|
||||||
|
j self_loop
|
||||||
|
|
||||||
|
|
||||||
|
trap_handler:
|
||||||
|
csrrw tp, mscratch, tp # swap tp and mscratch to put a trap stack pointer in tp
|
||||||
|
sw t0, 0(tp) # save t0 on trap stack
|
||||||
|
csrr t0, mepc # read mepc
|
||||||
|
addi t0, t0, 4 # mepc + 4
|
||||||
|
csrw mepc, t0 # mepc = mpec + 4 (return to next instruction)
|
||||||
|
lw t0, 0(tp) # restore t0 from trap stack
|
||||||
|
csrrw tp, mscratch, tp # restore tp and trap stack pointer
|
||||||
|
mret
|
||||||
|
|
||||||
|
trapstack:
|
||||||
|
.word 0 # room to save a register
|
17
examples/exercises/8p5/Makefile
Normal file
17
examples/exercises/8p5/Makefile
Normal file
|
@ -0,0 +1,17 @@
|
||||||
|
TARGET = 8p5
|
||||||
|
|
||||||
|
$(TARGET).elf.objdump: $(TARGET).elf
|
||||||
|
riscv64-unknown-elf-objdump -D $(TARGET).elf > $(TARGET).elf.objdump
|
||||||
|
|
||||||
|
$(TARGET).elf: $(TARGET).S Makefile
|
||||||
|
riscv64-unknown-elf-gcc -g -o $(TARGET) -march=rv32i_zicsr -mabi=ilp32 -mcmodel=medany \
|
||||||
|
-nostartfiles -T../../link/link.ld $(TARGET).S -o $(TARGET).elf
|
||||||
|
|
||||||
|
# simulate in lockstep with ImperasDV
|
||||||
|
sim: $(TARGET).elf.objdump
|
||||||
|
wsim rv32gc $(TARGET).elf --lockstepverbose
|
||||||
|
|
||||||
|
clean:
|
||||||
|
rm -f $(TARGET).elf*
|
||||||
|
|
||||||
|
|
164
examples/exercises/8p6/8p6.S
Normal file
164
examples/exercises/8p6/8p6.S
Normal file
|
@ -0,0 +1,164 @@
|
||||||
|
.section .text.init
|
||||||
|
.globl rvtest_entry_point
|
||||||
|
|
||||||
|
rvtest_entry_point:
|
||||||
|
|
||||||
|
# set up trap trap_handler
|
||||||
|
la t0, trap_handler # address of trap trap_handler
|
||||||
|
csrw mtvec, t0 # mtvec = pointer to trap handler
|
||||||
|
la t0, trapstack # address of trap stack
|
||||||
|
csrw mscratch, t0 # mscratch = pointer to trap stack
|
||||||
|
|
||||||
|
li t0, 7
|
||||||
|
li t1, 9
|
||||||
|
mul t2, t0, t1 # try 7 * 9. It will trap and invoke trap handler
|
||||||
|
|
||||||
|
self_loop:
|
||||||
|
j self_loop
|
||||||
|
|
||||||
|
|
||||||
|
trap_handler:
|
||||||
|
csrrw tp, mscratch, tp # swap tp and mscratch to put a trap stack pointer in tp
|
||||||
|
|
||||||
|
# save all registers on trap stack. We will need to index into them to find the arguments to emulate multiply
|
||||||
|
sw x0, 0(tp) # x0 is 0, but we might want to use it
|
||||||
|
sw x1, 4(tp)
|
||||||
|
sw x2, 8(tp)
|
||||||
|
sw x3, 12(tp)
|
||||||
|
sw x4, 16(tp)
|
||||||
|
sw x5, 20(tp)
|
||||||
|
sw x6, 24(tp)
|
||||||
|
sw x7, 28(tp)
|
||||||
|
sw x8, 32(tp)
|
||||||
|
sw x9, 36(tp)
|
||||||
|
sw x10, 40(tp)
|
||||||
|
sw x11, 44(tp)
|
||||||
|
sw x12, 48(tp)
|
||||||
|
sw x13, 52(tp)
|
||||||
|
sw x14, 56(tp)
|
||||||
|
sw x15, 60(tp)
|
||||||
|
sw x16, 64(tp)
|
||||||
|
sw x17, 68(tp)
|
||||||
|
sw x18, 72(tp)
|
||||||
|
sw x19, 76(tp)
|
||||||
|
sw x20, 80(tp)
|
||||||
|
sw x21, 84(tp)
|
||||||
|
sw x22, 88(tp)
|
||||||
|
sw x23, 92(tp)
|
||||||
|
sw x24, 96(tp)
|
||||||
|
sw x25, 100(tp)
|
||||||
|
sw x26, 104(tp)
|
||||||
|
sw x27, 108(tp)
|
||||||
|
sw x28, 112(tp)
|
||||||
|
sw x29, 116(tp)
|
||||||
|
sw x30, 120(tp)
|
||||||
|
sw x31, 124(tp)
|
||||||
|
|
||||||
|
csrr t0, mcause # check cause of trap
|
||||||
|
li t1, 2 # cause 2 is illegal instruction
|
||||||
|
bne t0, t1, exit # exit for any other trap than illegal instruction
|
||||||
|
|
||||||
|
# check if instruction is mul (op = 0110011, funct3 = 000, funct7 = 0000001)
|
||||||
|
csrr t0, mtval # fetch instruction that caused trap
|
||||||
|
andi t1, t0, 127 # get op field (instr[7:0])
|
||||||
|
xori t1, t1, 0b0110011 # set to 0 if op is 0110011
|
||||||
|
srli t2, t0, 12 # get funct3 field (instr[14:12])
|
||||||
|
andi t2, t2, 7 # mask off other bits. Should be 0 if funct3 = 000
|
||||||
|
srli t3, t0, 25 # get funct7 field (instr[31:25]). No need to mask
|
||||||
|
xori t3, t3, 0b0000001 # set to 0 if funct7 = 0000001
|
||||||
|
or t1, t1, t2 # nonzero if op or funct3 mismatch
|
||||||
|
or t1, t1, t3 # nonzero if instruction is not mul
|
||||||
|
bnez t1, exit # exit for any other instruction than mul
|
||||||
|
|
||||||
|
# emulate mul: fetch arguments
|
||||||
|
srli t1, t0, 15 # extract rs1 from instr[19:15]
|
||||||
|
andi t1, t1, 31 # mask off other bits
|
||||||
|
slli t1, t1, 2 # multiply rs1 by 4 to make it a word index
|
||||||
|
add t1, tp, t1 # find location of rs1 on trap stack
|
||||||
|
lw t1, 0(t1) # read value of rs1
|
||||||
|
srli t2, t0, 20 # extract rs2 from instr[24:20]
|
||||||
|
andi t2, t2, 31 # mask off other bits
|
||||||
|
slli t2, t2, 2 # multiply rs2 by 4 to make it a word index
|
||||||
|
add t2, tp, t2 # find location of rs2 on trap stack
|
||||||
|
lw t2, 0(t2) # read value of rs2
|
||||||
|
|
||||||
|
# emulate mul p = x * y: shift and add
|
||||||
|
# x in t1, y in t2, p in t3
|
||||||
|
// p = 0
|
||||||
|
// while (y != 0)) { # iterate until all bits of y are consumed
|
||||||
|
// if (y%2) p = p + x # add x to running total
|
||||||
|
// y = y >> 1 # go on to next bit
|
||||||
|
// x = x << 1 # shift x to double
|
||||||
|
// }
|
||||||
|
|
||||||
|
li t3, 0 # p = 0
|
||||||
|
mulloop:
|
||||||
|
beqz t2, muldone # done if y == 0
|
||||||
|
andi t4, t2, 1 # t4 = y % 2
|
||||||
|
beqz t4, skipadd # don't increment p if y%2 == 0
|
||||||
|
add t3, t3, t1 # otherwise p = p + x0
|
||||||
|
skipadd:
|
||||||
|
srli t2, t2, 1 # y = y >> 1
|
||||||
|
slli t1, t1, 1 # x = x << 1
|
||||||
|
j mulloop # repeat until done
|
||||||
|
muldone:
|
||||||
|
|
||||||
|
# find rd and put result there
|
||||||
|
srli t1, t0, 7 # extract rd from instr[11:7]
|
||||||
|
andi t1, t1, 31 # mask off other bits
|
||||||
|
slli t1, t1, 2 # multiply rd by 4 to make it a word index
|
||||||
|
add t1, tp, t1 # find location of rd on trap stack
|
||||||
|
sw t3, 0(t1) # store result into rd storage on trap stack
|
||||||
|
|
||||||
|
# return to next instruction
|
||||||
|
|
||||||
|
csrr t0, mepc # read mepc
|
||||||
|
addi t0, t0, 4 # mepc + 4
|
||||||
|
csrw mepc, t0 # mepc = mpec + 4 (return to next instruction)
|
||||||
|
# restore all of the registers from the trap stack (rd could be in any one)
|
||||||
|
lw x1, 4(tp)
|
||||||
|
lw x2, 8(tp)
|
||||||
|
lw x3, 12(tp)
|
||||||
|
lw x4, 16(tp)
|
||||||
|
lw x5, 20(tp)
|
||||||
|
lw x6, 24(tp)
|
||||||
|
lw x7, 28(tp)
|
||||||
|
lw x8, 32(tp)
|
||||||
|
lw x9, 36(tp)
|
||||||
|
lw x10, 40(tp)
|
||||||
|
lw x11, 44(tp)
|
||||||
|
lw x12, 48(tp)
|
||||||
|
lw x13, 52(tp)
|
||||||
|
lw x14, 56(tp)
|
||||||
|
lw x15, 60(tp)
|
||||||
|
lw x16, 64(tp)
|
||||||
|
lw x17, 68(tp)
|
||||||
|
lw x18, 72(tp)
|
||||||
|
lw x19, 76(tp)
|
||||||
|
lw x20, 80(tp)
|
||||||
|
lw x21, 84(tp)
|
||||||
|
lw x22, 88(tp)
|
||||||
|
lw x23, 92(tp)
|
||||||
|
lw x24, 96(tp)
|
||||||
|
lw x25, 100(tp)
|
||||||
|
lw x26, 104(tp)
|
||||||
|
lw x27, 108(tp)
|
||||||
|
lw x28, 112(tp)
|
||||||
|
lw x29, 116(tp)
|
||||||
|
lw x30, 120(tp)
|
||||||
|
lw x31, 124(tp)
|
||||||
|
csrrw tp, mscratch, tp # restore tp and trap stack pointer
|
||||||
|
mret
|
||||||
|
|
||||||
|
exit:
|
||||||
|
la t1, tohost
|
||||||
|
li t0, 3 # 1 for success, 3 for failure
|
||||||
|
sw t0, 0(t1) # send fail code
|
||||||
|
j self_loop # wait
|
||||||
|
|
||||||
|
.section .tohost
|
||||||
|
tohost: # write to HTIF
|
||||||
|
.dword 0
|
||||||
|
|
||||||
|
trapstack:
|
||||||
|
.fill 32, 4 # room to save registers
|
17
examples/exercises/8p6/Makefile
Normal file
17
examples/exercises/8p6/Makefile
Normal file
|
@ -0,0 +1,17 @@
|
||||||
|
TARGET = 8p6
|
||||||
|
|
||||||
|
$(TARGET).elf.objdump: $(TARGET).elf
|
||||||
|
riscv64-unknown-elf-objdump -D $(TARGET).elf > $(TARGET).elf.objdump
|
||||||
|
|
||||||
|
$(TARGET).elf: $(TARGET).S Makefile
|
||||||
|
riscv64-unknown-elf-gcc -g -o $(TARGET) -march=rv32im_zicsr -mabi=ilp32 -mcmodel=medany \
|
||||||
|
-nostartfiles -T../../link/link.ld $(TARGET).S -o $(TARGET).elf
|
||||||
|
|
||||||
|
# simulate in lockstep with ImperasDV
|
||||||
|
sim: $(TARGET).elf.objdump
|
||||||
|
spike --isa=rv32i_zicsr -d $(TARGET).elf
|
||||||
|
|
||||||
|
clean:
|
||||||
|
rm -f $(TARGET).elf*
|
||||||
|
|
||||||
|
|
134
examples/exercises/8p7/8p7.S
Normal file
134
examples/exercises/8p7/8p7.S
Normal file
|
@ -0,0 +1,134 @@
|
||||||
|
.section .text.init
|
||||||
|
.globl rvtest_entry_point
|
||||||
|
|
||||||
|
rvtest_entry_point:
|
||||||
|
|
||||||
|
# set up trap trap_handler
|
||||||
|
la t0, trap_handler # address of trap trap_handler
|
||||||
|
csrw mtvec, t0 # mtvec = pointer to trap handler
|
||||||
|
la t0, trapstack # address of trap stack
|
||||||
|
csrw mscratch, t0 # mscratch = pointer to trap stack
|
||||||
|
|
||||||
|
la t0, destination # get address to make a load
|
||||||
|
lw t0, 3(t0) # misaligned load will invoke trap handler
|
||||||
|
# should return 0x23456789 in t0
|
||||||
|
|
||||||
|
self_loop:
|
||||||
|
j self_loop
|
||||||
|
|
||||||
|
|
||||||
|
trap_handler:
|
||||||
|
csrrw tp, mscratch, tp # swap tp and mscratch to put a trap stack pointer in tp
|
||||||
|
|
||||||
|
# save all registers on trap stack. We will need to index into them to find the arguments to emulate multiply
|
||||||
|
sw x0, 0(tp) # x0 is 0, but we might want to use it
|
||||||
|
sw x1, 4(tp)
|
||||||
|
sw x2, 8(tp)
|
||||||
|
sw x3, 12(tp)
|
||||||
|
sw x4, 16(tp)
|
||||||
|
sw x5, 20(tp)
|
||||||
|
sw x6, 24(tp)
|
||||||
|
sw x7, 28(tp)
|
||||||
|
sw x8, 32(tp)
|
||||||
|
sw x9, 36(tp)
|
||||||
|
sw x10, 40(tp)
|
||||||
|
sw x11, 44(tp)
|
||||||
|
sw x12, 48(tp)
|
||||||
|
sw x13, 52(tp)
|
||||||
|
sw x14, 56(tp)
|
||||||
|
sw x15, 60(tp)
|
||||||
|
sw x16, 64(tp)
|
||||||
|
sw x17, 68(tp)
|
||||||
|
sw x18, 72(tp)
|
||||||
|
sw x19, 76(tp)
|
||||||
|
sw x20, 80(tp)
|
||||||
|
sw x21, 84(tp)
|
||||||
|
sw x22, 88(tp)
|
||||||
|
sw x23, 92(tp)
|
||||||
|
sw x24, 96(tp)
|
||||||
|
sw x25, 100(tp)
|
||||||
|
sw x26, 104(tp)
|
||||||
|
sw x27, 108(tp)
|
||||||
|
sw x28, 112(tp)
|
||||||
|
sw x29, 116(tp)
|
||||||
|
sw x30, 120(tp)
|
||||||
|
sw x31, 124(tp)
|
||||||
|
|
||||||
|
csrr t0, mcause # check cause of trap
|
||||||
|
li t1, 4 # cause 4 is misaligned load
|
||||||
|
bne t0, t1, trap_return # return for any other cause
|
||||||
|
|
||||||
|
# check if instruction is lw (op=0000011, funct3 = 010)
|
||||||
|
csrr t0, mepc # address of faulting instruction
|
||||||
|
lw t3, 0(t0) # fetch the instruction. It must have been a load.
|
||||||
|
srli t1, t3, 12 # get funct3 field (instr[14:12])
|
||||||
|
andi t1, t1, 7 # mask off other bits.
|
||||||
|
xori t1, t1, 0b010 # should produce 0 if funct3 = 010
|
||||||
|
bnez t1, trap_return # return if any other kind of load
|
||||||
|
|
||||||
|
# emulate lw by performing four byte loads
|
||||||
|
csrr t0, mtval # address of load instruction
|
||||||
|
lbu t1, 0(t0) # read zeroth byte
|
||||||
|
lbu t2, 1(t0) # read the first byte
|
||||||
|
slli t2, t2, 8 # shift into position
|
||||||
|
or t1, t1, t2 # merge with zeroth byte
|
||||||
|
lbu t2, 2(t0) # read the second byte
|
||||||
|
slli t2, t2, 16 # shift into position
|
||||||
|
or t1, t1, t2 # merge with previous two bytes
|
||||||
|
lbu t2, 3(t0) # read the third byte
|
||||||
|
slli t2, t2, 24 # shift into position
|
||||||
|
or t2, t1, t2 # merge with previous three bytes
|
||||||
|
|
||||||
|
# find rd and put result there
|
||||||
|
srli t1, t3, 7 # extract rd from instr[11:7]
|
||||||
|
andi t1, t1, 31 # mask off other bits
|
||||||
|
slli t1, t1, 2 # multiply rd by 4 to make it a word index
|
||||||
|
add t1, tp, t1 # find location of rd on trap stack
|
||||||
|
sw t2, 0(t1) # store result into rd storage on trap stack
|
||||||
|
|
||||||
|
# return to next instruction
|
||||||
|
|
||||||
|
trap_return:
|
||||||
|
csrr t0, mepc # read mepc
|
||||||
|
addi t0, t0, 4 # mepc + 4
|
||||||
|
csrw mepc, t0 # mepc = mpec + 4 (return to next instruction)
|
||||||
|
# restore all of the registers from the trap stack (rd could be in any one)
|
||||||
|
lw x1, 4(tp)
|
||||||
|
lw x2, 8(tp)
|
||||||
|
lw x3, 12(tp)
|
||||||
|
lw x4, 16(tp)
|
||||||
|
lw x5, 20(tp)
|
||||||
|
lw x6, 24(tp)
|
||||||
|
lw x7, 28(tp)
|
||||||
|
lw x8, 32(tp)
|
||||||
|
lw x9, 36(tp)
|
||||||
|
lw x10, 40(tp)
|
||||||
|
lw x11, 44(tp)
|
||||||
|
lw x12, 48(tp)
|
||||||
|
lw x13, 52(tp)
|
||||||
|
lw x14, 56(tp)
|
||||||
|
lw x15, 60(tp)
|
||||||
|
lw x16, 64(tp)
|
||||||
|
lw x17, 68(tp)
|
||||||
|
lw x18, 72(tp)
|
||||||
|
lw x19, 76(tp)
|
||||||
|
lw x20, 80(tp)
|
||||||
|
lw x21, 84(tp)
|
||||||
|
lw x22, 88(tp)
|
||||||
|
lw x23, 92(tp)
|
||||||
|
lw x24, 96(tp)
|
||||||
|
lw x25, 100(tp)
|
||||||
|
lw x26, 104(tp)
|
||||||
|
lw x27, 108(tp)
|
||||||
|
lw x28, 112(tp)
|
||||||
|
lw x29, 116(tp)
|
||||||
|
lw x30, 120(tp)
|
||||||
|
lw x31, 124(tp)
|
||||||
|
csrrw tp, mscratch, tp # restore tp and trap stack pointer
|
||||||
|
mret
|
||||||
|
|
||||||
|
destination:
|
||||||
|
.dword 0x0123456789ABCDEF # fill destination with some stuff
|
||||||
|
|
||||||
|
trapstack:
|
||||||
|
.fill 32, 4 # room to save registers
|
17
examples/exercises/8p7/Makefile
Normal file
17
examples/exercises/8p7/Makefile
Normal file
|
@ -0,0 +1,17 @@
|
||||||
|
TARGET = 8p7
|
||||||
|
|
||||||
|
$(TARGET).elf.objdump: $(TARGET).elf
|
||||||
|
riscv64-unknown-elf-objdump -D $(TARGET).elf > $(TARGET).elf.objdump
|
||||||
|
|
||||||
|
$(TARGET).elf: $(TARGET).S Makefile
|
||||||
|
riscv64-unknown-elf-gcc -g -o $(TARGET) -march=rv32im_zicsr -mabi=ilp32 -mcmodel=medany \
|
||||||
|
-nostartfiles -T../../link/link.ld $(TARGET).S -o $(TARGET).elf
|
||||||
|
|
||||||
|
# simulate in lockstep with ImperasDV
|
||||||
|
sim: $(TARGET).elf.objdump
|
||||||
|
spike --isa=rv32i_zicsr -d $(TARGET).elf
|
||||||
|
|
||||||
|
clean:
|
||||||
|
rm -f $(TARGET).elf*
|
||||||
|
|
||||||
|
|
56
examples/exercises/8p8/8p8.S
Normal file
56
examples/exercises/8p8/8p8.S
Normal file
|
@ -0,0 +1,56 @@
|
||||||
|
.section .text.init
|
||||||
|
.globl rvtest_entry_point
|
||||||
|
|
||||||
|
rvtest_entry_point:
|
||||||
|
|
||||||
|
# set up trap trap_handler
|
||||||
|
la t0, trap_handler # address of trap trap_handler
|
||||||
|
csrw mtvec, t0 # mtvec = pointer to trap handler
|
||||||
|
la t0, trapstack # address of trap stack
|
||||||
|
csrw mscratch, t0 # mscratch = pointer to trap stack
|
||||||
|
sw zero, 12(t0) # size of buffer
|
||||||
|
|
||||||
|
wait:
|
||||||
|
nop
|
||||||
|
j wait # wait for uart communication
|
||||||
|
|
||||||
|
|
||||||
|
self_loop:
|
||||||
|
j self_loop
|
||||||
|
|
||||||
|
|
||||||
|
trap_handler:
|
||||||
|
csrrw tp, mscratch, tp # swap tp and mscratch to put a trap stack pointer in tp
|
||||||
|
|
||||||
|
# save some registers on trap stack. ß
|
||||||
|
sw t0, 0(tp)
|
||||||
|
sw t1, 4(tp)
|
||||||
|
sw t2, 8(tp)
|
||||||
|
|
||||||
|
lw t0, 12(tp) # get current length of buffer
|
||||||
|
li t1, 0x10000000 # UART base address
|
||||||
|
lbu t1, 0(t1) # fetch next character
|
||||||
|
add t2, tp, t0 # address in buffer
|
||||||
|
sb t1, 0(t2) # store character in buffer
|
||||||
|
li t2, 79 # maximum buffer length
|
||||||
|
beq t0, t2, skip # is buffer full?
|
||||||
|
addi t0, t0, 1 # increase buffer pointer
|
||||||
|
skip:
|
||||||
|
sw t0, 12(tp) # update buffer length
|
||||||
|
|
||||||
|
trap_return: # return to next instruction
|
||||||
|
csrr t0, mepc # read mepc
|
||||||
|
addi t0, t0, 4 # mepc + 4
|
||||||
|
csrw mepc, t0 # mepc = mpec + 4 (return to next instruction)
|
||||||
|
# restore all of the registers from the trap stack (rd could be in any one)
|
||||||
|
lw t0, 0(tp)
|
||||||
|
lw t1, 4(tp)
|
||||||
|
lw t2, 8(tp)
|
||||||
|
csrrw tp, mscratch, tp # restore tp and trap stack pointer
|
||||||
|
mret
|
||||||
|
|
||||||
|
buffer:
|
||||||
|
.fill 80, 1 # room for buffer
|
||||||
|
|
||||||
|
trapstack:
|
||||||
|
.fill 34, 4 # room to save registers and buffer length
|
17
examples/exercises/8p8/Makefile
Normal file
17
examples/exercises/8p8/Makefile
Normal file
|
@ -0,0 +1,17 @@
|
||||||
|
TARGET = 8p8
|
||||||
|
|
||||||
|
$(TARGET).elf.objdump: $(TARGET).elf
|
||||||
|
riscv64-unknown-elf-objdump -D $(TARGET).elf > $(TARGET).elf.objdump
|
||||||
|
|
||||||
|
$(TARGET).elf: $(TARGET).S Makefile
|
||||||
|
riscv64-unknown-elf-gcc -g -o $(TARGET) -march=rv32im_zicsr -mabi=ilp32 -mcmodel=medany \
|
||||||
|
-nostartfiles -T../../link/link.ld $(TARGET).S -o $(TARGET).elf
|
||||||
|
|
||||||
|
# simulate in lockstep with ImperasDV
|
||||||
|
sim: $(TARGET).elf.objdump
|
||||||
|
spike --isa=rv32i_zicsr -d $(TARGET).elf
|
||||||
|
|
||||||
|
clean:
|
||||||
|
rm -f $(TARGET).elf*
|
||||||
|
|
||||||
|
|
61
examples/exercises/8p9/8p9.S
Normal file
61
examples/exercises/8p9/8p9.S
Normal file
|
@ -0,0 +1,61 @@
|
||||||
|
.section .text.init
|
||||||
|
.globl rvtest_entry_point
|
||||||
|
|
||||||
|
# register to write for GPIO output pins
|
||||||
|
.equ GPIO_OUTPUT_VAL, 0x1006000C
|
||||||
|
.equ CLINT_MTIMECMP, 0x02004000
|
||||||
|
.equ PERIOD, 500
|
||||||
|
|
||||||
|
# register use:
|
||||||
|
# s0: address of GPIO_OUTPUT_VAL
|
||||||
|
# s1: adress of CLINT_MTIME_CMP
|
||||||
|
# s2: PERIOD
|
||||||
|
|
||||||
|
rvtest_entry_point:
|
||||||
|
|
||||||
|
# initialize LED to off
|
||||||
|
li s0, GPIO_OUTPUT_VAL
|
||||||
|
sw zero, 0(s0) # LEDs off
|
||||||
|
|
||||||
|
# configure timer interrupt
|
||||||
|
li s2, PERIOD
|
||||||
|
csrr t0, time # read lower 32 bits of timer
|
||||||
|
csrr t1, timeh # read upper 32 bits of timer
|
||||||
|
add t0, t0, s2 # increment by PERIOD
|
||||||
|
li s1, CLINT_MTIMECMP # set timer for next toggle
|
||||||
|
sw t0, 0(s1) # CLINT_MTIMECMP = time + PERIOD
|
||||||
|
sw zero, 4(s1) # upper word = 0 (this is only because program is just starting)
|
||||||
|
# csrci mstatus, 8 # clear mstatus.MIE so interrupts are globally disabled
|
||||||
|
li t0, 128 # 1 in mie.MTIE
|
||||||
|
csrw mie, t0 # enable timer interrupts
|
||||||
|
li s3, 4 # loop counter
|
||||||
|
|
||||||
|
/*
|
||||||
|
# enter user mode
|
||||||
|
li t0, 0b11 # 3
|
||||||
|
slli t0, t0, 11 # 11 in bits 12:11
|
||||||
|
csrc mstatus, t0 # mstatus.MPP = 00 (for user mode)
|
||||||
|
la t0, user_start #
|
||||||
|
csrw mepc, t0 # where to go when entering user mode
|
||||||
|
mret
|
||||||
|
*/
|
||||||
|
|
||||||
|
#user_start: # loop with wfi
|
||||||
|
wait_loop:
|
||||||
|
csrr t0, time # check time before timer fires
|
||||||
|
wfi # wait until timer interrupt fires.
|
||||||
|
csrr t0, time # check time again after timer fires for debugging
|
||||||
|
# interrupts are globally disabled, so when the timer fires,
|
||||||
|
# wfi will advance here rather than going to an interrupt handler
|
||||||
|
lw t0, 0(s0) # read GPIO_OUTPUT_VAL
|
||||||
|
xori t0, t0, 1 # toggle least significant bits
|
||||||
|
sw t0, 0(s0) # update GPIO_OUTPUT_VAL to turn LED off->on or on->off
|
||||||
|
lw t0, 0(s1) # read CLINT_MTIME_CMP
|
||||||
|
add t0, t0, s2 # add PERIOD
|
||||||
|
sw t0, 0(s1) # CLINT_MTIME_CMP = CLINT_MTIME_CMP + PERIOD
|
||||||
|
addi s3, s3, -1 # decrement loop counter
|
||||||
|
bnez s3, wait_loop # repeat
|
||||||
|
|
||||||
|
self_loop:
|
||||||
|
j self_loop
|
||||||
|
|
17
examples/exercises/8p9/Makefile
Normal file
17
examples/exercises/8p9/Makefile
Normal file
|
@ -0,0 +1,17 @@
|
||||||
|
TARGET = 8p9
|
||||||
|
|
||||||
|
$(TARGET).elf.objdump: $(TARGET).elf
|
||||||
|
riscv64-unknown-elf-objdump -D $(TARGET).elf > $(TARGET).elf.objdump
|
||||||
|
|
||||||
|
$(TARGET).elf: $(TARGET).S Makefile
|
||||||
|
riscv64-unknown-elf-gcc -g -o $(TARGET) -march=rv32im_zicsr -mabi=ilp32 -mcmodel=medany \
|
||||||
|
-nostartfiles -T../../link/link.ld $(TARGET).S -o $(TARGET).elf
|
||||||
|
|
||||||
|
# simulate in lockstep with ImperasDV
|
||||||
|
sim: $(TARGET).elf.objdump
|
||||||
|
wsim rv32gc 8p9.elf --lockstepverbose > log
|
||||||
|
|
||||||
|
clean:
|
||||||
|
rm -f $(TARGET).elf*
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue