├── g4file ├── ZeonicaLexer.g4 └── ZeonicaParser.g4 ├── core ├── doc.go ├── core_suite_test.go ├── data.go ├── program_test.go ├── emu_internal_test.go ├── builder.go ├── util.go ├── program_asm_test.go ├── emu_unit_test.go └── core.go ├── .vscode ├── settings.json └── launch.json ├── .gitmodules ├── .gitignore ├── api ├── api_suite_test.go ├── builder.go ├── mock_cgra_test.go └── driver_internal_test.go ├── .github └── workflows │ └── test.yml ├── cgra ├── data.go ├── cgra.go └── msg.go ├── verify ├── cmd │ ├── verify-histogram │ │ └── main.go │ └── verify-axpy │ │ └── main.go ├── histogram_integration_test.go ├── report.go └── verify_test.go ├── LICENSE ├── go.mod ├── test ├── ctrl │ ├── test_fire.yaml │ ├── test_ret.yaml │ └── ret_test.go ├── cf │ ├── test_cmpex.yaml │ ├── test_phiconst.yaml │ ├── test_gpred.yaml │ └── cf_test.go ├── testbench │ ├── fir │ │ ├── main.go │ │ └── fir4x4.yaml │ └── gemm │ │ └── main.go ├── add │ ├── test_add.yaml │ ├── test_mul.yaml │ ├── test_div.yaml │ ├── test_sub.yaml │ └── arith_test.go ├── misc │ ├── test_spread.yaml │ └── spread_test.go ├── pred │ ├── test_gpred.yaml │ └── cf_test.go └── mem │ ├── test_lw.yaml │ ├── test_loadstore.yaml │ ├── test_all-shared-mem.yaml │ ├── test_lwsw-go-a-round.yaml │ └── mem_test.go ├── README.md ├── config ├── platform.go └── config.go └── go.sum /g4file/ZeonicaLexer.g4: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /core/doc.go: -------------------------------------------------------------------------------- 1 | // Package core defines a CGRA processing element. 2 | package core 3 | -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "cSpell.words": [ 3 | "cgra", 4 | "sarchlab", 5 | "zeonica" 6 | ] 7 | } -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "test/Zeonica_Testbench"] 2 | path = test/Zeonica_Testbench 3 | url = git@github.com:sarchlab/Zeonica_Testbench.git 4 | -------------------------------------------------------------------------------- /core/core_suite_test.go: -------------------------------------------------------------------------------- 1 | package core_test 2 | 3 | import ( 4 | "testing" 5 | 6 | . "github.com/onsi/ginkgo/v2" 7 | . "github.com/onsi/gomega" 8 | ) 9 | 10 | func TestCore(t *testing.T) { 11 | RegisterFailHandler(Fail) 12 | RunSpecs(t, "Core Suite") 13 | } 14 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Binaries for programs and plugins 2 | *.exe 3 | *.exe~ 4 | *.dll 5 | *.so 6 | *.dylib 7 | 8 | # Test binary, built with `go test -c` 9 | *.test 10 | 11 | # Output of the go coverage tool, specifically when used with LiteIDE 12 | *.out 13 | 14 | # Dependency directories (remove the comment below to include it) 15 | # vendor/ 16 | 17 | .DS_Store 18 | *.debug 19 | samples/passthrough/passthrough 20 | 21 | # output files 22 | output/ 23 | 24 | # logs 25 | *.log -------------------------------------------------------------------------------- /api/api_suite_test.go: -------------------------------------------------------------------------------- 1 | package api 2 | 3 | import ( 4 | "testing" 5 | 6 | . "github.com/onsi/ginkgo/v2" 7 | . "github.com/onsi/gomega" 8 | ) 9 | 10 | //go:generate mockgen -write_package_comment=false -package=$GOPACKAGE -destination=mock_cgra_test.go github.com/sarchlab/zeonica/cgra Device,Tile 11 | //go:generate mockgen -write_package_comment=false -package=$GOPACKAGE -destination=mock_sim_test.go github.com/sarchlab/akita/v4/sim Port,Engine 12 | func TestApi(t *testing.T) { 13 | RegisterFailHandler(Fail) 14 | RunSpecs(t, "Api Suite") 15 | } 16 | -------------------------------------------------------------------------------- /.github/workflows/test.yml: -------------------------------------------------------------------------------- 1 | name: Zeonica Test 2 | 3 | on: push 4 | 5 | jobs: 6 | 7 | compile: 8 | name: Compilation 9 | runs-on: ubuntu-latest 10 | steps: 11 | - name: Checkout 12 | uses: actions/checkout@v2 13 | 14 | - name: Setup Go 15 | uses: actions/setup-go@v4 16 | with: 17 | go-version: "stable" 18 | 19 | - name: Build 20 | run: go build ./... 21 | 22 | - name: Lint 23 | uses: golangci/golangci-lint-action@v3 24 | with: 25 | skip-pkg-cache: true 26 | version: "latest" 27 | args: --timeout=10m 28 | 29 | - name: Install Ginkgo 30 | run: go install github.com/onsi/ginkgo/v2/ginkgo 31 | 32 | - name: Unit Test 33 | run: ginkgo -r -------------------------------------------------------------------------------- /api/builder.go: -------------------------------------------------------------------------------- 1 | package api 2 | 3 | import "github.com/sarchlab/akita/v4/sim" 4 | 5 | type defaultPortFactory struct { 6 | } 7 | 8 | func (f defaultPortFactory) make(c sim.Component, name string) sim.Port { 9 | return sim.NewPort(c, 1, 1, name) 10 | } 11 | 12 | // DriverBuilder creates a new instance of Driver. 13 | type DriverBuilder struct { 14 | engine sim.Engine 15 | freq sim.Freq 16 | } 17 | 18 | // WithEngine sets the engine. 19 | func (b DriverBuilder) WithEngine(engine sim.Engine) DriverBuilder { 20 | b.engine = engine 21 | return b 22 | } 23 | 24 | // WithFreq sets the frequency of the driver. 25 | func (b DriverBuilder) WithFreq(freq sim.Freq) DriverBuilder { 26 | b.freq = freq 27 | return b 28 | } 29 | 30 | // Build create a driver. 31 | func (b DriverBuilder) Build(name string) Driver { 32 | d := &driverImpl{ 33 | portFactory: defaultPortFactory{}, 34 | } 35 | 36 | d.TickingComponent = sim.NewTickingComponent(name, b.engine, b.freq, d) 37 | 38 | return d 39 | } 40 | -------------------------------------------------------------------------------- /cgra/data.go: -------------------------------------------------------------------------------- 1 | package cgra 2 | 3 | type Data struct { 4 | Data []uint32 5 | Pred bool 6 | } 7 | 8 | // NewScalar creates a Data that wraps a single uint32 value with Pred=true by default. 9 | func NewScalar(v uint32) Data { 10 | return Data{Data: []uint32{v}, Pred: true} 11 | } 12 | 13 | // NewScalar creates a Data that wraps a single uint32 value with Pred=true by default. 14 | func NewScalarWithPred(v uint32, pred bool) Data { 15 | return Data{Data: []uint32{v}, Pred: pred} 16 | } 17 | 18 | // First returns the first lane value. If empty, returns 0. 19 | func (d Data) First() uint32 { 20 | if len(d.Data) == 0 { 21 | return 0 22 | } 23 | return d.Data[0] 24 | } 25 | 26 | // WithPred returns a copy with the given predicate flag. 27 | func (d Data) WithPred(pred bool) Data { 28 | d.Pred = pred 29 | return d 30 | } 31 | 32 | // FromSlice constructs a Data from a slice and optional predicate. 33 | func FromSlice(vals []uint32, pred bool) Data { 34 | return Data{Data: vals, Pred: pred} 35 | } 36 | -------------------------------------------------------------------------------- /core/data.go: -------------------------------------------------------------------------------- 1 | package core 2 | 3 | type Data struct { 4 | Data []uint32 5 | Pred bool 6 | } 7 | 8 | // NewScalar creates a Data that wraps a single uint32 value with Pred=true by default. 9 | func NewScalar(v uint32) Data { 10 | return Data{Data: []uint32{v}, Pred: true} 11 | } 12 | 13 | // NewScalar creates a Data that wraps a single uint32 value with Pred=true by default. 14 | func NewScalarWithPred(v uint32, pred bool) Data { 15 | return Data{Data: []uint32{v}, Pred: pred} 16 | } 17 | 18 | // First returns the first lane value. If empty, returns 0. 19 | func (d Data) First() uint32 { 20 | if len(d.Data) == 0 { 21 | return 0 22 | } 23 | return d.Data[0] 24 | } 25 | 26 | // WithPred returns a copy with the given predicate flag. 27 | func (d Data) WithPred(pred bool) Data { 28 | d.Pred = pred 29 | return d 30 | } 31 | 32 | // FromSlice constructs a Data from a slice and optional predicate. 33 | func FromSlice(vals []uint32, pred bool) Data { 34 | return Data{Data: vals, Pred: pred} 35 | } 36 | -------------------------------------------------------------------------------- /verify/cmd/verify-histogram/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "log" 6 | "os" 7 | 8 | "github.com/sarchlab/zeonica/core" 9 | "github.com/sarchlab/zeonica/verify" 10 | ) 11 | 12 | // main runs lint and functional simulation on histogram kernel 13 | func main() { 14 | programs := core.LoadProgramFileFromYAML("test/Zeonica_Testbench/kernel/histogram/histogram.yaml") 15 | if len(programs) == 0 { 16 | log.Fatal("Failed to load histogram.yaml") 17 | } 18 | 19 | // Create ArchInfo from arch_spec.yaml 20 | arch := &verify.ArchInfo{ 21 | Rows: 4, 22 | Columns: 4, 23 | Topology: "mesh", 24 | HopLatency: 1, 25 | MemCapacity: 2048, 26 | CtrlMemItems: 20, 27 | } 28 | 29 | // Generate report 30 | report := verify.GenerateReport(programs, arch, 100) 31 | 32 | // Write to stdout 33 | report.WriteReport(os.Stdout) 34 | 35 | // Save to file 36 | err := report.SaveReportToFile("histogram_verification_report.txt") 37 | if err != nil { 38 | log.Fatalf("Failed to save report: %v", err) 39 | } 40 | 41 | fmt.Println("✓ Report saved to: histogram_verification_report.txt") 42 | } 43 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2022 sarchlab 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /.vscode/launch.json: -------------------------------------------------------------------------------- 1 | { 2 | // Use IntelliSense to learn about possible attributes. 3 | // Hover to view descriptions of existing attributes. 4 | // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 5 | "version": "0.2.0", 6 | "configurations": [ 7 | { 8 | "name": "2D Pass Through", 9 | "type": "go", 10 | "request": "launch", 11 | "mode": "auto", 12 | "program": "${workspaceFolder}/samples/2Dpassthrough" 13 | }, 14 | { 15 | "name": "Pass Through", 16 | "type": "go", 17 | "request": "launch", 18 | "mode": "auto", 19 | "program": "${workspaceFolder}/samples/passthrough" 20 | }, 21 | { 22 | "name": "Matrix Multiplication", 23 | "type": "go", 24 | "request": "launch", 25 | "mode": "auto", 26 | "program": "${workspaceFolder}/samples/Matrixmulti" 27 | }, 28 | { 29 | "name": "Test core", 30 | "type": "go", 31 | "request": "launch", 32 | "mode": "test", 33 | "program": "${workspaceFolder}/core", 34 | "args": [] 35 | }, 36 | { 37 | "name": "Test api", 38 | "type": "go", 39 | "request": "launch", 40 | "mode": "test", 41 | "program": "${workspaceFolder}/api", 42 | "args": [] 43 | } 44 | ] 45 | } -------------------------------------------------------------------------------- /core/program_test.go: -------------------------------------------------------------------------------- 1 | package core 2 | 3 | import ( 4 | "fmt" 5 | "os" 6 | "testing" 7 | ) 8 | 9 | func TestLoadProgramFileFromYAML(t *testing.T) { 10 | // Check if file exists 11 | filePath := "../test/testbench/fir/fir4x4.yaml" 12 | if _, err := os.Stat(filePath); os.IsNotExist(err) { 13 | t.Fatalf("File does not exist: %s", filePath) 14 | } 15 | 16 | // Read and print first few lines of the file for debugging 17 | data, err := os.ReadFile(filePath) 18 | if err != nil { 19 | t.Fatalf("Failed to read file: %v", err) 20 | } 21 | 22 | fmt.Printf("=== File content (first 500 chars) ===\n") 23 | if len(data) > 500 { 24 | fmt.Printf("%s...\n", string(data[:500])) 25 | } else { 26 | fmt.Printf("%s\n", string(data)) 27 | } 28 | 29 | // Load the program file - adjust path from core/ directory 30 | programMap := LoadProgramFileFromYAML(filePath) 31 | 32 | // Print the loaded programs 33 | fmt.Println("=== Loaded Programs ===") 34 | for coord, program := range programMap { 35 | fmt.Printf("\n--- Core at %s ---\n", coord) 36 | PrintProgram(program) 37 | } 38 | 39 | // Verify that we loaded some programs 40 | if len(programMap) == 0 { 41 | t.Error("No programs were loaded from the file") 42 | } 43 | 44 | // Print summary 45 | fmt.Printf("\n=== Summary ===\n") 46 | fmt.Printf("Total cores loaded: %d\n", len(programMap)) 47 | 48 | // Print each core's coordinate 49 | fmt.Println("Core coordinates:") 50 | for coord := range programMap { 51 | fmt.Printf(" %s\n", coord) 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /go.mod: -------------------------------------------------------------------------------- 1 | module github.com/sarchlab/zeonica 2 | 3 | go 1.24 4 | 5 | toolchain go1.24.0 6 | 7 | require ( 8 | github.com/golang/mock v1.6.0 9 | github.com/onsi/ginkgo/v2 v2.20.2 10 | github.com/onsi/gomega v1.34.2 11 | github.com/sarchlab/akita/v4 v4.0.0 12 | github.com/tebeka/atexit v0.3.0 13 | ) 14 | 15 | require ( 16 | filippo.io/edwards25519 v1.1.0 // indirect 17 | github.com/go-logr/logr v1.4.2 // indirect 18 | github.com/go-ole/go-ole v1.3.0 // indirect 19 | github.com/go-sql-driver/mysql v1.8.1 // indirect 20 | github.com/go-task/slim-sprig/v3 v3.0.0 // indirect 21 | github.com/google/go-cmp v0.6.0 // indirect 22 | github.com/google/pprof v0.0.0-20240829160300-da1f7e9f2b25 // indirect 23 | github.com/gorilla/mux v1.8.1 // indirect 24 | github.com/jedib0t/go-pretty/v6 v6.6.8 // indirect 25 | github.com/kr/text v0.2.0 // indirect 26 | github.com/mattn/go-runewidth v0.0.16 // indirect 27 | github.com/mattn/go-sqlite3 v1.14.22 // indirect 28 | github.com/rivo/uniseg v0.4.7 // indirect 29 | github.com/rs/xid v1.6.0 // indirect 30 | github.com/shirou/gopsutil v3.21.11+incompatible // indirect 31 | github.com/syifan/goseth v0.1.2 // indirect 32 | github.com/tklauser/go-sysconf v0.3.14 // indirect 33 | github.com/tklauser/numcpus v0.8.0 // indirect 34 | github.com/yusufpapurcu/wmi v1.2.4 // indirect 35 | golang.org/x/net v0.38.0 // indirect 36 | golang.org/x/sys v0.31.0 // indirect 37 | golang.org/x/text v0.23.0 // indirect 38 | golang.org/x/tools v0.24.0 // indirect 39 | gopkg.in/yaml.v3 v3.0.1 // indirect 40 | ) 41 | 42 | //replace gitlab.com/akita/akita/v2 => ../akita 43 | 44 | //replace gitlab.com/akita/noc/v2 => ../noc 45 | -------------------------------------------------------------------------------- /test/ctrl/test_fire.yaml: -------------------------------------------------------------------------------- 1 | array_config: 2 | rows: 2 3 | columns: 2 4 | cores: 5 | - row: 0 6 | column: 0 7 | core_id: "core_0_0" 8 | entries: 9 | - entry_id: "entry0" 10 | type: "loop" 11 | instructions: 12 | - operations: 13 | - opcode: "MOV" 14 | src_operands: 15 | - operand: "#1" 16 | color: "R" 17 | dst_operands: 18 | - operand: "North" 19 | color: "R" 20 | 21 | - row: 1 22 | column: 0 23 | core_id: "core_1_0" 24 | entries: 25 | - entry_id: "entry0" 26 | type: "loop" 27 | instructions: 28 | - operations: 29 | - opcode: "MOV" 30 | src_operands: 31 | - operand: "South" 32 | color: "R" 33 | dst_operands: 34 | - operand: "East" 35 | color: "R" 36 | 37 | - row: 0 38 | column: 1 39 | core_id: "core_0_1" 40 | entries: 41 | - entry_id: "entry0" 42 | type: "loop" 43 | instructions: 44 | - operations: 45 | - opcode: "RET" 46 | src_operands: 47 | - operand: "North" 48 | color: "R" 49 | 50 | - row: 1 51 | column: 1 52 | core_id: "core_1_1" 53 | entries: 54 | - entry_id: "entry0" 55 | type: "loop" 56 | instructions: 57 | - operations: 58 | - opcode: "MOV" 59 | src_operands: 60 | - operand: "West" 61 | color: "R" 62 | dst_operands: 63 | - operand: "South" 64 | color: "R" -------------------------------------------------------------------------------- /test/ctrl/test_ret.yaml: -------------------------------------------------------------------------------- 1 | array_config: 2 | rows: 2 3 | columns: 2 4 | cores: 5 | - row: 0 6 | column: 0 7 | core_id: "core_0_0" 8 | entries: 9 | - entry_id: "entry0" 10 | type: "loop" 11 | instructions: 12 | - operations: 13 | - opcode: "MOV" 14 | src_operands: 15 | - operand: "West" 16 | color: "R" 17 | dst_operands: 18 | - operand: "North" 19 | color: "R" 20 | 21 | - row: 1 22 | column: 0 23 | core_id: "core_1_0" 24 | entries: 25 | - entry_id: "entry0" 26 | type: "loop" 27 | instructions: 28 | - operations: 29 | - opcode: "MOV" 30 | src_operands: 31 | - operand: "South" 32 | color: "R" 33 | dst_operands: 34 | - operand: "East" 35 | color: "R" 36 | 37 | - row: 0 38 | column: 1 39 | core_id: "core_0_1" 40 | entries: 41 | - entry_id: "entry0" 42 | type: "loop" 43 | instructions: 44 | - operations: 45 | - opcode: "RET" 46 | src_operands: 47 | - operand: "North" 48 | color: "R" 49 | 50 | - row: 1 51 | column: 1 52 | core_id: "core_1_1" 53 | entries: 54 | - entry_id: "entry0" 55 | type: "loop" 56 | instructions: 57 | - operations: 58 | - opcode: "MOV" 59 | src_operands: 60 | - operand: "West" 61 | color: "R" 62 | dst_operands: 63 | - operand: "South" 64 | color: "R" -------------------------------------------------------------------------------- /cgra/cgra.go: -------------------------------------------------------------------------------- 1 | // Package cgra defines the commonly used data structure for CGRAs. 2 | package cgra 3 | 4 | import ( 5 | "github.com/sarchlab/akita/v4/sim" 6 | ) 7 | 8 | // Side defines the side of a tile. 9 | type Side int 10 | 11 | const ( 12 | North Side = iota 13 | East 14 | South 15 | West 16 | NorthEast 17 | NorthWest 18 | SouthEast 19 | SouthWest 20 | Router 21 | Dummy1 22 | Dummy2 23 | Dummy3 24 | ) 25 | 26 | // Name returns the name of the side. 27 | func (s Side) Name() string { 28 | switch s { 29 | case North: 30 | return "North" 31 | case West: 32 | return "West" 33 | case South: 34 | return "South" 35 | case East: 36 | return "East" 37 | case NorthEast: 38 | return "NorthEast" 39 | case NorthWest: 40 | return "NorthWest" 41 | case SouthEast: 42 | return "SouthEast" 43 | case SouthWest: 44 | return "SouthWest" 45 | case Router: 46 | return "Router" 47 | case Dummy1: 48 | return "Dummy1" 49 | case Dummy2: 50 | return "Dummy2" 51 | case Dummy3: 52 | return "Dummy3" 53 | default: 54 | panic("invalid side") 55 | } 56 | } 57 | 58 | // Tile defines a tile in the CGRA. 59 | type Tile interface { 60 | GetPort(side Side) sim.Port 61 | SetRemotePort(side Side, port sim.RemotePort) 62 | MapProgram(program interface{}, x int, y int) 63 | GetMemory(x int, y int, addr uint32) uint32 64 | WriteMemory(x int, y int, data uint32, baseAddr uint32) 65 | WriteSharedMemory(x int, y int, data []byte, baseAddr uint32) 66 | GetTileX() int 67 | GetTileY() int 68 | GetRetVal() uint32 69 | GetTickingComponent() sim.Component 70 | } 71 | 72 | // A Device is a CGRA device. 73 | type Device interface { 74 | GetSize() (width, height int) 75 | GetTile(x, y int) Tile 76 | GetSidePorts(side Side, portRange [2]int) []sim.Port 77 | } 78 | 79 | // Platform is the hardware platform that may include multiple CGRA devices. 80 | type Platform struct { 81 | Devices []*Device 82 | } 83 | -------------------------------------------------------------------------------- /test/cf/test_cmpex.yaml: -------------------------------------------------------------------------------- 1 | array_config: 2 | rows: 2 3 | columns: 2 4 | cores: 5 | - row: 0 6 | column: 0 7 | core_id: "core_0_0" 8 | entries: 9 | - entry_id: "entry0" 10 | type: "loop" 11 | instructions: 12 | - operations: 13 | - opcode: "MOV" 14 | src_operands: 15 | - operand: "West" 16 | color: "R" 17 | dst_operands: 18 | - operand: "East" 19 | color: "R" 20 | 21 | - row: 1 22 | column: 0 23 | core_id: "core_1_0" 24 | entries: 25 | - entry_id: "entry0" 26 | type: "loop" 27 | instructions: 28 | - operations: 29 | - opcode: "MOV" 30 | src_operands: 31 | - operand: "West" 32 | color: "R" 33 | dst_operands: 34 | - operand: "East" 35 | color: "R" 36 | 37 | - row: 0 38 | column: 1 39 | core_id: "core_0_1" 40 | entries: 41 | - entry_id: "entry0" 42 | type: "loop" 43 | instructions: 44 | - operations: 45 | - opcode: "CMP_EXPORT" 46 | src_operands: 47 | - operand: "West" 48 | color: "R" 49 | - operand: "North" 50 | color: "R" 51 | dst_operands: 52 | - operand: "East" 53 | color: "R" 54 | 55 | - row: 1 56 | column: 1 57 | core_id: "core_1_1" 58 | entries: 59 | - entry_id: "entry0" 60 | type: "loop" 61 | instructions: 62 | - operations: 63 | - opcode: "MOV" 64 | src_operands: 65 | - operand: "West" 66 | color: "R" 67 | dst_operands: 68 | - operand: "South" 69 | color: "R" -------------------------------------------------------------------------------- /cgra/msg.go: -------------------------------------------------------------------------------- 1 | package cgra 2 | 3 | import ( 4 | "github.com/sarchlab/akita/v4/sim" 5 | ) 6 | 7 | // MoveMsg moves data from one tile to another in a CGRA. 8 | type MoveMsg struct { 9 | sim.MsgMeta 10 | 11 | Data Data 12 | Color int 13 | //create a new branch predicate data 14 | //Predicate int 15 | } 16 | 17 | // Meta returns the meta data of the msg. 18 | func (m *MoveMsg) Meta() *sim.MsgMeta { 19 | return &m.MsgMeta 20 | } 21 | 22 | // Clone creates a new MoveMsg with the same content. 23 | func (m *MoveMsg) Clone() sim.Msg { 24 | newM := *m 25 | newM.ID = sim.GetIDGenerator().Generate() 26 | 27 | return &newM 28 | } 29 | 30 | // MoveMsgBuilder is a factory for MoveMsg. 31 | type MoveMsgBuilder struct { 32 | src, dst sim.RemotePort 33 | sendTime sim.VTimeInSec 34 | data Data 35 | color int 36 | // predicate value 37 | //predicate int 38 | } 39 | 40 | // WithSrc sets the source port of the msg. 41 | func (m MoveMsgBuilder) WithSrc(src sim.RemotePort) MoveMsgBuilder { 42 | m.src = src 43 | return m 44 | } 45 | 46 | // WithDst sets the destination port of the msg. 47 | func (m MoveMsgBuilder) WithDst(dst sim.RemotePort) MoveMsgBuilder { 48 | m.dst = dst 49 | return m 50 | } 51 | 52 | // WithSendTime sets the send time of the msg. 53 | func (m MoveMsgBuilder) WithSendTime(sendTime sim.VTimeInSec) MoveMsgBuilder { 54 | m.sendTime = sendTime 55 | return m 56 | } 57 | 58 | // WithData sets the data of the msg. 59 | func (m MoveMsgBuilder) WithData(data Data) MoveMsgBuilder { 60 | m.data = data 61 | return m 62 | } 63 | 64 | // WithData sets the color of the msg 65 | func (m MoveMsgBuilder) WithColor(color int) MoveMsgBuilder { 66 | m.color = color 67 | return m 68 | } 69 | 70 | //WithPredicate sets the predicate of the msg 71 | // func (m MoveMsgBuilder) WithPredicate(predicate int) MoveMsgBuilder { 72 | // m.predicate = predicate 73 | // return m 74 | // } 75 | 76 | // Build creates a MoveMsg. 77 | func (m MoveMsgBuilder) Build() *MoveMsg { 78 | return &MoveMsg{ 79 | MsgMeta: sim.MsgMeta{ 80 | ID: sim.GetIDGenerator().Generate(), 81 | Src: m.src, 82 | Dst: m.dst, 83 | }, 84 | Data: m.data, 85 | Color: m.color, 86 | } 87 | } 88 | -------------------------------------------------------------------------------- /core/emu_internal_test.go: -------------------------------------------------------------------------------- 1 | package core 2 | 3 | /* 4 | import ( 5 | . "github.com/onsi/ginkgo/v2" 6 | . "github.com/onsi/gomega" 7 | ) 8 | 9 | var _ = Describe("InstEmulator", func() { 10 | var ( 11 | ie instEmulator 12 | s coreState 13 | ) 14 | 15 | BeforeEach(func() { 16 | ie = instEmulator{ 17 | CareFlags: true, 18 | } 19 | s = coreState{ 20 | SelectedBlock: nil, 21 | PCInBlock: 0, 22 | Directions: map[string]bool{ 23 | "North": true, 24 | "East": true, 25 | "South": true, 26 | "West": true, 27 | }, 28 | 29 | TileX: 0, 30 | TileY: 0, 31 | Registers: make([]uint32, 4), 32 | Code: Program{}, 33 | RecvBufHead: make([][]Data, 4), 34 | RecvBufHeadReady: make([][]bool, 4), 35 | SendBufHead: make([][]Data, 4), 36 | SendBufHeadBusy: make([][]bool, 4), 37 | } 38 | })*/ 39 | 40 | /* 41 | Context("when running WAIT", func() { 42 | It("should wait for data to arrive", func() { 43 | s.RecvBufHeadReady[0] = false 44 | 45 | inst := "WAIT, $0, NET_RECV_NORTH" 46 | 47 | ie.RunInst(inst, &s) 48 | 49 | Expect(s.PC).To(Equal(uint32(0))) 50 | }) 51 | 52 | It("should move data if the data is ready", func() { 53 | s.RecvBufHeadReady[0] = true 54 | s.RecvBufHead[0] = 4 55 | 56 | inst := "WAIT, $2, NET_RECV_NORTH" 57 | 58 | ie.RunInst(inst, &s) 59 | 60 | Expect(s.PC).To(Equal(uint32(1))) 61 | Expect(s.Registers[2]).To(Equal(uint32(4))) 62 | Expect(s.RecvBufHeadReady[0]).To(BeFalse()) 63 | }) 64 | }) 65 | 66 | Context("when running Send", func() { 67 | It("should wait if sendBuf is busy", func() { 68 | s.SendBufHeadBusy[0] = true 69 | 70 | inst := "SEND, NET_SEND_NORTH, $0" 71 | 72 | ie.RunInst(inst, &s) 73 | 74 | Expect(s.PC).To(Equal(uint32(0))) 75 | }) 76 | 77 | It("should send data", func() { 78 | s.SendBufHeadBusy[0] = false 79 | s.Registers[0] = 4 80 | 81 | inst := "SEND, NET_SEND_NORTH, $0" 82 | 83 | ie.RunInst(inst, &s) 84 | 85 | Expect(s.PC).To(Equal(uint32(1))) 86 | Expect(s.SendBufHeadBusy[0]).To(BeTrue()) 87 | Expect(s.SendBufHead[0]).To(Equal(uint32(4))) 88 | }) 89 | })*/ 90 | 91 | //}) 92 | -------------------------------------------------------------------------------- /test/testbench/fir/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "log/slog" 6 | "os" 7 | 8 | "github.com/sarchlab/akita/v4/sim" 9 | "github.com/sarchlab/zeonica/api" 10 | "github.com/sarchlab/zeonica/config" 11 | "github.com/sarchlab/zeonica/core" 12 | ) 13 | 14 | func Fir() { 15 | width := 4 16 | height := 4 17 | 18 | engine := sim.NewSerialEngine() 19 | 20 | driver := api.DriverBuilder{}. 21 | WithEngine(engine). 22 | WithFreq(1 * sim.GHz). 23 | Build("Driver") 24 | 25 | device := config.DeviceBuilder{}. 26 | WithEngine(engine). 27 | WithFreq(1 * sim.GHz). 28 | WithWidth(width). 29 | WithHeight(height). 30 | Build("Device") 31 | 32 | driver.RegisterDevice(device) 33 | 34 | program := core.LoadProgramFileFromYAML("test/testbench/fir/fir4x4.yaml") 35 | if len(program) == 0 { 36 | panic("Failed to load program") 37 | } 38 | 39 | for x := 0; x < width; x++ { 40 | for y := 0; y < height; y++ { 41 | coord := fmt.Sprintf("(%d,%d)", x, y) 42 | if prog, exists := program[coord]; exists { 43 | driver.MapProgram(prog, [2]int{x, y}) 44 | } 45 | } 46 | } 47 | 48 | // fire all the cores in the beginning 49 | for x := 0; x < width; x++ { 50 | for y := 0; y < height; y++ { 51 | tile := device.GetTile(x, y) 52 | // convert to tileCore 53 | tickingComponent := tile.GetTickingComponent() 54 | engine.Schedule(sim.MakeTickEvent(tickingComponent, 0)) 55 | } 56 | } 57 | 58 | driver.PreloadMemory(3, 3, 3, 0) 59 | driver.PreloadMemory(3, 3, 1, 1) 60 | driver.PreloadMemory(2, 1, 2, 0) 61 | driver.PreloadMemory(2, 1, 4, 1) // addr has ERRORS !!!!!! 62 | 63 | driver.Run() 64 | 65 | fmt.Println("========================") 66 | fmt.Println("========================") 67 | fmt.Println("========================") 68 | 69 | // get the returned value 70 | retVal := device.GetTile(0, 0).GetRetVal() 71 | fmt.Println("retVal:", retVal) 72 | 73 | if retVal == 12 { 74 | fmt.Println("✅ Fire tests passed!") 75 | } else { 76 | fmt.Println("❌ Fire tests failed!") 77 | } 78 | } 79 | 80 | func main() { 81 | handler := slog.NewJSONHandler(os.Stdout, &slog.HandlerOptions{ 82 | Level: core.LevelTrace, 83 | }) 84 | 85 | slog.SetDefault(slog.New(handler)) 86 | Fir() 87 | } 88 | -------------------------------------------------------------------------------- /test/testbench/gemm/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "log/slog" 6 | "os" 7 | 8 | "github.com/sarchlab/akita/v4/sim" 9 | "github.com/sarchlab/zeonica/api" 10 | "github.com/sarchlab/zeonica/config" 11 | "github.com/sarchlab/zeonica/core" 12 | ) 13 | 14 | func Gemm() { 15 | width := 4 16 | height := 4 17 | 18 | engine := sim.NewSerialEngine() 19 | 20 | driver := api.DriverBuilder{}. 21 | WithEngine(engine). 22 | WithFreq(1 * sim.GHz). 23 | Build("Driver") 24 | 25 | device := config.DeviceBuilder{}. 26 | WithEngine(engine). 27 | WithFreq(1 * sim.GHz). 28 | WithWidth(width). 29 | WithHeight(height). 30 | Build("Device") 31 | 32 | driver.RegisterDevice(device) 33 | 34 | program := core.LoadProgramFileFromYAML("test/testbench/gemm/gemm_int.yaml") 35 | if len(program) == 0 { 36 | panic("Failed to load program") 37 | } 38 | 39 | for x := 0; x < width; x++ { 40 | for y := 0; y < height; y++ { 41 | coord := fmt.Sprintf("(%d,%d)", x, y) 42 | if prog, exists := program[coord]; exists { 43 | driver.MapProgram(prog, [2]int{x, y}) 44 | } 45 | } 46 | } 47 | 48 | // fire all the cores in the beginning 49 | for x := 0; x < width; x++ { 50 | for y := 0; y < height; y++ { 51 | tile := device.GetTile(x, y) 52 | // convert to tileCore 53 | tickingComponent := tile.GetTickingComponent() 54 | engine.Schedule(sim.MakeTickEvent(tickingComponent, 0)) 55 | } 56 | } 57 | 58 | driver.PreloadMemory(3, 3, 3, 0) 59 | driver.PreloadMemory(3, 3, 1, 1) 60 | driver.PreloadMemory(2, 1, 2, 0) 61 | driver.PreloadMemory(2, 1, 4, 1) // addr has ERRORS !!!!!! 62 | 63 | driver.Run() 64 | 65 | fmt.Println("========================") 66 | fmt.Println("========================") 67 | fmt.Println("========================") 68 | 69 | // get the returned value 70 | retVal := device.GetTile(0, 0).GetRetVal() 71 | fmt.Println("retVal:", retVal) 72 | 73 | if retVal == 12 { 74 | fmt.Println("✅ Fire tests passed!") 75 | } else { 76 | fmt.Println("❌ Fire tests failed!") 77 | } 78 | } 79 | 80 | func main() { 81 | handler := slog.NewJSONHandler(os.Stdout, &slog.HandlerOptions{ 82 | Level: core.LevelTrace, 83 | }) 84 | 85 | slog.SetDefault(slog.New(handler)) 86 | Gemm() 87 | } 88 | -------------------------------------------------------------------------------- /g4file/ZeonicaParser.g4: -------------------------------------------------------------------------------- 1 | parser grammar ZeonicaParser; 2 | 3 | options { 4 | tokenVocab = ZeonicaLexer; 5 | } 6 | 7 | compilationUnit 8 | : peBlock* EOF 9 | ; 10 | 11 | peBlock 12 | : PE LPAREN DECIMAL_LITERAL (COMMA DECIMAL_LITERAL)? RPAREN (ENTRY_ARROW loopType)? LBRACE peBody RBRACE 13 | ; 14 | 15 | peBody 16 | : flatStyle #FlatBody 17 | | entryBlock+ #EntryBlockBody 18 | ; 19 | 20 | flatStyle 21 | : labeledGroup+ 22 | ; 23 | 24 | labeledGroup 25 | : label LBRACE normalInst* RBRACE 26 | ; 27 | 28 | entryBlock 29 | : ENTRY_BLOCK ENTRY_ARROW loopType LBRACE instGroupList RBRACE 30 | ; 31 | 32 | loopType 33 | : LOOP 34 | | ONCE 35 | ; 36 | 37 | instGroupList 38 | : instGroup* 39 | ; 40 | 41 | instGroup 42 | : LBRACE normalInst* RBRACE 43 | ; 44 | 45 | label 46 | : labelID COLON 47 | ; 48 | 49 | labelID 50 | : IDENTIFIER 51 | ; 52 | 53 | normalInst 54 | : opCode COMMA operandList RIGHT_ARROW operandList 55 | | opCode COMMA operandList 56 | | opCode 57 | | operand RIGHT_ARROW operand 58 | ; 59 | 60 | operandList 61 | : operand (COMMA operand)* 62 | ; 63 | 64 | operand 65 | : predTag LBRACK idList RBRACK 66 | | IMM LBRACK DECIMAL_LITERAL RBRACK 67 | | IMM LBRACK OCT_LITERAL RBRACK 68 | | IMM LBRACK HEX_LITERAL RBRACK 69 | | IMM LBRACK BINARY_LITERAL RBRACK 70 | | IMM LBRACK FLOAT_LITERAL RBRACK 71 | | predTag MEM LBRACK idList RBRACK 72 | | predTag MEM LBRACK HEX_LITERAL RBRACK 73 | | labelID 74 | ; 75 | 76 | idList 77 | : IDENTIFIER (COMMA IDENTIFIER)* 78 | ; 79 | 80 | predTag 81 | : AND_PRED 82 | | OR_PRED 83 | | 84 | ; 85 | 86 | opCode 87 | : ADD 88 | | ADDI 89 | | SUB 90 | | SUBI 91 | | MUL 92 | | DIV 93 | | MAC 94 | | INC 95 | | LLS 96 | | LRS 97 | | OR 98 | | AND 99 | | XOR 100 | | NOT 101 | | FADD 102 | | FSUB 103 | | FMUL 104 | | FDIV 105 | | FMAC 106 | | MOV 107 | | MUL_CONST_ADD 108 | | NOP 109 | | CBR 110 | | CMOV 111 | | SGE 112 | ; 113 | -------------------------------------------------------------------------------- /test/add/test_add.yaml: -------------------------------------------------------------------------------- 1 | array_config: 2 | rows: 2 3 | columns: 2 4 | cores: 5 | - row: 0 6 | column: 0 7 | core_id: "core_0_0" 8 | entries: 9 | - entry_id: "entry0" 10 | type: "loop" 11 | instructions: 12 | - operations: 13 | - opcode: "ADD" 14 | src_operands: 15 | - operand: "West" 16 | color: "R" 17 | - operand: "1" 18 | color: "R" 19 | dst_operands: 20 | - operand: "East" 21 | color: "R" 22 | 23 | - row: 0 24 | column: 1 25 | core_id: "core_0_1" 26 | entries: 27 | - entry_id: "entry0" 28 | type: "loop" 29 | instructions: 30 | - operations: 31 | - opcode: "ADD" 32 | src_operands: 33 | - operand: "West" 34 | color: "R" 35 | - operand: "1" 36 | color: "R" 37 | dst_operands: 38 | - operand: "East" 39 | color: "R" 40 | 41 | - row: 1 42 | column: 0 43 | core_id: "core_1_0" 44 | entries: 45 | - entry_id: "entry0" 46 | type: "loop" 47 | instructions: 48 | - operations: 49 | - opcode: "ADD" 50 | src_operands: 51 | - operand: "West" 52 | color: "R" 53 | - operand: "1" 54 | color: "R" 55 | dst_operands: 56 | - operand: "East" 57 | color: "R" 58 | 59 | - row: 1 60 | column: 1 61 | core_id: "core_1_1" 62 | entries: 63 | - entry_id: "entry0" 64 | type: "loop" 65 | instructions: 66 | - operations: 67 | - opcode: "ADD" 68 | src_operands: 69 | - operand: "West" 70 | color: "R" 71 | - operand: "1" 72 | color: "R" 73 | dst_operands: 74 | - operand: "East" 75 | color: "R" -------------------------------------------------------------------------------- /test/add/test_mul.yaml: -------------------------------------------------------------------------------- 1 | array_config: 2 | rows: 2 3 | columns: 2 4 | cores: 5 | - row: 0 6 | column: 0 7 | core_id: "core_0_0" 8 | entries: 9 | - entry_id: "entry0" 10 | type: "loop" 11 | instructions: 12 | - operations: 13 | - opcode: "MUL" 14 | src_operands: 15 | - operand: "East" 16 | color: "R" 17 | - operand: "2" 18 | color: "R" 19 | dst_operands: 20 | - operand: "West" 21 | color: "R" 22 | 23 | - row: 0 24 | column: 1 25 | core_id: "core_0_1" 26 | entries: 27 | - entry_id: "entry0" 28 | type: "loop" 29 | instructions: 30 | - operations: 31 | - opcode: "MUL" 32 | src_operands: 33 | - operand: "East" 34 | color: "R" 35 | - operand: "2" 36 | color: "R" 37 | dst_operands: 38 | - operand: "West" 39 | color: "R" 40 | 41 | - row: 1 42 | column: 0 43 | core_id: "core_1_0" 44 | entries: 45 | - entry_id: "entry0" 46 | type: "loop" 47 | instructions: 48 | - operations: 49 | - opcode: "MUL" 50 | src_operands: 51 | - operand: "East" 52 | color: "R" 53 | - operand: "2" 54 | color: "R" 55 | dst_operands: 56 | - operand: "West" 57 | color: "R" 58 | 59 | - row: 1 60 | column: 1 61 | core_id: "core_1_1" 62 | entries: 63 | - entry_id: "entry0" 64 | type: "loop" 65 | instructions: 66 | - operations: 67 | - opcode: "MUL" 68 | src_operands: 69 | - operand: "East" 70 | color: "R" 71 | - operand: "2" 72 | color: "R" 73 | dst_operands: 74 | - operand: "West" 75 | color: "R" -------------------------------------------------------------------------------- /test/add/test_div.yaml: -------------------------------------------------------------------------------- 1 | array_config: 2 | rows: 2 3 | columns: 2 4 | cores: 5 | - row: 0 6 | column: 0 7 | core_id: "core_0_0" 8 | entries: 9 | - entry_id: "entry0" 10 | type: "loop" 11 | instructions: 12 | - operations: 13 | - opcode: "DIV" 14 | src_operands: 15 | - operand: "North" 16 | color: "R" 17 | - operand: "2" 18 | color: "R" 19 | dst_operands: 20 | - operand: "South" 21 | color: "R" 22 | 23 | - row: 0 24 | column: 1 25 | core_id: "core_0_1" 26 | entries: 27 | - entry_id: "entry0" 28 | type: "loop" 29 | instructions: 30 | - operations: 31 | - opcode: "DIV" 32 | src_operands: 33 | - operand: "North" 34 | color: "R" 35 | - operand: "2" 36 | color: "R" 37 | dst_operands: 38 | - operand: "South" 39 | color: "R" 40 | 41 | - row: 1 42 | column: 0 43 | core_id: "core_1_0" 44 | entries: 45 | - entry_id: "entry0" 46 | type: "loop" 47 | instructions: 48 | - operations: 49 | - opcode: "DIV" 50 | src_operands: 51 | - operand: "North" 52 | color: "R" 53 | - operand: "2" 54 | color: "R" 55 | dst_operands: 56 | - operand: "South" 57 | color: "R" 58 | 59 | - row: 1 60 | column: 1 61 | core_id: "core_1_1" 62 | entries: 63 | - entry_id: "entry0" 64 | type: "loop" 65 | instructions: 66 | - operations: 67 | - opcode: "DIV" 68 | src_operands: 69 | - operand: "North" 70 | color: "R" 71 | - operand: "2" 72 | color: "R" 73 | dst_operands: 74 | - operand: "South" 75 | color: "R" -------------------------------------------------------------------------------- /test/add/test_sub.yaml: -------------------------------------------------------------------------------- 1 | array_config: 2 | rows: 2 3 | columns: 2 4 | cores: 5 | - row: 0 6 | column: 0 7 | core_id: "core_0_0" 8 | entries: 9 | - entry_id: "entry0" 10 | type: "loop" 11 | instructions: 12 | - operations: 13 | - opcode: "SUB" 14 | src_operands: 15 | - operand: "South" 16 | color: "R" 17 | - operand: "1" 18 | color: "R" 19 | dst_operands: 20 | - operand: "North" 21 | color: "R" 22 | 23 | - row: 0 24 | column: 1 25 | core_id: "core_0_1" 26 | entries: 27 | - entry_id: "entry0" 28 | type: "loop" 29 | instructions: 30 | - operations: 31 | - opcode: "SUB" 32 | src_operands: 33 | - operand: "South" 34 | color: "R" 35 | - operand: "1" 36 | color: "R" 37 | dst_operands: 38 | - operand: "North" 39 | color: "R" 40 | 41 | - row: 1 42 | column: 0 43 | core_id: "core_1_0" 44 | entries: 45 | - entry_id: "entry0" 46 | type: "loop" 47 | instructions: 48 | - operations: 49 | - opcode: "SUB" 50 | src_operands: 51 | - operand: "South" 52 | color: "R" 53 | - operand: "1" 54 | color: "R" 55 | dst_operands: 56 | - operand: "North" 57 | color: "R" 58 | 59 | - row: 1 60 | column: 1 61 | core_id: "core_1_1" 62 | entries: 63 | - entry_id: "entry0" 64 | type: "loop" 65 | instructions: 66 | - operations: 67 | - opcode: "SUB" 68 | src_operands: 69 | - operand: "South" 70 | color: "R" 71 | - operand: "1" 72 | color: "R" 73 | dst_operands: 74 | - operand: "North" 75 | color: "R" -------------------------------------------------------------------------------- /test/cf/test_phiconst.yaml: -------------------------------------------------------------------------------- 1 | array_config: 2 | rows: 2 3 | columns: 2 4 | cores: 5 | - row: 0 6 | column: 0 7 | core_id: "core_0_0" 8 | entries: 9 | - entry_id: "entry0" 10 | type: "loop" 11 | instructions: 12 | - operations: 13 | - opcode: "PHI_CONST" 14 | src_operands: 15 | - operand: "4" 16 | color: "R" 17 | - operand: "West" 18 | color: "R" 19 | dst_operands: 20 | - operand: "East" 21 | color: "R" 22 | 23 | - row: 1 24 | column: 0 25 | core_id: "core_1_0" 26 | entries: 27 | - entry_id: "entry0" 28 | type: "loop" 29 | instructions: 30 | - operations: 31 | - opcode: "PHI_CONST" 32 | src_operands: 33 | - operand: "1" 34 | color: "R" 35 | - operand: "East" 36 | color: "R" 37 | dst_operands: 38 | - operand: "West" 39 | color: "R" 40 | 41 | - row: 0 42 | column: 1 43 | core_id: "core_0_1" 44 | entries: 45 | - entry_id: "entry0" 46 | type: "loop" 47 | instructions: 48 | - operations: 49 | - opcode: "PHI_CONST" 50 | src_operands: 51 | - operand: "3" 52 | color: "R" 53 | - operand: "West" 54 | color: "R" 55 | dst_operands: 56 | - operand: "North" 57 | color: "R" 58 | 59 | - row: 1 60 | column: 1 61 | core_id: "core_1_1" 62 | entries: 63 | - entry_id: "entry0" 64 | type: "loop" 65 | instructions: 66 | - operations: 67 | - opcode: "PHI_CONST" 68 | src_operands: 69 | - operand: "2" 70 | color: "R" 71 | - operand: "South" 72 | color: "R" 73 | dst_operands: 74 | - operand: "West" 75 | color: "R" -------------------------------------------------------------------------------- /test/misc/test_spread.yaml: -------------------------------------------------------------------------------- 1 | array_config: 2 | rows: 2 3 | columns: 2 4 | cores: 5 | - row: 0 6 | column: 0 7 | core_id: "core_0_0" 8 | entries: 9 | - entry_id: "entry0" 10 | type: "loop" 11 | instructions: 12 | - operations: 13 | - opcode: "MOV" 14 | src_operands: 15 | - operand: "West" 16 | color: "R" 17 | dst_operands: 18 | - operand: "$0" 19 | color: "R" 20 | - operand: "East" 21 | color: "R" 22 | - operand: "North" 23 | color: "R" 24 | - operations: 25 | - opcode: "MOV" 26 | src_operands: 27 | - operand: "$0" 28 | color: "R" 29 | dst_operands: 30 | - operand: "West" 31 | color: "R" 32 | 33 | - row: 1 34 | column: 0 35 | core_id: "core_1_0" 36 | entries: 37 | - entry_id: "entry0" 38 | type: "loop" 39 | instructions: 40 | - operations: 41 | - opcode: "MOV" 42 | src_operands: 43 | - operand: "South" 44 | color: "R" 45 | dst_operands: 46 | - operand: "East" 47 | color: "R" 48 | - operand: "West" 49 | color: "R" 50 | 51 | - row: 0 52 | column: 1 53 | core_id: "core_0_1" 54 | entries: 55 | - entry_id: "entry0" 56 | type: "loop" 57 | instructions: 58 | - operations: 59 | - opcode: "MOV" 60 | src_operands: 61 | - operand: "West" 62 | color: "R" 63 | dst_operands: 64 | - operand: "East" 65 | color: "R" 66 | 67 | - row: 1 68 | column: 1 69 | core_id: "core_1_1" 70 | entries: 71 | - entry_id: "entry0" 72 | type: "loop" 73 | instructions: 74 | - operations: 75 | - opcode: "MOV" 76 | src_operands: 77 | - operand: "West" 78 | color: "R" 79 | dst_operands: 80 | - operand: "East" 81 | color: "R" -------------------------------------------------------------------------------- /test/pred/test_gpred.yaml: -------------------------------------------------------------------------------- 1 | array_config: 2 | rows: 2 3 | columns: 2 4 | cores: 5 | - row: 0 6 | column: 0 7 | core_id: "core_0_0" 8 | entries: 9 | - entry_id: "entry0" 10 | type: "loop" 11 | instructions: 12 | - operations: 13 | - opcode: "CMP_EXPORT" 14 | src_operands: 15 | - operand: "West" 16 | color: "R" 17 | - operand: "South" 18 | color: "R" 19 | dst_operands: 20 | - operand: "North" 21 | color: "R" 22 | - operand: "$0" 23 | color: "R" 24 | - operations: 25 | - opcode: "NOT" 26 | src_operands: 27 | - operand: "$0" 28 | color: "R" 29 | dst_operands: 30 | - operand: "East" 31 | color: "R" 32 | 33 | - row: 1 34 | column: 0 35 | core_id: "core_1_0" 36 | entries: 37 | - entry_id: "entry0" 38 | type: "loop" 39 | instructions: 40 | - operations: 41 | - opcode: "GRANT_PREDICATE" 42 | src_operands: 43 | - operand: "West" 44 | color: "R" 45 | - operand: "South" 46 | color: "R" 47 | dst_operands: 48 | - operand: "East" 49 | color: "R" 50 | 51 | 52 | - row: 0 53 | column: 1 54 | core_id: "core_0_1" 55 | entries: 56 | - entry_id: "entry0" 57 | type: "loop" 58 | instructions: 59 | - operations: 60 | - opcode: "GRANT_PREDICATE" 61 | src_operands: 62 | - operand: "South" 63 | color: "R" 64 | - operand: "West" 65 | color: "R" 66 | dst_operands: 67 | - operand: "North" 68 | color: "R" 69 | 70 | - row: 1 71 | column: 1 72 | core_id: "core_1_1" 73 | entries: 74 | - entry_id: "entry0" 75 | type: "loop" 76 | instructions: 77 | - operations: 78 | - opcode: "PHI" 79 | src_operands: 80 | - operand: "West" 81 | color: "R" 82 | - operand: "South" 83 | color: "R" 84 | dst_operands: 85 | - operand: "East" 86 | color: "R" -------------------------------------------------------------------------------- /core/builder.go: -------------------------------------------------------------------------------- 1 | package core 2 | 3 | import ( 4 | "github.com/sarchlab/akita/v4/sim" 5 | "github.com/sarchlab/zeonica/cgra" 6 | ) 7 | 8 | // Builder can create new cores. 9 | type Builder struct { 10 | engine sim.Engine 11 | freq sim.Freq 12 | exitAddr *bool 13 | retValAddr *uint32 14 | } 15 | 16 | // WithEngine sets the engine. 17 | func (b Builder) WithEngine(engine sim.Engine) Builder { 18 | b.engine = engine 19 | return b 20 | } 21 | 22 | // WithFreq sets the frequency of the core. 23 | func (b Builder) WithFreq(freq sim.Freq) Builder { 24 | b.freq = freq 25 | return b 26 | } 27 | 28 | func (b Builder) WithExitAddr(exitAddr *bool) Builder { 29 | b.exitAddr = exitAddr 30 | return b 31 | } 32 | 33 | func (b Builder) WithRetValAddr(retValAddr *uint32) Builder { 34 | b.retValAddr = retValAddr 35 | return b 36 | } 37 | 38 | // Build creates a core. 39 | func (b Builder) Build(name string) *Core { 40 | c := &Core{} 41 | 42 | c.TickingComponent = sim.NewTickingComponent(name, b.engine, b.freq, c) 43 | c.emu = instEmulator{ 44 | CareFlags: true, 45 | } 46 | c.state = coreState{ 47 | exit: b.exitAddr, 48 | retVal: b.retValAddr, 49 | SelectedBlock: nil, 50 | PCInBlock: -1, 51 | Directions: map[string]bool{ 52 | "North": true, 53 | "East": true, 54 | "South": true, 55 | "West": true, 56 | "NorthEast": true, 57 | "SouthEast": true, 58 | "SouthWest": true, 59 | "NorthWest": true, 60 | "Router": true, 61 | }, 62 | Registers: make([]cgra.Data, 64), 63 | Memory: make([]uint32, 1024), 64 | RecvBufHead: make([][]cgra.Data, 4), 65 | RecvBufHeadReady: make([][]bool, 4), 66 | SendBufHead: make([][]cgra.Data, 4), 67 | SendBufHeadBusy: make([][]bool, 4), 68 | AddrBuf: 0, 69 | IsToWriteMemory: false, 70 | States: make(map[string]interface{}), 71 | Mode: SyncOp, 72 | CurrReservationState: ReservationState{ 73 | ReservationMap: make(map[int]bool), 74 | OpToExec: 0, 75 | RefCountRuntime: make(map[string]int), 76 | }, 77 | } 78 | 79 | for i := 0; i < 4; i++ { 80 | c.state.RecvBufHead[i] = make([]cgra.Data, 12) 81 | c.state.RecvBufHeadReady[i] = make([]bool, 12) 82 | c.state.SendBufHead[i] = make([]cgra.Data, 12) 83 | c.state.SendBufHeadBusy[i] = make([]bool, 12) 84 | } 85 | 86 | c.state.States["Phiconst"] = false 87 | 88 | c.ports = make(map[cgra.Side]*portPair) 89 | 90 | b.makePort(c, cgra.North) 91 | b.makePort(c, cgra.West) 92 | b.makePort(c, cgra.South) 93 | b.makePort(c, cgra.East) 94 | b.makePort(c, cgra.NorthEast) 95 | b.makePort(c, cgra.SouthEast) 96 | b.makePort(c, cgra.SouthWest) 97 | b.makePort(c, cgra.NorthWest) 98 | b.makePort(c, cgra.Router) 99 | b.makePort(c, cgra.Dummy1) 100 | b.makePort(c, cgra.Dummy2) 101 | b.makePort(c, cgra.Dummy3) 102 | 103 | return c 104 | } 105 | 106 | func (b *Builder) makePort(c *Core, side cgra.Side) { 107 | localPort := sim.NewPort(c, 1, 1, c.Name()+"."+side.Name()) 108 | c.ports[side] = &portPair{ 109 | local: localPort, 110 | } 111 | c.AddPort(side.Name(), localPort) 112 | } 113 | -------------------------------------------------------------------------------- /test/pred/cf_test.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "testing" 6 | "unsafe" 7 | 8 | "github.com/sarchlab/akita/v4/sim" 9 | "github.com/sarchlab/zeonica/api" 10 | "github.com/sarchlab/zeonica/cgra" 11 | "github.com/sarchlab/zeonica/config" 12 | "github.com/sarchlab/zeonica/core" 13 | ) 14 | 15 | func TestPhiOperation(t *testing.T) { 16 | // Set test parameters 17 | width := 2 18 | height := 2 19 | length := 5 20 | 21 | // Generate random test data 22 | cmpSrcData1 := []uint32{6, 7, 3, 4, 8} 23 | cmpSrcData2 := []uint32{1, 2, 3, 4, 5} 24 | SrcData1 := []uint32{1, 2, 3, 4, 5} 25 | SrcData2 := []uint32{6, 7, 8, 9, 10} 26 | dst := make([]uint32, length) 27 | 28 | // Create simulation engine 29 | engine := sim.NewSerialEngine() 30 | 31 | // Create driver 32 | driver := api.DriverBuilder{}. 33 | WithEngine(engine). 34 | WithFreq(1 * sim.GHz). 35 | Build("Driver") 36 | 37 | // Create device 38 | device := config.DeviceBuilder{}. 39 | WithEngine(engine). 40 | WithFreq(1 * sim.GHz). 41 | WithWidth(width). 42 | WithHeight(height). 43 | Build("Device") 44 | 45 | driver.RegisterDevice(device) 46 | 47 | // Load program 48 | program := core.LoadProgramFileFromYAML("./test_gpred.yaml") 49 | if len(program) == 0 { 50 | t.Fatal("Failed to load program") 51 | } 52 | 53 | // Set data flow - input from west, output to east 54 | driver.FeedIn(cmpSrcData1, cgra.West, [2]int{0, 1}, 1, "R") 55 | driver.FeedIn(cmpSrcData2, cgra.South, [2]int{0, 1}, 1, "R") 56 | driver.FeedIn(SrcData1, cgra.West, [2]int{1, 2}, 1, "R") 57 | driver.FeedIn(SrcData2, cgra.South, [2]int{1, 2}, 1, "R") 58 | driver.Collect(dst, cgra.East, [2]int{1, 2}, 1, "R") 59 | 60 | // Map program to all cores 61 | for x := 0; x < width; x++ { 62 | for y := 0; y < height; y++ { 63 | coord := fmt.Sprintf("(%d,%d)", x, y) 64 | if prog, exists := program[coord]; exists { 65 | driver.MapProgram(prog, [2]int{x, y}) 66 | } 67 | } 68 | } 69 | 70 | // Run simulation 71 | driver.Run() 72 | 73 | // Convert results and verify 74 | cmpSrcIData1 := make([]int32, length) 75 | cmpSrcIData2 := make([]int32, length) 76 | srcIData1 := make([]int32, length) 77 | srcIData2 := make([]int32, length) 78 | dstI := make([]int32, length) 79 | 80 | for i := 0; i < length; i++ { 81 | cmpSrcIData1[i] = *(*int32)(unsafe.Pointer(&cmpSrcData1[i])) 82 | cmpSrcIData2[i] = *(*int32)(unsafe.Pointer(&cmpSrcData2[i])) 83 | srcIData1[i] = *(*int32)(unsafe.Pointer(&SrcData1[i])) 84 | srcIData2[i] = *(*int32)(unsafe.Pointer(&SrcData2[i])) 85 | } 86 | 87 | expected := []int32{6, 7, 3, 4, 10} 88 | for i := 0; i < 5; i++ { 89 | dstI[i] = *(*int32)(unsafe.Pointer(&dst[i])) 90 | } 91 | 92 | t.Log("=== Gpred Test Results ===") 93 | allPassed := true 94 | for i := 0; i < 5; i++ { 95 | actual := dstI[i] 96 | if actual != expected[i] { 97 | t.Errorf("Index %d:, cmpSrc1=%d, cmpSrc2=%d, src1=%d, src2=%d, Expected=%d, Actual=%d", 98 | i, cmpSrcIData1[i], cmpSrcIData2[i], srcIData1[i], srcIData2[i], expected[i], actual) 99 | allPassed = false 100 | } 101 | } 102 | 103 | if allPassed { 104 | t.Log("✅ Gpred tests passed!") 105 | } else { 106 | t.Fatal("❌ Gpred tests failed!") 107 | } 108 | } 109 | -------------------------------------------------------------------------------- /test/mem/test_lw.yaml: -------------------------------------------------------------------------------- 1 | array_config: 2 | rows: 2 3 | columns: 2 4 | cores: 5 | - row: 0 6 | column: 0 7 | core_id: "core_0_0" 8 | entries: 9 | - entry_id: "entry0" 10 | type: "loop" 11 | instructions: 12 | - operations: 13 | - opcode: "MOV" 14 | src_operands: 15 | - operand: "West" 16 | color: "R" 17 | dst_operands: 18 | - operand: "$0" 19 | color: "R" 20 | - operations: 21 | - opcode: "LD" 22 | src_operands: 23 | - operand: "0" 24 | color: "R" 25 | dst_operands: # just for flag check 26 | - operand: "Router" 27 | color: "R" 28 | - operations: 29 | - opcode: "LDW" 30 | src_operands: 31 | - operand: "Router" 32 | color: "R" 33 | dst_operands: 34 | - operand: "East" 35 | color: "R" 36 | 37 | - row: 1 38 | column: 0 39 | core_id: "core_1_0" 40 | entries: 41 | - entry_id: "entry0" 42 | type: "loop" 43 | instructions: 44 | - operations: 45 | - opcode: "MOV" 46 | src_operands: 47 | - operand: "West" 48 | color: "R" 49 | dst_operands: 50 | - operand: "$0" 51 | color: "R" 52 | - operations: 53 | - opcode: "LD" 54 | src_operands: 55 | - operand: "0" 56 | color: "R" 57 | dst_operands: # just for flag check 58 | - operand: "Router" 59 | color: "R" 60 | - operations: 61 | - opcode: "LDW" 62 | src_operands: 63 | - operand: "Router" 64 | color: "R" 65 | dst_operands: 66 | - operand: "East" 67 | color: "R" 68 | 69 | 70 | 71 | - row: 0 72 | column: 1 73 | core_id: "core_0_1" 74 | entries: 75 | - entry_id: "entry0" 76 | type: "loop" 77 | instructions: 78 | - operations: 79 | - opcode: "MOV" 80 | src_operands: 81 | - operand: "West" 82 | color: "R" 83 | dst_operands: 84 | - operand: "East" 85 | color: "R" 86 | 87 | - row: 1 88 | column: 1 89 | core_id: "core_1_1" 90 | entries: 91 | - entry_id: "entry0" 92 | type: "loop" 93 | instructions: 94 | - operations: 95 | - opcode: "MOV" 96 | src_operands: 97 | - operand: "West" 98 | color: "R" 99 | dst_operands: 100 | - operand: "East" 101 | color: "R" -------------------------------------------------------------------------------- /test/mem/test_loadstore.yaml: -------------------------------------------------------------------------------- 1 | array_config: 2 | rows: 2 3 | columns: 2 4 | cores: 5 | - row: 0 6 | column: 0 7 | core_id: "core_0_0" 8 | entries: 9 | - entry_id: "entry0" 10 | type: "loop" 11 | instructions: 12 | - operations: 13 | - opcode: "MOV" 14 | src_operands: 15 | - operand: "West" 16 | color: "R" 17 | dst_operands: 18 | - operand: "$0" 19 | color: "R" 20 | - operations: 21 | - opcode: "STD" 22 | src_operands: 23 | - operand: "0" 24 | color: "R" 25 | - operand: "$0" 26 | color: "R" 27 | - operations: 28 | - opcode: "LDD" 29 | src_operands: 30 | - operand: "0" 31 | color: "R" 32 | dst_operands: 33 | - operand: "East" 34 | color: "R" 35 | 36 | - row: 1 37 | column: 0 38 | core_id: "core_1_0" 39 | entries: 40 | - entry_id: "entry0" 41 | type: "loop" 42 | instructions: 43 | - operations: 44 | - opcode: "STD" 45 | src_operands: 46 | - operand: "0" 47 | color: "R" 48 | - operand: "East" 49 | color: "R" 50 | - operations: 51 | - opcode: "LDD" 52 | src_operands: 53 | - operand: "0" 54 | color: "R" 55 | dst_operands: 56 | - operand: "West" 57 | color: "R" 58 | - row: 0 59 | column: 1 60 | core_id: "core_0_1" 61 | entries: 62 | - entry_id: "entry0" 63 | type: "loop" 64 | instructions: 65 | - operations: 66 | - opcode: "STD" 67 | src_operands: 68 | - operand: "0" 69 | color: "R" 70 | - operand: "West" 71 | color: "R" 72 | - operations: 73 | - opcode: "LDD" 74 | src_operands: 75 | - operand: "0" 76 | color: "R" 77 | dst_operands: 78 | - operand: "North" 79 | color: "R" 80 | 81 | - row: 1 82 | column: 1 83 | core_id: "core_1_1" 84 | entries: 85 | - entry_id: "entry0" 86 | type: "loop" 87 | instructions: 88 | - operations: 89 | - opcode: "STD" 90 | src_operands: 91 | - operand: "0" 92 | color: "R" 93 | - operand: "South" 94 | color: "R" 95 | - operations: 96 | - opcode: "LDD" 97 | src_operands: 98 | - operand: "0" 99 | color: "R" 100 | dst_operands: 101 | - operand: "West" 102 | color: "R" -------------------------------------------------------------------------------- /test/cf/test_gpred.yaml: -------------------------------------------------------------------------------- 1 | array_config: 2 | rows: 2 3 | columns: 2 4 | cores: 5 | - row: 0 6 | column: 0 7 | core_id: "core_0_0" 8 | entries: 9 | - entry_id: "entry0" 10 | type: "loop" 11 | instructions: 12 | - operations: 13 | - opcode: "GPRED" 14 | src_operands: 15 | - operand: "West" 16 | color: "R" 17 | - operand: "North" 18 | color: "R" 19 | dst_operands: 20 | - operand: "East" 21 | color: "R" 22 | 23 | - row: 1 24 | column: 0 25 | core_id: "core_1_0" 26 | entries: 27 | - entry_id: "entry0" 28 | type: "loop" 29 | instructions: 30 | - operations: 31 | - opcode: "MOV" 32 | src_operands: 33 | - operand: "West" 34 | color: "R" 35 | dst_operands: 36 | - operand: "South" 37 | color: "R" 38 | - operations: 39 | - opcode: "MOV" 40 | src_operands: 41 | - operand: "West" 42 | color: "R" 43 | dst_operands: 44 | - operand: "East" 45 | color: "R" 46 | - operations: 47 | - opcode: "MOV" 48 | src_operands: 49 | - operand: "West" 50 | color: "R" 51 | dst_operands: 52 | - operand: "South" 53 | color: "R" 54 | - operations: 55 | - opcode: "MOV" 56 | src_operands: 57 | - operand: "West" 58 | color: "R" 59 | dst_operands: 60 | - operand: "South" 61 | color: "R" 62 | - operations: 63 | - opcode: "MOV" 64 | src_operands: 65 | - operand: "West" 66 | color: "R" 67 | dst_operands: 68 | - operand: "East" 69 | color: "R" 70 | 71 | - row: 0 72 | column: 1 73 | core_id: "core_0_1" 74 | entries: 75 | - entry_id: "entry0" 76 | type: "loop" 77 | instructions: 78 | - operations: 79 | - opcode: "GPRED" 80 | src_operands: 81 | - operand: "West" 82 | color: "R" 83 | - operand: "North" 84 | color: "R" 85 | dst_operands: 86 | - operand: "East" 87 | color: "R" 88 | 89 | - row: 1 90 | column: 1 91 | core_id: "core_1_1" 92 | entries: 93 | - entry_id: "entry0" 94 | type: "loop" 95 | instructions: 96 | - operations: 97 | - opcode: "MOV" 98 | src_operands: 99 | - operand: "West" 100 | color: "R" 101 | dst_operands: 102 | - operand: "South" 103 | color: "R" -------------------------------------------------------------------------------- /test/ctrl/ret_test.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "testing" 6 | 7 | "github.com/sarchlab/akita/v4/sim" 8 | "github.com/sarchlab/zeonica/api" 9 | "github.com/sarchlab/zeonica/cgra" 10 | "github.com/sarchlab/zeonica/config" 11 | "github.com/sarchlab/zeonica/core" 12 | ) 13 | 14 | func TestRetOperation(t *testing.T) { 15 | // Set test parameters 16 | width := 2 17 | height := 2 18 | 19 | // Generate random test data 20 | src := make([]uint32, 1) 21 | src[0] = 114514 22 | 23 | // Create simulation engine 24 | engine := sim.NewSerialEngine() 25 | 26 | // Create driver 27 | driver := api.DriverBuilder{}. 28 | WithEngine(engine). 29 | WithFreq(1 * sim.GHz). 30 | Build("Driver") 31 | 32 | // Create device 33 | device := config.DeviceBuilder{}. 34 | WithEngine(engine). 35 | WithFreq(1 * sim.GHz). 36 | WithWidth(width). 37 | WithHeight(height). 38 | Build("Device") 39 | 40 | driver.RegisterDevice(device) 41 | 42 | // Load program 43 | program := core.LoadProgramFileFromYAML("./test_ret.yaml") 44 | if len(program) == 0 { 45 | t.Fatal("Failed to load program") 46 | } 47 | 48 | // Set data flow - input from west, output to east 49 | driver.FeedIn(src, cgra.West, [2]int{0, 1}, 1, "R") 50 | 51 | // Map program to all cores 52 | for x := 0; x < width; x++ { 53 | for y := 0; y < height; y++ { 54 | coord := fmt.Sprintf("(%d,%d)", x, y) 55 | if prog, exists := program[coord]; exists { 56 | driver.MapProgram(prog, [2]int{x, y}) 57 | } 58 | } 59 | } 60 | 61 | // Run simulation 62 | driver.Run() 63 | 64 | retVal := device.GetTile(0, 0).GetRetVal() 65 | 66 | if retVal == 114514 { 67 | fmt.Println("retVal:", retVal) 68 | t.Log("✅ Ret tests passed!") 69 | } else { 70 | fmt.Println("retVal:", retVal) 71 | t.Fatal("❌ Ret tests failed!") 72 | } 73 | } 74 | 75 | func TestFireOperation(t *testing.T) { 76 | // Set test parameters 77 | width := 2 78 | height := 2 79 | 80 | // Create simulation engine 81 | engine := sim.NewSerialEngine() 82 | 83 | // Create driver 84 | driver := api.DriverBuilder{}. 85 | WithEngine(engine). 86 | WithFreq(1 * sim.GHz). 87 | Build("Driver") 88 | 89 | // Create device 90 | device := config.DeviceBuilder{}. 91 | WithEngine(engine). 92 | WithFreq(1 * sim.GHz). 93 | WithWidth(width). 94 | WithHeight(height). 95 | Build("Device") 96 | 97 | driver.RegisterDevice(device) 98 | 99 | // Load program 100 | program := core.LoadProgramFileFromYAML("./test_fire.yaml") 101 | if len(program) == 0 { 102 | t.Fatal("Failed to load program") 103 | } 104 | 105 | // fire all the cores in the beginning 106 | for x := 0; x < width; x++ { 107 | for y := 0; y < height; y++ { 108 | tile := device.GetTile(x, y) 109 | // convert to tileCore 110 | tickingComponent := tile.GetTickingComponent() 111 | engine.Schedule(sim.MakeTickEvent(tickingComponent, 0)) 112 | } 113 | } 114 | 115 | // Map program to all cores 116 | for x := 0; x < width; x++ { 117 | for y := 0; y < height; y++ { 118 | coord := fmt.Sprintf("(%d,%d)", x, y) 119 | if prog, exists := program[coord]; exists { 120 | driver.MapProgram(prog, [2]int{x, y}) 121 | } 122 | } 123 | } 124 | 125 | // Run simulation 126 | driver.Run() 127 | 128 | retVal := device.GetTile(0, 0).GetRetVal() 129 | 130 | if retVal == 1 { 131 | fmt.Println("retVal:", retVal) 132 | t.Log("✅ Fire tests passed!") 133 | } else { 134 | fmt.Println("retVal:", retVal) 135 | t.Fatal("❌ Fire tests failed!") 136 | } 137 | } 138 | -------------------------------------------------------------------------------- /test/misc/spread_test.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "testing" 6 | "unsafe" 7 | 8 | "github.com/sarchlab/akita/v4/sim" 9 | "github.com/sarchlab/zeonica/api" 10 | "github.com/sarchlab/zeonica/cgra" 11 | "github.com/sarchlab/zeonica/config" 12 | "github.com/sarchlab/zeonica/core" 13 | ) 14 | 15 | func TestSpreadOperation(t *testing.T) { 16 | // Set test parameters 17 | width := 2 18 | height := 2 19 | length := 10 20 | 21 | // Create test data 22 | src := make([]uint32, length) 23 | dst1 := make([]uint32, length) 24 | dst2 := make([]uint32, length) 25 | dst3 := make([]uint32, length) 26 | dst4 := make([]uint32, length) 27 | 28 | // Generate random test data 29 | src = []uint32{1, 2, 9, 9, 0, 0, 3, 5, 6, 7} 30 | 31 | // Create simulation engine 32 | engine := sim.NewSerialEngine() 33 | 34 | // Create driver 35 | driver := api.DriverBuilder{}. 36 | WithEngine(engine). 37 | WithFreq(1 * sim.GHz). 38 | Build("Driver") 39 | 40 | // Create device 41 | device := config.DeviceBuilder{}. 42 | WithEngine(engine). 43 | WithFreq(1 * sim.GHz). 44 | WithWidth(width). 45 | WithHeight(height). 46 | Build("Device") 47 | 48 | driver.RegisterDevice(device) 49 | 50 | // Load program 51 | program := core.LoadProgramFileFromYAML("./test_spread.yaml") 52 | if len(program) == 0 { 53 | t.Fatal("Failed to load program") 54 | } 55 | 56 | // Set data flow - input from west, output to east 57 | driver.FeedIn(src, cgra.West, [2]int{0, 1}, 1, "R") 58 | driver.Collect(dst1, cgra.West, [2]int{1, 2}, 1, "R") 59 | driver.Collect(dst2, cgra.East, [2]int{0, 1}, 1, "R") 60 | driver.Collect(dst3, cgra.East, [2]int{1, 2}, 1, "R") 61 | driver.Collect(dst4, cgra.West, [2]int{0, 1}, 1, "R") 62 | 63 | // Map program to all cores 64 | for x := 0; x < width; x++ { 65 | for y := 0; y < height; y++ { 66 | coord := fmt.Sprintf("(%d,%d)", x, y) 67 | if prog, exists := program[coord]; exists { 68 | driver.MapProgram(prog, [2]int{x, y}) 69 | } 70 | } 71 | } 72 | 73 | // Run simulation 74 | driver.Run() 75 | 76 | // Convert results and verify 77 | srcI := make([]int32, length) 78 | dstI1 := make([]int32, length) 79 | dstI2 := make([]int32, length) 80 | dstI3 := make([]int32, length) 81 | dstI4 := make([]int32, length) 82 | for i := 0; i < length; i++ { 83 | srcI[i] = *(*int32)(unsafe.Pointer(&src[i])) 84 | dstI1[i] = *(*int32)(unsafe.Pointer(&dst1[i])) 85 | dstI2[i] = *(*int32)(unsafe.Pointer(&dst2[i])) 86 | dstI3[i] = *(*int32)(unsafe.Pointer(&dst3[i])) 87 | dstI4[i] = *(*int32)(unsafe.Pointer(&dst4[i])) 88 | } 89 | 90 | expected := []int32{1, 2, 9, 9, 0, 0, 3, 5, 6, 7} 91 | // Verify results: output should be input+2 92 | t.Log("=== Spread Test Results ===") 93 | allPassed := true 94 | for i := 0; i < length; i++ { 95 | actual1 := dstI1[i] 96 | actual2 := dstI2[i] 97 | actual3 := dstI3[i] 98 | actual4 := dstI4[i] 99 | if actual1 != expected[i] || actual2 != expected[i] || actual3 != expected[i] || actual4 != expected[i] { 100 | t.Errorf("Index %d: Input=%d, Expected=%d, Actual=%d", 101 | i, srcI[i], expected[i], actual1) 102 | t.Errorf("Index %d: Input=%d, Expected=%d, Actual=%d", 103 | i, srcI[i], expected[i], actual2) 104 | t.Errorf("Index %d: Input=%d, Expected=%d, Actual=%d", 105 | i, srcI[i], expected[i], actual3) 106 | t.Errorf("Index %d: Input=%d, Expected=%d, Actual=%d", 107 | i, srcI[i], expected[i], actual4) 108 | allPassed = false 109 | } else { 110 | t.Logf("Index %d: Input=%d, Output=%d ✓", i, srcI[i], actual1) 111 | t.Logf("Index %d: Input=%d, Output=%d ✓", i, srcI[i], actual2) 112 | t.Logf("Index %d: Input=%d, Output=%d ✓", i, srcI[i], actual3) 113 | t.Logf("Index %d: Input=%d, Output=%d ✓", i, srcI[i], actual4) 114 | } 115 | } 116 | 117 | if allPassed { 118 | t.Log("✅ Spread tests passed!") 119 | } else { 120 | t.Fatal("❌ Spread tests failed!") 121 | } 122 | } 123 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Zeonica 2 | Cycle-accurate CGRA / wafer-scale accelerator simulator with a fast verification toolkit. 3 | 4 | ## Overview 5 | - Built on [Akita v4](https://github.com/sarchlab/akita) for timing-accurate simulation of CGRA tiles and interconnect. 6 | - Driver + device builder to map kernels, feed/collect data, and configure memory topology. 7 | - `verify/` package: static lint + functional simulator + reporting (fast semantic verification before full simulation). 8 | - Reference kernels live in the `test/Zeonica_Testbench` submodule (AXPY, histogram, etc.). 9 | 10 | ## Requirements 11 | - Go 1.24+ (see `go.mod` toolchain). 12 | - Git with submodules enabled. 13 | 14 | ## Setup 15 | ```bash 16 | git clone https://github.com/sarchlab/zeonica.git 17 | cd zeonica 18 | git submodule update --init --recursive # brings in test/Zeonica_Testbench 19 | go mod download 20 | ``` 21 | 22 | ## Quick Start 23 | ### Verify a kernel (fast path) 24 | - Library API: 25 | ```go 26 | programs := core.LoadProgramFileFromYAML("kernel.yaml") 27 | arch := &verify.ArchInfo{Rows: 4, Columns: 4, Topology: "mesh", HopLatency: 1, MemCapacity: 1024} 28 | verify.GenerateReport(programs, arch, 100).SaveReportToFile("report.txt") 29 | ``` 30 | - CLI tools: 31 | ```bash 32 | go run ./verify/cmd/verify-axpy # outputs verification_report.txt 33 | go run ./verify/cmd/verify-histogram # outputs histogram_verification_report.txt 34 | ``` 35 | 36 | ### Run tests 37 | - Verify package only: `go test ./verify -v` 38 | - Full suite (longer): `go test ./...` 39 | 40 | ## Project Layout 41 | - `core/` — cycle-accurate CGRA core, instruction emulator, tracing utilities. 42 | - `cgra/` — common CGRA data structures, ports, messages, device/tile interfaces. 43 | - `api/` — driver that maps kernels, feeds/collects data, and runs the engine. 44 | - `config/` — device builder, mesh wiring, and memory modes (simple/shared/local). 45 | - `verify/` — lint + functional simulator + report generator; CLI under `verify/cmd/`. 46 | - `test/` — regression tests and sample kernels; `test/Zeonica_Testbench` is a submodule with YAML kernels. 47 | 48 | ## Architecture (How it fits together) 49 | - **Tile/Core** (`core/`): Instruction emulator + cycle-accurate send/recv paths on Akita ports; traces dataflow/memory events. Opcodes implemented in `core/emu.go`, state in `core/core.go`. 50 | - **CGRA device** (`cgra/`, `config/`): Mesh wiring of tiles; configurable memory mode (`simple`, `shared`, `local`) via `config.DeviceBuilder`. Uses Akita direct connections and optional shared memory controllers. 51 | - **Driver** (`api/driver.go`): Maps per-PE kernels, feeds inputs, collects outputs, and ticks the simulation engine. Supports preload/read of per-PE memory. 52 | - **Verification fast path** (`verify/`): Static lint (STRUCT/TIMING) + functional simulator + report generator. Mirrors opcode semantics without timing/backpressure; CLIs in `verify/cmd/`. 53 | - **Testbench** (`test/Zeonica_Testbench` submodule): Reference kernels (AXPY, histogram, etc.) consumed by verify and simulation tests. 54 | 55 | ### Execution flow (simulation) 56 | ```mermaid 57 | flowchart LR 58 | Driver --> DeviceBuilder --> Device --> Cores --> AkitaEngine 59 | Driver -->|Map programs| Cores 60 | Driver -->|Feed/Collect| Cores 61 | ``` 62 | 63 | ### Execution flow (verification) 64 | ```mermaid 65 | flowchart LR 66 | KernelYAML -->|core.LoadProgramFileFromYAML| Programs 67 | Programs -->|RunLint| Lint 68 | Programs -->|FunctionalSim| FuncSim 69 | Lint --> Report 70 | FuncSim --> Report 71 | ``` 72 | 73 | ## Working with Kernels 74 | 1. Author kernel YAML (per-PE programs) under `test/Zeonica_Testbench/kernel/...`. 75 | 2. Lint + functional verify with `verify.GenerateReport` or the CLI tools. 76 | 3. For timing-accurate runs, map programs via the driver/config packages and use Akita simulation (see tests under `test/` for patterns). 77 | 78 | ## Tips & Troubleshooting 79 | - Submodule is required for the bundled kernels; re-run `git submodule update --init --recursive` after pulling. 80 | - Opcode semantics are implemented in `core/emu.go`; `verify` mirrors these for functional simulation. 81 | - If adding opcodes, update `core/emu.go` and `verify/funcsim.go`, plus unit tests in `verify/`. 82 | 83 | ## License 84 | See `LICENSE` for details. -------------------------------------------------------------------------------- /config/platform.go: -------------------------------------------------------------------------------- 1 | package config 2 | 3 | import ( 4 | "fmt" 5 | 6 | "github.com/sarchlab/akita/v4/mem/idealmemcontroller" 7 | "github.com/sarchlab/akita/v4/sim" 8 | "github.com/sarchlab/zeonica/cgra" 9 | ) 10 | 11 | type tileCore interface { 12 | sim.Component 13 | MapProgram(program interface{}, x int, y int) 14 | SetRemotePort(side cgra.Side, port sim.RemotePort) 15 | GetMemory(x int, y int, addr uint32) uint32 16 | WriteMemory(x int, y int, data uint32, baseAddr uint32) 17 | GetTileX() int 18 | GetTileY() int 19 | GetRetVal() uint32 20 | GetTickingComponent() sim.Component 21 | } 22 | 23 | type tile struct { 24 | Core tileCore 25 | SharedMemoryController *idealmemcontroller.Comp 26 | } 27 | 28 | func (t tile) GetTickingComponent() sim.Component { 29 | return t.Core.GetTickingComponent() 30 | } 31 | 32 | // GetPort returns the of the tile by the side. 33 | func (t tile) GetPort(side cgra.Side) sim.Port { 34 | switch side { 35 | case cgra.North: 36 | return t.Core.GetPortByName("North") 37 | case cgra.West: 38 | return t.Core.GetPortByName("West") 39 | case cgra.South: 40 | return t.Core.GetPortByName("South") 41 | case cgra.East: 42 | return t.Core.GetPortByName("East") 43 | case cgra.NorthEast: 44 | return t.Core.GetPortByName("NorthEast") 45 | case cgra.SouthEast: 46 | return t.Core.GetPortByName("SouthEast") 47 | case cgra.SouthWest: 48 | return t.Core.GetPortByName("SouthWest") 49 | case cgra.NorthWest: 50 | return t.Core.GetPortByName("NorthWest") 51 | case cgra.Router: 52 | return t.Core.GetPortByName("Router") 53 | default: 54 | panic("invalid side") 55 | } 56 | } 57 | 58 | func (t tile) GetTileX() int { 59 | return t.Core.GetTileX() 60 | } 61 | 62 | func (t tile) GetTileY() int { 63 | return t.Core.GetTileY() 64 | } 65 | func (t tile) String() string { 66 | return fmt.Sprintf("Tile(%d, %d)", t.Core.GetTileX(), t.Core.GetTileY()) 67 | } 68 | 69 | // getMemory returns the memory of the tile. 70 | func (t tile) GetMemory(x int, y int, addr uint32) uint32 { 71 | return t.Core.GetMemory(x, y, addr) 72 | } 73 | 74 | // writeMemory writes the memory of the tile. 75 | func (t tile) WriteMemory(x int, y int, data uint32, baseAddr uint32) { 76 | t.Core.WriteMemory(x, y, data, baseAddr) 77 | } 78 | 79 | func (t tile) WriteSharedMemory(x int, y int, data []byte, baseAddr uint32) { // x, y is useless here 80 | fmt.Println("WriteSharedMemory(", x, ",", y, ") ", baseAddr, " <- ", data) 81 | err := t.SharedMemoryController.Storage.Write(uint64(baseAddr), data) 82 | if err != nil { 83 | panic(err) 84 | } 85 | } 86 | 87 | // SetRemotePort sets the port that the core can send data to. 88 | func (t tile) SetRemotePort(side cgra.Side, port sim.RemotePort) { 89 | t.Core.SetRemotePort(side, port) 90 | } 91 | 92 | // MapProgram sets the program that the tile needs to run. 93 | func (t tile) MapProgram(program interface{}, x int, y int) { 94 | t.Core.MapProgram(program, x, y) 95 | } 96 | 97 | func (t tile) GetRetVal() uint32 { 98 | return t.Core.GetRetVal() 99 | } 100 | 101 | // A Device is a CGRA device that includes a large number of tiles. Tiles can be 102 | // retrieved using d.Tiles[y][x]. 103 | type device struct { 104 | Name string 105 | Width, Height int 106 | Tiles [][]*tile 107 | SharedMemoryControllers []*idealmemcontroller.Comp 108 | } 109 | 110 | // GetSize returns the width and height of the device. 111 | func (d *device) GetSize() (int, int) { 112 | return d.Width, d.Height 113 | } 114 | 115 | // GetTile returns the tile at the given coordinates. 116 | func (d *device) GetTile(x, y int) cgra.Tile { 117 | return d.Tiles[y][x] 118 | } 119 | 120 | // GetSidePorts returns the ports on the given side of the device. 121 | func (d *device) GetSidePorts( 122 | side cgra.Side, 123 | portRange [2]int, 124 | ) []sim.Port { 125 | ports := make([]sim.Port, 0) 126 | 127 | switch side { 128 | case cgra.North: 129 | for x := portRange[0]; x < portRange[1]; x++ { 130 | ports = append(ports, d.Tiles[d.Height-1][x].GetPort(side)) 131 | } 132 | case cgra.West: 133 | for y := portRange[0]; y < portRange[1]; y++ { 134 | ports = append(ports, d.Tiles[y][0].GetPort(side)) 135 | } 136 | case cgra.South: 137 | for x := portRange[0]; x < portRange[1]; x++ { 138 | ports = append(ports, d.Tiles[0][x].GetPort(side)) 139 | } 140 | case cgra.East: 141 | for y := portRange[0]; y < portRange[1]; y++ { 142 | ports = append(ports, d.Tiles[y][d.Width-1].GetPort(side)) 143 | } 144 | default: 145 | panic("invalid side") 146 | } 147 | 148 | return ports 149 | } 150 | -------------------------------------------------------------------------------- /verify/cmd/verify-axpy/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "log" 6 | 7 | "github.com/sarchlab/zeonica/core" 8 | "github.com/sarchlab/zeonica/verify" 9 | ) 10 | 11 | func main() { 12 | // Load AXPY kernel from YAML 13 | programPath := "test/Zeonica_Testbench/kernel/axpy/axpy.yaml" 14 | programs := core.LoadProgramFileFromYAML(programPath) 15 | 16 | if len(programs) == 0 { 17 | log.Fatalf("Failed to load AXPY program from %s", programPath) 18 | } 19 | 20 | // Create architecture info (AXPY uses 4x4 CGRA) 21 | arch := &verify.ArchInfo{ 22 | Rows: 4, 23 | Columns: 4, 24 | Topology: "mesh", 25 | HopLatency: 1, 26 | MemCapacity: 2048, 27 | CtrlMemItems: 20, 28 | } 29 | 30 | fmt.Println("==============================================================================") 31 | fmt.Println("AXPY KERNEL VERIFICATION") 32 | fmt.Println("==============================================================================") 33 | fmt.Printf("\nLoaded %d PE programs from %s\n\n", len(programs), programPath) 34 | 35 | // ========== LINT CHECK ========== 36 | fmt.Println("==============================================================================") 37 | fmt.Println("STAGE 1: LINT CHECK (Structural & Timing Validation)") 38 | fmt.Println("==============================================================================") 39 | fmt.Println() 40 | 41 | issues := verify.RunLint(programs, arch) 42 | 43 | if len(issues) == 0 { 44 | fmt.Println("✅ LINT PASSED - No structural or timing issues found") 45 | fmt.Println() 46 | } else { 47 | fmt.Printf("❌ LINT FAILED - Found %d issues:\n\n", len(issues)) 48 | for i, issue := range issues { 49 | fmt.Printf("Issue %d:\n", i+1) 50 | fmt.Printf(" Type: %s\n", issue.Type) 51 | fmt.Printf(" Location: PE(%d, %d) t=%d op=%d\n", issue.PEX, issue.PEY, issue.Time, issue.OpID) 52 | fmt.Printf(" Message: %s\n", issue.Message) 53 | if issue.Details != nil { 54 | fmt.Printf(" Details: %v\n", issue.Details) 55 | } 56 | fmt.Println() 57 | } 58 | } 59 | 60 | // ========== FUNCTIONAL SIMULATOR ========== 61 | fmt.Println("==============================================================================") 62 | fmt.Println("STAGE 2: FUNCTIONAL SIMULATOR (Dataflow Verification)") 63 | fmt.Println("==============================================================================") 64 | fmt.Println() 65 | 66 | fs := verify.NewFunctionalSimulator(programs, arch) 67 | if fs == nil { 68 | log.Fatalf("Failed to create FunctionalSimulator") 69 | } 70 | 71 | // Preload test data into memory if needed 72 | // (AXPY might need input data) 73 | // fs.PreloadMemory(x, y, value, address) 74 | 75 | // Run simulator for reasonable number of steps 76 | err := fs.Run(1000) 77 | if err != nil { 78 | log.Fatalf("Simulation failed: %v", err) 79 | } 80 | 81 | fmt.Println("✅ FUNCTIONAL SIMULATOR PASSED - Execution completed successfully") 82 | fmt.Println() 83 | 84 | // Display simulation results 85 | fmt.Println("------------------------------------------------------------------------------") 86 | fmt.Println("Simulation Results by PE:") 87 | fmt.Println("------------------------------------------------------------------------------") 88 | fmt.Println() 89 | 90 | for y := 0; y < arch.Rows; y++ { 91 | for x := 0; x < arch.Columns; x++ { 92 | coord := fmt.Sprintf("(%d, %d)", x, y) 93 | 94 | // Try to get some register values 95 | hasValues := false 96 | for regIdx := 0; regIdx < 4; regIdx++ { 97 | val := fs.GetRegisterValue(x, y, regIdx) 98 | if val != 0 { 99 | if !hasValues { 100 | fmt.Printf("PE %s:\n", coord) 101 | hasValues = true 102 | } 103 | fmt.Printf(" $%-2d = %d\n", regIdx, val) 104 | } 105 | } 106 | } 107 | } 108 | 109 | // ========== SUMMARY ========== 110 | fmt.Println() 111 | fmt.Println("==============================================================================") 112 | fmt.Println("VERIFICATION SUMMARY") 113 | fmt.Println("==============================================================================") 114 | fmt.Println() 115 | 116 | if len(issues) == 0 { 117 | fmt.Println("✅ Lint Check: PASSED") 118 | } else { 119 | fmt.Printf("❌ Lint Check: FAILED (%d issues)\n", len(issues)) 120 | } 121 | 122 | fmt.Println("✅ Functional Sim: PASSED") 123 | fmt.Println() 124 | fmt.Println("==============================================================================") 125 | fmt.Println() 126 | 127 | // Exit with error code if lint failed 128 | if len(issues) > 0 { 129 | log.Fatalf("AXPY verification failed with %d lint issues", len(issues)) 130 | } 131 | } 132 | -------------------------------------------------------------------------------- /core/util.go: -------------------------------------------------------------------------------- 1 | package core 2 | 3 | import ( 4 | "context" 5 | "fmt" 6 | "log/slog" 7 | 8 | "github.com/jedib0t/go-pretty/v6/table" 9 | ) 10 | 11 | const ( 12 | PrintToggle = false 13 | LevelTrace slog.Level = slog.LevelInfo + 1 14 | ) 15 | 16 | func Trace(msg string, args ...any) { 17 | slog.Log(context.Background(), LevelTrace, msg, args...) 18 | } 19 | 20 | func PrintState(state *coreState) { 21 | if !PrintToggle { 22 | return 23 | } 24 | fmt.Printf("==============State@(%d, %d)==============\n", state.TileX, state.TileY) 25 | 26 | // Create register table 27 | regTable := table.NewWriter() 28 | regTable.SetTitle("Registers (32 registers in 4 rows)") 29 | 30 | // Add table header 31 | regTable.AppendHeader(table.Row{"Row", "R0-R7", "R8-R15", "R16-R23", "R24-R31"}) 32 | 33 | // Add 4 rows of register data 34 | for row := 0; row < 4; row++ { 35 | regRow := make([]interface{}, 5) 36 | regRow[0] = fmt.Sprintf("Row%d", row) 37 | for col := 0; col < 4; col++ { 38 | startReg := row*8 + col*8 39 | regValues := "" 40 | for i := 0; i < 8; i++ { 41 | if i > 0 { 42 | regValues += " " 43 | } 44 | regValues += fmt.Sprintf("%d", int32(state.Registers[startReg+i].First())) 45 | } 46 | regRow[col+1] = regValues 47 | } 48 | regTable.AppendRow(regRow) 49 | } 50 | 51 | fmt.Println(regTable.Render()) 52 | fmt.Println() 53 | 54 | // Create buffer table 55 | bufTable := table.NewWriter() 56 | bufTable.SetTitle("Buffer Status") 57 | 58 | // Direction names 59 | directions := []string{"N", "E", "S", "W", "NE", "NW", "SE", "SW", "R", "D1", "D2", "D3"} 60 | 61 | // Add table header 62 | header := []interface{}{"Buffer Type"} 63 | for _, dir := range directions { 64 | header = append(header, dir) 65 | } 66 | bufTable.AppendHeader(header) 67 | 68 | // RecvBufHead (red data) 69 | recvRedRow := []interface{}{"RecvBufHead[Red]"} 70 | for i := 0; i < 12; i++ { 71 | recvRedRow = append(recvRedRow, int32(state.RecvBufHead[0][i].First())) 72 | } 73 | bufTable.AppendRow(recvRedRow) 74 | 75 | // RecvBufHead (yellow data) 76 | recvYellowRow := []interface{}{"RecvBufHead[Yellow]"} 77 | for i := 0; i < 12; i++ { 78 | recvYellowRow = append(recvYellowRow, int32(state.RecvBufHead[1][i].First())) 79 | } 80 | bufTable.AppendRow(recvYellowRow) 81 | 82 | // RecvBufHead (blue data) 83 | recvBlueRow := []interface{}{"RecvBufHead[Blue]"} 84 | for i := 0; i < 12; i++ { 85 | recvBlueRow = append(recvBlueRow, int32(state.RecvBufHead[2][i].First())) 86 | } 87 | bufTable.AppendRow(recvBlueRow) 88 | 89 | // RecvBufHeadReady (red data) 90 | recvRedReadyRow := []interface{}{"RecvBufHeadReady[Red]"} 91 | for i := 0; i < 12; i++ { 92 | recvRedReadyRow = append(recvRedReadyRow, state.RecvBufHeadReady[0][i]) 93 | } 94 | bufTable.AppendRow(recvRedReadyRow) 95 | 96 | // RecvBufHeadReady (yellow data) 97 | recvYellowReadyRow := []interface{}{"RecvBufHeadReady[Yellow]"} 98 | for i := 0; i < 12; i++ { 99 | recvYellowReadyRow = append(recvYellowReadyRow, state.RecvBufHeadReady[1][i]) 100 | } 101 | bufTable.AppendRow(recvYellowReadyRow) 102 | 103 | // RecvBufHeadReady (blue data) 104 | recvBlueReadyRow := []interface{}{"RecvBufHeadReady[Blue]"} 105 | for i := 0; i < 12; i++ { 106 | recvBlueReadyRow = append(recvBlueReadyRow, state.RecvBufHeadReady[2][i]) 107 | } 108 | bufTable.AppendRow(recvBlueReadyRow) 109 | 110 | // SendBufHead (red data) 111 | sendRedRow := []interface{}{"SendBufHead[Red]"} 112 | for i := 0; i < 12; i++ { 113 | sendRedRow = append(sendRedRow, int32(state.SendBufHead[0][i].First())) 114 | } 115 | bufTable.AppendRow(sendRedRow) 116 | 117 | // SendBufHead (yellow data) 118 | sendYellowRow := []interface{}{"SendBufHead[Yellow]"} 119 | for i := 0; i < 12; i++ { 120 | sendYellowRow = append(sendYellowRow, int32(state.SendBufHead[1][i].First())) 121 | } 122 | bufTable.AppendRow(sendYellowRow) 123 | 124 | // SendBufHead (blue data) 125 | sendBlueRow := []interface{}{"SendBufHead[Blue]"} 126 | for i := 0; i < 12; i++ { 127 | sendBlueRow = append(sendBlueRow, int32(state.SendBufHead[2][i].First())) 128 | } 129 | bufTable.AppendRow(sendBlueRow) 130 | 131 | // SendBufHeadBusy (red data) 132 | sendRedBusyRow := []interface{}{"SendBufHeadBusy[Red]"} 133 | for i := 0; i < 12; i++ { 134 | sendRedBusyRow = append(sendRedBusyRow, state.SendBufHeadBusy[0][i]) 135 | } 136 | bufTable.AppendRow(sendRedBusyRow) 137 | 138 | // SendBufHeadBusy (yellow data) 139 | sendYellowBusyRow := []interface{}{"SendBufHeadBusy[Yellow]"} 140 | for i := 0; i < 12; i++ { 141 | sendYellowBusyRow = append(sendYellowBusyRow, state.SendBufHeadBusy[1][i]) 142 | } 143 | bufTable.AppendRow(sendYellowBusyRow) 144 | 145 | // SendBufHeadBusy (blue data) 146 | sendBlueBusyRow := []interface{}{"SendBufHeadBusy[Blue]"} 147 | for i := 0; i < 12; i++ { 148 | sendBlueBusyRow = append(sendBlueBusyRow, state.SendBufHeadBusy[2][i]) 149 | } 150 | bufTable.AppendRow(sendBlueBusyRow) 151 | 152 | fmt.Println(bufTable.Render()) 153 | fmt.Println("================================================") 154 | } 155 | 156 | func LogState(state *coreState) { 157 | slog.Debug("StateCheckpoint", 158 | "X", state.TileX, "Y", state.TileY, 159 | "PCInBlock", state.PCInBlock, 160 | "SelectedBlock", state.SelectedBlock, 161 | "Registers", state.Registers, 162 | "States", state.States, 163 | "RecvBufHead", state.RecvBufHead, 164 | "RecvBufHeadReady", state.RecvBufHeadReady, 165 | "SendBufHead", state.SendBufHead, 166 | "SendBufHeadBusy", state.SendBufHeadBusy, 167 | ) 168 | } 169 | -------------------------------------------------------------------------------- /verify/histogram_integration_test.go: -------------------------------------------------------------------------------- 1 | package verify 2 | 3 | import ( 4 | "testing" 5 | 6 | "github.com/sarchlab/zeonica/core" 7 | ) 8 | 9 | // TestHistogramLint tests lint checking on the actual histogram kernel 10 | func TestHistogramLint(t *testing.T) { 11 | // Create ArchInfo matching histogram arch_spec.yaml: 12 | // - main CGRA: 4x4 mesh 13 | // - 128 registers per PE 14 | // - 2048 memory capacity per PE 15 | // - 20 control memory items 16 | arch := &ArchInfo{ 17 | Rows: 4, 18 | Columns: 4, 19 | Topology: "mesh", 20 | HopLatency: 1, 21 | MemCapacity: 2048, 22 | CtrlMemItems: 20, 23 | } 24 | 25 | // Load histogram program from YAML 26 | programs := core.LoadProgramFileFromYAML("../test/Zeonica_Testbench/kernel/histogram/histogram.yaml") 27 | 28 | if len(programs) == 0 { 29 | t.Skip("Histogram YAML not found; skipping integration test") 30 | } 31 | 32 | // Run lint checks 33 | issues := RunLint(programs, arch) 34 | 35 | // Report any issues found 36 | if len(issues) > 0 { 37 | t.Logf("Lint found %d issues:\n", len(issues)) 38 | for _, issue := range issues { 39 | t.Logf(" [%s] at PE (%d, %d) t=%d op=%d: %s\n", 40 | issue.Type, issue.PEX, issue.PEY, issue.Time, issue.OpID, issue.Message) 41 | if issue.Details != nil { 42 | for k, v := range issue.Details { 43 | t.Logf(" %s: %v\n", k, v) 44 | } 45 | } 46 | } 47 | // Don't fail for now - just report findings 48 | } 49 | 50 | // Verify lint found the expected number of structures (rough check) 51 | t.Logf("Total PEs with programs: %d\n", len(programs)) 52 | for coord := range programs { 53 | t.Logf(" Program at: %s\n", coord) 54 | } 55 | } 56 | 57 | // TestHistogramFunctionalSim tests functional simulation on histogram kernel 58 | func TestHistogramFunctionalSim(t *testing.T) { 59 | arch := &ArchInfo{ 60 | Rows: 4, 61 | Columns: 4, 62 | Topology: "mesh", 63 | HopLatency: 1, 64 | MemCapacity: 2048, 65 | CtrlMemItems: 20, 66 | } 67 | 68 | // Load histogram program 69 | programs := core.LoadProgramFileFromYAML("../test/Zeonica_Testbench/kernel/histogram/histogram.yaml") 70 | 71 | if len(programs) == 0 { 72 | t.Skip("Histogram YAML not found; skipping integration test") 73 | } 74 | 75 | // Create functional simulator 76 | fs := NewFunctionalSimulator(programs, arch) 77 | if fs == nil { 78 | t.Fatal("Failed to create FunctionalSimulator") 79 | } 80 | 81 | // Preload some test data into memory 82 | // Based on histogram.yaml: Core (0,2) does LOAD at timestep 10 83 | // This simulates data available in memory for loading 84 | fs.PreloadMemory(0, 2, 42, 0) 85 | fs.PreloadMemory(0, 2, 100, 1) 86 | fs.PreloadMemory(0, 2, 200, 2) 87 | fs.PreloadMemory(2, 1, 10, 0) 88 | fs.PreloadMemory(2, 1, 20, 1) 89 | fs.PreloadMemory(2, 1, 30, 2) 90 | 91 | // Run simulation for enough timesteps to cover histogram operations 92 | // histogram has operations up to t=12 in the visible spec 93 | err := fs.Run(100) 94 | if err != nil { 95 | t.Fatalf("Simulation failed: %v", err) 96 | } 97 | 98 | // Validate that certain operations were executed 99 | // Core (1,2) at t=11 does ADD: $0 = WEST + #1 100 | // After ADD, $0 should contain some computed value 101 | // (depends on data flow from (0,2)) 102 | 103 | t.Logf("✓ Histogram functional simulation completed without errors\n") 104 | 105 | // Print some register values for inspection 106 | val := fs.GetRegisterValue(1, 2, 0) 107 | t.Logf(" Core (1,2) register $0 = %d\n", val) 108 | 109 | val = fs.GetRegisterValue(0, 2, 0) 110 | t.Logf(" Core (0,2) register $0 = %d\n", val) 111 | } 112 | 113 | // TestHistogramBothModesComparison runs both lint and sim for comprehensive check 114 | func TestHistogramBothModesComparison(t *testing.T) { 115 | arch := &ArchInfo{ 116 | Rows: 4, 117 | Columns: 4, 118 | Topology: "mesh", 119 | HopLatency: 1, 120 | MemCapacity: 2048, 121 | CtrlMemItems: 20, 122 | } 123 | 124 | programs := core.LoadProgramFileFromYAML("../test/Zeonica_Testbench/kernel/histogram/histogram.yaml") 125 | 126 | if len(programs) == 0 { 127 | t.Skip("Histogram YAML not found; skipping integration test") 128 | } 129 | 130 | // Stage 1: Lint 131 | t.Log("Stage 1: Running lint checks...") 132 | lintIssues := RunLint(programs, arch) 133 | t.Logf(" Lint check complete: %d issues found\n", len(lintIssues)) 134 | 135 | structIssues := 0 136 | timingIssues := 0 137 | for _, issue := range lintIssues { 138 | if issue.Type == IssueStruct { 139 | structIssues++ 140 | } else if issue.Type == IssueTiming { 141 | timingIssues++ 142 | } 143 | } 144 | t.Logf(" - STRUCT issues: %d\n", structIssues) 145 | t.Logf(" - TIMING issues: %d\n", timingIssues) 146 | 147 | // Stage 2: Functional Simulation 148 | t.Log("Stage 2: Running functional simulator...") 149 | fs := NewFunctionalSimulator(programs, arch) 150 | 151 | // Preload memory for LOAD operations 152 | fs.PreloadMemory(0, 2, 42, 0) 153 | fs.PreloadMemory(2, 1, 10, 0) 154 | 155 | err := fs.Run(100) 156 | if err != nil { 157 | t.Logf(" Simulation error (may be expected): %v\n", err) 158 | } else { 159 | t.Log(" Functional simulation complete: OK") 160 | } 161 | 162 | // Summary 163 | t.Logf("\nHistogram Verification Summary:\n") 164 | t.Logf(" Programs loaded: %d PEs\n", len(programs)) 165 | t.Logf(" Lint result: %d issues (STRUCT: %d, TIMING: %d)\n", 166 | len(lintIssues), structIssues, timingIssues) 167 | t.Logf(" Simulation result: %s\n", func() string { 168 | if err != nil { 169 | return "ERROR: " + err.Error() 170 | } 171 | return "SUCCESS" 172 | }()) 173 | } 174 | -------------------------------------------------------------------------------- /verify/report.go: -------------------------------------------------------------------------------- 1 | package verify 2 | 3 | import ( 4 | "fmt" 5 | "io" 6 | "os" 7 | "strings" 8 | 9 | "github.com/sarchlab/zeonica/core" 10 | ) 11 | 12 | // VerificationReport represents a complete verification report 13 | type VerificationReport struct { 14 | ProgramCount int 15 | LintIssues []Issue 16 | StructIssues []Issue 17 | TimingIssues []Issue 18 | SimulationErr error 19 | SimulationOK bool 20 | Arch *ArchInfo 21 | Programs map[string]core.Program 22 | } 23 | 24 | // GenerateReport runs both lint and functional simulation, returns a report 25 | func GenerateReport(programs map[string]core.Program, arch *ArchInfo, maxSimSteps int) *VerificationReport { 26 | report := &VerificationReport{ 27 | ProgramCount: len(programs), 28 | Arch: arch, 29 | Programs: programs, 30 | } 31 | 32 | // Run lint 33 | report.LintIssues = RunLint(programs, arch) 34 | 35 | // Categorize issues 36 | for _, issue := range report.LintIssues { 37 | if issue.Type == IssueStruct { 38 | report.StructIssues = append(report.StructIssues, issue) 39 | } else { 40 | report.TimingIssues = append(report.TimingIssues, issue) 41 | } 42 | } 43 | 44 | // Run functional simulation 45 | fs := NewFunctionalSimulator(programs, arch) 46 | report.SimulationErr = fs.Run(maxSimSteps) 47 | report.SimulationOK = report.SimulationErr == nil 48 | 49 | return report 50 | } 51 | 52 | // WriteReport writes a formatted report to a writer 53 | func (r *VerificationReport) WriteReport(w io.Writer) { 54 | separator := strings.Repeat("=", 60) 55 | dash := strings.Repeat("-", 60) 56 | 57 | fmt.Fprintln(w, separator) 58 | fmt.Fprintln(w, "HISTOGRAM KERNEL VERIFICATION REPORT") 59 | fmt.Fprintln(w, separator) 60 | 61 | fmt.Fprintf(w, "\n✓ Loaded programs for %d PEs\n", r.ProgramCount) 62 | for coord := range r.Programs { 63 | fmt.Fprintf(w, " - %s\n", coord) 64 | } 65 | 66 | // STAGE 1: LINT 67 | fmt.Fprintln(w, "\n"+separator) 68 | fmt.Fprintln(w, "STAGE 1: STATIC LINT CHECKS") 69 | fmt.Fprintln(w, separator) 70 | 71 | if len(r.LintIssues) == 0 { 72 | fmt.Fprintln(w, "✓ No lint issues found!") 73 | } else { 74 | fmt.Fprintf(w, "⚠ Found %d lint issues:\n\n", len(r.LintIssues)) 75 | 76 | if len(r.StructIssues) > 0 { 77 | fmt.Fprintf(w, "\nSTRUCT ISSUES (%d):\n", len(r.StructIssues)) 78 | fmt.Fprintln(w, dash) 79 | for _, issue := range r.StructIssues { 80 | fmt.Fprintf(w, " [PE(%d,%d) t=%d op=%d] %s\n", 81 | issue.PEX, issue.PEY, issue.Time, issue.OpID, issue.Message) 82 | } 83 | } 84 | 85 | if len(r.TimingIssues) > 0 { 86 | fmt.Fprintf(w, "\nTIMING ISSUES (%d):\n", len(r.TimingIssues)) 87 | fmt.Fprintln(w, dash) 88 | for i, issue := range r.TimingIssues { 89 | fmt.Fprintf(w, " Issue %d: [PE(%d,%d) t=%d op=%d]\n", 90 | i+1, issue.PEX, issue.PEY, issue.Time, issue.OpID) 91 | fmt.Fprintf(w, " Message: %s\n", issue.Message) 92 | if issue.Details != nil { 93 | if producer_t, ok := issue.Details["producer_t"]; ok { 94 | fmt.Fprintf(w, " Producer writes at t=%v\n", producer_t) 95 | } 96 | if consumer_t, ok := issue.Details["consumer_t"]; ok { 97 | fmt.Fprintf(w, " Consumer reads at t=%v\n", consumer_t) 98 | } 99 | if required_lat, ok := issue.Details["required_latency"]; ok { 100 | fmt.Fprintf(w, " Required latency: %v cycles\n", required_lat) 101 | } 102 | if actual_lat, ok := issue.Details["actual_latency"]; ok { 103 | fmt.Fprintf(w, " Actual latency: %v cycles\n", actual_lat) 104 | } 105 | } 106 | fmt.Fprintln(w) 107 | } 108 | } 109 | } 110 | 111 | // STAGE 2: FUNCTIONAL SIMULATION 112 | fmt.Fprintln(w, "\n"+separator) 113 | fmt.Fprintln(w, "STAGE 2: FUNCTIONAL SIMULATION") 114 | fmt.Fprintln(w, separator) 115 | 116 | if r.SimulationOK { 117 | fmt.Fprintln(w, "✓ Simulation completed successfully") 118 | } else { 119 | fmt.Fprintf(w, "⚠ Simulation error: %v\n", r.SimulationErr) 120 | } 121 | 122 | // STAGE 3: SUMMARY 123 | fmt.Fprintln(w, "\n"+separator) 124 | fmt.Fprintln(w, "VERIFICATION SUMMARY") 125 | fmt.Fprintln(w, separator) 126 | 127 | fmt.Fprintf(w, "Program Structure: %d PEs deployed\n", r.ProgramCount) 128 | fmt.Fprintf(w, "Lint Result: %d issues detected (%d STRUCT, %d TIMING)\n", 129 | len(r.LintIssues), len(r.StructIssues), len(r.TimingIssues)) 130 | simStatus := "SUCCESS" 131 | if !r.SimulationOK { 132 | simStatus = "FAILED: " + r.SimulationErr.Error() 133 | } 134 | fmt.Fprintf(w, "Simulation Result: %s\n", simStatus) 135 | 136 | fmt.Fprintln(w, "\n"+separator) 137 | fmt.Fprintln(w, "RECOMMENDATION") 138 | fmt.Fprintln(w, separator) 139 | 140 | if len(r.TimingIssues) > 0 { 141 | fmt.Fprintln(w, "⚠ TIMING VIOLATIONS DETECTED") 142 | fmt.Fprintln(w, "The histogram kernel has cross-PE communication constraints") 143 | fmt.Fprintln(w, "that are not satisfied. Consider:") 144 | fmt.Fprintln(w, " 1. Adjusting operation timesteps to allow latency") 145 | fmt.Fprintln(w, " 2. Modifying the scheduling to respect network delays") 146 | fmt.Fprintln(w, " 3. Using buffering or pipelining strategies") 147 | } else { 148 | fmt.Fprintln(w, "✓ KERNEL PASSED ALL CHECKS") 149 | fmt.Fprintln(w, "The histogram kernel is ready for simulation.") 150 | } 151 | 152 | fmt.Fprintln(w) 153 | } 154 | 155 | // SaveReportToFile saves the report to a file and returns the filename 156 | func (r *VerificationReport) SaveReportToFile(filename string) error { 157 | file, err := os.Create(filename) 158 | if err != nil { 159 | return fmt.Errorf("failed to create report file: %w", err) 160 | } 161 | defer file.Close() 162 | 163 | r.WriteReport(file) 164 | return nil 165 | } 166 | -------------------------------------------------------------------------------- /core/program_asm_test.go: -------------------------------------------------------------------------------- 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 | } 237 | -------------------------------------------------------------------------------- /verify/verify_test.go: -------------------------------------------------------------------------------- 1 | package verify 2 | 3 | import ( 4 | "testing" 5 | 6 | "github.com/sarchlab/zeonica/core" 7 | ) 8 | 9 | // TestRunLintBasic validates the lint checks work on a simple program 10 | func TestRunLintBasic(t *testing.T) { 11 | // Create a minimal ArchInfo 12 | arch := &ArchInfo{ 13 | Rows: 4, 14 | Columns: 4, 15 | Topology: "mesh", 16 | HopLatency: 1, 17 | MemCapacity: 1024, 18 | CtrlMemItems: 256, 19 | } 20 | 21 | // Create a simple valid program at (0,0) 22 | prog := core.Program{ 23 | EntryBlocks: []core.EntryBlock{ 24 | { 25 | InstructionGroups: []core.InstructionGroup{ 26 | { 27 | Operations: []core.Operation{ 28 | { 29 | OpCode: "MOV", 30 | SrcOperands: core.OperandList{ 31 | Operands: []core.Operand{ 32 | {Impl: "#5"}, // Immediate 33 | }, 34 | }, 35 | DstOperands: core.OperandList{ 36 | Operands: []core.Operand{ 37 | {Impl: "$0"}, // Register 38 | }, 39 | }, 40 | }, 41 | }, 42 | }, 43 | }, 44 | }, 45 | }, 46 | } 47 | 48 | programs := map[string]core.Program{ 49 | "(0, 0)": prog, 50 | } 51 | 52 | issues := RunLint(programs, arch) 53 | if len(issues) > 0 { 54 | t.Errorf("Expected no lint issues for valid program, got %d", len(issues)) 55 | for _, issue := range issues { 56 | t.Logf(" Issue: %s at (%d, %d): %s", issue.Type, issue.PEX, issue.PEY, issue.Message) 57 | } 58 | } 59 | } 60 | 61 | // TestRunLintInvalidCoordinate validates detection of out-of-bounds coordinates 62 | func TestRunLintInvalidCoordinate(t *testing.T) { 63 | arch := &ArchInfo{ 64 | Rows: 2, 65 | Columns: 2, 66 | Topology: "mesh", 67 | HopLatency: 1, 68 | MemCapacity: 1024, 69 | CtrlMemItems: 256, 70 | } 71 | 72 | prog := core.Program{ 73 | EntryBlocks: []core.EntryBlock{ 74 | { 75 | InstructionGroups: []core.InstructionGroup{ 76 | { 77 | Operations: []core.Operation{ 78 | { 79 | OpCode: "NOP", 80 | SrcOperands: core.OperandList{Operands: []core.Operand{}}, 81 | DstOperands: core.OperandList{Operands: []core.Operand{}}, 82 | }, 83 | }, 84 | }, 85 | }, 86 | }, 87 | }, 88 | } 89 | 90 | programs := map[string]core.Program{ 91 | "(5, 5)": prog, // Out of bounds 92 | } 93 | 94 | issues := RunLint(programs, arch) 95 | found := false 96 | for _, issue := range issues { 97 | if issue.Type == IssueStruct { 98 | found = true 99 | break 100 | } 101 | } 102 | if !found { 103 | t.Error("Expected STRUCT issue for out-of-bounds coordinate") 104 | } 105 | } 106 | 107 | // TestFunctionalSimulatorBasic tests basic operation execution 108 | func TestFunctionalSimulatorBasic(t *testing.T) { 109 | arch := &ArchInfo{ 110 | Rows: 2, 111 | Columns: 2, 112 | Topology: "mesh", 113 | HopLatency: 1, 114 | MemCapacity: 1024, 115 | CtrlMemItems: 256, 116 | } 117 | 118 | // Create a program with MOV and ADD 119 | prog := core.Program{ 120 | EntryBlocks: []core.EntryBlock{ 121 | { 122 | InstructionGroups: []core.InstructionGroup{ 123 | { 124 | Operations: []core.Operation{ 125 | { 126 | OpCode: "MOV", 127 | SrcOperands: core.OperandList{ 128 | Operands: []core.Operand{{Impl: "#10"}}, 129 | }, 130 | DstOperands: core.OperandList{ 131 | Operands: []core.Operand{{Impl: "$0"}}, 132 | }, 133 | }, 134 | }, 135 | }, 136 | { 137 | Operations: []core.Operation{ 138 | { 139 | OpCode: "ADD", 140 | SrcOperands: core.OperandList{ 141 | Operands: []core.Operand{ 142 | {Impl: "$0"}, 143 | {Impl: "#5"}, 144 | }, 145 | }, 146 | DstOperands: core.OperandList{ 147 | Operands: []core.Operand{{Impl: "$1"}}, 148 | }, 149 | }, 150 | }, 151 | }, 152 | }, 153 | }, 154 | }, 155 | } 156 | 157 | programs := map[string]core.Program{ 158 | "(0, 0)": prog, 159 | } 160 | 161 | fs := NewFunctionalSimulator(programs, arch) 162 | if fs == nil { 163 | t.Fatal("Failed to create FunctionalSimulator") 164 | } 165 | 166 | // Run simulator 167 | err := fs.Run(100) 168 | if err != nil { 169 | t.Fatalf("Simulation failed: %v", err) 170 | } 171 | 172 | // Validate results 173 | val0 := fs.GetRegisterValue(0, 0, 0) 174 | if val0 != 10 { 175 | t.Errorf("Expected $0 = 10, got %d", val0) 176 | } 177 | 178 | val1 := fs.GetRegisterValue(0, 0, 1) 179 | if val1 != 15 { 180 | t.Errorf("Expected $1 = 15, got %d", val1) 181 | } 182 | } 183 | 184 | // TestFunctionalSimulatorMemory tests LOAD and STORE operations 185 | func TestFunctionalSimulatorMemory(t *testing.T) { 186 | arch := &ArchInfo{ 187 | Rows: 1, 188 | Columns: 1, 189 | Topology: "mesh", 190 | HopLatency: 1, 191 | MemCapacity: 1024, 192 | CtrlMemItems: 256, 193 | } 194 | 195 | // Create program with STORE and LOAD 196 | prog := core.Program{ 197 | EntryBlocks: []core.EntryBlock{ 198 | { 199 | InstructionGroups: []core.InstructionGroup{ 200 | { 201 | Operations: []core.Operation{ 202 | { 203 | OpCode: "MOV", 204 | SrcOperands: core.OperandList{ 205 | Operands: []core.Operand{{Impl: "#42"}}, 206 | }, 207 | DstOperands: core.OperandList{ 208 | Operands: []core.Operand{{Impl: "$0"}}, 209 | }, 210 | }, 211 | }, 212 | }, 213 | { 214 | Operations: []core.Operation{ 215 | { 216 | OpCode: "STORE", 217 | SrcOperands: core.OperandList{ 218 | Operands: []core.Operand{ 219 | {Impl: "$0"}, 220 | {Impl: "#0"}, 221 | }, 222 | }, 223 | DstOperands: core.OperandList{Operands: []core.Operand{}}, 224 | }, 225 | }, 226 | }, 227 | { 228 | Operations: []core.Operation{ 229 | { 230 | OpCode: "LOAD", 231 | SrcOperands: core.OperandList{ 232 | Operands: []core.Operand{{Impl: "#0"}}, 233 | }, 234 | DstOperands: core.OperandList{ 235 | Operands: []core.Operand{{Impl: "$1"}}, 236 | }, 237 | }, 238 | }, 239 | }, 240 | }, 241 | }, 242 | }, 243 | } 244 | 245 | programs := map[string]core.Program{ 246 | "(0, 0)": prog, 247 | } 248 | 249 | fs := NewFunctionalSimulator(programs, arch) 250 | if fs == nil { 251 | t.Fatal("Failed to create FunctionalSimulator") 252 | } 253 | 254 | // Run simulator 255 | err := fs.Run(100) 256 | if err != nil { 257 | t.Fatalf("Simulation failed: %v", err) 258 | } 259 | 260 | // Validate: $1 should contain 42 (loaded from memory) 261 | val1 := fs.GetRegisterValue(0, 0, 1) 262 | if val1 != 42 { 263 | t.Errorf("Expected $1 = 42 (from memory), got %d", val1) 264 | } 265 | } 266 | -------------------------------------------------------------------------------- /test/mem/test_all-shared-mem.yaml: -------------------------------------------------------------------------------- 1 | array_config: 2 | rows: 2 3 | columns: 2 4 | cores: 5 | - row: 0 6 | column: 0 7 | core_id: "core_0_0" 8 | entries: 9 | - entry_id: "entry0" 10 | type: "loop" 11 | instructions: 12 | - operations: 13 | - opcode: "MOV" 14 | src_operands: 15 | - operand: "West" 16 | color: "R" 17 | dst_operands: 18 | - operand: "$0" # catch token 19 | color: "R" 20 | - operations: 21 | - opcode: "ST" 22 | src_operands: 23 | - operand: "$1" 24 | color: "R" 25 | - operand: "$0" 26 | color: "R" 27 | dst_operands: 28 | - operand: "Router" 29 | color: "R" 30 | - operations: 31 | - opcode: "STW" 32 | src_operands: 33 | - operand: "Router" 34 | color: "R" 35 | - operations: # update addr 36 | - opcode: "ADD" 37 | src_operands: 38 | - operand: "$1" 39 | color: "R" 40 | - operand: "4" 41 | color: "R" 42 | dst_operands: 43 | - operand: "$1" 44 | color: "R" 45 | - operations: # throw token 46 | - opcode: "MOV" 47 | src_operands: 48 | - operand: "777" 49 | color: "R" 50 | dst_operands: 51 | - operand: "East" 52 | color: "R" 53 | 54 | - row: 1 55 | column: 0 56 | core_id: "core_1_0" 57 | entries: 58 | - entry_id: "entry0" 59 | type: "loop" 60 | instructions: 61 | - operations: # catch token 62 | - opcode: "MOV" 63 | src_operands: 64 | - operand: "East" 65 | color: "R" 66 | dst_operands: 67 | - operand: "$0" 68 | color: "R" 69 | - operations: 70 | - opcode: "LD" 71 | src_operands: 72 | - operand: "$1" 73 | color: "R" 74 | dst_operands: # just for flag check 75 | - operand: "Router" 76 | color: "R" 77 | - operations: # emit to the west edge 78 | - opcode: "LDW" 79 | src_operands: 80 | - operand: "Router" 81 | color: "R" 82 | dst_operands: 83 | - operand: "West" 84 | color: "R" 85 | - operations: 86 | - opcode: "ADD" 87 | src_operands: 88 | - operand: "$1" 89 | color: "R" 90 | - operand: "4" 91 | color: "R" 92 | dst_operands: 93 | - operand: "$1" 94 | color: "R" 95 | 96 | 97 | 98 | - row: 0 99 | column: 1 100 | core_id: "core_0_1" 101 | entries: 102 | - entry_id: "entry0" 103 | type: "loop" 104 | instructions: 105 | - operations: 106 | - opcode: "MOV" 107 | src_operands: 108 | - operand: "West" 109 | color: "R" 110 | dst_operands: 111 | - operand: "$0" 112 | color: "R" 113 | - operations: 114 | - opcode: "LD" 115 | src_operands: 116 | - operand: "$1" 117 | color: "R" 118 | dst_operands: # just for flag check 119 | - operand: "Router" 120 | color: "R" 121 | - operations: 122 | - opcode: "LDW" 123 | src_operands: 124 | - operand: "Router" 125 | color: "R" 126 | dst_operands: 127 | - operand: "East" # emit to the east edge 128 | color: "R" 129 | - operations: 130 | - opcode: "ADD" 131 | src_operands: 132 | - operand: "$1" 133 | color: "R" 134 | - operand: "4" 135 | color: "R" 136 | dst_operands: 137 | - operand: "$1" 138 | color: "R" 139 | - operations: # throw token to 1,1 140 | - opcode: "MOV" 141 | src_operands: 142 | - operand: "$0" 143 | color: "R" 144 | dst_operands: 145 | - operand: "North" 146 | color: "R" 147 | - row: 1 148 | column: 1 149 | core_id: "core_1_1" 150 | entries: 151 | - entry_id: "entry0" 152 | type: "loop" 153 | instructions: 154 | - operations: 155 | - opcode: "MOV" 156 | src_operands: 157 | - operand: "South" 158 | color: "R" 159 | dst_operands: 160 | - operand: "$0" 161 | color: "R" 162 | - operations: 163 | - opcode: "LD" 164 | src_operands: 165 | - operand: "$1" 166 | color: "R" 167 | dst_operands: # just for flag check 168 | - operand: "Router" 169 | color: "R" 170 | - operations: 171 | - opcode: "LDW" 172 | src_operands: 173 | - operand: "Router" 174 | color: "R" 175 | dst_operands: 176 | - operand: "East" # emit to the east edge 177 | color: "R" 178 | - operations: 179 | - opcode: "ADD" 180 | src_operands: 181 | - operand: "$1" 182 | color: "R" 183 | - operand: "4" 184 | color: "R" 185 | dst_operands: 186 | - operand: "$1" 187 | color: "R" 188 | - operations: # throw token to 0,1 189 | - opcode: "MOV" 190 | src_operands: 191 | - operand: "$0" 192 | color: "R" 193 | dst_operands: 194 | - operand: "West" 195 | color: "R" -------------------------------------------------------------------------------- /core/emu_unit_test.go: -------------------------------------------------------------------------------- 1 | package core 2 | 3 | import ( 4 | . "github.com/onsi/ginkgo/v2" 5 | . "github.com/onsi/gomega" 6 | "github.com/sarchlab/zeonica/cgra" 7 | ) 8 | 9 | var _ = Describe("InstEmulator", func() { 10 | var ( 11 | ie instEmulator 12 | s coreState 13 | ) 14 | 15 | BeforeEach(func() { 16 | ie = instEmulator{ 17 | CareFlags: true, 18 | } 19 | exit := false 20 | retVal := uint32(0) 21 | s = coreState{ 22 | exit: &exit, 23 | retVal: &retVal, 24 | PCInBlock: 0, 25 | SelectedBlock: nil, 26 | Directions: map[string]bool{ 27 | "North": true, 28 | "East": true, 29 | "South": true, 30 | "West": true, 31 | }, 32 | TileX: 0, 33 | TileY: 0, 34 | Registers: make([]cgra.Data, 16), 35 | Memory: make([]uint32, 1024), 36 | Code: Program{}, 37 | RecvBufHead: make([][]cgra.Data, 4), 38 | RecvBufHeadReady: make([][]bool, 4), 39 | SendBufHead: make([][]cgra.Data, 4), 40 | SendBufHeadBusy: make([][]bool, 4), 41 | } 42 | }) 43 | 44 | var mul_const_inst = InstructionGroup{ 45 | Operations: []Operation{ 46 | { 47 | OpCode: "MUL", 48 | SrcOperands: OperandList{ 49 | Operands: []Operand{ 50 | {Color: "NULL", Impl: "$0"}, 51 | {Color: "NULL", Impl: "3"}, 52 | }, 53 | }, 54 | DstOperands: OperandList{ 55 | Operands: []Operand{ 56 | {Color: "NULL", Impl: "$1"}, 57 | }, 58 | }, 59 | }, 60 | }, 61 | } 62 | 63 | Context("Arithmetic Instructions", func() { 64 | Describe("MUL_CONST", func() { 65 | It("should multiply register by immediate", func() { 66 | s.Registers[0] = cgra.NewScalar(5) 67 | ie.RunInstructionGroup(mul_const_inst, &s, 0) 68 | Expect(s.Registers[1]).To(Equal(cgra.NewScalar(15))) 69 | Expect(s.PCInBlock).To(Equal(int32(0))) 70 | // in the test, there is no SelectedBlock, so emu will not increase the PCInBlock 71 | }) 72 | 73 | // It("should handle negative values", func() { 74 | // s.Registers[0] = uint32(int32(-5)) 75 | // ie.RunInst("MUL_CONST, $1, $0, 3", &s) 76 | // Expect(int32(s.Registers[1])).To(Equal(int32(-15))) 77 | // }) 78 | }) 79 | 80 | }) 81 | 82 | /* 83 | 84 | Context("Bitwise Instructions", func() { 85 | Describe("LLS", func() { 86 | It("should perform logical left shift", func() { 87 | s.Registers[0] = 0x0000000F // 15 88 | ie.RunInst("LLS, $1, $0, 4", &s) 89 | Expect(s.Registers[1]).To(Equal(uint32(0x000000F0))) 90 | }) 91 | 92 | It("should handle overflow", func() { 93 | s.Registers[0] = 0x80000000 94 | ie.RunInst("LLS, $1, $0, 1", &s) 95 | Expect(s.Registers[1]).To(Equal(uint32(0x00000000))) 96 | }) 97 | }) 98 | 99 | Describe("LRS", func() { 100 | It("should perform logical right shift", func() { 101 | s.Registers[0] = 0xF0000000 102 | ie.RunInst("LRS, $1, $0, 4", &s) 103 | Expect(s.Registers[1]).To(Equal(uint32(0x0F000000))) 104 | }) 105 | }) 106 | 107 | Describe("OR/XOR/AND/NOT", func() { 108 | BeforeEach(func() { 109 | s.Registers[0] = 0x0F0F0F0F 110 | s.Registers[1] = 0x00FF00FF 111 | }) 112 | 113 | It("OR operation", func() { 114 | ie.RunInst("OR, $2, $0, $1", &s) 115 | Expect(s.Registers[2]).To(Equal(uint32(0x0FFF0FFF))) 116 | }) 117 | 118 | It("XOR operation", func() { 119 | ie.RunInst("XOR, $2, $0, $1", &s) 120 | Expect(s.Registers[2]).To(Equal(uint32(0x0FF00FF0))) 121 | }) 122 | 123 | It("AND operation", func() { 124 | ie.RunInst("AND, $2, $0, $1", &s) 125 | Expect(s.Registers[2]).To(Equal(uint32(0x000F000F))) 126 | }) 127 | 128 | It("NOT operation", func() { 129 | ie.RunInst("NOT, $2, $0", &s) 130 | Expect(s.Registers[2]).To(Equal(uint32(0xF0F0F0F0))) 131 | }) 132 | }) 133 | }) 134 | 135 | Context("Memory Instructions", func() { 136 | Describe("LD/ST", func() { 137 | It("should store/load from immediate address", func() { 138 | s.Registers[0] = 0xDEADBEEF 139 | ie.RunInst("ST, $0, 0x100", &s) // Store 140 | ie.RunInst("LD, $1, 0x100", &s) // Load 141 | Expect(s.Registers[1]).To(Equal(uint32(0xDEADBEEF))) 142 | }) 143 | 144 | It("should handle register-based addressing", func() { 145 | s.Registers[0] = 0x100 146 | s.Registers[1] = 0xCAFEBABE 147 | ie.RunInst("ST, $1, $0", &s) // Store at 0x100 148 | ie.RunInst("LD, $2, $0", &s) // Load from 0x100 149 | Expect(s.Registers[2]).To(Equal(uint32(0xCAFEBABE))) 150 | }) 151 | 152 | It("should panic on out-of-bounds access", func() { 153 | Expect(func() { 154 | ie.RunInst("LD, $0, 0xFFFFFFFF", &s) 155 | }).To(Panic()) 156 | }) 157 | }) 158 | }) 159 | 160 | Context("Floating Point Instructions", func() { 161 | Describe("FADD/FSUB/FMUL/FDIV/FINC/FMUL_CONST/FADD_CONST", func() { 162 | It("should perform Floating add operation", func() { 163 | s.Registers[0] = math.Float32bits(3.14) 164 | s.Registers[1] = math.Float32bits(2.71) 165 | ie.RunInst("FADD, $2, $0, $1", &s) 166 | result := math.Float32frombits(s.Registers[2]) 167 | Expect(result).To(BeNumerically("~", 5.85, 1e-6)) 168 | }) 169 | 170 | It("should perform Floating subtraction operation", func() { 171 | s.Registers[0] = math.Float32bits(3.14) 172 | s.Registers[1] = math.Float32bits(2.71) 173 | ie.RunInst("FSUB, $2, $0, $1", &s) 174 | result := math.Float32frombits(s.Registers[2]) 175 | Expect(result).To(BeNumerically("~", 0.43, 1e-6)) 176 | }) 177 | 178 | It("should perform Floating multiplication operation", func() { 179 | s.Registers[0] = math.Float32bits(3.14) 180 | s.Registers[1] = math.Float32bits(2.71) 181 | ie.RunInst("FMUL, $2, $0, $1", &s) 182 | result := math.Float32frombits(s.Registers[2]) 183 | Expect(result).To(BeNumerically("~", 3.14*2.71, 1e-6)) 184 | }) 185 | 186 | It("should perform Floating division operation", func() { 187 | s.Registers[0] = math.Float32bits(3.14) 188 | s.Registers[1] = math.Float32bits(2.71) 189 | ie.RunInst("FDIV, $2, $0, $1", &s) 190 | result := math.Float32frombits(s.Registers[2]) 191 | Expect(result).To(BeNumerically("~", 3.14/2.71, 1e-6)) 192 | }) 193 | 194 | It("should perform Floating increment operation", func() { 195 | s.Registers[0] = math.Float32bits(3.14) 196 | ie.RunInst("FINC, $0", &s) 197 | result := math.Float32frombits(s.Registers[0]) 198 | Expect(result).To(BeNumerically("~", 4.14, 1e-6)) 199 | }) 200 | 201 | It("should perform Floating add const operation", func() { 202 | s.Registers[0] = math.Float32bits(3.14) 203 | ie.RunInst("FADD_CONST, $2, $0, 1.78", &s) 204 | result := math.Float32frombits(s.Registers[2]) 205 | Expect(result).To(BeNumerically("~", 3.14+1.78, 1e-4)) 206 | }) 207 | 208 | It("should perform Floating multiply const operation", func() { 209 | s.Registers[0] = math.Float32bits(3.14) 210 | ie.RunInst("FMUL_CONST, $2, $0, 1.8", &s) 211 | result := math.Float32frombits(s.Registers[2]) 212 | Expect(result).To(BeNumerically("~", 3.14*1.8, 1e-4)) 213 | }) 214 | 215 | 216 | It("should handle special values", func() { 217 | // Test Infinity 218 | s.Registers[0] = math.Float32bits(float32(math.Inf(1))) 219 | s.Registers[1] = math.Float32bits(3.14) 220 | ie.RunInst("FADD, $2, $0, $1", &s) 221 | Expect(math.IsInf(float64(math.Float32frombits(s.Registers[2])), 1)).To(BeTrue()) 222 | 223 | // Test NaN 224 | s.Registers[0] = math.Float32bits(float32(math.NaN())) 225 | ie.RunInst("FADD, $2, $0, $1", &s) 226 | Expect(math.IsNaN(float64(math.Float32frombits(s.Registers[2])))).To(BeTrue()) 227 | }) 228 | }) 229 | }) 230 | */ 231 | }) 232 | -------------------------------------------------------------------------------- /test/cf/cf_test.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "testing" 6 | "unsafe" 7 | 8 | "github.com/sarchlab/akita/v4/sim" 9 | "github.com/sarchlab/zeonica/api" 10 | "github.com/sarchlab/zeonica/cgra" 11 | "github.com/sarchlab/zeonica/config" 12 | "github.com/sarchlab/zeonica/core" 13 | ) 14 | 15 | func TestCmpExOperation(t *testing.T) { 16 | // Set test parameters 17 | width := 2 18 | height := 2 19 | length := 5 20 | 21 | // Create test data 22 | src := make([]uint32, length) 23 | dst := make([]uint32, length) 24 | 25 | // Generate random test data 26 | src = []uint32{1, 2, 9, 9, 0, 0, 3, 5, 6, 7} 27 | 28 | // Create simulation engine 29 | engine := sim.NewSerialEngine() 30 | 31 | // Create driver 32 | driver := api.DriverBuilder{}. 33 | WithEngine(engine). 34 | WithFreq(1 * sim.GHz). 35 | Build("Driver") 36 | 37 | // Create device 38 | device := config.DeviceBuilder{}. 39 | WithEngine(engine). 40 | WithFreq(1 * sim.GHz). 41 | WithWidth(width). 42 | WithHeight(height). 43 | Build("Device") 44 | 45 | driver.RegisterDevice(device) 46 | 47 | // Load program 48 | program := core.LoadProgramFileFromYAML("./test_cmpex.yaml") 49 | if len(program) == 0 { 50 | t.Fatal("Failed to load program") 51 | } 52 | 53 | // Set data flow - input from west, output to east 54 | driver.FeedIn(src, cgra.West, [2]int{0, height}, height, "R") 55 | driver.Collect(dst, cgra.East, [2]int{0, 1}, 1, "R") 56 | 57 | // Map program to all cores 58 | for x := 0; x < width; x++ { 59 | for y := 0; y < height; y++ { 60 | coord := fmt.Sprintf("(%d,%d)", x, y) 61 | if prog, exists := program[coord]; exists { 62 | driver.MapProgram(prog, [2]int{x, y}) 63 | } 64 | } 65 | } 66 | 67 | // Run simulation 68 | driver.Run() 69 | 70 | // Convert results and verify 71 | srcI := make([]int32, length*2) 72 | dstI := make([]int32, length*2) 73 | for i := 0; i < length; i++ { 74 | srcI[i] = *(*int32)(unsafe.Pointer(&src[i])) 75 | dstI[i] = *(*int32)(unsafe.Pointer(&dst[i])) 76 | } 77 | 78 | expected := []int32{0, 1, 1, 0, 0} 79 | // Verify results: output should be input+2 80 | t.Log("=== CmpEx Test Results ===") 81 | allPassed := true 82 | for i := 0; i < length; i++ { 83 | actual := dstI[i] 84 | 85 | if actual != expected[i] { 86 | t.Errorf("Index %d: Input=%d, %d, Expected=%d, Actual=%d", 87 | i, srcI[2*i], srcI[2*i+1], expected[i], actual) 88 | allPassed = false 89 | } else { 90 | t.Logf("Index %d: Input=%d, %d, Output=%d ✓", i, srcI[2*i], srcI[2*i+1], actual) 91 | } 92 | } 93 | 94 | if allPassed { 95 | t.Log("✅ CmpEx tests passed!") 96 | } else { 97 | t.Fatal("❌ CmpEx tests failed!") 98 | } 99 | } 100 | 101 | /* 102 | func TestGpredOperation(t *testing.T) { 103 | 104 | handler := slog.NewJSONHandler(os.Stdout, &slog.HandlerOptions{ 105 | Level: core.LevelTrace, 106 | }) 107 | 108 | slog.SetDefault(slog.New(handler)) 109 | 110 | // 设置测试参数 111 | width := 2 112 | height := 2 113 | length := 10 114 | 115 | // 生成随机测试数据 116 | srcData := []uint32{8, 2, 9, 4, 12, 10, 3, 5, 6, 7} 117 | srcGrant1 := []uint32{1, 0, 1, 1, 0, 1, 1, 0, 1, 1} 118 | srcGrant2 := []uint32{1, 1, 0, 1, 1, 1, 0} 119 | srcMixedGrant := make([]uint32, 17) 120 | 121 | index1 := 0 122 | index2 := 0 123 | 124 | for i := 0; i < 17; i++ { 125 | if i%5 == 0 || i%5 == 2 || i%5 == 3 { 126 | srcMixedGrant[i] = srcGrant1[index1] 127 | index1++ 128 | } else { 129 | srcMixedGrant[i] = srcGrant2[index2] 130 | index2++ 131 | } 132 | } 133 | 134 | dst := make([]uint32, length) 135 | 136 | // 创建模拟引擎 137 | engine := sim.NewSerialEngine() 138 | 139 | // 创建driver 140 | driver := api.DriverBuilder{}. 141 | WithEngine(engine). 142 | WithFreq(1 * sim.GHz). 143 | Build("Driver") 144 | 145 | // 创建设备 146 | device := config.DeviceBuilder{}. 147 | WithEngine(engine). 148 | WithFreq(1 * sim.GHz). 149 | WithWidth(width). 150 | WithHeight(height). 151 | Build("Device") 152 | 153 | driver.RegisterDevice(device) 154 | 155 | // 加载程序 156 | program := core.LoadProgramFileFromYAML("./test_gpred.yaml") 157 | if len(program) == 0 { 158 | t.Fatal("Failed to load program") 159 | } 160 | 161 | // 设置数据流 - 从西边输入,东边输出 162 | driver.FeedIn(srcData, cgra.West, [2]int{0, 1}, 1, "R") 163 | driver.FeedIn(srcMixedGrant, cgra.West, [2]int{1, 2}, 1, "R") 164 | driver.Collect(dst, cgra.East, [2]int{0, 1}, 1, "R") 165 | 166 | // 映射程序到所有core 167 | for x := 0; x < width; x++ { 168 | for y := 0; y < height; y++ { 169 | coord := fmt.Sprintf("(%d,%d)", x, y) 170 | if prog, exists := program[coord]; exists { 171 | driver.MapProgram(prog, [2]int{x, y}) 172 | } 173 | } 174 | } 175 | 176 | // 运行模拟 177 | driver.Run() 178 | 179 | // 转换结果并验证 180 | srcIData := make([]int32, length) 181 | srcIGrant := make([]int32, 17) 182 | dstI := make([]int32, length) 183 | 184 | for i := 0; i < length; i++ { 185 | srcIData[i] = *(*int32)(unsafe.Pointer(&srcData[i])) 186 | } 187 | 188 | for i := 0; i < 17; i++ { 189 | srcIGrant[i] = *(*int32)(unsafe.Pointer(&srcMixedGrant[i])) 190 | } 191 | 192 | expected := []int32{8, 9, 10, 3, 6} 193 | for i := 0; i < 5; i++ { 194 | dstI[i] = *(*int32)(unsafe.Pointer(&dst[i])) 195 | } 196 | 197 | t.Log("=== Gpred Test Results ===") 198 | allPassed := true 199 | for i := 0; i < 5; i++ { 200 | actual := dstI[i] 201 | if actual != expected[i] { 202 | t.Errorf("Index %d:, Expected=%d, Actual=%d", 203 | i, expected[i], actual) 204 | allPassed = false 205 | } 206 | } 207 | 208 | if allPassed { 209 | t.Log("✅ Gpred tests passed!") 210 | } else { 211 | t.Fatal("❌ Gpred tests failed!") 212 | } 213 | } 214 | */ 215 | 216 | func TestPhiOperation(t *testing.T) { 217 | // Set test parameters 218 | width := 2 219 | height := 2 220 | length := 5 221 | 222 | // Generate random test data 223 | srcData := []uint32{5, 5, 5, 5, 5} 224 | dst := make([]uint32, length) 225 | 226 | // Create simulation engine 227 | engine := sim.NewSerialEngine() 228 | 229 | // Create driver 230 | driver := api.DriverBuilder{}. 231 | WithEngine(engine). 232 | WithFreq(1 * sim.GHz). 233 | Build("Driver") 234 | 235 | // Create device 236 | device := config.DeviceBuilder{}. 237 | WithEngine(engine). 238 | WithFreq(1 * sim.GHz). 239 | WithWidth(width). 240 | WithHeight(height). 241 | Build("Device") 242 | 243 | driver.RegisterDevice(device) 244 | 245 | // Load program 246 | program := core.LoadProgramFileFromYAML("./test_phiconst.yaml") 247 | if len(program) == 0 { 248 | t.Fatal("Failed to load program") 249 | } 250 | 251 | // Set data flow - input from west, output to east 252 | driver.FeedIn(srcData, cgra.West, [2]int{0, 1}, 1, "R") 253 | driver.Collect(dst, cgra.West, [2]int{1, 2}, 1, "R") 254 | 255 | // Map program to all cores 256 | for x := 0; x < width; x++ { 257 | for y := 0; y < height; y++ { 258 | coord := fmt.Sprintf("(%d,%d)", x, y) 259 | if prog, exists := program[coord]; exists { 260 | driver.MapProgram(prog, [2]int{x, y}) 261 | } 262 | } 263 | } 264 | 265 | // Run simulation 266 | driver.Run() 267 | 268 | // Convert results and verify 269 | srcIData := make([]int32, length) 270 | dstI := make([]int32, length) 271 | 272 | for i := 0; i < length; i++ { 273 | srcIData[i] = *(*int32)(unsafe.Pointer(&srcData[i])) 274 | } 275 | 276 | expected := []int32{1, 5, 5, 5, 5} 277 | for i := 0; i < 5; i++ { 278 | dstI[i] = *(*int32)(unsafe.Pointer(&dst[i])) 279 | } 280 | 281 | t.Log("=== Phi-Const Test Results ===") 282 | allPassed := true 283 | for i := 0; i < 5; i++ { 284 | actual := dstI[i] 285 | if actual != expected[i] { 286 | t.Errorf("Index %d:, Expected=%d, Actual=%d", 287 | i, expected[i], actual) 288 | allPassed = false 289 | } 290 | } 291 | 292 | if allPassed { 293 | t.Log("✅ Phi-Const tests passed!") 294 | } else { 295 | t.Fatal("❌ Gpred tests failed!") 296 | } 297 | } 298 | -------------------------------------------------------------------------------- /test/mem/test_lwsw-go-a-round.yaml: -------------------------------------------------------------------------------- 1 | array_config: 2 | rows: 2 3 | columns: 2 4 | cores: 5 | - row: 0 6 | column: 0 7 | core_id: "core_0_0" 8 | entries: 9 | - entry_id: "entry0" 10 | type: "loop" 11 | instructions: 12 | - operations: 13 | - opcode: "MOV" 14 | src_operands: 15 | - operand: "West" 16 | color: "R" 17 | dst_operands: 18 | - operand: "$0" 19 | color: "R" 20 | - operations: 21 | - opcode: "ST" 22 | src_operands: 23 | - operand: "$1" 24 | color: "R" 25 | - operand: "$0" 26 | color: "R" 27 | dst_operands: 28 | - operand: "Router" 29 | color: "R" 30 | - operations: 31 | - opcode: "STW" 32 | src_operands: 33 | - operand: "Router" 34 | color: "R" 35 | - operations: 36 | - opcode: "LD" 37 | src_operands: 38 | - operand: "$1" 39 | color: "R" 40 | dst_operands: # just for flag check 41 | - operand: "Router" 42 | color: "R" 43 | - operations: 44 | - opcode: "LDW" 45 | src_operands: 46 | - operand: "Router" 47 | color: "R" 48 | dst_operands: 49 | - operand: "East" 50 | color: "R" 51 | - operations: 52 | - opcode: "ADD" 53 | src_operands: 54 | - operand: "$1" 55 | color: "R" 56 | - operand: "4" 57 | color: "R" 58 | dst_operands: 59 | - operand: "$1" 60 | color: "R" 61 | 62 | 63 | - row: 1 64 | column: 0 65 | core_id: "core_1_0" 66 | entries: 67 | - entry_id: "entry0" 68 | type: "loop" 69 | instructions: 70 | - operations: 71 | - opcode: "MOV" 72 | src_operands: 73 | - operand: "East" 74 | color: "R" 75 | dst_operands: 76 | - operand: "$0" 77 | color: "R" 78 | - operations: 79 | - opcode: "ST" 80 | src_operands: 81 | - operand: "$1" 82 | color: "R" 83 | - operand: "$0" 84 | color: "R" 85 | dst_operands: 86 | - operand: "Router" 87 | color: "R" 88 | - operations: 89 | - opcode: "STW" 90 | src_operands: 91 | - operand: "Router" 92 | color: "R" 93 | - operations: 94 | - opcode: "LD" 95 | src_operands: 96 | - operand: "$1" 97 | color: "R" 98 | dst_operands: # just for flag check 99 | - operand: "Router" 100 | color: "R" 101 | - operations: 102 | - opcode: "LDW" 103 | src_operands: 104 | - operand: "Router" 105 | color: "R" 106 | dst_operands: 107 | - operand: "West" 108 | color: "R" 109 | - operations: 110 | - opcode: "ADD" 111 | src_operands: 112 | - operand: "$1" 113 | color: "R" 114 | - operand: "4" 115 | color: "R" 116 | dst_operands: 117 | - operand: "$1" 118 | color: "R" 119 | 120 | 121 | 122 | - row: 0 123 | column: 1 124 | core_id: "core_0_1" 125 | entries: 126 | - entry_id: "entry0" 127 | type: "loop" 128 | instructions: 129 | - operations: 130 | - opcode: "MOV" 131 | src_operands: 132 | - operand: "West" 133 | color: "R" 134 | dst_operands: 135 | - operand: "$0" 136 | color: "R" 137 | - operations: 138 | - opcode: "ST" 139 | src_operands: 140 | - operand: "$1" 141 | color: "R" 142 | - operand: "$0" 143 | color: "R" 144 | dst_operands: 145 | - operand: "Router" 146 | color: "R" 147 | - operations: 148 | - opcode: "STW" 149 | src_operands: 150 | - operand: "Router" 151 | color: "R" 152 | - operations: 153 | - opcode: "LD" 154 | src_operands: 155 | - operand: "$1" 156 | color: "R" 157 | dst_operands: # just for flag check 158 | - operand: "Router" 159 | color: "R" 160 | - operations: 161 | - opcode: "LDW" 162 | src_operands: 163 | - operand: "Router" 164 | color: "R" 165 | dst_operands: 166 | - operand: "North" 167 | color: "R" 168 | - operations: 169 | - opcode: "ADD" 170 | src_operands: 171 | - operand: "$1" 172 | color: "R" 173 | - operand: "4" 174 | color: "R" 175 | dst_operands: 176 | - operand: "$1" 177 | color: "R" 178 | 179 | - row: 1 180 | column: 1 181 | core_id: "core_1_1" 182 | entries: 183 | - entry_id: "entry0" 184 | type: "loop" 185 | instructions: 186 | - operations: 187 | - opcode: "MOV" 188 | src_operands: 189 | - operand: "South" 190 | color: "R" 191 | dst_operands: 192 | - operand: "$0" 193 | color: "R" 194 | - operations: 195 | - opcode: "ST" 196 | src_operands: 197 | - operand: "$1" 198 | color: "R" 199 | - operand: "$0" 200 | color: "R" 201 | dst_operands: 202 | - operand: "Router" 203 | color: "R" 204 | - operations: 205 | - opcode: "STW" 206 | src_operands: 207 | - operand: "Router" 208 | color: "R" 209 | - operations: 210 | - opcode: "LD" 211 | src_operands: 212 | - operand: "$1" 213 | color: "R" 214 | dst_operands: # just for flag check 215 | - operand: "Router" 216 | color: "R" 217 | - operations: 218 | - opcode: "LDW" 219 | src_operands: 220 | - operand: "Router" 221 | color: "R" 222 | dst_operands: 223 | - operand: "West" 224 | color: "R" 225 | - operations: 226 | - opcode: "ADD" 227 | src_operands: 228 | - operand: "$1" 229 | color: "R" 230 | - operand: "4" 231 | color: "R" 232 | dst_operands: 233 | - operand: "$1" 234 | color: "R" -------------------------------------------------------------------------------- /config/config.go: -------------------------------------------------------------------------------- 1 | // Package config provides a default configuration for the CGRA device. 2 | package config 3 | 4 | import ( 5 | "fmt" 6 | "strconv" 7 | 8 | "github.com/sarchlab/akita/v4/mem/idealmemcontroller" 9 | "github.com/sarchlab/akita/v4/mem/mem" 10 | "github.com/sarchlab/akita/v4/monitoring" 11 | "github.com/sarchlab/akita/v4/sim" 12 | "github.com/sarchlab/akita/v4/sim/directconnection" 13 | "github.com/sarchlab/zeonica/cgra" 14 | "github.com/sarchlab/zeonica/core" 15 | ) 16 | 17 | // DeviceBuilder can build CGRA devices. 18 | type DeviceBuilder struct { 19 | engine sim.Engine 20 | freq sim.Freq 21 | monitor *monitoring.Monitor 22 | //portFactory portFactory 23 | width, height int 24 | memoryMode string // simple or shared or local 25 | memoryShare map[[2]int]int //map[[x, y]]GroupID 26 | } 27 | 28 | // type portFactory interface { 29 | // make(c sim.Component, name string) sim.Port 30 | // } 31 | 32 | // WithEngine sets the engine that drives the device simulation. 33 | func (d DeviceBuilder) WithEngine(engine sim.Engine) DeviceBuilder { 34 | d.engine = engine 35 | return d 36 | } 37 | 38 | // WithFreq sets the frequency of the device. 39 | func (d DeviceBuilder) WithFreq(freq sim.Freq) DeviceBuilder { 40 | d.freq = freq 41 | return d 42 | } 43 | 44 | // WithMonitor sets the monitor that monitors the device. 45 | func (d DeviceBuilder) WithMonitor(monitor *monitoring.Monitor) DeviceBuilder { 46 | d.monitor = monitor 47 | return d 48 | } 49 | 50 | // WithWidth sets the width of CGRA mesh. 51 | func (d DeviceBuilder) WithWidth(width int) DeviceBuilder { 52 | d.width = width 53 | return d 54 | } 55 | 56 | // WithHeight sets the height of CGRA mesh. 57 | func (d DeviceBuilder) WithHeight(height int) DeviceBuilder { 58 | d.height = height 59 | return d 60 | } 61 | 62 | // WithMemoryMode sets the memory mode (simple or shared). 63 | func (d DeviceBuilder) WithMemoryMode(mode string) DeviceBuilder { 64 | if mode != "simple" && mode != "shared" && mode != "local" { 65 | panic("Invalid memory mode: " + mode) 66 | } 67 | d.memoryMode = mode 68 | return d 69 | } 70 | 71 | // WithMemoryShare sets the memory sharing configuration. 72 | func (d DeviceBuilder) WithMemoryShare(share map[[2]int]int) DeviceBuilder { 73 | d.memoryShare = share 74 | return d 75 | } 76 | 77 | // Build creates a CGRA device. 78 | func (d DeviceBuilder) Build(name string) cgra.Device { 79 | dev := &device{ 80 | Name: name, 81 | Width: d.width, 82 | Height: d.height, 83 | Tiles: make([][]*tile, d.height), 84 | } 85 | 86 | d.createTiles(dev, name) 87 | d.connectTiles(dev) 88 | d.createSharedMemory(dev) 89 | 90 | return dev 91 | } 92 | 93 | func (d DeviceBuilder) createSharedMemory(dev *device) { 94 | if d.memoryMode == "shared" { 95 | // Create shared memory controller 96 | 97 | controllers := make(map[int]*idealmemcontroller.Comp) 98 | connections := make(map[int]*directconnection.Comp) 99 | 100 | for x := 0; x < d.width; x++ { 101 | for y := 0; y < d.height; y++ { 102 | tile := dev.Tiles[y][x] 103 | // if has mapping 104 | if _, ok := d.memoryShare[[2]int{x, y}]; !ok { 105 | panic("No mapping for tile " + strconv.Itoa(x) + "," + strconv.Itoa(y)) 106 | } 107 | groupID := d.memoryShare[[2]int{x, y}] 108 | if _, ok := controllers[groupID]; !ok { 109 | // has not been created yet, create it 110 | controller := idealmemcontroller.MakeBuilder(). 111 | WithEngine(d.engine). 112 | WithNewStorage(4 * mem.GB). 113 | WithLatency(5). 114 | Build("SharedMemory") 115 | controllers[groupID] = controller 116 | 117 | name := fmt.Sprintf("SharedMemory%d%d", x, y) 118 | 119 | conn := directconnection.MakeBuilder(). 120 | WithEngine(d.engine). 121 | WithFreq(d.freq). 122 | Build(name) 123 | conn.PlugIn(controller.GetPortByName("Top")) 124 | conn.PlugIn(tile.Core.GetPortByName("Router")) 125 | connections[groupID] = conn 126 | tile.SetRemotePort(cgra.Router, controller.GetPortByName("Top").AsRemote()) 127 | tile.SharedMemoryController = controller 128 | dev.SharedMemoryControllers = append(dev.SharedMemoryControllers, controller) 129 | 130 | fmt.Println("Connect Tile (", x, ",", y, ") to SharedMemory Controller (", groupID, ") (new-created)") 131 | } else { 132 | // plug in the controller to the tile 133 | fmt.Println("Connect Tile (", x, ",", y, ") to SharedMemory Controller (", groupID, ") (already-created)") 134 | connections[groupID].PlugIn(tile.Core.GetPortByName("Router")) 135 | tile.SetRemotePort(cgra.Router, controllers[groupID].GetPortByName("Top").AsRemote()) 136 | tile.SharedMemoryController = controllers[groupID] 137 | dev.SharedMemoryControllers = append(dev.SharedMemoryControllers, controllers[groupID]) 138 | } 139 | } 140 | } 141 | } else if d.memoryMode == "local" { 142 | // create DRAM for each of the tiles 143 | for y := 0; y < d.height; y++ { 144 | for x := 0; x < d.width; x++ { 145 | tile := dev.Tiles[y][x] 146 | drams := idealmemcontroller.MakeBuilder(). 147 | WithEngine(d.engine). 148 | WithNewStorage(4 * mem.GB). 149 | WithLatency(5). 150 | Build("DRAM") 151 | 152 | conn := directconnection.MakeBuilder(). 153 | WithEngine(d.engine). 154 | WithFreq(d.freq). 155 | Build("DRAMConn") 156 | 157 | conn.PlugIn(drams.GetPortByName("Top")) 158 | conn.PlugIn(tile.Core.GetPortByName("Router")) // use router as the memory port 159 | 160 | // set the remote port of the tile to the DRAM port 161 | tile.SetRemotePort(cgra.Router, drams.GetPortByName("Top").AsRemote()) 162 | 163 | tile.SharedMemoryController = drams 164 | dev.SharedMemoryControllers = append(dev.SharedMemoryControllers, drams) 165 | 166 | fmt.Println("Init DRAM for tile", tile.Core.Name(), "at", x, y) 167 | } 168 | } 169 | } 170 | } 171 | 172 | func (d DeviceBuilder) createTiles( 173 | dev *device, 174 | name string, 175 | ) { 176 | var exit = false 177 | var retVal = uint32(0) 178 | for y := 0; y < d.height; y++ { 179 | dev.Tiles[y] = make([]*tile, d.width) 180 | for x := 0; x < d.width; x++ { 181 | tile := &tile{} 182 | coreName := fmt.Sprintf("%s.Tile[%d][%d].Core", name, y, x) 183 | tile.Core = core.Builder{}. 184 | WithEngine(d.engine). 185 | WithFreq(d.freq). 186 | WithExitAddr(&exit). 187 | WithRetValAddr(&retVal). 188 | Build(coreName) 189 | 190 | if d.monitor != nil { 191 | d.monitor.RegisterComponent(tile.Core) 192 | } 193 | 194 | tile.Core.MapProgram(core.Program{}, x, y) 195 | 196 | dev.Tiles[y][x] = tile 197 | } 198 | } 199 | } 200 | 201 | func (d DeviceBuilder) connectTiles(dev *device) { 202 | for y := 0; y < d.height; y++ { 203 | for x := 0; x < d.width; x++ { 204 | currentTile := dev.Tiles[y][x] 205 | // connect to the East tile 206 | if x < d.width-1 { 207 | eastTile := dev.Tiles[y][x+1] 208 | d.connectTilePorts(currentTile, cgra.East, eastTile, cgra.West) 209 | } 210 | // connect to the North tile 211 | if y < d.height-1 { 212 | northTile := dev.Tiles[y+1][x] 213 | d.connectTilePorts(currentTile, cgra.North, northTile, cgra.South) 214 | } 215 | // connect to the North East tile 216 | if y < d.height-1 && x < d.width-1 { 217 | northEastTile := dev.Tiles[y+1][x+1] 218 | d.connectTilePorts(currentTile, cgra.NorthEast, northEastTile, cgra.SouthWest) 219 | } 220 | // connect to the North West tile 221 | if y < d.height-1 && x > 0 { 222 | northWestTile := dev.Tiles[y+1][x-1] 223 | d.connectTilePorts(currentTile, cgra.NorthWest, northWestTile, cgra.SouthEast) 224 | } 225 | } 226 | } 227 | } 228 | 229 | func (d DeviceBuilder) connectTilePorts(srcTile *tile, 230 | srcSide cgra.Side, 231 | dstTile *tile, 232 | dstSide cgra.Side) { 233 | 234 | srcPort := srcTile.GetPort(srcSide) 235 | dstPort := dstTile.GetPort(dstSide) 236 | 237 | connName := fmt.Sprintf("%s.%s.%s.%s", 238 | srcTile.Core.Name(), srcSide.Name(), 239 | dstTile.Core.Name(), dstSide.Name(), 240 | ) 241 | conn := directconnection.MakeBuilder(). 242 | WithEngine(d.engine). 243 | WithFreq(d.freq). 244 | Build(connName) 245 | 246 | conn.PlugIn(srcPort) 247 | conn.PlugIn(dstPort) 248 | 249 | srcTile.SetRemotePort(srcSide, dstPort.AsRemote()) 250 | dstTile.SetRemotePort(dstSide, srcPort.AsRemote()) 251 | } 252 | -------------------------------------------------------------------------------- /api/mock_cgra_test.go: -------------------------------------------------------------------------------- 1 | // Code generated by MockGen. DO NOT EDIT. 2 | // Source: github.com/sarchlab/zeonica/cgra (interfaces: Device,Tile) 3 | 4 | package api 5 | 6 | import ( 7 | reflect "reflect" 8 | 9 | gomock "github.com/golang/mock/gomock" 10 | sim "github.com/sarchlab/akita/v4/sim" 11 | cgra "github.com/sarchlab/zeonica/cgra" 12 | ) 13 | 14 | // MockDevice is a mock of Device interface. 15 | type MockDevice struct { 16 | ctrl *gomock.Controller 17 | recorder *MockDeviceMockRecorder 18 | } 19 | 20 | // MockDeviceMockRecorder is the mock recorder for MockDevice. 21 | type MockDeviceMockRecorder struct { 22 | mock *MockDevice 23 | } 24 | 25 | // NewMockDevice creates a new mock instance. 26 | func NewMockDevice(ctrl *gomock.Controller) *MockDevice { 27 | mock := &MockDevice{ctrl: ctrl} 28 | mock.recorder = &MockDeviceMockRecorder{mock} 29 | return mock 30 | } 31 | 32 | // EXPECT returns an object that allows the caller to indicate expected use. 33 | func (m *MockDevice) EXPECT() *MockDeviceMockRecorder { 34 | return m.recorder 35 | } 36 | 37 | // GetSidePorts mocks base method. 38 | func (m *MockDevice) GetSidePorts(arg0 cgra.Side, arg1 [2]int) []sim.Port { 39 | m.ctrl.T.Helper() 40 | ret := m.ctrl.Call(m, "GetSidePorts", arg0, arg1) 41 | ret0, _ := ret[0].([]sim.Port) 42 | return ret0 43 | } 44 | 45 | // GetSidePorts indicates an expected call of GetSidePorts. 46 | func (mr *MockDeviceMockRecorder) GetSidePorts(arg0, arg1 interface{}) *gomock.Call { 47 | mr.mock.ctrl.T.Helper() 48 | return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetSidePorts", reflect.TypeOf((*MockDevice)(nil).GetSidePorts), arg0, arg1) 49 | } 50 | 51 | // GetSize mocks base method. 52 | func (m *MockDevice) GetSize() (int, int) { 53 | m.ctrl.T.Helper() 54 | ret := m.ctrl.Call(m, "GetSize") 55 | ret0, _ := ret[0].(int) 56 | ret1, _ := ret[1].(int) 57 | return ret0, ret1 58 | } 59 | 60 | // GetSize indicates an expected call of GetSize. 61 | func (mr *MockDeviceMockRecorder) GetSize() *gomock.Call { 62 | mr.mock.ctrl.T.Helper() 63 | return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetSize", reflect.TypeOf((*MockDevice)(nil).GetSize)) 64 | } 65 | 66 | // GetTile mocks base method. 67 | func (m *MockDevice) GetTile(arg0, arg1 int) cgra.Tile { 68 | m.ctrl.T.Helper() 69 | ret := m.ctrl.Call(m, "GetTile", arg0, arg1) 70 | ret0, _ := ret[0].(cgra.Tile) 71 | return ret0 72 | } 73 | 74 | // GetTile indicates an expected call of GetTile. 75 | func (mr *MockDeviceMockRecorder) GetTile(arg0, arg1 interface{}) *gomock.Call { 76 | mr.mock.ctrl.T.Helper() 77 | return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetTile", reflect.TypeOf((*MockDevice)(nil).GetTile), arg0, arg1) 78 | } 79 | 80 | // MockTile is a mock of Tile interface. 81 | type MockTile struct { 82 | ctrl *gomock.Controller 83 | recorder *MockTileMockRecorder 84 | } 85 | 86 | // MockTileMockRecorder is the mock recorder for MockTile. 87 | type MockTileMockRecorder struct { 88 | mock *MockTile 89 | } 90 | 91 | // NewMockTile creates a new mock instance. 92 | func NewMockTile(ctrl *gomock.Controller) *MockTile { 93 | mock := &MockTile{ctrl: ctrl} 94 | mock.recorder = &MockTileMockRecorder{mock} 95 | return mock 96 | } 97 | 98 | // EXPECT returns an object that allows the caller to indicate expected use. 99 | func (m *MockTile) EXPECT() *MockTileMockRecorder { 100 | return m.recorder 101 | } 102 | 103 | // GetMemory mocks base method. 104 | func (m *MockTile) GetMemory(arg0, arg1 int, arg2 uint32) uint32 { 105 | m.ctrl.T.Helper() 106 | ret := m.ctrl.Call(m, "GetMemory", arg0, arg1, arg2) 107 | ret0, _ := ret[0].(uint32) 108 | return ret0 109 | } 110 | 111 | // GetMemory indicates an expected call of GetMemory. 112 | func (mr *MockTileMockRecorder) GetMemory(arg0, arg1, arg2 interface{}) *gomock.Call { 113 | mr.mock.ctrl.T.Helper() 114 | return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetMemory", reflect.TypeOf((*MockTile)(nil).GetMemory), arg0, arg1, arg2) 115 | } 116 | 117 | // GetPort mocks base method. 118 | func (m *MockTile) GetPort(arg0 cgra.Side) sim.Port { 119 | m.ctrl.T.Helper() 120 | ret := m.ctrl.Call(m, "GetPort", arg0) 121 | ret0, _ := ret[0].(sim.Port) 122 | return ret0 123 | } 124 | 125 | // GetPort indicates an expected call of GetPort. 126 | func (mr *MockTileMockRecorder) GetPort(arg0 interface{}) *gomock.Call { 127 | mr.mock.ctrl.T.Helper() 128 | return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetPort", reflect.TypeOf((*MockTile)(nil).GetPort), arg0) 129 | } 130 | 131 | // GetRetVal mocks base method. 132 | func (m *MockTile) GetRetVal() uint32 { 133 | m.ctrl.T.Helper() 134 | ret := m.ctrl.Call(m, "GetRetVal") 135 | ret0, _ := ret[0].(uint32) 136 | return ret0 137 | } 138 | 139 | // GetRetVal indicates an expected call of GetRetVal. 140 | func (mr *MockTileMockRecorder) GetRetVal() *gomock.Call { 141 | mr.mock.ctrl.T.Helper() 142 | return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetRetVal", reflect.TypeOf((*MockTile)(nil).GetRetVal)) 143 | } 144 | 145 | // GetTickingComponent mocks base method. 146 | func (m *MockTile) GetTickingComponent() sim.Component { 147 | m.ctrl.T.Helper() 148 | ret := m.ctrl.Call(m, "GetTickingComponent") 149 | ret0, _ := ret[0].(sim.Component) 150 | return ret0 151 | } 152 | 153 | // GetTickingComponent indicates an expected call of GetTickingComponent. 154 | func (mr *MockTileMockRecorder) GetTickingComponent() *gomock.Call { 155 | mr.mock.ctrl.T.Helper() 156 | return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetTickingComponent", reflect.TypeOf((*MockTile)(nil).GetTickingComponent)) 157 | } 158 | 159 | // GetTileX mocks base method. 160 | func (m *MockTile) GetTileX() int { 161 | m.ctrl.T.Helper() 162 | ret := m.ctrl.Call(m, "GetTileX") 163 | ret0, _ := ret[0].(int) 164 | return ret0 165 | } 166 | 167 | // GetTileX indicates an expected call of GetTileX. 168 | func (mr *MockTileMockRecorder) GetTileX() *gomock.Call { 169 | mr.mock.ctrl.T.Helper() 170 | return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetTileX", reflect.TypeOf((*MockTile)(nil).GetTileX)) 171 | } 172 | 173 | // GetTileY mocks base method. 174 | func (m *MockTile) GetTileY() int { 175 | m.ctrl.T.Helper() 176 | ret := m.ctrl.Call(m, "GetTileY") 177 | ret0, _ := ret[0].(int) 178 | return ret0 179 | } 180 | 181 | // GetTileY indicates an expected call of GetTileY. 182 | func (mr *MockTileMockRecorder) GetTileY() *gomock.Call { 183 | mr.mock.ctrl.T.Helper() 184 | return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetTileY", reflect.TypeOf((*MockTile)(nil).GetTileY)) 185 | } 186 | 187 | // MapProgram mocks base method. 188 | func (m *MockTile) MapProgram(arg0 interface{}, arg1, arg2 int) { 189 | m.ctrl.T.Helper() 190 | m.ctrl.Call(m, "MapProgram", arg0, arg1, arg2) 191 | } 192 | 193 | // MapProgram indicates an expected call of MapProgram. 194 | func (mr *MockTileMockRecorder) MapProgram(arg0, arg1, arg2 interface{}) *gomock.Call { 195 | mr.mock.ctrl.T.Helper() 196 | return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "MapProgram", reflect.TypeOf((*MockTile)(nil).MapProgram), arg0, arg1, arg2) 197 | } 198 | 199 | // SetRemotePort mocks base method. 200 | func (m *MockTile) SetRemotePort(arg0 cgra.Side, arg1 sim.RemotePort) { 201 | m.ctrl.T.Helper() 202 | m.ctrl.Call(m, "SetRemotePort", arg0, arg1) 203 | } 204 | 205 | // SetRemotePort indicates an expected call of SetRemotePort. 206 | func (mr *MockTileMockRecorder) SetRemotePort(arg0, arg1 interface{}) *gomock.Call { 207 | mr.mock.ctrl.T.Helper() 208 | return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SetRemotePort", reflect.TypeOf((*MockTile)(nil).SetRemotePort), arg0, arg1) 209 | } 210 | 211 | // WriteMemory mocks base method. 212 | func (m *MockTile) WriteMemory(arg0, arg1 int, arg2, arg3 uint32) { 213 | m.ctrl.T.Helper() 214 | m.ctrl.Call(m, "WriteMemory", arg0, arg1, arg2, arg3) 215 | } 216 | 217 | // WriteMemory indicates an expected call of WriteMemory. 218 | func (mr *MockTileMockRecorder) WriteMemory(arg0, arg1, arg2, arg3 interface{}) *gomock.Call { 219 | mr.mock.ctrl.T.Helper() 220 | return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "WriteMemory", reflect.TypeOf((*MockTile)(nil).WriteMemory), arg0, arg1, arg2, arg3) 221 | } 222 | 223 | // WriteSharedMemory mocks base method. 224 | func (m *MockTile) WriteSharedMemory(arg0, arg1 int, arg2 []byte, arg3 uint32) { 225 | m.ctrl.T.Helper() 226 | m.ctrl.Call(m, "WriteSharedMemory", arg0, arg1, arg2, arg3) 227 | } 228 | 229 | // WriteSharedMemory indicates an expected call of WriteSharedMemory. 230 | func (mr *MockTileMockRecorder) WriteSharedMemory(arg0, arg1, arg2, arg3 interface{}) *gomock.Call { 231 | mr.mock.ctrl.T.Helper() 232 | return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "WriteSharedMemory", reflect.TypeOf((*MockTile)(nil).WriteSharedMemory), arg0, arg1, arg2, arg3) 233 | } 234 | -------------------------------------------------------------------------------- /go.sum: -------------------------------------------------------------------------------- 1 | filippo.io/edwards25519 v1.1.0 h1:FNf4tywRC1HmFuKW5xopWpigGjJKiJSV0Cqo0cJWDaA= 2 | filippo.io/edwards25519 v1.1.0/go.mod h1:BxyFTGdWcka3PhytdK4V28tE5sGfRvvvRV7EaN4VDT4= 3 | github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= 4 | github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= 5 | github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= 6 | github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= 7 | github.com/go-logr/logr v1.4.2 h1:6pFjapn8bFcIbiKo3XT4j/BhANplGihG6tvd+8rYgrY= 8 | github.com/go-logr/logr v1.4.2/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= 9 | github.com/go-ole/go-ole v1.2.6/go.mod h1:pprOEPIfldk/42T2oK7lQ4v4JSDwmV0As9GaiUsvbm0= 10 | github.com/go-ole/go-ole v1.3.0 h1:Dt6ye7+vXGIKZ7Xtk4s6/xVdGDQynvom7xCFEdWr6uE= 11 | github.com/go-ole/go-ole v1.3.0/go.mod h1:5LS6F96DhAwUc7C+1HLexzMXY1xGRSryjyPPKW6zv78= 12 | github.com/go-sql-driver/mysql v1.8.1 h1:LedoTUt/eveggdHS9qUFC1EFSa8bU2+1pZjSRpvNJ1Y= 13 | github.com/go-sql-driver/mysql v1.8.1/go.mod h1:wEBSXgmK//2ZFJyE+qWnIsVGmvmEKlqwuVSjsCm7DZg= 14 | github.com/go-task/slim-sprig/v3 v3.0.0 h1:sUs3vkvUymDpBKi3qH1YSqBQk9+9D/8M2mN1vB6EwHI= 15 | github.com/go-task/slim-sprig/v3 v3.0.0/go.mod h1:W848ghGpv3Qj3dhTPRyJypKRiqCdHZiAzKg9hl15HA8= 16 | github.com/golang/mock v1.6.0 h1:ErTB+efbowRARo13NNdxyJji2egdxLGQhRaY+DUumQc= 17 | github.com/golang/mock v1.6.0/go.mod h1:p6yTPP+5HYm5mzsMV8JkE6ZKdX+/wYM6Hr+LicevLPs= 18 | github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= 19 | github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= 20 | github.com/google/pprof v0.0.0-20240829160300-da1f7e9f2b25 h1:sEDPKUw6iPjczdu33njxFjO6tYa9bfc0z/QyB/zSsBw= 21 | github.com/google/pprof v0.0.0-20240829160300-da1f7e9f2b25/go.mod h1:vavhavw2zAxS5dIdcRluK6cSGGPlZynqzFM8NdvU144= 22 | github.com/gorilla/mux v1.8.1 h1:TuBL49tXwgrFYWhqrNgrUNEY92u81SPhu7sTdzQEiWY= 23 | github.com/gorilla/mux v1.8.1/go.mod h1:AKf9I4AEqPTmMytcMc0KkNouC66V3BtZ4qD5fmWSiMQ= 24 | github.com/jedib0t/go-pretty/v6 v6.6.8 h1:JnnzQeRz2bACBobIaa/r+nqjvws4yEhcmaZ4n1QzsEc= 25 | github.com/jedib0t/go-pretty/v6 v6.6.8/go.mod h1:YwC5CE4fJ1HFUDeivSV1r//AmANFHyqczZk+U6BDALU= 26 | github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI= 27 | github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= 28 | github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= 29 | github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= 30 | github.com/mattn/go-runewidth v0.0.16 h1:E5ScNMtiwvlvB5paMFdw9p4kSQzbXFikJ5SQO6TULQc= 31 | github.com/mattn/go-runewidth v0.0.16/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w= 32 | github.com/mattn/go-sqlite3 v1.14.22 h1:2gZY6PC6kBnID23Tichd1K+Z0oS6nE/XwU+Vz/5o4kU= 33 | github.com/mattn/go-sqlite3 v1.14.22/go.mod h1:Uh1q+B4BYcTPb+yiD3kU8Ct7aC0hY9fxUwlHK0RXw+Y= 34 | github.com/onsi/ginkgo/v2 v2.20.2 h1:7NVCeyIWROIAheY21RLS+3j2bb52W0W82tkberYytp4= 35 | github.com/onsi/ginkgo/v2 v2.20.2/go.mod h1:K9gyxPIlb+aIvnZ8bd9Ak+YP18w3APlR+5coaZoE2ag= 36 | github.com/onsi/gomega v1.34.2 h1:pNCwDkzrsv7MS9kpaQvVb1aVLahQXyJ/Tv5oAZMI3i8= 37 | github.com/onsi/gomega v1.34.2/go.mod h1:v1xfxRgk0KIsG+QOdm7p8UosrOzPYRo60fd3B/1Dukc= 38 | github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= 39 | github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= 40 | github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc= 41 | github.com/rivo/uniseg v0.4.7 h1:WUdvkW8uEhrYfLC4ZzdpI2ztxP1I582+49Oc5Mq64VQ= 42 | github.com/rivo/uniseg v0.4.7/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88= 43 | github.com/rs/xid v1.6.0 h1:fV591PaemRlL6JfRxGDEPl69wICngIQ3shQtzfy2gxU= 44 | github.com/rs/xid v1.6.0/go.mod h1:7XoLgs4eV+QndskICGsho+ADou8ySMSjJKDIan90Nz0= 45 | github.com/sarchlab/akita/v4 v4.0.0 h1:LPDqmjKZ6TauDGtxDpd9YjdST0BtpZFmrHd24pABhCY= 46 | github.com/sarchlab/akita/v4 v4.0.0/go.mod h1:GAEse/nsn+/yj1svoyxNxQz6pGtnLwNQJhnMa1XRC9M= 47 | github.com/shirou/gopsutil v3.21.11+incompatible h1:+1+c1VGhc88SSonWP6foOcLhvnKlUeu/erjjvaPEYiI= 48 | github.com/shirou/gopsutil v3.21.11+incompatible/go.mod h1:5b4v6he4MtMOwMlS0TUMTu2PcXUg8+E1lC7eC3UO/RA= 49 | github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= 50 | github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= 51 | github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk= 52 | github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= 53 | github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA= 54 | github.com/syifan/goseth v0.1.2 h1:b/VG4wboBQNedodAw6wzTz6fdtISSbYIR3ntzRw0J6Q= 55 | github.com/syifan/goseth v0.1.2/go.mod h1:XmguXtbJ2+jSQABDvr3X0uDiYo+7gak39C6BHoWDvYo= 56 | github.com/tebeka/atexit v0.3.0 h1:jleL99H7Ywt80oJKR+VWmJNnezcCOG0CuzcN3CIpsdI= 57 | github.com/tebeka/atexit v0.3.0/go.mod h1:WJmSUSmMT7WoR7etUOaGBVXk+f5/ZJ+67qwuedq7Fbs= 58 | github.com/tklauser/go-sysconf v0.3.14 h1:g5vzr9iPFFz24v2KZXs/pvpvh8/V9Fw6vQK5ZZb78yU= 59 | github.com/tklauser/go-sysconf v0.3.14/go.mod h1:1ym4lWMLUOhuBOPGtRcJm7tEGX4SCYNEEEtghGG/8uY= 60 | github.com/tklauser/numcpus v0.8.0 h1:Mx4Wwe/FjZLeQsK/6kt2EOepwwSl7SmJrK5bV/dXYgY= 61 | github.com/tklauser/numcpus v0.8.0/go.mod h1:ZJZlAY+dmR4eut8epnzf0u/VwodKmryxR8txiloSqBE= 62 | github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= 63 | github.com/yusufpapurcu/wmi v1.2.4 h1:zFUKzehAFReQwLys1b/iSMl+JQGSCSjtVqQn9bBrPo0= 64 | github.com/yusufpapurcu/wmi v1.2.4/go.mod h1:SBZ9tNy3G9/m5Oi98Zks0QjeHVDvuK0qfxQmPyzfmi0= 65 | golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= 66 | golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= 67 | golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= 68 | golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= 69 | golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= 70 | golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= 71 | golang.org/x/net v0.38.0 h1:vRMAPTMaeGqVhG5QyLJHqNDwecKTomGeqbnfZyKlBI8= 72 | golang.org/x/net v0.38.0/go.mod h1:ivrbrMbzFq5J41QOQh0siUuly180yBYtLp+CKbEaFx8= 73 | golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 74 | golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 75 | golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= 76 | golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 77 | golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 78 | golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 79 | golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 80 | golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 81 | golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 82 | golang.org/x/sys v0.31.0 h1:ioabZlmFYtWhL+TRYpcnNlLwhyxaM9kWTDEmfnprqik= 83 | golang.org/x/sys v0.31.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k= 84 | golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= 85 | golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= 86 | golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= 87 | golang.org/x/text v0.23.0 h1:D71I7dUrlY+VX0gQShAThNGHFxZ13dGLBHQLVl1mJlY= 88 | golang.org/x/text v0.23.0/go.mod h1:/BLNzu4aZCJ1+kcD0DNRotWKage4q2rGVAg4o22unh4= 89 | golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= 90 | golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= 91 | golang.org/x/tools v0.1.1/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= 92 | golang.org/x/tools v0.24.0 h1:J1shsA93PJUEVaUSaay7UXAyE8aimq3GW0pjlolpa24= 93 | golang.org/x/tools v0.24.0/go.mod h1:YhNqVBIfWHdzvTLs0d8LCuMhkKUgSUKldakyV7W/WDQ= 94 | golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= 95 | golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= 96 | golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= 97 | google.golang.org/protobuf v1.34.1 h1:9ddQBjfCyZPOHPUiPxpYESBLc+T8P3E+Vo4IbKZgFWg= 98 | google.golang.org/protobuf v1.34.1/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos= 99 | gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= 100 | gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY= 101 | gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= 102 | gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= 103 | gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= 104 | gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= 105 | -------------------------------------------------------------------------------- /core/core.go: -------------------------------------------------------------------------------- 1 | package core 2 | 3 | import ( 4 | "fmt" 5 | "log/slog" 6 | 7 | "github.com/sarchlab/akita/v4/mem/mem" 8 | "github.com/sarchlab/akita/v4/sim" 9 | "github.com/sarchlab/zeonica/cgra" 10 | ) 11 | 12 | type portPair struct { 13 | local sim.Port 14 | remote sim.RemotePort 15 | } 16 | 17 | type Core struct { 18 | *sim.TickingComponent 19 | 20 | ports map[cgra.Side]*portPair 21 | 22 | state coreState 23 | emu instEmulator 24 | } 25 | 26 | func (c *Core) GetRetVal() uint32 { 27 | return *c.state.retVal 28 | } 29 | 30 | func (c *Core) GetTileX() int { 31 | return int(c.state.TileX) 32 | } 33 | 34 | func (c *Core) GetTileY() int { 35 | return int(c.state.TileY) 36 | } 37 | 38 | func (c *Core) GetTickingComponent() sim.Component { 39 | return c.TickingComponent 40 | } 41 | 42 | // get memory 43 | func (c *Core) GetMemory(x int, y int, addr uint32) uint32 { 44 | if x == int(c.state.TileX) && y == int(c.state.TileY) { 45 | return c.state.Memory[addr] 46 | } else { 47 | panic("Invalid Tile") 48 | } 49 | } 50 | 51 | // write memory 52 | func (c *Core) WriteMemory(x int, y int, data uint32, baseAddr uint32) { 53 | //fmt.Printf("Core [%d][%d] receive WriteMemory(x=%d, y=%d)\n", c.state.TileX, c.state.TileY, x, y) 54 | if x == int(c.state.TileX) && y == int(c.state.TileY) { 55 | c.state.Memory[baseAddr] = data 56 | //fmt.Printf("Core [%d][%d] write memory[%d] = %d\n", c.state.TileX, c.state.TileY, baseAddr, c.state.Memory[baseAddr]) 57 | Trace("Memory", 58 | "Behavior", "WriteMemory", 59 | "Time", float64(c.Engine.CurrentTime()*1e9), 60 | "Data", data, 61 | "X", x, 62 | "Y", y, 63 | "Addr", baseAddr, 64 | ) 65 | } else { 66 | panic(fmt.Sprintf("Invalid Tile: Expect (%d, %d),but get (%d, %d)", c.state.TileX, c.state.TileY, x, y)) 67 | } 68 | } 69 | 70 | func (c *Core) SetRemotePort(side cgra.Side, remote sim.RemotePort) { 71 | c.ports[side].remote = remote 72 | } 73 | 74 | // MapProgram sets the program that the core needs to run. 75 | func (c *Core) MapProgram(program interface{}, x int, y int) { 76 | if prog, ok := program.(Program); ok { 77 | c.state.Code = prog 78 | } else { 79 | panic("MapProgram expects core.Program type") 80 | } 81 | c.state.PCInBlock = -1 82 | c.state.TileX = uint32(x) 83 | c.state.TileY = uint32(y) 84 | } 85 | 86 | // Tick runs the program for one cycle. 87 | func (c *Core) Tick() (madeProgress bool) { 88 | madeProgress = c.doSend() || madeProgress 89 | // madeProgress = c.AlwaysPart() || madeProgress 90 | // madeProgress = c.emu.runRoutingRules(&c.state) || madeProgress 91 | madeProgress = c.runProgram() || madeProgress 92 | madeProgress = c.doRecv() || madeProgress 93 | return madeProgress 94 | } 95 | 96 | func makeBytesFromUint32(data uint32) []byte { 97 | return []byte{byte(data >> 24), byte(data >> 16), byte(data >> 8), byte(data)} 98 | } 99 | 100 | func (c *Core) doSend() bool { 101 | madeProgress := false 102 | for i := 0; i < 8; i++ { // only 8 directions 103 | for color := 0; color < 4; color++ { 104 | 105 | if !c.state.SendBufHeadBusy[color][i] { 106 | continue 107 | } 108 | 109 | //fmt.Printf("\033[31m (%d, %d) Sending data %d to %s\033[0m\n", c.state.TileX, c.state.TileY, c.state.SendBufHead[color][i].First(), c.ports[cgra.Side(i)].remote) 110 | 111 | msg := cgra.MoveMsgBuilder{}. 112 | WithDst(c.ports[cgra.Side(i)].remote). 113 | WithSrc(c.ports[cgra.Side(i)].local.AsRemote()). 114 | WithData(c.state.SendBufHead[color][i]). 115 | WithSendTime(c.Engine.CurrentTime()). 116 | WithColor(color). 117 | Build() 118 | 119 | err := c.ports[cgra.Side(i)].local.Send(msg) 120 | if err != nil { 121 | continue 122 | } 123 | 124 | Trace("DataFlow", 125 | "Behavior", "Send", 126 | slog.Float64("Time", float64(c.Engine.CurrentTime()*1e9)), 127 | "Data", msg.Data.First(), 128 | "Pred", c.state.SendBufHead[color][i].Pred, 129 | "Color", color, 130 | "Src", msg.Src, 131 | "Dst", msg.Dst, 132 | ) 133 | c.state.SendBufHeadBusy[color][i] = false 134 | } 135 | } 136 | 137 | // handle the memory request 138 | 139 | if c.state.SendBufHeadBusy[c.emu.getColorIndex("R")][cgra.Router] { // only one port, must be Router-red 140 | 141 | if c.state.IsToWriteMemory { 142 | msg := mem.WriteReqBuilder{}. 143 | WithAddress(uint64(c.state.AddrBuf)). 144 | WithData(makeBytesFromUint32(c.state.SendBufHead[c.emu.getColorIndex("R")][cgra.Router].First())). 145 | WithSrc(c.ports[cgra.Side(cgra.Router)].local.AsRemote()). 146 | WithDst(c.ports[cgra.Side(cgra.Router)].remote). 147 | Build() 148 | 149 | err := c.ports[cgra.Side(cgra.Router)].local.Send(msg) 150 | if err != nil { 151 | return madeProgress 152 | } 153 | 154 | Trace("Memory", 155 | "Behavior", "Send", 156 | slog.Float64("Time", float64(c.Engine.CurrentTime()*1e9)), 157 | "Data", c.state.SendBufHead[c.emu.getColorIndex("R")][cgra.Router].First(), 158 | "Pred", c.state.SendBufHead[c.emu.getColorIndex("R")][cgra.Router].Pred, 159 | "Color", "R", 160 | "Src", msg.Src, 161 | "Dst", msg.Dst, 162 | ) 163 | c.state.SendBufHeadBusy[c.emu.getColorIndex("R")][cgra.Router] = false 164 | } else { 165 | msg := mem.ReadReqBuilder{}. 166 | WithAddress(uint64(c.state.AddrBuf)). 167 | WithSrc(c.ports[cgra.Side(cgra.Router)].local.AsRemote()). 168 | WithDst(c.ports[cgra.Side(cgra.Router)].remote). 169 | WithByteSize(4). 170 | Build() 171 | 172 | err := c.ports[cgra.Side(cgra.Router)].local.Send(msg) 173 | if err != nil { 174 | return madeProgress 175 | } 176 | 177 | Trace("Memory", 178 | "Behavior", "Send", 179 | slog.Float64("Time", float64(c.Engine.CurrentTime()*1e9)), 180 | "Data", c.state.AddrBuf, 181 | "Color", "R", 182 | "Src", msg.Src, 183 | "Dst", msg.Dst, 184 | ) 185 | c.state.SendBufHeadBusy[c.emu.getColorIndex("R")][cgra.Router] = false 186 | } 187 | } 188 | 189 | return madeProgress 190 | } 191 | 192 | func convert4BytesToUint32(data []byte) uint32 { 193 | return uint32(data[0])<<24 | uint32(data[1])<<16 | uint32(data[2])<<8 | uint32(data[3]) 194 | } 195 | 196 | func (c *Core) doRecv() bool { 197 | madeProgress := false 198 | for i := 0; i < 8; i++ { //direction 199 | item := c.ports[cgra.Side(i)].local.PeekIncoming() 200 | if item == nil { 201 | continue 202 | } 203 | 204 | // fmt.Printf("%10f, %s, %d retrieved\n", 205 | // c.Engine.CurrentTime()*1e9, 206 | // c.Name(), cgra.Side(i)) 207 | 208 | //fmt.Printf("%s Scanning direction %d(0 is North, 3 is West)\n", c.Name(), i) 209 | for color := 0; color < 4; color++ { 210 | //fmt.Printf("%s Receiving Data with color %d. Recv buffer head: %+v\n", 211 | // c.Name(), color, c.state.RecvBufHeadReady[color][i]) 212 | if c.state.RecvBufHeadReady[color][i] { 213 | continue 214 | } 215 | 216 | msg := item.(*cgra.MoveMsg) 217 | if color != msg.Color { 218 | continue 219 | } 220 | 221 | c.state.RecvBufHeadReady[color][i] = true 222 | c.state.RecvBufHead[color][i] = msg.Data 223 | 224 | Trace("DataFlow", 225 | "Behavior", "Recv", 226 | "Time", float64(c.Engine.CurrentTime()*1e9), 227 | "Data", msg.Data.First(), 228 | "Pred", c.state.RecvBufHead[color][i].Pred, 229 | "Src", msg.Src, 230 | "Dst", msg.Dst, 231 | "Color", color, 232 | ) 233 | 234 | c.ports[cgra.Side(i)].local.RetrieveIncoming() 235 | madeProgress = true 236 | } 237 | } 238 | 239 | item := c.ports[cgra.Side(cgra.Router)].local.PeekIncoming() 240 | if item == nil { 241 | return madeProgress 242 | } else { 243 | if c.state.RecvBufHeadReady[c.emu.getColorIndex("R")][cgra.Router] { 244 | return madeProgress 245 | } 246 | 247 | // if msg is DataReadyRsp, then the data is ready 248 | if msg, ok := item.(*mem.DataReadyRsp); ok { 249 | c.state.RecvBufHeadReady[c.emu.getColorIndex("R")][cgra.Router] = true 250 | c.state.RecvBufHead[c.emu.getColorIndex("R")][cgra.Router] = cgra.NewScalar(convert4BytesToUint32(msg.Data)) 251 | 252 | Trace("Memory", 253 | "Behavior", "Recv", 254 | "Time", float64(c.Engine.CurrentTime()*1e9), 255 | "Data", msg.Data, 256 | "Src", msg.Src, 257 | "Dst", msg.Dst, 258 | "Pred", c.state.RecvBufHead[c.emu.getColorIndex("R")][cgra.Router].Pred, 259 | "Color", "R", 260 | ) 261 | 262 | c.ports[cgra.Side(cgra.Router)].local.RetrieveIncoming() 263 | madeProgress = true 264 | } else if msg, ok := item.(*mem.WriteDoneRsp); ok { 265 | c.state.RecvBufHeadReady[c.emu.getColorIndex("R")][cgra.Router] = true 266 | c.state.RecvBufHead[c.emu.getColorIndex("R")][cgra.Router] = cgra.NewScalar(0) 267 | 268 | Trace("Memory", 269 | "Behavior", "Recv", 270 | "Time", float64(c.Engine.CurrentTime()*1e9), 271 | "Src", msg.Src, 272 | "Dst", msg.Dst, 273 | "Pred", c.state.RecvBufHead[c.emu.getColorIndex("R")][cgra.Router].Pred, 274 | "Color", "R", 275 | ) 276 | 277 | c.ports[cgra.Side(cgra.Router)].local.RetrieveIncoming() 278 | madeProgress = true 279 | } 280 | } 281 | 282 | return madeProgress 283 | } 284 | 285 | func (c *Core) runProgram() bool { 286 | if len(c.state.Code.EntryBlocks) == 0 { 287 | return false 288 | } 289 | 290 | if c.state.PCInBlock == -1 { 291 | c.state.PCInBlock = 0 292 | c.state.SelectedBlock = &c.state.Code.EntryBlocks[0] // just temp, only one block\ 293 | if c.state.Mode == AsyncOp { 294 | c.emu.SetUpInstructionGroup(0, &c.state) 295 | } 296 | c.state.NextPCInBlock = -1 297 | } 298 | //print("Op2Exec: ", c.state.CurrReservationState.OpToExec, "\n") 299 | 300 | iGroup := c.state.SelectedBlock.InstructionGroups[c.state.PCInBlock] 301 | 302 | makeProgress := c.emu.RunInstructionGroup(iGroup, &c.state, float64(c.Engine.CurrentTime()*1e9)) 303 | 304 | return makeProgress 305 | } 306 | -------------------------------------------------------------------------------- /test/mem/mem_test.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "testing" 6 | "unsafe" 7 | 8 | "github.com/sarchlab/akita/v4/sim" 9 | "github.com/sarchlab/zeonica/api" 10 | "github.com/sarchlab/zeonica/cgra" 11 | "github.com/sarchlab/zeonica/config" 12 | "github.com/sarchlab/zeonica/core" 13 | ) 14 | 15 | func TestLoadStoreOperation(t *testing.T) { 16 | // Set test parameters 17 | width := 2 18 | height := 2 19 | length := 10 20 | 21 | // Create test data 22 | src := make([]uint32, length) 23 | dst := make([]uint32, length) 24 | 25 | // Generate random test data 26 | src = []uint32{1, 2, 9, 9, 0, 0, 3, 5, 6, 7} 27 | 28 | // Create simulation engine 29 | engine := sim.NewSerialEngine() 30 | 31 | // Create driver 32 | driver := api.DriverBuilder{}. 33 | WithEngine(engine). 34 | WithFreq(1 * sim.GHz). 35 | Build("Driver") 36 | 37 | // Create device 38 | device := config.DeviceBuilder{}. 39 | WithEngine(engine). 40 | WithFreq(1 * sim.GHz). 41 | WithWidth(width). 42 | WithHeight(height). 43 | Build("Device") 44 | 45 | driver.RegisterDevice(device) 46 | 47 | // Load program 48 | program := core.LoadProgramFileFromYAML("./test_loadstore.yaml") 49 | if len(program) == 0 { 50 | t.Fatal("Failed to load program") 51 | } 52 | 53 | // Set data flow - input from west, output to east 54 | driver.FeedIn(src, cgra.West, [2]int{0, 1}, 1, "R") 55 | driver.Collect(dst, cgra.West, [2]int{1, 2}, 1, "R") 56 | 57 | // Map program to all cores 58 | for x := 0; x < width; x++ { 59 | for y := 0; y < height; y++ { 60 | coord := fmt.Sprintf("(%d,%d)", x, y) 61 | if prog, exists := program[coord]; exists { 62 | driver.MapProgram(prog, [2]int{x, y}) 63 | } 64 | } 65 | } 66 | 67 | // Run simulation 68 | driver.Run() 69 | 70 | // Convert results and verify 71 | srcI := make([]int32, length*2) 72 | dstI := make([]int32, length*2) 73 | for i := 0; i < length; i++ { 74 | srcI[i] = *(*int32)(unsafe.Pointer(&src[i])) 75 | dstI[i] = *(*int32)(unsafe.Pointer(&dst[i])) 76 | } 77 | 78 | expected := []int32{1, 2, 9, 9, 0, 0, 3, 5, 6, 7} 79 | // Verify results: output should be input+2 80 | t.Log("=== LoadStore Test Results ===") 81 | allPassed := true 82 | for i := 0; i < length; i++ { 83 | actual := dstI[i] 84 | 85 | if actual != expected[i] { 86 | t.Errorf("Index %d: Input=%d, Expected=%d, Actual=%d", 87 | i, srcI[i], expected[i], actual) 88 | allPassed = false 89 | } else { 90 | t.Logf("Index %d: Input=%d, Output=%d ✓", i, srcI[i], actual) 91 | } 92 | } 93 | 94 | if allPassed { 95 | t.Log("✅ LoadStore tests passed!") 96 | } else { 97 | t.Fatal("❌ LoadStore tests failed!") 98 | } 99 | } 100 | 101 | func makeBytesFromUint32(data uint32) []byte { 102 | return []byte{byte(data >> 24), byte(data >> 16), byte(data >> 8), byte(data)} 103 | } 104 | 105 | func TestLoadWaitDRAMOperation(t *testing.T) { 106 | width := 2 107 | height := 2 108 | 109 | src1 := make([]uint32, 1) 110 | src1[0] = 114 111 | src2 := make([]uint32, 1) 112 | src2[0] = 514 113 | dst1 := make([]uint32, 1) 114 | dst2 := make([]uint32, 1) 115 | 116 | engine := sim.NewSerialEngine() 117 | 118 | driver := api.DriverBuilder{}. 119 | WithEngine(engine). 120 | WithFreq(1 * sim.GHz). 121 | Build("Driver") 122 | 123 | device := config.DeviceBuilder{}. 124 | WithEngine(engine). 125 | WithFreq(1 * sim.GHz). 126 | WithWidth(width). 127 | WithHeight(height). 128 | WithMemoryMode("local"). 129 | Build("Device") 130 | 131 | driver.RegisterDevice(device) 132 | 133 | program := core.LoadProgramFileFromYAML("./test_lw.yaml") 134 | if len(program) == 0 { 135 | t.Fatal("Failed to load program") 136 | } 137 | 138 | driver.FeedIn(src1, cgra.West, [2]int{0, 1}, 1, "R") 139 | driver.FeedIn(src2, cgra.West, [2]int{1, 2}, 1, "R") 140 | driver.Collect(dst1, cgra.East, [2]int{0, 1}, 1, "R") 141 | driver.Collect(dst2, cgra.East, [2]int{1, 2}, 1, "R") 142 | 143 | for x := 0; x < width; x++ { 144 | for y := 0; y < height; y++ { 145 | coord := fmt.Sprintf("(%d,%d)", x, y) 146 | if prog, exists := program[coord]; exists { 147 | driver.MapProgram(prog, [2]int{x, y}) 148 | } 149 | } 150 | } 151 | 152 | driver.PreloadSharedMemory(0, 0, makeBytesFromUint32(3), 0) 153 | driver.PreloadSharedMemory(0, 1, makeBytesFromUint32(1), 0) 154 | 155 | driver.Run() 156 | 157 | srcI1 := make([]int32, 1) 158 | srcI2 := make([]int32, 1) 159 | dstI1 := make([]int32, 1) 160 | dstI2 := make([]int32, 1) 161 | 162 | for i := 0; i < 1; i++ { 163 | srcI1[i] = *(*int32)(unsafe.Pointer(&src1[i])) 164 | srcI2[i] = *(*int32)(unsafe.Pointer(&src2[i])) 165 | dstI1[i] = *(*int32)(unsafe.Pointer(&dst1[i])) 166 | dstI2[i] = *(*int32)(unsafe.Pointer(&dst2[i])) 167 | } 168 | 169 | expected1 := []int32{3} 170 | expected2 := []int32{1} 171 | 172 | t.Logf("=== LoadWaitDRAM Test Results ===") 173 | allPassed := true 174 | if dstI1[0] != expected1[0] { 175 | t.Errorf("Index 0: Input=%d, Expected=%d, Actual=%d", 176 | srcI1[0], expected1[0], dstI1[0]) 177 | allPassed = false 178 | } else { 179 | t.Logf("Index 0: Input=%d, Output=%d ✓", srcI1[0], dstI1[0]) 180 | } 181 | if dstI2[0] != expected2[0] { 182 | t.Errorf("Index 0: Input=%d, Expected=%d, Actual=%d", 183 | srcI2[0], expected2[0], dstI2[0]) 184 | allPassed = false 185 | } else { 186 | t.Logf("Index 0: Input=%d, Output=%d ✓", srcI2[0], dstI2[0]) 187 | } 188 | if allPassed { 189 | t.Log("✅ LoadWaitDRAM tests passed!") 190 | } else { 191 | t.Fatal("❌ LoadWaitDRAM tests failed!") 192 | } 193 | 194 | } 195 | 196 | func TestGoAround(t *testing.T) { 197 | width := 2 198 | height := 2 199 | 200 | src := make([]uint32, 5) 201 | src = []uint32{114, 514, 19, 19, 810} 202 | dst := make([]uint32, 5) 203 | srcI := make([]int32, 5) 204 | dstI := make([]int32, 5) 205 | 206 | engine := sim.NewSerialEngine() 207 | 208 | driver := api.DriverBuilder{}. 209 | WithEngine(engine). 210 | WithFreq(1 * sim.GHz). 211 | Build("Driver") 212 | 213 | device := config.DeviceBuilder{}. 214 | WithEngine(engine). 215 | WithFreq(1 * sim.GHz). 216 | WithWidth(width). 217 | WithHeight(height). 218 | WithMemoryMode("local"). 219 | Build("Device") 220 | 221 | driver.RegisterDevice(device) 222 | 223 | program := core.LoadProgramFileFromYAML("./test_lwsw-go-a-round.yaml") 224 | if len(program) == 0 { 225 | t.Fatal("Failed to load program") 226 | } 227 | 228 | driver.FeedIn(src, cgra.West, [2]int{0, 1}, 1, "R") 229 | driver.Collect(dst, cgra.West, [2]int{1, 2}, 1, "R") 230 | 231 | for x := 0; x < width; x++ { 232 | for y := 0; y < height; y++ { 233 | coord := fmt.Sprintf("(%d,%d)", x, y) 234 | if prog, exists := program[coord]; exists { 235 | driver.MapProgram(prog, [2]int{x, y}) 236 | } 237 | } 238 | } 239 | 240 | driver.Run() 241 | 242 | for i := 0; i < 5; i++ { 243 | srcI[i] = *(*int32)(unsafe.Pointer(&src[i])) 244 | dstI[i] = *(*int32)(unsafe.Pointer(&dst[i])) 245 | } 246 | 247 | expected := []int32{114, 514, 19, 19, 810} 248 | 249 | t.Logf("=== GoAround Test Results ===") 250 | allPassed := true 251 | for i := 0; i < 5; i++ { 252 | if dstI[i] != expected[i] { 253 | t.Errorf("Index %d: Input=%d, Expected=%d, Actual=%d", 254 | i, srcI[i], expected[i], dstI[i]) 255 | allPassed = false 256 | } else { 257 | t.Logf("Index %d: Input=%d, Output=%d ✓", i, srcI[i], dstI[i]) 258 | } 259 | } 260 | if allPassed { 261 | t.Log("✅ GoAround tests passed!") 262 | } else { 263 | t.Fatal("❌ GoAround tests failed!") 264 | } 265 | 266 | } 267 | 268 | func TestSharedMemory(t *testing.T) { 269 | width := 2 270 | height := 2 271 | 272 | src := make([]uint32, 5) 273 | src = []uint32{114, 514, 19, 19, 810} 274 | dst1 := make([]uint32, 5) 275 | dst2 := make([]uint32, 5) 276 | dst3 := make([]uint32, 5) 277 | srcI := make([]int32, 5) 278 | dstI1 := make([]int32, 5) 279 | dstI2 := make([]int32, 5) 280 | dstI3 := make([]int32, 5) 281 | 282 | engine := sim.NewSerialEngine() 283 | 284 | driver := api.DriverBuilder{}. 285 | WithEngine(engine). 286 | WithFreq(1 * sim.GHz). 287 | Build("Driver") 288 | 289 | device := config.DeviceBuilder{}. 290 | WithEngine(engine). 291 | WithFreq(1 * sim.GHz). 292 | WithWidth(width). 293 | WithHeight(height). 294 | WithMemoryMode("shared"). 295 | WithMemoryShare(map[[2]int]int{ 296 | {0, 0}: 0, 297 | {0, 1}: 0, 298 | {1, 0}: 0, 299 | {1, 1}: 0, 300 | }). 301 | Build("Device") 302 | 303 | driver.RegisterDevice(device) 304 | 305 | program := core.LoadProgramFileFromYAML("./test_all-shared-mem.yaml") 306 | if len(program) == 0 { 307 | t.Fatal("Failed to load program") 308 | } 309 | 310 | driver.FeedIn(src, cgra.West, [2]int{0, 1}, 1, "R") 311 | driver.Collect(dst1, cgra.West, [2]int{1, 2}, 1, "R") 312 | driver.Collect(dst2, cgra.East, [2]int{0, 1}, 1, "R") 313 | driver.Collect(dst3, cgra.East, [2]int{1, 2}, 1, "R") 314 | 315 | for x := 0; x < width; x++ { 316 | for y := 0; y < height; y++ { 317 | coord := fmt.Sprintf("(%d,%d)", x, y) 318 | if prog, exists := program[coord]; exists { 319 | driver.MapProgram(prog, [2]int{x, y}) 320 | } 321 | } 322 | } 323 | 324 | driver.Run() 325 | 326 | for i := 0; i < 5; i++ { 327 | srcI[i] = *(*int32)(unsafe.Pointer(&src[i])) 328 | dstI1[i] = *(*int32)(unsafe.Pointer(&dst1[i])) 329 | dstI2[i] = *(*int32)(unsafe.Pointer(&dst2[i])) 330 | dstI3[i] = *(*int32)(unsafe.Pointer(&dst3[i])) 331 | } 332 | 333 | expected := []int32{114, 514, 19, 19, 810} 334 | 335 | t.Logf("=== SharedMemory Test Results ===") 336 | allPassed := true 337 | for i := 0; i < 5; i++ { 338 | if dstI1[i] != expected[i] || dstI2[i] != expected[i] || dstI3[i] != expected[i] { 339 | t.Errorf("Index %d: Input=%d, Expected=%d, Actual1=%d, Actual2=%d, Actual3=%d", 340 | i, srcI[i], expected[i], dstI1[i], dstI2[i], dstI3[i]) 341 | allPassed = false 342 | } else { 343 | t.Logf("Index %d: Input=%d, Output1=%d, Output2=%d, Output3=%d ✓", i, srcI[i], dstI1[i], dstI2[i], dstI3[i]) 344 | } 345 | } 346 | if allPassed { 347 | t.Log("✅ SharedMemory tests passed!") 348 | } else { 349 | t.Fatal("❌ SharedMemory tests failed!") 350 | } 351 | 352 | } 353 | -------------------------------------------------------------------------------- /api/driver_internal_test.go: -------------------------------------------------------------------------------- 1 | package api 2 | 3 | import ( 4 | gomock "github.com/golang/mock/gomock" 5 | . "github.com/onsi/ginkgo/v2" 6 | . "github.com/onsi/gomega" 7 | "github.com/sarchlab/akita/v4/sim" 8 | "github.com/sarchlab/zeonica/cgra" 9 | ) 10 | 11 | type mockPortFactory struct { 12 | mockCtrl *gomock.Controller 13 | 14 | ports map[string]*MockPort 15 | } 16 | 17 | func (f *mockPortFactory) make(c sim.Component, name string) sim.Port { 18 | port := NewMockPort(f.mockCtrl) 19 | port.EXPECT().Name().Return("DriverSidePort").AnyTimes() 20 | port.EXPECT().SetConnection(gomock.Any()).AnyTimes() 21 | port.EXPECT().Deliver(gomock.Any()).AnyTimes() 22 | port.EXPECT().AsRemote().Return(sim.RemotePort(name)).AnyTimes() 23 | // PeekIncoming and RetrieveIncoming will be set up per test 24 | // Don't set default expectations here as they may conflict with test-specific ones 25 | f.ports[name] = port 26 | return port 27 | } 28 | 29 | var _ = Describe("Driver", func() { 30 | var ( 31 | mockCtrl *gomock.Controller 32 | mockEngine *MockEngine 33 | mockTile *MockTile 34 | mockDevice *MockDevice 35 | mockDeviceSidePort *MockPort 36 | portFactory *mockPortFactory 37 | driver *driverImpl 38 | ) 39 | 40 | BeforeEach(func() { 41 | mockCtrl = gomock.NewController(GinkgoT()) 42 | 43 | mockEngine = NewMockEngine(mockCtrl) 44 | mockEngine.EXPECT().CurrentTime().Return(sim.VTimeInSec(1)).AnyTimes() 45 | 46 | mockDeviceSidePort = NewMockPort(mockCtrl) 47 | mockDeviceSidePort.EXPECT().Name().Return("DevicePort").AnyTimes() 48 | mockDeviceSidePort.EXPECT().SetConnection(gomock.Any()).AnyTimes() 49 | mockDeviceSidePort.EXPECT().Deliver(gomock.Any()).AnyTimes() 50 | mockDeviceSidePort.EXPECT().AsRemote().Return(sim.RemotePort("DevicePort")).AnyTimes() 51 | 52 | mockTile = NewMockTile(mockCtrl) 53 | mockTile.EXPECT().SetRemotePort(gomock.Any(), gomock.Any()).AnyTimes() 54 | mockTile.EXPECT().GetMemory(gomock.Any(), gomock.Any(), gomock.Any()).Return(uint32(0)).AnyTimes() 55 | mockTile.EXPECT().GetTileX().Return(0).AnyTimes() 56 | mockTile.EXPECT().GetTileY().Return(0).AnyTimes() 57 | 58 | mockDevice = NewMockDevice(mockCtrl) 59 | mockDevice.EXPECT().GetSize().Return(4, 4).AnyTimes() 60 | mockDevice.EXPECT(). 61 | GetTile(gomock.Any(), gomock.Any()). 62 | Return(mockTile). 63 | AnyTimes() 64 | // handle incorrect coordinators 65 | mockDevice.EXPECT(). 66 | GetSidePorts(gomock.Any(), gomock.Any()). 67 | DoAndReturn(func(side cgra.Side, portRange [2]int) []sim.Port { 68 | ports := make([]sim.Port, portRange[1]-portRange[0]) 69 | for i := range ports { 70 | // MockPort needs to implement AsRemote, so we use mockDeviceSidePort directly 71 | ports[i] = mockDeviceSidePort 72 | } 73 | return ports 74 | }).AnyTimes() 75 | 76 | // Note: AsRemote() returns sim.RemotePort, which MockPort should implement 77 | // We'll set up the expectation when needed 78 | 79 | mockDevice.EXPECT(). 80 | GetTile(gomock.Any(), gomock.Any()). 81 | DoAndReturn(func(x, y int) cgra.Tile { 82 | if x >= 0 && x < 4 && y >= 0 && y < 4 { 83 | return mockTile 84 | } 85 | return nil 86 | }).AnyTimes() 87 | portFactory = &mockPortFactory{ 88 | mockCtrl: mockCtrl, 89 | ports: make(map[string]*MockPort), 90 | } 91 | driver = &driverImpl{ 92 | device: mockDevice, 93 | portFactory: portFactory, 94 | } 95 | driver.TickingComponent = 96 | sim.NewTickingComponent("Driver", mockEngine, 1, driver) 97 | driver.RegisterDevice(mockDevice) 98 | }) 99 | 100 | AfterEach(func() { 101 | mockCtrl.Finish() 102 | }) 103 | 104 | It("should handle FeedIn API", func() { 105 | data := []uint32{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12} 106 | 107 | driver.FeedIn(data, cgra.North, [2]int{0, 3}, 3, "R") 108 | 109 | sideIndex := int(cgra.North) 110 | Expect(driver.feedInTasks[sideIndex]).To(HaveLen(1)) 111 | Expect(driver.feedInTasks[sideIndex][0].data).To(Equal(data)) 112 | Expect(driver.feedInTasks[sideIndex][0].localPorts). 113 | To(HaveLen(3)) 114 | Expect(driver.feedInTasks[sideIndex][0].remotePorts). 115 | To(HaveLen(3)) 116 | Expect(driver.feedInTasks[sideIndex][0].stride).To(Equal(3)) 117 | }) 118 | 119 | It("should handle Collect API", func() { 120 | data := make([]uint32, 6) 121 | 122 | driver.Collect(data, cgra.North, [2]int{0, 3}, 3, "R") 123 | 124 | sideIndex := int(cgra.North) 125 | Expect(driver.collectTasks[sideIndex]).To(HaveLen(1)) 126 | Expect(driver.collectTasks[sideIndex][0].data).To(Equal(data)) 127 | Expect(driver.collectTasks[sideIndex][0].ports). 128 | To(HaveLen(3)) 129 | }) 130 | 131 | It("should do feed in", func() { 132 | remotePort1 := NewMockPort(mockCtrl) 133 | remotePort2 := NewMockPort(mockCtrl) 134 | remotePort3 := NewMockPort(mockCtrl) 135 | localPort1 := portFactory.ports["Driver.DeviceNorth[0]"] 136 | localPort2 := portFactory.ports["Driver.DeviceNorth[1]"] 137 | localPort3 := portFactory.ports["Driver.DeviceNorth[2]"] 138 | 139 | localPort1.EXPECT().CanSend().Return(true).AnyTimes() 140 | localPort2.EXPECT().CanSend().Return(true).AnyTimes() 141 | localPort3.EXPECT().CanSend().Return(true).AnyTimes() 142 | 143 | data := []uint32{1, 2, 3, 4, 5, 6} 144 | 145 | sideIndex := int(cgra.North) 146 | localPort1.EXPECT().Deliver(gomock.Any()).Return(nil).AnyTimes() 147 | localPort2.EXPECT().Deliver(gomock.Any()).Return(nil).AnyTimes() 148 | localPort3.EXPECT().Deliver(gomock.Any()).Return(nil).AnyTimes() 149 | 150 | // RemotePort is a string type in akita v4, so we can use port names 151 | remotePort1.EXPECT().AsRemote().Return(sim.RemotePort("remotePort1")).AnyTimes() 152 | remotePort2.EXPECT().AsRemote().Return(sim.RemotePort("remotePort2")).AnyTimes() 153 | remotePort3.EXPECT().AsRemote().Return(sim.RemotePort("remotePort3")).AnyTimes() 154 | 155 | localPorts := []sim.Port{localPort1, localPort2, localPort3} 156 | remotePorts := []sim.RemotePort{ 157 | sim.RemotePort("remotePort1"), 158 | sim.RemotePort("remotePort2"), 159 | sim.RemotePort("remotePort3"), 160 | } 161 | driver.feedInTasks[sideIndex] = []*feedInTask{ 162 | { 163 | data: data, 164 | localPorts: localPorts, 165 | remotePorts: remotePorts, 166 | stride: 3, 167 | color: 0, // R 168 | round: 0, 169 | }, 170 | } 171 | 172 | expectPortsToSend( 173 | []*MockPort{localPort1, localPort2, localPort3}, 174 | []*MockPort{remotePort1, remotePort2, remotePort3}, 175 | []uint32{1, 2, 3}, 176 | ) 177 | 178 | driver.Tick() 179 | 180 | expectPortsToSend( 181 | []*MockPort{localPort1, localPort2, localPort3}, 182 | []*MockPort{remotePort1, remotePort2, remotePort3}, 183 | []uint32{4, 5, 6}, 184 | ) 185 | 186 | driver.Tick() 187 | 188 | Expect(driver.feedInTasks[sideIndex]).To(BeEmpty()) 189 | }) 190 | 191 | It("should do collect", func() { 192 | localPort1 := portFactory.ports["Driver.DeviceNorth[0]"] 193 | localPort2 := portFactory.ports["Driver.DeviceNorth[1]"] 194 | localPort3 := portFactory.ports["Driver.DeviceNorth[2]"] 195 | 196 | data := make([]uint32, 6) 197 | 198 | sideIndex := int(cgra.North) 199 | ports := []sim.Port{localPort1, localPort2, localPort3} 200 | driver.collectTasks[sideIndex] = []*collectTask{ 201 | { 202 | data: data, 203 | ports: ports, 204 | stride: 3, 205 | color: 0, // R 206 | round: 0, 207 | }, 208 | } 209 | 210 | // Mock PeekIncoming and RetrieveIncoming for first round 211 | // Note: allDataReady checks PeekIncoming multiple times (once per port), 212 | // then doOneCollectTask calls RetrieveIncoming for each port 213 | msg1 := cgra.MoveMsgBuilder{}.WithData(cgra.NewScalar(1)).Build() 214 | msg2 := cgra.MoveMsgBuilder{}.WithData(cgra.NewScalar(2)).Build() 215 | msg3 := cgra.MoveMsgBuilder{}.WithData(cgra.NewScalar(3)).Build() 216 | // allDataReady will call PeekIncoming for all ports (at least once each) 217 | // Since allDataReady may be called multiple times, we use AnyTimes 218 | localPort1.EXPECT().PeekIncoming().Return(msg1).AnyTimes() 219 | localPort2.EXPECT().PeekIncoming().Return(msg2).AnyTimes() 220 | localPort3.EXPECT().PeekIncoming().Return(msg3).AnyTimes() 221 | // Then doOneCollectTask will call RetrieveIncoming for each port 222 | localPort1.EXPECT().RetrieveIncoming().Return(msg1).Times(1) 223 | localPort2.EXPECT().RetrieveIncoming().Return(msg2).Times(1) 224 | localPort3.EXPECT().RetrieveIncoming().Return(msg3).Times(1) 225 | 226 | driver.Tick() 227 | 228 | // Mock PeekIncoming and RetrieveIncoming for second round 229 | msg4 := cgra.MoveMsgBuilder{}.WithData(cgra.NewScalar(4)).Build() 230 | msg5 := cgra.MoveMsgBuilder{}.WithData(cgra.NewScalar(5)).Build() 231 | msg6 := cgra.MoveMsgBuilder{}.WithData(cgra.NewScalar(6)).Build() 232 | localPort1.EXPECT().PeekIncoming().Return(msg4).AnyTimes() 233 | localPort2.EXPECT().PeekIncoming().Return(msg5).AnyTimes() 234 | localPort3.EXPECT().PeekIncoming().Return(msg6).AnyTimes() 235 | localPort1.EXPECT().RetrieveIncoming().Return(msg4).Times(1) 236 | localPort2.EXPECT().RetrieveIncoming().Return(msg5).Times(1) 237 | localPort3.EXPECT().RetrieveIncoming().Return(msg6).Times(1) 238 | 239 | driver.Tick() 240 | 241 | Expect(driver.collectTasks[sideIndex]).To(BeEmpty()) 242 | Expect(data).To(Equal([]uint32{1, 2, 3, 4, 5, 6})) 243 | }) 244 | }) 245 | 246 | func expectPortsToSend( 247 | localPorts []*MockPort, 248 | remotePorts []*MockPort, 249 | data []uint32, 250 | ) { 251 | for i, port := range localPorts { 252 | func(port *MockPort, data uint32, i int) { 253 | port.EXPECT(). 254 | Send(gomock.Any()). 255 | Do(func(msg *cgra.MoveMsg) { 256 | // msg.Src is a RemotePort (string), not the port itself 257 | Expect(string(msg.Src)).NotTo(BeEmpty()) 258 | // msg.Dst is a RemotePort (string), not a MockPort 259 | Expect(string(msg.Dst)).NotTo(BeEmpty()) 260 | Expect(msg.Data).To(Equal(cgra.NewScalar(data))) 261 | }) 262 | }(port, data[i], i) 263 | } 264 | } 265 | 266 | func expectPortsToRecv( 267 | ports []*MockPort, 268 | data []uint32, 269 | ) { 270 | for i, port := range ports { 271 | func(port *MockPort, data uint32, i int) { 272 | msg := cgra.MoveMsgBuilder{}.WithData(cgra.NewScalar(data)).Build() 273 | port.EXPECT().RetrieveIncoming().Return(msg) 274 | }(port, data[i], i) 275 | } 276 | } 277 | -------------------------------------------------------------------------------- /test/add/arith_test.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "math/rand" 6 | "testing" 7 | "time" 8 | "unsafe" 9 | 10 | "github.com/sarchlab/akita/v4/sim" 11 | "github.com/sarchlab/zeonica/api" 12 | "github.com/sarchlab/zeonica/cgra" 13 | "github.com/sarchlab/zeonica/config" 14 | "github.com/sarchlab/zeonica/core" 15 | ) 16 | 17 | func TestAddOperationWithRandomData(t *testing.T) { 18 | // Set test parameters 19 | width := 2 20 | height := 2 21 | length := 16 22 | 23 | // Create test data 24 | src := make([]uint32, length) 25 | dst := make([]uint32, length) 26 | 27 | // Generate random test data 28 | rand.Seed(time.Now().UnixNano()) 29 | minI := int32(-10) 30 | maxI := int32(10) 31 | for i := 0; i < length; i++ { 32 | INum := minI + rand.Int31n(maxI-minI+1) 33 | src[i] = *(*uint32)(unsafe.Pointer(&INum)) 34 | } 35 | 36 | // Create simulation engine 37 | engine := sim.NewSerialEngine() 38 | 39 | // Create driver 40 | driver := api.DriverBuilder{}. 41 | WithEngine(engine). 42 | WithFreq(1 * sim.GHz). 43 | Build("Driver") 44 | 45 | // Create device 46 | device := config.DeviceBuilder{}. 47 | WithEngine(engine). 48 | WithFreq(1 * sim.GHz). 49 | WithWidth(width). 50 | WithHeight(height). 51 | Build("Device") 52 | 53 | driver.RegisterDevice(device) 54 | 55 | // Load program 56 | program := core.LoadProgramFileFromYAML("./test_add.yaml") 57 | if len(program) == 0 { 58 | t.Fatal("Failed to load program") 59 | } 60 | 61 | // Set data flow - input from west, output to east 62 | driver.FeedIn(src, cgra.West, [2]int{0, height}, height, "R") 63 | driver.Collect(dst, cgra.East, [2]int{0, height}, height, "R") 64 | 65 | // Map program to all cores 66 | for x := 0; x < width; x++ { 67 | for y := 0; y < height; y++ { 68 | coord := fmt.Sprintf("(%d,%d)", x, y) 69 | if prog, exists := program[coord]; exists { 70 | driver.MapProgram(prog, [2]int{x, y}) 71 | } 72 | } 73 | } 74 | 75 | // Run simulation 76 | driver.Run() 77 | 78 | // Convert results and verify 79 | srcI := make([]int32, length) 80 | dstI := make([]int32, length) 81 | for i := 0; i < length; i++ { 82 | srcI[i] = *(*int32)(unsafe.Pointer(&src[i])) 83 | dstI[i] = *(*int32)(unsafe.Pointer(&dst[i])) 84 | } 85 | 86 | // Verify results: output should be input+2 87 | t.Log("=== ADD Test Results ===") 88 | allPassed := true 89 | for i := 0; i < length; i++ { 90 | expected := srcI[i] + 2 91 | actual := dstI[i] 92 | 93 | if actual != expected { 94 | t.Errorf("Index %d: Input=%d, Expected=%d, Actual=%d", 95 | i, srcI[i], expected, actual) 96 | allPassed = false 97 | } else { 98 | t.Logf("Index %d: Input=%d, Output=%d ✓", i, srcI[i], actual) 99 | } 100 | } 101 | 102 | if allPassed { 103 | t.Log("✅ ADD tests passed!") 104 | } else { 105 | t.Fatal("❌ ADD tests failed!") 106 | } 107 | } 108 | 109 | func TestSubOperationWithRandomData(t *testing.T) { 110 | // Set test parameters 111 | width := 2 112 | height := 2 113 | length := 16 114 | 115 | // Create test data 116 | src := make([]uint32, length) 117 | dst := make([]uint32, length) 118 | 119 | // Generate random test data 120 | rand.Seed(time.Now().UnixNano()) 121 | minI := int32(-10) 122 | maxI := int32(10) 123 | for i := 0; i < length; i++ { 124 | INum := minI + rand.Int31n(maxI-minI+1) 125 | src[i] = *(*uint32)(unsafe.Pointer(&INum)) 126 | } 127 | 128 | // Create simulation engine 129 | engine := sim.NewSerialEngine() 130 | 131 | // Create driver 132 | driver := api.DriverBuilder{}. 133 | WithEngine(engine). 134 | WithFreq(1 * sim.GHz). 135 | Build("Driver") 136 | 137 | // Create device 138 | device := config.DeviceBuilder{}. 139 | WithEngine(engine). 140 | WithFreq(1 * sim.GHz). 141 | WithWidth(width). 142 | WithHeight(height). 143 | Build("Device") 144 | 145 | driver.RegisterDevice(device) 146 | 147 | // Load program 148 | program := core.LoadProgramFileFromYAML("./test_sub.yaml") 149 | if len(program) == 0 { 150 | t.Fatal("Failed to load program") 151 | } 152 | 153 | // Set data flow - input from north, output to south 154 | driver.FeedIn(src, cgra.South, [2]int{0, width}, width, "R") 155 | driver.Collect(dst, cgra.North, [2]int{0, width}, width, "R") 156 | 157 | // Map program to all cores 158 | for x := 0; x < width; x++ { 159 | for y := 0; y < height; y++ { 160 | coord := fmt.Sprintf("(%d,%d)", x, y) 161 | if prog, exists := program[coord]; exists { 162 | driver.MapProgram(prog, [2]int{x, y}) 163 | } 164 | } 165 | } 166 | 167 | // Run simulation 168 | driver.Run() 169 | 170 | // Convert results and verify 171 | srcI := make([]int32, length) 172 | dstI := make([]int32, length) 173 | for i := 0; i < length; i++ { 174 | srcI[i] = *(*int32)(unsafe.Pointer(&src[i])) 175 | dstI[i] = *(*int32)(unsafe.Pointer(&dst[i])) 176 | } 177 | 178 | // Verify results: output should be input-2 179 | t.Log("=== SUB Test Results ===") 180 | allPassed := true 181 | for i := 0; i < length; i++ { 182 | expected := srcI[i] - 2 183 | actual := dstI[i] 184 | 185 | if actual != expected { 186 | t.Errorf("Index %d: Input=%d, Expected=%d, Actual=%d", 187 | i, srcI[i], expected, actual) 188 | allPassed = false 189 | } else { 190 | t.Logf("Index %d: Input=%d, Output=%d ✓", i, srcI[i], actual) 191 | } 192 | } 193 | 194 | if allPassed { 195 | t.Log("✅ SUB tests passed!") 196 | } else { 197 | t.Fatal("❌ SUB tests failed!") 198 | } 199 | } 200 | 201 | func TestMulOperationWithRandomData(t *testing.T) { 202 | // Set test parameters 203 | width := 2 204 | height := 2 205 | length := 16 206 | 207 | // Create test data 208 | src := make([]uint32, length) 209 | dst := make([]uint32, length) 210 | 211 | // Generate random test data 212 | rand.Seed(time.Now().UnixNano()) 213 | minI := int32(-10) 214 | maxI := int32(10) 215 | for i := 0; i < length; i++ { 216 | INum := minI + rand.Int31n(maxI-minI+1) 217 | src[i] = *(*uint32)(unsafe.Pointer(&INum)) 218 | } 219 | 220 | // Create simulation engine 221 | engine := sim.NewSerialEngine() 222 | 223 | // Create driver 224 | driver := api.DriverBuilder{}. 225 | WithEngine(engine). 226 | WithFreq(1 * sim.GHz). 227 | Build("Driver") 228 | 229 | // Create device 230 | device := config.DeviceBuilder{}. 231 | WithEngine(engine). 232 | WithFreq(1 * sim.GHz). 233 | WithWidth(width). 234 | WithHeight(height). 235 | Build("Device") 236 | 237 | driver.RegisterDevice(device) 238 | 239 | // Load program 240 | program := core.LoadProgramFileFromYAML("./test_mul.yaml") 241 | if len(program) == 0 { 242 | t.Fatal("Failed to load program") 243 | } 244 | 245 | // Set data flow - input from east, output to west 246 | driver.FeedIn(src, cgra.East, [2]int{0, height}, height, "R") 247 | driver.Collect(dst, cgra.West, [2]int{0, height}, height, "R") 248 | 249 | // Map program to all cores 250 | for x := 0; x < width; x++ { 251 | for y := 0; y < height; y++ { 252 | coord := fmt.Sprintf("(%d,%d)", x, y) 253 | if prog, exists := program[coord]; exists { 254 | driver.MapProgram(prog, [2]int{x, y}) 255 | } 256 | } 257 | } 258 | 259 | // Run simulation 260 | driver.Run() 261 | 262 | // Convert results and verify 263 | srcI := make([]int32, length) 264 | dstI := make([]int32, length) 265 | for i := 0; i < length; i++ { 266 | srcI[i] = *(*int32)(unsafe.Pointer(&src[i])) 267 | dstI[i] = *(*int32)(unsafe.Pointer(&dst[i])) 268 | } 269 | 270 | // Verify results: output should be input*2 271 | t.Log("=== MUL Test Results ===") 272 | allPassed := true 273 | for i := 0; i < length; i++ { 274 | expected := srcI[i] * 4 275 | actual := dstI[i] 276 | 277 | if actual != expected { 278 | t.Errorf("Index %d: Input=%d, Expected=%d, Actual=%d", 279 | i, srcI[i], expected, actual) 280 | allPassed = false 281 | } else { 282 | t.Logf("Index %d: Input=%d, Output=%d ✓", i, srcI[i], actual) 283 | } 284 | } 285 | 286 | if allPassed { 287 | t.Log("✅ MUL tests passed!") 288 | } else { 289 | t.Fatal("❌ MUL tests failed!") 290 | } 291 | } 292 | 293 | func TestDivOperationWithRandomData(t *testing.T) { 294 | // Set test parameters 295 | width := 2 296 | height := 2 297 | length := 16 298 | 299 | // Create test data 300 | src := make([]uint32, length) 301 | dst := make([]uint32, length) 302 | 303 | // Generate random test data (avoid division by zero) 304 | rand.Seed(time.Now().UnixNano()) 305 | minI := int32(-20) 306 | maxI := int32(20) 307 | for i := 0; i < length; i++ { 308 | INum := minI + rand.Int31n(maxI-minI+1) 309 | // Ensure data is a multiple of 4 to avoid division precision issues 310 | if INum%4 != 0 { 311 | INum = INum - INum%4 + 4 312 | } 313 | src[i] = *(*uint32)(unsafe.Pointer(&INum)) 314 | } 315 | 316 | // Create simulation engine 317 | engine := sim.NewSerialEngine() 318 | 319 | // Create driver 320 | driver := api.DriverBuilder{}. 321 | WithEngine(engine). 322 | WithFreq(1 * sim.GHz). 323 | Build("Driver") 324 | 325 | // Create device 326 | device := config.DeviceBuilder{}. 327 | WithEngine(engine). 328 | WithFreq(1 * sim.GHz). 329 | WithWidth(width). 330 | WithHeight(height). 331 | Build("Device") 332 | 333 | driver.RegisterDevice(device) 334 | 335 | // Load program 336 | program := core.LoadProgramFileFromYAML("./test_div.yaml") 337 | if len(program) == 0 { 338 | t.Fatal("Failed to load program") 339 | } 340 | 341 | // Set data flow - input from south, output to north 342 | driver.FeedIn(src, cgra.North, [2]int{0, width}, width, "R") 343 | driver.Collect(dst, cgra.South, [2]int{0, width}, width, "R") 344 | 345 | // Map program to all cores 346 | for x := 0; x < width; x++ { 347 | for y := 0; y < height; y++ { 348 | coord := fmt.Sprintf("(%d,%d)", x, y) 349 | if prog, exists := program[coord]; exists { 350 | driver.MapProgram(prog, [2]int{x, y}) 351 | } 352 | } 353 | } 354 | 355 | // Run simulation 356 | driver.Run() 357 | 358 | // Convert results and verify 359 | srcI := make([]int32, length) 360 | dstI := make([]int32, length) 361 | for i := 0; i < length; i++ { 362 | srcI[i] = *(*int32)(unsafe.Pointer(&src[i])) 363 | dstI[i] = *(*int32)(unsafe.Pointer(&dst[i])) 364 | } 365 | 366 | // Verify results: output should be input/2 367 | t.Log("=== DIV Test Results ===") 368 | allPassed := true 369 | for i := 0; i < length; i++ { 370 | expected := srcI[i] / 4 371 | actual := dstI[i] 372 | 373 | if actual != expected { 374 | t.Errorf("Index %d: Input=%d, Expected=%d, Actual=%d", 375 | i, srcI[i], expected, actual) 376 | allPassed = false 377 | } else { 378 | t.Logf("Index %d: Input=%d, Output=%d ✓", i, srcI[i], actual) 379 | } 380 | } 381 | 382 | if allPassed { 383 | t.Log("✅ DIV tests passed!") 384 | } else { 385 | t.Fatal("❌ DIV tests failed!") 386 | } 387 | } 388 | -------------------------------------------------------------------------------- /test/testbench/fir/fir4x4.yaml: -------------------------------------------------------------------------------- 1 | array_config: 2 | columns: 4 3 | rows: 4 4 | compiled_ii: 5 5 | cores: 6 | - column: 0 7 | row: 1 8 | core_id: "4" 9 | entries: 10 | - entry_id: "entry0" 11 | instructions: 12 | - timestep: 3 13 | operations: 14 | - opcode: "GRANT_ONCE" 15 | src_operands: 16 | - operand: "#0" 17 | color: "RED" 18 | dst_operands: 19 | - operand: "$0" 20 | color: "RED" 21 | - timestep: 4 22 | operations: 23 | - opcode: "PHI" 24 | src_operands: 25 | - operand: "NORTH" 26 | color: "RED" 27 | - operand: "$0" 28 | color: "RED" 29 | dst_operands: 30 | - operand: "EAST" 31 | color: "RED" 32 | - column: 1 33 | row: 1 34 | core_id: "5" 35 | entries: 36 | - entry_id: "entry0" 37 | instructions: 38 | - timestep: 5 39 | operations: 40 | - opcode: "DATA_MOV" 41 | src_operands: 42 | - operand: "WEST" 43 | color: "RED" 44 | dst_operands: 45 | - operand: "NORTH" 46 | color: "RED" 47 | - opcode: "DATA_MOV" 48 | src_operands: 49 | - operand: "NORTH" 50 | color: "RED" 51 | dst_operands: 52 | - operand: "$0" 53 | color: "RED" 54 | - timestep: 8 55 | operations: 56 | - opcode: "GRANT_PREDICATE" 57 | src_operands: 58 | - operand: "NORTH" 59 | color: "RED" 60 | - operand: "$0" 61 | color: "RED" 62 | dst_operands: 63 | - operand: "EAST" 64 | color: "RED" 65 | - column: 2 66 | row: 1 67 | core_id: "6" 68 | entries: 69 | - entry_id: "entry0" 70 | instructions: 71 | - timestep: 3 72 | operations: 73 | - opcode: "LOAD" 74 | src_operands: 75 | - operand: "EAST" 76 | color: "RED" 77 | dst_operands: 78 | - operand: "NORTH" 79 | color: "RED" 80 | - timestep: 9 81 | operations: 82 | - opcode: "RETURN" 83 | src_operands: 84 | - operand: "WEST" 85 | color: "RED" 86 | - column: 3 87 | row: 1 88 | core_id: "7" 89 | entries: 90 | - entry_id: "entry0" 91 | instructions: 92 | - timestep: 2 93 | operations: 94 | - opcode: "GEP" 95 | src_operands: 96 | - operand: "NORTH" 97 | color: "RED" 98 | dst_operands: 99 | - operand: "WEST" 100 | color: "RED" 101 | - column: 0 102 | row: 2 103 | core_id: "8" 104 | entries: 105 | - entry_id: "entry0" 106 | instructions: 107 | - timestep: 6 108 | operations: 109 | - opcode: "DATA_MOV" 110 | src_operands: 111 | - operand: "EAST" 112 | color: "RED" 113 | dst_operands: 114 | - operand: "$0" 115 | color: "RED" 116 | - timestep: 8 117 | operations: 118 | - opcode: "GRANT_PREDICATE" 119 | src_operands: 120 | - operand: "EAST" 121 | color: "RED" 122 | - operand: "$0" 123 | color: "RED" 124 | dst_operands: 125 | - operand: "SOUTH" 126 | color: "RED" 127 | - column: 1 128 | row: 2 129 | core_id: "9" 130 | entries: 131 | - entry_id: "entry0" 132 | instructions: 133 | - timestep: 4 134 | operations: 135 | - opcode: "DATA_MOV" 136 | src_operands: 137 | - operand: "EAST" 138 | color: "RED" 139 | dst_operands: 140 | - operand: "SOUTH" 141 | color: "RED" 142 | - timestep: 5 143 | operations: 144 | - opcode: "DATA_MOV" 145 | src_operands: 146 | - operand: "EAST" 147 | color: "RED" 148 | dst_operands: 149 | - operand: "WEST" 150 | color: "RED" 151 | - timestep: 6 152 | operations: 153 | - opcode: "DATA_MOV" 154 | src_operands: 155 | - operand: "SOUTH" 156 | color: "RED" 157 | dst_operands: 158 | - operand: "$0" 159 | color: "RED" 160 | - timestep: 7 161 | operations: 162 | - opcode: "ADD" 163 | src_operands: 164 | - operand: "NORTH" 165 | color: "RED" 166 | - operand: "$0" 167 | color: "RED" 168 | dst_operands: 169 | - operand: "WEST" 170 | color: "RED" 171 | - operand: "SOUTH" 172 | color: "RED" 173 | - column: 2 174 | row: 2 175 | core_id: "10" 176 | entries: 177 | - entry_id: "entry0" 178 | instructions: 179 | - timestep: 2 180 | operations: 181 | - opcode: "DATA_MOV" 182 | src_operands: 183 | - operand: "EAST" 184 | color: "RED" 185 | dst_operands: 186 | - operand: "$0" 187 | color: "RED" 188 | - timestep: 3 189 | operations: 190 | - opcode: "ICMP_EQ" 191 | src_operands: 192 | - operand: "EAST" 193 | color: "RED" 194 | - operand: "#2" # for test, change to #32 for real test 195 | color: "RED" 196 | dst_operands: 197 | - operand: "$0" 198 | color: "RED" 199 | - operand: "WEST" 200 | color: "RED" 201 | - timestep: 4 202 | operations: 203 | - opcode: "NOT" 204 | src_operands: 205 | - operand: "$0" 206 | color: "RED" 207 | dst_operands: 208 | - operand: "$1" 209 | color: "RED" 210 | - operand: "WEST" 211 | color: "RED" 212 | - opcode: "DATA_MOV" 213 | src_operands: 214 | - operand: "SOUTH" 215 | color: "RED" 216 | dst_operands: 217 | - operand: "NORTH" 218 | color: "RED" 219 | - timestep: 5 220 | operations: 221 | - opcode: "GRANT_PREDICATE" 222 | src_operands: 223 | - operand: "$0" 224 | color: "RED" 225 | - operand: "$1" 226 | color: "RED" 227 | dst_operands: 228 | - operand: "EAST" 229 | color: "RED" 230 | - column: 3 231 | row: 2 232 | core_id: "11" 233 | entries: 234 | - entry_id: "entry0" 235 | instructions: 236 | - timestep: 0 237 | operations: 238 | - opcode: "GRANT_ONCE" 239 | src_operands: 240 | - operand: "#0" 241 | color: "RED" 242 | dst_operands: 243 | - operand: "$0" 244 | color: "RED" 245 | - timestep: 1 246 | operations: 247 | - opcode: "PHI" 248 | src_operands: 249 | - operand: "WEST" 250 | color: "RED" 251 | - operand: "$0" 252 | color: "RED" 253 | dst_operands: 254 | - operand: "NORTH" 255 | color: "RED" 256 | - operand: "SOUTH" 257 | color: "RED" 258 | - operand: "$0" 259 | color: "RED" 260 | - timestep: 2 261 | operations: 262 | - opcode: "ADD" 263 | src_operands: 264 | - operand: "$0" 265 | color: "RED" 266 | - operand: "#1" 267 | color: "RED" 268 | dst_operands: 269 | - operand: "WEST" 270 | color: "RED" 271 | - column: 1 272 | row: 3 273 | core_id: "13" 274 | entries: 275 | - entry_id: "entry0" 276 | instructions: 277 | - timestep: 6 278 | operations: 279 | - opcode: "DATA_MOV" 280 | src_operands: 281 | - operand: "EAST" 282 | color: "RED" 283 | dst_operands: 284 | - operand: "SOUTH" 285 | color: "RED" 286 | - column: 2 287 | row: 3 288 | core_id: "14" 289 | entries: 290 | - entry_id: "entry0" 291 | instructions: 292 | - timestep: 4 293 | operations: 294 | - opcode: "DATA_MOV" 295 | src_operands: 296 | - operand: "EAST" 297 | color: "RED" 298 | dst_operands: 299 | - operand: "$0" 300 | color: "RED" 301 | - timestep: 5 302 | operations: 303 | - opcode: "MUL" 304 | src_operands: 305 | - operand: "SOUTH" 306 | color: "RED" 307 | - operand: "$0" 308 | color: "RED" 309 | dst_operands: 310 | - operand: "WEST" 311 | color: "RED" 312 | - column: 3 313 | row: 3 314 | core_id: "15" 315 | entries: 316 | - entry_id: "entry0" 317 | instructions: 318 | - timestep: 2 319 | operations: 320 | - opcode: "GEP" 321 | src_operands: 322 | - operand: "SOUTH" 323 | color: "RED" 324 | dst_operands: 325 | - operand: "$0" 326 | color: "RED" 327 | - timestep: 3 328 | operations: 329 | - opcode: "LOAD" 330 | src_operands: 331 | - operand: "$0" 332 | color: "RED" 333 | dst_operands: 334 | - operand: "WEST" 335 | color: "RED" --------------------------------------------------------------------------------