-
-
Notifications
You must be signed in to change notification settings - Fork 1.1k
Add ESP-IDF build targets #5334
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: dev
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| 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 | ||
| } |
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe 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
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe 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 |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,4 +1,4 @@ | ||
| //go:build baremetal | ||
| //go:build baremetal && !espidf | ||
|
|
||
| package runtime | ||
|
|
||
|
|
||
| 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 | ||
|
|
||
|
|
||
| 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 | ||
|
|
||
|
|
||
| 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 | ||
|
|
||
|
|
||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe 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
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe 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).
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe 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 | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe 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. |
||
|
|
||
| //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 | ||
| } | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Please add |
| 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"], | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Since you are not defining |
||
| "scheduler": "none", | ||
| "rtlib": "none", | ||
| "libc": "none", | ||
| "cflags": [ | ||
| "-march=rv32imc" | ||
| ], | ||
| "ldflags": [ | ||
| "-r", | ||
| "--no-gc-sections" | ||
| ] | ||
| } | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Please add |
| 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" | ||
| ] | ||
| } |
There was a problem hiding this comment.
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?
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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.