-
Notifications
You must be signed in to change notification settings - Fork 1
02_FSM_parte 2
Basándonos en el paper, Syntesizable Finite State Machine Design Techniques Using the New System Verilog 3.0 Enhnancements" SNUG-2003 San JOse,CA Voted Best Paper 2nd Place (Clifford E.Cummings Sunburst Design, Inc)... vamos a intentar resumir y explicar como realizar FSM sintetizables de forma adecuada.
- Realizar un módulo por cada diseño FSM
- Usa parameter(locales) para definir los estados en vez de `define(globales), hay que pensar muy bien si se debe usar una constante de forma global.
Si tienes varios FSM que usan los mismos nombres para definir los estados y se han creado usando `define creando una definición global, este puede inducir fácilmente a errores.
Podemos ver en la siguiente figura la forma inadecuada del uso de define usado en dos máquinas FSM distintas:
La forma correcta sería:
-
Declarar state,next después de asignar los parámetros, algunas herramientas de optimización necesitan tener las asignaciones de los parámetros antes de declarar state y next ( actual y siguiente )
-
Todos los bloques always secuenciales (con reloj), deben usar asignaciones nonblocking <=
-
Todos los bloques always combinacionales (usa una lista sensible de señales sin reloj), deben usar asignaciones blocking = Estas últimas dos guías ayudarán a evitar race conditions
Tomando la siguiente máquina de estados, vamos a mostrar las distintas formas de codificación que se pueden aplicar:
Figura 1. FSM
En este ejemplo se define una máquina de 4 estados con una señal asíncrona de reset (a nivel bajo) rst_n, una señal de reloj clk, dos señales de entrada go y ws (wait state) y dos señales de salida rd (read) y ds (done strobe). Si no se indica, por defecto, rd=0 y ds=0.
En la siguiente figura podemos ver un diagrama de bloques Moore:
Vemos que tenemos dos bloques combinacionales y uno secuencial.
Una de las posibles formas de codificar la máquina de estados es usar solo dos bloques always:
- Un always secuencial(captura el estado siguiente y lo transforma en el estado actual)
- Un always en el cual se unen los dos bloques combinacionales (cálculo del estado lógico y cálculo de las salidas).
El módulo en verilog para codificar dicha máquina de estados sería:
module fsm_estiloA(output reg rd,ds,
input go,ws,clk,rst_n);
parameter IDLE = 2'b00,
READ = 2'b01,
DLY = 2'b11,
DONE = 2'b10;
reg[1:0] state,next;
// Bloque secuencial. Biestables que se encargarán de memorizar el estado en el que nos encontramos
//*************************************************************************************************
always @(posedge clk or negedge rst_n)
if(!rst_n) state <=IDLE;
else state <=next;
// Bloque combinacional. Juntamos los dos bloques combinacionales en un único bloque always
//******************************************************************************************
always @(state or go or ws) begin
next = 'bx; //por defecto
rd = 1'b0;
ds = 1'b0;
case (state)
IDLE: if (go) next = READ; //para cada estado definimos tanto las salidas como el próximo estado
else next = IDLE;
READ:begin
rd=1'b1;
next = DLY;
end
DLY: begin
rd=1'b1;
if(!ws) next = DONE;
else next = READ;
end
DONE:begin
ds=1'b1;
next = IDLE;
end
endcase
end
endmodule
Podemos simular y ver la síntesis de dicha máquina secuencial de forma fácil copiando el módulo en la siguiente página web y darle a simular y sintetizar:
Obtendremos:
pinchando sobre las varilables de entrada podremos ver el resultado que se obtiene en la salidas. Si nos colocamos con el ratón sobre alguno de los cables como por ejemplo el de state nos irá apareciendo en binario el valor del estado actual. Por otra parte nos muestra la síntesis realizada con Yosis.
Podemos crear un módulo en Icestudio añadiendo el código en un bloque de código de Icestudio y así obtener un módulo que estará formado por la máquina de estados deseada.
Notas:
- El bloque combinacional always está formado por una lista sensible a cambios sobre la variable state y todas las entradas posibles que tiene afectan a dicho módulo ( no nos podemos dejar ninguna fuera de la lista de sensibilidad al cambio).
- En el bloque combinacional always al inicio del bloque se asigna un valor por defecto a la variable next, de igual forma, al inicio antes del case se asignan valores por defecto para las salidas ( esto, elimina la creación de latches y reduce la cantidad de código requerido para codificar las salidas en el case ). Otra forma de hacer esto sería usando **default: ** en el case.
- En los estados donde el valor de salida no toma el valor por defecto ( puesto al inicio del always antes del case ), la asignación del valor de salida se pone una única vez por cada estado.
- Para una códificación clara, se alinean todos los next en una columna.
Un truco común que se usa en todas las codificaciones de FSM es poner como defecto a la variable next ='bx justo debajo de la lista de sensibilidad del bloque always. X's ayuda a debugear el sistema durante una simulación. Asignación X ayuda a resaltar errores en la simulación porque si olvidas hacer alguna asignación next en algún lugar del bloque combinacional always, la variable de estado next se mostrará con valor X's en todos los puntos donde la asignación se te ha olvidado (por ejemplo si en una de las opciones del case no se ha añadido ningún valor a next cuando entre a ese estado se mostrará el valor de next=xx y eso significaría que para ese estado no se ha codificado valor para next).