wd_fdc: Wait for sector read/write to complete on interrupt d0-7, fixes rmnimbus floppy access errors

This commit is contained in:
prime6809 2021-11-08 18:36:00 +00:00 committed by GitHub
parent 5c64a1771a
commit 9ef70e0322
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 515 additions and 238 deletions

View File

@ -22,8 +22,10 @@
#define LOG_STATE (1U << 12) // Show state machine
#define LOG_LIVE (1U << 13) // Live states
#define LOG_FUNC (1U << 14) // Function calls
#define LOG_CRC (1U << 15) // CRC errors
#define VERBOSE (LOG_DESC)
//#define VERBOSE (LOG_DESC | LOG_COMMAND | LOG_MATCH | LOG_WRITE | LOG_STATE | LOG_LINES | LOG_COMP | LOG_CRC )
//#define LOG_OUTPUT_STREAM std::cout
#include "logmacro.h"
@ -42,6 +44,7 @@
#define LOGSTATE(...) LOGMASKED(LOG_STATE, __VA_ARGS__)
#define LOGLIVE(...) LOGMASKED(LOG_LIVE, __VA_ARGS__)
#define LOGFUNC(...) LOGMASKED(LOG_FUNC, __VA_ARGS__)
#define LOGCRC(...) LOGMASKED(LOG_CRC, __VA_ARGS__)
#ifdef _MSC_VER
#define FUNCNAME __func__
@ -79,6 +82,58 @@ DEFINE_DEVICE_TYPE(WD1770, wd1770_device, "wd1770", "Western Digital
DEFINE_DEVICE_TYPE(WD1772, wd1772_device, "wd1772", "Western Digital WD1772 FDC")
DEFINE_DEVICE_TYPE(WD1773, wd1773_device, "wd1773", "Western Digital WD1773 FDC")
static const char *const states[] =
{
"IDLE",
"RESTORE",
"SEEK",
"STEP",
"READ_SECTOR",
"READ_TRACK",
"READ_ID",
"WRITE_TRACK",
"WRITE_SECTOR",
"SPINUP",
"SPINUP_WAIT",
"SPINUP_DONE",
"SETTLE_WAIT",
"SETTLE_DONE",
"DATA_LOAD_WAIT",
"DATA_LOAD_WAIT_DONE",
"SEEK_MOVE",
"SEEK_WAIT_STEP_TIME",
"SEEK_WAIT_STEP_TIME_DONE",
"SEEK_WAIT_STABILIZATION_TIME",
"SEEK_WAIT_STABILIZATION_TIME_DONE",
"SEEK_DONE",
"WAIT_INDEX",
"WAIT_INDEX_DONE",
"SCAN_ID",
"SCAN_ID_FAILED",
"SECTOR_READ",
"SECTOR_WRITE",
"TRACK_DONE",
"INITIAL_RESTORE",
"DUMMY",
"SEARCH_ADDRESS_MARK_HEADER",
"READ_HEADER_BLOCK_HEADER",
"READ_DATA_BLOCK_HEADER",
"READ_ID_BLOCK_TO_LOCAL",
"READ_ID_BLOCK_TO_DMA",
"READ_ID_BLOCK_TO_DMA_BYTE",
"SEARCH_ADDRESS_MARK_DATA",
"SEARCH_ADDRESS_MARK_DATA_FAILED",
"READ_SECTOR_DATA",
"READ_SECTOR_DATA_BYTE",
"READ_TRACK_DATA",
"READ_TRACK_DATA_BYTE",
"WRITE_TRACK_DATA",
"WRITE_BYTE",
"WRITE_BYTE_DONE",
"WRITE_SECTOR_PRE",
"WRITE_SECTOR_PRE_BYTE"
};
wd_fdc_device_base::wd_fdc_device_base(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock) :
device_t(mconfig, type, tag, owner, clock),
intrq_cb(*this),
@ -131,6 +186,8 @@ void wd_fdc_device_base::device_start()
data = 0x00;
track = 0x00;
mr = true;
delay_int = false;
save_item(NAME(status));
save_item(NAME(command));
@ -435,6 +492,7 @@ void wd_fdc_device_base::seek_continue()
if(cur_live.crc) {
status |= S_CRC;
live_start(SEARCH_ADDRESS_MARK_HEADER);
LOGCRC("CRC error in seek\n");
return;
}
command_end();
@ -540,6 +598,7 @@ void wd_fdc_device_base::read_sector_continue()
if(cur_live.crc) {
status |= S_CRC;
live_start(SEARCH_ADDRESS_MARK_HEADER);
LOGCRC("CRC error in readsector\n");
return;
}
sector_size = calc_sector_size(cur_live.idbuf[3], command);
@ -556,7 +615,10 @@ void wd_fdc_device_base::read_sector_continue()
case SECTOR_READ:
LOGSTATE("SECTOR_READ\n");
if(cur_live.crc)
{
status |= S_CRC;
LOGCRC("CRC error in readsector %04X\n",cur_live.crc);
}
if(command & 0x10 && !(status & S_RNF)) {
sector++;
@ -920,6 +982,7 @@ void wd_fdc_device_base::write_sector_continue()
if(cur_live.crc) {
status |= S_CRC;
live_start(SEARCH_ADDRESS_MARK_HEADER);
LOGCRC("CRC error in writesector\n");
return;
}
sector_size = calc_sector_size(cur_live.idbuf[3], command);
@ -957,6 +1020,23 @@ void wd_fdc_device_base::interrupt_start()
LOGCOMMAND("cmd: forced interrupt (c=%02x)\n", command);
// If writing a byte to a sector, then wait until it's written before terminating
// This behavior is required by the RM nimbus driver, otherwise the forced interrupt
// at the end of a multiple sector write occasionally prevents the CRC byte being
// written, causing the disk to be corrupted.
if (/*((main_state == READ_SECTOR) && (cur_live.state == READ_SECTOR_DATA)) ||*/
((main_state == WRITE_SECTOR) && (cur_live.state == WRITE_BYTE)))
{
delay_int = true;
return;
}
else
{
delay_int = false;
}
//logerror("main_state=%s, cur_live.state=%s\n",states[main_state],states[cur_live.state]);
if(status & S_BUSY) {
main_state = sub_state = cur_live.state = IDLE;
cur_live.tm = attotime::never;
@ -1229,6 +1309,8 @@ uint8_t wd_fdc_device_base::status_r()
uint8_t val = status;
if (inverted_bus) val ^= 0xff;
LOGCOMP("Status value: %02X\n",val);
return val;
}
@ -1778,6 +1860,7 @@ void wd_fdc_device_base::live_run(attotime limit)
if(cur_live.bit_counter == 16*6) {
if(cur_live.crc) {
status |= S_CRC;
LOGCRC("CRC error in live_run\n");
}
// Already synchronous
@ -1901,8 +1984,15 @@ void wd_fdc_device_base::live_run(attotime limit)
} else if(slot < sector_size+2) {
// CRC
if(slot == sector_size+1) {
live_delay(IDLE);
if(slot == sector_size+1)
{
// act on delayed interrupt if active
/* if (delay_int)
{
interrupt_start();
return;
}
*/ live_delay(IDLE);
return;
}
}
@ -2117,6 +2207,13 @@ void wd_fdc_device_base::live_run(attotime limit)
else {
pll_stop_writing(floppy, cur_live.tm);
cur_live.state = IDLE;
// Act on delayed interrupt if set.
if (delay_int)
{
interrupt_start();
return;
}
return;
}
@ -2146,9 +2243,17 @@ void wd_fdc_device_base::live_run(attotime limit)
live_write_mfm(cur_live.crc >> 8);
else if(cur_live.byte_counter < sector_size + 16+3)
live_write_mfm(0xff);
// live_write_mfm(0x4e);
else {
pll_stop_writing(floppy, cur_live.tm);
cur_live.state = IDLE;
// Act on delayed interrupt if set.
if (delay_int)
{
interrupt_start();
return;
}
return;
}
}
@ -2905,6 +3010,7 @@ wd2791_device::wd2791_device(const machine_config &mconfig, const char *tag, dev
wd2793_device::wd2793_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) : wd_fdc_analog_device_base(mconfig, WD2793, tag, owner, clock)
{
step_times = fd179x_step_times;
delay_register_commit = 16;
delay_command_commit = 12;
disable_mfm = false;

View File

@ -91,8 +91,7 @@ public:
DECLARE_WRITE_LINE_MEMBER(mr_w);
void index_callback(floppy_image_device *floppy, int state);
void index_callback(floppy_image_device *floppy, int state);
protected:
wd_fdc_device_base(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock);
@ -177,11 +176,11 @@ private:
enum {
// General "doing nothing" state
IDLE,
IDLE,
// Main states - the commands
RESTORE,
SEEK,
RESTORE,
SEEK,
STEP,
READ_SECTOR,
READ_TRACK,
@ -242,6 +241,8 @@ private:
WRITE_SECTOR_PRE_BYTE
};
struct live_info {
enum { PT_NONE, PT_CRC_1, PT_CRC_2 };
@ -304,6 +305,8 @@ private:
int format_last_byte_count;
std::string format_description_string;
bool delay_int;
void delay_cycles(emu_timer *tm, int cycles);
// Device timer subfunctions

View File

@ -133,10 +133,11 @@ void rmnimbus_state::nimbus(machine_config &config)
PALETTE(config, m_palette).set_entries(16);
/* Backing storage */
WD2793(config, m_fdc, 1000000);
WD2793(config, m_fdc, 2000000);
m_fdc->set_force_ready(true);
m_fdc->intrq_wr_callback().set(FUNC(rmnimbus_state::nimbus_fdc_intrq_w));
m_fdc->drq_wr_callback().set(FUNC(rmnimbus_state::nimbus_fdc_drq_w));
m_fdc->enmf_rd_callback().set(FUNC(rmnimbus_state::nimbus_fdc_enmf_r));
FLOPPY_CONNECTOR(config, FDC_TAG":0", rmnimbus_floppies, "35dd", isa8_fdc_device::floppy_formats);
FLOPPY_CONNECTOR(config, FDC_TAG":1", rmnimbus_floppies, "35dd", isa8_fdc_device::floppy_formats);
@ -210,6 +211,8 @@ void rmnimbus_state::nimbus(machine_config &config)
msm5205.add_route(ALL_OUTPUTS, MONO_TAG, 0.75);
SOFTWARE_LIST(config, "disk_list").set_original("nimbus");
m_maincpu->set_dasm_override(FUNC(rmnimbus_state::dasm_override));
}
/*

View File

@ -88,10 +88,12 @@ public:
void nimbus(machine_config &config);
uint32_t m_debug_machine;
uint32_t m_debug_trap;
void decode_subbios(device_t *device, offs_t pc, uint8_t raw_flag);
void decode_subbios(device_t *device, offs_t pc);
void decode_subbios_return(device_t *device, offs_t pc);
void decode_dos21(device_t *device, offs_t pc);
private:
required_device<i80186_cpu_device> m_maincpu;
required_device<i8031_device> m_iocpu;
@ -120,6 +122,7 @@ private:
uint8_t m_iou_reg092;
uint8_t m_last_playmode;
uint8_t m_ay8910_a;
uint8_t m_ay8910_b;
uint16_t m_x, m_y, m_yline;
uint8_t m_colours, m_mode, m_upmode;
uint32_t m_debug_video;
@ -131,7 +134,10 @@ private:
void nimbus_mcu_w(uint8_t data);
uint8_t scsi_r(offs_t offset);
void scsi_w(offs_t offset, uint8_t data);
uint8_t fdc_reg_r(offs_t offset);
void fdc_reg_w(offs_t offset, uint8_t data);
void fdc_ctl_w(uint8_t data);
void nimbus_voice_w(offs_t offset, uint8_t data);
uint8_t nimbus_pc8031_r(offs_t offset);
void nimbus_pc8031_w(offs_t offset, uint8_t data);
uint8_t nimbus_pc8031_iou_r(offs_t offset);
@ -142,6 +148,9 @@ private:
void nimbus_pc8031_port3_w(uint8_t data);
uint8_t nimbus_iou_r(offs_t offset);
void nimbus_iou_w(offs_t offset, uint8_t data);
uint8_t nimbus_rompack_r(offs_t offset);
void nimbus_rompack_w(offs_t offset, uint8_t data);
void nimbus_sound_ay8910_porta_w(uint8_t data);
void nimbus_sound_ay8910_portb_w(uint8_t data);
uint8_t nimbus_mouse_js_r();
@ -156,6 +165,8 @@ private:
DECLARE_WRITE_LINE_MEMBER(sio_interrupt);
DECLARE_WRITE_LINE_MEMBER(nimbus_fdc_intrq_w);
DECLARE_WRITE_LINE_MEMBER(nimbus_fdc_drq_w);
DECLARE_READ_LINE_MEMBER(nimbus_fdc_enmf_r);
void nimbus_via_write_portb(uint8_t data);
DECLARE_WRITE_LINE_MEMBER(write_scsi_bsy);
DECLARE_WRITE_LINE_MEMBER(write_scsi_cd);
@ -189,8 +200,8 @@ private:
void rmni_sound_reset();
void mouse_js_reset();
void check_scsi_irq();
void set_scsi_drqlat(bool clock, bool clear);
void set_scsi_drqlat(bool clock, bool clear);
int m_scsi_iena;
int m_scsi_msg;
int m_scsi_bsy;
@ -224,35 +235,40 @@ private:
/* Mouse/Joystick */
struct
{
int8_t m_mouse_x;
int8_t m_mouse_y;
int8_t m_mouse_x;
int8_t m_mouse_y;
uint8_t m_mouse_pcx;
uint8_t m_mouse_pcy;
uint8_t m_mouse_pcx;
uint8_t m_mouse_pcy;
uint8_t m_intstate_x;
uint8_t m_intstate_y;
uint8_t m_intstate_x;
uint8_t m_intstate_y;
uint8_t m_reg0a4;
uint8_t m_reg0a4;
emu_timer *m_mouse_timer;
} m_nimbus_mouse;
bool m_voice_enabled;
void nimbus_io(address_map &map);
void nimbus_iocpu_io(address_map &map);
void nimbus_iocpu_mem(address_map &map);
void nimbus_mem(address_map &map);
void decode_dssi_none(uint16_t ds, uint16_t si, uint8_t raw_flag);
void decode_dssi_generic(uint16_t ds, uint16_t si, uint8_t raw_flag);
void decode_dssi_f_fill_area(uint16_t ds, uint16_t si, uint8_t raw_flag);
void decode_dssi_f_plot_character_string(uint16_t ds, uint16_t si, uint8_t raw_flag);
void decode_dssi_f_set_new_clt(uint16_t ds, uint16_t si, uint8_t raw_flag);
void decode_dssi_f_plonk_char(uint16_t ds, uint16_t si, uint8_t raw_flag);
void decode_dssi_f_rw_sectors(uint16_t ds, uint16_t si, uint8_t raw_flag);
void decode_dssi_none(uint16_t ds, uint16_t si);
void decode_dssi_generic(uint16_t ds, uint16_t si);
void decode_dssi_f_fill_area(uint16_t ds, uint16_t si);
void decode_dssi_f_plot_character_string(uint16_t ds, uint16_t si);
void decode_dssi_f_set_new_clt(uint16_t ds, uint16_t si);
void decode_dssi_f_plonk_char(uint16_t ds, uint16_t si);
void decode_dssi_f_rw_sectors(uint16_t ds, uint16_t si);
void debug_command(const std::vector<std::string> &params);
void video_debug(const std::vector<std::string> &params);
offs_t dasm_override(std::ostream &stream, offs_t pc, const util::disasm_interface::data_buffer &opcodes, const util::disasm_interface::data_buffer &params);
void do_mouse();
};
#endif // MAME_INCLUDES_RMNIMBUS_H

View File

@ -109,16 +109,16 @@ chdman createhd -o ST125N.chd -chs 41921,1,1 -ss 512
#define MOUSE_INT_ENABLE 0x08
#define PC8031_INT_ENABLE 0x10
#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
#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_POLL_FREQUENCY 500
#define MOUSE_INT_ENABLED(state) (((state)->m_iou_reg092 & MOUSE_INT_ENABLE) ? 1 : 0)
@ -137,8 +137,8 @@ chdman createhd -o ST125N.chd -chs 41921,1,1 -ss 512
/* Debugging */
#define DEBUG_SET(flags) ((m_debug_machine & (flags))==(flags))
#define DEBUG_SET_STATE(flags) ((state->m_debug_machine & (flags))==(flags))
#define DEBUG_SET(flags) ((m_debug_machine & (flags))==(flags))
#define DEBUG_SET_STATE(flags) ((state->m_debug_machine & (flags))==(flags))
#define DEBUG_NONE 0x0000000
#define DECODE_BIOS 0x0000002
@ -216,7 +216,7 @@ void rmnimbus_state::machine_reset()
void rmnimbus_state::machine_start()
{
m_nimbus_mouse.m_mouse_timer=timer_alloc(TIMER_MOUSE);
/* setup debug commands */
if (machine().debug_flags & DEBUG_FLAG_ENABLED)
{
@ -228,7 +228,10 @@ void rmnimbus_state::machine_start()
}
m_debug_machine=DEBUG_NONE;
m_debug_trap=0;
m_voice_enabled=false;
m_fdc->dden_w(0);
//m_fdc->overide_delays(64,m_fdc->get_cmd_delay());
}
void rmnimbus_state::debug_command(const std::vector<std::string> &params)
@ -254,38 +257,59 @@ static int instruction_hook(device_t &device, offs_t curpc)
{
rmnimbus_state *state = device.machine().driver_data<rmnimbus_state>();
address_space &space = device.memory().space(AS_PROGRAM);
uint8_t *addr_ptr;
uint8_t *addr_ptr;
uint8_t first;
addr_ptr = (uint8_t*)space.get_read_ptr(curpc);
if ((addr_ptr !=nullptr) && (addr_ptr[0]==0xCD))
{
if(DEBUG_SET_STATE(DECODE_BIOS) && (addr_ptr[1]==0xF0))
{
if(DEBUG_SET_STATE(DECODE_BIOS_RAW))
state->decode_subbios(&device,curpc,1);
else
state->decode_subbios(&device,curpc,0);
}
first = (curpc & 0x01) ? 1 : 0;
if(DEBUG_SET_STATE(DECODE_DOS21) && (addr_ptr[1]==0x21))
if(DEBUG_SET_STATE(DECODE_BIOS) && (curpc == state->m_debug_trap) && (0 != state->m_debug_trap))
{
state->decode_subbios_return(&device,curpc);
}
if ((addr_ptr !=nullptr) && (addr_ptr[first]==0xCD))
{
if(DEBUG_SET_STATE(DECODE_BIOS) && (addr_ptr[first+1]==0xF0))
state->decode_subbios(&device,curpc);
if(DEBUG_SET_STATE(DECODE_DOS21) && (addr_ptr[first+1]==0x21))
state->decode_dos21(&device,curpc);
}
return 0;
}
void rmnimbus_state::decode_subbios_return(device_t *device, offs_t pc)
{
uint16_t ax = m_maincpu->state_int(I8086_AX);
uint16_t ds = m_maincpu->state_int(I8086_DS);
uint16_t si = m_maincpu->state_int(I8086_SI);
if(!DEBUG_SET(DECODE_BIOS_RAW))
{
logerror("at %05X sub-bios return code : %04X\n",pc,ax);
decode_dssi_generic(ds,si);
logerror("=======================================================================\n");
}
else
logerror("%05X :: %04X\n",pc,ax);
m_debug_trap=0;
}
#define set_type(type_name) sprintf(type_str,type_name)
#define set_drv(drv_name) sprintf(drv_str,drv_name)
#define set_func(func_name) sprintf(func_str,func_name)
void rmnimbus_state::decode_subbios(device_t *device,offs_t pc, uint8_t raw_flag)
void rmnimbus_state::decode_subbios(device_t *device,offs_t pc)
{
char type_str[80];
char drv_str[80];
char func_str[80];
void (rmnimbus_state::*dump_dssi)(uint16_t, uint16_t, uint8_t) = &rmnimbus_state::decode_dssi_none;
void (rmnimbus_state::*dump_dssi)(uint16_t, uint16_t) = &rmnimbus_state::decode_dssi_none;
uint16_t ax = m_maincpu->state_int(I8086_AX);
uint16_t bx = m_maincpu->state_int(I8086_BX);
@ -293,12 +317,15 @@ void rmnimbus_state::decode_subbios(device_t *device,offs_t pc, uint8_t raw_flag
uint16_t ds = m_maincpu->state_int(I8086_DS);
uint16_t si = m_maincpu->state_int(I8086_SI);
// Set the address to trap after the sub-bios call.
m_debug_trap=pc+2;
// *** TEMP Don't show f_enquire_display_line calls !
if((cx==6) && (ax==43))
return;
// *** END TEMP
if(!raw_flag)
if(!DEBUG_SET(DECODE_BIOS_RAW))
{
logerror("=======================================================================\n");
logerror("Sub-bios call at %08X, AX=%04X, BX=%04X, CX=%04X, DS:SI=%04X:%04X\n",pc,ax,bx,cx,ds,si);
@ -360,6 +387,8 @@ void rmnimbus_state::decode_subbios(device_t *device,offs_t pc, uint8_t raw_flag
case 4 : set_drv("d_eeprom"); break;
}
dump_dssi = &rmnimbus_state::decode_dssi_generic;
switch(ax)
{
case 0 : set_func("f_get_version_number"); break;
@ -368,12 +397,11 @@ void rmnimbus_state::decode_subbios(device_t *device,offs_t pc, uint8_t raw_flag
case 3 : set_func("f_get_device_status"); break;
case 4 : set_func("f_read_n_sectors"); dump_dssi = &rmnimbus_state::decode_dssi_f_rw_sectors; break;
case 5 : set_func("f_write_n_sectors"); dump_dssi = &rmnimbus_state::decode_dssi_f_rw_sectors; break;
case 6 : set_func("f_verify_n_sectors"); break;
case 6 : set_func("f_verify_n_sectors"); dump_dssi = &rmnimbus_state::decode_dssi_f_rw_sectors; break;
case 7 : set_func("f_media_check"); break;
case 8 : set_func("f_recalibrate"); break;
case 9 : set_func("f_motors_off"); break;
}
dump_dssi = &rmnimbus_state::decode_dssi_f_rw_sectors;
}; break;
@ -602,43 +630,42 @@ void rmnimbus_state::decode_subbios(device_t *device,offs_t pc, uint8_t raw_flag
}; break;
}
if(raw_flag)
if(DEBUG_SET(DECODE_BIOS_RAW))
{
(this->*dump_dssi)(ds, si, raw_flag);
(this->*dump_dssi)(ds, si);
}
else
{
logerror("Type=%s, Driver=%s, Function=%s\n",type_str,drv_str,func_str);
(this->*dump_dssi)(ds, si, raw_flag);
(this->*dump_dssi)(ds, si);
logerror("=======================================================================\n");
}
}
static inline void *get_dssi_ptr(address_space &space, uint16_t ds, uint16_t si)
static inline void *get_regpair_ptr(address_space &space, uint16_t segment, uint16_t offset)
{
int addr;
addr=((ds<<4)+si);
// OUTPUT_SEGOFS("DS:SI",ds,si);
addr=((segment<<4)+offset);
return space.get_read_ptr(addr);
}
void rmnimbus_state::decode_dssi_none(uint16_t ds, uint16_t si, uint8_t raw_flag)
void rmnimbus_state::decode_dssi_none(uint16_t ds, uint16_t si)
{
}
void rmnimbus_state::decode_dssi_generic(uint16_t ds, uint16_t si, uint8_t raw_flag)
void rmnimbus_state::decode_dssi_generic(uint16_t ds, uint16_t si)
{
address_space &space = m_maincpu->space(AS_PROGRAM);
uint16_t *params;
int count;
if(raw_flag)
if(DEBUG_SET(DECODE_BIOS_RAW))
return;
params=(uint16_t *)get_dssi_ptr(space,ds,si);
params=(uint16_t *)get_regpair_ptr(space,ds,si);
for(count=0; count<10; count++)
logerror("%04X ",params[count]);
@ -647,7 +674,7 @@ void rmnimbus_state::decode_dssi_generic(uint16_t ds, uint16_t si, uint8_t raw_f
}
void rmnimbus_state::decode_dssi_f_fill_area(uint16_t ds, uint16_t si, uint8_t raw_flag)
void rmnimbus_state::decode_dssi_f_fill_area(uint16_t ds, uint16_t si)
{
address_space &space = m_maincpu->space(AS_PROGRAM);
@ -656,14 +683,14 @@ void rmnimbus_state::decode_dssi_f_fill_area(uint16_t ds, uint16_t si, uint8_t r
t_nimbus_brush *brush;
int cocount;
area_params = (t_area_params *)get_dssi_ptr(space,ds,si);
area_params = (t_area_params *)get_regpair_ptr(space,ds,si);
if (!raw_flag)
if (!DEBUG_SET(DECODE_BIOS_RAW))
OUTPUT_SEGOFS("SegBrush:OfsBrush",area_params->seg_brush,area_params->ofs_brush);
brush=(t_nimbus_brush *)space.get_read_ptr(LINEAR_ADDR(area_params->seg_brush,area_params->ofs_brush));
if(raw_flag)
if(DEBUG_SET(DECODE_BIOS_RAW))
{
logerror("\tdw\t%04X, %04X, %04X, %04X, %04X, %04X, %04X, %04X, %04X, ",
brush->style,brush->style_index,brush->colour1,brush->colour2,
@ -685,7 +712,7 @@ void rmnimbus_state::decode_dssi_f_fill_area(uint16_t ds, uint16_t si, uint8_t r
addr_ptr = (uint16_t *)space.get_read_ptr(LINEAR_ADDR(area_params->seg_data,area_params->ofs_data));
for(cocount=0; cocount < area_params->count; cocount++)
{
if(raw_flag)
if(DEBUG_SET(DECODE_BIOS_RAW))
{
if(cocount!=(area_params->count-1))
logerror("%04X, %04X, ",addr_ptr[cocount*2],addr_ptr[(cocount*2)+1]);
@ -696,11 +723,11 @@ void rmnimbus_state::decode_dssi_f_fill_area(uint16_t ds, uint16_t si, uint8_t r
logerror("x=%d y=%d\n",addr_ptr[cocount*2],addr_ptr[(cocount*2)+1]);
}
if(raw_flag)
if(DEBUG_SET(DECODE_BIOS_RAW))
logerror("\n");
}
void rmnimbus_state::decode_dssi_f_plot_character_string(uint16_t ds, uint16_t si, uint8_t raw_flag)
void rmnimbus_state::decode_dssi_f_plot_character_string(uint16_t ds, uint16_t si)
{
address_space &space = m_maincpu->space(AS_PROGRAM);
@ -708,10 +735,10 @@ void rmnimbus_state::decode_dssi_f_plot_character_string(uint16_t ds, uint16_t s
t_plot_string_params *plot_string_params;
int charno;
if(raw_flag)
if(DEBUG_SET(DECODE_BIOS_RAW))
return;
plot_string_params=(t_plot_string_params *)get_dssi_ptr(space,ds,si);
plot_string_params=(t_plot_string_params *)get_regpair_ptr(space,ds,si);
OUTPUT_SEGOFS("SegFont:OfsFont",plot_string_params->seg_font,plot_string_params->ofs_font);
OUTPUT_SEGOFS("SegData:OfsData",plot_string_params->seg_data,plot_string_params->ofs_data);
@ -729,14 +756,14 @@ void rmnimbus_state::decode_dssi_f_plot_character_string(uint16_t ds, uint16_t s
logerror("\n");
}
void rmnimbus_state::decode_dssi_f_set_new_clt(uint16_t ds, uint16_t si, uint8_t raw_flag)
void rmnimbus_state::decode_dssi_f_set_new_clt(uint16_t ds, uint16_t si)
{
address_space &space = m_maincpu->space(AS_PROGRAM);
uint16_t *new_colours;
int colour;
new_colours=(uint16_t *)get_dssi_ptr(space,ds,si);
new_colours=(uint16_t *)get_regpair_ptr(space,ds,si);
if(raw_flag)
if(DEBUG_SET(DECODE_BIOS_RAW))
return;
OUTPUT_SEGOFS("SegColours:OfsColours",ds,si);
@ -746,13 +773,13 @@ void rmnimbus_state::decode_dssi_f_set_new_clt(uint16_t ds, uint16_t si, uint8_t
}
void rmnimbus_state::decode_dssi_f_plonk_char(uint16_t ds, uint16_t si, uint8_t raw_flag)
void rmnimbus_state::decode_dssi_f_plonk_char(uint16_t ds, uint16_t si)
{
address_space &space = m_maincpu->space(AS_PROGRAM);
uint16_t *params;
params=(uint16_t *)get_dssi_ptr(space,ds,si);
params=(uint16_t *)get_regpair_ptr(space,ds,si);
if(raw_flag)
if(DEBUG_SET(DECODE_BIOS_RAW))
return;
OUTPUT_SEGOFS("SegParams:OfsParams",ds,si);
@ -760,17 +787,25 @@ void rmnimbus_state::decode_dssi_f_plonk_char(uint16_t ds, uint16_t si, uint8_t
logerror("plonked_char=%c\n",params[0]);
}
void rmnimbus_state::decode_dssi_f_rw_sectors(uint16_t ds, uint16_t si, uint8_t raw_flag)
void rmnimbus_state::decode_dssi_f_rw_sectors(uint16_t ds, uint16_t si)
{
address_space &space = m_maincpu->space(AS_PROGRAM);
uint16_t *params;
int param_no;
if(raw_flag)
if(DEBUG_SET(DECODE_BIOS_RAW))
return;
params=(uint16_t *)get_dssi_ptr(space,ds,si);
params=(uint16_t *)get_regpair_ptr(space,ds,si);
logerror("unitno=%04X, count=%02X, first_sector=%08X buffer=%04X:%04X (%05X)\n",
params[0],
params[1],
((params[3] * 65536)+params[2]),
params[5],params[4],
((params[5]*16)+params[4])
);
for(param_no=0;param_no<16;param_no++)
logerror("%04X ",params[param_no]);
@ -779,6 +814,10 @@ void rmnimbus_state::decode_dssi_f_rw_sectors(uint16_t ds, uint16_t si, uint8_t
void rmnimbus_state::decode_dos21(device_t *device,offs_t pc)
{
address_space &space = m_maincpu->space(AS_PROGRAM);
//uint16_t *params;
char *path;
uint16_t ax = m_maincpu->state_int(I8086_AX);
uint16_t bx = m_maincpu->state_int(I8086_BX);
uint16_t cx = m_maincpu->state_int(I8086_CX);
@ -791,6 +830,8 @@ void rmnimbus_state::decode_dos21(device_t *device,offs_t pc)
uint16_t si = m_maincpu->state_int(I8086_SI);
uint16_t di = m_maincpu->state_int(I8086_DI);
uint16_t bp = m_maincpu->state_int(I8086_BP);
uint8_t dosfn = ax >> 8; // Dos function is AH, upper half of AX.
logerror("=======================================================================\n");
logerror("DOS Int 0x21 call at %05X\n",pc);
@ -798,8 +839,71 @@ void rmnimbus_state::decode_dos21(device_t *device,offs_t pc)
logerror("CS=%04X, DS=%04X, ES=%04X, SS=%04X\n",cs,ds,es,ss);
logerror("SI=%04X, DI=%04X, BP=%04X\n",si,di,bp);
logerror("=======================================================================\n");
if (((dosfn >= 0x39) && (dosfn <= 0x3d))
|| (0x43 == dosfn)
|| (0x4e == dosfn)
|| (0x56 == dosfn)
|| ((dosfn >= 0x5a) && (dosfn <= 0x5b)) )
{
path=(char *)get_regpair_ptr(space,ds,dx);
logerror("Path at DS:DX=%s\n",path);
if (0x56 == dosfn)
{
path=(char *)get_regpair_ptr(space,es,di);
logerror("Path at ES:DI=%s\n",path);
}
logerror("=======================================================================\n");
}
}
#define CBUFLEN 32
offs_t rmnimbus_state::dasm_override(std::ostream &stream, offs_t pc, const util::disasm_interface::data_buffer &opcodes, const util::disasm_interface::data_buffer &params)
{
unsigned call;
char callname[CBUFLEN];
offs_t result = 0;
// decode and document (some) INT XX calls
if (opcodes.r8(pc) == 0xCD)
{
call = opcodes.r8(pc+1);
switch (call)
{
case 0x20 :
strcpy(callname, "(dos terminate)");
break;
case 0x21 :
strcpy(callname, "(dos function)");
break;
case 0xf0 :
strcpy(callname, "(sub_bios)");
break;
case 0xf3 :
strcpy(callname, "(dispatch handler)");
break;
case 0xf5 :
strcpy(callname, "(event handler)");
break;
case 0xf6 :
strcpy(callname, "(resource message)");
break;
default :
strcpy(callname, "");
}
util::stream_format(stream, "int %02xh %s",call,callname);
result = 2;
}
return result;
}
/*
The Nimbus has 3 banks of memory each of which can be either 16x4164 or 16x41256 giving
@ -1021,6 +1125,11 @@ WRITE_LINE_MEMBER(rmnimbus_state::nimbus_fdc_drq_w)
m_maincpu->drq1_w(state && FDC_DRQ_ENABLED());
}
READ_LINE_MEMBER(rmnimbus_state::nimbus_fdc_enmf_r)
{
return false;
}
uint8_t rmnimbus_state::fdc_driveno(uint8_t drivesel)
{
switch (drivesel)
@ -1073,7 +1182,7 @@ uint8_t rmnimbus_state::scsi_r(offs_t offset)
{
result |= FDC_MOTOR() << 2;
result |= (!floppy->idx_r()) << 1;
result |= floppy->ready_r() << 0;
result |= (floppy->dskchg_r()) << 0;
}
break;
case 0x08 :
@ -1107,7 +1216,7 @@ void rmnimbus_state::fdc_ctl_w(uint8_t data)
uint8_t old_drq = m_nimbus_drives.reg400 & HDC_DRQ_MASK;
char drive[5];
floppy_image_device *floppy;
m_nimbus_drives.reg400 = data;
sprintf(drive, "%d", FDC_DRIVE());
@ -1163,14 +1272,14 @@ void rmnimbus_state::hdc_reset()
m_scsi_req = 0;
// Latched req, IC11b
m_scsi_reqlat = 0;
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.
/*
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()
@ -1185,13 +1294,13 @@ WRITE_LINE_MEMBER(rmnimbus_state::write_scsi_iena)
}
// This emulates the 74LS74 latched version of req
void rmnimbus_state::set_scsi_drqlat(bool clock, bool clear)
{
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
@ -1202,9 +1311,9 @@ 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);
set_scsi_drqlat(false, true);
}
void rmnimbus_state::hdc_drq(bool state)
@ -1220,10 +1329,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();
}
@ -1247,19 +1356,27 @@ WRITE_LINE_MEMBER( rmnimbus_state::write_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;
// 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();
}
void rmnimbus_state::nimbus_voice_w(offs_t offset, uint8_t data)
{
if (offset == 0xB0)
m_voice_enabled = true;
else if (offset == 0xB2)
m_voice_enabled = false;
}
/* 8031/8051 Peripheral controller 80186 side */
void rmnimbus_state::pc8031_reset()
@ -1485,6 +1602,20 @@ void rmnimbus_state::iou_reset()
m_eeprom_state = 0;
}
/* Rompacks, not completely implemented */
uint8_t rmnimbus_state::nimbus_rompack_r(offs_t offset)
{
logerror("Rompack read offset %02X, rompack address=%04X\n",offset,(m_ay8910_b*256)+m_ay8910_a);
return 0;
}
void rmnimbus_state::nimbus_rompack_w(offs_t offset, uint8_t data)
{
logerror("Rompack write offset %02X, data=%02X, rompack address=%04X\n",offset,data,(m_ay8910_b*256)+m_ay8910_a);
}
/*
Sound hardware : AY8910
@ -1507,6 +1638,7 @@ void rmnimbus_state::rmni_sound_reset()
m_msm->playmode_w(m_last_playmode);
m_ay8910_a=0;
m_ay8910_b=0;
}
void rmnimbus_state::nimbus_sound_ay8910_porta_w(uint8_t data)
@ -1514,16 +1646,21 @@ void rmnimbus_state::nimbus_sound_ay8910_porta_w(uint8_t data)
m_msm->data_w(data);
// Mouse code needs a copy of this.
// ROMpack lower address lines
m_ay8910_a=data;
}
void rmnimbus_state::nimbus_sound_ay8910_portb_w(uint8_t data)
{
if ((data & 0x07) != m_last_playmode)
// Only update msm5205 if voice is enabled.....
if (m_voice_enabled && ((data & 0x07) != m_last_playmode))
{
m_last_playmode = (data & 0x07);
m_msm->playmode_w(m_last_playmode);
}
// ROMpack upper address lines
m_ay8910_b=data;
}
WRITE_LINE_MEMBER(rmnimbus_state::nimbus_msm5205_vck)
@ -1532,60 +1669,54 @@ WRITE_LINE_MEMBER(rmnimbus_state::nimbus_msm5205_vck)
external_int(EXTERNAL_INT_MSM5205,state);
}
void rmnimbus_state::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr)
{
switch(id)
{
case TIMER_MOUSE : do_mouse(); break;
}
}
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()
void rmnimbus_state::do_mouse()
{
m_nimbus_mouse.m_mouse_x=128;
m_nimbus_mouse.m_mouse_y=128;
m_nimbus_mouse.m_mouse_pcx=0;
m_nimbus_mouse.m_mouse_pcy=0;
m_nimbus_mouse.m_intstate_x=0;
m_nimbus_mouse.m_intstate_y=0;
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(MOUSE_POLL_FREQUENCY));
}
void rmnimbus_state::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr)
{
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 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;
uint8_t mxa; // Values of quadrature encoders for X and Y
uint8_t mxa; // Values of quadrature encoders for X and Y
uint8_t mxb;
uint8_t mya;
uint8_t myb;
// 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();
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)
if (xdiff > 0x80)
xdiff -= 0x100;
else if (xdiff < -0x80)
xdiff += 0x100;
if (ydiff > 0x80)
if (ydiff > 0x80)
ydiff -= 0x100;
else if (ydiff < -0x80)
ydiff += 0x100;
ydiff += 0x100;
// convert movement into emulated movement of quadrature encoder in mouse.
if (xdiff < 0)
@ -1597,7 +1728,7 @@ void rmnimbus_state::device_timer(emu_timer &timer, device_timer_id id, int para
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;
m_nimbus_mouse.m_mouse_pcy &= 0x03;
@ -1648,6 +1779,20 @@ void rmnimbus_state::device_timer(emu_timer &timer, device_timer_id id, int para
m_nimbus_mouse.m_intstate_y=intstate_y;
}
void rmnimbus_state::mouse_js_reset()
{
m_nimbus_mouse.m_mouse_x=128;
m_nimbus_mouse.m_mouse_y=128;
m_nimbus_mouse.m_mouse_pcx=0;
m_nimbus_mouse.m_mouse_pcy=0;
m_nimbus_mouse.m_intstate_x=0;
m_nimbus_mouse.m_intstate_y=0;
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(MOUSE_POLL_FREQUENCY));
}
uint8_t rmnimbus_state::nimbus_mouse_js_r()
{
/*

View File

@ -22,10 +22,10 @@
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.
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"
@ -36,92 +36,92 @@
#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 :
/*
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
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
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
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
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)
0x2A X address status, returns current value of X counter (m_x)
0x2C Y address status, returns current value of Y counter (m_y)
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
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
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
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
0x2E 0..3 12 3
0x2E 4..7 13 3
0x2E 8..11 14 3
0x2E 12..15 15 3
*/
@ -129,47 +129,47 @@ Port Bits Low res High Res
// 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_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
#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
#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 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
#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 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
@ -424,6 +424,10 @@ void rmnimbus_state::nimbus_video_io_w(offs_t offset, uint16_t data, uint16_t me
change_palette(offset - P_COLOUR03, data);
return;
// This register doesn't appear to be documented, but is written regually in setpc ibm mode
case 0x18 :
break;
default:
logerror("nimbus: unknown video reg write %02x %04x\n", offset, data);
return;
@ -604,7 +608,7 @@ void rmnimbus_state::write_pixel_data(uint16_t x, uint16_t y, uint16_t data)
// 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