diff options
author | Astatin <[email protected]> | 2024-09-24 20:44:56 +0900 |
---|---|---|
committer | Astatin <astatin@redacted> | 2024-09-24 20:44:56 +0900 |
commit | ef861b3e9b9800259e011581e01a853d3a122bf4 (patch) | |
tree | 2a05126c25fa5b2970fd86a6cd48613d7124c2c6 | |
parent | 748e8ba9e9afd67695ca62f3b691970f943071a6 (diff) |
I tried to add labels and macros but brain is mushy and nothing is working correctly
-rw-r--r-- | instructions.go | 340 | ||||
-rw-r--r-- | macros.go | 139 | ||||
-rw-r--r-- | main.go | 129 | ||||
-rw-r--r-- | parameters.go | 121 |
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 +} @@ -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 } |