diff options
-rw-r--r-- | src/devices/video/ef9340_1.cpp | 158 | ||||
-rw-r--r-- | src/devices/video/ef9340_1.h | 36 | ||||
-rw-r--r-- | src/devices/video/i8244.cpp | 128 | ||||
-rw-r--r-- | src/devices/video/i8244.h | 2 | ||||
-rw-r--r-- | src/mame/drivers/odyssey2.cpp | 226 |
5 files changed, 270 insertions, 280 deletions
diff --git a/src/devices/video/ef9340_1.cpp b/src/devices/video/ef9340_1.cpp index 65e140666f0..0fd895ed148 100644 --- a/src/devices/video/ef9340_1.cpp +++ b/src/devices/video/ef9340_1.cpp @@ -1,15 +1,13 @@ // license:BSD-3-Clause -// copyright-holders:Wilbert Pol +// copyright-holders:Wilbert Pol, hap /*************************************************************************** Thomson EF9340 + EF9341 teletext graphics chips with 1KB external character ram. TODO: - busy state (right now it is immediate) -- character blinking mode -- character underline mode - character width/height doubling -- window boxing/conceal +- window boxing - Y zoom ***************************************************************************/ @@ -30,7 +28,6 @@ DEFINE_DEVICE_TYPE(EF9340_1, ef9340_1_device, "ef9340_1", "Thomson EF9340+EF9341 ef9340_1_device::ef9340_1_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) : device_t(mconfig, EF9340_1, tag, owner, clock) , device_video_interface(mconfig, *this) - , m_line_timer(nullptr) , m_charset(*this, "ef9340_1") { } @@ -54,7 +51,10 @@ void ef9340_1_device::device_start() screen().register_screen_bitmap(m_tmp_bitmap); m_line_timer = timer_alloc(TIMER_LINE); - m_line_timer->adjust( screen().time_until_pos(0, 0), 0, screen().scan_period() ); + m_line_timer->adjust( screen().time_until_pos(0, 0), 0, screen().scan_period() ); + + m_blink_timer = timer_alloc(TIMER_BLINK); + m_blink_timer->adjust( screen().time_until_pos(0, 0), 0, screen().frame_period() ); // zerofill m_ef9341.TA = 0; @@ -66,10 +66,12 @@ void ef9340_1_device::device_start() m_ef9340.Y0 = 0; m_ef9340.R = 0; m_ef9340.M = 0; + m_ef9340.blink = false; + m_ef9340.blink_prescaler = 0; - memset(m_ef934x_ram_a, 0, sizeof(m_ef934x_ram_a)); - memset(m_ef934x_ram_b, 0, sizeof(m_ef934x_ram_b)); - memset(m_ef934x_ram_b, 0, sizeof(m_ef934x_ext_char_ram)); + memset(m_ram_a, 0, sizeof(m_ram_a)); + memset(m_ram_b, 0, sizeof(m_ram_b)); + memset(m_ram_b, 0, sizeof(m_ef934x_ext_char_ram)); // register our state save_item(NAME(m_ef9341.TA)); @@ -81,9 +83,11 @@ void ef9340_1_device::device_start() save_item(NAME(m_ef9340.Y0)); save_item(NAME(m_ef9340.R)); save_item(NAME(m_ef9340.M)); + save_item(NAME(m_ef9340.blink)); + save_item(NAME(m_ef9340.blink_prescaler)); - save_item(NAME(m_ef934x_ram_a)); - save_item(NAME(m_ef934x_ram_b)); + save_item(NAME(m_ram_a)); + save_item(NAME(m_ram_b)); save_item(NAME(m_ef934x_ext_char_ram)); } @@ -95,6 +99,17 @@ void ef9340_1_device::device_timer(emu_timer &timer, device_timer_id id, int par case TIMER_LINE: ef9340_scanline(screen().vpos()); break; + + case TIMER_BLINK: + // blink rate is approximately 0.5s + m_ef9340.blink_prescaler = (m_ef9340.blink_prescaler + 1) & 0x1f; + if (m_ef9340.R & 0x40 && m_ef9340.blink_prescaler == 24) + m_ef9340.blink_prescaler = 0; + + if (m_ef9340.blink_prescaler == 0) + m_ef9340.blink = !m_ef9340.blink; + + break; } } @@ -197,20 +212,20 @@ void ef9340_1_device::ef9341_write( uint8_t command, uint8_t b, uint8_t data ) switch ( m_ef9340.M & 0xE0 ) { case 0x00: /* Write */ - m_ef934x_ram_a[addr] = m_ef9341.TA; - m_ef934x_ram_b[addr] = m_ef9341.TB; + m_ram_a[addr] = m_ef9341.TA; + m_ram_b[addr] = m_ef9341.TB; ef9340_inc_c(); break; case 0x40: /* Write without increment */ - m_ef934x_ram_a[addr] = m_ef9341.TA; - m_ef934x_ram_b[addr] = m_ef9341.TB; + m_ram_a[addr] = m_ef9341.TA; + m_ram_b[addr] = m_ef9341.TB; break; case 0x80: /* Write slice */ { - uint8_t a = m_ef934x_ram_a[addr]; - uint8_t b = m_ef934x_ram_b[addr]; + uint8_t a = m_ram_a[addr]; + uint8_t b = m_ram_b[addr]; uint8_t slice = ( m_ef9340.M & 0x0f ) % 10; if ( b >= 0xa0 ) @@ -264,20 +279,20 @@ uint8_t ef9340_1_device::ef9341_read( uint8_t command, uint8_t b ) switch ( m_ef9340.M & 0xE0 ) { case 0x20: /* Read */ - m_ef9341.TA = m_ef934x_ram_a[addr]; - m_ef9341.TB = m_ef934x_ram_b[addr]; + m_ef9341.TA = m_ram_a[addr]; + m_ef9341.TB = m_ram_b[addr]; ef9340_inc_c(); break; case 0x60: /* Read without increment */ - m_ef9341.TA = m_ef934x_ram_a[addr]; - m_ef9341.TB = m_ef934x_ram_b[addr]; + m_ef9341.TA = m_ram_a[addr]; + m_ef9341.TB = m_ram_b[addr]; break; case 0xA0: /* Read slice */ { - uint8_t a = m_ef934x_ram_a[addr]; - uint8_t b = m_ef934x_ram_b[addr]; + uint8_t a = m_ram_a[addr]; + uint8_t b = m_ram_b[addr]; uint8_t slice = ( m_ef9340.M & 0x0f ) % 10; if ( b >= 0xa0 ) @@ -307,14 +322,13 @@ uint8_t ef9340_1_device::ef9341_read( uint8_t command, uint8_t b ) void ef9340_1_device::ef9340_scanline(int vpos) { - static const uint8_t bgr2rgb[8] = - { - 0x00, 0x04, 0x02, 0x06, 0x01, 0x05, 0x03, 0x07 - }; - - for ( int i = 0; i < 40 * 8; i++ ) + for (int i = 0; i < m_tmp_bitmap.width(); i++) m_tmp_bitmap.pix16(vpos, i) = 0; + vpos -= m_offset_y; + if (vpos < 0) + return; + // display automaton active at 40-290, or 32-242 int max_vpos = ( m_ef9340.R & 0x40 ) ? 250 : 210; @@ -324,6 +338,8 @@ void ef9340_1_device::ef9340_scanline(int vpos) int y_row, slice; uint8_t fg = 0; uint8_t bg = 0; + bool underline = false; + bool blank = false; if ( y < 10 ) { @@ -337,6 +353,8 @@ void ef9340_1_device::ef9340_scanline(int vpos) else { // Service row is disabled + for (int i = 0; i < 40 * 8; i++) + m_tmp_bitmap.pix16(vpos, i) = 8; return; } } @@ -350,75 +368,103 @@ void ef9340_1_device::ef9340_scanline(int vpos) for ( int x = 0; x < 40; x++ ) { uint16_t addr = ef9340_get_c_addr( x, y_row ); - uint8_t a = m_ef934x_ram_a[addr]; - uint8_t b = m_ef934x_ram_b[addr]; + uint8_t a = m_ram_a[addr]; + uint8_t b = m_ram_b[addr]; uint8_t char_data = 0x00; + bool blink = m_ef9340.R & 0x80 && m_ef9340.blink; + bool cursor = m_ef9340.R & 0x10 && x == m_ef9340.X && y_row == m_ef9340.Y; + bool invert = cursor && !blink; + bool alpha = !bool(a & 0x80); - if ( a & 0x80 ) + if (alpha) { - // Graphics + // Alphanumeric if ( b & 0x80 ) { if ( b & 0x60 ) { // Extension - char_data = m_ef934x_ext_char_ram[ 0x400 | external_chargen_address( b & 0x7f, slice ) ]; - fg = bgr2rgb[ a & 0x07 ]; - bg = bgr2rgb[ ( a >> 4 ) & 0x07 ]; + char_data = m_ef934x_ext_char_ram[ external_chargen_address( b & 0x7f, slice ) ]; + fg = a & 0x07; } else { - // Illegal + // Deliminator + alpha = false; + blank = m_ef9340.R & 0x04 && b & 0x01; + underline = bool(b & 0x04); + char_data = 0xff; + fg = a & 0x07; + bg = a >> 4 & 0x07; } } else { // Normal - char_data = m_charset[((b | 0x80) * 10) + slice]; - fg = bgr2rgb[ a & 0x07 ]; - bg = bgr2rgb[ ( a >> 4 ) & 0x07 ]; + if (slice == 9 && underline) + char_data = 0xff; + else + char_data = m_charset[((b & 0x7f) * 10) + slice]; + fg = a & 0x07; + } + + // Inverted + if (alpha && a & 0x40) + { + invert = !invert; + blink = m_ef9340.R & 0x80 && !m_ef9340.blink; } } else { - // Alphanumeric + // Graphics if ( b & 0x80 ) { if ( b & 0x60 ) { // Extension - char_data = m_ef934x_ext_char_ram[ external_chargen_address( b & 0x7f, slice ) ]; - if ( a & 0x40 ) - char_data ^= 0xff; - fg = bgr2rgb[ a & 0x07 ]; + char_data = m_ef934x_ext_char_ram[ 0x400 | external_chargen_address( b & 0x7f, slice ) ]; + fg = a & 0x07; + bg = a >> 4 & 0x07; } else { - // DEL - char_data = 0xff; - fg = bgr2rgb[ a & 0x07 ]; - bg = bgr2rgb[ ( a >> 4 ) & 0x07 ]; + // Illegal } } else { // Normal - char_data = m_charset[((b & 0x7f) * 10) + slice]; - if ( a & 0x40 ) - char_data ^= 0xff; - fg = bgr2rgb[ a & 0x07 ]; + char_data = m_charset[((b | 0x80) * 10) + slice]; + fg = a & 0x07; + bg = a >> 4 & 0x07; } } - // Cursor is enabled - if ( m_ef9340.R & 0x10 && x == m_ef9340.X && y_row == m_ef9340.Y ) + // blink character + if (blink && !cursor && (b & 0xe0) != 0x80 && ~a & 0x08) + char_data = 0; + + if (invert) char_data ^= 0xff; for ( int i = 0; i < 8; i++ ) { - m_tmp_bitmap.pix16(vpos, 0 + x*8 + i ) = (char_data & 0x80) ? fg : bg; + uint16_t d = blank ? 0 : (char_data & 0x80) ? fg : bg; + m_tmp_bitmap.pix16(m_offset_y + vpos, m_offset_x + x*8 + i ) = d | 8; char_data <<= 1; } } } } + + +uint32_t ef9340_1_device::screen_update(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect) +{ + // note: palette d3 is transparency (datasheet calls it "I"), this handler masks it off + for (int y = cliprect.min_y; y <= cliprect.max_y; y++) + for (int x = cliprect.min_x; x <= cliprect.max_x; x++) + bitmap.pix16(y, x) = m_tmp_bitmap.pix16(y, x) & 7; + + return 0; +} diff --git a/src/devices/video/ef9340_1.h b/src/devices/video/ef9340_1.h index f2d9d906731..115ce51d25b 100644 --- a/src/devices/video/ef9340_1.h +++ b/src/devices/video/ef9340_1.h @@ -1,9 +1,8 @@ // license:BSD-3-Clause -// copyright-holders:Wilbert Pol +// copyright-holders:Wilbert Pol, hap /*************************************************************************** - Thomson EF9340 + EF9341 teletext graphics chips with 1KB external - character ram. + Thomson EF9340 + EF9341 teletext graphics chips ***************************************************************************/ @@ -25,9 +24,13 @@ public: set_screen(std::forward<T>(screen_tag)); } + // configuration helpers + ef9340_1_device &set_offsets(int x, int y) { m_offset_x = x; m_offset_y = y; return *this; } // when used with overlay chip + ef9340_1_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock); inline bitmap_ind16 *get_bitmap() { return &m_tmp_bitmap; } + uint32_t screen_update(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect); void ef9341_write( uint8_t command, uint8_t b, uint8_t data ); uint8_t ef9341_read( uint8_t command, uint8_t b ); @@ -48,31 +51,38 @@ protected: /* timers */ static constexpr device_timer_id TIMER_LINE = 0; + static constexpr device_timer_id TIMER_BLINK = 1; emu_timer *m_line_timer; + emu_timer *m_blink_timer; required_region_ptr<uint8_t> m_charset; bitmap_ind16 m_tmp_bitmap; + int m_offset_x = 0; + int m_offset_y = 0; + struct { - uint8_t TA; - uint8_t TB; - bool busy; + uint8_t TA; + uint8_t TB; + bool busy; } m_ef9341; struct { - uint8_t X; - uint8_t Y; - uint8_t Y0; - uint8_t R; - uint8_t M; + uint8_t X; + uint8_t Y; + uint8_t Y0; + uint8_t R; + uint8_t M; + bool blink; + int blink_prescaler; } m_ef9340; - uint8_t m_ef934x_ram_a[0x400]; // A10 to GND - uint8_t m_ef934x_ram_b[0x400]; // A10 to GND + uint8_t m_ram_a[0x400]; + uint8_t m_ram_b[0x400]; uint8_t m_ef934x_ext_char_ram[0x800]; // The G7400 has 2KB of external ram hooked up. The datasheet only describes how to hookup 1KB. }; diff --git a/src/devices/video/i8244.cpp b/src/devices/video/i8244.cpp index 184536257e3..3085508e7aa 100644 --- a/src/devices/video/i8244.cpp +++ b/src/devices/video/i8244.cpp @@ -159,20 +159,20 @@ void i8244_device::i8244_palette(palette_device &palette) const static constexpr rgb_t i8244_colors[16] = { { 0x00, 0x00, 0x00 }, // i r g b - { 0x00, 0x00, 0xb6 }, // i r g B - { 0x00, 0xb6, 0x00 }, // i r G b - { 0x00, 0xb6, 0xb6 }, // i r G B { 0xb6, 0x00, 0x00 }, // i R g b - { 0xb6, 0x00, 0xb6 }, // i R g B + { 0x00, 0xb6, 0x00 }, // i r G b { 0xb6, 0xb6, 0x00 }, // i R G b + { 0x00, 0x00, 0xb6 }, // i r g B + { 0xb6, 0x00, 0xb6 }, // i R g B + { 0x00, 0xb6, 0xb6 }, // i r G B { 0xb6, 0xb6, 0xb6 }, // i R G B { 0x49, 0x49, 0x49 }, // I r g b - { 0x49, 0x49, 0xff }, // I r g B - { 0x49, 0xff, 0x49 }, // I r G b - { 0x49, 0xff, 0xff }, // I r G B { 0xff, 0x49, 0x49 }, // I R g b - { 0xff, 0x49, 0xff }, // I R g B + { 0x49, 0xff, 0x49 }, // I r G b { 0xff, 0xff, 0x49 }, // I R G b + { 0x49, 0x49, 0xff }, // I r g B + { 0xff, 0x49, 0xff }, // I R g B + { 0x49, 0xff, 0xff }, // I r G B { 0xff, 0xff, 0xff } // I R G B }; @@ -473,7 +473,7 @@ void i8244_device::write_cx(int x, bool cx) { if (cx) { - u8 colx = m_collision_map[x]; + u8 colx = m_collision_map[x] & 0x3f; // Check if we collide with an already drawn source object if (colx) @@ -499,26 +499,8 @@ void i8244_device::write_cx(int x, bool cx) uint32_t i8244_device::screen_update(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect) { - // Some local constants for this method - //static const uint8_t COLLISION_SPRITE_0 = 0x01; - //static const uint8_t COLLISION_SPRITE_1 = 0x02; - //static const uint8_t COLLISION_SPRITE_2 = 0x04; - //static const uint8_t COLLISION_SPRITE_3 = 0x08; - static const uint8_t COLLISION_VERTICAL_GRID = 0x10; - static const uint8_t COLLISION_HORIZ_GRID_DOTS = 0x20; - static const uint8_t COLLISION_EXTERNAL = 0x40; - static const uint8_t COLLISION_CHARACTERS = 0x80; - - // Background and grid information is stored in RGB format - // while the character and sprite colors are stored in BGR - // format. - static const uint8_t bgr2rgb[8] = - { - 0x00, 0x04, 0x02, 0x06, 0x01, 0x05, 0x03, 0x07 - }; - /* Draw background color */ - bitmap.fill( (m_vdc.s.color >> 3) & 0x7, cliprect ); + bitmap.fill(bitswap<3>(m_vdc.s.color,3,4,5), cliprect); for (int scanline = cliprect.min_y; scanline <= cliprect.max_y; scanline++) { @@ -528,7 +510,7 @@ uint32_t i8244_device::screen_update(screen_device &screen, bitmap_ind16 &bitmap /* Display grid if enabled */ if ( m_vdc.s.control & 0x08 ) { - uint16_t color = ( m_vdc.s.color & 7 ) | ( ( m_vdc.s.color >> 3 ) & 0x08 ); + uint16_t color = bitswap<4>(m_vdc.s.color,6,0,1,2); int x_grid_offset = 13; int y_grid_offset = 24; int width = 16; @@ -552,7 +534,7 @@ uint32_t i8244_device::screen_update(screen_device &screen, bitmap_ind16 &bitmap { if (cliprect.contains(px, scanline)) { - m_collision_map[ px ] |= COLLISION_HORIZ_GRID_DOTS; + m_collision_map[ px ] |= 0x20; bitmap.pix16( scanline, px ) = color; } } @@ -579,7 +561,7 @@ uint32_t i8244_device::screen_update(screen_device &screen, bitmap_ind16 &bitmap { if (cliprect.contains(px, scanline)) { - m_collision_map[ px ] |= COLLISION_HORIZ_GRID_DOTS; + m_collision_map[ px ] |= 0x20; bitmap.pix16( scanline, px ) = color; } } @@ -606,7 +588,7 @@ uint32_t i8244_device::screen_update(screen_device &screen, bitmap_ind16 &bitmap { if (cliprect.contains(px, scanline)) { - m_collision_map[ px ] |= COLLISION_VERTICAL_GRID; + m_collision_map[ px ] |= 0x10; bitmap.pix16( scanline, px ) = color; } } @@ -629,7 +611,7 @@ uint32_t i8244_device::screen_update(screen_device &screen, bitmap_ind16 &bitmap if ( y <= scanline && scanline < y + height * 2 ) { - uint16_t color = 8 + bgr2rgb[ ( ( m_vdc.s.foreground[i].color >> 1 ) & 0x07 ) ]; + uint16_t color = 8 + ( ( m_vdc.s.foreground[i].color >> 1 ) & 0x07 ); int offset = ( m_vdc.s.foreground[i].ptr | ( ( m_vdc.s.foreground[i].color & 0x01 ) << 8 ) ) + ( y >> 1 ) + ( ( scanline - y ) >> 1 ); uint8_t chr = m_charset[ offset & 0x1FF ]; int x = (m_vdc.s.foreground[i].x + 5) * 2; @@ -642,25 +624,23 @@ uint32_t i8244_device::screen_update(screen_device &screen, bitmap_ind16 &bitmap { if (cliprect.contains(px, scanline)) { - /* Check collision with self */ - u8 colx = m_collision_map[ px ] & ~COLLISION_EXTERNAL; - if (colx & COLLISION_CHARACTERS) + // Check collision with self + u8 colx = m_collision_map[ px ]; + if (colx & 0x80) { - colx &= ~COLLISION_CHARACTERS; - m_control_status |= COLLISION_CHARACTERS; + colx &= ~0x80; + m_control_status |= 0x80; } - /* Check if we collide with an already drawn source object */ - if ( colx & m_vdc.s.collision ) - { - m_collision_status |= COLLISION_CHARACTERS; - } - /* Check if an already drawn object would collide with us */ - if ( COLLISION_CHARACTERS & m_vdc.s.collision ) - { + // Check if we collide with an already drawn source object + if (m_vdc.s.collision & colx) + m_collision_status |= 0x80; + + // Check if an already drawn object would collide with us + if (m_vdc.s.collision & 0x80) m_collision_status |= colx; - } - m_collision_map[ px ] |= COLLISION_CHARACTERS; + + m_collision_map[ px ] |= 0x80; bitmap.pix16( scanline, px ) = color; } } @@ -684,7 +664,7 @@ uint32_t i8244_device::screen_update(screen_device &screen, bitmap_ind16 &bitmap for ( int j = 0; j < ARRAY_LENGTH( m_vdc.s.quad[0].single ); j++, x += 16 ) { - uint16_t color = 8 + bgr2rgb[ ( ( m_vdc.s.quad[i].single[j].color >> 1 ) & 0x07 ) ]; + uint16_t color = 8 + ( ( m_vdc.s.quad[i].single[j].color >> 1 ) & 0x07 ); 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 ); uint8_t chr = m_charset[ offset & 0x1FF ]; @@ -696,25 +676,23 @@ uint32_t i8244_device::screen_update(screen_device &screen, bitmap_ind16 &bitmap { if (cliprect.contains(px, scanline)) { - /* Check collision with self */ - u8 colx = m_collision_map[ px ] & ~COLLISION_EXTERNAL; - if (colx & COLLISION_CHARACTERS) + // Check collision with self + u8 colx = m_collision_map[ px ]; + if (colx & 0x80) { - colx &= ~COLLISION_CHARACTERS; - m_control_status |= COLLISION_CHARACTERS; + colx &= ~0x80; + m_control_status |= 0x80; } - /* Check if we collide with an already drawn source object */ - if ( colx & m_vdc.s.collision ) - { - m_collision_status |= COLLISION_CHARACTERS; - } - /* Check if an already drawn object would collide with us */ - if ( COLLISION_CHARACTERS & m_vdc.s.collision ) - { + // Check if we collide with an already drawn source object + if (m_vdc.s.collision & colx) + m_collision_status |= 0x80; + + // Check if an already drawn object would collide with us + if (m_vdc.s.collision & 0x80) m_collision_status |= colx; - } - m_collision_map[ px ] |= COLLISION_CHARACTERS; + + m_collision_map[ px ] |= 0x80; bitmap.pix16( scanline, px ) = color; } } @@ -734,7 +712,7 @@ uint32_t i8244_device::screen_update(screen_device &screen, bitmap_ind16 &bitmap if ( y <= scanline && scanline < y + height * zoom_px ) { - uint16_t color = 8 + bgr2rgb[ ( ( m_vdc.s.sprites[i].color >> 3 ) & 0x07 ) ]; + uint16_t color = 8 + ( ( m_vdc.s.sprites[i].color >> 3 ) & 0x07 ); uint8_t chr = m_vdc.s.shape[i][ ( ( scanline - y ) / zoom_px ) ]; int x = (m_vdc.s.sprites[i].x + 5) * 2; int x_shift = 0; @@ -764,17 +742,17 @@ uint32_t i8244_device::screen_update(screen_device &screen, bitmap_ind16 &bitmap { if (cliprect.contains(px, scanline)) { - /* Check if we collide with an already drawn source object */ - if ( m_collision_map[ px ] & m_vdc.s.collision ) - { - m_collision_status |= ( 1 << i ); - } - /* Check if an already drawn object would collide with us */ - if ( ( 1 << i ) & m_vdc.s.collision ) - { + u8 mask = 1 << i; + + // Check if we collide with an already drawn source object + if (m_vdc.s.collision & m_collision_map[ px ]) + m_collision_status |= mask; + + // Check if an already drawn object would collide with us + if (m_vdc.s.collision & mask) m_collision_status |= m_collision_map[ px ]; - } - m_collision_map[ px ] |= ( 1 << i ); + + m_collision_map[ px ] |= mask; bitmap.pix16( scanline, px ) = color; } } diff --git a/src/devices/video/i8244.h b/src/devices/video/i8244.h index d27ae19ea52..6ddff5806aa 100644 --- a/src/devices/video/i8244.h +++ b/src/devices/video/i8244.h @@ -31,7 +31,7 @@ public: // configuration helpers auto irq_cb() { return m_irq_func.bind(); } - i8244_device &set_screen_size(int width, int height, int cropx, int cropy); + i8244_device &set_screen_size(int width, int height, int cropx = 0, int cropy = 0); uint8_t read(offs_t offset); void write(offs_t offset, uint8_t data); diff --git a/src/mame/drivers/odyssey2.cpp b/src/mame/drivers/odyssey2.cpp index 0470f08be39..fafb574e27f 100644 --- a/src/mame/drivers/odyssey2.cpp +++ b/src/mame/drivers/odyssey2.cpp @@ -34,15 +34,18 @@ XTAL notes (differs per model): TODO: - verify odyssey3 cpu/video clocks +- odyssey sets 210 line mode in plus graphics, which cuts off the bottom part + of the screen - backgamm doesn't draw all the sprites, what causes it? It doesn't seem like it's a 824x bug since it does properly write data in the partial screen updates -- 824x screen resolution is not strictly defined -- 824x on the real console, overlapping characters on eachother will cause glitches - (it is used to an advantage in some as-of-yet undumped homebrews) +- 824x screen resolution is not strictly defined, height(243) is correct, but + horizontal overscan differs depending on monitor/tv? +- 824x on the real console, overlapping characters on eachother will cause + glitches (it is used to an advantage in some as-of-yet undumped homebrews) - 8244(NTSC) is not supposed to show characters near the upper border, but hiding them will cause bugs in some Euro games - 8245(PAL) video timing is not 100% accurate, though vtotal and htotal should - be correct(see backgamm) + be correct - ppp(the tetris game) does not work properly on PAL, is this homebrew NTSC-only, or is it due to PAL video timing? The game does mid-scanline updates - g7400 probably has different video timing too (not same as g7000) @@ -92,8 +95,8 @@ protected: required_device<o2_cart_slot_device> m_cart; uint8_t m_ram[0x80]; - uint8_t m_p1; - uint8_t m_p2; + uint8_t m_p1 = 0xff; + uint8_t m_p2 = 0xff; DECLARE_READ_LINE_MEMBER(t1_read); void odyssey2_palette(palette_device &palette) const; @@ -103,16 +106,6 @@ protected: virtual void machine_start() override; - /* constants */ - static const uint8_t P1_BANK_LO_BIT = 0x01; - static const uint8_t P1_BANK_HI_BIT = 0x02; - static const uint8_t P1_KEYBOARD_SCAN_ENABLE = 0x04; /* active low */ - static const uint8_t P1_VDC_ENABLE = 0x08; /* active low */ - static const uint8_t P1_EXT_RAM_ENABLE = 0x10; /* active low */ - static const uint8_t P1_VPP_ENABLE = 0x20; /* active low */ - static const uint8_t P1_VDC_COPY_MODE_ENABLE = 0x40; - static const uint8_t P2_KEYBOARD_SELECT_MASK = 0x07; /* select row to scan */ - required_ioport_array<8> m_keyboard; required_ioport_array<2> m_joysticks; @@ -141,25 +134,25 @@ public: void g7400(machine_config &config); void odyssey3(machine_config &config); +protected: + virtual void machine_start() override; + private: required_device<i8243_device> m_i8243; required_device<ef9340_1_device> m_ef9340_1; uint32_t screen_update(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect); - virtual void machine_start() override; void p2_write(uint8_t data); + uint8_t io_vpp(offs_t offset, uint8_t data); uint8_t io_read(offs_t offset); void io_write(offs_t offset, uint8_t data); - void i8243_p4_w(uint8_t data); - void i8243_p5_w(uint8_t data); - void i8243_p6_w(uint8_t data); - void i8243_p7_w(uint8_t data); + template<int P> void i8243_port_w(uint8_t data); void g7400_io(address_map &map); - uint8_t m_ic674_decode[8]; - uint8_t m_ic678_decode[8]; + uint8_t m_mix_in = 0xff; + uint8_t m_mix_out = 0xff; }; @@ -251,20 +244,20 @@ static INPUT_PORTS_START( odyssey2 ) PORT_BIT(0xff, IP_ACTIVE_HIGH, IPT_UNUSED) PORT_START("JOY.0") - PORT_BIT(0x01, IP_ACTIVE_LOW, IPT_JOYSTICK_UP) PORT_PLAYER(2) - PORT_BIT(0x02, IP_ACTIVE_LOW, IPT_JOYSTICK_RIGHT) PORT_PLAYER(2) - PORT_BIT(0x04, IP_ACTIVE_LOW, IPT_JOYSTICK_DOWN) PORT_PLAYER(2) - PORT_BIT(0x08, IP_ACTIVE_LOW, IPT_JOYSTICK_LEFT) PORT_PLAYER(2) - PORT_BIT(0x10, IP_ACTIVE_LOW, IPT_BUTTON1) PORT_PLAYER(2) - PORT_BIT(0xe0, IP_ACTIVE_LOW, IPT_UNUSED) + PORT_BIT(0x01, IP_ACTIVE_HIGH, IPT_JOYSTICK_UP) PORT_PLAYER(2) + PORT_BIT(0x02, IP_ACTIVE_HIGH, IPT_JOYSTICK_RIGHT) PORT_PLAYER(2) + PORT_BIT(0x04, IP_ACTIVE_HIGH, IPT_JOYSTICK_DOWN) PORT_PLAYER(2) + PORT_BIT(0x08, IP_ACTIVE_HIGH, IPT_JOYSTICK_LEFT) PORT_PLAYER(2) + PORT_BIT(0x10, IP_ACTIVE_HIGH, IPT_BUTTON1) PORT_PLAYER(2) + PORT_BIT(0xe0, IP_ACTIVE_HIGH, IPT_UNUSED) PORT_START("JOY.1") - PORT_BIT(0x01, IP_ACTIVE_LOW, IPT_JOYSTICK_UP) PORT_PLAYER(1) - PORT_BIT(0x02, IP_ACTIVE_LOW, IPT_JOYSTICK_RIGHT) PORT_PLAYER(1) - PORT_BIT(0x04, IP_ACTIVE_LOW, IPT_JOYSTICK_DOWN) PORT_PLAYER(1) - PORT_BIT(0x08, IP_ACTIVE_LOW, IPT_JOYSTICK_LEFT) PORT_PLAYER(1) - PORT_BIT(0x10, IP_ACTIVE_LOW, IPT_BUTTON1) PORT_PLAYER(1) - PORT_BIT(0xe0, IP_ACTIVE_LOW, IPT_UNUSED) + PORT_BIT(0x01, IP_ACTIVE_HIGH, IPT_JOYSTICK_UP) PORT_PLAYER(1) + PORT_BIT(0x02, IP_ACTIVE_HIGH, IPT_JOYSTICK_RIGHT) PORT_PLAYER(1) + PORT_BIT(0x04, IP_ACTIVE_HIGH, IPT_JOYSTICK_DOWN) PORT_PLAYER(1) + PORT_BIT(0x08, IP_ACTIVE_HIGH, IPT_JOYSTICK_LEFT) PORT_PLAYER(1) + PORT_BIT(0x10, IP_ACTIVE_HIGH, IPT_BUTTON1) PORT_PLAYER(1) + PORT_BIT(0xe0, IP_ACTIVE_HIGH, IPT_UNUSED) PORT_START("RESET") PORT_BIT(0x01, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("Reset") PORT_CODE(KEYCODE_F1) PORT_CHANGED_MEMBER(DEVICE_SELF, odyssey2_state, reset_button, 0) @@ -354,22 +347,22 @@ constexpr rgb_t odyssey2_colors[] = { // Background,Grid Dim { 0x00, 0x00, 0x00 }, /* Black */ // i r g b - { 0x1a, 0x37, 0xbe }, /* Blue - Calibrated To Real VideoPac */ // i r g B - { 0x00, 0x6d, 0x07 }, /* Green - Calibrated To Real VideoPac */ // i r G b - { 0x2a, 0xaa, 0xbe }, /* Blue-Green - Calibrated To Real VideoPac */ // i r G B { 0x79, 0x00, 0x00 }, /* Red - Calibrated To Real VideoPac */ // i R g b - { 0x94, 0x30, 0x9f }, /* Violet - Calibrated To Real VideoPac */ // i R g B + { 0x00, 0x6d, 0x07 }, /* Green - Calibrated To Real VideoPac */ // i r G b { 0x77, 0x67, 0x0b }, /* Khaki - Calibrated To Real VideoPac */ // i R g B + { 0x1a, 0x37, 0xbe }, /* Blue - Calibrated To Real VideoPac */ // i r g B + { 0x94, 0x30, 0x9f }, /* Violet - Calibrated To Real VideoPac */ // i R g B + { 0x2a, 0xaa, 0xbe }, /* Blue-Green - Calibrated To Real VideoPac */ // i r G B { 0xce, 0xce, 0xce }, /* Lt Grey */ // i R G B // Background,Grid Bright { 0x67, 0x67, 0x67 }, /* Grey - Calibrated To Real VideoPac */ // I R g B - { 0x5c, 0x80, 0xf6 }, /* Lt Blue - Calibrated To Real VideoPac */ // I R g B - { 0x56, 0xc4, 0x69 }, /* Lt Green - Calibrated To Real VideoPac */ // I R g B - { 0x77, 0xe6, 0xeb }, /* Lt Blue-Green - Calibrated To Real VideoPac */ // I R g b { 0xc7, 0x51, 0x51 }, /* Lt Red - Calibrated To Real VideoPac */ // I R g b - { 0xdc, 0x84, 0xe8 }, /* Lt Violet - Calibrated To Real VideoPac */ // I R g B + { 0x56, 0xc4, 0x69 }, /* Lt Green - Calibrated To Real VideoPac */ // I R g B { 0xc6, 0xb8, 0x6a }, /* Lt Yellow - Calibrated To Real VideoPac */ // I R G b + { 0x5c, 0x80, 0xf6 }, /* Lt Blue - Calibrated To Real VideoPac */ // I R g B + { 0xdc, 0x84, 0xe8 }, /* Lt Violet - Calibrated To Real VideoPac */ // I R g B + { 0x77, 0xe6, 0xeb }, /* Lt Blue-Green - Calibrated To Real VideoPac */ // I R g b { 0xff, 0xff, 0xff } /* White */ // I R G B }; @@ -394,11 +387,8 @@ void g7400_state::machine_start() { odyssey2_state::machine_start(); - memset(m_ic674_decode, 0, sizeof(m_ic674_decode)); - memset(m_ic678_decode, 0, sizeof(m_ic678_decode)); - - save_item(NAME(m_ic674_decode)); - save_item(NAME(m_ic678_decode)); + save_item(NAME(m_mix_in)); + save_item(NAME(m_mix_out)); } @@ -407,10 +397,10 @@ void g7400_state::machine_start() uint8_t odyssey2_state::io_read(offs_t offset) { u8 data = m_cart->io_read(offset); - if (!(m_p1 & P1_EXT_RAM_ENABLE) && ~offset & 0x80) + if (!(m_p1 & 0x10) && ~offset & 0x80) data &= m_ram[offset]; - if ((m_p1 & (P1_VDC_COPY_MODE_ENABLE | P1_VDC_ENABLE)) == 0) + if ((m_p1 & 0x48) == 0) data &= m_i8244->read(offset); return data; @@ -419,23 +409,21 @@ uint8_t odyssey2_state::io_read(offs_t offset) void odyssey2_state::io_write(offs_t offset, uint8_t data) { - if (!(m_p1 & P1_VDC_COPY_MODE_ENABLE)) + if (!(m_p1 & 0x40)) { m_cart->io_write(offset, data); - if (!(m_p1 & P1_EXT_RAM_ENABLE) && ~offset & 0x80) + if (!(m_p1 & 0x10) && ~offset & 0x80) m_ram[offset] = data; } - if (!(m_p1 & P1_VDC_ENABLE)) + if (!(m_p1 & 0x08)) m_i8244->write(offset, data); } -uint8_t g7400_state::io_read(offs_t offset) +uint8_t g7400_state::io_vpp(offs_t offset, uint8_t data) { - u8 data = odyssey2_state::io_read(offset); - - if (!(m_p1 & P1_VPP_ENABLE)) + if (!(m_p1 & 0x20)) { // A2 to R/W pin if (offset & 4) @@ -448,12 +436,17 @@ uint8_t g7400_state::io_read(offs_t offset) } +uint8_t g7400_state::io_read(offs_t offset) +{ + u8 data = odyssey2_state::io_read(offset); + return io_vpp(offset, data); +} + + void g7400_state::io_write(offs_t offset, uint8_t data) { odyssey2_state::io_write(offset, data); - - if (!(m_p1 & P1_VPP_ENABLE) && ~offset & 4) - m_ef9340_1->ef9341_write( offset & 0x02, offset & 0x01, data ); + io_vpp(offset, data); } @@ -477,9 +470,6 @@ uint32_t g7400_state::screen_update(screen_device &screen, bitmap_ind16 &bitmap, u8 lum = ~m_p1 >> 4 & 0x08; bitmap_ind16 *ef934x_bitmap = m_ef9340_1->get_bitmap(); - const int xoffs = 15; - const int yoffs = 5; - // apply external LUM setting for (int y = cliprect.min_y; y <= cliprect.max_y; y++) { @@ -491,30 +481,22 @@ uint32_t g7400_state::screen_update(screen_device &screen, bitmap_ind16 &bitmap, for (int x = clip.min_x; x <= clip.max_x; x++) { uint16_t d = bitmap.pix16(y, x); + uint16_t e = ef934x_bitmap->pix16(y, x); - if ( ( ! m_ic678_decode[ d & 0x07 ] ) && x >= xoffs && x < (320 + xoffs) && y >= yoffs ) - { - // Use EF934x input - d = ef934x_bitmap->pix16( y - yoffs, x - xoffs ) & 0x07; + // I outputs to CX + bool i2 = !BIT(m_mix_out, e & 0x07); + m_i8244->write_cx(x, i2); - if ( ! m_ic674_decode[ d ] ) - { - d |= 0x08; - } + if (m_mix_in == 0xff || ((e & 0x08) && BIT(m_mix_in, d & 0x07))) + { + // Use i8245 input + bitmap.pix16(y, x) |= lum; } else { - // Use i8245 input - d |= lum; - - // I outputs to CX - if (x >= xoffs && x < (320 + xoffs) && y >= yoffs) - { - bool cx = !m_ic674_decode[ef934x_bitmap->pix16(y - yoffs, x - xoffs) & 0x07]; - m_i8244->write_cx(x, cx); - } + // Use EF934x input + bitmap.pix16(y, x) = i2 ? e | 0x08 : e & 0x07; } - bitmap.pix16(y, x) = d; } } @@ -549,10 +531,10 @@ uint8_t odyssey2_state::p2_read() { u8 data = 0xff; - if (!(m_p1 & P1_KEYBOARD_SCAN_ENABLE)) + if (!(m_p1 & 0x04)) { // 74148 priority encoder, GS to P24, outputs to P25-P27 - u8 inp = count_leading_zeros(m_keyboard[m_p2 & P2_KEYBOARD_SELECT_MASK]->read()) - 24; + u8 inp = count_leading_zeros(m_keyboard[m_p2 & 0x07]->read()) - 24; if (inp < 8) data &= inp << 5 | 0xf; } @@ -579,11 +561,11 @@ uint8_t odyssey2_state::bus_read() { u8 data = 0xff; - if (!(m_p1 & P1_KEYBOARD_SCAN_ENABLE)) + if (!(m_p1 & 0x04)) { - u8 sel = m_p2 & P2_KEYBOARD_SELECT_MASK; + u8 sel = m_p2 & 0x07; if (sel < 2) - data &= m_joysticks[sel]->read(); + data &= ~m_joysticks[sel]->read(); } return data; @@ -595,51 +577,24 @@ void odyssey2_state::bus_write(uint8_t data) } -/* - i8243 in the g7400 -*/ - -void g7400_state::i8243_p4_w(uint8_t data) +template<int P> +void g7400_state::i8243_port_w(uint8_t data) { - // "port 4" - m_screen->update_now(); - m_ic674_decode[1] = BIT(data,0); - m_ic674_decode[5] = BIT(data,1); - m_ic674_decode[3] = BIT(data,2); - m_ic674_decode[7] = BIT(data,3); -} - - -void g7400_state::i8243_p5_w(uint8_t data) -{ - // "port 5" - m_screen->update_now(); - m_ic674_decode[0] = BIT(data,0); - m_ic674_decode[4] = BIT(data,1); - m_ic674_decode[2] = BIT(data,2); - m_ic674_decode[6] = BIT(data,3); -} - + // P4,P5: color mix out (IC674) + // P6,P7: color mix in (IC678) + u8 mask = 0xf; + if (~P & 1) + { + data <<= 4; + mask <<= 4; + } -void g7400_state::i8243_p6_w(uint8_t data) -{ - // "port 6" m_screen->update_now(); - m_ic678_decode[1] = BIT(data,0); - m_ic678_decode[5] = BIT(data,1); - m_ic678_decode[3] = BIT(data,2); - m_ic678_decode[7] = BIT(data,3); -} - -void g7400_state::i8243_p7_w(uint8_t data) -{ - // "port 7" - m_screen->update_now(); - m_ic678_decode[0] = BIT(data,0); - m_ic678_decode[4] = BIT(data,1); - m_ic678_decode[2] = BIT(data,2); - m_ic678_decode[6] = BIT(data,3); + if (P & 2) + m_mix_in = (m_mix_in & ~mask) | (data & mask); + else + m_mix_out = (m_mix_out & ~mask) | (data & mask); } @@ -670,7 +625,7 @@ void odyssey2_state::odyssey2(machine_config &config) SPEAKER(config, "mono").front_center(); I8244(config, m_i8244, XTAL(7'159'090) / 2); m_i8244->set_screen("screen"); - m_i8244->set_screen_size(344, 242, 0, 0); + m_i8244->set_screen_size(356, 243); m_i8244->irq_cb().set_inputline(m_maincpu, MCS48_INPUT_IRQ); m_i8244->add_route(ALL_OUTPUTS, "mono", 0.40); @@ -687,7 +642,7 @@ void odyssey2_state::videopac(machine_config &config) // PAL video chip I8245(config.replace(), m_i8244, XTAL(17'734'476) / 5); m_i8244->set_screen("screen"); - m_i8244->set_screen_size(344, 242, 0, 0); + m_i8244->set_screen_size(356, 243); m_i8244->irq_cb().set_inputline(m_maincpu, MCS48_INPUT_IRQ); m_i8244->add_route(ALL_OUTPUTS, "mono", 0.40); @@ -729,17 +684,18 @@ void g7400_state::g7400(machine_config &config) PALETTE(config, "palette", m_i8244, FUNC(i8244_device::i8244_palette), 16); I8243(config, m_i8243); - m_i8243->p4_out_cb().set(FUNC(g7400_state::i8243_p4_w)); - m_i8243->p5_out_cb().set(FUNC(g7400_state::i8243_p5_w)); - m_i8243->p6_out_cb().set(FUNC(g7400_state::i8243_p6_w)); - m_i8243->p7_out_cb().set(FUNC(g7400_state::i8243_p7_w)); + m_i8243->p4_out_cb().set(FUNC(g7400_state::i8243_port_w<0>)); + m_i8243->p5_out_cb().set(FUNC(g7400_state::i8243_port_w<1>)); + m_i8243->p6_out_cb().set(FUNC(g7400_state::i8243_port_w<2>)); + m_i8243->p7_out_cb().set(FUNC(g7400_state::i8243_port_w<3>)); EF9340_1(config, m_ef9340_1, XTAL(8'867'000)/5 * 2, "screen"); + m_ef9340_1->set_offsets(15, 5); SPEAKER(config, "mono").front_center(); I8245(config, m_i8244, XTAL(8'867'000)/5 * 2); m_i8244->set_screen("screen"); - m_i8244->set_screen_size(320, 240, 15, 5); + m_i8244->set_screen_size(356, 243); m_i8244->irq_cb().set_inputline(m_maincpu, MCS48_INPUT_IRQ); m_i8244->add_route(ALL_OUTPUTS, "mono", 0.40); @@ -756,7 +712,7 @@ void g7400_state::odyssey3(machine_config &config) // NTSC video chip I8244(config.replace(), m_i8244, XTAL(7'159'090) / 2); m_i8244->set_screen("screen"); - m_i8244->set_screen_size(320, 240, 15, 5); + m_i8244->set_screen_size(356, 243); m_i8244->irq_cb().set_inputline(m_maincpu, MCS48_INPUT_IRQ); m_i8244->add_route(ALL_OUTPUTS, "mono", 0.40); |