En este tutorial veremos una versión mejorada de la CPU sencilla que hicimos en el capítulo 7.
Esta nueva release de la CPU corrige un bug por cual al introducir un nuevo dato en el bus, la ALU se realimenta de manera automática ofreciendo un resultado no deseado.
Para corregir dicho bug, se añade una señal enable a los registros y se conecta un tercer registro C en la salida de la ALU, de manera que el resultado de la ALU no pasa directamente al bus, si no que se almacena en dicho registro C y se pone en el bus mediante la señal enable correspondiente.
La imagen siguiente muestra el esquema de la CPU.
El resto de módulos de la CPU no cambia respecto del proyecto original -ya explicado en el Capítulo 7-, así que sólo veremos cómo se instancia este nuevo registro C en el módulo top.
module sap_cpu_top (clk, reset, a_latch, b_latch, c_latch, c_enable, a_enable, b_enable, alu_enable, data_in_enable, alu_sub, data_sw, led0, led1, led2, led3, led6, led7, seg, an, alu_C, alu_Z);
input clk, reset; // generic inputs
input a_latch, a_enable; // a reg inputs
input b_latch, b_enable; // b reg inputs
input c_latch, c_enable; // ALU reg inputs
input alu_enable, alu_sub, data_in_enable;
input [7:0] data_sw;
//input [3:0] opcore;
output alu_C, alu_Z;
output [6:0] seg;
output [3:0] an;
output led0, led1, led2, led3, led6, led7;
wire [7:0] data_bus, a_reg_bus, b_reg_bus, ssd_bus, alu_reg_bus, alu_bus;
wire w30, w31;
assign led0 = data_in_enable;
assign led1 = a_enable;
assign led2 = b_enable;
assign led3 = alu_enable;
assign led6 = w30;
assign led7 = w31;
//******************
// Structural coding
//******************
// encoder para seleccion de bus de datos
encoder ENC (
.in0(data_in_enable),
.in1(a_enable),
.in2(b_enable),
.in3(c_enable),
.s0(w30),
.s1(w31));
// mux 4-1 para bus de datos
mux_bus MB (
.s0(w30),
.s1(w31),
.in3(alu_reg_bus),
.in2(b_reg_bus),
.in1(a_reg_bus),
.in0(data_sw),
.out(data_bus));
// a register
sap_register a_register (
.clk(clk),
.reset(reset),
.DATA_IN(data_bus),
.latch(a_latch),
.enable(a_enable),
.REG_OUT(a_reg_bus));
// b register
sap_register b_register (
.clk(clk),
.reset(reset),
.DATA_IN(data_bus),
.latch(b_latch),
.enable(b_enable),
.REG_OUT(b_reg_bus));
// ALU register
sap_register c_register (
.clk(clk),
.reset(reset),
.DATA_IN(alu_bus),
.latch(c_latch),
.enable(c_enable),
.REG_OUT(alu_reg_bus));
// ALU
sap_alu ALU (
.enable(alu_enable),
.sub(alu_sub),
.A(a_reg_bus),
.B(b_reg_bus),
.DATA(alu_bus),
.C(alu_C),
.Z(alu_Z));
//.opcore(opcore),
// mux for seven segment display
mux4_1 MUX41 (
.clk(clk),
.in_0(alu_reg_bus),
.in_1(b_reg_bus),
.in_2(a_reg_bus),
.in_3(data_bus),
.out(ssd_bus),
.gates(an));
// Seven segnent display driver
ssd_driver SSDD (
.in(ssd_bus),
.seg(seg));
endmodule
El archivo .XDC queda así:
Lo subimos a la BASYS 3 y comprobamos el funcionamiento.
Con los switches sw8-15 introducimos los datos en el bus y con los pulsadores L y C los cargamos en los registros A y B respectivamente. Con los switches sw1 y sw2 verificamos que los datos se han almacenado correctamente.
Al accionar sw4 se habilita la ALU y con el pulsador R se almacena el resultado en el registro C. Con el sw3 habilitamos el registro C y verificamos que el resultado es correcto. Podemos seleccionar entre sumar o restar con el sw5.
Para mostrar correctamente los datos en los displays de 7 segmentos de la BASYS 3, sólo he tenido en cuenta los 4 bits menos significativos del bus.
Primera Parte: El bus de datos
Many thanks to Phil, for sharing his 8 bit computer project.
& 100 Random Task: Create a custom CPU from scratch.
Puedes descargar los archivos Verilog de este tutorial aquí abajo.