Files
de0-zx-spectrum/spectrum.sv
T

368 lines
11 KiB
Systemverilog
Raw Normal View History

2022-03-31 14:13:34 +03:00
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,
2022-04-02 14:56:02 +03:00
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
2022-04-02 14:56:02 +03:00
2022-03-31 14:13:34 +03:00
);
`default_nettype none
wire reset;
2022-03-31 14:13:34 +03:00
wire locked;
assign reset = locked & KEY[0:0];
2022-03-31 14:13:34 +03:00
reg turbo = 0;
wire turbo_button_debounced;
debouncer debounce_turbo(
.i_Clk(CLOCK_50),
.i_Switch(turbo_button),
.o_Switch(turbo_button_debounced)
2022-03-31 14:13:34 +03:00
);
always @(negedge turbo_button_debounced)
begin
turbo = !turbo;
end
2022-03-31 14:13:34 +03:00
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
2022-03-31 14:13:34 +03:00
// 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];
2022-03-31 14:13:34 +03:00
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// 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;
2022-03-31 14:13:34 +03:00
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
2022-03-31 14:13:34 +03:00
always @(*) // always_comb
begin
case ({nIORQ,nRD,nWR})
// --------------------------------
// Memory read --------------------------------
2022-03-31 14:13:34 +03:00
3'b101: begin
casez (A[15:14])
2'b00: D[7:0] = rom_data;
2'b01: D[7:0] = ram0_data;
2022-03-31 14:13:34 +03:00
2'b1?: D[7:0] = ram1_data;
endcase
2022-03-31 14:13:34 +03:00
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] };
2022-03-31 14:13:34 +03:00
end
end
default:
D[7:0] = {8{1'bz}};
endcase
end
// ----------------------------------------------------
// Instantiate ROM, 16K
// ----------------------------------------------------
wire[7:0] rom_data;
rom0 rom(
2022-04-02 15:57:16 +03:00
.clock(clk_vram),
2022-03-31 14:13:34 +03:00
.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),
2022-03-31 14:13:34 +03:00
.address_a(A[13:0]),
.data_a(D),
.q_a(ram0_data),
.wren_a(RamWE),
// .clock_b(clk_vram),
2022-03-31 14:13:34 +03:00
.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),
2022-03-31 14:13:34 +03:00
.address(A[14:0]),
.data(D),
.q(ram1_data),
.wren(ExtRamWE)
);
2022-04-02 14:56:02 +03:00
//
// SDRAM for 128K
//
wire[23:0] sdram_address;
2022-04-02 14:56:02 +03:00
wire[31:0] sdram_out_data;
wire[31:0] sdram_in_data;
2022-04-02 14:56:02 +03:00
wire sdram_read_request;
wire sdram_write_request;
wire sdram_out_valid;
2022-04-02 14:56:02 +03:00
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]};
2022-04-02 14:56:02 +03:00
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),
2022-04-02 14:56:02 +03:00
.req_read(sdram_read_request),
.req_write(ExtRamWE),
2022-04-02 14:56:02 +03:00
.data_out(sdram_out_data),
.data_out_valid(sdram_out_valid),
.data_in(sdram_in_data)
2022-04-02 14:56:02 +03:00
);
2022-04-02 14:56:02 +03:00
2022-03-31 14:13:34 +03:00
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// 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
2022-03-31 14:13:34 +03:00
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)
2022-03-31 14:13:34 +03:00
.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) --------------
2022-03-31 14:13:34 +03:00
.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),
2022-03-31 14:13:34 +03:00
//-------- VGA connector --------------------
.VGA_R (VGA_R),
.VGA_G (VGA_G),
.VGA_B (VGA_B),
.VGA_HS (VGA_HS),
.VGA_VS (VGA_VS)
2022-03-31 14:13:34 +03:00
);
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// 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