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