Lab: Lógica Sequencial
Lab |
---|
Entregue o código pelo repositório do Classroom |
💰 Laboratório com pontos
Pode ser feito em dupla!
Warning
O laboratório só pode ser realizado com FPGA.
Começando
Agora vamos ver como implementamos uma lógica sequencia em MyHDL! Até agora temos utilizado o decorator
: @always_comb
para indicar que uma função deve ser interpretada como um trecho combinacional:
@always_comb
def comb():
led.next = l
Agora vamos começar usar um novo decorator
(@always_seq
) para indicar que uma função deve ser sequencial e depender do clock
e do reset
. O módulo a seguir demonstra como implementar um flip-flop tipo D em MyHDL:
@block
def dff(q, d, clk, rst):
@always_seq(clk.posedge, reset=rst)
def seq():
q.next = d
return instances()
Notem que estamos usando @always_seq(clk.posedge, reset=rst)
, e indicando que o módulo deve ser acionado na borda de subida do sinal clk
e que o sinal de reset
deve ser o rst
.
Podemos interpretar o def seq()
da seguinte maneira: Sempre que o sinal clock variar de 0
para 1
a função é acionada e então a saída q
recebe a entrada d
. Podemos visualizar isso como um while True:
while True:
q.next = d
time.sleep(1/CLOCK)
Para todas as tarefas sigam o fluxo a seguir:
make toplevel.rbf
- Programe a FPGA
- Teste e obeserve se o resultado é o esperado.
dff - FlipFlop tipo D
Exercise
Aplicando
Com a possibilidade de executarmos uma acão por clock, conseguimos realizar tarefas que não eram possíveis antes como por exemplo contar eventos.
Exercise
Clock
Os dois módulos anteriores foram realizados utilizando o botão 0 (key_s[0]
) como sinal de clock para o nosso módulo, mas isso não é o jeito certo de trabalharmos com lógica sequência. O cenário correto, seria de usar um clock gerado em hardware e não pelo botão. A partir de agora iremos usar na entrada do clock o sinal CLOCK_50
que é um clock de 50Mhz gerado pela placa. Notem que 50Mhz
significa 50 000 000
vezes por segundo! Isso parece muito né? Mas, dependendo do projeto, podemos elevar o clock para 200Mhz ou usar FPGAs mais rápidas que chegam próximo do 1GHz.
Piscando o LED
Agora com o uso da lógica sequencial conseguimos contar 'tempo' e gerar eventos em determinado momento. Ou seja: podemos contar 0.5 segundos e mudar o valor do led (usando como base o nosso clock que é um valor fixo), contar mais 0.5 s e mudar novamente (fazer o famoso pisca led). Para isso, teremos que conseguir contar eventos de clock, e quando o valor chegar em 25 000 000 inverter o valor do LED e zerar o contador e ficar nesse loop para sempre.
Podemos usar o nosso adder
do lab anterior como módulo de contador, conectando a saída do adder
na entrada x
, mas passando por um registrador antes (para apenas mudar a cada clock). A entrada y
será conectado ao valor 1
, como resultado teremos: s = x + 1
. A expressão será executada a cada subida do clock. E x
será:
if s < MAX:
x.next = s
else:
x.next = 0
Se o valor de s
for menor que o valor máximo (define a velocidade que o LED irá piscar) copiamos a saída do somador para a entrada, e se o valor MAX
for atingido, iremos zerar o somador, para começarmos novamente. O HW que queremos gerar é algo como:
A ideia de piscar o LED é que temos que mudar uma variável a cada ciclo do contador.
----------- -------------
| | | Status
| | |
----------- ----------
_ 25000000 _ _
/ | / | / |
/ | / | / | Contador
/ | / | / |
/ |/ | / |
A implementação em MyHDL fica:
@block
def blinkLed(led, clk, rst):
cnt = Signal(intbv(0)[32:])
l = Signal(bool(0))
@always_seq(clk.posedge, reset=rst)
def seq():
if cnt < 25000000:
cnt.next = cnt + 1
else:
cnt.next = 0
l.next = not l
@always_comb
def comb():
led.next = l
return instances()
Alguns detalhes devem ser levados em consideração na implementação do componente:
- O
seq
acontece a cada mudança do clock - O
comb
acontece sempre - Não podemos
ler
uma saída - Em hardware as coisas acontecem ao mesmo tempo!
E então atribuímos o valor de l
para a saída led
na parte combinacional do módulo:
def comb():
led.next = l
Essa atribuição poderia ser feita dentro da parte sequencial do componente:
@always_seq(clk.posedge, reset=rst)
def seq():
if cnt < 25000000:
cnt.next = cnt + 1
else:
cnt.next = 0
l.next = not l
led.next = l
Exercise
Exercise
Answer
- 32 bits = 4294967296
- al/50M = 85s ! (maior tempo entre piscada dos leds)
Faz diferença sim! Quando mais bits, mais registradores temos que usar e maior ficar o hardware.
Poderíamos dimensionar o tamanho do vetor de acordo com o time_ms
que foi passado para o módulo.
Exercise
Exercise
Exercise
Exercise