2020-02-28 16:04:28 +00:00
/*
DingusPPC - The Experimental PowerPC Macintosh emulator
2023-09-30 19:34:47 +00:00
Copyright ( C ) 2018 - 24 divingkatae and maximum
2020-02-28 16:04:28 +00:00
( theweirdo ) spatium
( Contact divingkatae # 1017 or powermax # 2286 on Discord for more info )
This program is free software : you can redistribute it and / or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation , either version 3 of the License , or
( at your option ) any later version .
This program is distributed in the hope that it will be useful ,
but WITHOUT ANY WARRANTY ; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the
GNU General Public License for more details .
You should have received a copy of the GNU General Public License
along with this program . If not , see < https : //www.gnu.org/licenses/>.
*/
2020-01-05 17:38:32 +00:00
2021-10-23 18:17:47 +00:00
# include <cpu/ppc/ppcemu.h>
2022-07-15 18:52:13 +00:00
# include <devices/deviceregistry.h>
2022-12-07 21:36:25 +00:00
# include <devices/common/ata/idechannel.h>
2021-10-23 18:17:47 +00:00
# include <devices/common/dbdma.h>
2022-01-26 15:45:21 +00:00
# include <devices/common/hwcomponent.h>
2021-10-23 18:17:47 +00:00
# include <devices/common/viacuda.h>
2021-12-12 20:40:04 +00:00
# include <devices/floppy/swim3.h>
2021-10-23 18:17:47 +00:00
# include <devices/ioctrl/macio.h>
2021-10-25 20:19:27 +00:00
# include <devices/serial/escc.h>
2021-10-23 18:17:47 +00:00
# include <devices/sound/awacs.h>
2021-11-09 12:41:48 +00:00
# include <endianswap.h>
2021-10-24 22:26:02 +00:00
# include <loguru.hpp>
2021-10-23 18:17:47 +00:00
# include <machines/machinebase.h>
2020-05-12 18:55:45 +00:00
# include <cinttypes>
2021-10-04 22:26:43 +00:00
# include <functional>
2021-10-24 22:26:02 +00:00
# include <memory>
2019-08-23 21:34:19 +00:00
2019-10-07 01:18:18 +00:00
/** Heathrow Mac I/O device emulation.
2021-10-04 22:26:43 +00:00
Author : Max Poliakovski
2019-10-07 01:18:18 +00:00
*/
2019-08-23 21:34:19 +00:00
using namespace std ;
2022-03-13 20:00:16 +00:00
HeathrowIC : : HeathrowIC ( ) : PCIDevice ( " mac-io/heathrow " ) , InterruptCtrl ( )
{
2022-12-23 16:10:05 +00:00
supports_types ( HWCompType : : MMIO_DEV | HWCompType : : PCI_DEV | HWCompType : : INT_CTRL ) ;
2022-01-26 15:45:21 +00:00
2022-03-13 20:00:16 +00:00
// populate my PCI config header
this - > vendor_id = PCI_VENDOR_APPLE ;
this - > device_id = 0x0010 ;
this - > class_rev = 0xFF000001 ;
this - > cache_ln_sz = 8 ;
2023-02-04 16:57:46 +00:00
this - > setup_bars ( { { 0 , 0xFFF80000UL } } ) ; // declare 512Kb of memory-mapped I/O space
2022-03-13 20:00:16 +00:00
this - > pci_notify_bar_change = [ this ] ( int bar_num ) {
this - > notify_bar_change ( bar_num ) ;
} ;
2022-07-18 09:48:23 +00:00
// NVRAM connection
this - > nvram = dynamic_cast < NVram * > ( gMachineObj - > get_comp_by_name ( " NVRAM " ) ) ;
2020-03-14 14:39:34 +00:00
2022-07-18 09:48:23 +00:00
// connect Cuda
this - > viacuda = dynamic_cast < ViaCuda * > ( gMachineObj - > get_comp_by_name ( " ViaCuda " ) ) ;
2020-03-15 16:24:40 +00:00
2023-02-11 23:13:57 +00:00
// find appropriate sound chip, create a DMA output channel for sound,
// then wire everything together
2023-04-22 21:06:45 +00:00
this - > snd_codec = dynamic_cast < MacioSndCodec * > ( gMachineObj - > get_comp_by_type ( HWCompType : : SND_CODEC ) ) ;
2023-07-27 18:30:30 +00:00
this - > snd_out_dma = std : : unique_ptr < DMAChannel > ( new DMAChannel ( " snd_out " ) ) ;
2023-11-15 01:20:38 +00:00
this - > snd_out_dma - > register_dma_int ( this , this - > register_dma_int ( IntSrc : : DMA_DAVBUS_Tx ) ) ;
2023-02-11 23:13:57 +00:00
this - > snd_codec - > set_dma_out ( this - > snd_out_dma . get ( ) ) ;
2021-10-04 22:26:43 +00:00
this - > snd_out_dma - > set_callbacks (
2023-02-11 23:13:57 +00:00
std : : bind ( & AwacsScreamer : : dma_out_start , this - > snd_codec ) ,
std : : bind ( & AwacsScreamer : : dma_out_stop , this - > snd_codec )
2021-10-04 22:26:43 +00:00
) ;
2021-08-22 22:20:28 +00:00
2023-09-19 12:19:15 +00:00
// connect SCSI HW and the corresponding DMA channel
2023-12-11 07:05:16 +00:00
this - > mesh = dynamic_cast < MeshController * > ( gMachineObj - > get_comp_by_name ( " MeshHeathrow " ) ) ;
2023-09-30 19:34:47 +00:00
this - > mesh_dma = std : : unique_ptr < DMAChannel > ( new DMAChannel ( " mesh " ) ) ;
2022-06-13 21:15:48 +00:00
2022-10-08 23:51:54 +00:00
// connect IDE HW
2022-12-07 21:36:25 +00:00
this - > ide_0 = dynamic_cast < IdeChannel * > ( gMachineObj - > get_comp_by_name ( " Ide0 " ) ) ;
this - > ide_1 = dynamic_cast < IdeChannel * > ( gMachineObj - > get_comp_by_name ( " Ide1 " ) ) ;
2022-06-13 21:15:48 +00:00
2022-07-18 09:48:23 +00:00
// connect serial HW
this - > escc = dynamic_cast < EsccController * > ( gMachineObj - > get_comp_by_name ( " Escc " ) ) ;
2022-11-17 13:18:58 +00:00
// connect floppy disk HW and initialize its DMA channel
2022-07-18 09:48:23 +00:00
this - > swim3 = dynamic_cast < Swim3 : : Swim3Ctrl * > ( gMachineObj - > get_comp_by_name ( " Swim3 " ) ) ;
2023-07-27 18:30:30 +00:00
this - > floppy_dma = std : : unique_ptr < DMAChannel > ( new DMAChannel ( " floppy " ) ) ;
2022-11-17 13:18:58 +00:00
this - > swim3 - > set_dma_channel ( this - > floppy_dma . get ( ) ) ;
2023-09-18 23:57:45 +00:00
this - > floppy_dma - > register_dma_int ( this , this - > register_dma_int ( IntSrc : : DMA_SWIM3 ) ) ;
2022-07-20 18:08:37 +00:00
2023-07-07 23:25:25 +00:00
// connect Ethernet HW
2023-07-23 14:28:31 +00:00
this - > bmac = dynamic_cast < BigMac * > ( gMachineObj - > get_comp_by_type ( HWCompType : : ETHER_MAC ) ) ;
2023-07-27 18:30:30 +00:00
this - > enet_xmit_dma = std : : unique_ptr < DMAChannel > ( new DMAChannel ( " BmacTx " ) ) ;
this - > enet_rcv_dma = std : : unique_ptr < DMAChannel > ( new DMAChannel ( " BmacRx " ) ) ;
2023-07-07 23:25:25 +00:00
2022-07-20 18:08:37 +00:00
// set EMMO pin status (active low)
this - > emmo_pin = GET_BIN_PROP ( " emmo " ) ^ 1 ;
2019-08-27 12:14:12 +00:00
}
2022-03-13 20:00:16 +00:00
void HeathrowIC : : notify_bar_change ( int bar_num )
{
if ( bar_num ) // only BAR0 is supported
return ;
2019-08-23 21:34:19 +00:00
2022-03-13 20:00:16 +00:00
if ( this - > base_addr ! = ( this - > bars [ bar_num ] & 0xFFFFFFF0UL ) ) {
if ( this - > base_addr ) {
2023-02-13 00:51:28 +00:00
this - > host_instance - > pci_unregister_mmio_region ( this - > base_addr , 0x80000 , this ) ;
2019-08-23 21:34:19 +00:00
}
2022-03-13 20:00:16 +00:00
this - > base_addr = this - > bars [ 0 ] & 0xFFFFFFF0UL ;
this - > host_instance - > pci_register_mmio_region ( this - > base_addr , 0x80000 , this ) ;
LOG_F ( INFO , " %s: base address set to 0x%X " , this - > pci_name . c_str ( ) , this - > base_addr ) ;
2019-08-23 21:34:19 +00:00
}
}
2020-05-12 18:55:45 +00:00
uint32_t HeathrowIC : : dma_read ( uint32_t offset , int size ) {
switch ( offset > > 8 ) {
2023-09-19 12:19:15 +00:00
case MIO_OHARE_DMA_MESH :
2023-09-30 19:34:47 +00:00
if ( this - > mesh_dma )
return this - > mesh_dma - > reg_read ( offset & 0xFF , size ) ;
else
return 0 ;
2023-07-24 13:20:52 +00:00
case MIO_OHARE_DMA_FLOPPY :
2022-11-17 13:18:58 +00:00
return this - > floppy_dma - > reg_read ( offset & 0xFF , size ) ;
2023-09-21 22:11:19 +00:00
case MIO_OHARE_DMA_ETH_XMIT :
return this - > enet_xmit_dma - > reg_read ( offset & 0xFF , size ) ;
case MIO_OHARE_DMA_ETH_RCV :
return this - > enet_rcv_dma - > reg_read ( offset & 0xFF , size ) ;
2023-07-24 13:20:52 +00:00
case MIO_OHARE_DMA_AUDIO_OUT :
2022-11-17 13:18:58 +00:00
return this - > snd_out_dma - > reg_read ( offset & 0xFF , size ) ;
2020-03-18 16:34:03 +00:00
default :
LOG_F ( WARNING , " Unsupported DMA channel read, offset=0x%X " , offset ) ;
}
2022-11-17 13:18:58 +00:00
return 0 ;
2020-03-18 16:34:03 +00:00
}
2020-05-12 18:55:45 +00:00
void HeathrowIC : : dma_write ( uint32_t offset , uint32_t value , int size ) {
switch ( offset > > 8 ) {
2023-09-19 12:19:15 +00:00
case MIO_OHARE_DMA_MESH :
2023-09-30 19:34:47 +00:00
if ( this - > mesh_dma ) this - > mesh_dma - > reg_write ( offset & 0xFF , value , size ) ;
2023-09-19 12:19:15 +00:00
break ;
2023-07-24 13:20:52 +00:00
case MIO_OHARE_DMA_FLOPPY :
2022-11-17 13:18:58 +00:00
this - > floppy_dma - > reg_write ( offset & 0xFF , value , size ) ;
break ;
2023-09-21 22:11:19 +00:00
case MIO_OHARE_DMA_ETH_XMIT :
this - > enet_xmit_dma - > reg_write ( offset & 0xFF , value , size ) ;
break ;
case MIO_OHARE_DMA_ETH_RCV :
this - > enet_rcv_dma - > reg_write ( offset & 0xFF , value , size ) ;
break ;
2023-07-24 13:20:52 +00:00
case MIO_OHARE_DMA_AUDIO_OUT :
2020-03-18 16:34:03 +00:00
this - > snd_out_dma - > reg_write ( offset & 0xFF , value , size ) ;
break ;
default :
LOG_F ( WARNING , " Unsupported DMA channel write, offset=0x%X, val=0x%X " , offset , value ) ;
}
}
2022-08-22 10:16:31 +00:00
uint32_t HeathrowIC : : read ( uint32_t rgn_start , uint32_t offset , int size ) {
2019-08-27 12:14:12 +00:00
uint32_t res = 0 ;
2022-08-14 12:26:56 +00:00
LOG_F ( 9 , " %s: reading from offset %x " , this - > name . c_str ( ) , offset ) ;
2019-08-27 12:14:12 +00:00
2020-01-08 18:33:38 +00:00
unsigned sub_addr = ( offset > > 12 ) & 0x7F ;
2019-08-27 12:14:12 +00:00
2020-02-27 02:51:07 +00:00
switch ( sub_addr ) {
2019-08-27 12:14:12 +00:00
case 0 :
res = mio_ctrl_read ( offset , size ) ;
break ;
case 8 :
2020-03-18 16:34:03 +00:00
res = dma_read ( offset - 0x8000 , size ) ;
2019-08-27 12:14:12 +00:00
break ;
2023-07-07 23:25:25 +00:00
case 0x10 : // SCSI
2021-08-22 22:20:28 +00:00
res = this - > mesh - > read ( ( offset > > 4 ) & 0xF ) ;
break ;
2023-07-07 23:25:25 +00:00
case 0x11 : // Ethernet
res = BYTESWAP_SIZED ( this - > bmac - > read ( offset & 0xFFFU ) , size ) ;
break ;
2022-02-23 16:07:29 +00:00
case 0x12 : // ESCC compatible addressing
if ( ( offset & 0xFF ) < 16 ) {
2022-05-02 22:16:09 +00:00
return this - > escc - > read ( compat_to_macrisc [ ( offset > > 1 ) & 0xF ] ) ;
2022-02-23 16:07:29 +00:00
}
// fallthrough
case 0x13 : // ESCC MacRISC addressing
2021-10-25 20:19:27 +00:00
return this - > escc - > read ( ( offset > > 4 ) & 0xF ) ;
2019-08-27 12:14:12 +00:00
case 0x14 :
2023-02-11 23:13:57 +00:00
res = this - > snd_codec - > snd_ctrl_read ( offset - 0x14000 , size ) ;
2019-08-27 12:14:12 +00:00
break ;
2021-12-12 20:40:04 +00:00
case 0x15 : // SWIM3
2022-06-13 21:15:48 +00:00
return this - > swim3 - > read ( ( offset > > 4 ) & 0xF ) ;
2022-12-07 21:36:25 +00:00
case 0x16 : // VIA-CUDA
2019-08-27 12:14:12 +00:00
case 0x17 :
res = this - > viacuda - > read ( ( offset - 0x16000 ) > > 9 ) ;
break ;
2022-12-07 21:36:25 +00:00
case 0x20 : // IDE 0
res = this - > ide_0 - > read ( ( offset > > 4 ) & 0x1F , size ) ;
2022-12-05 15:42:51 +00:00
break ;
2022-12-07 21:36:25 +00:00
case 0x21 : // IDE 1
res = this - > ide_1 - > read ( ( offset > > 4 ) & 0x1F , size ) ;
2022-10-08 23:51:54 +00:00
break ;
2019-08-27 12:14:12 +00:00
default :
2020-01-08 18:33:38 +00:00
if ( sub_addr > = 0x60 ) {
res = this - > nvram - > read_byte ( ( offset - 0x60000 ) > > 4 ) ;
2020-05-12 18:55:45 +00:00
} else {
2023-07-23 06:25:47 +00:00
LOG_F ( WARNING , " Attempting to read from unmapped I/O space: %x " , offset ) ;
2020-01-08 18:33:38 +00:00
}
2019-08-27 12:14:12 +00:00
}
return res ;
2019-08-23 21:34:19 +00:00
}
2022-08-22 10:16:31 +00:00
void HeathrowIC : : write ( uint32_t rgn_start , uint32_t offset , uint32_t value , int size ) {
2022-08-14 12:26:56 +00:00
LOG_F ( 9 , " %s: writing to offset %x " , this - > name . c_str ( ) , offset ) ;
2019-08-27 12:14:12 +00:00
2020-01-08 18:33:38 +00:00
unsigned sub_addr = ( offset > > 12 ) & 0x7F ;
2019-08-27 12:14:12 +00:00
2020-02-27 02:51:07 +00:00
switch ( sub_addr ) {
2019-08-27 12:14:12 +00:00
case 0 :
mio_ctrl_write ( offset , value , size ) ;
break ;
case 8 :
2020-03-18 16:34:03 +00:00
dma_write ( offset - 0x8000 , value , size ) ;
2019-08-27 12:14:12 +00:00
break ;
2023-07-07 23:25:25 +00:00
case 0x10 : // SCSI
2021-08-22 22:20:28 +00:00
this - > mesh - > write ( ( offset > > 4 ) & 0xF , value ) ;
break ;
2023-07-07 23:25:25 +00:00
case 0x11 : // Ethernet
this - > bmac - > write ( offset & 0xFFFU , BYTESWAP_SIZED ( value , size ) ) ;
break ;
2022-02-23 16:07:29 +00:00
case 0x12 : // ESCC compatible addressing
if ( ( offset & 0xFF ) < 16 ) {
2022-05-02 22:16:09 +00:00
this - > escc - > write ( compat_to_macrisc [ ( offset > > 1 ) & 0xF ] , value ) ;
2022-02-23 16:07:29 +00:00
break ;
}
// fallthrough
case 0x13 : // ESCC MacRISC addressing
2021-10-25 20:19:27 +00:00
this - > escc - > write ( ( offset > > 4 ) & 0xF , value ) ;
break ;
2019-08-27 12:14:12 +00:00
case 0x14 :
2023-02-11 23:13:57 +00:00
this - > snd_codec - > snd_ctrl_write ( offset - 0x14000 , value , size ) ;
2019-08-27 12:14:12 +00:00
break ;
2022-06-13 21:15:48 +00:00
case 0x15 : // SWIM3
this - > swim3 - > write ( ( offset > > 4 ) & 0xF , value ) ;
2021-12-12 20:40:04 +00:00
break ;
2022-12-07 21:36:25 +00:00
case 0x16 : // VIA-CUDA
2019-08-27 12:14:12 +00:00
case 0x17 :
this - > viacuda - > write ( ( offset - 0x16000 ) > > 9 , value ) ;
break ;
2022-12-07 21:36:25 +00:00
case 0x20 : // IDE O
this - > ide_0 - > write ( ( offset > > 4 ) & 0x1F , value , size ) ;
2022-12-05 15:42:51 +00:00
break ;
2022-12-07 21:36:25 +00:00
case 0x21 : // IDE 1
this - > ide_1 - > write ( ( offset > > 4 ) & 0x1F , value , size ) ;
2022-10-08 23:51:54 +00:00
break ;
2019-08-27 12:14:12 +00:00
default :
2020-01-08 18:33:38 +00:00
if ( sub_addr > = 0x60 ) {
this - > nvram - > write_byte ( ( offset - 0x60000 ) > > 4 , value ) ;
2020-05-12 18:55:45 +00:00
} else {
2023-07-23 06:25:47 +00:00
LOG_F ( WARNING , " Attempting to write to unmapped I/O space: %x " , offset ) ;
2020-01-08 18:33:38 +00:00
}
2019-08-27 12:14:12 +00:00
}
}
2020-05-12 18:55:45 +00:00
uint32_t HeathrowIC : : mio_ctrl_read ( uint32_t offset , int size ) {
2019-08-27 12:14:12 +00:00
uint32_t res = 0 ;
2021-01-08 22:29:43 +00:00
switch ( offset & 0xFC ) {
2022-03-14 17:09:11 +00:00
case MIO_INT_EVENTS2 :
res = this - > int_events2 ;
2020-04-19 18:28:51 +00:00
break ;
2022-03-14 17:09:11 +00:00
case MIO_INT_MASK2 :
res = this - > int_mask2 ;
2020-04-19 18:28:51 +00:00
break ;
2022-03-14 17:09:11 +00:00
case MIO_INT_LEVELS2 :
2020-04-19 18:28:51 +00:00
res = this - > int_levels2 ;
break ;
2022-03-14 17:09:11 +00:00
case MIO_INT_EVENTS1 :
res = this - > int_events1 ;
2019-08-27 12:14:12 +00:00
break ;
2022-03-14 17:09:11 +00:00
case MIO_INT_MASK1 :
res = this - > int_mask1 ;
2019-08-27 12:14:12 +00:00
break ;
2022-03-14 17:09:11 +00:00
case MIO_INT_LEVELS1 :
2020-04-19 18:28:51 +00:00
res = this - > int_levels1 ;
break ;
2023-04-22 20:53:20 +00:00
case MIO_INT_CLEAR1 :
case MIO_INT_CLEAR2 :
// some Mac OS drivers reads from those write-only registers
// so we return zero here as real HW does
break ;
2022-12-23 16:10:05 +00:00
case MIO_OHARE_ID :
2022-08-14 12:26:56 +00:00
LOG_F ( 9 , " read from MIO:ID register at Address %x " , ppc_state . pc ) ;
2022-07-20 18:08:37 +00:00
res = ( this - > fp_id < < 24 ) | ( this - > mon_id < < 16 ) | ( this - > mb_id < < 8 ) |
2022-08-08 19:06:57 +00:00
( this - > cpu_id | ( this - > emmo_pin < < 4 ) ) ;
2019-10-07 01:18:18 +00:00
break ;
2022-12-23 16:10:05 +00:00
case MIO_OHARE_FEAT_CTRL :
2022-08-14 12:26:56 +00:00
LOG_F ( 9 , " read from MIO:Feat_Ctrl register " ) ;
2022-03-14 17:09:11 +00:00
res = this - > feat_ctrl ;
2019-08-27 12:14:12 +00:00
break ;
default :
2022-08-14 12:26:56 +00:00
LOG_F ( WARNING , " read from unknown MIO register at %x " , offset ) ;
2019-08-27 12:14:12 +00:00
break ;
}
2022-03-14 17:09:11 +00:00
return BYTESWAP_32 ( res ) ;
2019-08-27 12:14:12 +00:00
}
2020-05-12 18:55:45 +00:00
void HeathrowIC : : mio_ctrl_write ( uint32_t offset , uint32_t value , int size ) {
2021-01-08 22:29:43 +00:00
switch ( offset & 0xFC ) {
2022-03-14 17:09:11 +00:00
case MIO_INT_MASK2 :
this - > int_mask2 | = BYTESWAP_32 ( value ) & ~ MACIO_INT_MODE ;
2020-04-19 18:28:51 +00:00
break ;
2022-03-14 17:09:11 +00:00
case MIO_INT_CLEAR2 :
2023-09-25 00:05:57 +00:00
this - > int_events2 & = ~ ( BYTESWAP_32 ( value ) & 0x7FFFFFFFUL ) ;
clear_cpu_int ( ) ;
2019-08-27 12:14:12 +00:00
break ;
2022-03-14 17:09:11 +00:00
case MIO_INT_MASK1 :
this - > int_mask1 = BYTESWAP_32 ( value ) ;
// copy IntMode bit to InterruptMask2 register
this - > int_mask2 = ( this - > int_mask2 & ~ MACIO_INT_MODE ) | ( this - > int_mask1 & MACIO_INT_MODE ) ;
2019-08-27 12:14:12 +00:00
break ;
2022-03-14 17:09:11 +00:00
case MIO_INT_CLEAR1 :
2023-09-25 00:05:57 +00:00
if ( ( this - > int_mask1 & MACIO_INT_MODE ) & & ( value & MACIO_INT_CLR ) ) {
2022-03-14 17:09:11 +00:00
this - > int_events1 = 0 ;
2023-09-25 00:05:57 +00:00
this - > int_events2 = 0 ;
2022-03-14 17:09:11 +00:00
} else {
2023-09-25 00:05:57 +00:00
this - > int_events1 & = ~ ( BYTESWAP_32 ( value ) & 0x7FFFFFFFUL ) ;
2022-03-14 17:09:11 +00:00
}
2023-09-25 00:05:57 +00:00
clear_cpu_int ( ) ;
2020-04-19 18:28:51 +00:00
break ;
2022-12-23 16:10:05 +00:00
case MIO_OHARE_ID :
2022-08-14 12:26:56 +00:00
LOG_F ( WARNING , " Attempted to write %x to MIO:ID at %x; Address : %x " , value , offset , ppc_state . pc ) ;
2021-01-08 22:29:43 +00:00
break ;
2022-12-23 16:10:05 +00:00
case MIO_OHARE_FEAT_CTRL :
2021-11-09 12:41:48 +00:00
this - > feature_control ( BYTESWAP_32 ( value ) ) ;
2019-08-27 12:14:12 +00:00
break ;
2024-03-23 03:08:57 +00:00
case MIO_AUX_CTRL :
2022-08-14 12:26:56 +00:00
LOG_F ( 9 , " write %x to MIO:Aux_Ctrl register " , value ) ;
2021-01-08 22:29:43 +00:00
this - > aux_ctrl = value ;
break ;
2019-08-27 12:14:12 +00:00
default :
2022-08-14 12:26:56 +00:00
LOG_F ( WARNING , " write %x to unknown MIO register at %x " , value , offset ) ;
2019-08-27 12:14:12 +00:00
break ;
}
2020-02-28 16:04:28 +00:00
}
2021-11-09 12:41:48 +00:00
void HeathrowIC : : feature_control ( const uint32_t value )
{
2022-08-14 12:26:56 +00:00
LOG_F ( 9 , " write %x to MIO:Feat_Ctrl register " , value ) ;
2021-11-09 12:41:48 +00:00
this - > feat_ctrl = value ;
if ( ! ( this - > feat_ctrl & 1 ) ) {
LOG_F ( 9 , " Heathrow: Monitor sense enabled " ) ;
} else {
LOG_F ( 9 , " Heathrow: Monitor sense disabled " ) ;
}
}
2022-03-13 20:00:16 +00:00
2023-09-18 23:57:45 +00:00
# define FIRST_INT1_BIT 12 // The first ten are DMA, the next 2 appear to be unused. We'll map 1:1 the INT1 bits 31..12 (0x1F..0x0C) as IRQ_ID bits.
# define FIRST_INT2_BIT 2 // Skip the first two which are Ethernet DMA. We'll map INT2 bits 13..2 (interrupts 45..34 or 0x2D..0x22) as IRQ_ID bits 11..0.
# define FIRST_INT1_IRQ_ID_BIT 12 // Same as INT1_BIT so there won't be any shifting required.
# define FIRST_INT2_IRQ_ID_BIT 0
# define INT1_TO_IRQ_ID(int1) (1 << (int1 - FIRST_INT1_BIT + FIRST_INT1_IRQ_ID_BIT))
# define INT2_TO_IRQ_ID(int2) (1 << (int2 - FIRST_INT2_BIT + FIRST_INT2_IRQ_ID_BIT - 32))
# define INT_TO_IRQ_ID(intx) (intx < 32 ? INT1_TO_IRQ_ID(intx) : INT2_TO_IRQ_ID(intx))
# define IS_INT1(irq_id) (irq_id >= 1 << FIRST_INT1_IRQ_ID_BIT)
# define IRQ_ID_TO_INT1_MASK(irq_id) (irq_id <<= (FIRST_INT1_BIT - FIRST_INT1_IRQ_ID_BIT))
# define IRQ_ID_TO_INT2_MASK(irq_id) (irq_id <<= (FIRST_INT2_BIT - FIRST_INT2_IRQ_ID_BIT))
2022-03-13 20:00:16 +00:00
uint32_t HeathrowIC : : register_dev_int ( IntSrc src_id )
{
2022-03-14 17:09:11 +00:00
switch ( src_id ) {
2023-09-18 23:57:45 +00:00
case IntSrc : : SCSI_MESH : return INT_TO_IRQ_ID ( 0x0C ) ;
case IntSrc : : IDE0 : return INT_TO_IRQ_ID ( 0x0D ) ;
case IntSrc : : IDE1 : return INT_TO_IRQ_ID ( 0x0E ) ;
case IntSrc : : SCCA : return INT_TO_IRQ_ID ( 0x0F ) ;
case IntSrc : : SCCB : return INT_TO_IRQ_ID ( 0x10 ) ;
case IntSrc : : DAVBUS : return INT_TO_IRQ_ID ( 0x11 ) ;
case IntSrc : : VIA_CUDA : return INT_TO_IRQ_ID ( 0x12 ) ;
case IntSrc : : SWIM3 : return INT_TO_IRQ_ID ( 0x13 ) ;
case IntSrc : : NMI : return INT_TO_IRQ_ID ( 0x14 ) ; // nmiSource in AppleHeathrow/Heathrow.cpp
case IntSrc : : PERCH2 : return INT_TO_IRQ_ID ( 0x15 ) ;
case IntSrc : : PCI_GPU : return INT_TO_IRQ_ID ( 0x16 ) ;
case IntSrc : : PCI_A : return INT_TO_IRQ_ID ( 0x17 ) ;
case IntSrc : : PCI_B : return INT_TO_IRQ_ID ( 0x18 ) ;
case IntSrc : : PCI_C : return INT_TO_IRQ_ID ( 0x19 ) ;
case IntSrc : : PERCH1 : return INT_TO_IRQ_ID ( 0x1A ) ;
case IntSrc : : PCI_PERCH : return INT_TO_IRQ_ID ( 0x1C ) ;
case IntSrc : : ETHERNET : return INT_TO_IRQ_ID ( 0x2A ) ;
2022-03-14 17:09:11 +00:00
default :
ABORT_F ( " Heathrow: unknown interrupt source %d " , src_id ) ;
}
2022-03-13 20:00:16 +00:00
return 0 ;
}
2023-09-18 23:57:45 +00:00
# define FIRST_DMA_INT1_BIT 0 // bit 0 is SCSI DMA
# define FIRST_DMA_INT2_BIT 0 // bit 0 is Ethernet DMA Tx
# define FIRST_DMA_INT1_IRQ_ID_BIT 0
# define FIRST_DMA_INT2_IRQ_ID_BIT 16 // There's only 10 INT1 DMA bits but we'll put INT2 DMA bits in the upper 16 bits
# define DMA_INT1_TO_IRQ_ID(int1) (1 << (int1 - FIRST_DMA_INT1_BIT + FIRST_DMA_INT1_IRQ_ID_BIT))
# define DMA_INT2_TO_IRQ_ID(int2) (1 << (int2 - FIRST_DMA_INT2_BIT + FIRST_DMA_INT2_IRQ_ID_BIT - 32))
# define DMA_INT_TO_IRQ_ID(intx) (intx < 32 ? DMA_INT1_TO_IRQ_ID(intx) : DMA_INT2_TO_IRQ_ID(intx))
# define IS_DMA_INT1(irq_id) (irq_id < 1 << FIRST_DMA_INT2_IRQ_ID_BIT)
# define DMA_IRQ_ID_TO_INT1_MASK(irq_id) (irq_id <<= (FIRST_DMA_INT1_BIT - FIRST_DMA_INT1_IRQ_ID_BIT))
# define DMA_IRQ_ID_TO_INT2_MASK(irq_id) (irq_id >>= (FIRST_DMA_INT2_IRQ_ID_BIT - FIRST_DMA_INT2_BIT))
2022-03-13 20:00:16 +00:00
uint32_t HeathrowIC : : register_dma_int ( IntSrc src_id )
{
2023-09-18 23:57:45 +00:00
switch ( src_id ) {
case IntSrc : : DMA_SCSI_MESH : return DMA_INT_TO_IRQ_ID ( 0x00 ) ;
case IntSrc : : DMA_SWIM3 : return DMA_INT_TO_IRQ_ID ( 0x01 ) ;
case IntSrc : : DMA_IDE0 : return DMA_INT_TO_IRQ_ID ( 0x02 ) ;
case IntSrc : : DMA_IDE1 : return DMA_INT_TO_IRQ_ID ( 0x03 ) ;
case IntSrc : : DMA_SCCA_Tx : return DMA_INT_TO_IRQ_ID ( 0x04 ) ;
case IntSrc : : DMA_SCCA_Rx : return DMA_INT_TO_IRQ_ID ( 0x05 ) ;
case IntSrc : : DMA_SCCB_Tx : return DMA_INT_TO_IRQ_ID ( 0x06 ) ;
case IntSrc : : DMA_SCCB_Rx : return DMA_INT_TO_IRQ_ID ( 0x07 ) ;
case IntSrc : : DMA_DAVBUS_Tx : return DMA_INT_TO_IRQ_ID ( 0x08 ) ;
case IntSrc : : DMA_DAVBUS_Rx : return DMA_INT_TO_IRQ_ID ( 0x09 ) ;
case IntSrc : : DMA_ETHERNET_Tx : return DMA_INT_TO_IRQ_ID ( 0x20 ) ;
case IntSrc : : DMA_ETHERNET_Rx : return DMA_INT_TO_IRQ_ID ( 0x21 ) ;
default :
ABORT_F ( " Heathrow: unknown DMA interrupt source %d " , src_id ) ;
}
2022-03-13 20:00:16 +00:00
return 0 ;
}
void HeathrowIC : : ack_int ( uint32_t irq_id , uint8_t irq_line_state )
{
2023-09-25 01:25:50 +00:00
# if 1
2023-09-18 23:57:45 +00:00
if ( ! IS_INT1 ( irq_id ) ) { // does this irq_id belong to the second set?
IRQ_ID_TO_INT2_MASK ( irq_id ) ;
#if 0
LOG_F ( INFO , " %s: native interrupt events:%08x.%08x levels:%08x.%08x change2:%08x state:%d " , this - > name . c_str ( ) , this - > int_events1 , this - > int_events2 , this - > int_levels1 , this - > int_levels2 , irq_id , irq_line_state ) ;
# endif
2023-09-25 01:25:50 +00:00
// native mode: set IRQ bits in int_events2 on a 0-to-1 transition
// emulated mode: set IRQ bits in int_events2 on all transitions
if ( ( this - > int_mask1 & MACIO_INT_MODE ) | |
( irq_line_state & & ! ( this - > int_levels2 & irq_id ) ) ) {
this - > int_events2 | = irq_id ;
} else {
this - > int_events2 & = ~ irq_id ;
}
this - > int_events2 & = this - > int_mask2 ;
// update IRQ line state
if ( irq_line_state ) {
this - > int_levels2 | = irq_id ;
} else {
this - > int_levels2 & = ~ irq_id ;
}
} else {
2023-09-18 23:57:45 +00:00
IRQ_ID_TO_INT1_MASK ( irq_id ) ;
2023-09-25 01:25:50 +00:00
// native mode: set IRQ bits in int_events1 on a 0-to-1 transition
// emulated mode: set IRQ bits in int_events1 on all transitions
2023-09-18 23:57:45 +00:00
#if 0
LOG_F ( INFO , " %s: native interrupt events:%08x.%08x levels:%08x.%08x change1:%08x state:%d " , this - > name . c_str ( ) , this - > int_events1 , this - > int_events2 , this - > int_levels1 , this - > int_levels2 , irq_id , irq_line_state ) ;
# endif
2023-09-25 01:25:50 +00:00
if ( ( this - > int_mask1 & MACIO_INT_MODE ) | |
( irq_line_state & & ! ( this - > int_levels1 & irq_id ) ) ) {
this - > int_events1 | = irq_id ;
} else {
this - > int_events1 & = ~ irq_id ;
}
this - > int_events1 & = this - > int_mask1 ;
// update IRQ line state
if ( irq_line_state ) {
this - > int_levels1 | = irq_id ;
} else {
this - > int_levels1 & = ~ irq_id ;
}
}
this - > signal_cpu_int ( ) ;
# endif
#if 0
2022-03-14 17:09:11 +00:00
if ( this - > int_mask1 & MACIO_INT_MODE ) { // 68k interrupt emulation mode?
2023-09-18 23:57:45 +00:00
if ( ! IS_INT1 ( irq_id ) ) {
IRQ_ID_TO_INT2_MASK ( irq_id ) ;
2022-03-14 17:09:11 +00:00
this - > int_events2 | = irq_id ; // signal IRQ line change
this - > int_events2 & = this - > int_mask2 ;
// update IRQ line state
if ( irq_line_state ) {
this - > int_levels2 | = irq_id ;
} else {
this - > int_levels2 & = ~ irq_id ;
}
} else {
2023-09-18 23:57:45 +00:00
IRQ_ID_TO_INT1_MASK ( irq_id ) ;
2022-03-14 17:09:11 +00:00
this - > int_events1 | = irq_id ; // signal IRQ line change
this - > int_events1 & = this - > int_mask1 ;
// update IRQ line state
if ( irq_line_state ) {
this - > int_levels1 | = irq_id ;
} else {
this - > int_levels1 & = ~ irq_id ;
}
}
2023-04-22 20:53:20 +00:00
this - > signal_cpu_int ( ) ;
2022-03-14 17:09:11 +00:00
} else {
2023-09-25 01:25:50 +00:00
LOG_F ( WARNING , " %s: native interrupt mode not implemented " , this - > name . c_str ( ) ) ;
2022-03-14 17:09:11 +00:00
}
2023-09-25 01:25:50 +00:00
# endif
2022-03-13 20:00:16 +00:00
}
void HeathrowIC : : ack_dma_int ( uint32_t irq_id , uint8_t irq_line_state )
{
2023-09-25 01:25:50 +00:00
# if 1
2023-09-18 23:57:45 +00:00
if ( ! IS_DMA_INT1 ( irq_id ) ) {
DMA_IRQ_ID_TO_INT2_MASK ( irq_id ) ;
2023-09-25 01:25:50 +00:00
// native mode: set IRQ bits in int_events2 on a 0-to-1 transition
// emulated mode: set IRQ bits in int_events2 on all transitions
if ( ( this - > int_mask1 & MACIO_INT_MODE ) | |
( irq_line_state & & ! ( this - > int_levels2 & irq_id ) ) ) {
this - > int_events2 | = irq_id ;
} else {
this - > int_events2 & = ~ irq_id ;
}
this - > int_events2 & = this - > int_mask2 ;
// update IRQ line state
if ( irq_line_state ) {
this - > int_levels2 | = irq_id ;
} else {
this - > int_levels2 & = ~ irq_id ;
}
} else {
2023-09-18 23:57:45 +00:00
DMA_IRQ_ID_TO_INT1_MASK ( irq_id ) ;
2023-09-25 01:25:50 +00:00
// native mode: set IRQ bits in int_events1 on a 0-to-1 transition
// emulated mode: set IRQ bits in int_events1 on all transitions
if ( ( this - > int_mask1 & MACIO_INT_MODE ) | |
( irq_line_state & & ! ( this - > int_levels1 & irq_id ) ) ) {
this - > int_events1 | = irq_id ;
} else {
this - > int_events1 & = ~ irq_id ;
}
this - > int_events1 & = this - > int_mask1 ;
// update IRQ line state
if ( irq_line_state ) {
this - > int_levels1 | = irq_id ;
} else {
this - > int_levels1 & = ~ irq_id ;
}
}
this - > signal_cpu_int ( ) ;
# endif
#if 0
2023-04-22 20:53:20 +00:00
if ( this - > int_mask1 & MACIO_INT_MODE ) { // 68k interrupt emulation mode?
2023-09-18 23:57:45 +00:00
if ( ! IS_DMA_INT1 ( irq_id ) ) {
DMA_IRQ_ID_TO_INT2_MASK ( irq_id ) ;
2023-09-25 00:05:57 +00:00
this - > int_events2 | = irq_id ; // signal IRQ line change
this - > int_events2 & = this - > int_mask2 ;
// update IRQ line state
if ( irq_line_state ) {
this - > int_levels2 | = irq_id ;
} else {
this - > int_levels2 & = ~ irq_id ;
}
2023-04-22 20:53:20 +00:00
} else {
2023-09-18 23:57:45 +00:00
DMA_IRQ_ID_TO_INT1_MASK ( irq_id ) ;
2023-09-25 00:05:57 +00:00
this - > int_events1 | = irq_id ; // signal IRQ line change
this - > int_events1 & = this - > int_mask1 ;
// update IRQ line state
if ( irq_line_state ) {
this - > int_levels1 | = irq_id ;
} else {
this - > int_levels1 & = ~ irq_id ;
}
2023-04-22 20:53:20 +00:00
}
this - > signal_cpu_int ( ) ;
} else {
ABORT_F ( " %s: native interrupt mode not implemented " , this - > name . c_str ( ) ) ;
}
2023-09-25 01:25:50 +00:00
# endif
2023-04-22 20:53:20 +00:00
}
void HeathrowIC : : signal_cpu_int ( ) {
if ( this - > int_events1 | | this - > int_events2 ) {
if ( ! this - > cpu_int_latch ) {
this - > cpu_int_latch = true ;
ppc_assert_int ( ) ;
} else {
LOG_F ( 5 , " %s: CPU INT already latched " , this - > name . c_str ( ) ) ;
}
}
2022-03-13 20:00:16 +00:00
}
2022-07-15 18:52:13 +00:00
2022-08-24 12:14:42 +00:00
void HeathrowIC : : clear_cpu_int ( )
{
if ( ! this - > int_events1 & & ! this - > int_events2 ) {
this - > cpu_int_latch = false ;
ppc_release_int ( ) ;
LOG_F ( 5 , " Heathrow: CPU INT latch cleared " ) ;
}
}
2022-07-15 18:52:13 +00:00
static const vector < string > Heathrow_Subdevices = {
2023-09-30 19:34:47 +00:00
" NVRAM " , " ViaCuda " , " ScsiMesh " , " MeshHeathrow " , " Escc " , " Swim3 " , " Ide0 " , " Ide1 " ,
2023-07-07 23:25:25 +00:00
" BigMacHeathrow "
} ;
2022-07-15 18:52:13 +00:00
static const DeviceDescription Heathrow_Descriptor = {
HeathrowIC : : create , Heathrow_Subdevices , { }
} ;
REGISTER_DEVICE ( Heathrow , Heathrow_Descriptor ) ;