diff --git a/cores/Spectrum/control_enable_options.v b/cores/Spectrum/control_enable_options.v new file mode 100644 index 0000000..d1f3be9 --- /dev/null +++ b/cores/Spectrum/control_enable_options.v @@ -0,0 +1,59 @@ +`timescale 1ns / 1ps +////////////////////////////////////////////////////////////////////////////////// +// Company: +// Engineer: +// +// Create Date: 00:24:56 05/08/2016 +// Design Name: +// Module Name: control_enable_options +// Project Name: +// Target Devices: +// Tool versions: +// Description: +// +// Dependencies: +// +// Revision: +// Revision 0.01 - File Created +// Additional Comments: +// +////////////////////////////////////////////////////////////////////////////////// +module control_enable_options( + input wire clk, + input wire rst_n, + input wire [7:0] zxuno_addr, + input wire zxuno_regrd, + input wire zxuno_regwr, + input wire [7:0] din, + output reg [7:0] dout, + output wire oe_n, + output wire disable_ay, + output wire disable_turboay, + output wire disable_7ffd, + output wire disable_1ffd, + output wire disable_romsel7f, + output wire disable_romsel1f, + output wire enable_timexmmu, + output wire disable_spisd + ); + + parameter DEVOPTIONS = 8'h0E; + + assign oe_n = ~(zxuno_addr == DEVOPTIONS && zxuno_regrd == 1'b1); + reg [7:0] devoptions = 8'h00; // initial value + assign disable_ay = devoptions[0]; + assign disable_turboay = devoptions[1]; + assign disable_7ffd = devoptions[2]; + assign disable_1ffd = devoptions[3]; + assign disable_romsel7f = devoptions[4]; + assign disable_romsel1f = devoptions[5]; + assign enable_timexmmu = devoptions[6]; + assign disable_spisd = devoptions[7]; + always @(posedge clk) begin + if (rst_n == 1'b0) + devoptions <= 8'h00; // or after a hardware reset (not implemented yet) + else if (zxuno_addr == DEVOPTIONS && zxuno_regwr == 1'b1) + devoptions <= din; + dout <= devoptions; + end +endmodule diff --git a/cores/Spectrum/dp_memory.v b/cores/Spectrum/dp_memory.v deleted file mode 100644 index 7245504..0000000 --- a/cores/Spectrum/dp_memory.v +++ /dev/null @@ -1,146 +0,0 @@ -`timescale 1ns / 1ps -`default_nettype none - -////////////////////////////////////////////////////////////////////////////////// -// Company: -// Engineer: -// -// Create Date: 01:35:26 02/07/2014 -// Design Name: -// Module Name: dp_memory -// Project Name: -// Target Devices: -// Tool versions: -// Description: -// -// Dependencies: -// -// Revision: -// Revision 0.01 - File Created -// Additional Comments: -// -////////////////////////////////////////////////////////////////////////////////// -module dp_memory ( - input wire clk, // 28MHz - input wire [18:0] a1, - input wire [18:0] a2, - input wire oe1_n, - input wire oe2_n, - input wire we1_n, - input wire we2_n, - input wire [7:0] din1, - input wire [7:0] din2, - output wire [7:0] dout1, - output wire [7:0] dout2, - - output reg [18:0] a, - inout wire [7:0] d, - output reg ce_n, - output reg oe_n, - output reg we_n - ); - - parameter - ACCESO_M1 = 1, - READ_M1 = 2, - WRITE_M1 = 3, - ACCESO_M2 = 4, - READ_M2 = 5, - WRITE_M2 = 6; - - reg [7:0] data_to_write; - reg enable_input_to_sram; - - reg [7:0] doutput1; - reg [7:0] doutput2; - reg write_in_dout1; - reg write_in_dout2; - - reg [2:0] state = ACCESO_M1; - reg [2:0] next_state; - - always @(posedge clk) begin - state <= next_state; - end - - always @* begin - a = 0; - oe_n = 0; - we_n = 1; - ce_n = 0; - enable_input_to_sram = 0; - next_state = ACCESO_M1; - data_to_write = 8'h00; - write_in_dout1 = 0; - write_in_dout2 = 0; - - case (state) - ACCESO_M1: begin - a = a1; - if (we1_n == 1) begin - next_state = READ_M1; - end - else begin - oe_n = 1; - next_state = WRITE_M1; - end - end - READ_M1: begin - if (we1_n == 1) begin - a = a1; - write_in_dout1 = 1; - end - next_state = ACCESO_M2; - end - WRITE_M1: begin - if (we1_n == 0) begin - a = a1; - enable_input_to_sram = 1; - data_to_write = din1; - oe_n = 1; - we_n = 0; - end - next_state = ACCESO_M2; - end - ACCESO_M2: begin - a = a2; - if (we2_n == 1) begin - next_state = READ_M2; - end - else begin - oe_n = 1; - next_state = WRITE_M2; - end - end - READ_M2: begin - if (we2_n == 1) begin - a = a2; - write_in_dout2 = 1; - end - next_state = ACCESO_M1; - end - WRITE_M2: begin - if (we2_n == 0) begin - a = a2; - enable_input_to_sram = 1; - data_to_write = din2; - oe_n = 1; - we_n = 0; - end - next_state = ACCESO_M1; - end - endcase - end - - assign d = (enable_input_to_sram)? data_to_write : 8'hZZ; - assign dout1 = (oe1_n)? 8'hZZ : doutput1; - assign dout2 = (oe2_n)? 8'hZZ : doutput2; - - always @(posedge clk) begin - if (write_in_dout1) - doutput1 <= d; - else if (write_in_dout2) - doutput2 <= d; - end - -endmodule diff --git a/cores/Spectrum/memory.v b/cores/Spectrum/new_memory.v similarity index 53% rename from cores/Spectrum/memory.v rename to cores/Spectrum/new_memory.v index 406760e..f5bc12a 100644 --- a/cores/Spectrum/memory.v +++ b/cores/Spectrum/new_memory.v @@ -1,12 +1,11 @@ `timescale 1ns / 1ps -`default_nettype none ////////////////////////////////////////////////////////////////////////////////// // Company: // Engineer: // -// Create Date: 21:07:14 03/03/2014 +// Create Date: 16:40:14 05/04/2016 // Design Name: -// Module Name: memory +// Module Name: new_memory // Project Name: // Target Devices: // Tool versions: @@ -19,10 +18,11 @@ // Additional Comments: // ////////////////////////////////////////////////////////////////////////////////// -module memory ( + +module new_memory ( // Relojes y reset input wire clk, // Reloj del sistema CLK7 - input wire mclk, // Reloj para el modulo de memoria de doble puerto + input wire mclk, // Reloj para la BRAM input wire mrst_n, input wire rst_n, @@ -43,16 +43,28 @@ module memory ( // 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, + // 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 la SRAM output wire [18:0] sram_addr, @@ -151,8 +163,10 @@ module memory ( end end -`define ADDR_7FFD (a[0] && !a[1] && a[14] && !a[15]) +`define ADDR_7FFD_PLUS2A (a[0] && !a[1] && a[14] && !a[15]) // TO-DO repasar esta codificacion!!!! +`define ADDR_7FFD_SP128 (a[0] && !a[1] && !a[15]) `define ADDR_1FFD (a[0] && !a[1] && a[12] && a[15:13]==3'b000) +`define ADDR_TIMEX_MMU (a[7:0] == 8'hF4) `define PAGE0 3'b000 `define PAGE1 3'b001 @@ -163,12 +177,14 @@ module memory ( `define PAGE6 3'b110 `define 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 vrampage = bank128[3]; - wire [1:0] banco_rom = {bankplus3[2],bank128[4]}; + 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]; @@ -176,11 +192,16 @@ module memory ( if (!mrst_n || !rst_n) begin bank128 <= 8'h00; bankplus3 <= 8'h00; + timex_mmu <= 8'h00; end - else if (!iorq_n && !wr_n && `ADDR_7FFD && !puerto_bloqueado) - bank128 <= din; - else if (!iorq_n && !wr_n && `ADDR_1FFD && !puerto_bloqueado) + else if (!disable_1ffd && !iorq_n && !wr_n && `ADDR_1FFD && !puerto_bloqueado) bankplus3 <= din; + else if (!disable_7ffd && disable_1ffd && !iorq_n && !wr_n && `ADDR_7FFD_SP128 && !puerto_bloqueado) + bank128 <= din; + else if (!disable_7ffd && !disable_1ffd && !iorq_n && !wr_n && `ADDR_7FFD_PLUS2A && !puerto_bloqueado) + bank128 <= din; + else if (enable_timexmmu && !iorq_n && !wr_n && `ADDR_TIMEX_MMU) + timex_mmu <= din; end reg [18:0] addr_port2; @@ -196,6 +217,7 @@ module memory ( oe_bootrom_n = 1'b1; addr_port2 = 19'h00000; + //------------------------------------------------------------------------------------------------------------------ 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; @@ -204,44 +226,63 @@ module memory ( end else begin // estamos en modo normal de ejecución - if (divmmc_is_enabled && (divmmc_is_paged || conmem)) begin // DivMMC ha entrado en modo automapper o está mapeado a la fuerza - if (a[13]==1'b0) begin // Si estamos en los primeros 8K - if (conmem || !mapram_mode) begin - addr_port2 = {6'b011000,a[12:0]}; - we2_n = 1'b1; // en este modo, la ROM es intocable - end - else begin // mapram mode - addr_port2 = {2'b10,4'b0011,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 (conmem || !mapram_mode) begin - addr_port2 = {2'b10,divmmc_sram_page,a[12:0]}; - end - else begin // mapram mode - addr_port2 = {2'b10,divmmc_sram_page,a[12:0]}; - if (mapram_mode && divmmc_sram_page==4'b0011) - we2_n = 1'b1; // en este modo, la ROM es intocable - end - end - end + // 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í que se evalua primero. + if (divmmc_is_enabled && (divmmc_is_paged || conmem)) begin // DivMMC ha entrado en modo automapper o está mapeado a la fuerza + if (a[13]==1'b0) begin // Si estamos en los primeros 8K + if (conmem || !mapram_mode) begin + addr_port2 = {6'b011000,a[12:0]}; + we2_n = 1'b1; // en este modo, la ROM es intocable + end + else begin // mapram mode + addr_port2 = {6'b100011,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 (conmem || !mapram_mode) begin + addr_port2 = {2'b10,divmmc_sram_page,a[12:0]}; + end + else begin // mapram mode + addr_port2 = {2'b10,divmmc_sram_page,a[12:0]}; + if (mapram_mode && divmmc_sram_page==4'b0011) + we2_n = 1'b1; // en este modo, la ROM es intocable + end + end + end + + // DivMMC no está activo, asi que comprobamos qué 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ón, hay 4 bancos de ROMs + addr_port2 = {3'b010,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ón, tenemos el all-RAM + case (plus3_memory_arrangement) + 2'b00 : addr_port2 = {2'b00,`PAGE0,a[13:0]}; + 2'b01, + 2'b10, + 2'b11 : addr_port2 = {2'b00,`PAGE4,a[13:0]}; + endcase + end - else if (!amstrad_allram_page_mode) begin // en el modo normal de paginación, hay 4 bancos de ROMs - addr_port2 = {3'b010,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ón, tenemos el all-RAM - case (plus3_memory_arrangement) - 2'b00 : addr_port2 = {2'b00,`PAGE0,a[13:0]}; - 2'b01, - 2'b10, - 2'b11 : addr_port2 = {2'b00,`PAGE4,a[13:0]}; - endcase - end - end - end + // Miramos si hay que paginar DOC o EXT y actualizamos addr_port2 y we2_n segun sea el caso + if (!amstrad_allram_page_mode && a[13] == 1'b0 && timex_mmu[0] == 1'b1) begin + addr_port2 = {2'b11,doc_ext_option,3'b000,a[12:0]}; + we2_n = mreq_n | wr_n; + end + if (!amstrad_allram_page_mode && a[13] == 1'b1 && timex_mmu[1] == 1'b1) begin + addr_port2 = {2'b11,doc_ext_option,3'b001,a[12:0]}; + we2_n = mreq_n | wr_n; + end + end + end // del modo normal de ejecució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ón, o en modo boot, hacemos lo mismo, que es addr_port2 = {2'b00,`PAGE5,a[13:0]}; // paginar el banco 5 de RAM aquí @@ -254,8 +295,19 @@ module memory ( 2'b11 : addr_port2 = {2'b00,`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 (!amstrad_allram_page_mode && !initial_boot_mode) begin + if (a[13] == 1'b0 && timex_mmu[2] == 1'b1) begin + addr_port2 = {2'b11,doc_ext_option,3'b010,a[12:0]}; + end + if (a[13] == 1'b1 && timex_mmu[3] == 1'b1) begin + addr_port2 = {2'b11,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 = {2'b00,`PAGE2,a[13:0]}; @@ -268,8 +320,19 @@ module memory ( 2'b11 : addr_port2 = {2'b00,`PAGE6,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 (!amstrad_allram_page_mode && !initial_boot_mode) begin + if (a[13] == 1'b0 && timex_mmu[4] == 1'b1) begin + addr_port2 = {2'b11,doc_ext_option,3'b100,a[12:0]}; + end + if (a[13] == 1'b1 && timex_mmu[5] == 1'b1) begin + addr_port2 = {2'b11,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]}; @@ -287,9 +350,19 @@ module memory ( endcase end end - end + + // Miramos si hay que paginar DOC o EXT y actualizamos addr_port2 y we2_n segun sea el caso + if (!amstrad_allram_page_mode && !initial_boot_mode) begin + if (a[13] == 1'b0 && timex_mmu[6] == 1'b1) begin + addr_port2 = {2'b11,doc_ext_option,3'b110,a[12:0]}; + end + if (a[13] == 1'b1 && timex_mmu[7] == 1'b1) begin + addr_port2 = {2'b11,doc_ext_option,3'b111,a[12:0]}; + end + end + end // de a[15:14] == 2'b11 - else begin + else begin // realmente a esta parte nunca se habría de llegar, pero para completar la cadena de if-else if... oe_memory_n = 1'b1; oe_bootrom_n = 1'b1; end @@ -299,7 +372,12 @@ module memory ( always @* begin access_to_screen = 1'b0; if (!initial_boot_mode) begin - if (!amstrad_allram_page_mode) begin + if (a[15:13]==2'b010 && timex_mmu[2]==1'b1 || // si se ha paginado memoria de DOC o EXT, no hay contienda + a[15:13]==2'b011 && timex_mmu[3]==1'b1 || + a[15:13]==2'b110 && timex_mmu[6]==1'b1 || + a[15:13]==2'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==3'd5 || banco_ram==3'd7))) begin access_to_screen = 1'b1; end @@ -311,23 +389,17 @@ module memory ( wire [7:0] bootrom_dout; wire [7:0] ram_dout; - dp_memory dos_memorias ( // Controlador de memoria, que convierte a la SRAM en una memoria de doble puerto + sram_and_mirror toda_la_ram ( // Nuevo controlador de SRAM usando BRAM de doble puerto para evitar la contienda .clk(mclk), - .a1({3'b001,vrampage,1'b1,vramaddr}), + .a1({vrampage,vramaddr}), .a2(addr_port2), - .oe1_n(1'b0), - .oe2_n(1'b0), - .we1_n(1'b1), .we2_n(we2_n), - .din1(8'h00), .dout1(vramdout), .din2(din), .dout2(ram_dout), .a(sram_addr), // Interface con la SRAM real .d(sram_data), - .ce_n(), // Estos pines ya están a GND en el esquemático - .oe_n(), // así que no los conecto. .we_n(sram_we_n) ); @@ -343,10 +415,18 @@ module memory ( dout = bootrom_dout; oe_n = 1'b0; end + else if (!initial_boot_mode && inhibit_rom && a[15:14]==2'b00) begin + oe_n = 1'b0; + dout = din_external; + end else if (!oe_memory_n) begin dout = ram_dout; oe_n = 1'b0; end + else if (enable_timexmmu && iorq_n == 1'b0 && rd_n == 1'b0 && `ADDR_TIMEX_MMU) begin + oe_n = 1'b0; + 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_n = 1'b0; @@ -362,3 +442,42 @@ module memory ( end endmodule + +module sram_and_mirror ( + input wire clk, // 28MHz or higher if possible + input wire [14:0] a1, // to BRAM addr bus + input wire [18: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 + + output wire [18: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 + $readmemh("initial_bootscreen.hex", vram, 0, 6912); + for (i=6912;i<32768;i=i+1) + vram[i] = 8'h00; + end + + // BRAM manager + always @(posedge clk) begin + if (we2_n == 1'b0 && a2[18:16] == 3'b001 && a2[14] == 1'b1) + vram[{a2[15],a2[13:0]}] <= din2; + dout1 <= vram[a1]; + end + + // SRAM manager. Easy, isn't it? :D + assign a = a2; + assign we_n = we2_n; + assign dout2 = d; + assign d = (we2_n == 1'b0)? din2 : 8'hZZ; + +endmodule diff --git a/cores/Spectrum/tld_zxuno.prj b/cores/Spectrum/tld_zxuno.prj index 1dcb0cc..f43a410 100644 --- a/cores/Spectrum/tld_zxuno.prj +++ b/cores/Spectrum/tld_zxuno.prj @@ -13,7 +13,6 @@ verilog work "ps2mouse_to_kmouse.v" verilog work "pll_drp.v" verilog work "pal_sync_generator.v" verilog work "lut.v" -verilog work "dp_memory.v" verilog work "zxunoregs.v" verilog work "ula_radas.v" verilog work "tv80_to_t80_wrapper.v" @@ -24,12 +23,13 @@ verilog work "ps2_mouse_kempston.v" verilog work "ps2_keyb.v" verilog work "pll_top.v" verilog work "nmievents.v" +verilog work "new_memory.v" verilog work "multiboot.v" -verilog work "memory.v" verilog work "joystick_protocols.v" verilog work "flash_spi.v" verilog work "coreid.v" verilog work "control_rasterint.v" +verilog work "control_enable_options.v" verilog work "audio_management.v" verilog work "zxuno.v" verilog work "vga_scandoubler.v"