diff options
Diffstat (limited to 'src/mame/video/rmnimbus.cpp')
-rw-r--r-- | src/mame/video/rmnimbus.cpp | 664 |
1 files changed, 0 insertions, 664 deletions
diff --git a/src/mame/video/rmnimbus.cpp b/src/mame/video/rmnimbus.cpp deleted file mode 100644 index 6238ba126e3..00000000000 --- a/src/mame/video/rmnimbus.cpp +++ /dev/null @@ -1,664 +0,0 @@ -// license:BSD-3-Clause -// copyright-holders:Phill Harvey-Smith, Carl -/* - video/rmnimbus.c - - Research machines Nimbus. - - 2009-11-14, P.Harvey-Smith. - - This is my best guess implementation of the operation of the Nimbus - video system. - - On the real machine, the Video chip has a block of 64K of memory which is - completely separate from the main 80186 memory. - - The main CPU write to the video chip via a series of registers in the - 0x0000 to 0x002F reigon, the video chip then manages all video memory - from there. - - As I cannot find a datasheet for the vide chip marked - MB61H201 Fujitsu RML 12835 GCV, I have had to determine most of its - operation by disassembling the Nimbus bios and by writing experemental - code on the real machine. - - 2021-09-29, P.Harvey-Smith. - - I now have access to the service manual for the Nimbus, this documents to facilities provided - by the video chip, which will hopefully allow a much more accurate implementation. -*/ - -#include "emu.h" -#include "includes/rmnimbus.h" - -#include "debugger.h" -#include "debug/debugcon.h" - -#include <functional> - -/* - Acording to the service manual the Nimbus should be capable of the following modes : - - 320 x 200 4bpp - 640 x 200 2bpp - 400 x 200 4bpp - 800 x 200 2bpp - 320 x 250 4bpp - 640 x 250 2bpp - 400 x 250 4bpp - 800 x 250 2bpp -*/ - -/* - From the service manual the registers are defined as follows : - -Ports 0x00-0x1E are the registers used to update the display RAM thus : - -Addr m_x m_y Update memory on write? -0x00 nop nop no -0x02 load nop no -0x04 nop inc no -0x06 load inc no -0x08 nop nop no -0x0A inc nop no -0x0C nop load no -0x0E inc load no -0x10 nop nop yes -0x12 load nop yes -0x14 nop inc yes -0x16 load inc yes -0x18 nop nop yes -0x1A inc nop yes -0x1C nop load yes -0x1E inc load yes - -0x20 scroll port, contains 8 bit scroll address - -0x22 Update mode control port (up_mode), controls how data is written to display ram. - see UPMODE_ constants below - -0x24h Intensity port, provides current logical intensities for update operations - bits 0..3 Foreground - bits 4..7 Background - -0x26 Display mode (m_mode) current display mode and border colour. - see MODE_ constants below - -For READ. -Ports 0x28, 0x2A, 0x2C and 0x2E have different read and write functions : - -0x28 Timing / status, all bits active high - bit 0 line blank - bit 1 line display - bit 2 frame blank - bit 3 frame display - -0x2A X address status, returns current value of X counter (m_x) - -0x2C Y address status, returns current value of Y counter (m_y) - -For Write - -0x28, 0x2A, 0x2C, 0x2E Colour look up table : - - Logic colour -Port Bits Low res High Res -0x28 0..3 0 0 -0x28 4..7 1 0 -0x28 8..11 2 0 -0x28 12..15 3 0 - -0x2A 0..3 3 1 -0x2A 4..7 5 1 -0x2A 8..11 6 1 -0x2A 12..15 7 1 - -0x2C 0..3 8 2 -0x2C 4..7 9 2 -0x2C 8..11 10 2 -0x2C 12..15 11 2 - -0x2E 0..3 12 3 -0x2E 4..7 13 3 -0x2E 8..11 14 3 -0x2E 12..15 15 3 - - -*/ - -// In following definitions ports are the WORD offset, the RM manual -// lists them by the byte offset so they are 2* the value - -#define P_SCROLL 0x10 -#define P_UPDATE_MODE 0x11 -#define P_INTENSITY 0x12 -#define P_MODE 0x13 -#define P_STATUS 0x14 -#define P_X_COUNT 0x15 -#define P_Y_COUNT 0x16 - -#define P_COLOUR03 0x14 -#define P_COLOUR47 0x15 -#define P_COLOUR8B 0x16 -#define P_COLOURCF 0x17 - -// From the service manual, Reg022 update mode constants : -// The first 8 are NON XOR writes -#define UPMODE_40_TEXT 0x00 // 40 character text -#define UPMODE_80_TEXT 0x01 // 80 character text -#define UPMODE_LO_PIXEL 0x02 // Low res pixel -#define UPMODE_HI_PIXEL 0x03 // Hi res pixel -#define UPMODE_ANIMATION 0x04 // Animation (mask + data) -#define UPMODE_SCROLL 0x05 // Scroll mode -#define UPMODE_DIRECT 0x06 // Direct write to video ram -#define UPMODE_ILLEGAL7 0x07 - -// The second 8 are XOR writes -#define UPMODE_40_TEXT_X 0x08 -#define UPMODE_80_TEXT_X 0x09 -#define UPMODE_LO_PIXEL_X 0x0A -#define UPMODE_HI_PIXEL_X 0x0B -#define UPMODE_ANIMATION_X 0x0C -#define UPMODE_SCROLL_X 0x0D -#define UPMODE_DIRECT_X 0x0E -#define UPMODE_ILLEGALF 0x0F - -#define UP_XOR_MASK 0x08 - -// port 026, display mode (m_mode) -#define MODE_BORDER 0x0F // bits 0..3, Border colour number -#define MODE_RESOLUTION 0x10 // bit 4, 0=low res (40 col), high = high res (80 col) -#define MODE_WIDTH 0x20 // bit 5, 0=narrow, 1=wide -#define MODE_HEIGHT 0x40 // bit 6, 0=625 lines, 1=562 - -#define WIDTH_MASK 0x07 - -#define FG_COLOUR (m_colours&0x0F) -#define BG_COLOUR ((m_colours&0xF0)>>4) -#define SELECT_COL(x,c) (IS_80COL ? ((((x) & 1) ? ((c) << 2) : (c)) & 0xC) : (c)) -#define FILL_WORD(c) (((c) << 12) | ((c) << 8) | ((c) << 4) | (c)) - -#define IS_80COL (m_mode & MODE_RESOLUTION) -#define IS_XOR (m_upmode & UP_XOR_MASK) - -#define DEBUG_TEXT 0x01 -#define DEBUG_DB 0x02 -#define DEBUG_PIXEL 0x04 - -#define DEBUG_SET(flags) ((m_debug_video & (flags))==(flags)) - -uint16_t rmnimbus_state::nimbus_video_io_r(offs_t offset, uint16_t mem_mask) -{ - uint16_t result = 0; - - switch (offset) - { - case 0x00: - case 0x08: - result = read_pixel_data(m_x, m_y); - break; - case 0x02: - case 0x0A: - result = read_pixel_data(m_x, ++m_y); - break; - case 0x05: - case 0x0D: - result = read_pixel_data(++m_x, m_y); - break; - - case P_SCROLL: - result = m_yline; - break; - case P_UPDATE_MODE: - result = m_upmode; - break; - case P_INTENSITY: - result = m_colours; - break; - case P_MODE: - result = m_mode; - break; - case P_STATUS: - result = m_screen->vpos() % 0xb; // TODO: verify - break; - case P_X_COUNT: - result = m_x; - break; - case P_Y_COUNT: - result = m_y; - break; - - default: - logerror("nimbus: unknown video reg read %02x\n", offset); - break; - } - - if(DEBUG_SET(DEBUG_TEXT)) - logerror("Nimbus video IOR at %05X from %04X mask=%04X, data=%04X\n",m_maincpu->pc(),(offset*2),mem_mask,result); - - return result; -} - -uint8_t rmnimbus_state::get_pixel(uint16_t x, uint16_t y) -{ - uint8_t result = 0; - - if((x<640) && (y<250)) - { - if(IS_80COL) - result=m_video_mem.pix(y, x) >> 2; - else - result=m_video_mem.pix(y, x*2); - } - - return result; -} - -uint16_t rmnimbus_state::read_pixel_line(uint16_t x, uint16_t y, uint8_t pixels, uint8_t bpp) -{ - uint16_t colour = 0; - int i; - x *= pixels; - - if(DEBUG_SET(DEBUG_TEXT | DEBUG_PIXEL)) - logerror("read_pixel_line(x=%d, y=%d, width=%d, bpp=%d)\n",x,y,pixels,bpp); - - for(i = 0; i < pixels - 1; i++) - { - colour |= get_pixel(i + x, y); - - if(bpp==1) - colour=((colour==SELECT_COL(x + i, FG_COLOUR)) ? 1 : 0) << 1; - else - colour <<= bpp; - } - return colour | get_pixel(x + i, y); -} - -uint16_t rmnimbus_state::read_pixel_data(uint16_t x, uint16_t y) -{ - uint16_t result=0; - - if(DEBUG_SET(DEBUG_TEXT | DEBUG_PIXEL)) - logerror("read_pixel_data(x=%d, y=%d), reg022=%04X\n",x,y,m_upmode); - - if(IS_80COL) - { - switch (m_upmode & WIDTH_MASK) - { - case 0x00 : break; - - case 0x01 : break; - - case 0x02 : break; - - case 0x03 : break; - - case 0x04 : - result=read_pixel_line(x,y,4,2); - break; - - case 0x05 : break; - - case 0x06 : - result=read_pixel_line(x,y,8,2); - break; - - case 0x07 : break; - } - } - else /* 40 Col */ - { - switch (m_upmode & WIDTH_MASK) - { - case 0x00 : break; - - case 0x01 : break; - - case 0x02 : break; - - case 0x03 : break; - - case 0x04 : break; - - case 0x05 : break; - - case 0x06 : - result=read_pixel_line(x,y,4,4); - break; - - case 0x07 : break; - } - } - - return result; -} - -/* - Write to the video registers. - - Incase anyone wonders about the DEBUG_DB statement, this allows me to log which registers - are being written to and then play them back at the real machine, this has helped greatly - in figuring out what the video registers do. - -*/ - -void rmnimbus_state::nimbus_video_io_w(offs_t offset, uint16_t data, uint16_t mem_mask) -{ - uint16_t colours = data; - if(offset < 0x14) - { - if(DEBUG_SET(DEBUG_TEXT)) - logerror("Nimbus video IOW at %05X write of %04X to %04X mask=%04X\n",m_maincpu->pc(),data,(offset*2),mem_mask); - - if(DEBUG_SET(DEBUG_DB)) - logerror("dw %05X,%05X\n",(offset*2),data); - } - - switch (offset) - { - case 0x00: - case 0x08: - break; - - case 0x09: - colours = FILL_WORD(FG_COLOUR); - [[fallthrough]]; - case 0x01: - m_x = data; - break; - - case 0x02: - case 0x0A: - m_y++; - break; - - case 0x0B: - colours = FILL_WORD(FG_COLOUR); - [[fallthrough]]; - case 0x03: - m_x = data; - m_y++; - break; - - case 0x05: - case 0x0D: - m_x++; - break; - - case 0x0E: - colours = FILL_WORD(FG_COLOUR); - [[fallthrough]]; - case 0x06: - m_y = data; - break; - - case 0x0F: - colours = FILL_WORD(FG_COLOUR); - [[fallthrough]]; - case 0x07: - m_y = data; - m_x++; - break; - - case P_SCROLL: - m_yline = data; - return; - case P_UPDATE_MODE: - m_upmode = data; - return; - case P_INTENSITY: - m_colours = data; - return; - case P_MODE: - /* - bits 0..3 of reg026 contain the border colour. - bit 5 contains the 40/80 column (320/640 pixel) flag. - */ - m_mode = data; - return; - case P_COLOUR03: - case P_COLOUR47: - case P_COLOUR8B: - case P_COLOURCF: - change_palette(offset - P_COLOUR03, data); - return; - - default: - logerror("nimbus: unknown video reg write %02x %04x\n", offset, data); - return; - } - if(offset & 0x08) - write_pixel_data(m_x, m_y, colours); -} - -void rmnimbus_state::set_pixel(uint16_t x, uint16_t y, uint8_t colour) -{ - if(DEBUG_SET(DEBUG_TEXT | DEBUG_PIXEL)) - logerror("set_pixel(x=%d, y=%d, colour=%04X), IS_XOR=%02X\n",x,y,colour,IS_XOR); - - if((x<640) && (y<250)) - { - if(IS_XOR) - m_video_mem.pix(y, x)^=colour; - else - m_video_mem.pix(y, x)=colour; - } -} - -void rmnimbus_state::set_pixel40( uint16_t x, uint16_t y, uint8_t colour) -{ - set_pixel((x*2),y,colour); - set_pixel((x*2)+1,y,colour); -} - -void rmnimbus_state::write_pixel_line(uint16_t x, uint16_t y, uint16_t data, uint8_t pixels, uint8_t bpp) -{ - uint8_t colour; - uint8_t mask = (1 << bpp) - 1; - x *= pixels; - - if(DEBUG_SET(DEBUG_TEXT | DEBUG_PIXEL)) - logerror("write_pixel_line(x=%d, y=%d, data=%04X, width=%d, bpp=%d)\n",x,y,data,pixels,bpp); - - for(int i = (pixels - 1); i >= 0; i--) - { - if(bpp==1) - colour = SELECT_COL(x + i, (data & 1) ? FG_COLOUR : BG_COLOUR); - else if(IS_80COL) - colour = (data & mask) << 2; - else - colour = (data & mask); - - if(IS_80COL) - set_pixel(x + i,y,colour); - else - set_pixel40(x + i,y,colour); - - data >>= bpp; - } -} - -void rmnimbus_state::move_pixel_line(uint16_t x, uint16_t y, uint8_t pixels) -{ - x *= pixels; - if(DEBUG_SET(DEBUG_TEXT | DEBUG_PIXEL)) - logerror("move_pixel_line(x=%d, y=%d, width=%d)\n",x,y,pixels); - - for(int i = 0; i < pixels; i++) - { - if(DEBUG_SET(DEBUG_TEXT | DEBUG_PIXEL)) - logerror("x=%d\n",x + i); - m_video_mem.pix(m_yline, x + i) = m_video_mem.pix(y, x + i); - } -} - - - -/* - The values in the bottom 3 bits of reg022 seem to determine the number of bits per pixel - for following operations. - - The values that I have decoded so far are : - - 000 1bpp, foreground and background colours taken from reg024 - 001 2bpp, using the first 4 colours of the pallette - 010 - 011 - 100 4bpp, must be a 16 bit word, of which the upper byte is a mask anded with existing pixels then ored - with the lower byte containing the pixel data for two pixels. - 101 Move pixel data at x,reg020 to x,y, used for scrolling. - 110 if 40 col - 4bpp, 16 bit word containing the pixel data for 4 pixels. - else - 2bpp, 16 bit word containing the pixel data for 8 pixels. - 111 - - Bit 3 of reg022 is as follows : - - 0 pixels are written from supplied colour data - 1 pixels are xor'ed onto the screen -*/ - -void rmnimbus_state::write_pixel_data(uint16_t x, uint16_t y, uint16_t data) -{ - if(DEBUG_SET(DEBUG_TEXT | DEBUG_PIXEL)) - logerror("write_pixel_data(x=%d, y=%d, data=%04X), reg022=%04X\n",x,y,data,m_upmode); - - if(IS_80COL) - { - switch (m_upmode & WIDTH_MASK) - { - case UPMODE_40_TEXT: - write_pixel_line(x,y,data,16,1); - break; - - case UPMODE_80_TEXT: - write_pixel_line(x,y,data,8,1); - break; - - case UPMODE_LO_PIXEL: - write_pixel_line(x,y,data,8,1); - break; - - case UPMODE_HI_PIXEL: - set_pixel(x,y,SELECT_COL(x, FG_COLOUR)); - break; - - case UPMODE_ANIMATION: - write_pixel_line(x,y,(((data & 0xFF00)>>8) & (data & 0xFF)) | (~((data & 0xFF00)>>8) & read_pixel_line(x,y,4,2)),4,2); - break; - - case UPMODE_SCROLL: - move_pixel_line(x,y,16); - break; - - case UPMODE_DIRECT: - write_pixel_line(x,y,data,8,2); - break; - - case UPMODE_ILLEGAL7: - set_pixel(x,y,SELECT_COL(x, FG_COLOUR)); - break; - } - } - else /* 40 Col */ - { - switch (m_upmode & WIDTH_MASK) - { - case UPMODE_40_TEXT: - write_pixel_line(x,y,data,8,1); - break; - - case UPMODE_80_TEXT: - write_pixel_line(x,y,data,4,2); - break; - - case UPMODE_LO_PIXEL: - set_pixel40(x,y,FG_COLOUR); - break; - - case UPMODE_HI_PIXEL: - set_pixel(x,y,FG_COLOUR); - break; - - case UPMODE_ANIMATION: - write_pixel_line(x,y,(((data & 0xFF00)>>8) & (data & 0xFF)) | (~((data & 0xFF00)>>8) & read_pixel_line(x,y,2,4)),2,4); - break; - - case UPMODE_SCROLL: - move_pixel_line(x,y,16); - break; - - case UPMODE_DIRECT: - write_pixel_line(x,y,data,4,4); - break; - - case UPMODE_ILLEGAL7: - set_pixel(x,y,FG_COLOUR); - break; - } - } -} - -// Colours are encoded as follows : -// Each nibble contains a colour encoded as igrb -// so we shift through the specified colours and extract the bits, to set the palette. -// -void rmnimbus_state::change_palette(uint8_t bank, uint16_t colours) -{ - // loop over changing colours - for(int colourno = (bank * 4); colourno < ((bank + 1) * 4); colourno++) - { - int i = (colours & 8) >> 3; - m_palette->set_pen_color(colourno, pal2bit((colours & 2) | i), pal2bit(((colours & 4) >> 1) | i), pal2bit(((colours & 1) << 1) | i)); - - if(DEBUG_SET(DEBUG_TEXT)) - logerror("set colourno[%02X], colour=%02X\n",colourno, colours & 0xf); - colours >>= 4; - } -} - -void rmnimbus_state::video_debug(const std::vector<std::string> ¶ms) -{ - if (params.size() > 0) - { - int temp; - sscanf(params[0].c_str(), "%d", &temp); - m_debug_video = temp; - } - else - { - machine().debugger().console().printf("Error usage : nimbus_vid_debug <debuglevel>\n"); - machine().debugger().console().printf("Current debuglevel=%02X\n", m_debug_video); - } -} - -void rmnimbus_state::video_start() -{ - m_debug_video = 0; - - m_screen->register_screen_bitmap(m_video_mem); - - if (machine().debug_flags & DEBUG_FLAG_ENABLED) - { - using namespace std::placeholders; - machine().debugger().console().register_command("nimbus_vid_debug", CMDFLAG_NONE, 0, 1, std::bind(&rmnimbus_state::video_debug, this, _1)); - } -} - -void rmnimbus_state::video_reset() -{ - m_mode = 0; - m_x = 0; - m_y = 0; - m_upmode = 0; - m_yline = 0; -} - -uint32_t rmnimbus_state::screen_update_nimbus(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect) -{ - copybitmap(bitmap, m_video_mem, 0, 0, 0, 0, cliprect); - - return 0; -} |