/*
RM 380Z machine
*/
#include "includes/rm380z.h"
/*
PORT0 write in COS 4.0B/M:
bit0: 1=reset keyboard latch (?)
bit1: ?
bit2: ?
bit3: ?
bit4: ?
bit5: 40/80 cols switch (?)
bit6: 0=write to char RAM/1=write to attribute RAM
bit7: 1=map ROM at 0000-0fff/0=RAM
*/
WRITE8_MEMBER( rm380z_state::port_write )
{
switch ( offset )
{
case 0xFC: // PORT0
//printf("FBFCw[%2.2x] FBFD [%2.2x] FBFE [%2.2x] PC [%4.4x] writenum [%4.4x]\n",data,m_fbfd,m_fbfe,m_maincpu->safe_pc(),writenum);
m_port0 = data;
if (data&0x01)
{
//printf("WARNING: bit0 of port0 reset\n");
m_port0_kbd=0;
}
m_port1&=~0x01; //?
config_videomode();
config_memory_map();
break;
case 0xFD: // screen line counter (?)
//printf("FBFC [%2.2x] FBFDw[%2.2x] FBFE [%2.2x] PC [%4.4x] writenum [%4.4x]\n",m_port0,data,m_fbfe,m_maincpu->safe_pc(),writenum);
m_old_old_fbfd=m_old_fbfd;
m_old_fbfd=m_fbfd;
m_fbfd=data;
writenum++;
check_scroll_register();
break;
case 0xFE: // line on screen to write to divided by 2
//printf("FBFC [%2.2x] FBFD [%2.2x] FBFEw[%2.2x] PC [%4.4x] writenum [%4.4x]\n",m_port0,m_fbfd,data,m_maincpu->safe_pc(),writenum);
m_fbfe=data;
break;
case 0xFF: // user I/O port
//printf("write of [%x] to FBFF\n",data);
//logerror("%s: Write %02X to user I/O port\n", machine().describe_context(), data );
break;
default:
printf("unknown port [%2.2x] write of [%2.2x]\n",offset,data);
}
}
READ8_MEMBER( rm380z_state::port_read )
{
UINT8 data = 0xFF;
switch ( offset )
{
case 0xFC: // PORT0
//m_port0_kbd=getKeyboard();
data = m_port0_kbd;
//if (m_port0_kbd!=0) m_port0_kbd=0;
//m_port0_kbd=0;
//printf("read of port0 (kbd) from PC [%x]\n",m_maincpu->safe_pc());
break;
case 0xFD: // "counter" (?)
//printf("%s: Read from counter FBFD\n", machine().describe_context());
data = 0x00;
break;
case 0xFE: // PORT1
data = m_port1;
//printf("read of port1 from PC [%x]\n",m_maincpu->safe_pc());
break;
case 0xFF: // user port
//printf("%s: Read from user port\n", machine().describe_context());
break;
default:
printf("read from unknown port [%2.2x]\n",offset);
}
return data;
}
WRITE8_MEMBER( rm380z_state::port_write_1b00 )
{
address_space &program = m_maincpu->space(AS_PROGRAM);
port_write(program,offset+0xfc,data);
}
READ8_MEMBER( rm380z_state::port_read_1b00 )
{
address_space &program = m_maincpu->space(AS_PROGRAM);
return port_read(program,offset+0xfc);
}
READ8_MEMBER( rm380z_state::hiram_read )
{
return hiram[offset];
}
WRITE8_MEMBER( rm380z_state::hiram_write )
{
hiram[offset]=data;
}
READ8_MEMBER( rm380z_state::rm380z_portlow_r )
{
return 0xff;
}
WRITE8_MEMBER( rm380z_state::rm380z_portlow_w )
{
//printf("port write [%x] [%x] at PC [%x]\n",offset,data,m_maincpu->safe_pc());
}
READ8_MEMBER( rm380z_state::rm380z_porthi_r )
{
return 0xff;
}
WRITE8_MEMBER( rm380z_state::rm380z_porthi_w )
{
//printf("port write [%x] [%x]\n",offset+0xc5,data);
}
#define LINE_SUBDIVISION 82
#define HORZ_LINES 100
#define TIMER_SPEED 50*HORZ_LINES*LINE_SUBDIVISION
//
// this simulates line+frame blanking
// according to the System manual, "frame blanking bit (bit 6) of port1 becomes high
// for about 4.5 milliseconds every 20 milliseconds"
//
TIMER_CALLBACK_MEMBER(rm380z_state::static_vblank_timer)
{
//printf("timer callback called at [%f]\n",machine().time().as_double());
m_rasterlineCtr++;
m_rasterlineCtr%=(HORZ_LINES*LINE_SUBDIVISION);
// frame blanking
if (m_rasterlineCtr>=((HORZ_LINES-22)*LINE_SUBDIVISION))
{
m_port1|=0x40;
}
else
{
m_port1&=~0x40;
}
// line blanking
if ((m_rasterlineCtr%LINE_SUBDIVISION)>80)
{
m_port1|=0x80;
}
else
{
m_port1&=~0x80;
}
}
WRITE8_MEMBER( rm380z_state::keyboard_put )
{
if (data)
{
m_port0_kbd = data;
m_port1 |= 1;
}
}
//
// ports c0-cf are related to the floppy disc controller
// c0-c3: wd1771
// c4-c8: disk drive port0
//
// CP/M booting:
// from the service manual: "the B command reads a sector from drive 0, track 0, sector 1 into memory
// at 0x0080 to 0x00FF, then jumps to it if there is no error."
//
WRITE8_MEMBER( rm380z_state::disk_0_control )
{
fd1771_device *fdc = machine().device<fd1771_device>("wd1771");
//printf("disk drive port0 write [%x]\n",data);
// drive port0
if (data&0x01)
{
// drive select bit 0
fdc->set_drive(0);
}
if (data&0x02)
{
// drive select bit 1
fdc->set_drive(1);
}
if (data&0x08)
{
// motor on
}
// "MSEL (dir/side select bit)"
if (data&0x20)
{
fdc->set_side(1);
}
else
{
fdc->set_side(0);
}
// set drive en- (?)
if (data&0x40)
{
}
}
void rm380z_state::machine_start()
{
machine().scheduler().timer_pulse(attotime::from_hz(TIMER_SPEED), timer_expired_delegate(FUNC(rm380z_state::static_vblank_timer),this));
}
void rm380z_state::machine_reset()
{
m_port0=0x00;
m_port0_kbd=0x00;
m_port1=0x00;
m_fbfd=0x00;
m_fbfe=0x00;
m_old_fbfd=0x00;
m_old_old_fbfd=0x00;
writenum=0;
m_videomode=RM380Z_VIDEOMODE_80COL;
m_old_videomode=m_videomode;
m_rasterlineCtr=0;
// note: from COS 4.0 videos, screen seems to show garbage at the beginning
memset(m_mainVideoram,0,RM380Z_VIDEORAM_SIZE);
memset(m_vramattribs,0,RM380Z_SCREENSIZE);
memset(m_vramchars,0,RM380Z_SCREENSIZE);
memset(m_vram,0,RM380Z_SCREENSIZE);
config_memory_map();
machine().device("wd1771")->reset();
init_graphic_chars();
}
void rm380z_state::config_memory_map()
{
address_space &program = m_maincpu->space(AS_PROGRAM);
UINT8 *rom = memregion(RM380Z_MAINCPU_TAG)->base();
UINT8* m_ram_p = m_messram->pointer();
if ( RM380Z_PORTS_ENABLED_HIGH )
{
program.install_ram( 0x0000, 0xDFFF, m_ram_p );
}
else
{
program.install_rom( 0x0000, 0x0FFF, rom );
program.install_readwrite_handler(0x1BFC, 0x1BFF,read8_delegate(FUNC(rm380z_state::port_read_1b00), this),write8_delegate(FUNC(rm380z_state::port_write_1b00), this) );
program.install_rom( 0x1C00, 0x1DFF, rom + 0x1400 );
program.install_ram( 0x4000, 0xDFFF, m_ram_p );
}
}