summaryrefslogtreecommitdiffstatshomepage
diff options
context:
space:
mode:
-rw-r--r--.gitattributes4
-rw-r--r--src/mess/drivers/a7800.c88
-rw-r--r--src/mess/includes/a7800.h100
-rw-r--r--src/mess/mess.mak2
-rw-r--r--src/mess/video/a7800.c417
-rw-r--r--src/mess/video/maria.c442
-rw-r--r--src/mess/video/maria.h70
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