-
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
refactor for multi cpu architecture support (#16)
- Loading branch information
Showing
46 changed files
with
637 additions
and
457 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,61 @@ | ||
// Package assembler implements the architecture specific assembler functionality. | ||
package assembler | ||
|
||
import ( | ||
"fmt" | ||
"math" | ||
|
||
"github.com/retroenv/retroasm/arch" | ||
"github.com/retroenv/retroasm/arch/m6502/parser" | ||
"github.com/retroenv/retrogolib/arch/cpu/m6502" | ||
) | ||
|
||
func AssignInstructionAddress(assigner arch.AddressAssigner, ins arch.Instruction) (uint64, error) { | ||
pc := assigner.ProgramCounter() | ||
ins.SetAddress(pc) | ||
|
||
name := ins.Name() | ||
insDetails, ok := m6502.Instructions[name] | ||
if !ok { | ||
return 0, fmt.Errorf("unsupported instruction '%s'", name) | ||
} | ||
|
||
addressing := m6502.AddressingMode(ins.Addressing()) | ||
|
||
// handle disambiguous addressing mode to reduce absolute addressings to | ||
// zeropage ones if the used address value fits into byte | ||
switch addressing { | ||
case parser.XAddressing: | ||
argument := ins.Argument() | ||
value, err := assigner.ArgumentValue(argument) | ||
if err != nil { | ||
return 0, fmt.Errorf("getting instruction argument: %w", err) | ||
} | ||
if value > math.MaxUint8 { | ||
ins.SetAddressing(int(m6502.AbsoluteXAddressing)) | ||
} else { | ||
ins.SetAddressing(int(m6502.ZeroPageXAddressing)) | ||
} | ||
|
||
case parser.YAddressing: | ||
argument := ins.Argument() | ||
value, err := assigner.ArgumentValue(argument) | ||
if err != nil { | ||
return 0, fmt.Errorf("getting instruction argument: %w", err) | ||
} | ||
if value > math.MaxUint8 { | ||
ins.SetAddressing(int(m6502.AbsoluteYAddressing)) | ||
} else { | ||
ins.SetAddressing(int(m6502.ZeroPageYAddressing)) | ||
} | ||
} | ||
|
||
addressing = m6502.AddressingMode(ins.Addressing()) | ||
addressingInfo, ok := insDetails.Addressing[addressing] | ||
if !ok { | ||
return 0, fmt.Errorf("unsupported instruction '%s' addressing %d", name, addressing) | ||
} | ||
|
||
programCounter := pc + uint64(addressingInfo.Size) | ||
return programCounter, nil | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,108 @@ | ||
package assembler | ||
|
||
import ( | ||
"encoding/binary" | ||
"fmt" | ||
"math" | ||
|
||
"github.com/retroenv/retroasm/arch" | ||
"github.com/retroenv/retrogolib/arch/cpu/m6502" | ||
) | ||
|
||
// GenerateInstructionOpcode generates the instruction opcode based on the instruction base opcode, | ||
// its addressing mode and parameters. | ||
func GenerateInstructionOpcode(assigner arch.AddressAssigner, ins arch.Instruction) error { | ||
instructionInfo := m6502.Instructions[ins.Name()] | ||
addressing := m6502.AddressingMode(ins.Addressing()) | ||
addressingInfo := instructionInfo.Addressing[addressing] | ||
ins.SetOpcodes([]byte{addressingInfo.Opcode}) | ||
ins.SetSize(int(addressingInfo.Size)) | ||
|
||
switch addressing { | ||
case m6502.ImpliedAddressing, m6502.AccumulatorAddressing: | ||
|
||
case m6502.ImmediateAddressing: | ||
if err := generateImmediateAddressingOpcode(assigner, ins); err != nil { | ||
return fmt.Errorf("generating opcode: %w", err) | ||
} | ||
|
||
case m6502.AbsoluteAddressing, m6502.AbsoluteXAddressing, m6502.AbsoluteYAddressing, | ||
m6502.IndirectAddressing, m6502.IndirectXAddressing, m6502.IndirectYAddressing: | ||
if err := generateAbsoluteIndirectAddressingOpcode(assigner, ins); err != nil { | ||
return fmt.Errorf("generating opcode: %w", err) | ||
} | ||
|
||
case m6502.ZeroPageAddressing, m6502.ZeroPageXAddressing, m6502.ZeroPageYAddressing: | ||
if err := generateZeroPageAddressingOpcode(assigner, ins); err != nil { | ||
return fmt.Errorf("generating opcode: %w", err) | ||
} | ||
|
||
case m6502.RelativeAddressing: | ||
if err := generateRelativeAddressingOpcode(assigner, ins); err != nil { | ||
return fmt.Errorf("generating opcode: %w", err) | ||
} | ||
|
||
default: | ||
return fmt.Errorf("unsupported instruction addressing %d", addressing) | ||
} | ||
|
||
return nil | ||
} | ||
|
||
func generateAbsoluteIndirectAddressingOpcode(assigner arch.AddressAssigner, ins arch.Instruction) error { | ||
value, err := assigner.ArgumentValue(ins.Argument()) | ||
if err != nil { | ||
return fmt.Errorf("getting instruction argument: %w", err) | ||
} | ||
if value > math.MaxUint16 { | ||
return fmt.Errorf("value %d exceeds word", value) | ||
} | ||
|
||
opcodes := binary.LittleEndian.AppendUint16(ins.Opcodes(), uint16(value)) | ||
ins.SetOpcodes(opcodes) | ||
return nil | ||
} | ||
|
||
func generateZeroPageAddressingOpcode(assigner arch.AddressAssigner, ins arch.Instruction) error { | ||
value, err := assigner.ArgumentValue(ins.Argument()) | ||
if err != nil { | ||
return fmt.Errorf("getting instruction argument: %w", err) | ||
} | ||
if value > math.MaxUint8 { | ||
return fmt.Errorf("value %d exceeds byte", value) | ||
} | ||
|
||
opcodes := append(ins.Opcodes(), byte(value)) | ||
ins.SetOpcodes(opcodes) | ||
return nil | ||
} | ||
|
||
func generateImmediateAddressingOpcode(assigner arch.AddressAssigner, ins arch.Instruction) error { | ||
value, err := assigner.ArgumentValue(ins.Argument()) | ||
if err != nil { | ||
return fmt.Errorf("getting instruction argument: %w", err) | ||
} | ||
if value > math.MaxUint8 { | ||
return fmt.Errorf("value %d exceeds byte", value) | ||
} | ||
|
||
opcodes := append(ins.Opcodes(), byte(value)) | ||
ins.SetOpcodes(opcodes) | ||
return nil | ||
} | ||
|
||
func generateRelativeAddressingOpcode(assigner arch.AddressAssigner, ins arch.Instruction) error { | ||
value, err := assigner.ArgumentValue(ins.Argument()) | ||
if err != nil { | ||
return fmt.Errorf("getting instruction argument: %w", err) | ||
} | ||
|
||
b, err := assigner.RelativeOffset(value, ins.Address()+uint64(ins.Size())) | ||
if err != nil { | ||
return fmt.Errorf("value %d exceeds byte", value) | ||
} | ||
|
||
opcodes := append(ins.Opcodes(), b) | ||
ins.SetOpcodes(opcodes) | ||
return nil | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,47 @@ | ||
// Package m6502 provides a 6502 architecture specific assembler code. | ||
package m6502 | ||
|
||
import ( | ||
"github.com/retroenv/retroasm/arch" | ||
"github.com/retroenv/retroasm/arch/m6502/assembler" | ||
"github.com/retroenv/retroasm/arch/m6502/parser" | ||
"github.com/retroenv/retroasm/assembler/config" | ||
"github.com/retroenv/retroasm/parser/ast" | ||
"github.com/retroenv/retrogolib/arch/cpu/m6502" | ||
) | ||
|
||
// New returns a new 6502 architecture configuration. | ||
func New() *config.Config[*m6502.Instruction] { | ||
p := &arch6502[*m6502.Instruction]{} | ||
cfg := &config.Config[*m6502.Instruction]{ | ||
Arch: p, | ||
} | ||
return cfg | ||
} | ||
|
||
type arch6502[T any] struct { | ||
} | ||
|
||
func (_ *arch6502[T]) AddressWidth() int { | ||
return 16 | ||
} | ||
|
||
func (_ *arch6502[T]) Instruction(name string) (*m6502.Instruction, bool) { | ||
ins, ok := m6502.Instructions[name] | ||
return ins, ok | ||
} | ||
|
||
// nolint: wrapcheck | ||
func (_ *arch6502[T]) ParseIdentifier(p arch.Parser, ins *m6502.Instruction) (ast.Node, error) { | ||
return parser.ParseIdentifier(p, ins) | ||
} | ||
|
||
// nolint: wrapcheck | ||
func (_ *arch6502[T]) AssignInstructionAddress(assigner arch.AddressAssigner, ins arch.Instruction) (uint64, error) { | ||
return assembler.AssignInstructionAddress(assigner, ins) | ||
} | ||
|
||
// nolint: wrapcheck | ||
func (_ *arch6502[T]) GenerateInstructionOpcode(assigner arch.AddressAssigner, ins arch.Instruction) error { | ||
return assembler.GenerateInstructionOpcode(assigner, ins) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.