video/saa5240.cpp: Decode national character sets.

- Cursor rendered when enabled.
- Implemented clear memory register.
- Only acknowledge correct I2C device Id.
This commit is contained in:
Nigel Barnes 2025-02-16 20:07:46 +00:00
parent e7ed19e2da
commit e45679e227
4 changed files with 271 additions and 243 deletions

View File

@ -2,17 +2,23 @@
// copyright-holders:Nigel Barnes
/*********************************************************************
Philips SAA5240 European Controlled Teletext Circuit
Philips SAA5240 European Controlled Teletext Circuit (CCT)
TODO:
- implement data acquisition.
- output interlaced video.
*********************************************************************/
#include "emu.h"
#include "saa5240.h"
#include "screen.h"
#define LOG_DATA (1U << 1)
#define LOG_LINE (1U << 2)
#define VERBOSE (LOG_DATA)
#define VERBOSE (0)
#include "logmacro.h"
@ -22,44 +28,22 @@ DEFINE_DEVICE_TYPE(SAA5243E, saa5243e_device, "saa5243e", "SAA5243E EURO CCT")
//DEFINE_DEVICE_TYPE(SAA5243H, saa5243h_device, "saa5243h", "SAA5243H EURO CCT")
//-------------------------------------------------
// default address map
//-------------------------------------------------
void saa5240_device::saa5240_vram(address_map &map)
{
if (!has_configured_map(0))
map(0x0000, 0x1fff).ram();
}
//-------------------------------------------------
// memory_space_config - return a description of
// any address spaces owned by this device
//-------------------------------------------------
device_memory_interface::space_config_vector saa5240_device::memory_space_config() const
{
return space_config_vector {
std::make_pair(0, &m_space_config)
};
}
//-------------------------------------------------
// ROM( saa5240 )
//-------------------------------------------------
ROM_START( saa5240a )
ROM_REGION16_BE( 0xc80, "chargen", ROMREGION_ERASE00 )
ROM_START(saa5240a)
ROM_REGION16_BE(0xc80, "chargen", ROMREGION_ERASE00)
ROM_LOAD("saa5240a", 0x0280, 0x0a00, BAD_DUMP CRC(e205d1fc) SHA1(cb6872260c91f0665f8c7d691c9becc327e0ecc3)) // hand made from datasheet
ROM_END
ROM_START( saa5240b )
ROM_REGION16_BE( 0xc80, "chargen", ROMREGION_ERASE00 )
ROM_START(saa5240b)
ROM_REGION16_BE(0xc80, "chargen", ROMREGION_ERASE00)
ROM_LOAD("saa5240b", 0x0280, 0x0a00, BAD_DUMP CRC(7b196f2c) SHA1(61d4460ed0956ff470cc1362ea6bb1f9abe4bc03)) // hand made from datasheet
ROM_END
ROM_START( saa5243e )
ROM_REGION16_BE( 0x1180, "chargen", ROMREGION_ERASE00 )
ROM_START(saa5243e)
ROM_REGION16_BE(0x1180, "chargen", ROMREGION_ERASE00)
ROM_LOAD("saa5243e", 0x0280, 0x0f00, BAD_DUMP CRC(a74402e7) SHA1(48123c9bb0377e417a147f5a68088c1ed7bee12d)) // hand made from datasheet
ROM_END
@ -70,26 +54,20 @@ ROM_END
const tiny_rom_entry *saa5240a_device::device_rom_region() const
{
return ROM_NAME( saa5240a );
return ROM_NAME(saa5240a);
}
const tiny_rom_entry *saa5240b_device::device_rom_region() const
{
return ROM_NAME( saa5240b );
return ROM_NAME(saa5240b);
}
const tiny_rom_entry *saa5243e_device::device_rom_region() const
{
return ROM_NAME( saa5243e );
return ROM_NAME(saa5243e);
}
#define ALPHANUMERIC 0x01
#define CONTIGUOUS 0x02
#define SEPARATED 0x03
//**************************************************************************
// LIVE DEVICE
//**************************************************************************
@ -100,9 +78,8 @@ const tiny_rom_entry *saa5243e_device::device_rom_region() const
saa5240_device::saa5240_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock)
: device_t(mconfig, type, tag, owner, clock)
, device_memory_interface(mconfig, *this)
, m_char_rom(*this, "chargen")
, m_space_config("videoram", ENDIANNESS_LITTLE, 8, 13, 0, address_map_constructor(FUNC(saa5240a_device::saa5240_vram), this))
, m_ram_size(0x2000)
, m_slave_address(SAA5240_SLAVE_ADDRESS)
, m_i2c_scl(0)
, m_i2c_sdaw(0)
@ -115,18 +92,18 @@ saa5240_device::saa5240_device(const machine_config &mconfig, device_type type,
{
}
saa5240a_device::saa5240a_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) :
saa5240_device(mconfig, SAA5240A, tag, owner, clock)
saa5240a_device::saa5240a_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
: saa5240_device(mconfig, SAA5240A, tag, owner, clock)
{
}
saa5240b_device::saa5240b_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) :
saa5240_device(mconfig, SAA5240B, tag, owner, clock)
saa5240b_device::saa5240b_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
: saa5240_device(mconfig, SAA5240B, tag, owner, clock)
{
}
saa5243e_device::saa5243e_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) :
saa5240_device(mconfig, SAA5243E, tag, owner, clock)
saa5243e_device::saa5243e_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
: saa5240_device(mconfig, SAA5243E, tag, owner, clock)
{
}
@ -137,9 +114,21 @@ saa5243e_device::saa5243e_device(const machine_config &mconfig, const char *tag,
void saa5240_device::device_start()
{
m_videoram = &space(0);
m_ram = make_unique_clear<uint8_t[]>(m_ram_size);
// memory is cleared to 'space' on power-up
std::memset(m_ram.get(), 0x20, m_ram_size);
// row 0 column 7 chapter 0 is alpha white
m_ram[0x07] = 0x07;
// registers cleared on power-up, except R5 and R6
std::fill(std::begin(m_register), std::end(m_register), 0x00);
m_register[5] = 0x03;
m_register[6] = 0x03;
// state saving
save_pointer(NAME(m_ram), m_ram_size);
save_item(NAME(m_i2c_scl));
save_item(NAME(m_i2c_sdaw));
save_item(NAME(m_i2c_sdar));
@ -152,21 +141,6 @@ void saa5240_device::device_start()
save_item(NAME(m_slave_address));
}
void saa5240_device::device_reset()
{
// memmory is cleared to 'space' on power-up
for (int i = 0; i < 0x1fff; i++)
m_videoram->write_byte(i, 0x20);
// row 0 column 7 chapter 0 is alpha white
m_videoram->write_byte(7, 0x07);
// reset registers
std::fill(std::begin(m_register), std::end(m_register), 0x00);
m_register[5] = 0x03;
m_register[6] = 0x03;
}
//**************************************************************************
// READ/WRITE HANDLERS
@ -196,78 +170,86 @@ void saa5240_device::write_scl(int state)
{
if (m_i2c_scl)
{
switch (m_i2c_state)
{
case STATE_DEVSEL:
m_i2c_devsel = m_i2c_shift;
if ((m_i2c_devsel & 0xfe) != m_slave_address)
{
LOGMASKED(LOG_DATA, "devsel %02x: not this device\n", m_i2c_devsel);
m_i2c_state = STATE_IDLE;
}
else if ((m_i2c_devsel & 1) == 0)
{
LOGMASKED(LOG_DATA, "devsel %02x: write\n", m_i2c_devsel);
m_i2c_state = STATE_ADDRESS;
}
else
{
LOGMASKED(LOG_DATA, "devsel %02x: read\n", m_i2c_devsel);
m_i2c_state = STATE_DATAOUT;
}
break;
case STATE_ADDRESS:
m_i2c_address = m_i2c_shift;
LOGMASKED(LOG_DATA, "address %02x\n", m_i2c_shift);
m_i2c_state = STATE_DATAIN;
break;
case STATE_DATAIN:
m_register[m_i2c_address] = m_i2c_shift;
LOGMASKED(LOG_DATA, "data[ %02x ] <- %02x\n", m_i2c_address, m_i2c_shift);
switch (m_i2c_address)
{
case 1: case 2: case 3: case 4: case 5: case 6:
// auto-increment register
m_i2c_address++;
break;
case 8:
// active chapter - clear memory
//if (BIT(m_register[8], 3))
//{
// for (int i = 0; i < 0x3ff; i++)
// m_videoram->write_byte((m_register[8] & 0x07) * 0x400 + i, 0x20);
//}
[[fallthrough]];
case 9: case 10:
update_active_data();
// auto-increment register
m_i2c_address++;
break;
case 11:
// active data
offs_t offset = (m_register[8] & 0x07) * 0x400 + (m_register[9] & 0x1f) * 40 + (m_register[10] & 0x3f);
m_videoram->write_byte(offset, m_i2c_shift);
increment_active_data();
break;
}
break;
}
m_i2c_bits++;
}
else
{
if (m_i2c_bits == 8)
{
m_i2c_sdar = 0;
switch (m_i2c_state)
{
case STATE_DEVSEL:
m_i2c_devsel = m_i2c_shift;
if ((m_i2c_devsel & 0xfe) != m_slave_address)
{
LOGMASKED(LOG_DATA, "devsel %02x: not this device\n", m_i2c_devsel);
m_i2c_state = STATE_IDLE;
}
else if ((m_i2c_devsel & 1) == 0)
{
LOGMASKED(LOG_DATA, "devsel %02x: write\n", m_i2c_devsel);
m_i2c_state = STATE_ADDRESS;
}
else
{
LOGMASKED(LOG_DATA, "devsel %02x: read\n", m_i2c_devsel);
m_i2c_state = STATE_READSELACK;
}
break;
case STATE_ADDRESS:
m_i2c_address = m_i2c_shift;
LOGMASKED(LOG_DATA, "address %02x\n", m_i2c_shift);
m_i2c_state = STATE_DATAIN;
break;
case STATE_DATAIN:
m_register[m_i2c_address] = m_i2c_shift;
LOGMASKED(LOG_DATA, "data[ %02x ] <- %02x\n", m_i2c_address, m_i2c_shift);
switch (m_i2c_address)
{
case 1: // Mode
case 2: // Page request address
case 3: // Page request data
case 4: // Display chapter
case 5: // Display control (normal)
case 6: // Display control (newsflash/subtitle)
m_i2c_address++; // auto-increment register
break;
case 7: // Display mode
break;
case 8: // Active chapter
if (BIT(m_register[8], 3))
{
// clear memory
for (int i = 0; i < 0x400; i++)
m_ram[ram_addr(m_register[8], 0, 0) + i] = 0x20;
}
[[fallthrough]];
case 9: // Active row
case 10: // Active column
update_active_data();
m_i2c_address++; // auto-increment register
break;
case 11: // Active data
m_ram[ram_addr(m_register[8], m_register[9], m_register[10])] = m_i2c_shift;
increment_active_data();
break;
}
break;
}
if (m_i2c_state != STATE_IDLE)
{
m_i2c_sdar = 0;
}
}
else
{
@ -278,10 +260,19 @@ void saa5240_device::write_scl(int state)
}
break;
case STATE_READSELACK:
m_i2c_bits = 0;
m_i2c_state = STATE_DATAOUT;
break;
case STATE_DATAOUT:
if (m_i2c_bits < 8)
{
if (m_i2c_scl)
{
m_i2c_bits++;
}
else
{
if (m_i2c_bits == 0)
{
@ -291,8 +282,7 @@ void saa5240_device::write_scl(int state)
if (m_i2c_address == 11)
increment_active_data();
// FIXME: is this conditional?
if (BIT(m_register[1], 6))
if (!BIT(m_register[1], 6))
{
// 7 bits with parity checking
m_i2c_shift &= 0x7f;
@ -303,7 +293,6 @@ void saa5240_device::write_scl(int state)
m_i2c_sdar = (m_i2c_shift >> 7) & 1;
m_i2c_shift = (m_i2c_shift << 1) & 0xff;
m_i2c_bits++;
}
}
else
@ -316,18 +305,12 @@ void saa5240_device::write_scl(int state)
m_i2c_state = STATE_IDLE;
}
m_i2c_bits++;
m_i2c_bits = 0;
}
else
{
if (m_i2c_bits == 8)
{
m_i2c_sdar = 1;
}
else
{
m_i2c_bits = 0;
}
m_i2c_sdar = 1;
}
}
break;
@ -372,6 +355,12 @@ int saa5240_device::read_sda()
}
uint16_t saa5240_device::ram_addr(int chapter, int row, int column)
{
uint16_t addr = (chapter & 0x07) * 0x400 + (row & 0x1f) * 40 + (column & 0x3f);
return addr & (m_ram_size - 1);
}
void saa5240_device::increment_active_data()
{
// auto-increment column
@ -388,8 +377,7 @@ void saa5240_device::increment_active_data()
void saa5240_device::update_active_data()
{
offs_t offset = (m_register[8] & 0x07) * 0x400 + (m_register[9] & 0x1f) * 40 + (m_register[10] & 0x3f);
m_register[11] = m_videoram->read_byte(offset);
m_register[11] = m_ram[ram_addr(m_register[8], m_register[9], m_register[10])];
}
//-------------------------------------------------
@ -400,17 +388,16 @@ int saa5240_device::calc_parity(uint8_t data)
{
uint8_t count = 0;
while(data != 0)
while (data != 0)
{
count++;
data &= (data-1);
data &= (data - 1);
}
return (count ^ 1) & 1;
}
//-------------------------------------------------
// process_control_character
//-------------------------------------------------
@ -565,16 +552,83 @@ uint16_t saa5240_device::get_gfx_data(uint8_t data, offs_t row, bool separated)
uint16_t saa5240_device::get_rom_data(uint8_t data, offs_t row)
{
uint16_t c;
if (row < 0 || row >= 10)
static const uint8_t nc_char_matrix[6][128] =
{
c = 0;
}
// SAA5240A - German / SAA5240B - Italian / SAA5243E - German
{
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f,
0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f,
0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f,
0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f,
0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f,
0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f
},
// SAA5240A - English / SAA5240B - German / SAA5243E - English
{
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
0x20, 0x21, 0x22, 0x83, 0x84, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f,
0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f,
0x80, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f,
0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f,
0x81, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f,
0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7a, 0x82, 0x88, 0x89, 0x8a, 0x7f
},
// SAA5240A - Swedish / SAA5240B - French / SAA5243E - Swedish
{
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
0x20, 0x21, 0x22, 0x93, 0x94, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f,
0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f,
0x90, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f,
0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f,
0x91, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f,
0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7a, 0x92, 0x98, 0x99, 0x9a, 0x7f
},
// SAA5243E - Italian
{
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
0x20, 0x21, 0x22, 0xa3, 0xa4, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f,
0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f,
0xa0, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f,
0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5a, 0xab, 0xac, 0xad, 0xae, 0xaf,
0xa1, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f,
0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7a, 0xa2, 0xa8, 0xa9, 0xaa, 0x7f
},
// SAA5243E - Spanish
{
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
0x20, 0x21, 0x22, 0xb3, 0xb4, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f,
0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f,
0xb0, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f,
0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5a, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf,
0xb1, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f,
0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7a, 0xb2, 0xb8, 0xb9, 0xba, 0x7f
},
// SAA5243E - Swedish
{
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
0x20, 0x21, 0x22, 0xc3, 0xc4, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f,
0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f,
0xc0, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f,
0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5a, 0xcb, 0xcc, 0xcd, 0xce, 0xcf,
0xc1, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f,
0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7a, 0xc2, 0xc8, 0xc9, 0xca, 0x7f
}
};
// decode national option characters
if (!BIT(data, 7))
data = nc_char_matrix[1][data]; // TODO: select character set from page header control bits
else
{
c = m_char_rom[(data * 10) + row];
}
return c;
data &= 0x7f;
return m_char_rom[(data * 10) + row];
}
@ -628,7 +682,7 @@ void saa5240_device::get_character_data(uint8_t data)
m_held_char = 32;
}
if (m_curr_chartype == ALPHANUMERIC || !BIT(data,5))
if (m_curr_chartype == ALPHANUMERIC || !BIT(data, 5))
m_char_data = get_rom_data(data, ra);
else
m_char_data = get_gfx_data(data, ra, (m_curr_chartype == SEPARATED));
@ -643,9 +697,6 @@ void saa5240_device::vcs_w(int state)
{
if (state)
{
m_ra++;
m_ra %= 10;
if (!m_ra)
{
if (m_double_height_bottom_row)
@ -706,33 +757,31 @@ int saa5240_device::get_rgb()
uint32_t saa5240_device::screen_update(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect)
{
for (int y = 0; y < 25 * 10; y++)
for (int y = cliprect.min_y; y <= cliprect.max_y; y++)
{
int sy = y / 10;
int x = 0;
int x = screen.visible_area().left();
m_ra = y % 10;
vcs_w(1);
vcs_w(0);
for (int sx = 0; sx < 40; sx++)
{
uint8_t code = m_videoram->read_byte((sy * 40) + sx) & 0x7f;
get_character_data(code);
// get display data
get_character_data(m_ram[ram_addr(m_register[4], sy, sx)]);
for (int bit = 0; bit < 12; bit++)
{
f6_w(1);
f6_w(0);
int color = get_rgb();
if (BIT(code, 7)) color ^= 0x07;
int r = BIT(color, 0) * 0xff;
int g = BIT(color, 1) * 0xff;
int b = BIT(color, 2) * 0xff;
bitmap.pix(y, x++) = rgb_t(r, g, b);
// cursor on at active row/column
if (BIT(m_register[7], 6) && (sy == m_register[9]) && (sx == m_register[10]))
bitmap.pix(y, x++) = rgb_t::white();
else
bitmap.pix(y, x++) = rgb_t(pal1bit(BIT(get_rgb(), 0)), pal1bit(BIT(get_rgb(), 1)), pal1bit(BIT(get_rgb(), 2)));
}
}
}

View File

@ -38,28 +38,20 @@
#pragma once
//**************************************************************************
// CONSTANTS
//**************************************************************************
#define SAA5240_SLAVE_ADDRESS ( 0x22 )
//**************************************************************************
// TYPE DEFINITIONS
//**************************************************************************
// ======================> saa5240_device
class saa5240_device :
public device_t,
public device_memory_interface
class saa5240_device : public device_t
{
public:
// construction/destruction
saa5240_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock);
void set_ram_size(uint16_t ram_size) { m_ram_size = ram_size; }
void write_scl(int state);
void write_sda(int state);
int read_sda();
@ -73,18 +65,16 @@ public:
protected:
saa5240_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock);
// device-level overrides
// device_t overrides
virtual void device_start() override ATTR_COLD;
virtual void device_reset() override ATTR_COLD;
// optional information overrides
virtual space_config_vector memory_space_config() const override;
private:
static constexpr uint8_t SAA5240_SLAVE_ADDRESS = 0x22;
required_region_ptr<uint16_t> m_char_rom;
const address_space_config m_space_config;
address_space *m_videoram;
std::unique_ptr<uint8_t[]> m_ram;
uint16_t m_ram_size;
// internal state
uint8_t m_register[12];
@ -98,12 +88,11 @@ private:
int m_i2c_devsel;
int m_i2c_address;
uint16_t ram_addr(int chapter, int row, int column);
void increment_active_data();
void update_active_data();
enum { STATE_IDLE, STATE_DEVSEL, STATE_ADDRESS, STATE_DATAIN, STATE_DATAOUT };
void saa5240_vram(address_map &map) ATTR_COLD;
enum { STATE_IDLE, STATE_DEVSEL, STATE_ADDRESS, STATE_DATAIN, STATE_DATAOUT, STATE_READSELACK };
enum
{
@ -147,6 +136,10 @@ private:
uint16_t get_rom_data(uint8_t data, offs_t row);
void get_character_data(uint8_t data);
static constexpr uint8_t ALPHANUMERIC = 0x01;
static constexpr uint8_t CONTIGUOUS = 0x02;
static constexpr uint8_t SEPARATED = 0x03;
uint8_t m_held_char;
uint8_t m_next_chartype;
uint8_t m_curr_chartype;

View File

@ -25,22 +25,22 @@
#include "emu.h"
#include "bus/centronics/ctronics.h"
#include "bus/econet/econet.h"
#include "bus/rs232/rs232.h"
#include "cpu/g65816/g65816.h"
#include "machine/6522via.h"
#include "machine/6850acia.h"
#include "machine/clock.h"
#include "machine/input_merger.h"
#include "machine/mc6854.h"
#include "machine/ram.h"
#include "machine/nvram.h"
#include "machine/pcf8573.h"
#include "machine/ram.h"
#include "machine/scn_pci.h"
#include "sound/beep.h"
#include "sound/pcd3311.h"
#include "video/saa5240.h"
#include "bus/econet/econet.h"
#include "bus/centronics/ctronics.h"
#include "bus/rs232/rs232.h"
#include "emupal.h"
#include "screen.h"
@ -110,6 +110,8 @@ private:
void ram_w(offs_t offset, uint8_t data);
uint8_t sheila_r(offs_t offset);
void sheila_w(offs_t offset, uint8_t data);
uint8_t via_pb_r();
void via_pb_w(uint8_t data);
void accomm_palette(palette_device &palette) const;
@ -509,32 +511,31 @@ uint8_t accomm_state::ram_r(offs_t offset)
}
else
{
switch (m_ram->size())
{
case 512 * 1024:
data = m_ram->pointer()[offset & 0x7ffff];
break;
case 1024 * 1024:
data = m_ram->pointer()[offset & 0xfffff];
break;
}
data = m_ram->pointer()[offset & m_ram->mask()];
}
return data;
}
void accomm_state::ram_w(offs_t offset, uint8_t data)
{
switch (m_ram->size())
{
case 512 * 1024:
m_ram->pointer()[offset & 0x7ffff] = data;
break;
m_ram->pointer()[offset & m_ram->mask()] = data;
}
case 1024 * 1024:
m_ram->pointer()[offset & 0xfffff] = data;
break;
}
uint8_t accomm_state::via_pb_r()
{
return 0xfe | (m_rtc->sda_r() & m_cct->read_sda());
}
void accomm_state::via_pb_w(uint8_t data)
{
data ^= 0xff;
m_rtc->sda_w(BIT(data, 1));
m_rtc->scl_w(BIT(data, 2));
m_cct->write_sda(BIT(data, 1));
m_cct->write_scl(BIT(data, 2));
}
@ -710,11 +711,6 @@ void accomm_state::main_map(address_map &map)
map(0xff0000, 0xffffff).rom().region("maincpu", 0x010000); /* ROM bank 1 (ROM Slot 0) */
}
void accomm_state::saa5240_map(address_map &map)
{
map.global_mask(0x07ff);
map(0x0000, 0x07ff).ram();
}
INPUT_CHANGED_MEMBER(accomm_state::trigger_reset)
{
@ -926,17 +922,14 @@ void accomm_state::accomm(machine_config &config)
/* teletext */
SAA5240A(config, m_cct, 6_MHz_XTAL);
m_cct->set_addrmap(0, &accomm_state::saa5240_map);
m_cct->set_ram_size(0x800);
/* via */
MOS6522(config, m_via, 16_MHz_XTAL / 16);
m_via->writepa_handler().set("cent_data_out", FUNC(output_latch_device::write));
m_via->ca2_handler().set("centronics", FUNC(centronics_device::write_strobe));
m_via->readpb_handler().set([this] () { return uint8_t(m_rtc->sda_r() & m_cct->read_sda()); });
m_via->writepb_handler().set(m_rtc, FUNC(pcf8573_device::sda_w)).bit(1).invert();
m_via->writepb_handler().append(m_rtc, FUNC(pcf8573_device::scl_w)).bit(2).invert();
m_via->writepb_handler().append(m_cct, FUNC(saa5240a_device::write_sda)).bit(1).invert();
m_via->writepb_handler().append(m_cct, FUNC(saa5240a_device::write_scl)).bit(2).invert();
m_via->readpb_handler().set(FUNC(accomm_state::via_pb_r));
m_via->writepb_handler().set(FUNC(accomm_state::via_pb_w));
m_via->irq_handler().set(m_irqs, FUNC(input_merger_device::in_w<0>));
/* rs423 */
@ -977,7 +970,7 @@ void accomm_state::accomm(machine_config &config)
econet.clk_wr_callback().append(m_adlc, FUNC(mc6854_device::rxc_w));
econet.data_wr_callback().set(m_adlc, FUNC(mc6854_device::set_rx));
ECONET_SLOT(config, "econet254", "econet", econet_devices).set_slot(254);
ECONET_SLOT(config, "econet254", "econet", econet_devices);
/* printer */
centronics_device &centronics(CENTRONICS(config, "centronics", centronics_devices, "printer"));
@ -993,7 +986,7 @@ void accomm_state::accommi(machine_config &config)
/* teletext */
SAA5240B(config.replace(), m_cct, 6_MHz_XTAL);
m_cct->set_addrmap(0, &accomm_state::saa5240_map);
m_cct->set_ram_size(0x800);
}

View File

@ -32,7 +32,7 @@
------------------
22 SAA5240
A2 PCF8582
C0 ?
C0 SAB3036
TODO:
- implement keypad
@ -84,7 +84,6 @@ private:
void i2c_w(uint8_t data);
void mem_map(address_map &map) ATTR_COLD;
void saa5240_map(address_map &map) ATTR_COLD;
required_device<i80186_cpu_device> m_maincpu;
required_device<screen_device> m_screen;
@ -109,7 +108,7 @@ void datacast_state::mem_map(address_map &map)
map(0x00000, 0x7ffff).ram();
map(0xc0000, 0xc0000).rw(FUNC(datacast_state::keypad_r), FUNC(datacast_state::keypad_w)).umask16(0x00ff);
map(0xc0080, 0xc0080).lr8([]() { return 0xff; }, "dips"); // unknown purpose
map(0xc0100, 0xc010f).noprw(); //.rw(m_saa5250, FUNC(saa5250_device::read), FUNC(saa5250_device::write)).umask16(0x00ff);
map(0xc0100, 0xc010f).noprw(); //.rw(m_cidac, FUNC(saa5250_device::read), FUNC(saa5250_device::write)).umask16(0x00ff);
map(0xc0180, 0xc0180).rw(FUNC(datacast_state::i2c_r), FUNC(datacast_state::i2c_w)).umask16(0x00ff);
map(0xc0200, 0xc0203).rw(m_usart[0], FUNC(i8251_device::read), FUNC(i8251_device::write)).umask16(0x00ff);
map(0xc0280, 0xc0280).w(m_dbrg, FUNC(com8116_device::stt_str_w));
@ -117,12 +116,6 @@ void datacast_state::mem_map(address_map &map)
map(0xf0000, 0xfffff).rom().region("rom", 0);
}
void datacast_state::saa5240_map(address_map &map)
{
map.global_mask(0x07ff);
map(0x0000, 0x07ff).ram();
}
static INPUT_PORTS_START(datacast)
PORT_START("X1")
@ -158,7 +151,7 @@ INPUT_PORTS_END
uint8_t datacast_state::keypad_r()
{
uint8_t data = (m_kb->read() << 0) | (m_kb->da_r() << 5);
logerror("keypad_r: %02x\n", data);
logerror("%s keypad_r: %02x\n", machine().describe_context(), data);
return data;
}
@ -166,13 +159,13 @@ void datacast_state::keypad_w(uint8_t data)
{
m_key_col = data;
logerror("keypad_w: %02x\n", data);
logerror("%s keypad_w: %02x\n", machine().describe_context(), data);
}
uint8_t datacast_state::i2c_r()
{
return m_i2cmem->read_sda() & m_cct->read_sda();
return m_i2cmem->read_sda() & m_cct->read_sda();
}
void datacast_state::i2c_w(uint8_t data)
@ -203,10 +196,10 @@ void datacast_state::datacast(machine_config &config)
//SAA5231(config, m_saa5231, 13.875_MHz_XTAL);
SAA5240A(config, m_cct, 6_MHz_XTAL);
m_cct->set_addrmap(0, &datacast_state::saa5240_map);
m_cct->set_ram_size(0x800);
//SAA5250(config, m_saa5250, 0);
//m_saa5250->set_addrmap(0, &datacast_state::saa5250_map); // 2K RAM
//SAA5250(config, m_cidac, 0);
//m_cidac->set_buffer_size(0x800);
I2C_PCF8582(config, m_i2cmem).set_e0(1);