diff --git a/.gitignore b/.gitignore
index c29d90d..5488b0c 100644
--- a/.gitignore
+++ b/.gitignore
@@ -13,6 +13,7 @@
!*.pdf
!*.html
!*.yml
+!*.zip
# specific files
!.gitignore
@@ -32,6 +33,8 @@
!examples/sidberry
!examples/vice
!examples/hardsid-sidblaster
+!cases
+!cases/**
# folder contents
!examples/hardsid-sidblaster/**
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 43989e1..9888be2 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,15 +1,19 @@
# Changelog
-#### Version: 0.3.0-BETA (Unreleased)
+#### Version: 0.2.?-BETA (SNAPSHOT)
* ...
* Beam me up Scotty!
* Continue work on Midi handling
+
+#### Version: 0.2.3-BETA
+* Add workflow for auto version release build
* Fix issue in SID tests not stopping
- * Add Support for Pico2 (rp2350) green board
+* Add Support for Pico2 (rp2350) green board
* Add Support for PicoW (rp2040) green board
- NOTE: Due to the LED being used by the WiFi chip there is no VU support
* Rename Vue to Vu 🤦♀️
* Remove `__builtin_` function calls
+
#### Version: 0.2.2-BETA
* Add direct SID functions
- Detect SID type
@@ -28,11 +32,13 @@
* Enable CC's for bank 9 (temporary workaround)
* Refactor some whitespace
* Start work on support for PicoW and Pico2 boards
+
#### Version: 0.2.1-BETA
* Start on update for Midi handling
* Details will follow at a later time when finished
* Fix ASID play
* Fix config save error
+
#### Version: 0.2.0-BETA
* Basic Midi support
* Fixed to 6 voices polyfonic with 2 SID's up to 12 voices with 2x SKPico.
@@ -42,6 +48,7 @@
* Improved GPIO handling
* Bus control via DMA and PIO for cycle exact writes and reads
* Customizable config (config tool in development)
+
#### Version: 0.0.1-ALPHA
* Basic working functions
* Multiple firmware binaries per config type
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 735d91d..c119c89 100755
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -29,7 +29,7 @@ cmake_minimum_required(VERSION 3.17)
set(PROJECT_NAME usbsidpico)
set(PROJECT_MANUFACTURER "LouD")
set(PRODUCT_STRING "USBSID-Pico")
-set(MAGIC_SMOKE "20241208")
+set(MAGIC_SMOKE "20241220")
set(PROJECT_VERSION "0.2.3-BETA.${MAGIC_SMOKE}") # Must be the same as in config.h
### Want a cookie?
@@ -224,6 +224,7 @@ set(SOURCEFILES
${CMAKE_CURRENT_LIST_DIR}/src/sid.c
${CMAKE_CURRENT_LIST_DIR}/src/mcu.c
${CMAKE_CURRENT_LIST_DIR}/src/usb_descriptors.c
+ ${CMAKE_CURRENT_LIST_DIR}/src/util.c
)
### Libraries to link
@@ -245,6 +246,7 @@ set(TARGET_LL
pico_stdlib
pico_unique_id
pico_usb_reset_interface
+ pico_async_context_threadsafe_background
tinyusb_device
tinyusb_board
)
diff --git a/README.md b/README.md
index 1e32175..4dab9ab 100644
--- a/README.md
+++ b/README.md
@@ -12,6 +12,7 @@ USBSID-Pico is a RPi Pico/PicoW (RP2040) & Pico2 (RP2350) based board for interf
* [Hardware](#hardware)
* [Where to buy](#where-to-buy)
* [Schematic and BOM](#schematic-and-bom)
+ * [Cases](#cases)
* [Important PCB information](#important-pcb-information)
* [PCB in action](#usbsid-pico-in-action)
* [Software examples](#software)
@@ -94,8 +95,8 @@ See the [firmware changelog](CHANGELOG.md) for more information on what's change
### Firmware versions
Use `usbsidpico.uf2` for Pico1 regular green rp2040 Pico boards.
Use `usbsidpico-rgb.uf2` for Pico1 black clone rp2040 Pico boards with RGB LED onboard.
-Use `usbsidpico_w.uf2` for PicoW regular green rp2040 Pico boards.
-Use `usbsidpico2.uf2` for Pico2 regular green rp2040 Pico boards.
+Use `usbsidpico_w.uf2` for PicoW regular green rp2040 PicoW boards.
+Use `usbsidpico2.uf2` for Pico2 regular green rp2350 Pico2 boards.
**WARNING!** Do _NOT_ use the RGB firmware for any of the (non black) rp2040 or rp2350 Pico boards that do not contain an RGB LED.
### How to flash
A Raspberry Pi Pico board is incredibly easy to flash, as it comes with a built in bootloader for flashing new firmwares in the `uf2` format.
@@ -177,6 +178,10 @@ If you want and are up to it you can create your own development board by using
* v0.1 testboard
+## Cases
+All USBSID-Pico community created cases are available in the [cases](cases/) folder, direct links below.
+* [Cartridge case](cases/spotUP/USBSID-Pico_Case.zip) by @spotUP
+
## Important PCB information
[](images/v1.0-explained.png)
_Click image for larger view_
diff --git a/cases/spotUP/USBSID-Pico_Case.zip b/cases/spotUP/USBSID-Pico_Case.zip
new file mode 100644
index 0000000..8489930
Binary files /dev/null and b/cases/spotUP/USBSID-Pico_Case.zip differ
diff --git a/src/asid.c b/src/asid.c
index 2d690a5..b993342 100644
--- a/src/asid.c
+++ b/src/asid.c
@@ -39,6 +39,7 @@
/* GPIO externals */
extern uint8_t bus_operation(uint8_t command, uint8_t address, uint8_t data);
extern void pause_sid(void);
+extern void reset_sid(void);
/* Well, it does what it does */
void handle_asid_message(uint8_t sid, uint8_t* buffer, int size)
@@ -66,27 +67,28 @@ void handle_asid_message(uint8_t sid, uint8_t* buffer, int size)
void decode_asid_message(uint8_t* buffer, int size)
{
switch(buffer[2]) {
- case 0x4C:
- /* Play start */
+ case 0x4C: /* Play start */
midimachine.bus = CLAIMED;
break;
- case 0x4D:
- /* Play stop */
+ case 0x4D: /* Play stop */
+ reset_sid();
pause_sid();
midimachine.bus = FREE;
break;
- case 0x4F:
- /* Display characters */
+ case 0x4F: /* Display characters */
break;
- case 0x4E:
+ case 0x4E: /* SID 1 */
handle_asid_message(0, buffer, size);
break;
- case 0x50:
+ case 0x50: /* SID 2 */
handle_asid_message(32, buffer, size);
break;
- case 0x51:
+ case 0x51: /* SID 3 */
handle_asid_message(64, buffer, size);
break;
+ case 0x52: /* SID 4 */
+ handle_asid_message(96, buffer, size);
+ break;
case 0x60:
midimachine.fmopl = 1; /* Not implemented yet */
default:
diff --git a/src/config.c b/src/config.c
index b779af2..7b20382 100644
--- a/src/config.c
+++ b/src/config.c
@@ -23,7 +23,9 @@
*
*/
-#include
+
+#include "hardware/gpio.h"
+#include "hardware/pio.h"
#include "globals.h"
#include "config.h"
@@ -42,6 +44,8 @@ extern char dtype;
extern uint8_t *cdc_itf;
extern uint8_t *wusb_itf;
extern uint8_t *write_buffer_p;
+extern double clk_rate, sidfrq, frqpow;
+extern uint8_t sid_memory[];
/* SID externals */
extern uint8_t detect_sid_version(uint8_t start_addr);
@@ -52,7 +56,6 @@ extern void restart_bus(void);
/* Midi externals */
extern void midi_bus_operation(uint8_t a, uint8_t b);
-extern int curr_midi_channel;
/* MCU externals */
extern void mcu_reset(void);
@@ -65,6 +68,15 @@ uint8_t one, two, three, four;
const char* project_version = PROJECT_VERSION;
static uint8_t p_version_array[MAX_BUFFER_SIZE];
+/* Init string vars */
+const char *sidtypes[4] = { "UNKNOWN", "N/A", "MOS8580", "MOS6581" };
+const char *chiptypes[2] = { "Real", "Clone" };
+const char *clonetypes[6] = { "Disabled", "Other", "SKPico", "ARMSID", "FPGASID", "RedipSID" };
+const char *int_ext[2] = { "Internal", "External" };
+const char *en_dis[2] = { "Enabled", "Disabled" };
+const char *true_false[2] = { "True", "False" };
+const char *single_dual[2] = { "Dual SID", "Single SID" };
+
#define USBSID_DEFAULT_CONFIG_INIT { \
.magic = MAGIC_SMOKE, \
.default_config = 1, \
@@ -73,13 +85,19 @@ static uint8_t p_version_array[MAX_BUFFER_SIZE];
.socketOne = { \
.enabled = true, \
.dualsid = false, \
- .sidtype = 0x0, /* empty */ \
+ .chiptype = 0x0, /* real */ \
+ .clonetype = 0x0, /* disabled */ \
+ .sid1type = 0x0, /* unknown */ \
+ .sid2type = 0x0, /* unknown */ \
}, \
.socketTwo = { \
.enabled = true, \
.dualsid = false, \
.act_as_one = false, \
- .sidtype = 0x0, /* empty */ \
+ .chiptype = 0x0, /* real */ \
+ .clonetype = 0x0, /* disabled */ \
+ .sid1type = 0x0, /* unknown */ \
+ .sid2type = 0x0, /* unknown */ \
}, \
.LED = { \
.enabled = true, \
@@ -111,12 +129,12 @@ void print_cfg(const uint8_t *buf, size_t len) {
CFG("[PRINT CFG START]\n");
for (size_t i = 0; i < len; ++i) {
if (i == 0)
- CFG("[R%d] ", i);
+ CFG("[R%03d] ", i);
CFG("%02x", buf[i]);
if (i == (len - 1)) {
CFG("\n");
- } else if (i % 16 == 15) {
- CFG("\n[R%d] ", i);
+ } else if ((i != 0) && (i % 16 == 15)) {
+ CFG("\n[R%03d] ", i);
} else {
CFG(" ");
}
@@ -126,30 +144,70 @@ void print_cfg(const uint8_t *buf, size_t len) {
void detect_sid_types(void)
{
- const char *sidtypes[4] = {"NONE", "CLONE", "MOS8580", "MOS6581"};
- int sid1 = 0, sid2 = 0;
- if (usbsid_config.socketOne.enabled) {
+ int sid1 = 0, sid2 = 0, sid3 = 0, sid4 = 0;
+
+ if (numsids >= 1) {
sid1 = detect_sid_version(0x00);
- usbsid_config.socketOne.sidtype = sid1;
- } else {
- usbsid_config.socketOne.sidtype = 0;
+ CFG("[READ SID1] [%02x %s]\n", sid1, sidtypes[sid1]);
+ }
+ if (numsids >= 2) {
+ sid2 = detect_sid_version(0x20);
+ CFG("[READ SID2] [%02x %s]\n", sid2, sidtypes[sid2]);
+ }
+ if (numsids >= 3) {
+ sid3 = detect_sid_version(0x40);
+ CFG("[READ SID3] [%02x %s]\n", sid3, sidtypes[sid3]);
+ }
+ if (numsids == 4) {
+ sid4 = detect_sid_version(0x60);
+ CFG("[READ SID4] [%02x %s]\n", sid4, sidtypes[sid4]);
}
- if (usbsid_config.socketTwo.enabled) {
+
+ if (usbsid_config.socketOne.enabled && usbsid_config.socketTwo.enabled) {
+ if (usbsid_config.socketOne.dualsid && usbsid_config.socketTwo.dualsid) {
+ usbsid_config.socketOne.sid1type = sid1;
+ usbsid_config.socketOne.sid2type = sid2;
+ usbsid_config.socketTwo.sid1type = sid3;
+ usbsid_config.socketTwo.sid2type = sid4;
+ }
+ if (!usbsid_config.socketOne.dualsid && usbsid_config.socketTwo.dualsid) {
+ usbsid_config.socketOne.sid1type = sid1;
+ usbsid_config.socketOne.sid2type = 1;
+ usbsid_config.socketTwo.sid1type = sid2;
+ usbsid_config.socketTwo.sid2type = sid3;
+ }
+ if (usbsid_config.socketOne.dualsid && !usbsid_config.socketTwo.dualsid) {
+ usbsid_config.socketOne.sid1type = sid1;
+ usbsid_config.socketOne.sid2type = sid2;
+ usbsid_config.socketTwo.sid1type = sid3;
+ usbsid_config.socketTwo.sid2type = 1;
+ }
+ } else if (usbsid_config.socketOne.enabled && !usbsid_config.socketTwo.enabled) {
+ usbsid_config.socketTwo.sid1type = 1;
+ usbsid_config.socketTwo.sid2type = 1;
if (usbsid_config.socketOne.dualsid) {
- sid2 = detect_sid_version(0x40);
- usbsid_config.socketTwo.sidtype = sid2;
- } else {
- sid2 = detect_sid_version(0x20);
- usbsid_config.socketTwo.sidtype = sid2;
+ usbsid_config.socketOne.sid1type = sid1;
+ usbsid_config.socketOne.sid2type = sid2;
+ } else if (!usbsid_config.socketOne.dualsid) {
+ usbsid_config.socketOne.sid1type = sid1;
+ usbsid_config.socketOne.sid2type = 1;
+ }
+ } else if (!usbsid_config.socketOne.enabled && usbsid_config.socketTwo.enabled) {
+ usbsid_config.socketOne.sid1type = 1;
+ usbsid_config.socketOne.sid2type = 1;
+ if (usbsid_config.socketTwo.dualsid) {
+ usbsid_config.socketTwo.sid1type = sid1;
+ usbsid_config.socketTwo.sid2type = sid2;
+ } else if (!usbsid_config.socketTwo.dualsid) {
+ usbsid_config.socketTwo.sid1type = sid1;
+ usbsid_config.socketTwo.sid2type = 1;
}
- } else {
- usbsid_config.socketTwo.sidtype = 0;
}
- CFG("[SOCKET ONE] %s\n", sidtypes[usbsid_config.socketOne.sidtype]);
- CFG("[SOCKET TWO] %s\n", sidtypes[usbsid_config.socketTwo.sidtype]);
- CFG("[READ SID1] [%02x %s]\n", sid1, sidtypes[sid1]);
- CFG("[READ SID2] [%02x %s]\n", sid2, sidtypes[sid2]);
+ CFG("[SOCKET ONE SID1 TYPE] %s\n", sidtypes[usbsid_config.socketOne.sid1type]);
+ CFG("[SOCKET ONE SID2 TYPE] %s\n", sidtypes[usbsid_config.socketOne.sid2type]);
+ CFG("[SOCKET TWO SID1 TYPE] %s\n", sidtypes[usbsid_config.socketTwo.sid1type]);
+ CFG("[SOCKET TWO SID2 TYPE] %s\n", sidtypes[usbsid_config.socketTwo.sid2type]);
}
void read_config(Config* config)
@@ -163,11 +221,17 @@ void read_config(Config* config)
config_array[9] = config->clock_rate & BYTE;
config_array[10] = (int)config->socketOne.enabled;
config_array[11] = (int)config->socketOne.dualsid;
- config_array[12] = config->socketOne.sidtype;
+ config_array[12] = config->socketOne.chiptype;
+ config_array[13] = config->socketOne.clonetype;
+ config_array[14] = config->socketOne.sid1type;
+ config_array[15] = config->socketOne.sid2type;
config_array[20] = (int)config->socketTwo.enabled;
config_array[21] = (int)config->socketTwo.dualsid;
- config_array[22] = config->socketTwo.sidtype;
- config_array[23] = (int)config->socketTwo.act_as_one;
+ config_array[22] = (int)config->socketTwo.act_as_one;
+ config_array[23] = config->socketTwo.chiptype;
+ config_array[24] = config->socketTwo.clonetype;
+ config_array[25] = config->socketTwo.sid1type;
+ config_array[26] = config->socketTwo.sid2type;
config_array[30] = (int)config->LED.enabled;
config_array[31] = (int)config->LED.idle_breathe;
config_array[40] = (int)config->RGBLED.enabled;
@@ -195,7 +259,7 @@ void default_config(Config* config)
void load_config(Config* config)
{
- CFG("[COPY CONFIG] [FROM]0x%x [TO]0x%x [SIZE]%u\n", XIP_BASE + FLASH_TARGET_OFFSET, (uint)&config, sizeof(Config));
+ CFG("[COPY CONFIG] [FROM]0x%x [TO]0x%x [SIZE]%u\n", XIP_BASE + FLASH_TARGET_OFFSET, (uint)&config, sizeof(Config));
memcpy(config, (void *)(XIP_BASE + FLASH_TARGET_OFFSET), sizeof(Config));
stdio_flush();
if (config->magic != MAGIC_SMOKE) {
@@ -245,19 +309,12 @@ void handle_config_request(uint8_t * buffer)
/* TODO: loads current config and sends it to the requester ~ when config is finished */
/* ISSUE: Although 4 writes are performed, only the first 2 are received */
CFG("[XIP_BASE]%u [FLASH_PAGE_SIZE]%u [FLASH_SECTOR_SIZE]%u [FLASH_TARGET_OFFSET]%u\r\n", XIP_BASE, FLASH_PAGE_SIZE, FLASH_SECTOR_SIZE, FLASH_TARGET_OFFSET);
- CFG("[>]\r\n");
read_config(&usbsid_config);
print_cfg(config_array, count_of(config_array));
- CFG("[<]\r\n");
int writes = count_of(config_array) / 64; /* BUG: It should send 4 packets of 64 bytes, but sends only 2 and a zero packet */
- CFG("[>] SEND %d WRITES OF 64 BYTES TO %c [<]\n", writes, dtype);
memset(write_buffer_p, 0, 64);
for (int i = 0; i < writes; i++) {
memcpy(write_buffer_p, config_array + (i * 64), 64);
- CFG("[>] SEND WRITE %d OF %d [<]\n", i, writes);
- CFG("[>]");
- for (int i = 0; i < 64; i++) CFG(" %x", write_buffer_p[i]);
- CFG(" [<]\n");
switch (dtype) {
case 'C':
cdc_write(cdc_itf, 64);
@@ -280,14 +337,54 @@ void handle_config_request(uint8_t * buffer)
usbsid_config.clock_rate = clockrates[(int)buffer[2]];
break;
case 1: /* socketOne */
+ switch (buffer[2]) {
+ case 0: /* enabled */
+ if (buffer[3] <= 1) { /* 1 or 0 */
+ usbsid_config.socketOne.enabled = (buffer[3] == 1) ? true : false;
+ };
+ break;
+ case 1: /* dualsid */
+ if (buffer[3] <= 1) { /* 1 or 0 */
+ usbsid_config.socketOne.dualsid = (buffer[3] == 1) ? true : false;
+ };
+ break;
+ case 2: /* chiptype */
+ case 3: /* clonetype */
+ case 4: /* sid1type */
+ case 5: /* sid2type */
+ break;
+ };
break;
case 2: /* socketTwo */
+ switch (buffer[2]) {
+ case 0: /* enabled */
+ if (buffer[3] <= 1) { /* 1 or 0 */
+ usbsid_config.socketTwo.enabled = (buffer[3] == 1) ? true : false;
+ };
+ break;
+ case 1: /* dualsid */
+ if (buffer[3] <= 1) { /* 1 or 0 */
+ usbsid_config.socketTwo.dualsid = (buffer[3] == 1) ? true : false;
+ };
+ break;
+ case 2: /* act_as_one */
+ if (buffer[3] <= 1) { /* 1 or 0 */
+ usbsid_config.socketTwo.act_as_one = (buffer[3] == 1) ? true : false;
+ };
+ break;
+ case 3: /* chiptype */
+ case 4: /* clonetype */
+ case 5: /* sid1type */
+ case 6: /* sid2type */
+ break;
+ };
break;
case 3: /* LED */
switch (buffer[2]) {
case 0: /* enabled */
- if (buffer[3] <= 1) /* 1 or 0 */
+ if (buffer[3] <= 1) { /* 1 or 0 */
usbsid_config.LED.enabled = (buffer[3] == 1) ? true : false;
+ };
break;
case 1: /* idle_breathe */
if (buffer[3] <= 1) { /* 1 or 0 */
@@ -300,7 +397,7 @@ void handle_config_request(uint8_t * buffer)
break;
default:
break;
- }
+ };
break;
case 4: /* RGBLED */
switch (buffer[2]) {
@@ -344,7 +441,7 @@ void handle_config_request(uint8_t * buffer)
case 8: /* MIDI */
default:
break;
- }
+ };
break;
case SAVE_CONFIG:
CFG("[SAVE_CONFIG] and RESET_MCU\n");
@@ -371,8 +468,6 @@ void handle_config_request(uint8_t * buffer)
usbsid_config.socketTwo.enabled = false;
usbsid_config.socketOne.dualsid = false;
usbsid_config.socketTwo.dualsid = false;
- usbsid_config.socketOne.sidtype = 0;
- usbsid_config.socketTwo.sidtype = 0;
usbsid_config.socketTwo.act_as_one = true;
save_config(&usbsid_config);
load_config(&usbsid_config);
@@ -384,8 +479,6 @@ void handle_config_request(uint8_t * buffer)
usbsid_config.socketTwo.enabled = true;
usbsid_config.socketOne.dualsid = false;
usbsid_config.socketTwo.dualsid = false;
- usbsid_config.socketOne.sidtype = 1;
- usbsid_config.socketTwo.sidtype = 1;
usbsid_config.socketTwo.act_as_one = false;
save_config(&usbsid_config);
load_config(&usbsid_config);
@@ -397,8 +490,6 @@ void handle_config_request(uint8_t * buffer)
usbsid_config.socketTwo.enabled = true;
usbsid_config.socketOne.dualsid = true;
usbsid_config.socketTwo.dualsid = true;
- usbsid_config.socketOne.sidtype = 1;
- usbsid_config.socketTwo.sidtype = 1;
usbsid_config.socketTwo.act_as_one = false;
save_config(&usbsid_config);
load_config(&usbsid_config);
@@ -410,8 +501,6 @@ void handle_config_request(uint8_t * buffer)
usbsid_config.socketTwo.enabled = true;
usbsid_config.socketOne.dualsid = true;
usbsid_config.socketTwo.dualsid = false;
- usbsid_config.socketOne.sidtype = 1;
- usbsid_config.socketTwo.sidtype = 1;
usbsid_config.socketTwo.act_as_one = false;
save_config(&usbsid_config);
mcu_reset();
@@ -464,9 +553,14 @@ void handle_config_request(uint8_t * buffer)
if (clockrates[(int)buffer[1]] != usbsid_config.clock_rate) {
CFG("[CLOCK FROM]%d [CLOCK TO]%d\n", usbsid_config.clock_rate, clockrates[(int)buffer[1]]);
usbsid_config.clock_rate = clockrates[(int)buffer[1]];
+ /* Cycled write buffer vars */
+ clk_rate = usbsid_config.clock_rate;
+ sidfrq = (clk_rate / 1000 / 1000);
+ frqpow = (1 / sidfrq);
+ /* Start clock set */
deinit_sidclock();
init_sidclock();
- /* restart_bus(); */ /* TODO: Enable after bus_clock change */
+ restart_bus();
} else {
CFG("[CLOCK FROM]%d AND [CLOCK TO]%d ARE THE SAME, SKIPPING SET_CLOCK\n", usbsid_config.clock_rate, clockrates[(int)buffer[1]]);
}
@@ -533,6 +627,9 @@ void handle_config_request(uint8_t * buffer)
printf("A %x %x %d\n", (uint32_t)usbsid_config.magic, (uint32_t)MAGIC_SMOKE, usbsid_config.magic != MAGIC_SMOKE);
printf("A %d %d\n", (int)usbsid_config.magic, (int)MAGIC_SMOKE);
printf("A %d\n", usbsid_config.magic == MAGIC_SMOKE);
+
+ printf("[USBSID_SID_MEMORY]\n");
+ print_cfg(sid_memory, (numsids * 0x20));
break;
default:
break;
@@ -542,65 +639,132 @@ void handle_config_request(uint8_t * buffer)
void apply_config(void)
{
/* Debug logging */
- CFG("[CONFIG LOG START]\n");
- CFG("[USBSID VERSION]%s\n", project_version);
- CFG("[CLOCK] %s @%d\n", ((int)usbsid_config.external_clock == 0 ? "Internal" : "External"), (int)usbsid_config.clock_rate);
- CFG("[SOCKET ONE] %s as %s\n",((int)usbsid_config.socketOne.enabled == 1 ? "Enabled" : "Disabled"), ((int)usbsid_config.socketOne.dualsid == 1 ? "Dual SID" : "Single SID"));
- CFG("[SOCKET TWO] %s as %s\n",((int)usbsid_config.socketTwo.enabled == 1 ? "Enabled" : "Disabled"), ((int)usbsid_config.socketTwo.dualsid == 1 ? "Dual SID" : "Single SID"));
- CFG("[SOCKET TWO AS ONE] %s\n", ((int)usbsid_config.socketTwo.act_as_one == 1 ? "True" : "False"));
- CFG("[LED] %s, Idle breathe? %s\n", ((int)usbsid_config.LED.enabled == 1 ? "Enabled" : "Disabled"), ((int)usbsid_config.LED.idle_breathe == 1 ? "True" : "False"));
- CFG("[RGBLED] %s, Idle breathe? %s\n", ((int)usbsid_config.RGBLED.enabled == 1 ? "Enabled" : "Disabled"), ((int)usbsid_config.RGBLED.idle_breathe == 1 ? "True" : "False"));
- CFG("[RGBLED BRIGHTNESS] %d\n", (int)usbsid_config.RGBLED.brightness);
- CFG("[CDC] %s\n",((int)usbsid_config.Cdc.enabled == 1 ? "Enabled" : "Disabled"));
- CFG("[WebUSB] %s\n",((int)usbsid_config.WebUSB.enabled == 1 ? "Enabled" : "Disabled"));
- CFG("[Asid] %s\n",((int)usbsid_config.Asid.enabled == 1 ? "Enabled" : "Disabled"));
- CFG("[Midi] %s\n",((int)usbsid_config.Midi.enabled == 1 ? "Enabled" : "Disabled"));
- CFG("[CONFIG LOG END]\n");
-
- CFG("[APPLY CONFIG START]\n");
+ CFG("[PICO] PICO_PIO_VERSION = %d\n", PICO_PIO_VERSION); // pio.h PICO_PIO_VERSION
+ #if defined(PICO_DEFAULT_LED_PIN)
+ CFG("[PICO] PICO_DEFAULT_LED_PIN = %d\n", PICO_DEFAULT_LED_PIN); // pio.h PICO_PIO_VERSION
+ #elif defined(CYW43_WL_GPIO_LED_PIN)
+ CFG("[PICO] CYW43_WL_GPIO_LED_PIN = %d\n", CYW43_WL_GPIO_LED_PIN); // pio.h PICO_PIO_VERSION
+ #endif
+ CFG("[PICO] LED_PWM = %d\n", LED_PWM); // pio.h PICO_PIO_VERSION
+ CFG("[CONFIG] PRINT SETTINGS START\n");
+ CFG("[CONFIG] [USBSID VERSION] %s\n", project_version);
+
+ CFG("[CONFIG] [CLOCK] %s @%d\n",
+ ((int)usbsid_config.external_clock == 0 ? int_ext[0] : int_ext[1]),
+ (int)usbsid_config.clock_rate);
+
+ CFG("[CONFIG] [SOCKET ONE] %s as %s\n",
+ ((int)usbsid_config.socketOne.enabled == 1 ? en_dis[0] : en_dis[1]),
+ ((int)usbsid_config.socketOne.dualsid == 1 ? single_dual[0] : single_dual[1]));
+ CFG("[CONFIG] [SOCKET ONE] CHIP TYPE: %s, CLONE TYPE: %s\n",
+ chiptypes[usbsid_config.socketOne.chiptype],
+ clonetypes[usbsid_config.socketOne.clonetype]);
+ CFG("[CONFIG] [SOCKET ONE] SID 1 TYPE: %s, SID 2 TYPE: %s\n",
+ sidtypes[usbsid_config.socketOne.sid1type],
+ sidtypes[usbsid_config.socketOne.sid2type]);
+ CFG("[CONFIG] [SOCKET TWO] %s as %s\n",
+ ((int)usbsid_config.socketTwo.enabled == 1 ? en_dis[0] : en_dis[1]),
+ ((int)usbsid_config.socketTwo.dualsid == 1 ? single_dual[0] : single_dual[1]));
+ CFG("[CONFIG] [SOCKET TWO] CHIP TYPE: %s, CLONE TYPE: %s\n",
+ chiptypes[usbsid_config.socketTwo.chiptype],
+ clonetypes[usbsid_config.socketTwo.clonetype]);
+ CFG("[CONFIG] [SOCKET TWO] SID 1 TYPE: %s, SID 2 TYPE: %s\n",
+ sidtypes[usbsid_config.socketTwo.sid1type],
+ sidtypes[usbsid_config.socketTwo.sid2type]);
+ CFG("[CONFIG] [SOCKET TWO AS ONE] %s\n",
+ ((int)usbsid_config.socketTwo.act_as_one == 1 ? true_false[0] : true_false[1]));
+
+ CFG("[CONFIG] [LED] %s, Idle breathe? %s\n",
+ ((int)usbsid_config.LED.enabled == 1 ? en_dis[0] : en_dis[1]),
+ ((int)usbsid_config.LED.idle_breathe == 1 ? true_false[0] : true_false[1]));
+ CFG("[CONFIG] [RGBLED] %s, Idle breathe? %s\n",
+ ((int)usbsid_config.RGBLED.enabled == 1 ? en_dis[0] : en_dis[1]),
+ ((int)usbsid_config.RGBLED.idle_breathe == 1 ? true_false[0] : true_false[1]));
+ CFG("[CONFIG] [RGBLED SIDTOUSE] %d\n",
+ (int)usbsid_config.RGBLED.sid_to_use);
+ CFG("[CONFIG] [RGBLED BRIGHTNESS] %d\n",
+ (int)usbsid_config.RGBLED.brightness);
+
+ CFG("[CONFIG] [CDC] %s\n",
+ ((int)usbsid_config.Cdc.enabled == 1 ? en_dis[0] : en_dis[1]));
+ CFG("[CONFIG] [WebUSB] %s\n",
+ ((int)usbsid_config.WebUSB.enabled == 1 ? en_dis[0] : en_dis[1]));
+ CFG("[CONFIG] [Asid] %s\n",
+ ((int)usbsid_config.Asid.enabled == 1 ? en_dis[0] : en_dis[1]));
+ CFG("[CONFIG] [Midi] %s\n",
+ ((int)usbsid_config.Midi.enabled == 1 ? en_dis[0] : en_dis[1]));
+ CFG("[CONFIG] PRINT SETTINGS END\n");
+
+ CFG("[CONFIG APPLY] START\n");
+
+ act_as_one = usbsid_config.socketTwo.act_as_one;
+
sock_one = usbsid_config.socketOne.enabled;
sock_two = usbsid_config.socketTwo.enabled;
- act_as_one = usbsid_config.socketTwo.act_as_one;
+
sids_one = (sock_one == true) ? (usbsid_config.socketOne.dualsid == true) ? 2 : 1 : 0;
sids_two = (sock_two == true) ? (usbsid_config.socketTwo.dualsid == true) ? 2 : 1 : 0;
numsids = (sids_one + sids_two);
+ CFG("[CONFIG] Applying socket settings\n");
+ /* one == 0x00, two == 0x20, three == 0x40, four == 0x60 */
+ if (act_as_one) { /* act-as-one enabled overrules all settings */
+ CFG("[CONFIG] ACT AS ONE\n");
+ one = two = 0; /* CS1 low, CS2 low */
+ three = four = 0; /* CS1 low, CS2 low */
+ } else {
+ if (sock_one && !sock_two) { /* SocketOne enabled, SocketTwo disabled */
+ CFG("[CONFIG] sock_one enabled, sock_two disabled\n");
+ one = 0b100; /* CS1 low, CS2 high */
+ two = (sids_one == 2) ? 0b100 /* CS1 low, CS2 high */
+ : 0b110; /* CS1 high, CS2 high */
+ three = four = 0b110; /* CS1 high, CS2 high */
+ }
+ if (!sock_one && sock_two) { /* SocketOne disabled, SocketTwo enabled */
+ CFG("[CONFIG] sock_one disabled, sock_two enabled\n");
+ one = 0b010; /* CS1 high, CS2 low */
+ two = (sids_two == 2) ? 0b010 /* CS1 high, CS2 low */
+ : 0b110; /* CS1 high, CS2 high */
+ three = four = 0b110; /* CS1 high, CS2 high */
+ }
+ if (sock_one && sock_two) { /* SocketOne enabled, SocketTwo enabled */
+ CFG("[CONFIG] sock_one enabled, sock_two enabled\n");
+ one = 0b100; /* CS1 low, CS2 high */
+ two = (sids_one == 2) ? 0b100 /* CS1 low, CS2 high */
+ : 0b110; /* CS1 high, CS2 high */
+ three = 0b010; /* CS1 high, CS2 low */
+ four = (sids_two == 2) ? 0b010 /* CS1 high, CS2 low */
+ : 0b110; /* CS1 high, CS2 high */
+ }
+ }
+
+ CFG("[SOCK_ONE EN]%s [SOCK_TWO EN]%s [ACT_AS_ONE]%s\n[NO SIDS] [SOCK_ONE#]%d [SOCK_TWO#]%d [TOTAL#]%d\n[BUS] [ONE]%02x [TWO]%02x [THREE]%02x [FOUR]%02x\n",
+ (sock_one ? true_false[0] : true_false[1]),
+ (sock_two ? true_false[0] : true_false[1]),
+ (act_as_one ? true_false[0] : true_false[1]),
+ sids_one, sids_two, numsids,
+ one, two, three, four);
+
+ CFG("[CONFIG] Applying RGBLED SID\n");
usbsid_config.RGBLED.sid_to_use /* Make sure all SIDs are used if sid to use is higher then the number of sids */
= (usbsid_config.RGBLED.sid_to_use > 2)
&& (numsids <= 2)
? 0 : usbsid_config.RGBLED.sid_to_use;
- /* TODO: Not perfect yet ~ missing remaps for triple sid config settings */
- one = (act_as_one)
- ? 0 // CS1 low, CS2 low
- : (1 << 2); // CS1 low, CS2 high
- two = (sock_two && numsids == 2)
- ? (1 << 1) // CS1 high, CS2 low
- : (1 << 2); // CS1 low, CS2 high
- three = (numsids >= 3) || (sock_two && numsids == 2)
- ? (1 << 1) // CS1 high, CS2 low
- : (1 << 1) | (1 << 2); // CS1 high, CS2 high
- four = (numsids == 4)
- ? (1 << 1) // CS1 high, CS2 low
- : (1 << 1) | (1 << 2); // CS1 high, CS2 high
-
- CFG("[CONFIG APPLIED]\n[ONE]%02x [TWO]%02x [THREE]%02x [FOUR]%02x\n[SOCK_ONE EN]%s [SOCK_TWO EN]%s [ACT_AS_ONE]%s\n[NO SIDS][S1#]%d [S2#]%d [T#]%d\n",
- one, two, three, four,
- (sock_one ? "True" : "False"),
- (sock_two ? "True" : "False"),
- (act_as_one ? "True" : "False"),
- sids_one, sids_two, numsids);
+ CFG("[CONFIG APPLY] FINISHED\n");
}
void detect_default_config(void)
{
- CFG("[IS DEFAULT CONFIG?] %s\n", (usbsid_config.default_config ? "True" : "False"));
+ CFG("[CONFIG DETECT DEFAULT] START\n");
+ CFG("[IS DEFAULT CONFIG?] %s\n",
+ (usbsid_config.default_config ? true_false[0] : true_false[1]));
if(usbsid_config.default_config == 1) {
CFG("[DETECTED DEFAULT CONFIG]\n");
usbsid_config.default_config = 0;
save_config(&usbsid_config);
}
- CFG("[CONFIG LOAD FINISHED]\n");
+ CFG("[CONFIG DETECT DEFAULT] FINISHED\n");
}
void verify_clockrate(void)
diff --git a/src/config.h b/src/config.h
index b3846ad..9b37785 100644
--- a/src/config.h
+++ b/src/config.h
@@ -55,7 +55,7 @@
#define MAGIC_SMOKE 19700101 /* DATEOFRELEASE */
#endif
#ifndef PROJECT_VERSION
-#define PROJECT_VERSION "0.2.3-BETA.20241208" /* Must be the same as in CMakeLists.txt */
+#define PROJECT_VERSION "0.2.3-BETA.20241220" /* Must be the same as in CMakeLists.txt */
#endif
#ifdef PICO_DEFAULT_LED_PIN
@@ -78,14 +78,20 @@ typedef struct Config {
struct
{
bool enabled : 1; /* enable / disable this socket */
- bool dualsid : 1; /* enable / disable dual SID support for this socket */
- uint8_t sidtype; /* 0 = empty, 1 = SKPico or other clone, 2 = MOS6581, 3 = MOS8085 */
+ bool dualsid : 1; /* enable / disable dual SID support for this socket (requires clone) */
+ uint8_t chiptype; /* 0 = real, 1 = clone */
+ uint8_t clonetype; /* 0 = disabled, 1 = SKPico, 2 = ARMSID, 3 = FPGASID, 4 = other */
+ uint8_t sid1type; /* 0 = unknown, 1 = n/a, 2 = MOS8085, 3 = MOS6581 */
+ uint8_t sid2type; /* 0 = unknown, 1 = FMopl, 2 = MOS8085, 3 = MOS6581 */
} socketOne; /* 1 */
struct {
bool enabled : 1; /* enable / disable this socket */
- bool dualsid : 1; /* enable / disable dual SID support for this socket */
+ bool dualsid : 1; /* enable / disable dual SID support for this socket (requires clone) */
bool act_as_one : 1; /* act as socket 1 */
- uint8_t sidtype; /* 0 = empty, 1 = SKPico or other clone, 2 = MOS6581, 3 = MOS8085 */
+ uint8_t chiptype; /* 0 = real, 1 = clone */
+ uint8_t clonetype; /* 0 = disabled, 1 = SKPico, 2 = ARMSID, 3 = FPGASID, 4 = other */
+ uint8_t sid1type; /* 0 = unknown, 1 = n/a, 2 = MOS8085, 3 = MOS6581 */
+ uint8_t sid2type; /* 0 = unknown, 1 = FMopl, 2 = MOS8085, 3 = MOS6581 */
} socketTwo; /* 2 */
struct {
bool enabled : 1;
diff --git a/src/globals.h b/src/globals.h
index 7ace02d..ca8f303 100644
--- a/src/globals.h
+++ b/src/globals.h
@@ -35,6 +35,8 @@
/* Default includes */
#include
+/* Helper macro for constraining a value within a range */
+#define constrain(amt,low,high) ((amt)<(low)?(low):((amt)>(high)?(high):(amt)))
/* USBSID command byte */
enum
@@ -43,9 +45,11 @@ enum
READ, /* 1 */
PAUSE, /* 2 */
RESET_SID, /* 3 */
- RESET_MCU, /* 4 */
- CLEAR_BUS, /* 5 */
- BOOTLOADER, /* 6 */
+ DISABLE_SID, /* 4 */
+ ENABLE_SID, /* 5 */
+ CLEAR_BUS, /* 6 */
+ RESET_MCU, /* 7 */
+ BOOTLOADER, /* 8 */
};
/* USB data type */
diff --git a/src/gpio.c b/src/gpio.c
index 1446e8c..181b3e6 100644
--- a/src/gpio.c
+++ b/src/gpio.c
@@ -38,10 +38,20 @@ extern int sock_one, sock_two, sids_one, sids_two, numsids, act_as_one;
/* Init vars */
PIO bus_pio = pio0;
-uint sm_control, sm_data, offset_control, offset_data;
-int dma_tx_control, dma_tx_data, dma_rx_data;
-uint16_t control_word;
-uint32_t data_word, read_data, dir_mask;
+static uint sm_control, offset_control;
+static uint sm_data, offset_data;
+static uint sm_clock, offset_clock;
+static int dma_tx_control, dma_tx_data, dma_rx_data;
+static uint16_t control_word;
+static uint32_t data_word, read_data, dir_mask;
+
+/* Read GPIO macro
+ *
+ * The following 2 lines (var naming changed) are copied from SKPico code by frenetic
+ * see: https://github.com/frntc/SIDKick-pico
+ */
+register uint32_t b asm( "r10" );
+volatile const uint32_t *BUSState = &sio_hw->gpio_in;
void init_gpio()
@@ -93,25 +103,29 @@ void init_vu(void)
void setup_piobus(void)
{
- /* float freq = (float)clock_get_hz(clk_sys) / (usbsid_config.clock_rate * 8) / 2; */ /* Clock frequency is 8 times the SID clock */
+ float freq = (float)clock_get_hz(clk_sys) / (usbsid_config.clock_rate * 32) / 2; /* Clock frequency is 32 times the SID clock */
+ CFG("[BUS CLK INIT] START\n");
+ CFG("[PI CLK]@%dMHz [DIV]@%.2f [BUS CLK]@%.2f [CFG SID CLK]%d\n", ((int)clock_get_hz(clk_sys) / 1000 / 1000), freq, ((float)clock_get_hz(clk_sys) / freq / 2), (int)usbsid_config.clock_rate);
{ /* control bus */
offset_control = pio_add_program(bus_pio, &bus_control_program);
- sm_control = pio_claim_unused_sm(bus_pio, true);
+ sm_control = 1; /* PIO0 SM1 */
+ pio_sm_claim(bus_pio, sm_control);
for (uint i = RW; i < CS2 + 1; ++i)
pio_gpio_init(bus_pio, i);
pio_sm_config c_control = bus_control_program_get_default_config(offset_control);
sm_config_set_out_pins(&c_control, RW, 3);
sm_config_set_in_pins(&c_control, D0);
sm_config_set_jmp_pin(&c_control, RW);
- /* sm_config_set_clkdiv(&c_control, freq); */
+ sm_config_set_clkdiv(&c_control, freq);
pio_sm_init(bus_pio, sm_control, offset_control, &c_control);
pio_sm_set_enabled(bus_pio, sm_control, true);
}
{ /* databus */
offset_data = pio_add_program(bus_pio, &data_bus_program);
- sm_data = pio_claim_unused_sm(bus_pio, true);
+ sm_data = 2; /* PIO0 SM2 */
+ pio_sm_claim(bus_pio, sm_data);
for (uint i = D0; i < A5 + 1; ++i) {
pio_gpio_init(bus_pio, i);
}
@@ -119,20 +133,21 @@ void setup_piobus(void)
pio_sm_set_pindirs_with_mask(bus_pio, sm_data, PIO_PINDIRMASK, PIO_PINDIRMASK); /* WORKING */
sm_config_set_out_pins(&c_data, D0, A5 + 1);
sm_config_set_fifo_join(&c_data, PIO_FIFO_JOIN_TX);
- /* sm_config_set_clkdiv(&c_data, freq); */
+ sm_config_set_clkdiv(&c_data, freq);
pio_sm_init(bus_pio, sm_data, offset_data, &c_data);
pio_sm_set_enabled(bus_pio, sm_data, true);
}
+
+ CFG("[BUS CLK INIT] FINISHED\n");
}
void setup_dmachannels(void)
-{
+{ /* NOTE: Fo not manually assign DMA channels, this causes a Panic on the PicoW */
+ CFG("[DMA CHANNELS INIT] START\n");
{ /* dma controlbus */
dma_tx_control = dma_claim_unused_channel(true);
dma_channel_config tx_config_control = dma_channel_get_default_config(dma_tx_control);
channel_config_set_transfer_data_size(&tx_config_control, DMA_SIZE_16);
- channel_config_set_read_increment(&tx_config_control, true);
- channel_config_set_write_increment(&tx_config_control, false);
channel_config_set_dreq(&tx_config_control, pio_get_dreq(bus_pio, sm_control, true));
dma_channel_configure(dma_tx_control, &tx_config_control, &bus_pio->txf[sm_control], NULL, 1, false);
}
@@ -156,10 +171,25 @@ void setup_dmachannels(void)
channel_config_set_dreq(&rx_config, pio_get_dreq(bus_pio, sm_control, false));
dma_channel_configure(dma_rx_data, &rx_config, NULL, &bus_pio->rxf[sm_control], 1, false);
}
+
+ CFG("[DMA CHANNELS INIT] FINISHED\n");
}
+void sync_pios(void)
+{ /* Sync PIO's */
+ #if PICO_PIO_VERSION == 0
+ CFG("[RESTART PIOS] Pico & Pico_w\n");
+ pio_sm_restart(bus_pio, 0b111);
+ #elif PICO_PIO_VERSION > 0 // NOTE: rp2350 only
+ CFG("[SYNC PIOS] Pico2\n");
+ pio_clkdiv_restart_sm_multi_mask(bus_pio, 0 /* 0b111 */, 0b111, 0);
+ #endif
+}
+
+
void restart_bus(void)
{
+ CFG("[RESTART BUS START]\n");
/* disable databus rx dma */
dma_channel_unclaim(dma_rx_data);
/* disable databus tx dma */
@@ -178,6 +208,47 @@ void restart_bus(void)
setup_piobus();
/* start dma */
setup_dmachannels();
+ /* sync pios */
+ sync_pios();
+ CFG("[RESTART BUS END]\n");
+}
+
+/* Detect clock signal */
+int detect_clocksignal(void)
+{
+ CFG("[DETECT CLOCK] START\n");
+ int c = 0, r = 0;
+ gpio_init(PHI);
+ gpio_set_pulls(PHI, false, true);
+ for (int i = 0; i < 20; i++) {
+ b = *BUSState; /* read complete bus */
+ // DBG("[BUS]0x%"PRIu32", 0b"PRINTF_BINARY_PATTERN_INT32"", b, PRINTF_BYTE_TO_BINARY_INT32(b));
+ r |= c = (b & bPIN(PHI)) >> PHI;
+ // DBG(" [PHI2]%d [R]%d\r\n", c, r);
+ }
+ CFG("[RESULT] %d: %s\n", r, (r == 0 ? "INTERNAL CLOCK" : "EXTERNAL CLOCK"));
+ CFG("[DETECT CLOCK] END\n");
+ return r; /* 1 if clock detected */
+}
+
+/* Init nMHz square wave output */
+void init_sidclock(void)
+{
+ float freq = (float)clock_get_hz(clk_sys) / usbsid_config.clock_rate / 2;
+ CFG("[SID CLK INIT] START\n");
+ CFG("[PI CLK]@%dMHz [DIV]@%.2f [SID CLK]@%.2f [CFG SID CLK]%d\n", (int)clock_get_hz(clk_sys) / 1000 / 1000, freq, ((float)clock_get_hz(clk_sys) / freq / 2), (int)usbsid_config.clock_rate);
+ offset_clock = pio_add_program(bus_pio, &clock_program);
+ sm_clock = 0; /* PIO0 SM0 */
+ pio_sm_claim(bus_pio, sm_clock);
+ clock_program_init(bus_pio, sm_clock, offset_clock, PHI, freq);
+ CFG("[SID CLK INIT] FINISHED\n");
+}
+
+/* De-init nMHz square wave output */
+void deinit_sidclock(void)
+{
+ CFG("[DE-INIT CLOCK]\n");
+ clock_program_deinit(bus_pio, sm_clock, offset_clock, clock_program);
}
uint8_t __not_in_flash_func(bus_operation)(uint8_t command, uint8_t address, uint8_t data)
@@ -274,9 +345,13 @@ void pause_sid(void)
void reset_sid(void)
{
- disable_sid();
+ /* disable_sid();
clear_bus();
- enable_sid();
+ enable_sid(); */
+ gpio_put(CS1, 1);
+ gpio_put(CS2, 1);
+ gpio_put(RES, 0);
+ gpio_put(RES, 1);
}
void clear_sid_registers(void)
diff --git a/src/gpio.h b/src/gpio.h
index cbd097a..1541f29 100644
--- a/src/gpio.h
+++ b/src/gpio.h
@@ -54,7 +54,7 @@
/* PIO */
#include "bus_control.pio.h" /* Busje komt zo! */
-
+#include "clock.pio.h" /* Square wave generator */
/* Uart */
#define BAUD_RATE 115200
diff --git a/src/pio/bus_control.pio b/src/pio/bus_control.pio
index e467aab..ad77af7 100644
--- a/src/pio/bus_control.pio
+++ b/src/pio/bus_control.pio
@@ -22,6 +22,24 @@
; along with this program. If not, see .
;
+; BUS clock = 32 * SID clock
+; Example:
+; 32MHz BUS clock @ 1MHz SID clock
+; 32MHZ is 0.03125µs per cycle
+; 32MHZ is 31.25ns per cycle
+; 1MHz is 1µs per cycle
+; 1MHz is 1000ns per cycle
+; A 1MHz/1µs SID cycle _should_ contain 32 BUS cycles
+; This _should_ mean that 1 command or NOP == 31.25ns
+;
+; Except?
+; nop 26 waits 15 cycles to and including out pins
+; nop 25 waits 15 cycles to and including out pins
+; nop 24 waits 14 cycles to and including out pins
+; nop 14 waits 9 cycles to and including out pins
+; so 10 nops is 5 cycles? WTF!?
+;
+
.define PUBLIC PHI 22
; Bus control program
@@ -29,20 +47,15 @@
.wrap_target
pull block ; Pull data from FIFO
wait 1 gpio PHI ; Wait for clock to go high
- wait 0 gpio PHI ; Wait for clock to go low
- nop [31] ; Wait for ~103ns
+ wait 0 gpio PHI [26] ; Wait for clock to go low
out pins, 3 ; Set control pins (19-21)
- wait 1 gpio PHI ; Wait for clock to go high
- nop [31] ; Wait for ~103ns
+ wait 1 gpio PHI [24] ; Wait for clock to go high
jmp pin read ; Jump to read if IN pin is high
- nop [9] ; Wait for ~30ns
jmp done ; Jump to done
read:
- nop [31]
in pins, 8 ; Read data bus into isr
push block ; Push isr to fifo
done:
- nop [9] ; Wait for ~30ns
wait 0 gpio PHI ; Wait for clock to go low
out pins, 3 ; Set control to next 3 bits from fifo
.wrap
@@ -50,14 +63,11 @@ done:
; Data and address bus program
.program data_bus
.wrap_target
- pull block ; Pull data from FIFO
- wait 1 gpio PHI ; Wait for clock to go high
- wait 0 gpio PHI ; Wait for clock to go low
- nop [31] ; Wait for ~103ns
- out pins, 16 ; Set data bus pins
- out pindirs 16 ; Set pin directions
- wait 1 gpio PHI ; Wait for clock to go high
- nop [31] ; Wait for ~103ns
- nop [31] ; Wait for ~103ns
- nop [9] ; Wait for ~30ns
+ pull block ; Pull data from FIFO
+ wait 1 gpio PHI ; Wait for clock to go high
+ wait 0 gpio PHI [26] ; Wait for clock to go low and throw in some nops
+ out pins, 16 ; Set data bus pins
+ out pindirs 16 ; Set pin directions
+ wait 1 gpio PHI ; Wait for clock to go high
+ wait 0 gpio PHI ; Wait for clock to go low
.wrap
diff --git a/src/sid.c b/src/sid.c
index 58fc4b0..9c5214a 100644
--- a/src/sid.c
+++ b/src/sid.c
@@ -40,9 +40,13 @@ uint8_t waveforms[4] = { 16, 32, 64, 128 };
uint8_t detect_sid_version(uint8_t start_addr) /* Not working on real SIDS!? */
{
bus_operation(0x10, (start_addr + 0x12), 0xFF); /* Set testbit in voice 3 control register to disable oscillator */
+ sleep_ms(1);
bus_operation(0x10, (start_addr + 0x0E), 0xFF); /* Set frequency in voice 3 to $ffff */
+ sleep_ms(1);
bus_operation(0x10, (start_addr + 0x0F), 0xFF); /* Set frequency in voice 3 to $ffff */
+ sleep_ms(1);
bus_operation(0x10, (start_addr + 0x12), 0x20); /* Set Sawtooth wave and gatebit OFF to start oscillator again */
+ sleep_ms(1);
uint8_t sidtype = bus_operation(0x11, (start_addr + 0x1B), 0x00); /* Accu now has different value depending on sid model (6581=3/8580=2) */
return sidtype; /* that is: Carry flag is set for 6581, and clear for 8580. */
}
diff --git a/src/usbsid.c b/src/usbsid.c
index 193b78c..a9e1e96 100644
--- a/src/usbsid.c
+++ b/src/usbsid.c
@@ -31,22 +31,26 @@
#include "sid.h"
#include "logging.h"
+/* util.c */
+extern long map(long x, long in_min, long in_max, long out_min, long out_max);
+extern int randval(int min, int max);
/* Init external vars */
static semaphore_t core1_init;
/* Init vars */
+uint8_t __not_in_flash("usbsid_buffer") sid_memory[(0x20 * 4)] = {0}; /* 4x max */
uint8_t __not_in_flash("usbsid_buffer") read_buffer[MAX_BUFFER_SIZE];
uint8_t __not_in_flash("usbsid_buffer") write_buffer[MAX_BUFFER_SIZE];
int usb_connected = 0, usbdata = 0, pwm_value = 0, updown = 1;
uint32_t cdcread = 0, cdcwrite = 0, webread = 0, webwrite = 0;
-uint sm_clock, offset_clock;
-uint8_t *cdc_itf, *wusb_itf;
-uint16_t vu;
+uint8_t *cdc_itf = 0, *wusb_itf = 0;
+uint16_t vu = 0;
uint32_t breathe_interval_ms = BREATHE_INTV;
uint32_t start_ms = 0;
char ntype = '0', dtype = '0', cdc = 'C', asid = 'A', midi = 'M', wusb = 'W';
bool web_serial_connected = false;
+double /* cpu_mhz = 0, cpu_us = 0, */ clk_rate = 0, sidfrq = 0, frqpow = 0;
/* Init var pointers for external use */
uint8_t (*write_buffer_p)[MAX_BUFFER_SIZE] = &write_buffer;
@@ -64,14 +68,18 @@ extern void detect_default_config(void);
extern void verify_clockrate(void);
/* GPIO externals */
-extern PIO bus_pio;
extern void init_gpio(void);
extern void init_vu(void);
extern void setup_piobus(void);
extern void setup_dmachannels(void);
+extern void sync_pios(void);
+extern void init_sidclock(void);
+extern int detect_clocksignal(void);
extern void pause_sid(void);
-extern void disable_sid(void);
extern void reset_sid(void);
+extern void enable_sid(void);
+extern void disable_sid(void);
+extern void clear_bus(void);
extern uint8_t __not_in_flash_func(bus_operation)(uint8_t command, uint8_t address, uint8_t data);
/* MCU externals */
@@ -139,14 +147,6 @@ const __not_in_flash("usbsid_data") unsigned char color_LUT[43][6][3] =
};
#endif
-/* Read GPIO macro
- *
- * The following 2 lines (var naming changed) are copied from SKPico code by frenetic
- * see: https://github.com/frntc/SIDKick-pico
- */
-register uint32_t b asm( "r10" );
-volatile const uint32_t *BUSState = &sio_hw->gpio_in;
-
/* WebUSB Description URL */
static const tusb_desc_webusb_url_t desc_url =
{
@@ -173,32 +173,6 @@ void reset_reason(void)
#endif
}
-/* Detect clock signal */
-int detect_clock(void)
-{
- int c = 0, r = 0;
- gpio_init(PHI);
- gpio_set_pulls(PHI, false, true);
- for (int i = 0; i < 20; i++) {
- b = *BUSState; /* read complete bus */
- DBG("[BUS]0x%"PRIu32", 0b"PRINTF_BINARY_PATTERN_INT32"", b, PRINTF_BYTE_TO_BINARY_INT32(b));
- r |= c = (b & bPIN(PHI)) >> PHI;
- DBG(" [PHI2]%d [R]%d\r\n", c, r);
- }
- DBG("[RESULT]%d\r\n", r);
- return r; /* 1 if clock detected */
-}
-
-int randval(int min, int max)
-{
- return min + rand() / (RAND_MAX / (max - min + 1) + 1);
-}
-
-long map(long x, long in_min, long in_max, long out_min, long out_max)
-{
- return (x - in_min) * (out_max - out_min) / (in_max - in_min) + out_min;
-}
-
#if defined(USE_RGB)
void put_pixel(uint32_t pixel_grb) {
// pio_sm_put_blocking(pio_rgb, ws2812_sm, pixel_grb << 8u);
@@ -230,22 +204,6 @@ void init_logging(void)
#endif
}
-/* Init nMHz square wave output */
-void init_sidclock(void)
-{
- float freq = (float)clock_get_hz(clk_sys) / usbsid_config.clock_rate / 2;
- offset_clock = pio_add_program(bus_pio, &clock_program);
- sm_clock = pio_claim_unused_sm(bus_pio, true);
- clock_program_init(bus_pio, sm_clock, offset_clock, PHI, freq);
- DBG("[CLK INIT] [PI CLK]@%dMHz [DIV]@%.2f [SID CLK]@%.2f [CFG]%d\n", (int)clock_get_hz(clk_sys) / 1000 / 1000, freq, ((float)clock_get_hz(clk_sys) / freq / 2), (int)usbsid_config.clock_rate);
-}
-
-/* De-init nMHz square wave output */
-void deinit_sidclock(void)
-{
- clock_program_deinit(bus_pio, sm_clock, offset_clock, clock_program);
-}
-
/* Init the RGB LED pio */
void init_rgb(void)
{
@@ -253,7 +211,8 @@ void init_rgb(void)
_rgb = randval(0, 5);
r_ = g_ = b_ = 0;
offset_ws2812 = pio_add_program(pio_rgb, &ws2812_program);
- ws2812_sm = pio_claim_unused_sm(pio_rgb, true);
+ ws2812_sm = 0; /* PIO1 SM0 */
+ pio_sm_claim(pio_rgb, ws2812_sm);
ws2812_program_init(pio_rgb, ws2812_sm, offset_ws2812, 23, 800000, IS_RGBW);
put_pixel(urgb_u32(0,0,0));
#endif
@@ -291,6 +250,7 @@ void __not_in_flash_func(handle_buffer_task)(uint8_t * itf, uint32_t * n)
read_buffer[1] = read_buffer[2];
read_buffer[2] = read_buffer[3];
case BYTES_EXPECTED:
+ usbdata = 1;
IODBG("[%c][I]$%02x $%02x $%02x[RE]\r\n", dtype, read_buffer[0], read_buffer[1], read_buffer[2]);
switch (read_buffer[0]) {
case WRITE:
@@ -318,6 +278,18 @@ void __not_in_flash_func(handle_buffer_task)(uint8_t * itf, uint32_t * n)
DBG("[RESET_SID]\n");
reset_sid();
break;
+ case DISABLE_SID:
+ DBG("[DISABLE_SID]\n");
+ disable_sid();
+ break;
+ case ENABLE_SID:
+ DBG("[ENABLE_SID]\n");
+ enable_sid();
+ break;
+ case CLEAR_BUS:
+ DBG("[CLEAR_BUS]\n");
+ clear_bus();
+ break;
case RESET_MCU:
DBG("[RESET_MCU]\n");
mcu_reset();
@@ -336,10 +308,16 @@ void __not_in_flash_func(handle_buffer_task)(uint8_t * itf, uint32_t * n)
CFG("\r\n");
handle_config_request(read_buffer);
break;
- case MAX_BUFFER_SIZE: /* No implementation yet */
- IODBG("[%c][MAX %d]", dtype, *n);
- for (int i = 0; i < *n; i ++) IODBG("$%02x ", read_buffer[i]);
- IODBG("\r\n");
+ case MAX_BUFFER_SIZE: /* Cycled write buffer */
+ // ISSUE: Not perfect yet!
+ usbdata = 1;
+ for (int i = 0; i < *n; i += 4) {
+ uint16_t cycles = (read_buffer[i + 2] | read_buffer[i + 3]);
+ uint64_t sleep_time = ((double)cycles * frqpow);
+ /* uint32_t delay_cycles = (sleep_time / cpu_us) - 3; */
+ sleep_us(sleep_time - 2);
+ bus_operation(0x10, read_buffer[i], read_buffer[i + 1]);
+ }
break;
default:
/* Nope not gonna handle that shit, just log it */
@@ -446,11 +424,12 @@ void led_vumeter_task(void)
pwm_set_gpio_level(BUILTIN_LED, vu);
}
- MDBG("[%c:%d] [VOL]$%02x [PWM]$%04x | [V1] $%02X%02X %02X%02X %02X %02X %02X | [V2] $%02X%02X %02X%02X %02X %02X %02X | [V3] $%02X%02X %02X%02X %02X %02X %02X \n",
- dtype, usbdata, sid_memory[0x18], vu,
- sid_memory[0x00], sid_memory[0x01], sid_memory[0x02], sid_memory[0x03], sid_memory[0x04], sid_memory[0x05], sid_memory[0x06],
- sid_memory[0x07], sid_memory[0x08], sid_memory[0x09], sid_memory[0x0A], sid_memory[0x0B], sid_memory[0x0C], sid_memory[0x0D],
- sid_memory[0x0E], sid_memory[0x0F], sid_memory[0x10], sid_memory[0x11], sid_memory[0x12], sid_memory[0x13], sid_memory[0x14]);
+ MDBG("[%c:%d][PWM]$%04x[V1]$%02X%02X$%02X%02X$%02X$%02X$%02X[V2]$%02X%02X$%02X%02X$%02X$%02X$%02X[V3]$%02X%02X$%02X%02X$%02X$%02X$%02X[FC]$%02x%02x$%02x[VOL]$%02x\n",
+ dtype, usbdata, vu,
+ sid_memory[0x01], sid_memory[0x00], sid_memory[0x03], sid_memory[0x02], sid_memory[0x04], sid_memory[0x05], sid_memory[0x06],
+ sid_memory[0x08], sid_memory[0x07], sid_memory[0x0A], sid_memory[0x09], sid_memory[0x0B], sid_memory[0x0C], sid_memory[0x0D],
+ sid_memory[0x0F], sid_memory[0x0E], sid_memory[0x11], sid_memory[0x10], sid_memory[0x12], sid_memory[0x13], sid_memory[0x14],
+ sid_memory[0x16], sid_memory[0x15], sid_memory[0x17], sid_memory[0x18]);
}
#endif
@@ -614,9 +593,9 @@ void tud_vendor_rx_cb(uint8_t itf, uint8_t const* buffer, uint16_t bufsize)
(void)buffer;
(void)bufsize;
- usbdata = 1, dtype = wusb;
if (web_serial_connected) { /* vendor class has no connect check, thus use this */
wusb_itf = &itf;
+ usbdata = 1, dtype = wusb;
webread = tud_vendor_n_read(*wusb_itf, &read_buffer, MAX_BUFFER_SIZE);
tud_vendor_n_read_flush(*wusb_itf);
handle_buffer_task(wusb_itf, &webread);
@@ -692,7 +671,7 @@ void core1_main(void)
/* Apply saved config to used vars */
apply_config();
/* Detect optional external crystal */
- if (detect_clock() == 0) {
+ if (detect_clocksignal() == 0) {
usbsid_config.external_clock = false;
gpio_deinit(PHI); /* Disable PHI as gpio */
init_sidclock();
@@ -707,6 +686,14 @@ void core1_main(void)
memset(sid_memory, 0, sizeof sid_memory);
/* Start the VU */
init_vu();
+
+ /* Init cycled write buffer vars */
+ /* double cpu_mhz = (clock_get_hz(clk_sys) / 1000 / 1000); */
+ /* double cpu_us = (1 / cpu_mhz); */
+ clk_rate = usbsid_config.clock_rate;
+ sidfrq = (clk_rate / 1000 / 1000);
+ frqpow = (1 / sidfrq);
+
/* Release semaphore when core 1 is started */
sem_release(&core1_init);
@@ -734,8 +721,13 @@ int main()
{
(void)desc_url; /* NOTE: Remove if going to use it */
+ #if PICO_RP2040
/* System clock @ 125MHz */
set_sys_clock_pll(1500000000, 6, 2);
+ #elif PICO_RP2350
+ /* System clock @ 150MHz */
+ set_sys_clock_pll(1800000000, 6, 2);
+ #endif
/* Init board */
board_init();
/* Init USB */
@@ -760,6 +752,8 @@ int main()
init_gpio();
/* Init PIO */
setup_piobus();
+ /* Sync PIOS */
+ sync_pios();
/* Init DMA */
setup_dmachannels();
/* Init midi */
diff --git a/src/usbsid.h b/src/usbsid.h
index beebc58..82ff453 100644
--- a/src/usbsid.h
+++ b/src/usbsid.h
@@ -44,9 +44,10 @@
/* Pico libs */
#include "pico/stdlib.h"
-#include "pico/types.h" /* absolute_time_t */
-#include "pico/multicore.h" /* Multicore */
-#include "pico/sem.h" /* Semaphores */
+#include "pico/types.h" /* absolute_time_t */
+#include "pico/multicore.h" /* Multicore */
+#include "pico/sem.h" /* Semaphores */
+#include "pico/util/queue.h" /* Inter core queue */
/* Hardware api's */
#include "hardware/clocks.h"
@@ -72,8 +73,7 @@
#include "tusb.h" /* Tiny USB stack */
#include "tusb_config.h" /* Tiny USB configuration */
-/* PIO */
-#include "clock.pio.h" /* Square wave generator */
+/* RGBLED */
#if defined(USE_RGB)
#include "ws2812.pio.h" /* RGB led handler */
#endif
diff --git a/src/util.c b/src/util.c
new file mode 100644
index 0000000..d029f50
--- /dev/null
+++ b/src/util.c
@@ -0,0 +1,38 @@
+/*
+ * USBSID-Pico is a RPi Pico (RP2040) based board for interfacing one or two
+ * MOS SID chips and/or hardware SID emulators over (WEB)USB with your computer,
+ * phone or ASID supporting player
+ *
+ * util.c
+ * This file is part of USBSID-Pico (https://github.com/LouDnl/USBSID-Pico)
+ * File author: LouD
+ *
+ * Copyright (c) 2024 LouD
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, version 2.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ *
+ */
+
+/* Pico libs */
+#include
+#include "pico/stdlib.h"
+
+int randval(int min, int max)
+{
+ return min + rand() / (RAND_MAX / (max - min + 1) + 1);
+}
+
+long map(long x, long in_min, long in_max, long out_min, long out_max)
+{
+ return (x - in_min) * (out_max - out_min) / (in_max - in_min) + out_min;
+}