Skip to content

Commit

Permalink
Revert AdLib timing adjustments
Browse files Browse the repository at this point in the history
Modified timing in AdLib emulation introduced regression in
Blues Brothers (1991) (and probably other games developed by Titus
studio). This game was no longer detecting AdLib emulation and was
falling back to playing music via PC speaker. After bringing back older
versions of adlib.h/adlib.cpp, the game works correctly again.

This commit effectively reverts following changes inherited from the
upstream:

"Change adlib timer masking"

svn revision  trunk@4353
git commit    a3f6175

"Make adlib timers synchronize on clock interval and fix masking"

svn revision  trunk@4352
git commit    b67f36d
  • Loading branch information
dreamer committed Jul 3, 2020
1 parent 93fa6cc commit f9d532d
Show file tree
Hide file tree
Showing 2 changed files with 58 additions and 88 deletions.
54 changes: 27 additions & 27 deletions src/hardware/adlib.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -468,43 +468,40 @@ class Capture {
Chip
*/

Chip::Chip() : timer0(80), timer1(320) {
}

bool Chip::Write( Bit32u reg, Bit8u val ) {
switch ( reg ) {
case 0x02:
timer0.SetCounter(val);
timer[0].counter = val;
return true;
case 0x03:
timer1.SetCounter(val);
timer[1].counter = val;
return true;
case 0x04:
double time;
time = PIC_FullIndex();
//Reset overflow in both timers
if ( val & 0x80 ) {
timer0.Reset( time );
timer1.Reset( time );
timer[0].Reset( time );
timer[1].Reset( time );
} else {
//timer 0 not masked
if (val&0x20) {
if (val & 0x1) {
timer0.Start(time);
}
else {
timer0.Stop();
}
timer[0].Update( time );
timer[1].Update( time );
if ( val & 0x1 ) {
timer[0].Start( time, 80 );
} else {
timer[0].Stop( );
}
//Timer 1 not masked
if (val&0x40) {
if (val & 0x2) {
timer1.Start(time);
}
else {
timer1.Stop();
}
timer[0].masked = (val & 0x40) > 0;
if ( timer[0].masked )
timer[0].overflow = false;
if ( val & 0x2 ) {
timer[1].Start( time, 320 );
} else {
timer[1].Stop( );
}
timer[1].masked = (val & 0x20) > 0;
if ( timer[1].masked )
timer[1].overflow = false;

}
return true;
}
Expand All @@ -513,18 +510,21 @@ bool Chip::Write( Bit32u reg, Bit8u val ) {


Bit8u Chip::Read( ) {
const double time( PIC_FullIndex() );
double time( PIC_FullIndex() );
timer[0].Update( time );
timer[1].Update( time );
Bit8u ret = 0;
//Overflow won't be set if a channel is masked
if (timer0.Update(time)) {
if ( timer[0].overflow ) {
ret |= 0x40;
ret |= 0x80;
}
if (timer1.Update(time)) {
if ( timer[1].overflow ) {
ret |= 0x20;
ret |= 0x80;
}
return ret;

}

void Module::CacheWrite( Bit32u reg, Bit8u val ) {
Expand Down
92 changes: 31 additions & 61 deletions src/hardware/adlib.h
Original file line number Diff line number Diff line change
Expand Up @@ -31,88 +31,58 @@

namespace Adlib {

class Timer {
//Rounded down start time
double start;
//Clock interval
double interval;
//Delay before you overflow
double delay;
Bit8u counter;
bool enabled;
bool overflow;

public:
Timer(int16_t micros)
: start(0),
interval(micros * 0.001), // interval in milliseconds
delay(0),
counter(0),
enabled(false),
overflow(false)

{}

//Update returns with true if overflow
bool Update( double time ) {
if ( !enabled )
return false;
const double deltaTime = time - start;
struct Timer {
double start = 0.0;
double delay = 0.0;
bool enabled = false;
bool overflow = false;
bool masked = false;
Bit8u counter = 0;

Timer() = default;

//Call update before making any further changes
void Update( double time ) {
if ( !enabled || !delay )
return;
double deltaStart = time - start;
//Only set the overflow flag when not masked
if (deltaTime >= delay ) {
overflow = true;
return true;
if ( deltaStart >= 0 && !masked ) {
overflow = 1;
}
return false;
}

//On a reset make sure the start is in sync with the next cycle
void Reset(const double time ) {
void Reset(const double& time ) {
overflow = false;
if ( !enabled )
if ( !delay || !enabled )
return;
//Sync start to the last delay interval
const double deltaTime = time - start;
const double rem = fmod(deltaTime, delay);
start = time - rem;
double delta = (time - start);
double rem = fmod( delta, delay );
double next = delay - rem;
start = time + next;
}

void SetCounter(Bit8u val) {
counter = val;
}

//Stopping always clears the overflow as well
void Stop( ) {
enabled = false;
overflow = false;
}

//Starting clears overflow
void Start( const double time ) {
void Start( const double& time, Bits scale ) {
//Don't enable again
if ( enabled ) {
return;
}
enabled = true;
overflow = false;
//The counter is basically copied on start so calculate delay now
delay = (256 - counter) * interval;
//Sync start to the last clock interval
double rem = fmod(time, interval);
start = time - rem;
delay = 0.001 * (256 - counter ) * scale;
start = time + delay;
}

//Does this clock need an update, you could save a pic_fullindex on read?
bool NeedUpdate() const {
return enabled && !overflow;
}
};

struct Chip {
//Last selected register
Timer timer0, timer1;
Timer timer[2];
//Check for it being a write to the timer
bool Write( Bit32u addr, Bit8u val );
//Read the current timer state, will use current double
Bit8u Read( );

Chip();
};

//The type of handler this is
Expand Down

0 comments on commit f9d532d

Please sign in to comment.