diff --git a/ZZ9000_proto.sdk/ZZ9000OS/Debug/makefile b/ZZ9000_proto.sdk/ZZ9000OS/Debug/makefile index f100c3164c23251df533125b72eecd118650f4f8..35c372658aeb77d7b18300cbb1ffe26c49b07cab 100644 --- a/ZZ9000_proto.sdk/ZZ9000OS/Debug/makefile +++ b/ZZ9000_proto.sdk/ZZ9000OS/Debug/makefile @@ -9,6 +9,8 @@ RM := rm -rf # All of the sources participating in the build are defined here -include sources.mk -include src/usb/subdir.mk +-include src/mp3/subdir.mk +-include src/compression/audio/subdir.mk -include src/subdir.mk -include subdir.mk -include objects.mk diff --git a/ZZ9000_proto.sdk/ZZ9000OS/Debug/sources.mk b/ZZ9000_proto.sdk/ZZ9000OS/Debug/sources.mk index 5289394fc8659841a812391a92a29991fe9abd52..ae2a45e33e0863c36f681edd08c1001e7a7cc8d4 100644 --- a/ZZ9000_proto.sdk/ZZ9000OS/Debug/sources.mk +++ b/ZZ9000_proto.sdk/ZZ9000OS/Debug/sources.mk @@ -17,5 +17,7 @@ ELFSIZE := # Every subdirectory with source files must be described here SUBDIRS := \ src \ +src/compression/audio \ +src/mp3 \ src/usb \ diff --git a/ZZ9000_proto.sdk/ZZ9000OS/src/adc.c b/ZZ9000_proto.sdk/ZZ9000OS/src/adc.c new file mode 100644 index 0000000000000000000000000000000000000000..3852d5de6e4ec46440523eefe6986ea303f4a3e0 --- /dev/null +++ b/ZZ9000_proto.sdk/ZZ9000OS/src/adc.c @@ -0,0 +1,30 @@ +#include <stdio.h> +#include "xadcps.h" + +// XADC adc converter instance +XAdcPs Xadc; + +int xadc_init() { + printf("[adc] xadc_init()..."); + XAdcPs_Config* cfg; + cfg = XAdcPs_LookupConfig(XPAR_XADCPS_0_DEVICE_ID); + XAdcPs_CfgInitialize(&Xadc, cfg, cfg->BaseAddress); + int status = XAdcPs_SelfTest(&Xadc); + printf("[adc] xadc_init() done: %d", status); + return status; +} + +float xadc_get_temperature() { + u16 raw = XAdcPs_GetAdcData(&Xadc, XADCPS_CH_TEMP); + return XAdcPs_RawToTemperature(raw); +} + +float xadc_get_aux_voltage() { + u16 raw = XAdcPs_GetAdcData(&Xadc, XADCPS_CH_VCCAUX); + return XAdcPs_RawToVoltage(raw); +} + +float xadc_get_int_voltage() { + u16 raw = XAdcPs_GetAdcData(&Xadc, XADCPS_CH_VCCINT); + return XAdcPs_RawToVoltage(raw); +} diff --git a/ZZ9000_proto.sdk/ZZ9000OS/src/adc.h b/ZZ9000_proto.sdk/ZZ9000OS/src/adc.h new file mode 100644 index 0000000000000000000000000000000000000000..87d6f842486fec9bca9fedeecd1157ab8465f7d8 --- /dev/null +++ b/ZZ9000_proto.sdk/ZZ9000OS/src/adc.h @@ -0,0 +1,5 @@ + +int xadc_init(); +float xadc_get_temperature(); +float xadc_get_aux_voltage(); +float xadc_get_int_voltage(); diff --git a/ZZ9000_proto.sdk/ZZ9000OS/src/ax.c b/ZZ9000_proto.sdk/ZZ9000OS/src/ax.c new file mode 100644 index 0000000000000000000000000000000000000000..6adef6ee12bb6ff7407747af5413f0db96ea342d --- /dev/null +++ b/ZZ9000_proto.sdk/ZZ9000OS/src/ax.c @@ -0,0 +1,471 @@ +#include <stdio.h> + +#include "platform.h" +#include "xparameters.h" +#include "adau.h" +#include "xiicps.h" +#include "xi2stx.h" +#include "xi2srx.h" +#include "xaudioformatter.h" +#include "mntzorro.h" +#include "sleep.h" +#include "stdlib.h" + +#define IIC2_DEVICE_ID XPAR_XIICPS_1_DEVICE_ID +#define IIC2_SCLK_RATE 100000 +#define ADAU_I2C_ADDR 0x68 + +XIicPs Iic2; +XI2s_Tx i2s; +XI2s_Rx i2srx; +XAudioFormatter audio_formatter; +XAudioFormatter audio_formatter_rx; + +int adau_write16(u8 i2c_addr, u16 addr, u16 value) { + XIicPs* iic = &Iic2; + int status; + u8 buffer[4]; + buffer[0] = addr>>8; + buffer[1] = addr&0xff; + buffer[2] = value>>8; + buffer[3] = value&0xff; + + int timeout = 0; + while (XIicPs_BusIsBusy(iic)) { + usleep(1); + timeout++; + if (timeout>10000) { + printf("ADAU I2C write16 timeout.\n"); + return -1; + } + } + status = XIicPs_MasterSendPolled(iic, buffer, 4, i2c_addr); + + return status; +} + +int adau_write24(u8 i2c_addr, u16 addr, u32 value) { + XIicPs* iic = &Iic2; + int status; + u8 buffer[5]; + buffer[0] = addr>>8; + buffer[1] = addr&0xff; + buffer[2] = (value>>16)&0xff; + buffer[3] = (value>>8)&0xff; + buffer[4] = value&0xff; + + int timeout = 0; + while (XIicPs_BusIsBusy(iic)) { + usleep(1); + timeout++; + if (timeout>10000) { + printf("ADAU I2C write24 timeout.\n"); + return -1; + } + } + status = XIicPs_MasterSendPolled(iic, buffer, 5, i2c_addr); + + return status; +} + +// for storing 40 bit program words +int adau_write40(u8 i2c_addr, u16 addr, u8* data) { + XIicPs* iic = &Iic2; + int status; + u8 buffer[7]; + buffer[0] = addr>>8; + buffer[1] = addr&0xff; + buffer[2] = data[0]; + buffer[3] = data[1]; + buffer[4] = data[2]; + buffer[5] = data[3]; + buffer[6] = data[4]; + + int timeout = 0; + while (XIicPs_BusIsBusy(iic)) { + usleep(1); + timeout++; + if (timeout>10000) { + printf("ADAU I2C write40 timeout.\n"); + return -1; + } + } + + status = XIicPs_MasterSendPolled(iic, buffer, 2+5, i2c_addr); + return status; +} + +// for storing 32 bit parameter words +int adau_write32(u8 i2c_addr, u16 addr, u8* data) { + XIicPs* iic = &Iic2; + int status; + u8 buffer[6]; + buffer[0] = addr>>8; + buffer[1] = addr&0xff; + buffer[2] = data[0]; + buffer[3] = data[1]; + buffer[4] = data[2]; + buffer[5] = data[3]; + + int timeout = 0; + while (XIicPs_BusIsBusy(iic)) { + usleep(1); + timeout++; + if (timeout>10000) { + printf("ADAU I2C write40 timeout.\n"); + return -1; + } + } + + status = XIicPs_MasterSendPolled(iic, buffer, 2+4, i2c_addr); + return status; +} + +int adau_read16(u8 i2c_addr, u16 addr, u8* buffer) { + XIicPs* iic = &Iic2; + int status1; + u8 abuffer[2]; + abuffer[0] = addr>>8; + abuffer[1] = addr&0xff; + + XIicPs_SetOptions(iic, XIICPS_REP_START_OPTION); + + int timeout = 0; + while (XIicPs_BusIsBusy(iic)) { + usleep(1); + timeout++; + if (timeout>10000) { + printf("ADAU I2C read16a timeout.\n"); + return -1; + } + } + status1 = XIicPs_MasterSendPolled(iic, abuffer, 2, i2c_addr); + XIicPs_ClearOptions(iic, XIICPS_REP_START_OPTION); + XIicPs_MasterRecvPolled(iic, buffer, 2, i2c_addr); + timeout = 0; + while (XIicPs_BusIsBusy(iic)) { + usleep(1); + timeout++; + if (timeout>10000) { + printf("ADAU I2C read16b timeout.\n"); + return -1; + } + } + + return status1; +} + +int adau_read24(u8 i2c_addr, u16 addr, u8* buffer) { + XIicPs* iic = &Iic2; + int status1; + u8 abuffer[2]; + abuffer[0] = addr>>8; + abuffer[1] = addr&0xff; + + XIicPs_SetOptions(iic, XIICPS_REP_START_OPTION); + while (XIicPs_BusIsBusy(iic)) {}; + status1 = XIicPs_MasterSendPolled(iic, abuffer, 2, i2c_addr); + XIicPs_ClearOptions(iic, XIICPS_REP_START_OPTION); + XIicPs_MasterRecvPolled(iic, buffer, 3, i2c_addr); + int timeout = 0; + while (XIicPs_BusIsBusy(iic)) { + usleep(1); + timeout++; + if (timeout>10000) { + printf("ADAU I2C read24 timeout.\n"); + return -1; + } + } + + return status1; +} + +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); + } + + 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); + } +} + +// 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); + + XI2stx_Config* i2s_config = XI2s_Tx_LookupConfig(XPAR_XI2STX_0_DEVICE_ID); + status = XI2s_Tx_CfgInitialize(&i2s, i2s_config, i2s_config->BaseAddress); + + printf("[adau] I2S_TX cfg status: %d\n", status); + + printf("[adau] I2S Dwidth: %d\n", i2s.Config.DWidth); + printf("[adau] I2S MaxNumChannels: %d\n", i2s.Config.MaxNumChannels); + + XI2s_Tx_JustifyEnable(&i2s, 0); + + XAudioFormatter_Config* af_config = XAudioFormatter_LookupConfig(XPAR_XAUDIOFORMATTER_0_DEVICE_ID); + audio_formatter.BaseAddress = af_config->BaseAddress; + + status = XAudioFormatter_CfgInitialize(&audio_formatter, af_config); + + printf("[adau] AudioFormatter cfg status: %d\n", status); + + // reset the goddamn register + XAudioFormatter_WriteReg(audio_formatter.BaseAddress, + XAUD_FORMATTER_CTRL + XAUD_FORMATTER_MM2S_OFFSET, 0); + + XAudioFormatterHwParams af_params; + af_params.buf_addr = (u32)audio_buffer; + af_params.bits_per_sample = BIT_DEPTH_16; + af_params.periods = AUDIO_NUM_PERIODS; // 1 second = 192000 bytes + af_params.active_ch = 2; + // must be multiple of 32*channels = 64 + af_params.bytes_per_period = AUDIO_BYTES_PER_PERIOD; + + XAudioFormatterSetFsMultiplier(&audio_formatter, 48000*256, 48000); // mclk = 256 * Fs // this doesn't really seem to change anything?! + + printf("[adau] XAudioFormatterSetFsMultiplier\n"); + XAudioFormatterSetHwParams(&audio_formatter, &af_params); + printf("[adau] XAudioFormatterSetHwParams\n"); + + XAudioFormatter_InterruptDisable(&audio_formatter, 1<<14); // timeout + printf("[adau] XAudioFormatter_InterruptDisable\n"); + XAudioFormatter_InterruptDisable(&audio_formatter, 1<<13); // IOC + printf("[adau] XAudioFormatter_InterruptEnable\n"); + + // set up i2s receiver + + XAudioFormatter_Config* af_config_rx = XAudioFormatter_LookupConfig(XPAR_XAUDIOFORMATTER_1_DEVICE_ID); + audio_formatter_rx.BaseAddress = af_config_rx->BaseAddress; + + status = XAudioFormatter_CfgInitialize(&audio_formatter_rx, af_config_rx); + + printf("[adau] AudioFormatter RX cfg status: %d\n", status); + + XAudioFormatter_WriteReg(audio_formatter_rx.BaseAddress, + XAUD_FORMATTER_CTRL + XAUD_FORMATTER_S2MM_OFFSET, 0); + + XAudioFormatterHwParams afrx_params; + afrx_params.buf_addr = (u32)AUDIO_RX_BUFFER_ADDRESS; + afrx_params.bits_per_sample = BIT_DEPTH_16; + afrx_params.periods = AUDIO_NUM_PERIODS; // 1 second = 192000 bytes + afrx_params.active_ch = 2; + // must be multiple of 32*channels = 64 + afrx_params.bytes_per_period = AUDIO_BYTES_PER_PERIOD; + + XAudioFormatterSetFsMultiplier(&audio_formatter_rx, 48000*256, 48000); + printf("[adau] RX XAudioFormatterSetFsMultiplier\n"); + XAudioFormatterSetHwParams(&audio_formatter_rx, &afrx_params); + printf("[adau] RX XAudioFormatterSetHwParams\n"); + + XAudioFormatter_InterruptDisable(&audio_formatter_rx, 1<<14); // timeout + printf("[adau] RX XAudioFormatter_InterruptDisable\n"); + XAudioFormatter_InterruptDisable(&audio_formatter_rx, 1<<13); // IOC + /*XAudioFormatter_InterruptEnable(&audio_formatter_rx, 1<<13); // IOC + printf("[adau] RX XAudioFormatter_InterruptEnable\n");*/ + + XI2srx_Config* i2srx_config = XI2s_Rx_LookupConfig(XPAR_XI2SRX_0_DEVICE_ID); + status = XI2s_Rx_CfgInitialize(&i2srx, i2srx_config, i2srx_config->BaseAddress); + + //printf("[adau] I2S_RX cfg status: %d\n", status); + + //printf("[adau] I2S_RX Dwidth: %d\n", i2srx.Config.DWidth); + //printf("[adau] I2S_RX MaxNumChannels: %d\n", i2srx.Config.MaxNumChannels); + + XI2s_Rx_Enable(&i2srx, 1); + printf("[adau] XI2s_Rx_Enable\n"); + XAudioFormatterDMAStart(&audio_formatter_rx); + printf("[adau] RX XAudioFormatterDMAStart done.\n"); + + XAudioFormatter_InterruptEnable(&audio_formatter, 1<<13); // IOC + printf("[adau] XAudioFormatter_InterruptEnable\n"); + XI2s_Tx_Enable(&i2s, 1); + printf("[adau] XI2s_Tx_Enable\n"); + XAudioFormatterDMAStart(&audio_formatter); + printf("[adau] XAudioFormatterDMAStart done.\n"); + + return 1; +} + +static int interrupt_enabled_audio = 0; +static uint32_t interrupt_waiting_audio = 0; + +int isra_count = 0; + +// audio formatter interrupt, triggered whenever a period is completed +void isr_audio(void *dummy) { + uint32_t val = XAudioFormatter_ReadReg(XPAR_XAUDIOFORMATTER_0_BASEADDR, XAUD_FORMATTER_STS + XAUD_FORMATTER_MM2S_OFFSET); + val |= (1<<31); // clear irq + XAudioFormatter_WriteReg(XPAR_XAUDIOFORMATTER_0_BASEADDR, + XAUD_FORMATTER_STS + XAUD_FORMATTER_MM2S_OFFSET, val); + + if (isra_count++>100) { + printf("[isra]\n"); + isra_count = 0; + } + + if (interrupt_enabled_audio) { + 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; + } +} + +uint32_t audio_get_interrupt() { + return interrupt_waiting_audio; +} + +void audio_clear_interrupt() { + interrupt_waiting_audio = 0; +} + +int israrx_count = 0; + +// audio formatter interrupt, triggered whenever a period is completed +void isr_audio_rx(void *dummy) { + uint32_t val = XAudioFormatter_ReadReg(XPAR_XAUDIOFORMATTER_1_BASEADDR, XAUD_FORMATTER_STS + XAUD_FORMATTER_S2MM_OFFSET); + val |= (1<<31); // clear irq + XAudioFormatter_WriteReg(XPAR_XAUDIOFORMATTER_1_BASEADDR, + XAUD_FORMATTER_STS + XAUD_FORMATTER_S2MM_OFFSET, val); + + if (israrx_count++>100) { + printf("[isra_rx]\n"); + israrx_count = 0; + } +} + +uint32_t audio_get_dma_transfer_count() { + return XAudioFormatterGetDMATransferCount(&audio_formatter); +} + +void audio_set_interrupt_enabled(int en) { + printf("[audio] enable irq: %d\n", en); + interrupt_enabled_audio = en; +} + +// offset = offset from audio tx buffer +// returns audio_buffer_collision (1 or 0) +int audio_swab(int audio_scale, uint32_t offset) { + 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++) { + data[i] = __builtin_bswap16(data[i]); + } + } + + 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) { + audio_buffer_collision = 1; + 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); + + return audio_buffer_collision; +} + diff --git a/ZZ9000_proto.sdk/ZZ9000OS/src/ax.h b/ZZ9000_proto.sdk/ZZ9000OS/src/ax.h new file mode 100644 index 0000000000000000000000000000000000000000..9bb074831a484f2c7f530ffe0f0bd3211ae4a3cf --- /dev/null +++ b/ZZ9000_proto.sdk/ZZ9000OS/src/ax.h @@ -0,0 +1,10 @@ +#include <stdint.h> + +int audio_adau_init(uint32_t* audio_buffer); +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); diff --git a/ZZ9000_proto.sdk/ZZ9000OS/src/bootrom.c b/ZZ9000_proto.sdk/ZZ9000OS/src/bootrom.c index 87a8780f596e59dccc7352e35ffbe500afb4f914..edd50795a6bd2a322329b634127d741bb9106ec2 100644 --- a/ZZ9000_proto.sdk/ZZ9000OS/src/bootrom.c +++ b/ZZ9000_proto.sdk/ZZ9000OS/src/bootrom.c @@ -1,6 +1,6 @@ #include "bootrom.h" #include "xil_types.h" -#include "ethernet.h" +#include "memorymap.h" #include <stdio.h> // zzusb.device converted to an array diff --git a/ZZ9000_proto.sdk/ZZ9000OS/src/core2.c b/ZZ9000_proto.sdk/ZZ9000OS/src/core2.c new file mode 100644 index 0000000000000000000000000000000000000000..39952db902b477b63ec5e06a8ddeaa0329ff5ab4 --- /dev/null +++ b/ZZ9000_proto.sdk/ZZ9000OS/src/core2.c @@ -0,0 +1,272 @@ +#include <stdint.h> +#include <stdio.h> +#include "xil_cache.h" +#include "xil_exception.h" +#include "xil_io.h" +#include "xil_misc_psreset_api.h" +#include "core2.h" +#include "sleep.h" + +#define A9_CPU_RST_CTRL (XSLCR_BASEADDR + 0x244) +#define A9_RST1_MASK 0x00000002 +#define A9_CLKSTOP1_MASK 0x00000020 + +#define XSLCR_LOCK_ADDR (XSLCR_BASEADDR + 0x4) +#define XSLCR_LOCK_CODE 0x0000767B + +uint16_t arm_app_output_event_serial = 0; +uint16_t arm_app_output_event_code = 0; +char arm_app_output_event_ack = 0; +uint16_t arm_app_output_events_blocking = 0; +uint16_t arm_app_output_putchar_to_events = 0; +uint16_t arm_app_input_event_serial = 0; +uint16_t arm_app_input_event_code = 0; +char arm_app_input_event_ack = 0; + +uint32_t arm_app_output_events_timeout = 100000; + +volatile struct ZZ9K_ENV arm_run_env; + +volatile struct ZZ9K_ENV* arm_app_get_run_env() { + return &arm_run_env; +} + +void arm_app_put_event_code(uint16_t code) { + arm_app_output_event_code = code; + arm_app_output_event_ack = 0; + arm_app_output_event_serial++; +} + +char arm_app_output_event_acked() { + return arm_app_output_event_ack; +} + +void arm_app_set_output_events_blocking(char blocking) { + arm_app_output_events_blocking = blocking; +} + +void arm_app_set_output_putchar_to_events(char putchar_enabled) { + arm_app_output_putchar_to_events = putchar_enabled; +} + +uint16_t arm_app_get_event_serial() { + return arm_app_input_event_serial; +} + +uint16_t arm_app_get_event_code() { + arm_app_input_event_ack = 1; + return arm_app_input_event_code; +} + +int __attribute__ ((visibility ("default"))) _putchar(char c) { + if (arm_app_output_putchar_to_events) { + if (arm_app_output_events_blocking) { + for (uint32_t i = 0; i < arm_app_output_events_timeout; i++) { + usleep(1); + if (arm_app_output_event_ack) + break; + } + } + arm_app_put_event_code(c); + } + return putchar(c); +} + +//void DataAbort_InterruptHandler(void *InstancePtr); + +volatile void (*core1_trampoline)(volatile struct ZZ9K_ENV* env); +volatile int core2_execute = 0; + +#pragma GCC push_options +#pragma GCC optimize ("O1") +// core1_loop is executed on core1 (vs core0) +void core1_loop() { + asm("mov r0, r0"); + asm("mrc p15, 0, r1, c1, c0, 2"); + /* read cp access control register (CACR) into r1 */ + asm("orr r1, r1, #(0xf << 20)"); + /* enable full access for p10 & p11 */ + asm("mcr p15, 0, r1, c1, c0, 2"); + /* write back into CACR */ + + // enable FPU + asm("fmrx r1, FPEXC"); + /* read the exception register */ + asm("orr r1,r1, #0x40000000"); + /* set VFP enable bit, leave the others in orig state */ + asm("fmxr FPEXC, r1"); + /* write back the exception register */ + + // enable flow prediction + asm("mrc p15,0,r0,c1,c0,0"); + /* flow prediction enable */ + asm("orr r0, r0, #(0x01 << 11)"); + /* #0x8000 */ + asm("mcr p15,0,r0,c1,c0,0"); + + asm("mrc p15,0,r0,c1,c0,1"); + /* read Auxiliary Control Register */ + asm("orr r0, r0, #(0x1 << 2)"); + /* enable Dside prefetch */ + asm("orr r0, r0, #(0x1 << 1)"); + /* enable L2 Prefetch hint */ + asm("mcr p15,0,r0,c1,c0,1"); + /* write Auxiliary Control Register */ + + // stack + asm("mov sp, #0x06000000"); + + volatile uint32_t* addr = 0; + addr[0] = 0xe3e0000f; // mvn r0, #15 -- loads 0xfffffff0 + addr[1] = 0xe590f000; // ldr pc, [r0] -- jumps to the address in that address + + while (1) { + while (!core2_execute) { + usleep(1); + } + core2_execute = 0; + printf("[core2] executing at %p.\n", core1_trampoline); + Xil_DCacheFlush(); + Xil_ICacheInvalidate(); + + asm("push {r0-r12}"); + // FIXME HACK save our stack pointer in 0x10000 + asm("mov r0, #0x00010000"); + asm("str sp, [r0]"); + + core1_trampoline(&arm_run_env); + + asm("mov r0, #0x00010000"); + asm("ldr sp, [r0]"); + asm("pop {r0-r12}"); + } +} +#pragma GCC pop_options + +void arm_app_init() { + arm_run_env.api_version = 1; + arm_run_env.fn_putchar = _putchar; + arm_run_env.fn_get_event_code = arm_app_get_event_code; + arm_run_env.fn_get_event_serial = arm_app_get_event_serial; + arm_run_env.fn_output_event_acked = arm_app_output_event_acked; + arm_run_env.fn_put_event_code = arm_app_put_event_code; + arm_run_env.fn_set_output_events_blocking = + arm_app_set_output_events_blocking; + arm_run_env.fn_set_output_putchar_to_events = + arm_app_set_output_putchar_to_events; + arm_run_env.argc = 0; + + Xil_ExceptionRegisterHandler(XIL_EXCEPTION_ID_RESET, + (Xil_ExceptionHandler) arm_exception_handler_id_reset, NULL); + Xil_ExceptionRegisterHandler(XIL_EXCEPTION_ID_DATA_ABORT_INT, + (Xil_ExceptionHandler) arm_exception_handler_id_data_abort, NULL); + Xil_ExceptionRegisterHandler(XIL_EXCEPTION_ID_PREFETCH_ABORT_INT, + (Xil_ExceptionHandler) arm_exception_handler_id_prefetch_abort, NULL); + Xil_ExceptionRegisterHandler(XIL_EXCEPTION_ID_UNDEFINED_INT, + (Xil_ExceptionHandler) arm_exception_handler_illinst, NULL); + + printf("[core2] launch...\n"); + volatile uint32_t* core1_addr = (volatile uint32_t*) 0xFFFFFFF0; + *core1_addr = (uint32_t) core1_loop; + // Place some machine code in strategic positions that will catch core1 if it crashes + // FIXME: clean this up and turn into a debug handler / monitor + volatile uint32_t* core1_addr2 = (volatile uint32_t*) 0x140; // catch 1 + core1_addr2[0] = 0xe3e0000f; // mvn r0, #15 -- loads 0xfffffff0 + core1_addr2[1] = 0xe590f000; // ldr pc, [r0] -- jumps to the address in that address + + core1_addr2 = (volatile uint32_t*) 0x100; // catch 2 + core1_addr2[0] = 0xe3e0000f; // mvn r0, #15 -- loads 0xfffffff0 + core1_addr2[1] = 0xe590f000; // ldr pc, [r0] -- jumps to the address in that address + + asm("sev"); + printf("[core2] now idling.\n"); +} + +void arm_app_run(uint32_t arm_run_address) { + volatile uint32_t* core1_addr = (volatile uint32_t*) 0xFFFFFFF0; + volatile uint32_t* core1_addr2 = (volatile uint32_t*) 0x100; // catch 2 + + *core1_addr = (uint32_t) core1_loop; + core1_addr2[0] = 0xe3e0000f; // mvn r0, #15 -- loads 0xfffffff0 + core1_addr2[1] = 0xe590f000; // ldr pc, [r0] -- jumps to the address in that address + + printf("[ARM_RUN] %lx\n", arm_run_address); + if (arm_run_address > 0) { + core1_trampoline = (volatile void (*)( + volatile struct ZZ9K_ENV*)) arm_run_address; + printf("[ARM_RUN] signaling second core.\n"); + Xil_DCacheFlush(); + Xil_ICacheInvalidate(); + core2_execute = 1; + Xil_DCacheFlush(); + Xil_ICacheInvalidate(); + } else { + core1_trampoline = 0; + core2_execute = 0; + } + + // FIXME move this out of here + // sequence to reset cpu1 taken from https://xilinx-wiki.atlassian.net/wiki/spaces/A/pages/18842504/XAPP1079+Latest+Information + + Xil_Out32(XSLCR_UNLOCK_ADDR, XSLCR_UNLOCK_CODE); + uint32_t RegVal = Xil_In32(A9_CPU_RST_CTRL); + RegVal |= A9_RST1_MASK; + Xil_Out32(A9_CPU_RST_CTRL, RegVal); + RegVal |= A9_CLKSTOP1_MASK; + Xil_Out32(A9_CPU_RST_CTRL, RegVal); + RegVal &= ~A9_RST1_MASK; + Xil_Out32(A9_CPU_RST_CTRL, RegVal); + RegVal &= ~A9_CLKSTOP1_MASK; + Xil_Out32(A9_CPU_RST_CTRL, RegVal); + Xil_Out32(XSLCR_LOCK_ADDR, XSLCR_LOCK_CODE); + + dmb(); + dsb(); + isb(); + asm("sev"); +} + +void arm_app_input_event(uint32_t evt) { + arm_app_input_event_code = evt; + arm_app_input_event_serial++; + arm_app_input_event_ack = 0; +} + +uint32_t arm_app_output_event() { + uint32_t data = (arm_app_output_event_serial << 16) + | arm_app_output_event_code; + + arm_app_output_event_ack = 1; + + return data; +} + +void arm_exception_handler_id_reset(void *callback) { + printf("id_reset: arm_exception_handler()!\n"); + while (1) { + } +} + +void arm_exception_handler_id_data_abort(void *callback) { + printf("id_data_abort: arm_exception_handler()!\n"); + while (1) { + } +} + +void arm_exception_handler_id_prefetch_abort(void *callback) { + printf("id_prefetch_abort: arm_exception_handler()!\n"); + while (1) { + } +} + +void arm_exception_handler(void *callback) { + printf("arm_exception_handler()!\n"); + while (1) { + } +} + +void arm_exception_handler_illinst(void *callback) { + printf("arm_exception_handler_illinst()!\n"); + while (1) { + } +} diff --git a/ZZ9000_proto.sdk/ZZ9000OS/src/core2.h b/ZZ9000_proto.sdk/ZZ9000OS/src/core2.h new file mode 100644 index 0000000000000000000000000000000000000000..47e609210dabe378ff8e009c92f3140e6eaf4bcc --- /dev/null +++ b/ZZ9000_proto.sdk/ZZ9000OS/src/core2.h @@ -0,0 +1,25 @@ + +struct ZZ9K_ENV { + uint32_t api_version; + uint32_t argv[8]; + uint32_t argc; + + int (*fn_putchar)(char); + void (*fn_set_output_putchar_to_events)(char); + void (*fn_set_output_events_blocking)(char); + void (*fn_put_event_code)(uint16_t); + uint16_t (*fn_get_event_serial)(); + uint16_t (*fn_get_event_code)(); + char (*fn_output_event_acked)(); +}; + +void arm_app_init(); +volatile struct ZZ9K_ENV* arm_app_get_run_env(); +void arm_app_run(uint32_t arm_run_address); +void arm_app_input_event(uint32_t evt); +uint32_t arm_app_output_event(); + +void arm_exception_handler_id_reset(void *callback); +void arm_exception_handler_id_data_abort(void *callback); +void arm_exception_handler_id_prefetch_abort(void *callback); +void arm_exception_handler_illinst(void *callback); diff --git a/ZZ9000_proto.sdk/ZZ9000OS/src/dma_acc.c b/ZZ9000_proto.sdk/ZZ9000OS/src/dma_acc.c index e1f9b5a74229c654dba61b094fe8428dc53825e0..5147b71fe301753129616bbbe0145a0faa2a40b8 100644 --- a/ZZ9000_proto.sdk/ZZ9000OS/src/dma_acc.c +++ b/ZZ9000_proto.sdk/ZZ9000OS/src/dma_acc.c @@ -1,5 +1,6 @@ #include <stdio.h> #include "gfx.h" +#include "memorymap.h" #include <xil_types.h> #include "xil_printf.h" #include "compression/compression.h" @@ -9,8 +10,6 @@ extern unsigned int cur_mem_offset; extern uint8_t imc_tables_initialized; int current_c37_encoder = -1; -#define Z3_OUTPUT_ADDR 0x3400000 - void handle_acc_op(uint16_t zdata) { struct GFXData *data = (struct GFXData*)((u32)Z3_SCRATCH_ADDR); @@ -285,4 +284,4 @@ void handle_acc_op(uint16_t zdata) default: break; } -} \ No newline at end of file +} diff --git a/ZZ9000_proto.sdk/ZZ9000OS/src/dma_rtg.c b/ZZ9000_proto.sdk/ZZ9000OS/src/dma_rtg.c index 1922c233dc8445937abac220e54348be09f7fdbe..78ced857b3a1b6f1dad160488d1e04478efe45d3 100644 --- a/ZZ9000_proto.sdk/ZZ9000OS/src/dma_rtg.c +++ b/ZZ9000_proto.sdk/ZZ9000OS/src/dma_rtg.c @@ -1,31 +1,12 @@ #include <stdio.h> -#include "gfx.h" #include <xil_types.h> +#include "memorymap.h" +#include "zz_video_modes.h" +#include "gfx.h" +#include "video.h" #include "xil_printf.h" -extern u32* framebuffer; -extern u32 bgbuf_offset; -extern u32 framebuffer_color_format; -extern u32 framebuffer_pan_offset; -extern u32 framebuffer_pan_width; -extern u32 framebuffer_pan_offset_old; -extern u32 request_video_align; -extern u32 blitter_colormode; - -extern uint32_t sprite_colors[4]; - -extern int16_t sprite_x, sprite_x_adj, sprite_x_base; -extern int16_t sprite_y, sprite_y_adj, sprite_y_base; -extern int16_t sprite_x_offset; -extern int16_t sprite_y_offset; -extern uint16_t split_pos, next_split_pos; -extern uint16_t sprite_showing; -extern uint8_t sprite_width; -extern uint8_t sprite_height; - -extern int split_request_pos; - -void handle_blitter_dma_op(uint16_t zdata) +void handle_blitter_dma_op(struct ZZ_VIDEO_STATE* vs, uint16_t zdata) { struct GFXData *data = (struct GFXData*)((u32)Z3_SCRATCH_ADDR); switch(zdata) { @@ -37,7 +18,7 @@ void handle_blitter_dma_op(uint16_t zdata) SWAP16(data->pitch[0]); SWAP32(data->offset[0]); - set_fb((uint32_t*) ((u32) framebuffer + data->offset[0]), + set_fb((uint32_t*) ((u32)vs->framebuffer + data->offset[0]), data->pitch[0]); if (data->user[1] == 0xFFFF && data->mask == 0xFF) @@ -58,7 +39,7 @@ void handle_blitter_dma_op(uint16_t zdata) SWAP16(data->pitch[0]); SWAP32(data->offset[0]); - set_fb((uint32_t*) ((u32) framebuffer + data->offset[0]), + set_fb((uint32_t*) ((u32)vs->framebuffer + data->offset[0]), data->pitch[0]); if (data->mask == 0xFF) @@ -77,7 +58,7 @@ void handle_blitter_dma_op(uint16_t zdata) SWAP16(data->pitch[0]); SWAP16(data->pitch[1]); SWAP32(data->offset[0]); SWAP32(data->offset[1]); - set_fb((uint32_t*) ((u32) framebuffer + data->offset[0]), + set_fb((uint32_t*) ((u32)vs->framebuffer + data->offset[0]), data->pitch[0]); switch (zdata) { @@ -85,18 +66,18 @@ void handle_blitter_dma_op(uint16_t zdata) if (data->mask == 0xFF || (data->mask != 0xFF && data->u8_user[GFXDATA_U8_COLORMODE] != MNTVA_COLOR_8BIT)) copy_rect_nomask(data->x[0], data->y[0], data->x[1], data->y[1], data->x[2], data->y[2], data->u8_user[GFXDATA_U8_COLORMODE], - (uint32_t*) ((u32) framebuffer + data->offset[0]), + (uint32_t*) ((u32)vs->framebuffer + data->offset[0]), data->pitch[0], MINTERM_SRC); else copy_rect(data->x[0], data->y[0], data->x[1], data->y[1], data->x[2], data->y[2], data->u8_user[GFXDATA_U8_COLORMODE], - (uint32_t*) ((u32) framebuffer + data->offset[0]), + (uint32_t*) ((u32)vs->framebuffer + data->offset[0]), data->pitch[0], data->mask); break; case 4: // BlitRectNoMaskComplete copy_rect_nomask(data->x[0], data->y[0], data->x[1], data->y[1], data->x[2], data->y[2], data->u8_user[GFXDATA_U8_COLORMODE], - (uint32_t*) ((u32) framebuffer + data->offset[1]), + (uint32_t*) ((u32)vs->framebuffer + data->offset[1]), data->pitch[1], data->minterm); break; } @@ -110,9 +91,9 @@ void handle_blitter_dma_op(uint16_t zdata) SWAP16(data->pitch[0]); SWAP16(data->pitch[1]); SWAP32(data->offset[0]); SWAP32(data->offset[1]); - uint8_t* tmpl_data = (uint8_t*) ((u32) framebuffer + uint8_t* tmpl_data = (uint8_t*) ((u32)vs->framebuffer + data->offset[1]); - set_fb((uint32_t*) ((u32) framebuffer + data->offset[0]), + set_fb((uint32_t*) ((u32)vs->framebuffer + data->offset[0]), data->pitch[0]); @@ -153,10 +134,10 @@ void handle_blitter_dma_op(uint16_t zdata) SWAP16(data->user[0]); SWAP16(data->user[1]); - uint8_t* bmp_data = (uint8_t*) ((u32) framebuffer + uint8_t* bmp_data = (uint8_t*) ((u32)vs->framebuffer + data->offset[1]); - set_fb((uint32_t*) ((u32) framebuffer + data->offset[0]), + set_fb((uint32_t*) ((u32)vs->framebuffer + data->offset[0]), data->pitch[0]); if (zdata == OP_P2C) { @@ -180,20 +161,20 @@ void handle_blitter_dma_op(uint16_t zdata) SWAP16(data->pitch[0]); SWAP32(data->offset[0]); - set_fb((uint32_t*) ((u32) framebuffer + data->offset[0]), + set_fb((uint32_t*) ((u32)vs->framebuffer + data->offset[0]), data->pitch[0]); invert_rect(data->x[0], data->y[0], data->x[1], data->y[1], data->mask, data->u8_user[GFXDATA_U8_COLORMODE]); break; case OP_SPRITE_XY: - if (!sprite_showing) + if (!vs->sprite_showing) break; SWAP16(data->x[0]); SWAP16(data->y[0]); - sprite_x_base = (int16_t)data->x[0]; - sprite_y_base = (int16_t)data->y[0]; + vs->sprite_x_base = (int16_t)data->x[0]; + vs->sprite_y_base = (int16_t)data->y[0]; update_hw_sprite_pos((int16_t)data->x[0], (int16_t)data->y[0]); break; @@ -208,35 +189,36 @@ void handle_blitter_dma_op(uint16_t zdata) uint8_t* bmp_data; if (zdata == OP_SPRITE_BITMAP) - bmp_data = (uint8_t*) ((u32) framebuffer + data->offset[1]); + bmp_data = (uint8_t*) ((u32)vs->framebuffer + data->offset[1]); else bmp_data = (uint8_t*) ((u32) ADDR_ADJ + data->offset[1]); clear_hw_sprite(); - sprite_x_offset = (int16_t)data->x[0]; - sprite_y_offset = (int16_t)data->y[0]; - sprite_width = data->x[1]; + vs->sprite_x_offset = (int16_t)data->x[0]; + vs->sprite_y_offset = (int16_t)data->y[0]; + vs->sprite_width = data->x[1]; if (zdata == OP_SPRITE_CLUT_BITMAP) { - sprite_x_offset = -(sprite_x_offset); - sprite_y_offset = -(sprite_y_offset); + vs->sprite_x_offset = -(vs->sprite_x_offset); + vs->sprite_y_offset = -(vs->sprite_y_offset); } - sprite_height = data->y[1]; + vs->sprite_height = data->y[1]; if (zdata == OP_SPRITE_BITMAP) { - update_hw_sprite(bmp_data, sprite_colors, sprite_width, sprite_height); + update_hw_sprite(bmp_data); } else { //printf("Making a %dx%d cursor (%i %i)\n", sprite_width, sprite_height, sprite_x_offset, sprite_y_offset); - update_hw_sprite_clut(bmp_data, data->clut1, sprite_width, sprite_height, data->u8offset); + update_hw_sprite_clut(bmp_data, data->clut1, + vs->sprite_width, vs->sprite_height, data->u8offset); } - update_hw_sprite_pos(sprite_x_base, sprite_y_base); + update_hw_sprite_pos(vs->sprite_x_base, vs->sprite_y_base); break; } case OP_SPRITE_COLOR: { - sprite_colors[data->u8offset] = data->rgb[0]; - if (data->u8offset != 0 && sprite_colors[data->u8offset] == 0xff00ff) - sprite_colors[data->u8offset] = 0xfe00fe; + vs->sprite_colors[data->u8offset] = data->rgb[0]; + if (data->u8offset != 0 && vs->sprite_colors[data->u8offset] == 0xff00ff) + vs->sprite_colors[data->u8offset] = 0xfe00fe; break; } @@ -245,23 +227,23 @@ void handle_blitter_dma_op(uint16_t zdata) SWAP16(data->x[0]); SWAP16(data->y[0]); SWAP16(data->x[1]); - sprite_x_offset = (int16_t)data->x[0]; - sprite_y_offset = (int16_t)data->y[0]; + vs->sprite_x_offset = (int16_t)data->x[0]; + vs->sprite_y_offset = (int16_t)data->y[0]; - framebuffer_pan_width = data->x[1]; - framebuffer_color_format = data->u8_user[GFXDATA_U8_COLORMODE]; - framebuffer_pan_offset = data->offset[0] + (data->x[0] << data->u8_user[GFXDATA_U8_COLORMODE]); - if (split_pos == 0) { - framebuffer_pan_offset += (data->y[0] * (framebuffer_pan_width << framebuffer_color_format)); + vs->framebuffer_pan_width = data->x[1]; + u32 framebuffer_color_format = data->u8_user[GFXDATA_U8_COLORMODE]; + vs->framebuffer_pan_offset = data->offset[0] + (data->x[0] << data->u8_user[GFXDATA_U8_COLORMODE]); + if (vs->split_pos == 0) { + vs->framebuffer_pan_offset += (data->y[0] * (vs->framebuffer_pan_width << framebuffer_color_format)); } break; case OP_SET_SPLIT_POS: SWAP16(data->y[0]); SWAP32(data->offset[0]); - bgbuf_offset = data->offset[0]; + vs->bgbuf_offset = data->offset[0]; - split_request_pos = data->y[0]; + vs->split_request_pos = data->y[0]; break; default: diff --git a/ZZ9000_proto.sdk/ZZ9000OS/src/ethernet.c b/ZZ9000_proto.sdk/ZZ9000OS/src/ethernet.c index 66816dc90122abaccd7fccc480c0d3e24ddd6800..ed7dbc716c3b044226ee1a1bb65bbdd79e15e48c 100644 --- a/ZZ9000_proto.sdk/ZZ9000OS/src/ethernet.c +++ b/ZZ9000_proto.sdk/ZZ9000OS/src/ethernet.c @@ -27,6 +27,7 @@ #include <xscugic.h> #include "ethernet.h" #include "interrupt.h" +#include "memorymap.h" static XEmacPs EmacPsInstance; diff --git a/ZZ9000_proto.sdk/ZZ9000OS/src/ethernet.h b/ZZ9000_proto.sdk/ZZ9000OS/src/ethernet.h index faeab3e959a536d6c1df328270d882e614121e29..221bec1ccc4a473fc4b12a603558452a6439d949 100644 --- a/ZZ9000_proto.sdk/ZZ9000OS/src/ethernet.h +++ b/ZZ9000_proto.sdk/ZZ9000OS/src/ethernet.h @@ -27,18 +27,6 @@ uint8_t* ethernet_current_receive_ptr(); int ethernet_get_backlog(); void ethernet_task(); -// FIXME allocate this memory properly - -#define TX_BD_LIST_START_ADDRESS 0x3FD00000 -#define RX_BD_LIST_START_ADDRESS 0x3FD08000 -#define TX_FRAME_ADDRESS 0x3FD10000 -#define RX_FRAME_ADDRESS 0x3FD20000 -#define RX_BACKLOG_ADDRESS 0x3FE00000 // 32 * 2048 space (64 kB) -#define USB_BLOCK_STORAGE_ADDRESS 0x3FE10000 // FIXME move all of these to a memory table header file -#define BOOT_ROM_ADDRESS 0x3FCF0000 -#define RX_FRAME_PAD 4 -#define FRAME_SIZE 2048 - #define FRAME_MAX_BACKLOG 32 #define RXBD_CNT 1 /* Number of RxBDs to use */ diff --git a/ZZ9000_proto.sdk/ZZ9000OS/src/gfx.c b/ZZ9000_proto.sdk/ZZ9000OS/src/gfx.c index 2570c3e011075a613162990741fab4cd8408912b..def5797e4c14dffb14a0ee9cc8db8abb11cda9d3 100644 --- a/ZZ9000_proto.sdk/ZZ9000OS/src/gfx.c +++ b/ZZ9000_proto.sdk/ZZ9000OS/src/gfx.c @@ -20,6 +20,7 @@ #include <string.h> #include <math.h> #include "gfx.h" +#include "zz_video_modes.h" uint32_t* fb=0; uint32_t fb_pitch=0; diff --git a/ZZ9000_proto.sdk/ZZ9000OS/src/gfx.h b/ZZ9000_proto.sdk/ZZ9000OS/src/gfx.h index c1a8c273e5286550c77d42a866152c0d52ea84c8..e11c3ab94ced2543f34026faf138156900a5df84 100644 --- a/ZZ9000_proto.sdk/ZZ9000OS/src/gfx.h +++ b/ZZ9000_proto.sdk/ZZ9000OS/src/gfx.h @@ -15,24 +15,7 @@ */ #include <stdint.h> - -#define Z3_SCRATCH_ADDR 0x33F0000 -#define ADDR_ADJ 0x1F0000 - -#define MNTVF_OP_UNUSED 12 -#define MNTVF_OP_SPRITE_XY 13 -#define MNTVF_OP_SPRITE_ADDR 14 -#define MNTVF_OP_SPRITE_DATA 15 -#define MNTVF_OP_MAX 6 -#define MNTVF_OP_HS 7 -#define MNTVF_OP_VS 8 -#define MNTVF_OP_POLARITY 10 -#define MNTVF_OP_SCALE 4 -#define MNTVF_OP_DIMENSIONS 2 -#define MNTVF_OP_COLORMODE 1 -#define MNTVF_OP_REPORT_LINE 17 -#define MNTVF_OP_PALETTE_SEL 18 -#define MNTVF_OP_PALETTE_HI 19 +#include "video.h" typedef struct Vec2 { float x; @@ -50,15 +33,10 @@ typedef struct { } vec2_i32; void video_formatter_write(uint32_t data, uint16_t op); -void handle_blitter_dma_op(uint16_t zdata); +void handle_blitter_dma_op(struct ZZ_VIDEO_STATE* vs, uint16_t zdata); void handle_acc_op(uint16_t zdata); void set_fb(uint32_t* fb_, uint32_t pitch); -void update_hw_sprite(uint8_t *data, uint32_t *colors, uint16_t w, uint16_t h); -void update_hw_sprite_clut(uint8_t *data_, uint8_t *colors, uint16_t w, uint16_t h, uint8_t keycolor); -void update_hw_sprite_pos(int16_t x, int16_t y); -void clip_hw_sprite(int16_t offset_x, int16_t offset_y); -void clear_hw_sprite(); void fill_rect(uint16_t rect_x1, uint16_t rect_y1, uint16_t w, uint16_t h, uint32_t rect_rgb, uint32_t color_format, uint8_t mask); void fill_rect_solid(uint16_t rect_x1, uint16_t rect_y1, uint16_t w, uint16_t h, uint32_t rect_rgb, uint32_t color_format); @@ -96,14 +74,6 @@ void acc_fill_flat_tri(uint32_t dest, TriangleDef *d, uint16_t w, uint16_t h, ui void *get_color_conversion_table(int index); -enum color_formats { - MNTVA_COLOR_8BIT, - MNTVA_COLOR_16BIT565, - MNTVA_COLOR_32BIT, - MNTVA_COLOR_15BIT, - MNTVA_COLOR_NUM, -}; - #define SWAP16(a) a = __builtin_bswap16(a) #define SWAP32(a) a = __builtin_bswap32(a) diff --git a/ZZ9000_proto.sdk/ZZ9000OS/src/hdmi.c b/ZZ9000_proto.sdk/ZZ9000OS/src/hdmi.c new file mode 100644 index 0000000000000000000000000000000000000000..996235e2b4ca8967c4a4a493e24325eb89ffc3a5 --- /dev/null +++ b/ZZ9000_proto.sdk/ZZ9000OS/src/hdmi.c @@ -0,0 +1,145 @@ +#include "xiicps.h" + +#define IIC_DEVICE_ID XPAR_XIICPS_0_DEVICE_ID +#define HDMI_I2C_ADDR 0x3b +#define IIC_SCLK_RATE 400000 +#define I2C_PAUSE 10 + +// I2C controller instances +XIicPs Iic; + +int i2c_write_byte(XIicPs* iic, u8 i2c_addr, u8 addr, u8 value) { + u8 buffer[2]; + buffer[0] = addr; + buffer[1] = value; + int status; + + while (XIicPs_BusIsBusy(iic)) {}; + status = XIicPs_MasterSendPolled(iic, buffer, 2, i2c_addr); + while (XIicPs_BusIsBusy(iic)) {}; + usleep(I2C_PAUSE); + + status = XIicPs_MasterSendPolled(iic, buffer, 1, i2c_addr); + while (XIicPs_BusIsBusy(iic)) {}; + usleep(I2C_PAUSE); + buffer[1] = 0xff; + status = XIicPs_MasterRecvPolled(iic, buffer + 1, 1, i2c_addr); + + if (buffer[1] != value) { + printf("[i2c:%x] new value of 0x%x: 0x%x (should be 0x%x)\n", i2c_addr, addr, + buffer[1], value); + } + + return status; +} + +int i2c_read_byte(XIicPs* iic, u8 i2c_addr, u8 addr, u8* buffer) { + buffer[0] = addr; + buffer[1] = 0xff; + while (XIicPs_BusIsBusy(iic)) {}; + int status = XIicPs_MasterSendPolled(iic, buffer, 1, i2c_addr); + while (XIicPs_BusIsBusy(iic)) {}; + usleep(I2C_PAUSE); + status = XIicPs_MasterRecvPolled(iic, buffer + 1, 1, i2c_addr); + + return status; +} + +int hdmi_ctrl_write_byte(u8 addr, u8 value) { + return i2c_write_byte(&Iic, HDMI_I2C_ADDR, addr, value); +} + +int hdmi_ctrl_read_byte(u8 addr, u8* buffer) { + return i2c_read_byte(&Iic, HDMI_I2C_ADDR, addr, buffer); +} + +static u8 sii9022_init[] = { + 0x1e, 0x00,// TPI Device Power State Control Data (R/W) + 0x09, 0x00, // + 0x0a, 0x00, + + 0x60, 0x04, 0x3c, 0x01, // TPI Interrupt Enable (R/W) + + 0x1a, 0x10, // TPI System Control (R/W) + + 0x00, 0x4c, // PixelClock/10000 - LSB u16:6 + 0x01, 0x1d, // PixelClock/10000 - MSB + 0x02, 0x70, // Frequency in HZ - LSB + 0x03, 0x17, // Vertical Frequency in HZ - MSB + 0x04, 0x70, // Total Pixels per line - LSB + 0x05, 0x06, // Total Pixels per line - MSB + 0x06, 0xEE, // Total Lines - LSB + 0x07, 0x02, // Total Lines - MSB + 0x08, 0x70, // pixel repeat rate? + 0x1a, 0x00, // CTRL_DATA - bit 1 causes 2 purple extra columns on DVI monitors (probably HDMI mode) +}; + +void hdmi_set_video_mode(u16 htotal, u16 vtotal, u32 pixelclock_hz, u16 vhz, u8 hdmi) { + /* + * SII9022 registers + * + 0x00, 0x4c, // PixelClock/10000 - LSB + 0x01, 0x1d, // PixelClock/10000 - MSB + 0x02, 0x70, // Frequency in HZ - LSB + 0x03, 0x17, // Vertical Frequency in HZ - MSB + 0x04, 0x70, // Total Pixels per line - LSB + 0x05, 0x06, // Total Pixels per line - MSB + 0x06, 0xEE, // Total Lines - LSB + 0x07, 0x02, // Total Lines - MSB + 0x08, 0x70, // pixel repeat rate? + 0x1a, 0x00, // 0: DVI, 1: HDMI + */ + + // see also https://github.com/torvalds/linux/blob/master/drivers/gpu/drm/bridge/sii902x.c#L358 + u8* sii_mode = sii9022_init + 12; + + sii_mode[2 * 0 + 1] = pixelclock_hz / 10000; + sii_mode[2 * 1 + 1] = (pixelclock_hz / 10000) >> 8; + sii_mode[2 * 2 + 1] = vhz * 100; + sii_mode[2 * 3 + 1] = (vhz * 100) >> 8; + sii_mode[2 * 4 + 1] = htotal; + sii_mode[2 * 5 + 1] = htotal >> 8; + sii_mode[2 * 6 + 1] = vtotal; + sii_mode[2 * 7 + 1] = vtotal >> 8; + sii_mode[2 * 9 + 1] = hdmi; +} + +void hdmi_ctrl_init(struct zz_video_mode *mode) { + XIicPs_Config *config; + config = XIicPs_LookupConfig(IIC_DEVICE_ID); + int status = XIicPs_CfgInitialize(&Iic, config, config->BaseAddress); + //printf("XIicPs_CfgInitialize: %d\n", status); + usleep(10000); + //printf("XIicPs is ready: %lx\n", Iic.IsReady); + + status = XIicPs_SelfTest(&Iic); + //printf("XIicPs_SelfTest: %x\n", status); + + status = XIicPs_SetSClk(&Iic, IIC_SCLK_RATE); + //printf("XIicPs_SetSClk: %x\n", status); + + usleep(2500); + + // reset + status = hdmi_ctrl_write_byte(0xc7, 0); + + u8 buffer[2]; + status = hdmi_ctrl_read_byte(0x1b, buffer); + //printf("[%d] TPI device id: 0x%x\n", status, buffer[1]); + status = hdmi_ctrl_read_byte(0x1c, buffer); + //printf("[%d] TPI revision 1: 0x%x\n",status,buffer[1]); + //status = hdmi_ctrl_read_byte(0x1d,buffer); + //printf("[%d] TPI revision 2: 0x%x\n",status,buffer[1]); + //status = hdmi_ctrl_read_byte(0x30,buffer); + //printf("[%d] HDCP revision: 0x%x\n",status,buffer[1]); + //status = hdmi_ctrl_read_byte(0x3d,buffer); + //printf("[%d] hotplug: 0x%x\n", status, buffer[1]); + + //hdmi_set_video_mode(mode->hmax, mode->vmax, mode->phz, mode->vhz, mode->hdmi); + + for (int i = 0; i < sizeof(sii9022_init); i += 2) { + status = hdmi_ctrl_write_byte(sii9022_init[i], sii9022_init[i + 1]); + usleep(1); + } +} + diff --git a/ZZ9000_proto.sdk/ZZ9000OS/src/hdmi.h b/ZZ9000_proto.sdk/ZZ9000OS/src/hdmi.h new file mode 100644 index 0000000000000000000000000000000000000000..363ed19c0f0ffe6b7e975907ef2b4b824ac6c47f --- /dev/null +++ b/ZZ9000_proto.sdk/ZZ9000OS/src/hdmi.h @@ -0,0 +1,3 @@ +#include "zz_video_modes.h" + +void hdmi_ctrl_init(struct zz_video_mode *mode); diff --git a/ZZ9000_proto.sdk/ZZ9000OS/src/interrupt.c b/ZZ9000_proto.sdk/ZZ9000OS/src/interrupt.c index 911de967c2f1f7437b8337fed5089e5e18da2fee..09c11958808adb6cba44bc88f904778e54091373 100644 --- a/ZZ9000_proto.sdk/ZZ9000OS/src/interrupt.c +++ b/ZZ9000_proto.sdk/ZZ9000OS/src/interrupt.c @@ -36,3 +36,42 @@ int interrupt_configure() { return 0; } + +#define INTC_INTERRUPT_ID_0 61 // IRQ_F2P[0:0] +#define INTC_INTERRUPT_ID_1 62 // IRQ_F2P[1:1] +#define INTC_INTERRUPT_ID_2 63 // IRQ_F2P[2:2] + +int fpga_interrupt_connect(void* isr_video, void* isr_audio_tx, void* isr_audio_rx) { + int result; + XScuGic *intc_instance_ptr = interrupt_get_intc(); + + printf("XScuGic_SetPriorityTriggerType()\n"); + + // set the priority of IRQ_F2P[0:0] to 0xA0 (highest 0xF8, lowest 0x00) and a trigger for a rising edge 0x3. + XScuGic_SetPriorityTriggerType(intc_instance_ptr, INTC_INTERRUPT_ID_0, 0xA0, 0x3); // vblank / split + XScuGic_SetPriorityTriggerType(intc_instance_ptr, INTC_INTERRUPT_ID_1, 0x90, 0x3); // audio formatter TX + XScuGic_SetPriorityTriggerType(intc_instance_ptr, INTC_INTERRUPT_ID_2, 0x90, 0x3); // audio formatter RX + + printf("XScuGic_Connect()\n"); + + // connect the interrupt service routine isr0 to the interrupt controller + result = XScuGic_Connect(intc_instance_ptr, INTC_INTERRUPT_ID_0, (Xil_ExceptionHandler)isr_video, NULL); + result = XScuGic_Connect(intc_instance_ptr, INTC_INTERRUPT_ID_1, (Xil_ExceptionHandler)isr_audio_tx, NULL); + result = XScuGic_Connect(intc_instance_ptr, INTC_INTERRUPT_ID_2, (Xil_ExceptionHandler)isr_audio_rx, NULL); + + if (result != XST_SUCCESS) { + printf("XScuGic_Connect() failed!\n"); + return result; + } + + printf("XScuGic_Enable()\n"); + + // enable interrupts for IRQ_F2P[0:0] + XScuGic_Enable(intc_instance_ptr, INTC_INTERRUPT_ID_0); + // enable interrupts for IRQ_F2P[1:1] + XScuGic_Enable(intc_instance_ptr, INTC_INTERRUPT_ID_1); + // enable interrupts for IRQ_F2P[2:2] + XScuGic_Enable(intc_instance_ptr, INTC_INTERRUPT_ID_2); + + return 0; +} diff --git a/ZZ9000_proto.sdk/ZZ9000OS/src/interrupt.h b/ZZ9000_proto.sdk/ZZ9000OS/src/interrupt.h index a3227e66fc2a09bedae38360a21d39cd3ef1556e..92b8c5ec56a1e9080a298b3267363995f60057d7 100644 --- a/ZZ9000_proto.sdk/ZZ9000OS/src/interrupt.h +++ b/ZZ9000_proto.sdk/ZZ9000OS/src/interrupt.h @@ -5,5 +5,6 @@ XScuGic* interrupt_get_intc(); int interrupt_configure(); +int fpga_interrupt_connect(void* isr_video, void* isr_audio_tx, void* isr_audio_rx); #endif diff --git a/ZZ9000_proto.sdk/ZZ9000OS/src/main.c b/ZZ9000_proto.sdk/ZZ9000OS/src/main.c index 6c20c21dd5ffa4f62630ea92a957ae062800ae79..84d2da7c99fcadeac9e8d4c45b09266f1738a710 100644 --- a/ZZ9000_proto.sdk/ZZ9000OS/src/main.c +++ b/ZZ9000_proto.sdk/ZZ9000OS/src/main.c @@ -26,331 +26,38 @@ #include "xil_io.h" #include "xscugic.h" #include "xgpiops.h" -#include "xiicps.h" #include "sleep.h" -#include "xaxivdma.h" #include "xil_cache.h" -#include "xclk_wiz.h" #include "xil_exception.h" -#include "xadcps.h" +#include "xclk_wiz.h" #include "xtime_l.h" -#include "xil_misc_psreset_api.h" #include "xi2stx.h" #include "xi2srx.h" // workaround for typo in xilinx C code void Xil_AssertNonVoid() {} -#include "xaudioformatter.h" - +#include "memorymap.h" +#include "mntzorro.h" +#include "video.h" +#include "hdmi.h" #include "gfx.h" #include "ethernet.h" #include "usb.h" #include "interrupt.h" #include "bootrom.h" +#include "core2.h" +#include "adc.h" +#include "ax.h" #include "mp3/mp3.h" #include "zz_regs.h" #include "zz_video_modes.h" -#define A9_CPU_RST_CTRL (XSLCR_BASEADDR + 0x244) -#define A9_RST1_MASK 0x00000002 -#define A9_CLKSTOP1_MASK 0x00000020 - -#define XSLCR_LOCK_ADDR (XSLCR_BASEADDR + 0x4) -#define XSLCR_LOCK_CODE 0x0000767B +#define REVISION_MAJOR 1 +#define REVISION_MINOR 10 -#define IIC_DEVICE_ID XPAR_XIICPS_0_DEVICE_ID -#define VDMA_DEVICE_ID XPAR_AXIVDMA_0_DEVICE_ID -#define HDMI_I2C_ADDR 0x3b -#define IIC_SCLK_RATE 400000 #define GPIO_DEVICE_ID XPAR_XGPIOPS_0_DEVICE_ID -#define IIC2_DEVICE_ID XPAR_XIICPS_1_DEVICE_ID -#define IIC2_SCLK_RATE 100000 -#define ADAU_I2C_ADDR 0x68 - -#define I2C_PAUSE 10 - -// I2C controller instances -XIicPs Iic; -XIicPs Iic2; - -// XADC adc converter instance -XAdcPs Xadc; - -// audio state (ZZ9000AX) -static int adau_enabled = 0; -#define AUDIO_TX_BUFFER_SIZE 3840*10 // bytes per period * periods -#define AUDIO_TX_BUFFER_ADDRESS 0x200000 - -int xadc_init() { - printf("xadc_init()..."); - XAdcPs_Config* cfg; - cfg = XAdcPs_LookupConfig(XPAR_XADCPS_0_DEVICE_ID); - XAdcPs_CfgInitialize(&Xadc, cfg, cfg->BaseAddress); - int status = XAdcPs_SelfTest(&Xadc); - printf("xadc_init() done: %d", status); - return status; -} - -float xadc_get_temperature() { - u16 raw = XAdcPs_GetAdcData(&Xadc, XADCPS_CH_TEMP); - return XAdcPs_RawToTemperature(raw); -} - -float xadc_get_aux_voltage() { - u16 raw = XAdcPs_GetAdcData(&Xadc, XADCPS_CH_VCCAUX); - return XAdcPs_RawToVoltage(raw); -} - -float xadc_get_int_voltage() { - u16 raw = XAdcPs_GetAdcData(&Xadc, XADCPS_CH_VCCINT); - return XAdcPs_RawToVoltage(raw); -} - -// This is the absolute offset in ZZ9000 RAM for the "framebuffer transfer register", -// which can be replaced by the DMA acceleration functionality entirely, but some -// software still relies on this legacy register. -unsigned int cur_mem_offset = 0x3500000; - -int i2c_write_byte(XIicPs* iic, u8 i2c_addr, u8 addr, u8 value) { - - u8 buffer[2]; - buffer[0] = addr; - buffer[1] = value; - int status; - - /*while (XIicPs_BusIsBusy(iic)) {}; - usleep(I2C_PAUSE); - status = XIicPs_MasterSendPolled(iic, buffer, 1, i2c_addr); - while (XIicPs_BusIsBusy(iic)) {}; - usleep(I2C_PAUSE); - buffer[1] = 0xff; - status = XIicPs_MasterRecvPolled(iic, buffer + 1, 1, i2c_addr); - buffer[1] = value;*/ - - while (XIicPs_BusIsBusy(iic)) {}; - status = XIicPs_MasterSendPolled(iic, buffer, 2, i2c_addr); - while (XIicPs_BusIsBusy(iic)) {}; - usleep(I2C_PAUSE); - - status = XIicPs_MasterSendPolled(iic, buffer, 1, i2c_addr); - while (XIicPs_BusIsBusy(iic)) {}; - usleep(I2C_PAUSE); - buffer[1] = 0xff; - status = XIicPs_MasterRecvPolled(iic, buffer + 1, 1, i2c_addr); - - if (buffer[1] != value) { - printf("[i2c:%x] new value of 0x%x: 0x%x (should be 0x%x)\n", i2c_addr, addr, - buffer[1], value); - } - - return status; -} - -int i2c_read_byte(XIicPs* iic, u8 i2c_addr, u8 addr, u8* buffer) { - buffer[0] = addr; - buffer[1] = 0xff; - while (XIicPs_BusIsBusy(iic)) {}; - int status = XIicPs_MasterSendPolled(iic, buffer, 1, i2c_addr); - while (XIicPs_BusIsBusy(iic)) {}; - usleep(I2C_PAUSE); - status = XIicPs_MasterRecvPolled(iic, buffer + 1, 1, i2c_addr); - - return status; -} - -int hdmi_ctrl_write_byte(u8 addr, u8 value) { - return i2c_write_byte(&Iic, HDMI_I2C_ADDR, addr, value); -} - -int hdmi_ctrl_read_byte(u8 addr, u8* buffer) { - return i2c_read_byte(&Iic, HDMI_I2C_ADDR, addr, buffer); -} - -int adau_write16(u8 i2c_addr, u16 addr, u16 value) { - XIicPs* iic = &Iic2; - int status; - //u8 i2c_addr = ADAU_I2C_ADDR; - u8 buffer[4]; - buffer[0] = addr>>8; - buffer[1] = addr&0xff; - buffer[2] = value>>8; - buffer[3] = value&0xff; - - int timeout = 0; - while (XIicPs_BusIsBusy(iic)) { - usleep(1); - timeout++; - if (timeout>10000) { - printf("ADAU I2C write16 timeout.\n"); - return -1; - } - } - status = XIicPs_MasterSendPolled(iic, buffer, 4, i2c_addr); - - return status; -} - -int adau_write24(u8 i2c_addr, u16 addr, u32 value) { - XIicPs* iic = &Iic2; - int status; - //u8 i2c_addr = ADAU_I2C_ADDR; - u8 buffer[5]; - buffer[0] = addr>>8; - buffer[1] = addr&0xff; - buffer[2] = (value>>16)&0xff; - buffer[3] = (value>>8)&0xff; - buffer[4] = value&0xff; - - int timeout = 0; - while (XIicPs_BusIsBusy(iic)) { - usleep(1); - timeout++; - if (timeout>10000) { - printf("ADAU I2C write24 timeout.\n"); - return -1; - } - } - status = XIicPs_MasterSendPolled(iic, buffer, 5, i2c_addr); - - return status; -} - -// for storing 40 bit program words -int adau_write40(u8 i2c_addr, u16 addr, u8* data) { - XIicPs* iic = &Iic2; - int status; - u8 buffer[7]; - buffer[0] = addr>>8; - buffer[1] = addr&0xff; - buffer[2] = data[0]; - buffer[3] = data[1]; - buffer[4] = data[2]; - buffer[5] = data[3]; - buffer[6] = data[4]; - - int timeout = 0; - while (XIicPs_BusIsBusy(iic)) { - usleep(1); - timeout++; - if (timeout>10000) { - printf("ADAU I2C write40 timeout.\n"); - return -1; - } - } - - status = XIicPs_MasterSendPolled(iic, buffer, 2+5, i2c_addr); - return status; -} - -// for storing 32 bit parameter words -int adau_write32(u8 i2c_addr, u16 addr, u8* data) { - XIicPs* iic = &Iic2; - int status; - u8 buffer[6]; - buffer[0] = addr>>8; - buffer[1] = addr&0xff; - buffer[2] = data[0]; - buffer[3] = data[1]; - buffer[4] = data[2]; - buffer[5] = data[3]; - - int timeout = 0; - while (XIicPs_BusIsBusy(iic)) { - usleep(1); - timeout++; - if (timeout>10000) { - printf("ADAU I2C write40 timeout.\n"); - return -1; - } - } - - status = XIicPs_MasterSendPolled(iic, buffer, 2+4, i2c_addr); - return status; -} - -int adau_read16(u8 i2c_addr, u16 addr, u8* buffer) { - XIicPs* iic = &Iic2; - int status1; - //u8 i2c_addr = ADAU_I2C_ADDR; - u8 abuffer[2]; - abuffer[0] = addr>>8; - abuffer[1] = addr&0xff; - - XIicPs_SetOptions(iic, XIICPS_REP_START_OPTION); - - int timeout = 0; - while (XIicPs_BusIsBusy(iic)) { - usleep(1); - timeout++; - if (timeout>10000) { - printf("ADAU I2C read16a timeout.\n"); - return -1; - } - } - status1 = XIicPs_MasterSendPolled(iic, abuffer, 2, i2c_addr); - XIicPs_ClearOptions(iic, XIICPS_REP_START_OPTION); - XIicPs_MasterRecvPolled(iic, buffer, 2, i2c_addr); - timeout = 0; - while (XIicPs_BusIsBusy(iic)) { - usleep(1); - timeout++; - if (timeout>10000) { - printf("ADAU I2C read16b timeout.\n"); - return -1; - } - } - - return status1; -} - -int adau_read24(u8 i2c_addr, u16 addr, u8* buffer) { - XIicPs* iic = &Iic2; - int status1; - //u8 i2c_addr = ADAU_I2C_ADDR; - u8 abuffer[2]; - abuffer[0] = addr>>8; - abuffer[1] = addr&0xff; - - XIicPs_SetOptions(iic, XIICPS_REP_START_OPTION); - while (XIicPs_BusIsBusy(iic)) {}; - status1 = XIicPs_MasterSendPolled(iic, abuffer, 2, i2c_addr); - XIicPs_ClearOptions(iic, XIICPS_REP_START_OPTION); - XIicPs_MasterRecvPolled(iic, buffer, 3, i2c_addr); - int timeout = 0; - while (XIicPs_BusIsBusy(iic)) { - usleep(1); - timeout++; - if (timeout>10000) { - printf("ADAU I2C read24 timeout.\n"); - return -1; - } - } - - return status1; -} - -static u8 sii9022_init[] = { - 0x1e, 0x00,// TPI Device Power State Control Data (R/W) - 0x09, 0x00, // - 0x0a, 0x00, - - 0x60, 0x04, 0x3c, 0x01, // TPI Interrupt Enable (R/W) - - 0x1a, 0x10, // TPI System Control (R/W) - - 0x00, 0x4c, // PixelClock/10000 - LSB u16:6 - 0x01, 0x1d, // PixelClock/10000 - MSB - 0x02, 0x70, // Frequency in HZ - LSB - 0x03, 0x17, // Vertical Frequency in HZ - MSB - 0x04, 0x70, // Total Pixels per line - LSB - 0x05, 0x06, // Total Pixels per line - MSB - 0x06, 0xEE, // Total Lines - LSB - 0x07, 0x02, // Total Lines - MSB - 0x08, 0x70, // pixel repeat rate? - 0x1a, 0x00, // CTRL_DATA - bit 1 causes 2 purple extra columns on DVI monitors (probably HDMI mode) -}; void disable_reset_out() { XGpioPs Gpio; @@ -364,9 +71,9 @@ 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.\n"); - + // FIXME int adau_reset = 11; XGpioPs_SetDirectionPin(&Gpio, adau_reset, 1); XGpioPs_SetOutputEnablePin(&Gpio, adau_reset, 1); @@ -374,786 +81,20 @@ void disable_reset_out() { usleep(10000); XGpioPs_WritePin(&Gpio, adau_reset, 1); - print("GPIO ADAU reset done.\n"); + print("[gpio] ADAU reset done.\n"); } -void hdmi_set_video_mode(u16 htotal, u16 vtotal, u32 pixelclock_hz, u16 vhz, u8 hdmi) { - /* - * SII9022 registers - * - 0x00, 0x4c, // PixelClock/10000 - LSB - 0x01, 0x1d, // PixelClock/10000 - MSB - 0x02, 0x70, // Frequency in HZ - LSB - 0x03, 0x17, // Vertical Frequency in HZ - MSB - 0x04, 0x70, // Total Pixels per line - LSB - 0x05, 0x06, // Total Pixels per line - MSB - 0x06, 0xEE, // Total Lines - LSB - 0x07, 0x02, // Total Lines - MSB - 0x08, 0x70, // pixel repeat rate? - 0x1a, 0x00, // 0: DVI, 1: HDMI - */ - - // see also https://github.com/torvalds/linux/blob/master/drivers/gpu/drm/bridge/sii902x.c#L358 - u8* sii_mode = sii9022_init + 12; - - sii_mode[2 * 0 + 1] = pixelclock_hz / 10000; - sii_mode[2 * 1 + 1] = (pixelclock_hz / 10000) >> 8; - sii_mode[2 * 2 + 1] = vhz * 100; - sii_mode[2 * 3 + 1] = (vhz * 100) >> 8; - sii_mode[2 * 4 + 1] = htotal; - sii_mode[2 * 5 + 1] = htotal >> 8; - sii_mode[2 * 6 + 1] = vtotal; - sii_mode[2 * 7 + 1] = vtotal >> 8; - sii_mode[2 * 9 + 1] = hdmi; -} - -void hdmi_ctrl_init(struct zz_video_mode *mode) { - XIicPs_Config *config; - config = XIicPs_LookupConfig(IIC_DEVICE_ID); - int status = XIicPs_CfgInitialize(&Iic, config, config->BaseAddress); - //printf("XIicPs_CfgInitialize: %d\n", status); - usleep(10000); - //printf("XIicPs is ready: %lx\n", Iic.IsReady); - - status = XIicPs_SelfTest(&Iic); - //printf("XIicPs_SelfTest: %x\n", status); - - status = XIicPs_SetSClk(&Iic, IIC_SCLK_RATE); - //printf("XIicPs_SetSClk: %x\n", status); - - usleep(2500); - - // reset - status = hdmi_ctrl_write_byte(0xc7, 0); - - u8 buffer[2]; - status = hdmi_ctrl_read_byte(0x1b, buffer); - //printf("[%d] TPI device id: 0x%x\n", status, buffer[1]); - status = hdmi_ctrl_read_byte(0x1c, buffer); - //printf("[%d] TPI revision 1: 0x%x\n",status,buffer[1]); - //status = hdmi_ctrl_read_byte(0x1d,buffer); - //printf("[%d] TPI revision 2: 0x%x\n",status,buffer[1]); - //status = hdmi_ctrl_read_byte(0x30,buffer); - //printf("[%d] HDCP revision: 0x%x\n",status,buffer[1]); - //status = hdmi_ctrl_read_byte(0x3d,buffer); - //printf("[%d] hotplug: 0x%x\n", status, buffer[1]); - - //hdmi_set_video_mode(mode->hmax, mode->vmax, mode->phz, mode->vhz, mode->hdmi); - - for (int i = 0; i < sizeof(sii9022_init); i += 2) { - status = hdmi_ctrl_write_byte(sii9022_init[i], sii9022_init[i + 1]); - usleep(1); - } -} - -#include "adau.h" - -XI2s_Tx i2s; -XI2s_Rx i2srx; -XAudioFormatter audio_formatter; -XAudioFormatter audio_formatter_rx; - -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); - } - - 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); - } -} - -void init_adau(u32* 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; - } - - 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; - } - - adau_enabled = 1; - - 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); - - XI2stx_Config* i2s_config = XI2s_Tx_LookupConfig(XPAR_XI2STX_0_DEVICE_ID); - status = XI2s_Tx_CfgInitialize(&i2s, i2s_config, i2s_config->BaseAddress); - - printf("[adau] I2S_TX cfg status: %d\n", status); - - printf("[adau] I2S Dwidth: %d\n", i2s.Config.DWidth); - printf("[adau] I2S MaxNumChannels: %d\n", i2s.Config.MaxNumChannels); - - XI2s_Tx_JustifyEnable(&i2s, 0); - - XAudioFormatter_Config* af_config = XAudioFormatter_LookupConfig(XPAR_XAUDIOFORMATTER_0_DEVICE_ID); - audio_formatter.BaseAddress = af_config->BaseAddress; - - status = XAudioFormatter_CfgInitialize(&audio_formatter, af_config); - - printf("[adau] AudioFormatter cfg status: %d\n", status); - - // reset the goddamn register - XAudioFormatter_WriteReg(audio_formatter.BaseAddress, - XAUD_FORMATTER_CTRL + XAUD_FORMATTER_MM2S_OFFSET, 0); - - XAudioFormatterHwParams af_params; - af_params.buf_addr = (u32)audio_buffer; - af_params.bits_per_sample = BIT_DEPTH_16; - af_params.periods = 8; // 1 second = 192000 bytes - af_params.active_ch = 2; - // must be multiple of 32*channels = 64 - af_params.bytes_per_period = 3840; - - XAudioFormatterSetFsMultiplier(&audio_formatter, 48000*256, 48000); // mclk = 256 * Fs // this doesn't really seem to change anything?! - - printf("[adau] XAudioFormatterSetFsMultiplier\n"); - XAudioFormatterSetHwParams(&audio_formatter, &af_params); - printf("[adau] XAudioFormatterSetHwParams\n"); - - XAudioFormatter_InterruptDisable(&audio_formatter, 1<<14); // timeout - printf("[adau] XAudioFormatter_InterruptDisable\n"); - XAudioFormatter_InterruptDisable(&audio_formatter, 1<<13); // IOC - printf("[adau] XAudioFormatter_InterruptEnable\n"); - - // set up i2s receiver - - XAudioFormatter_Config* af_config_rx = XAudioFormatter_LookupConfig(XPAR_XAUDIOFORMATTER_1_DEVICE_ID); - audio_formatter_rx.BaseAddress = af_config_rx->BaseAddress; - - status = XAudioFormatter_CfgInitialize(&audio_formatter_rx, af_config_rx); - - printf("[adau] AudioFormatter RX cfg status: %d\n", status); - - XAudioFormatter_WriteReg(audio_formatter_rx.BaseAddress, - XAUD_FORMATTER_CTRL + XAUD_FORMATTER_S2MM_OFFSET, 0); - - XAudioFormatterHwParams afrx_params; - afrx_params.buf_addr = (u32)0x220000; // FIXME - afrx_params.bits_per_sample = BIT_DEPTH_16; - afrx_params.periods = 8; // 1 second = 192000 bytes - afrx_params.active_ch = 2; - // must be multiple of 32*channels = 64 - afrx_params.bytes_per_period = 3840; - - XAudioFormatterSetFsMultiplier(&audio_formatter_rx, 48000*256, 48000); - printf("[adau] RX XAudioFormatterSetFsMultiplier\n"); - XAudioFormatterSetHwParams(&audio_formatter_rx, &afrx_params); - printf("[adau] RX XAudioFormatterSetHwParams\n"); - - XAudioFormatter_InterruptDisable(&audio_formatter_rx, 1<<14); // timeout - printf("[adau] RX XAudioFormatter_InterruptDisable\n"); - XAudioFormatter_InterruptDisable(&audio_formatter_rx, 1<<13); // IOC - /*XAudioFormatter_InterruptEnable(&audio_formatter_rx, 1<<13); // IOC - printf("[adau] RX XAudioFormatter_InterruptEnable\n");*/ - - XI2srx_Config* i2srx_config = XI2s_Rx_LookupConfig(XPAR_XI2SRX_0_DEVICE_ID); - status = XI2s_Rx_CfgInitialize(&i2srx, i2srx_config, i2srx_config->BaseAddress); - - //printf("[adau] I2S_RX cfg status: %d\n", status); - - //printf("[adau] I2S_RX Dwidth: %d\n", i2srx.Config.DWidth); - //printf("[adau] I2S_RX MaxNumChannels: %d\n", i2srx.Config.MaxNumChannels); - - XI2s_Rx_Enable(&i2srx, 1); - printf("[adau] XI2s_Rx_Enable\n"); - XAudioFormatterDMAStart(&audio_formatter_rx); - printf("[adau] RX XAudioFormatterDMAStart done.\n"); - - XAudioFormatter_InterruptEnable(&audio_formatter, 1<<13); // IOC - printf("[adau] XAudioFormatter_InterruptEnable\n"); - XI2s_Tx_Enable(&i2s, 1); - printf("[adau] XI2s_Tx_Enable\n"); - XAudioFormatterDMAStart(&audio_formatter); - printf("[adau] XAudioFormatterDMAStart done.\n"); -} - -XAxiVdma vdma; -u32* framebuffer = 0; -u32 bgbuf_offset = 0; - -uint16_t split_pos = 0, next_split_pos = 0; -uint8_t card_feature_enabled[CARD_FEATURE_NUM]; -uint8_t scandoubler_mode_adjust = 0; - -u32 framebuffer_pan_offset = 0; -u32 framebuffer_pan_width = 0; -u32 framebuffer_color_format = 0; u32 blitter_colormode = MNTVA_COLOR_32BIT; static u32 blitter_dst_offset = 0; static u32 blitter_src_offset = 0; -static u32 vmode_hsize = 800, vmode_vsize = 600, vmode_hdiv = 1, vmode_vdiv = 2; - -// FIXME -extern u32 *fb; -uint8_t stride_div = 1; - -// 32bit: hdiv=1, 16bit: hdiv=2, 8bit: hdiv=4, ... -int init_vdma(int hsize, int vsize, int hdiv, int vdiv, u32 bufpos) { - int status; - XAxiVdma_Config *Config; - - Config = XAxiVdma_LookupConfig(VDMA_DEVICE_ID); - - if (!Config) { - printf("VDMA not found for ID %d\r\n", VDMA_DEVICE_ID); - return XST_FAILURE; - } - - /*XAxiVdma_DmaStop(&vdma, XAXIVDMA_READ); - XAxiVdma_Reset(&vdma, XAXIVDMA_READ); - XAxiVdma_ClearDmaChannelErrors(&vdma, XAXIVDMA_READ, XAXIVDMA_SR_ERR_ALL_MASK);*/ - - status = XAxiVdma_CfgInitialize(&vdma, Config, Config->BaseAddress); - if (status != XST_SUCCESS) { - printf("VDMA Configuration Initialization failed, status: 0x%X\r\n", - status); - //return status; - } - - //printf("VDMA MM2S DRE: %d\n", vdma.HasMm2SDRE); - //printf("VDMA Config MM2S DRE: %d\n", Config->HasMm2SDRE); - - u32 stride = hsize * (Config->Mm2SStreamWidth >> 3); - if (framebuffer_pan_width != 0 && framebuffer_pan_width != (hsize / hdiv)) { - stride = (framebuffer_pan_width * (Config->Mm2SStreamWidth >> 3)) * stride_div; - } - - XAxiVdma_DmaSetup ReadCfg; - - //printf("VDMA HDIV: %d VDIV: %d\n", hdiv, vdiv); - - ReadCfg.VertSizeInput = vsize / vdiv; - ReadCfg.HoriSizeInput = (hsize * (Config->Mm2SStreamWidth >> 3)) / hdiv; // note: changing this breaks the output - ReadCfg.Stride = stride / hdiv; // note: changing this is not a problem - ReadCfg.FrameDelay = 0; /* This example does not test frame delay */ - ReadCfg.EnableCircularBuf = 1; /* Only 1 buffer, continuous loop */ - ReadCfg.EnableSync = 0; /* Gen-Lock */ - ReadCfg.PointNum = 0; - ReadCfg.EnableFrameCounter = 0; /* Endless transfers */ - ReadCfg.FixedFrameStoreAddr = 0; /* We are not doing parking */ - - ReadCfg.FrameStoreStartAddr[0] = bufpos; - - //printf("VDMA Framebuffer at 0x%x\n", ReadCfg.FrameStoreStartAddr[0]); - - status = XAxiVdma_DmaConfig(&vdma, XAXIVDMA_READ, &ReadCfg); - if (status != XST_SUCCESS) { - printf("VDMA Read channel config failed, status: 0x%X\r\n", status); - return status; - } - - status = XAxiVdma_DmaSetBufferAddr(&vdma, XAXIVDMA_READ, ReadCfg.FrameStoreStartAddr); - if (status != XST_SUCCESS) { - printf("VDMA Read channel set buffer address failed, status: 0x%X\r\n", status); - return status; - } - - status = XAxiVdma_DmaStart(&vdma, XAXIVDMA_READ); - if (status != XST_SUCCESS) { - printf("VDMA Failed to start DMA engine (read channel), status: 0x%X\r\n", status); - return status; - } - return XST_SUCCESS; -} - -u32 dump_vdma_status(XAxiVdma *InstancePtr) { - u32 status = XAxiVdma_GetStatus(InstancePtr, XAXIVDMA_READ); - - xil_printf("Read channel dump\n\r"); - xil_printf("\tMM2S DMA Control Register: %x\r\n", - XAxiVdma_ReadReg(InstancePtr->ReadChannel.ChanBase, - XAXIVDMA_CR_OFFSET)); - xil_printf("\tMM2S DMA Status Register: %x\r\n", - XAxiVdma_ReadReg(InstancePtr->ReadChannel.ChanBase, - XAXIVDMA_SR_OFFSET)); - xil_printf("\tMM2S HI_FRMBUF Reg: %x\r\n", - XAxiVdma_ReadReg(InstancePtr->ReadChannel.ChanBase, - XAXIVDMA_HI_FRMBUF_OFFSET)); - xil_printf("\tFRMSTORE Reg: %d\r\n", - XAxiVdma_ReadReg(InstancePtr->ReadChannel.ChanBase, - XAXIVDMA_FRMSTORE_OFFSET)); - xil_printf("\tBUFTHRES Reg: %d\r\n", - XAxiVdma_ReadReg(InstancePtr->ReadChannel.ChanBase, - XAXIVDMA_BUFTHRES_OFFSET)); - xil_printf("\tMM2S Vertical Size Register: %d\r\n", - XAxiVdma_ReadReg(InstancePtr->ReadChannel.ChanBase, - XAXIVDMA_MM2S_ADDR_OFFSET + XAXIVDMA_VSIZE_OFFSET)); - xil_printf("\tMM2S Horizontal Size Register: %d\r\n", - XAxiVdma_ReadReg(InstancePtr->ReadChannel.ChanBase, - XAXIVDMA_MM2S_ADDR_OFFSET + XAXIVDMA_HSIZE_OFFSET)); - xil_printf("\tMM2S Frame Delay and Stride Register: %d\r\n", - XAxiVdma_ReadReg(InstancePtr->ReadChannel.ChanBase, - XAXIVDMA_MM2S_ADDR_OFFSET + XAXIVDMA_STRD_FRMDLY_OFFSET)); - xil_printf("\tMM2S Start Address 1: %x\r\n", - XAxiVdma_ReadReg(InstancePtr->ReadChannel.ChanBase, - XAXIVDMA_MM2S_ADDR_OFFSET + XAXIVDMA_START_ADDR_OFFSET)); - - xil_printf("VDMA status: "); - if (status & XAXIVDMA_SR_HALTED_MASK) - xil_printf("halted\n"); - else - xil_printf("running\n"); - if (status & XAXIVDMA_SR_IDLE_MASK) - xil_printf("idle\n"); - if (status & XAXIVDMA_SR_ERR_INTERNAL_MASK) - xil_printf("internal err\n"); - if (status & XAXIVDMA_SR_ERR_SLAVE_MASK) - xil_printf("slave err\n"); - if (status & XAXIVDMA_SR_ERR_DECODE_MASK) - xil_printf("decode err\n"); - if (status & XAXIVDMA_SR_ERR_FSZ_LESS_MASK) - xil_printf("FSize Less Mismatch err\n"); - if (status & XAXIVDMA_SR_ERR_LSZ_LESS_MASK) - xil_printf("LSize Less Mismatch err\n"); - if (status & XAXIVDMA_SR_ERR_SG_SLV_MASK) - xil_printf("SG slave err\n"); - if (status & XAXIVDMA_SR_ERR_SG_DEC_MASK) - xil_printf("SG decode err\n"); - if (status & XAXIVDMA_SR_ERR_FSZ_MORE_MASK) - xil_printf("FSize More Mismatch err\n"); - - return status; -} - -void fb_fill(uint32_t offset) { - memset(framebuffer + offset, 0, 1280 * 1024 * 4); -} - -static XClk_Wiz clkwiz; - -void pixelclock_init_2(struct zz_video_mode *mode) { - XClk_Wiz_Config conf; - XClk_Wiz_CfgInitialize(&clkwiz, &conf, XPAR_CLK_WIZ_0_BASEADDR); - - u32 mul = mode->mul; - u32 div = mode->div; - u32 otherdiv = mode->div2; - - XClk_Wiz_WriteReg(XPAR_CLK_WIZ_0_BASEADDR, 0x200, (mul << 8) | div); - XClk_Wiz_WriteReg(XPAR_CLK_WIZ_0_BASEADDR, 0x208, otherdiv); - - // load configuration - XClk_Wiz_WriteReg(XPAR_CLK_WIZ_0_BASEADDR, 0x25C, 0x00000003); - //XClk_Wiz_WriteReg(XPAR_CLK_WIZ_0_BASEADDR, 0x25C, 0x00000001); -} - -// FIXME! -#define MNTZ_BASE_ADDR 0x43C00000 - -#define MNTZORRO_REG0 0 -#define MNTZORRO_REG1 4 -#define MNTZORRO_REG2 8 -#define MNTZORRO_REG3 12 -#define MNTZORRO_REG4 16 -#define MNTZORRO_REG5 20 - -#define mntzorro_read(BaseAddress, RegOffset) \ - Xil_In32((BaseAddress) + (RegOffset)) - -#define mntzorro_write(BaseAddress, RegOffset, Data) \ - Xil_Out32((BaseAddress) + (RegOffset), (u32)(Data)) - -#define VF_DLY ; - -// ONLY isr0 is allowed to call this! -void video_formatter_valign() { - // vertical alignment - mntzorro_write(MNTZ_BASE_ADDR, MNTZORRO_REG3, 1); - VF_DLY; - mntzorro_write(MNTZ_BASE_ADDR, MNTZORRO_REG2, 0x80000000 + 0x5); // OP_VSYNC - VF_DLY; - mntzorro_write(MNTZ_BASE_ADDR, MNTZORRO_REG2, 0x80000000); // NOP - VF_DLY; - mntzorro_write(MNTZ_BASE_ADDR, MNTZORRO_REG2, 0); // clear - VF_DLY; - mntzorro_write(MNTZ_BASE_ADDR, MNTZORRO_REG3, 0); // unlock access, NOP - VF_DLY; -} - -// ONLY isr0 is allowed to call this! -void video_formatter_write(uint32_t data, uint16_t op) { - mntzorro_write(MNTZ_BASE_ADDR, MNTZORRO_REG3, data); - VF_DLY; - mntzorro_write(MNTZ_BASE_ADDR, MNTZORRO_REG2, 0x80000000 | op); // OP_MAX (vmax | hmax) - VF_DLY; - mntzorro_write(MNTZ_BASE_ADDR, MNTZORRO_REG2, 0x80000000); // NOP - VF_DLY; - mntzorro_write(MNTZ_BASE_ADDR, MNTZORRO_REG2, 0); // clear - VF_DLY; - mntzorro_write(MNTZ_BASE_ADDR, MNTZORRO_REG3, 0); // unlock access, NOP - VF_DLY; -} - -void video_formatter_init(int scalemode, int colormode, int width, int height, - int htotal, int vtotal, int hss, int hse, int vss, int vse, - int polarity) { - video_formatter_write((vtotal << 16) | htotal, MNTVF_OP_MAX); - video_formatter_write((height << 16) | width, MNTVF_OP_DIMENSIONS); - video_formatter_write((hss << 16) | hse, MNTVF_OP_HS); - video_formatter_write((vss << 16) | vse, MNTVF_OP_VS); - video_formatter_write(polarity, MNTVF_OP_POLARITY); - video_formatter_write(scalemode, MNTVF_OP_SCALE); - video_formatter_write(colormode, MNTVF_OP_COLORMODE); - - video_formatter_valign(); -} - -void video_system_init(struct zz_video_mode *mode, int hdiv, int vdiv) { - pixelclock_init_2(mode); - hdmi_ctrl_init(mode); - init_vdma(mode->hres, mode->vres, hdiv, vdiv, (u32)framebuffer + framebuffer_pan_offset); -} - -// Our address space is relative to the autoconfig base address (for example, it could be 0x600000) -#define MNT_REG_BASE 0x000000 -// Frame buffer/graphics memory starts at 64KB, leaving ample space for general purpose registers. -#define MNT_FB_BASE 0x010000 - -#define REVISION_MAJOR 1 -#define REVISION_MINOR 9 - -int scalemode = 0; - -static int interrupt_enabled_audio = 0; -static int interrupt_waiting_audio = 0; -static int audio_buffer_collision = 0; -static uint32_t audio_scale = 1; - -int isra_count = 0; - -// audio formatter interrupt, triggered whenever a period is completed -void isr_audio(void *dummy) { - uint32_t val = XAudioFormatter_ReadReg(XPAR_XAUDIOFORMATTER_0_BASEADDR, XAUD_FORMATTER_STS + XAUD_FORMATTER_MM2S_OFFSET); - val |= (1<<31); // clear irq - XAudioFormatter_WriteReg(XPAR_XAUDIOFORMATTER_0_BASEADDR, - XAUD_FORMATTER_STS + XAUD_FORMATTER_MM2S_OFFSET, val); - - if (isra_count++>100) { - printf("[isra]\n"); - isra_count = 0; - } - - if (interrupt_enabled_audio) { - 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; - } -} - -int israrx_count = 0; - -// audio formatter interrupt, triggered whenever a period is completed -void isr_audio_rx(void *dummy) { - uint32_t val = XAudioFormatter_ReadReg(XPAR_XAUDIOFORMATTER_1_BASEADDR, XAUD_FORMATTER_STS + XAUD_FORMATTER_S2MM_OFFSET); - val |= (1<<31); // clear irq - XAudioFormatter_WriteReg(XPAR_XAUDIOFORMATTER_1_BASEADDR, - XAUD_FORMATTER_STS + XAUD_FORMATTER_S2MM_OFFSET, val); - - if (israrx_count++>100) { - printf("[isra_rx]\n"); - israrx_count = 0; - } -} - -void video_mode_init(int mode, int scalemode, int colormode) { - printf("video_mode_init: %d color: %d scale: %d\n", mode, colormode, scalemode); - - int hdiv = 1, vdiv = 1; - stride_div = 1; - - if (scalemode & 1) { - hdiv = 2; - stride_div = 2; - } - if (scalemode & 2) - vdiv = 2; - - // 8 bit - if (colormode == MNTVA_COLOR_8BIT) - hdiv *= 4; - - if (colormode == MNTVA_COLOR_16BIT565 || colormode == MNTVA_COLOR_15BIT) - hdiv *= 2; - - struct zz_video_mode *vmode = &preset_video_modes[mode]; - - video_system_init(vmode, hdiv, vdiv); - - video_formatter_init(scalemode, colormode, - vmode->hres, vmode->vres, - vmode->hmax, vmode->vmax, - vmode->hstart, vmode->hend, - vmode->vstart, vmode->vend, - vmode->polarity); - - vmode_hsize = vmode->hres; - vmode_vsize = vmode->vres; - vmode_vdiv = vdiv; - vmode_hdiv = hdiv; -} - -int16_t sprite_x = 0, sprite_x_adj = 0, sprite_x_base = 0; -int16_t sprite_y = 0, sprite_y_adj = 0, sprite_y_base = 0; -int16_t sprite_x_offset = 0; -int16_t sprite_y_offset = 0; - -uint8_t sprite_width = 16; -uint8_t sprite_height = 16; - -uint32_t sprite_buf[32 * 48]; -uint8_t sprite_clipped = 0; -int16_t sprite_clip_x = 0, sprite_clip_y = 0; - -uint32_t sprite_colors[4] = { 0x00ff00ff, 0x00000000, 0x00000000, 0x00000000 }; - -int sprite_request_update_pos = 0; -int sprite_request_update_data = 0; -int sprite_request_show = 0; -int sprite_request_hide = 0; -int sprite_request_pos_x = 0; -int sprite_request_pos_y = 0; -int sprite_showing = 0; -int split_request_pos = 0; - -// FIXME: move all sprite and video formatter related things to another file -void update_hw_sprite(uint8_t *data, uint32_t *colors, uint16_t w, uint16_t h) -{ - uint8_t cur_bit = 0x80; - uint8_t cur_color = 0, out_pos = 0, iter_offset = 0; - uint8_t line_pitch = (w / 8) * 2; - uint8_t cur_bytes[8]; - - for (uint8_t y_line = 0; y_line < h; y_line++) { - if (w <= 16) { - cur_bytes[0] = data[y_line * line_pitch]; - cur_bytes[1] = data[(y_line * line_pitch) + 2]; - cur_bytes[2] = data[(y_line * line_pitch) + 1]; - cur_bytes[3] = data[(y_line * line_pitch) + 3]; - } - else { - cur_bytes[0] = data[y_line * line_pitch]; - cur_bytes[1] = data[(y_line * line_pitch) + 4]; - cur_bytes[2] = data[(y_line * line_pitch) + 1]; - cur_bytes[3] = data[(y_line * line_pitch) + 5]; - cur_bytes[4] = data[(y_line * line_pitch) + 2]; - cur_bytes[5] = data[(y_line * line_pitch) + 6]; - cur_bytes[6] = data[(y_line * line_pitch) + 3]; - cur_bytes[7] = data[(y_line * line_pitch) + 7]; - } - - while (out_pos < 8) { - for (uint8_t i = 0; i < line_pitch; i += 2) { - cur_color = (cur_bytes[i] & cur_bit) ? 1 : 0; - if (cur_bytes[i + 1] & cur_bit) cur_color += 2; - - sprite_buf[(y_line * 32) + out_pos + iter_offset] = colors[cur_color] & 0x00ffffff; - iter_offset += 8; - } - - out_pos++; - cur_bit >>= 1; - iter_offset = 0; - } - cur_bit = 0x80; - out_pos = 0; - } - - sprite_request_update_data = 1; -} - -void update_hw_sprite_clut(uint8_t *data_, uint8_t *colors, uint16_t w, uint16_t h, uint8_t keycolor) -{ - uint8_t *data = data_; - uint8_t color[4]; - - for (int y = 0; y < h && y < 48; y++) { - for (int x = 0; x < w && x < 32; x++) { - if (data[x] == keycolor) { - *((uint32_t *)color) = 0x00ff00ff; - } - else { - color[0] = colors[(data[x] * 3)+2]; - color[1] = colors[(data[x] * 3)+1]; - color[2] = colors[(data[x] * 3)]; - color[3] = 0x00; - if (*((uint32_t *)color) == 0x00FF00FF) - *((uint32_t *)color) = 0x00FE00FE; - } - sprite_buf[(y * 32) + x] = *((uint32_t *)color); - } - data += w; - } - - sprite_request_update_data = 1; -} - -void clear_hw_sprite() -{ - for (uint16_t i = 0; i < 32 * 48; i++) { - sprite_buf[i] = 0x00ff00ff; - } - //sprite_request_update_data = 1; -} - -void _clip_hw_sprite(int16_t offset_x, int16_t offset_y) -{ - uint16_t xo = 0, yo = 0; - if (offset_x < 0) - xo = -offset_x; - if (offset_y < 0) - yo = -offset_y; - - for (int y = 0; y < 48; y++) { - //printf("CLIP %02d: ",y); - for (int x = 0; x < 32; x++) { - video_formatter_write((y * 32) + x, 14); - if (x < 32 - xo && y < 48 - yo) { - //printf("%06lx", sprite_buf[((y + yo) * 32) + (x + xo)] & 0x00ffffff); - video_formatter_write(sprite_buf[((y + yo) * 32) + (x + xo)] & 0x00ffffff, 15); - } else { - //printf("%06lx", 0x00ff00ff); - video_formatter_write(0x00ff00ff, 15); - } - } - //printf("\n"); - } -} - -void _update_hw_sprite_pos(int16_t x, int16_t y) { - sprite_x = x - sprite_x_offset + 1; - // horizontally doubled mode - if (scalemode & 1) - sprite_x_adj = (sprite_x * 2) + 1; - else - sprite_x_adj = sprite_x + 2; - - sprite_y = y + split_pos - sprite_y_offset + 1; - - // vertically doubled mode - if (scalemode & 2) - sprite_y_adj = sprite_y *= 2; - else - sprite_y_adj = sprite_y; - - if (sprite_x < 0 || sprite_y < 0) { - if (sprite_clip_x != sprite_x || sprite_clip_y != sprite_y) { - _clip_hw_sprite((sprite_x < 0) ? sprite_x : 0, (sprite_y < 0) ? sprite_y : 0); - } - sprite_clipped = 1; - if (sprite_x < 0) { - sprite_x_adj = 0; - sprite_clip_x = sprite_x; - } - if (sprite_y < 0) { - sprite_y_adj = 0; - sprite_clip_y = sprite_y; - } - } - else if (sprite_clipped && sprite_x >= 0 && sprite_y >= 0) { - _clip_hw_sprite(0, 0); - sprite_clipped = 0; - } -} -void update_hw_sprite_pos(int16_t x, int16_t y) { - sprite_request_pos_x = x; - sprite_request_pos_y = y; - sprite_request_update_pos = 1; -} +struct ZZ_VIDEO_STATE* video_state; -// this mode can be changed by amiga software to select a different resolution / framerate for -// native video capture -//static int videocap_video_mode = ZZVMODE_720x576; -//static int video_mode = ZZVMODE_720x576|2<<12|MNTVA_COLOR_32BIT<<8; -//static int default_pan_offset = 0x00e00000; - -// default to more compatible 60hz mode -static int videocap_video_mode = ZZVMODE_800x600; -static int video_mode = ZZVMODE_800x600 | 2 << 12 | MNTVA_COLOR_32BIT << 8; -static int default_pan_offset_pal_800x600 = 0x00dff2f8; -static int default_pan_offset_pal = 0x00e00000; -static int default_pan_offset_ntsc = 0x00e00000; -static int interlace_old = -1; -static int videocap_ntsc_old = -1; -static int videocap_enabled_old = 0; +// FIXME +// This is the absolute offset in ZZ9000 RAM for the "framebuffer transfer register", +// which can be replaced by the DMA acceleration functionality entirely, but some +// software still relies on this legacy register. +unsigned int cur_mem_offset = 0x3500000; static char usb_storage_available = 0; static uint32_t usb_storage_read_block = 0; @@ -1163,240 +104,20 @@ static uint32_t usb_storage_write_block = 0; uint16_t ethernet_send_result = 0; static int backlog_nag_counter = 0; static int interrupt_enabled_ethernet = 0; -static int interrupt_signal_ethernet = 0; static int interrupt_waiting_ethernet = 0; // usb state uint16_t usb_status = 0; -// we can read or write a number of USB blocks at once, and amiga can select which one is mapped at the USB storage buffer area -uint32_t usb_selected_buffer_block = 0; uint32_t usb_read_write_num_blocks = 1; // debug things like individual reads/writes, greatly slowing the system down uint32_t debug_lowlevel = 0; -void videocap_area_clear() { - fb_fill(0x00dff000 / 4); -} - -#define INTC_INTERRUPT_ID_0 61 // IRQ_F2P[0:0] -#define INTC_INTERRUPT_ID_1 62 // IRQ_F2P[1:1] -#define INTC_INTERRUPT_ID_2 63 // IRQ_F2P[2:2] // FIXME: validate - -static int isr_flush_count=0; - -int vblank_count = 0; - -// interrupt service routine for IRQ_F2P[0:0] -// vblank + raster position interrupt -void isr0 (void *dummy) { - u32 zstate = mntzorro_read(MNTZ_BASE_ADDR, MNTZORRO_REG3); - - int vblank = (zstate & (1 << 21)); - int videocap_enabled = (zstate & (1 << 23)); - int videocap_ntsc = (zstate & (1 << 22)); - int interlace = !!(zstate & (1 << 24)); - - if (!videocap_enabled) { - if (!vblank) { - // if this is not the vblank interrupt, set up the split buffer - // TODO: VDMA doesn't seem to like switching buffers in the middle of a frame. - // the first line after a switch contains an extraneous word, so we end up - // with up to 4 pixels of the other buffer in the first line - if (split_pos != 0) { - if (card_feature_enabled[CARD_FEATURE_SECONDARY_PALETTE]) { - video_formatter_write(1, MNTVF_OP_PALETTE_SEL); - } - init_vdma(vmode_hsize, vmode_vsize, vmode_hdiv, vmode_vdiv, (u32)framebuffer + bgbuf_offset); - } - } else { - // if this is the vblank interrupt, set up the "normal" buffer in split mode - if (card_feature_enabled[CARD_FEATURE_SECONDARY_PALETTE]) { - video_formatter_write(0, MNTVF_OP_PALETTE_SEL); - } - init_vdma(vmode_hsize, vmode_vsize, vmode_hdiv, vmode_vdiv, (u32)framebuffer + framebuffer_pan_offset); - } - } else { - // FIXME magic constant - if (framebuffer_pan_offset >= 0x00dff000) { - // videocap is enabled and - // we are looking at the videocap area - // so set up the right mode for it - - int videocap_reset = 0; - - if (!videocap_enabled_old) { - videocap_area_clear(); - // force mode cleanup - videocap_reset = 1; - } - - if (videocap_ntsc != videocap_ntsc_old || videocap_reset) { - // change between ntsc+pal - videocap_area_clear(); - - // hide sprite - sprite_request_hide = 1; - - if (videocap_ntsc) { - // NTSC - printf("videocap: ntsc\n"); - framebuffer_pan_width = 0; - framebuffer_pan_offset = default_pan_offset_ntsc; - if (card_feature_enabled[CARD_FEATURE_NONSTANDARD_VSYNC]) { - init_ns_video_mode(ZZVMODE_720x480); - } else { - video_mode_init(ZZVMODE_720x480, 2, MNTVA_COLOR_32BIT); - - // use this if there are problems with 720x480 - //video_mode_init(ZZVMODE_800x600, 2, MNTVA_COLOR_32BIT); - } - } else { - // PAL - printf("videocap: pal\n"); - framebuffer_pan_width = 0; - if (videocap_video_mode == ZZVMODE_800x600) { - framebuffer_pan_offset = default_pan_offset_pal_800x600; - } else { - framebuffer_pan_offset = default_pan_offset_pal; - } - if (videocap_video_mode == ZZVMODE_720x576 && card_feature_enabled[CARD_FEATURE_NONSTANDARD_VSYNC]) { - init_ns_video_mode(ZZVMODE_720x576); - } else { - video_mode_init(videocap_video_mode, 2, MNTVA_COLOR_32BIT); - } - } - videocap_reset = 1; - } - - if (interlace != interlace_old || videocap_reset) { - // interlace has changed, we need to reconfigure vdma for the new screen height - vmode_vdiv = 2; - if (interlace) { - vmode_vdiv = 1; - } - videocap_area_clear(); - init_vdma(vmode_hsize, vmode_vsize, 1, vmode_vdiv, (u32)framebuffer + framebuffer_pan_offset); - video_formatter_valign(); - printf("videocap interlace mode changed to %d.\n", interlace); - } - - interlace_old = interlace; - videocap_ntsc_old = videocap_ntsc; - videocap_enabled_old = videocap_enabled; - } else { - // not looking at the videocap area - videocap_enabled_old = 0; - videocap_ntsc_old = -1; - interlace_old = -1; - } - } - - // on vblanks, handle arm cache flush, amiga interrupts and sprites - if (!vblank || (split_pos == 0)) { - // flush the data caches synchronized to full frames - Xil_L1DCacheFlush(); - Xil_L2CacheFlush(); - isr_flush_count = 0; - - if ((interrupt_signal_ethernet && 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 - interrupt_signal_ethernet = 0; - } - - if (sprite_request_show) { - sprite_showing = 1; - sprite_request_show = 0; - } - - if (sprite_request_update_data) { - _clip_hw_sprite(0, 0); - sprite_request_update_data = 0; - } - - if (sprite_request_update_pos) { - _update_hw_sprite_pos(sprite_request_pos_x, sprite_request_pos_y); - video_formatter_write((sprite_y_adj << 16) | sprite_x_adj, MNTVF_OP_SPRITE_XY); - sprite_request_update_pos = 0; - } - - if (sprite_request_hide) { - sprite_x = 2000; - sprite_y = 2000; - video_formatter_write((sprite_y << 16) | sprite_x, MNTVF_OP_SPRITE_XY); - sprite_showing = 0; - sprite_request_hide = 0; - } - - // handle screen dragging - if (split_request_pos != split_pos) { - split_pos = split_request_pos; - video_formatter_write(split_pos, MNTVF_OP_REPORT_LINE); - } - } - - vblank_count++; -} - -int fpga_interrupt_init() { - int result; - XScuGic *intc_instance_ptr = interrupt_get_intc(); - - printf("XScuGic_SetPriorityTriggerType()\n"); - - // set the priority of IRQ_F2P[0:0] to 0xA0 (highest 0xF8, lowest 0x00) and a trigger for a rising edge 0x3. - XScuGic_SetPriorityTriggerType(intc_instance_ptr, INTC_INTERRUPT_ID_0, 0xA0, 0x3); // vblank / split - XScuGic_SetPriorityTriggerType(intc_instance_ptr, INTC_INTERRUPT_ID_1, 0x90, 0x3); // audio formatter TX - XScuGic_SetPriorityTriggerType(intc_instance_ptr, INTC_INTERRUPT_ID_2, 0x90, 0x3); // audio formatter RX - - printf("XScuGic_Connect()\n"); - - // connect the interrupt service routine isr0 to the interrupt controller - result = XScuGic_Connect(intc_instance_ptr, INTC_INTERRUPT_ID_0, (Xil_ExceptionHandler)isr0, NULL); - result = XScuGic_Connect(intc_instance_ptr, INTC_INTERRUPT_ID_1, (Xil_ExceptionHandler)isr_audio, NULL); - result = XScuGic_Connect(intc_instance_ptr, INTC_INTERRUPT_ID_2, (Xil_ExceptionHandler)isr_audio_rx, NULL); - - if (result != XST_SUCCESS) { - printf("XScuGic_Connect() failed!\n"); - return result; - } - - printf("XScuGic_Enable()\n"); - - // enable interrupts for IRQ_F2P[0:0] - XScuGic_Enable(intc_instance_ptr, INTC_INTERRUPT_ID_0); - // enable interrupts for IRQ_F2P[1:1] - XScuGic_Enable(intc_instance_ptr, INTC_INTERRUPT_ID_1); - // enable interrupts for IRQ_F2P[2:2] - XScuGic_Enable(intc_instance_ptr, INTC_INTERRUPT_ID_2); - - return 0; -} - -void init_ns_video_mode(uint32_t mode_num) { - printf("init_ns_video_mode(%d)\n", mode_num); - if (mode_num == ZZVMODE_720x576) { - video_mode_init(ZZVMODE_720x576_NS_PAL + scandoubler_mode_adjust, 2, MNTVA_COLOR_32BIT); - } else { - video_mode_init(ZZVMODE_720x480_NS_PAL + scandoubler_mode_adjust, 2, MNTVA_COLOR_32BIT); - } -} +// audio state (ZZ9000AX) +static int audio_buffer_collision = 0; +static uint32_t audio_scale = 1; +static int adau_enabled = 0; void handle_amiga_reset() { - framebuffer_pan_width = 0; - framebuffer_pan_offset = default_pan_offset_pal_800x600; - split_request_pos = 0; - sprite_request_hide = 1; - - // Used for testing the nonstandard VSync modes without the driver having to enable them. - //card_feature_enabled[CARD_FEATURE_NONSTANDARD_VSYNC] = 1; - - videocap_enabled_old = 0; - printf(" _______________ ___ ___ ___ \n"); printf(" |___ /___ / _ \\ / _ \\ / _ \\ / _ \\ \n"); printf(" / / / / (_) | | | | | | | | | |\n"); @@ -1404,217 +125,69 @@ void handle_amiga_reset() { printf(" / /__ / /__ / /| |_| | |_| | |_| |\n"); printf(" /_____/_____|/_/ \\___/ \\___/ \\___/ \n\n"); - usb_storage_available = zz_usb_init(); + video_reset(); + // usb + usb_storage_available = zz_usb_init(); usb_status = 0; - usb_selected_buffer_block = 0; usb_read_write_num_blocks = 1; + + // ethernet ethernet_send_result = 0; backlog_nag_counter = 0; interrupt_enabled_ethernet = 0; - interrupt_enabled_audio = 0; // FIXME document cur_mem_offset = 0x3500000; - // FIXME temporary: clear audio buffer on reset - memset(AUDIO_TX_BUFFER_ADDRESS, 0, AUDIO_TX_BUFFER_SIZE); + // FIXME + memset((u32 *)Z3_SCRATCH_ADDR, 0, sizeof(struct GFXData)); - // FIXME there should be more state to be reset + // FIXME temporary: clear audio buffer on reset + memset((void*)AUDIO_TX_BUFFER_ADDRESS, 0, AUDIO_TX_BUFFER_SIZE); + + // FIXME test content for audio buffer + /*int16_t* adata = (uint16_t*)(((void*)AUDIO_TX_BUFFER_ADDRESS)); + float f = 1; + for (int i=0; i<AUDIO_TX_BUFFER_SIZE/2; i++) { + adata[i] = (sin((float)i/200.0)*65536)*f; + f-=0.0001; + }*/ // clear interrupt holding amiga mntzorro_write(MNTZ_BASE_ADDR, MNTZORRO_REG2, (1 << 30) | 0); -} - -uint16_t arm_app_output_event_serial = 0; -uint16_t arm_app_output_event_code = 0; -char arm_app_output_event_ack = 0; -uint16_t arm_app_output_events_blocking = 0; -uint16_t arm_app_output_putchar_to_events = 0; -uint16_t arm_app_input_event_serial = 0; -uint16_t arm_app_input_event_code = 0; -char arm_app_input_event_ack = 0; - -uint32_t arm_app_output_events_timeout = 100000; - -void arm_app_put_event_code(uint16_t code) { - arm_app_output_event_code = code; - arm_app_output_event_ack = 0; - arm_app_output_event_serial++; -} - -char arm_app_output_event_acked() { - return arm_app_output_event_ack; -} -void arm_app_set_output_events_blocking(char blocking) { - arm_app_output_events_blocking = blocking; -} - -void arm_app_set_output_putchar_to_events(char putchar_enabled) { - arm_app_output_putchar_to_events = putchar_enabled; -} - -uint16_t arm_app_get_event_serial() { - return arm_app_input_event_serial; -} - -uint16_t arm_app_get_event_code() { - arm_app_input_event_ack = 1; - return arm_app_input_event_code; -} - -int __attribute__ ((visibility ("default"))) _putchar(char c) { - if (arm_app_output_putchar_to_events) { - if (arm_app_output_events_blocking) { - for (uint32_t i = 0; i < arm_app_output_events_timeout; i++) { - usleep(1); - if (arm_app_output_event_ack) - break; - } - } - arm_app_put_event_code(c); - } - return putchar(c); + // Used for testing the nonstandard VSync modes without the driver having to enable them. + //card_feature_enabled[CARD_FEATURE_NONSTANDARD_VSYNC] = 1; } -struct ZZ9K_ENV { - uint32_t api_version; - uint32_t argv[8]; - uint32_t argc; - - int (*fn_putchar)(char); - void (*fn_set_output_putchar_to_events)(char); - void (*fn_set_output_events_blocking)(char); - void (*fn_put_event_code)(uint16_t); - uint16_t (*fn_get_event_serial)(); - uint16_t (*fn_get_event_code)(); - char (*fn_output_event_acked)(); -}; - -void arm_exception_handler_id_reset(void *callback); -void arm_exception_handler_id_data_abort(void *callback); -void arm_exception_handler_id_prefetch_abort(void *callback); -void arm_exception_handler_illinst(void *callback); -void DataAbort_InterruptHandler(void *InstancePtr); - -volatile struct ZZ9K_ENV arm_run_env; -volatile void (*core1_trampoline)(volatile struct ZZ9K_ENV* env); -volatile int core2_execute = 0; - -#pragma GCC push_options -#pragma GCC optimize ("O1") -// core1_loop is executed on core1 (vs core0) -void core1_loop() { - asm("mov r0, r0"); - asm("mrc p15, 0, r1, c1, c0, 2"); - /* read cp access control register (CACR) into r1 */ - asm("orr r1, r1, #(0xf << 20)"); - /* enable full access for p10 & p11 */ - asm("mcr p15, 0, r1, c1, c0, 2"); - /* write back into CACR */ - - // enable FPU - asm("fmrx r1, FPEXC"); - /* read the exception register */ - asm("orr r1,r1, #0x40000000"); - /* set VFP enable bit, leave the others in orig state */ - asm("fmxr FPEXC, r1"); - /* write back the exception register */ - - // enable flow prediction - asm("mrc p15,0,r0,c1,c0,0"); - /* flow prediction enable */ - asm("orr r0, r0, #(0x01 << 11)"); - /* #0x8000 */ - asm("mcr p15,0,r0,c1,c0,0"); - - asm("mrc p15,0,r0,c1,c0,1"); - /* read Auxiliary Control Register */ - asm("orr r0, r0, #(0x1 << 2)"); - /* enable Dside prefetch */ - asm("orr r0, r0, #(0x1 << 1)"); - /* enable L2 Prefetch hint */ - asm("mcr p15,0,r0,c1,c0,1"); - /* write Auxiliary Control Register */ - - // stack - asm("mov sp, #0x06000000"); - - volatile uint32_t* addr = 0; - addr[0] = 0xe3e0000f; // mvn r0, #15 -- loads 0xfffffff0 - addr[1] = 0xe590f000; // ldr pc, [r0] -- jumps to the address in that address - - // FIXME these don't seem to do anything useful yet - Xil_ExceptionRegisterHandler(XIL_EXCEPTION_ID_RESET, - (Xil_ExceptionHandler) arm_exception_handler_id_reset, NULL); - Xil_ExceptionRegisterHandler(XIL_EXCEPTION_ID_DATA_ABORT_INT, - (Xil_ExceptionHandler) arm_exception_handler_id_data_abort, NULL); - Xil_ExceptionRegisterHandler(XIL_EXCEPTION_ID_PREFETCH_ABORT_INT, - (Xil_ExceptionHandler) arm_exception_handler_id_prefetch_abort, NULL); - Xil_ExceptionRegisterHandler(XIL_EXCEPTION_ID_UNDEFINED_INT, - (Xil_ExceptionHandler) arm_exception_handler_illinst, NULL); - - while (1) { - while (!core2_execute) { - usleep(1); - } - core2_execute = 0; - printf("[CPU1] executing at %p.\n", core1_trampoline); - Xil_DCacheFlush(); - Xil_ICacheInvalidate(); - - asm("push {r0-r12}"); - // FIXME HACK save our stack pointer in 0x10000 - asm("mov r0, #0x00010000"); - asm("str sp, [r0]"); +int main() { + init_platform(); - core1_trampoline(&arm_run_env); + boot_rom_init(); - asm("mov r0, #0x00010000"); - asm("ldr sp, [r0]"); - asm("pop {r0-r12}"); - } -} -#pragma GCC pop_options + disable_reset_out(); -int main() { - const char* zstates[53] = { "RESET ", "Z2_CONF ", "Z2_IDLE ", "WAIT_WRI", - "WAIT_WR2", "Z2WRIFIN", "WAIT_RD ", "WAIT_RD2", "WAIT_RD3", - "CONFIGED", "CONF_CLR", "D_Z2_Z3 ", "Z3_IDLE ", "Z3_WRITE_UPP", - "Z3_WRITE_LOW", "Z3_READ_UP", "Z3_READ_LOW", "Z3_READ_DLY", - "Z3_READ_DLY1", "Z3_READ_DLY2", "Z3_WRITE_PRE", "Z3_WRITE_FIN", - "Z3_ENDCYCLE", "Z3_DTACK", "Z3_CONFIG", "Z2_REGWRITE", "REGWRITE", - "REGREAD", "Z2_REGR_POST", "Z3_REGR_POST", "Z3_REGWRITE", - "Z2_REGREAD", "Z3_REGREAD", "NONE_33", "Z2_PRE_CONF", "Z2_ENDCYCLE", - "NONE_36", "NONE_37", "NONE_38", "RESET_DVID", "COLD", "WR2B", - "WR2C", "Z3DMA1", "Z3DMA2", "Z3_AUTOCONF_RD", "Z3_AUTOCONF_WR", - "Z3_AUTOCONF_RD_DLY", "Z3_AUTOCONF_RD_DLY2", "Z3_REGWRITE_PRE", - "Z3_REGREAD_PRE", "Z3_WRITE_PRE2", "UNDEF", }; + video_init(); - init_platform(); + xadc_init(); - Xil_ExceptionRegisterHandler(XIL_EXCEPTION_ID_DATA_ABORT_INT, - (Xil_ExceptionHandler) arm_exception_handler_id_data_abort, NULL); - Xil_ExceptionRegisterHandler(XIL_EXCEPTION_ID_PREFETCH_ABORT_INT, - (Xil_ExceptionHandler) arm_exception_handler_id_prefetch_abort, NULL); - Xil_ExceptionRegisterHandler(XIL_EXCEPTION_ID_UNDEFINED_INT, - (Xil_ExceptionHandler) arm_exception_handler_illinst, NULL); + interrupt_configure(); - memset((u32 *)Z3_SCRATCH_ADDR, 0, sizeof(struct GFXData)); + ethernet_init(); - boot_rom_init(); + handle_amiga_reset(); - disable_reset_out(); + adau_enabled = audio_adau_init((uint32_t*)AUDIO_TX_BUFFER_ADDRESS); - xadc_init(); + fpga_interrupt_connect(isr_video, isr_audio, isr_audio_rx); - // FIXME constant - framebuffer = (u32*) 0x00200000; - int need_req_ack = 0; - u8* mem = (u8*) framebuffer; + // ARM app run environment + arm_app_init(); + volatile struct ZZ9K_ENV* arm_run_env = arm_app_get_run_env(); + uint32_t arm_run_address = 0; - // blitter etc + // graphics temporary registers uint16_t rect_x1 = 0; uint16_t rect_x2 = 0; uint16_t rect_x3 = 0; @@ -1626,63 +199,21 @@ int main() { uint32_t rect_rgb2 = 0; uint32_t blitter_colormode = MNTVA_COLOR_32BIT; uint16_t blitter_src_pitch = 0; - uint16_t blitter_user1 = 0; uint16_t blitter_user2 = 0; - uint16_t blitter_user3 = 0; - uint16_t blitter_user4 = 0; - // ARM app run environment - arm_run_env.api_version = 1; - arm_run_env.fn_putchar = _putchar; - arm_run_env.fn_get_event_code = arm_app_get_event_code; - arm_run_env.fn_get_event_serial = arm_app_get_event_serial; - arm_run_env.fn_output_event_acked = arm_app_output_event_acked; - arm_run_env.fn_put_event_code = arm_app_put_event_code; - arm_run_env.fn_set_output_events_blocking = - arm_app_set_output_events_blocking; - arm_run_env.fn_set_output_putchar_to_events = - arm_app_set_output_putchar_to_events; - - arm_run_env.argc = 0; - uint32_t arm_run_address = 0; + // custom video mode + int custom_video_mode = ZZVMODE_CUSTOM; + int custom_vmode_param = VMODE_PARAM_HRES; // zorro state u32 zstate_raw; + int need_req_ack = 0; - /*for (int i=0; i<5; i++) { - printf("Initial sleep...\n"); - sleep(1); - }*/ - - interrupt_configure(); - ethernet_init(); - - handle_amiga_reset(); - init_adau(framebuffer); - fpga_interrupt_init(); - - printf("launch core1...\n"); - volatile uint32_t* core1_addr = (volatile uint32_t*) 0xFFFFFFF0; - *core1_addr = (uint32_t) core1_loop; - // Place some machine code in strategic positions that will catch core1 if it crashes - // FIXME: clean this up and turn into a debug handler / monitor - volatile uint32_t* core1_addr2 = (volatile uint32_t*) 0x140; // catch 1 - core1_addr2[0] = 0xe3e0000f; // mvn r0, #15 -- loads 0xfffffff0 - core1_addr2[1] = 0xe590f000; // ldr pc, [r0] -- jumps to the address in that address - - core1_addr2 = (volatile uint32_t*) 0x100; // catch 2 - core1_addr2[0] = 0xe3e0000f; // mvn r0, #15 -- loads 0xfffffff0 - core1_addr2[1] = 0xe590f000; // ldr pc, [r0] -- jumps to the address in that address - - asm("sev"); - printf("core1 now idling.\n"); - - int colormode = 0; - video_mode = 0x2200; - - int custom_video_mode = ZZVMODE_CUSTOM; - int custom_vmode_param = VMODE_PARAM_HRES; + // decoder parameters (mp3 etc) + const int ZZ_NUM_DECODER_PARAMS = 8; + uint16_t decoder_params[ZZ_NUM_DECODER_PARAMS]; + int decoder_param = 0; // selected parameter while (1) { u32 zstate = mntzorro_read(MNTZ_BASE_ADDR, MNTZORRO_REG3); @@ -1706,10 +237,10 @@ int main() { if (zaddr > 0x10000000) { printf("ERRW illegal address %08lx\n", zaddr); } else if (zaddr >= MNT_FB_BASE || zaddr >= MNT_REG_BASE + 0x2000) { - u8* ptr = mem; + u8* ptr = (u8*)FRAMEBUFFER_ADDRESS; if (zaddr >= MNT_FB_BASE) { - ptr = mem + zaddr - MNT_FB_BASE; + ptr = ptr + zaddr - MNT_FB_BASE; } else if (zaddr < MNT_REG_BASE + 0x8000) { // NOP (RX frame is here) } else if (zaddr < MNT_REG_BASE + 0xa000) { @@ -1754,24 +285,24 @@ int main() { switch (zaddr) { // Various blitter/video registers case REG_ZZ_PAN_HI: - framebuffer_pan_offset = zdata << 16; + video_state->framebuffer_pan_offset = zdata << 16; break; case REG_ZZ_PAN_LO: - framebuffer_pan_offset |= zdata; + video_state->framebuffer_pan_offset |= zdata; - // cursor offset support for p96 split screen - sprite_x_offset = rect_x1; - sprite_y_offset = rect_y1; + // FIXME cursor offset support for p96 split screen + video_state->sprite_x_offset = rect_x1; + video_state->sprite_y_offset = rect_y1; // FIXME: document/comment this. rect_x1/x2/y1 are used for panning inside of a screen // together with blitter_colormode // TODO: rework to dedicated registers because this makes it hard to debug - framebuffer_pan_width = rect_x2; - framebuffer_color_format = blitter_colormode; - framebuffer_pan_offset += (rect_x1 << blitter_colormode); - if (split_pos == 0) { - framebuffer_pan_offset += (rect_y1 * (framebuffer_pan_width << framebuffer_color_format)); + video_state->framebuffer_pan_width = rect_x2; + u32 framebuffer_color_format = blitter_colormode; + video_state->framebuffer_pan_offset += (rect_x1 << blitter_colormode); + if (video_state->split_pos == 0) { + video_state->framebuffer_pan_offset += (rect_y1 * (video_state->framebuffer_pan_width << framebuffer_color_format)); } break; @@ -1802,72 +333,66 @@ int main() { interrupt_waiting_ethernet = 0; } if (zdata & 32) { - //printf("[clear] audio\n"); - interrupt_waiting_audio = 0; + audio_clear_interrupt(); } } else { - printf("[enable] eth: %d\n", zdata); + printf("[enable] eth: %d\n", (int)zdata); interrupt_enabled_ethernet = zdata & 1; } break; case REG_ZZ_MODE: { - // reset interlace tracking - interlace_old = -1; - int mode = zdata & 0xff; - colormode = (zdata & 0xf00) >> 8; - scalemode = (zdata & 0xf000) >> 12; - printf("mode change: %d color: %d scale: %d\n", mode, colormode, scalemode); + int colormode = (zdata & 0xf00) >> 8; + int scalemode = (zdata & 0xf000) >> 12; video_mode_init(mode, scalemode, colormode); + + // FIXME // remember selected video mode - video_mode = zdata; + // video_mode = zdata; break; } case REG_ZZ_VCAP_MODE: printf("videocap default mode select: %lx\n", zdata); - - videocap_video_mode = zdata & 0xff; + video_state->videocap_video_mode = zdata & 0xff; break; //case REG_ZZ_SPRITE_X: case REG_ZZ_SPRITE_Y: - if (!sprite_showing) + if (!video_state->sprite_showing) break; - sprite_x_base = (int16_t)rect_x1; - sprite_y_base = (int16_t)rect_y1; - - update_hw_sprite_pos(sprite_x_base, sprite_y_base); + video_state->sprite_x_base = (int16_t)rect_x1; + video_state->sprite_y_base = (int16_t)rect_y1; + update_hw_sprite_pos(video_state->sprite_x_base, video_state->sprite_y_base); break; case REG_ZZ_SPRITE_BITMAP: { if (zdata == 1) { // Hardware sprite enabled - sprite_request_show = 1; + hw_sprite_show(1); break; } else if (zdata == 2) { // Hardware sprite disabled - sprite_request_show = 0; + hw_sprite_show(0); break; } - uint8_t* bmp_data = (uint8_t*) ((u32) framebuffer + uint8_t* bmp_data = (uint8_t*) ((u32) video_state->framebuffer + blitter_src_offset); - clear_hw_sprite(); + video_state->sprite_x_offset = rect_x1; + video_state->sprite_y_offset = rect_y1; + video_state->sprite_width = rect_x2; + video_state->sprite_height = rect_y2; - sprite_x_offset = rect_x1; - sprite_y_offset = rect_y1; - sprite_width = rect_x2; - sprite_height = rect_y2; - - update_hw_sprite(bmp_data, sprite_colors, sprite_width, sprite_height); - update_hw_sprite_pos(sprite_x_base, sprite_y_base); + clear_hw_sprite(); + update_hw_sprite(bmp_data); + update_hw_sprite_pos(); break; } case REG_ZZ_SPRITE_COLORS: { - sprite_colors[zdata] = (blitter_user1 << 16) | blitter_user2; - if (zdata != 0 && sprite_colors[zdata] == 0xff00ff) - sprite_colors[zdata] = 0xfe00fe; + video_state->sprite_colors[zdata] = (blitter_user1 << 16) | blitter_user2; + if (zdata != 0 && video_state->sprite_colors[zdata] == 0xff00ff) + video_state->sprite_colors[zdata] = 0xfe00fe; break; } case REG_ZZ_SRC_PITCH: @@ -1903,10 +428,10 @@ int main() { blitter_user2 = zdata; break; case REG_ZZ_USER3: - blitter_user3 = zdata; + // FIXME unused break; case REG_ZZ_USER4: - blitter_user4 = zdata; + // FIXME unused break; case REG_ZZ_RGB_HI: @@ -1934,13 +459,13 @@ int main() { // DMA RTG rendering case REG_ZZ_BITTER_DMA_OP: { - handle_blitter_dma_op(zdata); + handle_blitter_dma_op(video_state, zdata); break; } // RTG rendering case REG_ZZ_FILLRECT: - set_fb((uint32_t*) ((u32) framebuffer + blitter_dst_offset), + set_fb((uint32_t*) ((u32)video_state->framebuffer + blitter_dst_offset), blitter_dst_pitch); uint8_t mask = zdata; @@ -1953,7 +478,7 @@ int main() { break; case REG_ZZ_COPYRECT: { - set_fb((uint32_t*) ((u32) framebuffer + blitter_dst_offset), + set_fb((uint32_t*) ((u32)video_state->framebuffer + blitter_dst_offset), blitter_dst_pitch); mask = (blitter_colormode >> 8); @@ -1962,20 +487,20 @@ int main() { if (mask == 0xFF || (mask != 0xFF && (blitter_colormode & 0x0F)) != MNTVA_COLOR_8BIT) copy_rect_nomask(rect_x1, rect_y1, rect_x2, rect_y2, rect_x3, rect_y3, blitter_colormode & 0x0F, - (uint32_t*) ((u32) framebuffer + (uint32_t*) ((u32)video_state->framebuffer + blitter_dst_offset), blitter_dst_pitch, MINTERM_SRC); else copy_rect(rect_x1, rect_y1, rect_x2, rect_y2, rect_x3, rect_y3, blitter_colormode & 0x0F, - (uint32_t*) ((u32) framebuffer + (uint32_t*) ((u32)video_state->framebuffer + blitter_dst_offset), blitter_dst_pitch, mask); break; case 2: // BlitRectNoMaskComplete copy_rect_nomask(rect_x1, rect_y1, rect_x2, rect_y2, rect_x3, rect_y3, blitter_colormode & 0x0F, - (uint32_t*) ((u32) framebuffer + (uint32_t*) ((u32)video_state->framebuffer + blitter_src_offset), blitter_src_pitch, mask); // Mask in this case is minterm/opcode. break; @@ -1986,9 +511,9 @@ int main() { case REG_ZZ_FILLTEMPLATE: { uint8_t draw_mode = blitter_colormode >> 8; - uint8_t* tmpl_data = (uint8_t*) ((u32) framebuffer + uint8_t* tmpl_data = (uint8_t*) ((u32)video_state->framebuffer + blitter_src_offset); - set_fb((uint32_t*) ((u32) framebuffer + blitter_dst_offset), + set_fb((uint32_t*) ((u32)video_state->framebuffer + blitter_dst_offset), blitter_dst_pitch); uint8_t bpp = 2 * (blitter_colormode & 0xff); @@ -2018,37 +543,40 @@ int main() { break; } - case 0x50: { // Copy crap from scratch area + case REG_ZZ_SCRATCH_COPY: { // Copy from scratch area + // FIXME for what? for (int i = 0; i < rect_y1; i++) { - memcpy ((uint32_t*) ((u32) framebuffer + framebuffer_pan_offset + (i * rect_x1)), + memcpy ((uint32_t*) ((u32)video_state->framebuffer + video_state->framebuffer_pan_offset + (i * rect_x1)), (uint32_t*) ((u32)Z3_SCRATCH_ADDR + (i * rect_x1)), rect_x1); } break; } - case 0x52: // Custom video mode param + case REG_ZZ_CVMODE_PARAM: // Custom video mode param + // FIXME custom_vmode_param = zdata; break; - case 0x54: { // Custom video mode data - int *target = &preset_video_modes[custom_video_mode].hres; + case REG_ZZ_CVMODE_VAL: { // Custom video mode data + struct zz_video_mode* vm = get_custom_video_mode_ptr(custom_video_mode); + int *target = &vm->hres; switch(custom_vmode_param) { - case VMODE_PARAM_VRES: target = &preset_video_modes[custom_video_mode].vres; break; - case VMODE_PARAM_HSTART: target = &preset_video_modes[custom_video_mode].hstart; break; - case VMODE_PARAM_HEND: target = &preset_video_modes[custom_video_mode].hend; break; - case VMODE_PARAM_HMAX: target = &preset_video_modes[custom_video_mode].hmax; break; - case VMODE_PARAM_VSTART: target = &preset_video_modes[custom_video_mode].vstart; break; - case VMODE_PARAM_VEND: target = &preset_video_modes[custom_video_mode].vend; break; - case VMODE_PARAM_VMAX: target = &preset_video_modes[custom_video_mode].vmax; break; - case VMODE_PARAM_POLARITY: target = &preset_video_modes[custom_video_mode].polarity; break; - case VMODE_PARAM_MHZ: target = &preset_video_modes[custom_video_mode].mhz; break; - case VMODE_PARAM_PHZ: target = &preset_video_modes[custom_video_mode].phz; break; - case VMODE_PARAM_VHZ: target = &preset_video_modes[custom_video_mode].vhz; break; - case VMODE_PARAM_HDMI: target = &preset_video_modes[custom_video_mode].hdmi; break; - case VMODE_PARAM_MUL: target = &preset_video_modes[custom_video_mode].mul; break; - case VMODE_PARAM_DIV: target = &preset_video_modes[custom_video_mode].div; break; - case VMODE_PARAM_DIV2: target = &preset_video_modes[custom_video_mode].div2; break; + case VMODE_PARAM_VRES: target = &vm->vres; break; + case VMODE_PARAM_HSTART: target = &vm->hstart; break; + case VMODE_PARAM_HEND: target = &vm->hend; break; + case VMODE_PARAM_HMAX: target = &vm->hmax; break; + case VMODE_PARAM_VSTART: target = &vm->vstart; break; + case VMODE_PARAM_VEND: target = &vm->vend; break; + case VMODE_PARAM_VMAX: target = &vm->vmax; break; + case VMODE_PARAM_POLARITY: target = &vm->polarity; break; + case VMODE_PARAM_MHZ: target = &vm->mhz; break; + case VMODE_PARAM_PHZ: target = &vm->phz; break; + case VMODE_PARAM_VHZ: target = &vm->vhz; break; + case VMODE_PARAM_HDMI: target = &vm->hdmi; break; + case VMODE_PARAM_MUL: target = &vm->mul; break; + case VMODE_PARAM_DIV: target = &vm->div; break; + case VMODE_PARAM_DIV2: target = &vm->div2; break; default: break; } @@ -2056,31 +584,31 @@ int main() { break; } - case 0x56: // Set custom video mode index + case REG_ZZ_CVMODE_SEL: // Set custom video mode index custom_video_mode = zdata; break; - case 0x58: // Set custom video mode without any questions asked. + case REG_ZZ_CVMODE: // Set custom video mode without any questions asked. // This assumes that the custom video mode is 640x480 or higher resolution. - video_mode_init(custom_video_mode, scalemode, colormode); + video_mode_init(custom_video_mode, video_state->scalemode, video_state->colormode); break; case REG_ZZ_SET_FEATURE: switch (blitter_user1) { case CARD_FEATURE_SECONDARY_PALETTE: - printf("[feature] SECONDARY_PALETTE: %d\n",zdata); + printf("[feature] SECONDARY_PALETTE: %lu\n",zdata); // Enables/disables the secondary palette on screen split with P96 3.10+ - card_feature_enabled[CARD_FEATURE_SECONDARY_PALETTE] = zdata; + video_state->card_feature_enabled[CARD_FEATURE_SECONDARY_PALETTE] = zdata; break; case CARD_FEATURE_NONSTANDARD_VSYNC: - printf("[feature] NONSTANDARD_VSYNC: %d\n",zdata); + printf("[feature] NONSTANDARD_VSYNC: %lu\n",zdata); // Enables/disables the nonstandard refresh rates for scandoubled PAL/NTSC HDMI output modes. if (zdata == 2) { - scandoubler_mode_adjust = 2; + video_state->scandoubler_mode_adjust = 2; } else { - scandoubler_mode_adjust = 0; + video_state->scandoubler_mode_adjust = 0; } - card_feature_enabled[CARD_FEATURE_NONSTANDARD_VSYNC] = zdata; + video_state->card_feature_enabled[CARD_FEATURE_NONSTANDARD_VSYNC] = zdata; break; default: break; @@ -2092,10 +620,10 @@ int main() { uint8_t planes = (zdata & 0xFF00) >> 8; uint8_t mask = (zdata & 0xFF); uint8_t layer_mask = blitter_user2; - uint8_t* bmp_data = (uint8_t*) ((u32) framebuffer + uint8_t* bmp_data = (uint8_t*) ((u32)video_state->framebuffer + blitter_src_offset); - set_fb((uint32_t*) ((u32) framebuffer + blitter_dst_offset), + set_fb((uint32_t*) ((u32)video_state->framebuffer + blitter_dst_offset), blitter_dst_pitch); p2c_rect(rect_x1, 0, rect_x2, rect_y2, rect_x3, @@ -2109,10 +637,10 @@ int main() { uint8_t planes = (zdata & 0xFF00) >> 8; uint8_t mask = (zdata & 0xFF); uint8_t layer_mask = blitter_user2; - uint8_t* bmp_data = (uint8_t*) ((u32) framebuffer + uint8_t* bmp_data = (uint8_t*) ((u32)video_state->framebuffer + blitter_src_offset); - set_fb((uint32_t*) ((u32) framebuffer + blitter_dst_offset), + set_fb((uint32_t*) ((u32)video_state->framebuffer + blitter_dst_offset), blitter_dst_pitch); p2d_rect(rect_x1, 0, rect_x2, rect_y2, rect_x3, rect_y3, draw_mode, planes, mask, layer_mask, rect_rgb, @@ -2122,7 +650,7 @@ int main() { case REG_ZZ_DRAWLINE: { uint8_t draw_mode = blitter_colormode >> 8; - set_fb((uint32_t*) ((u32) framebuffer + blitter_dst_offset), + set_fb((uint32_t*) ((u32)video_state->framebuffer + blitter_dst_offset), blitter_dst_pitch); // rect_x3 contains the pattern. if all bits are set for both the mask and the pattern, @@ -2141,15 +669,15 @@ int main() { } case REG_ZZ_INVERTRECT: - set_fb((uint32_t*) ((u32) framebuffer + blitter_dst_offset), + set_fb((uint32_t*) ((u32)video_state->framebuffer + blitter_dst_offset), blitter_dst_pitch); invert_rect(rect_x1, rect_y1, rect_x2, rect_y2, zdata & 0xFF, blitter_colormode); break; case REG_ZZ_SET_SPLIT_POS: - bgbuf_offset = blitter_src_offset; - split_request_pos = zdata; + video_state->bgbuf_offset = blitter_src_offset; + video_state->split_request_pos = zdata; break; // Ethernet @@ -2238,11 +766,10 @@ int main() { printf("%04x", (unsigned int)(zdata&0xffff)); break; } - case 0xF4: { + case REG_ZZ_AUDIO_CONFIG: { // FIXME temp // audio config - printf("[enable] audio: %d\n", zdata); - interrupt_enabled_audio = zdata & 1; + audio_set_interrupt_enabled((int)(zdata & 1)); break; } @@ -2251,132 +778,81 @@ int main() { arm_run_address = ((u32) zdata) << 16; break; case REG_ZZ_ARM_RUN_LO: - // TODO checksum? arm_run_address |= zdata; - - *core1_addr = (uint32_t) core1_loop; - core1_addr2[0] = 0xe3e0000f; // mvn r0, #15 -- loads 0xfffffff0 - core1_addr2[1] = 0xe590f000; // ldr pc, [r0] -- jumps to the address in that address - - printf("[ARM_RUN] %lx\n", arm_run_address); - if (arm_run_address > 0) { - core1_trampoline = (volatile void (*)( - volatile struct ZZ9K_ENV*)) arm_run_address; - printf("[ARM_RUN] signaling second core.\n"); - Xil_DCacheFlush(); - Xil_ICacheInvalidate(); - core2_execute = 1; - Xil_DCacheFlush(); - Xil_ICacheInvalidate(); - } else { - core1_trampoline = 0; - core2_execute = 0; - } - - // FIXME move this out of here - // sequence to reset cpu1 taken from https://xilinx-wiki.atlassian.net/wiki/spaces/A/pages/18842504/XAPP1079+Latest+Information - - Xil_Out32(XSLCR_UNLOCK_ADDR, XSLCR_UNLOCK_CODE); - uint32_t RegVal = Xil_In32(A9_CPU_RST_CTRL); - RegVal |= A9_RST1_MASK; - Xil_Out32(A9_CPU_RST_CTRL, RegVal); - RegVal |= A9_CLKSTOP1_MASK; - Xil_Out32(A9_CPU_RST_CTRL, RegVal); - RegVal &= ~A9_RST1_MASK; - Xil_Out32(A9_CPU_RST_CTRL, RegVal); - RegVal &= ~A9_CLKSTOP1_MASK; - Xil_Out32(A9_CPU_RST_CTRL, RegVal); - Xil_Out32(XSLCR_LOCK_ADDR, XSLCR_LOCK_CODE); - - dmb(); - dsb(); - isb(); - asm("sev"); + arm_app_run(arm_run_address); break; case REG_ZZ_ARM_ARGC: - arm_run_env.argc = zdata; + arm_run_env->argc = zdata; break; case REG_ZZ_ARM_ARGV0: - arm_run_env.argv[0] = ((u32) zdata) << 16; + arm_run_env->argv[0] = ((u32) zdata) << 16; break; case REG_ZZ_ARM_ARGV1: - arm_run_env.argv[0] |= zdata; - printf("ARG0 set: %lx\n", arm_run_env.argv[0]); + arm_run_env->argv[0] |= zdata; break; case REG_ZZ_ARM_ARGV2: - arm_run_env.argv[1] = ((u32) zdata) << 16; + arm_run_env->argv[1] = ((u32) zdata) << 16; break; case REG_ZZ_ARM_ARGV3: - arm_run_env.argv[1] |= zdata; - printf("ARG1 set: %lx\n", arm_run_env.argv[1]); + arm_run_env->argv[1] |= zdata; break; case REG_ZZ_ARM_ARGV4: - arm_run_env.argv[2] = ((u32) zdata) << 16; + arm_run_env->argv[2] = ((u32) zdata) << 16; break; case REG_ZZ_ARM_ARGV5: - arm_run_env.argv[2] |= zdata; - printf("ARG2 set: %lx\n", arm_run_env.argv[2]); + arm_run_env->argv[2] |= zdata; break; case REG_ZZ_ARM_ARGV6: - arm_run_env.argv[3] = ((u32) zdata) << 16; + arm_run_env->argv[3] = ((u32) zdata) << 16; break; case REG_ZZ_ARM_ARGV7: - arm_run_env.argv[3] |= zdata; - printf("ARG3 set: %lx\n", arm_run_env.argv[3]); + arm_run_env->argv[3] |= zdata; break; case REG_ZZ_ARM_EV_CODE: - arm_app_input_event_code = zdata; - arm_app_input_event_serial++; - arm_app_input_event_ack = 0; + arm_app_input_event(zdata); break; case REG_ZZ_AUDIO_SWAB: { // byteswap audio buffer uint32_t offset = zdata<<8; // *256 - 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++) { - data[i] = __builtin_bswap16(data[i]); - } - } - - u32 txcount = XAudioFormatterGetDMATransferCount(&audio_formatter); - - // 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) { - audio_buffer_collision = 1; - 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); - + audio_buffer_collision = audio_swab(audio_scale, offset); break; } case REG_ZZ_AUDIO_SCALE: audio_scale = zdata; break; - case REG_ZZ_MP3_DECODE: + case REG_ZZ_DECODER_PARAM: + if (zdata<ZZ_NUM_DECODER_PARAMS) { + decoder_param = zdata; + } else { + decoder_param = 0; + } + break; + case REG_ZZ_DECODER_VAL: + decoder_params[decoder_param] = zdata; + break; + case REG_ZZ_DECODE: { - uint8_t* input_buffer = (uint8_t*)fb + 0x30000; - size_t input_buffer_size = 0x200000-0x30000; - uint8_t* output_buffer = (uint8_t*)fb + 0x200000; - size_t output_buffer_size = 0x1000000; + // DECODER PARAMS: + // 0: input buffer offset hi + // 1: input buffer offset lo + // 2: input buffer size hi + // 3: input buffer size lo + // 4: output buffer offset hi + // 5: output buffer offset lo + // 6: output buffer size hi + // 7: output buffer size lo + + uint8_t* input_buffer = (uint8_t*)video_state->framebuffer + + ((decoder_params[0]<<16)|decoder_params[1]); + size_t input_buffer_size = (decoder_params[2]<<16)|decoder_params[3]; + + uint8_t* output_buffer = (uint8_t*)video_state->framebuffer + + ((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); decode_mp3(input_buffer, input_buffer_size, output_buffer, output_buffer_size); @@ -2399,11 +875,11 @@ int main() { u32 z3 = (zstate_raw & (1 << 25)); if (zaddr >= MNT_FB_BASE || zaddr >= MNT_REG_BASE + 0x2000) { - u8* ptr = mem; + u8* ptr = (u8*) FRAMEBUFFER_ADDRESS; if (zaddr >= MNT_FB_BASE) { // read from framebuffer / generic memory - ptr = mem + zaddr - MNT_FB_BASE; + ptr = ptr + zaddr - MNT_FB_BASE; } else if (zaddr < MNT_REG_BASE + 0x6000) { // 0x0000-0x1fff: read from ethernet RX frame // used by Z2 @@ -2455,9 +931,7 @@ int main() { data = (zstate_raw & (1 << 21)); break; case REG_ZZ_ARM_EV_SERIAL: - data = (arm_app_output_event_serial << 16) - | arm_app_output_event_code; - arm_app_output_event_ack = 1; + data = arm_app_output_event(); break; case REG_ZZ_ETH_MAC_HI: { uint8_t* mac = ethernet_get_mac_address_ptr(); @@ -2501,7 +975,7 @@ int main() { } case REG_ZZ_CONFIG: { //printf("read 0x04: a: %d e: %d\n", interrupt_waiting_audio, interrupt_waiting_ethernet); - data = ((interrupt_waiting_audio<<1)|(interrupt_waiting_ethernet))<<16; + data = ((audio_get_interrupt()<<1)|(interrupt_waiting_ethernet))<<16; break; } case REG_ZZ_AUDIO_SWAB: { @@ -2563,7 +1037,7 @@ int main() { // check for queued up ethernet frames int ethernet_backlog = ethernet_get_backlog(); if (ethernet_backlog > 0 && backlog_nag_counter > 5000) { - interrupt_signal_ethernet = 1; + video_state->interrupt_signal_ethernet = 1; interrupt_waiting_ethernet = 1; backlog_nag_counter = 0; } @@ -2576,38 +1050,3 @@ int main() { cleanup_platform(); return 0; } - -void arm_exception_handler_id_reset(void *callback) { - printf("id_reset: arm_exception_handler()!\n"); - while (1) { - } -} - -void arm_exception_handler_id_data_abort(void *callback) { - printf("id_data_abort: arm_exception_handler()!\n"); - while (1) { - } -} - -void arm_exception_handler_id_prefetch_abort(void *callback) { - printf("id_prefetch_abort: arm_exception_handler()!\n"); - while (1) { - } -} - -void arm_exception_handler(void *callback) { - printf("arm_exception_handler()!\n"); - while (1) { - } -} - -void arm_exception_handler_illinst(void *callback) { - printf("arm_exception_handler_illinst()!\n"); - while (1) { - } -} - -void DataAbort_InterruptHandler(void *InstancePtr) { - while(1) { - } -} diff --git a/ZZ9000_proto.sdk/ZZ9000OS/src/memorymap.h b/ZZ9000_proto.sdk/ZZ9000OS/src/memorymap.h new file mode 100644 index 0000000000000000000000000000000000000000..98d5b760d204443ef09eda6da2163a306bb3e84d --- /dev/null +++ b/ZZ9000_proto.sdk/ZZ9000OS/src/memorymap.h @@ -0,0 +1,33 @@ + +// FIXME allocate this memory properly + +#define AUDIO_NUM_PERIODS 8 +#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 TX_BD_LIST_START_ADDRESS 0x3FD00000 +#define RX_BD_LIST_START_ADDRESS 0x3FD08000 +#define TX_FRAME_ADDRESS 0x3FD10000 +#define RX_FRAME_ADDRESS 0x3FD20000 +#define RX_BACKLOG_ADDRESS 0x3FE00000 // 32 * 2048 space (64 kB) +#define USB_BLOCK_STORAGE_ADDRESS 0x3FE10000 // FIXME move all of these to a memory table header file +#define BOOT_ROM_ADDRESS 0x3FCF0000 +#define RX_FRAME_PAD 4 +#define FRAME_SIZE 2048 + +// Our address space is relative to the autoconfig base address (for example, it could be 0x600000) +#define MNT_REG_BASE 0x00000000 + +// 0x2000 - 0x7fff ETH RX +// 0x8000 - 0x9fff ETH TX +// 0xa000 - 0xffff USB BLOCK + +// Frame buffer/graphics memory starts at 64KB (relative to card address), leaving ample space for general purpose registers. +#define MNT_FB_BASE 0x00010000 diff --git a/ZZ9000_proto.sdk/ZZ9000OS/src/mntzorro.h b/ZZ9000_proto.sdk/ZZ9000OS/src/mntzorro.h new file mode 100644 index 0000000000000000000000000000000000000000..c74d3f943fdd8316e96a8d41f50bcb2178104079 --- /dev/null +++ b/ZZ9000_proto.sdk/ZZ9000OS/src/mntzorro.h @@ -0,0 +1,33 @@ +#include "platform.h" +#include "memorymap.h" +#include "xil_io.h" + +// FIXME! +#define MNTZ_BASE_ADDR 0x43C00000 + +#define MNTZORRO_REG0 0 +#define MNTZORRO_REG1 4 +#define MNTZORRO_REG2 8 +#define MNTZORRO_REG3 12 +#define MNTZORRO_REG4 16 +#define MNTZORRO_REG5 20 + +#define mntzorro_read(BaseAddress, RegOffset) \ + Xil_In32((BaseAddress) + (RegOffset)) + +#define mntzorro_write(BaseAddress, RegOffset, Data) \ + Xil_Out32((BaseAddress) + (RegOffset), (u32)(Data)) + + +/*const char* zstates[53] = { "RESET ", "Z2_CONF ", "Z2_IDLE ", "WAIT_WRI", + "WAIT_WR2", "Z2WRIFIN", "WAIT_RD ", "WAIT_RD2", "WAIT_RD3", + "CONFIGED", "CONF_CLR", "D_Z2_Z3 ", "Z3_IDLE ", "Z3_WRITE_UPP", + "Z3_WRITE_LOW", "Z3_READ_UP", "Z3_READ_LOW", "Z3_READ_DLY", + "Z3_READ_DLY1", "Z3_READ_DLY2", "Z3_WRITE_PRE", "Z3_WRITE_FIN", + "Z3_ENDCYCLE", "Z3_DTACK", "Z3_CONFIG", "Z2_REGWRITE", "REGWRITE", + "REGREAD", "Z2_REGR_POST", "Z3_REGR_POST", "Z3_REGWRITE", + "Z2_REGREAD", "Z3_REGREAD", "NONE_33", "Z2_PRE_CONF", "Z2_ENDCYCLE", + "NONE_36", "NONE_37", "NONE_38", "RESET_DVID", "COLD", "WR2B", + "WR2C", "Z3DMA1", "Z3DMA2", "Z3_AUTOCONF_RD", "Z3_AUTOCONF_WR", + "Z3_AUTOCONF_RD_DLY", "Z3_AUTOCONF_RD_DLY2", "Z3_REGWRITE_PRE", + "Z3_REGREAD_PRE", "Z3_WRITE_PRE2", "UNDEF", };*/ diff --git a/ZZ9000_proto.sdk/ZZ9000OS/src/video.c b/ZZ9000_proto.sdk/ZZ9000OS/src/video.c new file mode 100644 index 0000000000000000000000000000000000000000..b805b45e0612b02bef123b51879b9cd644913b77 --- /dev/null +++ b/ZZ9000_proto.sdk/ZZ9000OS/src/video.c @@ -0,0 +1,670 @@ +#include <stdint.h> +#include <stdio.h> +#include "video.h" +#include "mntzorro.h" +#include "xaxivdma.h" +#include "xclk_wiz.h" +#include "hdmi.h" +#include <sleep.h> + +#define VDMA_DEVICE_ID XPAR_AXIVDMA_0_DEVICE_ID + +static struct ZZ_VIDEO_STATE vs; +static XAxiVdma vdma; +static XClk_Wiz clkwiz; + +struct zz_video_mode preset_video_modes[ZZVMODE_NUM] = { + // HRES VRES HSTART HEND HMAX VSTART VEND VMAX POLARITY MHZ PIXELCLOCK HZ VERTICAL HZ HDMI MUL/DIV/DIV2 + { 1280, 720, 1390, 1430, 1650, 725, 730, 750, 0, 75, 75000000, 60, 0, 15, 1, 20 }, + { 800, 600, 840, 968, 1056, 601, 605, 628, 0, 40, 40000000, 60, 0, 14, 1, 35 }, + { 640, 480, 656, 752, 800, 490, 492, 525, 0, 25, 25175000, 60, 0, 15, 1, 60 }, + { 1024, 768, 1048, 1184, 1344, 771, 777, 806, 0, 65, 65000000, 60, 0, 13, 1, 20 }, + { 1280, 1024, 1328, 1440, 1688, 1025, 1028, 1066, 0, 108, 108000000, 60, 0, 54, 5, 10 }, + { 1920, 1080, 2008, 2052, 2200, 1084, 1089, 1125, 0, 150, 150000000, 60, 0, 15, 1, 10 }, + { 720, 576, 732, 796, 864, 581, 586, 625, 1, 27, 27000000, 50, 0, 45, 2, 83 }, + { 1920, 1080, 2448, 2492, 2640, 1084, 1089, 1125, 0, 150, 150000000, 50, 0, 15, 1, 10 }, + { 720, 480, 720, 752, 800, 490, 492, 525, 0, 25, 25175000, 60, 0, 19, 1, 75 }, + { 640, 512, 840, 968, 1056, 601, 605, 628, 0, 40, 40000000, 60, 0, 14, 1, 35 }, + { 1600, 1200, 1704, 1880, 2160, 1201, 1204, 1242, 0, 161, 16089999, 60, 0, 21, 1, 13 }, + { 2560, 1440, 2680, 2944, 3328, 1441, 1444, 1465, 0, 146, 15846000, 30, 0, 41, 2, 14 }, + { 720, 576, 732, 796, 864, 581, 586, 625, 1, 27, 27000000, 50, 0, 31, 1,115 }, // 720x576 non-standard VSync (PAL Amiga) + { 720, 480, 720, 752, 800, 490, 492, 525, 0, 25, 25175000, 60, 0, 61, 5, 49 }, // 720x480 non-standard VSync (PAL Amiga) + { 720, 576, 732, 796, 864, 581, 586, 625, 1, 27, 27000000, 50, 0, 59, 7, 31 }, // 720x576 non-standard VSync (NTSC Amiga) + { 720, 480, 720, 752, 800, 490, 492, 525, 0, 25, 25175000, 60, 0, 37, 3, 49 }, // 720x480 non-standard VSync (NTSC Amiga) + // The final entry here is the custom video mode, accessible through registers for debug purposes. + { 1280, 720, 1390, 1430, 1650, 725, 730, 750, 0, 75, 75000000, 60, 0, 15, 1, 20 }, +}; + +uint32_t sprite_buf[32 * 48]; +uint8_t sprite_clipped = 0; +int16_t sprite_clip_x = 0, sprite_clip_y = 0; + +int sprite_request_update_pos = 0; +int sprite_request_update_data = 0; +int sprite_request_show = 0; +int sprite_request_hide = 0; +int sprite_request_pos_x = 0; +int sprite_request_pos_y = 0; + +void _update_hw_sprite_pos(int16_t x, int16_t y); +void _clip_hw_sprite(int16_t offset_x, int16_t offset_y); + +// FIXME integrate with memory map +static int default_pan_offset_pal = 0x00e00000; +static int default_pan_offset_ntsc = 0x00e00000; +static int default_pan_offset_pal_800x600 = 0x00dff2f8; + +static int isr_flush_count = 0; +int vblank_count = 0; + +struct ZZ_VIDEO_STATE* video_get_state() { + return &vs; +} + +void video_init() { + vs.framebuffer = (u32*) FRAMEBUFFER_ADDRESS; + + // default to more compatible 60hz mode + vs.videocap_video_mode = ZZVMODE_800x600; + vs.video_mode = ZZVMODE_800x600 | 2 << 12 | MNTVA_COLOR_32BIT << 8; + vs.colormode = 0; + + video_reset(); +} + +void video_reset() { + vs.videocap_enabled_old = 0; + vs.framebuffer_pan_width = 0; + vs.framebuffer_pan_offset = default_pan_offset_pal_800x600; + vs.split_request_pos = 0; + + vs.sprite_colors[0] = 0x00ff00ff; + vs.sprite_colors[1] = 0x00000000; + vs.sprite_colors[2] = 0x00000000; + vs.sprite_colors[3] = 0x00000000; + + vs.sprite_width = 16; + vs.sprite_height = 16; + + sprite_request_hide = 1; +} + +uint8_t stride_div = 1; + +// 32bit: hdiv=1, 16bit: hdiv=2, 8bit: hdiv=4, ... +int init_vdma(int hsize, int vsize, int hdiv, int vdiv, u32 bufpos) { + int status; + XAxiVdma_Config *Config; + + Config = XAxiVdma_LookupConfig(VDMA_DEVICE_ID); + + if (!Config) { + printf("VDMA not found for ID %d\r\n", VDMA_DEVICE_ID); + return XST_FAILURE; + } + + /*XAxiVdma_DmaStop(&vdma, XAXIVDMA_READ); + XAxiVdma_Reset(&vdma, XAXIVDMA_READ); + XAxiVdma_ClearDmaChannelErrors(&vdma, XAXIVDMA_READ, XAXIVDMA_SR_ERR_ALL_MASK);*/ + + status = XAxiVdma_CfgInitialize(&vdma, Config, Config->BaseAddress); + if (status != XST_SUCCESS) { + printf("VDMA Configuration Initialization failed, status: 0x%X\r\n", + status); + //return status; + } + + //printf("VDMA MM2S DRE: %d\n", vdma.HasMm2SDRE); + //printf("VDMA Config MM2S DRE: %d\n", Config->HasMm2SDRE); + + u32 stride = hsize * (Config->Mm2SStreamWidth >> 3); + if (vs.framebuffer_pan_width != 0 && vs.framebuffer_pan_width != (hsize / hdiv)) { + stride = (vs.framebuffer_pan_width * (Config->Mm2SStreamWidth >> 3)) * stride_div; + } + + XAxiVdma_DmaSetup ReadCfg; + + //printf("VDMA HDIV: %d VDIV: %d\n", hdiv, vdiv); + + ReadCfg.VertSizeInput = vsize / vdiv; + ReadCfg.HoriSizeInput = (hsize * (Config->Mm2SStreamWidth >> 3)) / hdiv; // note: changing this breaks the output + ReadCfg.Stride = stride / hdiv; // note: changing this is not a problem + ReadCfg.FrameDelay = 0; /* This example does not test frame delay */ + ReadCfg.EnableCircularBuf = 1; /* Only 1 buffer, continuous loop */ + ReadCfg.EnableSync = 0; /* Gen-Lock */ + ReadCfg.PointNum = 0; + ReadCfg.EnableFrameCounter = 0; /* Endless transfers */ + ReadCfg.FixedFrameStoreAddr = 0; /* We are not doing parking */ + + ReadCfg.FrameStoreStartAddr[0] = bufpos; + + //printf("VDMA Framebuffer at 0x%x\n", ReadCfg.FrameStoreStartAddr[0]); + + status = XAxiVdma_DmaConfig(&vdma, XAXIVDMA_READ, &ReadCfg); + if (status != XST_SUCCESS) { + printf("VDMA Read channel config failed, status: 0x%X\r\n", status); + return status; + } + + status = XAxiVdma_DmaSetBufferAddr(&vdma, XAXIVDMA_READ, ReadCfg.FrameStoreStartAddr); + if (status != XST_SUCCESS) { + printf("VDMA Read channel set buffer address failed, status: 0x%X\r\n", status); + return status; + } + + status = XAxiVdma_DmaStart(&vdma, XAXIVDMA_READ); + if (status != XST_SUCCESS) { + printf("VDMA Failed to start DMA engine (read channel), status: 0x%X\r\n", status); + return status; + } + return XST_SUCCESS; +} + +void init_ns_video_mode(uint32_t mode_num) { + printf("init_ns_video_mode(%lu)\n", mode_num); + if (mode_num == ZZVMODE_720x576) { + video_mode_init(ZZVMODE_720x576_NS_PAL + vs.scandoubler_mode_adjust, 2, MNTVA_COLOR_32BIT); + } else { + video_mode_init(ZZVMODE_720x480_NS_PAL + vs.scandoubler_mode_adjust, 2, MNTVA_COLOR_32BIT); + } +} + +void fb_fill(uint32_t offset) { + memset(vs.framebuffer + offset, 0, 1280 * 1024 * 4); +} + +void videocap_area_clear() { + fb_fill(0x00dff000 / 4); +} + +#define VF_DLY ; + +// ONLY isr_video is allowed to call this! +void video_formatter_valign() { + // vertical alignment + mntzorro_write(MNTZ_BASE_ADDR, MNTZORRO_REG3, 1); + VF_DLY; + mntzorro_write(MNTZ_BASE_ADDR, MNTZORRO_REG2, 0x80000000 + 0x5); // OP_VSYNC + VF_DLY; + mntzorro_write(MNTZ_BASE_ADDR, MNTZORRO_REG2, 0x80000000); // NOP + VF_DLY; + mntzorro_write(MNTZ_BASE_ADDR, MNTZORRO_REG2, 0); // clear + VF_DLY; + mntzorro_write(MNTZ_BASE_ADDR, MNTZORRO_REG3, 0); // unlock access, NOP + VF_DLY; +} + +// ONLY isr_video is allowed to call this! +void video_formatter_write(uint32_t data, uint16_t op) { + mntzorro_write(MNTZ_BASE_ADDR, MNTZORRO_REG3, data); + VF_DLY; + mntzorro_write(MNTZ_BASE_ADDR, MNTZORRO_REG2, 0x80000000 | op); // OP_MAX (vmax | hmax) + VF_DLY; + mntzorro_write(MNTZ_BASE_ADDR, MNTZORRO_REG2, 0x80000000); // NOP + VF_DLY; + mntzorro_write(MNTZ_BASE_ADDR, MNTZORRO_REG2, 0); // clear + VF_DLY; + mntzorro_write(MNTZ_BASE_ADDR, MNTZORRO_REG3, 0); // unlock access, NOP + VF_DLY; +} + +// interrupt service routine for IRQ_F2P[0:0] +// vblank + raster position interrupt +void isr_video(void *dummy) { + u32 zstate = mntzorro_read(MNTZ_BASE_ADDR, MNTZORRO_REG3); + + int vblank = (zstate & (1 << 21)); + int videocap_enabled = (zstate & (1 << 23)); + int videocap_ntsc = (zstate & (1 << 22)); + int interlace = !!(zstate & (1 << 24)); + + if (!videocap_enabled) { + if (!vblank) { + // if this is not the vblank interrupt, set up the split buffer + // TODO: VDMA doesn't seem to like switching buffers in the middle of a frame. + // the first line after a switch contains an extraneous word, so we end up + // with up to 4 pixels of the other buffer in the first line + if (vs.split_pos != 0) { + if (vs.card_feature_enabled[CARD_FEATURE_SECONDARY_PALETTE]) { + video_formatter_write(1, MNTVF_OP_PALETTE_SEL); + } + init_vdma(vs.vmode_hsize, vs.vmode_vsize, vs.vmode_hdiv, vs.vmode_vdiv, + (u32)vs.framebuffer + vs.bgbuf_offset); + } + } else { + // if this is the vblank interrupt, set up the "normal" buffer in split mode + if (vs.card_feature_enabled[CARD_FEATURE_SECONDARY_PALETTE]) { + video_formatter_write(0, MNTVF_OP_PALETTE_SEL); + } + init_vdma(vs.vmode_hsize, vs.vmode_vsize, vs.vmode_hdiv, vs.vmode_vdiv, + (u32)vs.framebuffer + vs.framebuffer_pan_offset); + } + } else { + // FIXME magic constant + if (vs.framebuffer_pan_offset >= 0x00dff000) { + // videocap is enabled and + // we are looking at the videocap area + // so set up the right mode for it + + int videocap_reset = 0; + + if (!vs.videocap_enabled_old) { + videocap_area_clear(); + // force mode cleanup + videocap_reset = 1; + } + + if (videocap_ntsc != vs.videocap_ntsc_old || videocap_reset) { + // change between ntsc+pal + videocap_area_clear(); + + // hide sprite + sprite_request_hide = 1; + + if (videocap_ntsc) { + // NTSC + printf("videocap: ntsc\n"); + vs.framebuffer_pan_width = 0; + vs.framebuffer_pan_offset = default_pan_offset_ntsc; + if (vs.card_feature_enabled[CARD_FEATURE_NONSTANDARD_VSYNC]) { + init_ns_video_mode(ZZVMODE_720x480); + } else { + video_mode_init(ZZVMODE_720x480, 2, MNTVA_COLOR_32BIT); + + // use this if there are problems with 720x480 + //video_mode_init(ZZVMODE_800x600, 2, MNTVA_COLOR_32BIT); + } + } else { + // PAL + printf("videocap: pal\n"); + vs.framebuffer_pan_width = 0; + if (vs.videocap_video_mode == ZZVMODE_800x600) { + vs.framebuffer_pan_offset = default_pan_offset_pal_800x600; + } else { + vs.framebuffer_pan_offset = default_pan_offset_pal; + } + if (vs.videocap_video_mode == ZZVMODE_720x576 && vs.card_feature_enabled[CARD_FEATURE_NONSTANDARD_VSYNC]) { + init_ns_video_mode(ZZVMODE_720x576); + } else { + video_mode_init(vs.videocap_video_mode, 2, MNTVA_COLOR_32BIT); + } + } + videocap_reset = 1; + } + + if (interlace != vs.interlace_old || videocap_reset) { + // interlace has changed, we need to reconfigure vdma for the new screen height + vs.vmode_vdiv = 2; + if (interlace) { + vs.vmode_vdiv = 1; + } + videocap_area_clear(); + init_vdma(vs.vmode_hsize, vs.vmode_vsize, 1, vs.vmode_vdiv, + (u32)vs.framebuffer + vs.framebuffer_pan_offset); + video_formatter_valign(); + printf("videocap interlace mode changed to %d.\n", interlace); + } + + vs.interlace_old = interlace; + vs.videocap_ntsc_old = videocap_ntsc; + vs.videocap_enabled_old = videocap_enabled; + } else { + // not looking at the videocap area + vs.videocap_enabled_old = 0; + vs.videocap_ntsc_old = -1; + vs.interlace_old = -1; + } + } + + // on vblanks, handle arm cache flush, amiga interrupts and sprites + if (!vblank || (vs.split_pos == 0)) { + // flush the data caches synchronized to full frames + Xil_L1DCacheFlush(); + Xil_L2CacheFlush(); + isr_flush_count = 0; + + 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 + vs.interrupt_signal_ethernet = 0; + } + + if (sprite_request_show) { + vs.sprite_showing = 1; + sprite_request_show = 0; + } + + if (sprite_request_update_data) { + _clip_hw_sprite(0, 0); + sprite_request_update_data = 0; + } + + if (sprite_request_update_pos) { + _update_hw_sprite_pos(sprite_request_pos_x, sprite_request_pos_y); + video_formatter_write((vs.sprite_y_adj << 16) | vs.sprite_x_adj, MNTVF_OP_SPRITE_XY); + sprite_request_update_pos = 0; + } + + if (sprite_request_hide) { + vs.sprite_x = 2000; + vs.sprite_y = 2000; + video_formatter_write((vs.sprite_y << 16) | vs.sprite_x, MNTVF_OP_SPRITE_XY); + sprite_request_hide = 0; + vs.sprite_showing = 0; + } + + // handle screen dragging + if (vs.split_request_pos != vs.split_pos) { + vs.split_pos = vs.split_request_pos; + video_formatter_write(vs.split_pos, MNTVF_OP_REPORT_LINE); + } + } + + vblank_count++; +} + +u32 dump_vdma_status(XAxiVdma *InstancePtr) { + u32 status = XAxiVdma_GetStatus(InstancePtr, XAXIVDMA_READ); + + xil_printf("Read channel dump\n\r"); + xil_printf("\tMM2S DMA Control Register: %x\r\n", + XAxiVdma_ReadReg(InstancePtr->ReadChannel.ChanBase, + XAXIVDMA_CR_OFFSET)); + xil_printf("\tMM2S DMA Status Register: %x\r\n", + XAxiVdma_ReadReg(InstancePtr->ReadChannel.ChanBase, + XAXIVDMA_SR_OFFSET)); + xil_printf("\tMM2S HI_FRMBUF Reg: %x\r\n", + XAxiVdma_ReadReg(InstancePtr->ReadChannel.ChanBase, + XAXIVDMA_HI_FRMBUF_OFFSET)); + xil_printf("\tFRMSTORE Reg: %d\r\n", + XAxiVdma_ReadReg(InstancePtr->ReadChannel.ChanBase, + XAXIVDMA_FRMSTORE_OFFSET)); + xil_printf("\tBUFTHRES Reg: %d\r\n", + XAxiVdma_ReadReg(InstancePtr->ReadChannel.ChanBase, + XAXIVDMA_BUFTHRES_OFFSET)); + xil_printf("\tMM2S Vertical Size Register: %d\r\n", + XAxiVdma_ReadReg(InstancePtr->ReadChannel.ChanBase, + XAXIVDMA_MM2S_ADDR_OFFSET + XAXIVDMA_VSIZE_OFFSET)); + xil_printf("\tMM2S Horizontal Size Register: %d\r\n", + XAxiVdma_ReadReg(InstancePtr->ReadChannel.ChanBase, + XAXIVDMA_MM2S_ADDR_OFFSET + XAXIVDMA_HSIZE_OFFSET)); + xil_printf("\tMM2S Frame Delay and Stride Register: %d\r\n", + XAxiVdma_ReadReg(InstancePtr->ReadChannel.ChanBase, + XAXIVDMA_MM2S_ADDR_OFFSET + XAXIVDMA_STRD_FRMDLY_OFFSET)); + xil_printf("\tMM2S Start Address 1: %x\r\n", + XAxiVdma_ReadReg(InstancePtr->ReadChannel.ChanBase, + XAXIVDMA_MM2S_ADDR_OFFSET + XAXIVDMA_START_ADDR_OFFSET)); + + xil_printf("VDMA status: "); + if (status & XAXIVDMA_SR_HALTED_MASK) + xil_printf("halted\n"); + else + xil_printf("running\n"); + if (status & XAXIVDMA_SR_IDLE_MASK) + xil_printf("idle\n"); + if (status & XAXIVDMA_SR_ERR_INTERNAL_MASK) + xil_printf("internal err\n"); + if (status & XAXIVDMA_SR_ERR_SLAVE_MASK) + xil_printf("slave err\n"); + if (status & XAXIVDMA_SR_ERR_DECODE_MASK) + xil_printf("decode err\n"); + if (status & XAXIVDMA_SR_ERR_FSZ_LESS_MASK) + xil_printf("FSize Less Mismatch err\n"); + if (status & XAXIVDMA_SR_ERR_LSZ_LESS_MASK) + xil_printf("LSize Less Mismatch err\n"); + if (status & XAXIVDMA_SR_ERR_SG_SLV_MASK) + xil_printf("SG slave err\n"); + if (status & XAXIVDMA_SR_ERR_SG_DEC_MASK) + xil_printf("SG decode err\n"); + if (status & XAXIVDMA_SR_ERR_FSZ_MORE_MASK) + xil_printf("FSize More Mismatch err\n"); + + return status; +} + +void pixelclock_init_2(struct zz_video_mode *mode) { + XClk_Wiz_Config conf; + XClk_Wiz_CfgInitialize(&clkwiz, &conf, XPAR_CLK_WIZ_0_BASEADDR); + + u32 mul = mode->mul; + u32 div = mode->div; + u32 otherdiv = mode->div2; + + XClk_Wiz_WriteReg(XPAR_CLK_WIZ_0_BASEADDR, 0x200, (mul << 8) | div); + XClk_Wiz_WriteReg(XPAR_CLK_WIZ_0_BASEADDR, 0x208, otherdiv); + + // load configuration + XClk_Wiz_WriteReg(XPAR_CLK_WIZ_0_BASEADDR, 0x25C, 0x00000003); + //XClk_Wiz_WriteReg(XPAR_CLK_WIZ_0_BASEADDR, 0x25C, 0x00000001); +} + +void video_formatter_init(int scalemode, int colormode, int width, int height, + int htotal, int vtotal, int hss, int hse, int vss, int vse, + int polarity) { + video_formatter_write((vtotal << 16) | htotal, MNTVF_OP_MAX); + video_formatter_write((height << 16) | width, MNTVF_OP_DIMENSIONS); + video_formatter_write((hss << 16) | hse, MNTVF_OP_HS); + video_formatter_write((vss << 16) | vse, MNTVF_OP_VS); + video_formatter_write(polarity, MNTVF_OP_POLARITY); + video_formatter_write(scalemode, MNTVF_OP_SCALE); + video_formatter_write(colormode, MNTVF_OP_COLORMODE); + + video_formatter_valign(); +} + +void video_system_init(struct zz_video_mode *mode, int hdiv, int vdiv) { + pixelclock_init_2(mode); + hdmi_ctrl_init(mode); + init_vdma(mode->hres, mode->vres, hdiv, vdiv, (u32)vs.framebuffer + vs.framebuffer_pan_offset); +} + +int scalemode = 0; + +void video_mode_init(int mode, int scalemode, int colormode) { + printf("video_mode_init: %d color: %d scale: %d\n", mode, colormode, scalemode); + + // reset interlace tracking + vs.interlace_old = -1; + // remember mode + vs.video_mode = mode; + vs.scalemode = scalemode; + vs.colormode = colormode; + + int hdiv = 1, vdiv = 1; + stride_div = 1; + + if (scalemode & 1) { + hdiv = 2; + stride_div = 2; + } + if (scalemode & 2) + vdiv = 2; + + // 8 bit + if (colormode == MNTVA_COLOR_8BIT) + hdiv *= 4; + + if (colormode == MNTVA_COLOR_16BIT565 || colormode == MNTVA_COLOR_15BIT) + hdiv *= 2; + + struct zz_video_mode *vmode = &preset_video_modes[mode]; + + video_system_init(vmode, hdiv, vdiv); + + video_formatter_init(scalemode, colormode, + vmode->hres, vmode->vres, + vmode->hmax, vmode->vmax, + vmode->hstart, vmode->hend, + vmode->vstart, vmode->vend, + vmode->polarity); + + // FIXME ??? + vs.vmode_hsize = vmode->hres; + vs.vmode_vsize = vmode->vres; + vs.vmode_vdiv = vdiv; + vs.vmode_hdiv = hdiv; +} + +void update_hw_sprite(uint8_t *data) +{ + uint8_t cur_bit = 0x80; + uint8_t cur_color = 0, out_pos = 0, iter_offset = 0; + uint8_t cur_bytes[8]; + uint32_t *colors = vs.sprite_colors; + uint16_t w = vs.sprite_width; + uint16_t h = vs.sprite_height; + uint8_t line_pitch = (w / 8) * 2; + + for (uint8_t y_line = 0; y_line < h; y_line++) { + if (w <= 16) { + cur_bytes[0] = data[y_line * line_pitch]; + cur_bytes[1] = data[(y_line * line_pitch) + 2]; + cur_bytes[2] = data[(y_line * line_pitch) + 1]; + cur_bytes[3] = data[(y_line * line_pitch) + 3]; + } + else { + cur_bytes[0] = data[y_line * line_pitch]; + cur_bytes[1] = data[(y_line * line_pitch) + 4]; + cur_bytes[2] = data[(y_line * line_pitch) + 1]; + cur_bytes[3] = data[(y_line * line_pitch) + 5]; + cur_bytes[4] = data[(y_line * line_pitch) + 2]; + cur_bytes[5] = data[(y_line * line_pitch) + 6]; + cur_bytes[6] = data[(y_line * line_pitch) + 3]; + cur_bytes[7] = data[(y_line * line_pitch) + 7]; + } + + while (out_pos < 8) { + for (uint8_t i = 0; i < line_pitch; i += 2) { + cur_color = (cur_bytes[i] & cur_bit) ? 1 : 0; + if (cur_bytes[i + 1] & cur_bit) cur_color += 2; + + sprite_buf[(y_line * 32) + out_pos + iter_offset] = colors[cur_color] & 0x00ffffff; + iter_offset += 8; + } + + out_pos++; + cur_bit >>= 1; + iter_offset = 0; + } + cur_bit = 0x80; + out_pos = 0; + } + + sprite_request_update_data = 1; +} + +void update_hw_sprite_clut(uint8_t *data_, uint8_t *colors, uint16_t w, uint16_t h, uint8_t keycolor) +{ + uint8_t *data = data_; + uint8_t color[4]; + + for (int y = 0; y < h && y < 48; y++) { + for (int x = 0; x < w && x < 32; x++) { + if (data[x] == keycolor) { + *((uint32_t *)color) = 0x00ff00ff; + } + else { + color[0] = colors[(data[x] * 3)+2]; + color[1] = colors[(data[x] * 3)+1]; + color[2] = colors[(data[x] * 3)]; + color[3] = 0x00; + if (*((uint32_t *)color) == 0x00FF00FF) + *((uint32_t *)color) = 0x00FE00FE; + } + sprite_buf[(y * 32) + x] = *((uint32_t *)color); + } + data += w; + } + + sprite_request_update_data = 1; +} + +void clear_hw_sprite() +{ + for (uint16_t i = 0; i < 32 * 48; i++) { + sprite_buf[i] = 0x00ff00ff; + } + //sprite_request_update_data = 1; +} + +void _clip_hw_sprite(int16_t offset_x, int16_t offset_y) +{ + uint16_t xo = 0, yo = 0; + if (offset_x < 0) + xo = -offset_x; + if (offset_y < 0) + yo = -offset_y; + + for (int y = 0; y < 48; y++) { + //printf("CLIP %02d: ",y); + for (int x = 0; x < 32; x++) { + video_formatter_write((y * 32) + x, 14); + if (x < 32 - xo && y < 48 - yo) { + //printf("%06lx", sprite_buf[((y + yo) * 32) + (x + xo)] & 0x00ffffff); + video_formatter_write(sprite_buf[((y + yo) * 32) + (x + xo)] & 0x00ffffff, 15); + } else { + //printf("%06lx", 0x00ff00ff); + video_formatter_write(0x00ff00ff, 15); + } + } + //printf("\n"); + } +} + +void _update_hw_sprite_pos(int16_t x, int16_t y) { + vs.sprite_x = x - vs.sprite_x_offset + 1; + // horizontally doubled mode + if (scalemode & 1) + vs.sprite_x_adj = (vs.sprite_x * 2) + 1; + else + vs.sprite_x_adj = vs.sprite_x + 2; + + vs.sprite_y = y + vs.split_pos - vs.sprite_y_offset + 1; + + // vertically doubled mode + if (scalemode & 2) + vs.sprite_y_adj = vs.sprite_y *= 2; + else + vs.sprite_y_adj = vs.sprite_y; + + if (vs.sprite_x < 0 || vs.sprite_y < 0) { + if (sprite_clip_x != vs.sprite_x || sprite_clip_y != vs.sprite_y) { + _clip_hw_sprite((vs.sprite_x < 0) ? vs.sprite_x : 0, (vs.sprite_y < 0) ? vs.sprite_y : 0); + } + sprite_clipped = 1; + if (vs.sprite_x < 0) { + vs.sprite_x_adj = 0; + sprite_clip_x = vs.sprite_x; + } + if (vs.sprite_y < 0) { + vs.sprite_y_adj = 0; + sprite_clip_y = vs.sprite_y; + } + } + else if (sprite_clipped && vs.sprite_x >= 0 && vs.sprite_y >= 0) { + _clip_hw_sprite(0, 0); + sprite_clipped = 0; + } +} + +void update_hw_sprite_pos() { + sprite_request_pos_x = vs.sprite_x_base; + sprite_request_pos_y = vs.sprite_y_base; + sprite_request_update_pos = 1; +} + +void hw_sprite_show(int show) { + if (show) { + sprite_request_show = 1; + } else { + sprite_request_hide = 1; + } +} + +struct zz_video_mode* get_custom_video_mode_ptr(int custom_video_mode) { + return &preset_video_modes[custom_video_mode]; +} diff --git a/ZZ9000_proto.sdk/ZZ9000OS/src/video.h b/ZZ9000_proto.sdk/ZZ9000OS/src/video.h new file mode 100644 index 0000000000000000000000000000000000000000..87cca1abd118519eec31a8a621c3a00d0d6bbd90 --- /dev/null +++ b/ZZ9000_proto.sdk/ZZ9000OS/src/video.h @@ -0,0 +1,81 @@ +#ifndef ZZ_VIDEO_H +#define ZZ_VIDEO_H + +#include "zz_regs.h" +#include "zz_video_modes.h" + +#define MNTVF_OP_UNUSED 12 +#define MNTVF_OP_SPRITE_XY 13 +#define MNTVF_OP_SPRITE_ADDR 14 +#define MNTVF_OP_SPRITE_DATA 15 +#define MNTVF_OP_MAX 6 +#define MNTVF_OP_HS 7 +#define MNTVF_OP_VS 8 +#define MNTVF_OP_POLARITY 10 +#define MNTVF_OP_SCALE 4 +#define MNTVF_OP_DIMENSIONS 2 +#define MNTVF_OP_COLORMODE 1 +#define MNTVF_OP_REPORT_LINE 17 +#define MNTVF_OP_PALETTE_SEL 18 +#define MNTVF_OP_PALETTE_HI 19 + +struct ZZ_VIDEO_STATE { + uint32_t* framebuffer; + + int video_mode; + int colormode; + int scalemode; + + uint32_t vmode_hsize; + uint32_t vmode_vsize; + uint32_t vmode_hdiv; + uint32_t vmode_vdiv; + + int videocap_video_mode; + + int interlace_old; + int videocap_ntsc_old; + int videocap_enabled_old; + uint16_t split_request_pos; + uint16_t split_pos; + uint32_t bgbuf_offset; + + uint32_t framebuffer_pan_offset; + uint32_t framebuffer_pan_width; + uint8_t scandoubler_mode_adjust; + + int sprite_showing; + int16_t sprite_x; + int16_t sprite_x_adj; + int16_t sprite_x_base; + int16_t sprite_y; + int16_t sprite_y_adj; + int16_t sprite_y_base; + int16_t sprite_x_offset; + int16_t sprite_y_offset; + uint8_t sprite_width; + uint8_t sprite_height; + uint32_t sprite_colors[4]; + + uint8_t card_feature_enabled[CARD_FEATURE_NUM]; + + // FIXME this does not belong here + int interrupt_enabled_ethernet; + int interrupt_signal_ethernet; +}; + +void video_init(); +void video_reset(); +void isr_video(void *dummy); +void video_mode_init(int mode, int scalemode, int colormode); +void hw_sprite_show(int show); +void update_hw_sprite(uint8_t *data); +void update_hw_sprite_clut(uint8_t *data_, uint8_t *colors, uint16_t w, uint16_t h, uint8_t keycolor); +void update_hw_sprite_pos(); +void clip_hw_sprite(int16_t offset_x, int16_t offset_y); +void clear_hw_sprite(); +struct zz_video_mode* get_custom_video_mode_ptr(int custom_video_mode); + +struct ZZ_VIDEO_STATE* video_get_state(); + +#endif diff --git a/ZZ9000_proto.sdk/ZZ9000OS/src/zz_regs.h b/ZZ9000_proto.sdk/ZZ9000OS/src/zz_regs.h index e2aa16517f9eb33d8304527ea399b99a903bff56..dc3d7574c3d6b6820f8adba4f8e3c84fa637b989 100644 --- a/ZZ9000_proto.sdk/ZZ9000OS/src/zz_regs.h +++ b/ZZ9000_proto.sdk/ZZ9000OS/src/zz_regs.h @@ -14,6 +14,9 @@ * */ +#ifndef ZZ_REGS_H +#define ZZ_REGS_H + // Registers offsets relative to the register base, although the offset on the ARM side is always 0. enum zz_reg_offsets { REG_ZZ_UNUSED_REG00 = 0x00, @@ -61,11 +64,11 @@ enum zz_reg_offsets { REG_ZZ_VBLANK_STATUS = 0x4C, REG_ZZ_UNUSED_REG4E = 0x4E, - REG_ZZ_UNUSED_REG50 = 0x50, // These are actually not quite unused, but should - REG_ZZ_UNUSED_REG52 = 0x52, // be phased out at some point, since they're pretty - REG_ZZ_UNUSED_REG54 = 0x54, // much undocumented. - REG_ZZ_UNUSED_REG56 = 0x56, // I should also stop being lazy and rework DoomAttackZZ/060 - REG_ZZ_UNUSED_REG58 = 0x58, // to use the DMA ACC flip buffer to front command instead. [_Bnu] + REG_ZZ_SCRATCH_COPY = 0x50, + REG_ZZ_CVMODE_PARAM = 0x52, + REG_ZZ_CVMODE_VAL = 0x54, + REG_ZZ_CVMODE_SEL = 0x56, + REG_ZZ_CVMODE = 0x58, REG_ZZ_BITTER_DMA_OP = 0x5A, REG_ZZ_ACC_OP = 0x5C, REG_ZZ_SET_SPLIT_POS = 0x5E, @@ -82,9 +85,9 @@ enum zz_reg_offsets { REG_ZZ_AUDIO_SWAB = 0x70, REG_ZZ_UNUSED_REG72 = 0x72, REG_ZZ_AUDIO_SCALE = 0x74, - REG_ZZ_MP3_DECODE = 0x76, - REG_ZZ_UNUSED_REG78 = 0x78, - REG_ZZ_UNUSED_REG7A = 0x7A, + REG_ZZ_DECODE = 0x76, + REG_ZZ_DECODER_PARAM = 0x78, + REG_ZZ_DECODER_VAL = 0x7A, REG_ZZ_UNUSED_REG7C = 0x7C, REG_ZZ_UNUSED_REG7E = 0x7E, @@ -153,7 +156,7 @@ enum zz_reg_offsets { REG_ZZ_PRINT_CHR = 0xF0, REG_ZZ_PRINT_HEX = 0xF2, - REG_ZZ_UNUSED_REGF4 = 0xF4, + REG_ZZ_AUDIO_CONFIG = 0xF4, REG_ZZ_UNUSED_REGF6 = 0xF6, REG_ZZ_UNUSED_REGF8 = 0xF8, REG_ZZ_UNUSED_REGFA = 0xFA, @@ -167,3 +170,5 @@ enum zz9k_card_features { CARD_FEATURE_NONSTANDARD_VSYNC, CARD_FEATURE_NUM, }; + +#endif diff --git a/ZZ9000_proto.sdk/ZZ9000OS/src/zz_video_modes.h b/ZZ9000_proto.sdk/ZZ9000OS/src/zz_video_modes.h index ed0240948c9be6f684550e9ef70586fdd6d9a38e..136e5282766661ca37a73ccda837f385382559e5 100644 --- a/ZZ9000_proto.sdk/ZZ9000OS/src/zz_video_modes.h +++ b/ZZ9000_proto.sdk/ZZ9000OS/src/zz_video_modes.h @@ -1,3 +1,6 @@ +#ifndef ZZ_VIDEO_MODES_H +#define ZZ_VIDEO_MODES_H + enum zz_video_modes { ZZVMODE_1280x720, ZZVMODE_800x600, @@ -49,25 +52,12 @@ enum custom_vmode_params { VMODE_PARAM_NUM, }; - -struct zz_video_mode preset_video_modes[ZZVMODE_NUM] = { - // HRES VRES HSTART HEND HMAX VSTART VEND VMAX POLARITY MHZ PIXELCLOCK HZ VERTICAL HZ HDMI MUL/DIV/DIV2 - { 1280, 720, 1390, 1430, 1650, 725, 730, 750, 0, 75, 75000000, 60, 0, 15, 1, 20 }, - { 800, 600, 840, 968, 1056, 601, 605, 628, 0, 40, 40000000, 60, 0, 14, 1, 35 }, - { 640, 480, 656, 752, 800, 490, 492, 525, 0, 25, 25175000, 60, 0, 15, 1, 60 }, - { 1024, 768, 1048, 1184, 1344, 771, 777, 806, 0, 65, 65000000, 60, 0, 13, 1, 20 }, - { 1280, 1024, 1328, 1440, 1688, 1025, 1028, 1066, 0, 108, 108000000, 60, 0, 54, 5, 10 }, - { 1920, 1080, 2008, 2052, 2200, 1084, 1089, 1125, 0, 150, 150000000, 60, 0, 15, 1, 10 }, - { 720, 576, 732, 796, 864, 581, 586, 625, 1, 27, 27000000, 50, 0, 45, 2, 83 }, - { 1920, 1080, 2448, 2492, 2640, 1084, 1089, 1125, 0, 150, 150000000, 50, 0, 15, 1, 10 }, - { 720, 480, 720, 752, 800, 490, 492, 525, 0, 25, 25175000, 60, 0, 19, 1, 75 }, - { 640, 512, 840, 968, 1056, 601, 605, 628, 0, 40, 40000000, 60, 0, 14, 1, 35 }, - { 1600, 1200, 1704, 1880, 2160, 1201, 1204, 1242, 0, 161, 16089999, 60, 0, 21, 1, 13 }, - { 2560, 1440, 2680, 2944, 3328, 1441, 1444, 1465, 0, 146, 15846000, 30, 0, 41, 2, 14 }, - { 720, 576, 732, 796, 864, 581, 586, 625, 1, 27, 27000000, 50, 0, 31, 1,115 }, // 720x576 non-standard VSync (PAL Amiga) - { 720, 480, 720, 752, 800, 490, 492, 525, 0, 25, 25175000, 60, 0, 61, 5, 49 }, // 720x480 non-standard VSync (PAL Amiga) - { 720, 576, 732, 796, 864, 581, 586, 625, 1, 27, 27000000, 50, 0, 59, 7, 31 }, // 720x576 non-standard VSync (NTSC Amiga) - { 720, 480, 720, 752, 800, 490, 492, 525, 0, 25, 25175000, 60, 0, 37, 3, 49 }, // 720x480 non-standard VSync (NTSC Amiga) - // The final entry here is the custom video mode, accessible through registers for debug purposes. - { 1280, 720, 1390, 1430, 1650, 725, 730, 750, 0, 75, 75000000, 60, 0, 15, 1, 20 }, +enum color_formats { + MNTVA_COLOR_8BIT, + MNTVA_COLOR_16BIT565, + MNTVA_COLOR_32BIT, + MNTVA_COLOR_15BIT, + MNTVA_COLOR_NUM, }; + +#endif