// license:BSD-3-Clause // copyright-holders:Andrei I. Holub // thanks-to:Kev Brady, Peter Ped Helcmanovsky /********************************************************************** Spectrum Next Versions: TBBlue 1.2, Issue 0, Issue 1, Issue 2, Issue 2B (Kickstarter 1), Issue 2D, Issue 2E, Issue 2H, Issue 4 (Kickstarter 2), Issue 5 (Kickstarter 3) Current implementation is based on Issue 4. Only limited difference tracked through PORT_CONFIG TODO: * contention * internal_port_enable() support * (1) invalidate tiles/sprites caches on region w, not every frame **********************************************************************/ #include "emu.h" #include "../screen_ula.h" #include "../spec128.h" #include "specnext_copper.h" #include "specnext_ctc.h" #include "specnext_divmmc.h" #include "specnext_dma.h" #include "specnext_im2.h" #include "specnext_multiface.h" #include "specnext_layer2.h" #include "specnext_lores.h" #include "specnext_sprites.h" #include "specnext_tiles.h" #include "specnext_uart.h" #include "bus/midi/midi.h" #include "bus/rs232/rs232.h" #include "bus/rs232/null_modem.h" #include "bus/rs232/pty.h" #include "bus/spectrum/zxbus/bus.h" #include "cpu/z80/z80n.h" #include "machine/ds1307.h" #include "machine/spi_sdcard.h" #include "sound/ay8910.h" #include "sound/dac.h" #include "speaker.h" #define LOG_IO (1U << 1) #define LOG_MEM (1U << 2) #define LOG_COPPER (1U << 3) #define LOG_INT (1U << 4) #define LOG_INT_VVV (1U << 5) //#define VERBOSE ( LOG_GENERAL /*| LOG_IO | LOG_MEM | LOG_COPPER */ | LOG_INT_VVV | LOG_INT ) #include "logmacro.h" #define LOGIO(...) LOGMASKED(LOG_IO, __VA_ARGS__) #define LOGMEM(...) LOGMASKED(LOG_MEM, __VA_ARGS__) #define LOGCOPPER(...) LOGMASKED(LOG_COPPER, __VA_ARGS__) #define LOGINT(...) LOGMASKED(LOG_INT, __VA_ARGS__) #define LOGINTVVV(...) LOGMASKED(LOG_INT_VVV, __VA_ARGS__) namespace { #define TIMINGS_PERFECT 0 constexpr u8 INT_PRIORITY_LINE = 0; constexpr u8 INT_PRIORITY_UART0_RX = 1; constexpr u8 INT_PRIORITY_UART1_RX = 2; constexpr u8 INT_PRIORITY_CTC = 3; // 3-10 reserved for 8 chanels, only 4 used atm constexpr u8 INT_PRIORITY_ULA = 11; constexpr u8 INT_PRIORITY_UART0_TX = 12; constexpr u8 INT_PRIORITY_UART1_TX = 13; constexpr u8 INT_PRIORITY_NMI = 15; struct video_timings_info { u16 min_hblank; u16 int_h; u16 min_hsync; u16 max_hsync; u16 max_hblank; u16 min_hactive; // 256x192 area u16 max_hc; u16 min_vblank; u16 int_v; u16 min_vsync; // displays don't like vsync = vblank u16 max_vsync; u16 max_vblank; u16 min_vactive; // 256x192 area u16 max_vc; // hdmi 360x288 u16 hdmi_xmin; u16 hdmi_xmax; u16 hdmi_ymin; u16 hdmi_ymax; u16 hdmi_ysync; }; class specnext_state : public spectrum_128_state, public device_state_interface { public: specnext_state(const machine_config &mconfig, device_type type, const char *tag) : spectrum_128_state(mconfig, type, tag) , device_state_interface(mconfig, *this) , m_maincpu(*this, "maincpu") , m_io_expbus_view(*this, "io_expbus_view") , m_bank_boot_rom(*this, "bootrom") , m_bank_ram(*this, "bank_ram%u", 0U) , m_bram_bank5(*this, "bram_bank5", 0x4000, ENDIANNESS_LITTLE) , m_bram_bank7(*this, "bram_bank7", 0x2000, ENDIANNESS_LITTLE) , m_view0(*this, "mem_view0") , m_view1(*this, "mem_view1") , m_view2(*this, "mem_view2") , m_view3(*this, "mem_view3") , m_view4(*this, "mem_view4") , m_view5(*this, "mem_view5") , m_view6(*this, "mem_view6") , m_view7(*this, "mem_view7") , m_im2_line(*this, "im2_line") , m_im2_uart0_rx(*this, "im2_uart0_rx") , m_im2_uart1_rx(*this, "im2_uart1_rx") , m_im2_ula(*this, "im2_ula") , m_im2_uart0_tx(*this, "im2_uart0_tx") , m_im2_uart1_tx(*this, "im2_uart1_tx") , m_copper(*this, "copper") , m_ctc(*this, "ctc") , m_dma(*this, "dma") , m_i2c(*this, "i2c") , m_uart(*this, "uart%u", 0U) , m_midi_out(*this, "mdout") , m_sdcards(*this, "sdcard%u", 0U) , m_ay(*this, "ay%u", 0U) , m_dac(*this, "dac%u", 0U) , m_palette(*this, "palette") , m_regs_map(*this, "regs_map") , m_mf(*this, "multiface") , m_divmmc(*this, "divmmc") , m_ula_scr(*this, "ula_scr") , m_tiles(*this, "tiles") , m_layer2(*this, "layer2") , m_lores(*this, "lores") , m_sprites(*this, "sprites") , m_io_video(*this, "VIDEO") , m_io_layers(*this, "LYRS") , m_io_mouse(*this, "mouse_input%u", 0U) , m_io_joy_left(*this, "JOY_LEFT") , m_io_joy_right(*this, "JOY_RIGHT") {} void tbblue(machine_config &config); void ks1(machine_config &config); void ks2(machine_config &config); void ks3(machine_config &config); INPUT_CHANGED_MEMBER(on_nmi_button); protected: virtual void machine_start() override ATTR_COLD; virtual void device_post_load() override ATTR_COLD; virtual void machine_reset() override ATTR_COLD; virtual void state_import(const device_state_entry &entry) override; void reset_hard(); virtual void video_start() override ATTR_COLD; virtual void spectrum_128_update_memory() override {} void update_video_mode(); u8 do_m1(offs_t offset); void nmi_rq(); void leave_nmi(int state); void map_fetch(address_map &map) ATTR_COLD; void map_mem(address_map &map) ATTR_COLD; void map_io(address_map &map) ATTR_COLD; void map_regs(address_map &map) ATTR_COLD; u8 reg_r(offs_t reg); void reg_w(offs_t reg, u8 data); void mmu_w(offs_t bank, u8 data); void mmu_x2_w(offs_t bank, u8 data); u8 dma_r(bool dma_mode); void dma_w(bool dma_mode, u8 data); u8 dma_mreq_r(offs_t offset); void update_dma_delay(); u8 spi_data_r(); void spi_data_w(u8 data); void spi_miso_w(u8 data); void i2c_scl_w(u8 data); template u8 uart_reg_r(); template void uart_reg_w(u8 data); template void txd_w(int state); void rxd_w(int state); void palette_val_w(u8 nr_palette_priority, u16 nr_palette_value); u8 port_ff_r(); void port_ff_w(u8 data); void ulatm_w(u8 data); void turbosound_address_w(u8 data); template u8 mf_port_r(offs_t addr); template void mf_port_w(offs_t addr, u8 data); template u8 kempston_md_r(offs_t addr); u8 mouse_button_r(); attotime copper_until_pos_r(u16 pos); void bank_update(u8 bank, u8 count); void bank_update(u8 bank); void memory_change(u16 port, u8 data); u16 get_layer2_active_page(u8 bank); u32 screen_update(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect); required_device m_maincpu; private: static const u8 G_VERSION = 0x32; // 3.02 static const u8 G_SUB_VERSION = 0x04; static const u8 G_VIDEO_INC = 0b11; static const u16 UTM_FALLBACK_PEN = 0xa00; virtual TIMER_CALLBACK_MEMBER(irq_off) override; virtual TIMER_CALLBACK_MEMBER(irq_on) override; INTERRUPT_GEN_MEMBER(specnext_interrupt); TIMER_CALLBACK_MEMBER(line_irq_on); INTERRUPT_GEN_MEMBER(line_interrupt); TIMER_CALLBACK_MEMBER(spi_clock); void line_irq_adjust(); void irq_w(int state); u8 g_machine_id() { return m_machine_id; } u8 g_board_issue() { return m_board_issue; } bool machine_type_48() const { return m_nr_03_machine_type == 0 || m_nr_03_machine_type == 1; } bool machine_type_128() const { return m_nr_03_machine_type == 2 || m_nr_03_machine_type == 4; } bool machine_type_p3() const { return !machine_type_48() && !machine_type_128(); } bool nmi_assert_mf() { return ((m_io_nmi->read() & 1) || m_nr_02_generate_mf_nmi) && m_nr_06_button_m1_nmi_en; } bool nmi_assert_divmmc() { return ((m_io_nmi->read() & 2) || m_nr_02_generate_divmmc_nmi) && m_nr_06_button_drive_nmi_en; } void nr_02_w(u8 nr_wr_dat); bool nr_02_iotrap() { return m_nr_da_iotrap_cause & 3; } void nr_07_cpu_speed_w(u8 data); void nr_0a_mf_type_w(u8 data) { m_nr_0a_mf_type = data; m_mf->mf_mode_w(m_nr_0a_mf_type); } void nr_12_layer2_active_bank_w(u8 data) { m_nr_12_layer2_active_bank = data; bank_update(0, 6); m_layer2->layer2_active_bank_w(m_nr_12_layer2_active_bank); } void nr_13_layer2_shadow_bank_w(u8 data) { m_nr_13_layer2_shadow_bank = data; bank_update(0, 6); } void nr_14_global_transparent_rgb_w(u8 data); void nr_15_sprite_priority_w(bool data) { m_nr_15_sprite_priority = data; m_sprites->zero_on_top_w(m_nr_15_sprite_priority); } void nr_15_sprite_border_clip_en_w(bool data) { m_nr_15_sprite_border_clip_en = data; m_sprites->border_clip_en_w(m_nr_15_sprite_border_clip_en); } void nr_15_sprite_over_border_en_w(bool data) { m_nr_15_sprite_over_border_en = data; m_sprites->over_border_w(m_nr_15_sprite_over_border_en); } void nr_16_layer2_scrollx_w(u8 data) { m_nr_16_layer2_scrollx = data; m_layer2->scroll_x_w((m_nr_71_layer2_scrollx_msb << 8) | m_nr_16_layer2_scrollx); } void nr_17_layer2_scrolly_w(u8 data) { m_nr_17_layer2_scrolly = data; m_layer2->scroll_y_w(m_nr_17_layer2_scrolly); } void nr_18_layer2_clip_x1_w(u8 data) { m_nr_18_layer2_clip_x1 = data; m_layer2->clip_x1_w(m_nr_18_layer2_clip_x1); } void nr_18_layer2_clip_x2_w(u8 data) { m_nr_18_layer2_clip_x2 = data; m_layer2->clip_x2_w(m_nr_18_layer2_clip_x2); } void nr_18_layer2_clip_y1_w(u8 data) { m_nr_18_layer2_clip_y1 = data; m_layer2->clip_y1_w(m_nr_18_layer2_clip_y1); } void nr_18_layer2_clip_y2_w(u8 data) { m_nr_18_layer2_clip_y2 = data; m_layer2->clip_y2_w(m_nr_18_layer2_clip_y2); } void nr_19_sprite_clip_x1_w(u8 data) { m_nr_19_sprite_clip_x1 = data; m_sprites->clip_x1_w(m_nr_19_sprite_clip_x1); } void nr_19_sprite_clip_x2_w(u8 data) { m_nr_19_sprite_clip_x2 = data; m_sprites->clip_x2_w(m_nr_19_sprite_clip_x2); } void nr_19_sprite_clip_y1_w(u8 data) { m_nr_19_sprite_clip_y1 = data; m_sprites->clip_y1_w(m_nr_19_sprite_clip_y1); } void nr_19_sprite_clip_y2_w(u8 data) { m_nr_19_sprite_clip_y2 = data; m_sprites->clip_y2_w(m_nr_19_sprite_clip_y2); } void nr_1a_ula_clip_x1_w(u8 data) { m_nr_1a_ula_clip_x1 = data; m_ula_scr->ula_clip_x1_w(m_nr_1a_ula_clip_x1); m_lores->clip_x1_w(m_nr_1a_ula_clip_x1); } void nr_1a_ula_clip_x2_w(u8 data) { m_nr_1a_ula_clip_x2 = data; m_ula_scr->ula_clip_x2_w(m_nr_1a_ula_clip_x2); m_lores->clip_x2_w(m_nr_1a_ula_clip_x2); } void nr_1a_ula_clip_y1_w(u8 data) { m_nr_1a_ula_clip_y1 = data; m_ula_scr->ula_clip_y1_w(m_nr_1a_ula_clip_y1); m_lores->clip_y1_w(m_nr_1a_ula_clip_y1); } void nr_1a_ula_clip_y2_w(u8 data); void nr_1b_tm_clip_x1_w(u8 data) { m_nr_1b_tm_clip_x1 = data; m_tiles->clip_x1_w(m_nr_1b_tm_clip_x1); } void nr_1b_tm_clip_x2_w(u8 data) { m_nr_1b_tm_clip_x2 = data; m_tiles->clip_x2_w(m_nr_1b_tm_clip_x2); } void nr_1b_tm_clip_y1_w(u8 data) { m_nr_1b_tm_clip_y1 = data; m_tiles->clip_y1_w(m_nr_1b_tm_clip_y1); } void nr_1b_tm_clip_y2_w(u8 data) { m_nr_1b_tm_clip_y2 = data; m_tiles->clip_y2_w(m_nr_1b_tm_clip_y2); } void nr_26_ula_scrollx_w(u8 data) { m_nr_26_ula_scrollx = data; m_ula_scr->ula_scroll_x_w(m_nr_26_ula_scrollx); } void nr_27_ula_scrolly_w(u8 data) { m_nr_27_ula_scrolly = data; m_ula_scr->ula_scroll_y_w(m_nr_27_ula_scrolly); } void nr_30_tm_scrollx_w(u16 data) { m_nr_30_tm_scrollx = data; m_tiles->tm_scroll_x_w(m_nr_30_tm_scrollx); } void nr_31_tm_scrolly_w(u8 data) { m_nr_31_tm_scrolly = data; m_tiles->tm_scroll_y_w(m_nr_31_tm_scrolly); } void nr_32_lores_scrollx_w(u8 data) { m_nr_32_lores_scrollx = data; m_lores->scroll_x_w(m_nr_32_lores_scrollx); } void nr_33_lores_scrolly_w(u8 data) { m_nr_33_lores_scrolly = data; m_lores->scroll_y_w(m_nr_33_lores_scrolly); } void nr_42_ulanext_format_w(u8 data) { m_nr_42_ulanext_format = data; m_ula_scr->ulanext_format_w(m_nr_42_ulanext_format); } void nr_43_ulanext_en_w(bool data) { m_nr_43_ulanext_en = data; m_ula_scr->ulanext_en_w(m_nr_43_ulanext_en); m_lores->ulap_en_w(m_port_ff3b_ulap_en && !m_nr_43_ulanext_en); } void nr_43_active_ula_palette_w(bool data) { m_nr_43_active_ula_palette = data; m_ula_scr->ula_palette_select_w(m_nr_43_active_ula_palette); m_lores->lores_palette_select_w(m_nr_43_active_ula_palette); } void nr_43_active_layer2_palette_w(bool data) { m_nr_43_active_layer2_palette = data; m_layer2->layer2_palette_select_w(m_nr_43_active_layer2_palette); } void nr_43_active_sprite_palette_w(bool data) { m_nr_43_active_sprite_palette = data; m_sprites->sprite_palette_select_w(m_nr_43_active_sprite_palette); } void nr_4b_sprite_transparent_index_w(u8 data) { m_nr_4b_sprite_transparent_index = data; m_sprites->transp_colour_w(m_nr_4b_sprite_transparent_index); } void nr_4c_tm_transparent_index_w(u8 data) { m_nr_4c_tm_transparent_index = data; m_tiles->transp_colour_w(m_nr_4c_tm_transparent_index); } void nr_62_copper_mode_w(u8 data) { m_nr_62_copper_mode = data; m_copper->copper_en_w(m_nr_62_copper_mode); } void nr_68_ula_fine_scroll_x_w(bool data) { m_nr_68_ula_fine_scroll_x = data; m_ula_scr->ula_fine_scroll_x_w(m_nr_68_ula_fine_scroll_x); } void nr_6a_lores_radastan_w(bool data) { m_nr_6a_lores_radastan = data; m_lores->mode_w(m_nr_6a_lores_radastan); } void nr_6a_lores_radastan_xor_w(bool data) { m_nr_6a_lores_radastan_xor = data; m_lores->dfile_w(BIT(m_port_ff_data, 0) != m_nr_6a_lores_radastan_xor); } void nr_6a_lores_palette_offset_w(u8 data) { m_nr_6a_lores_palette_offset = data; m_lores->lores_palette_offset_w(m_nr_6a_lores_palette_offset); } void nr_6b_tm_control_w(u8 data) { m_nr_6b_tm_control = data; m_tiles->control_w(m_nr_6b_tm_control); } void nr_6c_tm_default_attr_w(u8 data) { m_nr_6c_tm_default_attr = data; m_tiles->default_flags_w(m_nr_6c_tm_default_attr); } void nr_6e_tilemap_base_w(bool data7, u8 data5_0) { m_nr_6e_tilemap_base_7 = data7; m_nr_6e_tilemap_base = data5_0; m_tiles->tm_map_base_w((m_nr_6e_tilemap_base_7 << 6) | m_nr_6e_tilemap_base); } void nr_6f_tilemap_tiles_w(bool data7, u8 data5_0) { m_nr_6f_tilemap_tiles_7 = data7; m_nr_6f_tilemap_tiles = data5_0; m_tiles->tm_tile_base_w((m_nr_6f_tilemap_tiles_7 << 6) | m_nr_6f_tilemap_tiles); } void nr_70_layer2_resolution_w(u8 data) { m_nr_70_layer2_resolution = data; m_layer2->resolution_w(m_nr_70_layer2_resolution); } void nr_70_layer2_palette_offset_w(u8 data) { m_nr_70_layer2_palette_offset = data; m_layer2->palette_offset_w(m_nr_70_layer2_palette_offset); } void nr_71_layer2_scrollx_msb_w(bool data) { m_nr_71_layer2_scrollx_msb = data; m_layer2->scroll_x_w((m_nr_71_layer2_scrollx_msb << 8) | m_nr_16_layer2_scrollx); } void nr_80_expbus_w(u8 data) { m_nr_80_expbus = data; m_io_expbus_view.select(BIT(m_nr_80_expbus, 7)); } bool nr_8c_altrom_en() const { return BIT(m_nr_8c_altrom, 7); } bool nr_8c_altrom_rw() const { return BIT(m_nr_8c_altrom, 6); } bool nr_8c_altrom_lock_rom1() const { return BIT(m_nr_8c_altrom, 5); } bool nr_8c_altrom_lock_rom0() const { return BIT(m_nr_8c_altrom, 4); } bool nr_8f_mapping_mode_profi() const { return 0; } bool nr_8f_mapping_mode_pentagon() const { return m_nr_8f_mapping_mode == 0b10 || nr_8f_mapping_mode_pentagon_1024_en(); } bool nr_8f_mapping_mode_pentagon_1024() const { return m_nr_8f_mapping_mode == 0b11; } bool nr_8f_mapping_mode_pentagon_1024_en() const { return nr_8f_mapping_mode_pentagon_1024() && BIT(~m_port_eff7_data, 2); } void nr_c0_im2_vector_w(bool mode_im2, u8 vector); u32 internal_port_enable() const; bool port_ff_io_en() const { return BIT(internal_port_enable(), 0); } bool port_7ffd_io_en() const { return BIT(internal_port_enable(), 1); } bool port_dffd_io_en() const { return BIT(internal_port_enable(), 2); } bool port_1ffd_io_en() const { return BIT(internal_port_enable(), 3); } bool port_p3_floating_bus_io_en() const { return BIT(internal_port_enable(), 4); } bool port_dma_6b_io_en() const { return BIT(internal_port_enable(), 5); } bool port_1f_io_en() const { return BIT(internal_port_enable(), 6); } bool port_37_io_en() const { return BIT(internal_port_enable(), 7); } bool port_divmmc_io_en() const { return BIT(internal_port_enable(), 8); } bool port_multiface_io_en() const { return BIT(internal_port_enable(), 9); } bool port_i2c_io_en() const { return BIT(internal_port_enable(), 10); } bool port_spi_io_en() const { return BIT(internal_port_enable(), 11); } bool port_uart_io_en() const { return BIT(internal_port_enable(), 12); } bool port_mouse_io_en() const { return BIT(internal_port_enable(), 13); } bool port_sprite_io_en() const { return BIT(internal_port_enable(), 14); } bool port_layer2_io_en() const { return BIT(internal_port_enable(), 15); } bool port_ay_io_en() const { return BIT(internal_port_enable(), 16); } bool port_dac_sd1_ABCD_1f0f4f5f_io_en() const { return BIT(internal_port_enable(), 17); } bool port_dac_sd2_ABCD_f1f3f9fb_io_en() const { return BIT(internal_port_enable(), 18); } bool port_dac_stereo_AD_3f5f_io_en() const { return BIT(internal_port_enable(), 19); } bool port_dac_stereo_BC_0f4f_io_en() const { return BIT(internal_port_enable(), 20); } bool port_dac_mono_AD_fb_io_en() const { return BIT(internal_port_enable(), 21); } bool port_dac_mono_BC_b3_io_en() const { return BIT(internal_port_enable(), 22); } bool port_dac_mono_AD_df_io_en() const { return BIT(internal_port_enable(), 23); } bool port_ulap_io_en() const { return BIT(internal_port_enable(), 24); } bool port_dma_0b_io_en() const { return BIT(internal_port_enable(), 25); } bool port_eff7_io_en() const { return BIT(internal_port_enable(), 26); } bool port_ctc_io_en() const { return BIT(internal_port_enable(), 27); } u16 vpos_to_cvc(u16 vpos) const { return (vpos - m_video_timings.min_vactive + m_nr_64_copper_offset + (m_video_timings.max_vc + 1)) % (m_video_timings.max_vc + 1); } u16 cvc_to_vpos(u16 cvc) const { return (cvc + m_video_timings.min_vactive - m_nr_64_copper_offset + m_screen->height()) % m_screen->height(); } u8 port_7ffd_bank() const { return (((nr_8f_mapping_mode_pentagon() || nr_8f_mapping_mode_profi()) ? 0 : BIT(m_port_dffd_data, 3)) << 6) | ((!nr_8f_mapping_mode_pentagon() ? BIT(m_port_dffd_data, 2) : (nr_8f_mapping_mode_pentagon_1024_en() && BIT(m_port_7ffd_data, 5))) << 5) | ((nr_8f_mapping_mode_pentagon() ? BIT(m_port_7ffd_data, 6, 2) : (m_port_dffd_data & 3)) << 3) | (m_port_7ffd_data & 7); } bool port_7ffd_shadow() const { return BIT(m_port_7ffd_data, 3); } bool port_7ffd_locked() const { return (nr_8f_mapping_mode_pentagon_1024_en() || (nr_8f_mapping_mode_profi() && BIT(m_port_dffd_data, 4))) ? 0 : BIT(m_port_7ffd_data, 5); } bool port_1ffd_special() const { return BIT(m_port_1ffd_data, 0); } u8 port_1ffd_rom() const { return (BIT(m_port_1ffd_data, 2) << 1) | BIT(m_port_7ffd_data, 4); } void port_7ffd_reg_w(u8 data); bool port_ff_interrupt_disable() { return BIT(m_port_ff_data, 6); } void port_123b_layer2_en_w(bool data) { m_screen->update_now(); m_port_123b_layer2_en = data; m_layer2->layer2_en_w(m_port_123b_layer2_en); } void port_ff3b_ulap_en_w(bool data) { m_port_ff3b_ulap_en = data; m_ula_scr->ulap_en_w(m_port_ff3b_ulap_en); m_lores->ulap_en_w(m_port_ff3b_ulap_en && !m_nr_43_ulanext_en); } u16 nr_palette_dat(); void port_e3_reg_w(u8 data); void port_e7_reg_w(u8 data); memory_access<8, 0, 0, ENDIANNESS_LITTLE>::specific m_next_regs; memory_view m_io_expbus_view; memory_bank_creator m_bank_boot_rom; memory_bank_array_creator<8> m_bank_ram; memory_share_creator m_bram_bank5; memory_share_creator m_bram_bank7; memory_view m_view0, m_view1, m_view2, m_view3, m_view4, m_view5, m_view6, m_view7; required_device m_im2_line; optional_device m_im2_uart0_rx; optional_device m_im2_uart1_rx; required_device m_im2_ula; optional_device m_im2_uart0_tx; optional_device m_im2_uart1_tx; required_device m_copper; required_device m_ctc; required_device m_dma; optional_device m_i2c; optional_device_array m_uart; optional_device m_midi_out; required_device_array m_sdcards; required_device_array m_ay; required_device_array m_dac; required_device m_palette; required_device m_regs_map; required_device m_mf; required_device m_divmmc; required_device m_ula_scr; required_device m_tiles; required_device m_layer2; required_device m_lores; required_device m_sprites; optional_ioport m_io_video; optional_ioport m_io_layers; required_ioport_array<4> m_io_mouse; required_ioport m_io_joy_left; required_ioport m_io_joy_right; u8 m_machine_id; u8 m_board_issue; u16 m_ram_pages; bitmap_rgb32 m_blendprio_bitmap; video_timings_info m_video_timings; rectangle m_clip256x192; rectangle m_clip320x256; int m_video_output_hdmi = -1; int m_page_shadow[8] = {-1, -1, -1, -1, -1, -1, -1, -1}; bool m_bootrom_en; u8 m_port_ff_data; bool m_port_1ffd_special_old; u8 m_port_1ffd_data; u8 m_port_7ffd_data; u8 m_port_dffd_data; u8 m_port_eff7_data; u8 m_port_e7_reg; u8 m_nr_register; u8 m_port_e3_reg; bool m_divmmc_delayed_check; u8 m_sram_rom; bool m_sram_rom3; bool m_sram_alt_128_n; u8 m_mmu[8]; bool m_nr_02_bus_reset; bool m_nr_02_generate_mf_nmi; bool m_nr_02_generate_divmmc_nmi; bool m_nr_02_hard_reset; u8 m_nr_02_reset_type; // u3 u8 m_nr_03_machine_type; // u3 bool m_nr_03_user_dt_lock; u8 m_nr_03_machine_timing; // u3 bool m_nr_03_config_mode; u8 m_nr_04_romram_bank; // issue <5 - u7, issue5 - u8 u8 m_nr_05_joy0; // u3 u8 m_nr_05_joy1; // u3 bool m_nr_05_5060; u8 m_nr_06_psg_mode; // u2 bool m_nr_06_ps2_mode; bool m_nr_06_button_m1_nmi_en; bool m_nr_06_button_drive_nmi_en; bool m_nr_06_hotkey_5060_en; bool m_nr_06_internal_speaker_beep; bool m_nr_06_hotkey_cpu_speed_en; u8 m_nr_07_cpu_speed; // u2 bool m_nr_08_keyboard_issue2; bool m_nr_08_psg_turbosound_en; bool m_nr_08_port_ff_rd_en; bool m_nr_08_dac_en; bool m_nr_08_internal_speaker_en; bool m_nr_08_psg_stereo_mode; bool m_nr_08_contention_disable; bool m_nr_09_hdmi_audio_en; bool m_nr_09_sprite_tie; u8 m_nr_09_psg_mono; // u3 u8 m_nr_0a_mouse_dpi; // u2 bool m_nr_0a_mouse_button_reverse; bool m_nr_0a_divmmc_automap_en; u8 m_nr_0a_mf_type; // u2 bool m_nr_0a_sd_swap; bool m_nr_0b_joy_iomode_0; u8 m_nr_0b_joy_iomode; // u2 bool m_nr_0b_joy_iomode_en; u8 m_nr_10_coreid; // u5 u8 m_nr_11_video_timing; // u3 bool m_nr_10_flashboot; u8 m_nr_12_layer2_active_bank; // u7 u8 m_nr_13_layer2_shadow_bank; // u7 u8 m_nr_14_global_transparent_rgb; bool m_nr_15_sprite_en; bool m_nr_15_sprite_over_border_en; u8 m_nr_15_layer_priority; // u3 bool m_nr_15_sprite_border_clip_en; bool m_nr_15_sprite_priority; bool m_nr_15_lores_en; u8 m_nr_16_layer2_scrollx; u8 m_nr_17_layer2_scrolly; u8 m_nr_18_layer2_clip_x1; u8 m_nr_18_layer2_clip_x2; u8 m_nr_18_layer2_clip_y1; u8 m_nr_18_layer2_clip_y2; u8 m_nr_18_layer2_clip_idx; // u2 u8 m_nr_19_sprite_clip_x1; u8 m_nr_19_sprite_clip_x2; u8 m_nr_19_sprite_clip_y1; u8 m_nr_19_sprite_clip_y2; u8 m_nr_19_sprite_clip_idx; // u2 u8 m_nr_1a_ula_clip_x1; u8 m_nr_1a_ula_clip_x2; u8 m_nr_1a_ula_clip_y1; u8 m_nr_1a_ula_clip_y2; u8 m_nr_1a_ula_clip_idx; // u2 u8 m_nr_1b_tm_clip_x1; u8 m_nr_1b_tm_clip_x2; u8 m_nr_1b_tm_clip_y1; u8 m_nr_1b_tm_clip_y2; u8 m_nr_1b_tm_clip_idx; // u2 bool m_nr_22_line_interrupt_en; u16 m_nr_23_line_interrupt; // u9 u8 m_nr_26_ula_scrollx; u8 m_nr_27_ula_scrolly; u8 m_nr_2d_i2s_sample; // u2 u16 m_nr_30_tm_scrollx; // u10 u8 m_nr_31_tm_scrolly; u8 m_nr_32_lores_scrollx; u8 m_nr_33_lores_scrolly; u8 m_nr_palette_idx; bool m_nr_palette_sub_idx; u8 m_nr_42_ulanext_format; bool m_nr_43_palette_autoinc_disable; u8 m_nr_43_palette_write_select; // u3 bool m_nr_43_active_sprite_palette; bool m_nr_43_active_layer2_palette; bool m_nr_43_active_ula_palette; bool m_nr_43_ulanext_en; u8 m_nr_stored_palette_value; u8 m_nr_4a_fallback_rgb; u8 m_nr_4b_sprite_transparent_index; u8 m_nr_4c_tm_transparent_index; // u4 u16 m_nr_copper_addr; // u11 u8 m_nr_copper_data_stored; u8 m_nr_62_copper_mode; // u2 u8 m_nr_64_copper_offset; bool m_nr_68_ula_en; u8 m_nr_68_blend_mode; // u2 bool m_nr_68_cancel_extended_keys; bool m_nr_68_ula_fine_scroll_x; bool m_nr_68_ula_stencil_mode; bool m_nr_6a_lores_radastan; bool m_nr_6a_lores_radastan_xor; u8 m_nr_6a_lores_palette_offset; // u4 bool m_nr_6b_tm_en; u8 m_nr_6b_tm_control; // u7 u8 m_nr_6c_tm_default_attr; u8 m_nr_6e_tilemap_base; // u6 bool m_nr_6e_tilemap_base_7; u8 m_nr_6f_tilemap_tiles; // u6 bool m_nr_6f_tilemap_tiles_7; u8 m_nr_70_layer2_resolution; // u2 u8 m_nr_70_layer2_palette_offset; // u4 bool m_nr_71_layer2_scrollx_msb; u8 m_nr_7f_user_register_0; u8 m_nr_80_expbus; u8 m_nr_81_expbus_speed; // u2 bool m_nr_81_expbus_clken; bool m_nr_81_expbus_nmi_debounce_disable; bool m_nr_81_expbus_ula_override; u8 m_nr_82_internal_port_enable; u8 m_nr_83_internal_port_enable; u8 m_nr_84_internal_port_enable; u8 m_nr_85_internal_port_enable; // u4 bool m_nr_85_internal_port_reset_type; u8 m_nr_86_bus_port_enable; u8 m_nr_87_bus_port_enable; u8 m_nr_88_bus_port_enable; u8 m_nr_89_bus_port_enable; // u4 bool m_nr_89_bus_port_reset_type; u8 m_nr_8a_bus_port_propagate; // u6 u8 m_nr_8c_altrom; u8 m_nr_8f_mapping_mode; // u2 u8 m_nr_90_pi_gpio_o_en; u8 m_nr_91_pi_gpio_o_en; u8 m_nr_92_pi_gpio_o_en; u8 m_nr_93_pi_gpio_o_en; // u4 u8 m_nr_98_pi_gpio_o; u8 m_nr_99_pi_gpio_o; u8 m_nr_9a_pi_gpio_o; u8 m_nr_9b_pi_gpio_o; // u4 u8 m_nr_a0_pi_peripheral_en; u8 m_nr_a2_pi_i2s_ctl; bool m_nr_a8_esp_gpio0_en; bool m_nr_a9_esp_gpio0; u8 m_nr_b8_divmmc_ep_0; u8 m_nr_b9_divmmc_ep_valid_0; u8 m_nr_ba_divmmc_ep_timing_0; u8 m_nr_bb_divmmc_ep_1; u8 m_nr_c0_im2_vector; // u3 bool m_nr_c0_stackless_nmi; bool m_nr_c0_int_mode_pulse_0_im2_1; u8 m_nr_c2_retn_address_lsb; u8 m_nr_c3_retn_address_msb; bool m_nr_c4_int_en_0_expbus; u8 m_nr_c6_int_en_2_654; // u3 u8 m_nr_c6_int_en_2_210; // u3 bool m_nr_cc_dma_int_en_0_7; u8 m_nr_cc_dma_int_en_0_10; // u2 u8 m_nr_cd_dma_int_en_1; u8 m_nr_ce_dma_int_en_2_654; // u3 u8 m_nr_ce_dma_int_en_2_210; // u3 bool m_nr_d8_io_trap_fdc_en; u8 m_nr_d9_iotrap_write; u8 m_nr_da_iotrap_cause; // u2 bool m_nr_f0_select; bool m_nr_f0_xdna_en; bool m_nr_f0_xadc_en; u8 m_nr_f0_xdev_cmd; bool m_nr_f0_xadc_eoc; bool m_nr_f0_xadc_eos; bool m_nr_f8_xadc_dwe; u8 m_nr_f8_xadc_daddr; // u7 bool m_nr_f8_xadc_den; u8 m_nr_f9_xadc_d0; u8 m_nr_fa_xadc_d1; bool m_pulse_int_n; u16 m_im2_int_status; // u14 u8 m_nr_09_scanlines; // u2 u8 m_eff_nr_03_machine_timing; // u3 bool m_eff_nr_05_5060; bool m_eff_nr_05_scandouble_en; bool m_eff_nr_08_contention_disable; u8 m_eff_nr_09_scanlines; // u2 bool m_port_123b_layer2_en; bool m_port_123b_layer2_map_wr_en; bool m_port_123b_layer2_map_rd_en; bool m_port_123b_layer2_map_shadow; u8 m_port_123b_layer2_map_segment; // u2 u8 m_port_123b_layer2_offset; // u3 u8 m_port_bf3b_ulap_mode; // u2 u8 m_port_bf3b_ulap_index; // u6 bool m_port_ff3b_ulap_en; u8 m_ay_select; // u2 bool m_uart_select; emu_timer *m_irq_line_timer; emu_timer *m_spi_clock; int m_spi_clock_cycles; bool m_spi_clock_state; u8 m_spi_mosi_dat; u8 m_spi_miso_dat; bool m_i2c_scl_data; bool m_i2c_sda_data; }; void specnext_state::bank_update(u8 bank, u8 count) { for (auto b = bank; count; ++b, --count) bank_update(b); } void specnext_state::bank_update(u8 bank) { using views_link = std::reference_wrapper; views_link views[] = { m_view0, m_view1, m_view2, m_view3, m_view4, m_view5, m_view6, m_view7 }; const bool is_rom = (bank >> 1) == 0; if (m_bootrom_en && is_rom) { m_bank_boot_rom->set_entry(m_nr_10_coreid > 0 ? 1 : 0); return views[bank].get().select(2); } if (machine_type_48()) { m_sram_rom = 0b00; m_sram_rom3 = 1; m_sram_alt_128_n = !(!nr_8c_altrom_lock_rom1() && nr_8c_altrom_lock_rom0()); } else if (machine_type_p3()) { if (nr_8c_altrom_lock_rom1() || nr_8c_altrom_lock_rom0()) { m_sram_rom = (nr_8c_altrom_lock_rom1() << 1) | nr_8c_altrom_lock_rom0(); m_sram_rom3 = nr_8c_altrom_lock_rom1() && nr_8c_altrom_lock_rom0(); m_sram_alt_128_n = nr_8c_altrom_lock_rom1(); } else { m_sram_rom = port_1ffd_rom(); m_sram_rom3 = port_1ffd_rom() == 0x03; m_sram_alt_128_n = port_1ffd_rom() & 1; } } else { if (nr_8c_altrom_lock_rom1() || nr_8c_altrom_lock_rom0()) { m_sram_rom = nr_8c_altrom_lock_rom1(); m_sram_rom3 = nr_8c_altrom_lock_rom1(); m_sram_alt_128_n = nr_8c_altrom_lock_rom1(); } else { m_sram_rom = port_1ffd_rom() & 1; m_sram_rom3 = port_1ffd_rom() & 1; m_sram_alt_128_n = port_1ffd_rom() & 1; } } const u8 mem_active_page = m_mmu[bank]; const bool mem_active_bank5 = mem_active_page == 0x0a || mem_active_page == 0x0b; const bool mem_active_bank7 = mem_active_page == 0x0e; const u16 mmu_A21_A13 = ((0b0001 + BIT(mem_active_page, 5, 3)) << 5) | BIT(mem_active_page, 0, 5); const u8 layer2_active_bank_offset_pre = m_port_123b_layer2_map_segment == 0b11 ? BIT(bank, 1, 2) : m_port_123b_layer2_map_segment; const u8 layer2_active_bank_offset = layer2_active_bank_offset_pre + m_port_123b_layer2_offset; const u8 layer2_active_bank = m_port_123b_layer2_map_shadow ? m_nr_13_layer2_shadow_bank : m_nr_12_layer2_active_bank; const u8 layer2_active_page = ((layer2_active_bank + layer2_active_bank_offset) << 1) | BIT(bank, 0); const u16 layer2_A21_A13 = ((0b0001 + BIT(layer2_active_page, 5, 3)) << 5) | BIT(layer2_active_page, 0, 5); // sram_pre_romcs_replace = expbus_romcs_replace; const bool sram_pre_alt_en = nr_8c_altrom_en(); const bool sram_pre_alt_128_n = m_sram_alt_128_n; const bool sram_pre_rom3 = m_sram_rom3; const bool sram_pre_layer2_rd_en = m_port_123b_layer2_map_rd_en; const bool sram_pre_layer2_wr_en = m_port_123b_layer2_map_wr_en; const u16 sram_pre_layer2_A21_A13 = layer2_A21_A13; u16 sram_pre_A21_A13; // u9 u8 sram_pre_override; // u3: divmmc & layer 2 & romcs bool sram_pre_active, sram_pre_bank5, sram_pre_bank7, sram_pre_rdonly; if (is_rom) // 0-1 { const bool cpu_a13 = bank & 1; m_mf->enable_w(port_multiface_io_en()); if (m_mf->mf_enabled_r()) { sram_pre_A21_A13 = 0b000001010 | cpu_a13; sram_pre_active = 1; sram_pre_bank5 = sram_pre_bank7 = 0; sram_pre_rdonly = !cpu_a13; sram_pre_override = 0b000; } else if (BIT(~mmu_A21_A13, 8)) { sram_pre_A21_A13 = mmu_A21_A13 & 0xff; sram_pre_active = !mem_active_bank5 && !mem_active_bank7; sram_pre_bank5 = mem_active_bank5; sram_pre_bank7 = mem_active_bank7; sram_pre_rdonly = 0; sram_pre_override = 0b110; } else if (m_nr_03_config_mode) { sram_pre_A21_A13 = (m_nr_04_romram_bank << 1) | cpu_a13; sram_pre_active = 1; sram_pre_bank5 = sram_pre_bank7 = 0; sram_pre_rdonly = 0; sram_pre_override = 0b110; } else { sram_pre_A21_A13 = (m_sram_rom << 1) | cpu_a13; sram_pre_active = 1; sram_pre_bank5 = sram_pre_bank7 = 0; sram_pre_rdonly = !(nr_8c_altrom_en() && nr_8c_altrom_rw()); sram_pre_override = 0b111; } } else { sram_pre_A21_A13 = mmu_A21_A13 & 0xff; sram_pre_active = BIT(~mmu_A21_A13, 8) && !mem_active_bank5 && !mem_active_bank7; sram_pre_bank5 = mem_active_bank5; sram_pre_bank7 = mem_active_bank7; sram_pre_rdonly = 0; sram_pre_override = (((bank & 0x06) != 0x06) && (m_port_123b_layer2_map_segment == 0x03)) << 1; } const bool sram_pre_romcs_n = 0; // expbus_eff_en && !expbus_eff_disable_mem; const bool sram_romcs = BIT(sram_pre_override, 0) && sram_pre_romcs_n; const bool sram_divmmc_automap_en = BIT(sram_pre_override, 2); m_divmmc->cpu_a_15_13_w(bank); m_divmmc->en_w(port_divmmc_io_en()); m_divmmc->automap_reset_w(!port_divmmc_io_en() || !m_nr_0a_divmmc_automap_en); m_divmmc->automap_active_w(sram_divmmc_automap_en); for (s8 cpu_rd_n = 1; cpu_rd_n >= 0; --cpu_rd_n) // check W then R { const bool sram_layer2_map_en = BIT(sram_pre_override, 1) && ((sram_pre_layer2_wr_en && cpu_rd_n) || (sram_pre_layer2_rd_en && !cpu_rd_n)); const bool sram_altrom_en = !(BIT(~sram_pre_override, 0) || !sram_pre_alt_en || (sram_pre_rdonly && cpu_rd_n) || (!sram_pre_rdonly && !cpu_rd_n)); const bool sram_divmmc_automap_rom3_en = ((sram_pre_override & 0x05) == 0x05) && !sram_layer2_map_en && !sram_romcs && ((sram_altrom_en && sram_pre_alt_128_n) || (sram_pre_rom3 && !sram_altrom_en)); m_divmmc->automap_rom3_active_w(sram_divmmc_automap_rom3_en); m_divmmc->clock_w(); u16 sram_A21_A13; // u9 bool sram_active, sram_bank5, sram_bank7, sram_rdonly, sram_romcs_en, sram_mem_hide_n; if (BIT(sram_pre_override, 2) && m_divmmc->divmmc_rom_en_r()) { sram_A21_A13 = 0b000001000; sram_active = 1; sram_bank5 = sram_bank7 = 0; sram_rdonly = 1; sram_romcs_en = 0; sram_mem_hide_n = 0; } else if (BIT(sram_pre_override, 2) && m_divmmc->divmmc_ram_en_r()) { sram_A21_A13 = 0b000010000 | m_divmmc->divmmc_ram_bank_r(); sram_active = 1; sram_bank5 = sram_bank7 = 0; sram_rdonly = m_divmmc->divmmc_rdonly_r(); sram_romcs_en = 0; sram_mem_hide_n = 0; } else if (sram_layer2_map_en) { sram_A21_A13 = sram_pre_layer2_A21_A13 & 0xff; sram_active = BIT(~sram_pre_layer2_A21_A13, 8); sram_bank5 = sram_bank7 = 0; sram_rdonly = 0; sram_romcs_en = 0; sram_mem_hide_n = 0; } else if (sram_romcs) { sram_A21_A13 = 0b000011110 | BIT(sram_pre_A21_A13, 0); sram_active = 1; sram_bank5 = sram_bank7 = 0; sram_rdonly = 1; sram_romcs_en = 1; sram_mem_hide_n = 1; } else if (sram_altrom_en) { sram_A21_A13 = 0b000001100 | (sram_pre_alt_128_n << 1) | BIT(sram_pre_A21_A13, 0); sram_active = 1; sram_bank5 = sram_bank7 = 0; sram_rdonly = sram_pre_rdonly; sram_romcs_en = 0; sram_mem_hide_n = 1; } else { sram_A21_A13 = sram_pre_A21_A13; sram_active = sram_pre_active; sram_bank5 = sram_pre_bank5; sram_bank7 = sram_pre_bank7; sram_rdonly = sram_pre_rdonly; sram_romcs_en = 0; sram_mem_hide_n = BIT(sram_pre_override, 0); } if (false) // unused in current implementation, makes compiler happy printf("%d", sram_romcs_en); if (cpu_rd_n) // write cycle { m_page_shadow[bank] = sram_rdonly ? -1 : sram_A21_A13; } else // read cycle { if (sram_A21_A13 < m_ram_pages) { if (!sram_active && !sram_mem_hide_n && (sram_bank5 || sram_bank7)) { views[bank].get().select(sram_A21_A13); LOGMEM("RAM%d = bank%d\n", bank, sram_bank5 ? 5 : 7); m_page_shadow[bank] = -1; } else { const bool ro = sram_rdonly || (m_page_shadow[bank] != sram_A21_A13); m_bank_ram[bank]->set_entry(sram_A21_A13); views[bank].get().select(ro); LOGMEM("%s%d = %x\n", ro ? "ROM" : "RAM", bank, sram_A21_A13); if (!ro) { if (m_page_shadow[bank] == sram_A21_A13) m_page_shadow[bank] = -1; } } } else { views[bank].get().disable(); m_page_shadow[bank] = -1; } } } } void specnext_state::memory_change(u16 port, u8 data) // port_memory_change_dly { if (port_1ffd_special()) { u8 b3 = (BIT(m_port_1ffd_data, 2) || BIT(m_port_1ffd_data, 1)) << 3; mmu_x2_w(0, b3 | 0b000); const u8 b2 = (BIT(m_port_1ffd_data, 2) && BIT(m_port_1ffd_data, 1)) << 2; mmu_x2_w(2, b3 | b2 | 0b10); mmu_x2_w(4, b3 | 0b100); b3 = (BIT(~m_port_1ffd_data, 2) && BIT(m_port_1ffd_data, 1)) << 3; mmu_x2_w(6, b3 | 0b110); } else { const bool mode_profi = nr_8f_mapping_mode_profi(); if (BIT(m_port_eff7_data, 3) || (mode_profi && BIT(m_port_dffd_data, 4))) mmu_x2_w(0, 0x00); else mmu_x2_w(0, 0xff); if (mode_profi && BIT(m_port_dffd_data, 3)) mmu_x2_w(2, (port_7ffd_bank() << 1) | 0); else if (mode_profi || m_port_1ffd_special_old) mmu_x2_w(2, 0x0a); if (mode_profi && BIT(m_port_dffd_data, 6)) mmu_x2_w(4, 0x0c); else if (mode_profi || m_port_1ffd_special_old) mmu_x2_w(4, 0x04); const bool port_memory_ram_change_dly = !(port == 0x8e && !BIT(data, 3)); if (mode_profi && BIT(m_port_dffd_data, 3)) mmu_x2_w(6, 0x0e); else if (m_port_1ffd_special_old || port_memory_ram_change_dly) mmu_x2_w(6, (port_7ffd_bank() << 1) | 0); } m_port_1ffd_special_old = port_1ffd_special(); } void specnext_state::update_video_mode() { std::string machine_name; if (BIT(m_nr_03_machine_timing, 2)) { machine_name = "Pentagon"; m_video_timings = // Pentagon is always 50 Hz { 0, 448 + 3 - 12, 16, 47, 63, 128, 447, 0, 319, 1, 14, 15, 80, 319, 76, 435, 24, 311, 24 + 0 }; m_nr_05_5060 = 0; } else if (BIT(m_nr_03_machine_timing, 1)) { machine_name = BIT(m_nr_03_machine_timing, 0) ? "+3" : "128K"; if (!m_nr_05_5060) m_video_timings = // 128K 50 Hz { 0, u16(!BIT(m_nr_03_machine_timing, 0) ? 136 + 4 - 12 /* 128 */ : 136 + 2 - 12 /* +3 */), 16, 47, 95, 136, 455, 0, 1, 1, 4, 7, 64, 310, 88, 447, 16, 303, 16 + 4 }; else m_video_timings = // 128K 60 Hz { 0, u16(!BIT(m_nr_03_machine_timing, 0) ? 136 + 4 - 12 /* 128 */ : 136 + 2 - 12 /* +3 */), 16, 47, 95, 136, 455, 0, 0, 1, 4, 7, 40, 263, 88, 447, 16, 255, 16 + 0 }; } else { machine_name = "48K"; if (!m_nr_05_5060) m_video_timings = // 48K 50 Hz { 0, 128 + 0 - 12, 16, 47, 95, 128, 447, 0, 0, 1, 4, 7, 64, 311, 80, 439, 16, 303, 16 + 4 }; else m_video_timings = // 48K 60 Hz { 0, 128 + 0 - 12, 16, 47, 95, 128, 447, 0, 0, 1, 4, 7, 40, 263, 80, 439, 16, 255, 16 + 0 }; } const int left = m_video_timings.min_hactive << 1; const int top = m_video_timings.min_vactive; const int width = (m_video_timings.max_hc + 1) << 1; const int height = m_video_timings.max_vc + 1; m_clip256x192 = rectangle(left, left + (256 << 1) - 1, top, top + 192 - 1); m_clip320x256 = rectangle(left - (32 << 1), left + ((256 + 32) << 1) - 1, top - 32, top + 192 + 32 - 1); rectangle visarea = m_video_output_hdmi ? rectangle(m_video_timings.hdmi_xmin << 1, (m_video_timings.hdmi_xmax << 1) | 1, m_video_timings.hdmi_ymin, m_video_timings.hdmi_ymax) : m_clip320x256; // The visarea can't overlap with screen last vpos. Possibly related to https://github.com/mamedev/mame/pull/9945 visarea.max_y = std::min(visarea.max_y, height - 2); m_screen->configure(width, height, visarea, HZ_TO_ATTOSECONDS(28_MHz_XTAL / 2) * width * height); m_ula_scr->set_raster_offset(left, top); m_lores->set_raster_offset(left, top); m_tiles->set_raster_offset(left, top); m_layer2->set_raster_offset(left, top); m_sprites->set_raster_offset(left, top); m_eff_nr_03_machine_timing = m_nr_03_machine_timing; m_eff_nr_05_5060 = m_nr_05_5060; LOG("%s %dHz\n", machine_name, m_nr_05_5060 ? 60 : 50); } u32 specnext_state::screen_update(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect) { rectangle clip256x192 = m_clip256x192; clip256x192 &= cliprect; rectangle clip320x256 = m_clip320x256; clip320x256 &= cliprect; const u8 layers_dev = ~m_io_layers->read(); const bool tiles_en = m_nr_6b_tm_en && BIT(layers_dev, 0); const bool ula_en = m_nr_68_ula_en && BIT(layers_dev, 1); const bool layer2_en = m_port_123b_layer2_en && BIT(layers_dev, 2); const bool sprites_en = m_nr_15_sprite_en && BIT(layers_dev, 3); // background screen.priority().fill(0, cliprect); bitmap.fill(m_palette->pen_color(UTM_FALLBACK_PEN), cliprect); if (m_nr_15_layer_priority < 0b110) { static const u8 lcfg[][3] = { // tiles+ula priority; l2 priority; l2 mask // + l2 pushes priority colors to 8 (foreground) { 1, 1, 0 }, // SLU { 1, 8, 0 }, // LSU { 1, 1, 1 }, // SUL { 8, 8, 0 }, // LUS { 8, 1, 8 }, // USL { 8, 8, 8 } // ULS }; const u8 (&l)[3] = lcfg[m_nr_15_layer_priority]; if (tiles_en) m_tiles->draw(screen, bitmap, clip320x256, TILEMAP_DRAW_CATEGORY(1), l[0]); if (ula_en) { m_ula_scr->draw_border(screen, bitmap, cliprect, m_port_fe_data & 0x07); if (m_nr_15_lores_en) m_lores->draw(screen, bitmap, clip256x192, l[0]); else m_ula_scr->draw(screen, bitmap, clip256x192, l[0]); } if (tiles_en) m_tiles->draw(screen, bitmap, clip320x256, TILEMAP_DRAW_CATEGORY(2), l[0]); if (layer2_en) m_layer2->draw(screen, bitmap, clip320x256, l[1], l[2]); } else // colors mixing case { if (m_nr_68_blend_mode == 0b00) // Use ULA as blend layer { if (ula_en) { m_ula_scr->draw_border(screen, bitmap, cliprect, m_port_fe_data & 0x07, 1); if (m_nr_15_lores_en) m_lores->draw(screen, bitmap, clip256x192, 1); else m_ula_scr->draw(screen, bitmap, clip256x192, 1); } if (layer2_en) m_layer2->draw_mix(screen, bitmap, m_blendprio_bitmap, clip320x256, m_nr_15_layer_priority & 1); if (tiles_en) m_tiles->draw(screen, bitmap, clip320x256, TILEMAP_DRAW_ALL_CATEGORIES); if (layer2_en) m_layer2->copyprio(screen, bitmap, m_blendprio_bitmap, clip320x256); } else if (m_nr_68_blend_mode == 0b10) // Use result of ULA + Tilemap { if (tiles_en) m_tiles->draw(screen, bitmap, clip320x256, TILEMAP_DRAW_CATEGORY(1), 1); if (ula_en) { m_ula_scr->draw_border(screen, bitmap, cliprect, m_port_fe_data & 0x07, 1); if (m_nr_15_lores_en) m_lores->draw(screen, bitmap, clip256x192, 1); else m_ula_scr->draw(screen, bitmap, clip256x192, 1); } if (tiles_en) m_tiles->draw(screen, bitmap, clip320x256, TILEMAP_DRAW_CATEGORY(2), 1); if (layer2_en) m_layer2->draw_mix(screen, bitmap, bitmap, clip320x256, m_nr_15_layer_priority & 1); } else if (m_nr_68_blend_mode == 0b11) // Use Tilemap as blend layer { if (tiles_en) m_tiles->draw(screen, bitmap, clip320x256, TILEMAP_DRAW_ALL_CATEGORIES, 1); if (layer2_en) m_layer2->draw_mix(screen, bitmap, m_blendprio_bitmap, clip320x256, m_nr_15_layer_priority & 1); if (ula_en) { m_ula_scr->draw_border(screen, bitmap, cliprect, m_port_fe_data & 0x07); if (m_nr_15_lores_en) m_lores->draw(screen, bitmap, clip256x192); else m_ula_scr->draw(screen, bitmap, clip256x192); } if (layer2_en) m_layer2->copyprio(screen, bitmap, m_blendprio_bitmap, clip320x256); } else // 0b01 - No blending (disable blend) { if (tiles_en) m_tiles->draw(screen, bitmap, clip320x256, TILEMAP_DRAW_CATEGORY(1), 2); if (ula_en) { m_ula_scr->draw_border(screen, bitmap, cliprect, m_port_fe_data & 0x07); if (m_nr_15_lores_en) m_lores->draw(screen, bitmap, clip256x192, 2); else m_ula_scr->draw(screen, bitmap, clip256x192, 2); } if (tiles_en) m_tiles->draw(screen, bitmap, clip320x256, TILEMAP_DRAW_CATEGORY(2), 2); if (layer2_en) m_layer2->draw_mix(screen, bitmap, bitmap, clip320x256, m_nr_15_layer_priority & 1); } } // sprites below foreground if (sprites_en) m_sprites->draw(screen, bitmap, clip320x256, GFX_PMASK_8); return 0; } u32 specnext_state::internal_port_enable() const { u32 ports_en = (m_nr_85_internal_port_enable << 24) | (m_nr_84_internal_port_enable << 16) | (m_nr_83_internal_port_enable << 8) | (m_nr_82_internal_port_enable << 0); if (m_nr_80_expbus & 0x80) { ports_en &= (m_nr_89_bus_port_enable << 24) | (m_nr_88_bus_port_enable << 16) | (m_nr_87_bus_port_enable << 8) | (m_nr_86_bus_port_enable << 0); } return ports_en; } u16 specnext_state::nr_palette_dat() { u16 nr_palette_index = (BIT(m_nr_43_palette_write_select, 1) << 9) | (BIT(m_nr_43_palette_write_select, 2) << 8) | m_nr_palette_idx; if ((BIT(m_nr_43_palette_write_select, 1) != BIT(m_nr_43_palette_write_select, 0))) nr_palette_index |= 0x400; if (nr_palette_index >= 0x600) // sprites palette nr_palette_index += 0x100; rgb_t rgb = m_palette->pen_color(nr_palette_index); return ((rgb.r() >> 5) << 6) | ((rgb.g() >> 5) << 3) | ((rgb.b() >> 5) << 0); } void specnext_state::palette_val_w(u8 nr_palette_priority, u16 nr_palette_value) { m_screen->update_now(); u16 nr_palette_index = (BIT(m_nr_43_palette_write_select, 1) << 9) | (BIT(m_nr_43_palette_write_select, 2) << 8) | m_nr_palette_idx; if ((BIT(m_nr_43_palette_write_select, 1) xor BIT(m_nr_43_palette_write_select, 0))) nr_palette_index |= 0x400; m_layer2->pen_priority_w(nr_palette_index, BIT(nr_palette_priority, 1)); if (nr_palette_index < 0x600) { m_palette->set_pen_color(nr_palette_index, rgbexpand<3,3,3>(nr_palette_value, 6, 3, 0)); } else if (nr_palette_index < 0x700) // 6xx: sprites palette - duplicated at 6xx + 7xx { m_palette->set_pen_color(nr_palette_index, rgbexpand<3,3,3>(nr_palette_value, 6, 3, 0)); m_palette->set_pen_color(nr_palette_index + 0x100, rgbexpand<3,3,3>(nr_palette_value, 6, 3, 0)); } else // 7xx: sprites (alt) palette - duplicated at 8xx + 9xx { m_palette->set_pen_color(nr_palette_index + 0x100, rgbexpand<3,3,3>(nr_palette_value, 6, 3, 0)); m_palette->set_pen_color(nr_palette_index + 0x200, rgbexpand<3,3,3>(nr_palette_value, 6, 3, 0)); } } u8 specnext_state::port_ff_r() { return (m_nr_08_port_ff_rd_en && port_ff_io_en()) ? m_port_ff_data // ==port_ff_dat_tmx : floating_bus_r(); } void specnext_state::port_ff_w(u8 data) { m_screen->update_now(); m_port_ff_data = data; // ==port_ff_dat_tmx m_ula_scr->port_ff_reg_w(m_port_ff_data); nr_6a_lores_radastan_xor_w(m_nr_6a_lores_radastan_xor); } void specnext_state::ulatm_w(u8 data) { u16 nr_palette_value = (data << 1) | BIT(data, 1) | BIT(data, 0); u16 nr_palette_index_utm = (BIT(m_nr_43_palette_write_select, 2) << 8) | (0b11 << 6) | m_port_bf3b_ulap_index; m_palette->set_pen_color(nr_palette_index_utm, rgbexpand<3,3,3>(nr_palette_value, 3, 6, 0)); } void specnext_state::port_7ffd_reg_w(u8 data) { m_port_7ffd_data = data; m_ula_scr->ula_shadow_en_w(port_7ffd_shadow()); } void specnext_state::port_e3_reg_w(u8 data) { m_port_e3_reg = data & ~0x30; m_divmmc->divmmc_reg_w(m_port_e3_reg & ~0x30); bank_update(0, 2); } void specnext_state::port_e7_reg_w(u8 data) { if ((data & 3) == 0b10) m_port_e7_reg = 0b11111100 | (!m_nr_0a_sd_swap << 1) | m_nr_0a_sd_swap; else if ((data & 3) == 0x01) m_port_e7_reg = 0b11111100 | (m_nr_0a_sd_swap << 1) | !m_nr_0a_sd_swap; else if ((data == 0xfb) || (data == 0xf7)) m_port_e7_reg = data; else if ((data == 0x7f) && (m_nr_03_config_mode || BIT(m_nr_02_reset_type, 2))) m_port_e7_reg = 0x7f; else m_port_e7_reg = 0xff; // bit 7 = fpga flash, bit 3 = rpi1, bit 2 = rpi0, bit 1 = sd1, bit 0 = sd0 m_sdcards[0]->spi_ss_w(BIT(~m_port_e7_reg, 0)); m_sdcards[1]->spi_ss_w(BIT(~m_port_e7_reg, 1)); } u8 specnext_state::spi_data_r() { u8 din = m_spi_miso_dat; if (!machine().side_effects_disabled()) spi_data_w(0xff); return din; } void specnext_state::spi_data_w(u8 data) { m_spi_mosi_dat = data; #if TIMINGS_PERFECT m_spi_clock_cycles = 8; m_spi_clock->adjust(m_maincpu->clocks_to_attotime(1) / 4, 0, m_maincpu->clocks_to_attotime(1) / 4); #else for (u8 m = 0x80; m; m >>= 1) { for (int i = 0; i < 2; ++i) { m_sdcards[i]->spi_mosi_w(m_spi_mosi_dat & m ? 1 : 0); m_sdcards[i]->spi_clock_w(CLEAR_LINE); m_sdcards[i]->spi_clock_w(ASSERT_LINE); } } #endif } void specnext_state::spi_miso_w(u8 data) { m_spi_miso_dat <<= 1; m_spi_miso_dat |= data; } void specnext_state::i2c_scl_w(u8 data) { if (port_i2c_io_en()) { m_i2c_scl_data = data & 1; m_i2c->scl_write(m_i2c_scl_data); } } template u8 specnext_state::uart_reg_r() { if (!port_uart_io_en()) return 0x00; return m_uart[m_uart_select]->reg_r(Reg); } template void specnext_state::uart_reg_w(u8 data) { if (!port_uart_io_en()) return; if (Reg == 0b01) m_uart_select = BIT(data, 6); m_uart[m_uart_select]->reg_w(Reg, data); } template void specnext_state::txd_w(int state) { if (m_nr_0b_joy_iomode_en && BIT(m_nr_0b_joy_iomode, 1) && (Uart == m_nr_0b_joy_iomode_0)) m_midi_out->write_txd(state); } void specnext_state::rxd_w(int state) { if (m_nr_0b_joy_iomode_en && BIT(m_nr_0b_joy_iomode, 1)) m_uart[m_nr_0b_joy_iomode_0]->rx_w(state); } void specnext_state::turbosound_address_w(u8 data) { if ((data & 0x9c) == 0x9c) m_ay_select = (data & 3) % 3; else m_ay[m_nr_08_psg_turbosound_en ? m_ay_select : 0]->address_w(data); } template u8 specnext_state::mf_port_r(offs_t addr) { if (!machine().side_effects_disabled()) { u8 port_mf_enable_io_a = 0x3f; u8 port_mf_disable_io_a = 0xbf; if (m_nr_0a_mf_type & 2) { port_mf_enable_io_a = 0x9f; port_mf_disable_io_a = 0x1f; } else if (m_nr_0a_mf_type & 1) { port_mf_enable_io_a = 0xbf; port_mf_disable_io_a = 0x3f; } m_mf->port_mf_enable_rd_w(port_multiface_io_en() && (Lsb == port_mf_enable_io_a)); m_mf->port_mf_disable_rd_w(port_multiface_io_en() && (Lsb == port_mf_disable_io_a)); m_mf->port_mf_enable_wr_w(0); m_mf->port_mf_disable_wr_w(0); m_mf->clock_w(); bank_update(0, 2); } u8 data; if (!m_mf->mf_port_en_r()) data = Lsb == 0x1f ? kempston_md_r<0>(addr) : 0x00; else if (m_nr_0a_mf_type != 0b00) data = (BIT(m_port_7ffd_data, 3) << 7) | 0x7f; else { switch (BIT(addr, 12, 4)) { case 0b0001: data = m_port_1ffd_data; break; case 0b0111: data = m_port_7ffd_data; break; case 0b1101: data = m_port_dffd_data; break; case 0b1110: data = m_port_eff7_data & 0xc0; break; default: data = m_port_fe_data & 0x07; } } if (!machine().side_effects_disabled()) { m_mf->port_mf_enable_rd_w(0); m_mf->port_mf_disable_rd_w(0); } return data; } template u8 specnext_state::kempston_md_r(offs_t addr) { const bool mdL_1f_en = m_nr_05_joy0 == 0b101; const bool mdL_37_en = m_nr_05_joy0 == 0b110; const bool joyL_1f_en = m_nr_05_joy0 == 0b001 || mdL_1f_en; const bool joyL_37_en = m_nr_05_joy0 == 0b100 || mdL_37_en; const bool mdR_1f_en = m_nr_05_joy1 == 0b101; const bool mdR_37_en = m_nr_05_joy1 == 0b110; const bool joyR_1f_en = m_nr_05_joy1 == 0b001 || mdR_1f_en; const bool joyR_37_en = m_nr_05_joy1 == 0b100 || mdR_37_en; if (Joy == 0 && port_1f_io_en() && (joyL_1f_en || joyR_1f_en)) { u8 joyL_1f = m_io_joy_left->read(); if (!mdL_1f_en) joyL_1f &= 0x3f; if (!joyL_1f_en) joyL_1f &= 0xc0; u8 joyR_1f = m_io_joy_right->read(); if (!mdR_1f_en) joyR_1f &= 0x3f; if (!joyR_1f_en) joyR_1f &= 0xc0; return joyL_1f | joyR_1f; } else if (Joy == 1 && port_37_io_en() && (joyL_37_en || joyR_37_en)) { u8 joyL_37 = m_io_joy_left->read(); if (!mdL_37_en) joyL_37 &= 0x3f; if (!joyL_37_en) joyL_37 &= 0xc0; u8 joyR_37 = m_io_joy_right->read(); if (!mdR_37_en) joyR_37 &= 0x3f; if (!joyR_37_en) joyR_37 &= 0xc0; return joyL_37 | joyR_37; } else { return 0x00; } } u8 specnext_state::mouse_button_r() { u8 buttons = m_io_mouse[2]->read(); if (m_nr_0a_mouse_button_reverse) buttons = bitswap<3>(buttons, 2, 0, 1); return (m_io_mouse[3]->read() << 4) | buttons; } template void specnext_state::mf_port_w(offs_t addr, u8 data) { u8 port_mf_enable_io_a = 0x3f; u8 port_mf_disable_io_a = 0xbf; if (m_nr_0a_mf_type & 2) { port_mf_enable_io_a = 0x9f; port_mf_disable_io_a = 0x1f; } else if (m_nr_0a_mf_type & 1) { port_mf_enable_io_a = 0xbf; port_mf_disable_io_a = 0x3f; } m_mf->port_mf_enable_rd_w(0); m_mf->port_mf_disable_rd_w(0); m_mf->port_mf_enable_wr_w(port_multiface_io_en() && (Lsb == port_mf_enable_io_a)); m_mf->port_mf_disable_wr_w(port_multiface_io_en() && (Lsb == port_mf_disable_io_a)); m_mf->clock_w(); bank_update(0, 2); if (Lsb == 0x1f && m_nr_08_dac_en && port_dac_sd1_ABCD_1f0f4f5f_io_en()) { m_dac[0]->data_w(data); m_dac[1]->data_w(data); m_dac[2]->data_w(data); m_dac[3]->data_w(data); } else if (Lsb == 0x3f && m_nr_08_dac_en && port_dac_stereo_AD_3f5f_io_en()) { m_dac[0]->data_w(data); m_dac[3]->data_w(data); } m_mf->port_mf_enable_rd_w(0); m_mf->port_mf_disable_rd_w(0); } attotime specnext_state::copper_until_pos_r(u16 pos) { const u16 vcount = BIT(pos, 0, 9); const u16 hcount = BIT(pos, 9, 6) << 3; if (vcount > m_video_timings.max_vc || hcount > m_video_timings.max_hc) { LOGCOPPER("[%s] HALT\n", m_copper->tag()); return attotime::never; } else { if (BIT(pos, 15)) // MOVE { u16 vtarget = cvc_to_vpos(vcount); u16 htarget = ((hcount/* + 12*/) + m_video_timings.min_hactive + m_video_timings.max_hc) % m_video_timings.max_hc; if (htarget < (m_video_timings.min_hactive)) vtarget = (vtarget + 1) % m_screen->height(); htarget <<= 1; const u16 vpos = m_screen->vpos(); const u16 hpos = m_screen->hpos(); LOGCOPPER("[%s] [%02x, %03x] WAIT(%02x+%02x, %03x)\n", m_copper->tag(), vpos, hpos >> 1, m_nr_64_copper_offset, vcount, hcount); if (vtarget != vpos || htarget > hpos) return m_screen->time_until_pos(vtarget, htarget); else { LOGCOPPER("[%s] !WAIT\n", m_copper->tag()); return attotime::zero; } } else // FRAME or RESET { assert(!vcount && !hcount); LOGCOPPER("[%s] FRAME (0, 0)\n", m_copper->tag()); return m_screen->time_until_pos(cvc_to_vpos(0), m_video_timings.min_hactive << 1); } } } TIMER_CALLBACK_MEMBER(specnext_state::spi_clock) { if (m_spi_clock_cycles > 0) { if (m_spi_clock_state) { m_sdcards[0]->spi_clock_w(ASSERT_LINE); m_sdcards[1]->spi_clock_w(ASSERT_LINE); m_spi_clock_cycles--; } else { m_sdcards[0]->spi_mosi_w(BIT(m_spi_mosi_dat, m_spi_clock_cycles - 1)); m_sdcards[0]->spi_clock_w(CLEAR_LINE); m_sdcards[1]->spi_mosi_w(BIT(m_spi_mosi_dat, m_spi_clock_cycles - 1)); m_sdcards[1]->spi_clock_w(CLEAR_LINE); } m_spi_clock_state = !m_spi_clock_state; } else { m_spi_clock_state = false; m_spi_clock->reset(); } } void specnext_state::mmu_w(offs_t bank, u8 data) { m_mmu[bank] = data; bank_update(bank); } void specnext_state::mmu_x2_w(offs_t bank, u8 data) { mmu_w(bank, data); mmu_w(bank | 1, data == 0xff ? 0xff : (data | 1)); } u8 specnext_state::dma_r(bool dma_mode) { m_dma->dma_mode_w(dma_mode); return m_dma->read(); } void specnext_state::dma_w(bool dma_mode, u8 data) { m_dma->dma_mode_w(dma_mode); m_dma->write(data); } u8 specnext_state::dma_mreq_r(offs_t offset) { if (m_nr_07_cpu_speed == 0b11) { m_dma->adjust_wait(1); } return m_program.read_byte(offset); } void specnext_state::update_dma_delay() { const u16 dma_int_mask = (m_nr_cc_dma_int_en_0_7 << INT_PRIORITY_NMI) | ((m_nr_cc_dma_int_en_0_10 & 1) << INT_PRIORITY_ULA) | (m_nr_cd_dma_int_en_1 << INT_PRIORITY_CTC) | ((m_nr_cc_dma_int_en_0_10 >> 1) << INT_PRIORITY_LINE); m_dma->dma_delay_w((m_nr_c0_int_mode_pulse_0_im2_1 && (dma_int_mask & m_im2_int_status)) ? 1 : 0); if (m_nr_c0_int_mode_pulse_0_im2_1) LOGINTVVV("DMA delay %d (int_status=%04x, int_mask=%04x)\n", (dma_int_mask & m_im2_int_status) ? 1 : 0, m_im2_int_status, dma_int_mask); } u8 specnext_state::reg_r(offs_t nr_register) { u8 port_253b_dat; switch (nr_register) { case 0x00: port_253b_dat = g_machine_id(); break; case 0x01: port_253b_dat = G_VERSION; break; case 0x02: port_253b_dat = (m_nr_02_bus_reset << 7) | (0b00 << 5) | (nr_02_iotrap() << 4) | (m_nr_02_generate_mf_nmi << 3) | (m_nr_02_generate_divmmc_nmi << 2) | BIT(m_nr_02_reset_type, 0, 2); break; case 0x03: port_253b_dat = (m_nr_palette_sub_idx << 7) | (0b00 << 5) | (m_nr_03_machine_timing << 4) | (m_nr_03_user_dt_lock << 3) | m_nr_03_machine_type; break; case 0x05: port_253b_dat = (BIT(m_nr_05_joy0, 0, 2) << 6) | (BIT(m_nr_05_joy1, 0, 2) << 4) | (BIT(m_nr_05_joy0, 2) << 3) | (m_eff_nr_05_5060 << 2) | (BIT(m_nr_05_joy1, 2) << 1) | m_eff_nr_05_scandouble_en; break; case 0x06: port_253b_dat = (m_nr_06_hotkey_cpu_speed_en << 7) | (m_nr_06_internal_speaker_beep << 6) | (m_nr_06_hotkey_5060_en << 5) | (m_nr_06_button_drive_nmi_en << 4) | (m_nr_06_button_m1_nmi_en << 3) | (m_nr_06_ps2_mode << 2) | m_nr_06_psg_mode; break; case 0x07: { u8 cpu_speed = 0; for (u8 clock_scale = BIT(u8(m_maincpu->clock_scale()), 0, 4) >> 1; clock_scale; clock_scale >>= 1, ++cpu_speed); port_253b_dat = (0b00 << 6) | (cpu_speed << 4) | (0b00 << 2) | m_nr_07_cpu_speed; } break; case 0x08: port_253b_dat = ((!port_7ffd_locked()) << 7) | (m_eff_nr_08_contention_disable << 6) | (m_nr_08_psg_stereo_mode << 5) | (m_nr_08_internal_speaker_en << 4) | (m_nr_08_dac_en << 3) | (m_nr_08_port_ff_rd_en << 2) | (m_nr_08_psg_turbosound_en << 1) | m_nr_08_keyboard_issue2; break; case 0x09: port_253b_dat = (m_nr_09_psg_mono << 5) | (m_nr_09_sprite_tie << 4) | (0 << 3) | ((!m_nr_09_hdmi_audio_en) << 2) | m_nr_09_scanlines; // m_eff_nr_09_scanlines break; case 0x0a: port_253b_dat = (m_nr_0a_mf_type << 6) | (m_nr_0a_sd_swap << 5) | (m_nr_0a_divmmc_automap_en << 4) | (m_nr_0a_mouse_button_reverse << 3) | (0 << 2) | m_nr_0a_mouse_dpi; break; case 0x0b: port_253b_dat = (m_nr_0b_joy_iomode_en << 7) | (0 << 6) | (m_nr_0b_joy_iomode << 4) | (0b000 << 1) | m_nr_0b_joy_iomode_0; break; case 0x0e: port_253b_dat = G_SUB_VERSION; break; case 0x0f: port_253b_dat = (0b0000 << 4) | g_board_issue(); break; case 0x10: port_253b_dat = (0 << 7) | (m_nr_10_coreid << 2) | (m_io_nmi->read() & 3); break; case 0x11: port_253b_dat = (0b00000 << 3) | m_nr_11_video_timing; break; case 0x12: port_253b_dat = (0 << 7) | m_nr_12_layer2_active_bank; break; case 0x13: port_253b_dat = (0 << 7) | m_nr_13_layer2_shadow_bank; break; case 0x14: port_253b_dat = m_nr_14_global_transparent_rgb; break; case 0x15: port_253b_dat = (m_nr_15_lores_en << 7) | (m_nr_15_sprite_priority << 6) | (m_nr_15_sprite_border_clip_en << 5) | (m_nr_15_layer_priority << 2) | (m_nr_15_sprite_over_border_en << 1) | m_nr_15_sprite_en; break; case 0x16: port_253b_dat = m_nr_16_layer2_scrollx; break; case 0x17: port_253b_dat = m_nr_17_layer2_scrolly; break; case 0x18: switch (m_nr_18_layer2_clip_idx) { case 0b00: port_253b_dat = m_nr_18_layer2_clip_x1; break; case 0b01: port_253b_dat = m_nr_18_layer2_clip_x2; break; case 0b10: port_253b_dat = m_nr_18_layer2_clip_y1; break; default: port_253b_dat = m_nr_18_layer2_clip_y2; } break; case 0x19: switch (m_nr_19_sprite_clip_idx) { case 0b00: port_253b_dat = m_nr_19_sprite_clip_x1; break; case 0b01: port_253b_dat = m_nr_19_sprite_clip_x2; break; case 0b10: port_253b_dat = m_nr_19_sprite_clip_y1; break; default: port_253b_dat = m_nr_19_sprite_clip_y2; } break; case 0x1a: switch (m_nr_1a_ula_clip_idx) { case 0b00: port_253b_dat = m_nr_1a_ula_clip_x1; break; case 0b01: port_253b_dat = m_nr_1a_ula_clip_x2; break; case 0b10: port_253b_dat = m_nr_1a_ula_clip_y1; break; default: port_253b_dat = m_nr_1a_ula_clip_y2; } break; case 0x1b: switch (m_nr_1b_tm_clip_idx) { case 0b00: port_253b_dat = m_nr_1b_tm_clip_x1; break; case 0b01: port_253b_dat = m_nr_1b_tm_clip_x2; break; case 0b10: port_253b_dat = m_nr_1b_tm_clip_y1; break; default: port_253b_dat = m_nr_1b_tm_clip_y2; } break; case 0x1c: port_253b_dat = (m_nr_1b_tm_clip_idx << 6) | (m_nr_1a_ula_clip_idx << 4) | (m_nr_19_sprite_clip_idx << 2) | m_nr_18_layer2_clip_idx; break; case 0x1e: port_253b_dat = BIT(vpos_to_cvc(m_screen->vpos()), 8); break; case 0x1f: port_253b_dat = vpos_to_cvc(m_screen->vpos()) & 0xff; break; case 0x20: port_253b_dat = (BIT(m_im2_int_status, INT_PRIORITY_LINE) << 7) | (BIT(m_im2_int_status, INT_PRIORITY_ULA) << 6) | (0b00 << 4) | BIT(m_im2_int_status, INT_PRIORITY_CTC, 4); break; case 0x22: port_253b_dat = ((!m_pulse_int_n) << 7) | (0b0000 << 3) | (port_ff_interrupt_disable() << 2) | (m_nr_22_line_interrupt_en << 1) | BIT(m_nr_23_line_interrupt, 8); break; case 0x23: port_253b_dat = BIT(m_nr_23_line_interrupt, 0, 8); break; case 0x26: port_253b_dat = m_nr_26_ula_scrollx; break; case 0x27: port_253b_dat = m_nr_27_ula_scrolly; break; case 0x28: port_253b_dat = m_nr_stored_palette_value; break; case 0x2c: port_253b_dat = 0;//pi_audio_L(9 downto 2); //m_nr_2d_i2s_sample = pi_audio_L(1 downto 0); break; case 0x2d: port_253b_dat = (m_nr_2d_i2s_sample << 6) | 0b000000; break; case 0x2e: port_253b_dat = 0;//pi_audio_R(9 downto 2); //m_nr_2d_i2s_sample = pi_audio_R(1 downto 0); break; case 0x2f: port_253b_dat = (0b000000 << 2) | BIT(m_nr_30_tm_scrollx, 8, 2); break; case 0x30: port_253b_dat = BIT(m_nr_30_tm_scrollx, 0, 8); break; case 0x31: port_253b_dat = m_nr_31_tm_scrolly; break; case 0x32: port_253b_dat = m_nr_32_lores_scrollx; break; case 0x33: port_253b_dat = m_nr_33_lores_scrolly; break; case 0x34: port_253b_dat = m_sprites->mirror_num_r() & 0x7f; break; case 0x40: port_253b_dat = m_nr_palette_idx; break; case 0x41: port_253b_dat = BIT(nr_palette_dat(), 1, 8); break; case 0x42: port_253b_dat = m_nr_42_ulanext_format; break; case 0x43: port_253b_dat = (m_nr_43_palette_autoinc_disable << 7) | (m_nr_43_palette_write_select << 4) | (m_nr_43_active_sprite_palette << 3) | (m_nr_43_active_layer2_palette << 2) | (m_nr_43_active_ula_palette << 1) | m_nr_43_ulanext_en; break; case 0x44: port_253b_dat = (BIT(nr_palette_dat(), 9, 2) << 6) | (0b00000 << 1) | BIT(nr_palette_dat(), 0); break; case 0x4a: port_253b_dat = m_nr_4a_fallback_rgb; break; case 0x4b: port_253b_dat = m_nr_4b_sprite_transparent_index; break; case 0x4c: port_253b_dat = (0b0000 << 4) | m_nr_4c_tm_transparent_index; break; case 0x50: case 0x51: case 0x52: case 0x53: case 0x54: case 0x55: case 0x56: case 0x57: port_253b_dat = m_mmu[nr_register - 0x50]; break; case 0x61: port_253b_dat = BIT(m_nr_copper_addr, 0, 8); break; case 0x62: port_253b_dat = (m_nr_62_copper_mode << 6) | (0b000 << 3) | BIT(m_nr_copper_addr, 8, 3); break; case 0x64: port_253b_dat = m_nr_64_copper_offset; break; case 0x68: port_253b_dat = ((!m_nr_68_ula_en) << 7) | (m_nr_68_blend_mode << 5) | (m_nr_68_cancel_extended_keys << 4) | (m_port_ff3b_ulap_en << 3) | (m_nr_68_ula_fine_scroll_x << 2) | (0 << 1) | m_nr_68_ula_stencil_mode; break; case 0x69: port_253b_dat = (m_port_123b_layer2_en << 7) | (port_7ffd_shadow() << 6) | BIT(m_port_ff_data, 0, 6); break; case 0x6a: port_253b_dat = (0b00 << 6) | (m_nr_6a_lores_radastan << 5) | (m_nr_6a_lores_radastan_xor << 4) | m_nr_6a_lores_palette_offset; break; case 0x6b: port_253b_dat = (m_nr_6b_tm_en << 7) | m_nr_6b_tm_control; break; case 0x6c: port_253b_dat = m_nr_6c_tm_default_attr; break; case 0x6e: port_253b_dat = (m_nr_6e_tilemap_base_7 << 7) | (0 << 6) | m_nr_6e_tilemap_base; break; case 0x6f: port_253b_dat = (m_nr_6f_tilemap_tiles_7 << 7) | (0 << 6) | m_nr_6f_tilemap_tiles; break; case 0x70: port_253b_dat = (0b00 << 6) | (m_nr_70_layer2_resolution << 4) | m_nr_70_layer2_palette_offset; break; case 0x71: port_253b_dat = (0b0000000 << 1) | m_nr_71_layer2_scrollx_msb; break; case 0x7f: port_253b_dat = m_nr_7f_user_register_0; break; case 0x80: port_253b_dat = m_nr_80_expbus; break; case 0x81: port_253b_dat = /*(i_BUS_ROMCS_n <<) |*/ (m_nr_81_expbus_ula_override << 6) | (m_nr_81_expbus_nmi_debounce_disable << 5) | (m_nr_81_expbus_clken << 4) | (0b00 << 2) | m_nr_81_expbus_speed; break; case 0x82: port_253b_dat = m_nr_82_internal_port_enable; break; case 0x83: port_253b_dat = m_nr_83_internal_port_enable; break; case 0x84: port_253b_dat = m_nr_84_internal_port_enable; break; case 0x85: port_253b_dat = (m_nr_85_internal_port_reset_type << 7) | (0b000 << 4) | m_nr_85_internal_port_enable; break; case 0x86: port_253b_dat = m_nr_86_bus_port_enable; break; case 0x87: port_253b_dat = m_nr_87_bus_port_enable; break; case 0x88: port_253b_dat = m_nr_88_bus_port_enable; break; case 0x89: port_253b_dat = (m_nr_89_bus_port_reset_type << 7) | (0b000 << 4) | m_nr_89_bus_port_enable; break; case 0x8a: port_253b_dat = (0b00 << 6) | m_nr_8a_bus_port_propagate; break; case 0x8c: port_253b_dat = m_nr_8c_altrom; break; case 0x8e: port_253b_dat = (BIT(m_port_dffd_data, 0) << 7) | (BIT(m_port_7ffd_data, 0, 3) << 4) | (1 << 3) | (BIT(m_port_1ffd_data, 0) << 2) | (BIT(m_port_1ffd_data, 2) << 1) | ((BIT(m_port_7ffd_data, 4) && !BIT(m_port_1ffd_data, 0)) || (BIT(m_port_1ffd_data, 1) && BIT(m_port_1ffd_data, 0))); break; case 0x8f: port_253b_dat = (0b000000 << 2) | m_nr_8f_mapping_mode; break; case 0x90: port_253b_dat = m_nr_90_pi_gpio_o_en; break; case 0x91: port_253b_dat = m_nr_91_pi_gpio_o_en; break; case 0x92: port_253b_dat = m_nr_92_pi_gpio_o_en; break; case 0x93: port_253b_dat = (0b0000 << 4) | m_nr_93_pi_gpio_o_en; break; case 0x98: port_253b_dat = 0;//i_GPIO(7 downto 0); break; case 0x99: port_253b_dat = 0;//i_GPIO(15 downto 8); break; case 0x9a: port_253b_dat = 0;//i_GPIO(23 downto 16); break; case 0x9b: port_253b_dat = (0b0000 << 4);// | i_GPIO(27 downto 24); break; case 0xa0: port_253b_dat = (0b00 << 6) | (BIT(m_nr_a0_pi_peripheral_en, 3, 3) << 2) | (0b00 << 1) | BIT(m_nr_a0_pi_peripheral_en, 0); break; case 0xa2: port_253b_dat = (BIT(m_nr_a2_pi_i2s_ctl, 6, 2) << 6) | (0 << 5) | (BIT(m_nr_a2_pi_i2s_ctl, 2, 3) << 2) | (1 << 1) | BIT(m_nr_a2_pi_i2s_ctl, 0); break; case 0xa8: port_253b_dat = (0b0000000 << 7) | m_nr_a8_esp_gpio0_en; break; case 0xa9: port_253b_dat = (0b00000 << 3);// | (i_ESP_GPIO_20(2) <<) | (0 << 1) | i_ESP_GPIO_20(0); break; case 0xb0: port_253b_dat = 0;//(i_KBD_EXTENDED_KEYS(8) <<) | (i_KBD_EXTENDED_KEYS(9) <<) | (i_KBD_EXTENDED_KEYS(10) <<) | (i_KBD_EXTENDED_KEYS(11) <<) | (i_KBD_EXTENDED_KEYS(1) <<) | i_KBD_EXTENDED_KEYS(15 downto 13); break; case 0xb1: port_253b_dat = 0;//(i_KBD_EXTENDED_KEYS(12) <<) | (i_KBD_EXTENDED_KEYS(7 downto 2) <<) | i_KBD_EXTENDED_KEYS(0); break; case 0xb2: { u16 i_joy_left = m_io_joy_left->read(); u16 i_joy_right = m_io_joy_right->read(); port_253b_dat = (BIT(i_joy_right, 8, 3) << 5) | (BIT(i_joy_right, 11) << 4) | (BIT(i_joy_left, 8, 3) << 1) | BIT(i_joy_left, 11); } break; case 0xb8: port_253b_dat = m_nr_b8_divmmc_ep_0; break; case 0xb9: port_253b_dat = m_nr_b9_divmmc_ep_valid_0; break; case 0xba: port_253b_dat = m_nr_ba_divmmc_ep_timing_0; break; case 0xbb: port_253b_dat = m_nr_bb_divmmc_ep_1; break; case 0xc0: port_253b_dat = (m_nr_c0_im2_vector << 5) | (0 << 4) | (m_nr_c0_stackless_nmi << 3) | /*(z80_im_mode << 1) |*/ m_nr_c0_int_mode_pulse_0_im2_1; break; case 0xc2: port_253b_dat = m_nr_c2_retn_address_lsb; break; case 0xc3: port_253b_dat = m_nr_c3_retn_address_msb; break; case 0xc4: { const u8 ula_int_en = (m_nr_22_line_interrupt_en << 1) | !port_ff_interrupt_disable(); port_253b_dat = (m_nr_c4_int_en_0_expbus << 7) | (0b00000 << 2) | ula_int_en; } break; case 0xc5: port_253b_dat = m_ctc->ctrl_int_r(); break; case 0xc6: port_253b_dat = (0 << 7) | (m_nr_c6_int_en_2_654 << 4) | (0 << 3) | m_nr_c6_int_en_2_210; break; case 0xc8: port_253b_dat = (0b000000 << 2) | (BIT(m_im2_int_status, INT_PRIORITY_LINE) << 1) | BIT(m_im2_int_status, INT_PRIORITY_ULA); break; case 0xc9: port_253b_dat = BIT(m_im2_int_status, INT_PRIORITY_CTC, 8); break; case 0xca: port_253b_dat = (0b0 << 7) | (BIT(m_im2_int_status, INT_PRIORITY_UART1_TX) << 6) | (BIT(m_im2_int_status, INT_PRIORITY_UART1_RX) << 5) | (BIT(m_im2_int_status, INT_PRIORITY_UART1_RX) << 4) | (0b0 << 3) | (BIT(m_im2_int_status, INT_PRIORITY_UART0_TX) << 2) | (BIT(m_im2_int_status, INT_PRIORITY_UART0_RX) << 1) | BIT(m_im2_int_status, INT_PRIORITY_UART0_RX); break; case 0xcc: port_253b_dat = (m_nr_cc_dma_int_en_0_7 << 7) | (0b00000 << 2) | m_nr_cc_dma_int_en_0_10; break; case 0xcd: port_253b_dat = m_nr_cd_dma_int_en_1; break; case 0xce: port_253b_dat = (0 << 7) | (m_nr_ce_dma_int_en_2_654 << 4) | (0 << 3) | m_nr_ce_dma_int_en_2_210; break; case 0xd8: port_253b_dat = (0b0000000 << 1) | m_nr_d8_io_trap_fdc_en; break; case 0xd9: port_253b_dat = m_nr_d9_iotrap_write; break; case 0xda: port_253b_dat = (0b000000 << 2) | m_nr_da_iotrap_cause; break; case 0xf0: port_253b_dat = m_nr_f0_xdev_cmd; break; case 0xf8: port_253b_dat = (0 << 7) | m_nr_f8_xadc_daddr; break; case 0xf9: port_253b_dat = m_nr_f9_xadc_d0; break; case 0xfa: port_253b_dat = m_nr_fa_xadc_d1; break; default: port_253b_dat = 0x00; if (!machine().side_effects_disabled()) LOG("rR: %X -> %x\n", nr_register, port_253b_dat); } return port_253b_dat; } void specnext_state::reg_w(offs_t nr_wr_reg, u8 nr_wr_dat) { switch (nr_wr_reg) { case 0x02: LOGINTVVV("[RESET] %02x\n", nr_wr_dat); nr_02_w(nr_wr_dat); break; case 0x03: m_bootrom_en = 0; if (BIT(nr_wr_dat, 7) == 1 && m_nr_03_user_dt_lock == 0 && BIT(nr_wr_dat, 3) == 0) { switch (BIT(nr_wr_dat, 4, 3)) { case 0b000: m_nr_03_machine_timing = 0b001; break; case 0b001: m_nr_03_machine_timing = 0b001; break; case 0b010: m_nr_03_machine_timing = 0b010; break; case 0b011: m_nr_03_machine_timing = 0b011; break; case 0b100: m_nr_03_machine_timing = 0b100; break; default: m_nr_03_machine_timing = 0b011; } } m_nr_03_user_dt_lock = m_nr_03_user_dt_lock ^ BIT(nr_wr_dat, 3); if (m_nr_03_config_mode == 1) { switch (BIT(nr_wr_dat, 0, 3)) { case 0b001: m_nr_03_machine_type = 0b001; break; case 0b010: m_nr_03_machine_type = 0b010; break; case 0b011: m_nr_03_machine_type = 0b011; break; case 0b100: m_nr_03_machine_type = 0b100; break; } } if (BIT(nr_wr_dat, 0, 3) == 0b111) m_nr_03_config_mode = 1; else if (BIT(nr_wr_dat, 0, 3) != 0b000) m_nr_03_config_mode = 0; break; case 0x04: m_nr_04_romram_bank = nr_wr_dat & (m_ram_pages > 0x100 ? 0xff : 0x7f); // >2Mb (KS3+)? bank_update(0, 2); break; case 0x05: m_nr_05_joy0 = (BIT(nr_wr_dat, 3) << 2) | BIT(nr_wr_dat, 6, 2); m_nr_05_joy1 = (BIT(nr_wr_dat, 1) << 2) | BIT(nr_wr_dat, 4, 2); m_nr_05_5060 = BIT(nr_wr_dat, 2); break; case 0x06: m_nr_06_hotkey_cpu_speed_en = BIT(nr_wr_dat, 7); m_nr_06_internal_speaker_beep = BIT(nr_wr_dat, 6); m_nr_06_hotkey_5060_en = BIT(nr_wr_dat, 5); m_nr_06_button_drive_nmi_en = BIT(nr_wr_dat, 4); m_nr_06_button_m1_nmi_en = BIT(nr_wr_dat, 3); if (m_nr_03_config_mode == 1) m_nr_06_ps2_mode = BIT(nr_wr_dat, 2); m_nr_06_psg_mode = BIT(nr_wr_dat, 0, 2); break; case 0x07: nr_07_cpu_speed_w(BIT(nr_wr_dat, 0, 2)); break; case 0x08: m_nr_08_contention_disable = BIT(nr_wr_dat, 6); m_eff_nr_08_contention_disable = m_nr_08_contention_disable; m_nr_08_psg_stereo_mode = BIT(nr_wr_dat, 5); m_nr_08_internal_speaker_en = BIT(nr_wr_dat, 4); m_nr_08_dac_en = BIT(nr_wr_dat, 3); m_nr_08_port_ff_rd_en = BIT(nr_wr_dat, 2); m_nr_08_psg_turbosound_en = BIT(nr_wr_dat, 1); m_nr_08_keyboard_issue2 = BIT(nr_wr_dat, 0); if (BIT(nr_wr_dat, 7)) port_7ffd_reg_w(m_port_7ffd_data &= ~0x20); break; case 0x09: m_nr_09_psg_mono = BIT(nr_wr_dat, 5, 3); m_nr_09_sprite_tie = BIT(nr_wr_dat, 4); m_sprites->mirror_tie_w(m_nr_09_sprite_tie); m_nr_09_hdmi_audio_en = not BIT(nr_wr_dat, 2); if (BIT(nr_wr_dat, 3)) port_e3_reg_w(m_port_e3_reg & ~0x40); m_nr_09_scanlines = BIT(nr_wr_dat, 0, 2); break; case 0x0a: if (m_nr_03_config_mode == 1) { nr_0a_mf_type_w(BIT(nr_wr_dat, 6, 2)); m_nr_0a_sd_swap = BIT(nr_wr_dat, 5); } m_nr_0a_divmmc_automap_en = BIT(nr_wr_dat, 4); m_nr_0a_mouse_button_reverse = BIT(nr_wr_dat, 3); m_nr_0a_mouse_dpi = BIT(nr_wr_dat, 0, 2); break; case 0x0b: m_nr_0b_joy_iomode_en = BIT(nr_wr_dat, 7); m_nr_0b_joy_iomode = BIT(nr_wr_dat, 4, 2); m_nr_0b_joy_iomode_0 = BIT(nr_wr_dat, 0); break; case 0x10: m_nr_10_flashboot = BIT(nr_wr_dat, 7); if (m_nr_03_config_mode) { if (g_board_issue() <= 1) { m_nr_10_coreid = BIT(nr_wr_dat, 0, 5); } else if (g_board_issue() >= 2) { if (BIT(~nr_wr_dat, 4) && BIT(nr_wr_dat, 0, 4) != 0b1111) m_nr_10_coreid = BIT(nr_wr_dat, 0, 4); } } if (m_nr_10_flashboot) { // At this point (used by Anti-Brick), requested core start loading by FPGA: // 0 - Anti-Brick, 1 - Next, 2+ - others LOG("Loading CORE: %d\n", m_nr_10_coreid); m_nr_02_hard_reset = 1; machine().schedule_soft_reset(); } break; case 0x11: if (m_nr_03_config_mode == 1) { if (G_VIDEO_INC == 0b10) m_nr_11_video_timing = (0b00 << 1) | BIT(nr_wr_dat, 0); else { m_nr_11_video_timing = BIT(nr_wr_dat, 0, 3); // MAME supports only mode 0 (VGA) if (m_nr_11_video_timing > 0) { LOG("[Video Timing] Video mode %d selected but not supported\n", m_nr_11_video_timing); m_nr_11_video_timing = 0; } } } break; case 0x12: m_screen->update_now(); nr_12_layer2_active_bank_w(nr_wr_dat); break; case 0x13: m_screen->update_now(); nr_13_layer2_shadow_bank_w(nr_wr_dat); break; case 0x14: nr_14_global_transparent_rgb_w(nr_wr_dat); break; case 0x15: m_screen->update_now(); m_nr_15_lores_en = BIT(nr_wr_dat, 7); nr_15_sprite_priority_w(BIT(nr_wr_dat, 6)); nr_15_sprite_border_clip_en_w(BIT(nr_wr_dat, 5)); m_nr_15_layer_priority = BIT(nr_wr_dat, 2, 3); nr_15_sprite_over_border_en_w(BIT(nr_wr_dat, 1)); m_nr_15_sprite_en = BIT(nr_wr_dat, 0); break; case 0x16: m_screen->update_now(); nr_16_layer2_scrollx_w(nr_wr_dat); break; case 0x17: m_screen->update_now(); nr_17_layer2_scrolly_w(nr_wr_dat); break; case 0x18: switch (m_nr_18_layer2_clip_idx) { case 0b00: nr_18_layer2_clip_x1_w(nr_wr_dat); break; case 0b01: nr_18_layer2_clip_x2_w(nr_wr_dat); break; case 0b10: nr_18_layer2_clip_y1_w(nr_wr_dat); break; default: nr_18_layer2_clip_y2_w(nr_wr_dat); } ++m_nr_18_layer2_clip_idx &= 0x03; break; case 0x19: switch (m_nr_19_sprite_clip_idx) { case 0b00: nr_19_sprite_clip_x1_w(nr_wr_dat); break; case 0b01: nr_19_sprite_clip_x2_w(nr_wr_dat); break; case 0b10: nr_19_sprite_clip_y1_w(nr_wr_dat); break; default: nr_19_sprite_clip_y2_w(nr_wr_dat); } ++m_nr_19_sprite_clip_idx &= 0x03; break; case 0x1a: switch (m_nr_1a_ula_clip_idx) { case 0b00: nr_1a_ula_clip_x1_w(nr_wr_dat); break; case 0b01: nr_1a_ula_clip_x2_w(nr_wr_dat); break; case 0b10: nr_1a_ula_clip_y1_w(nr_wr_dat); break; default: nr_1a_ula_clip_y2_w(nr_wr_dat); } ++m_nr_1a_ula_clip_idx &= 0x03; break; case 0x1b: switch (m_nr_1b_tm_clip_idx) { case 0b00: nr_1b_tm_clip_x1_w(nr_wr_dat); break; case 0b01: nr_1b_tm_clip_x2_w(nr_wr_dat); break; case 0b10: nr_1b_tm_clip_y1_w(nr_wr_dat); break; default: nr_1b_tm_clip_y2_w(nr_wr_dat); } ++m_nr_1b_tm_clip_idx &= 0x03; break; case 0x1c: if (BIT(nr_wr_dat, 0) == 1) m_nr_18_layer2_clip_idx = 0b00; if (BIT(nr_wr_dat, 1) == 1) m_nr_19_sprite_clip_idx = 0b00; if (BIT(nr_wr_dat, 2) == 1) m_nr_1a_ula_clip_idx = 0b00; if (BIT(nr_wr_dat, 3) == 1) m_nr_1b_tm_clip_idx = 0b00; break; case 0x22: m_nr_22_line_interrupt_en = BIT(nr_wr_dat, 1); m_nr_23_line_interrupt = (m_nr_23_line_interrupt & ~0x0100) | (BIT(nr_wr_dat, 0) << 8); line_irq_adjust(); port_ff_w((m_port_ff_data & 0xbf) | (BIT(nr_wr_dat, 2) << 6)); LOGINT("[Line Interrupt Control] ULA: %d; Line: %d; Line#: %03x\n", BIT(~nr_wr_dat, 2), m_nr_22_line_interrupt_en, m_nr_23_line_interrupt); break; case 0x23: m_nr_23_line_interrupt = (m_nr_23_line_interrupt & ~0x00ff) | nr_wr_dat; line_irq_adjust(); LOGINT("[Line Interrupt Value] %03x\n", m_nr_23_line_interrupt); break; case 0x26: m_screen->update_now(); nr_26_ula_scrollx_w(nr_wr_dat); break; case 0x27: m_screen->update_now(); nr_27_ula_scrolly_w(nr_wr_dat); break; case 0x28: //nr_keymap_sel <= nr_wr_dat(7); //nr_keymap_addr(8) <= nr_wr_dat(0); break; case 0x29: //nr_keymap_addr(7 downto 0) <= nr_wr_dat; break; case 0x2a: break; case 0x2b: // nr_keymap_addr <= nr_keymap_addr + 1; break; case 0x2c: m_dac[1]->data_w(nr_wr_dat); break; case 0x2d: m_dac[0]->data_w(nr_wr_dat); m_dac[3]->data_w(nr_wr_dat); break; case 0x2e: m_dac[2]->data_w(nr_wr_dat); break; case 0x2f: m_screen->update_now(); nr_30_tm_scrollx_w((m_nr_30_tm_scrollx & ~0x0300) | (BIT(nr_wr_dat, 0, 2) << 8)); break; case 0x30: m_screen->update_now(); nr_30_tm_scrollx_w((m_nr_30_tm_scrollx & ~0x00ff) | nr_wr_dat); break; case 0x31: m_screen->update_now(); nr_31_tm_scrolly_w(nr_wr_dat); break; case 0x32: m_screen->update_now(); nr_32_lores_scrollx_w(nr_wr_dat); break; case 0x33: m_screen->update_now(); nr_33_lores_scrolly_w(nr_wr_dat); break; case 0x34: m_screen->update_now(); m_sprites->mirror_data_w(nr_wr_dat); break; case 0x35: case 0x36: case 0x37: case 0x38: case 0x39: case 0x75: case 0x76: case 0x77: case 0x78: case 0x79: m_screen->update_now(); m_sprites->mirror_inc_w(BIT(nr_wr_reg, 6)); m_sprites->mirror_index_w((nr_wr_reg & 0x3f) - 0x35); m_sprites->mirror_data_w(nr_wr_dat); break; case 0x40: m_nr_palette_idx = nr_wr_dat; m_nr_palette_sub_idx = 0; break; case 0x41: palette_val_w(0b00, (nr_wr_dat << 1) | BIT(nr_wr_dat, 1) | BIT(nr_wr_dat, 0)); if (m_nr_43_palette_autoinc_disable == 0) ++m_nr_palette_idx; m_nr_palette_sub_idx = 0; break; case 0x42: nr_42_ulanext_format_w(nr_wr_dat); break; case 0x43: m_screen->update_now(); m_nr_43_palette_autoinc_disable = BIT(nr_wr_dat, 7); m_nr_43_palette_write_select = BIT(nr_wr_dat, 4, 3); nr_43_active_sprite_palette_w(BIT(nr_wr_dat, 3)); nr_43_active_layer2_palette_w(BIT(nr_wr_dat, 2)); nr_43_active_ula_palette_w(BIT(nr_wr_dat, 1)); nr_43_ulanext_en_w(BIT(nr_wr_dat, 0)); m_nr_palette_sub_idx = 0; break; case 0x44: if (m_nr_palette_sub_idx == 0) m_nr_stored_palette_value = nr_wr_dat; else { palette_val_w(BIT(nr_wr_dat, 6, 2), (m_nr_stored_palette_value << 1) | BIT(nr_wr_dat, 0)); if (m_nr_43_palette_autoinc_disable == 0) ++m_nr_palette_idx; } m_nr_palette_sub_idx = !m_nr_palette_sub_idx; break; case 0x4a: { m_screen->update_now(); m_nr_4a_fallback_rgb = nr_wr_dat; rgb_t fb = rgbexpand<3,3,3>((m_nr_4a_fallback_rgb << 1) | BIT(m_nr_4a_fallback_rgb, 1) | BIT(m_nr_4a_fallback_rgb, 0), 6, 3, 0); m_palette->set_pen_color(UTM_FALLBACK_PEN, fb); } break; case 0x4b: m_screen->update_now(); nr_4b_sprite_transparent_index_w(nr_wr_dat); break; case 0x4c: m_screen->update_now(); nr_4c_tm_transparent_index_w(BIT(nr_wr_dat, 0, 4)); break; case 0x50: case 0x51: case 0x52: case 0x53: case 0x54: case 0x55: case 0x56: case 0x57: mmu_w(nr_wr_reg - 0x50, nr_wr_dat); break; case 0x60: case 0x63: { const bool nr_copper_write_8 = nr_wr_reg == 0x60; if (BIT(m_nr_copper_addr, 0) == 0) { if (nr_copper_write_8) m_copper->data_w(m_nr_copper_addr, nr_wr_dat); // msb } else { if (!nr_copper_write_8) m_copper->data_w(m_nr_copper_addr & ~1, m_nr_copper_data_stored); // msb m_copper->data_w(m_nr_copper_addr, nr_wr_dat); // lsb } if (BIT(m_nr_copper_addr, 0) == 0) m_nr_copper_data_stored = nr_wr_dat; ++m_nr_copper_addr %= 0x800; } break; case 0x61: m_nr_copper_addr = (m_nr_copper_addr & ~0x00ff) | nr_wr_dat; break; case 0x62: nr_62_copper_mode_w(BIT(nr_wr_dat, 6, 2)); m_nr_copper_addr = (m_nr_copper_addr & ~0x0700) | (BIT(nr_wr_dat, 0, 3) << 8); break; case 0x64: m_nr_64_copper_offset = nr_wr_dat; break; case 0x68: m_screen->update_now(); m_nr_68_ula_en = not BIT(nr_wr_dat, 7); m_nr_68_blend_mode = BIT(nr_wr_dat, 5, 2); m_nr_68_cancel_extended_keys = BIT(nr_wr_dat, 4); port_ff3b_ulap_en_w(BIT(nr_wr_dat, 3)); nr_68_ula_fine_scroll_x_w(BIT(nr_wr_dat, 2)); m_nr_68_ula_stencil_mode = BIT(nr_wr_dat, 0); break; case 0x69: port_ff_w((m_port_ff_data & 0xc0) | (nr_wr_dat & 0x3f)); port_7ffd_reg_w((m_port_7ffd_data & ~0x08) | (BIT(nr_wr_dat, 6) << 3)); port_123b_layer2_en_w(BIT(nr_wr_dat, 7)); break; case 0x6a: nr_6a_lores_radastan_w(BIT(nr_wr_dat, 5)); nr_6a_lores_radastan_xor_w(BIT(nr_wr_dat, 4)); nr_6a_lores_palette_offset_w(BIT(nr_wr_dat, 0, 4)); break; case 0x6b: m_screen->update_now(); m_nr_6b_tm_en = BIT(nr_wr_dat, 7); nr_6b_tm_control_w(BIT(nr_wr_dat, 0, 7)); break; case 0x6c: nr_6c_tm_default_attr_w(nr_wr_dat); break; case 0x6e: m_screen->update_now(); nr_6e_tilemap_base_w(BIT(nr_wr_dat, 7), BIT(nr_wr_dat, 0, 6)); break; case 0x6f: m_screen->update_now(); nr_6f_tilemap_tiles_w(BIT(nr_wr_dat, 7), BIT(nr_wr_dat, 0, 6)); break; case 0x70: m_screen->update_now(); nr_70_layer2_resolution_w(BIT(nr_wr_dat, 4, 2)); nr_70_layer2_palette_offset_w(BIT(nr_wr_dat, 0, 4)); break; case 0x71: nr_71_layer2_scrollx_msb_w(BIT(nr_wr_dat, 0)); break; case 0x7f: m_nr_7f_user_register_0 = nr_wr_dat; break; case 0x80: nr_80_expbus_w(nr_wr_dat); break; case 0x81: m_nr_81_expbus_ula_override = BIT(nr_wr_dat, 6); m_nr_81_expbus_nmi_debounce_disable = BIT(nr_wr_dat, 5); m_nr_81_expbus_clken = BIT(nr_wr_dat, 4); m_nr_81_expbus_speed = 0b00; break; case 0x82: m_nr_82_internal_port_enable = nr_wr_dat; break; case 0x83: m_nr_83_internal_port_enable = nr_wr_dat; break; case 0x84: m_nr_84_internal_port_enable = nr_wr_dat; break; case 0x85: m_nr_85_internal_port_enable = BIT(nr_wr_dat, 0, 4); m_nr_85_internal_port_reset_type = BIT(nr_wr_dat, 7); break; case 0x86: m_nr_86_bus_port_enable = nr_wr_dat; break; case 0x87: m_nr_87_bus_port_enable = nr_wr_dat; break; case 0x88: m_nr_88_bus_port_enable = nr_wr_dat; break; case 0x89: m_nr_89_bus_port_enable = BIT(nr_wr_dat, 0, 4); m_nr_89_bus_port_reset_type = BIT(nr_wr_dat, 7); break; case 0x8a: m_nr_8a_bus_port_propagate = BIT(nr_wr_dat, 0, 6); break; case 0x8c: m_nr_8c_altrom = nr_wr_dat; bank_update(0, 2); break; case 0x8e: LOGMEM("8e (%x): 1f=%x 7f=%x df=%x\n", nr_wr_dat, m_port_1ffd_data, m_port_7ffd_data, m_port_dffd_data); if (BIT(nr_wr_dat, 3)) { if (!nr_8f_mapping_mode_profi()) m_port_dffd_data &= ~0x08; m_port_dffd_data = (m_port_dffd_data & ~0x07) | BIT(nr_wr_dat, 7); port_7ffd_reg_w((m_port_7ffd_data & ~0x07) | BIT(nr_wr_dat, 4, 3)); } if (BIT(~nr_wr_dat, 2)) port_7ffd_reg_w((m_port_7ffd_data & ~0x10) | ((nr_wr_dat & 1) << 4)); m_port_1ffd_data = (m_port_1ffd_data & ~0x04) | (BIT(nr_wr_dat, 1) << 2); m_port_1ffd_data = (m_port_1ffd_data & ~0x02) | (BIT(nr_wr_dat, 0) << 1); m_port_1ffd_data = (m_port_1ffd_data & ~0x01) | BIT(nr_wr_dat, 2); memory_change(0x8e, nr_wr_dat); LOGMEM("8e: 1f=%x 7f=%x df=%x\n", m_port_1ffd_data, m_port_7ffd_data, m_port_dffd_data); break; case 0x8f: m_nr_8f_mapping_mode = BIT(nr_wr_dat, 0, 2); memory_change(0x8f, nr_wr_dat); break; case 0x90: m_nr_90_pi_gpio_o_en = (BIT(nr_wr_dat, 2, 6) << 2) | 0b00; break; case 0x91: m_nr_91_pi_gpio_o_en = nr_wr_dat; break; case 0x92: m_nr_92_pi_gpio_o_en = nr_wr_dat; break; case 0x93: m_nr_93_pi_gpio_o_en = BIT(nr_wr_dat, 0, 4); break; case 0x98: m_nr_98_pi_gpio_o = nr_wr_dat; break; case 0x99: m_nr_99_pi_gpio_o = nr_wr_dat; break; case 0x9a: m_nr_9a_pi_gpio_o = nr_wr_dat; break; case 0x9b: m_nr_9b_pi_gpio_o = BIT(nr_wr_dat, 0, 4); break; case 0xa0: m_nr_a0_pi_peripheral_en = nr_wr_dat; break; case 0xa2: m_nr_a2_pi_i2s_ctl = nr_wr_dat; break; case 0xa8: m_nr_a8_esp_gpio0_en = BIT(nr_wr_dat, 0); break; case 0xa9: m_nr_a9_esp_gpio0 = BIT(nr_wr_dat, 0); break; case 0xb8: m_nr_b8_divmmc_ep_0 = nr_wr_dat; break; case 0xb9: m_nr_b9_divmmc_ep_valid_0 = nr_wr_dat; break; case 0xba: m_nr_ba_divmmc_ep_timing_0 = nr_wr_dat; break; case 0xbb: m_nr_bb_divmmc_ep_1 = nr_wr_dat; break; case 0xc0: nr_c0_im2_vector_w(BIT(nr_wr_dat, 0), BIT(nr_wr_dat, 5, 3)); m_nr_c0_stackless_nmi = BIT(nr_wr_dat, 3); m_maincpu->nmi_stackless_w(m_nr_c0_stackless_nmi); LOGINT("[Interrupt Control] Vector: %02x; HW IM2: %d\n", m_nr_c0_im2_vector << 5, m_nr_c0_int_mode_pulse_0_im2_1); break; case 0xc2: m_nr_c2_retn_address_lsb = nr_wr_dat; break; case 0xc3: m_nr_c3_retn_address_msb = nr_wr_dat; break; case 0xc4: m_nr_c4_int_en_0_expbus = BIT(nr_wr_dat, 7); m_nr_22_line_interrupt_en = BIT(nr_wr_dat, 1); line_irq_adjust(); port_ff_w((m_port_ff_data & 0xbf) | (BIT(~nr_wr_dat, 0) << 6)); LOGINT("[INT EN 0] Line: %d; ULA: %d\n", m_nr_22_line_interrupt_en, BIT(nr_wr_dat, 0)); break; case 0xc5: { u8 active = BIT(nr_wr_dat, 0, 4); m_ctc->ctrl_int_w(active); } LOGINT("[INT EN 1] CTC7..0: %02x\n", nr_wr_dat); break; case 0xc6: m_nr_c6_int_en_2_654 = (BIT(nr_wr_dat, 6) << 2) | (BIT(nr_wr_dat, 5) << 1) | BIT(nr_wr_dat, 4); m_nr_c6_int_en_2_210 = (BIT(nr_wr_dat, 2) << 2) | (BIT(nr_wr_dat, 1) << 1) | BIT(nr_wr_dat, 0); break; case 0xcc: m_nr_cc_dma_int_en_0_7 = BIT(nr_wr_dat, 7); m_nr_cc_dma_int_en_0_10 = BIT(nr_wr_dat, 0, 2); LOGINT("[DMA INT EN 0] NMI: %d; Line: %d; ULA: %d\n", m_nr_cc_dma_int_en_0_7, m_nr_cc_dma_int_en_0_10 >> 1, m_nr_cc_dma_int_en_0_10 & 1); break; case 0xcd: m_nr_cd_dma_int_en_1 = nr_wr_dat; LOGINT("[DMA INT EN 1] CTC7..0: %02x\n", m_nr_cd_dma_int_en_1); break; case 0xce: m_nr_ce_dma_int_en_2_654 = BIT(nr_wr_dat, 4, 3); m_nr_ce_dma_int_en_2_210 = BIT(nr_wr_dat, 0, 3); break; case 0xcf: if (nr_wr_dat) LOG("wR: CF <- %x, but 0 expected\n", nr_wr_dat); break; case 0xd8: m_nr_d8_io_trap_fdc_en = BIT(nr_wr_dat, 0); break; case 0xd9: m_nr_d9_iotrap_write = nr_wr_dat; break; case 0xff: LOG("Debug: #%02X\n", nr_wr_dat); // LED break; default: LOG("wR: %X <- %x\n", nr_wr_reg, nr_wr_dat); break; } m_sprites->mirror_index_w(0b111); m_sprites->mirror_inc_w(0); } void specnext_state::nr_02_w(u8 nr_wr_dat) { m_nr_02_bus_reset = BIT(nr_wr_dat, 7); if (BIT(~nr_wr_dat, 4)) m_nr_da_iotrap_cause = 0; m_nr_02_generate_mf_nmi = BIT(nr_wr_dat, 3); m_nr_02_generate_divmmc_nmi = BIT(nr_wr_dat, 2); nmi_rq(); if (BIT(nr_wr_dat, 1)) // hard reset { m_nr_02_hard_reset = 1; machine().schedule_soft_reset(); } else if (BIT(nr_wr_dat, 0)) // soft reset { m_nr_02_reset_type = (BIT(m_nr_02_reset_type, 2) << 1) | BIT(m_nr_02_reset_type, 1) | BIT(m_nr_02_reset_type, 0); machine().schedule_soft_reset(); } } void specnext_state::nr_07_cpu_speed_w(u8 data) { m_nr_07_cpu_speed = data & 3; m_maincpu->set_clock_scale(1 << m_nr_07_cpu_speed); m_dma->set_clock_scale(1 << m_nr_07_cpu_speed); m_im2_line->set_clock_scale(1 << m_nr_07_cpu_speed); m_im2_ula->set_clock_scale(1 << m_nr_07_cpu_speed); } void specnext_state::nr_14_global_transparent_rgb_w(u8 data) { m_screen->update_now(); m_nr_14_global_transparent_rgb = data; m_ula_scr->set_global_transparent(data); m_tiles->set_global_transparent(data); m_lores->set_global_transparent(data); m_layer2->set_global_transparent(data); } void specnext_state::nr_1a_ula_clip_y2_w(u8 data) { m_nr_1a_ula_clip_y2 = data; const u8 ula_clip_y2_0 = ((m_nr_1a_ula_clip_y2 & 0xc0) == 0xc0) ? 0xbf : m_nr_1a_ula_clip_y2; m_ula_scr->ula_clip_y2_w(ula_clip_y2_0); m_lores->clip_y2_w(ula_clip_y2_0); } void specnext_state::nr_c0_im2_vector_w(bool mode_im2, u8 vector) { m_nr_c0_int_mode_pulse_0_im2_1 = mode_im2; m_nr_c0_im2_vector = vector; const u8 vector_base = mode_im2 ? m_nr_c0_im2_vector << 5 : 0xff; m_im2_line->vector_w(vector_base | (INT_PRIORITY_LINE << 1)); m_im2_uart0_rx->vector_w(vector_base | (INT_PRIORITY_UART0_RX << 1)); m_im2_uart1_rx->vector_w(vector_base | (INT_PRIORITY_UART1_RX << 1)); m_ctc->vector_w(vector_base); m_im2_ula->vector_w(vector_base | (INT_PRIORITY_ULA << 1)); m_im2_uart0_tx->vector_w(vector_base | (INT_PRIORITY_UART0_TX << 1)); m_im2_uart1_tx->vector_w(vector_base | (INT_PRIORITY_UART1_TX << 1)); } static const z80_daisy_config z80_daisy_chain[] = { { "im2_line" }, { "im2_uart0_rx" }, { "im2_uart1_rx" }, { "ctc" }, { "im2_ula" }, { "im2_uart0_tx" }, { "im2_uart1_tx" }, { nullptr } }; TIMER_CALLBACK_MEMBER(specnext_state::irq_off) { assert(m_nr_c0_int_mode_pulse_0_im2_1 == 0); m_im2_ula->irq_w(CLEAR_LINE); m_im2_line->irq_w(CLEAR_LINE); } TIMER_CALLBACK_MEMBER(specnext_state::irq_on) { LOGINTVVV("\n"); m_im2_ula->irq_w(ASSERT_LINE); if (m_nr_c0_int_mode_pulse_0_im2_1 == 0) m_irq_off_timer->adjust(m_maincpu->clocks_to_attotime(32)); } TIMER_CALLBACK_MEMBER(specnext_state::line_irq_on) { m_screen->update_now(); LOGINTVVV("\n"); m_im2_line->irq_w(ASSERT_LINE); if (m_nr_c0_int_mode_pulse_0_im2_1 == 0) m_irq_off_timer->adjust(m_maincpu->clocks_to_attotime(32)); } void specnext_state::irq_w(int state) { m_maincpu->set_input_line(INPUT_LINE_IRQ0, state); const std::array states = { m_im2_line->z80daisy_irq_state(), m_im2_uart0_rx->z80daisy_irq_state(), m_im2_uart1_rx->z80daisy_irq_state(), m_ctc->z80daisy_chanel_irq_state(0), m_ctc->z80daisy_chanel_irq_state(1), m_ctc->z80daisy_chanel_irq_state(2), m_ctc->z80daisy_chanel_irq_state(3), m_im2_ula->z80daisy_irq_state(), m_im2_uart0_tx->z80daisy_irq_state(), m_im2_uart1_tx->z80daisy_irq_state() }; const std::array masks = { 1 << INT_PRIORITY_LINE, 1 << INT_PRIORITY_UART0_RX, 1 << INT_PRIORITY_UART1_RX, 1 << (INT_PRIORITY_CTC + 0), 1 << (INT_PRIORITY_CTC + 1), 1 << (INT_PRIORITY_CTC + 2), 1 << (INT_PRIORITY_CTC + 3), 1 << INT_PRIORITY_ULA, 1 << INT_PRIORITY_UART0_TX, 1 << INT_PRIORITY_UART1_TX }; const int tmp = m_im2_int_status; m_im2_int_status = 0; for(int i = 0; i < states.size(); ++i) { m_im2_int_status |= (states[i] & Z80_DAISY_IEO) ? masks[i] : 0; if ((states[i] & Z80_DAISY_INT) && !m_im2_int_status) // only highest priority IRQ m_im2_int_status |= masks[i]; } m_im2_int_status |= tmp & (1 << INT_PRIORITY_NMI); LOGINTVVV("IRQs: %s %04x -> %04x\n", state ? "+" : "-", tmp, m_im2_int_status); update_dma_delay(); } INTERRUPT_GEN_MEMBER(specnext_state::specnext_interrupt) { m_tiles->control_w(m_nr_6b_tm_control); // TODO (1): Santa's Pressie, The Next War const bool tmp = ~m_io_video.read_safe(0) & 1; if (m_video_output_hdmi != tmp || m_eff_nr_05_5060 != m_nr_05_5060 || m_nr_03_machine_timing != m_eff_nr_03_machine_timing) { m_video_output_hdmi = tmp; update_video_mode(); } line_irq_adjust(); if (!port_ff_interrupt_disable()) { m_irq_on_timer->adjust(m_screen->time_until_pos(m_video_timings.int_v, m_video_timings.int_h << 1)); } } void specnext_state::line_irq_adjust() { if (m_nr_22_line_interrupt_en && (m_nr_23_line_interrupt <= m_video_timings.max_vc)) { u16 vtarget = m_nr_23_line_interrupt ? (m_nr_23_line_interrupt - 1) : m_video_timings.max_vc; m_irq_line_timer->adjust(m_screen->time_until_pos(cvc_to_vpos(vtarget), m_clip256x192.right())); } else m_irq_line_timer->reset(); } INPUT_CHANGED_MEMBER(specnext_state::on_nmi_button) { nmi_rq(); } void specnext_state::nmi_rq() { if (!m_nr_03_config_mode) { m_mf->button_w(nmi_assert_mf()); m_mf->clock_w(); m_divmmc->divmmc_button_w(nmi_assert_divmmc()); m_divmmc->clock_w(); if ((nmi_assert_mf() || nmi_assert_divmmc())) { LOGINTVVV("NMI: on (%s)\n", nmi_assert_mf() ? "MF" : "DivMMC"); m_maincpu->set_input_line(INPUT_LINE_NMI, ASSERT_LINE); m_maincpu->abort_timeslice(); m_im2_int_status |= 1 << INT_PRIORITY_NMI; update_dma_delay(); } } } void specnext_state::leave_nmi(int state) { m_mf->cpu_retn_seen_w(1); m_mf->clock_w(); m_mf->cpu_retn_seen_w(0); m_mf->clock_w(); m_divmmc->retn_seen_w(1); m_divmmc->clock_w(); m_divmmc->retn_seen_w(0); m_divmmc->clock_w(); m_im2_int_status &= ~(1 << INT_PRIORITY_NMI); update_dma_delay(); bank_update(0, 2); LOGINTVVV("NMI: off\n"); m_maincpu->set_input_line(INPUT_LINE_NMI, CLEAR_LINE); } u8 specnext_state::do_m1(offs_t offset) { u8 bank = offset >> 13; // pre M1 m_divmmc->cpu_mreq_n_w(1); m_divmmc->clock_w(); // M1 m_divmmc->cpu_mreq_n_w(0); m_divmmc->cpu_m1_n_w(0); m_divmmc->clock_w(); if (bank < 2) bank_update(bank); const u8 data = m_program.read_byte(offset); // after M1 m_divmmc->automap_instant_on_w(0); m_divmmc->automap_delayed_on_w(0); m_divmmc->automap_delayed_off_w(0); m_divmmc->automap_rom3_instant_on_w(0); m_divmmc->automap_rom3_delayed_on_w(0); m_divmmc->automap_nmi_instant_on_w(0); m_divmmc->automap_nmi_delayed_on_w(0); m_divmmc->cpu_m1_n_w(1); m_divmmc->cpu_mreq_n_w(1); m_divmmc->clock_w(); bank_update(0, 2); m_divmmc_delayed_check = 1; return data; } void specnext_state::map_fetch(address_map &map) { map(0x0000, 0xffff).lr8(NAME([this](offs_t offset) { if (!machine().side_effects_disabled()) { if (m_divmmc_delayed_check) { /* Happens after RW cycles (before next M1 fetch). Feels like side effects check must be ignored here, because doesn't matter who reset this lines and such approach gives better experience in debugger UI. */ do_m1(offset); m_divmmc_delayed_check = 0; // do_m1 performs read from m_program with waits, we need to take it back if (m_nr_07_cpu_speed == 0b11) { m_maincpu->adjust_icount(1); } } } return m_program.read_byte(offset); })); map(0x0000, 0x0000).select(0x0038).lr8(NAME([this](offs_t offset) { if (!machine().side_effects_disabled()) { const u8 b = offset >> 3; const bool divmmc_rst_ep = BIT(m_nr_b8_divmmc_ep_0, b); const bool divmmc_rst_ep_valid = BIT(m_nr_b9_divmmc_ep_valid_0, b); const bool divmmc_rst_ep_timing = BIT(m_nr_ba_divmmc_ep_timing_0, b); m_divmmc->automap_instant_on_w(divmmc_rst_ep && divmmc_rst_ep_valid && divmmc_rst_ep_timing); m_divmmc->automap_delayed_on_w(divmmc_rst_ep && divmmc_rst_ep_valid && !divmmc_rst_ep_timing); m_divmmc->automap_rom3_instant_on_w(divmmc_rst_ep && !divmmc_rst_ep_valid && divmmc_rst_ep_timing); m_divmmc->automap_rom3_delayed_on_w(divmmc_rst_ep && !divmmc_rst_ep_valid && !divmmc_rst_ep_timing); return do_m1(offset); } else return m_program.read_byte(offset); })); map(0x1ff8, 0x1fff).lr8(NAME([this](offs_t offset) { if (!machine().side_effects_disabled()) { m_divmmc->automap_delayed_off_w(BIT(m_nr_bb_divmmc_ep_1, 6)); return do_m1(0x1ff8 + offset); } else return m_program.read_byte(0x1ff8 + offset); })); map(0x3d00, 0x3dff).lr8(NAME([this](offs_t offset) { if (!machine().side_effects_disabled()) { m_divmmc->automap_rom3_instant_on_w(BIT(m_nr_bb_divmmc_ep_1, 7)); return do_m1(0x3d00 + offset); } else return m_program.read_byte(0x3d00 + offset); })); map(0x04c6, 0x04c6).lr8(NAME([this](offs_t offset) { if (!machine().side_effects_disabled()) { m_divmmc->automap_rom3_delayed_on_w(BIT(m_nr_bb_divmmc_ep_1, 2)); return do_m1(0x04c6 + offset); } else return m_program.read_byte(0x04c6 + offset); })); map(0x0562, 0x0562).lr8(NAME([this](offs_t offset) { if (!machine().side_effects_disabled()) { m_divmmc->automap_rom3_delayed_on_w(BIT(m_nr_bb_divmmc_ep_1, 3)); return do_m1(0x0562 + offset); } else return m_program.read_byte(0x0562 + offset); })); map(0x04d7, 0x04d7).lr8(NAME([this](offs_t offset) { if (!machine().side_effects_disabled()) { m_divmmc->automap_rom3_delayed_on_w(BIT(m_nr_bb_divmmc_ep_1, 4)); return do_m1(0x04d7 + offset); } else return m_program.read_byte(0x04d7 + offset); })); map(0x056a, 0x056a).lr8(NAME([this](offs_t offset) { if (!machine().side_effects_disabled()) { m_divmmc->automap_rom3_delayed_on_w(BIT(m_nr_bb_divmmc_ep_1, 5)); return do_m1(0x056a + offset); } else return m_program.read_byte(0x056a + offset); })); map(0x0066, 0x0066).lr8(NAME([this](offs_t offset) { if (!machine().side_effects_disabled()) { m_mf->cpu_m1_n_w(0); m_mf->cpu_a_0066_w(1); m_mf->cpu_mreq_n_w(0); m_mf->clock_w(); m_divmmc->automap_nmi_instant_on_w(BIT(m_nr_bb_divmmc_ep_1, 1)); m_divmmc->automap_nmi_delayed_on_w(BIT(m_nr_bb_divmmc_ep_1, 0)); u8 data = do_m1(0x0066 + offset); m_mf->cpu_a_0066_w(0); m_mf->cpu_m1_n_w(1); m_mf->clock_w(); return data; } else return m_program.read_byte(0x0066 + offset); })); } void specnext_state::map_mem(address_map &map) { using views_link = std::reference_wrapper; views_link views[] = { m_view0, m_view1, m_view2, m_view3, m_view4, m_view5, m_view6, m_view7 }; for (auto i = 0; i < 8; i++) { map(0x0000 + i * 0x2000, 0x1fff + i * 0x2000).noprw(); map(0x0000 + i * 0x2000, 0x1fff + i * 0x2000).view(views[i].get()); views[i].get()[0](0x0000 + i * 0x2000, 0x1fff + i * 0x2000).bankrw(m_bank_ram[i]); views[i].get()[1](0x0000 + i * 0x2000, 0x1fff + i * 0x2000).bankr(m_bank_ram[i]); // bank5 views[i].get()[0x2a](0x0000 + i * 0x2000, 0x1fff + i * 0x2000).lrw8( NAME([this](offs_t offset) { return m_bram_bank5[offset & 0x1fff]; }), NAME([this](offs_t offset, u8 data) { m_screen->update_now(); m_bram_bank5[offset & 0x1fff] = data; }) ); views[i].get()[0x2b](0x0000 + i * 0x2000, 0x1fff + i * 0x2000).lrw8( NAME([this](offs_t offset) { return m_bram_bank5[0x2000 + (offset & 0x1fff)]; }), NAME([this](offs_t offset, u8 data) { m_screen->update_now(); m_bram_bank5[0x2000 + (offset & 0x1fff)] = data; }) ); // bank7 views[i].get()[0x2e](0x0000 + i * 0x2000, 0x1fff + i * 0x2000).lrw8( NAME([this](offs_t offset) { return m_bram_bank7[offset & 0x1fff]; }), NAME([this](offs_t offset, u8 data) { m_screen->update_now(); m_bram_bank7[offset & 0x1fff] = data; }) ); } views[0].get()[2](0x0000, 0x1fff).bankr(m_bank_boot_rom); views[1].get()[2](0x2000, 0x3fff).bankr(m_bank_boot_rom); } void specnext_state::map_io(address_map &map) { map.unmap_value_high(); map(0x0000, 0xffff).unmaprw(); map(0x0000, 0x0000).select(0xfffe).rw(FUNC(specnext_state::spectrum_ula_r), FUNC(specnext_state::spectrum_ula_w)); map(0x00ff, 0x00ff).mirror(0xff00).rw(FUNC(specnext_state::port_ff_r), FUNC(specnext_state::port_ff_w)); map(0x001f, 0x001f).select(0xff00).rw(FUNC(specnext_state::mf_port_r<0x1f>), FUNC(specnext_state::mf_port_w<0x1f>)); map(0x003f, 0x003f).select(0xff00).rw(FUNC(specnext_state::mf_port_r<0x3f>), FUNC(specnext_state::mf_port_w<0x3f>)); map(0x009f, 0x009f).select(0xff00).rw(FUNC(specnext_state::mf_port_r<0x9f>), FUNC(specnext_state::mf_port_w<0x9f>)); map(0x00bf, 0x00bf).select(0xff00).rw(FUNC(specnext_state::mf_port_r<0xbf>), FUNC(specnext_state::mf_port_w<0xbf>)); map(0x0001, 0x0001).mirror(0xfff4).lr8(NAME([this]() { // #bff5 return m_nr_08_psg_turbosound_en ? m_ay_select : 0; })); map(0xc005, 0xc005).mirror(0x3ff8).lr8(NAME([this]() { // #fffd return m_ay[m_nr_08_psg_turbosound_en ? m_ay_select : 0]->data_r(); })).w(FUNC(specnext_state::turbosound_address_w)); map(0x8005, 0x8005).mirror(0x3ff8).lw8(NAME([this](u8 data) { // #bffd m_ay[m_nr_08_psg_turbosound_en ? m_ay_select : 0]->data_w(data); })); map(0x0001, 0x0001).select(0x7ffc).lw8(NAME([this](offs_t offset, u8 data) { const bool p3_timing_hw_en = (m_nr_03_machine_timing & 3) == 0b11; if (port_7ffd_io_en() && (BIT(offset, 14) || !p3_timing_hw_en) && !port_7ffd_locked()) { port_7ffd_reg_w(data); memory_change(0x7ffd, data); } })); map(0xd001, 0xd001).mirror(0x0ffc).lw8(NAME([this](u8 data) { if (port_dffd_io_en() && (!port_7ffd_locked() || nr_8f_mapping_mode_profi())) { m_port_dffd_data = data; memory_change(0xdffd, data); } })); map(0x1001, 0x1001).mirror(0x0ffc).lw8(NAME([this](u8 data) { if (port_1ffd_io_en() && !port_7ffd_locked()) { m_port_1ffd_data = data; memory_change(0x1ffd, data); } })); map(0xe0f7, 0xe0f7).mirror(0x0f00).lw8(NAME([this](u8 data) { if (port_eff7_io_en()) { m_port_eff7_data = data; memory_change(0xeff7, data); } })); map(0x2001, 0x2001).mirror(0x0ffc).lr8(NAME([]() { return /*m_nr_d8_io_trap_fdc_en ? ... :*/ 0xff; })); map(0x3001, 0x3001).mirror(0x0ffc).lrw8(NAME([]() { return /*m_nr_d8_io_trap_fdc_en ? ... :*/ 0xff; }), NAME([this](u8 data) { if (m_nr_d8_io_trap_fdc_en) { } })); map(0x103b, 0x103b).lr8(NAME([this]() { return port_i2c_io_en() ? (0xfe | m_i2c_scl_data) : 0x00; })).w(FUNC(specnext_state::i2c_scl_w)); map(0x113b, 0x113b).lrw8(NAME([this]() { return port_i2c_io_en() ? (0xfe | (m_i2c_sda_data & 1)) : 0x00; }), NAME([this](u8 data) { if (port_i2c_io_en()) m_i2c->sda_write(data & 1); })); map(0x183b, 0x183b).select(0x0700).lrw8(NAME([this](offs_t offset) { u8 chanel = offset >> 8; return port_ctc_io_en() && (chanel < 4) ? m_ctc->read(chanel) : 0x00; }), NAME([this](offs_t offset, u8 data) { u8 chanel = offset >> 8; if (port_ctc_io_en() && (chanel < 4)) { m_ctc->write(chanel, data); m_maincpu->abort_timeslice(); // TODO: Must the CTC take care of this? } })); map(0x123b, 0x123b).lrw8(NAME([this]() { return (m_port_123b_layer2_map_segment << 6) | (0b00 << 4) | (m_port_123b_layer2_map_shadow << 3) | (m_port_123b_layer2_map_rd_en << 2) | (m_port_123b_layer2_en << 1) | m_port_123b_layer2_map_wr_en; }), NAME([this](u8 data) { if (BIT(~data, 4)) { port_123b_layer2_en_w(BIT(data, 1)); m_port_123b_layer2_map_wr_en = BIT(data, 0); m_port_123b_layer2_map_rd_en = BIT(data, 2); m_port_123b_layer2_map_shadow = BIT(data, 3); m_port_123b_layer2_map_segment = BIT(data, 6, 2); } else m_port_123b_layer2_offset = BIT(data, 0, 3); bank_update(0, 6); })); map(0x133b, 0x133b).rw(FUNC(specnext_state::uart_reg_r<3>), FUNC(specnext_state::uart_reg_w<3>)); map(0x143b, 0x143b).rw(FUNC(specnext_state::uart_reg_r<0>), FUNC(specnext_state::uart_reg_w<0>)); map(0x153b, 0x153b).w(FUNC(specnext_state::uart_reg_w<1>)); map(0x163b, 0x163b).w(FUNC(specnext_state::uart_reg_w<2>)); map(0x243b, 0x243b).lrw8(NAME([this]() { return m_nr_register; }) , NAME([this](u8 data) { m_nr_register = data; })); map(0x253b, 0x253b).lrw8(NAME([this]() { return m_next_regs.read_byte(m_nr_register); }) , NAME([this](u8 data) { m_next_regs.write_byte(m_nr_register, data); })); map(0x303b, 0x303b).lrw8(NAME([this]() { return port_sprite_io_en() ? m_sprites->status_r() : 0x00; }), NAME([this](u8 data) { if (port_sprite_io_en()) m_sprites->io_w(0x303b, data); })); map(0xbf3b, 0xbf3b).lw8(NAME([this](u8 data) { if (port_ulap_io_en()) { m_port_bf3b_ulap_mode = BIT(data, 6, 2); if (BIT(data, 6, 2) == 0b00) m_port_bf3b_ulap_index = BIT(data, 0, 6); } })); // ULA+ Register map(0xff3b, 0xff3b).lrw8(NAME([this]() { u8 port_ff3b_dat = 0x00; if (port_ulap_io_en()) { port_ff3b_dat = m_port_bf3b_ulap_mode == 0b00 ? bitswap<8>(nr_palette_dat(), 5, 4, 3, 8, 7, 6, 2, 1) : m_port_ff3b_ulap_en; } return port_ff3b_dat; }), NAME([this](u8 data) { if (port_ulap_io_en()) { if (m_port_bf3b_ulap_mode == 0b00) ulatm_w(data); else if (m_port_bf3b_ulap_mode == 0b01) port_ff3b_ulap_en_w(BIT(data, 0)); } })); // ULA+ Data map(0x0057, 0x0057).mirror(0xff00).lw8(NAME([this](u8 data) { if (port_sprite_io_en()) m_sprites->io_w(0x0057, data); })); map(0x005b, 0x005b).mirror(0xff00).lw8(NAME([this](u8 data) { if (port_sprite_io_en()) m_sprites->io_w(0x005b, data); })); map(0x00e7, 0x00e7).mirror(0xff00).w(FUNC(specnext_state::port_e7_reg_w)); map(0x00e3, 0x00e3).mirror(0xff00).lrw8(NAME([this]() { return port_divmmc_io_en() ? m_port_e3_reg & ~0x30 : 0x00; }) , NAME([this](u8 data) { if (port_divmmc_io_en()) { port_e3_reg_w((m_port_e3_reg & 0x40) | data); }})); map(0x00eb, 0x00eb).mirror(0xff00).rw(FUNC(specnext_state::spi_data_r), FUNC(specnext_state::spi_data_w)); map(0x000b, 0x000b).mirror(0xff00).lrw8(NAME([this]() { return dma_r(1); }), NAME([this](u8 data) { dma_w(1, data); })); map(0x006b, 0x006b).mirror(0xff00).lrw8(NAME([this]() { return dma_r(0); }), NAME([this](u8 data) { dma_w(0, data); })); map(0x0bdf, 0x0bdf).mirror(0xf000).lr8(NAME([this]() { return m_io_mouse[0]->read() >> m_nr_0a_mouse_dpi; })); // #fbdf map(0x0fdf, 0x0fdf).mirror(0xf000).lr8(NAME([this]() { return m_io_mouse[1]->read() >> m_nr_0a_mouse_dpi; })); // #ffdf map(0x0adf, 0x0adf).mirror(0xf000).r(FUNC(specnext_state::mouse_button_r)); // #fadf map(0x0037, 0x0037).mirror(0xff00).r(FUNC(specnext_state::kempston_md_r<1>)); map(0x00f1, 0x00f1).mirror(0xff00).lw8(NAME([this](u8 data) { if (m_nr_08_dac_en) m_dac[0]->data_w(data); })); map(0x000f, 0x000f).mirror(0xff00).lw8(NAME([this](u8 data) { if (m_nr_08_dac_en) m_dac[1]->data_w(data); })); map(0x00f3, 0x00f3).mirror(0xff00).lw8(NAME([this](u8 data) { if (m_nr_08_dac_en) m_dac[1]->data_w(data); })); map(0x00df, 0x00df).mirror(0xff00).lw8(NAME([this](u8 data) { if (m_nr_08_dac_en && port_dac_mono_AD_df_io_en()) { m_dac[0]->data_w(data); m_dac[3]->data_w(data); } })); map(0x00fb, 0x00fb).mirror(0xff00).lw8(NAME([this](u8 data) { if (m_nr_08_dac_en && port_dac_mono_AD_fb_io_en()) { m_dac[0]->data_w(data); m_dac[3]->data_w(data); } })); map(0x00b3, 0x00b3).mirror(0xff00).lw8(NAME([this](u8 data) { if (m_nr_08_dac_en && port_dac_mono_BC_b3_io_en()) { m_dac[1]->data_w(data); m_dac[2]->data_w(data); } })); map(0x004f, 0x004f).mirror(0xff00).lw8(NAME([this](u8 data) { if (m_nr_08_dac_en) m_dac[2]->data_w(data); })); map(0x00f9, 0x00f9).mirror(0xff00).lw8(NAME([this](u8 data) { if (m_nr_08_dac_en) m_dac[2]->data_w(data); })); map(0x005f, 0x005f).mirror(0xff00).lw8(NAME([this](u8 data) { if (m_nr_08_dac_en) m_dac[3]->data_w(data); })); map(0x0000, 0xffff).view(m_io_expbus_view); m_io_expbus_view[0]; // exp bus disabled subdevice("zxbus")->set_io_space(m_io_expbus_view[1], m_io_expbus_view[1]); } void specnext_state::map_regs(address_map &map) { map(0x00, 0xff).rw(FUNC(specnext_state::reg_r), FUNC(specnext_state::reg_w)); } INPUT_PORTS_START(specnext) PORT_INCLUDE(spec_plus) PORT_MODIFY("CONFIG") PORT_BIT(0xff, IP_ACTIVE_HIGH, IPT_UNUSED) // PS/2 Keyboard Mapping PORT_MODIFY("PLUS0") PORT_BIT(0x01, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("EDIT") PORT_CODE(KEYCODE_TILDE) PORT_CHAR('`') PORT_CHAR('~') PORT_BIT(0x04, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("TRUE VID") PORT_CODE(KEYCODE_TAB) PORT_CHAR('\t') PORT_BIT(0x08, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("INV VID") PORT_CODE(KEYCODE_BACKSLASH) PORT_CHAR('\\') PORT_CHAR('|') PORT_MODIFY("PLUS1") PORT_BIT(0x02, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("GRAPH") PORT_CODE(KEYCODE_RALT) PORT_MODIFY("PLUS2") PORT_BIT(0x01, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("BREAK") PORT_CODE(KEYCODE_ESC) PORT_BIT(0x02, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("EXT MODE") PORT_CODE(KEYCODE_LALT) PORT_MODIFY("LINE0") PORT_BIT(0x01, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("CAPS SHIFT") PORT_CODE(KEYCODE_LSHIFT) PORT_CODE(KEYCODE_RSHIFT) PORT_CHAR(UCHAR_SHIFT_1) PORT_CHAR(UCHAR_SHIFT_2) PORT_MODIFY("LINE7") PORT_BIT(0x02, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("SYMBOL SHIFT") PORT_CODE(KEYCODE_LCONTROL) PORT_CODE(KEYCODE_RCONTROL) PORT_START("VIDEO") PORT_CONFNAME(0x01, 0x00, "Captured Video Resolution" ) PORT_CONFSETTING(0x00, "360x288 (HDMI)" ) PORT_CONFSETTING(0x01, "320x256 (VGA)" ) PORT_BIT(0xfe, IP_ACTIVE_HIGH, IPT_UNUSED) PORT_START("mouse_input0") PORT_BIT(0x7ff, 0, IPT_MOUSE_X) PORT_SENSITIVITY(100) PORT_START("mouse_input1") PORT_BIT(0x7ff, 0, IPT_MOUSE_Y) PORT_REVERSE PORT_SENSITIVITY(100) PORT_START("mouse_input2") PORT_BIT(0x01, IP_ACTIVE_LOW, IPT_BUTTON1) PORT_NAME("Mouse Button Right") PORT_CODE(MOUSECODE_BUTTON2) PORT_BIT(0x02, IP_ACTIVE_LOW, IPT_BUTTON2) PORT_NAME("Mouse Button Left") PORT_CODE(MOUSECODE_BUTTON1) PORT_BIT(0x04, IP_ACTIVE_LOW, IPT_BUTTON3) PORT_NAME("Mouse Button Middle") PORT_CODE(MOUSECODE_BUTTON3) PORT_BIT(0xf8, IP_ACTIVE_HIGH, IPT_UNUSED) PORT_START("mouse_input3") PORT_BIT(0x0f, 0, IPT_DIAL_V) PORT_REVERSE PORT_NAME("Mouse Scroll V") PORT_SENSITIVITY(1) PORT_CODE(MOUSECODE_Z) PORT_START("JOY_LEFT") PORT_BIT(0x001, IP_ACTIVE_HIGH, IPT_JOYSTICK_RIGHT) PORT_PLAYER(1) PORT_CODE(JOYCODE_HAT1RIGHT) PORT_NAME("Joystick (L) Right") PORT_CODE(JOYCODE_X_RIGHT_SWITCH) PORT_8WAY PORT_BIT(0x002, IP_ACTIVE_HIGH, IPT_JOYSTICK_LEFT) PORT_PLAYER(1) PORT_CODE(JOYCODE_HAT1LEFT) PORT_NAME("Joystick (L) Left") PORT_CODE(JOYCODE_X_LEFT_SWITCH) PORT_8WAY PORT_BIT(0x004, IP_ACTIVE_HIGH, IPT_JOYSTICK_DOWN) PORT_PLAYER(1) PORT_CODE(JOYCODE_HAT1DOWN) PORT_NAME("Joystick (L) Down") PORT_CODE(JOYCODE_Y_DOWN_SWITCH) PORT_8WAY PORT_BIT(0x008, IP_ACTIVE_HIGH, IPT_JOYSTICK_UP) PORT_PLAYER(1) PORT_CODE(JOYCODE_HAT1UP) PORT_NAME("Joystick (L) Up") PORT_CODE(JOYCODE_Y_UP_SWITCH) PORT_8WAY PORT_BIT(0x010, IP_ACTIVE_HIGH, IPT_BUTTON2) PORT_PLAYER(1) PORT_CODE(JOYCODE_BUTTON2) PORT_NAME("Joystick (L) B") PORT_BIT(0x020, IP_ACTIVE_HIGH, IPT_BUTTON5) PORT_PLAYER(1) PORT_CODE(JOYCODE_BUTTON5) PORT_NAME("Joystick (L) C") PORT_BIT(0x040, IP_ACTIVE_HIGH, IPT_BUTTON1) PORT_PLAYER(1) PORT_CODE(JOYCODE_BUTTON1) PORT_NAME("Joystick (L) A") PORT_BIT(0x080, IP_ACTIVE_HIGH, IPT_BUTTON8) PORT_PLAYER(1) PORT_CODE(JOYCODE_BUTTON8) PORT_NAME("Joystick (L) Start") PORT_BIT(0x100, IP_ACTIVE_HIGH, IPT_BUTTON4) PORT_PLAYER(1) PORT_CODE(JOYCODE_BUTTON4) PORT_NAME("Joystick (L) Y") PORT_BIT(0x200, IP_ACTIVE_HIGH, IPT_BUTTON6) PORT_PLAYER(1) PORT_CODE(JOYCODE_BUTTON6) PORT_NAME("Joystick (L) Z") PORT_BIT(0x400, IP_ACTIVE_HIGH, IPT_BUTTON3) PORT_PLAYER(1) PORT_CODE(JOYCODE_BUTTON3) PORT_NAME("Joystick (L) X") PORT_BIT(0x800, IP_ACTIVE_HIGH, IPT_BUTTON7) PORT_PLAYER(1) PORT_CODE(JOYCODE_BUTTON7) PORT_NAME("Joystick (L) Mode") PORT_START("JOY_RIGHT") PORT_BIT(0x001, IP_ACTIVE_HIGH, IPT_JOYSTICK_RIGHT) PORT_PLAYER(2) PORT_CODE(JOYCODE_HAT1RIGHT) PORT_NAME("Joystick (R) Right") PORT_CODE(JOYCODE_X_RIGHT_SWITCH) PORT_8WAY PORT_BIT(0x002, IP_ACTIVE_HIGH, IPT_JOYSTICK_LEFT) PORT_PLAYER(2) PORT_CODE(JOYCODE_HAT1LEFT) PORT_NAME("Joystick (R) Left") PORT_CODE(JOYCODE_X_LEFT_SWITCH) PORT_8WAY PORT_BIT(0x004, IP_ACTIVE_HIGH, IPT_JOYSTICK_DOWN) PORT_PLAYER(2) PORT_CODE(JOYCODE_HAT1DOWN) PORT_NAME("Joystick (R) Down") PORT_CODE(JOYCODE_Y_DOWN_SWITCH) PORT_8WAY PORT_BIT(0x008, IP_ACTIVE_HIGH, IPT_JOYSTICK_UP) PORT_PLAYER(2) PORT_CODE(JOYCODE_HAT1UP) PORT_NAME("Joystick (R) Up") PORT_CODE(JOYCODE_Y_UP_SWITCH) PORT_8WAY PORT_BIT(0x010, IP_ACTIVE_HIGH, IPT_BUTTON2) PORT_PLAYER(2) PORT_CODE(JOYCODE_BUTTON2) PORT_NAME("Joystick (R) B") PORT_BIT(0x020, IP_ACTIVE_HIGH, IPT_BUTTON5) PORT_PLAYER(2) PORT_CODE(JOYCODE_BUTTON5) PORT_NAME("Joystick (R) C") PORT_BIT(0x040, IP_ACTIVE_HIGH, IPT_BUTTON1) PORT_PLAYER(2) PORT_CODE(JOYCODE_BUTTON1) PORT_NAME("Joystick (R) A") PORT_BIT(0x080, IP_ACTIVE_HIGH, IPT_BUTTON8) PORT_PLAYER(2) PORT_CODE(JOYCODE_BUTTON8) PORT_NAME("Joystick (R) Start") PORT_BIT(0x100, IP_ACTIVE_HIGH, IPT_BUTTON4) PORT_PLAYER(2) PORT_CODE(JOYCODE_BUTTON4) PORT_NAME("Joystick (R) Y") PORT_BIT(0x200, IP_ACTIVE_HIGH, IPT_BUTTON6) PORT_PLAYER(2) PORT_CODE(JOYCODE_BUTTON6) PORT_NAME("Joystick (R) Z") PORT_BIT(0x400, IP_ACTIVE_HIGH, IPT_BUTTON3) PORT_PLAYER(2) PORT_CODE(JOYCODE_BUTTON3) PORT_NAME("Joystick (R) X") PORT_BIT(0x800, IP_ACTIVE_HIGH, IPT_BUTTON7) PORT_PLAYER(2) PORT_CODE(JOYCODE_BUTTON7) PORT_NAME("Joystick (R) Mode") PORT_MODIFY("NMI") PORT_BIT(0x01, IP_ACTIVE_HIGH, IPT_OTHER) PORT_NAME("NMI MF") PORT_CODE(KEYCODE_F12) PORT_CHANGED_MEMBER(DEVICE_SELF, FUNC(specnext_state::on_nmi_button), 0) PORT_BIT(0x02, IP_ACTIVE_HIGH, IPT_OTHER) PORT_NAME("NMI DivMMC") PORT_CODE(KEYCODE_F11) PORT_CHANGED_MEMBER(DEVICE_SELF, FUNC(specnext_state::on_nmi_button), 0) PORT_START("LYRS") PORT_CONFNAME(0x08, 0x00, "Disable Sprites") PORT_CONFSETTING( 0x00, DEF_STR(Off)) PORT_CONFSETTING( 0x08, DEF_STR(On)) PORT_CONFNAME(0x04, 0x00, "Disable Layer2") PORT_CONFSETTING( 0x00, DEF_STR(Off)) PORT_CONFSETTING( 0x04, DEF_STR(On)) PORT_CONFNAME(0x02, 0x00, "Disable ULA/LoRes") PORT_CONFSETTING( 0x00, DEF_STR(Off)) PORT_CONFSETTING( 0x02, DEF_STR(On)) PORT_CONFNAME(0x01, 0x00, "Disable Tiles") PORT_CONFSETTING( 0x00, DEF_STR(Off)) PORT_CONFSETTING( 0x01, DEF_STR(On)) INPUT_PORTS_END void specnext_state::machine_start() { spectrum_128_state::machine_start(); m_screen->register_screen_bitmap(m_blendprio_bitmap); m_irq_line_timer = timer_alloc(FUNC(specnext_state::line_irq_on), this); m_spi_clock = timer_alloc(FUNC(specnext_state::spi_clock), this); m_regs_map->space(AS_PROGRAM).specific(m_next_regs); for (int addr = 0; addr < m_ram->size(); ++addr) m_ram->pointer()[addr] = machine().rand(); m_ram_pages = m_ram->size() / 0x2000; for (auto i = 0; i < 8; i++) m_bank_ram[i]->configure_entries(0, m_ram->size() / 0x2000, m_ram->pointer(), 0x2000); m_bank_boot_rom->configure_entries(0, 2, memregion("maincpu")->base(), 0x2000); const u8 *ram = m_ram->pointer() + 0x40000; m_ula_scr->set_bram_bank5_ptr(m_bram_bank5.target()); m_ula_scr->set_bram_bank7_ptr(m_bram_bank7.target()); m_tiles->set_bram_bank5_ptr(m_bram_bank5.target()); m_tiles->set_bram_bank7_ptr(m_bram_bank7.target()); m_layer2->set_host_ram_ptr(ram); m_lores->set_bram_bank5_ptr(m_bram_bank5.target()); m_nr_02_hard_reset = 1; m_nr_10_coreid = 0b00000; // Works but must be 1 if Next core bootrom selected // Save save_item(NAME(m_page_shadow)); save_item(NAME(m_bootrom_en)); save_item(NAME(m_port_ff_data)); save_item(NAME(m_port_1ffd_special_old)); save_item(NAME(m_port_1ffd_data)); //save_item(NAME(m_port_7ffd_data)); save_item(NAME(m_port_dffd_data)); save_item(NAME(m_port_eff7_data)); save_item(NAME(m_port_e7_reg)); save_item(NAME(m_nr_register)); save_item(NAME(m_port_e3_reg)); save_item(NAME(m_divmmc_delayed_check)); save_item(NAME(m_sram_rom)); save_item(NAME(m_sram_rom3)); save_item(NAME(m_sram_alt_128_n)); save_item(NAME(m_mmu)); save_item(NAME(m_nr_02_bus_reset)); save_item(NAME(m_nr_02_generate_mf_nmi)); save_item(NAME(m_nr_02_generate_divmmc_nmi)); save_item(NAME(m_nr_02_hard_reset)); save_item(NAME(m_nr_02_reset_type)); save_item(NAME(m_nr_03_machine_type)); save_item(NAME(m_nr_03_user_dt_lock)); save_item(NAME(m_nr_03_machine_timing)); save_item(NAME(m_nr_03_config_mode)); save_item(NAME(m_nr_04_romram_bank)); save_item(NAME(m_nr_05_joy1)); save_item(NAME(m_nr_05_joy0)); save_item(NAME(m_nr_05_5060)); save_item(NAME(m_nr_06_psg_mode)); save_item(NAME(m_nr_06_ps2_mode)); save_item(NAME(m_nr_06_button_m1_nmi_en)); save_item(NAME(m_nr_06_button_drive_nmi_en)); save_item(NAME(m_nr_06_hotkey_5060_en)); save_item(NAME(m_nr_06_internal_speaker_beep)); save_item(NAME(m_nr_06_hotkey_cpu_speed_en)); save_item(NAME(m_nr_07_cpu_speed)); save_item(NAME(m_nr_08_keyboard_issue2)); save_item(NAME(m_nr_08_psg_turbosound_en)); save_item(NAME(m_nr_08_port_ff_rd_en)); save_item(NAME(m_nr_08_dac_en)); save_item(NAME(m_nr_08_internal_speaker_en)); save_item(NAME(m_nr_08_psg_stereo_mode)); save_item(NAME(m_nr_08_contention_disable)); save_item(NAME(m_nr_09_hdmi_audio_en)); save_item(NAME(m_nr_09_sprite_tie)); save_item(NAME(m_nr_09_psg_mono)); save_item(NAME(m_nr_0a_mouse_dpi)); save_item(NAME(m_nr_0a_mouse_button_reverse)); save_item(NAME(m_nr_0a_divmmc_automap_en)); save_item(NAME(m_nr_0a_mf_type)); save_item(NAME(m_nr_0a_sd_swap)); save_item(NAME(m_nr_0b_joy_iomode_0)); save_item(NAME(m_nr_0b_joy_iomode)); save_item(NAME(m_nr_0b_joy_iomode_en)); save_item(NAME(m_nr_10_coreid)); save_item(NAME(m_nr_11_video_timing)); save_item(NAME(m_nr_10_flashboot)); save_item(NAME(m_nr_12_layer2_active_bank)); save_item(NAME(m_nr_13_layer2_shadow_bank)); save_item(NAME(m_nr_14_global_transparent_rgb)); save_item(NAME(m_nr_15_sprite_en)); save_item(NAME(m_nr_15_sprite_over_border_en)); save_item(NAME(m_nr_15_layer_priority)); save_item(NAME(m_nr_15_sprite_border_clip_en)); save_item(NAME(m_nr_15_sprite_priority)); save_item(NAME(m_nr_15_lores_en)); save_item(NAME(m_nr_16_layer2_scrollx)); save_item(NAME(m_nr_17_layer2_scrolly)); save_item(NAME(m_nr_18_layer2_clip_x1)); save_item(NAME(m_nr_18_layer2_clip_x2)); save_item(NAME(m_nr_18_layer2_clip_y1)); save_item(NAME(m_nr_18_layer2_clip_y2)); save_item(NAME(m_nr_18_layer2_clip_idx)); save_item(NAME(m_nr_19_sprite_clip_x1)); save_item(NAME(m_nr_19_sprite_clip_x2)); save_item(NAME(m_nr_19_sprite_clip_y1)); save_item(NAME(m_nr_19_sprite_clip_y2)); save_item(NAME(m_nr_19_sprite_clip_idx)); save_item(NAME(m_nr_1a_ula_clip_x1)); save_item(NAME(m_nr_1a_ula_clip_x2)); save_item(NAME(m_nr_1a_ula_clip_y1)); save_item(NAME(m_nr_1a_ula_clip_y2)); save_item(NAME(m_nr_1a_ula_clip_idx)); save_item(NAME(m_nr_1b_tm_clip_x1)); save_item(NAME(m_nr_1b_tm_clip_x2)); save_item(NAME(m_nr_1b_tm_clip_y1)); save_item(NAME(m_nr_1b_tm_clip_y2)); save_item(NAME(m_nr_1b_tm_clip_idx)); save_item(NAME(m_nr_22_line_interrupt_en)); save_item(NAME(m_nr_23_line_interrupt)); save_item(NAME(m_nr_26_ula_scrollx)); save_item(NAME(m_nr_27_ula_scrolly)); save_item(NAME(m_nr_2d_i2s_sample)); save_item(NAME(m_nr_30_tm_scrollx)); save_item(NAME(m_nr_31_tm_scrolly)); save_item(NAME(m_nr_32_lores_scrollx)); save_item(NAME(m_nr_33_lores_scrolly)); save_item(NAME(m_nr_palette_idx)); save_item(NAME(m_nr_palette_sub_idx)); save_item(NAME(m_nr_42_ulanext_format)); save_item(NAME(m_nr_43_palette_autoinc_disable)); save_item(NAME(m_nr_43_palette_write_select)); save_item(NAME(m_nr_43_active_sprite_palette)); save_item(NAME(m_nr_43_active_layer2_palette)); save_item(NAME(m_nr_43_active_ula_palette)); save_item(NAME(m_nr_43_ulanext_en)); save_item(NAME(m_nr_stored_palette_value)); save_item(NAME(m_nr_4a_fallback_rgb)); save_item(NAME(m_nr_4b_sprite_transparent_index)); save_item(NAME(m_nr_4c_tm_transparent_index)); save_item(NAME(m_nr_copper_addr)); save_item(NAME(m_nr_copper_data_stored)); save_item(NAME(m_nr_62_copper_mode)); save_item(NAME(m_nr_64_copper_offset)); save_item(NAME(m_nr_68_ula_en)); save_item(NAME(m_nr_68_blend_mode)); save_item(NAME(m_nr_68_cancel_extended_keys)); save_item(NAME(m_nr_68_ula_fine_scroll_x)); save_item(NAME(m_nr_68_ula_stencil_mode)); save_item(NAME(m_nr_6a_lores_radastan)); save_item(NAME(m_nr_6a_lores_radastan_xor)); save_item(NAME(m_nr_6a_lores_palette_offset)); save_item(NAME(m_nr_6b_tm_en)); save_item(NAME(m_nr_6b_tm_control)); save_item(NAME(m_nr_6c_tm_default_attr)); save_item(NAME(m_nr_6e_tilemap_base)); save_item(NAME(m_nr_6e_tilemap_base_7)); save_item(NAME(m_nr_6f_tilemap_tiles)); save_item(NAME(m_nr_6f_tilemap_tiles_7)); save_item(NAME(m_nr_70_layer2_resolution)); save_item(NAME(m_nr_70_layer2_palette_offset)); save_item(NAME(m_nr_71_layer2_scrollx_msb)); save_item(NAME(m_nr_7f_user_register_0)); save_item(NAME(m_nr_80_expbus)); save_item(NAME(m_nr_81_expbus_speed)); save_item(NAME(m_nr_81_expbus_clken)); save_item(NAME(m_nr_81_expbus_nmi_debounce_disable)); save_item(NAME(m_nr_81_expbus_ula_override)); save_item(NAME(m_nr_82_internal_port_enable)); save_item(NAME(m_nr_83_internal_port_enable)); save_item(NAME(m_nr_84_internal_port_enable)); save_item(NAME(m_nr_85_internal_port_enable)); save_item(NAME(m_nr_85_internal_port_reset_type)); save_item(NAME(m_nr_86_bus_port_enable)); save_item(NAME(m_nr_87_bus_port_enable)); save_item(NAME(m_nr_88_bus_port_enable)); save_item(NAME(m_nr_89_bus_port_enable)); save_item(NAME(m_nr_89_bus_port_reset_type)); save_item(NAME(m_nr_8a_bus_port_propagate)); save_item(NAME(m_nr_8c_altrom)); save_item(NAME(m_nr_8f_mapping_mode)); save_item(NAME(m_nr_90_pi_gpio_o_en)); save_item(NAME(m_nr_91_pi_gpio_o_en)); save_item(NAME(m_nr_92_pi_gpio_o_en)); save_item(NAME(m_nr_93_pi_gpio_o_en)); save_item(NAME(m_nr_98_pi_gpio_o)); save_item(NAME(m_nr_99_pi_gpio_o)); save_item(NAME(m_nr_9a_pi_gpio_o)); save_item(NAME(m_nr_9b_pi_gpio_o)); save_item(NAME(m_nr_a0_pi_peripheral_en)); save_item(NAME(m_nr_a2_pi_i2s_ctl)); save_item(NAME(m_nr_a8_esp_gpio0_en)); save_item(NAME(m_nr_a9_esp_gpio0)); save_item(NAME(m_nr_b8_divmmc_ep_0)); save_item(NAME(m_nr_b9_divmmc_ep_valid_0)); save_item(NAME(m_nr_ba_divmmc_ep_timing_0)); save_item(NAME(m_nr_bb_divmmc_ep_1)); save_item(NAME(m_nr_c0_im2_vector)); save_item(NAME(m_nr_c0_stackless_nmi)); save_item(NAME(m_nr_c0_int_mode_pulse_0_im2_1)); save_item(NAME(m_nr_c2_retn_address_lsb)); save_item(NAME(m_nr_c3_retn_address_msb)); save_item(NAME(m_nr_c4_int_en_0_expbus)); save_item(NAME(m_nr_c6_int_en_2_654)); save_item(NAME(m_nr_c6_int_en_2_210)); save_item(NAME(m_nr_cc_dma_int_en_0_7)); save_item(NAME(m_nr_cc_dma_int_en_0_10)); save_item(NAME(m_nr_cd_dma_int_en_1)); save_item(NAME(m_nr_ce_dma_int_en_2_654)); save_item(NAME(m_nr_ce_dma_int_en_2_210)); save_item(NAME(m_nr_d8_io_trap_fdc_en)); save_item(NAME(m_nr_d9_iotrap_write)); save_item(NAME(m_nr_da_iotrap_cause)); save_item(NAME(m_nr_f0_select)); save_item(NAME(m_nr_f0_xdna_en)); save_item(NAME(m_nr_f0_xadc_en)); save_item(NAME(m_nr_f0_xdev_cmd)); save_item(NAME(m_nr_f0_xadc_eoc)); save_item(NAME(m_nr_f0_xadc_eos)); save_item(NAME(m_nr_f8_xadc_dwe)); save_item(NAME(m_nr_f8_xadc_daddr)); save_item(NAME(m_nr_f8_xadc_den)); save_item(NAME(m_nr_f9_xadc_d0)); save_item(NAME(m_nr_fa_xadc_d1)); save_item(NAME(m_pulse_int_n)); save_item(NAME(m_im2_int_status)); save_item(NAME(m_nr_09_scanlines)); save_item(NAME(m_eff_nr_03_machine_timing)); save_item(NAME(m_eff_nr_05_5060)); save_item(NAME(m_eff_nr_05_scandouble_en)); save_item(NAME(m_eff_nr_08_contention_disable)); save_item(NAME(m_eff_nr_09_scanlines)); save_item(NAME(m_port_123b_layer2_en)); save_item(NAME(m_port_123b_layer2_map_wr_en)); save_item(NAME(m_port_123b_layer2_map_rd_en)); save_item(NAME(m_port_123b_layer2_map_shadow)); save_item(NAME(m_port_123b_layer2_map_segment)); save_item(NAME(m_port_123b_layer2_offset)); save_item(NAME(m_port_bf3b_ulap_mode)); save_item(NAME(m_port_bf3b_ulap_index)); save_item(NAME(m_port_ff3b_ulap_en)); save_item(NAME(m_ay_select)); save_item(NAME(m_uart_select)); save_item(NAME(m_spi_clock_cycles)); save_item(NAME(m_spi_clock_state)); save_item(NAME(m_spi_mosi_dat)); save_item(NAME(m_spi_miso_dat)); save_item(NAME(m_i2c_scl_data)); save_item(NAME(m_i2c_sda_data)); state_add(0, "mmu0", m_mmu[0]).callimport(); state_add(1, "mmu1", m_mmu[1]).callimport(); state_add(2, "mmu2", m_mmu[2]).callimport(); state_add(3, "mmu3", m_mmu[3]).callimport(); state_add(4, "mmu4", m_mmu[4]).callimport(); state_add(5, "mmu5", m_mmu[5]).callimport(); state_add(6, "mmu6", m_mmu[6]).callimport(); state_add(7, "mmu7", m_mmu[7]).callimport(); } void specnext_state::state_import(const device_state_entry &entry) { if (entry.index() < 8) { bank_update(entry.index()); } } void specnext_state::device_post_load() { m_video_output_hdmi = -1; } void specnext_state::reset_hard() { m_nr_02_hard_reset = 0; m_bootrom_en = 1; m_dma->dma_mode_w(0); // nmi_mf = 0; // nmi_divmmc = 0; // nmi_expbus = 0; m_nr_80_expbus = 0; // expbus_eff_en = 0; // expbus_eff_disable_io = 0; // expbus_eff_disable_mem = 0; // expbus_eff_clken = 0; m_nr_8c_altrom = 0; // bus_iorq_ula = 0; // port_253b_rd_qq = 0; // sram_req_d = 1; // sram_wait_n = 1; // m_port_103b_dat = 0xff; // m_port_113b_dat = 0xff; port_e7_reg_w(0xff); // joy_iomode_pin7 = 1; // port_fe_border = 0; m_nr_8f_mapping_mode = 0; // m_port_123b_dat = 0; m_nr_02_bus_reset = 0; m_nr_03_machine_timing = 0b011; m_nr_03_user_dt_lock = 0; m_nr_03_config_mode = 1; m_nr_03_machine_type = 0b011; m_nr_04_romram_bank = 0; m_nr_05_joy0 = 0b001; m_nr_05_joy1 = 0b000; m_nr_05_5060 = 0; m_nr_06_hotkey_cpu_speed_en = 1; m_nr_06_hotkey_5060_en = 1; m_nr_06_button_drive_nmi_en = 0; m_nr_06_button_m1_nmi_en = 0; m_nr_06_ps2_mode = 0; m_nr_06_psg_mode = 0b00; nr_07_cpu_speed_w(0b00); m_nr_06_internal_speaker_beep = 0; m_nr_08_contention_disable = 0; m_nr_08_psg_stereo_mode = 0; m_nr_08_internal_speaker_en = 1; m_nr_08_dac_en = 0; m_nr_08_port_ff_rd_en = 0; m_nr_08_psg_turbosound_en = 0; m_nr_08_keyboard_issue2 = 0; m_nr_09_psg_mono = 0; m_nr_09_hdmi_audio_en = 1; m_nr_09_sprite_tie = 0; nr_0a_mf_type_w(0b00); m_nr_0a_sd_swap = 0; m_nr_0a_divmmc_automap_en = 0; m_nr_0a_mouse_button_reverse = 0; m_nr_0a_mouse_dpi = 0b01; m_nr_10_flashboot = 0; //m_nr_10_coreid = 0b00001; m_nr_7f_user_register_0 = 0xff; m_nr_81_expbus_ula_override = 0; m_nr_81_expbus_nmi_debounce_disable = 0; m_nr_81_expbus_clken = 0; m_nr_81_expbus_speed = 0b00; m_nr_82_internal_port_enable = 0xff; m_nr_83_internal_port_enable = 0xff; m_nr_84_internal_port_enable = 0xff; m_nr_85_internal_port_enable = 0x0f; m_nr_85_internal_port_reset_type = 1; m_nr_86_bus_port_enable = 0xff; m_nr_87_bus_port_enable = 0xff; m_nr_88_bus_port_enable = 0xff; m_nr_89_bus_port_enable = 0x0f; m_nr_89_bus_port_reset_type = 1; m_nr_8a_bus_port_propagate = 0x3f; m_nr_90_pi_gpio_o_en = 0; m_nr_91_pi_gpio_o_en = 0; m_nr_92_pi_gpio_o_en = 0; m_nr_93_pi_gpio_o_en = 0; m_nr_a8_esp_gpio0_en = 0; m_nr_a9_esp_gpio0 = 1; m_nr_f0_select = 1; m_nr_f0_xdna_en = 0; m_nr_f0_xadc_en = 0; m_nr_f0_xdev_cmd = 0x00; m_nr_f0_xadc_eoc = 0; m_nr_f0_xadc_eos = 0; m_nr_f8_xadc_dwe = 0; m_nr_f8_xadc_daddr = 0x00; m_nr_f8_xadc_den = 0; m_nr_f9_xadc_d0 = 0; m_nr_fa_xadc_d1 = 0; //m_nr_05_scandouble_en = 1; m_nr_09_scanlines = 0b00; m_nr_02_reset_type = 0b100; // nr_keymap_sel = 0; // nr_keymap_addr = 0; // hotkeys_1 = 0; // hotkeys_0 = 0; // video_timing_change_d = 0; m_eff_nr_03_machine_timing = 0b011; m_eff_nr_08_contention_disable = 0; // xdna_load = 0; // xdna_shift = 0; // xadc_reset = 0; // xadc_convst = 0; m_eff_nr_05_scandouble_en = 0; m_eff_nr_09_scanlines = 0; m_nr_2d_i2s_sample = 0b00; // m_port_00_data = 0; m_nr_0a_divmmc_automap_en = 1; } void specnext_state::machine_reset() { // TODO prevent from soft reset in config mode? spectrum_128_state::machine_reset(); m_maincpu->set_input_line(INPUT_LINE_NMI, CLEAR_LINE); m_irq_line_timer->reset(); if (m_nr_02_hard_reset) reset_hard(); m_spi_clock->reset(); m_spi_clock_cycles = 0; m_spi_clock_state = false; port_ff_w(0x00); m_divmmc_delayed_check = 0; m_dma->dma_mode_w(0); //z80_retn_seen_28_d = 0; //im2_dma_delay = 0; m_pulse_int_n = 1; m_im2_int_status = 0x00; m_nr_c2_retn_address_lsb = 0x00; m_nr_c3_retn_address_msb = 0x00; //z80_stackless_retn_en = 0; //nmi_mf = 0; //nmi_divmmc = 0; //nmi_expbus = 0; //nmi_state = S_NMI_IDLE; nr_80_expbus_w((m_nr_80_expbus << 4) | (m_nr_80_expbus & 0x0f)); m_nr_8c_altrom = (m_nr_8c_altrom << 4) | (m_nr_8c_altrom & 0x0f); //port_253b_rd_qq = 0b00; //sram_req_d = 0; m_i2c_scl_data = 1; m_i2c_sda_data = 1; port_e7_reg_w(0xff); //joy_iomode_pin7 = 1; port_7ffd_reg_w(0x00); m_port_1ffd_data = 0; m_port_1ffd_special_old = 0; m_port_dffd_data = 0; m_port_eff7_data = 0; /* TODO don't use inherited port_fe_reg = 0x00; port_ff_reg = 0x00; port_7ffd_reg = 0x00; port_dffd_reg = 0x00; port_dffd_reg_6 = 0; port_1ffd_reg = 0x00; port_1ffd_special_old = 0; port_eff7_reg_2 = 0; port_eff7_reg_3 = 0; */ m_nr_02_generate_mf_nmi = 0; m_nr_02_generate_divmmc_nmi = 0; m_nr_da_iotrap_cause = 0x00; m_nr_d9_iotrap_write = 0x00; port_123b_layer2_en_w(0); m_port_123b_layer2_map_wr_en = 0; m_port_123b_layer2_map_rd_en = 0; m_port_123b_layer2_map_shadow = 0; m_port_123b_layer2_map_segment = 0x00; m_port_123b_layer2_offset = 0x00; port_e3_reg_w(0x00); m_port_bf3b_ulap_mode = 0x00; m_port_bf3b_ulap_index = 0x00; port_ff3b_ulap_en_w(0); m_nr_register = 0x24; //copper_requester_d = 0; //cpu_requester_d = 0; //cpu_req = 0; //cpu_nr_reg = 0x00; //cpu_nr_dat = 0x00; nr_07_cpu_speed_w(0b00); m_eff_nr_08_contention_disable = 0; //expbus_eff_en = expbus_en; //expbus_eff_disable_io = expbus_disable_io; //expbus_eff_disable_mem = expbus_disable_mem; //expbus_eff_clken = expbus_clken; m_nr_06_hotkey_cpu_speed_en = 1; m_nr_06_hotkey_5060_en = 1; m_nr_08_contention_disable = 0; m_nr_09_sprite_tie = 0; m_nr_0b_joy_iomode_en = 0; m_nr_0b_joy_iomode = 0b00; m_nr_0b_joy_iomode_0 = 1; nr_12_layer2_active_bank_w(0b0001000); nr_13_layer2_shadow_bank_w(0b0001011); nr_14_global_transparent_rgb_w(0xe3); m_nr_15_lores_en = 0; nr_15_sprite_priority_w(0); nr_15_sprite_border_clip_en_w(0); m_nr_15_layer_priority = 0x00; nr_15_sprite_over_border_en_w(0); m_nr_15_sprite_en = 0; nr_16_layer2_scrollx_w(0x00); nr_17_layer2_scrolly_w(0x00); nr_18_layer2_clip_x1_w(0x00); nr_18_layer2_clip_x2_w(0xff); nr_18_layer2_clip_y1_w(0x00); nr_18_layer2_clip_y2_w(0xbf); m_nr_18_layer2_clip_idx = 0b00; nr_19_sprite_clip_x1_w(0x00); nr_19_sprite_clip_x2_w(0xff); nr_19_sprite_clip_y1_w(0x00); nr_19_sprite_clip_y2_w(0xbf); m_nr_19_sprite_clip_idx = 0b00; nr_1a_ula_clip_x1_w(0x00); nr_1a_ula_clip_x2_w(0xff); nr_1a_ula_clip_y1_w(0x00); nr_1a_ula_clip_y2_w(0xbf); m_nr_1a_ula_clip_idx = 0b00; nr_1b_tm_clip_x1_w(0x00); nr_1b_tm_clip_x2_w(0x9f); nr_1b_tm_clip_y1_w(0x00); nr_1b_tm_clip_y2_w(0xff); m_nr_1b_tm_clip_idx = 0b00; m_nr_22_line_interrupt_en = 0; m_nr_23_line_interrupt = 0x00; nr_26_ula_scrollx_w(0x00); nr_27_ula_scrolly_w(0x00); nr_30_tm_scrollx_w(0x00); nr_31_tm_scrolly_w(0x00); nr_32_lores_scrollx_w(0x00); nr_33_lores_scrolly_w(0x00); m_nr_palette_idx = 0x00; m_nr_palette_sub_idx = 0; nr_42_ulanext_format_w(0x07); m_nr_43_palette_autoinc_disable = 0; m_nr_43_palette_write_select = 0b000; nr_43_active_sprite_palette_w(0); nr_43_active_layer2_palette_w(0); nr_43_active_ula_palette_w(0); nr_43_ulanext_en_w(0); m_nr_stored_palette_value = 0x00; reg_w(0x4a, 0xe3); // m_nr_4a_fallback_rgb = 0xe3; nr_4b_sprite_transparent_index_w(0xe3); nr_4c_tm_transparent_index_w(0xf); nr_62_copper_mode_w(0b00); m_nr_copper_addr = 0x00; m_nr_copper_data_stored = 0x00; m_nr_64_copper_offset = 0x00; m_nr_68_ula_en = 1; m_nr_68_blend_mode = 0b00; m_nr_68_cancel_extended_keys = 0; nr_68_ula_fine_scroll_x_w(0); m_nr_68_ula_stencil_mode = 0; nr_6a_lores_radastan_w(0); nr_6a_lores_palette_offset_w(0x00); nr_6a_lores_radastan_xor_w(0); m_nr_6b_tm_en = 0; nr_6b_tm_control_w(0x00); nr_6c_tm_default_attr_w(0x00); nr_6e_tilemap_base_w(0, 0b101100); nr_6f_tilemap_tiles_w(0, 0b001100); nr_70_layer2_resolution_w(0b00); nr_70_layer2_palette_offset_w(0x00); nr_71_layer2_scrollx_msb_w(0); if (m_nr_85_internal_port_reset_type) { m_nr_82_internal_port_enable = 0xff; m_nr_83_internal_port_enable = 0xff; m_nr_84_internal_port_enable = 0xff; m_nr_85_internal_port_enable = 0xf; } if (!m_nr_89_bus_port_reset_type) { m_nr_86_bus_port_enable = 0xff; m_nr_87_bus_port_enable = 0xff; m_nr_88_bus_port_enable = 0xff; m_nr_89_bus_port_enable = 0xf; } m_nr_98_pi_gpio_o = 0xff; m_nr_99_pi_gpio_o = 0x01; m_nr_9a_pi_gpio_o = 0x00; m_nr_9b_pi_gpio_o = 0x00; m_nr_90_pi_gpio_o_en = 0x00; m_nr_91_pi_gpio_o_en = 0x00; m_nr_92_pi_gpio_o_en = 0x00; m_nr_93_pi_gpio_o_en = 0x00; m_nr_a0_pi_peripheral_en = 0x00; m_nr_a2_pi_i2s_ctl = 0x00; m_nr_a8_esp_gpio0_en = 0; m_nr_a9_esp_gpio0 = 1; m_nr_b8_divmmc_ep_0 = 0x83; m_nr_b9_divmmc_ep_valid_0 = 0x01; m_nr_ba_divmmc_ep_timing_0 = 0x00; m_nr_bb_divmmc_ep_1 = 0xcd; nr_c0_im2_vector_w(0, 0x00); m_nr_c0_stackless_nmi = 0; m_maincpu->nmi_stackless_w(m_nr_c0_stackless_nmi); m_nr_c4_int_en_0_expbus = 1; m_nr_c6_int_en_2_654 = 0x00; m_nr_c6_int_en_2_210 = 0x00; m_nr_cc_dma_int_en_0_7 = 0; m_nr_cc_dma_int_en_0_10 = 0x00; m_nr_cd_dma_int_en_1 = 0x00; m_nr_ce_dma_int_en_2_654 = 0x00; m_nr_ce_dma_int_en_2_210 = 0x00; m_nr_d8_io_trap_fdc_en = 0; if (m_nr_03_config_mode) m_bootrom_en = 1; mmu_x2_w(0, 0xff); mmu_x2_w(2, 0x0a); mmu_x2_w(4, 0x04); mmu_x2_w(6, 0x00); m_ay_select = 0; m_uart_select = 0; m_video_output_hdmi = -1; } static const gfx_layout bootrom_charlayout = { 8, 8, // 8 x 8 characters */ 96, // 96 characters */ 1, // 1 bits per pixel */ { 0 }, // no bitplanes { STEP8(0, 1) }, // x offsets { STEP8(0, 8) }, // y offsets 8 * 8 // every char takes 8 bytes }; static GFXDECODE_START(gfx_tbblue) GFXDECODE_ENTRY("maincpu", 0x1584, bootrom_charlayout, 0xf7, 1) GFXDECODE_END void specnext_state::video_start() { spectrum_128_state::video_start(); address_space &prg = m_maincpu->space(AS_PROGRAM); prg.install_write_tap(0x0000, 0xbfff, "shadow_w", [this](offs_t offset, u8 &data, u8 mem_mask) { u8 bank8 = offset >> 13; if (m_page_shadow[bank8] >= 0) { u8 *to = m_ram->pointer() + (m_page_shadow[bank8] << 13); to[offset & 0x1fff] = data; } }); prg.install_read_tap(0x0000, 0xffff, "mem_wait_r", [this](offs_t offset, u8 &data, u8 mem_mask) { // The 28MHz with core 3.0.5 is adding extra wait state to every instruction opcode fetch and memory read if (!machine().side_effects_disabled() && (m_nr_07_cpu_speed == 0b11)) { m_maincpu->adjust_icount(-1); } }); update_video_mode(); } static DEVICE_INPUT_DEFAULTS_START(rs232_baud) DEVICE_INPUT_DEFAULTS( "RS232_RXBAUD", 0xff, RS232_BAUD_115200 ) DEVICE_INPUT_DEFAULTS( "RS232_TXBAUD", 0xff, RS232_BAUD_115200 ) DEVICE_INPUT_DEFAULTS_END static void rs232_devices(device_slot_interface &device) { device.option_add("null_modem", NULL_MODEM); device.option_add("pty", PSEUDO_TERMINAL); } void specnext_state::tbblue(machine_config &config) { spectrum_128(config); config.device_remove("exp"); config.device_remove("dma"); Z80N(config.replace(), m_maincpu, 28_MHz_XTAL / 8); m_maincpu->set_daisy_config(z80_daisy_chain); m_maincpu->set_m1_map(&specnext_state::map_fetch); m_maincpu->set_memory_map(&specnext_state::map_mem); m_maincpu->set_io_map(&specnext_state::map_io); m_maincpu->set_vblank_int("screen", FUNC(specnext_state::specnext_interrupt)); m_maincpu->set_irq_acknowledge_callback(NAME([](device_t &, int){ return 0xff; })); m_maincpu->out_nextreg_cb().set([this](offs_t offset, u8 data) { m_next_regs.write_byte(offset, data); }); m_maincpu->in_nextreg_cb().set([this](offs_t offset) { return m_next_regs.read_byte(offset); }); m_maincpu->out_retn_seen_cb().set(FUNC(specnext_state::leave_nmi)); m_maincpu->busack_cb().set(m_dma, FUNC(specnext_dma_device::bai_w)); m_maincpu->irqack_cb().set([this](int) { m_screen->update_now(); }); SPECNEXT_IM2(config, m_im2_line); m_im2_line->irq_callback().set(FUNC(specnext_state::irq_w)); SPECNEXT_IM2(config, m_im2_ula); m_im2_ula->irq_callback().set(FUNC(specnext_state::irq_w)); SPECNEXT_CTC(config, m_ctc, 28_MHz_XTAL); m_ctc->zc_callback<0>().set(m_ctc, FUNC(z80ctc_device::trg1)); m_ctc->zc_callback<1>().set(m_ctc, FUNC(z80ctc_device::trg2)); m_ctc->zc_callback<2>().set(m_ctc, FUNC(z80ctc_device::trg3)); m_ctc->intr_callback().set(FUNC(specnext_state::irq_w)); SPECNEXT_DMA(config, m_dma, 28_MHz_XTAL / 8); m_dma->out_busreq_callback().set_inputline(m_maincpu, Z80_INPUT_LINE_BUSREQ); m_dma->in_mreq_callback().set(FUNC(specnext_state::dma_mreq_r)); m_dma->out_mreq_callback().set([this](offs_t offset, u8 data) { m_program.write_byte(offset, data); }); m_dma->in_iorq_callback().set([this](offs_t offset) { return m_io.read_byte(offset); }); m_dma->out_iorq_callback().set([this](offs_t offset, u8 data) { m_io.write_byte(offset, data); }); ADDRESS_MAP_BANK(config, m_regs_map).set_map(&specnext_state::map_regs).set_options(ENDIANNESS_LITTLE, 8, 8, 0); I2C_DS1307(config, m_i2c); m_i2c->sda_callback().set([this](int state) { m_i2c_sda_data = state & 1; }); SPECNEXT_IM2(config, m_im2_uart0_rx); m_im2_uart0_rx->irq_callback().set(FUNC(specnext_state::irq_w)); SPECNEXT_IM2(config, m_im2_uart0_tx); m_im2_uart0_tx->irq_callback().set(FUNC(specnext_state::irq_w)); SPECNEXT_UART(config, m_uart[0], 28_MHz_XTAL); m_uart[0]->out_txd_callback().set("rs232_esp", FUNC(rs232_port_device::write_txd)); m_uart[0]->out_txd_callback().append(FUNC(specnext_state::txd_w<0>)); m_uart[0]->out_rx_full_near_callback().set(m_im2_uart0_rx, FUNC(specnext_im2_device::irq_w)); m_uart[0]->out_tx_empty_callback().set(m_im2_uart0_tx, FUNC(specnext_im2_device::irq_w)); rs232_port_device &rs232_esp(RS232_PORT(config, "rs232_esp", rs232_devices, nullptr)); rs232_esp.rxd_handler().set(m_uart[0], FUNC(specnext_uart_device::rx_w)); rs232_esp.set_option_device_input_defaults("null_modem", DEVICE_INPUT_DEFAULTS_NAME(rs232_baud)); rs232_esp.set_option_device_input_defaults("pty", DEVICE_INPUT_DEFAULTS_NAME(rs232_baud)); SPECNEXT_IM2(config, m_im2_uart1_rx); m_im2_uart1_rx->irq_callback().set(FUNC(specnext_state::irq_w)); SPECNEXT_IM2(config, m_im2_uart1_tx); m_im2_uart1_tx->irq_callback().set(FUNC(specnext_state::irq_w)); SPECNEXT_UART(config, m_uart[1], 28_MHz_XTAL); m_uart[1]->out_txd_callback().set("rs232_rpi", FUNC(rs232_port_device::write_txd)); m_uart[1]->out_txd_callback().append(FUNC(specnext_state::txd_w<1>)); m_uart[1]->out_rx_full_near_callback().set(m_im2_uart1_rx, FUNC(specnext_im2_device::irq_w)); m_uart[1]->out_tx_empty_callback().set(m_im2_uart1_tx, FUNC(specnext_im2_device::irq_w)); rs232_port_device &rs232_rpi(RS232_PORT(config, "rs232_rpi", rs232_devices, nullptr)); rs232_rpi.rxd_handler().set(m_uart[1], FUNC(specnext_uart_device::rx_w)); rs232_rpi.set_option_device_input_defaults("null_modem", DEVICE_INPUT_DEFAULTS_NAME(rs232_baud)); rs232_rpi.set_option_device_input_defaults("pty", DEVICE_INPUT_DEFAULTS_NAME(rs232_baud)); auto &mdin(MIDI_PORT(config, "mdin", midiin_slot, "midiin")); mdin.rxd_handler().set("mdthru", FUNC(midi_port_device::write_txd)); mdin.rxd_handler().append(FUNC(specnext_state::rxd_w)); MIDI_PORT(config, "mdthru", midiout_slot, "midiout"); MIDI_PORT(config, m_midi_out, midiout_slot, "midiout"); SPI_SDCARD(config, m_sdcards[0], 0); m_sdcards[0]->set_prefer_sdhc(); m_sdcards[0]->spi_miso_callback().set(FUNC(specnext_state::spi_miso_w)); SPI_SDCARD(config, m_sdcards[1], 0); m_sdcards[1]->set_prefer_sdhc(); m_sdcards[1]->spi_miso_callback().set(FUNC(specnext_state::spi_miso_w)); SPEAKER(config.replace(), "speakers", 2).front(); m_speaker->add_route(ALL_OUTPUTS, "speakers", 0.50, 1); DAC_8BIT_R2R(config, m_dac[0], 0).add_route(ALL_OUTPUTS, "speakers", 0.75, 0); DAC_8BIT_R2R(config, m_dac[1], 0).add_route(ALL_OUTPUTS, "speakers", 0.75, 0); DAC_8BIT_R2R(config, m_dac[2], 0).add_route(ALL_OUTPUTS, "speakers", 0.75, 1); DAC_8BIT_R2R(config, m_dac[3], 0).add_route(ALL_OUTPUTS, "speakers", 0.75, 1); config.device_remove("ay_slot"); for (auto i = 0; i < 3; ++i) { YM2149(config, m_ay[i], 14_MHz_XTAL / 8) .add_route(0, "speakers", 0.50, 0) .add_route(1, "speakers", 0.25, 0) .add_route(1, "speakers", 0.25, 1) .add_route(2, "speakers", 0.50, 1); } SPECNEXT_MULTIFACE(config, m_mf, 0); SPECNEXT_DIVMMC(config, m_divmmc, 0); zxbus_device &zxbus(ZXBUS(config, "zxbus", 0)); ZXBUS_SLOT(config, "zxbus:1", 0, zxbus, zxbus_cards, nullptr); m_screen->set_raw(28_MHz_XTAL / 2, 456 << 1, 312, { 0, (359 << 1) | 1, 0, 287 }); m_screen->set_screen_update(FUNC(specnext_state::screen_update)); m_screen->set_no_palette(); PALETTE(config.replace(), m_palette, palette_device::BLACK, 512 * (3 + 1 * 2) + 1); // ula tm l2 s*2 +1 == fallback subdevice("gfxdecode")->set_info(gfx_tbblue); SPECTRUM_ULA_UNCONTENDED(config.replace(), m_ula); SCREEN_ULA_NEXT (config, m_ula_scr, 0).set_palette(m_palette->device().tag(), 0x000, 0x100); SPECNEXT_LORES (config, m_lores, 0).set_palette(m_palette->device().tag(), 0x000, 0x100); SPECNEXT_TILES (config, m_tiles, 0).set_palette(m_palette->device().tag(), 0x200, 0x300); SPECNEXT_LAYER2 (config, m_layer2, 0).set_palette(m_palette->device().tag(), 0x400, 0x500); // drawgfx doesn't allow to mask palette access and in case of 256-color sprite does use offset, the index overflow palette boundries. // We are duplicating palletes to imitate mask on palette index which required by sprites device. SPECNEXT_SPRITES(config, m_sprites, 0).set_palette(m_palette->device().tag(), 0x600, 0x800); SPECNEXT_COPPER(config, m_copper, 28_MHz_XTAL); m_copper->out_nextreg_cb().set([this](offs_t offset, u8 data) { m_next_regs.write_byte(offset, data); }); m_copper->set_in_until_pos_cb(FUNC(specnext_state::copper_until_pos_r)); SOFTWARE_LIST(config, "sd_list").set_original("specnext_sd"); config.device_remove("snapshot"); m_machine_id = 0x08; m_board_issue = 0; m_ram->set_default_size("2M").set_extra_options("1M,4M").set_default_value(0); } void specnext_state::ks1(machine_config &config) { tbblue(config); m_machine_id = 0x0a; m_board_issue = 1; m_ram->set_default_size("1M").set_extra_options("2M"); } void specnext_state::ks2(machine_config &config) { tbblue(config); m_machine_id = 0x0a; m_board_issue = 2; m_ram->set_default_size("2M").set_extra_options(nullptr); } void specnext_state::ks3(machine_config &config) { tbblue(config); m_machine_id = 0x0a; m_board_issue = 3; m_ram->set_default_size("4M").set_extra_options(nullptr); } ROM_START(tbblue) ROM_REGION(0x4000, "maincpu", ROMREGION_ERASEFF) ROM_DEFAULT_BIOS("v30204") ROM_SYSTEM_BIOS(0, "v30100", "Next Core v3.01.00") ROMX_LOAD( "boot-30100.bin", 0x0000, 0x2000, CRC(ccbd55ba) SHA1(8b3c2a301f486904d1c74929b94845a7731bf230), ROM_BIOS(0)) ROMX_LOAD( "boot-30100.bin", 0x2000, 0x2000, CRC(ccbd55ba) SHA1(8b3c2a301f486904d1c74929b94845a7731bf230), ROM_BIOS(0)) ROM_SYSTEM_BIOS(1, "v30200ab", "Anti-Brick Core v3.02.00") ROMX_LOAD( "boot-30200-ab.bin", 0x0000, 0x2000, CRC(1d16e9d4) SHA1(6f9c8771e5a9ef5a6b52a31b2e65f0698f0f5cfa), ROM_BIOS(1)) ROMX_LOAD( "boot-30100.bin", 0x2000, 0x2000, CRC(ccbd55ba) SHA1(8b3c2a301f486904d1c74929b94845a7731bf230), ROM_BIOS(1)) ROM_SYSTEM_BIOS(2, "v30204", "Next Core v3.02.04") ROMX_LOAD( "boot-30204.bin", 0x0000, 0x2000, CRC(95118eb6) SHA1(acf5112e831be8c73952b8513fab33a427e88cf8), ROM_BIOS(2)) ROMX_LOAD( "boot-30204.bin", 0x2000, 0x2000, CRC(95118eb6) SHA1(acf5112e831be8c73952b8513fab33a427e88cf8), ROM_BIOS(2)) ROM_SYSTEM_BIOS(3, "v30204ab", "Anti-Brick Core v3.02.04") ROMX_LOAD( "boot-30204-ab.bin", 0x0000, 0x2000, CRC(96c32007) SHA1(6c9fcbd282f7a18fb5a726386ac6fb9df209c36b), ROM_BIOS(3)) ROMX_LOAD( "boot-30204.bin", 0x2000, 0x2000, CRC(95118eb6) SHA1(acf5112e831be8c73952b8513fab33a427e88cf8), ROM_BIOS(3)) ROM_END #define rom_specnext_ks1 rom_tbblue #define rom_specnext_ks2 rom_tbblue ROM_START(specnext_ks3) ROM_REGION(0x4000, "maincpu", ROMREGION_ERASEFF) ROM_DEFAULT_BIOS("v30204") ROM_SYSTEM_BIOS(0, "v30204", "Next Core v3.02.04") ROMX_LOAD( "boot-30204.bin", 0x0000, 0x2000, CRC(95118eb6) SHA1(acf5112e831be8c73952b8513fab33a427e88cf8), ROM_BIOS(0)) ROMX_LOAD( "boot-30204.bin", 0x2000, 0x2000, CRC(95118eb6) SHA1(acf5112e831be8c73952b8513fab33a427e88cf8), ROM_BIOS(0)) ROM_SYSTEM_BIOS(1, "v30204ab", "Anti-Brick Core v3.02.04") ROMX_LOAD( "boot-30204-ab.bin", 0x0000, 0x2000, CRC(96c32007) SHA1(6c9fcbd282f7a18fb5a726386ac6fb9df209c36b), ROM_BIOS(1)) ROMX_LOAD( "boot-30204.bin", 0x2000, 0x2000, CRC(95118eb6) SHA1(acf5112e831be8c73952b8513fab33a427e88cf8), ROM_BIOS(1)) ROM_END } // Anonymous namespace /* YEAR NAME PARENT COMPAT MACHINE INPUT CLASS INIT COMPANY FULLNAME FLAGS */ COMP( 2017, tbblue, 0 , 0, tbblue, specnext, specnext_state, empty_init, "SpecNext Ltd., Victor Trucco, Fabio Belavenuto", "ZX Spectrum Next: Emulators ID", MACHINE_SUPPORTS_SAVE ) COMP( 2020, specnext_ks1, tbblue, 0, ks1, specnext, specnext_state, empty_init, "SpecNext Ltd., Victor Trucco, Fabio Belavenuto", "ZX Spectrum Next: KS1", MACHINE_SUPPORTS_SAVE ) COMP( 2023, specnext_ks2, tbblue, 0, ks2, specnext, specnext_state, empty_init, "SpecNext Ltd., Victor Trucco, Fabio Belavenuto", "ZX Spectrum Next: KS2", MACHINE_SUPPORTS_SAVE ) COMP( 2025, specnext_ks3, tbblue, 0, ks3, specnext, specnext_state, empty_init, "SpecNext Ltd., Victor Trucco, Fabio Belavenuto", "ZX Spectrum Next: KS3", MACHINE_SUPPORTS_SAVE )