I made an error in my assumption of the flash programmer, though and I see I have to possibly change something. I was assuming that the flash device was using the rising edge of the WR line to write and starting to drive the data lines at the same as WR went low. This led to errors because it was actually using the falling edge of WR and so the data wasn't properly set up.
According to the Z-80 data sheet, the data is set up and held for ~15 ns before and after the WR line low is low. So, I should be able to use the rising edge of WR without a problem.
// This CPLD meant for the Lattice M4A5 64/32 is a simple bank switching
// memory control unit. It has 8 registers:
// 00 - bank 0
// 01 - bank 1
// 02 - bank 2
// 03 - bank 3
// 04 - update 0
// 05 - update 1
// 06 - update 2
// 07 - update 3
//
// The banks are meant to substitute starting address line 14.
// The update registers can only be written to from bank 00 i.e. the lowest
// 16kb.
//
// The banks are updated from the update registers when HALT is called
// from bank 0. NMI immediately follows HALT in this circumstance
//
`define BANKTOP 4
`define IO_RANGE 7:3
`define IO_VALUE 5'b00000
`define ACTIVELOW 1'b0
module mcu (
input pin_CLK,
input [15:0] pins_A,
input pin_nRESET, pin_nWR, pin_nRD, pin_nMREQ, pin_nIORQ, pin_nM1, pin_nHALT,
output reg pin_nNMI,
output [`BANKTOP-1:0] pins_Aout,
output pin_nCS0, pin_nCS1,
inout [7:0] pins_D
);
reg [`BANKTOP:0] bankReg0;
reg [`BANKTOP:0] bankReg1;
reg [`BANKTOP:0] bankReg2;
reg [`BANKTOP:0] bankReg3;
reg [`BANKTOP:0] updateReg0;
reg [`BANKTOP:0] updateReg1;
reg [`BANKTOP:0] updateReg2;
reg [`BANKTOP:0] updateReg3;
reg nKernel;
wire nInRange;
reg [7:0] Dint;
wire [`BANKTOP:0] selBank;
// Determine if the address bus is talking to us
assign nInRange = ((pins_A[`IO_RANGE] == `IO_VALUE) ? 1'b0 : 1'b1) | pin_nIORQ;
// Get selected output
assign selBank = pins_A[15] ? (pins_A[14] ? bankReg3 : bankReg2) : (pins_A[14] ? bankReg1 : bankReg0);
// assign Aout -- Hi-Z on reset
assign pins_Aout = pin_nRESET ? selBank[`BANKTOP-1:0] : 8'bzzzzzzzz;
// CS's for top bit of bank
assign pin_nCS0 = pin_nRESET ? (selBank[`BANKTOP] | pin_nMREQ) : 1'bz;
assign pin_nCS1 = pin_nRESET ? ((~selBank[`BANKTOP]) | pin_nMREQ) : 1'bz;
assign pins_D = ((pin_nRD | nInRange) == 1'b0) ? Dint : 8'bzzzzzzzz;
always @(*) begin
case (pins_A[2:0])
3'b000:
Dint = bankReg0;
3'b001:
Dint = bankReg1;
3'b010:
Dint = bankReg2;
3'b011:
Dint = bankReg3;
3'b100:
Dint = updateReg0;
3'b101:
Dint = updateReg1;
3'b110:
Dint = updateReg2;
3'b111:
Dint = updateReg3;
endcase
end
always @(posedge pin_CLK) begin
if (pin_nRESET == `ACTIVELOW) begin
bankReg0 <= 0;
bankReg1 <= 1;
bankReg2 <= (1 << `BANKTOP);
bankReg3 <= (1 << `BANKTOP) | 1;
pin_nNMI <= 1'b1;
end
else begin
if ((pin_nHALT | nKernel) == `ACTIVELOW) begin
bankReg0 <= updateReg0;
bankReg1 <= updateReg1;
bankReg2 <= updateReg2;
bankReg3 <= updateReg3;
end
pin_nNMI <= pin_nHALT;
if ((pin_nM1 | pin_nMREQ) == `ACTIVELOW) begin
nKernel <= pins_A[15] | pins_A[14];
end
end
end
always @(posedge pin_nWR) begin
if (((pin_nIORQ | nInRange) == `ACTIVELOW) && (pins_A[2] == 1'b1)) begin
case (pins_A[1:0])
2'b00: begin
updateReg0 <= pins_D;
end
2'b01: begin
updateReg1 <= pins_D;
end
2'b10: begin
updateReg2 <= pins_D;
end
2'b11: begin
updateReg3 <= pins_D;
end
endcase
end
end
endmodule
So, this is already old. I added a nBUSQACK pin for better cooperation with the in circuit flash programmer. Also added it to the testbench. It seems to work in the simulation.
No comments:
Post a Comment