diff --git a/ZZ9000_proto.sdk/ZZ9000OS/src/ax.c b/ZZ9000_proto.sdk/ZZ9000OS/src/ax.c index 6adef6ee12bb6ff7407747af5413f0db96ea342d..eb61e8e4c58d4c9d3df45626ae55e9df6d2bbb54 100644 --- a/ZZ9000_proto.sdk/ZZ9000OS/src/ax.c +++ b/ZZ9000_proto.sdk/ZZ9000OS/src/ax.c @@ -10,6 +10,9 @@ #include "mntzorro.h" #include "sleep.h" #include "stdlib.h" +#include "ax.h" +#include "memorymap.h" +#include "xtime_l.h" #define IIC2_DEVICE_ID XPAR_XIICPS_1_DEVICE_ID #define IIC2_SCLK_RATE 100000 @@ -21,6 +24,9 @@ XI2s_Rx i2srx; XAudioFormatter audio_formatter; XAudioFormatter audio_formatter_rx; +static uint8_t* audio_tx_buffer = (uint8_t*)AUDIO_TX_BUFFER_ADDRESS; +static uint8_t* audio_rx_buffer = (uint8_t*)AUDIO_RX_BUFFER_ADDRESS; + int adau_write16(u8 i2c_addr, u16 addr, u16 value) { XIicPs* iic = &Iic2; int status; @@ -183,100 +189,18 @@ int adau_read24(u8 i2c_addr, u16 addr, u8* buffer) { void program_adau(u8* program, u32 program_len, u8* params, u32 param_len) { for (u32 i = 0; i < program_len; i+=5) { int res = adau_write40(0x34, 1024+i/5, &program[i]); - printf("[adau_write40] %lx: %d\n", i, res); + if (res != 0) printf("[adau_write40] %lx: %d\n", i, res); } for (u32 i = 0; i < param_len; i+=4) { int res = adau_write32(0x34, 0+i/4, ¶ms[i]); - printf("[adau_write32] %lx: %d\n", i, res); + if (res != 0) printf("[adau_write32] %lx: %d\n", i, res); } } -// returns 1 if adau1701 found, otherwise 0 -int audio_adau_init(uint32_t* audio_buffer) { - XIicPs_Config* i2c_config; - i2c_config = XIicPs_LookupConfig(IIC2_DEVICE_ID); - int status = XIicPs_CfgInitialize(&Iic2, i2c_config, i2c_config->BaseAddress); - printf("[adau] XIicPs_CfgInitialize 2: %d\n", status); - usleep(10000); - printf("[adau] XIicPs 2 is ready: %lx\n", Iic2.IsReady); - status = XIicPs_SelfTest(&Iic2); - printf("[adau] XIicPs_SelfTest: %x\n", status); - - if (status != 0) { - printf("[adau] I2C instance 2 self test failed."); - return 0; - } - - status = XIicPs_SetSClk(&Iic2, IIC2_SCLK_RATE); - printf("[adau] XIicPs_SetSClk: %x\n", status); - - u8 rbuf[5]; - u8 i = 0x34; - - //usleep(10000); - // DSP core control: set ADM, DAM, CR - status = adau_write16(i, 2076, (1<<4)|(1<<3)|(1<<2)); - if (status == 0) { - printf("[adau] write DSP core control: %d\n", i); - printf("[adau] ZZ9000AX detected."); - } else { - printf("[adau] ZZ9000AX not detected."); - return 0; - } - - status = adau_read16(i, 2076, rbuf); - if (status == 0) { - printf("[adau] read: %d %x %x\n", i, rbuf[0], rbuf[1]); - } - - // DAC setup: DS = 01 - status = adau_write16(i, 2087, 1); - printf("[adau] write DAC setup: %d\n", status); - - rbuf[0] = 0; - rbuf[1] = 0; - - status = adau_read16(i, 2087, rbuf); - printf("[adau] read from 2087: %02x%02x (status: %d)\n", rbuf[0], rbuf[1], status); - - program_adau(Program_Data_IC_1, sizeof(Program_Data_IC_1), Param_Data_IC_1, sizeof(Param_Data_IC_1)); - - // TODO: OBP/OLRP - u16 MS = 1<<11; // clock master output - //u16 OBF = (0<<10)|(0<<9); // bclock = 49.152/16 = mclk/4 = 3.072mhz - u16 OBF = (1<<10)|(0<<9); // bclock = 49.152/4 = mclk = 12.288mhz - u16 OLF = (0<<8)|(0<<7); // lrclock = 49.152/1024 = word clock = 48khz?! - u16 MSB = 0; // msb 1 - u16 OWL = 1<<1; // 16 bit - status = adau_write16(i, 0x081e, MS|OBF|OLF|MSB|OWL); - printf("[adau] write serial output control: %d\n", status); - - u32 MP0 = 1<<2; // MP02 digital input 0 - u32 MP1 = 1<<6; // - u32 MP2 = 1<<10; // - u32 MP3 = 1<<14; // - u32 MP4 = 1<<18; // MP42 serial clock in - u32 MP5 = 1<<22; // MP52 serial clock in - - u32 MP6 = 1<<2; // - u32 MP7 = 1<<6; // - u32 MP8 = 1<<10; // - u32 MP9 = 1<<14; // - u32 MP10 = 1<<18; // MP102 set (serial clock out) - u32 MP11 = 1<<22; // MP112 set (serial clock out) - status = adau_write24(i, 0x0820, MP0|MP1|MP2|MP3|MP4|MP5); - printf("[adau] write MP control 0x820: %d\n", status); - status = adau_write24(i, 0x0821, MP6|MP7|MP8|MP9|MP10|MP11); - printf("[adau] write MP control 0x821: %d\n", status); - - status = adau_read24(i, 0x0820, rbuf); - printf("[adau] read from 0x820: %02x%02x%02x (status: %d)\n", rbuf[0], rbuf[1], rbuf[2], status); - status = adau_read24(i, 0x0821, rbuf); - printf("[adau] read from 0x821: %02x%02x%02x (status: %d)\n", rbuf[0], rbuf[1], rbuf[2], status); - +void audio_init_i2s() { XI2stx_Config* i2s_config = XI2s_Tx_LookupConfig(XPAR_XI2STX_0_DEVICE_ID); - status = XI2s_Tx_CfgInitialize(&i2s, i2s_config, i2s_config->BaseAddress); + int status = XI2s_Tx_CfgInitialize(&i2s, i2s_config, i2s_config->BaseAddress); printf("[adau] I2S_TX cfg status: %d\n", status); @@ -297,7 +221,7 @@ int audio_adau_init(uint32_t* audio_buffer) { XAUD_FORMATTER_CTRL + XAUD_FORMATTER_MM2S_OFFSET, 0); XAudioFormatterHwParams af_params; - af_params.buf_addr = (u32)audio_buffer; + af_params.buf_addr = (u32)audio_tx_buffer; af_params.bits_per_sample = BIT_DEPTH_16; af_params.periods = AUDIO_NUM_PERIODS; // 1 second = 192000 bytes af_params.active_ch = 2; @@ -328,7 +252,7 @@ int audio_adau_init(uint32_t* audio_buffer) { XAUD_FORMATTER_CTRL + XAUD_FORMATTER_S2MM_OFFSET, 0); XAudioFormatterHwParams afrx_params; - afrx_params.buf_addr = (u32)AUDIO_RX_BUFFER_ADDRESS; + afrx_params.buf_addr = (u32)audio_rx_buffer; afrx_params.bits_per_sample = BIT_DEPTH_16; afrx_params.periods = AUDIO_NUM_PERIODS; // 1 second = 192000 bytes afrx_params.active_ch = 2; @@ -365,6 +289,95 @@ int audio_adau_init(uint32_t* audio_buffer) { printf("[adau] XI2s_Tx_Enable\n"); XAudioFormatterDMAStart(&audio_formatter); printf("[adau] XAudioFormatterDMAStart done.\n"); +} + +// returns 1 if adau1701 found, otherwise 0 +// set audio_tx_buffer and audio_rx_buffer before! +int audio_adau_init(int program_dsp) { + XIicPs_Config* i2c_config; + i2c_config = XIicPs_LookupConfig(IIC2_DEVICE_ID); + int status = XIicPs_CfgInitialize(&Iic2, i2c_config, i2c_config->BaseAddress); + printf("[adau] XIicPs_CfgInitialize 2: %d\n", status); + usleep(10000); + printf("[adau] XIicPs 2 is ready: %lx\n", Iic2.IsReady); + status = XIicPs_SelfTest(&Iic2); + printf("[adau] XIicPs_SelfTest: %x\n", status); + + if (status != 0) { + printf("[adau] I2C instance 2 self test failed."); + return 0; + } + + status = XIicPs_SetSClk(&Iic2, IIC2_SCLK_RATE); + printf("[adau] XIicPs_SetSClk: %x\n", status); + + u8 rbuf[5]; + u8 i = 0x34; + + //usleep(10000); + // DSP core control: set ADM, DAM, CR + status = adau_write16(i, 2076, (1<<4)|(1<<3)|(1<<2)); + if (status == 0) { + printf("[adau] write DSP core control: %d\n", i); + printf("\n[adau] ~~~~ ZZ9000AX detected. ~~~~\n\n"); + } else { + printf("[adau] ZZ9000AX not detected.\n"); + return 0; + } + + status = adau_read16(i, 2076, rbuf); + if (status == 0) { + printf("[adau] read: %d %x %x\n", i, rbuf[0], rbuf[1]); + } + + // DAC setup: DS = 01 + status = adau_write16(i, 2087, 1); + printf("[adau] write DAC setup: %d\n", status); + + rbuf[0] = 0; + rbuf[1] = 0; + + status = adau_read16(i, 2087, rbuf); + printf("[adau] read from 2087: %02x%02x (status: %d)\n", rbuf[0], rbuf[1], status); + + if (program_dsp) { + program_adau(Program_Data_IC_1, sizeof(Program_Data_IC_1), Param_Data_IC_1, sizeof(Param_Data_IC_1)); + } + + // TODO: OBP/OLRP + u16 MS = 1<<11; // clock master output + //u16 OBF = (0<<10)|(0<<9); // bclock = 49.152/16 = mclk/4 = 3.072mhz + u16 OBF = (1<<10)|(0<<9); // bclock = 49.152/4 = mclk = 12.288mhz + u16 OLF = (0<<8)|(0<<7); // lrclock = 49.152/1024 = word clock = 48khz?! + u16 MSB = 0; // msb 1 + u16 OWL = 1<<1; // 16 bit + status = adau_write16(i, 0x081e, MS|OBF|OLF|MSB|OWL); + printf("[adau] write serial output control: %d\n", status); + + u32 MP0 = 1<<2; // MP02 digital input 0 + u32 MP1 = 1<<6; // + u32 MP2 = 1<<10; // + u32 MP3 = 1<<14; // + u32 MP4 = 1<<18; // MP42 serial clock in + u32 MP5 = 1<<22; // MP52 serial clock in + + u32 MP6 = 1<<2; // + u32 MP7 = 1<<6; // + u32 MP8 = 1<<10; // + u32 MP9 = 1<<14; // + u32 MP10 = 1<<18; // MP102 set (serial clock out) + u32 MP11 = 1<<22; // MP112 set (serial clock out) + status = adau_write24(i, 0x0820, MP0|MP1|MP2|MP3|MP4|MP5); + printf("[adau] write MP control 0x820: %d\n", status); + status = adau_write24(i, 0x0821, MP6|MP7|MP8|MP9|MP10|MP11); + printf("[adau] write MP control 0x821: %d\n", status); + + status = adau_read24(i, 0x0820, rbuf); + printf("[adau] read from 0x820: %02x%02x%02x (status: %d)\n", rbuf[0], rbuf[1], rbuf[2], status); + status = adau_read24(i, 0x0821, rbuf); + printf("[adau] read from 0x821: %02x%02x%02x (status: %d)\n", rbuf[0], rbuf[1], rbuf[2], status); + + audio_init_i2s(); return 1; } @@ -372,6 +385,20 @@ int audio_adau_init(uint32_t* audio_buffer) { static int interrupt_enabled_audio = 0; static uint32_t interrupt_waiting_audio = 0; +XTime debug_time_start = 0; + +void audio_debug_timer(int zdata) { + if (zdata == 0) { + XTime_GetTime(&debug_time_start); + } else { + XTime debug_time_stop; + XTime_GetTime(&debug_time_stop); + printf("%x;%09.2f us\n", (uint8_t)zdata, + 1.0 * (debug_time_stop-debug_time_start) / (COUNTS_PER_SECOND/1000000)); + XTime_GetTime(&debug_time_start); + } +} + int isra_count = 0; // audio formatter interrupt, triggered whenever a period is completed @@ -381,16 +408,17 @@ void isr_audio(void *dummy) { XAudioFormatter_WriteReg(XPAR_XAUDIOFORMATTER_0_BASEADDR, XAUD_FORMATTER_STS + XAUD_FORMATTER_MM2S_OFFSET, val); - if (isra_count++>100) { + if (isra_count++>1000) { printf("[isra]\n"); isra_count = 0; } if (interrupt_enabled_audio) { + audio_debug_timer(0); + interrupt_waiting_audio = 1; mntzorro_write(MNTZ_BASE_ADDR, MNTZORRO_REG2, (1 << 30) | 1); - usleep(1); mntzorro_write(MNTZ_BASE_ADDR, MNTZORRO_REG2, (1 << 30) | 0); } else { interrupt_waiting_audio = 0; @@ -402,6 +430,7 @@ uint32_t audio_get_interrupt() { } void audio_clear_interrupt() { + //printf("[clear] audio\n"); interrupt_waiting_audio = 0; } @@ -414,7 +443,7 @@ void isr_audio_rx(void *dummy) { XAudioFormatter_WriteReg(XPAR_XAUDIOFORMATTER_1_BASEADDR, XAUD_FORMATTER_STS + XAUD_FORMATTER_S2MM_OFFSET, val); - if (israrx_count++>100) { + if (israrx_count++>1000) { printf("[isra_rx]\n"); israrx_count = 0; } @@ -427,45 +456,96 @@ uint32_t audio_get_dma_transfer_count() { void audio_set_interrupt_enabled(int en) { printf("[audio] enable irq: %d\n", en); interrupt_enabled_audio = en; + + audio_silence(); } // offset = offset from audio tx buffer // returns audio_buffer_collision (1 or 0) -int audio_swab(int audio_scale, uint32_t offset) { +int audio_swab(int audio_buf_samples, uint32_t offset, int byteswap) { int audio_buffer_collision = 0; - uint16_t* data = (uint16_t*)(((void*)AUDIO_TX_BUFFER_ADDRESS)+offset); - - if (audio_scale > 1) { - // for lower freqs that are divisions of 48000Hz - int k = (3840/2)/audio_scale-1; - for (int i=3840/2-audio_scale; i>=0; i-=audio_scale) { - uint16_t s = __builtin_bswap16(data[k]); - data[i] = s; - for (int j=1; j<audio_scale; j++) { - data[i+j] = s; - } - k--; - } - } else { - // 48000Hz - for (int i=0; i<3840/2; i++) { + uint16_t* data = (uint16_t*)(audio_tx_buffer + offset); + int audio_freq = audio_buf_samples * 50; + + //printf("[audio:%d] play: %d +%lu\n", byteswap, audio_freq, offset); + + // byteswap + if (byteswap) { + for (int i=0; i < audio_buf_samples * 2; i++) { data[i] = __builtin_bswap16(data[i]); } } + // FIXME missing filter, wonky address calculation + // resample if other freq + if (audio_freq != 48000) { + resample_s16((int16_t*)(audio_tx_buffer + offset), + (int16_t*)(audio_tx_buffer+0x20000), audio_freq, 48000, audio_buf_samples); + memcpy(audio_tx_buffer + offset, audio_tx_buffer+0x20000, AUDIO_BYTES_PER_PERIOD); + } + u32 txcount = audio_get_dma_transfer_count(); // is the distance of reader (audio dma) and writer (amiga) in the ring buffer too small? // then signal this condition so amiga can adjust - if (abs(txcount-offset) < 3840) { + if (abs(txcount-offset) < AUDIO_BYTES_PER_PERIOD) { audio_buffer_collision = 1; - printf("[aswap] ring collision %d\n", abs(txcount-offset)); + //printf("[aswap] ring collision %d\n", abs(txcount-offset)); } else { audio_buffer_collision = 0; } - printf("[aswap] d-a: %ld scl: %d\n",txcount-offset,audio_scale); + if (audio_buffer_collision) { + printf("[aswap] d-a: %ld\n",txcount-offset); + } return audio_buffer_collision; } +uint32_t resample_s16(int16_t *input, int16_t *output, + int inSampleRate, int outSampleRate, uint32_t inputSize) { + const uint32_t channels = 2; + + //printf("[resample] %p -> %p (%d -> %d) %lu bytes\n", + // input, output, inSampleRate, outSampleRate, inputSize); + + uint32_t outputSize = 3840/4; // (uint32_t) (inputSize * (double) outSampleRate / (double) inSampleRate); + //outputSize -= outputSize % channels; + + double stepDist = ((double) inSampleRate / (double) outSampleRate); + const uint64_t fixedFraction = (1LL << 32); + const double normFixed = (1.0 / (1LL << 32)); + uint64_t step = ((uint64_t) (stepDist * fixedFraction + 0.5)); + uint64_t curOffset = 0; + + // HACK: glue at the end + input[inputSize*2] = input[(inputSize-1)*2]; + input[inputSize*2+1] = input[(inputSize-1)*2+1]; + + for (uint32_t i = 0; i < outputSize; i++) { + for (uint32_t c = 0; c < channels; c++) { + *output++ = (int16_t) (input[c] + (input[c + channels] - input[c]) * ( + (double) (curOffset >> 32) + ((curOffset & (fixedFraction - 1)) * normFixed))); + } + curOffset += step; + input += (curOffset >> 32) * channels; + curOffset &= (fixedFraction - 1); + } + return outputSize; +} + +void audio_set_tx_buffer(uint8_t* addr) { + printf("[audio] set tx buffer: %p\n", addr); + audio_tx_buffer = addr; + audio_init_i2s(); +} + +void audio_set_rx_buffer(uint8_t* addr) { + printf("[audio] set rx buffer: %p\n", addr); + audio_rx_buffer = addr; + audio_init_i2s(); +} + +void audio_silence() { + memset(audio_tx_buffer, 0, AUDIO_TX_BUFFER_SIZE); +} diff --git a/ZZ9000_proto.sdk/ZZ9000OS/src/ax.h b/ZZ9000_proto.sdk/ZZ9000OS/src/ax.h index 9bb074831a484f2c7f530ffe0f0bd3211ae4a3cf..1956fb1efff8458cc8bd0c9972a348290c0848ce 100644 --- a/ZZ9000_proto.sdk/ZZ9000OS/src/ax.h +++ b/ZZ9000_proto.sdk/ZZ9000OS/src/ax.h @@ -1,10 +1,14 @@ #include <stdint.h> -int audio_adau_init(uint32_t* audio_buffer); +int audio_adau_init(int program_dsp); void isr_audio(void *dummy); void isr_audio_rx(void *dummy); void audio_set_interrupt_enabled(int en); void audio_clear_interrupt(); uint32_t audio_get_interrupt(); uint32_t audio_get_dma_transfer_count(); -int audio_swab(int audio_scale, uint32_t offset); +int audio_swab(int audio_buf_samples, uint32_t offset, int byteswap); +void audio_set_tx_buffer(uint8_t* addr); +void audio_set_rx_buffer(uint8_t* addr); +uint32_t resample_s16(int16_t *input, int16_t *output, int inSampleRate, int outSampleRate, uint32_t inputSize); +void audio_silence(); diff --git a/ZZ9000_proto.sdk/ZZ9000OS/src/main.c b/ZZ9000_proto.sdk/ZZ9000OS/src/main.c index 84d2da7c99fcadeac9e8d4c45b09266f1738a710..195cc3bd3e63f6321f51c53d839e54aadb9c4117 100644 --- a/ZZ9000_proto.sdk/ZZ9000OS/src/main.c +++ b/ZZ9000_proto.sdk/ZZ9000OS/src/main.c @@ -71,7 +71,7 @@ void disable_reset_out() { XGpioPs_WritePin(&Gpio, output_pin, 0); usleep(10000); XGpioPs_WritePin(&Gpio, output_pin, 1); - print("[gpio] ethernet reset done.\n"); + print("[gpio] ethernet reset done.\r\n"); // FIXME int adau_reset = 11; @@ -81,7 +81,7 @@ void disable_reset_out() { usleep(10000); XGpioPs_WritePin(&Gpio, adau_reset, 1); - print("[gpio] ADAU reset done.\n"); + print("[gpio] ADAU reset done.\r\n"); } u32 blitter_colormode = MNTVA_COLOR_32BIT; @@ -102,9 +102,8 @@ static uint32_t usb_storage_write_block = 0; // ethernet state uint16_t ethernet_send_result = 0; -static int backlog_nag_counter = 0; -static int interrupt_enabled_ethernet = 0; -static int interrupt_waiting_ethernet = 0; +int eth_backlog_nag_counter = 0; +int interrupt_waiting_ethernet = 0; // usb state uint16_t usb_status = 0; @@ -114,7 +113,8 @@ uint32_t debug_lowlevel = 0; // audio state (ZZ9000AX) static int audio_buffer_collision = 0; -static uint32_t audio_scale = 1; +static uint32_t audio_scale = 48000/50; +static uint32_t audio_offset = 0; static int adau_enabled = 0; void handle_amiga_reset() { @@ -127,6 +127,11 @@ void handle_amiga_reset() { video_reset(); + // stop audio + audio_set_tx_buffer((uint8_t*)AUDIO_TX_BUFFER_ADDRESS); + audio_silence(); + audio_set_rx_buffer((uint8_t*)AUDIO_RX_BUFFER_ADDRESS); + // usb usb_storage_available = zz_usb_init(); usb_status = 0; @@ -134,8 +139,8 @@ void handle_amiga_reset() { // ethernet ethernet_send_result = 0; - backlog_nag_counter = 0; - interrupt_enabled_ethernet = 0; + eth_backlog_nag_counter = 0; + video_state->interrupt_enabled_ethernet = 0; // FIXME document cur_mem_offset = 0x3500000; @@ -154,6 +159,8 @@ void handle_amiga_reset() { f-=0.0001; }*/ + adau_enabled = audio_adau_init(1); + // clear interrupt holding amiga mntzorro_write(MNTZ_BASE_ADDR, MNTZORRO_REG2, (1 << 30) | 0); @@ -168,7 +175,7 @@ int main() { disable_reset_out(); - video_init(); + video_state = video_init(); xadc_init(); @@ -178,8 +185,6 @@ int main() { handle_amiga_reset(); - adau_enabled = audio_adau_init((uint32_t*)AUDIO_TX_BUFFER_ADDRESS); - fpga_interrupt_connect(isr_video, isr_audio, isr_audio_rx); // ARM app run environment @@ -210,6 +215,11 @@ int main() { u32 zstate_raw; int need_req_ack = 0; + // audio parameters (buffer locations) + const int ZZ_NUM_AUDIO_PARAMS = 4; + uint16_t audio_params[ZZ_NUM_AUDIO_PARAMS]; + int audio_param = 0; // selected parameter + // decoder parameters (mp3 etc) const int ZZ_NUM_DECODER_PARAMS = 8; uint16_t decoder_params[ZZ_NUM_DECODER_PARAMS]; @@ -329,7 +339,7 @@ int main() { if (zdata & 8) { // clear/ack if (zdata & 16) { - //printf("[clear] eth\n"); + printf("[clear] eth\n"); interrupt_waiting_ethernet = 0; } if (zdata & 32) { @@ -337,7 +347,7 @@ int main() { } } else { printf("[enable] eth: %d\n", (int)zdata); - interrupt_enabled_ethernet = zdata & 1; + video_state->interrupt_enabled_ethernet = zdata & 1; } break; case REG_ZZ_MODE: { @@ -754,7 +764,10 @@ int main() { } case REG_ZZ_DEBUG: { debug_lowlevel = zdata; - + break; + } + case REG_ZZ_DEBUG_TIMER: { + audio_debug_timer(zdata); break; } case REG_ZZ_PRINT_CHR: { @@ -813,14 +826,41 @@ int main() { break; case REG_ZZ_AUDIO_SWAB: { - // byteswap audio buffer - uint32_t offset = zdata<<8; // *256 - audio_buffer_collision = audio_swab(audio_scale, offset); + int byteswap = 1; + if (zdata&(1<<15)) byteswap = 0; + audio_offset = (zdata&0x7fff)<<8; // *256 + audio_buffer_collision = audio_swab(audio_scale, audio_offset, byteswap); + break; } case REG_ZZ_AUDIO_SCALE: audio_scale = zdata; break; + case REG_ZZ_AUDIO_PARAM: + // DECODER PARAMS: + // 0: tx buffer offset hi + // 1: tx buffer offset lo + // 2: rx buffer offset hi + // 3: rx buffer offset lo + + if (zdata<ZZ_NUM_AUDIO_PARAMS) { + audio_param = zdata; + } else { + audio_param = 0; + } + break; + case REG_ZZ_AUDIO_VAL: + audio_params[audio_param] = zdata; + if (audio_param == 1) { + uint8_t* addr = (uint8_t*)video_state->framebuffer + + ((audio_params[0]<<16)|audio_params[1]); + audio_set_tx_buffer(addr); + } else if (audio_param == 3) { + uint8_t* addr = (uint8_t*)video_state->framebuffer + + ((audio_params[2]<<16)|audio_params[3]); + audio_set_rx_buffer(addr); + } + break; case REG_ZZ_DECODER_PARAM: if (zdata<ZZ_NUM_DECODER_PARAMS) { decoder_param = zdata; @@ -851,15 +891,30 @@ int main() { + ((decoder_params[4]<<16)|decoder_params[5]); size_t output_buffer_size = (decoder_params[6]<<16)|decoder_params[7]; - printf("[decode:mp3] %p (%x) -> %p (%x)\n", input_buffer, input_buffer_size, - output_buffer, output_buffer_size); + if (zdata == 0) { + printf("[decode:mp3:%d] %p (%x) -> %p (%x)\n", (int)zdata, input_buffer, input_buffer_size, + output_buffer, output_buffer_size); + + decode_mp3_init(input_buffer, input_buffer_size); + } else { + int max_samples = output_buffer_size; + int mp3_freq = mp3_get_hz(); + if (mp3_freq < 48000) { + uint8_t* temp_buffer = output_buffer + 8*3840; // FIXME hack + max_samples = mp3_get_hz()/50*2; + //printf("[mp3] f: %d max: %d\n", mp3_get_hz(), max_samples); + + decode_mp3_samples(temp_buffer, max_samples); - decode_mp3(input_buffer, input_buffer_size, output_buffer, output_buffer_size); + // resample + resample_s16((int16_t*)temp_buffer, (int16_t*)output_buffer, + mp3_get_hz(), 48000, max_samples/2); - uint16_t* data = (uint16_t*)output_buffer; - for (int i=0; i<output_buffer_size/2; i++) { - data[i] = __builtin_bswap16(data[i]); + } else { + decode_mp3_samples(output_buffer, max_samples); + } } + break; } } @@ -1004,10 +1059,9 @@ int main() { need_req_ack = 2; } else { // there are no read/write requests, we can do other housekeeping - ethernet_task(); - if (zstate == 0) { + if ((zstate & 0xff) == 0) { // RESET handle_amiga_reset(); } @@ -1036,14 +1090,14 @@ int main() { // check for queued up ethernet frames int ethernet_backlog = ethernet_get_backlog(); - if (ethernet_backlog > 0 && backlog_nag_counter > 5000) { + if (ethernet_backlog > 0 && eth_backlog_nag_counter > 5000) { video_state->interrupt_signal_ethernet = 1; interrupt_waiting_ethernet = 1; - backlog_nag_counter = 0; + eth_backlog_nag_counter = 0; } - if (interrupt_enabled_ethernet && ethernet_backlog > 0) { - backlog_nag_counter++; + if (video_state->interrupt_enabled_ethernet && ethernet_backlog > 0) { + eth_backlog_nag_counter++; } } diff --git a/ZZ9000_proto.sdk/ZZ9000OS/src/memorymap.h b/ZZ9000_proto.sdk/ZZ9000OS/src/memorymap.h index 98d5b760d204443ef09eda6da2163a306bb3e84d..5d48dbc85559adc26c5a3739a95f426d4ca3e223 100644 --- a/ZZ9000_proto.sdk/ZZ9000OS/src/memorymap.h +++ b/ZZ9000_proto.sdk/ZZ9000OS/src/memorymap.h @@ -5,13 +5,13 @@ #define AUDIO_BYTES_PER_PERIOD 3840 #define FRAMEBUFFER_ADDRESS 0x00200000 -#define AUDIO_TX_BUFFER_ADDRESS 0x00200000 #define AUDIO_TX_BUFFER_SIZE (AUDIO_BYTES_PER_PERIOD * AUDIO_NUM_PERIODS) -#define AUDIO_RX_BUFFER_ADDRESS 0x00220000 // FIXME -#define Z3_SCRATCH_ADDR 0x033F0000 // FIXME -#define ADDR_ADJ 0x001F0000 +#define Z3_SCRATCH_ADDR 0x033F0000 // FIXME @ _Bnu +#define ADDR_ADJ 0x001F0000 // FIXME @ _Bnu +#define AUDIO_TX_BUFFER_ADDRESS 0x3FC00000 // default, changed by driver +#define AUDIO_RX_BUFFER_ADDRESS 0x3FC20000 // default, changed by driver #define TX_BD_LIST_START_ADDRESS 0x3FD00000 #define RX_BD_LIST_START_ADDRESS 0x3FD08000 #define TX_FRAME_ADDRESS 0x3FD10000 diff --git a/ZZ9000_proto.sdk/ZZ9000OS/src/mp3/decode_mp3.c b/ZZ9000_proto.sdk/ZZ9000OS/src/mp3/decode_mp3.c index d4e9e98445e84aed198400994089c590266026f4..f703500bca914ce9d5298e4aea6be847f2700b43 100644 --- a/ZZ9000_proto.sdk/ZZ9000OS/src/mp3/decode_mp3.c +++ b/ZZ9000_proto.sdk/ZZ9000OS/src/mp3/decode_mp3.c @@ -3,38 +3,60 @@ #define MINIMP3_IMPLEMENTATION 1 #include "minimp3_ex.h" -// TODO: package all minimp3 dependencies in this file -// TODO: enforce output format 16 bit signed integer samples, stereo interleaved, 48000Hz (first step: check if minimp3 can do all the necessary conversions by itself; for re-sampling consider something like libsamplerate?) -// TODO: adapt decode_mp3 interface to more specific requirements ("call a decode_mp3() function via a ZZ9000 register giving source and dest (uint32_t) pointers") -// TODO: status register where Amiga can pull result (OK/Error/busy) - -int decode_mp3(unsigned char * input_buffer, size_t input_buffer_size, unsigned char * output_buffer, size_t output_buffer_size) { - mp3dec_ex_t mp3d; - mp3dec_frame_info_t frame_info; - memset(&frame_info, 0, sizeof(frame_info)); - // // sets up input_buffer as mp3d->file.buffer - int ret = mp3dec_ex_open_buf(&mp3d, input_buffer, input_buffer_size, MP3D_DO_NOT_SCAN); - if (ret) { - printf("mp3dec_ex_open_buf failed: %d\n", ret); - exit(ret); - } - size_t offset_new_samples = 0; - int max_samples = UINT_MAX; - memset(output_buffer, 0, output_buffer_size); +static mp3dec_ex_t mp3d; +static mp3dec_frame_info_t frame_info; + +int decode_mp3_samples(void* output_buffer, int max_samples) { + int max_bytes = max_samples * 2; + int out_offset = 0; + int total_bytes_decoded = 0; + + //printf("[mp3] out_offset: %d max_bytes: %d\n", out_offset, max_bytes); + + // this will point into mp3d->buffer, which is defined on the stack + // as mp3d_sample_t buffer[MINIMP3_MAX_SAMPLES_PER_FRAME] + mp3d_sample_t * pcm_buffer = NULL; + while (1) { - // this will point into mp3d->buffer, which is defined on the stack - // as mp3d_sample_t buffer[MINIMP3_MAX_SAMPLES_PER_FRAME] - mp3d_sample_t * pcm_buffer = NULL; size_t read_samples = mp3dec_ex_read_frame(&mp3d, &pcm_buffer, &frame_info, max_samples); - if (!read_samples) { - break; - } - if (offset_new_samples + (read_samples * sizeof(mp3d_sample_t)) >= output_buffer_size) { + max_samples -= read_samples; + + int bytes_decoded = read_samples * sizeof(mp3d_sample_t); + total_bytes_decoded += bytes_decoded; + + //printf("[mp3] decoded: %d bytes\n", bytes_decoded); + + if (bytes_decoded > 0) { + int bytes_to_copy = bytes_decoded; + memcpy(output_buffer + out_offset, pcm_buffer, bytes_to_copy); + out_offset += bytes_decoded; + + if (out_offset >= max_bytes) { + break; + } + } else { break; } - size_t new_frame_size = read_samples * sizeof(mp3d_sample_t); - memcpy(output_buffer + offset_new_samples, pcm_buffer, new_frame_size); - offset_new_samples += read_samples * sizeof(mp3d_sample_t); } - return offset_new_samples; + + return total_bytes_decoded; +} + +int decode_mp3_init(uint8_t* input_buffer, size_t input_buffer_size) { + memset(&frame_info, 0, sizeof(frame_info)); + + // sets up input_buffer as mp3d->file.buffer + int ret = mp3dec_ex_open_buf(&mp3d, input_buffer, input_buffer_size, MP3D_DO_NOT_SCAN); + if (ret) { + printf("mp3dec_ex_open_buf failed: %d\n", ret); + } + return ret; +} + +int mp3_get_hz() { + return mp3d.info.hz; +} + +int mp3_get_channels() { + return mp3d.info.channels; } diff --git a/ZZ9000_proto.sdk/ZZ9000OS/src/mp3/mp3.h b/ZZ9000_proto.sdk/ZZ9000OS/src/mp3/mp3.h index bdb98242912b3ec9a11f77c13a4e75232cf80700..792578a9fdf0357a93f1261f681af9b76f6babae 100644 --- a/ZZ9000_proto.sdk/ZZ9000OS/src/mp3/mp3.h +++ b/ZZ9000_proto.sdk/ZZ9000OS/src/mp3/mp3.h @@ -1 +1,4 @@ -int decode_mp3(unsigned char * input_buffer, size_t input_buffer_size, unsigned char * output_buffer, size_t output_buffer_size); +int decode_mp3_init(uint8_t* input_buffer, size_t input_buffer_size); +int decode_mp3_samples(void* output_buffer, int max_samples); +int mp3_get_hz(); +int mp3_get_channels(); diff --git a/ZZ9000_proto.sdk/ZZ9000OS/src/video.c b/ZZ9000_proto.sdk/ZZ9000OS/src/video.c index b805b45e0612b02bef123b51879b9cd644913b77..d47d4b18a9855834ea2c0f5ab6f273cee4f03f77 100644 --- a/ZZ9000_proto.sdk/ZZ9000OS/src/video.c +++ b/ZZ9000_proto.sdk/ZZ9000OS/src/video.c @@ -61,7 +61,7 @@ struct ZZ_VIDEO_STATE* video_get_state() { return &vs; } -void video_init() { +struct ZZ_VIDEO_STATE* video_init() { vs.framebuffer = (u32*) FRAMEBUFFER_ADDRESS; // default to more compatible 60hz mode @@ -70,6 +70,8 @@ void video_init() { vs.colormode = 0; video_reset(); + + return video_get_state(); } void video_reset() { @@ -326,7 +328,6 @@ void isr_video(void *dummy) { if ((vs.interrupt_signal_ethernet && vs.interrupt_enabled_ethernet)) { // interrupt amiga (trigger int6/2) mntzorro_write(MNTZ_BASE_ADDR, MNTZORRO_REG2, (1 << 30) | 1); - usleep(1); mntzorro_write(MNTZ_BASE_ADDR, MNTZORRO_REG2, (1 << 30) | 0); // FIXME legacy behavior diff --git a/ZZ9000_proto.sdk/ZZ9000OS/src/video.h b/ZZ9000_proto.sdk/ZZ9000OS/src/video.h index 87cca1abd118519eec31a8a621c3a00d0d6bbd90..0a93e9b4c4dbd3ec9207e4a50e9f8a5226f3a207 100644 --- a/ZZ9000_proto.sdk/ZZ9000OS/src/video.h +++ b/ZZ9000_proto.sdk/ZZ9000OS/src/video.h @@ -64,7 +64,7 @@ struct ZZ_VIDEO_STATE { int interrupt_signal_ethernet; }; -void video_init(); +struct ZZ_VIDEO_STATE* video_init(); void video_reset(); void isr_video(void *dummy); void video_mode_init(int mode, int scalemode, int colormode); diff --git a/ZZ9000_proto.sdk/ZZ9000OS/src/zz_regs.h b/ZZ9000_proto.sdk/ZZ9000OS/src/zz_regs.h index dc3d7574c3d6b6820f8adba4f8e3c84fa637b989..36bfc0dd6b53152d91b3688a5359a0fbd8885275 100644 --- a/ZZ9000_proto.sdk/ZZ9000OS/src/zz_regs.h +++ b/ZZ9000_proto.sdk/ZZ9000OS/src/zz_regs.h @@ -85,11 +85,11 @@ enum zz_reg_offsets { REG_ZZ_AUDIO_SWAB = 0x70, REG_ZZ_UNUSED_REG72 = 0x72, REG_ZZ_AUDIO_SCALE = 0x74, - REG_ZZ_DECODE = 0x76, - REG_ZZ_DECODER_PARAM = 0x78, - REG_ZZ_DECODER_VAL = 0x7A, - REG_ZZ_UNUSED_REG7C = 0x7C, - REG_ZZ_UNUSED_REG7E = 0x7E, + REG_ZZ_AUDIO_PARAM = 0x76, + REG_ZZ_AUDIO_VAL = 0x78, + REG_ZZ_DECODER_PARAM = 0x7A, + REG_ZZ_DECODER_VAL = 0x7C, + REG_ZZ_DECODE = 0x7E, REG_ZZ_ETH_TX = 0x80, REG_ZZ_ETH_RX = 0x82, @@ -161,7 +161,7 @@ enum zz_reg_offsets { REG_ZZ_UNUSED_REGF8 = 0xF8, REG_ZZ_UNUSED_REGFA = 0xFA, REG_ZZ_DEBUG = 0xFC, - REG_ZZ_UNUSED_REGFE = 0xFE, + REG_ZZ_DEBUG_TIMER = 0xFE, }; enum zz9k_card_features {