Permalink
Cannot retrieve contributors at this time
3333 lines (2822 sloc)
134 KB
| // license:BSD-3-Clause | |
| // copyright-holders:Angelo Salese,Carl | |
| /************************************************************************************************** | |
| PC-9801 (c) 1981 NEC | |
| driver by Angelo Salese | |
| TODO: | |
| - proper 8251 uart hook-up on keyboard; | |
| - SASI/SCSI support; | |
| - Finish DIP-Switches support; | |
| - text scrolling, upd52611 (cfr. clipping in edge & arcus2, madoum* too?); | |
| - AGDC emulation, upd72120; | |
| - CMT support (-13/-36 cbus only, identify which models mounted it off the bat); | |
| - Write a PC80S31K device for 2d type floppies | |
| (also used on PC-8801 and PC-88VA, it's the FDC + Z80 sub-system); | |
| - DAC1BIT has a bit of clicking with start/end of samples, is it fixable or just a btanb? | |
| - clean-ups & split into separate devices and driver flavours; | |
| - derive romsets by default options (cfr. 3.5 2HD floppies vs. default 5.25, 2D/2DD etc.); | |
| - Remove kludge for POR bit in a20_ctrl_w fn; | |
| - floppy sounds never silences when drive is idle (disabled for the time being); | |
| TODO (PC-9801F) | |
| - kanji port 0xa9 readback is broken for several games (balpower, lovelyho). | |
| TODO (PC-9801RS): | |
| - several unemulated extra f/f features; | |
| - keyboard shift doesn't seem to disable properly (fixed by now?); | |
| - Several games hangs with stuck note by misfired/not catched up -26 / -86 irq; | |
| - clean-up duplicate code; | |
| TODO (PC-9821): | |
| - fix CPU for some clones; | |
| - "cache error" | |
| - undumped IDE ROM, kludged to work; | |
| TODO (PC-9821AS) | |
| - IPL ROM banking contradicts greatly from the other machines; | |
| TODO (PC-386M): | |
| - "ERR:BR" at boot (BIOS loader error). | |
| Executes some code in text VRAM area (PC=$a006e), trying to setup a writeable RAM bank | |
| (shadow RAM even?) to IPL window, I/O $c06 seems to be the control port for it; | |
| TODO: (PC-486SE/PC-486MU): | |
| - Verify ROM bankswitch; | |
| On PC-486SE sets up what is normally IPL bankswitch at PC=0xf5115, successive opcode | |
| is a jmp 0xf8000, pretty unlikely it delays bankswitch so assume it reloads | |
| the same bank. | |
| - Fix POR/ROM bankswitch on soft resets. | |
| - Eventually errors with a ERR:VR (GFX VRAM); | |
| TODO: (PC-9821AP) | |
| - No way to exit the initial loop. Code looks broken, bad dump? | |
| TODO: (PC-9821Xa16/PC-9821Ra20/PC-9821Ra333) | |
| - "MICON ERROR" at POST (generic HW fault, PCI?); | |
| =================================================================================================== | |
| This series features a huge number of models released between 1982 and 1997. They | |
| were not IBM PC-compatible, but they had similar hardware (and software: in the | |
| 1990s, they run MS Windows as OS) | |
| Models: | |
| | CPU | RAM | Drives | CBus| Release | | |
| PC-9801 | 8086 @ 5 | 128 KB | - | 6 | 1982/10 | | |
| PC-9801F1 | 8086-2 @ 5/8 | 128 KB | 5"2DDx1 | 4 | 1983/10 | | |
| PC-9801F2 | 8086-2 @ 5/8 | 128 KB | 5"2DDx2 | 4 | 1983/10 | | |
| PC-9801E | 8086-2 @ 5/8 | 128 KB | - | 6 | 1983/11 | | |
| PC-9801F3 | 8086-2 @ 5/8 | 256 KB | 5"2DDx1, 10M SASI HDD | 2 | 1984/10 | | |
| PC-9801M2 | 8086-2 @ 5/8 | 256 KB | 5"2HDx2 | 4 | 1984/11 | | |
| PC-9801M3 | 8086-2 @ 5/8 | 256 KB | 5"2HDx1, 20M SASI HDD | 3 | 1985/02 | | |
| PC-9801U2 | V30 @ 8 | 128 KB | 3.5"2HDx2 | 2 | 1985/05 | | |
| PC-98XA1 | 80286 @ 8 | 512 KB | - | 6 | 1985/05 | | |
| PC-98XA2 | 80286 @ 8 | 512 KB | 5"2DD/2HDx2 | 6 | 1985/05 | | |
| PC-98XA3 | 80286 @ 8 | 512 KB | 5"2DD/2HDx1, 20M SASI HDD | 6 | 1985/05 | | |
| PC-9801VF2 | V30 @ 8 | 384 KB | 5"2DDx2 | 4 | 1985/07 | | |
| PC-9801VM0 | V30 @ 8/10 | 384 KB | - | 4 | 1985/07 | | |
| PC-9801VM2 | V30 @ 8/10 | 384 KB | 5"2DD/2HDx2 | 4 | 1985/07 | | |
| PC-9801VM4 | V30 @ 8/10 | 384 KB | 5"2DD/2HDx2, 20M SASI HDD | 4 | 1985/10 | | |
| PC-98XA11 | 80286 @ 8 | 512 KB | - | 6 | 1986/05 | | |
| PC-98XA21 | 80286 @ 8 | 512 KB | 5"2DD/2HDx2 | 6 | 1986/05 | | |
| PC-98XA31 | 80286 @ 8 | 512 KB | 5"2DD/2HDx1, 20M SASI HDD | 6 | 1986/05 | | |
| PC-9801UV2 | V30 @ 8/10 | 384 KB | 3.5"2DD/2HDx2 | 2 | 1986/05 | | |
| PC-98LT1 | V50 @ 8 | 384 KB | 3.5"2DD/2HDx1 | 0 | 1986/11 | | |
| PC-98LT2 | V50 @ 8 | 384 KB | 3.5"2DD/2HDx1 | 0 | 1986/11 | | |
| PC-9801VM21 | V30 @ 8/10 | 640 KB | 5"2DD/2HDx2 | 4 | 1986/11 | | |
| PC-9801VX0 | 80286 @ 8 & V30 @ 8/10 | 640 KB | - | 4 | 1986/11 | | |
| PC-9801VX2 | 80286 @ 8 & V30 @ 8/10 | 640 KB | 5"2DD/2HDx2 | 4 | 1986/11 | | |
| PC-9801VX4 | 80286 @ 8 & V30 @ 8/10 | 640 KB | 5"2DD/2HDx2, 20M SASI HDD | 4 | 1986/11 | | |
| PC-9801VX4/WN | 80286 @ 8 & V30 @ 8/10 | 640 KB | 5"2DD/2HDx2, 20M SASI HDD | 4 | 1986/11 | | |
| PC-98XL1 | 80286 @ 8 & V30 @ 8/10 | 1152 KB | - | 4 | 1986/12 | | |
| PC-98XL2 | 80286 @ 8 & V30 @ 8/10 | 1152 KB | 5"2DD/2HDx2 | 4 | 1986/12 | | |
| PC-98XL4 | 80286 @ 8 & V30 @ 8/10 | 1152 KB | 5"2DD/2HDx1, 20M SASI HDD | 4 | 1986/12 | | |
| PC-9801VX01 | 80286-10 @ 8/10 & V30 @ 8/10 | 640 KB | - | 4 | 1987/06 | | |
| PC-9801VX21 | 80286-10 @ 8/10 & V30 @ 8/10 | 640 KB | 5"2DD/2HDx2 | 4 | 1987/06 | | |
| PC-9801VX41 | 80286-10 @ 8/10 & V30 @ 8/10 | 640 KB | 5"2DD/2HDx2, 20M SASI HDD | 4 | 1987/06 | | |
| PC-9801UV21 | V30 @ 8/10 | 640 KB | 3.5"2DD/2HDx2 | 2 | 1987/06 | | |
| PC-98XL^2 | i386DX-16 @ 16 & V30 @ 8 | 1.6 MB | 5"2DD/2HDx2, 40M SASI HDD | 4 | 1987/10 | | |
| PC-98LT11 | V50 @ 8 | 640 KB | 3.5"2DD/2HDx1 | 0 | 1987/10 | | |
| PC-98LT21 | V50 @ 8 | 640 KB | 3.5"2DD/2HDx1 | 0 | 1987/10 | | |
| PC-9801UX21 | 80286-10 @ 10 & V30 @ 8 | 640 KB | 3.5"2DD/2HDx2 | 3 | 1987/10 | | |
| PC-9801UX41 | 80286-10 @ 10 & V30 @ 8 | 640 KB | 3.5"2DD/2HDx2, 20M SASI HDD | 3 | 1987/10 | | |
| PC-9801LV21 | V30 @ 8/10 | 640 KB | 3.5"2DD/2HDx2 | 0 | 1988/03 | | |
| PC-9801CV21 | V30 @ 8/10 | 640 KB | 3.5"2DD/2HDx2 | 2 | 1988/03 | | |
| PC-9801UV11 | V30 @ 8/10 | 640 KB | 3.5"2DD/2HDx2 | 2 | 1988/03 | | |
| PC-9801RA2 | i386DX-16 @ 16 & V30 @ 8 | 1.6 MB | 5"2DD/2HDx2 | 4 | 1988/07 | | |
| PC-9801RA5 | i386DX-16 @ 16 & V30 @ 8 | 1.6 MB | 5"2DD/2HDx2, 40M SASI HDD | 4 | 1988/07 | | |
| PC-9801RX2 | 80286-12 @ 10/12 & V30 @ 8 | 640 KB | 5"2DD/2HDx2 | 4 | 1988/07 | | |
| PC-9801RX4 | 80286-12 @ 10/12 & V30 @ 8 | 640 KB | 5"2DD/2HDx2, 20M SASI HDD | 4 | 1988/07 | | |
| PC-98LT22 | V50 @ 8 | 640 KB | 3.5"2DD/2HDx1 | 0 | 1988/11 | | |
| PC-98LS2 | i386SX-16 @ 16 & V30 @ 8 | 1.6 MB | 5"2DD/2HDx2 | 0 | 1988/11 | | |
| PC-98LS5 | i386SX-16 @ 16 & V30 @ 8 | 1.6 MB | 5"2DD/2HDx2, 40M SASI HDD | 0 | 1988/11 | | |
| PC-9801VM11 | V30 @ 8/10 | 640 KB | 5"2DD/2HDx2 | 4 | 1988/11 | | |
| PC-9801LV22 | V30 @ 8/10 | 640 KB | 3.5"2DD/2HDx2 | 0 | 1989/01 | | |
| PC-98RL2 | i386DX-20 @ 16/20 & V30 @ 8 | 1.6 MB | 5"2DD/2HDx2 | 4 | 1989/02 | | |
| PC-98RL5 | i386DX-20 @ 16/20 & V30 @ 8 | 1.6 MB | 5"2DD/2HDx2, 40M SASI HDD | 4 | 1989/02 | | |
| PC-9801EX2 | 80286-12 @ 10/12 & V30 @ 8 | 640 KB | 3.5"2DD/2HDx2 | 3 | 1989/04 | | |
| PC-9801EX4 | 80286-12 @ 10/12 & V30 @ 8 | 640 KB | 3.5"2DD/2HDx2, 20M SASI HDD | 3 | 1989/04 | | |
| PC-9801ES2 | i386SX-16 @ 16 & V30 @ 8 | 1.6 MB | 3.5"2DD/2HDx2 | 3 | 1989/04 | | |
| PC-9801ES5 | i386SX-16 @ 16 & V30 @ 8 | 1.6 MB | 3.5"2DD/2HDx2, 40M SASI HDD | 3 | 1989/04 | | |
| PC-9801LX2 | 80286-12 @ 10/12 & V30 @ 8 | 640 KB | 3.5"2DD/2HDx2 | 0 | 1989/04 | | |
| PC-9801LX4 | 80286-12 @ 10/12 & V30 @ 8 | 640 KB | 3.5"2DD/2HDx2, 20M SASI HDD | 0 | 1989/04 | | |
| PC-9801LX5 | 80286-12 @ 10/12 & V30 @ 8 | 640 KB | 3.5"2DD/2HDx2, 40M SASI HDD | 0 | 1989/06 | | |
| PC-98DO | V30 @ 8/10 | 640 KB | 5"2DD/2HDx2 | 1 | 1989/06 | | |
| PC-9801LX5C | 80286-12 @ 10/12 & V30 @ 8 | 640 KB | 3.5"2DD/2HDx2, 40M SASI HDD | 0 | 1989/06 | | |
| PC-9801RX21 | 80286-12 @ 10/12 & V30 @ 8 | 640 KB | 5"2DD/2HDx2 | 4 | 1989/10 | | |
| PC-9801RX51 | 80286-12 @ 10/12 & V30 @ 8 | 640 KB | 5"2DD/2HDx2, 40M SASI HDD | 4 | 1989/10 | | |
| PC-9801RA21 | i386DX-20 @ 16/20 & V30 @ 8 | 1.6 MB | 5"2DD/2HDx2 | 4 | 1989/11 | | |
| PC-9801RA51 | i386DX-20 @ 16/20 & V30 @ 8 | 1.6 MB | 5"2DD/2HDx2, 40M SASI HDD | 4 | 1989/11 | | |
| PC-9801RS21 | i386SX-16 @ 16 & V30 @ 8 | 640 KB | 5"2DD/2HDx2 | 4 | 1989/11 | | |
| PC-9801RS51 | i386SX-16 @ 16 & V30 @ 8 | 640 KB | 5"2DD/2HDx2, 40M SASI HDD | 4 | 1989/11 | | |
| PC-9801N | V30 @ 10 | 640 KB | 3.5"2DD/2HDx1 | 0 | 1989/11 | | |
| PC-9801TW2 | i386SX-20 @ 20 & V30 @ 8 | 640 KB | 3.5"2DD/2HDx2 | 2 | 1990/02 | | |
| PC-9801TW5 | i386SX-20 @ 20 & V30 @ 8 | 1.6 MB | 3.5"2DD/2HDx2, 40M SASI HDD | 2 | 1990/02 | | |
| PC-9801TS5 | i386SX-20 @ 20 & V30 @ 8 | 1.6 MB | 3.5"2DD/2HDx2, 40M SASI HDD | 2 | 1990/06 | | |
| PC-9801NS | i386SX-12 @ 12 | 1.6 MB | 3.5"2DD/2HDx1 | 0 | 1990/06 | | |
| PC-9801TF5 | i386SX-20 @ 20 & V30 @ 8 | 1.6 MB | 3.5"2DD/2HDx2, 40M SASI HDD | 2 | 1990/07 | | |
| PC-9801NS-20 | i386SX-12 @ 12 | 1.6 MB | 3.5"2DD/2HDx1, 20M SASI HDD | 0 | 1990/09 | | |
| PC-98RL21 | i386DX-20 @ 20 & V30 @ 8 | 1.6 MB | 5"2DD/2HDx2 | 4 | 1990/09 | | |
| PC-98RL51 | i386DX-20 @ 20 & V30 @ 8 | 1.6 MB | 5"2DD/2HDx1, 40M SASI HDD | 4 | 1990/09 | | |
| PC-98DO+ | V33A @ 8/16 | 640 KB | 5"2DD/2HDx2 | 1 | 1990/10 | | |
| PC-9801DX2 | 80286-12 @ 10/12 & V30 @ 8 | 640 KB | 5"2DD/2HDx2 | 4 | 1990/11 | | |
| PC-9801DX/U2 | 80286-12 @ 10/12 & V30 @ 8 | 640 KB | 3.5"2DD/2HDx2 | 4 | 1990/11 | | |
| PC-9801DX5 | 80286-12 @ 10/12 & V30 @ 8 | 640 KB | 5"2DD/2HDx2, 40M SASI HDD | 4 | 1990/11 | | |
| PC-9801DX/U5 | 80286-12 @ 10/12 & V30 @ 8 | 640 KB | 3.5"2DD/2HDx2, 40M SASI HDD | 4 | 1990/11 | | |
| PC-9801NV | V30HL @ 8/16 | 1.6 MB | 3.5"2DD/2HDx1 | 0 | 1990/11 | | |
| PC-9801DS2 | i386SX-16 @ 16 & V30 @ 8 | 640 KB | 5"2DD/2HDx2 | 4 | 1991/01 | | |
| PC-9801DS/U2 | i386SX-16 @ 16 & V30 @ 8 | 640 KB | 3.5"2DD/2HDx2 | 4 | 1991/01 | | |
| PC-9801DS5 | i386SX-16 @ 16 & V30 @ 8 | 640 KB | 5"2DD/2HDx2, 40M SASI HDD | 4 | 1991/01 | | |
| PC-9801DS/U5 | i386SX-16 @ 16 & V30 @ 8 | 640 KB | 3.5"2DD/2HDx2, 40M SASI HDD | 4 | 1991/01 | | |
| PC-9801DA2 | i386DX-20 @ 16/20 & V30 @ 8 | 1.6 MB | 5"2DD/2HDx2 | 4 | 1991/01 | | |
| PC-9801DA/U2 | 80286-12 @ 10/12 & V30 @ 8 | 640 KB | 3.5"2DD/2HDx2 | 4 | 1991/01 | | |
| PC-9801DA5 | 80286-12 @ 10/12 & V30 @ 8 | 640 KB | 5"2DD/2HDx2, 40M SASI HDD | 4 | 1991/01 | | |
| PC-9801DA/U5 | 80286-12 @ 10/12 & V30 @ 8 | 640 KB | 3.5"2DD/2HDx2, 40M SASI HDD | 4 | 1991/01 | | |
| PC-9801DA7 | 80286-12 @ 10/12 & V30 @ 8 | 640 KB | 5"2DD/2HDx2, 100M SCSI HDD | 4 | 1991/02 | | |
| PC-9801DA/U7 | 80286-12 @ 10/12 & V30 @ 8 | 640 KB | 3.5"2DD/2HDx2, 100M SCSI HDD | 4 | 1991/02 | | |
| PC-9801UF | V30 @ 8/16 | 640 KB | 3.5"2DD/2HDx2 | 2 | 1991/02 | | |
| PC-9801UR | V30 @ 8/16 | 640 KB | 3.5"2DD/2HDx1, 1.25MB RAM Disk | 2 | 1991/02 | | |
| PC-9801UR/20 | V30 @ 8/16 | 640 KB | 3.5"2DD/2HDx1, 1.25MB RAM Disk, 20M SASI HDD | 2 | 1991/02 | | |
| PC-9801NS/E | i386SX-16 @ 16 | 1.6 MB | 3.5"2DD/2HDx1, 1.25MB RAM Disk | 0 | 1991/06 | | |
| PC-9801NS/E20 | i386SX-16 @ 16 | 1.6 MB | 3.5"2DD/2HDx1, 1.25MB RAM Disk, 20M SASI HDD | 0 | 1991/06 | | |
| PC-9801NS/E40 | i386SX-16 @ 16 | 1.6 MB | 3.5"2DD/2HDx1, 1.25MB RAM Disk, 40M SASI HDD | 0 | 1991/06 | | |
| PC-9801TW7 | i386SX-20 @ 20 & V30 @ 8 | 1.6 MB | 3.5"2DD/2HDx2, 100M SCSI HDD | 2 | 1991/07 | | |
| PC-9801TF51 | i386SX-20 @ 20 & V30 @ 8 | 1.6 MB | 3.5"2DD/2HDx2, 40M SASI HDD | 2 | 1991/07 | | |
| PC-9801TF71 | i386SX-20 @ 20 & V30 @ 8 | 1.6 MB | 3.5"2DD/2HDx2, 100M SCSI HDD | 2 | 1991/07 | | |
| PC-9801NC | i386SX-20 @ 20 | 2.6 MB | 3.5"2DD/2HDx1, 1.25MB RAM Disk | 0 | 1991/10 | | |
| PC-9801NC40 | i386SX-20 @ 20 | 2.6 MB | 3.5"2DD/2HDx1, 1.25MB RAM Disk, 40M SASI HDD | 0 | 1991/10 | | |
| PC-9801CS2 | i386SX-16 @ 16 | 640 KB | 3.5"2DD/2HDx2 | 2 | 1991/10 | | |
| PC-9801CS5 | i386SX-16 @ 16 | 640 KB | 3.5"2DD/2HDx2, 40M SASI HDD | 2 | 1991/10 | | |
| PC-9801CS5/W | i386SX-16 @ 16 | 3.6 MB | 3.5"2DD/2HDx2, 40M SASI HDD | 2 | 1991/11 | | |
| PC-98GS1 | i386SX-20 @ 20 & V30 @ 8 | 2.6 MB | 3.5"2DD/2HDx2, 40M SASI HDD | 3 | 1991/11 | | |
| PC-98GS2 | i386SX-20 @ 20 & V30 @ 8 | 2.6 MB | 3.5"2DD/2HDx2, 40M SASI HDD, 1xCD-ROM | 3 | 1991/11 | | |
| PC-9801FA2 | i486SX-16 @ 16 | 1.6 MB | 5"2DD/2HDx2 | 4 | 1992/01 | | |
| PC-9801FA/U2 | i486SX-16 @ 16 | 1.6 MB | 3.5"2DD/2HDx2 | 4 | 1992/01 | | |
| PC-9801FA5 | i486SX-16 @ 16 | 1.6 MB | 5"2DD/2HDx2, 40M SCSI HDD | 4 | 1992/01 | | |
| PC-9801FA/U5 | i486SX-16 @ 16 | 1.6 MB | 3.5"2DD/2HDx2, 40M SCSI HDD | 4 | 1992/01 | | |
| PC-9801FA7 | i486SX-16 @ 16 | 1.6 MB | 5"2DD/2HDx2, 100M SCSI HDD | 4 | 1992/01 | | |
| PC-9801FA/U7 | i486SX-16 @ 16 | 1.6 MB | 3.5"2DD/2HDx2, 100M SCSI HDD | 4 | 1992/01 | | |
| PC-9801FS2 | i386SX-20 @ 16/20 | 1.6 MB | 5"2DD/2HDx2 | 4 | 1992/05 | | |
| PC-9801FS/U2 | i386SX-20 @ 16/20 | 1.6 MB | 3.5"2DD/2HDx2 | 4 | 1992/05 | | |
| PC-9801FS5 | i386SX-20 @ 16/20 | 1.6 MB | 5"2DD/2HDx2, 40M SCSI HDD | 4 | 1992/05 | | |
| PC-9801FS/U5 | i386SX-20 @ 16/20 | 1.6 MB | 3.5"2DD/2HDx2, 40M SCSI HDD | 4 | 1992/05 | | |
| PC-9801FS7 | i386SX-20 @ 16/20 | 1.6 MB | 5"2DD/2HDx2, 100M SCSI HDD | 4 | 1992/01 | | |
| PC-9801FS/U7 | i386SX-20 @ 16/20 | 1.6 MB | 3.5"2DD/2HDx2, 100M SCSI HDD | 4 | 1992/01 | | |
| PC-9801NS/T | i386SL(98) @ 20 | 1.6 MB | 3.5"2DD/2HDx1, 1.25MB RAM Disk | 0 | 1992/01 | | |
| PC-9801NS/T40 | i386SL(98) @ 20 | 1.6 MB | 3.5"2DD/2HDx1, 1.25MB RAM Disk, 40M SASI HDD | 0 | 1992/01 | | |
| PC-9801NS/T80 | i386SL(98) @ 20 | 1.6 MB | 3.5"2DD/2HDx1, 1.25MB RAM Disk, 80M SASI HDD | 0 | 1992/01 | | |
| PC-9801NL | V30H @ 8/16 | 640 KB | 1.25 MB RAM Disk | 0 | 1992/01 | | |
| PC-9801FX2 | i386SX-12 @ 10/12 | 1.6 MB | 5"2DD/2HDx2 | 4 | 1992/05 | | |
| PC-9801FX/U2 | i386SX-12 @ 10/12 | 1.6 MB | 3.5"2DD/2HDx2 | 4 | 1992/05 | | |
| PC-9801FX5 | i386SX-12 @ 10/12 | 1.6 MB | 5"2DD/2HDx2, 40M SCSI HDD | 4 | 1992/05 | | |
| PC-9801FX/U5 | i386SX-12 @ 10/12 | 1.6 MB | 3.5"2DD/2HDx2, 40M SCSI HDD | 4 | 1992/05 | | |
| PC-9801US | i386SX-16 @ 16 | 1.6 MB | 3.5"2DD/2HDx2 | 2 | 1992/07 | | |
| PC-9801US40 | i386SX-16 @ 16 | 1.6 MB | 3.5"2DD/2HDx2, 40M SASI HDD | 2 | 1992/07 | | |
| PC-9801US80 | i386SX-16 @ 16 | 1.6 MB | 3.5"2DD/2HDx2, 80M SASI HDD | 2 | 1992/07 | | |
| PC-9801NS/L | i386SX-20 @ 10/20 | 1.6 MB | 3.5"2DD/2HDx1, 1.25MB RAM Disk | 0 | 1992/07 | | |
| PC-9801NS/L40 | i386SX-20 @ 10/20 | 1.6 MB | 3.5"2DD/2HDx1, 1.25MB RAM Disk, 40M SASI HDD | 0 | 1992/07 | | |
| PC-9801NA | i486SX-20 @ 20 | 2.6 MB | 3.5"2DD/2HDx1, 1.25MB RAM Disk | 0 | 1992/11 | | |
| PC-9801NA40 | i486SX-20 @ 20 | 2.6 MB | 3.5"2DD/2HDx1, 1.25MB RAM Disk, 40M SASI HDD | 0 | 1992/11 | | |
| PC-9801NA120 | i486SX-20 @ 20 | 2.6 MB | 3.5"2DD/2HDx1, 1.25MB RAM Disk, 120M SASI HDD | 0 | 1992/11 | | |
| PC-9801NA/C | i486SX-20 @ 20 | 2.6 MB | 3.5"2DD/2HDx1, 1.25MB RAM Disk | 0 | 1992/11 | | |
| PC-9801NA40/C | i486SX-20 @ 20 | 2.6 MB | 3.5"2DD/2HDx1, 1.25MB RAM Disk, 40M SASI HDD | 0 | 1992/11 | | |
| PC-9801NA120/C | i486SX-20 @ 20 | 2.6 MB | 3.5"2DD/2HDx1, 1.25MB RAM Disk, 120M SASI HDD | 0 | 1992/11 | | |
| PC-9801NS/R | i486SX(J) @ 20 | 1.6 MB | 3.5"2DD/2HDx1 (3mode), 1.25MB RAM Disk | 0 | 1993/01 | | |
| PC-9801NS/R40 | i486SX(J) @ 20 | 1.6 MB | 3.5"2DD/2HDx1 (3mode), 1.25MB RAM Disk, 40M SASI HDD | 0 | 1993/01 | | |
| PC-9801NS/R120 | i486SX(J) @ 20 | 1.6 MB | 3.5"2DD/2HDx1 (3mode), 1.25MB RAM Disk, 120M SASI HDD | 0 | 1993/01 | | |
| PC-9801BA/U2 | i486DX2-40 @ 40 | 1.6 MB | 3.5"2DD/2HDx2 | 3 | 1993/01 | | |
| PC-9801BA/U6 | i486DX2-40 @ 40 | 3.6 MB | 3.5"2DD/2HDx1, 40M SASI HDD | 3 | 1993/01 | | |
| PC-9801BA/M2 | i486DX2-40 @ 40 | 1.6 MB | 5"2DD/2HDx2 | 3 | 1993/01 | | |
| PC-9801BX/U2 | i486SX-20 @ 20 | 1.6 MB | 3.5"2DD/2HDx2 | 3 | 1993/01 | | |
| PC-9801BX/U6 | i486SX-20 @ 20 | 3.6 MB | 3.5"2DD/2HDx1, 40M SASI HDD | 3 | 1993/01 | | |
| PC-9801BX/M2 | i486SX-20 @ 20 | 1.6 MB | 5"2DD/2HDx2 | 3 | 1993/01 | | |
| PC-9801NX/C | i486SX(J) @ 20 | 1.6 MB | 3.5"2DD/2HDx1, 1.25MB RAM Disk | 0 | 1993/07 | | |
| PC-9801NX/C120 | i486SX(J) @ 20 | 3.6 MB | 3.5"2DD/2HDx1, 1.25MB RAM Disk | 0 | 1993/07 | | |
| PC-9801P40/D | i486SX(J) @ 20 | 5.6 MB | 40MB IDE HDD | 0 | 1993/07 | | |
| PC-9801P80/W | i486SX(J) @ 20 | 7.6 MB | 80MB IDE HDD | 0 | 1993/07 | | |
| PC-9801P80/P | i486SX(J) @ 20 | 7.6 MB | 80MB IDE HDD | 0 | 1993/07 | | |
| PC-9801BA2/U2 | i486DX2-66 @ 66 | 3.6 MB | 3.5"2DD/2HDx2 | 3 | 1993/11 | | |
| PC-9801BA2/U7 | i486DX2-66 @ 66 | 3.6 MB | 3.5"2DD/2HDx1, 120MB IDE HDD | 3 | 1993/11 | | |
| PC-9801BA2/M2 | i486DX2-66 @ 66 | 3.6 MB | 5"2DD/2HDx2 | 3 | 1993/11 | | |
| PC-9801BS2/U2 | i486SX-33 @ 33 | 3.6 MB | 3.5"2DD/2HDx2 | 3 | 1993/11 | | |
| PC-9801BS2/U7 | i486SX-33 @ 33 | 3.6 MB | 3.5"2DD/2HDx1, 120MB IDE HDD | 3 | 1993/11 | | |
| PC-9801BS2/M2 | i486SX-33 @ 33 | 3.6 MB | 5"2DD/2HDx2 | 3 | 1993/11 | | |
| PC-9801BX2/U2 | i486SX-25 @ 25 | 1.8 MB | 3.5"2DD/2HDx2 | 3 | 1993/11 | | |
| PC-9801BX2/U7 | i486SX-25 @ 25 | 3.6 MB | 3.5"2DD/2HDx1, 120MB IDE HDD | 3 | 1993/11 | | |
| PC-9801BX2/M2 | i486SX-25 @ 25 | 1.8 MB | 5"2DD/2HDx2 | 3 | 1993/11 | | |
| PC-9801BA3/U2 | i486DX-66 @ 66 | 3.6 MB | 3.5"2DD/2HDx2 | 3 | 1995/01 | | |
| PC-9801BA3/U2/W | i486DX-66 @ 66 | 7.6 MB | 3.5"2DD/2HDx2, 210MB IDE HDD | 3 | 1995/01 | | |
| PC-9801BX3/U2 | i486SX-33 @ 33 | 1.6 MB | 3.5"2DD/2HDx2 | 3 | 1995/01 | | |
| PC-9801BX3/U2/W | i486SX-33 @ 33 | 5.6 MB | 3.5"2DD/2HDx2, 210MB IDE HDD | 3 | 1995/01 | | |
| PC-9801BX4/U2 | AMD/i 486DX2-66 @ 66 | 2 MB | 3.5"2DD/2HDx2 | 3 | 1995/07 | | |
| PC-9801BX4/U2/C | AMD/i 486DX2-66 @ 66 | 2 MB | 3.5"2DD/2HDx2, 2xCD-ROM | 3 | 1995/07 | | |
| PC-9801BX4/U2-P | Pentium ODP @ 66 | 2 MB | 3.5"2DD/2HDx2 | 3 | 1995/09 | | |
| PC-9801BX4/U2/C-P | Pentium ODP @ 66 | 2 MB | 3.5"2DD/2HDx2, 2xCD-ROM | 3 | 1995/09 | | |
| For more info (e.g. optional hardware), see http://www.geocities.jp/retro_zzz/machines/nec/9801/mdl98cpu.html | |
| Epson Series | |
| http://www.pc-9800.net/db_epson/desk_index.htm | |
| PC-9821 Series | |
| PC-9821 (1992) - aka 98MULTi, desktop computer, 386 based | |
| PC-9821A series (1993->1994) - aka 98MATE A, desktop computers, 486 based | |
| PC-9821B series (1993) - aka 98MATE B, desktop computers, 486 based | |
| PC-9821C series (1993->1996) - aka 98MULTi CanBe, desktop & tower computers, various CPU | |
| PC-9821Es (1994) - aka 98FINE, desktop computer with integrated LCD, successor of the PC-98T | |
| PC-9821X series (1994->1995) - aka 98MATE X, desktop computers, Pentium based | |
| PC-9821V series (1995) - aka 98MATE Valuestar, desktop computers, Pentium based | |
| PC-9821S series (1995->1996) - aka 98Pro, tower computers, PentiumPro based | |
| PC-9821R series (1996->2000) - aka 98MATE R, desktop & tower & server computers, various CPU | |
| PC-9821C200 (1997) - aka CEREB, desktop computer, Pentium MMX based | |
| PC-9821 Ne/Ns/Np/Nm (1993->1995) - aka 98NOTE, laptops, 486 based | |
| PC-9821 Na/Nb/Nw (1995->1997) - aka 98NOTE Lavie, laptops, Pentium based | |
| PC-9821 Lt/Ld (1995) - aka 98NOTE Light, laptops, 486 based | |
| PC-9821 La/Ls (1995->1997) - aka 98NOTE Aile, laptops, Pentium based | |
| ==== | |
| Documentation notes (for unemulated stuff, courtesy of T. Kodaka and T. Kono): | |
| IDE: | |
| (r/w) | |
| 0x430: IDE drive switch | |
| 0x432: IDE drive switch | |
| 0x435: <unknown> | |
| (ISA correlated i/o) | |
| ---------------------------------------------------------- | |
| 0x0640 |WORD|R/W|Data Register |01F0h | |
| 0x0642 |BYTE| R |Error Register |01F1h | |
| 0x0642 |BYTE| W |Write Precomp Register |01F1h | |
| 0x0644 |BYTE|R/W|Sector Count |01F2h | |
| 0x0646 |BYTE|R/W|Sector Number |01F3h | |
| 0x0648 |BYTE|R/W|Cylinder Low |01F4h | |
| 0x064A |BYTE|R/W|Cylinder High |01F5h | |
| 0x064C |BYTE|R/W|SDH Register |01F6h | |
| 0x064E |BYTE| R |Status Register |01F7h | |
| 0x064E |BYTE| W |Command Register |01F7h | |
| 0x074C |BYTE| R |Alternate Status Register |03F6h | |
| 0x074C |BYTE| W |Digital Output Register |03F6h | |
| 0x074E |BYTE| R |Digital Input Register |03F7h | |
| Video F/F (i/o 0x68): | |
| KAC mode (video ff = 5) is basically how the kanji ROM could be accessed, 1=thru the CG window ports, 0=thru the kanji | |
| window RAM at 0xa4***. | |
| My guess is that the system locks up or doesn't have any data if the wrong port is being accessed. | |
| Ext Video F/F (i/o 0x6a): | |
| 0000 011x enables EGC | |
| 0000 111x enables PC-98GS | |
| 0010 000x enables multicolor (a.k.a. 256 colors mode) | |
| 0010 001x enables 65'536 colors | |
| 0010 010x 64k color palette related (?) | |
| 0010 011x full screen reverse (?) | |
| 0010 100x text and gfxs synthesis (?) | |
| 0010 101x 256 color palette registers fast write (?) | |
| 0010 110x 256 color overscan (?) | |
| 0100 000x (0) CRT (1) Plasma/LCD | |
| 0100 001x text and gfxs right shifted one dot (undocumented behaviour) | |
| 0100 010x hi-res mode in PC-9821 | |
| 0110 000x EEGC mode | |
| 0110 001x VRAM config (0) plain (1) packed | |
| 0110 011x AGDC mode | |
| 0110 100x 480 lines | |
| 0110 110x VRAM bitmap orientation (0) MSB left-to-right LSB (1) LSB left-to-right MSB | |
| 1000 001x CHR GDC clock (0) 2,5 MHz (1) 5 MHz | |
| 1000 010x BMP GDC clock | |
| 1000 111x related to GFX accelerator cards (like Vision864) | |
| 1100 010x chart GDC operating mode (?) | |
| (everything else is undocumented / unknown) | |
| Keyboard TX commands: | |
| 0xfa ACK | |
| 0xfc NACK | |
| 0x95 | |
| ---- --xx extension key settings (00 normal 11 Win and App Keys enabled) | |
| 0x96 identification codes | |
| 0x9c | |
| -xx- ---- key delay (11 = 1000 ms, 10 = 500 ms, 01 = 500 ms, 00 = 250 ms) | |
| ---x xxxx repeat rate (slow 11111 -> 00001 fast) | |
| 0x9d keyboard LED settings | |
| 0x9f keyboard ID | |
| **************************************************************************************************/ | |
| #include "emu.h" | |
| #include "includes/pc9801.h" | |
| #include "machine/input_merger.h" | |
| void pc9801_state::rtc_w(uint8_t data) | |
| { | |
| m_rtc->c0_w((data & 0x01) >> 0); | |
| m_rtc->c1_w((data & 0x02) >> 1); | |
| m_rtc->c2_w((data & 0x04) >> 2); | |
| m_rtc->stb_w((data & 0x08) >> 3); | |
| m_rtc->clk_w((data & 0x10) >> 4); | |
| m_rtc->data_in_w(((data & 0x20) >> 5)); | |
| if(data & 0xc0) | |
| logerror("RTC write to undefined bits %02x\n",data & 0xc0); | |
| } | |
| void pc9801_state::dmapg4_w(offs_t offset, uint8_t data) | |
| { | |
| if(offset < 4) | |
| m_dma_offset[(offset+1) & 3] = data & 0x0f; | |
| } | |
| void pc9801_state::dmapg8_w(offs_t offset, uint8_t data) | |
| { | |
| if(offset == 4) | |
| m_dma_autoinc[data & 3] = (data >> 2) & 3; | |
| else if(offset < 4) | |
| m_dma_offset[(offset+1) & 3] = data; | |
| } | |
| void pc9801_state::nmi_ctrl_w(offs_t offset, uint8_t data) | |
| { | |
| m_nmi_ff = offset; | |
| } | |
| void pc9801_state::vrtc_clear_w(uint8_t data) | |
| { | |
| m_pic1->ir2_w(0); | |
| } | |
| uint8_t pc9801_state::fdc_2hd_ctrl_r() | |
| { | |
| return 0x44; //unknown port meaning 2hd flag? | |
| } | |
| void pc9801_state::fdc_2hd_ctrl_w(uint8_t data) | |
| { | |
| //logerror("%02x ctrl\n",data); | |
| m_fdc_2hd->reset_w(BIT(data, 7)); | |
| m_fdc_2hd_ctrl = data; | |
| if(data & 0x40) | |
| { | |
| m_fdc_2hd->set_ready_line_connected(0); | |
| m_fdc_2hd->ready_w(0); | |
| } | |
| else | |
| m_fdc_2hd->set_ready_line_connected(1); | |
| if(!m_sys_type) // required for 9801f 2hd adapter bios | |
| { | |
| m_fdc_2hd->subdevice<floppy_connector>("0")->get_device()->mon_w(data & 8 ? ASSERT_LINE : CLEAR_LINE); | |
| m_fdc_2hd->subdevice<floppy_connector>("1")->get_device()->mon_w(data & 8 ? ASSERT_LINE : CLEAR_LINE); | |
| } | |
| else if(!(m_fdc_ctrl & 4)) // required for 9821 | |
| { | |
| m_fdc_2hd->subdevice<floppy_connector>("0")->get_device()->mon_w(data & 8 ? CLEAR_LINE : ASSERT_LINE); | |
| m_fdc_2hd->subdevice<floppy_connector>("1")->get_device()->mon_w(data & 8 ? CLEAR_LINE : ASSERT_LINE); | |
| } | |
| } | |
| uint8_t pc9801_state::fdc_2dd_ctrl_r() | |
| { | |
| int ret = (!m_fdc_2dd->subdevice<floppy_connector>("0")->get_device()->ready_r()) ? 0x10 : 0; | |
| ret |= (m_fdc_2dd->subdevice<floppy_connector>("1")->get_device()->ready_r()) ? 0x10 : 0; | |
| return ret | 0x40; //unknown port meaning, might be 0x70 | |
| } | |
| void pc9801_state::fdc_2dd_ctrl_w(uint8_t data) | |
| { | |
| logerror("%02x ctrl\n",data); | |
| m_fdc_2dd->reset_w(BIT(data, 7)); | |
| m_fdc_2dd_ctrl = data; | |
| m_fdc_2dd->subdevice<floppy_connector>("0")->get_device()->mon_w(data & 8 ? CLEAR_LINE : ASSERT_LINE); | |
| m_fdc_2dd->subdevice<floppy_connector>("1")->get_device()->mon_w(data & 8 ? CLEAR_LINE : ASSERT_LINE); | |
| } | |
| uint8_t pc9801_state::ide_ctrl_r() | |
| { | |
| address_space &ram = m_maincpu->space(AS_PROGRAM); | |
| // this makes the ide driver not do 512 to 256 byte sector translation, the 9821 looks for bit 6 of offset 0xac403 of the kanji ram to set this, the rs unknown | |
| ram.write_byte(0x457, ram.read_byte(0x457) | 0xc0); | |
| return m_ide_sel; | |
| } | |
| void pc9801_state::ide_ctrl_w(uint8_t data) | |
| { | |
| if(!(data & 0x80)) | |
| m_ide_sel = data & 1; | |
| } | |
| uint16_t pc9801_state::ide_cs0_r(offs_t offset, uint16_t mem_mask) | |
| { | |
| return m_ide[m_ide_sel]->cs0_r(offset, mem_mask); | |
| } | |
| void pc9801_state::ide_cs0_w(offs_t offset, uint16_t data, uint16_t mem_mask) | |
| { | |
| m_ide[m_ide_sel]->cs0_w(offset, data, mem_mask); | |
| } | |
| uint16_t pc9801_state::ide_cs1_r(offs_t offset, uint16_t mem_mask) | |
| { | |
| return m_ide[m_ide_sel]->cs1_r(offset, mem_mask); | |
| } | |
| void pc9801_state::ide_cs1_w(offs_t offset, uint16_t data, uint16_t mem_mask) | |
| { | |
| m_ide[m_ide_sel]->cs1_w(offset, data, mem_mask); | |
| } | |
| uint8_t pc9801_state::sasi_data_r() | |
| { | |
| uint8_t data = m_sasi_data_in->read(); | |
| if(m_sasi_ctrl_in->read() & 0x80) | |
| m_sasibus->write_ack(1); | |
| return data; | |
| } | |
| void pc9801_state::sasi_data_w(uint8_t data) | |
| { | |
| m_sasi_data = data; | |
| if (m_sasi_data_enable) | |
| { | |
| m_sasi_data_out->write(m_sasi_data); | |
| if(m_sasi_ctrl_in->read() & 0x80) | |
| m_sasibus->write_ack(1); | |
| } | |
| } | |
| WRITE_LINE_MEMBER( pc9801_state::write_sasi_io ) | |
| { | |
| m_sasi_ctrl_in->write_bit2(state); | |
| m_sasi_data_enable = !state; | |
| if (m_sasi_data_enable) | |
| { | |
| m_sasi_data_out->write(m_sasi_data); | |
| } | |
| else | |
| { | |
| m_sasi_data_out->write(0); | |
| } | |
| if((m_sasi_ctrl_in->read() & 0x9C) == 0x8C) | |
| m_pic2->ir1_w(m_sasi_ctrl & 1); | |
| else | |
| m_pic2->ir1_w(0); | |
| } | |
| WRITE_LINE_MEMBER( pc9801_state::write_sasi_req ) | |
| { | |
| m_sasi_ctrl_in->write_bit7(state); | |
| if (!state) | |
| m_sasibus->write_ack(0); | |
| if((m_sasi_ctrl_in->read() & 0x9C) == 0x8C) | |
| m_pic2->ir1_w(m_sasi_ctrl & 1); | |
| else | |
| m_pic2->ir1_w(0); | |
| m_dmac->dreq0_w(!(state && !(m_sasi_ctrl_in->read() & 8) && (m_sasi_ctrl & 2))); | |
| } | |
| uint8_t pc9801_state::sasi_status_r() | |
| { | |
| uint8_t res = 0; | |
| if(m_sasi_ctrl & 0x40) // read status | |
| { | |
| /* | |
| x--- ---- REQ | |
| -x-- ---- ACK | |
| --x- ---- BSY | |
| ---x ---- MSG | |
| ---- x--- CD | |
| ---- -x-- IO | |
| ---- ---x INT? | |
| */ | |
| res |= m_sasi_ctrl_in->read(); | |
| } | |
| else // read drive info | |
| { | |
| /* | |
| xx-- ---- unknown but tested | |
| --xx x--- SASI-1 media type | |
| ---- -xxx SASI-2 media type | |
| */ | |
| //res |= 7 << 3; // read mediatype SASI-1 | |
| //res |= 7; // read mediatype SASI-2 | |
| } | |
| return res; | |
| } | |
| void pc9801_state::sasi_ctrl_w(uint8_t data) | |
| { | |
| /* | |
| x--- ---- channel enable | |
| -x-- ---- read switch | |
| --x- ---- sel | |
| ---- x--- reset line | |
| ---- --x- dma enable | |
| ---- ---x irq enable | |
| */ | |
| m_sasibus->write_sel(BIT(data, 5)); | |
| if(m_sasi_ctrl & 8 && ((data & 8) == 0)) // 1 -> 0 transition | |
| { | |
| m_sasibus->write_rst(1); | |
| // m_timer_rst->adjust(attotime::from_nsec(100)); | |
| } | |
| else | |
| m_sasibus->write_rst(0); // TODO | |
| m_sasi_ctrl = data; | |
| // m_sasibus->write_sel(BIT(data, 0)); | |
| } | |
| uint8_t pc9801_state::f0_r(offs_t offset) | |
| { | |
| if(offset == 0) | |
| { | |
| // iterate thru all devices to check if an AMD98 is present | |
| for (pc9801_amd98_device &amd98 : device_type_enumerator<pc9801_amd98_device>(machine().root_device())) | |
| { | |
| logerror("Read AMD98 ID %s\n",amd98.tag()); | |
| return 0x18; // return the right ID | |
| } | |
| logerror("Read port 0 from 0xf0 (AMD98 check?)\n"); | |
| return 0; // card not present | |
| } | |
| return 0xff; | |
| } | |
| void pc9801_state::pc9801_map(address_map &map) | |
| { | |
| map(0xa0000, 0xa3fff).rw(FUNC(pc9801_state::tvram_r), FUNC(pc9801_state::tvram_w)); //TVRAM | |
| map(0xa8000, 0xbffff).rw(FUNC(pc9801_state::gvram_r), FUNC(pc9801_state::gvram_w)); //bitmap VRAM | |
| // map(0xcc000, 0xcffff).rom().region("sound_bios", 0); //sound BIOS | |
| map(0xd6000, 0xd6fff).rom().region("fdc_bios_2dd", 0); //floppy BIOS 2dd | |
| map(0xd7000, 0xd7fff).rom().region("fdc_bios_2hd", 0); //floppy BIOS 2hd | |
| map(0xe8000, 0xfffff).rom().region("ipl", 0); | |
| } | |
| /* first device is even offsets, second one is odd offsets */ | |
| void pc9801_state::pc9801_common_io(address_map &map) | |
| { | |
| map.unmap_value_high(); | |
| map(0x0000, 0x001f).rw(m_dmac, FUNC(am9517a_device::read), FUNC(am9517a_device::write)).umask16(0xff00); | |
| map(0x0000, 0x001f).rw(FUNC(pc9801_state::pic_r), FUNC(pc9801_state::pic_w)).umask16(0x00ff); // i8259 PIC (bit 3 ON slave / master) / i8237 DMA | |
| map(0x0020, 0x002f).w(FUNC(pc9801_state::rtc_w)).umask16(0x00ff); | |
| map(0x0030, 0x0037).rw(m_ppi_sys, FUNC(i8255_device::read), FUNC(i8255_device::write)).umask16(0xff00); //i8251 RS232c / i8255 system port | |
| map(0x0040, 0x0047).rw(m_ppi_prn, FUNC(i8255_device::read), FUNC(i8255_device::write)).umask16(0x00ff); | |
| map(0x0040, 0x0047).rw(m_keyb, FUNC(pc9801_kbd_device::rx_r), FUNC(pc9801_kbd_device::tx_w)).umask16(0xff00); //i8255 printer port / i8251 keyboard | |
| map(0x0050, 0x0057).rw("ppi8255_fdd", FUNC(i8255_device::read), FUNC(i8255_device::write)).umask16(0xff00); | |
| map(0x0050, 0x0057).w(FUNC(pc9801_state::nmi_ctrl_w)).umask16(0x00ff); // NMI FF / i8255 floppy port (2d?) | |
| map(0x0060, 0x0063).rw(m_hgdc1, FUNC(upd7220_device::read), FUNC(upd7220_device::write)).umask16(0x00ff); //upd7220 character ports / <undefined> | |
| map(0x0064, 0x0064).w(FUNC(pc9801_state::vrtc_clear_w)); | |
| // map(0x006c, 0x006f) border color / <undefined> | |
| map(0x0070, 0x007f).rw(m_pit8253, FUNC(pit8253_device::read), FUNC(pit8253_device::write)).umask16(0xff00); | |
| map(0x0070, 0x007f).rw(FUNC(pc9801_state::txt_scrl_r), FUNC(pc9801_state::txt_scrl_w)).umask16(0x00ff); //display registers / i8253 pit | |
| map(0x0090, 0x0090).r(m_fdc_2hd, FUNC(upd765a_device::msr_r)); | |
| map(0x0092, 0x0092).rw(m_fdc_2hd, FUNC(upd765a_device::fifo_r), FUNC(upd765a_device::fifo_w)); | |
| map(0x0094, 0x0094).rw(FUNC(pc9801_state::fdc_2hd_ctrl_r), FUNC(pc9801_state::fdc_2hd_ctrl_w)); | |
| map(0x0090, 0x0093).rw(m_sio, FUNC(i8251_device::read), FUNC(i8251_device::write)).umask16(0xff00); | |
| map(0x7fd8, 0x7fdf).rw("ppi8255_mouse", FUNC(i8255_device::read), FUNC(i8255_device::write)).umask16(0xff00); | |
| } | |
| void pc9801_state::pc9801_io(address_map &map) | |
| { | |
| pc9801_common_io(map); | |
| map(0x0020, 0x002f).w(FUNC(pc9801_state::dmapg4_w)).umask16(0xff00); | |
| map(0x0068, 0x0068).w(FUNC(pc9801_state::pc9801_video_ff_w)); //mode FF / <undefined> | |
| map(0x0080, 0x0080).rw(FUNC(pc9801_state::sasi_data_r), FUNC(pc9801_state::sasi_data_w)); | |
| map(0x0082, 0x0082).rw(FUNC(pc9801_state::sasi_status_r), FUNC(pc9801_state::sasi_ctrl_w)); | |
| map(0x00a0, 0x00af).rw(FUNC(pc9801_state::pc9801_a0_r), FUNC(pc9801_state::pc9801_a0_w)); //upd7220 bitmap ports / display registers | |
| map(0x00c8, 0x00cb).m(m_fdc_2dd, FUNC(upd765a_device::map)).umask16(0x00ff); | |
| map(0x00cc, 0x00cc).rw(FUNC(pc9801_state::fdc_2dd_ctrl_r), FUNC(pc9801_state::fdc_2dd_ctrl_w)); //upd765a 2dd / <undefined> | |
| map(0x00f0, 0x00ff).r(FUNC(pc9801_state::f0_r)).umask16(0x00ff); | |
| } | |
| /************************************* | |
| * | |
| * PC-9801RS specific handlers (IA-32) | |
| * | |
| ************************************/ | |
| /* TODO: it's possible that the offset calculation is actually linear. */ | |
| /* TODO: having this non-linear makes the system to boot in BASIC for PC-9821. Perhaps it stores settings? How to change these? */ | |
| uint8_t pc9801_state::pc9801rs_knjram_r(offs_t offset) | |
| { | |
| uint32_t pcg_offset; | |
| pcg_offset = (m_font_addr & 0x7fff) << 5; | |
| pcg_offset|= offset & 0x1e; | |
| pcg_offset|= m_font_lr; | |
| if(!(m_font_addr & 0xff)) | |
| { | |
| int char_size = m_video_ff[FONTSEL_REG]; | |
| return m_char_rom[(m_font_addr >> 8) * (8 << char_size) + (char_size * 0x800) + ((offset >> 1) & 0xf)]; | |
| } | |
| /* TODO: investigate on this difference */ | |
| if((m_font_addr & 0xff00) == 0x5600 || (m_font_addr & 0xff00) == 0x5700) | |
| return m_kanji_rom[pcg_offset]; | |
| pcg_offset = (m_font_addr & 0x7fff) << 5; | |
| pcg_offset|= offset & 0x1f; | |
| // pcg_offset|= m_font_lr; | |
| return m_kanji_rom[pcg_offset]; | |
| } | |
| void pc9801_state::pc9801rs_knjram_w(offs_t offset, uint8_t data) | |
| { | |
| uint32_t pcg_offset; | |
| pcg_offset = (m_font_addr & 0x7fff) << 5; | |
| pcg_offset|= offset & 0x1e; | |
| pcg_offset|= m_font_lr; | |
| if((m_font_addr & 0xff00) == 0x5600 || (m_font_addr & 0xff00) == 0x5700) | |
| { | |
| m_kanji_rom[pcg_offset] = data; | |
| m_gfxdecode->gfx(2)->mark_dirty(pcg_offset >> 5); | |
| } | |
| } | |
| /* FF-based */ | |
| void pc9801_state::pc9801rs_bank_w(offs_t offset, uint8_t data) | |
| { | |
| if(offset == 1) | |
| { | |
| if((data & 0xf0) == 0x00 || (data & 0xf0) == 0x10) | |
| { | |
| if((data & 0xed) == 0x00) | |
| { | |
| m_ipl->set_bank((data & 2) >> 1); | |
| return; | |
| } | |
| } | |
| logerror("Unknown EMS ROM setting %02x\n",data); | |
| } | |
| if(offset == 3) | |
| { | |
| if((data & 0xf0) == 0x20) | |
| m_vram_bank = (data & 2) >> 1; | |
| else | |
| { | |
| logerror("Unknown EMS RAM setting %02x\n",data); | |
| } | |
| } | |
| } | |
| uint8_t pc9801_state::a20_ctrl_r(offs_t offset) | |
| { | |
| if(offset == 0x01) | |
| return (m_gate_a20 ^ 1) | 0xfe; | |
| else if(offset == 0x03) | |
| return (m_gate_a20 ^ 1) | (m_nmi_ff << 1); | |
| return f0_r(offset); | |
| } | |
| void pc9801_state::a20_ctrl_w(offs_t offset, uint8_t data) | |
| { | |
| if(offset == 0x00) | |
| { | |
| uint8_t por; | |
| /* reset POR bit */ | |
| // TODO: is there any other way that doesn't involve direct r/w of ppi address? | |
| por = m_ppi_sys->read(2) & ~0x20; | |
| m_ppi_sys->write(2, por); | |
| m_maincpu->set_input_line(INPUT_LINE_A20, CLEAR_LINE); | |
| m_maincpu->pulse_input_line(INPUT_LINE_RESET, attotime::zero); | |
| m_gate_a20 = 0; | |
| } | |
| if(offset == 0x01) | |
| m_gate_a20 = 1; | |
| if(offset == 0x03) | |
| { | |
| if(data == 0x02) | |
| m_gate_a20 = 1; | |
| else if(data == 0x03) | |
| m_gate_a20 = 0; | |
| } | |
| m_maincpu->set_input_line(INPUT_LINE_A20, m_gate_a20); | |
| } | |
| uint8_t pc9801_state::grcg_r(offs_t offset) | |
| { | |
| if(offset == 6) | |
| { | |
| logerror("GRCG mode R\n"); | |
| return 0xff; | |
| } | |
| else if(offset == 7) | |
| { | |
| logerror("GRCG tile R\n"); | |
| return 0xff; | |
| } | |
| return txt_scrl_r(offset); | |
| } | |
| void pc9801_state::grcg_w(offs_t offset, uint8_t data) | |
| { | |
| if(offset == 6) | |
| { | |
| // logerror("%02x GRCG MODE\n",data); | |
| m_grcg.mode = data; | |
| m_grcg.tile_index = 0; | |
| return; | |
| } | |
| else if(offset == 7) | |
| { | |
| // logerror("%02x GRCG TILE %02x\n",data,m_grcg.tile_index); | |
| m_grcg.tile[m_grcg.tile_index] = bitswap<8>(data,0,1,2,3,4,5,6,7); | |
| m_grcg.tile_index ++; | |
| m_grcg.tile_index &= 3; | |
| return; | |
| } | |
| txt_scrl_w(offset,data); | |
| } | |
| void pc9801_state::egc_w(offs_t offset, uint16_t data, uint16_t mem_mask) | |
| { | |
| if(!m_ex_video_ff[2]) | |
| return; | |
| if(!(m_egc.regs[1] & 0x6000) || (offset != 4)) // why? | |
| COMBINE_DATA(&m_egc.regs[offset]); | |
| switch(offset) | |
| { | |
| case 6: | |
| case 7: | |
| m_egc.count = (m_egc.regs[7] & 0xfff) + 1; | |
| m_egc.first = true; | |
| m_egc.init = false; | |
| break; | |
| } | |
| } | |
| uint8_t pc9801_state::fdc_mode_ctrl_r() | |
| { | |
| return (m_fdc_ctrl & 3) | 0xf0 | 8 | 4; | |
| } | |
| void pc9801_state::fdc_mode_ctrl_w(uint8_t data) | |
| { | |
| /* | |
| ---- x--- ready line? | |
| ---- --x- select type (1) 2hd (0) 2dd | |
| ---- ---x select irq | |
| */ | |
| m_fdc_2hd->subdevice<floppy_connector>("0")->get_device()->set_rpm(data & 0x02 ? 360 : 300); | |
| m_fdc_2hd->subdevice<floppy_connector>("1")->get_device()->set_rpm(data & 0x02 ? 360 : 300); | |
| m_fdc_2hd->set_rate(data & 0x02 ? 500000 : 250000); | |
| m_fdc_ctrl = data; | |
| //if(data & 0xfc) | |
| // logerror("FDC ctrl called with %02x\n",data); | |
| } | |
| #if 0 | |
| uint8_t pc9801_state::pc9801rs_2dd_r() | |
| { | |
| // if(m_fdc_ctrl & 1) | |
| // return 0xff; | |
| if((offset & 1) == 0) | |
| { | |
| switch(offset & 6) | |
| { | |
| case 0: return m_fdc_2hd->msr_r(); | |
| case 2: return m_fdc_2hd->fifo_r(); | |
| case 4: return 0x44; //2dd flag | |
| } | |
| } | |
| logerror("Read to undefined port [%02x]\n",offset+0x90); | |
| return 0xff; | |
| } | |
| void pc9801_state::pc9801rs_2dd_w(uint8_t data) | |
| { | |
| // if(m_fdc_ctrl & 1) | |
| // return; | |
| if((offset & 1) == 0) | |
| { | |
| switch(offset & 6) | |
| { | |
| case 2: m_fdc_2hd->fifo_w(data); return; | |
| case 4: logerror("%02x 2DD FDC ctrl\n",data); return; | |
| } | |
| } | |
| logerror("Write to undefined port [%02x] %02x\n",offset+0x90,data); | |
| } | |
| #endif | |
| void pc9801_state::pc9801rs_video_ff_w(offs_t offset, uint8_t data) | |
| { | |
| if(offset == 1) | |
| { | |
| if((data & 0xf0) == 0) /* disable any PC-9821 specific HW regs */ | |
| m_ex_video_ff[(data & 0xfe) >> 1] = data & 1; | |
| if(0) | |
| { | |
| static const char *const ex_video_ff_regnames[] = | |
| { | |
| "16 colors mode", // 0 | |
| "<unknown>", // 1 | |
| "EGC related", // 2 | |
| "<unknown>" // 3 | |
| }; | |
| logerror("Write to extended video FF register %s -> %02x\n",ex_video_ff_regnames[(data & 0x06) >> 1],data & 1); | |
| } | |
| //else | |
| // logerror("Write to extended video FF register %02x\n",data); | |
| return; | |
| } | |
| pc9801_video_ff_w(data); | |
| } | |
| void pc9801_state::pc9801rs_a0_w(offs_t offset, uint8_t data) | |
| { | |
| if((offset & 1) == 0 && offset & 8 && m_ex_video_ff[ANALOG_16_MODE]) | |
| { | |
| switch(offset) | |
| { | |
| case 0x08: m_analog16.pal_entry = data & 0xf; break; | |
| case 0x0a: m_analog16.g[m_analog16.pal_entry] = data & 0xf; break; | |
| case 0x0c: m_analog16.r[m_analog16.pal_entry] = data & 0xf; break; | |
| case 0x0e: m_analog16.b[m_analog16.pal_entry] = data & 0xf; break; | |
| } | |
| m_palette->set_pen_color( | |
| m_analog16.pal_entry + 0x10, | |
| pal4bit(m_analog16.r[m_analog16.pal_entry]), | |
| pal4bit(m_analog16.g[m_analog16.pal_entry]), | |
| pal4bit(m_analog16.b[m_analog16.pal_entry]) | |
| ); | |
| return; | |
| } | |
| pc9801_a0_w(offset,data); | |
| } | |
| uint8_t pc9801_state::access_ctrl_r(offs_t offset) | |
| { | |
| if(offset == 1) | |
| return m_access_ctrl; | |
| return 0xff; | |
| } | |
| void pc9801_state::access_ctrl_w(offs_t offset, uint8_t data) | |
| { | |
| if(offset == 1) | |
| m_access_ctrl = data; | |
| } | |
| void pc9801_state::pc9801rs_mouse_freq_w(offs_t offset, uint8_t data) | |
| { | |
| /* TODO: bit 3 used */ | |
| if(offset == 3) | |
| { | |
| m_mouse.freq_reg = data & 3; | |
| m_mouse.freq_index = 0; | |
| } | |
| } | |
| uint8_t pc9801_state::midi_r() | |
| { | |
| /* unconnect, needed by Amaranth KH to boot */ | |
| return 0xff; | |
| } | |
| uint8_t pc9801_state::pic_r(offs_t offset) | |
| { | |
| return ((offset >= 4) ? m_pic2 : m_pic1)->read(offset & 3); | |
| } | |
| void pc9801_state::pic_w(offs_t offset, uint8_t data) | |
| { | |
| ((offset >= 4) ? m_pic2 : m_pic1)->write(offset & 3, data); | |
| } | |
| uint16_t pc9801_state::grcg_gvram_r(offs_t offset, uint16_t mem_mask) | |
| { | |
| uint16_t ret = upd7220_grcg_r((offset + 0x4000) | (m_vram_bank << 16), mem_mask); | |
| return bitswap<16>(ret,8,9,10,11,12,13,14,15,0,1,2,3,4,5,6,7); | |
| } | |
| void pc9801_state::grcg_gvram_w(offs_t offset, uint16_t data, uint16_t mem_mask) | |
| { | |
| data = bitswap<16>(data,8,9,10,11,12,13,14,15,0,1,2,3,4,5,6,7); | |
| upd7220_grcg_w((offset + 0x4000) | (m_vram_bank << 16), data, mem_mask); | |
| } | |
| uint16_t pc9801_state::grcg_gvram0_r(offs_t offset, uint16_t mem_mask) | |
| { | |
| uint16_t ret = upd7220_grcg_r(offset | (m_vram_bank << 16), mem_mask); | |
| return bitswap<16>(ret,8,9,10,11,12,13,14,15,0,1,2,3,4,5,6,7); | |
| } | |
| void pc9801_state::grcg_gvram0_w(offs_t offset, uint16_t data, uint16_t mem_mask) | |
| { | |
| data = bitswap<16>(data,8,9,10,11,12,13,14,15,0,1,2,3,4,5,6,7); | |
| upd7220_grcg_w(offset | (m_vram_bank << 16), data, mem_mask); | |
| } | |
| void pc9801_state::ipl_bank(address_map &map) | |
| { | |
| map(0x00000, 0x2ffff).rom().region("ipl", 0); | |
| } | |
| void pc9801_state::pc9801ux_map(address_map &map) | |
| { | |
| map(0x0a0000, 0x0a3fff).rw(FUNC(pc9801_state::tvram_r), FUNC(pc9801_state::tvram_w)); | |
| map(0x0a4000, 0x0a4fff).rw(FUNC(pc9801_state::pc9801rs_knjram_r), FUNC(pc9801_state::pc9801rs_knjram_w)); | |
| map(0x0a8000, 0x0bffff).rw(FUNC(pc9801_state::grcg_gvram_r), FUNC(pc9801_state::grcg_gvram_w)); | |
| map(0x0e0000, 0x0e7fff).rw(FUNC(pc9801_state::grcg_gvram0_r), FUNC(pc9801_state::grcg_gvram0_w)); | |
| map(0x0e8000, 0x0fffff).m(m_ipl, FUNC(address_map_bank_device::amap16)); | |
| } | |
| void pc9801_state::pc9801ux_io(address_map &map) | |
| { | |
| map.unmap_value_high(); | |
| pc9801_common_io(map); | |
| map(0x0020, 0x002f).w(FUNC(pc9801_state::dmapg8_w)).umask16(0xff00); | |
| map(0x0050, 0x0057).noprw(); // 2dd ppi? | |
| map(0x005c, 0x005f).r(FUNC(pc9801_state::timestamp_r)).nopw(); // artic | |
| map(0x0068, 0x006b).w(FUNC(pc9801_state::pc9801rs_video_ff_w)).umask16(0x00ff); //mode FF / <undefined> | |
| map(0x0070, 0x007f).rw(FUNC(pc9801_state::grcg_r), FUNC(pc9801_state::grcg_w)).umask16(0x00ff); //display registers "GRCG" / i8253 pit | |
| map(0x00a0, 0x00af).rw(FUNC(pc9801_state::pc9801_a0_r), FUNC(pc9801_state::pc9801rs_a0_w)); //upd7220 bitmap ports / display registers | |
| map(0x00bc, 0x00bf).rw(FUNC(pc9801_state::fdc_mode_ctrl_r), FUNC(pc9801_state::fdc_mode_ctrl_w)); | |
| map(0x00c8, 0x00cb).m(m_fdc_2hd, FUNC(upd765a_device::map)).umask16(0x00ff); | |
| map(0x00cc, 0x00cc).rw(FUNC(pc9801_state::fdc_2hd_ctrl_r), FUNC(pc9801_state::fdc_2hd_ctrl_w)); | |
| map(0x00f0, 0x00ff).rw(FUNC(pc9801_state::a20_ctrl_r), FUNC(pc9801_state::a20_ctrl_w)).umask16(0x00ff); | |
| map(0x0438, 0x043b).rw(FUNC(pc9801_state::access_ctrl_r), FUNC(pc9801_state::access_ctrl_w)); | |
| map(0x043c, 0x043f).w(FUNC(pc9801_state::pc9801rs_bank_w)); //ROM/RAM bank | |
| map(0x04a0, 0x04af).w(FUNC(pc9801_state::egc_w)); | |
| map(0x3fd8, 0x3fdf).rw(m_pit8253, FUNC(pit8253_device::read), FUNC(pit8253_device::write)).umask16(0xff00); | |
| } | |
| void pc9801_state::pc9801rs_map(address_map &map) | |
| { | |
| pc9801ux_map(map); | |
| // map(0x0d8000, 0x0d9fff).rom().region("ide",0); | |
| map(0x0da000, 0x0dbfff).ram(); // ide ram | |
| map(0xee8000, 0xefffff).m(m_ipl, FUNC(address_map_bank_device::amap16)); | |
| map(0xfe8000, 0xffffff).m(m_ipl, FUNC(address_map_bank_device::amap16)); | |
| } | |
| void pc9801_state::pc9801rs_io(address_map &map) | |
| { | |
| map.unmap_value_high(); | |
| pc9801ux_io(map); | |
| map(0x0430, 0x0433).rw(FUNC(pc9801_state::ide_ctrl_r), FUNC(pc9801_state::ide_ctrl_w)).umask16(0x00ff); | |
| map(0x0640, 0x064f).rw(FUNC(pc9801_state::ide_cs0_r), FUNC(pc9801_state::ide_cs0_w)); | |
| map(0x0740, 0x074f).rw(FUNC(pc9801_state::ide_cs1_r), FUNC(pc9801_state::ide_cs1_w)); | |
| map(0x1e8c, 0x1e8f).noprw(); // temp | |
| map(0xbfd8, 0xbfdf).w(FUNC(pc9801_state::pc9801rs_mouse_freq_w)); | |
| map(0xe0d0, 0xe0d3).r(FUNC(pc9801_state::midi_r)); | |
| } | |
| /************************************* | |
| * | |
| * PC-9821 specific handlers | |
| * | |
| ************************************/ | |
| void pc9801_state::pc9821_video_ff_w(offs_t offset, uint8_t data) | |
| { | |
| if(offset == 1) | |
| { | |
| if(((data & 0xfe) == 4) && !m_ex_video_ff[3]) // TODO: many other settings are protected | |
| return; | |
| m_ex_video_ff[(data & 0xfe) >> 1] = data & 1; | |
| //if((data & 0xfe) == 0x20) | |
| // logerror("%02x\n",data & 1); | |
| } | |
| /* Intentional fall-through */ | |
| pc9801rs_video_ff_w(offset,data); | |
| } | |
| uint8_t pc9801_state::pc9821_a0_r(offs_t offset) | |
| { | |
| if((offset & 1) == 0 && offset & 8) | |
| { | |
| if(m_ex_video_ff[ANALOG_256_MODE]) | |
| { | |
| logerror("256 color mode [%02x] R\n",offset); | |
| return 0; | |
| } | |
| else if(m_ex_video_ff[ANALOG_16_MODE]) //16 color mode, readback possible there | |
| { | |
| uint8_t res = 0; | |
| switch(offset) | |
| { | |
| case 0x08: res = m_analog16.pal_entry & 0xf; break; | |
| case 0x0a: res = m_analog16.g[m_analog16.pal_entry] & 0xf; break; | |
| case 0x0c: res = m_analog16.r[m_analog16.pal_entry] & 0xf; break; | |
| case 0x0e: res = m_analog16.b[m_analog16.pal_entry] & 0xf; break; | |
| } | |
| return res; | |
| } | |
| } | |
| return pc9801_a0_r(offset); | |
| } | |
| void pc9801_state::pc9821_a0_w(offs_t offset, uint8_t data) | |
| { | |
| if((offset & 1) == 0 && offset & 8 && m_ex_video_ff[ANALOG_256_MODE]) | |
| { | |
| switch(offset) | |
| { | |
| case 0x08: m_analog256.pal_entry = data & 0xff; break; | |
| case 0x0a: m_analog256.g[m_analog256.pal_entry] = data & 0xff; break; | |
| case 0x0c: m_analog256.r[m_analog256.pal_entry] = data & 0xff; break; | |
| case 0x0e: m_analog256.b[m_analog256.pal_entry] = data & 0xff; break; | |
| } | |
| m_palette->set_pen_color( | |
| m_analog256.pal_entry + 0x20, | |
| m_analog256.r[m_analog256.pal_entry], | |
| m_analog256.g[m_analog256.pal_entry], | |
| m_analog256.b[m_analog256.pal_entry] | |
| ); | |
| return; | |
| } | |
| pc9801rs_a0_w(offset,data); | |
| } | |
| uint8_t pc9801_state::window_bank_r(offs_t offset) | |
| { | |
| if(offset == 1) | |
| return m_pc9821_window_bank & 0xfe; | |
| return 0xff; | |
| } | |
| void pc9801_state::window_bank_w(offs_t offset, uint8_t data) | |
| { | |
| if(offset == 1) | |
| m_pc9821_window_bank = data & 0xfe; | |
| else | |
| logerror("PC-9821 $f0000 window bank %02x\n",data); | |
| } | |
| uint8_t pc9801_state::m_sdip_read(uint16_t port, uint8_t sdip_offset) | |
| { | |
| if(port == 2) | |
| return m_sdip[sdip_offset]; | |
| logerror("Warning: read from unknown SDIP area %02x %04x\n",port,0x841c + port + (sdip_offset % 12)*0x100); | |
| return 0xff; | |
| } | |
| void pc9801_state::m_sdip_write(uint16_t port, uint8_t sdip_offset,uint8_t data) | |
| { | |
| if(port == 2) | |
| { | |
| m_sdip[sdip_offset] = data; | |
| return; | |
| } | |
| logerror("Warning: write from unknown SDIP area %02x %04x %02x\n",port,0x841c + port + (sdip_offset % 12)*0x100,data); | |
| } | |
| uint8_t pc9801_state::sdip_0_r(offs_t offset) { return m_sdip_read(offset, 0+m_sdip_bank*12); } | |
| uint8_t pc9801_state::sdip_1_r(offs_t offset) { return m_sdip_read(offset, 1+m_sdip_bank*12); } | |
| uint8_t pc9801_state::sdip_2_r(offs_t offset) { return m_sdip_read(offset, 2+m_sdip_bank*12); } | |
| uint8_t pc9801_state::sdip_3_r(offs_t offset) { return m_sdip_read(offset, 3+m_sdip_bank*12); } | |
| uint8_t pc9801_state::sdip_4_r(offs_t offset) { return m_sdip_read(offset, 4+m_sdip_bank*12); } | |
| uint8_t pc9801_state::sdip_5_r(offs_t offset) { return m_sdip_read(offset, 5+m_sdip_bank*12); } | |
| uint8_t pc9801_state::sdip_6_r(offs_t offset) { return m_sdip_read(offset, 6+m_sdip_bank*12); } | |
| uint8_t pc9801_state::sdip_7_r(offs_t offset) { return m_sdip_read(offset, 7+m_sdip_bank*12); } | |
| uint8_t pc9801_state::sdip_8_r(offs_t offset) { return m_sdip_read(offset, 8+m_sdip_bank*12); } | |
| uint8_t pc9801_state::sdip_9_r(offs_t offset) { return m_sdip_read(offset, 9+m_sdip_bank*12); } | |
| uint8_t pc9801_state::sdip_a_r(offs_t offset) { return m_sdip_read(offset, 10+m_sdip_bank*12); } | |
| uint8_t pc9801_state::sdip_b_r(offs_t offset) { return m_sdip_read(offset, 11+m_sdip_bank*12); } | |
| void pc9801_state::sdip_0_w(offs_t offset, uint8_t data) { m_sdip_write(offset,0+m_sdip_bank*12,data); } | |
| void pc9801_state::sdip_1_w(offs_t offset, uint8_t data) { m_sdip_write(offset,1+m_sdip_bank*12,data); } | |
| void pc9801_state::sdip_2_w(offs_t offset, uint8_t data) { m_sdip_write(offset,2+m_sdip_bank*12,data); } | |
| void pc9801_state::sdip_3_w(offs_t offset, uint8_t data) { m_sdip_write(offset,3+m_sdip_bank*12,data); } | |
| void pc9801_state::sdip_4_w(offs_t offset, uint8_t data) { m_sdip_write(offset,4+m_sdip_bank*12,data); } | |
| void pc9801_state::sdip_5_w(offs_t offset, uint8_t data) { m_sdip_write(offset,5+m_sdip_bank*12,data); } | |
| void pc9801_state::sdip_6_w(offs_t offset, uint8_t data) { m_sdip_write(offset,6+m_sdip_bank*12,data); } | |
| void pc9801_state::sdip_7_w(offs_t offset, uint8_t data) { m_sdip_write(offset,7+m_sdip_bank*12,data); } | |
| void pc9801_state::sdip_8_w(offs_t offset, uint8_t data) { m_sdip_write(offset,8+m_sdip_bank*12,data); } | |
| void pc9801_state::sdip_9_w(offs_t offset, uint8_t data) { m_sdip_write(offset,9+m_sdip_bank*12,data); } | |
| void pc9801_state::sdip_a_w(offs_t offset, uint8_t data) { m_sdip_write(offset,10+m_sdip_bank*12,data); } | |
| void pc9801_state::sdip_b_w(offs_t offset, uint8_t data) | |
| { | |
| if(offset == 3) | |
| m_sdip_bank = (data & 0x40) >> 6; | |
| if(offset == 2) | |
| m_sdip_write(offset,11+m_sdip_bank*12,data); | |
| if((offset & 2) == 0) | |
| logerror("SDIP area B write %02x %02x\n",offset,data); | |
| } | |
| uint16_t pc9801_state::timestamp_r(offs_t offset) | |
| { | |
| return (m_maincpu->total_cycles() >> (16 * offset)); | |
| } | |
| /* basically a read-back of various registers */ | |
| // bit 1: GDC clock select (port 0x6a, selects with 0x84 & bit 0) | |
| // bit 0: current setting | |
| uint8_t pc9801_state::ext2_video_ff_r() | |
| { | |
| uint8_t res; | |
| res = 0; | |
| switch(m_ext2_ff) | |
| { | |
| // case 0x00: ? | |
| // case 0x01: 200 line color / b&w mode (i/o 0x68 -> 0x02) | |
| // case 0x02: Odd-numbered raster mask (i/o 0x68 -> 0x08) | |
| case 0x03: res = m_video_ff[DISPLAY_REG]; break; // display reg | |
| // case 0x04: palette mode (i/o 0x6a -> 0x00) | |
| // case 0x05: GDC sync mode (i/o 0x6a -> 0x40) | |
| // case 0x06: unknown (i/o 0x6a -> 0x44) | |
| // case 0x07: EGC compatibility mode (i/o 0x6a -> 0x04) | |
| // case 0x08: Protected mode f/f (i/o 0x6a -> 0x06) | |
| // case 0x09: GDC clock #0 (i/o 0x6a -> 0x82) | |
| case 0x0a: res = m_ex_video_ff[ANALOG_256_MODE]; break; // 256 color mode | |
| // case 0x0b: VRAM access mode (i/o 0x6a -> 0x62) | |
| // case 0x0c: unknown | |
| // case 0x0d: VRAM boundary mode (i/o 0x6a -> 0x68) | |
| // case 0x0e: 65536 color GFX mode (i/o 0x6a -> 0x22) | |
| // case 0x0f: 65,536 color palette mode (i/o 0x6a -> 0x24) | |
| // case 0x10: unknown (i/o 0x6a -> 0x6a) | |
| // case 0x11: Reverse mode related (i/o 0x6a -> 0x26) | |
| // case 0x12: 256 color overscan color (i/o 0x6a -> 0x2c) | |
| // case 0x13: Reverse mode related (i/o 0x6a -> 0x28) | |
| // case 0x14: AGDC Drawing processor selection (i/o 0x6a -> 0x66) | |
| // case 0x15: unknown (i/o 0x6a -> 0x60) | |
| // case 0x16: unknown (i/o 0x6a -> 0xc2) | |
| // case 0x17: bitmap config direction (i/o 0x6a -> 0x6c) | |
| // case 0x18: High speed palette write (i/o 0x6a -> 0x2a) | |
| // case 0x19: unknown (i/o 0x6a -> 0x48) | |
| // case 0x1a: unknown (i/o 0x6a -> 0xc8) | |
| // case 0x1b: unknown (i/o 0x6a -> 0x2e) | |
| // case 0x1c: unknown (i/o 0x6a -> 0x6e) | |
| // case 0x1d: unknown (i/o 0x6a -> 0xc0) | |
| // case 0x1e: unknown (i/o 0x6a -> 0x80 or 0x46?) | |
| // case 0x1f: unknown (i/o 0x6a -> 0x08) | |
| default: | |
| if(m_ext2_ff < 0x20) | |
| popmessage("PC-9821: read ext2 f/f with value %02x",m_ext2_ff); | |
| break; | |
| } | |
| res|= (m_ex_video_ff[GDC_IS_5MHz] << 1); | |
| return res; | |
| } | |
| void pc9801_state::ext2_video_ff_w(uint8_t data) | |
| { | |
| m_ext2_ff = data; | |
| } | |
| /*uint8_t pc9801_state::winram_r(offs_t offset) | |
| { | |
| offset = (offset & 0x1ffff) | (m_pc9821_window_bank & 0xfe) * 0x10000; | |
| return | |
| } | |
| void pc9801_state::winram_w(offs_t offset, uint8_t data) | |
| { | |
| offset = (offset & 0x1ffff) | (m_pc9821_window_bank & 0xfe) * 0x10000; | |
| }*/ | |
| // TODO: analog 256 mode needs HW tests | |
| uint16_t pc9801_state::pc9821_grcg_gvram_r(offs_t offset, uint16_t mem_mask) | |
| { | |
| if(m_ex_video_ff[ANALOG_256_MODE]) | |
| { | |
| u16 *ext_gvram = (u16 *)m_ext_gvram.target(); | |
| int bank = offset >> 14; | |
| if(bank <= 1) | |
| return ext_gvram[((m_analog256.bank[bank])*0x4000) + (offset & 0x3fff)]; | |
| return 0xffff; | |
| } | |
| return grcg_gvram_r(offset, mem_mask); | |
| } | |
| void pc9801_state::pc9821_grcg_gvram_w(offs_t offset, uint16_t data, uint16_t mem_mask) | |
| { | |
| if(m_ex_video_ff[ANALOG_256_MODE]) | |
| { | |
| u16 *ext_gvram = (u16 *)m_ext_gvram.target(); | |
| int bank = offset >> 14; | |
| if(bank <= 1) | |
| COMBINE_DATA(&ext_gvram[((m_analog256.bank[bank])*0x4000) + (offset & 0x3fff)]); | |
| return; | |
| } | |
| grcg_gvram_w(offset,data,mem_mask); | |
| } | |
| uint16_t pc9801_state::pc9821_grcg_gvram0_r(offs_t offset, uint16_t mem_mask) | |
| { | |
| if(m_ex_video_ff[ANALOG_256_MODE]) | |
| { | |
| switch(offset*2) | |
| { | |
| case 4: return m_analog256.bank[0]; | |
| case 6: return m_analog256.bank[1]; | |
| } | |
| //return 0; | |
| } | |
| return grcg_gvram0_r(offset, mem_mask); | |
| } | |
| void pc9801_state::pc9821_grcg_gvram0_w(offs_t offset, uint16_t data, uint16_t mem_mask) | |
| { | |
| if(m_ex_video_ff[ANALOG_256_MODE]) | |
| { | |
| //printf("%08x %08x\n",offset*2,data); | |
| if(mem_mask & 0xff) | |
| { | |
| switch(offset*2) | |
| { | |
| case 4: m_analog256.bank[0] = data & 0xf; break; | |
| case 6: m_analog256.bank[1] = data & 0xf; break; | |
| } | |
| } | |
| return; | |
| } | |
| grcg_gvram0_w(offset,data,mem_mask); | |
| } | |
| void pc9801_state::pc9821_map(address_map &map) | |
| { | |
| //map(0x00080000, 0x0009ffff).rw(FUNC(pc9801_state::winram_r), FUNC(pc9801_state::winram_w)) | |
| map(0x000a0000, 0x000a3fff).rw(FUNC(pc9801_state::tvram_r), FUNC(pc9801_state::tvram_w)); | |
| map(0x000a4000, 0x000a4fff).rw(FUNC(pc9801_state::pc9801rs_knjram_r), FUNC(pc9801_state::pc9801rs_knjram_w)); | |
| map(0x000a8000, 0x000bffff).rw(FUNC(pc9801_state::pc9821_grcg_gvram_r), FUNC(pc9801_state::pc9821_grcg_gvram_w)); | |
| // map(0x000cc000, 0x000cffff).rom().region("sound_bios", 0); //sound BIOS | |
| // map(0x000d8000, 0x000d9fff).rom().region("ide",0) | |
| map(0x000da000, 0x000dbfff).ram(); // ide ram | |
| map(0x000e0000, 0x000e7fff).rw(FUNC(pc9801_state::pc9821_grcg_gvram0_r), FUNC(pc9801_state::pc9821_grcg_gvram0_w)); | |
| map(0x000e8000, 0x000fffff).m(m_ipl, FUNC(address_map_bank_device::amap16)); | |
| map(0x00f00000, 0x00f9ffff).ram().share("ext_gvram"); | |
| map(0xffee8000, 0xffefffff).m(m_ipl, FUNC(address_map_bank_device::amap16)); | |
| map(0xfff00000, 0xfff9ffff).ram().share("ext_gvram"); | |
| map(0xfffe8000, 0xffffffff).m(m_ipl, FUNC(address_map_bank_device::amap16)); | |
| } | |
| void pc9801_state::pc9821_io(address_map &map) | |
| { | |
| // map.unmap_value_high(); // TODO: a read to somewhere makes this to fail at POST | |
| map(0x0000, 0x001f).rw(m_dmac, FUNC(am9517a_device::read), FUNC(am9517a_device::write)).umask32(0xff00ff00); | |
| map(0x0000, 0x001f).lr8(NAME([this] (offs_t o) { return BIT(o, 1) ? 0xff : pic_r(o); })).umask32(0x00ff00ff); | |
| map(0x0000, 0x001f).w(FUNC(pc9801_state::pic_w)).umask32(0x00ff00ff); // i8259 PIC (bit 3 ON slave / master) / i8237 DMA | |
| map(0x0020, 0x002f).w(FUNC(pc9801_state::rtc_w)).umask32(0x000000ff); | |
| map(0x0020, 0x002f).w(FUNC(pc9801_state::dmapg8_w)).umask32(0xff00ff00); | |
| map(0x0030, 0x0037).rw(m_ppi_sys, FUNC(i8255_device::read), FUNC(i8255_device::write)).umask32(0xff00ff00); //i8251 RS232c / i8255 system port | |
| map(0x0040, 0x0047).rw(m_ppi_prn, FUNC(i8255_device::read), FUNC(i8255_device::write)).umask32(0x00ff00ff); | |
| map(0x0040, 0x0047).rw(m_keyb, FUNC(pc9801_kbd_device::rx_r), FUNC(pc9801_kbd_device::tx_w)).umask32(0xff00ff00); //i8255 printer port / i8251 keyboard | |
| map(0x0050, 0x0053).w(FUNC(pc9801_state::nmi_ctrl_w)).umask32(0x00ff00ff); | |
| map(0x005c, 0x005f).r(FUNC(pc9801_state::timestamp_r)).nopw(); // artic | |
| map(0x0060, 0x0063).rw(m_hgdc1, FUNC(upd7220_device::read), FUNC(upd7220_device::write)).umask32(0x00ff00ff); //upd7220 character ports / <undefined> | |
| map(0x0060, 0x0063).r(FUNC(pc9801_state::unk_r)).umask32(0xff00ff00); // mouse related (unmapped checking for AT keyb controller\PS/2 mouse?) | |
| map(0x0064, 0x0064).w(FUNC(pc9801_state::vrtc_clear_w)); | |
| map(0x0068, 0x006b).w(FUNC(pc9801_state::pc9821_video_ff_w)).umask32(0x00ff00ff); //mode FF / <undefined> | |
| map(0x0070, 0x007f).rw(m_pit8253, FUNC(pit8253_device::read), FUNC(pit8253_device::write)).umask32(0xff00ff00); | |
| map(0x0070, 0x007f).rw(FUNC(pc9801_state::grcg_r), FUNC(pc9801_state::grcg_w)).umask32(0x00ff00ff); //display registers "GRCG" / i8253 pit | |
| map(0x0090, 0x0093).m(m_fdc_2hd, FUNC(upd765a_device::map)).umask32(0x00ff00ff); | |
| map(0x0094, 0x0094).rw(FUNC(pc9801_state::fdc_2hd_ctrl_r), FUNC(pc9801_state::fdc_2hd_ctrl_w)); | |
| map(0x00a0, 0x00af).rw(FUNC(pc9801_state::pc9821_a0_r), FUNC(pc9801_state::pc9821_a0_w)); //upd7220 bitmap ports / display registers | |
| // map(0x00b0, 0x00b3) PC9861k (serial port?) | |
| // map(0x00b9, 0x00b9) PC9861k | |
| // map(0x00bb, 0x00bb) PC9861k | |
| map(0x00bc, 0x00bf).rw(FUNC(pc9801_state::fdc_mode_ctrl_r), FUNC(pc9801_state::fdc_mode_ctrl_w)); | |
| map(0x00c8, 0x00cb).m(m_fdc_2hd, FUNC(upd765a_device::map)).umask32(0x00ff00ff); | |
| map(0x00cc, 0x00cc).rw(FUNC(pc9801_state::fdc_2hd_ctrl_r), FUNC(pc9801_state::fdc_2hd_ctrl_w)); | |
| // map(0x00d8, 0x00df) AMD98 (sound?) board | |
| map(0x00f0, 0x00ff).rw(FUNC(pc9801_state::a20_ctrl_r), FUNC(pc9801_state::a20_ctrl_w)).umask32(0x00ff00ff); | |
| // map(0x0188, 0x018f).rw(FUNC(pc9801_state::pc9801_opn_r), FUNC(pc9801_state::pc9801_opn_w)); //ym2203 opn / <undefined> | |
| // map(0x018c, 0x018f) YM2203 OPN extended ports / <undefined> | |
| map(0x0430, 0x0433).rw(FUNC(pc9801_state::ide_ctrl_r), FUNC(pc9801_state::ide_ctrl_w)).umask32(0x00ff00ff); | |
| map(0x0438, 0x043b).rw(FUNC(pc9801_state::access_ctrl_r), FUNC(pc9801_state::access_ctrl_w)); | |
| // map(0x043d, 0x043d) ROM/RAM bank (NEC) | |
| map(0x043c, 0x043f).w(FUNC(pc9801_state::pc9801rs_bank_w)); //ROM/RAM bank (EPSON) | |
| map(0x0460, 0x0463).rw(FUNC(pc9801_state::window_bank_r), FUNC(pc9801_state::window_bank_w)); | |
| map(0x04a0, 0x04af).w(FUNC(pc9801_state::egc_w)); | |
| // map(0x04be, 0x04be) FDC "RPM" register | |
| map(0x0640, 0x064f).rw(FUNC(pc9801_state::ide_cs0_r), FUNC(pc9801_state::ide_cs0_w)); | |
| map(0x0740, 0x074f).rw(FUNC(pc9801_state::ide_cs1_r), FUNC(pc9801_state::ide_cs1_w)); | |
| // map(0x08e0, 0x08ea) <undefined> / EMM SIO registers | |
| map(0x09a0, 0x09a0).rw(FUNC(pc9801_state::ext2_video_ff_r), FUNC(pc9801_state::ext2_video_ff_w)); // GDC extended register r/w | |
| // map(0x09a8, 0x09a8) GDC 31KHz register r/w | |
| // map(0x0c07, 0x0c07) EPSON register w | |
| // map(0x0c03, 0x0c03) EPSON register 0 r | |
| // map(0x0c13, 0x0c14) EPSON register 1 r | |
| // map(0x0c24, 0x0c24) cs4231 PCM board register control | |
| // map(0x0c2b, 0x0c2b) cs4231 PCM board low byte control | |
| // map(0x0c2d, 0x0c2d) cs4231 PCM board hi byte control | |
| // map(0x0cc0, 0x0cc7) SCSI interface / <undefined> | |
| // map(0x0cfc, 0x0cff) PCI bus | |
| map(0x1e8c, 0x1e8f).noprw(); // IDE RAM switch | |
| map(0x2ed0, 0x2edf).lr8(NAME([] (address_space &s, offs_t o, u8 mm) { return 0xff; })).umask32(0xffffffff); // unknown sound related | |
| map(0x3fd8, 0x3fdf).rw(m_pit8253, FUNC(pit8253_device::read), FUNC(pit8253_device::write)).umask32(0xff00ff00); // <undefined> / pit mirror ports | |
| map(0x7fd8, 0x7fdf).rw("ppi8255_mouse", FUNC(i8255_device::read), FUNC(i8255_device::write)).umask32(0xff00ff00); | |
| map(0x841c, 0x841f).rw(FUNC(pc9801_state::sdip_0_r), FUNC(pc9801_state::sdip_0_w)); | |
| map(0x851c, 0x851f).rw(FUNC(pc9801_state::sdip_1_r), FUNC(pc9801_state::sdip_1_w)); | |
| map(0x861c, 0x861f).rw(FUNC(pc9801_state::sdip_2_r), FUNC(pc9801_state::sdip_2_w)); | |
| map(0x871c, 0x871f).rw(FUNC(pc9801_state::sdip_3_r), FUNC(pc9801_state::sdip_3_w)); | |
| map(0x881c, 0x881f).rw(FUNC(pc9801_state::sdip_4_r), FUNC(pc9801_state::sdip_4_w)); | |
| map(0x891c, 0x891f).rw(FUNC(pc9801_state::sdip_5_r), FUNC(pc9801_state::sdip_5_w)); | |
| map(0x8a1c, 0x8a1f).rw(FUNC(pc9801_state::sdip_6_r), FUNC(pc9801_state::sdip_6_w)); | |
| map(0x8b1c, 0x8b1f).rw(FUNC(pc9801_state::sdip_7_r), FUNC(pc9801_state::sdip_7_w)); | |
| map(0x8c1c, 0x8c1f).rw(FUNC(pc9801_state::sdip_8_r), FUNC(pc9801_state::sdip_8_w)); | |
| map(0x8d1c, 0x8d1f).rw(FUNC(pc9801_state::sdip_9_r), FUNC(pc9801_state::sdip_9_w)); | |
| map(0x8e1c, 0x8e1f).rw(FUNC(pc9801_state::sdip_a_r), FUNC(pc9801_state::sdip_a_w)); | |
| map(0x8f1c, 0x8f1f).rw(FUNC(pc9801_state::sdip_b_r), FUNC(pc9801_state::sdip_b_w)); | |
| // map(0xa460, 0xa46f) cs4231 PCM extended port / <undefined> | |
| // map(0xbfdb, 0xbfdb) mouse timing port | |
| // map(0xc0d0, 0xc0d3) MIDI port, option 0 / <undefined> | |
| // map(0xc4d0, 0xc4d3) MIDI port, option 1 / <undefined> | |
| // map(0xc8d0, 0xc8d3) MIDI port, option 2 / <undefined> | |
| // map(0xccd0, 0xccd3) MIDI port, option 3 / <undefined> | |
| // map(0xd0d0, 0xd0d3) MIDI port, option 4 / <undefined> | |
| // map(0xd4d0, 0xd4d3) MIDI port, option 5 / <undefined> | |
| // map(0xd8d0, 0xd8d3) MIDI port, option 6 / <undefined> | |
| // map(0xdcd0, 0xdcd3) MIDI port, option 7 / <undefined> | |
| map(0xe0d0, 0xe0d3).r(FUNC(pc9801_state::midi_r)); // MIDI port, option 8 / <undefined> | |
| // map(0xe4d0, 0xe4d3) MIDI port, option 9 / <undefined> | |
| // map(0xe8d0, 0xe8d3) MIDI port, option A / <undefined> | |
| // map(0xecd0, 0xecd3) MIDI port, option B / <undefined> | |
| // map(0xf0d0, 0xf0d3) MIDI port, option C / <undefined> | |
| // map(0xf4d0, 0xf4d3) MIDI port, option D / <undefined> | |
| // map(0xf8d0, 0xf8d3) MIDI port, option E / <undefined> | |
| // map(0xfcd0, 0xfcd3) MIDI port, option F / <undefined> | |
| } | |
| // TODO: identify this, might be an alt way to access SDIP? | |
| uint8_t pc9801_state::as_unkdev_data_r(offs_t offset) | |
| { | |
| if (offset == 0) | |
| return m_unkdev0468[m_unkdev0468_addr]; | |
| return 0xff; | |
| } | |
| void pc9801_state::as_unkdev_data_w(offs_t offset, uint8_t data) | |
| { | |
| if (offset == 0) | |
| m_unkdev0468[m_unkdev0468_addr] = data; | |
| // offset == 0: access bit? | |
| } | |
| void pc9801_state::as_unkdev_addr_w(offs_t offset, uint8_t data) | |
| { | |
| if (offset == 0) | |
| m_unkdev0468_addr = data; | |
| } | |
| void pc9801_state::pc9821as_io(address_map &map) | |
| { | |
| pc9821_io(map); | |
| map(0x0468, 0x046b).rw(FUNC(pc9801_state::as_unkdev_data_r), FUNC(pc9801_state::as_unkdev_data_w)).umask32(0x00ff00ff); | |
| map(0x046c, 0x046f).w(FUNC(pc9801_state::as_unkdev_addr_w)).umask32(0x00ff00ff); | |
| } | |
| void pc9801_state::upd7220_1_map(address_map &map) | |
| { | |
| map(0x00000, 0x03fff).ram().share("video_ram_1"); | |
| } | |
| void pc9801_state::upd7220_2_map(address_map &map) | |
| { | |
| map(0x00000, 0x3ffff).ram().share("video_ram_2"); | |
| } | |
| void pc9801_state::upd7220_grcg_2_map(address_map &map) | |
| { | |
| map(0x00000, 0x3ffff).rw(FUNC(pc9801_state::upd7220_grcg_r), FUNC(pc9801_state::upd7220_grcg_w)).share("video_ram_2"); | |
| } | |
| CUSTOM_INPUT_MEMBER(pc9801_state::system_type_r) | |
| { | |
| // System Type (0x00 stock PC-9801, 0xc0 PC-9801U / PC-98LT, PC-98HA, 0x80 others) | |
| return m_sys_type; | |
| } | |
| static INPUT_PORTS_START( pc9801 ) | |
| PORT_START("DSW1") | |
| PORT_BIT(0x0001, IP_ACTIVE_HIGH,IPT_CUSTOM) PORT_READ_LINE_DEVICE_MEMBER("upd1990a", upd1990a_device, data_out_r) | |
| PORT_DIPNAME( 0x0002, 0x0000, "DSW1" ) // error beep if OFF | |
| PORT_DIPSETTING( 0x0002, DEF_STR( Off ) ) | |
| PORT_DIPSETTING( 0x0000, DEF_STR( On ) ) | |
| PORT_DIPNAME( 0x0004, 0x0000, DEF_STR( Unknown ) ) | |
| PORT_DIPSETTING( 0x0004, DEF_STR( Off ) ) | |
| PORT_DIPSETTING( 0x0000, DEF_STR( On ) ) | |
| PORT_DIPNAME( 0x0008, 0x0008, "Display Type" ) PORT_DIPLOCATION("SW2:1") | |
| PORT_DIPSETTING( 0x0000, "Normal Display" ) | |
| PORT_DIPSETTING( 0x0008, "Hi-Res Display" ) | |
| PORT_DIPNAME( 0x0010, 0x0000, DEF_STR( Unknown ) ) | |
| PORT_DIPSETTING( 0x0010, DEF_STR( Off ) ) | |
| PORT_DIPSETTING( 0x0000, DEF_STR( On ) ) | |
| PORT_DIPNAME( 0x0020, 0x0020, DEF_STR( Unknown ) ) | |
| PORT_DIPSETTING( 0x0020, DEF_STR( Off ) ) | |
| PORT_DIPSETTING( 0x0000, DEF_STR( On ) ) | |
| PORT_DIPNAME( 0x0040, 0x0040, DEF_STR( Unknown ) ) | |
| PORT_DIPSETTING( 0x0040, DEF_STR( Off ) ) | |
| PORT_DIPSETTING( 0x0000, DEF_STR( On ) ) | |
| PORT_DIPNAME( 0x0080, 0x0080, DEF_STR( Unknown ) ) | |
| PORT_DIPSETTING( 0x0080, DEF_STR( Off ) ) | |
| PORT_DIPSETTING( 0x0000, DEF_STR( On ) ) | |
| PORT_START("DSW5") | |
| PORT_DIPNAME( 0x01, 0x00, "DSW5" ) // goes into basic with this off, PC-9801VF / PC-9801U setting | |
| PORT_DIPSETTING( 0x01, DEF_STR( Off ) ) | |
| PORT_DIPSETTING( 0x00, DEF_STR( On ) ) | |
| PORT_DIPNAME( 0x02, 0x00, DEF_STR( Unknown ) ) // V30 / V33 | |
| PORT_DIPSETTING( 0x02, DEF_STR( Off ) ) | |
| PORT_DIPSETTING( 0x00, DEF_STR( On ) ) | |
| PORT_DIPNAME( 0x04, 0x04, DEF_STR( Unknown ) ) // printer busy | |
| PORT_DIPSETTING( 0x04, DEF_STR( Off ) ) | |
| PORT_DIPSETTING( 0x00, DEF_STR( On ) ) | |
| PORT_DIPNAME( 0x08, 0x08, DEF_STR( Unknown ) ) // 8 / 4096 | |
| PORT_DIPSETTING( 0x08, DEF_STR( Off ) ) | |
| PORT_DIPSETTING( 0x00, DEF_STR( On ) ) | |
| PORT_DIPNAME( 0x10, 0x10, DEF_STR( Unknown ) ) // LCD display | |
| PORT_DIPSETTING( 0x10, DEF_STR( Off ) ) | |
| PORT_DIPSETTING( 0x00, DEF_STR( On ) ) | |
| PORT_DIPNAME( 0x20, 0x00, DEF_STR( Unknown ) ) //system clock = 5 MHz (0) / 8 MHz (1) | |
| PORT_DIPSETTING( 0x20, DEF_STR( Off ) ) | |
| PORT_DIPSETTING( 0x00, DEF_STR( On ) ) | |
| PORT_BIT( 0xc0, IP_ACTIVE_HIGH, IPT_CUSTOM ) PORT_CUSTOM_MEMBER(pc9801_state, system_type_r) | |
| PORT_START("DSW2") | |
| PORT_DIPNAME( 0x01, 0x01, "System Specification" ) PORT_DIPLOCATION("SW1:1") //jumps to daa00 if off, presumably some card booting | |
| PORT_DIPSETTING( 0x01, DEF_STR( Off ) ) | |
| PORT_DIPSETTING( 0x00, DEF_STR( On ) ) | |
| PORT_DIPNAME( 0x02, 0x02, "Terminal Mode" ) PORT_DIPLOCATION("SW1:2") | |
| PORT_DIPSETTING( 0x02, DEF_STR( Off ) ) | |
| PORT_DIPSETTING( 0x00, DEF_STR( On ) ) | |
| PORT_DIPNAME( 0x04, 0x00, "Text width" ) PORT_DIPLOCATION("SW1:3") | |
| PORT_DIPSETTING( 0x04, "40 chars/line" ) | |
| PORT_DIPSETTING( 0x00, "80 chars/line" ) | |
| PORT_DIPNAME( 0x08, 0x00, "Text height" ) PORT_DIPLOCATION("SW1:4") | |
| PORT_DIPSETTING( 0x08, "20 lines/screen" ) | |
| PORT_DIPSETTING( 0x00, "25 lines/screen" ) | |
| PORT_DIPNAME( 0x10, 0x00, "Memory Switch Init" ) PORT_DIPLOCATION("SW1:5") | |
| PORT_DIPSETTING( 0x00, DEF_STR( No ) ) //Fix memory switch condition | |
| PORT_DIPSETTING( 0x10, DEF_STR( Yes ) ) //Initialize Memory Switch with the system default | |
| PORT_DIPUNUSED_DIPLOC( 0x20, 0x20, "SW1:6" ) | |
| PORT_DIPUNUSED_DIPLOC( 0x40, 0x40, "SW1:7" ) | |
| PORT_DIPUNUSED_DIPLOC( 0x80, 0x80, "SW1:8" ) | |
| PORT_START("DSW3") | |
| PORT_DIPNAME( 0x01, 0x01, "DSW3" ) | |
| PORT_DIPSETTING( 0x01, DEF_STR( Off ) ) | |
| PORT_DIPSETTING( 0x00, DEF_STR( On ) ) | |
| PORT_DIPNAME( 0x02, 0x02, DEF_STR( Unknown ) ) | |
| PORT_DIPSETTING( 0x02, DEF_STR( Off ) ) | |
| PORT_DIPSETTING( 0x00, DEF_STR( On ) ) | |
| PORT_DIPNAME( 0x04, 0x04, DEF_STR( Unknown ) ) | |
| PORT_DIPSETTING( 0x04, DEF_STR( Off ) ) | |
| PORT_DIPSETTING( 0x00, DEF_STR( On ) ) | |
| PORT_DIPNAME( 0x08, 0x08, DEF_STR( Unknown ) ) | |
| PORT_DIPSETTING( 0x08, DEF_STR( Off ) ) | |
| PORT_DIPSETTING( 0x00, DEF_STR( On ) ) | |
| PORT_DIPNAME( 0x10, 0x10, DEF_STR( Unknown ) ) | |
| PORT_DIPSETTING( 0x10, DEF_STR( Off ) ) | |
| PORT_DIPSETTING( 0x00, DEF_STR( On ) ) | |
| PORT_DIPNAME( 0x20, 0x20, DEF_STR( Unknown ) ) | |
| PORT_DIPSETTING( 0x20, DEF_STR( Off ) ) | |
| PORT_DIPSETTING( 0x00, DEF_STR( On ) ) | |
| PORT_DIPNAME( 0x40, 0x40, DEF_STR( Unknown ) ) | |
| PORT_DIPSETTING( 0x40, DEF_STR( Off ) ) | |
| PORT_DIPSETTING( 0x00, DEF_STR( On ) ) | |
| PORT_DIPNAME( 0x80, 0x80, DEF_STR( Unknown ) ) | |
| PORT_DIPSETTING( 0x80, DEF_STR( Off ) ) | |
| PORT_DIPSETTING( 0x00, DEF_STR( On ) ) | |
| PORT_START("DSW4") | |
| PORT_DIPNAME( 0x01, 0x01, "DSW4" ) | |
| PORT_DIPSETTING( 0x01, DEF_STR( Off ) ) | |
| PORT_DIPSETTING( 0x00, DEF_STR( On ) ) | |
| PORT_DIPNAME( 0x02, 0x02, DEF_STR( Unknown ) ) | |
| PORT_DIPSETTING( 0x02, DEF_STR( Off ) ) | |
| PORT_DIPSETTING( 0x00, DEF_STR( On ) ) | |
| PORT_DIPNAME( 0x04, 0x04, DEF_STR( Unknown ) ) | |
| PORT_DIPSETTING( 0x04, DEF_STR( Off ) ) | |
| PORT_DIPSETTING( 0x00, DEF_STR( On ) ) | |
| PORT_DIPNAME( 0x08, 0x08, DEF_STR( Unknown ) ) | |
| PORT_DIPSETTING( 0x08, DEF_STR( Off ) ) | |
| PORT_DIPSETTING( 0x00, DEF_STR( On ) ) | |
| PORT_DIPNAME( 0x10, 0x10, DEF_STR( Unknown ) ) | |
| PORT_DIPSETTING( 0x10, DEF_STR( Off ) ) | |
| PORT_DIPSETTING( 0x00, DEF_STR( On ) ) | |
| PORT_DIPNAME( 0x20, 0x20, DEF_STR( Unknown ) ) | |
| PORT_DIPSETTING( 0x20, DEF_STR( Off ) ) | |
| PORT_DIPSETTING( 0x00, DEF_STR( On ) ) | |
| PORT_DIPNAME( 0x40, 0x40, DEF_STR( Unknown ) ) | |
| PORT_DIPSETTING( 0x40, DEF_STR( Off ) ) | |
| PORT_DIPSETTING( 0x00, DEF_STR( On ) ) | |
| PORT_DIPNAME( 0x80, 0x80, DEF_STR( Unknown ) ) | |
| PORT_DIPSETTING( 0x80, DEF_STR( Off ) ) | |
| PORT_DIPSETTING( 0x00, DEF_STR( On ) ) | |
| PORT_START("MOUSE_X") | |
| PORT_BIT( 0xff, 0x00, IPT_MOUSE_X ) PORT_SENSITIVITY(30) PORT_KEYDELTA(30) | |
| PORT_START("MOUSE_Y") | |
| PORT_BIT( 0xff, 0x00, IPT_MOUSE_Y ) PORT_SENSITIVITY(30) PORT_KEYDELTA(30) | |
| PORT_START("MOUSE_B") | |
| PORT_BIT(0x0f, IP_ACTIVE_LOW, IPT_UNUSED ) | |
| PORT_BIT(0x10, IP_ACTIVE_LOW, IPT_UNUSED ) | |
| PORT_BIT(0x20, IP_ACTIVE_LOW, IPT_BUTTON2) PORT_CODE(MOUSECODE_BUTTON2) PORT_NAME("Mouse Right Button") | |
| PORT_BIT(0x40, IP_ACTIVE_LOW, IPT_BUTTON3) PORT_CODE(MOUSECODE_BUTTON3) PORT_NAME("Mouse Middle Button") | |
| PORT_BIT(0x80, IP_ACTIVE_LOW, IPT_BUTTON1) PORT_CODE(MOUSECODE_BUTTON1) PORT_NAME("Mouse Left Button") | |
| PORT_START("ROM_LOAD") | |
| PORT_CONFNAME( 0x01, 0x01, "Load floppy 2hd BIOS" ) | |
| PORT_CONFSETTING( 0x00, DEF_STR( Yes ) ) | |
| PORT_CONFSETTING( 0x01, DEF_STR( No ) ) | |
| PORT_CONFNAME( 0x02, 0x02, "Load floppy 2dd BIOS" ) | |
| PORT_CONFSETTING( 0x00, DEF_STR( Yes ) ) | |
| PORT_CONFSETTING( 0x02, DEF_STR( No ) ) | |
| INPUT_PORTS_END | |
| static INPUT_PORTS_START( pc9801rs ) | |
| PORT_INCLUDE( pc9801 ) | |
| PORT_MODIFY("DSW2") | |
| PORT_DIPNAME( 0x80, 0x80, "GDC clock" ) PORT_DIPLOCATION("SW1:8") // DSW 2-8 | |
| PORT_DIPSETTING( 0x80, "2.5 MHz" ) | |
| PORT_DIPSETTING( 0x00, "5 MHz" ) | |
| PORT_MODIFY("DSW4") | |
| PORT_DIPNAME( 0x04, 0x00, "CPU Type" ) PORT_DIPLOCATION("SW4:8") // DSW 3-8 | |
| PORT_DIPSETTING( 0x04, "V30" ) | |
| PORT_DIPSETTING( 0x00, "I386" ) | |
| PORT_MODIFY("DSW5") | |
| PORT_DIPNAME( 0x08, 0x00, "Graphic Function" ) // DSW 1-8 | |
| PORT_DIPSETTING( 0x08, "Basic (8 Colors)" ) | |
| PORT_DIPSETTING( 0x00, "Expanded (16/4096 Colors)" ) | |
| PORT_DIPNAME( 0x10, 0x10, "Display Type" ) // LCD display, 98DO Demo explicitly wants it to be non-Plasma | |
| PORT_DIPSETTING( 0x10, "RGB" ) | |
| PORT_DIPSETTING( 0x00, "Plasma" ) | |
| PORT_MODIFY("ROM_LOAD") | |
| PORT_BIT( 0x03, IP_ACTIVE_LOW, IPT_UNUSED ) | |
| PORT_CONFNAME( 0x04, 0x04, "Load IDE BIOS" ) | |
| PORT_CONFSETTING( 0x00, DEF_STR( Yes ) ) | |
| PORT_CONFSETTING( 0x04, DEF_STR( No ) ) | |
| // PORT_START("SOUND_CONFIG") | |
| // PORT_CONFNAME( 0x01, 0x00, "Sound Type" ) | |
| // PORT_CONFSETTING( 0x00, "YM2203 (OPN)" ) | |
| // PORT_CONFSETTING( 0x01, "YM2608 (OPNA)" ) | |
| INPUT_PORTS_END | |
| static INPUT_PORTS_START( pc9821 ) | |
| PORT_INCLUDE( pc9801rs ) | |
| PORT_MODIFY("DSW2") | |
| PORT_DIPNAME( 0x01, 0x00, "S-Dip SW Init" ) PORT_DIPLOCATION("SW1:1") | |
| PORT_DIPSETTING( 0x01, DEF_STR( Off ) ) | |
| PORT_DIPSETTING( 0x00, DEF_STR( On ) ) | |
| PORT_MODIFY("DSW3") | |
| PORT_DIPNAME( 0x40, 0x40, "Conventional RAM size" ) PORT_DIPLOCATION("SW3:7") | |
| PORT_DIPSETTING( 0x40, "640 KB" ) | |
| PORT_DIPSETTING( 0x00, "512 KB" ) | |
| INPUT_PORTS_END | |
| static const gfx_layout charset_8x8 = | |
| { | |
| 8,8, | |
| 256, | |
| 1, | |
| { 0 }, | |
| { 0, 1, 2, 3, 4, 5, 6, 7 }, | |
| { 0*8, 1*8, 2*8, 3*8, 4*8, 5*8, 6*8, 7*8 }, | |
| 8*8 | |
| }; | |
| static const gfx_layout charset_8x16 = | |
| { | |
| 8,16, | |
| 256, | |
| 1, | |
| { 0 }, | |
| { 0, 1, 2, 3, 4, 5, 6, 7 }, | |
| { 0*8, 1*8, 2*8, 3*8, 4*8, 5*8, 6*8, 7*8,8*8, 9*8, 10*8, 11*8, 12*8, 13*8, 14*8, 15*8 }, | |
| 8*16 | |
| }; | |
| static const gfx_layout charset_16x16 = | |
| { | |
| 16,16, | |
| RGN_FRAC(1,1), | |
| 1, | |
| { 0 }, | |
| { STEP16(0,1) }, | |
| { STEP16(0,16) }, | |
| 16*16 | |
| }; | |
| static GFXDECODE_START( gfx_pc9801 ) | |
| GFXDECODE_ENTRY( "chargen", 0x00000, charset_8x8, 0x000, 0x01 ) | |
| GFXDECODE_ENTRY( "chargen", 0x00800, charset_8x16, 0x000, 0x01 ) | |
| GFXDECODE_ENTRY( "kanji", 0x00000, charset_16x16, 0x000, 0x01 ) | |
| GFXDECODE_ENTRY( "raw_kanji", 0x00000, charset_16x16, 0x000, 0x01 ) | |
| GFXDECODE_ENTRY( "new_chargen",0, charset_16x16, 0x000, 0x01 ) | |
| GFXDECODE_END | |
| /**************************************** | |
| * | |
| * I8259 PIC interface | |
| * | |
| ****************************************/ | |
| /* | |
| irq assignment (PC-9801F): | |
| 8259 master: | |
| ir0 PIT | |
| ir1 keyboard | |
| ir2 vblank | |
| ir3 | |
| ir4 rs-232c | |
| ir5 | |
| ir6 | |
| ir7 slave irq | |
| 8259 slave: | |
| ir0 printer | |
| ir1 IDE? | |
| ir2 2dd floppy irq | |
| ir3 2hd floppy irq | |
| ir4 opn | |
| ir5 mouse | |
| ir6 | |
| ir7 | |
| */ | |
| uint8_t pc9801_state::get_slave_ack(offs_t offset) | |
| { | |
| if (offset==7) { // IRQ = 7 | |
| return m_pic2->acknowledge(); | |
| } | |
| return 0x00; | |
| } | |
| /**************************************** | |
| * | |
| * I8253 PIT interface | |
| * | |
| ****************************************/ | |
| /* These rates do NOT appear to represent actual XTALs. They are likely obtained in | |
| different ways on different PC-98 models as divisions of extant XTAL frequencies | |
| such as 14.7456 MHz, 15.9744 MHz, 19.6608 MHz and 23.9616 MHz. | |
| PC-9801RS needs X1 for the pit, otherwise Uchiyama Aki no Chou Bangai has sound pitch bugs | |
| PC-9821 definitely needs X2, otherwise there's a timer error at POST. Unless it needs a different clock anyway ... | |
| */ | |
| #define MAIN_CLOCK_X1 1'996'800 | |
| #define MAIN_CLOCK_X2 2'457'600 | |
| /**************************************** | |
| * | |
| * I8237 DMA interface | |
| * | |
| ****************************************/ | |
| WRITE_LINE_MEMBER(pc9801_state::dma_hrq_changed) | |
| { | |
| m_maincpu->set_input_line(INPUT_LINE_HALT, state ? ASSERT_LINE : CLEAR_LINE); | |
| m_dmac->hack_w(state); | |
| // logerror("%02x HLDA\n",state); | |
| } | |
| WRITE_LINE_MEMBER(pc9801_state::tc_w ) | |
| { | |
| /* floppy terminal count */ | |
| m_fdc_2hd->tc_w(state); | |
| if(m_fdc_2dd) | |
| m_fdc_2dd->tc_w(state); | |
| // logerror("TC %02x\n",state); | |
| } | |
| uint8_t pc9801_state::dma_read_byte(offs_t offset) | |
| { | |
| address_space &program = m_maincpu->space(AS_PROGRAM); | |
| offs_t addr = (m_dma_offset[m_dack] << 16) | offset; | |
| if(offset == 0xffff) | |
| { | |
| switch(m_dma_autoinc[m_dack]) | |
| { | |
| case 1: | |
| { | |
| uint8_t page = m_dma_offset[m_dack]; | |
| m_dma_offset[m_dack] = ((page + 1) & 0xf) | (page & 0xf0); | |
| break; | |
| } | |
| case 3: | |
| m_dma_offset[m_dack]++; | |
| break; | |
| } | |
| } | |
| // logerror("%08x\n",addr); | |
| return program.read_byte(addr); | |
| } | |
| void pc9801_state::dma_write_byte(offs_t offset, uint8_t data) | |
| { | |
| address_space &program = m_maincpu->space(AS_PROGRAM); | |
| offs_t addr = (m_dma_offset[m_dack] << 16) | offset; | |
| if(offset == 0xffff) | |
| { | |
| switch(m_dma_autoinc[m_dack]) | |
| { | |
| case 1: | |
| { | |
| uint8_t page = m_dma_offset[m_dack]; | |
| m_dma_offset[m_dack] = ((page + 1) & 0xf) | (page & 0xf0); | |
| break; | |
| } | |
| case 3: | |
| m_dma_offset[m_dack]++; | |
| break; | |
| } | |
| } | |
| // logerror("%08x %02x\n",addr,data); | |
| program.write_byte(addr, data); | |
| } | |
| void pc9801_state::set_dma_channel(int channel, int state) | |
| { | |
| if (!state) m_dack = channel; | |
| } | |
| WRITE_LINE_MEMBER(pc9801_state::dack0_w){ /*logerror("%02x 0\n",state);*/ set_dma_channel(0, state); } | |
| WRITE_LINE_MEMBER(pc9801_state::dack1_w){ /*logerror("%02x 1\n",state);*/ set_dma_channel(1, state); } | |
| WRITE_LINE_MEMBER(pc9801_state::dack2_w){ /*logerror("%02x 2\n",state);*/ set_dma_channel(2, state); } | |
| WRITE_LINE_MEMBER(pc9801_state::dack3_w){ /*logerror("%02x 3\n",state);*/ set_dma_channel(3, state); } | |
| /* | |
| ch1 cs-4231a | |
| ch2 FDC | |
| ch3 SCSI | |
| */ | |
| /**************************************** | |
| * | |
| * PPI interfaces | |
| * | |
| ****************************************/ | |
| void pc9801_state::ppi_sys_beep_portc_w(uint8_t data) | |
| { | |
| m_beeper->set_state(!(data & 0x08)); | |
| } | |
| void pc9801_state::ppi_sys_dac_portc_w(uint8_t data) | |
| { | |
| m_dac_disable = BIT(data, 3); | |
| // TODO: some models have a finer grained volume control at I/O port 0xae8e | |
| // (98NOTE only?) | |
| m_dac->set_output_gain(0, m_dac_disable ? 0.0 : 1.0); | |
| } | |
| /* | |
| * Mouse 8255 I/F | |
| * | |
| * Port A: | |
| * x--- ---- LEFT mouse button | |
| * -x-- ---- MIDDLE mouse button | |
| * \- Undocumented, most PC98 mice don't have it | |
| * --x- ---- RIGHT mouse button | |
| * ---? ---- <unused> | |
| * ---- xxxx MD3-0 mouse direction latch | |
| * | |
| * Port C: | |
| * | |
| * x--- ---- HC Latch Mode (1=read latch, 0=read delta) | |
| * \- on 0->1 transition reset delta | |
| * -x-- ---- SXY Axis select (1=Y 0=X) | |
| * --x- ---- SHL Read nibble select (1) upper (0) lower | |
| * ---x ---- INT # (1) disable (0) enable | |
| * | |
| * Reading Port B and Port C low nibble are misc DIPSW selectors, | |
| * their meaning diverges on XA/XL/RL classes vs. the rest. | |
| * | |
| */ | |
| uint8_t pc9801_state::ppi_mouse_porta_r() | |
| { | |
| uint8_t res = ioport("MOUSE_B")->read() & 0xf0; | |
| const uint8_t isporthi = ((m_mouse.control & 0x20) >> 5)*4; | |
| if ((m_mouse.control & 0x80) == 0) | |
| { | |
| if (m_mouse.control & 0x40) | |
| res |= (m_mouse.dy >> isporthi) & 0xf; | |
| else | |
| res |= (m_mouse.dx >> isporthi) & 0xf; | |
| } | |
| else | |
| { | |
| if (m_mouse.control & 0x40) | |
| res |= (m_mouse.ly >> isporthi) & 0xf; | |
| else | |
| res |= (m_mouse.lx >> isporthi) & 0xf; | |
| } | |
| // logerror("A\n"); | |
| return res; | |
| } | |
| void pc9801_state::ppi_mouse_porta_w(uint8_t data) | |
| { | |
| // logerror("A %02x\n",data); | |
| } | |
| void pc9801_state::ppi_mouse_portb_w(uint8_t data) | |
| { | |
| // logerror("B %02x\n",data); | |
| } | |
| void pc9801_state::ppi_mouse_portc_w(uint8_t data) | |
| { | |
| // fsmoon: 0x00 -> 0x80 -> 0xa0 -> 0xc0 -> 0xf0 | |
| // (read latch as relative) | |
| // prinmak2: 0x00 -> 0x20 -> 0x40 -> 0x60 -> 0x60 | |
| // (keeps reading "delta" but never reset it, absolute mode) | |
| // biblems2: 0x0f -> 0x2f -> 0x4f -> 0x6f -> 0xef | |
| // (latches a delta reset then reads delta diff, relative mode) | |
| const u8 mouse_x = ioport("MOUSE_X")->read(); | |
| const u8 mouse_y = ioport("MOUSE_Y")->read(); | |
| m_mouse.dx = (mouse_x - m_mouse.prev_dx) & 0xff; | |
| m_mouse.dy = (mouse_y - m_mouse.prev_dy) & 0xff; | |
| if ((m_mouse.control & 0x80) == 0 && data & 0x80) | |
| { | |
| m_mouse.lx = m_mouse.dx & 0xff; | |
| m_mouse.ly = m_mouse.dy & 0xff; | |
| m_mouse.prev_dx = mouse_x; | |
| m_mouse.prev_dy = mouse_y; | |
| } | |
| m_mouse.control = data; | |
| } | |
| uint8_t pc9801_state::unk_r() | |
| { | |
| return 0xff; | |
| } | |
| /**************************************** | |
| * | |
| * UPD765 interface | |
| * | |
| ****************************************/ | |
| static void pc9801_floppies(device_slot_interface &device) | |
| { | |
| device.option_add("525dd", FLOPPY_525_DD); | |
| device.option_add("525hd", FLOPPY_525_HD); | |
| device.option_add("35hd", FLOPPY_35_HD); | |
| } | |
| static void pc9801_cbus_devices(device_slot_interface &device) | |
| { | |
| // PC-9801-14 | |
| device.option_add("pc9801_26", PC9801_26); | |
| device.option_add("pc9801_86", PC9801_86); | |
| // PC-9801-86 | |
| // PC-9801-26 + PC-9801-86 (?) | |
| // PC-9801-86 + Chibi-Oto | |
| device.option_add("pc9801_118", PC9801_118); | |
| device.option_add("pc9801_spb", PC9801_SPEAKBOARD); | |
| // Spark Board | |
| // AMD-98 (AmuseMent boarD) | |
| device.option_add("pc9801_amd98", PC9801_AMD98); | |
| device.option_add("mpu_pc98", MPU_PC98); | |
| } | |
| // Jast Sound, could be put independently | |
| WRITE_LINE_MEMBER( pc9801_state::fdc_2dd_irq ) | |
| { | |
| logerror("IRQ 2DD %d\n",state); | |
| if(m_fdc_2dd_ctrl & 8) | |
| { | |
| m_pic2->ir2_w(state); | |
| } | |
| } | |
| WRITE_LINE_MEMBER( pc9801_state::pc9801rs_fdc_irq ) | |
| { | |
| /* 0xffaf8 */ | |
| //logerror("%02x %d\n",m_fdc_ctrl,state); | |
| if(m_fdc_ctrl & 1) | |
| m_pic2->ir3_w(state); | |
| else | |
| m_pic2->ir2_w(state); | |
| } | |
| WRITE_LINE_MEMBER( pc9801_state::pc9801rs_fdc_drq ) | |
| { | |
| if(m_fdc_ctrl & 1) | |
| m_dmac->dreq2_w(state ^ 1); | |
| else | |
| m_dmac->dreq3_w(state ^ 1); | |
| } | |
| uint32_t pc9801_state::a20_286(bool state) | |
| { | |
| return (state ? 0xffffff : 0x0fffff); | |
| } | |
| /**************************************** | |
| * | |
| * Init emulation status | |
| * | |
| ****************************************/ | |
| // | |
| void pc9801_state::pc9801_palette(palette_device &palette) const | |
| { | |
| for(int i = 0; i < 8; i++) | |
| palette.set_pen_color(i, pal1bit(i >> 1), pal1bit(i >> 2), pal1bit(i >> 0)); | |
| for(int i = 8; i < palette.entries(); i++) | |
| palette.set_pen_color(i, rgb_t::black()); | |
| } | |
| MACHINE_START_MEMBER(pc9801_state,pc9801_common) | |
| { | |
| m_rtc->cs_w(1); | |
| m_rtc->oe_w(1); | |
| int ram_size = m_ram->size() - (640*1024); | |
| address_space& space = m_maincpu->space(AS_PROGRAM); | |
| space.install_ram(0, (ram_size < 0) ? m_ram->size() - 1 : (640*1024) - 1, m_ram->pointer()); | |
| if(ram_size > 0) | |
| space.install_ram(1024*1024, (1024*1024) + ram_size - 1, &m_ram->pointer()[(640*1024)]); | |
| save_item(NAME(m_sasi_data)); | |
| save_item(NAME(m_sasi_data_enable)); | |
| save_item(NAME(m_sasi_ctrl)); | |
| save_item(NAME(m_egc.regs)); | |
| save_item(NAME(m_egc.pat)); | |
| save_item(NAME(m_egc.src)); | |
| save_item(NAME(m_egc.count)); | |
| save_item(NAME(m_egc.leftover)); | |
| save_item(NAME(m_egc.first)); | |
| save_item(NAME(m_egc.init)); | |
| } | |
| MACHINE_START_MEMBER(pc9801_state,pc9801f) | |
| { | |
| MACHINE_START_CALL_MEMBER(pc9801_common); | |
| m_fdc_2hd->set_rate(500000); | |
| m_fdc_2dd->set_rate(250000); | |
| m_sys_type = 0x00 >> 6; | |
| } | |
| MACHINE_START_MEMBER(pc9801_state,pc9801rs) | |
| { | |
| MACHINE_START_CALL_MEMBER(pc9801_common); | |
| save_item(NAME(m_dac_disable)); | |
| m_sys_type = 0x80 >> 6; | |
| } | |
| MACHINE_START_MEMBER(pc9801_state,pc9801bx2) | |
| { | |
| MACHINE_START_CALL_MEMBER(pc9801rs); | |
| save_pointer(NAME(m_sdip), 24); | |
| } | |
| MACHINE_START_MEMBER(pc9801_state,pc9821) | |
| { | |
| MACHINE_START_CALL_MEMBER(pc9801rs); | |
| save_pointer(NAME(m_sdip), 24); | |
| } | |
| MACHINE_START_MEMBER(pc9801_state,pc9821ap2) | |
| { | |
| MACHINE_START_CALL_MEMBER(pc9821); | |
| // ... | |
| } | |
| MACHINE_RESET_MEMBER(pc9801_state,pc9801_common) | |
| { | |
| memset(m_tvram.get(), 0, sizeof(uint16_t) * 0x2000); | |
| m_nmi_ff = 0; | |
| m_mouse.control = 0xff; | |
| m_mouse.freq_reg = 0; | |
| m_mouse.freq_index = 0; | |
| m_mouse.lx = m_mouse.ly = m_mouse.prev_dx = m_mouse.prev_dy = m_mouse.dx = m_mouse.dy = 0; | |
| m_dma_autoinc[0] = m_dma_autoinc[1] = m_dma_autoinc[2] = m_dma_autoinc[3] = 0; | |
| memset(&m_egc, 0, sizeof(m_egc)); | |
| } | |
| MACHINE_RESET_MEMBER(pc9801_state,pc9801f) | |
| { | |
| MACHINE_RESET_CALL_MEMBER(pc9801_common); | |
| uint8_t op_mode; | |
| uint8_t *ROM; | |
| uint8_t *PRG = memregion("fdc_data")->base(); | |
| int i; | |
| ROM = memregion("fdc_bios_2dd")->base(); | |
| op_mode = (ioport("ROM_LOAD")->read() & 2) >> 1; | |
| for(i=0;i<0x1000;i++) | |
| ROM[i] = PRG[i+op_mode*0x8000]; | |
| ROM = memregion("fdc_bios_2hd")->base(); | |
| op_mode = ioport("ROM_LOAD")->read() & 1; | |
| for(i=0;i<0x1000;i++) | |
| ROM[i] = PRG[i+op_mode*0x8000+0x10000]; | |
| m_beeper->set_state(0); | |
| } | |
| MACHINE_RESET_MEMBER(pc9801_state,pc9801rs) | |
| { | |
| MACHINE_RESET_CALL_MEMBER(pc9801_common); | |
| m_gate_a20 = 0; | |
| m_fdc_ctrl = 3; | |
| m_access_ctrl = 0; | |
| m_ide_sel = 0; | |
| m_maincpu->set_input_line(INPUT_LINE_A20, m_gate_a20); | |
| if(memregion("ide")) | |
| { | |
| if(!(ioport("ROM_LOAD")->read() & 4)) | |
| m_maincpu->space(AS_PROGRAM).install_rom(0xd8000, 0xd9fff, memregion("ide")->base()); | |
| else | |
| m_maincpu->space(AS_PROGRAM).install_rom(0xd8000, 0xd9fff, memregion("ide")->base() + 0x2000); | |
| } | |
| m_dac_disable = true; | |
| } | |
| MACHINE_RESET_MEMBER(pc9801_state,pc9821) | |
| { | |
| MACHINE_RESET_CALL_MEMBER(pc9801rs); | |
| m_pc9821_window_bank = 0x08; | |
| } | |
| WRITE_LINE_MEMBER(pc9801_state::vrtc_irq) | |
| { | |
| if(state) | |
| m_pic1->ir2_w(1); | |
| } | |
| void pc9801_state::floppy_formats(format_registration &fr) | |
| { | |
| fr.add_mfm_containers(); | |
| fr.add(FLOPPY_PC98_FORMAT); | |
| fr.add(FLOPPY_PC98FDI_FORMAT); | |
| fr.add(FLOPPY_FDD_FORMAT); | |
| fr.add(FLOPPY_DCP_FORMAT); | |
| fr.add(FLOPPY_DIP_FORMAT); | |
| fr.add(FLOPPY_NFD_FORMAT); | |
| } | |
| TIMER_DEVICE_CALLBACK_MEMBER( pc9801_state::mouse_irq_cb ) | |
| { | |
| if((m_mouse.control & 0x10) == 0) | |
| { | |
| m_mouse.freq_index ++; | |
| // logerror("%02x\n",m_mouse.freq_index); | |
| if(m_mouse.freq_index > m_mouse.freq_reg) | |
| { | |
| // logerror("irq %02x\n",m_mouse.freq_reg); | |
| m_mouse.freq_index = 0; | |
| m_pic2->ir5_w(0); | |
| m_pic2->ir5_w(1); | |
| } | |
| } | |
| } | |
| void pc9801_atapi_devices(device_slot_interface &device) | |
| { | |
| device.option_add("pc9801_cd", PC9801_CD); | |
| } | |
| void pc9801_state::pc9801_keyboard(machine_config &config) | |
| { | |
| PC9801_KBD(config, m_keyb, 53); | |
| m_keyb->irq_wr_callback().set(m_pic1, FUNC(pic8259_device::ir1_w)); | |
| } | |
| void pc9801_state::pc9801_pit_clock(machine_config &config, const XTAL clock) | |
| { | |
| m_pit8253->set_clk<0>(clock); | |
| m_pit8253->set_clk<1>(clock); | |
| m_pit8253->set_clk<2>(clock); | |
| } | |
| void pc9801_state::pc9801_mouse(machine_config &config) | |
| { | |
| i8255_device &ppi_mouse(I8255(config, "ppi8255_mouse")); | |
| ppi_mouse.in_pa_callback().set(FUNC(pc9801_state::ppi_mouse_porta_r)); | |
| ppi_mouse.out_pa_callback().set(FUNC(pc9801_state::ppi_mouse_porta_w)); | |
| ppi_mouse.in_pb_callback().set_ioport("DSW3"); | |
| ppi_mouse.out_pb_callback().set(FUNC(pc9801_state::ppi_mouse_portb_w)); | |
| ppi_mouse.in_pc_callback().set_ioport("DSW4"); | |
| ppi_mouse.out_pc_callback().set(FUNC(pc9801_state::ppi_mouse_portc_w)); | |
| TIMER(config, "mouse_timer").configure_periodic(FUNC(pc9801_state::mouse_irq_cb), attotime::from_hz(120)); | |
| } | |
| void pc9801_state::pc9801_cbus(machine_config &config) | |
| { | |
| pc9801_slot_device &cbus0(PC9801CBUS_SLOT(config, "cbus0", pc9801_cbus_devices, "pc9801_26")); | |
| cbus0.set_memspace(m_maincpu, AS_PROGRAM); | |
| cbus0.set_iospace(m_maincpu, AS_IO); | |
| cbus0.int_cb<0>().set("ir3", FUNC(input_merger_device::in_w<0>)); | |
| cbus0.int_cb<1>().set("ir5", FUNC(input_merger_device::in_w<0>)); | |
| cbus0.int_cb<2>().set("ir6", FUNC(input_merger_device::in_w<0>)); | |
| cbus0.int_cb<3>().set("ir9", FUNC(input_merger_device::in_w<0>)); | |
| cbus0.int_cb<4>().set("pic8259_slave", FUNC(pic8259_device::ir2_w)); | |
| cbus0.int_cb<5>().set("ir12", FUNC(input_merger_device::in_w<0>)); | |
| cbus0.int_cb<6>().set("ir13", FUNC(input_merger_device::in_w<0>)); | |
| pc9801_slot_device &cbus1(PC9801CBUS_SLOT(config, "cbus1", pc9801_cbus_devices, nullptr)); | |
| cbus1.set_memspace(m_maincpu, AS_PROGRAM); | |
| cbus1.set_iospace(m_maincpu, AS_IO); | |
| cbus1.int_cb<0>().set("ir3", FUNC(input_merger_device::in_w<1>)); | |
| cbus1.int_cb<1>().set("ir5", FUNC(input_merger_device::in_w<1>)); | |
| cbus1.int_cb<2>().set("ir6", FUNC(input_merger_device::in_w<1>)); | |
| cbus1.int_cb<3>().set("ir9", FUNC(input_merger_device::in_w<1>)); | |
| cbus1.int_cb<4>().set("pic8259_slave", FUNC(pic8259_device::ir3_w)); | |
| cbus1.int_cb<5>().set("ir12", FUNC(input_merger_device::in_w<1>)); | |
| cbus1.int_cb<6>().set("ir13", FUNC(input_merger_device::in_w<1>)); | |
| // TODO: six max slots | |
| INPUT_MERGER_ANY_HIGH(config, "ir3").output_handler().set("pic8259_master", FUNC(pic8259_device::ir3_w)); | |
| INPUT_MERGER_ANY_HIGH(config, "ir5").output_handler().set("pic8259_master", FUNC(pic8259_device::ir5_w)); | |
| INPUT_MERGER_ANY_HIGH(config, "ir6").output_handler().set("pic8259_master", FUNC(pic8259_device::ir6_w)); | |
| INPUT_MERGER_ANY_HIGH(config, "ir9").output_handler().set("pic8259_slave", FUNC(pic8259_device::ir1_w)); | |
| INPUT_MERGER_ANY_HIGH(config, "ir12").output_handler().set("pic8259_slave", FUNC(pic8259_device::ir4_w)); | |
| INPUT_MERGER_ANY_HIGH(config, "ir13").output_handler().set("pic8259_slave", FUNC(pic8259_device::ir5_w)); | |
| } | |
| void pc9801_state::pc9801_sasi(machine_config &config) | |
| { | |
| SCSI_PORT(config, m_sasibus, 0); | |
| m_sasibus->set_data_input_buffer("sasi_data_in"); | |
| m_sasibus->io_handler().set(FUNC(pc9801_state::write_sasi_io)); // bit2 | |
| m_sasibus->cd_handler().set("sasi_ctrl_in", FUNC(input_buffer_device::write_bit3)); | |
| m_sasibus->msg_handler().set("sasi_ctrl_in", FUNC(input_buffer_device::write_bit4)); | |
| m_sasibus->bsy_handler().set("sasi_ctrl_in", FUNC(input_buffer_device::write_bit5)); | |
| m_sasibus->ack_handler().set("sasi_ctrl_in", FUNC(input_buffer_device::write_bit6)); | |
| m_sasibus->req_handler().set(FUNC(pc9801_state::write_sasi_req)); | |
| m_sasibus->set_slot_device(1, "harddisk", PC9801_SASI, DEVICE_INPUT_DEFAULTS_NAME(SCSI_ID_0)); | |
| output_latch_device &sasi_out(OUTPUT_LATCH(config, "sasi_data_out")); | |
| m_sasibus->set_output_latch(sasi_out); | |
| INPUT_BUFFER(config, "sasi_data_in"); | |
| INPUT_BUFFER(config, "sasi_ctrl_in"); | |
| m_dmac->in_ior_callback<0>().set(FUNC(pc9801_state::sasi_data_r)); | |
| m_dmac->out_iow_callback<0>().set(FUNC(pc9801_state::sasi_data_w)); | |
| } | |
| void pc9801_state::cdrom_headphones(device_t *device) | |
| { | |
| cdda_device *cdda = device->subdevice<cdda_device>("cdda"); | |
| cdda->add_route(0, "^^lheadphone", 1.0); | |
| cdda->add_route(1, "^^rheadphone", 1.0); | |
| } | |
| void pc9801_state::pc9801_ide(machine_config &config) | |
| { | |
| SPEAKER(config, "lheadphone").front_left(); | |
| SPEAKER(config, "rheadphone").front_right(); | |
| ATA_INTERFACE(config, m_ide[0]).options(ata_devices, "hdd", nullptr, false); | |
| m_ide[0]->irq_handler().set("ideirq", FUNC(input_merger_device::in_w<0>)); | |
| ATA_INTERFACE(config, m_ide[1]).options(pc9801_atapi_devices, "pc9801_cd", nullptr, false); | |
| m_ide[1]->irq_handler().set("ideirq", FUNC(input_merger_device::in_w<1>)); | |
| m_ide[1]->slot(0).set_option_machine_config("pc9801_cd", cdrom_headphones); | |
| INPUT_MERGER_ANY_HIGH(config, "ideirq").output_handler().set("pic8259_slave", FUNC(pic8259_device::ir1_w)); | |
| SOFTWARE_LIST(config, "cd_list").set_original("pc98_cd"); | |
| } | |
| void pc9801_state::pc9801_common(machine_config &config) | |
| { | |
| PIT8253(config, m_pit8253, 0); | |
| m_pit8253->set_clk<0>(MAIN_CLOCK_X1); // heartbeat IRQ | |
| m_pit8253->out_handler<0>().set(m_pic1, FUNC(pic8259_device::ir0_w)); | |
| m_pit8253->set_clk<1>(MAIN_CLOCK_X1); // Memory Refresh | |
| m_pit8253->set_clk<2>(MAIN_CLOCK_X1); // RS-232C | |
| m_pit8253->out_handler<2>().set(m_sio, FUNC(i8251_device::write_txc)); | |
| m_pit8253->out_handler<2>().append(m_sio, FUNC(i8251_device::write_rxc)); | |
| AM9517A(config, m_dmac, 5000000); // unknown clock, TODO: check channels 0 - 1 | |
| m_dmac->out_hreq_callback().set(FUNC(pc9801_state::dma_hrq_changed)); | |
| m_dmac->out_eop_callback().set(FUNC(pc9801_state::tc_w)); | |
| m_dmac->in_memr_callback().set(FUNC(pc9801_state::dma_read_byte)); | |
| m_dmac->out_memw_callback().set(FUNC(pc9801_state::dma_write_byte)); | |
| m_dmac->in_ior_callback<2>().set(m_fdc_2hd, FUNC(upd765a_device::dma_r)); | |
| m_dmac->out_iow_callback<2>().set(m_fdc_2hd, FUNC(upd765a_device::dma_w)); | |
| m_dmac->out_dack_callback<0>().set(FUNC(pc9801_state::dack0_w)); | |
| m_dmac->out_dack_callback<1>().set(FUNC(pc9801_state::dack1_w)); | |
| m_dmac->out_dack_callback<2>().set(FUNC(pc9801_state::dack2_w)); | |
| m_dmac->out_dack_callback<3>().set(FUNC(pc9801_state::dack3_w)); | |
| PIC8259(config, m_pic1, 0); | |
| m_pic1->out_int_callback().set_inputline(m_maincpu, 0); | |
| m_pic1->in_sp_callback().set_constant(1); | |
| m_pic1->read_slave_ack_callback().set(FUNC(pc9801_state::get_slave_ack)); | |
| PIC8259(config, m_pic2, 0); | |
| m_pic2->out_int_callback().set(m_pic1, FUNC(pic8259_device::ir7_w)); // TODO: Check ir7_w | |
| m_pic2->in_sp_callback().set_constant(0); | |
| I8255(config, m_ppi_sys, 0); | |
| m_ppi_sys->in_pa_callback().set_ioport("DSW2"); | |
| m_ppi_sys->in_pb_callback().set_ioport("DSW1"); | |
| m_ppi_sys->in_pc_callback().set_constant(0xa0); // 0x80 cpu triple fault reset flag? | |
| // m_ppi_sys->out_pc_callback().set(FUNC(pc9801_state::ppi_sys_portc_w)); | |
| I8255(config, m_ppi_prn, 0); | |
| // TODO: check this one | |
| m_ppi_prn->in_pb_callback().set_ioport("DSW5"); | |
| pc9801_keyboard(config); | |
| pc9801_mouse(config); | |
| pc9801_cbus(config); | |
| I8251(config, m_sio, 0); | |
| PC9801_MEMSW(config, m_memsw, 0); | |
| UPD765A(config, m_fdc_2hd, 8'000'000, true, true); | |
| m_fdc_2hd->intrq_wr_callback().set(m_pic2, FUNC(pic8259_device::ir3_w)); | |
| m_fdc_2hd->drq_wr_callback().set(m_dmac, FUNC(am9517a_device::dreq2_w)).invert(); | |
| FLOPPY_CONNECTOR(config, "upd765_2hd:0", pc9801_floppies, "525hd", pc9801_state::floppy_formats); | |
| FLOPPY_CONNECTOR(config, "upd765_2hd:1", pc9801_floppies, "525hd", pc9801_state::floppy_formats); | |
| i8255_device &ppi_fdd(I8255(config, "ppi8255_fdd")); | |
| ppi_fdd.in_pa_callback().set_constant(0xff); | |
| ppi_fdd.in_pb_callback().set_constant(0xff); | |
| ppi_fdd.in_pc_callback().set_constant(0xff); | |
| //ppi_fdd.out_pc_callback().set(FUNC(pc9801_state::ppi_fdd_portc_w)); | |
| SOFTWARE_LIST(config, "disk_list").set_original("pc98"); | |
| /* video hardware */ | |
| SCREEN(config, m_screen, SCREEN_TYPE_RASTER); | |
| m_screen->set_raw(21.0526_MHz_XTAL, 848, 0, 640, 440, 0, 400); | |
| m_screen->set_screen_update(FUNC(pc9801_state::screen_update)); | |
| m_screen->screen_vblank().set(FUNC(pc9801_state::vrtc_irq)); | |
| UPD7220(config, m_hgdc1, 21.0526_MHz_XTAL / 8); | |
| m_hgdc1->set_addrmap(0, &pc9801_state::upd7220_1_map); | |
| m_hgdc1->set_draw_text(FUNC(pc9801_state::hgdc_draw_text)); | |
| m_hgdc1->vsync_wr_callback().set(m_hgdc2, FUNC(upd7220_device::ext_sync_w)); | |
| UPD7220(config, m_hgdc2, 21.0526_MHz_XTAL / 8); | |
| m_hgdc2->set_addrmap(0, &pc9801_state::upd7220_2_map); | |
| m_hgdc2->set_display_pixels(FUNC(pc9801_state::hgdc_display_pixels)); | |
| SPEAKER(config, "mono").front_center(); | |
| GFXDECODE(config, m_gfxdecode, m_palette, gfx_pc9801); | |
| } | |
| void pc9801_state::pc9801(machine_config &config) | |
| { | |
| I8086(config, m_maincpu, 5000000); //unknown clock | |
| m_maincpu->set_addrmap(AS_PROGRAM, &pc9801_state::pc9801_map); | |
| m_maincpu->set_addrmap(AS_IO, &pc9801_state::pc9801_io); | |
| m_maincpu->set_irq_acknowledge_callback("pic8259_master", FUNC(pic8259_device::inta_cb)); | |
| pc9801_common(config); | |
| m_ppi_sys->out_pc_callback().set(FUNC(pc9801_state::ppi_sys_beep_portc_w)); | |
| MCFG_MACHINE_START_OVERRIDE(pc9801_state, pc9801f) | |
| MCFG_MACHINE_RESET_OVERRIDE(pc9801_state, pc9801f) | |
| // TODO: maybe force dips to avoid beep error | |
| RAM(config, m_ram).set_default_size("640K").set_extra_options("128K,256K,384K,512K"); | |
| UPD765A(config, m_fdc_2dd, 8'000'000, false, true); | |
| m_fdc_2dd->intrq_wr_callback().set(FUNC(pc9801_state::fdc_2dd_irq)); | |
| m_fdc_2dd->drq_wr_callback().set(m_dmac, FUNC(am9517a_device::dreq3_w)).invert(); | |
| FLOPPY_CONNECTOR(config, "upd765_2dd:0", pc9801_floppies, "525dd", pc9801_state::floppy_formats); | |
| FLOPPY_CONNECTOR(config, "upd765_2dd:1", pc9801_floppies, "525dd", pc9801_state::floppy_formats); | |
| pc9801_sasi(config); | |
| UPD1990A(config, m_rtc); | |
| m_dmac->in_ior_callback<3>().set(m_fdc_2dd, FUNC(upd765a_device::dma_r)); | |
| m_dmac->out_iow_callback<3>().set(m_fdc_2dd, FUNC(upd765a_device::dma_w)); | |
| BEEP(config, m_beeper, 2400).add_route(ALL_OUTPUTS, "mono", 0.15); | |
| PALETTE(config, m_palette, FUNC(pc9801_state::pc9801_palette), 16); | |
| } | |
| void pc9801_state::pc9801rs(machine_config &config) | |
| { | |
| I386SX(config, m_maincpu, MAIN_CLOCK_X1*8); // unknown clock. | |
| m_maincpu->set_addrmap(AS_PROGRAM, &pc9801_state::pc9801rs_map); | |
| m_maincpu->set_addrmap(AS_IO, &pc9801_state::pc9801rs_io); | |
| m_maincpu->set_irq_acknowledge_callback("pic8259_master", FUNC(pic8259_device::inta_cb)); | |
| pc9801_common(config); | |
| m_ppi_sys->out_pc_callback().set(FUNC(pc9801_state::ppi_sys_dac_portc_w)); | |
| // TODO: verify if it needs invert(); | |
| m_pit8253->out_handler<1>().set( m_dac, FUNC(speaker_sound_device::level_w)); | |
| ADDRESS_MAP_BANK(config, "ipl_bank").set_map(&pc9801_state::ipl_bank).set_options(ENDIANNESS_LITTLE, 16, 18, 0x18000); | |
| MCFG_MACHINE_START_OVERRIDE(pc9801_state, pc9801rs) | |
| MCFG_MACHINE_RESET_OVERRIDE(pc9801_state, pc9801rs) | |
| m_dmac->set_clock(MAIN_CLOCK_X1*8); // unknown clock | |
| pc9801_ide(config); | |
| UPD4990A(config, m_rtc); | |
| RAM(config, m_ram).set_default_size("1664K").set_extra_options("640K,3712K,7808K,14M"); | |
| m_hgdc2->set_addrmap(0, &pc9801_state::upd7220_grcg_2_map); | |
| // DAC_1BIT(config, m_dac, 0).set_output_range(-1, 1).add_route(ALL_OUTPUTS, "mono", 0.15); | |
| SPEAKER_SOUND(config, m_dac).add_route(ALL_OUTPUTS, "mono", 0.40); | |
| PALETTE(config, m_palette, FUNC(pc9801_state::pc9801_palette), 16 + 16); | |
| } | |
| void pc9801_state::pc9801vm(machine_config &config) | |
| { | |
| pc9801rs(config); | |
| V30(config.replace(), m_maincpu, 10000000); | |
| m_maincpu->set_addrmap(AS_PROGRAM, &pc9801_state::pc9801ux_map); | |
| m_maincpu->set_addrmap(AS_IO, &pc9801_state::pc9801ux_io); | |
| m_maincpu->set_irq_acknowledge_callback("pic8259_master", FUNC(pic8259_device::inta_cb)); | |
| m_ram->set_default_size("640K").set_extra_options("640K"); // ??? | |
| MCFG_MACHINE_START_OVERRIDE(pc9801_state, pc9801rs) | |
| MCFG_MACHINE_RESET_OVERRIDE(pc9801_state, pc9801_common) | |
| } | |
| void pc9801_state::pc9801ux(machine_config &config) | |
| { | |
| pc9801rs(config); | |
| i80286_cpu_device &maincpu(I80286(config.replace(), m_maincpu, 10000000)); | |
| maincpu.set_addrmap(AS_PROGRAM, &pc9801_state::pc9801ux_map); | |
| maincpu.set_addrmap(AS_IO, &pc9801_state::pc9801ux_io); | |
| maincpu.set_a20_callback(i80286_cpu_device::a20_cb(&pc9801_state::a20_286, this)); | |
| maincpu.set_irq_acknowledge_callback("pic8259_master", FUNC(pic8259_device::inta_cb)); | |
| // AM9157A(config, "i8237", 10000000); // unknown clock | |
| } | |
| void pc9801_state::pc9801bx2(machine_config &config) | |
| { | |
| pc9801rs(config); | |
| I486(config.replace(), m_maincpu, 25000000); | |
| m_maincpu->set_addrmap(AS_PROGRAM, &pc9801_state::pc9821_map); | |
| m_maincpu->set_addrmap(AS_IO, &pc9801_state::pc9821_io); | |
| m_maincpu->set_irq_acknowledge_callback("pic8259_master", FUNC(pic8259_device::inta_cb)); | |
| MCFG_MACHINE_START_OVERRIDE(pc9801_state, pc9801bx2) | |
| } | |
| // TODO: setter for DMAC clock should follow up whatever is the CPU clock | |
| void pc9801_state::pc9821(machine_config &config) | |
| { | |
| pc9801rs(config); | |
| I486(config.replace(), m_maincpu, 16000000); // unknown clock | |
| m_maincpu->set_addrmap(AS_PROGRAM, &pc9801_state::pc9821_map); | |
| m_maincpu->set_addrmap(AS_IO, &pc9801_state::pc9821_io); | |
| m_maincpu->set_irq_acknowledge_callback("pic8259_master", FUNC(pic8259_device::inta_cb)); | |
| m_pit8253->set_clk<0>(MAIN_CLOCK_X2); | |
| m_pit8253->set_clk<1>(MAIN_CLOCK_X2); | |
| m_pit8253->set_clk<2>(MAIN_CLOCK_X2); | |
| MCFG_MACHINE_START_OVERRIDE(pc9801_state, pc9821) | |
| MCFG_MACHINE_RESET_OVERRIDE(pc9801_state, pc9821) | |
| m_dmac->set_clock(16000000); // unknown clock | |
| PALETTE(config.replace(), m_palette, FUNC(pc9801_state::pc9801_palette), 16 + 16 + 256); | |
| } | |
| void pc9801_state::pc9821as(machine_config &config) | |
| { | |
| pc9821(config); | |
| I486(config.replace(), m_maincpu, 33000000); // unknown clock | |
| m_maincpu->set_addrmap(AS_PROGRAM, &pc9801_state::pc9821_map); | |
| m_maincpu->set_addrmap(AS_IO, &pc9801_state::pc9821as_io); | |
| m_maincpu->set_irq_acknowledge_callback("pic8259_master", FUNC(pic8259_device::inta_cb)); | |
| } | |
| void pc9801_state::pc9821ap2(machine_config &config) | |
| { | |
| pc9821(config); | |
| I486(config.replace(), m_maincpu, 66666667); // unknown clock | |
| m_maincpu->set_addrmap(AS_PROGRAM, &pc9801_state::pc9821_map); | |
| m_maincpu->set_addrmap(AS_IO, &pc9801_state::pc9821_io); | |
| m_maincpu->set_irq_acknowledge_callback("pic8259_master", FUNC(pic8259_device::inta_cb)); | |
| MCFG_MACHINE_START_OVERRIDE(pc9801_state, pc9821ap2) | |
| } | |
| void pc9801_state::pc9821v20(machine_config &config) | |
| { | |
| pc9821(config); | |
| PENTIUM(config.replace(), m_maincpu, 32000000); // unknown clock, definitely not 32 MHz | |
| m_maincpu->set_addrmap(AS_PROGRAM, &pc9801_state::pc9821_map); | |
| m_maincpu->set_addrmap(AS_IO, &pc9801_state::pc9821_io); | |
| m_maincpu->set_irq_acknowledge_callback("pic8259_master", FUNC(pic8259_device::inta_cb)); | |
| } | |
| void pc9801_state::pc9821xa16(machine_config &config) | |
| { | |
| pc9821(config); | |
| PENTIUM(config.replace(), m_maincpu, 166000000); // Pentium P54C | |
| m_maincpu->set_addrmap(AS_PROGRAM, &pc9801_state::pc9821_map); | |
| m_maincpu->set_addrmap(AS_IO, &pc9801_state::pc9821_io); | |
| m_maincpu->set_irq_acknowledge_callback("pic8259_master", FUNC(pic8259_device::inta_cb)); | |
| } | |
| void pc9801_state::pc9821ra20(machine_config &config) | |
| { | |
| pc9821(config); | |
| PENTIUM_PRO(config.replace(), m_maincpu, XTAL(200'000'000)); | |
| m_maincpu->set_addrmap(AS_PROGRAM, &pc9801_state::pc9821_map); | |
| m_maincpu->set_addrmap(AS_IO, &pc9801_state::pc9821_io); | |
| m_maincpu->set_irq_acknowledge_callback("pic8259_master", FUNC(pic8259_device::inta_cb)); | |
| } | |
| void pc9801_state::pc9821ra333(machine_config &config) | |
| { | |
| pc9821(config); | |
| const double xtal = 333000000; | |
| PENTIUM2(config.replace(), m_maincpu, xtal); // actually a Celeron | |
| m_maincpu->set_addrmap(AS_PROGRAM, &pc9801_state::pc9821_map); | |
| m_maincpu->set_addrmap(AS_IO, &pc9801_state::pc9821_io); | |
| m_maincpu->set_irq_acknowledge_callback("pic8259_master", FUNC(pic8259_device::inta_cb)); | |
| // 128KB CPU cache RAM | |
| // Trident TGUI9682XGi + integrated 98 gfx card | |
| // 3x cbus + 2x PCI slots | |
| // 6GB HDD | |
| // built-in ethernet 100BASE-TX/10BASE-T | |
| } | |
| // Epson clones | |
| // TODO: definitely runs on their own state machine | |
| // (verify if for instance they need EGC and what kind of FM board they needs up) | |
| void pc9801_state::pc386m(machine_config &config) | |
| { | |
| pc9801rs(config); | |
| // I386SX(config.replace(), m_maincpu, 16000000); // i386SX 16MHz, switchable to 10/6 MHz | |
| // m_maincpu->set_addrmap(AS_PROGRAM, &pc9801_state::pc9801rs_map); | |
| // m_maincpu->set_addrmap(AS_IO, &pc9801_state::pc9801rs_io); | |
| // m_maincpu->set_irq_acknowledge_callback("pic8259_master", FUNC(pic8259_device::inta_cb)); | |
| // RAM: 640KB + 14.6MB max | |
| // 2 3.5 floppy drives | |
| // ... | |
| } | |
| void pc9801_state::pc486se(machine_config &config) | |
| { | |
| pc9821(config); | |
| const XTAL xtal = XTAL(25'000'000); | |
| I486(config.replace(), m_maincpu, xtal); // i486SX, switchable to 10/5 MHz, supports overdrive | |
| m_maincpu->set_addrmap(AS_PROGRAM, &pc9801_state::pc9821_map); | |
| m_maincpu->set_addrmap(AS_IO, &pc9801_state::pc9821as_io); | |
| m_maincpu->set_irq_acknowledge_callback("pic8259_master", FUNC(pic8259_device::inta_cb)); | |
| pc9801_pit_clock(config, xtal/8); // unknown, passes "ERR:TM" test | |
| // RAM: 1.6 MB (!) + 17.6 max | |
| // "dedicated internal memory slot x 1" | |
| // "dedicated video board" slot | |
| } | |
| void pc9801_state::pc486mu(machine_config &config) | |
| { | |
| pc9821(config); | |
| const XTAL xtal = XTAL(33'000'000); | |
| I486(config.replace(), m_maincpu, xtal); // i486SX, switchable to I386DX 10MHz/5MHz, Pentium ODP compatible | |
| m_maincpu->set_addrmap(AS_PROGRAM, &pc9801_state::pc9821_map); | |
| m_maincpu->set_addrmap(AS_IO, &pc9801_state::pc9821as_io); | |
| m_maincpu->set_irq_acknowledge_callback("pic8259_master", FUNC(pic8259_device::inta_cb)); | |
| pc9801_pit_clock(config, xtal/8); // unknown, passes "ERR:TM" test | |
| // CL-GD5428 | |
| // RAM: 5.6 + 61.6MB max | |
| // 2 x 3.5 floppy drives | |
| } | |
| /* took from "raw" memory dump, uncomment ROM_FILL if you want to play with it */ | |
| #define LOAD_IDE_ROM \ | |
| ROM_REGION( 0x4000, "ide", ROMREGION_ERASEVAL(0xcb) ) \ | |
| ROM_LOAD( "d8000.rom", 0x0000, 0x2000, BAD_DUMP CRC(5dda57cc) SHA1(d0dead41c5b763008a4d777aedddce651eb6dcbb) ) \ | |
| ROM_IGNORE( 0x2000 ) \ | |
| ROM_IGNORE( 0x2000 ) \ | |
| ROM_IGNORE( 0x2000 ) | |
| // all of these are half size :/ | |
| #define LOAD_KANJI_ROMS \ | |
| ROM_REGION( 0x80000, "raw_kanji", ROMREGION_ERASEFF ) \ | |
| ROM_LOAD16_BYTE( "24256c-x01.bin", 0x00000, 0x4000, BAD_DUMP CRC(28ec1375) SHA1(9d8e98e703ce0f483df17c79f7e841c5c5cd1692) ) \ | |
| ROM_CONTINUE( 0x20000, 0x4000 ) \ | |
| ROM_LOAD16_BYTE( "24256c-x02.bin", 0x00001, 0x4000, BAD_DUMP CRC(90985158) SHA1(78fb106131a3f4eb054e87e00fe4f41193416d65) ) \ | |
| ROM_CONTINUE( 0x20001, 0x4000 ) \ | |
| ROM_LOAD16_BYTE( "24256c-x03.bin", 0x40000, 0x4000, BAD_DUMP CRC(d4893543) SHA1(eb8c1bee0f694e1e0c145a24152222d4e444e86f) ) \ | |
| ROM_CONTINUE( 0x60000, 0x4000 ) \ | |
| ROM_LOAD16_BYTE( "24256c-x04.bin", 0x40001, 0x4000, BAD_DUMP CRC(5dec0fc2) SHA1(41000da14d0805ed0801b31eb60623552e50e41c) ) \ | |
| ROM_CONTINUE( 0x60001, 0x4000 ) \ | |
| ROM_REGION( 0x100000, "kanji", ROMREGION_ERASEFF ) \ | |
| ROM_REGION( 0x80000, "new_chargen", ROMREGION_ERASEFF ) | |
| /* | |
| F - 8086 5 | |
| */ | |
| ROM_START( pc9801f ) | |
| ROM_REGION16_LE( 0x18000, "ipl", ROMREGION_ERASEFF ) | |
| ROM_LOAD16_BYTE( "urm01-02.bin", 0x00000, 0x4000, CRC(cde04615) SHA1(8f6fb587c0522af7a8131b45d13f8ae8fc60e8cd) ) | |
| ROM_LOAD16_BYTE( "urm02-02.bin", 0x00001, 0x4000, CRC(9e39b8d1) SHA1(df1f3467050a41537cb9d071e4034f0506f07eda) ) | |
| ROM_LOAD16_BYTE( "urm03-02.bin", 0x08000, 0x4000, CRC(95e79064) SHA1(c27d96949fad82aeb26e316200c15a4891e1063f) ) | |
| ROM_LOAD16_BYTE( "urm04-02.bin", 0x08001, 0x4000, CRC(e4855a53) SHA1(223f66482c77409706cfc64c214cec7237c364e9) ) | |
| ROM_LOAD16_BYTE( "urm05-02.bin", 0x10000, 0x4000, CRC(ffefec65) SHA1(106e0d920e857e59da12225a489ca2756ca405c1) ) | |
| ROM_LOAD16_BYTE( "urm06-02.bin", 0x10001, 0x4000, CRC(1147760b) SHA1(4e0299091dfd53ac7988d40c5a6775a10389faac) ) | |
| ROM_REGION16_LE( 0x1000, "fdc_bios_2dd", ROMREGION_ERASEFF ) | |
| ROM_REGION16_LE( 0x1000, "fdc_bios_2hd", ROMREGION_ERASEFF ) | |
| ROM_REGION( 0x20000, "fdc_data", ROMREGION_ERASEFF ) // 2dd fdc bios, presumably bad size (should be 0x800 for each rom) | |
| ROM_LOAD16_BYTE( "urf01-01.bin", 0x00000, 0x4000, BAD_DUMP CRC(2f5ae147) SHA1(69eb264d520a8fc826310b4fce3c8323867520ee) ) | |
| ROM_LOAD16_BYTE( "urf02-01.bin", 0x00001, 0x4000, BAD_DUMP CRC(62a86928) SHA1(4160a6db096dbeff18e50cbee98f5d5c1a29e2d1) ) | |
| ROM_LOAD( "2hdif.rom", 0x10000, 0x1000, BAD_DUMP CRC(9652011b) SHA1(b607707d74b5a7d3ba211825de31a8f32aec8146) ) // needs dumping from a board | |
| ROM_REGION( 0x800, "kbd_mcu", ROMREGION_ERASEFF) | |
| ROM_LOAD( "mcu.bin", 0x0000, 0x0800, NO_DUMP ) //connected through a i8251 UART, needs decapping | |
| /* note: ROM names of following two might be swapped */ | |
| ROM_REGION( 0x80000, "chargen", 0 ) | |
| ROM_LOAD( "d23128c-17.bin", 0x00000, 0x00800, BAD_DUMP CRC(eea57180) SHA1(4aa037c684b72ad4521212928137d3369174eb1e) ) //original is a bad dump, this is taken from i386 model | |
| ROM_LOAD("hn613128pac8.bin",0x00800, 0x01000, BAD_DUMP CRC(b5a15b5c) SHA1(e5f071edb72a5e9a8b8b1c23cf94a74d24cb648e) ) //bad dump, 8x16 charset? (it's on the kanji board) | |
| LOAD_KANJI_ROMS | |
| ROM_END | |
| /* | |
| UX - 80286 10 + V30 8 | |
| */ | |
| ROM_START( pc9801ux ) | |
| ROM_REGION16_LE( 0x30000, "ipl", ROMREGION_ERASEFF ) | |
| ROM_LOAD( "itf_ux.rom", 0x10000, 0x08000, CRC(c7942563) SHA1(61bb210d64c7264be939b11df1e9cd14ffeee3c9) ) | |
| ROM_LOAD( "bios_ux.rom", 0x18000, 0x18000, BAD_DUMP CRC(97375ca2) SHA1(bfe458f671d90692104d0640730972ca8dc0a100) ) | |
| ROM_REGION( 0x80000, "chargen", 0 ) | |
| ROM_LOAD( "font_ux.rom", 0x000000, 0x046800, BAD_DUMP CRC(19a76eeb) SHA1(96a006e8515157a624599c2b53a581ae0dd560fd) ) | |
| LOAD_KANJI_ROMS | |
| // LOAD_IDE_ROM | |
| ROM_END | |
| /* | |
| RX - 80286 12 (no V30?) | |
| The bios is from a 386 model not an RX | |
| */ | |
| ROM_START( pc9801rx ) | |
| ROM_REGION16_LE( 0x30000, "ipl", ROMREGION_ERASEFF ) | |
| ROM_LOAD( "itf_rs.rom", 0x10000, 0x08000, BAD_DUMP CRC(c1815325) SHA1(a2fb11c000ed7c976520622cfb7940ed6ddc904e) ) | |
| ROM_LOAD( "bios_rx.rom", 0x18000, 0x18000, BAD_DUMP CRC(0a682b93) SHA1(76a7360502fa0296ea93b4c537174610a834d367) ) | |
| // fix csum | |
| ROM_FILL(0x2fffe, 1, 0x0d) | |
| ROM_REGION( 0x80000, "chargen", 0 ) | |
| ROM_LOAD( "font_rx.rom", 0x000000, 0x046800, BAD_DUMP CRC(456d9fc7) SHA1(78ba9960f135372825ab7244b5e4e73a810002ff) ) | |
| LOAD_KANJI_ROMS | |
| LOAD_IDE_ROM | |
| ROM_END | |
| /* | |
| RS - 386SX 16 | |
| (note: might be a different model!) | |
| */ | |
| ROM_START( pc9801rs ) | |
| ROM_REGION16_LE( 0x30000, "ipl", ROMREGION_ERASEFF ) | |
| ROM_LOAD( "itf_rs.rom", 0x10000, 0x08000, CRC(c1815325) SHA1(a2fb11c000ed7c976520622cfb7940ed6ddc904e) ) | |
| ROM_LOAD( "bios_rs.rom", 0x18000, 0x18000, BAD_DUMP CRC(315d2703) SHA1(4f208d1dbb68373080d23bff5636bb6b71eb7565) ) | |
| /* following is an emulator memory dump, should be checked and eventually nuked if nothing worth is there */ | |
| ROM_REGION( 0x100000, "memory", 0 ) | |
| ROM_LOAD( "00000.rom", 0x00000, 0x8000, CRC(6e299128) SHA1(d0e7d016c005cdce53ea5ecac01c6f883b752b80) ) | |
| ROM_LOAD( "c0000.rom", 0xc0000, 0x8000, CRC(1b43eabd) SHA1(ca711c69165e1fa5be72993b9a7870ef6d485249) ) // 0xff everywhere | |
| ROM_LOAD( "c8000.rom", 0xc8000, 0x8000, CRC(f2a262b0) SHA1(fe97d2068d18bbb7425d9774e2e56982df2aa1fb) ) | |
| ROM_LOAD( "d0000.rom", 0xd0000, 0x8000, CRC(1b43eabd) SHA1(ca711c69165e1fa5be72993b9a7870ef6d485249) ) // 0xff everywhere | |
| ROM_LOAD( "e8000.rom", 0xe8000, 0x8000, CRC(4e32081e) SHA1(e23571273b7cad01aa116cb7414c5115a1093f85) ) // contains n-88 basic (86) v2.0 | |
| ROM_LOAD( "f0000.rom", 0xf0000, 0x8000, CRC(4da85a6c) SHA1(18dccfaf6329387c0c64cc4c91b32c25cde8bd5a) ) | |
| ROM_LOAD( "f8000.rom", 0xf8000, 0x8000, CRC(2b1e45b1) SHA1(1fec35f17d96b2e2359e3c71670575ad9ff5007e) ) | |
| ROM_REGION( 0x80000, "chargen", 0 ) | |
| ROM_LOAD( "font_rs.rom", 0x00000, 0x46800, BAD_DUMP CRC(da370e7a) SHA1(584d0c7fde8c7eac1f76dc5e242102261a878c5e) ) | |
| LOAD_KANJI_ROMS | |
| LOAD_IDE_ROM | |
| ROM_END | |
| /* | |
| BX2/U2 - 486SX - (should be 33, but "dumper" note says it's 25 MHz) | |
| Yet another franken-romset done with direct memory dump, shrug | |
| */ | |
| ROM_START( pc9801bx2 ) | |
| ROM_REGION16_LE( 0x30000, "ipl", ROMREGION_ERASEFF ) | |
| ROM_LOAD( "pc98bank0.bin", 0x00000, 0x08000, BAD_DUMP CRC(bfd100cc) SHA1(cf8e6a5679cca7761481abef0ba4b35ead39efdb) ) | |
| ROM_LOAD( "pc98bank1.bin", 0x00000, 0x08000, BAD_DUMP CRC(d0562af8) SHA1(2c4fd27eb598f4b8a00f3e86941ba27007d58e47) ) | |
| ROM_LOAD( "pc98bank2.bin", 0x00000, 0x08000, BAD_DUMP CRC(12818a14) SHA1(9c31e8ac85d78fa779d6bbc2095557065294ec09) ) | |
| ROM_LOAD( "pc98bank3.bin", 0x00000, 0x08000, BAD_DUMP CRC(d0bda44e) SHA1(c1022a3b2be4d2a1e43914df9e4605254e5f99d5) ) | |
| ROM_LOAD( "pc98bank4.bin", 0x10000, 0x08000, BAD_DUMP CRC(be8092f4) SHA1(12c8a166b8c6ebbef85568b67e1f098562883365) ) | |
| ROM_LOAD( "pc98bank5.bin", 0x18000, 0x08000, BAD_DUMP CRC(4e32081e) SHA1(e23571273b7cad01aa116cb7414c5115a1093f85) ) | |
| ROM_LOAD( "pc98bank6.bin", 0x20000, 0x08000, BAD_DUMP CRC(f878c160) SHA1(cad47f09075ffe4f7b51bb937c9f716c709d4596) ) | |
| ROM_LOAD( "pc98bank7.bin", 0x28000, 0x08000, BAD_DUMP CRC(1bd6537b) SHA1(ff9ee1c976a12b87851635ce8991ac4ad607675b) ) | |
| ROM_REGION( 0x80000, "chargen", 0 ) | |
| ROM_LOAD( "font_rs.rom", 0x00000, 0x46800, BAD_DUMP CRC(da370e7a) SHA1(584d0c7fde8c7eac1f76dc5e242102261a878c5e) ) | |
| LOAD_KANJI_ROMS | |
| LOAD_IDE_ROM | |
| ROM_END | |
| /* | |
| VM - V30 8/10 | |
| TODO: missing itf roms, if they exist | |
| */ | |
| ROM_START( pc9801vm ) | |
| ROM_REGION16_LE( 0x30000, "ipl", ROMREGION_ERASEFF ) | |
| // ROM_LOAD( "itf_ux.rom", 0x10000, 0x08000, BAD_DUMP CRC(c7942563) SHA1(61bb210d64c7264be939b11df1e9cd14ffeee3c9) ) | |
| // ROM_LOAD( "bios_vm.rom", 0x18000, 0x18000, CRC(2e2d7cee) SHA1(159549f845dc70bf61955f9469d2281a0131b47f) ) | |
| // bios | |
| ROM_LOAD16_BYTE( "cpu_board_1a_23128e.bin", 0x10001, 0x4000, CRC(9965c914) SHA1(1ed318b774340bd532ef02ac02f39a012354dbf8) ) | |
| ROM_LOAD16_BYTE( "cpu_board_4a_d23128ec.bin", 0x10000, 0x4000, CRC(e7c24a70) SHA1(cc9584b8e56b391f103e9d559d397d0bc6d00b35) ) | |
| ROM_LOAD16_BYTE( "cpu_board_2a_d23c256ec.bin", 0x08001, 0x4000, CRC(3874970d) SHA1(e50ec5ae38f00dbfd156288dd42c7f2a2bf8bc35) ) | |
| ROM_CONTINUE( 0x00001, 0x4000 ) | |
| ROM_LOAD16_BYTE( "cpu_board_3a_23c256e.bin", 0x08000, 0x4000, CRC(4128276e) SHA1(32acb7eee779a31838a17ce51b05a9a987af4099) ) | |
| ROM_CONTINUE( 0x00000, 0x4000 ) | |
| ROM_REGION( 0x80000, "chargen", 0 ) | |
| // ROM_LOAD( "font_vm.rom", 0x000000, 0x046800, BAD_DUMP CRC(456d9fc7) SHA1(78ba9960f135372825ab7244b5e4e73a810002ff) ) | |
| // TODO: contains 8x8 "graphics" characters but we don't use them | |
| ROM_LOAD( "main_board_12f_d2364ec.bin", 0x000000, 0x002000, CRC(11197271) SHA1(8dbd2f25daeed545ea2c74d849f0a209ceaf4dd7) ) | |
| ROM_REGION( 0x80000, "raw_kanji", ROMREGION_ERASEFF ) | |
| // on main board, uPD23100 type roms | |
| // kanji and most other 16x16 characters | |
| ROM_LOAD16_BYTE( "main_board_12h_231000.bin", 0x00000, 0x20000, CRC(ecc2c062) SHA1(36c935c0f26c02a2b1ea46f5b6cd03fc11c7b003) ) | |
| ROM_LOAD16_BYTE( "main_board_10h_231000.bin", 0x00001, 0x20000, CRC(91d78281) SHA1(85a18ad40e281e68071f91800201e43d78fb4f1c) ) | |
| // 8x16 characters and the remaining 16x16 characters, with inverted bit order like 12f | |
| ROM_LOAD16_BYTE( "main_board_8h_d23256ac.bin", 0x40000, 0x04000, CRC(62a32ba6) SHA1(cdab480ae0dad9d128e52afb15e6c0b2b122cc3f) ) | |
| ROM_CONTINUE( 0x40001, 0x04000 ) | |
| ROM_REGION( 0x100000, "kanji", ROMREGION_ERASEFF ) | |
| ROM_REGION( 0x80000, "new_chargen", ROMREGION_ERASEFF ) | |
| // LOAD_KANJI_ROMS | |
| // LOAD_IDE_ROM | |
| ROM_END | |
| /* | |
| VM11 - V30 8/10 | |
| TODO: this ISN'T a real VM11 model! | |
| */ | |
| ROM_START( pc9801vm11 ) | |
| ROM_REGION16_LE( 0x30000, "ipl", ROMREGION_ERASEFF ) | |
| ROM_LOAD( "itf_ux.rom", 0x10000, 0x08000, BAD_DUMP CRC(c7942563) SHA1(61bb210d64c7264be939b11df1e9cd14ffeee3c9) ) | |
| ROM_LOAD( "bios_vm.rom", 0x18000, 0x18000, CRC(2e2d7cee) SHA1(159549f845dc70bf61955f9469d2281a0131b47f) ) | |
| ROM_REGION( 0x80000, "chargen", 0 ) | |
| ROM_LOAD( "font_vm.rom", 0x000000, 0x046800, BAD_DUMP CRC(456d9fc7) SHA1(78ba9960f135372825ab7244b5e4e73a810002ff) ) | |
| LOAD_KANJI_ROMS | |
| // LOAD_IDE_ROM | |
| ROM_END | |
| /* | |
| 98MATE A - 80486SX 25 | |
| (note: might be a different model!) | |
| */ | |
| ROM_START( pc9821 ) | |
| ROM_REGION16_LE( 0x30000, "ipl", ROMREGION_ERASEFF ) | |
| ROM_LOAD( "itf.rom", 0x10000, 0x08000, CRC(dd4c7bb8) SHA1(cf3aa193df2722899066246bccbed03f2e79a74a) ) | |
| ROM_LOAD( "bios.rom", 0x18000, 0x18000, BAD_DUMP CRC(34a19a59) SHA1(2e92346727b0355bc1ec9a7ded1b444a4917f2b9) ) | |
| ROM_FILL(0x24c40, 4, 0) // hide the _32_ marker until we have a 32-bit clean IDE bios otherwise windows tries to | |
| // make a 32-bit call into 16-bit code | |
| ROM_FILL(0x27ffe, 1, 0x92) | |
| ROM_FILL(0x27fff, 1, 0xd7) | |
| ROM_REGION( 0x80000, "chargen", 0 ) | |
| ROM_LOAD( "font.rom", 0x00000, 0x46800, BAD_DUMP CRC(a61c0649) SHA1(554b87377d176830d21bd03964dc71f8e98676b1) ) | |
| LOAD_KANJI_ROMS | |
| LOAD_IDE_ROM | |
| ROM_END | |
| /* | |
| As - 80486DX 33 | |
| */ | |
| ROM_START( pc9821as ) | |
| ROM_REGION( 0x80000, "biosrom", ROMREGION_ERASEFF ) | |
| // ROM_LOAD( "itf.rom", 0x10000, 0x08000, BAD_DUMP CRC(dd4c7bb8) SHA1(cf3aa193df2722899066246bccbed03f2e79a74a) ) | |
| // ROM_LOAD( "bios_as.rom", 0x18000, 0x18000, BAD_DUMP CRC(0a682b93) SHA1(76a7360502fa0296ea93b4c537174610a834d367) ) | |
| ROM_LOAD( "mvs0100-1.bin", 0x00000, 0x80000, CRC(ca37b631) SHA1(8c481dd0608d6c27235bc88bd77e345628dc28a1) ) | |
| ROM_REGION16_LE( 0x30000, "ipl", ROMREGION_ERASEFF ) | |
| // TODO: not quite right yet, needs actual itf rom loaded | |
| ROM_COPY( "biosrom", 0x20000, 0x10000, 0x08000 ) | |
| ROM_COPY( "biosrom", 0x30000, 0x18000, 0x18000 ) | |
| ROM_REGION( 0x80000, "chargen", 0 ) | |
| ROM_LOAD( "font_as.rom", 0x000000, 0x046800, BAD_DUMP CRC(456d9fc7) SHA1(78ba9960f135372825ab7244b5e4e73a810002ff) ) | |
| LOAD_KANJI_ROMS | |
| LOAD_IDE_ROM | |
| ROM_END | |
| /* | |
| PC-9821AP2/U8W | |
| 80486DX2 66MHz | |
| DOS 5.0, Windows 3.1 | |
| 5.6MB RAM, up to 73.6MB | |
| 340MB HD | |
| Expansion slot C-BUS4 (4) | |
| Graphics controller S3 86C928 | |
| */ | |
| ROM_START( pc9821ap2 ) | |
| ROM_REGION( 0x80000, "biosrom", ROMREGION_ERASEFF ) | |
| ROM_DEFAULT_BIOS("phd0104") | |
| ROM_SYSTEM_BIOS(0, "phd0104", "PHD0104") | |
| ROMX_LOAD( "phd0104.rom", 0x000000, 0x80000, CRC(da73b372) SHA1(2c15b63a0869b81ef7f04972dbb0975f4e77d384), ROM_BIOS(0) ) | |
| ROM_SYSTEM_BIOS(1, "phd0102", "PHD0102") | |
| ROMX_LOAD( "phd0102.rom", 0x000000, 0x80000, CRC(3036774c) SHA1(59856a348f156adf5eca06326f967aca54ff871c), ROM_BIOS(1) ) | |
| ROM_REGION16_LE( 0x30000, "ipl", ROMREGION_ERASEFF ) | |
| // TODO: identify ROM banks | |
| ROM_COPY( "biosrom", 0x20000, 0x10000, 0x08000 ) | |
| ROM_COPY( "biosrom", 0x30000, 0x18000, 0x18000 ) | |
| ROM_REGION( 0x80000, "chargen", 0 ) | |
| ROM_LOAD( "font.rom", 0x00000, 0x46800, BAD_DUMP CRC(a61c0649) SHA1(554b87377d176830d21bd03964dc71f8e98676b1) ) | |
| LOAD_KANJI_ROMS | |
| LOAD_IDE_ROM | |
| ROM_END | |
| /* | |
| 98NOTE - i486SX 33 | |
| */ | |
| ROM_START( pc9821ne ) | |
| ROM_REGION16_LE( 0x30000, "ipl", ROMREGION_ERASEFF ) | |
| ROM_LOAD( "itf.rom", 0x10000, 0x08000, CRC(dd4c7bb8) SHA1(cf3aa193df2722899066246bccbed03f2e79a74a) ) | |
| ROM_LOAD( "bios_ne.rom", 0x18000, 0x18000, BAD_DUMP CRC(2ae070c4) SHA1(d7963942042bfd84ed5fc9b7ba8f1c327c094172) ) | |
| ROM_REGION( 0x80000, "chargen", 0 ) | |
| ROM_LOAD( "font_ne.rom", 0x00000, 0x46800, BAD_DUMP CRC(fb213757) SHA1(61525826d62fb6e99377b23812faefa291d78c2e) ) | |
| LOAD_KANJI_ROMS | |
| LOAD_IDE_ROM | |
| ROM_END | |
| /* | |
| 98MULTi Ce2 - 80486SX 25 | |
| */ | |
| ROM_START( pc9821ce2 ) | |
| ROM_REGION16_LE( 0x30000, "ipl", ROMREGION_ERASEFF ) | |
| ROM_LOAD( "itf_ce2.rom", 0x10000, 0x008000, CRC(273e9e88) SHA1(9bca7d5116788776ed0f297bccb4dfc485379b41) ) | |
| ROM_LOAD( "bios_ce2.rom", 0x18000, 0x018000, BAD_DUMP CRC(76affd90) SHA1(910fae6763c0cd59b3957b6cde479c72e21f33c1) ) | |
| ROM_REGION( 0x80000, "chargen", 0 ) | |
| ROM_LOAD( "font_ce2.rom", 0x00000, 0x046800, BAD_DUMP CRC(d1c2702a) SHA1(e7781e9d35b6511d12631641d029ad2ba3f7daef) ) | |
| LOAD_KANJI_ROMS | |
| LOAD_IDE_ROM | |
| ROM_END | |
| /* | |
| 98MATE X - 486/Pentium based | |
| */ | |
| ROM_START( pc9821xs ) | |
| ROM_REGION16_LE( 0x30000, "ipl", ROMREGION_ERASEFF ) | |
| ROM_LOAD( "itf.rom", 0x10000, 0x008000, BAD_DUMP CRC(dd4c7bb8) SHA1(cf3aa193df2722899066246bccbed03f2e79a74a) ) | |
| ROM_LOAD( "bios_xs.rom", 0x18000, 0x018000, BAD_DUMP CRC(0a682b93) SHA1(76a7360502fa0296ea93b4c537174610a834d367) ) | |
| ROM_REGION( 0x80000, "chargen", 0 ) | |
| ROM_LOAD( "font_xs.rom", 0x00000, 0x046800, BAD_DUMP CRC(c9a77d8f) SHA1(deb8563712eb2a634a157289838b95098ba0c7f2) ) | |
| LOAD_KANJI_ROMS | |
| LOAD_IDE_ROM | |
| ROM_END | |
| /* | |
| 9821Xa16 | |
| Pentium P54C @ 166 | |
| 32MB | |
| 3.5"2DD/2HDx1, 8xCD-ROM | |
| CBus: 3 slots | |
| */ | |
| ROM_START( pc9821xa16 ) | |
| ROM_REGION16_LE( 0x40000, "biosrom", ROMREGION_ERASEFF ) | |
| ROM_LOAD( "pc-9821xa16_g8yewa_a1_wsg8b01_ab28f200b5-t.bin", 0x00000, 0x040000, CRC(f99c8ce2) SHA1(2bc328d2c496046f6f4f39b0637e90b713a63155) ) // SOP44 | |
| ROM_REGION16_LE( 0x30000, "ipl", ROMREGION_ERASEFF ) | |
| // TODO: all of the 256k space seems valid | |
| ROM_COPY( "biosrom", 0x28000, 0x00000, 0x18000 ) | |
| ROM_COPY( "biosrom", 0x00000, 0x18000, 0x18000 ) | |
| ROM_REGION( 0x80000, "chargen", 0 ) | |
| ROM_LOAD( "font.rom", 0x00000, 0x46800, BAD_DUMP CRC(a61c0649) SHA1(554b87377d176830d21bd03964dc71f8e98676b1) ) | |
| LOAD_KANJI_ROMS | |
| LOAD_IDE_ROM | |
| ROM_END | |
| /* | |
| pc-9821Ra20 (98MATE R) | |
| Pentium Pro @ 200 | |
| 32MB | |
| 3.5"2DD/2HDx1, 8xCD-ROM | |
| CBus: 3 slots | |
| */ | |
| ROM_START( pc9821ra20 ) | |
| ROM_REGION16_LE( 0x40000, "biosrom", ROMREGION_ERASEFF ) | |
| ROM_LOAD( "g8wtp_a13_wtp8b01_ab28f200b5-t.bin", 0x00000, 0x040000, CRC(cd3acc5c) SHA1(746490d7f3d8d0e8df865315adaaae65f3fd0425) ) // SOP44 | |
| ROM_REGION16_LE( 0x30000, "ipl", ROMREGION_ERASEFF ) | |
| // TODO: all of the 256k space seems valid | |
| ROM_COPY( "biosrom", 0x28000, 0x00000, 0x18000 ) | |
| ROM_COPY( "biosrom", 0x00000, 0x18000, 0x18000 ) | |
| ROM_REGION( 0x80000, "chargen", 0 ) | |
| ROM_LOAD( "font.rom", 0x00000, 0x46800, BAD_DUMP CRC(a61c0649) SHA1(554b87377d176830d21bd03964dc71f8e98676b1) ) | |
| LOAD_KANJI_ROMS | |
| LOAD_IDE_ROM | |
| ROM_END | |
| /* | |
| pc-9821Ra333 (98MATE R) | |
| Celeron @ 333 | |
| 32MB, max 256 MB (ECC EDO RAM) | |
| 3.5x1, 24xCD-ROM | |
| CBus: 3 slots, PCI: 2 slots | |
| */ | |
| ROM_START( pc9821ra333 ) | |
| ROM_REGION16_LE( 0x40000, "biosrom", ROMREGION_ERASEFF ) | |
| ROM_LOAD( "g8ykkw.bin", 0x00000, 0x040000, CRC(c605ef31) SHA1(3779aed757f21eb75093c1bfcbf18a232c198ee6) ) | |
| ROM_REGION16_LE( 0x30000, "ipl", ROMREGION_ERASEFF ) | |
| // TODO: all of the 256k space seems valid | |
| ROM_COPY( "biosrom", 0x28000, 0x00000, 0x18000 ) | |
| ROM_COPY( "biosrom", 0x00000, 0x18000, 0x18000 ) | |
| ROM_REGION( 0x80000, "chargen", 0 ) | |
| ROM_LOAD( "font.rom", 0x00000, 0x46800, BAD_DUMP CRC(a61c0649) SHA1(554b87377d176830d21bd03964dc71f8e98676b1) ) | |
| LOAD_KANJI_ROMS | |
| LOAD_IDE_ROM | |
| ROM_END | |
| /* | |
| 98MATE VALUESTAR - Pentium based | |
| */ | |
| ROM_START( pc9821v13 ) | |
| ROM_REGION16_LE( 0x30000, "ipl", ROMREGION_ERASEFF ) | |
| ROM_LOAD( "itf.rom", 0x10000, 0x08000, CRC(dd4c7bb8) SHA1(cf3aa193df2722899066246bccbed03f2e79a74a) ) | |
| ROM_LOAD( "bios_v13.rom", 0x18000, 0x18000, BAD_DUMP CRC(0a682b93) SHA1(76a7360502fa0296ea93b4c537174610a834d367) ) | |
| ROM_REGION( 0x80000, "chargen", 0 ) | |
| ROM_LOAD( "font_a.rom", 0x00000, 0x46800, BAD_DUMP CRC(c9a77d8f) SHA1(deb8563712eb2a634a157289838b95098ba0c7f2) ) | |
| LOAD_KANJI_ROMS | |
| LOAD_IDE_ROM | |
| ROM_END | |
| /* | |
| 98MATE VALUESTAR - Pentium based | |
| */ | |
| ROM_START( pc9821v20 ) | |
| ROM_REGION16_LE( 0x30000, "ipl", ROMREGION_ERASEFF ) | |
| ROM_LOAD( "itf_v20.rom", 0x10000, 0x08000, CRC(10e52302) SHA1(f95b8648e3f5a23e507a9fbda8ab2e317d8e5151) ) | |
| ROM_LOAD( "bios_v20.rom", 0x18000, 0x18000, BAD_DUMP CRC(d5d1f13b) SHA1(bf44b5f4e138e036f1b848d6616fbd41b5549764) ) | |
| ROM_REGION( 0x80000, "chargen", 0 ) | |
| ROM_LOAD( "font_v20.rom", 0x00000, 0x046800, BAD_DUMP CRC(6244c4c0) SHA1(9513cac321e89b4edb067b30e9ecb1adae7e7be7) ) | |
| LOAD_KANJI_ROMS | |
| LOAD_IDE_ROM | |
| ROM_END | |
| /* | |
| Epson PC-386M | |
| i386SX-16 @ 16 | |
| 1MB | |
| 3.5"2DD/2HDx2 | |
| CBus: 3slots | |
| */ | |
| ROM_START( pc386m ) | |
| ROM_REGION16_LE( 0x30000, "ipl", ROMREGION_ERASEFF ) | |
| ROM_LOAD( "cwma-a02.bin", 0x10000, 0x08000, CRC(d2c357a4) SHA1(819c9a1fc92124a8d6a85339c74651add7efaf92) ) | |
| ROM_CONTINUE( 0x18000, 0x18000 ) | |
| ROM_REGION( 0x80000, "chargen", 0 ) | |
| ROM_LOAD( "font_486mu.rom", 0x0000, 0x46800, BAD_DUMP CRC(456d9fc7) SHA1(78ba9960f135372825ab7244b5e4e73a810002ff)) | |
| LOAD_KANJI_ROMS | |
| LOAD_IDE_ROM | |
| ROM_END | |
| /* | |
| Epson PC-486SE | |
| i486SX @ 25 MHz | |
| 1.6 MB of conventional memory (???) | |
| 17.6 MB | |
| CBus: 2slots | |
| */ | |
| ROM_START( pc486se ) | |
| ROM_REGION16_LE( 0x20000, "biosrom", ROMREGION_ERASEFF ) | |
| ROM_LOAD( "1699ma_cw99-a03.bin", 0x00000, 0x20000, CRC(f03df711) SHA1(88614746e01c7d3cff9f3b8ce0a598830a77d1dc) ) | |
| ROM_REGION16_LE( 0x30000, "ipl", ROMREGION_ERASEFF ) | |
| // this looks convoluted | |
| ROM_COPY( "biosrom", 0x08000, 0x00000, 0x08000 ) // tests this area at PC=0xf5149 | |
| ROM_COPY( "biosrom", 0x00000, 0x10000, 0x08000 ) | |
| ROM_COPY( "biosrom", 0x10000, 0x08000, 0x08000 ) | |
| // ROM_FILL( 0x18000, 0x08000, 0x90) // untested by BIOS | |
| ROM_COPY( "biosrom", 0x10000, 0x20000, 0x08000 ) // PC=f5113 bankswitch into same area, correct? | |
| ROM_COPY( "biosrom", 0x18000, 0x28000, 0x08000 ) | |
| ROM_REGION( 0x80000, "chargen", 0 ) | |
| ROM_LOAD( "font_486mu.rom", 0x0000, 0x46800, BAD_DUMP CRC(456d9fc7) SHA1(78ba9960f135372825ab7244b5e4e73a810002ff)) | |
| LOAD_KANJI_ROMS | |
| LOAD_IDE_ROM | |
| ROM_END | |
| /* | |
| Epson PC-486MU | |
| i486SX-33 @ 33 | |
| 8MB RAM | |
| 3.5'2DD/2HDx2, 2xCD-ROM | |
| CBus: 3 slots | |
| */ | |
| ROM_START( pc486mu ) | |
| ROM_REGION16_LE( 0x20000, "biosrom", ROMREGION_ERASEFF ) | |
| ROM_LOAD( "pc-486mu_hn27c1024.bin", 0x00000, 0x20000, CRC(113268e1) SHA1(2a630abc825b2808f9f8fb65c6cb1fb7e7f6c710)) | |
| // ROM_LOAD( "bios_486mu.rom", 0x00000, 0x18000, BAD_DUMP CRC(57b5d701) SHA1(15029800842e93e07615b0fd91fb9f2bfe3e3c24)) | |
| ROM_REGION16_LE( 0x30000, "ipl", ROMREGION_ERASEFF ) | |
| // backported from pc486se | |
| ROM_COPY( "biosrom", 0x08000, 0x00000, 0x08000 ) | |
| ROM_COPY( "biosrom", 0x00000, 0x10000, 0x08000 ) | |
| ROM_COPY( "biosrom", 0x10000, 0x08000, 0x08000 ) | |
| // ROM_FILL( 0x18000, 0x08000, 0x90) // untested by BIOS | |
| ROM_COPY( "biosrom", 0x10000, 0x20000, 0x08000 ) | |
| ROM_COPY( "biosrom", 0x18000, 0x28000, 0x08000 ) | |
| ROM_REGION( 0x80000, "chargen", 0 ) | |
| ROM_LOAD( "font_486mu.rom", 0x0000, 0x46800, BAD_DUMP CRC(456d9fc7) SHA1(78ba9960f135372825ab7244b5e4e73a810002ff)) | |
| LOAD_KANJI_ROMS | |
| LOAD_IDE_ROM | |
| ROM_END | |
| void pc9801_state::init_pc9801_kanji() | |
| { | |
| #define copy_kanji_strip(_dst,_src,_fill_type) \ | |
| for (uint32_t i = _dst, k = _src; i < _dst + 0x20; i++, k++) \ | |
| { \ | |
| for (uint32_t j = 0; j < 0x20; j++) \ | |
| kanji[j+(i << 5)] = _fill_type ? new_chargen[j+(k << 5)] : 0; \ | |
| } | |
| uint32_t pcg_tile; | |
| uint8_t *kanji = memregion("kanji")->base(); | |
| uint8_t *raw_kanji = memregion("raw_kanji")->base(); | |
| uint8_t *new_chargen = memregion("new_chargen")->base(); | |
| uint8_t *chargen = memregion("chargen")->base(); | |
| /* Convert the ROM bitswap here from the original structure */ | |
| /* TODO: kanji bitswap should be completely wrong, will check it out once that a dump is remade. */ | |
| for (uint32_t i = 0; i < 0x80000 / 0x20; i++) | |
| { | |
| for (uint32_t j = 0; j < 0x20; j++) | |
| { | |
| pcg_tile = bitswap<16>(i,15,14,13,12,11,7,6,5,10,9,8,4,3,2,1,0) << 5; | |
| kanji[j+(i << 5)] = raw_kanji[j+pcg_tile]; | |
| } | |
| } | |
| /* convert charset into even/odd structure */ | |
| for (uint32_t i = 0; i < 0x80000 / 0x20; i++) | |
| { | |
| for (uint32_t j = 0; j < 0x10; j++) | |
| { | |
| new_chargen[j*2 + (i << 5)] = chargen[j + (i << 5)]; | |
| new_chargen[j*2 + (i << 5) + 1] = chargen[j + (i << 5) + 0x10]; | |
| } | |
| } | |
| /* now copy the data from the fake roms into our kanji struct */ | |
| copy_kanji_strip(0x0800, -1,0); copy_kanji_strip(0x0820, -1,0); copy_kanji_strip(0x0840, -1,0); copy_kanji_strip(0x0860, -1,0); | |
| copy_kanji_strip(0x0900, -1,0); copy_kanji_strip(0x0920,0x3c0,1); copy_kanji_strip(0x0940,0x3e0,1); copy_kanji_strip(0x0960,0x400,1); | |
| copy_kanji_strip(0x0a00, -1,0); copy_kanji_strip(0x0a20,0x420,1); copy_kanji_strip(0x0a40,0x440,1); copy_kanji_strip(0x0a60,0x460,1); | |
| copy_kanji_strip(0x0b00, -1,0); copy_kanji_strip(0x0b20,0x480,1); copy_kanji_strip(0x0b40,0x4a0,1); copy_kanji_strip(0x0b60,0x4c0,1); | |
| copy_kanji_strip(0x0c00, -1,0); copy_kanji_strip(0x0c20,0x4e0,1); copy_kanji_strip(0x0c40,0x500,1); copy_kanji_strip(0x0c60,0x520,1); | |
| copy_kanji_strip(0x0d00, -1,0); copy_kanji_strip(0x0d20,0x540,1); copy_kanji_strip(0x0d40,0x560,1); copy_kanji_strip(0x0d60,0x580,1); | |
| copy_kanji_strip(0x0e00, -1,0); copy_kanji_strip(0x0e20, -1,0); copy_kanji_strip(0x0e40, -1,0); copy_kanji_strip(0x0e60, -1,0); | |
| copy_kanji_strip(0x0f00, -1,0); copy_kanji_strip(0x0f20, -1,0); copy_kanji_strip(0x0f40, -1,0); copy_kanji_strip(0x0f60, -1,0); | |
| { | |
| int src_1,dst_1; | |
| for(src_1=0x1000,dst_1=0x660;src_1<0x8000;src_1+=0x100,dst_1+=0x60) | |
| { | |
| copy_kanji_strip(src_1, -1,0); | |
| copy_kanji_strip(src_1+0x20,dst_1+0x00,1); | |
| copy_kanji_strip(src_1+0x40,dst_1+0x20,1); | |
| copy_kanji_strip(src_1+0x60,dst_1+0x40,1); | |
| } | |
| } | |
| #undef copy_kanji_strip | |
| } | |
| void pc9801_state::init_pc9801vm_kanji() | |
| { | |
| uint32_t raw_tile; | |
| uint8_t *chargen = memregion("chargen")->base(); | |
| uint8_t *raw_kanji = memregion("raw_kanji")->base(); | |
| uint8_t *kanji = memregion("kanji")->base(); | |
| /* swap bits for 8x8 characters, discard 8x8 "graphics" characters */ | |
| /* TODO: should we keep and use the "graphics" characters? */ | |
| for( uint32_t i = 0; i < 0x100; i++ ) | |
| { | |
| for( uint32_t j = 0; j < 8; j++ ) | |
| { | |
| chargen[i*8+j] = bitswap<8>(chargen[i*0x10+j],0,1,2,3,4,5,6,7); | |
| } | |
| } | |
| /* swap bits for 8x16 characters */ | |
| for( uint32_t i = 0; i < 0x100; i++ ) | |
| { | |
| for( uint32_t j = 0; j < 0x10; j++ ) | |
| { | |
| chargen[0x100*8+i*0x10+j] = bitswap<8>(chargen[0x100*0x10+i*0x10+j],0,1,2,3,4,5,6,7); | |
| } | |
| } | |
| /* 16x16 0x0020-0x077f */ | |
| for( uint32_t hibyte = 0x00; hibyte <= 0x07; hibyte++ ) | |
| { | |
| for( uint32_t lobyte = 0x20; lobyte <= 0x7f; lobyte++ ) | |
| { | |
| raw_tile = bitswap<16>(hibyte*0x100+lobyte,15,14,13,12,11,7,6,5,10,9,8,4,3,2,1,0) * 0x20; | |
| for( uint32_t line = 0; line < 0x20; line++ ) | |
| { | |
| kanji[(hibyte*0x100+lobyte)*0x20+line] = raw_kanji[raw_tile+line]; | |
| } | |
| } | |
| } | |
| /* 16x16 0x0820-0x0f7f (swapped bits) */ | |
| for( uint32_t hibyte = 0x08; hibyte <= 0x0f; hibyte++ ) | |
| { | |
| for( uint32_t lobyte = 0x20; lobyte <= 0x7f; lobyte++ ) | |
| { | |
| raw_tile = bitswap<16>((hibyte-0x08)*0x100+lobyte,15,14,13,12,11,7,6,5,10,9,8,4,3,2,1,0) * 0x20 + 0x2000 * 0x20; | |
| for( uint32_t line = 0; line < 0x20; line++ ) | |
| { | |
| kanji[(hibyte*0x100+lobyte)*0x20+line] = bitswap<8>(raw_kanji[raw_tile+line],0,1,2,3,4,5,6,7); | |
| } | |
| } | |
| } | |
| /* 16x16 0x1020-0x4f7f */ | |
| for( uint32_t hibyte = 0x10; hibyte <= 0x4f; hibyte++ ) | |
| { | |
| for( uint32_t lobyte = 0x20; lobyte <= 0x7f; lobyte++ ) | |
| { | |
| raw_tile = bitswap<16>((hibyte-0x10)*0x100+lobyte,15,14,7,13,6,5,12,11,10,9,8,4,3,2,1,0) * 0x20; | |
| for( uint32_t line = 0; line < 0x20; line++ ) | |
| { | |
| kanji[(hibyte*0x100+lobyte)*0x20+line] = raw_kanji[raw_tile+line]; | |
| } | |
| } | |
| } | |
| /* 16x16 0x5020-0x537f */ | |
| for( uint32_t hibyte = 0x50; hibyte <= 0x53; hibyte++ ) | |
| { | |
| for( uint32_t lobyte = 0x20; lobyte <= 0x7f; lobyte++ ) | |
| { | |
| raw_tile = bitswap<16>((hibyte-0x50)*0x100+lobyte,15,14,13,12,11,7,6,5,10,9,8,4,3,2,1,0) * 0x20 + 0x1000 * 0x20; | |
| for( uint32_t line = 0; line < 0x20; line++ ) | |
| { | |
| kanji[(hibyte*0x100+lobyte)*0x20+line] = raw_kanji[raw_tile+line]; | |
| } | |
| } | |
| } | |
| } | |
| // For simpilicity's sake we arbitrarily group those with whatever romset came first historically. | |
| // This is also repeated in SW list reports: you'd have to use an "On RS class xxx" format to indicate a bug report | |
| // specifically happening for a family group. This will be hopefully put into stone with driver splits at some point in future. | |
| // "vanilla" class (i86, E/F/M) | |
| COMP( 1983, pc9801f, 0, 0, pc9801, pc9801, pc9801_state, init_pc9801_kanji, "NEC", "PC-9801F", MACHINE_NOT_WORKING | MACHINE_IMPERFECT_SOUND) // genuine dump | |
| // N5200 (started as a vanilla PC-98 business line derivative, eventually diverged into its own thing and incorporated various Hyper 98 features. Runs proprietary PTOS) | |
| // APC III (US version of either vanilla PC9801 or N5200, aimed at business market. Runs MS-DOS 2.11/3.xx or PC-UX) | |
| // ... | |
| // VM class (V30 and/or i286) | |
| COMP( 1985, pc9801vm, pc9801ux, 0, pc9801vm, pc9801rs, pc9801_state, init_pc9801vm_kanji, "NEC", "PC-9801VM", MACHINE_NOT_WORKING | MACHINE_IMPERFECT_SOUND) // genuine dump | |
| COMP( 1985, pc9801vm11, pc9801ux, 0, pc9801vm, pc9801rs, pc9801_state, init_pc9801_kanji, "NEC", "PC-9801VM11", MACHINE_NOT_WORKING | MACHINE_IMPERFECT_SOUND) | |
| COMP( 1987, pc9801ux, 0, 0, pc9801ux, pc9801rs, pc9801_state, init_pc9801_kanji, "NEC", "PC-9801UX", MACHINE_NOT_WORKING | MACHINE_IMPERFECT_SOUND) | |
| // VX class (first model using an EGC) | |
| // ... | |
| // XA/XL class (1120 x 750 true color, nicknamed "High-reso") | |
| // ... | |
| // PC-H98 (Hyper 98, '90-'93 high end line with High-reso, proprietary NESA bus, E²GC) | |
| // PC-H98T (LCD Hyper 98) | |
| // SV-H98 (Later Hyper 98 revision, up to Pentium CPU) | |
| // ... | |
| // RS class (i386SX) | |
| COMP( 1988, pc9801rx, pc9801rs, 0, pc9801rs, pc9801rs, pc9801_state, init_pc9801_kanji, "NEC", "PC-9801RX", MACHINE_NOT_WORKING | MACHINE_IMPERFECT_SOUND) | |
| COMP( 1989, pc9801rs, 0, 0, pc9801rs, pc9801rs, pc9801_state, init_pc9801_kanji, "NEC", "PC-9801RS", MACHINE_NOT_WORKING | MACHINE_IMPERFECT_SOUND) | |
| // FA class (i486SX) | |
| COMP( 1993, pc9801bx2, pc9801rs, 0, pc9801bx2, pc9801rs, pc9801_state, init_pc9801_kanji, "NEC", "PC-9801BX2/U2", MACHINE_NOT_WORKING | MACHINE_IMPERFECT_SOUND) | |
| // PC-98GS (Multimedia PC, exclusive video mode "Extended Screen Graphics", -73 sound board (a superset of later -86), superimposition) | |
| // ... | |
| // Epson class | |
| COMP( 1990, pc386m, 0, 0, pc386m, pc9801rs, pc9801_state, init_pc9801_kanji, "Epson", "PC-386M", MACHINE_NOT_WORKING | MACHINE_IMPERFECT_SOUND) | |
| COMP( 1994, pc486mu, 0, 0, pc486mu, pc9821, pc9801_state, init_pc9801_kanji, "Epson", "PC-486MU", MACHINE_NOT_WORKING | MACHINE_IMPERFECT_SOUND) | |
| COMP( 1993, pc486se, pc486mu, 0, pc486se, pc9801rs, pc9801_state, init_pc9801_kanji, "Epson", "PC-486SE", MACHINE_NOT_WORKING | MACHINE_IMPERFECT_SOUND) | |
| // PC9821 class | |
| // TODO: unknown real model of parent, given the BIOS rom size wrt the others it may be better suited as a "98Multi" or even a FA class? | |
| // investigate by making genuine BIOS dumps to boot | |
| COMP( 1994, pc9821, 0, 0, pc9821, pc9821, pc9801_state, init_pc9801_kanji, "NEC", "PC-9821 (98MATE)", MACHINE_NOT_WORKING | MACHINE_IMPERFECT_SOUND) | |
| COMP( 1993, pc9821as, pc9821, 0, pc9821as, pc9821, pc9801_state, init_pc9801_kanji, "NEC", "PC-9821 (98MATE A)", MACHINE_NOT_WORKING | MACHINE_IMPERFECT_SOUND) | |
| COMP( 1993, pc9821ap2, pc9821, 0, pc9821ap2, pc9821, pc9801_state, init_pc9801_kanji, "NEC", "PC-9821AP2/U8W (98MATE A)", MACHINE_NOT_WORKING | MACHINE_IMPERFECT_SOUND) | |
| COMP( 1994, pc9821xs, pc9821, 0, pc9821, pc9821, pc9801_state, init_pc9801_kanji, "NEC", "PC-9821 (98MATE Xs)", MACHINE_NOT_WORKING | MACHINE_IMPERFECT_SOUND) | |
| COMP( 1994, pc9821ce2, pc9821, 0, pc9821, pc9821, pc9801_state, init_pc9801_kanji, "NEC", "PC-9821 (98MULTi Ce2)", MACHINE_NOT_WORKING | MACHINE_IMPERFECT_SOUND) | |
| COMP( 1994, pc9821ne, pc9821, 0, pc9821, pc9821, pc9801_state, init_pc9801_kanji, "NEC", "PC-9821 (98NOTE)", MACHINE_NOT_WORKING | MACHINE_IMPERFECT_SOUND) | |
| COMP( 1996, pc9821xa16, pc9821, 0, pc9821xa16, pc9821, pc9801_state, init_pc9801_kanji, "NEC", "PC-9821Xa16", MACHINE_NOT_WORKING | MACHINE_IMPERFECT_SOUND) | |
| COMP( 1996, pc9821ra20, pc9821, 0, pc9821ra20, pc9821, pc9801_state, init_pc9801_kanji, "NEC", "PC-9821Ra20 (98MATE R)", MACHINE_NOT_WORKING | MACHINE_IMPERFECT_SOUND) | |
| COMP( 1998, pc9821ra333, pc9821, 0, pc9821ra333, pc9821, pc9801_state, init_pc9801_kanji, "NEC", "PC-9821Ra333 (98MATE R)", MACHINE_NOT_WORKING | MACHINE_IMPERFECT_SOUND) | |
| COMP( 1998, pc9821v13, pc9821, 0, pc9821, pc9821, pc9801_state, init_pc9801_kanji, "NEC", "PC-9821 (98MATE VALUESTAR 13)", MACHINE_NOT_WORKING | MACHINE_IMPERFECT_SOUND) | |
| COMP( 1998, pc9821v20, pc9821, 0, pc9821v20, pc9821, pc9801_state, init_pc9801_kanji, "NEC", "PC-9821 (98MATE VALUESTAR 20)", MACHINE_NOT_WORKING | MACHINE_IMPERFECT_SOUND) | |
| // PC98DO (PC88+PC98, V33 + μPD70008AC) | |
| // PC-98LT (laptop b&w LCD version V50, no upd7220, just one single bitmap layer) | |
| // PC-98HA aka HANDY98 (portable b&w LCD version, V50, apparently compatible with LT) | |
| // RC-9801 (portable (color?) LCD, i386SX, wireless 9600bps modem) | |
| // PC-9801P (LCD with light pen) |