forked from Github_Repos/cvw
		
	
		
			
				
	
	
		
			132 lines
		
	
	
		
			3.9 KiB
		
	
	
	
		
			ArmAsm
		
	
	
	
	
	
			
		
		
	
	
			132 lines
		
	
	
		
			3.9 KiB
		
	
	
	
		
			ArmAsm
		
	
	
	
	
	
// trap.S
 | 
						|
// David_Harris@hmc.edu 11 May 2022
 | 
						|
//
 | 
						|
// Demonstrates setting up traps and invoking a trap handler.
 | 
						|
// The trap handler accepts timer interrupts and ecalls.
 | 
						|
// Saves cause and mtval into the signature
 | 
						|
// Ecall takes one argument in a0
 | 
						|
//   0: change privilege mode to user
 | 
						|
//   1: change privilege mode to supervisor
 | 
						|
//   3: change privilege mode to machine
 | 
						|
//   4: exit program with write tohost
 | 
						|
 | 
						|
.EQU MTIME,    0x200bff8
 | 
						|
.EQU MTIMECMP, 0x2004000
 | 
						|
 | 
						|
.global rvtest_entry_point
 | 
						|
 | 
						|
rvtest_entry_point:
 | 
						|
    la sp, topofstack   # Initialize stack pointer (not used)
 | 
						|
    la s6, begin_signature  # s6 points to signature
 | 
						|
 | 
						|
    # Set up timer
 | 
						|
    jal set_timecmp
 | 
						|
 | 
						|
    # 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, 0x080       
 | 
						|
    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
 | 
						|
 | 
						|
main:
 | 
						|
    # Change to user mode
 | 
						|
    li a0, 0            # a0 = 0: argument to enter user mode
 | 
						|
    ecall               # System call to enter user mode
 | 
						|
 | 
						|
    # Wait for timer interrupts
 | 
						|
    li t0, 0x1000       # loop counter start value
 | 
						|
loop: 
 | 
						|
    addi t0, t0, -1     # decrement counter
 | 
						|
    bne t0, zero, loop  # and repeat until zero
 | 
						|
 | 
						|
done:
 | 
						|
    li a0, 4            # argument to finish program    
 | 
						|
    ecall               # system call to finish program
 | 
						|
    j self_loop         # wait forever (not taken)
 | 
						|
 | 
						|
set_timecmp:            # Set timer compare to 800 ticks later
 | 
						|
    la t0, MTIME
 | 
						|
    la t1, MTIMECMP
 | 
						|
    ld t0, 0(t0)        # Read current timer
 | 
						|
    addi t0, t0, 0x60   # Increment timer
 | 
						|
    sd t0, 0(t1)        # Set MTIMECMP = MTIME + 0x800
 | 
						|
    ret
 | 
						|
 | 
						|
.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
 | 
						|
    sd t0, 0(s6)        # Save MCAUSE and MTVAL in the signature
 | 
						|
    sd t1, 8(s6)            
 | 
						|
    addi s6, s6, 16     
 | 
						|
    bgez t0, exception  # if msb is clear, it is an exception
 | 
						|
 | 
						|
interrupt:              # must be a timer interrupt 
 | 
						|
    jal set_timecmp     # Increment compare for next timer interrupt
 | 
						|
    j trap_return       # clean up and return
 | 
						|
 | 
						|
exception:
 | 
						|
    csrr t1, mepc   # add 4 to MEPC to determine return Address
 | 
						|
    addi t1, t1, 4
 | 
						|
    csrw mepc, t1
 | 
						|
    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
 | 
						|
    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:
 | 
						|
 |