RM Nimbus updates: (#8684)

* Updated mouse handling so it mostly works
* Updated SASI/SCSI code so that formatting disks with HDFORM works for ST125N and ST225N.
* Added documentation of the video code drawn from the Nimbus Service manual.
This commit is contained in:
prime6809 2021-10-10 21:26:32 +01:00 committed by GitHub
parent fc906d7a17
commit a8ffd2235a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 312 additions and 167 deletions

View File

@ -121,7 +121,7 @@ private:
uint8_t m_last_playmode;
uint8_t m_ay8910_a;
uint16_t m_x, m_y, m_yline;
uint8_t m_colours, m_mode, m_op;
uint8_t m_colours, m_mode, m_upmode;
uint32_t m_debug_video;
uint8_t m_vector;
uint8_t m_eeprom_bits;
@ -189,13 +189,15 @@ private:
void rmni_sound_reset();
void mouse_js_reset();
void check_scsi_irq();
void set_scsi_drqlat(bool clock, bool clear);
int m_scsi_iena;
int m_scsi_msg;
int m_scsi_bsy;
int m_scsi_io;
int m_scsi_cd;
int m_scsi_req;
int m_scsi_reqlat;
virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) override;
@ -222,12 +224,9 @@ private:
/* Mouse/Joystick */
struct
{
uint8_t m_mouse_px;
uint8_t m_mouse_py;
int8_t m_mouse_x;
int8_t m_mouse_y;
uint8_t m_mouse_x;
uint8_t m_mouse_y;
uint8_t m_mouse_pc;
uint8_t m_mouse_pcx;
uint8_t m_mouse_pcy;

View File

@ -109,12 +109,16 @@ chdman createhd -o ST125N.chd -chs 41921,1,1 -ss 512
#define MOUSE_INT_ENABLE 0x08
#define PC8031_INT_ENABLE 0x10
enum
{
MOUSE_PHASE_STATIC = 0,
MOUSE_PHASE_POSITIVE,
MOUSE_PHASE_NEGATIVE
};
#define MOUSE_NONE 0x00
#define MOUSE_LEFT 0x01
#define MOUSE_RIGHT 0x02
#define MOUSE_DOWN 0x04
#define MOUSE_UP 0x08
#define MOUSE_LBUTTON 0x10
#define MOUSE_RBUTTON 0x20
// Frequency in Hz to poll for mouse movement.
#define MOUSE_POLL_FREQUENCY 5000
#define MOUSE_INT_ENABLED(state) (((state)->m_iou_reg092 & MOUSE_INT_ENABLE) ? 1 : 0)
@ -1064,7 +1068,7 @@ uint8_t rmnimbus_state::scsi_r(offs_t offset)
result |= m_scsi_cd << 6;
result |= m_scsi_io << 5;
result |= m_scsi_bsy << 4;
result |= !m_scsi_msg << 3;
result |= m_scsi_msg << 3;
if(floppy)
{
result |= FDC_MOTOR() << 2;
@ -1100,7 +1104,7 @@ uint8_t rmnimbus_state::scsi_r(offs_t offset)
*/
void rmnimbus_state::fdc_ctl_w(uint8_t data)
{
uint8_t reg400_old = m_nimbus_drives.reg400;
uint8_t old_drq = m_nimbus_drives.reg400 & HDC_DRQ_MASK;
char drive[5];
floppy_image_device *floppy;
@ -1117,8 +1121,8 @@ void rmnimbus_state::fdc_ctl_w(uint8_t data)
}
// if we enable hdc drq with a pending condition, act on it
if((data & HDC_DRQ_MASK) && (~reg400_old & HDC_DRQ_MASK))
hdc_drq(true);
if((data & HDC_DRQ_MASK) && (!old_drq))
set_scsi_drqlat(false, false);
}
/*
@ -1157,8 +1161,18 @@ void rmnimbus_state::hdc_reset()
m_scsi_io = 0;
m_scsi_cd = 0;
m_scsi_req = 0;
// Latched req, IC11b
m_scsi_reqlat = 0;
}
/*
The SCSI code outputs a 1 to indicate an active line, even though it is active low
The inputs on the RM schematic are fed through inverters, but because of the above
we don't need to invert them, unless the schematic uses the signal directly
For consistency we will invert msg before latching.
*/
void rmnimbus_state::check_scsi_irq()
{
nimbus_fdc_intrq_w(m_scsi_io && m_scsi_cd && m_scsi_req && m_scsi_iena);
@ -1170,10 +1184,27 @@ WRITE_LINE_MEMBER(rmnimbus_state::write_scsi_iena)
check_scsi_irq();
}
// This emulates the 74LS74 latched version of req
void rmnimbus_state::set_scsi_drqlat(bool clock, bool clear)
{
if (clear)
m_scsi_reqlat = 0;
else if (clock)
m_scsi_reqlat = 1;
if(m_scsi_reqlat)
hdc_drq(true);
else
hdc_drq(false);
}
void rmnimbus_state::hdc_post_rw()
{
if(m_scsi_req)
m_scsibus->write_ack(1);
// IC17A, IC17B, latched req cleared by SCSI data read or write, or C/D= command
set_scsi_drqlat(false, true);
}
void rmnimbus_state::hdc_drq(bool state)
@ -1189,6 +1220,10 @@ WRITE_LINE_MEMBER( rmnimbus_state::write_scsi_bsy )
WRITE_LINE_MEMBER( rmnimbus_state::write_scsi_cd )
{
m_scsi_cd = state;
// IC17A, IC17B, latched req cleared by SCSI data read or write, or C/D= command
set_scsi_drqlat(false, !m_scsi_cd);
check_scsi_irq();
}
@ -1205,26 +1240,23 @@ WRITE_LINE_MEMBER( rmnimbus_state::write_scsi_io )
WRITE_LINE_MEMBER( rmnimbus_state::write_scsi_msg )
{
m_scsi_msg = state;
m_scsi_msg = !state;
}
WRITE_LINE_MEMBER( rmnimbus_state::write_scsi_req )
{
int last = m_scsi_req;
// Detect rising edge on req, IC11b, clock
int rising = ((m_scsi_req == 0) && (state == 1));
// This is the state of the actual line from the SCSI
m_scsi_req = state;
if (state)
{
if (!m_scsi_cd && !last)
{
hdc_drq(true);
}
}
else
{
hdc_drq(false);
// Latched req, is forced low by C/D being set to command
set_scsi_drqlat(rising, m_scsi_cd);
if (!m_scsi_reqlat)
m_scsibus->write_ack(0);
}
check_scsi_irq();
}
@ -1500,18 +1532,13 @@ WRITE_LINE_MEMBER(rmnimbus_state::nimbus_msm5205_vck)
external_int(EXTERNAL_INT_MSM5205,state);
}
static const int MOUSE_XYA[3][4] = { { 0, 0, 0, 0 }, { 1, 1, 0, 0 }, { 0, 1, 1, 0 } };
static const int MOUSE_XYB[3][4] = { { 0, 0, 0, 0 }, { 0, 1, 1, 0 }, { 1, 1, 0, 0 } };
//static const int MOUSE_XYA[4] = { 1, 1, 0, 0 };
//static const int MOUSE_XYB[4] = { 0, 1, 1, 0 };
static const int MOUSE_XYA[4] = { 1, 1, 0, 0 };
static const int MOUSE_XYB[4] = { 0, 1, 1, 0 };
void rmnimbus_state::mouse_js_reset()
{
m_nimbus_mouse.m_mouse_px=0;
m_nimbus_mouse.m_mouse_py=0;
m_nimbus_mouse.m_mouse_x=128;
m_nimbus_mouse.m_mouse_y=128;
m_nimbus_mouse.m_mouse_pc=0;
m_nimbus_mouse.m_mouse_pcx=0;
m_nimbus_mouse.m_mouse_pcy=0;
m_nimbus_mouse.m_intstate_x=0;
@ -1519,114 +1546,88 @@ void rmnimbus_state::mouse_js_reset()
m_nimbus_mouse.m_reg0a4=0xC0;
// Setup timer to poll the mouse
m_nimbus_mouse.m_mouse_timer->adjust(attotime::zero, 0, attotime::from_hz(1000));
m_nimbus_mouse.m_mouse_timer->adjust(attotime::zero, 0, attotime::from_hz(MOUSE_POLL_FREQUENCY));
}
void rmnimbus_state::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr)
{
uint8_t x = 0;
uint8_t y = 0;
// int pc=m_maincpu->pc();
uint8_t intstate_x;
uint8_t intstate_y;
int xint;
int mouse_x = 0; // Current mouse X and Y
int mouse_y = 0;
int xdiff = 0; // Difference from previous X and Y
int ydiff = 0;
uint8_t intstate_x; // Used to calculate if we should trigger interrupt
uint8_t intstate_y;
int xint; // X and Y interrupts to trigger
int yint;
m_nimbus_mouse.m_reg0a4 = m_io_mouse_button->read() | 0xC0;
x = m_io_mousex->read();
y = m_io_mousey->read();
uint8_t mxa;
uint8_t mxa; // Values of quadrature encoders for X and Y
uint8_t mxb;
uint8_t mya;
uint8_t myb;
//logerror("poll_mouse()\n");
// Read mouse buttons
m_nimbus_mouse.m_reg0a4 = m_io_mouse_button->read();
// Read mose positions and calculate difference from previous value
mouse_x = m_io_mousex->read();
mouse_y = m_io_mousey->read();
if (x == m_nimbus_mouse.m_mouse_x)
{
m_nimbus_mouse.m_mouse_px = MOUSE_PHASE_STATIC;
}
else if (x > m_nimbus_mouse.m_mouse_x)
{
m_nimbus_mouse.m_mouse_px = MOUSE_PHASE_POSITIVE;
}
else if (x < m_nimbus_mouse.m_mouse_x)
{
m_nimbus_mouse.m_mouse_px = MOUSE_PHASE_NEGATIVE;
}
xdiff = m_nimbus_mouse.m_mouse_x - mouse_x;
ydiff = m_nimbus_mouse.m_mouse_y - mouse_y;
// check and compensate for wrap.....
if (xdiff > 0x80)
xdiff -= 0x100;
else if (xdiff < -0x80)
xdiff += 0x100;
if (y == m_nimbus_mouse.m_mouse_y)
{
m_nimbus_mouse.m_mouse_py = MOUSE_PHASE_STATIC;
}
else if (y > m_nimbus_mouse.m_mouse_y)
{
m_nimbus_mouse.m_mouse_py = MOUSE_PHASE_POSITIVE;
}
else if (y < m_nimbus_mouse.m_mouse_y)
{
m_nimbus_mouse.m_mouse_py = MOUSE_PHASE_NEGATIVE;
}
if (ydiff > 0x80)
ydiff -= 0x100;
else if (ydiff < -0x80)
ydiff += 0x100;
switch (m_nimbus_mouse.m_mouse_px)
{
case MOUSE_PHASE_STATIC : break;
case MOUSE_PHASE_POSITIVE : m_nimbus_mouse.m_mouse_pcx++; break;
case MOUSE_PHASE_NEGATIVE : m_nimbus_mouse.m_mouse_pcx--; break;
}
// convert movement into emulated movement of quadrature encoder in mouse.
if (xdiff < 0)
m_nimbus_mouse.m_mouse_pcx++;
else if (xdiff > 0)
m_nimbus_mouse.m_mouse_pcx--;
if (ydiff < 0)
m_nimbus_mouse.m_mouse_pcy++;
else if (ydiff > 0)
m_nimbus_mouse.m_mouse_pcy--;
// Compensate for quadrature wrap.
m_nimbus_mouse.m_mouse_pcx &= 0x03;
switch (m_nimbus_mouse.m_mouse_py)
{
case MOUSE_PHASE_STATIC : break;
case MOUSE_PHASE_POSITIVE : m_nimbus_mouse.m_mouse_pcy++; break;
case MOUSE_PHASE_NEGATIVE : m_nimbus_mouse.m_mouse_pcy--; break;
}
m_nimbus_mouse.m_mouse_pcy &= 0x03;
// mxb = MOUSE_XYB[state.m_mouse_px][state->m_mouse_pcx]; // XB
// mxa = MOUSE_XYA[state.m_mouse_px][state->m_mouse_pcx]; // XA
// mya = MOUSE_XYA[state.m_mouse_py][state->m_mouse_pcy]; // YA
// myb = MOUSE_XYB[state.m_mouse_py][state->m_mouse_pcy]; // YB
mxb = MOUSE_XYB[1][m_nimbus_mouse.m_mouse_pcx]; // XB
mxa = MOUSE_XYA[1][m_nimbus_mouse.m_mouse_pcx]; // XA
mya = MOUSE_XYA[1][m_nimbus_mouse.m_mouse_pcy]; // YA
myb = MOUSE_XYB[1][m_nimbus_mouse.m_mouse_pcy]; // YB
if ((m_nimbus_mouse.m_mouse_py!=MOUSE_PHASE_STATIC) || (m_nimbus_mouse.m_mouse_px!=MOUSE_PHASE_STATIC))
{
// logerror("mouse_px=%02X, mouse_py=%02X, mouse_pcx=%02X, mouse_pcy=%02X\n",
// state.m_mouse_px,state->m_mouse_py,state->m_mouse_pcx,state->m_mouse_pcy);
// logerror("mxb=%02x, mxa=%02X (mxb ^ mxa)=%02X, (ay8910_a & 0xC0)=%02X, (mxb ^ mxa) ^ ((ay8910_a & 0x80) >> 7)=%02X\n",
// mxb,mxa, (mxb ^ mxa) , (state.m_ay8910_a & 0xC0), (mxb ^ mxa) ^ ((state->m_ay8910_a & 0x40) >> 6));
}
// get value of mouse quadrature encoders for this wheel position
mxa = MOUSE_XYA[m_nimbus_mouse.m_mouse_pcx]; // XA
mxb = MOUSE_XYB[m_nimbus_mouse.m_mouse_pcx]; // XB
mya = MOUSE_XYA[m_nimbus_mouse.m_mouse_pcy]; // YA
myb = MOUSE_XYB[m_nimbus_mouse.m_mouse_pcy]; // YB
// calculate interrupt state
intstate_x = (mxb ^ mxa) ^ ((m_ay8910_a & 0x40) >> 6);
intstate_y = (myb ^ mya) ^ ((m_ay8910_a & 0x80) >> 7);
// Generate interrupts if enabled, otherwise return values in
// mouse register
if (MOUSE_INT_ENABLED(this))
{
if ((intstate_x==1) && (m_nimbus_mouse.m_intstate_x==0))
// if (intstate_x!=state.m_intstate_x)
{
xint=mxa ? EXTERNAL_INT_MOUSE_XR : EXTERNAL_INT_MOUSE_XL;
xint=mxa ? EXTERNAL_INT_MOUSE_XL : EXTERNAL_INT_MOUSE_XR;
external_int(xint, true);
// logerror("Xint:%02X, mxb=%02X\n",xint,mxb);
}
if ((intstate_y==1) && (m_nimbus_mouse.m_intstate_y==0))
// if (intstate_y!=state.m_intstate_y)
{
yint=myb ? EXTERNAL_INT_MOUSE_YU : EXTERNAL_INT_MOUSE_YD;
yint=myb ? EXTERNAL_INT_MOUSE_YD : EXTERNAL_INT_MOUSE_YU;
external_int(yint, true);
// logerror("Yint:%02X, myb=%02X\n",yint,myb);
}
}
else
@ -1638,15 +1639,11 @@ void rmnimbus_state::device_timer(emu_timer &timer, device_timer_id id, int para
m_nimbus_mouse.m_reg0a4 |= ( myb & 0x01) << 0; // YB
}
m_nimbus_mouse.m_mouse_x = x;
m_nimbus_mouse.m_mouse_y = y;
if ((m_nimbus_mouse.m_mouse_py!=MOUSE_PHASE_STATIC) || (m_nimbus_mouse.m_mouse_px!=MOUSE_PHASE_STATIC))
{
// logerror("pc=%05X, reg0a4=%02X, reg092=%02X, ay_a=%02X, x=%02X, y=%02X, px=%02X, py=%02X, intstate_x=%02X, intstate_y=%02X\n",
// pc,state.m_reg0a4,state->m_iou_reg092,state->m_ay8910_a,state->m_mouse_x,state->m_mouse_y,state->m_mouse_px,state->m_mouse_py,intstate_x,intstate_y);
}
// Update current mouse position
m_nimbus_mouse.m_mouse_x = mouse_x;
m_nimbus_mouse.m_mouse_y = mouse_y;
// and interrupt state
m_nimbus_mouse.m_intstate_x=intstate_x;
m_nimbus_mouse.m_intstate_y=intstate_y;
}
@ -1672,21 +1669,25 @@ uint8_t rmnimbus_state::nimbus_mouse_js_r()
if (m_io_config->read() & 0x01)
{
result=m_nimbus_mouse.m_reg0a4;
result=m_nimbus_mouse.m_reg0a4 | 0xC0;
//logerror("mouse_js_r: pc=%05X, result=%02X\n",pc,result);
}
else
{
result = m_io_joystick0->read();
result = m_io_joystick0->read() | 0xC0;
}
return result;
}
// Clear mose latches
void rmnimbus_state::nimbus_mouse_js_w(uint8_t data)
{
m_nimbus_mouse.m_reg0a4 = 0x00;
//logerror("clear mouse latches\n");
}
/**********************************************************************
Parallel printer / User port.
The Nimbus parallel printer port card is almost identical to the circuit

View File

@ -21,7 +21,13 @@
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"
@ -30,6 +36,140 @@
#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
@ -38,8 +178,8 @@
#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&0x10)
#define IS_XOR (m_op&8)
#define IS_80COL (m_mode & MODE_RESOLUTION)
#define IS_XOR (m_upmode & UP_XOR_MASK)
#define DEBUG_TEXT 0x01
#define DEBUG_DB 0x02
@ -66,27 +206,28 @@ uint16_t rmnimbus_state::nimbus_video_io_r(offs_t offset, uint16_t mem_mask)
result = read_pixel_data(++m_x, m_y);
break;
case 0x10:
case P_SCROLL:
result = m_yline;
break;
case 0x11:
result = m_op;
case P_UPDATE_MODE:
result = m_upmode;
break;
case 0x12:
case P_INTENSITY:
result = m_colours;
break;
case 0x13:
case P_MODE:
result = m_mode;
break;
case 0x14:
case P_STATUS:
result = m_screen->vpos() % 0xb; // TODO: verify
break;
case 0x15:
case P_X_COUNT:
result = m_x;
break;
case 0x16:
case P_Y_COUNT:
result = m_y;
break;
default:
logerror("nimbus: unknown video reg read %02x\n", offset);
break;
@ -139,11 +280,11 @@ 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_op);
logerror("read_pixel_data(x=%d, y=%d), reg022=%04X\n",x,y,m_upmode);
if(IS_80COL)
{
switch (m_op & WIDTH_MASK)
switch (m_upmode & WIDTH_MASK)
{
case 0x00 : break;
@ -168,7 +309,7 @@ uint16_t rmnimbus_state::read_pixel_data(uint16_t x, uint16_t y)
}
else /* 40 Col */
{
switch (m_op & WIDTH_MASK)
switch (m_upmode & WIDTH_MASK)
{
case 0x00 : break;
@ -260,27 +401,27 @@ void rmnimbus_state::nimbus_video_io_w(offs_t offset, uint16_t data, uint16_t me
m_x++;
break;
case 0x10:
case P_SCROLL:
m_yline = data;
return;
case 0x11:
m_op = data;
case P_UPDATE_MODE:
m_upmode = data;
return;
case 0x12:
case P_INTENSITY:
m_colours = data;
return;
case 0x13:
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 0x14:
case 0x15:
case 0x16:
case 0x17:
change_palette(offset - 0x14, data);
case P_COLOUR03:
case P_COLOUR47:
case P_COLOUR8B:
case P_COLOURCF:
change_palette(offset - P_COLOUR03, data);
return;
default:
@ -382,84 +523,88 @@ void rmnimbus_state::move_pixel_line(uint16_t x, uint16_t y, uint8_t pixels)
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_op);
logerror("write_pixel_data(x=%d, y=%d, data=%04X), reg022=%04X\n",x,y,data,m_upmode);
if(IS_80COL)
{
switch (m_op & WIDTH_MASK)
switch (m_upmode & WIDTH_MASK)
{
case 0x00:
case UPMODE_40_TEXT:
write_pixel_line(x,y,data,16,1);
break;
case 0x01:
case UPMODE_80_TEXT:
write_pixel_line(x,y,data,8,1);
break;
case 0x02:
case UPMODE_LO_PIXEL:
write_pixel_line(x,y,data,8,1);
break;
case 0x03:
case UPMODE_HI_PIXEL:
set_pixel(x,y,SELECT_COL(x, FG_COLOUR));
break;
case 0x04:
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 0x05:
case UPMODE_SCROLL:
move_pixel_line(x,y,16);
break;
case 0x06:
case UPMODE_DIRECT:
write_pixel_line(x,y,data,8,2);
break;
case 0x07:
case UPMODE_ILLEGAL7:
set_pixel(x,y,SELECT_COL(x, FG_COLOUR));
break;
}
}
else /* 40 Col */
{
switch (m_op & WIDTH_MASK)
switch (m_upmode & WIDTH_MASK)
{
case 0x00:
case UPMODE_40_TEXT:
write_pixel_line(x,y,data,8,1);
break;
case 0x01:
case UPMODE_80_TEXT:
write_pixel_line(x,y,data,4,2);
break;
case 0x02:
case UPMODE_LO_PIXEL:
set_pixel40(x,y,FG_COLOUR);
break;
case 0x03:
case UPMODE_HI_PIXEL:
set_pixel(x,y,FG_COLOUR);
break;
case 0x04:
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 0x05:
case UPMODE_SCROLL:
move_pixel_line(x,y,16);
break;
case 0x06:
case UPMODE_DIRECT:
write_pixel_line(x,y,data,4,4);
break;
case 0x07:
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
@ -507,7 +652,7 @@ void rmnimbus_state::video_reset()
m_mode = 0;
m_x = 0;
m_y = 0;
m_op = 0;
m_upmode = 0;
m_yline = 0;
}