Skip to content

Commit

Permalink
rp2040: move flash related functions into separate file from C import…
Browse files Browse the repository at this point in the history
…s for correct LSP. Fixes #3852

Signed-off-by: deadprogram <[email protected]>
  • Loading branch information
deadprogram committed Aug 13, 2023
1 parent 37a4fa2 commit bfe9ee3
Show file tree
Hide file tree
Showing 2 changed files with 100 additions and 81 deletions.
97 changes: 97 additions & 0 deletions src/machine/machine_rp2040_flash.go
Original file line number Diff line number Diff line change
@@ -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)
}
84 changes: 3 additions & 81 deletions src/machine/machine_rp2040_rom.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@
package machine

import (
"bytes"
"runtime/interrupt"
"unsafe"
)
Expand Down Expand Up @@ -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
}
Expand All @@ -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
Expand All @@ -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)
}

0 comments on commit bfe9ee3

Please sign in to comment.