1 // license:BSD-3-Clause
2 // copyright-holders:Aaron Giles
3 /***************************************************************************
4
5 Atari Blasteroids hardware
6
7 ****************************************************************************/
8
9 #include "emu.h"
10 #include "includes/blstroid.h"
11 #include "cpu/m68000/m68000.h"
12
13
14
15 /*************************************
16 *
17 * Tilemap callbacks
18 *
19 *************************************/
20
TILE_GET_INFO_MEMBER(blstroid_state::get_playfield_tile_info)21 TILE_GET_INFO_MEMBER(blstroid_state::get_playfield_tile_info)
22 {
23 uint16_t data = m_playfield_tilemap->basemem_read(tile_index);
24 int code = data & 0x1fff;
25 int color = (data >> 13) & 0x07;
26 tileinfo.set(0, code, color, 0);
27 }
28
29
30
31 /*************************************
32 *
33 * Video system start
34 *
35 *************************************/
36
37 const atari_motion_objects_config blstroid_state::s_mob_config =
38 {
39 1, /* index to which gfx system */
40 1, /* number of motion object banks */
41 1, /* are the entries linked? */
42 0, /* are the entries split? */
43 0, /* render in reverse order? */
44 0, /* render in swapped X/Y order? */
45 0, /* does the neighbor bit affect the next object? */
46 0, /* pixels per SLIP entry (0 for no-slip) */
47 0, /* pixel offset for SLIPs */
48 0, /* maximum number of links to visit/scanline (0=all) */
49
50 0x000, /* base palette entry */
51 0x100, /* maximum number of colors */
52 0, /* transparent pen index */
53
54 {{ 0,0,0x0ff8,0 }}, /* mask for the link */
55 {{ 0,0x3fff,0,0 }}, /* mask for the code index */
56 {{ 0,0,0,0x000f }}, /* mask for the color */
57 {{ 0,0,0,0xffc0 }}, /* mask for the X position */
58 {{ 0xff80,0,0,0 }}, /* mask for the Y position */
59 {{ 0 }}, /* mask for the width, in tiles*/
60 {{ 0x000f,0,0,0 }}, /* mask for the height, in tiles */
61 {{ 0,0x8000,0,0 }}, /* mask for the horizontal flip */
62 {{ 0,0x4000,0,0 }}, /* mask for the vertical flip */
63 {{ 0 }}, /* mask for the priority */
64 {{ 0 }}, /* mask for the neighbor */
65 {{ 0 }}, /* mask for absolute coordinates */
66
67 {{ 0 }}, /* mask for the special value */
68 0 /* resulting value to indicate "special" */
69 };
70
VIDEO_START_MEMBER(blstroid_state,blstroid)71 VIDEO_START_MEMBER(blstroid_state,blstroid)
72 {
73 m_irq_off_timer = timer_alloc(TIMER_IRQ_OFF);
74 m_irq_on_timer = timer_alloc(TIMER_IRQ_ON);
75
76 m_scanline_int_state = false;
77
78 save_item(NAME(m_scanline_int_state));
79 }
80
81
82
83 /*************************************
84 *
85 * Periodic scanline updater
86 *
87 *************************************/
88
device_timer(emu_timer & timer,device_timer_id id,int param,void * ptr)89 void blstroid_state::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr)
90 {
91 switch (id)
92 {
93 case TIMER_IRQ_OFF:
94 /* clear the interrupt */
95 m_maincpu->set_input_line(M68K_IRQ_1, CLEAR_LINE);
96 break;
97 case TIMER_IRQ_ON:
98 /* generate the interrupt */
99 m_maincpu->set_input_line(M68K_IRQ_1, ASSERT_LINE);
100 break;
101 default:
102 atarigen_state::device_timer(timer, id, param, ptr);
103 break;
104 }
105 }
106
107
TIMER_DEVICE_CALLBACK_MEMBER(blstroid_state::scanline_update)108 TIMER_DEVICE_CALLBACK_MEMBER(blstroid_state::scanline_update)
109 {
110 int scanline = param;
111 int offset = (scanline / 8) * 64 + 40;
112
113 /* check for interrupts */
114 if (offset < 0x1000)
115 if (m_playfield_tilemap->basemem_read(offset) & 0x8000)
116 {
117 /* FIXME: - the only thing this IRQ does it tweak the starting MO link */
118 /* unfortunately, it does it too early for the given MOs! */
119 /* perhaps it is not actually hooked up on the real PCB... */
120 return;
121
122 /* set a timer to turn the interrupt on at HBLANK of the 7th scanline */
123 /* and another to turn it off one scanline later */
124 int width = m_screen->width();
125 int vpos = m_screen->vpos();
126 attotime period_on = m_screen->time_until_pos(vpos + 7, width * 0.9);
127 attotime period_off = m_screen->time_until_pos(vpos + 8, width * 0.9);
128
129 m_irq_on_timer->adjust(period_on);
130 m_irq_off_timer->adjust(period_off);
131 }
132 }
133
134
135
136 /*************************************
137 *
138 * Main refresh
139 *
140 *************************************/
141
screen_update_blstroid(screen_device & screen,bitmap_ind16 & bitmap,const rectangle & cliprect)142 uint32_t blstroid_state::screen_update_blstroid(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect)
143 {
144 // start drawing
145 m_mob->draw_async(cliprect);
146
147 /* draw the playfield */
148 m_playfield_tilemap->draw(screen, bitmap, cliprect, 0, 0);
149
150 /* draw and merge the MO */
151 bitmap_ind16 &mobitmap = m_mob->bitmap();
152 for (const sparse_dirty_rect *rect = m_mob->first_dirty_rect(cliprect); rect != nullptr; rect = rect->next())
153 for (int y = rect->top(); y <= rect->bottom(); y++)
154 {
155 uint16_t const *const mo = &mobitmap.pix(y);
156 uint16_t *const pf = &bitmap.pix(y);
157 for (int x = rect->left(); x <= rect->right(); x++)
158 if (mo[x] != 0xffff)
159 {
160 /* verified via schematics
161
162 priority address = HPPPMMMM
163 */
164 int const priaddr = ((pf[x] & 8) << 4) | (pf[x] & 0x70) | ((mo[x] & 0xf0) >> 4);
165 if (m_priorityram[priaddr] & 1)
166 pf[x] = mo[x];
167 }
168 }
169 return 0;
170 }
171