Pullups in Verilog
So I have written in VHDL a long time ago and read verilog a few years ago. But I don’t know the ins and outs of verilog programming. Today, I went to check my waveforms on the flash programmer part to ensure that the whole bus and buscontrol goes Hi-Z when RESET is asserted. And I saw that the data bus was actually going from Hi-Z to unknown while RESET was asserted. Odd, I thought.
I quickly decided that the most likely scenario was that my memory simulator was mishandling the Hi-Z RD signal. And indeed. I routed the RD signal straight from the CPLD simulation to the memory simulator. So the memory simulator was getting Z as an input. Well, in verilog, if you have OR/NOR gates and everything that’s not L is either Z or X, the output is X. Similarly, with AND/NAND gates, if everything that’s not H is Z or X, the output is X. So, my bus enabler was getting confused.
The hardware solution is pullup resistors between the output and Vcc (or pull downs to ground as the case may be). But verilog has no resistors that I know of. What to do?
I added three new ‘wire’ declarations.
1 wire nCS_pu;
2 wire nRD_pu;
3 wire nWR_pu;
Then took the Hi-Z-able pins pin_nCS, pin_nRD, and pin_nWR and ran them through these:
1 assign nCS_pu = (pin_nCS === 1'bz) ? 1'b1 : pin_nCS;
2 assign nRD_pu = (pin_nRD === 1'bz) ? 1'b1 : pin_nRD;
3 assign nWR_pu = (pin_nWR === 1'bz) ? 1'b1 : pin_nWR;
And voila! Pull-ups. The === is needed to do a comparison to Z or X. With just ==, verilog rightly cannot determine the output and just assigns X if the the output is not 100% clear from the inputs. In other words a==b in verilog where a and b are both 1’bz is neither true nor false because the interpreter says Z can be either H or L–not sure which. So a==b might me H==L or H==H or L==H or L==L. But with ===, if both a and b are 1’bz, the result is true (false for !==) and if a and b are both 1’bx, then the results is true (again, false for !==). I think that 1’bz !== 1’bx. Obviously this behavior can’t be synthesized, but it is useful for testing.
I connected my memory to these and everything worked as expected.
Here is the testbench code.
1 // TOOL: vlog2tf
2 // DATE: 07/11/15 10:39:08
3 // TITLE: Lattice Semiconductor Corporation
4 // MODULE: flashProgrammer
5 // DESIGN: flashProgrammer
6 // FILENAME: flashProgrammer.tft
7 // PROJECT: flashprog
8 // VERSION: 1.0
9 // This file is auto generated by the ispLEVER
10
11
12 `timescale 1 ns / 1 ns
13
14 // Define Module for Test Fixture
15 module flashProgrammer_tf();
16
17 // Inputs
18 reg pin_ENABLE;
19 reg pin_CLK;
20 reg pin_Din;
21 reg pin_nCTRL;
22
23
24 // Outputs
25 wire pin_Dout;
26 wire [17:0] pins_A;
27 wire pin_nWR;
28 wire pin_nRD;
29 wire pin_nCS;
30
31
32 // Bidirs
33 wire [7:0] pins_D;
34 <b>
35
36 // pull-up lines
37 wire nWR_pu;
38 wire nRD_pu;
39 wire nCS_pu;
40 </b>
41
42
43 // Instantiate the UUT
44 flashProgrammer UUT (
45 .pin_ENABLE(pin_ENABLE),
46 .pin_CLK(pin_CLK),
47 .pin_Din(pin_Din),
48 .pin_nCTRL(pin_nCTRL),
49 .pin_Dout(pin_Dout),
50 .pins_A(pins_A),
51 .pin_nWR(pin_nWR),
52 .pin_nRD(pin_nRD),
53 .pin_nCS(pin_nCS),
54 .pins_D(pins_D)
55 );
56
57 flash simFlash (
58 .A(pins_A),
59 .D(pins_D),
60 <b>
61 .nWR(nWR_pu),
62 .nRD(nRD_pu),
63 .nCS(nCS_pu)
64 </b>
65 );
66
67 reg [2:0] ctrlToSend;
68 reg [17:0] aToSend;
69 reg [7:0] dToSend;
70 reg [3:0] cswrrdToSend;
71 reg [7:0] dRcvd;
72 reg [7:0] dShift;
73
74 <b>
75
76 // Pullups
77 assign nCS_pu = (pin_nCS===1'bz) ? 1'b1 : pin_nCS;
78 assign nRD_pu = (pin_nRD===1'bz) ? 1'b1 : pin_nRD;
79 assign nWR_pu = (pin_nWR===1'bz) ? 1'b1 : pin_nWR;
80 </b>
81
82 // Initialize Inputs
83 // You can add your stimulus here
84 initial begin
85
86 resetSequence();
87
88 write(17'h12345, 8'haa);
89
90 simFlash.testRdD = 8'hC3;
91 $display("simFlash.testRdD = %h", simFlash.testRdD);
92
93 read(17'h0abcd, dRcvd);
94
95 resetSequence();
96
97 write(17'h14567, 8'h55);
98 write(17'h14568, 8'h77);
99
100 simFlash.testRdD = 8'h3C;
101 $display("simFlash.testRdD = %h", simFlash.testRdD);
102
103 read(17'h19876, dRcvd);
104 simFlash.testRdD = 8'h55;
105 read(17'h19877, dRcvd);
106
107 #10
108
109 $finish;
110 end
111
112 task resetSequence;
113 begin
114 aToSend = 0;
115 dToSend = 0;
116
117 pin_ENABLE = 1;
118 pin_CLK = 0;
119 pin_Din = 0;
120 pin_nCTRL = 1;
121
122 pulseClk();
123
124 #5
125 pin_nCTRL = 0; // negedge resets outputs:w
126
127
128 pulseClk(); // CLK pulse resets flash_control
129 pulseClk(); // CLK pulse resets flash_control
130 pulseClk(); // CLK pulse resets flash_control
131
132 #5
133 pin_nCTRL = 1; // stobes chip control out
134
135 #5
136 pin_ENABLE = 0;
137
138 end
139 endtask
140
141 task write;
142 input [17:0] A;
143 input [7:0] D;
144 begin
145 $display("Writing %h to %h.", D, A);
146
147 setFullAddress(A);
148
149 setCtrl(3'b000);
150 sendData(D);
151 setCtrl(3'b111);
152 setDriveCsWrRd(0, 0, 1, 1); // drive, CS
153 pulseCtrl();
154 setDriveCsWrRd(0, 0, 0, 1); // drive CS WR
155 pulseCtrl();
156 setDriveCsWrRd(0, 0, 1, 1); // drive CS
157 pulseCtrl();
158 setDriveCsWrRd(1, 1, 1, 1); // done
159 pulseCtrl();
160 $display("SimFlash saw %h<-%h", simFlash.testWrA, simFlash.testWrD);
161
162 if (A != simFlash.testWrA) begin
163 $display("ERROR!");
164 $finish;
165 end
166 if (D != simFlash.testWrD) begin
167 $display("ERROR!");
168 $finish;
169 end
170 end
171 endtask
172
173 task read;
174 input [17:0] A;
175 output [7:0] D;
176 begin
177 $display("Reading %h.", A);
178
179 setFullAddress(A);
180
181 setCtrl(3'b111);
182 setDriveCsWrRd(0, 0, 1, 0); // drive CS RD
183 pulseCtrl();
184 setDriveCsWrRd(1, 0, 1, 0); // CS RD
185 pulseCtrl();
186 setDriveCsWrRd(1, 1, 1, 1); // done
187 pulseCtrl();
188 setCtrl(3'b000);
189 recvData();
190 D = dShift;
191 dShift = 8'bxxxxxxxx;
192 $display("Read %h", D);
193 $display("SimFlash saw %h", simFlash.testRdA);
194
195 if (D != simFlash.testRdD) begin
196 $display("ERROR!");
197 $finish;
198 end
199 end
200 endtask
201
202 task setFullAddress;
203 input [17:0] A;
204 begin
205 if (A[3:0] != aToSend[3:0]) begin
206 //$display("Writing A[3:0]");
207 setCtrl(3'b001);
208 setAddr3_0(A[3:0]);
209 end
210 if (A[7:4] != aToSend[7:4]) begin
211 //$display("Writing A[7:4]");
212 setCtrl(3'b010);
213 setAddr7_4(A[7:4]);
214 end
215 if (A[17:8] != aToSend[17:8]) begin
216 //$display("Writing A[17:8]");
217 setCtrl(3'b011);
218 setAddr17_8(A[17:8]);
219 end
220 end
221 endtask
222
223 task setCtrl;
224 input [2:0] regNo;
225 begin
226 ctrlToSend = regNo;
227 #5
228 pin_nCTRL = 0;
229 pin_Din = ctrlToSend[0];
230 pulseClk();
231 pin_Din = ctrlToSend[1];
232 pulseClk();
233 pin_Din = ctrlToSend[2];
234 pulseClk();
235 #5
236 pin_nCTRL = 1;
237 end
238 endtask
239
240 task pulseCtrl;
241 begin
242 #5
243 pin_nCTRL = 0;
244 #5
245 pin_nCTRL = 1;
246 end
247 endtask
248
249 task pulseClk;
250 begin
251 #2
252 pin_CLK = 0;
253 #5
254 pin_CLK = 1;
255 #2
256 pin_CLK = 0;
257 end
258 endtask
259
260 task setAddr3_0;
261 input [3:0] addrPart;
262 begin
263 aToSend[3:0] = addrPart;
264 pin_Din = aToSend[0];
265 pulseClk();
266 pin_Din = aToSend[1];
267 pulseClk();
268 pin_Din = aToSend[2];
269 pulseClk();
270 pin_Din = aToSend[3];
271 pulseClk();
272 end
273 endtask
274
275 task setAddr7_4;
276 input [3:0] addrPart;
277 begin
278 aToSend[7:4] = addrPart;
279 pin_Din = aToSend[4];
280 pulseClk();
281 pin_Din = aToSend[5];
282 pulseClk();
283 pin_Din = aToSend[6];
284 pulseClk();
285 pin_Din = aToSend[7];
286 pulseClk();
287 end
288 endtask
289
290 task setAddr17_8;
291 input [9:0] addrPart;
292 begin
293 aToSend[17:8] = addrPart;
294 pin_Din = aToSend[8];
295 pulseClk();
296 pin_Din = aToSend[9];
297 pulseClk();
298 pin_Din = aToSend[10];
299 pulseClk();
300 pin_Din = aToSend[11];
301 pulseClk();
302 pin_Din = aToSend[12];
303 pulseClk();
304 pin_Din = aToSend[13];
305 pulseClk();
306 pin_Din = aToSend[14];
307 pulseClk();
308 pin_Din = aToSend[15];
309 pulseClk();
310 pin_Din = aToSend[16];
311 pulseClk();
312 pin_Din = aToSend[17];
313 pulseClk();
314 end
315 endtask
316
317 task setDriveCsWrRd;
318 input rqDrive;
319 input rqCs;
320 input rqWr;
321 input rqRd;
322 begin
323 cswrrdToSend = { rqDrive, rqCs, rqWr, rqRd };
324 pin_Din = cswrrdToSend[0];
325 pulseClk();
326 pin_Din = cswrrdToSend[1];
327 pulseClk();
328 pin_Din = cswrrdToSend[2];
329 pulseClk();
330 pin_Din = cswrrdToSend[3];
331 pulseClk();
332 end
333 endtask
334
335 task sendData;
336 input [7:0] data;
337 begin
338 dToSend = data;
339 pin_Din = dToSend[0];
340 pulseClk();
341 pin_Din = dToSend[1];
342 pulseClk();
343 pin_Din = dToSend[2];
344 pulseClk();
345 pin_Din = dToSend[3];
346 pulseClk();
347 pin_Din = dToSend[4];
348 pulseClk();
349 pin_Din = dToSend[5];
350 pulseClk();
351 pin_Din = dToSend[6];
352 pulseClk();
353 pin_Din = dToSend[7];
354 pulseClk();
355 end
356 endtask
357
358 task recvData;
359 begin
360 pulseClk();
361 dShift[0] = pin_Dout;
362 pulseClk();
363 dShift[1] = pin_Dout;
364 pulseClk();
365 dShift[2] = pin_Dout;
366 pulseClk();
367 dShift[3] = pin_Dout;
368 pulseClk();
369 dShift[4] = pin_Dout;
370 pulseClk();
371 dShift[5] = pin_Dout;
372 pulseClk();
373 dShift[6] = pin_Dout;
374 pulseClk();
375 dShift[7] = pin_Dout;
376 end
377 endtask
378
379 endmodule // flashProgrammer_tf
380
381 module flash(
382 input [78:0] A,
383 inout [7:0] D,
384
385 input nWR,
386 input nRD,
387 input nCS,
388 );
389
390 reg [7:0] testWrD;
391 reg [17:0] testWrA;
392 reg [7:0] testRdD;
393 reg [17:0] testRdA;
394
395 <b>
396 assign D = ((nRD | nCS) == 1'b0) ? testRdD : 8'bzzzzzzzz;
397 </b>
398
399 always @(posedge nRD) begin
400 if (nCS == 1'b0) begin
401 testRdA <= A;
402 end
403
404 end
405 always @(posedge nWR) begin
406 if (nCS == 1'b0) begin
407 testWrA <= A;
408 testWrD <= D;
409 end
410 end
411
412 endmodule