module spectrum(output wire[7:0] LED,
                output wire[33:0] GPIO_0,
                input wire CLOCK_50,       // Input clock 50 MHz
                input wire[1:0] KEY,         // 0 = RESET button; active low, 1 = NMI button
                input wire PS2_CLK,
                input wire PS2_DAT,
                inout wire I2C_SCLK,
                inout wire I2C_SDAT,
                output wire AUD_XCK,
                output wire AUD_ADCLRCK,
                output wire AUD_DACLRCK,
                output wire AUD_BCLK,
                output wire AUD_DACDAT,
                input wire AUD_ADCDAT,
                output wire [3:0] VGA_R,
                output wire [3:0] VGA_G,
                output wire [3:0] VGA_B,
                output reg VGA_HS,
                output reg VGA_VS,
                input wire[3:0] SW,          // 0 = ROM selection, 1 = enable/disable interrupts, 2 = turbo speed
                output wire[33:0] GPIO_1 // Exports CPU chip pins
);
`default_nettype none


wire reset;
wire locked;
assign reset = locked & KEY[0:0];


// Export selected pins to the extension connector
assign GPIO_1[15:0] = A[15:0];
assign GPIO_1[23:16] = D[7:0];
assign GPIO_1[31:24] = {nM1,nMREQ,nIORQ,nRD,nWR,nRFSH,nHALT,nBUSACK};

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Internal buses and address map selection logic
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
wire [15:0] A;                  // Global address bus
wire [7:0] D;                   // CPU data bus

wire [7:0] ram_data;            // Internal 16K RAM data
wire RamWE;
assign RamWE = A[15:14]==2'b01 && nIORQ==1 && nRD==1 && nWR==0;

wire ExtRamWE;                  // Extended (and external) 32K RAM
assign ExtRamWE = A[15]==1 && nIORQ==1 && nRD==1 && nWR==0;

wire [7:0] ula_data;            // ULA
wire io_we;
assign io_we = nIORQ==0 && nRD==1 && nWR==0;


// Memory map:
//   0000 - 3FFF  16K ROM (mapped to rom0)
//   4000 - 7FFF  16K dual-port ram0
//   8000 - FFFF  32K RAM (mapped to ram1)
always @(*) // always_comb
begin
    case ({nIORQ,nRD,nWR})
        // -------------------------------- Memory read --------------------------------
        3'b101: begin
                casez (A[15:14])
                    2'b00:  D[7:0] = rom_data;
                    2'b01:  D[7:0] = ram0_data;
                    2'b1?:  D[7:0] = ram1_data;
                endcase
            end
        // ---------------------------------- IO read ----------------------------------
        3'b001: begin
                // Normally data supplied by the ULA
                D[7:0] = ula_data;

                // Kempston joystick at the IO address 0x1F; active bits are high:
                //                   FIRE         UP           DOWN         LEFT         RIGHT
//                if (A[7:0]==8'h1F) begin
//                    D[7:0] = { 3'b0, !kempston[4],!kempston[0],!kempston[1],!kempston[2],!kempston[3] };
//                end
            end
    default:
        D[7:0] = {8{1'bz}};
    endcase
end


// ----------------------------------------------------
// Instantiate ROM, 16K
// ----------------------------------------------------
wire[7:0]  rom_data;
rom0 rom(
    .clock(clk_cpu),
	 
    .address(A),
    .q(rom_data)
);


// ----------------------------------------------------
// Instantiate RAM0, 16K, dual port
// ----------------------------------------------------
wire clk_vram;
wire[7:0] ram0_data;
// "A" port is the CPU side, "B" port is the VGA image generator in the ULA
ram16 ram0(
    .clock(clk_vram),

    .address_a(A[13:0]),
    .data_a(D),
    .q_a(ram0_data),
    .wren_a(RamWE),

    .address_b({1'b0, vram_address}),
    .data_b(8'b0),
    .q_b(vram_data),
    .wren_b(0)
);

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Rest of RAM, 32K
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
wire[7:0] ram1_data;
ram32 ram1(
    .clock(clk_cpu),

    .address(A[14:0]),
    .data(D),
    .q(ram1_data),
    .wren(0)
);


//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Instantiate ULA
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
wire clk_cpu;                   // Global CPU clock of 3.5 MHz
assign LED[2:2] = SW[2:2];      // Glow red when in turbo mode (7.0 MHz)
wire [12:0] vram_address;       // ULA video block requests a byte from the video RAM
wire [7:0] vram_data;           // ULA video block reads a byte from the video RAM
wire vs_nintr;                  // Generates a vertical retrace interrupt
wire pressed;                   // Show that a key is being pressed
wire beeper;                    // Show the beeper state

ula ula_(
    //-------- Clocks and reset -----------------
    .CLOCK_50 (CLOCK_50),       // Input clock 50 MHz
    .turbo (SW[2:2]),           // Turbo speed (3.5 MHz x 2 = 7.0 MHz)
    .clk_vram (clk_vram),
    .nreset (reset),            // KEY0 is reset; on DE1, keys are active low!
    .locked (locked),           // PLL is locked signal

    //-------- CPU control ----------------------
    .clk_cpu (clk_cpu),         // Generates CPU clock of 3.5 MHz
    .vs_nintr (vs_nintr),       // Generates a vertical retrace interrupt

    //-------- Address and data buses -----------
    .A (A),                     // Input address bus
    .D (D),                     // Input data bus
    .ula_data (ula_data),       // Output data
    .io_we (io_we),             // Write enable to data register through IO

    .vram_address (vram_address),// ULA video block requests a byte from the video RAM
    .vram_data (vram_data),     // ULA video block reads a byte from the video RAM

    //-------- PS/2 Keyboard --------------------
    .PS2_CLK (PS2_CLK),
    .PS2_DAT (PS2_DAT),
    .pressed (pressed),

    //-------- Audio (Tape player) --------------
    .I2C_SCLK (I2C_SCLK),
    .I2C_SDAT (I2C_SDAT),
    .AUD_XCK (AUD_XCK),
    .AUD_ADCLRCK (AUD_ADCLRCK),
    .AUD_DACLRCK (AUD_DACLRCK),
    .AUD_BCLK (AUD_BCLK),
    .AUD_DACDAT (AUD_DACDAT),
    .AUD_ADCDAT (AUD_ADCDAT),
    .beeper (beeper),

    //-------- VGA connector --------------------
    .VGA_R (VGA_R),
    .VGA_G (VGA_G),
    .VGA_B (VGA_B),
    .VGA_HS (VGA_HS),
    .VGA_VS (VGA_VS)
);

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Instantiate A-Z80 CPU
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
wire nM1;
wire nMREQ;
wire nIORQ;
wire nRD;
wire nWR;
wire nRFSH;
wire nHALT;
wire nBUSACK;

wire nWAIT = 1;
wire nINT = (SW[1:1]==0)? vs_nintr : 1'b1;// SW1 disables interrupts and, hence, keyboard
assign LED[0] = SW[1:1];               // Glow red when interrupts are *disabled*
wire nNMI = KEY[1:1];                   // Pressing KEY1 issues a NMI
wire nBUSRQ = 1;

z80_top_direct_n z80_(
    .nM1 (nM1),
    .nMREQ (nMREQ),
    .nIORQ (nIORQ),
    .nRD (nRD),
    .nWR (nWR),
    .nRFSH (nRFSH),
    .nHALT (nHALT),
    .nBUSACK (nBUSACK),

    .nWAIT (nWAIT),
    .nINT (nINT),
    .nNMI (nNMI),
    .nRESET (reset),
    .nBUSRQ (nBUSRQ),

    .CLK (clk_cpu),
    .A (A),
    .D (D)
);


// reg[21:0] counter;
// always @(posedge CLOCK_50)
// begin
//     counter <= counter + 1;
//     if (counter == 0)
//     begin
//         A <= A + 1;
//     end
// end

// // make the leds blink with rom and ram0 data
// assign LED[3:0] = rom_data[3:0];
// assign LED[7:4] = ram0_data[7:4];

// // expose memories at A to GPIO_0
// assign GPIO_0[7:0]   = rom_data;
// assign GPIO_0[15:8]  = ram0_data;
// assign GPIO_0[23:16] = ram1_data;
// assign GPIO_0[31:24] = vram_data;

endmodule
