Some preliminary work on ASC (Apple Sound Chip) emulation
This commit is contained in:
parent
b936ace3eb
commit
3bc6aed00a
|
@ -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);
|
||||
|
|
|
@ -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");
|
||||
|
|
|
@ -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
|
||||
|
|
199
core/sound.c
199
core/sound.c
|
@ -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, doesn’t preserve any written bits (doesn’t 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
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
*/
|
||||
|
||||
|
||||
|
|
Loading…
Reference in New Issue