Skip to content

Commit

Permalink
Added Interrupts finally
Browse files Browse the repository at this point in the history
  • Loading branch information
Daniel Knuettel committed Sep 29, 2016
1 parent c39ff6e commit f914090
Show file tree
Hide file tree
Showing 2 changed files with 106 additions and 4 deletions.
76 changes: 76 additions & 0 deletions core/interrupts.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
#!/usr/bin/python3

"""
**py_register_machine2.core.interrupts**: Basic module to provide Interrupts.
"""


class Interrupt(object):
"""
.. _Interrupt:
The Base Class for Interrupts.
If ``Interrupt.interrupt`` is invoked this will invoke ``Processor.interrupt`` and provide the address of the
Interrupt.
This will allow one to place an ISR (Interrupt Service Routine) at this address.
"""
def __init__(self, address, processor):
self.enable = False
self.address = address
self.processor = processor
self.processor.interrupts.append(self)
def interrupt(self):
"""
Will interrupt the Processor, if the Interrupt is enabled.
"""
if(self.enable):
self.processor.interrupt(self.address)


class Counter(Interrupt):
"""
.. _Counter:
A Counter/Timer implementation.
The ``__init__`` method will inject an ``on_cycle_callback`` into the Processor.
This callback will increment the internal counter variable by one.
If the internal counter reaches a predefined value the ``interrupt`` method will be invoked.
"""

def __init__(self, address, processor, overflow_size):
Interrupt.__init__(self, address, processor)
self.processor.on_cycle_callbacks.append(self.increment_counter)
self.counter = 0
self.overflow = overflow_size

def increment_counter(self):
self.counter += 1
if(self.counter >= self.overflow):
self.counter = 0
self.interrupt()

class Autoreset(Interrupt):
"""
.. _Autoreset:
A really rude form of the Watchdog.
This Interrupt will force the Processor to jump to offset ``0``.
"""

def __init__(self, processor, overflow_size):
Interrupt.__init__(self, 0, processor)
self.counter = 0
self.overflow = overflow_size
self.processor.on_cycle_callbacks.append(self.increment_counter)
def increment_counter(self):
self.counter += 1
if(self.counter >= self.overflow):
self.counter = 0
self.interrupt()

34 changes: 30 additions & 4 deletions core/processor.py
Original file line number Diff line number Diff line change
Expand Up @@ -166,7 +166,7 @@ def __init__(self, f_cpu = None, width = 64,
self.memory_bus = memory.BUS(width = width, debug = debug)
self.device_bus = device.BUS(width = width, debug = debug)
self.register_interface = RegisterInterface(width = width, debug = debug)
# program counter
# program counter, engine control register, stack pointer
self.register_interface.add_register(register.Register("PC", width = width))
self.register_interface.add_register(register.Register("ECR", width = width))
self.register_interface.add_register(register.Register("SP", width = width))
Expand All @@ -175,23 +175,46 @@ def __init__(self, f_cpu = None, width = 64,

if(f_cpu != None and clock != None):
raise SetupError("Software Clock (f_cpu) and Thread Clock (clock_barrier) are mutually exclusive")
self.interrupts = interrupts
self.interrupt_enable = interrupts
self.interrupts = []
self.debug = debug

self.commands_by_opcode = {}

self.last_cycle = None
self.current_cycle = None

if(interrupts):
raise SetupError("Interrupts are not yet implemented")

self.pc = 0
self.ecr = 0
self.sp = 0
self.on_cycle_callbacks = []
self.constants = {}
self.cycles = 0
self.push_pc = False

def en_dis_able_interrupts(self, mask):
"""
This callback might be used by a Register to enable/disable Interrupts.
``mask`` is an ``int``, the Interrupts are bits in this mask, the first registered interrupt
has the bit ``(1 << 0)``, the n-th Interrupt the bit ``(1 << (n - 1))``.
If the bit is cleared (``0``) the Interrupt will be disabled.
"""
for shift, interrupt in enumerate(self.interrupts):
if(mask & (1 << shift)):
interrupt.enable = True
else:
interrupt.enable = False
def interrupt(self, address):
"""
Interrupts the Processor and forces him to jump to ``address``.
If ``push_pc`` is enabled this will push the PC to the stack.
"""
if(self.push_pc):
self.memory_bus.write_word(self.sp, self.pc)
self._set_sp(self.sp - 1)
self._set_pc(address)

def _increase_pc(self):
self.pc += 1
Expand Down Expand Up @@ -235,6 +258,8 @@ def setup_done(self):
sets the Stack Pointer to RAMEND_HIGH, if there is a RAM attached.
If there is no RAM attached, SP will stay ``0``.
If there is a RAM attached ``push_pc`` is set.
Might raise SetupError_.
"""
if(self.memory_bus.device_count() < 1):
Expand All @@ -249,6 +274,7 @@ def setup_done(self):
self.constants["RAMEND_HIGH"] = rom.size + ram.size - 1
self.constants["RAMEND_LOW"] = rom.size
self._set_sp(rom.size + ram.size - 1)
self.push_pc = True
if(self.device_bus.device_count() > 0):
flash = self.device_bus.devices[0]
self.constants["FLASH_START"] = 0
Expand Down

0 comments on commit f914090

Please sign in to comment.