From 2a803fc679eaa03c6007be66d608aefe1606c601 Mon Sep 17 00:00:00 2001 From: Alon Krymgand Date: Sat, 14 Dec 2024 13:39:59 +0200 Subject: [PATCH] Added `Bz` instruction to `usm64` --- usm64/core/argument.go | 20 ++++++++++++-- usm64/isa/bz.go | 50 ++++++++++++++++++++++++++++++++++ usm64/isa/jump.go | 17 +++--------- usm64/isa/put.go | 4 +-- usm64/managers/instructions.go | 17 ++++++++++-- 5 files changed, 87 insertions(+), 21 deletions(-) create mode 100644 usm64/isa/bz.go diff --git a/usm64/core/argument.go b/usm64/core/argument.go index 5a75db8..aa57caa 100644 --- a/usm64/core/argument.go +++ b/usm64/core/argument.go @@ -16,9 +16,7 @@ type ValuedArgument interface { Value(ctx *EmulationContext) uint64 } -func ArgumentToValuedArgument( - arg Argument, -) (ValuedArgument, core.ResultList) { +func ArgumentToValuedArgument(arg Argument) (ValuedArgument, core.ResultList) { valued, ok := arg.(ValuedArgument) if !ok { v := arg.Declaration() @@ -34,6 +32,22 @@ func ArgumentToValuedArgument( return valued, core.ResultList{} } +func ArgumentToLabel(argument Argument) (Label, core.ResultList) { + label, ok := argument.(Label) + if !ok { + v := argument.Declaration() + return Label{}, list.FromSingle(core.Result{ + { + Type: core.ErrorResult, + Message: "Expected label argument", + Location: &v, + }, + }) + } + + return label, core.ResultList{} +} + func NewArgument(argument gen.ArgumentInfo) (Argument, core.ResultList) { switch typedArgument := argument.(type) { case *gen.ImmediateInfo: diff --git a/usm64/isa/bz.go b/usm64/isa/bz.go new file mode 100644 index 0000000..56271e7 --- /dev/null +++ b/usm64/isa/bz.go @@ -0,0 +1,50 @@ +package usm64isa + +import ( + "alon.kr/x/usm/core" + "alon.kr/x/usm/gen" + usm64core "alon.kr/x/usm/usm64/core" +) + +type BzInstruction struct { + Argument usm64core.ValuedArgument + Label usm64core.Label +} + +func (i *BzInstruction) Emulate( + ctx *usm64core.EmulationContext, +) usm64core.EmulationError { + if i.Argument.Value(ctx) == uint64(0) { + ctx.JumpToLabel(i.Label) + } else { + ctx.IncrementInstructionPointer() + } + return nil +} + +func NewBzInstruction( + targets []usm64core.Register, + arguments []usm64core.Argument, +) (usm64core.Instruction, core.ResultList) { + results := core.ResultList{} + + argument, argumentResults := usm64core.ArgumentToValuedArgument(arguments[0]) + results.Extend(&argumentResults) + + label, labelResults := usm64core.ArgumentToLabel(arguments[1]) + results.Extend(&labelResults) + + if !results.IsEmpty() { + return nil, results + } + + return &BzInstruction{Argument: argument, Label: label}, core.ResultList{} +} + +func NewBzInstructionDefinition() gen.InstructionDefinition[usm64core.Instruction] { + return &FixedInstructionDefinition{ + Targets: 0, + Arguments: 2, + Creator: NewBzInstruction, + } +} diff --git a/usm64/isa/jump.go b/usm64/isa/jump.go index 8485514..5716d59 100644 --- a/usm64/isa/jump.go +++ b/usm64/isa/jump.go @@ -1,7 +1,6 @@ package usm64isa import ( - "alon.kr/x/list" "alon.kr/x/usm/core" "alon.kr/x/usm/gen" usm64core "alon.kr/x/usm/usm64/core" @@ -20,19 +19,11 @@ func (i *JumpInstruction) Emulate( func NewJumpInstruction( targets []usm64core.Register, - argument []usm64core.Argument, + arguments []usm64core.Argument, ) (usm64core.Instruction, core.ResultList) { - - label, ok := argument[0].(usm64core.Label) - if !ok { - v := argument[0].Declaration() - return nil, list.FromSingle(core.Result{ - { - Type: core.ErrorResult, - Message: "Expected label argument", - Location: &v, - }, - }) + label, results := usm64core.ArgumentToLabel(arguments[0]) + if !results.IsEmpty() { + return nil, results } return &JumpInstruction{Label: label}, core.ResultList{} diff --git a/usm64/isa/put.go b/usm64/isa/put.go index 62f28d7..ee54d51 100644 --- a/usm64/isa/put.go +++ b/usm64/isa/put.go @@ -22,9 +22,9 @@ func (i *PutInstruction) Emulate( func NewPutInstruction( targets []usm64core.Register, - argument []usm64core.Argument, + arguments []usm64core.Argument, ) (usm64core.Instruction, core.ResultList) { - valued, results := usm64core.ArgumentToValuedArgument(argument[0]) + valued, results := usm64core.ArgumentToValuedArgument(arguments[0]) if !results.IsEmpty() { return nil, results } diff --git a/usm64/managers/instructions.go b/usm64/managers/instructions.go index 8b1b153..fa69542 100644 --- a/usm64/managers/instructions.go +++ b/usm64/managers/instructions.go @@ -22,6 +22,7 @@ func (m *InstructionMap) GetInstructionDefinition( return nil, list.FromSingle(core.Result{{ Type: core.ErrorResult, Message: "Undefined instruction", + // TODO: add location }}) } return instDef, core.ResultList{} @@ -30,10 +31,20 @@ func (m *InstructionMap) GetInstructionDefinition( func NewInstructionManager() gen.InstructionManager[usm64core.Instruction] { return gen.InstructionManager[usm64core.Instruction]( &InstructionMap{ - "": usm64isa.NewMovInstructionDefinition(), - "add": usm64isa.NewAddInstructionDefinition(), - "put": usm64isa.NewPutInstructionDefinition(), + + // mov + "": usm64isa.NewMovInstructionDefinition(), + "mov": usm64isa.NewMovInstructionDefinition(), + + // arithmetic + "add": usm64isa.NewAddInstructionDefinition(), + + // control flow "jump": usm64isa.NewJumpInstructionDefinition(), + "bz": usm64isa.NewBzInstructionDefinition(), + + // debug + "put": usm64isa.NewPutInstructionDefinition(), }, ) }