diff --git a/docs/migen.rst b/docs/migen.rst index aae8a940..a2631499 100644 --- a/docs/migen.rst +++ b/docs/migen.rst @@ -206,3 +206,10 @@ your ``build/csr.csv`` says) and see them take effect immediately. You can see that it takes very little code to take a Signal from HDL and expose it on the Wishbone bus. + +Tying Signals together +^^^^^^^^^^^^^^^^^^^^^^ + +See ``workshop_rot13.py`` for another example, where two CSRs are connected +(one as an input, one as an output) in order to create a one-character ROT13 +encoder/decoder. diff --git a/litex/workshop_rot13.py b/litex/workshop_rot13.py new file mode 100755 index 00000000..fa2a85c1 --- /dev/null +++ b/litex/workshop_rot13.py @@ -0,0 +1,106 @@ +#!/usr/bin/env python3 +# This variable defines all the external programs that this module +# relies on. lxbuildenv reads this variable in order to ensure +# the build will finish without exiting due to missing third-party +# programs. +LX_DEPENDENCIES = ["icestorm", "yosys", "nextpnr-ice40"] +#LX_CONFIG = "skip-git" # This can be useful for workshops + +# Import lxbuildenv to integrate the deps/ directory +import os,os.path,shutil,sys,subprocess +sys.path.insert(0, os.path.dirname(__file__)) +import lxbuildenv + +# Disable pylint's E1101, which breaks completely on migen +#pylint:disable=E1101 + +from migen import * +from migen.genlib.resetsync import AsyncResetSynchronizer + +from litex.soc.integration.soc_core import SoCCore +from litex.soc.integration.builder import Builder +from litex.soc.interconnect.csr import AutoCSR, CSRStatus, CSRStorage, CSRField + +from litex_boards.partner.targets.fomu import BaseSoC, add_dfu_suffix + +from valentyusb.usbcore import io as usbio +from valentyusb.usbcore.cpu import dummyusb + +import argparse + +# ROT13 input CSR. Doesn't need to do anything special. +class FomuROT13In(Module, AutoCSR): + def __init__(self): + # 8-Bit CSR (one ASCII character) + self.csr = CSRStorage(8) + +# ROT13 output CSR, plus the wiring to automatically create the output from +# the input CSR. +class FomuROT13Out(Module, AutoCSR): + def __init__(self, rot13_in): + # Set up an 8-bit CSR (one ASCII character) + self.csr = CSRStorage(8) + # ROT13 is described fully here - https://en.wikipedia.org/wiki/ROT13 + # + # In short, for letters of the English alphabet, they're "rotated" 13 + # places along ("A" becomes "N", "B" becomes "O"); at the end of the + # alphabet you wrap back around ("Z" becomes "M"). Anything not in + # the English alphabet (numbers, special characters) is left + # untouched. + # + # Conveniently (due to the wrap-around property) we can just + # *subtract* 13 to get the same result as the wrap-around. + # + # This means we care about three cases: + # 1. It's "A" through "M": Add 13, to make the letters "N" through "Z". + # (Likewise for lowercase "a" through "m"). + # 2. It's "N" through "Z": Remove 13, to make the letters "A" through "M". + # (Likewise for lowercase "n" through "z"). + # 3. It's something else, so leave it alone. + # + # In all three cases, we want to wire up the "output" signal (self.csr.storage) + # to be equal to something based on the input signal (rot13_in.csr.storage). + self.sync += If( # A-M, a-m + (rot13_in.csr.storage >= ord('A')) & (rot13_in.csr.storage <= ord('M')) | (rot13_in.csr.storage >= ord('a')) & (rot13_in.csr.storage <= ord('m')), + self.csr.storage.eq(rot13_in.csr.storage + 13) + ).Elif( # N-Z, n-z + (rot13_in.csr.storage >= ord('N')) & (rot13_in.csr.storage <= ord('Z')) | (rot13_in.csr.storage >= ord('n')) & (rot13_in.csr.storage <= ord('z')), + self.csr.storage.eq(rot13_in.csr.storage - 13) + ).Else( + self.csr.storage.eq(rot13_in.csr.storage) + ) + +def main(): + parser = argparse.ArgumentParser( + description="Build Fomu Main Gateware") + parser.add_argument( + "--seed", default=0, help="seed to use in nextpnr" + ) + parser.add_argument( + "--placer", default="heap", choices=["sa", "heap"], help="which placer to use in nextpnr" + ) + parser.add_argument( + "--board", choices=["evt", "pvt", "hacker"], required=True, + help="build for a particular hardware board" + ) + args = parser.parse_args() + + soc = BaseSoC(args.board, pnr_seed=args.seed, pnr_placer=args.placer, usb_bridge=True) + + # Create a CSR-based ROT13 input and output, export the CSRs + rot13_in = FomuROT13In() + soc.submodules.fomu_rot13_in = rot13_in + soc.submodules.fomu_rot13_out = FomuROT13Out(rot13_in) + soc.add_csr("fomu_rot13_in") + soc.add_csr("fomu_rot13_out") + + builder = Builder(soc, + output_dir="build", csr_csv="build/csr.csv", + compile_software=False) + vns = builder.build() + soc.do_exit(vns) + add_dfu_suffix(os.path.join('build', 'gateware', 'top.bin')) + + +if __name__ == "__main__": + main()