From f9140903a677b91ef780d7b6942852ed491f298b Mon Sep 17 00:00:00 2001 From: Daniel Knuettel Date: Thu, 29 Sep 2016 20:38:10 +0200 Subject: [PATCH] Added Interrupts finally --- core/interrupts.py | 76 ++++++++++++++++++++++++++++++++++++++++++++++ core/processor.py | 34 ++++++++++++++++++--- 2 files changed, 106 insertions(+), 4 deletions(-) create mode 100644 core/interrupts.py diff --git a/core/interrupts.py b/core/interrupts.py new file mode 100644 index 0000000..9b7f94e --- /dev/null +++ b/core/interrupts.py @@ -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() + diff --git a/core/processor.py b/core/processor.py index 4148da6..0989473 100644 --- a/core/processor.py +++ b/core/processor.py @@ -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)) @@ -175,7 +175,8 @@ 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 = {} @@ -183,8 +184,6 @@ def __init__(self, f_cpu = None, width = 64, self.last_cycle = None self.current_cycle = None - if(interrupts): - raise SetupError("Interrupts are not yet implemented") self.pc = 0 self.ecr = 0 @@ -192,6 +191,30 @@ def __init__(self, f_cpu = None, width = 64, 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 @@ -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): @@ -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