Skip to content

Instantly share code, notes, and snippets.

@cr1901
Created March 21, 2016 18:17
Show Gist options
  • Save cr1901/60822b6e291308919c8d to your computer and use it in GitHub Desktop.
Save cr1901/60822b6e291308919c8d to your computer and use it in GitHub Desktop.
Migen NCO Example
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