[myhdl-list] Simplifying Interfaces
Brought to you by:
jandecaluwe
From: Christopher F. <chr...@gm...> - 2012-06-20 03:37:20
|
In one of the MEP-107 threads we had been discussing the current support of attribute conversion. It was pointed out by Oscar that attributes will convert fine as long as a local reference is made. This was interesting because it provides a means with the current release to use objects to simplify interfaces. At first I thought this would be restrictive in the sense that the attributes would only be an intermediate reference, something like the following: In [2]: def top(clock, reset): ...: x,y,z = [Signal(False) for ii in range(3)] ...: class bucket(): pass ...: bb = bucket() ...: bb.x = x ...: bb.y = y ...: bb.z = z ...: g1 = some_module(clock, reset, bb) ...: return g1 ...: In [3]: def some_module(clock, reset, bb): ...: x = bb.x ...: y = bb.y ...: z = bb.z ...: @always(clock.posedge) ...: def hdl(): ...: if not reset: ...: z.next = False ...: else: ...: z.next = x or y ...: return hdl Which converts to the following ... always @(posedge clock) begin: TOP_G1_HDL if ((!reset)) begin z <= 1'b0; end else begin z <= (x || y); end end What I found interesting was the fact that you do not need to start with the individual signals and reference through attributes. The conversion will work in the following case as well. In [11]: def top2(clock, reset): ...: class bucket(): ...: def __init__(self): ...: self.x = Signal(False) ...: self.y = Signal(False) ...: self.z = Signal(False) ...: bb = bucket() ...: g1 = some_module(clock, reset, bb) ...: return g1 The above will convert to always @(posedge clock) begin: TOP2_G1_HDL if ((!reset)) begin g1_z <= 1'b0; end else begin g1_z <= (g1_x || g1_y); end end There doesn't seem to be any restriction in the use of attributes other than they need to be locally referenced (with the current release and development branch). I created a larger example using an embedded bus, wishbone. Using a similar technique you can simplify the interfaces between modules. This example is functional but incomplete. I had a little bit of time and implemented but time was limited and didn't even take the time to look at the wishbone spec (it has been a while since I last used wishbone). There could be some inaccuracies. Using this approach, which is fully supported by conversion with today's releases, a couple simplifications (imo) were achieved. First, the interface was simplified and generalized. As discussed only a single reference was passed to a module. All the signals were encapsulated by the reference. def gpio(wb, out, NumOutputs=1): """Very simple memory mapped peripheral""" Second, now the embedded bus can be very modular. In this case the peripheral doesn't know or care what bus is actually used. In the peripheral it simply requests the registers it needs. This works for basic rw (control) and ro (status) registers (although the current example only uses rw). The ridiculously simple gpio is: def gpio(wb, out, NumInputs=0, NumOutputs=1): """Very simple memory mapped peripheral""" rin = Signal(intbv(0)[8:]) rout = Signal(intbv(0)[8:]) wbdev = wb.AddDevice(Name="GPIO") iReg = wb.AddDeviceRegister(rin, rout, wbdev) @always_comb def hdl_assigns(): out.next = rout[0] return iReg, hdl_assigns The above should probably be changed to have a AddDeviceRwRegister(...) and AddDeviceRoRegister(...). As mentioned, the bus referenced passed could be any bus protocol because the actual bus interfacing is part of the generators in the bus object. The top-level looks something like the following def simple_top(clock, reset, buttons, leds): wb = Wishbone(DataWidth=8, AddressWidth=16) iController = buttons2bus(clock, reset, wb, buttons) outs = [Signal(False) for ii in range(len(leds))] iGpios = [None for ii in range(len(leds))] for ii in range(len(leds)): iGpios[ii] = gpio(wb, outs[ii]) iBus = wb.DeviceBusses() print(wb.Summary()) return iController, iGpios, iBus, hdl_assigns The complete example can be found here https://bitbucket.org/cfelton/examples/src/tip/simple The main file is the simple.py file and the bus is implemented in the wishbone.py. This example is *silly*. It has buttons as inputs and leds as outputs. If a button is pressed it will create a bus access to a gpio (one module per led) and toggle the led. The example was simple to verify (limited inputs and outputs) and I can test it on actual hardware. Feedback and comments welcomed. Chris Felton |