trunk/src/emu/video/i8244.c
| r0 | r20209 | |
| 1 | /*************************************************************************** |
| 2 | |
| 3 | i8244.c |
| 4 | |
| 5 | Intel 8244 (NTSC)/8245 (PAL) Graphics and sound chip |
| 6 | |
| 7 | |
| 8 | ***************************************************************************/ |
| 9 | |
| 10 | #include "emu.h" |
| 11 | #include "i8244.h" |
| 12 | |
| 13 | |
| 14 | // device type definition |
| 15 | const device_type I8244 = &device_creator<i8244_device>; |
| 16 | const device_type I8245 = &device_creator<i8245_device>; |
| 17 | |
| 18 | |
| 19 | static const UINT8 c_shape[0x40 * 8]={ |
| 20 | 0x7C,0xC6,0xC6,0xC6,0xC6,0xC6,0x7C,0x00, // 0 |
| 21 | 0x18,0x38,0x18,0x18,0x18,0x18,0x3C,0x00, |
| 22 | 0x3C,0x66,0x0C,0x18,0x30,0x60,0x7E,0x00, |
| 23 | 0x7C,0xC6,0x06,0x3C,0x06,0xC6,0x7C,0x00, |
| 24 | 0xCC,0xCC,0xCC,0xFE,0x0C,0x0C,0x0C,0x00, |
| 25 | 0xFE,0xC0,0xC0,0x7C,0x06,0xC6,0x7C,0x00, |
| 26 | 0x7C,0xC6,0xC0,0xFC,0xC6,0xC6,0x7C,0x00, |
| 27 | 0xFE,0x06,0x0C,0x18,0x30,0x60,0xC0,0x00, |
| 28 | 0x7C,0xC6,0xC6,0x7C,0xC6,0xC6,0x7C,0x00, |
| 29 | 0x7C,0xC6,0xC6,0x7E,0x06,0xC6,0x7C,0x00, |
| 30 | 0x00,0x18,0x18,0x00,0x18,0x18,0x00,0x00, |
| 31 | 0x18,0x7E,0x58,0x7E,0x1A,0x7E,0x18,0x00, |
| 32 | 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, |
| 33 | 0x3C,0x66,0x0C,0x18,0x18,0x00,0x18,0x00, |
| 34 | 0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xFE,0x00, |
| 35 | 0xFC,0xC6,0xC6,0xFC,0xC0,0xC0,0xC0,0x00, |
| 36 | 0x00,0x18,0x18,0x7E,0x18,0x18,0x00,0x00, |
| 37 | 0xC6,0xC6,0xC6,0xD6,0xFE,0xEE,0xC6,0x00, |
| 38 | 0xFE,0xC0,0xC0,0xF8,0xC0,0xC0,0xFE,0x00, |
| 39 | 0xFC,0xC6,0xC6,0xFC,0xD8,0xCC,0xC6,0x00, |
| 40 | 0x7E,0x18,0x18,0x18,0x18,0x18,0x18,0x00, |
| 41 | 0xC6,0xC6,0xC6,0xC6,0xC6,0xC6,0x7C,0x00, |
| 42 | 0x3C,0x18,0x18,0x18,0x18,0x18,0x3C,0x00, |
| 43 | 0x7C,0xC6,0xC6,0xC6,0xC6,0xC6,0x7C,0x00, |
| 44 | 0x7C,0xC6,0xC6,0xC6,0xDE,0xCC,0x76,0x00, |
| 45 | 0x7C,0xC6,0xC0,0x7C,0x06,0xC6,0x7C,0x00, |
| 46 | 0xFC,0xC6,0xC6,0xC6,0xC6,0xC6,0xFC,0x00, |
| 47 | 0xFE,0xC0,0xC0,0xF8,0xC0,0xC0,0xC0,0x00, |
| 48 | 0x7C,0xC6,0xC0,0xC0,0xCE,0xC6,0x7E,0x00, |
| 49 | 0xC6,0xC6,0xC6,0xFE,0xC6,0xC6,0xC6,0x00, |
| 50 | 0x06,0x06,0x06,0x06,0x06,0xC6,0x7C,0x00, |
| 51 | 0xC6,0xCC,0xD8,0xF0,0xD8,0xCC,0xC6,0x00, |
| 52 | 0x38,0x6C,0xC6,0xC6,0xFE,0xC6,0xC6,0x00, |
| 53 | 0x7E,0x06,0x0C,0x18,0x30,0x60,0x7E,0x00, |
| 54 | 0xC6,0xC6,0x6C,0x38,0x6C,0xC6,0xC6,0x00, |
| 55 | 0x7C,0xC6,0xC0,0xC0,0xC0,0xC6,0x7C,0x00, |
| 56 | 0xC6,0xC6,0xC6,0xC6,0xC6,0x6C,0x38,0x00, |
| 57 | 0xFC,0xC6,0xC6,0xFC,0xC6,0xC6,0xFC,0x00, |
| 58 | 0xC6,0xEE,0xFE,0xD6,0xC6,0xC6,0xC6,0x00, |
| 59 | 0x00,0x00,0x00,0x00,0x00,0x18,0x18,0x00, |
| 60 | 0x00,0x00,0x00,0x7E,0x00,0x00,0x00,0x00, |
| 61 | 0x00,0x66,0x3C,0x18,0x3C,0x66,0x00,0x00, |
| 62 | 0x00,0x18,0x00,0x7E,0x00,0x18,0x00,0x00, |
| 63 | 0x00,0x00,0x7E,0x00,0x7E,0x00,0x00,0x00, |
| 64 | 0x66,0x66,0x66,0x3C,0x18,0x18,0x18,0x00, |
| 65 | 0xC6,0xE6,0xF6,0xFE,0xDE,0xCE,0xC6,0x00, |
| 66 | 0x03,0x06,0x0C,0x18,0x30,0x60,0xC0,0x00, |
| 67 | 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0x00, |
| 68 | 0xCE,0xDB,0xDB,0xDB,0xDB,0xDB,0xCE,0x00, |
| 69 | 0x00,0x00,0x3C,0x7E,0x7E,0x7E,0x3C,0x00, |
| 70 | 0x1C,0x1C,0x18,0x1E,0x18,0x18,0x1C,0x00, |
| 71 | 0x1C,0x1C,0x18,0x1E,0x18,0x34,0x26,0x00, |
| 72 | 0x38,0x38,0x18,0x78,0x18,0x2C,0x64,0x00, |
| 73 | 0x38,0x38,0x18,0x78,0x18,0x18,0x38,0x00, |
| 74 | 0x00,0x18,0x0C,0xFE,0x0C,0x18,0x00,0x00, |
| 75 | 0x18,0x3C,0x7E,0xFF,0xFF,0x18,0x18,0x00, |
| 76 | 0x03,0x07,0x0F,0x1F,0x3F,0x7F,0xFF,0x00, |
| 77 | 0xC0,0xE0,0xF0,0xF8,0xFC,0xFE,0xFF,0x00, |
| 78 | 0x38,0x38,0x12,0xFE,0xB8,0x28,0x6C,0x00, |
| 79 | 0xC0,0x60,0x30,0x18,0x0C,0x06,0x03,0x00, |
| 80 | 0x00,0x00,0x0C,0x08,0x08,0x7F,0x3E,0x00, |
| 81 | 0x00,0x03,0x63,0xFF,0xFF,0x18,0x08,0x00, |
| 82 | 0x00,0x00,0x00,0x10,0x38,0xFF,0x7E,0x00 |
| 83 | }; |
| 84 | |
| 85 | |
| 86 | // Background and grid information is stored in RGB format |
| 87 | // while the character and sprite colors are stored in BGR |
| 88 | // format. |
| 89 | static const UINT8 bgr2rgb[8] = |
| 90 | { |
| 91 | 0x00, 0x04, 0x02, 0x06, 0x01, 0x05, 0x03, 0x07 |
| 92 | }; |
| 93 | |
| 94 | |
| 95 | //------------------------------------------------- |
| 96 | // i8243_device - constructor |
| 97 | //------------------------------------------------- |
| 98 | |
| 99 | i8244_device::i8244_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) |
| 100 | : device_t(mconfig, I8244, "I8244", tag, owner, clock) |
| 101 | , device_sound_interface(mconfig, *this) |
| 102 | , m_irq_func(*this) |
| 103 | , m_postprocess_func(*this) |
| 104 | , m_screen_tag(NULL) |
| 105 | , m_screen(NULL) |
| 106 | , m_start_vpos(START_Y) |
| 107 | , m_start_vblank(START_Y + SCREEN_HEIGHT) |
| 108 | , m_screen_lines(LINES) |
| 109 | { |
| 110 | } |
| 111 | |
| 112 | |
| 113 | i8244_device::i8244_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, int lines) |
| 114 | : device_t(mconfig, type, name, tag, owner, clock) |
| 115 | , device_sound_interface(mconfig, *this) |
| 116 | , m_irq_func(*this) |
| 117 | , m_postprocess_func(*this) |
| 118 | , m_screen_tag(NULL) |
| 119 | , m_screen(NULL) |
| 120 | , m_start_vpos(START_Y) |
| 121 | , m_start_vblank(START_Y + SCREEN_HEIGHT) |
| 122 | , m_screen_lines(lines) |
| 123 | { |
| 124 | } |
| 125 | |
| 126 | |
| 127 | i8245_device::i8245_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) |
| 128 | : i8244_device(mconfig, I8245, "I8245", tag, owner, clock, i8245_device::LINES) |
| 129 | { |
| 130 | } |
| 131 | |
| 132 | |
| 133 | //------------------------------------------------- |
| 134 | // device_start - device-specific startup |
| 135 | //------------------------------------------------- |
| 136 | |
| 137 | void i8244_device::device_start() |
| 138 | { |
| 139 | assert( m_screen_tag != NULL ); |
| 140 | m_screen = machine().device<screen_device>(m_screen_tag); |
| 141 | assert( m_screen != NULL ); |
| 142 | |
| 143 | // Let the screen create our temporary bitmap with the screen's dimensions |
| 144 | m_screen->register_screen_bitmap(m_tmp_bitmap); |
| 145 | |
| 146 | m_line_timer = timer_alloc(TIMER_LINE); |
| 147 | m_line_timer->adjust( m_screen->time_until_pos(1, START_ACTIVE_SCAN ), 0, m_screen->scan_period() ); |
| 148 | |
| 149 | m_hblank_timer = timer_alloc(TIMER_HBLANK); |
| 150 | m_hblank_timer->adjust( m_screen->time_until_pos(1, END_ACTIVE_SCAN + 18 ), 0, m_screen->scan_period() ); |
| 151 | |
| 152 | m_irq_func.resolve_safe(); |
| 153 | m_postprocess_func.resolve_safe(); |
| 154 | |
| 155 | // allocate a stream |
| 156 | m_stream = stream_alloc( 0, 1, clock()/(LINE_CLOCKS*4) ); |
| 157 | |
| 158 | // register our state |
| 159 | save_pointer(NAME(m_vdc.reg), 0x100); |
| 160 | save_item(NAME(m_sh_count)); |
| 161 | save_item(NAME(m_x_beam_pos)); |
| 162 | save_item(NAME(m_y_beam_pos)); |
| 163 | save_item(NAME(m_control_status)); |
| 164 | save_item(NAME(m_collision_status)); |
| 165 | save_item(NAME(m_iff)); |
| 166 | } |
| 167 | |
| 168 | |
| 169 | //------------------------------------------------- |
| 170 | // device_reset - device-specific reset |
| 171 | //------------------------------------------------- |
| 172 | |
| 173 | void i8244_device::device_reset() |
| 174 | { |
| 175 | memset(m_vdc.reg, 0, 0x100); |
| 176 | |
| 177 | m_sh_count = 0; |
| 178 | m_x_beam_pos = 0; |
| 179 | m_y_beam_pos = 0; |
| 180 | m_control_status = 0; |
| 181 | m_collision_status = 0; |
| 182 | m_iff = 0; |
| 183 | } |
| 184 | |
| 185 | |
| 186 | void i8244_device::palette_init() |
| 187 | { |
| 188 | static const UINT8 i8244_colors[3*16] = |
| 189 | { |
| 190 | 0x00, 0x00, 0x00, // i r g b |
| 191 | 0x00, 0x00, 0xAA, // i r g B |
| 192 | 0x00, 0xAA, 0x00, // i r G b |
| 193 | 0x00, 0xAA, 0xAA, // i r G B |
| 194 | 0xAA, 0x00, 0x00, // i R g b |
| 195 | 0xAA, 0x00, 0xAA, // i R g B |
| 196 | 0xAA, 0xAA, 0x00, // i R G b |
| 197 | 0xAA, 0xAA, 0xAA, // i R G B |
| 198 | 0x55, 0x55, 0x55, // I r g b |
| 199 | 0x55, 0x55, 0xFF, // I r g B |
| 200 | 0x55, 0xFF, 0x55, // I r G b |
| 201 | 0x55, 0xFF, 0xFF, // I r G B |
| 202 | 0xFF, 0x55, 0x55, // I R g b |
| 203 | 0xFF, 0x55, 0xFF, // I R g B |
| 204 | 0xFF, 0xFF, 0x55, // I R G b |
| 205 | 0xFF, 0xFF, 0xFF, // I R G B |
| 206 | }; |
| 207 | |
| 208 | for ( int i = 0; i < 16; i++ ) |
| 209 | { |
| 210 | palette_set_color_rgb( machine(), i, i8244_colors[i*3], i8244_colors[i*3+1], i8244_colors[i*3+2] ); |
| 211 | } |
| 212 | } |
| 213 | |
| 214 | |
| 215 | void i8244_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) |
| 216 | { |
| 217 | int vpos = m_screen->vpos(); |
| 218 | |
| 219 | switch ( id ) |
| 220 | { |
| 221 | case TIMER_LINE: |
| 222 | // handle i824x line timer |
| 223 | render_scanline(vpos); |
| 224 | break; |
| 225 | |
| 226 | case TIMER_HBLANK: |
| 227 | // handle i824x HBlank timer |
| 228 | if ( vpos < m_start_vpos - 1 ) |
| 229 | { |
| 230 | return; |
| 231 | } |
| 232 | |
| 233 | if ( vpos < m_start_vblank - 1 ) |
| 234 | { |
| 235 | m_control_status |= 0x01; |
| 236 | } |
| 237 | break; |
| 238 | } |
| 239 | } |
| 240 | |
| 241 | |
| 242 | int i8244_device::get_y_beam() |
| 243 | { |
| 244 | int y = m_screen->vpos() - m_start_vpos; |
| 245 | |
| 246 | // The Y register becomes 0 only when the VBlank signal is turned off! |
| 247 | if ( y < 0 || ( y == 0 && m_screen->hpos() < 366+42 ) ) |
| 248 | { |
| 249 | y += m_screen_lines; |
| 250 | } |
| 251 | |
| 252 | return y; |
| 253 | } |
| 254 | |
| 255 | |
| 256 | int i8244_device::get_x_beam() |
| 257 | { |
| 258 | int x = m_screen->hpos() - START_ACTIVE_SCAN; |
| 259 | |
| 260 | if ( x < 0 ) |
| 261 | { |
| 262 | x += LINE_CLOCKS; |
| 263 | } |
| 264 | |
| 265 | return x >> 1; |
| 266 | } |
| 267 | |
| 268 | |
| 269 | offs_t i8244_device::fix_register_mirrors( offs_t offset ) |
| 270 | { |
| 271 | // registers $40,$41 are mirrored at $44,$45, $48,$49, and $4C,$4D |
| 272 | if ( ( offset & 0xF2 ) == 0x40 ) |
| 273 | { |
| 274 | offset &= ~0x0C; |
| 275 | } |
| 276 | |
| 277 | // registers $A0-$AF are mirrored at $B0-$BF |
| 278 | if ( ( offset & 0xF0 ) == 0xB0 ) |
| 279 | { |
| 280 | offset &= ~0x10; |
| 281 | } |
| 282 | |
| 283 | return offset; |
| 284 | } |
| 285 | |
| 286 | |
| 287 | READ8_MEMBER(i8244_device::read) |
| 288 | { |
| 289 | UINT8 data = 0; |
| 290 | |
| 291 | offset = fix_register_mirrors( offset ); |
| 292 | |
| 293 | switch (offset) |
| 294 | { |
| 295 | case 0xa1: |
| 296 | data = m_control_status & 0xFE; |
| 297 | m_iff = 0; |
| 298 | m_irq_func(CLEAR_LINE); |
| 299 | m_control_status &= ~0x08; |
| 300 | if ( hblank() ) |
| 301 | { |
| 302 | data |= 1; |
| 303 | } |
| 304 | break; |
| 305 | |
| 306 | case 0xa2: |
| 307 | data = m_collision_status; |
| 308 | m_collision_status = 0; |
| 309 | break; |
| 310 | |
| 311 | case 0xa4: |
| 312 | if (m_vdc.s.control & VDC_CONTROL_REG_STROBE_XY) |
| 313 | { |
| 314 | m_y_beam_pos = get_y_beam(); |
| 315 | } |
| 316 | data = m_y_beam_pos; |
| 317 | break; |
| 318 | |
| 319 | |
| 320 | case 0xa5: |
| 321 | if ((m_vdc.s.control & VDC_CONTROL_REG_STROBE_XY)) |
| 322 | { |
| 323 | m_x_beam_pos = get_x_beam(); |
| 324 | } |
| 325 | data = m_x_beam_pos; |
| 326 | break; |
| 327 | |
| 328 | default: |
| 329 | data = m_vdc.reg[offset]; |
| 330 | break; |
| 331 | } |
| 332 | |
| 333 | return data; |
| 334 | } |
| 335 | |
| 336 | |
| 337 | WRITE8_MEMBER(i8244_device::write) |
| 338 | { |
| 339 | offset = fix_register_mirrors( offset ); |
| 340 | |
| 341 | /* Update the sound */ |
| 342 | if( offset >= 0xa7 && offset <= 0xaa ) |
| 343 | { |
| 344 | m_stream->update(); |
| 345 | } |
| 346 | |
| 347 | if (offset == 0xa0) |
| 348 | { |
| 349 | if ( ( m_vdc.s.control & VDC_CONTROL_REG_STROBE_XY ) |
| 350 | && !(data & VDC_CONTROL_REG_STROBE_XY)) |
| 351 | { |
| 352 | /* Toggling strobe bit, tuck away values */ |
| 353 | m_x_beam_pos = get_x_beam(); |
| 354 | m_y_beam_pos = get_y_beam(); |
| 355 | } |
| 356 | } |
| 357 | |
| 358 | m_vdc.reg[offset] = data; |
| 359 | } |
| 360 | |
| 361 | |
| 362 | READ_LINE_MEMBER(i8244_device::vblank) |
| 363 | { |
| 364 | if ( m_screen->vpos() > m_start_vpos && m_screen->vpos() < m_start_vblank ) |
| 365 | { |
| 366 | return 0; |
| 367 | } |
| 368 | return 1; |
| 369 | } |
| 370 | |
| 371 | |
| 372 | READ_LINE_MEMBER(i8244_device::hblank) |
| 373 | { |
| 374 | int hpos = m_screen->hpos(); |
| 375 | int vpos = m_screen->vpos(); |
| 376 | |
| 377 | if ( hpos >= START_ACTIVE_SCAN && hpos < END_ACTIVE_SCAN ) |
| 378 | { |
| 379 | return 0; |
| 380 | } |
| 381 | |
| 382 | // Before active area? |
| 383 | if ( vpos < m_start_vpos - 1 ) |
| 384 | { |
| 385 | return 0; |
| 386 | } |
| 387 | |
| 388 | // During active area? |
| 389 | if ( vpos < m_start_vblank - 1 ) |
| 390 | { |
| 391 | return 1; |
| 392 | } |
| 393 | |
| 394 | // After active area |
| 395 | return 0; |
| 396 | } |
| 397 | |
| 398 | |
| 399 | void i8244_device::render_scanline(int vpos) |
| 400 | { |
| 401 | // Some local constants for this method |
| 402 | //static const UINT8 COLLISION_SPRITE_0 = 0x01; |
| 403 | //static const UINT8 COLLISION_SPRITE_1 = 0x02; |
| 404 | //static const UINT8 COLLISION_SPRITE_2 = 0x04; |
| 405 | //static const UINT8 COLLISION_SPRITE_3 = 0x08; |
| 406 | static const UINT8 COLLISION_VERTICAL_GRID = 0x10; |
| 407 | static const UINT8 COLLISION_HORIZ_GRID_DOTS = 0x20; |
| 408 | //static const UINT8 COLLISION_EXTERNAL_UNUSED = 0x40; |
| 409 | static const UINT8 COLLISION_CHARACTERS = 0x80; |
| 410 | |
| 411 | UINT8 collision_map[160]; |
| 412 | |
| 413 | |
| 414 | if ( vpos == m_start_vpos ) |
| 415 | { |
| 416 | m_control_status &= ~0x08; |
| 417 | } |
| 418 | |
| 419 | if ( m_start_vpos < vpos && vpos < m_start_vblank ) |
| 420 | { |
| 421 | rectangle rect; |
| 422 | int scanline = vpos - m_start_vpos; |
| 423 | |
| 424 | m_control_status &= ~ 0x01; |
| 425 | |
| 426 | /* Draw a line */ |
| 427 | rect.set(START_ACTIVE_SCAN, END_ACTIVE_SCAN - 1, vpos, vpos); |
| 428 | m_tmp_bitmap.fill( (m_vdc.s.color >> 3) & 0x7, rect ); |
| 429 | |
| 430 | /* Clear collision map */ |
| 431 | memset( collision_map, 0, sizeof( collision_map ) ); |
| 432 | |
| 433 | /* Display grid if enabled */ |
| 434 | if ( m_vdc.s.control & 0x08 ) |
| 435 | { |
| 436 | UINT16 color = ( m_vdc.s.color & 7 ) | ( ( m_vdc.s.color >> 3 ) & 0x08 ); |
| 437 | int x_grid_offset = 8; |
| 438 | int y_grid_offset = 24; |
| 439 | int width = 16; |
| 440 | int height = 24; |
| 441 | int w = ( m_vdc.s.control & 0x80 ) ? width : 2; |
| 442 | |
| 443 | /* Draw horizontal part of grid */ |
| 444 | for ( int j = 1, y = 0; y < 9; y++, j <<= 1 ) |
| 445 | { |
| 446 | if ( y_grid_offset + y * height <= scanline && scanline < y_grid_offset + y * height + 3 ) |
| 447 | { |
| 448 | for ( int i = 0; i < 9; i++ ) |
| 449 | { |
| 450 | if ( ( m_vdc.s.hgrid[0][i] & j ) || ( m_vdc.s.hgrid[1][i] & ( j >> 8 ) ) ) |
| 451 | { |
| 452 | for ( int k = 0; k < width + 2; k++ ) |
| 453 | { |
| 454 | int px = x_grid_offset + i * width + k; |
| 455 | collision_map[ px ] |= COLLISION_HORIZ_GRID_DOTS; |
| 456 | m_tmp_bitmap.pix16( vpos, START_ACTIVE_SCAN + 10 + 2 * px ) = color; |
| 457 | m_tmp_bitmap.pix16( vpos, START_ACTIVE_SCAN + 10 + 2 * px + 1 ) = color; |
| 458 | } |
| 459 | } |
| 460 | } |
| 461 | } |
| 462 | } |
| 463 | |
| 464 | /* Draw vertical part of grid */ |
| 465 | for( int j = 1, y = 0; y < 8; y++, j <<= 1 ) |
| 466 | { |
| 467 | if ( y_grid_offset + y * height <= scanline && scanline < y_grid_offset + ( y + 1 ) * height ) |
| 468 | { |
| 469 | for ( int i = 0; i < 10; i++ ) |
| 470 | { |
| 471 | if ( m_vdc.s.vgrid[i] & j ) |
| 472 | { |
| 473 | for ( int k = 0; k < w; k++ ) |
| 474 | { |
| 475 | int px = x_grid_offset + i * width + k; |
| 476 | |
| 477 | /* Check if we collide with an already drawn source object */ |
| 478 | if ( collision_map[ px ] & m_vdc.s.collision ) |
| 479 | { |
| 480 | m_collision_status |= COLLISION_VERTICAL_GRID; |
| 481 | } |
| 482 | /* Check if an already drawn object would collide with us */ |
| 483 | if ( COLLISION_VERTICAL_GRID & m_vdc.s.collision && collision_map[ px ] ) |
| 484 | { |
| 485 | m_collision_status |= collision_map[ px ]; |
| 486 | } |
| 487 | collision_map[ px ] |= COLLISION_VERTICAL_GRID; |
| 488 | m_tmp_bitmap.pix16( vpos, START_ACTIVE_SCAN + 10 + 2 * px ) = color; |
| 489 | m_tmp_bitmap.pix16( vpos, START_ACTIVE_SCAN + 10 + 2 * px + 1 ) = color; |
| 490 | } |
| 491 | } |
| 492 | } |
| 493 | } |
| 494 | } |
| 495 | } |
| 496 | |
| 497 | /* Display objects if enabled */ |
| 498 | if ( m_vdc.s.control & 0x20 ) |
| 499 | { |
| 500 | /* Regular foreground objects */ |
| 501 | for ( int i = 0; i < ARRAY_LENGTH( m_vdc.s.foreground ); i++ ) |
| 502 | { |
| 503 | int y = m_vdc.s.foreground[i].y & 0xFE; |
| 504 | int height = 8 - ( ( ( y >> 1 ) + m_vdc.s.foreground[i].ptr ) & 7 ); |
| 505 | |
| 506 | if ( y >= 0x0E && y <= scanline && scanline < y + height * 2 ) |
| 507 | { |
| 508 | UINT16 color = 8 + bgr2rgb[ ( ( m_vdc.s.foreground[i].color >> 1 ) & 0x07 ) ]; |
| 509 | int offset = ( m_vdc.s.foreground[i].ptr | ( ( m_vdc.s.foreground[i].color & 0x01 ) << 8 ) ) + ( y >> 1 ) + ( ( scanline - y ) >> 1 ); |
| 510 | UINT8 chr = c_shape[ offset & 0x1FF ]; |
| 511 | int x = m_vdc.s.foreground[i].x; |
| 512 | |
| 513 | for ( UINT8 m = 0x80; m > 0; m >>= 1, x++ ) |
| 514 | { |
| 515 | if ( chr & m ) |
| 516 | { |
| 517 | if ( x >= 0 && x < 160 ) |
| 518 | { |
| 519 | /* Check if we collide with an already drawn source object */ |
| 520 | if ( collision_map[ x ] & m_vdc.s.collision ) |
| 521 | { |
| 522 | m_collision_status |= COLLISION_CHARACTERS; |
| 523 | } |
| 524 | /* Check if an already drawn object would collide with us */ |
| 525 | if ( COLLISION_CHARACTERS & m_vdc.s.collision && collision_map[ x ] ) |
| 526 | { |
| 527 | m_collision_status |= collision_map[ x ]; |
| 528 | } |
| 529 | collision_map[ x ] |= COLLISION_CHARACTERS; |
| 530 | m_tmp_bitmap.pix16( vpos, START_ACTIVE_SCAN + 10 + 2 * x ) = color; |
| 531 | m_tmp_bitmap.pix16( vpos, START_ACTIVE_SCAN + 10 + 2 * x + 1 ) = color; |
| 532 | } |
| 533 | } |
| 534 | } |
| 535 | } |
| 536 | } |
| 537 | |
| 538 | /* Quad objects */ |
| 539 | for ( int i = 0; i < ARRAY_LENGTH( m_vdc.s.quad ); i++ ) |
| 540 | { |
| 541 | int y = m_vdc.s.quad[i].single[0].y; |
| 542 | int height = 8; |
| 543 | |
| 544 | if ( y <= scanline && scanline < y + height * 2 ) |
| 545 | { |
| 546 | int x = m_vdc.s.quad[i].single[0].x; |
| 547 | |
| 548 | // Charaecter height is always determined by the height of the 4th character |
| 549 | int char_height = 8 - ( ( ( y >> 1 ) + m_vdc.s.quad[i].single[3].ptr ) & 7 ); |
| 550 | |
| 551 | for ( int j = 0; j < ARRAY_LENGTH( m_vdc.s.quad[0].single ); j++, x += 8 ) |
| 552 | { |
| 553 | if ( y <= scanline && scanline < y + char_height * 2 ) |
| 554 | { |
| 555 | |
| 556 | UINT16 color = 8 + bgr2rgb[ ( ( m_vdc.s.quad[i].single[j].color >> 1 ) & 0x07 ) ]; |
| 557 | int offset = ( m_vdc.s.quad[i].single[j].ptr | ( ( m_vdc.s.quad[i].single[j].color & 0x01 ) << 8 ) ) + ( y >> 1 ) + ( ( scanline - y ) >> 1 ); |
| 558 | UINT8 chr = c_shape[ offset & 0x1FF ]; |
| 559 | |
| 560 | for ( UINT8 m = 0x80; m > 0; m >>= 1, x++ ) |
| 561 | { |
| 562 | if ( chr & m ) |
| 563 | { |
| 564 | if ( x >= 0 && x < 160 ) |
| 565 | { |
| 566 | /* Check if we collide with an already drawn source object */ |
| 567 | if ( collision_map[ x ] & m_vdc.s.collision ) |
| 568 | { |
| 569 | m_collision_status |= COLLISION_CHARACTERS; |
| 570 | } |
| 571 | /* Check if an already drawn object would collide with us */ |
| 572 | if ( COLLISION_CHARACTERS & m_vdc.s.collision && collision_map[ x ] ) |
| 573 | { |
| 574 | m_collision_status |= collision_map[ x ]; |
| 575 | } |
| 576 | collision_map[ x ] |= COLLISION_CHARACTERS; |
| 577 | m_tmp_bitmap.pix16( vpos, START_ACTIVE_SCAN + 10 + 2 * x ) = color; |
| 578 | m_tmp_bitmap.pix16( vpos, START_ACTIVE_SCAN + 10 + 2 * x + 1 ) = color; |
| 579 | } |
| 580 | } |
| 581 | } |
| 582 | } |
| 583 | else |
| 584 | { |
| 585 | x += 8; |
| 586 | } |
| 587 | } |
| 588 | } |
| 589 | } |
| 590 | |
| 591 | /* Sprites */ |
| 592 | for ( int i = 0; i < ARRAY_LENGTH( m_vdc.s.sprites ); i++ ) |
| 593 | { |
| 594 | int y = m_vdc.s.sprites[i].y; |
| 595 | int height = 8; |
| 596 | |
| 597 | if ( m_vdc.s.sprites[i].color & 4 ) |
| 598 | { |
| 599 | /* Zoomed sprite */ |
| 600 | if ( y <= scanline && scanline < y + height * 4 ) |
| 601 | { |
| 602 | UINT16 color = 8 + bgr2rgb[ ( ( m_vdc.s.sprites[i].color >> 3 ) & 0x07 ) ]; |
| 603 | UINT8 chr = m_vdc.s.shape[i][ ( ( scanline - y ) >> 2 ) ]; |
| 604 | int x = m_vdc.s.sprites[i].x; |
| 605 | int x_shift = 0; |
| 606 | |
| 607 | switch ( m_vdc.s.sprites[i].color & 0x03 ) |
| 608 | { |
| 609 | case 1: // Xg attribute set |
| 610 | x_shift = 2; |
| 611 | break; |
| 612 | case 2: // S attribute set |
| 613 | x_shift = ( ( ( scanline - y ) >> 1 ) & 0x01 ) ^ 0x01; |
| 614 | break; |
| 615 | case 3: // Xg and S attributes set |
| 616 | x_shift = ( ( scanline - y ) >> 1 ) & 0x01; |
| 617 | break; |
| 618 | } |
| 619 | x_shift <<= 1; |
| 620 | |
| 621 | for ( UINT8 m = 0x01; m > 0; m <<= 1, x += 2 ) |
| 622 | { |
| 623 | if ( chr & m ) |
| 624 | { |
| 625 | if ( x >= 0 && x < 160 ) |
| 626 | { |
| 627 | /* Check if we collide with an already drawn source object */ |
| 628 | if ( collision_map[ x ] & m_vdc.s.collision ) |
| 629 | { |
| 630 | m_collision_status |= ( 1 << i ); |
| 631 | } |
| 632 | /* Check if an already drawn object would collide with us */ |
| 633 | if ( ( 1 << i ) & m_vdc.s.collision && collision_map[ x ] ) |
| 634 | { |
| 635 | m_collision_status |= collision_map[ x ]; |
| 636 | } |
| 637 | collision_map[ x ] |= ( 1 << i ); |
| 638 | m_tmp_bitmap.pix16( vpos, START_ACTIVE_SCAN + 10 + x_shift + 2 * x ) = color; |
| 639 | m_tmp_bitmap.pix16( vpos, START_ACTIVE_SCAN + 10 + x_shift + 2 * x + 1 ) = color; |
| 640 | } |
| 641 | if ( x >= -1 && x < 159 ) |
| 642 | { |
| 643 | /* Check if we collide with an already drawn source object */ |
| 644 | if ( collision_map[ x ] & m_vdc.s.collision ) |
| 645 | { |
| 646 | m_collision_status |= ( 1 << i ); |
| 647 | } |
| 648 | /* Check if an already drawn object would collide with us */ |
| 649 | if ( ( 1 << i ) & m_vdc.s.collision && collision_map[ x ] ) |
| 650 | { |
| 651 | m_collision_status |= collision_map[ x ]; |
| 652 | } |
| 653 | collision_map[ x ] |= ( 1 << i ); |
| 654 | m_tmp_bitmap.pix16( vpos, START_ACTIVE_SCAN + 10 + x_shift + 2 * x + 2 ) = color; |
| 655 | m_tmp_bitmap.pix16( vpos, START_ACTIVE_SCAN + 10 + x_shift + 2 * x + 3 ) = color; |
| 656 | } |
| 657 | } |
| 658 | } |
| 659 | } |
| 660 | } |
| 661 | else |
| 662 | { |
| 663 | /* Regular sprite */ |
| 664 | if ( y <= scanline && scanline < y + height * 2 ) |
| 665 | { |
| 666 | UINT16 color = 8 + bgr2rgb[ ( ( m_vdc.s.sprites[i].color >> 3 ) & 0x07 ) ]; |
| 667 | UINT8 chr = m_vdc.s.shape[i][ ( ( scanline - y ) >> 1 ) ]; |
| 668 | int x = m_vdc.s.sprites[i].x; |
| 669 | int x_shift = 0; |
| 670 | |
| 671 | switch ( m_vdc.s.sprites[i].color & 0x03 ) |
| 672 | { |
| 673 | case 1: // Xg attribute set |
| 674 | x_shift = 1; |
| 675 | break; |
| 676 | case 2: // S attribute set |
| 677 | x_shift = ( ( ( scanline - y ) >> 1 ) & 0x01 ) ^ 0x01; |
| 678 | break; |
| 679 | case 3: // Xg and S attributes set |
| 680 | x_shift = ( ( scanline - y ) >> 1 ) & 0x01; |
| 681 | break; |
| 682 | } |
| 683 | |
| 684 | for ( UINT8 m = 0x01; m > 0; m <<= 1, x++ ) |
| 685 | { |
| 686 | if ( chr & m ) |
| 687 | { |
| 688 | if ( x >= 0 && x < 160 ) |
| 689 | { |
| 690 | /* Check if we collide with an already drawn source object */ |
| 691 | if ( collision_map[ x ] & m_vdc.s.collision ) |
| 692 | { |
| 693 | m_collision_status |= ( 1 << i ); |
| 694 | } |
| 695 | /* Check if an already drawn object would collide with us */ |
| 696 | if ( ( 1 << i ) & m_vdc.s.collision && collision_map[ x ] ) |
| 697 | { |
| 698 | m_collision_status |= collision_map[ x ]; |
| 699 | } |
| 700 | collision_map[ x ] |= ( 1 << i ); |
| 701 | m_tmp_bitmap.pix16( vpos, START_ACTIVE_SCAN + 10 + x_shift + 2 * x ) = color; |
| 702 | m_tmp_bitmap.pix16( vpos, START_ACTIVE_SCAN + 10 + x_shift + 2 * x + 1 ) = color; |
| 703 | } |
| 704 | } |
| 705 | } |
| 706 | } |
| 707 | } |
| 708 | } |
| 709 | } |
| 710 | } |
| 711 | |
| 712 | // Allow driver to do additional processing |
| 713 | m_postprocess_func( vpos ); |
| 714 | |
| 715 | /* Check for start of VBlank */ |
| 716 | if ( vpos == m_start_vblank ) |
| 717 | { |
| 718 | m_control_status |= 0x08; |
| 719 | if ( ! m_iff ) |
| 720 | { |
| 721 | m_iff = 1; |
| 722 | m_irq_func(ASSERT_LINE); |
| 723 | } |
| 724 | } |
| 725 | } |
| 726 | |
| 727 | |
| 728 | void i8244_device::sound_stream_update(sound_stream &stream, stream_sample_t **inputs, stream_sample_t **outputs, int samples) |
| 729 | { |
| 730 | UINT32 old_signal, signal; |
| 731 | int ii; |
| 732 | int period; |
| 733 | stream_sample_t *buffer = outputs[0]; |
| 734 | |
| 735 | /* Generate the signal */ |
| 736 | old_signal = signal = m_vdc.s.shift3 | (m_vdc.s.shift2 << 8) | (m_vdc.s.shift1 << 16); |
| 737 | |
| 738 | if( m_vdc.s.sound & 0x80 ) /* Sound is enabled */ |
| 739 | { |
| 740 | for( ii = 0; ii < samples; ii++, buffer++ ) |
| 741 | { |
| 742 | *buffer = 0; |
| 743 | *buffer = signal & 0x1; |
| 744 | period = (m_vdc.s.sound & 0x20) ? 1 : 4; |
| 745 | if( ++m_sh_count >= period ) |
| 746 | { |
| 747 | m_sh_count = 0; |
| 748 | signal >>= 1; |
| 749 | /* Loop sound */ |
| 750 | signal |= *buffer << 23; |
| 751 | /* Check if noise should be applied */ |
| 752 | if ( m_vdc.s.sound & 0x10 ) |
| 753 | { |
| 754 | /* Noise tap is on bits 0 and 5 and fed back to bits 15 (and 23!) */ |
| 755 | UINT32 new_bit = ( ( old_signal ) ^ ( old_signal >> 5 ) ) & 0x01; |
| 756 | signal = ( old_signal & 0xFF0000 ) | ( ( old_signal & 0xFFFF ) >> 1 ) | ( new_bit << 15 ) | ( new_bit << 23 ); |
| 757 | } |
| 758 | m_vdc.s.shift3 = signal & 0xFF; |
| 759 | m_vdc.s.shift2 = ( signal >> 8 ) & 0xFF; |
| 760 | m_vdc.s.shift1 = ( signal >> 16 ) & 0xFF; |
| 761 | old_signal = signal; |
| 762 | } |
| 763 | |
| 764 | /* Throw an interrupt if enabled */ |
| 765 | if( m_vdc.s.control & 0x4 ) |
| 766 | { |
| 767 | // This feature does not seem to be finished/enabled in hardware! |
| 768 | } |
| 769 | |
| 770 | /* Adjust volume */ |
| 771 | *buffer *= m_vdc.s.sound & 0xf; |
| 772 | /* Pump the volume up */ |
| 773 | *buffer <<= 10; |
| 774 | } |
| 775 | } |
| 776 | else |
| 777 | { |
| 778 | /* Sound disabled, so clear the buffer */ |
| 779 | for( ii = 0; ii < samples; ii++, buffer++ ) |
| 780 | { |
| 781 | *buffer = 0; |
| 782 | } |
| 783 | } |
| 784 | } |
| 785 | |
| 786 | |
| 787 | UINT32 i8244_device::screen_update(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect) |
| 788 | { |
| 789 | copybitmap( bitmap, m_tmp_bitmap, 0, 0, 0, 0, cliprect ); |
| 790 | |
| 791 | return 0; |
| 792 | } |
| 793 | |
| 794 | |
trunk/src/mess/video/odyssey2.c
| r20208 | r20209 | |
| 34 | 34 | const UINT8 odyssey2_colors[] = |
| 35 | 35 | { |
| 36 | 36 | /* Background,Grid Dim */ |
| 37 | | 0x00,0x00,0x00, |
| 38 | | 0x00,0x00,0xFF, /* Blue */ |
| 39 | | 0x00,0x80,0x00, /* DK Green */ |
| 40 | | 0xff,0x9b,0x60, |
| 41 | | 0xCC,0x00,0x00, /* Red */ |
| 42 | | 0xa9,0x80,0xff, |
| 43 | | 0x82,0xfd,0xdb, |
| 44 | | 0xFF,0xFF,0xFF, |
| 37 | 0x00, 0x00, 0x00, // 0x00,0x00,0x00, // i r g b |
| 38 | 0x00, 0x00, 0xAA, // 0x00,0x00,0xFF, /* Blue */ // i r g B |
| 39 | 0x00, 0xAA, 0x00, // 0x00,0x80,0x00, /* DK Green */ // i r G b |
| 40 | 0x00, 0xAA, 0xAA, // 0xff,0x9b,0x60, // i r G B |
| 41 | 0xAA, 0x00, 0x00, // 0xCC,0x00,0x00, /* Red */ // i R g b |
| 42 | 0xAA, 0x00, 0xAA, // 0xa9,0x80,0xff, // i R g B |
| 43 | 0xAA, 0xAA, 0x00, // 0x82,0xfd,0xdb, // i R G b |
| 44 | 0xAA, 0xAA, 0xAA, // 0xFF,0xFF,0xFF, // i R G B |
| 45 | 45 | |
| 46 | 46 | /* Background,Grid Bright */ |
| 47 | | 0x80,0x80,0x80, |
| 48 | | 0x50,0xAE,0xFF, /* Blue */ |
| 49 | | 0x00,0xFF,0x00, /* Dk Green */ |
| 50 | | 0x82,0xfb,0xdb, /* Lt Grey */ |
| 51 | | 0xEC,0x02,0x60, /* Red */ |
| 52 | | 0xa9,0x80,0xff, /* Violet */ |
| 53 | | 0xff,0x9b,0x60, /* Orange */ |
| 54 | | 0xFF,0xFF,0xFF, |
| 47 | 0x55, 0x55, 0x55, // 0x80,0x80,0x80, // I r g b |
| 48 | 0x55, 0x55, 0xFF, // 0x50,0xAE,0xFF, /* Blue */ // I r g B |
| 49 | 0x55, 0xFF, 0x55, // 0x00,0xFF,0x00, /* Dk Green */ // I r G b |
| 50 | 0x55, 0xFF, 0xFF, // 0x82,0xfb,0xdb, /* Lt Grey */ // I r G B |
| 51 | 0xFF, 0x55, 0x55, // 0xEC,0x02,0x60, /* Red */ // I R g b |
| 52 | 0xFF, 0x55, 0xFF, // 0xa9,0x80,0xff, /* Violet */ // I R g B |
| 53 | 0xFF, 0xFF, 0x55, // 0xff,0x9b,0x60, /* Orange */ // I R G b |
| 54 | 0xFF, 0xFF, 0xFF, // 0xFF,0xFF,0xFF, // I R G B |
| 55 | 55 | |
| 56 | 56 | /* Character,Sprite colors */ |
| 57 | | 0x80,0x80,0x80, /* Dark Grey */ |
| 58 | | 0xFF,0x80,0x80, /* Red */ |
| 59 | | 0x00,0xC0,0x00, /* Green */ |
| 60 | | 0xff,0x9b,0x60, /* Orange */ |
| 61 | | 0x50,0xAE,0xFF, /* Blue */ |
| 62 | | 0xa9,0x80,0xff, /* Violet */ |
| 63 | | 0x82,0xfb,0xdb, /* Lt Grey */ |
| 64 | | 0xff,0xff,0xff, /* White */ |
| 57 | 0x80,0x80,0x80, /* Dark Grey */ // I r g b |
| 58 | 0xFF,0x80,0x80, /* Red */ // I R g b |
| 59 | 0x00,0xC0,0x00, /* Green */ // I r G b |
| 60 | 0xff,0x9b,0x60, /* Orange */ // I R G b |
| 61 | 0x50,0xAE,0xFF, /* Blue */ // I r g B |
| 62 | 0xa9,0x80,0xff, /* Violet */ // I R g B |
| 63 | 0x82,0xfb,0xdb, /* Lt Grey */ // I r G B |
| 64 | 0xff,0xff,0xff, /* White */ // I R G B |
| 65 | 65 | |
| 66 | 66 | /* EF9340/EF9341 colors */ |
| 67 | 67 | 0x00, 0x00, 0x00, |
| r20208 | r20209 | |
| 175 | 175 | break; |
| 176 | 176 | |
| 177 | 177 | case 0xa4: |
| 178 | | if (m_o2_vdc.s.control & VDC_CONTROL_REG_STROBE_XY) |
| 178 | if (m_o2_vdc.s.control & OLD_VDC_CONTROL_REG_STROBE_XY) |
| 179 | 179 | { |
| 180 | 180 | m_y_beam_pos = m_screen->vpos() - m_start_vpos; |
| 181 | 181 | } |
| r20208 | r20209 | |
| 187 | 187 | |
| 188 | 188 | case 0xa5: |
| 189 | 189 | |
| 190 | | if ((m_o2_vdc.s.control & VDC_CONTROL_REG_STROBE_XY)) |
| 190 | if ((m_o2_vdc.s.control & OLD_VDC_CONTROL_REG_STROBE_XY)) |
| 191 | 191 | { |
| 192 | 192 | m_x_beam_pos = m_screen->hpos(); |
| 193 | 193 | if ( m_x_beam_pos < I824X_START_ACTIVE_SCAN ) |
| r20208 | r20209 | |
| 219 | 219 | m_sh_channel->update(); |
| 220 | 220 | |
| 221 | 221 | if (offset == 0xa0) { |
| 222 | | if ( m_o2_vdc.s.control & VDC_CONTROL_REG_STROBE_XY |
| 223 | | && !(data & VDC_CONTROL_REG_STROBE_XY)) |
| 222 | if ( m_o2_vdc.s.control & OLD_VDC_CONTROL_REG_STROBE_XY |
| 223 | && !(data & OLD_VDC_CONTROL_REG_STROBE_XY)) |
| 224 | 224 | { |
| 225 | 225 | /* Toggling strobe bit, tuck away values */ |
| 226 | 226 | m_x_beam_pos = m_screen->hpos(); |
| r20208 | r20209 | |
| 243 | 243 | |
| 244 | 244 | WRITE8_MEMBER(odyssey2_state::lum_write) |
| 245 | 245 | { |
| 246 | | m_lum = data; |
| 246 | m_lum = ( data & 0x01 ) << 3; |
| 247 | 247 | } |
| 248 | 248 | |
| 249 | 249 | |
| 250 | WRITE16_MEMBER(odyssey2_state::scanline_postprocess) |
| 251 | { |
| 252 | int vpos = data; |
| 253 | bitmap_ind16 *bitmap = m_i8244->get_bitmap(); |
| 254 | |
| 255 | // apply external LUM setting |
| 256 | for ( int x = i8244_device::START_ACTIVE_SCAN; x < i8244_device::END_ACTIVE_SCAN; x++ ) |
| 257 | { |
| 258 | bitmap->pix16( vpos, x ) |= ( m_lum ^ 0x08 ); |
| 259 | } |
| 260 | } |
| 261 | |
| 262 | |
| 250 | 263 | READ8_MEMBER(odyssey2_state::t1_read) |
| 251 | 264 | { |
| 252 | 265 | if ( m_screen->vpos() > m_start_vpos && m_screen->vpos() < m_start_vblank ) |
| r20208 | r20209 | |
| 260 | 273 | } |
| 261 | 274 | |
| 262 | 275 | |
| 276 | READ8_MEMBER(odyssey2_state::t1_read_g7400) |
| 277 | { |
| 278 | if ( m_i8244->vblank() || m_i8244->hblank() ) |
| 279 | { |
| 280 | return 1; |
| 281 | } |
| 282 | return 0; |
| 283 | } |
| 284 | |
| 285 | |
| 263 | 286 | void odyssey2_state::i824x_scanline(int vpos) |
| 264 | 287 | { |
| 265 | 288 | UINT8 collision_map[160]; |
| r20208 | r20209 | |
| 647 | 670 | { |
| 648 | 671 | copybitmap( bitmap, m_tmp_bitmap, 0, 0, 0, 0, cliprect ); |
| 649 | 672 | |
| 673 | if ( m_i8244 ) |
| 674 | { |
| 675 | return m_i8244->screen_update(screen, bitmap, cliprect); |
| 676 | } |
| 650 | 677 | return 0; |
| 651 | 678 | } |
| 652 | 679 | |