diff --git a/litex/soc/cores/watchdog.py b/litex/soc/cores/watchdog.py new file mode 100644 index 000000000..9ebcc2fb3 --- /dev/null +++ b/litex/soc/cores/watchdog.py @@ -0,0 +1,70 @@ +# +# This file is part of LiteX. +# +# Copyright (c) 2024 Fin Maaß +# SPDX-License-Identifier: BSD-2-Clause + +from migen import * + +from litex.gen import * +from litex.gen.genlib.misc import WaitTimer + +from litex.soc.interconnect.csr import * +from litex.soc.interconnect.csr_eventmanager import * + +# Watchdog -------------------------------------------------------------------------------------------- + +class Watchdog(LiteXModule): + """Watchdog + + Provides a generic Watchdog core. + """ + + def __init__(self, width=32, crg_rst=None, reset_delay=0, halted=None): + self.enable = Signal() + self.reset_mode = Signal() + self.feed = Signal() + self.halted = Signal() + + self.execute = Signal() + + self._control = CSRStorage(description="Watchdog Control.", fields=[ + CSRField("feed", size=1, offset=0, pulse=True, description="Watchdog feed (Write ``1`` to feed)."), + CSRField("enable", size=1, offset=8, description="Watchdog enable."), + CSRField("reset", size=1, offset=16, description="Reset SoC when watchdog times out."), + CSRField("pause_halted", size=1, offset=24, description="Pause watchdog when CPU is halted.") + ]) + + self.comb += [ + self.enable.eq(self._control.fields.enable & ~self.halted), + self.feed.eq(self._control.fields.feed), + self.reset_mode.eq(self._control.fields.reset), + ] + + if isinstance(halted, Signal): + self.comb += self.halted.eq(halted & self._control.fields.pause_halted) + + self._cycles = cycles = CSRStorage(description="Watchdog cycles until timeout.", size=width) + self._remaining = remaining = CSRStatus(description="Watchdog cycles remaining until timeout.", size=width) + + self.ev = EventManager() + self.ev.wdt = EventSourceProcess(edge="rising") + self.ev.finalize() + + self.sync += [ + If(self.feed, + remaining.status.eq(cycles.storage) + ).Elif(self.enable, + If(remaining.status != 0, + remaining.status.eq(remaining.status - 1) + ), + self.execute.eq(remaining.status == 0), + ) + ] + + self.comb += If(self.enable, self.ev.wdt.trigger.eq(self.execute)) + + if isinstance(crg_rst, Signal): + self.reset_timer = WaitTimer(reset_delay) + self.comb += self.reset_timer.wait.eq(self.enable & self.execute & self.reset_mode) + self.comb += If(self.reset_timer.done, crg_rst.eq(1)) diff --git a/litex/soc/integration/soc.py b/litex/soc/integration/soc.py index 3ed2aacd3..647cd90d1 100644 --- a/litex/soc/integration/soc.py +++ b/litex/soc/integration/soc.py @@ -1317,6 +1317,24 @@ class SoC(LiteXModule, SoCCoreCompat): if self.irq.enabled: self.irq.add(name, use_loc_if_exists=True) + # Add Watchdog --------------------------------------------------------------------------------- + def add_watchdog(self, name="watchdog0", width=32, crg_rst=None, reset_delay=None): + from litex.soc.cores.watchdog import Watchdog + + if crg_rst is None: + crg_rst = getattr(self.crg, "rst", None) if hasattr(self, "crg") else None + if reset_delay is None: + reset_delay = self.sys_clk_freq + + halted = getattr(self.cpu, "o_halted", None) if hasattr(self, "cpu") else None + + self.check_if_exists(name) + watchdog = Watchdog(width=width, crg_rst=crg_rst, reset_delay=int(reset_delay), halted=halted) + self.add_module(name=name, module=watchdog) + + if self.irq.enabled: + self.irq.add(name, use_loc_if_exists=True) + # SoC finalization ----------------------------------------------------------------------------- def finalize(self): if self.finalized: diff --git a/litex/soc/integration/soc_core.py b/litex/soc/integration/soc_core.py index 34a430bfc..0373c5058 100644 --- a/litex/soc/integration/soc_core.py +++ b/litex/soc/integration/soc_core.py @@ -115,6 +115,11 @@ class SoCCore(LiteXSoC): # UARTBone. with_uartbone = False, + # Watchdog. + with_watchdog = False, + watchdog_width = 32, + watchdog_reset_delay = None, + # Others. **kwargs): @@ -266,6 +271,10 @@ class SoCCore(LiteXSoC): if timer_uptime: self.timer0.add_uptime() + # Add Watchdog. + if with_watchdog: + self.add_watchdog(name="watchdog0" ,width=watchdog_width, reset_delay=watchdog_reset_delay) + # Methods -------------------------------------------------------------------------------------- def add_csr(self, csr_name, csr_id=None, use_loc_if_exists=False): @@ -338,6 +347,11 @@ def soc_core_args(parser): soc_group.add_argument("--no-timer", action="store_true", help="Disable Timer.") soc_group.add_argument("--timer-uptime", action="store_true", help="Add an uptime capability to Timer.") + # Watchdog parameters. + soc_group.add_argument("--with-watchdog", action="store_true", help="Enable Watchdog.") + soc_group.add_argument("--watchdog-width", default=32, type=auto_int, help="Watchdog width.") + soc_group.add_argument("--watchdog-reset-delay", default=None, type=auto_int, help="Watchdog width.") + # L2 Cache. soc_group.add_argument("--l2-size", default=8192, type=auto_int, help="L2 cache size.") diff --git a/litex/tools/litex_json2dts_zephyr.py b/litex/tools/litex_json2dts_zephyr.py index b5a2451d1..8b755eedd 100755 --- a/litex/tools/litex_json2dts_zephyr.py +++ b/litex/tools/litex_json2dts_zephyr.py @@ -314,6 +314,10 @@ overlay_handlers = { 'handler': i2s_handler, 'config_entry': 'I2S_LITEX' }, + 'watchdog0': { + 'handler': peripheral_handler, + 'alias': 'wdt0', + }, 'mmcm' : { 'alias': 'clock0', 'handler': peripheral_handler,