-
Notifications
You must be signed in to change notification settings - Fork 0
/
flash_loader.v
160 lines (143 loc) · 5.67 KB
/
flash_loader.v
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
`default_nettype none
module flash_loader(
input wire i_clk,
input wire [23:0] i_read_addr,
input wire i_read_stb,
// SPI connection to flash
output wire o_flash_mosi,
input wire i_flash_miso,
output wire o_flash_sck,
output wire o_flash_cs,
// Write interface to memory
output wire [11:0] o_ram_addr,
output wire [15:0] o_ram_data,
output wire o_ram_write_en
);
// Instruction for initiating a read from the flash chip
`define FLASH_OP_RESET 16'H6699
`define FLASH_OP_FAST_READ 8'H0B
`define FLASH_OP_WAKEUP 8'HAB
localparam
s_idle = 0,
s_initiate_reset = 1,
s_initiate_wakeup = 2,
s_initiate_read = 3,
s_flush_command_buffer = 4,
s_shift_data = 5;
reg flash_sck = 0;
reg flash_mosi = 0;
reg flash_cs = 1;
assign o_flash_sck = flash_sck;
assign o_flash_mosi = flash_mosi;
assign o_flash_cs = flash_cs;
reg [3:0] state = s_idle;
reg [3:0] next_state;
reg [(8*5)-1:0] command_buffer;
reg [5:0] cmd_buffer_bits_to_shift;
reg [23:0] flash_read_addr;
reg [15:0] input_shift_data = 0;
reg [4:0] input_bits_to_shift = 0;
reg [12:0] words_to_read = 0;
reg [11:0] ram_address;
reg [15:0] ram_data;
reg ram_write_enable = 0;
assign o_ram_addr = ram_address;
assign o_ram_data = ram_data;
assign o_ram_write_en = ram_write_enable;
always @(posedge i_clk) begin
case (state)
s_idle: begin
if (i_read_stb) begin
// To initiate a read, we need to clock out
// - The opcode
// - A 24 bit start address
// - One dummy clock
// And then the flash will read until we deassert CS.
flash_read_addr <= i_read_addr;
state <= s_initiate_reset;
end
end
s_initiate_reset: begin
command_buffer <= {`FLASH_OP_RESET, 24'b0};
cmd_buffer_bits_to_shift <= 16;
flash_cs <= 0;
next_state <= s_initiate_wakeup;
state <= s_flush_command_buffer;
end
s_initiate_wakeup: begin
command_buffer <= {`FLASH_OP_WAKEUP, 32'b0};
cmd_buffer_bits_to_shift <= 8;
flash_cs <= 0;
next_state <= s_initiate_read;
state <= s_flush_command_buffer;
end
s_initiate_read: begin
// Set the command to send
command_buffer <= {`FLASH_OP_FAST_READ, flash_read_addr, 8'b0};
cmd_buffer_bits_to_shift <= (5 * 8);
flash_cs <= 0;
// Also initialize the read data registers
input_bits_to_shift <= 5'd16;
words_to_read <= 4096;
ram_address <= 0;
// Process command buffer
next_state <= s_shift_data;
state <= s_flush_command_buffer;
end
s_flush_command_buffer: begin
if (cmd_buffer_bits_to_shift > 0) begin
if (flash_sck == 0) begin
// Latch new data and perform rising edge
{flash_mosi, command_buffer} <= {command_buffer, 1'b0};
flash_sck <= 1;
end else begin
// Perform falling edge and decrement bit count
flash_sck <= 0;
cmd_buffer_bits_to_shift <= cmd_buffer_bits_to_shift - 1;
end
end else begin
// Done - move to continuation state
state <= next_state;
// If we aren't moving to the read state, deassert CS
if (next_state != s_shift_data)
flash_cs <= 1;
end
end
s_shift_data: begin
// We are going to care about 16 bit chunks, since that's
// the interface we're using for our block RAMs
if (words_to_read == 0) begin
ram_write_enable <= 0;
flash_cs <= 1;
state <= s_idle;
end else begin
if (input_bits_to_shift == 0) begin
// Done shifting a word, move it to the output data
// lines and strobe the write signal
ram_data <= input_shift_data;
ram_write_enable <= 1;
words_to_read <= words_to_read - 1;
input_bits_to_shift <= 16;
end else begin
// If we just did a write, bring the strobe back down
// and increment the write address for next time
if (ram_write_enable) begin
ram_write_enable <= 0;
ram_address <= ram_address + 1;
end
if (o_flash_sck == 0) begin
// Set up rising edge of SPI clock
flash_mosi <= 1'b0;
flash_sck <= 1;
end else begin
// Falling edge
flash_sck <= 0;
input_shift_data <= {input_shift_data[14:0], i_flash_miso};
input_bits_to_shift <= input_bits_to_shift - 1;
end
end
end
end
endcase
end
endmodule