1 // license:BSD-3-Clause
2 // copyright-holders:Aaron Giles
3 /***************************************************************************
4 
5     Atari "Stella on Steroids" hardware
6 
7 ****************************************************************************/
8 
9 #include "emu.h"
10 #include "includes/beathead.h"
11 
12 
13 
14 /*************************************
15  *
16  *  Video start/stop
17  *
18  *************************************/
19 
video_start()20 void beathead_state::video_start()
21 {
22 	save_item(NAME(m_finescroll));
23 	save_item(NAME(m_vram_latch_offset));
24 	save_item(NAME(m_hsyncram_offset));
25 	save_item(NAME(m_hsyncram_start));
26 	save_item(NAME(m_hsyncram));
27 }
28 
29 
30 
31 /*************************************
32  *
33  *  VRAM handling
34  *
35  *************************************/
36 
vram_transparent_w(offs_t offset,uint32_t data,uint32_t mem_mask)37 void beathead_state::vram_transparent_w(offs_t offset, uint32_t data, uint32_t mem_mask)
38 {
39 	/* writes to this area appear to handle transparency */
40 	if (!(data & 0x000000ff)) mem_mask &= ~0x000000ff;
41 	if (!(data & 0x0000ff00)) mem_mask &= ~0x0000ff00;
42 	if (!(data & 0x00ff0000)) mem_mask &= ~0x00ff0000;
43 	if (!(data & 0xff000000)) mem_mask &= ~0xff000000;
44 	COMBINE_DATA(&m_videoram[offset]);
45 }
46 
47 
vram_bulk_w(offs_t offset,uint32_t data,uint32_t mem_mask)48 void beathead_state::vram_bulk_w(offs_t offset, uint32_t data, uint32_t mem_mask)
49 {
50 	/* it appears that writes to this area pass in a mask for 4 words in VRAM */
51 	/* allowing them to be filled from a preset latch */
52 	offset &= ~3;
53 	data = data & mem_mask & 0x0f0f0f0f;
54 
55 	/* for now, just handle the bulk fill case; the others we'll catch later */
56 	if (data == 0x0f0f0f0f)
57 		m_videoram[offset+0] = m_videoram[offset+1] = m_videoram[offset+2] = m_videoram[offset+3] = *m_vram_bulk_latch;
58 	else
59 		logerror("Detected bulk VRAM write with mask %08x\n", data);
60 }
61 
62 
vram_latch_w(offs_t offset,uint32_t data)63 void beathead_state::vram_latch_w(offs_t offset, uint32_t data)
64 {
65 	/* latch the address */
66 	m_vram_latch_offset = (4 * offset) & 0x7ffff;
67 }
68 
69 
vram_copy_w(offs_t offset,uint32_t data)70 void beathead_state::vram_copy_w(offs_t offset, uint32_t data)
71 {
72 	/* copy from VRAM to VRAM, for 1024 bytes */
73 	offs_t dest_offset = (4 * offset) & 0x7ffff;
74 	memcpy(&m_videoram[dest_offset / 4], &m_videoram[m_vram_latch_offset / 4], 0x400);
75 }
76 
77 
78 
79 /*************************************
80  *
81  *  Scroll offset handling
82  *
83  *************************************/
84 
finescroll_w(offs_t offset,uint32_t data,uint32_t mem_mask)85 void beathead_state::finescroll_w(offs_t offset, uint32_t data, uint32_t mem_mask)
86 {
87 	uint32_t oldword = m_finescroll;
88 	uint32_t newword = COMBINE_DATA(&m_finescroll);
89 
90 	/* if VBLANK is going off on a scanline other than the last, suspend time */
91 	if ((oldword & 8) && !(newword & 8) && m_screen->vpos() != 261)
92 	{
93 		logerror("Suspending time! (scanline = %d)\n", m_screen->vpos());
94 		m_maincpu->set_input_line(INPUT_LINE_HALT, ASSERT_LINE);
95 	}
96 }
97 
98 
99 
100 /*************************************
101  *
102  *  HSYNC RAM handling
103  *
104  *************************************/
105 
hsync_ram_r(offs_t offset)106 uint32_t beathead_state::hsync_ram_r(offs_t offset)
107 {
108 	/* offset 0 is probably write-only */
109 	if (offset == 0)
110 		logerror("%08X:Unexpected HSYNC RAM read at offset 0\n", m_maincpu->pcbase());
111 
112 	/* offset 1 reads the data */
113 	else
114 		return m_hsyncram[m_hsyncram_offset];
115 
116 	return 0;
117 }
118 
hsync_ram_w(offs_t offset,uint32_t data,uint32_t mem_mask)119 void beathead_state::hsync_ram_w(offs_t offset, uint32_t data, uint32_t mem_mask)
120 {
121 	/* offset 0 selects the address, and can specify the start address */
122 	if (offset == 0)
123 	{
124 		COMBINE_DATA(&m_hsyncram_offset);
125 		if (m_hsyncram_offset & 0x800)
126 			m_hsyncram_start = m_hsyncram_offset & 0x7ff;
127 	}
128 
129 	/* offset 1 writes the data */
130 	else
131 		COMBINE_DATA(&m_hsyncram[m_hsyncram_offset]);
132 }
133 
134 
135 
136 /*************************************
137  *
138  *  Main screen refresher
139  *
140  *************************************/
141 
screen_update(screen_device & screen,bitmap_ind16 & bitmap,const rectangle & cliprect)142 uint32_t beathead_state::screen_update(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect)
143 {
144 	uint8_t *videoram = reinterpret_cast<uint8_t *>(m_videoram.target());
145 	int x, y;
146 
147 	/* generate the final screen */
148 	for (y = cliprect.top(); y <= cliprect.bottom(); y++)
149 	{
150 		pen_t pen_base = (*m_palette_select & 0x7f) * 256;
151 		uint16_t scanline[336];
152 
153 		/* blanking */
154 		if (m_finescroll & 8)
155 			for (x = cliprect.left(); x <= cliprect.right(); x++)
156 				scanline[x] = pen_base;
157 
158 		/* non-blanking */
159 		else
160 		{
161 			offs_t scanline_offset = m_vram_latch_offset + (m_finescroll & 3);
162 			offs_t src = scanline_offset + cliprect.left();
163 
164 			/* unswizzle the scanline first */
165 			for (x = cliprect.left(); x <= cliprect.right(); x++)
166 				scanline[x] = pen_base | videoram[BYTE4_XOR_LE(src++)];
167 		}
168 
169 		/* then draw it */
170 		draw_scanline16(bitmap, cliprect.left(), y, cliprect.width(), &scanline[cliprect.left()], nullptr);
171 	}
172 	return 0;
173 }
174