diff --git a/hash/lynx.xml b/hash/lynx.xml index 4ffaad52505..dc883cdef06 100644 --- a/hash/lynx.xml +++ b/hash/lynx.xml @@ -37,6 +37,7 @@ Known undumped prototypes: Atari + @@ -48,6 +49,7 @@ Known undumped prototypes: 199? Atari + @@ -60,6 +62,7 @@ Known undumped prototypes: Atari + @@ -72,6 +75,7 @@ Known undumped prototypes: Atari + @@ -84,6 +88,7 @@ Known undumped prototypes: Atari + @@ -96,6 +101,7 @@ Known undumped prototypes: Atari + @@ -108,6 +114,7 @@ Known undumped prototypes: Beyond Games + @@ -120,6 +127,7 @@ Known undumped prototypes: Atari + @@ -132,6 +140,7 @@ Known undumped prototypes: Atari + @@ -144,6 +153,7 @@ Known undumped prototypes: Atari + @@ -156,6 +166,7 @@ Known undumped prototypes: Atari + @@ -168,6 +179,7 @@ Known undumped prototypes: Atari + @@ -180,6 +192,7 @@ Known undumped prototypes: Telegames + @@ -192,6 +205,7 @@ Known undumped prototypes: Atari + @@ -204,6 +218,7 @@ Known undumped prototypes: Shadowsoft + @@ -216,6 +231,7 @@ Known undumped prototypes: Atari + @@ -228,6 +244,7 @@ Known undumped prototypes: Atari + @@ -240,6 +257,7 @@ Known undumped prototypes: Atari + @@ -252,6 +270,7 @@ Known undumped prototypes: Songbird Productions + @@ -263,6 +282,7 @@ Known undumped prototypes: 199? Atari + @@ -275,6 +295,7 @@ Known undumped prototypes: Telegames + @@ -287,6 +308,7 @@ Known undumped prototypes: Atari + @@ -299,6 +321,7 @@ Known undumped prototypes: Atari + @@ -311,6 +334,7 @@ Known undumped prototypes: Telegames + @@ -323,6 +347,7 @@ Known undumped prototypes: Atari + @@ -335,6 +360,7 @@ Known undumped prototypes: Atari + @@ -347,6 +373,7 @@ Known undumped prototypes: Telegames + @@ -358,6 +385,7 @@ Known undumped prototypes: 199? NuFX + @@ -369,6 +397,7 @@ Known undumped prototypes: 199? Telegames + @@ -381,6 +410,7 @@ Known undumped prototypes: Telegames + @@ -393,6 +423,7 @@ Known undumped prototypes: Atari + @@ -406,6 +437,7 @@ Known undumped prototypes: + @@ -418,6 +450,7 @@ Known undumped prototypes: Atari + @@ -430,6 +463,7 @@ Known undumped prototypes: Atari + @@ -442,6 +476,7 @@ Known undumped prototypes: Atari + @@ -454,6 +489,7 @@ Known undumped prototypes: Atari + @@ -466,6 +502,7 @@ Known undumped prototypes: Atari + @@ -478,6 +515,7 @@ Known undumped prototypes: Atari + @@ -490,6 +528,7 @@ Known undumped prototypes: Williams Entertainment + @@ -503,6 +542,7 @@ Known undumped prototypes: + @@ -515,6 +555,7 @@ Known undumped prototypes: Telegames + @@ -527,6 +568,7 @@ Known undumped prototypes: Atari + @@ -539,6 +581,7 @@ Known undumped prototypes: Atari + @@ -552,6 +595,7 @@ Known undumped prototypes: + @@ -564,6 +608,7 @@ Known undumped prototypes: Songbird Productions + @@ -576,6 +621,7 @@ Known undumped prototypes: Atari + @@ -588,6 +634,7 @@ Known undumped prototypes: Atari + @@ -599,6 +646,7 @@ Known undumped prototypes: 1993 Digital Image + @@ -611,6 +659,7 @@ Known undumped prototypes: Songbird Productions + @@ -623,6 +672,7 @@ Known undumped prototypes: Atari + @@ -636,6 +686,7 @@ Known undumped prototypes: + @@ -648,6 +699,7 @@ Known undumped prototypes: Atari + @@ -660,6 +712,7 @@ Known undumped prototypes: Atari + @@ -672,6 +725,7 @@ Known undumped prototypes: Atari + @@ -684,6 +738,7 @@ Known undumped prototypes: Atari + @@ -696,6 +751,7 @@ Known undumped prototypes: Atari + @@ -708,6 +764,7 @@ Known undumped prototypes: Atari + @@ -720,6 +777,7 @@ Known undumped prototypes: Songbird Productions + @@ -732,6 +790,7 @@ Known undumped prototypes: Atari + @@ -744,6 +803,7 @@ Known undumped prototypes: Telegames + @@ -756,6 +816,7 @@ Known undumped prototypes: Telegames + @@ -768,6 +829,7 @@ Known undumped prototypes: Atari + @@ -780,6 +842,7 @@ Known undumped prototypes: Atari + @@ -791,6 +854,7 @@ Known undumped prototypes: 199? Atari + @@ -803,6 +867,7 @@ Known undumped prototypes: Atari + @@ -815,6 +880,7 @@ Known undumped prototypes: Atari + @@ -827,6 +893,7 @@ Known undumped prototypes: Williams Entertainment + @@ -839,6 +906,7 @@ Known undumped prototypes: Atari + @@ -851,6 +919,7 @@ Known undumped prototypes: Atari + @@ -863,6 +932,7 @@ Known undumped prototypes: Atari + @@ -875,6 +945,7 @@ Known undumped prototypes: Atari + @@ -887,6 +958,7 @@ Known undumped prototypes: Atari + @@ -899,6 +971,7 @@ Known undumped prototypes: Atari + @@ -911,6 +984,7 @@ Known undumped prototypes: Atari + @@ -923,6 +997,7 @@ Known undumped prototypes: Telegames + @@ -935,6 +1010,7 @@ Known undumped prototypes: Atari + @@ -947,6 +1023,7 @@ Known undumped prototypes: Atari + @@ -959,6 +1036,7 @@ Known undumped prototypes: Atari + @@ -971,6 +1049,7 @@ Known undumped prototypes: Atari + @@ -983,6 +1062,7 @@ Known undumped prototypes: Atari + @@ -995,6 +1075,7 @@ Known undumped prototypes: Atari + @@ -1007,6 +1088,7 @@ Known undumped prototypes: Atari + @@ -1019,6 +1101,7 @@ Known undumped prototypes: Atari + @@ -1031,6 +1114,7 @@ Known undumped prototypes: Atari + @@ -1043,6 +1127,7 @@ Known undumped prototypes: Atari + @@ -1055,13 +1140,14 @@ Known undumped prototypes: Atari + - + Yastuna Vol.1 - The Alchemy of Cubes 2008 Fadest @@ -1072,7 +1158,7 @@ Known undumped prototypes: - + Yastuna Vol.2 - The Space Incident 2008 Fadest @@ -1089,18 +1175,21 @@ Known undumped prototypes: Atari + - + Alpine Games 2004 <homebrew> + + @@ -1114,6 +1203,7 @@ Known undumped prototypes: <homebrew> + @@ -1125,6 +1215,7 @@ Known undumped prototypes: 1995 <unknown> + @@ -1136,6 +1227,7 @@ Known undumped prototypes: 19?? <unknown> + @@ -1148,6 +1240,7 @@ Known undumped prototypes: <homebrew> + @@ -1159,6 +1252,7 @@ Known undumped prototypes: 2016 Luchs Soft + @@ -1170,6 +1264,7 @@ Known undumped prototypes: 2009 Super Fighter Team / Penguinet + @@ -1181,6 +1276,7 @@ Known undumped prototypes: 2009 Penguinet + diff --git a/scripts/src/sound.lua b/scripts/src/sound.lua index da54941155b..00e5d9f4c43 100644 --- a/scripts/src/sound.lua +++ b/scripts/src/sound.lua @@ -1565,3 +1565,15 @@ if (SOUNDS["UDA1344"]~=null) then MAME_DIR .. "src/devices/sound/uda1344.h", } end + +--------------------------------------------------- +-- +--@src/devices/sound/lynx.h,SOUNDS["LYNX"] = true +--------------------------------------------------- + +if (SOUNDS["LYNX"]~=null) then + files { + MAME_DIR .. "src/devices/sound/lynx.cpp", + MAME_DIR .. "src/devices/sound/lynx.h", + } +end diff --git a/scripts/target/mame/arcade.lua b/scripts/target/mame/arcade.lua index a962a7a7c57..7eea5036039 100644 --- a/scripts/target/mame/arcade.lua +++ b/scripts/target/mame/arcade.lua @@ -298,6 +298,7 @@ SOUNDS["TT5665"] = true --SOUNDS["UDA1344"] = true SOUNDS["SWP30"] = true SOUNDS["XT446"] = true +--SOUNDS["LYNX"] = true -------------------------------------------------- -- specify available video cores diff --git a/scripts/target/mame/mess.lua b/scripts/target/mame/mess.lua index a828abdb146..5d92661b03f 100644 --- a/scripts/target/mame/mess.lua +++ b/scripts/target/mame/mess.lua @@ -325,6 +325,7 @@ SOUNDS["ROLANDPCM"] = true --SOUNDS["TT5665"] = true SOUNDS["RP2C33_SOUND"] = true SOUNDS["UDA1344"] = true +SOUNDS["LYNX"] = true -------------------------------------------------- -- specify available video cores @@ -1913,8 +1914,6 @@ files { MAME_DIR .. "src/mame/video/atarist.h", MAME_DIR .. "src/mame/drivers/lynx.cpp", MAME_DIR .. "src/mame/includes/lynx.h", - MAME_DIR .. "src/mame/audio/lynx.cpp", - MAME_DIR .. "src/mame/audio/lynx.h", MAME_DIR .. "src/mame/machine/lynx.cpp", MAME_DIR .. "src/mame/drivers/pofo.cpp", MAME_DIR .. "src/mame/machine/pofo_kbd.cpp", diff --git a/src/mame/audio/lynx.cpp b/src/devices/sound/lynx.cpp similarity index 84% rename from src/mame/audio/lynx.cpp rename to src/devices/sound/lynx.cpp index d839a4c1704..d546e4ce00c 100644 --- a/src/mame/audio/lynx.cpp +++ b/src/devices/sound/lynx.cpp @@ -1,11 +1,15 @@ // license:GPL-2.0+ // copyright-holders:Peter Trauner /****************************************************************************** + + Atari Lynx sound hardware, Part of Mikey (Hayato in Lynx II) PeT mess@utanet.at 2000,2001 + ******************************************************************************/ #include "emu.h" -#include "audio/lynx.h" +#include "lynx.h" +#include /* accordingly to atari's reference manual @@ -85,8 +89,8 @@ AUD_A_RIGHT EQU %00000001 // device type definition -DEFINE_DEVICE_TYPE(LYNX_SND, lynx_sound_device, "lynx_sound", "Mikey") -DEFINE_DEVICE_TYPE(LYNX2_SND, lynx2_sound_device, "lynx2_sound", "Mikey (Lynx II)") +DEFINE_DEVICE_TYPE(LYNX_SND, lynx_sound_device, "lynx_sound", "Atari Mikey (Sound)") +DEFINE_DEVICE_TYPE(LYNX2_SND, lynx2_sound_device, "lynx2_sound", "Atari Hayato (Sound)") //************************************************************************** // LIVE DEVICE @@ -172,8 +176,7 @@ void lynx_sound_device::init() void lynx_sound_device::device_start() { - m_mixer_channel = stream_alloc(0, 1, machine().sample_rate()); - m_usec_per_sample = 1000000 / machine().sample_rate(); + m_mixer_channel = stream_alloc(0, 1, clock() / 16); m_timer_delegate.resolve(); init(); register_save(); @@ -182,8 +185,7 @@ void lynx_sound_device::device_start() void lynx2_sound_device::device_start() { - m_mixer_channel = stream_alloc(0, 2, machine().sample_rate()); - m_usec_per_sample = 1000000 / machine().sample_rate(); + m_mixer_channel = stream_alloc(0, 2, clock() / 16); m_timer_delegate.resolve(); init(); register_save(); @@ -201,6 +203,15 @@ void lynx_sound_device::device_reset() } } +//------------------------------------------------- +// device_clock_changed - called if the clock +// changes +//------------------------------------------------- + +void lynx_sound_device::device_clock_changed() +{ + m_mixer_channel->set_sample_rate(clock() / 16); +} void lynx_sound_device::reset_channel(LYNX_AUDIO *channel) { @@ -223,7 +234,7 @@ void lynx_sound_device::reset_channel(LYNX_AUDIO *channel) void lynx_sound_device::count_down(int nr) { LYNX_AUDIO *channel = &m_audio[nr]; - if (channel->reg.control1 & 8 && (channel->reg.control1 & 7) != 7) + if ((channel->reg.count_en()) && (!(channel->reg.linked()))) return; if (nr == 0) m_mixer_channel->update(); @@ -233,25 +244,25 @@ void lynx_sound_device::count_down(int nr) void lynx_sound_device::shift(int chan_nr) { - int16_t out_temp; + s16 out_temp; LYNX_AUDIO *channel; assert(chan_nr < 4); channel = &m_audio[chan_nr]; - //channel->shifter = ((channel->shifter<<1)&0xffe) | (m_shift_xor[ channel->shifter & channel->mask ]&1); + //channel->shifter = ((channel->shifter << 1) & 0xffe) | (m_shift_xor[channel->shifter & channel->mask] & 1); // alternative method (functionally the same as above) - uint8_t xor_out = 0; + u8 xor_out = 1; // output of xor is inverted for (int bit = 0; bit < 12; bit++) { - if ((channel->mask >> bit) & 1) - xor_out ^= (channel->shifter >> bit) & 1; + if (BIT(channel->mask, bit)) + xor_out ^= BIT(channel->shifter, bit); } - channel->shifter = ((channel->shifter << 1) & 0xffe) | (xor_out ^ 1); // output of xor is inverted + channel->shifter = ((channel->shifter << 1) & 0xffe) | xor_out; - if (channel->reg.control1 & 0x20) // integrate mode enabled + if (channel->reg.integrate_mode()) // integrate mode enabled { if (channel->shifter & 1) out_temp = channel->reg.output + channel->reg.volume; @@ -259,9 +270,7 @@ void lynx_sound_device::shift(int chan_nr) out_temp = channel->reg.output - channel->reg.volume; // clipping - if (out_temp > 127) out_temp = 127; - if (out_temp < -128) out_temp = -128; - channel->reg.output = (int16_t)out_temp; + channel->reg.output = std::clamp(out_temp, -128, 127); } switch (chan_nr) @@ -284,22 +293,22 @@ void lynx_sound_device::execute(int chan_nr) channel = &m_audio[chan_nr]; - if (channel->reg.control1 & 8) // count enable + if (channel->reg.count_en()) // count enable { - channel->ticks += m_usec_per_sample; - if ((channel->reg.control1 & 7) == 7) // link + channel->ticks++; + if (channel->reg.linked()) // link { if (channel->count < 0) // counter finished { //channel->count+=channel->reg.counter; // reload (wrong?) - if (channel->reg.control1 & 0x10) + if (channel->reg.reload_en()) channel->count = channel->reg.bakup; shift(chan_nr); } } else { - int t = 1 << (channel->reg.control1 & 7); // microseconds per count + const int t = 1 << (channel->reg.timer_clock()); // microseconds per count for (;;) { for (; (channel->ticks >= t) && (channel->count >= 0); channel->ticks -= t) // at least one sampled worth of time left, timer not expired @@ -311,7 +320,7 @@ void lynx_sound_device::execute(int chan_nr) if (channel->count < 0) { shift(chan_nr); - if (channel->reg.control1 & 0x10) + if (channel->reg.reload_en()) channel->count = channel->reg.bakup; else break; @@ -319,10 +328,9 @@ void lynx_sound_device::execute(int chan_nr) } } - if (!(channel->reg.control1 & 0x20)) // normal mode - { - channel->reg.output = (channel->shifter & 1) ? channel->reg.volume : -channel->reg.volume; - } + if (!(channel->reg.integrate_mode())) // normal mode + channel->reg.output = BIT(channel->shifter, 0) ? channel->reg.volume : -channel->reg.volume; + } else { @@ -331,9 +339,9 @@ void lynx_sound_device::execute(int chan_nr) } } -uint8_t lynx_sound_device::read(offs_t offset) +u8 lynx_sound_device::read(offs_t offset) { - uint8_t value = 0; + u8 value = 0; LYNX_AUDIO *channel = &m_audio[(offset >> 3) & 3]; m_mixer_channel->update(); @@ -363,7 +371,7 @@ uint8_t lynx_sound_device::read(offs_t offset) break; case 6: //current timer value - if (channel->count >=0) + if (channel->count >= 0) value = channel->count; else value = 0; @@ -394,7 +402,7 @@ uint8_t lynx_sound_device::read(offs_t offset) return value; } -void lynx_sound_device::write(offs_t offset, uint8_t data) +void lynx_sound_device::write(offs_t offset, u8 data) { //logerror("audio write %.2x %.2x\n", offset, data); LYNX_AUDIO *channel = &m_audio[(offset >> 3) & 3]; @@ -414,7 +422,7 @@ void lynx_sound_device::write(offs_t offset, uint8_t data) case 1: channel->reg.feedback = data; channel->mask &= 0x80; - channel->mask |= (data & 0x3f) | ((data & 0xc0)<<4); + channel->mask |= (data & 0x3f) | ((data & 0xc0) << 4); break; // Output value case 2: @@ -433,17 +441,17 @@ void lynx_sound_device::write(offs_t offset, uint8_t data) // Audio control bits case 5: channel->mask &= ~0x80; - channel->mask |= (data&0x80); + channel->mask |= (data & 0x80); channel->reg.control1 = data; break; // Current count case 6: - channel->count=data; + channel->count = data; break; // Upper 4 bits of shift register and audio status bits case 7: - channel->shifter&=0xff; - channel->shifter|=(data&0xf0)<<4; + channel->shifter &= 0xff; + channel->shifter |= (data & 0xf0) << 4; channel->reg.control2 = data; break; } @@ -453,7 +461,7 @@ void lynx_sound_device::write(offs_t offset, uint8_t data) switch (offset) // Stereo Registers { case 0x40: case 0x41: case 0x42: case 0x43: - m_audio[offset&3].attenuation = data; + m_audio[offset & 3].attenuation = data; break; case 0x44: m_attenuation_enable = data; @@ -472,7 +480,6 @@ void lynx_sound_device::write(offs_t offset, uint8_t data) void lynx_sound_device::sound_stream_update(sound_stream &stream, std::vector const &inputs, std::vector &outputs) { - int v; auto &buffer = outputs[0]; for (int i = 0; i < buffer.samples(); i++) @@ -481,8 +488,7 @@ void lynx_sound_device::sound_stream_update(sound_stream &stream, std::vector const &inputs, std::vector &outputs) { - auto &left=outputs[0]; - auto &right=outputs[1]; - int v; + auto &left = outputs[0]; + auto &right = outputs[1]; for (int i = 0; i < left.samples(); i++) { @@ -505,7 +510,7 @@ void lynx2_sound_device::sound_stream_update(sound_stream &stream, std::vector void set_timer_delegate(T &&... args) { m_timer_delegate.set(std::forward(args)...); } protected: struct LYNX_AUDIO { struct { - int8_t volume; - uint8_t feedback; - int8_t output; - uint8_t shifter; - uint8_t bakup; - uint8_t control1; - uint8_t counter; - uint8_t control2; + //bool reset_done() const { return BIT(control1, 6); } // Reset timer done flag (not implemented) + bool integrate_mode() const { return BIT(control1, 5); } // Integrate mode + bool reload_en() const { return BIT(control1, 4); } // Reload enable + bool count_en() const { return BIT(control1, 3); } // Count enable + u8 timer_clock() const { return BIT(control1, 0, 3); } // Timer clock + bool linked() const { return timer_clock() == 0b111; } // Linked timer? + + //bool last_clock() const { return BIT(control2, 2); } // Last clock (not implemented) + //bool borrow_in() const { return BIT(control2, 1); } // Borrow in (not implemented) + //bool borrow_out() const { return BIT(control2, 0); } // Borrow out (not implemented) + + s8 volume = 0; + u8 feedback = 0; + s8 output = 0; + u8 shifter = 0; + u8 bakup = 0; + u8 control1 = 0; + u8 counter = 0; + u8 control2 = 0; } reg; - uint8_t attenuation; - uint16_t mask; // 12-bit - uint16_t shifter; // 12-bit - float ticks; - int count; + u8 attenuation = 0; + u16 mask = 0; // 12-bit + u16 shifter = 0; // 12-bit + s16 ticks = 0; + s16 count = 0; }; lynx_sound_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock); // device-level overrides virtual void device_start() override; - virtual void device_reset() override; + virtual void device_clock_changed() override; // sound stream update overrides virtual void sound_stream_update(sound_stream &stream, std::vector const &inputs, std::vector &outputs) override; @@ -54,13 +65,12 @@ protected: void register_save(); sound_stream *m_mixer_channel; - timer_delegate m_timer_delegate; // this calls lynx_timer_count_down from the driver state + timer_delegate m_timer_delegate; // this calls lynx_timer_count_down from the driver state - float m_usec_per_sample; std::unique_ptr m_shift_mask; std::unique_ptr m_shift_xor; - uint8_t m_attenuation_enable; - uint8_t m_master_enable; + u8 m_attenuation_enable = 0; + u8 m_master_enable = 0; LYNX_AUDIO m_audio[4]; }; @@ -82,4 +92,4 @@ protected: DECLARE_DEVICE_TYPE(LYNX_SND, lynx_sound_device) DECLARE_DEVICE_TYPE(LYNX2_SND, lynx2_sound_device) -#endif // MAME_AUDIO_LYNX_H +#endif // MAME_SOUND_LYNX_H diff --git a/src/mame/drivers/lynx.cpp b/src/mame/drivers/lynx.cpp index 68a5e89ebc8..5dfe482607b 100644 --- a/src/mame/drivers/lynx.cpp +++ b/src/mame/drivers/lynx.cpp @@ -1,16 +1,23 @@ // license:GPL-2.0+ // copyright-holders:Peter Trauner /****************************************************************************** + + Atari Lynx PeT peter.trauner@utanet.at 2000,2001 info found in bastian schick's bll and in cc65 for lynx + TODO: + - ComLynx emulation is missing/imperfect + - Verify timings from real hardware + - EEPROM Support in some homebrew cartridges? + - Lynx II support, needs internal ROM dump + ******************************************************************************/ #include "emu.h" #include "includes/lynx.h" -#include "audio/lynx.h" #include "cpu/m6502/m65sc02.h" #include "softlist.h" @@ -18,27 +25,19 @@ #include "lynx.lh" -void lynx_state::lynx_mem(address_map &map) +void lynx_state::cpu_map(address_map &map) { - map(0x0000, 0xfbff).ram().share("mem_0000"); - map(0xfc00, 0xfcff).m(m_bank_fc00, FUNC(address_map_bank_device::amap8)); - map(0xfd00, 0xfdff).m(m_bank_fd00, FUNC(address_map_bank_device::amap8)); - map(0xfe00, 0xfff7).bankr("bank_fe00").writeonly().share("mem_fe00"); - map(0xfff8, 0xfff8).ram(); - map(0xfff9, 0xfff9).rw(FUNC(lynx_state::lynx_memory_config_r), FUNC(lynx_state::lynx_memory_config_w)); - map(0xfffa, 0xffff).bankr("bank_fffa").writeonly().share("mem_fffa"); -} - -void lynx_state::lynx_fc00_mem(address_map &map) -{ - map(0x000, 0x0ff).rw(FUNC(lynx_state::suzy_read), FUNC(lynx_state::suzy_write)); - map(0x100, 0x1ff).ram().share("mem_fc00"); -} - -void lynx_state::lynx_fd00_mem(address_map &map) -{ - map(0x000, 0x0ff).rw(FUNC(lynx_state::mikey_read), FUNC(lynx_state::mikey_write)); - map(0x100, 0x1ff).ram().share("mem_fd00"); + map(0x0000, 0xffff).ram().share(m_dram); + map(0xfc00, 0xfcff).view(m_suzy_view); + m_suzy_view[0](0xfc00, 0xfcff).rw(FUNC(lynx_state::suzy_read), FUNC(lynx_state::suzy_write)); + map(0xfd00, 0xfdff).view(m_mikey_view); + m_mikey_view[0](0xfd00, 0xfdff).rw(FUNC(lynx_state::mikey_read), FUNC(lynx_state::mikey_write)); + map(0xfe00, 0xffff).view(m_rom_view); + m_rom_view[0](0xfe00, 0xfff7).rom().region("maincpu", 0x0000); + map(0xfff8, 0xfff8).ram(); // Reserved for future hardware (RAM) + map(0xfff9, 0xfff9).rw(FUNC(lynx_state::memory_config_r), FUNC(lynx_state::memory_config_w)); + map(0xfff8, 0xffff).view(m_vector_view); + m_vector_view[0](0xfffa, 0xffff).rom().region("maincpu", 0x01fa); } static INPUT_PORTS_START( lynx ) @@ -54,6 +53,8 @@ static INPUT_PORTS_START( lynx ) PORT_START("PAUSE") PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME(DEF_STR(Pause)) PORT_CODE(KEYCODE_3) + //PORT_BIT( 0x02, IP_ACTIVE_HIGH, IPT_OTHER ) CART0 Strobe + //PORT_BIT( 0x04, IP_ACTIVE_HIGH, IPT_OTHER ) CART1 Strobe // power on and power off buttons INPUT_PORTS_END @@ -62,34 +63,31 @@ void lynx_state::video_start() m_screen->register_screen_bitmap(m_bitmap); } -uint32_t lynx_state::screen_update(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect) +u32 lynx_state::screen_update(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect) { copybitmap(bitmap, m_bitmap, 0, 0, 0, 0, cliprect); return 0; } -// callback for Mikey call of shift(3) which shall act on the lynx_timer_count_down +// callback for Mikey call of shift(3) which shall act on the timer_count_down void lynx_state::sound_cb() { - lynx_timer_count_down(1); + timer_count_down(1); } void lynx_state::lynx(machine_config &config) { /* basic machine hardware */ - M65SC02(config, m_maincpu, 4000000); /* vti core, integrated in vlsi, stz, but not bbr bbs */ - m_maincpu->set_addrmap(AS_PROGRAM, &lynx_state::lynx_mem); + M65SC02(config, m_maincpu, XTAL(16'000'000) / 4); /* vti core, integrated in vlsi, stz, but not bbr bbs */ + m_maincpu->set_addrmap(AS_PROGRAM, &lynx_state::cpu_map); config.set_maximum_quantum(attotime::from_hz(60)); - ADDRESS_MAP_BANK(config, "bank_fc00").set_map(&lynx_state::lynx_fc00_mem).set_options(ENDIANNESS_LITTLE, 8, 9, 0x100); - ADDRESS_MAP_BANK(config, "bank_fd00").set_map(&lynx_state::lynx_fd00_mem).set_options(ENDIANNESS_LITTLE, 8, 9, 0x100); - /* video hardware */ SCREEN(config, m_screen, SCREEN_TYPE_LCD); - m_screen->set_refresh_hz(30); + m_screen->set_refresh_hz(XTAL(16'000'000) / 16 / (158 + 1) / (104 + 1)); // default config from machine_reset(), actually variable m_screen->set_vblank_time(ATTOSECONDS_IN_USEC(2500)); /* not accurate */ m_screen->set_screen_update(FUNC(lynx_state::screen_update)); - m_screen->set_size(160, 102); + m_screen->set_size(160, 105); // 102 visible scanline + 3 blank scanline, horizontal unknown/unverified, variable? m_screen->set_visarea(0, 160-1, 0, 102-1); config.set_default_layout(layout_lynx); @@ -97,7 +95,7 @@ void lynx_state::lynx(machine_config &config) /* sound hardware */ SPEAKER(config, "mono").front_center(); - LYNX_SND(config, m_sound, 0); + LYNX_SND(config, m_sound, XTAL(16'000'000)); m_sound->set_timer_delegate(FUNC(lynx_state::sound_cb)); m_sound->add_route(ALL_OUTPUTS, "mono", 0.50); @@ -112,6 +110,7 @@ void lynx_state::lynx(machine_config &config) SOFTWARE_LIST(config, "cart_list").set_original("lynx"); } +// Lynx II has Hayato replaces Mikey, Compatible but supports stereo #if 0 void lynx_state::lynx2(machine_config &config) { @@ -121,8 +120,7 @@ void lynx_state::lynx2(machine_config &config) config.device_remove("mono"); SPEAKER(config, "lspeaker").front_left(); SPEAKER(config, "rspeaker").front_right(); - config.device_remove("lynx"); - LYNX2_SND(config.replace(), m_sound, 0); + LYNX2_SND(config.replace(), m_sound, XTAL(16'000'000)); m_sound->set_timer_delegate(FUNC(lynx_state::sound_cb)); m_sound->add_route(0, "lspeaker", 0.50); m_sound->add_route(1, "rspeaker", 0.50); @@ -141,16 +139,12 @@ ROM_START(lynx) ROMX_LOAD("lynx.bin", 0x00000, 0x200, BAD_DUMP CRC(e1ffecb6) SHA1(de60f2263851bbe10e5801ef8f6c357a4bc077e6), ROM_BIOS(0)) ROM_SYSTEM_BIOS( 1, "a", "alternate rom save" ) ROMX_LOAD("lynxa.bin", 0x00000, 0x200, BAD_DUMP CRC(0d973c9d) SHA1(e4ed47fae31693e016b081c6bda48da5b70d7ccb), ROM_BIOS(1)) - - ROM_REGION(0x100,"gfx1", ROMREGION_ERASE00) ROM_END #if 0 ROM_START(lynx2) ROM_REGION(0x200,"maincpu", 0) ROM_LOAD("lynx2.bin", 0, 0x200, NO_DUMP) - - ROM_REGION(0x100,"gfx1", ROMREGION_ERASE00) ROM_END #endif @@ -158,9 +152,9 @@ ROM_END QUICKLOAD_LOAD_MEMBER(lynx_state::quickload_cb) { address_space &space = m_maincpu->space(AS_PROGRAM); - std::vector data; - uint8_t *rom = memregion("maincpu")->base(); - uint8_t header[10]; // 80 08 dw Start dw Len B S 9 3 + std::vector data; + u8 *rom = memregion("maincpu")->base(); + u8 header[10]; // 80 08 dw Start dw Len B S 9 3 uint16_t start, length; int i; @@ -168,7 +162,7 @@ QUICKLOAD_LOAD_MEMBER(lynx_state::quickload_cb) return image_init_result::FAIL; /* Check the image */ - if (lynx_verify_cart((char*)header, LYNX_QUICKLOAD) != image_verify_result::PASS) + if (verify_cart((char*)header, LYNX_QUICKLOAD) != image_verify_result::PASS) { image.seterror(image_error::INVALIDIMAGE, "Not a valid Lynx file"); return image_init_result::FAIL; diff --git a/src/mame/includes/lynx.h b/src/mame/includes/lynx.h index 8d14e0d9dfa..f63fb202f33 100644 --- a/src/mame/includes/lynx.h +++ b/src/mame/includes/lynx.h @@ -1,10 +1,10 @@ // license:GPL-2.0+ // copyright-holders:Peter Trauner /***************************************************************************** - * - * includes/lynx.h - * - ****************************************************************************/ + + Atari Lynx + +******************************************************************************/ #ifndef MAME_INCLUDES_LYNX_H #define MAME_INCLUDES_LYNX_H @@ -12,9 +12,8 @@ #include "emupal.h" #include "screen.h" -#include "audio/lynx.h" +#include "sound/lynx.h" #include "imagedev/snapquik.h" -#include "machine/bankdev.h" #include "bus/generic/slot.h" #include "bus/generic/carts.h" @@ -29,98 +28,188 @@ class lynx_state : public driver_device public: lynx_state(const machine_config &mconfig, device_type type, const char *tag) : driver_device(mconfig, type, tag), - m_mem_0000(*this, "mem_0000"), - m_mem_fc00(*this, "mem_fc00"), - m_mem_fd00(*this, "mem_fd00"), - m_mem_fe00(*this, "mem_fe00"), - m_mem_fffa(*this, "mem_fffa"), + m_dram(*this, "dram"), m_maincpu(*this, "maincpu"), m_sound(*this, "custom"), m_cart(*this, "cartslot"), m_palette(*this, "palette"), m_screen(*this, "screen"), - m_bank_fc00(*this, "bank_fc00"), - m_bank_fd00(*this, "bank_fd00"), - m_bank_fe00(*this, "bank_fe00"), - m_bank_fffa(*this, "bank_fffa") + m_suzy_view(*this, "suzy_view"), + m_mikey_view(*this, "mikey_view"), + m_rom_view(*this, "rom_view"), + m_vector_view(*this, "vector_view"), + m_joy_io(*this, "JOY"), + m_pause_io(*this, "PAUSE") { } void lynx(machine_config &config); +protected: + virtual void machine_start() override; + virtual void machine_reset() override; + virtual void video_start() override; + + virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) override; + virtual void device_post_load() override; + private: struct BLITTER { + // 0xfc80 SPRCTL0 Sprite control bits 0 + u8 BPP() const { return BIT(spr_ctl0, 6, 2); } // Bit per pixel - 1 + bool HFLIP() const { return BIT(spr_ctl0, 5); } // Horizontal flip + bool VFLIP() const { return BIT(spr_ctl0, 4); } // Vertical flip + u8 SPRITE_TYPE() const { return BIT(spr_ctl0, 0, 3); } // Sprite type + + // 0xfc81 SPRCTL1 Sprite control bits 1 + bool RLE() const { return BIT(spr_ctl1, 7); } // Normal(1) or RLE(0) sprite + //bool ALGO3() const { return BIT(spr_ctl1, 6); } // Size algorithm, Adder(0, Algo4), Shifter(1, algo3) (not implemented) + u8 RELOAD_SCALE() const { return BIT(spr_ctl1, 4, 2); } // Reload scale factors + bool REUSE_PALETTE() const { return BIT(spr_ctl1, 3); } // Reload(0) or Reuse(1) palette + bool SKIP_SPRITE() const { return BIT(spr_ctl1, 2); } // Skip this sprite + u8 DRAW_ORIGIN() const { return BIT(spr_ctl1, 0, 2); } // Start draw origin + //bool DRAW_UP() const { return BIT(spr_ctl1, 1); } // Start drawing up(1) or down(0) + //bool DRAW_LEFT() const { return BIT(spr_ctl1, 0); } // Start drawing left(1) or right(0) + + // 0xfc82 SPRCOLL Sprite collision number + bool SPRITE_COLLEN() const { return BIT(spr_coll, 5); } // Sprite collide(0) or Don't collide(1) flag + u8 SPRITE_COLNUM() const { return BIT(spr_coll, 0, 4); } // Sprite collision number + + bool SPRITE_COLLIDE() const { return sprite_collide && (!(no_collide)); } // collision enabled? + // global - uint16_t screen; - uint16_t colbuf; - uint16_t colpos; // byte where value of collision is written - int16_t xoff, yoff; + u16 screen = 0; + u16 colbuf = 0; + u16 colpos = 0; // byte where value of collision is written + s16 xoff = 0; + s16 yoff = 0; // in command - int mode; - uint8_t spr_coll; - uint8_t spritenr; - int16_t x_pos,y_pos; - uint16_t width, height; // uint16 important for blue lightning - int16_t tilt_accumulator; - uint16_t height_accumulator, width_accumulator; - uint16_t width_offset, height_offset; - int16_t stretch, tilt; - uint8_t color[16]; // or stored - uint16_t bitmap; - int use_rle; - int line_color; + u8 mode = 0; + u8 spr_coll = 0; + u8 spritenr = 0; + s16 x_pos = 0; + s16 y_pos = 0; + u16 width = 0; + u16 height = 0; // uint16 important for blue lightning + s16 tilt_accumulator = 0; + u16 height_accumulator = 0; + u16 width_accumulator = 0; + u16 width_offset = 0; + u16 height_offset = 0; + s16 stretch = 0; + s16 tilt = 0; + u8 color[16] = {0}; // or stored + u16 bitmap = 0; + bool use_rle = false; + u8 line_color = 0; - uint8_t spr_ctl0; - uint8_t spr_ctl1; - uint16_t scb; - uint16_t scb_next; - uint8_t sprite_collide; + u8 spr_ctl0 = 0; + u8 spr_ctl1 = 0; + u16 scb = 0; + u16 scb_next = 0; + bool sprite_collide = false; - int everon; - uint8_t fred; - int memory_accesses; - attotime time; + bool everon = false; + u8 fred = 0; + u32 memory_accesses = 0; + //attotime time; - int no_collide; - int vstretch; - int lefthanded; - int busy; + bool no_collide = false; + bool vstretch = false; + bool lefthanded = false; + bool busy = false; }; struct UART { - uint8_t serctl; - uint8_t data_received, data_to_send, buffer; - int received; - int sending; - int buffer_loaded; + // 0xfd8c SERCTL Serial control register (Write) + bool TXINTEN() const { return BIT(serctl, 7); } // Transmit interrupt enable + bool RXINTEN() const { return BIT(serctl, 6); } // Receive interrupt enable + //bool PAREN() const { return BIT(serctl, 4); } // Xmit parity bit enable (not implemented) + //bool RESETERR() const { return BIT(serctl, 3); } // Reset all errors (not implemented) + //bool TXOPEN() const { return BIT(serctl, 2); } // Open collector driver(1) or TTL driver(0) (not implemented) + //bool TXBRK() const { return BIT(serctl, 1); } // Send a break (not implemented) + //bool PAREVEN() const { return BIT(serctl, 0); } // Send/Recevie even parity (not implemented) + + u8 serctl = 0; + u8 data_received = 0; + u8 data_to_send = 0; + u8 buffer = 0; + bool received = false; + bool sending = false; + bool buffer_loaded = false; }; struct SUZY { - uint8_t data[0x100]; - uint8_t high; - int low; - int signed_math; - int accumulate; - int accumulate_overflow; + // 0xfc91 SPRGO Sprite process start bit + bool EVER_ON() const { return BIT(data[0x91], 2); } // Everon detector enable + bool SPRITE_GO() const { return BIT(data[0x91], 0); } // Sprite process enable + + u8 data[0x100] = {0}; + bool signed_math = false; + bool accumulate = false; + bool accumulate_overflow = false; }; struct MIKEY { - uint8_t data[0x100]; - uint16_t disp_addr; - uint8_t vb_rest; + // 0xfd8a IODIR + u8 IODIR() const { return data[0x8a]; } // Parallel I/O direction + + // 0xfd8b IODAT + u8 IODAT() const { return data[0x8b]; } // Parallel I/O data + + // 0xfd92 DISPCTL Video bus request enable + //bool COLOR() const { return BIT(data[0x92], 3); } // Color(1) or Monochrome(0) display (not implemented) + //bool FOURBIT() const { return BIT(data[0x92], 2); } // 4bpp(1) or 2bpp(0) color (not implemented) + bool FLIP_SCREEN() const { return BIT(data[0x92], 1); } // Flipped screen + //bool VIDEO_DMA() const { return BIT(data[0x92], 0); } // Video DMA enabled (not implemented) + + u8 data[0x100] = {0}; + u16 disp_addr = 0; + bool vb_rest = false; + u8 interrupt = 0; }; struct LYNX_TIMER { - uint8_t bakup; - uint8_t cntrl1; - uint8_t cntrl2; - uint8_t counter; - emu_timer *timer; - int timer_active; + bool int_en() const { return BIT(cntrl1, 7); } // Interrupt enable + //bool reset_done() const { return BIT(cntrl1, 6); } // Reset timer done flag + bool reload_en() const { return BIT(cntrl1, 4); } // Reload enable + bool count_en() const { return BIT(cntrl1, 3); } // Count enable + u8 timer_clock() const { return BIT(cntrl1, 0, 3); } // Timer clock + bool linked() const { return timer_clock() == 0b111; } // Linked timer? + + bool timer_done() const { return BIT(cntrl2, 3); } // Timer done flag + //bool last_clock() const { return BIT(cntrl2, 2); } // Last clock (not implemented) + //bool borrow_in() const { return BIT(cntrl2, 1); } // Borrow in (not implemented) + bool borrow_out() const { return BIT(cntrl2, 0); } // Borrow out + + // set timer done flag + void set_timer_done(bool set) + { + if (set) // set + cntrl2 |= 8; + else // clear + cntrl2 &= ~8; + } + + // set borrow out flag + void set_borrow_out(bool set) + { + if (set) // set + cntrl2 |= 1; + else // clear + cntrl2 &= ~1; + } + + u8 bakup = 0; + u8 cntrl1 = 0; + u8 cntrl2 = 0; + u8 counter = 0; + emu_timer *timer = nullptr; + bool timer_active = false; }; enum @@ -131,30 +220,40 @@ private: TIMER_UART }; - virtual void machine_start() override; - virtual void machine_reset() override; - virtual void video_start() override; - virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) override; - - required_shared_ptr m_mem_0000; - required_shared_ptr m_mem_fc00; - required_shared_ptr m_mem_fd00; - required_shared_ptr m_mem_fe00; - required_shared_ptr m_mem_fffa; + // devices + required_shared_ptr m_dram; // 2 64Kx4 bit DRAMs connected to CPU required_device m_maincpu; required_device m_sound; required_device m_cart; required_device m_palette; required_device m_screen; - required_device m_bank_fc00; - required_device m_bank_fd00; - required_memory_bank m_bank_fe00; - required_memory_bank m_bank_fffa; - uint16_t m_granularity; - int m_sign_AB; - int m_sign_CD; - int m_rotate; - uint8_t m_memory_config; + + // memory views + memory_view m_suzy_view; + memory_view m_mikey_view; + memory_view m_rom_view; + memory_view m_vector_view; + + // io ports + required_ioport m_joy_io; + required_ioport m_pause_io; + + // connected to cartridge slot + inline u32 get_cart_addr() { return (BIT(m_mikey.IODAT(), 4) * m_audin_offset) + (m_cart_addr_block * m_granularity) + m_cart_addr_counter; } + u8 m_cart_addr_block = 0; // Address block (74HC164 at schematics, connected to cartridge slot A12...A19) + u16 m_cart_addr_counter = 0; // Address counter (4040 at schematics, connected to cartridge slot A0...A10) + u16 m_granularity = 0; // Address counter granularity + u32 m_audin_offset = 0; // Some cartridge uses AUDIN pin for bankswitch + // AUDIN pin, can be input or output + + // internal states + int m_sign_AB = 1; + int m_sign_CD = 1; + int m_rotate = 0; + u8 m_memory_config; + u32 m_pixclock = ~0; + u8 m_hcount = ~0; + u8 m_vcount = ~0; BLITTER m_blitter; SUZY m_suzy; @@ -165,52 +264,56 @@ private: bitmap_rgb32 m_bitmap; bitmap_rgb32 m_bitmap_temp; - void lynx_mem(address_map &map); - void lynx_fc00_mem(address_map &map); - void lynx_fd00_mem(address_map &map); + void cpu_map(address_map &map); - uint32_t screen_update(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect); + u32 screen_update(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect); - uint8_t suzy_read(offs_t offset); - void suzy_write(offs_t offset, uint8_t data); - void lynx_uart_w(offs_t offset, uint8_t data); - uint8_t lynx_uart_r(offs_t offset); - uint8_t mikey_read(offs_t offset); - void mikey_write(offs_t offset, uint8_t data); - uint8_t lynx_memory_config_r(); - void lynx_memory_config_w(uint8_t data); - void lynx_divide(); - void lynx_multiply(); - uint8_t lynx_timer_read(int which, int offset); - void lynx_timer_write(int which, int offset, uint8_t data); + u8 suzy_read(offs_t offset); + void suzy_write(offs_t offset, u8 data); + void uart_w(offs_t offset, u8 data); + u8 uart_r(offs_t offset); + u8 mikey_read(offs_t offset); + void mikey_write(offs_t offset, u8 data); + u8 memory_config_r(); + void memory_config_w(u8 data); + void suzy_divide(); + void suzy_multiply(); + u8 timer_read(int which, int offset); + void timer_write(int which, int offset, u8 data); + void update_screen_timing(); void sound_cb(); - TIMER_CALLBACK_MEMBER(lynx_blitter_timer); - TIMER_CALLBACK_MEMBER(lynx_timer_shot); - TIMER_CALLBACK_MEMBER(lynx_uart_loopback_timer); - TIMER_CALLBACK_MEMBER(lynx_uart_timer); - void lynx_postload(); + TIMER_CALLBACK_MEMBER(blitter_timer); + TIMER_CALLBACK_MEMBER(timer_shot); + TIMER_CALLBACK_MEMBER(uart_loopback_timer); + TIMER_CALLBACK_MEMBER(uart_timer); DECLARE_DEVICE_IMAGE_LOAD_MEMBER(cart_load); - uint8_t lynx_read_ram(uint16_t address); - void lynx_write_ram(uint16_t address, uint8_t data); - inline void lynx_plot_pixel(const int mode, const int16_t x, const int y, const int color); - void lynx_blit_do_work(const int y, const int xdir, const int bits_per_pixel, const int mask ); - void lynx_blit_rle_do_work( const int16_t y, const int xdir, const int bits_per_pixel, const int mask ); - void lynx_blit_lines(); - void lynx_blitter(); - void lynx_draw_line(); - void lynx_timer_init(int which); - void lynx_timer_signal_irq(int which); - void lynx_timer_count_down(int which); - uint32_t lynx_time_factor(int val); - void lynx_uart_reset(); - image_verify_result lynx_verify_cart(char *header, int kind); + + // DRAM accessor, 0xfff8-0xfff9 Reserved? + inline u8 dram_byte_r(u16 addr) { return ((addr & 0xfffe) != 0xfff8) ? m_dram[addr] : 0; } + inline void dram_byte_w(u16 addr, u8 data, u8 mem_mask = ~0) { if ((addr & 0xfffe) != 0xfff8) { COMBINE_DATA(&m_dram[addr]); } } + inline u16 dram_word_r(u16 addr) { return dram_byte_r(addr) | (u16(dram_byte_r((addr + 1) & 0xffff)) << 8); } + + inline void plot_pixel(const s16 x, const s16 y, const u8 color); + void blit_do_work(const s16 y, const int xdir, const int bits_per_pixel, const u8 mask); + void blit_rle_do_work(const s16 y, const int xdir, const int bits_per_pixel, const u8 mask); + void blit_lines(); + void blitter(); + void draw_line(); + void timer_init(int which); + void timer_signal_irq(int which); + void timer_count_down(int which); + u32 time_factor(int val); + void uart_reset(); + void interrupt_set(u8 line); + void interrupt_update(); + image_verify_result verify_cart(char *header, int kind); DECLARE_QUICKLOAD_LOAD_MEMBER(quickload_cb); }; /*---------- suzy registers ------------- */ -#define TMPADRL 0x00 // Temporary address (not sure what this is used for) -#define TMPADRH 0x01 +#define TMPADRL 0x00 // Temporary address (not sure what this is used for) +#define TMPADRH 0x01 #define TILTACUML 0x02 // Tilt accumulator (signed fixed-point, eight bits to the left of decimal) #define TILTACUMH 0x03 #define HOFFL 0x04 // X offset to edge of visible window @@ -227,8 +330,8 @@ private: #define COLLADRH 0x0F #define SCBNEXTL 0x10 // Address of next SCB #define SCBNEXTH 0x11 -#define SPRDLINEL 0x12 // Sprite data start address -#define SPRDLINEH 0x13 +#define SPRDLINEL 0x12 // Sprite data start address +#define SPRDLINEH 0x13 #define HPOSSTRTL 0x14 // Starting Hpos #define HPOSSTRTH 0x15 #define VPOSSTRTL 0x16 // Starting Vpos @@ -253,8 +356,8 @@ private: #define HSIZOFFH 0x29 #define VSIZOFFL 0x2A // Vertical Size Offset #define VSIZOFFH 0x2B -#define SCBADRL 0x2C // Address of Current SCB -#define SCBADRH 0x2D +#define SCBADRL 0x2C // Address of Current SCB +#define SCBADRH 0x2D #define PROCADRL 0x2E // Current Spr Data Proc Address #define MATH_D 0x52 @@ -273,10 +376,10 @@ private: #define MATH_K 0x6e #define MATH_J 0x6f -#define SPRCTL0 0x80 // Sprite Control Bits 0 (W)(U) -#define SPRCTL1 0x81 // Sprite Control Bits 1 (W)(U) -#define SPRCOLL 0x82 // Sprite Collision Number (W) -#define SPRINIT 0x83 // Sprite Initialization Bits (W)(U) +#define SPRCTL0 0x80 // Sprite Control Bits 0 (W)(U) +#define SPRCTL1 0x81 // Sprite Control Bits 1 (W)(U) +#define SPRCOLL 0x82 // Sprite Collision Number (W) +#define SPRINIT 0x83 // Sprite Initialization Bits (W)(U) #define SUZYHREV 0x88 // Suzy Hardware Revision (R) = '01' @@ -305,10 +408,10 @@ private: #define SCB_SCBNEXT 0x03 // L,H Address of Next SCB #define SCB_SPRDLINE 0x05 // L,H Start of Sprite Data Line Address #define SCB_HPOSSTRT 0x07 // L,H Starting Hpos -#define SCB_VPOSSTRT 0x09 // L,H Starting Vpos +#define SCB_VPOSSTRT 0x09 // L,H Starting Vpos #define SCB_SPRHSIZ 0x0B // L,H H Size -#define SCB_SPRVSIZ 0x0D // L,H V Size -#define SCB_STRETCH 0x0F // L H H/V Size Adder -#define SCB_TILT 0x11 // L,H H Position Adder +#define SCB_SPRVSIZ 0x0D // L,H V Size +#define SCB_STRETCH 0x0F // L H H/V Size Adder +#define SCB_TILT 0x11 // L,H H Position Adder #endif // MAME_INCLUDES_LYNX_H diff --git a/src/mame/machine/lynx.cpp b/src/mame/machine/lynx.cpp index 161359d5d11..0292ea3ecb9 100644 --- a/src/mame/machine/lynx.cpp +++ b/src/mame/machine/lynx.cpp @@ -35,36 +35,6 @@ enum { SHADOW }; -uint8_t lynx_state::lynx_read_ram(uint16_t address) -{ - uint8_t result = 0x00; - if (address <= 0xfbff) - result = m_mem_0000[address - 0x0000]; - else if (address <= 0xfcff) - result = m_mem_fc00[address - 0xfc00]; - else if (address <= 0xfdff) - result = m_mem_fd00[address - 0xfd00]; - else if (address <= 0xfff7) - result = m_mem_fe00[address - 0xfe00]; - else if (address >= 0xfffa) - result = m_mem_fffa[address - 0xfffa]; - return result; -} - -void lynx_state::lynx_write_ram(uint16_t address, uint8_t data) -{ - if (address <= 0xfbff) - m_mem_0000[address - 0x0000] = data; - else if (address <= 0xfcff) - m_mem_fc00[address - 0xfc00] = data; - else if (address <= 0xfdff) - m_mem_fd00[address - 0xfd00] = data; - else if (address <= 0xfff7) - m_mem_fe00[address - 0xfe00] = data; - else if (address >= 0xfffa) - m_mem_fffa[address - 0xfffa] = data; -} - /* The pen numbers range from '0' to 'F. Pen numbers '1' through 'D' are always collidable and opaque. The other ones have different behavior depending on the sprite type: there are 8 types of sprites, each has different characteristics relating to some or all of their pen numbers. @@ -93,22 +63,20 @@ The sprite types relate to specific hardware functions according to the followin 0 0 0 0 0 0 0 1 exclusive-or the data */ -inline void lynx_state::lynx_plot_pixel(const int mode, const int16_t x, const int y, const int color) +inline void lynx_state::plot_pixel(const s16 x, const s16 y, const u8 color) { - uint8_t back; - uint16_t screen; - uint16_t colbuf; + u8 back; m_blitter.everon = true; - screen = m_blitter.screen + y * 80 + x / 2; - colbuf = m_blitter.colbuf + y * 80 + x / 2; + const u16 screen = m_blitter.screen + y * 80 + x / 2; + const u16 colbuf = m_blitter.colbuf + y * 80 + x / 2; /* a note on timing: The hardware packs the pixel data and updates the screen and collision buffer a byte at a time. Thus the buffer update for two pixels takes 3 memory accesses for a normal sprite (write to screen buffer, read/write to collision buffer). +1 memory access for palette fetch? */ - switch (mode&0x7) + switch (m_blitter.mode & 0x7) { case NORMAL_SPRITE: /* A sprite may be set to 'normal'. This means that pen number '0' will be transparent and @@ -117,31 +85,29 @@ inline void lynx_state::lynx_plot_pixel(const int mode, const int16_t x, const i break; if (!(x & 0x01)) /* Upper nibble */ { - back = lynx_read_ram(screen); - lynx_write_ram(screen, (back & 0x0f) | (color << 4)); + dram_byte_w(screen, color << 4, 0xf0); m_blitter.memory_accesses++; - if(m_blitter.sprite_collide && !(m_blitter.no_collide)) + if (m_blitter.SPRITE_COLLIDE()) { - back = lynx_read_ram(colbuf); - lynx_write_ram(colbuf, (back & ~0xf0) | (m_blitter.spritenr << 4)); + back = BIT(dram_byte_r(colbuf), 4, 4); + if (back > m_blitter.fred) + m_blitter.fred = back; + dram_byte_w(colbuf, m_blitter.spritenr << 4, 0xf0); m_blitter.memory_accesses += 2; - if ((back >> 4) > m_blitter.fred) - m_blitter.fred = back >> 4; } m_blitter.memory_accesses++; } else /* Lower nibble */ { - back = lynx_read_ram(screen); - lynx_write_ram(screen, (back & 0xf0) | color); + dram_byte_w(screen, color, 0x0f); - if(m_blitter.sprite_collide && !(m_blitter.no_collide)) + if (m_blitter.SPRITE_COLLIDE()) { - back = lynx_read_ram(colbuf); - lynx_write_ram(colbuf, (back & ~0x0f) | (m_blitter.spritenr)); - if ((back & 0x0f) > m_blitter.fred) - m_blitter.fred = back >> 4; + back = BIT(dram_byte_r(colbuf), 0, 4); + if (back > m_blitter.fred) + m_blitter.fred = back; + dram_byte_w(colbuf, m_blitter.spritenr, 0x0f); } } break; @@ -155,16 +121,15 @@ inline void lynx_state::lynx_plot_pixel(const int mode, const int16_t x, const i { if (color != 0x0f) { - back = lynx_read_ram(screen); - lynx_write_ram(screen, (back & 0x0f) | (color << 4)); + dram_byte_w(screen, color << 4, 0xf0); m_blitter.memory_accesses++; } - if(m_blitter.sprite_collide && !(m_blitter.no_collide)) + if (m_blitter.SPRITE_COLLIDE()) { - back = lynx_read_ram(colbuf); - lynx_write_ram(colbuf, (back & ~0xf0) | (m_blitter.spritenr << 4)); - if ((back >> 4) > m_blitter.fred) - m_blitter.fred = back >> 4; + back = BIT(dram_byte_r(colbuf), 4, 4); + if (back > m_blitter.fred) + m_blitter.fred = back; + dram_byte_w(colbuf, m_blitter.spritenr << 4, 0xf0); m_blitter.memory_accesses += 2; } m_blitter.memory_accesses++; @@ -173,15 +138,14 @@ inline void lynx_state::lynx_plot_pixel(const int mode, const int16_t x, const i { if (color != 0x0f) { - back = lynx_read_ram(screen); - lynx_write_ram(screen, (back & 0xf0) | color); + dram_byte_w(screen, color, 0x0f); } - if(m_blitter.sprite_collide && !(m_blitter.no_collide)) + if (m_blitter.SPRITE_COLLIDE()) { - back = lynx_read_ram(colbuf); - lynx_write_ram(colbuf, (back & ~0x0f) | (m_blitter.spritenr)); - if ((back & 0x0f) > m_blitter.fred) - m_blitter.fred = back >> 4; + back = BIT(dram_byte_r(colbuf), 0, 4); + if (back > m_blitter.fred) + m_blitter.fred = back; + dram_byte_w(colbuf, m_blitter.spritenr, 0x0f); } } break; @@ -193,31 +157,29 @@ inline void lynx_state::lynx_plot_pixel(const int mode, const int16_t x, const i break; if (!(x & 0x01)) /* Upper nibble */ { - back = lynx_read_ram(screen); - lynx_write_ram(screen, (back & 0x0f) | (color << 4)); + dram_byte_w(screen, color << 4, 0xf0); m_blitter.memory_accesses++; - if (m_blitter.sprite_collide && (color != 0x0e) && !(m_blitter.no_collide)) + if (m_blitter.SPRITE_COLLIDE() && (color != 0x0e)) { - back = lynx_read_ram(colbuf); - lynx_write_ram(colbuf, (back & ~0xf0) | (m_blitter.spritenr << 4)); - if ((back >> 4) > m_blitter.fred) - m_blitter.fred = back >> 4; + back = BIT(dram_byte_r(colbuf), 4, 4); + if (back > m_blitter.fred) + m_blitter.fred = back; + dram_byte_w(colbuf, m_blitter.spritenr << 4, 0xf0); m_blitter.memory_accesses += 2; } m_blitter.memory_accesses++; } else /* Lower nibble */ { - back = lynx_read_ram(screen); - lynx_write_ram(screen, (back & 0xf0) | color); + dram_byte_w(screen, color, 0x0f); - if (m_blitter.sprite_collide && (color != 0x0e) && !(m_blitter.no_collide)) + if (m_blitter.SPRITE_COLLIDE() && (color != 0x0e)) { - back = lynx_read_ram(colbuf); - lynx_write_ram(colbuf, (back & ~0x0f) | (m_blitter.spritenr)); - if ((back & 0x0f) > m_blitter.fred) - m_blitter.fred = back >> 4; + back = BIT(dram_byte_r(colbuf), 0, 4); + if (back > m_blitter.fred) + m_blitter.fred = back; + dram_byte_w(colbuf, m_blitter.spritenr, 0x0f); } } break; @@ -232,16 +194,15 @@ inline void lynx_state::lynx_plot_pixel(const int mode, const int16_t x, const i { if (color != 0x0f) { - back = lynx_read_ram(screen); - lynx_write_ram(screen, (back & 0x0f) | (color << 4)); + dram_byte_w(screen, color << 4, 0xf0); m_blitter.memory_accesses++; } - if (m_blitter.sprite_collide && (color != 0x0e) && !(m_blitter.no_collide)) + if (m_blitter.SPRITE_COLLIDE() && (color != 0x0e)) { - back = lynx_read_ram(colbuf); - lynx_write_ram(colbuf, (back & ~0xf0) | (m_blitter.spritenr << 4)); - if ((back >> 4) > m_blitter.fred) - m_blitter.fred = back >> 4; + back = BIT(dram_byte_r(colbuf), 4, 4); + if (back > m_blitter.fred) + m_blitter.fred = back; + dram_byte_w(colbuf, m_blitter.spritenr << 4, 0xf0); m_blitter.memory_accesses += 2; } m_blitter.memory_accesses++; @@ -250,15 +211,14 @@ inline void lynx_state::lynx_plot_pixel(const int mode, const int16_t x, const i { if (color != 0x0f) { - back = lynx_read_ram(screen); - lynx_write_ram(screen, (back & 0xf0) | color); + dram_byte_w(screen, color, 0x0f); } - if (m_blitter.sprite_collide && (color != 0x0e) && !(m_blitter.no_collide)) + if (m_blitter.SPRITE_COLLIDE() && (color != 0x0e)) { - back = lynx_read_ram(colbuf); - lynx_write_ram(colbuf, (back & ~0x0f) | (m_blitter.spritenr)); - if ((back & 0x0f) > m_blitter.fred) - m_blitter.fred = back >> 4; + back = BIT(dram_byte_r(colbuf), 0, 4); + if (back > m_blitter.fred) + m_blitter.fred = back; + dram_byte_w(colbuf, m_blitter.spritenr, 0x0f); } } break; @@ -271,27 +231,23 @@ inline void lynx_state::lynx_plot_pixel(const int mode, const int16_t x, const i and therefore not clear the collision buffer */ if (!(x & 0x01)) /* Upper nibble */ { - back = lynx_read_ram(screen); - lynx_write_ram(screen, (back & 0x0f) | (color << 4)); + dram_byte_w(screen, color << 4, 0xf0); m_blitter.memory_accesses++; - if (m_blitter.sprite_collide && (color != 0x0e) && !(m_blitter.no_collide)) + if (m_blitter.SPRITE_COLLIDE() && (color != 0x0e)) { - back = lynx_read_ram(colbuf); - lynx_write_ram(colbuf, (back & ~0xf0) | (m_blitter.spritenr << 4)); + dram_byte_w(colbuf, m_blitter.spritenr << 4, 0xf0); m_blitter.memory_accesses++; } m_blitter.memory_accesses++; } else /* Lower nibble */ { - back = lynx_read_ram(screen); - lynx_write_ram(screen, (back & 0xf0) | color); + dram_byte_w(screen, color, 0x0f); - if (m_blitter.sprite_collide && (color != 0x0e) && !(m_blitter.no_collide)) + if (m_blitter.SPRITE_COLLIDE() && (color != 0x0e)) { - back = lynx_read_ram(colbuf); - lynx_write_ram(colbuf, (back & ~0x0f) | (m_blitter.spritenr)); + dram_byte_w(colbuf, m_blitter.spritenr, 0x0f); } } break; @@ -300,15 +256,13 @@ inline void lynx_state::lynx_plot_pixel(const int mode, const int16_t x, const i /* This is a 'background' sprite with the exception that no activity occurs in the collision buffer */ if (!(x & 0x01)) /* Upper nibble */ { - back = lynx_read_ram(screen); - lynx_write_ram(screen, (back & 0x0f) | (color << 4)); + dram_byte_w(screen, color << 4, 0xf0); m_blitter.memory_accesses++; m_blitter.memory_accesses++; } else /* Lower nibble */ { - back = lynx_read_ram(screen); - lynx_write_ram(screen, (back & 0xf0) | color); + dram_byte_w(screen, color, 0x0f); } break; @@ -319,15 +273,13 @@ inline void lynx_state::lynx_plot_pixel(const int mode, const int16_t x, const i break; if (!(x & 0x01)) /* Upper nibble */ { - back = lynx_read_ram(screen); - lynx_write_ram(screen, (back & 0x0f) | (color << 4)); + dram_byte_w(screen, color << 4, 0xf0); m_blitter.memory_accesses++; m_blitter.memory_accesses++; } else /* Lower nibble */ { - back = lynx_read_ram(screen); - lynx_write_ram(screen, (back & 0xf0) | color); + dram_byte_w(screen, color, 0x0f); } break; @@ -340,60 +292,58 @@ inline void lynx_state::lynx_plot_pixel(const int mode, const int16_t x, const i break; if (!(x & 0x01)) /* Upper nibble */ { - back = lynx_read_ram(screen); - lynx_write_ram(screen, back^(color << 4)); + dram_byte_w(screen, dram_byte_r(screen) ^ (color << 4), 0xf0); m_blitter.memory_accesses += 2; - if (m_blitter.sprite_collide && (color != 0x0e) && !(m_blitter.no_collide)) + if (m_blitter.SPRITE_COLLIDE() && (color != 0x0e)) { - back = lynx_read_ram(colbuf); - lynx_write_ram(colbuf, (back & ~0xf0) | (m_blitter.spritenr << 4)); - if ((back >> 4) > m_blitter.fred) - m_blitter.fred = back >> 4; + back = BIT(dram_byte_r(colbuf), 4, 4); + if (back > m_blitter.fred) + m_blitter.fred = back; + dram_byte_w(colbuf, m_blitter.spritenr << 4, 0xf0); m_blitter.memory_accesses += 2; } m_blitter.memory_accesses++; } else /* Lower nibble */ { - back = lynx_read_ram(screen); - lynx_write_ram(screen, back^color); - if (m_blitter.sprite_collide && (color != 0x0e) && !(m_blitter.no_collide)) + dram_byte_w(screen, dram_byte_r(screen) ^ color, 0x0f); + if (m_blitter.SPRITE_COLLIDE() && (color != 0x0e)) { - back = lynx_read_ram(colbuf); - lynx_write_ram(colbuf, (back & ~0x0f) | (m_blitter.spritenr)); - if ((back & 0x0f) > m_blitter.fred) - m_blitter.fred = back >> 4; + back = BIT(dram_byte_r(colbuf), 0, 4); + if (back > m_blitter.fred) + m_blitter.fred = back; + dram_byte_w(colbuf, m_blitter.spritenr, 0x0f); } } break; } } -void lynx_state::lynx_blit_do_work( const int y, const int xdir, const int bits_per_pixel, const int mask ) +void lynx_state::blit_do_work(const s16 y, const int xdir, const int bits_per_pixel, const u8 mask) { - int next_line_addr,i,j; + int i,j; int xi, bits, color; - uint16_t width_accum, buffer; + u16 buffer; - next_line_addr = lynx_read_ram(m_blitter.bitmap); // offset to second sprite line - width_accum = (xdir == 1) ? m_blitter.width_offset : 0; + const int next_line_addr = dram_byte_r(m_blitter.bitmap); // offset to second sprite line + u16 width_accum = (xdir == 1) ? m_blitter.width_offset : 0; m_blitter.memory_accesses++; - for (xi = m_blitter.x_pos - m_blitter.xoff, bits = 0, buffer = 0, j = 1; j < next_line_addr;j++) + for (xi = m_blitter.x_pos - m_blitter.xoff, bits = 0, buffer = 0, j = 1; j < next_line_addr; j++) { - buffer = (buffer << 8) | lynx_read_ram(m_blitter.bitmap + j); + buffer = (buffer << 8) | dram_byte_r(m_blitter.bitmap + j); bits += 8; // current bits in buffer m_blitter.memory_accesses++; - for ( ; bits > bits_per_pixel; bits -= bits_per_pixel) // last data packet at end of scanline is not rendered (qix, blulght) + for (; bits > bits_per_pixel; bits -= bits_per_pixel) // last data packet at end of scanline is not rendered (qix, blulght) { color = m_blitter.color[(buffer >> (bits - bits_per_pixel)) & mask]; width_accum += m_blitter.width; - for (i = 0; i < (width_accum>>8); i++, xi += xdir) + for (i = 0; i < (width_accum >> 8); i++, xi += xdir) { if ((xi >= 0) && (xi < 160)) { - lynx_plot_pixel(m_blitter.mode, xi, y, color); + plot_pixel(xi, y, color); } } width_accum &= 0xff; @@ -401,25 +351,25 @@ void lynx_state::lynx_blit_do_work( const int y, const int xdir, const int bits_ } } -void lynx_state::lynx_blit_rle_do_work( const int16_t y, const int xdir, const int bits_per_pixel, const int mask ) +void lynx_state::blit_rle_do_work(const s16 y, const int xdir, const int bits_per_pixel, const u8 mask) { int i; int xi; int buffer, bits, j; int literal_data, count, color; - uint16_t width_accum; - width_accum = (xdir == 1) ? m_blitter.width_offset : 0; - for( bits = 0, j = 0, buffer = 0, xi = m_blitter.x_pos - m_blitter.xoff; ; ) /* through the rle entries */ + const int next_line_addr = dram_byte_r(m_blitter.bitmap); // offset to second sprite line + u16 width_accum = (xdir == 1) ? m_blitter.width_offset : 0; + for (bits = 0, j = 0, buffer = 0, xi = m_blitter.x_pos - m_blitter.xoff; ;) /* through the rle entries */ { if (bits < 5 + bits_per_pixel) /* under 7 bits no complete entry */ { j++; - if (j >= lynx_read_ram(m_blitter.bitmap)) + if (j >= next_line_addr) return; bits += 8; - buffer = (buffer << 8) | lynx_read_ram(m_blitter.bitmap + j); + buffer = (buffer << 8) | dram_byte_r(m_blitter.bitmap + j); m_blitter.memory_accesses++; } @@ -430,25 +380,25 @@ void lynx_state::lynx_blit_rle_do_work( const int16_t y, const int xdir, const i if (literal_data) /* count of different pixels */ { - for ( ; count >= 0; count--) + for (; count >= 0; count--) { if (bits < bits_per_pixel) { j++; - if (j >= lynx_read_ram(m_blitter.bitmap)) + if (j >= next_line_addr) return; bits += 8; - buffer = (buffer << 8) | lynx_read_ram(m_blitter.bitmap + j); + buffer = (buffer << 8) | dram_byte_r(m_blitter.bitmap + j); m_blitter.memory_accesses++; } color = m_blitter.color[(buffer >> (bits - bits_per_pixel)) & mask]; bits -= bits_per_pixel; width_accum += m_blitter.width; - for (i = 0; i < (width_accum>>8); i++, xi += xdir) + for (i = 0; i < (width_accum >> 8); i++, xi += xdir) { if ((xi >= 0) && (xi < 160)) - lynx_plot_pixel(m_blitter.mode, xi, y, color); + plot_pixel(xi, y, color); } width_accum &= 0xff; } @@ -461,23 +411,23 @@ void lynx_state::lynx_blit_rle_do_work( const int16_t y, const int xdir, const i if (bits < bits_per_pixel) { j++; - if (j >= lynx_read_ram(m_blitter.bitmap)) + if (j >= next_line_addr) return; bits += 8; - buffer = (buffer << 8) | lynx_read_ram(m_blitter.bitmap + j); + buffer = (buffer << 8) | dram_byte_r(m_blitter.bitmap + j); m_blitter.memory_accesses++; } color = m_blitter.color[(buffer >> (bits - bits_per_pixel)) & mask]; bits -= bits_per_pixel; - for ( ; count>=0; count--) + for (; count >= 0; count--) { width_accum += m_blitter.width; for (i = 0; i < (width_accum >> 8); i++, xi += xdir) { if ((xi >= 0) && (xi < 160)) - lynx_plot_pixel(m_blitter.mode, xi, y, color); + plot_pixel(xi, y, color); } width_accum &= 0xff; } @@ -485,17 +435,17 @@ void lynx_state::lynx_blit_rle_do_work( const int16_t y, const int xdir, const i } } -void lynx_state::lynx_blit_lines() +void lynx_state::blit_lines() { - static const int lynx_color_masks[4] = { 0x01, 0x03, 0x07, 0x0f }; - int16_t y; + static const u8 lynx_color_masks[4] = { 0x01, 0x03, 0x07, 0x0f }; + s16 y; int i; int ydir = 0, xdir = 0; int flip = 0; m_blitter.everon = false; - switch (m_blitter.spr_ctl1 & 0x03) /* Initial drawing direction */ + switch (m_blitter.DRAW_ORIGIN()) /* Initial drawing direction */ { case 0: // Down/Right (quadrant 0) xdir = 1; @@ -519,12 +469,12 @@ void lynx_state::lynx_blit_lines() break; } - if (m_blitter.spr_ctl0 & 0x20) /* Horizontal Flip */ + if (m_blitter.HFLIP()) /* Horizontal Flip */ { xdir *= -1; } - if (m_blitter.spr_ctl0 & 0x10) /* Vertical Flip */ + if (m_blitter.VFLIP()) /* Vertical Flip */ { ydir *= -1; } @@ -533,7 +483,7 @@ void lynx_state::lynx_blit_lines() m_blitter.height_accumulator = (ydir == 1) ? m_blitter.height_offset : 0x00; // loop through lines, next line offset of zero indicates end of sprite - for (y = m_blitter.y_pos - m_blitter.yoff; (i = lynx_read_ram(m_blitter.bitmap)); m_blitter.bitmap += i) + for (y = m_blitter.y_pos - m_blitter.yoff; (i = dram_byte_r(m_blitter.bitmap)); m_blitter.bitmap += i) { m_blitter.memory_accesses++; @@ -565,18 +515,18 @@ void lynx_state::lynx_blit_lines() if (y >= 0 && y < 102) { if (m_blitter.use_rle) - lynx_blit_rle_do_work(y, xdir, m_blitter.line_color + 1, lynx_color_masks[m_blitter.line_color]); + blit_rle_do_work(y, xdir, m_blitter.line_color + 1, lynx_color_masks[m_blitter.line_color]); else - lynx_blit_do_work(y, xdir, m_blitter.line_color + 1, lynx_color_masks[m_blitter.line_color]); + blit_do_work(y, xdir, m_blitter.line_color + 1, lynx_color_masks[m_blitter.line_color]); } - m_blitter.width += (int16_t)m_blitter.stretch; + m_blitter.width += (s16)m_blitter.stretch; if (m_blitter.vstretch) // doesn't seem to be used { - m_blitter.height += (int16_t)m_blitter.stretch; + m_blitter.height += (s16)m_blitter.stretch; logerror("vertical stretch enabled"); } m_blitter.tilt_accumulator += m_blitter.tilt; - m_blitter.x_pos += (m_blitter.tilt_accumulator>>8); + m_blitter.x_pos += (m_blitter.tilt_accumulator >> 8); m_blitter.tilt_accumulator &= 0xff; } m_blitter.height_accumulator &= 0xff; @@ -588,25 +538,25 @@ void lynx_state::device_timer(emu_timer &timer, device_timer_id id, int param, v switch (id) { case TIMER_BLITTER: - lynx_blitter_timer(ptr, param); + blitter_timer(ptr, param); break; case TIMER_SHOT: - lynx_timer_shot(ptr, param); + timer_shot(ptr, param); break; case TIMER_UART_LOOPBACK: - lynx_uart_loopback_timer(ptr, param); + uart_loopback_timer(ptr, param); break; case TIMER_UART: - lynx_uart_timer(ptr, param); + uart_timer(ptr, param); break; default: throw emu_fatalerror("Unknown id in lynx_state::device_timer"); } } -TIMER_CALLBACK_MEMBER(lynx_state::lynx_blitter_timer) +TIMER_CALLBACK_MEMBER(lynx_state::blitter_timer) { - m_blitter.busy=0; // blitter finished + m_blitter.busy = false; // blitter finished m_maincpu->set_input_line(INPUT_LINE_HALT, CLEAR_LINE); } @@ -683,12 +633,10 @@ TIMER_CALLBACK_MEMBER(lynx_state::lynx_blitter_timer) */ -void lynx_state::lynx_blitter() +void lynx_state::blitter() { - static const int lynx_colors[4] = { 2, 4, 8, 16 }; - uint8_t palette_offset; - uint8_t coldep; - int colors; + static const u8 lynx_colors[4] = { 2, 4, 8, 16 }; + u8 palette_offset; m_blitter.busy = 1; // blitter working m_blitter.memory_accesses = 0; @@ -701,69 +649,69 @@ void lynx_state::lynx_blitter() m_blitter.tilt_accumulator = 0; m_blitter.scb = m_blitter.scb_next; // current scb - m_blitter.scb_next = lynx_read_ram(m_blitter.scb + SCB_SCBNEXT) | (lynx_read_ram(m_blitter.scb + SCB_SCBNEXT + 1) << 8); // next scb - m_blitter.spr_ctl0 = lynx_read_ram(m_blitter.scb + SCB_SPRCTL0); - m_blitter.spr_ctl1 = lynx_read_ram(m_blitter.scb + SCB_SPRCTL1); - m_blitter.spr_coll = lynx_read_ram(m_blitter.scb + SCB_SPRCOLL); + m_blitter.scb_next = dram_word_r(m_blitter.scb + SCB_SCBNEXT); // next scb + m_blitter.spr_ctl0 = dram_byte_r(m_blitter.scb + SCB_SPRCTL0); + m_blitter.spr_ctl1 = dram_byte_r(m_blitter.scb + SCB_SPRCTL1); + m_blitter.spr_coll = dram_byte_r(m_blitter.scb + SCB_SPRCOLL); m_blitter.memory_accesses += 5; - if(!(m_blitter.spr_ctl1 & 0x04)) // sprite will be processed (if sprite is skipped first 5 bytes are still copied to suzy) + if (!(m_blitter.SKIP_SPRITE())) // sprite will be processed (if sprite is skipped first 5 bytes are still copied to suzy) { - m_blitter.bitmap = lynx_read_ram(m_blitter.scb + SCB_SPRDLINE) | (lynx_read_ram(m_blitter.scb + SCB_SPRDLINE + 1) << 8); - m_blitter.x_pos = lynx_read_ram(m_blitter.scb + SCB_HPOSSTRT) | (lynx_read_ram(m_blitter.scb + SCB_HPOSSTRT + 1) << 8); - m_blitter.y_pos = lynx_read_ram(m_blitter.scb + SCB_VPOSSTRT) | (lynx_read_ram(m_blitter.scb + SCB_VPOSSTRT + 1) << 8); + m_blitter.bitmap = dram_word_r(m_blitter.scb + SCB_SPRDLINE); + m_blitter.x_pos = dram_word_r(m_blitter.scb + SCB_HPOSSTRT); + m_blitter.y_pos = dram_word_r(m_blitter.scb + SCB_VPOSSTRT); m_blitter.memory_accesses += 6; - switch(m_blitter.spr_ctl1 & 0x30) // reload sprite scaling + switch (m_blitter.RELOAD_SCALE()) // reload sprite scaling { - case 0x30: // width, height, tilt, stretch - m_blitter.tilt = lynx_read_ram(m_blitter.scb + SCB_TILT) | (lynx_read_ram(m_blitter.scb + SCB_TILT + 1) << 8); - m_blitter.memory_accesses+=2; + case 0b11: // width, height, tilt, stretch + m_blitter.tilt = dram_word_r(m_blitter.scb + SCB_TILT); + m_blitter.memory_accesses += 2; [[fallthrough]]; - case 0x20: // width, height, stretch - m_blitter.stretch = lynx_read_ram(m_blitter.scb + SCB_STRETCH) | (lynx_read_ram(m_blitter.scb + SCB_STRETCH + 1) << 8); - m_blitter.memory_accesses+=2; + case 0b10: // width, height, stretch + m_blitter.stretch = dram_word_r(m_blitter.scb + SCB_STRETCH); + m_blitter.memory_accesses += 2; [[fallthrough]]; - case 0x10: // width, height - m_blitter.width = lynx_read_ram(m_blitter.scb + SCB_SPRHSIZ) | (lynx_read_ram(m_blitter.scb + SCB_SPRHSIZ + 1) << 8); - m_blitter.height = lynx_read_ram(m_blitter.scb + SCB_SPRVSIZ) | (lynx_read_ram(m_blitter.scb + SCB_SPRVSIZ + 1) << 8); - m_blitter.memory_accesses+=4; + case 0b01: // width, height + m_blitter.width = dram_word_r(m_blitter.scb + SCB_SPRHSIZ); + m_blitter.height = dram_word_r(m_blitter.scb + SCB_SPRVSIZ); + m_blitter.memory_accesses += 4; } - if(!(m_blitter.spr_ctl1 & 0x08)) // reload palette + if (!(m_blitter.REUSE_PALETTE())) // reload palette { - if (m_blitter.spr_ctl1 & 0x30) - palette_offset = 0x0b + 2*(((m_blitter.spr_ctl1 & 0x30)>>4) + 1); // palette data offset depends on width, height, etc. reloading + if (m_blitter.RELOAD_SCALE() != 0) + palette_offset = 0x0b + 2 * (m_blitter.RELOAD_SCALE() + 1); // palette data offset depends on width, height, etc. reloading else palette_offset = 0x0b; - colors = lynx_colors[m_blitter.spr_ctl0 >> 6]; + u8 colors = lynx_colors[m_blitter.BPP()]; for (int i = 0; i < colors / 2; i++) { - m_blitter.color[i * 2] = lynx_read_ram(m_blitter.scb + palette_offset + i) >> 4; - m_blitter.color[i * 2 + 1 ] = lynx_read_ram(m_blitter.scb + palette_offset + i) & 0x0f; + m_blitter.color[i * 2] = dram_byte_r(m_blitter.scb + palette_offset + i) >> 4; + m_blitter.color[i * 2 + 1] = dram_byte_r(m_blitter.scb + palette_offset + i) & 0x0f; m_blitter.memory_accesses++; } } - } + } - if (!(m_blitter.spr_ctl1 & 0x04)) // if 0, we skip this sprite + if (!(m_blitter.SKIP_SPRITE())) // if 0, we skip this sprite { - m_blitter.colpos = m_blitter.scb + (m_suzy.data[COLLOFFL] | (m_suzy.data[COLLOFFH]<<8)); - m_blitter.mode = m_blitter.spr_ctl0 & 0x07; - m_blitter.use_rle = m_blitter.spr_ctl1 & 0x80 ? 0 : 1; - m_blitter.line_color = (m_blitter.spr_ctl0 >> 6) & 0x03; + m_blitter.colpos = m_blitter.scb + (m_suzy.data[COLLOFFL] | (m_suzy.data[COLLOFFH] << 8)); + m_blitter.mode = m_blitter.SPRITE_TYPE(); + m_blitter.use_rle = !(m_blitter.RLE()); + m_blitter.line_color = m_blitter.BPP(); - m_blitter.sprite_collide = !(m_blitter.spr_coll & 0x20); - m_blitter.spritenr = m_blitter.spr_coll & 0x0f; + m_blitter.sprite_collide = !(m_blitter.SPRITE_COLLEN()); + m_blitter.spritenr = m_blitter.SPRITE_COLNUM(); m_blitter.fred = 0; /* Draw Sprite */ - lynx_blit_lines(); + blit_lines(); - if (m_blitter.sprite_collide && !(m_blitter.no_collide)) + if (m_blitter.SPRITE_COLLIDE()) { switch (m_blitter.mode) { @@ -772,20 +720,13 @@ void lynx_state::lynx_blitter() case NORMAL_SPRITE: case XOR_SPRITE: case SHADOW: - lynx_write_ram(m_blitter.colpos, m_blitter.fred); + dram_byte_w(m_blitter.colpos, m_blitter.fred); break; } } - if (m_suzy.data[SPRGO] & 0x04) // Everon enabled - { - coldep = lynx_read_ram(m_blitter.colpos); - if (!m_blitter.everon) - coldep |= 0x80; - else - coldep &= 0x7f; - lynx_write_ram(m_blitter.colpos, coldep); - } + if (m_suzy.EVER_ON()) // Everon enabled + dram_byte_w(m_blitter.colpos, m_blitter.everon ? 0x00 : 0x80, 0x80); } } @@ -810,11 +751,11 @@ if you just load the lower byte after a multiply by zero. - in divide, the remainder will have 2 possible errors, depending on its actual value (no further notes on these errors available) */ -void lynx_state::lynx_divide() +void lynx_state::suzy_divide() { - uint32_t left; - uint16_t right; - uint32_t res, mod; + u32 left; + u16 right; + u32 res, mod; /* Hardware divide: EFGH @@ -851,10 +792,10 @@ void lynx_state::lynx_divide() m_suzy.data[MATH_J] = 0; } -void lynx_state::lynx_multiply() +void lynx_state::suzy_multiply() { - uint16_t left, right; - uint32_t res, accu; + u16 left, right; + u32 res, accu; /* Hardware multiply: AB @@ -896,86 +837,87 @@ void lynx_state::lynx_multiply() } } -uint8_t lynx_state::suzy_read(offs_t offset) +u8 lynx_state::suzy_read(offs_t offset) { - uint8_t value = 0, input; + u8 value = 0, input; switch (offset) { case TILTACUML: return m_blitter.tilt_accumulator & 0xff; case TILTACUMH: - return m_blitter.tilt_accumulator>>8; + return m_blitter.tilt_accumulator >> 8; case HOFFL: return m_blitter.xoff & 0xff; case HOFFH: - return m_blitter.xoff>>8; + return m_blitter.xoff >> 8; case VOFFL: return m_blitter.yoff & 0xff; case VOFFH: - return m_blitter.yoff>>8; + return m_blitter.yoff >> 8; case VIDBASL: return m_blitter.screen & 0xff; case VIDBASH: - return m_blitter.screen>>8; + return m_blitter.screen >> 8; case COLLBASL: return m_blitter.colbuf & 0xff; case COLLBASH: - return m_blitter.colbuf>>8; + return m_blitter.colbuf >> 8; case SCBNEXTL: return m_blitter.scb_next & 0xff; case SCBNEXTH: - return m_blitter.scb_next>>8; + return m_blitter.scb_next >> 8; case SPRDLINEL: return m_blitter.bitmap & 0xff; case SPRDLINEH: - return m_blitter.bitmap>>8; + return m_blitter.bitmap >> 8; case HPOSSTRTL: return m_blitter.x_pos & 0xff; case HPOSSTRTH: - return m_blitter.x_pos>>8; + return m_blitter.x_pos >> 8; case VPOSSTRTL: return m_blitter.y_pos & 0xff; case VPOSSTRTH: - return m_blitter.y_pos>>8; + return m_blitter.y_pos >> 8; case SPRHSIZL: return m_blitter.width & 0xff; case SPRHSIZH: - return m_blitter.width>>8; + return m_blitter.width >> 8; case SPRVSIZL: return m_blitter.height & 0xff; case SPRVSIZH: - return m_blitter.height>>8; + return m_blitter.height >> 8; case STRETCHL: return m_blitter.stretch & 0xff; case STRETCHH: - return m_blitter.stretch>>8; + return m_blitter.stretch >> 8; case TILTL: return m_blitter.tilt & 0xff; case TILTH: - return m_blitter.tilt>>8; + return m_blitter.tilt >> 8; // case SPRDOFFL: // case SPRVPOSL: // case COLLOFFL: case VSIZACUML: return m_blitter.height_accumulator & 0xff; case VSIZACUMH: - return m_blitter.height_accumulator>>8; + return m_blitter.height_accumulator >> 8; case HSIZOFFL: return m_blitter.width_offset & 0xff; case HSIZOFFH: - return m_blitter.width_offset>>8; + return m_blitter.width_offset >> 8; case VSIZOFFL: return m_blitter.height_offset & 0xff; case VSIZOFFH: - return m_blitter.height_offset>>8; + return m_blitter.height_offset >> 8; case SCBADRL: return m_blitter.scb & 0xff; case SCBADRH: - return m_blitter.scb>>8; + return m_blitter.scb >> 8; //case PROCADRL: - case SUZYHREV: + case SUZYHREV: // Suzy hardware revision return 0x01; // must not be 0 for correct power up + //case 0x89: // SUZYSREV Suzy software revision case SPRSYS: // math busy, last carry, unsafe access, and stop on current sprite bits not implemented. if (m_suzy.accumulate_overflow) @@ -988,7 +930,7 @@ uint8_t lynx_state::suzy_read(offs_t offset) value |= 0x01; break; case JOYSTICK: - input = ioport("JOY")->read(); + input = m_joy_io->read(); switch (m_rotate) { case 1: @@ -1020,16 +962,17 @@ uint8_t lynx_state::suzy_read(offs_t offset) value = input; break; case SWITCHES: - value = ioport("PAUSE")->read(); + value = m_pause_io->read(); break; - case RCART: + case RCART: // connected to CE0 in cartridge slot if (m_cart->exists()) - value = m_cart->read_rom((m_suzy.high * m_granularity) + m_suzy.low); + value = m_cart->read_rom(get_cart_addr()); else value = 0; - m_suzy.low = (m_suzy.low + 1) & (m_granularity - 1); + if (!machine().side_effects_disabled()) + m_cart_addr_counter = (m_cart_addr_counter + 1) & (m_granularity - 1); // 4040 clock break; - //case RCART_BANK1: /* we need bank 1 emulation!!! */ + //case RCART_BANK1: // connected to CE1 in cartridge slot /* we need bank 1 emulation!!! */ case SPRCTL0: case SPRCTL1: case SPRCOLL: @@ -1046,7 +989,7 @@ uint8_t lynx_state::suzy_read(offs_t offset) return value; } -void lynx_state::suzy_write(offs_t offset, uint8_t data) +void lynx_state::suzy_write(offs_t offset, u8 data) { m_suzy.data[offset] = data; //logerror("suzy write %.2x %.2x\n",offset,data); @@ -1058,7 +1001,7 @@ void lynx_state::suzy_write(offs_t offset, uint8_t data) if ((offset < 0x80) && !(offset & 0x01)) m_suzy.data[offset + 1] = 0; - switch(offset) + switch (offset) { //case TMPADRL: //case TMPADRH: @@ -1067,91 +1010,91 @@ void lynx_state::suzy_write(offs_t offset, uint8_t data) break; case TILTACUMH: m_blitter.tilt_accumulator &= 0xff; - m_blitter.tilt_accumulator |= data<<8; + m_blitter.tilt_accumulator |= data << 8; break; case HOFFL: m_blitter.xoff = data; break; case HOFFH: m_blitter.xoff &= 0xff; - m_blitter.xoff |= data<<8; + m_blitter.xoff |= data << 8; break; case VOFFL: m_blitter.yoff = data; break; case VOFFH: m_blitter.yoff &= 0xff; - m_blitter.yoff |= data<<8; + m_blitter.yoff |= data << 8; break; case VIDBASL: m_blitter.screen = data; break; case VIDBASH: m_blitter.screen &= 0xff; - m_blitter.screen |= data<<8; + m_blitter.screen |= data << 8; break; case COLLBASL: m_blitter.colbuf = data; break; case COLLBASH: m_blitter.colbuf &= 0xff; - m_blitter.colbuf |= data<<8; + m_blitter.colbuf |= data << 8; break; case SCBNEXTL: m_blitter.scb_next = data; break; case SCBNEXTH: m_blitter.scb_next &= 0xff; - m_blitter.scb_next |= data<<8; + m_blitter.scb_next |= data << 8; break; case SPRDLINEL: m_blitter.bitmap = data; break; case SPRDLINEH: m_blitter.bitmap &= 0xff; - m_blitter.bitmap |= data<<8; + m_blitter.bitmap |= data << 8; break; case HPOSSTRTL: m_blitter.x_pos = data; [[fallthrough]]; // FIXME: really? case HPOSSTRTH: m_blitter.x_pos &= 0xff; - m_blitter.x_pos |= data<<8; + m_blitter.x_pos |= data << 8; [[fallthrough]]; // FIXME: really? case VPOSSTRTL: m_blitter.y_pos = data; [[fallthrough]]; // FIXME: really? case VPOSSTRTH: m_blitter.y_pos &= 0xff; - m_blitter.y_pos |= data<<8; + m_blitter.y_pos |= data << 8; [[fallthrough]]; // FIXME: really? case SPRHSIZL: m_blitter.width = data; break; case SPRHSIZH: m_blitter.width &= 0xff; - m_blitter.width |= data<<8; + m_blitter.width |= data << 8; break; case SPRVSIZL: m_blitter.height = data; break; case SPRVSIZH: m_blitter.height &= 0xff; - m_blitter.height |= data<<8; + m_blitter.height |= data << 8; break; case STRETCHL: m_blitter.stretch = data; break; case STRETCHH: m_blitter.stretch &= 0xff; - m_blitter.stretch |= data<<8; + m_blitter.stretch |= data << 8; break; case TILTL: m_blitter.tilt = data; break; case TILTH: m_blitter.tilt &= 0xff; - m_blitter.tilt |= data<<8; + m_blitter.tilt |= data << 8; break; // case SPRDOFFL: // case SPRVPOSL: @@ -1161,28 +1104,28 @@ void lynx_state::suzy_write(offs_t offset, uint8_t data) break; case VSIZACUMH: m_blitter.height_accumulator &= 0xff; - m_blitter.height_accumulator |= data<<8; + m_blitter.height_accumulator |= data << 8; break; case HSIZOFFL: m_blitter.width_offset = data; break; case HSIZOFFH: m_blitter.width_offset &= 0xff; - m_blitter.width_offset |= data<<8; + m_blitter.width_offset |= data << 8; break; case VSIZOFFL: m_blitter.height_offset = data; break; case VSIZOFFH: m_blitter.height_offset &= 0xff; - m_blitter.height_offset |= data<<8; + m_blitter.height_offset |= data << 8; break; case SCBADRL: m_blitter.scb = data; break; case SCBADRH: m_blitter.scb &= 0xff; - m_blitter.scb |= data<<8; + m_blitter.scb |= data << 8; break; //case PROCADRL: @@ -1195,12 +1138,12 @@ void lynx_state::suzy_write(offs_t offset, uint8_t data) to an unsigned one */ if (m_suzy.signed_math) { - uint16_t factor, temp; + u16 factor, temp; factor = m_suzy.data[MATH_D] | (m_suzy.data[MATH_C] << 8); if ((factor - 1) & 0x8000) /* here we use -1 to cover the math bugs on the sign of 0 and 0x8000 */ { temp = (factor ^ 0xffff) + 1; - m_sign_CD = - 1; + m_sign_CD = -1; m_suzy.data[MATH_D] = temp & 0xff; m_suzy.data[MATH_C] = temp >> 8; } @@ -1222,23 +1165,23 @@ void lynx_state::suzy_write(offs_t offset, uint8_t data) case MATH_A: if (m_suzy.signed_math) { - uint16_t factor, temp; + u16 factor, temp; factor = m_suzy.data[MATH_B] | (m_suzy.data[MATH_A] << 8); if ((factor - 1) & 0x8000) /* here we use -1 to cover the math bugs on the sign of 0 and 0x8000 */ { temp = (factor ^ 0xffff) + 1; - m_sign_AB = - 1; + m_sign_AB = -1; m_suzy.data[MATH_B] = temp & 0xff; m_suzy.data[MATH_A] = temp >> 8; } else m_sign_AB = 1; } - lynx_multiply(); + suzy_multiply(); break; /* Writing to E will start a 16 bit divide */ case MATH_E: - lynx_divide(); + suzy_divide(); break; case SPRCTL0: m_blitter.spr_ctl0 = data; @@ -1253,19 +1196,19 @@ void lynx_state::suzy_write(offs_t offset, uint8_t data) logerror("write to SUSYBUSEN %x \n", data); break; case SPRSYS: - m_suzy.signed_math = (data & 0x80) ? 1:0; - m_suzy.accumulate = (data & 0x40) ? 1:0; - m_blitter.no_collide = (data & 0x20) ? 1:0; - m_blitter.vstretch = (data & 0x10) ? 1:0; - m_blitter.lefthanded = (data & 0x08) ? 1:0; - // unsafe access clear and sprite engine stop request are not enabled - if (data & 0x02) logerror("sprite engine stop request\n"); - break; + m_suzy.signed_math = BIT(data, 7); + m_suzy.accumulate = BIT(data, 6); + m_blitter.no_collide = BIT(data, 5); + m_blitter.vstretch = BIT(data, 4); + m_blitter.lefthanded = BIT(data, 3); + // unsafe access clear and sprite engine stop request are not enabled + if (BIT(data, 1)) logerror("sprite engine stop request\n"); + break; case SPRGO: - if ((data & 0x01) && m_suzy.data[SUZYBUSEN]) + if (m_suzy.SPRITE_GO() && m_suzy.data[SUZYBUSEN]) { //m_blitter.time = machine().time(); - lynx_blitter(); + blitter(); } break; case JOYSTICK: @@ -1295,6 +1238,20 @@ void lynx_state::suzy_write(offs_t offset, uint8_t data) */ +void lynx_state::interrupt_set(u8 line) +{ + m_mikey.interrupt |= (1 << line); + m_maincpu->set_input_line(INPUT_LINE_HALT, CLEAR_LINE); + interrupt_update(); +} + + +void lynx_state::interrupt_update() +{ + m_maincpu->set_input_line(M65SC02_IRQ_LINE, (m_mikey.interrupt == 0) ? CLEAR_LINE : ASSERT_LINE); +} + + /* DISPCTL EQU $FD92 ; set to $D by INITMIKEY @@ -1305,33 +1262,32 @@ DISPCTL EQU $FD92 ; set to $D by INITMIKEY ; B0 1 EQU video DMA enabled */ -void lynx_state::lynx_draw_line() +void lynx_state::draw_line() { pen_t const *const pen = m_palette->pens(); - uint16_t j; // clipping needed! // calculate y: first three lines are vblank, - int const y = 101-m_timer[2].counter; + int const y = 101 - m_timer[2].counter; // Documentation states lower two bits of buffer address are ignored (thus 0xfffc mask) - j = (m_mikey.disp_addr & 0xfffc) + y * 160 / 2; + u16 j = (m_mikey.disp_addr & 0xfffc) + y * 160 / 2; // clipping needed! if (m_mikey.data[0x92] & 0x02) { j -= 160 * 102 / 2 - 1; - uint32_t *const line = &m_bitmap_temp.pix(102 - 1 - y); + u32 *const line = &m_bitmap_temp.pix(102 - 1 - y); for (int x = 160 - 2; x >= 0; j++, x -= 2) { - uint8_t const byte = lynx_read_ram(j); + u8 const byte = dram_byte_r(j); line[x + 1] = pen[(byte >> 4) & 0x0f]; line[x + 0] = pen[(byte >> 0) & 0x0f]; } } else { - uint32_t *const line = &m_bitmap_temp.pix(y); + u32 *const line = &m_bitmap_temp.pix(y); for (int x = 0; x < 160; j++, x += 2) { - uint8_t const byte = lynx_read_ram(j); + u8 const byte = dram_byte_r(j); line[x + 0] = pen[(byte >> 4) & 0x0f]; line[x + 1] = pen[(byte >> 0) & 0x0f]; } @@ -1383,7 +1339,7 @@ TIM_BORROWOUT EQU %00000001 -void lynx_state::lynx_timer_init(int which) +void lynx_state::timer_init(int which) { memset(&m_timer[which], 0, sizeof(LYNX_TIMER)); m_timer[which].timer = timer_alloc(TIMER_SHOT); @@ -1395,13 +1351,11 @@ void lynx_state::lynx_timer_init(int which) save_item(NAME(m_timer[which].timer_active), which); } -void lynx_state::lynx_timer_signal_irq(int which) +void lynx_state::timer_signal_irq(int which) { - if ((m_timer[which].cntrl1 & 0x80) && (which != 4)) // if interrupts are enabled and timer != 4 + if ((m_timer[which].int_en()) && (which != 4)) // if interrupts are enabled and timer != 4 { - m_mikey.data[0x81] |= (1 << which); // set interrupt poll register - m_maincpu->set_input_line(INPUT_LINE_HALT, CLEAR_LINE); - m_maincpu->set_input_line(M65SC02_IRQ_LINE, ASSERT_LINE); + interrupt_set(which); // set interrupt poll register } switch (which) // count down linked timers { @@ -1411,32 +1365,34 @@ void lynx_state::lynx_timer_signal_irq(int which) case 104: break; case 103: - m_mikey.vb_rest = 1; + m_mikey.vb_rest = true; break; case 102: m_mikey.disp_addr = m_mikey.data[0x94] | (m_mikey.data[0x95] << 8); break; case 101: - m_mikey.vb_rest = 0; - lynx_draw_line(); + m_mikey.vb_rest = false; + draw_line(); break; default: - lynx_draw_line(); + draw_line(); + break; } - lynx_timer_count_down(2); + timer_count_down(2); break; case 2: copybitmap(m_bitmap, m_bitmap_temp, 0, 0, 0, 0, m_screen->cliprect()); - lynx_timer_count_down(4); + update_screen_timing(); + timer_count_down(4); break; case 1: - lynx_timer_count_down(3); + timer_count_down(3); break; case 3: - lynx_timer_count_down(5); + timer_count_down(5); break; case 5: - lynx_timer_count_down(7); + timer_count_down(7); break; case 7: m_sound->count_down(0); @@ -1444,9 +1400,9 @@ void lynx_state::lynx_timer_signal_irq(int which) } } -void lynx_state::lynx_timer_count_down(int which) +void lynx_state::timer_count_down(int which) { - if ((m_timer[which].cntrl1 & 0x0f) == 0x0f) // count and linking enabled + if (m_timer[which].count_en() && m_timer[which].linked()) // count and linking enabled { if (m_timer[which].counter > 0) { @@ -1456,34 +1412,34 @@ void lynx_state::lynx_timer_count_down(int which) } if (m_timer[which].counter == 0) { - if (m_timer[which].cntrl2 & 0x01) // borrow out + if (m_timer[which].borrow_out()) // borrow out { - lynx_timer_signal_irq(which); - if (m_timer[which].cntrl1 & 0x10) // if reload enabled + timer_signal_irq(which); + if (m_timer[which].reload_en()) // if reload enabled { m_timer[which].counter = m_timer[which].bakup; } else { - m_timer[which].cntrl2 |= 8; // set timer done + m_timer[which].set_timer_done(true); // set timer done } - m_timer[which].cntrl2 &= ~0x01; // clear borrow out + m_timer[which].set_borrow_out(false); // clear borrow out } else - m_timer[which].cntrl2 |= 0x01; // set borrow out + m_timer[which].set_borrow_out(true); // set borrow out return; } } else { //m_timer[which].borrow_in = 0; - m_timer[which].cntrl2 &= ~0x01; + m_timer[which].set_borrow_out(false); } } -uint32_t lynx_state::lynx_time_factor(int val) +u32 lynx_state::time_factor(int val) { - switch(val) + switch (val) { case 0: return 1000000; case 1: return 500000; @@ -1496,24 +1452,24 @@ uint32_t lynx_state::lynx_time_factor(int val) } } -TIMER_CALLBACK_MEMBER(lynx_state::lynx_timer_shot) +TIMER_CALLBACK_MEMBER(lynx_state::timer_shot) { - lynx_timer_signal_irq(param); - if (!(m_timer[param].cntrl1 & 0x10)) // if reload not enabled + timer_signal_irq(param); + if (!(m_timer[param].reload_en())) // if reload not enabled { - m_timer[param].timer_active = 0; - m_timer[param].cntrl2 |= 8; // set timer done + m_timer[param].timer_active = false; + m_timer[param].set_timer_done(true); // set timer done } else { - attotime t = (attotime::from_hz(lynx_time_factor(m_timer[param].cntrl1 & 0x07)) * (m_timer[param].bakup + 1)); + attotime t = (attotime::from_hz(time_factor(m_timer[param].timer_clock())) * (m_timer[param].bakup + 1)); m_timer[param].timer->adjust(t, param); } } -uint8_t lynx_state::lynx_timer_read(int which, int offset) +u8 lynx_state::timer_read(int which, int offset) { - uint8_t value = 0; + u8 value = 0; switch (offset) { @@ -1524,15 +1480,15 @@ uint8_t lynx_state::lynx_timer_read(int which, int offset) value = m_timer[which].cntrl1; break; case 2: - if ((m_timer[which].cntrl1 & 0x07) == 0x07) // linked timer + if (m_timer[which].linked()) // linked timer { value = m_timer[which].counter; } else { - if ( m_timer[which].timer_active ) + if (m_timer[which].timer_active) { - value = (uint8_t) (m_timer[which].timer->remaining().as_ticks(1000000>>(m_timer[which].cntrl1 & 0x07))); + value = u8(m_timer[which].timer->remaining().as_ticks(1000000>>(m_timer[which].timer_clock()))); value -= value ? 1 : 0; } } @@ -1546,14 +1502,14 @@ uint8_t lynx_state::lynx_timer_read(int which, int offset) return value; } -void lynx_state::lynx_timer_write(int which, int offset, uint8_t data) +void lynx_state::timer_write(int which, int offset, u8 data) { //logerror("timer %d write %x %.2x\n", which, offset, data); attotime t; - if ( m_timer[which].timer_active && ((m_timer[which].cntrl1 & 0x07) != 0x07)) + if (m_timer[which].timer_active && (!(m_timer[which].linked()))) { - m_timer[which].counter = (uint8_t) (m_timer[which].timer->remaining().as_ticks(1000000>>(m_timer[which].cntrl1 & 0x07))); + m_timer[which].counter = u8(m_timer[which].timer->remaining().as_ticks(1000000>>(m_timer[which].timer_clock()))); m_timer[which].counter -= (m_timer[which].counter) ? 1 : 0; } @@ -1565,7 +1521,7 @@ void lynx_state::lynx_timer_write(int which, int offset, uint8_t data) case 1: m_timer[which].cntrl1 = data; if (data & 0x40) // reset timer done - m_timer[which].cntrl2 &= ~0x08; + m_timer[which].set_timer_done(false); break; case 2: m_timer[which].counter = data; @@ -1576,22 +1532,42 @@ void lynx_state::lynx_timer_write(int which, int offset, uint8_t data) } /* Update timers */ - //if ( offset < 3 ) + //if (offset < 3) //{ m_timer[which].timer->reset(); - m_timer[which].timer_active = 0; - if ((m_timer[which].cntrl1 & 0x08) && !(m_timer[which].cntrl2 & 0x08)) // if enable count + m_timer[which].timer_active = false; + if ((m_timer[which].count_en()) && !(m_timer[which].timer_done())) // if enable count { - if ((m_timer[which].cntrl1 & 0x07) != 0x07) // if not set to link mode + if (!(m_timer[which].linked())) // if not set to link mode { - t = (attotime::from_hz(lynx_time_factor(m_timer[which].cntrl1 & 0x07)) * (m_timer[which].counter + 1)); + t = (attotime::from_hz(time_factor(m_timer[which].timer_clock())) * (m_timer[which].counter + 1)); m_timer[which].timer->adjust(t, which); - m_timer[which].timer_active = 1; + m_timer[which].timer_active = true; } } //} } +void lynx_state::update_screen_timing() +{ + // variable framerate handling, but needs to verification for screen size handling + if ((!(m_timer[0].linked())) + && ((m_timer[0].cntrl1 & 0x18) == 0x18) + && (m_timer[0].bakup != 0) + && ((m_timer[2].cntrl1 & 0x1f) == 0x1f) + && (m_timer[2].bakup != 0)) + { + if ((m_pixclock != (m_timer[0].timer_clock())) || (m_hcount != m_timer[0].bakup) || (m_vcount != m_timer[2].bakup)) + { + m_pixclock = time_factor(m_timer[0].timer_clock()); + m_hcount = m_timer[0].bakup; // TODO: multiplied internally? + m_vcount = m_timer[2].bakup; + attotime framerate = attotime::from_hz(m_pixclock) * (m_hcount + 1) * (m_vcount + 1); + m_screen->configure(m_screen->width(), m_screen->height(), m_screen->visible_area(), framerate.attoseconds()); + } + } +} + /**************************************** @@ -1600,17 +1576,17 @@ void lynx_state::lynx_timer_write(int which, int offset, uint8_t data) ****************************************/ -void lynx_state::lynx_uart_reset() +void lynx_state::uart_reset() { memset(&m_uart, 0, sizeof(m_uart)); } -TIMER_CALLBACK_MEMBER(lynx_state::lynx_uart_loopback_timer) +TIMER_CALLBACK_MEMBER(lynx_state::uart_loopback_timer) { m_uart.received = false; } -TIMER_CALLBACK_MEMBER(lynx_state::lynx_uart_timer) +TIMER_CALLBACK_MEMBER(lynx_state::uart_timer) { if (m_uart.buffer_loaded) { @@ -1624,34 +1600,35 @@ TIMER_CALLBACK_MEMBER(lynx_state::lynx_uart_timer) m_uart.received = true; m_uart.data_received = m_uart.data_to_send; timer_set(attotime::from_usec(11*16), TIMER_UART_LOOPBACK); - if (m_uart.serctl & 0x40) + if (m_uart.RXINTEN()) { - m_mikey.data[0x81] |= 0x10; - m_maincpu->set_input_line(INPUT_LINE_HALT, CLEAR_LINE); - m_maincpu->set_input_line(M65SC02_IRQ_LINE, ASSERT_LINE); + interrupt_set(4); } } - if (m_uart.serctl & 0x80) + if (m_uart.TXINTEN()) { - m_mikey.data[0x81] |= 0x10; - m_maincpu->set_input_line(INPUT_LINE_HALT, CLEAR_LINE); - m_maincpu->set_input_line(M65SC02_IRQ_LINE, ASSERT_LINE); + interrupt_set(4); } } -uint8_t lynx_state::lynx_uart_r(offs_t offset) +u8 lynx_state::uart_r(offs_t offset) { - uint8_t value = 0x00; + u8 value = 0x00; switch (offset) { case 0x8c: - if (!m_uart.buffer_loaded) + if (!m_uart.buffer_loaded) // TXRDY Transmit buffer ready value |= 0x80; - if (m_uart.received) + if (m_uart.received) // RXRDY Recevie character ready value |= 0x40; - if (!m_uart.sending) + if (!m_uart.sending) // TXEMPTY Transmit done value |= 0x20; + // value |= 0x10; PARERR Recevied parity error (not implemented) + // value |= 0x08; OVERRUN Recevied overrun error (not implemented) + // value |= 0x04; FRAMERR Recevied framing error (not implemented) + // value |= 0x02; RXBRK Break recevied (not implemented) + // value |= 0x01; PARBIT 9th bit (not implemented) break; case 0x8d: @@ -1662,7 +1639,7 @@ uint8_t lynx_state::lynx_uart_r(offs_t offset) return value; } -void lynx_state::lynx_uart_w(offs_t offset, uint8_t data) +void lynx_state::uart_w(offs_t offset, u8 data) { logerror("uart write %.2x %.2x\n", offset, data); switch (offset) @@ -1696,9 +1673,9 @@ void lynx_state::lynx_uart_w(offs_t offset, uint8_t data) ****************************************/ -uint8_t lynx_state::mikey_read(offs_t offset) +u8 lynx_state::mikey_read(offs_t offset) { - uint8_t direction, value = 0x00; + u8 direction, value = 0x00; switch (offset) { @@ -1710,7 +1687,7 @@ uint8_t lynx_state::mikey_read(offs_t offset) case 0x14: case 0x15: case 0x16: case 0x17: case 0x18: case 0x19: case 0x1a: case 0x1b: case 0x1c: case 0x1d: case 0x1e: case 0x1f: - value = lynx_timer_read(offset >> 2, offset & 0x03); + value = timer_read(offset >> 2, offset & 0x03); break; case 0x20: case 0x21: case 0x22: case 0x23: case 0x24: case 0x25: case 0x26: case 0x27: @@ -1723,31 +1700,32 @@ uint8_t lynx_state::mikey_read(offs_t offset) case 0x80: case 0x81: - value = m_mikey.data[0x81]; // both registers access the same interrupt status byte - // logerror( "mikey read %.2x %.2x\n", offset, value ); + value = m_mikey.interrupt; // both registers access the same interrupt status byte + // logerror("mikey read %.2x %.2x\n", offset, value); break; - case 0x84: - case 0x85: + case 0x84: // MAGRDY0 Mag. tape channel 0 ready bit + case 0x85: // MAGRDY1 Mag. tape channel 1 ready bit value = 0x00; break; - case 0x86: + case 0x86: // AUDIN Audio in value = 0x80; break; - case 0x88: + case 0x88: // MIKEYHREV Mikey hardware revision value = 0x01; break; + //case 0x89: // MIKEYSREV Mikey software revision case 0x8b: - direction = m_mikey.data[0x8a]; - value |= (direction & 0x01) ? (m_mikey.data[offset] & 0x01) : 0x01; // External Power input - value |= (direction & 0x02) ? (m_mikey.data[offset] & 0x02) : 0x00; // Cart Address Data output (0 turns cart power on) - value |= (direction & 0x04) ? (m_mikey.data[offset] & 0x04) : 0x04; // noexp input + direction = m_mikey.IODIR(); + value |= BIT(direction, 0) ? (m_mikey.data[offset] & 0x01) : 0x01; // External Power input + value |= BIT(direction, 1) ? (m_mikey.data[offset] & 0x02) : 0x00; // Cart Address Data output (0 turns cart power on) + value |= BIT(direction, 2) ? (m_mikey.data[offset] & 0x04) : 0x04; // noexp input // REST read returns actual rest state anded with rest output bit - value |= (direction & 0x08) ? (((m_mikey.data[offset] & 0x08) && (m_mikey.vb_rest)) ? 0x00 : 0x08) : 0x00; // rest output - value |= (direction & 0x10) ? (m_mikey.data[offset] & 0x10) : 0x10; // audin input + value |= BIT(direction, 3) ? (((m_mikey.data[offset] & 0x08) && (m_mikey.vb_rest)) ? 0x00 : 0x08) : 0x00; // rest output + value |= BIT(direction, 4) ? (m_mikey.data[offset] & 0x10) : 0x10; // audin input /* Hack: we disable COMLynx */ value |= 0x04; /* B5, B6 & B7 are not used */ @@ -1755,17 +1733,17 @@ uint8_t lynx_state::mikey_read(offs_t offset) case 0x8c: case 0x8d: - value = lynx_uart_r(offset); + value = uart_r(offset); break; default: value = m_mikey.data[offset]; - //logerror( "mikey read %.2x %.2x\n", offset, value ); + //logerror("mikey read %.2x %.2x\n", offset, value); } return value; } -void lynx_state::mikey_write(offs_t offset, uint8_t data) +void lynx_state::mikey_write(offs_t offset, u8 data) { switch (offset) { @@ -1777,7 +1755,7 @@ void lynx_state::mikey_write(offs_t offset, uint8_t data) case 0x14: case 0x15: case 0x16: case 0x17: case 0x18: case 0x19: case 0x1a: case 0x1b: case 0x1c: case 0x1d: case 0x1e: case 0x1f: - lynx_timer_write(offset >> 2, offset & 3, data); + timer_write(offset >> 2, offset & 3, data); return; case 0x20: case 0x21: case 0x22: case 0x23: case 0x24: case 0x25: case 0x26: case 0x27: @@ -1789,67 +1767,51 @@ void lynx_state::mikey_write(offs_t offset, uint8_t data) return; case 0x80: - m_mikey.data[0x81] &= ~data; // clear interrupt source + m_mikey.interrupt &= ~data; // clear interrupt source // logerror("mikey write %.2x %.2x\n", offset, data); - if (!m_mikey.data[0x81]) - m_maincpu->set_input_line(M65SC02_IRQ_LINE, CLEAR_LINE); + if (!m_mikey.interrupt) + interrupt_update(); break; /* Is this correct? */ // Notes say writing to register will result in interrupt being triggered. case 0x81: - m_mikey.data[0x81] |= data; + m_mikey.interrupt |= data; if (data) { m_maincpu->set_input_line(INPUT_LINE_HALT, CLEAR_LINE); - m_maincpu->set_input_line(M65SC02_IRQ_LINE, ASSERT_LINE); + interrupt_update(); logerror("direct write to interrupt register\n"); } break; case 0x87: m_mikey.data[offset] = data; - if (data & 0x02) // Power (1 = on) + if (BIT(data, 1)) // Power (1 = on) { - if (data & 0x01) // Cart Address Strobe + if (BIT(data, 0)) // Cart Address Strobe, positive edge { - m_suzy.high <<= 1; - if (m_mikey.data[0x8b] & 0x02) - m_suzy.high |= 1; - m_suzy.high &= 0xff; - m_suzy.low = 0; + m_cart_addr_block = ((m_cart_addr_block << 1) & 0xfe) | BIT(m_mikey.IODAT(), 1); // 74HC164 clock + m_cart_addr_counter = 0; // 4040 reset } } else { - m_suzy.high = 0; - m_suzy.low = 0; + m_cart_addr_block = 0; + m_cart_addr_counter = 0; } break; - case 0x8c: case 0x8d: - lynx_uart_w(offset, data); - break; - - case 0xa0: case 0xa1: case 0xa2: case 0xa3: case 0xa4: case 0xa5: case 0xa6: case 0xa7: - case 0xa8: case 0xa9: case 0xaa: case 0xab: case 0xac: case 0xad: case 0xae: case 0xaf: - case 0xb0: case 0xb1: case 0xb2: case 0xb3: case 0xb4: case 0xb5: case 0xb6: case 0xb7: - case 0xb8: case 0xb9: case 0xba: case 0xbb: case 0xbc: case 0xbd: case 0xbe: case 0xbf: - m_mikey.data[offset] = data; - - /* RED = 0xb- & 0x0f, GREEN = 0xa- & 0x0f, BLUE = (0xb- & 0xf0) >> 4 */ - m_palette->set_pen_color(offset & 0x0f, rgb_t( - pal4bit(m_mikey.data[0xb0 | (offset & 0x0f)] & 0x0f), - pal4bit(m_mikey.data[0xa0 | (offset & 0x0f)] & 0x0f), - pal4bit((m_mikey.data[0xb0 | (offset & 0x0f)] & 0xf0) >> 4))); - break; - /* TODO: properly implement these writes */ case 0x8b: m_mikey.data[offset] = data; - if (m_mikey.data[0x8a] & 0x10) + if ((m_audin_offset == 0) && (m_mikey.IODIR() & 0x10)) logerror("Trying to enable bank 1 write. %d\n", m_mikey.data[offset] & 0x10); break; + case 0x8c: case 0x8d: + uart_w(offset, data); + break; + //case 0x90: // SDONEACK - Suzy Done Acknowledge case 0x91: // CPUSLEEP - CPU Bus Request Disable m_mikey.data[offset] = data; @@ -1859,16 +1821,34 @@ void lynx_state::mikey_write(offs_t offset, uint8_t data) /* A write of '0' to this address will reset the CPU bus request flip flop */ } break; + //case 0x93: // PBKUP - Magic 'P' count value case 0x94: case 0x95: - m_mikey.data[offset]=data; + m_mikey.data[offset] = data; break; case 0x9c: case 0x9d: case 0x9e: - m_mikey.data[offset]=data; - logerror("Mtest%d write: %x\n", offset&0x3, data); + m_mikey.data[offset] = data; + logerror("Mtest%d write: %x\n", offset & 0x3, data); + break; + + case 0xa0: case 0xa1: case 0xa2: case 0xa3: case 0xa4: case 0xa5: case 0xa6: case 0xa7: + case 0xa8: case 0xa9: case 0xaa: case 0xab: case 0xac: case 0xad: case 0xae: case 0xaf: + m_mikey.data[offset] = data; + + /* RED = 0xb- & 0x0f, GREEN = 0xa- & 0x0f, BLUE = (0xb- & 0xf0) >> 4 */ + m_palette->set_pen_green_level(offset & 0x0f, pal4bit(data & 0x0f)); + break; + + case 0xb0: case 0xb1: case 0xb2: case 0xb3: case 0xb4: case 0xb5: case 0xb6: case 0xb7: + case 0xb8: case 0xb9: case 0xba: case 0xbb: case 0xbc: case 0xbd: case 0xbe: case 0xbf: + m_mikey.data[offset] = data; + + /* RED = 0xb- & 0x0f, GREEN = 0xa- & 0x0f, BLUE = (0xb- & 0xf0) >> 4 */ + m_palette->set_pen_red_level(offset & 0x0f, pal4bit(data & 0x0f)); + m_palette->set_pen_blue_level(offset & 0x0f, pal4bit((data & 0xf0) >> 4)); break; default: - m_mikey.data[offset]=data; + m_mikey.data[offset] = data; //logerror("mikey write %.2x %.2x\n",offset,data); break; } @@ -1880,27 +1860,43 @@ void lynx_state::mikey_write(offs_t offset, uint8_t data) ****************************************/ -uint8_t lynx_state::lynx_memory_config_r() +u8 lynx_state::memory_config_r() { return m_memory_config; } -void lynx_state::lynx_memory_config_w(uint8_t data) +void lynx_state::memory_config_w(u8 data) { - /* bit 7: hispeed, uses page mode accesses (4 instead of 5 cycles ) + /* bit 7: hispeed, uses page mode accesses (4 instead of 5 cycles) * when these are safe in the cpu */ m_memory_config = data; - m_bank_fc00->set_bank(BIT(data, 0)); - m_bank_fd00->set_bank(BIT(data, 1)); - m_bank_fe00->set_entry(BIT(data, 2)); - m_bank_fffa->set_entry(BIT(data, 3)); + if (BIT(data, 0)) + m_suzy_view.disable(); + else + m_suzy_view.select(0); + + if (BIT(data, 1)) + m_mikey_view.disable(); + else + m_mikey_view.select(0); + + if (BIT(data, 2)) + m_rom_view.disable(); + else + m_rom_view.select(0); + + if (BIT(data, 3)) + m_vector_view.disable(); + else + m_vector_view.select(0); } void lynx_state::machine_reset() { - lynx_memory_config_w(0); + memory_config_w(0); + m_mikey.interrupt = 0; m_maincpu->set_input_line(INPUT_LINE_HALT, CLEAR_LINE); m_maincpu->set_input_line(M65SC02_IRQ_LINE, CLEAR_LINE); @@ -1918,34 +1914,39 @@ void lynx_state::machine_reset() m_mikey.data[0x90] = 0x00; m_mikey.data[0x92] = 0x00; - lynx_uart_reset(); + uart_reset(); // hack to allow current object loading to work #if 0 - lynx_timer_write( this, 0, 0, 160 ); // set backup value (hpos) = 160 - lynx_timer_write( this, 0, 1, 0x10 | 0x8 | 0 ); // enable count, enable reload, 1us period - lynx_timer_write( this, 2, 0, 105 ); // set backup value (vpos) = 102 - lynx_timer_write( this, 2, 1, 0x10 | 0x8 | 7 ); // enable count, enable reload, link + timer_write(0, 0, 158); // set backup value (hpos) = 159 + timer_write(0, 1, 0x10 | 0x8 | 0); // enable count, enable reload, 1us period + timer_write(2, 0, 104); // set backup value (vpos) = 105 + timer_write(2, 1, 0x10 | 0x8 | 7); // enable count, enable reload, link #endif render_target *target = machine().render().first_target(); target->set_view(m_rotate); } -void lynx_state::lynx_postload() +void lynx_state::device_post_load() { - lynx_memory_config_w(m_memory_config); + memory_config_w(m_memory_config); } void lynx_state::machine_start() { - m_bitmap_temp.allocate(160,102,0,0); + m_bitmap_temp.allocate(160,105,0,0); // save driver variables + save_item(NAME(m_cart_addr_block)); + save_item(NAME(m_cart_addr_counter)); save_item(NAME(m_memory_config)); save_item(NAME(m_sign_AB)); save_item(NAME(m_sign_CD)); save_item(NAME(m_rotate)); + save_item(NAME(m_pixclock)); + save_item(NAME(m_hcount)); + save_item(NAME(m_vcount)); // save blitter variables save_item(NAME(m_blitter.screen)); save_item(NAME(m_blitter.colbuf)); @@ -1984,8 +1985,6 @@ void lynx_state::machine_start() save_item(NAME(m_blitter.busy)); // save suzy variables save_item(NAME(m_suzy.data)); - save_item(NAME(m_suzy.high)); - save_item(NAME(m_suzy.low)); save_item(NAME(m_suzy.signed_math)); save_item(NAME(m_suzy.accumulate)); save_item(NAME(m_suzy.accumulate_overflow)); @@ -1993,6 +1992,7 @@ void lynx_state::machine_start() save_item(NAME(m_mikey.data)); save_item(NAME(m_mikey.disp_addr)); save_item(NAME(m_mikey.vb_rest)); + save_item(NAME(m_mikey.interrupt)); // save uart variables save_item(NAME(m_uart.serctl)); save_item(NAME(m_uart.data_received)); @@ -2002,15 +2002,13 @@ void lynx_state::machine_start() save_item(NAME(m_uart.sending)); save_item(NAME(m_uart.buffer_loaded)); - machine().save().register_postload(save_prepost_delegate(FUNC(lynx_state::lynx_postload), this)); - - m_bank_fe00->configure_entry(0, memregion("maincpu")->base() + 0x0000); - m_bank_fe00->configure_entry(1, m_mem_fe00); - m_bank_fffa->configure_entry(0, memregion("maincpu")->base() + 0x01fa); - m_bank_fffa->configure_entry(1, m_mem_fffa); + m_suzy_view.select(0); + m_mikey_view.select(0); + m_rom_view.select(0); + m_vector_view.select(0); for (int i = 0; i < NR_LYNX_TIMERS; i++) - lynx_timer_init(i); + timer_init(i); } @@ -2020,7 +2018,7 @@ void lynx_state::machine_start() ****************************************/ -image_verify_result lynx_state::lynx_verify_cart(char *header, int kind) +image_verify_result lynx_state::verify_cart(char *header, int kind) { if (kind) { @@ -2053,8 +2051,8 @@ DEVICE_IMAGE_LOAD_MEMBER(lynx_state::cart_load) /* Lynx carts have 19 address lines, the upper 8 used for bank select. The lower 11 bits are used to address data within the selected bank. Valid bank sizes are 256, 512, 1024 or 2048 bytes. Commercial roms use all 256 banks.*/ - uint32_t size = m_cart->common_get_size("rom"); - uint16_t gran = 0; + u32 size = m_cart->common_get_size("rom"); + u16 gran = 0; if (!image.loaded_through_softlist()) { @@ -2067,15 +2065,15 @@ DEVICE_IMAGE_LOAD_MEMBER(lynx_state::cart_load) // 0 0 1 0 // 32 chars name // 22 chars manufacturer - uint8_t header[0x40]; + u8 header[0x40]; image.fread(header, 0x40); // Check the image - if (lynx_verify_cart((char*)header, LYNX_CART) != image_verify_result::PASS) + if (verify_cart((char*)header, LYNX_CART) != image_verify_result::PASS) return image_init_result::FAIL; /* 2008-10 FP: According to Handy source these should be page_size_bank0. Are we using - it correctly in MESS? Moreover, the next two values should be page_size_bank1. We should + it correctly in MAME? Moreover, the next two values should be page_size_bank1. We should implement this as well */ gran = header[4] | (header[5] << 8); @@ -2107,10 +2105,19 @@ DEVICE_IMAGE_LOAD_MEMBER(lynx_state::cart_load) } else { - if (size > 0xffff) // 64,128,256,512k cartridges - m_granularity = size >> 8; + // Some cartridge uses AUDIN pin for bankswitch + if (image.get_feature("audin_offset") != nullptr) + m_audin_offset = atol(image.get_feature("audin_offset")); + + if (image.get_feature("granularity") != nullptr) + m_granularity = atol(image.get_feature("granularity")); else - m_granularity = 0x400; // Homebrew roms not using all 256 banks (T-Tris) (none currently in softlist) + { + if (size > 0xffff) // 64,128,256,512k cartridges + m_granularity = size >> 8; + else + m_granularity = 0x400; // Homebrew roms not using all 256 banks (T-Tris) (none currently in softlist) + } } // set-up rotation from softlist