summaryrefslogtreecommitdiff
path: root/Chip/Q1CpuInstructions.cs
blob: 8b79a1d19c0cde77474b696f935c9f9f160e9b7a (plain)
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
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
namespace Q1Emu.Chip;

using System;
using System.Collections.Generic;

public partial class Q1Cpu
{
    public Dictionary<u8, (Action, Action<u8>, Action, Action<u8, u8>)> InstructionLookup;
    private void LoadInstructionLookup()
    {
        this.InstructionLookup = new Dictionary<u8, (Action, Action<u8>, Action, Action<u8, u8>)>
        {
            { 0x00, (this.Instruction_NOP, this.Instruction_JMP, this.Instruction_HALT, this.Instruction_MOV) },
            { 0x01, (this.Instruction_RET, this.Instruction_CALL, this.Instruction_SUS, this.Instruction_CMP) },
            { 0x02, (this.Instruction_BR, this.Instruction_BZ, this.Instruction_BZ_LX, this.Instruction_LT) },
            { 0x03, (this.Instruction_NOP, this.Instruction_NOP, this.Instruction_NOP, this.Instruction_GT) },

            { 0x04, (this.Instruction_NOT_LX, this.Instruction_NOT, this.Instruction_NOP, this.Instruction_AND) },
            { 0x05, (this.Instruction_INV_DX, this.Instruction_INV, this.Instruction_NOP, this.Instruction_OR) },
            { 0x06, (this.Instruction_SHL_DX, this.Instruction_SHL, this.Instruction_NOP, this.Instruction_XOR) },
            { 0x07, (this.Instruction_SHR_DX, this.Instruction_SHR, this.Instruction_NOP, this.Instruction_NOP) },

            { 0x08, (this.Instruction_INC_AX, this.Instruction_INC, this.Instruction_NOP, this.Instruction_ADD) },
            { 0x09, (this.Instruction_DEC_AX, this.Instruction_DEC, this.Instruction_NOP, this.Instruction_SUB) },
            { 0x0A, (this.Instruction_NOP, this.Instruction_NOP, this.Instruction_NOP, this.Instruction_DIV) },
            { 0x0B, (this.Instruction_NOP, this.Instruction_NOP, this.Instruction_NOP, this.Instruction_MUL) },
            { 0x0C, (this.Instruction_NOP, this.Instruction_NOP, this.Instruction_NOP, this.Instruction_MOD) },
        };
    }
    private void Instruction_ADD(u8 m1, u8 m2)
    {
        u16 v1 = this.FetchData(m1);
        u16 v2 = this.FetchData(m2);
        
        u16 result = (u16) (v1 + v2);
        this.AX = result;
    }
    private void Instruction_SUB(u8 m1, u8 m2)
    {
        u16 v1 = this.FetchData(m1);
        u16 v2 = this.FetchData(m2);
        
        u16 result = (u16)(v1 - v2);
        this.AX = result;
    }
    private void Instruction_MUL(u8 m1, u8 m2)
    {
        u16 v1 = this.FetchData(m1);
        u16 v2 = this.FetchData(m2);
        
        u16 result = (u16) (v1 * v2);
        this.AX = result;
    }
    private void Instruction_DIV(u8 m1, u8 m2)
    {
        u16 v1 = this.FetchData(m1);
        u16 v2 = this.FetchData(m2);
        
        if (v2 == 0)
            throw new DivideByZeroException("Cannot perform division by zero.");
        u16 result = (u16)(v1 / v2);
        this.AX = result;
    }
    private void Instruction_MOD(u8 m1, u8 m2)
    {
        u16 v1 = this.FetchData(m1);
        u16 v2 = this.FetchData(m2);
        
        if (v2 == 0)
            throw new DivideByZeroException("Cannot perform modulo operation with divisor zero.");
        u16 result = (u16)(v1 % v2);
        this.AX = result;
    }
    private void Instruction_INC(u8 obj)
    {
        this.TransformData(obj, value => (u16)(value + 1));
    }
    private void Instruction_DEC(u8 obj)
    {
        this.TransformData(obj, value => (u16)(value - 1));
    }
    private void Instruction_INC_AX()
    {
        this.AX = (u16)(this.AX + 1);
    }
    private void Instruction_DEC_AX()
    {
        this.AX = (u16)(this.AX - 1);
    }
    private void Instruction_SHL(u8 obj)
    {
        this.TransformData(obj, value => (u16)(value << 1));
    }
    private void Instruction_SHR(u8 obj)
    {
        this.TransformData(obj, value => (u16)(value >> 1));
    }
    private void Instruction_SHL_DX()
    {
        this.DX = (u16)(this.DX << 1);
    }
    private void Instruction_SHR_DX()
    {
        this.DX = (u16)(this.DX >> 1);
    }
    private void Instruction_XOR(u8 m1, u8 m2)
    {
        u16 v1 = this.FetchData(m1);
        u16 v2 = this.FetchData(m2);
        
        u16 result = (u16)(v1 ^ v2);
        this.DX = result;
    }
    private void Instruction_OR(u8 m1, u8 m2)
    {
        u16 v1 = this.FetchData(m1);
        u16 v2 = this.FetchData(m2);
        
        u16 result = (u16)(v1 | v2);
        this.DX = result;
    }
    private void Instruction_INV(u8 obj)
    {
        u16 value = this.FetchData(obj);
        u16 result = (u16)~value;
        this.DX = result;
    }
    private void Instruction_INV_DX()
    {
        this.DX = (u16)~this.DX;
    }
    private void Instruction_AND(u8 m1, u8 m2)
    {
        u16 v1 = this.FetchData(m1);
        u16 v2 = this.FetchData(m2);
        
        u16 result = (u16)(v1 & v2);
        this.DX = result;
    }
    private void Instruction_NOT(u8 obj)
    {
        u16 value = this.FetchData(obj);
        u16 result = value == 0 ? (u16)1 : (u16)0;
        this.LX = result;
    }
    private void Instruction_NOT_LX()
    {
        this.LX = this.LX == 0 ? (u16)1 : (u16)0;
    }
    private void Instruction_GT(u8 m1, u8 m2)
    {
        u16 v1 = this.FetchData(m1);
        u16 v2 = this.FetchData(m2);
        
        this.LX = (u16)(v1 > v2 ? 1 : 0);
    }
    private void Instruction_LT(u8 m1, u8 m2)
    {
        u16 v1 = this.FetchData(m1);
        u16 v2 = this.FetchData(m2);
        
        this.LX = (u16)(v1 < v2 ? 1 : 0);
    }
    
    private void Instruction_BR()
    {
        this.FetchInstruction(out _, out _, out _, out u8 length);
        this.PC += length;
    }
    private void Instruction_BZ_LX()
    {
        if (this.LX == 0)
            this.Instruction_BR();
    }
    private void Instruction_BZ(u8 obj)
    {
        u16 value = this.FetchData(obj);
        if (value == 0)
            this.Instruction_BR();
    }
    private void Instruction_CMP(u8 m1, u8 m2)
    {
        u16 v1 = this.FetchData(m1);
        u16 v2 = this.FetchData(m2);
        
        // Set LX based on comparison
        this.LX = (u16)(v1 == v2 ? 1 : 0);
    }
    private void Instruction_MOV(u8 m1, u8 m2)
    {
        u16 value = this.FetchData(m1);
        this.StoreData(m2, value);
    }

    public void Instruction_NOP() { }
    public void Instruction_NOP(u8 m1) { }
    public void Instruction_NOP(u8 m1, u8 m2) { }

    public void Instruction_JMP(u8 m1)
    {
        this.PC = this.FetchData(m1);
    }

    public void Instruction_RET()
    {
        this.PC = this.PopStack();
    }

    public void Instruction_CALL(u8 m1)
    {
        u16 address = this.FetchData(m1);
        this.PushStack(this.PC);
        this.PC = address;
    }

    public void Instruction_HALT()
    {
        throw new NotImplementedException("Halt instruction not implemented yet.");
    }

    public void Instruction_SUS()
    {
        this.PC -= 2;
    }
}