Skip to content

Commit e5ad7d7

Browse files
committed
Check for Gameboy-specific opcodes, add .z80 directive
1 parent 9d95df9 commit e5ad7d7

File tree

7 files changed

+74
-42
lines changed

7 files changed

+74
-42
lines changed

Archs/Z80/CZ80Instruction.cpp

Lines changed: 22 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -93,26 +93,29 @@ bool CZ80Instruction::Validate(const ValidateState& state)
9393
Vars.Immediate = -Vars.Immediate;
9494
}
9595

96-
// Special loads in range 0xFF00 - 0xFFFF
97-
if (!(Opcode.flags & Z80_IMMEDIATE_U3) && Vars.RightParam.num == Z80_REG8_A && Vars.Immediate >= 0xFF00)
96+
if (Z80.GetVersion() == ZARCH_GAMEBOY)
9897
{
99-
// ld (0xFF00+u8),a can be encoded as E0 XX instead
100-
Vars.Encoding = 0xE0;
101-
Vars.Length = 2;
102-
Vars.Immediate &= 0xFF;
103-
Vars.RightParam.num = 0;
104-
Vars.WriteImmediate8 = true;
105-
Vars.WriteImmediate16 = false;
106-
}
107-
else if (Vars.LeftParam.num == Z80_REG8_A && Vars.Immediate >= 0xFF00)
108-
{
109-
// ld a,(0xFF00+u8) can be encoded as F0 XX instead
110-
Vars.Encoding = 0xF0;
111-
Vars.Length = 2;
112-
Vars.Immediate &= 0xFF;
113-
Vars.LeftParam.num = 0;
114-
Vars.WriteImmediate8 = true;
115-
Vars.WriteImmediate16 = false;
98+
// Special loads in range 0xFF00 - 0xFFFF
99+
if (Vars.RightParam.num == Z80_REG8_A && Vars.Immediate >= 0xFF00 && !(Opcode.flags & Z80_IMMEDIATE_U3))
100+
{
101+
// ld (0xFF00+u8),a can be encoded as E0 XX instead
102+
Vars.Encoding = 0xE0;
103+
Vars.Length = 2;
104+
Vars.Immediate &= 0xFF;
105+
Vars.RightParam.num = 0;
106+
Vars.WriteImmediate8 = true;
107+
Vars.WriteImmediate16 = false;
108+
}
109+
else if (Vars.LeftParam.num == Z80_REG8_A && Vars.Immediate >= 0xFF00)
110+
{
111+
// ld a,(0xFF00+u8) can be encoded as F0 XX instead
112+
Vars.Encoding = 0xF0;
113+
Vars.Length = 2;
114+
Vars.Immediate &= 0xFF;
115+
Vars.LeftParam.num = 0;
116+
Vars.WriteImmediate8 = true;
117+
Vars.WriteImmediate16 = false;
118+
}
116119
}
117120

118121
if (Vars.Immediate < min || Vars.Immediate > max)

Archs/Z80/Z80.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@
44
#include "Core/ELF/ElfRelocator.h"
55
#include "Core/Expression.h"
66

7+
enum Z80ArchType { ZARCH_Z80 = 0, ZARCH_GAMEBOY, ZARCH_INVALID };
8+
79
struct Z80RegisterValue
810
{
911
std::wstring name;
@@ -22,6 +24,10 @@ class CZ80Architecture: public CArchitecture
2224
virtual void Revalidate();
2325
virtual std::unique_ptr<IElfRelocator> getElfRelocator() { return 0; };
2426
virtual Endianness getEndianness() { return Endianness::Little; };
27+
void SetVersion(Z80ArchType v) { Version = v; };
28+
Z80ArchType GetVersion() { return Version; };
29+
private:
30+
Z80ArchType Version;
2531
};
2632

2733
extern CZ80Architecture Z80;

Archs/Z80/Z80Opcodes.cpp

Lines changed: 20 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -11,35 +11,35 @@ const tZ80Opcode Z80Opcodes[] = {
1111
{ L"ld", 1, 0x40, Z80_PARAM_REG8_MEMHL, Z80_PARAM_REG8_MEMHL, 3, 0, Z80_LOAD_REG8_REG8 },
1212
{ L"ld", 1, 0x02, Z80_PARAM_MEMBC_MEMDE, Z80_PARAM_A, 4, -1, 0 },
1313
{ L"ld", 1, 0x0A, Z80_PARAM_A, Z80_PARAM_MEMBC_MEMDE, -1, 4, 0 },
14-
{ L"ld", 1, 0x22, Z80_PARAM_HLI_HLD, Z80_PARAM_A, 4, -1, 0 },
15-
{ L"ld", 1, 0x2A, Z80_PARAM_A, Z80_PARAM_HLI_HLD, -1, 4, 0 },
16-
{ L"ld", 1, 0xE2, Z80_PARAM_FF00_C, Z80_PARAM_A, -1, -1, 0 },
17-
{ L"ld", 1, 0xF2, Z80_PARAM_A, Z80_PARAM_FF00_C, -1, -1, 0 },
14+
{ L"ld", 1, 0x22, Z80_PARAM_HLI_HLD, Z80_PARAM_A, 4, -1, Z80_GAMEBOY },
15+
{ L"ld", 1, 0x2A, Z80_PARAM_A, Z80_PARAM_HLI_HLD, -1, 4, Z80_GAMEBOY },
16+
{ L"ld", 1, 0xE2, Z80_PARAM_FF00_C, Z80_PARAM_A, -1, -1, Z80_GAMEBOY },
17+
{ L"ld", 1, 0xF2, Z80_PARAM_A, Z80_PARAM_FF00_C, -1, -1, Z80_GAMEBOY },
1818
{ L"ld", 1, 0xF9, Z80_PARAM_SP, Z80_PARAM_HL, -1, -1, 0 },
19-
{ L"ld", 2, 0xF8, Z80_PARAM_HL, Z80_PARAM_SP_IMM, -1, -1, Z80_IMMEDIATE_S8 },
20-
{ L"ld", 3, 0xFA, Z80_PARAM_A, Z80_PARAM_MEMIMMEDIATE, -1, -1, Z80_IMMEDIATE_U16 },
19+
{ L"ld", 2, 0xF8, Z80_PARAM_HL, Z80_PARAM_SP_IMM, -1, -1, Z80_IMMEDIATE_S8 | Z80_GAMEBOY },
20+
{ L"ld", 3, 0xFA, Z80_PARAM_A, Z80_PARAM_MEMIMMEDIATE, -1, -1, Z80_IMMEDIATE_U16 | Z80_GAMEBOY },
2121
{ L"ld", 2, 0x06, Z80_PARAM_REG8_MEMHL, Z80_PARAM_IMMEDIATE, 3, -1, Z80_IMMEDIATE_U8 },
2222
{ L"ld", 3, 0x01, Z80_PARAM_REG16_SP, Z80_PARAM_IMMEDIATE, 4, -1, Z80_IMMEDIATE_U16 },
23-
{ L"ld", 3, 0x08, Z80_PARAM_MEMIMMEDIATE, Z80_PARAM_SP, -1, -1, Z80_IMMEDIATE_U16 },
24-
{ L"ld", 3, 0xEA, Z80_PARAM_MEMIMMEDIATE, Z80_PARAM_A, -1, -1, Z80_IMMEDIATE_U16 },
25-
{ L"ldi", 1, 0x22, Z80_PARAM_MEMHL, Z80_PARAM_A, -1, -1, 0 },
26-
{ L"ldi", 1, 0x2A, Z80_PARAM_A, Z80_PARAM_MEMHL, -1, -1, 0 },
27-
{ L"ldd", 1, 0x32, Z80_PARAM_MEMHL, Z80_PARAM_A, -1, -1, 0 },
28-
{ L"ldd", 1, 0x3A, Z80_PARAM_A, Z80_PARAM_MEMHL, -1, -1, 0 },
29-
{ L"ldh", 2, 0xE0, Z80_PARAM_MEMIMMEDIATE, Z80_PARAM_A, -1, -1, Z80_IMMEDIATE_U8 },
30-
{ L"ldh", 2, 0xF0, Z80_PARAM_A, Z80_PARAM_MEMIMMEDIATE, -1, -1, Z80_IMMEDIATE_U8 },
31-
{ L"ldhl", 2, 0xF8, Z80_PARAM_SP, Z80_PARAM_IMMEDIATE, -1, -1, Z80_IMMEDIATE_S8 },
23+
{ L"ld", 3, 0x08, Z80_PARAM_MEMIMMEDIATE, Z80_PARAM_SP, -1, -1, Z80_IMMEDIATE_U16 | Z80_GAMEBOY },
24+
{ L"ld", 3, 0xEA, Z80_PARAM_MEMIMMEDIATE, Z80_PARAM_A, -1, -1, Z80_IMMEDIATE_U16 | Z80_GAMEBOY },
25+
{ L"ldi", 1, 0x22, Z80_PARAM_MEMHL, Z80_PARAM_A, -1, -1, Z80_GAMEBOY },
26+
{ L"ldi", 1, 0x2A, Z80_PARAM_A, Z80_PARAM_MEMHL, -1, -1, Z80_GAMEBOY },
27+
{ L"ldd", 1, 0x32, Z80_PARAM_MEMHL, Z80_PARAM_A, -1, -1, Z80_GAMEBOY },
28+
{ L"ldd", 1, 0x3A, Z80_PARAM_A, Z80_PARAM_MEMHL, -1, -1, Z80_GAMEBOY },
29+
{ L"ldh", 2, 0xE0, Z80_PARAM_MEMIMMEDIATE, Z80_PARAM_A, -1, -1, Z80_IMMEDIATE_U8 | Z80_GAMEBOY },
30+
{ L"ldh", 2, 0xF0, Z80_PARAM_A, Z80_PARAM_MEMIMMEDIATE, -1, -1, Z80_IMMEDIATE_U8 | Z80_GAMEBOY },
31+
{ L"ldhl", 2, 0xF8, Z80_PARAM_SP, Z80_PARAM_IMMEDIATE, -1, -1, Z80_IMMEDIATE_S8 | Z80_GAMEBOY },
3232
{ L"push", 1, 0xC5, Z80_PARAM_REG16_AF, Z80_PARAM_NONE, 4, -1, 0 },
3333
{ L"pop", 1, 0xC1, Z80_PARAM_REG16_AF, Z80_PARAM_NONE, 4, -1, 0 },
3434
{ L"add", 1, 0x09, Z80_PARAM_HL, Z80_PARAM_REG16_SP, -1, 4, 0 },
3535
{ L"add", 1, 0x80, Z80_PARAM_A, Z80_PARAM_REG8_MEMHL, -1, 0, 0 },
3636
{ L"add", 2, 0xC6, Z80_PARAM_A, Z80_PARAM_IMMEDIATE, -1, -1, Z80_IMMEDIATE_U8 | Z80_ADD_SUB_IMMEDIATE },
37-
{ L"add", 2, 0xE8, Z80_PARAM_SP, Z80_PARAM_IMMEDIATE, -1, -1, Z80_IMMEDIATE_S8 },
37+
{ L"add", 2, 0xE8, Z80_PARAM_SP, Z80_PARAM_IMMEDIATE, -1, -1, Z80_IMMEDIATE_S8 | Z80_GAMEBOY },
3838
{ L"adc", 1, 0x88, Z80_PARAM_A, Z80_PARAM_REG8_MEMHL, -1, 0, 0 },
3939
{ L"adc", 2, 0xCE, Z80_PARAM_A, Z80_PARAM_IMMEDIATE, -1, -1, Z80_IMMEDIATE_U8 | Z80_ADD_SUB_IMMEDIATE },
4040
{ L"sub", 1, 0x90, Z80_PARAM_A, Z80_PARAM_REG8_MEMHL, -1, 0, 0 },
4141
{ L"sub", 2, 0xD6, Z80_PARAM_A, Z80_PARAM_IMMEDIATE, -1, -1, Z80_IMMEDIATE_U8 | Z80_ADD_SUB_IMMEDIATE },
42-
{ L"sub", 2, 0xE8, Z80_PARAM_SP, Z80_PARAM_IMMEDIATE, -1, -1, Z80_IMMEDIATE_S8 | Z80_NEGATE_IMM },
42+
{ L"sub", 2, 0xE8, Z80_PARAM_SP, Z80_PARAM_IMMEDIATE, -1, -1, Z80_IMMEDIATE_S8 | Z80_NEGATE_IMM | Z80_GAMEBOY },
4343
{ L"sbc", 1, 0x98, Z80_PARAM_A, Z80_PARAM_REG8_MEMHL, -1, 0, 0 },
4444
{ L"sbc", 2, 0xDE, Z80_PARAM_A, Z80_PARAM_IMMEDIATE, -1, -1, Z80_IMMEDIATE_U8 | Z80_ADD_SUB_IMMEDIATE },
4545
{ L"and", 1, 0xA0, Z80_PARAM_A, Z80_PARAM_REG8_MEMHL, -1, 0, 0 },
@@ -66,15 +66,15 @@ const tZ80Opcode Z80Opcodes[] = {
6666
{ L"rr", 2, 0x18, Z80_PARAM_REG8_MEMHL, Z80_PARAM_NONE, 0, -1, Z80_PREFIX_CB },
6767
{ L"sla", 2, 0x20, Z80_PARAM_REG8_MEMHL, Z80_PARAM_NONE, 0, -1, Z80_PREFIX_CB },
6868
{ L"sra", 2, 0x28, Z80_PARAM_REG8_MEMHL, Z80_PARAM_NONE, 0, -1, Z80_PREFIX_CB },
69-
{ L"swap", 2, 0x30, Z80_PARAM_REG8_MEMHL, Z80_PARAM_NONE, 0, -1, Z80_PREFIX_CB },
69+
{ L"swap", 2, 0x30, Z80_PARAM_REG8_MEMHL, Z80_PARAM_NONE, 0, -1, Z80_PREFIX_CB | Z80_GAMEBOY },
7070
{ L"srl", 2, 0x38, Z80_PARAM_REG8_MEMHL, Z80_PARAM_NONE, 0, -1, Z80_PREFIX_CB },
7171
{ L"bit", 2, 0x40, Z80_PARAM_IMMEDIATE, Z80_PARAM_REG8_MEMHL, 3, 0, Z80_PREFIX_CB | Z80_IMMEDIATE_U3 },
7272
{ L"res", 2, 0x80, Z80_PARAM_IMMEDIATE, Z80_PARAM_REG8_MEMHL, 3, 0, Z80_PREFIX_CB | Z80_IMMEDIATE_U3 },
7373
{ L"set", 2, 0xC0, Z80_PARAM_IMMEDIATE, Z80_PARAM_REG8_MEMHL, 3, 0, Z80_PREFIX_CB | Z80_IMMEDIATE_U3 },
7474
{ L"ccf", 1, 0x3F, Z80_PARAM_NONE, Z80_PARAM_NONE, -1, -1, 0 },
7575
{ L"scf", 1, 0x37, Z80_PARAM_NONE, Z80_PARAM_NONE, -1, -1, 0 },
7676
{ L"halt", 1, 0x76, Z80_PARAM_NONE, Z80_PARAM_NONE, -1, -1, 0 },
77-
{ L"stop", 2, 0x10, Z80_PARAM_NONE, Z80_PARAM_NONE, -1, -1, Z80_STOP },
77+
{ L"stop", 2, 0x10, Z80_PARAM_NONE, Z80_PARAM_NONE, -1, -1, Z80_STOP | Z80_GAMEBOY },
7878
{ L"di", 1, 0xF3, Z80_PARAM_NONE, Z80_PARAM_NONE, -1, -1, 0 },
7979
{ L"ei", 1, 0xFB, Z80_PARAM_NONE, Z80_PARAM_NONE, -1, -1, 0 },
8080
{ L"jp", 3, 0xC2, Z80_PARAM_CONDITION, Z80_PARAM_IMMEDIATE, 3, -1, Z80_IMMEDIATE_U16 },
@@ -86,7 +86,7 @@ const tZ80Opcode Z80Opcodes[] = {
8686
{ L"call", 3, 0xCD, Z80_PARAM_IMMEDIATE, Z80_PARAM_NONE, -1, -1, Z80_IMMEDIATE_U16 },
8787
{ L"ret", 1, 0xC0, Z80_PARAM_CONDITION, Z80_PARAM_NONE, 3, -1, 0 },
8888
{ L"ret", 1, 0xC9, Z80_PARAM_NONE, Z80_PARAM_NONE, -1, -1, 0 },
89-
{ L"reti", 1, 0xD9, Z80_PARAM_NONE, Z80_PARAM_NONE, -1, -1, 0 },
89+
{ L"reti", 1, 0xD9, Z80_PARAM_NONE, Z80_PARAM_NONE, -1, -1, Z80_GAMEBOY },
9090
{ L"rst", 1, 0xC7, Z80_PARAM_IMMEDIATE, Z80_PARAM_NONE, 0, -1, Z80_RST },
9191
{ nullptr, 0, 0x00, Z80_PARAM_NONE, Z80_PARAM_NONE, -1, -1, 0 },
9292
};

Archs/Z80/Z80Opcodes.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,7 @@
5656
#define Z80_ADD_SUB_IMMEDIATE 0x00000100
5757
#define Z80_NEGATE_IMM 0x00000200
5858
#define Z80_JUMP_RELATIVE 0x00000400
59+
#define Z80_GAMEBOY 0x00000800
5960

6061
#define Z80_HAS_IMMEDIATE ( Z80_IMMEDIATE_U3 | Z80_IMMEDIATE_U8 | Z80_IMMEDIATE_S8 \
6162
| Z80_IMMEDIATE_U16 | Z80_RST | Z80_JUMP_RELATIVE )

Archs/Z80/Z80Parser.cpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -255,6 +255,9 @@ std::unique_ptr<CZ80Instruction> Z80Parser::parseOpcode(Parser& parser)
255255
const std::wstring stringValue = token.getStringValue();
256256
for (int z = 0; Z80Opcodes[z].name != nullptr; z++)
257257
{
258+
if ((Z80Opcodes[z].flags & Z80_GAMEBOY) && Z80.GetVersion() != ZARCH_GAMEBOY)
259+
continue;
260+
258261
if (stringValue == Z80Opcodes[z].name)
259262
{
260263
TokenizerPosition tokenPos = parser.getTokenizer()->getPosition();

Parser/DirectivesParser.cpp

Lines changed: 17 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -450,7 +450,20 @@ std::unique_ptr<CAssemblerCommand> parseDirectiveZ80Arch(Parser& parser, int fla
450450
{
451451
Arch = &Z80;
452452

453-
return std::make_unique<ArchitectureCommand>(L".gb", L"");
453+
switch (flags)
454+
{
455+
case DIRECTIVE_Z80_Z80:
456+
Z80.SetVersion(ZARCH_Z80);
457+
return std::make_unique<ArchitectureCommand>(L".z80", L"");
458+
case DIRECTIVE_Z80_GB:
459+
Z80.SetVersion(ZARCH_GAMEBOY);
460+
return std::make_unique<ArchitectureCommand>(L".gb", L"");
461+
case DIRECTIVE_Z80_GBC:
462+
Z80.SetVersion(ZARCH_GAMEBOY);
463+
return std::make_unique<ArchitectureCommand>(L".gbc", L"");
464+
}
465+
466+
return nullptr;
454467
}
455468

456469
std::unique_ptr<CAssemblerCommand> parseDirectiveArea(Parser& parser, int flags)
@@ -784,8 +797,9 @@ const DirectiveMap directives = {
784797
{ L".arm.big", { &parseDirectiveArmArch, DIRECTIVE_ARM_BIG } },
785798
{ L".arm.little", { &parseDirectiveArmArch, DIRECTIVE_ARM_LITTLE } },
786799

787-
{ L".gb", { &parseDirectiveZ80Arch, 0 } },
788-
{ L".gbc", { &parseDirectiveZ80Arch, 0 } },
800+
{ L".z80", { &parseDirectiveZ80Arch, DIRECTIVE_Z80_Z80 } },
801+
{ L".gb", { &parseDirectiveZ80Arch, DIRECTIVE_Z80_GB } },
802+
{ L".gbc", { &parseDirectiveZ80Arch, DIRECTIVE_Z80_GBC } },
789803

790804
{ L".area", { &parseDirectiveArea, 0 } },
791805
{ L".autoregion", { &parseDirectiveAutoRegion, 0 } },

Parser/DirectivesParser.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,11 @@ using DirectiveMap = std::unordered_multimap<std::wstring, const DirectiveEntry>
6868
#define DIRECTIVE_ARM_BIG 0x00000004
6969
#define DIRECTIVE_ARM_LITTLE 0x00000005
7070

71+
// Z80 directive flags
72+
#define DIRECTIVE_Z80_Z80 0x00000001
73+
#define DIRECTIVE_Z80_GB 0x00000002
74+
#define DIRECTIVE_Z80_GBC 0x00000003
75+
7176
// Area directive flags
7277
#define DIRECTIVE_AREA_SHARED 0x00000001
7378

0 commit comments

Comments
 (0)