2022-01-30 23:08:02 +00:00
///////////////////////////////////////////
//
// WALLY-TEST-LIB-64.S
//
// Author: Kip Macsai-Goren <kmacsaigoren@g.hmc.edu>
//
// Created 2021-07-19
//
// Copyright (C) 2021 Harvey Mudd College & Oklahoma State University
//
// Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation
// files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy,
// modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software
// is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
// BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT
// OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
///////////////////////////////////////////
# include "model_test.h"
# include "arch_test.h"
2022-02-14 02:22:12 +00:00
. macro INIT_TESTS
2022-01-30 23:08:02 +00:00
RVTEST_ISA ( " RV64I " )
. section . text . init
. globl rvtest_entry_point
rvtest_entry_point :
RVMODEL_BOOT
RVTEST_CODE_BEGIN
2022-02-25 22:14:52 +00:00
2022-01-30 23:08:02 +00:00
// ---------------------------------------------------------------------------------------------
// Initialization Overview:
//
2022-04-29 18:52:42 +00:00
// Initialize t1 as a virtual pointer to the test results
// Initialize a6 as a physical pointer to the test results
2022-04-06 06:43:03 +00:00
// Set up stack pointer, mscratch, sscratch
2022-01-30 23:08:02 +00:00
//
// ---------------------------------------------------------------------------------------------
// address for test results
2022-04-29 18:52:42 +00:00
la t1 , test_1_res
la a6 , test_1_res // a6 reserved for the physical address equivalent of t1 to be used in trap handlers
2022-01-30 23:08:02 +00:00
// any time either is used, both must be updated.
2022-04-06 06:43:03 +00:00
// address for normal user stack, mscratch stack, and sscratch stack
la sp , mscratch_top
csrw mscratch , sp
la sp , sscratch_top
csrw sscratch , sp
la sp , stack_top
2022-01-30 23:08:02 +00:00
2022-02-25 22:14:52 +00:00
. endm
2022-03-25 22:57:03 +00:00
// Code to trigger traps goes here so we have consistent mtvals for instruction adresses
// Even if more tests are added.
. macro CAUSE_TRAP_TRIGGERS
j end_trap_triggers
// The following tests involve causing many of the interrupts and exceptions that are easily done in a few lines
// This effectively includes everything that isn't to do with page faults (virtual memory)
2022-04-20 06:47:18 +00:00
//
// INPUTS: a3 (x13): the number of times one of the infinitely looping interrupt causes should loop before giving up and continuing without the interrupt firing.
//
2022-03-25 22:57:03 +00:00
cause_instr_addr_misaligned :
// cause a misaligned address trap
2022-04-29 18:52:42 +00:00
auipc t3 , 0 // get current PC, which is aligned
addi t3 , t3 , 0x2 // add 2 to pc to create misaligned address (Assumes compressed instructions are disabled)
jr t3 // cause instruction address midaligned trap
2022-03-25 22:57:03 +00:00
ret
cause_instr_access :
2022-04-29 18:52:42 +00:00
sd ra , - 8 ( sp ) // push the return adress onto the stack
2022-03-25 22:57:03 +00:00
addi sp , sp , - 8
2022-05-04 23:01:23 +00:00
jalr zero // cause instruction access trap (address zero is an address with no memory)
2022-04-29 18:52:42 +00:00
ld ra , 0 ( sp ) // pop return adress back from the stack
2022-03-25 22:57:03 +00:00
addi sp , sp , 8
ret
cause_illegal_instr :
2022-04-17 20:56:15 +00:00
. word 0x00000000 // 32 bit zero is an illegal instruction
2022-03-25 22:57:03 +00:00
ret
2022-04-06 06:43:03 +00:00
cause_breakpnt :
2022-03-25 22:57:03 +00:00
ebreak
ret
cause_load_addr_misaligned :
2022-04-29 18:52:42 +00:00
auipc t3 , 0 // get current PC, which is aligned
addi t3 , t3 , 1
lw t4 , 0 ( t3 ) // load from a misaligned address
2022-03-25 22:57:03 +00:00
ret
cause_load_acc :
2022-05-04 23:01:23 +00:00
lw t4 , 0 ( zero ) // load from unimplemented address ( zero)
2022-03-25 22:57:03 +00:00
ret
cause_store_addr_misaligned :
2022-04-29 18:52:42 +00:00
auipc t3 , 0 // get current PC, which is aligned
addi t3 , t3 , 1
sw t4 , 0 ( t3 ) // store to a misaligned address
2022-03-25 22:57:03 +00:00
ret
cause_store_acc :
2022-05-04 23:01:23 +00:00
sw t4 , 0 ( zero ) // store to unimplemented address (zero)
2022-03-25 22:57:03 +00:00
ret
cause_ecall :
2022-04-25 17:45:47 +00:00
// ASSUMES you have already gone to the mode you need to call this from.
2022-03-25 22:57:03 +00:00
ecall
ret
2022-04-17 20:56:15 +00:00
cause_m_time_interrupt :
2022-03-25 22:57:03 +00:00
// The following code works for both RV32 and RV64.
// RV64 alone would be easier using double-word adds and stores
2022-04-29 18:52:42 +00:00
li t3 , 0x30 // Desired offset from the present time
mv a3 , t3 // copy value in to know to stop waiting for interrupt after this many cycles
la t4 , 0x02004000 // MTIMECMP register in CLINT
la t5 , 0x0200BFF8 // MTIME register in CLINT
lw t2 , 0 ( t5 ) // low word of MTIME
lw t6 , 4 ( t5 ) // high word of MTIME
add t3 , t2 , t3 // add desired offset to the current time
bgtu t3 , t2 , nowrap // check new time exceeds current time (no wraparound)
addi t6 , t6 , 1 // if wrap, increment most significant word
sw t6 , 4 ( t4 ) // store into most significant word of MTIMECMP
2022-03-25 22:57:03 +00:00
nowrap :
2022-04-29 18:52:42 +00:00
sw t3 , 0 ( t4 ) // store into least significant word of MTIMECMP
2022-04-17 20:56:15 +00:00
time_loop :
2022-04-20 06:47:18 +00:00
addi a3 , a3 , - 1
2022-04-22 22:45:53 +00:00
bnez a3 , time_loop // go through this loop for [a3 value] iterations before returning without performing interrupt
2022-03-25 22:57:03 +00:00
ret
2022-04-17 20:56:15 +00:00
cause_s_time_interrupt :
2022-04-29 18:52:42 +00:00
li t3 , 0x20
csrs mip , t3 // set supervisor time interrupt pending.
2022-04-17 20:56:15 +00:00
nop // added extra nops in so the csrs can get through the pipeline before returning.
ret
cause_m_soft_interrupt :
2022-04-29 18:52:42 +00:00
la t3 , 0x02000000 // MSIP register in CLINT
li t4 , 1 // 1 in the lsb
sw t4 , 0 ( t3 ) // Write MSIP bit
2022-03-25 22:57:03 +00:00
ret
2022-04-17 20:56:15 +00:00
cause_s_soft_interrupt :
2022-04-29 18:52:42 +00:00
li t3 , 0x2
csrs sip , t3 // set supervisor software interrupt pending. SIP is a subset of MIP, so writing this should also change MIP.
2022-04-17 20:56:15 +00:00
ret
cause_m_ext_interrupt :
2022-04-29 19:55:29 +00:00
// ========== Configure PLIC ==========
// m priority threshold = 0
2022-04-29 18:52:42 +00:00
li t3 , 0xC200000
li t4 , 0
sw t4 , 0 ( t3 )
2022-04-29 19:55:29 +00:00
// s priority threshold = 7
2022-04-29 18:52:42 +00:00
li t3 , 0xC201000
li t4 , 7
sw t4 , 0 ( t3 )
2022-04-29 19:55:29 +00:00
// source 3 (GPIO) priority = 1
2022-04-29 18:52:42 +00:00
li t3 , 0xC000000
li t4 , 1
sw t4 , 0x0C ( t3 )
2022-04-29 19:55:29 +00:00
// enable source 3 in M Mode
2022-04-29 18:52:42 +00:00
li t3 , 0x0C002000
li t4 , 0 b1000
sw t4 , 0 ( t3 )
li t3 , 0x10060000 // load base GPIO memory location
li t4 , 0x1
sw t4 , 0x08 ( t3 ) // enable the first pin as an output
sw t4 , 0x04 ( t3 ) // enable the first pin as an input as well to cause the interrupt to fire
sw zero , 0x1C ( t3 ) // clear rise_ip
sw zero , 0x24 ( t3 ) // clear fall_ip
sw zero , 0x2C ( t3 ) // clear high_ip
sw zero , 0x34 ( t3 ) // clear low_ip
sw t4 , 0x28 ( t3 ) // set first pin to interrupt on a rising value
sw t4 , 0x0C ( t3 ) // write a 1 to the first output pin (cause interrupt)
2022-04-17 20:56:15 +00:00
m_ext_loop :
2022-04-20 06:47:18 +00:00
addi a3 , a3 , - 1
bnez a3 , m_ext_loop // go through this loop for [a3 value] iterations before returning without performing interrupt
2022-04-17 20:56:15 +00:00
ret
cause_s_ext_interrupt_GPIO :
2022-04-29 19:55:29 +00:00
// ========== Configure PLIC ==========
// s priority threshold = 0
2022-04-29 18:52:42 +00:00
li t3 , 0xC201000
li t4 , 0
sw t4 , 0 ( t3 )
2022-04-29 19:55:29 +00:00
// m priority threshold = 7
2022-04-29 18:52:42 +00:00
li t3 , 0xC200000
li t4 , 7
sw t4 , 0 ( t3 )
2022-04-29 19:55:29 +00:00
// source 3 (GPIO) priority = 1
2022-04-29 18:52:42 +00:00
li t3 , 0xC000000
li t4 , 1
sw t4 , 0x0C ( t3 )
2022-04-29 19:55:29 +00:00
// enable source 3 in S mode
2022-04-29 18:52:42 +00:00
li t3 , 0x0C002080
li t4 , 0 b1000
sw t4 , 0 ( t3 )
li t3 , 0x10060000 // load base GPIO memory location
li t4 , 0x1
sw t4 , 0x08 ( t3 ) // enable the first pin as an output
sw t4 , 0x04 ( t3 ) // enable the first pin as an input as well to cause the interrupt to fire
sw zero , 0x1C ( t3 ) // clear rise_ip
sw zero , 0x24 ( t3 ) // clear fall_ip
sw zero , 0x2C ( t3 ) // clear high_ip
sw zero , 0x34 ( t3 ) // clear low_ip
sw t4 , 0x28 ( t3 ) // set first pin to interrupt on a rising value
sw t4 , 0x0C ( t3 ) // write a 1 to the first output pin (cause interrupt)
2022-04-17 20:56:15 +00:00
s_ext_loop :
2022-04-20 06:47:18 +00:00
addi a3 , a3 , - 1
2022-04-22 22:45:53 +00:00
bnez a3 , s_ext_loop // go through this loop for [a3 value] iterations before returning without performing interrupt
2022-03-25 22:57:03 +00:00
ret
end_trap_triggers :
. endm
2022-05-04 21:39:36 +00:00
. macro TRAP_HANDLER MODE , VECTORED = 1 , EXT_SIGNATURE = 0
2022-03-11 19:09:16 +00:00
// MODE decides which mode this trap handler will be taken in (M or S mode)
2022-04-06 06:43:03 +00:00
// Vectored decides whether interrupts are handled with the vector table at trap_handler_MODE (1)
2022-03-11 19:09:16 +00:00
// vs Using the non-vector approach the rest of the trap handler takes (0)
2022-05-04 21:39:36 +00:00
// EXT_SIGNATURE decides whether we will print mtval a string with status.mpie, status.mie, and status.mpp to the signature (1)
2022-03-11 19:09:16 +00:00
// vs not saving that info to the signature (0)
2022-02-25 22:14:52 +00:00
2022-04-29 18:52:42 +00:00
// Set up the exception Handler, keeping the original handler in tp.
la ra , trap_handler_ \ MODE \ ( )
ori ra , ra , \ VECTORED // set mode field of tvec to VECTORED, which will force vectored interrupts if it's 1.
2022-02-25 22:37:11 +00:00
2022-02-25 22:14:52 +00:00
. if ( \ MODE \ ( ) = = m )
2022-04-29 18:52:42 +00:00
csrrw tp , \ MODE \ ( ) tvec , ra // tp reserved for "default" trap handler address that needs to be restored before halting this test.
2022-02-25 22:14:52 +00:00
. else
2022-04-29 18:52:42 +00:00
csrw \ MODE \ ( ) tvec , ra // we only neet save the machine trap handler and this if statement ensures it isn't overwritten
2022-02-25 22:14:52 +00:00
. endif
2022-01-30 23:08:02 +00:00
li a0 , 0
li a1 , 0
li a2 , 0 // reset trap handler inputs to zero
2022-04-29 18:52:42 +00:00
la t4 , 0x02004000 // MTIMECMP register in CLINT
li t5 , 0xFFFFFFFF
sd t5 , 0 ( t4 ) // set mtimecmp to 0xFFFFFFFF to really make sure time interrupts don't go off immediately after being enabled
2022-04-02 19:17:34 +00:00
2022-02-25 22:37:11 +00:00
j trap_handler_end_ \ MODE \ ( ) // skip the trap handler when it is being defined.
2022-01-30 23:08:02 +00:00
// ---------------------------------------------------------------------------------------------
// General traps Handler
//
// Handles traps by branching to different behaviors based on mcause.
//
// Note that allowing the exception handler to change mode for a program is a huge security
// hole, but this is an expedient way of writing tests that need different modes
//
// input parameters:
//
// a0 (x10):
// 0: halt program with no failures
// 1: halt program with failure in x11 = a1
// 2: go to machine mode
// 3: go to supervisor mode
// 4: go to user mode
// others: do nothing
//
// a1 (x11):
// VPN for return address after changing privilege mode.
// This should be the base VPN with no offset.
// 0x0 : defaults to next instruction on the same page the trap was called on.
//
// a2 (x12):
// Pagetype of the current address VPN before changing privilge mode
// Used so that we can know how many bits of the adress are the offset.
// Ignored if a1 == 0x0
// 0: Kilopage
// 1: Megapage
// 2: Gigapage
// 3: Terapage
//
// --------------------------------------------------------------------------------------------
2022-04-17 20:56:15 +00:00
. align 3
2022-02-25 22:14:52 +00:00
trap_handler_ \ MODE \ ( ) :
2022-02-25 22:37:11 +00:00
j trap_unvectored_ \ MODE \ ( ) // for the unvectored implimentation: jump past this table of addresses into the actual handler
// *** ASSUMES that a cause value of 0 for an interrupt is unimplemented
// otherwise, a vectored interrupt handler should jump to trap_handler_\MODE\() + 4 * Interrupt cause code
2022-03-11 19:09:16 +00:00
// No matter the value of VECTORED, exceptions (not interrupts) are handled in an unvecotred way
2022-04-06 06:43:03 +00:00
j s_soft_vector_ \ MODE \ ( ) // 1: instruction access fault // the zero spot is taken up by the instruction to skip this table.
2022-03-11 19:09:16 +00:00
j segfault_ \ MODE \ ( ) // 2: reserved
2022-04-06 06:43:03 +00:00
j m_soft_vector_ \ MODE \ ( ) // 3: breakpoint
2022-03-11 19:09:16 +00:00
j segfault_ \ MODE \ ( ) // 4: reserved
2022-04-06 06:43:03 +00:00
j s_time_vector_ \ MODE \ ( ) // 5: load access fault
2022-03-11 19:09:16 +00:00
j segfault_ \ MODE \ ( ) // 6: reserved
2022-04-06 06:43:03 +00:00
j m_time_vector_ \ MODE \ ( ) // 7: store access fault
2022-03-11 19:09:16 +00:00
j segfault_ \ MODE \ ( ) // 8: reserved
2022-04-06 06:43:03 +00:00
j s_ext_vector_ \ MODE \ ( ) // 9: ecall from S-mode
2022-03-11 19:09:16 +00:00
j segfault_ \ MODE \ ( ) // 10: reserved
2022-04-06 06:43:03 +00:00
j m_ext_vector_ \ MODE \ ( ) // 11: ecall from M-mode
2022-02-25 22:37:11 +00:00
// 12 through >=16 are reserved or designated for platform use
trap_unvectored_ \ MODE \ ( ) :
2022-04-06 06:43:03 +00:00
csrrw sp , \ MODE \ ( ) scratch , sp // swap sp and scratch so we can use the scratch stack in the trap hanler without messing up sp's value or the stack itself.
// *** NOTE: this means that nested traps will be screwed up but they shouldn't happen in any of these tests
trap_stack_saved_ \ MODE \ ( ) : // jump here after handling vectored interupt since we already switch sp and scratch there
2022-01-30 23:08:02 +00:00
// save registers on stack before using
2022-04-29 18:52:42 +00:00
sd ra , - 8 ( sp )
sd t0 , - 16 ( sp )
sd t2 , - 24 ( sp )
2022-01-30 23:08:02 +00:00
// Record trap
2022-04-29 18:52:42 +00:00
csrr ra , \ MODE \ ( ) cause // record the mcause
sd ra , 0 ( a6 )
addi t1 , t1 , 8
addi a6 , a6 , 8 // update pointers for logging results
2022-01-30 23:08:02 +00:00
2022-05-04 21:39:36 +00:00
. if ( \ EXT_SIGNATURE \ ( ) = = 1 ) // record extra information (MTVAL, some status bits) about traps
2022-04-29 18:52:42 +00:00
csrr ra , \ MODE \ ( ) tval
sd ra , 0 ( a6 )
addi t1 , t1 , 8
addi a6 , a6 , 8
2022-03-11 19:09:16 +00:00
2022-04-29 18:52:42 +00:00
csrr ra , \ MODE \ ( ) status
2022-04-02 19:17:34 +00:00
. if ( \ MODE \ ( ) = = m ) // Taking traps in different modes means we want to get different bits from the status register.
2022-04-29 18:52:42 +00:00
li t0 , 0x1888 // mask bits to select MPP, MPIE, and MIE.
2022-04-02 19:17:34 +00:00
. else
2022-04-29 18:52:42 +00:00
li t0 , 0x122 // mask bits to select SPP, SPIE, and SIE.
2022-04-02 19:17:34 +00:00
. endif
2022-04-29 18:52:42 +00:00
and t0 , t0 , ra
sd t0 , 0 ( a6 ) // store masked out status bits to the output
addi t1 , t1 , 8
addi a6 , a6 , 8
2022-03-11 19:09:16 +00:00
. endif
2022-01-30 23:08:02 +00:00
// Respond to trap based on cause
// All interrupts should return after being logged
2022-04-29 18:52:42 +00:00
csrr ra , \ MODE \ ( ) cause
li t0 , 0x8000000000000000 // if msb is set, it is an interrupt
and t0 , t0 , ra
bnez t0 , interrupt_handler_ \ MODE \ ( )
2022-01-30 23:08:02 +00:00
// Other trap handling is specified in the vector Table
2022-04-29 18:52:42 +00:00
la t0 , exception_vector_table_ \ MODE \ ( )
slli ra , ra , 3 // multiply cause by 8 to get offset in vector Table
add t0 , t0 , ra // compute address of vector in Table
ld t0 , 0 ( t0 ) // fectch address of handler from vector Table
jr t0 // and jump to the handler
2022-04-06 06:43:03 +00:00
interrupt_handler_ \ MODE \ ( ) :
2022-04-29 18:52:42 +00:00
la t0 , interrupt_vector_table_ \ MODE \ ( ) // NOTE THIS IS NOT THE SAME AS VECTORED INTERRUPTS!!!
slli ra , ra , 3 // multiply cause by 8 to get offset in vector Table
add t0 , t0 , ra // compute address of vector in Table
ld t0 , 0 ( t0 ) // fectch address of handler from vector Table
jr t0 // and jump to the handler
2022-04-06 06:43:03 +00:00
2022-02-25 22:14:52 +00:00
segfault_ \ MODE \ ( ) :
2022-04-29 18:52:42 +00:00
ld t2 , - 24 ( sp ) // restore registers from stack before faulting
ld t0 , - 16 ( sp )
ld ra , - 8 ( sp )
2022-01-30 23:08:02 +00:00
j terminate_test // halt program.
2022-02-25 22:14:52 +00:00
trapreturn_ \ MODE \ ( ) :
2022-04-29 18:52:42 +00:00
csrr ra , \ MODE \ ( ) epc
addi ra , ra , 4 // return to the address AFTER the trapping instruction
2022-01-30 23:08:02 +00:00
2022-02-25 22:14:52 +00:00
trapreturn_specified_ \ MODE \ ( ) :
2022-04-29 18:52:42 +00:00
// reset the necessary pointers and registers (ra, t0, t1, and the return address going to mepc)
// note that we don't need to change t2 since it was a temporary register with no important address in it.
2022-01-30 23:08:02 +00:00
// so that when we return to a new virtual address, they're all in the right spot as well.
2022-02-25 22:14:52 +00:00
beqz a1 , trapreturn_finished_ \ MODE \ ( ) // either update values, of go to default return address.
2022-01-30 23:08:02 +00:00
2022-04-29 18:52:42 +00:00
la t0 , trap_return_pagetype_table_ \ MODE \ ( )
2022-01-30 23:08:02 +00:00
slli a2 , a2 , 3
2022-04-29 18:52:42 +00:00
add t0 , t0 , a2
ld a2 , 0 ( t0 ) // a2 = number of offset bits in current page type
2022-01-30 23:08:02 +00:00
2022-04-29 18:52:42 +00:00
li t0 , 1
sll t0 , t0 , a2
addi t0 , t0 , - 1 // t0 = mask bits for offset into current pagetype
2022-01-30 23:08:02 +00:00
2022-04-06 06:43:03 +00:00
// reset the top of the stack, which will be put into ra
2022-04-29 18:52:42 +00:00
ld t2 , - 8 ( sp )
and t2 , t0 , t2 // t2 = offset for ra
add t2 , t2 , a1 // t2 = new address for ra
sd t2 , - 8 ( sp )
// reset the second spot in the stack, which will be put into t0
ld t2 , - 16 ( sp )
and t2 , t0 , t2 // t2 = offset for t0
add t2 , t2 , a1 // t2 = new address for t0
sd t2 , - 16 ( sp )
// reset t1, the pointer for the virtual address of the output of the tests
and t2 , t0 , t1 // t2 = offset for t1
add t1 , t2 , a1 // t1 = new address for the result pointer
2022-01-30 23:08:02 +00:00
2022-04-29 18:52:42 +00:00
// reset ra, which temporarily holds the return address that will be written to mepc.
and ra , t0 , ra // ra = offset for the return address
add ra , ra , a1 // ra = new return address.
2022-01-30 23:08:02 +00:00
li a1 , 0
li a2 , 0 // reset trapreturn inputs to the trap handler
2022-02-25 22:14:52 +00:00
trapreturn_finished_ \ MODE \ ( ) :
2022-04-29 18:52:42 +00:00
csrw \ MODE \ ( ) epc , ra // update the epc with address of next instruction
ld t2 , - 24 ( sp ) // restore registers from stack before returning
ld t0 , - 16 ( sp )
ld ra , - 8 ( sp )
2022-04-17 20:56:15 +00:00
csrrw sp , \ MODE \ ( ) scratch , sp // switch sp and scratch stack back to restore the non-trap stack pointer
2022-02-25 22:14:52 +00:00
\ MODE \ ( ) ret // return from trap
2022-01-30 23:08:02 +00:00
2022-04-22 22:45:53 +00:00
// specific exception handlers
2022-02-25 22:14:52 +00:00
ecallhandler_ \ MODE \ ( ) :
2022-01-30 23:08:02 +00:00
// Check input parameter a0. encoding above.
2022-04-29 18:52:42 +00:00
li t0 , 2 // case 2: change to machine mode
beq a0 , t0 , ecallhandler_changetomachinemode_ \ MODE \ ( )
li t0 , 3 // case 3: change to supervisor mode
beq a0 , t0 , ecallhandler_changetosupervisormode_ \ MODE \ ( )
li t0 , 4 // case 4: change to user mode
beq a0 , t0 , ecallhandler_changetousermode_ \ MODE \ ( )
2022-01-30 23:08:02 +00:00
// unsupported ecalls should segfault
2022-02-25 22:14:52 +00:00
j segfault_ \ MODE \ ( )
2022-01-30 23:08:02 +00:00
2022-02-25 22:14:52 +00:00
ecallhandler_changetomachinemode_ \ MODE \ ( ) :
// Force status.MPP (bits 12:11) to 11 to enter machine mode after mret
2022-04-20 06:47:18 +00:00
// note that it is impossible to return to M mode after a trap delegated to S mode
2022-04-29 18:52:42 +00:00
li ra , 0 b1100000000000
csrs \ MODE \ ( ) status , ra
2022-04-22 22:45:53 +00:00
j trapreturn_ \ MODE \ ( )
2022-01-30 23:08:02 +00:00
2022-02-25 22:14:52 +00:00
ecallhandler_changetosupervisormode_ \ MODE \ ( ) :
2022-04-20 06:47:18 +00:00
// Force status.MPP (bits 12:11) and status.SPP (bit 8) to 01 to enter supervisor mode after (m/s)ret
2022-04-29 18:52:42 +00:00
li ra , 0 b1000000000000
csrc \ MODE \ ( ) status , ra
li ra , 0 b0100100000000
csrs \ MODE \ ( ) status , ra
2022-02-25 22:14:52 +00:00
j trapreturn_ \ MODE \ ( )
2022-01-30 23:08:02 +00:00
2022-02-25 22:14:52 +00:00
ecallhandler_changetousermode_ \ MODE \ ( ) :
2022-04-20 06:47:18 +00:00
// Force status.MPP (bits 12:11) and status.SPP (bit 8) to 00 to enter user mode after (m/s)ret
2022-04-29 18:52:42 +00:00
li ra , 0 b1100100000000
csrc \ MODE \ ( ) status , ra
2022-02-25 22:14:52 +00:00
j trapreturn_ \ MODE \ ( )
2022-01-30 23:08:02 +00:00
2022-03-11 19:09:16 +00:00
instrpagefault_ \ MODE \ ( ) :
2022-04-29 18:52:42 +00:00
ld ra , - 8 ( sp ) // load return address from stack into ra (the address AFTER the jal to the faulting address)
j trapreturn_finished_ \ MODE \ ( ) // puts ra into mepc, restores stack and returns to program (outside of faulting page)
2022-01-30 23:08:02 +00:00
2022-03-11 19:09:16 +00:00
instrfault_ \ MODE \ ( ) :
2022-04-29 18:52:42 +00:00
ld ra , - 8 ( sp ) // load return address from stack into ra (the address AFTER the jal to the faulting address)
2022-04-06 06:43:03 +00:00
j trapreturn_finished_ \ MODE \ ( ) // return to the code at ra value from before trap
2022-03-11 19:09:16 +00:00
2022-02-25 22:14:52 +00:00
illegalinstr_ \ MODE \ ( ) :
j trapreturn_ \ MODE \ ( ) // return to the code after recording the mcause
2022-02-14 02:22:12 +00:00
2022-02-25 22:14:52 +00:00
accessfault_ \ MODE \ ( ) :
j trapreturn_ \ MODE \ ( )
2022-01-30 23:08:02 +00:00
2022-03-11 19:09:16 +00:00
addr_misaligned_ \ MODE \ ( ) :
2022-02-25 22:37:11 +00:00
j trapreturn_ \ MODE \ ( )
2022-03-11 19:09:16 +00:00
breakpt_ \ MODE \ ( ) :
2022-02-25 22:37:11 +00:00
j trapreturn_ \ MODE \ ( )
2022-04-22 22:45:53 +00:00
// Vectored interrupt handlers: record the fact that the handler went to the correct vector and then continue to handling
// note: does not mess up any registers, saves and restores them to the stack instead.
2022-04-06 06:43:03 +00:00
s_soft_vector_ \ MODE \ ( ) :
csrrw sp , \ MODE \ ( ) scratch , sp // swap sp and scratch so we can use the scratch stack in the trap hanler without messing up sp's value or the stack itself.
2022-04-29 18:52:42 +00:00
sd t0 , - 8 ( sp ) // put t0 on the scratch stack before messing with it
li t0 , 0x7EC01 // write 0x7ec01 (for "VEC"tored and 01 for the interrupt code)
2022-04-06 06:43:03 +00:00
j vectored_int_end_ \ MODE \ ( )
m_soft_vector_ \ MODE \ ( ) :
csrrw sp , \ MODE \ ( ) scratch , sp // swap sp and scratch so we can use the scratch stack in the trap hanler without messing up sp's value or the stack itself.
2022-04-29 18:52:42 +00:00
sd t0 , - 8 ( sp ) // put t0 on the scratch stack before messing with it
li t0 , 0x7EC03 // write 0x7ec03 (for "VEC"tored and 03 for the interrupt code)
2022-04-06 06:43:03 +00:00
j vectored_int_end_ \ MODE \ ( )
s_time_vector_ \ MODE \ ( ) :
csrrw sp , \ MODE \ ( ) scratch , sp // swap sp and scratch so we can use the scratch stack in the trap hanler without messing up sp's value or the stack itself.
2022-04-29 18:52:42 +00:00
sd t0 , - 8 ( sp ) // put t0 on the scratch stack before messing with it
li t0 , 0x7EC05 // write 0x7ec05 (for "VEC"tored and 05 for the interrupt code)
2022-04-06 06:43:03 +00:00
j vectored_int_end_ \ MODE \ ( )
m_time_vector_ \ MODE \ ( ) :
csrrw sp , \ MODE \ ( ) scratch , sp // swap sp and scratch so we can use the scratch stack in the trap hanler without messing up sp's value or the stack itself.
2022-04-29 18:52:42 +00:00
sd t0 , - 8 ( sp ) // put t0 on the scratch stack before messing with it
li t0 , 0x7EC07 // write 0x7ec07 (for "VEC"tored and 07 for the interrupt code)
2022-04-06 06:43:03 +00:00
j vectored_int_end_ \ MODE \ ( )
s_ext_vector_ \ MODE \ ( ) :
csrrw sp , \ MODE \ ( ) scratch , sp // swap sp and scratch so we can use the scratch stack in the trap hanler without messing up sp's value or the stack itself.
2022-04-29 18:52:42 +00:00
sd t0 , - 8 ( sp ) // put t0 on the scratch stack before messing with it
li t0 , 0x7EC09 // write 0x7ec09 (for "VEC"tored and 08 for the interrupt code)
2022-04-06 06:43:03 +00:00
j vectored_int_end_ \ MODE \ ( )
m_ext_vector_ \ MODE \ ( ) :
csrrw sp , \ MODE \ ( ) scratch , sp // swap sp and scratch so we can use the scratch stack in the trap hanler without messing up sp's value or the stack itself.
2022-04-29 18:52:42 +00:00
sd t0 , - 8 ( sp ) // put t0 on the scratch stack before messing with it
li t0 , 0x7EC0B // write 0x7ec0B (for "VEC"tored and 0B for the interrupt code)
2022-04-06 06:43:03 +00:00
j vectored_int_end_ \ MODE \ ( )
vectored_int_end_ \ MODE \ ( ) :
2022-04-29 18:52:42 +00:00
sd t0 , 0 ( a6 ) // store to signature to show vectored interrupts succeeded.
addi t1 , t1 , 8
addi a6 , a6 , 8
ld t0 , - 8 ( sp ) // restore t0 before continuing to handle trap in case its needed.
2022-04-06 06:43:03 +00:00
j trap_stack_saved_ \ MODE \ ( )
2022-04-22 22:45:53 +00:00
// specific interrupt handlers
2022-04-06 06:43:03 +00:00
soft_interrupt_ \ MODE \ ( ) :
2022-04-29 18:52:42 +00:00
la t0 , 0x02000000 // Reset by clearing MSIP interrupt from CLINT
sw zero , 0 ( t0 )
2022-04-17 20:56:15 +00:00
2022-04-18 07:22:16 +00:00
csrci \ MODE \ ( ) ip , 0x2 // clear supervisor software interrupt pending bit
2022-04-29 18:52:42 +00:00
ld ra , - 8 ( sp ) // load return address from stack into ra (the address to return to after causing this interrupt)
2022-04-17 20:56:15 +00:00
// Note: we do this because the mepc loads in the address of the instruction after the sw that causes the interrupt
// This means that this trap handler will return to the next address after that one, which might be unpredictable behavior.
j trapreturn_finished_ \ MODE \ ( ) // return to the code at ra value from before trap
2022-04-02 19:17:34 +00:00
time_interrupt_ \ MODE \ ( ) :
2022-04-29 18:52:42 +00:00
la t0 , 0x02004000 // MTIMECMP register in CLINT
li t2 , 0xFFFFFFFF
sd t2 , 0 ( t0 ) // reset interrupt by setting mtimecmp to 0xFFFFFFFF
2022-04-06 06:43:03 +00:00
2022-04-29 18:52:42 +00:00
li t0 , 0x20
csrc \ MODE \ ( ) ip , t0
ld ra , - 8 ( sp ) // load return address from stack into ra (the address to return to after the loop is complete)
2022-04-06 06:43:03 +00:00
j trapreturn_finished_ \ MODE \ ( ) // return to the code at ra value from before trap
2022-02-25 22:37:11 +00:00
2022-04-02 19:17:34 +00:00
ext_interrupt_ \ MODE \ ( ) :
2022-04-29 18:52:42 +00:00
li t3 , 0x10060000 // reset interrupt by clearing all the GPIO bits
sw zero , 8 ( t3 ) // disable the first pin as an output
sw zero , 40 ( t3 ) // write a 0 to the first output pin (reset interrupt)
2022-04-17 20:56:15 +00:00
2022-04-29 19:55:29 +00:00
// reset PLIC to turn off external interrupts
// m priority threshold = 7
2022-04-29 18:52:42 +00:00
li t3 , 0xC200000
li t0 , 0x7
sw t0 , 0 ( t3 )
2022-04-29 19:55:29 +00:00
// s priority threshold = 7
2022-04-29 18:52:42 +00:00
li t3 , 0xC201000
li t0 , 0x7
sw t0 , 0 ( t3 )
2022-04-29 19:55:29 +00:00
// source 3 (GPIO) priority = 0
2022-04-29 18:52:42 +00:00
li t3 , 0xC000000
li t0 , 0
sw t0 , 0x0C ( t3 )
2022-04-29 19:55:29 +00:00
// disable source 3 in M mode
2022-04-29 18:52:42 +00:00
li t3 , 0x0C002000
li t0 , 0 b0000
sw t0 , 0 ( t3 )
2022-04-29 19:55:29 +00:00
// enable source 3 in S mode
2022-04-29 18:52:42 +00:00
li t3 , 0x0C002080
li t4 , 0 b0000
sw t4 , 0 ( t3 )
2022-04-18 07:22:16 +00:00
2022-04-29 18:52:42 +00:00
li t0 , 0x200
csrc \ MODE \ ( ) ip , t0
2022-04-18 07:22:16 +00:00
2022-04-29 18:52:42 +00:00
ld ra , - 8 ( sp ) // load return address from stack into ra (the address to return to after the loop is complete)
2022-04-18 07:22:16 +00:00
j trapreturn_finished_ \ MODE \ ( ) // return to the code at ra value from before trap
2022-01-30 23:08:02 +00:00
// Table of trap behavior
// lists what to do on each exception (not interrupts)
// unexpected exceptions should cause segfaults for easy detection
// Expected exceptions should increment the EPC to the next instruction and return
. align 3 // aligns this data table to an 8 byte boundary
2022-02-25 22:37:11 +00:00
exception_vector_table_ \ MODE \ ( ) :
2022-03-11 19:09:16 +00:00
.8 byte addr_misaligned_ \ MODE \ ( ) // 0: instruction address misaligned
2022-02-25 22:14:52 +00:00
.8 byte instrfault_ \ MODE \ ( ) // 1: instruction access fault
.8 byte illegalinstr_ \ MODE \ ( ) // 2: illegal instruction
2022-03-11 19:09:16 +00:00
.8 byte breakpt_ \ MODE \ ( ) // 3: breakpoint
.8 byte addr_misaligned_ \ MODE \ ( ) // 4: load address misaligned
2022-02-25 22:14:52 +00:00
.8 byte accessfault_ \ MODE \ ( ) // 5: load access fault
2022-03-11 19:09:16 +00:00
.8 byte addr_misaligned_ \ MODE \ ( ) // 6: store address misaligned
2022-02-25 22:14:52 +00:00
.8 byte accessfault_ \ MODE \ ( ) // 7: store access fault
.8 byte ecallhandler_ \ MODE \ ( ) // 8: ecall from U-mode
.8 byte ecallhandler_ \ MODE \ ( ) // 9: ecall from S-mode
.8 byte segfault_ \ MODE \ ( ) // 10: reserved
.8 byte ecallhandler_ \ MODE \ ( ) // 11: ecall from M-mode
2022-03-11 19:09:16 +00:00
.8 byte instrpagefault_ \ MODE \ ( ) // 12: instruction page fault
2022-02-25 22:14:52 +00:00
.8 byte trapreturn_ \ MODE \ ( ) // 13: load page fault
.8 byte segfault_ \ MODE \ ( ) // 14: reserved
.8 byte trapreturn_ \ MODE \ ( ) // 15: store page fault
2022-01-30 23:08:02 +00:00
2022-04-06 06:43:03 +00:00
. align 3 // aligns this data table to an 8 byte boundary
interrupt_vector_table_ \ MODE \ ( ) :
.8 byte segfault_ \ MODE \ ( ) // 0: reserved
2022-04-17 20:56:15 +00:00
.8 byte soft_interrupt_ \ MODE \ ( ) // 1: instruction access fault // the zero spot is taken up by the instruction to skip this table.
2022-04-06 06:43:03 +00:00
.8 byte segfault_ \ MODE \ ( ) // 2: reserved
2022-04-17 20:56:15 +00:00
.8 byte soft_interrupt_ \ MODE \ ( ) // 3: breakpoint
2022-04-06 06:43:03 +00:00
.8 byte segfault_ \ MODE \ ( ) // 4: reserved
2022-04-17 20:56:15 +00:00
.8 byte time_interrupt_ \ MODE \ ( ) // 5: load access fault
2022-04-06 06:43:03 +00:00
.8 byte segfault_ \ MODE \ ( ) // 6: reserved
2022-04-17 20:56:15 +00:00
.8 byte time_interrupt_ \ MODE \ ( ) // 7: store access fault
2022-04-06 06:43:03 +00:00
.8 byte segfault_ \ MODE \ ( ) // 8: reserved
2022-04-17 20:56:15 +00:00
.8 byte ext_interrupt_ \ MODE \ ( ) // 9: ecall from S-mode
2022-04-06 06:43:03 +00:00
.8 byte segfault_ \ MODE \ ( ) // 10: reserved
2022-04-17 20:56:15 +00:00
.8 byte ext_interrupt_ \ MODE \ ( ) // 11: ecall from M-mode
2022-04-06 06:43:03 +00:00
2022-01-30 23:08:02 +00:00
. align 3
2022-02-25 22:14:52 +00:00
trap_return_pagetype_table_ \ MODE \ ( ) :
2022-01-30 23:08:02 +00:00
.8 byte 0xC // 0: kilopage has 12 offset bits
.8 byte 0x15 // 1: megapage has 21 offset bits
.8 byte 0x1E // 2: gigapage has 30 offset bits
.8 byte 0x27 // 3: terapage has 39 offset bits
2022-02-25 22:14:52 +00:00
trap_handler_end_ \ MODE \ ( ) : // place to jump to so we can skip the trap handler and continue with the test
2022-02-14 02:22:12 +00:00
. endm
// Test Summary table!
// Test Name : Description : Fault output value : Normal output values
// ---------------------:-------------------------------------------:-------------------------------------------:------------------------------------------------------
// write64_test : Write 64 bits to address : 0x6, 0x7, or 0xf : None
// write32_test : Write 32 bits to address : 0x6, 0x7, or 0xf : None
// write16_test : Write 16 bits to address : 0x6, 0x7, or 0xf : None
// write08_test : Write 8 bits to address : 0x6, 0x7, or 0xf : None
// read64_test : Read 64 bits from address : 0x4, 0x5, or 0xd, then 0xbad : readvalue in hex
2022-02-15 20:15:09 +00:00
// read32_test : Read 32 bits from address : 0x4, 0x5, or 0xd, then 0xbad : readvalue in hex
// read16_test : Read 16 bits from address : 0x4, 0x5, or 0xd, then 0xbad : readvalue in hex
// read08_test : Read 8 bits from address : 0x4, 0x5, or 0xd, then 0xbad : readvalue in hex
2022-04-29 18:52:42 +00:00
// executable_test : test executable on virtual page : 0x0, 0x1, or 0xc, then 0xbad : value of t2 modified by exectuion code (usually 0x111)
2022-02-14 02:22:12 +00:00
// terminate_test : terminate tests : mcause value for fault : from M 0xb, from S 0x9, from U 0x8
// goto_baremetal : satp.MODE = bare metal : None : None
// goto_sv39 : satp.MODE = sv39 : None : None
// goto_sv48 : satp.MODE = sv48 : None : None
// goto_m_mode : go to mahcine mode : mcause value for fault : from M 0xb, from S 0x9, from U 0x8
// goto_s_mode : go to supervisor mode : mcause value for fault : from M 0xb, from S 0x9, from U 0x8
// goto_u_mode : go to user mode : mcause value for fault : from M 0xb, from S 0x9, from U 0x8
// write_read_csr : write to specified CSR : old CSR value, 0x2, depending on perms : value written to CSR
// csr_r_access : test read-only permissions on CSR : 0xbad : 0x2, then 0x11
. macro WRITE64 ADDR VAL
// attempt to write VAL to ADDR
// Success outputs:
// None
// Fault outputs:
// 0x6: misaligned address
// 0x7: access fault
// 0xf: page fault
2022-04-29 18:52:42 +00:00
li t4 , \ VAL
li t5 , \ ADDR
sd t4 , 0 ( t5 )
2022-02-14 02:22:12 +00:00
. endm
. macro WRITE32 ADDR VAL
// all write tests have the same description/outputs as write64
2022-04-29 18:52:42 +00:00
li t4 , \ VAL
li t5 , \ ADDR
sw t4 , 0 ( t5 )
2022-02-14 02:22:12 +00:00
. endm
. macro WRITE16 ADDR VAL
// all write tests have the same description/outputs as write64
2022-04-29 18:52:42 +00:00
li t4 , \ VAL
li t5 , \ ADDR
sh t4 , 0 ( t5 )
2022-02-14 02:22:12 +00:00
. endm
. macro WRITE08 ADDR VAL
// all write tests have the same description/outputs as write64
2022-04-29 18:52:42 +00:00
li t4 , \ VAL
li t5 , \ ADDR
sb t4 , 0 ( t5 )
2022-02-14 02:22:12 +00:00
. endm
. macro READ64 ADDR
// Attempt read at ADDR. Write the value read out to the output *** Consider adding specific test for reading a non known value
// Success outputs:
// value read out from ADDR
// Fault outputs:
// One of the following followed by 0xBAD
// 0x4: misaligned address
// 0x5: access fault
// 0xD: page fault
2022-04-29 18:52:42 +00:00
li t2 , 0xBAD // bad value that will be overwritten on good reads.
li t4 , \ ADDR
ld t2 , 0 ( t4 )
sd t2 , 0 ( t1 )
addi t1 , t1 , 8
addi a6 , a6 , 8
2022-02-14 02:22:12 +00:00
. endm
. macro READ32 ADDR
// All reads have the same description/outputs as read64.
// They will store the sign extended value of what was read out at ADDR
2022-04-29 18:52:42 +00:00
li t2 , 0xBAD // bad value that will be overwritten on good reads.
li t4 , \ ADDR
lw t2 , 0 ( t4 )
sd t2 , 0 ( t1 )
addi t1 , t1 , 8
addi a6 , a6 , 8
2022-02-14 02:22:12 +00:00
. endm
. macro READ16 ADDR
// All reads have the same description/outputs as read64.
// They will store the sign extended value of what was read out at ADDR
2022-04-29 18:52:42 +00:00
li t2 , 0xBAD // bad value that will be overwritten on good reads.
li t4 , \ ADDR
lh t2 , 0 ( t4 )
sd t2 , 0 ( t1 )
addi t1 , t1 , 8
addi a6 , a6 , 8
2022-02-14 02:22:12 +00:00
. endm
. macro READ08 ADDR
// All reads have the same description/outputs as read64.
// They will store the sign extended value of what was read out at ADDR
2022-04-29 18:52:42 +00:00
li t2 , 0xBAD // bad value that will be overwritten on good reads.
li t4 , \ ADDR
lb t2 , 0 ( t4 )
sd t2 , 0 ( t1 )
addi t1 , t1 , 8
addi a6 , a6 , 8
2022-02-14 02:22:12 +00:00
. endm
// These goto_x_mode tests all involve invoking the trap handler,
// So their outputs are inevitably:
// 0x8: test called from U mode
// 0x9: test called from S mode
// 0xB: test called from M mode
// they generally do not fault or cause issues as long as these modes are enabled
2022-03-11 19:09:16 +00:00
. macro GOTO_M_MODE RETURN_VPN = 0x0 RETURN_PAGETYPE = 0x0
2022-02-14 02:22:12 +00:00
li a0 , 2 // determine trap handler behavior (go to machine mode)
li a1 , \ RETURN_VPN // return VPN
li a2 , \ RETURN_PAGETYPE // return page types
ecall // writes mcause to the output.
// now in S mode
. endm
2022-03-11 19:09:16 +00:00
. macro GOTO_S_MODE RETURN_VPN = 0x0 RETURN_PAGETYPE = 0x0
2022-02-14 02:22:12 +00:00
li a0 , 3 // determine trap handler behavior (go to supervisor mode)
li a1 , \ RETURN_VPN // return VPN
li a2 , \ RETURN_PAGETYPE // return page types
ecall // writes mcause to the output.
// now in S mode
. endm
2022-03-11 19:09:16 +00:00
. macro GOTO_U_MODE RETURN_VPN = 0x0 RETURN_PAGETYPE = 0x0
2022-02-14 02:22:12 +00:00
li a0 , 4 // determine trap handler behavior (go to user mode)
li a1 , \ RETURN_VPN // return VPN
li a2 , \ RETURN_PAGETYPE // return page types
ecall // writes mcause to the output.
// now in S mode
. endm
// These tests change virtual memory settings, turning it on/off and changing between types.
2022-04-25 17:45:47 +00:00
// They don't have outputs as any error with turning on virtual memory should reveal itself in the tests
2022-02-14 02:22:12 +00:00
. macro GOTO_BAREMETAL
// Turn translation off
2022-04-29 18:52:42 +00:00
li t2 , 0 // satp.MODE value for bare metal (0)
slli t2 , t2 , 60
csrw satp , t2
2022-02-14 02:22:12 +00:00
. endm
2022-02-27 23:28:25 +00:00
. macro GOTO_SV39 ASID BASE_PPN
2022-02-14 02:22:12 +00:00
// Turn on sv39 virtual memory
2022-04-29 18:52:42 +00:00
li t2 , 8 // satp.MODE value for Sv39 (8)
slli t2 , t2 , 60
li t4 , \ ASID
slli t4 , t4 , 44
or t2 , t2 , t4 // put ASID into the correct field of SATP
li t3 , \ BASE_PPN // Base Pagetable physical page number, satp.PPN field.
add t2 , t2 , t3
csrw satp , t2
2022-02-14 02:22:12 +00:00
. endm
2022-02-27 23:28:25 +00:00
. macro GOTO_SV48 ASID BASE_PPN
2022-02-14 02:22:12 +00:00
// Turn on sv48 virtual memory
2022-04-29 18:52:42 +00:00
li t2 , 9 // satp.MODE value for Sv39 (8)
slli t2 , t2 , 60
li t4 , \ ASID
slli t4 , t4 , 44
or t2 , t2 , t4 // put ASID into the correct field of SATP
li t3 , \ BASE_PPN // Base Pagetable physical page number, satp.PPN field.
add t2 , t2 , t3
csrw satp , t2
2022-02-14 02:22:12 +00:00
. endm
. macro WRITE_READ_CSR CSR VAL
// attempt to write CSR with VAL. Note: this also tests read access to CSR
// Success outputs:
// value read back out from CSR after writing
// Fault outputs:
// The previous CSR value before write attempt
2022-04-25 17:45:47 +00:00
// Most likely 0x2, the mcause for illegal instruction if we don't have write or read access
2022-04-29 18:52:42 +00:00
li t5 , 0xbad // load bad value to be overwritten by csrr
li t4 , \ VAL \ ( )
csrw \ CSR \ ( ) , t4
csrr t5 , \ CSR
sd t5 , 0 ( t1 )
addi t1 , t1 , 8
addi a6 , a6 , 8
2022-02-14 02:22:12 +00:00
. endm
. macro CSR_R_ACCESS CSR
// verify that a csr is accessible to read but not to write
// Success outputs:
// 0x2, then
2022-04-25 17:45:47 +00:00
// 0x11
2022-02-14 02:22:12 +00:00
// Fault outputs:
2022-04-25 17:45:47 +00:00
// 0xBAD
2022-04-29 18:52:42 +00:00
csrr t4 , \ CSR
2022-02-14 02:22:12 +00:00
csrwi \ CSR \ ( ) , 0xA // Attempt to write a 'random' value to the CSR
2022-04-29 18:52:42 +00:00
csrr t5 , \ CSR
bne t5 , t4 , 1f // 1f represents write_access
li t5 , 0x11 // Write failed, confirming read only permissions.
2022-02-14 02:22:12 +00:00
j 2f // j r_access_end
1 : // w_access (write succeeded, violating read-only)
2022-04-29 18:52:42 +00:00
li t5 , 0xBAD
2022-02-14 02:22:12 +00:00
2 : // r_access end
2022-04-29 18:52:42 +00:00
sd t5 , 0 ( t1 )
addi t1 , t1 , 8
addi a6 , a6 , 8
2022-02-14 02:22:12 +00:00
. endm
. macro EXECUTE_AT_ADDRESS ADDR
2022-04-29 18:52:42 +00:00
// Execute the code already written to ADDR, returning the value in t2.
2022-04-25 17:45:47 +00:00
// Note: this test itself doesn't write the code to ADDR because it might be callled at a point where we dont have write access to ADDR
2022-04-29 18:52:42 +00:00
// Assumes the code modifies t2, usually to become 0x111.
// Sample code: 0x11100393 (li t2, 0x111), 0x00008067 (ret)
2022-02-14 02:22:12 +00:00
// Success outputs:
2022-04-29 18:52:42 +00:00
// modified value of t2. (0x111 if you use the sample code)
2022-02-14 02:22:12 +00:00
// Fault outputs:
// One of the following followed by 0xBAD
// 0x0: misaligned address
// 0x1: access fault
// 0xC: page fault
fence . i // forces caches and main memory to sync so execution code written to ADDR can run.
2022-04-29 18:52:42 +00:00
li t2 , 0xBAD
li t3 , \ ADDR
jalr t3 // jump to executable test code
sd t2 , 0 ( t1 )
addi t1 , t1 , 8
addi a6 , a6 , 8
2022-02-14 02:22:12 +00:00
. endm
2022-06-28 01:59:44 +00:00
. macro SETUP_PLIC
# Setup PLIC with a series of register writes
. equ PLIC_INTPRI_GPIO , 0x0C00000C # GPIO is interrupt 3
. equ PLIC_INTPRI_UART , 0x0C000028 # UART is interrupt 10
. equ PLIC_INTPENDING0 , 0x0C001000 # intPending0 register
. equ PLIC_INTEN00 , 0x0C002000 # interrupt enables for context 0 ( machine mode ) sources 31 : 1
. equ PLIC_INTEN10 , 0x0C002080 # interrupt enables for context 1 ( supervisor mode ) sources 31 : 1
. equ PLIC_THRESH0 , 0x0C200000 # Priority threshold for context 0 ( machine mode )
. equ PLIC_CLAIM0 , 0x0C200004 # Claim / Complete register for context 0
. equ PLIC_THRESH1 , 0x0C201000 # Priority threshold for context 1 ( supervisor mode )
. equ PLIC_CLAIM1 , 0x0C201004 # Claim / Complete register for context 1
.4 byte PLIC_THRESH0 , 0 , write32_test # Set PLIC machine mode interrupt threshold to 0 to accept all interrupts
.4 byte PLIC_THRESH1 , 7 , write32_test # Set PLIC supervisor mode interrupt threshold to 7 to accept no interrupts
.4 byte PLIC_INTPRI_GPIO , 7 , write32_test # Set GPIO to high priority
.4 byte PLIC_INTPRI_UART , 7 , write32_test # Set UART to high priority
.4 byte PLIC_INTEN00 , 0xFFFFFFFF , write32_test # Enable all interrupt sources for machine mode
.4 byte PLIC_INTEN10 , 0x00000000 , write32_test # Disable all interrupt sources for supervisor mode
. endm
2022-02-14 02:22:12 +00:00
. macro END_TESTS
// invokes one final ecall to return to machine mode then terminates this program, so the output is
// 0x8: termination called from U mode
// 0x9: termination called from S mode
// 0xB: termination called from M mode
j terminate_test
. endm
2022-01-30 23:08:02 +00:00
// ---------------------------------------------------------------------------------------------
// Test Handler
//
// This test handler works in a similar wy to the trap handler. It takes in a few things by reading from a table in memory
// (see test_cases) and performing certain behavior based on them.
//
// Input parameters:
//
2022-04-29 18:52:42 +00:00
// t3:
2022-02-14 05:30:00 +00:00
// Address input for the test taking place (think: address to read/write, new address to return to, etc...)
2022-01-30 23:08:02 +00:00
//
2022-04-29 18:52:42 +00:00
// t4:
2022-02-14 05:30:00 +00:00
// Value input for the test taking place (think: value to write, any other extra info needed)
2022-01-30 23:08:02 +00:00
//
2022-04-29 18:52:42 +00:00
// t5:
2022-02-14 05:30:00 +00:00
// Label for the location of the test that's about to take place
2022-01-30 23:08:02 +00:00
// ------------------------------------------------------------------------------------------------------------------------------------
2022-04-25 17:45:47 +00:00
. macro INIT_TEST_TABLE
2022-02-14 02:22:12 +00:00
2022-05-04 21:39:36 +00:00
run_test_loop :
2022-04-29 18:52:42 +00:00
la t0 , test_cases
2022-01-30 23:08:02 +00:00
test_loop :
2022-04-29 18:52:42 +00:00
ld t3 , 0 ( t0 ) // fetch test case address
ld t4 , 8 ( t0 ) // fetch test case value
ld t5 , 16 ( t0 ) // fetch test case flag
addi t0 , t0 , 24 // set t0 to next test case
2022-01-30 23:08:02 +00:00
2022-04-29 18:52:42 +00:00
// t0 has the symbol for a test's location in the assembly
li t2 , 0x1FFFFF
and t5 , t5 , t2 // This program is always on at least a megapage, so this masks out the megapage offset.
auipc t2 , 0x0
srli t2 , t2 , 21
slli t2 , t2 , 21 // zero out the bottom 21 bits so the megapage offset of the symbol can be placed there
or t5 , t2 , t5 // t5 = virtual address of the symbol for this type of test.
2022-01-30 23:08:02 +00:00
2022-04-29 18:52:42 +00:00
jr t5
2022-01-30 23:08:02 +00:00
// Test Name : Description : Fault output value : Normal output values
// ----------------------:-------------------------------------------:------------------------:------------------------------------------------------
// write64_test : Write 64 bits to address : 0xf : None
// write32_test : Write 32 bits to address : 0xf : None
// write16_test : Write 16 bits to address : 0xf : None
// write08_test : Write 8 bits to address : 0xf : None
// read64_test : Read 64 bits from address : 0xd, 0xbad : readvalue in hex
// read32_test : Read 32 bitsfrom address : 0xd, 0xbad : readvalue in hex
// read16_test : Read 16 bitsfrom address : 0xd, 0xbad : readvalue in hex
// read08_test : Read 8 bitsfrom address : 0xd, 0xbad : readvalue in hex
2022-04-29 18:52:42 +00:00
// executable_test : test executable on virtual page : 0xc, 0xbad : value of t2 modified by exectuion code (usually 0x111)
2022-01-30 23:08:02 +00:00
// terminate_test : terminate tests : mcause value for fault : from M 0xb, from S 0x9, from U 0x8
// goto_baremetal : satp.MODE = bare metal : None : None
// goto_sv39 : satp.MODE = sv39 : None : None
// goto_sv48 : satp.MODE = sv48 : None : None
// write_mxr_sum : write sstatus.[19:18] = MXR, SUM bits : None : None
// goto_m_mode : go to mahcine mode : mcause value for fault : from M 0xb, from S 0x9, from U 0x8
// goto_s_mode : go to supervisor mode : mcause value for fault : from M 0xb, from S 0x9, from U 0x8
// goto_u_mode : go to user mode : mcause value for fault : from M 0xb, from S 0x9, from U 0x8
// write_pmpcfg_x : Write one of the pmpcfg csr's : mstatuses?, 0xD : readback of pmpcfg value
// write_pmpaddr_x : Write one of the pmpaddr csr's : None : readback of pmpaddr value
write64_test :
2022-04-29 18:52:42 +00:00
// address to write in t3, double value in t4
sd t4 , 0 ( t3 )
2022-01-30 23:08:02 +00:00
j test_loop // go to next test case
write32_test :
2022-04-29 18:52:42 +00:00
// address to write in t3, word value in t4
sw t4 , 0 ( t3 )
2022-01-30 23:08:02 +00:00
j test_loop // go to next test case
write16_test :
2022-04-29 18:52:42 +00:00
// address to write in t3, halfword value in t4
sh t4 , 0 ( t3 )
2022-01-30 23:08:02 +00:00
j test_loop // go to next test case
write08_test :
2022-04-29 18:52:42 +00:00
// address to write in t3, value in t4
sb t4 , 0 ( t3 )
2022-01-30 23:08:02 +00:00
j test_loop // go to next test case
read64_test :
2022-04-29 18:52:42 +00:00
// address to read in t3, expected 64 bit value in t4 (unused, but there for your perusal).
li t2 , 0xBAD // bad value that will be overwritten on good reads.
ld t2 , 0 ( t3 )
sd t2 , 0 ( t1 )
addi t1 , t1 , 8
addi a6 , a6 , 8
2022-01-30 23:08:02 +00:00
j test_loop // go to next test case
read32_test :
2022-04-29 18:52:42 +00:00
// address to read in t3, expected 32 bit value in t4 (unused, but there for your perusal).
li t2 , 0xBAD // bad value that will be overwritten on good reads.
lw t2 , 0 ( t3 )
sd t2 , 0 ( t1 )
addi t1 , t1 , 8
addi a6 , a6 , 8
2022-01-30 23:08:02 +00:00
j test_loop // go to next test case
read16_test :
2022-04-29 18:52:42 +00:00
// address to read in t3, expected 16 bit value in t4 (unused, but there for your perusal).
li t2 , 0xBAD // bad value that will be overwritten on good reads.
lh t2 , 0 ( t3 )
sd t2 , 0 ( t1 )
addi t1 , t1 , 8
addi a6 , a6 , 8
2022-01-30 23:08:02 +00:00
j test_loop // go to next test case
read08_test :
2022-04-29 18:52:42 +00:00
// address to read in t3, expected 8 bit value in t4 (unused, but there for your perusal).
li t2 , 0xBAD // bad value that will be overwritten on good reads.
lb t2 , 0 ( t3 )
sd t2 , 0 ( t1 )
addi t1 , t1 , 8
addi a6 , a6 , 8
2022-01-30 23:08:02 +00:00
j test_loop // go to next test case
2022-06-28 01:59:44 +00:00
readmip_test : // read the MIP into the signature
csrr t2 , mip
sw t2 , 0 ( t1 )
addi t1 , t1 , 4
addi a6 , a6 , 4
j test_loop // go to next test case
readsip_test : // read the MIP into the signature
csrr t2 , sip
sw t2 , 0 ( t1 )
addi t1 , t1 , 4
addi a6 , a6 , 4
j test_loop // go to next test case
2022-01-30 23:08:02 +00:00
goto_s_mode :
2022-04-29 18:52:42 +00:00
// return to address in t3,
2022-01-30 23:08:02 +00:00
li a0 , 3 // Trap handler behavior (go to supervisor mode)
2022-04-29 18:52:42 +00:00
mv a1 , t3 // return VPN
mv a2 , t4 // return page types
2022-01-30 23:08:02 +00:00
ecall // writes mcause to the output.
// now in S mode
j test_loop
goto_m_mode :
li a0 , 2 // Trap handler behavior (go to machine mode)
2022-04-29 18:52:42 +00:00
mv a1 , t3 // return VPN
mv a2 , t4 // return page types
2022-01-30 23:08:02 +00:00
ecall // writes mcause to the output.
j test_loop
goto_u_mode :
li a0 , 4 // Trap handler behavior (go to user mode)
2022-04-29 18:52:42 +00:00
mv a1 , t3 // return VPN
mv a2 , t4 // return page types
2022-01-30 23:08:02 +00:00
ecall // writes mcause to the output.
j test_loop
goto_baremetal :
// Turn translation off
2022-02-14 05:30:00 +00:00
GOTO_BAREMETAL
2022-01-30 23:08:02 +00:00
j test_loop // go to next test case
goto_sv39 :
2022-02-27 23:28:25 +00:00
// Turn sv39 translation on
2022-04-29 18:52:42 +00:00
// Base PPN in t3, ASID in t4
li t2 , 8 // satp.MODE value for sv39 (8)
slli t2 , t2 , 60
slli t4 , t4 , 44
or t2 , t2 , t4 // put ASID into the correct field of SATP
or t2 , t2 , t3 // Base Pagetable physical page number, satp.PPN field.
csrw satp , t2
2022-01-30 23:08:02 +00:00
j test_loop // go to next test case
goto_sv48 :
2022-02-27 23:28:25 +00:00
// Turn sv48 translation on
2022-04-29 18:52:42 +00:00
// Base PPN in t3, ASID in t4
li t2 , 9 // satp.MODE value for sv48 (9)
slli t2 , t2 , 60
slli t4 , t4 , 44
or t2 , t2 , t4 // put ASID into the correct field of SATP
or t2 , t2 , t3 // Base Pagetable physical page number, satp.PPN field.
csrw satp , t2
2022-01-30 23:08:02 +00:00
j test_loop // go to next test case
write_mxr_sum :
2022-04-29 18:52:42 +00:00
// writes sstatus.[mxr, sum] with the (assumed to be) 2 bit value in t4. also assumes we're in S or M mode
li t5 , 0xC0000 // mask bits for MXR, SUM
not t2 , t4
slli t2 , t2 , 18
and t2 , t2 , t5
slli t4 , t4 , 18
csrc sstatus , t2
csrs sstatus , t4
2022-01-30 23:08:02 +00:00
j test_loop
2022-02-27 23:28:25 +00:00
read_write_mprv :
// reads old mstatus.mprv value to output, then
2022-04-29 18:52:42 +00:00
// Writes mstatus.mprv with the 1 bit value in t4. assumes we're in m mode
li t5 , 0x20000 // mask bits for mprv
csrr t2 , mstatus
and t2 , t2 , t5
srli t2 , t2 , 17
sd t2 , 0 ( t1 ) // store old mprv to output
addi t1 , t1 , 8
addi a6 , a6 , 8
not t2 , t4
slli t2 , t2 , 17
slli t4 , t4 , 17
csrc mstatus , t2
csrs mstatus , t4 // clear or set mprv bit
li t2 , 0x1800
csrc mstatus , t2
li t2 , 0x800
csrs mstatus , t2 // set mpp to supervisor mode to see if mprv=1 really executes in the mpp mode
2022-02-27 23:28:25 +00:00
j test_loop
2022-01-30 23:08:02 +00:00
write_pmpcfg_0 :
2022-04-29 18:52:42 +00:00
// writes the value in t4 to the pmpcfg register specified in t3.
2022-01-30 23:08:02 +00:00
// then writes the final value of pmpcfgX to the output.
2022-04-29 18:52:42 +00:00
csrw pmpcfg0 , t4
csrr t5 , pmpcfg0
2022-02-14 05:30:00 +00:00
j write_pmpcfg_end
2022-01-30 23:08:02 +00:00
write_pmpcfg_2 :
2022-04-29 18:52:42 +00:00
csrw pmpcfg2 , t4
csrr t5 , pmpcfg2 // I would use csrrw but we need the value AFTER the csr has been written
2022-02-14 05:30:00 +00:00
j write_pmpcfg_end
2022-01-30 23:08:02 +00:00
write_pmpcfg_end :
2022-04-29 18:52:42 +00:00
sd t5 , 0 ( t1 )
addi t1 , t1 , 8
addi a6 , a6 , 8
2022-01-30 23:08:02 +00:00
j test_loop
write_pmpaddr_0 :
2022-04-29 18:52:42 +00:00
// write_read_csr pmpaddr0, t4
// writes the value in t4 to the pmpaddr register specified in t3.
2022-01-30 23:08:02 +00:00
// then writes the final value of pmpaddrX to the output.
2022-04-29 18:52:42 +00:00
csrw pmpaddr0 , t4
csrr t5 , pmpaddr0
2022-01-30 23:08:02 +00:00
j write_pmpaddr_end
2022-02-14 05:30:00 +00:00
2022-01-30 23:08:02 +00:00
write_pmpaddr_1 :
2022-04-29 18:52:42 +00:00
csrw pmpaddr1 , t4
csrr t5 , pmpaddr1
2022-01-30 23:08:02 +00:00
j write_pmpaddr_end
2022-02-14 05:30:00 +00:00
2022-01-30 23:08:02 +00:00
write_pmpaddr_2 :
2022-04-29 18:52:42 +00:00
csrw pmpaddr2 , t4
csrr t5 , pmpaddr2
2022-01-30 23:08:02 +00:00
j write_pmpaddr_end
2022-02-14 05:30:00 +00:00
2022-01-30 23:08:02 +00:00
write_pmpaddr_3 :
2022-04-29 18:52:42 +00:00
csrw pmpaddr3 , t4
csrr t5 , pmpaddr3
2022-01-30 23:08:02 +00:00
j write_pmpaddr_end
2022-02-14 05:30:00 +00:00
2022-01-30 23:08:02 +00:00
write_pmpaddr_4 :
2022-04-29 18:52:42 +00:00
csrw pmpaddr4 , t4
csrr t5 , pmpaddr4
2022-01-30 23:08:02 +00:00
j write_pmpaddr_end
2022-02-14 05:30:00 +00:00
2022-01-30 23:08:02 +00:00
write_pmpaddr_5 :
2022-04-29 18:52:42 +00:00
csrw pmpaddr5 , t4
csrr t5 , pmpaddr5
2022-01-30 23:08:02 +00:00
j write_pmpaddr_end
2022-02-14 05:30:00 +00:00
2022-01-30 23:08:02 +00:00
write_pmpaddr_6 :
2022-04-29 18:52:42 +00:00
csrw pmpaddr6 , t4
csrr t5 , pmpaddr6
2022-01-30 23:08:02 +00:00
j write_pmpaddr_end
2022-02-14 05:30:00 +00:00
2022-01-30 23:08:02 +00:00
write_pmpaddr_7 :
2022-04-29 18:52:42 +00:00
csrw pmpaddr7 , t4
csrr t5 , pmpaddr7
2022-01-30 23:08:02 +00:00
j write_pmpaddr_end
2022-02-14 05:30:00 +00:00
2022-01-30 23:08:02 +00:00
write_pmpaddr_8 :
2022-04-29 18:52:42 +00:00
csrw pmpaddr8 , t4
csrr t5 , pmpaddr8
2022-01-30 23:08:02 +00:00
j write_pmpaddr_end
2022-02-14 05:30:00 +00:00
2022-01-30 23:08:02 +00:00
write_pmpaddr_9 :
2022-04-29 18:52:42 +00:00
csrw pmpaddr9 , t4
csrr t5 , pmpaddr9
2022-01-30 23:08:02 +00:00
j write_pmpaddr_end
2022-02-14 05:30:00 +00:00
2022-01-30 23:08:02 +00:00
write_pmpaddr_10 :
2022-04-29 18:52:42 +00:00
csrw pmpaddr10 , t4
csrr t5 , pmpaddr10
2022-01-30 23:08:02 +00:00
j write_pmpaddr_end
2022-02-14 05:30:00 +00:00
2022-01-30 23:08:02 +00:00
write_pmpaddr_11 :
2022-04-29 18:52:42 +00:00
csrw pmpaddr11 , t4
csrr t5 , pmpaddr11
2022-01-30 23:08:02 +00:00
j write_pmpaddr_end
2022-02-14 05:30:00 +00:00
2022-01-30 23:08:02 +00:00
write_pmpaddr_12 :
2022-04-29 18:52:42 +00:00
csrw pmpaddr12 , t4
csrr t5 , pmpaddr12
2022-01-30 23:08:02 +00:00
j write_pmpaddr_end
2022-02-14 05:30:00 +00:00
2022-01-30 23:08:02 +00:00
write_pmpaddr_13 :
2022-04-29 18:52:42 +00:00
csrw pmpaddr13 , t4
csrr t5 , pmpaddr13
2022-01-30 23:08:02 +00:00
j write_pmpaddr_end
2022-02-14 05:30:00 +00:00
2022-01-30 23:08:02 +00:00
write_pmpaddr_14 :
2022-04-29 18:52:42 +00:00
csrw pmpaddr14 , t4
csrr t5 , pmpaddr14
2022-01-30 23:08:02 +00:00
j write_pmpaddr_end
2022-02-14 05:30:00 +00:00
2022-01-30 23:08:02 +00:00
write_pmpaddr_15 :
2022-04-29 18:52:42 +00:00
csrw pmpaddr15 , t4
csrr t5 , pmpaddr15
2022-01-30 23:08:02 +00:00
j write_pmpaddr_end
2022-02-14 05:30:00 +00:00
2022-01-30 23:08:02 +00:00
write_pmpaddr_end :
2022-04-29 18:52:42 +00:00
sd t5 , 0 ( t1 )
addi t1 , t1 , 8
addi a6 , a6 , 8
2022-01-30 23:08:02 +00:00
j test_loop
executable_test :
2022-04-29 18:52:42 +00:00
// Execute the code at the address in t3, returning the value in t2.
// Assumes the code modifies t2, to become the value stored in t4 for this test.
2022-01-30 23:08:02 +00:00
fence . i // forces cache and main memory to sync so execution code written by the program can run.
2022-04-29 18:52:42 +00:00
li t2 , 0xBAD
jalr t3
sd t2 , 0 ( t1 )
addi t1 , t1 , 8
addi a6 , a6 , 8
2022-01-30 23:08:02 +00:00
j test_loop
2022-02-14 02:22:12 +00:00
. endm
// notably, terminate_test is not a part of the test table macro because it needs to be defined
// in any type of test, macro or test table, for the trap handler to work
2022-01-30 23:08:02 +00:00
terminate_test :
li a0 , 2 // Trap handler behavior (go to machine mode)
ecall // writes mcause to the output.
2022-04-29 18:52:42 +00:00
csrw mtvec , tp // restore original trap handler to halt program
2022-01-30 23:08:02 +00:00
RVTEST_CODE_END
RVMODEL_HALT
2022-02-14 02:22:12 +00:00
. macro TEST_STACK_AND_DATA
2022-01-30 23:08:02 +00:00
RVTEST_DATA_BEGIN
. align 4
rvtest_data :
. word 0xbabecafe
RVTEST_DATA_END
. align 3 // align stack to 8 byte boundary
2022-04-06 06:43:03 +00:00
stack_bottom :
2022-01-30 23:08:02 +00:00
. fill 1024 , 4 , 0xdeadbeef
2022-04-06 06:43:03 +00:00
stack_top :
. align 3
mscratch_bottom :
. fill 512 , 4 , 0xdeadbeef
mscratch_top :
. align 3
sscratch_bottom :
. fill 512 , 4 , 0xdeadbeef
sscratch_top :
2022-01-30 23:08:02 +00:00
RVMODEL_DATA_BEGIN
test_1_res :
. fill 1024 , 4 , 0xdeadbeef
RVMODEL_DATA_END
# ifdef rvtest_mtrap_routine
mtrap_sigptr :
. fill 64 * ( XLEN / 32 ) , 4 , 0xdeadbeef
# endif
# ifdef rvtest_gpr_save
gpr_save :
. fill 32 * ( XLEN / 32 ) , 4 , 0xdeadbeef
# endif
2022-02-14 02:22:12 +00:00
. endm