Skip to content

Commit

Permalink
gateware/freq_count.py: Add docstrings.
Browse files Browse the repository at this point in the history
  • Loading branch information
William D. Jones committed Aug 9, 2016
1 parent bafece1 commit a686d8b
Showing 1 changed file with 206 additions and 1 deletion.
207 changes: 206 additions & 1 deletion gateware/freq_count.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,15 +7,56 @@
# Essentially an "Always-enabled GrayCounter with a separate clock domain."
@ClockDomainsRenamer("src")
class EventGrayCounter(GrayCounter):
"""Gray counter with reset.
This module subclasses GrayCounter, making it always enabled and
usable in a separate clock domain from cd_sys. Each positive edge
of the src clock domain will increment the counter.
Parameters
----------
width: int
Width of the counter
Attributes
----------
ce: Signal, in
Chip-enable.
q: list of Signals, out
Current gray-encoded counter output, incremented each clock.
"""
def __init__(self, width):
GrayCounter.__init__(self, width)
self.input_sig = Signal()

###
self.comb += [self.ce.eq(1)]


class Synchronizer(Module):
"""A register suitable for clock-domain crossings.
Synchronizer takes an gray-encoded input signal from one clock
domain and safely transfers the signal to another clock domain.
Parameters
----------
width : int
Width of the register
Attributes
----------
inp : list of Signals, in
Source clock domain input.
out : list of Signals, out
Destination clock domain output.
Notes
-----
By default, the source clock domain is sys, and the source clock
domain is dest. Make sure to instantiate these clock domains, or
use the ClockDomainsRenamer decorator.
"""
def __init__(self, width):
self.inp = Signal(width)
stage1 = Signal(width)
Expand All @@ -27,6 +68,20 @@ def __init__(self, width):


class GrayToBinary(Module):
"""Convert a Gray code value to standard binary representation.
Parameters
----------
width : int
Width of the conversion.
Attributes
----------
gray_in : list of Signals, in
Gray-encoded input.
binary_out : list of Signals, out
Binary-encoded output.
"""
def __init__(self, width):
self.gray_in = Signal(width)
self.binary_out = Signal(width)
Expand All @@ -41,6 +96,20 @@ def __init__(self, width):

@ResetInserter
class Counter(Module):
"""Counter with reset.
Parameters
----------
width : int
Width of the counter
Attributes
----------
reset : Signal, in
Reset the counter to 0 when asserted.
count : list of Signals, out
Counter output.
"""
def __init__(self, width):
self.count = Signal(width)

Expand All @@ -50,6 +119,22 @@ def __init__(self, width):

@ResetInserter()
class FlipFlop(Module):
"""Flip-flop with reset.
Parameters
----------
width : int
Width of the flip-flop
Attributes
----------
reset : Signal, in
Reset flip-flop to 0 when asserted.
inp : list of Signals, in
Flip-flop input to be latched to output, next clock cycle.
out : list of Signals, out
Current flip-flop latched value.
"""
def __init__(self, width):
self.inp = Signal(width)
self.out = Signal(width)
Expand All @@ -59,6 +144,40 @@ def __init__(self, width):


class Sampler(Module):
"""Increment an internal accumulator each destination clock tick.
Every clock tick in the destination clock domain, Sampler will
latch the number of ticks counted from the source clock domain,
and add them to an internal accumulator. The source clock tick
counter should then be reset be external means, and counting will
repeat until the next tick in the destination clock domain.
Parameters
----------
sample_width : int
Width of the source clock domain counter. In theory, this
limits the maximum number of events which can be counted
in a single destination clock tick to 2**width - 1 source
ticks.
full_width: int
Width of the internal accumulator.
Attributes
----------
sample_in : list of Signals, in
Number of events counted in the source clock domain, generated
externally.
end_period : Signal, in
Reset the internal accumulator to 0.
last_total : list of Signals, out
Register holding the total number of source events counted
since the previous end_period (or system reset).
inc : list of Signals, out
curr_total.out : list of Signals, out
Internal signal holding the current number of source events
counted since the previous end_period (or system reset).
"""
def __init__(self, sample_width, full_width):
self.sample_in = Signal(sample_width)
self.inc = Signal(sample_width)
Expand All @@ -83,6 +202,48 @@ def __init__(self, sample_width, full_width):


class FreqCountCore(Module):
"""Frequency counter.
FreqCountCore provides an interface to a full-fledged frequency
counter, which can be wrapped in a higher-level class to add
as an I/O peripheral on a CPU bus.
Parameters
----------
sample_width : int
Width of the source clock domain counter. In theory, this
limits the maximum number of events which can be counted
in a single destination clock tick to 2**width - 1 source
ticks.
full_width : int
Width of the internal accumulator.
Attributes
----------
count_curr : list of Signals, out
Number of source ticks currently elapsed in the
current sampling period.
count_latched : list of Signals, out
Number of source ticks total in last sampling period.
latch : Signal, in
Latch and reset the internal accumulator.
cd_src : ClockDomain, in
Source clock domain object. The clk attribute is the signal
of interest to count.
cd_dest : ClockDomain, in
Destination clock domain object. The clk and rst attribute
drive the rest of the design.
Notes
-----
The frequency counter's design was inspired by ideas discussed on
this page:
http://hamsterworks.co.nz/mediawiki/index.php/High_Speed_Frequency_Counter
The default clock domains are named src and dest respectively.
These can be overidden using ClockDomainsRenamer, or accessing
the clock domains directly.
"""
def __init__(self, sample_width, full_width):
self.count_curr = Signal(full_width)
self.count_latched = Signal(full_width)
Expand Down Expand Up @@ -111,6 +272,50 @@ def __init__(self, sample_width, full_width):


class FrequencyCounter(Module, AutoCSR):
"""Frequency counter using the CSR bus.
FrequencyCounter wraps around FreqCountCore and offers a CSR-bus
interface to a frequency counter. Attaching this as a submodule
in a MiSoC design, and assigning an address to csr_peripherals
should be sufficient to generate proper API access functions and
add as an I/O peripheral on a SoC.
Parameters
----------
sample_clk_ticks : int
Number of clock ticks in the destination clock domain that
should elapsed before FreqCountCore latches/resets the
Sampler's internal accumulator.
sample_width : int
Width of the source clock domain counter. In theory, this
limits the maximum number of events which can be counted
in a single destination clock tick to 2**width - 1 source
ticks.
full_width : int
Width of the internal accumulator.
Attributes
----------
core : FreqCountCore
Access to all of FreqCountCore's signals is provided through
this attribute.
Registers
---------
value : Number of source ticks total in last sampling period.
num_events : Number of source ticks currently elapsed in the
current sampling period.
num_samples: Number of elapsed dest clock ticks in current period.
last_inc: Number of elapsed source ticks in last sample. This
value was routed up from a signal used internally by Sampler
and should not otherwise be used.
Notes
-----
If the sample_clk_ticks value does not coincide with the dest
clock frequency, it is the user's responsibility to calculate
the frequency by converting the unit of time measured to 1 second.
"""
# sample_clk_ticks: How many clocks of the dest domain should elapsed
# to be considered a full period.
# sample_width: Bit width of the src domain sampling counter.
Expand Down

0 comments on commit a686d8b

Please sign in to comment.