mirror of https://github.com/zxdos/zxuno.git
584 lines
23 KiB
Verilog
584 lines
23 KiB
Verilog
`timescale 1ns / 1ps
|
||
`default_nettype none
|
||
|
||
// This file is part of the ZXUNO Spectrum core.
|
||
// Creation date is 16:40:14 2016-05-04 by Miguel Angel Rodriguez Jodar
|
||
// (c)2014-2020 ZXUNO association.
|
||
// ZXUNO official repository: http://svn.zxuno.com/svn/zxuno
|
||
// Username: guest Password: zxuno
|
||
// Github repository for this core: https://github.com/mcleod-ideafix/zxuno_spectrum_core
|
||
//
|
||
// ZXUNO Spectrum core is free software: you can redistribute it and/or modify
|
||
// it under the terms of the GNU General Public License as published by
|
||
// the Free Software Foundation, either version 3 of the License, or
|
||
// (at your option) any later version.
|
||
//
|
||
// ZXUNO Spectrum core is distributed in the hope that it will be useful,
|
||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||
// GNU General Public License for more details.
|
||
//
|
||
// You should have received a copy of the GNU General Public License
|
||
// along with the ZXUNO Spectrum core. If not, see <https://www.gnu.org/licenses/>.
|
||
//
|
||
// Any distributed copy of this file must keep this notice intact.
|
||
|
||
module new_memory (
|
||
// Relojes y reset
|
||
input wire clk, // Reloj de la CPU
|
||
input wire mrst_n,
|
||
input wire rst_n,
|
||
|
||
// Interface con la CPU
|
||
input wire [15:0] a,
|
||
input wire [7:0] din, // proveniente del bus de datos de salida de la CPU
|
||
output reg [7:0] dout, // hacia el bus de datos de entrada de la CPU
|
||
output reg oe, // el dato es valido
|
||
input wire mreq_n,
|
||
input wire iorq_n,
|
||
input wire rd_n,
|
||
input wire wr_n,
|
||
input wire m1_n,
|
||
input wire rfsh_n,
|
||
input wire busak_n,
|
||
output wire enable_nmi_n,
|
||
input wire page_configrom_active,
|
||
|
||
// Interface con la ULA
|
||
input wire [13:0] vramaddr,
|
||
output wire [7:0] vramdout,
|
||
input wire doc_ext_option,
|
||
output wire issue2_keyboard_enabled,
|
||
output reg [1:0] timing_mode,
|
||
output wire disable_contention,
|
||
output reg access_to_screen,
|
||
output reg ioreqbank,
|
||
|
||
// Interface con el bus externo
|
||
input wire inhibit_rom,
|
||
input wire [7:0] din_external,
|
||
|
||
// Interface para registros ZXUNO
|
||
input wire [7:0] addr,
|
||
input wire ior,
|
||
input wire iow,
|
||
output wire in_boot_mode,
|
||
|
||
// Interface con modulo de habilitacion de opciones
|
||
input wire disable_7ffd,
|
||
input wire disable_1ffd,
|
||
input wire disable_romsel7f,
|
||
input wire disable_romsel1f,
|
||
input wire enable_timexmmu,
|
||
|
||
// Interface con el m<>dulo lector PZX
|
||
input wire [20:0] pzx_addr,
|
||
output wire enable_pzx,
|
||
output wire in48kmode,
|
||
input wire [7:0] data_from_pzx,
|
||
output wire [7:0] data_to_pzx,
|
||
input wire write_data_pzx,
|
||
|
||
// Interface con la SRAM
|
||
output wire [20:0] sram_addr,
|
||
inout wire [7:0] sram_data,
|
||
output wire sram_we_n
|
||
);
|
||
|
||
`include "config.vh"
|
||
|
||
reg initial_boot_mode = 1'b1;
|
||
reg divmmc_is_enabled = 1'b0;
|
||
reg divmmc_nmi_is_disabled = 1'b0;
|
||
reg issue2_keyboard = 1'b0;
|
||
initial timing_mode = 2'b01;
|
||
reg disable_cont = 1'b0;
|
||
reg masterconf_frozen = 1'b0;
|
||
reg [1:0] negedge_configrom = 2'b00;
|
||
reg rom48k_selected = 1'b1; // forced to 1 so Derby++ can work, as it maps 48K ROM into ROM 1, not ROM 3.
|
||
|
||
assign issue2_keyboard_enabled = issue2_keyboard;
|
||
assign in_boot_mode = ~masterconf_frozen;
|
||
assign disable_contention = disable_cont;
|
||
|
||
always @(posedge clk) begin
|
||
negedge_configrom <= {negedge_configrom[0], page_configrom_active};
|
||
if (!mrst_n) begin
|
||
{timing_mode[1],disable_cont,timing_mode[0],issue2_keyboard,divmmc_nmi_is_disabled,divmmc_is_enabled,initial_boot_mode} <= 7'b0000001;
|
||
masterconf_frozen <= 1'b0;
|
||
end
|
||
else if (page_configrom_active == 1'b1) begin
|
||
masterconf_frozen <= 1'b0;
|
||
initial_boot_mode <= 1'b1;
|
||
end
|
||
else if (negedge_configrom == 2'b10) begin
|
||
masterconf_frozen <= 1'b1;
|
||
initial_boot_mode <= 1'b0;
|
||
end
|
||
else if (addr==MASTERCONF && iow) begin
|
||
{timing_mode[1],disable_cont,timing_mode[0],issue2_keyboard,divmmc_nmi_is_disabled,divmmc_is_enabled} <= din[6:1];
|
||
if (!masterconf_frozen) begin
|
||
masterconf_frozen <= din[7];
|
||
initial_boot_mode <= din[0];
|
||
end
|
||
end
|
||
end
|
||
|
||
reg [6:0] mastermapper = 7'h00;
|
||
always @(posedge clk) begin
|
||
if (!mrst_n)
|
||
mastermapper <= 7'h00;
|
||
else if (addr==MASTERMAPPER && iow && initial_boot_mode)
|
||
mastermapper <= din[6:0];
|
||
end
|
||
|
||
// DIVMMC control register
|
||
reg [7:0] divmmc_ctrl = 8'h00;
|
||
wire [5:0] divmmc_sram_page = divmmc_ctrl[5:0];
|
||
wire divmmc_sram_page_is_valid = (divmmc_sram_page[5:4] == 2'b00); // solo admito 128K de SRAM para DivMMC
|
||
wire mapram_mode = divmmc_ctrl[6];
|
||
wire conmem = divmmc_ctrl[7];
|
||
always @(posedge clk) begin
|
||
if (!mrst_n)
|
||
divmmc_ctrl <= 8'h00;
|
||
else if (!rst_n)
|
||
divmmc_ctrl <= {1'b0, mapram_mode, 6'b000000};
|
||
else if (a[7:0]==8'he3 && !iorq_n && !wr_n) begin
|
||
if (mapram_mode == 1'b0)
|
||
divmmc_ctrl <= din;
|
||
else
|
||
divmmc_ctrl <= {din[7], 1'b1, din[5:0]};
|
||
end
|
||
end
|
||
|
||
// DIVMMC automapper
|
||
reg divmmc_is_paged = 1'b0;
|
||
reg divmmc_status_after_m1 = 1'b0;
|
||
assign enable_nmi_n = divmmc_is_enabled & divmmc_is_paged & ~divmmc_nmi_is_disabled;
|
||
wire divmmc_rom_active = divmmc_is_enabled && (divmmc_is_paged || conmem);
|
||
|
||
always @(posedge clk) begin
|
||
if (!mrst_n || !rst_n) begin
|
||
divmmc_is_paged <= 1'b0;
|
||
divmmc_status_after_m1 <= 1'b0;
|
||
end
|
||
else begin
|
||
if (!mreq_n && !rd_n && !m1_n && (a==16'h0000 ||
|
||
a==16'h0008 && rom48k_selected ||
|
||
a==16'h0038 && rom48k_selected ||
|
||
(a==16'h0066 && rom48k_selected && divmmc_nmi_is_disabled==1'b0 && page_configrom_active==1'b0) ||
|
||
a==16'h04C6 && rom48k_selected ||
|
||
a==16'h0562 && rom48k_selected)) begin // automapper diferido (siguiente ciclo)
|
||
divmmc_status_after_m1 <= 1'b1;
|
||
end
|
||
else if (!mreq_n && !rd_n && !m1_n && a[15:8]==8'h3D && rom48k_selected) begin // automapper no diferido (ciclo actual)
|
||
divmmc_is_paged <= 1'b1;
|
||
divmmc_status_after_m1 <= 1'b1;
|
||
end
|
||
else if (!mreq_n && !rd_n && !m1_n && a[15:3]==13'b0001_1111_1111_1) begin // desconexi<78>n de automapper diferido
|
||
divmmc_status_after_m1 <= 1'b0;
|
||
end
|
||
end
|
||
if (m1_n==1'b1) begin // tras el ciclo M1, aqu<71> es cuando realmente se hace el mapping
|
||
divmmc_is_paged <= divmmc_status_after_m1;
|
||
end
|
||
end
|
||
|
||
wire ADDR_7FFD_PLUS2A = (!a[1] && a[15:14]==2'b01 && (!enable_timexmmu || a[7:0]!=8'hF4));
|
||
wire ADDR_7FFD_SP128 = (!a[1] && !a[15] && (!enable_timexmmu || a[7:0]!=8'hF4));
|
||
wire ADDR_1FFD = (!a[1] && a[15:12]==4'b0001 && (!enable_timexmmu || a[7:0]!=8'hF4));
|
||
wire ADDR_TIMEX_MMU = (a[7:0] == 8'hF4);
|
||
|
||
localparam PAGE0 = 3'b000,
|
||
PAGE1 = 3'b001,
|
||
PAGE2 = 3'b010,
|
||
PAGE3 = 3'b011,
|
||
PAGE4 = 3'b100,
|
||
PAGE5 = 3'b101,
|
||
PAGE6 = 3'b110,
|
||
PAGE7 = 3'b111;
|
||
|
||
// Standard 128K memory manager and Timex MMU manager
|
||
reg [7:0] bank128 = 8'h00;
|
||
reg [7:0] bankplus3 = 8'h00;
|
||
reg [7:0] timex_mmu = 8'h00;
|
||
wire puerto_bloqueado = bank128[5];
|
||
wire [2:0] banco_ram = bank128[2:0];
|
||
wire [1:0] banco_extendido_512k = bank128[7:6];
|
||
wire vrampage = bank128[3];
|
||
wire [1:0] banco_rom = {bankplus3[2] & (~disable_romsel1f), bank128[4] & (~disable_romsel7f)};
|
||
wire amstrad_allram_page_mode = bankplus3[0];
|
||
wire [1:0] plus3_memory_arrangement = bankplus3[2:1];
|
||
|
||
assign in48kmode = puerto_bloqueado | disable_7ffd;
|
||
|
||
always @(posedge clk) begin
|
||
if (!mrst_n || !rst_n) begin
|
||
bank128 <= 8'h00;
|
||
bankplus3 <= 8'h00;
|
||
timex_mmu <= 8'h00;
|
||
end
|
||
else begin
|
||
if (!disable_1ffd && !disable_7ffd) begin
|
||
if (!iorq_n && !wr_n && ADDR_1FFD && !puerto_bloqueado) begin
|
||
bankplus3[7:3] <= din[7:3];
|
||
bankplus3[1:0] <= din[1:0];
|
||
bankplus3[2] <= din[2];
|
||
end
|
||
else if (!iorq_n && !wr_n && ADDR_7FFD_PLUS2A && !puerto_bloqueado) begin
|
||
bank128[7:5] <= din[7:5];
|
||
bank128[3:0] <= din[3:0];
|
||
bank128[4] <= din[4];
|
||
end
|
||
end
|
||
else if (!disable_7ffd && disable_1ffd && !iorq_n && !wr_n && ADDR_7FFD_SP128 && !puerto_bloqueado) begin
|
||
bank128[7:5] <= din[7:5];
|
||
bank128[3:0] <= din[3:0];
|
||
bank128[4] <= din[4];
|
||
end
|
||
else if (enable_timexmmu && !iorq_n && !wr_n && ADDR_TIMEX_MMU)
|
||
timex_mmu <= din;
|
||
end
|
||
end
|
||
|
||
always @* begin
|
||
if (!disable_7ffd && disable_1ffd && !iorq_n && (!wr_n || !rd_n) && ADDR_7FFD_SP128)
|
||
ioreqbank = 1'b1;
|
||
else
|
||
ioreqbank = 1'b0;
|
||
end
|
||
|
||
reg [20:0] addr_port2;
|
||
reg oe_memory_n;
|
||
reg oe_bootrom_n;
|
||
reg we2_n;
|
||
reg ram_busy;
|
||
assign enable_pzx = ~ram_busy;
|
||
|
||
// always @* begin
|
||
// rom48k_selected = 1'b0;
|
||
// if (banco_rom == 2'b11 ||
|
||
// banco_rom == 2'b01 && disable_romsel1f == 1'b1 && disable_romsel7f == 1'b0 ||
|
||
// banco_rom == 2'b00 && disable_romsel1f == 1'b1 && disable_romsel7f == 1'b1)
|
||
// rom48k_selected = 1'b1;
|
||
// end
|
||
|
||
// Calculo de la direcci<63>n en la SRAM a la que se va a acceder
|
||
// y se<73>ales de acceso de lectura y escritura
|
||
|
||
always @* begin
|
||
oe_memory_n = mreq_n | rd_n;
|
||
we2_n = mreq_n | wr_n;
|
||
oe_bootrom_n = 1'b1;
|
||
addr_port2 = 21'h000000;
|
||
|
||
if (busak_n == 1'b1 && (rfsh_n == 1'b0 || iorq_n == 1'b0))
|
||
ram_busy = 1'b0;
|
||
else
|
||
ram_busy = 1'b1;
|
||
|
||
//------------------------------------------------------------------------------------------------------------------
|
||
if (!mreq_n && a[15:14]==2'b00) begin // la CPU quiere acceder al espacio de ROM, $0000-$3FFF
|
||
if (initial_boot_mode) begin // en el modo boot, s<>lo se accede a la ROM interna
|
||
oe_memory_n = 1'b1;
|
||
oe_bootrom_n = 1'b0;
|
||
we2_n = 1'b1;
|
||
ram_busy = 1'b0;
|
||
end
|
||
else begin // estamos en modo normal de ejecuci<63>n
|
||
// Lo que mas prioridad tiene es la linea externa ROMCS. Si esta activa, no se tiene en cuenta nada mas
|
||
if (inhibit_rom == 1'b0) begin
|
||
// DIVMMC tiene m<>s prioridad que la MMU del Timex, as<61> que se evalua primero.
|
||
if (divmmc_rom_active) begin // DivMMC ha entrado en modo automapper o est<73> mapeado a la fuerza
|
||
if (a[13]==1'b0) begin // Si estamos en los primeros 8K
|
||
if (mapram_mode == 1'b0 || conmem == 1'b1) begin
|
||
addr_port2 = {8'b00011000,a[12:0]};
|
||
we2_n = 1'b1; // en este modo, la ROM es intocable
|
||
end
|
||
else begin // mapram mode
|
||
addr_port2 = {8'b00100011,a[12:0]}; // pagina 3 de la SRAM del DIVMMC
|
||
we2_n = 1'b1;
|
||
end
|
||
end
|
||
else begin // Si estamos en los segundos 8K
|
||
if (mapram_mode == 1'b0 || conmem == 1'b1) begin
|
||
addr_port2 = {4'b0010,divmmc_sram_page[3:0],a[12:0]};
|
||
if (divmmc_sram_page_is_valid == 1'b0)
|
||
we2_n = 1'b1;
|
||
end
|
||
else begin // mapram mode
|
||
addr_port2 = {4'b0010,divmmc_sram_page[3:0],a[12:0]};
|
||
if (mapram_mode && divmmc_sram_page==6'b000011 || divmmc_sram_page_is_valid == 1'b0)
|
||
we2_n = 1'b1; // en este modo, la ROM es intocable
|
||
end
|
||
end
|
||
end
|
||
|
||
// DivMMC no est<73> activo, asi que comprobamos qu<71> p<>gina toca de HOME. Luego comprobamos si hay que paginar DOC
|
||
// o EXT y se hace un override a lo que haya definido en HOME
|
||
else begin
|
||
if (!amstrad_allram_page_mode) begin // en el modo normal de paginaci<63>n, hay 4 bancos de ROMs
|
||
addr_port2 = {5'b00010,banco_rom,a[13:0]}; // que vienen de los bancos de SRAM del 8 al 11
|
||
we2_n = 1'b1;
|
||
end
|
||
else begin // en el modo especial de paginaci<63>n, tenemos el all-RAM
|
||
case (plus3_memory_arrangement)
|
||
2'b00 : addr_port2 = {4'b0000,PAGE0,a[13:0]};
|
||
2'b01,
|
||
2'b10,
|
||
2'b11 : addr_port2 = {4'b0000,PAGE4,a[13:0]};
|
||
endcase
|
||
end
|
||
|
||
// Miramos si hay que paginar DOC o EXT y actualizamos addr_port2 y we2_n segun sea el caso
|
||
if (a[13] == 1'b0 && timex_mmu[0] == 1'b1) begin
|
||
addr_port2 = {4'b0011,doc_ext_option,3'b000,a[12:0]};
|
||
we2_n = mreq_n | wr_n;
|
||
end
|
||
if (a[13] == 1'b1 && timex_mmu[1] == 1'b1) begin
|
||
addr_port2 = {4'b0011,doc_ext_option,3'b001,a[12:0]};
|
||
we2_n = mreq_n | wr_n;
|
||
end
|
||
end
|
||
end // del modo normal de ejecuci<63>n
|
||
end // de la comprobacion de ROMCS
|
||
end // de a[15:14] == 2'b00
|
||
|
||
//------------------------------------------------------------------------------------------------------------------
|
||
else if (!mreq_n && a[15:14]==2'b01) begin // la CPU quiere acceder al espacio de RAM de $4000-$7FFF
|
||
if (initial_boot_mode || !amstrad_allram_page_mode) begin // en modo normal de paginaci<63>n, o en modo boot, hacemos lo mismo, que es
|
||
addr_port2 = {4'b0000,PAGE5,a[13:0]}; // paginar el banco 5 de RAM aqu<71>
|
||
end
|
||
else begin // en el modo especial de paginaci<63>n del +3...
|
||
case (plus3_memory_arrangement)
|
||
2'b00 : addr_port2 = {4'b0000,PAGE1,a[13:0]};
|
||
2'b01,
|
||
2'b10 : addr_port2 = {4'b0000,PAGE5,a[13:0]};
|
||
2'b11 : addr_port2 = {4'b0000,PAGE7,a[13:0]};
|
||
endcase
|
||
end
|
||
|
||
// Miramos si hay que paginar DOC o EXT y actualizamos addr_port2 y we2_n segun sea el caso
|
||
if (!initial_boot_mode) begin
|
||
if (a[13] == 1'b0 && timex_mmu[2] == 1'b1) begin
|
||
addr_port2 = {4'b0011,doc_ext_option,3'b010,a[12:0]};
|
||
end
|
||
if (a[13] == 1'b1 && timex_mmu[3] == 1'b1) begin
|
||
addr_port2 = {4'b0011,doc_ext_option,3'b011,a[12:0]};
|
||
end
|
||
end
|
||
end // de a[15:14] == 2'b01
|
||
|
||
//------------------------------------------------------------------------------------------------------------------
|
||
else if (!mreq_n && a[15:14]==2'b10) begin // la CPU quiere acceder al espacio de RAM de $8000-$BFFF
|
||
if (initial_boot_mode || !amstrad_allram_page_mode) begin
|
||
addr_port2 = {4'b0000,PAGE2,a[13:0]};
|
||
end
|
||
else begin // en el modo especial de paginaci<63>n del +3...
|
||
case (plus3_memory_arrangement)
|
||
2'b00 : addr_port2 = {4'b0000,PAGE2,a[13:0]};
|
||
2'b01,
|
||
2'b10,
|
||
2'b11 : addr_port2 = {4'b0000,PAGE6,a[13:0]};
|
||
endcase
|
||
end
|
||
|
||
// Miramos si hay que paginar DOC o EXT y actualizamos addr_port2 y we2_n segun sea el caso
|
||
if (!initial_boot_mode) begin
|
||
if (a[13] == 1'b0 && timex_mmu[4] == 1'b1) begin
|
||
addr_port2 = {4'b0011,doc_ext_option,3'b100,a[12:0]};
|
||
end
|
||
if (a[13] == 1'b1 && timex_mmu[5] == 1'b1) begin
|
||
addr_port2 = {4'b0011,doc_ext_option,3'b101,a[12:0]};
|
||
end
|
||
end
|
||
end // de a[15:14] == 2'b10
|
||
|
||
//------------------------------------------------------------------------------------------------------------------
|
||
else if (!mreq_n && a[15:14]==2'b11) begin // la CPU quiere acceder al espacio de RAM de $C000-$FFFF
|
||
if (initial_boot_mode) begin // en el modo de boot, este area contiene una p<>gina de 16K de la SRAM, la que sea
|
||
addr_port2 = {mastermapper,a[13:0]};
|
||
end
|
||
else begin
|
||
if (!amstrad_allram_page_mode) begin
|
||
`ifdef PENTAGON_512K_SUPPORT
|
||
addr_port2 = {banco_extendido_512k,2'b00,banco_ram,a[13:0]}; // para soportar Pentagon 512.
|
||
`else
|
||
addr_port2 = {4'b0000,banco_ram,a[13:0]};
|
||
`endif
|
||
end
|
||
else begin
|
||
case (plus3_memory_arrangement)
|
||
2'b00,
|
||
2'b10,
|
||
2'b11 : addr_port2 = {4'b0000,PAGE3,a[13:0]};
|
||
2'b01 : addr_port2 = {4'b0000,PAGE7,a[13:0]};
|
||
endcase
|
||
end
|
||
end
|
||
|
||
// Miramos si hay que paginar DOC o EXT y actualizamos addr_port2 y we2_n segun sea el caso
|
||
if (!initial_boot_mode) begin
|
||
if (a[13] == 1'b0 && timex_mmu[6] == 1'b1) begin
|
||
addr_port2 = {4'b0011,doc_ext_option,3'b110,a[12:0]};
|
||
end
|
||
if (a[13] == 1'b1 && timex_mmu[7] == 1'b1) begin
|
||
addr_port2 = {4'b0011,doc_ext_option,3'b111,a[12:0]};
|
||
end
|
||
end
|
||
end // de a[15:14] == 2'b11
|
||
|
||
else begin // realmente a esta parte nunca se habr<62>a de llegar, pero para completar la cadena de if-else if...
|
||
oe_memory_n = 1'b1;
|
||
oe_bootrom_n = 1'b1;
|
||
end
|
||
end
|
||
|
||
always @* begin
|
||
access_to_screen = 1'b0;
|
||
if (!initial_boot_mode) begin
|
||
if (a[15:13]==3'b010 && timex_mmu[2]==1'b1 || // si se ha paginado memoria de DOC o EXT, no hay contienda
|
||
a[15:13]==3'b011 && timex_mmu[3]==1'b1 ||
|
||
a[15:13]==3'b110 && timex_mmu[6]==1'b1 ||
|
||
a[15:13]==3'b111 && timex_mmu[7]==1'b1)
|
||
access_to_screen = 1'b0;
|
||
else if (!amstrad_allram_page_mode) begin
|
||
if (a[15:14]==2'b01 || (a[15:14]==2'b11 && banco_ram[0]==1'b1) ) begin // Hay contienda en las p<>ginas impares de memoria
|
||
access_to_screen = 1'b1;
|
||
end
|
||
end
|
||
end
|
||
end
|
||
|
||
// Conexiones internas
|
||
wire [7:0] bootrom_dout;
|
||
wire [7:0] ram_dout;
|
||
|
||
sram_and_mirror toda_la_ram ( // Nuevo controlador de SRAM usando BRAM de doble puerto para evitar la contienda
|
||
.clk(clk),
|
||
.a1({vrampage,vramaddr}),
|
||
.a2(addr_port2),
|
||
.we2_n(we2_n),
|
||
.dout1(vramdout),
|
||
.din2(din),
|
||
.dout2(ram_dout),
|
||
|
||
.pzx_addr(pzx_addr),
|
||
.enable_pzx(~ram_busy),
|
||
.data_from_pzx(data_from_pzx),
|
||
.data_to_pzx(data_to_pzx),
|
||
.write_data_pzx(write_data_pzx),
|
||
|
||
.a(sram_addr), // Interface con la SRAM real
|
||
.d(sram_data),
|
||
.we_n(sram_we_n)
|
||
);
|
||
|
||
rom boot_rom (
|
||
.clk(clk),
|
||
.a(a[13:0]),
|
||
.dout(bootrom_dout)
|
||
);
|
||
|
||
// Elecci<63>n del dato a entregar a la CPU
|
||
always @* begin
|
||
if (!oe_bootrom_n) begin
|
||
dout = bootrom_dout;
|
||
oe = 1'b1;
|
||
end
|
||
else if (!initial_boot_mode && inhibit_rom && a[15:14]==2'b00) begin
|
||
oe = 1'b1;
|
||
dout = din_external;
|
||
end
|
||
else if (!oe_memory_n) begin
|
||
dout = ram_dout;
|
||
oe = 1'b1;
|
||
end
|
||
else if (enable_timexmmu && iorq_n == 1'b0 && rd_n == 1'b0 && ADDR_TIMEX_MMU) begin
|
||
oe = 1'b1;
|
||
dout = timex_mmu;
|
||
end
|
||
else if (addr==MASTERCONF && ior) begin
|
||
dout = {masterconf_frozen,timing_mode[1],disable_cont,timing_mode[0],issue2_keyboard,divmmc_nmi_is_disabled,divmmc_is_enabled,initial_boot_mode};
|
||
oe = 1'b1;
|
||
end
|
||
else if (addr==MASTERMAPPER && ior) begin
|
||
dout = {1'b0,mastermapper};
|
||
oe = 1'b1;
|
||
end
|
||
else begin
|
||
dout = 8'hFF;
|
||
oe = 1'b0;
|
||
end
|
||
end
|
||
|
||
endmodule
|
||
|
||
module sram_and_mirror (
|
||
input wire clk, // 28MHz
|
||
input wire [14:0] a1, // to BRAM addr bus
|
||
input wire [20:0] a2, // to SRAM addr bus
|
||
input wire we2_n, // to SRAM WE enable
|
||
input wire [7:0] din2, // to SRAM data bus in
|
||
output reg [7:0] dout1, // from BRAM data bus out
|
||
output wire [7:0] dout2, // from SRAM data bus out
|
||
|
||
input wire [20:0] pzx_addr,
|
||
input wire enable_pzx,
|
||
input wire write_data_pzx,
|
||
input wire [7:0] data_from_pzx,
|
||
output wire [7:0] data_to_pzx,
|
||
|
||
output wire [20:0] a, // SRAM addr bus
|
||
inout wire [7:0] d, // SRAM bidirectional data bus
|
||
output wire we_n // SRAM WE enable
|
||
);
|
||
|
||
// BRAM to implement a dual port 32KB memory buffer
|
||
// First 16KB mirrors page 5, second 16KB mirrors page 7
|
||
reg [7:0] vram[0:32767];
|
||
integer i;
|
||
initial begin
|
||
for (i=0;i<32768;i=i+1)
|
||
vram[i] = 8'h00;
|
||
`ifdef LOAD_ROM_FROM_FLASH_OPTION
|
||
$readmemh("initial_bootscreen.hex", vram, 0);
|
||
`else
|
||
$readmemh(`DEFAULT_SYSTEM_ROM, vram, 0);
|
||
`endif
|
||
end
|
||
|
||
// BRAM manager
|
||
reg [7:0] data_from_bram;
|
||
always @(posedge clk) begin
|
||
if (a2[20:16] == 5'b00001 && a2[14] == 1'b1) begin
|
||
if (we2_n == 1'b0)
|
||
vram[{a2[15],a2[13:0]}] <= din2;
|
||
else
|
||
data_from_bram <= vram[{a2[15],a2[13:0]}];
|
||
end
|
||
dout1 <= vram[a1];
|
||
end
|
||
|
||
reg we2_n_dly = 1'b1;
|
||
always @(negedge clk)
|
||
we2_n_dly <= we2_n;
|
||
|
||
// SRAM manager. Easy, isn't it? :D
|
||
`ifdef PZX_PLAYER_OPTION
|
||
assign a = (enable_pzx)? pzx_addr : a2;
|
||
assign we_n = (enable_pzx)? ~write_data_pzx : we2_n & we2_n_dly; // pulso de escritura ligeramente ensenchado
|
||
assign dout2 = (a2[20:16] == 5'b00001 && a2[14] == 1'b1)? data_from_bram : d;
|
||
assign data_to_pzx = d;
|
||
assign d = (we2_n_dly == 1'b0 && write_data_pzx == 1'b0)? din2 : // dejo medio ciclo de reloj a Z antes de poner el dato
|
||
(enable_pzx == 1'b1 && write_data_pzx == 1'b1)? data_from_pzx :
|
||
8'hZZ;
|
||
`else
|
||
assign a = a2;
|
||
assign we_n = we2_n & we2_n_dly;
|
||
assign dout2 = (a2[20:16] == 5'b00001 && a2[14] == 1'b1)? data_from_bram : d;
|
||
assign data_to_pzx = 8'h00;
|
||
assign d = (we2_n_dly == 1'b0)? din2 : 8'hZZ;
|
||
`endif
|
||
endmodule
|