11`timescale 1ns / 1ps
22
3- // Receives a RISC-V program over UART and writes it into CPU memory
4- // via io_debug_write. Holds CPU in reset until a 4x 0xFF end sequence
5- // is received.
6- //
7- // Protocol:
8- // - Send program bytes little-endian, 4 bytes per word
9- // - Send 0xFF 0xFF 0xFF 0xFF to signal end of program
10- // - CPU is released from reset automatically after end sequence
11-
123module uart_program_loader (
134 input wire clk,
14- input wire rst_n, // external reset (active low)
15- input wire rx, // UART RX pin
5+ input wire rst_n,
6+ input wire rx,
167
17- // CPU control
18- output reg cpu_reset, // hold high to keep CPU in reset
8+ output reg cpu_reset,
199 output reg debug_write,
2010 output reg [31 :0 ] debug_write_address,
2111 output reg [31 :0 ] debug_write_data
@@ -38,17 +28,13 @@ module uart_program_loader (
3828 // -------------------------------------------------------
3929 // Loader FSM
4030 // -------------------------------------------------------
41- // Accumulate 4 bytes into a 32-bit word (little-endian)
42- // Detect end sequence: 4 consecutive 0xFF bytes
43-
44- reg [31 :0 ] word_buf; // accumulates current word
45- reg [1 :0 ] byte_idx; // which byte in current word (0-3)
46- reg [31 :0 ] word_address; // current word address in memory
47- reg [1 :0 ] ff_count; // consecutive 0xFF bytes seen
48- reg loading; // are we in loading mode?
49- reg rx_valid_prev; // edge detect
31+ reg [31 :0 ] word_buf;
32+ reg [1 :0 ] byte_idx;
33+ reg [31 :0 ] word_address;
34+ reg [1 :0 ] ff_count;
35+ reg loading;
36+ reg rx_valid_prev;
5037
51- // One-cycle pulse on new byte
5238 wire rx_edge = rx_valid && ! rx_valid_prev;
5339
5440 always @(posedge clk) begin
@@ -65,27 +51,26 @@ module uart_program_loader (
6551 rx_valid_prev <= 1'b0 ;
6652 end else begin
6753 rx_valid_prev <= rx_valid;
68- debug_write <= 1'b0 ; // default: no write
54+ debug_write <= 1'b0 ;
6955
7056 if (loading && rx_edge) begin
7157 if (rx_data == 8'hFF ) begin
72- // Count consecutive 0xFF bytes
7358 ff_count <= ff_count + 2'h1 ;
74-
75- // Still assemble into word in case it's data not end seq
7659 word_buf <= {rx_data, word_buf[31 :8 ]};
77- byte_idx <= byte_idx + 2'h1 ;
7860
7961 if (ff_count == 2'h3 ) begin
80- // 4th 0xFF - end sequence complete , release CPU
62+ // 4th consecutive 0xFF - end sequence, release CPU
8163 loading <= 1'b0 ;
8264 cpu_reset <= 1'b0 ;
83- ff_count <= 2'h0 ;
65+ end else if (byte_idx == 2'h3 ) begin
66+ // Word complete - write it even though it contains 0xFF
67+ debug_write <= 1'b1 ;
68+ debug_write_address <= word_address;
69+ debug_write_data <= {rx_data, word_buf[23 :0 ]};
70+ word_address <= word_address + 32'h1 ;
71+ byte_idx <= 2'h0 ;
8472 end else begin
85- // Might still be end sequence, don't write yet
86- if (byte_idx == 2'h3 ) begin
87- byte_idx <= 2'h0 ;
88- end
73+ byte_idx <= byte_idx + 2'h1 ;
8974 end
9075 end else begin
9176 // Non-0xFF byte resets end sequence counter
@@ -100,7 +85,6 @@ module uart_program_loader (
10085 endcase
10186
10287 if (byte_idx == 2'h3 ) begin
103- // Full word assembled - write to memory
10488 debug_write <= 1'b1 ;
10589 debug_write_address <= word_address;
10690 debug_write_data <= {rx_data, word_buf[23 :0 ]};
0 commit comments