Skip to content

Instantly share code, notes, and snippets.

@cfelton
Last active May 11, 2017 06:38
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save cfelton/4de2b1e93dd7418f56e4 to your computer and use it in GitHub Desktop.
Save cfelton/4de2b1e93dd7418f56e4 to your computer and use it in GitHub Desktop.
Code snips for http://www.fpgarelated.com/showarticle/25.php, see the link for description
from myhdl import Signal, intbv, always_seq
def shift_reg(clock, reset, y):
shift = Signal(intbv(0)[len(y):])
mask = shift.max - 1
@always_seq(clock.posedge, reset=reset)
def beh_shift():
if y == 0:
y.next = 1
else:
y.next = (y << 1) & mask
return beh_shift
def verify(clock, led, clock_frequency, led_rate, numled, numdumb):
cnt, numclk = 0, int(clock_frequency*led_rate)
nloops, direction = 30000, 'wait'
ledlsb, ledmsb = 1, 1 << len(led)
led_last = led.val
for ii in range(nloops):
yield clock.posedge
cnt += 1
if direction == 'wait':
if (led & ledmsb) == ledmsb:
direction = 'right'
led_last = led.val
elif (led & ledlsb) == ledlsb:
direction = 'left'
led_last = led.val
elif led == 0:
direction = 'wait'
if led != led_last:
if direction == 'right':
assert led_last>>1 == led.val, \
"{:x} != {:x}".format(led, led_last)
elif direction == 'left':
assert led_last<<1 == led.val, \
"{:x} != {:x}".format(led, led_last)
assert cnt == numclk
cnt = 0
from myhdl import always_seq
def led_stroby(
# ~~~[Ports]~~~
clock, # input: system sync clock
led, # output: to IO ports drive LEDs
reset=None, # input: reset, many boards don't have reset
# ~~~[Parameters]~~~
clock_frequency=48e6, # clock frequency
led_rate=333e-3, # strobe change rate of 333ms
num_dumb=4, # The number of dummy LEDS on each side
):
# empty module, it is good practice to create the test first
# and use the empty module to verify the test fails, this
# stub contains the myhdl generator but doesn't implement
# any of the logic.
@always_seq(clock.posedge, reset=reset)
def beh_stroby():
led.next = 0
return beh_stroby
from myhdl import Signal, intbv, always_seq, always_comb
def led_stroby(
# ~~~[Ports]~~~
clock, # input : system sync clock
led, # output : to IO ports drive LEDs
reset=None, # input : reset
# ~~~[Parameters]~~~
clock_frequency=48e6, # clock frequency
led_rate=333e-3, # strobe change rate of 333ms
num_dumb=4, # The number of dummy LEDS on each side
):
# Number of LEDs
led_bank = len(led)
# Need to calculate some constants. Want the value to
# be an integer (non-fractional value only whole number)
cnt_max = int(clock_frequency * led_rate)
# Some useful definitions
mb = led_bank + 2*num_dumb
lsb, msb = 0, mb-1
msb_reverse_val = (1 << mb-2)
lsb_reverse_val = 2
# Declare the internal Signals in our design
led_bit_mem = Signal(intbv(1)[mb:])
left_not_right = Signal(True)
clk_cnt = Signal(intbv(0, min=0, max=cnt_max))
strobe = Signal(False)
@always_seq(clock.posedge, reset=reset)
def beh_strobe():
# Generate the strobe event, use the "greater
# than" for initial condition cases. Count the
# number of clock ticks that equals the LED strobe rate
if clk_cnt >= cnt_max-1:
clk_cnt.next = 0
strobe.next = True
else:
clk_cnt.next = clk_cnt + 1
strobe.next = False
# Describe the strobing, note the following always
# changes direction and "resets" when either the lsb
# or msb is set. This handles our initial condition
# as well.
if strobe:
if led_bit_mem[msb]:
led_bit_mem.next = msb_reverse_val
left_not_right.next = False
elif led_bit_mem[lsb]:
led_bit_mem.next = lsb_reverse_val
left_not_right.next = True
else:
if left_not_right:
led_bit_mem.next = led_bit_mem << 1
else:
led_bit_mem.next = led_bit_mem >> 1
@always_comb
def beh_map_output():
led.next = led_bit_mem[led_bank+num_dumb:num_dumb]
return beh_strobe, beh_map_output
import random
import argparse
import myhdl
from myhdl import *
try:
from rhea.build import get_board
build_package_available = True
except:
build_package_available = False
from fpga25_snip4 import led_stroby
from test_stroby import verify, test_random
def convert(args):
myhdl.toVerilog(led_stroby, clock, leds, reset,
clock_frequency, led_rate, num_dumb)
myhdl.toVHDL(led_stroby, clock, leds, reset,
clock_frequency, led_rate, num_dumb)
def build(args):
if build_package_available:
brd = get_board(args.board)
flow = brd.get_flow(top=led_stroby)
flow.run()
def cliargs():
parser = argparse.ArgumentParser()
parser.add_argument('-N', type=int, default=1,
help="number of loops to test")
parser.add_argument('--trace', action='store_true', default=False,
help="enable tracing in the testbench")
parser.add_argument('--convert', action='store_true', default=False,
help="convert the design under test")
parser.add_argument('--build', action='store_true', default=False,
help="attempt to invoke FPGA tools")
parser.add_argument('--board',
choices=('sx1', 'ufo400', 'de0nano', 'zybo',
'atlys', 'xula', 'xula2', 'cat'),
help="FPGA development board selection")
args = parser.parse_args()
return args
def main():
args = cliargs()
# tests are always run before conversion / build
for ii in range(args.N):
test_random()
if args.convert:
convert(args)
if args.build:
build(args)
if __name__ == '__main__':
main()
from __future__ import print_function
import myhdl
from myhdl import (Signal, ResetSignal, intbv, always, instance,
delay, StopSimulation)
from fpga25_snip1 import shift_reg
def test():
clock = Signal(bool(0))
reset = ResetSignal(0, active=1, async=False)
y = Signal(intbv(1)[4:])
def bench():
tbdut = myhdl.traceSignals(shift_reg, clock, reset, y)
@always(delay(1))
def tbclk():
clock.next = not clock
@instance
def tbstim():
reset.next = True
yield delay(2)
reset.next = False
for ii in range(4):
yield clock.negedge
print("{:3d} {}".format(myhdl.now(), myhdl.bin(y, 4)))
raise StopSimulation
return tbdut, tbclk, tbstim
myhdl.Simulation(bench()).run()
if __name__ == '__main__':
test()
from __future__ import print_function, division
import random
import myhdl
from myhdl import (Signal, ResetSignal, intbv, always,
instance, delay, StopSimulation)
# replace the following with from stroby import led_stroby
from fpga25_snip4 import led_stroby
def verify(clock, led, clock_frequency, led_rate):
cnt, numclk = 0, int(clock_frequency*led_rate)
nloops, direction = 30000, 'wait'
ledlsb, ledmsb = 1, 1 << len(led)
led_last = led.val
for ii in range(nloops):
yield clock.posedge
cnt += 1
if direction == 'wait':
if (led & ledmsb) == ledmsb:
direction = 'right'
led_last = led.val
elif (led & ledlsb) == ledlsb:
direction = 'left'
led_last = led.val
elif led == 0:
direction = 'wait'
if led != led_last:
if direction == 'right':
assert led_last >> 1 == led.val, \
"{:x} != {:x}".format(led, led_last)
elif direction == 'left':
assert led_last << 1 == led.val, \
"{:x} != {:x}".format(led, led_last)
assert cnt == numclk
cnt = 0
def test_random():
clock_frequency = random.randint(20, 5000)
led_rate = random.randrange(2, 10)/10
num_led = random.randint(2, 64)
num_dumb = random.randint(1, 16)
clock = Signal(False)
reset = ResetSignal(0, active=0, async=True)
leds = Signal(intbv(0)[num_led:])
print("Testing: clock frequency {}, # leds {}, # dumb (pad) {}".format(
clock_frequency, num_led, num_dumb))
def bench():
tbdut = led_stroby(clock, leds, reset, clock_frequency,
led_rate, num_dumb)
# note the following delay is generic, it is simply the number
# of simulation ticks. In this simulation the sim ticks are
# not defined to an absolute physical time unit.
@always(delay(5))
def tbclk():
clock.next = not clock
@instance
def tbstim():
reset.next = reset.active
yield delay(100)
reset.next = not reset.active
yield verify(clock, leds, clock_frequency, led_rate)
print("Test passed")
raise StopSimulation
return tbdut, tbclk, tbstim
# run the simulaiton and create a waveform dumpy file
myhdl.Simulation(myhdl.traceSignals(bench)).run()
myhdl.toVerilog(led_stroby, clock, leds, reset,
clock_frequency, led_rate, num_dumb)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment