diff --git a/.landscape.yml b/.landscape.yml index d03ad55..5883131 100644 --- a/.landscape.yml +++ b/.landscape.yml @@ -2,4 +2,5 @@ pylint: disable: - too-many-arguments - unused-argument - + - too-many-branches + - too-many-boolean-expressions diff --git a/revelation/execute_branch.py b/revelation/execute_branch.py index 07ed279..1a645cd 100644 --- a/revelation/execute_branch.py +++ b/revelation/execute_branch.py @@ -1,7 +1,7 @@ from revelation.condition_codes import condition_passed +from revelation.registers import reg_map from revelation.utils import signed, sext_8, sext_24, trim_32 -import revelation.isa def make_bcond_executor(is16bit): def execute_bcond(s, inst): @@ -18,7 +18,7 @@ def execute_bcond(s, inst): cond = inst.cond imm = inst.bcond_imm if cond == 0b1111: # Branch and link (BL). - s.rf[revelation.isa.reg_map['LR']] = s.pc + (2 if is16bit else 4) + s.rf[reg_map['LR']] = s.pc + (2 if is16bit else 4) if condition_passed(s, cond): offset = (signed(sext_8(imm)) << 1) if is16bit else (signed(sext_24(imm)) << 1) s.pc = trim_32(s.pc + offset) diff --git a/revelation/execute_farith.py b/revelation/execute_farith.py index 06f6e6b..8c7143c 100644 --- a/revelation/execute_farith.py +++ b/revelation/execute_farith.py @@ -1,8 +1,8 @@ -from revelation.utils import bits2float, float2bits, get_exponent_as_decimal, is_nan, trim_32 +from revelation.utils import (bits2float, float2bits, get_exponent_as_decimal, + is_nan, trim_32) +from revelation.registers import reg_map from pydgin.utils import signed -import revelation.isa - def make_float_executor(is16bit): def exec_float(s, inst): @@ -38,9 +38,9 @@ def exec_float(s, inst): s.BVS = s.BVS | s.BV # No exceptions for float instruction. if s.CTIMER0CONFIG == s.timer_config['FPU VALID'] and not s.BIS: - s.rf[revelation.isa.reg_map['CTIMER0']] -= 1 + s.rf[reg_map['CTIMER0']] -= 1 if s.CTIMER1CONFIG == s.timer_config['FPU VALID'] and not s.BIS: - s.rf[revelation.isa.reg_map['CTIMER1']] -= 1 + s.rf[reg_map['CTIMER1']] -= 1 s.debug_flags() s.pc += 2 if is16bit else 4 return exec_float @@ -88,9 +88,9 @@ def exec_fix(s, inst): s.BVS = s.BVS | s.BV # FIXME: Find out whether fix generates interrupts. if s.CTIMER0CONFIG == s.timer_config['FPU VALID'] and not s.BIS: - s.rf[revelation.isa.reg_map['CTIMER0']] -= 1 + s.rf[reg_map['CTIMER0']] -= 1 if s.CTIMER1CONFIG == s.timer_config['FPU VALID'] and not s.BIS: - s.rf[revelation.isa.reg_map['CTIMER1']] -= 1 + s.rf[reg_map['CTIMER1']] -= 1 s.debug_flags() s.pc += 2 if is16bit else 4 return exec_fix @@ -126,9 +126,9 @@ def exec_fabs(s, inst): s.BVS = s.BVS | s.BV # Deal with fpu interrupts. if s.CTIMER0CONFIG == s.timer_config['FPU VALID'] and not s.BIS: - s.rf[revelation.isa.reg_map['CTIMER0']] -= 1 # pragma: no cover + s.rf[reg_map['CTIMER0']] -= 1 # pragma: no cover if s.CTIMER1CONFIG == s.timer_config['FPU VALID'] and not s.BIS: - s.rf[revelation.isa.reg_map['CTIMER1']] -= 1 # pragma: no cover + s.rf[reg_map['CTIMER1']] -= 1 # pragma: no cover s.debug_flags() s.pc += 2 if is16bit else 4 return exec_fabs @@ -182,12 +182,12 @@ def farith(s, inst): s.BVS = s.BVS | s.BV # Deal with fpu interrupts. if (s.IEN and s.BIS) or (s.OEN and s.BV) or (s.UEN and s.BUS): - s.rf[revelation.isa.reg_map['ILAT']] |= (1 << 1) + s.rf[reg_map['ILAT']] |= (1 << 1) s.EXCAUSE = s.exceptions['FPU EXCEPTION'] if s.CTIMER0CONFIG == s.timer_config['FPU VALID'] and not s.BIS: - s.rf[revelation.isa.reg_map['CTIMER0']] -= 1 + s.rf[reg_map['CTIMER0']] -= 1 if s.CTIMER1CONFIG == s.timer_config['FPU VALID'] and not s.BIS: - s.rf[revelation.isa.reg_map['CTIMER1']] -= 1 + s.rf[reg_map['CTIMER1']] -= 1 elif s.ARITHMODE == s.FPU_MODES['SIGNED INTEGER']: rd = signed(s.rf[inst.rd]) rn = signed(s.rf[inst.rn]) @@ -210,9 +210,9 @@ def farith(s, inst): # if (RD[30:0] == 0) { BZ=1 } else { BZ=0 } s.BZ = True if result == 0 else False if s.CTIMER0CONFIG == s.timer_config['IALU VALID']: - s.rf[revelation.isa.reg_map['CTIMER0']] -= 1 + s.rf[reg_map['CTIMER0']] -= 1 if s.CTIMER1CONFIG == s.timer_config['IALU VALID']: - s.rf[revelation.isa.reg_map['CTIMER1']] -= 1 + s.rf[reg_map['CTIMER1']] -= 1 s.debug_flags() s.pc += 2 if is16bit else 4 return farith diff --git a/revelation/execute_interrupt.py b/revelation/execute_interrupt.py index 9fb68dc..344ef82 100644 --- a/revelation/execute_interrupt.py +++ b/revelation/execute_interrupt.py @@ -1,7 +1,7 @@ -from pydgin.misc import FatalError - +from revelation.registers import reg_map from revelation.utils import trim_32 -import revelation.isa + +from pydgin.misc import FatalError, NotImplementedInstError def execute_nop16(s, inst): @@ -26,15 +26,13 @@ def execute_bkpt16(s, inst): GDB and should not be user software. The instruction is included here only for the purpose of reference. """ - s.rf[revelation.isa.reg_map['DEBUGSTATUS']] |= 1 - s.pc += 2 - s.running = False + raise NotImplementedInstError('bkpt instruction not implemented.') def execute_mbkpt16(s, inst): """Halts all cores within the group (sets DEBUGSTATUS[0] to 1). """ - raise NotImplementedError('Multicore not implemented.') + raise NotImplementedInstError('mbkpt instruction not implemented.') def execute_gie16(s, inst): @@ -47,8 +45,8 @@ def execute_gie16(s, inst): 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) + if not (s.rf[reg_map['IMASK']] & (1 << index)): + s.rf[reg_map['ILAT']] &= ~(1 << index) s.GID = 0 s.pc += 2 @@ -67,7 +65,7 @@ def execute_gid16(s, inst): def execute_sync16(s, inst): """Sets the ILAT[0] of all cores within a work group to 1. """ - raise NotImplementedError('Interrupts not implemented.') + raise NotImplementedInstError('sync instruction not implemented.') def execute_rti16(s, inst): @@ -89,11 +87,11 @@ def execute_rti16(s, inst): interrupt_level = s.get_pending_interrupt() # Bit N of IPEND is cleared. if interrupt_level >= 0: - s.rf[revelation.isa.reg_map['IPEND']] &= ~(1 << interrupt_level) + s.rf[reg_map['IPEND']] &= ~(1 << interrupt_level) # The GID bit in STATUS is cleared. s.GID = 0 # PC is set to IRET. - s.pc = s.rf[revelation.isa.reg_map['IRET']] + s.pc = s.rf[reg_map['IRET']] def execute_swi16(s, inst): @@ -101,7 +99,7 @@ def execute_swi16(s, inst): # The architecture has an undocumented SWI instruction which raises a software # exception. It sets bit 1 of ILAT and sets the EXCAUSE bits in STATUS to # 0b0001 (for Epiphany III) or 0b1110 (for Epiphany IV). - s.rf[revelation.isa.reg_map['ILAT']] |= (1 << 1) + s.rf[reg_map['ILAT']] |= (1 << 1) s.EXCAUSE = s.exceptions['SWI'] s.pc += 2 @@ -200,7 +198,7 @@ def execute_wand16(s, inst): """ STATUS[3] = 1 """ - raise NotImplementedError('Multicore not implemented.') + raise NotImplementedInstError('wand instruction not implemented.') def execute_unimpl(s, inst): diff --git a/revelation/execute_jump.py b/revelation/execute_jump.py index 18c3ec5..7491308 100644 --- a/revelation/execute_jump.py +++ b/revelation/execute_jump.py @@ -1,4 +1,4 @@ -import revelation.isa +from revelation.registers import reg_map from revelation.utils import trim_32 def make_jr_executor(is16bit, save_lr): @@ -10,6 +10,6 @@ def execute_jr(s, inst): if is16bit: inst.bits &= 0xffff if save_lr: - s.rf[revelation.isa.reg_map['LR']] = trim_32(s.pc + (2 if is16bit else 4)) + s.rf[reg_map['LR']] = trim_32(s.pc + (2 if is16bit else 4)) s.pc = s.rf[inst.rn] return execute_jr diff --git a/revelation/execute_load_store.py b/revelation/execute_load_store.py index aadfe9b..123f134 100644 --- a/revelation/execute_load_store.py +++ b/revelation/execute_load_store.py @@ -1,7 +1,7 @@ -from pydgin.misc import FatalError - from revelation.utils import trim_32 +from pydgin.misc import FatalError + def execute_ldstrpmd32(s, inst): """ diff --git a/revelation/isa.py b/revelation/isa.py index 03130ec..f2687ec 100644 --- a/revelation/isa.py +++ b/revelation/isa.py @@ -9,79 +9,6 @@ from pydgin.misc import create_risc_decoder -reg_map = { - 'r0' : 0, 'r1' : 1, 'r2' : 2, 'r3' : 3, - 'r4' : 4, 'r5' : 5, 'r6' : 6, 'r7' : 7, - 'r8' : 8, 'r9' : 9, 'r10' : 10, 'r11' : 11, - 'r12' : 12, 'r13' : 13, 'r14' : 14, 'r15' : 15, - 'r16' : 16, 'r17' : 17, 'r18' : 18, 'r19' : 19, - 'r20' : 20, 'r21' : 21, 'r22' : 22, 'r23' : 23, - 'r24' : 24, 'r25' : 25, 'r26' : 26, 'r27' : 27, - 'r28' : 28, 'r29' : 29, 'r30' : 30, 'r31' : 31, - 'r32' : 32, 'r33' : 33, 'r34' : 34, 'r35' : 35, - 'r36' : 36, 'r37' : 37, 'r38' : 38, 'r39' : 39, - 'r40' : 40, 'r41' : 41, 'r42' : 42, 'r43' : 43, - 'r44' : 44, 'r45' : 45, 'r46' : 46, 'r47' : 47, - 'r48' : 48, 'r49' : 49, 'r50' : 50, 'r51' : 51, - 'r52' : 52, 'r53' : 53, 'r54' : 54, 'r55' : 55, - 'r56' : 56, 'r57' : 57, 'r58' : 58, 'r59' : 59, - 'r60' : 40, 'r61' : 61, 'r62' : 62, 'r63' : 63, - # Synonyms. - 'SB' : 9, # Static base - 'SL' : 10, # Stack limit - 'FP' : 11, # Frame pointer - 'SP' : 13, # Stack pointer - 'LR' : 14, # Link register - # Special registers. - 'CONFIG' : 64, # Core configuration - 'STATUS' : 65, # Core status - 'pc' : 66, # Program counter - 'DEBUGSTATUS' : 67, # Debug status - 'LC' : 68, # Hardware counter loop - 'LS' : 69, # Hardware counter start address - 'LE' : 70, # Hardware counter end address - 'IRET' : 71, # Interrupt PC return address - 'IMASK' : 72, # Interrupt mask - 'ILAT' : 73, # Interrupt latch - 'ILATST' : 74, # Alias for setting interrupts - 'ILATCL' : 75, # Alias for clearing interrupts - 'IPEND' : 76, # Interrupt currently in progress - 'FSTATUS' : 77, # Alias for writing to all STATUS bits - 'DEBUGCMD' : 78, # Debug command register - 'RESETCORE' : 79, # Per core software reset - # Event timer registers - 'CTIMER0' : 80, # Core timer 0 - 'CTIMER1' : 81, # Core timer 1 - # Process control registers - 'MEMSTATUS' : 82, # Memory protection status - 'MEMPROTECT' : 83, # Memory protection registration - # DMA registers - 'DMA0CONFIG' : 84, # DMA channel 0 configuration - 'DMA0STRIDE' : 85, # DMA channel 0 stride - 'DMA0COUNT' : 86, # DMA channel 0 count - 'DMA0SRCADDR' : 87, # DMA channel 0 source address - 'DMA0DSTADDR' : 88, # DMA channel 0 destination address - 'DMA0AUTO0' : 89, # DMA channel 0 slave lower data - 'DMA0AUTO1' : 90, # DMA channel 0 slave upper data - 'DMA0STATUS' : 91, # DMA channel 0 status - 'DMA1CONFIG' : 92, # DMA channel 1 configuration - 'DMA1STRIDE' : 93, # DMA channel 1 stride - 'DMA1COUNT' : 94, # DMA channel 1 count - 'DMA1SRCADDR' : 95, # DMA channel 1 source address - 'DMA1DSTADDR' : 96, # DMA channel 1 destination address - 'DMA1AUTO0' : 97, # DMA channel 1 slave lower data - 'DMA1AUTO1' : 98, # DMA channel 1 slave upper data - 'DMA1STATUS' : 99, # DMA channel 1 status - # Mesh node control registers - 'MESHCONFIG' : 100, # Mesh node configuration - 'COREID' : 101, # Processor core ID - 'MULTICAST' : 102, # Multicast configuration - 'CMESHROUTE' : 103, # cMesh routing configuration, 12 bits - 'XMESHROUTE' : 104, # xMesh routing configuration, 12 bits - 'RMESHROUTE' : 105, # rMesh routing configuration, 12 bits -} - - encodings = [ # Branch on condition ['bcond32', 'xxxxxxxx_xxxxxxxx_xxxxxxxx_xxxx1000'], diff --git a/revelation/machine.py b/revelation/machine.py index f797319..16010ed 100644 --- a/revelation/machine.py +++ b/revelation/machine.py @@ -1,9 +1,8 @@ -from revelation.isa import reg_map +from revelation.registers import LOCAL_PC_ADDRESS, reg_map from revelation.storage import MemoryMappedRegisterFile RESET_ADDR = 0 -PC_ADDRESS = 0xf0408 class State(object): @@ -62,15 +61,15 @@ def set_first_core(self, value): @property def pc(self): - return self.mem.iread(PC_ADDRESS, 4, from_core=self.coreid) + return self.mem.iread(LOCAL_PC_ADDRESS, 4, from_core=self.coreid) @pc.setter def pc(self, value): - return self.mem.write(PC_ADDRESS, 4, value, from_core=self.coreid) + return self.mem.write(LOCAL_PC_ADDRESS, 4, value, from_core=self.coreid) def fetch_pc(self): # Override method from base class. Needed by Pydgin. - return self.mem.iread(PC_ADDRESS, 4, from_core=self.coreid) + return self.mem.iread(LOCAL_PC_ADDRESS, 4, from_core=self.coreid) def get_pending_interrupt(self): ipend_highest_bit = -1 diff --git a/revelation/registers.py b/revelation/registers.py new file mode 100644 index 0000000..38ace82 --- /dev/null +++ b/revelation/registers.py @@ -0,0 +1,154 @@ +from collections import OrderedDict + +LOCAL_PC_ADDRESS = 0xf0408 + + +def get_address_of_register_by_name(register_name): + for reg_index in reg_memory_map: # reg_memory_map at end of file. + if reg_memory_map[reg_index][2] == register_name: + return reg_memory_map[reg_index][0] + + +def get_register_size_by_address(register_address): + """Returns size of register in bits. + """ + size = 32 # __special_purpose_registers at end of file. + for address, size, _ in _special_purpose_registers: + if address == register_address: + break + return size + + +reg_map = { + 'r0' : 0, 'r1' : 1, 'r2' : 2, 'r3' : 3, + 'r4' : 4, 'r5' : 5, 'r6' : 6, 'r7' : 7, + 'r8' : 8, 'r9' : 9, 'r10' : 10, 'r11' : 11, + 'r12' : 12, 'r13' : 13, 'r14' : 14, 'r15' : 15, + 'r16' : 16, 'r17' : 17, 'r18' : 18, 'r19' : 19, + 'r20' : 20, 'r21' : 21, 'r22' : 22, 'r23' : 23, + 'r24' : 24, 'r25' : 25, 'r26' : 26, 'r27' : 27, + 'r28' : 28, 'r29' : 29, 'r30' : 30, 'r31' : 31, + 'r32' : 32, 'r33' : 33, 'r34' : 34, 'r35' : 35, + 'r36' : 36, 'r37' : 37, 'r38' : 38, 'r39' : 39, + 'r40' : 40, 'r41' : 41, 'r42' : 42, 'r43' : 43, + 'r44' : 44, 'r45' : 45, 'r46' : 46, 'r47' : 47, + 'r48' : 48, 'r49' : 49, 'r50' : 50, 'r51' : 51, + 'r52' : 52, 'r53' : 53, 'r54' : 54, 'r55' : 55, + 'r56' : 56, 'r57' : 57, 'r58' : 58, 'r59' : 59, + 'r60' : 40, 'r61' : 61, 'r62' : 62, 'r63' : 63, + # Synonyms. + 'SB' : 9, # Static base + 'SL' : 10, # Stack limit + 'FP' : 11, # Frame pointer + 'SP' : 13, # Stack pointer + 'LR' : 14, # Link register + # Special registers. + 'CONFIG' : 64, # Core configuration + 'STATUS' : 65, # Core status + 'pc' : 66, # Program counter + 'DEBUGSTATUS' : 67, # Debug status + 'LC' : 68, # Hardware counter loop + 'LS' : 69, # Hardware counter start address + 'LE' : 70, # Hardware counter end address + 'IRET' : 71, # Interrupt PC return address + 'IMASK' : 72, # Interrupt mask + 'ILAT' : 73, # Interrupt latch + 'ILATST' : 74, # Alias for setting interrupts + 'ILATCL' : 75, # Alias for clearing interrupts + 'IPEND' : 76, # Interrupt currently in progress + 'FSTATUS' : 77, # Alias for writing to all STATUS bits + 'DEBUGCMD' : 78, # Debug command register + 'RESETCORE' : 79, # Per core software reset + # Event timer registers + 'CTIMER0' : 80, # Core timer 0 + 'CTIMER1' : 81, # Core timer 1 + # Process control registers + 'MEMSTATUS' : 82, # Memory protection status + 'MEMPROTECT' : 83, # Memory protection registration + # DMA registers + 'DMA0CONFIG' : 84, # DMA channel 0 configuration + 'DMA0STRIDE' : 85, # DMA channel 0 stride + 'DMA0COUNT' : 86, # DMA channel 0 count + 'DMA0SRCADDR' : 87, # DMA channel 0 source address + 'DMA0DSTADDR' : 88, # DMA channel 0 destination address + 'DMA0AUTO0' : 89, # DMA channel 0 slave lower data + 'DMA0AUTO1' : 90, # DMA channel 0 slave upper data + 'DMA0STATUS' : 91, # DMA channel 0 status + 'DMA1CONFIG' : 92, # DMA channel 1 configuration + 'DMA1STRIDE' : 93, # DMA channel 1 stride + 'DMA1COUNT' : 94, # DMA channel 1 count + 'DMA1SRCADDR' : 95, # DMA channel 1 source address + 'DMA1DSTADDR' : 96, # DMA channel 1 destination address + 'DMA1AUTO0' : 97, # DMA channel 1 slave lower data + 'DMA1AUTO1' : 98, # DMA channel 1 slave upper data + 'DMA1STATUS' : 99, # DMA channel 1 status + # Mesh node control registers + 'MESHCONFIG' : 100, # Mesh node configuration + 'COREID' : 101, # Processor core ID + 'MULTICAST' : 102, # Multicast configuration + 'CMESHROUTE' : 103, # cMesh routing configuration, 12 bits + 'XMESHROUTE' : 104, # xMesh routing configuration, 12 bits + 'RMESHROUTE' : 105, # rMesh routing configuration, 12 bits +} + + +_special_purpose_registers = [ + (0xf0400, 32, 'CONFIG'), # Core configuration + (0xf0404, 32, 'STATUS'), # Core status + (0xf0408, 32, 'pc'), # Program counter + (0xf040c, 32, 'DEBUGSTATUS'), # Debug status + (0xf0414, 32, 'LC'), # Hardware counter loop + (0xf0418, 32, 'LS'), # Hardware counter start address + (0xf041c, 32, 'LE'), # Hardware counter end address + (0xf0420, 32, 'IRET'), # Interrupt PC return address + (0xf0424, 10, 'IMASK'), # Interrupt mask + (0xf0428, 10, 'ILAT'), # Interrupt latch + (0xf042c, 10, 'ILATST'), # Alias for setting interrupts + (0xf0430, 10, 'ILATCL'), # Alias for clearing interrupts + (0xf0434, 10, 'IPEND'), # Interrupt currently in progress + (0xf0440, 32, 'FSTATUS'), # Alias for writing to all STATUS bits + (0xf0448, 2, 'DEBUGCMD'), # Debug command register (2 bits) + (0xf070c, 1, 'RESETCORE'), # Per core software reset (1 bit) + # Event timer registers + (0xf0438, 32, 'CTIMER0'), # Core timer 0 + (0xf043c, 32, 'CTIMER1'), # Core timer 1 + # Process control registers + (0xf0604, 3, 'MEMSTATUS'), # Memory protection status + # Epiphany IV: 14 bits, III: 1 bit ([2]) + (0xf0608, 8, 'MEMPROTECT'), # Memory protection registration + # Epiphany IV: 16 bits, III: 8 bits. + # DMA registers + (0xf0500, 32, 'DMA0CONFIG'), # DMA channel 0 configuration + (0xf0504, 32, 'DMA0STRIDE'), # DMA channel 0 stride + (0xf0508, 32, 'DMA0COUNT'), # DMA channel 0 count + (0xf050c, 32, 'DMA0SRCADDR'), # DMA channel 0 source address + (0xf0510, 32, 'DMA0DSTADDR'), # DMA channel 0 destination address + (0xf0514, 32, 'DMA0AUTO0'), # DMA channel 0 slave lower data + (0xf0518, 32, 'DMA0AUTO1'), # DMA channel 0 slave upper data + (0xf051c, 32, 'DMA0STATUS'), # DMA channel 0 status + (0xf0520, 32, 'DMA1CONFIG'), # DMA channel 1 configuration + (0xf0524, 32, 'DMA1STRIDE'), # DMA channel 1 stride + (0xf0528, 32, 'DMA1COUNT'), # DMA channel 1 count + (0xf052c, 32, 'DMA1SRCADDR'), # DMA channel 1 source address + (0xf0530, 32, 'DMA1DSTADDR'), # DMA channel 1 destination address + (0xf0534, 32, 'DMA1AUTO0'), # DMA channel 1 slave lower data + (0xf0538, 32, 'DMA1AUTO1'), # DMA channel 1 slave upper data + (0xf053c, 32, 'DMA1STATUS'), # DMA channel 1 status + # Mesh node control registers + (0xf0700, 16, 'MESHCONFIG'), # Mesh node configuration + (0xf0704, 12, 'COREID'), # Processor core ID (12 bits) + (0xf0708, 12, 'MULTICAST'), # Multicast configuration + (0xf0710, 12, 'CMESHROUTE'), # cMesh routing configuration (12 bits) + (0xf0714, 12, 'XMESHROUTE'), # xMesh routing configuration (12 bits) + (0xf0718, 12, 'RMESHROUTE'), # rMesh routing configuration (12 bits) +] + + +# Register number -> (memory address, num bytes, name) +reg_memory_map = OrderedDict() +# Add general purpose registers to register_map. +for index, address in enumerate(xrange(0xf0000, 0xf0100, 0x4)): + reg_memory_map[index] = (address, 32, 'r%d' % ((address - 0xf0000) / 0x4)) +# Add special purpose registers to _register_map. +for index in xrange(len(_special_purpose_registers)): + reg_memory_map[index + 64] = _special_purpose_registers[index] diff --git a/revelation/sim.py b/revelation/sim.py index d03a3c7..43d7e04 100644 --- a/revelation/sim.py +++ b/revelation/sim.py @@ -1,17 +1,20 @@ from pydgin.debug import Debug, pad, pad_hex from pydgin.elf import elf_reader from pydgin.jit import elidable, hint, JitDriver, set_param, set_user_param -from pydgin.misc import FatalError from pydgin.sim import Sim, init_sim from revelation.argument_parser import cli_parser, DoNotInterpretError from revelation.elf_loader import load_program from revelation.instruction import Instruction -from revelation.isa import decode, reg_map +from revelation.isa import decode from revelation.logger import Logger from revelation.machine import State +from revelation.registers import reg_map from revelation.storage import Memory -from revelation.utils import get_coords_from_coreid, get_coreid_from_coords, zfill +from revelation.utils import (get_coords_from_coreid, get_coreid_from_coords, + zfill) + +from pydgin.misc import FatalError, NotImplementedInstError import time @@ -45,8 +48,8 @@ def __init__(self): if self.jit_enabled: self.jitdriver = JitDriver( greens = ['pc', 'core', 'coreid', 'opcode'], - reds = ['tick_counter', 'halted_cores', 'idle_cores', - 'old_pcs', 'memory', 'sim', 'state', 'start_time'], + reds = ['tick_counter', 'old_pc', 'halted_cores', 'idle_cores', + 'memory', 'sim', 'state', 'start_time'], virtualizables = ['state'], get_printable_location=get_printable_location) self.default_trace_limit = 400000 @@ -196,7 +199,7 @@ def run(self): opcode = 0 # a more meaningful trace in the JIT log. tick_counter = 0 # Number of instructions executed by all cores. halted_cores, idle_cores = [], [] - old_pcs = [0] * len(self.states) + old_pc = 0 start_time, end_time = time.time(), .0 while True: @@ -205,9 +208,9 @@ def run(self): coreid=coreid, opcode=opcode, tick_counter=tick_counter, + old_pc=old_pc, halted_cores=halted_cores, idle_cores=idle_cores, - old_pcs=old_pcs, memory=memory, sim=self, state=self.states[self.core], @@ -215,15 +218,17 @@ def run(self): # Fetch PC, decode instruction and execute. pc = hint(self.states[self.core].fetch_pc(), promote=True) coreid = hint(self.states[self.core].coreid, promote=True) - old_pcs[self.core] = pc + old_pc = pc opcode = memory.iread(pc, 4, from_core=self.states[self.core].coreid) try: instruction, exec_fun = self.decode(opcode) self.pre_execute() exec_fun(self.states[self.core], instruction) self.post_execute() - except FatalError as error: - print 'Exception in execution (pc: 0x%s), aborting!' % pad_hex(pc) + except (FatalError, NotImplementedInstError) as error: + mnemonic, _ = decode(opcode) + print ('Exception in execution of %s (pc: 0x%s), aborting!' % + (mnemonic, pad_hex(pc))) print 'Exception message: %s' % error.msg # Ensure that entry_point() returns correct exit code. return EXIT_GENERAL_ERROR # pragma: no cover @@ -251,15 +256,15 @@ def run(self): elif (self.core in idle_cores and self.fetch_latch() > 0): idle_cores.remove(self.core) self._service_interrupts() - if self.states[self.core].fetch_pc() < old_pcs[self.core]: + if self.states[self.core].fetch_pc() < old_pc: self.jitdriver.can_enter_jit(pc=self.states[self.core].fetch_pc(), core=self.core, coreid=coreid, opcode=opcode, tick_counter=tick_counter, + old_pc=old_pc, halted_cores=halted_cores, idle_cores=idle_cores, - old_pcs=old_pcs, memory=memory, sim=self, state=self.states[self.core], diff --git a/revelation/storage.py b/revelation/storage.py index 33b2e29..265758b 100644 --- a/revelation/storage.py +++ b/revelation/storage.py @@ -1,9 +1,9 @@ -from collections import OrderedDict - from pydgin.debug import Debug, pad, pad_hex from pydgin.jit import elidable, unroll_safe, hint from pydgin.utils import specialize +from revelation.registers import reg_memory_map + def is_local_address(address): return (address >> 20) == 0x0 @@ -13,22 +13,6 @@ def is_register_address(address): return address >= 0xf0000 and address <= 0xf0718 -def get_address_of_register_by_name(register_name): - for reg_index in _register_map: # _register_map at end of file. - if _register_map[reg_index][2] == register_name: - return _register_map[reg_index][0] - - -def get_register_size_by_address(register_address): - """Returns size of register in bits. - """ - size = 32 # _special_purpose_registers at end of file. - for address, size, _ in _special_purpose_registers: - if address == register_address: - break - return size - - class _BlockMemory(object): """32MB block of memory, initialised to zero. """ @@ -191,11 +175,11 @@ def __init__(self, memory, coreid, logger): self.coreid = coreid self.is_first_core = False self.memory.write(0xf0704, 4, coreid & 0xfff, from_core=coreid) - self.num_regs = len(_register_map) + self.num_regs = len(reg_memory_map) self.debug_nchars = 8 def __getitem__(self, index): - address, bitsize, _ = _register_map[index] + address, bitsize, _ = reg_memory_map[index] mask = (1 << bitsize) - 1 value = self.memory.iread(address, 4, from_core=self.coreid) & mask if (self.debug.enabled('rf') and self.logger and index < 64 and @@ -208,7 +192,7 @@ def __getitem__(self, index): def __setitem__(self, index, value): if index == 0x65: # COREID register. Read only. Other Read/Write only return # registers need to be accessed by instructions. - address, bitsize, _ = _register_map[index] # Lower 20 bits of address. + address, bitsize, _ = reg_memory_map[index] # Lower 20 bits of address. mask = (1 << bitsize) - 1 self.memory.write(address, 4, value & mask, from_core=self.coreid, quiet=True) @@ -216,65 +200,3 @@ def __setitem__(self, index, value): self.is_first_core): self.logger.log(' :: WR.RF[%s] = %s' % ((pad('%d' % index, 2), pad_hex(value, len=self.debug_nchars)))) - - -_special_purpose_registers = [ - (0xf0400, 32, 'CONFIG'), # Core configuration - (0xf0404, 32, 'STATUS'), # Core status - (0xf0408, 32, 'pc'), # Program counter - (0xf040c, 32, 'DEBUGSTATUS'), # Debug status - (0xf0414, 32, 'LC'), # Hardware counter loop - (0xf0418, 32, 'LS'), # Hardware counter start address - (0xf041c, 32, 'LE'), # Hardware counter end address - (0xf0420, 32, 'IRET'), # Interrupt PC return address - (0xf0424, 10, 'IMASK'), # Interrupt mask - (0xf0428, 10, 'ILAT'), # Interrupt latch - (0xf042c, 10, 'ILATST'), # Alias for setting interrupts - (0xf0430, 10, 'ILATCL'), # Alias for clearing interrupts - (0xf0434, 10, 'IPEND'), # Interrupt currently in progress - (0xf0440, 32, 'FSTATUS'), # Alias for writing to all STATUS bits - (0xf0448, 2, 'DEBUGCMD'), # Debug command register (2 bits) - (0xf070c, 1, 'RESETCORE'), # Per core software reset (1 bit) - # Event timer registers - (0xf0438, 32, 'CTIMER0'), # Core timer 0 - (0xf043c, 32, 'CTIMER1'), # Core timer 1 - # Process control registers - (0xf0604, 3, 'MEMSTATUS'), # Memory protection status - # Epiphany IV: 14 bits, III: 1 bit ([2]) - (0xf0608, 8, 'MEMPROTECT'), # Memory protection registration - # Epiphany IV: 16 bits, III: 8 bits. - # DMA registers - (0xf0500, 32, 'DMA0CONFIG'), # DMA channel 0 configuration - (0xf0504, 32, 'DMA0STRIDE'), # DMA channel 0 stride - (0xf0508, 32, 'DMA0COUNT'), # DMA channel 0 count - (0xf050c, 32, 'DMA0SRCADDR'), # DMA channel 0 source address - (0xf0510, 32, 'DMA0DSTADDR'), # DMA channel 0 destination address - (0xf0514, 32, 'DMA0AUTO0'), # DMA channel 0 slave lower data - (0xf0518, 32, 'DMA0AUTO1'), # DMA channel 0 slave upper data - (0xf051c, 32, 'DMA0STATUS'), # DMA channel 0 status - (0xf0520, 32, 'DMA1CONFIG'), # DMA channel 1 configuration - (0xf0524, 32, 'DMA1STRIDE'), # DMA channel 1 stride - (0xf0528, 32, 'DMA1COUNT'), # DMA channel 1 count - (0xf052c, 32, 'DMA1SRCADDR'), # DMA channel 1 source address - (0xf0530, 32, 'DMA1DSTADDR'), # DMA channel 1 destination address - (0xf0534, 32, 'DMA1AUTO0'), # DMA channel 1 slave lower data - (0xf0538, 32, 'DMA1AUTO1'), # DMA channel 1 slave upper data - (0xf053c, 32, 'DMA1STATUS'), # DMA channel 1 status - # Mesh node control registers - (0xf0700, 16, 'MESHCONFIG'), # Mesh node configuration - (0xf0704, 12, 'COREID'), # Processor core ID (12 bits) - (0xf0708, 12, 'MULTICAST'), # Multicast configuration - (0xf0710, 12, 'CMESHROUTE'), # cMesh routing configuration (12 bits) - (0xf0714, 12, 'XMESHROUTE'), # xMesh routing configuration (12 bits) - (0xf0718, 12, 'RMESHROUTE'), # rMesh routing configuration (12 bits) -] - - -# Register number -> (memory address, num bytes, name) -_register_map = OrderedDict() -# Add general purpose registers to register_map. -for index, address in enumerate(xrange(0xf0000, 0xf0100, 0x4)): - _register_map[index] = (address, 32, 'r%d' % ((address - 0xf0000) / 0x4)) -# Add special purpose registers to _register_map. -for index in xrange(len(_special_purpose_registers)): - _register_map[index + 64] = _special_purpose_registers[index] diff --git a/revelation/test/c/fib.c b/revelation/test/c/fib.c index 1b10069..b3d254e 100644 --- a/revelation/test/c/fib.c +++ b/revelation/test/c/fib.c @@ -5,9 +5,6 @@ int main() { temp = a; a = b; b += temp; - if (i == 19) { - __asm__("bkpt"); - } } return 0; } diff --git a/revelation/test/c/fib.elf b/revelation/test/c/fib.elf index a21cc98..505e2a5 100755 Binary files a/revelation/test/c/fib.elf and b/revelation/test/c/fib.elf differ diff --git a/revelation/test/machine.py b/revelation/test/machine.py index 98aa589..e278370 100644 --- a/revelation/test/machine.py +++ b/revelation/test/machine.py @@ -1,7 +1,7 @@ from pydgin.debug import Debug from revelation.machine import State from revelation.sim import new_memory -from revelation.isa import reg_map +from revelation.registers import reg_map from revelation.utils import bits2float flags = 'ACTIVE GID KERNEL WAND AN AZ AC AV AVS BN BV BIS BVS BUS BZ EXCAUSE pc'.split() diff --git a/revelation/test/opcode_factory.py b/revelation/test/opcode_factory.py index 31ae635..2c06a95 100644 --- a/revelation/test/opcode_factory.py +++ b/revelation/test/opcode_factory.py @@ -1,4 +1,4 @@ -from revelation.storage import get_address_of_register_by_name +from revelation.registers import get_address_of_register_by_name def make_zero_operand_factory(opcode): def factory(): diff --git a/revelation/test/test_asm.py b/revelation/test/test_asm.py index 5e1ef32..1de409a 100644 --- a/revelation/test/test_asm.py +++ b/revelation/test/test_asm.py @@ -260,7 +260,7 @@ def test_testset32_fail(capfd): is given is too low.. """ elf_filename = os.path.join(elf_dir, 'testset_fail.elf') - expected_text = """Exception in execution (pc: 0x00000358), aborting! + expected_text = """Exception in execution of testset32 (pc: 0x00000358), aborting! Exception message: testset32 has failed to write to address %s. The absolute address used for the test and set instruction must be located within the on-chip local memory and must be greater than 0x00100000 (2^20). diff --git a/revelation/test/test_compiled_c.py b/revelation/test/test_compiled_c.py index e71a5f4..b9169b4 100644 --- a/revelation/test/test_compiled_c.py +++ b/revelation/test/test_compiled_c.py @@ -103,7 +103,7 @@ def test_compiled_c_with_return(elf_file, expected): @pytest.mark.parametrize('elf_file,expected', [('nothing.elf', 250), - ('fib.elf', 461), + ('fib.elf', 544), ]) def test_compiled_c(elf_file, expected, capsys): """Test an ELF file that has been compiled from a C function. diff --git a/revelation/test/test_condition_passed.py b/revelation/test/test_condition_passed.py index 005cceb..9154703 100644 --- a/revelation/test/test_condition_passed.py +++ b/revelation/test/test_condition_passed.py @@ -1,8 +1,8 @@ -from pydgin.misc import FatalError - from revelation.condition_codes import condition_passed from revelation.test.machine import new_state +from pydgin.misc import FatalError + import pytest diff --git a/revelation/test/test_execute_interrupt.py b/revelation/test/test_execute_interrupt.py index cd0ae91..702f8dc 100644 --- a/revelation/test/test_execute_interrupt.py +++ b/revelation/test/test_execute_interrupt.py @@ -1,10 +1,10 @@ -from pydgin.misc import FatalError - from revelation.instruction import Instruction from revelation.isa import decode from revelation.machine import RESET_ADDR from revelation.test.machine import StateChecker, new_state +from pydgin.misc import FatalError, NotImplementedInstError + import opcode_factory import pytest @@ -46,13 +46,11 @@ def test_execute_idle16(): def test_execute_bkpt16(): - state = new_state(rfDEBUGSTATUS=0) - instr = opcode_factory.bkpt16() - name, executefn = decode(instr) - executefn(state, Instruction(instr, None)) - expected_state = StateChecker(rfDEBUGSTATUS=1) - expected_state.check(state) - assert not state.running + with pytest.raises(NotImplementedInstError): + state = new_state() + instr = opcode_factory.bkpt16() + name, executefn = decode(instr) + executefn(state, Instruction(instr, None)) def test_execute_rti16_no_interrupt(): @@ -143,7 +141,7 @@ def test_execute_trap_warning(): ('wand16', opcode_factory.wand16()), ]) def test_execute_multicore_instructions(name, instr): - with pytest.raises(NotImplementedError): + with pytest.raises(NotImplementedInstError): state = new_state() name, executefn = decode(instr) executefn(state, Instruction(instr, None)) diff --git a/revelation/test/test_execute_load_store.py b/revelation/test/test_execute_load_store.py index a18cc57..8617928 100644 --- a/revelation/test/test_execute_load_store.py +++ b/revelation/test/test_execute_load_store.py @@ -1,9 +1,9 @@ -from pydgin.misc import FatalError - from revelation.instruction import Instruction from revelation.isa import decode from revelation.test.machine import StateChecker, new_state +from pydgin.misc import FatalError + import opcode_factory import pytest diff --git a/revelation/test/test_opcode_factory.py b/revelation/test/test_opcode_factory.py index 027a75f..c66b704 100644 --- a/revelation/test/test_opcode_factory.py +++ b/revelation/test/test_opcode_factory.py @@ -1,4 +1,4 @@ -from revelation.isa import reg_map +from revelation.registers import reg_map from opcode_factory import * import pytest diff --git a/revelation/test/test_sim.py b/revelation/test/test_sim.py index cb593ab..33fa0f4 100644 --- a/revelation/test/test_sim.py +++ b/revelation/test/test_sim.py @@ -4,8 +4,8 @@ import opcode_factory -def test_sim_bkpt16(): - instructions = [(opcode_factory.bkpt16(), 16), # BKPT16 +def test_sim_trap16_3(): + instructions = [(opcode_factory.trap16(3), 16), ] revelation = MockRevelation() revelation.init_state(instructions) @@ -17,8 +17,8 @@ def test_sim_bkpt16(): def test_sim_nop16(): - instructions = [(opcode_factory.nop16(), 16), # NOP16 - (opcode_factory.bkpt16(), 16), # BKPT16 + instructions = [(opcode_factory.nop16(), 16), + (opcode_factory.trap16(3), 16), ] revelation = MockRevelation() revelation.init_state(instructions) @@ -31,7 +31,7 @@ def test_sim_nop16(): def test_single_inst_add32(): instructions = [(opcode_factory.add32_immediate(rd=1, rn=0, imm=0b01010101010), 32), - (opcode_factory.bkpt16(), 16)] + (opcode_factory.trap16(3), 16)] revelation = MockRevelation() revelation.init_state(instructions, rf0=0b01010101010) assert revelation.states[0].running @@ -44,7 +44,7 @@ def test_single_inst_add32(): def test_single_inst_sub32(): from pydgin.utils import trim_32 instructions = [(opcode_factory.sub32_immediate(rd=1, rn=0, imm=0b01010101010), 32), - (opcode_factory.bkpt16(), 16)] + (opcode_factory.trap16(3), 16)] revelation = MockRevelation() revelation.init_state(instructions, rf0=5) assert revelation.states[0].running @@ -61,7 +61,7 @@ def test_add32_sub32(): # TODO: Add new instruction to move the result of instruction 1 # TODO: to rf[0] before instruction 2 is executed. (opcode_factory.sub32_immediate(rd=1, rn=0, imm=0b01010101010), 32), - (opcode_factory.bkpt16(), 16), + (opcode_factory.trap16(3), 16), ] revelation = MockRevelation() revelation.init_state(instructions, rf0=0) @@ -77,7 +77,7 @@ def test_bcond32(): instructions = [(opcode_factory.sub32_immediate(rd=1, rn=0, imm=0b00000000101), 32), (opcode_factory.bcond32(condition=0b0000, imm=0b000000000000000000000100), 32), (opcode_factory.add32_immediate(rd=1, rn=0, imm=0b01010101010), 32), - (opcode_factory.bkpt16(), 16), + (opcode_factory.trap16(3), 16), ] revelation = MockRevelation() revelation.init_state(instructions, rf0=5) @@ -99,7 +99,7 @@ def test_add32_nop16_sub32(): instructions = [(opcode_factory.add32_immediate(rd=1, rn=0, imm=0b01010101010), 32), (opcode_factory.nop16(), 16), (opcode_factory.sub32_immediate(rd=1, rn=0, imm=0b01010101010), 32), - (opcode_factory.bkpt16(), 16), + (opcode_factory.trap16(3), 16), ] revelation = MockRevelation() revelation.init_state(instructions, rf0=0) @@ -114,7 +114,7 @@ def test_add32_nop16_sub32(): def test_sim_all_16bit(): instructions = [ (opcode_factory.gie16(), 16), (opcode_factory.gid16(), 16), - (opcode_factory.bkpt16(), 16), + (opcode_factory.trap16(3), 16), ] revelation = MockRevelation() revelation.init_state(instructions) diff --git a/revelation/utils.py b/revelation/utils.py index cdb2508..e7e746b 100644 --- a/revelation/utils.py +++ b/revelation/utils.py @@ -1,4 +1,4 @@ -from revelation.storage import get_register_size_by_address +from revelation.registers import get_register_size_by_address import pydgin.utils