add: uart_tx module
This commit is contained in:
@@ -30,11 +30,32 @@ module top (
|
||||
input prog_we,
|
||||
|
||||
// Debug & UART
|
||||
input rx,
|
||||
output tx,
|
||||
output [1:0] leds,
|
||||
output [31:0] uart_tx_data,
|
||||
output [7:0] uart_tx_data,
|
||||
output uart_tx_en
|
||||
);
|
||||
|
||||
// ==========================================
|
||||
// BOOTLOADER
|
||||
// ==========================================
|
||||
wire [31:0] prog_data;
|
||||
wire [31:0] prog_addr;
|
||||
wire prog_we;
|
||||
wire boot_rst;
|
||||
|
||||
uart_bootloader u_boot (
|
||||
.clk(clk),
|
||||
.rx(rx),
|
||||
.prog_data(prog_data),
|
||||
.prog_addr(prog_addr),
|
||||
.prog_we(prog_we),
|
||||
.cpu_rst(boot_rst)
|
||||
);
|
||||
|
||||
wire sys_rst = rst | boot_rst;
|
||||
|
||||
// ==========================================
|
||||
// ETAPA IF
|
||||
// ==========================================
|
||||
@@ -47,7 +68,7 @@ module top (
|
||||
|
||||
pc u_pc (
|
||||
.clk(clk),
|
||||
.rst(rst),
|
||||
.rst(sys_rst),
|
||||
.next_pc(pc_stall),
|
||||
.pc_out(npc_IF)
|
||||
);
|
||||
@@ -55,7 +76,7 @@ module top (
|
||||
imem u_imem (
|
||||
.clk(clk),
|
||||
// por aqui lee la CPU
|
||||
.read_addr(pc_IF),
|
||||
.read_addr(npc_IF),
|
||||
.inst_out(ir_IF),
|
||||
// por aqui meto el programa
|
||||
.we_ext(prog_we),
|
||||
@@ -69,7 +90,7 @@ module top (
|
||||
wire [31:0] npc_ID, pc4_ID, ir_ID;
|
||||
|
||||
if_id u_if_id (
|
||||
.clk(clk), .rst(rst), .en(IF_ID_En), .clr(IF_ID_Clr),
|
||||
.clk(clk), .rst(sys_rst), .en(IF_ID_En), .clr(IF_ID_Clr),
|
||||
.pc_in(npc_IF), .pc4_in(pc4_IF), .inst_in(ir_IF),
|
||||
.pc_out(npc_ID), .pc4_out(pc4_ID), .inst_out(ir_ID)
|
||||
);
|
||||
@@ -137,7 +158,7 @@ module top (
|
||||
wire [3:0] alu_op_EX;
|
||||
|
||||
id_ex u_id_ex (
|
||||
.clk(clk), .rst(rst), .clr(ID_EX_Clr),
|
||||
.clk(clk), .rst(sys_rst), .clr(ID_EX_Clr),
|
||||
.we_reg_in(we_reg_ID), .we_mem_in(we_mem_ID), .mem_to_reg_in(mem_to_reg_ID),
|
||||
.alu_src_in(alu_src_ID), .branch_in(branch_ID), .alu_op_in(alu_op_ID),
|
||||
.jump_in(jump_ID),
|
||||
@@ -184,7 +205,7 @@ module top (
|
||||
wire we_reg_ME, we_mem_ME, mem_to_reg_ME;
|
||||
|
||||
ex_me u_ex_me (
|
||||
.clk(clk), .rst(rst),
|
||||
.clk(clk), .rst(sys_rst),
|
||||
.we_reg_in(we_reg_EX), .we_mem_in(we_mem_EX), .mem_to_reg_in(mem_to_reg_EX),
|
||||
.we_reg_out(we_reg_ME), .we_mem_out(we_mem_ME), .mem_to_reg_out(mem_to_reg_ME),
|
||||
.alu_in(alu_res_EX), .regB_in(alu_B_temp), .pc4_in(pc4_EX), .rd_in(rd_EX),
|
||||
@@ -200,7 +221,14 @@ module top (
|
||||
wire dmem_we = we_mem_ME & ~is_uart; // si va pa la UART no escribimos en memoria
|
||||
|
||||
assign uart_tx_en = we_mem_ME & is_uart;
|
||||
assign uart_tx_data = regB_ME;
|
||||
assign uart_tx_data = regB_ME[7:0];
|
||||
|
||||
uart_tx u_tx (
|
||||
.clk(clk),
|
||||
.data_in(uart_tx_data),
|
||||
.tx_en(uart_tx_en),
|
||||
.tx(tx)
|
||||
);
|
||||
// --------------------------------------------------------------
|
||||
|
||||
wire [31:0] mem_data_ME;
|
||||
@@ -214,7 +242,7 @@ module top (
|
||||
wire we_reg_WB, mem_to_reg_WB;
|
||||
|
||||
me_wb u_me_wb (
|
||||
.clk(clk), .rst(rst),
|
||||
.clk(clk), .rst(sys_rst),
|
||||
.we_reg_in(we_reg_ME), .mem_to_reg_in(mem_to_reg_ME),
|
||||
.we_reg_out(we_reg_WB), .mem_to_reg_out(mem_to_reg_WB),
|
||||
.alu_in(alu_res_ME), .mem_data_in(mem_data_ME), .pc4_in(pc4_ME), .rd_in(rd_ME),
|
||||
|
||||
255
riscv-ac.srcs/sources_1/new/uart_bootloader.v
Normal file
255
riscv-ac.srcs/sources_1/new/uart_bootloader.v
Normal file
@@ -0,0 +1,255 @@
|
||||
`timescale 1ns / 1ps
|
||||
//////////////////////////////////////////////////////////////////////////////////
|
||||
// Company: nope
|
||||
// Engineer: Jose
|
||||
//
|
||||
// Create Date: 03/03/2026 02:40:56 AM
|
||||
// Design Name: Bootloader
|
||||
// Module Name: uart_bootloader
|
||||
// Project Name: riscv-ac
|
||||
// Target Devices: Artix 7
|
||||
// Tool Versions: 2025.2
|
||||
// Description: Allows dynamic program burning
|
||||
//
|
||||
// Dependencies:
|
||||
//
|
||||
// Revision: 1.0
|
||||
// Revision 0.01 - File Created
|
||||
// Additional Comments:
|
||||
//
|
||||
//////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
module uart_bootloader (
|
||||
input wire clk, // Reloj de la placa (12 MHz)
|
||||
input wire rx, // Cable de entrada de datos desde el USB
|
||||
output reg [31:0] prog_data, // Instrucción completa de 32 bits
|
||||
output reg [31:0] prog_addr, // Dirección donde vamos a guardarla
|
||||
output reg prog_we, // Señal para escribir en la imem
|
||||
output wire cpu_rst // Mantiene al RISC-V en reset mientras programamos
|
||||
);
|
||||
|
||||
// Parámetros para 12 MHz y 115200 baudios
|
||||
// 12.000.000 / 115200 = 104 ciclos por bit
|
||||
localparam CLKS_PER_BIT = 104;
|
||||
// 1 segundo de timeout a 12 MHz para soltar el reset
|
||||
localparam TIMEOUT_LIMIT = 12_000_000;
|
||||
|
||||
// Estados de la máquina UART RX
|
||||
localparam S_IDLE = 2'b00;
|
||||
localparam S_START = 2'b01;
|
||||
localparam S_DATA = 2'b10;
|
||||
localparam S_STOP = 2'b11;
|
||||
|
||||
reg [1:0] state = S_IDLE;
|
||||
reg [7:0] clk_count = 0;
|
||||
reg [2:0] bit_index = 0;
|
||||
reg [7:0] rx_byte = 0;
|
||||
reg rx_done = 0;
|
||||
|
||||
// --- 1. MÁQUINA DE ESTADOS UART RX ---
|
||||
always @(posedge clk) begin
|
||||
rx_done <= 0;
|
||||
|
||||
case (state)
|
||||
S_IDLE: begin
|
||||
clk_count <= 0;
|
||||
bit_index <= 0;
|
||||
if (rx == 1'b0) // Detectamos el Start Bit (baja a 0)
|
||||
state <= S_START;
|
||||
end
|
||||
|
||||
S_START: begin
|
||||
if (clk_count == (CLKS_PER_BIT / 2)) begin
|
||||
if (rx == 1'b0) begin // Confirmamos que es un Start bit válido
|
||||
clk_count <= 0;
|
||||
state <= S_DATA;
|
||||
end else
|
||||
state <= S_IDLE;
|
||||
end else
|
||||
clk_count <= clk_count + 1;
|
||||
end
|
||||
|
||||
S_DATA: begin
|
||||
if (clk_count == CLKS_PER_BIT - 1) begin
|
||||
clk_count <= 0;
|
||||
rx_byte[bit_index] <= rx; // Guardamos el bit
|
||||
if (bit_index == 7) begin
|
||||
bit_index <= 0;
|
||||
state <= S_STOP;
|
||||
end else
|
||||
bit_index <= bit_index + 1;
|
||||
end else
|
||||
clk_count <= clk_count + 1;
|
||||
end
|
||||
|
||||
S_STOP: begin
|
||||
if (clk_count == CLKS_PER_BIT - 1) begin
|
||||
rx_done <= 1; // ¡Byte recibido de lujo!
|
||||
state <= S_IDLE;
|
||||
end else
|
||||
clk_count <= clk_count + 1;
|
||||
end
|
||||
endcase
|
||||
end
|
||||
|
||||
// --- 2. ENSAMBLADOR DE 32 BITS Y CONTROL DE TIMEOUT ---
|
||||
reg [1:0] byte_count = 0;
|
||||
reg [23:0] timeout_counter = 0;
|
||||
reg is_programming = 1; // Empezamos en modo programación por defecto
|
||||
|
||||
// El procesador está en reset (apagado) mientras is_programming sea 1
|
||||
assign cpu_rst = is_programming;
|
||||
|
||||
always @(posedge clk) begin
|
||||
prog_we <= 0; // Por defecto no escribimos
|
||||
|
||||
if (rx_done) begin
|
||||
// Ha llegado un byte nuevo, reseteamos el timeout
|
||||
timeout_counter <= 0;
|
||||
is_programming <= 1;
|
||||
|
||||
// RISC-V usa Little Endian (el byte menos significativo llega primero)
|
||||
prog_data <= {rx_byte, prog_data[31:8]};
|
||||
|
||||
if (byte_count == 3) begin
|
||||
byte_count <= 0;
|
||||
prog_we <= 1; // ¡Tenemos los 32 bits! Damos la orden de escribir
|
||||
// Avanzamos la dirección para la siguiente instrucción (después de escribir)
|
||||
end else begin
|
||||
byte_count <= byte_count + 1;
|
||||
end
|
||||
end else begin
|
||||
// Si acabamos de escribir, subimos la dirección
|
||||
if (prog_we) begin
|
||||
prog_addr <= prog_addr + 4;
|
||||
end
|
||||
|
||||
// Control de timeout (perro guardián)
|
||||
if (is_programming) begin
|
||||
if (timeout_counter == TIMEOUT_LIMIT) begin
|
||||
is_programming <= 0; // ¡Se acabó el tiempo! Soltamos al procesador
|
||||
prog_addr <= 0; // Reseteamos el puntero para la próxima vez
|
||||
byte_count <= 0;
|
||||
end else begin
|
||||
timeout_counter <= timeout_counter + 1;
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
endmodule`timescale 1ns / 1ps
|
||||
`default_nettype none
|
||||
|
||||
module uart_bootloader (
|
||||
input wire clk, // reloj de la placa (12 MHz)
|
||||
input wire rx, // cable de entrada de datos desde el USB
|
||||
output reg [31:0] prog_data = 0, // instrucción completa de 32 bits
|
||||
output reg [31:0] prog_addr = 0, // dirección donde vamos a guardarla
|
||||
output reg prog_we, // señal para escribir en la imem
|
||||
output wire cpu_rst // mantiene el CPU en reset mientras programamos
|
||||
);
|
||||
|
||||
// parámetros para 12 MHz y 115200 de baudrate
|
||||
// 12e6 / 115200 = 104 ciclos por bit
|
||||
// 1 segundo de timeout a 12 MHz para soltar el reset
|
||||
localparam CLKS_PER_BIT = 104; // 868;
|
||||
localparam TIMEOUT_LIMIT = 12_000_000; // 50000;
|
||||
|
||||
localparam S_IDLE = 2'b00;
|
||||
localparam S_START = 2'b01;
|
||||
localparam S_DATA = 2'b10;
|
||||
localparam S_STOP = 2'b11;
|
||||
|
||||
reg [1:0] state = S_IDLE;
|
||||
reg [15:0] clk_count = 0;
|
||||
reg [2:0] bit_index = 0;
|
||||
reg [7:0] rx_byte = 0;
|
||||
reg rx_done = 0;
|
||||
reg [1:0] byte_count = 0;
|
||||
reg [23:0] timeout_counter = 0;
|
||||
reg is_programming = 1;
|
||||
|
||||
// FSM de la UART
|
||||
always @(posedge clk) begin
|
||||
rx_done <= 0;
|
||||
|
||||
case (state)
|
||||
S_IDLE: begin
|
||||
clk_count <= 0;
|
||||
bit_index <= 0;
|
||||
if (rx == 1'b0)
|
||||
state <= S_START;
|
||||
end
|
||||
|
||||
S_START: begin
|
||||
if (clk_count == (CLKS_PER_BIT / 2)) begin
|
||||
if (rx == 1'b0) begin
|
||||
clk_count <= 0;
|
||||
state <= S_DATA;
|
||||
end else
|
||||
state <= S_IDLE;
|
||||
end else
|
||||
clk_count <= clk_count + 1;
|
||||
end
|
||||
|
||||
S_DATA: begin
|
||||
if (clk_count == CLKS_PER_BIT - 1) begin
|
||||
clk_count <= 0;
|
||||
rx_byte[bit_index] <= rx;
|
||||
if (bit_index == 7) begin
|
||||
bit_index <= 0;
|
||||
state <= S_STOP;
|
||||
end else
|
||||
bit_index <= bit_index + 1;
|
||||
end else
|
||||
clk_count <= clk_count + 1;
|
||||
end
|
||||
|
||||
S_STOP: begin
|
||||
if (clk_count == CLKS_PER_BIT - 1) begin
|
||||
rx_done <= 1; // byte recibido
|
||||
state <= S_IDLE;
|
||||
end else
|
||||
clk_count <= clk_count + 1;
|
||||
end
|
||||
endcase
|
||||
end
|
||||
|
||||
assign cpu_rst = is_programming;
|
||||
|
||||
always @(posedge clk) begin
|
||||
prog_we <= 0;
|
||||
|
||||
if (rx_done) begin
|
||||
// byte nuevo
|
||||
timeout_counter <= 0;
|
||||
is_programming <= 1;
|
||||
|
||||
// little-endian
|
||||
prog_data <= {rx_byte, prog_data[31:8]};
|
||||
|
||||
if (byte_count == 3) begin
|
||||
byte_count <= 0;
|
||||
prog_we <= 1; // 32b han llegado, escribimos
|
||||
end else begin
|
||||
byte_count <= byte_count + 1;
|
||||
end
|
||||
end else begin
|
||||
if (prog_we) begin
|
||||
prog_addr <= prog_addr + 4;
|
||||
end
|
||||
|
||||
if (is_programming) begin
|
||||
if (timeout_counter == TIMEOUT_LIMIT) begin
|
||||
is_programming <= 0; // timeout excedido, soltamos CPU
|
||||
prog_addr <= 0; // reset al puntero
|
||||
byte_count <= 0;
|
||||
end else begin
|
||||
timeout_counter <= timeout_counter + 1;
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
endmodule
|
||||
89
riscv-ac.srcs/sources_1/new/uart_tx.v
Normal file
89
riscv-ac.srcs/sources_1/new/uart_tx.v
Normal file
@@ -0,0 +1,89 @@
|
||||
`timescale 1ns / 1ps
|
||||
//////////////////////////////////////////////////////////////////////////////////
|
||||
// Company: nope
|
||||
// Engineer: Jose
|
||||
//
|
||||
// Create Date: 03/03/2026 03:02:49 AM
|
||||
// Design Name: UART TX Module
|
||||
// Module Name: uart_tx
|
||||
// Project Name: riscv-ac
|
||||
// Target Devices: Artix 7
|
||||
// Tool Versions: 2025.2
|
||||
// Description: Allows UART transmission
|
||||
//
|
||||
// Dependencies:
|
||||
//
|
||||
// Revision: 1.0
|
||||
// Revision 0.01 - File Created
|
||||
// Additional Comments:
|
||||
//
|
||||
//////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
module uart_tx (
|
||||
input wire clk,
|
||||
input wire [7:0] data_in,
|
||||
input wire tx_en,
|
||||
output reg tx = 1
|
||||
);
|
||||
|
||||
// 12e6 / 115200 = 104 ciclos
|
||||
localparam CLKS_PER_BIT = 104; // 104;
|
||||
|
||||
localparam S_IDLE = 2'b00;
|
||||
localparam S_START = 2'b01;
|
||||
localparam S_DATA = 2'b10;
|
||||
localparam S_STOP = 2'b11;
|
||||
|
||||
reg [1:0] state = S_IDLE;
|
||||
reg [15:0] clk_count = 0;
|
||||
reg [2:0] bit_index = 0;
|
||||
reg [7:0] tx_data = 0;
|
||||
|
||||
always @(posedge clk) begin
|
||||
case (state)
|
||||
S_IDLE: begin
|
||||
tx <= 1;
|
||||
clk_count <= 0;
|
||||
bit_index <= 0;
|
||||
if (tx_en) begin
|
||||
tx_data <= data_in;
|
||||
state <= S_START;
|
||||
end
|
||||
end
|
||||
|
||||
S_START: begin
|
||||
tx <= 0;
|
||||
if (clk_count < CLKS_PER_BIT - 1) begin
|
||||
clk_count <= clk_count + 1;
|
||||
end else begin
|
||||
clk_count <= 0;
|
||||
state <= S_DATA;
|
||||
end
|
||||
end
|
||||
|
||||
S_DATA: begin
|
||||
tx <= tx_data[bit_index];
|
||||
if (clk_count < CLKS_PER_BIT - 1) begin
|
||||
clk_count <= clk_count + 1;
|
||||
end else begin
|
||||
clk_count <= 0;
|
||||
if (bit_index == 7) begin
|
||||
state <= S_STOP;
|
||||
end else begin
|
||||
bit_index <= bit_index + 1;
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
S_STOP: begin
|
||||
tx <= 1;
|
||||
if (clk_count < CLKS_PER_BIT - 1) begin
|
||||
clk_count <= clk_count + 1;
|
||||
end else begin
|
||||
state <= S_IDLE;
|
||||
end
|
||||
end
|
||||
endcase
|
||||
end
|
||||
endmodule
|
||||
Reference in New Issue
Block a user