diff --git a/hash/ibm5170_cdrom.xml b/hash/ibm5170_cdrom.xml
index 6d7885069e7..070327a4779 100644
--- a/hash/ibm5170_cdrom.xml
+++ b/hash/ibm5170_cdrom.xml
@@ -6509,93 +6509,29 @@ Has setup menu glitch with text [8514]
-
+
-
-
- Acer CPR
- 1995
- Acer America Corporation
-
-
+
+
+ BeOS 4.5
+ 1999
+ Be Inc
+
-
-
+
-
-
-
-
-
-
-
-
-
-
- DIV Games Studio (English, v1.03b)
- 1998
- Hammer Technologies
-
-
-
-
-
-
-
-
-
-
- DIV Games Studio (French, v1.03b)
- 2000
- Hammer Technologies
-
-
-
-
-
-
-
-
-
- Adaptec EZ-SCSI 4.01 (Rev A)
- 1996
- Adaptec
-
-
-
-
-
-
-
-
-
- Adaptec EZ-SCSI 5.0 Deluxe Edition (Rev B)
-
- 1999
- Adaptec
-
+
+
-
+
@@ -6782,64 +6718,6 @@ EZCDLITE Contains Easy CD Creator Lite ASPI setup
-
-
-
-
- Key CAD Complete Creations (v6.0)
- 1996
- SoftKey
-
-
-
-
-
-
-
-
-
-
- Lexmark Z22 / Z32 Color Jetprinter
- 2000
- Lexmark
-
-
-
-
-
-
-
-
- The Matrox Millennium Multimedia SuperPack (v1.60)
- 1996
- Matrox
-
-
-
-
-
-
-
-
-
-
-
- Mustek Power of Scanning
- 1997
- Mustek
-
-
-
-
-
-
-
-
NASLite NAS Server Operating System (v1.x)
2004
@@ -6852,93 +6730,6 @@ Contains software drivers for a ScanExpress 6000SP Flatbed Scanner, SCSI i/f
-
-
- Lotus Notes Express v3.30 for OS2, Special Promotion Copy NFR
- 1995
- Lotus Development Corporation
-
-
-
-
-
-
-
-
-
-
- Caldera OpenDOS Machine Readable Source Kit (M.R.S) 7.01
- 1997
- Caldera
-
-
-
-
-
-
-
-
-
-
-
- IBM DEMOpkg for OS2 - First Edition 99Q3
- 1999
- IBM
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
OS/2 Warp Special CD - november 1995
@@ -7043,24 +6834,6 @@ Contains software drivers for a ScanExpress 6000SP Flatbed Scanner, SCSI i/f
-
-
- Paranasal Sinuses & Anterior Skull Base
- 1993
- Elsevier Science B.V.
-
-
-
-
-
-
-
PC DOS 7
1995
@@ -7086,18 +6859,417 @@ Contains software drivers for a ScanExpress 6000SP Flatbed Scanner, SCSI i/f
-
- S3 Drivers Collection 1998 (Rev 2.1)
- 1998
- S3
-
+ Windows 95 (en 4.00.950)
+ 1995
+ Microsoft
+
+
+
+
+
+
+
+
+
+ Windows 95 OSR1 (en 4.00.950.osr1)
+ 1996
+ Microsoft
+
+
+
+
+
+
+
+
+
+
+ Windows 95 OSR2 (en 4.00.1111.osr2)
+ 1996
+ Microsoft
+
+
+
+
+
+
+
+
+
+
+ Windows 95 OSR2.5 (en 4.03.1216.osr2.5)
+ 1997
+ Microsoft
+
+
+
+
+
+
+
+
+
+ Windows 98 (en 4.10.1998) (Retail Full)
+ 1998
+ Microsoft
+
+
+
+
+
+
+
+
+
+ Windows 98 Second Edition (en 4.10.2222) (Retail Full)
+ 1999
+ Microsoft
+
+
+
+
+
+
+
+
+
+
+
+ Windows 98 Second Edition (jp 4.10.2222) (Retail Full)
+ 1999
+ Microsoft
+
+
+
+
+
+
+
+
+
+
+
+ Windows ME (en 4.90.3000) (Retail Full)
+ 2000
+ Microsoft
+
+
+
+
+
+
+
+
+
+ Windows NT 3.1 Workstation (3.10.511.1)
+ 1993
+ Microsoft
+
+
+
+
+
+
+
+
+
+ Windows NT 3.51 Workstation (3.51.1057.1)
+ 1995
+ Microsoft
+
+
+
+
+
+
+
+
+
+ Windows 2000 Professional (with Service Pack 4) (en 5.00.2195.6717)
+ 1999
+ Microsoft
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Acer CPR
+ 1995
+ Acer America Corporation
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ DIV Games Studio (English, v1.03b)
+ 1998
+ Hammer Technologies
+
+
+
+
+
+
+
+
+
+
+ DIV Games Studio (French, v1.03b)
+ 2000
+ Hammer Technologies
+
+
+
+
+
+
+
+
+
+ Adaptec EZ-SCSI 4.01 (Rev A)
+ 1996
+ Adaptec
+
+
+
+
+
+
+
+
+
+ Adaptec EZ-SCSI 5.0 Deluxe Edition (Rev B)
+
+ 1999
+ Adaptec
+
+
+
+
+
+
+
+
+
+
+
+ Key CAD Complete Creations (v6.0)
+ 1996
+ SoftKey
+
+
+
+
+
+
+
+
+
+
+ Lexmark Z22 / Z32 Color Jetprinter
+ 2000
+ Lexmark
+
+
+
+
+
+
+
+
+ The Matrox Millennium Multimedia SuperPack (v1.60)
+ 1996
+ Matrox
+
+
+
+
+
+
+
+
+
+
+
+ Mustek Power of Scanning
+ 1997
+ Mustek
+
+
+
+
+
+
+
+
+
+
+ Lotus Notes Express v3.30 for OS2, Special Promotion Copy NFR
+ 1995
+ Lotus Development Corporation
+
+
+
+
+
+
+
+
+
+
+ Caldera OpenDOS Machine Readable Source Kit (M.R.S) 7.01
+ 1997
+ Caldera
+
+
+
+
+
+
+
+
+
+
+
+ IBM DEMOpkg for OS2 - First Edition 99Q3
+ 1999
+ IBM
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Paranasal Sinuses & Anterior Skull Base
+ 1993
+ Elsevier Science B.V.
+
+
+
+
+
+
+
+
+ S3 Drivers Collection 1998 (Rev 2.1)
+ 1998
+ S3
+
-
-
-
- Windows 95 (en 4.00.950)
- 1995
- Microsoft
-
-
-
-
-
-
-
-
-
- Windows 95 OSR1 (en 4.00.950.osr1)
- 1996
- Microsoft
-
-
-
-
-
-
-
-
-
- Windows 95 OSR2 (en 4.00.1111.osr2)
- 1996
- Microsoft
-
-
-
-
-
-
-
-
-
- Windows 95 OSR2.5 (en 4.03.1216.osr2.5)
- 1997
- Microsoft
-
-
-
-
-
-
-
-
-
- Windows 98 (en 4.10.1998) (Retail Full)
- 1998
- Microsoft
-
-
-
-
-
-
-
-
-
- Windows 98 Second Edition (en 4.10.2222) (Retail Full)
- 1999
- Microsoft
-
-
-
-
-
-
-
-
-
-
-
- Windows 98 Second Edition (jp 4.10.2222) (Retail Full)
- 1999
- Microsoft
-
-
-
-
-
-
-
-
-
-
-
- Windows ME (en 4.90.3000) (Retail Full)
- 2000
- Microsoft
-
-
-
-
-
-
-
-
-
- Windows NT 3.1 Workstation (3.10.511.1)
- 1993
- Microsoft
-
-
-
-
-
-
-
-
-
- Windows NT 3.51 Workstation (3.51.1057.1)
- 1995
- Microsoft
-
-
-
-
-
-
-
-
-
- Windows 2000 Professional (with Service Pack 4) (en 5.00.2195.6717)
- 1999
- Microsoft
-
-
-
-
-
-
-
-
-
-
diff --git a/hash/msx1_flop.xml b/hash/msx1_flop.xml
index 2789a6c1105..3e68fa2bdf5 100644
--- a/hash/msx1_flop.xml
+++ b/hash/msx1_flop.xml
@@ -44,6 +44,31 @@ The following floppies came with the machines.
+
+ Serial Interface (Netherlands)
+ 1986
+ Philips
+ Included with NMS 1210, NMS 1211, and NMS 1212 RS-232C packages. These serial interfaces are not supported.
+
+
+
+
+
+
+
+
+ MSX Data Communications (Netherlands)
+ 1987
+ Philips
+ Included with NMS 1250 Modem package. NMS 1250 is not supported.
+
+
+
+
+
+
+
+
@@ -207,6 +232,23 @@ The following floppies came with the machines.
+
+ Aackotext II (Netherlands, v2.2)
+ 1985
+ Aackosoft
+
+
+
+
+
+
+
+
+
+
+
+
+
Adonis (Japan)
@@ -346,6 +388,18 @@ The following floppies came with the machines.
+
+ Brasil Geográfico (Brazil)
+ 1991
+ Discovery Informática
+
+
+
+
+
+
+
+
Breaker Breaker (Europe)
1988
@@ -524,6 +578,18 @@ The following floppies came with the machines.
+
+ dBASE II (Netherlands)
+ 1983
+ C.U.C.
+
+
+
+
+
+
+
+
Delta BASIC (Netherlands)
1987
@@ -1253,6 +1319,37 @@ The following floppies came with the machines.
+
+ MS Text (Netherlands)
+ 1985
+ Philips
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Score Editor (Japan)
+ 1987
+ Toshiba-EMI Ltd.
+
+
+
+
+
+
+
+
+
+
MSX Compilation 5 (Netherlands)
1986
@@ -1303,6 +1400,17 @@ The following floppies came with the machines.
+
+ MSX-AIDS (Japan, v1.1)
+ 1988
+ Sansai Books
+
+
+
+
+
+
+
Music Creator (Netherlands)
@@ -1366,6 +1474,28 @@ The following floppies came with the machines.
+
+ Nihongo Waupuro Kan-juku Tomato (Japan)
+ 1985
+ Sony
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
North Sea Helicopter (Netherlands, hacked)
1987
@@ -1951,9 +2081,8 @@ The following floppies came with the machines.
Methodic Solutions
-
-
-
+
+
@@ -2079,6 +2208,17 @@ The following floppies came with the machines.
+
+ Zanac (Netherlands)
+ 1986
+ Eaglesoft
+
+
+
+
+
+
+
Zen (United Kingdom)
1986
@@ -2295,6 +2435,18 @@ The following floppies came with the machines.
+
+ JUBILEUM Diskette (Netherlands)
+ 1989
+ Stichting C.U.C.
+
+
+
+
+
+
+
+
Cyuji Games (Japan)
@@ -5116,6 +5268,19 @@ The following floppies came with the machines.
+
+ Yamaha Portatone PSR-6300 Demonstration
+ 19??
+ Yamaha
+ Midi connection to PSR-6300 has not been tested.
+
+
+
+
+
+
+
+
Zeta 2000 (Japan, disk conversion)
19??
@@ -5878,17 +6043,4 @@ The following floppies came with the machines.
-
- Zanac (Netherlands)
- 1986
- Eaglesoft
-
-
-
-
-
-
-
-
-
diff --git a/hash/msxr_flop.xml b/hash/msxr_flop.xml
index 74facbeed26..5ef38976fae 100644
--- a/hash/msxr_flop.xml
+++ b/hash/msxr_flop.xml
@@ -7,12 +7,13 @@ license:CC0-1.0
+
-
- 2021 Snooky! (Jpn)
+
+ FS-A1GT (Japan)
+ 1990
+ Panasonic
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ FS-A1ST (Japan)
+ 1990
+ Panasonic
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 2021 Snooky! (Japan)
1991
Studio Hawk
-
@@ -45,11 +87,100 @@ Known undumped:
-
- Die Frage II' (Jpn)
+
+ The Best of Hamaraja Night (Japan)
+ 1999
+ Pastel Hope
+ MSX Turbo-R is not supported.
+
+
+
+
+
+
+
+
+ Dewoman Zenpen (Japan)
+ 1993
+ Blue Eyes
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Dewoman Chuuhen (Japan)
+ 1993
+ Blue Eyes
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Die Frage II' (Japan)
199?
Studio Sequence
-
@@ -57,24 +188,33 @@ Known undumped:
-
- Die Frage II' (Jpn, Bad Dump?)
+
+ Die Frage II' (Japan, bad dump?)
199?
Studio Sequence
+
+
+
+
+
+
+
+ Fantasy Attraction (Japan)
+ 1996
+ Rem Company
-
+
-
- Fray - In Magical Adventure (Jpn)
+
+ Fray - In Magical Adventure (Japan)
1990
Micro Cabin
-
-
+
@@ -107,12 +247,11 @@ Known undumped:
-
- Fray - In Magical Adventure (Jpn, Alt)
+
+ Fray - In Magical Adventure (Japan, alt)
1990
Micro Cabin
-
-
+
@@ -145,12 +284,11 @@ Known undumped:
-
- Fray - In Magical Adventure (Jpn, Alt 2)
+
+ Fray - In Magical Adventure (Japan, alt 2)
1990
Micro Cabin
-
-
+
@@ -183,12 +321,11 @@ Known undumped:
-
- Illusion City - Genei Toshi (Jpn)
+
+ Illusion City - Genei Toshi (Japan)
1991
Micro Cabin
-
@@ -239,11 +376,85 @@ Known undumped:
-
- μ.Note (Jpn)
+
+ innocent wish ~destiny2~ (Japan)
+ 1995
+ Sign House
+
+
+
+
+
+
+
+
+ Mahou no Kuni no Hoippuru (Japan)
+ 1996
+ Pastel Hope
+
+
+
+
+
+
+
+
+
+ Mechanical Brain (Japan)
+ 1996
+ Studio Sequence
+
+
+
+
+
+
+
+
+ Mejuu Sa - Medusa (Japan)
+ 1994
+ Blue Eyes
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ MSX ViewCALC (Japan)
+ 1991
+ ASCII Corporation
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ μ.Note (Japan)
1992
Bit²
-
@@ -258,11 +469,10 @@ Known undumped:
-
- μ.Sios (Jpn)
+
+ μ.Sios (Japan)
1991
Bit²
-
@@ -283,12 +493,22 @@ Known undumped:
-
- Ranma ½ - Hiryuu Densetsu (Jpn)
+
+ R2 Chaser's (Japan)
+ 1996
+ Studio Sequence
+
+
+
+
+
+
+
+
+ Ranma ½ - Hiryuu Densetsu (Japan)
1992
Bothtec
-
-
+
@@ -339,12 +559,11 @@ Known undumped:
-
- Ranma ½ - Hiryuu Densetsu (Jpn, Alt)
+
+ Ranma ½ - Hiryuu Densetsu (Japan, alt)
1992
Bothtec
-
-
+
@@ -395,12 +614,11 @@ Known undumped:
-
- Ranma ½ - Hiryuu Densetsu (Jpn, Alt 2)
+
+ Ranma ½ - Hiryuu Densetsu (Japan, alt 2)
1992
Bothtec
-
-
+
@@ -451,12 +669,11 @@ Known undumped:
-
- Ranma ½ - Hiryuu Densetsu (Jpn, Alt Disk 1)
+
+ Ranma ½ - Hiryuu Densetsu (Japan, alt disk 1)
1992
Bothtec
-
-
+
@@ -507,12 +724,11 @@ Known undumped:
-
- Seed of Dragon (Jpn)
+
+ Seed of Dragon (Japan)
1990
Riverhill Soft
-
-
+
@@ -533,12 +749,11 @@ Known undumped:
-
- Seed of Dragon (Jpn, Alt)
+
+ Seed of Dragon (Japan, alt)
1990
Riverhill Soft
-
@@ -559,12 +774,11 @@ Known undumped:
-
- Seed of Dragon (Jpn, Alt Disk 1)
+
+ Seed of Dragon (Japan, alt disk 1)
1990
Riverhill Soft
-
@@ -585,11 +799,70 @@ Known undumped:
-
- Turbo Booster (Jpn)
+
+ South Town's Hero II (Japan)
+ 1995
+ FM-Guamuom
+
+
+
+
+
+
+
+
+
+
+
+
+
+ South Town's Hero Turbo (Japan)
+ 1995
+ FM-Guamuom
+
+
+
+
+
+
+
+
+ Speedline (demo)
+ 2001
+ Traposoft
+
+
+
+
+
+
+
+
+ Superiority Fighters (Japan)
+ 1994
+ Mushroom
+
+
+
+
+
+
+
+
+ Turbo Blaster (Japan)
+ 1994
+ M.O.V
+
+
+
+
+
+
+
+
+ Turbo Booster (Japan)
1990
Kyoto Media
-
@@ -597,17 +870,33 @@ Known undumped:
+
+ Welkis the Legend (Japan)
+ 1996
+ Uechan Dayo
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
- Dream Drops - Secret Design of the Hearts (Jpn)
+
+ Dream Drops - Secret Design of the Hearts (Japan)
2011
- <doujin>
-
-
+ Rabbit Soft Worker's
@@ -615,12 +904,10 @@ Known undumped:
-
- Dream Fighters (Jpn)
+
+ Dream Fighters (Japan)
1996
- <doujin>
-
-
+ Monoki
@@ -629,12 +916,10 @@ Known undumped:
-
- Earth Attack (Jpn)
+
+ Earth Attack (Japan)
19??
- <doujin>
-
-
+ GW's Workshop
@@ -642,12 +927,10 @@ Known undumped:
-
- F-Nano 2 - 3D Car Action (Jpn)
+
+ F-Nano 2 - 3D Car Action (Japan)
1994
- <doujin>
-
-
+ XRay
@@ -655,12 +938,10 @@ Known undumped:
-
- F-Nano 2' - 3D Car Action (Jpn)
+
+ F-Nano 2' - 3D Car Action (Japan)
1997
- <doujin>
-
-
+ XRay
@@ -668,13 +949,11 @@ Known undumped:
-
- Gekikara Roudousha (Jpn)
+
+ Gekikara Roudousha (Japan)
1995
- <doujin>
-
-
-
+ Delta Trial
+
@@ -682,12 +961,10 @@ Known undumped:
-
- Gun Shot vs Festa Again (Jpn)
+
+ Gun Shot vs Festa Again (Japan)
2001
- <doujin>
-
-
+ Rabbit Soft Worker's
@@ -695,12 +972,21 @@ Known undumped:
-
- In the 6th Sense - Product of the Hearts (Jpn)
- 2007
- <doujin>
-
+
+ Hyper Role Playing Story LOSTWORD Episode 0 (Japan)
+ 2019
+ Rabbit Soft Worker's
+
+
+
+
+
+
+
+ In the 6th Sense - Product of the Hearts (Japan)
+ 2007
+ Rabbit Soft Worker's
@@ -708,12 +994,10 @@ Known undumped:
-
+
Mistral Blue
2002
- <doujin>
-
-
+ Popcorn
@@ -721,12 +1005,10 @@ Known undumped:
-
+
Mobius Debugger 2 - Eternal Striker
1995
- <doujin>
-
-
+ Studio Sequence
@@ -734,38 +1016,57 @@ Known undumped:
-
- Moon Light Saga (Jpn)
+
+ Moon Light Saga - Horus no Shou (Japan)
1996
- <doujin>
-
-
+ MapleYard
+
+
-
+
+
+
+
+
+
+
+
+
+
+
+
+
-
- Moon Light Saga (Jpn, Bad Dump?)
+
+ Moon Light Saga (Japan, bad dump?)
1996
- <doujin>
-
+ MapleYard
+
+
+
+
+
+
+
+ Moon Light Saga (Japan, alt)
+ 1996
+ MapleYard
-
+
-
- Multi-Plex (Jpn)
+
+ Multi-Plex (Japan)
1993
- <doujin>
-
-
+ MIWA
@@ -773,12 +1074,10 @@ Known undumped:
-
- Multi-Plex (Jpn, Alt)
+
+ Multi-Plex (Japan, alt)
1993
- <doujin>
-
-
+ MIWA
@@ -787,12 +1086,10 @@ Known undumped:
-
- PaRaDream - Parallel Dream (Jpn)
+
+ PaRaDream - Parallel Dream (Japan)
1992
- <doujin>
-
-
+ RAC House
@@ -800,12 +1097,10 @@ Known undumped:
-
- PaRaDream - Parallel Dream (Jpn, Alt)
+
+ PaRaDream - Parallel Dream (Japan, alt)
1992
- <doujin>
-
-
+ RAC House
@@ -813,12 +1108,10 @@ Known undumped:
-
- PaRaDream - Parallel Dream (Jpn, Alt 2)
+
+ PaRaDream - Parallel Dream (Japan, alt 2)
1992
- <doujin>
-
-
+ RAC House
@@ -826,12 +1119,10 @@ Known undumped:
-
+
Phi
2004
- <doujin>
-
-
+ Mariko-ban GCC
@@ -839,25 +1130,32 @@ Known undumped:
-
- Space Panic!
- 1998
- <doujin>
-
+
+ Qui Veut Gagner Des Millions
+ 2004
+ Walter
+
+
+
+
+
+
+
+ Quien Quiere Ser Milionario
+ 2009
+ Walter
-
+
-
- S.T.G. (Jpn)
+
+ S.T.G. (Japan)
1996
- <doujin>
-
-
+ Y. Tomohara
@@ -865,12 +1163,10 @@ Known undumped:
-
- S.T.G. Special - Do Don Taku (Jpn)
+
+ S.T.G. Special - Do Don Taku (Japan)
1998
- <doujin>
-
-
+ Y. Tomohara
@@ -878,13 +1174,11 @@ Known undumped:
-
- Saishuu Bouei-sen - Save Your Mother Planet: The Earth (Jpn)
+
+ Saishuu Bouei-sen - Save Your Mother Planet: The Earth (Japan)
1996
- <doujin>
-
-
-
+ GW's Workshop
+
@@ -892,12 +1186,10 @@ Known undumped:
-
- Shoot That Flying Windows! (Fin)
+
+ Shoot That Flying Windows! (Finland)
1997
- <homebrew>
-
-
+ Nyyrikki
@@ -905,12 +1197,10 @@ Known undumped:
-
- Shoot That Flying Windows! (Fin, Alt)
+
+ Shoot That Flying Windows! (Finland, alt)
1997
- <homebrew>
-
-
+ Nyyrikki
@@ -918,27 +1208,57 @@ Known undumped:
-
- Shoulder Blade (Jpn, Bad Dump?)
+
+ Shoulder Blade (Japan, bad dump?)
1997
- <doujin>
-
+ GW's Workshop
+
+
+
+
+
+
+
+
+ Space Panic! (Japan)
+ 1998
+ Mikasen
+
+
+
+
+
+
+
+ Stage 11 (Japan)
+ 1996
+ Mikasen
-
+
+
+
+
+
+
+ Stage 11 Kai (Japan)
+ 1998
+ Mikasen
+
+
+
+
-
- Sweet (Jpn)
+
+ Sweet (Japan)
1994
- <doujin>
-
-
+ Kazuyuki Suzuki
@@ -946,86 +1266,94 @@ Known undumped:
-
- Treasure of Babylon (Fra)
- 2013
- <homebrew>
-
-
+
+ Telebasic Edición No. 1 (Spain)
+ 1993
+ Traposoft
-
+
-
- Zone Terra (Ned)
+
+ Telebasic Edición No. 2 (Spain)
1994
- <homebrew>
-
-
+ Traposoft
-
+
-
- Zone Terra (Ned, Demo)
- 1994
- <homebrew>
-
+
+ Telebasic Edición No. 3 (Spain)
+ 1995
+ Traposoft
+
+
+
+
+
+
+
+ Treasure of Babylon (France)
+ 2013
+ Eric Boez
-
+
-
- Zekkou no Tsuri Biyori ya!! (Jpn)
- 1996
- <doujin>
-
-
+
+ Zone Terra (Netherlands)
+ 1994
+ Quadrivium
+
+
+
+
+
+
+
+ Zone Terra (Netherlands, demo)
+ 1994
+ Quadrivium
-
+
-
- Zekkou no Tsuri Biyori ya!! (Jpn, Alt)
+
+ Zekkou no Tsuri Biyori ya!! (Japan)
1996
- <doujin>
-
-
-
+ GW's Workshop
+
-
+
-
-
-
- MSX View (Jpn, Bad Dump?)
- 19??
- <unknown>
-
+
+ Zekkou no Tsuri Biyori ya!! (Japan, alt)
+ 1996
+ GW's Workshop
+
-
+
-
diff --git a/src/devices/bus/hexbus/hexbus.h b/src/devices/bus/hexbus/hexbus.h
index 1d225c55749..34bbea63193 100644
--- a/src/devices/bus/hexbus/hexbus.h
+++ b/src/devices/bus/hexbus/hexbus.h
@@ -161,7 +161,7 @@ class hexbus_device : public device_t, public device_single_card_slot_interface<
void write(int dir, uint8_t data);
protected:
- void device_start() override;
+ virtual void device_start() override;
device_hexbus_interface *m_next_dev;
private:
diff --git a/src/devices/bus/hexbus/hx5102.cpp b/src/devices/bus/hexbus/hx5102.cpp
index 459157fc604..999df7fe520 100644
--- a/src/devices/bus/hexbus/hx5102.cpp
+++ b/src/devices/bus/hexbus/hx5102.cpp
@@ -86,9 +86,10 @@
#define LOG_MOTOR (1U << 9) // Motor activity
#define LOG_STATUS (1U << 10) // Main status register
#define LOG_FIFO (1U << 11) // Data register
+#define LOG_CONFIG (1U << 12) // Configuration
// Minimum log should be config and warnings
-#define VERBOSE (LOG_GENERAL | LOG_WARN)
+#define VERBOSE (LOG_GENERAL | LOG_WARN | LOG_CONFIG)
#include "logmacro.h"
@@ -104,6 +105,9 @@
#define ROM1_TAG "u25_rom"
#define ROM2_TAG "u29_rom"
+#define FLOP0 "d0"
+#define FLOP1 "d1"
+
#define MOTOR_TIMER 1
#define UNDEF -1
@@ -138,6 +142,8 @@ hx5102_device::hx5102_device(const machine_config &mconfig, const char *tag, dev
m_dack(false),
m_dacken(false),
m_wait(false),
+ m_flopcon0(*this, FLOP0),
+ m_flopcon1(*this, FLOP1),
m_current_floppy(nullptr),
m_floppy_select(0),
m_floppy_select_last(UNDEF),
@@ -581,13 +587,21 @@ void hx5102_device::update_drive_select()
*/
void hx5102_device::device_start()
{
- m_floppy[0] = m_floppy[1] = nullptr;
-
- if (subdevice("d0")!=nullptr) m_floppy[0] = static_cast(subdevice("d0")->subdevices().first());
- if (subdevice("d1")!=nullptr) m_floppy[1] = static_cast(subdevice("d1")->subdevices().first());
-
m_rom1 = (uint8_t*)memregion(DSR_TAG)->base();
m_rom2 = (uint8_t*)memregion(DSR_TAG)->base() + 0x2000;
+
+ m_floppy[0] = m_flopcon0->get_device();
+ m_floppy[1] = m_flopcon1->get_device();
+
+ if (m_floppy[0] != nullptr)
+ LOGMASKED(LOG_CONFIG, "Internal floppy drive connected\n");
+ else
+ LOGMASKED(LOG_WARN, "Internal floppy drive not found\n");
+
+ if (m_floppy[1] != nullptr)
+ LOGMASKED(LOG_CONFIG, "External floppy drive connected\n");
+ else
+ LOGMASKED(LOG_CONFIG, "External floppy drive not connected\n");
}
/*
@@ -686,8 +700,8 @@ void hx5102_device::device_add_mconfig(machine_config& config)
m_floppy_ctrl->intrq_wr_callback().set(FUNC(hx5102_device::fdc_irq_w));
m_floppy_ctrl->drq_wr_callback().set(FUNC(hx5102_device::fdc_drq_w));
- FLOPPY_CONNECTOR(config, "d0", hx5102_drive, "525dd", hx5102_device::floppy_formats).enable_sound(true);
- FLOPPY_CONNECTOR(config, "d1", hx5102_drive, nullptr, hx5102_device::floppy_formats).enable_sound(true);
+ FLOPPY_CONNECTOR(config, m_flopcon0, hx5102_drive, "525dd", hx5102_device::floppy_formats).enable_sound(true);
+ FLOPPY_CONNECTOR(config, m_flopcon1, hx5102_drive, nullptr, hx5102_device::floppy_formats).enable_sound(true);
// Addressable latches
LS259(config, m_crulatch[0]); // U18
diff --git a/src/devices/bus/hexbus/hx5102.h b/src/devices/bus/hexbus/hx5102.h
index 34c3bc6f705..b0e490237d8 100644
--- a/src/devices/bus/hexbus/hx5102.h
+++ b/src/devices/bus/hexbus/hx5102.h
@@ -38,7 +38,7 @@ class hx5102_device : public hexbus_chained_device
protected:
virtual const tiny_rom_entry *device_rom_region() const override;
virtual void device_add_mconfig(machine_config &config) override;
- ioport_constructor device_input_ports() const override;
+ virtual ioport_constructor device_input_ports() const override;
void crumap(address_map &map);
void memmap(address_map &map);
@@ -48,8 +48,8 @@ class hx5102_device : public hexbus_chained_device
void board_reset(int state);
static void floppy_formats(format_registration &fr);
- void device_start() override;
- void device_reset() override;
+ virtual void device_start() override;
+ virtual void device_reset() override;
virtual void hexbus_value_changed(uint8_t data) override;
private:
@@ -101,6 +101,8 @@ class hx5102_device : public hexbus_chained_device
void update_readyff_input();
// Link to the attached floppy drives
+ required_device m_flopcon0;
+ required_device m_flopcon1;
floppy_image_device* m_floppy[2];
floppy_image_device* m_current_floppy;
int m_floppy_select, m_floppy_select_last;
diff --git a/src/devices/bus/ti99/gromport/cartridges.cpp b/src/devices/bus/ti99/gromport/cartridges.cpp
index f60e90d5e7e..e54f82e42ec 100644
--- a/src/devices/bus/ti99/gromport/cartridges.cpp
+++ b/src/devices/bus/ti99/gromport/cartridges.cpp
@@ -30,7 +30,7 @@
#define LOG_RPK (1U << 8) // RPK handler
#define LOG_WARNW (1U << 9) // Warn when writing to cartridge space
-#define VERBOSE (LOG_GENERAL | LOG_WARN | LOG_CONFIG)
+#define VERBOSE (LOG_GENERAL | LOG_WARN | LOG_CONFIG | LOG_CHANGE)
#include "logmacro.h"
DEFINE_DEVICE_TYPE(TI99_CART, bus::ti99::gromport::ti99_cartridge_device, "ti99cart", "TI-99 cartridge")
@@ -94,7 +94,6 @@ ti99_cartridge_device::ti99_cartridge_device(const machine_config &mconfig, cons
: device_t(mconfig, TI99_CART, tag, owner, clock),
device_cartrom_image_interface(mconfig, *this),
m_pcbtype(0),
- m_slot(0),
m_pcb(nullptr),
m_connector(nullptr)
{
@@ -274,7 +273,8 @@ int ti99_cartridge_device::get_index_from_tagname()
std::pair ti99_cartridge_device::call_load()
{
// File name is in m_basename
- LOGMASKED(LOG_CHANGE, "Loading %s in slot %s\n", basename());
+ int slot = get_index_from_tagname() + 1;
+ LOGMASKED(LOG_CHANGE, "Loading %s in slot %d\n", basename(), slot);
if (loaded_through_softlist())
{
@@ -363,8 +363,7 @@ std::pair ti99_cartridge_device::call_load()
prepare_cartridge();
m_pcb->set_cartridge(this);
m_pcb->set_tag(tag());
- m_slot = get_index_from_tagname();
- m_connector->insert(m_slot, this);
+ m_connector->insert();
return std::make_pair(std::error_condition(), std::string());
}
@@ -387,13 +386,21 @@ void ti99_cartridge_device::call_unload()
}
}
- m_pcb = nullptr;
- m_connector->remove(m_slot);
-}
+ // If we don't clear this, swapping cartridges may make old contents reappear
+ if (memregion("grom"))
+ machine().memory().region_free(memregion("grom")->name());
-void ti99_cartridge_device::set_slot(int i)
-{
- m_slot = i;
+ if (memregion("rom"))
+ machine().memory().region_free(memregion("rom")->name());
+
+ if (memregion("nvram"))
+ machine().memory().region_free(memregion("nvram")->name());
+
+ if (memregion("ram"))
+ machine().memory().region_free(memregion("ram")->name());
+
+ m_pcb = nullptr;
+ m_connector->remove();
}
void ti99_cartridge_device::readz(offs_t offset, uint8_t *value)
@@ -450,12 +457,6 @@ bool ti99_cartridge_device::is_grom_idle()
return (m_pcb != nullptr)? m_pcb->is_grom_idle() : false;
}
-void ti99_cartridge_device::device_config_complete()
-{
- m_connector = dynamic_cast(owner());
- // owner is the empty_state during -listxml, so this will be nullptr
-}
-
/*
5 GROMs that may be contained in a cartridge
*/
diff --git a/src/devices/bus/ti99/gromport/cartridges.h b/src/devices/bus/ti99/gromport/cartridges.h
index 952288a7d59..6402d4cf38c 100644
--- a/src/devices/bus/ti99/gromport/cartridges.h
+++ b/src/devices/bus/ti99/gromport/cartridges.h
@@ -27,6 +27,10 @@ class ti99_cartridge_pcb;
class ti99_cartridge_device : public device_t, public device_cartrom_image_interface
{
+ friend class ti99_single_cart_conn_device;
+ friend class ti99_multi_cart_conn_device;
+ friend class ti99_gkracker_device;
+
public:
ti99_cartridge_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock);
@@ -43,12 +47,10 @@ class ti99_cartridge_device : public device_t, public device_cartrom_image_inter
void gclock_in(int state);
bool is_available() { return m_pcb != nullptr; }
- void set_slot(int i);
bool is_grom_idle();
protected:
virtual void device_start() override { }
- virtual void device_config_complete() override;
virtual void device_add_mconfig(machine_config &config) override;
virtual const tiny_rom_entry* device_rom_region() const override;
@@ -63,6 +65,8 @@ class ti99_cartridge_device : public device_t, public device_cartrom_image_inter
const char *image_interface() const noexcept override { return "ti99_cart"; }
const char *file_extensions() const noexcept override { return "rpk"; }
+ void set_connector(cartridge_connector_device* conn) { m_connector = conn; }
+
private:
class ti99_rpk_socket;
@@ -116,7 +120,6 @@ class ti99_cartridge_device : public device_t, public device_cartrom_image_inter
bool m_readrom;
int m_pcbtype;
- int m_slot;
int get_index_from_tagname();
std::unique_ptr m_pcb; // inbound
diff --git a/src/devices/bus/ti99/gromport/gkracker.cpp b/src/devices/bus/ti99/gromport/gkracker.cpp
index 0a6055bcd53..c39a3cae806 100644
--- a/src/devices/bus/ti99/gromport/gkracker.cpp
+++ b/src/devices/bus/ti99/gromport/gkracker.cpp
@@ -101,7 +101,7 @@
#define LOG_CHANGE (1U << 2) // Cartridge change
#define LOG_GKRACKER (1U << 3) // Gram Kracker operation
-#define VERBOSE (LOG_WARN)
+#define VERBOSE (LOG_GENERAL | LOG_WARN)
#include "logmacro.h"
DEFINE_DEVICE_TYPE(TI99_GROMPORT_GK, bus::ti99::gromport::ti99_gkracker_device, "ti99_gkracker", "Miller's Graphics GRAM Kracker")
@@ -141,16 +141,15 @@ ti99_gkracker_device::ti99_gkracker_device(const machine_config &mconfig, const
m_ram_ptr(nullptr),
m_grom_ptr(nullptr),
m_waddr_LSB(false),
- m_cartridge(nullptr)
+ m_cartridge(*this, "cartridge")
{
}
void ti99_gkracker_device::romgq_line(int state)
{
m_romspace_selected = (state==ASSERT_LINE);
- // Propagate to the guest
- if (m_cartridge != nullptr)
- m_cartridge->romgq_line(state);
+ // Propagate to the guest (if available)
+ m_cartridge->romgq_line(state);
}
/*
@@ -159,14 +158,12 @@ void ti99_gkracker_device::romgq_line(int state)
void ti99_gkracker_device::set_gromlines(line_state mline, line_state moline, line_state gsq)
{
m_grom_selected = (gsq==ASSERT_LINE);
- if (m_cartridge != nullptr)
- m_cartridge->set_gromlines(mline, moline, gsq);
+ m_cartridge->set_gromlines(mline, moline, gsq);
}
void ti99_gkracker_device::gclock_in(int state)
{
- if (m_cartridge != nullptr)
- m_cartridge->gclock_in(state);
+ m_cartridge->gclock_in(state);
}
/*
@@ -174,7 +171,7 @@ void ti99_gkracker_device::gclock_in(int state)
*/
bool ti99_gkracker_device::is_grom_idle()
{
- return (m_cartridge != nullptr) ? m_cartridge->is_grom_idle() : false;
+ return m_cartridge->is_grom_idle();
}
void ti99_gkracker_device::readz(offs_t offset, uint8_t *value)
@@ -224,25 +221,19 @@ void ti99_gkracker_device::readz(offs_t offset, uint8_t *value)
}
// If the guest has GROMs or ROMs they will override the GK contents
- if (m_cartridge != nullptr)
- {
- // For debugging
- uint8_t val1 = *value;
+ // For debugging
+ uint8_t val1 = *value;
- // Read from the guest cartridge.
- m_cartridge->readz(offset, value);
- if (val1 != *value)
- LOGMASKED(LOG_GKRACKER, "Read (from guest) %04x -> %02x\n", offset, *value);
- }
+ // Read from the guest cartridge.
+ m_cartridge->readz(offset, value);
+ if (val1 != *value)
+ LOGMASKED(LOG_GKRACKER, "Read (from guest) %04x -> %02x\n", offset, *value);
}
void ti99_gkracker_device::write(offs_t offset, uint8_t data)
{
// write to the guest cartridge if present
- if (m_cartridge != nullptr)
- {
- m_cartridge->write(offset, data);
- }
+ m_cartridge->write(offset, data);
if (m_grom_selected)
{
@@ -310,14 +301,12 @@ void ti99_gkracker_device::write(offs_t offset, uint8_t data)
void ti99_gkracker_device::crureadz(offs_t offset, uint8_t *value)
{
- if (m_cartridge != nullptr)
- m_cartridge->crureadz(offset, value);
+ m_cartridge->crureadz(offset, value);
}
void ti99_gkracker_device::cruwrite(offs_t offset, uint8_t data)
{
- if (m_cartridge != nullptr)
- m_cartridge->cruwrite(offset, data);
+ m_cartridge->cruwrite(offset, data);
}
INPUT_CHANGED_MEMBER( ti99_gkracker_device::gk_changed )
@@ -326,21 +315,6 @@ INPUT_CHANGED_MEMBER( ti99_gkracker_device::gk_changed )
m_gk_switch[param & 0x07] = newval;
}
-void ti99_gkracker_device::insert(int index, ti99_cartridge_device* cart)
-{
- LOGMASKED(LOG_CHANGE, "Insert cartridge\n");
- m_cartridge = cart;
- // Switch 1 has a third location for resetting. We do the reset by default
- // here. It can be turned off in the configuration.
- m_gromport->cartridge_inserted();
-}
-
-void ti99_gkracker_device::remove(int index)
-{
- LOGMASKED(LOG_CHANGE, "Remove cartridge\n");
- m_cartridge = nullptr;
-}
-
void ti99_gkracker_device::gk_install_menu(const char* menutext, int len, int ptr, int next, int start)
{
const int base = 0x0000;
@@ -406,7 +380,8 @@ void ti99_gkracker_device::device_start()
{
m_ram_ptr = memregion(GKRACKER_NVRAM_TAG)->base();
m_grom_ptr = memregion(GKRACKER_ROM_TAG)->base();
- m_cartridge = nullptr;
+ m_cartridge->set_connector(this);
+
for (int i=1; i < 6; i++) m_gk_switch[i] = 0;
save_pointer(NAME(m_gk_switch),6);
save_item(NAME(m_romspace_selected));
@@ -444,7 +419,7 @@ const tiny_rom_entry *ti99_gkracker_device::device_rom_region() const
void ti99_gkracker_device::device_add_mconfig(machine_config &config)
{
- TI99_CART(config, "cartridge", 0);
+ TI99_CART(config, m_cartridge, 0);
}
INPUT_PORTS_START(gkracker)
diff --git a/src/devices/bus/ti99/gromport/gkracker.h b/src/devices/bus/ti99/gromport/gkracker.h
index a163baffd8a..79efe94544c 100644
--- a/src/devices/bus/ti99/gromport/gkracker.h
+++ b/src/devices/bus/ti99/gromport/gkracker.h
@@ -26,8 +26,6 @@ class ti99_gkracker_device : public cartridge_connector_device, public device_nv
void set_gromlines(line_state mline, line_state moline, line_state gsq) override;
void gclock_in(int state) override;
- void insert(int index, ti99_cartridge_device* cart) override;
- void remove(int index) override;
DECLARE_INPUT_CHANGED_MEMBER( gk_changed );
// We may have a cartridge plugged into the GK
@@ -57,7 +55,7 @@ class ti99_gkracker_device : public cartridge_connector_device, public device_nv
bool m_waddr_LSB;
- ti99_cartridge_device *m_cartridge; // guest cartridge
+ required_device m_cartridge;
// Just for proper initialization
void gk_install_menu(const char* menutext, int len, int ptr, int next, int start);
diff --git a/src/devices/bus/ti99/gromport/gromport.cpp b/src/devices/bus/ti99/gromport/gromport.cpp
index a317fcb998e..6204c9b5af1 100644
--- a/src/devices/bus/ti99/gromport/gromport.cpp
+++ b/src/devices/bus/ti99/gromport/gromport.cpp
@@ -205,8 +205,9 @@ void gromport_device::set_gromlines(line_state mline, line_state moline, line_st
void gromport_device::device_start()
{
-
save_item(NAME(m_romgq));
+ if (m_connector != nullptr)
+ m_connector->set_port(this);
}
void gromport_device::device_reset()
@@ -281,12 +282,6 @@ void cartridge_connector_device::ready_line(int state)
m_gromport->ready_line(state);
}
-void cartridge_connector_device::device_config_complete()
-{
- m_gromport = dynamic_cast(owner());
- // owner is the empty_state during -listxml, so this will be nullptr
-}
-
} // end namespace bus::ti99::gromport
void ti99_gromport_options(device_slot_interface &device)
diff --git a/src/devices/bus/ti99/gromport/gromport.h b/src/devices/bus/ti99/gromport/gromport.h
index 724885f3ec4..10c339e9128 100644
--- a/src/devices/bus/ti99/gromport/gromport.h
+++ b/src/devices/bus/ti99/gromport/gromport.h
@@ -59,10 +59,10 @@ class gromport_device : public device_t, public device_single_card_slot_interfac
gromport_device& extend() { m_mask = 0x3fff; return *this; }
protected:
- void device_start() override;
- void device_reset() override;
- void device_config_complete() override;
- ioport_constructor device_input_ports() const override;
+ virtual void device_start() override;
+ virtual void device_reset() override;
+ virtual void device_config_complete() override;
+ virtual ioport_constructor device_input_ports() const override;
private:
cartridge_connector_device* m_connector;
@@ -75,6 +75,8 @@ class gromport_device : public device_t, public device_single_card_slot_interfac
class cartridge_connector_device : public device_t
{
+ friend class gromport_device;
+
public:
virtual void readz(offs_t offset, uint8_t *value) = 0;
virtual void write(offs_t offset, uint8_t data) = 0;
@@ -90,16 +92,17 @@ class cartridge_connector_device : public device_t
void ready_line(int state);
- virtual void insert(int index, bus::ti99::gromport::ti99_cartridge_device* cart) { m_gromport->cartridge_inserted(); }
- virtual void remove(int index) { }
+ virtual void insert() { m_gromport->cartridge_inserted(); }
+ virtual void remove() { }
virtual bool is_grom_idle() = 0;
protected:
cartridge_connector_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock);
- virtual void device_config_complete() override;
gromport_device* m_gromport;
bool m_grom_selected;
+
+ void set_port(gromport_device* gromport) { m_gromport = gromport; }
};
} // end namespace bus::ti99::gromport
diff --git a/src/devices/bus/ti99/gromport/multiconn.cpp b/src/devices/bus/ti99/gromport/multiconn.cpp
index 4c6b434187b..415fc7c3873 100644
--- a/src/devices/bus/ti99/gromport/multiconn.cpp
+++ b/src/devices/bus/ti99/gromport/multiconn.cpp
@@ -59,7 +59,8 @@ ti99_multi_cart_conn_device::ti99_multi_cart_conn_device(const machine_config &m
: cartridge_connector_device(mconfig, TI99_GROMPORT_MULTI, tag, owner, clock),
m_active_slot(0),
m_fixed_slot(0),
- m_next_free_slot(0)
+ m_next_free_slot(0),
+ m_cart(*this, "%u", 1)
{
}
@@ -124,31 +125,13 @@ int ti99_multi_cart_conn_device::get_active_slot(bool changebase, offs_t offset)
return slot;
}
-void ti99_multi_cart_conn_device::insert(int index, ti99_cartridge_device* cart)
-{
- LOGMASKED(LOG_CHANGE, "Insert slot %d\n", index);
- m_cartridge[index] = cart;
- m_gromport->cartridge_inserted();
-}
-
-void ti99_multi_cart_conn_device::remove(int index)
-{
- LOGMASKED(LOG_CHANGE, "Remove slot %d\n", index);
- m_cartridge[index] = nullptr;
-}
-
void ti99_multi_cart_conn_device::romgq_line(int state)
{
m_readrom = state;
// Propagate to all slots
- for (int i=0; i < NUMBER_OF_CARTRIDGE_SLOTS; i++)
- {
- if (m_cartridge[i] != nullptr)
- {
- m_cartridge[i]->romgq_line(state);
- }
- }
+ for (auto &cart : m_cart)
+ cart->romgq_line(state);
}
/*
@@ -159,26 +142,14 @@ void ti99_multi_cart_conn_device::set_gromlines(line_state mline, line_state mol
// GROM selected?
m_grom_selected = (gsq == ASSERT_LINE);
- // Propagate to all slots
- for (int i=0; i < NUMBER_OF_CARTRIDGE_SLOTS; i++)
- {
- if (m_cartridge[i] != nullptr)
- {
- m_cartridge[i]->set_gromlines(mline, moline, gsq);
- }
- }
+ for (auto &cart : m_cart)
+ cart->set_gromlines(mline, moline, gsq);
}
void ti99_multi_cart_conn_device::gclock_in(int state)
{
- // Propagate to all slots
- for (int i=0; i < NUMBER_OF_CARTRIDGE_SLOTS; i++)
- {
- if (m_cartridge[i] != nullptr)
- {
- m_cartridge[i]->gclock_in(state);
- }
- }
+ for (auto &cart : m_cart)
+ cart->gclock_in(state);
}
void ti99_multi_cart_conn_device::readz(offs_t offset, uint8_t *value)
@@ -192,23 +163,16 @@ void ti99_multi_cart_conn_device::readz(offs_t offset, uint8_t *value)
{
for (int i=0; i < NUMBER_OF_CARTRIDGE_SLOTS; i++)
{
- if (m_cartridge[i] != nullptr)
- {
- uint8_t newval = *value;
- m_cartridge[i]->readz(offset, &newval);
- if (i==slot)
- {
- *value = newval;
- }
- }
+ uint8_t newval = *value;
+ m_cart[i]->readz(offset, &newval);
+ if (i==slot)
+ *value = newval;
}
}
else
{
- if (slot < NUMBER_OF_CARTRIDGE_SLOTS && m_cartridge[slot] != nullptr)
- {
- m_cartridge[slot]->readz(offset, value);
- }
+ if (slot < NUMBER_OF_CARTRIDGE_SLOTS)
+ m_cart[slot]->readz(offset, value);
}
}
@@ -218,50 +182,32 @@ void ti99_multi_cart_conn_device::write(offs_t offset, uint8_t data)
// We don't have GRAM cartridges, anyway, so it's just used for setting the address.
if (m_grom_selected)
{
- for (auto & elem : m_cartridge)
- {
- if (elem != nullptr)
- {
- elem->write(offset, data);
- }
- }
+ for (auto &cart : m_cart)
+ cart->write(offset, data);
}
else
{
int slot = get_active_slot(true, offset);
- if (slot < NUMBER_OF_CARTRIDGE_SLOTS && m_cartridge[slot] != nullptr)
- {
+ if (slot < NUMBER_OF_CARTRIDGE_SLOTS)
// logerror("writing %04x (slot %d) <- %02x\n", offset, slot, data);
- m_cartridge[slot]->write(offset, data);
- }
+ m_cart[slot]->write(offset, data);
}
}
void ti99_multi_cart_conn_device::crureadz(offs_t offset, uint8_t *value)
{
int slot = get_active_slot(false, offset);
- /* Sanity check. Higher slots are always empty. */
- if (slot >= NUMBER_OF_CARTRIDGE_SLOTS)
- return;
-
- if (m_cartridge[slot] != nullptr)
- {
- m_cartridge[slot]->crureadz(offset, value);
- }
+ // Sanity check. Higher slots are always empty.
+ if (slot < NUMBER_OF_CARTRIDGE_SLOTS)
+ m_cart[slot]->crureadz(offset, value);
}
void ti99_multi_cart_conn_device::cruwrite(offs_t offset, uint8_t data)
{
int slot = get_active_slot(false, offset);
- /* Sanity check. Higher slots are always empty. */
- if (slot >= NUMBER_OF_CARTRIDGE_SLOTS)
- return;
-
- if (m_cartridge[slot] != nullptr)
- {
- m_cartridge[slot]->cruwrite(offset, data);
- }
+ if (slot < NUMBER_OF_CARTRIDGE_SLOTS)
+ m_cart[slot]->cruwrite(offset, data);
}
/*
@@ -270,12 +216,9 @@ void ti99_multi_cart_conn_device::cruwrite(offs_t offset, uint8_t data)
*/
bool ti99_multi_cart_conn_device::is_grom_idle()
{
- /* Sanity check. Higher slots are always empty. */
- if (m_active_slot >= NUMBER_OF_CARTRIDGE_SLOTS)
- return false;
-
- if (m_cartridge[m_active_slot] != nullptr)
- return m_cartridge[m_active_slot]->is_grom_idle();
+ // Sanity check. Higher slots are always empty.
+ if (m_active_slot < NUMBER_OF_CARTRIDGE_SLOTS)
+ return m_cart[m_active_slot]->is_grom_idle();
return false;
}
@@ -284,14 +227,14 @@ void ti99_multi_cart_conn_device::device_start()
{
m_next_free_slot = 0;
m_active_slot = 0;
- for (auto & elem : m_cartridge)
- {
- elem = nullptr;
- }
+
save_item(NAME(m_readrom));
save_item(NAME(m_active_slot));
save_item(NAME(m_fixed_slot));
save_item(NAME(m_next_free_slot));
+
+ for (auto &cart : m_cart)
+ cart->set_connector(this);
}
void ti99_multi_cart_conn_device::device_reset(void)
@@ -303,10 +246,8 @@ void ti99_multi_cart_conn_device::device_reset(void)
void ti99_multi_cart_conn_device::device_add_mconfig(machine_config &config)
{
- TI99_CART(config, "cartridge1", 0);
- TI99_CART(config, "cartridge2", 0);
- TI99_CART(config, "cartridge3", 0);
- TI99_CART(config, "cartridge4", 0);
+ for (int i=0; i < NUMBER_OF_CARTRIDGE_SLOTS; i++)
+ TI99_CART(config, m_cart[i], 0);
}
INPUT_CHANGED_MEMBER( ti99_multi_cart_conn_device::switch_changed )
diff --git a/src/devices/bus/ti99/gromport/multiconn.h b/src/devices/bus/ti99/gromport/multiconn.h
index fd4af556f8f..1767461b82f 100644
--- a/src/devices/bus/ti99/gromport/multiconn.h
+++ b/src/devices/bus/ti99/gromport/multiconn.h
@@ -30,26 +30,24 @@ class ti99_multi_cart_conn_device : public cartridge_connector_device
void set_gromlines(line_state mline, line_state moline, line_state gsq) override;
void gclock_in(int state) override;
- void insert(int index, ti99_cartridge_device* cart) override;
- void remove(int index) override;
DECLARE_INPUT_CHANGED_MEMBER( switch_changed );
bool is_grom_idle() override;
protected:
- static constexpr unsigned NUMBER_OF_CARTRIDGE_SLOTS = 4;
-
virtual void device_start() override;
virtual void device_reset() override;
virtual void device_add_mconfig(machine_config &config) override;
virtual ioport_constructor device_input_ports() const override;
private:
+ static constexpr unsigned NUMBER_OF_CARTRIDGE_SLOTS = 4;
bool m_readrom;
int m_active_slot;
int m_fixed_slot;
int m_next_free_slot;
- ti99_cartridge_device* m_cartridge[NUMBER_OF_CARTRIDGE_SLOTS];
+
+ required_device_array m_cart;
void set_slot(int slotnumber);
int get_active_slot(bool changebase, offs_t offset);
diff --git a/src/devices/bus/ti99/gromport/singleconn.cpp b/src/devices/bus/ti99/gromport/singleconn.cpp
index 35469762a65..d5b1b8a897e 100644
--- a/src/devices/bus/ti99/gromport/singleconn.cpp
+++ b/src/devices/bus/ti99/gromport/singleconn.cpp
@@ -15,7 +15,7 @@ namespace bus::ti99::gromport {
ti99_single_cart_conn_device::ti99_single_cart_conn_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
: cartridge_connector_device(mconfig, TI99_GROMPORT_SINGLE, tag, owner, clock),
- m_cartridge(nullptr)
+ m_cartridge(*this, "cartridge")
{
}
@@ -73,19 +73,10 @@ bool ti99_single_cart_conn_device::is_grom_idle()
return m_cartridge->is_grom_idle();
}
-void ti99_single_cart_conn_device::device_start()
-{
- m_cartridge = static_cast(subdevices().first());
-}
-
-void ti99_single_cart_conn_device::device_reset()
-{
- m_cartridge->set_slot(0);
-}
-
void ti99_single_cart_conn_device::device_add_mconfig(machine_config &config)
{
- TI99_CART(config, "cartridge", 0);
+ TI99_CART(config, m_cartridge, 0);
+ m_cartridge->set_connector(this);
}
} // end namespace bus::ti99::gromport
diff --git a/src/devices/bus/ti99/gromport/singleconn.h b/src/devices/bus/ti99/gromport/singleconn.h
index 6cf9d09240c..c368e37683c 100644
--- a/src/devices/bus/ti99/gromport/singleconn.h
+++ b/src/devices/bus/ti99/gromport/singleconn.h
@@ -29,12 +29,11 @@ class ti99_single_cart_conn_device : public cartridge_connector_device
bool is_grom_idle() override;
protected:
- virtual void device_start() override;
- virtual void device_reset() override;
+ virtual void device_start() override { };
virtual void device_add_mconfig(machine_config &config) override;
private:
- ti99_cartridge_device *m_cartridge;
+ required_device m_cartridge;
};
} // end namespace bus::ti99::gromport
diff --git a/src/devices/bus/ti99/internal/992board.cpp b/src/devices/bus/ti99/internal/992board.cpp
index a2222b36c3a..23274d08291 100644
--- a/src/devices/bus/ti99/internal/992board.cpp
+++ b/src/devices/bus/ti99/internal/992board.cpp
@@ -591,7 +591,7 @@ ioport_constructor io992_device::device_input_ports() const
ti992_expport_device::ti992_expport_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
: device_t(mconfig, TI992_EXPPORT, tag, owner, clock),
- device_slot_interface(mconfig, *this),
+ device_single_card_slot_interface(mconfig, *this),
m_connected(nullptr)
{
}
@@ -610,7 +610,7 @@ void ti992_expport_device::write(offs_t offset, uint8_t data)
void ti992_expport_device::device_config_complete()
{
- m_connected = static_cast(subdevices().first());
+ m_connected = get_card_device();
}
/*
diff --git a/src/devices/bus/ti99/internal/992board.h b/src/devices/bus/ti99/internal/992board.h
index ec345ebce0a..41c198a8e5d 100644
--- a/src/devices/bus/ti99/internal/992board.h
+++ b/src/devices/bus/ti99/internal/992board.h
@@ -174,10 +174,8 @@ class ti992_expport_attached_device : public device_t
virtual void write(offs_t offset, uint8_t data) { }
};
-class ti992_expport_device : public device_t, public device_slot_interface
+class ti992_expport_device : public device_t, public device_single_card_slot_interface
{
- friend class expport_attached_device;
-
public:
template
ti992_expport_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock, U &&opts, const char *dflt)
diff --git a/src/devices/bus/ti99/internal/ioport.h b/src/devices/bus/ti99/internal/ioport.h
index cf38f6f2540..29ac6fb7fc4 100644
--- a/src/devices/bus/ti99/internal/ioport.h
+++ b/src/devices/bus/ti99/internal/ioport.h
@@ -86,8 +86,8 @@ class ioport_device : public device_t, public device_single_card_slot_interface<
auto ready_cb() { return m_console_ready.bind(); }
protected:
- void device_start() override;
- void device_config_complete() override;
+ virtual void device_start() override;
+ virtual void device_config_complete() override;
// Methods called back from the external device
devcb_write_line m_console_extint; // EXTINT line
diff --git a/src/devices/bus/ti99/joyport/joyport.h b/src/devices/bus/ti99/joyport/joyport.h
index 40f7b358ac6..b377e6ce7c1 100644
--- a/src/devices/bus/ti99/joyport/joyport.h
+++ b/src/devices/bus/ti99/joyport/joyport.h
@@ -76,8 +76,8 @@ class joyport_device : public device_t, public device_single_card_slot_interface
auto int_cb() { return m_interrupt.bind(); }
protected:
- void device_start() override;
- void device_config_complete() override;
+ virtual void device_start() override;
+ virtual void device_config_complete() override;
private:
devcb_write_line m_interrupt;
diff --git a/src/devices/bus/ti99/peb/bwg.cpp b/src/devices/bus/ti99/peb/bwg.cpp
index 4787df88964..3f6d21a293b 100644
--- a/src/devices/bus/ti99/peb/bwg.cpp
+++ b/src/devices/bus/ti99/peb/bwg.cpp
@@ -60,7 +60,7 @@
#define LOG_MOTOR (1U << 8) // Show motor operations
#define LOG_CONFIG (1U << 9) // Configuration
-#define VERBOSE (LOG_CONFIG | LOG_WARN)
+#define VERBOSE (LOG_GENERAL | LOG_CONFIG | LOG_WARN)
#include "logmacro.h"
DEFINE_DEVICE_TYPE(TI99_BWG, bus::ti99::peb::snug_bwg_device, "ti99_bwg", "SNUG BwG Floppy Controller")
@@ -94,6 +94,7 @@ snug_bwg_device::snug_bwg_device(const machine_config &mconfig, const char *tag,
m_address(0),
m_dsrrom(nullptr),
m_buffer_ram(*this, BUFFER),
+ m_floppy(*this, "%u", 0),
m_sel_floppy(0),
m_wd1773(*this, FDC_TAG),
m_clock(*this, CLOCK_TAG),
@@ -355,10 +356,10 @@ void snug_bwg_device::crureadz(offs_t offset, uint8_t *value)
if ((offset & 0x00f0)==0)
{
// Check what drives are not connected
- reply = ((m_floppy[0] != nullptr)? 0 : 0x02) // DSK1
- | ((m_floppy[1] != nullptr)? 0 : 0x04) // DSK2
- | ((m_floppy[2] != nullptr)? 0 : 0x08) // DSK3
- | ((m_floppy[3] != nullptr)? 0 : 0x01); // DSK4
+ reply = ((m_floppy[0]->get_device() != nullptr)? 0 : 0x02) // DSK1
+ | ((m_floppy[1]->get_device() != nullptr)? 0 : 0x04) // DSK2
+ | ((m_floppy[2]->get_device() != nullptr)? 0 : 0x08) // DSK3
+ | ((m_floppy[3]->get_device() != nullptr)? 0 : 0x01); // DSK4
// DIP switches for step and date/time display
if (m_dip1 != 0) reply |= 0x10;
@@ -463,11 +464,11 @@ void snug_bwg_device::select_drive(int n, int state)
LOGMASKED(LOG_WARN, "Warning: DSK%d selected while DSK%d not yet unselected\n", n, m_sel_floppy);
}
- if (m_floppy[n-1] != nullptr)
+ if (m_floppy[n-1]->get_device() != nullptr)
{
m_sel_floppy = n;
- m_wd1773->set_floppy(m_floppy[n-1]);
- m_floppy[n-1]->ss_w(m_crulatch0_7->q7_r());
+ m_wd1773->set_floppy(m_floppy[n-1]->get_device());
+ m_floppy[n-1]->get_device()->ss_w(m_crulatch0_7->q7_r());
}
}
}
@@ -478,7 +479,7 @@ void snug_bwg_device::sidsel_w(int state)
if (m_sel_floppy != 0)
{
LOGMASKED(LOG_CRU, "Set side (bit 7) = %d on DSK%d\n", state, m_sel_floppy);
- m_floppy[m_sel_floppy-1]->ss_w(m_crulatch0_7->q7_r());
+ m_floppy[m_sel_floppy-1]->get_device()->ss_w(m_crulatch0_7->q7_r());
}
}
@@ -502,7 +503,8 @@ void snug_bwg_device::motorona_w(int state)
// Set all motors
for (auto & elem : m_floppy)
- if (elem != nullptr) elem->mon_w((state==ASSERT_LINE)? 0 : 1);
+ if (elem->get_device() != nullptr)
+ elem->get_device()->mon_w((state==ASSERT_LINE)? 0 : 1);
// The motor-on line also connects to the wait state logic
operate_ready_line();
@@ -541,13 +543,13 @@ void snug_bwg_device::device_reset()
m_address = 0;
m_WDsel = false;
m_WDsel0 = false;
-
- for (int i=0; i < 4; i++)
+
+ for (auto &flop : m_floppy)
{
- if (m_floppy[i] != nullptr)
- LOGMASKED(LOG_CONFIG, "Connector %d with %s\n", i, m_floppy[i]->name());
+ if (flop->get_device() != nullptr)
+ LOGMASKED(LOG_CONFIG, "Connector %d with %s\n", flop->basetag(), flop->get_device()->name());
else
- LOGMASKED(LOG_CONFIG, "Connector %d has no floppy attached\n", i);
+ LOGMASKED(LOG_CONFIG, "Connector %d has no floppy attached\n", flop->basetag());
}
m_wd1773->set_floppy(nullptr);
@@ -557,18 +559,6 @@ void snug_bwg_device::device_reset()
m_dip34 = ioport("BWGDIP34")->read();
}
-void snug_bwg_device::device_config_complete()
-{
- for (auto & elem : m_floppy)
- elem = nullptr;
-
- // Seems to be null when doing a "-listslots"
- if (subdevice("0")!=nullptr) m_floppy[0] = static_cast(subdevice("0")->subdevices().first());
- if (subdevice("1")!=nullptr) m_floppy[1] = static_cast(subdevice("1")->subdevices().first());
- if (subdevice("2")!=nullptr) m_floppy[2] = static_cast(subdevice("2")->subdevices().first());
- if (subdevice("3")!=nullptr) m_floppy[3] = static_cast(subdevice("3")->subdevices().first());
-}
-
INPUT_PORTS_START( bwg_fdc )
PORT_START( "BWGDIP1" )
PORT_DIPNAME( 0x01, 0x00, "BwG step rate" )
@@ -615,10 +605,10 @@ void snug_bwg_device::device_add_mconfig(machine_config& config)
MM58274C(config, CLOCK_TAG, 32.768_kHz_XTAL).set_mode_and_day(1, 0); // 24h, sunday
- FLOPPY_CONNECTOR(config, "0", bwg_floppies, "525dd", snug_bwg_device::floppy_formats).enable_sound(true);
- FLOPPY_CONNECTOR(config, "1", bwg_floppies, "525dd", snug_bwg_device::floppy_formats).enable_sound(true);
- FLOPPY_CONNECTOR(config, "2", bwg_floppies, nullptr, snug_bwg_device::floppy_formats).enable_sound(true);
- FLOPPY_CONNECTOR(config, "3", bwg_floppies, nullptr, snug_bwg_device::floppy_formats).enable_sound(true);
+ FLOPPY_CONNECTOR(config, m_floppy[0], bwg_floppies, "525dd", snug_bwg_device::floppy_formats).enable_sound(true);
+ FLOPPY_CONNECTOR(config, m_floppy[1], bwg_floppies, "525dd", snug_bwg_device::floppy_formats).enable_sound(true);
+ FLOPPY_CONNECTOR(config, m_floppy[2], bwg_floppies, nullptr, snug_bwg_device::floppy_formats).enable_sound(true);
+ FLOPPY_CONNECTOR(config, m_floppy[3], bwg_floppies, nullptr, snug_bwg_device::floppy_formats).enable_sound(true);
RAM(config, BUFFER).set_default_size("2K").set_default_value(0);
diff --git a/src/devices/bus/ti99/peb/bwg.h b/src/devices/bus/ti99/peb/bwg.h
index 752eb3aff65..4739c09c175 100644
--- a/src/devices/bus/ti99/peb/bwg.h
+++ b/src/devices/bus/ti99/peb/bwg.h
@@ -39,13 +39,12 @@ class snug_bwg_device : public device_t, public device_ti99_peribox_card_interfa
void cruwrite(offs_t offset, uint8_t data) override;
protected:
- void device_start() override;
- void device_reset() override;
- void device_config_complete() override;
+ virtual void device_start() override;
+ virtual void device_reset() override;
- const tiny_rom_entry *device_rom_region() const override;
+ virtual const tiny_rom_entry *device_rom_region() const override;
virtual void device_add_mconfig(machine_config &config) override;
- ioport_constructor device_input_ports() const override;
+ virtual ioport_constructor device_input_ports() const override;
private:
static void floppy_formats(format_registration &fr);
@@ -113,7 +112,7 @@ class snug_bwg_device : public device_t, public device_ti99_peribox_card_interfa
required_device m_buffer_ram;
// Link to the attached floppy drives
- floppy_image_device* m_floppy[4];
+ required_device_array m_floppy;
// Currently selected floppy drive (1-4, 0=none)
int m_sel_floppy;
diff --git a/src/devices/bus/ti99/peb/cc_fdc.cpp b/src/devices/bus/ti99/peb/cc_fdc.cpp
index 2fe2a74b3a0..88fa46d2aa3 100644
--- a/src/devices/bus/ti99/peb/cc_fdc.cpp
+++ b/src/devices/bus/ti99/peb/cc_fdc.cpp
@@ -72,12 +72,13 @@ namespace bus::ti99::peb {
// ----------------------------------
-corcomp_fdc_device::corcomp_fdc_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock):
+corcomp_fdc_device::corcomp_fdc_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock, const char *dpname, const char *cpname):
device_t(mconfig, type, tag, owner, clock),
device_ti99_peribox_card_interface(mconfig, *this),
m_wdc(*this, WDC_TAG),
- m_decpal(nullptr),
- m_ctrlpal(nullptr),
+ m_decpal(*this, dpname),
+ m_ctrlpal(*this, cpname),
+ m_floppy(*this, "%u", 0),
m_motormf(*this, MOTORMF_TAG),
m_tms9901(*this, TMS9901_TAG),
m_buffer_ram(*this, BUFFER),
@@ -363,10 +364,10 @@ void corcomp_fdc_device::select_dsk(int state)
}
LOGMASKED(LOG_DRIVE, "Select drive DSK%d\n", m_selected_drive);
- if (m_floppy[m_selected_drive-1] != nullptr)
+ if (m_floppy[m_selected_drive-1]->get_device() != nullptr)
{
- m_wdc->set_floppy(m_floppy[m_selected_drive-1]);
- m_floppy[m_selected_drive-1]->ss_w(m_tms9901->read_bit(tms9901_device::INT15_P7));
+ m_wdc->set_floppy(m_floppy[m_selected_drive-1]->get_device());
+ m_floppy[m_selected_drive-1]->get_device()->ss_w(m_tms9901->read_bit(tms9901_device::INT15_P7));
}
}
}
@@ -377,7 +378,7 @@ void corcomp_fdc_device::side_select(int state)
if (m_selected_drive != 0)
{
LOGMASKED(LOG_DRIVE, "Set side (bit 7) = %d on DSK%d\n", state, m_selected_drive);
- m_floppy[m_selected_drive-1]->ss_w(state);
+ m_floppy[m_selected_drive-1]->get_device()->ss_w(state);
}
}
@@ -390,8 +391,10 @@ void corcomp_fdc_device::motor_w(int state)
m_wdc->set_force_ready(state==ASSERT_LINE);
// Set all motors
- for (auto & elem : m_floppy)
- if (elem != nullptr) elem->mon_w((state==ASSERT_LINE)? 0 : 1);
+ for (auto &elem : m_floppy)
+ if (elem->get_device() != nullptr)
+ elem->get_device()->mon_w((state==ASSERT_LINE)? 0 : 1);
+
operate_ready_line();
}
@@ -426,24 +429,17 @@ void corcomp_fdc_device::device_start()
void corcomp_fdc_device::device_reset()
{
- for (int i=0; i < 4; i++)
+ for (auto &flop : m_floppy)
{
- if (m_floppy[i] != nullptr)
- LOGMASKED(LOG_CONFIG, "Connector %d with %s\n", i, m_floppy[i]->name());
+ if (flop->get_device() != nullptr)
+ LOGMASKED(LOG_CONFIG, "Connector %d with %s\n", flop->basetag(), flop->get_device()->name());
else
- LOGMASKED(LOG_CONFIG, "Connector %d has no floppy attached\n", i);
+ LOGMASKED(LOG_CONFIG, "Connector %d has no floppy attached\n", flop->basetag());
}
-}
-
-void corcomp_fdc_device::connect_drives()
-{
- for (auto & elem : m_floppy)
- elem = nullptr;
- if (subdevice("0")!=nullptr) m_floppy[0] = static_cast(subdevice("0")->subdevices().first());
- if (subdevice("1")!=nullptr) m_floppy[1] = static_cast(subdevice("1")->subdevices().first());
- if (subdevice("2")!=nullptr) m_floppy[2] = static_cast(subdevice("2")->subdevices().first());
- if (subdevice("3")!=nullptr) m_floppy[3] = static_cast(subdevice("3")->subdevices().first());
+ m_decpal->set_board(this);
+ m_ctrlpal->set_board(this);
+ m_ctrlpal->set_decoder(m_decpal);
}
INPUT_PORTS_START( cc_fdc )
@@ -528,10 +524,10 @@ void corcomp_fdc_device::common_config(machine_config& config)
m_motormf->set_clear_pin_value(1);
m_motormf->out_cb().set(FUNC(corcomp_fdc_device::motor_w));
- FLOPPY_CONNECTOR(config, "0", ccfdc_floppies, "525dd", corcomp_fdc_device::floppy_formats).enable_sound(true);
- FLOPPY_CONNECTOR(config, "1", ccfdc_floppies, "525dd", corcomp_fdc_device::floppy_formats).enable_sound(true);
- FLOPPY_CONNECTOR(config, "2", ccfdc_floppies, nullptr, corcomp_fdc_device::floppy_formats).enable_sound(true);
- FLOPPY_CONNECTOR(config, "3", ccfdc_floppies, nullptr, corcomp_fdc_device::floppy_formats).enable_sound(true);
+ FLOPPY_CONNECTOR(config, m_floppy[0], ccfdc_floppies, "525dd", corcomp_fdc_device::floppy_formats).enable_sound(true);
+ FLOPPY_CONNECTOR(config, m_floppy[1], ccfdc_floppies, "525dd", corcomp_fdc_device::floppy_formats).enable_sound(true);
+ FLOPPY_CONNECTOR(config, m_floppy[2], ccfdc_floppies, nullptr, corcomp_fdc_device::floppy_formats).enable_sound(true);
+ FLOPPY_CONNECTOR(config, m_floppy[3], ccfdc_floppies, nullptr, corcomp_fdc_device::floppy_formats).enable_sound(true);
// SRAM 2114 1Kx4
RAM(config, BUFFER).set_default_size("1k").set_default_value(0);
@@ -542,7 +538,7 @@ void corcomp_fdc_device::common_config(machine_config& config)
// ============================================================================
corcomp_dcc_device::corcomp_dcc_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock):
- corcomp_fdc_device(mconfig, TI99_CCDCC, tag, owner, clock)
+ corcomp_fdc_device(mconfig, TI99_CCDCC, tag, owner, clock, CCDCC_PALU2_TAG, CCDCC_PALU1_TAG)
{
}
@@ -565,14 +561,6 @@ ROM_START( cc_dcc )
ROM_LOAD("ccdcc_v89.u4", 0x2000, 0x2000, CRC(9c4e5c08) SHA1(26f8096ae60f3839902b4e8764c5fde283ad4ba2)) /* 8K single ROM bank 2*/
ROM_END
-void corcomp_dcc_device::device_config_complete()
-{
- m_decpal = dynamic_cast(subdevice(CCDCC_PALU2_TAG));
- m_ctrlpal = dynamic_cast(subdevice(CCDCC_PALU1_TAG));
- if (m_decpal != nullptr)
- connect_drives();
-}
-
ioport_constructor corcomp_fdc_device::device_input_ports() const
{
return INPUT_PORTS_NAME( cc_fdc );
@@ -604,12 +592,6 @@ ccfdc_sel_pal_device::ccfdc_sel_pal_device(const machine_config &mconfig, device
{
}
-void ccfdc_dec_pal_device::device_config_complete()
-{
- m_board = dynamic_cast(owner());
- // owner is the empty_state during -listxml, so this will be nullptr
-}
-
/*
Indicates 9901 addressing.
*/
@@ -707,19 +689,12 @@ int ccdcc_palu1_device::ready_out()
return ready;
}
-void ccdcc_palu1_device::device_config_complete()
-{
- m_board = dynamic_cast(owner());
- m_decpal = dynamic_cast(owner()->subdevice(CCDCC_PALU2_TAG));
- // owner is the empty_state during -listxml, so this will be nullptr
-}
-
// ============================================================================
// Revised CorComp floppy disk controller card REV A
// ============================================================================
corcomp_fdca_device::corcomp_fdca_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock):
- corcomp_fdc_device(mconfig, TI99_CCFDC, tag, owner, clock)
+ corcomp_fdc_device(mconfig, TI99_CCFDC, tag, owner, clock, CCFDC_PALU12_TAG, CCFDC_PALU6_TAG)
{
}
@@ -749,13 +724,6 @@ ROM_START( cc_fdcmg )
ROM_LOAD("ccfdc_v89mg.u2", 0x2000, 0x2000, CRC(0cad8f5b) SHA1(7744f777b51eedf614f766576bbc3f8c2c2e0042)) /* 16K single ROM */
ROM_END
-void corcomp_fdca_device::device_config_complete()
-{
- m_decpal = static_cast(subdevice(CCFDC_PALU12_TAG));
- m_ctrlpal = static_cast(subdevice(CCFDC_PALU6_TAG));
- connect_drives();
-}
-
const tiny_rom_entry *corcomp_fdca_device::device_rom_region() const
{
return ROM_NAME( cc_fdcmg );
@@ -816,7 +784,12 @@ int ccfdc_palu6_device::ready_out()
{
bool wdc = m_decpal->addresswdc(); // Addressing the WDC
bool even = (m_board->get_address()&1)==0; // A15 = 0
- bool trap = static_cast(m_board)->ready_trap_active(); // READY trap active
+ bool trap = false;
+
+ // The PAL u6 is only used on the Rev A board
+ corcomp_fdca_device* boarda = static_cast(m_board);
+ trap = boarda->ready_trap_active(); // READY trap active
+
bool waitbyte = m_wdc->drq_r()==CLEAR_LINE; // We are waiting for a byte
bool noterm = m_wdc->intrq_r()==CLEAR_LINE; // There is no interrupt yet
@@ -826,10 +799,4 @@ int ccfdc_palu6_device::ready_out()
return ready;
}
-void ccfdc_palu6_device::device_config_complete()
-{
- m_board = dynamic_cast(owner());
- m_decpal = dynamic_cast(owner()->subdevice(CCFDC_PALU12_TAG));
-}
-
} // end namespace bus::ti99::peb
diff --git a/src/devices/bus/ti99/peb/cc_fdc.h b/src/devices/bus/ti99/peb/cc_fdc.h
index b668f2cc59d..736b8c0ae14 100644
--- a/src/devices/bus/ti99/peb/cc_fdc.h
+++ b/src/devices/bus/ti99/peb/cc_fdc.h
@@ -57,14 +57,13 @@ class corcomp_fdc_device : public device_t, public device_ti99_peribox_card_inte
void select_bank(int state);
protected:
- corcomp_fdc_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock);
+ corcomp_fdc_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock, const char *dpname, const char *cpname);
- void device_start() override;
- void device_reset() override;
- void connect_drives();
+ virtual void device_start() override;
+ virtual void device_reset() override;
virtual void device_add_mconfig(machine_config &config) override =0;
- ioport_constructor device_input_ports() const override;
+ virtual ioport_constructor device_input_ports() const override;
void common_config(machine_config& config);
@@ -74,8 +73,8 @@ class corcomp_fdc_device : public device_t, public device_ti99_peribox_card_inte
required_device m_wdc;
// PALs
- ccfdc_dec_pal_device* m_decpal;
- ccfdc_sel_pal_device* m_ctrlpal;
+ required_device m_decpal;
+ required_device m_ctrlpal;
// Lines that are polled by the PAL chips
bool card_selected();
@@ -90,7 +89,7 @@ class corcomp_fdc_device : public device_t, public device_ti99_peribox_card_inte
void operate_ready_line();
// Link to the attached floppy drives
- floppy_image_device* m_floppy[4];
+ required_device_array m_floppy;
// Motor monoflop
required_device m_motormf;
@@ -131,15 +130,15 @@ class corcomp_dcc_device : public corcomp_fdc_device
{
public:
corcomp_dcc_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock);
-private:
- void device_add_mconfig(machine_config &config) override;
- void device_config_complete() override;
- const tiny_rom_entry *device_rom_region() const override;
+protected:
+ virtual void device_add_mconfig(machine_config &config) override;
+ virtual const tiny_rom_entry *device_rom_region() const override;
};
// =========== Decoder PAL circuit ================
class ccfdc_dec_pal_device : public device_t
{
+ friend class corcomp_fdc_device;
public:
int addresswdc();
int address4();
@@ -150,16 +149,18 @@ class ccfdc_dec_pal_device : public device_t
ccfdc_dec_pal_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock);
void device_start() override { }
- void device_config_complete() override;
corcomp_fdc_device* m_board;
required_device m_tms9901;
+
+ void set_board(corcomp_fdc_device* board) { m_board = board; }
};
// =========== Selector PAL circuit ================
class ccfdc_sel_pal_device : public device_t
{
+ friend class corcomp_fdc_device;
public:
int selectram();
virtual int selectwdc();
@@ -169,14 +170,16 @@ class ccfdc_sel_pal_device : public device_t
protected:
ccfdc_sel_pal_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock);
- void device_start() override { }
- virtual void device_config_complete() override =0;
+ virtual void device_start() override { }
corcomp_fdc_device* m_board;
ccfdc_dec_pal_device* m_decpal;
required_device m_motormf;
required_device m_tms9901;
required_device m_wdc;
+
+ void set_board(corcomp_fdc_device* board) { m_board = board; }
+ void set_decoder(ccfdc_dec_pal_device* decpal) { m_decpal = decpal; }
};
// =========== Specific decoder PAL circuit of the CCDCC ================
@@ -194,9 +197,6 @@ class ccdcc_palu1_device : public ccfdc_sel_pal_device
public:
ccdcc_palu1_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock);
int ready_out() override;
-
-private:
- void device_config_complete() override;
};
// ============================================================================
@@ -209,10 +209,10 @@ class corcomp_fdca_device : public corcomp_fdc_device
public:
corcomp_fdca_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock);
+protected:
+ virtual void device_add_mconfig(machine_config &config) override;
+ virtual const tiny_rom_entry *device_rom_region() const override;
private:
- void device_add_mconfig(machine_config &config) override;
- void device_config_complete() override;
- const tiny_rom_entry *device_rom_region() const override;
bool ready_trap_active();
};
@@ -235,9 +235,6 @@ class ccfdc_palu6_device : public ccfdc_sel_pal_device
int selectdsr() override;
int ready_out() override;
-
-private:
- void device_config_complete() override;
};
} // end namespace bus::ti99::peb
diff --git a/src/devices/bus/ti99/peb/hfdc.cpp b/src/devices/bus/ti99/peb/hfdc.cpp
index 5f67410a299..ad116788507 100644
--- a/src/devices/bus/ti99/peb/hfdc.cpp
+++ b/src/devices/bus/ti99/peb/hfdc.cpp
@@ -102,6 +102,8 @@ myarc_hfdc_device::myarc_hfdc_device(const machine_config &mconfig, const char *
m_motor_on_timer(nullptr),
m_hdc9234(*this, FDC_TAG),
m_clock(*this, CLOCK_TAG),
+ m_floppy(*this, "f%u", 1),
+ m_harddisk(*this, "h%u", 1),
m_current_floppy(nullptr),
m_current_harddisk(nullptr),
m_current_floppy_index(NONE),
@@ -727,7 +729,7 @@ void myarc_hfdc_device::connect_floppy_unit(int index)
LOGMASKED(LOG_LINES, "Select floppy drive DSK%d\n", index+1);
// Connect new drive
- m_current_floppy = m_floppy_unit[index];
+ m_current_floppy = m_floppy[index]->get_device();
m_current_floppy_index = index;
// We don't use the READY line of floppy drives.
@@ -757,7 +759,7 @@ void myarc_hfdc_device::connect_harddisk_unit(int index)
LOGMASKED(LOG_LINES, "Select hard disk WDS%d\n", index+1);
// Connect new drive
- m_current_harddisk = m_harddisk_unit[index];
+ m_current_harddisk = m_harddisk[index]->get_device();
m_current_hd_index = index;
LOGMASKED(LOG_LINES, "Connect index callback WDS%d\n", index+1);
@@ -819,8 +821,8 @@ void myarc_hfdc_device::set_floppy_motors_running(bool run)
}
// Set all motors
- for (auto & elem : m_floppy_unit)
- if (elem != nullptr) elem->mon_w((run)? 0 : 1);
+ for (auto & elem : m_floppy)
+ if (elem->get_device() != nullptr) elem->get_device()->mon_w((run)? 0 : 1);
}
/*
@@ -943,20 +945,20 @@ void myarc_hfdc_device::device_reset()
m_lastval = 0;
m_readyflags = 0;
- for (int i=0; i < 4; i++)
+ for (auto &flop : m_floppy)
{
- if (m_floppy_unit[i] != nullptr)
- LOGMASKED(LOG_CONFIG, "FD connector %d with %s\n", i+1, m_floppy_unit[i]->name());
+ if (flop->get_device() != nullptr)
+ LOGMASKED(LOG_CONFIG, "FD connector %d with %s\n", flop->basetag(), flop->get_device()->name());
else
- LOGMASKED(LOG_CONFIG, "FD connector %d has no floppy attached\n", i+1);
+ LOGMASKED(LOG_CONFIG, "FD connector %d has no floppy attached\n", flop->basetag());
}
- for (int i=0; i < 3; i++)
+ for (auto &hard : m_harddisk)
{
- if (m_harddisk_unit[i] != nullptr)
- LOGMASKED(LOG_CONFIG, "HD connector %d with %s\n", i+1, m_harddisk_unit[i]->name());
+ if (hard->get_device() != nullptr)
+ LOGMASKED(LOG_CONFIG, "HD connector %d with %s\n", hard->basetag(), hard->get_device()->name());
else
- LOGMASKED(LOG_CONFIG, "HD connector %d has no drive attached\n", i+1);
+ LOGMASKED(LOG_CONFIG, "HD connector %d has no floppy attached\n", hard->basetag());
}
// Disconnect all units
@@ -964,29 +966,6 @@ void myarc_hfdc_device::device_reset()
disconnect_hard_drives();
}
-void myarc_hfdc_device::device_config_complete()
-{
- for (int i=0; i < 3; i++)
- {
- m_floppy_unit[i] = nullptr;
- m_harddisk_unit[i] = nullptr;
- }
- m_floppy_unit[3] = nullptr;
-
- // Seems to be null when doing a "-listslots"
- if (subdevice("f1")!=nullptr)
- {
- m_floppy_unit[0] = static_cast(subdevice("f1"))->get_device();
- m_floppy_unit[1] = static_cast(subdevice("f2"))->get_device();
- m_floppy_unit[2] = static_cast(subdevice("f3"))->get_device();
- m_floppy_unit[3] = static_cast(subdevice("f4"))->get_device();
-
- m_harddisk_unit[0] = static_cast(subdevice("h1"))->get_device();
- m_harddisk_unit[1] = static_cast(subdevice("h2"))->get_device();
- m_harddisk_unit[2] = static_cast(subdevice("h3"))->get_device();
- }
-}
-
/*
The HFDC controller can be configured for different CRU base addresses,
but DSK1-DSK4 are only available for CRU 1100. For all other addresses,
@@ -1080,15 +1059,15 @@ void myarc_hfdc_device::device_add_mconfig(machine_config& config)
m_hdc9234->dmaout_cb().set(FUNC(myarc_hfdc_device::write_buffer));
// First two floppy drives shall be connected by default
- FLOPPY_CONNECTOR(config, "f1", hfdc_floppies, "525dd", myarc_hfdc_device::floppy_formats).enable_sound(true);
- FLOPPY_CONNECTOR(config, "f2", hfdc_floppies, "525dd", myarc_hfdc_device::floppy_formats).enable_sound(true);
- FLOPPY_CONNECTOR(config, "f3", hfdc_floppies, nullptr, myarc_hfdc_device::floppy_formats).enable_sound(true);
- FLOPPY_CONNECTOR(config, "f4", hfdc_floppies, nullptr, myarc_hfdc_device::floppy_formats).enable_sound(true);
+ FLOPPY_CONNECTOR(config, m_floppy[0], hfdc_floppies, "525dd", myarc_hfdc_device::floppy_formats).enable_sound(true);
+ FLOPPY_CONNECTOR(config, m_floppy[1], hfdc_floppies, "525dd", myarc_hfdc_device::floppy_formats).enable_sound(true);
+ FLOPPY_CONNECTOR(config, m_floppy[2], hfdc_floppies, nullptr, myarc_hfdc_device::floppy_formats).enable_sound(true);
+ FLOPPY_CONNECTOR(config, m_floppy[3], hfdc_floppies, nullptr, myarc_hfdc_device::floppy_formats).enable_sound(true);
// Hard disks don't go without image (other than floppy drives)
- MFM_HD_CONNECTOR(config, "h1", hfdc_harddisks, nullptr, MFM_BYTE, 3000, 20, MFMHD_GEN_FORMAT);
- MFM_HD_CONNECTOR(config, "h2", hfdc_harddisks, nullptr, MFM_BYTE, 3000, 20, MFMHD_GEN_FORMAT);
- MFM_HD_CONNECTOR(config, "h3", hfdc_harddisks, nullptr, MFM_BYTE, 3000, 20, MFMHD_GEN_FORMAT);
+ MFM_HD_CONNECTOR(config, m_harddisk[0], hfdc_harddisks, nullptr, MFM_BYTE, 3000, 20, MFMHD_GEN_FORMAT);
+ MFM_HD_CONNECTOR(config, m_harddisk[1], hfdc_harddisks, nullptr, MFM_BYTE, 3000, 20, MFMHD_GEN_FORMAT);
+ MFM_HD_CONNECTOR(config, m_harddisk[2], hfdc_harddisks, nullptr, MFM_BYTE, 3000, 20, MFMHD_GEN_FORMAT);
MM58274C(config, CLOCK_TAG, 0).set_mode_and_day(1, 0); // 24h, sunday
diff --git a/src/devices/bus/ti99/peb/hfdc.h b/src/devices/bus/ti99/peb/hfdc.h
index aeff0cca3ad..a600412849a 100644
--- a/src/devices/bus/ti99/peb/hfdc.h
+++ b/src/devices/bus/ti99/peb/hfdc.h
@@ -44,8 +44,6 @@ class myarc_hfdc_device : public device_t, public device_ti99_peribox_card_inter
virtual void cruwrite(offs_t offset, uint8_t data) override;
protected:
- virtual void device_config_complete() override;
-
virtual void device_start() override;
virtual void device_reset() override;
@@ -101,10 +99,10 @@ class myarc_hfdc_device : public device_t, public device_ti99_peribox_card_inter
required_device m_clock;
// Link to the attached floppy drives
- floppy_image_device* m_floppy_unit[4];
+ required_device_array m_floppy;
// Link to the attached hard disks
- mfm_harddisk_device* m_harddisk_unit[3];
+ required_device_array m_harddisk;
// Currently selected floppy drive
floppy_image_device* m_current_floppy;
diff --git a/src/devices/bus/ti99/peb/myarcfdc.cpp b/src/devices/bus/ti99/peb/myarcfdc.cpp
index bcaacf0222e..6d96c9587c1 100644
--- a/src/devices/bus/ti99/peb/myarcfdc.cpp
+++ b/src/devices/bus/ti99/peb/myarcfdc.cpp
@@ -64,6 +64,7 @@ myarc_fdc_device::myarc_fdc_device(const machine_config &mconfig, const char *ta
m_buffer_ram(*this, BUFFER_TAG),
m_pal(*this, PAL_TAG),
m_dsrrom(nullptr),
+ m_floppy(*this, "%u", 0),
m_banksel(false),
m_cardsel(false),
m_selected_drive(0),
@@ -274,8 +275,8 @@ void myarc_fdc_device::fdc_mon_w(int state)
// Do not start the motors when no drive is selected. However, motors
// can always be stopped.
if (m_selected_drive != 0 || state==1)
- for (int i = 0; i < 4; i++)
- if (m_floppy[i] != nullptr) m_floppy[i]->mon_w(state);
+ for (auto &flop : m_floppy)
+ if (flop->get_device() != nullptr) flop->get_device()->mon_w(state);
}
/*
@@ -299,7 +300,7 @@ void myarc_fdc_device::sidsel_w(int state)
if (m_selected_drive != 0)
{
LOGMASKED(LOG_DRIVE, "Set side = %d on DSK%d\n", state, m_selected_drive);
- m_floppy[m_selected_drive-1]->ss_w(state);
+ m_floppy[m_selected_drive-1]->get_device()->ss_w(state);
}
}
@@ -335,12 +336,12 @@ void myarc_fdc_device::drivesel_w(int state)
}
else
{
- if (m_floppy[driveno-1] != nullptr)
+ if (m_floppy[driveno-1]->get_device() != nullptr)
{
m_selected_drive = driveno;
LOGMASKED(LOG_DRIVE, "Select drive DSK%d\n", driveno);
- m_wdc->set_floppy(m_floppy[driveno-1]);
- m_floppy[driveno-1]->ss_w(m_drivelatch->q2_r());
+ m_wdc->set_floppy(m_floppy[driveno-1]->get_device());
+ m_floppy[driveno-1]->get_device()->ss_w(m_drivelatch->q2_r());
}
}
}
@@ -356,23 +357,22 @@ void myarc_fdc_device::device_start()
void myarc_fdc_device::device_reset()
{
+ for (auto &flop : m_floppy)
+ {
+ if (flop->get_device() != nullptr)
+ LOGMASKED(LOG_CONFIG, "Connector %d with %s\n", flop->basetag(), flop->get_device()->name());
+ else
+ LOGMASKED(LOG_CONFIG, "Connector %d has no floppy attached\n", flop->basetag());
+ }
+
if (ioport("CONTROLLER")->read()==0)
m_wdc = m_wd1770;
else
m_wdc = m_wd1772;
m_dec_high = (ioport("AMADECODE")->read()!=0);
-}
-
-void myarc_fdc_device::device_config_complete()
-{
- for (auto & elem : m_floppy)
- elem = nullptr;
-
- if (subdevice("0")!=nullptr) m_floppy[0] = static_cast(subdevice("0")->subdevices().first());
- if (subdevice("1")!=nullptr) m_floppy[1] = static_cast(subdevice("1")->subdevices().first());
- if (subdevice("2")!=nullptr) m_floppy[2] = static_cast(subdevice("2")->subdevices().first());
- if (subdevice("3")!=nullptr) m_floppy[3] = static_cast(subdevice("3")->subdevices().first());
+
+ m_pal->set_board(this);
}
void myarc_fdc_device::floppy_formats(format_registration &fr)
@@ -459,10 +459,10 @@ void myarc_fdc_device::device_add_mconfig(machine_config& config)
DDCC1_PAL(config, PAL_TAG, 0);
// Floppy drives
- FLOPPY_CONNECTOR(config, "0", myarc_ddcc_floppies, "525dd", myarc_fdc_device::floppy_formats).enable_sound(true);
- FLOPPY_CONNECTOR(config, "1", myarc_ddcc_floppies, "525dd", myarc_fdc_device::floppy_formats).enable_sound(true);
- FLOPPY_CONNECTOR(config, "2", myarc_ddcc_floppies, nullptr, myarc_fdc_device::floppy_formats).enable_sound(true);
- FLOPPY_CONNECTOR(config, "3", myarc_ddcc_floppies, nullptr, myarc_fdc_device::floppy_formats).enable_sound(true);
+ FLOPPY_CONNECTOR(config, m_floppy[0], myarc_ddcc_floppies, "525dd", myarc_fdc_device::floppy_formats).enable_sound(true);
+ FLOPPY_CONNECTOR(config, m_floppy[1], myarc_ddcc_floppies, "525dd", myarc_fdc_device::floppy_formats).enable_sound(true);
+ FLOPPY_CONNECTOR(config, m_floppy[2], myarc_ddcc_floppies, nullptr, myarc_fdc_device::floppy_formats).enable_sound(true);
+ FLOPPY_CONNECTOR(config, m_floppy[3], myarc_ddcc_floppies, nullptr, myarc_fdc_device::floppy_formats).enable_sound(true);
}
ioport_constructor myarc_fdc_device::device_input_ports() const
@@ -512,10 +512,4 @@ bool ddcc1_pal_device::cs259()
return ((m_board->get_address() & 0xff00)==0x1100);
}
-void ddcc1_pal_device::device_config_complete()
-{
- m_board = dynamic_cast(owner());
- // owner is the empty_state during -listxml, so this will be nullptr
-}
-
} // end namespace bus::ti99::peb
diff --git a/src/devices/bus/ti99/peb/myarcfdc.h b/src/devices/bus/ti99/peb/myarcfdc.h
index 8e64b55e483..2e3bd355576 100644
--- a/src/devices/bus/ti99/peb/myarcfdc.h
+++ b/src/devices/bus/ti99/peb/myarcfdc.h
@@ -38,15 +38,15 @@ class myarc_fdc_device : public device_t, public device_ti99_peribox_card_interf
void crureadz(offs_t offset, uint8_t *value) override;
void cruwrite(offs_t offset, uint8_t data) override;
-private:
- void device_start() override;
- void device_reset() override;
- void device_config_complete() override;
+protected:
+ virtual void device_start() override;
+ virtual void device_reset() override;
- const tiny_rom_entry *device_rom_region() const override;
- void device_add_mconfig(machine_config &config) override;
- ioport_constructor device_input_ports() const override;
+ virtual const tiny_rom_entry *device_rom_region() const override;
+ virtual void device_add_mconfig(machine_config &config) override;
+ virtual ioport_constructor device_input_ports() const override;
+private:
static void floppy_formats(format_registration &fr);
// Callback methods
@@ -86,7 +86,7 @@ class myarc_fdc_device : public device_t, public device_ti99_peribox_card_interf
uint8_t* m_dsrrom;
// Link to the attached floppy drives
- floppy_image_device* m_floppy[4];
+ required_device_array m_floppy;
// Debugger accessors
void debug_read(offs_t offset, uint8_t* value);
@@ -111,6 +111,8 @@ class myarc_fdc_device : public device_t, public device_ti99_peribox_card_interf
// =========== Decoder PAL circuit ================
class ddcc1_pal_device : public device_t
{
+ friend class myarc_fdc_device;
+
public:
ddcc1_pal_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock);
@@ -123,9 +125,8 @@ class ddcc1_pal_device : public device_t
private:
void device_start() override { }
- void device_config_complete() override;
-
myarc_fdc_device* m_board;
+ void set_board(myarc_fdc_device* board) { m_board = board; }
};
} // end namespace bus::ti99::peb
diff --git a/src/devices/bus/ti99/peb/peribox.cpp b/src/devices/bus/ti99/peb/peribox.cpp
index c2d9fe68d11..4df80e153d5 100644
--- a/src/devices/bus/ti99/peb/peribox.cpp
+++ b/src/devices/bus/ti99/peb/peribox.cpp
@@ -683,6 +683,7 @@ peribox_slot_device::peribox_slot_device(const machine_config &mconfig, const ch
device_t(mconfig, TI99_PERIBOX_SLOT, tag, owner, clock),
device_single_card_slot_interface(mconfig, *this),
m_card(nullptr),
+ m_peb(nullptr),
m_slotnumber(0)
{
}
@@ -739,9 +740,9 @@ void peribox_slot_device::device_start()
void peribox_slot_device::device_config_complete()
{
m_card = get_card_device();
- peribox_device *peb = dynamic_cast(owner());
- if (peb)
- peb->set_slot_loaded(m_slotnumber, m_card ? this : nullptr);
+ m_peb = dynamic_cast(owner());
+ if (m_peb)
+ m_peb->set_slot_loaded(m_slotnumber, m_card ? this : nullptr);
}
/*
@@ -750,26 +751,26 @@ void peribox_slot_device::device_config_complete()
*/
void peribox_slot_device::set_inta(int state)
{
- peribox_device *peb = static_cast(owner());
- peb->inta_join(m_slotnumber, state);
+ if (m_peb)
+ m_peb->inta_join(m_slotnumber, state);
}
void peribox_slot_device::set_intb(int state)
{
- peribox_device *peb = static_cast(owner());
- peb->intb_join(m_slotnumber, state);
+ if (m_peb)
+ m_peb->intb_join(m_slotnumber, state);
}
void peribox_slot_device::lcp_line(int state)
{
- peribox_device *peb = static_cast(owner());
- peb->lcp_join(m_slotnumber, state);
+ if (m_peb)
+ m_peb->lcp_join(m_slotnumber, state);
}
void peribox_slot_device::set_ready(int state)
{
- peribox_device *peb = static_cast(owner());
- peb->ready_join(m_slotnumber, state);
+ if (m_peb)
+ m_peb->ready_join(m_slotnumber, state);
}
/***************************************************************************/
diff --git a/src/devices/bus/ti99/peb/peribox.h b/src/devices/bus/ti99/peb/peribox.h
index ca0c84f2ec3..d8e19ff0e66 100644
--- a/src/devices/bus/ti99/peb/peribox.h
+++ b/src/devices/bus/ti99/peb/peribox.h
@@ -125,7 +125,7 @@ class peribox_sg_device : public peribox_device
peribox_sg_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock);
protected:
- void device_add_mconfig(machine_config &config) override;
+ virtual void device_add_mconfig(machine_config &config) override;
};
/*
@@ -137,7 +137,7 @@ class peribox_ev_device : public peribox_device
peribox_ev_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock);
protected:
- void device_add_mconfig(machine_config &config) override;
+ virtual void device_add_mconfig(machine_config &config) override;
};
@@ -163,7 +163,7 @@ class peribox_genmod_device : public peribox_gen_device
peribox_genmod_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock);
protected:
- void device_add_mconfig(machine_config &config) override;
+ virtual void device_add_mconfig(machine_config &config) override;
};
/*****************************************************************************
@@ -251,12 +251,13 @@ class peribox_slot_device : public device_t, public device_single_card_slot_inte
void set_number(int number) { m_slotnumber = number; }
protected:
- void device_start() override;
- void device_config_complete() override;
+ virtual void device_start() override;
+ virtual void device_config_complete() override;
private:
int get_index_from_tagname();
device_ti99_peribox_card_interface *m_card;
+ peribox_device *m_peb;
int m_slotnumber;
const char* card_name() { return m_card->device().tag(); }
};
diff --git a/src/devices/bus/ti99/peb/scsicard.cpp b/src/devices/bus/ti99/peb/scsicard.cpp
index 1299ccc45a9..4ffe141aeb7 100644
--- a/src/devices/bus/ti99/peb/scsicard.cpp
+++ b/src/devices/bus/ti99/peb/scsicard.cpp
@@ -375,7 +375,8 @@ void whtech_scsi_card_device::device_add_mconfig(machine_config &config)
RAM(config, BUFFER).set_default_size("32K").set_default_value(0);
// PLD circuit
- WHTSCSI_PLD(config, PLD_TAG, 0);
+ WHTSCSI_PLD(config, m_pld, 0);
+ m_pld->set_board(this);
// SCSI bus
NSCSI_BUS(config, m_scsibus);
@@ -695,10 +696,4 @@ void whtscsi_pld_device::update_line_states(int address, bool drq, bool irq)
m_readyout = (irq || !m_dma_lock)? true : drq;
}
-void whtscsi_pld_device::device_config_complete()
-{
- m_board = dynamic_cast(owner());
- // owner is the empty_state during -listxml, so this will be nullptr
-}
-
} // end namespace bus::ti99::peb
diff --git a/src/devices/bus/ti99/peb/scsicard.h b/src/devices/bus/ti99/peb/scsicard.h
index f442f9ffde1..e41bdcc3948 100644
--- a/src/devices/bus/ti99/peb/scsicard.h
+++ b/src/devices/bus/ti99/peb/scsicard.h
@@ -41,13 +41,14 @@ class whtech_scsi_card_device : public device_t, public device_ti99_peribox_card
void debug_read(offs_t offset, uint8_t* value);
void debug_write(offs_t offset, uint8_t data);
-private:
- void device_start() override;
- void device_reset() override;
- void device_add_mconfig(machine_config &config) override;
- ioport_constructor device_input_ports() const override;
- const tiny_rom_entry *device_rom_region() const override;
+protected:
+ virtual void device_start() override;
+ virtual void device_reset() override;
+ virtual void device_add_mconfig(machine_config &config) override;
+ virtual ioport_constructor device_input_ports() const override;
+ virtual const tiny_rom_entry *device_rom_region() const override;
+private:
// SCSI card on-board SRAM (32K)
required_device m_buffer_ram;
@@ -93,6 +94,8 @@ class whtech_scsi_card_device : public device_t, public device_ti99_peribox_card
class whtscsi_pld_device : public device_t
{
+ friend class whtech_scsi_card_device;
+
public:
whtscsi_pld_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock);
@@ -113,13 +116,14 @@ class whtscsi_pld_device : public device_t
void update_line_states(int address, bool drq, bool irq);
-private:
- void device_start() override;
- void device_reset() override;
- void device_config_complete() override;
+protected:
+ virtual void device_start() override;
+ virtual void device_reset() override;
+private:
whtech_scsi_card_device* m_board;
+ void set_board(whtech_scsi_card_device* board) { m_board = board; }
bool busen();
// Flags
diff --git a/src/devices/bus/ti99/peb/ti_fdc.cpp b/src/devices/bus/ti99/peb/ti_fdc.cpp
index bca56861607..2bb69dfbca6 100644
--- a/src/devices/bus/ti99/peb/ti_fdc.cpp
+++ b/src/devices/bus/ti99/peb/ti_fdc.cpp
@@ -29,7 +29,7 @@
#define LOG_MOTOR (1U << 10)
#define LOG_ADDRESS (1U << 11)
-#define VERBOSE (LOG_CONFIG | LOG_WARN)
+#define VERBOSE (LOG_GENERAL | LOG_CONFIG | LOG_WARN)
#include "logmacro.h"
DEFINE_DEVICE_TYPE(TI99_FDC, bus::ti99::peb::ti_fdc_device, "ti99_fdc", "TI-99 Standard DSSD Floppy Controller")
@@ -56,6 +56,7 @@ ti_fdc_device::ti_fdc_device(const machine_config &mconfig, const char *tag, dev
m_crulatch(*this, "crulatch"),
m_motormf(*this, "motormf"),
m_dsrrom(nullptr),
+ m_floppy(*this, "%u", 0),
m_sel_floppy(0)
{
}
@@ -255,7 +256,8 @@ void ti_fdc_device::dvena_w(int state)
// Set all motors
for (auto & elem : m_floppy)
- if (elem != nullptr) elem->mon_w((state==ASSERT_LINE)? 0 : 1);
+ if (elem->get_device() != nullptr)
+ elem->get_device()->mon_w((state==ASSERT_LINE)? 0 : 1);
// The motor-on line also connects to the wait state logic
operate_ready_line();
@@ -281,7 +283,8 @@ void ti_fdc_device::sidsel_w(int state)
{
// Select side of disk (bit 7)
LOGMASKED(LOG_CRU, "Set side (bit 7) = %d\n", state);
- if (m_sel_floppy != 0) m_floppy[m_sel_floppy-1]->ss_w(state);
+ if (m_sel_floppy > 0)
+ m_floppy[m_sel_floppy-1]->get_device()->ss_w(state);
}
/*
@@ -323,12 +326,12 @@ void ti_fdc_device::select_drive(int n, int state)
{
LOGMASKED(LOG_WARN, "Warning: DSK%d selected while DSK%d not yet unselected\n", n, m_sel_floppy);
}
-
- if (m_floppy[n-1] != nullptr)
+
+ if (m_floppy[n-1]->get_device() != nullptr)
{
m_sel_floppy = n;
- m_fd1771->set_floppy(m_floppy[n-1]);
- m_floppy[n-1]->ss_w(m_crulatch->q7_r());
+ m_fd1771->set_floppy(m_floppy[n-1]->get_device());
+ m_floppy[n-1]->get_device()->ss_w(m_crulatch->q7_r());
}
}
}
@@ -357,28 +360,18 @@ void ti_fdc_device::device_reset()
m_selected = false;
m_inDsrArea = false;
m_WDsel = false;
-
- for (int i=0; i < 3; i++)
+
+ for (auto &flop : m_floppy)
{
- if (m_floppy[i] != nullptr)
- LOGMASKED(LOG_CONFIG, "Connector %d with %s\n", i, m_floppy[i]->name());
+ if (flop->get_device() != nullptr)
+ LOGMASKED(LOG_CONFIG, "Connector %d with %s\n", flop->basetag(), flop->get_device()->name());
else
- LOGMASKED(LOG_CONFIG, "No floppy attached to connector %d\n", i);
+ LOGMASKED(LOG_CONFIG, "Connector %d has no floppy attached\n", flop->basetag());
}
-
+
m_sel_floppy = 0;
}
-void ti_fdc_device::device_config_complete()
-{
- // Seems to be null when doing a "-listslots"
- for (auto &elem : m_floppy)
- elem = nullptr;
- if (subdevice("0")!=nullptr) m_floppy[0] = static_cast(subdevice("0")->subdevices().first());
- if (subdevice("1")!=nullptr) m_floppy[1] = static_cast(subdevice("1")->subdevices().first());
- if (subdevice("2")!=nullptr) m_floppy[2] = static_cast(subdevice("2")->subdevices().first());
-}
-
void ti_fdc_device::floppy_formats(format_registration &fr)
{
fr.add_mfm_containers();
@@ -404,9 +397,9 @@ void ti_fdc_device::device_add_mconfig(machine_config& config)
m_fd1771->drq_wr_callback().set(FUNC(ti_fdc_device::fdc_drq_w));
m_fd1771->hld_wr_callback().set(FUNC(ti_fdc_device::fdc_hld_w));
- FLOPPY_CONNECTOR(config, "0", tifdc_floppies, "525dd", ti_fdc_device::floppy_formats).enable_sound(true);
- FLOPPY_CONNECTOR(config, "1", tifdc_floppies, "525dd", ti_fdc_device::floppy_formats).enable_sound(true);
- FLOPPY_CONNECTOR(config, "2", tifdc_floppies, nullptr, ti_fdc_device::floppy_formats).enable_sound(true);
+ FLOPPY_CONNECTOR(config, m_floppy[0], tifdc_floppies, "525dd", ti_fdc_device::floppy_formats).enable_sound(true);
+ FLOPPY_CONNECTOR(config, m_floppy[1], tifdc_floppies, "525dd", ti_fdc_device::floppy_formats).enable_sound(true);
+ FLOPPY_CONNECTOR(config, m_floppy[2], tifdc_floppies, nullptr, ti_fdc_device::floppy_formats).enable_sound(true);
LS259(config, m_crulatch); // U23
m_crulatch->q_out_cb<0>().set(FUNC(ti_fdc_device::dskpgena_w));
diff --git a/src/devices/bus/ti99/peb/ti_fdc.h b/src/devices/bus/ti99/peb/ti_fdc.h
index 0de44473001..3b67295d367 100644
--- a/src/devices/bus/ti99/peb/ti_fdc.h
+++ b/src/devices/bus/ti99/peb/ti_fdc.h
@@ -38,11 +38,10 @@ class ti_fdc_device : public device_t, public device_ti99_peribox_card_interface
// bool dvena_r();
protected:
- void device_start() override;
- void device_reset() override;
- void device_config_complete() override;
+ virtual void device_start() override;
+ virtual void device_reset() override;
- const tiny_rom_entry *device_rom_region() const override;
+ virtual const tiny_rom_entry *device_rom_region() const override;
virtual void device_add_mconfig(machine_config &config) override;
private:
@@ -105,7 +104,7 @@ class ti_fdc_device : public device_t, public device_ti99_peribox_card_interface
uint8_t* m_dsrrom;
// Link to the attached floppy drives
- floppy_image_device* m_floppy[3];
+ required_device_array m_floppy;
// Currently selected floppy drive
int m_sel_floppy;
diff --git a/src/devices/bus/ti99/peb/ti_rs232.cpp b/src/devices/bus/ti99/peb/ti_rs232.cpp
index 3fe4968630c..1005029b23c 100644
--- a/src/devices/bus/ti99/peb/ti_rs232.cpp
+++ b/src/devices/bus/ti99/peb/ti_rs232.cpp
@@ -206,17 +206,15 @@ void ti_rs232_attached_device::call_unload()
*/
std::pair ti_pio_attached_device::call_load()
{
- ti_rs232_pio_device* card = static_cast(owner());
-
// tell whether the image is readable
- card->m_pio_readable = true;
+ m_card->m_pio_readable = true;
// tell whether the image is writable
- card->m_pio_writable = !is_readonly();
+ m_card->m_pio_writable = !is_readonly();
- if (card->m_pio_write && card->m_pio_writable)
- card->m_pio_handshakein = false; // receiver ready
+ if (m_card->m_pio_write && m_card->m_pio_writable)
+ m_card->m_pio_handshakein = false; // receiver ready
else
- card->m_pio_handshakein = true;
+ m_card->m_pio_handshakein = true;
return std::make_pair(std::error_condition(), std::string()); // OK
}
@@ -226,11 +224,9 @@ std::pair ti_pio_attached_device::call_load()
*/
void ti_pio_attached_device::call_unload()
{
- ti_rs232_pio_device* card = static_cast(owner());
-
- card->m_pio_writable = false;
- card->m_pio_handshakein = true; /* receiver not ready */
- card->m_pio_sparein = false;
+ m_card->m_pio_writable = false;
+ m_card->m_pio_handshakein = true; /* receiver not ready */
+ m_card->m_pio_sparein = false;
}
/****************************************************************************/
@@ -1108,6 +1104,7 @@ void ti_rs232_pio_device::device_add_mconfig(machine_config &config)
m_serdev1->connect(m_uart1);
TI99_PIO_DEV(config, m_piodev, 0);
+ m_piodev->set_card(this);
LS259(config, m_crulatch); // U12
m_crulatch->q_out_cb<0>().set(FUNC(ti_rs232_pio_device::selected_w));
diff --git a/src/devices/bus/ti99/peb/ti_rs232.h b/src/devices/bus/ti99/peb/ti_rs232.h
index c10fd7e81a4..edd20827765 100644
--- a/src/devices/bus/ti99/peb/ti_rs232.h
+++ b/src/devices/bus/ti99/peb/ti_rs232.h
@@ -38,12 +38,12 @@ class ti_rs232_pio_device : public device_t, public device_ti99_peribox_card_int
void cruwrite(offs_t offset, uint8_t data) override;
protected:
- void device_start() override;
- void device_reset() override;
- void device_stop() override;
- const tiny_rom_entry *device_rom_region() const override;
- void device_add_mconfig(machine_config &config) override;
- ioport_constructor device_input_ports() const override;
+ virtual void device_start() override;
+ virtual void device_reset() override;
+ virtual void device_stop() override;
+ virtual const tiny_rom_entry *device_rom_region() const override;
+ virtual void device_add_mconfig(machine_config &config) override;
+ virtual ioport_constructor device_input_ports() const override;
private:
void int0_callback(int state);
@@ -159,6 +159,7 @@ class ti_rs232_attached_device : public device_t, public device_image_interface
*/
class ti_pio_attached_device : public device_t, public device_image_interface
{
+ friend class ti_rs232_pio_device;
public:
ti_pio_attached_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock);
@@ -176,6 +177,10 @@ class ti_pio_attached_device : public device_t, public device_image_interface
void device_start() override { }
std::pair call_load() override;
void call_unload() override;
+
+private:
+ ti_rs232_pio_device* m_card;
+ void set_card(ti_rs232_pio_device* card) { m_card = card; }
};
} // end namespace bus::ti99::peb
diff --git a/src/devices/cpu/palm/palm.cpp b/src/devices/cpu/palm/palm.cpp
index 4e7558770d6..0febe5b3793 100644
--- a/src/devices/cpu/palm/palm.cpp
+++ b/src/devices/cpu/palm/palm.cpp
@@ -8,7 +8,7 @@
* - IBM 5100 Maintenance Information Manual, SY31-0405-3, Fourth Edition (October 1979), International Business Machines Corporation
*
* TODO:
- * - machine check/interrupts
+ * - machine check
* - instruction timing
*/
@@ -30,6 +30,8 @@ template constexpr T IBIT(T x, U n, V w)
return BIT(x, sizeof(T) * 8 - n - w, w);
}
+static u8 constexpr il_priority[] = { 0, 1, 2, 2, 3, 3, 3, 3 };
+
DEFINE_DEVICE_TYPE(PALM, palm_device, "palm", "IBM PALM")
palm_device::palm_device(machine_config const &mconfig, char const *tag, device_t *owner, u32 clock)
@@ -38,29 +40,41 @@ palm_device::palm_device(machine_config const &mconfig, char const *tag, device_
, m_rws_config("rws", ENDIANNESS_BIG, 16, 16)
, m_ioc_config("ioc", ENDIANNESS_BIG, 8, 4)
, m_iod_config("iod", ENDIANNESS_BIG, 8, 4)
+ , m_getb_bus(*this)
+ , m_select_ros(*this)
, m_icount(0)
, m_r{}
- , m_il(0)
- , m_il_pending(0)
- , m_irpt_req(0)
{
}
+enum ff_mask : u8
+{
+ FF_IPL = 0x80, // initial program load
+ FF_MSS = 0x40, // microprogram storage switch
+
+ FF_IE = 0x08, // interrupt enable
+ FF_IR3 = 0x04, // interrupt request 3
+ FF_IR2 = 0x02, // interrupt request 2
+ FF_IR1 = 0x01, // interrupt request 1
+
+ FF_IR = 0x07, // interrupt request
+};
+
void palm_device::device_start()
{
set_icountptr(m_icount);
- state_add(STATE_GENPC, "GENPC", m_r[m_il][0]).mask(0xfffe).noshow();
- state_add(STATE_GENPCBASE, "CURPC", m_r[m_il][0]).mask(0xfffe);
+ state_add(STATE_GENPC, "GENPC", m_pc).noshow();
+ state_add(STATE_GENPCBASE, "CURPC", [this]() { return m_r[m_il][0] & 0xfffeU; });
state_add(0, "IL", m_il);
for (unsigned i = 0; i < std::size(m_r[m_il]); i++)
- state_add(i + 1, util::string_format("R%d", i).c_str(), m_r[m_il][i]);
+ state_add(i + 1, util::string_format("R%d", i).c_str(), [this, i]() { return m_r[m_il][i]; }, [this, i](u16 data) { m_r[m_il][i] = data; });
+ save_item(NAME(m_pc));
save_item(NAME(m_r));
save_item(NAME(m_il));
- save_item(NAME(m_il_pending));
- save_item(NAME(m_irpt_req));
+ save_item(NAME(m_ff));
space(AS_ROS).specific(m_ros);
space(AS_RWS).specific(m_rws);
@@ -72,10 +86,13 @@ void palm_device::device_reset()
{
space(AS_RWS).install_ram(0, sizeof(m_r) - 1, m_r);
- m_il = 0;
+ // select instruction source
+ m_ff = FF_IPL | FF_MSS;
+ m_select_ros((m_ff & FF_MSS) && !(m_ff & FF_IPL));
// read initial PC from ROS
- m_r[m_il][0] = m_ros.read_word(0);
+ m_il = 0;
+ m_pc = m_r[m_il][0] = m_ros.read_word(0);
}
#define Rx r[IBIT(op, 4, 4)]
@@ -88,13 +105,14 @@ void palm_device::execute_run()
{
while (m_icount > 0)
{
- // immediately switch to highest pending interrupt level
- if (m_il != m_il_pending)
+ // handle pending interrupts
+ u8 const il = il_priority[m_ff & FF_IR];
+ if ((m_ff & FF_IE) && m_il != il)
{
- m_il = m_il_pending;
+ m_il = il;
// notify the debugger
- if (m_il && machine().debug_flags & DEBUG_FLAG_ENABLED)
+ if (m_il && (machine().debug_flags & DEBUG_FLAG_ENABLED))
debug()->interrupt_hook(m_il - 1, m_r[m_il][0] & ~1);
}
@@ -133,7 +151,13 @@ void palm_device::execute_run()
case 0xf: Ry += (7 - count_leading_ones_32(u32(m_iod.read_byte(DA)) << 24)) * 2; break; // get to register and add
}
break;
- case 0x1: m_ioc.write_byte(DA, IMM); break; // control
+ case 0x1:
+ // control
+ if (DA == 0)
+ control(IMM);
+
+ m_ioc.write_byte(DA, IMM);
+ break;
case 0x2: Rx = m_rws.read_word(IMM * 2); break; // load halfword direct
case 0x3: m_rws.write_word(IMM * 2, Rx); break; // store halfword direct
case 0x4:
@@ -185,6 +209,8 @@ void palm_device::execute_run()
}
else
{
+ m_getb_bus(DA, Ry);
+
if (MOD < 0xc)
{
// get byte
@@ -201,13 +227,12 @@ void palm_device::execute_run()
// TODO: average instruction time quoted as 1.75µs (~27 machine cycles)
m_icount -= 27;
+ m_pc = r[0];
}
}
void palm_device::execute_set_input(int irqline, int state)
{
- u8 const il_priority[] = { 0, 1, 2, 3, 3, 3, 3, 3 };
-
switch (irqline)
{
case INPUT_LINE_NMI:
@@ -217,12 +242,9 @@ void palm_device::execute_set_input(int irqline, int state)
default:
// interrupt lines are active low
if (!state)
- m_irpt_req |= 1U << irqline;
+ m_ff |= 1U << irqline;
else
- m_irpt_req &= ~(1U << irqline);
-
- // update pending interrupt level
- m_il_pending = il_priority[m_irpt_req & 7];
+ m_ff &= ~(1U << irqline);
break;
}
}
@@ -278,3 +300,31 @@ s16 palm_device::modifier(unsigned const modifier) const
else
return 0;
}
+
+void palm_device::control(u8 data)
+{
+ LOG("control 0x%02x (%s)\n", data, machine().describe_context());
+
+ // 0 reset controller errors
+
+ // 1: 0=disable interrupts
+ // 2: 0=enable interrupts
+ if (!IBIT(data, 1))
+ m_ff &= ~FF_IE;
+ else if (!IBIT(data, 2))
+ m_ff |= FF_IE;
+
+ // TODO: 3 not used?
+ // 4 not used (0:display & select frame on)
+
+ // 5 state transition
+ if (!IBIT(data, 5))
+ {
+ m_ff &= ~FF_IPL;
+ m_ff ^= FF_MSS;
+
+ m_select_ros((m_ff & FF_MSS) && !(m_ff & FF_IPL));
+ }
+
+ // TODO: 6..7 not used (frame bit #1,2?)
+}
diff --git a/src/devices/cpu/palm/palm.h b/src/devices/cpu/palm/palm.h
index ff2bc0c6d08..bd1a1c15974 100644
--- a/src/devices/cpu/palm/palm.h
+++ b/src/devices/cpu/palm/palm.h
@@ -20,6 +20,9 @@ class palm_device : public cpu_device
static unsigned constexpr AS_IOC = AS_IO;
static unsigned constexpr AS_IOD = 4;
+ auto getb_bus() { return m_getb_bus.bind(); }
+ auto select_ros() { return m_select_ros.bind(); }
+
palm_device(machine_config const &mconfig, char const *tag, device_t *owner, u32 clock);
protected:
@@ -43,6 +46,8 @@ class palm_device : public cpu_device
bool condition(unsigned const modifier, u16 const data, u8 const mask) const;
s16 modifier(unsigned const modifier) const;
+ void control(u8 data);
+
private:
// address spaces
address_space_config const m_ros_config;
@@ -55,13 +60,16 @@ class palm_device : public cpu_device
memory_access<4, 0, 0, ENDIANNESS_BIG>::specific m_ioc;
memory_access<4, 0, 0, ENDIANNESS_BIG>::specific m_iod;
+ devcb_write8 m_getb_bus;
+ devcb_write_line m_select_ros;
+
// mame state
int m_icount;
+ u16 m_pc;
u16 m_r[4][16]; // registers
u8 m_il; // interrupt level
- u8 m_il_pending; // pending interrupt level
- u8 m_irpt_req; // interrupt line state
+ u8 m_ff; // controller flip-flops
};
DECLARE_DEVICE_TYPE(PALM, palm_device)
diff --git a/src/devices/cpu/tms9900/tms9900.cpp b/src/devices/cpu/tms9900/tms9900.cpp
index 49e60c1a28b..2f5c2d413d3 100644
--- a/src/devices/cpu/tms9900/tms9900.cpp
+++ b/src/devices/cpu/tms9900/tms9900.cpp
@@ -1346,6 +1346,12 @@ void tms99xx_device::service_interrupt()
m_reset = false;
LOG("** RESET triggered\n");
+
+ // RESET could occur during a data derivation sequence, so we have to
+ // prevent the execution loop to return into that sequence by
+ // clearing the return index. This fixes a bug that leads to undefined
+ // behaviour in that situation.
+ m_caller_index = NOPRG;
}
else
{
diff --git a/src/devices/cpu/upd78k/upd78k2d.cpp b/src/devices/cpu/upd78k/upd78k2d.cpp
index 7fcc4bd85a2..45c7fd64342 100644
--- a/src/devices/cpu/upd78k/upd78k2d.cpp
+++ b/src/devices/cpu/upd78k/upd78k2d.cpp
@@ -14,7 +14,7 @@ offs_t upd78k2_disassembler::dasm_01xx(std::ostream &stream, u8 op2, offs_t pc,
if (op2 == 0x05)
{
u8 op3 = opcodes.r8(pc + 2);
- if ((op3 & 0xed) == 0x89)
+ if ((op3 & 0xed) == 0x8c)
{
util::stream_format(stream, "%-8s&[%s]", BIT(op3, 4) ? "ROL4" : "ROR4", BIT(op3, 1) ? "HL" : "DE");
return 3 | SUPPORTED;
@@ -127,7 +127,7 @@ offs_t upd78k2_disassembler::dasm_05xx(std::ostream &stream, u8 op2, offs_t pc,
util::stream_format(stream, "%-8s%s", BIT(op2, 4) ? "CALL" : "BR", s_rp_names[(op2 & 0x06) >> 1]);
return 2 | (BIT(op2, 4) ? STEP_OVER : 0) | SUPPORTED;
}
- else if ((op2 & 0xed) == 0x89)
+ else if ((op2 & 0xed) == 0x8c)
{
util::stream_format(stream, "%-8s[%s]", BIT(op2, 4) ? "ROL4" : "ROR4", BIT(op2, 1) ? "HL" : "DE");
return 2 | SUPPORTED;
diff --git a/src/devices/machine/icd2061a.cpp b/src/devices/machine/icd2061a.cpp
index 62c90f72055..1dfe44a1e06 100644
--- a/src/devices/machine/icd2061a.cpp
+++ b/src/devices/machine/icd2061a.cpp
@@ -24,11 +24,15 @@
#define LOG_PINS (1 << 1)
#define LOG_STATE (1 << 2)
+#define LOG_TODO (1 << 3)
-// #define VERBOSE (LOG_GENERAL | LOG_PINS | LOG_STATE)
+// #define VERBOSE (LOG_GENERAL | LOG_PINS | LOG_STATE | LOG_TODO)
+#define VERBOSE (LOG_TODO)
#include "logmacro.h"
+#define LOGTODO(...) LOGMASKED(LOG_TODO, __VA_ARGS__)
+
DEFINE_DEVICE_TYPE(ICD2061A, icd2061a_device, "icd2061a", "IC Designs 2061A Dual Programmable Graphics Clock Generator")
@@ -168,6 +172,8 @@ TIMER_CALLBACK_MEMBER( icd2061a_device::update_clock_callback )
const int m = BIT(m_regs[MREG], 7, 3); // post-vco divisor
const int q = BIT(m_regs[MREG], 0, 7) + 2; // q counter value
m_reg_clocks[MREG] = (clock() * m_prescale[a] * (p / double(q))) / (1 << m);
+ } else {
+ LOGTODO("unimplemented mclkout selected %d\n", m_mclkout_select);
}
if (m_reg_clocks[MREG] != m_mclkout_clock) {
@@ -189,18 +195,23 @@ TIMER_CALLBACK_MEMBER( icd2061a_device::update_clock_callback )
else if (m_outdis == 1 && m_pwrdwn == 1 && m_sel1 == 1 && (m_intclk == 1 || m_sel0 == 1))
m_vclkout_select = VCLKOUT_REG2;
+ uint32_t vclkout_clock = m_vclkout_clock;
if (m_vclkout_select == VCLKOUT_FEATCLK) {
- m_reg_clocks[m_vclkout_select] = m_featclock;
+ vclkout_clock = m_featclock;
} else if (m_vclkout_select >= VCLKOUT_REG0 && m_vclkout_select <= VCLKOUT_REG2) {
const int a = BIT(m_regs[m_vclkout_select], 21, 2); // register addr
const int p = BIT(m_regs[m_vclkout_select], 10, 7) + 3; // p counter value
const int m = BIT(m_regs[m_vclkout_select], 7, 3); // post-vco divisor
const int q = BIT(m_regs[m_vclkout_select], 0, 7) + 2; // q counter value
- m_reg_clocks[m_vclkout_select] = (clock() * m_prescale[a] * (p / double(q))) / (1 << m);
+ vclkout_clock = m_reg_clocks[m_vclkout_select] = (clock() * m_prescale[a] * (p / double(q))) / (1 << m);
+ } else {
+ LOGTODO("unimplemented vclkout selected %d\n", m_vclkout_select);
}
- m_vclkout_changed_cb(m_reg_clocks[m_vclkout_select]);
- m_vclkout_clock = m_reg_clocks[m_vclkout_select];
+ if (vclkout_clock != m_vclkout_clock) {
+ m_vclkout_clock = vclkout_clock;
+ m_vclkout_changed_cb(vclkout_clock);
+ }
}
void icd2061a_device::update_clock()
diff --git a/src/devices/machine/spi_sdcard.cpp b/src/devices/machine/spi_sdcard.cpp
index 4db4fc2c8f9..23296a94b33 100644
--- a/src/devices/machine/spi_sdcard.cpp
+++ b/src/devices/machine/spi_sdcard.cpp
@@ -327,17 +327,18 @@ void spi_sdcard_device::do_command()
case 12: // CMD12 - STOP_TRANSMISSION
m_data[0] = 0;
- send_data(1, m_state == SD_STATE_RCV ? SD_STATE_PRG : SD_STATE_TRAN);
+ send_data(1, (m_state == SD_STATE_RCV) ? SD_STATE_PRG : SD_STATE_TRAN);
break;
case 13: // CMD13 - SEND_STATUS
m_data[0] = 0; // TODO
- send_data(1, SD_STATE_STBY);
+ m_data[1] = 0;
+ send_data(2, SD_STATE_STBY);
break;
case 16: // CMD16 - SET_BLOCKLEN
m_blksize = get_u16be(&m_cmd[3]);
- if (m_image->set_block_size(m_blksize))
+ if (m_image->exists() && m_image->set_block_size(m_blksize))
{
m_data[0] = 0;
}
diff --git a/src/devices/machine/z80ctc.cpp b/src/devices/machine/z80ctc.cpp
index 735ea85b8e7..7f0049b28e8 100644
--- a/src/devices/machine/z80ctc.cpp
+++ b/src/devices/machine/z80ctc.cpp
@@ -77,12 +77,17 @@ DEFINE_DEVICE_TYPE(Z80CTC_CHANNEL, z80ctc_channel_device, "z80ctc_channel", "Z80
//-------------------------------------------------
z80ctc_device::z80ctc_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock)
- : device_t(mconfig, Z80CTC, tag, owner, clock)
+ : z80ctc_device(mconfig, Z80CTC, tag, owner, clock)
+{
+}
+
+z80ctc_device::z80ctc_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, u32 clock)
+ : device_t(mconfig, type, tag, owner, clock)
, device_z80daisy_interface(mconfig, *this)
+ , m_channel(*this, "ch%u", 0U)
, m_intr_cb(*this)
, m_zc_cb(*this)
, m_vector(0)
- , m_channel(*this, "ch%u", 0U)
{
}
diff --git a/src/devices/machine/z80ctc.h b/src/devices/machine/z80ctc.h
index 9f0d5aa410f..098915aceab 100644
--- a/src/devices/machine/z80ctc.h
+++ b/src/devices/machine/z80ctc.h
@@ -100,6 +100,8 @@ class z80ctc_device : public device_t,
u16 get_channel_constant(int ch) const { return m_channel[ch]->m_tconst; }
protected:
+ z80ctc_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, u32 clock);
+
// device_t implementation
virtual void device_add_mconfig(machine_config &config) override;
virtual void device_start() override;
@@ -110,20 +112,18 @@ class z80ctc_device : public device_t,
virtual int z80daisy_irq_ack() override;
virtual void z80daisy_irq_reti() override;
-private:
// internal helpers
+ u8 channel_int_state(int ch) const noexcept { return m_channel[ch]->m_int_state; }
void interrupt_check();
z80ctc_channel_device &channel_config(int ch) { return *m_channel[ch].lookup(); }
// internal state
- devcb_write_line m_intr_cb; // interrupt callback
- devcb_write_line::array<4> m_zc_cb; // zero crossing/timer output callbacks
-
- u8 m_vector; // interrupt vector
+ required_device_array m_channel; // subdevice for each channel
+ devcb_write_line m_intr_cb; // interrupt callback
+ devcb_write_line::array<4> m_zc_cb; // zero crossing/timer output callbacks
- // subdevice for each channel
- required_device_array m_channel;
+ u8 m_vector; // interrupt vector
};
diff --git a/src/devices/machine/z80dma.cpp b/src/devices/machine/z80dma.cpp
index 34c40b6183c..2e0240af8a3 100644
--- a/src/devices/machine/z80dma.cpp
+++ b/src/devices/machine/z80dma.cpp
@@ -45,36 +45,13 @@ enum
INT_MATCH_END_OF_BLOCK
};
-constexpr int COMMAND_RESET = 0xc3;
-constexpr int COMMAND_RESET_PORT_A_TIMING = 0xc7;
-constexpr int COMMAND_RESET_PORT_B_TIMING = 0xcb;
-constexpr int COMMAND_LOAD = 0xcf;
-constexpr int COMMAND_CONTINUE = 0xd3;
-constexpr int COMMAND_DISABLE_INTERRUPTS = 0xaf;
-constexpr int COMMAND_ENABLE_INTERRUPTS = 0xab;
-constexpr int COMMAND_RESET_AND_DISABLE_INTERRUPTS = 0xa3;
-constexpr int COMMAND_ENABLE_AFTER_RETI = 0xb7;
-constexpr int COMMAND_READ_STATUS_BYTE = 0xbf;
-constexpr int COMMAND_REINITIALIZE_STATUS_BYTE = 0x8b;
-constexpr int COMMAND_INITIATE_READ_SEQUENCE = 0xa7;
-constexpr int COMMAND_FORCE_READY = 0xb3;
-constexpr int COMMAND_ENABLE_DMA = 0x87;
-constexpr int COMMAND_DISABLE_DMA = 0x83;
-constexpr int COMMAND_READ_MASK_FOLLOWS = 0xbb;
-
-constexpr int TM_TRANSFER = 0x01;
-constexpr int TM_SEARCH = 0x02;
-constexpr int TM_SEARCH_TRANSFER = 0x03;
-
//**************************************************************************
// MACROS
//**************************************************************************
-#define REGNUM(_m, _s) (((_m)<<3) + (_s))
#define GET_REGNUM(_r) (&(_r) - &(WR0))
-#define REG(_m, _s) m_regs[REGNUM(_m,_s)]
#define WR0 REG(0, 0)
#define WR1 REG(1, 0)
#define WR2 REG(2, 0)
@@ -149,7 +126,12 @@ DEFINE_DEVICE_TYPE(Z80DMA, z80dma_device, "z80dma", "Z80 DMA Controller")
//-------------------------------------------------
z80dma_device::z80dma_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
- : device_t(mconfig, Z80DMA, tag, owner, clock)
+ : z80dma_device(mconfig, Z80DMA, tag, owner, clock)
+{
+}
+
+z80dma_device::z80dma_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock)
+ : device_t(mconfig, type, tag, owner, clock)
, device_z80daisy_interface(mconfig, *this)
, m_out_busreq_cb(*this)
, m_out_int_cb(*this)
diff --git a/src/devices/machine/z80dma.h b/src/devices/machine/z80dma.h
index f327b818223..7bbb91760ac 100644
--- a/src/devices/machine/z80dma.h
+++ b/src/devices/machine/z80dma.h
@@ -61,32 +61,67 @@ class z80dma_device : public device_t,
auto out_iorq_callback() { return m_out_iorq_cb.bind(); }
uint8_t read();
- void write(uint8_t data);
+ virtual void write(uint8_t data);
void iei_w(int state) { m_iei = state; interrupt_check(); }
void rdy_w(int state);
void wait_w(int state);
void bai_w(int state);
-private:
- // device-level overrides
+protected:
+ static inline constexpr int COMMAND_RESET = 0xc3;
+ static inline constexpr int COMMAND_RESET_PORT_A_TIMING = 0xc7;
+ static inline constexpr int COMMAND_RESET_PORT_B_TIMING = 0xcb;
+ static inline constexpr int COMMAND_LOAD = 0xcf;
+ static inline constexpr int COMMAND_CONTINUE = 0xd3;
+ static inline constexpr int COMMAND_DISABLE_INTERRUPTS = 0xaf;
+ static inline constexpr int COMMAND_ENABLE_INTERRUPTS = 0xab;
+ static inline constexpr int COMMAND_RESET_AND_DISABLE_INTERRUPTS = 0xa3;
+ static inline constexpr int COMMAND_ENABLE_AFTER_RETI = 0xb7;
+ static inline constexpr int COMMAND_READ_STATUS_BYTE = 0xbf;
+ static inline constexpr int COMMAND_REINITIALIZE_STATUS_BYTE = 0x8b;
+ static inline constexpr int COMMAND_INITIATE_READ_SEQUENCE = 0xa7;
+ static inline constexpr int COMMAND_FORCE_READY = 0xb3;
+ static inline constexpr int COMMAND_ENABLE_DMA = 0x87;
+ static inline constexpr int COMMAND_DISABLE_DMA = 0x83;
+ static inline constexpr int COMMAND_READ_MASK_FOLLOWS = 0xbb;
+
+ static inline constexpr int TM_TRANSFER = 0x01;
+ static inline constexpr int TM_SEARCH = 0x02;
+ static inline constexpr int TM_SEARCH_TRANSFER = 0x03;
+
+ z80dma_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock);
+
+ // device_t implementation
virtual void device_start() override;
virtual void device_reset() override;
- // device_z80daisy_interface overrides
- virtual int z80daisy_irq_state() override;
- virtual int z80daisy_irq_ack() override;
- virtual void z80daisy_irq_reti() override;
-
// internal helpers
- int is_ready();
+ bool is_dma_enabled() const noexcept { return m_dma_enabled; }
+ u8 num_follow() const noexcept { return m_num_follow; }
+ virtual int is_ready();
void interrupt_check();
void trigger_interrupt(int level);
void do_read();
- void do_write();
+ virtual void do_write();
void do_transfer_write();
void do_search();
+ uint16_t ®(unsigned m, unsigned s) noexcept { return m_regs[REGNUM(m, s)]; }
+
+ static constexpr unsigned REGNUM(unsigned m, unsigned s) { return (m << 3) + s; }
+
+ uint16_t m_addressA;
+ uint16_t m_addressB;
+ uint16_t m_count;
+ uint16_t m_byte_counter;
+
+private:
+ // device_z80daisy_interface implementation
+ virtual int z80daisy_irq_state() override;
+ virtual int z80daisy_irq_ack() override;
+ virtual void z80daisy_irq_reti() override;
+
TIMER_CALLBACK_MEMBER(timerproc);
void update_status();
@@ -105,7 +140,7 @@ class z80dma_device : public device_t,
emu_timer *m_timer;
- uint16_t m_regs[(6<<3)+1+1];
+ uint16_t m_regs[(6 << 3) + 1 + 1];
uint8_t m_num_follow;
uint8_t m_cur_follow;
uint8_t m_regs_follow[5];
@@ -115,11 +150,6 @@ class z80dma_device : public device_t,
uint8_t m_status;
uint8_t m_dma_enabled;
- uint16_t m_addressA;
- uint16_t m_addressB;
- uint16_t m_count;
- uint16_t m_byte_counter;
-
int m_rdy;
int m_force_ready;
uint8_t m_reset_pointer;
@@ -133,7 +163,7 @@ class z80dma_device : public device_t,
int m_iei; // interrupt enable input
int m_ip; // interrupt pending
int m_ius; // interrupt under service
- uint8_t m_vector; // interrupt vector
+ uint8_t m_vector; // interrupt vector
};
diff --git a/src/devices/video/crt9007.cpp b/src/devices/video/crt9007.cpp
index eac1717e41a..6bbafceebae 100644
--- a/src/devices/video/crt9007.cpp
+++ b/src/devices/video/crt9007.cpp
@@ -950,3 +950,13 @@ void crt9007_device::set_character_width(unsigned value)
if (started())
recompute_parameters();
}
+
+
+//-------------------------------------------------
+// cursor_active - is cursor active at location
+//-------------------------------------------------
+
+bool crt9007_device::cursor_active(unsigned x, unsigned y)
+{
+ return (x == HORIZONTAL_CURSOR && y == VERTICAL_CURSOR);
+}
diff --git a/src/devices/video/crt9007.h b/src/devices/video/crt9007.h
index 9ea8b3b9a48..369cb0b9fb6 100644
--- a/src/devices/video/crt9007.h
+++ b/src/devices/video/crt9007.h
@@ -71,6 +71,9 @@ class crt9007_device : public device_t,
void ack_w(int state);
void lpstb_w(int state);
+ // cursor location
+ bool cursor_active(unsigned x, unsigned y);
+
protected:
// device_t implementation
virtual void device_start() override;
diff --git a/src/devices/video/crtc_ega.cpp b/src/devices/video/crtc_ega.cpp
index 15131095fd3..3b9f8ac5d20 100644
--- a/src/devices/video/crtc_ega.cpp
+++ b/src/devices/video/crtc_ega.cpp
@@ -105,7 +105,7 @@ void crtc_ega_device::register_w(uint8_t data)
m_vert_blank_start = ((data & 0x08) << 5) | (m_vert_blank_start & 0x00ff);
m_line_compare = ((data & 0x10) << 4) | (m_line_compare & 0x00ff);
break;
- case 0x08: m_preset_row_scan = data & 0x1f;
+ case 0x08: m_preset_row_latch = data & 0x1f;
break;
case 0x09: m_max_ras_addr = data & 0x1f;
break;
@@ -272,7 +272,10 @@ void crtc_ega_device::set_vblank(int state)
if (!m_irq_enable)
m_res_out_irq_cb(m_vblank);
if (state)
+ {
m_disp_start_addr = m_start_addr_latch;
+ m_preset_row_scan = m_preset_row_latch;
+ }
}
}
diff --git a/src/devices/video/crtc_ega.h b/src/devices/video/crtc_ega.h
index 62bcac8c5c3..6418f248ef3 100644
--- a/src/devices/video/crtc_ega.h
+++ b/src/devices/video/crtc_ega.h
@@ -130,6 +130,7 @@ class crtc_ega_device : public device_t,
/* other internal state */
uint8_t m_register_address_latch;
uint16_t m_start_addr_latch;
+ uint8_t m_preset_row_latch;
bool m_cursor_state; /* 0 = off, 1 = on */
uint8_t m_cursor_blink_count;
int m_hpixels_per_column; /* number of pixels per video memory address */
diff --git a/src/emu/xtal.cpp b/src/emu/xtal.cpp
index 188ed1d46d6..2569c4a617d 100644
--- a/src/emu/xtal.cpp
+++ b/src/emu/xtal.cpp
@@ -241,6 +241,7 @@ const double XTAL::known_xtals[] = {
14'314'000, /* 14.314_MHz_XTAL Taito TTL Board */
14'318'181, /* 14.318181_MHz_XTAL Extremely common, used on 100's of PCBs (4x NTSC subcarrier) */
14'349'600, /* 14.3496_MHz_XTAL Roland S-50 VDP */
+ 14'469'000, /* 14.469_MHz_XTAL Esprit Systems Executive 10/102 */
14'580'000, /* 14.58_MHz_XTAL Fortune 32:16 Video Controller */
14'705'882, /* 14.705882_MHz_XTAL Aleck64 */
14'728'000, /* 14.728_MHz_XTAL ADM 36 */
@@ -286,6 +287,7 @@ const double XTAL::known_xtals[] = {
16'670'000, /* 16.67_MHz_XTAL - */
16'777'216, /* 16.777216_MHz_XTAL Nintendo Game Boy Advance */
16'934'400, /* 16.9344_MHz_XTAL Usually used to drive 90's Yamaha OPL/FM chips (44100 * 384) */
+ 16'960'000, /* 16.960_MHz_XTAL Esprit Systems Executive 10/102 */
17'010'000, /* 17.01_MHz_XTAL Epic 14E */
17'064'000, /* 17.064_MHz_XTAL Memorex 1377 */
17'074'800, /* 17.0748_MHz_XTAL SWTPC 8212 */
diff --git a/src/mame/atari/harddriv.cpp b/src/mame/atari/harddriv.cpp
index 45a39824363..e0b25440ad7 100644
--- a/src/mame/atari/harddriv.cpp
+++ b/src/mame/atari/harddriv.cpp
@@ -322,6 +322,13 @@ A046901
68010 clock input - 8.000MHz [32/4]
34010 clock input - 48.000MHz
+ strtdriv brake calibration doesn't work properly. You need to have
+ the brake fully depressed when it says to "TAKE YOUR HANDS AND FEET
+ OFF ALL CONTROLS" and "TAKE YOUR FOOT OFF THE BRAKE". When it says
+ "NOW STEP ON THE BRAKE FIRMLY AND RELEASE" you need to release the
+ brake and then press it again. If you abort the calibration, the
+ defaults will work anyway.
+
****************************************************************************/
#include "emu.h"
@@ -1313,7 +1320,7 @@ static INPUT_PORTS_START( strtdriv )
PORT_BIT( 0xff, IP_ACTIVE_LOW, IPT_UNUSED )
PORT_START("mainpcb:8BADC.2") /* b00000 - 8 bit ADC 2 - brake */
- PORT_BIT( 0xff, 0x00, IPT_PEDAL2 ) PORT_SENSITIVITY(25) PORT_KEYDELTA(40) PORT_NAME("Brake")
+ PORT_BIT( 0xff, 0x20, IPT_PEDAL2 ) PORT_MINMAX(0x20, 0xf0) PORT_SENSITIVITY(25) PORT_KEYDELTA(40) PORT_NAME("Brake")
PORT_START("mainpcb:8BADC.3") /* b00000 - 8 bit ADC 3 - volume */
PORT_BIT( 0xff, 0x80, IPT_UNUSED )
@@ -1331,7 +1338,7 @@ static INPUT_PORTS_START( strtdriv )
PORT_BIT( 0xff, 0x80, IPT_UNUSED )
PORT_START("mainpcb:12BADC.0") /* 400000 - steering wheel */
- PORT_BIT(0xfff, 0x800, IPT_PADDLE) PORT_MINMAX(0x010, 0xff0) PORT_SENSITIVITY(400) PORT_KEYDELTA(5) PORT_NAME("Steering Wheel")
+ PORT_BIT(0xfff, 0x200, IPT_PADDLE) PORT_MINMAX(0x000, 0x3ff) PORT_SENSITIVITY(100) PORT_KEYDELTA(5) PORT_NAME("Steering Wheel")
/* dummy ADC ports to end up with the same number as the full version */
PORT_START("mainpcb:12BADC.1") /* FAKE */
@@ -1421,7 +1428,7 @@ static INPUT_PORTS_START( hdrivair )
PORT_BIT( 0xff, 0x80, IPT_UNUSED )
PORT_START("mainpcb:12BADC.0") /* 400000 - steering wheel */
- PORT_BIT(0xfff, 0x800, IPT_PADDLE) PORT_MINMAX(0x010, 0xff0) PORT_SENSITIVITY(400) PORT_KEYDELTA(5) PORT_REVERSE PORT_NAME("Steering Wheel")
+ PORT_BIT(0xfff, 0x200, IPT_PADDLE) PORT_MINMAX(0x000, 0x3ff) PORT_SENSITIVITY(100) PORT_KEYDELTA(5) PORT_REVERSE PORT_NAME("Steering Wheel")
/* dummy ADC ports to end up with the same number as the full version */
PORT_START("mainpcb:12BADC.1")
diff --git a/src/mame/esprit/executive10.cpp b/src/mame/esprit/executive10.cpp
new file mode 100644
index 00000000000..28c25b5d4c2
--- /dev/null
+++ b/src/mame/esprit/executive10.cpp
@@ -0,0 +1,352 @@
+// license: BSD-3-Clause
+// copyright-holders: Dirk Best
+/***************************************************************************
+
+ Esprit Systems Executive 10/102
+
+ VT102 compatible terminal
+
+ Hardware:
+ - Intel P8088
+ - Intel D8284A
+ - Intel P8259A-8
+ - 2x 2764 EPROM, 1x 2732 EPROM
+ - SY2128-2 (2k RAM)
+ - X2212D NOVRAM
+ - MC68B50P
+ - SCN2681A
+ - 14.469 MHz XTAL (near CPU), 3.6864 MHz XTAL (near 2681)
+ - CRT 9007
+ - 2x CRT 9006-135
+ - CRT9021A
+ - 2764 EPROM
+ - 4x SY2128-2 (8k RAM)
+ - 21.800 MHz XTAL (near 9007), 16.960 MHz XTAL (near 9007)
+ - 9 position DIP switch
+
+ TODO:
+ - Improve rendering (132 columns, smooth scrolling, non-line attributes(?))
+ - NOVRAM store/recall
+ - Printer
+ - DIP switch
+
+ Notes:
+ - Other models in this line: 10/51 (IBM 5251), 10/78 (IBM 3278)
+ - To go online: Enter Set-Up, press 5 for next screen, press 4 to switch
+ from local to online (no feedback, would be shown on keyboard LEDs)
+
+***************************************************************************/
+
+#include "emu.h"
+
+#include "executive10_102_kbd.h"
+
+#include "bus/rs232/rs232.h"
+#include "cpu/i86/i86.h"
+#include "machine/6850acia.h"
+#include "machine/mc68681.h"
+#include "machine/pic8259.h"
+#include "machine/x2212.h"
+#include "video/crt9007.h"
+
+#include "emupal.h"
+#include "multibyte.h"
+#include "screen.h"
+
+
+namespace {
+
+
+//**************************************************************************
+// TYPE DEFINITIONS
+//**************************************************************************
+
+class executive10_state : public driver_device
+{
+public:
+ executive10_state(const machine_config &mconfig, device_type type, const char *tag) :
+ driver_device(mconfig, type, tag),
+ m_maincpu(*this, "maincpu"),
+ m_novram(*this, "novram"),
+ m_pic(*this, "pic"),
+ m_screen(*this, "screen"),
+ m_palette(*this, "palette"),
+ m_vpac(*this, "vpac"),
+ m_duart(*this, "duart"),
+ m_acia(*this, "acia"),
+ m_cram(*this, "cram"),
+ m_aram(*this, "aram"),
+ m_chargen(*this, "chargen")
+ { }
+
+ void executive10(machine_config &config);
+
+protected:
+ virtual void machine_start() override;
+ virtual void machine_reset() override;
+
+private:
+ required_device m_maincpu;
+ required_device m_novram;
+ required_device m_pic;
+ required_device m_screen;
+ required_device m_palette;
+ required_device m_vpac;
+ required_device m_duart;
+ required_device m_acia;
+ required_shared_ptr m_cram;
+ required_shared_ptr m_aram;
+ required_region_ptr m_chargen;
+
+ void mem_map(address_map &map);
+ void io_map(address_map &map);
+
+ uint32_t screen_update(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect);
+};
+
+
+//**************************************************************************
+// ADDRESS MAPS
+//**************************************************************************
+
+void executive10_state::mem_map(address_map &map)
+{
+ map.global_mask(0xffff);
+ map(0x0000, 0x07ff).ram();
+ map(0x2000, 0x2fff).ram().share("cram");
+ map(0x4000, 0x4fff).ram().share("aram");
+ map(0x6000, 0x60ff).rw(m_novram, FUNC(x2210_device::read), FUNC(x2210_device::write));
+ map(0xb000, 0xffff).rom().region("maincpu", 0);
+}
+
+void executive10_state::io_map(address_map &map)
+{
+ map(0x000, 0x03f).rw(m_vpac, FUNC(crt9007_device::read), FUNC(crt9007_device::write));
+ map(0x040, 0x04f).rw(m_duart, FUNC(scn2681_device::read), FUNC(scn2681_device::write));
+ map(0x080, 0x080).w(m_acia, FUNC(acia6850_device::control_w));
+ map(0x081, 0x081).r(m_acia, FUNC(acia6850_device::status_r));
+ map(0x082, 0x082).w(m_acia, FUNC(acia6850_device::data_w));
+ map(0x083, 0x083).r(m_acia, FUNC(acia6850_device::data_r));
+ map(0x0c0, 0x0c1).rw(m_pic, FUNC(pic8259_device::read), FUNC(pic8259_device::write));
+ //map(0x180, 0x180).nopw(); // novram store/recall?
+}
+
+
+//**************************************************************************
+// INPUT PORT DEFINITIONS
+//**************************************************************************
+
+static INPUT_PORTS_START( executive10 )
+INPUT_PORTS_END
+
+
+//**************************************************************************
+// VIDEO EMULATION
+//**************************************************************************
+
+uint32_t executive10_state::screen_update(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect)
+{
+ const pen_t *const pen = m_palette->pens();
+
+ for (int y = 0; y < 25; y++)
+ {
+ // f--------------- double height line
+ // -e-------------- double width line
+ // --dc------------ unknown
+ // ----ba9876543210 line address
+
+ uint16_t addr = get_u16le(&m_cram[0xfcc + (y * 2)]);
+ bool dw = addr & 0xc000;
+
+ uint8_t line_attr = 0x00;
+
+ for (int x = 0; x < (dw ? 40 : 80); x++)
+ {
+ uint16_t code = m_cram[(addr & 0x0fff) + x];
+
+ // move bit 7 to 8 (acs characters)
+ code = bitswap<9>(code, 7, 8, 6, 5, 4, 3, 2, 1, 0);
+
+ // select 80/132 column character set
+ code |= 0x80; // fixed 80 columns mode for now
+
+ // 7------- active for line attributes
+ // -6------ unknown
+ // --5----- blink
+ // ---4---- reverse
+ // ----3--- 0 = blank?
+ // -----2-- underline
+ // ------1- unknown
+ // -------0 highlight
+
+ uint8_t attr = m_aram[(addr & 0x0fff) + x];
+
+ // new line attribute?
+ if (BIT(attr, 7))
+ line_attr = attr;
+
+ for (int i = 0; i < 12; i++)
+ {
+ unsigned char_line = i;
+
+ // adjust rendered line for double height mode
+ if (BIT(addr, 15))
+ char_line = (i / 2) + (BIT(addr, 14) * (12 / 2));
+
+ uint16_t data = m_chargen[(code << 4) + char_line] << 1;
+
+ // maybe? fixes line drawing characters
+ if (BIT(data, 8) == 1)
+ {
+ if (BIT(data, 1) == 1)
+ data |= 0x001;
+
+ if (BIT(data, 7) == 0)
+ data &= ~0x100;
+ }
+
+ // underline?
+ if (BIT(line_attr, 2) && i == 10)
+ data = 0x1ff;
+
+ // reverse?
+ if (BIT(line_attr, 4))
+ data = ~data;
+
+ // blink?
+ if (BIT(line_attr, 5) && (m_screen->frame_number() & 0x20)) // wrong timing
+ data = 0x000;
+
+ // cursor?
+ if (m_vpac->cursor_active(x, y))
+ data = ~data; // might be solid instead
+
+ // foreground/background colors
+ rgb_t fg = BIT(line_attr, 0) ? pen[2] : pen[1];
+ rgb_t bg = pen[0];
+
+ // draw character line
+ if (dw)
+ {
+ for (int p = 0; p < 9; p++)
+ {
+ bitmap.pix(y * 12 + i, x * 18 + p * 2 + 0) = BIT(data, 8 - p) ? fg : bg;
+ bitmap.pix(y * 12 + i, x * 18 + p * 2 + 1) = BIT(data, 8 - p) ? fg : bg;
+ }
+ }
+ else
+ {
+ for (int p = 0; p < 9; p++)
+ bitmap.pix(y * 12 + i, x * 9 + p) = BIT(data, 8 - p) ? fg : bg;
+ }
+ }
+ }
+ }
+
+ return 0;
+}
+
+static const gfx_layout char_layout =
+{
+ 8, 12,
+ RGN_FRAC(1,1),
+ 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 },
+ 8 * 16
+};
+
+static GFXDECODE_START( chars )
+ GFXDECODE_ENTRY("chargen", 0, char_layout, 0, 1)
+GFXDECODE_END
+
+
+//**************************************************************************
+// MACHINE EMULATION
+//**************************************************************************
+
+void executive10_state::machine_start()
+{
+}
+
+void executive10_state::machine_reset()
+{
+}
+
+
+//**************************************************************************
+// MACHINE DEFINTIONS
+//**************************************************************************
+
+void executive10_state::executive10(machine_config &config)
+{
+ I8088(config, m_maincpu, 14.469_MHz_XTAL / 3);
+ m_maincpu->set_addrmap(AS_PROGRAM, &executive10_state::mem_map);
+ m_maincpu->set_addrmap(AS_IO, &executive10_state::io_map);
+ m_maincpu->set_irq_acknowledge_callback(m_pic, FUNC(pic8259_device::inta_cb));
+
+ X2212(config, m_novram);
+
+ PIC8259(config, m_pic);
+ m_pic->out_int_callback().set_inputline(m_maincpu, INPUT_LINE_IRQ0);
+
+ SCREEN(config, m_screen, SCREEN_TYPE_RASTER);
+ m_screen->set_color(rgb_t::green());
+ m_screen->set_raw(16.960_MHz_XTAL, 890, 0, 720, 320, 0, 300); // maybe
+ m_screen->set_screen_update(FUNC(executive10_state::screen_update));
+
+ PALETTE(config, m_palette, palette_device::MONOCHROME_HIGHLIGHT);
+
+ GFXDECODE(config, "gfxdecode", m_palette, chars);
+
+ CRT9007(config, m_vpac, 16.960_MHz_XTAL / 9);
+ m_vpac->set_screen("screen");
+ m_vpac->set_character_width(9);
+ m_vpac->int_callback().set(m_pic, FUNC(pic8259_device::ir2_w));
+
+ SCN2681(config, m_duart, 3.6864_MHz_XTAL);
+ m_duart->a_tx_cb().set("serial", FUNC(rs232_port_device::write_txd));
+ m_duart->outport_cb().set(m_acia, FUNC(acia6850_device::write_rxc)).bit(3);
+ m_duart->outport_cb().append(m_acia, FUNC(acia6850_device::write_txc)).bit(3);
+ m_duart->outport_cb().append(m_pic, FUNC(pic8259_device::ir0_w)).bit(4).invert();
+ m_duart->outport_cb().append(m_pic, FUNC(pic8259_device::ir1_w)).bit(5).invert();
+
+ rs232_port_device &serial(RS232_PORT(config, "serial", default_rs232_devices, nullptr));
+ serial.rxd_handler().set(m_duart, FUNC(scn2681_device::rx_a_w));
+ serial.cts_handler().set(m_duart, FUNC(scn2681_device::ip0_w));
+
+ ACIA6850(config, m_acia);
+ m_acia->irq_handler().set(m_pic, FUNC(pic8259_device::ir4_w));
+ m_acia->txd_handler().set("kbd", FUNC(executive10_102_kbd_device::rxd_w));
+
+ executive10_102_kbd_device &kbd(EXECUTIVE10_102_KBD(config, "kbd"));
+ kbd.txd_cb().set(m_acia, FUNC(acia6850_device::write_rxd));
+ kbd.cts_cb().set(m_acia, FUNC(acia6850_device::write_cts));
+}
+
+
+//**************************************************************************
+// ROM DEFINITIONS
+//**************************************************************************
+
+ROM_START( exe10102 )
+ ROM_REGION(0x5000, "maincpu", 0)
+ ROM_LOAD("113-03-0.u25", 0x0000, 0x1000, CRC(bf5498d4) SHA1(46a3e832a1ba9a08c1d4938d6c94b2194ef00081))
+ ROM_LOAD("113-01-0.u26", 0x1000, 0x2000, CRC(5e6babb3) SHA1(4669107e9cfaba1a697db6e832bc36c8220ee591))
+ ROM_LOAD("113-02-0.u27", 0x3000, 0x2000, CRC(05bcd49b) SHA1(fbeac116ded46215644df7db1810f4f9d41e49ca))
+
+ ROM_REGION(0x2000, "chargen", 0)
+ ROM_LOAD("111-01-0.u59", 0x0000, 0x2000, CRC(4e54c69f) SHA1(92640a57863c5eab9db6d07c31deebfa3d1dafa5))
+ROM_END
+
+
+} // anonymous namespace
+
+
+//**************************************************************************
+// SYSTEM DRIVERS
+//**************************************************************************
+
+// YEAR NAME PARENT COMPAT MACHINE INPUT CLASS INIT COMPANY FULLNAME FLAGS
+COMP( 1983, exe10102, 0, 0, executive10, executive10, executive10_state, empty_init, "Esprit Systems", "Executive 10/102", MACHINE_NOT_WORKING | MACHINE_SUPPORTS_SAVE )
diff --git a/src/mame/esprit/executive10_102_kbd.cpp b/src/mame/esprit/executive10_102_kbd.cpp
new file mode 100644
index 00000000000..04d0f7a5262
--- /dev/null
+++ b/src/mame/esprit/executive10_102_kbd.cpp
@@ -0,0 +1,278 @@
+// license: BSD-3-Clause
+// copyright-holders: Dirk Best
+/***************************************************************************
+
+ Esprit Systems Executive 10/102 Keyboard
+
+ Hardware:
+ - Intel D8749
+ - 6.144 MHz XTAL
+ - NE556
+ - Buzzer
+ - 8 LEDs
+
+ TODO:
+ - Verify Break/No Scroll key
+ - LEDs
+
+ Notes:
+ - A/N 9102 754 2200
+ - P/N 3001 900 8108
+
+***************************************************************************/
+
+#include "emu.h"
+#include "executive10_102_kbd.h"
+
+#include "speaker.h"
+
+
+//**************************************************************************
+// TYPE DEFINITIONS
+//**************************************************************************
+
+DEFINE_DEVICE_TYPE(EXECUTIVE10_102_KBD, executive10_102_kbd_device, "executive10_102_kbd", "Executive 10/102 Keyboard")
+
+executive10_102_kbd_device::executive10_102_kbd_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) :
+ device_t(mconfig, EXECUTIVE10_102_KBD, tag, owner, 0U),
+ m_mcu(*this, "mcu"),
+ m_buzzer(*this, "buzzer"),
+ m_shift(*this, "shift"),
+ m_ctrl(*this, "ctrl"),
+ m_keys(*this, "row_%x", 0U),
+ m_txd_cb(*this),
+ m_cts_cb(*this)
+{
+}
+
+
+//**************************************************************************
+// ROM DEFINITIONS
+//**************************************************************************
+
+ROM_START( firmware )
+ ROM_REGION(0x800, "mcu", 0)
+ ROM_LOAD("118-01-1.u1", 0x000, 0x800, CRC(311ed6a6) SHA1(2701ab4eaaf89270575ecff841f813db1907a434))
+ROM_END
+
+const tiny_rom_entry *executive10_102_kbd_device::device_rom_region() const
+{
+ return ROM_NAME( firmware );
+}
+
+
+//**************************************************************************
+// MACHINE DEFINITIONS
+//**************************************************************************
+
+void executive10_102_kbd_device::device_add_mconfig(machine_config &config)
+{
+ I8749(config, m_mcu, 6.144_MHz_XTAL);
+ m_mcu->t0_in_cb().set(FUNC(executive10_102_kbd_device::t0_r));
+ m_mcu->t1_in_cb().set(FUNC(executive10_102_kbd_device::t1_r));
+ m_mcu->bus_in_cb().set(FUNC(executive10_102_kbd_device::bus_r));
+ m_mcu->p1_out_cb().set(FUNC(executive10_102_kbd_device::p1_w));
+ m_mcu->p2_out_cb().set(FUNC(executive10_102_kbd_device::p2_w));
+
+ SPEAKER(config, "mono").front_center();
+
+ BEEP(config, m_buzzer, 786); // unknown frequency
+ m_buzzer->add_route(ALL_OUTPUTS, "mono", 0.5);
+}
+
+
+//**************************************************************************
+// INPUT PORT DEFINITIONS
+//**************************************************************************
+
+static INPUT_PORTS_START( keyboard )
+ PORT_START("shift")
+ PORT_BIT(0x01, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_LSHIFT) PORT_CODE(KEYCODE_RSHIFT) PORT_CHAR(UCHAR_SHIFT_1) PORT_NAME("Shift")
+
+ PORT_START("ctrl")
+ PORT_BIT(0x01, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_LCONTROL) PORT_CODE(KEYCODE_RCONTROL) PORT_CHAR(UCHAR_MAMEKEY(LCONTROL)) PORT_NAME("Ctrl")
+
+ PORT_START("row_0")
+ PORT_BIT(0x01, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_X) PORT_CHAR('x') PORT_CHAR('X')
+ PORT_BIT(0x02, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_Z) PORT_CHAR('z') PORT_CHAR('Z')
+ PORT_BIT(0x04, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_A) PORT_CHAR('a') PORT_CHAR('A')
+ PORT_BIT(0x08, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_Q) PORT_CHAR('q') PORT_CHAR('Q')
+ PORT_BIT(0x10, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_ESC) PORT_CHAR(UCHAR_MAMEKEY(ESC))
+ PORT_BIT(0x20, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_1) PORT_CHAR('1') PORT_CHAR('!')
+ PORT_BIT(0x40, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_TAB) PORT_CHAR(9)
+ PORT_BIT(0x80, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_F5) PORT_NAME("Set Up")
+
+ PORT_START("row_1")
+ PORT_BIT(0x01, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_V) PORT_CHAR('v') PORT_CHAR('V')
+ PORT_BIT(0x02, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_C) PORT_CHAR('c') PORT_CHAR('C')
+ PORT_BIT(0x04, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_D) PORT_CHAR('d') PORT_CHAR('D')
+ PORT_BIT(0x08, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_S) PORT_CHAR('s') PORT_CHAR('S')
+ PORT_BIT(0x10, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_E) PORT_CHAR('e') PORT_CHAR('E')
+ PORT_BIT(0x20, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_W) PORT_CHAR('w') PORT_CHAR('W')
+ PORT_BIT(0x40, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_3) PORT_CHAR('3') PORT_CHAR('#')
+ PORT_BIT(0x80, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_2) PORT_CHAR('2') PORT_CHAR('@')
+
+ PORT_START("row_2")
+ PORT_BIT(0x01, IP_ACTIVE_LOW, IPT_UNUSED)
+ PORT_BIT(0x02, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_B) PORT_CHAR('b') PORT_CHAR('B')
+ PORT_BIT(0x04, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_G) PORT_CHAR('g') PORT_CHAR('G')
+ PORT_BIT(0x08, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_F) PORT_CHAR('f') PORT_CHAR('F')
+ PORT_BIT(0x10, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_R) PORT_CHAR('r') PORT_CHAR('R')
+ PORT_BIT(0x20, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_T) PORT_CHAR('t') PORT_CHAR('T')
+ PORT_BIT(0x40, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_5) PORT_CHAR('5') PORT_CHAR('%')
+ PORT_BIT(0x80, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_4) PORT_CHAR('4') PORT_CHAR('$')
+
+ PORT_START("row_3")
+ PORT_BIT(0x01, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_SLASH) PORT_CHAR('/') PORT_CHAR('?')
+ PORT_BIT(0x02, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_STOP) PORT_CHAR('.') PORT_CHAR('>')
+ PORT_BIT(0x04, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_COMMA) PORT_CHAR(',') PORT_CHAR('<')
+ PORT_BIT(0x08, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_M) PORT_CHAR('m') PORT_CHAR('M')
+ PORT_BIT(0x10, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_N) PORT_CHAR('n') PORT_CHAR('N')
+ PORT_BIT(0x20, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_H) PORT_CHAR('h') PORT_CHAR('H')
+ PORT_BIT(0x40, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_Y) PORT_CHAR('y') PORT_CHAR('Y')
+ PORT_BIT(0x80, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_6) PORT_CHAR('6') PORT_CHAR('^')
+
+ PORT_START("row_4")
+ PORT_BIT(0x01, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_QUOTE) PORT_CHAR('\'') PORT_CHAR('"')
+ PORT_BIT(0x02, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_COLON) PORT_CHAR(';') PORT_CHAR(':')
+ PORT_BIT(0x04, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_L) PORT_CHAR('l') PORT_CHAR('L')
+ PORT_BIT(0x08, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_K) PORT_CHAR('k') PORT_CHAR('K')
+ PORT_BIT(0x10, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_J) PORT_CHAR('j') PORT_CHAR('J')
+ PORT_BIT(0x20, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_U) PORT_CHAR('u') PORT_CHAR('U')
+ PORT_BIT(0x40, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_8) PORT_CHAR('8') PORT_CHAR('*')
+ PORT_BIT(0x80, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_7) PORT_CHAR('7') PORT_CHAR('&')
+
+ PORT_START("row_5")
+ PORT_BIT(0x01, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_ENTER) PORT_CHAR(13)
+ PORT_BIT(0x02, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_CLOSEBRACE) PORT_CHAR(']') PORT_CHAR('}')
+ PORT_BIT(0x04, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_OPENBRACE) PORT_CHAR('[') PORT_CHAR('{')
+ PORT_BIT(0x08, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_P) PORT_CHAR('p') PORT_CHAR('P')
+ PORT_BIT(0x10, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_I) PORT_CHAR('i') PORT_CHAR('I')
+ PORT_BIT(0x20, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_O) PORT_CHAR('o') PORT_CHAR('O')
+ PORT_BIT(0x40, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_0) PORT_CHAR('0') PORT_CHAR(')')
+ PORT_BIT(0x80, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_9) PORT_CHAR('9') PORT_CHAR('(')
+
+ PORT_START("row_6")
+ PORT_BIT(0x01, IP_ACTIVE_LOW, IPT_UNUSED)
+ PORT_BIT(0x02, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_TILDE) PORT_CHAR('`') PORT_CHAR('~')
+ PORT_BIT(0x04, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_EQUALS) PORT_CHAR('=') PORT_CHAR('+')
+ PORT_BIT(0x08, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_MINUS) PORT_CHAR('-') PORT_CHAR('_')
+ PORT_BIT(0x10, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_RIGHT) PORT_CHAR(UCHAR_MAMEKEY(RIGHT)) PORT_NAME(u8"\u2192") // →
+ PORT_BIT(0x20, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_LEFT) PORT_CHAR(UCHAR_MAMEKEY(LEFT)) PORT_NAME(u8"\u2190") // ←
+ PORT_BIT(0x40, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_DOWN) PORT_CHAR(UCHAR_MAMEKEY(DOWN)) PORT_NAME(u8"\u2193") // ↓
+ PORT_BIT(0x80, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_UP) PORT_CHAR(UCHAR_MAMEKEY(UP)) PORT_NAME(u8"\u2191") // ↑
+
+ PORT_START("row_7")
+ PORT_BIT(0x01, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CHAR(10) PORT_NAME("Line Feed")
+ PORT_BIT(0x02, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_BACKSLASH) PORT_CHAR('\\') PORT_CHAR('|')
+ PORT_BIT(0x04, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_DEL) PORT_CHAR(UCHAR_MAMEKEY(DEL))
+ PORT_BIT(0x08, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_CANCEL) PORT_CHAR(UCHAR_MAMEKEY(CANCEL)) PORT_NAME("Break")
+ PORT_BIT(0x10, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_BACKSPACE) PORT_CHAR(8)
+ PORT_BIT(0x20, IP_ACTIVE_LOW, IPT_UNUSED)
+ PORT_BIT(0x40, IP_ACTIVE_LOW, IPT_UNUSED)
+ PORT_BIT(0x80, IP_ACTIVE_LOW, IPT_UNUSED)
+
+ PORT_START("row_8")
+ PORT_BIT(0x01, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_ENTER_PAD) PORT_CHAR(UCHAR_MAMEKEY(ENTER_PAD))
+ PORT_BIT(0x02, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("Keypad .")
+ PORT_BIT(0x04, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_0_PAD) PORT_CHAR(UCHAR_MAMEKEY(0_PAD))
+ PORT_BIT(0x08, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_2_PAD) PORT_CHAR(UCHAR_MAMEKEY(2_PAD))
+ PORT_BIT(0x10, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_1_PAD) PORT_CHAR(UCHAR_MAMEKEY(1_PAD))
+ PORT_BIT(0x20, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_4_PAD) PORT_CHAR(UCHAR_MAMEKEY(4_PAD))
+ PORT_BIT(0x40, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_7_PAD) PORT_CHAR(UCHAR_MAMEKEY(7_PAD))
+ PORT_BIT(0x80, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_F1) PORT_CHAR(UCHAR_MAMEKEY(F1)) PORT_NAME("PF1")
+
+ PORT_START("row_9")
+ PORT_BIT(0x01, IP_ACTIVE_LOW, IPT_UNUSED)
+ PORT_BIT(0x02, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_3_PAD) PORT_CHAR(UCHAR_MAMEKEY(3_PAD))
+ PORT_BIT(0x04, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_6_PAD) PORT_CHAR(UCHAR_MAMEKEY(6_PAD))
+ PORT_BIT(0x08, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_5_PAD) PORT_CHAR(UCHAR_MAMEKEY(5_PAD))
+ PORT_BIT(0x10, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_9_PAD) PORT_CHAR(UCHAR_MAMEKEY(9_PAD))
+ PORT_BIT(0x20, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_8_PAD) PORT_CHAR(UCHAR_MAMEKEY(8_PAD))
+ PORT_BIT(0x40, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_F3) PORT_CHAR(UCHAR_MAMEKEY(F3)) PORT_NAME("PF3")
+ PORT_BIT(0x80, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_F2) PORT_CHAR(UCHAR_MAMEKEY(F2)) PORT_NAME("PF2")
+
+ PORT_START("row_a")
+ PORT_BIT(0x01, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_SPACE) PORT_CHAR(' ')
+ PORT_BIT(0x02, IP_ACTIVE_LOW, IPT_UNUSED)
+ PORT_BIT(0x04, IP_ACTIVE_LOW, IPT_UNUSED)
+ PORT_BIT(0x08, IP_ACTIVE_LOW, IPT_UNUSED)
+ PORT_BIT(0x10, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("No Scroll")
+ PORT_BIT(0x20, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_COMMA_PAD) PORT_CHAR(UCHAR_MAMEKEY(COMMA_PAD))
+ PORT_BIT(0x40, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_MINUS_PAD) PORT_CHAR(UCHAR_MAMEKEY(MINUS_PAD))
+ PORT_BIT(0x80, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_F4) PORT_CHAR(UCHAR_MAMEKEY(F4)) PORT_NAME("PF4")
+
+ PORT_START("row_b")
+ PORT_BIT(0xff, 0xff, IPT_UNUSED)
+
+ PORT_START("row_c")
+ PORT_BIT(0xff, 0xff, IPT_UNUSED)
+
+ PORT_START("row_d")
+ PORT_BIT(0xff, 0xff, IPT_UNUSED)
+
+ PORT_START("row_e")
+ PORT_BIT(0xff, 0xff, IPT_UNUSED)
+
+ PORT_START("row_f")
+ PORT_BIT(0xff, 0xff, IPT_UNUSED)
+INPUT_PORTS_END
+
+ioport_constructor executive10_102_kbd_device::device_input_ports() const
+{
+ return INPUT_PORTS_NAME( keyboard );
+}
+
+
+//**************************************************************************
+// MACHINE EMULATION
+//**************************************************************************
+
+void executive10_102_kbd_device::device_start()
+{
+ // register for save states
+ save_item(NAME(m_key_row));
+}
+
+void executive10_102_kbd_device::device_reset()
+{
+ // signal we are connected to the host
+ m_cts_cb(0);
+}
+
+void executive10_102_kbd_device::rxd_w(int state)
+{
+ m_mcu->set_input_line(MCS48_INPUT_IRQ, state ? CLEAR_LINE : ASSERT_LINE);
+}
+
+int executive10_102_kbd_device::t0_r()
+{
+ return m_shift->read();
+}
+
+int executive10_102_kbd_device::t1_r()
+{
+ return m_ctrl->read();
+}
+
+uint8_t executive10_102_kbd_device::bus_r()
+{
+ return m_keys[m_key_row]->read();
+}
+
+void executive10_102_kbd_device::p1_w(uint8_t data)
+{
+ // LEDs
+}
+
+void executive10_102_kbd_device::p2_w(uint8_t data)
+{
+ // 76------ unknown
+ // --5----- serial data output
+ // ---4---- buzzer
+ // ----3210 key row to scan
+
+ m_key_row = data & 0x0f;
+ m_buzzer->set_state(BIT(~data, 4));
+ m_txd_cb(BIT(data, 5));
+}
diff --git a/src/mame/esprit/executive10_102_kbd.h b/src/mame/esprit/executive10_102_kbd.h
new file mode 100644
index 00000000000..9704f95e940
--- /dev/null
+++ b/src/mame/esprit/executive10_102_kbd.h
@@ -0,0 +1,65 @@
+// license: BSD-3-Clause
+// copyright-holders: Dirk Best
+/***************************************************************************
+
+ Esprit Systems Executive 10/102 Keyboard
+
+***************************************************************************/
+
+#ifndef MAME_ESPRIT_EXECUTIVE10_102_KBD_H
+#define MAME_ESPRIT_EXECUTIVE10_102_KBD_H
+
+#pragma once
+
+#include "cpu/mcs48/mcs48.h"
+#include "sound/beep.h"
+
+
+//**************************************************************************
+// TYPE DEFINITIONS
+//**************************************************************************
+
+class executive10_102_kbd_device : public device_t
+{
+public:
+ // construction/destruction
+ executive10_102_kbd_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock = 0);
+
+ // callbacks
+ auto txd_cb() { return m_txd_cb.bind(); }
+ auto cts_cb() { return m_cts_cb.bind(); }
+
+ // from host
+ void rxd_w(int state);
+
+protected:
+ // device_t overrides
+ virtual const tiny_rom_entry *device_rom_region() const override;
+ virtual void device_add_mconfig(machine_config &config) override;
+ virtual ioport_constructor device_input_ports() const override;
+ virtual void device_start() override;
+ virtual void device_reset() override;
+
+private:
+ required_device m_mcu;
+ required_device m_buzzer;
+ required_ioport m_shift;
+ required_ioport m_ctrl;
+ required_ioport_array<16> m_keys;
+
+ devcb_write_line m_txd_cb;
+ devcb_write_line m_cts_cb;
+
+ uint8_t m_key_row;
+
+ int t0_r();
+ int t1_r();
+ uint8_t bus_r();
+ void p1_w(uint8_t data);
+ void p2_w(uint8_t data);
+};
+
+// device type declaration
+DECLARE_DEVICE_TYPE(EXECUTIVE10_102_KBD, executive10_102_kbd_device)
+
+#endif // MAME_ESPRIT_EXECUTIVE10_102_KBD_H
diff --git a/src/mame/ibm/ibm5100.cpp b/src/mame/ibm/ibm5100.cpp
new file mode 100644
index 00000000000..35be65063d4
--- /dev/null
+++ b/src/mame/ibm/ibm5100.cpp
@@ -0,0 +1,488 @@
+// license:BSD-3-Clause
+// copyright-holders:Patrick Mackinlay
+
+/*
+ * IBM 5100.
+ *
+ * Sources:
+ * - IBM 5100 Maintenance Information Manual, SY31-0405-3, Fourth Edition (October 1979), International Business Machines Corporation
+ *
+ * TODO:
+ * - display registers
+ * - device address f
+ * - tape controller
+ * - printer
+ * - communications cards
+ * - expansion feature
+ * - later models (5110, 5120, 5130)
+ */
+
+#include "emu.h"
+
+#include "ibm5100_kbd.h"
+
+#include "cpu/palm/palm.h"
+
+#include "screen.h"
+
+//#define VERBOSE (LOG_GENERAL)
+#include "logmacro.h"
+
+namespace {
+
+class ibm5100_state : public driver_device
+{
+public:
+ ibm5100_state(machine_config const &mconfig, device_type type, char const *tag)
+ : driver_device(mconfig, type, tag)
+ , m_cpu(*this, "cpu")
+ , m_screen(*this, "screen")
+ , m_kbd(*this, "kbd")
+ , m_nxr(*this, { "apl", "basic" })
+ , m_j2(*this, "j2")
+ , m_conf(*this, "CONF")
+ , m_disp(*this, "DISP")
+ , m_lang(*this, "LANG")
+ , m_ros(*this, "ros")
+ {
+ }
+
+ void ibm5100(machine_config &config);
+
+protected:
+ // driver_device implementation
+ virtual void machine_start() override;
+ virtual void machine_reset() override;
+
+ void cpu_ros_map(address_map &map);
+ void cpu_rws_map(address_map &map);
+ void cpu_ioc_map(address_map &map);
+ void cpu_iod_map(address_map &map);
+
+ u32 screen_update(screen_device &screen, bitmap_rgb32 &bitmap, rectangle const &cliprect);
+
+ // e2 - ros control card
+ u8 e2_sts_r();
+ void e2_ctl_w(u8 data);
+ u8 e2_r();
+ void e2_w(u8 data);
+
+ // f2 - base i/o card
+ u8 f2_kbd_sts_r();
+ void f2_kbd_ctl_w(u8 data);
+ void da0_ctl_w(u8 data);
+ void daf_ctl_w(u8 data);
+
+private:
+ required_device m_cpu;
+ required_device m_screen;
+ required_device m_kbd;
+
+ required_region_ptr_array m_nxr;
+ required_region_ptr m_j2;
+
+ required_ioport m_conf;
+ required_ioport m_disp;
+ required_ioport m_lang;
+
+ memory_view m_ros;
+
+ u8 m_getb_bus;
+
+ u8 m_e2_ff; // e2 card flip-flops
+ u8 m_f2_ff; // f2 card flip-flops
+ u16 m_e2_address;
+
+ std::unique_ptr m_rws;
+};
+
+enum e2_ff_mask : u8
+{
+ E2_RS = 0x01, // ROS select (0=APL, 1=BASIC/common)
+ E2_PS = 0x02, // put strobe
+ E2_B0 = 0x04, // data address bit 0
+};
+
+enum f2_ff_mask : u8
+{
+ F2_KIE = 0x01, // keyboard interrupt enable
+ F2_DO = 0x10, // display off
+};
+
+void ibm5100_state::machine_start()
+{
+ // for simplicity allocate maximum 64KiB
+ m_rws = std::make_unique(0x8000);
+
+ save_item(NAME(m_getb_bus));
+
+ save_item(NAME(m_e2_ff));
+ save_item(NAME(m_f2_ff));
+ save_item(NAME(m_e2_address));
+
+ save_pointer(NAME(m_rws), 0x8000);
+}
+
+void ibm5100_state::machine_reset()
+{
+ m_e2_ff = 0;
+ m_f2_ff = 0;
+
+ m_e2_address = 0;
+
+ // install configured rws
+ unsigned const rws_cards = (m_conf->read() & 3) + 1;
+ m_cpu->space(palm_device::AS_RWS).install_ram(0x80, 0x4000 * rws_cards - 1, &m_rws[0x40]);
+ m_ros[1].install_ram(0x80, 0x4000 * rws_cards - 1, &m_rws[0x40]);
+}
+
+void ibm5100_state::cpu_ros_map(address_map &map)
+{
+ map(0x0000, 0xffff).view(m_ros);
+ m_ros[0](0x0000, 0xffff).rom().region("ros", 0);
+}
+
+void ibm5100_state::cpu_rws_map(address_map &map)
+{
+ map.unmap_value_high();
+}
+
+void ibm5100_state::cpu_ioc_map(address_map &map)
+{
+ map(0x0, 0x0).w(FUNC(ibm5100_state::da0_ctl_w));
+ map(0x1, 0x1).rw(FUNC(ibm5100_state::e2_sts_r), FUNC(ibm5100_state::e2_ctl_w));
+ map(0x2, 0x3).noprw();
+ map(0x4, 0x4).rw(FUNC(ibm5100_state::f2_kbd_sts_r), FUNC(ibm5100_state::f2_kbd_ctl_w));
+ // 5 printer r:not used w:control
+ map(0x6, 0x7).noprw();
+ // 8 expansion r:status w:control
+ map(0x9, 0xd).noprw();
+ // e tape r:status w:control
+ map(0xf, 0xf).nopr().w(FUNC(ibm5100_state::daf_ctl_w));
+}
+
+void ibm5100_state::cpu_iod_map(address_map &map)
+{
+ map.unmap_value_high();
+
+ map(0x0, 0x0).noprw();
+ map(0x1, 0x1).rw(FUNC(ibm5100_state::e2_r), FUNC(ibm5100_state::e2_w));
+ map(0x2, 0x3).noprw();
+ map(0x4, 0x4).r(m_kbd, FUNC(ibm5100_keyboard_device::read)).nopw();
+ // 5 r:printer w:print data
+ map(0x6, 0x7).noprw();
+ // 8 expansion r:not used w:data
+ map(0x9, 0xd).noprw();
+ // e r:tape data w:tape
+ map(0xf, 0xf).noprw();
+}
+
+void ibm5100_state::ibm5100(machine_config &config)
+{
+ PALM(config, m_cpu, 15'091'200);
+ m_cpu->set_addrmap(palm_device::AS_ROS, &ibm5100_state::cpu_ros_map);
+ m_cpu->set_addrmap(palm_device::AS_RWS, &ibm5100_state::cpu_rws_map);
+ m_cpu->set_addrmap(palm_device::AS_IOC, &ibm5100_state::cpu_ioc_map);
+ m_cpu->set_addrmap(palm_device::AS_IOD, &ibm5100_state::cpu_iod_map);
+ m_cpu->getb_bus().set([this](offs_t offset, u8 data) { m_getb_bus = data; });
+ m_cpu->select_ros().set([this](int state) { m_ros.select(state); });
+
+ /*
+ * Display output is 16 rows of 64 characters. Each character cell is 10x12
+ * pixels with 8x12 driven from character ROS data. The last two horizontal
+ * pixels of each character cell line and every other scan line are blank.
+ */
+ SCREEN(config, m_screen, SCREEN_TYPE_RASTER);
+ m_screen->set_raw(15'091'200, 64*10, 0, 64*10, 16*12*2, 0, 16*12*2);
+ m_screen->set_screen_update(FUNC(ibm5100_state::screen_update));
+
+ IBM5100_KEYBOARD(config, m_kbd);
+ m_kbd->strobe().set(
+ [this](int state)
+ {
+ if ((m_f2_ff & F2_KIE) && !state)
+ m_cpu->set_input_line(palm_device::IRPT_REQ3, 0);
+ });
+}
+
+u32 ibm5100_state::screen_update(screen_device &screen, bitmap_rgb32 &bitmap, rectangle const &cliprect)
+{
+ static rgb_t const c[] = { rgb_t::white(), rgb_t::black() };
+
+ // read display switches
+ u8 const disp = m_disp->read();
+
+ bool const reverse = BIT(disp, 0);
+ bool const n64 = !BIT(disp, 2);
+ bool const r32 = BIT(disp, 3);
+
+ // start with a blank screen
+ bitmap.fill(c[reverse]);
+
+ // then generate characters
+ auto const rws = util::big_endian_cast(m_rws.get());
+ for (unsigned char_y = 0; char_y < 16; char_y++)
+ {
+ // every other scan line is blank
+ int const y = screen.visible_area().min_y + char_y * 12 * 2;
+
+ // compute offset into rws for each row
+ offs_t offset = 0x200 + char_y * 64 + (r32 ? 32 : 0);
+
+ for (unsigned char_x = 0; char_x < 64; char_x++)
+ {
+ int const x = screen.visible_area().min_x + char_x * 10;
+
+ // read next character if display is on and normal mode or even column
+ u8 char_data = 0;
+ if (!(m_f2_ff & F2_DO) && (n64 || !(char_x & 1)))
+ char_data = rws[offset++];
+
+ // draw 8x12 character cell
+ for (unsigned cell_y = 0; cell_y < 12; cell_y++)
+ {
+ // index into character font data
+ unsigned const underline = ((cell_y > 7) && BIT(char_data, 7)) ? 4 : 0;
+ u8 const cell_data = m_j2[(char_data & 0x7f) * 16 + cell_y + underline];
+
+ bitmap.pix(y + cell_y * 2, x + 0) = c[BIT(cell_data, 7) ^ reverse];
+ bitmap.pix(y + cell_y * 2, x + 1) = c[BIT(cell_data, 6) ^ reverse];
+ bitmap.pix(y + cell_y * 2, x + 2) = c[BIT(cell_data, 5) ^ reverse];
+ bitmap.pix(y + cell_y * 2, x + 3) = c[BIT(cell_data, 4) ^ reverse];
+ bitmap.pix(y + cell_y * 2, x + 4) = c[BIT(cell_data, 3) ^ reverse];
+ bitmap.pix(y + cell_y * 2, x + 5) = c[BIT(cell_data, 2) ^ reverse];
+ bitmap.pix(y + cell_y * 2, x + 6) = c[BIT(cell_data, 1) ^ reverse];
+ bitmap.pix(y + cell_y * 2, x + 7) = c[BIT(cell_data, 0) ^ reverse];
+ }
+ }
+ }
+
+ return 0;
+}
+
+void ibm5100_state::da0_ctl_w(u8 data)
+{
+ LOG("da0_ctl_w 0x%02x (%s)\n", data, machine().describe_context());
+
+ // bit 4: 0=display off
+ if (!BIT(data, 4))
+ m_f2_ff |= F2_DO;
+ else
+ m_f2_ff &= ~F2_DO;
+}
+
+u8 ibm5100_state::e2_sts_r()
+{
+ u8 data = 0xff;
+
+ if (!machine().side_effects_disabled())
+ {
+ data = (m_e2_ff & E2_PS) ? u8(m_e2_address) : (m_e2_address >> 8);
+
+ m_e2_ff ^= E2_PS;
+ }
+
+ return data;
+}
+
+void ibm5100_state::e2_ctl_w(u8 data)
+{
+ LOG("e2_ctl_w 0x%02x (%s)\n", data, machine().describe_context());
+
+ if (!BIT(data, 3))
+ m_e2_ff &= ~E2_RS;
+ else if (!BIT(data, 2))
+ m_e2_ff |= E2_RS;
+
+ m_e2_ff &= ~(E2_B0 | E2_PS);
+ m_e2_address = 0;
+}
+
+u8 ibm5100_state::e2_r()
+{
+ u8 data = 0xff;
+
+ if (!machine().side_effects_disabled())
+ {
+ bool const basic = m_e2_ff & E2_RS;
+
+ // check model has selected ROS (all models have common)
+ if (BIT(m_conf->read(), 2 + basic) || (basic && m_e2_address >= 0x9000))
+ {
+ /*
+ * APL non-executable ROS is addressed with an unshifted 16-bit
+ * address, giving a 128KiB range; BASIC uses a shifted address,
+ * giving 64KiB. Even and odd bytes are selected by a flip-flop
+ * which is toggled with each read.
+ */
+ data = BIT(m_nxr[basic][m_e2_address >> basic], (m_e2_ff & E2_B0) ? 0 : 8, 8);
+ }
+
+ // always increment address for BASIC, only on odd bytes for APL
+ if (basic || (m_e2_ff & E2_B0))
+ m_e2_address++;
+
+ // toggle even/odd byte flip-flop
+ m_e2_ff ^= E2_B0;
+ }
+
+ return data;
+}
+
+void ibm5100_state::e2_w(u8 data)
+{
+ m_e2_address = (m_e2_address << 8) | data;
+
+ if (m_e2_ff & E2_PS)
+ {
+ LOG("e2_address 0x%04x (%s)\n", m_e2_address, machine().describe_context());
+
+ // data byte even/odd flip-flop is cleared except when BASIC is
+ // selected and the address is odd
+ if ((m_e2_ff & E2_RS) && (m_e2_address & 1))
+ m_e2_ff |= E2_B0;
+ else
+ m_e2_ff &= ~E2_B0;
+ }
+
+ // toggle put strobe flip-flop
+ m_e2_ff ^= E2_PS;
+}
+
+u8 ibm5100_state::f2_kbd_sts_r()
+{
+ if (!machine().side_effects_disabled())
+ {
+ switch (m_getb_bus)
+ {
+ case 0x40:
+ // keyboard data gate
+ return m_kbd->read();
+ case 0x80:
+ // keyboard status gate
+ return m_lang->read();
+ default:
+ LOG("f2_kbd_sts_r: unknown 0x%02x (%s)\n", m_getb_bus, machine().describe_context());
+ break;
+ }
+ }
+
+ return 0xff;
+}
+
+void ibm5100_state::f2_kbd_ctl_w(u8 data)
+{
+ LOG("f2_kbd_ctl_w 0x%02x (%s)\n", data, machine().describe_context());
+
+ // bit 6: 0=reset and disable keyboard interrupts
+ if (!BIT(data, 6))
+ {
+ m_f2_ff &= ~F2_KIE;
+
+ m_cpu->set_input_line(palm_device::IRPT_REQ3, 1);
+ }
+
+ // bit 4: 0=lock keyboard
+ m_kbd->lock_w(BIT(data, 4));
+
+ // bit 1: 0=enable typamatic
+ // FIXME: inverted?
+ m_kbd->typamatic_w(BIT(data, 1));
+
+ // bit 0: 0=enable keyboard interrupt
+ if (!BIT(data, 0))
+ m_f2_ff |= F2_KIE;
+ else
+ m_f2_ff &= ~F2_KIE;
+}
+
+void ibm5100_state::daf_ctl_w(u8 data)
+{
+ LOG("daf_ctl_w 0x%02x (%s)\n", data, machine().describe_context());
+
+ // bit function
+ // 7 expansion da=8
+ // 6 tape da=e
+ // 5 keyboard da=4
+ // 4 printer da=5
+ // 3 enable cycle steal
+ // 2 reset da=b
+ // 1 reset da=c
+ // 0 reset da=d
+}
+
+ROM_START(ibm5100)
+ // Executable ROS
+ ROM_REGION16_BE(0x10000, "ros", 0)
+ ROM_LOAD("h2.ros", 0x0000, 0x8000, CRC(36d11e3d) SHA1(6be2c0728b88debcd557879c25781a9c7afc5224))
+ ROM_LOAD("h4.ros", 0x8000, 0x8000, CRC(5d3eceb7) SHA1(e5412914d74e8149ea8a250a6560d1738555ec7e))
+
+ // BASIC + Common and Language non-executable ROS
+ /*
+ * The common ROS is physically located on the E2 card, and not on the C4
+ * BASIC card, however it is selected together with the BASIC ROS and
+ * logically appended to the address space.
+ */
+ ROM_REGION16_BE(0x10000, "basic", 0)
+ ROM_LOAD("c4.ros", 0x0000, 0x9000, CRC(b1abeb4a) SHA1(e0151fefe63c43c8912599615ddfb7c06f111c72))
+ ROM_LOAD("e2.ros", 0x9000, 0x4800, CRC(be4289c3) SHA1(008ea7bb25fda94540bf5e02eff5a59bb1c86aac))
+ ROM_FILL(0xd800, 0x2800, 0xff)
+
+ // APL non-executable ROS
+ ROM_REGION16_BE(0x20000, "apl", 0)
+ ROM_LOAD("c2.ros", 0x00000, 0x8000, CRC(fba01c70) SHA1(a7dd9b60ba33021d830751df2de5513e0de452f2))
+ ROM_LOAD("d2.ros", 0x08000, 0x8000, CRC(afb3ba33) SHA1(15292d1082a2d6211fbdbbb0781466506d310954))
+ ROM_LOAD("d4.ros", 0x10000, 0x8000, CRC(a03570c9) SHA1(5a6e7a5b38b96c8ff47be2572272f8ed0cd31efd))
+ ROM_FILL(0x18000, 0x8000, 0xff)
+
+ // Display Adapter ROS
+ /*
+ * This data was hand-made based on the character map in the documentation.
+ * It was assumed that the first 8 bytes of each character store the upper
+ * 8x8 cell, then 2x4 byte entries contain the normal and underlined lower
+ * 4 rows of the total 8x12 cell respectively.
+ */
+ ROM_REGION(0x800, "j2", 0)
+ ROM_LOAD("j2.ros", 0x000, 0x800, CRC(428e5b66) SHA1(9def68eed9dc2b8f08581387f8b74b49b3faf7e7) BAD_DUMP)
+ROM_END
+
+static INPUT_PORTS_START(ibm5100)
+ PORT_START("CONF")
+ PORT_CONFNAME(0x0f, 0x0f, "Model")
+ PORT_CONFSETTING(0x04, "A1 - APL 16K")
+ PORT_CONFSETTING(0x05, "A2 - APL 32K")
+ PORT_CONFSETTING(0x06, "A3 - APL 48K")
+ PORT_CONFSETTING(0x07, "A4 - APL 64K")
+
+ PORT_CONFSETTING(0x08, "B1 - BASIC 16K")
+ PORT_CONFSETTING(0x09, "B2 - BASIC 32K")
+ PORT_CONFSETTING(0x0a, "B3 - BASIC 48K")
+ PORT_CONFSETTING(0x0b, "B4 - BASIC 64K")
+
+ PORT_CONFSETTING(0x0c, "C1 - APL/BASIC 16K")
+ PORT_CONFSETTING(0x0d, "C2 - APL/BASIC 32K")
+ PORT_CONFSETTING(0x0e, "C3 - APL/BASIC 48K")
+ PORT_CONFSETTING(0x0f, "C4 - APL/BASIC 64K")
+
+ PORT_START("DISP")
+ PORT_CONFNAME(0x01, 0x00, "Reverse")
+ PORT_CONFSETTING(0x00, "Black on White")
+ PORT_CONFSETTING(0x01, "White on Black")
+ PORT_CONFNAME(0x02, 0x00, "Display")
+ PORT_CONFSETTING(0x00, "Normal")
+ PORT_CONFSETTING(0x02, "Registers")
+ PORT_CONFNAME(0x0c, 0x00, "Columns")
+ PORT_CONFSETTING(0x04, "L32")
+ PORT_CONFSETTING(0x00, "64")
+ PORT_CONFSETTING(0x0c, "R32")
+
+ PORT_START("LANG")
+ PORT_CONFNAME(0x40, 0x40, "Language")
+ PORT_CONFSETTING(0x00, "APL") PORT_CONDITION("CONF", 0x04, EQUALS, 0x04)
+ PORT_CONFSETTING(0x40, "BASIC") PORT_CONDITION("CONF", 0x08, EQUALS, 0x08)
+INPUT_PORTS_END
+
+} // anonymous namespace
+
+/* YEAR NAME PARENT COMPAT MACHINE INPUT CLASS INIT COMPANY FULLNAME FLAGS */
+COMP(1975, ibm5100, 0, 0, ibm5100, ibm5100, ibm5100_state, empty_init, "International Business Machines", "IBM 5100", MACHINE_NO_SOUND_HW)
diff --git a/src/mame/ibm/ibm5100_kbd.cpp b/src/mame/ibm/ibm5100_kbd.cpp
new file mode 100644
index 00000000000..c20386b1495
--- /dev/null
+++ b/src/mame/ibm/ibm5100_kbd.cpp
@@ -0,0 +1,299 @@
+// license:BSD-3-Clause
+// copyright-holders:Patrick Mackinlay
+
+/*
+ * A high level emulation of the IBM 5100 keyboard.
+ *
+ * Sources:
+ * - IBM 5100 Maintenance Information Manual, SY31-0405-3, Fourth Edition (October 1979), International Business Machines Corporation
+ *
+ * TODO:
+ * - missing key names and chars
+ *
+ * For columns 0..15, the scan code format is SrrCcccc where:
+ *
+ * S = shift modifier (1=active)
+ * rr = matrix row number
+ * C = command modifier (1=active)
+ * cccc = matrix column number
+ *
+ * For columns > 15, the scan code format is 1rrccCSc where:
+ *
+ * S = shift modifier (0=active)
+ * rr = matrix row number
+ * C = command modifier (1=active)
+ * cc..c = matrix column number
+ *
+ * This scheme disallows modifier combinations, with shift taking priority over
+ * command. Bits 5 and 6 of the scan code are swapped when output.
+ *
+ * Regular alpha, numeric and keypad keys are easily mapped 1:1 with a standard
+ * modern keyboard. Additional keys are mapped by default as follows:
+ *
+ * 5100 Key Mapping Rationale
+ * -------- ------- ---------
+ * +/- - closest key position, matching shifted symbol
+ * ×/÷ = closest key position
+ * ←/→ ; moved to row with two non-alpha keys
+ * = ' moved to row with two non-alpha keys
+ * [/( [ moved to row with three non-alpha keys, matching unshifted symbol
+ * ]/) ] moved to row with three non-alpha keys, matching unshifted symbol
+ * #/@ \ moved to row with three non-alpha keys
+ * &/$ ` available standard symbol key
+ *
+ * l/r/u/d arrow keys conceptual match
+ * Attention Delete available non-symbol, non-modal key
+ * Hold Backspace available non-symbol, non-modal key
+ * Execute Enter conceptual match
+ * Command L/R Control conceptual match
+ */
+
+#include "emu.h"
+#include "ibm5100_kbd.h"
+
+#include "machine/keyboard.ipp"
+
+//#define VERBOSE (LOG_GENERAL)
+#include "logmacro.h"
+
+DEFINE_DEVICE_TYPE(IBM5100_KEYBOARD, ibm5100_keyboard_device, "ibm5100_keyboard", "IBM 5100 Keyboard")
+
+INPUT_PORTS_START(ibm5100_keyboard)
+ PORT_START("modifiers")
+ PORT_BIT(0x01, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_LSHIFT)
+ PORT_CODE(KEYCODE_RSHIFT) PORT_NAME("Shift") PORT_CHAR(UCHAR_SHIFT_1)
+ PORT_BIT(0x02, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_LCONTROL)
+ PORT_CODE(KEYCODE_RCONTROL) PORT_NAME("Command") PORT_CHAR(UCHAR_MAMEKEY(LCONTROL))
+
+ PORT_START("col.0")
+ PORT_BIT(0x01, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_9) PORT_NAME(u8"9 \u2228") PORT_CHAR('9')
+ PORT_BIT(0x02, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_I) PORT_NAME(u8"I \u2373") PORT_CHAR('I')
+ PORT_BIT(0x04, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_K) PORT_NAME(u8"K '") PORT_CHAR('K') PORT_CHAR('\'')
+ PORT_BIT(0x08, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_COMMA) PORT_CHAR(',') PORT_CHAR(';')
+
+ PORT_START("col.1")
+ PORT_BIT(0x01, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_8) PORT_NAME(u8"8 \u2260") PORT_CHAR('8')
+ PORT_BIT(0x02, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_U) PORT_NAME(u8"U \u2193") PORT_CHAR('U')
+ PORT_BIT(0x04, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_J) PORT_NAME(u8"J \u2218") PORT_CHAR('J')
+ PORT_BIT(0x08, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_M) PORT_NAME(u8"M \u2223") PORT_CHAR('M')
+
+ PORT_START("col.2")
+ PORT_BIT(0x01, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_EQUALS) PORT_NAME(u8"× ÷") // FIXME: PORT_CHAR?
+ PORT_BIT(0x02, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_COLON) PORT_NAME(u8"\u2190 \u2192") // FIXME: PORT_CHAR?
+ PORT_BIT(0x04, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_CLOSEBRACE) PORT_CHAR(']') PORT_CHAR(')')
+ PORT_BIT(0x08, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_SLASH) PORT_CHAR('/') PORT_CHAR('\\')
+
+ PORT_START("col.3")
+ PORT_BIT(0x01, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_MINUS) PORT_CHAR('+') PORT_CHAR('-')
+ PORT_BIT(0x02, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_P) PORT_NAME(u8"P \u22c6") PORT_CHAR('P')
+ PORT_BIT(0x04, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_OPENBRACE) PORT_CHAR('[') PORT_CHAR('(')
+ PORT_BIT(0x08, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_SPACE) PORT_NAME("Space") PORT_CHAR(UCHAR_MAMEKEY(SPACE))
+
+ PORT_START("col.4")
+ PORT_BIT(0x01, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_UP) PORT_NAME("Up") PORT_CHAR(UCHAR_MAMEKEY(UP))
+ PORT_BIT(0x02, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_8_PAD) PORT_CHAR(UCHAR_MAMEKEY(8_PAD))
+ PORT_BIT(0x04, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_5_PAD) PORT_CHAR(UCHAR_MAMEKEY(5_PAD))
+ PORT_BIT(0x08, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_2_PAD) PORT_CHAR(UCHAR_MAMEKEY(2_PAD))
+
+ PORT_START("col.5")
+ PORT_BIT(0x01, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_7_PAD) PORT_CHAR(UCHAR_MAMEKEY(7_PAD))
+ PORT_BIT(0x02, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_4_PAD) PORT_CHAR(UCHAR_MAMEKEY(4_PAD))
+ PORT_BIT(0x04, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_1_PAD) PORT_CHAR(UCHAR_MAMEKEY(1_PAD))
+ PORT_BIT(0x08, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_0_PAD) PORT_CHAR(UCHAR_MAMEKEY(0_PAD))
+
+ PORT_START("col.6")
+ PORT_BIT(0x01, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_SLASH_PAD) PORT_CHAR(UCHAR_MAMEKEY(SLASH_PAD))
+ PORT_BIT(0x02, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_ASTERISK) PORT_NAME("Keypad *") PORT_CHAR(UCHAR_MAMEKEY(ASTERISK))
+ PORT_BIT(0x04, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_MINUS_PAD) PORT_CHAR(UCHAR_MAMEKEY(MINUS_PAD))
+ PORT_BIT(0x08, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_PLUS_PAD) PORT_CHAR(UCHAR_MAMEKEY(PLUS_PAD))
+
+ PORT_START("col.7")
+ PORT_BIT(0x01, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_9_PAD) PORT_CHAR(UCHAR_MAMEKEY(9_PAD))
+ PORT_BIT(0x02, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_6_PAD) PORT_CHAR(UCHAR_MAMEKEY(6_PAD))
+ PORT_BIT(0x04, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_3_PAD) PORT_CHAR(UCHAR_MAMEKEY(3_PAD))
+ PORT_BIT(0x08, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_DEL_PAD) PORT_NAME("Keypad .") PORT_CHAR(UCHAR_MAMEKEY(DEL_PAD))
+
+ PORT_START("col.8")
+ PORT_BIT(0x01, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_6) PORT_NAME(u8"6 \u2265") PORT_CHAR('6')
+ PORT_BIT(0x02, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_T) PORT_NAME(u8"T \u223c") PORT_CHAR('T')
+ PORT_BIT(0x04, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_G) PORT_NAME(u8"G \u2207") PORT_CHAR('G')
+ PORT_BIT(0x08, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_B) PORT_NAME(u8"B \u22a5") PORT_CHAR('B')
+
+ PORT_START("col.9")
+ PORT_BIT(0x01, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_7) PORT_NAME(u8"7 >") PORT_CHAR('7') PORT_CHAR('>')
+ PORT_BIT(0x02, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_Y) PORT_NAME(u8"Y \u2191") PORT_CHAR('Y')
+ PORT_BIT(0x04, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_H) PORT_NAME(u8"H \u2206") PORT_CHAR('H')
+ PORT_BIT(0x08, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_N) PORT_NAME(u8"N \u22a4") PORT_CHAR('N')
+
+ PORT_START("col.a")
+ PORT_BIT(0x01, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_4) PORT_NAME(u8"4 \u2264") PORT_CHAR('4')
+ PORT_BIT(0x02, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_E) PORT_NAME(u8"E \u220a") PORT_CHAR('E')
+ PORT_BIT(0x04, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_D) PORT_NAME(u8"D \u230a") PORT_CHAR('D')
+ PORT_BIT(0x08, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_C) PORT_NAME(u8"C \u2229") PORT_CHAR('C')
+
+ PORT_START("col.b")
+ PORT_BIT(0x01, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_5) PORT_NAME(u8"5 =") PORT_CHAR('5')
+ PORT_BIT(0x02, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_R) PORT_NAME(u8"R \u2374") PORT_CHAR('R')
+ PORT_BIT(0x04, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_F) PORT_NAME(u8"F _") PORT_CHAR('F') PORT_CHAR('_')
+ PORT_BIT(0x08, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_V) PORT_NAME(u8"V \u222a") PORT_CHAR('V')
+
+ PORT_START("col.c")
+ PORT_BIT(0x01, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_3) PORT_NAME(u8"3 <") PORT_CHAR('3') PORT_CHAR('<')
+ PORT_BIT(0x02, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_W) PORT_NAME(u8"W \u2375") PORT_CHAR('W')
+ PORT_BIT(0x04, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_S) PORT_NAME(u8"S \u2308") PORT_CHAR('S')
+ PORT_BIT(0x08, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_X) PORT_NAME(u8"X \u2283") PORT_CHAR('X')
+
+ PORT_START("col.d")
+ PORT_BIT(0x01, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_DOWN) PORT_NAME("Down") PORT_CHAR(UCHAR_MAMEKEY(DOWN))
+ PORT_BIT(0x02, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_1) PORT_NAME(u8"1 ¨") PORT_CHAR('1')
+ PORT_BIT(0x04, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_TILDE) PORT_NAME("&") PORT_CHAR('&') PORT_CHAR('$')
+ PORT_BIT(0x08, IP_ACTIVE_HIGH, IPT_UNUSED)
+
+ PORT_START("col.e")
+ PORT_BIT(0x01, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_0) PORT_NAME(u8"0 \u2227") PORT_CHAR('0')
+ PORT_BIT(0x02, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_O) PORT_NAME(u8"O \u25cb") PORT_CHAR('O')
+ PORT_BIT(0x04, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_L) PORT_NAME(u8"L \u2395") PORT_CHAR('L')
+ PORT_BIT(0x08, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_STOP) PORT_CHAR('.') PORT_CHAR(':')
+
+ PORT_START("col.f")
+ PORT_BIT(0x01, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_2) PORT_NAME(u8"2 \u203e") PORT_CHAR('2')
+ PORT_BIT(0x02, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_Q) PORT_NAME(u8"Q ?") PORT_CHAR('Q') PORT_CHAR('?')
+ PORT_BIT(0x04, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_A) PORT_NAME(u8"A \u237a") PORT_CHAR('A')
+ PORT_BIT(0x08, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_Z) PORT_NAME(u8"Z \u2282") PORT_CHAR('Z')
+
+ PORT_START("col.10")
+ PORT_BIT(0x01, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_DEL) PORT_NAME("Attention") PORT_CHAR(UCHAR_MAMEKEY(DEL))
+ PORT_BIT(0x02, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_RIGHT) PORT_NAME("Right") PORT_CHAR(UCHAR_MAMEKEY(RIGHT))
+ PORT_BIT(0x04, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_ENTER)
+ PORT_CODE(KEYCODE_ENTER_PAD) PORT_NAME("Execute") PORT_CHAR(13)
+ PORT_BIT(0x08, IP_ACTIVE_HIGH, IPT_UNUSED)
+
+ PORT_START("col.11")
+ PORT_BIT(0x01, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_BACKSPACE) PORT_NAME("Hold") PORT_CHAR(8)
+ PORT_BIT(0x02, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_LEFT) PORT_NAME("Left") PORT_CHAR(UCHAR_MAMEKEY(LEFT))
+ PORT_BIT(0x04, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_QUOTE) PORT_NAME("Equals") PORT_CHAR('=')
+ PORT_BIT(0x08, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_BACKSLASH) PORT_NAME("# @") PORT_CHAR('#') PORT_CHAR('@')
+INPUT_PORTS_END
+
+static const std::pairtypamatic_keys[] =
+{
+ std::make_pair( 3, 3), // space
+ std::make_pair( 4, 0), // cursor up
+ std::make_pair(13, 0), // cursor down
+ std::make_pair(16, 1), // cursor right
+ std::make_pair(17, 1), // cursor left
+};
+
+ibm5100_keyboard_device::ibm5100_keyboard_device(machine_config const &mconfig, char const *tag, device_t *owner, u32 clock)
+ : device_t(mconfig, IBM5100_KEYBOARD, tag, owner, clock)
+ , device_matrix_keyboard_interface(mconfig, *this
+ , "col.0", "col.1", "col.2", "col.3", "col.4", "col.5", "col.6", "col.7"
+ , "col.8", "col.9", "col.a", "col.b", "col.c", "col.d", "col.e", "col.f"
+ , "col.10", "col.11")
+ , m_strobe(*this)
+ , m_modifiers(*this, "modifiers")
+ , m_lock(false)
+{
+}
+
+void ibm5100_keyboard_device::device_start()
+{
+ save_item(NAME(m_scan));
+ save_item(NAME(m_typamatic));
+ save_item(NAME(m_lock));
+}
+
+void ibm5100_keyboard_device::device_reset()
+{
+ m_scan = 0;
+ m_strobe(1);
+ m_typamatic = false;
+
+ reset_key_state();
+ start_processing(attotime::from_hz(25'000));
+ typematic_stop();
+}
+
+void ibm5100_keyboard_device::key_make(u8 row, u8 column)
+{
+ if (m_lock)
+ return;
+
+ m_scan = translate(row, column);
+
+ LOG("key_make row %d column %d scan 0x%02x\n", row, column, m_scan);
+
+ m_strobe(0);
+ m_strobe(1);
+
+ // only some keys have typamatic action
+ if (std::find(std::begin(typamatic_keys), std::end(typamatic_keys), std::make_pair(row, column)) != std::end(typamatic_keys))
+ typematic_start(row, column, attotime::from_msec(700), attotime::from_msec(100));
+}
+
+void ibm5100_keyboard_device::key_break(u8 row, u8 column)
+{
+ if (typematic_is(row, column))
+ typematic_stop();
+
+ m_scan = 0;
+}
+
+void ibm5100_keyboard_device::key_repeat(u8 row, u8 column)
+{
+ if (m_typamatic)
+ {
+ m_scan = translate(row, column);
+
+ m_strobe(0);
+ m_strobe(1);
+ }
+}
+
+// column and row are swapped with respect device_matrix_keyboard_interface arguments
+u8 ibm5100_keyboard_device::translate(u8 column, u8 row)
+{
+ // compute basic scan code with bits 5 and 6 swapped
+ u8 data = bitswap<8>(row << 5 | column, 7, 5, 6, 4, 3, 2, 1, 0);
+
+ u8 const modifiers = m_modifiers->read();
+
+ // modifiers are applied differently for columns > 15
+ if (column < 16)
+ {
+ if (BIT(modifiers, 0))
+ // shift
+ data |= 0x80;
+ else if (BIT(modifiers, 1))
+ // command
+ data |= 0x10;
+ }
+ else
+ {
+ data |= 0x82;
+
+ if (BIT(modifiers, 0))
+ // shift
+ data &= ~0x02;
+ else if (BIT(modifiers, 1))
+ // command
+ data |= 0x04;
+ }
+
+ return data;
+}
+
+void ibm5100_keyboard_device::typamatic_w(int state)
+{
+ m_typamatic = state;
+}
+
+void ibm5100_keyboard_device::lock_w(int state)
+{
+ m_lock = !state;
+}
+
+ioport_constructor ibm5100_keyboard_device::device_input_ports() const
+{
+ return INPUT_PORTS_NAME(ibm5100_keyboard);
+}
diff --git a/src/mame/ibm/ibm5100_kbd.h b/src/mame/ibm/ibm5100_kbd.h
new file mode 100644
index 00000000000..799bb3551ef
--- /dev/null
+++ b/src/mame/ibm/ibm5100_kbd.h
@@ -0,0 +1,49 @@
+// license:BSD-3-Clause
+// copyright-holders:Patrick Mackinlay
+
+#ifndef MAME_IBM_IBM5100_KBD_H
+#define MAME_IBM_IBM5100_KBD_H
+
+#pragma once
+
+#include "machine/keyboard.h"
+
+class ibm5100_keyboard_device
+ : public device_t
+ , protected device_matrix_keyboard_interface<18U>
+{
+public:
+ auto strobe() { return m_strobe.bind(); }
+
+ ibm5100_keyboard_device(machine_config const &mconfig, char const *tag, device_t *owner, u32 clock = 0);
+
+ u8 read() { return m_scan; }
+ void typamatic_w(int state);
+ void lock_w(int state);
+
+protected:
+ // device_t implementation
+ virtual ioport_constructor device_input_ports() const override;
+ virtual void device_start() override;
+ virtual void device_reset() override;
+
+ // device_matrix_keyboard_interface implementation
+ virtual void key_make(u8 row, u8 column) override;
+ virtual void key_break(u8 row, u8 column) override;
+ virtual void key_repeat(u8 row, u8 column) override;
+
+ u8 translate(u8 column, u8 row);
+
+private:
+ devcb_write_line m_strobe;
+
+ required_ioport m_modifiers;
+
+ u8 m_scan;
+ bool m_typamatic;
+ bool m_lock;
+};
+
+DECLARE_DEVICE_TYPE(IBM5100_KEYBOARD, ibm5100_keyboard_device)
+
+#endif // MAME_IBM_IBM5100_KBD_H
diff --git a/src/mame/mame.lst b/src/mame/mame.lst
index 1d6df1814a2..7a9ffd21892 100644
--- a/src/mame/mame.lst
+++ b/src/mame/mame.lst
@@ -17756,6 +17756,9 @@ e9161 //
@source:ericsson/eispc.cpp
epc // 1984 Ericsson PC
+@source:esprit/executive10.cpp
+exe10102 // 1983 Esprit Systems
+
@source:excalibur/igor.cpp
igor
@@ -19798,6 +19801,9 @@ husky // DVW Husky
@source:ibm/ibm3153.cpp
ibm3153 //
+@source:ibm/ibm5100.cpp
+ibm5100
+
@source:ibm/ibm5550.cpp
ibm5550 //
@@ -35856,6 +35862,7 @@ streetgr3 // (c) 1993
@source:pc/pcipc.cpp
pciagp //
pcipc //
+pcipcs7 //
pcipctx //
@source:pc/pcipc_sis.cpp
diff --git a/src/mame/namco/namcos12.cpp b/src/mame/namco/namcos12.cpp
index 290ea9ce7c1..644042a503f 100644
--- a/src/mame/namco/namcos12.cpp
+++ b/src/mame/namco/namcos12.cpp
@@ -97,10 +97,6 @@ It was shown only at an amusement show. Possibly a prototype still exists. Possi
Tekno Werk (C) Namco, 1999
Some kind of music game similar to Konami's Keyboard Mania series
-Um Jammer Lammy (C) Namco, 1999
-http://www.wailee.com/sys/lpic/UM_Jammer_Lammy.jpg
-https://www.youtube.com/watch?v=Jrwj4lUzKgU
-
The Namco System 12 system comprises 3 mandatory PCB's....
MOTHER PCB - This is the main PCB. It holds all sound circuitry, sound ROMs, program ROMs, shared RAM, bank-switching
logic, controller/input logic (including sound CPU) and some video output circuitry.
diff --git a/src/mame/pc/pcipc.cpp b/src/mame/pc/pcipc.cpp
index bda654aafb8..65290b71e6c 100644
--- a/src/mame/pc/pcipc.cpp
+++ b/src/mame/pc/pcipc.cpp
@@ -40,6 +40,8 @@
#include "machine/pci-ide.h"
#include "machine/w83977tf.h"
+#include "softlist_dev.h"
+
// enable ISA verbose messaging at I/O $80
// NOTE: xubuntu 6.10 will ping the port a lot once it gets to GNOME.
#define VERBOSE_ISA_DEBUG 0
@@ -59,13 +61,16 @@ class pcipc_state : public driver_device
static const boot_state_info boot_state_infos_award[];
void pcipc(machine_config &config);
+ void pcipcs7(machine_config &config);
void pcipctx(machine_config &config);
void pcinv3(machine_config &config);
- void pcimga(machine_config &config);
void pciagp(machine_config &config);
pcipc_state(const machine_config &mconfig, device_type type, const char *tag);
+protected:
+ void x86_softlists(machine_config &config);
+
private:
void pcipc_map(address_map &map);
void pcipc_map_io(address_map &map);
@@ -556,6 +561,16 @@ void pcipc_state::pcipc_map_io(address_map &map)
map.unmap_value_high();
}
+void pcipc_state::x86_softlists(machine_config &config)
+{
+ /* software lists */
+ SOFTWARE_LIST(config, "pc_disk_list").set_original("ibm5150");
+ SOFTWARE_LIST(config, "at_disk_list").set_original("ibm5170");
+ SOFTWARE_LIST(config, "at_cdrom_list").set_original("ibm5170_cdrom");
+ SOFTWARE_LIST(config, "at_hdd_list").set_original("ibm5170_hdd");
+ SOFTWARE_LIST(config, "midi_disk_list").set_compatible("midi_flop");
+}
+
void pcipc_state::pcipc(machine_config &config)
{
pentium_device &maincpu(PENTIUM(config, "maincpu", 90000000));
@@ -602,6 +617,18 @@ void pcipc_state::pcipc(machine_config &config)
serport1.cts_handler().set("board4:fdc37c93x", FUNC(fdc37c93x_device::ncts2_w));
// SW1000XG(config, "pci:11.0");
+
+ x86_softlists(config);
+}
+
+void pcipc_state::pcipcs7(machine_config &config)
+{
+ pcipc_state::pcipc(config);
+ pentium_mmx_device &maincpu(PENTIUM_MMX(config.replace(), "maincpu", 266'000'000)); // socket 7 CPU
+ maincpu.set_addrmap(AS_PROGRAM, &pcipc_state::pcipc_map);
+ maincpu.set_addrmap(AS_IO, &pcipc_state::pcipc_map_io);
+ maincpu.set_irq_acknowledge_callback("pci:07.0:pic8259_master", FUNC(pic8259_device::inta_cb));
+ maincpu.smiact().set("pci:00.0", FUNC(i82439hx_host_device::smi_act_w));
}
void pcipc_state::pcipctx(machine_config &config)
@@ -620,6 +647,8 @@ void pcipc_state::pcipctx(machine_config &config)
PCI_SLOT(config, "pci:2", pci_cards, 16, 1, 2, 3, 0, nullptr);
PCI_SLOT(config, "pci:3", pci_cards, 17, 2, 3, 0, 1, nullptr);
PCI_SLOT(config, "pci:4", pci_cards, 18, 3, 0, 1, 2, "mga2064w");
+
+ x86_softlists(config);
}
void pcipc_state::pciagp(machine_config &config)
@@ -676,6 +705,8 @@ void pcipc_state::pciagp(machine_config &config)
PCI_SLOT(config, "pci:2", pci_cards, 16, 1, 2, 3, 0, nullptr);
PCI_SLOT(config, "pci:3", pci_cards, 17, 2, 3, 0, 1, nullptr);
PCI_SLOT(config, "pci:4", pci_cards, 18, 3, 0, 1, 2, nullptr);
+
+ x86_softlists(config);
}
ROM_START(pcipc)
@@ -709,6 +740,8 @@ ROM_START(pciagp)
ROMX_LOAD( "p2xbl_award_451pg.bin", 0x00000, 0x040000, CRC(37d0030e) SHA1(c6773d0e02325116f95c497b9953f59a9ac81317), ROM_BIOS(0) )
ROM_END
+#define rom_pcipcs7 rom_pcipc
+
static INPUT_PORTS_START(pcipc)
INPUT_PORTS_END
@@ -716,5 +749,6 @@ INPUT_PORTS_END
COMP(1998, pcipc, 0, 0, pcipc, pcipc, pcipc_state, empty_init, "Hack Inc.", "Sandbox PCI PC (430HX)", MACHINE_NO_SOUND )
+COMP(1998, pcipcs7, pcipc, 0, pcipcs7, pcipc, pcipc_state, empty_init, "Hack Inc.", "Sandbox PCI PC (430HX, Socket 7 CPU)", MACHINE_NO_SOUND ) // alternative of above, for running already installed OSes at their nominal speed + fiddling with MMX
COMP(1998, pcipctx, 0, 0, pcipctx, pcipc, pcipc_state, empty_init, "Hack Inc.", "Sandbox PCI PC (430TX)", MACHINE_NO_SOUND | MACHINE_NOT_WORKING) // unemulated super I/O
COMP(1999, pciagp, 0, 0, pciagp, pcipc, pcipc_state, empty_init, "Hack Inc.", "Sandbox PCI/AGP PC (440BX)", MACHINE_NO_SOUND | MACHINE_NOT_WORKING) // errors out with ISA state $05 (keyboard, blame 8042kbdc.cpp) bp e140c,1,{eax&=~1;g}) does stuff if bypassed but eventually PnP breaks OS booting
diff --git a/src/mame/sinclair/atm.h b/src/mame/sinclair/atm.h
index 09c012e9f8b..fbdbbe20081 100644
--- a/src/mame/sinclair/atm.h
+++ b/src/mame/sinclair/atm.h
@@ -63,7 +63,7 @@ class atm_state : public spectrum_128_state
u16 &pen_page(u8 bank) { return m_pages_map[BIT(m_port_7ffd_data, 4)][bank]; }
void atm_update_memory();
virtual u8 merge_ram_with_7ffd(u8 ram_page) { return (ram_page & ~0x07) | (m_port_7ffd_data & 0x07); }
- virtual bool is_port_7ffd_locked() { return BIT(m_port_7ffd_data, 5); };
+ virtual bool is_port_7ffd_locked() { return BIT(m_port_7ffd_data, 5); }
bool is_dos_active() { return !m_cpm_n || m_beta->is_active(); }
virtual void spectrum_update_screen(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect) override;
diff --git a/src/mame/sinclair/spec128.cpp b/src/mame/sinclair/spec128.cpp
index a00cef71087..b89ad3a02d6 100644
--- a/src/mame/sinclair/spec128.cpp
+++ b/src/mame/sinclair/spec128.cpp
@@ -353,9 +353,9 @@ void spectrum_128_state::spectrum_128(machine_config &config)
spectrum(config);
Z80(config.replace(), m_maincpu, X1_128_SINCLAIR / 10);
- m_maincpu->set_addrmap(AS_PROGRAM, &spectrum_128_state::spectrum_128_mem);
- m_maincpu->set_addrmap(AS_IO, &spectrum_128_state::spectrum_128_io);
- m_maincpu->set_addrmap(AS_OPCODES, &spectrum_128_state::spectrum_128_fetch);
+ m_maincpu->set_memory_map(&spectrum_128_state::spectrum_128_mem);
+ m_maincpu->set_io_map(&spectrum_128_state::spectrum_128_io);
+ m_maincpu->set_m1_map(&spectrum_128_state::spectrum_128_fetch);
m_maincpu->set_vblank_int("screen", FUNC(spectrum_128_state::spec_interrupt));
m_maincpu->nomreq_cb().set(FUNC(spectrum_128_state::spectrum_nomreq));
diff --git a/src/mame/sinclair/spec_snqk.cpp b/src/mame/sinclair/spec_snqk.cpp
index 1bd015df895..784dc7998c5 100644
--- a/src/mame/sinclair/spec_snqk.cpp
+++ b/src/mame/sinclair/spec_snqk.cpp
@@ -1072,7 +1072,7 @@ void spectrum_state::setup_plusd(uint8_t *snapdata, uint32_t snapsize)
m_port_7ffd_data += i;
update_paging();
break;
- };
+ }
logerror("Loading bank %d from offset:%05X\n", i, PLUSD128_HDR + i*SPECTRUM_BANK);
for (j = 0; j < SPECTRUM_BANK; j++)
space.write_byte(j + addr, snapdata[j + PLUSD128_HDR + i*SPECTRUM_BANK]);
@@ -2010,7 +2010,7 @@ void spectrum_state::setup_frz(uint8_t *snapdata, uint32_t snapsize)
m_port_7ffd_data += banks[i];
update_paging();
break;
- };
+ }
logerror("Loading bank %d from offset:%05X\n", banks[i], FRZ_HDR + i*SPECTRUM_BANK);
for (j = 0; j < SPECTRUM_BANK; j++)
space.write_byte(j + addr, snapdata[j + FRZ_HDR + i*SPECTRUM_BANK]);
diff --git a/src/mame/sinclair/specnext_copper.cpp b/src/mame/sinclair/specnext_copper.cpp
new file mode 100644
index 00000000000..acbdc0feb4d
--- /dev/null
+++ b/src/mame/sinclair/specnext_copper.cpp
@@ -0,0 +1,142 @@
+// license:BSD-3-Clause
+/**********************************************************************
+ Spectrum Next Copper
+Refs:
+ https://gitlab.com/thesmog358/tbblue/-/raw/master/docs/extra-hw/copper/COPPER-v0.1c.TXT
+**********************************************************************/
+
+#include "emu.h"
+#include "specnext_copper.h"
+
+#include
+
+
+#define LOG_CTRL (1U << 1)
+#define LOG_DATA (1U << 2)
+
+#define VERBOSE ( LOG_GENERAL /*| LOG_CTRL | LOG_DATA*/ )
+#include "logmacro.h"
+
+#define LOGCTRL(...) LOGMASKED(LOG_CTRL, __VA_ARGS__)
+#define LOGDATA(...) LOGMASKED(LOG_DATA, __VA_ARGS__)
+
+
+// device type definition
+DEFINE_DEVICE_TYPE(SPECNEXT_COPPER, specnext_copper_device, "specnext_copper", "Spectrum Next Copper")
+
+
+specnext_copper_device::specnext_copper_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock)
+ : device_t(mconfig, SPECNEXT_COPPER, tag, owner, clock)
+ , m_timer(nullptr)
+ , m_frame_timer(nullptr)
+ , m_listram(*this, "listram", 0x400 * 2, ENDIANNESS_LITTLE)
+ , m_out_nextreg_cb(*this)
+ , m_in_until_pos_cb(*this)
+{
+}
+
+void specnext_copper_device::copper_en_w(u8 data)
+{
+ if (m_copper_en != data)
+ {
+ m_copper_en = data;
+ if ((m_copper_en == 0b01) || (m_copper_en == 0b11))
+ m_copper_list_addr = 0;
+ m_copper_dout = 0;
+
+ switch(m_copper_en)
+ {
+ case 0b00:
+ LOGCTRL("STOP\n");
+ m_timer->reset();
+ m_frame_timer->reset();
+ break;
+ case 0b01:
+ LOGCTRL("RESET\n");
+ m_timer->adjust(m_in_until_pos_cb(0x0000));
+ break;
+ case 0b10:
+ LOGCTRL("START\n");
+ m_timer->adjust(attotime::zero);
+ break;
+ case 0b11:
+ LOGCTRL("FRAME\n");
+ m_frame_timer->adjust(m_in_until_pos_cb(0x0000));
+ break;
+ }
+ }
+}
+
+void specnext_copper_device::data_w(u16 addr, u8 data)
+{
+ LOGDATA("data(W) %03x %02x\n", addr, data);
+ assert(addr < 0x800);
+ m_listram[addr] = data;
+}
+
+TIMER_CALLBACK_MEMBER(specnext_copper_device::timer_callback)
+{
+ if (m_copper_dout == 0)
+ m_copper_list_data = (m_listram[m_copper_list_addr << 1] << 8) | m_listram[(m_copper_list_addr << 1) | 1];
+
+ if (m_copper_dout == 1) // if we are on MOVE, clear the output for the next cycle
+ {
+ m_out_nextreg_cb((m_copper_list_data >> 8) & 0x7f, m_copper_list_data & 0xff);
+ m_copper_dout = 0;
+ }
+ else if (BIT(m_copper_list_data, 15) == 1) // command WAIT
+ {
+ m_timer->adjust(m_in_until_pos_cb(0x8000 | m_copper_list_data));
+ ++m_copper_list_addr;
+ m_copper_dout = 0;
+ return;
+ }
+ else // command MOVE
+ {
+ if (BIT(m_copper_list_data, 8, 7) != 0) // dont generate the write pulse if its a NOP (MOVE 0,0)
+ m_copper_dout = 1;
+ ++m_copper_list_addr;
+ };
+
+ m_copper_list_addr %= 0x400;
+ m_timer->adjust(attotime::from_hz(clock()));
+}
+
+TIMER_CALLBACK_MEMBER(specnext_copper_device::frame_timer_callback)
+{
+ if (m_copper_en == 0b11)
+ {
+ m_copper_list_addr = 0;
+ m_copper_dout = 0;
+ m_frame_timer->adjust(m_in_until_pos_cb(0x0000));
+ m_timer->adjust(attotime::zero);
+ }
+ else
+ m_frame_timer->reset();
+}
+
+
+void specnext_copper_device::device_start()
+{
+ m_timer = timer_alloc(FUNC(specnext_copper_device::timer_callback), this);
+ m_frame_timer = timer_alloc(FUNC(specnext_copper_device::frame_timer_callback), this);
+
+ m_in_until_pos_cb.resolve_safe(attotime::zero);
+
+ save_item(NAME(m_copper_en));
+ save_item(NAME(m_copper_list_addr));
+ save_item(NAME(m_copper_list_data));
+ save_item(NAME(m_copper_dout));
+}
+
+void specnext_copper_device::device_reset()
+{
+ m_timer->reset();
+ m_frame_timer->reset();
+ memset(m_listram, 0, sizeof(m_listram));
+
+ m_copper_en = 0b00;
+ m_copper_list_addr = 0x0000;
+ m_copper_list_data = 0x00;
+ m_copper_dout = 0;
+}
diff --git a/src/mame/sinclair/specnext_copper.h b/src/mame/sinclair/specnext_copper.h
new file mode 100644
index 00000000000..f62ee548789
--- /dev/null
+++ b/src/mame/sinclair/specnext_copper.h
@@ -0,0 +1,50 @@
+// license:BSD-3-Clause
+// copyright-holders:Andrei I. Holub
+#ifndef MAME_SINCLAIR_SPECNEXT_COPPER_H
+#define MAME_SINCLAIR_SPECNEXT_COPPER_H
+
+#pragma once
+
+#include
+
+
+class specnext_copper_device : public device_t
+{
+
+public:
+ specnext_copper_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock);
+
+ auto out_nextreg_cb() { return m_out_nextreg_cb.bind(); }
+ template void set_in_until_pos_cb(T &&... args) { return m_in_until_pos_cb.set(std::forward(args)...); }
+
+ u8 data_r(u16 addr) { return m_listram[addr]; }
+ void data_w(u16 addr, u8 data);
+
+ void copper_en_w(u8 data);
+
+protected:
+ virtual void device_start() override;
+ virtual void device_reset() override;
+
+ TIMER_CALLBACK_MEMBER(timer_callback);
+ TIMER_CALLBACK_MEMBER(frame_timer_callback);
+
+ emu_timer *m_timer;
+ emu_timer *m_frame_timer;
+
+private:
+ memory_share_creator m_listram;
+
+ devcb_write8 m_out_nextreg_cb;
+ device_delegate m_in_until_pos_cb;
+
+ u8 m_copper_en; // u2
+ u16 m_copper_list_addr; // u10
+ u16 m_copper_list_data; // u16
+ bool m_copper_dout;
+};
+
+
+DECLARE_DEVICE_TYPE(SPECNEXT_COPPER, specnext_copper_device)
+
+#endif // MAME_SINCLAIR_SPECNEXT_COPPER_H
diff --git a/src/mame/sinclair/specnext_ctc.cpp b/src/mame/sinclair/specnext_ctc.cpp
new file mode 100644
index 00000000000..07492067010
--- /dev/null
+++ b/src/mame/sinclair/specnext_ctc.cpp
@@ -0,0 +1,26 @@
+// license:BSD-3-Clause
+// copyright-holders:Andrei I. Holub
+/**********************************************************************
+ Spectrum Next CTC
+**********************************************************************/
+
+#include "emu.h"
+#include "specnext_ctc.h"
+
+
+// device type definition
+DEFINE_DEVICE_TYPE(SPECNEXT_CTC, specnext_ctc_device, "specnext_ctc", "Spectrum Next CTC")
+
+
+specnext_ctc_device::specnext_ctc_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock)
+ : z80ctc_device(mconfig, SPECNEXT_CTC, tag, owner, clock)
+{
+}
+
+int specnext_ctc_device::z80daisy_irq_ack()
+{
+ int const channel = (z80ctc_device::z80daisy_irq_ack() - m_vector) / 2;
+ return ((channel > 0) || (channel_int_state(0) == Z80_DAISY_IEO))
+ ? (m_vector + (channel + 3) * 2)
+ : m_vector;
+}
diff --git a/src/mame/sinclair/specnext_ctc.h b/src/mame/sinclair/specnext_ctc.h
new file mode 100644
index 00000000000..27cdb0399ff
--- /dev/null
+++ b/src/mame/sinclair/specnext_ctc.h
@@ -0,0 +1,23 @@
+// license:BSD-3-Clause
+// copyright-holders:Andrei I. Holub
+#ifndef MAME_SINCLAIR_SPECNEXT_CTC_H
+#define MAME_SINCLAIR_SPECNEXT_CTC_H
+
+#pragma once
+
+#include "machine/z80ctc.h"
+
+class specnext_ctc_device : public z80ctc_device
+{
+
+public:
+ specnext_ctc_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock);
+
+protected:
+ virtual int z80daisy_irq_ack() override;
+
+};
+
+DECLARE_DEVICE_TYPE(SPECNEXT_CTC, specnext_ctc_device)
+
+#endif // MAME_SINCLAIR_SPECNEXT_CTC_H
diff --git a/src/mame/sinclair/specnext_dma.cpp b/src/mame/sinclair/specnext_dma.cpp
new file mode 100644
index 00000000000..863c81f8690
--- /dev/null
+++ b/src/mame/sinclair/specnext_dma.cpp
@@ -0,0 +1,118 @@
+// license:BSD-3-Clause
+// copyright-holders:Andrei I. Holub
+/**********************************************************************
+ Spectrum Next DMA
+
+ Spectrum Next DMA operates in two mode: z80dma compatible and
+ N-mode with Next specific fixes.
+
+ z80dma mode is implemented there based on intensive testing of
+ the device. Potentially any mismatches not related to N-mode
+ covered here must be moved to the z80dma parent.
+
+**********************************************************************/
+
+#include "emu.h"
+#include "specnext_dma.h"
+
+// device type definition
+DEFINE_DEVICE_TYPE(SPECNEXT_DMA, specnext_dma_device, "specnext_dma", "Spectrum Next DMA")
+
+
+// TODO: this stuff is copy/pasted from machine/z80dma.cpp - ideally it wouldn't need to be
+#define WR0 REG(0, 0)
+#define WR1 REG(1, 0)
+#define WR2 REG(2, 0)
+
+#define PORTA_INC (WR1 & 0x10)
+#define PORTB_INC (WR2 & 0x10)
+#define PORTA_FIXED (((WR1 >> 4) & 0x02) == 0x02)
+#define PORTB_FIXED (((WR2 >> 4) & 0x02) == 0x02)
+
+#define TRANSFER_MODE (WR0 & 0x03)
+
+
+specnext_dma_device::specnext_dma_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock)
+ : z80dma_device(mconfig, SPECNEXT_DMA, tag, owner, clock)
+{
+}
+
+int specnext_dma_device::is_ready()
+{
+ return is_dma_enabled() || z80dma_device::is_ready();
+}
+
+void specnext_dma_device::write(u8 data)
+{
+ z80dma_device::write(data);
+
+ if (num_follow() == 0)
+ {
+ if ((data & 0x83) == 0x83) // WR6
+ {
+ switch (data)
+ {
+ case COMMAND_ENABLE_DMA:
+ m_byte_counter = 0;
+ break;
+ default:
+ break;
+ }
+ }
+ }
+}
+
+void specnext_dma_device::do_write()
+{
+ if (m_dma_mode)
+ {
+ z80dma_device::do_write();
+ return;
+ }
+ // else (zxnDMA)
+
+ if (m_byte_counter)
+ m_addressB += PORTB_FIXED ? 0 : PORTB_INC ? 1 : -1;
+
+ u8 const mode = TRANSFER_MODE;
+ switch (mode)
+ {
+ case TM_TRANSFER:
+ do_transfer_write();
+ break;
+
+ case TM_SEARCH:
+ do_search();
+ break;
+
+ case TM_SEARCH_TRANSFER:
+ do_transfer_write();
+ do_search();
+ break;
+
+ default:
+ logerror("z80dma_do_operation: invalid mode %d!\n", mode);
+ break;
+ }
+
+ m_addressA += PORTA_FIXED ? 0 : PORTA_INC ? 1 : -1;
+
+ m_byte_counter++;
+ if ((m_byte_counter + 1) == m_count)
+ m_byte_counter++;
+}
+
+
+void specnext_dma_device::device_start()
+{
+ z80dma_device::device_start();
+
+ save_item(NAME(m_dma_mode));
+}
+
+void specnext_dma_device::device_reset()
+{
+ z80dma_device::device_reset();
+
+ m_dma_mode = 0;
+}
diff --git a/src/mame/sinclair/specnext_dma.h b/src/mame/sinclair/specnext_dma.h
new file mode 100644
index 00000000000..c1c9891e402
--- /dev/null
+++ b/src/mame/sinclair/specnext_dma.h
@@ -0,0 +1,32 @@
+// license:BSD-3-Clause
+// copyright-holders:Andrei I. Holub
+#ifndef MAME_SINCLAIR_SPECNEXT_DMA_H
+#define MAME_SINCLAIR_SPECNEXT_DMA_H
+
+#pragma once
+
+#include "machine/z80dma.h"
+
+class specnext_dma_device : public z80dma_device
+{
+public:
+ specnext_dma_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock);
+
+ void dma_mode_w(bool dma_mode) { m_dma_mode = dma_mode; }
+
+ virtual void write(u8 data) override;
+
+protected:
+ virtual void device_start() override;
+ virtual void device_reset() override;
+
+ virtual int is_ready() override;
+ virtual void do_write() override;
+
+private:
+ bool m_dma_mode; // 0 = zxn dma, 1 = z80 dma
+};
+
+DECLARE_DEVICE_TYPE(SPECNEXT_DMA, specnext_dma_device)
+
+#endif // MAME_SINCLAIR_SPECNEXT_DMA_H
diff --git a/src/mame/sinclair/specnext_multiface.cpp b/src/mame/sinclair/specnext_multiface.cpp
new file mode 100644
index 00000000000..75f22236037
--- /dev/null
+++ b/src/mame/sinclair/specnext_multiface.cpp
@@ -0,0 +1,114 @@
+// license:BSD-3-Clause
+// copyright-holders:Andrei I. Holub
+/**********************************************************************
+ Spectrum Next Multiface
+**********************************************************************/
+
+#include "emu.h"
+#include "specnext_multiface.h"
+
+
+// device type definition
+DEFINE_DEVICE_TYPE(SPECNEXT_MULTIFACE, specnext_multiface_device, "specnext_multiface", "Spectrum Next Multiface")
+
+
+specnext_multiface_device::specnext_multiface_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock)
+ : device_t(mconfig, SPECNEXT_MULTIFACE, tag, owner, clock)
+{
+}
+
+
+bool specnext_multiface_device::mode_48()
+{
+ return m_mf_mode == 0b11;
+}
+
+bool specnext_multiface_device::mode_128()
+{
+ return !(mode_p3() || mode_48());
+}
+
+bool specnext_multiface_device::mode_p3()
+{
+ return m_mf_mode == 0b00;
+}
+
+bool specnext_multiface_device::button_pulse()
+{
+ return m_button && !m_nmi_active;
+}
+
+bool specnext_multiface_device::invisible_eff()
+{
+ return m_invisible && !mode_48();
+}
+
+bool specnext_multiface_device::fetch_66()
+{
+ return m_cpu_a_0066 && !m_cpu_m1_n && m_nmi_active;
+}
+
+bool specnext_multiface_device::mf_enable_eff()
+{
+ return m_mf_enable || fetch_66();
+}
+
+void specnext_multiface_device::clock_w()
+{
+ // Rising edge
+ bool port_io_dly = m_port_mf_enable_rd || m_port_mf_enable_wr || m_port_mf_disable_rd || m_port_mf_disable_wr;
+
+ if (button_pulse())
+ m_invisible = 0;
+ else if (((m_port_mf_disable_wr && !mode_p3()) || (m_port_mf_enable_wr && mode_p3())) && !port_io_dly)
+ m_invisible = 1;
+
+ if (button_pulse())
+ m_nmi_active = 1;
+ else if (m_cpu_retn_seen || ((m_port_mf_enable_wr || m_port_mf_disable_wr || (m_port_mf_disable_rd && mode_p3())) && !port_io_dly))
+ m_nmi_active = 0;
+
+ if (fetch_66() && !m_cpu_mreq_n)
+ m_mf_enable = 1;
+ else if (m_port_mf_disable_rd || m_cpu_retn_seen)
+ m_mf_enable = 0;
+ else if (m_port_mf_enable_rd)
+ m_mf_enable = !invisible_eff();
+}
+
+void specnext_multiface_device::device_start()
+{
+ save_item(NAME(m_cpu_a_0066));
+ save_item(NAME(m_cpu_mreq_n));
+ save_item(NAME(m_cpu_m1_n));
+ save_item(NAME(m_cpu_retn_seen));
+ save_item(NAME(m_enable));
+ save_item(NAME(m_button));
+ save_item(NAME(m_mf_mode));
+ save_item(NAME(m_port_mf_enable_rd));
+ save_item(NAME(m_port_mf_enable_wr));
+ save_item(NAME(m_port_mf_disable_rd));
+ save_item(NAME(m_port_mf_disable_wr));
+ save_item(NAME(m_nmi_active));
+ save_item(NAME(m_invisible));
+ save_item(NAME(m_mf_enable));
+}
+
+void specnext_multiface_device::device_reset()
+{
+ m_cpu_a_0066 = 0;
+ m_cpu_mreq_n = 0;;
+ m_cpu_m1_n = 1;
+ m_cpu_retn_seen = 0;
+ m_enable = 1;
+ m_button = 0;
+ m_mf_mode = 0;
+ m_port_mf_enable_rd = 0;
+ m_port_mf_enable_wr = 0;
+ m_port_mf_disable_rd = 0;
+ m_port_mf_disable_wr = 0;
+
+ m_nmi_active = 0;
+ m_invisible = 1;
+ m_mf_enable = 0;
+}
diff --git a/src/mame/sinclair/specnext_multiface.h b/src/mame/sinclair/specnext_multiface.h
new file mode 100644
index 00000000000..f01d117b4e1
--- /dev/null
+++ b/src/mame/sinclair/specnext_multiface.h
@@ -0,0 +1,75 @@
+// license:BSD-3-Clause
+// copyright-holders:Andrei I. Holub
+#ifndef MAME_SINCLAIR_SPECNEXT_MULTIFACE_H
+#define MAME_SINCLAIR_SPECNEXT_MULTIFACE_H
+
+#pragma once
+
+class specnext_multiface_device : public device_t
+{
+public:
+ specnext_multiface_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock);
+
+ void cpu_a_0066_w(bool data) { m_cpu_a_0066 = data; }
+
+ void cpu_mreq_n_w(bool data) { m_cpu_mreq_n = data; }
+ void cpu_m1_n_w(bool data) { m_cpu_m1_n = data; }
+ void cpu_retn_seen_w(bool data) { m_cpu_retn_seen = data; }
+
+ void enable_w(bool data) { m_enable = data; }
+ void button_w(bool data) { m_button = data; }
+
+ void mf_mode_w(u8 data) { m_mf_mode = data; }
+
+ void port_mf_enable_rd_w(bool data) { m_port_mf_enable_rd = data; }
+ void port_mf_enable_wr_w(bool data) { m_port_mf_enable_wr = data; }
+ void port_mf_disable_rd_w(bool data) { m_port_mf_disable_rd = data; }
+ void port_mf_disable_wr_w(bool data) { m_port_mf_disable_wr = data; }
+
+ bool nmi_disable_r() { return m_enable && m_nmi_active; };
+ bool mf_enabled_r() { return m_enable && mf_enable_eff(); };
+ bool mf_port_en_r() { return m_enable && (m_port_mf_enable_rd && !invisible_eff() && (mode_128() || mode_p3())); };
+
+ void clock_w(); // called on active clock edge
+
+protected:
+ virtual void device_start() override;
+ virtual void device_reset() override;
+
+private:
+ // in
+ bool m_cpu_a_0066;
+ bool m_cpu_mreq_n;
+ bool m_cpu_m1_n;
+ bool m_cpu_retn_seen;
+
+ bool m_enable;
+ bool m_button;
+
+ u8 m_mf_mode; // u2: 00 = mf +3, 11 = mf 48, else mf 128
+
+ bool m_port_mf_enable_rd;
+ bool m_port_mf_enable_wr;
+ bool m_port_mf_disable_rd;
+ bool m_port_mf_disable_wr;
+
+ // internal
+ bool m_nmi_active;
+ bool m_invisible;
+ bool m_mf_enable;
+
+ // signal
+ bool mode_48();
+ bool mode_128();
+ bool mode_p3();
+
+ bool button_pulse();
+ bool invisible_eff();
+ bool fetch_66();
+ bool mf_enable_eff();
+};
+
+
+DECLARE_DEVICE_TYPE(SPECNEXT_MULTIFACE, specnext_multiface_device)
+
+#endif // MAME_SINCLAIR_SPECNEXT_MULTIFACE_H
diff --git a/src/mame/sinclair/sprinter.cpp b/src/mame/sinclair/sprinter.cpp
index 3c509da368c..3fdc45ed751 100644
--- a/src/mame/sinclair/sprinter.cpp
+++ b/src/mame/sinclair/sprinter.cpp
@@ -122,7 +122,7 @@ class sprinter_state : public spectrum_128_state
void update_memory();
void update_cpu();
- TIMER_CALLBACK_MEMBER(irq_on) override;
+ virtual TIMER_CALLBACK_MEMBER(irq_on) override;
TIMER_CALLBACK_MEMBER(cbl_tick);
u32 screen_update(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect);
diff --git a/src/mame/sinclair/tsconf.h b/src/mame/sinclair/tsconf.h
index 34ce5cd5df9..c247d6ce87d 100644
--- a/src/mame/sinclair/tsconf.h
+++ b/src/mame/sinclair/tsconf.h
@@ -51,11 +51,11 @@ class tsconf_state : public spectrum_128_state
static constexpr u16 with_vblank(u16 pixclocks) { return 32 + pixclocks; }
protected:
- void video_start() override;
- void machine_start() override;
- void machine_reset() override;
+ virtual void video_start() override;
+ virtual void machine_start() override;
+ virtual void machine_reset() override;
- TIMER_CALLBACK_MEMBER(irq_off) override;
+ virtual TIMER_CALLBACK_MEMBER(irq_off) override;
TIMER_CALLBACK_MEMBER(irq_frame);
TIMER_CALLBACK_MEMBER(irq_scanline);
@@ -149,10 +149,10 @@ class tsconf_state : public spectrum_128_state
template
TILE_GET_INFO_MEMBER(get_tile_info_16c);
- u8 get_border_color(u16 hpos = ~0, u16 vpos = ~0) override;
+ virtual u8 get_border_color(u16 hpos = ~0, u16 vpos = ~0) override;
u32 get_vpage_offset();
- rectangle get_screen_area() override;
- void spectrum_update_screen(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect) override;
+ virtual rectangle get_screen_area() override;
+ virtual void spectrum_update_screen(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect) override;
void tsconf_UpdateZxScreenBitmap(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect);
void tsconf_UpdateTxtBitmap(bitmap_ind16 &bitmap, const rectangle &cliprect);
void tsconf_UpdateGfxBitmap(bitmap_ind16 &bitmap, const rectangle &cliprect);
diff --git a/src/mame/sinclair/tsconf_m.cpp b/src/mame/sinclair/tsconf_m.cpp
index 76de0e2bd42..3c15f870f27 100644
--- a/src/mame/sinclair/tsconf_m.cpp
+++ b/src/mame/sinclair/tsconf_m.cpp
@@ -395,20 +395,20 @@ void tsconf_state::cram_write(u16 offset, u8 data)
u8 pen = dest >> 1;
rgb_t rgb = from_pwm((m_cram->read(dest | 1) << 8 | m_cram->read(dest & 0x1fe)));
m_palette->set_pen_color(pen, rgb);
-};
+}
void tsconf_state::cram_write16(offs_t offset, u16 data)
{
cram_write(offset & 0x1fe, data >> 8);
cram_write(offset | 1, data & 0xff);
-};
+}
void tsconf_state::sfile_write16(offs_t offset, u16 data)
{
u16 dest = offset & 0x1fe;
m_sfile->write(dest, data >> 8);
m_sfile->write(dest | 1, data & 0xff);
-};
+}
u8 tsconf_state::tsconf_port_xx1f_r(offs_t offset) {
return m_beta->started() && m_beta->is_active()