1 | unit UCpu;
|
---|
2 |
|
---|
3 | {$mode delphi}{$H+}
|
---|
4 |
|
---|
5 | interface
|
---|
6 |
|
---|
7 | uses
|
---|
8 | Classes, SysUtils;
|
---|
9 |
|
---|
10 | type
|
---|
11 | TAddress = QWord;
|
---|
12 | TData = QWord;
|
---|
13 | TOpcode = (opNop, opHalt, opLda, opSta, opAdda, opSuba, opLdca, opBra, opInp,
|
---|
14 | opOut, opBrz, opBrnz, opInca, opDeca, opLdi, opSti, opAnd, opOr, opXor,
|
---|
15 | opLdp, opStp, opAddp, opSubp, opLdcp, opIncp, opDecp);
|
---|
16 |
|
---|
17 | PAddress = ^TAddress;
|
---|
18 | PData = ^TData;
|
---|
19 | POpcode = ^TOpcode;
|
---|
20 |
|
---|
21 | TOpcodeHandler = procedure of object;
|
---|
22 | TInputEvent = function (Address: TAddress): TData of object;
|
---|
23 | TOutputEvent = procedure (Address: TAddress; Data: TData) of object;
|
---|
24 |
|
---|
25 | { TCpu }
|
---|
26 |
|
---|
27 | TCpu = class
|
---|
28 | private
|
---|
29 | FOnInput: TInputEvent;
|
---|
30 | FOnOutput: TOutputEvent;
|
---|
31 | OpcodeHandlers: array[TOpcode] of TOpcodeHandler;
|
---|
32 | procedure OpcodeAddp;
|
---|
33 | procedure OpcodeLdcp;
|
---|
34 | procedure OpcodeLdp;
|
---|
35 | procedure OpcodeNop;
|
---|
36 | procedure OpcodeHalt;
|
---|
37 | procedure OpcodeLda;
|
---|
38 | procedure OpcodeSta;
|
---|
39 | procedure OpcodeAdda;
|
---|
40 | procedure OpcodeStp;
|
---|
41 | procedure OpcodeSuba;
|
---|
42 | procedure OpcodeBra;
|
---|
43 | procedure OpcodeBrz;
|
---|
44 | procedure OpcodeBrnz;
|
---|
45 | procedure OpcodeLdca;
|
---|
46 | procedure OpcodeInp;
|
---|
47 | procedure OpcodeOut;
|
---|
48 | procedure OpcodeInca;
|
---|
49 | procedure OpcodeDeca;
|
---|
50 | procedure OpcodeLdi;
|
---|
51 | procedure OpcodeSti;
|
---|
52 | procedure OpcodeAnd;
|
---|
53 | procedure OpcodeOr;
|
---|
54 | procedure OpcodeSubp;
|
---|
55 | procedure OpcodeXor;
|
---|
56 | procedure OpcodeIncp;
|
---|
57 | procedure OpcodeDecp;
|
---|
58 | public
|
---|
59 | Memory: array of Byte;
|
---|
60 | A: TData;
|
---|
61 | P: TAddress;
|
---|
62 | IP: TAddress;
|
---|
63 | Cycles: Integer;
|
---|
64 | Terminated: Boolean;
|
---|
65 | function ReadOpcode: TOpcode;
|
---|
66 | function ReadData: TData;
|
---|
67 | function ReadAddress: TAddress;
|
---|
68 | procedure WriteOpcode(Opcode: TOpcode);
|
---|
69 | procedure WriteData(Data: TData);
|
---|
70 | procedure WriteAddress(Address: TAddress);
|
---|
71 | procedure WriteString(Text: string);
|
---|
72 | procedure Step;
|
---|
73 | procedure Run;
|
---|
74 | procedure Reset;
|
---|
75 | constructor Create;
|
---|
76 | property OnInput: TInputEvent read FOnInput write FOnInput;
|
---|
77 | property OnOutput: TOutputEvent read FOnOutput write FOnOutput;
|
---|
78 | end;
|
---|
79 |
|
---|
80 | implementation
|
---|
81 |
|
---|
82 | { TCpu }
|
---|
83 |
|
---|
84 | procedure TCpu.OpcodeNop;
|
---|
85 | begin
|
---|
86 | end;
|
---|
87 |
|
---|
88 | procedure TCpu.OpcodeHalt;
|
---|
89 | begin
|
---|
90 | Terminated := True;
|
---|
91 | end;
|
---|
92 |
|
---|
93 | procedure TCpu.OpcodeLda;
|
---|
94 | var
|
---|
95 | Address: TAddress;
|
---|
96 | begin
|
---|
97 | Address := ReadAddress;
|
---|
98 | A := PData(@Memory[Address])^;
|
---|
99 | end;
|
---|
100 |
|
---|
101 | procedure TCpu.OpcodeSta;
|
---|
102 | var
|
---|
103 | Address: TAddress;
|
---|
104 | begin
|
---|
105 | Address := ReadAddress;
|
---|
106 | PData(@Memory[Address])^ := A;
|
---|
107 | end;
|
---|
108 |
|
---|
109 | procedure TCpu.OpcodeAdda;
|
---|
110 | var
|
---|
111 | Address: TAddress;
|
---|
112 | begin
|
---|
113 | Address := ReadAddress;
|
---|
114 | A := A + PData(@Memory[Address])^;
|
---|
115 | end;
|
---|
116 |
|
---|
117 | procedure TCpu.OpcodeSuba;
|
---|
118 | var
|
---|
119 | Address: TAddress;
|
---|
120 | begin
|
---|
121 | Address := ReadAddress;
|
---|
122 | A := A - PData(@Memory[Address])^;
|
---|
123 | end;
|
---|
124 |
|
---|
125 | procedure TCpu.OpcodeBra;
|
---|
126 | begin
|
---|
127 | IP := ReadAddress;
|
---|
128 | end;
|
---|
129 |
|
---|
130 | procedure TCpu.OpcodeBrz;
|
---|
131 | var
|
---|
132 | Address: TAddress;
|
---|
133 | begin
|
---|
134 | Address := ReadAddress;
|
---|
135 | if A = 0 then IP := Address;
|
---|
136 | end;
|
---|
137 |
|
---|
138 | procedure TCpu.OpcodeBrnz;
|
---|
139 | var
|
---|
140 | Address: TAddress;
|
---|
141 | begin
|
---|
142 | Address := ReadAddress;
|
---|
143 | if A <> 0 then IP := Address;
|
---|
144 | end;
|
---|
145 |
|
---|
146 | procedure TCpu.OpcodeLdca;
|
---|
147 | begin
|
---|
148 | A := ReadData;
|
---|
149 | end;
|
---|
150 |
|
---|
151 | procedure TCpu.OpcodeInp;
|
---|
152 | var
|
---|
153 | Address: TAddress;
|
---|
154 | begin
|
---|
155 | Address := ReadAddress;
|
---|
156 | if Assigned(FOnInput) then
|
---|
157 | A := FOnInput(Address);
|
---|
158 | end;
|
---|
159 |
|
---|
160 | procedure TCpu.OpcodeOut;
|
---|
161 | var
|
---|
162 | Address: TAddress;
|
---|
163 | begin
|
---|
164 | Address := ReadAddress;
|
---|
165 | if Assigned(FOnOutput) then
|
---|
166 | FOnOutput(Address, A);
|
---|
167 | end;
|
---|
168 |
|
---|
169 | procedure TCpu.OpcodeInca;
|
---|
170 | begin
|
---|
171 | A := A + 1;
|
---|
172 | end;
|
---|
173 |
|
---|
174 | procedure TCpu.OpcodeDeca;
|
---|
175 | begin
|
---|
176 | A := A - 1;
|
---|
177 | end;
|
---|
178 |
|
---|
179 | procedure TCpu.OpcodeLdi;
|
---|
180 | var
|
---|
181 | Address: TAddress;
|
---|
182 | begin
|
---|
183 | Address := ReadAddress;
|
---|
184 | Address := PAddress(@Memory[Address])^;
|
---|
185 | A := PData(@Memory[Address])^;
|
---|
186 | end;
|
---|
187 |
|
---|
188 | procedure TCpu.OpcodeSti;
|
---|
189 | var
|
---|
190 | Address: TAddress;
|
---|
191 | begin
|
---|
192 | Address := ReadAddress;
|
---|
193 | Address := PAddress(@Memory[Address])^;
|
---|
194 | PData(@Memory[Address])^ := A;
|
---|
195 | end;
|
---|
196 |
|
---|
197 | procedure TCpu.OpcodeAnd;
|
---|
198 | var
|
---|
199 | Address: TAddress;
|
---|
200 | begin
|
---|
201 | Address := ReadAddress;
|
---|
202 | A := A and PData(@Memory[Address])^;
|
---|
203 | end;
|
---|
204 |
|
---|
205 | procedure TCpu.OpcodeOr;
|
---|
206 | begin
|
---|
207 | A := A or PData(@Memory[ReadAddress])^;
|
---|
208 | end;
|
---|
209 |
|
---|
210 | procedure TCpu.OpcodeXor;
|
---|
211 | begin
|
---|
212 | A := A xor PData(@Memory[ReadAddress])^;
|
---|
213 | end;
|
---|
214 |
|
---|
215 | procedure TCpu.OpcodeIncp;
|
---|
216 | begin
|
---|
217 | P := P + 1;
|
---|
218 | end;
|
---|
219 |
|
---|
220 | procedure TCpu.OpcodeDecp;
|
---|
221 | begin
|
---|
222 | P := P - 1;
|
---|
223 | end;
|
---|
224 |
|
---|
225 | procedure TCpu.OpcodeLdp;
|
---|
226 | var
|
---|
227 | Address: TAddress;
|
---|
228 | begin
|
---|
229 | Address := ReadAddress;
|
---|
230 | P := PAddress(@Memory[Address])^;
|
---|
231 | end;
|
---|
232 |
|
---|
233 | procedure TCpu.OpcodeStp;
|
---|
234 | var
|
---|
235 | Address: TAddress;
|
---|
236 | begin
|
---|
237 | Address := ReadAddress;
|
---|
238 | PAddress(@Memory[Address])^ := P;
|
---|
239 | end;
|
---|
240 |
|
---|
241 | procedure TCpu.OpcodeAddp;
|
---|
242 | var
|
---|
243 | Address: TAddress;
|
---|
244 | begin
|
---|
245 | Address := ReadAddress;
|
---|
246 | P := P + PAddress(@Memory[Address])^;
|
---|
247 | end;
|
---|
248 |
|
---|
249 | procedure TCpu.OpcodeSubp;
|
---|
250 | var
|
---|
251 | Address: TAddress;
|
---|
252 | begin
|
---|
253 | Address := ReadAddress;
|
---|
254 | P := P - PAddress(@Memory[Address])^;
|
---|
255 | end;
|
---|
256 |
|
---|
257 | procedure TCpu.OpcodeLdcp;
|
---|
258 | begin
|
---|
259 | P := ReadAddress;
|
---|
260 | end;
|
---|
261 |
|
---|
262 | function TCpu.ReadOpcode: TOpcode;
|
---|
263 | begin
|
---|
264 | Result := TOpcode(PByte(@Memory[IP])^);
|
---|
265 | Inc(IP, SizeOf(Byte));
|
---|
266 | end;
|
---|
267 |
|
---|
268 | function TCpu.ReadAddress: TAddress;
|
---|
269 | begin
|
---|
270 | Result := PAddress(@Memory[IP])^;
|
---|
271 | Inc(IP, SizeOf(TAddress));
|
---|
272 | end;
|
---|
273 |
|
---|
274 | procedure TCpu.WriteOpcode(Opcode: TOpcode);
|
---|
275 | begin
|
---|
276 | PByte(@Memory[IP])^ := Byte(Opcode);
|
---|
277 | Inc(IP, SizeOf(Byte));
|
---|
278 | end;
|
---|
279 |
|
---|
280 | procedure TCpu.WriteData(Data: TData);
|
---|
281 | begin
|
---|
282 | PData(@Memory[IP])^ := Data;
|
---|
283 | Inc(IP, SizeOf(TData));
|
---|
284 | end;
|
---|
285 |
|
---|
286 | procedure TCpu.WriteAddress(Address: TAddress);
|
---|
287 | begin
|
---|
288 | PAddress(@Memory[IP])^ := Address;
|
---|
289 | Inc(IP, SizeOf(TAddress));
|
---|
290 | end;
|
---|
291 |
|
---|
292 | procedure TCpu.WriteString(Text: string);
|
---|
293 | var
|
---|
294 | I: Integer;
|
---|
295 | begin
|
---|
296 | for I := 1 to Length(Text) do
|
---|
297 | Memory[IP + I - 1] := Ord(Text[I]);
|
---|
298 | Inc(IP, Length(Text));
|
---|
299 | end;
|
---|
300 |
|
---|
301 | function TCpu.ReadData: TData;
|
---|
302 | begin
|
---|
303 | Result := PData(@Memory[IP])^;
|
---|
304 | Inc(IP, SizeOf(TData));
|
---|
305 | end;
|
---|
306 |
|
---|
307 | procedure TCpu.Step;
|
---|
308 | var
|
---|
309 | Opcode: TOpcode;
|
---|
310 | begin
|
---|
311 | Opcode := ReadOpcode;
|
---|
312 | OpcodeHandlers[Opcode];
|
---|
313 | Inc(Cycles);
|
---|
314 | end;
|
---|
315 |
|
---|
316 | procedure TCpu.Run;
|
---|
317 | begin
|
---|
318 | while not Terminated do
|
---|
319 | Step;
|
---|
320 | end;
|
---|
321 |
|
---|
322 | procedure TCpu.Reset;
|
---|
323 | begin
|
---|
324 | IP := 0;
|
---|
325 | A := 0;
|
---|
326 | Cycles := 0;
|
---|
327 | Terminated := False;
|
---|
328 | end;
|
---|
329 |
|
---|
330 | constructor TCpu.Create;
|
---|
331 | begin
|
---|
332 | OpcodeHandlers[opNop] := OpcodeNop;
|
---|
333 | OpcodeHandlers[opHalt] := OpcodeHalt;
|
---|
334 | OpcodeHandlers[opLda] := OpcodeLda;
|
---|
335 | OpcodeHandlers[opSta] := OpcodeSta;
|
---|
336 | OpcodeHandlers[opAdda] := OpcodeAdda;
|
---|
337 | OpcodeHandlers[opSuba] := OpcodeSuba;
|
---|
338 | OpcodeHandlers[opLdca] := OpcodeLdca;
|
---|
339 | OpcodeHandlers[opBra] := OpcodeBra;
|
---|
340 | OpcodeHandlers[opBrz] := OpcodeBrz;
|
---|
341 | OpcodeHandlers[opBrnz] := OpcodeBrnz;
|
---|
342 | OpcodeHandlers[opInp] := OpcodeInp;
|
---|
343 | OpcodeHandlers[opOut] := OpcodeOut;
|
---|
344 | OpcodeHandlers[opInca] := OpcodeInca;
|
---|
345 | OpcodeHandlers[opDeca] := OpcodeDeca;
|
---|
346 | OpcodeHandlers[opLdi] := OpcodeLdi;
|
---|
347 | OpcodeHandlers[opSti] := OpcodeSti;
|
---|
348 | OpcodeHandlers[opAnd] := OpcodeAnd;
|
---|
349 | OpcodeHandlers[opOr] := OpcodeOr;
|
---|
350 | OpcodeHandlers[opXor] := OpcodeXor;
|
---|
351 |
|
---|
352 | // Address
|
---|
353 | OpcodeHandlers[opLdp] := OpcodeLdp;
|
---|
354 | OpcodeHandlers[opStp] := OpcodeStp;
|
---|
355 | OpcodeHandlers[opAddp] := OpcodeAddp;
|
---|
356 | OpcodeHandlers[opSubp] := OpcodeSubp;
|
---|
357 | OpcodeHandlers[opLdcp] := OpcodeLdcp;
|
---|
358 | OpcodeHandlers[opIncp] := OpcodeIncp;
|
---|
359 | OpcodeHandlers[opDecp] := OpcodeDecp;
|
---|
360 | end;
|
---|
361 |
|
---|
362 | end.
|
---|
363 |
|
---|