module spectrum(output wire[7:0] LED, 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 wire VGA_HS, output wire VGA_VS, input wire[3:0] SW, // 0 = ROM selection, 1 = enable/disable interrupts, 2 = turbo speed output wire[31:0] GPIO_1, // Exports CPU chip pins, output wire buzzer_out, input wire raw_loader_in, output wire[1:0] DRAM_BA, output wire[1:0] DRAM_DQM, output wire DRAM_RAS_N, output wire DRAM_CAS_N, output wire DRAM_CKE, output wire DRAM_CLK, output wire DRAM_WE_N, output wire DRAM_CS_N, inout wire[15:0] DRAM_DQ, output wire[12:0] DRAM_ADDR, // output wire[2:0] GPIO_0, //-------- Atari joystick mapped as Kempston input wire [4:0] kempston, // Input with weak pull-up output wire kempston_gnd, // Helps mapping to DB9 cable input wire turbo_button, input wire kempston_autofire_button ); `default_nettype none wire reset; wire locked; assign reset = locked & KEY[0:0]; reg turbo = 0; wire turbo_button_debounced; debouncer debounce_turbo( .i_Clk(CLOCK_50), .i_Switch(turbo_button), .o_Switch(turbo_button_debounced) ); always @(negedge turbo_button_debounced) begin turbo = !turbo; end reg kempston_autofire_enabled = 0; wire kempston_autofire_button_debounced; debouncer debounce_autofire( .i_Clk(CLOCK_50), .i_Switch(kempston_autofire_button), .o_Switch(kempston_autofire_button_debounced) ); always @(negedge kempston_autofire_button_debounced) begin kempston_autofire_enabled = !kempston_autofire_enabled; end // 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}; assign kempston_gnd = 0; // enable kempston assign LED[7] = !kempston[4] & kempston_auto_fire; assign LED[6] = !kempston[3]; assign LED[5] = !kempston[2]; assign LED[4] = !kempston[1]; assign LED[3] = !kempston[0]; //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // 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'b1 && 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) wire is_io_read_requested; wire is_io_write_requested; wire is_mem_read_requested; wire is_mem_write_requested; wire is_rom_address; wire is_upper_ram_address; assign is_rom_address = A[15:14] == 2'b00; assign is_upper_ram_address = A[15] == 1'b1; assign is_io_read_requested = {nIORQ,nRD,nWR} == 3'b001 ? 1'b1 : 1'b0; assign is_io_write_requested = {nIORQ,nRD,nWR} == 3'b010 ? 1'b1 : 1'b0; assign is_mem_read_requested = {nIORQ,nRD,nWR} == 3'b101 ? 1'b1 : 1'b0; assign is_mem_write_requested = {nIORQ,nRD,nWR} == 3'b110 ? 1'b1 : 1'b0; // assign D = sdram_out_valid ? sdram_out_data[7:0] : 8b'zzzzzzzz; //assign D = is_io_read_requested ? ula_data : (is_mem_read_requested ? (A[15:14] == 2'b00 ? rom_data : (sdram_out_valid ? sdram_out_data : {8{1'bz}})) : {8{1'bz}}); reg kempston_auto_fire = 0; reg kempston_last_fire_state = 0; reg[17:0] kempston_auto_fire_counter = 0; always @(posedge clk_cpu) begin if (kempston_autofire_enabled == 0) kempston_auto_fire <= 1; else begin kempston_auto_fire_counter <= kempston_auto_fire_counter + 1; if (kempston_auto_fire_counter == 0) kempston_auto_fire <= !kempston_auto_fire; end end 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_auto_fire,!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_vram), .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(CLOCK_50), // .clock_a(clk_cpu), .address_a(A[13:0]), .data_a(D), .q_a(ram0_data), .wren_a(RamWE), // .clock_b(clk_vram), .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_vram), .address(A[14:0]), .data(D), .q(ram1_data), .wren(ExtRamWE) ); // // SDRAM for 128K // wire[23:0] sdram_address; wire[31:0] sdram_out_data; wire[31:0] sdram_in_data; wire sdram_read_request; wire sdram_write_request; wire sdram_out_valid; assign sdram_write_request = is_upper_ram_address && is_mem_write_requested; assign sdram_read_request = is_upper_ram_address && is_mem_read_requested; assign sdram_in_data = {24'd0, D[7:0]}; assign sdram_address = {8'd0, A[15:0]}; sdram_controller sdram_( .CLOCK_50(CLOCK_50), .DRAM_ADDR(DRAM_ADDR), .DRAM_BA(DRAM_BA), .DRAM_CAS_N(DRAM_CAS_N), .DRAM_CKE(DRAM_CKE), .DRAM_CLK(DRAM_CLK), .DRAM_CS_N(DRAM_CS_N), .DRAM_DQ(DRAM_DQ), .DRAM_DQM(DRAM_DQM), .DRAM_RAS_N(DRAM_RAS_N), .DRAM_WE_N(DRAM_WE_N), .address(sdram_address), .req_read(sdram_read_request), .req_write(ExtRamWE), .data_out(sdram_out_data), .data_out_valid(sdram_out_valid), .data_in(sdram_in_data) ); //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // Instantiate ULA //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ wire clk_cpu; // Global CPU clock of 3.5 MHz assign LED[2] = turbo; // Glow red when in turbo mode (7.0 MHz) assign LED[1] = raw_loader_in; // feedback from audio in 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 (turbo), // 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 (e 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), .beep(buzzer_out), .raw_loader_in(raw_loader_in), //-------- 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 SW1; assign SW1 = SW[1:1]; wire KEY1; assign KEY1 = KEY[1:1]; wire nWAIT = 1; wire nINT = (SW1==0)? vs_nintr : 1'b1; // SW1 disables interrupts and, hence, keyboard assign LED[0] = SW1; // Glow red when interrupts are *disabled* wire nNMI = KEY1; // 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) ); endmodule