summaryrefslogtreecommitdiffstatshomepage
diff options
context:
space:
mode:
author hap <happppp@users.noreply.github.com>2020-08-16 20:55:10 +0200
committer hap <happppp@users.noreply.github.com>2020-08-16 20:55:27 +0200
commit9ee3de7b1f5d8d68d06650ef1d77697000ad494e (patch)
tree93d7311186025a8d05b561d3394d0217585f8e61
parent6c5e9d3eff7435546faf844384a1f6c86cf3a025 (diff)
ef9340: add character blink/underline modes
-rw-r--r--src/devices/video/ef9340_1.cpp158
-rw-r--r--src/devices/video/ef9340_1.h36
-rw-r--r--src/devices/video/i8244.cpp128
-rw-r--r--src/devices/video/i8244.h2
-rw-r--r--src/mame/drivers/odyssey2.cpp226
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);