From b01fe7a38b5091e2084311d2bd535ee4c53c8291 Mon Sep 17 00:00:00 2001 From: David Harris Date: Tue, 27 May 2025 03:14:16 -0700 Subject: [PATCH] Exercise solutions --- examples/exercises/11p6/11p6.S | 77 +++++++++++++++ examples/exercises/11p6/Makefile | 17 ++++ examples/exercises/8p3/8p3.S | 9 ++ examples/exercises/8p3/Makefile | 17 ++++ examples/exercises/8p4/8p4.S | 20 ++++ examples/exercises/8p4/Makefile | 17 ++++ examples/exercises/8p5/8p5.S | 29 ++++++ examples/exercises/8p5/Makefile | 17 ++++ examples/exercises/8p6/8p6.S | 164 +++++++++++++++++++++++++++++++ examples/exercises/8p6/Makefile | 17 ++++ examples/exercises/8p7/8p7.S | 134 +++++++++++++++++++++++++ examples/exercises/8p7/Makefile | 17 ++++ examples/exercises/8p8/8p8.S | 56 +++++++++++ examples/exercises/8p8/Makefile | 17 ++++ examples/exercises/8p9/8p9.S | 61 ++++++++++++ examples/exercises/8p9/Makefile | 17 ++++ 16 files changed, 686 insertions(+) create mode 100644 examples/exercises/11p6/11p6.S create mode 100644 examples/exercises/11p6/Makefile create mode 100644 examples/exercises/8p3/8p3.S create mode 100644 examples/exercises/8p3/Makefile create mode 100644 examples/exercises/8p4/8p4.S create mode 100644 examples/exercises/8p4/Makefile create mode 100644 examples/exercises/8p5/8p5.S create mode 100644 examples/exercises/8p5/Makefile create mode 100644 examples/exercises/8p6/8p6.S create mode 100644 examples/exercises/8p6/Makefile create mode 100644 examples/exercises/8p7/8p7.S create mode 100644 examples/exercises/8p7/Makefile create mode 100644 examples/exercises/8p8/8p8.S create mode 100644 examples/exercises/8p8/Makefile create mode 100644 examples/exercises/8p9/8p9.S create mode 100644 examples/exercises/8p9/Makefile diff --git a/examples/exercises/11p6/11p6.S b/examples/exercises/11p6/11p6.S new file mode 100644 index 000000000..380339716 --- /dev/null +++ b/examples/exercises/11p6/11p6.S @@ -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 + + + diff --git a/examples/exercises/11p6/Makefile b/examples/exercises/11p6/Makefile new file mode 100644 index 000000000..ffc37df98 --- /dev/null +++ b/examples/exercises/11p6/Makefile @@ -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* + + diff --git a/examples/exercises/8p3/8p3.S b/examples/exercises/8p3/8p3.S new file mode 100644 index 000000000..d147dba74 --- /dev/null +++ b/examples/exercises/8p3/8p3.S @@ -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 diff --git a/examples/exercises/8p3/Makefile b/examples/exercises/8p3/Makefile new file mode 100644 index 000000000..6764fac1b --- /dev/null +++ b/examples/exercises/8p3/Makefile @@ -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* + + diff --git a/examples/exercises/8p4/8p4.S b/examples/exercises/8p4/8p4.S new file mode 100644 index 000000000..2e00cd087 --- /dev/null +++ b/examples/exercises/8p4/8p4.S @@ -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 diff --git a/examples/exercises/8p4/Makefile b/examples/exercises/8p4/Makefile new file mode 100644 index 000000000..b4cc1c41e --- /dev/null +++ b/examples/exercises/8p4/Makefile @@ -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* + + diff --git a/examples/exercises/8p5/8p5.S b/examples/exercises/8p5/8p5.S new file mode 100644 index 000000000..869281f07 --- /dev/null +++ b/examples/exercises/8p5/8p5.S @@ -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 \ No newline at end of file diff --git a/examples/exercises/8p5/Makefile b/examples/exercises/8p5/Makefile new file mode 100644 index 000000000..f28fc2c57 --- /dev/null +++ b/examples/exercises/8p5/Makefile @@ -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* + + diff --git a/examples/exercises/8p6/8p6.S b/examples/exercises/8p6/8p6.S new file mode 100644 index 000000000..cb1791734 --- /dev/null +++ b/examples/exercises/8p6/8p6.S @@ -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 \ No newline at end of file diff --git a/examples/exercises/8p6/Makefile b/examples/exercises/8p6/Makefile new file mode 100644 index 000000000..9cbe543a1 --- /dev/null +++ b/examples/exercises/8p6/Makefile @@ -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* + + diff --git a/examples/exercises/8p7/8p7.S b/examples/exercises/8p7/8p7.S new file mode 100644 index 000000000..16dbadc11 --- /dev/null +++ b/examples/exercises/8p7/8p7.S @@ -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 \ No newline at end of file diff --git a/examples/exercises/8p7/Makefile b/examples/exercises/8p7/Makefile new file mode 100644 index 000000000..38f3d4705 --- /dev/null +++ b/examples/exercises/8p7/Makefile @@ -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* + + diff --git a/examples/exercises/8p8/8p8.S b/examples/exercises/8p8/8p8.S new file mode 100644 index 000000000..f0f757f0d --- /dev/null +++ b/examples/exercises/8p8/8p8.S @@ -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 \ No newline at end of file diff --git a/examples/exercises/8p8/Makefile b/examples/exercises/8p8/Makefile new file mode 100644 index 000000000..d86276a04 --- /dev/null +++ b/examples/exercises/8p8/Makefile @@ -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* + + diff --git a/examples/exercises/8p9/8p9.S b/examples/exercises/8p9/8p9.S new file mode 100644 index 000000000..f80adc65a --- /dev/null +++ b/examples/exercises/8p9/8p9.S @@ -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 + diff --git a/examples/exercises/8p9/Makefile b/examples/exercises/8p9/Makefile new file mode 100644 index 000000000..eaffe9595 --- /dev/null +++ b/examples/exercises/8p9/Makefile @@ -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* + +