mirror of
https://github.com/holub/mame
synced 2025-06-30 07:58:56 +03:00
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:
parent
fc906d7a17
commit
a8ffd2235a
@ -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,6 +189,7 @@ 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;
|
||||
@ -196,6 +197,7 @@ private:
|
||||
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;
|
||||
|
||||
|
@ -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();
|
||||
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;
|
||||
uint8_t intstate_x; // Used to calculate if we should trigger interrupt
|
||||
uint8_t intstate_y;
|
||||
int xint;
|
||||
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();
|
||||
|
||||
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;
|
||||
}
|
||||
// Read mose positions and calculate difference from previous value
|
||||
mouse_x = m_io_mousex->read();
|
||||
mouse_y = m_io_mousey->read();
|
||||
|
||||
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;
|
||||
}
|
||||
xdiff = m_nimbus_mouse.m_mouse_x - mouse_x;
|
||||
ydiff = m_nimbus_mouse.m_mouse_y - mouse_y;
|
||||
|
||||
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;
|
||||
}
|
||||
// check and compensate for wrap.....
|
||||
if (xdiff > 0x80)
|
||||
xdiff -= 0x100;
|
||||
else if (xdiff < -0x80)
|
||||
xdiff += 0x100;
|
||||
|
||||
if (ydiff > 0x80)
|
||||
ydiff -= 0x100;
|
||||
else if (ydiff < -0x80)
|
||||
ydiff += 0x100;
|
||||
|
||||
// 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
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user