diff options
Diffstat (limited to 'src/devices/video/saa5240.cpp')
-rw-r--r-- | src/devices/video/saa5240.cpp | 790 |
1 files changed, 790 insertions, 0 deletions
diff --git a/src/devices/video/saa5240.cpp b/src/devices/video/saa5240.cpp new file mode 100644 index 00000000000..52b653b0709 --- /dev/null +++ b/src/devices/video/saa5240.cpp @@ -0,0 +1,790 @@ +// license:BSD-3-Clause +// copyright-holders:Nigel Barnes +/********************************************************************* + + 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 (0) +#include "logmacro.h" + + +DEFINE_DEVICE_TYPE(SAA5240A, saa5240a_device, "saa5240a", "SAA5240A EURO CCT") +DEFINE_DEVICE_TYPE(SAA5240B, saa5240b_device, "saa5240b", "SAA5240B EURO CCT") +DEFINE_DEVICE_TYPE(SAA5243E, saa5243e_device, "saa5243e", "SAA5243E EURO CCT") +//DEFINE_DEVICE_TYPE(SAA5243H, saa5243h_device, "saa5243h", "SAA5243H EURO CCT") + + +//------------------------------------------------- +// ROM( saa5240 ) +//------------------------------------------------- + +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_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_LOAD("saa5243e", 0x0280, 0x0f00, BAD_DUMP CRC(a74402e7) SHA1(48123c9bb0377e417a147f5a68088c1ed7bee12d)) // hand made from datasheet +ROM_END + + +//------------------------------------------------- +// rom_region - device-specific ROM region +//------------------------------------------------- + +const tiny_rom_entry *saa5240a_device::device_rom_region() const +{ + return ROM_NAME(saa5240a); +} + +const tiny_rom_entry *saa5240b_device::device_rom_region() const +{ + return ROM_NAME(saa5240b); +} + +const tiny_rom_entry *saa5243e_device::device_rom_region() const +{ + return ROM_NAME(saa5243e); +} + + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// saa5240_device - constructor +//------------------------------------------------- + +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) + , m_char_rom(*this, "chargen") + , m_ram_size(0x2000) + , m_slave_address(SAA5240_SLAVE_ADDRESS) + , m_i2c_scl(0) + , m_i2c_sdaw(0) + , m_i2c_sdar(1) + , m_i2c_state(STATE_IDLE) + , m_i2c_bits(0) + , m_i2c_shift(0) + , m_i2c_devsel(0) + , m_i2c_address(0) +{ +} + +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) +{ +} + +saa5243e_device::saa5243e_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) + : saa5240_device(mconfig, SAA5243E, tag, owner, clock) +{ +} + + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void saa5240_device::device_start() +{ + 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)); + save_item(NAME(m_i2c_state)); + save_item(NAME(m_i2c_bits)); + save_item(NAME(m_i2c_shift)); + save_item(NAME(m_i2c_devsel)); + save_item(NAME(m_i2c_address)); + save_item(NAME(m_register)); + save_item(NAME(m_slave_address)); +} + + +//************************************************************************** +// READ/WRITE HANDLERS +//************************************************************************** + +void saa5240_device::write_scl(int state) +{ + if (m_i2c_scl != state) + { + m_i2c_scl = state; + LOGMASKED(LOG_LINE, "set_scl_line %d\n", m_i2c_scl); + + switch (m_i2c_state) + { + case STATE_DEVSEL: + case STATE_ADDRESS: + case STATE_DATAIN: + if (m_i2c_bits < 8) + { + if (m_i2c_scl) + { + m_i2c_shift = ((m_i2c_shift << 1) | m_i2c_sdaw) & 0xff; + m_i2c_bits++; + } + } + else + { + if (m_i2c_scl) + { + m_i2c_bits++; + } + else + { + if (m_i2c_bits == 8) + { + 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 + { + m_i2c_bits = 0; + m_i2c_sdar = 1; + } + } + } + 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) + { + m_i2c_shift = m_register[m_i2c_address]; + LOGMASKED(LOG_DATA, "data[ %02x ] -> %02x\n", m_i2c_address, m_i2c_shift); + + if (m_i2c_address == 11) + increment_active_data(); + + if (!BIT(m_register[1], 6)) + { + // 7 bits with parity checking + m_i2c_shift &= 0x7f; + m_i2c_shift = (m_i2c_shift << 1) | calc_parity(m_i2c_shift); + } + } + + m_i2c_sdar = (m_i2c_shift >> 7) & 1; + + m_i2c_shift = (m_i2c_shift << 1) & 0xff; + } + } + else + { + if (m_i2c_scl) + { + if (m_i2c_sdaw) + { + LOGMASKED(LOG_DATA, "nack\n"); + m_i2c_state = STATE_IDLE; + } + + m_i2c_bits = 0; + } + else + { + + m_i2c_sdar = 1; + } + } + break; + } + } +} + +void saa5240_device::write_sda(int state) +{ + state &= 1; + if (m_i2c_sdaw != state) + { + LOGMASKED(LOG_LINE, "set sda %d\n", state); + m_i2c_sdaw = state; + + if (m_i2c_scl) + { + if (m_i2c_sdaw) + { + LOGMASKED(LOG_DATA, "stop\n"); + m_i2c_state = STATE_IDLE; + } + else + { + LOGMASKED(LOG_DATA, "start\n"); + m_i2c_state = STATE_DEVSEL; + m_i2c_bits = 0; + } + + m_i2c_sdar = 1; + } + } +} + +int saa5240_device::read_sda() +{ + int res = m_i2c_sdar & 1; + + LOGMASKED(LOG_LINE, "read sda %d\n", res); + + return res; +} + + +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 + m_register[10]++; + + if (m_register[10] >= 40) + { + m_register[10] = 0; + m_register[9]++; + } + + update_active_data(); +} + +void saa5240_device::update_active_data() +{ + m_register[11] = m_ram[ram_addr(m_register[8], m_register[9], m_register[10])]; +} + +//------------------------------------------------- +// calculate the byte parity +//------------------------------------------------- + +int saa5240_device::calc_parity(uint8_t data) +{ + uint8_t count = 0; + + while (data != 0) + { + count++; + data &= (data - 1); + } + + return (count ^ 1) & 1; +} + + +//------------------------------------------------- +// process_control_character +//------------------------------------------------- + +void saa5240_device::process_control_character(uint8_t data) +{ + m_hold_clear = false; + m_hold_off = false; + + switch (data) + { + case ALPHA_RED: + case ALPHA_GREEN: + case ALPHA_YELLOW: + case ALPHA_BLUE: + case ALPHA_MAGENTA: + case ALPHA_CYAN: + case ALPHA_WHITE: + m_graphics = false; + m_hold_clear = true; + m_fg = data & 0x07; + set_next_chartype(); + break; + + case FLASH: + m_flash = true; + break; + + case STEADY: + m_flash = false; + break; + + case END_BOX: + case START_BOX: + // TODO + break; + + case NORMAL_HEIGHT: + case DOUBLE_HEIGHT: + m_double_height = !!(data & 1); + if (m_double_height) m_double_height_prev_row = true; + break; + + case GRAPHICS_RED: + case GRAPHICS_GREEN: + case GRAPHICS_YELLOW: + case GRAPHICS_BLUE: + case GRAPHICS_MAGENTA: + case GRAPHICS_CYAN: + case GRAPHICS_WHITE: + m_graphics = true; + m_fg = data & 0x07; + set_next_chartype(); + break; + + case CONCEAL_DISPLAY: + m_fg = m_prev_col = m_bg; + break; + + case CONTIGUOUS_GFX: + m_separated = false; + set_next_chartype(); + break; + + case SEPARATED_GFX: + m_separated = true; + set_next_chartype(); + break; + + case BLACK_BACKGROUND: + m_bg = 0; + break; + + case NEW_BACKGROUND: + m_bg = m_fg; + break; + + case HOLD_GRAPHICS: + m_hold_char = true; + break; + + case RELEASE_GRAPHICS: + m_hold_off = true; + break; + } +} + + +void saa5240_device::set_next_chartype() +{ + if (m_graphics) + { + if (m_separated) + m_next_chartype = SEPARATED; + else + m_next_chartype = CONTIGUOUS; + } + else + { + m_next_chartype = ALPHANUMERIC; + } +}; + + +//------------------------------------------------- +// get_gfx_data - graphics generator +//------------------------------------------------- + +uint16_t saa5240_device::get_gfx_data(uint8_t data, offs_t row, bool separated) +{ + uint16_t c = 0; + switch (row >> 1) + { + case 0: case 1: + c += (data & 0x01) ? 0xfc0 : 0; // bit 1 top left + c += (data & 0x02) ? 0x03f : 0; // bit 2 top right + if (separated) c &= 0x3cf; + break; + case 2: + if (separated) break; + c += (data & 0x01) ? 0xfc0 : 0; // bit 1 top left + c += (data & 0x02) ? 0x03f : 0; // bit 2 top right + break; + case 3: case 4: case 5: + c += (data & 0x04) ? 0xfc0 : 0; // bit 3 middle left + c += (data & 0x08) ? 0x03f : 0; // bit 4 middle right + if (separated) c &= 0x3cf; + break; + case 6: + if (separated) break; + c += (data & 0x04) ? 0xfc0 : 0; // bit 3 middle left + c += (data & 0x08) ? 0x03f : 0; // bit 4 middle right + break; + case 7: case 8: + c += (data & 0x10) ? 0xfc0 : 0; // bit 5 bottom left + c += (data & 0x40) ? 0x03f : 0; // bit 7 bottom right + if (separated) c &= 0x3cf; + break; + case 9: + if (separated) break; + c += (data & 0x10) ? 0xfc0 : 0; // bit 5 bottom left + c += (data & 0x40) ? 0x03f : 0; // bit 7 bottom right + break; + } + return c; +} + + +//------------------------------------------------- +// get_rom_data - read rom +//------------------------------------------------- + +uint16_t saa5240_device::get_rom_data(uint8_t data, offs_t row) +{ + static const uint8_t nc_char_matrix[6][128] = + { + // 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 + data &= 0x7f; + + return m_char_rom[(data * 10) + row]; +} + + +//------------------------------------------------- +// get_character_data +//------------------------------------------------- + +void saa5240_device::get_character_data(uint8_t data) +{ + m_double_height_old = m_double_height; + m_prev_col = m_fg; + m_curr_chartype = m_next_chartype; + + if (data < 0x20) + { + process_control_character(data); + if (m_hold_char && m_double_height == m_double_height_old) + { + data = m_held_char; + if (data >= 0x40 && data < 0x60) data = 0x20; + m_curr_chartype = m_held_chartype; + } + else + { + data = 0x20; + } + } + else if (m_graphics) + { + m_held_char = data; + m_held_chartype = m_curr_chartype; + } + + offs_t ra = m_ra; + if (m_double_height_old) + { + ra >>= 1; + if (m_double_height_bottom_row) ra += 10; + } + + if (m_flash && (m_frame_count > 38)) data = 0x20; + if (m_double_height_bottom_row && !m_double_height) data = 0x20; + + if (m_hold_off) + { + m_hold_char = false; + m_held_char = 32; + } + if (m_hold_clear) + { + m_held_char = 32; + } + + 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)); +} + + +//------------------------------------------------- +// vcs_w - video composite sync +//------------------------------------------------- + +void saa5240_device::vcs_w(int state) +{ + if (state) + { + if (!m_ra) + { + if (m_double_height_bottom_row) + m_double_height_bottom_row = false; + else + m_double_height_bottom_row = m_double_height_prev_row; + } + + m_fg = 7; + m_bg = 0; + m_graphics = false; + m_separated = false; + m_flash = false; + m_boxed = false; + m_hold_char = false; + m_held_char = 0x20; + m_next_chartype = ALPHANUMERIC; + m_held_chartype = ALPHANUMERIC; + m_double_height = false; + m_double_height_prev_row = false; + m_bit = 11; + } +} + + +//------------------------------------------------- +// f6_w - character display clock +//------------------------------------------------- + +void saa5240_device::f6_w(int state) +{ + if (state) + { + m_color = BIT(m_char_data, m_bit) ? m_prev_col : m_bg; + + m_bit--; + if (m_bit < 0) + { + m_bit = 11; + } + } +} + + +//------------------------------------------------- +// get_rgb - get output color +//------------------------------------------------- + +int saa5240_device::get_rgb() +{ + return m_color; +} + + +//------------------------------------------------- +// screen_update +//------------------------------------------------- + +uint32_t saa5240_device::screen_update(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect) +{ + for (int y = cliprect.min_y; y <= cliprect.max_y; y++) + { + int sy = y / 10; + int x = screen.visible_area().left(); + + m_ra = y % 10; + + vcs_w(1); + vcs_w(0); + + for (int sx = 0; sx < 40; sx++) + { + // 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); + + // 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))); + } + } + } + + return 0; +} |