diff options
Diffstat (limited to 'src/mame/machine/amiga.cpp')
-rw-r--r-- | src/mame/machine/amiga.cpp | 1718 |
1 files changed, 0 insertions, 1718 deletions
diff --git a/src/mame/machine/amiga.cpp b/src/mame/machine/amiga.cpp deleted file mode 100644 index 62da9267548..00000000000 --- a/src/mame/machine/amiga.cpp +++ /dev/null @@ -1,1718 +0,0 @@ -// license:BSD-3-Clause -// copyright-holders:Ernesto Corvi, Aaron Giles, Mariusz Wojcieszek -/*************************************************************************** - - Amiga Computer / Arcadia Game System - - Driver by: - - Aaron Giles, Ernesto Corvi & Mariusz Wojcieszek - -***************************************************************************/ - -#include "emu.h" -#include "includes/amiga.h" -#include "cpu/m68000/m68000.h" - - -/************************************* - * - * Debugging - * - *************************************/ - -#define LOG_CUSTOM 0 -#define LOG_CIA 0 -#define LOG_BLITS 0 -#define LOG_SERIAL 1 - - - -/************************************* - * - * Constants - * - *************************************/ - -/* How many CPU cycles we delay until we fire a pending interrupt */ -#define AMIGA_IRQ_DELAY_CYCLES 24 - -/* How many CPU cycles we wait until we process a blit when the blitter-nasty bit is set */ -#define BLITTER_NASTY_DELAY 16 - - - -/************************************* - * - * Globals - * - *************************************/ - -const char *const amiga_state::s_custom_reg_names[0x100] = -{ - /* 0x000 */ - "BLTDDAT", "DMACONR", "VPOSR", "VHPOSR", - "DSKDATR", "JOY0DAT", "JOY1DAT", "CLXDAT", - "ADKCONR", "POT0DAT", "POT1DAT", "POTGOR", - "SERDATR", "DSKBYTR", "INTENAR", "INTREQR", - /* 0x020 */ - "DSKPTH", "DSKPTL", "DSKLEN", "DSKDAT", - "REFPTR", "VPOSW", "VHPOSW", "COPCON", - "SERDAT", "SERPER", "POTGO", "JOYTEST", - "STREQU", "STRVBL", "STRHOR", "STRLONG", - /* 0x040 */ - "BLTCON0", "BLTCON1", "BLTAFWM", "BLTALWM", - "BLTCPTH", "BLTCPTL", "BLTBPTH", "BLTBPTL", - "BLTAPTH", "BLTAPTL", "BLTDPTH", "BLTDPTL", - "BLTSIZE", "BLTCON0L", "BLTSIZV", "BLTSIZH", - /* 0x060 */ - "BLTCMOD", "BLTBMOD", "BLTAMOD", "BLTDMOD", - "UNK068", "UNK06A", "UNK06C", "UNK06E", - "BLTCDAT", "BLTBDAT", "BLTADAT", "UNK076", - "SPRHDAT", "BPLHDAT", "LISAID", "DSRSYNC", - /* 0x080 */ - "COP1LCH", "COP1LCL", "COP2LCH", "COP2LCL", - "COPJMP1", "COPJMP2", "COPINS", "DIWSTRT", - "DIWSTOP", "DDFSTRT", "DDFSTOP", "DMACON", - "CLXCON", "INTENA", "INTREQ", "ADKCON", - /* 0x0A0 */ - "AUD0LCH", "AUD0LCL", "AUD0LEN", "AUD0PER", - "AUD0VOL", "AUD0DAT", "UNK0AC", "UNK0AE", - "AUD1LCH", "AUD1LCL", "AUD1LEN", "AUD1PER", - "AUD1VOL", "AUD1DAT", "UNK0BC", "UNK0BE", - /* 0x0C0 */ - "AUD2LCH", "AUD2LCL", "AUD2LEN", "AUD2PER", - "AUD2VOL", "AUD2DAT", "UNK0CC", "UNK0CE", - "AUD3LCH", "AUD3LCL", "AUD3LEN", "AUD3PER", - "AUD3VOL", "AUD3DAT", "UNK0DC", "UNK0DE", - /* 0x0E0 */ - "BPL1PTH", "BPL1PTL", "BPL2PTH", "BPL2PTL", - "BPL3PTH", "BPL3PTL", "BPL4PTH", "BPL4PTL", - "BPL5PTH", "BPL5PTL", "BPL6PTH", "BPL6PTL", - "BPL7PTH", "BPL7PTL", "BPL8PTH", "BPL8PTL", - /* 0x100 */ - "BPLCON0", "BPLCON1", "BPLCON2", "BPLCON3", - "BPL1MOD", "BPL2MOD", "BPLCON4", "CLXCON2", - "BPL1DAT", "BPL2DAT", "BPL3DAT", "BPL4DAT", - "BPL5DAT", "BPL6DAT", "BPL7DAT", "BPL8DAT", - /* 0x120 */ - "SPR0PTH", "SPR0PTL", "SPR1PTH", "SPR1PTL", - "SPR2PTH", "SPR2PTL", "SPR3PTH", "SPR3PTL", - "SPR4PTH", "SPR4PTL", "SPR5PTH", "SPR5PTL", - "SPR6PTH", "SPR6PTL", "SPR7PTH", "SPR7PTL", - /* 0x140 */ - "SPR0POS", "SPR0CTL", "SPR0DATA", "SPR0DATB", - "SPR1POS", "SPR1CTL", "SPR1DATA", "SPR1DATB", - "SPR2POS", "SPR2CTL", "SPR2DATA", "SPR2DATB", - "SPR3POS", "SPR3CTL", "SPR3DATA", "SPR3DATB", - /* 0x160 */ - "SPR4POS", "SPR4CTL", "SPR4DATA", "SPR4DATB", - "SPR5POS", "SPR5CTL", "SPR5DATA", "SPR5DATB", - "SPR6POS", "SPR6CTL", "SPR6DATA", "SPR6DATB", - "SPR7POS", "SPR7CTL", "SPR7DATA", "SPR7DATB", - /* 0x180 */ - "COLOR00", "COLOR01", "COLOR02", "COLOR03", - "COLOR04", "COLOR05", "COLOR06", "COLOR07", - "COLOR08", "COLOR09", "COLOR10", "COLOR11", - "COLOR12", "COLOR13", "COLOR14", "COLOR15", - /* 0x1A0 */ - "COLOR16", "COLOR17", "COLOR18", "COLOR19", - "COLOR20", "COLOR21", "COLOR22", "COLOR23", - "COLOR24", "COLOR25", "COLOR26", "COLOR27", - "COLOR28", "COLOR29", "COLOR30", "COLOR31", - /* 0x1C0 */ - "HTOTAL", "HSSTOP", "HBSTRT", "HBSTOP", - "VTOTAL", "VSSTOP", "VBSTRT", "VBSTOP", - "SPRHSTRT", "SPRHSTOP", "BPLHSTRT", "BPLHSTOP", - "HHPOSW", "HHPOSR", "BEAMCON0", "HSSTRT", - /* 0x1E0 */ - "VSSTRT", "HCENTER", "DIWHIGH", "BPLHMOD", - "SPRHPTH", "SPRHPTL", "BPLHPTH", "BPLHPTL", - "UNK1F0", "UNK1F2", "UNK1F4", "UNK1F6", - "UNK1F8", "UNK1FA", "FMODE", "UNK1FE" -}; - -constexpr XTAL amiga_state::CLK_28M_PAL; -constexpr XTAL amiga_state::CLK_7M_PAL; -constexpr XTAL amiga_state::CLK_C1_PAL; -constexpr XTAL amiga_state::CLK_E_PAL; - -constexpr XTAL amiga_state::CLK_28M_NTSC; -constexpr XTAL amiga_state::CLK_7M_NTSC; -constexpr XTAL amiga_state::CLK_C1_NTSC; -constexpr XTAL amiga_state::CLK_E_NTSC; - - -/************************************* - * - * Machine reset - * - *************************************/ - -void amiga_state::machine_start() -{ - m_power_led.resolve(); - - // add callback for RESET instruction - m_maincpu->set_reset_callback(*this, FUNC(amiga_state::m68k_reset)); - - // set up chip RAM access - memory_share *share = memshare("chip_ram"); - if (share == nullptr) - fatalerror("Unable to find Amiga chip RAM\n"); - m_chip_ram.set(*share, 2); - m_chip_ram_mask = (m_chip_ram.bytes() - 1) & ~1; - - // set up the timers - m_irq_timer = timer_alloc(TIMER_AMIGA_IRQ); - m_blitter_timer = timer_alloc(TIMER_AMIGA_BLITTER); - m_serial_timer = timer_alloc(TIMER_SERIAL); - m_scanline_timer = timer_alloc(TIMER_SCANLINE); - - // start the scanline timer - m_scanline_timer->adjust(m_screen->time_until_pos(0)); -} - -WRITE_LINE_MEMBER( amiga_state::m68k_reset ) -{ - logerror("%s: Executed RESET\n", machine().describe_context()); - machine_reset(); -} - -void amiga_state::machine_reset() -{ - // reset cia chips - m_cia_0->reset(); - m_cia_1->reset(); - - // reset custom chip registers - custom_chip_reset(); - - // map kickstart rom to location 0 - // this either done by reseting the cia chips - // or directly by gayle where available - m_gayle_reset = true; - m_overlay->set_bank(1); -} - -WRITE_LINE_MEMBER(amiga_state::fdc_dskblk_w) -{ - set_interrupt(INTENA_SETCLR | INTENA_DSKBLK); -} - -WRITE_LINE_MEMBER(amiga_state::fdc_dsksyn_w) -{ - set_interrupt((state ? INTENA_SETCLR : 0) | INTENA_DSKSYN); -} - -WRITE_LINE_MEMBER( amiga_state::kbreset_w ) -{ - // this is connected to the gary chip, gary then resets the 68k, agnus, paula and the cias - if (!state) - { - m_paula->reset(); - machine_reset(); - m_maincpu->reset(); - } -} - -// simple mirror of region 0xf80000 to 0xfbffff -uint16_t amiga_state::rom_mirror_r(offs_t offset, uint16_t mem_mask) -{ - return m_maincpu->space(AS_PROGRAM).read_word(offset + 0xf80000, mem_mask); -} - -uint32_t amiga_state::rom_mirror32_r(offs_t offset, uint32_t mem_mask) -{ - return m_maincpu->space(AS_PROGRAM).read_dword(offset + 0xf80000, mem_mask); -} - -void amiga_state::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) -{ - switch (id) - { - case TIMER_SCANLINE: - scanline_callback(ptr, param); - break; - case TIMER_AMIGA_IRQ: - amiga_irq_proc(ptr, param); - break; - case TIMER_AMIGA_BLITTER: - amiga_blitter_proc(ptr, param); - break; - case TIMER_SERIAL: - serial_shift(); - break; - default: - fatalerror("Invalid timer: %d\n", id); - } -} - - -/************************************* - * - * Per scanline callback - * - *************************************/ - -void amiga_state::vblank() -{ -} - -// todo: cia a clock can be connected to either a fixed 50/60hz signal from the power supply, or the vblank -TIMER_CALLBACK_MEMBER( amiga_state::scanline_callback ) -{ - int scanline = param; - - // vblank start - if (scanline == 0) - { - // signal vblank irq - set_interrupt(INTENA_SETCLR | INTENA_VERTB); - - // clock tod - m_cia_0->tod_w(1); - - // additional bookkeeping by drivers - vblank(); - } - - // vblank end - if (scanline == m_screen->visible_area().top()) - { - m_cia_0->tod_w(0); - } - - if (m_potgo_port.found()) - { - // pot counters (start counting at 7 (ntsc) or 8 (pal)) - if (BIT(CUSTOM_REG(REG_POTGO), 0) && (scanline /2 ) > 7) - { - m_pot0x += !(m_potgo_port->read() & 0x0100); - m_pot0y += !(m_potgo_port->read() & 0x0400); - m_pot1x += !(m_potgo_port->read() & 0x1000); - m_pot1y += !(m_potgo_port->read() & 0x4000); - } - } - - // render up to this scanline - if (!m_screen->update_partial(scanline)) - { - bitmap_rgb32 dummy_bitmap; - if (IS_AGA()) - aga_render_scanline(dummy_bitmap, scanline); - else - render_scanline(dummy_bitmap, scanline); - } - - // clock tod (if we actually render this scanline) - m_cia_1->tod_w((scanline & 1) ^ BIT(CUSTOM_REG(REG_VPOSR), 15)); - - // force a sound update - m_paula->update(); - - // set timer for next line - scanline = (scanline + 1) % m_screen->height(); - m_scanline_timer->adjust(m_screen->time_until_pos(scanline), scanline); -} - - - -/************************************* - * - * Interrupt management - * - *************************************/ - -void amiga_state::set_interrupt(int interrupt) -{ - custom_chip_w(REG_INTREQ, interrupt); -} - -bool amiga_state::int2_pending() -{ - return m_cia_0_irq; -} - -bool amiga_state::int6_pending() -{ - return m_cia_1_irq; -} - -void amiga_state::update_int2() -{ - set_interrupt((int2_pending() ? INTENA_SETCLR : 0x0000) | INTENA_PORTS); -} - -void amiga_state::update_int6() -{ - set_interrupt((int6_pending() ? INTENA_SETCLR : 0x0000) | INTENA_EXTER); -} - -void amiga_state::update_irqs() -{ - // if the external interrupt line is still active, set the interrupt request bit - if (int2_pending()) - CUSTOM_REG(REG_INTREQ) |= INTENA_PORTS; - - if (int6_pending()) - CUSTOM_REG(REG_INTREQ) |= INTENA_EXTER; - - int ints = CUSTOM_REG(REG_INTENA) & CUSTOM_REG(REG_INTREQ); - - // master interrupt switch - if (CUSTOM_REG(REG_INTENA) & INTENA_INTEN) - { - m_maincpu->set_input_line(1, ints & (INTENA_TBE | INTENA_DSKBLK | INTENA_SOFT) ? ASSERT_LINE : CLEAR_LINE); - m_maincpu->set_input_line(2, ints & (INTENA_PORTS) ? ASSERT_LINE : CLEAR_LINE); - m_maincpu->set_input_line(3, ints & (INTENA_COPER | INTENA_VERTB | INTENA_BLIT) ? ASSERT_LINE : CLEAR_LINE); - m_maincpu->set_input_line(4, ints & (INTENA_AUD0 | INTENA_AUD1 | INTENA_AUD2 | INTENA_AUD3) ? ASSERT_LINE : CLEAR_LINE); - m_maincpu->set_input_line(5, ints & (INTENA_RBF | INTENA_DSKSYN) ? ASSERT_LINE : CLEAR_LINE); - m_maincpu->set_input_line(6, ints & (INTENA_EXTER) ? ASSERT_LINE : CLEAR_LINE); - } - else - { - m_maincpu->set_input_line(1, CLEAR_LINE); - m_maincpu->set_input_line(2, CLEAR_LINE); - m_maincpu->set_input_line(3, CLEAR_LINE); - m_maincpu->set_input_line(4, CLEAR_LINE); - m_maincpu->set_input_line(5, CLEAR_LINE); - m_maincpu->set_input_line(6, CLEAR_LINE); - } -} - -TIMER_CALLBACK_MEMBER( amiga_state::amiga_irq_proc ) -{ - update_irqs(); - m_irq_timer->reset(); -} - -void amiga_state::paula_int_w (offs_t channel, u8 state) -{ - set_interrupt(INTENA_SETCLR | (0x80 << channel)); -} - - -//************************************************************************** -// INPUTS -//************************************************************************** - -uint16_t amiga_state::joy0dat_r() -{ - if (!m_input_device.found() || (m_input_device->read() & 0x10)) - return m_joy0dat_port.read_safe(0xffff); - else - return (m_p1_mouse_y.read_safe(0xff) << 8) | m_p1_mouse_x.read_safe(0xff); -} - -uint16_t amiga_state::joy1dat_r() -{ - if (!m_input_device.found() || m_input_device->read() & 0x20) - return m_joy1dat_port.read_safe(0xffff); - else - return (m_p2_mouse_y.read_safe(0xff) << 8) | m_p2_mouse_x.read_safe(0xff); -} - - - -/************************************* - * - * Ascending blitter variant - * - *************************************/ - -uint32_t amiga_state::blit_ascending() -{ - uint32_t shifta = (CUSTOM_REG(REG_BLTCON0) >> 12) & 0xf; - uint32_t shiftb = (CUSTOM_REG(REG_BLTCON1) >> 12) & 0xf; - uint32_t height = CUSTOM_REG(REG_BLTSIZV); - uint32_t width = CUSTOM_REG(REG_BLTSIZH); - uint32_t acca = 0, accb = 0; - uint32_t blitsum = 0; - uint32_t x, y; - - /* iterate over the height */ - for (y = 0; y < height; y++) - { - /* iterate over the width */ - for (x = 0; x < width; x++) - { - uint16_t abc0, abc1, abc2, abc3; - uint32_t tempa, tempd = 0; - uint32_t b; - - /* fetch data for A */ - if (CUSTOM_REG(REG_BLTCON0) & 0x0800) - { - //CUSTOM_REG(REG_BLTADAT) = m_maincpu->space(AS_PROGRAM).read_word(CUSTOM_REG_LONG(REG_BLTAPTH)); - CUSTOM_REG(REG_BLTADAT) = read_chip_ram(CUSTOM_REG_LONG(REG_BLTAPTH)); - CUSTOM_REG_LONG(REG_BLTAPTH) += 2; - } - - /* fetch data for B */ - if (CUSTOM_REG(REG_BLTCON0) & 0x0400) - { - CUSTOM_REG(REG_BLTBDAT) = read_chip_ram(CUSTOM_REG_LONG(REG_BLTBPTH)); - CUSTOM_REG_LONG(REG_BLTBPTH) += 2; - } - - /* fetch data for C */ - if (CUSTOM_REG(REG_BLTCON0) & 0x0200) - { - CUSTOM_REG(REG_BLTCDAT) = read_chip_ram(CUSTOM_REG_LONG(REG_BLTCPTH)); - CUSTOM_REG_LONG(REG_BLTCPTH) += 2; - } - - /* apply start/end masks to the A data */ - tempa = CUSTOM_REG(REG_BLTADAT); - if (x == 0) - tempa &= CUSTOM_REG(REG_BLTAFWM); - if (x == width - 1) - tempa &= CUSTOM_REG(REG_BLTALWM); - - /* update the B accumulator applying shifts */ - acca = (acca << 16) | (tempa << (16 - shifta)); - accb = (accb << 16) | (CUSTOM_REG(REG_BLTBDAT) << (16 - shiftb)); - - /* build up 4 16-bit words containing 4 pixels each in 0ABC bit order */ - abc0 = ((acca >> 17) & 0x4444) | ((accb >> 18) & 0x2222) | ((CUSTOM_REG(REG_BLTCDAT) >> 3) & 0x1111); - abc1 = ((acca >> 16) & 0x4444) | ((accb >> 17) & 0x2222) | ((CUSTOM_REG(REG_BLTCDAT) >> 2) & 0x1111); - abc2 = ((acca >> 15) & 0x4444) | ((accb >> 16) & 0x2222) | ((CUSTOM_REG(REG_BLTCDAT) >> 1) & 0x1111); - abc3 = ((acca >> 14) & 0x4444) | ((accb >> 15) & 0x2222) | ((CUSTOM_REG(REG_BLTCDAT) >> 0) & 0x1111); - - /* now loop over bits and compute the destination value */ - for (b = 0; b < 4; b++) - { - uint32_t bit; - - /* shift previous data up 4 bits */ - tempd <<= 4; - - /* lookup first bit in series */ - bit = (CUSTOM_REG(REG_BLTCON0) >> (abc0 >> 12)) & 1; - abc0 <<= 4; - tempd |= bit << 3; - - /* lookup second bit in series */ - bit = (CUSTOM_REG(REG_BLTCON0) >> (abc1 >> 12)) & 1; - abc1 <<= 4; - tempd |= bit << 2; - - /* lookup third bit in series */ - bit = (CUSTOM_REG(REG_BLTCON0) >> (abc2 >> 12)) & 1; - abc2 <<= 4; - tempd |= bit << 1; - - /* lookup fourth bit in series */ - bit = (CUSTOM_REG(REG_BLTCON0) >> (abc3 >> 12)) & 1; - abc3 <<= 4; - tempd |= bit << 0; - } - - /* accumulate the sum */ - blitsum |= tempd; - - /* write to the destination */ - if (CUSTOM_REG(REG_BLTCON0) & 0x0100) - { - write_chip_ram(CUSTOM_REG_LONG(REG_BLTDPTH), tempd); - CUSTOM_REG_LONG(REG_BLTDPTH) += 2; - } - } - - /* apply end of line modulos */ - if (CUSTOM_REG(REG_BLTCON0) & 0x0800) - CUSTOM_REG_LONG(REG_BLTAPTH) += CUSTOM_REG_SIGNED(REG_BLTAMOD) & ~1; - if (CUSTOM_REG(REG_BLTCON0) & 0x0400) - CUSTOM_REG_LONG(REG_BLTBPTH) += CUSTOM_REG_SIGNED(REG_BLTBMOD) & ~1; - if (CUSTOM_REG(REG_BLTCON0) & 0x0200) - CUSTOM_REG_LONG(REG_BLTCPTH) += CUSTOM_REG_SIGNED(REG_BLTCMOD) & ~1; - if (CUSTOM_REG(REG_BLTCON0) & 0x0100) - CUSTOM_REG_LONG(REG_BLTDPTH) += CUSTOM_REG_SIGNED(REG_BLTDMOD) & ~1; - } - - /* return the blit sum */ - return blitsum; -} - - - -/************************************* - * - * Descending blitter variant - * - *************************************/ - -uint32_t amiga_state::blit_descending() -{ - uint32_t fill_exclusive = (CUSTOM_REG(REG_BLTCON1) >> 4); - uint32_t fill_inclusive = (CUSTOM_REG(REG_BLTCON1) >> 3); - uint32_t shifta = (CUSTOM_REG(REG_BLTCON0) >> 12) & 0xf; - uint32_t shiftb = (CUSTOM_REG(REG_BLTCON1) >> 12) & 0xf; - uint32_t height = CUSTOM_REG(REG_BLTSIZV); - uint32_t width = CUSTOM_REG(REG_BLTSIZH); - uint32_t acca = 0, accb = 0; - uint32_t blitsum = 0; - uint32_t x, y; - - /* iterate over the height */ - for (y = 0; y < height; y++) - { - uint32_t fill_state = (CUSTOM_REG(REG_BLTCON1) >> 2) & 1; - - /* iterate over the width */ - for (x = 0; x < width; x++) - { - uint16_t abc0, abc1, abc2, abc3; - uint32_t tempa, tempd = 0; - uint32_t b; - - /* fetch data for A */ - if (CUSTOM_REG(REG_BLTCON0) & 0x0800) - { - CUSTOM_REG(REG_BLTADAT) = read_chip_ram(CUSTOM_REG_LONG(REG_BLTAPTH)); - CUSTOM_REG_LONG(REG_BLTAPTH) -= 2; - } - - /* fetch data for B */ - if (CUSTOM_REG(REG_BLTCON0) & 0x0400) - { - CUSTOM_REG(REG_BLTBDAT) = read_chip_ram(CUSTOM_REG_LONG(REG_BLTBPTH)); - CUSTOM_REG_LONG(REG_BLTBPTH) -= 2; - } - - /* fetch data for C */ - if (CUSTOM_REG(REG_BLTCON0) & 0x0200) - { - CUSTOM_REG(REG_BLTCDAT) = read_chip_ram(CUSTOM_REG_LONG(REG_BLTCPTH)); - CUSTOM_REG_LONG(REG_BLTCPTH) -= 2; - } - - /* apply start/end masks to the A data */ - tempa = CUSTOM_REG(REG_BLTADAT); - if (x == 0) - tempa &= CUSTOM_REG(REG_BLTAFWM); - if (x == width - 1) - tempa &= CUSTOM_REG(REG_BLTALWM); - - /* update the B accumulator applying shifts */ - acca = (acca >> 16) | (tempa << shifta); - accb = (accb >> 16) | (CUSTOM_REG(REG_BLTBDAT) << shiftb); - - /* build up 4 16-bit words containing 4 pixels each in 0ABC bit order */ - abc0 = ((acca >> 1) & 0x4444) | ((accb >> 2) & 0x2222) | ((CUSTOM_REG(REG_BLTCDAT) >> 3) & 0x1111); - abc1 = ((acca >> 0) & 0x4444) | ((accb >> 1) & 0x2222) | ((CUSTOM_REG(REG_BLTCDAT) >> 2) & 0x1111); - abc2 = ((acca << 1) & 0x4444) | ((accb >> 0) & 0x2222) | ((CUSTOM_REG(REG_BLTCDAT) >> 1) & 0x1111); - abc3 = ((acca << 2) & 0x4444) | ((accb << 1) & 0x2222) | ((CUSTOM_REG(REG_BLTCDAT) >> 0) & 0x1111); - - /* now loop over bits and compute the destination value */ - for (b = 0; b < 4; b++) - { - uint32_t prev_fill_state; - uint32_t bit; - - /* shift previous data up 4 bits */ - tempd >>= 4; - - /* lookup fourth bit in series */ - bit = (CUSTOM_REG(REG_BLTCON0) >> (abc3 & 0xf)) & 1; - abc3 >>= 4; - prev_fill_state = fill_state; - fill_state ^= bit; - bit ^= prev_fill_state & fill_exclusive; - bit |= prev_fill_state & fill_inclusive; - tempd |= bit << 12; - - /* lookup third bit in series */ - bit = (CUSTOM_REG(REG_BLTCON0) >> (abc2 & 0xf)) & 1; - abc2 >>= 4; - prev_fill_state = fill_state; - fill_state ^= bit; - bit ^= prev_fill_state & fill_exclusive; - bit |= prev_fill_state & fill_inclusive; - tempd |= bit << 13; - - /* lookup second bit in series */ - bit = (CUSTOM_REG(REG_BLTCON0) >> (abc1 & 0xf)) & 1; - abc1 >>= 4; - prev_fill_state = fill_state; - fill_state ^= bit; - bit ^= prev_fill_state & fill_exclusive; - bit |= prev_fill_state & fill_inclusive; - tempd |= bit << 14; - - /* lookup first bit in series */ - bit = (CUSTOM_REG(REG_BLTCON0) >> (abc0 & 0xf)) & 1; - abc0 >>= 4; - prev_fill_state = fill_state; - fill_state ^= bit; - bit ^= prev_fill_state & fill_exclusive; - bit |= prev_fill_state & fill_inclusive; - tempd |= bit << 15; - } - - /* accumulate the sum */ - blitsum |= tempd; - - /* write to the destination */ - if (CUSTOM_REG(REG_BLTCON0) & 0x0100) - { - write_chip_ram(CUSTOM_REG_LONG(REG_BLTDPTH), tempd); - CUSTOM_REG_LONG(REG_BLTDPTH) -= 2; - } - } - - /* apply end of line modulos */ - if (CUSTOM_REG(REG_BLTCON0) & 0x0800) - CUSTOM_REG_LONG(REG_BLTAPTH) -= CUSTOM_REG_SIGNED(REG_BLTAMOD) & ~1; - if (CUSTOM_REG(REG_BLTCON0) & 0x0400) - CUSTOM_REG_LONG(REG_BLTBPTH) -= CUSTOM_REG_SIGNED(REG_BLTBMOD) & ~1; - if (CUSTOM_REG(REG_BLTCON0) & 0x0200) - CUSTOM_REG_LONG(REG_BLTCPTH) -= CUSTOM_REG_SIGNED(REG_BLTCMOD) & ~1; - if (CUSTOM_REG(REG_BLTCON0) & 0x0100) - CUSTOM_REG_LONG(REG_BLTDPTH) -= CUSTOM_REG_SIGNED(REG_BLTDMOD) & ~1; - } - - /* return the blit sum */ - return blitsum; -} - - - -/************************************* - * - * Line drawing blitter variant - * - *************************************/ - -/* - The exact line drawing algorithm is not known, but based on the cryptic - setup instructions, it is clear that it is a basic Bresenham line - algorithm. A standard Bresenham algorithm looks like this: - - epsilon = 0; - while (length--) - { - plot(x, y); - x++; - epsilon += dy; - if ((2 * epsilon) >= dx) - { - y++; - epsilon -= dx; - } - } - - If you multiply the epsilon term by 4 and shuffle the logic a bit, the - equivalent logic is: - - epsilon = 4 * dy - 2 * dx; - while (length--) - { - plot(x, y); - x++; - if (epsilon >= 0) - { - y++; - epsilon += 4 * (dy - dx); - } - else - epsilon += 4 * dy; - } - - With this refactoring, you can see that BLTAPT = epsilon, - BLTAMOD = 4 * (dy - dx) and BLTBMOD = 4 * dy. -*/ - -uint32_t amiga_state::blit_line() -{ - uint32_t singlemode = (CUSTOM_REG(REG_BLTCON1) & 0x0002) ? 0x0000 : 0xffff; - uint32_t singlemask = 0xffff; - uint32_t blitsum = 0; - uint32_t height; - - /* see if folks are breaking the rules */ - if (CUSTOM_REG(REG_BLTSIZH) != 0x0002) - logerror("Blitter: Blit width != 2 in line mode!\n"); - if ((CUSTOM_REG(REG_BLTCON0) & 0x0a00) != 0x0a00) - logerror("Blitter: Channel selection incorrect in line mode!\n" ); - - /* extract the length of the line */ - height = CUSTOM_REG(REG_BLTSIZV); - - /* iterate over the line height */ - while (height--) - { - uint16_t abc0, abc1, abc2, abc3; - uint32_t tempa, tempb, tempd = 0; - int b, dx, dy; - - /* fetch data for C */ - if (CUSTOM_REG(REG_BLTCON0) & 0x0200) - CUSTOM_REG(REG_BLTCDAT) = read_chip_ram(CUSTOM_REG_LONG(REG_BLTCPTH)); - - /* rotate the A data according to the shift */ - tempa = CUSTOM_REG(REG_BLTADAT) >> (CUSTOM_REG(REG_BLTCON0) >> 12); - - /* apply single bit mask */ - tempa &= singlemask; - singlemask &= singlemode; - - /* rotate the B data according to the shift and expand to 16 bits */ - tempb = -((CUSTOM_REG(REG_BLTBDAT) >> (CUSTOM_REG(REG_BLTCON1) >> 12)) & 1); - - /* build up 4 16-bit words containing 4 pixels each in 0ABC bit order */ - abc0 = ((tempa >> 1) & 0x4444) | (tempb & 0x2222) | ((CUSTOM_REG(REG_BLTCDAT) >> 3) & 0x1111); - abc1 = ((tempa >> 0) & 0x4444) | (tempb & 0x2222) | ((CUSTOM_REG(REG_BLTCDAT) >> 2) & 0x1111); - abc2 = ((tempa << 1) & 0x4444) | (tempb & 0x2222) | ((CUSTOM_REG(REG_BLTCDAT) >> 1) & 0x1111); - abc3 = ((tempa << 2) & 0x4444) | (tempb & 0x2222) | ((CUSTOM_REG(REG_BLTCDAT) >> 0) & 0x1111); - - /* now loop over bits and compute the destination value */ - for (b = 0; b < 4; b++) - { - uint32_t bit; - - /* shift previous data up 4 bits */ - tempd <<= 4; - - /* lookup first bit in series */ - bit = (CUSTOM_REG(REG_BLTCON0) >> (abc0 >> 12)) & 1; - abc0 <<= 4; - tempd |= bit << 3; - - /* lookup second bit in series */ - bit = (CUSTOM_REG(REG_BLTCON0) >> (abc1 >> 12)) & 1; - abc1 <<= 4; - tempd |= bit << 2; - - /* lookup third bit in series */ - bit = (CUSTOM_REG(REG_BLTCON0) >> (abc2 >> 12)) & 1; - abc2 <<= 4; - tempd |= bit << 1; - - /* lookup fourth bit in series */ - bit = (CUSTOM_REG(REG_BLTCON0) >> (abc3 >> 12)) & 1; - abc3 <<= 4; - tempd |= bit << 0; - } - - /* accumulate the sum */ - blitsum |= tempd; - - /* write to the destination */ - write_chip_ram(CUSTOM_REG_LONG(REG_BLTDPTH), tempd); - - /* always increment along the major axis */ - if (CUSTOM_REG(REG_BLTCON1) & 0x0010) - { - dx = (CUSTOM_REG(REG_BLTCON1) & 0x0004) ? -1 : 1; - dy = 0; - } - else - { - dx = 0; - dy = (CUSTOM_REG(REG_BLTCON1) & 0x0004) ? -1 : 1; - } - - /* is the sign bit clear? */ - if (!(CUSTOM_REG(REG_BLTCON1) & 0x0040)) - { - /* add 4 * (dy-dx) */ - CUSTOM_REG_LONG(REG_BLTAPTH) += CUSTOM_REG_SIGNED(REG_BLTAMOD) & ~1; - - /* increment along the minor axis */ - if (CUSTOM_REG(REG_BLTCON1) & 0x0010) - dy = (CUSTOM_REG(REG_BLTCON1) & 0x0008) ? -1 : 1; - else - dx = (CUSTOM_REG(REG_BLTCON1) & 0x0008) ? -1 : 1; - } - - /* else add 4 * dy and don't increment along the minor axis */ - else - CUSTOM_REG_LONG(REG_BLTAPTH) += CUSTOM_REG_SIGNED(REG_BLTBMOD) & ~1; - - /* adjust X if necessary */ - if (dx) - { - /* adjust the A shift value */ - uint32_t temp = CUSTOM_REG(REG_BLTCON0) + (int32_t)(dx << 12); - CUSTOM_REG(REG_BLTCON0) = temp; - - /* if we went from 0xf to 0x0 or vice-versa, adjust the actual pointers */ - if (temp & 0x10000) - { - CUSTOM_REG_LONG(REG_BLTCPTH) += 2 * dx; - CUSTOM_REG_LONG(REG_BLTDPTH) += 2 * dx; - } - } - - /* adjust Y if necessary */ - if (dy) - { - /* BLTCMOD seems to be used for both C and D pointers */ - CUSTOM_REG_LONG(REG_BLTCPTH) += dy * (int16_t)(CUSTOM_REG_SIGNED(REG_BLTCMOD) & ~1); - CUSTOM_REG_LONG(REG_BLTDPTH) += dy * (int16_t)(CUSTOM_REG_SIGNED(REG_BLTCMOD) & ~1); - - /* reset the single mask since we're on a new line */ - singlemask = 0xffff; - } - - /* set the new sign bit value */ - CUSTOM_REG(REG_BLTCON1) = (CUSTOM_REG(REG_BLTCON1) & ~0x0040) | ((CUSTOM_REG(REG_BLTAPTL) >> 9) & 0x0040); - - /* increment texture shift on every pixel */ - CUSTOM_REG(REG_BLTCON1) += 0x1000; - } - - return blitsum; -} - - - -/************************************* - * - * Blitter deferred callback - * - *************************************/ - -TIMER_CALLBACK_MEMBER( amiga_state::amiga_blitter_proc ) -{ - uint32_t blitsum = 0; - - /* logging */ - if (LOG_BLITS) - { - static const char *const type[] = { "ASCENDING", "LINE", "DESCENDING", "LINE" }; - logerror("BLIT %s: %dx%d %04x %04x\n", type[CUSTOM_REG(REG_BLTCON1) & 0x0003], CUSTOM_REG(REG_BLTSIZH), CUSTOM_REG(REG_BLTSIZV), CUSTOM_REG(REG_BLTCON0), CUSTOM_REG(REG_BLTCON1)); - if (CUSTOM_REG(REG_BLTCON0) & 0x0800) - logerror(" A: addr=%06X mod=%3d shift=%2d maskl=%04x maskr=%04x\n", CUSTOM_REG_LONG(REG_BLTAPTH), CUSTOM_REG_SIGNED(REG_BLTAMOD), CUSTOM_REG(REG_BLTCON0) >> 12, CUSTOM_REG(REG_BLTAFWM), CUSTOM_REG(REG_BLTALWM)); - if (CUSTOM_REG(REG_BLTCON0) & 0x0400) - logerror(" B: addr=%06X mod=%3d shift=%2d\n", CUSTOM_REG_LONG(REG_BLTBPTH), CUSTOM_REG_SIGNED(REG_BLTBMOD), CUSTOM_REG(REG_BLTCON1) >> 12); - if (CUSTOM_REG(REG_BLTCON0) & 0x0200) - logerror(" C: addr=%06X mod=%3d\n", CUSTOM_REG_LONG(REG_BLTCPTH), CUSTOM_REG_SIGNED(REG_BLTCMOD)); - if (CUSTOM_REG(REG_BLTCON0) & 0x0100) - logerror(" D: addr=%06X mod=%3d\n", CUSTOM_REG_LONG(REG_BLTDPTH), CUSTOM_REG_SIGNED(REG_BLTDMOD)); - } - - /* set the zero flag */ - CUSTOM_REG(REG_DMACON) |= 0x2000; - - /* switch off the type of blit */ - switch (CUSTOM_REG(REG_BLTCON1) & 0x0003) - { - case 0: /* ascending */ - blitsum = blit_ascending(); - break; - - case 2: /* descending */ - blitsum = blit_descending(); - break; - - case 1: /* line */ - case 3: - blitsum = blit_line(); - break; - } - - /* clear the zero flag if we actually wrote data */ - if (blitsum) - CUSTOM_REG(REG_DMACON) &= ~0x2000; - - /* no longer busy */ - CUSTOM_REG(REG_DMACON) &= ~0x4000; - - // signal an interrupt - set_interrupt(INTENA_SETCLR | INTENA_BLIT); - - /* reset the blitter timer */ - m_blitter_timer->reset(); -} - - - -/************************************* - * - * Blitter setup - * - *************************************/ - -void amiga_state::blitter_setup() -{ - int ticks, width, height, blittime; - - /* is there another blitting in progress? */ - if (CUSTOM_REG(REG_DMACON) & 0x4000) - { - logerror("%s - This program is playing tricks with the blitter\n", machine().describe_context() ); - return; - } - - /* line mode is 8 ticks/pixel */ - if (CUSTOM_REG(REG_BLTCON1) & 1) - ticks = 8; - - /* standard mode is 4 ticks base */ - else - { - ticks = 4; - - /* plus 2 ticks if channel B is involved */ - if (CUSTOM_REG(REG_BLTCON0) & 0x0400) - ticks += 2; - - /* plus 2 ticks if both channel C and D are involved */ - if ((CUSTOM_REG(REG_BLTCON0) & 0x0300) == 0x0300) - ticks += 2; - } - - /* extract height/width */ - width = CUSTOM_REG(REG_BLTSIZH); - height = CUSTOM_REG(REG_BLTSIZV); - - /* compute the blit time */ - blittime = ticks * height * width; - - /* if 'blitter-nasty' is set, then the blitter takes over the bus. Make the blit semi-immediate */ - if ( CUSTOM_REG(REG_DMACON) & 0x0400 ) - { - /* simulate the 68k not running while the blit is going */ - m_maincpu->adjust_icount(-(blittime/2) ); - - blittime = BLITTER_NASTY_DELAY; - } - - /* AGA has twice the bus bandwidth, so blits take half the time */ - if (IS_AGA()) - blittime /= 2; - - /* signal blitter busy */ - CUSTOM_REG(REG_DMACON) |= 0x4000; - - /* set a timer */ - m_blitter_timer->adjust( m_maincpu->cycles_to_attotime( blittime )); -} - - -//************************************************************************** -// CENTRONICS -//************************************************************************** - -WRITE_LINE_MEMBER( amiga_state::centronics_ack_w ) -{ - m_cia_0->flag_w(state); -} - -WRITE_LINE_MEMBER( amiga_state::centronics_busy_w ) -{ - m_centronics_busy = state; - m_cia_1->sp_w(state); -} - -WRITE_LINE_MEMBER( amiga_state::centronics_perror_w ) -{ - m_centronics_perror = state; - m_cia_1->cnt_w(state); -} - -WRITE_LINE_MEMBER( amiga_state::centronics_select_w ) -{ - m_centronics_select = state; -} - - -//************************************************************************** -// 8520 CIA -//************************************************************************** - -// CIA-A access: 101x xxxx xxx0 oooo xxxx xxx1 -// CIA-B access: 101x xxxx xx0x oooo xxxx xxx0 - -uint16_t amiga_state::cia_r(offs_t offset, uint16_t mem_mask) -{ - uint16_t data = 0; - - if ((offset & 0x1000/2) == 0 && ACCESSING_BITS_0_7) - data |= m_cia_0->read(offset >> 7); - - if ((offset & 0x2000/2) == 0 && ACCESSING_BITS_8_15) - data |= m_cia_1->read(offset >> 7) << 8; - - if (LOG_CIA) - logerror("%s: cia_r(%06x) = %04x & %04x\n", machine().describe_context(), offset, data, mem_mask); - - return data; -} - -void amiga_state::cia_w(offs_t offset, uint16_t data, uint16_t mem_mask) -{ - if (LOG_CIA) - logerror("%s: cia_w(%06x) = %04x & %04x\n", machine().describe_context(), offset, data, mem_mask); - - if ((offset & 0x1000/2) == 0 && ACCESSING_BITS_0_7) - m_cia_0->write(offset >> 7, data & 0xff); - - if ((offset & 0x2000/2) == 0 && ACCESSING_BITS_8_15) - m_cia_1->write(offset >> 7, data >> 8); -} - -void amiga_state::gayle_cia_w(offs_t offset, uint16_t data, uint16_t mem_mask) -{ - // the first write to cia 0 after a reset switches in chip ram - if (m_gayle_reset && (offset & 0x1000/2) == 0 && ACCESSING_BITS_0_7) - { - m_gayle_reset = false; - m_overlay->set_bank(0); - } - - // hand down to the standard cia handler - cia_w(offset, data, mem_mask); -} - -CUSTOM_INPUT_MEMBER( amiga_state::floppy_drive_status ) -{ - return m_fdc->ciaapra_r(); -} - -void amiga_state::cia_0_port_a_write(uint8_t data) -{ - // bit 0, kickstart overlay - m_overlay->set_bank(BIT(data, 0)); - - // bit 1, power led - m_power_led = BIT(~data, 1); -} - -WRITE_LINE_MEMBER( amiga_state::cia_0_irq ) -{ - if (LOG_CIA) - logerror("%s: cia_0_irq: %d\n", machine().describe_context(), state); - - m_cia_0_irq = state; - update_int2(); -} - -uint8_t amiga_state::cia_1_port_a_read() -{ - uint8_t data = 0; - - // bit 0 to 2, centronics - data |= m_centronics_busy << 0; - data |= m_centronics_perror << 1; - data |= m_centronics_select << 2; - - // bit 2 to 7, serial line - data |= m_rs232_ri << 2; - data |= m_rs232_dsr << 3; - data |= m_rs232_cts << 4; - data |= m_rs232_dcd << 5; - - return data; -} - -void amiga_state::cia_1_port_a_write(uint8_t data) -{ - if (m_rs232) - { - m_rs232->write_rts(BIT(data, 6)); - m_rs232->write_dtr(BIT(data, 7)); - } -} - -WRITE_LINE_MEMBER( amiga_state::cia_1_irq ) -{ - if (LOG_CIA) - logerror("%s: cia_1_irq: %d\n", machine().describe_context(), state); - - m_cia_1_irq = state; - update_int6(); -} - - -//************************************************************************** -// CUSTOM CHIPS -//************************************************************************** - -void amiga_state::custom_chip_reset() -{ - CUSTOM_REG(REG_DENISEID) = m_denise_id; - CUSTOM_REG(REG_VPOSR) = m_agnus_id << 8; - CUSTOM_REG(REG_DDFSTRT) = 0x18; - CUSTOM_REG(REG_DDFSTOP) = 0xd8; - CUSTOM_REG(REG_INTENA) = 0x0000; - CUSTOM_REG(REG_SERDATR) = SERDATR_RXD | SERDATR_TSRE | SERDATR_TBE; - CUSTOM_REG(REG_BEAMCON0) = (m_agnus_id & 0x10) ? 0x0000 : 0x0020; -} - -uint16_t amiga_state::custom_chip_r(offs_t offset) -{ - uint16_t temp; - - if (LOG_CUSTOM) - logerror("%06X:read from custom %s\n", m_maincpu->pc(), s_custom_reg_names[offset & 0xff]); - - switch (offset & 0xff) - { - case REG_BLTDDAT: - return CUSTOM_REG(REG_BLTDDAT); - - case REG_DMACONR: - return CUSTOM_REG(REG_DMACON); - - case REG_VPOSR: - CUSTOM_REG(REG_VPOSR) &= 0xff00; - CUSTOM_REG(REG_VPOSR) |= amiga_gethvpos() >> 16; - - return CUSTOM_REG(REG_VPOSR); - - case REG_VHPOSR: - return amiga_gethvpos() & 0xffff; - - case REG_SERDATR: - if (LOG_SERIAL) - logerror("r SERDATR: %04x\n", CUSTOM_REG(REG_SERDATR)); - - return CUSTOM_REG(REG_SERDATR); - - case REG_JOY0DAT: - if (m_joy0dat_port.found()) - return joy0dat_r(); - [[fallthrough]]; // FIXME: Really? Fall through to potentially reading the other joystick? - case REG_JOY1DAT: - if (m_joy1dat_port.found()) - return joy1dat_r(); - [[fallthrough]]; // TODO: check that this is correct - case REG_POTGOR: - return m_potgo_port.read_safe(0x5500); - - case REG_POT0DAT: - if (m_pot0dat_port.found()) - { - return m_pot0dat_port->read(); - } - else - { - int scale = m_agnus_id & 0x10 ? 525 : 625; - - m_pot0dat = (int) ((double) m_pot0x / scale) * 0xff; - m_pot0dat |= (int)(((double) m_pot0y / scale) * 0xff) << 8; - - return m_pot0dat; - } - - case REG_POT1DAT: - if (m_pot1dat_port.found()) - { - return m_pot1dat_port->read(); - } - else - { - int scale = m_agnus_id & 0x10 ? 525 : 625; - - m_pot1dat = (int) ((double) m_pot1x / scale) * 0xff; - m_pot1dat |= (int)(((double) m_pot1y / scale) * 0xff) << 8; - - return m_pot1dat; - } - - case REG_DSKBYTR: - return m_fdc->dskbytr_r(); - - case REG_INTENAR: - return CUSTOM_REG(REG_INTENA); - - case REG_INTREQR: - return CUSTOM_REG(REG_INTREQ); - - case REG_COPJMP1: - copper_setpc(CUSTOM_REG_LONG(REG_COP1LCH)); - break; - - case REG_COPJMP2: - copper_setpc(CUSTOM_REG_LONG(REG_COP2LCH)); - break; - - case REG_CLXDAT: - temp = CUSTOM_REG(REG_CLXDAT); - CUSTOM_REG(REG_CLXDAT) = 0; - return temp; - - case REG_DENISEID: - return CUSTOM_REG(REG_DENISEID); - - case REG_DSKPTH: - return m_fdc->dskpth_r(); - - case REG_DSKPTL: - return m_fdc->dskptl_r(); - - case REG_ADKCONR: - return m_fdc->adkcon_r(); - - case REG_DSKDATR: - popmessage("DSKDAT R, contact MESSdev"); - break; - } - - return 0xffff; -} - -void amiga_state::custom_chip_w(offs_t offset, uint16_t data) -{ - uint16_t temp; - offset &= 0xff; - - if (LOG_CUSTOM) - logerror("%06X:write to custom %s = %04X\n", m_maincpu->pc(), s_custom_reg_names[offset & 0xff], data); - - // paula will handle some of those registers - m_paula->reg_w(offset, data); - - switch (offset) - { - case REG_BLTDDAT: case REG_DMACONR: case REG_VPOSR: case REG_VHPOSR: - case REG_DSKDATR: case REG_JOY0DAT: case REG_JOY1DAT: case REG_CLXDAT: - case REG_ADKCONR: case REG_POT0DAT: case REG_POT1DAT: case REG_POTGOR: - case REG_SERDATR: case REG_DSKBYTR: case REG_INTENAR: case REG_INTREQR: - // read-only registers - return; - - case REG_DSKDAT: - popmessage("DSKDAT W %04x, contact MESSdev",data); - break; - - case REG_DSKSYNC: - m_fdc->dsksync_w(data); - break; - - case REG_DSKPTH: - m_fdc->dskpth_w(data); - break; - - case REG_DSKPTL: - m_fdc->dskptl_w(data); - break; - - case REG_DSKLEN: - m_fdc->dsklen_w(data); - break; - - case REG_POTGO: - if (BIT(data, 0)) - { - // start counters - m_pot0x = 0; - m_pot0y = 0; - m_pot1x = 0; - m_pot1y = 0; - } - potgo_w(data); - break; - - case REG_SERDAT: - if (LOG_SERIAL) - logerror("w SERDAT: %04x\n", data); - - CUSTOM_REG(REG_SERDAT) = data; - - // transmit shift register currently empty? - if (CUSTOM_REG(REG_SERDATR) & SERDATR_TSRE) - { - // transfer new data to shift register - m_tx_shift = CUSTOM_REG(REG_SERDAT); - CUSTOM_REG(REG_SERDAT) = 0; - - // and signal transmit buffer empty - CUSTOM_REG(REG_SERDATR) &= ~SERDATR_TSRE; - CUSTOM_REG(REG_SERDATR) |= SERDATR_TBE; - set_interrupt(INTENA_SETCLR | INTENA_TBE); - } - else - { - // transmit buffer now full - CUSTOM_REG(REG_SERDATR) &= ~SERDATR_TBE; - } - - return; - - case REG_SERPER: - if (LOG_SERIAL) - logerror("w SERPER: %04x\n", data); - - CUSTOM_REG(REG_SERPER) = data; - serial_adjust(); - - return; - - case REG_BLTSIZE: - CUSTOM_REG(REG_BLTSIZE) = data; - CUSTOM_REG(REG_BLTSIZV) = (data >> 6) & 0x3ff; - CUSTOM_REG(REG_BLTSIZH) = data & 0x3f; - if ( CUSTOM_REG(REG_BLTSIZV) == 0 ) CUSTOM_REG(REG_BLTSIZV) = 0x400; - if ( CUSTOM_REG(REG_BLTSIZH) == 0 ) CUSTOM_REG(REG_BLTSIZH) = 0x40; - blitter_setup(); - break; - - case REG_BLTSIZV: - if (IS_ECS() || IS_AGA()) - { - CUSTOM_REG(REG_BLTSIZV) = data & 0x7fff; - if ( CUSTOM_REG(REG_BLTSIZV) == 0 ) CUSTOM_REG(REG_BLTSIZV) = 0x8000; - } - break; - - case REG_BLTSIZH: - if (IS_ECS() || IS_AGA()) - { - CUSTOM_REG(REG_BLTSIZH) = data & 0x7ff; - if ( CUSTOM_REG(REG_BLTSIZH) == 0 ) CUSTOM_REG(REG_BLTSIZH) = 0x800; - blitter_setup(); - } - break; - - case REG_BLTCON0L: - if (IS_ECS() || IS_AGA()) - { - CUSTOM_REG(REG_BLTCON0) &= 0xff00; - CUSTOM_REG(REG_BLTCON0) |= data & 0xff; - } - break; - - case REG_SPR0PTH: case REG_SPR1PTH: case REG_SPR2PTH: case REG_SPR3PTH: - case REG_SPR4PTH: case REG_SPR5PTH: case REG_SPR6PTH: case REG_SPR7PTH: - data &= ( m_chip_ram_mask >> 16 ); - break; - - case REG_SPR0PTL: case REG_SPR1PTL: case REG_SPR2PTL: case REG_SPR3PTL: - case REG_SPR4PTL: case REG_SPR5PTL: case REG_SPR6PTL: case REG_SPR7PTL: - sprite_dma_reset((offset - REG_SPR0PTL) / 2); - break; - - case REG_SPR0CTL: case REG_SPR1CTL: case REG_SPR2CTL: case REG_SPR3CTL: - case REG_SPR4CTL: case REG_SPR5CTL: case REG_SPR6CTL: case REG_SPR7CTL: - /* disable comparitor on writes here */ - sprite_enable_comparitor((offset - REG_SPR0CTL) / 4, false); - break; - - case REG_SPR0DATA: case REG_SPR1DATA: case REG_SPR2DATA: case REG_SPR3DATA: - case REG_SPR4DATA: case REG_SPR5DATA: case REG_SPR6DATA: case REG_SPR7DATA: - /* enable comparitor on writes here */ - sprite_enable_comparitor((offset - REG_SPR0DATA) / 4, true); - break; - - case REG_COP1LCH: - case REG_COP2LCH: - data &= ( m_chip_ram_mask >> 16 ); - break; - - case REG_COPJMP1: - copper_setpc(CUSTOM_REG_LONG(REG_COP1LCH)); - break; - - case REG_COPJMP2: - copper_setpc(CUSTOM_REG_LONG(REG_COP2LCH)); - break; - - case REG_DDFSTRT: - /* impose hardware limits ( HRM, page 75 ) */ - data &= 0xfe; - if (data < 0x18) - data = 0x18; - break; - - case REG_DDFSTOP: - /* impose hardware limits ( HRM, page 75 ) */ - data &= 0xfe; - if (data > 0xd8) - data = 0xd8; - break; - - case REG_DMACON: - /* bits BBUSY (14) and BZERO (13) are read-only */ - data &= 0x9fff; - data = (data & 0x8000) ? (CUSTOM_REG(offset) | (data & 0x7fff)) : (CUSTOM_REG(offset) & ~(data & 0x7fff)); - m_fdc->dmacon_set(data); - - /* if 'blitter-nasty' has been turned on and we have a blit pending, reschedule it */ - if ( ( data & 0x400 ) && ( CUSTOM_REG(REG_DMACON) & 0x4000 ) ) - m_blitter_timer->adjust(m_maincpu->cycles_to_attotime(BLITTER_NASTY_DELAY)); - - break; - - case REG_INTENA: - temp = data; - - data = (data & INTENA_SETCLR) ? (CUSTOM_REG(offset) | (data & 0x7fff)) : (CUSTOM_REG(offset) & ~(data & 0x7fff)); - CUSTOM_REG(offset) = data; - if (temp & INTENA_SETCLR) - // if we're enabling irq's, delay a bit - m_irq_timer->adjust(m_maincpu->cycles_to_attotime(AMIGA_IRQ_DELAY_CYCLES)); - else - // if we're disabling irq's, process right away - update_irqs(); - break; - - case REG_INTREQ: - temp = data; - - // clear receive buffer full? - if (!(data & INTENA_SETCLR) && (data & INTENA_RBF)) - { - CUSTOM_REG(REG_SERDATR) &= ~SERDATR_OVRUN; - CUSTOM_REG(REG_SERDATR) &= ~SERDATR_RBF; - } - - // clear transmit buffer empty? - if (!(data & INTENA_SETCLR) && (data & INTENA_TBE)) - CUSTOM_REG(REG_SERDATR) |= SERDATR_TBE; - - data = (data & INTENA_SETCLR) ? (CUSTOM_REG(offset) | (data & 0x7fff)) : (CUSTOM_REG(offset) & ~(data & 0x7fff)); - CUSTOM_REG(offset) = data; - - if (temp & INTENA_SETCLR) - // if we're generating irq's, delay a bit - m_irq_timer->adjust(m_maincpu->cycles_to_attotime(AMIGA_IRQ_DELAY_CYCLES)); - else - // if we're clearing irq's, process right away - update_irqs(); - break; - - case REG_ADKCON: - data = (data & 0x8000) ? (CUSTOM_REG(offset) | (data & 0x7fff)) : (CUSTOM_REG(offset) & ~(data & 0x7fff)); - m_fdc->adkcon_set(data); - break; - - case REG_BPL1PTH: case REG_BPL2PTH: case REG_BPL3PTH: case REG_BPL4PTH: - case REG_BPL5PTH: case REG_BPL6PTH: - data &= ( m_chip_ram_mask >> 16 ); - break; - - case REG_BPLCON0: - if ((data & (BPLCON0_BPU0 | BPLCON0_BPU1 | BPLCON0_BPU2)) == (BPLCON0_BPU0 | BPLCON0_BPU1 | BPLCON0_BPU2)) - { - /* planes go from 0 to 6, inclusive */ - logerror( "This game is doing funky planes stuff. (planes > 6)\n" ); - data &= ~BPLCON0_BPU0; - } - CUSTOM_REG(offset) = data; - break; - - case REG_BPL1MOD: case REG_BPL2MOD: - // bit 0 is implicitly ignored on writes, - // and wouldn't otherwise make sense with 68k inability of word reading with odd addresses. - // hpoker/hpokera would otherwise draw misaligned bottom GFX area without this (writes 0x27) - data &= ~1; - break; - - case REG_COLOR00: case REG_COLOR01: case REG_COLOR02: case REG_COLOR03: - case REG_COLOR04: case REG_COLOR05: case REG_COLOR06: case REG_COLOR07: - case REG_COLOR08: case REG_COLOR09: case REG_COLOR10: case REG_COLOR11: - case REG_COLOR12: case REG_COLOR13: case REG_COLOR14: case REG_COLOR15: - case REG_COLOR16: case REG_COLOR17: case REG_COLOR18: case REG_COLOR19: - case REG_COLOR20: case REG_COLOR21: case REG_COLOR22: case REG_COLOR23: - case REG_COLOR24: case REG_COLOR25: case REG_COLOR26: case REG_COLOR27: - case REG_COLOR28: case REG_COLOR29: case REG_COLOR30: case REG_COLOR31: - if (IS_AGA()) - { - aga_palette_write(offset - REG_COLOR00, data); - } - else - { - data &= 0xfff; - CUSTOM_REG(offset + 32) = (data >> 1) & 0x777; - } - break; - - // display window start/stop - case REG_DIWSTRT: - case REG_DIWSTOP: - m_diwhigh_valid = false; - break; - - // display window high - case REG_DIWHIGH: - if (IS_ECS() || IS_AGA()) - { - m_diwhigh_valid = true; - CUSTOM_REG(REG_DIWHIGH) = data; - } - break; - - case REG_BEAMCON0: - // only available on ecs agnus - if (m_agnus_id >= AGNUS_HR_PAL) - { - CUSTOM_REG(REG_BEAMCON0) = data; - update_screenmode(); - } - break; - - default: - break; - } - - if (IS_AGA()) - CUSTOM_REG(offset) = data; - else - if (offset <= REG_COLOR31) - CUSTOM_REG(offset) = data; -} - - -//************************************************************************** -// SERIAL -//************************************************************************** - -void amiga_state::serial_adjust() -{ - uint32_t divisor = (CUSTOM_REG(REG_SERPER) & 0x7fff) + 1; - uint32_t baud = m_paula->clock() / divisor; - - m_serial_timer->adjust(attotime::from_hz(baud) / 2, 0, attotime::from_hz(baud)); -} - -void amiga_state::serial_shift() -{ - if (CUSTOM_REG(REG_ADKCON) & ADKCON_UARTBRK) - { - // break active, force low - rs232_tx(0); - } - else - { - // transmit shift register not empty? - if ((CUSTOM_REG(REG_SERDATR) & SERDATR_TSRE) == 0) - { - if (m_tx_state == 0) - { - // transmit start bit - rs232_tx(0); - m_tx_state++; - } - else if (m_tx_state <= 8 + BIT(CUSTOM_REG(REG_SERPER), 15)) - { - // send data bits - rs232_tx(m_tx_shift & 1); - m_tx_shift >>= 1; - m_tx_state++; - } - else - { - // send stop bits until we run out - if (m_tx_shift & 1) - { - rs232_tx(m_tx_shift & 1); - m_tx_shift >>= 1; - } - else - { - // more data? - if (CUSTOM_REG(REG_SERDAT)) - { - // transfer to shift register - m_tx_shift = CUSTOM_REG(REG_SERDAT); - CUSTOM_REG(REG_SERDAT) = 0; - - // signal buffer empty - CUSTOM_REG(REG_SERDATR) |= SERDATR_TBE; - set_interrupt(INTENA_SETCLR | INTENA_TBE); - } - else - { - // we're done - CUSTOM_REG(REG_SERDATR) |= SERDATR_TSRE; - } - - m_tx_state = 0; - } - } - } - else - { - // transmit register empty - rs232_tx(1); - } - } - - // waiting for start bit? - if (m_rx_state == 0) - { - // start bit seen (high to low transition) - if (m_rx_previous && (CUSTOM_REG(REG_SERDATR) & SERDATR_RXD) == 0) - { - m_rx_state++; - } - } - else if (m_rx_state <= 8 + BIT(CUSTOM_REG(REG_SERPER), 15)) - { - // receive data - m_rx_shift >>= 1; - m_rx_shift = (m_rx_shift & 0x7fff) | (BIT(CUSTOM_REG(REG_SERDATR), 11) << 15); - m_rx_state++; - } - else - { - // stop bit - m_rx_shift >>= 1; - m_rx_shift = (m_rx_shift & 0x7fff) | (BIT(CUSTOM_REG(REG_SERDATR), 11) << 15); - - // shift to start - m_rx_shift >>= (15 - (8 + BIT(CUSTOM_REG(REG_SERPER), 15))); - - // save data - CUSTOM_REG(REG_SERDATR) &= ~0x3ff; - CUSTOM_REG(REG_SERDATR) |= m_rx_shift & 0x3ff; - - // overrun? - if (CUSTOM_REG(REG_SERDATR) & SERDATR_RBF) - CUSTOM_REG(REG_SERDATR) |= SERDATR_OVRUN; - - // set ready and signal interrupt - CUSTOM_REG(REG_SERDATR) |= SERDATR_RBF; - set_interrupt(INTENA_SETCLR | INTENA_RBF); - - m_rx_shift = 0; - m_rx_state = 0; - } -} - -void amiga_state::rs232_tx(int state) -{ - if (m_rs232) - m_rs232->write_txd(state); -} - -void amiga_state::rx_write(int level) -{ - m_rx_previous = BIT(CUSTOM_REG(REG_SERDATR), 11); - CUSTOM_REG(REG_SERDATR) &= ~SERDATR_RXD; - CUSTOM_REG(REG_SERDATR) |= level << 11; -} - -WRITE_LINE_MEMBER( amiga_state::rs232_rx_w ) -{ - rx_write(state); - - // start bit received? - if (m_rx_state == 1) - serial_adjust(); -} - -WRITE_LINE_MEMBER( amiga_state::rs232_dcd_w ) -{ - m_rs232_dcd = state; -} - -WRITE_LINE_MEMBER( amiga_state::rs232_dsr_w ) -{ - m_rs232_dsr = state; -} - -WRITE_LINE_MEMBER( amiga_state::rs232_ri_w ) -{ - m_rs232_ri = state; -} - -WRITE_LINE_MEMBER( amiga_state::rs232_cts_w ) -{ - m_rs232_cts = state; -} |