mirror of
https://github.com/Polprzewodnikowy/SummerCart64.git
synced 2024-12-27 21:41:55 +01:00
update stuff done
This commit is contained in:
parent
ab0c72ce26
commit
eb7443d95d
20
build.sh
20
build.sh
@ -6,13 +6,8 @@ PACKAGE_FILE_NAME="SC64"
|
|||||||
|
|
||||||
FILES=(
|
FILES=(
|
||||||
"./fw/ft232h_config.xml"
|
"./fw/ft232h_config.xml"
|
||||||
"./fw/project/lcmxo2/impl1/sc64_impl1.bit"
|
|
||||||
"./fw/project/lcmxo2/impl1/sc64_impl1.jed"
|
|
||||||
"./sw/bootloader/build/bootloader.bin"
|
|
||||||
"./sw/controller/build/controller.bin"
|
|
||||||
"./sw/controller/build/controller.elf"
|
|
||||||
"./sw/pc/helpers.py"
|
|
||||||
"./sw/pc/sc64.py"
|
"./sw/pc/sc64.py"
|
||||||
|
"./sw/update/sc64.upd"
|
||||||
"./LICENSE"
|
"./LICENSE"
|
||||||
"./README.md"
|
"./README.md"
|
||||||
)
|
)
|
||||||
@ -75,6 +70,19 @@ build_update () {
|
|||||||
build_controller
|
build_controller
|
||||||
build_fpga
|
build_fpga
|
||||||
|
|
||||||
|
pushd sw/update > /dev/null
|
||||||
|
INFO=""
|
||||||
|
if [ ! -z "${GIT_BRANCH+x}" ]; then INFO+=" $GIT_BRANCH"; fi
|
||||||
|
if [ ! -z "${GIT_TAG+x}" ]; then INFO+=" $GIT_TAG"; fi
|
||||||
|
if [ ! -z "${GIT_SHA+x}" ]; then INFO+=" $GIT_SHA"; fi
|
||||||
|
python3 update.py \
|
||||||
|
--info "$INFO" \
|
||||||
|
--mcu ../controller/build/app/app.bin \
|
||||||
|
--fpga ../../fw/project/lcmxo2/impl1/sc64_impl1.jed \
|
||||||
|
--boot ../bootloader/build/bootloader.bin \
|
||||||
|
sc64.upd
|
||||||
|
popd > /dev/null
|
||||||
|
|
||||||
BUILT_UPDATE=true
|
BUILT_UPDATE=true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,3 +1,2 @@
|
|||||||
prj_project open sc64.ldf
|
prj_project open sc64.ldf
|
||||||
prj_run Export -impl impl1 -task Bitgen
|
|
||||||
prj_run Export -impl impl1 -task Jedecgen
|
prj_run Export -impl impl1 -task Jedecgen
|
||||||
|
@ -19,6 +19,7 @@ SRC_FILES = \
|
|||||||
task.c \
|
task.c \
|
||||||
update.c \
|
update.c \
|
||||||
usb.c
|
usb.c
|
||||||
|
PAD_TO = 0x08008000
|
||||||
|
|
||||||
include common.mk
|
include common.mk
|
||||||
|
|
||||||
|
@ -30,7 +30,7 @@ $(BUILD_DIR)/$(EXE_NAME).elf: $(OBJS) $(LD_SCRIPT)
|
|||||||
@$(OBJDUMP) -S -D $@ > $(BUILD_DIR)/$(EXE_NAME).lst
|
@$(OBJDUMP) -S -D $@ > $(BUILD_DIR)/$(EXE_NAME).lst
|
||||||
|
|
||||||
$(BUILD_DIR)/$(EXE_NAME).bin: $(BUILD_DIR)/$(EXE_NAME).elf
|
$(BUILD_DIR)/$(EXE_NAME).bin: $(BUILD_DIR)/$(EXE_NAME).elf
|
||||||
$(OBJCOPY) -O binary $< $@
|
$(OBJCOPY) -O binary --gap-fill 0xFF --pad-to $(PAD_TO) $< $@
|
||||||
|
|
||||||
$(BUILD_DIR)/$(EXE_NAME).hex: $(BUILD_DIR)/$(EXE_NAME).bin
|
$(BUILD_DIR)/$(EXE_NAME).hex: $(BUILD_DIR)/$(EXE_NAME).bin
|
||||||
@$(OBJCOPY) -I binary -O ihex $< $@
|
@$(OBJCOPY) -I binary -O ihex $< $@
|
||||||
|
@ -3,10 +3,12 @@ LD_SCRIPT = loader.ld
|
|||||||
BUILD_DIR = build/loader
|
BUILD_DIR = build/loader
|
||||||
SRC_FILES = \
|
SRC_FILES = \
|
||||||
loader.S \
|
loader.S \
|
||||||
|
flash.c \
|
||||||
fpga.c \
|
fpga.c \
|
||||||
hw.c \
|
hw.c \
|
||||||
lcmxo2.c \
|
lcmxo2.c \
|
||||||
loader.c \
|
loader.c \
|
||||||
update.c
|
update.c
|
||||||
|
PAD_TO = 0x08001000
|
||||||
|
|
||||||
include common.mk
|
include common.mk
|
||||||
|
@ -5,6 +5,9 @@
|
|||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
|
||||||
|
|
||||||
|
#define FLASH_ERASE_BLOCK_SIZE (128 * 1024)
|
||||||
|
|
||||||
|
|
||||||
void flash_erase_block (uint32_t offset);
|
void flash_erase_block (uint32_t offset);
|
||||||
|
|
||||||
|
|
||||||
|
@ -40,9 +40,13 @@ void fpga_reg_set (fpga_reg_t reg, uint32_t value) {
|
|||||||
void fpga_mem_read (uint32_t address, size_t length, uint8_t *buffer) {
|
void fpga_mem_read (uint32_t address, size_t length, uint8_t *buffer) {
|
||||||
fpga_cmd_t cmd = CMD_MEM_READ;
|
fpga_cmd_t cmd = CMD_MEM_READ;
|
||||||
uint8_t buffer_address = 0;
|
uint8_t buffer_address = 0;
|
||||||
|
size_t dma_length = length;
|
||||||
|
if ((dma_length % 2) != 0) {
|
||||||
|
dma_length += 1;
|
||||||
|
}
|
||||||
|
|
||||||
fpga_reg_set(REG_MEM_ADDRESS, address);
|
fpga_reg_set(REG_MEM_ADDRESS, address);
|
||||||
fpga_reg_set(REG_MEM_SCR, (length << MEM_SCR_LENGTH_BIT) | MEM_SCR_START);
|
fpga_reg_set(REG_MEM_SCR, (dma_length << MEM_SCR_LENGTH_BIT) | MEM_SCR_START);
|
||||||
while (fpga_reg_get(REG_MEM_SCR) & MEM_SCR_BUSY);
|
while (fpga_reg_get(REG_MEM_SCR) & MEM_SCR_BUSY);
|
||||||
|
|
||||||
hw_spi_start();
|
hw_spi_start();
|
||||||
@ -55,6 +59,10 @@ void fpga_mem_read (uint32_t address, size_t length, uint8_t *buffer) {
|
|||||||
void fpga_mem_write (uint32_t address, size_t length, uint8_t *buffer) {
|
void fpga_mem_write (uint32_t address, size_t length, uint8_t *buffer) {
|
||||||
fpga_cmd_t cmd = CMD_MEM_WRITE;
|
fpga_cmd_t cmd = CMD_MEM_WRITE;
|
||||||
uint8_t buffer_address = 0;
|
uint8_t buffer_address = 0;
|
||||||
|
size_t dma_length = length;
|
||||||
|
if ((dma_length % 2) != 0) {
|
||||||
|
dma_length += 1;
|
||||||
|
}
|
||||||
|
|
||||||
hw_spi_start();
|
hw_spi_start();
|
||||||
hw_spi_trx((uint8_t *) (&cmd), 1, SPI_TX);
|
hw_spi_trx((uint8_t *) (&cmd), 1, SPI_TX);
|
||||||
@ -63,17 +71,22 @@ void fpga_mem_write (uint32_t address, size_t length, uint8_t *buffer) {
|
|||||||
hw_spi_stop();
|
hw_spi_stop();
|
||||||
|
|
||||||
fpga_reg_set(REG_MEM_ADDRESS, address);
|
fpga_reg_set(REG_MEM_ADDRESS, address);
|
||||||
fpga_reg_set(REG_MEM_SCR, (length << MEM_SCR_LENGTH_BIT) | MEM_SCR_DIRECTION | MEM_SCR_START);
|
fpga_reg_set(REG_MEM_SCR, (dma_length << MEM_SCR_LENGTH_BIT) | MEM_SCR_DIRECTION | MEM_SCR_START);
|
||||||
while (fpga_reg_get(REG_MEM_SCR) & MEM_SCR_BUSY);
|
while (fpga_reg_get(REG_MEM_SCR) & MEM_SCR_BUSY);
|
||||||
}
|
}
|
||||||
|
|
||||||
void fpga_mem_copy (uint32_t src, uint32_t dst, size_t length) {
|
void fpga_mem_copy (uint32_t src, uint32_t dst, size_t length) {
|
||||||
|
size_t dma_length = length;
|
||||||
|
if ((dma_length % 2) != 0) {
|
||||||
|
dma_length += 1;
|
||||||
|
}
|
||||||
|
|
||||||
fpga_reg_set(REG_MEM_ADDRESS, src);
|
fpga_reg_set(REG_MEM_ADDRESS, src);
|
||||||
fpga_reg_set(REG_MEM_SCR, (length << MEM_SCR_LENGTH_BIT) | MEM_SCR_START);
|
fpga_reg_set(REG_MEM_SCR, (dma_length << MEM_SCR_LENGTH_BIT) | MEM_SCR_START);
|
||||||
while (fpga_reg_get(REG_MEM_SCR) & MEM_SCR_BUSY);
|
while (fpga_reg_get(REG_MEM_SCR) & MEM_SCR_BUSY);
|
||||||
|
|
||||||
fpga_reg_set(REG_MEM_ADDRESS, dst);
|
fpga_reg_set(REG_MEM_ADDRESS, dst);
|
||||||
fpga_reg_set(REG_MEM_SCR, (length << MEM_SCR_LENGTH_BIT) | MEM_SCR_DIRECTION | MEM_SCR_START);
|
fpga_reg_set(REG_MEM_SCR, (dma_length << MEM_SCR_LENGTH_BIT) | MEM_SCR_DIRECTION | MEM_SCR_START);
|
||||||
while (fpga_reg_get(REG_MEM_SCR) & MEM_SCR_BUSY);
|
while (fpga_reg_get(REG_MEM_SCR) & MEM_SCR_BUSY);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -313,10 +313,10 @@ void hw_loader_reset (loader_parameters_t *parameters) {
|
|||||||
RCC->APBENR1 |= RCC_APBENR1_PWREN | RCC_APBENR1_RTCAPBEN;
|
RCC->APBENR1 |= RCC_APBENR1_PWREN | RCC_APBENR1_RTCAPBEN;
|
||||||
PWR->CR1 |= PWR_CR1_DBP;
|
PWR->CR1 |= PWR_CR1_DBP;
|
||||||
TAMP->BKP0R = parameters->magic;
|
TAMP->BKP0R = parameters->magic;
|
||||||
TAMP->BKP1R = parameters->mcu_address;
|
TAMP->BKP1R = parameters->flags;
|
||||||
TAMP->BKP2R = parameters->mcu_length;
|
TAMP->BKP2R = parameters->mcu_address;
|
||||||
TAMP->BKP3R = parameters->fpga_address;
|
TAMP->BKP3R = parameters->fpga_address;
|
||||||
TAMP->BKP4R = parameters->fpga_length;
|
TAMP->BKP4R = parameters->bootloader_address;
|
||||||
PWR->CR1 &= ~(PWR_CR1_DBP);
|
PWR->CR1 &= ~(PWR_CR1_DBP);
|
||||||
RCC->APBENR1 &= ~(RCC_APBENR1_PWREN | RCC_APBENR1_RTCAPBEN);
|
RCC->APBENR1 &= ~(RCC_APBENR1_PWREN | RCC_APBENR1_RTCAPBEN);
|
||||||
NVIC_SystemReset();
|
NVIC_SystemReset();
|
||||||
@ -325,10 +325,10 @@ void hw_loader_reset (loader_parameters_t *parameters) {
|
|||||||
void hw_loader_get_parameters (loader_parameters_t *parameters) {
|
void hw_loader_get_parameters (loader_parameters_t *parameters) {
|
||||||
RCC->APBENR1 |= RCC_APBENR1_PWREN | RCC_APBENR1_RTCAPBEN;
|
RCC->APBENR1 |= RCC_APBENR1_PWREN | RCC_APBENR1_RTCAPBEN;
|
||||||
parameters->magic = TAMP->BKP0R;
|
parameters->magic = TAMP->BKP0R;
|
||||||
parameters->mcu_address = TAMP->BKP1R;
|
parameters->flags = TAMP->BKP1R;
|
||||||
parameters->mcu_length = TAMP->BKP2R;
|
parameters->mcu_address = TAMP->BKP2R;
|
||||||
parameters->fpga_address = TAMP->BKP3R;
|
parameters->fpga_address = TAMP->BKP3R;
|
||||||
parameters->fpga_length = TAMP->BKP4R;
|
parameters->bootloader_address = TAMP->BKP4R;
|
||||||
PWR->CR1 |= PWR_CR1_DBP;
|
PWR->CR1 |= PWR_CR1_DBP;
|
||||||
TAMP->BKP0R = 0;
|
TAMP->BKP0R = 0;
|
||||||
TAMP->BKP1R = 0;
|
TAMP->BKP1R = 0;
|
||||||
|
@ -43,12 +43,18 @@ typedef enum {
|
|||||||
|
|
||||||
typedef uint64_t hw_flash_t;
|
typedef uint64_t hw_flash_t;
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
LOADER_FLAGS_UPDATE_MCU = (1 << 0),
|
||||||
|
LOADER_FLAGS_UPDATE_FPGA = (1 << 1),
|
||||||
|
LOADER_FLAGS_UPDATE_BOOTLOADER = (1 << 2),
|
||||||
|
} loader_parameters_flags_t;
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
uint32_t magic;
|
uint32_t magic;
|
||||||
|
loader_parameters_flags_t flags;
|
||||||
uint32_t mcu_address;
|
uint32_t mcu_address;
|
||||||
uint32_t mcu_length;
|
|
||||||
uint32_t fpga_address;
|
uint32_t fpga_address;
|
||||||
uint32_t fpga_length;
|
uint32_t bootloader_address;
|
||||||
} loader_parameters_t;
|
} loader_parameters_t;
|
||||||
|
|
||||||
|
|
||||||
|
@ -1,3 +1,4 @@
|
|||||||
|
#include "flash.h"
|
||||||
#include "fpga.h"
|
#include "fpga.h"
|
||||||
#include "hw.h"
|
#include "hw.h"
|
||||||
#include "update.h"
|
#include "update.h"
|
||||||
@ -5,12 +6,15 @@
|
|||||||
#include "vendor.h"
|
#include "vendor.h"
|
||||||
|
|
||||||
|
|
||||||
#define UPDATE_MAGIC_START (0x54535055)
|
#define UPDATE_MAGIC_START (0x54535055UL)
|
||||||
|
#define BOOTLOADER_ADDRESS (0x04E00000UL)
|
||||||
|
#define BOOTLOADER_LENGTH (0x001E0000UL)
|
||||||
|
|
||||||
|
|
||||||
typedef enum {
|
typedef enum {
|
||||||
UPDATE_STATUS_MCU = 1,
|
UPDATE_STATUS_MCU = 1,
|
||||||
UPDATE_STATUS_FPGA = 2,
|
UPDATE_STATUS_FPGA = 2,
|
||||||
|
UPDATE_STATUS_BOOTLOADER = 3,
|
||||||
UPDATE_STATUS_DONE = 0x80,
|
UPDATE_STATUS_DONE = 0x80,
|
||||||
UPDATE_STATUS_ERROR = 0xFF,
|
UPDATE_STATUS_ERROR = 0xFF,
|
||||||
} update_status_t;
|
} update_status_t;
|
||||||
@ -19,6 +23,7 @@ typedef enum {
|
|||||||
CHUNK_ID_UPDATE_INFO = 1,
|
CHUNK_ID_UPDATE_INFO = 1,
|
||||||
CHUNK_ID_MCU_DATA = 2,
|
CHUNK_ID_MCU_DATA = 2,
|
||||||
CHUNK_ID_FPGA_DATA = 3,
|
CHUNK_ID_FPGA_DATA = 3,
|
||||||
|
CHUNK_ID_BOOTLOADER_DATA = 4,
|
||||||
} chunk_id_t;
|
} chunk_id_t;
|
||||||
|
|
||||||
|
|
||||||
@ -31,6 +36,13 @@ static uint8_t status_data[12] = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
static uint32_t update_align (uint32_t value) {
|
||||||
|
if ((value % 16) != 0) {
|
||||||
|
value += (16 - (value % 16));
|
||||||
|
}
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
static uint32_t update_checksum (uint32_t address, uint32_t length) {
|
static uint32_t update_checksum (uint32_t address, uint32_t length) {
|
||||||
uint8_t buffer[32];
|
uint8_t buffer[32];
|
||||||
uint32_t block_size;
|
uint32_t block_size;
|
||||||
@ -55,16 +67,21 @@ static uint32_t update_write_token (uint32_t *address) {
|
|||||||
|
|
||||||
static uint32_t update_prepare_chunk (uint32_t *address, chunk_id_t chunk_id) {
|
static uint32_t update_prepare_chunk (uint32_t *address, chunk_id_t chunk_id) {
|
||||||
uint32_t id = (uint32_t) (chunk_id);
|
uint32_t id = (uint32_t) (chunk_id);
|
||||||
uint32_t length = sizeof(id) + (2 * sizeof(uint32_t));
|
uint32_t length = (4 * sizeof(uint32_t));
|
||||||
fpga_mem_write(*address, sizeof(id), (uint8_t *) (&id));
|
fpga_mem_write(*address, sizeof(id), (uint8_t *) (&id));
|
||||||
*address += length;
|
*address += length;
|
||||||
return length;
|
return length;
|
||||||
}
|
}
|
||||||
|
|
||||||
static uint32_t update_finalize_chunk (uint32_t *address, uint32_t length) {
|
static uint32_t update_finalize_chunk (uint32_t *address, uint32_t length) {
|
||||||
|
uint32_t chunk_length = ((4 * sizeof(uint32_t)) + length);
|
||||||
|
uint32_t aligned_chunk_length = update_align(chunk_length);
|
||||||
|
uint32_t aligned_length = aligned_chunk_length - (2 * sizeof(uint32_t));
|
||||||
uint32_t checksum = update_checksum(*address, length);
|
uint32_t checksum = update_checksum(*address, length);
|
||||||
fpga_mem_write(*address - (2 * sizeof(uint32_t)), sizeof(length), (uint8_t *) (&length));
|
fpga_mem_write(*address - (3 * sizeof(uint32_t)), sizeof(aligned_length), (uint8_t *) (&aligned_length));
|
||||||
fpga_mem_write(*address - sizeof(uint32_t), sizeof(checksum), (uint8_t *) (&checksum));
|
fpga_mem_write(*address - (2 * sizeof(uint32_t)), sizeof(checksum), (uint8_t *) (&checksum));
|
||||||
|
fpga_mem_write(*address - sizeof(uint32_t), sizeof(length), (uint8_t *) (&length));
|
||||||
|
length += (aligned_chunk_length - chunk_length);
|
||||||
*address += length;
|
*address += length;
|
||||||
return length;
|
return length;
|
||||||
}
|
}
|
||||||
@ -83,16 +100,19 @@ static bool update_check_token (uint32_t *address) {
|
|||||||
|
|
||||||
static bool update_get_chunk (uint32_t *address, chunk_id_t *chunk_id, uint32_t *data_address, uint32_t *data_length) {
|
static bool update_get_chunk (uint32_t *address, chunk_id_t *chunk_id, uint32_t *data_address, uint32_t *data_length) {
|
||||||
uint32_t id;
|
uint32_t id;
|
||||||
|
uint32_t chunk_length;
|
||||||
uint32_t checksum;
|
uint32_t checksum;
|
||||||
fpga_mem_read(*address, sizeof(id), (uint8_t *) (&id));
|
fpga_mem_read(*address, sizeof(id), (uint8_t *) (&id));
|
||||||
*chunk_id = (chunk_id_t) (id);
|
*chunk_id = (chunk_id_t) (id);
|
||||||
*address += sizeof(id);
|
*address += sizeof(id);
|
||||||
fpga_mem_read(*address, sizeof(*data_length), (uint8_t *) (data_length));
|
fpga_mem_read(*address, sizeof(chunk_length), (uint8_t *) (&chunk_length));
|
||||||
*address += sizeof(*data_length);
|
*address += sizeof(chunk_length);
|
||||||
fpga_mem_read(*address, sizeof(checksum), (uint8_t *) (&checksum));
|
fpga_mem_read(*address, sizeof(checksum), (uint8_t *) (&checksum));
|
||||||
*address += sizeof(checksum);
|
*address += sizeof(checksum);
|
||||||
|
fpga_mem_read(*address, sizeof(*data_length), (uint8_t *) (data_length));
|
||||||
|
*address += sizeof(*data_length);
|
||||||
*data_address = *address;
|
*data_address = *address;
|
||||||
*address += *data_length;
|
*address += (chunk_length - (2 * sizeof(uint32_t)));
|
||||||
if (checksum != update_checksum(*data_address, *data_length)) {
|
if (checksum != update_checksum(*data_address, *data_length)) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -127,16 +147,16 @@ static void update_status_notify (update_status_t status) {
|
|||||||
|
|
||||||
|
|
||||||
update_error_t update_backup (uint32_t address, uint32_t *length) {
|
update_error_t update_backup (uint32_t address, uint32_t *length) {
|
||||||
hw_flash_t buffer;
|
|
||||||
uint32_t mcu_length;
|
uint32_t mcu_length;
|
||||||
uint32_t fpga_length;
|
uint32_t fpga_length;
|
||||||
|
uint32_t bootloader_length;
|
||||||
|
|
||||||
*length = update_write_token(&address);
|
*length = update_write_token(&address);
|
||||||
|
|
||||||
*length += update_prepare_chunk(&address, CHUNK_ID_MCU_DATA);
|
*length += update_prepare_chunk(&address, CHUNK_ID_MCU_DATA);
|
||||||
mcu_length = hw_flash_size();
|
mcu_length = hw_flash_size();
|
||||||
for (uint32_t offset = 0; offset < mcu_length; offset += sizeof(hw_flash_t)) {
|
for (uint32_t offset = 0; offset < mcu_length; offset += sizeof(hw_flash_t)) {
|
||||||
buffer = hw_flash_read(offset);
|
hw_flash_t buffer = hw_flash_read(offset);
|
||||||
fpga_mem_write(address + offset, sizeof(hw_flash_t), (uint8_t *) (&buffer));
|
fpga_mem_write(address + offset, sizeof(hw_flash_t), (uint8_t *) (&buffer));
|
||||||
}
|
}
|
||||||
*length += update_finalize_chunk(&address, mcu_length);
|
*length += update_finalize_chunk(&address, mcu_length);
|
||||||
@ -147,6 +167,13 @@ update_error_t update_backup (uint32_t address, uint32_t *length) {
|
|||||||
}
|
}
|
||||||
*length += update_finalize_chunk(&address, fpga_length);
|
*length += update_finalize_chunk(&address, fpga_length);
|
||||||
|
|
||||||
|
*length += update_prepare_chunk(&address, CHUNK_ID_BOOTLOADER_DATA);
|
||||||
|
bootloader_length = BOOTLOADER_LENGTH;
|
||||||
|
for (uint32_t offset = 0; offset < bootloader_length; offset += FPGA_MAX_MEM_TRANSFER) {
|
||||||
|
fpga_mem_copy(BOOTLOADER_ADDRESS + offset, address + offset, FPGA_MAX_MEM_TRANSFER);
|
||||||
|
}
|
||||||
|
*length += update_finalize_chunk(&address, bootloader_length);
|
||||||
|
|
||||||
return UPDATE_OK;
|
return UPDATE_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -160,10 +187,10 @@ update_error_t update_prepare (uint32_t address, uint32_t length) {
|
|||||||
return UPDATE_ERROR_TOKEN;
|
return UPDATE_ERROR_TOKEN;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
parameters.flags = 0;
|
||||||
parameters.mcu_address = 0;
|
parameters.mcu_address = 0;
|
||||||
parameters.mcu_length = 0;
|
|
||||||
parameters.fpga_address = 0;
|
parameters.fpga_address = 0;
|
||||||
parameters.fpga_length = 0;
|
parameters.bootloader_address = 0;
|
||||||
|
|
||||||
while (address < end_address) {
|
while (address < end_address) {
|
||||||
if (update_get_chunk(&address, &id, &data_address, &data_length)) {
|
if (update_get_chunk(&address, &id, &data_address, &data_length)) {
|
||||||
@ -178,16 +205,24 @@ update_error_t update_prepare (uint32_t address, uint32_t length) {
|
|||||||
if (data_length > hw_flash_size()) {
|
if (data_length > hw_flash_size()) {
|
||||||
return UPDATE_ERROR_SIZE;
|
return UPDATE_ERROR_SIZE;
|
||||||
}
|
}
|
||||||
|
parameters.flags |= LOADER_FLAGS_UPDATE_MCU;
|
||||||
parameters.mcu_address = data_address;
|
parameters.mcu_address = data_address;
|
||||||
parameters.mcu_length = data_length;
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case CHUNK_ID_FPGA_DATA:
|
case CHUNK_ID_FPGA_DATA:
|
||||||
if (data_length > vendor_flash_size()) {
|
if (data_length > vendor_flash_size()) {
|
||||||
return UPDATE_ERROR_SIZE;
|
return UPDATE_ERROR_SIZE;
|
||||||
}
|
}
|
||||||
|
parameters.flags |= LOADER_FLAGS_UPDATE_FPGA;
|
||||||
parameters.fpga_address = data_address;
|
parameters.fpga_address = data_address;
|
||||||
parameters.fpga_length = data_length;
|
break;
|
||||||
|
|
||||||
|
case CHUNK_ID_BOOTLOADER_DATA:
|
||||||
|
if (data_length > BOOTLOADER_LENGTH) {
|
||||||
|
return UPDATE_ERROR_SIZE;
|
||||||
|
}
|
||||||
|
parameters.flags |= LOADER_FLAGS_UPDATE_BOOTLOADER;
|
||||||
|
parameters.bootloader_address = data_address;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
@ -209,12 +244,14 @@ bool update_check (void) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void update_perform (void) {
|
void update_perform (void) {
|
||||||
hw_flash_t buffer;
|
uint32_t length;
|
||||||
|
|
||||||
if (parameters.mcu_length != 0) {
|
if (parameters.flags & LOADER_FLAGS_UPDATE_MCU) {
|
||||||
|
hw_flash_t buffer;
|
||||||
update_status_notify(UPDATE_STATUS_MCU);
|
update_status_notify(UPDATE_STATUS_MCU);
|
||||||
|
fpga_mem_read(parameters.mcu_address - 4, sizeof(length), (uint8_t *) (&length));
|
||||||
hw_flash_erase();
|
hw_flash_erase();
|
||||||
for (uint32_t offset = 0; offset < parameters.mcu_length; offset += sizeof(hw_flash_t)) {
|
for (uint32_t offset = 0; offset < length; offset += sizeof(hw_flash_t)) {
|
||||||
fpga_mem_read(parameters.mcu_address + offset, sizeof(hw_flash_t), (uint8_t *) (&buffer));
|
fpga_mem_read(parameters.mcu_address + offset, sizeof(hw_flash_t), (uint8_t *) (&buffer));
|
||||||
hw_flash_program(offset, buffer);
|
hw_flash_program(offset, buffer);
|
||||||
if (hw_flash_read(offset) != buffer) {
|
if (hw_flash_read(offset) != buffer) {
|
||||||
@ -224,14 +261,26 @@ void update_perform (void) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (parameters.fpga_length != 0) {
|
if (parameters.flags & LOADER_FLAGS_UPDATE_FPGA) {
|
||||||
update_status_notify(UPDATE_STATUS_FPGA);
|
update_status_notify(UPDATE_STATUS_FPGA);
|
||||||
if (vendor_update(parameters.fpga_address, parameters.fpga_length) != VENDOR_OK) {
|
fpga_mem_read(parameters.fpga_address - 4, sizeof(length), (uint8_t *) (&length));
|
||||||
|
if (vendor_update(parameters.fpga_address, length) != VENDOR_OK) {
|
||||||
update_status_notify(UPDATE_STATUS_ERROR);
|
update_status_notify(UPDATE_STATUS_ERROR);
|
||||||
while (1);
|
while (1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (parameters.flags & LOADER_FLAGS_UPDATE_BOOTLOADER) {
|
||||||
|
update_status_notify(UPDATE_STATUS_BOOTLOADER);
|
||||||
|
fpga_mem_read(parameters.bootloader_address - 4, sizeof(length), (uint8_t *) (&length));
|
||||||
|
for (uint32_t offset = 0; offset < BOOTLOADER_LENGTH; offset += FLASH_ERASE_BLOCK_SIZE) {
|
||||||
|
flash_erase_block(BOOTLOADER_ADDRESS + offset);
|
||||||
|
}
|
||||||
|
for (uint32_t offset = 0; offset < length; offset += FPGA_MAX_MEM_TRANSFER) {
|
||||||
|
fpga_mem_copy(parameters.bootloader_address + offset, BOOTLOADER_ADDRESS + offset, FPGA_MAX_MEM_TRANSFER);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
update_status_notify(UPDATE_STATUS_DONE);
|
update_status_notify(UPDATE_STATUS_DONE);
|
||||||
|
|
||||||
vendor_reconfigure();
|
vendor_reconfigure();
|
||||||
|
1
sw/update/.gitignore
vendored
Normal file
1
sw/update/.gitignore
vendored
Normal file
@ -0,0 +1 @@
|
|||||||
|
*.upd
|
216
sw/update/update.py
Normal file
216
sw/update/update.py
Normal file
@ -0,0 +1,216 @@
|
|||||||
|
import argparse
|
||||||
|
import math
|
||||||
|
import os
|
||||||
|
import sys
|
||||||
|
from binascii import crc32
|
||||||
|
from datetime import datetime
|
||||||
|
from io import BufferedRandom
|
||||||
|
|
||||||
|
|
||||||
|
class JedecError(Exception):
|
||||||
|
pass
|
||||||
|
|
||||||
|
class JedecFile:
|
||||||
|
__fuse_length: int = 0
|
||||||
|
__fuse_offset: int = 0
|
||||||
|
__fuse_data: bytes = b''
|
||||||
|
__byte_buffer: int = 0
|
||||||
|
|
||||||
|
def __handle_q_field(self, f: BufferedRandom) -> None:
|
||||||
|
type = f.read(1)
|
||||||
|
if (type == b'F'):
|
||||||
|
value = b''
|
||||||
|
while (True):
|
||||||
|
data = f.read(1)
|
||||||
|
if (data == b'*'):
|
||||||
|
value = value.decode('ascii', errors='backslashreplace')
|
||||||
|
if (not value.isdecimal()):
|
||||||
|
raise JedecError('Invalid Q field data')
|
||||||
|
self.__fuse_length = int(value)
|
||||||
|
break
|
||||||
|
else:
|
||||||
|
value += data
|
||||||
|
else:
|
||||||
|
self.__ignore_field(f)
|
||||||
|
|
||||||
|
def __handle_l_field(self, f: BufferedRandom) -> None:
|
||||||
|
if (self.__fuse_length <= 0):
|
||||||
|
raise JedecError('Found fuse data before declaring fuse count')
|
||||||
|
|
||||||
|
offset = b''
|
||||||
|
while (True):
|
||||||
|
data = f.read(1)
|
||||||
|
if (data >= b'0' and data <= b'9'):
|
||||||
|
offset += data
|
||||||
|
elif (data == b'\r' or data == b'\n'):
|
||||||
|
offset = offset.decode('ascii', errors='backslashreplace')
|
||||||
|
if (not offset.isdecimal()):
|
||||||
|
raise JedecError('Invalid L field offset data')
|
||||||
|
offset = int(offset)
|
||||||
|
if (offset != self.__fuse_offset):
|
||||||
|
raise JedecError('Fuse data is not continuous')
|
||||||
|
break
|
||||||
|
else:
|
||||||
|
raise JedecError('Unexpected byte inside L field offset data')
|
||||||
|
|
||||||
|
data = b''
|
||||||
|
while (True):
|
||||||
|
data = f.read(1)
|
||||||
|
if (data == b'0' or data == b'1'):
|
||||||
|
shift = (7 - (self.__fuse_offset % 8))
|
||||||
|
self.__byte_buffer |= (1 if data == b'1' else 0) << shift
|
||||||
|
if (((self.__fuse_offset % 8) == 7) or (self.__fuse_offset == (self.__fuse_length - 1))):
|
||||||
|
self.__fuse_data += int.to_bytes(self.__byte_buffer, 1, byteorder='little')
|
||||||
|
self.__byte_buffer = 0
|
||||||
|
self.__fuse_offset += 1
|
||||||
|
elif (data == b'\r' or data == b'\n'):
|
||||||
|
pass
|
||||||
|
elif (data == b'*'):
|
||||||
|
break
|
||||||
|
elif (data == b''):
|
||||||
|
raise JedecError('Unexpected end of file')
|
||||||
|
else:
|
||||||
|
raise JedecError('Unexpected byte inside L field fuse data')
|
||||||
|
|
||||||
|
def __ignore_field(self, f: BufferedRandom) -> None:
|
||||||
|
data = None
|
||||||
|
while (data != b'*'):
|
||||||
|
data = f.read(1)
|
||||||
|
if (data == b''):
|
||||||
|
raise JedecError('Unexpected end of file')
|
||||||
|
|
||||||
|
def parse(self, path: str) -> bytes:
|
||||||
|
self.__fuse_length = 0
|
||||||
|
self.__fuse_offset = 0
|
||||||
|
self.__fuse_data = b''
|
||||||
|
self.__byte_buffer = 0
|
||||||
|
|
||||||
|
field = None
|
||||||
|
with open(path, 'rb+') as f:
|
||||||
|
while (True):
|
||||||
|
field = f.read(1)
|
||||||
|
if (field == b'\x02'):
|
||||||
|
f.seek(-1, os.SEEK_CUR)
|
||||||
|
break
|
||||||
|
elif (field == b''):
|
||||||
|
raise JedecError('Unexpected end of file')
|
||||||
|
|
||||||
|
while (True):
|
||||||
|
field = f.read(1)
|
||||||
|
if (field == b'Q'):
|
||||||
|
self.__handle_q_field(f)
|
||||||
|
elif (field == b'L'):
|
||||||
|
self.__handle_l_field(f)
|
||||||
|
elif (field == b'\r' or field == b'\n'):
|
||||||
|
pass
|
||||||
|
elif (field == b'\x03'):
|
||||||
|
break
|
||||||
|
elif (field == b''):
|
||||||
|
raise JedecError('Unexpected end of file')
|
||||||
|
else:
|
||||||
|
self.__ignore_field(f)
|
||||||
|
|
||||||
|
if (self.__fuse_length <= 0):
|
||||||
|
raise JedecError('No fuse data found')
|
||||||
|
|
||||||
|
if (self.__fuse_offset != self.__fuse_length):
|
||||||
|
raise JedecError('Missing fuse data inside JEDEC file')
|
||||||
|
|
||||||
|
if (len(self.__fuse_data) != math.ceil(self.__fuse_length / 8)):
|
||||||
|
raise JedecError('Missing fuse data inside JEDEC file')
|
||||||
|
|
||||||
|
return self.__fuse_data
|
||||||
|
|
||||||
|
|
||||||
|
class SC64UpdateData:
|
||||||
|
__UPDATE_TOKEN = b'SC64 Update v2.0'
|
||||||
|
|
||||||
|
__CHUNK_ID_UPDATE_INFO = 1
|
||||||
|
__CHUNK_ID_MCU_DATA = 2
|
||||||
|
__CHUNK_ID_FPGA_DATA = 3
|
||||||
|
__CHUNK_ID_BOOTLOADER_DATA = 4
|
||||||
|
|
||||||
|
__data = b''
|
||||||
|
|
||||||
|
def __int_to_bytes(self, value: int) -> bytes:
|
||||||
|
return value.to_bytes(4, byteorder='little')
|
||||||
|
|
||||||
|
def __align(self, value: int) -> int:
|
||||||
|
if (value % 16 != 0):
|
||||||
|
value += (16 - (value % 16))
|
||||||
|
return value
|
||||||
|
|
||||||
|
def __add_chunk(self, id: int, data: bytes) -> None:
|
||||||
|
chunk = b''
|
||||||
|
chunk_length = (16 + len(data))
|
||||||
|
aligned_length = self.__align(chunk_length)
|
||||||
|
chunk += self.__int_to_bytes(id)
|
||||||
|
chunk += self.__int_to_bytes(aligned_length - 8)
|
||||||
|
chunk += self.__int_to_bytes(crc32(data))
|
||||||
|
chunk += self.__int_to_bytes(len(data))
|
||||||
|
chunk += data
|
||||||
|
chunk += bytes([0] * (aligned_length - chunk_length))
|
||||||
|
self.__data += chunk
|
||||||
|
|
||||||
|
def create_update_data(self) -> None:
|
||||||
|
self.__data = self.__UPDATE_TOKEN
|
||||||
|
|
||||||
|
def add_update_info(self, data: bytes) -> None:
|
||||||
|
self.__add_chunk(self.__CHUNK_ID_UPDATE_INFO, data)
|
||||||
|
|
||||||
|
def add_mcu_data(self, data: bytes) -> None:
|
||||||
|
self.__add_chunk(self.__CHUNK_ID_MCU_DATA, data)
|
||||||
|
|
||||||
|
def add_fpga_data(self, data: bytes) -> None:
|
||||||
|
self.__add_chunk(self.__CHUNK_ID_FPGA_DATA, data)
|
||||||
|
|
||||||
|
def add_bootloader_data(self, data: bytes) -> None:
|
||||||
|
self.__add_chunk(self.__CHUNK_ID_BOOTLOADER_DATA, data)
|
||||||
|
|
||||||
|
def get_update_data(self) -> bytes:
|
||||||
|
return self.__data
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
parser = argparse.ArgumentParser(description='SC64 update file generator')
|
||||||
|
parser.add_argument('--info', metavar='info_text', required=False, help='text to embed as update info')
|
||||||
|
parser.add_argument('--mcu', metavar='mcu_path', required=False, help='path to MCU update data')
|
||||||
|
parser.add_argument('--fpga', metavar='fpga_path', required=False, help='path to FPGA update data')
|
||||||
|
parser.add_argument('--boot', metavar='bootloader_path', required=False, help='path to N64 bootloader update data')
|
||||||
|
parser.add_argument('output', metavar='output_path', help='path to final update data')
|
||||||
|
|
||||||
|
if (len(sys.argv) <= 1):
|
||||||
|
parser.print_help()
|
||||||
|
parser.exit()
|
||||||
|
|
||||||
|
args = parser.parse_args()
|
||||||
|
|
||||||
|
try:
|
||||||
|
update = SC64UpdateData()
|
||||||
|
update.create_update_data()
|
||||||
|
|
||||||
|
creation_time = datetime.now().strftime('%d.%m.%Y %H:%M:%S')
|
||||||
|
info_text = args.info or ''
|
||||||
|
update_info = f'{creation_time}{info_text}'
|
||||||
|
print(f'Update info text: {update_info}')
|
||||||
|
update.add_update_info(update_info.encode())
|
||||||
|
|
||||||
|
if (args.mcu):
|
||||||
|
with open(args.mcu, 'rb+') as f:
|
||||||
|
update.add_mcu_data(f.read())
|
||||||
|
|
||||||
|
if (args.fpga):
|
||||||
|
update.add_fpga_data(JedecFile().parse(args.fpga))
|
||||||
|
|
||||||
|
if (args.boot):
|
||||||
|
with open(args.boot, 'rb+') as f:
|
||||||
|
update.add_bootloader_data(f.read())
|
||||||
|
|
||||||
|
with open(args.output, 'wb+') as f:
|
||||||
|
f.write(update.get_update_data())
|
||||||
|
except JedecError as e:
|
||||||
|
print(f'Error while parsing FPGA update data: {e}')
|
||||||
|
exit(-1)
|
||||||
|
except IOError as e:
|
||||||
|
print(f'IOError: {e}')
|
||||||
|
exit(-1)
|
Loading…
Reference in New Issue
Block a user