mirror of
https://github.com/holub/mame
synced 2025-04-22 16:31:49 +03:00
casio/fp200.cpp: cleanups, convert I/O to memory_view, hookup RTC
This commit is contained in:
parent
7a87d06ae6
commit
1db8f70e30
@ -1,27 +1,25 @@
|
||||
// license:BSD-3-Clause
|
||||
// copyright-holders:Angelo Salese
|
||||
/***************************************************************************
|
||||
/**************************************************************************************************
|
||||
|
||||
FP-200 (c) 1982 Casio
|
||||
FP-200 (c) 1982 Casio
|
||||
|
||||
preliminary driver by Angelo Salese
|
||||
TODO:
|
||||
- Identify LCDC type, move to device (custom inside the gate array);
|
||||
- Confirm not having any sound capaibilities;
|
||||
- backup RAM;
|
||||
- cassette i/f;
|
||||
- FDC (requires test program that Service manual mentions);
|
||||
|
||||
TODO:
|
||||
- What's the LCDC type? Custom?
|
||||
- Unless I've missed something in the schems, this one shouldn't have any
|
||||
sound capability.
|
||||
- backup RAM.
|
||||
- Rewrite video emulation from scratch.
|
||||
|
||||
Notes:
|
||||
- on start-up there's a "memory illegal" warning. Enter "RESET" command
|
||||
to initialize it (thanks to Takeda Toshiya for pointing this out).
|
||||
|
||||
***************************************************************************/
|
||||
Notes:
|
||||
- on start-up there's a "memory illegal" warning. Enter "RESET" command
|
||||
to initialize it (thanks to Takeda Toshiya for pointing this out).
|
||||
|
||||
**************************************************************************************************/
|
||||
|
||||
#include "emu.h"
|
||||
#include "cpu/i8085/i8085.h"
|
||||
#include "machine/rp5c01.h"
|
||||
#include "emupal.h"
|
||||
#include "screen.h"
|
||||
#include "speaker.h"
|
||||
@ -37,6 +35,8 @@ public:
|
||||
fp200_state(const machine_config &mconfig, device_type type, const char *tag)
|
||||
: driver_device(mconfig, type, tag)
|
||||
, m_maincpu(*this, "maincpu")
|
||||
, m_rtc(*this, "rtc")
|
||||
, m_ioview(*this, "ioview")
|
||||
{ }
|
||||
|
||||
void fp200(machine_config &config);
|
||||
@ -46,9 +46,10 @@ public:
|
||||
private:
|
||||
// devices
|
||||
required_device<i8085a_cpu_device> m_maincpu;
|
||||
uint8_t m_io_type = 0;
|
||||
required_device<rp5c01_device> m_rtc;
|
||||
memory_view m_ioview;
|
||||
uint8_t *m_chargen = nullptr;
|
||||
uint8_t m_keyb_mux = 0;
|
||||
uint8_t m_keyb_matrix = 0;
|
||||
|
||||
struct{
|
||||
uint8_t x = 0;
|
||||
@ -65,19 +66,17 @@ private:
|
||||
// screen updates
|
||||
uint32_t screen_update(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect);
|
||||
|
||||
uint8_t fp200_io_r(offs_t offset);
|
||||
void fp200_io_w(offs_t offset, uint8_t data);
|
||||
uint8_t fp200_lcd_r(offs_t offset);
|
||||
void fp200_lcd_w(offs_t offset, uint8_t data);
|
||||
uint8_t fp200_keyb_r(offs_t offset);
|
||||
void fp200_keyb_w(offs_t offset, uint8_t data);
|
||||
uint8_t lcd_r(offs_t offset);
|
||||
void lcd_w(offs_t offset, uint8_t data);
|
||||
uint8_t keyb_r(offs_t offset);
|
||||
void keyb_w(offs_t offset, uint8_t data);
|
||||
|
||||
void sod_w(int state);
|
||||
int sid_r();
|
||||
|
||||
void fp200_palette(palette_device &palette) const;
|
||||
void fp200_io(address_map &map);
|
||||
void fp200_map(address_map &map);
|
||||
void palette_init(palette_device &palette) const;
|
||||
void main_io(address_map &map);
|
||||
void main_map(address_map &map);
|
||||
|
||||
// driver_device overrides
|
||||
virtual void machine_start() override;
|
||||
@ -92,7 +91,7 @@ void fp200_state::video_start()
|
||||
m_lcd.attr = make_unique_clear<uint8_t[]>(20*64);
|
||||
}
|
||||
|
||||
/* TODO: Very preliminary, I actually believe that the LCDC writes in a blitter fashion ... */
|
||||
// TODO: rewrite, don't loop 4 times
|
||||
uint32_t fp200_state::screen_update( screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect )
|
||||
{
|
||||
uint16_t l_offs, r_offs;
|
||||
@ -101,11 +100,11 @@ uint32_t fp200_state::screen_update( screen_device &screen, bitmap_ind16 &bitmap
|
||||
|
||||
l_offs = 0;
|
||||
r_offs = 0;
|
||||
for(int y=cliprect.top(); y<cliprect.bottom(); y++) // FIXME: off-by-one?
|
||||
for(int y = cliprect.top(); y <= cliprect.bottom(); y++)
|
||||
{
|
||||
for(int x=0;x<80;x++)
|
||||
for(int x = 0; x < 80;x++)
|
||||
{
|
||||
if(m_lcd.attr[x/8+y*20] == 0x50)
|
||||
if(m_lcd.attr[x / 8 + y * 20] == 0x50)
|
||||
{
|
||||
l_offs = (y & ~7);
|
||||
break;
|
||||
@ -113,7 +112,7 @@ uint32_t fp200_state::screen_update( screen_device &screen, bitmap_ind16 &bitmap
|
||||
}
|
||||
}
|
||||
|
||||
for(int y=cliprect.top(); y<cliprect.bottom(); y++) // FIXME: off-by-one?
|
||||
for(int y = cliprect.top(); y <= cliprect.bottom(); y++)
|
||||
{
|
||||
for(int x=80;x<160;x++)
|
||||
{
|
||||
@ -125,7 +124,7 @@ uint32_t fp200_state::screen_update( screen_device &screen, bitmap_ind16 &bitmap
|
||||
}
|
||||
}
|
||||
|
||||
for(int y=cliprect.top(); y<cliprect.bottom(); y++) // FIXME: off-by-one?
|
||||
for(int y = cliprect.top(); y <= cliprect.bottom(); y++)
|
||||
{
|
||||
for(int x=0;x<80;x++)
|
||||
{
|
||||
@ -152,7 +151,7 @@ uint32_t fp200_state::screen_update( screen_device &screen, bitmap_ind16 &bitmap
|
||||
}
|
||||
}
|
||||
|
||||
for(int y=cliprect.top(); y<cliprect.bottom(); y++) // FIXME: off-by-one?
|
||||
for(int y = cliprect.top(); y <= cliprect.bottom(); y++)
|
||||
{
|
||||
for(int x=80;x<160;x++)
|
||||
{
|
||||
@ -224,7 +223,7 @@ uint8_t fp200_state::read_lcd_vram(uint16_t X, uint16_t Y)
|
||||
return res;
|
||||
}
|
||||
|
||||
uint8_t fp200_state::fp200_lcd_r(offs_t offset)
|
||||
uint8_t fp200_state::lcd_r(offs_t offset)
|
||||
{
|
||||
uint8_t res;
|
||||
|
||||
@ -233,14 +232,14 @@ uint8_t fp200_state::fp200_lcd_r(offs_t offset)
|
||||
switch(offset)
|
||||
{
|
||||
case 1:
|
||||
//printf("%d %d -> (L) %02x\n",m_lcd.x,m_lcd.y,m_lcd.status);
|
||||
//logerror("%d %d -> (L) %02x\n",m_lcd.x,m_lcd.y,m_lcd.status);
|
||||
if(m_lcd.status == 0xb)
|
||||
res = read_lcd_attr(m_lcd.x,m_lcd.y);
|
||||
else if(m_lcd.status == 1)
|
||||
res = read_lcd_vram(m_lcd.x,m_lcd.y);
|
||||
break;
|
||||
case 2:
|
||||
//printf("%d %d -> (R) %02x\n",m_lcd.x,m_lcd.y,m_lcd.status);
|
||||
//logerror("%d %d -> (R) %02x\n",m_lcd.x,m_lcd.y,m_lcd.status);
|
||||
if(m_lcd.status == 0xb)
|
||||
res = read_lcd_attr(m_lcd.x + 10,m_lcd.y);
|
||||
else if(m_lcd.status == 1)
|
||||
@ -272,7 +271,7 @@ void fp200_state::write_lcd_attr(uint16_t X, uint16_t Y,uint8_t data)
|
||||
return;
|
||||
|
||||
//if(data != 0x60)
|
||||
// printf("%d %d %02x\n",X,Y,data);
|
||||
// logerror("%d %d %02x\n",X,Y,data);
|
||||
|
||||
m_lcd.attr[base_offs] = data;
|
||||
}
|
||||
@ -293,19 +292,19 @@ void fp200_state::write_lcd_vram(uint16_t X, uint16_t Y,uint8_t data)
|
||||
}
|
||||
}
|
||||
|
||||
void fp200_state::fp200_lcd_w(offs_t offset, uint8_t data)
|
||||
void fp200_state::lcd_w(offs_t offset, uint8_t data)
|
||||
{
|
||||
switch(offset)
|
||||
{
|
||||
case 1:
|
||||
//printf("%d %d -> %02x (%c) (L %02x)\n",m_lcd.x,m_lcd.y,data,data,m_lcd.status);
|
||||
//logerror("%d %d -> %02x (%c) (L %02x)\n",m_lcd.x,m_lcd.y,data,data,m_lcd.status);
|
||||
if(m_lcd.status == 0xb)
|
||||
write_lcd_attr(m_lcd.x,m_lcd.y,data);
|
||||
else if(m_lcd.status == 1)
|
||||
write_lcd_vram(m_lcd.x,m_lcd.y,data);
|
||||
break;
|
||||
case 2:
|
||||
//printf("%d %d -> %02x (%c) (R %02x)\n",m_lcd.x + 10,m_lcd.y,data,data,m_lcd.status);
|
||||
//logerror("%d %d -> %02x (%c) (R %02x)\n",m_lcd.x + 10,m_lcd.y,data,data,m_lcd.status);
|
||||
if(m_lcd.status == 0xb)
|
||||
write_lcd_attr(m_lcd.x + 10,m_lcd.y,data);
|
||||
else if(m_lcd.status == 1)
|
||||
@ -323,7 +322,7 @@ void fp200_state::fp200_lcd_w(offs_t offset, uint8_t data)
|
||||
}
|
||||
}
|
||||
|
||||
uint8_t fp200_state::fp200_keyb_r(offs_t offset)
|
||||
uint8_t fp200_state::keyb_r(offs_t offset)
|
||||
{
|
||||
const char *const keynames[16] = { "KEY0", "KEY1", "KEY2", "KEY3",
|
||||
"KEY4", "KEY5", "KEY6", "KEY7",
|
||||
@ -332,108 +331,57 @@ uint8_t fp200_state::fp200_keyb_r(offs_t offset)
|
||||
uint8_t res;
|
||||
|
||||
if(offset == 0)
|
||||
res = ioport(keynames[m_keyb_mux])->read();
|
||||
res = ioport(keynames[m_keyb_matrix])->read();
|
||||
else
|
||||
{
|
||||
printf("Unknown keyboard offset read access %02x\n",offset + 0x20);
|
||||
logerror("Unknown keyboard offset read access %02x\n",offset + 0x20);
|
||||
res = 0;
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
void fp200_state::fp200_keyb_w(offs_t offset, uint8_t data)
|
||||
void fp200_state::keyb_w(offs_t offset, uint8_t data)
|
||||
{
|
||||
if(offset == 1)
|
||||
m_keyb_mux = data & 0xf;
|
||||
else if(offset == 0)
|
||||
{
|
||||
// ... ?
|
||||
}
|
||||
m_keyb_matrix = data & 0xf;
|
||||
else
|
||||
printf("Unknown keyboard offset write access %02x %02x\n",offset + 0x20,data);
|
||||
logerror("Unknown keyboard offset write access %02x %02x\n",offset + 0x20,data);
|
||||
}
|
||||
|
||||
/*
|
||||
Annoyingly the i/o map uses the SOD to access different devices, so we need trampolines.
|
||||
SOD = 0
|
||||
0x10 - 0x1f Timer control (RPC05 RTC)
|
||||
0x20 - 0x2f AUTO-POWER OFF
|
||||
0x40 - 0x4f FDC Device ID Code (5 for "FP-1021FD")
|
||||
0x80 - 0xff FDD (unknown type)
|
||||
SOD = 1
|
||||
0x00 - 0x0f LCD control.
|
||||
0x10 - 0x1f I/O control
|
||||
0x20 - 0x2f Keyboard
|
||||
0x40 - 0x4f MT.RS-232C control
|
||||
0x80 - 0x8f Printer (Centronics)
|
||||
*/
|
||||
uint8_t fp200_state::fp200_io_r(offs_t offset)
|
||||
void fp200_state::main_map(address_map &map)
|
||||
{
|
||||
uint8_t res;
|
||||
|
||||
if(m_io_type == 0)
|
||||
{
|
||||
res = 0;
|
||||
logerror("Unemulated I/O read %02x (%02x)\n",offset,m_io_type);
|
||||
}
|
||||
else
|
||||
{
|
||||
switch(offset & 0xf0)
|
||||
{
|
||||
//case 0x00: return;
|
||||
case 0x00: res = fp200_lcd_r(offset & 0xf); break;
|
||||
case 0x20: res = fp200_keyb_r(offset & 0xf); break;
|
||||
default: res = 0; logerror("Unemulated I/O read %02x (%02x)\n",offset,m_io_type); break;
|
||||
}
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
void fp200_state::fp200_io_w(offs_t offset, uint8_t data)
|
||||
{
|
||||
if(m_io_type == 0)
|
||||
{
|
||||
switch(offset & 0xf0)
|
||||
{
|
||||
default:logerror("Unemulated I/O write %02x (%02x) <- %02x\n",offset,m_io_type,data); break;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
switch(offset & 0xf0)
|
||||
{
|
||||
case 0x00: fp200_lcd_w(offset & 0xf,data); break;
|
||||
case 0x20: fp200_keyb_w(offset & 0xf,data); break;
|
||||
default:logerror("Unemulated I/O write %02x (%02x) <- %02x\n",offset,m_io_type,data); break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void fp200_state::fp200_map(address_map &map)
|
||||
{
|
||||
map(0x0000, 0x7fff).rom();
|
||||
map(0x8000, 0x9fff).ram();
|
||||
// 0xa000, 0xffff exp RAM
|
||||
map(0x0000, 0x7fff).rom(); // basic & cetl
|
||||
// TODO: 1 waitstate penalty for accessing any RAM
|
||||
map(0x8000, 0x9fff).ram(); // internal RAM
|
||||
// 0xa000, 0xffff exp RAM (FP-201RAM)
|
||||
map(0xa000, 0xbfff).ram();
|
||||
map(0xc000, 0xdfff).ram();
|
||||
map(0xe000, 0xffff).ram();
|
||||
map(0xe000, 0xffff).ram(); // or exp ROM (FP-206ROM)
|
||||
}
|
||||
|
||||
void fp200_state::fp200_io(address_map &map)
|
||||
void fp200_state::main_io(address_map &map)
|
||||
{
|
||||
map(0x00, 0xff).rw(FUNC(fp200_state::fp200_io_r), FUNC(fp200_state::fp200_io_w));
|
||||
map(0x00, 0xff).view(m_ioview);
|
||||
m_ioview[0](0x10, 0x1f).rw("rtc", FUNC(rp5c01_device::read), FUNC(rp5c01_device::write));
|
||||
// m_ioview[0](0x20, 0x2f) AUTO-POWER OFF
|
||||
// m_ioview[0](0x40, 0x4f) FDC Device ID Code (5 for "FP-1021FD")
|
||||
// m_ioview[0](0x80, 0xff) FDD (unknown type)
|
||||
m_ioview[1](0x00, 0x0f).rw(FUNC(fp200_state::lcd_r), FUNC(fp200_state::lcd_w));
|
||||
// m_ioview[1](0x10, 0x10) I/O control (w/o), D1 selects CMT or RS-232C
|
||||
// m_ioview[1](0x11, 0x11) I/O control (w/o), uPD65010G gate array control
|
||||
m_ioview[1](0x20, 0x2f).rw(FUNC(fp200_state::keyb_r), FUNC(fp200_state::keyb_w));
|
||||
// m_ioview[1](0x40, 0x4f) CMT & RS-232C control
|
||||
// m_ioview[1](0x80, 0x8f) [Centronics] printer
|
||||
}
|
||||
|
||||
INPUT_CHANGED_MEMBER(fp200_state::keyb_irq)
|
||||
{
|
||||
/* a keyboard stroke causes a rst7.5 */
|
||||
m_maincpu->set_input_line(I8085_RST75_LINE, (newval) ? ASSERT_LINE : CLEAR_LINE);
|
||||
|
||||
}
|
||||
|
||||
/* TODO: remote SW? */
|
||||
// TODO: implement remote SW
|
||||
static INPUT_PORTS_START( fp200 )
|
||||
PORT_START("KEY0")
|
||||
PORT_BIT( 0x0f, IP_ACTIVE_HIGH, IPT_UNUSED )
|
||||
@ -541,8 +489,8 @@ static const gfx_layout charlayout =
|
||||
RGN_FRAC(1,1),
|
||||
1,
|
||||
{ RGN_FRAC(0,1) },
|
||||
{ 0*8, 1*8, 2*8, 3*8, 4*8, 5*8, 6*8, 7*8 },
|
||||
{ 0, 1, 2, 3, 4, 5, 6, 7 },
|
||||
{ STEP8(0, 8) },
|
||||
{ STEP8(0, 1) },
|
||||
8*8
|
||||
};
|
||||
|
||||
@ -556,10 +504,9 @@ void fp200_state::machine_start()
|
||||
uint8_t *raw_gfx = memregion("raw_gfx")->base();
|
||||
m_chargen = memregion("chargen")->base();
|
||||
|
||||
for(int i=0;i<0x800;i++)
|
||||
{
|
||||
m_chargen[i] = raw_gfx[bitswap<16>(i,15,14,13,12,11,6,5,4,3,10,9,8,7,2,1,0)];
|
||||
}
|
||||
// HACK: convert GFX to a more usable format
|
||||
for(int i = 0; i < 0x800; i++)
|
||||
m_chargen[i] = raw_gfx[bitswap<16>(i, 15, 14, 13, 12, 11, 6, 5, 4, 3, 10, 9, 8, 7, 2, 1, 0)];
|
||||
}
|
||||
|
||||
void fp200_state::machine_reset()
|
||||
@ -567,7 +514,7 @@ void fp200_state::machine_reset()
|
||||
}
|
||||
|
||||
|
||||
void fp200_state::fp200_palette(palette_device &palette) const
|
||||
void fp200_state::palette_init(palette_device &palette) const
|
||||
{
|
||||
palette.set_pen_color(0, 0xa0, 0xa8, 0xa0);
|
||||
palette.set_pen_color(1, 0x30, 0x38, 0x10);
|
||||
@ -575,23 +522,25 @@ void fp200_state::fp200_palette(palette_device &palette) const
|
||||
|
||||
void fp200_state::sod_w(int state)
|
||||
{
|
||||
m_io_type = state;
|
||||
m_ioview.select(state);
|
||||
}
|
||||
|
||||
int fp200_state::sid_r()
|
||||
{
|
||||
return (ioport("KEYMOD")->read() >> m_keyb_mux) & 1;
|
||||
return (ioport("KEYMOD")->read() >> m_keyb_matrix) & 1;
|
||||
}
|
||||
|
||||
void fp200_state::fp200(machine_config &config)
|
||||
{
|
||||
/* basic machine hardware */
|
||||
I8085A(config, m_maincpu, MAIN_CLOCK);
|
||||
m_maincpu->set_addrmap(AS_PROGRAM, &fp200_state::fp200_map);
|
||||
m_maincpu->set_addrmap(AS_IO, &fp200_state::fp200_io);
|
||||
m_maincpu->set_addrmap(AS_PROGRAM, &fp200_state::main_map);
|
||||
m_maincpu->set_addrmap(AS_IO, &fp200_state::main_io);
|
||||
m_maincpu->in_sid_func().set(FUNC(fp200_state::sid_r));
|
||||
m_maincpu->out_sod_func().set(FUNC(fp200_state::sod_w));
|
||||
|
||||
RP5C01(config, "rtc", XTAL(32'768));
|
||||
|
||||
/* video hardware */
|
||||
screen_device &screen(SCREEN(config, "screen", SCREEN_TYPE_LCD));
|
||||
screen.set_refresh_hz(60);
|
||||
@ -603,10 +552,9 @@ void fp200_state::fp200(machine_config &config)
|
||||
|
||||
GFXDECODE(config, "gfxdecode", "palette", gfx_fp200);
|
||||
|
||||
PALETTE(config, "palette", FUNC(fp200_state::fp200_palette), 2);
|
||||
PALETTE(config, "palette", FUNC(fp200_state::palette_init), 2);
|
||||
|
||||
/* sound hardware */
|
||||
SPEAKER(config, "mono").front_center();
|
||||
// No sound HW
|
||||
}
|
||||
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user