Skip to content

Commit c7ae224

Browse files
committed
feat: Add ASM program file loading support
- Implement LoadProgramFileFromASM() function to parse ASM format program files - Support PE(x,y) format with instruction groups wrapped in {} - Support Core x,y format with one instruction per line - Add parseASMOperand() to handle various operand formats (direction+color, register, immediate) - Add parseASMInstruction() to parse instruction lines - Add parsePEFormat() and parseCoreFormat() parsers - Rename LoadProgramFile() to LoadProgramFileFromYAML() for clarity - Update all call sites to use the new function name - Add comprehensive tests for ASM parsing (program_asm_test.go)
1 parent e93bfaa commit c7ae224

10 files changed

Lines changed: 713 additions & 22 deletions

File tree

core/program.go

Lines changed: 458 additions & 3 deletions
Large diffs are not rendered by default.

core/program_asm_test.go

Lines changed: 236 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,236 @@
1+
package core
2+
3+
import (
4+
"fmt"
5+
"os"
6+
"testing"
7+
)
8+
9+
func TestLoadProgramFileFromASM_PEFormat(t *testing.T) {
10+
// Test with fir4x4.asm format
11+
filePath := "../test/Zeonica_Testbench/kernel/fir/fir4x4.asm"
12+
if _, err := os.Stat(filePath); os.IsNotExist(err) {
13+
t.Skipf("Test file does not exist: %s", filePath)
14+
}
15+
16+
// Load the program file
17+
programMap := LoadProgramFileFromASM(filePath)
18+
19+
// Verify that we loaded some programs
20+
if len(programMap) == 0 {
21+
t.Error("No programs were loaded from the ASM file")
22+
}
23+
24+
// Print the loaded programs
25+
fmt.Println("=== Loaded Programs (PE Format) ===")
26+
for coord, program := range programMap {
27+
fmt.Printf("\n--- Core at %s ---\n", coord)
28+
PrintProgram(program)
29+
}
30+
31+
// Print summary
32+
fmt.Printf("\n=== Summary ===\n")
33+
fmt.Printf("Total cores loaded: %d\n", len(programMap))
34+
35+
// Verify specific core exists
36+
if _, exists := programMap["(0,1)"]; !exists {
37+
t.Error("Expected core at (0,1) not found")
38+
}
39+
40+
// Verify core has entry blocks
41+
for coord, program := range programMap {
42+
if len(program.EntryBlocks) == 0 {
43+
t.Errorf("Core at %s has no entry blocks", coord)
44+
}
45+
for _, entryBlock := range program.EntryBlocks {
46+
if len(entryBlock.InstructionGroups) == 0 {
47+
t.Errorf("Core at %s has no instruction groups", coord)
48+
}
49+
}
50+
}
51+
}
52+
53+
func TestLoadProgramFileFromASM_CoreFormat(t *testing.T) {
54+
// Test with fir.asm format
55+
filePath := "../test/fir/fir.asm"
56+
if _, err := os.Stat(filePath); os.IsNotExist(err) {
57+
t.Skipf("Test file does not exist: %s", filePath)
58+
}
59+
60+
// Load the program file
61+
programMap := LoadProgramFileFromASM(filePath)
62+
63+
// Verify that we loaded some programs
64+
if len(programMap) == 0 {
65+
t.Error("No programs were loaded from the ASM file")
66+
}
67+
68+
// Print the loaded programs
69+
fmt.Println("=== Loaded Programs (Core Format) ===")
70+
for coord, program := range programMap {
71+
fmt.Printf("\n--- Core at %s ---\n", coord)
72+
PrintProgram(program)
73+
}
74+
75+
// Print summary
76+
fmt.Printf("\n=== Summary ===\n")
77+
fmt.Printf("Total cores loaded: %d\n", len(programMap))
78+
79+
// Verify specific core exists
80+
if _, exists := programMap["(0,0)"]; !exists {
81+
t.Error("Expected core at (0,0) not found")
82+
}
83+
84+
// Verify core has entry blocks
85+
for coord, program := range programMap {
86+
if len(program.EntryBlocks) == 0 {
87+
t.Errorf("Core at %s has no entry blocks", coord)
88+
}
89+
for _, entryBlock := range program.EntryBlocks {
90+
if len(entryBlock.InstructionGroups) == 0 {
91+
t.Errorf("Core at %s has no instruction groups", coord)
92+
}
93+
}
94+
}
95+
}
96+
97+
func TestParseASMOperand(t *testing.T) {
98+
tests := []struct {
99+
name string
100+
input string
101+
expected Operand
102+
}{
103+
{
104+
name: "Direction and color in brackets",
105+
input: "[NORTH, RED]",
106+
expected: Operand{
107+
Flag: false,
108+
Color: "R",
109+
Impl: "North",
110+
},
111+
},
112+
{
113+
name: "Register in brackets",
114+
input: "[$0]",
115+
expected: Operand{
116+
Flag: false,
117+
Color: "",
118+
Impl: "$0",
119+
},
120+
},
121+
{
122+
name: "Immediate in brackets",
123+
input: "[#0]",
124+
expected: Operand{
125+
Flag: false,
126+
Color: "",
127+
Impl: "0",
128+
},
129+
},
130+
{
131+
name: "Register without brackets",
132+
input: "$0",
133+
expected: Operand{
134+
Flag: false,
135+
Color: "",
136+
Impl: "$0",
137+
},
138+
},
139+
{
140+
name: "Direction without brackets",
141+
input: "North",
142+
expected: Operand{
143+
Flag: false,
144+
Color: "",
145+
Impl: "North",
146+
},
147+
},
148+
{
149+
name: "Immediate number",
150+
input: "114",
151+
expected: Operand{
152+
Flag: false,
153+
Color: "",
154+
Impl: "114",
155+
},
156+
},
157+
{
158+
name: "Yellow color",
159+
input: "[WEST, YELLOW]",
160+
expected: Operand{
161+
Flag: false,
162+
Color: "Y",
163+
Impl: "West",
164+
},
165+
},
166+
}
167+
168+
for _, tt := range tests {
169+
t.Run(tt.name, func(t *testing.T) {
170+
result := parseASMOperand(tt.input)
171+
if result.Flag != tt.expected.Flag {
172+
t.Errorf("Flag: got %v, want %v", result.Flag, tt.expected.Flag)
173+
}
174+
if result.Color != tt.expected.Color {
175+
t.Errorf("Color: got %v, want %v", result.Color, tt.expected.Color)
176+
}
177+
if result.Impl != tt.expected.Impl {
178+
t.Errorf("Impl: got %v, want %v", result.Impl, tt.expected.Impl)
179+
}
180+
})
181+
}
182+
}
183+
184+
func TestParseASMInstruction(t *testing.T) {
185+
tests := []struct {
186+
name string
187+
input string
188+
expectedOp string
189+
expectedSrcs int
190+
expectedDsts int
191+
}{
192+
{
193+
name: "Comma-separated format with brackets",
194+
input: "GRANT_ONCE, [#0] -> [$0]",
195+
expectedOp: "GRANT_ONCE",
196+
expectedSrcs: 1,
197+
expectedDsts: 1,
198+
},
199+
{
200+
name: "Space-separated format with immediate",
201+
input: "PHI_CONST 0 East -> East South $0",
202+
expectedOp: "PHI_CONST",
203+
expectedSrcs: 2,
204+
expectedDsts: 3,
205+
},
206+
{
207+
name: "Multiple source operands",
208+
input: "ADD, [NORTH, RED], [$0] -> [WEST, RED], [SOUTH, RED]",
209+
expectedOp: "ADD",
210+
expectedSrcs: 2,
211+
expectedDsts: 2,
212+
},
213+
{
214+
name: "No destination operands",
215+
input: "RETURN, [WEST, RED]",
216+
expectedOp: "RETURN",
217+
expectedSrcs: 1,
218+
expectedDsts: 0,
219+
},
220+
}
221+
222+
for _, tt := range tests {
223+
t.Run(tt.name, func(t *testing.T) {
224+
opcode, srcOps, dstOps := parseASMInstruction(tt.input)
225+
if opcode != tt.expectedOp {
226+
t.Errorf("Opcode: got %v, want %v", opcode, tt.expectedOp)
227+
}
228+
if len(srcOps) != tt.expectedSrcs {
229+
t.Errorf("Source operands: got %d, want %d", len(srcOps), tt.expectedSrcs)
230+
}
231+
if len(dstOps) != tt.expectedDsts {
232+
t.Errorf("Destination operands: got %d, want %d", len(dstOps), tt.expectedDsts)
233+
}
234+
})
235+
}
236+
}

core/program_test.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ import (
66
"testing"
77
)
88

9-
func TestLoadProgramFile(t *testing.T) {
9+
func TestLoadProgramFileFromYAML(t *testing.T) {
1010
// Check if file exists
1111
filePath := "../samples/fir/instructions.yaml"
1212
if _, err := os.Stat(filePath); os.IsNotExist(err) {
@@ -27,7 +27,7 @@ func TestLoadProgramFile(t *testing.T) {
2727
}
2828

2929
// Load the program file - adjust path from core/ directory
30-
programMap := LoadProgramFile(filePath)
30+
programMap := LoadProgramFileFromYAML(filePath)
3131

3232
// Print the loaded programs
3333
fmt.Println("=== Loaded Programs ===")

samples/fir/main.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,7 @@ func test_through(driver api.Driver, program map[string]core.Program) {
6464
func main() {
6565

6666
// Load the program - use path relative to workspace root
67-
program := core.LoadProgramFile("./demo_instructions.yaml")
67+
program := core.LoadProgramFileFromYAML("./demo_instructions.yaml")
6868
fmt.Println(program)
6969

7070
engine := sim.NewSerialEngine()

test/add/arith_test.go

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,7 @@ func TestAddOperationWithRandomData(t *testing.T) {
5353
driver.RegisterDevice(device)
5454

5555
// 加载程序
56-
program := core.LoadProgramFile("./test_add.yaml")
56+
program := core.LoadProgramFileFromYAML("./test_add.yaml")
5757
if len(program) == 0 {
5858
t.Fatal("Failed to load program")
5959
}
@@ -145,7 +145,7 @@ func TestSubOperationWithRandomData(t *testing.T) {
145145
driver.RegisterDevice(device)
146146

147147
// 加载程序
148-
program := core.LoadProgramFile("./test_sub.yaml")
148+
program := core.LoadProgramFileFromYAML("./test_sub.yaml")
149149
if len(program) == 0 {
150150
t.Fatal("Failed to load program")
151151
}
@@ -237,7 +237,7 @@ func TestMulOperationWithRandomData(t *testing.T) {
237237
driver.RegisterDevice(device)
238238

239239
// 加载程序
240-
program := core.LoadProgramFile("./test_mul.yaml")
240+
program := core.LoadProgramFileFromYAML("./test_mul.yaml")
241241
if len(program) == 0 {
242242
t.Fatal("Failed to load program")
243243
}
@@ -333,7 +333,7 @@ func TestDivOperationWithRandomData(t *testing.T) {
333333
driver.RegisterDevice(device)
334334

335335
// 加载程序
336-
program := core.LoadProgramFile("./test_div.yaml")
336+
program := core.LoadProgramFileFromYAML("./test_div.yaml")
337337
if len(program) == 0 {
338338
t.Fatal("Failed to load program")
339339
}

test/add/main.bkp.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -72,7 +72,7 @@ func main() {
7272
fmt.Printf("Array size: %dx%d\n", width, height)
7373

7474
// Load the program - use path relative to workspace root
75-
program := core.LoadProgramFile("./test_add.yaml")
75+
program := core.LoadProgramFileFromYAML("./test_add.yaml")
7676
fmt.Println("Loaded programs for cores:", len(program))
7777

7878
// 打印每个core的程序信息

test/cf/cf_test.go

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@ func TestCmpExOperation(t *testing.T) {
4747
driver.RegisterDevice(device)
4848

4949
// 加载程序
50-
program := core.LoadProgramFile("./test_cmpex.yaml")
50+
program := core.LoadProgramFileFromYAML("./test_cmpex.yaml")
5151
if len(program) == 0 {
5252
t.Fatal("Failed to load program")
5353
}
@@ -154,7 +154,7 @@ func TestGpredOperation(t *testing.T) {
154154
driver.RegisterDevice(device)
155155

156156
// 加载程序
157-
program := core.LoadProgramFile("./test_gpred.yaml")
157+
program := core.LoadProgramFileFromYAML("./test_gpred.yaml")
158158
if len(program) == 0 {
159159
t.Fatal("Failed to load program")
160160
}
@@ -243,7 +243,7 @@ func TestPhiOperation(t *testing.T) {
243243
driver.RegisterDevice(device)
244244

245245
// 加载程序
246-
program := core.LoadProgramFile("./test_phiconst.yaml")
246+
program := core.LoadProgramFileFromYAML("./test_phiconst.yaml")
247247
if len(program) == 0 {
248248
t.Fatal("Failed to load program")
249249
}

test/fir/main.go

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -27,8 +27,8 @@ func Fir() {
2727
Build("Driver")
2828

2929
// 创建设备
30-
device := config.DeviceBuilder{}.
31-
WithEngine(engine).
30+
device := config.DeviceBuilder{}
31+
WithEngine(engine).
3232
WithFreq(1 * sim.GHz).
3333
WithWidth(width).
3434
WithHeight(height).
@@ -37,7 +37,7 @@ func Fir() {
3737
driver.RegisterDevice(device)
3838

3939
// 加载程序
40-
program := core.LoadProgramFile("./fir.yaml")
40+
program := core.LoadProgramFileFromYAML("./fir.yaml")
4141
if len(program) == 0 {
4242
panic("Failed to load program")
4343
}

test/mem/mem_test.go

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ func TestLoadStoreOperation(t *testing.T) {
4545
driver.RegisterDevice(device)
4646

4747
// 加载程序
48-
program := core.LoadProgramFile("./test_loadstore.yaml")
48+
program := core.LoadProgramFileFromYAML("./test_loadstore.yaml")
4949
if len(program) == 0 {
5050
t.Fatal("Failed to load program")
5151
}
@@ -130,7 +130,7 @@ func TestLoadWaitDRAMOperation(t *testing.T) {
130130

131131
driver.RegisterDevice(device)
132132

133-
program := core.LoadProgramFile("./test_lw.yaml")
133+
program := core.LoadProgramFileFromYAML("./test_lw.yaml")
134134
if len(program) == 0 {
135135
t.Fatal("Failed to load program")
136136
}
@@ -220,7 +220,7 @@ func TestGoAround(t *testing.T) {
220220

221221
driver.RegisterDevice(device)
222222

223-
program := core.LoadProgramFile("./test_lwsw-go-a-round.yaml")
223+
program := core.LoadProgramFileFromYAML("./test_lwsw-go-a-round.yaml")
224224
if len(program) == 0 {
225225
t.Fatal("Failed to load program")
226226
}
@@ -302,7 +302,7 @@ func TestSharedMemory(t *testing.T) {
302302

303303
driver.RegisterDevice(device)
304304

305-
program := core.LoadProgramFile("./test_all-shared-mem.yaml")
305+
program := core.LoadProgramFileFromYAML("./test_all-shared-mem.yaml")
306306
if len(program) == 0 {
307307
t.Fatal("Failed to load program")
308308
}

0 commit comments

Comments
 (0)