MyHDL, de Python al silicio

img/Afiche.png
por Martín Gaitán

PyDay Córdoba 2011


img/by-sa.svg

El desafío

A modo de intro: Dónde estamos?

img/esta_aqui.jpg

Software? No era hardware?

La burocracia del Hardware

img/flow.jpg

Un workflow más pythonico

img/flow.jpg

Y qué corno es MyHDL ?

img/myhdl_logo_256.png

Un multiplexor en VHDL: The hard way

img/mux.png
library ieee ;
use ieee . std logic 1164 . all ;

entity mux is
    port (
    a, b : in std logic vector (3 downto 0);
    s : in std logic ;
    o : out std logic vector (3 downto 0));
end mux;
architecture behavior of mux is
begin  behavior
    o <= a when s = '0' else b;
end behavior

Myhdl's way

img/mux.png
def mux(s, o, a, b):
 """2-channels N-bits multiplexor

 a, b: generic bits input channels
 o: output vector
 s: channel selector"""

 @always_comb
 def logic():
     if s == 0:
         o.next = a
     else:
         o.next = b
 return logic

Ok, pero explicalo

Bueno, enchufemos!

>>> val = intbv(1, min=0, max=15)
>>> len(val)
4
>>> bus = Signal(val)

Ahora sí, enchufemos!

def testBench():

I0, I1 = [Signal(intbv(random.randint(0, 255))[32:]) for i in range(2)]
O = Signal(intbv(0)[32:])
S = Signal(intbv(0, min=0, max=2))

mux_inst = mux (S, O, I0, I1)

@instance
def stimulus():
    header =  "%-6s|%-6s|%-6s|%-6s|%-6s" % ('time', 'I0', 'I1', 'S', 'O')
    print header + '\n' + '-' * len(header)
    while True:
        S.next = intbv(random.randint(0, 1))[1:]
        I0.next, I1.next = [intbv(random.randint(0, 255))[32:] for i in range(2)]
        print "%-6s|%-6s|%-6s|%-6s|%-6s" % (now(), I0, I1, S, O)
        yield delay(5)

return mux_inst, stimulus

Y simulemos!

sim = Simulation(testBench())
sim.run(20)
time  |I0    |I1    |S     |O
----------------------------------
0     |35    |96    |0     |0
5     |164   |254   |1     |254
10    |132   |60    |0     |132
15    |32    |138   |0     |32
20    |15    |112   |1     |112
<class 'myhdl._SuspendSimulation'>: Simulated 20 timesteps

Entonces se verifica con prints?

tb_4_sim = traceSignals(testBench)
sim = Simulation(tb_4_sim)
sim.run(20)

Pero mejor es hacer test de verdad!

class MuxTest(unittest.TestCase):

    def setUp(self):
        self.channels = [Signal(intbv(random.randint(0, 255))[32:]) for i in range(2)]
        self.O = Signal(intbv(0)[32:])
        self.S = Signal(intbv(0, min=0, max=2))
        self.mux_inst = mux(self.S, self.O, self.channels[0], self.channels[1])

    def test_starts_in_channel_0(self):
        yield delay(1)
        Simulation( self.mux_inst )
        self.assertEqual(self.channels[0].val, self.O.val)

    def test_channel_1_when_select_is_1(self):
        self.S.next = intbv(1)
        yield delay(1)
        Simulation( self.mux_inst )
        self.assertEqual(self.channels[1].val, self.O.val)

Convirtiendo pa'sintetizar

mux_inst = toVHDL(mux, S, O, I0, I1)
mux_inst = toVerilog(mux, S, O, I0, I1)

Conclusiones

Preguntas ?

for p in preguntas:
    try:
        responder(p)
    except NiPutaIdea:
        sonreir_y_hacerse_el_gil()

La hora referí