Skip to content
Open
Show file tree
Hide file tree
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
2 changes: 1 addition & 1 deletion builder/build.go
Original file line number Diff line number Diff line change
Expand Up @@ -188,7 +188,7 @@ func Build(pkgName, outpath, tmpdir string, config *compileopts.Config) (BuildRe
defer unlock()
libcDependencies = append(libcDependencies, libcJob)
libcDependencies = append(libcDependencies, makeMinGWExtraLibs(tmpdir, config.GOARCH())...)
case "":
case "", "none":

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Why not just keep it as an empty string?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

It doesn't work. You can't set the libc to an empty string in the target json, it doesn't override and unset any base target setting.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

It's because in the json, the empty string is omitted (because of omitempty), so the setting never gets set to the empty string.

// no library specified, so nothing to do
default:
return BuildResult{}, fmt.Errorf("unknown libc: %s", config.Target.Libc)
Expand Down
2 changes: 1 addition & 1 deletion compileopts/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -434,7 +434,7 @@ func (c *Config) LibcCFlags() []string {
)
}
return cflags
case "":
case "", "none":
// No libc specified, nothing to add.
return nil
default:
Expand Down
22 changes: 22 additions & 0 deletions src/crypto/rand/rand_espidf.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
//go:build espidf

package rand

import "unsafe"

func init() {
Reader = &reader{}
}

type reader struct{}

//export esp_fill_random
func esp_fill_random(buf unsafe.Pointer, len uintptr)

func (r *reader) Read(b []byte) (n int, err error) {
if len(b) == 0 {
return
}
esp_fill_random(unsafe.Pointer(&b[0]), uintptr(len(b)))
return len(b), nil
}
52 changes: 52 additions & 0 deletions src/device/esp/esp32s3-stack.S

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Why did you move this to a new file? (Note that as long as tinygo_scanCurrentStack is not called it will be removed from the binary by the linker).

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

I think its because it still needs tinygo_scanCurrentStack for the GC. Without importing the other definitions in esp32s3.S which cause multiple definitions if I remember correctly.

Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
// -----------------------------------------------------------------------
// tinygo_scanCurrentStack — Spill all Xtensa register windows to the
// stack, then call tinygo_scanstack(sp) so the conservative GC can
// discover live heap pointers that are currently in physical registers.
//
// On RISC-V / ARM the equivalent function pushes callee-saved registers
// before the call. On Xtensa windowed ABI the same effect is achieved
// by forcing hardware window-overflow for every occupied pane: each
// overflow saves the four registers in that pane to the stack frame
// pointed to by the pane's a1 (sp). After all panes are flushed, a
// scan from the current sp to stackTop covers every live value.
// -----------------------------------------------------------------------
.section .text.tinygo_scanstack

.global tinygo_scanCurrentStack
tinygo_scanCurrentStack:
entry a1, 48

// Disable interrupts while flushing register windows.
rsr a4, PS
s32i a4, a1, 0 // save PS for later restore
rsil a4, 3 // XCHAL_EXCM_LEVEL

// Flush all register windows using recursive call4.
// For NAREG=64 (16 panes), 15 recursive levels cover all panes
// except the current one (which is kept active).
movi a6, 15
call4 .Lscan_spill

// Restore interrupts.
l32i a4, a1, 0
wsr.ps a4
rsync

// Pass current sp to tinygo_scanstack.
// call4 maps caller's a5→callee's a1 (stack ptr for callee's entry)
// and caller's a6→callee's a2 (first argument = sp).
mov a5, a1 // callee's a1 = valid stack pointer
mov a6, a1 // callee's a2 = sp argument
call4 tinygo_scanstack

retw

.balign 4
.Lscan_spill:
entry a1, 16
beqz a2, .Lscan_spill_done
addi a2, a2, -1
mov a6, a2
call4 .Lscan_spill
.Lscan_spill_done:
retw
53 changes: 0 additions & 53 deletions src/device/esp/esp32s3.S
Original file line number Diff line number Diff line change
Expand Up @@ -350,56 +350,3 @@ call_start_cpu0:

// If main returns, loop forever.
1: j 1b

// -----------------------------------------------------------------------
// tinygo_scanCurrentStack — Spill all Xtensa register windows to the
// stack, then call tinygo_scanstack(sp) so the conservative GC can
// discover live heap pointers that are currently in physical registers.
//
// On RISC-V / ARM the equivalent function pushes callee-saved registers
// before the call. On Xtensa windowed ABI the same effect is achieved
// by forcing hardware window-overflow for every occupied pane: each
// overflow saves the four registers in that pane to the stack frame
// pointed to by the pane's a1 (sp). After all panes are flushed, a
// scan from the current sp to stackTop covers every live value.
// -----------------------------------------------------------------------
.section .text.tinygo_scanCurrentStack

.global tinygo_scanCurrentStack
tinygo_scanCurrentStack:
entry a1, 48

// Disable interrupts while flushing register windows.
rsr a4, PS
s32i a4, a1, 0 // save PS for later restore
rsil a4, 3 // XCHAL_EXCM_LEVEL

// Flush all register windows using recursive call4.
// For NAREG=64 (16 panes), 15 recursive levels cover all panes
// except the current one (which is kept active).
movi a6, 15
call4 .Lscan_spill

// Restore interrupts.
l32i a4, a1, 0
wsr.ps a4
rsync

// Pass current sp to tinygo_scanstack.
// call4 maps caller's a5→callee's a1 (stack ptr for callee's entry)
// and caller's a6→callee's a2 (first argument = sp).
mov a5, a1 // callee's a1 = valid stack pointer
mov a6, a1 // callee's a2 = sp argument
call4 tinygo_scanstack

retw

.balign 4
.Lscan_spill:
entry a1, 16
beqz a2, .Lscan_spill_done
addi a2, a2, -1
mov a6, a2
call4 .Lscan_spill
.Lscan_spill_done:
retw
2 changes: 1 addition & 1 deletion src/runtime/atomics_critical.go
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
//go:build baremetal && !tinygo.wasm
//go:build baremetal && !tinygo.wasm && !espidf

// Automatically generated file. DO NOT EDIT.
// This file implements standins for non-native atomics using critical sections.
Expand Down
2 changes: 1 addition & 1 deletion src/runtime/baremetal.go
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
//go:build baremetal
//go:build baremetal && !espidf

package runtime

Expand Down
2 changes: 1 addition & 1 deletion src/runtime/interrupt/interrupt_none.go
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
//go:build !baremetal || tkey || uefi
//go:build !baremetal || tkey || uefi || espidf

package interrupt

Expand Down
2 changes: 1 addition & 1 deletion src/runtime/interrupt/interrupt_tinygoriscv.go
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
//go:build tinygo.riscv && !tkey
//go:build tinygo.riscv && !tkey && !espidf

package interrupt

Expand Down
2 changes: 1 addition & 1 deletion src/runtime/interrupt/interrupt_xtensa.go
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
//go:build xtensa && !esp32s3 && !esp32
//go:build xtensa && !esp32s3 && !esp32 && !espidf

package interrupt

Expand Down
2 changes: 1 addition & 1 deletion src/runtime/rand_norng.go
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
//go:build baremetal && !(nrf || (stm32 && !(stm32f103 || stm32l0x1 || stm32g0 || stm32u0)) || (sam && atsamd51) || (sam && atsame5x) || esp32c3 || esp32s3 || tkey || (tinygo.riscv32 && virt) || rp2040 || rp2350)
//go:build baremetal && !(nrf || (stm32 && !(stm32f103 || stm32l0x1 || stm32g0 || stm32u0)) || (sam && atsamd51) || (sam && atsame5x) || esp32c3 || esp32s3 || espidf || tkey || (tinygo.riscv32 && virt) || rp2040 || rp2350)

package runtime

Expand Down
128 changes: 128 additions & 0 deletions src/runtime/runtime_espidf.go

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Can you add a bit more documentation somewhere (this file, for example) describing how to use this target?

Original file line number Diff line number Diff line change
@@ -0,0 +1,128 @@
//go:build espidf

package runtime

import "unsafe"

var (
heapStart uintptr
heapEnd uintptr
globalsStart uintptr
globalsEnd uintptr
stackTop uintptr
)

// Allows C consumers of the library to set the GC variables.
//
//export tinygo_init
func tinygo_init(heap, heapSize, glob, globEnd, stack uintptr) {
heapStart, heapEnd = heap, heap+heapSize
globalsStart, globalsEnd = glob, globEnd
stackTop = stack
initRand()
initHeap()
initAll()
}

func growHeap() bool {
return false
}

//export abort
func abort()

//export exit
func exit(code int)

//export putchar
func libc_putchar(c byte)

func putchar(c byte) {
libc_putchar(c)
}

//export getchar
func libc_getchar() byte

func getchar() byte {
return libc_getchar()
}

func buffered() int {
return 0
}

const (
clock_REALTIME = 1
clock_MONOTONIC = 4
)

type timespec struct {
tv_sec int64
tv_nsec int32
}

//export clock_gettime
func clock_gettime(clock int32, ts *timespec)

func getTime(clock int32) uint64 {
var ts timespec
clock_gettime(clock, &ts)
Comment on lines +69 to +70

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Note that this might result in a heap allocation, which might not be intended (especially in a potentially time sensitive function).

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Right, but how would I ensure the struct is allocated on the stack? Is there no escape analysis?

return uint64(ts.tv_sec)*1e9 + uint64(ts.tv_nsec)
}

func monotime() uint64 {
return getTime(clock_MONOTONIC)
}

func ticks() timeUnit {
return timeUnit(monotime())
}

func ticksToNanoseconds(ticks timeUnit) int64 {
return int64(ticks)
}

func nanosecondsToTicks(ns int64) timeUnit {
return timeUnit(ns)
}

//export usleep
func usleep(usec uint) int

func sleepTicks(d timeUnit) {
usleep(uint(d / 1e3))
}

const baremetal = true

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

It's sort of in between now: ESP-IDF is kind of like an OS.
But since it isn't actually used (only use is in gc_blocks.go and it doesn't matter since hasScheduler is also false) it may be worth setting to false since what this actually controls is interrupt handling in the GC.


//go:linkname now time.now
func now() (sec int64, nsec int32, mono int64) {
var ts timespec
clock_gettime(clock_REALTIME, &ts)
sec = ts.tv_sec
nsec = ts.tv_nsec
mono = nanotime()
return
}

// Picolibc is not configured to define its own errno value, instead it calls
// __errno_location.
// TODO: a global works well enough for now (same as errno on Linux with
// -scheduler=tasks), but this should ideally be a thread-local variable stored
// in task.Task.
// Especially when we add multicore support for microcontrollers.
var errno int32

//export __errno_location
func libc_errno_location() *int32 {
return &errno
}

//export esp_fill_random
func esp_fill_random(buf unsafe.Pointer, len uintptr)

func hardwareRand() (n uint64, ok bool) {
esp_fill_random(unsafe.Pointer(&n), 8)
return n, true
}
15 changes: 15 additions & 0 deletions targets/esp32c3-idf.json

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Please add esp32c3-idf to TestClangAttributes, and also add a smoke test to GNUmakefile.

Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
{
"inherits": ["riscv32"],
"features": "+32bit,+c,+m,+zmmul,-a,-b,-d,-e,-experimental-sdext,-experimental-sdtrig,-experimental-smctr,-experimental-ssctr,-experimental-svukte,-experimental-xqcia,-experimental-xqciac,-experimental-xqcicli,-experimental-xqcicm,-experimental-xqcics,-experimental-xqcicsr,-experimental-xqciint,-experimental-xqcilo,-experimental-xqcilsm,-experimental-xqcisls,-experimental-zalasr,-experimental-zicfilp,-experimental-zicfiss,-experimental-zvbc32e,-experimental-zvkgs,-f,-h,-relax,-sha,-shcounterenw,-shgatpa,-shtvala,-shvsatpa,-shvstvala,-shvstvecd,-smaia,-smcdeleg,-smcsrind,-smdbltrp,-smepmp,-smmpm,-smnpm,-smrnmi,-smstateen,-ssaia,-ssccfg,-ssccptr,-sscofpmf,-sscounterenw,-sscsrind,-ssdbltrp,-ssnpm,-sspm,-ssqosid,-ssstateen,-ssstrict,-sstc,-sstvala,-sstvecd,-ssu64xl,-supm,-svade,-svadu,-svbare,-svinval,-svnapot,-svpbmt,-svvptc,-v,-xcvalu,-xcvbi,-xcvbitmanip,-xcvelw,-xcvmac,-xcvmem,-xcvsimd,-xesppie,-xmipscmove,-xmipslsp,-xsfcease,-xsfvcp,-xsfvfnrclipxfqf,-xsfvfwmaccqqq,-xsfvqmaccdod,-xsfvqmaccqoq,-xsifivecdiscarddlone,-xsifivecflushdlone,-xtheadba,-xtheadbb,-xtheadbs,-xtheadcmo,-xtheadcondmov,-xtheadfmemidx,-xtheadmac,-xtheadmemidx,-xtheadmempair,-xtheadsync,-xtheadvdot,-xventanacondops,-xwchc,-za128rs,-za64rs,-zaamo,-zabha,-zacas,-zalrsc,-zama16b,-zawrs,-zba,-zbb,-zbc,-zbkb,-zbkc,-zbkx,-zbs,-zca,-zcb,-zcd,-zce,-zcf,-zcmop,-zcmp,-zcmt,-zdinx,-zfa,-zfbfmin,-zfh,-zfhmin,-zfinx,-zhinx,-zhinxmin,-zic64b,-zicbom,-zicbop,-zicboz,-ziccamoa,-ziccif,-zicclsm,-ziccrse,-zicntr,-zicond,-zicsr,-zifencei,-zihintntl,-zihintpause,-zihpm,-zimop,-zk,-zkn,-zknd,-zkne,-zknh,-zkr,-zks,-zksed,-zksh,-zkt,-ztso,-zvbb,-zvbc,-zve32f,-zve32x,-zve64d,-zve64f,-zve64x,-zvfbfmin,-zvfbfwma,-zvfh,-zvfhmin,-zvkb,-zvkg,-zvkn,-zvknc,-zvkned,-zvkng,-zvknha,-zvknhb,-zvks,-zvksc,-zvksed,-zvksg,-zvksh,-zvkt,-zvl1024b,-zvl128b,-zvl16384b,-zvl2048b,-zvl256b,-zvl32768b,-zvl32b,-zvl4096b,-zvl512b,-zvl64b,-zvl65536b,-zvl8192b",
"build-tags": ["espidf", "esp"],

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Since you are not defining esp32c3, I assume it is okay for this target to be entirely without support from the machine package?

"scheduler": "none",
"rtlib": "none",
"libc": "none",
"cflags": [
"-march=rv32imc"
],
"ldflags": [
"-r",
"--no-gc-sections"
]
}
14 changes: 14 additions & 0 deletions targets/esp32s3-idf.json

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Please add esp32s3-idf to TestClangAttributes, and add a smoke test.

Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
{
"inherits": ["xtensa"],
"cpu": "esp32s3",
"features": "+atomctl,+bool,+clamps,+coprocessor,+debug,+density,+div32,+esp32s3,+exception,+fp,+highpriinterrupts,+interrupt,+loop,+mac16,+memctl,+minmax,+miscsr,+mul32,+mul32high,+nsa,+prid,+regprotect,+rvector,+s32c1i,+sext,+threadptr,+timerint,+windowed",
"build-tags": ["espidf", "esp"],
"linker": "ld.lld",
"ldflags": [
"-r",
"--no-gc-sections"
],
"extra-files": [
"src/device/esp/esp32s3-stack.S"
]
}
1 change: 1 addition & 0 deletions targets/esp32s3.json
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
"linkerscript": "targets/esp32s3.ld",
"extra-files": [
"src/device/esp/esp32s3.S",
"src/device/esp/esp32s3-stack.S",
"targets/esp32s3-interrupts.S",
"src/internal/task/task_stack_esp32.S"
],
Expand Down
2 changes: 1 addition & 1 deletion tools/gen-critical-atomics/gen-critical-atomics.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ var tmpl = template.Must(template.New("go").Funcs(template.FuncMap{
return v
},
"title": strings.Title,
}).Parse(`//go:build baremetal && !tinygo.wasm
}).Parse(`//go:build baremetal && !tinygo.wasm && !espidf

// Automatically generated file. DO NOT EDIT.
// This file implements standins for non-native atomics using critical sections.
Expand Down
Loading