mirror of
https://github.com/JorjBauer/aiie.git
synced 2024-12-01 14:50:54 +00:00
more audio cleanup
This commit is contained in:
parent
89a6450a91
commit
5d85c2204a
181
apple/sy6522.cpp
181
apple/sy6522.cpp
@ -1,181 +0,0 @@
|
|||||||
#include "sy6522.h"
|
|
||||||
#include <stdio.h>
|
|
||||||
|
|
||||||
#include "globals.h"
|
|
||||||
|
|
||||||
SY6522::SY6522()
|
|
||||||
{
|
|
||||||
ORB = ORA = 0;
|
|
||||||
DDRB = DDRA = 0x00;
|
|
||||||
T1_CTR = T2_CTR = 0;
|
|
||||||
T1_CTR_LATCH = T2_CTR_LATCH = 0;
|
|
||||||
ACR = 0x20; // free-running; FIXME: constant?
|
|
||||||
PCR = 0xB0; // FIXME: ?
|
|
||||||
IFR = 0x00; // FIXME: ?
|
|
||||||
IER = 0x90; // FIXME: ?
|
|
||||||
}
|
|
||||||
|
|
||||||
uint8_t SY6522::read(uint8_t address)
|
|
||||||
{
|
|
||||||
switch (address) {
|
|
||||||
case SY_ORB:
|
|
||||||
return ORB;
|
|
||||||
case SY_ORA:
|
|
||||||
return ORA;
|
|
||||||
case SY_DDRB:
|
|
||||||
return DDRB;
|
|
||||||
case SY_DDRA:
|
|
||||||
return DDRA;
|
|
||||||
case SY_TMR1L:
|
|
||||||
IFR &= ~SY_IR_TIMER1;
|
|
||||||
return (T1_CTR & 0xFF);
|
|
||||||
case SY_TMR1H:
|
|
||||||
return (T1_CTR >> 8);
|
|
||||||
case SY_TMR1LL:
|
|
||||||
return (T1_CTR_LATCH & 0xFF);
|
|
||||||
case SY_TMR1HL:
|
|
||||||
return (T1_CTR_LATCH >> 8);
|
|
||||||
case SY_TMR2L:
|
|
||||||
IFR &= ~SY_IR_TIMER2;
|
|
||||||
return (T2_CTR & 0xFF);
|
|
||||||
case SY_TMR2H:
|
|
||||||
return (T2_CTR >> 8);
|
|
||||||
case SY_SS:
|
|
||||||
// FIXME: floating
|
|
||||||
return 0xFF;
|
|
||||||
case SY_ACR:
|
|
||||||
return ACR;
|
|
||||||
case SY_PCR:
|
|
||||||
return PCR;
|
|
||||||
case SY_IFR:
|
|
||||||
return IFR;
|
|
||||||
case SY_IER:
|
|
||||||
return 0x80 | IER;
|
|
||||||
case SY_ORANOHS:
|
|
||||||
return ORA;
|
|
||||||
}
|
|
||||||
return 0xFF;
|
|
||||||
}
|
|
||||||
|
|
||||||
void SY6522::write(uint8_t address, uint8_t val)
|
|
||||||
{
|
|
||||||
switch (address) {
|
|
||||||
case SY_ORB:
|
|
||||||
val &= DDRB;
|
|
||||||
ORB = val;
|
|
||||||
ay8910[0].write(val, ORA & DDRA);
|
|
||||||
return;
|
|
||||||
|
|
||||||
case SY_ORA:
|
|
||||||
ORA = val & DDRA;
|
|
||||||
return;
|
|
||||||
|
|
||||||
case SY_DDRB:
|
|
||||||
DDRB = val;
|
|
||||||
return;
|
|
||||||
|
|
||||||
case SY_DDRA:
|
|
||||||
DDRA = val;
|
|
||||||
return;
|
|
||||||
|
|
||||||
case SY_TMR1L:
|
|
||||||
case SY_TMR1LL:
|
|
||||||
T1_CTR_LATCH = (T1_CTR_LATCH & 0xFF00) | val;
|
|
||||||
return;
|
|
||||||
|
|
||||||
case SY_TMR1H:
|
|
||||||
IFR &= SY_IR_TIMER1;
|
|
||||||
|
|
||||||
// Update IFR?
|
|
||||||
IFR &= 0x7F;
|
|
||||||
if (IFR & IER) {
|
|
||||||
// an interrupt is happening; keep the IE flag on
|
|
||||||
IFR |= 0x80;
|
|
||||||
}
|
|
||||||
|
|
||||||
// FIXME: clear interrupt flag
|
|
||||||
T1_CTR_LATCH = (T1_CTR_LATCH & 0x00FF) | (val << 8);
|
|
||||||
T1_CTR = T1_CTR_LATCH;
|
|
||||||
// FIXME: start timer?
|
|
||||||
return;
|
|
||||||
|
|
||||||
case SY_TMR1HL:
|
|
||||||
T1_CTR_LATCH = (T1_CTR_LATCH & 0x00FF) | (val << 8);
|
|
||||||
// FIXME: clear interrupt flag
|
|
||||||
return;
|
|
||||||
|
|
||||||
case SY_TMR2L:
|
|
||||||
T2_CTR_LATCH = (T2_CTR_LATCH & 0xFF00) | val;
|
|
||||||
return;
|
|
||||||
|
|
||||||
case SY_TMR2H:
|
|
||||||
// FIXME: clear timer2 interrupt flag
|
|
||||||
T2_CTR_LATCH = (T2_CTR_LATCH & 0x00FF) | (val << 8);
|
|
||||||
T2_CTR = T2_CTR_LATCH;
|
|
||||||
return;
|
|
||||||
|
|
||||||
case SY_SS:
|
|
||||||
// FIXME: what is this for?
|
|
||||||
return;
|
|
||||||
|
|
||||||
case SY_ACR:
|
|
||||||
ACR = val;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case SY_PCR:
|
|
||||||
PCR = val;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case SY_IFR:
|
|
||||||
// Clear whatever low bits are set in IFR.
|
|
||||||
val |= 0x80;
|
|
||||||
val ^= 0x7F;
|
|
||||||
IFR &= val;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case SY_IER:
|
|
||||||
if (val & 0x80) {
|
|
||||||
// Set bits based on val
|
|
||||||
val &= 0x7F;
|
|
||||||
IER |= val;
|
|
||||||
// FIXME: start timer if necessary?
|
|
||||||
} else {
|
|
||||||
// Clear whatever low bits are set in IER.
|
|
||||||
val |= 0x80;
|
|
||||||
val ^= 0x7F;
|
|
||||||
IER &= val;
|
|
||||||
// FIXME: stop timer if it's running?
|
|
||||||
}
|
|
||||||
return;
|
|
||||||
|
|
||||||
case SY_ORANOHS:
|
|
||||||
// FIXME: what is this for?
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void SY6522::update(uint32_t cycles)
|
|
||||||
{
|
|
||||||
/* Update 6522 timers */
|
|
||||||
|
|
||||||
// ...
|
|
||||||
/*
|
|
||||||
SY_IR_CA2 = 1,
|
|
||||||
SY_IR_CA1 = 2,
|
|
||||||
SY_IR_SHIFTREG = 4,
|
|
||||||
SY_IR_CB2 = 8,
|
|
||||||
SY_IR_CB1 = 16,
|
|
||||||
SY_IR_TIMER2 = 32,
|
|
||||||
SY_IR_TIMER1 = 64,
|
|
||||||
SY_IER_SETCLEAR = 128,
|
|
||||||
SY_IFR_IRQ = 128
|
|
||||||
*/
|
|
||||||
/* Check for 6522 interrupts */
|
|
||||||
if (IFR & 0x80) {
|
|
||||||
g_cpu->stageIRQ();
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Update the attached 8910 chip(s) */
|
|
||||||
ay8910[0].update(cycles);
|
|
||||||
}
|
|
||||||
|
|
@ -1,67 +0,0 @@
|
|||||||
#ifndef __SY6522_H
|
|
||||||
#define __SY6522_H
|
|
||||||
|
|
||||||
#include <stdint.h>
|
|
||||||
|
|
||||||
#include "ay8910.h"
|
|
||||||
|
|
||||||
// 6522 interface registers
|
|
||||||
enum {
|
|
||||||
SY_ORB = 0x00, // ORB
|
|
||||||
SY_ORA = 0x01, // ORA
|
|
||||||
SY_DDRB = 0x02, // DDRB
|
|
||||||
SY_DDRA = 0x03, // DDRA
|
|
||||||
SY_TMR1L = 0x04, // TIMER1L_COUNTER
|
|
||||||
SY_TMR1H = 0x05, // TIMER1H_COUNTER
|
|
||||||
SY_TMR1LL = 0x06, // TIMER1L_LATCH
|
|
||||||
SY_TMR1HL = 0x07, // TIMER1H_LATCH
|
|
||||||
SY_TMR2L = 0x08, // TIMER2L
|
|
||||||
SY_TMR2H = 0x09, // TIMER2H
|
|
||||||
SY_SS = 0x0a, // SERIAL_SHIFT
|
|
||||||
SY_ACR = 0x0b, // ACR
|
|
||||||
SY_PCR = 0x0c, // PCR
|
|
||||||
SY_IFR = 0x0d, // IFR
|
|
||||||
SY_IER = 0x0e, // IER
|
|
||||||
SY_ORANOHS = 0x0f // ORA_NO_HS
|
|
||||||
};
|
|
||||||
|
|
||||||
// IFR and IER share the names of all but the high bit
|
|
||||||
enum {
|
|
||||||
SY_IR_CA2 = 1,
|
|
||||||
SY_IR_CA1 = 2,
|
|
||||||
SY_IR_SHIFTREG = 4,
|
|
||||||
SY_IR_CB2 = 8,
|
|
||||||
SY_IR_CB1 = 16,
|
|
||||||
SY_IR_TIMER2 = 32,
|
|
||||||
SY_IR_TIMER1 = 64,
|
|
||||||
SY_IER_SETCLEAR = 128,
|
|
||||||
SY_IFR_IRQ = 128
|
|
||||||
};
|
|
||||||
|
|
||||||
class SY6522 {
|
|
||||||
public:
|
|
||||||
SY6522();
|
|
||||||
|
|
||||||
uint8_t read(uint8_t address);
|
|
||||||
void write(uint8_t address, uint8_t val);
|
|
||||||
|
|
||||||
void update(uint32_t cycles);
|
|
||||||
|
|
||||||
private:
|
|
||||||
uint8_t ORB; // port B
|
|
||||||
uint8_t ORA; // port A
|
|
||||||
uint8_t DDRB; // data direction register
|
|
||||||
uint8_t DDRA; //
|
|
||||||
uint16_t T1_CTR; // counters
|
|
||||||
uint16_t T1_CTR_LATCH;
|
|
||||||
uint16_t T2_CTR;
|
|
||||||
uint16_t T2_CTR_LATCH;
|
|
||||||
uint8_t ACR; // Aux Control Register
|
|
||||||
uint8_t PCR; // Peripheral Control Register
|
|
||||||
uint8_t IFR; // Interrupt Flag Register
|
|
||||||
uint8_t IER; // Interrupt Enable Register
|
|
||||||
|
|
||||||
AY8910 ay8910[1]; // FIXME: an array in case we support more than one ... ?
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif
|
|
@ -1 +0,0 @@
|
|||||||
../apple/sy6522.cpp
|
|
@ -1 +0,0 @@
|
|||||||
../apple/sy6522.h
|
|
@ -226,7 +226,6 @@ void runCPU()
|
|||||||
((AppleVM *)g_vm)->cpuMaintenance(g_cpu->cycles);
|
((AppleVM *)g_vm)->cpuMaintenance(g_cpu->cycles);
|
||||||
g_speaker->maintainSpeaker(g_cpu->cycles);
|
g_speaker->maintainSpeaker(g_cpu->cycles);
|
||||||
|
|
||||||
|
|
||||||
// The CPU of the Apple //e ran at 1.023 MHz. Adjust when we think
|
// The CPU of the Apple //e ran at 1.023 MHz. Adjust when we think
|
||||||
// the next instruction should run based on how long the execution
|
// the next instruction should run based on how long the execution
|
||||||
// was ((1000/1023) * numberOfCycles) - which is about 97.8%.
|
// was ((1000/1023) * numberOfCycles) - which is about 97.8%.
|
||||||
@ -252,6 +251,19 @@ void loop()
|
|||||||
|
|
||||||
// Only redraw if the CPU is caught up; and then we'll suspend the
|
// Only redraw if the CPU is caught up; and then we'll suspend the
|
||||||
// CPU to draw a full frame.
|
// CPU to draw a full frame.
|
||||||
|
|
||||||
|
// Note that this breaks audio, b/c it's real-time and requires the
|
||||||
|
// CPU running to change the audio line's value. So we need to EITHER
|
||||||
|
//
|
||||||
|
// - delay the audio line by at least the time it takes for one
|
||||||
|
// display update, OR
|
||||||
|
// - lock display updates so the CPU can update the memory, but we
|
||||||
|
// keep drawing what was going to be displayed
|
||||||
|
//
|
||||||
|
// The Timer1.stop()/start() is bad. Using it, the display doesn't
|
||||||
|
// tear; but the audio is also broken. Taking it out, audio is good
|
||||||
|
// but the display tears.
|
||||||
|
|
||||||
Timer1.stop();
|
Timer1.stop();
|
||||||
g_vm->vmdisplay->needsRedraw();
|
g_vm->vmdisplay->needsRedraw();
|
||||||
AiieRect what = g_vm->vmdisplay->getDirtyRect();
|
AiieRect what = g_vm->vmdisplay->getDirtyRect();
|
||||||
|
Loading…
Reference in New Issue
Block a user