diff options
Diffstat (limited to 'src/devices/video/ef9345.cpp')
-rw-r--r-- | src/devices/video/ef9345.cpp | 1021 |
1 files changed, 1021 insertions, 0 deletions
diff --git a/src/devices/video/ef9345.cpp b/src/devices/video/ef9345.cpp new file mode 100644 index 00000000000..ca8062bbb95 --- /dev/null +++ b/src/devices/video/ef9345.cpp @@ -0,0 +1,1021 @@ +// license:GPL-2.0+ +// copyright-holders:Daniel Coulom,Sandro Ronco +/********************************************************************* + + ef9345.c + + Thomson EF9345 video controller emulator code + + This code is based on Daniel Coulom's implementation in DCVG5k + and DCAlice released by Daniel Coulom under GPL license + +*********************************************************************/ + +#include "emu.h" +#include "ef9345.h" + +#define MODE24x40 0 +#define MODEVAR40 1 +#define MODE8x80 2 +#define MODE12x80 3 +#define MODE16x40 4 + +//************************************************************************** +// GLOBAL VARIABLES +//************************************************************************** + +// devices +const device_type EF9345 = &device_creator<ef9345_device>; + +// default address map +static ADDRESS_MAP_START( ef9345, AS_0, 8, ef9345_device ) + AM_RANGE(0x0000, 0x3fff) AM_RAM +ADDRESS_MAP_END + +//------------------------------------------------- +// memory_space_config - return a description of +// any address spaces owned by this device +//------------------------------------------------- + +const address_space_config *ef9345_device::memory_space_config(address_spacenum spacenum) const +{ + return (spacenum == AS_0) ? &m_space_config : NULL; +} + +//************************************************************************** +// INLINE HELPERS +//************************************************************************** + +// calculate the internal RAM offset +inline UINT16 ef9345_device::indexram(UINT8 r) +{ + UINT8 x = m_registers[r]; + UINT8 y = m_registers[r - 1]; + if (y < 8) + y &= 1; + return ((x&0x3f) | ((x & 0x40) << 6) | ((x & 0x80) << 4) | ((y & 0x1f) << 6) | ((y & 0x20) << 8)); +} + +// calculate the internal ROM offset +inline UINT16 ef9345_device::indexrom(UINT8 r) +{ + UINT8 x = m_registers[r]; + UINT8 y = m_registers[r - 1]; + if (y < 8) + y &= 1; + return((x&0x3f)|((x&0x40)<<6)|((x&0x80)<<4)|((y&0x1f)<<6)); +} + +// increment x +inline void ef9345_device::inc_x(UINT8 r) +{ + UINT8 i = (m_registers[r] & 0x3f) + 1; + if (i > 39) + { + i -= 40; + m_state |= 0x40; + } + m_registers[r] = (m_registers[r] & 0xc0) | i; +} + +// increment y +inline void ef9345_device::inc_y(UINT8 r) +{ + UINT8 i = (m_registers[r] & 0x1f) + 1; + if (i > 31) + i -= 24; + m_registers[r] = (m_registers[r] & 0xe0) | i; +} + + +//************************************************************************** +// live device +//************************************************************************** + +//------------------------------------------------- +// ef9345_device - constructor +//------------------------------------------------- + +ef9345_device::ef9345_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + device_t(mconfig, EF9345, "EF9345", tag, owner, clock, "ef9345", __FILE__), + device_memory_interface(mconfig, *this), + device_video_interface(mconfig, *this), + m_space_config("videoram", ENDIANNESS_LITTLE, 8, 16, 0, NULL, *ADDRESS_MAP_NAME(ef9345)), + m_palette(*this) +{ +} + +//------------------------------------------------- +// static_set_palette_tag: Set the tag of the +// palette device +//------------------------------------------------- + +void ef9345_device::static_set_palette_tag(device_t &device, const char *tag) +{ + downcast<ef9345_device &>(device).m_palette.set_tag(tag); +} + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void ef9345_device::device_start() +{ + m_busy_timer = timer_alloc(BUSY_TIMER); + m_blink_timer = timer_alloc(BLINKING_TIMER); + + m_videoram = &space(0); + m_charset = region(); + + m_screen_out.allocate(496, m_screen->height()); + + m_blink_timer->adjust(attotime::from_msec(500), 0, attotime::from_msec(500)); + + init_accented_chars(); + + save_item(NAME(m_border)); + save_item(NAME(m_registers)); + save_item(NAME(m_last_dial)); + save_item(NAME(m_ram_base)); + save_item(NAME(m_bf)); + save_item(NAME(m_char_mode)); + save_item(NAME(m_state)); + save_item(NAME(m_tgs)); + save_item(NAME(m_mat)); + save_item(NAME(m_pat)); + save_item(NAME(m_dor)); + save_item(NAME(m_ror)); + save_item(NAME(m_block)); + save_item(NAME(m_blink)); + save_item(NAME(m_latchc0)); + save_item(NAME(m_latchm)); + save_item(NAME(m_latchi)); + save_item(NAME(m_latchu)); + + save_item(NAME(m_screen_out)); +} + +//------------------------------------------------- +// device_reset - device-specific reset +//------------------------------------------------- +void ef9345_device::device_reset() +{ + m_tgs = m_mat = m_pat = m_dor = m_ror = 0; + m_state = 0; + m_bf = 0; + m_block = 0; + m_blink = 0; + m_latchc0 = 0; + m_latchm = 0; + m_latchi = 0; + m_latchu = 0; + m_char_mode = 0; + + memset(m_last_dial, 0, sizeof(m_last_dial)); + memset(m_registers, 0, sizeof(m_registers)); + memset(m_border, 0, sizeof(m_border)); + memset(m_border, 0, sizeof(m_ram_base)); + + m_screen_out.fill(0); + + set_video_mode(); +} + +//------------------------------------------------- +// device_timer - handler timer events +//------------------------------------------------- +void ef9345_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) +{ + switch(id) + { + case BUSY_TIMER: + m_bf = 0; + break; + + case BLINKING_TIMER: + m_blink = !m_blink; + break; + } +} + + +// set busy flag and timer to clear it +void ef9345_device::set_busy_flag(int period) +{ + m_bf = 1; + m_busy_timer->adjust(attotime::from_usec(period)); +} + +// draw a char in 40 char line mode +void ef9345_device::draw_char_40(UINT8 *c, UINT16 x, UINT16 y) +{ + //verify size limit + if (y * 10 >= m_screen->height() || x * 8 >= m_screen->width()) + return; + + const rgb_t *palette = m_palette->palette()->entry_list_raw(); + for(int i = 0; i < 10; i++) + for(int j = 0; j < 8; j++) + m_screen_out.pix32(y * 10 + i, x * 8 + j) = palette[c[8 * i + j] & 0x07]; +} + +// draw a char in 80 char line mode +void ef9345_device::draw_char_80(UINT8 *c, UINT16 x, UINT16 y) +{ + // verify size limit + if (y * 10 >= m_screen->height() || x * 6 >= m_screen->width()) + return; + + const rgb_t *palette = m_palette->palette()->entry_list_raw(); + for(int i = 0; i < 10; i++) + for(int j = 0; j < 6; j++) + m_screen_out.pix32(y * 10 + i, x * 6 + j) = palette[c[6 * i + j] & 0x07]; +} + + +// set then ef9345 mode +void ef9345_device::set_video_mode(void) +{ + m_char_mode = ((m_pat & 0x80) >> 5) | ((m_tgs & 0xc0) >> 6); + UINT16 new_width = (m_char_mode == MODE12x80 || m_char_mode == MODE8x80) ? 492 : 336; + + if (m_screen->width() != new_width) + { + rectangle visarea = m_screen->visible_area(); + visarea.max_x = new_width - 1; + + m_screen->configure(new_width, m_screen->height(), visarea, m_screen->frame_period().attoseconds()); + } + + //border color + memset(m_border, m_mat & 0x07, sizeof(m_border)); + + //set the base for the m_videoram charset + m_ram_base[0] = ((m_dor & 0x07) << 11); + m_ram_base[1] = m_ram_base[0]; + m_ram_base[2] = ((m_dor & 0x30) << 8); + m_ram_base[3] = m_ram_base[2] + 0x0800; + + //address of the current memory block + m_block = 0x0800 * ((((m_ror & 0xf0) >> 4) | ((m_ror & 0x40) >> 5) | ((m_ror & 0x20) >> 3)) & 0x0c); +} + +// initialize the ef9345 accented chars +void ef9345_device::init_accented_chars(void) +{ + UINT16 i, j; + for(j = 0; j < 0x10; j++) + for(i = 0; i < 0x200; i++) + m_acc_char[(j << 9) + i] = m_charset->u8(0x0600 + i); + + for(j = 0; j < 0x200; j += 0x40) + for(i = 0; i < 4; i++) + { + m_acc_char[0x0200 + j + i + 4] |= 0x1c; //tilde + m_acc_char[0x0400 + j + i + 4] |= 0x10; //acute + m_acc_char[0x0400 + j + i + 8] |= 0x08; //acute + m_acc_char[0x0600 + j + i + 4] |= 0x04; //grave + m_acc_char[0x0600 + j + i + 8] |= 0x08; //grave + + m_acc_char[0x0a00 + j + i + 4] |= 0x1c; //tilde + m_acc_char[0x0c00 + j + i + 4] |= 0x10; //acute + m_acc_char[0x0c00 + j + i + 8] |= 0x08; //acute + m_acc_char[0x0e00 + j + i + 4] |= 0x04; //grave + m_acc_char[0x0e00 + j + i + 8] |= 0x08; //grave + + m_acc_char[0x1200 + j + i + 4] |= 0x08; //point + m_acc_char[0x1400 + j + i + 4] |= 0x14; //trema + m_acc_char[0x1600 + j + i + 32] |= 0x08; //cedilla + m_acc_char[0x1600 + j + i + 36] |= 0x04; //cedilla + + m_acc_char[0x1a00 + j + i + 4] |= 0x08; //point + m_acc_char[0x1c00 + j + i + 4] |= 0x14; //trema + m_acc_char[0x1e00 + j + i + 32] |= 0x08; //cedilla + m_acc_char[0x1e00 + j + i + 36] |= 0x04; //cedilla + } +} + +// read a char in charset or in m_videoram +UINT8 ef9345_device::read_char(UINT8 index, UINT16 addr) +{ + if (index < 0x04) + return m_charset->u8(0x0800*index + addr); + else if (index < 0x08) + return m_acc_char[0x0800*(index&3) + addr]; + else if (index < 0x0c) + return m_videoram->read_byte(m_ram_base[index-8] + addr); + else + return m_videoram->read_byte(addr); +} + +// calculate the dial position of the char +UINT8 ef9345_device::get_dial(UINT8 x, UINT8 attrib) +{ + if (x > 0 && m_last_dial[x-1] == 1) //top right + m_last_dial[x] = 2; + else if (x > 0 && m_last_dial[x-1] == 5) //half right + m_last_dial[x] = 10; + else if (m_last_dial[x] == 1) //bottom left + m_last_dial[x] = 4; + else if (m_last_dial[x] == 2) //bottom right + m_last_dial[x] = 8; + else if (m_last_dial[x] == 3) //lower half + m_last_dial[x] = 12; + else if (attrib == 1) //Left half + m_last_dial[x] = 5; + else if (attrib == 2) //half high + m_last_dial[x] = 3; + else if (attrib == 3) //top left + m_last_dial[x] = 1; + else //none + m_last_dial[x] = 0; + + return m_last_dial[x]; +} + +// zoom the char +void ef9345_device::zoom(UINT8 *pix, UINT16 n) +{ + UINT8 i, j; + if ((n & 0x0a) == 0) + for(i = 0; i < 80; i += 8) // 1, 4, 5 + for(j = 7; j > 0; j--) + pix[i + j] = pix[i + j / 2]; + + if ((n & 0x05) == 0) + for(i = 0; i < 80; i += 8) // 2, 8, 10 + for(j =0 ; j < 7; j++) + pix[i + j] = pix[i + 4 + j / 2]; + + if ((n & 0x0c) == 0) + for(i = 0; i < 8; i++) // 1, 2, 3 + for(j = 9; j > 0; j--) + pix[i + 8 * j] = pix[i + 8 * (j / 2)]; + + if ((n & 0x03) == 0) + for(i = 0; i < 8; i++) // 4, 8, 12 + for(j = 0; j < 9; j++) + pix[i + 8 * j] = pix[i + 40 + 8 * (j / 2)]; +} + + +// calculate the address of the char x,y +UINT16 ef9345_device::indexblock(UINT16 x, UINT16 y) +{ + UINT16 i = x, j; + j = (y == 0) ? ((m_tgs & 0x20) >> 5) : ((m_ror & 0x1f) + y - 1); + + //right side of a double width character + if ((m_tgs & 0x80) == 0 && x > 0) + { + if (m_last_dial[x - 1] == 1) i--; + if (m_last_dial[x - 1] == 4) i--; + if (m_last_dial[x - 1] == 5) i--; + } + + return 0x40 * j + i; +} + +// draw bichrome character (40 columns) +void ef9345_device::bichrome40(UINT8 type, UINT16 address, UINT8 dial, UINT16 iblock, UINT16 x, UINT16 y, UINT8 c0, UINT8 c1, UINT8 insert, UINT8 flash, UINT8 hided, UINT8 negative, UINT8 underline) +{ + UINT16 i; + UINT8 pix[80]; + + if (flash && m_pat & 0x40 && m_blink) + c1 = c0; //flash + if (hided && m_pat & 0x08) + c1 = c0; //hided + if (negative) //negative + { + i = c1; + c1 = c0; + c0 = i; + } + + if ((m_pat & 0x30) == 0x30) + insert = 0; //active area mark + if (insert == 0) + c1 += 8; //foreground color + if ((m_pat & 0x30) == 0x00) + insert = 1; //insert mode + if (insert == 0) + c0 += 8; //background color + + //draw the cursor + i = (m_registers[6] & 0x1f); + if (i < 8) + i &= 1; + + if (iblock == 0x40 * i + (m_registers[7] & 0x3f)) //cursor position + { + switch(m_mat & 0x70) + { + case 0x40: //00 = fixed complemented + c0 = (23 - c0) & 15; + c1 = (23 - c1) & 15; + break; + case 0x50: //01 = fixed underlined + underline = 1; + break; + case 0x60: //10 = flash complemented + if (m_blink) + { + c0 = (23 - c0) & 15; + c1 = (23 - c1) & 15; + } + break; + case 0x70: //11 = flash underlined + if (m_blink) + underline = 1; + break; + } + } + + // generate the pixel table + for(i = 0; i < 40; i+=4) + { + UINT8 ch = read_char(type, address + i); + + for (UINT8 b=0; b<8; b++) + pix[i*2 + b] = (ch & (1<<b)) ? c1 : c0; + } + + //draw the underline + if (underline) + memset(&pix[72], c1, 8); + + if (dial > 0) + zoom(pix, dial); + + //doubles the height of the char + if (m_mat & 0x80) + zoom(pix, (y & 0x01) ? 0x0c : 0x03); + + draw_char_40(pix, x + 1 , y + 1); +} + +// draw quadrichrome character (40 columns) +void ef9345_device::quadrichrome40(UINT8 c, UINT8 b, UINT8 a, UINT16 x, UINT16 y) +{ + //C0-6= character code + //B0= insert not yet implemented !!! + //B1= low resolution + //B2= subset index (low resolution only) + //B3-5 = set number + //A0-6 = 4 color palette + + UINT8 i, j, n, col[8], pix[80]; + UINT8 lowresolution = (b & 0x02) >> 1, ramx, ramy, ramblock; + UINT16 ramindex; + + //quadrichrome don't suppor double size + m_last_dial[x] = 0; + + //initialize the color table + for(j = 1, n = 0, i = 0; i < 8; i++) + { + col[n++] = (a & j) ? i : 7; + j <<= 1; + } + + //find block number in ram + ramblock = 0; + if (b & 0x20) ramblock |= 4; //B5 + if (b & 0x08) ramblock |= 2; //B3 + if (b & 0x10) ramblock |= 1; //B4 + + //find character address in ram + ramx = c & 0x03; + ramy =(c & 0x7f) >> 2; + ramindex = 0x0800 * ramblock + 0x40 * ramy + ramx; + if (lowresolution) ramindex += 5 * (b & 0x04); + + //fill pixel table + for(i = 0, j = 0; i < 10; i++) + { + UINT8 ch = read_char(0x0c, ramindex + 4 * (i >> lowresolution)); + pix[j] = pix[j + 1] = col[(ch & 0x03) >> 0]; j += 2; + pix[j] = pix[j + 1] = col[(ch & 0x0c) >> 2]; j += 2; + pix[j] = pix[j + 1] = col[(ch & 0x30) >> 4]; j += 2; + pix[j] = pix[j + 1] = col[(ch & 0xc0) >> 6]; j += 2; + } + + draw_char_40(pix, x + 1, y + 1); +} + +// draw bichrome character (80 columns) +void ef9345_device::bichrome80(UINT8 c, UINT8 a, UINT16 x, UINT16 y) +{ + UINT8 c0, c1, pix[60]; + UINT16 i, j, d; + + c1 = (a & 1) ? (m_dor >> 4) & 7 : m_dor & 7; //foreground color = DOR + c0 = m_mat & 7; //background color = MAT + + switch(c & 0x80) + { + case 0: //alphanumeric G0 set + //A0: D = color set + //A1: U = underline + //A2: F = flash + //A3: N = negative + //C0-6: character code + + if ((a & 4) && (m_pat & 0x40) && (m_blink)) + c1 = c0; //flash + if (a & 8) //negative + { + i = c1; + c1 = c0; + c0 = i; + } + + d = ((c & 0x7f) >> 2) * 0x40 + (c & 0x03); //char position + + for(i=0, j=0; i < 10; i++) + { + UINT8 ch = read_char(0, d + 4 * i); + for (UINT8 b=0; b<6; b++) + pix[j++] = (ch & (1<<b)) ? c1 : c0; + } + + //draw the underline + if (a & 2) + memset(&pix[54], c1, 6); + + break; + default: //dedicated mosaic set + //A0: D = color set + //A1-3: 3 blocks de 6 pixels + //C0-6: 7 blocks de 6 pixels + pix[ 0] = (c & 0x01) ? c1 : c0; + pix[ 3] = (c & 0x02) ? c1 : c0; + pix[12] = (c & 0x04) ? c1 : c0; + pix[15] = (c & 0x08) ? c1 : c0; + pix[24] = (c & 0x10) ? c1 : c0; + pix[27] = (c & 0x20) ? c1 : c0; + pix[36] = (c & 0x40) ? c1 : c0; + pix[39] = (a & 0x02) ? c1 : c0; + pix[48] = (a & 0x04) ? c1 : c0; + pix[51] = (a & 0x08) ? c1 : c0; + + for(i = 0; i < 60; i += 12) + { + pix[i + 6] = pix[i]; + pix[i + 9] = pix[i + 3]; + } + + for(i = 0; i < 60; i += 3) + pix[i + 2] = pix[i + 1] = pix[i]; + + break; + } + + draw_char_80(pix, x, y); +} + +// generate 16 bits 40 columns char +void ef9345_device::makechar_16x40(UINT16 x, UINT16 y) +{ + UINT8 a, b, c0, c1, i, f, m, n, u, type, dial; + UINT16 address, iblock; + + iblock = (m_mat & 0x80 && y > 1) ? indexblock(x, y / 2) : indexblock(x, y); + a = m_videoram->read_byte(m_block + iblock); + b = m_videoram->read_byte(m_block + iblock + 0x0800); + + dial = get_dial(x, (a & 0x80) ? 0 : (((a & 0x20) >> 5) | ((a & 0x10) >> 3))); + + //type and address of the char + type = ((b & 0x80) >> 4) | ((a & 0x80) >> 6); + address = ((b & 0x7f) >> 2) * 0x40 + (b & 0x03); + + //negative space + if ((b & 0xe0) == 0x80) + { + address = 0; + type = 3; + } + + //reset attributes latch + if (x == 0) + m_latchm = m_latchi = m_latchu = m_latchc0 = 0; + + if (type == 4) + { + m_latchm = b & 1; + m_latchi = (b & 2) >> 1; + m_latchu = (b & 4) >> 2; + } + + if (a & 0x80) + m_latchc0 = (a & 0x70) >> 4; + + //char attributes + c0 = m_latchc0; //background + c1 = a & 0x07; //foreground + i = m_latchi; //insert mode + f = (a & 0x08) >> 3; //flash + m = m_latchm; //hided + n = (a & 0x80) ? 0: ((a & 0x40) >> 6); //negative + u = m_latchu; //underline + + bichrome40(type, address, dial, iblock, x, y, c0, c1, i, f, m, n, u); +} + +// generate 24 bits 40 columns char +void ef9345_device::makechar_24x40(UINT16 x, UINT16 y) +{ + UINT8 a, b, c, c0, c1, i, f, m, n, u, type, dial; + UINT16 address, iblock; + + iblock = (m_mat & 0x80 && y > 1) ? indexblock(x, y / 2) : indexblock(x, y); + c = m_videoram->read_byte(m_block + iblock); + b = m_videoram->read_byte(m_block + iblock + 0x0800); + a = m_videoram->read_byte(m_block + iblock + 0x1000); + + if ((b & 0xc0) == 0xc0) + { + quadrichrome40(c, b, a, x, y); + return; + } + + dial = get_dial(x, (b & 0x02) + ((b & 0x08) >> 3)); + + //type and address of the char + address = ((c & 0x7f) >> 2) * 0x40 + (c & 0x03); + type = (b & 0xf0) >> 4; + + //char attributes + c0 = a & 0x07; //background + c1 = (a & 0x70) >> 4; //foreground + i = b & 0x01; //insert + f = (a & 0x08) >> 3; //flash + m = (b & 0x04) >> 2; //hided + n = ((a & 0x80) >> 7); //negative + u = (((b & 0x60) == 0) || ((b & 0xc0) == 0x40)) ? ((b & 0x10) >> 4) : 0; //underline + + bichrome40(type, address, dial, iblock, x, y, c0, c1, i, f, m, n, u); +} + +// generate 12 bits 80 columns char +void ef9345_device::makechar_12x80(UINT16 x, UINT16 y) +{ + UINT16 iblock = indexblock(x, y); + bichrome80(m_videoram->read_byte(m_block + iblock), (m_videoram->read_byte(m_block + iblock + 0x1000) >> 4) & 0x0f, 2 * x + 1, y + 1); + bichrome80(m_videoram->read_byte(m_block + iblock + 0x0800), m_videoram->read_byte(m_block + iblock + 0x1000) & 0x0f, 2 * x + 2, y + 1); +} + +void ef9345_device::draw_border(UINT16 line) +{ + if (m_char_mode == MODE12x80 || m_char_mode == MODE8x80) + for(int i = 0; i < 82; i++) + draw_char_80(m_border, i, line); + else + for(int i = 0; i < 42; i++) + draw_char_40(m_border, i, line); +} + +void ef9345_device::makechar(UINT16 x, UINT16 y) +{ + switch (m_char_mode) + { + case MODE24x40: + makechar_24x40(x, y); + break; + case MODEVAR40: + case MODE8x80: + logerror("Unemulated EF9345 mode: %02x\n", m_char_mode); + break; + case MODE12x80: + makechar_12x80(x, y); + break; + case MODE16x40: + makechar_16x40(x, y); + break; + default: + logerror("Unknown EF9345 mode: %02x\n", m_char_mode); + break; + } +} + +// Execute EF9345 command +void ef9345_device::ef9345_exec(UINT8 cmd) +{ + m_state = 0; + if ((m_registers[5] & 0x3f) == 39) m_state |= 0x10; //S4(LXa) set + if ((m_registers[7] & 0x3f) == 39) m_state |= 0x20; //S5(LXm) set + + UINT16 a = indexram(7); + + switch(cmd) + { + case 0x00: //KRF: R1,R2,R3->ram + case 0x01: //KRF: R1,R2,R3->ram + increment + set_busy_flag(4); + m_videoram->write_byte(a, m_registers[1]); + m_videoram->write_byte(a + 0x0800, m_registers[2]); + m_videoram->write_byte(a + 0x1000, m_registers[3]); + if (cmd&1) inc_x(7); + break; + case 0x02: //KRG: R1,R2->ram + case 0x03: //KRG: R1,R2->ram + increment + set_busy_flag(5.5); + m_videoram->write_byte(a, m_registers[1]); + m_videoram->write_byte(a + 0x0800, m_registers[2]); + if (cmd&1) inc_x(7); + break; + case 0x08: //KRF: ram->R1,R2,R3 + case 0x09: //KRF: ram->R1,R2,R3 + increment + set_busy_flag(7.5); + m_registers[1] = m_videoram->read_byte(a); + m_registers[2] = m_videoram->read_byte(a + 0x0800); + m_registers[3] = m_videoram->read_byte(a + 0x1000); + if (cmd&1) inc_x(7); + break; + case 0x0a: //KRG: ram->R1,R2 + case 0x0b: //KRG: ram->R1,R2 + increment + set_busy_flag(7.5); + m_registers[1] = m_videoram->read_byte(a); + m_registers[2] = m_videoram->read_byte(a + 0x0800); + if (cmd&1) inc_x(7); + break; + case 0x30: //OCT: R1->RAM, main pointer + case 0x31: //OCT: R1->RAM, main pointer + inc + set_busy_flag(4); + m_videoram->write_byte(indexram(7), m_registers[1]); + + if (cmd&1) + { + inc_x(7); + if ((m_registers[7] & 0x3f) == 0) + inc_y(6); + } + break; + case 0x34: //OCT: R1->RAM, aux pointer + case 0x35: //OCT: R1->RAM, aux pointer + inc + set_busy_flag(4); + m_videoram->write_byte(indexram(5), m_registers[1]); + + if (cmd&1) + inc_x(5); + break; + case 0x38: //OCT: RAM->R1, main pointer + case 0x39: //OCT: RAM->R1, main pointer + inc + set_busy_flag(4.5); + m_registers[1] = m_videoram->read_byte(indexram(7)); + + if (cmd&1) + { + inc_x(7); + + if ((m_registers[7] & 0x3f) == 0) + inc_y(6); + } + break; + case 0x3c: //OCT: RAM->R1, aux pointer + case 0x3d: //OCT: RAM->R1, aux pointer + inc + set_busy_flag(4.5); + m_registers[1] = m_videoram->read_byte(indexram(5)); + + if (cmd&1) + inc_x(5); + break; + case 0x50: //KRL: 80 UINT8 - 12 bits write + case 0x51: //KRL: 80 UINT8 - 12 bits write + inc + set_busy_flag(12.5); + m_videoram->write_byte(a, m_registers[1]); + switch((a / 0x0800) & 1) + { + case 0: + { + UINT8 tmp_data = m_videoram->read_byte(a + 0x1000); + m_videoram->write_byte(a + 0x1000, (tmp_data & 0x0f) | (m_registers[3] & 0xf0)); + break; + } + case 1: + { + UINT8 tmp_data = m_videoram->read_byte(a + 0x0800); + m_videoram->write_byte(a + 0x0800, (tmp_data & 0xf0) | (m_registers[3] & 0x0f)); + break; + } + } + if (cmd&1) + { + if ((m_registers[7] & 0x80) == 0x00) { m_registers[7] |= 0x80; return; } + m_registers[7] &= 0x80; + inc_x(7); + } + break; + case 0x58: //KRL: 80 UINT8 - 12 bits read + case 0x59: //KRL: 80 UINT8 - 12 bits read + inc + set_busy_flag(11.5); + m_registers[1] = m_videoram->read_byte(a); + switch((a / 0x0800) & 1) + { + case 0: + m_registers[3] = m_videoram->read_byte(a + 0x1000); + break; + case 1: + m_registers[3] = m_videoram->read_byte(a + 0x0800); + break; + } + if (cmd&1) + { + if ((m_registers[7] & 0x80) == 0x00) + { + m_registers[7] |= 0x80; + break; + } + m_registers[7] &= 0x80; + inc_x(7); + } + break; + case 0x80: //IND: R1->ROM (impossible ?) + break; + case 0x81: //IND: R1->TGS + case 0x82: //IND: R1->MAT + case 0x83: //IND: R1->PAT + case 0x84: //IND: R1->DOR + case 0x87: //IND: R1->ROR + set_busy_flag(2); + switch(cmd&7) + { + case 1: m_tgs = m_registers[1]; break; + case 2: m_mat = m_registers[1]; break; + case 3: m_pat = m_registers[1]; break; + case 4: m_dor = m_registers[1]; break; + case 7: m_ror = m_registers[1]; break; + } + set_video_mode(); + m_state &= 0x8f; //reset S4(LXa), S5(LXm), S6(Al) + break; + case 0x88: //IND: ROM->R1 + case 0x89: //IND: TGS->R1 + case 0x8a: //IND: MAT->R1 + case 0x8b: //IND: PAT->R1 + case 0x8c: //IND: DOR->R1 + case 0x8f: //IND: ROR->R1 + set_busy_flag(3.5); + switch(cmd&7) + { + case 0: m_registers[1] = m_charset->u8(indexrom(7) & 0x1fff); + case 1: m_registers[1] = m_tgs; break; + case 2: m_registers[1] = m_mat; break; + case 3: m_registers[1] = m_pat; break; + case 4: m_registers[1] = m_dor; break; + case 7: m_registers[1] = m_ror; break; + } + m_state &= 0x8f; //reset S4(LXa), S5(LXm), S6(Al) + break; + case 0x90: //NOP: no operation + case 0x91: //NOP: no operation + case 0x95: //VRM: vertical sync mask reset + case 0x99: //VSM: vertical sync mask set + break; + case 0xb0: //INY: increment Y + set_busy_flag(2); + inc_y(6); + m_state &= 0x8f; //reset S4(LXa), S5(LXm), S6(Al) + break; + case 0xd5: //MVB: move buffer MP->AP stop + case 0xd6: //MVB: move buffer MP->AP nostop + case 0xd9: //MVB: move buffer AP->MP stop + case 0xda: //MVB: move buffer AP->MP nostop + case 0xe5: //MVD: move double buffer MP->AP stop + case 0xe6: //MVD: move double buffer MP->AP nostop + case 0xe9: //MVD: move double buffer AP->MP stop + case 0xea: //MVD: move double buffer AP->MP nostop + case 0xf5: //MVT: move triple buffer MP->AP stop + case 0xf6: //MVT: move triple buffer MP->AP nostop + case 0xf9: //MVT: move triple buffer AP->MP stop + case 0xfa: //MVT: move triple buffer AP->MP nostop + { + UINT16 i, a1, a2; + UINT8 n = (cmd>>4) - 0x0c; + UINT8 r1 = (cmd&0x04) ? 7 : 5; + UINT8 r2 = (cmd&0x04) ? 5 : 7; + int busy = 2; + + for(i = 0; i < 1280; i++) + { + a1 = indexram(r1); a2 = indexram(r2); + m_videoram->write_byte(a2, m_videoram->read_byte(a1)); + + if (n > 1) m_videoram->write_byte(a2 + 0x0800, m_videoram->read_byte(a1 + 0x0800)); + if (n > 2) m_videoram->write_byte(a2 + 0x1000, m_videoram->read_byte(a1 + 0x1000)); + + inc_x(r1); + inc_x(r2); + if ((m_registers[5] & 0x3f) == 0 && (cmd&1)) + break; + + if ((m_registers[7] & 0x3f) == 0) + { + if (cmd&1) + break; + else + inc_y(6); + } + + busy += 4 * n; + } + m_state &= 0x8f; //reset S4(LXa), S5(LXm), S6(Al) + set_busy_flag(busy); + } + break; + case 0x05: //CLF: Clear page 24 bits + case 0x07: //CLG: Clear page 16 bits + case 0x40: //KRC: R1 -> ram + case 0x41: //KRC: R1 -> ram + inc + case 0x48: //KRC: 80 characters - 8 bits + case 0x49: //KRC: 80 characters - 8 bits + default: + logerror("Unemulated EF9345 cmd: %02x\n", cmd); + } +} + + +/************************************************************** + EF9345 interface +**************************************************************/ + +UINT32 ef9345_device::screen_update(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect) +{ + copybitmap(bitmap, m_screen_out, 0, 0, 0, 0, cliprect); + return 0; +} + +void ef9345_device::update_scanline(UINT16 scanline) +{ + UINT16 i; + + if (scanline == 250) + m_state &= 0xfb; + + set_busy_flag(104); + + if (m_char_mode == MODE12x80 || m_char_mode == MODE8x80) + { + draw_char_80(m_border, 0, (scanline / 10) + 1); + draw_char_80(m_border, 81, (scanline / 10) + 1); + } + else + { + draw_char_40(m_border, 0, (scanline / 10) + 1); + draw_char_40(m_border, 41, (scanline / 10) + 1); + } + + if (scanline == 0) + { + m_state |= 0x04; + draw_border(0); + if (m_pat & 1) + for(i = 0; i < 40; i++) + makechar(i, (scanline / 10)); + else + for(i = 0; i < 42; i++) + draw_char_40(m_border, i, 1); + } + else if (scanline < 120) + { + if (m_pat & 2) + for(i = 0; i < 40; i++) + makechar(i, (scanline / 10)); + else + draw_border(scanline / 10); + } + else if (scanline < 250) + { + if (m_pat & 4) + for(i = 0; i < 40; i++) + makechar(i, (scanline / 10)); + else + draw_border(scanline / 10); + + if (scanline == 240) + draw_border(26); + } +} + +READ8_MEMBER( ef9345_device::data_r ) +{ + if (offset & 7) + return m_registers[offset & 7]; + + if (m_bf) + m_state |= 0x80; + else + m_state &= 0x7f; + + return m_state; +} + +WRITE8_MEMBER( ef9345_device::data_w ) +{ + m_registers[offset & 7] = data; + + if (offset & 8) + ef9345_exec(m_registers[0] & 0xff); +} |