1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
|
namespace Q1.core.Arch;
// Big endian
public class Chip
{
public IAddressable Bus;
public u16 Pc, Sp;
public u16 Ax, Dx, Lx;
private u16[] _registers;
public void Reset()
{
this._registers = new u16[64];
this.Pc = ChipLayout.PROGRAM_START;
this.Sp = ChipLayout.STACK_START;
}
public void Clock()
{
this.Bus.Clock();
this.Fetch(out u8 opcode, out u8 m1, out u8 m2, out bool word);
switch (m1, m2)
{
case (0x00, 0x00):
InstructionSet.Lookup[opcode].Implicit.Execute(this, word);
break;
case (_, 0x00):
InstructionSet.Lookup[opcode].SimpleAddressing.Execute(this, m1, word);
break;
case (0x00, 0x01):
InstructionSet.Lookup[opcode].ExtendedImplicit.Execute(this, word);
break;
case (_, _):
InstructionSet.Lookup[opcode].ExtendedAddressing.Execute(this, m1, m2, word);
break;
}
}
/// [opcode: 7 bits] [word: 1 bits] [m1: 4 bits] [m2: 4 bits]
public void Fetch(out u8 opcode, out u8 m1, out u8 m2, out bool word)
{
u16 instruction = this.Bus.ReadWord(this.Pc);
this.Pc += 2;
opcode = (u8) ((instruction >> 8) & 0xFE); // 128 opcodes
word = ((instruction >> 8) & 0x1) != 0; // flag for word mode
m1 = (u8) ((instruction >> 4) & 0x0F); // 16 modes
m2 = (u8) (instruction & 0x0F); // 16 modes
}
public void SkipInstruction()
{
this.Fetch(out u8 _, out u8 m1, out u8 m2, out bool word);
this.Pc += (u8)(Size(m1, word) + Size(m2, word));
}
public u16 Load(u8 mode, bool word)
{
AddressingMode am = AddressingModes.Lookup[mode];
return word ? am.LoadWord(this) : am.LoadByte(this);
}
public void Store(u8 mode, u16 value, bool word)
{
AddressingMode am = AddressingModes.Lookup[mode];
if (word) am.StoreWord(this, value);
else am.StoreByte(this, (u8)(value & 0xFF));
}
public u8 Size(u8 mode, bool word)
{
AddressingMode am = AddressingModes.Lookup[mode];
return word ? am.SizeW : am.SizeB;
}
public void Push(u16 value)
{
if (this.Sp + 2 > ChipLayout.STACK_START + ChipLayout.STACK_SIZE)
throw new InvalidOperationException("Stack overflow");
this.Bus.WriteWord(this.Sp, value);
this.Sp += 2;
}
public u16 Pop()
{
if (this.Sp - 2 < ChipLayout.STACK_START)
throw new InvalidOperationException("Stack underflow");
this.Sp -= 2;
u16 value = this.Bus.ReadWord(this.Sp);
return value;
}
public u16 GetRegister(u8 index)
{
if (index < 64) return this._registers[index];
if (index == 0x40) return this.Ax;
if (index == 0x41) return (u16) (this.Ax >> 8); // High byte of Ax
if (index == 0x42) return (u16) (this.Ax & 0xFF); // Low byte of Ax
if (index == 0x44) return this.Dx;
if (index == 0x45) return (u16) (this.Dx >> 8); // High byte of Dx
if (index == 0x46) return (u16) (this.Dx & 0xFF); // Low byte of Dx
if (index == 0x48) return this.Lx;
if (index == 0x4C) return this.Pc;
if (index == 0x4D) return this.Sp;
throw new InvalidOperationException($"Invalid register index: {index}");
}
public void SetRegister(u8 index, u16 value)
{
if (index < 64) this._registers[index] = value;
else if (index == 0x40) this.Ax = value;
else if (index == 0x41) this.Ax = (u16)((this.Ax & 0x00FF) | ((value & 0xFF) << 8)); // Set high byte of Ax
else if (index == 0x42) this.Ax = (u16)((this.Ax & 0xFF00) | (value & 0xFF)); // Set low byte of Ax
else if (index == 0x44) this.Dx = value;
else if (index == 0x45) this.Dx = (u16)((this.Dx & 0x00FF) | ((value & 0xFF) << 8)); // Set high byte of Dx
else if (index == 0x46) this.Dx = (u16)((this.Dx & 0xFF00) | (value & 0xFF)); // Set low byte of Dx
else if (index == 0x48) this.Lx = value;
else if (index == 0x4C) this.Pc = value;
else if (index == 0x4D) this.Sp = value;
else throw new InvalidOperationException($"Invalid register index: {index}");
}
}
|