From fd8739d51708ce7829bf6cc8723be6c6b33f6e22 Mon Sep 17 00:00:00 2001 From: Robert Mibus Date: Sat, 25 Jul 2020 13:02:22 +1000 Subject: [PATCH 1/4] Add a ROT13 workshop example --- litex/workshop_rot13.py | 83 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 83 insertions(+) create mode 100755 litex/workshop_rot13.py diff --git a/litex/workshop_rot13.py b/litex/workshop_rot13.py new file mode 100755 index 00000000..9572498b --- /dev/null +++ b/litex/workshop_rot13.py @@ -0,0 +1,83 @@ +#!/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): + 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): + self.csr = CSRStorage(8) + 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() From 5a3c933cf3b5abd820e2ed742ee7bc59bb19bfa5 Mon Sep 17 00:00:00 2001 From: Robert Mibus Date: Sat, 25 Jul 2020 13:42:39 +1000 Subject: [PATCH 2/4] Add some comments to the ROT13 example --- litex/workshop_rot13.py | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/litex/workshop_rot13.py b/litex/workshop_rot13.py index 9572498b..408e04c7 100755 --- a/litex/workshop_rot13.py +++ b/litex/workshop_rot13.py @@ -31,12 +31,21 @@ # 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) + # There are three cases: + # 1. It's "A" through "M": Add 13, to make the letters "N" through "Z". + # 2. It's "N" through "Z": Remove 13, to make the letters "A" through "M". + # 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) From 6297c5bc8b72b6235ff1700c1ccae0cbb21c5d4c Mon Sep 17 00:00:00 2001 From: Robert Mibus Date: Sat, 25 Jul 2020 15:36:45 +1000 Subject: [PATCH 3/4] Mention the ROT13 example in the docs --- docs/migen.rst | 7 +++++++ 1 file changed, 7 insertions(+) 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. From 5802609aae8eeb085db212e906d4c3066e149601 Mon Sep 17 00:00:00 2001 From: Robert Mibus Date: Sun, 26 Jul 2020 12:18:32 +1000 Subject: [PATCH 4/4] Improve rot13 comments further --- litex/workshop_rot13.py | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/litex/workshop_rot13.py b/litex/workshop_rot13.py index 408e04c7..fa2a85c1 100755 --- a/litex/workshop_rot13.py +++ b/litex/workshop_rot13.py @@ -34,14 +34,28 @@ 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. +# 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) - # There are three cases: + # 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)