diff options
author | 2014-08-26 05:54:24 +0000 | |
---|---|---|
committer | 2014-08-26 05:54:24 +0000 | |
commit | 30d296ba22ba538f2007349eaa1bb8644786eed3 (patch) | |
tree | 08c68f4968d9cb21f8794d676425f1c9fc752f21 | |
parent | 5dfe8ac4853b5e2a68ab0a352977c35ed8089e32 (diff) |
(MESS) a7800: split video emulation (Atari MARIA chip) into a
separate device. [Fabio Priuli]
-rw-r--r-- | .gitattributes | 4 | ||||
-rw-r--r-- | src/mess/drivers/a7800.c | 88 | ||||
-rw-r--r-- | src/mess/includes/a7800.h | 100 | ||||
-rw-r--r-- | src/mess/mess.mak | 2 | ||||
-rw-r--r-- | src/mess/video/a7800.c | 417 | ||||
-rw-r--r-- | src/mess/video/maria.c | 442 | ||||
-rw-r--r-- | src/mess/video/maria.h | 70 |
7 files changed, 598 insertions, 525 deletions
diff --git a/.gitattributes b/.gitattributes index a3015e04339..5b223239746 100644 --- a/.gitattributes +++ b/.gitattributes @@ -8519,7 +8519,6 @@ src/mess/drivers/zorba.c svneol=native#text/plain src/mess/drivers/zrt80.c svneol=native#text/plain src/mess/drivers/zsbc3.c svneol=native#text/plain src/mess/drivers/zx.c svneol=native#text/plain -src/mess/includes/a7800.h svneol=native#text/plain src/mess/includes/abc1600.h svneol=native#text/plain src/mess/includes/abc80.h svneol=native#text/plain src/mess/includes/abc80x.h svneol=native#text/plain @@ -9205,7 +9204,6 @@ src/mess/video/911_chr.h svneol=native#text/plain src/mess/video/911_key.h svneol=native#text/plain src/mess/video/911_vdt.c svneol=native#text/plain src/mess/video/911_vdt.h svneol=native#text/plain -src/mess/video/a7800.c svneol=native#text/plain src/mess/video/abc1600.c svneol=native#text/plain src/mess/video/abc1600.h svneol=native#text/plain src/mess/video/abc80.c svneol=native#text/plain @@ -9261,6 +9259,8 @@ src/mess/video/kyocera.c svneol=native#text/plain src/mess/video/llc.c svneol=native#text/plain src/mess/video/lviv.c svneol=native#text/plain src/mess/video/mac.c svneol=native#text/plain +src/mess/video/maria.c svneol=native#text/plain +src/mess/video/maria.h svneol=native#text/plain src/mess/video/mbc55x.c svneol=native#text/plain src/mess/video/mbee.c svneol=native#text/plain src/mess/video/mc80.c svneol=native#text/plain diff --git a/src/mess/drivers/a7800.c b/src/mess/drivers/a7800.c index 2af68e471a3..7acd600e539 100644 --- a/src/mess/drivers/a7800.c +++ b/src/mess/drivers/a7800.c @@ -97,15 +97,74 @@ #include "emu.h" #include "cpu/m6502/m6502.h" #include "sound/tiaintf.h" -#include "bus/a7800/a78_carts.h" +#include "sound/tiasound.h" #include "machine/6532riot.h" -#include "includes/a7800.h" +#include "video/maria.h" +#include "bus/a7800/a78_carts.h" #define A7800_NTSC_Y1 XTAL_14_31818MHz #define CLK_PAL 1773447 +class a7800_state : public driver_device +{ +public: + a7800_state(const machine_config &mconfig, device_type type, const char *tag) + : driver_device(mconfig, type, tag), + m_maincpu(*this, "maincpu"), + m_tia(*this, "tia"), + m_maria(*this, "maria"), + m_io_joysticks(*this, "joysticks"), + m_io_buttons(*this, "buttons"), + m_io_vblank(*this, "vblank"), + m_io_console_buttons(*this, "console_buttons"), + m_cartslot(*this, "cartslot"), + m_screen(*this, "screen") { } + + int m_lines; + int m_ispal; + + int m_ctrl_lock; + int m_ctrl_reg; + int m_maria_flag; + int m_p1_one_button; + int m_p2_one_button; + int m_bios_enabled; + + UINT8 *m_bios; + + DECLARE_READ8_MEMBER(bios_or_cart_r); + DECLARE_WRITE8_MEMBER(ram0_w); + DECLARE_READ8_MEMBER(tia_r); + DECLARE_WRITE8_MEMBER(tia_w); + DECLARE_READ8_MEMBER(maria_r); + DECLARE_WRITE8_MEMBER(maria_w); + DECLARE_DRIVER_INIT(a7800_pal); + DECLARE_DRIVER_INIT(a7800_ntsc); + virtual void machine_start(); + virtual void machine_reset(); + DECLARE_PALETTE_INIT(a7800); + DECLARE_PALETTE_INIT(a7800p); + TIMER_DEVICE_CALLBACK_MEMBER(interrupt); + TIMER_CALLBACK_MEMBER(maria_startdma); + DECLARE_READ8_MEMBER(riot_joystick_r); + DECLARE_READ8_MEMBER(riot_console_button_r); + DECLARE_WRITE8_MEMBER(riot_button_pullup_w); + +protected: + required_device<cpu_device> m_maincpu; + required_device<tia_device> m_tia; + required_device<atari_maria_device> m_maria; + required_ioport m_io_joysticks; + required_ioport m_io_buttons; + required_ioport m_io_vblank; + required_ioport m_io_console_buttons; + required_device<a78_cart_slot_device> m_cartslot; + required_device<screen_device> m_screen; +}; + + /*************************************************************************** MEMORY HANDLERS ***************************************************************************/ @@ -191,6 +250,22 @@ WRITE8_MEMBER(a7800_state::tia_w) } +// TIMERS + +TIMER_DEVICE_CALLBACK_MEMBER(a7800_state::interrupt) +{ + // DMA Begins 7 cycles after hblank + machine().scheduler().timer_set(m_maincpu->cycles_to_attotime(7), timer_expired_delegate(FUNC(a7800_state::maria_startdma),this)); + m_maria->interrupt(m_lines); +} + +TIMER_CALLBACK_MEMBER(a7800_state::maria_startdma) +{ + m_maria->startdma(m_lines); +} + + + // ROM READ8_MEMBER(a7800_state::bios_or_cart_r) { @@ -206,7 +281,7 @@ READ8_MEMBER(a7800_state::bios_or_cart_r) static ADDRESS_MAP_START( a7800_mem, AS_PROGRAM, 8, a7800_state ) AM_RANGE(0x0000, 0x001f) AM_MIRROR(0x300) AM_READWRITE(tia_r, tia_w) - AM_RANGE(0x0020, 0x003f) AM_MIRROR(0x300) AM_READWRITE(maria_r, maria_w) + AM_RANGE(0x0020, 0x003f) AM_MIRROR(0x300) AM_DEVREADWRITE("maria", atari_maria_device, read, write) AM_RANGE(0x0040, 0x00ff) AM_RAMBANK("ram0") // RAM (6116 block 0) AM_RANGE(0x0140, 0x01ff) AM_RAMBANK("ram1") // RAM (6116 block 1) AM_RANGE(0x0280, 0x02ff) AM_DEVREADWRITE("riot", riot6532_device, read, write) @@ -1272,17 +1347,20 @@ static MACHINE_CONFIG_START( a7800_ntsc, a7800_state ) /* basic machine hardware */ MCFG_CPU_ADD("maincpu", M6502, A7800_NTSC_Y1/8) /* 1.79 MHz (switches to 1.19 MHz on TIA or RIOT access) */ MCFG_CPU_PROGRAM_MAP(a7800_mem) - MCFG_TIMER_DRIVER_ADD_SCANLINE("scantimer", a7800_state, a7800_interrupt, "screen", 0, 1) + MCFG_TIMER_DRIVER_ADD_SCANLINE("scantimer", a7800_state, interrupt, "screen", 0, 1) /* video hardware */ MCFG_SCREEN_ADD("screen", RASTER) MCFG_SCREEN_RAW_PARAMS( 7159090, 454, 0, 320, 263, 27, 27 + 192 + 32 ) - MCFG_SCREEN_UPDATE_DRIVER(a7800_state, screen_update_a7800) + MCFG_SCREEN_UPDATE_DEVICE("maria", atari_maria_device, screen_update) MCFG_SCREEN_PALETTE("palette") MCFG_PALETTE_ADD("palette", ARRAY_LENGTH(a7800_palette) / 3) MCFG_PALETTE_INIT_OWNER(a7800_state, a7800) + MCFG_DEVICE_ADD("maria", ATARI_MARIA, 0) + MCFG_MARIA_DMACPU("maincpu") + /* sound hardware */ MCFG_SPEAKER_STANDARD_MONO("mono") MCFG_SOUND_TIA_ADD("tia", 31400) diff --git a/src/mess/includes/a7800.h b/src/mess/includes/a7800.h deleted file mode 100644 index b8754be5f05..00000000000 --- a/src/mess/includes/a7800.h +++ /dev/null @@ -1,100 +0,0 @@ -/***************************************************************************** - * - * includes/a7800.h - * - ****************************************************************************/ - -#ifndef A7800_H_ -#define A7800_H_ - -#include "machine/6532riot.h" -#include "sound/tiasound.h" -#include "sound/tiaintf.h" -#include "bus/a7800/a78_slot.h" - - -class a7800_state : public driver_device -{ -public: - a7800_state(const machine_config &mconfig, device_type type, const char *tag) - : driver_device(mconfig, type, tag), - m_maincpu(*this, "maincpu"), - m_tia(*this, "tia"), - m_io_joysticks(*this, "joysticks"), - m_io_buttons(*this, "buttons"), - m_io_vblank(*this, "vblank"), - m_io_console_buttons(*this, "console_buttons"), - m_cartslot(*this, "cartslot"), - m_screen(*this, "screen") { } - - int m_lines; - int m_ispal; - - int m_ctrl_lock; - int m_ctrl_reg; - int m_maria_flag; - int m_p1_one_button; - int m_p2_one_button; - int m_bios_enabled; - - UINT8 *m_bios; - - int m_maria_palette[32]; - int m_line_ram[2][160]; - int m_active_buffer; - int m_maria_write_mode; - unsigned int m_maria_dll; - unsigned int m_maria_dl; - int m_maria_holey; - int m_maria_offset; - int m_maria_vblank; - int m_maria_dli; - int m_maria_dmaon; - int m_maria_dpp; - int m_maria_wsync; - int m_maria_backcolor; - int m_maria_color_kill; - int m_maria_cwidth; - int m_maria_bcntl; - int m_maria_kangaroo; - int m_maria_rm; - int m_maria_nmi; - unsigned int m_maria_charbase; - bitmap_ind16 m_bitmap; - - DECLARE_READ8_MEMBER(bios_or_cart_r); - DECLARE_WRITE8_MEMBER(ram0_w); - DECLARE_READ8_MEMBER(tia_r); - DECLARE_WRITE8_MEMBER(tia_w); - DECLARE_READ8_MEMBER(maria_r); - DECLARE_WRITE8_MEMBER(maria_w); - DECLARE_DRIVER_INIT(a7800_pal); - DECLARE_DRIVER_INIT(a7800_ntsc); - virtual void machine_start(); - virtual void machine_reset(); - virtual void video_start(); - DECLARE_PALETTE_INIT(a7800); - DECLARE_PALETTE_INIT(a7800p); - UINT32 screen_update_a7800(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect); - TIMER_DEVICE_CALLBACK_MEMBER(a7800_interrupt); - TIMER_CALLBACK_MEMBER(a7800_maria_startdma); - DECLARE_READ8_MEMBER(riot_joystick_r); - DECLARE_READ8_MEMBER(riot_console_button_r); - DECLARE_WRITE8_MEMBER(riot_button_pullup_w); - -protected: - required_device<cpu_device> m_maincpu; - required_device<tia_device> m_tia; - required_ioport m_io_joysticks; - required_ioport m_io_buttons; - required_ioport m_io_vblank; - required_ioport m_io_console_buttons; - required_device<a78_cart_slot_device> m_cartslot; - required_device<screen_device> m_screen; - - void maria_draw_scanline(); - int is_holey(unsigned int addr); - int write_line_ram(int addr, UINT8 offset, int pal); -}; - -#endif diff --git a/src/mess/mess.mak b/src/mess/mess.mak index b1c259278bc..a541da6f355 100644 --- a/src/mess/mess.mak +++ b/src/mess/mess.mak @@ -1025,7 +1025,7 @@ $(MESSOBJ)/atari.a: \ $(MESS_MACHINE)/atarifdc.o \ $(MESS_DRIVERS)/atari400.o \ $(MESS_DRIVERS)/a7800.o \ - $(MESS_VIDEO)/a7800.o \ + $(MESS_VIDEO)/maria.o \ $(MESS_DRIVERS)/a2600.o \ $(MESS_DRIVERS)/atarist.o \ $(MESS_VIDEO)/atarist.o \ diff --git a/src/mess/video/a7800.c b/src/mess/video/a7800.c deleted file mode 100644 index 4edd2091b39..00000000000 --- a/src/mess/video/a7800.c +++ /dev/null @@ -1,417 +0,0 @@ -/*************************************************************************** - - video/a7800.c - - Routines to control the Atari 7800 video hardware - - 2014-05-06 Mike Saarna Added interrupts to DMA cycle eating. Updates to - LL, OL, and spin accounting for HALT behavior. - - 2014-03-24 Mike Saarna Fixed DMA regarding startup, shutdown and - cycle stealing. - - 2013-05-08 huygens rewrite to emulate line ram buffers (mostly fixes Kung-Fu Master - Started DMA cycle stealing implementation - - 2003-06-23 ericball Kangaroo mode & 320 mode & other stuff - - 2002-05-14 kubecj vblank dma stop fix - - 2002-05-13 kubecj fixed 320C mode (displayed 2 pixels instead of one!) - noticed that Jinks uses 0x02-320D mode - implemented the mode - completely unsure if good! - implemented some Maria CTRL variables - - 2002-05-12 kubecj added cases for 0x01-160A, 0x05-160B as stated by docs - -***************************************************************************/ - -#include "emu.h" -#include "cpu/m6502/m6502.h" -#include "includes/a7800.h" - - -#define TRIGGER_HSYNC 64717 - -#define READ_MEM(x) space.read_byte(x) - -/********** Maria ***********/ - -/*************************************************************************** - - Start the video hardware emulation. - -***************************************************************************/ -void a7800_state::video_start() -{ - int i,j; - for(i=0; i<32; i++) - { - m_maria_palette[i]=0; - } - - for(i=0; i<2; i++) - { - for(j=0; j<160; j++) - m_line_ram[i][j] = 0; - } - - m_active_buffer = 0; - - m_maria_write_mode=0; - m_maria_dmaon=0; - m_maria_vblank=0x80; - m_maria_dll=0; - m_maria_wsync=0; - - m_maria_color_kill = 0; - m_maria_cwidth = 0; - m_maria_bcntl = 0; - m_maria_kangaroo = 0; - m_maria_rm = 0; - - machine().first_screen()->register_screen_bitmap(m_bitmap); -} - -/*************************************************************************** - - Stop the video hardware emulation. - -***************************************************************************/ - -int a7800_state::is_holey(unsigned int addr) -{ - if (((m_maria_holey & 0x02) && ((addr & 0x9000) == 0x9000)) || ( (m_maria_holey & 0x01) && ((addr & 0x8800) == 0x8800))) - return 1; - else - return 0; -} - -int a7800_state::write_line_ram(int addr, UINT8 offset, int pal) -{ - address_space& space = m_maincpu->space(AS_PROGRAM); - int data, c; - - data = READ_MEM(addr); - pal = pal << 2; - - if (m_maria_write_mode) - { - c = (pal & 0x10) | (data & 0x0C) | (data >> 6); // P2 D3 D2 D7 D6 - if (((c & 3) || m_maria_kangaroo) && (offset < 160)) - m_line_ram[m_active_buffer][offset] = c; - offset++; - c = (pal & 0x10) | ((data & 0x03) << 2) | ((data & 0x30) >> 4); // P2 D1 D0 D5 D4 - if (((c & 3) || m_maria_kangaroo) && (offset < 160)) - m_line_ram[m_active_buffer][offset] = c; - } - else - { - for (int i=0; i<4; i++, offset++) - { - c = pal | ((data >> (6 - 2*i)) & 0x03); - if (((c & 3) || m_maria_kangaroo) && (offset < 160)) - m_line_ram[m_active_buffer][offset] = c; - } - } - return m_maria_write_mode ? 2 : 4; -} - - -void a7800_state::maria_draw_scanline() -{ - address_space& space = m_maincpu->space(AS_PROGRAM); - unsigned int graph_adr,data_addr; - int width,pal,ind; - UINT8 hpos; - unsigned int dl; - int x, d, c, i, pixel_cell, cells; - int maria_cycles; - - if ( m_maria_offset == 0 ) - { - if(READ_MEM(m_maria_dll+3) & 0x80) - maria_cycles=40; // DMA + maria interrupt overhead - else - maria_cycles=19; // DMA - } - else - { - maria_cycles = 16; // DMA - } - - cells = 0; - - /* Process this DLL entry */ - dl = m_maria_dl; - - /* DMA */ - /* Step through DL's */ - while ((READ_MEM(dl + 1) & 0x5F) != 0) - { - /* Extended header */ - if (!(READ_MEM(dl+1) & 0x1F)) - { - graph_adr = (READ_MEM(dl+2) << 8) | READ_MEM(dl); - width = ((READ_MEM(dl+3) ^ 0xff) & 0x1F) + 1; - hpos = READ_MEM(dl+4); - pal = READ_MEM(dl+3) >> 5; - m_maria_write_mode = (READ_MEM(dl+1) & 0x80) >> 5; - ind = READ_MEM(dl+1) & 0x20; - dl+=5; - maria_cycles += 10; - } - /* Normal header */ - else - { - graph_adr = (READ_MEM(dl+2) << 8) | READ_MEM(dl); - width = ((READ_MEM(dl+1) ^ 0xff) & 0x1F) + 1; - hpos = READ_MEM(dl+3); - pal = READ_MEM(dl+1) >> 5; - ind = 0x00; - dl+=4; - maria_cycles += 8; - } - - /*logerror("%x DL: ADR=%x width=%x hpos=%x pal=%x mode=%x ind=%x\n",m_screen->vpos(),graph_adr,width,hpos,pal,m_maria_write_mode,ind );*/ - - for (x=0; x<width; x++) - { - /* Do indirect mode */ - if (ind) - { - c = READ_MEM(graph_adr + x) & 0xFF; - data_addr = (m_maria_charbase | c) + (m_maria_offset << 8); - if (is_holey(data_addr)) - continue; - maria_cycles += 3; - if( m_maria_cwidth ) // two data bytes per map byte - { - cells = write_line_ram(data_addr, hpos, pal); - hpos += cells; - cells = write_line_ram(data_addr+1, hpos, pal); - hpos += cells; - maria_cycles += 6; - } - else - { - cells = write_line_ram(data_addr, hpos, pal); - hpos += cells; - maria_cycles += 3; - } - } - else // direct mode - { - data_addr = graph_adr + x + (m_maria_offset << 8); - if (is_holey(data_addr)) - continue; - cells = write_line_ram(data_addr, hpos, pal); - hpos += cells; - maria_cycles += 3; - } - } - } - // Spin the CPU for Maria DMA, if it's not already spinning for WSYNC. - // MARIA generates the 6502 clock by dividing its own clock by 4. It needs to HALT and unHALT - // the 6502 on ths same clock phase, so MARIA will wait until its clock divides evenly by 4. - // To spin until an even divisor, we just round-up any would-be truncations by adding 3. - if ( ! m_maria_wsync ) - m_maincpu->spin_until_time(m_maincpu->cycles_to_attotime((maria_cycles+3)/4)); - - // draw line buffer to screen - m_active_buffer = !m_active_buffer; // switch buffers - UINT16 *scanline; - scanline = &m_bitmap.pix16(m_screen->vpos()); - - - for ( i = 0; i<160; i++ ) - { - switch (m_maria_rm) - { - case 0x00: /* 160A, 160B */ - case 0x01: /* 160A, 160B */ - pixel_cell = m_line_ram[m_active_buffer][i]; - scanline[2*i] = m_maria_palette[pixel_cell]; - scanline[2*i+1] = m_maria_palette[pixel_cell]; - break; - - case 0x02: /* 320B, 320D */ - pixel_cell = m_line_ram[m_active_buffer][i]; - d = (pixel_cell & 0x10) | (pixel_cell & 0x02) | ((pixel_cell >> 3) & 1); // b4 0 0 b1 b3 - scanline[2*i] = m_maria_palette[d]; - d = (pixel_cell & 0x10) | ((pixel_cell << 1) & 0x02) | ((pixel_cell >> 2) & 1); // b4 0 0 b0 b2 - scanline[2*i+1] = m_maria_palette[d]; - break; - - case 0x03: /* 320A, 320C */ - pixel_cell = m_line_ram[m_active_buffer][i]; - d = (pixel_cell & 0x1C) | (pixel_cell & 0x02); // b4 b3 b2 b1 0 - scanline[2*i] = m_maria_palette[d]; - d = (pixel_cell & 0x1C) | ((pixel_cell << 1) & 0x02); // b4 b3 b2 b0 0 - scanline[2*i+1] = m_maria_palette[d]; - break; - } - } - - for(i=0; i<160; i++) // buffer automaticaly cleared once displayed - m_line_ram[m_active_buffer][i] = 0; -} - - - -TIMER_DEVICE_CALLBACK_MEMBER(a7800_state::a7800_interrupt) -{ - // DMA Begins 7 cycles after hblank - machine().scheduler().timer_set(m_maincpu->cycles_to_attotime(7), timer_expired_delegate(FUNC(a7800_state::a7800_maria_startdma),this)); - if( m_maria_wsync ) - { - machine().scheduler().trigger( TRIGGER_HSYNC ); - m_maria_wsync = 0; - } - - int frame_scanline = m_screen->vpos() % ( m_lines + 1 ); - if (frame_scanline == 16) - m_maria_vblank = 0x00; - - if ( frame_scanline == ( m_lines - 5 ) ) - { - m_maria_vblank = 0x80; - } -} - - -TIMER_CALLBACK_MEMBER(a7800_state::a7800_maria_startdma) -{ - int frame_scanline; - address_space& space = m_maincpu->space(AS_PROGRAM); - int maria_scanline = m_screen->vpos(); - - frame_scanline = maria_scanline % ( m_lines + 1 ); - - if( (frame_scanline == 16) && m_maria_dmaon ) - { - /* end of vblank */ - - m_maria_dll = m_maria_dpp; // currently only handle changes to dll during vblank - m_maria_dl = (READ_MEM(m_maria_dll+1) << 8) | READ_MEM(m_maria_dll+2); - m_maria_offset = READ_MEM(m_maria_dll) & 0x0f; - m_maria_holey = (READ_MEM(m_maria_dll) & 0x60) >> 5; - m_maria_nmi = READ_MEM(m_maria_dll) & 0x80; - /* logerror("DLL=%x\n",m_maria_dll); */ - maria_draw_scanline(); - } - - - if( ( frame_scanline > 16 ) && (frame_scanline < (m_lines - 5)) && m_maria_dmaon ) - { - maria_draw_scanline(); - - if( m_maria_offset == 0 ) - { - m_maria_dll+=3; - m_maria_dl = (READ_MEM(m_maria_dll+1) << 8) | READ_MEM(m_maria_dll+2); - m_maria_offset = READ_MEM(m_maria_dll) & 0x0f; - m_maria_holey = (READ_MEM(m_maria_dll) & 0x60) >> 5; - if ( READ_MEM(m_maria_dll & 0x10) ) - logerror("dll bit 5 set!\n"); - m_maria_nmi = READ_MEM(m_maria_dll) & 0x80; - } - else - { - m_maria_offset--; - } - } - - if( m_maria_nmi ) - { - m_maincpu->set_input_line(INPUT_LINE_NMI, PULSE_LINE); - m_maria_nmi = 0; - } -} - -/*************************************************************************** - - Refresh the video screen - -***************************************************************************/ -/* This routine is called at the start of vblank to refresh the screen */ -UINT32 a7800_state::screen_update_a7800(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect) -{ - copybitmap(bitmap, m_bitmap, 0, 0, 0, 0, cliprect); - return 0; -} - - -/****** MARIA ***************************************/ - -READ8_MEMBER(a7800_state::maria_r) -{ - switch (offset) - { - case 0x08: - return m_maria_vblank; - - default: - logerror("undefined MARIA read %x\n",offset); - return 0x00; // don't know if this should be 0x00 or 0xff - } -} - -WRITE8_MEMBER(a7800_state::maria_w) -{ - int i; - - if ((offset & 3) != 0) - m_maria_palette[offset] = data; - - switch (offset) - { - case 0x00: - // all color ram addresses with 00 for their least significant bits point to the background color - for (i = 0; i<8; i++) - m_maria_palette[4*i] = data; - break; - case 0x04: - m_maincpu->spin_until_trigger(TRIGGER_HSYNC); - m_maria_wsync=1; - break; - case 0x0C: // DPPH - m_maria_dpp = (m_maria_dpp & 0x00ff) | (data << 8); - break; - case 0x10: // DPPL - m_maria_dpp = (m_maria_dpp & 0xff00) | data; - break; - case 0x14: - m_maria_charbase = (data << 8); - break; - case 0x1C: - /*logerror("MARIA CTRL=%x\n",data);*/ - m_maria_color_kill = data & 0x80; - switch ((data >> 5) & 3) - { - case 0x00: case 01: - logerror("dma test mode, do not use.\n"); - break; - case 0x02: - m_maria_dmaon = 1; - break; - case 0x03: - m_maria_dmaon = 0; - break; - } - m_maria_cwidth = data & 0x10; - m_maria_bcntl = data & 0x08; // Currently unimplemented as we don't display the border - m_maria_kangaroo = data & 0x04; - m_maria_rm = data & 0x03; - - /*logerror( "MARIA CTRL: CK:%d DMA:%d CW:%d BC:%d KM:%d RM:%d\n", - m_maria_color_kill ? 1 : 0, - ( data & 0x60 ) >> 5, - m_maria_cwidth ? 1 : 0, - m_maria_bcntl ? 1 : 0, - m_maria_kangaroo ? 1 : 0, - m_maria_rm );*/ - - break; - } -} diff --git a/src/mess/video/maria.c b/src/mess/video/maria.c new file mode 100644 index 00000000000..432c6b8939a --- /dev/null +++ b/src/mess/video/maria.c @@ -0,0 +1,442 @@ +/*************************************************************************** + + Atari MARIA video emulation + + + - some history: + + 2014-08-26 Fabio Priuli Converted to device + + 2014-05-06 Mike Saarna Added interrupts to DMA cycle eating. Updates to + LL, OL, and spin accounting for HALT behavior. + + 2014-03-24 Mike Saarna Fixed DMA regarding startup, shutdown and + cycle stealing. + + 2013-05-08 huygens rewrite to emulate line ram buffers (mostly fixes Kung-Fu Master + Started DMA cycle stealing implementation + + 2003-06-23 ericball Kangaroo mode & 320 mode & other stuff + + 2002-05-14 kubecj vblank dma stop fix + + 2002-05-13 kubecj fixed 320C mode (displayed 2 pixels instead of one!) + noticed that Jinks uses 0x02-320D mode + implemented the mode - completely unsure if good! + implemented some Maria CTRL variables + + 2002-05-12 kubecj added cases for 0x01-160A, 0x05-160B as stated by docs + +***************************************************************************/ + +#include "emu.h" +#include "maria.h" + + +#define TRIGGER_HSYNC 64717 + +#define READ_MEM(x) space.read_byte(x) + +const device_type ATARI_MARIA = &device_creator<atari_maria_device>; + + + +atari_maria_device::atari_maria_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : device_t(mconfig, ATARI_MARIA, "Atari MARIA", tag, owner, clock, "atari_maria", __FILE__) +{ +} + + +void atari_maria_device::device_start() +{ + m_cpu = machine().device<cpu_device>(m_cpu_tag); + m_screen = machine().first_screen(); + m_screen->register_screen_bitmap(m_bitmap); + + save_item(NAME(m_maria_palette)); + save_item(NAME(m_line_ram)); + save_item(NAME(m_active_buffer)); + save_item(NAME(m_write_mode)); + save_item(NAME(m_dll)); + save_item(NAME(m_dl)); + save_item(NAME(m_holey)); + save_item(NAME(m_offset)); + save_item(NAME(m_vblank)); + save_item(NAME(m_dmaon)); + save_item(NAME(m_dpp)); + save_item(NAME(m_wsync)); + save_item(NAME(m_color_kill)); + save_item(NAME(m_cwidth)); + save_item(NAME(m_bcntl)); + save_item(NAME(m_kangaroo)); + save_item(NAME(m_rm)); + save_item(NAME(m_nmi)); + save_item(NAME(m_charbase)); +} + +void atari_maria_device::device_reset() +{ + for (int i = 0; i < 32; i++) + m_maria_palette[i] = 0; + + for (int i = 0; i < 2; i++) + for (int j = 0; j < 160; j++) + m_line_ram[i][j] = 0; + + m_active_buffer = 0; + + m_write_mode = 0; + m_dmaon = 0; + m_vblank = 0x80; + m_dll = 0; + m_wsync = 0; + + m_color_kill = 0; + m_cwidth = 0; + m_bcntl = 0; + m_kangaroo = 0; + m_rm = 0; + + m_dl = 0; + m_holey = 0; + m_offset = 0; + m_dpp = 0; + m_nmi = 0; + m_charbase = 0; +} + +/*************************************************************************** + + Stop the video hardware emulation. + +***************************************************************************/ + +int atari_maria_device::is_holey(unsigned int addr) +{ + if (((m_holey & 0x02) && ((addr & 0x9000) == 0x9000)) || ( (m_holey & 0x01) && ((addr & 0x8800) == 0x8800))) + return 1; + else + return 0; +} + +int atari_maria_device::write_line_ram(int addr, UINT8 offset, int pal) +{ + address_space& space = m_cpu->space(AS_PROGRAM); + int c; + + int data = READ_MEM(addr); + pal <<= 2; + + if (m_write_mode) + { + c = (pal & 0x10) | (data & 0x0c) | (data >> 6); // P2 D3 D2 D7 D6 + if (((c & 3) || m_kangaroo) && (offset < 160)) + m_line_ram[m_active_buffer][offset] = c; + offset++; + + c = (pal & 0x10) | ((data & 0x03) << 2) | ((data & 0x30) >> 4); // P2 D1 D0 D5 D4 + if (((c & 3) || m_kangaroo) && (offset < 160)) + m_line_ram[m_active_buffer][offset] = c; + } + else + { + for (int i = 0; i < 4; i++, offset++) + { + c = pal | ((data >> (6 - 2 * i)) & 0x03); + if (((c & 3) || m_kangaroo) && (offset < 160)) + m_line_ram[m_active_buffer][offset] = c; + } + } + return m_write_mode ? 2 : 4; +} + + +void atari_maria_device::draw_scanline() +{ + address_space& space = m_cpu->space(AS_PROGRAM); + UINT16 graph_adr, data_addr; + int width, pal, ind; + UINT8 hpos; + UINT16 dl; + int d, c, pixel_cell, cells; + int maria_cycles; + + if (m_offset == 0) + { + if (READ_MEM(m_dll + 3) & 0x80) + maria_cycles = 40; // DMA + maria interrupt overhead + else + maria_cycles = 19; // DMA + } + else + { + maria_cycles = 16; // DMA + } + + cells = 0; + + /* Process this DLL entry */ + dl = m_dl; + + /* DMA */ + /* Step through DL's */ + while ((READ_MEM(dl + 1) & 0x5f) != 0) + { + /* Extended header */ + if (!(READ_MEM(dl + 1) & 0x1f)) + { + graph_adr = (READ_MEM(dl + 2) << 8) | READ_MEM(dl); + width = ((READ_MEM(dl + 3) ^ 0xff) & 0x1f) + 1; + hpos = READ_MEM(dl + 4); + pal = READ_MEM(dl + 3) >> 5; + m_write_mode = (READ_MEM(dl + 1) & 0x80) >> 5; + ind = READ_MEM(dl + 1) & 0x20; + dl += 5; + maria_cycles += 10; + } + /* Normal header */ + else + { + graph_adr = (READ_MEM(dl + 2) << 8) | READ_MEM(dl); + width = ((READ_MEM(dl + 1) ^ 0xff) & 0x1f) + 1; + hpos = READ_MEM(dl + 3); + pal = READ_MEM(dl + 1) >> 5; + ind = 0x00; + dl += 4; + maria_cycles += 8; + } + + /*logerror("%x DL: ADR=%x width=%x hpos=%x pal=%x mode=%x ind=%x\n", m_screen->vpos(), graph_adr, width, hpos, pal, m_write_mode, ind);*/ + + for (int x = 0; x < width; x++) + { + /* Do indirect mode */ + if (ind) + { + c = READ_MEM(graph_adr + x) & 0xff; + data_addr = (m_charbase | c) + (m_offset << 8); + if (is_holey(data_addr)) + continue; + + maria_cycles += 3; + if (m_cwidth) // two data bytes per map byte + { + cells = write_line_ram(data_addr, hpos, pal); + hpos += cells; + cells = write_line_ram(data_addr+1, hpos, pal); + hpos += cells; + maria_cycles += 6; + } + else + { + cells = write_line_ram(data_addr, hpos, pal); + hpos += cells; + maria_cycles += 3; + } + } + else // direct mode + { + data_addr = graph_adr + x + (m_offset << 8); + if (is_holey(data_addr)) + continue; + cells = write_line_ram(data_addr, hpos, pal); + hpos += cells; + maria_cycles += 3; + } + } + } + // Spin the CPU for Maria DMA, if it's not already spinning for WSYNC. + // MARIA generates the 6502 clock by dividing its own clock by 4. It needs to HALT and unHALT + // the 6502 on ths same clock phase, so MARIA will wait until its clock divides evenly by 4. + // To spin until an even divisor, we just round-up any would-be truncations by adding 3. + if (!m_wsync) + m_cpu->spin_until_time(m_cpu->cycles_to_attotime((maria_cycles+3)/4)); + + // draw line buffer to screen + m_active_buffer = !m_active_buffer; // switch buffers + UINT16 *scanline; + scanline = &m_bitmap.pix16(m_screen->vpos()); + + + for (int i = 0; i < 160; i++) + { + switch (m_rm) + { + case 0x00: /* 160A, 160B */ + case 0x01: /* 160A, 160B */ + pixel_cell = m_line_ram[m_active_buffer][i]; + scanline[2 * i] = m_maria_palette[pixel_cell]; + scanline[2 * i + 1] = m_maria_palette[pixel_cell]; + break; + + case 0x02: /* 320B, 320D */ + pixel_cell = m_line_ram[m_active_buffer][i]; + d = (pixel_cell & 0x10) | (pixel_cell & 0x02) | ((pixel_cell >> 3) & 1); // b4 0 0 b1 b3 + scanline[2 * i] = m_maria_palette[d]; + d = (pixel_cell & 0x10) | ((pixel_cell << 1) & 0x02) | ((pixel_cell >> 2) & 1); // b4 0 0 b0 b2 + scanline[2 * i + 1] = m_maria_palette[d]; + break; + + case 0x03: /* 320A, 320C */ + pixel_cell = m_line_ram[m_active_buffer][i]; + d = (pixel_cell & 0x1c) | (pixel_cell & 0x02); // b4 b3 b2 b1 0 + scanline[2 * i] = m_maria_palette[d]; + d = (pixel_cell & 0x1c) | ((pixel_cell << 1) & 0x02); // b4 b3 b2 b0 0 + scanline[2 * i + 1] = m_maria_palette[d]; + break; + } + } + + for (int i = 0; i < 160; i++) // buffer automaticaly cleared once displayed + m_line_ram[m_active_buffer][i] = 0; +} + + +void atari_maria_device::interrupt(int lines) +{ + if (m_wsync) + { + machine().scheduler().trigger(TRIGGER_HSYNC); + m_wsync = 0; + } + + int frame_scanline = m_screen->vpos() % (lines + 1); + if (frame_scanline == 16) + m_vblank = 0x00; + + if (frame_scanline == (lines - 5)) + m_vblank = 0x80; +} + + +void atari_maria_device::startdma(int lines) +{ + address_space& space = m_cpu->space(AS_PROGRAM); + int maria_scanline = m_screen->vpos(); + int frame_scanline = maria_scanline % (lines + 1); + + if ((frame_scanline == 16) && m_dmaon) + { + /* end of vblank */ + m_dll = m_dpp; // currently only handle changes to dll during vblank + m_dl = (READ_MEM(m_dll + 1) << 8) | READ_MEM(m_dll+2); + m_offset = READ_MEM(m_dll) & 0x0f; + m_holey = (READ_MEM(m_dll) & 0x60) >> 5; + m_nmi = READ_MEM(m_dll) & 0x80; + /* logerror("DLL=%x\n",m_dll); */ + draw_scanline(); + } + + + if ((frame_scanline > 16) && (frame_scanline < (lines - 5)) && m_dmaon) + { + draw_scanline(); + if (m_offset == 0) + { + m_dll += 3; + m_dl = (READ_MEM(m_dll + 1) << 8) | READ_MEM(m_dll + 2); + m_offset = READ_MEM(m_dll) & 0x0f; + m_holey = (READ_MEM(m_dll) & 0x60) >> 5; + if (READ_MEM(m_dll & 0x10)) + logerror("dll bit 5 set!\n"); + m_nmi = READ_MEM(m_dll) & 0x80; + } + else + { + m_offset--; + } + } + + if (m_nmi) + { + m_cpu->set_input_line(INPUT_LINE_NMI, PULSE_LINE); + m_nmi = 0; + } +} + +/*************************************************************************** + + Refresh the video screen + +***************************************************************************/ + +/* This routine is called at the start of vblank to refresh the screen */ +UINT32 atari_maria_device::screen_update(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect) +{ + copybitmap(bitmap, m_bitmap, 0, 0, 0, 0, cliprect); + return 0; +} + + +READ8_MEMBER(atari_maria_device::read) +{ + switch (offset) + { + case 0x08: + return m_vblank; + + default: + logerror("undefined MARIA read %x\n",offset); + return 0x00; // don't know if this should be 0x00 or 0xff + } +} + +WRITE8_MEMBER(atari_maria_device::write) +{ + if ((offset & 3) != 0) + m_maria_palette[offset] = data; + + switch (offset) + { + case 0x00: + // all color ram addresses with 00 for their least significant bits point to the background color + for (int i = 0; i < 8; i++) + m_maria_palette[4 * i] = data; + break; + case 0x04: + m_cpu->spin_until_trigger(TRIGGER_HSYNC); + m_wsync = 1; + break; + case 0x0C: // DPPH + m_dpp = (m_dpp & 0x00ff) | (data << 8); + break; + case 0x10: // DPPL + m_dpp = (m_dpp & 0xff00) | data; + break; + case 0x14: + m_charbase = (data << 8); + break; + case 0x1C: + /*logerror("MARIA CTRL=%x\n",data);*/ + m_color_kill = data & 0x80; + switch ((data >> 5) & 3) + { + case 0x00: + case 01: + logerror("dma test mode, do not use.\n"); + break; + + case 0x02: + m_dmaon = 1; + break; + + case 0x03: + m_dmaon = 0; + break; + } + m_cwidth = data & 0x10; + m_bcntl = data & 0x08; // Currently unimplemented as we don't display the border + m_kangaroo = data & 0x04; + m_rm = data & 0x03; + + /*logerror( "MARIA CTRL: CK:%d DMA:%d CW:%d BC:%d KM:%d RM:%d\n", + m_color_kill ? 1 : 0, + (data & 0x60) >> 5, + m_cwidth ? 1 : 0, + m_bcntl ? 1 : 0, + m_kangaroo ? 1 : 0, + m_rm );*/ + + break; + } +} diff --git a/src/mess/video/maria.h b/src/mess/video/maria.h new file mode 100644 index 00000000000..e1b70baf4a8 --- /dev/null +++ b/src/mess/video/maria.h @@ -0,0 +1,70 @@ +#ifndef __ATARI_MARIA__ +#define __ATARI_MARIA__ + +#include "emu.h" + +// ======================> atari_maria_device + +class atari_maria_device : public device_t +{ +public: + // construction/destruction + atari_maria_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + static void set_cpu_tag(device_t &device, const char *tag) { downcast<atari_maria_device &>(device).m_cpu_tag = tag; } + + void interrupt(int lines); + void startdma(int lines); + + DECLARE_READ8_MEMBER(read); + DECLARE_WRITE8_MEMBER(write); + + UINT32 screen_update(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect); + +protected: + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + +private: + + int m_maria_palette[32]; + int m_line_ram[2][160]; + int m_active_buffer; + int m_write_mode; + unsigned int m_dll; + unsigned int m_dl; + int m_holey; + int m_offset; + int m_vblank; + int m_dmaon; + int m_dpp; + int m_wsync; + int m_color_kill; + int m_cwidth; + int m_bcntl; + int m_kangaroo; + int m_rm; + int m_nmi; + unsigned int m_charbase; + bitmap_ind16 m_bitmap; + + void draw_scanline(); + int is_holey(unsigned int addr); + int write_line_ram(int addr, UINT8 offset, int pal); + + const char *m_cpu_tag; + cpu_device *m_cpu; // CPU whose space(AS_PROGRAM) serves as DMA source + screen_device *m_screen; +}; + + +// device type definition +extern const device_type ATARI_MARIA; + + +#define MCFG_MARIA_DMACPU(_tag) \ + atari_maria_device::set_cpu_tag(*device, _tag); + + +#endif |