Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Decode functions #15

Open
wants to merge 5 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions go.mod
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
module zepa-machine

go 1.23.1
160 changes: 147 additions & 13 deletions zepa.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
package machine

type Register byte
type Register uint32
type Opcode byte
type Operation func(m *Machine, inst Instruction)

const (
w0 Register = iota
Expand All @@ -15,38 +17,170 @@ const (
sr
mdr
mar

MV Opcode = iota
ADD
SUB
CMP
JUMP
LOAD
STORE
FETCH
)

const (
opcodeLength = 6
rdLength = 5
rs1Length = 5
rs2Length = 5
funct5Length = 5
funct6Length = 6
immediateLen = 16
word = 32
)

const (
opcodeBitMask = 0b111111
registerBitMask = 0b11111
immediateBitMask = 0b1111111111111111
funct5BitMask = 0b11111
funct6BitMask = 0b111111
)

var operations = map[byte]Operation{
byte(MV): (*Machine).mv,
byte(ADD): (*Machine).add,
byte(SUB): (*Machine).sub,
byte(CMP): (*Machine).cmp,
byte(JUMP): (*Machine).jump,
byte(LOAD): (*Machine).load,
byte(STORE): (*Machine).store,
}

type Instruction struct {
opcode func(m *Machine, inst Instruction)
rd Register
rs1 Register
rs2 Register
funct5 byte
funct6 byte
immediate uint16
}

type Machine struct {
memory []byte
registers map[Register]byte
registers map[Register]uint32
}

func (m *Machine) mv(inst Instruction) {}

func (m *Machine) add(inst Instruction) {}

func (m *Machine) sub(inst Instruction) {}

func (m *Machine) cmp(inst Instruction) {}

func (m *Machine) jump(inst Instruction) {}

func (m *Machine) load(inst Instruction) {}

func (m *Machine) store(inst Instruction) {}

func (m *Machine) fetch() {
currentInstructionAddress := m.registers[pc]
currentInstruction := m.memory[currentInstructionAddress]
// Update Instruction Register with current instruction
m.registers[ir] = currentInstruction
// Increment Program Counter
m.registers[pc] += 1
var completeInstruction uint32 = 0
for i := 0; i < 4; i++ {
currentInstructionAddress := m.registers[pc]
currentInstruction := m.memory[currentInstructionAddress]
completeInstruction = completeInstruction | uint32(currentInstruction)<<(24-8*i)
m.registers[pc] += 1
}
m.registers[ir] = completeInstruction
}

func (m *Machine) decode() {}
func (m *Machine) decodeRTypeInst(instruction uint32) Instruction {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should return an error checking the operands

offsetOpcode := word - opcodeLength
offSetRd := offsetOpcode - rdLength
offSetRs1 := offSetRd - rs1Length
offSetRs2 := offSetRs1 - rs2Length
offSetFunct5 := offSetRs2 - funct5Length
offSetFunct6 := offSetFunct5 - funct6Length

opcode := instruction >> (uint32(offsetOpcode)) & 0b111111
rd := (instruction >> uint32(offSetRd)) & registerBitMask
rs1 := (instruction >> (uint32(offSetRs1))) & registerBitMask
rs2 := (instruction >> (uint32(offSetRs2))) & registerBitMask
funct5 := (instruction >> (uint32(offSetFunct5))) & funct5BitMask
funct6 := (instruction >> (uint32(offSetFunct6))) & funct6BitMask

operation := operations[byte(opcode)]

return Instruction{
opcode: operation,
rd: Register(rd),
rs1: Register(rs1),
rs2: Register(rs2),
funct5: byte(funct5),
funct6: byte(funct6),
}
}

func (m *Machine) decodeITypeInst(instruction uint32) Instruction {
offsetOpcode := word - opcodeLength
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should return an error checking the operands

offSetRdRs1 := offsetOpcode - rdLength
offSetImmediate := offSetRdRs1 - immediateLen
offSetFunct5 := offSetImmediate - funct5Length

opcode := instruction >> (uint32(offsetOpcode)) & opcodeBitMask
rdRs1 := (instruction >> uint32(offSetRdRs1)) & registerBitMask
immediate := (instruction >> (uint32(offSetImmediate))) & immediateBitMask
funct5 := (instruction >> (uint32(offSetFunct5))) & funct5BitMask

operation := operations[byte(opcode)]

return Instruction{
opcode: operation,
rd: Register(rdRs1),
immediate: uint16(immediate),
funct5: byte(funct5),
}
}

func (m *Machine) getOpcode(instruction uint32) Opcode {
offsetOpcode := word - opcodeLength
opcode := instruction >> (uint32(offsetOpcode))

return Opcode(opcode)
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This function should return an error if the opcode provided cannot be mapped to one of the options, even if the assembler checks this on a higher level changes will happen and is safe to add this check.

}

func (m *Machine) decode() Instruction {
instruction := m.registers[ir]
opcode := m.getOpcode(instruction)

switch opcode {
case ADD, SUB, CMP:
return m.decodeRTypeInst(instruction)
case MV, JUMP, LOAD, STORE:
fallthrough
default:
return m.decodeITypeInst(instruction)
}
}

func (m *Machine) execute() {}
func (m *Machine) execute(inst Instruction) {}

func (m *Machine) boot() {
for {
m.fetch()
m.decode()
m.execute()
decodedInstruction := m.decode()
m.execute(decodedInstruction)
break
}
}

func NewMachine(memoryBytes int) *Machine {
machine := &Machine{
memory: make([]byte, memoryBytes),
registers: make(map[Register]byte),
registers: make(map[Register]uint32),
}

return machine
Expand Down
53 changes: 53 additions & 0 deletions zepa_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
package machine

import (
"testing"
)

func TestFetch(t *testing.T) {

machine := NewMachine(2048)
machine.memory[0] = 0b00110100
machine.memory[1] = 0b01000011
machine.memory[2] = 0b00001000
machine.memory[3] = 0b00000000
machine.fetch()

expectedInstruction := uint32(0b00110100010000110000100000000000)
if machine.registers[ir] != expectedInstruction {
t.Errorf("Expected 0b%032b, but got 0b%032b", expectedInstruction, machine.registers[ir])
}

if machine.registers[pc] != 4 {
t.Errorf("Expected PC to be 4, but got %d", machine.registers[pc])
}
}

// To-do: refact to avoid code duplication
func TestDecode(t *testing.T) {

machine := NewMachine(2048)
machine.memory[0] = 0b00110100
machine.memory[1] = 0b01000011
machine.memory[2] = 0b00001000
machine.memory[3] = 0b00000000
machine.fetch()

decodedInstruction := machine.decode()

if decodedInstruction.rd != Register(2) {
t.Errorf("Expected rd to be 2, but got %d", decodedInstruction.rd)
}
if decodedInstruction.rs1 != Register(3) {
t.Errorf("Expected rs1 to be 3, but got %d", decodedInstruction.rs1)
}
if decodedInstruction.rs2 != Register(1) {
t.Errorf("Expected rs2 to be 1, but got %d", decodedInstruction.rs2)
}
if decodedInstruction.funct3 != 0 {
t.Errorf("Expected funct3 to be 0, but got %d", decodedInstruction.funct3)
}
if decodedInstruction.funct7 != 0 {
t.Errorf("Expected funct7 to be 0, but got %d", decodedInstruction.funct7)
}
}