Skip to content

Commit

Permalink
v0.5! reload latest SNDH zip archive, some music bug-fixes
Browse files Browse the repository at this point in the history
  • Loading branch information
arnaud-carre committed Aug 21, 2023
1 parent 3d9cfcb commit cd57cf2
Show file tree
Hide file tree
Showing 9 changed files with 154 additions and 78 deletions.
123 changes: 95 additions & 28 deletions AtariAudio/AtariMachine.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -12,11 +12,16 @@

#define D_DUMP_READ 0
#define D_DUMP_WRITE 0
static const uint32_t D_DUMP_READ_AD1 = 0xfffa00;
static const uint32_t D_DUMP_READ_AD2 = 0xfffaff;
static const uint32_t D_DUMP_WRITE_AD1 = 0xfffa00;
static const uint32_t D_DUMP_WRITE_AD2 = 0xfffaff;
#if (D_DUMP_READ|D_DUMP_WRITE)
#include <stdio.h>
#endif

static AtariMachine* gCurrentMachine = NULL;
static const uint32_t ivector[5] = { 0x134,0x120,0x114,0x110,0x13c };

unsigned int m68k_read_memory_8(unsigned int address)
{
Expand Down Expand Up @@ -69,7 +74,7 @@ unsigned int AtariMachine::memRead8(unsigned int address)
else if ((address >= 0xff8900) && (address < 0xff8926))
r = m_SteDac.Read8(address - 0xff8900);
#if D_DUMP_READ
if ((address >= 0xff8201) && (address <= 0xff820d))
if ((address >= D_DUMP_READ_AD1) && (address <= D_DUMP_READ_AD2))
{
uint32_t pc = m68k_get_reg(NULL, M68K_REG_PC);
printf("$%06x: move.b $%06x,d0 ( =#$%02x )\n", pc, address, r);
Expand All @@ -91,7 +96,7 @@ unsigned int AtariMachine::memRead16(unsigned int address)
else if ((address >= 0xff8900) && (address < 0xff8926))
r = m_SteDac.Read16(address - 0xff8900);
#if D_DUMP_READ
if ((address >= 0xff8201) && (address <= 0xff820d))
if ((address >= D_DUMP_READ_AD1) && (address <= D_DUMP_READ_AD2))
{
uint32_t pc = m68k_get_reg(NULL, M68K_REG_PC);
printf("$%06x: move.w $%06x,d0 ( =#$%04x )\n", pc, address, r);
Expand All @@ -109,7 +114,7 @@ void AtariMachine::memWrite8(unsigned int address, unsigned int value)
return;
}
#if D_DUMP_WRITE
if ((address >= 0xff8201) && (address <= 0xff820d))
if ((address >= D_DUMP_WRITE_AD1) && (address <= D_DUMP_WRITE_AD2))
{
uint32_t pc = m68k_get_reg(NULL, M68K_REG_PC);
printf("$%06x: move.b #$%02x,$%06x\n", pc, value, address);
Expand All @@ -133,7 +138,7 @@ void AtariMachine::memWrite16(unsigned int address, unsigned int value)
return;
}
#if D_DUMP_WRITE
if ((address >= 0xff8201) && (address <= 0xff820d))
if ((address >= D_DUMP_WRITE_AD1) && (address <= D_DUMP_WRITE_AD2))
{
uint32_t pc = m68k_get_reg(NULL, M68K_REG_PC);
printf("$%06x: move.w #$%04x,$%06x\n", pc, value, address);
Expand Down Expand Up @@ -196,36 +201,99 @@ extern "C"
}
}

void AtariMachine::TrapInstructionCallback(int v)
void AtariMachine::Gemdos(int func, uint32_t a7)
{
if (1 == v)
{ // gemdos
int a7 = m68k_get_reg(NULL, M68K_REG_SP);
int func = m68k_read_memory_16(a7);
switch (func)
{
case 0x48: // MALLOC
{
// very basic incremental allocator (required by Maxymizer player)
int size = m68k_read_memory_32(a7 + 2);
m68k_set_reg(M68K_REG_D0, m_NextGemdosMallocAd);
m_NextGemdosMallocAd = (m_NextGemdosMallocAd + size + 1)&(-2);
assert(m_NextGemdosMallocAd <= RAM_SIZE);
}
switch (func)
{
case 0x48: // MALLOC
{
// very basic incremental allocator (required by Maxymizer player)
int size = m68k_read_memory_32(a7 + 2);
m68k_set_reg(M68K_REG_D0, m_NextGemdosMallocAd);
m_NextGemdosMallocAd = (m_NextGemdosMallocAd + size + 1)&(-2);
assert(m_NextGemdosMallocAd <= RAM_SIZE);
}
break;
case 0x30: // system version
{
m68k_set_reg(M68K_REG_D0, 0x0000); // 0.15 : TOS 1.04 & 1.06
}
break;

default:
assert(false); // unsupported GEMDOS function
break;
case 0x30: // system version
}
}

void AtariMachine::XbiosTimerSet(int ctrlPort, int dataPort, int enablePort, int bit, int mask, int ctrlValue, int dataValue)
{
const uint8_t back = m_Mfp.Read8(ctrlPort)&mask;
m_Mfp.Write8(ctrlPort, back | 0x0);
m_Mfp.Write8(dataPort, dataValue);
m_Mfp.Write8(ctrlPort, back | ctrlValue);
// seems Atari BIOS always enable the timer (even when switching it off)
m_Mfp.Write8(enablePort, m_Mfp.Read8(enablePort) | (1 << bit));
m_Mfp.Write8(enablePort+12, m_Mfp.Read8(enablePort+12) | (1 << bit));
}

void AtariMachine::XBios(int func, uint32_t a7)
{
switch (func)
{
case 31:
{
uint16_t timer = m68k_read_memory_16(a7 + 2);
uint16_t ctrlWord = m68k_read_memory_16(a7 + 4);
uint16_t dataWord = m68k_read_memory_16(a7 + 6);
uint32_t vector = m68k_read_memory_32(a7 + 8);
if (timer < 4)
{
m68k_set_reg(M68K_REG_D0, 0x0000); // 0.15 : TOS 1.04 & 1.06
m68k_write_memory_32(ivector[timer], vector);
switch (timer)
{
case 0: // A
XbiosTimerSet(0x19, 0x1f, 0x07, 5, 0x00, ctrlWord, dataWord);
break;
case 1: // B
XbiosTimerSet(0x1b, 0x21, 0x07, 0, 0x00, ctrlWord, dataWord);
break;
case 2: // C
XbiosTimerSet(0x1d, 0x23, 0x09, 5, 0x0f, (ctrlWord&0xf)<<4, dataWord);
break;
case 3: // D
XbiosTimerSet(0x1d, 0x25, 0x09, 4, 0xf0, ctrlWord&0xf, dataWord);
break;
default:
assert(false); // unknown timer!
break;
}
}
}
break;
default:
assert(false); // unsupported XBIOS function
break;

default:
assert(false); // unsupported GEMDOS function
}
}
else
}

void AtariMachine::TrapInstructionCallback(int v)
{

int a7 = m68k_get_reg(NULL, M68K_REG_SP);
int func = m68k_read_memory_16(a7);

switch (v)
{
case 1:
Gemdos(func, a7);
break;
case 14:
XBios(func, a7);
break;
default:
assert(false); // unsupported TRAP #n
break;
}
}

Expand Down Expand Up @@ -333,11 +401,10 @@ int16_t AtariMachine::ComputeNextSample(uint32_t* pSampleDebugInfo)
int16_t out = (int16_t)level;

// tick 4 Atari timers, maybe one of them is running
for (int t = 0; t < 4; t++)
for (int t = 0; t < 4+1; t++)
{
if (m_Mfp.Tick(t))
{
static const uint32_t ivector[4] = { 0x134,0x120,0x114,0x110 };
uint32_t pc = m68k_read_memory_32(ivector[t]);
ConfigureReturnByRte();
m_Ym2149.InsideTimerIrq(true);
Expand Down
3 changes: 3 additions & 0 deletions AtariAudio/AtariMachine.h
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,9 @@ class AtariMachine
void ConfigureReturnByRts();
void ConfigureReturnByRte();
bool JmpBinary(int pc, int timeOut50Hz);
void Gemdos(int func, uint32_t a7);
void XBios(int func, uint32_t a7);
void XbiosTimerSet(int ctrlPort, int dataPort, int enablePort, int bit, int mask, int ctrlValue, int dataValue);

uint8_t* m_RAM;
int m_ExitCode;
Expand Down
13 changes: 12 additions & 1 deletion AtariAudio/Mk68901.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,18 @@ void Mk68901::Reset(uint32_t hostReplayRate)
for (int i = 0; i < 256; i++)
m_regs[i] = 0;

for (int t = 0; t < 4; t++)
for (int t = 0; t < 5; t++)
m_timers[t].Reset();

// by default on Atari OS timer C is enable (and even running, but we just enable)
m_timers[eTimerC].enable = true;
m_timers[eTimerC].mask = true;

// gpi7 is not really a timer, "simulate" an event type timer with count=1 to make the code simpler
m_timers[eGpi7].controlRegister = 1<<3; // simulate event mode
m_timers[eGpi7].dataRegisterInit = 1; // event count always 1
m_timers[eGpi7].dataRegister = 1;

m_hostReplayRate = hostReplayRate;
}

Expand Down Expand Up @@ -83,6 +92,7 @@ void Mk68901::Write8(int port,uint8_t data)
case 0x07:
m_timers[eTimerA].SetER((data&(1 << 5)) != 0);
m_timers[eTimerB].SetER((data&(1 << 0)) != 0);
m_timers[eGpi7].SetER((data&(1 << 7)) != 0);
break;
case 0x09:
m_timers[eTimerC].SetER((data&(1 << 5)) != 0);
Expand All @@ -91,6 +101,7 @@ void Mk68901::Write8(int port,uint8_t data)
case 0x13:
m_timers[eTimerA].SetMR((data&(1 << 5)) != 0);
m_timers[eTimerB].SetMR((data&(1 << 0)) != 0);
m_timers[eGpi7].SetMR((data&(1 << 7)) != 0);
break;
case 0x15:
m_timers[eTimerC].SetMR((data&(1 << 5)) != 0);
Expand Down
7 changes: 4 additions & 3 deletions AtariAudio/Mk68901.h
Original file line number Diff line number Diff line change
Expand Up @@ -19,14 +19,15 @@ class Mk68901
eTimerA = 0,
eTimerB,
eTimerC,
eTimerD
eTimerD,
eGpi7,
};

uint8_t Read8(int port);
uint16_t Read16(int port);
void Write8(int port, uint8_t data); // Write a 8bits value to a MFP register
void Write16(int port, uint16_t data); // Write a 16bits value on MFP register
void SetExternalEvent(eTimerName timerId) { m_timers[timerId].externalEvent = true; }
void SetSteDacExternalEvent() { m_timers[eTimerA].externalEvent = true; m_timers[eGpi7].externalEvent = true; }

private:
struct Timer
Expand All @@ -52,6 +53,6 @@ class Mk68901

uint32_t m_hostReplayRate;
uint8_t m_regs[256];
Timer m_timers[4];
Timer m_timers[5];
};

2 changes: 1 addition & 1 deletion AtariAudio/SteDac.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -144,7 +144,7 @@ int16_t SteDac::ComputeNextSample(const int8_t* atariRam, uint32_t ramSize, Mk68
m_samplePtr += mono ? 1 : 2;
if (m_samplePtr == m_sampleEndPtr)
{
mfp.SetExternalEvent(Mk68901::eTimerA);
mfp.SetSteDacExternalEvent();
FetchSamplePtr();
if ((m_regs[0x1] & (1 << 1)) == 0)
{
Expand Down
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ ATARI-ST SNDH ZIP Archive music browser/player by [Leonard/Oxygene](https://twit

# Versions

- v0.5 : reload last loaded SNDH archive, bug fixes for some SNDH
- v0.4 : per voice visualization oscilloscopes, 2MiB emulated Atari machine, AtariAudio API cleanup, some optimizations
- v0.3 : WAV export, play/pause button, and low CPU usage when app minimized
- v0.2 : SNDH music are time seekable! enjoy!
Expand Down
Loading

0 comments on commit cd57cf2

Please sign in to comment.