From bfe9ee378fd7dd1ec9b42b8ca0bfc1b3b7d3e79a Mon Sep 17 00:00:00 2001 From: deadprogram Date: Sat, 12 Aug 2023 16:59:53 +0200 Subject: [PATCH] rp2040: move flash related functions into separate file from C imports for correct LSP. Fixes #3852 Signed-off-by: deadprogram --- src/machine/machine_rp2040_flash.go | 97 +++++++++++++++++++++++++++++ src/machine/machine_rp2040_rom.go | 84 +------------------------ 2 files changed, 100 insertions(+), 81 deletions(-) create mode 100644 src/machine/machine_rp2040_flash.go diff --git a/src/machine/machine_rp2040_flash.go b/src/machine/machine_rp2040_flash.go new file mode 100644 index 0000000000..f3d24e8e7d --- /dev/null +++ b/src/machine/machine_rp2040_flash.go @@ -0,0 +1,97 @@ +//go:build rp2040 + +package machine + +import ( + "bytes" + "unsafe" +) + +// EnterBootloader should perform a system reset in preparation +// to switch to the bootloader to flash new firmware. +func EnterBootloader() { + enterBootloader() +} + +// compile-time check for ensuring we fulfill BlockDevice interface +var _ BlockDevice = flashBlockDevice{} + +var Flash flashBlockDevice + +type flashBlockDevice struct { +} + +// ReadAt reads the given number of bytes from the block device. +func (f flashBlockDevice) ReadAt(p []byte, off int64) (n int, err error) { + if readAddress(off) > FlashDataEnd() { + return 0, errFlashCannotReadPastEOF + } + + data := unsafe.Slice((*byte)(unsafe.Pointer(readAddress(off))), len(p)) + copy(p, data) + + return len(p), nil +} + +// WriteAt writes the given number of bytes to the block device. +// Only word (32 bits) length data can be programmed. +// If the length of p is not long enough it will be padded with 0xFF bytes. +// This method assumes that the destination is already erased. +func (f flashBlockDevice) WriteAt(p []byte, off int64) (n int, err error) { + return f.writeAt(p, off) +} + +// Size returns the number of bytes in this block device. +func (f flashBlockDevice) Size() int64 { + return int64(FlashDataEnd() - FlashDataStart()) +} + +const writeBlockSize = 1 << 8 + +// WriteBlockSize returns the block size in which data can be written to +// memory. It can be used by a client to optimize writes, non-aligned writes +// should always work correctly. +func (f flashBlockDevice) WriteBlockSize() int64 { + return writeBlockSize +} + +const eraseBlockSizeValue = 1 << 12 + +func eraseBlockSize() int64 { + return eraseBlockSizeValue +} + +// EraseBlockSize returns the smallest erasable area on this particular chip +// in bytes. This is used for the block size in EraseBlocks. +func (f flashBlockDevice) EraseBlockSize() int64 { + return eraseBlockSize() +} + +// EraseBlocks erases the given number of blocks. An implementation may +// transparently coalesce ranges of blocks into larger bundles if the chip +// supports this. The start and len parameters are in block numbers, use +// EraseBlockSize to map addresses to blocks. +func (f flashBlockDevice) EraseBlocks(start, length int64) error { + return f.eraseBlocks(start, length) +} + +// pad data if needed so it is long enough for correct byte alignment on writes. +func (f flashBlockDevice) pad(p []byte) []byte { + overflow := int64(len(p)) % f.WriteBlockSize() + if overflow == 0 { + return p + } + + padding := bytes.Repeat([]byte{0xff}, int(f.WriteBlockSize()-overflow)) + return append(p, padding...) +} + +// return the correct address to be used for write +func writeAddress(off int64) uintptr { + return readAddress(off) - uintptr(memoryStart) +} + +// return the correct address to be used for reads +func readAddress(off int64) uintptr { + return FlashDataStart() + uintptr(off) +} diff --git a/src/machine/machine_rp2040_rom.go b/src/machine/machine_rp2040_rom.go index b4370c77c7..fdb05bb627 100644 --- a/src/machine/machine_rp2040_rom.go +++ b/src/machine/machine_rp2040_rom.go @@ -3,7 +3,6 @@ package machine import ( - "bytes" "runtime/interrupt" "unsafe" ) @@ -136,40 +135,14 @@ void ram_func flash_erase_blocks(uint32_t offset, size_t count) */ import "C" -// EnterBootloader should perform a system reset in preparation -// to switch to the bootloader to flash new firmware. -func EnterBootloader() { +func enterBootloader() { C.reset_usb_boot(0, 0) } // Flash related code const memoryStart = C.XIP_BASE // memory start for purpose of erase -// compile-time check for ensuring we fulfill BlockDevice interface -var _ BlockDevice = flashBlockDevice{} - -var Flash flashBlockDevice - -type flashBlockDevice struct { -} - -// ReadAt reads the given number of bytes from the block device. -func (f flashBlockDevice) ReadAt(p []byte, off int64) (n int, err error) { - if readAddress(off) > FlashDataEnd() { - return 0, errFlashCannotReadPastEOF - } - - data := unsafe.Slice((*byte)(unsafe.Pointer(readAddress(off))), len(p)) - copy(p, data) - - return len(p), nil -} - -// WriteAt writes the given number of bytes to the block device. -// Only word (32 bits) length data can be programmed. -// If the length of p is not long enough it will be padded with 0xFF bytes. -// This method assumes that the destination is already erased. -func (f flashBlockDevice) WriteAt(p []byte, off int64) (n int, err error) { +func (f flashBlockDevice) writeAt(p []byte, off int64) (n int, err error) { if writeAddress(off)+uintptr(C.XIP_BASE) > FlashDataEnd() { return 0, errFlashCannotWritePastEOF } @@ -190,37 +163,7 @@ func (f flashBlockDevice) WriteAt(p []byte, off int64) (n int, err error) { return len(padded), nil } -// Size returns the number of bytes in this block device. -func (f flashBlockDevice) Size() int64 { - return int64(FlashDataEnd() - FlashDataStart()) -} - -const writeBlockSize = 1 << 8 - -// WriteBlockSize returns the block size in which data can be written to -// memory. It can be used by a client to optimize writes, non-aligned writes -// should always work correctly. -func (f flashBlockDevice) WriteBlockSize() int64 { - return writeBlockSize -} - -const eraseBlockSizeValue = 1 << 12 - -func eraseBlockSize() int64 { - return eraseBlockSizeValue -} - -// EraseBlockSize returns the smallest erasable area on this particular chip -// in bytes. This is used for the block size in EraseBlocks. -func (f flashBlockDevice) EraseBlockSize() int64 { - return eraseBlockSize() -} - -// EraseBlocks erases the given number of blocks. An implementation may -// transparently coalesce ranges of blocks into larger bundles if the chip -// supports this. The start and len parameters are in block numbers, use -// EraseBlockSize to map addresses to blocks. -func (f flashBlockDevice) EraseBlocks(start, length int64) error { +func (f flashBlockDevice) eraseBlocks(start, length int64) error { address := writeAddress(start * f.EraseBlockSize()) if address+uintptr(C.XIP_BASE) > FlashDataEnd() { return errFlashCannotErasePastEOF @@ -233,24 +176,3 @@ func (f flashBlockDevice) EraseBlocks(start, length int64) error { return nil } - -// pad data if needed so it is long enough for correct byte alignment on writes. -func (f flashBlockDevice) pad(p []byte) []byte { - overflow := int64(len(p)) % f.WriteBlockSize() - if overflow == 0 { - return p - } - - padding := bytes.Repeat([]byte{0xff}, int(f.WriteBlockSize()-overflow)) - return append(p, padding...) -} - -// return the correct address to be used for write -func writeAddress(off int64) uintptr { - return readAddress(off) - uintptr(C.XIP_BASE) -} - -// return the correct address to be used for reads -func readAddress(off int64) uintptr { - return FlashDataStart() + uintptr(off) -}