mirror of
				https://github.com/openhwgroup/cvw
				synced 2025-02-11 06:05:49 +00:00 
			
		
		
		
	
		
			
				
	
	
		
			153 lines
		
	
	
		
			5.3 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			153 lines
		
	
	
		
			5.3 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
///////////////////////////////////////////
 | 
						|
// WALLY-init-lib.h
 | 
						|
//
 | 
						|
// Written: David_Harris@hmc.edu 21 March 2023
 | 
						|
//
 | 
						|
// Purpose: Initialize stack, handle interrupts, terminate test case
 | 
						|
//
 | 
						|
// A component of the CORE-V-WALLY configurable RISC-V project.
 | 
						|
// https://github.com/openhwgroup/cvw
 | 
						|
// 
 | 
						|
// Copyright (C) 2021-23 Harvey Mudd College & Oklahoma State University
 | 
						|
//
 | 
						|
// SPDX-License-Identifier: Apache-2.0 WITH SHL-2.1
 | 
						|
//
 | 
						|
// Licensed under the Solderpad Hardware License v 2.1 (the “License”); you may not use this file 
 | 
						|
// except in compliance with the License, or, at your option, the Apache License version 2.0. You 
 | 
						|
// may obtain a copy of the License at
 | 
						|
//
 | 
						|
// https://solderpad.org/licenses/SHL-2.1/
 | 
						|
//
 | 
						|
// Unless required by applicable law or agreed to in writing, any work distributed under the 
 | 
						|
// License is distributed on an “AS IS” BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, 
 | 
						|
// either express or implied. See the License for the specific language governing permissions 
 | 
						|
// and limitations under the License.
 | 
						|
////////////////////////////////////////////////////////////////////////////////////////////////
 | 
						|
 | 
						|
// load code to initalize stack, handle interrupts, terminate
 | 
						|
// The PMP tests are sensitive to the exact addresses in this code, so unfortunately
 | 
						|
// modifying anything breaks those tests.
 | 
						|
 | 
						|
.section .text.init
 | 
						|
.global rvtest_entry_point
 | 
						|
 | 
						|
rvtest_entry_point:
 | 
						|
    la sp, topofstack       # Initialize stack pointer (not used)
 | 
						|
 | 
						|
    # Set up interrupts
 | 
						|
    la t0, trap_handler
 | 
						|
    csrw mtvec, t0      # Initialize MTVEC to trap_handler
 | 
						|
    csrw mideleg, zero  # Don't delegate interrupts
 | 
						|
    csrw medeleg, zero  # Don't delegate exceptions
 | 
						|
#    li t0, -1           # set mtimecmp to biggest number so it doesnt interrupt again
 | 
						|
#    li t1, 0x02004000   # MTIMECMP in CLINT
 | 
						|
#    sd t0, 0(t1)      
 | 
						|
    li t0, 0x80         
 | 
						|
#    li t0, 0x00         
 | 
						|
    csrw mie, t0        # Enable machine timer interrupt
 | 
						|
    la t0, topoftrapstack 
 | 
						|
    csrw mscratch, t0   # MSCRATCH holds trap stack pointer
 | 
						|
    csrsi mstatus, 0x8  # Turn on mstatus.MIE global interrupt enable
 | 
						|
    # set up PMP so user and supervisor mode can access full address space
 | 
						|
    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
 | 
						|
    j main              # Call main function in user test program
 | 
						|
 | 
						|
done:
 | 
						|
    li a0, 4            # argument to finish program    
 | 
						|
    ecall               # system call to finish program
 | 
						|
    j self_loop         # wait forever (not taken)
 | 
						|
 | 
						|
.align 4                # trap handlers must be aligned to multiple of 4
 | 
						|
trap_handler:
 | 
						|
    # Load trap handler stack pointer tp
 | 
						|
    csrrw tp, mscratch, tp  # swap MSCRATCH and tp
 | 
						|
    sd t0, 0(tp)        # Save t0 and t1 on the stack
 | 
						|
    sd t1, -8(tp)
 | 
						|
    csrr t0, mcause     # Check the cause
 | 
						|
    csrr t1, mtval      # And the trap value
 | 
						|
    bgez t0, exception  # if msb is clear, it is an exception
 | 
						|
 | 
						|
interrupt:              # must be a timer interrupt 
 | 
						|
    li t0, -1           # set mtimecmp to biggest number so it doesnt interrupt again
 | 
						|
    li t1, 0x02004000   # MTIMECMP in CLIN
 | 
						|
    sd t0, 0(t1)      
 | 
						|
    csrw stimecmp, t0   # sets stimecmp to big number so it doesnt interrupt 
 | 
						|
    li t0, 32
 | 
						|
    csrc sip, t0        # clears stimer interrupt
 | 
						|
    j trap_return       # clean up and return
 | 
						|
 | 
						|
exception:
 | 
						|
    csrr t0, mcause
 | 
						|
    li t1, 8            # is it an ecall trap?
 | 
						|
    andi t0, t0, 0xFC # if CAUSE = 8, 9, or 11
 | 
						|
    bne t0, t1, trap_return # ignore other exceptions
 | 
						|
 | 
						|
ecall:
 | 
						|
    li t0, 4
 | 
						|
    beq a0, t0, write_tohost    # call 4: terminate program
 | 
						|
    bltu a0, t0, changeprivilege    # calls 0-3: change privilege level
 | 
						|
    j trap_return       # ignore other ecalls
 | 
						|
 | 
						|
changeprivilege:
 | 
						|
    li t0, 0x00001800   # mask off mstatus.MPP in bits 11-12
 | 
						|
    csrc mstatus, t0
 | 
						|
    andi a0, a0, 0x003  # only keep bottom two bits of argument
 | 
						|
    slli a0, a0, 11     # move into mstatus.MPP position
 | 
						|
    csrs mstatus, a0    # set mstatus.MPP with desired privilege
 | 
						|
 | 
						|
trap_return:            # return from trap handler
 | 
						|
    csrr t0, mepc  # get address of instruction that caused exception
 | 
						|
    li t1, 0x20000  
 | 
						|
    csrs mstatus, t1    # set mprv bit to fetch instruction with permission of code that trapped
 | 
						|
    lh t0, 0(t0)   # get instruction that caused exception
 | 
						|
    csrc mstatus, t1    # clear mprv bit to restore normal operation
 | 
						|
    li t1, 3
 | 
						|
    and t0, t0, t1  # mask off upper bits
 | 
						|
    beq t0, t1, instr32  # if lower 2 bits are 11, instruction is uncompresssed
 | 
						|
    li t0, 2        # increment PC by 2 for compressed instruction
 | 
						|
    j updateepc
 | 
						|
instr32:
 | 
						|
    li t0, 4
 | 
						|
updateepc:
 | 
						|
    csrr t1, mepc   # add 2 or 4 (from t0) to MEPC to determine return Address
 | 
						|
    add t1, t1, t0
 | 
						|
    csrw mepc, t1
 | 
						|
 | 
						|
    ld t1, -8(tp)       # restore t1 and t0
 | 
						|
    ld t0, 0(tp)
 | 
						|
    csrrw tp, mscratch, tp  # restore tp
 | 
						|
    mret                # return from trap
 | 
						|
 | 
						|
write_tohost:
 | 
						|
    la t1, tohost
 | 
						|
    li t0, 1            # 1 for success, 3 for failure
 | 
						|
    sd t0, 0(t1)        # send success code
 | 
						|
 | 
						|
self_loop:
 | 
						|
    j self_loop         # wait
 | 
						|
    
 | 
						|
.section .tohost 
 | 
						|
tohost:                 # write to HTIF
 | 
						|
    .dword 0
 | 
						|
fromhost:
 | 
						|
    .dword 0
 | 
						|
 | 
						|
.EQU XLEN,64
 | 
						|
begin_signature:
 | 
						|
    .fill 6*(XLEN/32),4,0xdeadbeef    # 
 | 
						|
end_signature:
 | 
						|
 | 
						|
# Initialize stack with room for 512 bytes
 | 
						|
.bss
 | 
						|
    .space 512
 | 
						|
topofstack:
 | 
						|
# And another stack for the trap handler
 | 
						|
.bss   
 | 
						|
    .space 512
 | 
						|
topoftrapstack:
 | 
						|
 | 
						|
.align 4
 | 
						|
.section .text.main
 |