source: branches/configured machine/Cpu.pas

Last change on this file was 239, checked in by chronos, 10 months ago
File size: 14.1 KB
Line 
1unit Cpu;
2
3interface
4
5uses
6 Classes, SysUtils, Memory;
7
8type
9 TBitWidth = (bw8, bw16, bw32, bw64, bw128, bw256, bw512, bw1024);
10
11 TOpcode = (opNop, opHalt, opLoadMem, opStoreMem, opIncrement, opDecrement,
12 opJump, opPush, opPop, opCall, opReturn, opInput, opOutput, opAdd,
13 opSubtract, opLoad,
14 opDataWidth8, opDataWidth16, opAddressWidth8, opAddressWidth16);
15
16 { TValue }
17
18 TValue = record
19 class function Create8(Value: Byte): TValue; static;
20 class function Create16(Value: Word): TValue; static;
21 class function Create32(Value: DWord): TValue; static;
22 class function Create64(Value: QWord): TValue; static;
23 case TBitWidth of
24 bw8: (Value8: Byte);
25 bw16: (Value16: Word);
26 bw32: (Value32: DWord);
27 bw64: (Value64: QWord);
28 end;
29
30 TSignedValue = record
31 case TBitWidth of
32 bw8: (Value8: ShortInt);
33 bw16: (Value16: SmallInt);
34 bw32: (Value32: LongInt);
35 bw64: (Value64: Int64);
36 end;
37
38 { TCpu }
39
40 TCpu = class
41 private
42 FAddress: TValue;
43 FAddressWidth: TBitWidth;
44 FDataWidth: TBitWidth;
45 FFrequency: Integer;
46 FOnOutput: TNotifyEvent;
47 FOnInput: TNotifyEvent;
48 FOnRead: TNotifyEvent;
49 FOnWrite: TNotifyEvent;
50 function GetFrequency: Integer;
51 procedure SetAddressWidth(AValue: TBitWidth);
52 procedure SetFrequency(AValue: Integer);
53 procedure SetDataWidth(AValue: TBitWidth);
54 procedure Push(Data: TValue; BitWidth: TBitWidth);
55 procedure Pop(var Data: TValue; BitWidth: TBitWidth);
56 procedure DoRead;
57 procedure DoWrite;
58 procedure DoInput;
59 procedure DoOutput;
60 public
61 IP: TValue;
62 SP: TValue;
63 A: TValue;
64 Terminated: Boolean;
65 Data: TValue;
66 procedure Reset;
67 procedure Step;
68 procedure Run;
69 constructor Create;
70 destructor Destroy; override;
71 procedure AssignValue(var Dest: TValue; Source: TValue; Width: TBitWidth);
72 procedure ReadD8A8(var AAddress: TValue; var AData: TValue; Increment: Boolean);
73 procedure ReadD8A16(var AAddress: TValue; var AData: TValue; Increment: Boolean);
74 procedure ReadD16A8(var AAddress: TValue; var AData: TValue; Increment: Boolean);
75 procedure ReadD16A16(var AAddress: TValue; var AData: TValue; Increment: Boolean);
76 procedure Read(var Address: TValue; var Data: TValue; Increment: Boolean;
77 AddressWidth: TBitWidth; DataWidth: TBitWidth);
78 procedure ReadAddressA8(var Address: TValue; var Data: TValue; Increment: Boolean);
79 procedure ReadAddressA16(var Address: TValue; var Data: TValue; Increment: Boolean);
80 procedure ReadDataA8(var Address: TValue; var Data: TValue; Increment: Boolean);
81 procedure ReadDataA16(var Address: TValue; var Data: TValue; Increment: Boolean);
82 procedure ReadData(var Address: TValue; var Data: TValue; Increment: Boolean);
83 procedure ReadAddress(var Address: TValue; var Data: TValue; Increment: Boolean);
84 procedure WriteD8A8(var Address: TValue; AData: TValue; Increment: Boolean);
85 procedure WriteD8A16(var Address: TValue; AData: TValue; Increment: Boolean);
86 procedure WriteD16A8(var Address: TValue; AData: TValue; Increment: Boolean);
87 procedure WriteD16A16(var Address: TValue; AData: TValue; Increment: Boolean);
88 procedure Write(var Address: TValue; Data: TValue; Increment: Boolean;
89 AddressWidth: TBitWidth; DataWidth: TBitWidth);
90 procedure WriteAddressA8(var Address: TValue; Data: TValue; Increment: Boolean);
91 procedure WriteAddressA16(var Address: TValue; Data: TValue; Increment: Boolean);
92 procedure WriteDataA8(var Address: TValue; Data: TValue; Increment: Boolean);
93 procedure WriteDataA16(var Address: TValue; Data: TValue; Increment: Boolean);
94 procedure WriteData(var Address: TValue; Value: TValue; Increment: Boolean);
95 procedure WriteAddress(var Address: TValue; Value: TValue; Increment: Boolean);
96 property Frequency: Integer read FFrequency write FFrequency;
97 property DataWidth: TBitWidth read FDataWidth write SetDataWidth;
98 property Address: TValue read FAddress;
99 property AddressWidth: TBitWidth read FAddressWidth write SetAddressWidth;
100 property OnInput: TNotifyEvent read FOnInput write FOnInput;
101 property OnOutput: TNotifyEvent read FOnOutput write FOnOutput;
102 property OnRead: TNotifyEvent read FOnRead write FOnRead;
103 property OnWrite: TNotifyEvent read FOnWrite write FOnWrite;
104 end;
105
106const
107 BitWidthByteSize: array[TBitWidth] of Byte = (1, 2, 4, 8, 16, 32, 64, 128);
108
109
110implementation
111
112{ TValue }
113
114class function TValue.Create8(Value: Byte): TValue;
115begin
116 Result.Value8 := Value;
117end;
118
119class function TValue.Create16(Value: Word): TValue;
120begin
121 Result.Value16 := Value;
122end;
123
124class function TValue.Create32(Value: DWord): TValue;
125begin
126 Result.Value32 := Value;
127end;
128
129class function TValue.Create64(Value: QWord): TValue;
130begin
131 Result.Value64 := Value;
132end;
133
134procedure TCpu.ReadD8A8(var AAddress: TValue; var AData: TValue;
135 Increment: Boolean);
136begin
137 FAddress.Value8 := AAddress.Value8;
138 DoRead;
139 AData.Value8 := Data.Value8;
140 if Increment then AAddress.Value8 := AAddress.Value8 + 1;
141end;
142
143procedure TCpu.ReadD8A16(var AAddress: TValue; var AData: TValue;
144 Increment: Boolean);
145begin
146 FAddress.Value16 := AAddress.Value16;
147 DoRead;
148 AData.Value8 := Data.Value8;
149 if Increment then AAddress.Value16 := AAddress.Value16 + 1;
150end;
151
152procedure TCpu.ReadD16A8(var AAddress: TValue; var AData: TValue;
153 Increment: Boolean);
154begin
155 FAddress.Value8 := AAddress.Value8;
156 DoRead;
157 AData.Value16 := Data.Value16;
158 if Increment then AAddress.Value8 := AAddress.Value8 + 1;
159end;
160
161procedure TCpu.ReadD16A16(var AAddress: TValue; var AData: TValue;
162 Increment: Boolean);
163begin
164 FAddress.Value16 := AAddress.Value16;
165 DoRead;
166 AData.Value16 := Data.Value16;
167 if Increment then AAddress.Value16 := AAddress.Value16 + 1;
168end;
169
170procedure TCpu.Read(var Address: TValue; var Data: TValue; Increment: Boolean;
171 AddressWidth: TBitWidth; DataWidth: TBitWidth);
172begin
173 case AddressWidth of
174 bw8: case DataWidth of
175 bw8: ReadD8A8(Address, Data, Increment);
176 bw16: ReadD16A8(Address, Data, Increment);
177 end;
178 bw16: case DataWidth of
179 bw8: ReadD8A16(Address, Data, Increment);
180 bw16: ReadD16A16(Address, Data, Increment);
181 end;
182 end;
183end;
184
185procedure TCpu.ReadAddressA8(var Address: TValue; var Data: TValue;
186 Increment: Boolean);
187begin
188 case AddressWidth of
189 bw8: ReadD8A8(Address, Data, Increment);
190 bw16: ReadD16A8(Address, Data, Increment);
191 end;
192end;
193
194procedure TCpu.ReadAddressA16(var Address: TValue; var Data: TValue;
195 Increment: Boolean);
196begin
197 case AddressWidth of
198 bw8: ReadD8A16(Address, Data, Increment);
199 bw16: ReadD16A16(Address, Data, Increment);
200 end;
201end;
202
203procedure TCpu.ReadDataA8(var Address: TValue; var Data: TValue;
204 Increment: Boolean);
205begin
206 case DataWidth of
207 bw8: ReadD8A8(Address, Data, Increment);
208 bw16: ReadD16A8(Address, Data, Increment);
209 end;
210end;
211
212procedure TCpu.ReadDataA16(var Address: TValue; var Data: TValue;
213 Increment: Boolean);
214begin
215 case DataWidth of
216 bw8: ReadD8A16(Address, Data, Increment);
217 bw16: ReadD16A16(Address, Data, Increment);
218 end;
219end;
220
221procedure TCpu.ReadAddress(var Address: TValue; var Data: TValue;
222 Increment: Boolean);
223begin
224 case AddressWidth of
225 bw8: ReadAddressA8(Address, Data, Increment);
226 bw16: ReadAddressA16(Address, Data, Increment);
227 end;
228end;
229
230procedure TCpu.ReadData(var Address: TValue; var Data: TValue;
231 Increment: Boolean);
232begin
233 case AddressWidth of
234 bw8: ReadDataA8(Address, Data, Increment);
235 bw16: ReadDataA16(Address, Data, Increment);
236 end;
237end;
238
239procedure TCpu.WriteD8A8(var Address: TValue; AData: TValue; Increment: Boolean);
240begin
241 FAddress.Value8 := Address.Value8;
242 Data.Value8 := AData.Value8;
243 DoWrite;
244 if Increment then Address.Value8 := Address.Value8 + 1;
245end;
246
247procedure TCpu.WriteD8A16(var Address: TValue; AData: TValue; Increment: Boolean
248 );
249begin
250 FAddress.Value16 := Address.Value16;
251 Data.Value8 := AData.Value8;
252 DoWrite;
253 if Increment then Address.Value16 := Address.Value16 + 1;
254end;
255
256procedure TCpu.WriteD16A8(var Address: TValue; AData: TValue; Increment: Boolean
257 );
258begin
259 FAddress.Value8 := Address.Value8;
260 Data.Value16 := AData.Value16;
261 DoWrite;
262 if Increment then Address.Value8 := Address.Value8 + 1;
263end;
264
265procedure TCpu.WriteD16A16(var Address: TValue; AData: TValue; Increment: Boolean
266 );
267begin
268 FAddress.Value16 := Address.Value16;
269 AData.Value16 := AData.Value16;
270 DoWrite;
271 if Increment then Address.Value16 := Address.Value16 + 1;
272end;
273
274procedure TCpu.Write(var Address: TValue; Data: TValue; Increment: Boolean;
275 AddressWidth: TBitWidth; DataWidth: TBitWidth);
276begin
277 case AddressWidth of
278 bw8: case DataWidth of
279 bw8: WriteD8A8(Address, Data, Increment);
280 bw16: WriteD16A8(Address, Data, Increment);
281 end;
282 bw16: case DataWidth of
283 bw8: WriteD8A16(Address, Data, Increment);
284 bw16: WriteD16A16(Address, Data, Increment);
285 end;
286 end;
287end;
288
289procedure TCpu.WriteAddressA8(var Address: TValue; Data: TValue;
290 Increment: Boolean);
291begin
292 case AddressWidth of
293 bw8: WriteD8A8(Address, Data, Increment);
294 bw16: WriteD16A8(Address, Data, Increment);
295 end;
296end;
297
298procedure TCpu.WriteAddressA16(var Address: TValue; Data: TValue;
299 Increment: Boolean);
300begin
301 case AddressWidth of
302 bw8: WriteD8A16(Address, Data, Increment);
303 bw16: WriteD16A16(Address, Data, Increment);
304 end;
305end;
306
307procedure TCpu.WriteDataA8(var Address: TValue; Data: TValue; Increment: Boolean
308 );
309begin
310 case DataWidth of
311 bw8: WriteD8A8(Address, Data, Increment);
312 bw16: WriteD16A8(Address, Data, Increment);
313 end;
314end;
315
316procedure TCpu.WriteDataA16(var Address: TValue; Data: TValue;
317 Increment: Boolean);
318begin
319 case DataWidth of
320 bw8: WriteD8A16(Address, Data, Increment);
321 bw16: WriteD16A16(Address, Data, Increment);
322 end;
323end;
324
325procedure TCpu.WriteData(var Address: TValue; Value: TValue; Increment: Boolean
326 );
327begin
328 case AddressWidth of
329 bw8: WriteDataA8(Address, Value, Increment);
330 bw16: WriteDataA16(Address, Value, Increment);
331 end;
332end;
333
334procedure TCpu.WriteAddress(var Address: TValue; Value: TValue;
335 Increment: Boolean);
336begin
337 case AddressWidth of
338 bw8: WriteAddressA8(Address, Value, Increment);
339 bw16: WriteAddressA16(Address, Value, Increment);
340 end;
341end;
342
343procedure TCpu.Push(Data: TValue; BitWidth: TBitWidth);
344begin
345 case AddressWidth of
346 bw8: SP.Value8 := SP.Value8 - BitWidthByteSize[BitWidth];
347 bw16: SP.Value16 := SP.Value16 - BitWidthByteSize[BitWidth];
348 end;
349 WriteData(SP, Data, False);
350end;
351
352procedure TCpu.Pop(var Data: TValue; BitWidth: TBitWidth);
353begin
354 ReadData(SP, Data, False);
355 case AddressWidth of
356 bw8: SP.Value8 := SP.Value8 + BitWidthByteSize[BitWidth];
357 bw16: SP.Value16 := SP.Value16 + BitWidthByteSize[BitWidth];
358 end;
359end;
360
361procedure TCpu.DoRead;
362begin
363 if Assigned(FOnRead) then FOnRead(Self);
364end;
365
366procedure TCpu.DoWrite;
367begin
368 if Assigned(FOnWrite) then FOnWrite(Self);
369end;
370
371procedure TCpu.DoInput;
372begin
373 if Assigned(FOnInput) then FOnInput(Self);
374end;
375
376procedure TCpu.DoOutput;
377begin
378 if Assigned(FOnOutput) then FOnOutput(Self);
379end;
380
381procedure TCpu.Reset;
382begin
383 Terminated := False;
384 A.Value64 := 0;
385 IP.Value64 := 0;
386 SP.Value64 := 0;
387end;
388
389function TCpu.GetFrequency: Integer;
390begin
391 Result := FFrequency;
392end;
393
394procedure TCpu.SetAddressWidth(AValue: TBitWidth);
395begin
396 if FAddressWidth = AValue then Exit;
397 FAddressWidth := AValue;
398end;
399
400procedure TCpu.SetFrequency(AValue: Integer);
401begin
402 FFrequency := AValue;
403end;
404
405procedure TCpu.SetDataWidth(AValue: TBitWidth);
406begin
407 if FDataWidth = AValue then Exit;
408 FDataWidth := AValue;
409end;
410
411procedure TCpu.Step;
412var
413 Opcode: TOpcode;
414 Data: TValue;
415 Addr: TValue;
416 LastWidth: TBitWidth;
417begin
418 Read(IP, Data, True, AddressWidth, bw8);
419 Opcode := TOpcode(Data.Value8);
420 case Opcode of
421 opNop: ; // Do nothing
422 opHalt: Terminated := True;
423 opLoad: ReadData(IP, A, True);
424 opLoadMem: begin
425 ReadAddress(IP, Addr, True);
426 ReadData(Addr, A, False);
427 end;
428 opStoreMem: begin
429 ReadAddress(IP, Addr, True);
430 WriteData(Addr, A, False);
431 end;
432 opIncrement: case DataWidth of
433 bw8: A.Value8 := A.Value8 + 1;
434 bw16: A.Value16 := A.Value16 + 1;
435 end;
436 opDecrement: case DataWidth of
437 bw8: A.Value8 := A.Value8 - 1;
438 bw16: A.Value16 := A.Value16 - 1;
439 end;
440 opJump: begin
441 ReadAddress(IP, Addr, True);
442 IP := Addr;
443 end;
444 opPush: Push(A, DataWidth);
445 opPop: Pop(A, DataWidth);
446 opCall: begin
447 ReadAddress(IP, Addr, True);
448 Push(Addr, AddressWidth);
449 IP := Addr;
450 end;
451 opReturn: begin
452 Pop(Addr, AddressWidth);
453 IP := Addr;
454 end;
455 opAdd: begin
456 ReadData(IP, Data, True);
457 case DataWidth of
458 bw8: A.Value8 := A.Value8 + Data.Value8;
459 bw16: A.Value16 := A.Value16 + Data.Value16;
460 end;
461 end;
462 opSubtract: begin
463 ReadData(IP, Data, True);
464 case DataWidth of
465 bw8: A.Value8 := A.Value8 - Data.Value8;
466 bw16: A.Value16 := A.Value16 - Data.Value16;
467 end;
468 end;
469 opInput: begin
470 ReadAddress(IP, FAddress, True);
471 DoInput;
472 AssignValue(A, Data, DataWidth);
473 end;
474 opOutput: begin
475 ReadAddress(IP, FAddress, True);
476 AssignValue(Data, A, DataWidth);
477 DoOutput;
478 end;
479 opDataWidth8: if DataWidth <> bw8 then begin
480 LastWidth := DataWidth;
481 DataWidth := bw8;
482 Step;
483 DataWidth := LastWidth;
484 end;
485 opDataWidth16: if DataWidth <> bw16 then begin
486 LastWidth := DataWidth;
487 DataWidth := bw16;
488 Step;
489 DataWidth := LastWidth;
490 end;
491 opAddressWidth8: if AddressWidth <> bw8 then begin
492 LastWidth := AddressWidth;
493 AddressWidth := bw8;
494 Step;
495 AddressWidth := LastWidth;
496 end;
497 opAddressWidth16: if AddressWidth <> bw16 then begin
498 LastWidth := AddressWidth;
499 AddressWidth := bw16;
500 Step;
501 AddressWidth := LastWidth;
502 end;
503 end;
504end;
505
506procedure TCpu.Run;
507begin
508 Reset;
509 while not Terminated do
510 Step;
511end;
512
513constructor TCpu.Create;
514begin
515end;
516
517destructor TCpu.Destroy;
518begin
519 inherited;
520end;
521
522procedure TCpu.AssignValue(var Dest: TValue; Source: TValue; Width: TBitWidth);
523begin
524 case Width of
525 bw8: Dest.Value8 := Source.Value8;
526 end;
527end;
528
529end.
530
Note: See TracBrowser for help on using the repository browser.