Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Create freq_count.py #204

Closed
wants to merge 3 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
1 change: 1 addition & 0 deletions firmware/lm32/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ OBJECTS=isr.o \
main.o \
opsis_eeprom.o \
tofe_eeprom.o \
freq.o \
version.o \
version_data.o \

Expand Down
21 changes: 21 additions & 0 deletions firmware/lm32/ci.c
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
#include "hdmi_out0.h"
#include "hdmi_out1.h"
#include "version.h"
#include "freq.h"

int status_enabled;

Expand Down Expand Up @@ -97,6 +98,9 @@ static void help_debug(void)
puts(" debug ddr - show DDR bandwidth");
puts(" debug dna - show Board's DNA");
puts(" debug edid - dump monitor EDID");
#ifdef CSR_FREQ_COUNT_BASE
puts(" debug freq - get input frequencies");
#endif
#ifdef CSR_OPSIS_EEPROM_I2C_W_ADDR
puts(" debug opsis_eeprom - dump Opsis Info EEPROM");
#endif
Expand Down Expand Up @@ -160,6 +164,7 @@ static void status_disable(void)
}

static void debug_ddr(void);
static void debug_freq(void);

static void status_print(void)
{
Expand Down Expand Up @@ -225,6 +230,10 @@ static void status_print(void)
#endif
printf("ddr: ");
debug_ddr();
#ifdef CSR_FREQ_COUNT_BASE
printf("freq: ");
debug_freq();
#endif
}

static void status_service(void)
Expand Down Expand Up @@ -465,6 +474,13 @@ static void debug_input(unsigned int channels, unsigned int change, unsigned int
}
#endif

#ifdef CSR_FREQ_COUNT_BASE
static void debug_freq(void)
{
freq_dump();
}
#endif

static char *readstr(void)
{
char c[2];
Expand Down Expand Up @@ -742,6 +758,11 @@ void ci_service(void)
debug_ddr();
else if(strcmp(token, "dna") == 0)
print_board_dna();
#ifdef CSR_FREQ_COUNT_BASE
else if(strcmp(token, "freq") == 0) {
debug_freq();
}
#endif
#ifdef CSR_OPSIS_EEPROM_I2C_W_ADDR
else if(strcmp(token, "opsis_eeprom") == 0) {
opsis_eeprom_dump();
Expand Down
9 changes: 9 additions & 0 deletions firmware/lm32/freq.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
#include <stdio.h>
#include <generated/csr.h>

#include "freq.h"

void freq_dump(void)
{
printf("Frequency: %d Hz\n", freq_count_freq_out_read());
}
6 changes: 6 additions & 0 deletions firmware/lm32/freq.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
#ifndef __FREQ_H
#define __FREQ_H

void freq_dump(void);

#endif
142 changes: 142 additions & 0 deletions gateware/freq_count.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,142 @@
from migen.fhdl.std import *
from migen.genlib.fifo import AsyncFIFO
from migen.genlib.misc import ClockDomainsRenamer
from migen.fhdl.bitcontainer import flen
from migen.genlib.cdc import GrayCounter
from migen.bank.description import *
from migen.fhdl import verilog


# Essentially an "Always-enabled GrayCounter with a separate clock domain."
@ClockDomainsRenamer("src")
class EventGrayCounter(GrayCounter):
def __init__(self, width):
GrayCounter.__init__(self, width)
self.input_sig = Signal()

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


class Synchronizer(Module):
def __init__(self, width):
self.inp = Signal(width)
stage1 = Signal(width)
self.out = Signal(width)

###
self.sync.dest += [stage1.eq(self.inp),
self.out.eq(stage1)]


class GrayToBinary(Module):
def __init__(self, width):
self.gray_in = Signal(width)
self.binary_out = Signal(width)

###
self.comb += [self.binary_out[-1].eq(self.gray_in[-1])]

for n in range(width - 2, -1, -1):
self.comb += [self.binary_out[n].eq(self.binary_out[n + 1] ^ self.gray_in[n])]


@ResetInserter
class Counter(Module):
def __init__(self, width):
self.count = Signal(width)

###
self.sync.dest += [self.count.eq(self.count + 1)]


@ResetInserter()
class FlipFlop(Module):
def __init__(self, width):
self.inp = Signal(width)
self.out = Signal(width)

###
self.sync.dest += [self.out.eq(self.inp)]


class Sampler(Module):
def __init__(self, sample_width, full_width):
self.sample_in = Signal(sample_width)
self.inc = Signal(sample_width)
self.last_total = Signal(full_width)
self.end_period = Signal(1)

self.submodules.last_sample = FlipFlop(sample_width)
self.submodules.curr_total = FlipFlop(full_width)

###
self.comb += [self.last_sample.inp.eq(self.sample_in)]
# Resetting souce clock domain is unreliable, so just use wrapping
# property of unsigned arithmetic to reset the count each sample.
self.comb += [self.inc.eq(self.sample_in - self.last_sample.out)]
self.comb += [self.curr_total.inp.eq(self.curr_total.out + self.inc)]
self.comb += [self.curr_total.reset.eq(self.end_period)]

# During period reset, curr_total won't latch the final value, so
# store it in separate location.
self.sync.dest += [If(self.end_period,
self.last_total.eq(self.curr_total.inp))]


class FreqCountCore(Module):
def __init__(self, sample_width, full_width):
self.count_curr = Signal(full_width)
self.count_latched = Signal(full_width)
self.latch = Signal(1)

self.submodules.ev_count = EventGrayCounter(sample_width)
self.submodules.clk_sync = Synchronizer(sample_width)
self.submodules.gray2bin = GrayToBinary(sample_width)
self.submodules.sampler = Sampler(sample_width, full_width)

self.clock_domains.cd_dest = ClockDomain()
self.clock_domains.cd_src = ClockDomain(reset_less=True)

###
self.comb += [self.clk_sync.inp.eq(self.ev_count.q),
self.gray2bin.gray_in.eq(self.clk_sync.out),
self.sampler.sample_in.eq(self.gray2bin.binary_out),
self.count_latched.eq(self.sampler.last_total),
self.count_curr.eq(self.sampler.curr_total.out),
self.sampler.end_period.eq(self.latch)]


class FrequencyCounter(Module, AutoCSR):
# 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.
# full_width: Bit width of the dest domain sampling counter, output being
# the sum of all samples in the current period.

# freq_out: Number of src eventstotal in last sampling period.
# num_events: Number of src events in current elapsed sampling period.
# num_samples: Number of elapsed dest clks in current period.
# last_inc: Number of elapsed src clks in last sample.
def __init__(self, sample_clk_ticks, sample_width, full_width):
self.freq_out = CSRStatus(full_width)
self.num_events = CSRStatus(full_width)
self.num_samples = CSRStatus(full_width)
self.last_inc = CSRStatus(sample_width)

# TODO: Perhaps configure the number of dest clk ticks before
# number of events is latched?

self.submodules.core = FreqCountCore(sample_width, full_width)

###
self.comb += [self.freq_out.status.eq(self.core.count_latched),
self.num_events.status.eq(self.core.count_curr),
self.last_inc.status.eq(self.core.sampler.inc)]

# sample_clk_ticks = 0 is a legal sample period. It means sample each cycle.
self.sync.dest += [self.core.latch.eq(0),
If(self.num_samples.status == sample_clk_ticks,
self.num_samples.status.eq(0),
self.core.latch.eq(1)).
Else(self.num_samples.status.eq(self.num_samples.status + 1))]
2 changes: 2 additions & 0 deletions platforms/minispartan6.py
Original file line number Diff line number Diff line change
Expand Up @@ -170,6 +170,8 @@ class Platform(XilinxPlatform):

def __init__(self, device="xc6slx25", programmer="openocd"):
XilinxPlatform.__init__(self, device+"-3-ftg256", _io, _connectors)
# FPGA AUX is connected to the 3.3V supply
self.add_platform_command("""CONFIG VCCAUX="3.3";""")
self.programmer = programmer

def create_programmer(self):
Expand Down
16 changes: 16 additions & 0 deletions targets/minispartan6_base.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,9 @@
from migen.fhdl.specials import Keep
from migen.genlib.resetsync import AsyncResetSynchronizer
from migen.actorlib.fifo import SyncFIFO
from migen.fhdl.tools import *

from mibuild.generic_platform import *

from misoclib.com.gpio import GPIOOut
from misoclib.mem.flash import spiflash
Expand All @@ -23,6 +26,7 @@
from gateware import firmware
from gateware import git_info
from gateware import platform_info
from gateware import freq_count

from targets.common import *

Expand Down Expand Up @@ -102,6 +106,7 @@ class BaseSoC(SDRAMSoC):
"dna",
"git_info",
"platform_info",
"freq_count",
)
csr_map_update(SDRAMSoC.csr_map, csr_peripherals)

Expand Down Expand Up @@ -138,6 +143,17 @@ def __init__(self, platform,
self.flash_boot_address = self.mem_map["spiflash"]+platform.gateware_size
self.register_mem("spiflash", self.mem_map["spiflash"], self.spiflash.bus, size=platform.gateware_size)

# freq_in = [("freq_in", 0, Pins("A:0"), IOStandard("LVTTL"))]
# platform.add_extension(freq_in)
# self.clock_domains.cd_inc = ClockDomain(reset_less=True)
# self.specials += Instance("BUFG", i_I=platform.request("freq_in"), o_O=self.cd_inc.clk)
#
# # Only rename source, manually connect dest b/c of Migen decoration rules.
# self.submodules.freq_count = ClockDomainsRenamer({"src" : "inc"})(freq_count.FrequencyCounter(clk_freq, 6, 32))
#
# self.comb += [self.freq_count.core.cd_dest.clk.eq(self.crg.cd_sys.clk)]
# self.comb += [self.freq_count.core.cd_dest.rst.eq(self.crg.cd_sys.rst)]


class USBSoC(BaseSoC):
csr_map = {
Expand Down
70 changes: 50 additions & 20 deletions targets/minispartan6_video.py
Original file line number Diff line number Diff line change
@@ -1,15 +1,27 @@
from migen.fhdl.std import ClockDomainsRenamer, ClockSignal, Signal, Instance

from gateware.hdmi_in import HDMIIn
from gateware.hdmi_in.edid import EDID
from gateware.hdmi_in.clocking import Clocking
from gateware.hdmi_in.datacapture import DataCapture
from gateware.hdmi_out import HDMIOut
from gateware import freq_count

from targets.common import *
from targets.minispartan6_base import default_subtarget as BaseSoC


class VideoMixerSoC(BaseSoC):
csr_peripherals = (
"hdmi_out0",
"hdmi_in0",
"hdmi_in0_edid_mem",
# "hdmi_out0",
"edid",
"edid_mem",
"clocking",
# "data0_cap",
# "data0_cap",
# "data0_cap"
# "hdmi_in0",
# "hdmi_in0_edid_mem",
)
csr_map_update(BaseSoC.csr_map, csr_peripherals)

Expand All @@ -20,25 +32,43 @@ class VideoMixerSoC(BaseSoC):

def __init__(self, platform, **kwargs):
BaseSoC.__init__(self, platform, **kwargs)
# self.submodules.hdmi_in0 = HDMIIn(
# platform.request("hdmi_in", 0),
# self.sdram.crossbar.get_master(),
# fifo_depth=1024)
self.submodules.hdmi_out0 = HDMIOut(
platform.request("hdmi_out", 0),
self.sdram.crossbar.get_master())
# self.submodules.hdmi_in0 = HDMIIn(
# platform.request("hdmi_in", 0),
# self.sdram.crossbar.get_master(),
# fifo_depth=1024)

in_pads = platform.request("hdmi_in", 0)
self.submodules.edid = EDID(in_pads)
self.submodules.clocking = Clocking(in_pads)
for datan in range(3):
pad_se = Signal()
name = "data" + str(datan)
self.specials += Instance("IBUFDS", i_I=getattr(in_pads, name + "_p"),
i_IB=getattr(in_pads, name + "_n"), o_O=pad_se)

# self.submodules.hdmi_out0 = HDMIOut(
# platform.request("hdmi_out", 0),
# self.sdram.crossbar.get_master())

# Only rename source, manually connect dest b/c of Migen decoration rules.
# self.submodules.freq_count = ClockDomainsRenamer({"src" : "pix"})(freq_count.FrequencyCounter(80*1000000, 6, 32))
self.submodules.freq_count = freq_count.FrequencyCounter(80*1000000, 6, 32)
self.comb += [self.freq_count.core.cd_src.clk.eq(self.clocking._cd_pix.clk)]
self.comb += [self.freq_count.core.cd_dest.clk.eq(self.crg.cd_sys.clk)]
self.comb += [self.freq_count.core.cd_dest.rst.eq(self.crg.cd_sys.rst)]


# FIXME: Fix the HDMI out so this can be removed.
platform.add_platform_command(
"""PIN "hdmi_out_pix_bufg.O" CLOCK_DEDICATED_ROUTE = FALSE;""")
platform.add_platform_command(
"""
NET "{pix0_clk}" TNM_NET = "GRPpix0_clk";
TIMESPEC "TSise_sucks7" = FROM "GRPpix0_clk" TO "GRPsys_clk" TIG;
TIMESPEC "TSise_sucks8" = FROM "GRPsys_clk" TO "GRPpix0_clk" TIG;
""",
pix0_clk=self.hdmi_out0.driver.clocking.cd_pix.clk,
)
# platform.add_platform_command(
# """PIN "hdmi_out_pix_bufg.O" CLOCK_DEDICATED_ROUTE = FALSE;""")
# platform.add_platform_command(
# """
# NET "{pix0_clk}" TNM_NET = "GRPpix0_clk";
# TIMESPEC "TSise_sucks7" = FROM "GRPpix0_clk" TO "GRPsys_clk" TIG;
# TIMESPEC "TSise_sucks8" = FROM "GRPsys_clk" TO "GRPpix0_clk" TIG;
# """,
# pix0_clk=self.hdmi_out0.driver.clocking.cd_pix.clk,
# )

for k, v in sorted(platform.hdmi_infos.items()):
self.add_constant(k, v)
Expand Down