summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rwxr-xr-xassemble.go281
-rwxr-xr-xgo.mod3
-rwxr-xr-xparse.go51
-rwxr-xr-xqdmabin2355595 -> 0 bytes
-rwxr-xr-xqdma.go243
-rwxr-xr-xsymbol.go52
-rwxr-xr-xtest6.asm18
-rwxr-xr-xtest6.binbin0 -> 28 bytes
-rwxr-xr-x[-rw-r--r--]tests/test5.binbin56 -> 56 bytes
9 files changed, 405 insertions, 243 deletions
diff --git a/assemble.go b/assemble.go
new file mode 100755
index 0000000..98af916
--- /dev/null
+++ b/assemble.go
@@ -0,0 +1,281 @@
+package main
+
+import (
+ "bufio"
+ "encoding/binary"
+ "fmt"
+ "os"
+ "regexp"
+ "strconv"
+ "strings"
+)
+
+var isText bool = true
+
+var Instructions = map[string]struct {
+ isRtype bool
+ opcode uint32
+}{
+ "add": {true, 32},
+ "addi": {false, 8},
+ "addiu": {false, 9},
+ "sub": {true, 34},
+ "subu": {true, 35},
+ "mult": {true, 24},
+ "multu": {true, 25},
+ "div": {true, 26},
+ "divu": {true, 27},
+ "and": {true, 36},
+ "andi": {false, 12},
+ "or": {true, 37},
+ "ori": {false, 13},
+ "xor": {true, 38},
+ "xori": {false, 14},
+ "sll": {true, 0},
+ "sra": {true, 3},
+ "srl": {true, 2},
+ "lw": {false, 35},
+ "sw": {false, 43},
+ "slt": {true, 42},
+ "slti": {false, 10},
+ "sltiu": {false, 11},
+ "sltu": {true, 43},
+ "beq": {false, 4},
+ "bne": {false, 5},
+ "j": {false, 2},
+ "jal": {false, 3},
+ "jr": {true, 8},
+ "syscall": {false, 12},
+}
+
+var RegNums = map[string]uint32{
+ "$zero": 0,
+ "$at": 1,
+ "$v0": 2,
+ "$v1": 3,
+ "$a0": 4,
+ "$a1": 5,
+ "$a2": 6,
+ "$a3": 7,
+ "$t0": 8,
+ "$t1": 9,
+ "$t2": 10,
+ "$t3": 11,
+ "$t4": 12,
+ "$t5": 13,
+ "$t6": 14,
+ "$t7": 15,
+ "$s0": 16,
+ "$s1": 17,
+ "$s2": 18,
+ "$s3": 19,
+ "$s4": 20,
+ "$s5": 21,
+ "$s6": 22,
+ "$s7": 23,
+ "$t8": 24,
+ "$t9": 25,
+ "$k0": 26,
+ "$k1": 27,
+ "$gp": 28,
+ "$sp": 29,
+ "$fp": 30,
+ "$ra": 31,
+}
+
+func Encode(inst []string, pc int32) ([]byte, error) {
+ var ret uint32 = 0
+ var imm int16
+ bytes := make([]byte, 4)
+ for _, s := range inst {
+ switch s {
+ case "syscall":
+ binary.NativeEndian.PutUint32(bytes, 12)
+ return bytes, nil
+ case "nop":
+ binary.NativeEndian.PutUint32(bytes, 0)
+ return bytes, nil
+ }
+ }
+
+ function := Instructions[inst[0]]
+ if function.isRtype && function.opcode == 8 {
+ ret = (RegNums[inst[1]] << 21) | function.opcode
+ } else if function.isRtype {
+ ret = (RegNums[inst[2]] << 21) | (RegNums[inst[3]] <<
+ 16) | (RegNums[inst[1]] << 11) | function.opcode
+ } else if function.opcode == 2 || function.opcode == 3 {
+ label, _ := labels[inst[1]]
+ ret = (function.opcode << 26) | uint32(label&0x03FFFFFF)
+ } else if function.opcode == 35 || function.opcode == 43 {
+ immReg, err := regexp.Compile("^[0-9]+")
+ if err != nil {
+ return nil, err
+ }
+ regReg, err := regexp.Compile("\\$([a-z]|[0-9])+")
+ if err != nil {
+ return nil, err
+ }
+ t, err := strconv.Atoi(immReg.FindString(inst[2]))
+ if err != nil {
+ return nil, err
+ }
+ imm = int16(t)
+ reg := regReg.FindString(inst[2])
+ ret = (function.opcode << 26) | (RegNums[reg] << 21) |
+ (RegNums[inst[1]] << 16) | (0xFFFF & uint32(imm))
+ } else {
+ addr, isLabel := labels[inst[3]]
+ if isLabel {
+ imm = int16(int32(addr) - pc - 12)
+ } else {
+ i, err := strconv.Atoi(inst[3])
+ if err != nil {
+ return nil, err
+ }
+ imm = int16(i)
+ }
+ ret = (function.opcode << 26) | (RegNums[inst[2]] << 21) |
+ (RegNums[inst[1]] << 16) | (0xFFFF & uint32(imm))
+ }
+ binary.NativeEndian.PutUint32(bytes, ret)
+ return bytes, nil
+}
+
+func EncodeData(line []string) ([]byte, error) {
+ var size int
+ var err error = nil
+ var data int64
+ isString := false
+ isData := false
+ nullTerm := false
+
+ line[1] = strings.ReplaceAll(line[1], "\"", "")
+
+ switch line[0] {
+ case ".space":
+ size, err = strconv.Atoi(line[1])
+ case ".word":
+ size = 4
+ isData = true
+ case ".byte":
+ size = 1
+ isData = true
+ case ".half":
+ size = 2
+ isData = true
+ case ".asciiz":
+ size = len(line[1]) + 1
+ isString = true
+ nullTerm = true
+ case ".ascii":
+ size = len(line[1])
+ isString = true
+ }
+ if err != nil {
+ return nil, err
+ }
+ bytes := make([]byte, size)
+
+ if isData {
+ if strings.Contains(line[1], "0x") {
+ line[1] = strings.ReplaceAll(line[1], "0x", "")
+ var t uint64
+ t, err = strconv.ParseUint(line[1], 16, size*8)
+ data = int64(t)
+ } else {
+ data, err = strconv.ParseInt(line[1], 10, size*8)
+ }
+ if err != nil {
+ return nil, err
+ }
+ switch size {
+ case 1:
+ bytes[0] = uint8(data)
+ case 2:
+ binary.NativeEndian.PutUint16(bytes, uint16(data))
+ case 4:
+ binary.NativeEndian.PutUint32(bytes, uint32(data))
+ }
+ } else if isString {
+ if nullTerm {
+ for i, b := range []byte(line[1]) {
+ bytes[i] = b
+ }
+ bytes[size-1] = 0
+ } else {
+ bytes = []byte(line[1])
+ }
+ }
+
+ return bytes, nil
+}
+
+func Assemble(path string) {
+ file, err := os.Open(path)
+ if err != nil {
+ panic(err)
+ }
+ defer file.Close()
+
+ out, err := os.Create(strings.ReplaceAll(path, ".asm", ".bin"))
+ if err != nil {
+ panic(err)
+ }
+ defer out.Close()
+
+ scanner := bufio.NewScanner(file)
+ for i := 0; scanner.Scan(); i += 4 {
+ var s string = scanner.Text()
+ if s == "" {
+ i -= 4
+ continue
+ } else if s == ".data" {
+ isText = false
+ continue
+ } else if s == ".text" {
+ isText = true
+ continue
+ }
+
+ inst, err := Parse(s)
+ if err != nil {
+ panic(err)
+ }
+
+ _, isLabel := labels[strings.ReplaceAll(inst[0], ":", "")]
+ if isLabel {
+ inst = inst[1:]
+ }
+
+ if len(inst) == 0 || (len(inst) == 1 && inst[0] == "") {
+ i -= 4
+ continue
+ }
+
+ var bytes []byte
+ if isText {
+ bytes, err = Encode(inst, int32(i))
+ } else {
+ bytes, err = EncodeData(inst)
+ }
+ if err != nil {
+ fmt.Fprintf(os.Stderr, "while encoding %s: %v", s, err)
+ panic(err)
+ }
+ if _, err = out.Write(bytes); err != nil {
+ panic(err)
+ }
+ }
+
+ /*
+ // Write the new starting PC into the header
+ if _, err := out.Seek(0, io.SeekStart); err != nil {
+ panic(err)
+ }
+ */
+
+ if err := scanner.Err(); err != nil {
+ panic(err)
+ }
+}
diff --git a/go.mod b/go.mod
new file mode 100755
index 0000000..9c9af7e
--- /dev/null
+++ b/go.mod
@@ -0,0 +1,3 @@
+module github.com/JacobMcDonnell/qdma
+
+go 1.22.2
diff --git a/parse.go b/parse.go
new file mode 100755
index 0000000..da0c47e
--- /dev/null
+++ b/parse.go
@@ -0,0 +1,51 @@
+package main
+
+import (
+ "regexp"
+ "strings"
+)
+
+func Parse(s string) ([]string, error) {
+ comments, err := regexp.Compile("#.*")
+ if err != nil {
+ panic(err)
+ }
+
+ edgeWs, err := regexp.Compile("(^\\s+|\\s+$)+")
+ if err != nil {
+ return nil, err
+ }
+
+ whiteSpace, err := regexp.Compile("\\s+")
+ if err != nil {
+ return nil, err
+ }
+
+ repeatComma, err := regexp.Compile(",{2,}")
+ if err != nil {
+ return nil, err
+ }
+
+ userStrings, err := regexp.Compile("\"([[:graph:]]|\\s)+\"")
+ if err != nil {
+ return nil, err
+ }
+
+ placeHolder := "__PLACE_HOLDER__"
+ phReg, err := regexp.Compile(placeHolder)
+ if err != nil {
+ return nil, err
+ }
+
+ us := userStrings.FindString(s)
+ s = userStrings.ReplaceAllString(s, placeHolder)
+ s = comments.ReplaceAllString(s, "")
+ s = edgeWs.ReplaceAllString(s, "")
+ s = whiteSpace.ReplaceAllString(s, ",")
+ s = repeatComma.ReplaceAllString(s, ",")
+ res := strings.Split(s, ",")
+ for i, arg := range res {
+ res[i] = phReg.ReplaceAllString(arg, us)
+ }
+ return res, nil
+}
diff --git a/qdma b/qdma
deleted file mode 100755
index 454c066..0000000
--- a/qdma
+++ /dev/null
Binary files differ
diff --git a/qdma.go b/qdma.go
index 8aed06a..b28dfe9 100755
--- a/qdma.go
+++ b/qdma.go
@@ -1,252 +1,9 @@
package main
import (
- "bufio"
- "encoding/binary"
- "fmt"
"os"
- "regexp"
- "strconv"
- "strings"
)
-var Instructions = map[string]struct {
- isRtype bool
- opcode uint32
-}{
- "add": {true, 32},
- "addi": {false, 8},
- "addiu": {false, 9},
- "sub": {true, 34},
- "subu": {true, 35},
- "mult": {true, 24},
- "multu": {true, 25},
- "div": {true, 26},
- "divu": {true, 27},
- "and": {true, 36},
- "andi": {false, 12},
- "or": {true, 37},
- "ori": {false, 13},
- "xor": {true, 38},
- "xori": {false, 14},
- "sll": {true, 0},
- "sra": {true, 3},
- "srl": {true, 2},
- "lw": {false, 35},
- "sw": {false, 43},
- "slt": {true, 42},
- "slti": {false, 10},
- "sltiu": {false, 11},
- "sltu": {true, 43},
- "beq": {false, 4},
- "bne": {false, 5},
- "j": {false, 2},
- "jal": {false, 3},
- "jr": {true, 8},
- "syscall": {false, 12},
-}
-
-var RegNums = map[string]uint32{
- "$zero": 0,
- "$at": 1,
- "$v0": 2,
- "$v1": 3,
- "$a0": 4,
- "$a1": 5,
- "$a2": 6,
- "$a3": 7,
- "$t0": 8,
- "$t1": 9,
- "$t2": 10,
- "$t3": 11,
- "$t4": 12,
- "$t5": 13,
- "$t6": 14,
- "$t7": 15,
- "$s0": 16,
- "$s1": 17,
- "$s2": 18,
- "$s3": 19,
- "$s4": 20,
- "$s5": 21,
- "$s6": 22,
- "$s7": 23,
- "$t8": 24,
- "$t9": 25,
- "$k0": 26,
- "$k1": 27,
- "$gp": 28,
- "$sp": 29,
- "$fp": 30,
- "$ra": 31,
-}
-
-// Map for labels and their addresses
-var labels map[string]uint = make(map[string]uint)
-
-func LabelFind(path string) {
- file, err := os.Open(path)
- if err != nil {
- panic(err)
- }
- defer file.Close()
-
- input := bufio.NewScanner(file)
-
- for i := 0; input.Scan(); i += 4 {
- if input.Text() == "" {
- i -= 4
- continue
- }
- s, err := Parse(input.Text())
- if err != nil {
- panic(err)
- }
-
- if len(s) == 1 && s[0] == "" {
- i -= 4
- continue
- }
-
- hasLabel, err := regexp.MatchString("^.*:", s[0])
- if err != nil {
- panic(err)
- }
- if hasLabel {
- labels[strings.ReplaceAll(s[0], ":", "")] = uint(i)
- if len(s) == 1 {
- i -= 4
- }
- }
- }
-}
-
-func Encode(inst []string, pc int32) (uint32, error) {
- var ret uint32 = 0
- for _, s := range inst {
- switch s {
- case "syscall":
- return 12, nil
- case "nop":
- return 0, nil
- }
- }
-
- function := Instructions[inst[0]]
- if function.isRtype && function.opcode == 8 {
- ret = (RegNums[inst[1]] << 21) | function.opcode
- } else if function.isRtype {
- ret = (RegNums[inst[2]] << 21) | (RegNums[inst[3]] <<
- 16) | (RegNums[inst[1]] << 11) | function.opcode
- } else if function.opcode == 2 || function.opcode == 3 {
- label, _ := labels[inst[1]]
- ret = (function.opcode << 26) | uint32(label&0x03FFFFFF)
- } else {
- var imm int16
- addr, isLabel := labels[inst[3]]
- if isLabel {
- imm = int16(int32(addr) - pc - 12)
- } else {
- i, err := strconv.Atoi(inst[3])
- if err != nil {
- return 0, err
- }
- imm = int16(i)
- }
- ret = (function.opcode << 26) | (RegNums[inst[2]] << 21) |
- (RegNums[inst[1]] << 16) | (0x0000FFFF & uint32(imm))
- }
- return ret, nil
-}
-
-func Assemble(path string) {
- file, err := os.Open(path)
- if err != nil {
- panic(err)
- }
- defer file.Close()
-
- out, err := os.Create(strings.ReplaceAll(path, ".asm", ".bin"))
- if err != nil {
- panic(err)
- }
- defer out.Close()
-
- scanner := bufio.NewScanner(file)
- bs := make([]byte, 4)
- for i := 0; scanner.Scan(); i += 4 {
- var s string = scanner.Text()
- if s == "" {
- i -= 4
- continue
- }
-
- inst, err := Parse(s)
- if err != nil {
- panic(err)
- }
-
- _, isLabel := labels[strings.ReplaceAll(inst[0], ":", "")]
- if isLabel {
- inst = inst[1:]
- }
-
- if len(inst) == 0 || (len(inst) == 1 && inst[0] == "") {
- i -= 4
- continue
- }
-
- bytes, err := Encode(inst, int32(i))
- if err != nil {
- fmt.Fprintf(os.Stderr, "while encoding %s: %v", s, err)
- panic(err)
- }
- binary.BigEndian.PutUint32(bs, bytes)
- _, err = out.Write(bs)
- if err != nil {
- panic(err)
- }
- }
-
- if err := scanner.Err(); err != nil {
- panic(err)
- }
-}
-
-func Parse(s string) ([]string, error) {
- /* regex to match 00($t0)
- offset, err := regexp.Compile("[0-9]+\\((.*)+\\)")
- if err != nil {
- panic(err)
- }*/
-
- comments, err := regexp.Compile("#.*")
- if err != nil {
- panic(err)
- }
-
- edgeWs, err := regexp.Compile("(^\\s+|\\s+$)+")
- if err != nil {
- return nil, err
- }
-
- whiteSpace, err := regexp.Compile("\\s+")
- if err != nil {
- return nil, err
- }
-
- repeatComma, err := regexp.Compile(",{2,}")
- if err != nil {
- return nil, err
- }
-
- s = comments.ReplaceAllString(s, "")
- s = edgeWs.ReplaceAllString(s, "")
- s = whiteSpace.ReplaceAllString(s, ",")
- s = repeatComma.ReplaceAllString(s, ",")
- return strings.Split(s, ","), nil
-}
-
func main() {
for _, arg := range os.Args[1:] {
LabelFind(arg) // First pass to find all labels.
diff --git a/symbol.go b/symbol.go
new file mode 100755
index 0000000..f63bb8e
--- /dev/null
+++ b/symbol.go
@@ -0,0 +1,52 @@
+package main
+
+import (
+ "bufio"
+ "os"
+ "regexp"
+ "strings"
+)
+
+// Map for labels and their addresses
+var labels map[string]uint = make(map[string]uint)
+
+func LabelFind(path string) {
+ file, err := os.Open(path)
+ if err != nil {
+ panic(err)
+ }
+ defer file.Close()
+
+ input := bufio.NewScanner(file)
+
+ for i := 0; input.Scan(); i += 4 {
+ k := input.Text()
+ if k == "" {
+ i -= 4
+ continue
+ } else if k == ".text" || k == ".data" {
+ i += 4
+ continue
+ }
+ s, err := Parse(k)
+ if err != nil {
+ panic(err)
+ }
+
+ if len(s) == 1 && s[0] == "" {
+ i -= 4
+ continue
+ }
+
+ hasLabel, err := regexp.MatchString("^.*:", s[0])
+ if err != nil {
+ panic(err)
+ }
+ if hasLabel {
+ labels[strings.ReplaceAll(s[0], ":", "")] = uint(i)
+ if len(s) == 1 {
+ i -= 4
+ }
+ }
+ }
+}
diff --git a/test6.asm b/test6.asm
new file mode 100755
index 0000000..3a9a21f
--- /dev/null
+++ b/test6.asm
@@ -0,0 +1,18 @@
+.text
+
+addi $t0, $zero, x
+addi $v0, $zero, 1
+lw $a0, 0($t0)
+syscall
+addi $v0, $zero, 10
+syscall
+
+.data
+
+x: .word 0xFFFFFFFF
+#fib: .space 40
+#h: .half 255
+#c: .byte 0
+#dogs: .ascii "Dogs are cool\n"
+#cats: .asciiz "cats are cool\n"
+
diff --git a/test6.bin b/test6.bin
new file mode 100755
index 0000000..8e47a8d
--- /dev/null
+++ b/test6.bin
Binary files differ
diff --git a/tests/test5.bin b/tests/test5.bin
index 61cb805..dd1cc83 100644..100755
--- a/tests/test5.bin
+++ b/tests/test5.bin
Binary files differ