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