gen/common: Introduce LiteXModule class to simplify Modules creation and avoid common mistakes.

LiteXModule can be used as a remplacement of Migen's Module and in this initial version:
- Automatically inherit from AutoCSR (Forgeting to inherit from AutoCSR on a Module was a common mistake).
- Simplify design creation with:
  - m.module_x  = .. equivalent of Migen's m.submodules.module_x = ..
  - m.special_x = .. equivalent of Migen's m.specials.special_x  = ..
  - m.cd_x      = .. equivalent of Migen's m.clock_domains.cd_x  = ..
  - m += module_x  equivalent of Migen's m.submodules += module_x.
  - m += special_x equivalent of Migen's m.specials += special_x.
  - m += cd_x  equivalent of Migen's m.clock_domains += cd_x.
-> Forgeting to attach a correctly a Sub-module/Special was a very common mistake and having to use
m.submodules., m.specials., m.clock_domains. was not natural.
This commit is contained in:
Florent Kermarrec 2022-10-27 15:27:57 +02:00
parent e570b612b2
commit a71fd1d31b
2 changed files with 47 additions and 2 deletions

View File

@ -1,11 +1,16 @@
# #
# This file is part of LiteX. # This file is part of LiteX.
# #
# This file is Copyright (c) 2018 Florent Kermarrec <florent@enjoy-digital.fr> # This file is Copyright (c) 2018-2022 Florent Kermarrec <florent@enjoy-digital.fr>
# SPDX-License-Identifier: BSD-2-Clause # SPDX-License-Identifier: BSD-2-Clause
from migen import * from migen import *
from migen.fhdl.module import _ModuleProxy
from migen.fhdl.specials import Special
from litex.soc.interconnect.csr import AutoCSR
# Bit/Bytes Reversing ------------------------------------------------------------------------------
def reverse_bits(s): def reverse_bits(s):
return s[::-1] return s[::-1]
@ -15,3 +20,42 @@ def reverse_bytes(s):
n = (len(s) + 7)//8 n = (len(s) + 7)//8
return Cat(*[s[i*8:min((i + 1)*8, len(s))] return Cat(*[s[i*8:min((i + 1)*8, len(s))]
for i in reversed(range(n))]) for i in reversed(range(n))])
# LiteX Module -------------------------------------------------------------------------------------
class LiteXModule(Module, AutoCSR):
def __setattr__(m, name, value):
# Migen:
if name in ["comb", "sync", "specials", "submodules", "clock_domains"]:
if not isinstance(value, _ModuleProxy):
raise AttributeError("Attempted to assign special Module property - use += instead")
# LiteX fix-up: Automatically collect specials/submodules/clock_domains:
# - m.module_x = .. equivalent of Migen's m.submodules.module_x = ..
elif isinstance(value, Module) and ((name, value) not in m._submodules):
setattr(m.submodules, name, value)
# - m.special_x = .. equivalent of Migen's m.specials.special_x = ..
elif isinstance(value, Special) and (value not in m._fragment.specials):
setattr(m.specials, name, value)
# - m.cd_x = .. equivalent of Migen's m.clock_domains.cd_x = ..
elif isinstance(value, ClockDomain) and (value not in m._fragment.clock_domains):
setattr(m.clock_domains, name, value)
# Else use default __setattr__.
else:
object.__setattr__(m, name, value)
# LiteX fix-up: Automatically collect specials/submodules/clock_domains:
def __iadd__(m, other):
# - m += module_x equivalent of Migen's m.submodules += module_x.
if isinstance(other, Module):
print(other)
m.submodules += other
# - m += special_x equivalent of Migen's m.specials += special_x.
elif isinstnace(other, Special):
m.specials += other
# - m += cd_x equivalent of Migen's m.clock_domains += cd_x.
elif isinstance(other, ClockDomain):
m.clock_domains += other
# Else use default __iadd__.
else:
object.__iadd__(m, other)
return m

View File

@ -15,6 +15,7 @@ import datetime
from math import log2, ceil from math import log2, ceil
from migen import * from migen import *
from litex.gen import LiteXModule
from litex.soc.cores import cpu from litex.soc.cores import cpu
@ -766,7 +767,7 @@ class SoCController(Module, AutoCSR):
# SoC ---------------------------------------------------------------------------------------------- # SoC ----------------------------------------------------------------------------------------------
class SoC(Module): class SoC(LiteXModule):
mem_map = {} mem_map = {}
def __init__(self, platform, sys_clk_freq, def __init__(self, platform, sys_clk_freq,
bus_standard = "wishbone", bus_standard = "wishbone",