You are on page 1of 13

Personal

Open source

Business

Explore

Pricing

Blog

Support

This repository

Obijuan / open-fpga-verilog-tutorial
Code

Issues 0

Pull requests 0

Search

Watch
Wiki

Pulse

Sign in

13

Star

31

Sign up

Fork

15

Graphs

Captulo 27: Memoria ROM genrica


Testato edited this page Feb 21, 2016 27 revisions

Pages 40

Inicio (EN)

Captulos

Ejemplos de este captulo en github

Introduccin
Las memorias son elementos muy comunes, que usaremos mucho en nuestros diseos. En vez
de estar haciendo memorias con un tamao determinado, es ms verstil crear una memoria
genrica cuyos parmetros de longitud de datos y de direcciones se establezcan al instanciarlas.
Crearemos una memoria rom genrica y la utilizaremos en dos ejemplo: uno para reproducir una
secuencia de luces en los leds y otro para tocar una meloda: la marcha imperial

Memoria rom paramtrica

0 You are leaving the privative


sector (EN)
1 Hola mundo! (EN)
2 De un bit a datos (EN)
3 Puerta NOT (EN)
4 Contador de 26 bits (EN)
5 Prescaler de N bits (EN)
6 Mltiples prescalers
7 Contador de 4 bits con prescaler
8 Registro de 4 bits
9 Inicializador
10 Registro de desplazamiento
11 Multiplexor de 2 a 1
12 Multiplexor de M a 1
13 Inicializando registros
14 Registro de N bits con reset
sncrono
15 Divisor de frecuencias
16 Contador de segundos
17 Generando tonos audibles
18 Tocando notas
19 Secuenciando notas
20 Comunicaciones serie
asncronas
21 Baudios y transmisin
22 Reglas de diseo sncrono
23 Controladores y autmatas
finitos
24 Unidad de transmisin serie
asncrona
25 Unidad de recepcin serie
asncrona
26 Memoria ROM
27 Memoria ROM genrica
28 Memoria RAM
29 Puertas triestado
30 Hacia el microprocesador y ms
all
Clone this wiki locally

La memoria rom genrica la denominaremos genrom

Parmetros

https://github.com/Obijuan/open-fpga-verilog-tutor

Clone in Desktop

Tiene 3 parmetros que se asignan al instanciarse la rom:

converted by Web2PDFConvert.com

DW (Data width): Anchura de los datos (en bits)


AW (Address width): Anchura de las direcciones (en bits)
ROMFILE: Fichero con el contenido de la rom

Puertos
Los puertos de la rom son los clsicos, pero ahora su tamao no est especificado:

Addr: Bus de direcciones


data: Bus de datos
clk: Reloj del sistema

genrom.v: Descripcin en Verilog


Puesto que los puertos (addr y data) son genricos, y por tanto se tienen que definir al declarar el
mdulo, es necesario primero definir los parmetros AW y DW. Luego, en funcin de ellos se definen
los puertos. Esto se codifica en verilog con esta estructura:

module nombre #(definicin de parametros) (definicion de puertos);


El cdigo verilog de la memoria rom genrica es:

converted by Web2PDFConvert.com

//-- Fichero: genrom.v


module genrom #(
//-- Parametros
parameter AW = 5, //-- Bits de las direcciones (Adress width)
parameter DW = 4) //-- Bits de los datos (Data witdh)
(

//-- Puertos
input clk,
//-- Seal de reloj global
input wire [AW-1: 0] addr, //-- Direcciones
output reg [DW-1: 0] data); //-- Dato de salida

//-- Parametro: Nombre del fichero con el contenido de la ROM


parameter ROMFILE = "rom1.list";
//-- Calcular el numero de posiciones totales de memoria
localparam NPOS = 2 ** AW;
//-- Memoria
reg [DW-1: 0] rom [0: NPOS-1];
//-- Lectura de la memoria
always @(posedge clk) begin
data <= rom[addr];
end
//-- Cargar en la memoria el fichero ROMFILE
//-- Los valores deben estan dados en hexadecimal
initial begin
$readmemh(ROMFILE, rom);
end
endmodule

El tercer parmetro, ROMFILE, se define de la manera habitual, usando la palabra clave parameter
dentro del mdulo. Dentro de #() slo se definen los parmetros que afectan a los puertos

Instanciando la rom en nuestros diseos


La mejor manera de utilizar la rom genrica en nuestros diseos es volviendo a definir los
parmetros AW y DW (aunque se pueden usar otros nombres) usando como valores los que
necesitemos en nuestro diseo:
parameter AW = 5;
parameter DW = 5;

Ahora declaramos los cables que van conectados a la rom genrica en funcin de estos
parmetros:
reg [AW-1: 0] addr; //-- Bus de direcciones
reg [DW-1: 0] data; //-- Bus de datos

y finalmente instanciamos la rom:


genrom
#( .ROMFILE(ROMFILE), //-- Asignacion de parametros
.AW(AW),
.DW(DW))
ROM (
//-- coneion de cables
.clk(clk),
.addr(addr),
.data(data)
);

converted by Web2PDFConvert.com

Ejemplo 1: secuencia en los leds


En este ejemplo reproduciremos una secuencia en los leds, igual que en los ejemplos del captulo
anterior, pero usando una rom genrica

Diagrama de bloques
Utilizaremos 5 leds para la secuencia, por lo que la anchura de los datos ser de 5 bits (DW = 5),
y una anchura de direcciones tambin de 5 bits (AW = 5, para tener 32 posiciones). La secuencia
es un contador. En cada posicin de la memoria se almacena su nmero de direccin

genromleds.v: Descripcin en verilog


La descripcin en verilog del ejemplo es:

converted by Web2PDFConvert.com

//-- Fichero: genromleds.v


`default_nettype none
`include "divider.vh"
module genromleds (input wire clk,
output wire [4:0] leds);
//- Tiempo de envio
parameter DELAY = `T_500ms;
//-- Fichero con la rom
parameter ROMFILE = "rom1.list";
//-- Numero de bits de la direccione
parameter AW = 5;
parameter DW = 5;
//-- Cable para direccionar la memoria
reg [AW-1: 0] addr;
reg rstn = 0;
wire clk_delay;
//-- Instanciar la memoria rom
genrom
#( .ROMFILE(ROMFILE),
.AW(AW),
.DW(DW))
ROM (
.clk(clk),
.addr(addr),
.data(leds)
);
//-- Contador
always @(negedge clk)
if (rstn == 0)
addr <= 0;
else if (clk_delay)
addr <= addr + 1;
//--------------------------//-- Temporizador
//--------------------------dividerp1 #(.M(DELAY))
DIV0 ( .clk(clk),
.clk_out(clk_delay)
);
//-- Inicializador
always @(negedge clk)
rstn <= 1;
endmodule

Fichero rom1.list
El fichero que se graba en la rom, con la secuencia de ejemplo (contador) es el siguiente:

converted by Web2PDFConvert.com

//-- Fichero rom1.list


//-- Cada linea se corresponde con una posicion de memoria
//-- Se pueden poner comentarios
//-- ROM1: contiene los numeros del 0 al 31 (en hexadecimal)
0 //-- Posicion 0
1 //-- Posicion 1
2
3
4
5
6
7
8
9
A
B
C
D
E
F
10
11
12
13
14
15
16
17
18
19
1A
1B
1C
1D
1E
1F

Simulacin
El banco de pruebas es el mismo que en el captulo anterior. Para simular ejecutamos:
$ make sim

y en el gtkwave vemos lo siguiente:

Por los leds aparece la secuencia de cuenta, desde 0 hasta 31 (en hexadecimal)

Sntesis y pruebas
Para sintetizar hay que ejecutar el comando:

converted by Web2PDFConvert.com

$ make sint

Los recursos empleados son:

Recurso

ocupacin

PIOs

7 / 96

PLBs

15 / 160

BRAMs

1 / 16

El diseo se carga con:


$ sudo iceprog genromleds.bin

Se podr ver por los leds la secuencia de cuenta

Ejemplo 2: Tocando la marcha imperial


En el segundo ejemplo tocaremos un fragmento de la marcha imperial de star wars. Esto es un
clsico en el grupo de Clone wars, tocndose con los motores paso a paso para comprobar su
funcionamiento. Pues bien, una FPGA no la tendrs dominada hasta que no toques con ella la
marcha imperial :-)

Diagrama de bloques
El diseo consta de una memoria ROM de 64 posiciones de 16 bits. En cada una de ellas se
almacena el valor del divisor para generar una nota musical. Los 5 bits menos significativos de
cada valor de la nota se envan a los leds, para ver la actividad

converted by Web2PDFConvert.com

El generador de notas (notegen) es similar al que se hizo en el captulo 17 pero adaptndolo a las
reglas del diseo sncrono y haciendo que el mdulo del contador se pase como una entrada ms,
en vez de ser un valor fijo. Adems, se ha modificado para que la seal cuadrada generada tenga
siempre un ciclo de trabajo del 50% (y que todas las notas suenen con la misma intensidad)
La duracin de cada nota se ha establecido en 200ms. Colocando la misma nota en dos
posiciones consecutivas de la memoria rom, su duracin ser el doble (400ms). De esta forma se
controla de forma sencilla la duracin de todas las notas y los silencios

Descripcin en verilog
Los dos ficheros principales son el notegen.v, que contiene el componente de generacin de las
notas musicales y romnotes.v que tiene el reproductor completo

notegen.v:
//-- Fichero: notegen.v
module notegen(input wire clk,
//-- Senal de reloj global
input wire rstn,
//-- Reset
input wire [15:0] note, //-- Divisor
output reg clk_out); //-- Seal de salida
wire clk_tmp;
//-- Registro para implementar el contador modulo note
reg [15:0] divcounter = 0;
//-- Contador mdulo note
always @(posedge clk)
//-- Reset
if (rstn == 0)
divcounter <= 0;
//-- Si la nota es 0 no se incrementa contador
else if (note == 0)
divcounter <= 0;
//-- Si se alcanza el tope, poner a 0
else if (divcounter == note - 1)
divcounter <= 0;
//-- Incrementar contador
else
divcounter <= divcounter + 1;
//-- Sacar un pulso de anchura 1 ciclo de reloj si el generador
assign clk_tmp = (divcounter == 0) ? 1 : 0;
//-- Divisor de frecuencia entre 2, para obtener como salida una seal
//-- con un ciclo de trabajo del 50%
always @(posedge clk)
if (rstn == 0)
clk_out <= 0;
else if (note == 0)
clk_out <= 0;
else if (clk_tmp == 1)
clk_out <= ~clk_out;
endmodule

romnotes.v
converted by Web2PDFConvert.com

La descripcin en verilog del circuito reproductor se muestra a continuacin:


//-- Fichero romnotes.v
//-- Incluir las constantes del modulo del divisor
`include "divider.vh"
//-- Parametros:
//-- clk: Reloj de entrada de la placa iCEstick
//-- ch_out: Canal de salida
module romnotes(input wire clk,
output wire [4:0] leds,
output wire ch_out);
//-- Parametros
//-- Duracion de las notas
parameter DUR = `T_200ms;
//-- Fichero con las notas para cargar en la rom
parameter ROMFILE = "imperial.list";
//-- Tamao del bus de direcciones de la rom
parameter AW = 6;
//-- Tamao de las notas
parameter DW = 16;
//-- Cables de salida de los canales
wire ch0, ch1, ch2;
//-- Seleccin del canal del multiplexor
reg [AW-1: 0] addr = 0;
//-- Reloj con la duracion de la nota
wire clk_dur;
reg rstn = 0;
wire [DW-1: 0] note;
//-- Instanciar la memoria rom
genrom
#( .ROMFILE(ROMFILE),
.AW(AW),
.DW(DW))
ROM (
.clk(clk),
.addr(addr),
.data(note)
);
//-- Generador de notas
notegen
CH0 (
.clk(clk),
.rstn(rstn),
.note(note),
.clk_out(ch_out)
);
//-- Sacar los 5 bits menos significativos de la nota por los leds
assign leds = note[4:0];
//-- Inicializador
always @(posedge clk)
rstn <= 1;

//-- Contador para seleccion de nota


always @(posedge clk)
if (clk_dur)
addr <= addr + 1;
converted by Web2PDFConvert.com

addr <= addr + 1;


//-- Divisor para marcar la duracin de cada nota
dividerp1 #(DUR)
TIMER0 (
.clk(clk),
.clk_out(clk_dur)
);
endmodule

El parmetro DUR determina la duracin mnima de una nota (o un silencio), que se ha


establecido en 200ms. Para reproducir una nota del doble de duracin, simplemente se toca dos
veces. Tocndola N veces durar N * 200ms.

Contenido de la ROM: imperial.list


La meloda de la marcha imperial est almacenada en este fichero de texto:

converted by Web2PDFConvert.com

//-- Marcha imperial


0 //-- Un 0 es un SILENCIO
0
0
0
0
0
0
0
0
471A //-- MI_4
471A
0
471A //-- MI_4
471A
0
471A //-- MI_4
471A
0
5996 //-- DO_4
5996
3BCA //-- SOL_4
471A //-- MI_4
471A
0
5996 //-- DO_4
5996
3BCA //-- SOL_4
471A //-- MI_4
471A
//----------- Segundo trozo
0
0
0
2F75 //-- SI_4
2F75
0
2F75 //-- SI_4
2F75
0
2F75 //-- SI_4
2F75
0
2CCB //-- DO_5
2CCB
3BCA //-- SOL_4
471A //-- MI_4
471A
0
5996 //-- DO_4
5996
3BCA //-- SOL_4
471A //-- MI_4
471A

Lo que se almacenan son los valores de los divisores (en hexadecimal) para generar las notas.
Los valores de las diferentes notas se encuentran en el archivo notegen.vh.
Para que una nota dure ms tiempo, se reproduce 2 ms veces, colocndose en memoria las
copias de la misma nota.
La nota 0 equivale a un silencio

Simulacin
El banco de pruebas es el clsico: se instancia el componente romnotes y se genera el reloj para que

converted by Web2PDFConvert.com

funcione:
//-- Fichero: romnotes_tb.v
module romnotes_tb();
//-- Registro para generar la seal de reloj
reg clk = 0;
//-- Salidas de los canales
wire ch_out;

//-- Instanciar el componente y establecer el valor del divisor


//-- Se pone un valor bajo para simular (de lo contrario tardaria mucho)
romnotes #(.DUR(2))
dut(
.clk(clk),
.ch_out(ch_out)
);
//-- Generador de reloj. Periodo 2 unidades
always
# 1 clk <= ~clk;

//-- Proceso al inicio


initial begin
//-- Fichero donde almacenar los resultados
$dumpfile("romnotes_tb.vcd");
$dumpvars(0, romnotes_tb);
# 200 $display("FIN de la simulacion");
$finish;
end
endmodule

Para simulare ejecutamos:


$ make sim2

Y en la simulacin podremos ver cmo se van enviando los 5 bits menos significativos de la nota a
los leds. En la simulacin la duracin de la nota est puesta a 2 unidades

Sntesis y pruebas
La sntesis se realiza con el comando:
$ make sint2

converted by Web2PDFConvert.com

Los recursos empleados son:

Recurso

ocupacin

PIOs

7 / 96

PLBs

31 / 160

BRAMs

1 / 16

El diseo se carga con:


$ sudo iceprog romnotes.bin

El resultado se puede ver en este vdeo de youtube:

Que las FPGAs te acompaen!

Ejercicios
Completar la marcha imperial, aumentando la memoria y aadiendo el resto de notas

Conclusiones
TODO

FPGA Libres: [Wiki] [Repo]

2016 GitHub, Inc. Terms Privacy Security Contact Help

Status API Training Shop Blog About

converted by Web2PDFConvert.com

You might also like