Skip to content

Commit

Permalink
Implement kernel mode. More tests for interrupts. Fixes Issue #18.
Browse files Browse the repository at this point in the history
  • Loading branch information
Sarah Mount committed Jul 2, 2016
1 parent 7cc2e5a commit 6f3173c
Show file tree
Hide file tree
Showing 17 changed files with 371 additions and 39 deletions.
4 changes: 4 additions & 0 deletions .coveragerc
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,10 @@ exclude_lines =
def init_state
def iread

# Don't complain about every single status bit.
self._get_nth_bit_of_register
self._set_nth_bit_of_register

# Don't complain about not generating debug output.
if self.debug.enabled('flags'):
if self.debug.enabled('rf'):
Expand Down
11 changes: 11 additions & 0 deletions revelation/execute_interrupt.py
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,11 @@ def execute_gie16(s, inst):
"""Enables all interrupts in ILAT register, dependent on the per bit
settings in the IMASK register.
STATUS[1]=0
Only available in Kernel mode.
"""
if s.ENABLE_USER_MODE and not s.KERNEL: # GIE illegal in user mode.
s.pc += 2
return
for index in range(10):
if not (s.rf[revelation.isa.reg_map['IMASK']] & (1 << index)):
s.rf[revelation.isa.reg_map['ILAT']] &= ~(1 << index)
Expand All @@ -63,6 +67,9 @@ def execute_gid16(s, inst):
"""Disable all interrupts.
STATUS[1]=1
"""
if s.ENABLE_USER_MODE and not s.KERNEL: # GID illegal in user mode.
s.pc += 2
return
s.GID = 1
s.pc += 2

Expand Down Expand Up @@ -90,6 +97,10 @@ def execute_rti16(s, inst):
proceeds as if there were an interrupt to service:
https://parallella.org/forums/viewtopic.php?f=23&t=818&hilit=interrupt#p5185
"""
if s.ENABLE_USER_MODE and not s.KERNEL: # If in user mode, RTI changes mode.
s.KERNEL = True
s.pc += 2
return
# Let N be the interrupt level.
interrupt_level = s.get_pending_interrupt()
# Bit N of IPEND is cleared.
Expand Down
173 changes: 168 additions & 5 deletions revelation/machine.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,27 @@ def __init__(self, memory, debug, reset_addr=RESET_ADDR):
'ILLEGAL ACCESS' : 0b0101,
'FPU EXCEPTION' : 0b0011,
}
# Valid settings for bits [7:4] and [11:8] of the CONFIG register.
self.timer_config = { 'OFF' : 0b0000,
'CLK' : 0b0001,
'IDLE CYCLES' : 0b0010,
'RESERVED 0' : 0b0011,
'IALU VALID' : 0b0100,
'FPU VALID' : 0b0101,
'DUAL ISSUE' : 0b0110,
'E1 STALLS' : 0b0111,
'RA STALLS' : 0b1000,
'RESERVED 1' : 0b1001,
'LOCAL FETCHSTALLS' : 0b1010,
'LOCAL LOAD STALLS' : 0b1011,
'EXTERNAL FETCH STALLS' : 0b1100,
'EXTERNAL LOAD STALLS' : 0b1101,
'MESH TRAFFIC 0' : 0b1110,
'MESH TRAFFIC 1' : 0b1111,
}
self.ACTIVE = True
# Kernel mode on by default.
self.KERNEL = True

def get_pending_interrupt(self):
ipend_highest_bit = -1
Expand All @@ -43,7 +64,7 @@ def get_pending_interrupt(self):
break
return ipend_highest_bit

def get_lateched_interrupt(self):
def get_latched_interrupt(self):
ilat_highest_bit= -1
for index in range(10):
if ((self.rf[reg_map['ILAT']] & (1 << index)) and
Expand All @@ -61,6 +82,8 @@ def _set_nth_bit_of_register(self, register, n, value):
else:
self.rf[reg_map[register]] &= ~(1 << n)

# STATUS bits.

@property
def ACTIVE(self):
return self._get_nth_bit_of_register('STATUS', 0)
Expand All @@ -78,11 +101,11 @@ def GID(self, value):
self._set_nth_bit_of_register('STATUS', 1, value)

@property
def SUPERUSER(self):
def KERNEL(self):
return self._get_nth_bit_of_register('STATUS', 2)

@SUPERUSER.setter
def SUPERUSER(self, value):
@KERNEL.setter
def KERNEL(self, value):
self._set_nth_bit_of_register('STATUS', 2, value)

@property
Expand Down Expand Up @@ -183,7 +206,6 @@ def BUS(self, value):

@property
def EXCAUSE(self):
print 'STATUS', bin(self.rf[reg_map['STATUS']])
return (self.rf[reg_map['STATUS']] >> 16) & 0xf

@EXCAUSE.setter
Expand All @@ -193,6 +215,147 @@ def EXCAUSE(self, value):
self._set_nth_bit_of_register('STATUS', 18, (value >> 2) & 0x1)
self._set_nth_bit_of_register('STATUS', 19, (value >> 3) & 0x1)

# CONFIG bits.

@property
def RMODE(self):
return self._get_nth_bit_of_register('CONFIG', 0)

@RMODE.setter
def RMODE(self, value):
self._set_nth_bit_of_register('CONFIG', 0, value)

@property
def IEN(self):
return self._get_nth_bit_of_register('CONFIG', 1)

@IEN.setter
def IEN(self, value):
self._set_nth_bit_of_register('CONFIG', 1, value)

@property
def OEN(self):
return self._get_nth_bit_of_register('CONFIG', 2)

@OEN.setter
def OEN(self, value):
self._set_nth_bit_of_register('CONFIG', 2, value)

@property
def UEN(self):
return self._get_nth_bit_of_register('CONFIG', 3)

@UEN.setter
def UEN(self, value):
self._set_nth_bit_of_register('CONFIG', 3, value)

@property
def CTIMER0CONFIG(self):
return (self.rf[reg_map['CONFIG']] >> 4) & 0xf

@CTIMER0CONFIG.setter
def CTIMER0CONFIG(self, value):
self._set_nth_bit_of_register('CONFIG', 4, value & 0x1)
self._set_nth_bit_of_register('CONFIG', 5, (value >> 1) & 0x1)
self._set_nth_bit_of_register('CONFIG', 6, (value >> 2) & 0x1)
self._set_nth_bit_of_register('CONFIG', 7, (value >> 3) & 0x1)

@property
def CTIMER1CONFIG(self):
return (self.rf[reg_map['CONFIG']] >> 8) & 0xf

@CTIMER1CONFIG.setter
def CTIMER1CONFIG(self, value):
self._set_nth_bit_of_register('CONFIG', 8, value & 0x1)
self._set_nth_bit_of_register('CONFIG', 9, (value >> 1) & 0x1)
self._set_nth_bit_of_register('CONFIG', 10, (value >> 2) & 0x1)
self._set_nth_bit_of_register('CONFIG', 11, (value >> 3) & 0x1)

@property
def CTRLMODE(self):
return (self.rf[reg_map['CONFIG']] >> 12) & 0xf

@CTRLMODE.setter
def CTRLMODE(self, value):
self._set_nth_bit_of_register('CONFIG', 12, value & 0x1)
self._set_nth_bit_of_register('CONFIG', 13, (value >> 1) & 0x1)
self._set_nth_bit_of_register('CONFIG', 14, (value >> 2) & 0x1)
self._set_nth_bit_of_register('CONFIG', 15, (value >> 3) & 0x1)

@property
def RESERVED0(self):
return self._get_nth_bit_of_register('CONFIG', 16)

@RESERVED0.setter
def RESERVED0(self, value):
self._set_nth_bit_of_register('CONFIG', 16, value)

@property
def ARITHMODE(self):
return (self.rf[reg_map['CONFIG']] >> 17) & 0x7

@ARITHMODE.setter
def ARITHMODE(self, value):
self._set_nth_bit_of_register('CONFIG', 17, value & 0x1)
self._set_nth_bit_of_register('CONFIG', 18, (value >> 1) & 0x1)
self._set_nth_bit_of_register('CONFIG', 19, (value >> 2) & 0x1)

@property
def RESERVED1(self):
return (self.rf[reg_map['CONFIG']] >> 20) & 0x3

@RESERVED1.setter
def RESERVED1(self, value):
self._set_nth_bit_of_register('CONFIG', 20, value & 0x1)
self._set_nth_bit_of_register('CONFIG', 21, (value >> 1) & 0x1)

@property
def LPMODE(self):
return self._get_nth_bit_of_register('CONFIG', 22)

@LPMODE.setter
def LPMODE(self, value):
self._set_nth_bit_of_register('CONFIG', 22, value)

@property
def RESERVED2(self):
return (self.rf[reg_map['CONFIG']] >> 23) & 0x3

@RESERVED2.setter
def RESERVED2(self, value):
self._set_nth_bit_of_register('CONFIG', 23, value & 0x1)
self._set_nth_bit_of_register('CONFIG', 24, (value >> 1) & 0x1)

@property
def ENABLE_USER_MODE(self):
return self._get_nth_bit_of_register('CONFIG', 25)

@ENABLE_USER_MODE.setter
def ENABLE_USER_MODE(self, value):
self._set_nth_bit_of_register('CONFIG', 25, value)

@property
def TIMEWRAP(self):
return self._get_nth_bit_of_register('CONFIG', 26)

@TIMEWRAP.setter
def TIMEWRAP(self, value):
self._set_nth_bit_of_register('CONFIG', 26, value)

@property
def RESERVED3(self):
return (self.rf[reg_map['CONFIG']] >> 27) & 0x1f

@RESERVED3.setter
def RESERVED3(self, value):
self._set_nth_bit_of_register('CONFIG', 27, value & 0x1)
self._set_nth_bit_of_register('CONFIG', 28, (value >> 1) & 0x1)
self._set_nth_bit_of_register('CONFIG', 29, (value >> 2) & 0x1)
self._set_nth_bit_of_register('CONFIG', 30, (value >> 3) & 0x1)
self._set_nth_bit_of_register('CONFIG', 31, (value >> 4) & 0x1)

# PC

@property
def pc(self):
return self.rf[reg_map['pc']]
Expand Down
4 changes: 1 addition & 3 deletions revelation/sim.py
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ def post_execute(self):

def _service_interrupts(self):
# Let N be the interrupt level:
latched_interrupt = self.state.get_lateched_interrupt()
latched_interrupt = self.state.get_latched_interrupt()
pending_interrupt = self.state.get_pending_interrupt()
# If there is no interrupt to process, return.
if latched_interrupt == pending_interrupt == -1:
Expand Down Expand Up @@ -93,7 +93,5 @@ def init_state(self, exe_file, filename, run_argv,
memory = new_memory()
_, _ = load_program(exe_file, memory)
self.state = State(memory, self.debug, reset_addr=RESET_ADDR)
self.state.ACTIVE = True
self.state.SUPERUSER = True

init_sim(Revelation())
56 changes: 56 additions & 0 deletions revelation/test/c/interrupt_fpu_exceptions_off.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
/* Based on code by Ola Jeppsson @olajep
* From: https://github.com/olajep/esim-test-bins
*/
#include <stdio.h>
#include <stdint.h>

void fpu_interrupt_handler() __attribute__ ((interrupt));
void fpu_interrupt_handler() {
printf("fpu_handler:\tyou should see this message only once.\n");
}

int main() {
register uint32_t r38 __asm__("r38"); /* tmp for enabling fp exceptions. */

float a = 1e38;
float b = 1e38;
float c;

uint32_t *ivt_usr, *ivt_exception; /* Interrupt vector pointers. */
uint32_t addr_usr, addr_exception; /* Relative branch address. */
uint32_t br32_usr, br32_exception; /* Relative address branch instruction. */

ivt_usr = (uint32_t *) 0x4;
addr_usr = (uint32_t) &fpu_interrupt_handler;
addr_usr -= (uint32_t) ivt_usr; /* Adjust for user interrupt branch address. */
addr_usr = (addr_usr >> 1); /* Lowest bit is skipped (alignment). */
br32_usr = 0xe8;
br32_usr |= ((addr_usr & (0x00ffffff))) << 8;
*ivt_usr = br32_usr;

/* Clear imask. */
__asm__("movt r40, 0");
__asm__("mov r40, 0");
__asm__("movts imask, r40");

/* Enable float exceptions. */
__asm__("movfs r38, config");
r38 |= 14;
__asm__("movts config, r38");

/* Trigger fpu interrupt. */
c = a * b;

/* Disable fpu exceptions. */
__asm__("movfs r38, config");
r38 = r38 & ~(1 << 1); /* Invalid floating-point exception. */
r38 = r38 & ~(1 << 2); /* Overflow floating-point exception. */
r38 = r38 & ~(1 << 3); /* Underflow floating-point exception. */
__asm__("movts config, r38");

/* Trigger fpu interrupt. */
c = a * b;

printf("Test complete.\n");
return 0;
}
Binary file not shown.
Loading

0 comments on commit 6f3173c

Please sign in to comment.