Skip to content

Commit

Permalink
Software simulation
Browse files Browse the repository at this point in the history
  • Loading branch information
alabarjasteh committed Jul 4, 2021
1 parent 942fb96 commit 99066f6
Show file tree
Hide file tree
Showing 11 changed files with 348 additions and 7 deletions.
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
.vscode/launch.json
.DS_Store
3 changes: 3 additions & 0 deletions go.mod
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
module github.com/alabarjasteh/mips-simulator

go 1.16
56 changes: 56 additions & 0 deletions main.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
package main

import (
"fmt"

"github.com/alabarjasteh/mips-simulator/mips"
)

type Instruction int64

func main() {
mem := mips.NewMemory()
cpu := mips.NewCPU(mem)

for {
_, instData := cpu.Fetch()
instruction, err := cpu.Decode(instData)
if err != nil {
fmt.Printf("error: %v", err)
return
}
err = cpu.Execute(instruction)
if err != nil {
fmt.Printf("error: %v", err)
return
}
}
}

// func fetchBurst(pc *int, mem *memory.Mem, reg *register.IfDec) {
// inst, err := mem.FetchInstruction(*pc)
// if err != nil {
// log.Fatal(err)
// }
// reg.IR = inst
// log.Printf("IR : %v", reg.IR)
// *pc += 4
// reg.NPC = *pc
// }

// func decodeBurst(rf *register.File, ifDec *register.IfDec, decEx *register.DecEx) {
// r1, r2 := getReadingRegisters(rf, ifDec.IR)
// imm := extractImmediate(ifDec.IR)
// decEx.IR = ifDec.IR
// decEx.NPC = ifDec.NPC
// decEx.R1 = r1
// decEx.R2 = r2
// decEx.Imm = imm
// }

// func executeBurst() {

// }

// func memoryBurst() {}
// func writebackBurst() {}
7 changes: 0 additions & 7 deletions memory/state1.txt

This file was deleted.

6 changes: 6 additions & 0 deletions memory_state1.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
10001100000000010000000000010000
10001100000000100000000000010100
00000000001000100001100000100000
10101100000000110000000000011000
00000000000000000000000000000001
00000000000000000000000000000011
7 changes: 7 additions & 0 deletions memory/instructions1.txt → memory_state2.txt
Original file line number Diff line number Diff line change
Expand Up @@ -8,3 +8,10 @@
00100000001000100000000000000001
00101000001000100000000000000001
00110100001000100000000000000001
00000000000000000000000000000001
00000000000000000000000000000010
00000000000000000000000000000011
00000000000000000000000000000100
00000000000000000000000000000101
00000000000000000000000000000110
00000000000000000000000000000111
85 changes: 85 additions & 0 deletions mips/cpu.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
package mips

import (
"errors"
"fmt"
)

type CPU struct {
PC int
Memory Memory
RegFile [32]int32
}

func NewCPU(mem Memory) *CPU {
return &CPU{
PC: 0,
RegFile: [32]int32{},
Memory: mem,
}
}

func (cpu *CPU) Fetch() (npc int, instData int) {
ins := cpu.Memory[cpu.PC]
fmt.Printf("instruction: %b\n", ins)
cpu.PC += 4
npc = cpu.PC
return npc, ins
}

func (cpu *CPU) Decode(insData int) (*Instruction, error) {
fmt.Printf("inst: %b\n", insData)
opcode := insData >> 26
fmt.Printf("opcode: %b\n", opcode)
opcodeType, err := getOpcodeType(opcode)
if err != nil {
return nil, err
}

ins := &Instruction{}
ins.Opcode = opcode
ins.OpcodeType = opcodeType

switch opcodeType {
case OpcodeTypeR:
insTypeR := &InstructionTypeR{}
insTypeR.FuncCode = insData & 0b111111
insTypeR.DestinationRegister = (insData >> 11) & 0b11111
insTypeR.TargetRegister = (insData >> 16) & 0b11111
insTypeR.SourceRegister = (insData >> 21) & 0b11111
f, ok := FunctionTypeRMap[insTypeR.FuncCode]
if !ok {
return nil, errors.New("unsupported funcCode")
}
insTypeR.Function = f

ins.TypeR = insTypeR
case OpcodeTypeI:
insTypeI := &InstructionTypeI{}
insTypeI.Immediate = insData & 0xFFFF
insTypeI.TargetRegister = (insData >> 16) & 0b11111
insTypeI.SourceRegister = (insData >> 21) & 0b11111
f, ok := FunctionTypeIMap[opcode]
if !ok {
return nil, errors.New("unsupported opcode")
}
insTypeI.Function = f

ins.TypeI = insTypeI
}

return ins, nil
}

func (cpu *CPU) Execute(ins *Instruction) error {
var err error
switch ins.OpcodeType {
case OpcodeTypeR:
r := ins.TypeR
err = r.Function(cpu, r.SourceRegister, r.TargetRegister, r.DestinationRegister)
case OpcodeTypeI:
i := ins.TypeI
err = i.Function(cpu, i.SourceRegister, i.TargetRegister, i.Immediate)
}
return err
}
84 changes: 84 additions & 0 deletions mips/function.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
package mips

import (
"errors"
"fmt"
)

// R Type Instructions
type FunctionTypeR func(cpu *CPU, rs int, rt int, rd int) error

func Add(cpu *CPU, rs int, rt int, rd int) error {

cpu.RegFile[rd] = cpu.RegFile[rs] + cpu.RegFile[rt]

return nil
}

func And(cpu *CPU, rs int, rt int, rd int) error {
fmt.Printf("(\"and\" not implemented)\n")
return errors.New("not implemented: and")
}

func Slt(cpu *CPU, rs int, rt int, rd int) error {
fmt.Printf("(\"slt\" not implemented)\n")
return errors.New("not implemented: slt")
}

func Sub(cpu *CPU, rs int, rt int, rd int) error {
fmt.Printf("(\"sub\" not implemented)\n")
return errors.New("not implemented: sub")
}

func Or(cpu *CPU, rs int, rt int, rd int) error {

cpu.RegFile[rd] = cpu.RegFile[rs] | cpu.RegFile[rt]

return nil
}

// I Type Instruction
type FunctionTypeI func(cpu *CPU, rs int, rt int, imm int) error

func Addi(cpu *CPU, rs int, rt int, imm int) error {

cpu.RegFile[rt] = cpu.RegFile[rs] + int32(int16(imm))

return nil
}

func Andi(cpu *CPU, rs int, rt int, imm int) error {
fmt.Printf("(\"andi\" not implemented)\n")
return errors.New("not implemented: andi")
}

func Lw(cpu *CPU, rs int, rt int, imm int) error {

value := int32(cpu.Memory[int(int16(imm))+int(cpu.RegFile[rs])])
cpu.RegFile[rt] = value

return nil
}

func Ori(cpu *CPU, rs int, rt int, imm int) error {
fmt.Printf("(\"ori\" not implemented)\n")
return errors.New("not implemented: ori")
}

func Slti(cpu *CPU, rs int, rt int, imm int) error {

if cpu.RegFile[rs] < int32(int16(imm)) {
cpu.RegFile[rt] = 1
} else {
cpu.RegFile[rt] = 0
}

return nil
}

func Sw(cpu *CPU, rs int, rt int, imm int) error {

cpu.Memory[int(int16(imm))+int(cpu.RegFile[rs])] = int(cpu.RegFile[rt])

return nil
}
42 changes: 42 additions & 0 deletions mips/instruction.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
package mips

var FunctionTypeRMap = map[int]FunctionTypeR{
0b100000: Add,
0b100010: Sub,
0b100101: Or,
0b100100: And,
0b101010: Slt,
}

var FunctionTypeIMap = map[int]FunctionTypeI{
0b101011: Sw,
0b100011: Lw,
0b001000: Addi,
0b001010: Slti,
0b001100: Andi,
0b001101: Ori,
}

type Instruction struct {
Opcode int
OpcodeType OpcodeType
TypeR *InstructionTypeR
TypeI *InstructionTypeI
}

type InstructionTypeR struct {
SourceRegister int
TargetRegister int
DestinationRegister int
FuncCode int

Function func(cpu *CPU, rs int, rt int, rd int) error
}

type InstructionTypeI struct {
SourceRegister int
TargetRegister int
Immediate int

Function func(cpu *CPU, rs int, rt int, imm int) error
}
40 changes: 40 additions & 0 deletions mips/memory.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
package mips

import (
"bufio"
"fmt"
"log"
"os"
"strconv"
)

type Memory map[int]int // map[PC]Data

func NewMemory() Memory {
mem := Memory{}
mem.loadMemoryFromFile()
return mem
}

func (mem Memory) loadMemoryFromFile() {
file, err := os.Open("./memory_state1.txt")
if err != nil {
log.Fatalf("failed to open")

}
defer file.Close()
scanner := bufio.NewScanner(file)
i := 0
for scanner.Scan() {
val, err := strconv.ParseInt(scanner.Text(), 2, 64)
if err != nil {
log.Fatal("cannot parse memory state from file")
}
mem[i] = int(val)
fmt.Printf("mem: %b\n", mem[i])
i += 4
}
if err := scanner.Err(); err != nil {
log.Fatal(err)
}
}
23 changes: 23 additions & 0 deletions mips/opcode.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
package mips

import "errors"

type OpcodeType byte

var ErrInvalidOpcode = errors.New("invalid opcode")

const (
OpcodeTypeInvalid OpcodeType = iota
OpcodeTypeR
OpcodeTypeI
)

func getOpcodeType(opcode int) (OpcodeType, error) {
if opcode == 0 {
return OpcodeTypeR, nil
}
if _, ok := FunctionTypeIMap[opcode]; ok {
return OpcodeTypeI, nil
}
return OpcodeTypeInvalid, ErrInvalidOpcode
}

0 comments on commit 99066f6

Please sign in to comment.