diff options
Diffstat (limited to 'src/devices/video/ibm8514a.cpp')
-rw-r--r-- | src/devices/video/ibm8514a.cpp | 1664 |
1 files changed, 1664 insertions, 0 deletions
diff --git a/src/devices/video/ibm8514a.cpp b/src/devices/video/ibm8514a.cpp new file mode 100644 index 00000000000..5adac1dc434 --- /dev/null +++ b/src/devices/video/ibm8514a.cpp @@ -0,0 +1,1664 @@ +// license:BSD-3-Clause +// copyright-holders:Barry Rodewald + +#include "emu.h" +#include "ibm8514a.h" + +#define VERBOSE (LOG_GENERAL) +//#define LOG_OUTPUT_FUNC osd_printf_info +#include "logmacro.h" + +enum +{ + IBM8514_IDLE = 0, + IBM8514_DRAWING_RECT, + IBM8514_DRAWING_LINE, + IBM8514_DRAWING_BITBLT, + IBM8514_DRAWING_PATTERN, + IBM8514_DRAWING_SSV_1, + IBM8514_DRAWING_SSV_2, + MACH8_DRAWING_SCAN +}; + +#define IBM8514_LINE_LENGTH (m_vga->offset()) + +DEFINE_DEVICE_TYPE(IBM8514A, ibm8514a_device, "ibm8514a", "IBM 8514/A Video") + +ibm8514a_device::ibm8514a_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) + : ibm8514a_device(mconfig, IBM8514A, tag, owner, clock) +{ +} + +ibm8514a_device::ibm8514a_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_vga(*this, finder_base::DUMMY_TAG) +{ +} + +void ibm8514a_device::device_start() +{ + memset(&ibm8514, 0, sizeof(ibm8514)); + ibm8514.read_mask = 0x00000000; + ibm8514.write_mask = 0xffffffff; +} + +void ibm8514a_device::ibm8514_write_fg(uint32_t offset) +{ + offset %= m_vga->vga.svga_intf.vram_size; + uint8_t dst = m_vga->mem_linear_r(offset); + uint8_t src = 0; + + // check clipping rectangle + if((ibm8514.current_cmd & 0xe000) == 0xc000) // BitBLT writes to the destination X/Y, so check that instead + { + if(ibm8514.dest_x < ibm8514.scissors_left || ibm8514.dest_x > ibm8514.scissors_right || ibm8514.dest_y < ibm8514.scissors_top || ibm8514.dest_y > ibm8514.scissors_bottom) + return; // do nothing + } + else + { + if(ibm8514.curr_x < ibm8514.scissors_left || ibm8514.curr_x > ibm8514.scissors_right || ibm8514.curr_y < ibm8514.scissors_top || ibm8514.curr_y > ibm8514.scissors_bottom) + return; // do nothing + } + + // determine source + switch(ibm8514.fgmix & 0x0060) + { + case 0x0000: + src = ibm8514.bgcolour; + break; + case 0x0020: + src = ibm8514.fgcolour; + break; + case 0x0040: + { + // Windows 95 in svga 8bpp mode wants this (start logo, moving icons around, games etc.) + u32 shift_values[4] = { 0, 8, 16, 24 }; + src = (ibm8514.pixel_xfer >> shift_values[(ibm8514.curr_x - ibm8514.prev_x) & 3]) & 0xff; + break; + } + case 0x0060: + // video memory - presume the memory is sourced from the current X/Y co-ords + src = m_vga->mem_linear_r(((ibm8514.curr_y * IBM8514_LINE_LENGTH) + ibm8514.curr_x)); + break; + } + + // write the data + switch(ibm8514.fgmix & 0x000f) + { + case 0x0000: + m_vga->mem_linear_w(offset,~dst); + break; + case 0x0001: + m_vga->mem_linear_w(offset,0x00); + break; + case 0x0002: + m_vga->mem_linear_w(offset,0xff); + break; + case 0x0003: + m_vga->mem_linear_w(offset,dst); + break; + case 0x0004: + m_vga->mem_linear_w(offset,~src); + break; + case 0x0005: + m_vga->mem_linear_w(offset,src ^ dst); + break; + case 0x0006: + m_vga->mem_linear_w(offset,~(src ^ dst)); + break; + case 0x0007: + m_vga->mem_linear_w(offset,src); + break; + case 0x0008: + m_vga->mem_linear_w(offset,~(src & dst)); + break; + case 0x0009: + m_vga->mem_linear_w(offset,(~src) | dst); + break; + case 0x000a: + m_vga->mem_linear_w(offset,src | (~dst)); + break; + case 0x000b: + m_vga->mem_linear_w(offset,src | dst); + break; + case 0x000c: + m_vga->mem_linear_w(offset,src & dst); + break; + case 0x000d: + m_vga->mem_linear_w(offset,src & (~dst)); + break; + case 0x000e: + m_vga->mem_linear_w(offset,(~src) & dst); + break; + case 0x000f: + m_vga->mem_linear_w(offset,~(src | dst)); + break; + } +} + +void ibm8514a_device::ibm8514_write_bg(uint32_t offset) +{ + offset %= m_vga->vga.svga_intf.vram_size; + uint8_t dst = m_vga->mem_linear_r(offset); + uint8_t src = 0; + + // check clipping rectangle + if((ibm8514.current_cmd & 0xe000) == 0xc000) // BitBLT writes to the destination X/Y, so check that instead + { + if(ibm8514.dest_x < ibm8514.scissors_left || ibm8514.dest_x > ibm8514.scissors_right || ibm8514.dest_y < ibm8514.scissors_top || ibm8514.dest_y > ibm8514.scissors_bottom) + return; // do nothing + } + else + if(ibm8514.curr_x < ibm8514.scissors_left || ibm8514.curr_x > ibm8514.scissors_right || ibm8514.curr_y < ibm8514.scissors_top || ibm8514.curr_y > ibm8514.scissors_bottom) + return; // do nothing + + // determine source + switch(ibm8514.bgmix & 0x0060) + { + case 0x0000: + src = ibm8514.bgcolour; + break; + case 0x0020: + src = ibm8514.fgcolour; + break; + case 0x0040: + src = ibm8514.pixel_xfer; + break; + case 0x0060: + // video memory - presume the memory is sourced from the current X/Y co-ords + src = m_vga->mem_linear_r(((ibm8514.curr_y * IBM8514_LINE_LENGTH) + ibm8514.curr_x)); + break; + } + + // write the data + switch(ibm8514.bgmix & 0x000f) + { + case 0x0000: + m_vga->mem_linear_w(offset,~dst); + break; + case 0x0001: + m_vga->mem_linear_w(offset,0x00); + break; + case 0x0002: + m_vga->mem_linear_w(offset,0xff); + break; + case 0x0003: + m_vga->mem_linear_w(offset,dst); + break; + case 0x0004: + m_vga->mem_linear_w(offset,~src); + break; + case 0x0005: + m_vga->mem_linear_w(offset,src ^ dst); + break; + case 0x0006: + m_vga->mem_linear_w(offset,~(src ^ dst)); + break; + case 0x0007: + m_vga->mem_linear_w(offset,src); + break; + case 0x0008: + m_vga->mem_linear_w(offset,~(src & dst)); + break; + case 0x0009: + m_vga->mem_linear_w(offset,(~src) | dst); + break; + case 0x000a: + m_vga->mem_linear_w(offset,src | (~dst)); + break; + case 0x000b: + m_vga->mem_linear_w(offset,src | dst); + break; + case 0x000c: + m_vga->mem_linear_w(offset,src & dst); + break; + case 0x000d: + m_vga->mem_linear_w(offset,src & (~dst)); + break; + case 0x000e: + m_vga->mem_linear_w(offset,(~src) & dst); + break; + case 0x000f: + m_vga->mem_linear_w(offset,~(src | dst)); + break; + } +} + +void ibm8514a_device::ibm8514_write(uint32_t offset, uint32_t src) +{ + int data_size = 8; + uint32_t xfer; + + switch(ibm8514.pixel_control & 0x00c0) + { + case 0x0000: // Foreground Mix only + ibm8514_write_fg(offset); + break; + case 0x0040: // fixed pattern (?) + // TODO + break; + case 0x0080: // use pixel transfer register + if(ibm8514.bus_size == 0) // 8-bit + data_size = 8; + if(ibm8514.bus_size == 1) // 16-bit + data_size = 16; + if(ibm8514.bus_size == 2) // 32-bit + data_size = 32; + if((ibm8514.current_cmd & 0x1000) && (data_size != 8)) + { + xfer = ((ibm8514.pixel_xfer & 0x000000ff) << 8) | ((ibm8514.pixel_xfer & 0x0000ff00) >> 8) + | ((ibm8514.pixel_xfer & 0x00ff0000) << 8) | ((ibm8514.pixel_xfer & 0xff000000) >> 8); + } + else + xfer = ibm8514.pixel_xfer; + if(ibm8514.current_cmd & 0x0002) + { + if((xfer & ((1<<(data_size-1))>>ibm8514.src_x)) != 0) + ibm8514_write_fg(offset); + else + ibm8514_write_bg(offset); + } + else + { + ibm8514_write_fg(offset); + } + ibm8514.src_x++; + if(ibm8514.src_x >= data_size) + ibm8514.src_x = 0; + break; + case 0x00c0: // use source plane + if (m_vga->mem_linear_r(src) != 0x00) + ibm8514_write_fg(offset); + else + ibm8514_write_bg(offset); + break; + } +} + +/* +92E8h W(R/W): Line Error Term Read/Write Register (ERR_TERM). +bit 0-12 (911/924) LINE PARAMETER/ERROR TERM. For Line Drawing this is the + Bresenham Initial Error Term 2*dminor-dmajor (one less if the + starting X is less than the ending X) in two's complement format. + (dminor is the length of the line projected onto the minor or + dependent axis, dmajor is the length of the line projected onto + the major or independent axis). + 0-13 (80x +) LINE PARAMETER/ERROR TERM. See above. + */ +uint16_t ibm8514a_device::ibm8514_line_error_r() +{ + return ibm8514.line_errorterm; +} + +void ibm8514a_device::ibm8514_line_error_w(uint16_t data) +{ + ibm8514.line_errorterm = data; + LOG("8514/A: Line Parameter/Error Term write %04x\n", data); +} + +/* + 9AE8h W(R): Graphics Processor Status Register (GP_STAT) +bit 0-7 Queue State. + 00h = 8 words available - queue is empty + 01h = 7 words available + 03h = 6 words available + 07h = 5 words available + 0Fh = 4 words available + 1Fh = 3 words available + 3Fh = 2 words available + 7Fh = 1 word available + FFh = 0 words available - queue is full + 8 (911-928) DTA AVA. Read Data Available. If set data is ready to be + read from the PIX_TRANS register (E2E8h). + 9 HDW BSY. Hardware Graphics Processor Busy + If set the Graphics Processor is busy. + 10 (928 +) AE. All FIFO Slots Empty. If set all FIFO slots are empty. + 11-15 (864/964) (R) Queue State bits 8-12. 1Fh if 8 words or less + available, Fh for 9 words, 7 for 10 words, 3 for 11 words, 1 for + 12 words and 0 for 13 words available. + */ +uint16_t ibm8514a_device::ibm8514_gpstatus_r() +{ + uint16_t ret = 0x0000; + + //LOG("S3: 9AE8 read\n"); + if(ibm8514.gpbusy == true) + ret |= 0x0200; + if(ibm8514.data_avail == true) + ret |= 0x0100; + return ret; +} + +void ibm8514a_device::ibm8514_draw_vector(uint8_t len, uint8_t dir, bool draw) +{ + uint32_t offset; + int x = 0; + + while(x <= len) + { + offset = (ibm8514.curr_y * IBM8514_LINE_LENGTH) + ibm8514.curr_x; + if(draw) + ibm8514_write(offset,offset); + switch(dir) + { + case 0: // 0 degrees + ibm8514.curr_x++; + break; + case 1: // 45 degrees + ibm8514.curr_x++; + ibm8514.curr_y--; + break; + case 2: // 90 degrees + ibm8514.curr_y--; + break; + case 3: // 135 degrees + ibm8514.curr_y--; + ibm8514.curr_x--; + break; + case 4: // 180 degrees + ibm8514.curr_x--; + break; + case 5: // 225 degrees + ibm8514.curr_x--; + ibm8514.curr_y++; + break; + case 6: // 270 degrees + ibm8514.curr_y++; + break; + case 7: // 315 degrees + ibm8514.curr_y++; + ibm8514.curr_x++; + break; + } + x++; + } +} + +/* +9AE8h W(W): Drawing Command Register (CMD) +bit 0 (911-928) ~RD/WT. Read/Write Data. If set VRAM write operations are + enabled. If clear operations execute normally but writes are + disabled. + 1 PX MD. Pixel Mode. Defines the orientation of the display bitmap. + 0 = Through plane mode (Single pixel transferred at a time) + 1 = Across plane mode (Multiple pixels transferred at a time). + 2 LAST PXOF. Last Pixel Off. If set the last pixel of a line command + (CMD_LINE, SSV or LINEAF) is not drawn. This is used for mixes such + as XOR where drawing the same pixel twice would give the wrong + color. + 3 DIR TYP. Direction Type. + 0: Bresenham line drawing (X-Y Axial) + CMD_LINE draws a line using the Bresenham algorithm as + specified in the DESTY_AXSTP (8AE8h), DESTX_DIASTP (8EE8h), + ERR_TERM (92E8h) and MAJ_AXIS_PCNT (96E8h) registers + INC_X, INC_Y and YMAJAXIS determines the direction. + 1: Vector line draws (Radial). + CMD_NOP allows drawing of Short Stroke Vectors (SSVs) by + writing to the Short Stroke register (9EE8h). + CMD_LINE draws a vector of length MAJ_AXIS_PCNT (96E8h) + in the direction specified by LINEDIR (bits 5-7). + DRWG-DIR determines the direction of the line. + 4 DRAW YES. If clear the current position is moved, but no pixels + are modified. This bit should be set when attempting read or + write of bitmap data. + 5-7 DRWG-DIR. Drawing Direction. When a line draw command (CMD_LINE) + with DIR TYP=1 (Radial) is issued, these bits define the direction + of the line counter clockwise relative to the positive X-axis. + 0 = 000 degrees + 1 = 045 degrees + 2 = 090 degrees + 3 = 135 degrees + 4 = 180 degrees + 5 = 225 degrees + 6 = 270 degrees + 7 = 315 degrees + 5 INC_X. This bit together with INC_Y determines which quadrant + the slope of a line lies within. They also determine the + orientation of rectangle draw commands. + If set lines are drawn in the positive X direction (left to right). + 6 YMAJAXIS. For Bresenham line drawing commands this bit determines + which axis is the independent or major axis. INC_X and INC_Y + determines which quadrant the slope falls within. This bit further + defines the slope to within an octant. + If set Y is the major (independent) axis. + 7 INC_Y. This bit together with INC_X determines which quadrant + the slope of a line lies within. They also determine the + orientation of rectangle draw commands. + If set lines are drawn in the positive Y direction (down). + 8 WAIT YES. If set the drawing engine waits for read/write of the + PIX_TRANS register (E2E8h) for each pixel during a draw operation. + 9 (911-928) BUS SIZE. If set the PIX_TRANS register (E2E8h) is + processed internally as two bytes in the order specified by BYTE + SWAP. If clear all accesses to E2E8h are 8bit. + 9-10 (864,964) BUS SIZE. Select System Bus Size. Controls the width of + the Pixel Data Transfer registers (E2E8h,E2EAh) and the memory + mapped I/O. 0: 8bit, 1: 16bit, 2: 32bit + 12 BYTE SWAP. Affects both reads and writes of SHORT_STROKE (9EE8h) + and PIX_TRANS (E2E8h) when 16bit=1. + If set take low byte first, if clear take high byte first. + 13-15 Draw Command: + 0 = NOP. Used for Short Stroke Vectors. + 1 = Draw Line. If bit 3 is set the line is drawn to the angle in + bits 5-7 and the length in the Major Axis Pixel Count register + (96E8h), if clear the line is drawn from the Bresenham + constants in the Axial Step Constant register(8AE8h), Diagonal + Step Constant register (8EE8h), Line Error Term register + (92E8h) and bits 5-7 of this register. + 2 = Rectangle Fill. The Current X (86E8h) and Y (82E8h) + registers holds the coordinates of the rectangle to fill and + the Major Axis Pixel Count register (96E8h) holds the + horizontal width (in pixels) fill and the Minor Axis Pixel + Count register (BEE8h index 0) holds the height of the + rectangle. + 6 = BitBLT. Copies the source rectangle specified by the Current X + (86E8h) and Y (8AE8h) registers to the destination rectangle, + specified as for the Rectangle Fills. + 7 = (80x +) Pattern Fill. The source rectangle is an 8x8 pattern + rectangle, which is copied repeatably to the destination + rectangle. + */ +void ibm8514a_device::ibm8514_cmd_w(uint16_t data) +{ + int x,y; + int pattern_x,pattern_y; + uint32_t off,src; + uint8_t readmask; + + ibm8514.current_cmd = data; + ibm8514.src_x = 0; + ibm8514.src_y = 0; + ibm8514.bus_size = (data & 0x0600) >> 9; + switch(data & 0xe000) + { + case 0x0000: // NOP (for "Short Stroke Vectors") + ibm8514.state = IBM8514_IDLE; + ibm8514.gpbusy = false; + LOG("8514/A: Command (%04x) - NOP (Short Stroke Vector)\n", ibm8514.current_cmd); + break; + case 0x2000: // Line + ibm8514.state = IBM8514_IDLE; + ibm8514.gpbusy = false; + if(data & 0x0008) + { + if(data & 0x0100) + { + ibm8514.state = IBM8514_DRAWING_LINE; + ibm8514.data_avail = true; + LOG("8514/A: Command (%04x) - Vector Line (WAIT) %i,%i \n", ibm8514.current_cmd, ibm8514.curr_x, ibm8514.curr_y); + } + else + { + ibm8514_draw_vector(ibm8514.rect_width,(data & 0x00e0) >> 5,(data & 0010) ? true : false); + LOG("8514/A: Command (%04x) - Vector Line - %i,%i \n", ibm8514.current_cmd, ibm8514.curr_x, ibm8514.curr_y); + } + } + else + { + // Not perfect, but will do for now. + int16_t dx = ibm8514.rect_width; + int16_t dy = ibm8514.line_axial_step >> 1; + int16_t err = ibm8514.line_errorterm; + int sx = (data & 0x0020) ? 1 : -1; + int sy = (data & 0x0080) ? 1 : -1; + int count = 0; + int16_t temp; + + LOG("8514/A: Command (%04x) - Line (Bresenham) - %i,%i Axial %i, Diagonal %i, Error %i, Major Axis %i, Minor Axis %i\n", + ibm8514.current_cmd, ibm8514.curr_x, ibm8514.curr_y, ibm8514.line_axial_step, ibm8514.line_diagonal_step, ibm8514.line_errorterm, ibm8514.rect_width, ibm8514.rect_height); + + if((data & 0x0040)) + { + temp = dx; dx = dy; dy = temp; + } + for(;;) + { + ibm8514_write(ibm8514.curr_x + (ibm8514.curr_y * IBM8514_LINE_LENGTH),ibm8514.curr_x + (ibm8514.curr_y * IBM8514_LINE_LENGTH)); + if (count > ibm8514.rect_width) break; + count++; + if((err*2) > -dy) + { + err -= dy; + ibm8514.curr_x += sx; + } + if((err*2) < dx) + { + err += dx; + ibm8514.curr_y += sy; + } + } + } + break; + case 0x4000: // Rectangle Fill + if(data & 0x0100) // WAIT (for read/write of PIXEL TRANSFER (E2E8)) + { + ibm8514.state = IBM8514_DRAWING_RECT; + //ibm8514.gpbusy = true; // DirectX 5 keeps waiting for the busy bit to be clear... + ibm8514.bus_size = (data & 0x0600) >> 9; + ibm8514.data_avail = true; + LOG("8514/A: Command (%04x) - Rectangle Fill (WAIT) %i,%i Width: %i Height: %i Colour: %08x\n", + ibm8514.current_cmd, ibm8514.curr_x, ibm8514.curr_y, ibm8514.rect_width, ibm8514.rect_height, ibm8514.fgcolour); + break; + } + LOG("8514/A: Command (%04x) - Rectangle Fill %i,%i Width: %i Height: %i Colour: %08x\n", + ibm8514.current_cmd, ibm8514.curr_x, ibm8514.curr_y, ibm8514.rect_width, ibm8514.rect_height, ibm8514.fgcolour); + off = 0; + off += (IBM8514_LINE_LENGTH * ibm8514.curr_y); + off += ibm8514.curr_x; + for(y=0;y<=ibm8514.rect_height;y++) + { + for(x=0;x<=ibm8514.rect_width;x++) + { + if(data & 0x0020) // source pattern is always based on current X/Y? + ibm8514_write((off+x) % m_vga->vga.svga_intf.vram_size,(off+x) % m_vga->vga.svga_intf.vram_size); + else + ibm8514_write((off-x) % m_vga->vga.svga_intf.vram_size,(off-x) % m_vga->vga.svga_intf.vram_size); + if(ibm8514.current_cmd & 0x0020) + { + ibm8514.curr_x++; + if(ibm8514.curr_x > ibm8514.prev_x + ibm8514.rect_width) + { + ibm8514.curr_x = ibm8514.prev_x; + ibm8514.src_x = 0; + if(ibm8514.current_cmd & 0x0080) + ibm8514.curr_y++; + else + ibm8514.curr_y--; + } + } + else + { + ibm8514.curr_x--; + if(ibm8514.curr_x < ibm8514.prev_x - ibm8514.rect_width) + { + ibm8514.curr_x = ibm8514.prev_x; + ibm8514.src_x = 0; + if(ibm8514.current_cmd & 0x0080) + ibm8514.curr_y++; + else + ibm8514.curr_y--; + } + } + } + if(data & 0x0080) + off += IBM8514_LINE_LENGTH; + else + off -= IBM8514_LINE_LENGTH; + } + ibm8514.state = IBM8514_IDLE; + ibm8514.gpbusy = false; + break; + case 0xc000: // BitBLT + // TODO: a10cuba sets up blantantly invalid parameters here, CPU core bug maybe? + LOG("8514/A: Command (%04x) - BitBLT from %i,%i to %i,%i Width: %i Height: %i\n", + ibm8514.current_cmd, ibm8514.curr_x, ibm8514.curr_y, ibm8514.dest_x, ibm8514.dest_y, ibm8514.rect_width, ibm8514.rect_height); + off = 0; + off += (IBM8514_LINE_LENGTH * ibm8514.dest_y); + off += ibm8514.dest_x; + src = 0; + src += (IBM8514_LINE_LENGTH * ibm8514.curr_y); + src += ibm8514.curr_x; + readmask = ((ibm8514.read_mask & 0x01) << 7) | ((ibm8514.read_mask & 0xfe) >> 1); + for(y=0;y<=ibm8514.rect_height;y++) + { + for(x=0;x<=ibm8514.rect_width;x++) + { + if((ibm8514.pixel_control & 0xc0) == 0xc0) + { + // only check read mask if Mix Select is set to 11 (VRAM determines mix) + if(m_vga->mem_linear_r((src+x)) & ~readmask) + { + // presumably every program is going to be smart enough to set the FG mix to use VRAM (0x6x) + if(data & 0x0020) + ibm8514_write(off+x,src+x); + else + ibm8514_write(off-x,src-x); + } + } + else + { + // presumably every program is going to be smart enough to set the FG mix to use VRAM (0x6x) + if(data & 0x0020) + ibm8514_write(off+x,src+x); + else + ibm8514_write(off-x,src-x); + } + if(ibm8514.current_cmd & 0x0020) + { + ibm8514.curr_x++; + if(ibm8514.curr_x > ibm8514.prev_x + ibm8514.rect_width) + { + ibm8514.curr_x = ibm8514.prev_x; + ibm8514.src_x = 0; + if(ibm8514.current_cmd & 0x0080) + ibm8514.curr_y++; + else + ibm8514.curr_y--; + } + } + else + { + ibm8514.curr_x--; + if(ibm8514.curr_x < ibm8514.prev_x - ibm8514.rect_width) + { + ibm8514.curr_x = ibm8514.prev_x; + ibm8514.src_x = 0; + if(ibm8514.current_cmd & 0x0080) + ibm8514.curr_y++; + else + ibm8514.curr_y--; + } + } + } + if(data & 0x0080) + { + src += IBM8514_LINE_LENGTH; + off += IBM8514_LINE_LENGTH; + } + else + { + src -= IBM8514_LINE_LENGTH; + off -= IBM8514_LINE_LENGTH; + } + } + ibm8514.state = IBM8514_IDLE; + ibm8514.gpbusy = false; + ibm8514.curr_x = ibm8514.prev_x; + ibm8514.curr_y = ibm8514.prev_y; + break; + case 0xe000: // Pattern Fill + LOG("8514/A: Command (%04x) - Pattern Fill - source %i,%i dest %i,%i Width: %i Height: %i\n", + ibm8514.current_cmd, ibm8514.curr_x, ibm8514.curr_y, ibm8514.dest_x, ibm8514.dest_y, ibm8514.rect_width, ibm8514.rect_height); + off = 0; + off += (IBM8514_LINE_LENGTH * ibm8514.dest_y); + off += ibm8514.dest_x; + src = 0; + src += (IBM8514_LINE_LENGTH * ibm8514.curr_y); + src += ibm8514.curr_x; + if(data & 0x0020) + pattern_x = 0; + else + pattern_x = 7; + if(data & 0x0080) + pattern_y = 0; + else + pattern_y = 7; + + for(y=0;y<=ibm8514.rect_height;y++) + { + for(x=0;x<=ibm8514.rect_width;x++) + { + if(data & 0x0020) + { + ibm8514_write(off+x,src+pattern_x); + pattern_x++; + if(pattern_x >= 8) + pattern_x = 0; + } + else + { + ibm8514_write(off-x,src-pattern_x); + pattern_x--; + if(pattern_x < 0) + pattern_x = 7; + } + } + + // for now, presume that INC_X and INC_Y affect both src and dest, at is would for a bitblt. + if(data & 0x0020) + pattern_x = 0; + else + pattern_x = 7; + if(data & 0x0080) + { + pattern_y++; + src += IBM8514_LINE_LENGTH; + if(pattern_y >= 8) + { + pattern_y = 0; + src -= (IBM8514_LINE_LENGTH * 8); // move src pointer back to top of pattern + } + off += IBM8514_LINE_LENGTH; + } + else + { + pattern_y--; + src -= IBM8514_LINE_LENGTH; + if(pattern_y < 0) + { + pattern_y = 7; + src += (IBM8514_LINE_LENGTH * 8); // move src pointer back to bottom of pattern + } + off -= IBM8514_LINE_LENGTH; + } + } + ibm8514.state = IBM8514_IDLE; + ibm8514.gpbusy = false; + break; + default: + ibm8514.state = IBM8514_IDLE; + ibm8514.gpbusy = false; + LOG("8514/A: Unknown command: %04x\n", data); + break; + } +} + +/* +8AE8h W(R/W): Destination Y Position & Axial Step Constant Register + (DESTY_AXSTP) +bit 0-11 DESTINATION Y-POSITION. During BITBLT operations this is the Y + co-ordinate of the destination in pixels. + 0-12 (911/924) LINE PARAMETER AXIAL STEP CONSTANT. During Line Drawing, + this is the Bresenham constant 2*dminor in two's complement + format. (dminor is the length of the line projected onto the minor + or dependent axis). + 0-13 (80 x+) LINE PARAMETER AXIAL STEP CONSTANT. Se above + + */ +uint16_t ibm8514a_device::ibm8514_desty_r() +{ + return ibm8514.line_axial_step; +} + +void ibm8514a_device::ibm8514_desty_w(uint16_t data) +{ + ibm8514.line_axial_step = data; + ibm8514.dest_y = data; + LOG("8514/A: Line Axial Step / Destination Y write %04x\n", data); +} + +/* +8EE8h W(R/W): Destination X Position & Diagonal Step Constant Register + (DESTX_DISTP) +bit 0-11 DESTINATION X-POSITION. During BITBLT operations this is the X + co-ordinate of the destination in pixels. + 0-12 (911/924) LINE PARAMETER DIAGONAL STEP CONSTANT. During Line + Drawing this is the Bresenham constant 2*dminor-2*dmajor in two's + complement format. (dminor is the length of the line projected + onto the minor or dependent axis, dmajor is the length of the line + projected onto the major or independent axis) + 0-13 (80x +) LINE PARAMETER DIAGONAL STEP CONSTANT. Se above + + */ +uint16_t ibm8514a_device::ibm8514_destx_r() +{ + return ibm8514.line_diagonal_step; +} + +void ibm8514a_device::ibm8514_destx_w(uint16_t data) +{ + ibm8514.line_diagonal_step = data; + ibm8514.dest_x = data; + LOG("8514/A: Line Diagonal Step / Destination X write %04x\n", data); +} + +/* +9EE8h W(R/W): Short Stroke Vector Transfer Register (SHORT_STROKE) +bit 0-3 Length of vector projected onto the major axis. + This is also the number of pixels drawn. + 4 Must be set for pixels to be written. + 5-7 VECDIR. The angle measured counter-clockwise from horizontal + right) at which the line is drawn, + 0 = 000 degrees + 1 = 045 degrees + 2 = 090 degrees + 3 = 135 degrees + 4 = 180 degrees + 5 = 225 degrees + 6 = 270 degrees + 7 = 315 degrees + 8-15 The lower 8 bits are duplicated in the upper 8 bits so two + short stroke vectors can be drawn with one command. +Note: The upper byte must be written for the SSV command to be executed. + Thus if a byte is written to 9EE8h another byte must be written to + 9EE9h before execution starts. A single 16bit write will do. + If only one SSV is desired the other byte can be set to 0. + */ +void ibm8514a_device::ibm8514_wait_draw_ssv() +{ + uint8_t len = ibm8514.wait_vector_len; + uint8_t dir = ibm8514.wait_vector_dir; + bool draw = ibm8514.wait_vector_draw; + uint8_t count = ibm8514.wait_vector_count; + uint32_t offset; + int x; + int data_size; + + switch(ibm8514.bus_size) + { + case 0: + data_size = 8; + break; + case 1: + data_size = 16; + break; + case 2: + data_size = 32; + break; + default: + data_size = 8; + break; + } + + for(x=0;x<data_size;x++) + { + if(len > count) + { + if(ibm8514.state == IBM8514_DRAWING_SSV_1) + { + ibm8514.state = IBM8514_DRAWING_SSV_2; + ibm8514.wait_vector_len = (ibm8514.ssv & 0x0f00) >> 8; + ibm8514.wait_vector_dir = (ibm8514.ssv & 0xe000) >> 13; + ibm8514.wait_vector_draw = (ibm8514.ssv & 0x1000) ? true : false; + ibm8514.wait_vector_count = 0; + return; + } + else if(ibm8514.state == IBM8514_DRAWING_SSV_2) + { + ibm8514.state = IBM8514_IDLE; + ibm8514.gpbusy = false; + ibm8514.data_avail = false; + return; + } + } + + if(ibm8514.state == IBM8514_DRAWING_SSV_1 || ibm8514.state == IBM8514_DRAWING_SSV_2) + { + offset = (ibm8514.curr_y * IBM8514_LINE_LENGTH) + ibm8514.curr_x; + if(draw) + ibm8514_write(offset,offset); + switch(dir) + { + case 0: // 0 degrees + ibm8514.curr_x++; + break; + case 1: // 45 degrees + ibm8514.curr_x++; + ibm8514.curr_y--; + break; + case 2: // 90 degrees + ibm8514.curr_y--; + break; + case 3: // 135 degrees + ibm8514.curr_y--; + ibm8514.curr_x--; + break; + case 4: // 180 degrees + ibm8514.curr_x--; + break; + case 5: // 225 degrees + ibm8514.curr_x--; + ibm8514.curr_y++; + break; + case 6: // 270 degrees + ibm8514.curr_y++; + break; + case 7: // 315 degrees + ibm8514.curr_y++; + ibm8514.curr_x++; + break; + } + } + } +} + +void ibm8514a_device::ibm8514_draw_ssv(uint8_t data) +{ + uint8_t len = data & 0x0f; + uint8_t dir = (data & 0xe0) >> 5; + bool draw = (data & 0x10) ? true : false; + + ibm8514_draw_vector(len,dir,draw); +} + +uint16_t ibm8514a_device::ibm8514_ssv_r() +{ + return ibm8514.ssv; +} + +void ibm8514a_device::ibm8514_ssv_w(uint16_t data) +{ + ibm8514.ssv = data; + + if(ibm8514.current_cmd & 0x0100) + { + ibm8514.state = IBM8514_DRAWING_SSV_1; + ibm8514.data_avail = true; + ibm8514.wait_vector_len = ibm8514.ssv & 0x0f; + ibm8514.wait_vector_dir = (ibm8514.ssv & 0xe0) >> 5; + ibm8514.wait_vector_draw = (ibm8514.ssv & 0x10) ? true : false; + ibm8514.wait_vector_count = 0; + return; + } + + if(ibm8514.current_cmd & 0x1000) // byte sequence + { + ibm8514_draw_ssv(data & 0xff); + ibm8514_draw_ssv(data >> 8); + } + else + { + ibm8514_draw_ssv(data >> 8); + ibm8514_draw_ssv(data & 0xff); + } + LOG("8514/A: Short Stroke Vector write %04x\n", data); +} + +void ibm8514a_device::ibm8514_wait_draw_vector() +{ + uint8_t len = ibm8514.wait_vector_len; + uint8_t dir = ibm8514.wait_vector_dir; + bool draw = ibm8514.wait_vector_draw; + uint8_t count = ibm8514.wait_vector_count; + uint32_t offset; + uint8_t data_size = 0; + int x; + + if(ibm8514.bus_size == 0) // 8-bit + data_size = 8; + if(ibm8514.bus_size == 1) // 16-bit + data_size = 16; + if(ibm8514.bus_size == 2) // 32-bit + data_size = 32; + + for(x=0;x<data_size;x++) + { + if(len > count) + { + if(ibm8514.state == IBM8514_DRAWING_LINE) + { + ibm8514.state = IBM8514_IDLE; + ibm8514.gpbusy = false; + ibm8514.data_avail = false; + return; + } + } + + if(ibm8514.state == IBM8514_DRAWING_LINE) + { + offset = (ibm8514.curr_y * IBM8514_LINE_LENGTH) + ibm8514.curr_x; + if(draw) + ibm8514_write(offset,offset); + switch(dir) + { + case 0: // 0 degrees + ibm8514.curr_x++; + break; + case 1: // 45 degrees + ibm8514.curr_x++; + ibm8514.curr_y--; + break; + case 2: // 90 degrees + ibm8514.curr_y--; + break; + case 3: // 135 degrees + ibm8514.curr_y--; + ibm8514.curr_x--; + break; + case 4: // 180 degrees + ibm8514.curr_x--; + break; + case 5: // 225 degrees + ibm8514.curr_x--; + ibm8514.curr_y++; + break; + case 6: // 270 degrees + ibm8514.curr_y++; + break; + case 7: // 315 degrees + ibm8514.curr_y++; + ibm8514.curr_x++; + break; + } + } + } +} + +/* +96E8h W(R/W): Major Axis Pixel Count/Rectangle Width Register (MAJ_AXIS_PCNT) +bit 0-10 (911/924) RECTANGLE WIDTH/LINE PARAMETER MAX. For BITBLT and + rectangle commands this is the width of the area. For Line Drawing + this is the Bresenham constant dmajor in two's complement format. + (dmajor is the length of the line projected onto the major or + independent axis). Must be positive. + 0-11 (80x +) RECTANGLE WIDTH/LINE PARAMETER MAX. See above + */ +uint16_t ibm8514a_device::ibm8514_width_r() +{ + return ibm8514.rect_width; +} + +void ibm8514a_device::ibm8514_width_w(uint16_t data) +{ + ibm8514.rect_width = data & 0x1fff; + LOG("8514/A: Major Axis Pixel Count / Rectangle Width write %04x\n", data); +} + +uint16_t ibm8514a_device::ibm8514_currentx_r() +{ + return ibm8514.curr_x; +} + +void ibm8514a_device::ibm8514_currentx_w(uint16_t data) +{ + ibm8514.curr_x = data; + ibm8514.prev_x = data; + LOG("8514/A: Current X set to %04x (%i)\n", data, ibm8514.curr_x); +} + +uint16_t ibm8514a_device::ibm8514_currenty_r() +{ + return ibm8514.curr_y; +} + +void ibm8514a_device::ibm8514_currenty_w(uint16_t data) +{ + ibm8514.curr_y = data; + ibm8514.prev_y = data; + LOG("8514/A: Current Y set to %04x (%i)\n", data, ibm8514.curr_y); +} + +uint16_t ibm8514a_device::ibm8514_fgcolour_r() +{ + return ibm8514.fgcolour; +} + +void ibm8514a_device::ibm8514_fgcolour_w(uint16_t data) +{ + ibm8514.fgcolour = data; + LOG("8514/A: Foreground Colour write %04x\n", data); +} + +uint16_t ibm8514a_device::ibm8514_bgcolour_r() +{ + return ibm8514.bgcolour; +} + +void ibm8514a_device::ibm8514_bgcolour_w(uint16_t data) +{ + ibm8514.bgcolour = data; + LOG("8514/A: Background Colour write %04x\n", data); +} + +/* +AEE8h W(R/W): Read Mask Register (RD_MASK) +bit 0-7 (911/924) Read Mask affects the following commands: CMD_RECT, + CMD_BITBLT and reading data in Across Plane Mode. + Each bit set prevents the plane from being read. + 0-15 (801/5) Readmask. See above. + 0-31 (928 +) Readmask. See above. In 32 bits per pixel modes there are + two 16bit registers at this address. BEE8h index 0Eh bit 4 selects + which 16 bits are accessible and each access toggles to the other + 16 bits. + */ +uint16_t ibm8514a_device::ibm8514_read_mask_r() +{ + return ibm8514.read_mask & 0xffff; +} + +void ibm8514a_device::ibm8514_read_mask_w(uint16_t data) +{ + ibm8514.read_mask = (ibm8514.read_mask & 0xffff0000) | data; + LOG("8514/A: Read Mask (Low) write = %08x\n", ibm8514.read_mask); +} + +/* +AAE8h W(R/W): Write Mask Register (WRT_MASK) +bit 0-7 (911/924) Writemask. A plane can only be modified if the + corresponding bit is set. + 0-15 (801/5) Writemask. See above. + 0-31 (928 +) Writemask. See above. In 32 bits per pixel modes there are + two 16bit registers at this address. BEE8h index 0Eh bit 4 selects + which 16 bits are accessible and each access toggles to the other + 16 bits. + */ +uint16_t ibm8514a_device::ibm8514_write_mask_r() +{ + return ibm8514.write_mask & 0xffff; +} + +void ibm8514a_device::ibm8514_write_mask_w(uint16_t data) +{ + ibm8514.write_mask = (ibm8514.write_mask & 0xffff0000) | data; + LOG("8514/A: Write Mask (Low) write = %08x\n", ibm8514.write_mask); +} + +uint16_t ibm8514a_device::ibm8514_multifunc_r() +{ + switch(ibm8514.multifunc_sel) + { + case 0: + return ibm8514.rect_height; + case 1: + return ibm8514.scissors_top; + case 2: + return ibm8514.scissors_left; + case 3: + return ibm8514.scissors_bottom; + case 4: + return ibm8514.scissors_right; + // TODO: remaining functions + default: + LOG("8514/A: Unimplemented multifunction register %i selected\n", ibm8514.multifunc_sel); + return 0xff; + } +} + +void ibm8514a_device::ibm8514_multifunc_w(uint16_t data) +{ + switch(data & 0xf000) + { +/* +BEE8h index 00h W(R/W): Minor Axis Pixel Count Register (MIN_AXIS_PCNT). +bit 0-10 (911/924) Rectangle Height. Height of BITBLT or rectangle command. + Actual height is one larger. + 0-11 (80x +) Rectangle Height. See above +*/ + case 0x0000: + ibm8514.rect_height = data & 0x0fff; + LOG("8514/A: Minor Axis Pixel Count / Rectangle Height write %04x\n", data); + break; +/* +BEE8h index 01h W(R/W): Top Scissors Register (SCISSORS_T). +bit 0-10 (911/924) Clipping Top Limit. Defines the upper bound of the + Clipping Rectangle (Lowest Y coordinate). + 0-11 (80x +) Clipping Top Limit. See above + +BEE8h index 02h W(R/W): Left Scissors Registers (SCISSORS_L). +bit 0-10 (911,924) Clipping Left Limit. Defines the left bound of the + Clipping Rectangle (Lowest X coordinate). + 0-11 (80x +) Clipping Left Limit. See above. + +BEE8h index 03h W(R/W): Bottom Scissors Register (SCISSORS_B). +bit 0-10 (911,924) Clipping Bottom Limit. Defines the bottom bound of the + Clipping Rectangle (Highest Y coordinate). + 0-11 (80x +) Clipping Bottom Limit. See above. + +BEE8h index 04h W(R/W): Right Scissors Register (SCISSORS_R). +bit 0-10 (911,924) Clipping Right Limit. Defines the right bound of the + Clipping Rectangle (Highest X coordinate). + 0-11 (80x +) Clipping Bottom Limit. See above. + */ + case 0x1000: + ibm8514.scissors_top = data & 0x0fff; + LOG("S3: Scissors Top write %04x\n", data); + break; + case 0x2000: + ibm8514.scissors_left = data & 0x0fff; + LOG("S3: Scissors Left write %04x\n", data); + break; + case 0x3000: + ibm8514.scissors_bottom = data & 0x0fff; + LOG("S3: Scissors Bottom write %04x\n", data); + break; + case 0x4000: + ibm8514.scissors_right = data & 0x0fff; + LOG("S3: Scissors Right write %04x\n", data); + break; +/* +BEE8h index 0Ah W(R/W): Pixel Control Register (PIX_CNTL). +BIT 2 (911-928) Pack Data. If set image read data is a monochrome bitmap, + if clear it is a bitmap of the current pixel depth + 6-7 DT-EX-DRC. Select Mix Select. + 0 Foreground Mix is always used. + 1 use fixed pattern to decide which mix setting to use on a pixel + 2 CPU Data (Pixel Transfer register) determines the Mix register used. + 3 Video memory determines the Mix register used. + */ + case 0xa000: + ibm8514.pixel_control = data; + LOG("S3: Pixel control write %04x\n", data); + break; + case 0xe000: + ibm8514.multifunc_misc = data; + LOG("S3: Multifunction Miscellaneous write %04x\n", data); + break; +/* +BEE8h index 0Fh W(W): Read Register Select Register (READ_SEL) (801/5,928) +bit 0-2 (911-928) READ-REG-SEL. Read Register Select. Selects the register + that is actually read when a read of BEE8h happens. Each read of + BEE8h increments this register by one. + 0: Read will return contents of BEE8h index 0. + 1: Read will return contents of BEE8h index 1. + 2: Read will return contents of BEE8h index 2. + 3: Read will return contents of BEE8h index 3. + 4: Read will return contents of BEE8h index 4. + 5: Read will return contents of BEE8h index 0Ah. + 6: Read will return contents of BEE8h index 0Eh. + 7: Read will return contents of 9AE8h (Bits 13-15 will be 0). + 0-3 (864,964) READ-REG-SEL. See above plus: + 8: Read will return contents of 42E8h (Bits 12-15 will be 0) + 9: Read will return contents of 46E8h + 10: Read will return contents of BEE8h index 0Dh + */ + case 0xf000: + ibm8514.multifunc_sel = data & 0x000f; + LOG("S3: Multifunction select write %04x\n", data); + break; + default: + LOG("S3: Unimplemented multifunction register %i write %03x\n", data >> 12, data & 0x0fff); + break; + } +} + +void ibm8514a_device::ibm8514_wait_draw() +{ + int x, data_size = 8; + uint32_t off; + + // the data in the pixel transfer register or written to VRAM masks the rectangle output + if(ibm8514.bus_size == 0) // 8-bit + data_size = 8; + if(ibm8514.bus_size == 1) // 16-bit + data_size = 16; + if(ibm8514.bus_size == 2) // 32-bit + data_size = 32; + off = 0; + off += (IBM8514_LINE_LENGTH * ibm8514.curr_y); + off += ibm8514.curr_x; + if(ibm8514.current_cmd & 0x02) // "across plane mode" + { + for(x=0;x<data_size;x++) + { + ibm8514_write(off,off); + if(ibm8514.current_cmd & 0x0020) + { + off++; + ibm8514.curr_x++; + if(ibm8514.curr_x > ibm8514.prev_x + ibm8514.rect_width) + { + ibm8514.curr_x = ibm8514.prev_x; + ibm8514.src_x = 0; + if(ibm8514.current_cmd & 0x0080) + { + ibm8514.curr_y++; + if(ibm8514.curr_y > ibm8514.prev_y + ibm8514.rect_height) + { + ibm8514.state = IBM8514_IDLE; + ibm8514.data_avail = false; + ibm8514.gpbusy = false; + } + } + else + { + ibm8514.curr_y--; + if(ibm8514.curr_y < ibm8514.prev_y - ibm8514.rect_height) + { + ibm8514.state = IBM8514_IDLE; + ibm8514.data_avail = false; + ibm8514.gpbusy = false; + } + } + return; + } + } + else + { + off--; + ibm8514.curr_x--; + if(ibm8514.curr_x < ibm8514.prev_x - ibm8514.rect_width) + { + ibm8514.curr_x = ibm8514.prev_x; + ibm8514.src_x = 0; + if(ibm8514.current_cmd & 0x0080) + { + ibm8514.curr_y++; + if(ibm8514.curr_y > ibm8514.prev_y + ibm8514.rect_height) + { + ibm8514.state = IBM8514_IDLE; + ibm8514.gpbusy = false; + ibm8514.data_avail = false; + } + } + else + { + ibm8514.curr_y--; + if(ibm8514.curr_y < ibm8514.prev_y - ibm8514.rect_height) + { + ibm8514.state = IBM8514_IDLE; + ibm8514.gpbusy = false; + ibm8514.data_avail = false; + } + } + return; + } + } + } + } + else + { + // "through plane" mode (single pixel) + for(x=0;x<data_size;x+=8) + { + ibm8514_write(off,off); + + if(ibm8514.current_cmd & 0x0020) + { + off++; + ibm8514.curr_x++; + if(ibm8514.curr_x > ibm8514.prev_x + ibm8514.rect_width) + { + ibm8514.curr_x = ibm8514.prev_x; + ibm8514.src_x = 0; + if(ibm8514.current_cmd & 0x0080) + { + ibm8514.curr_y++; + if(ibm8514.curr_y > ibm8514.prev_y + ibm8514.rect_height) + { + ibm8514.state = IBM8514_IDLE; + ibm8514.gpbusy = false; + ibm8514.data_avail = false; + } + } + else + { + ibm8514.curr_y--; + if(ibm8514.curr_y < ibm8514.prev_y - ibm8514.rect_height) + { + ibm8514.state = IBM8514_IDLE; + ibm8514.gpbusy = false; + ibm8514.data_avail = false; + } + } + return; + } + } + else + { + off--; + ibm8514.curr_x--; + if(ibm8514.curr_x < ibm8514.prev_x - ibm8514.rect_width) + { + ibm8514.curr_x = ibm8514.prev_x; + ibm8514.src_x = 0; + if(ibm8514.current_cmd & 0x0080) + { + ibm8514.curr_y++; + if(ibm8514.curr_y > ibm8514.prev_y + ibm8514.rect_height) + { + ibm8514.state = IBM8514_IDLE; + ibm8514.gpbusy = false; + ibm8514.data_avail = false; + } + } + else + { + ibm8514.curr_y--; + if(ibm8514.curr_y < ibm8514.prev_y - ibm8514.rect_height) + { + ibm8514.state = IBM8514_IDLE; + ibm8514.gpbusy = false; + ibm8514.data_avail = false; + } + } + return; + } + } + } + } +} + +/* +B6E8h W(R/W): Background Mix Register (BKGD_MIX) +bit 0-3 Background MIX (BACKMIX). + 00 not DST + 01 0 (false) + 02 1 (true) + 03 2 DST + 04 not SRC + 05 SRC xor DST + 06 not (SRC xor DST) + 07 SRC + 08 not (SRC and DST) + 09 (not SRC) or DST + 0A SRC or (not DST) + 0B SRC or DST + 0C SRC and DST + 0D SRC and (not DST) + 0E (not SRC) and DST + 0F not (SRC or DST) + DST is always the destination bitmap, bit SRC has four + possible sources selected by the BSS bits. + 5-6 Background Source Select (BSS) + 0 BSS is Background Color + 1 BSS is Foreground Color + 2 BSS is Pixel Data from the PIX_TRANS register (E2E8h) + 3 BSS is Bitmap Data (Source data from display buffer). + */ +uint16_t ibm8514a_device::ibm8514_backmix_r() +{ + return ibm8514.bgmix; +} + +void ibm8514a_device::ibm8514_backmix_w(uint16_t data) +{ + ibm8514.bgmix = data; + LOG("8514/A: BG Mix write %04x\n", data); +} + +uint16_t ibm8514a_device::ibm8514_foremix_r() +{ + return ibm8514.fgmix; +} + +void ibm8514a_device::ibm8514_foremix_w(uint16_t data) +{ + ibm8514.fgmix = data; + LOG("8514/A: FG Mix write %04x\n", data); +} + +uint16_t ibm8514a_device::ibm8514_pixel_xfer_r(offs_t offset) +{ + if(offset == 1) + return (ibm8514.pixel_xfer & 0xffff0000) >> 16; + else + return ibm8514.pixel_xfer & 0x0000ffff; +} + +void ibm8514a_device::ibm8514_pixel_xfer_w(offs_t offset, uint16_t data) +{ + if(offset == 1) + ibm8514.pixel_xfer = (ibm8514.pixel_xfer & 0x0000ffff) | (data << 16); + else + ibm8514.pixel_xfer = (ibm8514.pixel_xfer & 0xffff0000) | data; + + if(ibm8514.state == IBM8514_DRAWING_RECT) + ibm8514_wait_draw(); + + if(ibm8514.state == IBM8514_DRAWING_SSV_1 || ibm8514.state == IBM8514_DRAWING_SSV_2) + ibm8514_wait_draw_ssv(); + + if(ibm8514.state == IBM8514_DRAWING_LINE) + ibm8514_wait_draw_vector(); + + LOG("8514/A: Pixel Transfer = %08x\n", ibm8514.pixel_xfer); +} + +/* +02E8h W(R): Display Status Register +bit 0 SENSE is the result of a wired-OR of 3 comparators, one + for each of the RGB video signal. + By programming the RAMDAC for various values + and patterns and then reading the SENSE, the monitor type + (color, monochrome or none) can be determined. + 1 VBLANK. Vertical Blank State + If Vertical Blank is active this bit is set. + 2 HORTOG. Horizontal Toggle + This bit toggles every time a HSYNC pulse starts + 3-15 Reserved(0) + */ +uint8_t ibm8514a_device::ibm8514_status_r(offs_t offset) +{ + switch(offset) + { + case 0: + return m_vga->vga_vblank() << 1; + case 2: + return m_vga->ramdac_mask_r(0); + case 3: + return m_vga->ramdac_state_r(0); + case 4: + return m_vga->ramdac_write_index_r(0); + case 5: + return m_vga->ramdac_data_r(0); + } + return 0; +} + +void ibm8514a_device::ibm8514_htotal_w(offs_t offset, uint8_t data) +{ + switch(offset) + { + case 0: + ibm8514.htotal = data & 0xff; + break; + case 2: + m_vga->ramdac_mask_w(0, data); + break; + case 3: + m_vga->ramdac_read_index_w(0, data); + break; + case 4: + m_vga->ramdac_write_index_w(0, data); + break; + case 5: + m_vga->ramdac_data_w(0, data); + break; + } + //vga.crtc.horz_total = data & 0x01ff; + LOG("8514/A: Horizontal total write %04x\n", data); +} + +/* +42E8h W(R): Subsystem Status Register (SUBSYS_STAT) +bit 0-3 Interrupt requests. These bits show the state of internal interrupt + requests. An interrupt will only occur if the corresponding bit(s) + in SUBSYS_CNTL is set. Interrupts can only be reset by writing a 1 + to the corresponding Interrupt Clear bit in SUBSYS_CNTL. + Bit 0: VBLNKFLG + 1: PICKFLAG + 2: INVALIDIO + 3: GPIDLE + 4-6 MONITORID. + 1: IBM 8507 (1024x768) Monochrome + 2: IBM 8514 (1024x768) Color + 5: IBM 8503 (640x480) Monochrome + 6: IBM 8512/13 (640x480) Color + 7 8PLANE. + (CT82c480) This bit is latched on reset from pin P4D7. + 8-11 CHIP_REV. Chip revision number. + 12-15 (CT82c480) CHIP_ID. 0=CT 82c480. + */ +uint16_t ibm8514a_device::ibm8514_substatus_r() +{ + // TODO: + if(m_vga->vga_vblank() != 0) // not correct, but will do for now + ibm8514.substatus |= 0x01; + return ibm8514.substatus; +} + +/* +42E8h W(W): Subsystem Control Register (SUBSYS_CNTL) +bit 0-3 Interrupt Reset. Write 1 to a bit to reset the interrupt. + Bit 0 RVBLNKFLG Write 1 to reset Vertical Blank interrupt. + 1 RPICKFLAG Write 1 to reset PICK interrupt. + 2 RINVALIDIO Write 1 to reset Queue Overflow/Data + Underflow interrupt. + 3 RGPIDLE Write 1 to reset GPIDLE interrupt. + 4-7 Reserved(0) + 8 IBLNKFLG. If set Vertical Blank Interrupts are enabled. + 9 IPICKFLAG. If set PICK Interrupts are enabled. + 10 IINVALIDIO. If set Queue Overflow/Data Underflow Interrupts are + enabled. + 11 IGPIDLE. If set Graphics Engine Idle Interrupts are enabled. + 12-13 CHPTEST. Used for chip testing. + 14-15 Graphics Processor Control (GPCTRL). + */ +void ibm8514a_device::ibm8514_subcontrol_w(uint16_t data) +{ + ibm8514.subctrl = data; + ibm8514.substatus &= ~(data & 0x0f); // reset interrupts +// LOG("8514/A: Subsystem control write %04x\n", data); +} + +uint16_t ibm8514a_device::ibm8514_subcontrol_r() +{ + return ibm8514.subctrl; +} + +/* 22E8 (W) + * Display Control + * bits 1-2: Line skip control - 0=bits 1-2 skipped, 1=bit 2 skipped + * bit 3: Double scan + * bit 4: Interlace + * bits 5-6: Emable Display - 0=no change, 1=enable 8514/A, 2 or 3=8514/A reset + */ +void ibm8514a_device::ibm8514_display_ctrl_w(uint16_t data) +{ + ibm8514.display_ctrl = data & 0x7e; + switch(data & 0x60) + { + case 0x00: + break; // do nothing + case 0x20: + ibm8514.enabled = true; // enable 8514/A + break; + case 0x40: + case 0x60: // reset (does this disable the 8514/A?) + ibm8514.enabled = false; + break; + } +} + +void ibm8514a_device::ibm8514_advfunc_w(uint16_t data) +{ + ibm8514.advfunction_ctrl = data; + ibm8514.passthrough = data & 0x0001; +} + +uint16_t ibm8514a_device::ibm8514_htotal_r() +{ + return ibm8514.htotal; +} + +uint16_t ibm8514a_device::ibm8514_vtotal_r() +{ + return ibm8514.vtotal; +} + +void ibm8514a_device::ibm8514_vtotal_w(uint16_t data) +{ + ibm8514.vtotal = data; +// vga.crtc.vert_total = data; + LOG("8514/A: Vertical total write %04x\n", data); +} + +uint16_t ibm8514a_device::ibm8514_vdisp_r() +{ + return ibm8514.vdisp; +} + +void ibm8514a_device::ibm8514_vdisp_w(uint16_t data) +{ + ibm8514.vdisp = data; +// vga.crtc.vert_disp_end = data >> 3; + LOG("8514/A: Vertical Displayed write %04x\n", data); +} + +uint16_t ibm8514a_device::ibm8514_vsync_r() +{ + return ibm8514.vsync; +} + +void ibm8514a_device::ibm8514_vsync_w(uint16_t data) +{ + ibm8514.vsync = data; + LOG("8514/A: Vertical Sync write %04x\n", data); +} + +void ibm8514a_device::enabled() +{ + ibm8514.state = IBM8514_IDLE; + ibm8514.gpbusy = false; +} + + |