|
| 1 | +/* |
| 2 | + * USBSID-Pico is a RPi Pico/PicoW (RP2040) & Pico2/Pico2W (RP2350) based board |
| 3 | + * for interfacing one or two MOS SID chips and/or hardware SID emulators over |
| 4 | + * (WEB)USB with your computer, phone or ASID supporting player |
| 5 | + * |
| 6 | + * sid_detection.c |
| 7 | + * This file is part of USBSID-Pico (https://github.com/LouDnl/USBSID-Pico) |
| 8 | + * File author: LouD |
| 9 | + * |
| 10 | + * Copyright (c) 2024-2025 LouD |
| 11 | + * |
| 12 | + * This program is free software: you can redistribute it and/or modify |
| 13 | + * it under the terms of the GNU General Public License as published by |
| 14 | + * the Free Software Foundation, version 2. |
| 15 | + * |
| 16 | + * This program is distributed in the hope that it will be useful, but |
| 17 | + * WITHOUT ANY WARRANTY; without even the implied warranty of |
| 18 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
| 19 | + * General Public License for more details. |
| 20 | + * |
| 21 | + * You should have received a copy of the GNU General Public License |
| 22 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
| 23 | + * |
| 24 | + */ |
| 25 | + |
| 26 | +#include "globals.h" |
| 27 | +#include "config.h" |
| 28 | +#include "usbsid.h" |
| 29 | +#include "sid.h" |
| 30 | +#include "logging.h" |
| 31 | +#include "sid_fpgasid.h" |
| 32 | +#include "sid_skpico.h" |
| 33 | + |
| 34 | + |
| 35 | +/* GPIO */ |
| 36 | +extern void __no_inline_not_in_flash_func(cycled_write_operation)(uint8_t address, uint8_t data, uint16_t cycles); |
| 37 | +extern uint8_t __no_inline_not_in_flash_func(cycled_read_operation)(uint8_t address, uint16_t cycles); |
| 38 | +void reset_sid(void); |
| 39 | + |
| 40 | +/* Config */ |
| 41 | +extern Config usbsid_config; |
| 42 | +extern RuntimeCFG cfg; |
| 43 | + |
| 44 | +/* Config logging */ |
| 45 | +extern void print_cfg(const uint8_t *buf, size_t len); |
| 46 | +extern char *sidtypes[5]; |
| 47 | + |
| 48 | +/* Init local variables */ |
| 49 | +static uint8_t skpico_config[64] = {0xFF}; |
| 50 | +static const char * error_type[1] = {"ERROR"}; |
| 51 | + |
| 52 | + |
| 53 | +void print_fpgasid_sidconfig(int slot, int sidno, uint8_t * configarray) |
| 54 | +{ |
| 55 | + int extin = ((configarray[2] & 0b11000000) >> 6); |
| 56 | + int readb = ((configarray[2] & 0b110000) >> 4); |
| 57 | + int regd = ((configarray[2] & 0b1000) >> 3); |
| 58 | + int mixw = ((configarray[2] & 0b100) >> 2); |
| 59 | + int crunch = ((configarray[2] & 0b10) >> 1); |
| 60 | + int fltr = (configarray[2] & 0b1); |
| 61 | + int outp = ((configarray[1] & 0b1000) >> 3); |
| 62 | + int addr1 = (((configarray[1] & 0b100) >> 2) == 1 ? 1 : 4); |
| 63 | + int addr2 = (((configarray[1] & 0b10) >> 1) == 1 ? 2 : 4); |
| 64 | + int addr3 = ((configarray[1] & 0b1) == 1 ? 3 : 4); |
| 65 | + int addr = ((addr1 + addr2 + addr3) == 0 ? 12 : 4); |
| 66 | + |
| 67 | + CFG("\n"); |
| 68 | + CFG("[FPGASID CURRENT CONFIG SLOT%s SID %d]\n", slots[slot], sidno); |
| 69 | + if (sidno == 1) { |
| 70 | + CFG("OUTPUT MODE: %s\n", outputmode[outp]); |
| 71 | + CFG("SID2 ADDRESSES: %s%s%s%s\n", sid2addr[addr], sid2addr[addr1], sid2addr[addr2], sid2addr[addr3]); |
| 72 | + } |
| 73 | + CFG("SOURCE EXTIN: %s\n", extinsource[extin]); |
| 74 | + CFG("REGISTER READ: %s\n", readback[readb]); |
| 75 | + CFG("REGISTER DELAY: %s\n", regdelay[regd]); |
| 76 | + CFG("MIXED WAVEFORM: %s\n", mixedwave[mixw]); |
| 77 | + CFG("CRUNCHY DAC: %s\n", crunchydac[crunch]); |
| 78 | + CFG("ANALOG FILTER: %s\n", filtermode[fltr]); |
| 79 | + CFG("DIGIFIX VALUE: %02X\n", configarray[0]); |
| 80 | +} |
| 81 | + |
| 82 | +void read_fpgasid_configuration(uint8_t base_address) |
| 83 | +{ |
| 84 | + |
| 85 | + if (((base_address >= 0x0 && base_address < 0x40) && (usbsid_config.socketOne.clonetype != 4)) |
| 86 | + || ((base_address >= 0x40 && base_address < 0x80) && (usbsid_config.socketTwo.clonetype != 4))) { |
| 87 | + CFG("[SID] ERROR INCORRECT ADDRESS (0x%02x) AND CLONETYPE (%d %d)\n", |
| 88 | + base_address, usbsid_config.socketOne.clonetype, usbsid_config.socketTwo.clonetype); |
| 89 | + return; /* Do nothing if no FPGASID configured */ |
| 90 | + } |
| 91 | + uint8_t idHi, idLo, cpld, fpga, pca, select_pins, idxa, idxb, flta, fltb; |
| 92 | + float frequency = 0.0; |
| 93 | + uint8_t unique_id[8]; |
| 94 | + uint8_t sid_one_a[3]; |
| 95 | + uint8_t sid_two_a[3]; |
| 96 | + uint8_t sid_one_b[3]; |
| 97 | + uint8_t sid_two_b[3]; |
| 98 | + CFG("[SID] READING CONFIGURATION FROM FPGASID @ 0x%02X\n", base_address); |
| 99 | + /* Enable diag mode */ |
| 100 | + cycled_write_operation((0x19 + base_address), 0xEE, 6); /* Write magic cookie Hi */ |
| 101 | + cycled_write_operation((0x1A + base_address), 0xAB, 6); /* Write magic cookie Lo */ |
| 102 | + |
| 103 | + /* Double check that we are actually data from an FPGASID */ |
| 104 | + idLo = cycled_read_operation((0x0 + base_address), 4); /* Read identify Hi */ |
| 105 | + idHi = cycled_read_operation((0x1 + base_address), 4); /* Read identify Lo */ |
| 106 | + uint16_t fpgasid_id = (idHi << 8 | idLo); |
| 107 | + if (fpgasid_id != FPGASID_IDENTIFIER) { |
| 108 | + CFG("[SID] ERROR: 0x%04X != 0x%04X FPGASID NOT FOUND @ 0x%02X\n", fpgasid_id, FPGASID_IDENTIFIER, base_address); |
| 109 | + return; |
| 110 | + } |
| 111 | + |
| 112 | + /* Start diag config read */ |
| 113 | + cpld = cycled_read_operation((0x02 + base_address), 4); /* Read clpd revision */ |
| 114 | + fpga = cycled_read_operation((0x03 + base_address), 4); /* Read fpga revision */ |
| 115 | + pca = cycled_read_operation((0x0D + base_address), 4); /* Read pca revision */ |
| 116 | + select_pins = cycled_read_operation((0x0D + base_address), 4); /* Read select pins */ |
| 117 | + for (int i = 0; i < 8; i++) { |
| 118 | + unique_id[i] = cycled_read_operation(((0x04 + base_address) + i), 4); /* Read unique identifier */ |
| 119 | + } |
| 120 | + idxa = cycled_read_operation((0x1B + base_address), 4); /* Read config index A revision */ |
| 121 | + idxb = cycled_read_operation((0x1C + base_address), 4); /* Read config index B revision */ |
| 122 | + flta = cycled_read_operation((0x1D + base_address), 4); /* Read filterbias A revision */ |
| 123 | + fltb = cycled_read_operation((0x1E + base_address), 4); /* Read filterbias B revision */ |
| 124 | + /* 0 digifix, 1 stereo, 2 mode */ |
| 125 | + for (int i = 0; i < 3; i++) { |
| 126 | + sid_one_a[i] = cycled_read_operation(((0x0F + base_address) + i), 4); /* Read SID1 A config */ |
| 127 | + } |
| 128 | + for (int i = 0; i < 3; i++) { |
| 129 | + sid_two_a[i] = cycled_read_operation(((0x12 + base_address) + i), 4); /* Read SID2 A config */ |
| 130 | + } |
| 131 | + for (int i = 0; i < 3; i++) { |
| 132 | + sid_one_b[i] = cycled_read_operation(((0x15 + base_address) + i), 4); /* Read SID1 B config */ |
| 133 | + } |
| 134 | + for (int i = 0; i < 3; i++) { |
| 135 | + sid_two_b[i] = cycled_read_operation(((0x18 + base_address) + i), 4); /* Read SID2 B config */ |
| 136 | + } |
| 137 | + for (int i = 0; i < 10; i++) { |
| 138 | + frequency += cycled_read_operation((0x0C + base_address), 4); /* Read Ø2 frequency */ |
| 139 | + } |
| 140 | + frequency /= 10; // 10 reads |
| 141 | + frequency *= 12.5; // kHz |
| 142 | + frequency /= 1000; // to uS |
| 143 | + |
| 144 | + /* Exit diag mode */ |
| 145 | + cycled_write_operation((0x19 + base_address), 0x0, 6); /* Clear magic cookie Hi */ |
| 146 | + cycled_write_operation((0x1A + base_address), 0x0, 6); /* Clear magic cookie Lo */ |
| 147 | + |
| 148 | + CFG("\n"); |
| 149 | + CFG("[FPGASID DIAGNOSTIC RESULT]\n"); |
| 150 | + CFG("ID: %04X (FPGASID)\n", fpgasid_id); |
| 151 | + CFG("CPLD REVISION: %02X\n", cpld); |
| 152 | + CFG("FPGA REVISION: %02X\n", fpga); |
| 153 | + CFG("PCA REVISION: %02X\n", pca); |
| 154 | + CFG("UNIQUE IDENTIFIER: %02X%02X%02X%02X%02X%02X%02X%02X\n", |
| 155 | + unique_id[0], unique_id[1], unique_id[2], unique_id[3], unique_id[4], unique_id[5], unique_id[6], unique_id[7]); |
| 156 | + CFG("CLOCK FREQUENCY READS: %.3f uS\n", frequency); |
| 157 | + CFG("SELECT PINS: %02X\n", select_pins); |
| 158 | + CFG("INDEX CFG A: %02X\n", idxa); |
| 159 | + CFG("SID 1 A: %02X%02X%02X\n", sid_one_a[0], sid_one_a[1], sid_one_a[2]); |
| 160 | + CFG("SID 2 A: %02X%02X%02X\n", sid_two_a[0], sid_two_a[1], sid_two_a[2]); |
| 161 | + CFG("FILTERBIAS A SID1/SID2: %02X\n", flta); |
| 162 | + CFG("INDEX CFG B: %02X\n", idxb); |
| 163 | + CFG("SID 1 B: %02X%02X%02X\n", sid_one_b[0], sid_one_b[1], sid_one_b[2]); |
| 164 | + CFG("SID 2 B: %02X%02X%02X\n", sid_two_b[0], sid_two_b[1], sid_two_b[2]); |
| 165 | + CFG("FILTERBIAS B SID1/SID2: %02X\n", fltb); |
| 166 | + |
| 167 | + print_fpgasid_sidconfig(0, 1, sid_one_a); |
| 168 | + print_fpgasid_sidconfig(0, 2, sid_two_a); |
| 169 | + print_fpgasid_sidconfig(1, 1, sid_one_b); |
| 170 | + print_fpgasid_sidconfig(1, 2, sid_two_b); |
| 171 | + |
| 172 | + CFG("\n"); |
| 173 | + |
| 174 | + return; |
| 175 | +} |
| 176 | + |
| 177 | +void print_skpico_configuration(uint8_t base_address, uint8_t * configarray) |
| 178 | +{ |
| 179 | + |
| 180 | + CFG("\n"); |
| 181 | + printf("[SIDKICK-pico @ 0x%02X CONFIG]\n", base_address); |
| 182 | + for (size_t i = 0; i < 64; i++) { |
| 183 | + if (i >= 4 && i <= 7) continue; |
| 184 | + if (i >= 13 && i <= 56) continue; |
| 185 | + if (i == 62 || i == 63) continue; |
| 186 | + if (i == 0 || i == 8) { |
| 187 | + printf("[%02ld] %s: %02X ~ %s\n", i, config_names[i], configarray[i], (configarray[i] < s_sid_types) ? (char*)sid_types[configarray[i]] : (char*)error_type[0]); |
| 188 | + continue; |
| 189 | + } |
| 190 | + if (i == 10) { |
| 191 | + printf("[%02ld] %s: %02X ~ %s\n", i, config_names[i], configarray[i], (configarray[i] < s_sid2_address) ? (char*)sid2_address[configarray[i]] : (char*)error_type[0]); |
| 192 | + continue; |
| 193 | + } |
| 194 | + if (i == 59) { |
| 195 | + printf("[%02ld] %s: %02X ~ %s\n", i, config_names[i], configarray[i], (configarray[i] < s_clock_speed) ? (char*)clock_speed[configarray[i]] : (char*)error_type[0]); |
| 196 | + continue; |
| 197 | + } |
| 198 | + printf("[%02ld] %s: %02X\n", i, config_names[i], configarray[i]); |
| 199 | + } |
| 200 | + printf("[PRINT CFG SETTINGS END]\n"); |
| 201 | +} |
| 202 | + |
| 203 | +void read_skpico_configuration(uint8_t base_address) |
| 204 | +{ |
| 205 | + /* Enter config mode */ |
| 206 | + cycled_write_operation((init_configmode[0] + base_address), init_configmode[1], 6); |
| 207 | + /* printf("[W]$%02X:%02X\n", (init_configmode[0] + base_address), init_configmode[1]); */ |
| 208 | + |
| 209 | + /* Read config from SKPico */ |
| 210 | + for (int i = 0; i <= 63; ++i) { |
| 211 | + sleep_us(1); |
| 212 | + skpico_config[i] = cycled_read_operation((0x1D + base_address), 0); |
| 213 | + /* printf("[R%d]$%02X:%02X\n", i, (0x1D + base_address), skpico_config[i]); */ |
| 214 | + } |
| 215 | + |
| 216 | + /* Exit config mode */ |
| 217 | + cycled_write_operation((config_exit[0] + base_address), config_exit[1], 6); |
| 218 | + /* printf("[W]$%02X:%02X\n", (config_exit[0] + base_address), config_exit[1]); */ |
| 219 | + |
| 220 | + CFG("\n"); |
| 221 | + CFG("[SKPICO RECEIVED BUFFER]\n"); |
| 222 | + print_cfg(skpico_config, 64); |
| 223 | + |
| 224 | + print_skpico_configuration(base_address, skpico_config); |
| 225 | + CFG("\n"); |
| 226 | + |
| 227 | +} |
0 commit comments