-
Notifications
You must be signed in to change notification settings - Fork 1
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
base: main
Are you sure you want to change the base?
Decode functions #15
Changes from all commits
d6d8bcf
7344064
c45af62
1ea4cca
a40be84
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
module zepa-machine | ||
|
||
go 1.23.1 |
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 | ||
|
@@ -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 { | ||
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 | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe 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) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe 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 | ||
|
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) | ||
} | ||
} |
There was a problem hiding this comment.
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