Skip to content

Commit 0388218

Browse files
committed
dynamic program loading
1 parent 045c747 commit 0388218

5 files changed

Lines changed: 309 additions & 42 deletions

File tree

RISC-V-Scaffold-Basys3/RISC-V-Scaffold-Basys3.srcs/constrs_1/new/master.xdc

Lines changed: 12 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -45,24 +45,20 @@
4545

4646

4747

48-
49-
50-
51-
52-
53-
54-
55-
5648

5749

5850
## Clock
5951
set_property -dict { PACKAGE_PIN W5 IOSTANDARD LVCMOS33 } [get_ports clk]
6052
create_clock -add -name sys_clk_pin -period 10.00 -waveform {0 5} [get_ports clk]
6153

62-
## Reset button (btnC)
54+
## Reset (btnC)
6355
set_property -dict { PACKAGE_PIN U18 IOSTANDARD LVCMOS33 } [get_ports btnC]
6456

65-
## LEDs - debug_1[15:0]
57+
## UART
58+
set_property -dict { PACKAGE_PIN B18 IOSTANDARD LVCMOS33 } [get_ports RsRx]
59+
set_property -dict { PACKAGE_PIN A18 IOSTANDARD LVCMOS33 } [get_ports RsTx]
60+
61+
## LEDs
6662
set_property -dict { PACKAGE_PIN U16 IOSTANDARD LVCMOS33 } [get_ports {led[0]}]
6763
set_property -dict { PACKAGE_PIN E19 IOSTANDARD LVCMOS33 } [get_ports {led[1]}]
6864
set_property -dict { PACKAGE_PIN U19 IOSTANDARD LVCMOS33 } [get_ports {led[2]}]
@@ -85,4 +81,9 @@ set_property CONFIG_VOLTAGE 3.3 [current_design]
8581
set_property CFGBVS VCCO [current_design]
8682
set_property BITSTREAM.GENERAL.COMPRESS TRUE [current_design]
8783
set_property BITSTREAM.CONFIG.CONFIGRATE 33 [current_design]
88-
set_property CONFIG_MODE SPIx4 [current_design]
84+
set_property CONFIG_MODE SPIx4 [current_design]
85+
86+
87+
88+
89+

RISC-V-Scaffold-Basys3/RISC-V-Scaffold-Basys3.srcs/sources_1/new/top.v

Lines changed: 40 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -2,21 +2,42 @@
22

33
module Top(
44
input wire clk,
5-
input wire btnC,
5+
input wire btnC, // external reset
6+
input wire RsRx, // UART RX
7+
output wire RsTx, // UART TX (unused)
68
output wire [15:0] led
79
);
810

11+
wire rst_n = ~btnC;
12+
13+
// -------------------------------------------------------
14+
// UART program loader
15+
// -------------------------------------------------------
16+
wire cpu_reset;
17+
wire debug_write;
18+
wire [31:0] debug_write_address;
19+
wire [31:0] debug_write_data;
20+
21+
uart_program_loader loader (
22+
.clk (clk),
23+
.rst_n (rst_n),
24+
.rx (RsRx),
25+
.cpu_reset (cpu_reset),
26+
.debug_write (debug_write),
27+
.debug_write_address (debug_write_address),
28+
.debug_write_data (debug_write_data)
29+
);
30+
931
// -------------------------------------------------------
10-
// Generate a 2-cycle wide enable pulse at ~5Hz
11-
// Period = 20_000_000 cycles at 100MHz
12-
// We pulse ce high for 2 consecutive cycles each period
32+
// 2-cycle wide enable pulse at ~5Hz
33+
// Only runs when CPU is not being loaded
1334
// -------------------------------------------------------
1435
reg [23:0] ce_counter;
15-
reg [1:0] ce_phase; // counts 0,1,2 then back to 0
36+
reg [1:0] ce_phase;
1637
reg ce;
1738

1839
always @(posedge clk) begin
19-
if (btnC) begin
40+
if (btnC | cpu_reset) begin
2041
ce_counter <= 24'd0;
2142
ce_phase <= 2'd0;
2243
ce <= 1'b0;
@@ -32,14 +53,12 @@ module Top(
3253
end
3354
end
3455
2'd1: begin
35-
// First execute pulse - memory latches address
36-
ce <= 1'b1;
37-
ce_phase <= 2'd2;
56+
ce <= 1'b1;
57+
ce_phase <= 2'd2;
3858
end
3959
2'd2: begin
40-
// Second execute pulse - memory returns data
41-
ce <= 1'b1;
42-
ce_phase <= 2'd0;
60+
ce <= 1'b1;
61+
ce_phase <= 2'd0;
4362
end
4463
default: ce_phase <= 2'd0;
4564
endcase
@@ -52,15 +71,16 @@ module Top(
5271
wire [31:0] debug_1;
5372

5473
Main cpu (
55-
.clock (clk),
56-
.reset (btnC),
57-
.io_execute (ce),
58-
.io_debug_write (1'b0),
59-
.io_debug_write_address(32'h0),
60-
.io_debug_write_data (32'h0),
61-
.io_debug_1 (debug_1)
74+
.clock (clk),
75+
.reset (cpu_reset | btnC),
76+
.io_execute (ce),
77+
.io_debug_write (debug_write),
78+
.io_debug_write_address (debug_write_address),
79+
.io_debug_write_data (debug_write_data),
80+
.io_debug_1 (debug_1)
6281
);
6382

64-
assign led = debug_1[15:0];
83+
assign led = debug_1[15:0];
84+
assign RsTx = 1'b1;
6585

6686
endmodule
Lines changed: 117 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,117 @@
1+
`timescale 1ns / 1ps
2+
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+
12+
module uart_program_loader (
13+
input wire clk,
14+
input wire rst_n, // external reset (active low)
15+
input wire rx, // UART RX pin
16+
17+
// CPU control
18+
output reg cpu_reset, // hold high to keep CPU in reset
19+
output reg debug_write,
20+
output reg [31:0] debug_write_address,
21+
output reg [31:0] debug_write_data
22+
);
23+
24+
// -------------------------------------------------------
25+
// UART RX
26+
// -------------------------------------------------------
27+
wire [7:0] rx_data;
28+
wire rx_valid;
29+
30+
uart_rx rx_inst (
31+
.clk (clk),
32+
.rst_n (rst_n),
33+
.rx (rx),
34+
.data_out (rx_data),
35+
.data_valid(rx_valid)
36+
);
37+
38+
// -------------------------------------------------------
39+
// Loader FSM
40+
// -------------------------------------------------------
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
50+
51+
// One-cycle pulse on new byte
52+
wire rx_edge = rx_valid && !rx_valid_prev;
53+
54+
always @(posedge clk) begin
55+
if (!rst_n) begin
56+
cpu_reset <= 1'b1;
57+
debug_write <= 1'b0;
58+
debug_write_address <= 32'h0;
59+
debug_write_data <= 32'h0;
60+
word_buf <= 32'h0;
61+
byte_idx <= 2'h0;
62+
word_address <= 32'h0;
63+
ff_count <= 2'h0;
64+
loading <= 1'b1;
65+
rx_valid_prev <= 1'b0;
66+
end else begin
67+
rx_valid_prev <= rx_valid;
68+
debug_write <= 1'b0; // default: no write
69+
70+
if (loading && rx_edge) begin
71+
if (rx_data == 8'hFF) begin
72+
// Count consecutive 0xFF bytes
73+
ff_count <= ff_count + 2'h1;
74+
75+
// Still assemble into word in case it's data not end seq
76+
word_buf <= {rx_data, word_buf[31:8]};
77+
byte_idx <= byte_idx + 2'h1;
78+
79+
if (ff_count == 2'h3) begin
80+
// 4th 0xFF - end sequence complete, release CPU
81+
loading <= 1'b0;
82+
cpu_reset <= 1'b0;
83+
ff_count <= 2'h0;
84+
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
89+
end
90+
end else begin
91+
// Non-0xFF byte resets end sequence counter
92+
ff_count <= 2'h0;
93+
94+
// Assemble word little-endian
95+
case (byte_idx)
96+
2'h0: word_buf <= {word_buf[31:8], rx_data};
97+
2'h1: word_buf <= {word_buf[31:16], rx_data, word_buf[7:0]};
98+
2'h2: word_buf <= {word_buf[31:24], rx_data, word_buf[15:0]};
99+
2'h3: word_buf <= {rx_data, word_buf[23:0]};
100+
endcase
101+
102+
if (byte_idx == 2'h3) begin
103+
// Full word assembled - write to memory
104+
debug_write <= 1'b1;
105+
debug_write_address <= word_address;
106+
debug_write_data <= {rx_data, word_buf[23:0]};
107+
word_address <= word_address + 32'h1;
108+
byte_idx <= 2'h0;
109+
end else begin
110+
byte_idx <= byte_idx + 2'h1;
111+
end
112+
end
113+
end
114+
end
115+
end
116+
117+
endmodule
Lines changed: 109 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,109 @@
1+
`timescale 1ns / 1ps
2+
//////////////////////////////////////////////////////////////////////////////////
3+
// Company:
4+
// Engineer:
5+
//
6+
// Create Date: 02/26/2026 12:18:53 AM
7+
// Design Name:
8+
// Module Name: uart_rx
9+
// Project Name:
10+
// Target Devices:
11+
// Tool Versions:
12+
// Description:
13+
//
14+
// Dependencies:
15+
//
16+
// Revision:
17+
// Revision 0.01 - File Created
18+
// Additional Comments:
19+
//
20+
//////////////////////////////////////////////////////////////////////////////////
21+
22+
23+
module uart_rx(
24+
input wire clk,
25+
input wire rst_n,
26+
input wire rx,
27+
output reg [7:0] data_out,
28+
output reg data_valid
29+
);
30+
31+
localparam IDLE = 2'd0;
32+
localparam START = 2'd1;
33+
localparam DATA = 2'd2;
34+
localparam STOP = 2'd3;
35+
reg rx_sync_0;
36+
reg rx_sync_1;
37+
38+
reg [7:0] data_packet = 0;
39+
reg [2:0] bit_idx = 0;
40+
reg [1:0] state = 0;
41+
reg [9:0] counter = 0;
42+
43+
44+
always @(posedge clk) begin
45+
if(!rst_n) begin
46+
rx_sync_0 <=0;
47+
rx_sync_1 <=0;
48+
data_packet <= 0;
49+
bit_idx <= 0;
50+
state <= 0;
51+
counter <= 0;
52+
data_valid <= 0;
53+
54+
end else begin
55+
rx_sync_0 <= rx;
56+
rx_sync_1 <= rx_sync_0;
57+
case(state)
58+
IDLE: begin
59+
data_valid <= 0;
60+
if(!rx_sync_1) begin
61+
counter <= 1;
62+
state <= START;
63+
end
64+
65+
end
66+
START: begin
67+
counter <= counter +1;
68+
if(counter == 433) begin
69+
if(!rx_sync_1) begin
70+
counter <= 1;
71+
state <= DATA;
72+
end else begin
73+
state <= IDLE;
74+
end
75+
end
76+
end
77+
DATA: begin
78+
counter <= counter +1;
79+
if(counter == 867) begin
80+
counter<=0;
81+
data_packet[bit_idx] <= rx_sync_1;
82+
if(bit_idx == 7) begin
83+
state <= STOP;
84+
bit_idx <= 0;
85+
end else begin
86+
bit_idx <= bit_idx+1;
87+
end
88+
end
89+
end
90+
STOP: begin
91+
92+
if(rx_sync_1) begin
93+
data_valid <= 1;
94+
data_out <= data_packet;
95+
state<=IDLE;
96+
end
97+
98+
99+
100+
end
101+
102+
endcase
103+
104+
105+
106+
end
107+
108+
end
109+
endmodule

0 commit comments

Comments
 (0)