Some preliminary work on ASC (Apple Sound Chip) emulation

This commit is contained in:
Peter Rutenbar 2015-08-24 22:41:52 -04:00
parent b936ace3eb
commit 3bc6aed00a
4 changed files with 211 additions and 21 deletions

View File

@ -737,6 +737,7 @@ uint32_t shoebill_initialize(shoebill_config_t *config)
init_adb_state();
init_scsi_bus_state();
init_iwm_state();
init_asc_state();
/* Invalidate the pc cache */
invalidate_pccache();
@ -1020,7 +1021,7 @@ void slog(const char *fmt, ...)
{
va_list args;
return ;
// return ;
va_start(args, fmt);
vprintf(fmt, args);

View File

@ -77,7 +77,7 @@ void _physical_get_io (void)
return ;
case 0x50014000 ... 0x50015fff: // Sound
// slog("physical_get: got read to sound\n");
shoe.physical_dat = sound_dma_read_raw(shoe.physical_addr - 0x50014000, shoe.physical_size);
shoe.physical_dat = sound_dma_read_raw(shoe.physical_addr & 0x1fff, shoe.physical_size);
// slog("soundsound read : register 0x%04x sz=%u\n",
//shoe.physical_addr - 0x50014000, shoe.physical_size);
// shoe.physical_dat = 0;
@ -205,7 +205,7 @@ void _physical_set_io (void)
scsi_dma_write(shoe.physical_dat);
return ;
case 0x50014000 ... 0x50015fff: // Sound
sound_dma_write_raw(shoe.physical_addr - 0x50014000, shoe.physical_size, shoe.physical_dat);
sound_dma_write_raw(shoe.physical_addr & 0x1fff, shoe.physical_size, shoe.physical_dat);
// slog("soundsound write: register 0x%04x sz=%u dat=0x%x\n",
// shoe.physical_addr - 0x50014000, shoe.physical_size, (uint32_t)shoe.physical_dat);
// slog("physical_set: got write to sound\n");

View File

@ -417,6 +417,27 @@ typedef struct {
dbg_breakpoint_t *breakpoints;
} debugger_state_t;
// Sound (Apple Sound Chip)
void sound_dma_write_raw(uint16_t addr, uint8_t sz, uint32_t data);
uint32_t sound_dma_read_raw(uint16_t addr, uint8_t sz);
void init_asc_state(void);
typedef struct __attribute__ ((__packed__)) {
uint8_t buf[0x800];
uint8_t version; // read-only
uint8_t asc_mode;
uint8_t channel_ctrl;
uint8_t fifo_ctrl;
uint8_t fifo_intr; // read-only
uint8_t unknown1;
uint8_t volume_ctrl;
uint8_t clock_ctrl;
uint8_t unknown2[8];
uint16_t left_ptr, right_ptr;
} apple_sound_chip_registers_t;
typedef enum {
adb_talk,
adb_listen,
@ -820,6 +841,7 @@ typedef struct {
pram_state_t pram;
keyboard_state_t key;
mouse_state_t mouse;
apple_sound_chip_registers_t asc;
iwm_state_t iwm;
@ -1064,8 +1086,4 @@ uint32_t nubus_ethernet_read_func(uint32_t, uint32_t, uint8_t);
void nubus_ethernet_write_func(uint32_t, uint32_t, uint32_t, uint8_t);
void nubus_ethernet_destroy_func(uint8_t);
// Sound (Apple Sound Chip)
void sound_dma_write_raw(uint16_t addr, uint8_t sz, uint32_t data);
uint32_t sound_dma_read_raw(uint16_t addr, uint8_t sz);
#endif // _SHOEBILL_H

View File

@ -24,32 +24,128 @@
*/
#include <assert.h>
#include <string.h>
#include "../core/shoebill.h"
void init_asc_state(void)
{
memset(&shoe.asc, 0, sizeof(shoe.asc));
shoe.asc.version = 0x00; // My Mac II's ASC reports 0x00 as its version.
// From the ROM, it looks like other Mac II ASC masks have different version numbers
}
static uint8_t sound_dma_read_byte(uint16_t addr)
{
if (addr == 0x804)
return 0xff;
apple_sound_chip_registers_t *asc = &shoe.asc;
if (addr < 0x800) {
}
switch (addr) {
case 0x800: // Version
return asc->version;
break;
case 0x801: // ASC-mode
return asc->asc_mode;
break;
case 0x802: // Channel control
return asc->channel_ctrl;
break;
case 0x803: // FIFO control
return asc->fifo_ctrl;
break;
case 0x804: // FIFO interrupt
//return asc->fifo_intr;
return 0xff;
break;
case 0x805: // Unknown (??)
return asc->unknown1;
break;
case 0x806: // Volume control
return asc->volume_ctrl;
break;
case 0x807: // Clock control
return asc->clock_ctrl;
break;
}
return 0;
}
static void sound_dma_write_byte(uint16_t addr, uint8_t data)
{
if (addr >= 0x800) {
// registers
}
else if (addr >= 0x400) {
// Buf B
apple_sound_chip_registers_t *asc = &shoe.asc;
if (addr < 0x800) { // buf_a/b
if (asc->asc_mode == 1) {
// PCM mode (FIFO is append-only)
if (asc->channel_ctrl & 2) {
// stereo mode - each channel has its own buffer pointer
}
else {
// mono mode
}
}
else {
// Off or wavetable mode (FIFO is random access)
asc->buf[asc->left_ptr] = data;
asc->left_ptr = (asc->left_ptr + 1) & 0x7ff;
}
}
else {
// Buf A
/*FILE *f = fopen("buf_a.dmp", "ab");
if (f) {
fwrite(&data, 1, 1, f);
fclose(f);
}*/
switch (addr) {
case 0x800: // Version
// Version is read-only
break;
case 0x801: // ASC-mode
// ASC version 0x00 preserves the low 2 bits
asc->asc_mode = data & 0x03;
assert(asc->asc_mode != 3); // mode-3 produces noise, but isn't deterministic
break;
case 0x802: // Channel control
// ASC version 0x00 preserves the high bit and low 2 bits
asc->channel_ctrl = data & 0x83;
break;
case 0x803: // FIFO control
// ASC version 0x00 preserves the low 2 bits
asc->fifo_ctrl = data & 0x83;
break;
case 0x804: // FIFO interrupt
// FIFO interrupt is read-only
break;
case 0x805: // unknown (???)
// ASC version 0x00 preserves the high bit and low 4 bits
// (But what does it do?)
asc->unknown1 = data & 0x8f;
break;
case 0x806: // Volume control
// ASC version 0x00 preserves the high 6 bits
asc->volume_ctrl = data & 0xfc;
break;
case 0x807: // Clock control
// ASC version 0x00 preserves the low 2 bits
asc->clock_ctrl = data & 0x03;
break;
}
}
}
@ -73,4 +169,79 @@ uint32_t sound_dma_read_raw(uint16_t addr, uint8_t sz)
}
return result;
}
}
/*
ASC notes:
buf_a (0x000-0x3ff) -> left
buf_b (0x400-0x7ff) -> right
writing to any address in buf_a or buf_b appends to the end pointer in the ring buffer (ignoring the address)
reading from any address returns... the currently-being-read byte? Or the about-to-be-overwritten byte?
(def one or the other)
- Update: MODE=0: You can do regular random read/write access to buf_a/b when MODE=0.
MODE=1: Writing anywhere within the buffer automatically appends to the end of the ring buffer
For stereo mode, writing between 0-0x3ff appends to buf_a, 0x400-0x7ff to buf_b
Reading anywhere in the buffer is strange - it seems non-deterministic.
Update 2: no wait, it's returning the byte at buf_b's ring pointer, does it always do that?
Update 3: yes, it looks like reading anywhere returns the byte at buf_b's pointer in stereo mode,
and buf_a's pointer in mono mode
MODE=2: Same as MODE=0 (?)
- ASC maintains two distinct ring buffer pointers for stereo mode
0x800 - Version (?) MacII only ever seems to TST.B it
(READ ONLY)
$00 -> My Mac II's ASC's version. According to the Mac II rom, there seem to be other masks with non-0x00 versions.
$b0 -> something more advanced than regular ASC (something with registers in the $fxx range)
0x801 - Mode (?) 0 == no output, 1 == PCM, 2 == wavetable
- Preserves low 2 bits, ignores high 6 bits
0x802 - Channel selector
Preserves mask 0x83 (high bit, low 2 bits)
- High bit is set if engine overflow (according to MESS)
- Low bits, 0x?2 -> stereo output (buf_a -> left, buf_b -> right)
0x?0 -> Mono output (from buf_a)
- Switching to stereo from mono produces a blip of sound in the right ear, unless the fifo has been cleared (buf_b), (or unless there was nothing in buf_b to start with)
0x803 - Fifo control (cycle 0x80 to reset the internal FIFO pointer (pointers?))
Preserves mask 0x83 (high bit, low 2 bits)
0x804 - Fifo interrupt status
(READ ONLY, doesnt preserve any written bits (doesnt acknowledge writes at all?))
0x805 - ???
- Preserves bits at 0x8F, (high bit, low 4 bits), doesn't seem to do anything
0x806 - Volume control (high 3 bits)
Preserves top 6 bits, ignores bottom 2 bits. (Only top 3 bits control volume)
0x807 - Clock rate select (0, 2, or 3, I think)
0x00 -> 11127hz
0x01 -> Illegal???
0x02 -> 11025hz
0x03 -> 22050hz
Writes to fifo_a/b(?) seem to block for clock rates 0, 2, and 3, but not 1. The speaker clicks like the sound chip is turning off when you set clock to 0x01.
ASC has more registers past 0x807 for wave table control
*/