New timer code
This commit is contained in:
parent
22f4327c0d
commit
bf117ac730
|
@ -96,12 +96,12 @@ class Paddles
|
||||||
if (onTrigger[i] == 0) onTrigger[i] = 1;
|
if (onTrigger[i] == 0) onTrigger[i] = 1;
|
||||||
switchVal[i] = 0x80;
|
switchVal[i] = 0x80;
|
||||||
}
|
}
|
||||||
timer.new Counter(onTrigger[0], &pdl_0_expired);
|
timer.addCounter(onTrigger[0], &pdl_0_expired);
|
||||||
timer.new Counter(onTrigger[1], &pdl_1_expired);
|
timer.addCounter(onTrigger[1], &pdl_1_expired);
|
||||||
if (numPaddles > 2)
|
if (numPaddles > 2)
|
||||||
{
|
{
|
||||||
timer.new Counter(onTrigger[2], &pdl_2_expired);
|
timer.addCounter(onTrigger[2], &pdl_2_expired);
|
||||||
timer.new Counter(onTrigger[3], &pdl_3_expired);
|
timer.addCounter(onTrigger[3], &pdl_3_expired);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -103,8 +103,8 @@ class Speaker
|
||||||
|
|
||||||
void update()
|
void update()
|
||||||
{
|
{
|
||||||
uint elapsedSinceToggle = cycle.currentVal() - lastToggleTick;
|
uint elapsedSinceToggle = cycle.val() - lastToggleTick;
|
||||||
lastToggleTick = cycle.currentVal();
|
lastToggleTick = cycle.val();
|
||||||
elapsedSinceToggle = processExtraBuffer(elapsedSinceToggle);
|
elapsedSinceToggle = processExtraBuffer(elapsedSinceToggle);
|
||||||
|
|
||||||
uint samples = elapsedSinceToggle / sampleTicks;
|
uint samples = elapsedSinceToggle / sampleTicks;
|
||||||
|
|
|
@ -70,28 +70,34 @@ ubyte[256] controllerRom = [
|
||||||
class StopTimer
|
class StopTimer
|
||||||
{
|
{
|
||||||
Timer timer;
|
Timer timer;
|
||||||
Timer.Counter stopCounter;
|
bool stopCounter;
|
||||||
void delegate() notifyExpired;
|
void delegate() notifyExpired;
|
||||||
|
ulong t_tick;
|
||||||
|
size_t t_idx;
|
||||||
|
|
||||||
void startCountdown()
|
void startCountdown()
|
||||||
{
|
{
|
||||||
if (stopCounter is null)
|
if (!stopCounter)
|
||||||
stopCounter = timer.new Counter(1_020_484, &expire);
|
{
|
||||||
|
t_idx = timer.addCounter(1_020_484, &expire);
|
||||||
|
t_tick = timer.totalTicks;
|
||||||
|
stopCounter = true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void stopCountdown()
|
void stopCountdown()
|
||||||
{
|
{
|
||||||
if (stopCounter !is null)
|
if (stopCounter)
|
||||||
{
|
{
|
||||||
stopCounter.discard();
|
timer.removeCounter(t_tick, t_idx);
|
||||||
stopCounter = null;
|
stopCounter = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool expire()
|
bool expire()
|
||||||
{
|
{
|
||||||
notifyExpired();
|
notifyExpired();
|
||||||
stopCounter = null;
|
stopCounter = false;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -40,17 +40,15 @@ import ioummu;
|
||||||
class SystemBase
|
class SystemBase
|
||||||
{
|
{
|
||||||
Video video_;
|
Video video_;
|
||||||
|
Timer timer;
|
||||||
|
|
||||||
abstract void reboot();
|
abstract void reboot();
|
||||||
abstract void reset();
|
abstract void reset();
|
||||||
abstract uint checkpoint();
|
|
||||||
abstract uint sinceCheckpoint(uint cp);
|
|
||||||
abstract void execute();
|
abstract void execute();
|
||||||
}
|
}
|
||||||
|
|
||||||
class System(string chip) : SystemBase
|
class System(string chip) : SystemBase
|
||||||
{
|
{
|
||||||
Timer timer;
|
|
||||||
Timer.Cycle deviceCycle;
|
Timer.Cycle deviceCycle;
|
||||||
AddressDecoder decoder;
|
AddressDecoder decoder;
|
||||||
SoftSwitchPage switches;
|
SoftSwitchPage switches;
|
||||||
|
@ -138,9 +136,9 @@ class System(string chip) : SystemBase
|
||||||
void initTimer()
|
void initTimer()
|
||||||
{
|
{
|
||||||
// XXX constants? variables?
|
// XXX constants? variables?
|
||||||
timer = new Timer(10_205, 1_020_484);
|
timer = new Timer(10_205, 1_020_484, &primaryStop);
|
||||||
deviceCycle =
|
deviceCycle =
|
||||||
timer.startCycle(timer.primaryCounter.startLength * 2);
|
timer.new Cycle(timer.primaryLength * 2);
|
||||||
}
|
}
|
||||||
|
|
||||||
void initMemory(ubyte[] romDump)
|
void initMemory(ubyte[] romDump)
|
||||||
|
@ -177,7 +175,7 @@ class System(string chip) : SystemBase
|
||||||
resetLow = &cpu.resetLow;
|
resetLow = &cpu.resetLow;
|
||||||
|
|
||||||
debug(disassemble) cpu.memoryName = &decoder.memoryReadName;
|
debug(disassemble) cpu.memoryName = &decoder.memoryReadName;
|
||||||
timer.onPrimaryStop(&primaryStop);
|
// timer.onPrimaryStop(&primaryStop);
|
||||||
}
|
}
|
||||||
|
|
||||||
void initIO(ubyte[] vidRom)
|
void initIO(ubyte[] vidRom)
|
||||||
|
@ -218,18 +216,6 @@ class System(string chip) : SystemBase
|
||||||
*resetLow = true;
|
*resetLow = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
override uint checkpoint()
|
|
||||||
{
|
|
||||||
return timer.primaryCounter.currentLength;
|
|
||||||
}
|
|
||||||
|
|
||||||
override uint sinceCheckpoint(uint cp)
|
|
||||||
{
|
|
||||||
uint currentLength = timer.primaryCounter.currentLength;
|
|
||||||
return ((currentLength == timer.primaryCounter.startLength) ?
|
|
||||||
cp : (cp - currentLength));
|
|
||||||
}
|
|
||||||
|
|
||||||
override void execute()
|
override void execute()
|
||||||
{
|
{
|
||||||
cpu.run(true);
|
cpu.run(true);
|
||||||
|
|
472
src/timer.d
472
src/timer.d
|
@ -1,7 +1,7 @@
|
||||||
/+
|
/+
|
||||||
+ timer.d
|
+ timer.d
|
||||||
+
|
+
|
||||||
+ Copyright: 2007 Gerald Stocker
|
+ Copyright: 2012 Ed McCardell, 2007 Gerald Stocker
|
||||||
+
|
+
|
||||||
+ This file is part of twoapple-reboot.
|
+ This file is part of twoapple-reboot.
|
||||||
+
|
+
|
||||||
|
@ -22,222 +22,318 @@
|
||||||
|
|
||||||
module timer;
|
module timer;
|
||||||
|
|
||||||
class Timer
|
final class Timer
|
||||||
{
|
{
|
||||||
class Cycle
|
private:
|
||||||
{
|
static struct Counter
|
||||||
int delta;
|
|
||||||
uint rollOver;
|
|
||||||
|
|
||||||
this(uint maxVal)
|
|
||||||
{
|
|
||||||
rollOver = maxVal;
|
|
||||||
restart();
|
|
||||||
}
|
|
||||||
|
|
||||||
void restart()
|
|
||||||
{
|
|
||||||
delta = 0 - currentCounter.elapsed();
|
|
||||||
}
|
|
||||||
|
|
||||||
uint currentVal()
|
|
||||||
{
|
|
||||||
return (currentCounter.elapsed() + delta) % rollOver;
|
|
||||||
}
|
|
||||||
|
|
||||||
void update()
|
|
||||||
{
|
|
||||||
delta = currentVal();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class Counter
|
|
||||||
{
|
{
|
||||||
|
uint start, curr;
|
||||||
|
bool active;
|
||||||
|
size_t next = -1, nextFree;
|
||||||
bool delegate() expiry;
|
bool delegate() expiry;
|
||||||
uint startLength, currentLength;
|
ulong creationTick;
|
||||||
int ticks;
|
|
||||||
bool shouldContinue;
|
|
||||||
|
|
||||||
this(uint start)
|
this(uint length, bool delegate() expiry, ulong creationTick)
|
||||||
{
|
{
|
||||||
shouldContinue = true;
|
start = curr = length;
|
||||||
startLength = currentLength = ticks = start;
|
this.expiry = expiry;
|
||||||
addCounter(this);
|
this.creationTick = creationTick;
|
||||||
}
|
active = true;
|
||||||
|
|
||||||
this(uint start, bool delegate() expiration)
|
|
||||||
{
|
|
||||||
this(start);
|
|
||||||
initCounter(this);
|
|
||||||
expiry = expiration;
|
|
||||||
}
|
|
||||||
|
|
||||||
final uint elapsed()
|
|
||||||
{
|
|
||||||
return currentLength - ticks;
|
|
||||||
}
|
|
||||||
|
|
||||||
final void tick()
|
|
||||||
{
|
|
||||||
--ticks;
|
|
||||||
if (ticks == 0)
|
|
||||||
{
|
|
||||||
reset();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
final void forceExpire()
|
|
||||||
{
|
|
||||||
ticks = 1;
|
|
||||||
tick();
|
|
||||||
}
|
|
||||||
|
|
||||||
final void discard()
|
|
||||||
{
|
|
||||||
expiry = &nullExpiry;
|
|
||||||
forceExpire();
|
|
||||||
}
|
|
||||||
|
|
||||||
private final void resume()
|
|
||||||
{
|
|
||||||
currentLength = ticks;
|
|
||||||
}
|
|
||||||
|
|
||||||
private final bool expire()
|
|
||||||
{
|
|
||||||
ticks = currentLength = startLength;
|
|
||||||
return expiry();
|
|
||||||
}
|
|
||||||
|
|
||||||
private bool nullExpiry() { return false; }
|
|
||||||
}
|
|
||||||
|
|
||||||
class DelayedCounter : Counter
|
|
||||||
{
|
|
||||||
uint realStart;
|
|
||||||
bool delegate() realExpiry;
|
|
||||||
|
|
||||||
this(uint start, bool delegate() expiration, uint delay)
|
|
||||||
{
|
|
||||||
realStart = start;
|
|
||||||
realExpiry = expiration;
|
|
||||||
super(delay, &becomeReal);
|
|
||||||
}
|
|
||||||
|
|
||||||
private bool becomeReal()
|
|
||||||
{
|
|
||||||
ticks = currentLength = startLength = realStart;
|
|
||||||
expiry = realExpiry;
|
|
||||||
bool retval = expiry();
|
|
||||||
initCounter(this);
|
|
||||||
return retval;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Cycle[] cycles;
|
ulong _totalTicks;
|
||||||
|
uint start = uint.max, curr = uint.max, minCurr = uint.max;
|
||||||
|
uint balance;
|
||||||
|
size_t head, tail, nextFree;
|
||||||
Counter[] counters;
|
Counter[] counters;
|
||||||
Counter primaryCounter, currentCounter;
|
uint _hertz;
|
||||||
uint hertz;
|
|
||||||
|
|
||||||
this(uint primaryStart, uint hz)
|
final void setNextFree()
|
||||||
{
|
{
|
||||||
hertz = hz;
|
for (size_t i = nextFree; i < counters.length; i++)
|
||||||
cycles.length = 10;
|
counters[i].nextFree = i + 1;
|
||||||
counters.length = 10;
|
|
||||||
cycles.length = 0;
|
|
||||||
counters.length = 0;
|
|
||||||
currentCounter = primaryCounter = new Counter(primaryStart);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
final void onPrimaryStop(bool delegate() expiration)
|
final void deleteCounter(size_t idx, size_t prev)
|
||||||
{
|
{
|
||||||
primaryCounter.expiry = expiration;
|
auto tmp = nextFree;
|
||||||
}
|
nextFree = idx;
|
||||||
|
counters[idx].nextFree = tmp;
|
||||||
|
|
||||||
Cycle startCycle(uint maxVal)
|
auto next = counters[idx].next;
|
||||||
{
|
if (idx == head)
|
||||||
cycles.length = cycles.length + 1;
|
|
||||||
cycles[$-1] = new Cycle(maxVal);
|
|
||||||
return cycles[$-1];
|
|
||||||
}
|
|
||||||
|
|
||||||
void tick()
|
|
||||||
{
|
|
||||||
currentCounter.tick();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void deleteCounters()
|
|
||||||
{
|
|
||||||
int numCounters = cast(int)counters.length;
|
|
||||||
int lastCounter;
|
|
||||||
main: for (int counter = 0; counter < counters.length; ++counter)
|
|
||||||
{
|
{
|
||||||
lastCounter = counter;
|
head = next;
|
||||||
while (!counters[counter].shouldContinue)
|
|
||||||
{
|
|
||||||
numCounters--;
|
|
||||||
if (++counter >= counters.length) break main;
|
|
||||||
}
|
|
||||||
currentCounter = counters[lastCounter] = counters[counter];
|
|
||||||
}
|
|
||||||
if (numCounters < counters.length)
|
|
||||||
{
|
|
||||||
counters.length = numCounters;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void addCounter(Counter newCounter)
|
|
||||||
{
|
|
||||||
counters.length = counters.length + 1;
|
|
||||||
counters[$-1] = newCounter;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void initCounter(Counter newCounter)
|
|
||||||
{
|
|
||||||
if (newCounter.ticks < currentCounter.ticks)
|
|
||||||
{
|
|
||||||
reset(newCounter);
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
newCounter.ticks += currentCounter.elapsed();
|
counters[prev].next = next;
|
||||||
}
|
}
|
||||||
|
if (idx == tail)
|
||||||
|
{
|
||||||
|
tail = prev;
|
||||||
|
counters[tail].next = -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
counters[idx].active = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void reset(Counter newCounter = null)
|
public:
|
||||||
|
this(uint primaryLength, uint hertz, bool delegate() primaryStop)
|
||||||
{
|
{
|
||||||
// update cycle counts
|
counters = new Counter[50];
|
||||||
for (int cycle = 0; cycle < cycles.length; ++cycle)
|
setNextFree();
|
||||||
{
|
_hertz = hertz;
|
||||||
cycles[cycle].update();
|
addCounter(primaryLength, primaryStop);
|
||||||
}
|
}
|
||||||
|
|
||||||
// update counter counts
|
final @property uint primaryRemaining()
|
||||||
for (int counter = 0; counter < counters.length; ++counter)
|
{
|
||||||
{
|
return counters[0].curr;
|
||||||
if (counters[counter] !is currentCounter &&
|
}
|
||||||
counters[counter] !is newCounter)
|
|
||||||
counters[counter].ticks -= currentCounter.elapsed();
|
|
||||||
}
|
|
||||||
|
|
||||||
// check for expired counters
|
final @property uint primaryLength()
|
||||||
for (int counter = 0; counter < counters.length; ++counter)
|
{
|
||||||
{
|
return counters[0].start;
|
||||||
if (counters[counter].ticks <= 0)
|
}
|
||||||
counters[counter].shouldContinue = counters[counter].expire();
|
|
||||||
else
|
|
||||||
counters[counter].resume();
|
|
||||||
}
|
|
||||||
|
|
||||||
//delete counters that should be deleted
|
final @property uint hertz()
|
||||||
deleteCounters();
|
{
|
||||||
|
return _hertz;
|
||||||
|
}
|
||||||
|
|
||||||
// set current counter
|
final @property ulong totalTicks()
|
||||||
for (int counter = 0; counter < counters.length; ++counter)
|
{
|
||||||
|
return _totalTicks;
|
||||||
|
}
|
||||||
|
|
||||||
|
final void tick()
|
||||||
|
{
|
||||||
|
_totalTicks++;
|
||||||
|
curr--;
|
||||||
|
if (!curr)
|
||||||
{
|
{
|
||||||
if (counters[counter].ticks < currentCounter.ticks)
|
minCurr = uint.max;
|
||||||
currentCounter = counters[counter];
|
size_t idx = head;
|
||||||
|
size_t prev = -1;
|
||||||
|
while (idx != -1)
|
||||||
|
{
|
||||||
|
if (counters[idx].active)
|
||||||
|
{
|
||||||
|
counters[idx].curr -= start;
|
||||||
|
if (counters[idx].curr) counters[idx].curr -= balance;
|
||||||
|
if (!counters[idx].curr)
|
||||||
|
{
|
||||||
|
if (counters[idx].expiry())
|
||||||
|
counters[idx].curr = counters[idx].start;
|
||||||
|
else
|
||||||
|
deleteCounter(idx, prev);
|
||||||
|
}
|
||||||
|
if (counters[idx].active && counters[idx].curr < minCurr)
|
||||||
|
minCurr = counters[idx].curr;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
deleteCounter(idx, prev);
|
||||||
|
}
|
||||||
|
prev = idx;
|
||||||
|
idx = counters[idx].next;
|
||||||
|
}
|
||||||
|
start = curr = minCurr;
|
||||||
|
balance = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
final size_t addCounter(uint length, bool delegate() expiry)
|
||||||
|
{
|
||||||
|
if (nextFree == counters.length)
|
||||||
|
{
|
||||||
|
counters.length += 20;
|
||||||
|
setNextFree();
|
||||||
|
}
|
||||||
|
|
||||||
|
auto idx = nextFree;
|
||||||
|
nextFree = counters[nextFree].nextFree;
|
||||||
|
counters[idx] = Counter(length, expiry, _totalTicks);
|
||||||
|
counters[tail].next = idx;
|
||||||
|
tail = idx;
|
||||||
|
counters[tail].next = -1;
|
||||||
|
|
||||||
|
if (curr == 0)
|
||||||
|
{
|
||||||
|
counters[idx].curr += start;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (counters[idx].curr < curr)
|
||||||
|
{
|
||||||
|
balance = start - curr;
|
||||||
|
start = curr = counters[idx].curr;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
counters[idx].curr += (start - curr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return idx;
|
||||||
|
}
|
||||||
|
|
||||||
|
final void removeCounter(ulong creationTick, size_t idx)
|
||||||
|
{
|
||||||
|
assert(counters[idx].creationTick == creationTick);
|
||||||
|
counters[idx].active = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
final class Cycle
|
||||||
|
{
|
||||||
|
ulong startTick;
|
||||||
|
uint rollOver;
|
||||||
|
|
||||||
|
this(uint rollOver)
|
||||||
|
{
|
||||||
|
this.rollOver = rollOver;
|
||||||
|
restart();
|
||||||
|
}
|
||||||
|
|
||||||
|
final void restart()
|
||||||
|
{
|
||||||
|
startTick = _totalTicks;
|
||||||
|
}
|
||||||
|
|
||||||
|
final uint val()
|
||||||
|
{
|
||||||
|
return (_totalTicks - startTick) % rollOver;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
unittest
|
||||||
|
{
|
||||||
|
bool primary() { return true; }
|
||||||
|
|
||||||
|
auto t = new Timer(10205, 1020484, &primary);
|
||||||
|
int c1 = 0, c2 = 0;
|
||||||
|
t.addCounter(10, (){assert(t._totalTicks == 10); c1++; return true;});
|
||||||
|
foreach (i; 0..9) t.tick();
|
||||||
|
t.addCounter(5, (){assert(t._totalTicks == 14); c2++; return true;});
|
||||||
|
foreach (i; 0..5) t.tick();
|
||||||
|
assert (c1 == 1 && c2 == 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
unittest
|
||||||
|
{
|
||||||
|
bool primary() { return true; }
|
||||||
|
|
||||||
|
auto t = new Timer(10205, 1020484, &primary);
|
||||||
|
int c1 = 0, c2 = 0;
|
||||||
|
struct Dummy
|
||||||
|
{
|
||||||
|
bool exp1()
|
||||||
|
{
|
||||||
|
auto ticks = t._totalTicks;
|
||||||
|
assert((c1 == 0 && ticks == 10) || (c1 == 1 && ticks == 30));
|
||||||
|
c1++;
|
||||||
|
t.addCounter(10, &exp2);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
bool exp2()
|
||||||
|
{
|
||||||
|
auto ticks = t._totalTicks;
|
||||||
|
assert((c2 == 0 && ticks == 20) || (c2 == 1 && ticks == 40));
|
||||||
|
c2++;
|
||||||
|
t.addCounter(10, &exp1);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Dummy d;
|
||||||
|
t.addCounter(10, &d.exp1);
|
||||||
|
foreach (i; 0..40) t.tick();
|
||||||
|
assert(c1 == 2 && c2 == 2);
|
||||||
|
}
|
||||||
|
|
||||||
|
unittest
|
||||||
|
{
|
||||||
|
bool primary() { return true; }
|
||||||
|
|
||||||
|
auto t = new Timer(10205, 1020484, &primary);
|
||||||
|
int c1 = 0, c2 = 0, c3 = 0;
|
||||||
|
|
||||||
|
void addExtra()
|
||||||
|
{
|
||||||
|
t.addCounter(4, (){auto ticks = t._totalTicks;
|
||||||
|
assert((c1 == 0 && ticks == 14) ||
|
||||||
|
(c1 == 1 && ticks == 24));
|
||||||
|
c1++;
|
||||||
|
return false;});
|
||||||
|
t.addCounter(5, (){auto ticks = t._totalTicks;
|
||||||
|
assert((c2 == 0 && ticks == 15) ||
|
||||||
|
(c2 == 1 && ticks == 25));
|
||||||
|
c2++;
|
||||||
|
return false;});
|
||||||
|
t.addCounter(6, (){auto ticks = t._totalTicks;
|
||||||
|
assert((c3 == 0 && ticks == 16) ||
|
||||||
|
(c3 == 1 && ticks == 26));
|
||||||
|
c3++;
|
||||||
|
return false;});
|
||||||
|
}
|
||||||
|
t.addCounter(10, (){addExtra(); return true;});
|
||||||
|
foreach (i; 0..30) t.tick();
|
||||||
|
assert (c1 == 2 && c2 == 2 && c3 == 2);
|
||||||
|
}
|
||||||
|
|
||||||
|
unittest
|
||||||
|
{
|
||||||
|
bool primary() { return true; }
|
||||||
|
|
||||||
|
auto t = new Timer(10205, 1020484, &primary);
|
||||||
|
auto c1 = t.addCounter(10, (){assert(false); return false;});
|
||||||
|
auto c1_tick = t._totalTicks;
|
||||||
|
foreach (i; 0..5) t.tick();
|
||||||
|
t.removeCounter(c1_tick, c1);
|
||||||
|
foreach (i; 0..5) t.tick();
|
||||||
|
}
|
||||||
|
|
||||||
|
unittest
|
||||||
|
{
|
||||||
|
bool primary() { return true; }
|
||||||
|
|
||||||
|
auto t = new Timer(10205, 1020484, &primary);
|
||||||
|
int c1 = 0, c2 = 0;
|
||||||
|
t.addCounter(10, (){c1++; return true;});
|
||||||
|
auto idx = t.addCounter(15, (){c2++; return true;});
|
||||||
|
auto tick = t._totalTicks;
|
||||||
|
foreach (i; 0..20) t.tick();
|
||||||
|
assert(c1 == 2 && c2 == 1);
|
||||||
|
t.removeCounter(tick, idx);
|
||||||
|
foreach (i; 0..20) t.tick();
|
||||||
|
assert(c1 == 4 && c2 == 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
unittest
|
||||||
|
{
|
||||||
|
bool primary() { return true; }
|
||||||
|
|
||||||
|
auto t = new Timer(10205, 1020484, &primary);
|
||||||
|
|
||||||
|
bool t1() { assert(!(t.totalTicks % 5000)); return true; }
|
||||||
|
bool t2() { assert(!(t.totalTicks % 4500)); return true; }
|
||||||
|
bool t3() { assert(!(t.totalTicks % 6500)); return true; }
|
||||||
|
bool junk() { assert(!((t.totalTicks - 7000) % 1500)); return true; }
|
||||||
|
|
||||||
|
t.addCounter(5000, &t1);
|
||||||
|
t.addCounter(4500, &t2);
|
||||||
|
t.addCounter(6500, &t3);
|
||||||
|
|
||||||
|
foreach (i; 0..7000) t.tick();
|
||||||
|
|
||||||
|
t.addCounter(1500, &junk);
|
||||||
|
t.addCounter(1500, &junk);
|
||||||
|
t.addCounter(1500, &junk);
|
||||||
|
t.addCounter(1500, &junk);
|
||||||
|
|
||||||
|
foreach (i; 0..7000) t.tick();
|
||||||
}
|
}
|
||||||
|
|
|
@ -210,6 +210,8 @@ class Input
|
||||||
|
|
||||||
void onJoystickEvent()
|
void onJoystickEvent()
|
||||||
{
|
{
|
||||||
|
import std.stdio;
|
||||||
|
writeln("QWERTY joyevent");
|
||||||
static const float scale = 65535.0 / 2760.0;
|
static const float scale = 65535.0 / 2760.0;
|
||||||
static const int shift = 32768;
|
static const int shift = 32768;
|
||||||
bool buttonDown = false;
|
bool buttonDown = false;
|
||||||
|
|
|
@ -143,6 +143,13 @@ class TwoappleMainWindow : MainWindow
|
||||||
return super.windowDelete(event, widget);
|
return super.windowDelete(event, widget);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
uint sinceCheckpoint(uint cp)
|
||||||
|
{
|
||||||
|
uint currentLength = system.timer.primaryRemaining;
|
||||||
|
return ((currentLength == system.timer.primaryLength) ?
|
||||||
|
cp : (cp - currentLength));
|
||||||
|
}
|
||||||
|
|
||||||
bool configChanged;
|
bool configChanged;
|
||||||
bool runOnce;
|
bool runOnce;
|
||||||
bool stayOpen;
|
bool stayOpen;
|
||||||
|
@ -189,9 +196,9 @@ class TwoappleMainWindow : MainWindow
|
||||||
|
|
||||||
if (shouldRun)
|
if (shouldRun)
|
||||||
{
|
{
|
||||||
willElapse = system.checkpoint();
|
willElapse = system.timer.primaryRemaining;
|
||||||
system.execute();
|
system.execute();
|
||||||
didElapse = system.sinceCheckpoint(willElapse);
|
didElapse = sinceCheckpoint(willElapse);
|
||||||
input.processEvents();
|
input.processEvents();
|
||||||
// XXX do something about typeahead?
|
// XXX do something about typeahead?
|
||||||
if (!runOnce)
|
if (!runOnce)
|
||||||
|
|
|
@ -222,7 +222,7 @@ class TextPatternGenerator_II : TextPatternGenerator
|
||||||
// XXX XXX INIT
|
// XXX XXX INIT
|
||||||
void init(Timer timer)
|
void init(Timer timer)
|
||||||
{
|
{
|
||||||
timer.new Counter(timer.hertz / 2, &toggleFlash);
|
timer.addCounter(timer.hertz / 2, &toggleFlash);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -307,7 +307,7 @@ class TextPatternGenerator_IIe : TextPatternGenerator
|
||||||
// XXX XXX INIT
|
// XXX XXX INIT
|
||||||
void init(Timer timer)
|
void init(Timer timer)
|
||||||
{
|
{
|
||||||
timer.new Counter(32 * 262 * 65, &toggleFlash); // XXX PAL
|
timer.addCounter(32 * 262 * 65, &toggleFlash); // XXX PAL
|
||||||
}
|
}
|
||||||
|
|
||||||
void altCharsetOn()
|
void altCharsetOn()
|
||||||
|
|
|
@ -28,12 +28,14 @@ import memory;
|
||||||
import timer;
|
import timer;
|
||||||
import device.base;
|
import device.base;
|
||||||
|
|
||||||
|
|
||||||
class Scanner : ScannerBase
|
class Scanner : ScannerBase
|
||||||
{
|
{
|
||||||
uint page;
|
uint page;
|
||||||
bool graphicsTime, textSwitch, mixedSwitch, hiresSwitch, oldTextSwitch;
|
bool graphicsTime, textSwitch, mixedSwitch, hiresSwitch, oldTextSwitch;
|
||||||
Mode mode;
|
Mode mode;
|
||||||
|
|
||||||
|
Timer timer;
|
||||||
Timer.Cycle vidCycle;
|
Timer.Cycle vidCycle;
|
||||||
uint frameSkip, frameCount;
|
uint frameSkip, frameCount;
|
||||||
|
|
||||||
|
@ -47,14 +49,23 @@ class Scanner : ScannerBase
|
||||||
void init(Timer timer)
|
void init(Timer timer)
|
||||||
{
|
{
|
||||||
int frameLen = 262 * 65; // XXX PAL: 312 * 65
|
int frameLen = 262 * 65; // XXX PAL: 312 * 65
|
||||||
vidCycle = timer.startCycle(frameLen);
|
this.timer = timer;
|
||||||
|
vidCycle = timer.new Cycle(frameLen);
|
||||||
graphicsTime = true;
|
graphicsTime = true;
|
||||||
|
|
||||||
timer.new Counter(frameLen, &graphicsTimeOn);
|
timer.addCounter(frameLen, &graphicsTimeOn);
|
||||||
timer.new DelayedCounter(frameLen, &frameComplete, frameLen - 1);
|
timer.addCounter(frameLen - 1,
|
||||||
timer.new DelayedCounter(frameLen, &graphicsTimeOff, 160 * 65);
|
(){frameComplete();
|
||||||
timer.new DelayedCounter(frameLen, &graphicsTimeOn, 192 * 65);
|
timer.addCounter(frameLen, &frameComplete); return false;});
|
||||||
timer.new DelayedCounter(frameLen, &graphicsTimeOff, 224 * 65);
|
timer.addCounter(160 * 65,
|
||||||
|
(){graphicsTimeOff();
|
||||||
|
timer.addCounter(frameLen, &graphicsTimeOff); return false;});
|
||||||
|
timer.addCounter(192 * 65,
|
||||||
|
(){graphicsTimeOn();
|
||||||
|
timer.addCounter(frameLen, &graphicsTimeOn); return false;});
|
||||||
|
timer.addCounter(224 * 65,
|
||||||
|
(){graphicsTimeOff();
|
||||||
|
timer.addCounter(frameLen, &graphicsTimeOff); return false;});
|
||||||
}
|
}
|
||||||
|
|
||||||
void forceFrame()
|
void forceFrame()
|
||||||
|
@ -199,12 +210,12 @@ class Scanner : ScannerBase
|
||||||
|
|
||||||
uint currentLine()
|
uint currentLine()
|
||||||
{
|
{
|
||||||
return vidCycle.currentVal() / 65;
|
return vidCycle.val() / 65;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint currentCol()
|
uint currentCol()
|
||||||
{
|
{
|
||||||
return vidCycle.currentVal() % 65;
|
return vidCycle.val() % 65;
|
||||||
}
|
}
|
||||||
|
|
||||||
ubyte* getData(uint vidClock)
|
ubyte* getData(uint vidClock)
|
||||||
|
@ -243,7 +254,7 @@ class Scanner_II : Scanner
|
||||||
|
|
||||||
ubyte floatingBus(ushort addr)
|
ubyte floatingBus(ushort addr)
|
||||||
{
|
{
|
||||||
uint clock = vidCycle.currentVal();
|
uint clock = vidCycle.val();
|
||||||
if (((clock % 65) < 25) && (mode != Mode.HIRES))
|
if (((clock % 65) < 25) && (mode != Mode.HIRES))
|
||||||
return decoder.read(
|
return decoder.read(
|
||||||
cast(ushort)(0x1400 + (page * 0x400) + scanOffset(clock, mode)));
|
cast(ushort)(0x1400 + (page * 0x400) + scanOffset(clock, mode)));
|
||||||
|
@ -263,7 +274,7 @@ class Scanner_IIe : Scanner
|
||||||
{
|
{
|
||||||
ubyte floatingBus(ushort addr)
|
ubyte floatingBus(ushort addr)
|
||||||
{
|
{
|
||||||
return displayMem[mode][page].data[scanOffset(vidCycle.currentVal(),
|
return displayMem[mode][page].data[scanOffset(vidCycle.val(),
|
||||||
mode)];
|
mode)];
|
||||||
// equivalent to getData()[0];
|
// equivalent to getData()[0];
|
||||||
}
|
}
|
||||||
|
@ -280,7 +291,7 @@ class Scanner_IIe : Scanner
|
||||||
|
|
||||||
bool readVBL()
|
bool readVBL()
|
||||||
{
|
{
|
||||||
return (vidCycle.currentVal() >= (192 * 65));
|
return (vidCycle.val() >= (192 * 65));
|
||||||
}
|
}
|
||||||
|
|
||||||
ubyte readLowVBL()
|
ubyte readLowVBL()
|
||||||
|
|
Loading…
Reference in New Issue