mirror of
https://github.com/polpo/picogus.git
synced 2026-10-25 21:40:16 +00:00
1244 lines
40 KiB
C++
1244 lines
40 KiB
C++
/*
|
|
* Copyright (C) 2022-2024 Ian Scott
|
|
*
|
|
* This program is free software; you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License as published by
|
|
* the Free Software Foundation; either version 2 of the License, or
|
|
* (at your option) any later version.
|
|
*
|
|
* This program is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License along
|
|
* with this program; if not, write to the Free Software Foundation, Inc.,
|
|
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
|
*/
|
|
|
|
#include <stdio.h>
|
|
#include <string.h>
|
|
#include "pico/stdlib.h"
|
|
#include "pico/multicore.h"
|
|
#include "hardware/adc.h"
|
|
#include "hardware/pio.h"
|
|
#include "hardware/irq.h"
|
|
#include "hardware/regs/vreg_and_chip_reset.h"
|
|
#include "hardware/vreg.h"
|
|
#include "hardware/clocks.h"
|
|
|
|
#include "pico_reflash.h"
|
|
#include "flash_settings.h"
|
|
|
|
// For multifw
|
|
#include "hardware/watchdog.h"
|
|
#include "hardware/structs/watchdog.h"
|
|
|
|
#include "../common/picogus.h"
|
|
|
|
board_type_t BOARD_TYPE;
|
|
|
|
#ifdef PSRAM
|
|
#include "psram_spi.h"
|
|
psram_spi_inst_t psram_spi;
|
|
psram_spi_inst_t* async_spi_inst;
|
|
#endif
|
|
#include "isa_io.pio.h"
|
|
|
|
#ifdef ASYNC_UART
|
|
#include "stdio_async_uart.h"
|
|
#endif
|
|
// UART_TX_PIN is defined in isa_io.pio.h
|
|
#define UART_RX_PIN (-1)
|
|
#define UART_ID uart0
|
|
#define BAUD_RATE 115200
|
|
|
|
uint LED_PIN;
|
|
|
|
#include "M62429/M62429.h"
|
|
M62429* m62429;
|
|
|
|
#ifdef SOUND_SB
|
|
static uint16_t sb_port_test;
|
|
extern void sbdsp_write(uint8_t address, uint8_t value);
|
|
extern uint8_t sbdsp_read(uint8_t address);
|
|
extern void sbdsp_init();
|
|
extern void sbdsp_process();
|
|
#endif
|
|
#ifdef SOUND_OPL
|
|
#include "opl.h"
|
|
void play_adlib(void);
|
|
extern "C" int OPL_Pico_Init(unsigned int);
|
|
extern "C" unsigned int OPL_Pico_PortRead(opl_port_t);
|
|
#include "cmd_buffers.h"
|
|
cms_buffer_t opl_buffer = { {0}, 0, 0 };
|
|
#endif
|
|
|
|
#ifdef CDROM
|
|
static uint16_t cdrom_port_test;
|
|
extern "C" void MKE_WRITE(uint16_t address, uint8_t value);
|
|
extern "C" uint8_t MKE_READ(uint16_t address);
|
|
extern "C" void mke_init();
|
|
|
|
#define CDROM_NUM 1
|
|
#include "cdrom/cdrom.h"
|
|
#include "cdrom/cdrom_image_manager.h"
|
|
cdrom_t cdrom[CDROM_NUM];
|
|
|
|
static uint32_t cur_read_idx;
|
|
#endif
|
|
|
|
#ifdef SOUND_GUS
|
|
#include "gus-x.cpp"
|
|
|
|
#include "isa_dma.h"
|
|
dma_inst_t dma_config;
|
|
static uint16_t gus_port_test;
|
|
void play_gus(void);
|
|
#endif
|
|
|
|
|
|
#ifdef SOUND_MPU
|
|
#include "mpu401/export.h"
|
|
#ifdef MPU_ONLY
|
|
void play_mpu(void);
|
|
#endif
|
|
#endif
|
|
|
|
#ifdef SOUND_TANDY
|
|
#include "square/square.h"
|
|
void play_tandy(void);
|
|
|
|
#include "cmd_buffers.h"
|
|
tandy_buffer_t tandy_buffer = { {0}, 0, 0 };
|
|
#endif
|
|
|
|
#ifdef SOUND_CMS
|
|
void play_cms(void);
|
|
static uint8_t cms_detect = 0xFF;
|
|
|
|
#include "cmd_buffers.h"
|
|
cms_buffer_t cms_buffer = { {0}, 0, 0 };
|
|
#endif
|
|
|
|
|
|
#ifdef NE2000
|
|
extern "C" {
|
|
#include "ne2000/ne2000.h"
|
|
}
|
|
void play_ne2000(void);
|
|
#endif
|
|
|
|
|
|
#ifdef USB_JOYSTICK
|
|
#include "usb_hid/joy.h"
|
|
extern "C" joystate_struct_t joystate_struct;
|
|
uint8_t joystate_bin;
|
|
#include "hardware/pwm.h"
|
|
#endif
|
|
#ifdef USB_MOUSE
|
|
#include "mouse/8250uart.h"
|
|
#include "mouse/sermouse.h"
|
|
#endif
|
|
#ifdef USB_ONLY
|
|
void play_usb(void);
|
|
#endif
|
|
|
|
|
|
// PicoGUS control and data ports
|
|
static bool control_active = false;
|
|
static uint8_t sel_reg = 0;
|
|
static uint32_t cur_read = 0;
|
|
static uint32_t cur_write = 0;
|
|
static bool queueSaveSettings = false;
|
|
static bool queueReboot = false;
|
|
|
|
Settings settings;
|
|
void processSettings(void);
|
|
|
|
#define IOW_PIO_SM 0
|
|
#define IOR_PIO_SM 1
|
|
|
|
const char* firmware_string = PICO_PROGRAM_NAME " v" PICO_PROGRAM_VERSION_STRING;
|
|
|
|
static uint8_t basePort_low;
|
|
static uint8_t mouseSensitivity_low;
|
|
|
|
__force_inline void select_picogus(uint8_t value) {
|
|
// printf("select picogus %x\n", value);
|
|
sel_reg = value;
|
|
switch (sel_reg) {
|
|
case MODE_MAGIC: // Magic string
|
|
case MODE_PROTOCOL: // Protocol version
|
|
break;
|
|
case MODE_FWSTRING: // Firmware string
|
|
cur_read = 0;
|
|
break;
|
|
case MODE_BOOTMODE: // Mode (GUS, OPL, MPU, etc...)
|
|
break;
|
|
case MODE_GUSPORT: // GUS Base port
|
|
case MODE_OPLPORT: // Adlib Base port
|
|
case MODE_SBPORT: // SB Base port
|
|
case MODE_MPUPORT: // MPU Base port
|
|
case MODE_TANDYPORT: // Tandy Base port
|
|
case MODE_CMSPORT: // CMS Base port
|
|
basePort_low = 0;
|
|
break;
|
|
case MODE_JOYEN: // enable joystick
|
|
break;
|
|
case MODE_GUSBUF: // Audio buffer size
|
|
case MODE_GUSDMA: // DMA interval
|
|
case MODE_GUS44K: // Force 44k
|
|
break;
|
|
case MODE_WTVOL: // Wavetable mixer volume
|
|
break;
|
|
case MODE_MPUDELAY: // MPU sysex delay
|
|
case MODE_MPUFAKE: // MPU fake all notes off
|
|
break;
|
|
case MODE_OPLWAIT: // Adlib speed sensitive fix
|
|
break;
|
|
case MODE_MOUSEPORT:
|
|
basePort_low = 0;
|
|
break;
|
|
case MODE_MOUSEPROTO:
|
|
case MODE_MOUSERATE:
|
|
case MODE_MOUSESEN:
|
|
break;
|
|
case MODE_NE2KPORT:
|
|
basePort_low = 0;
|
|
break;
|
|
case MODE_WIFISSID:
|
|
memset(settings.WiFi.ssid, 0, sizeof(settings.WiFi.ssid));
|
|
cur_write = 0;
|
|
break;
|
|
case MODE_WIFIPASS:
|
|
memset(settings.WiFi.password, 0, sizeof(settings.WiFi.password));
|
|
cur_write = 0;
|
|
break;
|
|
case MODE_WIFIAPPLY:
|
|
case MODE_WIFISTAT:
|
|
break;
|
|
case MODE_CDPORT: // CMS Base port
|
|
basePort_low = 0;
|
|
break;
|
|
case MODE_CDSTATUS:
|
|
break;
|
|
case MODE_CDIMAGES:
|
|
#ifdef CDROM
|
|
if (cdrom[0].image_status != CD_STATUS_READY) {
|
|
cdrom[0].image_status = CD_STATUS_BUSY;
|
|
cdrom[0].image_command = CD_COMMAND_IMAGE_LIST;
|
|
puts("cdimages start");
|
|
}
|
|
puts("cdimages read");
|
|
cur_read = 0;
|
|
cur_read_idx = 0;
|
|
#endif
|
|
break;
|
|
case MODE_CDLOAD:
|
|
case MODE_CDSELECT:
|
|
break;
|
|
case MODE_SAVE: // Select save settings register
|
|
case MODE_REBOOT: // Select reboot register
|
|
case MODE_DEFAULTS: // Select reset to defaults register
|
|
break;
|
|
case MODE_HWTYPE: // Hardware version
|
|
break;
|
|
case MODE_FLASH: // Firmware write mode
|
|
pico_firmware_start();
|
|
break;
|
|
default:
|
|
control_active = false;
|
|
break;
|
|
}
|
|
}
|
|
|
|
__force_inline void write_picogus_low(uint8_t value) {
|
|
switch (sel_reg) {
|
|
case MODE_GUSPORT: // GUS Base port
|
|
case MODE_OPLPORT: // Adlib Base port
|
|
case MODE_SBPORT: // SB Base port
|
|
case MODE_MPUPORT: // MPU Base port
|
|
case MODE_TANDYPORT: // Tandy Base port
|
|
case MODE_CMSPORT: // CMS Base port
|
|
case MODE_MOUSEPORT: // USB Mouse port (0 - disabled)
|
|
case MODE_CDPORT: // USB Mouse port (0 - disabled)
|
|
basePort_low = value;
|
|
break;
|
|
case MODE_MOUSESEN: // USB Mouse Sensitivity (8.8 fixedpoint)
|
|
mouseSensitivity_low = value;
|
|
break;
|
|
}
|
|
}
|
|
|
|
__force_inline void write_picogus_high(uint8_t value) {
|
|
switch (sel_reg) {
|
|
case MODE_GUSPORT: // GUS Base port
|
|
settings.GUS.basePort = (value || basePort_low) ? ((value << 8) | basePort_low) : 0xFFFF;
|
|
#ifdef SOUND_GUS
|
|
gus_port_test = settings.GUS.basePort >> 4 | 0x10;
|
|
#endif
|
|
break;
|
|
case MODE_OPLPORT: // Adlib Base port
|
|
settings.SB.oplBasePort = (value || basePort_low) ? ((value << 8) | basePort_low) : 0xFFFF;
|
|
break;
|
|
case MODE_SBPORT: // SB Base port
|
|
settings.SB.basePort = (value || basePort_low) ? ((value << 8) | basePort_low) : 0xFFFF;
|
|
#ifdef SOUND_SB
|
|
sb_port_test = settings.SB.basePort >> 4;
|
|
#endif
|
|
break;
|
|
case MODE_MPUPORT: // MPU Base port
|
|
settings.MPU.basePort = (value || basePort_low) ? ((value << 8) | basePort_low) : 0xFFFF;
|
|
break;
|
|
case MODE_TANDYPORT: // Tandy Base port
|
|
settings.Tandy.basePort = (value || basePort_low) ? ((value << 8) | basePort_low) : 0xFFFF;
|
|
break;
|
|
case MODE_CMSPORT: // CMS Base port
|
|
settings.CMS.basePort = (value || basePort_low) ? ((value << 8) | basePort_low) : 0xFFFF;
|
|
break;
|
|
case MODE_JOYEN: // enable joystick
|
|
settings.Joy.basePort = value ? 0x201u : 0xffff;
|
|
break;
|
|
case MODE_GUSBUF: // GUS audio buffer size
|
|
// Value is sent by pgusinit as the size - 1, so we need to add 1 back to it
|
|
settings.GUS.audioBuffer = value + 1;
|
|
#ifdef SOUND_GUS
|
|
GUS_SetAudioBuffer(settings.GUS.audioBuffer);
|
|
#endif
|
|
break;
|
|
case MODE_GUSDMA: // GUS DMA interval
|
|
settings.GUS.dmaInterval = value;
|
|
#ifdef SOUND_GUS
|
|
GUS_SetDMAInterval(settings.GUS.dmaInterval);
|
|
#endif
|
|
break;
|
|
case MODE_GUS44K: // Force 44k output
|
|
settings.GUS.force44k = value;
|
|
#ifdef SOUND_GUS
|
|
GUS_SetFixed44k(settings.GUS.force44k);
|
|
#endif
|
|
break;
|
|
case MODE_WTVOL: // Wavetable mixer volume
|
|
settings.Global.waveTableVolume = value;
|
|
if (BOARD_TYPE == PICOGUS_2) {
|
|
m62429->setVolume(M62429_BOTH, settings.Global.waveTableVolume);
|
|
}
|
|
break;
|
|
case MODE_MPUDELAY: // MPU SYSEX delay
|
|
settings.MPU.delaySysex = value;
|
|
#ifdef SOUND_MPU
|
|
MPU401_Init(settings.MPU.delaySysex, settings.MPU.fakeAllNotesOff);
|
|
#endif
|
|
break;
|
|
case MODE_MPUFAKE: // MPU fake all notes off
|
|
settings.MPU.fakeAllNotesOff = value;
|
|
#ifdef SOUND_MPU
|
|
MPU401_Init(settings.MPU.delaySysex, settings.MPU.fakeAllNotesOff);
|
|
#endif
|
|
break;
|
|
case MODE_OPLWAIT: // Adlib speed sensitive fix
|
|
settings.SB.oplSpeedSensitive = value;
|
|
break;
|
|
case MODE_MOUSEPORT: // USB Mouse port (0 - disabled)
|
|
settings.Mouse.basePort = (value || basePort_low) ? ((value << 8) | basePort_low) : 0xFFFF;
|
|
break;
|
|
case MODE_MOUSEPROTO: // USB Mouse protocol
|
|
settings.Mouse.protocol = value;
|
|
#ifdef USB_MOUSE
|
|
sermouse_set_protocol(settings.Mouse.protocol);
|
|
#endif
|
|
break;
|
|
case MODE_MOUSERATE: // USB Mouse Report Rate
|
|
settings.Mouse.reportRate = value;
|
|
#ifdef USB_MOUSE
|
|
sermouse_set_report_rate_hz(settings.Mouse.reportRate);
|
|
#endif
|
|
break;
|
|
case MODE_MOUSESEN: // USB Mouse Sensitivity (8.8 fixedpoint)
|
|
settings.Mouse.sensitivity = (value << 8) | (mouseSensitivity_low & 0xFF);
|
|
#ifdef USB_MOUSE
|
|
sermouse_set_sensitivity(settings.Mouse.sensitivity);
|
|
#endif
|
|
break;
|
|
case MODE_NE2KPORT: // NE2000 Base port
|
|
settings.NE2K.basePort = (value || basePort_low) ? ((value << 8) | basePort_low) : 0xFFFF;
|
|
break;
|
|
case MODE_WIFISSID:
|
|
settings.WiFi.ssid[cur_write++] = value;
|
|
break;
|
|
case MODE_WIFIPASS:
|
|
settings.WiFi.password[cur_write++] = value;
|
|
/* printf("%s\n", settings.WiFi.password); */
|
|
break;
|
|
case MODE_WIFIAPPLY:
|
|
printf("Applying wifi settings: %s %s\n", settings.WiFi.ssid, settings.WiFi.password);
|
|
#ifdef PICOW
|
|
PG_Wifi_Connect(settings.WiFi.ssid, settings.WiFi.password);
|
|
#endif
|
|
break;
|
|
case MODE_WIFISTAT:
|
|
#ifdef PICOW
|
|
multicore_fifo_push_blocking(FIFO_WIFI_STATUS);
|
|
#endif
|
|
break;
|
|
case MODE_CDPORT: // CD Base port
|
|
settings.CD.basePort = (value || basePort_low) ? ((value << 8) | basePort_low) : 0xFFFF;
|
|
#ifdef CDROM
|
|
cdrom_port_test = settings.CD.basePort >> 4;
|
|
#endif
|
|
break;
|
|
#ifdef CDROM
|
|
case MODE_CDLOAD: // Load CD image
|
|
cdrom[0].image_data = value;
|
|
cdrom[0].image_status = CD_STATUS_BUSY;
|
|
cdrom[0].image_command = CD_COMMAND_IMAGE_LOAD_INDEX;
|
|
break;
|
|
case MODE_CDSELECT:
|
|
break;
|
|
#endif
|
|
// For multifw
|
|
case MODE_BOOTMODE:
|
|
settings.startupMode = value;
|
|
printf("requesting startup mode: %u\n", value);
|
|
break;
|
|
case MODE_SAVE:
|
|
queueSaveSettings = true;
|
|
break;
|
|
case MODE_REBOOT:
|
|
watchdog_hw->scratch[3] = settings.startupMode;
|
|
printf("rebooting into mode: %u\n", settings.startupMode);
|
|
watchdog_reboot(0, 0, 0);
|
|
break;
|
|
case MODE_DEFAULTS:
|
|
getDefaultSettings(&settings);
|
|
processSettings();
|
|
break;
|
|
case MODE_FLASH: // Firmware write
|
|
pico_firmware_write(value);
|
|
break;
|
|
}
|
|
}
|
|
|
|
__force_inline uint8_t read_picogus_low(void) {
|
|
switch (sel_reg) {
|
|
case MODE_GUSPORT: // GUS Base port
|
|
return settings.GUS.basePort == 0xFFFF ? 0 : (settings.GUS.basePort & 0xFF);
|
|
case MODE_OPLPORT: // Adlib Base port
|
|
return settings.SB.oplBasePort == 0xFFFF ? 0 : (settings.SB.oplBasePort & 0xFF);
|
|
case MODE_SBPORT: // SB Base port
|
|
return settings.SB.basePort == 0xFFFF ? 0 : (settings.SB.basePort & 0xFF);
|
|
case MODE_MPUPORT: // MPU Base port
|
|
return settings.MPU.basePort == 0xFFFF ? 0 : (settings.MPU.basePort & 0xFF);
|
|
case MODE_TANDYPORT: // Tandy Base port
|
|
return settings.Tandy.basePort == 0xFFFF ? 0 : (settings.Tandy.basePort & 0xFF);
|
|
case MODE_CMSPORT: // CMS Base port
|
|
return settings.CMS.basePort == 0xFFFF ? 0 : (settings.CMS.basePort & 0xFF);
|
|
case MODE_MOUSEPORT: // USB Mouse port (0 - disabled)
|
|
return settings.Mouse.basePort == 0xFFFF ? 0 : (settings.Mouse.basePort & 0xFF);
|
|
case MODE_MOUSESEN: // USB Mouse Sensitivity (8.8 fixedpoint)
|
|
return settings.Mouse.sensitivity & 0xFF;
|
|
case MODE_NE2KPORT: // NE2000 Base port (0 - disabled)
|
|
return settings.NE2K.basePort == 0xFFFF ? 0 : (settings.NE2K.basePort & 0xFF);
|
|
case MODE_CDPORT: // SB Base port
|
|
return settings.CD.basePort == 0xFFFF ? 0 : (settings.CD.basePort & 0xFF);
|
|
default:
|
|
return 0x0;
|
|
}
|
|
}
|
|
|
|
__force_inline uint8_t read_picogus_high(void) {
|
|
uint8_t ret;
|
|
switch (sel_reg) {
|
|
case MODE_MAGIC: // PicoGUS magic string
|
|
return 0xdd;
|
|
case MODE_PROTOCOL: // PicoGUS protocol version
|
|
return PICOGUS_PROTOCOL_VER;
|
|
case MODE_FWSTRING: // Firmware string
|
|
ret = firmware_string[cur_read++];
|
|
if (ret == 0) { // Null terminated
|
|
cur_read = 0;
|
|
}
|
|
return ret;
|
|
case MODE_BOOTMODE: // Mode (GUS, OPL, MPU, etc...)
|
|
return settings.startupMode;
|
|
case MODE_GUSPORT: // GUS Base port
|
|
return settings.GUS.basePort == 0xFFFF ? 0 : (settings.GUS.basePort >> 8);
|
|
case MODE_OPLPORT: // Adlib Base port
|
|
return settings.SB.oplBasePort == 0xFFFF ? 0 : (settings.SB.oplBasePort >> 8);
|
|
case MODE_SBPORT: // SB Base port
|
|
return settings.SB.basePort == 0xFFFF ? 0 : (settings.SB.basePort >> 8);
|
|
case MODE_MPUPORT: // MPU Base port
|
|
return settings.MPU.basePort == 0xFFFF ? 0 : (settings.MPU.basePort >> 8);
|
|
case MODE_TANDYPORT: // Tandy Base port
|
|
return settings.Tandy.basePort == 0xFFFF ? 0 : (settings.Tandy.basePort >> 8);
|
|
case MODE_CMSPORT: // CMS Base port
|
|
return settings.CMS.basePort == 0xFFFF ? 0 : (settings.CMS.basePort >> 8);
|
|
case MODE_JOYEN: // enable joystick
|
|
return settings.Joy.basePort == 0x201u;
|
|
case MODE_GUSBUF: // GUS audio buffer size
|
|
return settings.GUS.audioBuffer - 1;
|
|
case MODE_GUSDMA: // GUS DMA interval
|
|
return settings.GUS.dmaInterval;
|
|
case MODE_GUS44K: // Force 44k output
|
|
return settings.GUS.force44k;
|
|
case MODE_WTVOL: // Wavetable mixer volume
|
|
return (BOARD_TYPE == PICOGUS_2) ? m62429->getVolume(0) : 0;
|
|
case MODE_MPUDELAY: // SYSEX delay
|
|
return settings.MPU.delaySysex;
|
|
case MODE_MPUFAKE: // MPU fake all notes off
|
|
return settings.MPU.fakeAllNotesOff;
|
|
case MODE_OPLWAIT: // Adlib speed sensitive fix
|
|
return settings.SB.oplSpeedSensitive;
|
|
case MODE_MOUSEPORT: // USB Mouse port (0 - disabled)
|
|
return settings.Mouse.basePort == 0xFFFF ? 0 : (settings.Mouse.basePort >> 8);
|
|
case MODE_MOUSEPROTO: // USB Mouse protocol
|
|
return settings.Mouse.protocol;
|
|
case MODE_MOUSERATE: // USB Mouse Report Rate
|
|
return settings.Mouse.reportRate;
|
|
case MODE_MOUSESEN: // USB Mouse Sensitivity (8.8 fixedpoint)
|
|
return settings.Mouse.sensitivity >> 8;
|
|
case MODE_NE2KPORT: // NE2000 Base port
|
|
return settings.NE2K.basePort == 0xFFFF ? 0 : (settings.NE2K.basePort >> 8);
|
|
/*
|
|
case MODE_WIFISSID:
|
|
break;
|
|
case MODE_WIFIPASS:
|
|
break;
|
|
*/
|
|
case MODE_WIFISTAT:
|
|
#ifdef PICOW
|
|
return PG_Wifi_ReadStatusStr();
|
|
#else
|
|
return 0;
|
|
#endif
|
|
break;
|
|
case MODE_CDPORT: // SB Base port
|
|
return settings.CD.basePort == 0xFFFF ? 0 : (settings.CD.basePort >> 8);
|
|
#ifdef CDROM
|
|
case MODE_CDSTATUS:
|
|
printf("cdstatus %x\n", cdrom[0].image_status);
|
|
return cdrom[0].image_status;
|
|
case MODE_CDIMAGES:
|
|
if (cur_read_idx == cdrom[0].image_count) { // If end of the images
|
|
cur_read_idx = cur_read = 0;
|
|
cdrom[0].image_status = CD_STATUS_IDLE;
|
|
cdman_list_images_free(cdrom[0].image_list, cdrom[0].image_count);
|
|
return 0x04; // EOT
|
|
}
|
|
ret = cdrom[0].image_list[cur_read_idx][cur_read++];
|
|
putchar(ret);
|
|
if (ret == 0) { // Null terminated
|
|
++cur_read_idx;
|
|
cur_read = 0;
|
|
}
|
|
return ret;
|
|
case MODE_CDLOAD: // Load CD image
|
|
return cdman_current_image_index();
|
|
#endif
|
|
case MODE_HWTYPE: // Hardware version
|
|
return BOARD_TYPE;
|
|
case MODE_FLASH:
|
|
// Get status of firmware write
|
|
return pico_firmware_getStatus();
|
|
default:
|
|
return 0xff;
|
|
}
|
|
}
|
|
|
|
|
|
void processSettings(void) {
|
|
#if defined(SOUND_GUS)
|
|
settings.startupMode = GUS_MODE;
|
|
#elif defined(SOUND_TANDY)
|
|
settings.startupMode = TANDY_MODE;
|
|
#elif defined(SOUND_CMS)
|
|
settings.startupMode = CMS_MODE;
|
|
#elif defined(SOUND_SB)
|
|
settings.startupMode = SB_MODE;
|
|
#elif defined(SOUND_OPL)
|
|
settings.startupMode = ADLIB_MODE;
|
|
#elif defined(MPU_ONLY)
|
|
settings.startupMode = MPU_MODE;
|
|
#elif defined(USB_ONLY)
|
|
settings.startupMode = USB_MODE;
|
|
#elif defined(NE2000)
|
|
settings.startupMode = NE2000_MODE;
|
|
#else
|
|
settings.startupMode = INVALID_MODE;
|
|
#endif
|
|
#ifdef SOUND_SB
|
|
sb_port_test = settings.SB.basePort >> 4;
|
|
#endif
|
|
#ifdef SOUND_GUS
|
|
gus_port_test = settings.GUS.basePort >> 4 | 0x10;
|
|
GUS_SetFixed44k(settings.GUS.force44k);
|
|
GUS_SetAudioBuffer(settings.GUS.audioBuffer);
|
|
GUS_SetDMAInterval(settings.GUS.dmaInterval);
|
|
#endif
|
|
#ifdef USB_MOUSE
|
|
sermouse_set_protocol(settings.Mouse.protocol);
|
|
sermouse_set_report_rate_hz(settings.Mouse.reportRate);
|
|
sermouse_set_sensitivity(settings.Mouse.sensitivity);
|
|
#endif
|
|
#ifdef CDROM
|
|
cdrom_port_test = settings.CD.basePort >> 4;
|
|
printf("cdrom base port: %x\n", settings.CD.basePort);
|
|
#endif
|
|
if (BOARD_TYPE == PICOGUS_2) {
|
|
m62429->setVolume(M62429_BOTH, settings.Global.waveTableVolume);
|
|
}
|
|
}
|
|
|
|
|
|
static constexpr uint32_t IO_WAIT = 0xffffffffu;
|
|
static constexpr uint32_t IO_END = 0x0u;
|
|
// OR with 0x0000ff00 is required to set pindirs in the PIO
|
|
static constexpr uint32_t IOR_SET_VALUE = 0x0000ff00u;
|
|
|
|
__force_inline void handle_iow(void) {
|
|
uint32_t iow_read = pio_sm_get(pio0, IOW_PIO_SM); //>> 16;
|
|
// printf("%x", iow_read);
|
|
uint16_t port = (iow_read >> 8) & 0x3FF;
|
|
// printf("IOW: %x %x\n", port, iow_read & 0xFF);
|
|
#ifdef SOUND_GUS
|
|
if ((port >> 4 | 0x10) == gus_port_test) {
|
|
port -= settings.GUS.basePort;
|
|
switch (port) {
|
|
case 0x8:
|
|
case 0xb:
|
|
case 0x102:
|
|
case 0x103:
|
|
case 0x104:
|
|
// Fast write, don't set iochrdy by writing 0
|
|
pio_sm_put(pio0, IOW_PIO_SM, IO_END);
|
|
write_gus(port, iow_read & 0xFF);
|
|
// Fast write - return early as we've already written 0x0u to the PIO
|
|
return;
|
|
break;
|
|
default:
|
|
// gpio_xor_mask(LED_PIN);
|
|
// Slow write, set iochrdy by writing non-0
|
|
pio_sm_put(pio0, IOW_PIO_SM, IO_WAIT);
|
|
write_gus(port, iow_read & 0xFF);
|
|
gpio_xor_mask(LED_PIN);
|
|
break;
|
|
}
|
|
// printf("GUS IOW: port: %x value: %x\n", port, value);
|
|
// puts("IOW");
|
|
} else // if follows down below
|
|
#endif // SOUND_GUS
|
|
#ifdef SOUND_SB
|
|
if ((port >> 4) == sb_port_test) {
|
|
switch (port - settings.SB.basePort) {
|
|
// OPL ports
|
|
case 0x8:
|
|
// Fast write
|
|
pio_sm_put(pio0, IOW_PIO_SM, IO_END);
|
|
opl_buffer.cmds[opl_buffer.head++] = {
|
|
OPL_REGISTER_PORT,
|
|
(uint8_t)(iow_read & 0xFF)
|
|
};
|
|
// Fast write - return early as we've already written 0x0u to the PIO
|
|
return;
|
|
break;
|
|
case 0x9:
|
|
pio_sm_put(pio0, IOW_PIO_SM, IO_WAIT);
|
|
opl_buffer.cmds[opl_buffer.head++] = {
|
|
OPL_DATA_PORT,
|
|
(uint8_t)(iow_read & 0xFF)
|
|
};
|
|
break;
|
|
// DSP ports
|
|
default:
|
|
pio_sm_put(pio0, IOW_PIO_SM, IO_WAIT);
|
|
sbdsp_process();
|
|
sbdsp_write(port & 0xF,iow_read & 0xFF);
|
|
sbdsp_process();
|
|
break;
|
|
}
|
|
} else // if follows down below
|
|
#endif // SOUND_SB
|
|
#ifdef CDROM
|
|
if ((port >> 4) == cdrom_port_test) {
|
|
pio_sm_put(pio0, IOW_PIO_SM, IO_WAIT);
|
|
// putchar('w');
|
|
MKE_WRITE(port, iow_read & 0xFF);
|
|
} else // if follows down below
|
|
#endif
|
|
#if defined(SOUND_OPL)
|
|
if (port == settings.SB.oplBasePort) {
|
|
// Fast write
|
|
pio_sm_put(pio0, IOW_PIO_SM, IO_END);
|
|
opl_buffer.cmds[opl_buffer.head++] = {
|
|
OPL_REGISTER_PORT,
|
|
(uint8_t)(iow_read & 0xFF)
|
|
};
|
|
// Fast write - return early as we've already written 0x0u to the PIO
|
|
return;
|
|
} else if (port == settings.SB.oplBasePort + 1) {
|
|
pio_sm_put(pio0, IOW_PIO_SM, IO_WAIT);
|
|
if (settings.SB.oplSpeedSensitive) {
|
|
busy_wait_us(1); // busy wait for speed sensitive games
|
|
}
|
|
opl_buffer.cmds[opl_buffer.head++] = {
|
|
OPL_DATA_PORT,
|
|
(uint8_t)(iow_read & 0xFF)
|
|
};
|
|
} else // if follows down below
|
|
#endif // SOUND_OPL
|
|
#ifdef SOUND_TANDY
|
|
if (port == settings.Tandy.basePort) {
|
|
pio_sm_put(pio0, IOW_PIO_SM, IO_END);
|
|
tandy_buffer.cmds[tandy_buffer.head++] = iow_read & 0xFF;
|
|
return;
|
|
} else // if follows down below
|
|
#endif // SOUND_TANDY
|
|
#ifdef USB_JOYSTICK
|
|
if (port == settings.Joy.basePort) {
|
|
pio_sm_put(pio0, IOW_PIO_SM, IO_END);
|
|
// Set times in # of cycles (affected by clkdiv) for each PWM slice to count up and wrap back to 0
|
|
// TODO better calibrate this
|
|
// GUS w/ gravis gamestick -
|
|
// sbdiag: 322/267 16/18 572/520
|
|
// gravutil 34/29 2/2 61/56
|
|
// checkit 556/451 23/25 984/902
|
|
// Noname w/ gravis gamestick
|
|
// sbdiag: 256/214 7/6 495/435
|
|
// gravutil 28/23 1/1 53/47
|
|
// checkit 355/284 6/5 675/585
|
|
pwm_set_wrap(0, 2000 + ((uint16_t)joystate_struct.joy1_x << 6));
|
|
pwm_set_wrap(1, 2000 + ((uint16_t)joystate_struct.joy1_y << 6));
|
|
pwm_set_wrap(2, 2000 + ((uint16_t)joystate_struct.joy2_x << 6));
|
|
pwm_set_wrap(3, 2000 + ((uint16_t)joystate_struct.joy2_y << 6));
|
|
// Convince PWM to run as one-shot by immediately setting wrap to 0. This will take effect once the wrap
|
|
// times set above hit, so after wrapping the counter value will stay at 0 instead of counting again
|
|
pwm_set_wrap(0, 0);
|
|
pwm_set_wrap(1, 0);
|
|
pwm_set_wrap(2, 0);
|
|
pwm_set_wrap(3, 0);
|
|
return;
|
|
} else // if follows down below
|
|
#endif // USB_JOYSTICK
|
|
#ifdef USB_MOUSE
|
|
if ((port & ~7) == settings.Mouse.basePort) {
|
|
pio_sm_put(pio0, IOW_PIO_SM, IO_WAIT); // leave some time for UART logic emualtion
|
|
uartemu_write(port & 7, iow_read & 0xFF);
|
|
} else // if follows down below
|
|
#endif // USB_MOUSE
|
|
#ifdef NE2000
|
|
if((port & ~0x1F) == settings.NE2K.basePort) {
|
|
pio_sm_put(pio0, IOW_PIO_SM, IO_WAIT);
|
|
PG_NE2000_Write(port & 0x1f, iow_read & 0xFF);
|
|
} else // if follows down below
|
|
#endif
|
|
// PicoGUS control
|
|
if (port == CONTROL_PORT) {
|
|
pio_sm_put(pio0, IOW_PIO_SM, IO_WAIT);
|
|
// printf("iow control port: %x %d\n", iow_read & 0xff, control_active);
|
|
if ((iow_read & 0xFF) == 0xCC) {
|
|
// printf("activate ");
|
|
control_active = true;
|
|
} else if (control_active) {
|
|
select_picogus(iow_read & 0xFF);
|
|
}
|
|
} else if (port == DATA_PORT_LOW) {
|
|
pio_sm_put(pio0, IOW_PIO_SM, IO_END);
|
|
if (control_active) {
|
|
write_picogus_low(iow_read & 0xFF);
|
|
}
|
|
// Fast write - return early as we've already written 0x0u to the PIO
|
|
return;
|
|
} else if (port == DATA_PORT_HIGH) {
|
|
// printf("iow data port: %x\n", iow_read & 0xff);
|
|
pio_sm_put(pio0, IOW_PIO_SM, IO_WAIT);
|
|
if (control_active) {
|
|
write_picogus_high(iow_read & 0xFF);
|
|
}
|
|
} else {
|
|
#ifdef SOUND_CMS
|
|
switch (port - settings.CMS.basePort) {
|
|
// SAA data/address ports
|
|
case 0x0:
|
|
case 0x1:
|
|
case 0x2:
|
|
case 0x3:
|
|
pio_sm_put(pio0, IOW_PIO_SM, IO_END);
|
|
cms_buffer.cmds[cms_buffer.head++] = {
|
|
port,
|
|
(uint8_t)(iow_read & 0xFF)
|
|
};
|
|
return;
|
|
break;
|
|
// CMS autodetect ports
|
|
case 0x6:
|
|
case 0x7:
|
|
pio_sm_put(pio0, IOW_PIO_SM, IO_END);
|
|
cms_detect = iow_read & 0xFF;
|
|
return;
|
|
break;
|
|
}
|
|
#endif // SOUND_CMS
|
|
#ifdef SOUND_MPU
|
|
switch (port - settings.MPU.basePort) {
|
|
case 0:
|
|
pio_sm_put(pio0, IOW_PIO_SM, IO_WAIT);
|
|
// printf("MPU IOW: port: %x value: %x\n", port, iow_read & 0xFF);
|
|
MPU401_WriteData(iow_read & 0xFF, true);
|
|
gpio_xor_mask(LED_PIN);
|
|
break;
|
|
case 1:
|
|
pio_sm_put(pio0, IOW_PIO_SM, IO_WAIT);
|
|
MPU401_WriteCommand(iow_read & 0xFF, true);
|
|
// printf("MPU IOW: port: %x value: %x\n", port, iow_read & 0xFF);
|
|
// __dsb();
|
|
break;
|
|
}
|
|
#endif // SOUND_MPU
|
|
}
|
|
// Fallthrough if no match, or for slow write, reset PIO
|
|
pio_sm_put(pio0, IOW_PIO_SM, IO_END);
|
|
if (queueSaveSettings) {
|
|
saveSettings(&settings);
|
|
queueSaveSettings = false;
|
|
}
|
|
}
|
|
|
|
__force_inline void handle_ior(void) {
|
|
uint8_t x;
|
|
uint16_t port = pio_sm_get(pio0, IOR_PIO_SM) & 0x3FF;
|
|
#if defined(SOUND_GUS)
|
|
if ((port >> 4 | 0x10) == gus_port_test) {
|
|
// Tell PIO to wait for data
|
|
pio_sm_put(pio0, IOR_PIO_SM, IO_WAIT);
|
|
pio_sm_put(pio0, IOR_PIO_SM, IOR_SET_VALUE | read_gus(port - settings.GUS.basePort));
|
|
// gpio_xor_mask(LED_PIN);
|
|
} else // if follows down below
|
|
#endif
|
|
#if defined(SOUND_SB)
|
|
if ((port >> 4) == sb_port_test) {
|
|
pio_sm_put(pio0, IOR_PIO_SM, IO_WAIT);
|
|
switch (port - settings.SB.basePort) {
|
|
case 0x8:
|
|
// wait for OPL buffer to process
|
|
while (opl_buffer.tail != opl_buffer.head) {
|
|
tight_loop_contents();
|
|
}
|
|
pio_sm_put(pio0, IOR_PIO_SM, IOR_SET_VALUE | OPL_Pico_PortRead(OPL_REGISTER_PORT));
|
|
break;
|
|
default:
|
|
sbdsp_process();
|
|
pio_sm_put(pio0, IOR_PIO_SM, IOR_SET_VALUE | sbdsp_read(port & 0xF));
|
|
sbdsp_process();
|
|
break;
|
|
}
|
|
} else // if follows down below
|
|
#endif
|
|
#if defined(CDROM)
|
|
if ((port >> 4) == cdrom_port_test) {
|
|
// if ((port >> 4) == 0x23) {
|
|
pio_sm_put(pio0, IOR_PIO_SM, IO_WAIT);
|
|
pio_sm_put(pio0, IOR_PIO_SM, IOR_SET_VALUE | MKE_READ(port));
|
|
// putchar('r');
|
|
} else // if follows down below
|
|
#endif
|
|
#if defined(SOUND_OPL)
|
|
if (port == settings.SB.oplBasePort) {
|
|
// Tell PIO to wait for data
|
|
pio_sm_put(pio0, IOR_PIO_SM, IO_WAIT);
|
|
// wait for OPL buffer to process
|
|
while (opl_buffer.tail != opl_buffer.head) {
|
|
tight_loop_contents();
|
|
}
|
|
pio_sm_put(pio0, IOR_PIO_SM, IOR_SET_VALUE | OPL_Pico_PortRead(OPL_REGISTER_PORT));
|
|
} else // if follows down below
|
|
#endif
|
|
#if defined(SOUND_MPU)
|
|
if (port == settings.MPU.basePort) {
|
|
// Tell PIO to wait for data
|
|
pio_sm_put(pio0, IOR_PIO_SM, IO_WAIT);
|
|
// printf("MPU IOR: port: %x value: %x\n", port, value);
|
|
pio_sm_put(pio0, IOR_PIO_SM, IOR_SET_VALUE | MPU401_ReadData());
|
|
} else if (port == settings.MPU.basePort + 1) {
|
|
// Tell PIO to wait for data
|
|
pio_sm_put(pio0, IOR_PIO_SM, IO_WAIT);
|
|
// printf("MPU IOR: port: %x value: %x\n", port, value);
|
|
pio_sm_put(pio0, IOR_PIO_SM, IOR_SET_VALUE | MPU401_ReadStatus());
|
|
} else // if follows down below
|
|
#endif
|
|
#ifdef NE2000
|
|
if((port & ~0x1F) == settings.NE2K.basePort) {
|
|
pio_sm_put(pio0, IOR_PIO_SM, IO_WAIT);
|
|
pio_sm_put(pio0, IOR_PIO_SM, IOR_SET_VALUE | PG_NE2000_Read(port & 0x1f));
|
|
return;
|
|
}
|
|
#endif
|
|
#ifdef USB_JOYSTICK
|
|
if (port == settings.Joy.basePort) {
|
|
pio_sm_put(pio0, IOR_PIO_SM, IO_WAIT);
|
|
uint8_t value =
|
|
// Proportional bits: 1 if counter is still counting, 0 otherwise
|
|
(bool)pwm_get_counter(0) |
|
|
((bool)pwm_get_counter(1) << 1) |
|
|
((bool)pwm_get_counter(2) << 2) |
|
|
((bool)pwm_get_counter(3) << 3) |
|
|
joystate_struct.button_mask;
|
|
pio_sm_put(pio0, IOR_PIO_SM, IOR_SET_VALUE | value);
|
|
} else // if follows down below
|
|
#endif // USB_JOYSTICK
|
|
#ifdef USB_MOUSE
|
|
if ((port & ~7) == settings.Mouse.basePort) {
|
|
pio_sm_put(pio0, IOR_PIO_SM, IO_WAIT);
|
|
pio_sm_put(pio0, IOR_PIO_SM, IOR_SET_VALUE | uartemu_read(port & 7));
|
|
return;
|
|
} else // if follows down below
|
|
#endif // USB_MOUSE
|
|
if (port == CONTROL_PORT) {
|
|
// Tell PIO to wait for data
|
|
pio_sm_put(pio0, IOR_PIO_SM, IO_WAIT);
|
|
pio_sm_put(pio0, IOR_PIO_SM, IOR_SET_VALUE | sel_reg);
|
|
} else if (port == DATA_PORT_LOW) {
|
|
// Tell PIO to wait for data
|
|
pio_sm_put(pio0, IOR_PIO_SM, IO_WAIT);
|
|
pio_sm_put(pio0, IOR_PIO_SM, IOR_SET_VALUE | read_picogus_low());
|
|
} else if (port == DATA_PORT_HIGH) {
|
|
pio_sm_put(pio0, IOR_PIO_SM, IO_WAIT);
|
|
pio_sm_put(pio0, IOR_PIO_SM, IOR_SET_VALUE | read_picogus_high());
|
|
} else {
|
|
#if defined(SOUND_CMS)
|
|
switch (port - settings.CMS.basePort) {
|
|
// CMS autodetect ports
|
|
case 0x4:
|
|
pio_sm_put(pio0, IOR_PIO_SM, IO_WAIT);
|
|
pio_sm_put(pio0, IOR_PIO_SM, IOR_SET_VALUE | 0x7F);
|
|
return;
|
|
case 0xa:
|
|
case 0xb:
|
|
pio_sm_put(pio0, IOR_PIO_SM, IO_WAIT);
|
|
pio_sm_put(pio0, IOR_PIO_SM, IOR_SET_VALUE | cms_detect);
|
|
return;
|
|
}
|
|
#endif // SOUND_CMS
|
|
// Reset PIO
|
|
pio_sm_put(pio0, IOR_PIO_SM, IO_END);
|
|
}
|
|
}
|
|
|
|
#ifdef USE_IRQ
|
|
void iow_isr(void) {
|
|
/* //printf("ints %x\n", pio0->ints0); */
|
|
handle_iow();
|
|
// pio_interrupt_clear(pio0, pio_intr_sm0_rxnempty_lsb);
|
|
irq_clear(PIO0_IRQ_0);
|
|
}
|
|
void ior_isr(void) {
|
|
handle_ior();
|
|
// pio_interrupt_clear(pio0, PIO_INTR_SM0_RXNEMPTY_LSB);
|
|
irq_clear(PIO0_IRQ_1);
|
|
}
|
|
#endif
|
|
|
|
void err_blink(void) {
|
|
for (;;) {
|
|
//gpio_xor_mask(LED_PIN);//need to abscrat led functions out to handle chipdown vs picow
|
|
busy_wait_ms(100);
|
|
}
|
|
}
|
|
|
|
constexpr uint32_t rp2_clock = RP2_CLOCK_SPEED;
|
|
constexpr float psram_clkdiv = (float)rp2_clock / 200000.0;
|
|
constexpr float pwm_clkdiv = (float)rp2_clock / 22727.27;
|
|
constexpr float iow_clkdiv = (float)rp2_clock / 183000.0;
|
|
|
|
constexpr uint32_t iow_rxempty = 1u << (PIO_FSTAT_RXEMPTY_LSB + IOW_PIO_SM);
|
|
__force_inline bool iow_has_data() {
|
|
return !(pio0->fstat & iow_rxempty);
|
|
}
|
|
|
|
constexpr uint32_t ior_rxempty = 1u << (PIO_FSTAT_RXEMPTY_LSB + IOR_PIO_SM);
|
|
__force_inline bool ior_has_data() {
|
|
return !(pio0->fstat & ior_rxempty);
|
|
}
|
|
|
|
#include "hardware/structs/xip_ctrl.h"
|
|
int main()
|
|
{
|
|
#ifdef ASYNC_UART
|
|
stdio_async_uart_init_full(UART_ID, BAUD_RATE, UART_TX_PIN, UART_RX_PIN);
|
|
#else
|
|
stdio_init_all();
|
|
#endif
|
|
puts(firmware_string);
|
|
io_rw_32 *reset_reason = (io_rw_32 *) (VREG_AND_CHIP_RESET_BASE + VREG_AND_CHIP_RESET_CHIP_RESET_OFFSET);
|
|
if (*reset_reason & VREG_AND_CHIP_RESET_CHIP_RESET_HAD_POR_BITS) {
|
|
puts("I was reset due to power on reset or brownout detection.");
|
|
} else if (*reset_reason & VREG_AND_CHIP_RESET_CHIP_RESET_HAD_RUN_BITS) {
|
|
puts("I was reset due to the RUN pin (either manually or due to ISA RESET signal)");
|
|
} else if(*reset_reason & VREG_AND_CHIP_RESET_CHIP_RESET_HAD_PSM_RESTART_BITS) {
|
|
puts("I was reset due the debug port");
|
|
}
|
|
|
|
// Load settings from flash
|
|
loadSettings(&settings);
|
|
hw_clear_bits(&xip_ctrl_hw->ctrl, XIP_CTRL_EN_BITS);
|
|
|
|
// Determine board type. GPIO 29 is grounded on PicoGUS v2.0, and on a Pico, it's VSYS/3 (~1.666V)
|
|
// GPIO 25 must be high to read GPIO 29 on the Pico W
|
|
gpio_init(25);
|
|
gpio_set_dir(25, GPIO_OUT);
|
|
gpio_put(25, 1);
|
|
adc_init();
|
|
adc_gpio_init(29);
|
|
// Select ADC input 3 (GPIO29)
|
|
adc_select_input(3);
|
|
// Read several times to let ADC stabilize
|
|
adc_read(); adc_read(); adc_read(); adc_read(); adc_read();
|
|
uint16_t result = adc_read();
|
|
printf("ADC value: 0x%03x... ", result);
|
|
gpio_put(25, 0);
|
|
gpio_deinit(25);
|
|
|
|
if (result > 0x100) {
|
|
puts("Running on Pico-based board (PicoGUS v1.1+, PicoGUS Femto)");
|
|
// On Pico-based board (PicoGUS v1.1+, PicoGUS Femto)
|
|
#ifndef PICOW
|
|
LED_PIN = 1 << PICO_DEFAULT_LED_PIN;
|
|
gpio_init(PICO_DEFAULT_LED_PIN);
|
|
gpio_set_dir(PICO_DEFAULT_LED_PIN, GPIO_OUT);
|
|
#endif
|
|
BOARD_TYPE = PICO_BASED;
|
|
} else {
|
|
// On chipdown board (PicoGUS v2.0)
|
|
puts("Running on PicoGUS v2.0");
|
|
LED_PIN = 1 << 23;
|
|
gpio_init(23);
|
|
gpio_set_dir(23, GPIO_OUT);
|
|
BOARD_TYPE = PICOGUS_2;
|
|
}
|
|
gpio_set_mask(LED_PIN);
|
|
printf("Waiting for board to stabilize... ");
|
|
busy_wait_ms(250);
|
|
// Overclock!
|
|
printf("Overclocking... ");
|
|
vreg_set_voltage(VREG_VOLTAGE_1_25);
|
|
// vreg_set_voltage(VREG_VOLTAGE_1_15);
|
|
busy_wait_ms(250);
|
|
set_sys_clock_khz(rp2_clock, true);
|
|
busy_wait_ms(250);
|
|
gpio_xor_mask(LED_PIN);
|
|
#ifdef ASYNC_UART
|
|
uart_init(UART_ID, 0);
|
|
#else
|
|
stdio_init_all();
|
|
#endif
|
|
puts("Done. Continuing!");
|
|
|
|
// Set clk_peri to use the XOSC
|
|
// clock_configure(clk_peri,
|
|
// 0,
|
|
// CLOCKS_CLK_PERI_CTRL_AUXSRC_VALUE_XOSC_CLKSRC,
|
|
// 12 * MHZ,
|
|
// 12 * MHZ);
|
|
// clock_configure(clk_peri, 0, CLOCKS_CLK_PERI_CTRL_AUXSRC_VALUE_CLK_SYS,
|
|
// 12 * MHZ, 12 * MHZ);
|
|
|
|
if (BOARD_TYPE == PICOGUS_2) {
|
|
// Create new interface to M62429 digital volume control
|
|
m62429 = new M62429();
|
|
// Data pin = GPIO24, data pin = GPIO25
|
|
#ifdef M62429_PIO
|
|
m62429->begin(24, 25, pio1, -1);
|
|
#else
|
|
m62429->begin(24, 25);
|
|
// Initial volume is set in processSettings()
|
|
#endif // M62429_PIO
|
|
}
|
|
|
|
gpio_init(IRQ_PIN);
|
|
gpio_set_dir(IRQ_PIN, GPIO_OUT);
|
|
gpio_set_drive_strength(IRQ_PIN, GPIO_DRIVE_STRENGTH_12MA);
|
|
|
|
#ifdef SOUND_MPU
|
|
puts("Initing MIDI UART...");
|
|
uart_init(UART_ID, 31250);
|
|
uart_set_translate_crlf(UART_ID, false);
|
|
uart_set_format(UART_ID, 8, 1, UART_PARITY_NONE);
|
|
if (BOARD_TYPE == PICO_BASED) {
|
|
// Original hardware drives MIDI directly from RP2040. Newer HW uses an open drain inverter
|
|
// PicoGUS v1.2 also uses an open drain but we can't detect that particular board
|
|
gpio_set_drive_strength(UART_TX_PIN, GPIO_DRIVE_STRENGTH_12MA);
|
|
}
|
|
gpio_set_function(UART_TX_PIN, GPIO_FUNC_UART);
|
|
#endif // SOUND_MPU
|
|
|
|
#ifdef PSRAM_CORE0
|
|
#ifdef PSRAM
|
|
puts("Initing PSRAM...");
|
|
// Try different PSRAM strategies
|
|
if (BOARD_TYPE == PICOGUS_2) {
|
|
psram_spi = psram_spi_init_clkdiv(pio1, -1, psram_clkdiv /* clkdiv */, false /* fudge */);
|
|
#if TEST_PSRAM
|
|
// Only bother to test every 97th address
|
|
if (test_psram(&psram_spi, 97) == 1) {
|
|
printf("Default PSRAM strategy of no fudge not working, switching to fudge\n");
|
|
psram_spi_uninit(psram_spi, false /* fudge */);
|
|
psram_spi = psram_spi_init_clkdiv(pio1, -1, psram_clkdiv /* clkdiv */, true /* fudge */);
|
|
if (test_psram(&psram_spi, 97) == 1) {
|
|
printf("Error: No PSRAM strategies found to work!\n");
|
|
err_blink();
|
|
}
|
|
}
|
|
#endif // TEST_PSRAM
|
|
} else {
|
|
psram_spi = psram_spi_init_clkdiv(pio1, -1, psram_clkdiv /* clkdiv */, true /* fudge */);
|
|
#if TEST_PSRAM
|
|
if (test_psram(&psram_spi, 97) == 1) {
|
|
psram_spi_uninit(psram_spi, true /* fudge */);
|
|
psram_spi = psram_spi_init_clkdiv(pio1, -1, psram_clkdiv /* clkdiv */, false /* fudge */);
|
|
if (test_psram(&psram_spi, 97) == 1) {
|
|
printf("Error: No PSRAM strategies found to work!\n");
|
|
err_blink();
|
|
}
|
|
}
|
|
#endif // TEST_PSRAM
|
|
}
|
|
#endif // PSRAM
|
|
#endif // PSRAM_CORE0
|
|
|
|
|
|
#ifdef SOUND_SB
|
|
puts("Initializing SoundBlaster DSP");
|
|
sbdsp_init();
|
|
#endif // SOUND_SB
|
|
#ifdef SOUND_OPL
|
|
puts("Creating OPL");
|
|
OPL_Pico_Init(0);
|
|
multicore_launch_core1(&play_adlib);
|
|
#endif
|
|
|
|
#ifdef CDROM
|
|
mke_init();
|
|
#endif
|
|
|
|
#ifdef SOUND_GUS
|
|
puts("Creating GUS");
|
|
GUS_OnReset();
|
|
multicore_launch_core1(&play_gus);
|
|
#endif // SOUND_GUS
|
|
|
|
#ifdef SOUND_MPU
|
|
#ifdef MPU_ONLY
|
|
multicore_launch_core1(&play_mpu);
|
|
#endif // MPU_ONLY
|
|
#endif // SOUND_MPU
|
|
|
|
#ifdef SOUND_TANDY
|
|
puts("Creating tandysound");
|
|
multicore_launch_core1(&play_tandy);
|
|
#endif // SOUND_TANDY
|
|
|
|
#ifdef SOUND_CMS
|
|
puts("Creating CMS");
|
|
multicore_launch_core1(&play_cms);
|
|
#endif // SOUND_CMS
|
|
|
|
#ifdef NE2000
|
|
extern void PIC_ActivateIRQ(void);
|
|
extern void PIC_DeActivateIRQ(void);
|
|
|
|
puts("Creating NE2000");
|
|
multicore_launch_core1(&play_ne2000);
|
|
#endif
|
|
|
|
#ifdef USB_JOYSTICK
|
|
// Init joystick as centered with no buttons pressed
|
|
joystate_struct = {127, 127, 127, 127, 0xf};
|
|
puts("Config joystick PWM");
|
|
pwm_config pwm_c = pwm_get_default_config();
|
|
// TODO better calibrate this
|
|
pwm_config_set_clkdiv(&pwm_c, pwm_clkdiv);
|
|
// Start the PWM off constantly looping at 0
|
|
pwm_config_set_wrap(&pwm_c, 0);
|
|
pwm_init(0, &pwm_c, true);
|
|
pwm_init(1, &pwm_c, true);
|
|
pwm_init(2, &pwm_c, true);
|
|
pwm_init(3, &pwm_c, true);
|
|
#endif // USB_JOYSTICK
|
|
#ifdef USB_MOUSE
|
|
puts("Config USB Mouse emulation");
|
|
uartemu_init(0);
|
|
sermouse_init(settings.Mouse.protocol, settings.Mouse.reportRate, settings.Mouse.sensitivity);
|
|
sermouse_attach_uart();
|
|
#endif // USB_MOUSE
|
|
#ifdef USB_ONLY
|
|
multicore_launch_core1(&play_usb);
|
|
#endif // USBONLY
|
|
|
|
for(int i=AD0_PIN; i<(AD0_PIN + 10); ++i) {
|
|
gpio_disable_pulls(i);
|
|
}
|
|
gpio_disable_pulls(IOW_PIN);
|
|
gpio_disable_pulls(IOR_PIN);
|
|
gpio_pull_down(IOCHRDY_PIN);
|
|
gpio_set_dir(IOCHRDY_PIN, GPIO_OUT);
|
|
|
|
puts("Enabling bus transceivers...");
|
|
// waggle ADS to set BUSOE latch
|
|
gpio_init(ADS_PIN);
|
|
gpio_set_dir(ADS_PIN, GPIO_OUT);
|
|
gpio_put(ADS_PIN, 1);
|
|
busy_wait_ms(10);
|
|
gpio_put(ADS_PIN, 0);
|
|
|
|
puts("Starting ISA bus PIO...");
|
|
// gpio_set_drive_strength(ADS_PIN, GPIO_DRIVE_STRENGTH_12MA);
|
|
gpio_set_slew_rate(ADS_PIN, GPIO_SLEW_RATE_FAST);
|
|
|
|
uint iow_offset = pio_add_program(pio0, &iow_program);
|
|
pio_sm_claim(pio0, IOW_PIO_SM);
|
|
printf("iow sm: %u\n", IOW_PIO_SM);
|
|
|
|
uint ior_offset = pio_add_program(pio0, &ior_program);
|
|
pio_sm_claim(pio0, IOR_PIO_SM);
|
|
printf("ior sm: %u\n", IOR_PIO_SM);
|
|
|
|
iow_program_init(pio0, IOW_PIO_SM, iow_offset, iow_clkdiv);
|
|
ior_program_init(pio0, IOR_PIO_SM, ior_offset);
|
|
|
|
#ifdef USE_IRQ
|
|
puts("Enabling IRQ on ISA IOR/IOW events");
|
|
// iow irq
|
|
irq_set_enabled(PIO0_IRQ_0, false);
|
|
pio_set_irq0_source_enabled(pio0, pis_sm0_rx_fifo_not_empty, true);
|
|
irq_set_priority(PIO0_IRQ_0, PICO_HIGHEST_IRQ_PRIORITY);
|
|
irq_set_exclusive_handler(PIO0_IRQ_0, iow_isr);
|
|
irq_set_enabled(PIO0_IRQ_0, true);
|
|
// ior irq
|
|
irq_set_enabled(PIO0_IRQ_1, false);
|
|
pio_set_irq1_source_enabled(pio0, pis_sm1_rx_fifo_not_empty, true);
|
|
irq_set_priority(PIO0_IRQ_1, PICO_HIGHEST_IRQ_PRIORITY);
|
|
irq_set_exclusive_handler(PIO0_IRQ_1, ior_isr);
|
|
irq_set_enabled(PIO0_IRQ_1, true);
|
|
#endif
|
|
|
|
gpio_xor_mask(LED_PIN);
|
|
|
|
processSettings();
|
|
|
|
for (;;) {
|
|
#ifndef USE_IRQ
|
|
if (iow_has_data()) {
|
|
handle_iow();
|
|
}
|
|
|
|
if (ior_has_data()) {
|
|
handle_ior();
|
|
}
|
|
#endif
|
|
#ifdef POLLING_DMA
|
|
process_dma();
|
|
#endif
|
|
// cdrom_tasks(&cdrom[0]);
|
|
}
|
|
}
|