Created
March 21, 2016 18:17
-
-
Save cr1901/60822b6e291308919c8d to your computer and use it in GitHub Desktop.
Migen NCO Example
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
from migen import * | |
from migen.fhdl import verilog | |
import numpy as np | |
import matplotlib.pyplot as plt | |
import struct | |
class NCO(Module): | |
def __init__(self, out_width=8, depth=10, acc_out_width=24, base_freq=1000000, clk_freq=50000000): | |
self.norm_freq = base_freq/clk_freq | |
num_entries = 2**depth | |
self.specials.sin_LUT = Memory(width=out_width, depth=num_entries, init=self.fixed_point_sine(out_width, num_entries)) | |
port = self.sin_LUT.get_port() | |
self.specials += port | |
# samples_lut/rev * rev/second * seconds/clk_sample | |
samples_per_rev = 2**acc_out_width | |
revs_per_clk = base_freq/50000000 # rev/sec / clk/sec | |
inc_per_clk = revs_per_clk * samples_per_rev # revs/clk * inc/revs | |
bias = Constant(int(inc_per_clk), (acc_out_width, False)) | |
accumulator = Signal((acc_out_width, False)) | |
increment = Signal((acc_out_width, False)) | |
self.resolution = clk_freq/samples_per_rev | |
self.freq_ctl = Signal((acc_out_width, True)) | |
self.phase = Signal(depth) | |
self.output = Signal(out_width) | |
self.comb += [self.phase.eq(accumulator[(acc_out_width-depth):]), self.output.eq(port.dat_r), | |
port.adr.eq(self.phase)] | |
self.comb += [increment.eq(self.freq_ctl + bias)] | |
self.sync += [accumulator.eq(accumulator + increment)] | |
def fixed_point_sine(self, precision, out_width): | |
time = np.linspace(0, 1, out_width, endpoint=False) | |
max_val = 2**(precision - 1) | |
bias = 1/(max_val) # TODO: Try 1/(2*max_val), which the YM2612 uses and may be better. | |
float_sine = max_val*np.sin(2*np.pi*time) - bias | |
int_sine = [int(x) for x in float_sine] | |
return int_sine | |
def NCO_tb(dut, freq, inputs, outputs): | |
yield dut.freq_ctl.eq(0) | |
cycle_increment = Constant(500/dut.resolution) | |
for cycle in range(1000): | |
yield dut.freq_ctl.eq(dut.freq_ctl - cycle_increment) | |
outputs.append(struct.unpack("b", struct.pack("B", (yield dut.output)))[0] & 128) | |
yield | |
m = NCO() | |
out_signals = [] | |
tb = NCO_tb(m, 50000000, [], out_signals) | |
run_simulation(m, tb) | |
plt.plot(out_signals) | |
plt.show() | |
m = NCO() | |
print(verilog.convert(m, ios={m.freq_ctl, m.output})) | |
plt.figure() | |
plt.plot(m.fixed_point_sine(8, 1024), '-') | |
plt.show() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment