Wednesday, July 15, 2015

MCU Design Refinements

I changed the MCU CPLD verilog.

The MCU is just a simple bank switcher. I had 4 5 bit banks. The top two bits of the 16 bit address bus: 15 and 14, select a map. Then this map result is used for address bits 17-14.

Originally, I was thinking I would the top bit (essentially A[18]) as the chip select for the SRAM or the flash. But Duh!  Ab address line does not a chip select make. So I removed the top address line and added two pin_nCS lines. These will select. And they tristate in reset. Also, the mapping tristates in reset also. This will allow me to use my in-circuit flash programmer. The Arduino will assert RESET to....   I need that needle scratching across the record sound effect... I just realized a problem.

I went to see if the bus control signals tristate on the Z-80 in reset. They don't. They go high. I DO need to use BUSREQ because they do tri-state in that mode. And I can't see what happens if I just tie BUSREQ to RESET. Which takes priority? Most likely RESET.

Well, crap! Back to the CPLD design...

[UPDATE: OK, I've decided to use 2 switches on the DIP switch instead. So the CPLD pin_nRESET line will connect to the board RESET or CPU BUSREQ line. So all is well with the CPLD...for now.]

Here is the latest MCU code before I realized that I need to use BUSREQ or BUSACK to tristate the bus lines:
       
// 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

No comments:

Post a Comment