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
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
|
`default_nettype none
`timescale 1ns/1ns
`include "messages.vh"
`ifndef SIMULATION
`error_SIMULATION_not_defined
; /* Cause syntax error */
`endif
module W25Q16BV_flash
#(
parameter BYTES_TO_INITIALIZE = 0,
parameter INITIAL_CONTENTS_FILE = "some_file.mem"
)
(
/* wires we're not using are omitted */
input wire sdo,
output wire sdi,
input wire sck,
input wire ss_n
);
reg outputting;
initial
outputting <= 0;
reg outputted_bit;
assign sdi = (outputting && !ss_n) ? outputted_bit : 1'bz;
reg powered_up;
initial
powered_up <= 0;
reg powering_up_in_progress;
initial
powering_up_in_progress <= 0;
parameter power_up_wait_time = 3000; /* ns */
integer power_up_time;
parameter idle = 0;
parameter error = 1;
parameter receiving_instruction = 2;
parameter releasing_power_down = 3;
parameter receiving_fast_read_address = 4;
parameter receiving_fast_read_dummy_byte = 5;
parameter responding_fast_read = 6;
integer state;
initial
state <= idle;
parameter release_power_down_instruction = 8'hAB;
parameter fast_read_instruction = 8'h0B;
reg [7:0] instruction;
integer instruction_bits_received;
reg [23:0] address;
integer address_bits_received;
reg [2:0] bit_in_byte;
integer dummy_bits_received;
parameter memory_size = 1024 * 1024 * 2; /* 2 megabytes */
reg [7:0] memory [memory_size - 1 : 0];
initial
$readmemh(INITIAL_CONTENTS_FILE, memory, 0, BYTES_TO_INITIALIZE - 1);
always @ (posedge sck) begin
if (!powered_up && power_up_time + power_up_wait_time < $time) begin
powered_up <= 1;
if (state == releasing_power_down)
state = idle;
end
case (state)
idle : begin
if (!ss_n) begin
state <= receiving_instruction;
instruction_bits_received <= 1;
instruction[7] <= sdo;
end
end
error : begin
if (ss_n) begin
state <= idle;
end
end
receiving_instruction : begin
if (ss_n) begin
state <= idle;
`MSG(("SPI: error: operation aborted after only %0d instruction bits received",
instruction_bits_received));
end else begin
instruction[7 - instruction_bits_received] <= sdo;
instruction_bits_received <= instruction_bits_received + 1;
if (instruction_bits_received + 1 == 8) begin
if (!powered_up && ({instruction[7:1], sdo} !=
release_power_down_instruction)) begin
state <= error;
`MSG(("SPI: error: attempted instruction 0x%x while in power down mode",
{instruction[7:1], sdo}));
end else begin
case ({instruction[7:1], sdo})
release_power_down_instruction : begin
state <= releasing_power_down;
power_up_time <= $time;
`DBG(("SPI: release power down issued"));
end
fast_read_instruction : begin
state <= receiving_fast_read_address;
address_bits_received <= 0;
`DBG(("SPI: fast read issued"));
end
default : begin
state <= error;
`MSG(("SPI: error: unknown instruction: 0x%x",
{instruction[7:1], sdo}));
end
endcase // case ({instruction[7:1], sdo})
end // else: !if(!powered_up && ({instruction[7:1], sdo} !=...
end // if (instruction_bits_received + 1 == 8)
end // else: !if(ss_n)
end // case: receiving_instruction
releasing_power_down : begin
if (!ss_n) begin
state <= receiving_instruction;
instruction_bits_received <= 1;
instruction[7] <= sdo;
if (power_up_time + power_up_wait_time >= $time) begin
`MSG(("SPI: error: release power down interrupted %0d ns before finishing",
power_up_time + power_up_wait_time - $time));
end
end // if (!ss_n)
end // case: releasing_power_down
receiving_fast_read_address : begin
if (ss_n) begin
state <= idle;
`MSG(("SPI: error: fast read instruction aborted after %0d bits of address were sent",
address_bits_received));
end else begin
address[23 - address_bits_received] <= sdo;
address_bits_received <= address_bits_received + 1;
if (address_bits_received + 1 == 24) begin
state <= receiving_fast_read_dummy_byte;
dummy_bits_received <= 0;
end
end
end
receiving_fast_read_dummy_byte : begin
if (ss_n) begin
state <= idle;
`MSG(("SPI: error: fast read instruction aborted after %0d bits of dummy byte were sent",
dummy_bits_received));
end else begin
dummy_bits_received <= dummy_bits_received + 1;
if (dummy_bits_received + 1 == 8) begin
bit_in_byte <= 7;
if (address >= memory_size) begin
state <= error;
`MSG(("SPI: error: memory address too high (0x%x)",
address));
end else begin
state <= responding_fast_read;
end
end
end // else: !if(ss_n)
end // case: receiving_fast_read_dummy_byte
responding_fast_read : begin
if (ss_n) begin
state <= idle;
end else begin
bit_in_byte <= bit_in_byte - 1;
if (bit_in_byte == 0) begin
address <= address + 1;
if (address + 1 >= memory_size) begin
state <= error;
`MSG(("SPI: error: memory address too high (0x%x)",
address));
end
end
end // else: !if(ss_n)
end // case: responding_fast_read
endcase // case (state)
end // always @ (posedge sck)
always @ (negedge sck) begin
if (ss_n) begin
outputting <= 0;
end else if (state == responding_fast_read) begin
outputting <= 1;
outputted_bit <= memory[address][bit_in_byte];
end else if (state == error) begin
outputted_bit <= 1'bx;
end else begin
outputting <= 0;
end
end // always @ (negedge sck)
endmodule // W25Q16BV_flash
|