2017-12-28 16:40:15 +00:00
/ *
* Copyright ( C ) 2012 Brendan Robert ( BLuRry ) brendan . robert @gmail.com.
*
* This library is free software ; you can redistribute it and / or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation ; either
* version 2 . 1 of the License , or ( at your option ) any later version .
*
* This library 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
* Lesser General Public License for more details .
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library ; if not , write to the Free Software
* Foundation , Inc . , 51 Franklin Street , Fifth Floor , Boston ,
* MA 02110 - 1301 USA
* /
package jace.core ;
2023-07-03 20:44:23 +00:00
import java.util.HashSet ;
2017-12-28 16:40:15 +00:00
import jace.apple2e.SoftSwitches ;
import jace.apple2e.Speaker ;
import jace.config.ConfigurableField ;
2021-11-09 17:20:19 +00:00
2017-12-28 16:40:15 +00:00
/ * *
* Motherboard is the heart of the computer . It can have a list of cards
* inserted ( the behavior and number of cards is determined by the Memory class )
* as well as a speaker and any other miscellaneous devices ( e . g . joysticks ) .
* This class provides the real main loop of the emulator , and is responsible
* for all timing as well as the pause / resume features used to prevent resource
* collisions between threads . Created on May 1 , 2007 , 11 : 22 PM
*
* @author Brendan Robert ( BLuRry ) brendan . robert @gmail.com
* /
public class Motherboard extends TimedDevice {
2020-06-06 07:05:08 +00:00
2017-12-28 16:40:15 +00:00
@ConfigurableField ( name = " Enable Speaker " , shortName = " speaker " , defaultValue = " true " )
public static boolean enableSpeaker = true ;
public Speaker speaker ;
void vblankEnd ( ) {
SoftSwitches . VBL . getSwitch ( ) . setState ( true ) ;
computer . notifyVBLStateChanged ( true ) ;
}
void vblankStart ( ) {
SoftSwitches . VBL . getSwitch ( ) . setState ( false ) ;
computer . notifyVBLStateChanged ( false ) ;
}
/ * *
* Creates a new instance of Motherboard
* @param computer
* @param oldMotherboard
* /
public Motherboard ( Computer computer , Motherboard oldMotherboard ) {
super ( computer ) ;
if ( oldMotherboard ! = null ) {
2018-09-15 21:23:32 +00:00
addAllDevices ( oldMotherboard . getChildren ( ) ) ;
2017-12-28 16:40:15 +00:00
speaker = oldMotherboard . speaker ;
2018-02-01 15:09:18 +00:00
accelorationRequestors . addAll ( oldMotherboard . accelorationRequestors ) ;
setSpeedInHz ( oldMotherboard . getSpeedInHz ( ) ) ;
setMaxSpeed ( oldMotherboard . isMaxSpeed ( ) ) ;
2017-12-28 16:40:15 +00:00
}
}
@Override
protected String getDeviceName ( ) {
return " Motherboard " ;
}
@Override
public String getShortName ( ) {
return " mb " ;
}
2023-07-03 20:44:23 +00:00
@ConfigurableField ( category = " advanced " , shortName = " cpuPerClock " , name = " CPU per clock " , defaultValue = " 1 " , description = " Number of extra CPU cycles per clock cycle (normal = 1) " )
public static int cpuPerClock = 0 ;
2017-12-28 16:40:15 +00:00
public int clockCounter = 1 ;
@Override
public void tick ( ) {
2022-03-04 02:10:20 +00:00
// Extra CPU cycles requested, other devices are called by the TimedDevice abstraction
for ( int i = 1 ; i < cpuPerClock ; i + + ) {
2023-07-03 20:44:23 +00:00
computer . getCpu ( ) . doTick ( ) ;
if ( Speaker . force1mhz ) {
speaker . tick ( ) ;
}
2022-03-04 02:10:20 +00:00
}
/ *
2017-12-28 16:40:15 +00:00
try {
clockCounter - - ;
computer . getCpu ( ) . doTick ( ) ;
if ( clockCounter > 0 ) {
return ;
}
clockCounter = cpuPerClock ;
computer . getVideo ( ) . doTick ( ) ;
2021-11-09 17:20:19 +00:00
Optional < Card > [ ] cards = computer . getMemory ( ) . getAllCards ( ) ;
2017-12-28 16:40:15 +00:00
for ( Optional < Card > card : cards ) {
2018-05-16 05:40:40 +00:00
card . ifPresent ( Card : : doTick ) ;
2017-12-28 16:40:15 +00:00
}
} catch ( Throwable t ) {
2021-11-09 17:20:19 +00:00
System . out . print ( " ! " ) ;
2017-12-28 16:40:15 +00:00
Logger . getLogger ( getClass ( ) . getName ( ) ) . log ( Level . SEVERE , null , t ) ;
}
2022-03-04 02:10:20 +00:00
* /
2017-12-28 16:40:15 +00:00
}
// From the holy word of Sather 3:5 (Table 3.1) :-)
// This average speed averages in the "long" cycles
2023-07-03 20:44:23 +00:00
public static final long DEFAULT_SPEED = 1020484L ; // (NTSC)
2017-12-28 16:40:15 +00:00
//public static long SPEED = 1015625L; // (PAL)
@Override
public long defaultCyclesPerSecond ( ) {
2023-07-03 20:44:23 +00:00
return DEFAULT_SPEED ;
2017-12-28 16:40:15 +00:00
}
@Override
public synchronized void reconfigure ( ) {
2021-11-09 17:20:19 +00:00
whileSuspended ( ( ) - > {
accelorationRequestors . clear ( ) ;
super . reconfigure ( ) ;
// Now create devices as needed, e.g. sound
if ( enableSpeaker ) {
try {
if ( speaker = = null ) {
speaker = new Speaker ( computer ) ;
2023-07-03 20:44:23 +00:00
speaker . attach ( ) ;
2017-12-28 16:40:15 +00:00
}
2021-11-09 17:20:19 +00:00
speaker . reconfigure ( ) ;
2023-07-03 20:44:23 +00:00
addChildDevice ( speaker ) ;
2021-11-09 17:20:19 +00:00
} catch ( Throwable t ) {
System . out . println ( " Unable to initalize sound -- deactivating speaker out " ) ;
2017-12-28 16:40:15 +00:00
}
2021-11-09 17:20:19 +00:00
} else {
System . out . println ( " Speaker not enabled, leaving it off. " ) ;
2017-12-28 16:40:15 +00:00
}
2021-11-09 17:20:19 +00:00
} ) ;
2022-03-04 02:10:20 +00:00
adjustRelativeSpeeds ( ) ;
2017-12-28 16:40:15 +00:00
}
2018-02-01 15:09:18 +00:00
HashSet < Object > accelorationRequestors = new HashSet < > ( ) ;
2017-12-28 16:40:15 +00:00
public void requestSpeed ( Object requester ) {
accelorationRequestors . add ( requester ) ;
enableTempMaxSpeed ( ) ;
}
public void cancelSpeedRequest ( Object requester ) {
accelorationRequestors . remove ( requester ) ;
if ( accelorationRequestors . isEmpty ( ) ) {
disableTempMaxSpeed ( ) ;
}
}
2022-03-04 02:10:20 +00:00
void adjustRelativeSpeeds ( ) {
2023-07-03 20:44:23 +00:00
if ( computer . getVideo ( ) ! = null ) {
if ( isMaxSpeed ( ) ) {
computer . getVideo ( ) . setWaitPerCycle ( 8 ) ;
} else if ( getSpeedInHz ( ) > DEFAULT_SPEED ) {
computer . getVideo ( ) . setWaitPerCycle ( getSpeedInHz ( ) / DEFAULT_SPEED ) ;
} else {
computer . getVideo ( ) . setWaitPerCycle ( 0 ) ;
}
}
2022-03-04 02:10:20 +00:00
}
2017-12-28 16:40:15 +00:00
}