270 lines
7.9 KiB
Systemverilog
270 lines
7.9 KiB
Systemverilog
|
|
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[33:0] GPIO_1, // Exports CPU chip pins,
|
||
|
|
output wire buzzer_out
|
||
|
|
);
|
||
|
|
`default_nettype none
|
||
|
|
|
||
|
|
/*
|
||
|
|
assign GPIO_1[0] = VGA_VS;
|
||
|
|
assign GPIO_1[1] = VGA_HS;
|
||
|
|
assign GPIO_1[2] = VGA_B[0];
|
||
|
|
assign GPIO_1[3] = vs_nintr;
|
||
|
|
|
||
|
|
wire clk_pix; // VGA pixel clock (25.175 MHz)
|
||
|
|
wire locked;
|
||
|
|
wire clk_vram;
|
||
|
|
|
||
|
|
pll_video pll_(
|
||
|
|
.locked(locked),
|
||
|
|
.inclk0(CLOCK_50),
|
||
|
|
.c0(clk_pix)
|
||
|
|
);
|
||
|
|
|
||
|
|
|
||
|
|
reg [12:0] vram_address;
|
||
|
|
reg [7:0] vram_data;
|
||
|
|
rom_scr rom_(
|
||
|
|
.clock(CLOCK_50),
|
||
|
|
.address(vram_address),
|
||
|
|
.q(vram_data)
|
||
|
|
// .q(8'b10111000)
|
||
|
|
);
|
||
|
|
|
||
|
|
wire [2:0] border; // Border color index value
|
||
|
|
assign border = SW[2:0];
|
||
|
|
|
||
|
|
wire vs_nintr; // Vertical retrace interrupt
|
||
|
|
video video_( .*, .vram_address(vram_address), .vram_data(vram_data) );
|
||
|
|
//video video_( .*, .vram_address(vram_address), .vram_data(8'b10111000) );
|
||
|
|
*/
|
||
|
|
|
||
|
|
|
||
|
|
|
||
|
|
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(CLOCK_50),
|
||
|
|
.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),
|
||
|
|
|
||
|
|
.address_a(A[13:0]),
|
||
|
|
.data_a(D),
|
||
|
|
.q_a(ram0_data),
|
||
|
|
.wren_a(RamWE),
|
||
|
|
// .wren_a(0),
|
||
|
|
|
||
|
|
.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(ExtRamWE)
|
||
|
|
);
|
||
|
|
|
||
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||
|
|
// 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),
|
||
|
|
.beep(buzzer_out),
|
||
|
|
|
||
|
|
//-------- 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
|