Last active
January 26, 2016 12:59
-
-
Save cfelton/50cb0fbed5f188fcc1bb to your computer and use it in GitHub Desktop.
using constants in myhdl
This file contains 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
import argparse | |
from argparse import Namespace | |
from myhdl import * | |
class Constants(object): | |
def __init__(self, **constargs): | |
# the const can contain int and str convert all to int | |
for name, const in constargs.items(): | |
assert isinstance(name, str) | |
assert isinstance(const, (int, str,)) | |
if isinstance(const, str): | |
ival = int(const.replace('_', ''), 2) | |
else: | |
ival = int(const) | |
constargs[name] = ival | |
# create a set, the set of of constants | |
self._constset = set([cc for np, cc in constargs.items()]) | |
# add the constants to the instance as attributes | |
for name, const in constargs.items(): | |
self.__dict__[name] = const | |
self._constants = constargs | |
def __len__(self): | |
return len(self._constants) | |
def __call__(self, val=0): | |
cmin, cmax = min(self._constset), max(self._constset) | |
return intbv(val, min=cmin, max=cmax+1) | |
# global constant used | |
CPUMODES = Constants(user=0b10000, fiq=0b10001, irq=0b10010) | |
def enum_cpumodes(modes): | |
num = 0 | |
if modes == CPUMODES.user: | |
num = 1 | |
elif modes == CPUMODES.fiq: | |
num = 2 | |
elif modes == CPUMODES.irq: | |
num = 3 | |
return num | |
def mymodes_function(modes, modeenum): | |
@always_comb | |
def beh_encode(): | |
modeenum.next = enum_cpumodes(modes) | |
return beh_encode | |
def mymodes_module(modes, modeenum): | |
@always_comb | |
def beh_encode(): | |
if modes == CPUMODES.user: | |
modeenum.next = 1 | |
elif modes == CPUMODES.fiq: | |
modeenum.next = 2 | |
elif modes == CPUMODES.irq: | |
modeenum.next = 3 | |
return beh_encode | |
def constant_top(clock, next_mode, sel, modeenum, args): | |
modes = [Signal(CPUMODES(CPUMODES.user)) | |
for _ in range(2)] | |
@always(clock.posedge) | |
def beh_mode_change(): | |
if next_mode: | |
if modes[sel] == CPUMODES.user: | |
modes[sel].next = CPUMODES.fiq | |
elif modes[sel] == CPUMODES.fiq: | |
modes[sel].next = CPUMODES.irq | |
elif modes[sel] == CPUMODES.irq: | |
modes[sel].next = CPUMODES.user | |
moe = [Signal(intbv(0, min=0, max=len(CPUMODES)+1)) | |
for _ in range(2)] | |
enum_inst = [None, None] | |
for ii in range(2): | |
if args.use_func: | |
enum_inst[ii] = mymodes_function(modes[ii], moe[ii]) | |
else: | |
enum_inst[ii] = mymodes_module(modes[ii], moe[ii]) | |
@always_comb | |
def beh_select(): | |
modeenum.next = moe[sel] | |
return beh_mode_change, enum_inst, beh_select | |
def check_modeenum(clock, modeenum, next_mode, sel): | |
yield clock.posedge | |
assert modeenum == 1 | |
yield clock.posedge | |
next_mode.next = True | |
yield clock.posedge | |
next_mode.next = False | |
yield clock.posedge | |
assert modeenum == 2 | |
yield clock.posedge | |
sel.next = 1 | |
yield clock.posedge | |
yield clock.posedge | |
assert modeenum == 1 | |
def test_func(args=None): | |
if args is None: | |
args = Namespace(convert=False, trace=True, use_func=True) | |
clock = Signal(bool(0)) | |
sel = Signal(bool(0)) | |
next_mode = Signal(bool(0)) | |
modeenum = Signal(intbv(0, min=0, max=len(CPUMODES)+1)) | |
def bench_func(): | |
tbdut = constant_top(clock, next_mode, sel, modeenum, args=args) | |
@always(delay(5)) | |
def tbclk(): | |
clock.next = not clock | |
@instance | |
def tbstim(): | |
yield check_modeenum(clock, modeenum, next_mode, sel) | |
raise StopSimulation | |
return tbdut, tbclk, tbstim | |
if args.trace: | |
g = traceSignals(bench_func) | |
else: | |
g = bench_func() | |
Simulation(g).run() | |
if args.convert: | |
toVerilog(constant_top, clock, next_mode, sel, modeenum, args=args) | |
toVHDL(constant_top, clock, next_mode, sel, modeenum, args=args) | |
def test_module(args=None): | |
if args is None: | |
args = Namespace(convert=False, trace=True, use_func=False) | |
clock = Signal(bool(0)) | |
sel = Signal(bool(0)) | |
next_mode = Signal(bool(0)) | |
modeenum = Signal(intbv(0, min=0, max=len(CPUMODES)+1)) | |
def bench_mod(): | |
tbdut = constant_top(clock, next_mode, sel, modeenum, args=args) | |
@always(delay(5)) | |
def tbclk(): | |
clock.next = not clock | |
@instance | |
def tbstim(): | |
yield check_modeenum(clock, modeenum, next_mode, sel) | |
raise StopSimulation | |
return tbdut, tbclk, tbstim | |
if args.trace: | |
g = traceSignals(bench_mod) | |
else: | |
g = bench_mod() | |
Simulation(g).run() | |
if args.convert: | |
toVerilog(constant_top, clock, next_mode, sel, modeenum, args=args) | |
toVHDL(constant_top, clock, next_mode, sel, modeenum, args=args) | |
def convert(): | |
modes = Signal(CPUMODES(CPUMODES.user)) | |
modeenum = Signal(intbv(0, min=0, max=len(CPUMODES)+1)) | |
toVHDL(mymodes_module, modes, modeenum) | |
def get_cli_args(): | |
parser = argparse.ArgumentParser() | |
# @todo: finish | |
if __name__ == '__main__': | |
test_func() | |
test_module() | |
@cfelton I like that solution as well ;)
Awesome. I really like this solution. Next thing would be to add it to the official sources ;)
Updated to use two tests that both create VCD files.
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
@josyb I updated it before I saw your comment to use
**kwargs
I think I did it the first way because the OP mentioned something like it ...