mirror of
https://gitee.com/wa-lang/wa.git
synced 2025-12-06 09:18:53 +08:00
添加汇编器的测试资源
This commit is contained in:
@@ -90,7 +90,7 @@ func RunCountCodeLines(c *cli.Context) {
|
||||
}
|
||||
|
||||
func needSkip(path string, data []byte) bool {
|
||||
if !hasExt(path, ".wa", ".go", ".ws") {
|
||||
if !hasExt(path, ".wa", ".wz", ".go", ".ws") {
|
||||
return true
|
||||
}
|
||||
if strings.Contains(path, "3rdparty") {
|
||||
|
||||
116
internal/native/examples/esp32-c3-hello/flasher/flasher.go
Normal file
116
internal/native/examples/esp32-c3-hello/flasher/flasher.go
Normal file
@@ -0,0 +1,116 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
"log"
|
||||
"os"
|
||||
"time"
|
||||
|
||||
"go.bug.st/serial"
|
||||
)
|
||||
|
||||
// 烧写配置
|
||||
const (
|
||||
portName = "/dev/ttyUSB0" // 根据您的系统修改为正确的串口名称 (e.g., COM3 on Windows)
|
||||
baudRate = 115200
|
||||
dataFile = "your_firmware.bin" // 假设这是你的汇编器生成的固件
|
||||
flashAddr = 0x42000000 // ESP32-C3 Flash的典型起始地址之一
|
||||
)
|
||||
|
||||
func main() {
|
||||
// 1. 打开串口
|
||||
mode := &serial.Mode{
|
||||
BaudRate: baudRate,
|
||||
DataBits: 8,
|
||||
Parity: serial.NoParity,
|
||||
StopBits: serial.OneStopBit,
|
||||
}
|
||||
|
||||
port, err := serial.Open(portName, mode)
|
||||
if err != nil {
|
||||
log.Fatalf("无法打开串口 %s: %v", portName, err)
|
||||
}
|
||||
defer port.Close()
|
||||
|
||||
log.Printf("成功打开串口 %s", portName)
|
||||
|
||||
// 2. 模拟 ROM Bootloader 握手 (SYNC)
|
||||
// 实际操作中,你需要发送一个复杂的命令序列,这里仅模拟发送
|
||||
fmt.Println("--- 模拟 ROM Bootloader 握手 ---")
|
||||
|
||||
// 假设的同步命令(实际请查阅文档)
|
||||
syncCmd := []byte{0x07, 0x07, 0x12, 0x20}
|
||||
|
||||
n, err := port.Write(syncCmd)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
log.Printf("发送了 %d 字节的同步命令。", n)
|
||||
|
||||
// 等待设备响应 (实际需要解析响应,这里只是等待)
|
||||
time.Sleep(100 * time.Millisecond)
|
||||
|
||||
// 3. 模拟发送固件
|
||||
fmt.Println("--- 模拟发送固件数据 ---")
|
||||
|
||||
firmware, err := os.ReadFile(dataFile)
|
||||
if err != nil {
|
||||
log.Fatalf("无法读取固件文件 %s: %v", dataFile, err)
|
||||
}
|
||||
|
||||
// 假设的写入 Flash 命令头 (实际会包含地址、长度、校验和等)
|
||||
// 在实际烧写中,会是 (Command Header + Data Segment Header + Firmware Chunk)
|
||||
|
||||
dataChunkSize := 256 // 假设每次发送256字节
|
||||
|
||||
for i := 0; i < len(firmware); i += dataChunkSize {
|
||||
end := i + dataChunkSize
|
||||
if end > len(firmware) {
|
||||
end = len(firmware)
|
||||
}
|
||||
|
||||
chunk := firmware[i:end]
|
||||
|
||||
// 实际烧写时,需要在发送数据块前发送一个带有目标地址和长度的命令包
|
||||
|
||||
// 模拟发送数据块
|
||||
n, err := port.Write(chunk)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
log.Printf("发送数据块: 地址 0x%X, 长度 %d 字节", flashAddr+i, n)
|
||||
|
||||
// 实际烧写中,每发送一个块都需要等待设备的 ACK 确认
|
||||
time.Sleep(1 * time.Millisecond)
|
||||
}
|
||||
|
||||
// 4. 模拟运行命令 (RUN)
|
||||
fmt.Println("--- 模拟 RUN 命令 ---")
|
||||
// 实际操作中,你需要发送一个 RUN 命令,指定程序入口地址
|
||||
|
||||
// 5. 切换到串口监视模式
|
||||
fmt.Println("--- 切换到串口监视模式,等待设备输出 ---")
|
||||
|
||||
// 启动一个 goroutine 来持续读取串口数据
|
||||
go func() {
|
||||
buf := make([]byte, 128)
|
||||
for {
|
||||
n, err := port.Read(buf)
|
||||
if err != nil {
|
||||
if err != io.EOF {
|
||||
fmt.Printf("\n串口读取错误: %v\n", err)
|
||||
}
|
||||
return
|
||||
}
|
||||
if n > 0 {
|
||||
fmt.Printf("%s", buf[:n])
|
||||
}
|
||||
}
|
||||
}()
|
||||
|
||||
// 保持主程序运行,直到用户按下 Enter
|
||||
fmt.Println("烧写和监视器已启动。按下 Enter 键退出...")
|
||||
fmt.Scanln()
|
||||
}
|
||||
10
internal/native/examples/esp32-c3-hello/go.mod
Normal file
10
internal/native/examples/esp32-c3-hello/go.mod
Normal file
@@ -0,0 +1,10 @@
|
||||
module github.com/wa-lang/wa/internal/native/examples/esp32-c3-hello
|
||||
|
||||
go 1.17
|
||||
|
||||
require go.bug.st/serial v1.6.4
|
||||
|
||||
require (
|
||||
github.com/creack/goselect v0.1.2 // indirect
|
||||
golang.org/x/sys v0.19.0 // indirect
|
||||
)
|
||||
22
internal/native/examples/esp32-c3-hello/go.sum
Normal file
22
internal/native/examples/esp32-c3-hello/go.sum
Normal file
@@ -0,0 +1,22 @@
|
||||
github.com/creack/goselect v0.1.2 h1:2DNy14+JPjRBgPzAd1thbQp4BSIihxcBf0IXhQXDRa0=
|
||||
github.com/creack/goselect v0.1.2/go.mod h1:a/NhLweNvqIYMuxcMOuWY516Cimucms3DglDzQP3hKY=
|
||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
|
||||
github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
|
||||
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
|
||||
github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk=
|
||||
github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
|
||||
go.bug.st/serial v1.6.4 h1:7FmqNPgVp3pu2Jz5PoPtbZ9jJO5gnEnZIvnI1lzve8A=
|
||||
go.bug.st/serial v1.6.4/go.mod h1:nofMJxTeNVny/m6+KaafC6vJGj3miwQZ6vW4BZUGJPI=
|
||||
golang.org/x/sys v0.19.0 h1:q5f1RH2jigJ1MoAWp2KTp3gm5zAGFUTarQZ5U386+4o=
|
||||
golang.org/x/sys v0.19.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
||||
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
41
internal/native/examples/esp32-c3-hello/hello.s
Normal file
41
internal/native/examples/esp32-c3-hello/hello.s
Normal file
@@ -0,0 +1,41 @@
|
||||
// 需要针对 ESP32-C3 硬件微调。
|
||||
|
||||
.section .text
|
||||
.globl _start
|
||||
|
||||
_start:
|
||||
// 1. 设置堆栈指针 (非常重要!)
|
||||
// 假设 RAM 从 0x3FC80000 开始,使用末尾作为堆栈
|
||||
li sp, 0x3FC8FFFF
|
||||
|
||||
// 2. 将 UART0 基地址加载到 t0 (UART_BASE)
|
||||
// 必须查阅手册确认!!! 假设为 0x60000000
|
||||
li t0, 0x60000000
|
||||
|
||||
// 3. 调用主程序逻辑
|
||||
call main
|
||||
|
||||
// 循环发送字符串
|
||||
main:
|
||||
li t1, msg // t1 = 字符串地址
|
||||
|
||||
loop:
|
||||
lb t2, 0(t1) // t2 = *t1 (加载一个字节)
|
||||
beqz t2, done // 如果是零字节 (字符串结束), 跳转到 done
|
||||
|
||||
// 假设 UART0 的发送数据寄存器在基地址 0 偏移处
|
||||
// 实际需要检查 UART FIFO 状态,但最简示例暂时跳过
|
||||
sb t2, 0(t0) // 将 t2 中的字符写入 UART0 (地址 t0 + 0)
|
||||
|
||||
addi t1, t1, 1 // t1++ (指向下一个字符)
|
||||
j loop
|
||||
|
||||
done:
|
||||
// 程序结束,进入休眠/无限循环
|
||||
wfi // Wait For Interrupt (低功耗模式)
|
||||
j done
|
||||
|
||||
|
||||
.section .rodata
|
||||
msg:
|
||||
.string "Hello from RISC-V Naked Assembly!\n"
|
||||
35
internal/native/examples/esp32-c3-hello/mkbin/mkbin.go
Normal file
35
internal/native/examples/esp32-c3-hello/mkbin/mkbin.go
Normal file
@@ -0,0 +1,35 @@
|
||||
package main
|
||||
|
||||
// ESP32-C3 固件映像头 (Image Header)
|
||||
// 结构体字段顺序和大小必须与硬件文档严格匹配
|
||||
type ImageHeader struct {
|
||||
Magic uint32 // 魔术字:必须是 0xE9
|
||||
SegmentCount byte // 段的数量 (对于单段程序为 1)
|
||||
SpiMode byte // SPI Flash 模式 (通常为 0x02)
|
||||
SpiSpeed byte // SPI Flash 速度 (通常为 0x01)
|
||||
SpiSize byte // SPI Flash 大小 (通常为 0x20)
|
||||
EntryAddr uint32 // 程序入口点地址 (例如: 0x42000000)
|
||||
Reserved [16]byte // 保留字段
|
||||
Checksum byte // 映像头和所有段头的校验和(通常放在最后计算)
|
||||
}
|
||||
|
||||
// 段头 (Segment Header)
|
||||
type SegmentHeader struct {
|
||||
LoadAddr uint32 // 该段数据将被加载到的 RAM/IRAM 地址
|
||||
DataLen uint32 // 该段数据的字节长度
|
||||
}
|
||||
|
||||
const (
|
||||
ESP_IMAGE_MAGIC = 0xE9 // ESP32-C3 固件映像魔术字
|
||||
// 假设的程序入口点地址 (Flash 地址)
|
||||
// ROM Bootloader 会将它作为入口点执行
|
||||
DEFAULT_ENTRY_ADDR = 0x42000000
|
||||
)
|
||||
|
||||
// 假设这是您的 Go 汇编器生成的原始机器指令
|
||||
var rawMachineCode = []byte{
|
||||
// 假设这是 RISC-V 指令的机器码序列
|
||||
0x13, 0x05, 0x00, 0x00, // li a0, 0
|
||||
0x67, 0x80, 0x00, 0x00, // ret
|
||||
// 实际代码会更长,包括 UART 操作
|
||||
}
|
||||
3
internal/native/examples/esp32-c3-hello/readme.md
Normal file
3
internal/native/examples/esp32-c3-hello/readme.md
Normal file
@@ -0,0 +1,3 @@
|
||||
# ESP32-C3 例子
|
||||
|
||||
TODO
|
||||
@@ -64,8 +64,6 @@ func (p *watPrinter) printFuncs_body(fn *ast.Func) {
|
||||
for _, ins := range fn.Body.Insts {
|
||||
p.printFuncs_body_ins(ins, 0)
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
func watPrinter_printFuncs_indent(w io.Writer, indent string, blkLevel int) {
|
||||
|
||||
@@ -32,7 +32,7 @@ func (p *watPrinter) printImport() error {
|
||||
fmt.Fprintf(p.w, "(import %q %q", importSpec.ObjModule, importSpec.ObjName)
|
||||
fmt.Fprintf(p.w, " (memory")
|
||||
if s := importSpec.Memory.Name; s != "" {
|
||||
fmt.Fprintf(p.w, " $"+s)
|
||||
fmt.Fprint(p.w, " $"+s)
|
||||
}
|
||||
fmt.Fprintf(p.w, " %d", importSpec.Memory.Pages)
|
||||
if importSpec.Memory.MaxPages != 0 {
|
||||
@@ -55,7 +55,6 @@ func (p *watPrinter) printImport_global(importSpec *ast.ImportSpec) {
|
||||
watPrinter_identOrIndex(importSpec.GlobalName),
|
||||
importSpec.GlobalType,
|
||||
)
|
||||
return
|
||||
}
|
||||
|
||||
func (p *watPrinter) printImport_func(importSpec *ast.ImportSpec) {
|
||||
@@ -76,5 +75,4 @@ func (p *watPrinter) printImport_func(importSpec *ast.ImportSpec) {
|
||||
}
|
||||
|
||||
fmt.Fprint(p.w, ")")
|
||||
return
|
||||
}
|
||||
|
||||
@@ -43,5 +43,4 @@ func (p *watPrinter) printType_func(typ *ast.TypeSection) {
|
||||
}
|
||||
|
||||
fmt.Fprintln(p.w, "))")
|
||||
return
|
||||
}
|
||||
|
||||
@@ -1,6 +1,9 @@
|
||||
# 版本日志
|
||||
|
||||
- dev (2025-??-??)
|
||||
- 完善中文版的支持, 修复中英文错误接口不能互通的问题
|
||||
- 标准库增加中文版的“万国码/码八方”包
|
||||
- 凹语言RISCV汇编器支持中文指令集
|
||||
- v1.4.0 (2025-11-10)
|
||||
- 修复 `wa init` 命令会卡死的问题
|
||||
- 凹语言中文版技术平权继续, 双向导出了错误接口, 增加了多个中文包
|
||||
|
||||
Reference in New Issue
Block a user