/* 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("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 ); } }