# Module - Module ports can be automatically infered for signals cross multiple modules - Each module instance has its own parameters. All module instances construct a module tree, and all parameters construct a parameter tree. - configuration function is lazy evaluated and matches module id, which is the declaration name by default . ## Config ```py @conf Global(clock_period): # set timing conf.timing = Bundle( timescale = '1ns', Clock = {'low':clock_period, 'high':clock_period, 'phase':0}, Logic = {'delay': 1}, Gate = {'delay': 1}, ) # a configuration that matches "RippleCarry.*" @conf RippleCarry: w = 32 @conf KoggeStone: w = 64 AdderIO = lambda w: Bundle( x = UInt[w ](0) @ Input, y = UInt[w ](0) @ Input, out = UInt[w+1](0) @ Output) @module FullAdder: a, b, cin = UInt([0,0,0]) s = a ^ b ^ cin cout = a & b | (a ^ b) & cin @module RippleCarry: io = AdderIO(conf.p.w) adders = Array(FullAdder() for _ in range(conf.p.w)) adders[:,'a' ] <== io.x.split() adders[:,'b' ] <== io.y.split() adders[:,'cin'] <== 0, *adders[:-1,'cout'] io.out <== Cat(*adders[:,'s'], adders[-1,'cout']) @module KoggeStone: io = AdderIO(conf.p.w) P_odd = io.x ^ io.y P = P_odd.split() G = (io.x & io.y).split() dist = 1 while dist < conf.p.w: for i in reversed(range(dist,conf.p.w)): G[i] = G[i] | (P[i] & G[i-dist]) if i >= dist * 2: P[i] = P[i] & P[i-dist] dist *= 2 io.out <== Cat(0, *G) ^ P_odd ``` ## Session All signals, gates and modules should be instantiated in a `Session`, which contains the simulator and other necessary settings. ```py @task tb(self, dut, N): for _ in range(N): x, y = setr(dut.io[['x','y']]) yield self.clock_n() self.AssertEq(getv(dut.io.out), x + y) with Session(Config()) as sess: adder1, adder2 = RippleCarry(), KoggeStone() sess.track(adder1, adder2) sess.join(tb(adder1, 100), tb(adder2, 200)) sess.dumpVCD('Adders.vcd') sess.dumpVerilog('Adders.sv') ```