From 3bc6aed00a0e352f0b4ef5a36b6fc900f8b91a1c Mon Sep 17 00:00:00 2001 From: Peter Rutenbar Date: Mon, 24 Aug 2015 22:41:52 -0400 Subject: [PATCH] Some preliminary work on ASC (Apple Sound Chip) emulation --- core/core_api.c | 3 +- core/mem.c | 4 +- core/shoebill.h | 26 ++++++- core/sound.c | 199 ++++++++++++++++++++++++++++++++++++++++++++---- 4 files changed, 211 insertions(+), 21 deletions(-) diff --git a/core/core_api.c b/core/core_api.c index 0ba4029..f4ad12b 100644 --- a/core/core_api.c +++ b/core/core_api.c @@ -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); diff --git a/core/mem.c b/core/mem.c index 923d986..b62e815 100644 --- a/core/mem.c +++ b/core/mem.c @@ -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"); diff --git a/core/shoebill.h b/core/shoebill.h index dfc4746..ad4f630 100644 --- a/core/shoebill.h +++ b/core/shoebill.h @@ -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 diff --git a/core/sound.c b/core/sound.c index 872bb8c..188e618 100644 --- a/core/sound.c +++ b/core/sound.c @@ -24,32 +24,128 @@ */ #include +#include #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; -} \ No newline at end of file +} + + + + +/* +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 + + + + + + */ + +