-"""Simple example of a FSM-based ALU
-
-This demonstrates a design that follows the valid/ready protocol of the
-ALU, but with a FSM implementation, instead of a pipeline. It is also
-intended to comply with both the CompALU API and the nmutil Pipeline API
-(Liskov Substitution Principle)
-
-The basic rules are:
-
-1) p.ready_o is asserted on the initial ("Idle") state, otherwise it keeps low.
-2) n.valid_o is asserted on the final ("Done") state, otherwise it keeps low.
-3) The FSM stays in the Idle state while p.valid_i is low, otherwise
- it accepts the input data and moves on.
-4) The FSM stays in the Done state while n.ready_i is low, otherwise
- it releases the output data and goes back to the Idle state.
-
-"""
+"""Generation of GTKWave documents with nmutil.gtkw"""
from nmigen import Elaboratable, Signal, Module, Cat
-cxxsim = False
-if cxxsim:
- from nmigen.sim.cxxsim import Simulator, Settle
-else:
- from nmigen.back.pysim import Simulator, Settle
+from nmigen.back.pysim import Simulator
from nmigen.cli import rtlil
from math import log2
from nmutil.iocontrol import PrevControl, NextControl
from soc.fu.base_input_record import CompOpSubsetBase
-from soc.decoder.power_enums import (MicrOp, Function)
from vcd.gtkw import GTKWSave, GTKWColor
from nmutil.gtkw import write_gtkw
class Shifter(Elaboratable):
"""Simple sequential shifter
- Prev port data:
* p.data_i.data: value to be shifted
+
* p.data_i.shift: shift amount
- * When zero, no shift occurs.
- * On POWER, range is 0 to 63 for 32-bit,
- * and 0 to 127 for 64-bit.
- * Other values wrap around.
- Operation type
* op.sdir: shift direction (0 = left, 1 = right)
- Next port data:
* n.data_o.data: shifted value
"""
class PrevData:
m.submodules.p = self.p
m.submodules.n = self.n
- # Note:
- # It is good practice to design a sequential circuit as
- # a data path and a control path.
-
- # Data path
- # ---------
- # The idea is to have a register that can be
- # loaded or shifted (left and right).
-
# the control signals
load = Signal()
shift = Signal()
# register the next value
m.d.sync += shift_reg.eq(next_shift)
- # Control path
- # ------------
- # The idea is to have a SHIFT state where the shift register
- # is shifted every cycle, while a counter decrements.
- # This counter is loaded with shift amount in the initial state.
- # The SHIFT state is left when the counter goes to zero.
-
# Shift counter
shift_width = int(log2(self.width)) + 1
next_count = Signal(shift_width)
return list(self)
-# Write a formatted GTKWave "save" file
-def write_gtkw_v1(base_name, top_dut_name, loc):
+def write_gtkw_direct():
+ """Write a formatted GTKWave "save" file, using vcd.gtkw directly"""
# hierarchy path, to prepend to signal names
- dut = top_dut_name + "."
+ dut = "top.shf."
# color styles
style_input = GTKWColor.orange
style_output = GTKWColor.yellow
style_debug = GTKWColor.red
- with open(base_name + ".gtkw", "wt") as gtkw_file:
+ with open("test_shifter_direct.gtkw", "wt") as gtkw_file:
gtkw = GTKWSave(gtkw_file)
- gtkw.comment("Auto-generated by " + loc)
- gtkw.dumpfile(base_name + ".vcd")
+ gtkw.comment("Auto-generated by " + __file__)
+ gtkw.dumpfile("test_shifter.vcd")
# set a reasonable zoom level
# also, move the marker to an interesting place
gtkw.zoom_markers(-22.9, 10500000)
def test_shifter():
+ """Simulate the Shifter to generate some traces,
+ as well as the GTKWave documents"""
m = Module()
m.submodules.shf = dut = Shifter(8)
print("Shifter port names:")
with open("test_shifter.il", "w") as f:
f.write(il)
- # Write the GTKWave project file
- write_gtkw_v1("test_shifter", "top.shf", __file__)
+ # write the GTKWave project file, directly
+ write_gtkw_direct()
# Describe a GTKWave document
]),
]
- write_gtkw("test_shifter_v2.gtkw", "test_shifter.vcd",
+ write_gtkw("test_shifter.gtkw", "test_shifter.vcd",
gtkwave_desc, gtkwave_style,
module="top.shf", loc=__file__, marker=10500000)