Anda di halaman 1dari 99

Diseño sobre FPGA de una Unidad Aritmética Decimal

TITULACIÓN: Ingeniería Técnica Industrial en Electrónica Industrial

AUTOR: Alejandro Baena Alonso

DIRECTOR: Jean-Pierre Deschamps

FECHA: Febrero / 2010


Diseño sobre FPGA de una Unidad Aritmética Decimal

1. ÍNDICE GENERAL
Diseño sobre FPGA de una Unidad Aritmética Decimal Índice general

2. INTRODUCCIÓN

2.1 Objetivos del proyecto ............................................................................................................... 7


2.2 Aspectos básicos ......................................................................................................................... 7
2.2.1 Aritmética decimal.............................................................................................................. 7
2.2.2 Código decimal codificado en binario (BCD) .................................................................... 8
2.2.3 Dispositivos programables.................................................................................................. 8
2.3 Diseño de Sistemas Electrónicos ............................................................................................... 9
2.3.1 Tendencias generales en Diseño Electrónico...................................................................... 9
2.3.2 Lenguajes de descripción del hardware .............................................................................. 9
2.3.2.1 ¿Qué son los lenguajes de descripción del hardware?............................................. 9
2.3.2.2 El lenguaje VHDL ................................................................................................... 10
2.3.2.2.1 Introducción al lenguaje VHDL .................................................................... 10
2.3.2.2.2 Características............................................................................................... 10
2.3.2.2.3 Niveles de descripción ................................................................................... 11
2.3.2.2.4 Estructura de una descripción....................................................................... 11
2.3.2.2.5 Metodología de diseño................................................................................... 12
2.3.3 Dispositivos lógicos programables ................................................................................... 13
2.3.4 Componentes IP (IP cores)............................................................................................... 15
2.3.5 Prototipado rápido ............................................................................................................ 16
2.4 Spartan-3E Starter Kit Board ................................................................................................... 16

3. MEMORIA DESCRIPTIVA

3.1 La Unidad Aritmética Decimal ............................................................................................... 20


3.2 Bloques de la unidad ................................................................................................................ 21
3.2.1 Sumador/Restador............................................................................................................. 21
3.2.1.1 Sumador .................................................................................................................. 21
3.2.1.1.1 Sumador de 1 dígito BCD (bloque “one_digit_adder.vhd”)......................... 21
3.2.1.1.2 Sumador de n dígitos decimales .................................................................... 24
3.2.1.2 Restador…............................................................................................................... 26
3.2.1.2.1 Cálculo del complemento a 9 (bloque “nine_complement.vhd”).................. 27
3.2.1.2.2 Sumador/Restador en complemento a 10n ..................................................... 28
3.2.1.3 Sumador/Restador, representación con signo y magnitud (bloque
“n_adder_subs.vhd”).......................................................................................................... 29
3.2.2 Multiplicador…….. .......................................................................................................... 32
3.2.2.1 Multiplicador de 1x1 dígitos BCD (bloque “one_digit_multiplier.vhd”)................ 32
3.2.2.2 Multiplicador de Nx1 dígitos BCD (bloque“n_by_one_multiplier.vhd”)............... 34
3.2.2.3 Multiplicador de NxM dígitos BCD (bloque“n_by_m_multiplier.vhd”) ................ 37
3.2.3 Divisor .............................................................................................................................. 41
3.2.3.1 Algoritmo de división binaria ................................................................................. 41
3.2.3.2 Algoritmo de división BCD ..................................................................................... 42
3.2.3.3 Error generado........................................................................................................ 42
3.2.3.4 Divisor BCD (bloque “divider.vhd”)...................................................................... 43
3.3 Diseño de la Unidad Aritmética Decimal ............................................................................... 48

-3-
Diseño sobre FPGA de una Unidad Aritmética Decimal Índice general

4. MEMORIA EXPERIMENTAL

4.1 Descripción del proceso ........................................................................................................... 54


4.2 Especificaciones ........................................................................................................................ 54
4.3 Elementos necesarios................................................................................................................ 55
4.4 Arquitectura a desarrollar ...................................................................................................... 55
4.5 Módulos IP de terceros utilizados........................................................................................... 57
4.5.1 Microcontrolador PicoBlaze (módulo “kcpsm.vhd”)........................................................ 57
4.5.2 Interfaz LCD (módulo “lcd_interface.vhd”)..................................................................... 58
4.6 Memoria de programa (módulo “program_memory.vhd”) ................................................... 60
4.7 Generación del circuito (módulo “main.vhd”) ....................................................................... 62
4.8 Asignación de pines en la FPGA (archivo “pins.ucf”) .......................................................... 63
4.9 Implementación en la FPGA ................................................................................................... 65
4.9.1 Generación del archivo ..................................................................................................... 66
4.9.2 Implementación en la FPGA ............................................................................................ 68

5. ANEXOS

5.1 Modelos VHDL......................................................................................................................... 72


5.1.1 Sumador de 1 dígito BCD (one_digit_adder.vhd)............................................................ 72
5.1.2 Complemento a 9 (nine_complement.vhd) ....................................................................... 73
5.1.3 Sumador/Restador de n dígitos decimales (n_adder_subs.vhd) ....................................... 73
5.1.4 Multiplicador de 1x1 dígitos BCD (one_digit_multiplier.vhd) ........................................ 75
5.1.5 Multiplicador de Nx1 dígitos BCD (n_by_one_multiplier.vhd) ....................................... 76
5.1.6 Multiplicador de NxM dígitos BCD (n_by_m_multiplier.vhd)......................................... 78
5.1.7 Divisor BCD (divider.vhd) ............................................................................................... 80
5.1.8 Unidad Aritmética Decimal (arithmetic_unit.vhd) ........................................................... 83
5.1.9 Memoria de programa (program_memory.vhd) ............................................................... 86
5.1.10 Circuito completo (main.vhd) ......................................................................................... 89
5.2 Programa en lenguaje ensamblador (decimal_unit.asm) ...................................................... 94
5.3 Asignación de pines en la Spartan-3E (pins.ucf) .................................................................... 97

6. BIBLIOGRAFÍA........................................................................................................................ 99

-4-
Diseño sobre FPGA de una Unidad Aritmética Decimal

2. INTRODUCCIÓN
Diseño sobre FPGA de una Unidad Aritmética Decimal Introducción

2.1 Objetivos del proyecto ............................................................................................................... 7


2.2 Aspectos básicos ......................................................................................................................... 7
2.2.1 Aritmética decimal.............................................................................................................. 7
2.2.2 Código decimal codificado en binario (BCD) .................................................................... 8
2.2.3 Dispositivos programables.................................................................................................. 8
2.3 Diseño de Sistemas Electrónicos ............................................................................................... 9
2.3.1 Tendencias generales en Diseño Electrónico...................................................................... 9
2.3.2 Lenguajes de descripción del hardware .............................................................................. 9
2.3.2.1 ¿Qué son los lenguajes de descripción del hardware?............................................. 9
2.3.2.2 El lenguaje VHDL ................................................................................................... 10
2.3.2.2.1 Introducción al lenguaje VHDL .................................................................... 10
2.3.2.2.2 Características............................................................................................... 10
2.3.2.2.3 Niveles de descripción ................................................................................... 11
2.3.2.2.4 Estructura de una descripción....................................................................... 11
2.3.2.2.5 Metodología de diseño................................................................................... 12
2.3.3 Dispositivos lógicos programables ................................................................................... 13
2.3.4 Componentes IP (IP cores)............................................................................................... 15
2.3.5 Prototipado rápido ............................................................................................................ 16
2.4 Spartan-3E Starter Kit Board ................................................................................................... 16

-6-
Diseño sobre FPGA de una Unidad Aritmética Decimal Introducción

2.1 Objetivos del proyecto

El objetivo de este proyecto es el diseño del modelo VHDL de una Unidad Aritmética
Decimal, que pueda funcionar como coprocesador/acelerador dentro de otro sistema más
complejo. Por tanto, se trata de un componente virtual utilizable en cualquier tipo de
sistemas que requieran operar en decimal.

Dicha unidad permitirá realizar las operaciones aritméticas básicas – siempre operando en
decimal – como son la suma, resta, multiplicación y división de dos valores decimales.

Posteriormente, y a modo de testeo del modelo resultante, se implementará sobre una


FPGA, la SPARTAN-3E modelo XC3S500E de XILINX.

Para la creación y simulación de la unidad aritmética decimal se ha utilizado el programa


MODELSIM PE en su versión STUDENT EDITION. Para la implementación en la FPGA,
se ha utilizado el ensamblador PBLAZ IDE para la creación de la memoria de programa, y
el paquete ISE DESIGN SUITE de XILINX para la síntesis y grabación del código en la
placa de pruebas.

2.2 Aspectos básicos

2.2.1 Aritmética decimal

Los sistemas que operan en decimal son preferibles a los que lo hacen en binario en un
gran número de aplicaciones aritméticas informáticas. El motivo principal no es la
complejidad de las interfaces de codificación y decodificación (que también influye), sino
principalmente la falta de precisión y claridad de los resultados.

La aritmética decimal desempeña un papel clave en el procesamiento de datos en diversos


entornos, ya sean comerciales, financieros o de aplicaciones basadas en Internet, entre
otros. Y las prestaciones que estos requieren no quedan satisfechas con las unidades
convencionales que internamente operan en binario. En consecuencia, los procesadores de
propósito general que incluyen la implementación hardware de aritmética decimal están
adquiriendo relevancia

Actualmente, el sistema decimal codificado en binario (BCD) es utilizado en el diseño de


algoritmos de aritmética decimal; aunque otros sistemas de codificación podrían resultar
interesantes, el sistema BCD parece la mejor opción por el momento.

-7-
Diseño sobre FPGA de una Unidad Aritmética Decimal Introducción

2.2.2 Código decimal codificado en binario (BCD)

El código decimal codificado en binario (BCD, Binary Coded Decimal, también conocido
como código 8421) codifica los dígitos decimales del 0 al 9 mediante sus representaciones
binarias sin signo de 4 bits, desde 0000 a 1001. Las palabras de código restantes, de 1010 a
1111, no se utilizan. Las conversiones entre las representaciones BCD y decimal son
triviales e implican la sustitución directa de cuatro bits por cada dígito decimal.

El decimal codificado en binario es un código ponderado, puesto que cada dígito decimal
puede obtenerse a partir de su palabra de código asignando un peso fijo a cada bit de
palabra de código. Los pesos para los bits BCD son 8, 4, 2, 1, y por esta razón el código se
denomina en ocasiones código 8421.

En la siguiente tabla se representa la correspondencia entre los números decimales y las


combinaciones binarias del código BCD:

Decimal BCD
0 0000
1 0001
2 0010
3 0011
4 0100
5 0101
6 0110
7 0111
8 1000
9 1001
Tabla 2.1. Correspondencia entre los dígitos decimales y código BCD

2.2.3 Dispositivos programables

Hoy en día, las FPGA (Field Programmable Gate Arrays, de las que se hablará más
adelante) son una de las tecnologías disponibles para el desarrollo de sistemas electrónicos.
Representan una atractiva opción para la producción de pequeñas cantidades ya que sus
costes fijos (coste del prototipo, de la primera unidad) son bastante más bajos que los
correspondientes en ASIC (Application-Specific Integrated Circuit, circuitos integrados de
aplicación específica). Además, en pos de reducir el tamaño y por tanto el coste unitario,
una posibilidad interesante es reconfigurarlas mientras operan de modo que el mismo
dispositivo pueda ejecutar diferentes funciones predefinidas.

-8-
Diseño sobre FPGA de una Unidad Aritmética Decimal Introducción

2.3 Diseño de Sistemas Electrónicos

2.3.1 Tendencias generales en Diseño Electrónico

Actualmente los sistemas electrónicos están muy presentes en la mayoría de ámbitos,


desde la electrónica de consumo a los sistemas de control industrial, pasando por las
aplicaciones para automoción o seguridad, y un largo etcétera…

El problema principal radica en la complejidad del diseño de muchos de los elementos,


donde se exige, por ejemplo, que sean de fácil utilización y adaptables a varias
aplicaciones, que consuman pocos recursos y que puedan estar rápidamente a la venta…

La tecnología actual de circuitos integrados permite realizar e integrar estos complejos


sistemas en muy poco espacio; son los llamados sistemas empotrados (o embebidos) o SoC
(System on Chip). Estos sistemas, como pueden ser los ASIC (Application-Specific
Integrated Circuit) o las FPGA, permiten integrar en el mismo dispositivo uno o más
microprocesadores o microcontroladores, coprocesadores, diversos bloques de memoria de
diferentes tipos, periféricos de entrada-salida, osciladores, buses para interconectar los
bloques, etc.

Estos sistemas embebidos para aplicaciones específicas incluyen hardware y software


específico. En el caso de las FPGA, al ser dispositivos reconfigurables, son altamente útiles
para el desarrollo de prototipos o pequeñas cantidades, a un precio razonablemente bajo.

2.3.2 Lenguajes de descripción del hardware

2.3.2.1 ¿Qué son los lenguajes de descripción del hardware?

Los lenguajes de descripción hardware (HDL, Hardware Description Language) surgen de


la necesidad de los diseñadores de disponer de un conjunto de herramientas que permitan
describir los sistemas digitales de formas diferentes, facilitando el diálogo entre los propios
diseñadores, aunque también entre las herramientas de diseño asistido por ordenador
(CAD, Computer-Aided Design) y entre diseñadores y herramientas.

Los sistemas de desarrollo basados en lenguajes HDL permiten especificar y modelar la


estructura y función de un circuito digital; incluyen herramientas para compilar, simular y
sintetizar sistemas digitales. Estas herramientas de programación se utilizan para
comprobar el funcionamiento del modelo antes de que sea construido.

Actualmente, los lenguajes HDL más utilizados son VHDL y Verilog, ya que están
estandarizados por el IEEE (Institute of Electrical and Electronic Engineers). Nosotros nos
centraremos en el primero de ellos.

-9-
Diseño sobre FPGA de una Unidad Aritmética Decimal Introducción

2.3.2.2 El lenguaje VHDL

2.3.2.2.1 Introducción al lenguaje VHDL

VHDL proviene de VHSIC (Very High Speed Integrated Circuit) Hardware Description
Language. VHDL es un lenguaje de descripción del hardware que puede utilizarse para
modelar, documentar, simular, verificar y sintetizar un sistema digital. Por tanto, abarca el
ciclo completo de diseño (salvo el trazado físico o layout) desde las especificaciones
iniciales hasta la construcción del prototipo hardware. Proporciona el soporte necesario
para especificar su comportamiento o estructura, incluyendo jerarquías. Asimismo, es útil
para metodologías de diseño ascendentes (bottom-up) como, sobre todo, descendentes (top-
down).

La semántica y construcciones del lenguaje permiten también diseñar con facilidad bancos
de prueba (test-benches), mediante los que se lleva a cabo la simulación de los sistemas
modelados.

2.3.2.2.2 Características

VDHL es un lenguaje de descripción hardware de ámbito general derivado del lenguaje de


alto nivel ADA (que es el lenguaje para programar sistemas en tiempo real por excelencia).
Dispone de tipos abstractos para definir el formato y valores de señales, variables,
constantes, etc., y proporciona amplias facilidades para la realización de algoritmos.

Admite casi todos los niveles de descripción, desde el algorítmico (nivel más alto) hasta el
lógico (nivel más bajo). Para ello proporciona herramientas semánticas y sintácticas que se
pueden agrupar así:

• Aquellas orientadas a las descripciones del comportamiento del circuito.


• Aquellas orientas a la descripción de las relaciones entre los distintos bloques
de un circuito, es decir, su estructura.

Al realizar una descripción VHDL es importante elegir adecuadamente el nivel de función


del objetivo perseguido. Por ejemplo, si se pretende sintetizar la descripción realizada, es
decir, si el objetivo final es obtener un conjunto de puertas e interconexiones, no se debe
emplear el nivel algorítmico, pues en general las herramientas actuales de síntesis no
procesan de forma eficiente estas descripciones. Sin embargo, este nivel sí es adecuado
cuando el objetivo es comprobar que un sistema complejo funciona correctamente, pues se
puede describir y simular de una forma rápida y eficaz.

- 10 -
Diseño sobre FPGA de una Unidad Aritmética Decimal Introducción

2.3.2.2.3 Niveles de descripción

El lenguaje VHDL presenta tres métodos básicos para describir un circuito digital por
software:

• El nivel algorítmico es el que presenta un mayor grado de abstracción (alto nivel).


Aquí el diseñador solo describe el comportamiento del sistema, sin preocuparse de
las señales o componentes internos del mismo. También llamado nivel de
comportamiento o behavior.

• El nivel RTL (Register-Transfer Level, nivel de transferencia de registros)


proporciona un cierto grado de abstracción con respecto al hardware, pero el
diseñador se ve obligado a describir las distintas señales que interactúan en un
circuito y su comportamiento en función de las entradas por medio de ecuaciones
lógicas y sentencias de asignación. También conocido como nivel de flujo de datos.

• El nivel lógico describe la estructura interna de un circuito basándose en unos


componentes básicos definidos previamente (equivaldría a un diagrama lógico).

2.3.2.2.4 Estructura de una descripción

Toda descripción en VHDL está constituida al menos por tres tipos de elementos:
bibliotecas (libraries), entidades (entities) y arquitecturas (architectures).

El diseñador generalmente realiza la descripción de las entidades empleando elementos


almacenados en las bibliotecas.

En la declaración de la entidad se define el diseño como si fuera un producto encapsulado,


indicando el número de pines, los puertos de entrada y salida. La entidad puede definir
bien las entradas y salidas de un circuito integrado por diseñar o puede definir la interfaz
de un módulo que será utilizado en un diseño más grande.

Para que la descripción de un circuito sea completa se necesita, además de su declaración


como entidad, una especificación de su funcionamiento. La arquitectura es la encargada de
ello. Es posible realizar diversas descripciones del funcionamiento del circuito, por lo que
pueden existir varias arquitecturas para una misma entidad.

- 11 -
Diseño sobre FPGA de una Unidad Aritmética Decimal Introducción

2.3.2.2.5 Metodología de diseño

La Figura 2.1 muestra el flujo de diseño de un circuito en VHDL, desde su concepción


hasta su fabricación.

Figura 2.1. Flujo de diseño en VHDL

Una vez finalizada la prueba del concepto, se pasa al diseño detallado. Dependiendo de la
herramienta de síntesis que se utilice y de las especificaciones del circuito, la descripción
VHDL estará desarrollada en un nivel de abstracción mayor o menor (desde un nivel
algorítmico a uno lógico).

Por último se aborda la síntesis del circuito, es decir, el paso de una descripción en VHDL
a un circuito real. El proceso de diseño puede terminar antes si el objetivo final no es la
fabricación sino, por ejemplo, la creación de componentes de biblioteca para uso posterior.

- 12 -
Diseño sobre FPGA de una Unidad Aritmética Decimal Introducción

2.3.3 Dispositivos lógicos programables

Existen dos grandes grupos de dispositivos lógicos programables: PLDs (Programmable


Logic Device, dispositivo lógico programable) y FPGAs (Field Programmable Gate Array,
matriz de puertas configurables).

Figura 2.2. Tipos de lógica programable

Los PLDs están basados en una matriz AND + OR. Dentro de los PLDs encontramos las
PROM (Programmable Read Only Memory), las PAL (Programmable Logic Array) y las
PAL (Programmable Array Logic).

Figura 2.3. Familia de los PLD

Dentro de las PAL se encuentran los CPLDs (Complex PLD), compuestos por la
integración de PLDs (PAL/GAL o PLA). Están formados por bloques lógicos y matrices
de interruptores, donde cada bloque lógico corresponde a un PLD.

Figura 2.4. Ejemplo de arquitectura de CPLD (con 4 elementos lógicos o bloques programables)

- 13 -
Diseño sobre FPGA de una Unidad Aritmética Decimal Introducción

Las FPGA están compuestas por una matriz de elementos lógicos cuya interconexión y
funcionalidad se puede programar. En comparación con los dispositivos CPLD, difieren en
la arquitectura, no utilizan matrices de tipo PAL/PLA y tienen unas densidades mucho
mayores que los anteriores. Una FPGA típica tiene un número de puertas equivalentes
mucho mayor que un dispositivo CPLD típico. Los elementos que implementan las
funciones lógicas en las FPGA son, generalmente, mucho más pequeños que en los CPLD,
por lo que hay muchos más de esos elementos. Asimismo, en las FPGA, las
interconexiones programables están organizadas según una disposición de filas y
columnas.

Figura 2.5. Arquitectura interna de una FPGA

Los tres elementos básicos en una FPGA son el bloque configurable (CLB, Configurable
Logic Block), las interconexiones y los bloques de entrada/salida (E/S). Los bloques CLB
de una FPGA son menos complejos que sus homónimos en un CPLD, pero suele haber
muchos más de ellos. La matriz distribuida de interconexiones programables permite
interconectar los bloques CLB entre sí y conectarlos a las entradas y a las salidas. Los
bloques de E/S situados alrededor del perímetro de las estructura proporcionan un acceso
de entrada/salida o bidireccional, individualmente seleccionable, hacia el mundo exterior.

Estructura de los bloques lógicos configurables

Cada bloque lógico de la FPGA está formado por múltiples módulos lógicos más pequeños
(que son los componentes básicos) y por una serie de interconexiones programables locales
que se emplean para conectar entre sí los módulos lógicos que componen el CLB.

CLB

Módulo lógico

Módulo lógico

Interconexión
local

Módulo lógico

Figura 2.6. Arquitectura de un CLB

- 14 -
Diseño sobre FPGA de una Unidad Aritmética Decimal Introducción

Un módulo lógico puede configurarse para implementar lógica combinacional, lógica


registrada o una combinación de ambas. Se emplea un flip-flop que forma parte de la lógica
asociada para implementar lógica registrada. A continuación se muestra un diagrama de
bloques de un módulo lógico típico basado en LUT (Look-Up Table, tipo de memoria
programable que se utiliza para generar funciones booleanas):

Salida suma de
productos
A0
A1
Lógica E/S
LUT
asociada

An-1
Módulo lógico

Figura 2.7. Diagrama de bloques básico de un módulo lógico

Los dispositivos FPGA son reprogramables, y los de gran tamaño pueden tener decenas de
miles de bloques CLB, además de memoria y otros recursos. Por todo ello y la gran
flexibilidad que presentan, son ideales para realizar prototipos de manera rápida, en
pequeñas cantidades.

2.3.4 Componentes IP (IP cores)

Dentro de una FPGA se puede incluir la funcionalidad de varios circuitos integrados. Esta
funcionalidad puede ser desarrollada uno mismo o adquirida a través de terceros. Debido a
que estas funcionalidades son como componentes electrónicos, pero sin su parte física, se
les suele llamar componentes virtuales. En la industria se les conoce como bloques de
propiedad intelectual o IP cores (Intellectual Property).

Existen tres tipos de IP cores:

• Hablamos de soft-core cuando se trata de código sintetizable, similar al código


fuente para software o también a descripción a nivel de puerta (netlist).
• Entendemos por hard-core el caso de una descripción física, a nivel físico (de
transistores); estos módulos presentan problemas a la hora de asociar diferentes
procesos entre ellos o pasar de una línea de fabricación a otra.
• Por firm-core nos referimos a un diseño que puede ser modificado en términos de
placement & routing o en tecnología de bibliotecas.

Los dispositivos FPGA que contienen procesadores integrados y otras funciones


implementadas en forma de módulos de hardware (hard-core) y de módulos de software
(soft-core) se conocen con el nombre de dispositivos FPGA de plataforma, porque
pueden emplearse para implementar un sistema completo sin necesidad de dispositivos
externos de soporte.

El objetivo de este proyecto es el de crear un IP core o componente IP que realice


operaciones en decimal. En este caso se tratará de un soft-core.

- 15 -
Diseño sobre FPGA de una Unidad Aritmética Decimal Introducción

2.3.5 Prototipado rápido

Un sistema completo (hardware y software) y su entorno no puede ser validado únicamente


mediante la simulación. El objetivo es comprobar en la práctica el funcionamiento del
prototipo a un coste asequible.

El prototipado rápido es una posibilidad que facilita enormemente el diseño, mediante la


cual un circuito compuesto por una gran cantidad de puertas lógicas puede ser
implementado en un circuito integrado configurable, como lo puede ser una FPGA, a partir
de una descripción en HDL mediante un simple ordenador personal (PC), sin la necesidad
de adquirir o disponer de un equipamiento caro. Y la tecnología que permite dicha técnica
la forman las tarjetas de prototipado rápido, que permiten reproducir desde funciones
sencillas hasta complejos sistemas en un chip (SoC, System on Chip).

Dichas tarjetas incluyen los componentes necesarios para esta misión: dispositivos
programables (CPLD, FPGA), memoria de datos y de programa, componentes de entrada-
salida y conectores (displays, puertos Ethernet, USB, RS-232, conversores analógico-
digital y viceversa, interruptores, LEDs…), osciladores internos (reloj del sistema)…

Un ejemplo de este tipo de dispositivos es la Spartan-3E Starter Kit Board, que


utilizaremos para comprobar el funcionamiento de nuestra Unidad Aritmética Decimal.

2.4 Spartan-3E Starter Kit Board

La unidad Spartan-3E Starter Kit Board nos proporciona las herramientas necesarias para
testear nuestro sistema. Incluye la placa de pruebas con una FPGA Spartan-3E modelo
XC3S500E, fuente de alimentación, cable USB para programar el dispositivo, software
para sintetizar e implementar nuestro modelo y manuales de referencia.

A continuación enumeramos algunas características de la placa:

• Dispositivos Xilinx integrados:

- FPGA de la familia Spartan-3E modelo XC3S500E-4FG320C (con 232 pines


de E/S para el usuario, 1164 CLBs o bloque lógicos configurables y 10000
celdas o módulos lógicos)
- Controlador CPLD CoolRunner-II CPLD (XC2C64A-5VQ44C)
- 4 Mbits de memoria PROM Platform Flash

• Reloj: oscilador de 50 MHz

• Otra memoria incluida:

- 128 Mbits de memoria Parallel Flash


- 16 Mbits de memoria SPI (Serial Peripheral Interface) Flash
- 64 MBytes de memoria DDR SDRAM

- 16 -
Diseño sobre FPGA de una Unidad Aritmética Decimal Introducción

• Interfaces y conectores:

- 4 interruptores tipo pulsador


- 4 salidas DAC (Digital-to-Analog Converter)
- 2 entradas ADC (Analog-to-Digital Converter)
- Conexión Ethernet 10/100
- Puerto USB
- 2 puertos serie RS-232
- Puerto PS/2 para ratón o teclado
- 4 interruptores tipo slide
- …

• Display: Pantalla LCD de 2 líneas de 16 caracteres cada una

Figura 2.8. Vista superior de la Spartan-3E

- 17 -
Diseño sobre FPGA de una Unidad Aritmética Decimal

3. MEMORIA DESCRIPTIVA
Diseño sobre FPGA de una Unidad Aritmética Decimal Memoria descriptiva

3.1 La Unidad Aritmética Decimal ............................................................................................... 20


3.2 Bloques de la unidad ................................................................................................................ 21
3.2.1 Sumador/Restador............................................................................................................. 21
3.2.1.1 Sumador .................................................................................................................. 21
3.2.1.1.1 Sumador de 1 dígito BCD (bloque “one_digit_adder.vhd”)......................... 21
3.2.1.1.2 Sumador de n dígitos decimales .................................................................... 24
3.2.1.2 Restador…............................................................................................................... 26
3.2.1.2.1 Cálculo del complemento a 9 (bloque “nine_complement.vhd”).................. 27
3.2.1.2.2 Sumador/Restador en complemento a 10n ..................................................... 28
3.2.1.3 Sumador/Restador, representación con signo y magnitud (bloque
“n_adder_subs.vhd”).......................................................................................................... 29
3.2.2 Multiplicador…….. .......................................................................................................... 32
3.2.2.1 Multiplicador de 1x1 dígitos BCD (bloque “one_digit_multiplier.vhd”)................ 32
3.2.2.2 Multiplicador de Nx1 dígitos BCD (bloque“n_by_one_multiplier.vhd”)............... 34
3.2.2.3 Multiplicador de NxM dígitos BCD (bloque“n_by_m_multiplier.vhd”) ................ 37
3.2.3 Divisor .............................................................................................................................. 41
3.2.3.1 Algoritmo de división binaria ................................................................................. 41
3.2.3.2 Algoritmo de división BCD ..................................................................................... 42
3.2.3.3 Error generado........................................................................................................ 42
3.2.3.4 Divisor BCD (bloque “divider.vhd”)...................................................................... 43
3.3 Diseño de la Unidad Aritmética Decimal ............................................................................... 48

- 19 -
Diseño sobre FPGA de una Unidad Aritmética Decimal Memoria descriptiva

3.1 La Unidad Aritmética Decimal

Nuestro objetivo es la creación del modelo VHDL de una Unidad Aritmética Decimal, es
decir, una unidad que, operando en sistema BCD, realice las operaciones de suma, resta,
multiplicación y división.

Figura 3.1. Representación previa de la Unidad Aritmética Decimal

Necesitaremos un sistema que dados dos valores de entrada de n dígitos BCD cada uno, x e
y, calcule el resultado z (de 2n dígitos BCD) de la operación que hayamos escogido
previamente mediante la señal de entrada operation. Además, contaremos con las señales
de entrada start (para iniciar el cálculo interno cuando sea necesario), reset (reiniciar el
sistema), clk (señal de reloj) y las de salida carry (acarreo de salida cuando sea necesario)
y done (indicador de resultado disponible).

Para ello, la primera idea es que deberemos crear el modelo necesario para poder ejecutar
cada operación.

Unidad aritmética decimal

Sumador Restador Multiplicador Divisor

Figura 3.2. Estructura interna previa de la Unidad Aritmética Decimal

Por consiguiente, nos centraremos primero en el diseño de los módulos primarios que
realizarán las diferentes operaciones y después los integraremos en la unidad principal.

- 20 -
Diseño sobre FPGA de una Unidad Aritmética Decimal Memoria descriptiva

3.2 Bloques de la unidad

3.2.1 Sumador/Restador

3.2.1.1 Sumador

En este apartado nuestro objetivo es la realización de un sumador de n dígitos decimales.


Para ello, lo primero que hacemos es crear una estructura básica, el sumador de 1 dígito
decimal.

3.2.1.1.1 Sumador de 1 dígito BCD (bloque “one_digit_adder.vhd”)

La idea principal de este bloque es que, dadas dos entradas, a y b, que representan cada una
1 dígito decimal, tenemos una arquitectura cuya misión es realizar la suma de ambos
dígitos y dar como resultado (c) 1 dígito decimal de salida y un acarreo (carry_out) en caso
de ser necesario.

Figura 3.3. Sumador de 1 dígito decimal

La estructura interna del bloque sería la siguiente:

Figura 3.4. Arquitectura del sumador de 1 dígito decimal

- 21 -
Diseño sobre FPGA de una Unidad Aritmética Decimal Memoria descriptiva

Tenemos dos entradas, a y b, que pueden representar cualquier dígito decimal del 0 al 9,
una salida c que también será un dígito BCD, y un acarreo de salida (carry_out). También
hay un acarreo de entrada, carry_in, que nos permitirá interconectar diversos bloques.

Funcionamiento

Al realizar la suma binaria se nos pueden presentar dos casos: si el resultado de dicha suma
es igual o menor a 9 (‘1001’), el resultado es directo (es decir, a + b = c). Si la suma es
superior a 9, debemos realizar una corrección al valor obtenido.

El proceso en este segundo caso es el siguiente: realizamos la suma de a y b en binario,


obteniendo el valor intermedio d formado por 5 bits (Figura 3.4). Son 5 bits porque el
máximo número en decimal que podemos obtener es que el que se da cuando a y b tienen
sus valores máximos (9) y el acarreo de entrada carry_in es igual a ‘1’; el resultado de la
suma (a + b + carry_in) es 19, y en binario sería ‘10011’ (los cinco bits mencionados).
Para el caso de que la suma de a y b sea mayor que 9, aplicaremos un factor de corrección
que sería restar 10 al valor obtenido y aumentar 1 el dígito de las decenas. Y restar diez
equivale en binario a sumar 6 (‘0110’). Un ejemplo: si a es 5 y b es 7, la suma es 12 y
debemos realizar la corrección.

Empezamos sumando 5 y 7. Sus correspondientes en binario son ‘0101’ para el 5 y ‘0111’


para el número 7. El resultado es 12, que en binario se representa como ‘1100’.

1 1 1 decimal
0 1 0 1 → 5
+ 0 1 1 1 → 7
1 1 0 0 → 12

Vemos que este valor es superior a 9, y por tanto no es un valor BCD válido. Entonces
hemos de aplicar una corrección para obtener el valor correspondiente en BCD, donde el
número 12 se representaría con dos dígitos de cuatro bits cada uno; un primer grupo para el
1 ‘0001’, y otro grupo para el 2 ‘0010’. Para pasar de binario a BCD vamos a sumar 6 (en
binario ‘0110’):

1 1
1 1 0 0 → 12
+ 0 1 1 0 → 6
1 0 0 1 0

Equivale a un dígito BCD Equivale a un dígito BCD de


de valor 1 (‘0001’) valor 2 (‘0010’)

Obtenemos ‘10010’, donde debemos leer los últimos cuatro bits para el primer dígito
decimal ‘0010’ y que equivalen al número 2, y el bit de más peso, ‘1’, que formaría parte
del siguiente dígito decimal, que sería un 1. Por tanto, tendríamos como resultado dos
dígitos decimales, un dígito decimal de las decenas igual a 1, y otro para las unidades que
sería un 2. Hemos pasado del valor 12, ‘10010’ en binario, a su equivalente en
nomenclatura BCD, ‘0001 0010’.

- 22 -
Diseño sobre FPGA de una Unidad Aritmética Decimal Memoria descriptiva

Decimal 12
Binario 1100
BCD 0001 0010

En resumen:

• Si a + b + cy_in ≤ 9, a + b + cy_in = c, acarreo de salida = 0 (3.1)

• Si a + b + cy_in > 9, a + b + cy_in = (c + 6) mod 16, acarreo de salida = 1 (3.2)

A continuación podemos ver una simulación del funcionamiento de este bloque:

Figura 3.5. Simulación del sumador de 1 dígito decimal

Podemos observar como se realiza la corrección cuando a + b > 9, obteniendo como


resultado en c el dígito de las unidades, y el dígito 1 (‘0001’) de las decenas en el acarreo
de salida (cy_out).

- 23 -
Diseño sobre FPGA de una Unidad Aritmética Decimal Memoria descriptiva

3.2.1.1.2 Sumador de n dígitos decimales

Para obtener el sumador de n dígitos BCD vamos a interconectar n sumadores de 1 dígito


decimal (el bloque que hemos creado antes). Gracias a la entrada carry_in de cada bloque,
podemos propagar el acarreo de manera que el resultado obtenido sea el correcto.

Figura 3.6. Diagrama de bloques del sumador de n dígitos decimales

La interconexión de los bloques sencillos creará el sumador de n dígitos BCD,

Figura 3.7. Sumador de n dígitos decimales

donde tendremos dos entradas, x e y, de n dígitos BCD (4n bits), y una salida z que será el
resultado de la operación. Además, en el caso de que haya desbordamiento en z, la salida
out_carry se pondrá a ‘1’. La entrada ini_carry en este bloque se corresponde con el
acarreo de entrada del primer sumador de 1 dígito BCD.

- 24 -
Diseño sobre FPGA de una Unidad Aritmética Decimal Memoria descriptiva

A continuación se muestra la simulación de unos ejemplos para n = 4:

Figura 3.8. Simulación del sumador de 4 dígitos decimales

Podemos ver como en la tercera operación (x = 3050, y = 8070), el acarreo de salida está a
nivel alto, lo que indica que el resultado es z = 11120.

- 25 -
Diseño sobre FPGA de una Unidad Aritmética Decimal Memoria descriptiva

3.2.1.2 Restador

El objetivo es crear un bloque que dados dos valores de entrada de n dígitos, x e y, calcule
la diferencia z, e indique mediante una señal de salida denominada carry_out si el
resultado ha sido positivo (carry_out = ‘0’) o negativo (carry_out = ‘1’),

Figura 3.9. Restador de n dígitos decimales

Para ello, nos basaremos en dos operaciones básicas; una es la suma descrita en el apartado
anterior, por lo que utilizaremos el Sumador de n dígitos decimales, y la otra es la
utilización del complemento a 10n del valor y de entrada. El complemento a 10n de un
número se puede obtener a partir de calcular el complemento a 9 de cada dígito (con un
bloque que haga esta función) y sumando 1 al resultado.

Un valor decimal x puede expresarse como:

xn-1 xn-2 … x1 x0 = xn-1 · 10n-1 + xn-1 · 10n-2 + … + x1 · 10 + x0, (3.3)

y su complemento a 9 equivale a

9 – xn-1 9 – xn-2 … 9 – x1 9 – x0 = 10n – 1 – (xn-1 xn-2 … x1 x0), (3.4)

por lo que podemos establecer la siguiente igualdad:

10n – (xn-1 xn-2 … x1 x0) = (9 – xn-1 9 – xn-2 … 9 – x1 9 – x0) + 1 (3.5)

Es decir, el complemento a 10n de un valor x equivale a realizar el complemento a 9 de


cada dígito y sumar 1 (lo que ya habíamos avanzado anteriormente).

Se puede calcular la resta mediante la expresión x + (10n – y), que plantea dos casos
posibles:

• Si x ≥ y: x + (10n – y) ≥ 10n , siendo z = x – y, con carry_out = ‘1’ (3.6)

• Si x < y: x + (10n – y) < 10n , siendo z = 10n + (x – y), con carry_out = ‘0’ (3.7)

- 26 -
Diseño sobre FPGA de una Unidad Aritmética Decimal Memoria descriptiva

3.2.1.2.1 Cálculo del complemento a 9 (bloque “nine_complement.vhd”)

Diseñamos un bloque que dado un dígito BCD de entrada (e), calcule su complemento a 9
(s). Este bloque estará controlado por una señal de entrada denominada add_sub,
encargada de habilitar o no la operación. Si su valor es ‘1’, s mostrará el complemento a 9
de e; en caso contrario s tomará el mismo valor que e.

Figura 3.10. Bloque de complemento a 9 de un dígito BCD

Dado un dígito BCD e de cuatro bits (e3 e2 e1 e0), su complemento a 9 (s3 s2 s1 s0) se
obtiene mediante la operación ‘1001’ – e3 e2 e1 e0 (o su equivalente, ‘1001’ + e3’ e2’ e1’ e0’
+ 1, es decir, sumando al minuendo el complemento a 2 del sustraendo). Las expresiones
resultantes son las siguientes:

s0 = e0
s1 = e1
(3.8)
s2 = e1 ⊕ e2
s3 = e1 ⋅ e2 ⋅ e3

Si añadimos la señal de control add_sub, dichas expresiones quedan modificadas de esta


forma:

s0 = add _ sub ⋅ e0 + add _ sub ⋅ e0


s1 = e1
(3.9)
s 2 = add _ sub ⋅ e2 + add _ sub ⋅ (e1 ⊕ e2 )
(
s3 = add _ sub ⋅ e3 + add _ sub ⋅ e1 ⋅ e2 ⋅ e3 )

Figura 3.11. Ejemplo del funcionamiento del bloque de complemento a 9

- 27 -
Diseño sobre FPGA de una Unidad Aritmética Decimal Memoria descriptiva

3.2.1.2.2 Sumador/Restador en complemento a 10n

Para implementar el restador utilizaremos, como hemos explicado antes, el sumador de n


dígitos y el bloque de complemento a 9 (nine_complement.vhd). El diagrama de bloques
resultante sería el mostrado a continuación:

Figura 3.12. Restador de n dígitos decimales

Si nos fijamos en la Figura 3.12, podemos ver que la señal de control add_sub nos permite
realizar las operaciones de suma y resta:

• Si add_sub = ‘0’, la señal y no se modifica y tenemos la operación suma (z = x + y)

• Si add_sub = ‘1’, lo que entra al sumador es el complemento a 9 de y; además la


señal de entrada del sumador ini_carry (acarreo de entrada) toma el valor de
add_sub, por lo que la operación que se realiza es la resta (z = x + y’ + ini_carry).

Debido a que podemos realizar las dos operaciones con un mismo bloque, lo
denominaremos Sumador/Restador de n dígitos.

- 28 -
Diseño sobre FPGA de una Unidad Aritmética Decimal Memoria descriptiva

3.2.1.3 Sumador/Restador, representación con signo y magnitud (bloque


“n_adder_subs.vhd”)

Observemos otra vez en el último bloque creado (Figura 3.12). Hemos visto que esta
estructura nos permite realizar las operaciones de suma y resta. Pongamos un par de
ejemplos sobre la resta siendo n = 3:

• Si x = 735 e y = 177 (su complemento a 9 es 822), tendremos 735 + 822 + 1 (del


acarreo de entrada, valor de la señal add_sub). El resultado será positivo e igual a
578, con el acarreo de salida (out_carry) igual a 1.

• Si x = 485 e y 823 (su complemento a 9 es 176), tendremos 485 + 176 + 1. El


resultado será 662 con un acarreo de salida igual a 0 (resultado negativo).

En este último caso, para saber el resultado exacto de la operación debemos calcular el
complemento a 10n del valor z que hemos obtenido; es decir, calcular el complemento a 9
de cada dígito de z y sumar 1 al resultado obtenido. Esto lo hacemos mediante una
modificación de la arquitectura anterior, por lo que el diagrama de bloques final del
Sumador/Restador de n dígitos BCD será el siguiente:

y(4n-1:0) z1
4n add_sub 4n

Complemento Complemento
x(4n-1:0) a9 a9
‘1’
4n 4n 4n 4n

oc Sumador de n Sumador de n
carry_out ini_carry ini_carry
ini_carry ‘0’
dígitos decimales dígitos decimales

4n 4n
z1 z3

0 1
add_sub
4n

z(4n-1:0)

Figura 3.13. Sumador/Restador de n dígitos decimales

- 29 -
Diseño sobre FPGA de una Unidad Aritmética Decimal Memoria descriptiva

Esta modificación implica un cambio en el significado del valor del acarreo de salida del
bloque (denominado carry_out), cuando realizamos la operación resta:

• Si carry_out = ‘0’, el resultado de la resta es no negativo (x > y)

• Si carry_out = ‘1’, el resultado de la resta es negativo (x < y)

Hemos añadido otro bloque que complementa a 9 el resultado z1 de la primera etapa y


posteriormente suma 1, lo que genera la señal z3. Dependiendo de los valores de add_sub y
oc (acarreo de la primera etapa), el multiplexor seleccionará z1 o z3. Concretamente,
cuando el resultado de la resta sea positivo (carry_out = ‘0’), el multiplexor seleccionará el
canal 0 (z1), y si el resultado es negativo (carry_out = ‘1’) seleccionará el canal 1 (z3).

A modo de resumen, el Sumador/Restador de n dígitos decimales presenta las siguientes


características:

add_sub Operación carry_out Resultado


0 Suma 0 Exacto
0 Suma 1 Hay desbordamiento
1 Resta 0 Positivo
1 Resta 1 Negativo

Tabla 3.1. Operaciones del Sumador/Restador

A continuación mostramos unos ejemplos de la simulación para n = 4:

En modo resta (add_sub = ‘1’):

Figura 3.14. Simulación del Sumador/Restador en modo resta

- 30 -
Diseño sobre FPGA de una Unidad Aritmética Decimal Memoria descriptiva

En modo suma (add_sub = ‘0’):

Figura 3.15. Simulación del Sumador/Restador en modo suma

- 31 -
Diseño sobre FPGA de una Unidad Aritmética Decimal Memoria descriptiva

3.2.2 Multiplicador

En este apartado crearemos un módulo que multiplique dos valores de entrada, x e y, de n y


m dígitos BCD respectivamente, y muestre el resultado en z, de n + m dígitos BCD.

Figura 3.16. Multiplicador de NxM dígitos BCD

Para ello lo primero que haremos será definir una estructura básica que realizará la
multiplicación de dos dígitos BCD (multiplicador de 1x1 dígitos BCD), después
realizaremos un bloque que multiplique un número de n por 1 dígitos BCD, y finalmente el
multiplicador de NxM dígitos BCD.

3.2.2.1 Multiplicador de 1x1 dígitos BCD (bloque “one_digit_multiplier.vhd”)

El producto decimal se puede obtener a través del producto binario y una etapa de
corrección posterior. La etapa básica sería un multiplicador de 1x1 dígitos BCD, es decir,
dos entradas de 1 dígito BCD cada una. Ésta se puede implementar a partir de un circuito
combinacional.

a(3:0) b(3:0)

4 4

Multiplicador de
1 dígito BCD

4 4

d(3:0) u(3:0)

Figura 3.17. Multiplicador de 1x1 dígitos BCD

- 32 -
Diseño sobre FPGA de una Unidad Aritmética Decimal Memoria descriptiva

Tenemos A y B que son dos dígitos BCD (a3 a2 a1 a0 y b3 b2 b1 b0 respectivamente). El


producto BCD de ambos dígitos se puede expresar como:

A ⋅ B = D ⋅ 10 + U , (3.10)

es decir, la cifra de las decenas multiplicada por 10 más las unidades.

El producto binario de A y B se puede expresar en un primer paso como un número de 7


bits tal que:

A ⋅ B = P = p6 p5 p4 p3 p2 p1 p0 (3.11)

Son un máximo de 7 bits porque el resultado máximo que podemos tener en esta operación
es 81 en decimal, que corresponderá al caso de que A y B tengan su valor máximo, y este
es 9. La representación binaria del número 81 es ‘1010001’ (7 bits).

Podemos convertir el número binario P a código BCD mediante sumas binarias tras
corregir los términos descritos en la Figura 3.18. La primera fila indica el peso de cada
dígito BCD. Los pesos de p3 p2 p1 p0 son los mismos que para el valor binario. Pero los
pesos de p4 p5 y p6 se pueden descomponer en los valores BCD de la Figura 3.18.
Concretamente, p4 (cuyo peso es 16 en binario) se puede descomponer como (10, 4, 2), p5
(peso binario igual a 32) se puede descomponer en (20, 10, 2) y por último p6 (peso binario
64) como (40, 20, 4).

80 40 20 8 104 2 1
p3 p2 p1 p0
p4 p4 p4
+ p5 p5 p5
p6 p6 p6
d3 d2 d1 d0 u3 u2 u1 u0

Figura 3.18. Reducción aritmética de binario a BCD

Sumamos los términos y obtenemos las expresiones que nos darán el valor de las unidades
(uu) y las decenas (dd):

uu = p3 p2 p1 p0 + 0 p4 p4 0 + 0 p6 p5 0
(3.12)
dd = p6 p5 p4 + 0 p6 p5

Dada esta última expresión de uu, podemos ver que su valor estará entre 0 y 27 (según los
valores de p0, p1, p2, p3, p4, p5 y p6). Si el valor de uu es superior a 9 (con lo que se
necesitaría de más de 1 dígito BCD para representarse) deberemos realizar una corrección
para obtener un resultado correcto. A continuación definimos dichos términos de
corrección:

• Si uu ≤ 9: no hacemos ninguna corrección, el valor es correcto,


• Si 9 < uu ≤ 19: sumamos 1 a dd, (añadimos 1 a las decenas y 6 a las unidades; esto
último equivale a restar 10),
• Si 19 < uu: sumamos 2 a dd, (añadimos 2 a las decenas y 12 a las unidades; esto
último equivale a restar 20).

- 33 -
Diseño sobre FPGA de una Unidad Aritmética Decimal Memoria descriptiva

Definiremos una variable para cada caso y mediante las siguientes expresiones booleanas
sabremos cual tenemos en cada momento.

• Si uu es mayor o igual a 10:

gt 9 = uu 4 ∨ uu 3 ⋅ (uu 2 ∨ uu1 ) (3.13)

• Si uu es mayor o igual a 20:

gt 20 = uu 4 ⋅ (uu 3 ∨ uu 2 ) (3.14)

• Si uu se encuentra entre 10 y 19 (ambos incluidos):

gt10st19 = gt 9 ⋅ gt 20 (3.15)

Por último obtenemos los valores finales para las decenas (d) y las unidades (u) al añadir
las correcciones pertinentes:

u = (uu3 uu2 uu1 uu0) + (gt20 gt9 gt10st19 0)


d = (dd3 dd2 dd1 dd0) + (0 0 gt20 gt10st19) (3.16)

Simulación

Figura 3.19. Muestra de la simulación del multiplicador de 1x1 dígitos BCD

3.2.2.2 Multiplicador de Nx1 dígitos BCD (bloque “n_by_one_multiplier.vhd”)

Un multiplicador de Nx1 dígitos BCD se puede construir a partir de n multiplicadores de


1x1 dígitos BCD seguido de sumadores BCD. Por tanto, para realizar este bloque
utilizaremos dos que hemos creado anteriormente; uno será el multiplicador que acabamos
de hacer (multiplicador de 1x1 dígitos BCD, one_digit_multiplier.vhd) y el otro será el
sumador de 1 dígito BCD (one_digit_adder.vhd).

- 34 -
Diseño sobre FPGA de una Unidad Aritmética Decimal Memoria descriptiva

Pongamos un ejemplo: si n es igual a 3, tendremos la siguiente estructura,

x2 y x1 y x0 y

4 4 4 4 4 4

4 Multipl. 4 Multipl. 4 Multipl.


1x1 BCD 1x1 BCD 1x1 BCD

4 4 4

d2 u2 d1 u1 d0 u0

Figura 3.20. Multiplicador de 3x1 dígitos BCD (parte 1)

donde x será el número de 3 dígitos BCD (x2 x1 x0). Cada multiplicador genera un valor
para las unidades (ux) y uno para las decenas (dx); este último será el que deba sumarse a
las unidades del siguiente multiplicador. Esta estructura nos muestra que necesitaremos un
sumador de n + 1 dígitos BCD.

El resultado z (formada por 4 dígitos BCD) será el siguiente:

z = (0 u2 u1 u0) + (d2 d1 d0 0) (3.17)

‘0’ d2 u2 d1 u1 d0 u0 ‘0’

4 4 4 4 4 4 4 4

Sumador 1 Sumador 1 Sumador 1 Sumador 1


dígito BCD dígito BCD dígito BCD dígito BCD

4 4 4 4

z3 z2 z1 z0

Figura 3.21. Multiplicador de 3x1 dígitos BCD (parte 2)

Viendo este ejemplo podemos afirmar que, para un multiplicador de Nx1 dígitos BCD,
necesitaremos n multiplicadores 1x1 y n + 1 sumadores de 1 dígito.

- 35 -
Diseño sobre FPGA de una Unidad Aritmética Decimal Memoria descriptiva

Tendremos dos señales de entrada: un valor x de n dígitos (xn-1 xn-2 … x2 x1 x0) y un valor y
de 1 dígito, lo que generará una señal de salida z (zn zn-1 zn-2 … z2 z1 z0).

Figura 3.22. Multiplicador de Nx1 dígitos. Incluye n multiplicadores 1x1 y n + 1 sumadores de 1 dígito

A continuación se muestra un ejemplo de la simulación del bloque para n = 5:

Figura 3.23. Simulación del multiplicador Nx1 dígitos BCD

- 36 -
Diseño sobre FPGA de una Unidad Aritmética Decimal Memoria descriptiva

3.2.2.3 Multiplicador de NxM dígitos BCD (bloque “n_by_m_multiplier.vhd”)

En este bloque tenemos como datos iniciales dos números decimales, x e y, de n y m


dígitos respectivamente (xn-1 xn-2 … x2 x1 x0 e ym-1 ym-2 … y2 y1 y0). El resultado será z, un
número decimal de n + m dígitos (z(n+m)-1 z(n+m)-2 … z2 z1 z0).

Figura 3.24. Multiplicador de NxM dígitos BCD

También tendremos las entradas start (indica inicio de operación), clk (señal de reloj) y
reset (que inicializa el bloque), y la salida done (que informa de operación realizada).

Los valores n y m serán los parámetros genéricos del circuito.

Para realizar esta operación vamos a crear un sistema secuencial (a diferencia de los que
habíamos hecho hasta ahora, que eran combinacionales) en el que mediante un bucle,
utilizaremos m veces el multiplicador de Nx1 dígitos (n_by_one_multiplier.vhd) y
sumaremos y almacenaremos los resultados parciales (mediante el bloque
n_adder_subs.vhd en modo suma y registros internos).

Que sea un sistema secuencial ayudará a reducir el coste del mismo, ya que utilizaremos un
solo multiplicador en lugar de utilizar m multiplicadores de Nx1.

El algoritmo que utilizaremos será el siguiente:

z := 0;
for i in 1 .. m loop
z := z · 10 + x · ym-i;
end loop;

- 37 -
Diseño sobre FPGA de una Unidad Aritmética Decimal Memoria descriptiva

El diagrama de bloques del circuito es:

y(4m-1:0) ‘1111’

4m 4
x(4n-1:0)
int_y(m) load
4n 4
left shift register y shift
clk

Multiplicador Nx1
dígitos BCD
z_by_10
4(n+1) x_by_yi
4(n+m)
Sumador n
dígitos BCD
x 10
next_z

load
register z shift
clk

z(4(n+m)-1:0)

Figura 3.25. Diagrama de bloques del multiplicador NxM

El funcionamiento es el siguiente: se inicializa el registro de desplazamiento (load = ‘1’)


con el valor de y seguido de un dígito no decimal (15 = ‘1111’), que será el indicador de
que ya hemos multiplicado todos los valores de y. A cada etapa (shift = ‘1’) se desplaza el
valor una posición (4 bits) a la izquierda. De esta manera entrarán sucesivamente en el
multiplicador Nx1 los dígitos ym-1, ym-2, … y1, y0; una señal interna detectará el ‘1111’ e
indicará el fin de cálculo.

En el multiplicador Nx1 tendremos en una entrada el valor de x, multiplicando cada vez


por el dígito de y correspondiente. Es decir, en un primer paso el multiplicador realizaría el
producto de xn-1 xn-2 … x1 x0 e ym-1. El valor resultante pasaría al sumador, donde no se
modificaría ya que el registro z se inicializa con 0, y se almacenaría en dicho registro.

En la siguiente etapa, se desplazará el registro de desplazamiento otra posición; en el


multiplicador ahora tendremos como entradas xn-1 xn-2 … x1 x0 e ym-2. En el sumador
tendremos como entradas el último producto generado y el primer valor que se almacenó
en el registro z multiplicado por 10.

Este proceso se repite hasta que se detecta el dígito no decimal ‘1111’ en el registro de
desplazamiento que indica que se han leído todos los valores de y.

- 38 -
Diseño sobre FPGA de una Unidad Aritmética Decimal Memoria descriptiva

En la siguiente figura podemos ver una simulación del proceso, donde hemos establecido
n = 3 y m = 4:

Figura 3.26. Simulación del multiplicador NxM dígitos BCD

Para controlar este sistema secuencial necesitaremos una unidad de control. Dicha unidad
recibirá como señales de entrada start, clk, reset y end_of_computation, y generará las
señales shift, load y done:

Figura 3.27. Unidad de control

La unidad de control se puede representar con una máquina de 4 estados:

end_of_ computation = 1

start = 1 start = 0 end_of_ computation = 0

start = 0 start = 1
E0 E1 E2 E3

shift = 0 shift = 0 shift = 0 shift = 1


load = 0 load = 0 load = 1 load = 0
done = 1 done = 1 done = 0 done = 0

Figura 3.28. Máquina de estados de la unidad de control

- 39 -
Diseño sobre FPGA de una Unidad Aritmética Decimal Memoria descriptiva

E0 es el estado inicial (señal current_state), con un bucle de espera para que la señal start
pase a nivel bajo y avanzar al estado 1 (caso de que start se haya mantenido a ‘1’ como
consecuencia de una operación anterior).

Aquí se espera a que start sea igual ‘1’ (lo que hemos hecho ha sido detectar la transición
de ‘0’ a ‘1’ de esta señal). En E2 se cargan los valores iniciales en los registros (load = ‘1’).
Entonces pasamos a E3, donde se ejecutan las etapas de cálculo (shift = ‘1’) hasta que la
señal end_of_computation sea igual a ‘1’, lo que significará que el dígito leído int_y es 15
(‘1111’) y ha finalizado la operación, volviendo al estado inicial y poniendo la señal done a
‘1’, indicando que el proceso ha terminado.

- 40 -
Diseño sobre FPGA de una Unidad Aritmética Decimal Memoria descriptiva

3.2.3 Divisor

3.2.3.1 Algoritmo de división binaria

Dados dos números naturales x e y, siendo x < y, el algoritmo de división binaria genera
dos naturales q y r tales que:

x ⋅ 2 p = q ⋅ y + r , con r < y (3.18)

Así
x = q ⋅ y ⋅ 2− p + r ⋅ 2− p , (3.19)

y
x r r
= q ⋅ 2 − p + ⋅ 2 − p , siendo ⋅ 2 − p < 2 − p (3.20)
y y y

El algoritmo se basa en el siguiente conjunto de igualdades:

r0 = x, de modo que r0 < y,


2 · r0 = qp-1 · y + r1, con r1 < y,
2 · r1 = qp-2 · y + r2, con r2 < y,
2 · r2 = qp-3 · y + r3, con r3 < y,

2 · rp-1 = q0 · y + rp, con rp < y, (3.21)

Multiplicando la primera ecuación por 2p, la segunda por 2p-1, la tercera por 2p-2,…, y la
última por 20, y sumando las p ecuaciones tenemos que:

x · 2p = (qp-1 · 2p-1 + qp-2 · 2p-2 + qp-3 · 2p-3 + … + q0 · 20) y + rp (3.22)

Si comparamos la expresión con (3.18), podemos obtener q y r ya que:

q = 0. qp-1 qp-2 qp-3 … q0 y r = rp (3.23)

En cada paso se calculan qp-i y ri en función de ri-1 e y:

2 · ri-1 = qp-i · y + ri, siendo ri < y (3.24)

Se plantean dos opciones:

• 2 · ri-1 ≥ y : entonces

qp-i = 1 y ri = 2 · ri-1 – y (3.25)

• 2 · ri-1 < y : entonces


qp-i = 0 y ri = 2 · ri-1 (3.26)

- 41 -
Diseño sobre FPGA de una Unidad Aritmética Decimal Memoria descriptiva

3.2.3.2 Algoritmo de división BCD

El algoritmo de división binaria se puede utilizar cualquiera que sea el sistema de


numeración. Si trabajamos en base 10, la única condición para poder utilizarlo es que todas
las operaciones se hagan en base 10.

El algoritmo que utilizaremos será el siguiente:

r := x; q := 0; ulp := 0.5;
for i in 1 .. p loop
two_r := 2*r; dif := two_r - y;
if dif < 0 then r := two_r;
else r := dif; q := q + ulp;
end if;
ulp := ulp/2;
end loop;

Las operaciones en BCD que utilizaremos serán la multiplicación por 2, la resta con
generación de signo y la suma. Además, la representación BCD de 1/2, 1/22, ..., 1/2p será
calculada sobre la marcha.

3.2.3.3 Error generado

Si se ejecutan p etapas, el error es menor que 1/2p (según el algoritmo). Supongamos que el
objetivo sea que el resultado se escriba con m dígitos fraccionarios y que el error sea menor
que 1/10m (significa que el resultado obtenido es el cociente exacto truncado). Para ello
basta con que se cumpla la siguiente relación:
p m
⎛1⎞ ⎛1⎞
⎜ ⎟ < ⎜ ⎟ , es decir p > m ⋅ log 2 (10) , o sea que p > 3.3 ⋅ m (3.27)
⎝2⎠ ⎝ 10 ⎠

- 42 -
Diseño sobre FPGA de una Unidad Aritmética Decimal Memoria descriptiva

3.2.3.4 Divisor BCD (bloque “divider.vhd”)

El divisor BCD será un módulo que realice la división entre dos valores de entrada, x / y,
donde x < y (para que el algoritmo funcione), dando como resultado el cociente q de m
dígitos decimales (qm-1 qm-2 … q2 q1 q0).

También tendrá como entradas las señales start (inicio de operación), clk (señal de reloj) y
reset (que inicializa el bloque), y la salida done (que informa de operación realizada).

Figura 3.29. Divisor BCD

El cociente q es una salida de m dígitos. Internamente, el cociente debe generarse con p


dígitos, donde p es del orden de 3.3m (según hemos explicado anteriormente). Llámese qq
al cociente interno con p dígitos. El cociente q (el resultado que nosotros veremos) consta
de los m dígitos más significativos de qq.

Los valores de n (dígitos de los valores de entrada), m (dígitos y por tanto precisión del
resultado, el cociente), p (número de iteraciones que se realizarán) y logp (número de bits
necesario para representar p) serán los parámetros genéricos del modelo.

- 43 -
Diseño sobre FPGA de una Unidad Aritmética Decimal Memoria descriptiva

Basándonos en el algoritmo de ejecución creamos el siguiente diagrama de bloques:

r ‘0010’
4n 4

Multiplicador
Nx1 dígitos BCD

4n+4
qq ulp
y(4n-1:0)
rr 4p 4p
4n ulp ‘0101’

4p 4
carry_out add_sub ‘1’ carry_out add_sub ‘0’
Sumador/Restador Sumador/Restador
n dígitos BCD n dígitos BCD Multiplicador
Nx1 dígitos BCD

rr_y(4n-5:0)
4p+4
4p
load
clk initially: 0.5
0 1 0 1

4p
4n 4p
ulp
load ini.: x(4n-1:0) initially: 0
clk

4p 4p
4n
qq
4p-4(p-m)

r
q(4m-1:0)

Figura 3.30. Diagrama de bloques del divisor BCD

Inicialmente cargamos en el registro r el valor de entrada x.

Para calcular el doble de r utilizamos un multiplicador de Nx1 dígitos BCD


(n_by_one_multiplier.vhd). En una entrada tendremos el valor r y en la otra el dígito 2
(‘0010’ en binario).

La diferencia entre el doble de r (2r, señal rr) y el valor decimal de entrada y, la


calculamos mediante un Sumador/Restador de n dígitos BCD (n_adder_subs.vhd) en
modo resta (señal de entrada add_sub = ‘1’).

Si el resultado de la resta es positivo (rr > y) entonces carry_out = ‘0’ y se almacenarán en


el registro r los n dígitos menos significativos de la diferencia recién calculada (rr - y). Si
por el contrario rr < y, carry_out = ‘1’, se almacenarán en el registro los n dígitos menos
significativos del valor de rr.

- 44 -
Diseño sobre FPGA de una Unidad Aritmética Decimal Memoria descriptiva

El registro qq donde se almacenan los valores intermedios del cociente se inicializa a 0.

La suma de qq y ulp la calculamos mediante un Sumador/Restador de n dígitos BCD


(n_adder_subs.vhd) que opere en modo suma (add_sub = ‘0’). Si el resultado antes
calculado de rr - y es positivo, se almacenará en el registro qq el resultado de qq + ulp; si
es negativo, lo que se almacene será el valor de qq.

La señal ulp (Unit in the Least significant Position, unidad en la posición menos
significativa) es un número que al final del cálculo tendrá p dígitos. Su registro
(register_ulp) se inicializa con el valor 0.5 (‘0000 0101’ en código BCD). En cada
iteración irá tomando los valores 0.5, 0.25, 0.125, 0.0625, y así sucesivamente; es decir,
multiplicando el anterior valor por 5 (mediante el multiplicador de Nx1 dígitos,
n_by_one_multiplier.vhd) y desplazando el resultado 4 bits a la derecha (o lo que es lo
mismo, introduciendo un 0 decimal delante). Al ser la salida del multiplicador por 5 un
número de p + 1 dígitos, sólo utilizaremos los p dígitos de más peso (lo que equivale a
dividir por 10).

Al acabar el cálculo de la operación (señal zero = ‘1’), obtendremos el cociente q de


truncar el último valor almacenado en el registro qq, a partir del número de dígitos m que
hayamos seleccionado.

Unidad de control

Este sistema que hemos creado también es secuencial y necesitará de una unidad de control
que lo gobierne.

Figura 3.31. Unidad de control del divisor

La unidad de control genera las señales load (escritura de los valores iniciales en los
registros), ce (actualización de los registros) y done (operación finalizada).

La señal zero vendrá controlada por un contador de p estados (este número se representa
con logp bits, como hemos dicho antes). Dicha señal se pondrá a ‘1’ cuando se ejecute el
paso p de la iteración.

- 45 -
Diseño sobre FPGA de una Unidad Aritmética Decimal Memoria descriptiva

La máquina de estados asociada a la unidad de control es la siguiente:

Figura 3.32. Máquina de estados de la unidad de control del divisor

Simulación

A continuación mostramos un ejemplo de la simulación del sistema para los valores


genéricos n = 3, m = 8, p = 27 y logp = 5:

Figura 3.33. Simulación del divisor

La división entre x = 335 e y = 927 genera el cociente q = 36138079, que representa


0.36138079 (como x < y, el primer dígito siempre es 0). Al haber definido m = 8, el
cociente está representado por 8 dígitos decimales.

- 46 -
Diseño sobre FPGA de una Unidad Aritmética Decimal Memoria descriptiva

Podemos observar con mayor facilidad en la Figura 3.34 la transición entre estados, y
vemos como, desde el estado 0 (señal current_state) y dado que la señal start es ‘0’,
pasamos al estado 1 (en caso de que start se hubiera mantenido a ‘1’ como resultado de un
cálculo anterior, el sistema esperaría a que dicha señal se pusiera a ‘0’).

Figura 3.34. Ampliación de la Figura 3.33

En el estado 1 y tras detectar un flanco de subida de la señal start, pasamos al estado 2,


donde la unidad de control activa (a ‘1’) la señal load y se escriben los valores iniciales en
los registros. La señal done se pone a ‘0’ indicando que hay una operación en curso.

Tras un ciclo de reloj pasamos al estado 3 y se inicia el cálculo; aquí empieza a funcionar
el contador regresivo (count) de p estados (27 en el ejemplo, de 26 a 0) que determina el
número de iteraciones a realizar. También se activa la señal ce que permitirá actualizar los
registros. Cuando el contador llegue a 0, dejarán de actualizarse los registros (ce = ‘0’) y se
activará la señal zero informando del fin de cálculo (esto se puede ver en la Figura 3.33),
volviendo al estado 0 y poniéndose el indicador de operación realizada done a nivel alto.

- 47 -
Diseño sobre FPGA de una Unidad Aritmética Decimal Memoria descriptiva

3.3 Diseño de la Unidad Aritmética Decimal (bloque “arithmetic_unit.vhd”)

El siguiente paso es la definición de la Unidad Aritmética Decimal, una estructura que


integre los tres bloques anteriores (Sumador/Restador de n dígitos decimales,
Multiplicador de NxM dígitos BCD y Divisor BCD).

Figura 3.35. Unidad Aritmética Decimal

Los parámetros genéricos del modelo serán:

• n: tamaño de los operandos (en dígitos decimales) de x e y


• p: número de etapas de la división
• logp: número de bits necesario para representar p

Este bloque estará controlado por una señal de entrada llamada operation, mediante la cual
se indicará a la unidad la operación a realizar:

operation Operación Resultado


00 Suma z=x+y
01 Resta z=x-y
10 Multiplicación z=x·y
11 División z = x / y (con una precisión de 2n dígitos fraccionarios)

Tabla 3.2. Operaciones de la Unidad Aritmética Decimal

Tanto para la suma como la resta z tendrá un tamaño de 4n + 1 bits (el bit de mayor peso
corresponde a la señal carry_out del bloque Sumador/Restador), mientras que para la
multiplicación y división el tamaño será de 8n bits.

En la multiplicación y la división el cálculo empieza con un flanco de subida de la señal de


entrada start. La bandera done se pone a ‘0’. Una vez disponible el resultado, done tomará
el valor ‘1’.

- 48 -
Diseño sobre FPGA de una Unidad Aritmética Decimal Memoria descriptiva

El diagrama de bloques de la unidad se muestra a continuación:

x(4n-1:0)
y(4n-1:0)
operation1
operation0
start

4n 4n 4n 4n 4n 4n

carry_out add_sub
c_out Sumador/Restador
Multiplicador de Divisor de n
start1 NxM dígitos BCD start2 dígitos BCD
n dígitos BCD
clk clk
reset reset
4n 8n 8n
s2 done1 done2
s1 s3

‘1’

00 01 10 11 00 01 10 11 00 01 10 11
operation MUX-1 MUX-2 MUX-3

4n 4n 4n

z(4n-1:0) z(8n-1:4n) done

Figura 3.36. Diagrama de bloques de la Unidad Aritmética Decimal

De cara a la implementación en la FPGA, el operando y del Multiplicador de NxM dígitos


decimales pasará de estar formado por m dígitos a estarlo por n (podemos decir que ahora
el bloque es un “Multiplicador de n dígitos decimales”) De esta manera unificamos los
valores de entrada, que siempre estarán formados por n dígitos decimales.

Utilizaremos el bit de menor peso de la señal operation para indicar al Sumador/Restador


la operación a realizar (entrada add_sub de éste).

Para habilitar el bloque multiplicador utilizaremos la señal start1, que es la salida de una
puerta AND de tres entradas (los dos bits de operation, con el de menor peso negado, y
start). Para el divisor utilizaremos start2, resultado de una puerta AND también de tres
entradas, pero esta vez sin negar el bit de menos peso de operation.

Figura 3.37. Circuito generador de las señales start1 y start2

- 49 -
Diseño sobre FPGA de una Unidad Aritmética Decimal Memoria descriptiva

La salida del primer multiplexor (MUX-1) muestra el resultado de las operaciones suma
(operation = ‘00’) o resta (operation = ‘01’), y la parte baja del resultado de las
operaciones multiplicación (operation = ‘10’) o división (operation = ‘11’), que sería
z(4n-1:0).

El segundo multiplexor recibe a través de sus dos primeros canales el valor de la señal
carry_out del Sumador/Restador (llamada c_out). Como este valor ocupa 1 solo bit, los
otros bits del dígito de menos peso serán 0 (el dígito de menor peso, 4n+3:4n, estará
formado por ‘0 0 0 c_out’); los demás dígitos (8n-1:4n+4) serán 0. Para la multiplicación y
la división mostrará la parte alta del resultado, los dígitos de mayor peso (8n-1:4n).

MUX-3 muestra el valor actual de la señal done, que estará a nivel alto excepto cuando se
realice el cálculo de la multiplicación o de la división (periodo en que la señal se pondrá a
nivel bajo, debido a que done1 o done2 tomarán este valor).

A continuación se muestra una simulación del sistema con los parámetros n = 8 y p = 56


(en consecuencia logp = 6), para las diferentes operaciones:

Figura 3.38. Simulación de la Unidad Aritmética Decimal (suma y resta)

En este ejemplo podemos ver las operaciones suma y resta. Los valores de entrada son x =
00867335 e y = 02350927 (ambos de 8 dígitos BCD, ya que habíamos establecido n = 8).
Primero se realiza la suma (operation = ‘00’), siendo el resultado z = 03218262; como no
hay desbordamiento en el resultado, c_out (acarreo de salida) es 0. Al cambiar operation a
‘01’ obtenemos la resta, siendo z = 01483592; en este caso el dígito de menor peso de la
parte alta de z es 1 (00000001), lo que indica que el resultado es negativo (z = – 1483592).

Seguidamente mostramos la simulación de la unidad cuando queremos realizar la


multiplicación de dos valores (seleccionando operation = ‘10’):

- 50 -
Diseño sobre FPGA de una Unidad Aritmética Decimal Memoria descriptiva

Figura 3.39. Simulación de la Unidad Aritmética Decimal (multiplicación)

Al iniciarse el cálculo, la señal que lo indica (done1) se pone a ‘0’, lo que provoca que la
salida del sistema done también lo haga. Al acabar la ejecución, done1 vuelve a nivel alto y
done también. Vemos como start1 se activa habilitando el multiplicador, en cambio start2
sigue a nivel bajo.

Por último tenemos la simulación de la unidad cuando ejecutamos la operación de división


(operation = ‘11’).

Figura 3.40. Simulación de la Unidad Aritmética Decimal (división)

Observamos la influencia de la señal done2 en done (tomando el valor ‘0’ durante la


ejecución, las p etapas que habíamos explicado anteriormente). El resultado z se debe leer
como 0.3689331910348556.

- 51 -
Diseño sobre FPGA de una Unidad Aritmética Decimal

4. MEMORIA EXPERIMENTAL
Diseño sobre FPGA de una Unidad Aritmética Decimal Memoria experimental

4.1 Descripción del proceso ........................................................................................................... 54


4.2 Especificaciones ........................................................................................................................ 54
4.3 Elementos necesarios................................................................................................................ 55
4.4 Arquitectura a desarrollar ...................................................................................................... 55
4.5 Módulos IP de terceros utilizados........................................................................................... 57
4.5.1 Microcontrolador PicoBlaze (módulo “kcpsm.vhd”)........................................................ 57
4.5.2 Interfaz LCD (módulo “lcd_interface.vhd”)..................................................................... 58
4.6 Memoria de programa (módulo “program_memory.vhd”) ................................................... 60
4.7 Generación del circuito (módulo “main.vhd”) ....................................................................... 62
4.8 Asignación de pines en la FPGA (archivo “pins.ucf”) .......................................................... 63
4.9 Implementación en la FPGA ................................................................................................... 65
4.9.1 Generación del archivo ..................................................................................................... 66
4.9.2 Implementación en la FPGA ............................................................................................ 68

- 53 -
Diseño sobre FPGA de una Unidad Aritmética Decimal Memoria experimental

4.1 Descripción del proceso

En este capítulo describiremos la implementación del componente virtual que hemos


creado, la Unidad Aritmética Decimal, en la plataforma FPGA Spartan-3E Starter Kit, con
el fin de comprobar su correcto funcionamiento.

Para ello debemos estructurar un sistema completo, con una CPU que gobierne el sistema,
una memoria de programa con el juego de instrucciones que se ejecutarán, una interfaz que
visualice los datos en la pantalla de la placa, y nuestra unidad, como principales elementos.

Como CPU utilizaremos un módulo IP proporcionado por Xilinx, el microcontrolador de 8


bits PicoBlaze (kcpsm.vhd); para la interfaz de visualización de datos, el módulo
lcd_interface.vhd, que es un módulo previamente generado en proyectos anteriores

El primer paso consistirá en la creación de la memoria de programa que utilizará


PicoBlaze, utilizando la aplicación pBlaze IDE. Después crearemos un modelo VHDL que
incluya los módulos mencionados antes. Por último, implementaremos todo el diseño en la
FPGA mediante el paquete Xilinx ISE Desing Suite.

4.2 Especificaciones

Consideremos las dos líneas de 16 caracteres cada una que posee la placa, y que se
distribuyen de la siguiente manera: en la primera línea, los 8 primeros dígitos (BCD)
corresponden al operando x, y los 8 últimos al operando y. La segunda línea será el
resultado z.

Figura 4.1. Posicionamiento de los dígitos en el display

Un primer pulso (pulso 0) de synch (señal de sincronización) borra el display. Mediante los
interruptores SW3, SW2, SW1 y SW0 (pesos 8, 4, 2, 1 respectivamente) el dígito de
entrada, y con el pulsador synch procedemos a almacenarlo en el registro interno
correspondiente y visualizarlo en pantalla.

Tras haber introducido los 16 dígitos (los 8 primeros para el operando x y los 8 siguientes
para el operando y), un nuevo pulso de synch muestra en el display el resultado de la suma;
en los sucesivos pulsos de synch veremos los resultados de la resta, la multiplicación y la
división. Un último pulso (pulso 21) dará la señal para limpiar el visualizador.

- 54 -
Diseño sobre FPGA de una Unidad Aritmética Decimal Memoria experimental

La siguiente figura ilustra el proceso que acabamos de describir:

pulso 0

pulso 1 0

pulso 2 02

pulso 3 028
...
pulso 16 0 2 8 6 7 3 3 5 5 0 2 9 9 7 2 3

pulso 17 0 2 8 6 7 3 3 5 5 0 2 9 9 7 2 3
0000000053167058
pulso 18 0 2 8 6 7 3 3 5 5 0 2 9 9 7 2 3
0000000147432388
...
pulso 21

Figura 4.2. Funcionamiento del sistema

4.3 Elementos necesarios

De acuerdo a las especificaciones, precisamos los siguientes elementos de la Spartan-3E


Starter Kit:

• Interruptores SW3, SW2, SW1, SW0 para seleccionar el dígito BCD de entrada
data_in.
• Pulsadores para las señales synch (de sincronización) y reset.
• Visualizador LCD de la placa.
• Oscilador de 50 MHz.

4.4 Arquitectura a desarrollar

Debemos elaborar una arquitectura capaz de llevar a cabo el proceso descrito


anteriormente. Dicha arquitectura deberá disponer (entre otras cosas) de:

• Una CPU que controle la entrada de dígitos, la codificación (a ASCII) de los datos
y la ejecución de las diferentes operaciones. Las operaciones se definirán mediante
un juego de instrucciones en lenguaje ensamblador, que posteriormente formarán la
memoria de programa.
• Una interfaz para el display LCD.
• La Unidad Aritmética Decimal.

- 55 -
Diseño sobre FPGA de una Unidad Aritmética Decimal Memoria experimental

Podemos definir la arquitectura del sistema mediante el siguiente diagrama de bloques:

data_in synch

mult_out
in_port done
15 …. 0

z (15:0)

PicoBlaze
reset port_id
(CPU and Unidad Aritmética
clk program memory) write_strobe start Decimal
reset
clk

operation y (7:0) x (7:0)


out_port
Registro Registro Registro
clk 2 bits 8*4 bits 8*4 bits

Registro Registro
clk
temp_write i_write d_write

ready
lcd_interface

lcd_data lcd_e lcd_rs lcd_rw

Figura 4.3. Diagrama de bloques del sistema

Como CPU del sistema utilizaremos el microcontrolador PicoBlaze proporcionado por


Xilinx; emplearemos dos componentes virtuales más, el modelo VHDL de una interfaz
LCD y nuestra Unidad Aritmética Decimal, que es el módulo que queremos testear.

- 56 -
Diseño sobre FPGA de una Unidad Aritmética Decimal Memoria experimental

4.5 Módulos IP de terceros utilizados

En este apartado hablaremos un poco sobre los dos componentes virtuales que utilizaremos
y que son suministrados por terceros.

4.5.1 Microcontrolador PicoBlaze (módulo “kcpsm.vhd”)

PicoBlaze es el nombre del modelo VHDL de un microcontrolador de 8 bits (KCPSM –


Constant (K) Coded Programmable State Machine) desarrollado por Xilinx y que puede ser
integrado en las FPGA de la familia Spartan-3E, entre otras.

Este módulo no requiere soporte externo y proporciona un entorno flexible para conectarlo
a otros componentes. Se suministra como descripción VHDL.

El ensamblador pBlaze IDE permite crear el modelo VHDL de la memoria de programa


que utilizará el microcontrolador.

Algunas características de PicoBlaze son:

• Posee 16 registros de 8 bits de propósito general (s0 a sF).


• 256 puertos de entrada y 256 de salida.
• Rápida respuesta a interrupciones (el peor caso es de 5 ciclos de reloj).
• Soporta programas de hasta 256 instrucciones.
• El tamaño de las instrucciones es de 16 bits.
• Todas las instrucciones se ejecutan en 2 ciclos de reloj.

Estructura

A continuación podemos ver el diagrama de bloques del módulo PicoBlaze.

Figura 4.4. Diagrama de bloques del módulo PicoBlaze

- 57 -
Diseño sobre FPGA de una Unidad Aritmética Decimal Memoria experimental

Arquitectura

Figura 4.5. Arquitectura interna de PicoBlaze

4.5.2 Interfaz LCD (módulo “lcd_interface.vhd”)

Es un módulo VHDL que añade la funcionalidad necesaria para presentar datos en el


visualizador de la FPGA.

temp_write i_write d_write

ready
reset lcd_interface
clk

lcd_data lcd_e lcd_rs lcd_rw

Figura 4.6. Módulo lcd_interface

- 58 -
Diseño sobre FPGA de una Unidad Aritmética Decimal Memoria experimental

La entrada de 8 bits temp_write puede ser un carácter (código ASCII) o un comando. La


entrada de control i_write envía el comando temp_write a la pantalla, y la entrada de
control d_write hace lo mismo pero con un carácter (Figura 4.7). La señal ready se activa
cuando la interfaz está disponible para una nueva operación.

Figura 4.7. Operaciones

Este componente implementa internamente 4 retardos diferentes mediante un contador


programable, para una correcta visualización de los datos en el display:

• very long: 3.218 clock cycles; at 50 MHz: 786,432 x 20 ns ≈ 16 ms;

• long: 213 clock cycles; at 50 MHz: 8,19 x 20 ns ≈ 160 μs;

• short: 50 clock cycles; at 50 MHz: 50 x 20 ns = 1 μs;

• very short: 12 clock cycles; at 50 MHz: 12 x 20 ns = 240 ns.

Los comandos que utilizaremos son los siguientes:

comando (hex.) Operación


01 Limpiar el display
80 Fijar el cursor al inicio de la primera línea
C0 Fijar el cursor al inicio de la segunda línea

Tabla 4.1. Comando utilizados

- 59 -
Diseño sobre FPGA de una Unidad Aritmética Decimal Memoria experimental

El diagrama de bloques de la interfaz LCD es el siguiente:

d_write temp_write
very_short very_long
short long

ce ce_cd
0 1 2 3 sel_delay

status cd(7..0)
(to control unit) load
load
counter
cd(7..4) cd(3..0)

time_out
1 0 (to control unit)
sel_nibble

i_write s_write ready


nibble
(to control unit)
status
time_out ce_cd
nibble sel_nibble
control unit sel_delay
load
reset
clk

lcd_data lcd_e lcd_rs lcd_write


(= 0)

Figura 4.8. Circuito de la interfaz LCD

4.6 Memoria de programa (módulo “program_memory.vhd”)

El primer paso consiste en realizar la memoria de programa. Para ello, realizaremos un


programa en lenguaje ensamblador (decimal_unit.asm) definiendo las direcciones de
entrada y salida, los registros que se emplearán y las instrucciones que se ejecutarán
(incluyendo un programa principal y diversas subrutinas). Este paso lo llevaremos a cabo
mediante la aplicación pBlaze IDE, que nos permitirá ensamblar y simular nuestro código,
y generará, a partir de un modelo “en blanco” (my_ROM_blank.vhd) el modelo VHDL de
la memoria de programa (program_memory.vhd).

Definimos las direcciones de entrada según la siguiente tabla:

señal dirección
z 00 a 0f
synch 10
data_in 11
ready 12
done 13
Tabla 4.2. Direcciones de entrada

- 60 -
Diseño sobre FPGA de una Unidad Aritmética Decimal Memoria experimental

Y las de salida:

señal dirección
y 00 a 07
x 08 a 0f
temp_wr 10
id_write 11
start 12
operation 13
Tabla 4.3. Direcciones de salida

El algoritmo utilizado sería el siguiente:

external loop (infinite)


send command 01 (clear) to display;
send command 80 (cursor address = 00) to display;
internal loop (16 times)
wait for a positive edge on synch;
store data_in in data;
write data into x(i) and y(i);
encode data;
display character data;
end internal loop;
wait for a positive edge on synch;
store 01 (addition) in data;
write data into operation;
display z;
wait for a positive edge on synch;
store 02 (substraction) in data;
write data into operation;
display z;
wait for a positive edge on synch;
store 03 (multiplication) in data;
write data into operation;
start multiplier;
wait for done;
display z;
wait for a positive edge on synch;
store 04 (division) in data;
write data into operation;
start divider;
wait for done;
display z;
end external loop;

Con el objetivo de reducir el tamaño del código, se incluiría una subrutina (entre otras) que
mostrara el resultado z en el visualizador después de cada operación:

subroutine display z;
send command c0 (cursor address = 40) to display;
internal loop (16 times)
store z(i) in data;
encode data;
display character data;
end internal loop;

- 61 -
Diseño sobre FPGA de una Unidad Aritmética Decimal Memoria experimental

4.7 Generación del circuito (módulo “main.vhd”)

Con los modelos VHDL disponibles, el microcontrolador PicoBlaze (kcpsm.vhd) y la


memoria de programa (program_memory.vhd), la interfaz LCD (lcd_interface.vhd) y la
Unidad Aritmética Decimal (arithmetic_unit.vhd), ya podemos diseñar nuestro circuito
completo. Añadiremos varios registros necesarios para el funcionamiento del sistema.

El diagrama de bloques es el que hemos mostrado antes:

data_in synch

mult_out
in_port done
15 …. 0

z (15:0)

PicoBlaze
reset port_id
(CPU and Unidad Aritmética
clk program memory) write_strobe start Decimal
reset
clk

operation y (7:0) x (7:0)


out_port
Registro Registro Registro
clk 2 bits 8*4 bits 8*4 bits

Registro Registro
clk
temp_write i_write d_write

ready
lcd_interface

lcd_data lcd_e lcd_rs lcd_rw

Figura 4.9. Diagrama de bloques del sistema

Definiremos la Unidad Aritmética Decimal con los siguientes parámetros:

• n = 8, lo que quiere decir que los operandos x e y serán de 8 dígitos BCD cada uno,
• p = 56, es el número de etapas que se ejecutarán para calcular el resultado cuando
realicemos la división,
• logp = 6, que son los bits necesarios para representar el valor de p.

- 62 -
Diseño sobre FPGA de una Unidad Aritmética Decimal Memoria experimental

Utilizaremos 2 registros de 32 bits (8 dígitos BCD por 4 bits cada uno) para almacenar los
valores que se vayan introduciendo de los operandos x e y; en el caso de la señal operation
tendremos suficiente con un registro de 2 bits.

Otros 2 registros más serán necesarios para las señales temp_write y i_write/d_write de la
interfaz LCD.

También incluiremos un divisor de frecuencia ya que la proporcionada por el reloj de la


placa es demasiado alta (50 MHz). En el circuito se añaden cuatro divisores de frecuencia
que generan clk_2, clk_4, clk_8 y clk; esta última señal es la que se utilizará como señal de
reloj de los diferentes bloques del circuito. Cada divisor reduce la frecuencia anterior a la
mitad, por lo que tras 4 divisores, la frecuencia inicial de 50 MHz se dividirá por 16 y
obtendremos una frecuencia de trabajo de 3.125 MHz.

4.8 Asignación de pines en la FPGA (archivo “pins.ucf”)

El siguiente paso consiste en crear un archivo UCF (User Constraint File) que asigne las
señales que utilizamos a los pines correspondientes de la Spartan-3E. Las descripciones
necesarias para cada elemento de la placa se pueden encontrar en la Spartan-3E Starter Kit
Board User Guide.

Los interruptores SW3 (mayor peso), SW2, SW1 y SW0 (menor peso) serán asignados a
los siguientes pines (entre paréntesis):

• data_in<3> → SW3 (N17)


• data_in<2> → SW2 (H18)
• data_in<1> → SW1 (L14)
• data_in<0> → SW0 (L13)

Figura 4.10. Distribución de los interruptores SW

- 63 -
Diseño sobre FPGA de una Unidad Aritmética Decimal Memoria experimental

Pulsadores:

• synch → BTN_WEST (D18)


• reset → BTN_SOUTH (K17)

Figura 4.11. Pulsadores disponibles en la placa

Señal de reloj:

• ext_clk → CLK_50MHz (C9)

Figura 4.12. Señales de reloj disponibles

Señales de la interfaz LCD:

Señal Nombre interno PIN asociado


lcd_e LCD_E M18
lcd_rs LCD_RS L18
lcd_rw LCD_RW L17
lcd_data<3> SF_D<11> M15
lcd_data<2> SF_D<10> P17
lcd_data<1> SF_D<9> R16
lcd_data<0> SF_D<8> R15

Tabla 4.4. Asignación de pines para la interfaz LCD

- 64 -
Diseño sobre FPGA de una Unidad Aritmética Decimal Memoria experimental

Figura 4.13. Interfaz LCD

4.9 Implementación en la FPGA

Ahora que disponemos del modelo VHDL del circuito completo (main.vhd), con los
diferentes componentes virtuales que lo integran (kcpsm.vhd, arithmetic_unit.vhd,
lcd_interface.vhd, program_memory.vhd) y del archivo de asignación de pines (pins.ucf),
procederemos a sintetizarlo e implementarlo en la FPGA.

Para ello utilizaremos la aplicación Xilinx ISE Design Suite 11, con dos de sus programas,
ISE Project Navigator para generar el archivo e iMPACT para grabarlo en la placa.

Para mayor comodidad nuestra, uniremos en un solo archivo VHDL todos los
componentes que conforman la Unidad Aritmética Decimal; este archivo será el
blocks_uad.vhd. Por tanto, el listado de programas utilizado será el siguiente:

• blocks_uad.vhd
• kcpsm.vhd
• lcd_interface.vhd
• main.vhd
• pins.ucf
• program_memory.vhd

- 65 -
Diseño sobre FPGA de una Unidad Aritmética Decimal Memoria experimental

4.9.1 Generación del archivo

Abrimos el programa ISE Project Navigator y creamos un nuevo proyecto (New Project) y
escogemos un nombre para él. El siguiente paso es seleccionar las características del
dispositivo que estamos utilizando, que en nuestro caso serán las siguientes:

Figura 4.14. Características de la FPGA

Añadimos los modelos VHDL y el archivo pins.ucf:

Figura 4.15. Archivos utilizados en el proyecto

- 66 -
Diseño sobre FPGA de una Unidad Aritmética Decimal Memoria experimental

Y vemos el dispositivo y los archivos que dependen de él:

Figura 4.16. Jerarquía del sistema completo

El primer paso consiste en sintetizar el modelo (Synthesize - XST); esto genera un reporte
que indica los recursos necesarios estimados para el dispositivo:

Tabla 4.5. Utilización del dispositivo

Ahora realizamos la implementación (Implement Design), el Placement & Routing, que


nos da una descripción concreta de los recursos necesarios de la FPGA para grabar nuestro
diseño:

Tabla 4.6. Utilización del dispositivo

- 67 -
Diseño sobre FPGA de una Unidad Aritmética Decimal Memoria experimental

El siguiente paso consiste en generar el archivo de programación (Generate Programming


File). Ya tenemos creado nuestro archivo main.bit que será el que bajemos a la placa.

4.9.2 Implementación en la FPGA

Grabaremos nuestro diseño (archivo main.bit) a través del puerto USB de la Spartan-3E.

Desde Configure Target Device, seleccionamos Manage Configuration Project (iMPACT),


los que nos llevará a la aplicación iMPACT. A través de Boundary Scan, buscamos el
dispositivo (Initialize Chain) y se muestra en pantalla:

Figura 4.17. Componentes disponibles de la FPGA

El componente xc3s500e corresponde a la FPGA y es donde programaremos nuestro


diseño. Los otros dos componentes pertenecen a la memoria Platform Flash y al CPLD
que hay integrados en la placa.

Asignamos el archivo main.bit a la FPGA y los otros dos componentes los dejamos como
están (Bypass). Ejecutamos Program en xc3s500e y ya tenemos la unidad operativa (el led
DONE de la placa se enciende indicando que el proceso de implementación se ha
completado correctamente).

Figura 4.18. FPGA disponible para su utilización

- 68 -
Diseño sobre FPGA de una Unidad Aritmética Decimal Memoria experimental

A continuación se muestran unas ilustraciones con ejemplos de las diferentes operaciones,


siendo los operandos x = 2867335 e y = 50299723:

• Suma: el resultado es 53167058.

Figura 4.19. Resultado de la suma

• Resta: el resultado es – 47432388. Es negativo porque el dígito z8 (según la Figura


4.1) es 1.

Figura 4.20. Resultado de la resta

• Multiplicación: el resultado es 144226156248205.

Figura 4.21. Resultado de la multiplicación

• División: el resultado se ha de interpretar como 0.0570049858922682.

Figura 4.22. Resultado de la división

- 69 -
Diseño sobre FPGA de una Unidad Aritmética Decimal

5. ANEXOS
Diseño sobre FPGA de una Unidad Aritmética Decimal Anexos

5.1 Modelos VHDL......................................................................................................................... 72


5.1.1 Sumador de 1 dígito BCD (one_digit_adder.vhd)............................................................ 72
5.1.2 Complemento a 9 (nine_complement.vhd) ....................................................................... 73
5.1.3 Sumador/Restador de n dígitos decimales (n_adder_subs.vhd) ....................................... 73
5.1.4 Multiplicador de 1x1 dígitos BCD (one_digit_multiplier.vhd) ........................................ 75
5.1.5 Multiplicador de Nx1 dígitos BCD (n_by_one_multiplier.vhd) ....................................... 76
5.1.6 Multiplicador de NxM dígitos BCD (n_by_m_multiplier.vhd) ........................................ 78
5.1.7 Divisor BCD (divider.vhd) ............................................................................................... 80
5.1.8 Unidad Aritmética Decimal (arithmetic_unit.vhd) ........................................................... 83
5.1.9 Memoria de programa (program_memory.vhd) ............................................................... 86
5.1.10 Circuito completo (main.vhd) ......................................................................................... 89
5.2 Programa en lenguaje ensamblador (decimal_unit.asm) ...................................................... 94
5.3 Asignación de pines en la Spartan-3E (pins.ucf) .................................................................... 97

- 71 -
Diseño sobre FPGA de una Unidad Aritmética Decimal Anexos

5.1 Modelos VHDL

A continuación se detallan los diferentes modelos VHDL creados en los apartados


anteriores.

5.1.1 Sumador de 1 dígito BCD (one_digit_adder.vhd)

----------------------------------------------------------------------
--Entidad del sumador de 1 dígito decimal
----------------------------------------------------------------------
LIBRARY IEEE;
USE IEEE.STD_LOGIC_1164.ALL;
USE IEEE.STD_LOGIC_ARITH.ALL;
USE IEEE.STD_LOGIC_UNSIGNED.ALL;

ENTITY one_digit_adder IS PORT(


a: IN STD_LOGIC_VECTOR(3 DOWNTO 0);
b: IN STD_LOGIC_VECTOR(3 DOWNTO 0);
c: OUT STD_LOGIC_VECTOR(3 DOWNTO 0);
cy_in: IN STD_LOGIC; --carry de entrada al bloque
cy_out: INOUT STD_LOGIC); --carry de salida del bloque
END one_digit_adder;

----------------------------------------------------------------------
--Arquitectura del sumador de 1 dígito decimal
----------------------------------------------------------------------
LIBRARY IEEE;
USE IEEE.STD_LOGIC_1164.ALL;
USE IEEE.STD_LOGIC_ARITH.ALL;
USE IEEE.STD_LOGIC_UNSIGNED.ALL;

ARCHITECTURE architecture_oda OF one_digit_adder IS

--Declaración de señales
SIGNAL d: STD_LOGIC_VECTOR(4 DOWNTO 0);
SIGNAL correction: STD_LOGIC_VECTOR(3 DOWNTO 0);

--Inicio
BEGIN

d <= '0' & a + b + cy_in;

cy_out <= d(4) OR (d(3) AND (d(2) OR d(1))); --crea carry de salida
--si d>9
correction <= '0' & cy_out & cy_out & '0'; --se pone a '0110' si hay
--carry de salida
c <= d(3 DOWNTO 0) + correction; --aplica la corrección si
--hay carry de salida

END architecture_oda;

- 72 -
Diseño sobre FPGA de una Unidad Aritmética Decimal Anexos

5.1.2 Complemento a 9 (nine_complement.vhd)

----------------------------------------------------------------------
--Entidad del bloque de complemento a 9
----------------------------------------------------------------------
LIBRARY IEEE;
USE IEEE.STD_LOGIC_1164.ALL;
USE IEEE.STD_LOGIC_ARITH.ALL;
USE IEEE.STD_LOGIC_UNSIGNED.ALL;

ENTITY nine_complement IS
PORT(
e: IN STD_LOGIC_VECTOR(3 DOWNTO 0); --dígito de entrada
add_sub: IN STD_LOGIC; --señal de control del bloque
s: OUT STD_LOGIC_VECTOR(3 DOWNTO 0)); --dígito de salida
END nine_complement;

----------------------------------------------------------------------
--Arquitectura del bloque de complemento a 9
----------------------------------------------------------------------
LIBRARY IEEE;
USE IEEE.STD_LOGIC_1164.ALL;
USE IEEE.STD_LOGIC_ARITH.ALL;
USE IEEE.STD_LOGIC_UNSIGNED.ALL;

ARCHITECTURE architecture_nc OF nine_complement IS

BEGIN

s(0) <= (NOT(add_sub) AND e(0)) OR (add_sub AND NOT(e(0)));


s(1) <= e(1);
s(2) <= (NOT(add_sub) AND e(2)) OR (add_sub AND (e(1) XOR e(2)));
s(3) <= (NOT(add_sub) AND e(3)) OR (add_sub AND (NOT(e(1)) AND
NOT(e(2)) AND NOT(e(3))));

END architecture_nc;

5.1.3 Sumador/Restador de n dígitos decimales (n_adder_subs.vhd)

----------------------------------------------------------------------
--Entidad del sumador/restador de n dígitos decimales
----------------------------------------------------------------------
LIBRARY IEEE;
USE IEEE.STD_LOGIC_1164.ALL;
USE IEEE.STD_LOGIC_ARITH.ALL;
USE IEEE.STD_LOGIC_UNSIGNED.ALL;

ENTITY n_adder_subs IS
GENERIC (n:natural);
PORT(
x: IN STD_LOGIC_VECTOR(4*n-1 DOWNTO 0); --entrada de n dígitos BCD
y: IN STD_LOGIC_VECTOR(4*n-1 DOWNTO 0); --entrada de n dígitos BCD
add_sub: IN STD_LOGIC; --operación: '0' suma y '1' resta
z: OUT STD_LOGIC_VECTOR(4*n-1 DOWNTO 0); --salida de n dígitos BCD
carry_out: OUT STD_LOGIC); --acarreo de salida
END n_adder_subs;

- 73 -
Diseño sobre FPGA de una Unidad Aritmética Decimal Anexos

----------------------------------------------------------------------
--Arquitectura del sumador/restador de n dígitos decimales
----------------------------------------------------------------------
LIBRARY IEEE;
USE IEEE.STD_LOGIC_1164.ALL;
USE IEEE.STD_LOGIC_ARITH.ALL;
USE IEEE.STD_LOGIC_UNSIGNED.ALL;

ARCHITECTURE architecture_nas OF n_adder_subs IS

--Declaración de constantes
CONSTANT i1: STD_LOGIC_VECTOR(4*n-1 DOWNTO 0) :=
CONV_STD_LOGIC_VECTOR(1,4*n);

--Declaración de señales
SIGNAL carries,carries2: STD_LOGIC_VECTOR(n DOWNTO 0);
SIGNAL y1: STD_LOGIC_VECTOR(4*n-1 DOWNTO 0);
SIGNAL z1,z2,z3: STD_LOGIC_VECTOR(4*n-1 DOWNTO 0);
SIGNAL oc, output_selection: STD_LOGIC;

--Declaración de componentes
COMPONENT one_digit_adder IS PORT(
a: IN STD_LOGIC_VECTOR(3 DOWNTO 0);
b: IN STD_LOGIC_VECTOR(3 DOWNTO 0);
c: OUT STD_LOGIC_VECTOR(3 DOWNTO 0);
cy_in: IN STD_LOGIC; --carry de entrada al bloque
cy_out: INOUT STD_LOGIC); --carry de salida del bloque
END COMPONENT;

COMPONENT nine_complement PORT( --bloque que complementa a 9


e: IN STD_LOGIC_VECTOR(3 DOWNTO 0); --dígito de entrada
add_sub: IN STD_LOGIC; --señal de control del bloque
s: OUT STD_LOGIC_VECTOR(3 DOWNTO 0)); --dígito de salida
END COMPONENT;

--Inicio
BEGIN
carries(0) <= add_sub;

a1_iteration: FOR i IN 0 TO n-1 GENERATE --Complemento a 9 de 'y'


nine_compl: nine_complement PORT MAP( --en función de 'add_sub'
e => y(4*i+3 DOWNTO 4*i),
add_sub => add_sub,
s => y1(4*i+3 DOWNTO 4*i));
END GENERATE;

a2_iteration: FOR i IN 0 TO n-1 GENERATE


addition: one_digit_adder PORT MAP(
a => x(4*i+3 DOWNTO 4*i),
b => y1(4*i+3 DOWNTO 4*i),
c => z1(4*i+3 DOWNTO 4*i),
cy_in => carries(i),
cy_out => carries(i+1));
END GENERATE;

oc <= carries(n); --señal que utilizamos si el carry de


--de salida es 0, resultado negativo

- 74 -
Diseño sobre FPGA de una Unidad Aritmética Decimal Anexos

b1_iteration: FOR i IN 0 TO n-1 GENERATE --bloque que complementa a 9


nine_compl_2: nine_complement PORT MAP( --cuando el resultado
e => z1(4*i+3 DOWNTO 4*i), --anterior sea negativo
add_sub => add_sub,
s => z2(4*i+3 DOWNTO 4*i));
END GENERATE;

carries2(0) <= '0';

b2_iteration: FOR i IN 0 TO n-1 GENERATE --bloque utilizado para


addition_2: one_digit_adder PORT MAP( --sumar 1 en BCD al
a => z2(4*i+3 DOWNTO 4*i), --complemento a nueve
b => i1(4*i+3 DOWNTO 4*i), --generado antes
c => z3(4*i+3 DOWNTO 4*i),
cy_in => carries2(i),
cy_out => carries2(i+1));
END GENERATE;

output_selection <= add_sub AND NOT(oc);

WITH output_selection SELECT z <= z3 WHEN '1', z1 WHEN OTHERS;

carry_out <= oc XOR add_sub;


--Si la operación es suma: carry_out = '0' => resultado exacto
--Si la operación es suma: carry_out = '1' => hay desbordamiento,
--añadir un '1' a la izquierda
--Si la operación es resta: carry_out = '0' => resultado no negativo
--Si la operación es resta: carry_out = '1' => resultado negativo

END architecture_nas;

5.1.4 Multiplicador de 1x1 dígitos BCD (one_digit_multiplier.vhd)

----------------------------------------------------------------------
--Entidad del multiplicador de 1 dígito decimal
----------------------------------------------------------------------
LIBRARY IEEE;
USE IEEE.STD_LOGIC_1164.ALL;
USE IEEE.STD_LOGIC_ARITH.ALL;
USE IEEE.STD_LOGIC_UNSIGNED.ALL;

ENTITY one_digit_multiplier IS PORT(


a: IN STD_LOGIC_VECTOR(3 DOWNTO 0); --entrada de 1 dígito BCD
b: IN STD_LOGIC_VECTOR(3 DOWNTO 0); --entrada de 1 dígito BCD
d: OUT STD_LOGIC_VECTOR(3 DOWNTO 0); --salida de 1 dígito BCD
u: OUT STD_LOGIC_VECTOR(3 DOWNTO 0)); --salida de 1 dígito BCD
END one_digit_multiplier;

----------------------------------------------------------------------
--Arquitectura del multiplicador de 1 dígito decimal
----------------------------------------------------------------------
LIBRARY IEEE;
USE IEEE.STD_LOGIC_1164.ALL;
USE IEEE.STD_LOGIC_ARITH.ALL;
USE IEEE.STD_LOGIC_UNSIGNED.ALL;

ARCHITECTURE architecture_odm OF one_digit_multiplier IS

- 75 -
Diseño sobre FPGA de una Unidad Aritmética Decimal Anexos

--Declaración de señales
SIGNAL p: STD_LOGIC_VECTOR(7 DOWNTO 0);
SIGNAL uu: STD_LOGIC_VECTOR(4 DOWNTO 0);
SIGNAL dd: STD_LOGIC_VECTOR(3 DOWNTO 0);
SIGNAL gt9, gt20, gt10st19: STD_LOGIC;

--Inicio
BEGIN

p <= a*b; --producto binario

uu <= p(3 DOWNTO 0) + ("00"&p(4)&p(4)&'0') + ("00"&p(6 DOWNTO 5)&'0');


dd <= p(6 DOWNTO 4) + ("00"&p(6 DOWNTO 5));

gt9 <= uu(4) OR (uu(3) AND (uu(2) OR uu(1))); --mayor a 9


gt20 <= uu(4) AND (uu(3) OR uu(2)); --mayor a 19
gt10st19 <= gt9 AND NOT(gt20); --entre 10 y 19

d <= dd + ('0' & '0' & gt20 & gt10st19);


u <= uu(3 DOWNTO 0) + (gt20 & gt9 & gt10st19 & '0');

END architecture_odm;

5.1.5 Multiplicador de Nx1 dígitos BCD (n_by_one_multiplier.vhd)

----------------------------------------------------------------------
--Entidad del multiplicador de Nx1 dígitos decimales
----------------------------------------------------------------------
LIBRARY IEEE;
USE IEEE.STD_LOGIC_1164.ALL;
USE IEEE.STD_LOGIC_ARITH.ALL;
USE IEEE.STD_LOGIC_UNSIGNED.ALL;

ENTITY n_by_one_multiplier IS
GENERIC (n:natural);
PORT(
x: IN STD_LOGIC_VECTOR(4*n-1 DOWNTO 0); --entrada de n dígitos BCD
y: IN STD_LOGIC_VECTOR(3 DOWNTO 0); --entrada de 1 dígito BCD
z: OUT STD_LOGIC_VECTOR(4*n+3 DOWNTO 0)); --salida de n dígitos BCD
END n_by_one_multiplier;

----------------------------------------------------------------------
--Arquitectura del multiplicador de Nx1 dígitos decimales
----------------------------------------------------------------------
LIBRARY IEEE;
USE IEEE.STD_LOGIC_1164.ALL;
USE IEEE.STD_LOGIC_ARITH.ALL;
USE IEEE.STD_LOGIC_UNSIGNED.ALL;

ARCHITECTURE architecture_nbom OF n_by_one_multiplier IS

--Declaración de señales
SIGNAL dd,uu: STD_LOGIC_VECTOR(4*n-1 DOWNTO 0);
SIGNAL ddc,uuc: STD_LOGIC_VECTOR(4*n+3 DOWNTO 0);
SIGNAL carries: STD_LOGIC_VECTOR(n+1 DOWNTO 0);

- 76 -
Diseño sobre FPGA de una Unidad Aritmética Decimal Anexos

--Declaración de componentes
COMPONENT one_digit_multiplier IS PORT(
a: IN STD_LOGIC_VECTOR(3 DOWNTO 0); --entrada de 1 dígito BCD
b: IN STD_LOGIC_VECTOR(3 DOWNTO 0); --entrada de 1 dígito BCD
d: OUT STD_LOGIC_VECTOR(3 DOWNTO 0); --salida de 1 dígito BCD
u: OUT STD_LOGIC_VECTOR(3 DOWNTO 0)); --salida de 1 dígito BCD
END COMPONENT;

COMPONENT one_digit_adder IS PORT(


a: IN STD_LOGIC_VECTOR(3 DOWNTO 0);
b: IN STD_LOGIC_VECTOR(3 DOWNTO 0);
c: OUT STD_LOGIC_VECTOR(3 DOWNTO 0);
cy_in: IN STD_LOGIC; --carry de entrada al bloque
cy_out: INOUT STD_LOGIC); --carry de salida del bloque
END COMPONENT;

--Inicio
BEGIN
a_iteration: FOR i IN 0 TO n-1 GENERATE
multiplier: one_digit_multiplier PORT MAP(
a => x(4*i+3 DOWNTO 4*i),
b => y,
d => dd(4*i+3 DOWNTO 4*i),
u => uu(4*i+3 DOWNTO 4*i));
END GENERATE;

ddc <= dd & "0000";


uuc <= "0000" & uu;

carries(0) <= '0';

b_iteration: FOR i IN 0 TO n GENERATE


adder: one_digit_adder PORT MAP(
a => ddc(4*i+3 DOWNTO 4*i),
b => uuc(4*i+3 DOWNTO 4*i),
c => z(4*i+3 DOWNTO 4*i),
cy_in => carries(i),
cy_out => carries(i+1));
END GENERATE;

END architecture_nbom;

- 77 -
Diseño sobre FPGA de una Unidad Aritmética Decimal Anexos

5.1.6 Multiplicador de NxM dígitos BCD (n_by_m_multiplier.vhd)

----------------------------------------------------------------------
--Entidad del multiplicador de N x M dígitos decimales
----------------------------------------------------------------------
LIBRARY IEEE;
USE IEEE.STD_LOGIC_1164.ALL;
USE IEEE.STD_LOGIC_ARITH.ALL;
USE IEEE.STD_LOGIC_UNSIGNED.ALL;

ENTITY n_by_m_multiplier IS
GENERIC (n,m:natural);
PORT(
x: IN STD_LOGIC_VECTOR(4*n-1 DOWNTO 0); --entrada de n dígitos BCD
y: IN STD_LOGIC_VECTOR(4*m-1 DOWNTO 0); --entrada de m dígitos BCD
start: IN STD_LOGIC; --señal de inicio
clk: IN STD_LOGIC; --señal de reloj
reset: IN STD_LOGIC; --inicializa la operación
z: INOUT STD_LOGIC_VECTOR(4*(n+m)-1 DOWNTO 0); --salida de N+M
--dígitos BCD
done: OUT STD_LOGIC); --resultado disponible
END n_by_m_multiplier;

----------------------------------------------------------------------
--Arquitectura del multiplicador de N x M dígitos decimales
----------------------------------------------------------------------
LIBRARY IEEE;
USE IEEE.STD_LOGIC_1164.ALL;
USE IEEE.STD_LOGIC_ARITH.ALL;
USE IEEE.STD_LOGIC_UNSIGNED.ALL;

ARCHITECTURE architecture_nbmm OF n_by_m_multiplier IS

--Declaración de estados
TYPE states IS RANGE 0 TO 3;
SIGNAL current_state: states;

--Declaración de constantes
CONSTANT initial_zeroes: STD_LOGIC_VECTOR(4*m-5 DOWNTO 0) := (OTHERS =>
'0');

--Declaración de señales
SIGNAL int_y: STD_LOGIC_VECTOR(4*m+3 DOWNTO 0); --registro y
--el registro z se declara en la entidad
SIGNAL x_by_yi: STD_LOGIC_VECTOR(4*n+3 DOWNTO 0);
SIGNAL next_z: STD_LOGIC_VECTOR(4*(n+m)-1 DOWNTO 0);
SIGNAL z_by_10, long_x_by_yi: STD_LOGIC_VECTOR(4*(n+m)-1 DOWNTO 0);
SIGNAL load, shift, end_of_computation: STD_LOGIC;

--Declaración de componentes
COMPONENT n_by_one_multiplier IS --multiplicador de Nx1 dígitos BCD
GENERIC (n:natural);
PORT(
x: IN STD_LOGIC_VECTOR(4*n-1 DOWNTO 0); --entrada de n dígitos BCD
y: IN STD_LOGIC_VECTOR(3 DOWNTO 0); --entrada de 1 dígito BCD
z: OUT STD_LOGIC_VECTOR(4*n+3 DOWNTO 0)); --salida de n dígitos BCD
END COMPONENT;

- 78 -
Diseño sobre FPGA de una Unidad Aritmética Decimal Anexos

COMPONENT n_adder_subs IS --Sumador/restador utilizado para sumar


GENERIC (n:natural);
PORT(
x: IN STD_LOGIC_VECTOR(4*n-1 DOWNTO 0); --entrada de n dígitos BCD
y: IN STD_LOGIC_VECTOR(4*n-1 DOWNTO 0); --entrada de n dígitos BCD
add_sub: IN STD_LOGIC; --operación: '0' suma y '1' resta
z: OUT STD_LOGIC_VECTOR(4*n-1 DOWNTO 0); --salida de n dígitos BCD
carry_out: OUT STD_LOGIC); --acarreo de salida
END COMPONENT;

--Inicio
BEGIN

multiplier: n_by_one_multiplier
GENERIC MAP(n => n)
PORT MAP(
x => x,
y => int_y(4*m+3 DOWNTO 4*m),
z => x_by_yi);

long_x_by_yi <= initial_zeroes&x_by_yi; --equiparamos las dos entradas


--del sumador en cuanto a
--número de dígitos
adder: n_adder_subs
GENERIC MAP(n => n+m)
PORT MAP(
x => long_x_by_yi,
y => z_by_10,
add_sub => '0', --operación a realizar: suma
z => next_z);

z_by_10 <= z(4*(n+m)-5 DOWNTO 0)&"0000"; --multiplicamos z por 10

--Sentencias secuenciales
register_y: PROCESS(clk)
BEGIN
IF clk'EVENT AND clk = '1' THEN
IF load = '1' THEN int_y <= y & "1111";
ELSIF shift = '1' THEN int_y <= int_y(4*m-1 DOWNTO 0) & "0000";
END IF;
END IF;
END PROCESS;

register_z: PROCESS(clk)
BEGIN
IF clk'EVENT AND clk = '1' THEN
IF load = '1' THEN z <= (OTHERS => '0');
ELSIF shift = '1' THEN z <= next_z;
END IF;
END IF;
END PROCESS;

end_of_computation <= int_y(4*m+3) AND int_y(4*m+2);

- 79 -
Diseño sobre FPGA de una Unidad Aritmética Decimal Anexos

--Unidad de control
control_unit_output: PROCESS(current_state, end_of_computation)
BEGIN
CASE current_state IS
WHEN 0 to 1 => shift <= '0'; load <= '0'; done <= '1';
WHEN 2 => shift <= '0'; load <= '1'; done <= '0';
WHEN 3 => IF end_of_computation = '0' THEN shift <= '1';
ELSE shift <= '0'; END IF; load <= '0'; done <= '0';
END CASE;
END PROCESS;

control_unit_next_state: PROCESS(clk, reset)


BEGIN
IF reset = '1' THEN current_state <= 0;
ELSIF clk'event AND clk = '1' THEN
CASE current_state IS
WHEN 0 => IF start = '0' THEN current_state <= 1; END IF;
WHEN 1 => IF start = '1' THEN current_state <= 2; END IF;
WHEN 2 => current_state <= 3;
WHEN 3 => IF end_of_computation = '1' THEN
current_state <= 0; END IF;
END CASE;
END IF;
END PROCESS;

END architecture_nbmm;

5.1.7 Divisor BCD (divider.vhd)

----------------------------------------------------------------------
--Entidad del divisor de n dígitos decimales
----------------------------------------------------------------------
LIBRARY IEEE;
USE IEEE.STD_LOGIC_1164.ALL;
USE IEEE.STD_LOGIC_ARITH.ALL;
USE IEEE.STD_LOGIC_UNSIGNED.ALL;

ENTITY decimal_divider IS
GENERIC (n,m,p,logp:natural);
PORT(
x: IN STD_LOGIC_VECTOR(4*n-1 DOWNTO 0); --dividendo
y: IN STD_LOGIC_VECTOR(4*n-1 DOWNTO 0); --divisor
start: IN STD_LOGIC; --señal de inicio
clk: IN STD_LOGIC; --señal de reloj
reset: IN STD_LOGIC; --inicializa operación
q: OUT STD_LOGIC_VECTOR(4*m-1 DOWNTO 0); --resultado (cociente)
done: OUT STD_LOGIC); --operación realizada
END decimal_divider;

- 80 -
Diseño sobre FPGA de una Unidad Aritmética Decimal Anexos

----------------------------------------------------------------------
--Arquitectura del divisor de n dígitos decimales
----------------------------------------------------------------------
LIBRARY IEEE;
USE IEEE.STD_LOGIC_1164.ALL;
USE IEEE.STD_LOGIC_ARITH.ALL;
USE IEEE.STD_LOGIC_UNSIGNED.ALL;

ARCHITECTURE architecture_divider OF decimal_divider IS

--Declaración de estados
TYPE states IS RANGE 0 TO 3;
SIGNAL current_state: states;

--Declaración de constantes
CONSTANT initial_zeroes: STD_LOGIC_VECTOR(4*p-9 DOWNTO 0) := (
OTHERS => '0');
CONSTANT initial_zeroes_2: STD_LOGIC_VECTOR(4*p-5 DOWNTO 0) := (
OTHERS => '0');

--Declaración de señales
SIGNAL r, s1: STD_LOGIC_VECTOR(4*n-1 DOWNTO 0);
SIGNAL rr, rr_y, yy: STD_LOGIC_VECTOR(4*n+3 DOWNTO 0);
SIGNAL qq, ulp, qq_ulp, s2: STD_LOGIC_VECTOR(4*p-1 DOWNTO 0);
SIGNAL c_out: STD_LOGIC;
SIGNAL load, ce, zero: STD_LOGIC;
SIGNAL ulp_by_5: STD_LOGIC_VECTOR(4*p+3 DOWNTO 0);
SIGNAL count: STD_LOGIC_VECTOR(logp-1 DOWNTO 0);

--Declaración de componentes
COMPONENT n_by_one_multiplier IS --multiplicador de Nx1 dígitos BCD
GENERIC (n:natural);
PORT(
x: IN STD_LOGIC_VECTOR(4*n-1 DOWNTO 0); --entrada de n dígitos BCD
y: IN STD_LOGIC_VECTOR(3 DOWNTO 0); --entrada de 1 dígito BCD
z: OUT STD_LOGIC_VECTOR(4*n+3 DOWNTO 0)); --salida de n dígitos BCD
END COMPONENT;

COMPONENT n_adder_subs IS --Sumador/restador utilizado para sumar


GENERIC (n:natural);
PORT(
x: IN STD_LOGIC_VECTOR(4*n-1 DOWNTO 0); --entrada de n dígitos BCD
y: IN STD_LOGIC_VECTOR(4*n-1 DOWNTO 0); --entrada de n dígitos BCD
add_sub: IN STD_LOGIC; --operación: '0' suma y '1' resta
z: OUT STD_LOGIC_VECTOR(4*n-1 DOWNTO 0); --salida de n dígitos BCD
carry_out: OUT STD_LOGIC); --acarreo de salida
END COMPONENT;

--Inicio
BEGIN

yy <= "0000" & y; --Añadimos un 0 decimal a 'y' para igualarla


--en número de dígitos a rr (2r)

multiplier_r_by_2: n_by_one_multiplier --Multiplicador de r x 2


GENERIC MAP(n => n)
PORT MAP(
x => r,
y => "0010", --2 en decimal
z => rr); --resultado 2r

- 81 -
Diseño sobre FPGA de una Unidad Aritmética Decimal Anexos

subtraction: n_adder_subs --Restador para realizar 2r - y


GENERIC MAP(n => n+1)
PORT MAP(
x => rr, --2r
y => yy,
add_sub => '1', --Resta como operación a realizar
z => rr_y, --resultado de 2r-y
carry_out => c_out);

WITH NOT(c_out) SELECT s1 <= rr(4*n-1 DOWNTO 0) WHEN '0', rr_y(4*n-1


DOWNTO 0) WHEN OTHERS;

addition: n_adder_subs --Sumador para realizar qq + ulp


GENERIC MAP(n => p)
PORT MAP(
x => qq,
y => ulp,
add_sub => '0', --Suma como operación a realizar
z => qq_ulp);

WITH NOT(c_out) SELECT s2 <= qq WHEN '0', qq_ulp WHEN OTHERS;

multiplier_ulp_by_5: n_by_one_multiplier --Multiplicador de ulp x 5


GENERIC MAP(n => p)
PORT MAP(
x => ulp,
y => "0101", --5 en BCD
z => ulp_by_5); --resultado 5*ulp

q <= qq(4*p-1 DOWNTO 4*(p-m)); --Los m dígitos más significativos


--de qq
--Sentencias secuenciales
register_r: PROCESS(clk)
BEGIN
IF clk'EVENT AND clk = '1' THEN
IF load = '1' THEN r <= x; --El valor inicial de r es x
ELSIF ce = '1' THEN r <= s1; --Actualiza el valor de r
END IF;
END IF;
END PROCESS;

register_qq: PROCESS(clk)
BEGIN
IF clk'EVENT AND clk = '1' THEN
IF load = '1' THEN qq <= (OTHERS => '0');--Valor inicial de qq es 0
ELSIF ce = '1' THEN qq <= s2; --Actualiza el valor de qq
END IF;
END IF;
END PROCESS;

register_ulp: PROCESS(clk)
BEGIN
IF clk'EVENT AND clk = '1' THEN
IF load = '1' THEN ulp <= "0101" & initial_zeroes_2;
--El valor inicial es 5, que representa 0.5
ELSIF ce = '1' THEN ulp <= ulp_by_5(4*p+3 DOWNTO 4);--Actualiza ulp
END IF;
END IF;
END PROCESS;

- 82 -
Diseño sobre FPGA de una Unidad Aritmética Decimal Anexos

--Contador de p estados
counter_stages: PROCESS(clk)
BEGIN
IF clk'EVENT AND clk = '1' THEN
IF load = '1' THEN count <= CONV_STD_LOGIC_VECTOR(p-1, logp);
ELSIF ce = '1' THEN count <= count - 1;
END IF;
END IF;
END PROCESS;

zero <= '1' WHEN count = "0" ELSE '0';

--Unidad de control
control_unit: PROCESS(clk, reset, current_state, zero)
BEGIN
CASE current_state IS
WHEN 0 to 1 => load <= '0'; ce <= '0'; done <= '1';
WHEN 2 => load <= '1'; ce <= '0'; done <= '0';
WHEN 3 => load <= '0'; ce <= '1'; done <= '0';
END CASE;
IF reset = '1' THEN current_state <= 0;
ELSIF clk'EVENT AND clk = '1' THEN
CASE current_state IS
WHEN 0 => IF start = '0' THEN current_state <= 1; END IF;
WHEN 1 => IF start = '1' THEN current_state <= 2; END IF;
WHEN 2 => current_state <= 3;
WHEN 3 => IF zero = '1' THEN current_state <= 0; END IF;
END CASE;
END IF;
END PROCESS;

END architecture_divider;

5.1.8 Unidad Aritmética Decimal (arithmetic_unit.vhd)

----------------------------------------------------------------------
--Entidad de la unidad aritmética decimal
----------------------------------------------------------------------
LIBRARY IEEE;
USE IEEE.STD_LOGIC_1164.ALL;
USE IEEE.STD_LOGIC_ARITH.ALL;
USE IEEE.STD_LOGIC_UNSIGNED.ALL;

ENTITY arithmetic_unit IS
GENERIC (n, p, logp: NATURAL);
PORT(
x: IN STD_LOGIC_VECTOR(4*n-1 DOWNTO 0); --operando x
y: IN STD_LOGIC_VECTOR(4*n-1 DOWNTO 0); --operando y
operation: IN STD_LOGIC_VECTOR(1 DOWNTO 0); --operación
start: IN STD_LOGIC; --señal de inicio
clk: IN STD_LOGIC; --señal de reloj
reset: IN STD_LOGIC; --inicializa
z: OUT STD_LOGIC_VECTOR(8*n-1 DOWNTO 0); --resultado
done: OUT STD_LOGIC); --operación lista
END arithmetic_unit;

- 83 -
Diseño sobre FPGA de una Unidad Aritmética Decimal Anexos

----------------------------------------------------------------------
--Arquitectura de la unidad aritmética decimal
----------------------------------------------------------------------
LIBRARY IEEE;
USE IEEE.STD_LOGIC_1164.ALL;
USE IEEE.STD_LOGIC_ARITH.ALL;
USE IEEE.STD_LOGIC_UNSIGNED.ALL;

ARCHITECTURE architecture_au OF arithmetic_unit IS

--Declaración de señales
SIGNAL s1: STD_LOGIC_VECTOR(4*n-1 DOWNTO 0);
SIGNAL s2, s3: STD_LOGIC_VECTOR(8*n-1 DOWNTO 0);
SIGNAL c_out, done1, done2: STD_LOGIC;
SIGNAL start1, start2: STD_LOGIC;

--Declaración de componentes
COMPONENT n_adder_subs IS
GENERIC (n:natural);
PORT(
x: IN STD_LOGIC_VECTOR(4*n-1 DOWNTO 0); --entrada de n dígitos BCD
y: IN STD_LOGIC_VECTOR(4*n-1 DOWNTO 0); --entrada de n dígitos BCD
add_sub: IN STD_LOGIC; --operación: '0' suma y '1' resta
z: OUT STD_LOGIC_VECTOR(4*n-1 DOWNTO 0); --salida de n dígitos BCD
carry_out: OUT STD_LOGIC); --acarreo de salida
END COMPONENT;

COMPONENT n_by_m_multiplier IS
GENERIC (n, m: natural);
PORT(
x: IN STD_LOGIC_VECTOR(4*n-1 DOWNTO 0); --entrada de n dígitos BCD
y: IN STD_LOGIC_VECTOR(4*m-1 DOWNTO 0); --entrada de m dígitos BCD
start: IN STD_LOGIC; --señal de inicio
clk: IN STD_LOGIC; --señal de reloj
reset: IN STD_LOGIC; --inicializa la operación
z: INOUT STD_LOGIC_VECTOR(4*(n+m)-1 DOWNTO 0); --salida de N+M
--dígitos BCD
done: OUT STD_LOGIC); --resultado disponible
END COMPONENT;

COMPONENT decimal_divider IS
GENERIC (n, m, p, logp: natural);
PORT(
x: IN STD_LOGIC_VECTOR(4*n-1 DOWNTO 0); --dividendo
y: IN STD_LOGIC_VECTOR(4*n-1 DOWNTO 0); --divisor
start: IN STD_LOGIC; --señal de inicio
clk: IN STD_LOGIC; --señal de reloj
reset: IN STD_LOGIC; --inicializa operación
q: OUT STD_LOGIC_VECTOR(4*m-1 DOWNTO 0); --resultado (cociente)
done: OUT STD_LOGIC); --operación realizada
END COMPONENT;

--Inicio
BEGIN

start1 <= start AND NOT(operation(0)) AND operation(1);


start2 <= start AND operation(0) AND operation(1);

- 84 -
Diseño sobre FPGA de una Unidad Aritmética Decimal Anexos

addition_substraction: n_adder_subs
GENERIC MAP(n => n)
PORT MAP(
x => x,
y => y,
add_sub => operation(0),
z => s1,
carry_out => c_out);

multiplier: n_by_m_multiplier
GENERIC MAP(n => n, m => n)
PORT MAP(
x => x,
y => y,
start => start1,
clk => clk,
reset => reset,
z => s2,
done => done1);

divider: decimal_divider
GENERIC MAP(n => n, m => 2*n, p => p, logp => logp)
PORT MAP(
x => x,
y => y,
start => start2,
clk => clk,
reset => reset,
q => s3,
done => done2);

WITH operation SELECT z(4*n-1 DOWNTO 0) <=


s1 WHEN "00",
s1 WHEN "01",
s2(4*n-1 DOWNTO 0) WHEN "10",
s3(4*n-1 DOWNTO 0) WHEN OTHERS;

WITH operation SELECT z(8*n-1 DOWNTO 4*n) <=


x"0000000" & "000" & c_out WHEN "00",
x"0000000" & "000" & c_out WHEN "01",
s2(8*n-1 DOWNTO 4*n) WHEN "10",
s3(8*n-1 DOWNTO 4*n) WHEN OTHERS;

WITH operation SELECT done <=


'1' WHEN "00",
'1' WHEN "01",
done1 WHEN "10",
done2 WHEN OTHERS;

END architecture_au;

- 85 -
Diseño sobre FPGA de una Unidad Aritmética Decimal Anexos

5.1.9 Memoria de programa (program_memory.vhd)

library IEEE ;
use IEEE.STD_LOGIC_1164.all ;
use IEEE.STD_LOGIC_ARITH.all ;
use IEEE.STD_LOGIC_UNSIGNED.all ;
library unisim ;
use unisim.vcomponents.all ;
entity program_memory is
port (
clk : in std_logic ;
reset : out std_logic ;
address : in std_logic_vector( 7 downto 0 ) ;
instruction : out std_logic_vector( 15 downto 0 )
) ;
end entity program_memory ;

architecture mix of program_memory is


component jtag_shifter is
port (
clk : in std_logic ;
user1 : out std_logic ;
write : out std_logic ;
addr : out std_logic_vector( 8 downto 0 ) ;
data : out std_logic_vector( 7 downto 0 )
) ;
end component ;

signal jaddr : std_logic_vector( 8 downto 0 ) ;


signal jdata : std_logic_vector( 7 downto 0 ) ;
signal juser1 : std_logic ;
signal jwrite : std_logic ;

attribute INIT_00 : string ;


attribute INIT_01 : string ;
attribute INIT_02 : string ;
attribute INIT_03 : string ;
attribute INIT_04 : string ;
attribute INIT_05 : string ;
attribute INIT_06 : string ;
attribute INIT_07 : string ;
attribute INIT_08 : string ;
attribute INIT_09 : string ;
attribute INIT_0A : string ;
attribute INIT_0B : string ;
attribute INIT_0C : string ;
attribute INIT_0D : string ;
attribute INIT_0E : string ;
attribute INIT_0F : string ;
attribute INIT_10 : string ;
attribute INIT_11 : string ;
attribute INIT_12 : string ;
attribute INIT_13 : string ;
attribute INIT_14 : string ;
attribute INIT_15 : string ;
attribute INIT_16 : string ;
attribute INIT_17 : string ;
attribute INIT_18 : string ;
attribute INIT_19 : string ;
attribute INIT_1A : string ;
attribute INIT_1B : string ;

- 86 -
Diseño sobre FPGA de una Unidad Aritmética Decimal Anexos

attribute INIT_1C : string ;


attribute INIT_1D : string ;
attribute INIT_1E : string ;
attribute INIT_1F : string ;
attribute INIT_20 : string ;
attribute INIT_21 : string ;
attribute INIT_22 : string ;
attribute INIT_23 : string ;
attribute INIT_24 : string ;
attribute INIT_25 : string ;
attribute INIT_26 : string ;
attribute INIT_27 : string ;
attribute INIT_28 : string ;
attribute INIT_29 : string ;
attribute INIT_2A : string ;
attribute INIT_2B : string ;
attribute INIT_2C : string ;
attribute INIT_2D : string ;
attribute INIT_2E : string ;
attribute INIT_2F : string ;
attribute INIT_30 : string ;
attribute INIT_31 : string ;
attribute INIT_32 : string ;
attribute INIT_33 : string ;
attribute INIT_34 : string ;
attribute INIT_35 : string ;
attribute INIT_36 : string ;
attribute INIT_37 : string ;
attribute INIT_38 : string ;
attribute INIT_39 : string ;
attribute INIT_3A : string ;
attribute INIT_3B : string ;
attribute INIT_3C : string ;
attribute INIT_3D : string ;
attribute INIT_3E : string ;
attribute INIT_3F : string ;
attribute INITP_00 : string ;
attribute INITP_01 : string ;
attribute INITP_02 : string ;
attribute INITP_03 : string ;
attribute INITP_04 : string ;
attribute INITP_05 : string ;
attribute INITP_06 : string ;
attribute INITP_07 : string ;

attribute INIT_00 of bram : label is


"8322E2130200832B9D0561018339834BF210A211832B010F8340038083400301" ;
attribute INIT_01 of bram : label is
"83228347E212E2130203832B83228347E212E2130202832B8322E2130201832B" ;
attribute INIT_02 of bram : label is
"6000A010952B6000A01080809D2561018339834BB210010F834003C08100832B" ;
attribute INIT_03 of bram : label is
"8080E0110000E0110002E2108335808091356000A01280809532640104FF912E" ;
attribute INIT_04 of bram : label is
"808042309D50600AC020808091476000A0138080E0110000E0110001E3108335" ;
attribute INIT_05 of bram : label is
"0000000000000000000000000000000000000000000000000000808042406209" ;
attribute INIT_06 of bram : label is
"0000000000000000000000000000000000000000000000000000000000000000" ;
attribute INIT_07 of bram : label is
"0000000000000000000000000000000000000000000000000000000000000000" ;

- 87 -
Diseño sobre FPGA de una Unidad Aritmética Decimal Anexos

attribute INIT_08 of bram : label is


"0000000000000000000000000000000000000000000000000000000000000000" ;
attribute INIT_09 of bram : label is
"0000000000000000000000000000000000000000000000000000000000000000" ;
attribute INIT_0A of bram : label is
"0000000000000000000000000000000000000000000000000000000000000000" ;
attribute INIT_0B of bram : label is
"0000000000000000000000000000000000000000000000000000000000000000" ;
attribute INIT_0C of bram : label is
"0000000000000000000000000000000000000000000000000000000000000000" ;
attribute INIT_0D of bram : label is
"0000000000000000000000000000000000000000000000000000000000000000" ;
attribute INIT_0E of bram : label is
"0000000000000000000000000000000000000000000000000000000000000000" ;
attribute INIT_0F of bram : label is
"0000000000000000000000000000000000000000000000000000000000000000" ;

begin
bram : component RAMB4_S8_S16
generic map (
INIT_00 =>
X"8322E2130200832B9D0561018339834BF210A211832B010F8340038083400301",
INIT_01 =>
X"83228347E212E2130203832B83228347E212E2130202832B8322E2130201832B",
INIT_02 =>
X"6000A010952B6000A01080809D2561018339834BB210010F834003C08100832B",
INIT_03 =>
X"8080E0110000E0110002E2108335808091356000A01280809532640104FF912E",
INIT_04 =>
X"808042309D50600AC020808091476000A0138080E0110000E0110001E3108335",
INIT_05 =>
X"0000000000000000000000000000000000000000000000000000808042406209",
INIT_06 =>
X"0000000000000000000000000000000000000000000000000000000000000000",
INIT_07 =>
X"0000000000000000000000000000000000000000000000000000000000000000",
INIT_08 =>
X"0000000000000000000000000000000000000000000000000000000000000000",
INIT_09 =>
X"0000000000000000000000000000000000000000000000000000000000000000",
INIT_0A =>
X"0000000000000000000000000000000000000000000000000000000000000000",
INIT_0B =>
X"0000000000000000000000000000000000000000000000000000000000000000",
INIT_0C =>
X"0000000000000000000000000000000000000000000000000000000000000000",
INIT_0D =>
X"0000000000000000000000000000000000000000000000000000000000000000",
INIT_0E =>
X"0000000000000000000000000000000000000000000000000000000000000000",
INIT_0F =>
X"0000000000000000000000000000000000000000000000000000000000000000"
)
port map (
DIB => "0000000000000000",
ENB => '1',
WEB => '0',
RSTB => '0',
CLKB => clk,
ADDRB => address,
DOB => instruction( 15 downto 0 ),

- 88 -
Diseño sobre FPGA de una Unidad Aritmética Decimal Anexos

DIA => jdata( 7 downto 0 ),


ENA => juser1,
WEA => jwrite,
RSTA => '0',
CLKA => clk,
ADDRA => jaddr,
DOA => open
) ;

jdata <= ( others => '0' ) ;


jaddr <= ( others => '0' ) ;
juser1 <= '0' ;
jwrite <= '0' ;
end architecture mix ;

5.1.10 Circuito completo (main.vhd)

----------------------------------------------------------------------
--Entidad del circuito completo
----------------------------------------------------------------------
LIBRARY IEEE;
USE IEEE.STD_LOGIC_1164.ALL;
USE IEEE.STD_LOGIC_ARITH.ALL;
USE IEEE.STD_LOGIC_UNSIGNED.ALL;

ENTITY main IS PORT(


data_in: IN STD_LOGIC_VECTOR(3 DOWNTO 0);
ext_clk: IN STD_LOGIC;
reset: IN STD_LOGIC;
synch: IN STD_LOGIC;
lcd_data: OUT STD_LOGIC_VECTOR(3 DOWNTO 0);
lcd_e: OUT STD_LOGIC;
lcd_rs: OUT STD_LOGIC;
lcd_rw: OUT STD_LOGIC);
END main;

----------------------------------------------------------------------
--Arquitectura del circuito completo
----------------------------------------------------------------------
LIBRARY IEEE;
USE IEEE.STD_LOGIC_1164.ALL;
USE IEEE.STD_LOGIC_ARITH.ALL;
USE IEEE.STD_LOGIC_UNSIGNED.ALL;

ARCHITECTURE architecture_main OF main IS

--Declaración de componentes
COMPONENT kcpsm IS PORT( --Procesador
instruction: IN STD_LOGIC_VECTOR(15 DOWNTO 0);
in_port: IN STD_LOGIC_VECTOR(7 DOWNTO 0);
interrupt: IN STD_LOGIC;
reset: IN STD_LOGIC;
clk: IN STD_LOGIC;
address: OUT STD_LOGIC_VECTOR(7 DOWNTO 0);
port_id: OUT STD_LOGIC_VECTOR(7 DOWNTO 0);
out_port: OUT STD_LOGIC_VECTOR(7 DOWNTO 0);
write_strobe: OUT STD_LOGIC;
read_strobe: OUT STD_LOGIC);
END COMPONENT;

- 89 -
Diseño sobre FPGA de una Unidad Aritmética Decimal Anexos

COMPONENT program_memory IS PORT( --Memoria de programa


address: IN STD_LOGIC_VECTOR(7 DOWNTO 0);
clk: IN STD_LOGIC;
instruction: OUT STD_LOGIC_VECTOR(15 DOWNTO 0);
reset: OUT STD_LOGIC);
END COMPONENT;

COMPONENT lcd_interface IS PORT( --Interfaz LCD


temp_wr: IN STD_LOGIC_VECTOR(7 DOWNTO 0);
reset: IN STD_LOGIC;
clk: IN STD_LOGIC;
i_write: IN STD_LOGIC;
d_write: IN STD_LOGIC;
lcd_data: OUT STD_LOGIC_VECTOR(3 DOWNTO 0);
lcd_e: OUT STD_LOGIC;
lcd_rs: OUT STD_LOGIC;
lcd_rw: OUT STD_LOGIC;
ready: OUT STD_LOGIC);
END COMPONENT;

COMPONENT arithmetic_unit IS --Unidad aritmética decimal


GENERIC (n, p, logp: NATURAL);
PORT(
x: IN STD_LOGIC_VECTOR(4*n-1 DOWNTO 0); --operando x
y: IN STD_LOGIC_VECTOR(4*n-1 DOWNTO 0); --operando y
operation: IN STD_LOGIC_VECTOR(1 DOWNTO 0); --operación
start: IN STD_LOGIC; --señal de inicio
clk: IN STD_LOGIC; --señal de reloj
reset: IN STD_LOGIC; --inicializa
z: OUT STD_LOGIC_VECTOR(8*n-1 DOWNTO 0); --resultado
done: OUT STD_LOGIC); --operación lista
END COMPONENT;

--Declaración de señales
SIGNAL port_id, in_port: STD_LOGIC_VECTOR(7 DOWNTO 0);
SIGNAL mult_out: STD_LOGIC_VECTOR(3 DOWNTO 0);
SIGNAL ready, done: STD_LOGIC;

SIGNAL instruction: STD_LOGIC_VECTOR(15 DOWNTO 0);


SIGNAL address, out_port: STD_LOGIC_VECTOR(7 DOWNTO 0);
SIGNAL interrupt, write_strobe, read_strobe: STD_LOGIC;

SIGNAL temp_wr: STD_LOGIC_VECTOR(7 DOWNTO 0);


SIGNAL i_write, d_write: STD_LOGIC;

SIGNAL id_write: STD_LOGIC_VECTOR(1 DOWNTO 0);


SIGNAL x, y: STD_LOGIC_VECTOR(31 DOWNTO 0);
SIGNAL operation: STD_LOGIC_VECTOR(1 DOWNTO 0);

SIGNAL z: STD_LOGIC_VECTOR(63 DOWNTO 0);


SIGNAL start_op: STD_LOGIC;

SIGNAL clk_2, clk_4, clk_8, clk: STD_LOGIC;

- 90 -
Diseño sobre FPGA de una Unidad Aritmética Decimal Anexos

--Inicio
BEGIN

WITH port_id SELECT in_port <=


("0000000"&synch) when "00010000",
("0000"&data_in) when "00010001",
("0000000"&ready) when "00010010",
("0000000"&done) when "00010011",
("0000"&mult_out) when others;

processor: kcpsm PORT MAP(


instruction, in_port, interrupt, reset, clk, address, port_id,
out_port, write_strobe, read_strobe);

memory: program_memory PORT MAP(


address => address,
clk => clk,
instruction => instruction);

output_interface: lcd_interface PORT MAP(


temp_wr, reset, clk, i_write, d_write, lcd_data, lcd_e, lcd_rs,
lcd_rw, ready);

--Divisor de frecuencia
PROCESS(ext_clk)
BEGIN
IF reset = '1' THEN clk_2 <= '0';
ELSIF ext_clk'EVENT AND ext_clk = '1' THEN clk_2 <= NOT(clk_2);
END IF;
END PROCESS;

PROCESS(clk_2)
BEGIN
IF reset = '1' THEN clk_4 <= '0';
ELSIF clk_2'EVENT AND clk_2 = '1' THEN clk_4 <= NOT(clk_4);
END IF;
END PROCESS;

PROCESS(clk_4)
BEGIN
IF reset = '1' THEN clk_8 <= '0';
ELSIF clk_4'EVENT AND clk_4 = '1' THEN clk_8 <= NOT(clk_8);
END IF;
END PROCESS;

PROCESS(clk_8)
BEGIN
IF reset = '1' THEN clk <= '0';
ELSIF clk_8'EVENT AND clk_8 = '1' THEN clk <= NOT(clk);
END IF;
END PROCESS;

--Registros
register_temp_wr: PROCESS(clk)
BEGIN
IF clk'event AND clk = '0' THEN
IF port_id = "00010000" AND write_strobe = '1' THEN temp_wr <=
out_port;
END IF;
END IF;
END PROCESS;

- 91 -
Diseño sobre FPGA de una Unidad Aritmética Decimal Anexos

register_id_write: PROCESS(clk)
BEGIN
IF clk'event AND clk = '0' THEN
IF reset = '1' THEN id_write <= "00";
ELSIF port_id = "00010001" AND write_strobe = '1' THEN
id_write <= out_port(1 DOWNTO 0);
END IF;
END IF;
END PROCESS;

i_write <= id_write(0);


d_write <= id_write(1);

register_x: PROCESS(clk)
BEGIN
IF clk'event AND clk = '0' THEN
IF port_id = "00001000" AND write_strobe = '1' THEN
x(3 DOWNTO 0) <= out_port(3 DOWNTO 0);
ELSIF port_id = "00001001" AND write_strobe = '1' THEN
x(7 DOWNTO 4) <= out_port(3 DOWNTO 0);
ELSIF port_id = "00001010" AND write_strobe = '1' THEN
x(11 DOWNTO 8) <= out_port(3 DOWNTO 0);
ELSIF port_id = "00001011" AND write_strobe = '1' THEN
x(15 DOWNTO 12) <= out_port(3 DOWNTO 0);
ELSIF port_id = "00001100" AND write_strobe = '1' THEN
x(19 DOWNTO 16) <= out_port(3 DOWNTO 0);
ELSIF port_id = "00001101" AND write_strobe = '1' THEN
x(23 DOWNTO 20) <= out_port(3 DOWNTO 0);
ELSIF port_id = "00001110" AND write_strobe = '1' THEN
x(27 DOWNTO 24) <= out_port(3 DOWNTO 0);
ELSIF port_id = "00001111" AND write_strobe = '1' THEN
x(31 DOWNTO 28) <= out_port(3 DOWNTO 0);
END IF;
END IF;
END PROCESS;

register_y: PROCESS(clk)
BEGIN
IF clk'event AND clk = '0' THEN
IF port_id = "00000000" AND write_strobe = '1' THEN
y(3 DOWNTO 0) <= out_port(3 DOWNTO 0);
ELSIF port_id = "00000001" AND write_strobe = '1' THEN
y(7 DOWNTO 4) <= out_port(3 DOWNTO 0);
ELSIF port_id = "00000010" AND write_strobe = '1' THEN
y(11 DOWNTO 8) <= out_port(3 DOWNTO 0);
ELSIF port_id = "00000011" AND write_strobe = '1' THEN
y(15 DOWNTO 12) <= out_port(3 DOWNTO 0);
ELSIF port_id = "00000100" AND write_strobe = '1' THEN
y(19 DOWNTO 16) <= out_port(3 DOWNTO 0);
ELSIF port_id = "00000101" AND write_strobe = '1' THEN
y(23 DOWNTO 20) <= out_port(3 DOWNTO 0);
ELSIF port_id = "00000110" AND write_strobe = '1' THEN
y(27 DOWNTO 24) <= out_port(3 DOWNTO 0);
ELSIF port_id = "00000111" AND write_strobe = '1' THEN
y(31 DOWNTO 28) <= out_port(3 DOWNTO 0);
END IF;
END IF;
END PROCESS;

- 92 -
Diseño sobre FPGA de una Unidad Aritmética Decimal Anexos

register_operation: PROCESS(clk)
BEGIN
IF clk'event AND clk = '0' THEN
IF port_id = "00010011" AND write_strobe = '1' THEN
operation(1 DOWNTO 0) <= out_port(1 DOWNTO 0);
END IF;
END IF;
END PROCESS;

start_op <= '1' WHEN port_id = "00010010" AND write_strobe = '1'


ELSE '0';

main_component: arithmetic_unit
GENERIC MAP(n => 8, p => 56, logp => 6)
PORT MAP(
x => x,
y => y,
operation => operation,
start => start_op,
clk => clk,
reset => reset,
z => z,
done => done);

WITH port_id SELECT mult_out <=


z(3 DOWNTO 0) WHEN "00000000",
z(7 DOWNTO 4) WHEN "00000001",
z(11 DOWNTO 8) WHEN "00000010",
z(15 DOWNTO 12) WHEN "00000011",
z(19 DOWNTO 16) WHEN "00000100",
z(23 DOWNTO 20) WHEN "00000101",
z(27 DOWNTO 24) WHEN "00000110",
z(31 DOWNTO 28) WHEN "00000111",
z(35 DOWNTO 32) WHEN "00001000",
z(39 DOWNTO 36) WHEN "00001001",
z(43 DOWNTO 40) WHEN "00001010",
z(47 DOWNTO 44) WHEN "00001011",
z(51 DOWNTO 48) WHEN "00001100",
z(55 DOWNTO 52) WHEN "00001101",
z(59 DOWNTO 56) WHEN "00001110",
z(63 DOWNTO 60) WHEN OTHERS;

interrupt <= '0';

END architecture_main;

- 93 -
Diseño sobre FPGA de una Unidad Aritmética Decimal Anexos

5.2 Programa en lenguaje ensamblador (decimal_unit.asm)

VHDL "my_ROM_blank.vhd", "program_memory.vhd", "program_memory"

;direcciones de entrada
z0 DSIN $00
z1 DSIN $01
z2 DSIN $02
z3 DSIN $03
z4 DSIN $04
z5 DSIN $05
z6 DSIN $06
z7 DSIN $07
z8 DSIN $08
z9 DSIN $09
z10 DSIN $0a
z11 DSIN $0b
z12 DSIN $0c
z13 DSIN $0d
z14 DSIN $0e
z15 DSIN $0f
synch DSIN $10
data_in DSIN $11
ready DSIN $12
done DSIN $13

;direcciones de salida
y0 DSOUT $00
y1 DSOUT $01
y2 DSOUT $02
y3 DSOUT $03
y4 DSOUT $04
y5 DSOUT $05
y6 DSOUT $06
y7 DSOUT $07
x0 DSOUT $08
x1 DSOUT $09
x2 DSOUT $0a
x3 DSOUT $0b
x4 DSOUT $0c
x5 DSOUT $0d
x6 DSOUT $0e
x7 DSOUT $0f
temp_wr DSOUT $10
id_write DSOUT $11
start DSOUT $12
operation DSOUT $13

;registros internos
acc EQU s0
address EQU s1
data EQU s2
command EQU s3
counter EQU s4

- 94 -
Diseño sobre FPGA de una Unidad Aritmética Decimal Anexos

;main program
begin:
load command, $01
call lcd_control ;send command 01 (clear) to display,
;borramos el display
load command, $80
call lcd_control ;send command 80 (cursor address = 00) to
;display, situamos el cursor al inicio de
;la primera fila
load address, $0f ;initial address = 15

first: ;escribimos los 16 dígitos de entrada, 8


;para 'x' y 8 para 'y'
call wait_for_synch ;wait for a positive edge on synch
in data, data_in ;store data_in in data
out data, address ;write data into x(address)
call encode_data ;data = ASCII code
call lcd_data ;display character data
sub address, $01 ;update address
jump NC, first ;check whether address < 0

;addition
call wait_for_synch ;wait for a positive edge on synch
load data, $00
out data, operation ;operation = 00
call display_z ;display x+y
;end of addition

;substraction
call wait_for_synch ;wait for a positive edge on synch
load data, $01
out data, operation ;operation = 01
call display_z ;display x-y
;end of substraction

;multiplication
call wait_for_synch ;wait for a positive edge on synch
load data, $02
out data, operation ;operation = 10
out data, start ;start computation
call wait_for_done
call display_z ;display x*y
;end of multiplication

;division
call wait_for_synch ;wait for a positive edge on synch
load data, $03
out data, operation ;operation = 11
out data, start ;start computation
call wait_for_done
call display_z ;display x/y
;end of division

call wait_for_synch ;wait for a positive edge on synch


jump begin
;end of main program

- 95 -
Diseño sobre FPGA de una Unidad Aritmética Decimal Anexos

;subroutines:

;display the result of the operation


display_z:
load command, $c0
call lcd_control ;send command c0 (cursor address = 40) to
;display
load address, $0f ;initial address = 15

first_bis:
in data, address ;read z(address)
call encode_data ;data = ASCII code
call lcd_data ;display character data
sub address, $01 ;update address
jump NC, first_bis ;check whether address < 0
ret

;wait for a positive edge on synch; acc is modified


wait_for_synch:
in acc, synch
sub acc, $00
jump NZ, wait_for_synch

wait_for_1:
in acc, synch
sub acc, $00
jump Z, wait_for_1
load counter, $ff

update_counter:
sub counter, $01
jump NZ, update_counter
ret

;wait until ready is set; acc is modified


wait_for_ready:
in acc, ready
sub acc, $00
jump Z, wait_for_ready
ret

;lcd_data sends the character "data" to temp_wr and generates a


;two-cycle pulse on d_write; it clears "acc"
lcd_data:
call wait_for_ready ;wait fot lcd_interface ready
out data, temp_wr ;send character to lcd
load acc, $02 ;set d_write
out acc, id_write
load acc, $00 ;clear d_write
out acc, id_write
ret

- 96 -
Diseño sobre FPGA de una Unidad Aritmética Decimal Anexos

;lcd_controls sends the instruction "command" to temp_wr and generates a


;two-cycle pulse on i_write; it clears "acc"
lcd_control:
call wait_for_ready ;wait fot lcd_interface ready
out command, temp_wr ;send instruction to lcd
load acc, $01 ;set i_write
out acc, id_write
load acc, $00 ;clear i_write
out acc, id_write
ret

;wait until done is set; acc is modified


wait_for_done:
in acc, done
sub acc, $00
jump Z, wait_for_done
ret

;data = ASCII(data)
encode_data:
load acc, data
sub acc, $0a
jump NC, g_t_9
add data, $30
ret

g_t_9:
sub data, $09
add data, $40
ret

5.3 Asignación de pines en la Spartan-3E (pins.ucf)

NET "ext_clk" LOC = "C9" | IOSTANDARD = LVCMOS33 ;


NET "reset" LOC = "K17" | IOSTANDARD = LVTTL | PULLDOWN ;
NET "data_in<3>" LOC = "N17" | IOSTANDARD = LVTTL | PULLUP ;
NET "data_in<2>" LOC = "H18" | IOSTANDARD = LVTTL | PULLUP ;
NET "data_in<1>" LOC = "L14" | IOSTANDARD = LVTTL | PULLUP ;
NET "data_in<0>" LOC = "L13" | IOSTANDARD = LVTTL | PULLUP ;

NET "synch" LOC = "D18" | IOSTANDARD = LVTTL | PULLDOWN ;

NET "lcd_e" LOC = "M18" | IOSTANDARD = LVCMOS33 | DRIVE = 4 | SLEW = SLOW


;
NET "lcd_rs" LOC = "L18" | IOSTANDARD = LVCMOS33 | DRIVE = 4 | SLEW =
SLOW ;
NET "lcd_rw" LOC = "L17" | IOSTANDARD = LVCMOS33 | DRIVE = 4 | SLEW =
SLOW ;
NET "lcd_data<3>" LOC = "M15" | IOSTANDARD = LVCMOS33 | DRIVE = 4 | SLEW
= SLOW ;
NET "lcd_data<2>" LOC = "P17" | IOSTANDARD = LVCMOS33 | DRIVE = 4 | SLEW
= SLOW ;
NET "lcd_data<1>" LOC = "R16" | IOSTANDARD = LVCMOS33 | DRIVE = 4 | SLEW
= SLOW ;
NET "lcd_data<0>" LOC = "R15" | IOSTANDARD = LVCMOS33 | DRIVE = 4 | SLEW
= SLOW ;

- 97 -
Diseño sobre FPGA de una Unidad Aritmética Decimal

6. BIBLIOGRAFÍA
Diseño sobre FPGA de una Unidad Aritmética Decimal Bibliografía

6. Bibliografía

[1] Serafín Alfonso Pérez, Enrique Soto, Santiago Fernández, “Diseño de Sistemas Digitales con VDHL”,
Editorial Thomson, 2002.

[2] Fernando Pardo Carpio, José A. Boluda Grau, “VHDL: Lenguaje para síntesis y modelado de
circuitos”, Editorial Ra-Ma, 1999.

[3] John F. Wakerly, “Diseño digital. Principios y prácticas”, Tercera edición, Editorial Prentice Hall,
2001.

[4] Thomas L. Floyd, “Fundamentos de sistemas digitales”, Novena edición, Editorial Prentice Hall,
2006.

[5] M. Vazquez, G. Sutter, G. Bioul, J.-P. Deschamps, “Decimal adders/substractors in FPGA: Efficient
6-input LUT implementations”.

[6] J.-P. Deschamps, G. Sutter, G. Bioul, M. Vazquez, “Decimal division: algorithms and FPGA
implementations”.

[7] G. Sutter, E. Todorovich, G. Bioul, M. Vazquez, J.-P. Deschamps, “FPGA Implementations of BCD
Multipliers”.

[8] Electrónica Digital I, apuntes de la asignatura.

[9] ModelSim User’s Manual Software Version 6.5ª, Mentor Graphics, 2009.

[10] Spartan-3E FPGA Starter Kit Board User Guide, UG230 (v1.1), Xilinx, 2008.

[11] Spartan-3E FPGA Family: Functional Description, DS312-2 (v1.0), Xilinx, 2005.

[12] PicoBlaze 8-Bit Microcontroller for Virtex-E and Spartan-II/IIE Devices, XAPP213 (v2.1), Xilinx,
2003.

[13] http://www.model.com/

[14] http://www.xilinx.com/

- 99 -

Anda mungkin juga menyukai