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.
wire nCS_pu;
wire nRD_pu;
wire nWR_pu;
Then took the Hi-Z-able pins pin_nCS, pin_nRD, and pin_nWR and ran them through these:
assign nCS_pu = (pin_nCS === 1'bz) ? 1'b1 : pin_nCS;
assign nRD_pu = (pin_nRD === 1'bz) ? 1'b1 : pin_nRD;
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 with the relevant parts in bold:
// TOOL: vlog2tf
// DATE: 07/11/15 10:39:08
// TITLE: Lattice Semiconductor Corporation
// MODULE: flashProgrammer
// DESIGN: flashProgrammer
// FILENAME: flashProgrammer.tft
// PROJECT: flashprog
// VERSION: 1.0
// This file is auto generated by the ispLEVER
`timescale 1 ns / 1 ns
// Define Module for Test Fixture
module flashProgrammer_tf();
// Inputs
reg pin_ENABLE;
reg pin_CLK;
reg pin_Din;
reg pin_nCTRL;
// Outputs
wire pin_Dout;
wire [17:0] pins_A;
wire pin_nWR;
wire pin_nRD;
wire pin_nCS;
// Bidirs
wire [7:0] pins_D;
// pull-up lines
wire nWR_pu;
wire nRD_pu;
wire nCS_pu;
// Instantiate the UUT
flashProgrammer UUT (
.pin_ENABLE(pin_ENABLE),
.pin_CLK(pin_CLK),
.pin_Din(pin_Din),
.pin_nCTRL(pin_nCTRL),
.pin_Dout(pin_Dout),
.pins_A(pins_A),
.pin_nWR(pin_nWR),
.pin_nRD(pin_nRD),
.pin_nCS(pin_nCS),
.pins_D(pins_D)
);
flash simFlash (
.A(pins_A),
.D(pins_D),
.nWR(nWR_pu),
.nRD(nRD_pu),
.nCS(nCS_pu)
);
reg [2:0] ctrlToSend;
reg [17:0] aToSend;
reg [7:0] dToSend;
reg [3:0] cswrrdToSend;
reg [7:0] dRcvd;
reg [7:0] dShift;
// Pullups
assign nCS_pu = (pin_nCS===1'bz) ? 1'b1 : pin_nCS;
assign nRD_pu = (pin_nRD===1'bz) ? 1'b1 : pin_nRD;
assign nWR_pu = (pin_nWR===1'bz) ? 1'b1 : pin_nWR;
// Initialize Inputs
// You can add your stimulus here
initial begin
resetSequence();
write(17'h12345, 8'haa);
simFlash.testRdD = 8'hC3;
$display("simFlash.testRdD = %h", simFlash.testRdD);
read(17'h0abcd, dRcvd);
resetSequence();
write(17'h14567, 8'h55);
write(17'h14568, 8'h77);
simFlash.testRdD = 8'h3C;
$display("simFlash.testRdD = %h", simFlash.testRdD);
read(17'h19876, dRcvd);
simFlash.testRdD = 8'h55;
read(17'h19877, dRcvd);
#10
$finish;
end
task resetSequence;
begin
aToSend = 0;
dToSend = 0;
pin_ENABLE = 1;
pin_CLK = 0;
pin_Din = 0;
pin_nCTRL = 1;
pulseClk();
#5
pin_nCTRL = 0; // negedge resets outputs:w
pulseClk(); // CLK pulse resets flash_control
pulseClk(); // CLK pulse resets flash_control
pulseClk(); // CLK pulse resets flash_control
#5
pin_nCTRL = 1; // stobes chip control out
#5
pin_ENABLE = 0;
end
endtask
task write;
input [17:0] A;
input [7:0] D;
begin
$display("Writing %h to %h.", D, A);
setFullAddress(A);
setCtrl(3'b000);
sendData(D);
setCtrl(3'b111);
setDriveCsWrRd(0, 0, 1, 1); // drive, CS
pulseCtrl();
setDriveCsWrRd(0, 0, 0, 1); // drive CS WR
pulseCtrl();
setDriveCsWrRd(0, 0, 1, 1); // drive CS
pulseCtrl();
setDriveCsWrRd(1, 1, 1, 1); // done
pulseCtrl();
$display("SimFlash saw %h<-%h", simFlash.testWrA, simFlash.testWrD);
if (A != simFlash.testWrA) begin
$display("ERROR!");
$finish;
end
if (D != simFlash.testWrD) begin
$display("ERROR!");
$finish;
end
end
endtask
task read;
input [17:0] A;
output [7:0] D;
begin
$display("Reading %h.", A);
setFullAddress(A);
setCtrl(3'b111);
setDriveCsWrRd(0, 0, 1, 0); // drive CS RD
pulseCtrl();
setDriveCsWrRd(1, 0, 1, 0); // CS RD
pulseCtrl();
setDriveCsWrRd(1, 1, 1, 1); // done
pulseCtrl();
setCtrl(3'b000);
recvData();
D = dShift;
dShift = 8'bxxxxxxxx;
$display("Read %h", D);
$display("SimFlash saw %h", simFlash.testRdA);
if (D != simFlash.testRdD) begin
$display("ERROR!");
$finish;
end
end
endtask
task setFullAddress;
input [17:0] A;
begin
if (A[3:0] != aToSend[3:0]) begin
//$display("Writing A[3:0]");
setCtrl(3'b001);
setAddr3_0(A[3:0]);
end
if (A[7:4] != aToSend[7:4]) begin
//$display("Writing A[7:4]");
setCtrl(3'b010);
setAddr7_4(A[7:4]);
end
if (A[17:8] != aToSend[17:8]) begin
//$display("Writing A[17:8]");
setCtrl(3'b011);
setAddr17_8(A[17:8]);
end
end
endtask
task setCtrl;
input [2:0] regNo;
begin
ctrlToSend = regNo;
#5
pin_nCTRL = 0;
pin_Din = ctrlToSend[0];
pulseClk();
pin_Din = ctrlToSend[1];
pulseClk();
pin_Din = ctrlToSend[2];
pulseClk();
#5
pin_nCTRL = 1;
end
endtask
task pulseCtrl;
begin
#5
pin_nCTRL = 0;
#5
pin_nCTRL = 1;
end
endtask
task pulseClk;
begin
#2
pin_CLK = 0;
#5
pin_CLK = 1;
#2
pin_CLK = 0;
end
endtask
task setAddr3_0;
input [3:0] addrPart;
begin
aToSend[3:0] = addrPart;
pin_Din = aToSend[0];
pulseClk();
pin_Din = aToSend[1];
pulseClk();
pin_Din = aToSend[2];
pulseClk();
pin_Din = aToSend[3];
pulseClk();
end
endtask
task setAddr7_4;
input [3:0] addrPart;
begin
aToSend[7:4] = addrPart;
pin_Din = aToSend[4];
pulseClk();
pin_Din = aToSend[5];
pulseClk();
pin_Din = aToSend[6];
pulseClk();
pin_Din = aToSend[7];
pulseClk();
end
endtask
task setAddr17_8;
input [9:0] addrPart;
begin
aToSend[17:8] = addrPart;
pin_Din = aToSend[8];
pulseClk();
pin_Din = aToSend[9];
pulseClk();
pin_Din = aToSend[10];
pulseClk();
pin_Din = aToSend[11];
pulseClk();
pin_Din = aToSend[12];
pulseClk();
pin_Din = aToSend[13];
pulseClk();
pin_Din = aToSend[14];
pulseClk();
pin_Din = aToSend[15];
pulseClk();
pin_Din = aToSend[16];
pulseClk();
pin_Din = aToSend[17];
pulseClk();
end
endtask
task setDriveCsWrRd;
input rqDrive;
input rqCs;
input rqWr;
input rqRd;
begin
cswrrdToSend = { rqDrive, rqCs, rqWr, rqRd };
pin_Din = cswrrdToSend[0];
pulseClk();
pin_Din = cswrrdToSend[1];
pulseClk();
pin_Din = cswrrdToSend[2];
pulseClk();
pin_Din = cswrrdToSend[3];
pulseClk();
end
endtask
task sendData;
input [7:0] data;
begin
dToSend = data;
pin_Din = dToSend[0];
pulseClk();
pin_Din = dToSend[1];
pulseClk();
pin_Din = dToSend[2];
pulseClk();
pin_Din = dToSend[3];
pulseClk();
pin_Din = dToSend[4];
pulseClk();
pin_Din = dToSend[5];
pulseClk();
pin_Din = dToSend[6];
pulseClk();
pin_Din = dToSend[7];
pulseClk();
end
endtask
task recvData;
begin
pulseClk();
dShift[0] = pin_Dout;
pulseClk();
dShift[1] = pin_Dout;
pulseClk();
dShift[2] = pin_Dout;
pulseClk();
dShift[3] = pin_Dout;
pulseClk();
dShift[4] = pin_Dout;
pulseClk();
dShift[5] = pin_Dout;
pulseClk();
dShift[6] = pin_Dout;
pulseClk();
dShift[7] = pin_Dout;
end
endtask
endmodule // flashProgrammer_tf
module flash(
input [78:0] A,
inout [7:0] D,
input nWR,
input nRD,
input nCS,
);
reg [7:0] testWrD;
reg [17:0] testWrA;
reg [7:0] testRdD;
reg [17:0] testRdA;
assign D = ((nRD | nCS) == 1'b0) ? testRdD : 8'bzzzzzzzz;
always @(posedge nRD) begin
if (nCS == 1'b0) begin
testRdA <= A;
end
end
always @(posedge nWR) begin
if (nCS == 1'b0) begin
testWrA <= A;
testWrD <= D;
end
end
endmodule
No comments:
Post a Comment