mirror of
https://github.com/polpo/picogus.git
synced 2026-10-25 21:40:16 +00:00
343 lines
10 KiB
C++
343 lines
10 KiB
C++
#include <stdio.h>
|
|
#include "pico/stdlib.h"
|
|
#include "pico/multicore.h"
|
|
#include "hardware/pio.h"
|
|
#include "hardware/irq.h"
|
|
// #include "hardware/vreg.h"
|
|
#include "hardware/regs/vreg_and_chip_reset.h"
|
|
|
|
|
|
#include "stdio_async_uart.h"
|
|
/*
|
|
#define UART_TX_PIN (0)
|
|
#define UART_RX_PIN (1)
|
|
#define UART_ID uart0
|
|
*/
|
|
#define UART_TX_PIN (28)
|
|
#define UART_RX_PIN (-1)
|
|
#define UART_ID uart0
|
|
#define BAUD_RATE 115200
|
|
|
|
// #include "clock_pll.h"
|
|
|
|
#ifdef PSRAM
|
|
#include "psram_spi.h"
|
|
pio_spi_inst_t psram_spi;
|
|
#endif
|
|
#include "isa_io.pio.h"
|
|
|
|
#ifdef SOUND_OPL
|
|
#include "opl.h"
|
|
|
|
void play_adlib(void);
|
|
extern "C" int OPL_Pico_Init(unsigned int);
|
|
extern "C" void OPL_Pico_PortWrite(opl_port_t, unsigned int);
|
|
#endif
|
|
|
|
#ifdef SOUND_GUS
|
|
#ifdef DOSBOX_STAGING
|
|
#include "gus.h"
|
|
Gus* gus;
|
|
#else
|
|
#include "gus-x.cpp"
|
|
#endif
|
|
|
|
constexpr uint16_t GUS_PORT = 0x240u;
|
|
constexpr uint16_t GUS_PORT_TEST = GUS_PORT >> 4 | 0x10;
|
|
void play_gus(void);
|
|
#endif
|
|
|
|
constexpr uint LED_PIN = PICO_DEFAULT_LED_PIN;
|
|
|
|
static uint iow_sm;
|
|
static uint ior_sm;
|
|
static uint ior_write_sm;
|
|
uint32_t iow_read;
|
|
uint32_t ior_read;
|
|
uint16_t port;
|
|
uint32_t value;
|
|
|
|
|
|
__force_inline void handle_iow(void) {
|
|
iow_read = pio_sm_get_blocking(pio0, iow_sm); //>> 16;
|
|
// printf("IOW: %x\n", iow_read);
|
|
port = (iow_read >> 8) & 0x3FF;
|
|
#ifdef SOUND_GUS
|
|
if ((port >> 4 | 0x10) == GUS_PORT_TEST) {
|
|
pio_sm_put(pio0, iow_sm, 0xffffffffu);
|
|
value = iow_read & 0xFF;
|
|
// uint32_t write_begin = time_us_32();
|
|
#ifdef DOSBOX_STAGING
|
|
gus->WriteToPort(port, value, io_width_t::byte); // 3x4 supports 16-bit transfers but PiGUS doesn't! force byte
|
|
#else
|
|
write_gus(port, value, 1 /* always an 8 bit write */);
|
|
#endif
|
|
// uint32_t write_elapsed = time_us_32() - write_begin;
|
|
// if (write_elapsed > 1) {
|
|
// printf("long write to port %x, (sel reg %x), took %d us\n", port, gus->selected_register, write_elapsed);
|
|
// }
|
|
// Tell PIO that we are done
|
|
pio_sm_put(pio0, iow_sm, 0x0u);
|
|
//printf("GUS IOW: port: %x value: %x\n", port, value);
|
|
// gpio_xor_mask(1u << LED_PIN);
|
|
// puts("IOW");
|
|
// uart_print_hex_u32(port);
|
|
// uart_print_hex_u32(value);
|
|
} else {
|
|
// Reset SM
|
|
pio_sm_put(pio0, iow_sm, 0x0u);
|
|
// gpio_xor_mask(1u << LED_PIN);
|
|
}
|
|
#endif // SOUND_GUS
|
|
#ifdef SOUND_OPL
|
|
switch (port) {
|
|
case 0x388:
|
|
pio_sm_put(pio0, iow_sm, 0xffffffffu);
|
|
OPL_Pico_PortWrite(OPL_REGISTER_PORT, iow_read & 0xFF);
|
|
// Tell PIO that we are done
|
|
pio_sm_put(pio0, iow_sm, 0x0u);
|
|
break;
|
|
case 0x389:
|
|
pio_sm_put(pio0, iow_sm, 0xffffffffu);
|
|
OPL_Pico_PortWrite(OPL_DATA_PORT, iow_read & 0xFF);
|
|
__dsb();
|
|
// Tell PIO that we are done
|
|
pio_sm_put(pio0, iow_sm, 0x0u);
|
|
break;
|
|
default:
|
|
pio_sm_put(pio0, iow_sm, 0x0u);
|
|
}
|
|
#endif // SOUND_OPL
|
|
}
|
|
|
|
__force_inline void handle_ior(void) {
|
|
ior_read = pio_sm_get_blocking(pio0, ior_sm); //>> 16;
|
|
port = ior_read & 0x3FF;
|
|
// printf("IOR: %x\n", port);
|
|
#ifdef SOUND_GUS
|
|
if ((port >> 4 | 0x10) == GUS_PORT_TEST) {
|
|
// Tell PIO to wait for data
|
|
pio_sm_put(pio0, ior_sm, 0xffffffffu);
|
|
if (port == 0x242) {
|
|
value = 0xdd;
|
|
} else {
|
|
#ifdef DOSBOX_STAGING
|
|
value = gus->ReadFromPort(port, io_width_t::byte);
|
|
#else
|
|
value = read_gus(port, 1);
|
|
#endif
|
|
}
|
|
// OR with 0x00ffff00 is required to set pindirs in the PIO
|
|
pio_sm_put(pio0, ior_sm, 0x00ffff00u | value);
|
|
// printf("GUS IOR: port: %x value: %x\n", port, value);
|
|
// gpio_xor_mask(1u << LED_PIN);
|
|
} else {
|
|
// Reset PIO
|
|
pio_sm_put(pio0, ior_sm, 0x0u);
|
|
}
|
|
#endif
|
|
}
|
|
|
|
#ifdef USE_IRQ
|
|
void isr(void) {
|
|
/* //printf("ints %x\n", pio0->ints0); */
|
|
if (pio0->ints0 & PIO_INTR_SM0_RXNEMPTY_LSB) {
|
|
/* //printf("ints iow %x\n", pio0->ints0); */
|
|
handle_iow();
|
|
pio_interrupt_clear(pio0, PIO_INTR_SM0_RXNEMPTY_LSB);
|
|
}
|
|
if (pio0->ints0 & PIO_INTR_SM1_RXNEMPTY_LSB) {
|
|
/* //printf("ints ior %x\n", pio0->ints0); */
|
|
handle_ior();
|
|
pio_interrupt_clear(pio0, PIO_INTR_SM1_RXNEMPTY_LSB);
|
|
}
|
|
/* irq_clear(PIO0_IRQ_0); */
|
|
}
|
|
#endif
|
|
|
|
void err_blink(void) {
|
|
for (;;) {
|
|
gpio_xor_mask(1u << LED_PIN);
|
|
busy_wait_ms(100);
|
|
}
|
|
}
|
|
|
|
#ifndef USE_ALARM
|
|
#include "pico_pic.h"
|
|
#endif
|
|
|
|
int main()
|
|
{
|
|
// Overclock!
|
|
// set_sys_clock_khz(200000, true);
|
|
// Use hacked set_sys_clock_khz to keep SPI clock high - see clock_pll.h for details
|
|
// gset_sys_clock_khz(266000, true);
|
|
set_sys_clock_khz(270000, true);
|
|
// vreg_set_voltage(VREG_VOLTAGE_1_20);
|
|
|
|
// stdio_init_all();
|
|
stdio_async_uart_init_full(UART_ID, BAUD_RATE, UART_TX_PIN, UART_RX_PIN);
|
|
|
|
puts("PicoGUS booting!");
|
|
|
|
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_POR_BITS) {
|
|
puts("I was reset due the debug port");
|
|
}
|
|
|
|
gpio_init(LED_PIN);
|
|
gpio_set_dir(LED_PIN, GPIO_OUT);
|
|
|
|
alarm_pool_init_default();
|
|
gpio_init(IRQ_PIN);
|
|
gpio_set_dir(IRQ_PIN, GPIO_OUT);
|
|
|
|
#ifdef USE_IRQ
|
|
puts("Enabling IRQ");
|
|
const int irq = PIO0_IRQ_0;
|
|
pio_set_irq0_source_mask_enabled(pio0, PIO_INTR_SM0_RXNEMPTY_LSB | PIO_INTR_SM1_RXNEMPTY_LSB | PIO_INTR_SM2_RXNEMPTY_LSB | PIO_INTR_SM3_RXNEMPTY_LSB, true);
|
|
irq_set_enabled(irq, false);
|
|
irq_set_priority(irq, PICO_HIGHEST_IRQ_PRIORITY);
|
|
irq_set_exclusive_handler(irq, isr);
|
|
irq_set_enabled(irq, true);
|
|
#endif
|
|
|
|
#ifdef PSRAM
|
|
puts("Initing PSRAM...");
|
|
psram_spi = psram_init();
|
|
#if TEST_PSRAM
|
|
puts("Writing PSRAM...");
|
|
uint8_t deadbeef[8] = {0xd, 0xe, 0xa, 0xd, 0xb, 0xe, 0xe, 0xf};
|
|
for (uint32_t addr = 0; addr < (1024 * 1024); ++addr) {
|
|
psram_write8(&psram_spi, addr, (addr & 0xFF));
|
|
}
|
|
puts("Reading PSRAM...");
|
|
uint32_t psram_begin = time_us_32();
|
|
for (uint32_t addr = 0; addr < (1024 * 1024); ++addr) {
|
|
uint8_t result = psram_read8(&psram_spi, addr);
|
|
if (static_cast<uint8_t>((addr & 0xFF)) != result) {
|
|
printf("\nPSRAM failure at address %x (%x != %x)\n", addr, addr & 0xFF, result);
|
|
err_blink();
|
|
return 1;
|
|
}
|
|
}
|
|
uint32_t psram_elapsed = time_us_32() - psram_begin;
|
|
float psram_speed = 1000000.0 * 1024.0 * 1024 / psram_elapsed;
|
|
printf("8 bit: PSRAM read 1MB in %d us, %d B/s (target 705600 B/s)\n", psram_elapsed, (uint32_t)psram_speed);
|
|
|
|
psram_begin = time_us_32();
|
|
for (uint32_t addr = 0; addr < (1024 * 1024); addr += 2) {
|
|
uint16_t result = psram_read16(&psram_spi, addr);
|
|
if (static_cast<uint16_t>(
|
|
(((addr + 1) & 0xFF) << 8) |
|
|
(addr & 0XFF)) != result
|
|
) {
|
|
printf("PSRAM failure at address %x (%x != %x) ", addr, addr & 0xFF, result & 0xFF);
|
|
err_blink();
|
|
return 1;
|
|
}
|
|
}
|
|
psram_elapsed = (time_us_32() - psram_begin);
|
|
psram_speed = 1000000.0 * 1024 * 1024 / psram_elapsed;
|
|
printf("16 bit: PSRAM read 1MB in %d us, %d B/s (target 1411200 B/s)\n", psram_elapsed, (uint32_t)psram_speed);
|
|
|
|
psram_begin = time_us_32();
|
|
for (uint32_t addr = 0; addr < (1024 * 1024); addr += 4) {
|
|
uint32_t result = psram_read32(&psram_spi, addr);
|
|
if (static_cast<uint32_t>(
|
|
(((addr + 3) & 0xFF) << 24) |
|
|
(((addr + 2) & 0xFF) << 16) |
|
|
(((addr + 1) & 0xFF) << 8) |
|
|
(addr & 0XFF)) != result
|
|
) {
|
|
printf("PSRAM failure at address %x (%x != %x) ", addr, addr & 0xFF, result & 0xFF);
|
|
err_blink();
|
|
return 1;
|
|
}
|
|
}
|
|
psram_elapsed = (time_us_32() - psram_begin);
|
|
psram_speed = 1000000.0 * 1024 * 1024 / psram_elapsed;
|
|
printf("32 bit: PSRAM read 1MB in %d us, %d B/s (target 1411200 B/s)\n", psram_elapsed, (uint32_t)psram_speed);
|
|
#endif
|
|
#endif
|
|
|
|
#ifdef SOUND_OPL
|
|
puts("Creating OPL");
|
|
OPL_Pico_Init(0x388);
|
|
multicore_launch_core1(&play_adlib);
|
|
#endif
|
|
|
|
#ifdef SOUND_GUS
|
|
puts("Creating GUS");
|
|
#ifdef DOSBOX_STAGING
|
|
gus = new Gus(GUS_PORT, nullptr, nullptr);
|
|
#else
|
|
GUS_OnReset();
|
|
#endif
|
|
multicore_launch_core1(&play_gus);
|
|
#endif
|
|
|
|
|
|
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_disable_pulls(IOCHRDY_PIN);
|
|
// gpio_put(IOCHRDY_PIN, 1);
|
|
// gpio_init(IOCHRDY_PIN);
|
|
gpio_pull_up(IOCHRDY_PIN);
|
|
gpio_set_dir(IOCHRDY_PIN, GPIO_OUT);
|
|
// gpio_put(IOCHRDY_PIN, 1);
|
|
|
|
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);
|
|
|
|
PIO pio = pio0;
|
|
|
|
uint ior_offset = pio_add_program(pio, &ior_program);
|
|
ior_sm = pio_claim_unused_sm(pio, true);
|
|
|
|
uint iow_offset = pio_add_program(pio, &iow_program);
|
|
iow_sm = pio_claim_unused_sm(pio, true);
|
|
|
|
ior_program_init(pio, ior_sm, ior_offset);
|
|
iow_program_init(pio, iow_sm, iow_offset);
|
|
|
|
gpio_xor_mask(1u << LED_PIN);
|
|
|
|
/*
|
|
PIC_Init();
|
|
*/
|
|
|
|
for (;;) {
|
|
#ifndef USE_IRQ
|
|
if (!pio_sm_is_rx_fifo_empty(pio, iow_sm)) {
|
|
handle_iow();
|
|
// gpio_xor_mask(1u << LED_PIN);
|
|
}
|
|
|
|
if (!pio_sm_is_rx_fifo_empty(pio, ior_sm)) {
|
|
handle_ior();
|
|
// gpio_xor_mask(1u << LED_PIN);
|
|
}
|
|
#endif
|
|
#ifndef USE_ALARM
|
|
PIC_HandleEvents();
|
|
#endif
|
|
}
|
|
}
|