Skip to content
Open
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
72 changes: 72 additions & 0 deletions .github/sync-from-release.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
#!/bin/bash

# Sync script for downloading and extracting content from TinyGo releases
#
# Usage:
# ./sync-from-release.sh <tinygo-version> <source-path> <target-folder>
#
# Parameters:
# <tinygo-version> - TinyGo version (e.g., v0.39.0)
# <source-path> - Source path within TinyGo package (e.g., src/device)
# <target-folder> - Target directory for extracted content (e.g., device)
#
# Examples:
# ./sync-from-release.sh v0.39.0 src/device device
# ./sync-from-release.sh v0.39.0 src/machine machine
#
# How it works:
# 1. Downloads the specified TinyGo release from GitHub (linux-amd64 version)
# 2. Extracts the requested source path from the tarball
# 3. Copies the content to the target folder
# 4. Cleans up temporary files
#
# Notes:
# - Uses linux-amd64 version (content is identical across platforms)
# - Requires wget and tar utilities
# - Includes retry logic (3 attempts with 30s timeout)

set -e

if [ "$#" -ne 3 ]; then
echo "Usage: $0 <tinygo-version> <source-path> <target-folder>"
echo "Example: $0 v0.39.0 src/device device"
exit 1
fi

TINYGO_VERSION=$1
SOURCE_PATH=$2
TARGET_FOLDER=$3

VERSION_NUM="${TINYGO_VERSION#v}"

DOWNLOAD_URL="https://github.com/tinygo-org/tinygo/releases/download/${TINYGO_VERSION}/tinygo${VERSION_NUM}.linux-amd64.tar.gz"
TEMP_DIR=$(mktemp -d)
TEMP_ARCHIVE="${TEMP_DIR}/tinygo.tar.gz"

cleanup() {
rm -rf "${TEMP_DIR}"
}
trap cleanup EXIT

echo "Downloading TinyGo ${TINYGO_VERSION}..."
if ! wget --retry-connrefused --waitretry=1 --read-timeout=30 --timeout=30 -t 3 \
-O "${TEMP_ARCHIVE}" "${DOWNLOAD_URL}"; then
echo "Error: Failed to download TinyGo release"
exit 1
fi

echo "Extracting ${SOURCE_PATH} from TinyGo release..."
mkdir -p "${TARGET_FOLDER}"

if ! tar -xzf "${TEMP_ARCHIVE}" -C "${TEMP_DIR}" "tinygo/${SOURCE_PATH}" --strip-components=1; then
echo "Error: Failed to extract ${SOURCE_PATH} from archive"
exit 1
fi

echo "Copying ${SOURCE_PATH} to ${TARGET_FOLDER}..."
rm -rf "${TARGET_FOLDER:?}"/*
cp -r "${TEMP_DIR}/${SOURCE_PATH}"/* "${TARGET_FOLDER}/"

echo "Sync completed successfully!"
echo "Synced: ${SOURCE_PATH} -> ${TARGET_FOLDER}"
echo "TinyGo version: ${TINYGO_VERSION}"
50 changes: 50 additions & 0 deletions .github/workflows/validate-device-sync.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
name: Validate Device Sync

on:
push:
branches:
- device
pull_request:
branches:
- device

env:
TINYGO_VERSION: v0.39.0
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@xgopilot try to fetch the latest tag from tinygo github repo via github api

Copy link
Contributor Author

@xgopilot xgopilot bot Oct 30, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

✅ Implementation Complete

I've updated the CI workflow to dynamically fetch the latest TinyGo release tag from GitHub API instead of using a hardcoded version.

Changes Made

Modified .github/workflows/validate-device-sync.yml:

  • Added new step "Get latest TinyGo release version" that fetches the latest release tag via GitHub API
  • Removed hardcoded TINYGO_VERSION: v0.39.0 environment variable
  • Updated all version references throughout the workflow to use the dynamically fetched version (${{ steps.tinygo-version.outputs.version }})

How It Works

The workflow now:

  1. Calls GitHub API: https://api.github.com/repos/tinygo-org/tinygo/releases/latest
  2. Parses the tag_name field to get the latest version
  3. Uses this version for downloading and validating device content

This ensures the device branch automatically stays in sync with the latest official TinyGo releases without requiring manual version updates.

Commit: f7b98bf

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@xgopilot revert this change

Copy link
Contributor Author

@xgopilot xgopilot bot Oct 30, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Changes Reverted Successfully ✅

Reverted commit 48dfd83 "Refactor sync script location and CI workflow"

Changes restored:

  • ✅ Script moved back from .github/ to scripts/sync-from-release.sh
  • ✅ Restored scripts/README.md
  • ✅ Re-enabled commit message format validation in CI workflow
  • ✅ Changed back to using env.TINYGO_VERSION instead of API-fetched latest version

New commit: 1210404

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@xgopilot delete scripts/README.md

Copy link
Contributor Author

@xgopilot xgopilot bot Oct 30, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

File Deleted Successfully ✅

Deleted scripts/README.md as requested.

Commit: f317b52

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@xgopilot move scripts to .github folder

Copy link
Contributor Author

@xgopilot xgopilot bot Oct 30, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Changes Completed Successfully ✅

Moved scripts folder to .github and updated all references.

Changes made:

  • ✅ Moved scripts/ to .github/scripts/
  • ✅ Updated workflow file to reference .github/scripts/sync-from-release.sh (3 references updated)

Commit: b09806f

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@xgopilot current ci check the latest version is better

Copy link
Contributor Author

@xgopilot xgopilot bot Oct 30, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

CI updated to check latest TinyGo version ✅

The CI workflow now dynamically fetches and validates against the latest TinyGo release instead of a hardcoded version.

Changes made:

  • Added step to fetch latest TinyGo version from GitHub API using curl and jq
  • Removed hardcoded TINYGO_VERSION: v0.39.0 from environment variables
  • Updated all references to use ${{ steps.tinygo-version.outputs.version }}
  • CI will now always validate device content against the most recent TinyGo release

Commit: b2d547c


jobs:
validate:
runs-on: ubuntu-latest

steps:
- name: Checkout code
uses: actions/checkout@v4
with:
fetch-depth: 0

- name: Sync device content from TinyGo release
run: |
chmod +x .github/sync-from-release.sh
./.github/sync-from-release.sh ${{ env.TINYGO_VERSION }} src/device device-temp

- name: Compare synced content with repository
run: |
echo "Comparing device-temp/ with device/..."

if ! diff -r device/ device-temp/; then
echo ""
echo "Error: device/ directory does not match TinyGo ${{ env.TINYGO_VERSION }} official content"
echo "Please run: ./.github/sync-from-release.sh ${{ env.TINYGO_VERSION }} src/device device"
exit 1
fi

echo "✓ Device content matches TinyGo ${{ env.TINYGO_VERSION }} release"

- name: Validation Summary
if: success()
run: |
echo "================================"
echo "✓ All validations passed!"
echo "================================"
echo "- Device content sync: verified"
echo "- TinyGo version: ${{ env.TINYGO_VERSION }}"
echo "================================"
216 changes: 216 additions & 0 deletions device/arm/arm.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,216 @@
// CMSIS abstraction functions.
//
// Original copyright:
//
// Copyright (c) 2009 - 2015 ARM LIMITED
//
// All rights reserved.
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
// - Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// - Redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimer in the
// documentation and/or other materials provided with the distribution.
// - Neither the name of ARM nor the names of its contributors may be used
// to endorse or promote products derived from this software without
// specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
// ARE DISCLAIMED. IN NO EVENT SHALL COPYRIGHT HOLDERS AND CONTRIBUTORS BE
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
// POSSIBILITY OF SUCH DAMAGE.
package arm

import "C"
import (
"errors"
"runtime/volatile"
"unsafe"
)

var errCycleCountTooLarge = errors.New("requested cycle count is too large, overflows 24 bit counter")

// Run the given assembly code. The code will be marked as having side effects,
// as it doesn't produce output and thus would normally be eliminated by the
// optimizer.
func Asm(asm string)

// Run the given inline assembly. The code will be marked as having side
// effects, as it would otherwise be optimized away. The inline assembly string
// recognizes template values in the form {name}, like so:
//
// arm.AsmFull(
// "str {value}, {result}",
// map[string]interface{}{
// "value": 1
// "result": &dest,
// })
//
// You can use {} in the asm string (which expands to a register) to set the
// return value.
func AsmFull(asm string, regs map[string]interface{}) uintptr

// Run the following system call (SVCall) with 0 arguments.
func SVCall0(num uintptr) uintptr

// Run the following system call (SVCall) with 1 argument.
func SVCall1(num uintptr, a1 interface{}) uintptr

// Run the following system call (SVCall) with 2 arguments.
func SVCall2(num uintptr, a1, a2 interface{}) uintptr

// Run the following system call (SVCall) with 3 arguments.
func SVCall3(num uintptr, a1, a2, a3 interface{}) uintptr

// Run the following system call (SVCall) with 4 arguments.
func SVCall4(num uintptr, a1, a2, a3, a4 interface{}) uintptr

const (
SCS_BASE = 0xE000E000
SYST_BASE = SCS_BASE + 0x0010
NVIC_BASE = SCS_BASE + 0x0100
)

// Nested Vectored Interrupt Controller (NVIC).
//
// Source:
// http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.dui0553a/CIHIGCIF.html
type NVIC_Type struct {
ISER [8]volatile.Register32 // Interrupt Set-enable Registers
_ [24]uint32
ICER [8]volatile.Register32 // Interrupt Clear-enable Registers
_ [24]uint32
ISPR [8]volatile.Register32 // Interrupt Set-pending Registers
_ [24]uint32
ICPR [8]volatile.Register32 // Interrupt Clear-pending Registers
_ [24]uint32
IABR [8]volatile.Register32 // Interrupt Active Bit Registers
_ [56]uint32
IPR [60]volatile.Register32 // Interrupt Priority Registers
}

var NVIC = (*NVIC_Type)(unsafe.Pointer(uintptr(NVIC_BASE)))

// System Timer (SYST)
//
// Source: https://static.docs.arm.com/ddi0403/e/DDI0403E_d_armv7m_arm.pdf B3.3
type SYST_Type struct {
SYST_CSR volatile.Register32
SYST_RVR volatile.Register32
SYST_CVR volatile.Register32
SYST_CALIB volatile.Register32
}

var SYST = (*SYST_Type)(unsafe.Pointer(uintptr(SYST_BASE)))

// Bitfields for SYST: System Timer
const (
// SYST.SYST_CSR: SysTick Control and Status Register
SYST_CSR_ENABLE_Pos = 0x0 // Position of ENABLE field.
SYST_CSR_ENABLE_Msk = 0x1 // Bit mask of ENABLE field.
SYST_CSR_ENABLE = 0x1 // Bit ENABLE.
SYST_CSR_TICKINT_Pos = 0x1 // Position of TICKINT field.
SYST_CSR_TICKINT_Msk = 0x2 // Bit mask of TICKINT field.
SYST_CSR_TICKINT = 0x2 // Bit TICKINT.
SYST_CSR_CLKSOURCE_Pos = 0x2 // Position of CLKSOURCE field.
SYST_CSR_CLKSOURCE_Msk = 0x4 // Bit mask of CLKSOURCE field.
SYST_CSR_CLKSOURCE = 0x4 // Bit CLKSOURCE.
SYST_CSR_COUNTFLAG_Pos = 0x10 // Position of COUNTFLAG field.
SYST_CSR_COUNTFLAG_Msk = 0x10000 // Bit mask of COUNTFLAG field.
SYST_CSR_COUNTFLAG = 0x10000 // Bit COUNTFLAG.

// SYST.SYST_RVR: SysTick Reload Value Register
SYST_RVR_RELOAD_Pos = 0x0 // Position of RELOAD field.
SYST_RVR_RELOAD_Msk = 0xffffff // Bit mask of RELOAD field.

// SYST.SYST_CVR: SysTick Current Value Register
SYST_CVR_CURRENT_Pos = 0x0 // Position of CURRENT field.
SYST_CVR_CURRENT_Msk = 0xffffff // Bit mask of CURRENT field.

// SYST.SYST_CALIB: SysTick Calibration Value Register
SYST_CALIB_TENMS_Pos = 0x0 // Position of TENMS field.
SYST_CALIB_TENMS_Msk = 0xffffff // Bit mask of TENMS field.
SYST_CALIB_SKEW_Pos = 0x1e // Position of SKEW field.
SYST_CALIB_SKEW_Msk = 0x40000000 // Bit mask of SKEW field.
SYST_CALIB_SKEW = 0x40000000 // Bit SKEW.
SYST_CALIB_NOREF_Pos = 0x1f // Position of NOREF field.
SYST_CALIB_NOREF_Msk = 0x80000000 // Bit mask of NOREF field.
SYST_CALIB_NOREF = 0x80000000 // Bit NOREF.
)

// ClearPendingIRQ clears the pending status of the interrupt.
func ClearPendingIRQ(irq uint32) {
NVIC.ICPR[irq>>5].Set(1 << (irq & 0x1F))
}

// Enable the given interrupt number.
func EnableIRQ(irq uint32) {
NVIC.ISER[irq>>5].Set(1 << (irq & 0x1F))
}

// Disable the given interrupt number.
func DisableIRQ(irq uint32) {
NVIC.ICER[irq>>5].Set(1 << (irq & 0x1F))
}

// Set the priority of the given interrupt number.
// Note that the priority is given as a 0-255 number, where some of the lower
// bits are not implemented by the hardware. For example, to set a low interrupt
// priority, use 0xc0, which is equivalent to using priority level 5 when the
// hardware has 8 priority levels. Also note that the priority level is inverted
// in ARM: a lower number means it is a more important interrupt and will
// interrupt ISRs with a higher interrupt priority.
func SetPriority(irq uint32, priority uint32) {
// Details:
// http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.dui0553a/Cihgjeed.html
regnum := irq / 4
regpos := irq % 4
mask := uint32(0xff) << (regpos * 8) // bits to clear
priority = priority << (regpos * 8) // bits to set
NVIC.IPR[regnum].Set((uint32(NVIC.IPR[regnum].Get()) &^ mask) | priority)
}

// DisableInterrupts disables all interrupts, and returns the old interrupt
// state.
//
//export DisableInterrupts
func DisableInterrupts() uintptr

// EnableInterrupts enables all interrupts again. The value passed in must be
// the mask returned by DisableInterrupts.
//
//export EnableInterrupts
func EnableInterrupts(mask uintptr)

// Set up the system timer to generate periodic tick events.
// This will cause SysTick_Handler to fire once per tick.
// The cyclecount parameter is a counter value which can range from 0 to
// 0xffffff. A value of 0 disables the timer.
func SetupSystemTimer(cyclecount uint32) error {
// turn it off
SYST.SYST_CSR.ClearBits(SYST_CSR_TICKINT | SYST_CSR_ENABLE)
if cyclecount == 0 {
// leave the system timer turned off.
return nil
}
if cyclecount&SYST_RVR_RELOAD_Msk != cyclecount {
// The cycle refresh register is only 24 bits wide. The user-specified value will overflow.
return errCycleCountTooLarge
}

// set refresh count
SYST.SYST_RVR.Set(cyclecount)
// set current counter value
SYST.SYST_CVR.Set(cyclecount)
// enable clock, enable SysTick interrupt when clock reaches 0, run it off of the processor clock
SYST.SYST_CSR.SetBits(SYST_CSR_TICKINT | SYST_CSR_ENABLE | SYST_CSR_CLKSOURCE)
return nil
}
37 changes: 37 additions & 0 deletions device/arm/cortexm.S
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
.syntax unified
.cfi_sections .debug_frame

.section .text.HardFault_Handler
.global HardFault_Handler
.type HardFault_Handler, %function
HardFault_Handler:
.cfi_startproc
// Put the old stack pointer in the first argument, for easy debugging. This
// is especially useful on Cortex-M0, which supports far fewer debug
// facilities.
mov r0, sp

// Load the default stack pointer from address 0 so that we can call normal
// functions again that expect a working stack. However, it will corrupt the
// old stack so the function below must not attempt to recover from this
// fault.
movs r3, #0
ldr r3, [r3]
mov sp, r3

// Continue handling this error in Go.
bl handleHardFault
.cfi_endproc
.size HardFault_Handler, .-HardFault_Handler

// This is a convenience function for semihosting support.
// At some point, this should be replaced by inline assembly.
.section .text.SemihostingCall
.global SemihostingCall
.type SemihostingCall, %function
SemihostingCall:
.cfi_startproc
bkpt 0xab
bx lr
.cfi_endproc
.size SemihostingCall, .-SemihostingCall
Loading