zxuno-git/cores/Spectrum/zxuno.v

618 lines
18 KiB
Verilog

`timescale 1ns / 1ps
`default_nettype none
//////////////////////////////////////////////////////////////////////////////////
// Company:
// Engineer:
//
// Create Date: 14:16:16 02/06/2014
// Design Name:
// Module Name: zxuno
// Project Name:
// Target Devices:
// Tool versions:
// Description:
//
// Dependencies:
//
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
//
//////////////////////////////////////////////////////////////////////////////////
module zxuno (
// Relojes
input wire clk28,
input wire clk14,
input wire clk7,
input wire clk3d5,
input wire cpuclkplain, // reloj seleccionado para la CPU, antes de aplicar contención
input wire cpuclk, // reloj seleccionado par ala CPU, después de aplicar contención
output wire CPUContention, // Señal de contención del reloj de la CPU
input wire power_on_reset_n,
// E/S
output wire [2:0] r,
output wire [2:0] g,
output wire [2:0] b,
output wire hsync,
output wire vsync,
output wire csync,
inout wire clkps2,
inout wire dataps2,
input wire ear,
output wire audio_out,
// SRAM
output wire [18:0] sram_addr,
inout wire [7:0] sram_data,
output wire sram_we_n,
// Flash SPI
output wire flash_cs_n,
output wire flash_clk,
output wire flash_di,
input wire flash_do,
// SD/MMC
output wire sd_cs_n,
output wire sd_clk,
output wire sd_mosi,
input wire sd_miso,
// DB9 JOYSTICK
input wire joyup,
input wire joydown,
input wire joyleft,
input wire joyright,
input wire joyfire,
// MOUSE
inout wire mouseclk,
inout wire mousedata,
// SCANDOUBLER CTRL
output wire vga_enable,
output wire scanlines_enable,
output wire [2:0] freq_option,
output wire [1:0] turbo_enable
);
// Señales de la CPU
wire mreq_n,iorq_n,rd_n,wr_n,int_n,m1_n,nmi_n,rfsh_n,wait_n;
wire enable_nmi_n;
wire [15:0] cpuaddr;
reg [7:0] cpudin;
wire [7:0] cpudout;
wire [7:0] ula_dout;
// Señales acceso RAM por parte de la ULA
wire [13:0] vram_addr;
wire [7:0] vram_dout;
// Señales acceso RAM por parte de la CPU
wire [7:0] memory_dout;
wire oe_n_romyram;
// Señales de acceso del AY por parte de la CPU
wire [7:0] ay_dout;
wire bc1,bdir;
wire oe_n_ay;
// Señales de acceso a registro de direcciones ZX-Uno
wire [7:0] zxuno_addr_to_cpu; // al bus de datos de entrada del Z80
wire [7:0] zxuno_addr; // direccion de registro actual
wire regaddr_changed; // indica que se ha escrito un nuevo valor en el registro de direcciones
wire oe_n_zxunoaddr; // el dato en el bus de entrada del Z80 es válido
wire zxuno_regrd; // Acceso de lectura en el puerto de datos de ZX-Uno
wire zxuno_regwr; // Acceso de escritura en el puerto de datos del ZX-Uno
wire in_boot_mode; // Vae 1 cuando el sistema está en modo boot (ejecutando la BIOS)
// Señales de acceso al módulo Flash SPI
wire [7:0] spi_dout;
wire oe_n_spi;
// Fuentes de sonido
wire mic;
wire spk;
wire [7:0] ay1_audio;
wire [7:0] ay2_audio;
// Interfaz de acceso al teclado
wire [4:0] kbdcol;
wire [7:0] kbdrow = cpuaddr[15:8]; // las filas del teclado son A8-A15 de la CPU;
wire mrst_n,rst_n; // los dos resets suministrados por el teclado
wire [7:0] scancode_dout; // scancode original desde el teclado PC
wire oe_n_scancode;
wire [7:0] keymap_dout;
wire oe_n_keymap;
wire [7:0] kbstatus_dout;
wire oe_n_kbstatus;
wire [4:0] user_toggles;
wire video_output_change; // señal que da la tecla Scroll Lock para cambiar de modo de video
// Interfaz joystick configurable
wire oe_n_joystick;
wire [4:0] kbd_joy;
wire [7:0] joystick_dout;
wire [4:0] kbdcol_to_ula;
// Configuración ULA
wire [1:0] timing_mode;
wire issue2_keyboard;
wire disable_contention;
wire access_to_screen;
wire doc_ext_option; // bit 7 del puerto $FF del Timex
wire ioreqbank;
// CoreID
wire oe_n_coreid;
wire [7:0] coreid_dout;
// Scratch register
wire oe_n_scratch;
wire [7:0] scratch_dout;
// Scandoubler control
wire csync_option;
wire [7:0] scndblctrl_dout;
wire oe_n_scndblctrl;
// Raster INT control
wire rasterint_enable;
wire vretraceint_disable;
wire [8:0] raster_line;
wire raster_int_in_progress;
wire [7:0] rasterint_dout;
wire oe_n_rasterint;
// Device enable options
wire disable_ay;
wire disable_turboay;
wire disable_7ffd;
wire disable_1ffd;
wire disable_romsel7f;
wire disable_romsel1f;
wire enable_timexmmu;
wire disable_spisd;
wire disable_timexscr;
wire disable_ulaplus;
wire disable_radas;
wire [7:0] devoptions_dout;
wire oe_n_devoptions;
// NMI events
wire [7:0] nmievents_dout;
wire oe_n_nmievents;
wire nmispecial_n;
wire page_configrom_active;
// Kempston mouse
wire [7:0] kmouse_dout;
wire [7:0] mousedata_dout;
wire [7:0] mousestatus_dout;
wire oe_n_kmouse, oe_n_mousedata, oe_n_mousestatus;
// Asignación de dato para la CPU segun la decodificación de todos los dispositivos
// conectados a ella.
always @* begin
case (1'b0)
oe_n_ay : cpudin = ay_dout;
oe_n_joystick : cpudin = joystick_dout;
oe_n_zxunoaddr : cpudin = zxuno_addr_to_cpu;
oe_n_spi : cpudin = spi_dout;
oe_n_scancode : cpudin = scancode_dout;
oe_n_kbstatus : cpudin = kbstatus_dout;
oe_n_coreid : cpudin = coreid_dout;
oe_n_keymap : cpudin = keymap_dout;
oe_n_scratch : cpudin = scratch_dout;
oe_n_scndblctrl : cpudin = scndblctrl_dout;
oe_n_nmievents : cpudin = nmievents_dout;
oe_n_kmouse : cpudin = kmouse_dout;
oe_n_mousedata : cpudin = mousedata_dout;
oe_n_mousestatus : cpudin = mousestatus_dout;
oe_n_rasterint : cpudin = rasterint_dout;
oe_n_devoptions : cpudin = devoptions_dout;
oe_n_romyram : cpudin = memory_dout;
default : cpudin = ula_dout;
endcase
end
tv80n_wrapper el_z80 (
.m1_n(m1_n),
.mreq_n(mreq_n),
.iorq_n(iorq_n),
.rd_n(rd_n),
.wr_n(wr_n),
.rfsh_n(rfsh_n),
.halt_n(),
.busak_n(),
.A(cpuaddr),
.dout(cpudout),
.reset_n(rst_n & mrst_n & power_on_reset_n), // cualquiera de los dos resets
.clk(cpuclk),
.wait_n(wait_n),
.int_n(int_n),
.nmi_n((nmi_n | enable_nmi_n) & nmispecial_n),
.busrq_n(1'b1),
.di(cpudin)
);
ula_radas la_ula (
// Clocks
.clk28(clk28),
.clkregs(cpuclkplain),
.clk14(clk14), // 14MHz master clock
.clk7(clk7),
.cpuclk(cpuclk),
.CPUContention(CPUContention),
.rst_n(mrst_n & rst_n & power_on_reset_n),
// CPU interface
.a(cpuaddr),
.access_to_contmem(access_to_screen),
.mreq_n(mreq_n),
.iorq_n(iorq_n),
.rd_n(rd_n),
.wr_n(wr_n),
.int_n(int_n),
.din(cpudout),
.dout(ula_dout),
.rasterint_enable(rasterint_enable),
.vretraceint_disable(vretraceint_disable),
.raster_line(raster_line),
.raster_int_in_progress(raster_int_in_progress),
// VRAM interface
.va(vram_addr), // 16KB videoram, 2 pages
.vramdata(vram_dout),
// ZX-UNO register interface
.zxuno_addr(zxuno_addr),
.zxuno_regrd(zxuno_regrd),
.zxuno_regwr(zxuno_regwr),
.regaddr_changed(regaddr_changed),
// I/O ports
.ear(ear),
.mic(mic),
.spk(spk),
.kbd(kbdcol_to_ula),
.issue2_keyboard(issue2_keyboard),
.mode(timing_mode),
.ioreqbank(ioreqbank),
.disable_contention(disable_contention),
.doc_ext_option(doc_ext_option),
.enable_timexmmu(enable_timexmmu),
.disable_timexscr(disable_timexscr),
.disable_ulaplus(disable_ulaplus),
.disable_radas(disable_radas),
.csync_option(csync_option),
// Video
.r(r),
.g(g),
.b(b),
.hsync(hsync),
.vsync(vsync),
.csync(csync)
);
zxunoregs addr_reg_zxuno (
.clk(cpuclkplain),
.rst_n(rst_n & mrst_n & power_on_reset_n),
.a(cpuaddr),
.iorq_n(iorq_n),
.rd_n(rd_n),
.wr_n(wr_n),
.din(cpudout),
.dout(zxuno_addr_to_cpu),
.oe_n(oe_n_zxunoaddr),
.addr(zxuno_addr),
.read_from_reg(zxuno_regrd),
.write_to_reg(zxuno_regwr),
.regaddr_changed(regaddr_changed)
);
flash_and_sd cacharros_con_spi (
.clk(clk14),
.a(cpuaddr),
.iorq_n(iorq_n),
.rd_n(rd_n),
.wr_n(wr_n),
.addr(zxuno_addr),
.ior(zxuno_regrd),
.iow(zxuno_regwr),
.din(cpudout),
.dout(spi_dout),
.oe_n(oe_n_spi),
.wait_n(wait_n),
.in_boot_mode(in_boot_mode),
.flash_cs_n(flash_cs_n),
.flash_clk(flash_clk),
.flash_di(flash_di),
.flash_do(flash_do),
.disable_spisd(disable_spisd),
.sd_cs_n(sd_cs_n),
.sd_clk(sd_clk),
.sd_mosi(sd_mosi),
.sd_miso(sd_miso)
);
new_memory bootrom_rom_y_ram (
// Relojes y reset
.clk(cpuclkplain), // Reloj para registros de configuración
.mclk(clk28), // Reloj para el modulo de memoria de doble puerto
.mrst_n(mrst_n & power_on_reset_n),
.rst_n(rst_n & power_on_reset_n),
// Interface con la CPU
.a(cpuaddr),
.din(cpudout), // proveniente del bus de datos de salida de la CPU
.dout(memory_dout), // hacia el bus de datos de entrada de la CPU
.oe_n(oe_n_romyram), // el dato es valido
.mreq_n(mreq_n),
.iorq_n(iorq_n),
.rd_n(rd_n),
.wr_n(wr_n),
.m1_n(m1_n), // Necesarios para implementar DIVMMC
.rfsh_n(rfsh_n),
.enable_nmi_n(enable_nmi_n),
.page_configrom_active(page_configrom_active), // Para habilitar la ROM de ayuda y configuración
// Interface con la ULA
.vramaddr(vram_addr),
.vramdout(vram_dout),
.doc_ext_option(doc_ext_option),
.issue2_keyboard_enabled(issue2_keyboard),
.timing_mode(timing_mode),
.disable_contention(disable_contention),
.access_to_screen(access_to_screen),
.ioreqbank(ioreqbank),
// Interface con el bus externo (TO-DO)
.inhibit_rom(1'b0),
.din_external(8'h00),
// Interface para registros ZXUNO
.addr(zxuno_addr),
.ior(zxuno_regrd),
.iow(zxuno_regwr),
.in_boot_mode(in_boot_mode),
// Interface con modulo de habilitacion de opciones
.disable_7ffd(disable_7ffd),
.disable_1ffd(disable_1ffd),
.disable_romsel7f(disable_romsel7f),
.disable_romsel1f(disable_romsel1f),
.enable_timexmmu(enable_timexmmu),
// Interface con la SRAM
.sram_addr(sram_addr),
.sram_data(sram_data),
.sram_we_n(sram_we_n)
);
ps2_keyb el_teclado (
.clk(clk28),
.clkps2(clkps2),
.dataps2(dataps2),
.rows(kbdrow),
.cols(kbdcol),
.joy(kbd_joy), // Implementación joystick kempston en teclado numerico
.rst_out_n(rst_n), // esto son salidas, no entradas
.nmi_out_n(nmi_n), // Señales de reset y NMI
.mrst_out_n(mrst_n), // generadas por pulsaciones especiales del teclado
.user_toggles(user_toggles), // funciones de usuario
.video_output_change(video_output_change),
//----------------------------
.zxuno_addr(zxuno_addr),
.zxuno_regrd(zxuno_regrd),
.zxuno_regwr(zxuno_regwr),
.regaddr_changed(regaddr_changed),
.din(cpudout),
.keymap_dout(keymap_dout),
.oe_n_keymap(oe_n_keymap),
.scancode_dout(scancode_dout),
.oe_n_scancode(oe_n_scancode),
.kbstatus_dout(kbstatus_dout),
.oe_n_kbstatus(oe_n_kbstatus)
);
joystick_protocols los_joysticks (
.clk(cpuclkplain),
//-- cpu interface
.a(cpuaddr),
.iorq_n(iorq_n),
.rd_n(rd_n),
.din(cpudout),
.dout(joystick_dout),
.oe_n(oe_n_joystick),
//-- interface with ZXUNO reg bank
.zxuno_addr(zxuno_addr),
.zxuno_regrd(zxuno_regrd),
.zxuno_regwr(zxuno_regwr),
//-- actual joystick and keyboard signals
.kbdjoy_in(kbd_joy),
.db9joy_in({joyfire, joyup, joydown, joyleft, joyright}),
.kbdcol_in(kbdcol),
.kbdcol_out(kbdcol_to_ula),
.vertical_retrace_int_n(int_n) // this is used as base clock for autofire
);
coreid identificacion_del_core (
.clk(cpuclkplain),
.rst_n(rst_n & mrst_n & power_on_reset_n),
.zxuno_addr(zxuno_addr),
.zxuno_regrd(zxuno_regrd),
.regaddr_changed(regaddr_changed),
.dout(coreid_dout),
.oe_n(oe_n_coreid)
);
scratch_register scratch (
.clk(cpuclkplain),
.poweron_rst_n(power_on_reset_n),
.zxuno_addr(zxuno_addr),
.zxuno_regrd(zxuno_regrd),
.zxuno_regwr(zxuno_regwr),
.din(cpudout),
.dout(scratch_dout),
.oe_n(oe_n_scratch)
);
control_enable_options device_enables (
.clk(cpuclkplain),
.rst_n(mrst_n & power_on_reset_n),
.zxuno_addr(zxuno_addr),
.zxuno_regrd(zxuno_regrd),
.zxuno_regwr(zxuno_regwr),
.din(cpudout),
.dout(devoptions_dout),
.oe_n(oe_n_devoptions),
.disable_ay(disable_ay),
.disable_turboay(disable_turboay),
.disable_7ffd(disable_7ffd),
.disable_1ffd(disable_1ffd),
.disable_romsel7f(disable_romsel7f),
.disable_romsel1f(disable_romsel1f),
.enable_timexmmu(enable_timexmmu),
.disable_spisd(disable_spisd),
.disable_timexscr(disable_timexscr),
.disable_ulaplus(disable_ulaplus),
.disable_radas(disable_radas)
);
scandoubler_ctrl control_scandoubler (
.clk(clk28),
.a(cpuaddr),
.kbd_change_video_output(video_output_change),
.iorq_n(iorq_n),
.wr_n(wr_n),
.zxuno_addr(zxuno_addr),
.zxuno_regrd(zxuno_regrd),
.zxuno_regwr(zxuno_regwr),
.din(cpudout),
.dout(scndblctrl_dout),
.oe_n(oe_n_scndblctrl),
.vga_enable(vga_enable),
.scanlines_enable(scanlines_enable),
.freq_option(freq_option),
.turbo_enable(turbo_enable),
.csync_option(csync_option)
);
rasterint_ctrl control_rasterint (
.clk(cpuclkplain),
.rst_n(rst_n & mrst_n & power_on_reset_n),
.zxuno_addr(zxuno_addr),
.zxuno_regrd(zxuno_regrd),
.zxuno_regwr(zxuno_regwr),
.din(cpudout),
.dout(rasterint_dout),
.oe_n(oe_n_rasterint),
.rasterint_enable(rasterint_enable),
.vretraceint_disable(vretraceint_disable),
.raster_line(raster_line),
.raster_int_in_progress(raster_int_in_progress)
);
nmievents nmi_especial_de_antonio (
.clk(cpuclkplain),
.rst_n(rst_n & mrst_n & power_on_reset_n),
//------------------------------
.zxuno_addr(zxuno_addr),
.zxuno_regrd(zxuno_regrd),
//------------------------------
.userevents(user_toggles),
//------------------------------
.a(cpuaddr),
.m1_n(m1_n),
.mreq_n(mreq_n),
.rd_n(rd_n),
.dout(nmievents_dout),
.oe_n(oe_n_nmievents),
.nmiout_n(nmispecial_n),
.page_configrom_active(page_configrom_active)
);
ps2_mouse_kempston el_raton (
.clk(clk28),
.rst_n(rst_n & mrst_n & power_on_reset_n),
.clkps2(mouseclk),
.dataps2(mousedata),
//---------------------------------
.a(cpuaddr),
.iorq_n(iorq_n),
.rd_n(rd_n),
.kmouse_dout(kmouse_dout),
.oe_n_kmouse(oe_n_kmouse),
//---------------------------------
.zxuno_addr(zxuno_addr),
.zxuno_regrd(zxuno_regrd),
.zxuno_regwr(zxuno_regwr),
.din(cpudout),
.mousedata_dout(mousedata_dout),
.oe_n_mousedata(oe_n_mousedata),
.mousestatus_dout(mousestatus_dout),
.oe_n_mousestatus(oe_n_mousestatus)
);
multiboot el_multiboot (
.clk(cpuclkplain),
.clk_icap(clk14),
.rst_n(rst_n & mrst_n & power_on_reset_n),
.zxuno_addr(zxuno_addr),
.zxuno_regwr(zxuno_regwr),
.din(cpudout)
);
///////////////////////////////////
// AY-3-8912 SOUND
///////////////////////////////////
// BDIR BC2 BC1 MODE
// 0 1 0 inactive
// 0 1 1 read
// 1 1 0 write
// 1 1 1 address
assign bdir = (cpuaddr[15] && cpuaddr[1:0]==2'b01 && !iorq_n && !wr_n)? 1'b1 : 1'b0;
assign bc1 = (cpuaddr[15] && cpuaddr[1:0]==2'b01 && cpuaddr[14] && !iorq_n)? 1'b1 : 1'b0;
turbosound dos_ays (
.clk(cpuclkplain),
.clkay(clk3d5),
.disable_ay(disable_ay),
.disable_turboay(disable_turboay),
.reset_n(rst_n & mrst_n & power_on_reset_n),
.bdir(bdir),
.bc1(bc1),
.din(cpudout),
.dout(ay_dout),
.oe_n(oe_n_ay),
.audio_out_ay1(ay1_audio),
.audio_out_ay2(ay2_audio)
);
///////////////////////////////////
// SOUND MIXER
///////////////////////////////////
// 8-bit mixer to generate different audio levels according to input sources
mixer audio_mix(
.clkdac(clk28),
.reset(1'b0),
// Audio sources to mix
.mic(mic),
.spk(spk),
.ear(ear),
.ay1(ay1_audio),
.ay2(ay2_audio),
// PWM output mixed (monoaural ATM)
.audio(audio_out)
);
endmodule