2016-08-14 22:07:17 -04:00
/* Copyright holders: Greatpsycho
see COPYING for more details
*/
2016-06-26 00:34:39 +02:00
/*This is the chipset used in the Award 286 clone model*/
# include "ibm.h"
# include "io.h"
# include "scat.h"
# include "mem.h"
static uint8_t scat_regs [ 256 ] ;
static int scat_index ;
static uint8_t scat_port_92 = 0 ;
static uint8_t scat_ems_reg_2xA = 0 ;
static mem_mapping_t scat_mapping [ 32 ] ;
static mem_mapping_t scat_high_mapping [ 16 ] ;
static scat_t scat_stat [ 32 ] ;
static uint32_t scat_xms_bound ;
static mem_mapping_t scat_shadowram_mapping ;
static mem_mapping_t scat_512k_clip_mapping ;
void scat_shadow_state_update ( )
{
int i , val , val2 ;
// TODO - Segment A000 to BFFF shadow ram enable features and ROM enable features should be implemented later.
for ( i = 8 ; i < 24 ; i + + )
{
val = ( ( scat_regs [ SCAT_SHADOW_RAM_ENABLE_1 + ( i > > 3 ) ] > > ( i & 7 ) ) & 1 ) ? MEM_READ_INTERNAL : MEM_READ_EXTERNAL ;
if ( i < 8 )
{
val | = ( ( scat_regs [ SCAT_SHADOW_RAM_ENABLE_1 + ( i > > 3 ) ] > > ( i & 7 ) ) & 1 ) ? MEM_WRITE_INTERNAL : MEM_WRITE_EXTERNAL ;
}
else
{
if ( ( scat_regs [ SCAT_RAM_WRITE_PROTECT ] > > ( ( i - 8 ) > > 1 ) ) & 1 )
{
val | = MEM_WRITE_DISABLED ;
}
else
{
val | = ( ( scat_regs [ SCAT_SHADOW_RAM_ENABLE_1 + ( i > > 3 ) ] > > ( i & 7 ) ) & 1 ) ? MEM_WRITE_INTERNAL : MEM_WRITE_EXTERNAL ;
}
mem_set_mem_state ( ( i + 40 ) < < 14 , 0x4000 , val ) ;
}
}
flushmmucache ( ) ;
}
void scat_set_xms_bound ( uint8_t val )
{
uint32_t max_xms_size = ( mem_size > = 16384 ) ? 0xFC0000 : mem_size < < 10 ;
switch ( val )
{
case 1 :
scat_xms_bound = 0x100000 ;
break ;
case 2 :
scat_xms_bound = 0x140000 ;
break ;
case 3 :
scat_xms_bound = 0x180000 ;
break ;
case 4 :
scat_xms_bound = 0x200000 ;
break ;
case 5 :
scat_xms_bound = 0x300000 ;
break ;
case 6 :
scat_xms_bound = 0x400000 ;
break ;
case 7 :
scat_xms_bound = 0x600000 ;
break ;
case 8 :
scat_xms_bound = 0x800000 ;
break ;
case 9 :
scat_xms_bound = 0xA00000 ;
break ;
case 10 :
scat_xms_bound = 0xC00000 ;
break ;
case 11 :
scat_xms_bound = 0xE00000 ;
break ;
default :
scat_xms_bound = ( mem_size > = 16384 ? 0xFC0000 : mem_size < < 10 ) ;
break ;
}
if ( ( scat_regs [ SCAT_DRAM_CONFIGURATION ] & 0x0F ) = = 3 )
{
if ( val ! = 1 )
{
mem_mapping_enable ( & scat_shadowram_mapping ) ;
if ( val = = 0 )
scat_xms_bound = 0x160000 ;
}
else
{
mem_mapping_disable ( & scat_shadowram_mapping ) ;
}
pclog ( " Set XMS bound(%02X) = %06X(%dKbytes for EMS access) \n " , val , scat_xms_bound , ( 0x160000 - scat_xms_bound ) > > 10 ) ;
if ( scat_xms_bound > 0x100000 )
mem_set_mem_state ( 0x100000 , scat_xms_bound - 0x100000 , MEM_READ_INTERNAL | MEM_WRITE_INTERNAL ) ;
if ( scat_xms_bound < 0x160000 )
mem_set_mem_state ( scat_xms_bound , 0x160000 - scat_xms_bound , MEM_READ_EXTERNAL | MEM_WRITE_EXTERNAL ) ;
}
else
{
if ( scat_xms_bound > max_xms_size )
scat_xms_bound = max_xms_size ;
pclog ( " Set XMS bound(%02X) = %06X(%dKbytes for EMS access) \n " , val , scat_xms_bound , ( ( mem_size < < 10 ) - scat_xms_bound ) > > 10 ) ;
if ( scat_xms_bound > 0x100000 )
mem_set_mem_state ( 0x100000 , scat_xms_bound - 0x100000 , MEM_READ_INTERNAL | MEM_WRITE_INTERNAL ) ;
if ( scat_xms_bound < ( mem_size < < 10 ) )
mem_set_mem_state ( scat_xms_bound , ( mem_size < < 10 ) - scat_xms_bound , MEM_READ_EXTERNAL | MEM_WRITE_EXTERNAL ) ;
}
}
uint32_t get_scat_addr ( uint32_t addr , scat_t * p )
{
if ( p & & ( scat_regs [ SCAT_EMS_CONTROL ] & 0x80 ) & & ( p - > regs_2x9 & 0x80 ) )
{
addr = ( addr & 0x3fff ) | ( ( ( p - > regs_2x9 & 3 ) < < 8 ) | p - > regs_2x8 ) < < 14 ;
}
else if ( p = = NULL & & mem_size < 2048 & & ( ( scat_regs [ SCAT_DRAM_CONFIGURATION ] & 0x0F ) > 7 ) )
addr & = 0x7FFFF ;
if ( ( scat_regs [ SCAT_EXTENDED_BOUNDARY ] & 0x40 ) = = 0 & & ( scat_regs [ SCAT_DRAM_CONFIGURATION ] & 0x0F ) = = 3 & & addr > = 0x100000 )
addr - = 0x60000 ;
return addr ;
}
void scat_write ( uint16_t port , uint8_t val , void * priv )
{
uint8_t scat_reg_valid = 0 , scat_shadow_update = 0 , index ;
uint32_t base_addr , virt_addr ;
switch ( port )
{
case 0x22 :
scat_index = val ;
break ;
case 0x23 :
switch ( scat_index )
{
case SCAT_CLOCK_CONTROL :
case SCAT_PERIPHERAL_CONTROL :
case SCAT_EMS_CONTROL :
scat_reg_valid = 1 ;
break ;
case SCAT_POWER_MANAGEMENT :
val & = 0x40 ; // TODO - Only use AUX parity disable bit for this version. Other bits should be implemented later.
scat_reg_valid = 1 ;
break ;
case SCAT_DRAM_CONFIGURATION :
if ( ( scat_regs [ SCAT_EXTENDED_BOUNDARY ] & 0x40 ) = = 0 )
{
if ( ( val & 0x0F ) = = 3 )
{
mem_mapping_enable ( & scat_shadowram_mapping ) ;
}
else
{
mem_mapping_disable ( & scat_shadowram_mapping ) ;
}
if ( mem_size < 2048 )
{
if ( ( val & 0x0F ) > 7 ) mem_mapping_enable ( & scat_512k_clip_mapping ) ;
else mem_mapping_disable ( & scat_512k_clip_mapping ) ;
}
}
flushmmucache ( ) ;
scat_reg_valid = 1 ;
break ;
case SCAT_EXTENDED_BOUNDARY :
scat_set_xms_bound ( val & 0x0f ) ;
mem_set_mem_state ( 0x40000 , 0x60000 , ( val & 0x20 ) ? MEM_READ_EXTERNAL | MEM_WRITE_EXTERNAL : MEM_READ_INTERNAL | MEM_WRITE_INTERNAL ) ;
flushmmucache ( ) ;
scat_reg_valid = 1 ;
break ;
case SCAT_ROM_ENABLE :
case SCAT_RAM_WRITE_PROTECT :
case SCAT_SHADOW_RAM_ENABLE_1 :
case SCAT_SHADOW_RAM_ENABLE_2 :
case SCAT_SHADOW_RAM_ENABLE_3 :
scat_reg_valid = 1 ;
scat_shadow_update = 1 ;
break ;
default :
break ;
}
if ( scat_reg_valid )
scat_regs [ scat_index ] = val ;
if ( scat_shadow_update )
scat_shadow_state_update ( ) ;
pclog ( " Write SCAT Register %02X to %02X at %04X:%04X \n " , scat_index , val , CS , cpu_state . pc ) ;
break ;
case 0x92 :
if ( ( mem_a20_alt ^ val ) & 2 )
{
mem_a20_alt = val & 2 ;
mem_a20_recalc ( ) ;
}
if ( ( ~ scat_port_92 & val ) & 1 )
{
softresetx86 ( ) ;
}
scat_port_92 = val ;
break ;
case 0x208 :
if ( ( scat_regs [ SCAT_EMS_CONTROL ] & 0x41 ) = = 0x40 )
{
pclog ( " Write SCAT EMS Control Port %04X to %02X at %04X:%04X \n " , port , val , CS , cpu_state . pc ) ;
index = scat_ems_reg_2xA & 0x1F ;
scat_stat [ index ] . regs_2x8 = val ;
}
break ;
case 0x209 :
if ( ( scat_regs [ SCAT_EMS_CONTROL ] & 0x41 ) = = 0x40 )
{
pclog ( " Write SCAT EMS Control Port %04X to %02X at %04X:%04X \n " , port , val , CS , cpu_state . pc ) ;
index = scat_ems_reg_2xA & 0x1F ;
scat_stat [ index ] . regs_2x9 = val ;
base_addr = ( index + 16 ) < < 14 ;
if ( index > = 24 )
base_addr + = 0x30000 ;
if ( val & 0x80 )
{
virt_addr = ( ( ( scat_stat [ index ] . regs_2x9 & 3 ) < < 8 ) | scat_stat [ index ] . regs_2x8 ) < < 14 ;
mem_mapping_enable ( & scat_mapping [ index ] ) ;
mem_mapping_set_exec ( & scat_mapping [ index ] , ram + get_scat_addr ( virt_addr , & scat_stat [ index ] ) ) ;
pclog ( " Map page %d(address %05X) to address %06X \n " , scat_ems_reg_2xA & 0x1f , base_addr , virt_addr ) ;
}
else
{
mem_mapping_disable ( & scat_mapping [ index ] ) ;
pclog ( " Unmap page %d(address %06X) \n " , scat_ems_reg_2xA & 0x1f , base_addr ) ;
}
if ( scat_ems_reg_2xA & 0x80 )
{
scat_ems_reg_2xA = ( scat_ems_reg_2xA & 0xe0 ) | ( ( scat_ems_reg_2xA + 1 ) & 0x1f ) ;
}
}
break ;
case 0x20A :
if ( ( scat_regs [ SCAT_EMS_CONTROL ] & 0x41 ) = = 0x40 )
{
pclog ( " Write SCAT EMS Control Port %04X to %02X at %04X:%04X \n " , port , val , CS , cpu_state . pc ) ;
scat_ems_reg_2xA = val ;
}
break ;
case 0x218 :
if ( ( scat_regs [ SCAT_EMS_CONTROL ] & 0x41 ) = = 0x41 )
{
pclog ( " Write SCAT EMS Control Port %04X to %02X at %04X:%04X \n " , port , val , CS , cpu_state . pc ) ;
index = scat_ems_reg_2xA & 0x1F ;
scat_stat [ index ] . regs_2x8 = val ;
}
break ;
case 0x219 :
if ( ( scat_regs [ SCAT_EMS_CONTROL ] & 0x41 ) = = 0x41 )
{
pclog ( " Write SCAT EMS Control Port %04X to %02X at %04X:%04X \n " , port , val , CS , cpu_state . pc ) ;
index = scat_ems_reg_2xA & 0x1F ;
scat_stat [ index ] . regs_2x9 = val ;
base_addr = ( index + 16 ) < < 14 ;
if ( index > = 24 )
base_addr + = 0x30000 ;
if ( val & 0x80 )
{
virt_addr = ( ( ( scat_stat [ index ] . regs_2x9 & 3 ) < < 8 ) | scat_stat [ index ] . regs_2x8 ) < < 14 ;
mem_mapping_enable ( & scat_mapping [ index ] ) ;
mem_mapping_set_exec ( & scat_mapping [ index ] , ram + get_scat_addr ( virt_addr , & scat_stat [ index ] ) ) ;
pclog ( " Map page %d(address %05X) to address %06X \n " , scat_ems_reg_2xA & 0x1f , base_addr , virt_addr ) ;
}
else
{
mem_mapping_disable ( & scat_mapping [ index ] ) ;
pclog ( " Unmap page %d(address %05X) \n " , scat_ems_reg_2xA & 0x1f , base_addr ) ;
}
if ( scat_ems_reg_2xA & 0x80 )
{
scat_ems_reg_2xA = ( scat_ems_reg_2xA & 0xe0 ) | ( ( scat_ems_reg_2xA + 1 ) & 0x1f ) ;
}
}
break ;
case 0x21A :
if ( ( scat_regs [ SCAT_EMS_CONTROL ] & 0x41 ) = = 0x41 )
{
pclog ( " Write SCAT EMS Control Port %04X to %02X at %04X:%04X \n " , port , val , CS , cpu_state . pc ) ;
scat_ems_reg_2xA = val ;
}
break ;
}
}
uint8_t scat_read ( uint16_t port , void * priv )
{
uint8_t val = 0xff , index ;
switch ( port )
{
case 0x23 :
switch ( scat_index )
{
case SCAT_MISCELLANEOUS_STATUS :
val = ( scat_regs [ scat_index ] & 0xbf ) | ( ( scat_port_92 & 2 ) < < 5 ) ;
break ;
default :
val = scat_regs [ scat_index ] ;
break ;
}
pclog ( " Read SCAT Register %02X at %04X:%04X \n " , scat_index , CS , cpu_state . pc ) ;
break ;
case 0x92 :
val = scat_port_92 ;
break ;
case 0x208 :
if ( ( scat_regs [ SCAT_EMS_CONTROL ] & 0x41 ) = = 0x40 )
{
pclog ( " Read SCAT EMS Control Port %04X at %04X:%04X \n " , port , CS , cpu_state . pc ) ;
index = scat_ems_reg_2xA & 0x1F ;
val = scat_stat [ index ] . regs_2x8 ;
}
break ;
case 0x209 :
if ( ( scat_regs [ SCAT_EMS_CONTROL ] & 0x41 ) = = 0x40 )
{
pclog ( " Read SCAT EMS Control Port %04X at %04X:%04X \n " , port , CS , cpu_state . pc ) ;
index = scat_ems_reg_2xA & 0x1F ;
val = scat_stat [ index ] . regs_2x9 ;
}
break ;
case 0x20A :
if ( ( scat_regs [ SCAT_EMS_CONTROL ] & 0x41 ) = = 0x40 )
{
pclog ( " Read SCAT EMS Control Port %04X at %04X:%04X \n " , port , CS , cpu_state . pc ) ;
val = scat_ems_reg_2xA ;
}
break ;
case 0x218 :
if ( ( scat_regs [ SCAT_EMS_CONTROL ] & 0x41 ) = = 0x41 )
{
pclog ( " Read SCAT EMS Control Port %04X at %04X:%04X \n " , port , CS , cpu_state . pc ) ;
index = scat_ems_reg_2xA & 0x1F ;
val = scat_stat [ index ] . regs_2x8 ;
}
break ;
case 0x219 :
if ( ( scat_regs [ SCAT_EMS_CONTROL ] & 0x41 ) = = 0x41 )
{
pclog ( " Read SCAT EMS Control Port %04X at %04X:%04X \n " , port , CS , cpu_state . pc ) ;
index = scat_ems_reg_2xA & 0x1F ;
val = scat_stat [ index ] . regs_2x9 ;
}
break ;
case 0x21A :
if ( ( scat_regs [ SCAT_EMS_CONTROL ] & 0x41 ) = = 0x41 )
{
pclog ( " Read SCAT EMS Control Port %04X at %04X:%04X \n " , port , CS , cpu_state . pc ) ;
val = scat_ems_reg_2xA ;
}
break ;
}
return val ;
}
uint8_t mem_read_scatems ( uint32_t addr , void * priv )
{
uint8_t val = 0xff ;
scat_t * stat = ( scat_t * ) priv ;
addr = get_scat_addr ( addr , stat ) ;
if ( addr < ( mem_size < < 10 ) )
val = mem_read_ram ( addr , priv ) ;
return val ;
}
uint16_t mem_read_scatemsw ( uint32_t addr , void * priv )
{
uint16_t val = 0xffff ;
scat_t * stat = ( scat_t * ) priv ;
addr = get_scat_addr ( addr , stat ) ;
if ( addr < ( mem_size < < 10 ) )
val = mem_read_ramw ( addr , priv ) ;
return val ;
}
uint32_t mem_read_scatemsl ( uint32_t addr , void * priv )
{
uint32_t val = 0xffffffff ;
scat_t * stat = ( scat_t * ) priv ;
addr = get_scat_addr ( addr , stat ) ;
if ( addr < ( mem_size < < 10 ) )
val = mem_read_raml ( addr , priv ) ;
return val ;
}
void mem_write_scatems ( uint32_t addr , uint8_t val , void * priv )
{
scat_t * stat = ( scat_t * ) priv ;
addr = get_scat_addr ( addr , stat ) ;
if ( addr < ( mem_size < < 10 ) )
mem_write_ram ( addr , val , priv ) ;
}
void mem_write_scatemsw ( uint32_t addr , uint16_t val , void * priv )
{
scat_t * stat = ( scat_t * ) priv ;
addr = get_scat_addr ( addr , stat ) ;
if ( addr < ( mem_size < < 10 ) )
mem_write_ramw ( addr , val , priv ) ;
}
void mem_write_scatemsl ( uint32_t addr , uint32_t val , void * priv )
{
scat_t * stat = ( scat_t * ) priv ;
addr = get_scat_addr ( addr , stat ) ;
if ( addr < ( mem_size < < 10 ) )
mem_write_raml ( addr , val , priv ) ;
}
void scat_init ( )
{
int i ;
io_sethandler ( 0x0022 , 0x0002 , scat_read , NULL , NULL , scat_write , NULL , NULL , NULL ) ;
io_sethandler ( 0x0092 , 0x0001 , scat_read , NULL , NULL , scat_write , NULL , NULL , NULL ) ;
io_sethandler ( 0x0208 , 0x0003 , scat_read , NULL , NULL , scat_write , NULL , NULL , NULL ) ;
io_sethandler ( 0x0218 , 0x0003 , scat_read , NULL , NULL , scat_write , NULL , NULL , NULL ) ;
for ( i = 0 ; i < 256 ; i + + )
{
scat_regs [ i ] = 0xff ;
}
scat_regs [ SCAT_DMA_WAIT_STATE_CONTROL ] = 0 ;
scat_regs [ SCAT_VERSION ] = 10 ;
scat_regs [ SCAT_CLOCK_CONTROL ] = 2 ;
scat_regs [ SCAT_PERIPHERAL_CONTROL ] = 0x80 ;
scat_regs [ SCAT_MISCELLANEOUS_STATUS ] = 0x37 ;
scat_regs [ SCAT_POWER_MANAGEMENT ] = 0 ;
scat_regs [ SCAT_ROM_ENABLE ] = 0xC0 ;
scat_regs [ SCAT_RAM_WRITE_PROTECT ] = 0 ;
scat_regs [ SCAT_SHADOW_RAM_ENABLE_1 ] = 0 ;
scat_regs [ SCAT_SHADOW_RAM_ENABLE_2 ] = 0 ;
scat_regs [ SCAT_SHADOW_RAM_ENABLE_3 ] = 0 ;
scat_regs [ SCAT_DRAM_CONFIGURATION ] = 2 ;
scat_regs [ SCAT_EXTENDED_BOUNDARY ] = 0 ;
scat_regs [ SCAT_EMS_CONTROL ] = 0 ;
for ( i = 0 ; i < 32 ; i + + )
{
scat_stat [ i ] . regs_2x8 = 0xff ;
scat_stat [ i ] . regs_2x9 = 0x03 ;
mem_mapping_add ( & scat_mapping [ i ] , ( i + ( i > = 24 ? 28 : 16 ) ) < < 14 , 0x04000 , mem_read_scatems , mem_read_scatemsw , mem_read_scatemsl , mem_write_scatems , mem_write_scatemsw , mem_write_scatemsl , ram + ( ( i + ( i > = 24 ? 28 : 16 ) ) < < 14 ) , 0 , & scat_stat [ i ] ) ;
mem_mapping_disable ( & scat_mapping [ i ] ) ;
}
// TODO - Only normal CPU accessing address FF0000 to FFFFFF mapped to ROM. Normal CPU accessing address FC0000 to FEFFFF map to ROM should be implemented later.
for ( i = 12 ; i < 16 ; i + + )
{
mem_mapping_add ( & scat_high_mapping [ i ] , ( i < < 14 ) + 0xFC0000 , 0x04000 , mem_read_bios , mem_read_biosw , mem_read_biosl , mem_write_null , mem_write_nullw , mem_write_nulll , rom + ( i < < 14 ) , 0 , NULL ) ;
}
if ( mem_size = = 1024 )
{
mem_mapping_add ( & scat_shadowram_mapping , 0x100000 , 0x60000 , mem_read_scatems , mem_read_scatemsw , mem_read_scatemsl , mem_write_scatems , mem_write_scatemsw , mem_write_scatemsl , ram + 0xA0000 , MEM_MAPPING_INTERNAL , NULL ) ;
}
// Need to RAM 512kb clipping emulation if only 256KB or 64KB modules installed in memory bank.
// TODO - 512KB clipping should be applied all RAM refer.
mem_mapping_add ( & scat_512k_clip_mapping , 0x80000 , 0x20000 , mem_read_scatems , mem_read_scatemsw , mem_read_scatemsl , mem_write_scatems , mem_write_scatemsw , mem_write_scatemsl , ram , MEM_MAPPING_INTERNAL , NULL ) ;
mem_mapping_disable ( & scat_512k_clip_mapping ) ;
// ---
scat_set_xms_bound ( 0 ) ;
scat_shadow_state_update ( ) ;
}