1 |
2 |
ayersg |
`timescale 1ns / 1ps
|
2 |
|
|
/*
|
3 |
|
|
* File : uart_bootloader_v2.v
|
4 |
|
|
* Project : University of Utah, XUM Project MIPS32 core
|
5 |
|
|
* Creator(s) : Grant Ayers (ayers@cs.utah.edu)
|
6 |
|
|
*
|
7 |
|
|
* Modification History:
|
8 |
|
|
* Rev Date Initials Description of Change
|
9 |
|
|
* 1.0 24-May-2010 GEA Initial design of standalone bootloader
|
10 |
|
|
* 2.0 7-Jul-2012 GEA Added data memory bus to allow for general-purpose use.
|
11 |
|
|
*
|
12 |
|
|
* Standards/Formatting:
|
13 |
|
|
* Verilog 2001, 4 soft tab, wide column.
|
14 |
|
|
*
|
15 |
|
|
* Description:
|
16 |
|
|
* An RS-232 compatible UART coupled with the XUM bootloader.
|
17 |
|
|
*
|
18 |
|
|
* The UART is general-purpose and capable of sending and receiving at a
|
19 |
|
|
* pre-determined BAUD rate (determined by the clocking module)
|
20 |
|
|
* with 8 data bits, 1 stop bit, and no parity. In other words it
|
21 |
|
|
* is 8N1 with only RxD and TxD signals. It uses two 256-byte FIFO
|
22 |
|
|
* buffers, one for receiving and the other for transmitting.
|
23 |
|
|
*
|
24 |
|
|
* The XUM bootloader protocol is as follows:
|
25 |
|
|
*
|
26 |
|
|
* 1. Programmer sends 'XUM' ASCII bytes.
|
27 |
|
|
* 2. Programmer sends a number indicating how many 32-bit data words
|
28 |
|
|
* it has to send, minus 1. (For example, if it has one 32-bit data word,
|
29 |
|
|
* this number would be 0.) The size of this number is 18 bits.
|
30 |
|
|
* This means the minimum transmission size is 1 word (32 bits), and
|
31 |
|
|
* the maximum transmission size is 262144 words, or exactly 1 MB.
|
32 |
|
|
* This 18-bit number is sent MSB first, in three bytes, with the six
|
33 |
|
|
* most-significant bits set to 0.
|
34 |
|
|
* 3. The FPGA sends back the third size byte from the programmer, allowing
|
35 |
|
|
* the programmer to determine if the FPGA is listening and conforming
|
36 |
|
|
* to the XUM boot protocol.
|
37 |
|
|
* 4. The programmer sends another 18-bit number indicating the starting
|
38 |
|
|
* offset in memory where the data should be placed. Normally this will
|
39 |
|
|
* be 0. This number is also sent in three bytes, and the six most-significant
|
40 |
|
|
* bits of the first byte are ignored.
|
41 |
|
|
* 5. The programmer sends the data. A copy of each byte that it sends will be
|
42 |
|
|
* sent back to the programmer from the FPGA, allowing the programmer
|
43 |
|
|
* to determine if all of the data was transmitted successfully.
|
44 |
|
|
*
|
45 |
|
|
* On reset, the bootloader is enabled by default. When the bootloader is enabled,
|
46 |
|
|
* the data memory bus will not see any incoming data. To configure the UART for
|
47 |
|
|
* general-purpose use, software must issue a write command to the UART
|
48 |
|
|
* over the data memory bus with bit 8 set. This disables the boot protocol until
|
49 |
|
|
* the UART is reset again and allows normal use. Note however that there is
|
50 |
|
|
* a 5-second guard time after reset during which the boot loader is
|
51 |
|
|
* enabled regardless of any software commands to disable it. After the 5 second
|
52 |
|
|
* time has lapsed after reset, the software state determines the operating mode
|
53 |
|
|
* of the UART.
|
54 |
|
|
*/
|
55 |
|
|
module uart_bootloader(
|
56 |
|
|
input clock,
|
57 |
|
|
input reset,
|
58 |
|
|
input Read, // MMIO
|
59 |
|
|
input Write, // MMIO
|
60 |
|
|
input [8:0] DataIn, // MMIO
|
61 |
|
|
output reg [16:0] DataOut, // MMIO
|
62 |
|
|
output Ack, // MMIO
|
63 |
|
|
output DataReady, // Can be used as an interrupt
|
64 |
|
|
output BootResetCPU, // XUM Boot Protocol: Reset CPU
|
65 |
|
|
output BootWriteMem, // XUM Boot Protocol: Write to CPU memory
|
66 |
|
|
output reg [17:0] BootAddr, // XUM Boot Protocol
|
67 |
|
|
output reg [31:0] BootData, // XUM Boot Protocol
|
68 |
|
|
input RxD, // UART Rx Signal
|
69 |
|
|
output TxD // UART Tx Signal
|
70 |
|
|
);
|
71 |
|
|
|
72 |
|
|
localparam [4:0] IDLE=0, WRITE=1, READ=2, BUSW=3, XHEAD1=4, XHEAD2=5, XHEAD3=6, XSIZE1=7, XSIZE2=8, XSIZE3=9,
|
73 |
|
|
XOFST1=10, XOFST2=11, XOFST3=12, XDATA1=13, XDATA2=14, XDATA3=15, XDATA4=16, XADDRI=17;
|
74 |
|
|
|
75 |
|
|
// UART module signals
|
76 |
|
|
wire uart_write;
|
77 |
|
|
reg uart_read;
|
78 |
|
|
wire uart_data_ready;
|
79 |
|
|
wire [7:0] uart_data_in;
|
80 |
|
|
wire [7:0] uart_data_out;
|
81 |
|
|
wire [8:0] uart_rx_count;
|
82 |
|
|
|
83 |
|
|
reg [8:0] DataIn_r; // Latch for incoming data to improve timing
|
84 |
|
|
wire DisableBoot = DataIn_r[8]; // Software boot disable command is bit 8
|
85 |
|
|
reg [28:0] BootTimedEnable; // Hardware override enabler for boot loader after reset
|
86 |
|
|
reg BootSwEnabled; // Software enabled/disabled state of bootloader
|
87 |
|
|
wire BootProtoEnabled; // Master bootloader enabled signal
|
88 |
|
|
reg [17:0] rx_count; // Number of 32-bit words received (boot loader)
|
89 |
|
|
reg [17:0] rx_size; // Number of 32-bit words to expect (boot loader)
|
90 |
|
|
reg [4:0] state;
|
91 |
|
|
|
92 |
|
|
always @(posedge clock) begin
|
93 |
|
|
if (reset) begin
|
94 |
|
|
state <= IDLE;
|
95 |
|
|
end
|
96 |
|
|
else begin
|
97 |
|
|
case (state)
|
98 |
|
|
IDLE: begin
|
99 |
|
|
if (Write) state <= WRITE;
|
100 |
|
|
else if (Read) state <= READ;
|
101 |
|
|
else if (BootProtoEnabled & uart_data_ready) state <= XHEAD1;
|
102 |
|
|
else state <= IDLE;
|
103 |
|
|
end
|
104 |
|
|
WRITE: state <= BUSW;
|
105 |
|
|
READ: state <= BUSW;
|
106 |
|
|
BUSW: state <= ~(Read | Write) ? IDLE : BUSW;
|
107 |
|
|
XHEAD1: state <= (uart_data_out == 8'h58) ? XHEAD2 : IDLE; // 'X'
|
108 |
|
|
XHEAD2: state <= (uart_data_ready) ? ((uart_data_out == 8'h55) ? XHEAD3 : IDLE) : XHEAD2; // 'U'
|
109 |
|
|
XHEAD3: state <= (uart_data_ready) ? ((uart_data_out == 8'h4D) ? XSIZE1 : IDLE) : XHEAD3; // 'M'
|
110 |
|
|
XSIZE1: state <= (uart_data_ready) ? ((uart_data_out[7:2] == 6'b000000) ? XSIZE2 : IDLE) : XSIZE1;
|
111 |
|
|
XSIZE2: state <= (uart_data_ready) ? XSIZE3 : XSIZE2;
|
112 |
|
|
XSIZE3: state <= (uart_data_ready) ? XOFST1 : XSIZE3;
|
113 |
|
|
XOFST1: state <= (uart_data_ready) ? XOFST2 : XOFST1;
|
114 |
|
|
XOFST2: state <= (uart_data_ready) ? XOFST3 : XOFST2;
|
115 |
|
|
XOFST3: state <= (uart_data_ready) ? XDATA1 : XOFST3;
|
116 |
|
|
XDATA1: state <= (uart_data_ready) ? XDATA2 : XDATA1;
|
117 |
|
|
XDATA2: state <= (uart_data_ready) ? XDATA3 : XDATA2;
|
118 |
|
|
XDATA3: state <= (uart_data_ready) ? XDATA4 : XDATA3;
|
119 |
|
|
XDATA4: state <= (uart_data_ready) ? XADDRI : XDATA4;
|
120 |
|
|
XADDRI: state <= (rx_count == rx_size) ? IDLE : XDATA1;
|
121 |
|
|
default: state <= IDLE;
|
122 |
|
|
endcase
|
123 |
|
|
end
|
124 |
|
|
end
|
125 |
|
|
|
126 |
|
|
always @(*) begin
|
127 |
|
|
case (state)
|
128 |
|
|
IDLE: uart_read <= 0;
|
129 |
|
|
WRITE: uart_read <= 0;
|
130 |
|
|
READ: uart_read <= 1;
|
131 |
|
|
BUSW: uart_read <= 0;
|
132 |
|
|
XHEAD1: uart_read <= uart_data_ready;
|
133 |
|
|
XHEAD2: uart_read <= uart_data_ready;
|
134 |
|
|
XHEAD3: uart_read <= uart_data_ready;
|
135 |
|
|
XSIZE1: uart_read <= uart_data_ready;
|
136 |
|
|
XSIZE2: uart_read <= uart_data_ready;
|
137 |
|
|
XSIZE3: uart_read <= uart_data_ready;
|
138 |
|
|
XOFST1: uart_read <= uart_data_ready;
|
139 |
|
|
XOFST2: uart_read <= uart_data_ready;
|
140 |
|
|
XOFST3: uart_read <= uart_data_ready;
|
141 |
|
|
XDATA1: uart_read <= uart_data_ready;
|
142 |
|
|
XDATA2: uart_read <= uart_data_ready;
|
143 |
|
|
XDATA3: uart_read <= uart_data_ready;
|
144 |
|
|
XDATA4: uart_read <= uart_data_ready;
|
145 |
|
|
XADDRI: uart_read <= 0;
|
146 |
|
|
default: uart_read <= 0;
|
147 |
|
|
endcase
|
148 |
|
|
end
|
149 |
|
|
|
150 |
|
|
always @(posedge clock) begin
|
151 |
|
|
DataIn_r <= ((state == IDLE) & Write) ? DataIn : DataIn_r;
|
152 |
|
|
end
|
153 |
|
|
|
154 |
|
|
always @(posedge clock) begin
|
155 |
|
|
DataOut <= (reset) ? 17'h00000 : ((state == READ) ? {uart_rx_count[8:0], uart_data_out[7:0]} : DataOut);
|
156 |
|
|
end
|
157 |
|
|
|
158 |
|
|
always @(posedge clock) begin
|
159 |
|
|
BootTimedEnable <= (reset) ? 29'h00000000 : (BootTimedEnable != 29'h1dcd6500) ? BootTimedEnable + 1 : BootTimedEnable; // 5 sec @ 100 MHz
|
160 |
|
|
BootSwEnabled <= (reset) ? 1 : ((state == WRITE) ? ~DisableBoot : BootSwEnabled);
|
161 |
|
|
end
|
162 |
|
|
|
163 |
|
|
assign BootResetCPU = (state != IDLE) && (state != WRITE) && (state != READ) && (state != BUSW) &&
|
164 |
|
|
(state != XHEAD1) && (state != XHEAD2) && (state != XHEAD3) && (state != XSIZE1);
|
165 |
|
|
assign BootWriteMem = (state == XADDRI);
|
166 |
|
|
assign uart_write = ((state == WRITE) & ~DisableBoot) |
|
167 |
|
|
(uart_data_ready & ((state == XSIZE3) | (state == XDATA1) | (state == XDATA2) | (state == XDATA3) | (state == XDATA4)));
|
168 |
|
|
assign uart_data_in = (state == WRITE) ? DataIn_r[7:0] : uart_data_out;
|
169 |
|
|
assign Ack = (state == BUSW);
|
170 |
|
|
assign DataReady = uart_data_ready;
|
171 |
|
|
assign BootProtoEnabled = BootSwEnabled | (BootTimedEnable != 29'h1dcd6500);
|
172 |
|
|
|
173 |
|
|
|
174 |
|
|
// XUM Boot Protocol Logic
|
175 |
|
|
always @(posedge clock) begin
|
176 |
|
|
BootData[31:24] <= (reset) ? 8'h00 : (((state == XDATA1) & uart_data_ready) ? uart_data_out : BootData[31:24]);
|
177 |
|
|
BootData[23:16] <= (reset) ? 8'h00 : (((state == XDATA2) & uart_data_ready) ? uart_data_out : BootData[23:16]);
|
178 |
|
|
BootData[15:8] <= (reset) ? 8'h00 : (((state == XDATA3) & uart_data_ready) ? uart_data_out : BootData[15:8]);
|
179 |
|
|
BootData[7:0] <= (reset) ? 8'h00 : (((state == XDATA4) & uart_data_ready) ? uart_data_out : BootData[7:0]);
|
180 |
|
|
end
|
181 |
|
|
|
182 |
|
|
always @(posedge clock) begin
|
183 |
|
|
if (reset) begin
|
184 |
|
|
BootAddr <= 18'h00000;
|
185 |
|
|
end
|
186 |
|
|
else if (state == XADDRI) begin
|
187 |
|
|
BootAddr <= BootAddr + 1;
|
188 |
|
|
end
|
189 |
|
|
else begin
|
190 |
|
|
BootAddr[17:16] <= ((state == XOFST1) & uart_data_ready) ? uart_data_out[1:0] : BootAddr[17:16];
|
191 |
|
|
BootAddr[15:8] <= ((state == XOFST2) & uart_data_ready) ? uart_data_out[7:0] : BootAddr[15:8];
|
192 |
|
|
BootAddr[7:0] <= ((state == XOFST3) & uart_data_ready) ? uart_data_out[7:0] : BootAddr[7:0];
|
193 |
|
|
end
|
194 |
|
|
end
|
195 |
|
|
|
196 |
|
|
always @(posedge clock) begin
|
197 |
|
|
rx_count <= (state == IDLE) ? 18'h00000 : ((state == XADDRI) ? rx_count + 1 : rx_count);
|
198 |
|
|
end
|
199 |
|
|
|
200 |
|
|
always @(posedge clock) begin
|
201 |
|
|
rx_size[17:16] <= (reset) ? 2'b00 : (((state == XSIZE1) & uart_data_ready) ? uart_data_out[1:0] : rx_size[17:16]);
|
202 |
|
|
rx_size[15:8] <= (reset) ? 8'h00 : (((state == XSIZE2) & uart_data_ready) ? uart_data_out[7:0] : rx_size[15:8]);
|
203 |
|
|
rx_size[7:0] <= (reset) ? 8'h00 : (((state == XSIZE3) & uart_data_ready) ? uart_data_out[7:0] : rx_size[7:0]);
|
204 |
|
|
end
|
205 |
|
|
|
206 |
|
|
// UART Driver
|
207 |
|
|
uart_min UART (
|
208 |
|
|
.clock (clock),
|
209 |
|
|
.reset (reset),
|
210 |
|
|
.write (uart_write),
|
211 |
|
|
.data_in (uart_data_in),
|
212 |
|
|
.read (uart_read),
|
213 |
|
|
.data_out (uart_data_out),
|
214 |
|
|
.data_ready (uart_data_ready),
|
215 |
|
|
.rx_count (uart_rx_count),
|
216 |
|
|
.RxD (RxD),
|
217 |
|
|
.TxD (TxD)
|
218 |
|
|
);
|
219 |
|
|
|
220 |
|
|
endmodule
|
221 |
3 |
ayersg |
|