//============================================================================ // Sinclair QL // // Copyright (c) 2015 Till Harbaum // // Port to MiSTer // Copyright (C) 2017-2019 Sorgelig // // This program 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 2 of the License, or (at your option) // any later version. // // This program 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 this program; if not, write to the Free Software Foundation, Inc., // 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. //============================================================================ module emu ( //Master input clock input CLK_50M, //Async reset from top-level module. //Can be used as initial reset. input RESET, //Must be passed to hps_io module inout [48:0] HPS_BUS, //Base video clock. Usually equals to CLK_SYS. output CLK_VIDEO, //Multiple resolutions are supported using different CE_PIXEL rates. //Must be based on CLK_VIDEO output CE_PIXEL, //Video aspect ratio for HDMI. Most retro systems have ratio 4:3. //if VIDEO_ARX[12] or VIDEO_ARY[12] is set then [11:0] contains scaled size instead of aspect ratio. output [12:0] VIDEO_ARX, output [12:0] VIDEO_ARY, output [7:0] VGA_R, output [7:0] VGA_G, output [7:0] VGA_B, output VGA_HS, output VGA_VS, output VGA_DE, // = ~(VBlank | HBlank) output VGA_F1, output [1:0] VGA_SL, output VGA_SCALER, // Force VGA scaler output VGA_DISABLE, // analog out is off input [11:0] HDMI_WIDTH, input [11:0] HDMI_HEIGHT, output HDMI_FREEZE, output HDMI_BLACKOUT, output HDMI_BOB_DEINT, `ifdef MISTER_FB // Use framebuffer in DDRAM // FB_FORMAT: // [2:0] : 011=8bpp(palette) 100=16bpp 101=24bpp 110=32bpp // [3] : 0=16bits 565 1=16bits 1555 // [4] : 0=RGB 1=BGR (for 16/24/32 modes) // // FB_STRIDE either 0 (rounded to 256 bytes) or multiple of pixel size (in bytes) output FB_EN, output [4:0] FB_FORMAT, output [11:0] FB_WIDTH, output [11:0] FB_HEIGHT, output [31:0] FB_BASE, output [13:0] FB_STRIDE, input FB_VBL, input FB_LL, output FB_FORCE_BLANK, `ifdef MISTER_FB_PALETTE // Palette control for 8bit modes. // Ignored for other video modes. output FB_PAL_CLK, output [7:0] FB_PAL_ADDR, output [23:0] FB_PAL_DOUT, input [23:0] FB_PAL_DIN, output FB_PAL_WR, `endif `endif output LED_USER, // 1 - ON, 0 - OFF. // b[1]: 0 - LED status is system status OR'd with b[0] // 1 - LED status is controled solely by b[0] // hint: supply 2'b00 to let the system control the LED. output [1:0] LED_POWER, output [1:0] LED_DISK, // I/O board button press simulation (active high) // b[1]: user button // b[0]: osd button output [1:0] BUTTONS, input CLK_AUDIO, // 24.576 MHz output [15:0] AUDIO_L, output [15:0] AUDIO_R, output AUDIO_S, // 1 - signed audio samples, 0 - unsigned output [1:0] AUDIO_MIX, // 0 - no mix, 1 - 25%, 2 - 50%, 3 - 100% (mono) //ADC inout [3:0] ADC_BUS, //SD-SPI output SD_SCK, output SD_MOSI, input SD_MISO, output SD_CS, input SD_CD, //High latency DDR3 RAM interface //Use for non-critical time purposes output DDRAM_CLK, input DDRAM_BUSY, output [7:0] DDRAM_BURSTCNT, output [28:0] DDRAM_ADDR, input [63:0] DDRAM_DOUT, input DDRAM_DOUT_READY, output DDRAM_RD, output [63:0] DDRAM_DIN, output [7:0] DDRAM_BE, output DDRAM_WE, //SDRAM interface with lower latency output SDRAM_CLK, output SDRAM_CKE, output [12:0] SDRAM_A, output [1:0] SDRAM_BA, inout [15:0] SDRAM_DQ, output SDRAM_DQML, output SDRAM_DQMH, output SDRAM_nCS, output SDRAM_nCAS, output SDRAM_nRAS, output SDRAM_nWE, `ifdef MISTER_DUAL_SDRAM //Secondary SDRAM //Set all output SDRAM_* signals to Z ASAP if SDRAM2_EN is 0 input SDRAM2_EN, output SDRAM2_CLK, output [12:0] SDRAM2_A, output [1:0] SDRAM2_BA, inout [15:0] SDRAM2_DQ, output SDRAM2_nCS, output SDRAM2_nCAS, output SDRAM2_nRAS, output SDRAM2_nWE, `endif input UART_CTS, output UART_RTS, input UART_RXD, output UART_TXD, output UART_DTR, input UART_DSR, // Open-drain User port. // 0 - D+/RX // 1 - D-/TX // 2..6 - USR2..USR6 // Set USER_OUT to 1 to read from USER_IN. input [6:0] USER_IN, output [6:0] USER_OUT, input OSD_STATUS ); assign ADC_BUS = 'Z; assign USER_OUT = '1; assign {UART_RTS, UART_TXD, UART_DTR} = 0; assign {DDRAM_CLK, DDRAM_BURSTCNT, DDRAM_ADDR, DDRAM_DIN, DDRAM_BE, DDRAM_RD, DDRAM_WE} = 0; assign LED_USER = mdv_led | ioctl_download | sd_act; assign LED_DISK = {1'b1, status[0]}; assign LED_POWER = 0; assign BUTTONS = 0; assign VGA_SCALER= 0; assign VGA_DISABLE = 0; assign HDMI_FREEZE = 0; assign HDMI_BLACKOUT = 0; assign HDMI_BOB_DEINT = 0; video_freak video_freak ( .*, .VGA_DE_IN(VGA_DE), .VGA_DE(), .ARX((!ar) ? 12'd4 : (ar - 1'd1)), .ARY((!ar) ? 12'd3 : 12'd0), .CROP_SIZE(0), .CROP_OFF(0), .SCALE(status[14:13]) ); ///////////////// CONFIGURATION ///////////////// `include "build_id.v" parameter CONF_STR = { "QL;;", "SC0,WIN,Mount HD image;", "-;", "F2,MDV,Load MDV image;", "O2,MDV direction,normal,reverse;", "-;", "F4,ROM,Load OS;", "-;", "O3,Video mode,PAL,NTSC;", "OBC,Aspect ratio,Original,Full Screen,[ARC1],[ARC2];", "O9A,Scandoubler Fx,None,HQ2x,CRT 25%,CRT 50%;", "ODE,Scale,Normal,V-Integer,Narrower HV-Integer,Wider HV-Integer;", "-;", "O78,CPU speed,QL,16 Mhz,24 Mhz,Full;", "O45,RAM,128k,640k,896k,4096k;", "R0,Reset & unload MDV;", "V,v",`BUILD_DATE }; parameter MDV_IOCTL_INDEX = 8'd2; parameter ROM_IOCTL_INDEX = 8'd4; wire mdv_reverse = status[2]; wire ntsc_mode = status[3]; wire osd_reset = status[0]; wire [1:0] cpu_speed = status[8:7]; wire [1:0] scale = status[10:9]; wire ql_mode = cpu_speed == 2'b00; wire gc_en = ram_cfg == 2'b11; wire [1:0] ar = status[12:11]; reg [1:0] ram_cfg; // 00 = 128k, 01 = 640k, 10 = 896k, 11 = 4096k always @(posedge clk_sys) if (reset) ram_cfg <= status[5:4]; ///////////////// CLOCKS //////////////////////// wire clk_sys; wire pll_locked; pll pll ( .refclk(CLK_50M), .rst(0), .outclk_0(clk_sys), // System clock .locked(pll_locked) ); // 84MHz sys_clk parameter FRACT_BUS_QL = 17'd11702; // 84MHz * 11702 / 65536 = 14.999MHz parameter FRACT_BUS_16 = 17'd24966; // 84MHz * 24966 / 65536 = 31.999MHz parameter FRACT_BUS_24 = 17'd37449; // 84MHz * 37449 / 65536 = 48.000MHz parameter FRACT_BUS_FULL = 17'h10000; // 84MHz parameter FRACT_SD = 17'd19505; // 84MHz * 39010 / 65536 = 50Mhz (effectively 25Mhz SPI speed) parameter FRACT_11M = 17'd8582; // 84MHz * 8582 / 65536 = 10.999Mhz parameter DIV_131k = 10'd640; // 84MHz / 640 = 131250Hz parameter DIV_VID = 4'd8; // 84MHz / 8 = 10.5MHz // 94.5MHz sys_clk /*parameter FRACT_BUS_QL = 17'd10403; // 94.5MHz * 10403 / 65536 = 15.000MHz parameter FRACT_BUS_16 = 17'd22192; // 94.5MHz * 22192 / 65536 = 31.999MHz parameter FRACT_BUS_24 = 17'd33288; // 94.5MHz * 33288 / 65536 = 48.000MHz parameter FRACT_BUS_FULL = 17'h10000; // 94.5MHz parameter FRACT_SD = 17'd34675; // 94.5MHz * 34675 / 65536 = 49.999MHz (effectively 25Mhz SPI speed) parameter FRACT_11M = 17'd7629; // 94.5MHz * 7629 / 65536 = 11.001MHz parameter DIV_131k = 10'd720; // 94.5MHz / 720 = 131250Hz parameter DIV_VID = 4'd9; // 94.5MHz / 9 = 10.5MHz*/ // 105MHz sys_clk /*parameter FRACT_BUS_QL = 17'd9362; // 105MHz * 9362 / 65536 = 14.999MHz parameter FRACT_BUS_16 = 17'd19973; // 105MHz * 19973 / 65536 = 32.000MHz parameter FRACT_BUS_24 = 17'd29959; // 105MHz * 29959 / 65536 = 47.999MHz parameter FRACT_BUS_FULL = 17'h10000; // 105MHz parameter FRACT_SD = 17'd31208; // 105MHz * 31208 / 65536 = 50.000MHz (effectively 25Mhz SPI speed) parameter FRACT_11M = 17'd6866; // 105MHz * 6866 / 65536 = 11.001MHz parameter DIV_131k = 10'd800; // 105MHz / 800 = 131250Hz parameter DIV_VID = 4'd10; // 105MHz / 10 = 10.5MHz*/ wire [16:0] fract_bus = cpu_speed == 0? FRACT_BUS_QL: cpu_speed == 1? FRACT_BUS_16: cpu_speed == 2? FRACT_BUS_24: FRACT_BUS_FULL; reg ce_bus_p, ce_bus_n; reg ce_131k; // Supposed to be 131025 Hz for SDRAM refresh and clock update reg ce_vid; // 10.5Mhz pixel clock reg ce_sd; // ~50 Mhz SD clock reg ce_11m; always @(negedge clk_sys) begin reg bus_pol; reg bus_tick; reg [15:0] cnt_bus; reg [15:0] cnt_sd; reg [15:0] cnt_11m; reg [9:0] div131k; reg [3:0] divVid; if (reset) begin bus_pol <= 0; cnt_bus <= 0; div131k <= 0; divVid <= 0; end else begin div131k<= div131k + 10'd1; divVid <= divVid + 4'd1; end // CPU clock {bus_tick, cnt_bus} <= cnt_bus + fract_bus; ce_bus_p <= bus_tick && !bus_pol; ce_bus_n <= bus_tick && bus_pol; bus_pol <= bus_tick ^ bus_pol; // SDRAM refresh and clock update if (div131k == DIV_131k - 1) div131k <= 0; ce_131k <= !div131k; // 10.5Mhz pixel clock if (divVid == DIV_VID - 1) divVid <= 0; ce_vid <= !divVid; // QL-SD clock {ce_sd, cnt_sd} <= cnt_sd + FRACT_SD; // 11Mhz IPC clock {ce_11m, cnt_11m} <= cnt_11m + FRACT_11M; end //////////////// QL RAM timing //////////////////// wire ram_delay_dtack; ql_timing ql_timing( .*, .enable(ql_mode) ); ///////////////// HPS /////////////////////////// wire [31:0] status; wire [1:0] buttons; wire [15:0] joystick_0, joystick_1; wire ioctl_download; wire [7:0] ioctl_index; wire ioctl_wr; wire [24:0] ioctl_addr; wire [15:0] ioctl_dout = {ioctl_data[7:0], ioctl_data[15:8]}; wire [15:0] ioctl_data; reg ioctl_wait = 0; wire [31:0] sd_lba; wire sd_rd; wire sd_wr; wire sd_ack; wire [7:0] sd_buff_addr; wire [15:0] sd_buff_dout; wire [15:0] sd_buff_din; wire sd_buff_wr; wire img_mounted; wire img_readonly; wire [63:0] img_size; wire [24:0] ps2_mouse; wire [10:0] ps2_key; wire [32:0] TIMESTAMP; wire forced_scandoubler; wire [21:0] gamma_bus; hps_io #(.CONF_STR(CONF_STR), .WIDE(1)) hps_io ( .clk_sys(clk_sys), .HPS_BUS(HPS_BUS), .buttons(buttons), .status(status), .forced_scandoubler(forced_scandoubler), .gamma_bus(gamma_bus), .TIMESTAMP(TIMESTAMP), .ioctl_download(ioctl_download), .ioctl_index(ioctl_index), .ioctl_wr(ioctl_wr), .ioctl_addr(ioctl_addr), .ioctl_dout(ioctl_data), .ioctl_wait(ioctl_wait), .sd_lba('{sd_lba}), .sd_rd(sd_rd), .sd_wr(sd_wr), .sd_ack(sd_ack), .sd_buff_addr(sd_buff_addr), .sd_buff_dout(sd_buff_dout), .sd_buff_din('{sd_buff_din}), .sd_buff_wr(sd_buff_wr), .img_mounted(img_mounted), .img_readonly(img_readonly), .img_size(img_size), .ps2_key(ps2_key), .ps2_mouse(ps2_mouse), .joystick_0(joystick_0), .joystick_1(joystick_1) ); ///////////////// SD //////////////////////////// // SD card emulator reg vsd_sel = 0; always @(posedge clk_sys) if (img_mounted) vsd_sel <= |img_size; wire vsd_miso; wire sd_clk; wire sd_mosi; wire sd_miso = sd_phys_cs? vsd_miso: SD_MISO; wire sd_cs1, sd_cs2; wire sd_phys_cs = vsd_sel? sd_cs2: sd_cs1; // Physical SD as card2 if vitual SD is enabled sd_card #(.WIDE(1)) sd_card ( .*, .clk_spi(clk_sys), .sdhc(1), .sck(sd_clk), .ss(sd_cs1 || ~vsd_sel), .mosi(sd_mosi), .miso(vsd_miso) ); assign SD_CS = sd_phys_cs; assign SD_SCK = sd_phys_cs? 1'd0: sd_clk; assign SD_MOSI = sd_phys_cs? 1'd0: sd_mosi; // QL-SD interface wire qlsd_en = (!gc_en || rom_shadow) && cpu_rom && cpu_rd; wire qlsd_reg = qlsd_en && (cpu_addr[15:4] == 12'hfee || cpu_addr[15:4] == 12'hfef); wire qlsd_rd = qlsd_en && (cpu_addr[15:0] == 16'hfee4); // only one register actually returns data wire qlsd_dat = qlsd_en && cpu_addr[15:8] == 8'hff; wire qlsd_sel = qlsd_reg || qlsd_dat; wire [7:0] qlsd_dout; wire qlsd_dtack; qlromext qlromext ( .clk ( clk_sys ), .ce_sd ( ce_sd ), .dtack ( qlsd_dtack ), .romoel ( !qlsd_sel ), .a ( cpu_addr[15:0] ), .d ( qlsd_dout ), .sd_do ( sd_miso ), .sd_cs1l ( sd_cs1 ), .sd_cs2l ( sd_cs2 ), .sd_clk ( sd_clk ), .sd_di ( sd_mosi ), .io2 ( 1'b0 ) ); // SD led reg sd_act; always @(posedge clk_sys) begin reg old_mosi, old_miso; integer timeout = 0; old_mosi <= sd_mosi; old_miso <= sd_miso; sd_act <= 0; if (timeout < 4000000) begin timeout <= timeout + 1; sd_act <= 1; end if ((old_mosi ^ sd_mosi) || (old_miso ^ sd_miso)) timeout <= 0; end ///////////////// RESET ///////////////////////// reg [11:0] reset_cnt; wire reset = (reset_cnt != 0); always @(posedge clk_sys) begin if(RESET || buttons[1] || osd_reset || !pll_locked || rom_download) reset_cnt <= 12'hfff; else if(ce_bus_p && reset_cnt != 0) reset_cnt <= reset_cnt - 1'd1; end ///////////////// SDRAM ///////////////////////// wire [23:0] sdram_addr = { 3'b000, cpu_addr[21:1]}; wire [15:0] sdram_din = cpu_dout; wire sdram_wr = cpu_as && !cpu_rw && (cpu_ram || rom_shadow_write); wire sdram_oe = cpu_rd && (cpu_ram || rom_shadow_read); wire sdram_uds = cpu_uds; wire sdram_lds = cpu_lds; wire [15:0] sdram_dout; wire sdram_dtack; assign SDRAM_CKE = 1; sdram sdram ( .*, // system interface .clk ( clk_sys ), .refresh ( ce_131k ), .init ( !pll_locked ), // cpu interface .din ( sdram_din ), .addr ( sdram_addr ), .we ( sdram_wr ), .oe ( sdram_oe ), .uds ( sdram_uds ), .lds ( sdram_lds ), .dout ( sdram_dout ), .dtack ( sdram_dtack ) ); ////////////// GoldCard registers /////////////// // GoldCard style ROM shadow RAM reg rom_shadow; wire rom_shadow_read = cpu_rd && cpu_os_rom && rom_shadow; wire rom_shadow_write = cpu_as && !cpu_rw && cpu_os_rom && !rom_shadow; always @(posedge clk_sys) begin if (reset) rom_shadow <= 0; else if (gc_io && cpu_wr && cpu_uds && !cpu_lds) begin if (cpu_addr[7:0] == 8'h60) rom_shadow <= 1; // glo_rena: enable shadow RAM else if (cpu_addr[7:0] == 8'h64) rom_shadow <= 0; // glo_rdis: disable shadow RAM end end ////////////////// ROM ////////////////////////// wire rom_download = ioctl_download && (!ioctl_index || ioctl_index == ROM_IOCTL_INDEX); wire rom_ioctl_write = ioctl_wr && (!ioctl_index || ioctl_index == ROM_IOCTL_INDEX); wire [15:0] ql_rom_dout; dpram #(15) ql_rom ( .wrclock ( clk_sys ), .wraddress ( ioctl_addr[15:1] ), .wren ( rom_ioctl_write ), .byteena_a ( 2'b11 ), .data ( ioctl_dout ), .rdclock ( clk_sys ), .rdaddress ( cpu_addr[15:1] ), .q ( ql_rom_dout ) ); /////////// MisterGoldCard boot ROM ///////////// wire [15:0] gc_rom_dout; mgc_rom gc_rom ( .clock ( clk_sys ), .address ( cpu_addr[15:1] ), .q ( gc_rom_dout ) ); ///////////////// VRAM ////////////////////////// wire [15:0] vram_dout; dpram #(15) vram ( .wrclock(clk_sys), .wraddress ( cpu_addr[15:1] ), .wren ( cpu_wr && (cpu_addr[23:16] == 2) ), .byteena_a ( {cpu_uds, cpu_lds} ), .data ( cpu_dout ), .rdclock(clk_sys), .rdaddress(video_addr), .q(vram_dout) ); ///////////////// ZX8301 //////////////////////// wire video_r, video_g, video_b; wire HS, VS; wire HBlank, VBlank, ce_pix; reg HSync, VSync; always @(posedge CLK_VIDEO) begin HSync <= HS; if(~HSync & HS) VSync <= VS; end assign VGA_SL = scale ? scale - 1'd1 : 2'd0; assign VGA_F1 = 0; assign CLK_VIDEO = clk_sys; video_mixer #(.HALF_DEPTH(1), .GAMMA(1)) video_mixer ( .*, .scandoubler(scale || forced_scandoubler), .hq2x(scale==1), .freeze_sync(), .R({4{video_r}}), .G({4{video_g}}), .B({4{video_b}}) ); wire [14:0] video_addr; // The zx8301 has only one write-only register at $18063 wire zx8301_ce = ql_io && ({cpu_addr[6:5], cpu_addr[1]} == 3'b111) && cpu_wr && cpu_lds; reg [7:0] mc_stat; always @(posedge clk_sys) begin if (reset) begin mc_stat <= 8'h00; end else if (zx8301_ce) begin mc_stat <= cpu_dout[7:0]; end end zx8301 zx8301 ( .reset ( reset ), .clk ( clk_sys ), .ce ( ce_vid ), .ce_out ( ce_pix ), .ntsc ( ntsc_mode ), .mc_stat ( mc_stat ), .addr ( video_addr ), .din ( vram_dout ), .hs ( HS ), .vs ( VS ), .r ( video_r ), .g ( video_g ), .b ( video_b ), .HBlank ( HBlank ), .VBlank ( VBlank ) ); ///////////////// ZX8302 //////////////////////// wire zx8302_sel = cpu_io && ql_io && !cpu_addr[6]; wire [1:0] zx8302_addr = {cpu_addr[5], cpu_addr[1]}; wire [15:0] zx8302_dout; wire mdv_download = (ioctl_index == MDV_IOCTL_INDEX) && ioctl_download; wire audio; assign AUDIO_L = {15{audio}}; assign AUDIO_R = {15{audio}}; assign AUDIO_S = 0; assign AUDIO_MIX = 0; wire mdv_led; zx8302 zx8302 ( .reset ( reset ), .reset_mdv ( osd_reset ), .clk ( clk_sys ), .ce_11m ( ce_11m ), .xint ( qimi_irq ), .ipl ( cpu_ipl ), .led ( mdv_led ), .audio ( audio ), // CPU connection .cep ( ce_bus_p ), .cen ( ce_bus_n ), .ce_131k ( ce_131k ), .rtc_data ( TIMESTAMP ), .cpu_sel ( zx8302_sel ), .cpu_wr ( cpu_wr ), .cpu_addr ( zx8302_addr ), .cpu_uds ( cpu_uds ), .cpu_lds ( cpu_lds ), .cpu_din ( cpu_dout ), .cpu_dout ( zx8302_dout ), // joysticks .js0 ( joystick_0[4:0] ), .js1 ( joystick_1[4:0] ), .ps2_key ( ps2_key ), .vs ( VS ), .mdv_reverse ( mdv_reverse ), .mdv_download ( mdv_download ), .mdv_dl_wr ( ioctl_wr && mdv_download), .mdv_dl_data ( ioctl_dout ), .mdv_dl_addr ( ioctl_addr[17:1] ) ); ///////////////// MOUSE ///////////////////////// // qimi is at 1bfxx wire qimi_sel = cpu_io && ql_io && (cpu_addr[13:8] == 6'b111111); wire [7:0] qimi_data; wire qimi_irq; qimi qimi ( .reset ( reset ), .clk ( clk_sys ), .cep ( ce_bus_p ), .cen ( ce_bus_n ), .cpu_sel ( qimi_sel ), .cpu_addr ( { cpu_addr[5], cpu_addr[1] } ), .cpu_data ( qimi_data ), .irq ( qimi_irq ), .ps2_mouse ( ps2_mouse ) ); ///////////////// CPU /////////////////////////// wire ram_128 = !ram_cfg; wire ram_512 = ram_cfg == 2'b01; wire ram_768 = ram_cfg == 2'b10; wire ram_4k = &ram_cfg; wire [23:0] cpu_addr_mask = ram_128? 24'h03FFFF: // Wrap address space at 256kb (128KB RAM) ram_512 || ram_768? 24'h0FFFFF: // Wrap address space at 1MB (640 + 896KB RAM) 24'h7FFFFF; // Wrap address space at 8MB (4MB RAM + extended I/O space) // Address decoding wire cpu_rd = cpu_as && cpu_rw && (cpu_uds || cpu_lds); wire cpu_wr = cpu_as && !cpu_rw && (cpu_uds || cpu_lds); wire cpu_io = cpu_rd || cpu_wr; wire ql_io = {cpu_addr[23:14], 2'b00} == 12'h018; // internal IO $18000-$1bfff wire cpu_bram = cpu_addr[23:17] == 5'b00001; // 128k RAM $20000-$3ffff wire cpu_ram512 = ram_512 && !cpu_addr[23:20] && ^cpu_addr[19:18]; // ExtRAM 512k $40000-$bffff wire cpu_ram768 = ram_768 && !cpu_addr[23:20] && |cpu_addr[19:18]; // ExtRAM 768k $40000-$fffff wire cpu_ram4k = ram_4k && !cpu_addr[23:22] && |cpu_addr[21:18]; // ExtRAM 4096k $40000-$3fffff wire cpu_xram = cpu_ram512 || cpu_ram768 || cpu_ram4k; // ExtRAM 512k/768k/4096k wire cpu_ram = (cpu_bram || cpu_xram || gc_ram1 || gc_ram2); // any RAM wire cpu_rom = cpu_addr[23:16] == 8'h00; // 64k ROM $0000-$ffff wire cpu_ext_rom = {cpu_addr[23:14], 2'b00} == 12'h00C; // 16k ext ROM $c000-$ffff wire cpu_os_rom = cpu_rom && !cpu_ext_rom; // 48k OS ROM $0000-$bfff // Additional (Super)GoldCard spaces wire gc_io = gc_en && ({cpu_addr[23:8]} == 16'h01C0); // GoldCard IO $1c000-$1c0ff wire gc_ram1 = gc_en && {cpu_addr[23:15], 3'b000} == 12'h010; // 32kb additional SuperGoldCard RAM $10000-$17fff wire gc_ram2 = gc_en && {cpu_addr[23:14], 2'b00} == 12'h01C && !gc_io; // 16kb additional SuperGoldCard RAM $1c100-$1ffff wire gc_boot_rom = gc_en && cpu_addr[23:16] == 8'h04; // Another copy of the boot ROM $040000-$04ffff wire gc_os_rom = gc_en && cpu_addr[23:16] == 8'h40; // SuperGoldCard copy of QL ROM $400000-$40ffff //wire gc_ext_io = gc_en && {cpu_addr[23:18], 2'b00} == 8'h4c; // SuperGoldCard extended I/O $4c0000-$4fffff wire [15:0] io_dout = qimi_sel? {qimi_data, qimi_data}: zx8302_sel? zx8302_dout: 16'h0000; // Data bus on GC boot (shadow RAM disabled) wire [15:0] gc_dout_boot = cpu_rom? gc_rom_dout: // 000000..00ffff: GC ROM gc_boot_rom? gc_rom_dout: // 040000..04ffff: Another copy of GC ROM gc_os_rom? ql_rom_dout: // 400000..40ffff: Original OS ROM cpu_ram? sdram_dout: 16'hffff; // Data bus if GC RAM shadow is enabled wire [15:0] gc_dout_shadow = cpu_os_rom? sdram_dout: // 000000..007fff: Shadow-RAM qlsd_rd? {qlsd_dout, qlsd_dout}: // 00fee4 : QL-SD maps into rom area cpu_ext_rom? ql_rom_dout: // 00c000..00ffff: EXT-ROM space gc_os_rom? ql_rom_dout: // 400000..40ffff: Original OS ROM cpu_ram? sdram_dout: 16'hffff; // Gold Card mode data bus wire [15:0] gc_dout = rom_shadow? gc_dout_shadow: gc_dout_boot; // QL mode data bus wire [15:0] ql_dout = qlsd_rd? {qlsd_dout, qlsd_dout}: // 00fee4 : QL-SD maps into rom area cpu_rom? ql_rom_dout: // 000000..00ffff: OS ROM + EXT ROM cpu_ram? sdram_dout: 16'hffff; // Bring it all together wire [15:0] cpu_din = ql_io? io_dout: // 18000..1bfff: Always mapped gc_en? gc_dout: // GC-mode memory spaces ql_dout; // QL-mode memory spaces wire cpu_dtack = qlsd_sel? qlsd_dtack: rom_shadow_read || rom_shadow_write? sdram_dtack: cpu_ram? sdram_dtack && !ram_delay_dtack: !ram_delay_dtack; // Debugging only //reg [23:0] cpu_addr_reg /* synthesis noprune */; //always @(posedge clk_sys) begin // cpu_addr_reg <= cpu_addr; //end wire [23:1] cpu_addr16; wire [23:0] cpu_addr = {cpu_addr16, !cpu_uds && cpu_lds} & cpu_addr_mask; wire [15:0] cpu_dout; wire [1:0] cpu_ipl; wire cpu_uds_n; wire cpu_lds_n; wire cpu_uds = !cpu_uds_n; wire cpu_lds = !cpu_lds_n; wire cpu_as_n; wire cpu_as = !cpu_as_n; wire cpu_rw; wire [2:0] cpu_fc; wire cpu_int_ack = &cpu_fc; fx68k fx68k ( .clk ( clk_sys ), .HALTn ( 1'b1 ), .extReset ( reset ), .pwrUp ( reset ), .enPhi1 ( ce_bus_p ), .enPhi2 ( ce_bus_n ), .eRWn ( cpu_rw ), .ASn ( cpu_as_n ), .UDSn ( cpu_uds_n ), .LDSn ( cpu_lds_n ), .FC0 ( cpu_fc[0] ), .FC1 ( cpu_fc[1] ), .FC2 ( cpu_fc[2] ), .BGn ( ), .DTACKn ( ~cpu_dtack ), .VPAn ( ~cpu_int_ack ), .BERRn ( 1 ), .BRn ( 1 ), .BGACKn ( 1 ), .IPL0n ( cpu_ipl[0] ), .IPL1n ( cpu_ipl[1] ), .IPL2n ( cpu_ipl[0] ), // ipl 0 and 2 are tied together on 68008 .iEdb ( cpu_din ), .oEdb ( cpu_dout ), .eab ( cpu_addr16 ) ); endmodule