source: branches/configured machine/CpuLevels.pas

Last change on this file was 239, checked in by chronos, 16 months ago
File size: 6.8 KB
Line 
1unit CpuLevels;
2
3interface
4
5uses
6 Classes, SysUtils, Math;
7
8type
9 TInstruction = (inNop, inReti, inLoadMem, inStoreMem, inInput, inOutput,
10 inDescend, inAscend, inStoreSys, inSysCall);
11
12 TInstructionCall = procedure of object;
13
14 TData = Integer;
15 PData = ^TData;
16
17 { TLevel }
18
19 TLevel = class
20 Level: Byte;
21 MemoryBase: PByte;
22 MemorySize: Integer;
23 VirtMemBase: TData;
24 VirtMemSize: TData;
25 SP: TData;
26 PC: TData;
27 InstructionHandlers: array[TInstruction] of TInstructionCall;
28 function ReadMem(Address: TData): TData;
29 procedure WriteMem(Address: TData; Data: TData);
30 end;
31
32 TInputEvent = function(Address: TData): TData of object;
33 TOutputEvent = procedure(Address: TData; Data: TData) of object;
34
35 { TCpu }
36
37 TCpu = class
38 private
39 FLevelIndex: Integer;
40 FOnInput: TInputEvent;
41 FOnOutput: TOutputEvent;
42 procedure InitInstructionHandlers(Level: TLevel; Index: Integer);
43 procedure SetLevelIndex(AValue: Integer);
44 procedure InstructionNop;
45 procedure InstructionLoadMem;
46 procedure InstructionStoreMem;
47 procedure InstructionReti;
48 procedure InstructionUnknown;
49 procedure InstructionInput;
50 procedure InstructionOutput;
51 procedure InstructionDescend;
52 procedure InstructionAscend;
53 procedure InstructionStoreSys;
54 procedure InstructionSysCall;
55 procedure RebuildMem;
56 public
57 Levels: array of TLevel;
58 Level: TLevel;
59 InterruptedLevel: Integer;
60 InterruptEnabled: Boolean;
61 InterruptPending: Boolean;
62 InterruptVector: Integer;
63 Terminated: Boolean;
64 A: TData;
65 function ReadByte: Byte;
66 function ReadData: TData;
67 procedure Step;
68 procedure Run;
69 procedure Reset;
70 procedure Interrupt(Vector: Integer);
71 procedure Push(Value: TData);
72 function Pop: TData;
73 constructor Create;
74 property LevelIndex: Integer read FLevelIndex write SetLevelIndex;
75 property OnInput: TInputEvent read FOnInput write FOnInput;
76 property OnOutput: TOutputEvent read FOnOutput write FOnOutput;
77 end;
78
79const
80 InterruptVectorReset = 0;
81 InterruptVectorUnknownInstruction = 1;
82 InterruptVectorSysCall = 2;
83
84implementation
85
86{ TLevel }
87
88function TLevel.ReadMem(Address: TData): TData;
89begin
90 Result := PData(MemoryBase + Address)^;
91end;
92
93procedure TLevel.WriteMem(Address: TData; Data: TData);
94begin
95 PData(MemoryBase + Address)^ := Data;
96end;
97
98{ TCpu }
99
100procedure TCpu.InitInstructionHandlers(Level: TLevel; Index: Integer);
101begin
102 with Level do begin
103 InstructionHandlers[inNop] := InstructionNop;
104 InstructionHandlers[inLoadMem] := InstructionLoadMem;
105 InstructionHandlers[inStoreMem] := InstructionStoreMem;
106 InstructionHandlers[inAscend] := InstructionAscend;
107 InstructionHandlers[inDescend] := InstructionDescend;
108 InstructionHandlers[inStoreSys] := InstructionStoreSys;
109 if Index = 0 then begin
110 InstructionHandlers[inInput] := InstructionInput;
111 InstructionHandlers[inOutput] := InstructionOutput;
112 InstructionHandlers[inReti] := InstructionReti;
113 end else begin
114 InstructionHandlers[inInput] := InstructionUnknown;
115 InstructionHandlers[inOutput] := InstructionUnknown;
116 InstructionHandlers[inReti] := InstructionUnknown;
117 end;
118 end;
119end;
120
121procedure TCpu.SetLevelIndex(AValue: Integer);
122begin
123 if FLevelIndex = AValue then Exit;
124 FLevelIndex := AValue;
125 Level := Levels[FLevelIndex];
126end;
127
128procedure TCpu.InstructionNop;
129begin
130 // Do nothing
131end;
132
133procedure TCpu.InstructionLoadMem;
134var
135 Addr: Byte;
136begin
137 Addr := ReadByte;
138 A := Level.ReadMem(Addr);
139end;
140
141procedure TCpu.InstructionStoreMem;
142var
143 Addr: Byte;
144begin
145 Addr := ReadByte;
146 Level.WriteMem(Addr, A);
147end;
148
149function TCpu.ReadByte: Byte;
150begin
151 Result := PByte(Level.MemoryBase + Level.PC)^;
152 Inc(Level.PC);
153end;
154
155function TCpu.ReadData: TData;
156begin
157 Result := PData(Level.MemoryBase + Level.PC)^;
158 Inc(Level.PC, SizeOf(TData));
159end;
160
161procedure TCpu.Step;
162var
163 Instruction: TInstruction;
164begin
165 if InterruptEnabled and InterruptPending then begin
166 InterruptEnabled := False;
167 InterruptPending := False;
168 InterruptedLevel := LevelIndex;
169 LevelIndex := 0;
170 Push(Level.PC);
171 Level.PC := InterruptVector;
172 end else begin
173 Instruction := TInstruction(ReadByte);
174 Level.InstructionHandlers[Instruction];
175 end;
176end;
177
178procedure TCpu.Run;
179begin
180 Reset;
181 while not Terminated do
182 Step;
183end;
184
185procedure TCpu.Reset;
186begin
187 Terminated := False;
188 InterruptEnabled := True;
189 InterruptPending := False;
190 InterruptVector := 0;
191 LevelIndex := 0;
192 Level.PC := 0;
193 Level.SP := 0;
194 InitInstructionHandlers(Level, 0);
195end;
196
197procedure TCpu.Interrupt(Vector: Integer);
198begin
199 InterruptPending := True;
200 InterruptVector := Vector;
201end;
202
203procedure TCpu.InstructionReti;
204begin
205 Level.PC := Pop;
206 LevelIndex := InterruptedLevel;
207 InterruptEnabled := True;
208end;
209
210procedure TCpu.InstructionUnknown;
211begin
212 if LevelIndex = 0 then Interrupt(1)
213 else begin
214 InterruptedLevel := LevelIndex;
215 LevelIndex := LevelIndex - 1;
216 Level.PC := InterruptVectorUnknownInstruction;
217 //Level.A := LastInstruction;
218 end;
219end;
220
221procedure TCpu.InstructionInput;
222var
223 Address: TData;
224begin
225 Address := ReadData;
226 if Assigned(FOnInput) then A := FOnInput(Address);
227end;
228
229procedure TCpu.InstructionOutput;
230var
231 Address: TData;
232begin
233 Address := ReadData;
234 if Assigned(FOnOutput) then FOnOutput(Address, A);
235end;
236
237procedure TCpu.InstructionDescend;
238begin
239 if LevelIndex < Length(Levels) - 1 then
240 LevelIndex := LevelIndex + 1;
241end;
242
243procedure TCpu.InstructionAscend;
244begin
245 if LevelIndex > 0 then
246 LevelIndex := LevelIndex - 1;
247end;
248
249procedure TCpu.InstructionStoreSys;
250var
251 Index: Byte;
252 Data: TData;
253begin
254 Index := ReadByte;
255 Data := ReadData;
256 case Index of
257 0: Levels[LevelIndex + 1].PC := Data;
258 1: Levels[LevelIndex + 1].SP := Data;
259 2: begin
260 Levels[LevelIndex + 1].VirtMemBase := Data;
261 RebuildMem;
262 end;
263 3: begin
264 Levels[LevelIndex + 1].VirtMemSize := Data;
265 RebuildMem;
266 end;
267 end;
268end;
269
270procedure TCpu.InstructionSysCall;
271var
272 Index: TData;
273begin
274 Index := ReadData;
275 InstructionAscend;
276 Level.PC := InterruptVectorSysCall;
277 A := Index;
278end;
279
280procedure TCpu.RebuildMem;
281var
282 I: Integer;
283begin
284 for I := 0 to Length(Levels) - 2 do begin
285 Levels[I + 1].MemoryBase := Levels[I].MemoryBase + Levels[I + 1].VirtMemBase;
286 Levels[I + 1].MemorySize := Min(Levels[I].MemorySize - Levels[I + 1].VirtMemBase, Levels[I + 1].VirtMemSize);
287 end;
288end;
289
290procedure TCpu.Push(Value: TData);
291begin
292 Dec(Level.SP, SizeOf(TData));
293 Level.WriteMem(Level.SP, Value);
294end;
295
296function TCpu.Pop: TData;
297begin
298 Result := Level.ReadMem(Level.SP);
299 Inc(Level.SP, SizeOf(TData));
300end;
301
302constructor TCpu.Create;
303var
304 I: Integer;
305begin
306 SetLength(Levels, 8);
307 for I := 0 to Length(Levels) - 1 do
308 Levels[I].Level := I;
309end;
310
311end.
312
313LD A, n
314LDM A, (n)
315LDM A, (B)
316STM (A), B
317LDS A, (B)
318STS (A), B
319ASCD
320DSND
321IN A, (n)
322OUT (n), A
323SYS n
324RETI
Note: See TracBrowser for help on using the repository browser.