mirror of
https://github.com/polpo/picogus.git
synced 2026-10-25 21:40:16 +00:00
38 files changed
+977
-477
No files matched your search
+58
-27
@@ -71,7 +71,7 @@ static void pageprintf(char *format, ...)
|
||||
|
||||
static void banner(void)
|
||||
{
|
||||
printf("PicoGUSinit v3.8.0 (c) 2025 Ian Scott - licensed under the GNU GPL v2\n");
|
||||
printf("PicoGUSinit v3.9.0 (c) 2025 Ian Scott - licensed under the GNU GPL v2\n");
|
||||
}
|
||||
|
||||
|
||||
@@ -182,23 +182,48 @@ static void err_ultrasnd(void)
|
||||
}
|
||||
|
||||
|
||||
static void err_blaster(void)
|
||||
typedef enum {
|
||||
BLASTER_UNSET,
|
||||
BLASTER_MALFORMED,
|
||||
BLASTER_DMA16_MISMATCH,
|
||||
BLASTER_MISMATCH,
|
||||
} blaster_err_t;
|
||||
|
||||
static void err_blaster_format_help(void)
|
||||
{
|
||||
// "................................................................................\n"
|
||||
fprintf(stderr, "ERROR: In SB mode but no BLASTER variable set or is malformed!\n");
|
||||
fprintf(stderr, "The BLASTER environment variable must be set in the following format:\n");
|
||||
fprintf(stderr, "\tset BLASTER=Axxx Iy Dz Hz Tw\n");
|
||||
fprintf(stderr, "Where xxx = port, y = IRQ, z = DMA. w = SB type:\n");
|
||||
fprintf(stderr, " 1 - SB 1.x, 2 - SB Pro 1 (dual OPL2), 3 - SB 2.0,\n");
|
||||
fprintf(stderr, " 4 - SB Pro 2 (OPL3), 6 - SB 16\n");
|
||||
fprintf(stderr, "Port is set via /sbport xxx option; DMA and IRQ configued via jumper then also\n");
|
||||
fprintf(stderr, "set via /sbirq y and /sbdma y options.\n");
|
||||
}
|
||||
|
||||
static void err_blaster16_dma_mismatch(void)
|
||||
static void err_blaster(blaster_err_t reason)
|
||||
{
|
||||
// "................................................................................\n"
|
||||
fprintf(stderr, "ERROR: In SB 16 mode, low (Dx) and high (Hx) DMA in BLASTER variable must match!\n");
|
||||
// "................................................................................\n"
|
||||
switch (reason) {
|
||||
case BLASTER_UNSET:
|
||||
fprintf(stderr, "ERROR: In SB mode but BLASTER environment variable is not set!\n");
|
||||
err_blaster_format_help();
|
||||
fprintf(stderr, "Then run pgusinit /sbenv to apply the BLASTER settings to the card.\n");
|
||||
break;
|
||||
case BLASTER_MALFORMED:
|
||||
fprintf(stderr, "ERROR: BLASTER environment variable is malformed!\n");
|
||||
fprintf(stderr, "Current value: BLASTER=%s\n", getenv("BLASTER"));
|
||||
err_blaster_format_help();
|
||||
break;
|
||||
case BLASTER_DMA16_MISMATCH:
|
||||
fprintf(stderr, "ERROR: In SB 16 mode, low (Dx) and high (Hx) DMA in BLASTER variable must match!\n");
|
||||
fprintf(stderr, "Current value: BLASTER=%s\n", getenv("BLASTER"));
|
||||
break;
|
||||
case BLASTER_MISMATCH:
|
||||
fprintf(stderr, "ERROR: SB settings on card don't match the BLASTER environment variable!\n");
|
||||
fprintf(stderr, "Double-check that PicoGUS is jumpered correctly for the desired IRQ and DMA,\n");
|
||||
fprintf(stderr, "then run pgusinit /sbenv to set card resources from the BLASTER variable.\n");
|
||||
fprintf(stderr, "Alternatively, use /sbport, /sbirq, /sbdma, /sbtype to set values directly.\n");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void err_pigus(void)
|
||||
@@ -278,7 +303,7 @@ static int init_sb(void)
|
||||
|
||||
char* blaster = getenv("BLASTER");
|
||||
if (blaster == NULL) {
|
||||
err_blaster();
|
||||
err_blaster(BLASTER_UNSET);
|
||||
return 1;
|
||||
}
|
||||
char blasterTemp[256];
|
||||
@@ -299,8 +324,12 @@ static int init_sb(void)
|
||||
p = strtok(NULL, " ");
|
||||
}
|
||||
|
||||
if ((port == -1) || (irq == -1) || (dma8 == -1) || (sbtype > 6) || (dspver[sbtype] == 0) || ((sbtype == 6) && (dma8 != dma16))) {
|
||||
err_blaster();
|
||||
if ((port == -1) || (irq == -1) || (dma8 == -1) || (sbtype > 6) || (dspver[sbtype] == 0)) {
|
||||
err_blaster(BLASTER_MALFORMED);
|
||||
return 2;
|
||||
}
|
||||
if ((sbtype == 6) && (dma8 != dma16)) {
|
||||
err_blaster(BLASTER_DMA16_MISMATCH);
|
||||
return 2;
|
||||
}
|
||||
|
||||
@@ -322,28 +351,28 @@ static int init_sb(void)
|
||||
outp(CONTROL_PORT, CMD_SBPORT); // Select port register
|
||||
uint16_t tmp_port = inpw(DATA_PORT_LOW);
|
||||
if (port != tmp_port) {
|
||||
err_blaster();
|
||||
err_blaster(BLASTER_MISMATCH);
|
||||
return 2;
|
||||
}
|
||||
|
||||
outp(CONTROL_PORT, CMD_SBIRQ); // Select IRQ register
|
||||
uint8_t tmp_irq = inp(DATA_PORT_HIGH);
|
||||
if (irq != tmp_irq) {
|
||||
err_blaster();
|
||||
err_blaster(BLASTER_MISMATCH);
|
||||
return 2;
|
||||
}
|
||||
|
||||
outp(CONTROL_PORT, CMD_SBDMA); // Select DMA register
|
||||
uint8_t tmp_dma = inp(DATA_PORT_HIGH);
|
||||
if (dma8 != tmp_dma) {
|
||||
err_blaster();
|
||||
err_blaster(BLASTER_MISMATCH);
|
||||
return 2;
|
||||
}
|
||||
|
||||
outp(CONTROL_PORT, CMD_SBTYPE); // Select SB type register
|
||||
uint8_t tmp_type = inp(DATA_PORT_HIGH);
|
||||
if (sbtype != tmp_type) {
|
||||
err_blaster();
|
||||
err_blaster(BLASTER_MISMATCH);
|
||||
return 2;
|
||||
}
|
||||
}
|
||||
@@ -461,6 +490,7 @@ static int wait_for_cd_load(void)
|
||||
print_string(CMD_CDERROR);
|
||||
return 98;
|
||||
}
|
||||
return print_cdimage_current();
|
||||
}
|
||||
|
||||
|
||||
@@ -631,7 +661,7 @@ static int write_firmware(const char* fw_filename)
|
||||
for (uint16_t b = 0; b < 512; ++b) {
|
||||
// Write firmware byte
|
||||
outp(DATA_PORT_HIGH, uf2_buf.buf[b]);
|
||||
if (b == 512 && protocol == 1) {
|
||||
if (b == 511 && protocol == 1) {
|
||||
// Protocol 1 abuses IOCHRDY to pause during flash erase/write. Some chipsets give
|
||||
// up waiting on IOCHRDY and release the ISA bus after a certain amount of time before
|
||||
// the flash operation is finished. This is an extra delay to work around this issue.
|
||||
@@ -682,7 +712,7 @@ static void wifi_printStatus(void)
|
||||
uint16_t try = 0;
|
||||
char c;
|
||||
while (c = inp(DATA_PORT_HIGH)) {
|
||||
if (c == 255) {
|
||||
if ((unsigned char)c == 255) {
|
||||
if (++try == 10000) {
|
||||
printf("Error getting WiFI status\n");
|
||||
break;
|
||||
@@ -772,7 +802,7 @@ static bool cmdSetMode(const char* arg, const int cmd, const int cmd2, const int
|
||||
return true;
|
||||
}
|
||||
}
|
||||
fprintf(stderr, "Invalid mode %s. Valid modes: gus, sb, mpu, psg, adlib, usb\n");
|
||||
fprintf(stderr, "Invalid mode %s. Valid modes: gus, sb, mpu, psg, adlib, usb\n", arg);
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -859,7 +889,9 @@ static bool cmdSendPort(const char* arg, const int cmd, const int cmd2, const in
|
||||
|
||||
static bool cmdDefaults(const char* arg, const int cmd, const int cmd2, const int cmd3)
|
||||
{
|
||||
return cmdSendUint8(CMD_DEFAULTS, 0xff, 0, 0);
|
||||
outp(CONTROL_PORT, CMD_DEFAULTS);
|
||||
outp(DATA_PORT_HIGH, 0xff);
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool cmdSetVol(const char* arg, const int cmd, const int cmd2, const int cmd3)
|
||||
@@ -1081,16 +1113,15 @@ int parseCommand(int argc, char* argv[], int* i, ParseCommand commands[])
|
||||
} else {
|
||||
printf("\n");
|
||||
}
|
||||
return retVal;
|
||||
return retVal;
|
||||
}
|
||||
arg = argv[++(*i)];
|
||||
}
|
||||
|
||||
if (!stricmp(argv[idx + 1], "default")) {
|
||||
if (command->def) {
|
||||
argv[idx + 1] = command->def;
|
||||
} else {
|
||||
return retVal;
|
||||
if (!stricmp(arg, "default")) {
|
||||
if (command->def) {
|
||||
arg = command->def;
|
||||
} else {
|
||||
return retVal;
|
||||
}
|
||||
}
|
||||
}
|
||||
return command->routine(arg, command->cmd, command->cmd2, command->cmd3);
|
||||
|
||||
@@ -1,3 +1,32 @@
|
||||
# v4.1.0
|
||||
|
||||
## Fixes/improvements
|
||||
|
||||
### SB mode
|
||||
|
||||
- Sound Blaster ADPCM playback is now supported (4, 2.6, and 2-bit modes). This allows for sound effects in Duke Nukem 2 without needing to patch the game. Thanks to [Tube Time (@schlae)'s annotated disassembly of the SB DSP firmware](https://github.com/schlae/sb-firmware/tree/master) and [Torsten Stremlau (@TerrySoba)'s VocTool](https://github.com/TerrySoba/VocTool) for an MIT-licensed C implementation to use as a basis.
|
||||
- Sample rates >44100Hz are now supported, for example 45454Hz, the fastest supported by SB16.
|
||||
- SBMIDI is supported in addition to MPU-401 in SB mode.
|
||||
- Fake ADC (recording) is supported. This records garbage data but should help SB16 sound card detection in some OSes.
|
||||
- Fixes bug in passing DMA from BLASTER variable when running pgusinit. Thanks @andreacampanella for the fix in PR #134.
|
||||
- More helpful error messages when the BLASTER variable does not match the port/IRQ/DMA settings stored on the PicoGUS.
|
||||
|
||||
### MPU-401
|
||||
|
||||
- Behavior of the MPU-401 emulation is now much more in line with a real MPU-401: it has a 256 byte ring buffer for MIDI out data, and flow control is done via bit 6 of the status port. Previously, MPU support had no flow control and used a pretty enormous buffer to make up for that. The SRAM savings from the smaller buffer will allow for more PicoGUS features in the future.
|
||||
- Sysex delay is now accurately calculated (we were using microseconds, not milliseconds).
|
||||
- Re-introduces the song change fix for Frederik Pohl's Gateway.
|
||||
|
||||
### CD-ROM
|
||||
|
||||
- Read multiple sectors at a time during CD audio playback. Should help with pops/distortion on marginal USB drives.
|
||||
- Fixes loading .iso images in Win9x w/ MKEPanasonic driver by handling lead-out.
|
||||
- The loaded image is printed after a successful `pgusinit /cdload`.
|
||||
|
||||
### General
|
||||
|
||||
- SRAM usage is saved across the board by completely eliminating debug prints in release builds, as well as eliminating use of sscanf() type functions. These debug prints didn't go anywhere in release builds (since the UART is taken by MIDI out, and USB by joystick), but they still had runtime overhead in calling printf(), etc.
|
||||
|
||||
# v4.0.0
|
||||
|
||||
## New features/changes
|
||||
|
||||
+30
-3
@@ -19,7 +19,7 @@ set(PICO_COPY_TO_RAM 1)
|
||||
include(pico_sdk_import.cmake)
|
||||
|
||||
project(picogus
|
||||
VERSION "4.0.0"
|
||||
VERSION "4.1.0"
|
||||
LANGUAGES C CXX ASM
|
||||
)
|
||||
|
||||
@@ -55,6 +55,8 @@ function(set_linker_script TARGET script)
|
||||
endfunction()
|
||||
|
||||
|
||||
option(PGDEBUG "Enable debug printf framework" OFF)
|
||||
|
||||
# Global definitions across all targets
|
||||
add_compile_definitions(
|
||||
# 370MHz is extremely closely evenly divisible by 44100Hz.
|
||||
@@ -212,15 +214,37 @@ function(config_target TARGET_NAME MULTIFW)
|
||||
)
|
||||
pico_add_extra_outputs(${TARGET_NAME})
|
||||
|
||||
# Determine which stdio drivers are available for this firmware type
|
||||
if (SOUND_MPU)
|
||||
pico_enable_stdio_uart(${TARGET_NAME} 0)
|
||||
else()
|
||||
pico_enable_stdio_uart(${TARGET_NAME} 1)
|
||||
set(HAS_STDIO_UART TRUE)
|
||||
endif()
|
||||
if (USB_STACK)
|
||||
pico_enable_stdio_usb(${TARGET_NAME} 0)
|
||||
else()
|
||||
pico_enable_stdio_usb(${TARGET_NAME} 1)
|
||||
set(HAS_STDIO_USB TRUE)
|
||||
endif()
|
||||
|
||||
if(PGDEBUG AND (HAS_STDIO_UART OR HAS_STDIO_USB))
|
||||
# Debug output is possible: enable available drivers and printf formatter
|
||||
target_compile_definitions(${TARGET_NAME} PRIVATE PGDEBUG=1)
|
||||
target_compile_definitions(rp2040-psram INTERFACE PSRAM_DEBUG=1)
|
||||
if (HAS_STDIO_UART)
|
||||
pico_enable_stdio_uart(${TARGET_NAME} 1)
|
||||
endif()
|
||||
if (HAS_STDIO_USB)
|
||||
pico_enable_stdio_usb(${TARGET_NAME} 1)
|
||||
endif()
|
||||
else()
|
||||
# No debug output possible or not requested: strip printf entirely
|
||||
if (NOT SOUND_MPU)
|
||||
pico_enable_stdio_uart(${TARGET_NAME} 0)
|
||||
endif()
|
||||
if (NOT USB_STACK)
|
||||
pico_enable_stdio_usb(${TARGET_NAME} 0)
|
||||
endif()
|
||||
pico_set_printf_implementation(${TARGET_NAME} none)
|
||||
endif()
|
||||
pico_enable_stdio_semihosting(${TARGET_NAME} 0)
|
||||
endfunction()
|
||||
@@ -638,6 +662,9 @@ if(PROJECT_TYPE STREQUAL "MULTIFW")
|
||||
pico_enable_stdio_uart(bootloader 0)
|
||||
pico_enable_stdio_usb(bootloader 0)
|
||||
pico_enable_stdio_semihosting(bootloader 0)
|
||||
if(NOT PGDEBUG)
|
||||
pico_set_printf_implementation(bootloader none)
|
||||
endif()
|
||||
add_dependencies(bootloader generate_flash_firmware_h)
|
||||
|
||||
if (NOT UF2CREATE_FOUND)
|
||||
|
||||
@@ -18,7 +18,7 @@
|
||||
|
||||
#include <inttypes.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdio.h>
|
||||
#include "../include/pg_debug.h"
|
||||
#include <string.h>
|
||||
#include "system/pico_pic.h"
|
||||
#include "audio/volctrl.h"
|
||||
@@ -191,7 +191,7 @@ static void ad1848_apply_iface(uint8_t iface) {
|
||||
if (!ad1848.play && (iface & 1)) { // start playback
|
||||
ad1848.ppio = (iface & 0x40);
|
||||
ad1848.play = true;
|
||||
printf("start sr %u intvl %u 16b %u st %u bpf %u ct %u ppio %u\n",
|
||||
DBG_PRINTF("start sr %u intvl %u 16b %u st %u bpf %u ct %u ppio %u\n",
|
||||
ad1848.sample_rate, ad1848.frame_interval,
|
||||
ad1848.playback_16bit, ad1848.playback_stereo,
|
||||
ad1848.frame_bytes, ad1848.current_count, ad1848.ppio);
|
||||
@@ -344,8 +344,8 @@ uint32_t ad1848_sample_stereo() {
|
||||
|
||||
|
||||
void ad1848_init() {
|
||||
puts("Initing AD1848...");
|
||||
puts("Initing ISA DMA PIO...");
|
||||
DBG_PUTS("Initing AD1848...");
|
||||
DBG_PUTS("Initing ISA DMA PIO...");
|
||||
AD1848_DMA_isr_pt = ad1848_dma_isr;
|
||||
dma_config = DMA_multi_init(pio0, DMA_PIO_SM, AD1848_DMA_isr_pt);
|
||||
|
||||
|
||||
+4
-16
@@ -1,26 +1,14 @@
|
||||
#include <stdarg.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include "../include/pg_debug.h"
|
||||
#include "86box_compat.h"
|
||||
|
||||
void fatal(const char *fmt, ...) {
|
||||
char temp[1024];
|
||||
va_list ap;
|
||||
char *sp;
|
||||
va_start(ap, fmt);
|
||||
vsprintf(temp, fmt, ap);
|
||||
printf("%s",temp);
|
||||
va_end(ap);
|
||||
ERR_PUTS(fmt);
|
||||
while(1) {
|
||||
}
|
||||
}
|
||||
|
||||
void pclog_ex(const char *fmt, va_list ap){
|
||||
char temp[1024];
|
||||
|
||||
if (strcmp(fmt, "") == 0)
|
||||
return;
|
||||
|
||||
vsprintf(temp, fmt, ap);
|
||||
printf("%s\n\r",temp);
|
||||
(void)fmt;
|
||||
(void)ap;
|
||||
}
|
||||
+111
-107
@@ -21,11 +21,11 @@
|
||||
#include <inttypes.h>
|
||||
#include <stdarg.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <wchar.h>
|
||||
#define HAVE_STDARG_H
|
||||
#include "../include/pg_debug.h"
|
||||
#include "86box_compat.h"
|
||||
#include "cdrom.h"
|
||||
#include "cdrom_image_manager.h"
|
||||
@@ -93,25 +93,8 @@ static uint8_t extra_buffer[296];
|
||||
|
||||
/* int cdrom_interface_current; */
|
||||
|
||||
//#define ENABLE_CDROM_LOG 1
|
||||
|
||||
#ifdef ENABLE_CDROM_LOG
|
||||
int cdrom_do_log = ENABLE_CDROM_LOG;
|
||||
|
||||
void
|
||||
cdrom_log(const char *fmt, ...)
|
||||
{
|
||||
va_list ap;
|
||||
|
||||
if (cdrom_do_log) {
|
||||
va_start(ap, fmt);
|
||||
pclog_ex(fmt, ap);
|
||||
va_end(ap);
|
||||
}
|
||||
}
|
||||
#else
|
||||
# define cdrom_log(fmt, ...)
|
||||
#endif
|
||||
#define PGDEBUG_CDROM 0
|
||||
#define cdrom_log(fmt, ...) do { if (PGDEBUG_CDROM) DBG_PRINTF(fmt "\n", ##__VA_ARGS__); } while(0)
|
||||
|
||||
/*
|
||||
static __inline int
|
||||
@@ -152,17 +135,17 @@ void cdrom_tasks(cdrom_t *dev) {
|
||||
cdman_load_image_index(dev, dev->image_data);
|
||||
break;
|
||||
case CD_COMMAND_IMAGE_LOAD:
|
||||
printf("loading");
|
||||
DBG_PRINTF("loading");
|
||||
cdrom_errorstr_clear();
|
||||
if (dev->disk_loaded) {
|
||||
dev->disk_loaded = 0;
|
||||
dev->media_changed = 1;
|
||||
cdrom_image_close(dev);
|
||||
printf("Disk Removed.\n");
|
||||
DBG_PRINTF("Disk Removed.\n");
|
||||
cdrom_error(dev, 0x11); //media changed
|
||||
}
|
||||
if (dev->image_path[0]) {
|
||||
printf("Opening %s...",dev->image_path);
|
||||
DBG_PRINTF("Opening %s...",dev->image_path);
|
||||
if (cdrom_image_open(dev,dev->image_path)) {
|
||||
dev->image_command = CD_COMMAND_NONE;
|
||||
dev->image_status = CD_STATUS_ERROR;
|
||||
@@ -171,7 +154,7 @@ void cdrom_tasks(cdrom_t *dev) {
|
||||
} else {
|
||||
cdman_set_image_index(dev);
|
||||
}
|
||||
printf("Done.\n");
|
||||
DBG_PRINTF("Done.\n");
|
||||
dev->disk_loaded = 1;
|
||||
dev->media_changed = 1;
|
||||
cdrom_error(dev, 0x11); //media changed
|
||||
@@ -227,7 +210,7 @@ uint16_t __inline cdrom_fifo_level(cdrom_fifo_t *fifo) {
|
||||
uint8_t cdrom_fifo_read(cdrom_fifo_t *fifo) {
|
||||
uint8_t x;
|
||||
if(!cdrom_fifo_level(fifo)) {
|
||||
printf("FIFO UNDERRUN(%p)\n",fifo);
|
||||
DBG_PRINTF("FIFO UNDERRUN(%p)\n",fifo);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -238,7 +221,7 @@ uint8_t cdrom_fifo_read(cdrom_fifo_t *fifo) {
|
||||
}
|
||||
void cdrom_fifo_clear(cdrom_fifo_t *fifo) {
|
||||
if(cdrom_fifo_level(fifo)) {
|
||||
printf("*** DISCARD %u *** (%p)\n",cdrom_fifo_level(fifo),fifo);
|
||||
DBG_PRINTF("*** DISCARD %u *** (%p)\n",cdrom_fifo_level(fifo),fifo);
|
||||
fifo->tail = fifo->head;
|
||||
}
|
||||
}
|
||||
@@ -249,6 +232,9 @@ cdrom_stop(cdrom_t *dev)
|
||||
{
|
||||
if (dev->cd_status > CD_STATUS_DATA_ONLY)
|
||||
dev->cd_status = CD_STATUS_STOPPED;
|
||||
dev->audio_staging_sectors = 0;
|
||||
dev->audio_staging_index = 0;
|
||||
dev->audio_sector_consumed_pairs = 0;
|
||||
#if USE_CD_AUDIO_FIFO
|
||||
fifo_reset(&dev->audio_fifo);
|
||||
#endif
|
||||
@@ -281,71 +267,75 @@ bool cdrom_audio_callback(cdrom_t *dev, uint32_t len) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// --- Fill audio_fifo using data from audio_sector_buffer, reading new sectors as needed ---
|
||||
// Loop until FIFO has 'len' stereo pairs, or is full, or an error/EoT occurs.
|
||||
// --- Fill audio_fifo from staging buffer, batch-reading new sectors as needed ---
|
||||
while (fifo_level(&dev->audio_fifo) < len && ret) {
|
||||
uint32_t pairs_remaining_in_sector = STEREO_SAMPLES_PER_SECTOR - dev->audio_sector_consumed_pairs;
|
||||
// Advance to next sector in batch if current one is fully consumed
|
||||
if (dev->audio_sector_consumed_pairs >= STEREO_SAMPLES_PER_SECTOR) {
|
||||
dev->audio_staging_index++;
|
||||
dev->audio_sector_consumed_pairs = 0;
|
||||
}
|
||||
|
||||
if (pairs_remaining_in_sector == 0) { // Need to read a new sector
|
||||
if (dev->seek_pos < dev->cd_end) {
|
||||
bool read_successful;
|
||||
if (dev->audio_muted_soft) {
|
||||
// Muted: "Fake" a read by filling the sector buffer with silence
|
||||
cdrom_log("CD-ROM %i: Muted. Faking read of LBA %08X with silence.\n", dev->id, dev->seek_pos);
|
||||
read_successful = true;
|
||||
memset(dev->audio_sector_buffer, 0, RAW_SECTOR_SIZE);
|
||||
} else {
|
||||
read_successful = dev->ops->read_sector(dev, CD_READ_AUDIO, dev->audio_sector_buffer, dev->seek_pos);
|
||||
}
|
||||
if (read_successful) {
|
||||
/* putchar('r'); */
|
||||
cdrom_log("CD-ROM %i: Read LBA %08X successful\n", dev->id, dev->seek_pos);
|
||||
dev->seek_pos++;
|
||||
dev->audio_sector_consumed_pairs = 0;
|
||||
pairs_remaining_in_sector = STEREO_SAMPLES_PER_SECTOR; // Update for current iteration
|
||||
} else {
|
||||
cdrom_log("CD-ROM %i: Read LBA %08X failed\n", dev->id, dev->seek_pos);
|
||||
dev->cd_status = CD_STATUS_STOPPED;
|
||||
ret = false; // Mark error
|
||||
break; // Exit fill loop: read error
|
||||
}
|
||||
} else { // End of disc
|
||||
// Read a new batch when the staging buffer is exhausted
|
||||
if (dev->audio_staging_index >= dev->audio_staging_sectors) {
|
||||
if (dev->seek_pos >= dev->cd_end) {
|
||||
cdrom_log("CD-ROM %i: Playing completed (reached cd_end)\n", dev->id);
|
||||
dev->cd_status = CD_STATUS_PLAYING_COMPLETED;
|
||||
ret = false; // Mark end of track
|
||||
break; // Exit fill loop: end of track
|
||||
ret = false;
|
||||
break;
|
||||
}
|
||||
|
||||
uint32_t avail = dev->cd_end - dev->seek_pos;
|
||||
uint32_t batch = (avail < AUDIO_SECTOR_BATCH) ? avail : AUDIO_SECTOR_BATCH;
|
||||
int sectors_read;
|
||||
|
||||
if (dev->audio_muted_soft) {
|
||||
cdrom_log("CD-ROM %i: Muted. Faking batch read of %u sectors with silence.\n", dev->id, batch);
|
||||
memset(dev->audio_sector_buffer, 0, batch * RAW_SECTOR_SIZE);
|
||||
sectors_read = batch;
|
||||
} else {
|
||||
sectors_read = dev->ops->read_audio_sectors(dev, dev->audio_sector_buffer, dev->seek_pos, batch);
|
||||
}
|
||||
|
||||
if (sectors_read > 0) {
|
||||
cdrom_log("CD-ROM %i: Batch read %u sectors at LBA %08X\n", dev->id, sectors_read, dev->seek_pos);
|
||||
dev->seek_pos += sectors_read;
|
||||
dev->audio_staging_sectors = sectors_read;
|
||||
dev->audio_staging_index = 0;
|
||||
dev->audio_sector_consumed_pairs = 0;
|
||||
} else {
|
||||
cdrom_log("CD-ROM %i: Batch read at LBA %08X failed\n", dev->id, dev->seek_pos);
|
||||
dev->cd_status = CD_STATUS_STOPPED;
|
||||
ret = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// At this point, if ret is still true, pairs_remaining_in_sector should be > 0.
|
||||
// Point into the current sector within the staging buffer
|
||||
dev->current_sector_samples = (sample_pair *)(dev->audio_sector_buffer
|
||||
+ dev->audio_staging_index * RAW_SECTOR_SIZE);
|
||||
|
||||
uint32_t pairs_remaining = STEREO_SAMPLES_PER_SECTOR - dev->audio_sector_consumed_pairs;
|
||||
uint32_t space_in_fifo = fifo_free_space(&dev->audio_fifo);
|
||||
uint32_t pairs_to_transfer = (pairs_remaining < space_in_fifo) ?
|
||||
pairs_remaining : space_in_fifo;
|
||||
|
||||
// Determine how many stereo pairs to transfer from staging to FIFO
|
||||
uint32_t pairs_to_transfer = (pairs_remaining_in_sector < space_in_fifo) ?
|
||||
pairs_remaining_in_sector : space_in_fifo;
|
||||
|
||||
/* printf("%u\n", pairs_to_transfer); */
|
||||
// Add stereo pairs from sector buffer to FIFO
|
||||
bool added_ok = fifo_add_samples(&dev->audio_fifo,
|
||||
&dev->current_sector_samples[dev->audio_sector_consumed_pairs],
|
||||
pairs_to_transfer);
|
||||
if (added_ok) {
|
||||
/* putchar('y'); */
|
||||
dev->audio_sector_consumed_pairs += pairs_to_transfer;
|
||||
} else {
|
||||
putchar('n');
|
||||
// This implies fifo_add_samples failed even though we thought there was space.
|
||||
// Could be a bug in fifo_free_space or fifo_add_samples, or a race condition in a threaded env (not here).
|
||||
DBG_PUTCHAR('n');
|
||||
cdrom_log("CD-ROM %i: fifo_add_samples failed unexpectedly! Space was %u, tried to add %u.\n",
|
||||
dev->id, space_in_fifo, pairs_to_transfer);
|
||||
ret = false; // Treat as an error
|
||||
ret = false;
|
||||
break;
|
||||
}
|
||||
} // End while (fifo_level < len && ret)
|
||||
}
|
||||
|
||||
cdrom_log("CD-ROM %i: Audio cb. FIFO level: %u. Staging consumed: %d. Ret %d\n",
|
||||
cdrom_log("CD-ROM %i: Audio cb. FIFO level: %u. Staging consumed: %d/%d. Ret %d\n",
|
||||
dev->id, fifo_level(&dev->audio_fifo),
|
||||
dev->audio_sector_consumed_pairs, ret);
|
||||
dev->audio_staging_index, dev->audio_staging_sectors, ret);
|
||||
return ret;
|
||||
}
|
||||
#endif // USE_CD_AUDIO_FIFO
|
||||
@@ -357,49 +347,56 @@ uint32_t cdrom_audio_callback_simple(cdrom_t *dev, int16_t *buffer, uint32_t len
|
||||
|
||||
uint32_t pairs_produced = 0;
|
||||
uint32_t pairs_requested = len / 2;
|
||||
// --- Fill buffer using data from audio_sector_buffer, reading new sectors as needed ---
|
||||
// Loop until buffer has 'len' samples, or an error/EoT occurs.
|
||||
// --- Fill buffer from staging buffer, batch-reading new sectors as needed ---
|
||||
while (pairs_produced < pairs_requested) {
|
||||
uint32_t pairs_remaining_in_sector = STEREO_SAMPLES_PER_SECTOR - dev->audio_sector_consumed_pairs;
|
||||
// Advance to next sector in batch if current one is fully consumed
|
||||
if (dev->audio_sector_consumed_pairs >= STEREO_SAMPLES_PER_SECTOR) {
|
||||
dev->audio_staging_index++;
|
||||
dev->audio_sector_consumed_pairs = 0;
|
||||
}
|
||||
|
||||
if (pairs_remaining_in_sector == 0) { // Need to read a new sector
|
||||
if (dev->seek_pos < dev->cd_end) {
|
||||
bool read_successful;
|
||||
if (dev->audio_muted_soft) {
|
||||
// Muted: "Fake" a read by filling the sector buffer with silence
|
||||
cdrom_log("CD-ROM %i: Muted. Faking read of LBA %08X with silence.\n", dev->id, dev->seek_pos);
|
||||
read_successful = true;
|
||||
memset(dev->audio_sector_buffer, 0, RAW_SECTOR_SIZE);
|
||||
} else {
|
||||
read_successful = dev->ops->read_sector(dev, CD_READ_AUDIO, dev->audio_sector_buffer, dev->seek_pos);
|
||||
}
|
||||
if (read_successful) {
|
||||
/* putchar('r'); */
|
||||
cdrom_log("CD-ROM %i: Read LBA %08X successful\n", dev->id, dev->seek_pos);
|
||||
dev->seek_pos++;
|
||||
dev->audio_sector_consumed_pairs = 0;
|
||||
pairs_remaining_in_sector = STEREO_SAMPLES_PER_SECTOR; // Update for current iteration
|
||||
} else {
|
||||
cdrom_log("CD-ROM %i: Read LBA %08X failed\n", dev->id, dev->seek_pos);
|
||||
dev->cd_status = CD_STATUS_STOPPED;
|
||||
break; // Exit fill loop: read error
|
||||
}
|
||||
} else { // End of disc
|
||||
// Read a new batch when the staging buffer is exhausted
|
||||
if (dev->audio_staging_index >= dev->audio_staging_sectors) {
|
||||
if (dev->seek_pos >= dev->cd_end) {
|
||||
cdrom_log("CD-ROM %i: Playing completed (reached cd_end)\n", dev->id);
|
||||
dev->cd_status = CD_STATUS_PLAYING_COMPLETED;
|
||||
break; // Exit fill loop: end of track
|
||||
break;
|
||||
}
|
||||
|
||||
uint32_t avail = dev->cd_end - dev->seek_pos;
|
||||
uint32_t batch = (avail < AUDIO_SECTOR_BATCH) ? avail : AUDIO_SECTOR_BATCH;
|
||||
int sectors_read;
|
||||
|
||||
if (dev->audio_muted_soft) {
|
||||
cdrom_log("CD-ROM %i: Muted. Faking batch read of %u sectors with silence.\n", dev->id, batch);
|
||||
memset(dev->audio_sector_buffer, 0, batch * RAW_SECTOR_SIZE);
|
||||
sectors_read = batch;
|
||||
} else {
|
||||
sectors_read = dev->ops->read_audio_sectors(dev, dev->audio_sector_buffer, dev->seek_pos, batch);
|
||||
}
|
||||
|
||||
if (sectors_read > 0) {
|
||||
cdrom_log("CD-ROM %i: Batch read %u sectors at LBA %08X\n", dev->id, sectors_read, dev->seek_pos);
|
||||
dev->seek_pos += sectors_read;
|
||||
dev->audio_staging_sectors = sectors_read;
|
||||
dev->audio_staging_index = 0;
|
||||
dev->audio_sector_consumed_pairs = 0;
|
||||
} else {
|
||||
cdrom_log("CD-ROM %i: Batch read at LBA %08X failed\n", dev->id, dev->seek_pos);
|
||||
dev->cd_status = CD_STATUS_STOPPED;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// At this point, pairs_remaining_in_sector should be > 0.
|
||||
// Point into the current sector within the staging buffer
|
||||
dev->current_sector_samples = (sample_pair *)(dev->audio_sector_buffer
|
||||
+ dev->audio_staging_index * RAW_SECTOR_SIZE);
|
||||
|
||||
uint32_t pairs_remaining = STEREO_SAMPLES_PER_SECTOR - dev->audio_sector_consumed_pairs;
|
||||
uint32_t space_in_buffer = pairs_requested - pairs_produced;
|
||||
// Determine how many stereo pairs to transfer from staging to buffer
|
||||
uint32_t pairs_to_transfer = (pairs_remaining_in_sector < space_in_buffer) ?
|
||||
pairs_remaining_in_sector : space_in_buffer;
|
||||
uint32_t pairs_to_transfer = (pairs_remaining < space_in_buffer) ?
|
||||
pairs_remaining : space_in_buffer;
|
||||
|
||||
/* printf("%u\n", pairs_to_transfer); */
|
||||
// Add samples from sector buffer to output buffer
|
||||
//memcpy(buffer + pairs_produced * 2, &dev->current_sector_samples[dev->audio_sector_consumed_pairs], pairs_to_transfer * sizeof(sample_pair));
|
||||
for (uint32_t i = 0; i < pairs_to_transfer; i++)
|
||||
{
|
||||
sample_pair sp = dev->current_sector_samples[dev->audio_sector_consumed_pairs + i];
|
||||
@@ -501,7 +498,7 @@ uint8_t cdrom_audio_playmsf(cdrom_t *dev, int m,int s, int f, int M, int S, int
|
||||
pos2 = MSFtoLBA(M,S,F) - 150;
|
||||
|
||||
if (!(dev->ops->track_type(dev, pos) & CD_TRACK_AUDIO)) {
|
||||
printf("CD-ROM %i: LBA %08X not on an audio track\n", dev->id, pos);
|
||||
DBG_PRINTF("CD-ROM %i: LBA %08X not on an audio track\n", dev->id, pos);
|
||||
cdrom_log("CD-ROM %i: LBA %08X not on an audio track\n", dev->id, pos);
|
||||
cdrom_error(dev,0x0E);
|
||||
cdrom_error(dev,0x10);
|
||||
@@ -516,6 +513,9 @@ uint8_t cdrom_audio_playmsf(cdrom_t *dev, int m,int s, int f, int M, int S, int
|
||||
|
||||
dev->seek_pos = pos;
|
||||
dev->cd_end = pos2;
|
||||
dev->audio_staging_sectors = 0;
|
||||
dev->audio_staging_index = 0;
|
||||
dev->audio_sector_consumed_pairs = 0;
|
||||
#if USE_CD_AUDIO_FIFO
|
||||
fifo_reset(&dev->audio_fifo);
|
||||
#endif
|
||||
@@ -582,8 +582,12 @@ uint8_t cdrom_read_toc(cdrom_t *dev, unsigned char *b, uint8_t track) {
|
||||
track_info_t ti;
|
||||
int first_track;
|
||||
int last_track;
|
||||
dev->ops->get_tracks(dev, &first_track, &last_track);
|
||||
if(track > last_track) return 0;
|
||||
dev->ops->get_tracks(dev, &first_track, &last_track);
|
||||
// Handle lead-out track
|
||||
if (track == 0xaa)
|
||||
track = last_track + 1;
|
||||
else if (track > last_track)
|
||||
return 0;
|
||||
dev->ops->get_track_info(dev, track, 0, &ti);
|
||||
b[0]=0x0;
|
||||
b[1]=ti.attr;
|
||||
|
||||
+11
-3
@@ -57,6 +57,11 @@
|
||||
#define SAMPLES_PER_SECTOR 1176
|
||||
#define STEREO_SAMPLES_PER_SECTOR 588
|
||||
|
||||
/* number of CD sectors to read at once. Larger values reduce USB command
|
||||
* overhead (one SCSI READ10 instead of N) hopefully helping marginal USB drives
|
||||
* keep up with 44.1 kHz audio. */
|
||||
#define AUDIO_SECTOR_BATCH 4
|
||||
|
||||
#define STAT_READY 0x01
|
||||
#define STAT_PLAY 0x08
|
||||
#define STAT_ERROR 0x10
|
||||
@@ -123,6 +128,7 @@ typedef struct cdrom_ops_t {
|
||||
int (*is_track_pre)(struct cdrom *dev, uint32_t lba);
|
||||
int (*sector_size)(struct cdrom *dev, uint32_t lba);
|
||||
int (*read_sector)(struct cdrom *dev, int type, uint8_t *b, uint32_t lba);
|
||||
int (*read_audio_sectors)(struct cdrom *dev, uint8_t *b, uint32_t lba, uint32_t count);
|
||||
int (*track_type)(struct cdrom *dev, uint32_t lba);
|
||||
void (*exit)(struct cdrom *dev);
|
||||
} cdrom_ops_t;
|
||||
@@ -196,9 +202,11 @@ typedef struct cdrom {
|
||||
const char *error_str;
|
||||
|
||||
// int16_t cd_buffer[BUF_SIZE];
|
||||
uint8_t audio_sector_buffer[RAW_SECTOR_SIZE];
|
||||
sample_pair *current_sector_samples; // Convenience pointer: (sample_pair*)audio_sector_buffer
|
||||
int audio_sector_consumed_pairs; // Stereo pairs consumed from current_sector_samples
|
||||
uint8_t audio_sector_buffer[AUDIO_SECTOR_BATCH * RAW_SECTOR_SIZE];
|
||||
sample_pair *current_sector_samples; // Points to current sector's audio data within staging buffer
|
||||
int audio_sector_consumed_pairs; // Stereo pairs consumed from current sector (0..588)
|
||||
int audio_staging_sectors; // Number of sectors loaded in staging buffer
|
||||
int audio_staging_index; // Which sector in the batch is being consumed
|
||||
|
||||
#if USE_CD_AUDIO_FIFO
|
||||
audio_fifo_t audio_fifo;
|
||||
|
||||
@@ -1,15 +1,32 @@
|
||||
#include "cdrom_error_msg.h"
|
||||
|
||||
#include <stdarg.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
static char _error[256];
|
||||
|
||||
/* Minimal vsnprintf that only handles %s — all cdrom_errorstr_set callers use %s exclusively. */
|
||||
static void simple_fmt(char *buf, size_t n, const char *fmt, va_list ap) {
|
||||
size_t pos = 0;
|
||||
while (*fmt && pos < n - 1) {
|
||||
if (fmt[0] == '%' && fmt[1] == 's') {
|
||||
const char *s = va_arg(ap, const char *);
|
||||
if (s) {
|
||||
while (*s && pos < n - 1)
|
||||
buf[pos++] = *s++;
|
||||
}
|
||||
fmt += 2;
|
||||
} else {
|
||||
buf[pos++] = *fmt++;
|
||||
}
|
||||
}
|
||||
buf[pos] = '\0';
|
||||
}
|
||||
|
||||
void cdrom_errorstr_set(const char *fmt, ...) {
|
||||
va_list ap;
|
||||
va_start(ap, fmt);
|
||||
vsnprintf(_error, 256, fmt, ap);
|
||||
/* printf("setting cdrom error: %s\n", _error); */
|
||||
simple_fmt(_error, sizeof(_error), fmt, ap);
|
||||
va_end(ap);
|
||||
}
|
||||
|
||||
|
||||
+11
-20
@@ -24,36 +24,19 @@
|
||||
*/
|
||||
#include <inttypes.h>
|
||||
#include <stdarg.h>
|
||||
#include <stdio.h>
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <wchar.h>
|
||||
#define HAVE_STDARG_H
|
||||
|
||||
#include "../include/pg_debug.h"
|
||||
#include "cdrom_image_backend.h"
|
||||
#include "cdrom.h"
|
||||
#include "86box_compat.h"
|
||||
|
||||
//#define ENABLE_CDROM_IMAGE_LOG 1
|
||||
|
||||
#ifdef ENABLE_CDROM_IMAGE_LOG
|
||||
int cdrom_image_do_log = ENABLE_CDROM_IMAGE_LOG;
|
||||
|
||||
void
|
||||
cdrom_image_log(const char *fmt, ...)
|
||||
{
|
||||
va_list ap;
|
||||
|
||||
if (cdrom_image_do_log) {
|
||||
va_start(ap, fmt);
|
||||
pclog_ex(fmt, ap);
|
||||
va_end(ap);
|
||||
}
|
||||
}
|
||||
#else
|
||||
# define cdrom_image_log(fmt, ...)
|
||||
#endif
|
||||
#define PGDEBUG_CDROM_IMAGE 0
|
||||
#define cdrom_image_log(fmt, ...) do { if (PGDEBUG_CDROM_IMAGE) DBG_PRINTF(fmt "\n", ##__VA_ARGS__); } while(0)
|
||||
|
||||
/* The addresses sent from the guest are absolute, ie. a LBA of 0 corresponds to a MSF of 00:00:00. Otherwise, the counter displayed by the guest is wrong:
|
||||
there is a seeming 2 seconds in which audio plays but counter does not move, while a data track before audio jumps to 2 seconds before the actual start
|
||||
@@ -193,6 +176,13 @@ image_read_sector(struct cdrom *dev, int type, uint8_t *b, uint32_t lba)
|
||||
}
|
||||
}
|
||||
|
||||
static int
|
||||
image_read_audio_sectors(struct cdrom *dev, uint8_t *b, uint32_t lba, uint32_t count)
|
||||
{
|
||||
cd_img_t *img = (cd_img_t *) dev->image;
|
||||
return cdi_read_audio_sectors(img, b, lba, count);
|
||||
}
|
||||
|
||||
static int
|
||||
image_track_type(cdrom_t *dev, uint32_t lba)
|
||||
{
|
||||
@@ -233,6 +223,7 @@ static const cdrom_ops_t cdrom_image_ops = {
|
||||
image_is_track_pre,
|
||||
image_sector_size,
|
||||
image_read_sector,
|
||||
image_read_audio_sectors,
|
||||
image_track_type,
|
||||
image_exit
|
||||
};
|
||||
|
||||
@@ -24,7 +24,6 @@
|
||||
#include <inttypes.h>
|
||||
#include <stdarg.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <sys/stat.h>
|
||||
@@ -35,6 +34,7 @@
|
||||
# include <libgen.h>
|
||||
#endif
|
||||
#define HAVE_STDARG_H
|
||||
#include "../include/pg_debug.h"
|
||||
#include "cdrom_image_backend.h"
|
||||
#include "cdrom_error_msg.h"
|
||||
#include "86box_compat.h"
|
||||
@@ -77,33 +77,8 @@ static inline void frames_to_msf(uint32_t total_frames, uint8_t *pM, uint8_t *pS
|
||||
|
||||
static char temp_keyword[64];
|
||||
|
||||
#ifdef ENABLE_CDROM_IMAGE_BACKEND_LOG
|
||||
int cdrom_image_backend_do_log = ENABLE_CDROM_IMAGE_BACKEND_LOG;
|
||||
|
||||
void cdrom_image_backend_log(const char *fmt, ...) {
|
||||
char temp[1024];
|
||||
va_list ap;
|
||||
char *sp;
|
||||
va_start(ap, fmt);
|
||||
vsprintf(temp, fmt, ap);
|
||||
printf("%s\n\r",temp);
|
||||
va_end(ap);
|
||||
}
|
||||
/*
|
||||
cdrom_image_backend_log(const char *fmt, ...)
|
||||
{
|
||||
va_list ap;
|
||||
|
||||
if (cdrom_image_backend_do_log) {
|
||||
va_start(ap, fmt);
|
||||
pclog_ex(fmt, ap);
|
||||
va_end(ap);
|
||||
}
|
||||
}
|
||||
*/
|
||||
#else
|
||||
# define cdrom_image_backend_log(fmt, ...)
|
||||
#endif
|
||||
#define PGDEBUG_CDROM_BACKEND 0
|
||||
#define cdrom_image_backend_log(fmt, ...) do { if (PGDEBUG_CDROM_BACKEND) DBG_PRINTF(fmt "\n", ##__VA_ARGS__); } while(0)
|
||||
|
||||
/* #include "pico/stdlib.h" */
|
||||
/* extern uint LED_PIN; */
|
||||
@@ -123,17 +98,13 @@ bin_read(void *priv, uint8_t *buffer, uint32_t seek, size_t count)
|
||||
return 0;
|
||||
//if (fseeko64(tf->fp, seek, SEEK_SET) == -1) {
|
||||
if (f_lseek(tf->fp, seek) != FR_OK) {
|
||||
#ifdef ENABLE_CDROM_IMAGE_BACKEND_LOG
|
||||
cdrom_image_backend_log("CDROM: binary_read failed during seek!\n");
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
||||
//if (fread(buffer, count, 1, tf->fp) != 1) {
|
||||
if (f_read(tf->fp,buffer, count,&bytes_read) != FR_OK) {
|
||||
#ifdef ENABLE_CDROM_IMAGE_BACKEND_LOG
|
||||
if (f_read(tf->fp,buffer, count,&bytes_read) != FR_OK || bytes_read != count) {
|
||||
cdrom_image_backend_log("CDROM: binary_read failed during read!\n");
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
/* gpio_xor_mask(LED_PIN); */
|
||||
@@ -513,6 +484,31 @@ cdi_read_sectors(cd_img_t *cdi, uint8_t *buffer, int raw, uint32_t sector, uint3
|
||||
return success;
|
||||
}
|
||||
|
||||
/* Batch read consecutive audio sectors in a single file I/O. Returns the number
|
||||
of sectors read, 0 on error. Clips to track boundary so the caller may get
|
||||
fewer than requested. */
|
||||
int
|
||||
cdi_read_audio_sectors(cd_img_t *cdi, uint8_t *buffer, uint32_t sector, uint32_t num)
|
||||
{
|
||||
int track = cdi_get_track(cdi, sector) - 1;
|
||||
if (track < 0 || num == 0)
|
||||
return 0;
|
||||
|
||||
track_t *trk = &cdi->tracks[track];
|
||||
|
||||
/* clip to track boundary */
|
||||
uint32_t track_end = trk->start + trk->length;
|
||||
if (sector + num > track_end)
|
||||
num = track_end - sector;
|
||||
if (num == 0)
|
||||
return 0;
|
||||
|
||||
uint32_t seek = trk->skip + ((sector - trk->start) * trk->sector_size);
|
||||
if (!trk->file->read(trk->file, buffer, seek, num * trk->sector_size))
|
||||
return 0;
|
||||
return (int) num;
|
||||
}
|
||||
|
||||
/* TODO: Do CUE+BIN images with a sector size of 2448 even exist? */
|
||||
int
|
||||
cdi_read_sector_sub(cd_img_t *cdi, uint8_t *buffer, uint32_t sector)
|
||||
@@ -746,8 +742,9 @@ cdi_cue_get_number(char **line)
|
||||
if (!cdi_cue_get_buffer(temp, line, 0))
|
||||
return 0;
|
||||
|
||||
/* if (sscanf(temp, "%" PRIu64, &num) != 1) */
|
||||
if (sscanf(temp, "%" PRIu32, &num) != 1)
|
||||
char *end;
|
||||
num = (uint32_t)strtoul(temp, &end, 10);
|
||||
if (end == temp)
|
||||
return 0;
|
||||
|
||||
return num;
|
||||
@@ -767,9 +764,18 @@ cdi_cue_get_frame(uint32_t *frames, char **line)
|
||||
if (!success)
|
||||
return 0;
|
||||
|
||||
success = sscanf(temp, "%d:%d:%d", &min, &sec, &fr) == 3;
|
||||
if (!success)
|
||||
return 0;
|
||||
{
|
||||
char *p = temp;
|
||||
char *end;
|
||||
min = (int)strtol(p, &end, 10);
|
||||
if (*end != ':') return 0;
|
||||
p = end + 1;
|
||||
sec = (int)strtol(p, &end, 10);
|
||||
if (*end != ':') return 0;
|
||||
p = end + 1;
|
||||
fr = (int)strtol(p, &end, 10);
|
||||
if (end == p) return 0;
|
||||
}
|
||||
|
||||
*frames = MSF_TO_FRAMES(min, sec, fr);
|
||||
|
||||
|
||||
@@ -106,6 +106,7 @@ extern int cdi_get_track(cd_img_t *cdi, uint32_t sector);
|
||||
extern int cdi_get_audio_sub(cd_img_t *cdi, uint32_t sector, uint8_t *attr, uint8_t *track, uint8_t *index, TMSF *rel_pos, TMSF *abs_pos);
|
||||
extern int cdi_read_sector(cd_img_t *cdi, uint8_t *buffer, int raw, uint32_t sector);
|
||||
extern int cdi_read_sectors(cd_img_t *cdi, uint8_t *buffer, int raw, uint32_t sector, uint32_t num);
|
||||
extern int cdi_read_audio_sectors(cd_img_t *cdi, uint8_t *buffer, uint32_t sector, uint32_t count);
|
||||
extern int cdi_read_sector_sub(cd_img_t *cdi, uint8_t *buffer, uint32_t sector);
|
||||
extern int cdi_get_sector_size(cd_img_t *cdi, uint32_t sector);
|
||||
extern int cdi_is_mode2(cd_img_t *cdi, uint32_t sector);
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
#include <stdlib.h>
|
||||
#include <ctype.h>
|
||||
|
||||
#include <stdio.h>
|
||||
#include "../include/pg_debug.h"
|
||||
|
||||
#include "cdrom_error_msg.h"
|
||||
|
||||
@@ -274,7 +274,7 @@ static uint32_t drive_serial;
|
||||
static bool autoadvance;
|
||||
|
||||
void cdman_set_autoadvance(bool setting) {
|
||||
printf("setting autoadvance to %u\n", setting);
|
||||
DBG_PRINTF("setting autoadvance to %u\n", setting);
|
||||
autoadvance = setting;
|
||||
}
|
||||
|
||||
@@ -287,11 +287,11 @@ void cdman_reload_image(cdrom_t *dev) {
|
||||
void cdman_set_serial(cdrom_t *dev, uint32_t serial) {
|
||||
if (drive_serial == serial) {
|
||||
// If we are re-inserting the same drive, maybe advance the disc image
|
||||
printf("Inserting the same drive...\n");
|
||||
DBG_PRINTF("Inserting the same drive...\n");
|
||||
cdman_reload_image(dev);
|
||||
} else {
|
||||
drive_serial = serial;
|
||||
printf("New drive with serial %u inserted", serial);
|
||||
DBG_PRINTF("New drive with serial %u inserted", serial);
|
||||
cdman_load_image_index(dev, 1);
|
||||
}
|
||||
}
|
||||
+4
-3
@@ -27,6 +27,7 @@
|
||||
#include "tusb.h"
|
||||
/* #include "bsp/board_api.h" */
|
||||
#include "pico/stdlib.h"
|
||||
#include "../include/pg_debug.h"
|
||||
|
||||
#include "ff.h"
|
||||
#include "diskio.h"
|
||||
@@ -75,7 +76,7 @@ static bool inquiry_complete_cb(uint8_t dev_addr, tuh_msc_complete_data_t const
|
||||
|
||||
// For simplicity: we only mount 1 device
|
||||
if (f_mount(&fatfs, "", 1) != FR_OK) {
|
||||
puts("mount failed");
|
||||
ERR_PUTS("mount failed");
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -132,7 +133,7 @@ static void wait_for_disk_io(void)
|
||||
while (_disk_busy) {
|
||||
tuh_task();
|
||||
if ((int32_t)(time_us_32() - deadline) >= 0) {
|
||||
printf("disk_io: timeout waiting for USB transfer\n");
|
||||
DBG_PRINTF("disk_io: timeout waiting for USB transfer\n");
|
||||
_disk_busy = false;
|
||||
_disk_error = true;
|
||||
return;
|
||||
@@ -147,7 +148,7 @@ static bool disk_io_complete(uint8_t dev_addr, tuh_msc_complete_data_t const * c
|
||||
* reported an error (e.g. medium error, illegal request). */
|
||||
_disk_error = (cb_data->csw->status != 0);
|
||||
if (_disk_error)
|
||||
printf("disk_io: SCSI error status %u\n", cb_data->csw->status);
|
||||
DBG_PRINTF("disk_io: SCSI error status %u\n", cb_data->csw->status);
|
||||
_disk_busy = false;
|
||||
return true;
|
||||
}
|
||||
|
||||
+6
-6
@@ -67,7 +67,7 @@ using namespace std;
|
||||
|
||||
// #define GUS_BASE myGUS.portbase
|
||||
#define GUS_RATE myGUS.rate
|
||||
#define LOG_GUS 0
|
||||
#define PGDEBUG_GUS 0
|
||||
|
||||
#define VOL_SHIFT 14
|
||||
|
||||
@@ -1051,7 +1051,7 @@ __force_inline static uint16_t ExecuteReadRegister(void) {
|
||||
critical_section_exit(&gus_crit);
|
||||
return (uint16_t)(tmpreg << 8);
|
||||
default:
|
||||
#if LOG_GUS
|
||||
#if PGDEBUG_GUS
|
||||
LOG_MSG("Read Register num 0x%x", myGUS.gRegSelect);
|
||||
#endif
|
||||
return myGUS.gRegData;
|
||||
@@ -1214,7 +1214,7 @@ __force_inline static void ExecuteGlobRegister(void) {
|
||||
// myGUS.basefreq = (uint32_t)(1000000.0/(1.619695497*(float)(myGUS.ActiveChannels)));
|
||||
myGUS.basefreq = myGUS.fixed_44k_output ? 44100 : sample_rates[myGUS.ActiveChannels - 1];
|
||||
|
||||
#if LOG_GUS
|
||||
#if PGDEBUG_GUS
|
||||
LOG_MSG("GUS set to %d channels freq=%luHz", myGUS.ActiveChannels,(unsigned long)myGUS.basefreq);
|
||||
#endif
|
||||
for (i=0;i<myGUS.ActiveChannels;i++) guschan[i]->UpdateWaveRamp();
|
||||
@@ -1270,7 +1270,7 @@ __force_inline static void ExecuteGlobRegister(void) {
|
||||
GUSReset();
|
||||
break;
|
||||
default:
|
||||
#if LOG_GUS
|
||||
#if PGDEBUG_GUS
|
||||
LOG_MSG("Unimplemented global register %x -- %x", myGUS.gRegSelect, myGUS.gRegData);
|
||||
#endif
|
||||
break;
|
||||
@@ -1364,7 +1364,7 @@ __force_inline uint8_t read_gus(Bitu port) {
|
||||
}
|
||||
case 0x106:
|
||||
default:
|
||||
#if LOG_GUS
|
||||
#if PGDEBUG_GUS
|
||||
LOG_MSG("Read GUS at port 0x%x", port);
|
||||
#endif
|
||||
break;
|
||||
@@ -1448,7 +1448,7 @@ __force_inline void write_gus(Bitu port, Bitu val) {
|
||||
}
|
||||
break;
|
||||
default:
|
||||
#if LOG_GUS
|
||||
#if PGDEBUG_GUS
|
||||
LOG_MSG("Write GUS at port 0x%x with %x", port, val);
|
||||
#endif
|
||||
break;
|
||||
|
||||
+10
-10
@@ -16,7 +16,7 @@
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include "include/pg_debug.h"
|
||||
// #include "stdio_async_uart.h"
|
||||
#include <math.h>
|
||||
|
||||
@@ -103,12 +103,12 @@ static void update_gus_timing(uint8_t channels) {
|
||||
uint32_t divider = cps * 4;
|
||||
pio_sm_set_clkdiv_int_frac(audio_pio, PICO_AUDIO_I2S_SM, divider >> 8u, divider & 0xffu);
|
||||
|
||||
printf("GUS channels: %u\n", channels);
|
||||
DBG_PRINTF("GUS channels: %u\n", channels);
|
||||
}
|
||||
|
||||
// void __xip_cache("my_sub_section") (play_gus)(void) {
|
||||
void play_gus() {
|
||||
puts("starting core 1");
|
||||
DBG_PUTS("starting core 1");
|
||||
// flash_safe_execute_core_init();
|
||||
uint32_t start, end;
|
||||
|
||||
@@ -116,31 +116,31 @@ void play_gus() {
|
||||
PIC_Init();
|
||||
|
||||
// Init ISA DMA on this core so it handles the ISR
|
||||
puts("Initing ISA DMA PIO...");
|
||||
DBG_PUTS("Initing ISA DMA PIO...");
|
||||
dma_config = DMA_init(pio0, DMA_PIO_SM, GUS_DMA_isr_pt);
|
||||
|
||||
#ifdef PSRAM_CORE1
|
||||
#ifdef PSRAM
|
||||
puts("Initing PSRAM...");
|
||||
DBG_PUTS("Initing PSRAM...");
|
||||
psram_spi = psram_spi_init_clkdiv(pio1, -1, 1.6);
|
||||
#if TEST_PSRAM
|
||||
puts("Writing PSRAM...");
|
||||
DBG_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_async(&psram_spi, addr, (addr & 0xFF));
|
||||
}
|
||||
puts("Reading PSRAM...");
|
||||
DBG_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);
|
||||
DBG_PRINTF("\nPSRAM failure at address %x (%x != %x)\n", addr, addr & 0xFF, result);
|
||||
return;
|
||||
}
|
||||
}
|
||||
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);
|
||||
DBG_PRINTF("8 bit: PSRAM read 1MB in %d us, %d B/s (target 705600 B/s)\n", psram_elapsed, (uint32_t)psram_speed);
|
||||
#endif
|
||||
#endif
|
||||
#endif
|
||||
@@ -157,7 +157,7 @@ void play_gus() {
|
||||
|
||||
init_audio();
|
||||
|
||||
printf("GUS IRQ-driven audio started\n");
|
||||
DBG_PRINTF("GUS IRQ-driven audio started\n");
|
||||
|
||||
// Use the PWM peripheral to trigger an IRQ at the GUS sample rate
|
||||
pwm_config pwm_c = pwm_get_default_config();
|
||||
|
||||
@@ -31,10 +31,7 @@ static INLINE uint16_t host_readw(ConstHostPt off) {
|
||||
return __builtin_bswap16(*(uint16_t *)off);
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
#define LOG_MSG(msg, ...) printf(msg "\n", ##__VA_ARGS__);
|
||||
#define DEBUG_LOG_MSG(msg, ...) printf(msg "\n", ##__VA_ARGS__);
|
||||
#else
|
||||
#define LOG_MSG(...) (void)0
|
||||
#define DEBUG_LOG_MSG(...) (void)0
|
||||
#endif
|
||||
#include "pg_debug.h"
|
||||
|
||||
#define LOG_MSG(msg, ...) DBG_PRINTF(msg "\n", ##__VA_ARGS__)
|
||||
#define DEBUG_LOG_MSG(msg, ...) DBG_PRINTF(msg "\n", ##__VA_ARGS__)
|
||||
@@ -0,0 +1,48 @@
|
||||
/*
|
||||
* PicoGUS Debug Printing Framework
|
||||
*
|
||||
* Copyright (C) 2024 Ian Scott
|
||||
*
|
||||
* Master switch: PGDEBUG (set via CMake: -DPGDEBUG=ON)
|
||||
* When PGDEBUG is not defined, all debug macros compile to ((void)0).
|
||||
*
|
||||
* Module-level switches (PGDEBUG_GUS, PGDEBUG_CDROM, etc.) provide
|
||||
* per-module granularity within debug builds.
|
||||
*
|
||||
* ERR_PUTS outputs fatal error strings via UART directly, bypassing
|
||||
* printf/stdio entirely. Works even with pico_set_printf_implementation(none).
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "hardware/uart.h"
|
||||
#include "hardware/gpio.h"
|
||||
|
||||
/* ---- Fatal error output: always active, bypasses printf ---- */
|
||||
static inline void _pg_err_puts(const char *s) {
|
||||
uart_inst_t *uart = uart0;
|
||||
if (!uart_is_enabled(uart)) {
|
||||
uart_init(uart, PICO_DEFAULT_UART_BAUD_RATE);
|
||||
gpio_set_function(PICO_DEFAULT_UART_TX_PIN, GPIO_FUNC_UART);
|
||||
}
|
||||
uart_puts(uart, s);
|
||||
uart_puts(uart, "\r\n");
|
||||
}
|
||||
#define ERR_PUTS(s) _pg_err_puts(s)
|
||||
|
||||
/* ---- Debug macros: gated on PGDEBUG ---- */
|
||||
#ifdef PGDEBUG
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#define DBG_PRINTF(fmt, ...) printf(fmt, ##__VA_ARGS__)
|
||||
#define DBG_PUTS(s) puts(s)
|
||||
#define DBG_PUTCHAR(c) putchar(c)
|
||||
|
||||
#else
|
||||
|
||||
#define DBG_PRINTF(fmt, ...) ((void)0)
|
||||
#define DBG_PUTS(s) ((void)0)
|
||||
#define DBG_PUTCHAR(c) ((void)0)
|
||||
|
||||
#endif /* PGDEBUG */
|
||||
+3
-3
@@ -59,7 +59,7 @@ Data (input) = base + 2 (base)
|
||||
#include "../cdrom/cdrom.h"
|
||||
#include "../cdrom/cdrom_image_manager.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include "../include/pg_debug.h"
|
||||
|
||||
#define mke_log(fmt, ...)
|
||||
|
||||
@@ -115,14 +115,14 @@ void MKE_COMMAND(uint8_t value) {
|
||||
switch(mke.command_buffer[0]) {
|
||||
case 06: //TRAY OUT
|
||||
cdrom_fifo_clear(&cdrom.info_fifo);
|
||||
printf("TRAY OUT\n");
|
||||
DBG_PRINTF("TRAY OUT\n");
|
||||
cdman_unload_image(&cdrom);
|
||||
cdrom_output_status(&cdrom);
|
||||
mke.tray_open=true;
|
||||
break;
|
||||
case 07: //TRAY IN
|
||||
cdrom_fifo_clear(&cdrom.info_fifo);
|
||||
printf("TRAY IN\n");
|
||||
DBG_PRINTF("TRAY IN\n");
|
||||
cdman_reload_image(&cdrom);
|
||||
cdrom_output_status(&cdrom);
|
||||
mke.tray_open=false;
|
||||
|
||||
@@ -44,6 +44,8 @@ Bit8u MPU401_ReadStatus(void);
|
||||
void MPU401_WriteData(Bit8u val, bool crit);
|
||||
Bit8u QueueUsed();
|
||||
void send_midi_bytes(int maxbytes);
|
||||
uint32_t MIDI_BufferFree(void);
|
||||
void MIDI_RawOutByte(Bit8u data);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
||||
+33
-36
@@ -45,19 +45,12 @@ static critical_section_t midi_crit;
|
||||
typedef uint32_t Bit32u;
|
||||
typedef int32_t Bits;
|
||||
|
||||
/* RAWBUF: This is the buffer for outgoing MIDI data. The larger the buffer,
|
||||
the less likely it is to overrun when SysEx delay is enabled and large SysEx
|
||||
transfers are occurring. */
|
||||
//#define RAWBUF 14336
|
||||
#ifdef MPU_ONLY
|
||||
#define SYSEX_SIZE 8192 // sysex buffer for delay calculation
|
||||
#define RAWBUF 65536
|
||||
#define RAWBUF_BITS 65535
|
||||
#else
|
||||
#define SYSEX_SIZE 2048 // sysex buffer for delay calculation
|
||||
#define RAWBUF 8192
|
||||
#define RAWBUF_BITS 8191
|
||||
#endif // MPU_ONLY
|
||||
/* RAWBUF: Ring buffer for outgoing MIDI data. Flow control via the status
|
||||
register (bit 6/DRR) throttles the host to MIDI wire speed. Matches
|
||||
the 256 byte size of a real MPU-401 */
|
||||
#define SYSEX_SIZE 32 // sysex buffer for header inspection
|
||||
#define RAWBUF 256
|
||||
#define RAWBUF_BITS 255
|
||||
|
||||
typedef struct ring_buffer {
|
||||
uint8_t buffer[RAWBUF];
|
||||
@@ -67,6 +60,13 @@ typedef struct ring_buffer {
|
||||
|
||||
static ring_buffer midi_out_buff = { {0}, 0, 0 };
|
||||
|
||||
volatile bool midi_output_busy = false;
|
||||
|
||||
uint32_t MIDI_BufferFree(void) {
|
||||
uint32_t used = (midi_out_buff.head - midi_out_buff.tail) & RAWBUF_BITS;
|
||||
return (RAWBUF - 1) - used;
|
||||
}
|
||||
|
||||
/* SOFTMPU: Note tracking for RA-50 */
|
||||
#define MAX_TRACKED_CHANNELS 16
|
||||
#define MAX_TRACKED_NOTES 8
|
||||
@@ -162,6 +162,8 @@ __force_inline static void PlayMsg(Bit8u* msg, Bitu len)
|
||||
}
|
||||
critical_section_exit(&midi_crit);
|
||||
}
|
||||
uint32_t used = (midi_out_buff.head - midi_out_buff.tail) & RAWBUF_BITS;
|
||||
midi_output_busy = used >= (RAWBUF - 2);
|
||||
}
|
||||
|
||||
__force_inline static void send_midi_byte_now(Bit8u byte) {
|
||||
@@ -252,14 +254,11 @@ void MIDI_RawOutByte(Bit8u data) {
|
||||
}
|
||||
}
|
||||
|
||||
__force_inline static bool send_midi_byte() {
|
||||
__force_inline static bool send_midi_byte() {
|
||||
if (uart_tx_status()) return false; // can't send yet
|
||||
if (midi_out_buff.head == midi_out_buff.tail) return false; // nothing to send
|
||||
/* putchar('s'); */
|
||||
critical_section_enter_blocking(&midi_crit);
|
||||
if (midi_out_buff.head == midi_out_buff.tail) {
|
||||
critical_section_exit(&midi_crit);
|
||||
return false; // nothing to send
|
||||
}
|
||||
if (midi.sysex.start) {
|
||||
Bit32u passed_ticks = time_us_32() - midi.sysex.start;
|
||||
if (passed_ticks < midi.sysex.delay) { // still waiting for sysex delay
|
||||
@@ -268,10 +267,12 @@ __force_inline static bool send_midi_byte() {
|
||||
}
|
||||
}
|
||||
Bit8u data = midi_out_buff.buffer[midi_out_buff.tail];
|
||||
midi_out_buff.tail = (midi_out_buff.tail + 1) & RAWBUF_BITS; // increment tail, wrap to 0 if we're at the end
|
||||
midi_out_buff.tail = (midi_out_buff.tail + 1) & RAWBUF_BITS;
|
||||
uint32_t used = (midi_out_buff.head - midi_out_buff.tail) & RAWBUF_BITS;
|
||||
midi_output_busy = used >= (RAWBUF - 2);
|
||||
critical_section_exit(&midi_crit);
|
||||
|
||||
if (midi.sysex.status==0xf0) { // Start
|
||||
if (midi.sysex.status==0xf0) { // Start
|
||||
/* putchar('s'); */
|
||||
if (!(data&0x80)) {
|
||||
/*
|
||||
@@ -282,34 +283,30 @@ __force_inline static bool send_midi_byte() {
|
||||
*/
|
||||
|
||||
output_to_uart(data);
|
||||
if (midi.sysex.used<(SYSEX_SIZE-1)) midi.sysex.buf[midi.sysex.used++] = data;
|
||||
if (midi.sysex.used < SYSEX_SIZE) midi.sysex.buf[midi.sysex.used] = data;
|
||||
midi.sysex.used++;
|
||||
/* midi.sysex.buf[midi.sysex.used++] = data; */
|
||||
return true;
|
||||
} else {
|
||||
output_to_uart(0xf7);
|
||||
midi.sysex.buf[midi.sysex.used++] = 0xf7;
|
||||
if (midi.sysex.used < SYSEX_SIZE) midi.sysex.buf[midi.sysex.used] = 0xf7;
|
||||
midi.sysex.used++;
|
||||
midi.sysex.status = 0xf7;
|
||||
/*LOG(LOG_ALL,LOG_NORMAL)("Play sysex; address:%02X %02X %02X, length:%4d, delay:%3d", midi.sysex.buf[5], midi.sysex.buf[6], midi.sysex.buf[7], midi.sysex.used, midi.sysex.delay);*/
|
||||
if (midi.sysex.start) {
|
||||
/* if (midi.sysex.usedbufs == 0 && midi.sysex.buf[5] == 0x7F) { */
|
||||
if (midi.sysex.buf[5] == 0x7F) {
|
||||
midi.sysex.delay = 290; // PicoGUS // All Parameters reset
|
||||
/* } else if (midi.sysex.usedbufs == 0 && midi.sysex.buf[5] == 0x10 && midi.sysex.buf[6] == 0x00 && midi.sysex.buf[7] == 0x04) { */
|
||||
midi.sysex.delay = 290000; // All Parameters reset (290 ms)
|
||||
} else if (midi.sysex.buf[5] == 0x10 && midi.sysex.buf[6] == 0x00 && midi.sysex.buf[7] == 0x04) {
|
||||
midi.sysex.delay = 145; // PicoGUS // Viking Child
|
||||
/* } else if (midi.sysex.usedbufs == 0 && midi.sysex.buf[5] == 0x10 && midi.sysex.buf[6] == 0x00 && midi.sysex.buf[7] == 0x01) { */
|
||||
midi.sysex.delay = 145000; // Viking Child (145 ms)
|
||||
} else if (midi.sysex.buf[5] == 0x10 && midi.sysex.buf[6] == 0x00 && midi.sysex.buf[7] == 0x01) {
|
||||
midi.sysex.delay = 30; // PicoGUS // Dark Sun 1
|
||||
midi.sysex.delay = 30000; // Dark Sun 1 (30 ms)
|
||||
} else {
|
||||
// HardMPU:
|
||||
/* midi.sysex.delay = ((((midi.sysex.usedbufs*SYSEX_SIZE)+midi.sysex.used)/2)+2); */
|
||||
// DOSBox:
|
||||
/* midi.sysex.delay = (Bitu)(((float)(midi.sysex.used) * 1.25f) * 1000.0f / 3125.0f) + 2 */
|
||||
// PicoGUS: 1.25 * 1000.0 / 3125.0 = 0.4
|
||||
/* midi.sysex.delay = ((midi.sysex.usedbufs*SYSEX_SIZE)+midi.sysex.used) * 0.4f + 2; */
|
||||
midi.sysex.delay = midi.sysex.used * 0.4f + 2;
|
||||
if (midi.sysex.extra_delay && midi.sysex.delay < 40) {
|
||||
midi.sysex.delay = 40;
|
||||
// DOSBox formula: (used * 1.25 * 1000 / 3125) + 2 ms = (used * 0.4 + 2) ms
|
||||
// Convert to µs for time_us_32() comparison
|
||||
midi.sysex.delay = (Bitu)(midi.sysex.used * 400.0f) + 2000;
|
||||
if (midi.sysex.extra_delay && midi.sysex.delay < 40000) {
|
||||
midi.sysex.delay = 40000;
|
||||
}
|
||||
}
|
||||
midi.sysex.start = time_us_32(); // PicoGUS
|
||||
|
||||
+35
-3
@@ -47,11 +47,17 @@ typedef uint16_t Bit16u;
|
||||
typedef int32_t Bits;
|
||||
typedef int8_t Bit8s;
|
||||
|
||||
// autodetect when Gateway runs by watching for it setting this message on the MT-32's LCD
|
||||
static const char* gateway_msg = "\xf0\x41\x10\x16\x12\x20\x00\x00 Gateway";
|
||||
static uint8_t gateway_pos = 0;
|
||||
static uint8_t gateway_len = 22;
|
||||
|
||||
#include "system/pico_pic.h"
|
||||
|
||||
void MIDI_Init(bool delaysysex,bool fakeallnotesoff);
|
||||
void MIDI_RawOutByte(Bit8u data);
|
||||
bool MIDI_Available(void);
|
||||
extern volatile bool midi_output_busy;
|
||||
|
||||
static uint32_t MPU401_EventHandler(Bitu val);
|
||||
static PIC_TimerEvent MPU401_Event = {
|
||||
@@ -95,6 +101,7 @@ typedef enum MpuDataType MpuDataType; /* SOFTMPU */
|
||||
#define MSG_MPU_CLOCK 0xfd
|
||||
#define MSG_MPU_ACK 0xfe
|
||||
|
||||
static bool config_versionfix = false;
|
||||
static bool config_delaysysex = false;
|
||||
static bool config_fakeallnotesoff = false;
|
||||
|
||||
@@ -160,7 +167,7 @@ __force_inline static void ClrQueue(void) {
|
||||
__force_inline Bit8u MPU401_ReadStatus(void) { /* SOFTMPU */
|
||||
critical_section_enter_blocking(&mpu_crit);
|
||||
uint8_t ret=0x3f; /* Bits 6 and 7 clear */
|
||||
if (mpu.state.cmd_pending) ret|=0x40;
|
||||
if (mpu.state.cmd_pending || midi_output_busy) ret|=0x40;
|
||||
if (!mpu.queue_used) ret|=0x80;
|
||||
critical_section_exit(&mpu_crit);
|
||||
return ret;
|
||||
@@ -272,8 +279,14 @@ __force_inline void MPU401_WriteCommand(Bit8u val, bool crit) { /* SOFTMPU */
|
||||
QueueByte(0);
|
||||
goto write_command_return;
|
||||
case 0xac: /* Request version */
|
||||
QueueByte(MSG_MPU_ACK);
|
||||
QueueByte(MPU401_VERSION);
|
||||
if (config_versionfix) {
|
||||
// Hack for Gateway
|
||||
QueueByte(MPU401_VERSION);
|
||||
QueueByte(MSG_MPU_ACK);
|
||||
} else {
|
||||
QueueByte(MSG_MPU_ACK);
|
||||
QueueByte(MPU401_VERSION);
|
||||
}
|
||||
goto write_command_return;
|
||||
case 0xad: /* Request revision */
|
||||
QueueByte(MSG_MPU_ACK);
|
||||
@@ -376,6 +389,16 @@ __force_inline void MPU401_WriteData(Bit8u val, bool crit) { /* SOFTMPU */
|
||||
static Bit8u length,cnt,posd; /* SOFTMPU */
|
||||
if (mpu.mode==M_UART) {
|
||||
MIDI_RawOutByte(val);
|
||||
// autodetect when Gateway runs
|
||||
if (val == gateway_msg[gateway_pos]) {
|
||||
++gateway_pos;
|
||||
if (gateway_pos == gateway_len) {
|
||||
config_versionfix = true;
|
||||
gateway_pos = 0;
|
||||
}
|
||||
} else {
|
||||
gateway_pos = 0;
|
||||
}
|
||||
goto write_return;
|
||||
}
|
||||
switch (mpu.state.command_byte) { /* 0xe# command data */
|
||||
@@ -581,6 +604,14 @@ __force_inline static void MPU401_IntelligentOut(Bit8u chan) {
|
||||
}
|
||||
|
||||
__force_inline static void UpdateTrack(Bit8u chan) {
|
||||
/* block until MIDI output buffer has room, matching real MPU-401 (busy-wait
|
||||
with SCI TX interrupt draining), checks for >= 4 free bytes before writing
|
||||
a message. */
|
||||
if (mpu.playbuf[chan].type != T_OVERFLOW) {
|
||||
while (MIDI_BufferFree() < 4) {
|
||||
send_midi_bytes(1);
|
||||
}
|
||||
}
|
||||
MPU401_IntelligentOut(chan);
|
||||
if (mpu.state.amask&(1<<chan)) {
|
||||
mpu.playbuf[chan].vlength=0;
|
||||
@@ -733,6 +764,7 @@ __force_inline static void MPU401_Reset(void) {
|
||||
/* HardMPU: Initialisation */
|
||||
void MPU401_Init(bool delaysysex, bool fakeallnotesoff)
|
||||
{
|
||||
config_versionfix = false;
|
||||
config_delaysysex = delaysysex;
|
||||
config_fakeallnotesoff = fakeallnotesoff;
|
||||
if (!critical_section_is_initialized(&mpu_crit)) {
|
||||
|
||||
+3
-3
@@ -16,7 +16,7 @@
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include "include/pg_debug.h"
|
||||
|
||||
#include "system/flash_settings.h"
|
||||
extern Settings settings;
|
||||
@@ -30,7 +30,7 @@ extern Settings settings;
|
||||
#include "mpu401/export.h"
|
||||
|
||||
void play_mpu() {
|
||||
puts("starting core 1 MPU");
|
||||
DBG_PUTS("starting core 1 MPU");
|
||||
// flash_safe_execute_core_init();
|
||||
|
||||
#ifdef USB_STACK
|
||||
@@ -40,7 +40,7 @@ void play_mpu() {
|
||||
|
||||
// Init PIC on this core so it handles timers
|
||||
PIC_Init();
|
||||
puts("pic inited on core 1");
|
||||
DBG_PUTS("pic inited on core 1");
|
||||
MPU401_Init(settings.MPU.delaySysex, settings.MPU.fakeAllNotesOff);
|
||||
|
||||
for (;;) {
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
#include <hardware/flash.h>
|
||||
#include "flash_firmware.h"
|
||||
#include "system/flash_settings.h"
|
||||
#include <stdio.h>
|
||||
#include "../include/pg_debug.h"
|
||||
|
||||
static uint32_t sStart = 0;
|
||||
static const uint32_t offset[NR_OF_FIRMWARES] = {FLASH_FIRMWARE1, FLASH_FIRMWARE2, FLASH_FIRMWARE3, FLASH_FIRMWARE4, FLASH_FIRMWARE5, FLASH_FIRMWARE6};
|
||||
@@ -27,7 +27,7 @@ uint8_t read_permMode(void)
|
||||
int main(void)
|
||||
{
|
||||
stdio_init_all();
|
||||
printf("picogus bootloader\n");
|
||||
DBG_PUTS("picogus bootloader");
|
||||
stdio_flush();
|
||||
uint8_t firmware_nr = (uint8_t) (0x000000FF & watchdog_hw->scratch[3]);
|
||||
|
||||
|
||||
+11
-11
@@ -34,7 +34,7 @@ Modifications for use with Pico by Kevin Moonlight (me@yyzkevin.com)
|
||||
*/
|
||||
|
||||
|
||||
#include <stdio.h>
|
||||
#include "../include/pg_debug.h"
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <time.h>
|
||||
@@ -142,31 +142,31 @@ void PG_Wifi_Connect(const char* ssid, const char* pass) {
|
||||
strlcpy(PG_Wifi_info.WIFI_KEY, pass, 64);
|
||||
}
|
||||
if (!PG_Wifi_info.WIFI_SSID[0]) {
|
||||
printf("No SSID set\n");
|
||||
DBG_PRINTF("No SSID set\n");
|
||||
return;
|
||||
}
|
||||
|
||||
printf("Joining SSID: %s\n", PG_Wifi_info.WIFI_SSID);
|
||||
DBG_PRINTF("Joining SSID: %s\n", PG_Wifi_info.WIFI_SSID);
|
||||
int ConnectErr=cyw43_arch_wifi_connect_async(
|
||||
PG_Wifi_info.WIFI_SSID,
|
||||
PG_Wifi_info.WIFI_KEY,
|
||||
PG_Wifi_info.WIFI_KEY[0] == 0 ? CYW43_AUTH_OPEN : CYW43_AUTH_WPA2_MIXED_PSK
|
||||
);
|
||||
if (ConnectErr==0) printf("Connection started\n");
|
||||
else printf("Connection Error: %d", ConnectErr);
|
||||
if (ConnectErr==0) DBG_PRINTF("Connection started\n");
|
||||
else DBG_PRINTF("Connection Error: %d", ConnectErr);
|
||||
}
|
||||
|
||||
void PG_Wifi_Reconnect(void)
|
||||
{
|
||||
int32_t rssi;
|
||||
cyw43_ioctl(&cyw43_state, CYW43_IOCTL_GET_RSSI, sizeof(rssi), (uint8_t*)&rssi, CYW43_ITF_STA);
|
||||
printf("rssi %d ", rssi);
|
||||
DBG_PRINTF("rssi %d ", rssi);
|
||||
if (rssi == 0) {
|
||||
PG_Wifi_Connect(NULL, NULL);
|
||||
return;
|
||||
}
|
||||
int16_t status = cyw43_wifi_link_status(&cyw43_state, CYW43_ITF_STA);
|
||||
printf("status: %d\n", status);
|
||||
DBG_PRINTF("status: %d\n", status);
|
||||
switch(status)
|
||||
{
|
||||
case CYW43_LINK_JOIN :
|
||||
@@ -180,22 +180,22 @@ void PG_Wifi_Reconnect(void)
|
||||
|
||||
uint8_t PG_EnableWifi(void) {
|
||||
if (cyw43_arch_init()) {
|
||||
printf("Init failed\n");
|
||||
DBG_PRINTF("Init failed\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
cyw43_arch_gpio_put(CYW43_WL_GPIO_LED_PIN, 1);
|
||||
|
||||
printf("cyw43_wifi_set_up(&cyw43_state,CYW43_ITF_STA,true,CYW43_COUNTRY_WORLDWIDE);\n");
|
||||
DBG_PRINTF("cyw43_wifi_set_up(&cyw43_state,CYW43_ITF_STA,true,CYW43_COUNTRY_WORLDWIDE);\n");
|
||||
cyw43_wifi_set_up(&cyw43_state, CYW43_ITF_STA, true, CYW43_COUNTRY_WORLDWIDE);
|
||||
cyw43_wifi_get_mac(&cyw43_state, CYW43_ITF_STA, PG_Wifi_info.cyw43_mac);
|
||||
printf("WIFI Address: %02x:%02x:%02x:%02x:%02x:%02x\n\r",
|
||||
DBG_PRINTF("WIFI Address: %02x:%02x:%02x:%02x:%02x:%02x\n\r",
|
||||
PG_Wifi_info.cyw43_mac[0], PG_Wifi_info.cyw43_mac[1], PG_Wifi_info.cyw43_mac[2],
|
||||
PG_Wifi_info.cyw43_mac[3], PG_Wifi_info.cyw43_mac[4], PG_Wifi_info.cyw43_mac[5]);
|
||||
cyw43_wifi_pm(&cyw43_state, cyw43_pm_value(CYW43_NO_POWERSAVE_MODE, 20, 1, 1, 1));
|
||||
|
||||
nic = ne2000_init();
|
||||
printf("Inited\n");
|
||||
DBG_PRINTF("Inited\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
+1
-1
@@ -20,7 +20,7 @@ typedef enum { NE2000_NE2000, NE2000_RTL8029AS } ne2000_type;
|
||||
|
||||
#define NETBLOCKING 0 // we won't block our pcap
|
||||
|
||||
//#define NE2000_DEBUG
|
||||
#define PGDEBUG_NE2000 0
|
||||
|
||||
#define BX_RESET_HARDWARE 0
|
||||
#define BX_RESET_SOFTWARE 1
|
||||
|
||||
+4
-3
@@ -17,10 +17,11 @@
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <math.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "include/pg_debug.h"
|
||||
|
||||
#if PICO_ON_DEVICE
|
||||
|
||||
#include "hardware/clocks.h"
|
||||
@@ -49,7 +50,7 @@ void play_ne2000() {
|
||||
// Init PIC on this core so it handles timers
|
||||
PIC_Init();
|
||||
|
||||
puts("starting core 1 ne2000");
|
||||
DBG_PUTS("starting core 1 ne2000");
|
||||
PG_EnableWifi();
|
||||
PG_Wifi_Connect(settings.WiFi.ssid, settings.WiFi.password);
|
||||
|
||||
@@ -69,7 +70,7 @@ void play_ne2000() {
|
||||
}
|
||||
if (((time_us_32() >> 21) & 0x1) == 0x1) {
|
||||
if (flag == false) {
|
||||
putchar('=');
|
||||
DBG_PUTCHAR('=');
|
||||
PG_Wifi_Reconnect();
|
||||
flag = true;
|
||||
}
|
||||
|
||||
+2
-2
@@ -445,7 +445,7 @@ static void initializeTables() {
|
||||
#define CAR(o, x) (&(o)->slot[((x) << 1) | 1])
|
||||
#define BIT(s, b) (((s) >> (b)) & 1)
|
||||
|
||||
#if OPL_DEBUG
|
||||
#if PGDEBUG_OPL
|
||||
static void _debug_print_patch(OPL_SLOT *slot) {
|
||||
OPL_PATCH *p = slot->patch;
|
||||
printf("[slot#%d am:%d pm:%d eg:%d kr:%d ml:%d kl:%d tl:%d ws:%d fb:%d A:%d D:%d S:%d R:%d]\n", slot->number, //
|
||||
@@ -566,7 +566,7 @@ static void commit_slot_update(OPL_SLOT *slot, uint8_t notesel) {
|
||||
}
|
||||
}
|
||||
|
||||
#if OPL_DEBUG
|
||||
#if PGDEBUG_OPL
|
||||
if (slot->last_eg_state != slot->eg_state) {
|
||||
_debug_print_slot_info(slot);
|
||||
slot->last_eg_state = slot->eg_state;
|
||||
|
||||
+2
-2
@@ -8,7 +8,7 @@
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#define OPL_DEBUG 0
|
||||
#define PGDEBUG_OPL 0
|
||||
|
||||
/* mask */
|
||||
#define OPL_MASK_CH(x) (1 << (x))
|
||||
@@ -61,7 +61,7 @@ typedef struct __OPL_SLOT {
|
||||
|
||||
uint32_t update_requests; /* flags to debounce update */
|
||||
|
||||
#if OPL_DEBUG
|
||||
#if PGDEBUG_OPL
|
||||
uint8_t last_eg_state;
|
||||
#endif
|
||||
} OPL_SLOT;
|
||||
|
||||
+31
-31
@@ -16,8 +16,8 @@
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include "include/pg_debug.h"
|
||||
#include "pico/stdlib.h"
|
||||
#include "pico/multicore.h"
|
||||
#include "hardware/adc.h"
|
||||
@@ -426,7 +426,7 @@ __force_inline void write_picogus_high(uint8_t value) {
|
||||
/* printf("%s\n", settings.WiFi.password); */
|
||||
break;
|
||||
case CMD_WIFIAPPLY:
|
||||
printf("Applying wifi settings: %s %s\n", settings.WiFi.ssid, settings.WiFi.password);
|
||||
DBG_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
|
||||
@@ -507,14 +507,14 @@ __force_inline void write_picogus_high(uint8_t value) {
|
||||
// For multifw
|
||||
case CMD_BOOTMODE:
|
||||
settings.startupMode = value;
|
||||
printf("requesting startup mode: %u\n", value);
|
||||
DBG_PRINTF("requesting startup mode: %u\n", value);
|
||||
break;
|
||||
case CMD_SAVE:
|
||||
queueSaveSettings = true;
|
||||
break;
|
||||
case CMD_REBOOT:
|
||||
watchdog_hw->scratch[3] = settings.startupMode;
|
||||
printf("rebooting into mode: %u\n", settings.startupMode);
|
||||
DBG_PRINTF("rebooting into mode: %u\n", settings.startupMode);
|
||||
watchdog_reboot(0, 0, 0);
|
||||
break;
|
||||
case CMD_DEFAULTS:
|
||||
@@ -642,7 +642,7 @@ __force_inline uint8_t read_picogus_high(void) {
|
||||
return 0x04; // EOT
|
||||
}
|
||||
ret = cdrom.image_list[cur_read_idx][cur_read++];
|
||||
putchar(ret);
|
||||
DBG_PUTCHAR(ret);
|
||||
if (ret == 0) { // Null terminated
|
||||
++cur_read_idx;
|
||||
cur_read = 0;
|
||||
@@ -727,7 +727,7 @@ void processSettings(void) {
|
||||
#endif
|
||||
#ifdef CDROM
|
||||
cdrom_port_test = settings.CD.basePort >> 4;
|
||||
printf("cdrom base port: %x\n", settings.CD.basePort);
|
||||
DBG_PRINTF("cdrom base port: %x\n", settings.CD.basePort);
|
||||
cdman_set_autoadvance(settings.CD.autoAdvance);
|
||||
#endif
|
||||
if (BOARD_TYPE == PICOGUS_2) {
|
||||
@@ -1228,14 +1228,14 @@ int main()
|
||||
#else
|
||||
stdio_init_all();
|
||||
#endif
|
||||
puts(firmware_string);
|
||||
DBG_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.");
|
||||
DBG_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)");
|
||||
DBG_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");
|
||||
DBG_PUTS("I was reset due the debug port");
|
||||
}
|
||||
|
||||
// Load settings from flash
|
||||
@@ -1254,12 +1254,12 @@ int main()
|
||||
// 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);
|
||||
DBG_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)");
|
||||
DBG_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;
|
||||
@@ -1269,7 +1269,7 @@ int main()
|
||||
BOARD_TYPE = PICO_BASED;
|
||||
} else {
|
||||
// On chipdown board (PicoGUS v2.0)
|
||||
puts("Running on PicoGUS v2.0");
|
||||
DBG_PUTS("Running on PicoGUS v2.0");
|
||||
LED_PIN = 1 << 23;
|
||||
gpio_init(23);
|
||||
gpio_set_dir(23, GPIO_OUT);
|
||||
@@ -1294,7 +1294,7 @@ int main()
|
||||
gpio_set_drive_strength(IRQ_PIN, GPIO_DRIVE_STRENGTH_12MA);
|
||||
|
||||
#ifdef SOUND_MPU
|
||||
puts("Initing MIDI UART...");
|
||||
DBG_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);
|
||||
@@ -1308,18 +1308,18 @@ int main()
|
||||
|
||||
#ifdef PSRAM_CORE0
|
||||
#ifdef PSRAM
|
||||
puts("Initing PSRAM...");
|
||||
DBG_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");
|
||||
DBG_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_PUTS("Error: No PSRAM strategies found to work!");
|
||||
err_blink();
|
||||
}
|
||||
}
|
||||
@@ -1331,7 +1331,7 @@ int main()
|
||||
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_PUTS("Error: No PSRAM strategies found to work!");
|
||||
err_blink();
|
||||
}
|
||||
}
|
||||
@@ -1343,14 +1343,14 @@ int main()
|
||||
|
||||
#ifdef SOUND_SB
|
||||
#ifdef SOUND_WSS
|
||||
puts("Initializing WSS AD1848");
|
||||
DBG_PUTS("Initializing WSS AD1848");
|
||||
#else
|
||||
puts("Initializing SoundBlaster DSP");
|
||||
DBG_PUTS("Initializing SoundBlaster DSP");
|
||||
#endif
|
||||
// init actually happens on core 1 in play_adlib()
|
||||
#endif // SOUND_SB
|
||||
#ifdef SOUND_OPL
|
||||
puts("Creating OPL");
|
||||
DBG_PUTS("Creating OPL");
|
||||
OPL_Pico_Init(0);
|
||||
multicore_launch_core1(&play_adlib);
|
||||
#endif
|
||||
@@ -1361,7 +1361,7 @@ int main()
|
||||
#endif
|
||||
|
||||
#ifdef SOUND_GUS
|
||||
puts("Creating GUS");
|
||||
DBG_PUTS("Creating GUS");
|
||||
GUS_OnReset();
|
||||
multicore_launch_core1(&play_gus);
|
||||
#endif // SOUND_GUS
|
||||
@@ -1373,7 +1373,7 @@ int main()
|
||||
#endif // SOUND_MPU
|
||||
|
||||
#if (SOUND_TANDY || SOUND_CMS)
|
||||
puts("Creating psgsound");
|
||||
DBG_PUTS("Creating psgsound");
|
||||
multicore_launch_core1(&play_psg);
|
||||
#endif // (SOUND_TANDY || SOUND_CMS)
|
||||
|
||||
@@ -1381,14 +1381,14 @@ int main()
|
||||
extern void PIC_ActivateIRQ(void);
|
||||
extern void PIC_DeActivateIRQ(void);
|
||||
|
||||
puts("Creating NE2000");
|
||||
DBG_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");
|
||||
DBG_PUTS("Config joystick PWM");
|
||||
pwm_config pwm_c = pwm_get_default_config();
|
||||
// TODO better calibrate this
|
||||
pwm_config_set_clkdiv(&pwm_c, pwm_clkdiv);
|
||||
@@ -1400,7 +1400,7 @@ extern void PIC_DeActivateIRQ(void);
|
||||
pwm_init(3, &pwm_c, true);
|
||||
#endif // USB_JOYSTICK
|
||||
#ifdef USB_MOUSE
|
||||
puts("Config USB Mouse emulation");
|
||||
DBG_PUTS("Config USB Mouse emulation");
|
||||
uartemu_init(0);
|
||||
sermouse_init(settings.Mouse.protocol, settings.Mouse.reportRate, settings.Mouse.sensitivity);
|
||||
sermouse_attach_uart();
|
||||
@@ -1417,7 +1417,7 @@ extern void PIC_DeActivateIRQ(void);
|
||||
gpio_pull_down(IOCHRDY_PIN);
|
||||
gpio_set_dir(IOCHRDY_PIN, GPIO_OUT);
|
||||
|
||||
puts("Enabling bus transceivers...");
|
||||
DBG_PUTS("Enabling bus transceivers...");
|
||||
// waggle ADS to set BUSOE latch
|
||||
gpio_init(ADS_PIN);
|
||||
gpio_set_dir(ADS_PIN, GPIO_OUT);
|
||||
@@ -1425,23 +1425,23 @@ extern void PIC_DeActivateIRQ(void);
|
||||
busy_wait_ms(10);
|
||||
gpio_put(ADS_PIN, 0);
|
||||
|
||||
puts("Starting ISA bus PIO...");
|
||||
DBG_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);
|
||||
DBG_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);
|
||||
DBG_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");
|
||||
DBG_PUTS("Enabling IRQ on ISA IOR/IOW events");
|
||||
irq_set_enabled(PIO0_IRQ_1, false);
|
||||
pio_set_irq1_source_enabled(pio0, pio_get_rx_fifo_not_empty_interrupt_source(IOW_PIO_SM), true);
|
||||
pio_set_irq1_source_enabled(pio0, pio_get_rx_fifo_not_empty_interrupt_source(IOR_PIO_SM), true);
|
||||
|
||||
+4
-3
@@ -16,9 +16,10 @@
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <math.h>
|
||||
|
||||
#include "include/pg_debug.h"
|
||||
|
||||
#if PICO_ON_DEVICE
|
||||
|
||||
#include "hardware/clocks.h"
|
||||
@@ -107,13 +108,13 @@ struct audio_buffer_pool *init_audio() {
|
||||
}
|
||||
|
||||
void play_psg() {
|
||||
puts("starting core 1 psg");
|
||||
DBG_PUTS("starting core 1 psg");
|
||||
// flash_safe_execute_core_init();
|
||||
|
||||
#if defined(USB_MOUSE) || defined(SOUND_MPU)
|
||||
// Init PIC on this core so it handles timers
|
||||
PIC_Init();
|
||||
puts("pic inited on core 1");
|
||||
DBG_PUTS("pic inited on core 1");
|
||||
#endif
|
||||
#ifdef USB_STACK
|
||||
// Init TinyUSB for joystick support
|
||||
|
||||
+1
-1
Submodule sw/rp2040-psram updated: 7786c93ec8...419375d5af.
+393
-75
@@ -1,10 +1,13 @@
|
||||
#include <inttypes.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdio.h>
|
||||
#include "../include/pg_debug.h"
|
||||
#include <string.h>
|
||||
#include "system/pico_pic.h"
|
||||
#include "audio/volctrl.h"
|
||||
#include "sbdsp.h"
|
||||
#ifdef SOUND_MPU
|
||||
#include "mpu401/export.h"
|
||||
#endif
|
||||
|
||||
/*
|
||||
Title : SoundBlaster DSP Emulation
|
||||
@@ -12,7 +15,7 @@ Date : 2023-12-30
|
||||
Author : Kevin Moonlight <me@yyzkevin.com>
|
||||
|
||||
Copyright (C) 2023 Kevin Moonlight
|
||||
Copyright (C) 2024 Ian Scott
|
||||
Copyright (C) 2024-2026 Ian Scott
|
||||
Copyright (C) 2026 Artem Vasilev
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
@@ -73,7 +76,6 @@ static dma_inst_t dma_config;
|
||||
// Sound Blaster DSP commands.
|
||||
#define DSP_DMA_HS_SINGLE 0x91
|
||||
#define DSP_DMA_HS_AUTO 0x90
|
||||
#define DSP_DMA_ADPCM 0x7F //creative ADPCM 8bit to 3bit
|
||||
#define DSP_DMA_SINGLE 0x14 //follosed by length
|
||||
#define DSP_DMA_AUTO 0X1C //length based on 48h
|
||||
#define DSP_DMA_BLOCK_SIZE 0x48 //block size for highspeed/dma
|
||||
@@ -159,6 +161,116 @@ union sample32 {
|
||||
|
||||
sbdsp_t sbdsp;
|
||||
|
||||
// Creative ADPCM decoders. Each sub-sample is decoded as:
|
||||
// delta = magnitude * accumulator + accumulator/2
|
||||
// reference += +/-delta (clamped to 0..255, sign from the sub-sample's sign bit)
|
||||
// The accumulator doubles on max-magnitude sub-samples (up to a per-format
|
||||
// cap) and halves on zero-magnitude sub-samples (down to 1).
|
||||
//
|
||||
// Algorithm derived from the SB v2.02 DSP firmware disassembly (TubeTime,
|
||||
// https://github.com/schlae/sb-firmware) and VocTool (MIT, Torsten Stremlau).
|
||||
// Not derived from DOSBox/dosbox-x or 86Box.
|
||||
|
||||
// 4-bit: nibble is sign (bit 3) + 3 magnitude bits (bits 2..0).
|
||||
// Accumulator range [1..8].
|
||||
// Structure adapted from VocTool's CreativeAdpcmDecoder4Bit (MIT, Torsten
|
||||
// Stremlau); the sign formula below is inverted relative to VocTool's so that
|
||||
// bit 3 set means subtract, matching the SB DSP firmware convention.
|
||||
static inline uint8_t decode_ADPCM_4_sample(uint8_t bits) {
|
||||
int32_t sign = 1 - ((bits & 8) >> 2); // bit 3 is the sign bit (0 -> +1, 1 -> -1)
|
||||
int32_t data = bits & 7; // the lower 3 bits are the sample data
|
||||
int32_t delta =
|
||||
(data * sbdsp.adpcm.accum) +
|
||||
(sbdsp.adpcm.accum >> 1); // scale sample data using accumulator value
|
||||
int32_t result = sbdsp.adpcm.reference + sign * delta; // calculate the next value
|
||||
if (result > 0xff) result = 0xff; // limit value to 0..255
|
||||
else if (result < 0) result = 0;
|
||||
sbdsp.adpcm.reference = (uint8_t)result;
|
||||
|
||||
if ((data == 0) && (sbdsp.adpcm.accum > 1)) // if input value is 0, and accumulator is
|
||||
sbdsp.adpcm.accum >>= 1; // larger than 1, then halve accumulator.
|
||||
if ((data >= 5) && (sbdsp.adpcm.accum < 8)) // if input value larger than 5, and accumulator is
|
||||
sbdsp.adpcm.accum <<= 1; // lower than 8, then double accumulator.
|
||||
|
||||
return sbdsp.adpcm.reference;
|
||||
}
|
||||
|
||||
// 2.6-bit: 3 samples per byte (3 bits, 3 bits, 2 bits). Accumulator range [1..16].
|
||||
// Caller passes magnitude bits (0..3 for the first two samples, 0..1 for the third)
|
||||
// and sign separately since sign-bit position varies per sub-sample.
|
||||
static inline uint8_t decode_ADPCM_3_sample(uint8_t bits, bool negative) {
|
||||
int32_t sign = negative ? -1 : 1; // sign bit extracted by caller
|
||||
int32_t data = bits; // 0..3, or 0..1 for the final sample
|
||||
int32_t delta =
|
||||
(data * sbdsp.adpcm.accum) +
|
||||
(sbdsp.adpcm.accum >> 1); // scale sample data using accumulator value
|
||||
int32_t result = sbdsp.adpcm.reference + sign * delta; // calculate the next value
|
||||
if (result > 0xff) result = 0xff; // limit value to 0..255
|
||||
else if (result < 0) result = 0;
|
||||
sbdsp.adpcm.reference = (uint8_t)result;
|
||||
|
||||
if ((data == 0) && (sbdsp.adpcm.accum > 1)) // if input value is 0, and accumulator is
|
||||
sbdsp.adpcm.accum >>= 1; // larger than 1, then halve accumulator.
|
||||
if ((data >= 3) && (sbdsp.adpcm.accum < 0x10)) // if input value is 3, and accumulator is
|
||||
sbdsp.adpcm.accum <<= 1; // lower than 0x10, then double accumulator.
|
||||
|
||||
return sbdsp.adpcm.reference;
|
||||
}
|
||||
|
||||
// 2-bit: sign (bit 1) + 1 magnitude bit (bit 0). Accumulator range [1..32].
|
||||
static inline uint8_t decode_ADPCM_2_sample(uint8_t bits) {
|
||||
int32_t sign = 1 - (bits & 2); // bit 1 is the sign bit (0 -> +1, 1 -> -1)
|
||||
int32_t data = bits & 1; // the lower bit is the sample data
|
||||
int32_t delta =
|
||||
(data * sbdsp.adpcm.accum) +
|
||||
(sbdsp.adpcm.accum >> 1); // scale sample data using accumulator value
|
||||
int32_t result = sbdsp.adpcm.reference + sign * delta; // calculate the next value
|
||||
if (result > 0xff) result = 0xff; // limit value to 0..255
|
||||
else if (result < 0) result = 0;
|
||||
sbdsp.adpcm.reference = (uint8_t)result;
|
||||
|
||||
if ((data == 0) && (sbdsp.adpcm.accum > 1)) // if input value is 0, and accumulator is
|
||||
sbdsp.adpcm.accum >>= 1; // larger than 1, then halve accumulator.
|
||||
if ((data >= 1) && (sbdsp.adpcm.accum < 0x20)) // if input value is 1, and accumulator is
|
||||
sbdsp.adpcm.accum <<= 1; // lower than 0x20, then double accumulator.
|
||||
|
||||
return sbdsp.adpcm.reference;
|
||||
}
|
||||
|
||||
// Convert decoded 8-bit unsigned mono sample to packed signed stereo
|
||||
static inline uint32_t adpcm_to_stereo(uint8_t ref) {
|
||||
int16_t s = ((int16_t)(int8_t)(ref ^ 0x80)) << 8;
|
||||
return (uint32_t)(uint16_t)s | ((uint32_t)(uint16_t)s << 16);
|
||||
}
|
||||
|
||||
// Ring buffer helpers
|
||||
static inline uint8_t ring_count() {
|
||||
return (uint8_t)(sbdsp.rs.ring_head - sbdsp.rs.ring_tail);
|
||||
}
|
||||
static inline uint8_t ring_free() {
|
||||
return SB_RING_SIZE - ring_count();
|
||||
}
|
||||
static inline bool ring_empty() {
|
||||
return sbdsp.rs.ring_head == sbdsp.rs.ring_tail;
|
||||
}
|
||||
static inline void ring_push(uint32_t sample) {
|
||||
sbdsp.rs.ring[sbdsp.rs.ring_head & (SB_RING_SIZE - 1)] = sample;
|
||||
sbdsp.rs.ring_head++;
|
||||
}
|
||||
static inline uint32_t ring_pop() {
|
||||
uint32_t s = sbdsp.rs.ring[sbdsp.rs.ring_tail & (SB_RING_SIZE - 1)];
|
||||
sbdsp.rs.ring_tail++;
|
||||
return s;
|
||||
}
|
||||
static inline uint8_t samples_per_transfer() {
|
||||
switch (sbdsp.adpcm.format) {
|
||||
case 4: return 2;
|
||||
case 3: return 3;
|
||||
case 2: return 4;
|
||||
default: return 1;
|
||||
}
|
||||
}
|
||||
|
||||
static uint8_t mixer_state[256] = { 0 };
|
||||
static uint8_t sb_8051_ram[256] = { 0 };
|
||||
|
||||
@@ -171,11 +283,39 @@ void sbdsp_set_wtvol_passthrough(uint8_t *wt_volume, sbmixer_wtvol_cb_t cb) {
|
||||
wtvol_cb = cb;
|
||||
}
|
||||
|
||||
// Fake ADC (recording) - just fire IRQ after the expected transfer time so
|
||||
// programs don't hang, but they will get garbage data
|
||||
static uint32_t DSP_ADC_eventHandler(Bitu val);
|
||||
static PIC_TimerEvent DSP_ADC_event = {
|
||||
.handler = DSP_ADC_eventHandler,
|
||||
};
|
||||
static uint32_t DSP_ADC_eventHandler(Bitu val) {
|
||||
if (!sbdsp.adc_active) return 0;
|
||||
if (sbdsp.dma_16bit) {
|
||||
sbdsp.irq_16_pending = true;
|
||||
} else {
|
||||
sbdsp.irq_8_pending = true;
|
||||
}
|
||||
PIC_ActivateIRQ();
|
||||
// for auto-init, reschedule the next block
|
||||
if (sbdsp.autoinit) {
|
||||
PIC_AddEvent(&DSP_ADC_event, sbdsp.dma_interval * (sbdsp.dma_block_size + 1), 0);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static __force_inline void sbdsp_dma_disable(bool pause) {
|
||||
if (sbdsp.adc_active) {
|
||||
PIC_RemoveEvent(&DSP_ADC_event);
|
||||
if (!pause) sbdsp.adc_active = false;
|
||||
return;
|
||||
}
|
||||
sbdsp.dma_enabled = false;
|
||||
memset(&sbdsp.rsm, 0, sizeof(sbdsp.rsm));
|
||||
sbdsp.rs.dma_pending = false;
|
||||
// sbdsp.cur_sample = 0; // hold last sample to prevent pops!
|
||||
if (!pause) {
|
||||
sbdsp.rs.ring_head = sbdsp.rs.ring_tail = 0;
|
||||
sbdsp.adpcm.format = 0;
|
||||
sbdsp.dma_16bit = false;
|
||||
sbdsp.dma_signed = false;
|
||||
sbdsp.dma_stereo = false;
|
||||
@@ -188,40 +328,20 @@ uint32_t sbdsp_generate_sample() {
|
||||
sbdsp.rs.phase_acc -= (1 << SB_RSM_FRAC);
|
||||
|
||||
// advance interpolation buffer state
|
||||
sbdsp.rs.buf[1] = sbdsp.rs.buf[0];
|
||||
sbdsp.rs.interp[1] = sbdsp.rs.interp[0];
|
||||
|
||||
if (sbdsp.rsm.dma_sample_ready) {
|
||||
// sample ready, advance DMA state
|
||||
sbdsp.rs.buf[0] = sbdsp.rsm.dma_sample;
|
||||
sbdsp.rsm.dma_sample_ready = false;
|
||||
if (!ring_empty()) {
|
||||
sbdsp.rs.interp[0] = ring_pop();
|
||||
}
|
||||
// else: hold last sample (graceful degradation)
|
||||
}
|
||||
|
||||
// is this last sample?
|
||||
sbdsp.dma_xfer_count_left--;
|
||||
if (!sbdsp.dma_xfer_count_left) {
|
||||
// terminal count, current block is finished
|
||||
sbdsp.dma_done = true;
|
||||
if (sbdsp.dma_16bit) {
|
||||
sbdsp.irq_16_pending = true;
|
||||
} else {
|
||||
sbdsp.irq_8_pending = true;
|
||||
}
|
||||
PIC_ActivateIRQ();
|
||||
if (sbdsp.autoinit) {
|
||||
// reload with transfer count
|
||||
sbdsp.dma_xfer_count_left = sbdsp.dma_xfer_count;
|
||||
} else {
|
||||
// stop DMA
|
||||
sbdsp_dma_disable(false);
|
||||
}
|
||||
}
|
||||
|
||||
if (sbdsp.dma_enabled && !sbdsp.rsm.dma_pending) {
|
||||
// request DMA to transfer next sample
|
||||
// TODO: handle rates above 44 KHz (may reqest 2 sample frames per single 44KHz sample)
|
||||
// TODO: handle Creative ADPCM as well
|
||||
sbdsp.rsm.dma_pending = true;
|
||||
DMA_Multi_Start_Write(&dma_config, sbdsp.dma_bytes_per_frame);
|
||||
}
|
||||
// Restart DMA chain if ring drained and DMA still active
|
||||
if (sbdsp.dma_enabled && !sbdsp.rs.dma_pending) {
|
||||
uint8_t samples_per_xfer = samples_per_transfer();
|
||||
if (ring_free() >= samples_per_xfer) {
|
||||
sbdsp.rs.dma_pending = true;
|
||||
DMA_Multi_Start_Write(&dma_config, sbdsp.dma_bytes_per_frame);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -232,21 +352,21 @@ uint32_t sbdsp_generate_sample() {
|
||||
interp0->accum[1] = sbdsp.rs.phase_acc;
|
||||
|
||||
// left channel: older_L in low 16, newer_L in high 16
|
||||
interp0->base01 = (sbdsp.rs.buf[1] & 0xFFFF)
|
||||
| ((sbdsp.rs.buf[0] & 0xFFFF) << 16);
|
||||
interp0->base01 = (sbdsp.rs.interp[1] & 0xFFFF)
|
||||
| ((sbdsp.rs.interp[0] & 0xFFFF) << 16);
|
||||
int32_t out_l = interp0->peek[1];
|
||||
|
||||
// right channel: older_R in low 16, newer_R in high 16
|
||||
interp0->base01 = (sbdsp.rs.buf[1] >> 16)
|
||||
| (sbdsp.rs.buf[0] & 0xFFFF0000);
|
||||
interp0->base01 = (sbdsp.rs.interp[1] >> 16)
|
||||
| (sbdsp.rs.interp[0] & 0xFFFF0000);
|
||||
int32_t out_r = interp0->peek[1];
|
||||
|
||||
return (uint32_t)((out_l & 0xFFFF) | (out_r << 16));
|
||||
#else
|
||||
int32_t l0 = (int16_t)(sbdsp.rs.buf[0] & 0xFFFF);
|
||||
int32_t r0 = (int16_t)(sbdsp.rs.buf[0] >> 16);
|
||||
int32_t l1 = (int16_t)(sbdsp.rs.buf[1] & 0xFFFF);
|
||||
int32_t r1 = (int16_t)(sbdsp.rs.buf[1] >> 16);
|
||||
int32_t l0 = (int16_t)(sbdsp.rs.interp[0] & 0xFFFF);
|
||||
int32_t r0 = (int16_t)(sbdsp.rs.interp[0] >> 16);
|
||||
int32_t l1 = (int16_t)(sbdsp.rs.interp[1] & 0xFFFF);
|
||||
int32_t r1 = (int16_t)(sbdsp.rs.interp[1] >> 16);
|
||||
|
||||
int32_t phase_frac = sbdsp.rs.phase_acc & ((1 << SB_RSM_FRAC) - 1);
|
||||
int32_t out_l = ((l0 * phase_frac) + (l1 * ((1 << SB_RSM_FRAC) - phase_frac))) >> SB_RSM_FRAC;
|
||||
@@ -295,13 +415,17 @@ static __force_inline void sbdsp_set_dma_interval() {
|
||||
}
|
||||
|
||||
static __force_inline void sbdsp_dma_enable() {
|
||||
if (sbdsp.adc_active) {
|
||||
// resume fake ADC
|
||||
PIC_AddEvent(&DSP_ADC_event, sbdsp.dma_interval * (sbdsp.dma_block_size + 1), 0);
|
||||
return;
|
||||
}
|
||||
if (!sbdsp.dma_enabled) {
|
||||
sbdsp.dma_enabled = true;
|
||||
// Set autopush bits to number of bits per audio frame.
|
||||
// 32 will get masked to 0 by this operation which is correct behavior.
|
||||
DMA_Multi_Set_Push_Threshold(&dma_config, sbdsp.dma_bytes_per_frame << 3);
|
||||
memset(&sbdsp.rsm, 0, sizeof(sbdsp.rsm));
|
||||
sbdsp.rsm.dma_pending = true;
|
||||
sbdsp.rs.dma_pending = true;
|
||||
DMA_Multi_Start_Write(&dma_config, sbdsp.dma_bytes_per_frame);
|
||||
}
|
||||
}
|
||||
@@ -310,27 +434,81 @@ static void sbdsp_dma_isr(void) {
|
||||
// dma_write_multi uses right-shift: bytes fill from MSB down.
|
||||
// Complete frame arrives as one push thanks to autopush threshold.
|
||||
const uint32_t dma_data = DMA_Complete_Write(&dma_config);
|
||||
uint32_t sample;
|
||||
if (sbdsp.dma_stereo) {
|
||||
if (sbdsp.dma_16bit) {
|
||||
sample = dma_data;
|
||||
sbdsp.rs.dma_pending = false;
|
||||
|
||||
// Decode and push to ring buffer.
|
||||
// Reference byte case: consumes a DMA byte but pushes no samples.
|
||||
if (sbdsp.adpcm.have_ref) {
|
||||
sbdsp.adpcm.reference = dma_data >> 24;
|
||||
sbdsp.adpcm.accum = 1; // accumulator starts at 1 in SB DSP firmware
|
||||
sbdsp.adpcm.have_ref = false;
|
||||
} else if (sbdsp.adpcm.format == 0) {
|
||||
// PCM decode (existing logic), push 1 sample
|
||||
uint32_t sample;
|
||||
if (sbdsp.dma_stereo) {
|
||||
if (sbdsp.dma_16bit) {
|
||||
sample = dma_data;
|
||||
} else {
|
||||
// 8-bit stereo: L at [23:16], R at [31:24] to MSB of each 16-bit half
|
||||
sample = (dma_data & 0xFF000000) | ((dma_data >> 8) & 0x0000FF00);
|
||||
}
|
||||
} else {
|
||||
// 8-bit stereo: L at [23:16], R at [31:24] to MSB of each 16-bit half
|
||||
sample = (dma_data & 0xFF000000) | ((dma_data >> 8) & 0x0000FF00);
|
||||
if (sbdsp.dma_16bit) {
|
||||
// 16-bit mono: duplicate upper 16 to both halves
|
||||
sample = (dma_data & 0xFFFF0000) | (dma_data >> 16);
|
||||
} else {
|
||||
// 8-bit mono: byte at [31:24], duplicate to MSB of each half
|
||||
sample = (dma_data & 0xFF000000) | ((dma_data >> 16) & 0x0000FF00);
|
||||
}
|
||||
}
|
||||
if (!sbdsp.dma_signed) sample ^= 0x80008000;
|
||||
ring_push(sample);
|
||||
} else {
|
||||
if (sbdsp.dma_16bit) {
|
||||
// 16-bit mono: duplicate upper 16 to both halves
|
||||
sample = (dma_data & 0xFFFF0000) | (dma_data >> 16);
|
||||
} else {
|
||||
// 8-bit mono: byte at [31:24], duplicate to MSB of each half
|
||||
sample = (dma_data & 0xFF000000) | ((dma_data >> 16) & 0x0000FF00);
|
||||
// ADPCM decode: extract samples from byte, push each
|
||||
uint8_t byte = dma_data >> 24; // ADPCM is always 1-byte mono
|
||||
switch (sbdsp.adpcm.format) {
|
||||
case 4: // 4-bit: 2 samples per byte
|
||||
ring_push(adpcm_to_stereo(decode_ADPCM_4_sample(byte >> 4)));
|
||||
ring_push(adpcm_to_stereo(decode_ADPCM_4_sample(byte & 0xf)));
|
||||
break;
|
||||
case 3: // 2.6-bit: 3 samples per byte (3 bits, 3 bits, 2 bits)
|
||||
ring_push(adpcm_to_stereo(decode_ADPCM_3_sample((byte >> 5) & 3, byte & 0x80)));
|
||||
ring_push(adpcm_to_stereo(decode_ADPCM_3_sample((byte >> 2) & 3, byte & 0x10)));
|
||||
ring_push(adpcm_to_stereo(decode_ADPCM_3_sample( byte & 1, byte & 0x02)));
|
||||
break;
|
||||
case 2: // 2-bit: 4 samples per byte
|
||||
ring_push(adpcm_to_stereo(decode_ADPCM_2_sample((byte >> 6) & 3)));
|
||||
ring_push(adpcm_to_stereo(decode_ADPCM_2_sample((byte >> 4) & 3)));
|
||||
ring_push(adpcm_to_stereo(decode_ADPCM_2_sample((byte >> 2) & 3)));
|
||||
ring_push(adpcm_to_stereo(decode_ADPCM_2_sample(byte & 3)));
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!sbdsp.dma_signed) sample ^= 0x80008000;
|
||||
sbdsp.rsm.dma_sample = sample;
|
||||
sbdsp.rsm.dma_sample_ready = true;
|
||||
sbdsp.rsm.dma_pending = false;
|
||||
|
||||
// Transfer counting (runs for all cases including reference byte)
|
||||
sbdsp.dma_xfer_count_left--;
|
||||
if (!sbdsp.dma_xfer_count_left) {
|
||||
sbdsp.dma_done = true;
|
||||
if (sbdsp.dma_16bit) {
|
||||
sbdsp.irq_16_pending = true;
|
||||
} else {
|
||||
sbdsp.irq_8_pending = true;
|
||||
}
|
||||
PIC_ActivateIRQ();
|
||||
if (sbdsp.autoinit) {
|
||||
sbdsp.dma_xfer_count_left = sbdsp.dma_xfer_count;
|
||||
} else {
|
||||
sbdsp.dma_enabled = false;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// Chain next DMA if ring has space
|
||||
uint8_t samples_per_xfer = samples_per_transfer();
|
||||
if (sbdsp.dma_enabled && ring_free() >= samples_per_xfer) {
|
||||
sbdsp.rs.dma_pending = true;
|
||||
DMA_Multi_Start_Write(&dma_config, sbdsp.dma_bytes_per_frame);
|
||||
}
|
||||
}
|
||||
|
||||
static uint32_t DSP_DAC_Resume_eventHandler(Bitu val) {
|
||||
@@ -396,7 +574,7 @@ void sbdsp_set_dma(uint8_t dma) {
|
||||
|
||||
static void sbmixer_reset(void);
|
||||
void sbdsp_init() {
|
||||
puts("Initing ISA DMA PIO...");
|
||||
DBG_PUTS("Initing ISA DMA PIO...");
|
||||
SBDSP_DMA_isr_pt = sbdsp_dma_isr;
|
||||
|
||||
sbdsp.outbox = 0xAA;
|
||||
@@ -436,10 +614,29 @@ static __force_inline void sbdsp_output(uint8_t value) {
|
||||
sbdsp.dav_pc = 1;
|
||||
}
|
||||
|
||||
// start ADPCM DMA transfer
|
||||
static void sbdsp_start_adpcm_dma(int autoinit, uint16_t xfer_size, uint8_t format, bool with_ref) {
|
||||
sbdsp.autoinit = autoinit;
|
||||
sbdsp.adpcm.format = format;
|
||||
sbdsp.adpcm.have_ref = with_ref;
|
||||
sbdsp.adpcm.accum = 1; // SB DSP firmware initializes accumulator to 1 at DMA start
|
||||
// (for have_ref it's overwritten again when the ref byte arrives)
|
||||
sbdsp.dma_16bit = false;
|
||||
sbdsp.dma_signed = false;
|
||||
sbdsp.dma_stereo = false;
|
||||
sbdsp.dma_stereo_sbpro = false;
|
||||
sbdsp.dma_bytes_per_frame = 1; // ADPCM always 1 byte at a time
|
||||
sbdsp.dma_xfer_count = xfer_size + 1; // byte count
|
||||
sbdsp.dma_xfer_count_left = sbdsp.dma_xfer_count;
|
||||
sbdsp_set_dma_interval();
|
||||
sbdsp.dma_done = false;
|
||||
sbdsp_dma_enable();
|
||||
}
|
||||
|
||||
// start pre-SB16 PCM DMA transfer
|
||||
// TODO: Creative ADPCM?
|
||||
static void sbdsp_start_pcm_dma(int autoinit, uint16_t xfer_size) {
|
||||
sbdsp.autoinit = autoinit;
|
||||
sbdsp.adpcm.format = 0; // ensure PCM mode
|
||||
|
||||
bool dma_stereo = (mixer_state[0x0E] & 2);
|
||||
if (dma_stereo && ((xfer_size + 1) == 1)) {
|
||||
@@ -567,6 +764,43 @@ void sbdsp_process(void) {
|
||||
sbdsp.current_command_index++;
|
||||
}
|
||||
break;
|
||||
// Single-cycle ADPCM (2 param bytes: length-1 low, length-1 high)
|
||||
case 0x74: case 0x75: // 4-bit ADPCM / with ref
|
||||
case 0x76: case 0x77: // 2.6-bit ADPCM / with ref
|
||||
case 0x16: case 0x17: // 2-bit ADPCM / with ref
|
||||
if (sbdsp.dav_dsp) {
|
||||
if (sbdsp.current_command_index == 1) {
|
||||
sbdsp.dma_sample_count = sbdsp.inbox;
|
||||
sbdsp.dav_dsp = 0;
|
||||
} else if (sbdsp.current_command_index == 2) {
|
||||
sbdsp.dma_sample_count += (sbdsp.inbox << 8);
|
||||
uint8_t cmd = sbdsp.current_command;
|
||||
uint8_t fmt = (cmd >= 0x74) ? ((cmd <= 0x75) ? 4 : 3) : 2;
|
||||
bool ref = cmd & 1;
|
||||
sbdsp.dav_dsp = 0;
|
||||
sbdsp.current_command = 0;
|
||||
sbdsp_start_adpcm_dma(0, sbdsp.dma_sample_count, fmt, ref);
|
||||
}
|
||||
sbdsp.current_command_index++;
|
||||
}
|
||||
break;
|
||||
// Auto-init ADPCM (no params, use dma_block_size)
|
||||
case 0x7D: // 4-bit ADPCM auto-init
|
||||
sbdsp.dav_dsp = 0;
|
||||
sbdsp.current_command = 0;
|
||||
sbdsp_start_adpcm_dma(1, sbdsp.dma_block_size, 4, true);
|
||||
break;
|
||||
case 0x7F: // 2.6-bit ADPCM auto-init
|
||||
sbdsp.dav_dsp = 0;
|
||||
sbdsp.current_command = 0;
|
||||
sbdsp_start_adpcm_dma(1, sbdsp.dma_block_size, 3, true);
|
||||
break;
|
||||
case 0x1F: // 2-bit ADPCM auto-init
|
||||
sbdsp.dav_dsp = 0;
|
||||
sbdsp.current_command = 0;
|
||||
sbdsp_start_adpcm_dma(1, sbdsp.dma_block_size, 2, true);
|
||||
break;
|
||||
|
||||
case DSP_IRQ_8:
|
||||
sbdsp.current_command = 0;
|
||||
sbdsp.irq_8_pending = true;
|
||||
@@ -684,7 +918,8 @@ void sbdsp_process(void) {
|
||||
} else if (sbdsp.current_command_index == 2) {
|
||||
sbdsp.dac_pause_duration = sbdsp.dac_pause_duration_low + (sbdsp.inbox << 8);
|
||||
sbdsp.dac_resume_pending = true;
|
||||
PIC_AddEvent(&DSP_DAC_Resume_event, sbdsp.dma_interval * sbdsp.dac_pause_duration, 0);
|
||||
// length of pause is samples - 1, so add 1
|
||||
PIC_AddEvent(&DSP_DAC_Resume_event, sbdsp.dma_interval * (sbdsp.dac_pause_duration + 1), 0);
|
||||
sbdsp.dav_dsp = 0;
|
||||
sbdsp.current_command = 0;
|
||||
}
|
||||
@@ -718,6 +953,7 @@ void sbdsp_process(void) {
|
||||
// SB16 DMA transfer
|
||||
if (sbdsp.dav_dsp) {
|
||||
if (sbdsp.current_command_index == 0) { // bCommand + bMode
|
||||
sbdsp.adpcm.format = 0; // SB16 commands are always PCM
|
||||
sbdsp.dma_16bit = (sbdsp.current_command & 0xf0) == 0xb0;
|
||||
sbdsp.autoinit = sbdsp.current_command & 0x4;
|
||||
sbdsp.dma_signed = sbdsp.inbox & 0x10;
|
||||
@@ -747,16 +983,23 @@ void sbdsp_process(void) {
|
||||
// SB16: sample_count counts individual DMA transfers minus 1.
|
||||
// Each DMA event transfers one complete frame, so for stereo
|
||||
// we halve the count (2 DMA words per stereo frame).
|
||||
sbdsp.dma_xfer_count = sbdsp.dma_stereo
|
||||
? (sbdsp.dma_sample_count + 1) >> 1
|
||||
: sbdsp.dma_sample_count + 1;
|
||||
sbdsp.dma_xfer_count_left = sbdsp.dma_xfer_count;
|
||||
sbdsp.dav_dsp = 0;
|
||||
sbdsp.current_command = 0;
|
||||
sbdsp.speaker_on = true;
|
||||
sbdsp_set_dma_interval();
|
||||
sbdsp.dma_done = false;
|
||||
sbdsp_dma_enable();
|
||||
if (sbdsp.current_command & 0x8) {
|
||||
// ADC (recording) - schedule fake IRQ, no real DMA
|
||||
sbdsp.adc_active = true;
|
||||
PIC_AddEvent(&DSP_ADC_event, sbdsp.dma_interval * (sbdsp.dma_sample_count + 1), 0);
|
||||
} else {
|
||||
// DAC (playback)
|
||||
sbdsp.dma_xfer_count = sbdsp.dma_stereo
|
||||
? (sbdsp.dma_sample_count + 1) >> 1
|
||||
: sbdsp.dma_sample_count + 1;
|
||||
sbdsp.dma_xfer_count_left = sbdsp.dma_xfer_count;
|
||||
sbdsp.speaker_on = true;
|
||||
sbdsp.dma_done = false;
|
||||
sbdsp_dma_enable();
|
||||
}
|
||||
sbdsp.current_command = 0;
|
||||
}
|
||||
sbdsp.current_command_index++;
|
||||
}
|
||||
@@ -792,6 +1035,62 @@ void sbdsp_process(void) {
|
||||
sbdsp.current_command_index++;
|
||||
}
|
||||
break;
|
||||
// SB MIDI commands
|
||||
case DSP_MIDI_WRITE_POLL: // 0x38: write MIDI byte
|
||||
if (sbdsp.dav_dsp) {
|
||||
if (sbdsp.current_command_index == 1) {
|
||||
#ifdef SOUND_MPU
|
||||
MIDI_RawOutByte(sbdsp.inbox);
|
||||
#endif
|
||||
sbdsp.dav_dsp = 0;
|
||||
sbdsp.current_command = 0;
|
||||
}
|
||||
sbdsp.current_command_index++;
|
||||
}
|
||||
break;
|
||||
case DSP_MIDI_READ_POLL: // 0x30: read MIDI byte
|
||||
if (sbdsp.current_command_index == 0) {
|
||||
sbdsp.current_command = 0;
|
||||
sbdsp_output(0x00); // no MIDI input
|
||||
}
|
||||
break;
|
||||
case 0x31: // MIDI Read Interrupt - accept and ignore
|
||||
case 0xA0: // Disable Stereo Input Mode
|
||||
case 0xA8: // Enable Stereo Input Mode
|
||||
sbdsp.current_command = 0;
|
||||
break;
|
||||
case 0x34: // MIDI UART read+write poll
|
||||
case 0x35: // MIDI UART read interrupt+Write poll
|
||||
sbdsp.midi_uart_mode = true;
|
||||
sbdsp.current_command = 0;
|
||||
break;
|
||||
// recording commands - fake ADC
|
||||
case 0x24: // DMA ADC, 8-bit single-cycle (2 param bytes: length-1)
|
||||
if (sbdsp.dav_dsp) {
|
||||
if (sbdsp.current_command_index == 1) {
|
||||
sbdsp.dma_sample_count = sbdsp.inbox;
|
||||
sbdsp.dav_dsp = 0;
|
||||
} else if (sbdsp.current_command_index == 2) {
|
||||
sbdsp.dma_sample_count += (sbdsp.inbox << 8);
|
||||
sbdsp.dav_dsp = 0;
|
||||
sbdsp.current_command = 0;
|
||||
sbdsp.autoinit = 0;
|
||||
sbdsp.dma_16bit = false;
|
||||
sbdsp.adc_active = true;
|
||||
sbdsp_set_dma_interval();
|
||||
PIC_AddEvent(&DSP_ADC_event, sbdsp.dma_interval * (sbdsp.dma_sample_count + 1), 0);
|
||||
}
|
||||
sbdsp.current_command_index++;
|
||||
}
|
||||
break;
|
||||
case 0x2C: // autoinit DMA ADC, 8-bit
|
||||
sbdsp.current_command = 0;
|
||||
sbdsp.autoinit = 1;
|
||||
sbdsp.dma_16bit = false;
|
||||
sbdsp.adc_active = true;
|
||||
sbdsp_set_dma_interval();
|
||||
PIC_AddEvent(&DSP_ADC_event, sbdsp.dma_interval * (sbdsp.dma_block_size + 1), 0);
|
||||
break;
|
||||
case 0:
|
||||
//not in a command
|
||||
break;
|
||||
@@ -816,6 +1115,8 @@ static uint32_t DSP_Reset_EventHandler(Bitu val) {
|
||||
sbdsp.speaker_on = (sbdsp.dsp_version.major >= 4); // SB16 speaker always on
|
||||
sbdsp.dma_done = false;
|
||||
sbdsp.dac_resume_pending = false;
|
||||
memset(&sbdsp.adpcm, 0, sizeof(sbdsp.adpcm));
|
||||
sbdsp.rs.ring_head = sbdsp.rs.ring_tail = 0;
|
||||
|
||||
sbdsp.outbox = 0xAA;
|
||||
sbdsp.dav_pc = 1;
|
||||
@@ -834,6 +1135,7 @@ static __force_inline void sbdsp_reset(uint8_t value) {
|
||||
while (sbdsp.dsp_busy) tight_loop_contents(); // TODO timeout!!!!!!
|
||||
sbdsp.reset_state = 1;
|
||||
sbdsp.autoinit = 0;
|
||||
sbdsp.midi_uart_mode = false;
|
||||
sbdsp_dma_disable(false);
|
||||
break;
|
||||
case 0:
|
||||
@@ -954,7 +1256,12 @@ static void sbmixer_16_set(uint8_t sb16_reg, uint8_t value) {
|
||||
}
|
||||
|
||||
static void sbmixer_reset(void) {
|
||||
// preserve IRQ/DMA select registers across mixer reset
|
||||
uint8_t saved_irq = mixer_state[MIXER_INTERRUPT];
|
||||
uint8_t saved_dma = mixer_state[MIXER_DMA];
|
||||
memset(mixer_state, 0, sizeof(mixer_state));
|
||||
mixer_state[MIXER_INTERRUPT] = saved_irq;
|
||||
mixer_state[MIXER_DMA] = saved_dma;
|
||||
|
||||
// initialize default values
|
||||
sbmixer_pro_set(MIXER_VOL_MASTER, 0xFF);
|
||||
@@ -1010,6 +1317,10 @@ static __force_inline void sbmixer_write(uint8_t value) {
|
||||
case 0x00: // Mixer reset
|
||||
sbmixer_reset();
|
||||
break;
|
||||
case 0x02: // SBPro Master Volume alias (chains to 0x22)
|
||||
mixer_state[0x02] = value;
|
||||
sbmixer_pro_set(MIXER_VOL_MASTER, value);
|
||||
break;
|
||||
case MIXER_VOL_MASTER:
|
||||
case MIXER_VOL_MIDI:
|
||||
case MIXER_VOL_CD:
|
||||
@@ -1057,7 +1368,7 @@ uint8_t sbdsp_read(uint8_t address) {
|
||||
PIC_DeActivateIRQ();
|
||||
}
|
||||
return (sbdsp.dav_pc << 7) | DSP_UNUSED_STATUS_BITS_PULLED_HIGH;
|
||||
case DSP_IRQ_16_STATUS: // +0xD
|
||||
case DSP_IRQ_16_STATUS: // +0xF
|
||||
if (sbdsp.irq_16_pending) {
|
||||
sbdsp.irq_16_pending = false;
|
||||
PIC_DeActivateIRQ();
|
||||
@@ -1079,7 +1390,14 @@ void sbdsp_write(uint8_t address, uint8_t value) {
|
||||
switch (address) {
|
||||
case DSP_WRITE: // 0xC
|
||||
case DSP_WRITE+1: // 0xD
|
||||
if (sbdsp.dav_dsp) printf("WARN - DAV_DSP OVERWRITE\n");
|
||||
// in MIDI UART mode, all writes to DSP data port are MIDI output
|
||||
if (sbdsp.midi_uart_mode) {
|
||||
#ifdef SOUND_MPU
|
||||
MIDI_RawOutByte(value);
|
||||
#endif
|
||||
break;
|
||||
}
|
||||
if (sbdsp.dav_dsp) DBG_PRINTF("WARN - DAV_DSP OVERWRITE\n");
|
||||
sbdsp.inbox = value;
|
||||
sbdsp.dav_dsp = 1;
|
||||
break;
|
||||
|
||||
+18
-19
@@ -97,32 +97,31 @@ typedef struct sbdsp_t {
|
||||
#define SB_RSM_FRAC 12
|
||||
|
||||
volatile uint32_t cur_sample; // packed stereo pair: L in low 16, R in high 16
|
||||
#if 0
|
||||
|
||||
// ADPCM decode state
|
||||
struct {
|
||||
uint32_t old_sample;
|
||||
uint32_t new_sample;
|
||||
volatile uint32_t dma_sample;
|
||||
volatile bool dma_sample_ready;
|
||||
bool dma_pending; // a DMA transfer is in flight
|
||||
int32_t samplecnt;
|
||||
} rsm; // resampling state, memset to zero on start/stop
|
||||
#else
|
||||
uint8_t reference; // current output level 0-255
|
||||
uint8_t accum; // accumulator (1..32 depending on format)
|
||||
uint8_t format; // 0=PCM, 2=2-bit, 3=2.6-bit, 4=4-bit ADPCM
|
||||
bool have_ref; // next DMA byte is reference byte
|
||||
} adpcm;
|
||||
|
||||
#define SB_RING_SIZE 8
|
||||
|
||||
struct {
|
||||
int32_t phase_acc;
|
||||
uint32_t buf[2]; // sample buffer, used for linear interpolation
|
||||
uint32_t interp[2]; // interpolation buffer [0]=newer [1]=older
|
||||
|
||||
// DMA stuff
|
||||
// TODO: make it a very short (max. 8 samples) ring buffer for Creative ADPCM
|
||||
// and rates slightly higher than 44100Hz (SB16 cap is 45454Hz)
|
||||
uint32_t ring[SB_RING_SIZE]; // decoded sample ring buffer
|
||||
volatile uint8_t ring_head; // ISR writes here
|
||||
uint8_t ring_tail; // consumer reads here
|
||||
volatile bool dma_pending; // a DMA transfer is in flight
|
||||
} rs;
|
||||
struct {
|
||||
volatile uint32_t dma_sample;
|
||||
volatile bool dma_sample_ready;
|
||||
bool dma_pending; // a DMA transfer is in flight
|
||||
} rsm;
|
||||
#endif
|
||||
|
||||
int32_t rateratio;
|
||||
|
||||
bool midi_uart_mode; // DSP MIDI UART mode (commands 0x34/0x35)
|
||||
bool adc_active; // fake ADC recording in progress (timer-based, no real DMA)
|
||||
} sbdsp_t;
|
||||
|
||||
void sbdsp_init();
|
||||
|
||||
+4
-3
@@ -16,9 +16,10 @@
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <math.h>
|
||||
|
||||
#include "include/pg_debug.h"
|
||||
|
||||
#if PICO_ON_DEVICE
|
||||
|
||||
#include "hardware/clocks.h"
|
||||
@@ -223,7 +224,7 @@ void audio_sample_handler(void) {
|
||||
}
|
||||
|
||||
void play_adlib() {
|
||||
puts("starting core 1");
|
||||
DBG_PUTS("starting core 1");
|
||||
// flash_safe_execute_core_init();
|
||||
uint32_t start, end;
|
||||
set_volume(CMD_OPLVOL);
|
||||
@@ -274,7 +275,7 @@ void play_adlib() {
|
||||
set_volume(CMD_SBVOL);
|
||||
#endif
|
||||
|
||||
printf("OPL stereo pipeline started\n");
|
||||
DBG_PRINTF("OPL stereo pipeline started\n");
|
||||
|
||||
#ifdef CDROM
|
||||
cd_fifo = cdrom_audio_fifo_peek(&cdrom);
|
||||
|
||||
@@ -17,9 +17,9 @@
|
||||
*/
|
||||
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include "flash_settings.h"
|
||||
#include "../include/pg_debug.h"
|
||||
#include "overclock.h"
|
||||
#include "hardware/flash.h"
|
||||
#include "hardware/sync.h"
|
||||
@@ -173,13 +173,13 @@ static void migrateSettings(Settings* settings, uint8_t oldVersion) {
|
||||
|
||||
void loadSettings(Settings* settings, bool migrate)
|
||||
{
|
||||
printf("copying settings to %u from %u with size %u\n", settings, XIP_BASE + SETTINGS_SECTOR, sizeof(Settings));
|
||||
DBG_PRINTF("copying settings to %u from %u with size %u\n", settings, XIP_BASE + SETTINGS_SECTOR, sizeof(Settings));
|
||||
memcpy(settings, (void *)(XIP_BASE + SETTINGS_SECTOR), sizeof(Settings));
|
||||
/* stdio_flush(); */
|
||||
|
||||
if (settings->magic != SETTINGS_MAGIC || settings->version > SETTINGS_VERSION) {
|
||||
// No valid settings found, use defaults
|
||||
puts("No valid settings found, using defaults");
|
||||
DBG_PUTS("No valid settings found, using defaults");
|
||||
stdio_flush();
|
||||
memcpy(settings, &defaultSettings, sizeof(Settings));
|
||||
return;
|
||||
@@ -187,7 +187,7 @@ void loadSettings(Settings* settings, bool migrate)
|
||||
|
||||
if (migrate && settings->version < SETTINGS_VERSION) {
|
||||
// Older version found - preserve existing fields, apply defaults to new ones
|
||||
printf("Migrating settings from version %d to %d\n", settings->version, SETTINGS_VERSION);
|
||||
DBG_PRINTF("Migrating settings from version %d to %d\n", settings->version, SETTINGS_VERSION);
|
||||
stdio_flush();
|
||||
migrateSettings(settings, settings->version);
|
||||
}
|
||||
@@ -201,20 +201,20 @@ void saveSettings(const Settings* settings)
|
||||
uint8_t data[FLASH_PAGE_SIZE] = {0};
|
||||
static_assert(sizeof(Settings) < FLASH_PAGE_SIZE, "Settings struct doesn't fit inside one flash page");
|
||||
memcpy(data, settings, sizeof(Settings));
|
||||
printf("doing settings save: ");
|
||||
DBG_PRINTF("doing settings save: ");
|
||||
// No need for flash_safe_execute or stop second core, since it will not touch flash
|
||||
// If the 2nd core will ever touch flash, reconsider this approach!
|
||||
// Clock down the RP2040 so the flash at its default 1/2 clock divider is within spec (<=133MHz)
|
||||
set_sys_clock_khz(240000, true);
|
||||
|
||||
putchar('/');
|
||||
DBG_PUTCHAR('/');
|
||||
uint32_t ints = save_and_disable_interrupts();
|
||||
flash_range_erase(SETTINGS_SECTOR, FLASH_SECTOR_SIZE); // last sector
|
||||
putchar('/');
|
||||
DBG_PUTCHAR('/');
|
||||
flash_range_program(SETTINGS_SECTOR, data, FLASH_PAGE_SIZE);
|
||||
restore_interrupts(ints);
|
||||
overclock_370mhz();
|
||||
printf("settings saved");
|
||||
DBG_PRINTF("settings saved");
|
||||
}
|
||||
|
||||
void getDefaultSettings(Settings* settings)
|
||||
|
||||
@@ -18,8 +18,8 @@
|
||||
|
||||
#include "pico_reflash.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <hardware/flash.h>
|
||||
#include "../include/pg_debug.h"
|
||||
#include "hardware/clocks.h"
|
||||
#include "pico/multicore.h"
|
||||
#include "pico/stdlib.h"
|
||||
@@ -61,15 +61,15 @@ static void pico_firmware_process_block(void)
|
||||
{
|
||||
if (uf2_buf.uf2.magicStart0 != 0x0A324655 || uf2_buf.uf2.magicStart1 != 0x9E5D5157 || uf2_buf.uf2.magicEnd != 0x0AB16F30) {
|
||||
// Invalid UF2 file
|
||||
puts("Invalid UF2 data!");
|
||||
ERR_PUTS("Invalid UF2 data!");
|
||||
pico_firmware_reset(PICO_FIRMWARE_ERROR);
|
||||
return;
|
||||
}
|
||||
pico_firmware_status = PICO_FIRMWARE_BUSY;
|
||||
if (pico_firmware_curBlock == 0) {
|
||||
puts("Starting firmware write...");
|
||||
DBG_PUTS("Starting firmware write...");
|
||||
pico_firmware_numBlocks = uf2_buf.uf2.numBlocks;
|
||||
printf("numBlocks: %u\n", pico_firmware_numBlocks);
|
||||
DBG_PRINTF("numBlocks: %u\n", pico_firmware_numBlocks);
|
||||
pico_firmware_payloadSize = uf2_buf.uf2.payloadSize;
|
||||
uint32_t totalSize = pico_firmware_numBlocks * pico_firmware_payloadSize;
|
||||
// Point of no return... erasing the flash!
|
||||
@@ -81,11 +81,11 @@ static void pico_firmware_process_block(void)
|
||||
uint32_t ints = save_and_disable_interrupts();
|
||||
flash_range_program(curAddress, uf2_buf.uf2.data, pico_firmware_payloadSize);
|
||||
restore_interrupts(ints);
|
||||
printf("curBlock: %u\n", pico_firmware_curBlock);
|
||||
DBG_PRINTF("curBlock: %u\n", pico_firmware_curBlock);
|
||||
++pico_firmware_curBlock;
|
||||
if (pico_firmware_curBlock == pico_firmware_numBlocks) {
|
||||
// Final block has been written
|
||||
puts("Final block written.");
|
||||
DBG_PUTS("Final block written.");
|
||||
pico_firmware_status = PICO_FIRMWARE_DONE;
|
||||
} else {
|
||||
pico_firmware_status = PICO_FIRMWARE_WRITING;
|
||||
@@ -99,7 +99,7 @@ void pico_firmware_write(uint8_t data)
|
||||
}
|
||||
|
||||
void firmware_loop() {
|
||||
puts("starting core 1");
|
||||
DBG_PUTS("starting core 1");
|
||||
|
||||
for (;;) {
|
||||
if (!multicore_fifo_rvalid()) {
|
||||
@@ -120,7 +120,7 @@ void firmware_loop() {
|
||||
|
||||
static void pico_firmware_reboot()
|
||||
{
|
||||
puts("Rebooting!");
|
||||
DBG_PUTS("Rebooting!");
|
||||
// Stop second core
|
||||
multicore_reset_core1();
|
||||
// Go back to stock speed
|
||||
|
||||
+10
-9
@@ -25,6 +25,7 @@
|
||||
*
|
||||
*/
|
||||
|
||||
#include "../include/pg_debug.h"
|
||||
#include "tusb.h"
|
||||
#ifdef USB_JOYSTICK
|
||||
#include "xinput_host.h"
|
||||
@@ -208,19 +209,19 @@ static inline void process_sony_ds4(uint8_t const* report, uint16_t len)
|
||||
// therefore report_desc = NULL, desc_len = 0
|
||||
void tuh_hid_mount_cb(uint8_t dev_addr, uint8_t instance, uint8_t const* desc_report, uint16_t desc_len)
|
||||
{
|
||||
printf("HID dev:%d inst:%d mounted\r\n", dev_addr, instance);
|
||||
DBG_PRINTF("HID dev:%d inst:%d mounted\r\n", dev_addr, instance);
|
||||
|
||||
// Interface protocol (hid_interface_protocol_enum_t)
|
||||
const char* protocol_str[] = { "n/a", "kbd", "mouse" };
|
||||
uint8_t const itf_protocol = tuh_hid_interface_protocol(dev_addr, instance);
|
||||
|
||||
printf("HID protocol=%s\r\n", protocol_str[itf_protocol]);
|
||||
DBG_PRINTF("HID protocol=%s\r\n", protocol_str[itf_protocol]);
|
||||
|
||||
// By default host stack will use activate boot protocol on supported interface.
|
||||
// Therefore for this simple example, we only need to parse generic report descriptor (with built-in parser)
|
||||
if (itf_protocol == HID_ITF_PROTOCOL_NONE) {
|
||||
hid_info[instance].report_count = tuh_hid_parse_report_descriptor(hid_info[instance].report_info, MAX_REPORT, desc_report, desc_len);
|
||||
printf("HID has %u reports \r\n", hid_info[instance].report_count);
|
||||
DBG_PRINTF("HID has %u reports \r\n", hid_info[instance].report_count);
|
||||
} else {
|
||||
// force boot protocol
|
||||
tuh_hid_set_protocol(dev_addr, instance, HID_PROTOCOL_BOOT);
|
||||
@@ -229,14 +230,14 @@ void tuh_hid_mount_cb(uint8_t dev_addr, uint8_t instance, uint8_t const* desc_re
|
||||
// request to receive report
|
||||
// tuh_hid_report_received_cb() will be invoked when report is available
|
||||
if (!tuh_hid_receive_report(dev_addr, instance)) {
|
||||
printf("err(%d:%d) can't recv HID report\r\n", dev_addr, instance);
|
||||
DBG_PRINTF("err(%d:%d) can't recv HID report\r\n", dev_addr, instance);
|
||||
}
|
||||
}
|
||||
|
||||
// Invoked when device with hid interface is un-mounted
|
||||
void tuh_hid_umount_cb(uint8_t dev_addr, uint8_t instance)
|
||||
{
|
||||
printf("HID dev:%d inst:%d unmounted\r\n", dev_addr, instance);
|
||||
DBG_PRINTF("HID dev:%d inst:%d unmounted\r\n", dev_addr, instance);
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
@@ -276,7 +277,7 @@ static inline void process_generic_report(uint8_t dev_addr, uint8_t instance, ui
|
||||
}
|
||||
|
||||
if (!rpt_info) {
|
||||
printf("Couldn't find the report info for this report !\r\n");
|
||||
DBG_PRINTF("Couldn't find the report info for this report !\r\n");
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -332,7 +333,7 @@ void tuh_hid_report_received_cb(uint8_t dev_addr, uint8_t instance, uint8_t cons
|
||||
|
||||
// continue to request to receive report
|
||||
if (!tuh_hid_receive_report(dev_addr, instance)) {
|
||||
printf("err(%d:%d) can't recv HID report\r\n", dev_addr, instance);
|
||||
DBG_PRINTF("err(%d:%d) can't recv HID report\r\n", dev_addr, instance);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -390,7 +391,7 @@ void tuh_xinput_report_received_cb(uint8_t dev_addr, uint8_t instance, xinputh_i
|
||||
|
||||
void tuh_xinput_mount_cb(uint8_t dev_addr, uint8_t instance, const xinputh_interface_t *xinput_itf)
|
||||
{
|
||||
printf("XINPUT MOUNTED %02x %d\n", dev_addr, instance);
|
||||
DBG_PRINTF("XINPUT MOUNTED %02x %d\n", dev_addr, instance);
|
||||
// If this is a Xbox 360 Wireless controller we need to wait for a connection packet
|
||||
// on the in pipe before setting LEDs etc. So just start getting data until a controller is connected.
|
||||
if (xinput_itf->type == XBOX360_WIRELESS && xinput_itf->connected == false) {
|
||||
@@ -434,6 +435,6 @@ void tuh_xinput_mount_cb(uint8_t dev_addr, uint8_t instance, const xinputh_inter
|
||||
|
||||
void tuh_xinput_umount_cb(uint8_t dev_addr, uint8_t instance)
|
||||
{
|
||||
printf("XINPUT UNMOUNTED %02x %d\n", dev_addr, instance);
|
||||
DBG_PRINTF("XINPUT UNMOUNTED %02x %d\n", dev_addr, instance);
|
||||
}
|
||||
#endif
|
||||
+3
-3
@@ -16,7 +16,7 @@
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include "include/pg_debug.h"
|
||||
|
||||
#include "tusb.h"
|
||||
#include "mouse/8250uart.h"
|
||||
@@ -77,14 +77,14 @@ struct audio_buffer_pool *init_audio() {
|
||||
#endif // CDROM
|
||||
|
||||
void play_usb() {
|
||||
puts("starting core 1 USB");
|
||||
DBG_PUTS("starting core 1 USB");
|
||||
// flash_safe_execute_core_init();
|
||||
|
||||
// board_init();
|
||||
|
||||
// Init PIC on this core so it handles timers
|
||||
PIC_Init();
|
||||
puts("pic inited on core 1");
|
||||
DBG_PUTS("pic inited on core 1");
|
||||
|
||||
// init host stack on configured roothub port
|
||||
tuh_init(BOARD_TUH_RHPORT);
|
||||
|
||||
Reference in new issue
Block a user