Skip to content
This repository was archived by the owner on Mar 7, 2026. It is now read-only.
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
84 changes: 70 additions & 14 deletions src/target/puya.c
Original file line number Diff line number Diff line change
Expand Up @@ -38,22 +38,31 @@
#include "adiv5.h"
#include "buffer_utils.h"

/* Chip IDs */
#define ID_PY32F07X 0x06188061U

/* Flash */
#define PUYA_FLASH_START 0x08000000U
#define PUYA_FLASH_PAGE_SIZE 128
#define PUYA_FLASH_START 0x08000000U
#define PUYA_00A_FLASH_PAGE_SIZE 128U
#define PUYA_07X_FLASH_PAGE_SIZE 256U
#define PUYA_07X_RAM_SIZE 0x4000U

/* Pile of timing parameters needed to make sure flash works,
* see section "4.4. Flash configuration bytes" of the RM.
*/
#define PUYA_FLASH_TIMING_CAL_BASE 0x1fff0f1cU
#define PUYA_00A_FLASH_TIMING_CAL_BASE 0x1fff0f1cU
#define PUYA_07X_FLASH_TIMING_CAL_BASE 0x1fff3238U

/* This config word is undocumented, but the Puya-ISP boot code
* uses it to determine the valid flash/ram size.
* (yes, this *does* include undocumented free extra flash/ram in the 002A)
*
* bits[2:0] => flash size in multiples of 0x2000 bytes, minus 1
* bits[5:4] => RAM size in multiples of 0x800 bytes, minus 1
*/
#define PUYA_FLASH_RAM_SZ 0x1fff0ffcU
#define PUYA_00A_FLASH_RAM_SZ 0x1fff0ffcU
#define PUYA_07X_FLASH_RAM_SZ 0x1fff31fcU

#define PUYA_FLASH_SZ_SHIFT 0U
#define PUYA_FLASH_SZ_MASK 7U
#define PUYA_FLASH_UNIT_SHIFT 13U
Expand Down Expand Up @@ -105,7 +114,8 @@
*/
static bool puya_flash_erase(target_flash_s *flash, target_addr_t addr, size_t len);
static bool puya_flash_write(target_flash_s *flash, target_addr_t dest, const void *src, size_t len);
static bool puya_flash_prepare(target_flash_s *flash);
static bool puya_00a_flash_prepare(target_flash_s *flash);
static bool puya_07x_flash_prepare(target_flash_s *flash);
static bool puya_flash_done(target_flash_s *flash);

bool puya_probe(target_s *target)
Expand All @@ -114,39 +124,83 @@ bool puya_probe(target_s *target)
size_t flash_size = 0U;

const uint32_t dbg_idcode = target_mem32_read32(target, PUYA_DBG_IDCODE);
if ((dbg_idcode & 0xfffU) == 0) {
const uint32_t flash_ram_sz = target_mem32_read32(target, PUYA_FLASH_RAM_SZ);
if (dbg_idcode == ID_PY32F07X) {
const uint32_t flash_ram_sz = target_mem32_read32(target, PUYA_07X_FLASH_RAM_SZ);
flash_size = (((flash_ram_sz >> PUYA_FLASH_SZ_SHIFT) & PUYA_FLASH_SZ_MASK) + 1) << PUYA_FLASH_UNIT_SHIFT;
ram_size = (((flash_ram_sz >> PUYA_RAM_SZ_SHIFT) & PUYA_RAM_SZ_MASK) + 1) << PUYA_RAM_UNIT_SHIFT;
target->driver = "PY32F07x";
target_add_ram32(target, PUYA_RAM_START, PUYA_07X_RAM_SIZE);
} else if ((dbg_idcode & 0xfffU) == 0U) {
const uint32_t flash_ram_sz = target_mem32_read32(target, PUYA_00A_FLASH_RAM_SZ);
flash_size = (((flash_ram_sz >> PUYA_FLASH_SZ_SHIFT) & PUYA_FLASH_SZ_MASK) + 1) << PUYA_FLASH_UNIT_SHIFT;
ram_size = (((flash_ram_sz >> PUYA_RAM_SZ_SHIFT) & PUYA_RAM_SZ_MASK) + 1) << PUYA_RAM_UNIT_SHIFT;
// TODO: which part families does this actually correspond to?
// Tested with a PY32F002AW15U which returns 0x60001000 in IDCODE
target->driver = "PY32Fxxx";
target_add_ram32(target, PUYA_RAM_START, ram_size);
} else {
DEBUG_TARGET("Unknown PY32 device %08" PRIx32 "\n", dbg_idcode);
return false;
}

target_add_ram32(target, PUYA_RAM_START, ram_size);
target_flash_s *flash = calloc(1, sizeof(*flash));
if (!flash) { /* calloc failed: heap exhaustion */
DEBUG_ERROR("calloc: failed in %s\n", __func__);
return false;
}

flash->start = PUYA_FLASH_START;
flash->length = flash_size;
flash->blocksize = PUYA_FLASH_PAGE_SIZE;
flash->writesize = PUYA_FLASH_PAGE_SIZE;
flash->erase = puya_flash_erase;
flash->write = puya_flash_write;
flash->prepare = puya_flash_prepare;
if (dbg_idcode == ID_PY32F07X) {
flash->blocksize = PUYA_07X_FLASH_PAGE_SIZE;
flash->writesize = PUYA_07X_FLASH_PAGE_SIZE;
flash->prepare = puya_07x_flash_prepare;
} else {
flash->blocksize = PUYA_00A_FLASH_PAGE_SIZE;
flash->writesize = PUYA_00A_FLASH_PAGE_SIZE;
flash->prepare = puya_00a_flash_prepare;
}
flash->done = puya_flash_done;
flash->erased = 0xffU;
target_add_flash(target, flash);

return true;
}

static bool puya_flash_prepare(target_flash_s *flash)
static bool puya_00a_flash_prepare(target_flash_s *flash)
{
target_mem32_write32(flash->t, PUYA_FLASH_KEYR, PUYA_FLASH_KEYR_KEY1);
target_mem32_write32(flash->t, PUYA_FLASH_KEYR, PUYA_FLASH_KEYR_KEY2);

uint8_t hsi_fs =
(target_mem32_read32(flash->t, PUYA_RCC_ICSCR) >> PUYA_RCC_ICSCR_HSI_FS_SHIFT) & PUYA_RCC_ICSCR_HSI_FS_MASK;
if (hsi_fs > 4U)
hsi_fs = 0U;
DEBUG_TARGET("HSI frequency selection is %d\n", hsi_fs);

uint32_t eppara[5] = {0};

for (uint16_t i = 0; i < 5; i++) {
eppara[i] = target_mem32_read32(flash->t, PUYA_00A_FLASH_TIMING_CAL_BASE + hsi_fs * 20 + i * 4U);
DEBUG_TARGET("PY32 flash timing cal %u: %08" PRIx32 "\n", i, eppara[i]);
}

target_mem32_write32(flash->t, PUYA_FLASH_TS0, eppara[0] & 0xffU);
target_mem32_write32(flash->t, PUYA_FLASH_TS1, (eppara[0] >> 16U) & 0x1ffU);
target_mem32_write32(flash->t, PUYA_FLASH_TS3, (eppara[0] >> 8U) & 0xffU);
target_mem32_write32(flash->t, PUYA_FLASH_TS2P, eppara[1] & 0xffU);
target_mem32_write32(flash->t, PUYA_FLASH_TPS3, (eppara[1] >> 16U) & 0x7ffU);
target_mem32_write32(flash->t, PUYA_FLASH_PERTPE, eppara[2] & 0x1ffffU);
target_mem32_write32(flash->t, PUYA_FLASH_SMERTPE, eppara[3] & 0x1ffffU);
target_mem32_write32(flash->t, PUYA_FLASH_PRGTPE, eppara[4] & 0xffffU);
target_mem32_write32(flash->t, PUYA_FLASH_PRETPE, (eppara[4] >> 16U) & 0x3fffU);

return true;
}

static bool puya_07x_flash_prepare(target_flash_s *flash)
{
target_mem32_write32(flash->t, PUYA_FLASH_KEYR, PUYA_FLASH_KEYR_KEY1);
target_mem32_write32(flash->t, PUYA_FLASH_KEYR, PUYA_FLASH_KEYR_KEY2);
Expand All @@ -158,10 +212,12 @@ static bool puya_flash_prepare(target_flash_s *flash)
DEBUG_TARGET("HSI frequency selection is %d\n", hsi_fs);

uint32_t eppara[5] = {0};

for (uint16_t i = 0; i < 5; i++) {
eppara[i] = target_mem32_read32(flash->t, PUYA_FLASH_TIMING_CAL_BASE + hsi_fs * 20 + i * 4U);
eppara[i] = target_mem32_read32(flash->t, PUYA_07X_FLASH_TIMING_CAL_BASE + 4 * 0x28 + i * 8U);
DEBUG_TARGET("PY32 flash timing cal %u: %08" PRIx32 "\n", i, eppara[i]);
}

target_mem32_write32(flash->t, PUYA_FLASH_TS0, eppara[0] & 0xffU);
target_mem32_write32(flash->t, PUYA_FLASH_TS1, (eppara[0] >> 16U) & 0x1ffU);
target_mem32_write32(flash->t, PUYA_FLASH_TS3, (eppara[0] >> 8U) & 0xffU);
Expand All @@ -170,7 +226,7 @@ static bool puya_flash_prepare(target_flash_s *flash)
target_mem32_write32(flash->t, PUYA_FLASH_PERTPE, eppara[2] & 0x1ffffU);
target_mem32_write32(flash->t, PUYA_FLASH_SMERTPE, eppara[3] & 0x1ffffU);
target_mem32_write32(flash->t, PUYA_FLASH_PRGTPE, eppara[4] & 0xffffU);
target_mem32_write32(flash->t, PUYA_FLASH_PRETPE, (eppara[4] >> 16U) & 0x3fffU);
target_mem32_write32(flash->t, PUYA_FLASH_PRETPE, (eppara[4] >> 16U) & 0xffffU); // diff

return true;
}
Expand Down
Loading