---
# System prepended metadata

title: 'Lab. 4: Microcontrolador'

---

# Lab. 4: Microcontrolador

## 1. Abreviaturas y definiciones
- **FPGA**: Field Programmable Gate Arrays
- **UART**: Universal Asynchronous Receiver / Transmitter
- **RISC-V**: Reduced Instruction Set Computer-V

## 2. Referencias
[0] David Harris y Sarah Harris. *Digital Design and Computer Architecture. RISC-V Edition.* Morgan Kaufmann, 2022. ISBN: 978-0-12-820064-3

## 3. Desarrollo


### 3.1 Microprocesador monociclo

La arquitectura del microprocesador desarrollado se basa en los siguientes módulos:

* `module_riscvsingle.sv`
* `module_controller.sv`
* `module_datapath.sv`
* `module_main_decoder.sv`
* `module_alu_decoder.sv`
* `module_adder.sv`
* `module_alu.sv`
* `module_extend.sv`
* `module_flopr.sv`
* `module_mux_2_a_1.sv`
* `module_mux_3_a_1.sv`
* `module_regfile.sv`


### 3.2 module_riscvsingle

Este es el módulo del microprocesador, por lo que en él se instancian los módulos del controlador y el datapath.

#### 1. Encabezado del módulo
```SystemVerilog
module module_riscvsingle_v2(
    
    input logic             clk_i,
    input logic             rst_i,
    input logic [31 : 0]    ProgIn_i,
    input logic [31 : 0]    Data_In_i,  
    output logic            we_o,
    output logic [31 : 0]   ProgAddress_o,
    output logic [31 : 0]   DataAddress_o,
    output logic [31 : 0]   DataOut_o
    
    );
```
#### 2. Parámetros
Este módulo no tiene parámetros.

#### 3. Entradas y salidas:
- `clk_i`: señal del reloj de 10 MHz.
- `rst_i`: reset del sistema.
- `ProgIn_i`: entrada de la memoria de instrucciones.
- `Data_In_i`: entrada de la memoria de datos.
- `we_o`: señal de write enable.
- `ProgAddress_o`: address de la memoria de instrucciones.
- `DataAddress_o`: address de la memoria de datos.
- `DataOut_o`: datos de la salida.

#### 4. Criterios de diseño

Para el diseño del microprocesador se hizo uso de la literatura recomendada para el curso, dada en [0].

#### 4. Testbench

Este módulo no tiene testbench.


### 3.3 module_controller

Este corresponde al controlador principal del microprocesador monociclo.

#### 1. Encabezado del módulo
```SystemVerilog
module module_controller(
    
    input logic             funct7b5_i,
    input logic             zero_i,
    input logic [6 : 0]     op_i,
    input logic [2 : 0]     funct3_i,  
    output logic            mem_write_o,
    output logic            pc_src_o,
    output logic            alu_src_o,
    output logic            reg_write_o,
    output logic            jump_o,
    output logic [1 : 0]    result_src_o,
    output logic [1 : 0]    imm_src_o, 
    output logic [2 : 0]    alu_control_o   

    );
```
#### 2. Parámetros
Este módulo no tiene parámetros.

#### 3. Entradas y salidas:
- `funct7b5_i`: señal de entrada de 1 bit.
- `zero_i`: entrada del indicar de resultado 0 en la ALU.
- `op_i`: dato de 7 bits que contiene la operación por realizar.
- `funct3_i`: señal de entrada de 3 bits.
- `mem_write_o`: señal de salida del write enable.
- `pc_src_o`: señal de salida de 1 bit.
- `alu_src_o`: señal de salida de 1 bit.
- `reg_write_o`: señal de escritura en el registro.
- `jump_o`: señal de salida de 1 bit.
- `result_src_o`:señal de salida de 2 bits.
- `imm_src_o`: señal de salida de 2 bits.
- `alu_control_o`: señal de 3 bits que controla la operación de la ALU.



#### 4. Testbench

Este módulo no tiene testbench.

### 3.4 module_main_decoder 

Este corresponde al decodificador principal del microprocesador monociclo.

#### 1. Encabezado del módulo
```SystemVerilog
module module_main_decoder (

    input   logic   [6:0]   op_i,
    output  logic           mem_write_o,
    output  logic           branch_o, 
    output  logic           alu_src_o,
    output  logic           reg_write_o,
    output  logic           jump_o,
    output  logic   [1:0]   alu_op_o,
    output  logic   [1:0]   result_src_o,
    output  logic   [1:0]   imm_src_o
    
    );
```
#### 2. Parámetros
Este módulo no tiene parámetros.

#### 3. Entradas y salidas:
- `op_i`: señal de entrada de 7 bits.
- `mem_write_o`: señal de salida de write enable.
- `branch_o`: señal de salida de 1 bit que permite hacer branch.
- `alu_src_o`: señal de salida de 1 bit.
- `reg_write_o`: señal de escritura en el registro.
- `jump_o`: señal de salida de 1 bit.
- `alu_op_o`: señal de 2 bits que indica la operación en la ALU.
- `result_src_o`; señal de salida de 2 bits.
- `imm_src_o`: señal de salida de 2 bits.




#### 4. Testbench

Este módulo no tiene testbench.



### 3.5 module_alu_decoder

Este corresponde al decodificador de la ALU del microprocesador monociclo.

#### 1. Encabezado del módulo
```SystemVerilog
module module_alu_decoder (

    input   logic                   opb5_i,
    input   logic   [2 : 0]         funct3_i,
    input   logic                   funct7b5_i,
    input   logic   [1 : 0]         alu_op_i,
    output  logic   [2 : 0]         alu_control_o
 
     );
```
#### 2. Parámetros
Este módulo no tiene parámetros.

#### 3. Entradas y salidas:
- `opb5_i`: señal de entrada de 1 bit.
- `funct3_i`: señal de entrada de 3 bits.
- `funct7b5_i`: señal de entrada de 1 bit.
- `alu_op_i`: señal de entrada de 2 bits para seleccionar la funcionalidad.
- `alu_control_o`: señal de salida de 3 bits que controla la ALU.




#### 4. Testbench

Este módulo no tiene testbench.


### 3.6 module_datapath

Corresponde al datapath del microprocesador monociclo.

#### 1. Encabezado del módulo
```SystemVerilog
module module_datapath (

        input logic                 clk_i, 
        input logic                 rst_i,
        input logic                 pc_src_i, 
        input logic                 alu_src_i,
        input logic                 reg_write_i, 
        input logic     [1:0]       result_src_i,
        input logic     [1:0]       imm_src_i,
        input logic     [2:0]       alu_control_i,
        input logic     [31:0]      instr_i,
        input logic     [31:0]      read_data_i,
        output logic                zero_o,
        output logic    [31:0]      pc_o,
        output logic    [31:0]      alu_out_o, 
        output logic    [31:0]      write_data_o
        
        );
```
#### 2. Parámetros
Este módulo no tiene parámetros.

#### 3. Entradas y salidas:
- `clk_i`: señal de entrada del reloj.
- `rst_i`: señal de entrada del reset.
- `pc_src_i`: señal de entrada para habilitar el program counter.
- `alu_src_i`: señal de entrada de 1 bit.
- `reg_write_i`: señal de entrada para escritura de registro.
- `result_src_i`: señal de entrada de 2 bits de los resultados
- `imm_src_i`: señal de 2 bits de entrada.
- `alu_control_i`: señal de entrada de 3 bits del control de la ALU.
- `instr_i`: señal de entrada de 32 bits.
- `read_data_i`: señal de entrada de 32 bits.
- `zero_o`: señal de salida del zero flag.
- `pc_o`: salida de 32 bits del program counter.
- `alu_out_o`: salida de 32 bits de la ALU.
- `write_data_o`: salida de 32 bits de los datos a escribir en memoria RAM.



#### 4. Testbench

Este módulo no tiene testbench.


### 3.7 module_flopr

Corresponde a un módulo parametrizable de un flip-flop tipo D.

#### 1. Encabezado del módulo
```SystemVerilog
module module_flopr #(parameter WIDTH = 8)(
    
    input   logic                       clk_i,
    input   logic                       rst_i,
    input   logic   [WIDTH - 1: 0]      d_i,
    output  logic   [WIDTH - 1: 0]      q_o
                 
    );
```
#### 2. Parámetros
- `WIDTH`: ancho de los bits de entrada

#### 3. Entradas y salidas:
- `clk_i`: señal de entrada del reloj.
- `rst_i`: señal de reset.
- `d_i`: dato de entrada.
- `q_o`: salida del flip-flop.


#### 4. Testbench

Este módulo no tiene testbench.


### 3.8 module_adder

Corresponde a un módulo sumador de datos de 32 bits.

#### 1. Encabezado del módulo
```SystemVerilog
module module_adder(
    
    input logic [31 : 0]    a_i,
    input logic [31 : 0]    b_i,
    output logic [31 : 0]   y_o
    
);
```
#### 2. Parámetros
Este módulo no tiene parámetros.

#### 3. Entradas y salidas:
- `a_i`: sumando 1.
- `b_i`: sumando 2.
- `y_o`: resultado de la suma.

#### 4. Testbench

Este módulo no tiene testbench.


### 3.9 module_mux_2_a_1

Corresponde a un multiplexor 2 a 1 parametrizable.

#### 1. Encabezado del módulo
```SystemVerilog
module module_mux_2_a_1 #(parameter WIDTH = 8)(
    
    input   logic                               s_i,
    input   logic       [WIDTH - 1 : 0]         d0_i,
    input   logic       [WIDTH - 1 : 0]         d1_i,
    output  logic       [WIDTH - 1 : 0]         y_o
    
    );
```
#### 2. Parámetros
- `WIDTH`: ancho de los datos de entrada

#### 3. Entradas y salidas:
- `s_i`: bit de selección del mux.
- `d0_i`: dato 1.
- `d1_i`: dato 2.
- `y_o`: dato de salida.

#### 4. Testbench

Este módulo no tiene testbench.


### 3.10 module_regfile

Corresponde al banco de registros del microprocesador.

#### 1. Encabezado del módulo
```SystemVerilog
module module_regfile(
    
    input   logic               clk_i,
    input   logic               rst_i,
    input   logic               we3_i,
    input   logic   [4 : 0]     a1_i,
    input   logic   [4 : 0]     a2_i,
    input   logic   [4 : 0]     a3_i,
    input   logic   [31 : 0]    wd3_i,
    output  logic   [31 : 0]    rd1_o,
    output  logic   [31 : 0]    rd2_o
    
    );
```
#### 2. Parámetros
Este módulo no tiene parámetros.

#### 3. Entradas y salidas:
- `clk_i`: señal del reloj del sistema.
- `rst_i`: reset del sistema.
- `we3_i`: señal de write enable.
- `a1_i`: dirección 1.
- `a2_i`: dirección 2.
- `a3_i`: dirección 3, usada para escribir en los registros.
- `wd3_i`: dato de 32 bits que se desea escribir en los registros.
- `rd1_o`: dato leído 1, controlado por `a1_i`.
- `rd2_o`: dato leído 2, controlado por `a2_i`.




#### 4. Testbench

Este módulo no tiene testbench.




### 3.11 module_extend

Corresponde al decodificador de instrucciones, ya que recibe una instrucción y devuelve otra en la salida.

#### 1. Encabezado del módulo
```SystemVerilog
module module_extend(

    input   logic   [31:7]      instr_i,
    input   logic   [1:0]       imm_src_i,
    output  logic   [31:0]      imm_ext_o
    
    );
```
#### 2. Parámetros
Este módulo no tiene parámetros.

#### 3. Entradas y salidas:
- `instr_i`: señal de entrada de 24 bits de instrucción.
- `imm_src_i`: señal de entrada de 2 bits.
- `imm_ext_o`: señal de salida de 32 bits.




#### 4. Testbench

Este módulo no tiene testbench.



### 3.12 module_mux_3_a_1

Corresponde a un mux 3 a 1.

#### 1. Encabezado del módulo
```SystemVerilog
module module_mux_3_a_1 #(parameter WIDTH = 8)(
    
    input   logic       [1 : 0]                 s_i,
    input   logic       [WIDTH - 1 : 0]         d0_i,
    input   logic       [WIDTH - 1 : 0]         d1_i,
    input   logic       [WIDTH - 1 : 0]         d2_i,
    output  logic       [WIDTH - 1: 0]          y_o
    
    );
```
#### 2. Parámetros
- `WIDTH`: ancho de los datos de entrada

#### 3. Entradas y salidas:
- `s_i`: selección del mux.
- `d0_i`: dato 1.
- `d1_i`: dato 2.
- `d2_i`: dato 3.
- `y_o`: salida del mux.


#### 4. Testbench

Este módulo no tiene testbench.


### 3.13 module_alu

Corresponde a la ALU del microprocesador.

#### 1. Encabezado del módulo
```SystemVerilog
module module_alu(

    input  logic    [31 : 0]        dato1_i,
    input  logic    [31 : 0]        dato2_i,
    input  logic    [2 : 0]         alu_control_i,
    output logic                    zero_o,
    output logic    [31 : 0]        alu_out_o
    
    );
```
#### 2. Parámetros
Este módulo no tiene parámetros.

#### 3. Entradas y salidas:
- `dato1_i`: operando 1.
- `dato2_i`: operando 2.
- `alu_control_i`: selector de operaciones de la ALU.
- `zero_o`: flag de resultado igual a cero en la ALU.
- `alu_out_o`: salida de la ALU.


#### 4. Testbench

Este módulo no tiene testbench.


### 3.14 top_riscv_single_cycle_processor_v2

Corresponde a un módulo TOP creado para probar el correcto funcionamiento del microprocesador.

#### 1. Encabezado del módulo
```SystemVerilog
module top_riscv_single_cycle_processor_v2(
    
    input   logic               clk_100m_i,
    input   logic               rst_i,
    output logic [31 : 0]       write_data,     
    output logic [31 : 0]       alu_out,        
    output logic                mem_write       
    
    );
```
#### 2. Parámetros
Este módulo no tiene parámetros.

#### 3. Entradas y salidas:
- `clk_100m_i`: señal de entrada del reloj de 100 MHz.
- `rst_i`: señal de entrada del reset del sistema.
- `write_data`: datos de entrada provenientes de la memoria RAM.
- `alu_out`: señal de address de la RAM.
- `mem_write`: señal del write enable de la RAM.

#### 4. Criterios de diseño

Este módulo fue creado únicamente para probar el microprocesador antes de proceder a montar el sistema empotrado final. La programación en ensamblador se encuentra en el archivo `prueba_harris_v2.asm`, este código fue provisto por el libro principal del curso, dado en [0]. En él se prueban todas las instrucciones que es capaz de realizar el microprocesador.

En este módulo se instancian tanto el microprocesador, como los IP-cores de la memoria RAM, ROM y el Clocking Wizard.

#### 5. Testbench

El archivo de testbench se encuentra en `tb_top_single_cycle_processor.sv`. Como se mencionó anteriormente, en este módulo se prueban todas las instrucciones soportadas por el microprocesador monociclo. Por lo que en caso de ejecutar todas las instrucciones correctamente, el microprocesador debería escribir el valor de  4140 (0x102C) en el address 216 (0xd8).

La siguiente figura corresponde a la simulación de comportamiento, la cual muestra el correcto funcionamiento del microprocesador, ya que a los 10.1 ns, se escribe en la memoria RAM un 4140 en la dirección 216.

![](https://hackmd.io/_uploads/S1CLiCvr2.png)

### 4.1 Bus Driver 
Corresponde al módulo creado para la comunicación entre los periféricos y el microprocesador.

#### 1. Encabezado del módulo
```SystemVerilog
module module_conductor_de_bus(
    
    input logic             we_i,                    
    input logic [31 : 0]    addr_i,
    
    input logic [31 : 0]    do_ram_i,
    input logic [31 : 0]    do_switches_i,
    input logic [31 : 0]    do_uart_a_i,
    input logic [31 : 0]    do_uart_b_i,
    input logic [31 : 0]    do_uart_c_i,
    
    output logic            we_ram_o,
    output logic            we_leds_o,
    output logic            we_7seg_o,
    output logic            we_uart_a_o,
    output logic            we_uart_b_o,
    output logic            we_uart_c_o,
    
    output logic [31 : 0]   d_out_o  

    );
```
#### 2. Parámetros
Este módulo no tiene parámetros.

#### 3. Entradas y salidas:
- `we_i`: Señal de write enable proveniente del microrocesador, entra al `DEMUX`.
- `addr_i`: Dirección proveniente del microprocesador.
- `do_ram_i`: datos de entrada provenientes de la memoria RAM.
- `do_switches_i`: Datos provenientes de los switches.
- `do_uart_a_i`: Datos provenientes del UART A.
- `do_uart_b_i`: Datos provenientes del UART B.
- `do_uart_c_i`: Datos provenientes del UART C.
- `we_ram_o`: Señal del write enable de la RAM.
- `we_leds_o`: Señal del write enable de los LED's
- `we_7seg_o`: Señal del write enable del 7 segmentos.
- `we_uart_a_o`: Señal del write enable del `UART A` 
- `we_uart_b_o`: Señal del write enable del `UART B`
- `we_uart_c_o`: Señal del write enable del `UART C`
- `d_out_o`: Salida del Mux con el valor de los datos.

#### 4. Criterios de diseño

En la siguiente figura se muestra el diagrama de bloques del bus driver.

![](https://hackmd.io/_uploads/B1WdGKCr2.jpg)


Este módulo conta de un DEMUX para la señal de `we_i` que llega hasta los perífericos para poder habilitarlos y poder obtener los datos provenientes de estos.
A la salida del MUX `d_out_o` se asignará el valor del periférico que fue seleccionado a través del microprocesador por medio del dato `addr_i`. Este puntero escoge un valor entre 0x1000 hasta 0x203C, el módulo de bus driver toma este valor y verifica el valor, una vez hecho esto, lo asocia a uno de los periféricos.


#### 5. Testbench

El archivo de testbench se encuentra en `tb_module_conductor_de_bus.sv`. En él se prueban todos los casos en los que puede estar la señal de `addr_i`, además, se asignan valores aleatorios a las señales de salida de los demás periféricos que componen el sistema. En la siguiente imagen se muestra la simulación post-síntesis, en donde se comprueba que el bus driver funciona correctamente. 

![](https://hackmd.io/_uploads/H1BaO_0Bh.png)


### 4.1 Display de 7 segmentos
#### 1. Encabezado del módulo
```SystemVerilog
module module_7seg_disp(
    
    input logic             clk,
    input logic             rst,
    input logic [31 : 0]    data_in,	
    input logic             we,
    output logic [7 : 0]    an,
    output logic [7 : 0]    seg

);
```
#### 2. Parámetros
Este módulo no tiene parámetros.

#### 3. Entradas y salidas:
- `clk`: Señal de reloj de 10MHz.
- `rst`: Señal de reset.
- `data_in`: Datos de entrada al 7 segmentos.
- `we`: Señal de write enable para habilitar el 7 segmentos.
- `an`: Habilita los anodos del display.
- `seg`: Habilita los segmentos del display.

#### 4. Criterios de diseño
Este módulo enciende los primeros 4 display del lado derecho de la FPGA Nexys4, se habilita si hay un 1 en el `we` e imprime en el diplay el dato que le llega a través de `data_in`.

#### 5. Testbench
Para este módulo no se generó un testbench.

### 4.2 LED's
#### 1. Encabezado del módulo
```SystemVerilog
module module_leds(
    input  logic          clk_i,
    input  logic          rst_i,
    input  logic          we_leds_i,
    input  logic [31 : 0] leds_i,
    output logic [15 : 0] leds_o

    );
```
#### 2. Parámetros
Este módulo no tiene parámetros.

#### 3. Entradas y salidas:
- `clk_i`: Señal de reloj de 10MHz.
- `rst_i`: Señal de reset.
- `we_leds_i`: Señal de write enable para los leds.
- `leds_i`: Dato que entra al módulo de los leds.
- `leds_o`: Dato que sale del módulo de los leds.

#### 4. Criterios de diseño
Este módulo se diseñó para recibir un valor proveniente del bus driver `leds_i`, el cual va a encender los LED's con este mismo valor en binario `leds_o`, el cual se va a habilitar por medio del `we_leds_i`.

#### 5. Testbench
Este módulo no tiene testbench.

### 4.2 Switches
#### 1. Encabezado del módulo
```SystemVerilog
module module_switches(

    input  logic          clk_i,
    input  logic          rst_i,
    input  logic [19 : 0] sw_bt_i,
    output logic [31 : 0] sw_o
    
    );
```
#### 2. Parámetros
Este módulo no tiene parámetros.

#### 3. Entradas y salidas:
- `clk_i`: Señal de reloj de 10MHz.
- `rst_i`: Señal de reset.
- `sw_bt_i`:Entrada a los swtiches.
- `sw_o`: Salida de los switches.

#### 4. Criterios de diseño
Este módulo consta con una entrada de 20 bits a la entrada `sw_bt_i` a la cual se le concatenan 12 ceros para completar un ancho de palabra de 32 bits los cuales son la salida del módulo `sw_o`.

#### 5. Testbench
Este módulo no tiene testbench.

### 4.3 Antirebotes
#### 1. Encabezado del módulo
```SystemVerilog
module module_antirrebote (

    input  logic    clk_i,      // Señal de reloj
    input  logic    rst_i,      // Señal de reset
    input  logic    btn_i,      // Señal de entrada
    output logic    q_o         // Señal de salida
        
    );
        
```
#### 2. Parámetros
Este módulo no tiene parámetros.

#### 3. Entradas y salidas:
- `clk_i`: Señal de reloj de 10MHz.
- `rst_i`: Señal de reset.
- `btn_i`:Señal de entrada con rebote.
- `q_o`:Señal de salida sin rebote.

#### 4. Criterios de diseño
Para el diseño del bloque Antirebote, se utiliza un latch SR. El módulo tiene como variables locales S y R. La señal de entrada `btn_i` define los valores de S y R: cuando la señal de entrada es valor lógico 1, S y R se colocan en 1 y 0 respectivamente. Estos valores determinan un "set" para el latch SR, y la salida `q_o` se coloca en 1. Cuando la señal de entrada es valor lógico 0, S y R se colocan en 0 y 1 respectivamente. Estos valores determinan un "reset" para el latch SR, y la salida `q_o` se coloca en 0.

#### 5. Testbench
Este módulo no tiene testbench.

### 4.2 Sincronizador
#### 1. Encabezado del módulo

```SystemVerilog
module module_sincronizador (

        input  logic clk_i,    // Señal de reloj
        input  logic reset_i,  // Señal de reset
        input  logic D0_i,     // Dato de entrada
        output logic D1_o      // Dato de salida
        
    );
        
```
#### 2. Parámetros
Este módulo no tiene parámetros.

#### 3. Entradas y salidas:
- `clk_i`: Señal de reloj de 10MHz.
- `reset_i`: Señal de reset.
- `D0_i`: Dato de entrada sin sincronizar.
- `D1_o`: Dato de salida sincronizado.

#### 4. Criterios de diseño


Para el diseño del bloque Sincronizador, el problema principal a resolver corresponde a la metaestabilidad, la cual ocurre cuando se intenta utilizar una señal en el proceso de cambiar de estado lógico bajo a alto y viceversa. Al conectar 2 flip-flops en serie, debido a la señal de reloj así como el tiempo de retardo de los componentes, la señal tiene el tiempo suficiente para cambiar su estado lógico y estabilizarse en dicho estado (La señal tiene el tiempo necesario para resolver su posible estado metaestable).

#### 5. Testbench
Este módulo no tiene testbench.

### 4.3 UART
#### 1. Encabezado del módulo
```SystemVerilog
module module_interfaz_UART ( 
    input logic             clk_i,                                
    input logic             rst_i,                                     
    input logic [31 : 0]    entrada_i,
    input logic             reg_sel_i,
    input logic             wr_i,
    input logic             addr_i,
    input logic             rx,
    output logic [31 : 0]   salida_o,
    output logic            tx      
);
        
```
#### 2. Parámetros
- Este módulo no posee parámetros.

#### 3. Entradas y salidas:
- `clk_i`: Reloj de 100MHz.
- `rst_i`: Reinicia el sistema, posee lógica positiva.
- `entrada_i`: Entrada del UART para 32 bits.
- `reg_sel_i`: Selecciona entre el registro de datos y el registro de control.
- `wr_i`: Write Enable de la unidad.
- `addr_i`: Punteros de selección entre los registros de datos 0 y 1.
- `rx`: Entrada serial para la recepción.
- `salida_o`: Salida de la unidad `UART` de 32 bits.
- `tx`: Salida serial para la transmisión de datos.

#### 4. Criterios de diseño
En este módulo se unen todos los módulos anteriormente descritos en el laboratorio 3 además de los modulos que se nos fueron brindados por el profesor como insumos para la creación de la unidad `UART`, en este modulo se instancian estos modulos además de que se realizan varios procesos por ejemplo la concatenación de los bits `new_rx` y `send` con 30 ceros para obtener un ancho de 32 bits para el registro de control.
#### 5. Testbench
Para este módulo no se realizó testbench.


### 4.4 Top del sistema empotrado

#### 1. Encabezado del módulo
```SystemVerilog
module top_sistema_empotrado(  
    
    input logic                 clk_100m_i, 
    input logic                 rst_i,      
    input logic [19 : 0]        sw_bt_i,    
    input logic                 rx_a_i,     
    input logic                 rx_b_i,
    input logic                 rx_c_i, 
    output logic [15 : 0]       leds_o,      
    output logic [7 : 0]        an_o,
    output logic [7 : 0]        seg_o,
    output logic                tx_a_o,
    output logic                tx_b_o,
    output logic                tx_c_o
    
    );
        
```
#### 2. Parámetros
- Este módulo no posee parámetros.

#### 3. Entradas y salidas:
- `clk_i`: Reloj de 100 MHz.
- `rst_i`: Botón que reinicia el sistema, posee lógica positiva.
- `sw_bt_i`: Entrada de los 16 switches y 4 botones.
- `rx_a_i`: Señal de rx del UART A.
- `rx_b_i`: Señal de rx del UART B.
- `rx_c_i`: Señal de rx del UART C.
- `leds_o`: Señal de salida de los 16 LEDS de la FPGA.
- `an_o`: Señal de 8 bits que controla los ánodos de los 7 segmentos.
- `seg_o`: Señal de 8 bits que controla los segmentos del display.
- `tx_a_o`: Señal de tx del UART A.
- `tx_b_o`: Señal de tx del UART B.
- `tx_c_o`: Señal de tx del UART C.


#### 4. Criterios de diseño


Este módulo corresponde al TOP del sistema empotrado, en él se instancian los demás periféricos que componen al sistema. Es decir, memorias ROM y RAM, Switches, LEDS, 7 segmentos, UART y el bus driver.


#### 5. Testbench

El archivo de testbench del sistema empotrado se encuentra en `tb_top_sistema_empotrado.sv`. En este testbench se define a la FPGA con el identificador 2 en los switches (`sw_bt_i[11:8]`).

En la siguiente imagen se muestra el funcionamiento de los modos: REPOSO -> PROCESAMIENTO -> CONSUMIR. Primeramente, a partir del los 400 us, se recibe el dato 0xA2 por el UART A (`rx_a_i`). Posteriormente, a los 1400 us, en la señal `leds_o` se muestra el aumento en el contador de paquetes recibidos. Luego, como los bits de destino del paquete corresponden a los bits de identificación de `sw_bt_i`, se procede a consumir el paquete recibido y se muestra en los 7 segmentos (señal `data_out[15:0]`).

![](https://hackmd.io/_uploads/H1K-gQ-Ih.jpg)


En la siguiente figura se muestra el funcionamiento de los modos: REPOSO -> PROCESAMIENTO -> RETRANSMITIR. A partir de los 1548 us, se recibe el dato 0x58 a través del UART B (`rx_b_i`). Como los bits de identificación no coinciden con los bits de destino, se procede a retransmitir el paquete por los UART A y C. Se nota que el contador de paquetes recibidos ha aumentado `leds_o`, pero el contador de paquetes consumidos no lo hace `data_out[15:8]`. 

![](https://hackmd.io/_uploads/BJ74QXbU2.jpg)

Por último, se prueban los modos: REPOSO -> GENERACIÓN. En los 12.96 ms se observa que el dato de `sw_bt_i` cambia al valor 0x102F0. Lo que significa que se presionó el bit de send (`sw_bt_i[16]`), la FPGA tiene identificador igual a 2 y se quiere enviar el dato 0xF al dispositivo 0x0. Como se observa en la figura se envía el dato de los switches por los tres UART.


![](https://hackmd.io/_uploads/SJtqV7-Lh.jpg)


## 5. Aplicación
En este módulo se diseñó dos sistemas distintos necesarios para la configuración de la Red Daisy Chain, siendo uno un sistema empotrado que es quien me ejecuta la configuración necesaria de cada dispositivo y una aplicación de la PC como centro de control, que se realizó por medio del programa Python, donde se cumplió la relación relacionada a la siguiente figura y los criterios de estos programas se definen a continuación.
![](https://hackmd.io/_uploads/rJI45aaS2.png)

Algunos parámetros de funcionamiento son que cada una de las FPGA's tuviera una dirección única de envío y que siempre la PC fuera el dispositivo `0`, para que mediante esta forma no existieran choques en los envíos de los paquetes.

Para enviar los paquetes se tuvo en cuenta el siguiente formato de instrucción.
![](https://hackmd.io/_uploads/Syi25ppBh.png)

Donde del bit `0` al bit `3` se definió como la dirección única de destinatario y del bit `4` al bit `7` se definió como el dato que quiero enviar a la dirección seleccionada.


### 5.1. Hola Mundo
Para la creación de la programación en ensamblador del Hola Mundo primero hay que tener en cuenta como funciona la unidad UART de la cual se habló anteriormente, ya que para esto tendremos que poner el bit `send` en 1, además de esto debemos apuntar a la unidad `UART` de interés para este casa va a ser la unidad C puesto que es la que está conectada al PC, está unidad tiene una dirección de establecida que abarca desde la dirección 0x2030 hasta la 0x203C. 

El valor a enviar al`UART C` se guarda en el registro de datos 1, el cual tiene la dirección 0x2038. Además de esto se le hizo un contador de 2000 ciclos de reloj al inicio para un mejor funcionamiento del `UART`. A continuación se presenta un diagrama de flujo para este módulo.

![](https://hackmd.io/_uploads/HJC_NARr2.png)



### 5.2. Aplicación en el sistema empotrado

#### 1. Criterios de diseño: 
La programación en ensamblador se encuentra en el archivo `Primer_intento.asm`. Este sistema fue diseñado por medio de la descripción de las instrucciones en ensamblador, mediante la aplicación RARS, donde se tuvo en cuenta que se necesitaban desarrollar diferentes tipos de funcionamiento, como lo son el modo Reposo, Procesamiento, Generación, Consumir y Retransmitir. Estos módulos tienen un flujo determinado relacionado con la siguiente imagen.
![](https://hackmd.io/_uploads/Hk5TvT6S2.png)

Aquí se muestra como el estado de modo Reposo es el que espera la activación del botón de inicio para pasar al modo generación y enviar el dato del banco de registros definido. Luego el modo Reposo alternativamente se encuentra en un constante sondeo (polling) que donde si se detecta un valor en la entrada del dispositivo, donde puede dividirse en dos modos adicionales, donde si el dato cumple con las características de puerto único ejecutará el modo consumir y al contrario ejecutará el modo retransmitir.

Para implementarlo en el microcontrolador, se cargó los valores obtenidos del sistema RARS en lenguaje de máquina y se configuró dentro de los archivos de ejecución de las memorias ROM quienes ejecutarán estas consultas en conjunto con los demás sistemas para lograr el correcto funcionamiento.

Para las pruebas se necesitó que al configurar la interconexión de cada FPGA existiera una resistencia de Pull-Up, que me permitía mantener los puertos restantes en un valor constante y no me aumentara los contadores de recibidos dentro del sistema. 

Por lo que se logró enviar de cada FPGA un valor y se comprobó cada modo de funcionamiento, de manera que los datos si llegaran a la dirección de destino especificada al Bus Driver del microcontrolador.



### 5.2.1 Modo Reposo

En la programación del modo reposo se hace un sondeo constante del botón de envío del bloque switches (`sw[16]`), así como un sondeo de los registros de control de los tres periféricos UART, en concreto el bit de `new_rx`.

![](https://hackmd.io/_uploads/ryhkfzWUh.jpg)


### 5.2.2 Modo Generación
Este modo se encarga de monitorear constantemente los switches del sistema, si hay algún cambio en estos y se presiona el botón predefinido para la transmisión del valor binario de los switches se transmite a través del puerto serial de las 3 unidades `UART` (A,B,C). A continuación se presenta un diagrama de flujo de este modo.
![](https://hackmd.io/_uploads/r1tKgxJUh.png)

### 5.2.3 Modo Procesamiento

A continuación se muestra el diagrama de flujo de la programación del modo de PROCESAMIENTO.

![](https://hackmd.io/_uploads/Sy7KvzWU2.jpg)

### 5.2.4 Modo Consumir

Se muestra el diagrama de flujo del modo CONSUMIR.

![](https://hackmd.io/_uploads/rkBeFfWLn.jpg)

### 5.2.5 Modo Retransmitir

 Por último, se tiene el modo RETRANSMITIR. En el cual se identifica por cuál de los 3 periféricos UART se acaba de recibir el paquete. Posteriomente, se prosigue a retransmitir el paquete por los otros 2 UART.
 
![](https://hackmd.io/_uploads/SkQ6cz-U3.jpg)


### 5.2.6 Aplicación en la PC.
#### 1. Criterios de diseño
Primeramente, se define la utilización de "Tkinter" para la interfaz gráfica. Además, se requiere la librería "pySerial" para hacer uso de los puertos seriales en la programación de Python.

Se conoce que la ventana de interfaz gráfica creada con Tkinter corresponde a un ciclo infinito para efectos de la programación de Python. Además, como parte de la funcionalidad, la PC debe siempre estar pendiente de si se recibió algún dato por el puerto serial especificado, lo cual también corresponde a un ciclo infinito. Debido a que se deben correr 2 ciclos infinitos (uno para la revisión del puerto serial y otro para la interfaz gráfica) se utilizan los hilos o "threads" de Python. Los hilos corresponden a una librería de Python que permite correr diferentes códigos "en paralelo". Por lo que se crea un hilo para la revisión del puerto serial y otro para la ventana gráfica.
Con respecto a la función de enviar, se realiza mediante el llamado al atributo "nombre_del_puerto.write". Esto permite escribir el dato en bytes al puerto serial y enviarse. La función de revisar el puerto serial se realiza con un ciclo infinito, en el cual existe un condicional con el atributo "nombre_del_puerto.InWaiting". Si dicho atributo es diferente se 0, significa que existe un dato esperando en el puerto serial.

Una vez que se sabe que existe un dato esperando, se captura dicho dato con el atributo "nombre_del_puerto.read" y se aumenta el contador de paquetes recibidos. Después se evalúa el dato recibido para saber si contiene el identificador "0000", el cual corresponde al identificador asignado para la PC. Si el mensaje tiene como destinatario la PC, en la ventana de interfaz gráfica se imprime el dato y se aumenta el contador de paquetes procesados. Si este no es el caso, sólo se aumenta el contador de paquetes recibidos.
La siguiente figura es como se ve la interfaz de usuario donde se tienen dos label color rojo y verde asignados a los contadores anteriormente descritos, dos cajas de registro para el dato a enviar y el ID de destinatario respectivamente de izquierda a derecha, el botón de enviar lo registrado anteriormente y el último label color azul que registra el dato recibido en caso de que se le envíe a la PC algún mensaje. También tenemos la lista desplegable de los puertos disponibles de la sección COM que me aporta información útil para el funcionamiento.


![](https://hackmd.io/_uploads/ByqhGWyI3.png)




