aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAstatin <[email protected]>2024-09-24 20:44:56 +0900
committerAstatin <astatin@redacted>2024-09-24 20:44:56 +0900
commitef861b3e9b9800259e011581e01a853d3a122bf4 (patch)
tree2a05126c25fa5b2970fd86a6cd48613d7124c2c6
parent748e8ba9e9afd67695ca62f3b691970f943071a6 (diff)
I tried to add labels and macros but brain is mushy and nothing is working correctly
-rw-r--r--instructions.go340
-rw-r--r--macros.go139
-rw-r--r--main.go129
-rw-r--r--parameters.go121
4 files changed, 559 insertions, 170 deletions
diff --git a/instructions.go b/instructions.go
index 32e2794..0a7afb9 100644
--- a/instructions.go
+++ b/instructions.go
@@ -5,387 +5,486 @@ import (
"strings"
)
-type ParamType func(state *ProgramState, param string) (uint16, error)
+type ParamType func(labels *Labels, defs *Definitions, param string) (uint16, error)
type InstructionParams struct {
Types []ParamType
- Assembler func(args []uint16) []uint8
+ Assembler func(currentAddress uint16, args []uint16) ([]uint8, error)
+ Wildcard bool
}
type InstructionSet map[string][]InstructionParams
var Instructions = InstructionSetNew()
+func absoluteJPValueToRelative(baseAddress uint16, absoluteAddress uint16) (uint8, error) {
+ newAddress := (int16(absoluteAddress) - int16(baseAddress) - 2)
+ if newAddress < -127 || newAddress > 128 {
+ return 0, fmt.Errorf(
+ "Address 0x%04x and 0x%04x are too far apart to use JR. Please use JP instead",
+ baseAddress,
+ absoluteAddress,
+ )
+ }
+ return uint8(newAddress & 0xff), nil
+}
+
func InstructionSetNew() InstructionSet {
result := make(InstructionSet)
result["LD"] = []InstructionParams{
{
Types: []ParamType{Reg8, Reg8},
- Assembler: func(args []uint16) []byte {
- return []byte{0b01000000 | (uint8(uint8(args[0])) << 3) | uint8(uint8(args[1]))}
+ Assembler: func(_ uint16, args []uint16) ([]byte, error) {
+ return []byte{
+ 0b01000000 | (uint8(uint8(args[0])) << 3) | uint8(uint8(args[1])),
+ }, nil
},
},
+ // {
+ // Types: []ParamType{HL, Raw8Indirect},
+ // Assembler: func(_ uint16, args []uint16) ([]byte, error) { return []byte{0b11111000, uint8(args[1])}, nil },
+ // },
{
- Types: []ParamType{Reg8, Raw8},
- Assembler: func(args []uint16) []byte { return []byte{0b00000110 | (uint8(args[0]) << 3), uint8(args[1])} },
+ Types: []ParamType{Reg8, Raw8},
+ Assembler: func(_ uint16, args []uint16) ([]byte, error) {
+ return []byte{0b00000110 | (uint8(args[0]) << 3), uint8(args[1])}, nil
+ },
},
{
- Types: []ParamType{A, Reg16Indirect},
- Assembler: func(args []uint16) []byte { return []byte{0b00001010 | uint8(args[1])<<4} },
+ Types: []ParamType{A, Raw8Indirect},
+ Assembler: func(_ uint16, args []uint16) ([]byte, error) { return []byte{0b11110000, uint8(args[1])}, nil },
},
{
- Types: []ParamType{Reg16Indirect, A},
- Assembler: func(args []uint16) []byte { return []byte{0b00000010 | uint8(args[1])<<4} },
+ Types: []ParamType{Raw8Indirect, A},
+ Assembler: func(_ uint16, args []uint16) ([]byte, error) { return []byte{0b11100000, uint8(args[0])}, nil },
},
{
- Types: []ParamType{A, Raw16Indirect},
- Assembler: func(args []uint16) []byte { return []byte{0b11111010, uint8(args[1]) & 0xff, uint8(args[1] >> 8)} },
+ Types: []ParamType{A, Reg16Indirect},
+ Assembler: func(_ uint16, args []uint16) ([]byte, error) { return []byte{0b00001010 | uint8(args[1])<<4}, nil },
},
{
- Types: []ParamType{Raw16Indirect, A},
- Assembler: func(args []uint16) []byte { return []byte{0b11101010, uint8(args[0]) & 0xff, uint8(args[0] >> 8)} },
+ Types: []ParamType{Reg16Indirect, A},
+ Assembler: func(_ uint16, args []uint16) ([]byte, error) { return []byte{0b00000010 | uint8(args[0])<<4}, nil },
},
{
- Types: []ParamType{A, IndirectC},
- Assembler: func(args []uint16) []byte { return []byte{0b11110010} },
+ Types: []ParamType{A, Raw16Indirect},
+ Assembler: func(_ uint16, args []uint16) ([]byte, error) {
+ return []byte{0b11111010, uint8(args[1]) & 0xff, uint8(args[1] >> 8)}, nil
+ },
},
{
- Types: []ParamType{IndirectC, A},
- Assembler: func(args []uint16) []byte { return []byte{0b11100010} },
+ Types: []ParamType{Raw16Indirect, A},
+ Assembler: func(_ uint16, args []uint16) ([]byte, error) {
+ return []byte{0b11101010, uint8(args[0]) & 0xff, uint8(args[0] >> 8)}, nil
+ },
},
{
- Types: []ParamType{A, Raw8Indirect},
- Assembler: func(args []uint16) []byte { return []byte{0b11110000, uint8(args[1])} },
+ Types: []ParamType{A, IndirectC},
+ Assembler: func(_ uint16, args []uint16) ([]byte, error) { return []byte{0b11110010}, nil },
},
{
- Types: []ParamType{Raw8Indirect, A},
- Assembler: func(args []uint16) []byte { return []byte{0b11100000, uint8(args[0])} },
+ Types: []ParamType{IndirectC, A},
+ Assembler: func(_ uint16, args []uint16) ([]byte, error) { return []byte{0b11100010}, nil },
},
{
Types: []ParamType{Reg16, Raw16},
- Assembler: func(args []uint16) []byte {
+ Assembler: func(_ uint16, args []uint16) ([]byte, error) {
return []byte{
0b00000001 | (uint8(args[0]) << 4),
uint8(args[1]) & 0xff,
uint8(args[1] >> 8),
- }
+ }, nil
},
},
{
- Types: []ParamType{Raw16Indirect, SP},
- Assembler: func(args []uint16) []byte { return []byte{0b00001000, uint8(args[0]) & 0xff, uint8(args[0] >> 8)} },
+ Types: []ParamType{Raw16Indirect, SP},
+ Assembler: func(_ uint16, args []uint16) ([]byte, error) {
+ return []byte{0b00001000, uint8(args[0]) & 0xff, uint8(args[0] >> 8)}, nil
+ },
},
{
Types: []ParamType{SP, HL},
- Assembler: func(args []uint16) []byte { return []byte{0b11111001} },
- },
- {
- Types: []ParamType{HL, Raw8},
- Assembler: func(args []uint16) []byte { return []byte{0b11111000, uint8(args[1])} },
+ Assembler: func(_ uint16, args []uint16) ([]byte, error) { return []byte{0b11111001}, nil },
},
}
result["PUSH"] = []InstructionParams{
{
Types: []ParamType{Reg16},
- Assembler: func(args []uint16) []byte { return []byte{0b11000101 | (uint8(args[0]) << 4)} },
+ Assembler: func(_ uint16, args []uint16) ([]byte, error) { return []byte{0b11000101 | (uint8(args[0]) << 4)}, nil },
},
}
result["POP"] = []InstructionParams{
{
Types: []ParamType{Reg16},
- Assembler: func(args []uint16) []byte { return []byte{0b11000001 | (uint8(args[0]) << 4)} },
+ Assembler: func(_ uint16, args []uint16) ([]byte, error) { return []byte{0b11000001 | (uint8(args[0]) << 4)}, nil },
},
}
result["ADD"] = []InstructionParams{
{
Types: []ParamType{Reg8},
- Assembler: func(args []uint16) []byte { return []byte{0b10000000 | (uint8(args[0]))} },
+ Assembler: func(_ uint16, args []uint16) ([]byte, error) { return []byte{0b10000000 | (uint8(args[0]))}, nil },
},
{
Types: []ParamType{Raw8},
- Assembler: func(args []uint16) []byte { return []byte{0b11000110, uint8(args[0])} },
+ Assembler: func(_ uint16, args []uint16) ([]byte, error) { return []byte{0b11000110, uint8(args[0])}, nil },
},
{
Types: []ParamType{SP, Raw8},
- Assembler: func(args []uint16) []byte { return []byte{0b11101000, uint8(args[1])} },
+ Assembler: func(_ uint16, args []uint16) ([]byte, error) { return []byte{0b11101000, uint8(args[1])}, nil },
},
}
result["ADC"] = []InstructionParams{
{
Types: []ParamType{Reg8},
- Assembler: func(args []uint16) []byte { return []byte{0b10001000 | uint8(args[0])} },
+ Assembler: func(_ uint16, args []uint16) ([]byte, error) { return []byte{0b10001000 | uint8(args[0])}, nil },
},
{
Types: []ParamType{Raw8},
- Assembler: func(args []uint16) []byte { return []byte{0b11001110, uint8(args[0])} },
+ Assembler: func(_ uint16, args []uint16) ([]byte, error) { return []byte{0b11001110, uint8(args[0])}, nil },
},
}
result["SUB"] = []InstructionParams{
{
Types: []ParamType{Reg8},
- Assembler: func(args []uint16) []byte { return []byte{0b10010000 | (uint8(args[0]))} },
+ Assembler: func(_ uint16, args []uint16) ([]byte, error) { return []byte{0b10010000 | (uint8(args[0]))}, nil },
},
{
Types: []ParamType{Raw8},
- Assembler: func(args []uint16) []byte { return []byte{0b11010110, uint8(args[0])} },
+ Assembler: func(_ uint16, args []uint16) ([]byte, error) { return []byte{0b11010110, uint8(args[0])}, nil },
},
}
result["SBC"] = []InstructionParams{
{
Types: []ParamType{Reg8},
- Assembler: func(args []uint16) []byte { return []byte{0b10011000 | uint8(args[0])} },
+ Assembler: func(_ uint16, args []uint16) ([]byte, error) { return []byte{0b10011000 | uint8(args[0])}, nil },
},
{
Types: []ParamType{Raw8},
- Assembler: func(args []uint16) []byte { return []byte{0b11011110, uint8(args[0])} },
+ Assembler: func(_ uint16, args []uint16) ([]byte, error) { return []byte{0b11011110, uint8(args[0])}, nil },
},
}
result["CP"] = []InstructionParams{
{
Types: []ParamType{Reg8},
- Assembler: func(args []uint16) []byte { return []byte{0b10111000 | (uint8(args[0]))} },
+ Assembler: func(_ uint16, args []uint16) ([]byte, error) { return []byte{0b10111000 | (uint8(args[0]))}, nil },
},
{
Types: []ParamType{Raw8},
- Assembler: func(args []uint16) []byte { return []byte{0b11111110, uint8(args[0])} },
+ Assembler: func(_ uint16, args []uint16) ([]byte, error) { return []byte{0b11111110, uint8(args[0])}, nil },
},
}
result["INC"] = []InstructionParams{
{
Types: []ParamType{Reg8},
- Assembler: func(args []uint16) []byte { return []byte{0b00000100 | (uint8(args[0]) << 3)} },
+ Assembler: func(_ uint16, args []uint16) ([]byte, error) { return []byte{0b00000100 | (uint8(args[0]) << 3)}, nil },
},
{
Types: []ParamType{Reg16},
- Assembler: func(args []uint16) []byte { return []byte{0b00000011 | (uint8(args[0]) << 4)} },
+ Assembler: func(_ uint16, args []uint16) ([]byte, error) { return []byte{0b00000011 | (uint8(args[0]) << 4)}, nil },
},
}
result["DEC"] = []InstructionParams{
{
Types: []ParamType{Reg8},
- Assembler: func(args []uint16) []byte { return []byte{0b00000101 | (uint8(args[0]) << 3)} },
+ Assembler: func(_ uint16, args []uint16) ([]byte, error) { return []byte{0b00000101 | (uint8(args[0]) << 3)}, nil },
},
{
Types: []ParamType{Reg16},
- Assembler: func(args []uint16) []byte { return []byte{0b00001011 | (uint8(args[0]) << 4)} },
+ Assembler: func(_ uint16, args []uint16) ([]byte, error) { return []byte{0b00001011 | (uint8(args[0]) << 4)}, nil },
},
}
result["AND"] = []InstructionParams{
{
Types: []ParamType{Reg8},
- Assembler: func(args []uint16) []byte { return []byte{0b10100000 | (uint8(args[0]))} },
+ Assembler: func(_ uint16, args []uint16) ([]byte, error) { return []byte{0b10100000 | (uint8(args[0]))}, nil },
},
{
Types: []ParamType{Raw8},
- Assembler: func(args []uint16) []byte { return []byte{0b11100110, uint8(args[0])} },
+ Assembler: func(_ uint16, args []uint16) ([]byte, error) { return []byte{0b11100110, uint8(args[0])}, nil },
},
}
result["OR"] = []InstructionParams{
{
Types: []ParamType{Reg8},
- Assembler: func(args []uint16) []byte { return []byte{0b10110000 | (uint8(args[0]))} },
+ Assembler: func(_ uint16, args []uint16) ([]byte, error) { return []byte{0b10110000 | (uint8(args[0]))}, nil },
},
{
Types: []ParamType{Raw8},
- Assembler: func(args []uint16) []byte { return []byte{0b11110110, uint8(args[0])} },
+ Assembler: func(_ uint16, args []uint16) ([]byte, error) { return []byte{0b11110110, uint8(args[0])}, nil },
},
}
result["XOR"] = []InstructionParams{
{
Types: []ParamType{Reg8},
- Assembler: func(args []uint16) []byte { return []byte{0b10101000 | (uint8(args[0]))} },
+ Assembler: func(_ uint16, args []uint16) ([]byte, error) { return []byte{0b10101000 | (uint8(args[0]))}, nil },
},
{
Types: []ParamType{Raw8},
- Assembler: func(args []uint16) []byte { return []byte{0b11101110, uint8(args[0])} },
+ Assembler: func(_ uint16, args []uint16) ([]byte, error) { return []byte{0b11101110, uint8(args[0])}, nil },
},
}
result["CCF"] = []InstructionParams{
- {Types: []ParamType{}, Assembler: func(args []uint16) []byte { return []byte{0b00111111} }},
+ {
+ Types: []ParamType{},
+ Assembler: func(_ uint16, args []uint16) ([]byte, error) { return []byte{0b00111111}, nil },
+ },
}
result["SCF"] = []InstructionParams{
- {Types: []ParamType{}, Assembler: func(args []uint16) []byte { return []byte{0b00110111} }},
+ {
+ Types: []ParamType{},
+ Assembler: func(_ uint16, args []uint16) ([]byte, error) { return []byte{0b00110111}, nil },
+ },
}
result["DAA"] = []InstructionParams{
- {Types: []ParamType{}, Assembler: func(args []uint16) []byte { return []byte{0b00100111} }},
+ {
+ Types: []ParamType{},
+ Assembler: func(_ uint16, args []uint16) ([]byte, error) { return []byte{0b00100111}, nil },
+ },
}
result["CPL"] = []InstructionParams{
- {Types: []ParamType{}, Assembler: func(args []uint16) []byte { return []byte{0b00101111} }},
+ {
+ Types: []ParamType{},
+ Assembler: func(_ uint16, args []uint16) ([]byte, error) { return []byte{0b00101111}, nil },
+ },
}
result["JP"] = []InstructionParams{
{
- Types: []ParamType{Raw16},
- Assembler: func(args []uint16) []byte { return []byte{0b11000011, uint8(args[0]) & 0xff, uint8(args[0] >> 8)} },
+ Types: []ParamType{Raw16},
+ Assembler: func(_ uint16, args []uint16) ([]byte, error) {
+ return []byte{0b11000011, uint8(args[0]) & 0xff, uint8(args[0] >> 8)}, nil
+ },
},
{
Types: []ParamType{HL},
- Assembler: func(args []uint16) []byte { return []byte{0b11101001} },
+ Assembler: func(_ uint16, args []uint16) ([]byte, error) { return []byte{0b11101001}, nil },
},
{
Types: []ParamType{Condition, Raw16},
- Assembler: func(args []uint16) []byte {
+ Assembler: func(_ uint16, args []uint16) ([]byte, error) {
return []byte{
0b11000010 | (uint8(args[0]) << 3),
uint8(args[1]) & 0xff,
uint8(args[1] >> 8),
- }
+ }, nil
},
},
}
result["JR"] = []InstructionParams{
{
Types: []ParamType{Raw8},
- Assembler: func(args []uint16) []byte { return []byte{0b00011000, uint8(args[0])} },
+ Assembler: func(_ uint16, args []uint16) ([]byte, error) { return []byte{0b00011000, uint8(args[0])}, nil },
+ },
+ {
+ Types: []ParamType{Condition, Raw8},
+ Assembler: func(_ uint16, args []uint16) ([]byte, error) {
+ return []byte{0b00100000 | (uint8(args[0]) << 3), uint8(args[1])}, nil
+ },
},
// TODO: Add the relative thingies somehow
{
- Types: []ParamType{Raw16},
- Assembler: func(args []uint16) []byte { return []byte{0b00011000, uint8(args[0])} },
+ Types: []ParamType{Raw16},
+ Assembler: func(currentAddress uint16, args []uint16) ([]byte, error) {
+ relativeAddress, err := absoluteJPValueToRelative(currentAddress, args[0])
+ if err != nil {
+ return nil, err
+ }
+ return []byte{0b00011000, relativeAddress}, nil
+ },
},
{
- Types: []ParamType{Condition, Raw8},
- Assembler: func(args []uint16) []byte { return []byte{0b00100000 | (uint8(args[0]) << 3), uint8(args[1])} },
+ Types: []ParamType{Condition, Raw16},
+ Assembler: func(currentAddress uint16, args []uint16) ([]byte, error) {
+ relativeAddress, err := absoluteJPValueToRelative(currentAddress, args[1])
+ if err != nil {
+ return nil, err
+ }
+ return []byte{0b00100000 | (uint8(args[0]) << 3), relativeAddress}, nil
+ },
},
- // {
- // Types: []ParamType{Condition, Raw16},
- // Assembler: func(args []uint16) []byte { return []byte{0b00100000 | (uint8(args[0]) << 3), uint8(args[1])} },
- // },
}
result["CALL"] = []InstructionParams{
{
- Types: []ParamType{Raw16},
- Assembler: func(args []uint16) []byte { return []byte{0b11001101, uint8(args[0]) & 0xff, uint8(args[0] >> 8)} },
+ Types: []ParamType{Raw16},
+ Assembler: func(_ uint16, args []uint16) ([]byte, error) {
+ return []byte{0b11001101, uint8(args[0]) & 0xff, uint8(args[0] >> 8)}, nil
+ },
},
{
Types: []ParamType{Condition, Raw16},
- Assembler: func(args []uint16) []byte {
+ Assembler: func(_ uint16, args []uint16) ([]byte, error) {
return []byte{
0b11000100 | (uint8(args[0]) << 3),
uint8(args[1]) & 0xff,
uint8(args[1] >> 8),
- }
+ }, nil
},
},
}
result["RET"] = []InstructionParams{
- {Types: []ParamType{}, Assembler: func(args []uint16) []byte { return []byte{0b11001001} }},
+ {
+ Types: []ParamType{},
+ Assembler: func(_ uint16, args []uint16) ([]byte, error) { return []byte{0b11001001}, nil },
+ },
{
Types: []ParamType{Condition},
- Assembler: func(args []uint16) []byte { return []byte{0b11000000 | (uint8(args[0]) << 3)} },
+ Assembler: func(_ uint16, args []uint16) ([]byte, error) { return []byte{0b11000000 | (uint8(args[0]) << 3)}, nil },
},
}
result["RETI"] = []InstructionParams{
- {Types: []ParamType{}, Assembler: func(args []uint16) []byte { return []byte{0b11011001} }},
+ {
+ Types: []ParamType{},
+ Assembler: func(_ uint16, args []uint16) ([]byte, error) { return []byte{0b11011001}, nil },
+ },
}
result["RST"] = []InstructionParams{
{
Types: []ParamType{BitOrdinal},
- Assembler: func(args []uint16) []byte { return []byte{0b11000111 | (uint8(args[0]) << 3)} },
+ Assembler: func(_ uint16, args []uint16) ([]byte, error) { return []byte{0b11000111 | (uint8(args[0]) << 3)}, nil },
},
}
result["DI"] = []InstructionParams{
- {Types: []ParamType{}, Assembler: func(args []uint16) []byte { return []byte{0b11110011} }},
+ {
+ Types: []ParamType{},
+ Assembler: func(_ uint16, args []uint16) ([]byte, error) { return []byte{0b11110011}, nil },
+ },
}
result["EI"] = []InstructionParams{
- {Types: []ParamType{}, Assembler: func(args []uint16) []byte { return []byte{0b11111011} }},
+ {
+ Types: []ParamType{},
+ Assembler: func(_ uint16, args []uint16) ([]byte, error) { return []byte{0b11111011}, nil },
+ },
}
result["NOP"] = []InstructionParams{
- {Types: []ParamType{}, Assembler: func(args []uint16) []byte { return []byte{0b00000000} }},
+ {
+ Types: []ParamType{},
+ Assembler: func(_ uint16, args []uint16) ([]byte, error) { return []byte{0b00000000}, nil },
+ },
}
result["HALT"] = []InstructionParams{
- {Types: []ParamType{}, Assembler: func(args []uint16) []byte { return []byte{0b01110110} }},
+ {
+ Types: []ParamType{},
+ Assembler: func(_ uint16, args []uint16) ([]byte, error) { return []byte{0b01110110}, nil },
+ },
}
result["STOP"] = []InstructionParams{
{
Types: []ParamType{},
- Assembler: func(args []uint16) []byte { return []byte{0b00010000, 0b00000000} },
+ Assembler: func(_ uint16, args []uint16) ([]byte, error) { return []byte{0b00010000, 0b00000000}, nil },
},
}
result["RLCA"] = []InstructionParams{
- {Types: []ParamType{}, Assembler: func(args []uint16) []byte { return []byte{0b00000111} }},
+ {
+ Types: []ParamType{},
+ Assembler: func(_ uint16, args []uint16) ([]byte, error) { return []byte{0b00000111}, nil },
+ },
}
result["RLA"] = []InstructionParams{
- {Types: []ParamType{}, Assembler: func(args []uint16) []byte { return []byte{0b00010111} }},
+ {
+ Types: []ParamType{},
+ Assembler: func(_ uint16, args []uint16) ([]byte, error) { return []byte{0b00010111}, nil },
+ },
}
result["RRCA"] = []InstructionParams{
- {Types: []ParamType{}, Assembler: func(args []uint16) []byte { return []byte{0b00001111} }},
+ {
+ Types: []ParamType{},
+ Assembler: func(_ uint16, args []uint16) ([]byte, error) { return []byte{0b00001111}, nil },
+ },
}
result["RRA"] = []InstructionParams{
- {Types: []ParamType{}, Assembler: func(args []uint16) []byte { return []byte{0b00011111} }},
+ {
+ Types: []ParamType{},
+ Assembler: func(_ uint16, args []uint16) ([]byte, error) { return []byte{0b00011111}, nil },
+ },
}
result["BIT"] = []InstructionParams{
{
Types: []ParamType{BitOrdinal, Reg8},
- Assembler: func(args []uint16) []byte {
- return []byte{0b11001011, 0b01000000 | (uint8(args[0]) << 3) | uint8(args[1])}
+ Assembler: func(_ uint16, args []uint16) ([]byte, error) {
+ return []byte{0b11001011, 0b01000000 | (uint8(args[0]) << 3) | uint8(args[1])}, nil
},
},
}
result["SET"] = []InstructionParams{
{
Types: []ParamType{BitOrdinal, Reg8},
- Assembler: func(args []uint16) []byte {
- return []byte{0b11001011, 0b11000000 | (uint8(args[0]) << 3) | uint8(args[1])}
+ Assembler: func(_ uint16, args []uint16) ([]byte, error) {
+ return []byte{0b11001011, 0b11000000 | (uint8(args[0]) << 3) | uint8(args[1])}, nil
},
},
}
result["RES"] = []InstructionParams{
{
Types: []ParamType{BitOrdinal, Reg8},
- Assembler: func(args []uint16) []byte {
- return []byte{0b11001011, 0b10000000 | (uint8(args[0]) << 3) | uint8(args[1])}
+ Assembler: func(_ uint16, args []uint16) ([]byte, error) {
+ return []byte{0b11001011, 0b10000000 | (uint8(args[0]) << 3) | uint8(args[1])}, nil
},
},
}
result["RLC"] = []InstructionParams{
{
- Types: []ParamType{Reg8},
- Assembler: func(args []uint16) []byte { return []byte{0b11001011, 0b00000000 | uint8(args[0])} },
+ Types: []ParamType{Reg8},
+ Assembler: func(_ uint16, args []uint16) ([]byte, error) {
+ return []byte{0b11001011, 0b00000000 | uint8(args[0])}, nil
+ },
},
}
result["RL"] = []InstructionParams{
{
- Types: []ParamType{Reg8},
- Assembler: func(args []uint16) []byte { return []byte{0b11001011, 0b00010000 | uint8(args[0])} },
+ Types: []ParamType{Reg8},
+ Assembler: func(_ uint16, args []uint16) ([]byte, error) {
+ return []byte{0b11001011, 0b00010000 | uint8(args[0])}, nil
+ },
},
}
result["RRC"] = []InstructionParams{
{
- Types: []ParamType{Reg8},
- Assembler: func(args []uint16) []byte { return []byte{0b11001011, 0b00001000 | uint8(args[0])} },
+ Types: []ParamType{Reg8},
+ Assembler: func(_ uint16, args []uint16) ([]byte, error) {
+ return []byte{0b11001011, 0b00001000 | uint8(args[0])}, nil
+ },
},
}
result["RR"] = []InstructionParams{
{
- Types: []ParamType{Reg8},
- Assembler: func(args []uint16) []byte { return []byte{0b11001011, 0b00011000 | uint8(args[0])} },
+ Types: []ParamType{Reg8},
+ Assembler: func(_ uint16, args []uint16) ([]byte, error) {
+ return []byte{0b11001011, 0b00011000 | uint8(args[0])}, nil
+ },
},
}
result["SLA"] = []InstructionParams{
{
- Types: []ParamType{Reg8},
- Assembler: func(args []uint16) []byte { return []byte{0b11001011, 0b00100000 | uint8(args[0])} },
+ Types: []ParamType{Reg8},
+ Assembler: func(_ uint16, args []uint16) ([]byte, error) {
+ return []byte{0b11001011, 0b00100000 | uint8(args[0])}, nil
+ },
},
}
result["SWAP"] = []InstructionParams{
{
- Types: []ParamType{Reg8},
- Assembler: func(args []uint16) []byte { return []byte{0b11001011, 0b00110000 | uint8(args[0])} },
+ Types: []ParamType{Reg8},
+ Assembler: func(_ uint16, args []uint16) ([]byte, error) {
+ return []byte{0b11001011, 0b00110000 | uint8(args[0])}, nil
+ },
},
}
result["SRA"] = []InstructionParams{
{
- Types: []ParamType{Reg8},
- Assembler: func(args []uint16) []byte { return []byte{0b11001011, 0b00101000 | uint8(args[0])} },
+ Types: []ParamType{Reg8},
+ Assembler: func(_ uint16, args []uint16) ([]byte, error) {
+ return []byte{0b11001011, 0b00101000 | uint8(args[0])}, nil
+ },
},
}
result["SRL"] = []InstructionParams{
{
- Types: []ParamType{Reg8},
- Assembler: func(args []uint16) []byte { return []byte{0b11001011, 0b00111000 | uint8(args[0])} },
+ Types: []ParamType{Reg8},
+ Assembler: func(_ uint16, args []uint16) ([]byte, error) {
+ return []byte{0b11001011, 0b00111000 | uint8(args[0])}, nil
+ },
},
}
@@ -393,7 +492,9 @@ func InstructionSetNew() InstructionSet {
}
func (set InstructionSet) Parse(
- state *ProgramState,
+ labels *Labels,
+ defs *Definitions,
+ currentAddress uint16,
line string,
) ([]byte, error) {
words := strings.Fields(strings.ReplaceAll(strings.Trim(line, " \t\n"), ",", " "))
@@ -411,13 +512,20 @@ func (set InstructionSet) Parse(
instruction_param_loop:
for _, instrParam := range instruction {
- if len(instrParam.Types) != len(params) {
+ if !instrParam.Wildcard && len(instrParam.Types) != len(params) {
continue
}
parsed_params := make([]uint16, len(params))
- for i, paramType := range instrParam.Types {
- parsed, err := paramType(state, params[i])
+ for i := range parsed_params {
+ var paramType ParamType
+ if instrParam.Wildcard {
+ paramType = instrParam.Types[0]
+ } else {
+ paramType = instrParam.Types[i]
+ }
+
+ parsed, err := paramType(labels, defs, params[i])
if err != nil {
continue instruction_param_loop
}
@@ -425,7 +533,7 @@ instruction_param_loop:
parsed_params[i] = parsed
}
- return instrParam.Assembler(parsed_params), nil
+ return instrParam.Assembler(currentAddress, parsed_params)
}
return nil, fmt.Errorf(
"Instruction \"%s\" doesn't have a parameter set that can parse \"%s\"",
diff --git a/macros.go b/macros.go
new file mode 100644
index 0000000..5003524
--- /dev/null
+++ b/macros.go
@@ -0,0 +1,139 @@
+package main
+
+import (
+ "fmt"
+ "io"
+ "os"
+ "strconv"
+ "strings"
+)
+
+var MacroInstructions = NewInstructionSetMacros()
+
+func NewInstructionSetMacros() InstructionSet {
+ result := make(InstructionSet)
+
+ result[".PADTO"] = []InstructionParams{
+ {
+ Types: []ParamType{Raw16},
+ Assembler: func(currentAddress uint16, args []uint16) ([]byte, error) {
+ fmt.Printf(
+ ".PADTO 0x%04x, currentAddress: 0x%04x, inserting: 0x%04x\n",
+ args[0],
+ currentAddress,
+ args[0]-currentAddress,
+ )
+ return make([]byte, args[0]-currentAddress), nil
+ },
+ },
+ }
+
+ result[".DB"] = []InstructionParams{
+ {
+ Types: []ParamType{Raw8},
+ Assembler: func(currentAddress uint16, args []uint16) ([]byte, error) {
+ result := make([]byte, len(args))
+ for i := range args {
+ result[i] = uint8(args[i])
+ }
+ return result, nil
+ },
+ Wildcard: true,
+ },
+ }
+
+ return result
+}
+
+type (
+ Indirect8b uint16
+ Indirect16b uint16
+ Raw8b uint16
+ Raw16b uint16
+)
+
+func MacroParse(
+ line string,
+ result *[]byte,
+ state *ProgramState,
+ _ *int, // line_nb
+ is_first_pass bool,
+ offset uint,
+) error {
+ words := strings.Split(line, " ")
+ if len(words) == 0 {
+ return fmt.Errorf("Macro parsed doesn't accept empty lines")
+ }
+
+ macroName := words[0]
+
+ if _, ok := MacroInstructions[macroName]; ok {
+ new_instruction, err := MacroInstructions.Parse(
+ &state.Labels,
+ &state.Defs,
+ uint16(uint(len(*result))+offset),
+ line,
+ )
+ if err != nil {
+ return fmt.Errorf("Macro instruction parsing failed %w", err)
+ }
+
+ *result = append(*result, new_instruction...)
+ return nil
+ } else if macroName == ".INCLUDE" {
+ filePath := strings.Trim(strings.TrimSpace(strings.TrimPrefix(line, ".INCLUDE")), "\"'")
+
+ input_file, err := os.Open(filePath)
+ if err != nil {
+ return fmt.Errorf("Error while opening file %s", filePath)
+ }
+
+ input, err := io.ReadAll(input_file)
+ if err != nil {
+ return fmt.Errorf("Error while reading file %s", filePath)
+ }
+
+ fileStartOffset := uint(len(*result)) + offset
+ if is_first_pass {
+ included, err := firstPass(filePath, input, fileStartOffset, state)
+ if err != nil {
+ return err
+ }
+ *result = append(*result, included...)
+ } else {
+ included, err := secondPass(filePath, input, fileStartOffset, *state)
+ if err != nil {
+ return err
+ }
+ *result = append(*result, included...)
+ }
+ } else if macroName == ".DEFINE" {
+ if len(words) != 3 {
+ return fmt.Errorf(".DEFINE must have 2 arguments (%v)", words)
+ }
+
+ name := strings.ToUpper(words[1])
+ _, err := strconv.ParseUint(name, 16, 16)
+ if err == nil {
+ return fmt.Errorf("Defined variable \"%s\" is also valid hexadecimal", name)
+ }
+
+ var definedValue any
+ if v, err := Raw8Indirect(&state.Labels, &state.Defs, words[2]); err == nil {
+ definedValue = Indirect8b(v)
+ } else if v, err := Raw16Indirect(&state.Labels, &state.Defs, words[2]); err == nil {
+ definedValue = Indirect16b(v)
+ } else if v, err := Raw8(&state.Labels, &state.Defs, words[2]); err == nil {
+ definedValue = Raw8b(v)
+ } else if v, err := Raw16(&state.Labels, &state.Defs, words[2]); err == nil {
+ definedValue = Raw16b(v)
+ } else {
+ return fmt.Errorf("\"%s\" could not be parsed as a .DEFINE argument", words[2])
+ }
+
+ state.Defs[name] = definedValue
+ } else {
+ return fmt.Errorf("Unknown macro \"%s\"", macroName)
+ }
+ return nil
+}
diff --git a/main.go b/main.go
index b4fa941..30bda30 100644
--- a/main.go
+++ b/main.go
@@ -7,27 +7,49 @@ import (
"strings"
)
+type (
+ Labels map[string]uint
+ Definitions map[string]any
+)
+
type ProgramState struct {
- Labels map[string]uint
- Defs map[string]any
+ Labels Labels
+ Defs Definitions
}
-func parseFile(input_file_name string, input []byte) ([]byte, error) {
- lines := strings.Split(string(input), "\n")
-
+func parseFile(input_file_name string, input []byte, offset uint) ([]byte, error) {
state := ProgramState{
Labels: make(map[string]uint),
Defs: make(map[string]any),
}
- label_line_number := uint(0)
- for line_nb, line := range lines {
+ _, err := firstPass(input_file_name, input, offset, &state)
+ if err != nil {
+ return nil, err
+ }
+ return secondPass(input_file_name, input, offset, state)
+}
+
+func firstPass(
+ input_file_name string,
+ input []byte,
+ offset uint,
+ state *ProgramState,
+) ([]byte, error) {
+ lines := strings.Split(string(input), "\n")
+
+ line_nb := 0
+ result := []byte{}
+ for line_nb < len(lines) {
+ line := lines[line_nb]
+ line_parts := strings.Split(line, ";")
+ line = line_parts[0]
is_label_defined := strings.Contains(line, ":")
if is_label_defined {
parts := strings.Split(line, ":")
for _, label := range parts[:len(parts)-1] {
- label = strings.ToUpper(label)
+ label = strings.TrimSpace(strings.ToUpper(label))
if _, ok := state.Labels[label]; ok {
fmt.Fprintf(
os.Stderr,
@@ -38,7 +60,7 @@ func parseFile(input_file_name string, input []byte) ([]byte, error) {
)
os.Exit(1)
}
- state.Labels[label] = label_line_number
+ state.Labels[label] = uint(len(result)) + offset
}
line = parts[len(parts)-1]
@@ -46,22 +68,50 @@ func parseFile(input_file_name string, input []byte) ([]byte, error) {
line = strings.TrimSpace(line)
- next_instruction, err := Instructions.Parse(nil, line)
- if err != nil {
- return nil, fmt.Errorf(
- "File %s, line %d (1st pass):\n%w",
- input_file_name,
- line_nb,
- err,
- )
- }
+ // nil sets all the labels and defintion to 0 & thus, to not crash JR, the currentAddress should also be 0
+ if strings.HasPrefix(line, ".") {
+ err := MacroParse(line, &result, state, &line_nb, true, offset)
+ if err != nil {
+ return nil, fmt.Errorf(
+ "File %s, line %d (1st pass|macro):\n%w",
+ input_file_name,
+ line_nb,
+ err,
+ )
+ }
+ } else {
+ next_instruction, err := Instructions.Parse(nil, &state.Defs, 0, line)
+ if err != nil {
+ return nil, fmt.Errorf(
+ "File %s, line %d (1st pass):\n%w",
+ input_file_name,
+ line_nb,
+ err,
+ )
+ }
- // TODO: Handle the case of program bigger than MBC (or maybe do it directly in the parameters)
- label_line_number += uint(len(next_instruction))
+ result = append(result, next_instruction...)
+ }
+ line_nb += 1
}
+ return result, nil
+}
+
+func secondPass(
+ input_file_name string,
+ input []byte,
+ offset uint,
+ state ProgramState,
+) ([]byte, error) {
+ lines := strings.Split(string(input), "\n")
+
+ line_nb := 0
result := []byte{}
- for line_nb, line := range lines {
+ for line_nb < len(lines) {
+ line := lines[line_nb]
+ line_parts := strings.Split(line, ";")
+ line = line_parts[0]
is_label_defined := strings.Contains(line, ":")
if is_label_defined {
@@ -70,17 +120,32 @@ func parseFile(input_file_name string, input []byte) ([]byte, error) {
line = parts[len(parts)-1]
}
- next_instruction, err := Instructions.Parse(&state, line)
- if err != nil {
- return nil, fmt.Errorf(
- "File %s, line %d (2nd pass): %w",
- input_file_name,
- line_nb,
- err,
- )
- }
+ line = strings.TrimSpace(line)
+
+ if strings.HasPrefix(line, ".") {
+ err := MacroParse(line, &result, &state, &line_nb, false, offset)
+ if err != nil {
+ return nil, fmt.Errorf(
+ "File %s, line %d (2nd pass|macro):\n%w",
+ input_file_name,
+ line_nb,
+ err,
+ )
+ }
+ } else {
+ next_instruction, err := Instructions.Parse(&state.Labels, &state.Defs, uint16(uint(len(result))+offset), line)
+ if err != nil {
+ return nil, fmt.Errorf(
+ "File %s, line %d (2nd pass): %w",
+ input_file_name,
+ line_nb,
+ err,
+ )
+ }
- result = append(result, next_instruction...)
+ result = append(result, next_instruction...)
+ }
+ line_nb += 1
}
return result, nil
@@ -107,7 +172,7 @@ func main() {
os.Exit(1)
}
- result, err := parseFile(input_file_name, input)
+ result, err := parseFile(input_file_name, input, 0)
if err != nil {
fmt.Fprintf(os.Stderr, "Error: %s\n", err.Error())
os.Exit(1)
diff --git a/parameters.go b/parameters.go
index 02991cf..8a3174b 100644
--- a/parameters.go
+++ b/parameters.go
@@ -6,7 +6,7 @@ import (
"strings"
)
-func Reg8(_ *ProgramState, param string) (uint16, error) {
+func Reg8(_ *Labels, _ *Definitions, param string) (uint16, error) {
switch param {
case "A":
return 7, nil
@@ -28,35 +28,35 @@ func Reg8(_ *ProgramState, param string) (uint16, error) {
return 0, fmt.Errorf("Invalid reg8")
}
-func A(_ *ProgramState, param string) (uint16, error) {
+func A(_ *Labels, _ *Definitions, param string) (uint16, error) {
if param == "A" {
return 0, nil
}
return 0, fmt.Errorf("Invalid A")
}
-func HL(_ *ProgramState, param string) (uint16, error) {
+func HL(_ *Labels, _ *Definitions, param string) (uint16, error) {
if param == "HL" {
return 0, nil
}
return 0, fmt.Errorf("Invalid HL")
}
-func SP(_ *ProgramState, param string) (uint16, error) {
+func SP(_ *Labels, _ *Definitions, param string) (uint16, error) {
if param == "SP" {
return 0, nil
}
return 0, fmt.Errorf("Invalid SP")
}
-func IndirectC(_ *ProgramState, param string) (uint16, error) {
+func IndirectC(_ *Labels, _ *Definitions, param string) (uint16, error) {
if param == "(C)" {
return 0, nil
}
return 0, fmt.Errorf("Invalid (C)")
}
-func Reg16(_ *ProgramState, param string) (uint16, error) {
+func Reg16(_ *Labels, _ *Definitions, param string) (uint16, error) {
switch param {
case "BC":
return 0, nil
@@ -73,21 +73,60 @@ func Reg16(_ *ProgramState, param string) (uint16, error) {
return 0, fmt.Errorf("Invalid reg16")
}
-func Raw8(_ *ProgramState, param string) (uint16, error) {
- res, err := strconv.ParseInt(param, 0, 8)
+func Raw8(_ *Labels, defs *Definitions, param string) (uint16, error) {
+ if strings.HasPrefix(param, "$") {
+ param = strings.ToUpper(strings.TrimPrefix(param, "$"))
+ if res, err := strconv.ParseUint(param, 16, 16); err == nil {
+ if len(param) > 2 {
+ return 0, fmt.Errorf("%s is > 8bit precision", param)
+ }
+ return uint16(res), nil
+ }
+
+ definition, ok := (*defs)[param]
+ if !ok {
+ return 0, fmt.Errorf("$%s is undefined", param)
+ }
+
+ res, ok := definition.(Raw8b)
+ if !ok {
+ return 0, fmt.Errorf("$%s is of type %T but Raw8b is expected", param, res)
+ }
+ return uint16(res), nil
+ }
+ if strings.HasPrefix(param, "0x") && len(param) > 4 {
+ return 0, fmt.Errorf("%s is > 8bit precision", param)
+ }
+ res, err := strconv.ParseUint(param, 0, 8)
return uint16(res), err
}
-func Raw16(state *ProgramState, param string) (uint16, error) {
- res, err := strconv.ParseInt(param, 0, 16)
+func Raw16(labels *Labels, defs *Definitions, param string) (uint16, error) {
+ if strings.HasPrefix(param, "$") {
+ param = strings.ToUpper(strings.TrimPrefix(param, "$"))
+ if res, err := strconv.ParseUint(param, 16, 16); err == nil {
+ return uint16(res), nil
+ }
+
+ definition, ok := (*defs)[param]
+ if !ok {
+ return 0, fmt.Errorf("$%s is undefined", param)
+ }
+
+ res, ok := definition.(Raw16b)
+ if !ok {
+ return 0, fmt.Errorf("$%s is of type %T but Raw16b is expected", param, res)
+ }
+ return uint16(res), nil
+ }
if strings.HasPrefix(param, "=") {
- if state == nil {
+ if labels == nil {
return 0, nil
}
label := strings.ToUpper(strings.TrimPrefix(param, "="))
- labelValue, ok := state.Labels[label]
+ labelValue, ok := (*labels)[label]
if !ok {
return 0, fmt.Errorf("Label \"%s\" not found", label)
}
@@ -100,10 +139,12 @@ func Raw16(state *ProgramState, param string) (uint16, error) {
return uint16(labelValue), nil
}
+ res, err := strconv.ParseUint(param, 0, 16)
+
return uint16(res), err
}
-func Reg16Indirect(_ *ProgramState, param string) (uint16, error) {
+func Reg16Indirect(_ *Labels, _ *Definitions, param string) (uint16, error) {
switch param {
case "(BC)":
return 0, nil
@@ -117,25 +158,61 @@ func Reg16Indirect(_ *ProgramState, param string) (uint16, error) {
return 0, fmt.Errorf("Invalid reg16 indirect")
}
-func Raw8Indirect(_ *ProgramState, param string) (uint16, error) {
+func Raw8Indirect(labels *Labels, defs *Definitions, param string) (uint16, error) {
+ if strings.HasPrefix(param, "$") {
+ param = strings.ToUpper(strings.TrimPrefix(param, "$"))
+
+ definition, ok := (*defs)[param]
+ if !ok {
+ return 0, fmt.Errorf("$%s is undefined", param)
+ }
+
+ res, ok := definition.(Indirect8b)
+ if !ok {
+ return 0, fmt.Errorf("$%s is of type %T but Indirect8bb is expected", param, res)
+ }
+ return uint16(res), nil
+ }
+
if len(param) < 2 || param[0] != '(' || param[len(param)-1] != ')' {
return 0, fmt.Errorf("Invalid raw8indirect")
}
- res, err := strconv.ParseInt(param[1:len(param)-1], 0, 8)
- return uint16(res), err
+ res, err := Raw8(labels, defs, param[1:len(param)-1])
+ if err == nil {
+ return res, nil
+ }
+ return 0, err
}
-func Raw16Indirect(_ *ProgramState, param string) (uint16, error) {
+func Raw16Indirect(labels *Labels, defs *Definitions, param string) (uint16, error) {
+ if strings.HasPrefix(param, "$") {
+ param = strings.ToUpper(strings.TrimPrefix(param, "$"))
+
+ if labels == nil {
+ return 0, nil
+ }
+
+ definition, ok := (*defs)[param]
+ if !ok {
+ return 0, fmt.Errorf("$%s is undefined", param)
+ }
+
+ res, ok := definition.(Indirect16b)
+ if !ok {
+ return 0, fmt.Errorf("$%s is of type %T but Indirect16b expected", param, res)
+ }
+ fmt.Println("YOU CAN LOOSE YOUR MIND NOW ! IT OFFICIALLY DOESN'T MAKE SENSE", param, res)
+ return uint16(res), nil
+ }
if len(param) < 2 || param[0] != '(' || param[len(param)-1] != ')' {
return 0, fmt.Errorf("Invalid raw16indirect")
}
- res, err := strconv.ParseInt(param[1:len(param)-1], 0, 16)
- return uint16(res), err
+ return Raw16(labels, defs, param[1:len(param)-1])
}
-func Condition(_ *ProgramState, param string) (uint16, error) {
+func Condition(_ *Labels, _ *Definitions, param string) (uint16, error) {
switch param {
case "NZ":
return 0, nil
@@ -149,7 +226,7 @@ func Condition(_ *ProgramState, param string) (uint16, error) {
return 0, fmt.Errorf("Invalid condition")
}
-func BitOrdinal(_ *ProgramState, param string) (uint16, error) {
- res, err := strconv.ParseInt(param, 0, 3)
+func BitOrdinal(_ *Labels, _ *Definitions, param string) (uint16, error) {
+ res, err := strconv.ParseUint(param, 0, 3)
return uint16(res), err
}