Skip to content

Commit 7158e2b

Browse files
committed
test: run tests for AVR
This runs the currently working compiler tests for AVR using simavr. I picked the atmega1284p target as it seems like the most suitable one (most importantly, with a lot of RAM) so that tests are less likely to hit resource limitations. One extra change this required is using a different implementation of the runtime.abort() function. The new one is smaller and will prevent interrupts from running on exit, which should at least in theory be fine. This pattern is required as it signals to simavr the program is finished.
1 parent 9c2d2b6 commit 7158e2b

File tree

3 files changed

+63
-3
lines changed

3 files changed

+63
-3
lines changed

.circleci/config.yml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ commands:
2626
gcc-aarch64-linux-gnu \
2727
qemu-system-arm \
2828
qemu-user \
29+
simavr \
2930
gcc-avr \
3031
avr-libc
3132
sudo apt-get install --no-install-recommends libc6-dev-i386 lib32gcc-8-dev
@@ -139,6 +140,7 @@ commands:
139140
libc6-dev-arm64-cross \
140141
qemu-system-arm \
141142
qemu-user \
143+
simavr \
142144
gcc-avr \
143145
avr-libc
144146
sudo apt-get install --no-install-recommends libc6-dev-i386 lib32gcc-6-dev
@@ -200,6 +202,7 @@ commands:
200202
libc6-dev-arm64-cross \
201203
qemu-system-arm \
202204
qemu-user \
205+
simavr \
203206
gcc-avr \
204207
avr-libc
205208
sudo apt-get install --no-install-recommends libc6-dev-i386 lib32gcc-6-dev

main_test.go

Lines changed: 53 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,10 @@ import (
1212
"os"
1313
"os/exec"
1414
"path/filepath"
15+
"regexp"
1516
"runtime"
1617
"sort"
18+
"strconv"
1719
"strings"
1820
"sync"
1921
"testing"
@@ -22,12 +24,31 @@ import (
2224
"github.com/tinygo-org/tinygo/builder"
2325
"github.com/tinygo-org/tinygo/compileopts"
2426
"github.com/tinygo-org/tinygo/goenv"
27+
"tinygo.org/x/go-llvm"
2528
)
2629

2730
const TESTDATA = "testdata"
2831

2932
var testTarget = flag.String("target", "", "override test target")
3033

34+
// There are a lot of tests that don't yet pass on AVR, often because avr-libc
35+
// doesn't provide the required functions (for float64 for example).
36+
var skipOnAVR = map[string]struct{}{
37+
"testdata/atomic.go": {},
38+
"testdata/cgo/": {},
39+
"testdata/channel.go": {},
40+
"testdata/coroutines.go": {},
41+
"testdata/float.go": {},
42+
"testdata/gc.go": {},
43+
"testdata/interface.go": {},
44+
"testdata/map.go": {},
45+
"testdata/math.go": {},
46+
"testdata/print.go": {},
47+
"testdata/reflect.go": {},
48+
"testdata/stdlib.go": {},
49+
"testdata/structs.go": {},
50+
}
51+
3152
func TestCompiler(t *testing.T) {
3253
matches, err := filepath.Glob(filepath.Join(TESTDATA, "*.go"))
3354
if err != nil {
@@ -105,6 +126,15 @@ func TestCompiler(t *testing.T) {
105126
t.Run("WASI", func(t *testing.T) {
106127
runPlatTests("wasi", matches, t)
107128
})
129+
130+
llvmMajorVersion, _ := strconv.ParseInt(strings.Split(llvm.Version, ".")[0], 10, 32)
131+
if llvmMajorVersion >= 11 {
132+
// The AVR backend in LLVM 11 has been significantly improved and is
133+
// able to correctly compile a lot more tests than before.
134+
t.Run("AVR", func(t *testing.T) {
135+
runPlatTests("atmega1284p", matches, t)
136+
})
137+
}
108138
}
109139
}
110140

@@ -114,6 +144,13 @@ func runPlatTests(target string, matches []string, t *testing.T) {
114144
for _, path := range matches {
115145
path := path // redefine to avoid race condition
116146

147+
if target == "atmega1284p" {
148+
if _, ok := skipOnAVR[path]; ok {
149+
// Some tests don't work on AVR yet, so skip them.
150+
continue
151+
}
152+
}
153+
117154
t.Run(filepath.Base(path), func(t *testing.T) {
118155
t.Parallel()
119156
runTest(path, target, t)
@@ -180,6 +217,7 @@ func runTest(path, target string, t *testing.T) {
180217
runComplete := make(chan struct{})
181218
var cmd *exec.Cmd
182219
ranTooLong := false
220+
var emulator = ""
183221
if target == "" {
184222
cmd = exec.Command(binary)
185223
} else {
@@ -190,13 +228,19 @@ func runTest(path, target string, t *testing.T) {
190228
if len(spec.Emulator) == 0 {
191229
cmd = exec.Command(binary)
192230
} else {
231+
emulator = spec.Emulator[0]
193232
args := append(spec.Emulator[1:], binary)
194233
cmd = exec.Command(spec.Emulator[0], args...)
195234
}
196235
}
197236
stdout := &bytes.Buffer{}
198-
cmd.Stdout = stdout
199-
cmd.Stderr = os.Stderr
237+
if emulator == "simavr" {
238+
cmd.Stdout = nil
239+
cmd.Stderr = stdout
240+
} else {
241+
cmd.Stdout = stdout
242+
cmd.Stderr = os.Stderr
243+
}
200244
err = cmd.Start()
201245
if err != nil {
202246
t.Fatal("failed to start:", err)
@@ -230,6 +274,13 @@ func runTest(path, target string, t *testing.T) {
230274
actual := bytes.Replace(stdout.Bytes(), []byte{'\r', '\n'}, []byte{'\n'}, -1)
231275
expected = bytes.Replace(expected, []byte{'\r', '\n'}, []byte{'\n'}, -1) // for Windows
232276

277+
if emulator == "simavr" {
278+
// Munge the data a bit to remove escape characters and the two dots
279+
// simavr likes to put at the end of each line.
280+
actual = regexp.MustCompile("\x1b.*?m").ReplaceAll(actual, nil)
281+
actual = regexp.MustCompile("\\.\\.\n").ReplaceAll(actual, []byte{'\n'})
282+
}
283+
233284
// Check whether the command ran successfully.
234285
fail := false
235286
if err != nil {

src/runtime/runtime_avr.go

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -96,7 +96,13 @@ func ticks() timeUnit {
9696
}
9797

9898
func abort() {
99+
avr.Asm("cli")
99100
for {
100-
sleepWDT(WDT_PERIOD_2S)
101+
// Sleeping with interrupts disabled will mean the MCU sleeps forever.
102+
// To be extra sure, put it in a loop.
103+
// This mechanism is used by simavr to detect a program exit, the
104+
// emulator will stop when it detects a sleep instruction with
105+
// interrupts disabled.
106+
avr.Asm("sleep")
101107
}
102108
}

0 commit comments

Comments
 (0)