From 3240bc6540044d283b09a61d7d48ed562a51ae9b Mon Sep 17 00:00:00 2001 From: Jacob McDonnell Date: Thu, 9 May 2024 19:12:42 -0400 Subject: Initial Commit --- LICENSE | 21 ++++++++++ README.md | 54 ++++++++++++++++++++++++ qdma.go | 140 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ test.asm | 10 +++++ test.bin | Bin 0 -> 32 bytes test2.asm | 21 ++++++++++ 6 files changed, 246 insertions(+) create mode 100755 LICENSE create mode 100755 README.md create mode 100755 qdma.go create mode 100755 test.asm create mode 100755 test.bin create mode 100755 test2.asm diff --git a/LICENSE b/LICENSE new file mode 100755 index 0000000..10f0753 --- /dev/null +++ b/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2024 Jacob McDonnell + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/README.md b/README.md new file mode 100755 index 0000000..fc47712 --- /dev/null +++ b/README.md @@ -0,0 +1,54 @@ +# QDMA - Quick and Dirty MIPS Assembler + +## Intro + +QDMA is a simple MIPS assembler written in Go for +[QDME](https://github.com/JacobMcDonnell/QDME), which is my simple MIPS +emulator. Currently this assembler can only handle standard instructions, +which means no sections and no predefined data outside of an I-Type +instruction. + +## Instructions + +Here is a list of supported instructions. + +|Instruction|Type|Action| +|-----------|----|------| +|add |R |rd = rs + rt| +|addu |R |rd = rs + rt| +|and |R |rd = rs & rt| +|or |R |rd = rs \| rt| +|slt |R |rd = rs < rt| +|sltu |R |rd = rs < rt| +|sub |R |rd = rs - rt| +|subu |R |rd = rs - rt| +|xor |R |rd = rs ^ rt| +|sll |R |rd = rt << shamt| +|sra |R |rd = rt >> shamt| +|srl |R |rd = rt >> shamt| +|div |R |hi = rs % rt lo = rs / rt| +|divu |R |hi = rs % rt lo = rs / rt| +|mult |R |hi, lo = rs * rt| +|multu |R |hi, lo = rs * rt| +|MFHI |R |rd = hi| +|MFLO |R |rd = lo| +|MTHI |R |rs = hi| +|MTLO |R |rs = lo| +|jr |R |pc = addr, pc = $ra| +|jalr |R |rd = pc, pc = addr| +|syscall |R |System Call| +|jal |J |$ra = pc, pc = addr| +|j |J |pc = addr| +|beq |I | pc = (rs == rt) ? imm + pc + 4 : pc| +|bne |I | pc = (rs != rt) ? imm + pc + 4 : pc| +|addi |I |rt = rs + imm| +|addiu |I |rt = rs + imm| +|andi |I |rt = rs & imm| +|ori |I |rt = rs \| imm| +|xori |I |rt = rs ^ imm| +|slti |R |rt = rs < imm| +|sltiu |R |rt = rs < imm| +|lui |I |rt = rs << 16| +|lw |I |rs = imm(rt)| +|sw |I |imm(rt) = rs| + diff --git a/qdma.go b/qdma.go new file mode 100755 index 0000000..37e83a1 --- /dev/null +++ b/qdma.go @@ -0,0 +1,140 @@ +package main + +import ( + "bufio" + "encoding/binary" + "log" + "os" + "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, +} + +func Encode(instruction string) uint32 { + var ret uint32 = 0 + if instruction == "syscall" { + return 12 + } + inst := strings.Fields(strings.ReplaceAll(instruction, ",", "")) + if Instructions[inst[0]].isRtype { + ret = (RegNums[inst[2]] << 21) | (RegNums[inst[3]] << 16) | + (RegNums[inst[1]] << 11) | Instructions[inst[0]].opcode + } else { + var imm int32 + i, err := strconv.Atoi(inst[3]) + if err != nil { + log.Fatal(err) + } + imm = int32(i) + ret = (Instructions[inst[0]].opcode << 26) | (RegNums[inst[2]] << 21) | + (RegNums[inst[1]] << 16) | uint32(imm) + } + return ret +} + +func Assemble(path string) { + file, err := os.Open(path) + if err != nil { + log.Fatal(err) + } + defer file.Close() + + out, err := os.Create(strings.ReplaceAll(path, ".asm", ".bin")) + if err != nil { + log.Fatal(err) + } + defer out.Close() + + scanner := bufio.NewScanner(file) + for scanner.Scan() { + var s string = scanner.Text() + if s != "" { + bs := make([]byte, 4) + binary.BigEndian.PutUint32(bs, Encode(s)) + _, err := out.Write(bs) + if err != nil { + log.Fatal(err) + } + } + } + + if err := scanner.Err(); err != nil { + log.Fatal(err) + } +} + +func main() { + for _, arg := range os.Args[1:] { + Assemble(arg) + } +} diff --git a/test.asm b/test.asm new file mode 100755 index 0000000..fbb450b --- /dev/null +++ b/test.asm @@ -0,0 +1,10 @@ +addi $t0, $zero, 10 +addi $t1, $zero, 12 +add $t2, $t1, $t0 + +add $a0, $t2, $zero +addi $v0, $zero, 1 +syscall + +addi $v0, $zero, 10 +syscall diff --git a/test.bin b/test.bin new file mode 100755 index 0000000..2cf7b8d Binary files /dev/null and b/test.bin differ diff --git a/test2.asm b/test2.asm new file mode 100755 index 0000000..e22cd5e --- /dev/null +++ b/test2.asm @@ -0,0 +1,21 @@ +.data + +fib: space 40 + +str: .asciiz "Hello" + +.text +main: addi $t0, $zero, 10 + addi $t1, $zero, 11 + loop: add $t2, $t1, $t0 + + addi $v0, $zero, 1 + addi $a0, $t2, 0 + syscall + + addi $t0, $t0, -1 + addi $t1, $t1, -1 + bne $t0, $zero, loop + addi $v0, $zero, 10 + syscall + -- cgit v1.2.3