1 | unit UInstructionWriter;
|
---|
2 |
|
---|
3 | {$mode delphi}{$H+}
|
---|
4 |
|
---|
5 | interface
|
---|
6 |
|
---|
7 | uses
|
---|
8 | Classes, SysUtils, UCpu;
|
---|
9 |
|
---|
10 | type
|
---|
11 |
|
---|
12 | { TInstructionWriter }
|
---|
13 |
|
---|
14 | TInstructionWriter = class
|
---|
15 | private
|
---|
16 | procedure PrefixBegin;
|
---|
17 | procedure PrefixEnd;
|
---|
18 | public
|
---|
19 | Cpu: TCpu;
|
---|
20 | IP: Integer;
|
---|
21 | DataSize: TBitWidth;
|
---|
22 | DataSizeBase: TBitWidth;
|
---|
23 | AddrSize: TBitWidth;
|
---|
24 | AddrSizeBase: TBitWidth;
|
---|
25 | Prefix: Boolean;
|
---|
26 | procedure Init;
|
---|
27 | function GetRelativeAddr(BitWidth: TBitWidth; BaseIP, TargetAddr: QWord): Int64;
|
---|
28 | procedure Write8(Value: Byte);
|
---|
29 | procedure Write16(Value: Word);
|
---|
30 | procedure Write32(Value: DWord);
|
---|
31 | procedure Write64(Value: QWord);
|
---|
32 | procedure WriteAddress(Value: TAddress);
|
---|
33 | procedure WriteAddressSigned(Value: TAddressSigned); inline;
|
---|
34 | procedure WriteData(Value: QWord);
|
---|
35 | procedure WriteString(Text: string);
|
---|
36 | procedure Nop;
|
---|
37 | procedure Halt;
|
---|
38 | procedure Loadi(Reg: TRegIndex; Value: QWord);
|
---|
39 | procedure Increment(Reg: TRegIndex);
|
---|
40 | procedure Decrement(Reg: TRegIndex);
|
---|
41 | procedure Jump(Addr: QWord);
|
---|
42 | procedure JumpNotZero(Addr: QWord);
|
---|
43 | procedure JumpZero(Addr: QWord);
|
---|
44 | procedure JumpRel(Addr: QWord);
|
---|
45 | procedure JumpRelNotZero(Addr: QWord);
|
---|
46 | procedure JumpRelZero(Addr: QWord);
|
---|
47 | procedure Push(Reg: TRegIndex);
|
---|
48 | procedure Pop(Reg: TRegIndex);
|
---|
49 | procedure Call(Addr: QWord);
|
---|
50 | procedure Return;
|
---|
51 | procedure Convert(Reg: TRegIndex);
|
---|
52 | procedure DataPrefix8;
|
---|
53 | procedure DataPrefix16;
|
---|
54 | procedure DataPrefix32;
|
---|
55 | procedure DataPrefix64;
|
---|
56 | procedure AddrPrefix8;
|
---|
57 | procedure AddrPrefix16;
|
---|
58 | procedure AddrPrefix32;
|
---|
59 | procedure AddrPrefix64;
|
---|
60 | procedure StoreMem(RegAddr, RegSrc: TRegIndex);
|
---|
61 | procedure LoadMem(RegDst, RegAddr: TRegIndex);
|
---|
62 | procedure Output(Port: TAddress; Reg: TRegIndex);
|
---|
63 | procedure Input(Reg: TRegIndex; Port: TAddress);
|
---|
64 | procedure Test(Reg: TRegIndex);
|
---|
65 | end;
|
---|
66 |
|
---|
67 |
|
---|
68 | implementation
|
---|
69 |
|
---|
70 | { TInstructionWriter }
|
---|
71 |
|
---|
72 | procedure TInstructionWriter.Nop;
|
---|
73 | begin
|
---|
74 | PrefixBegin;
|
---|
75 | Write8(Byte(opNop));
|
---|
76 | PrefixEnd;
|
---|
77 | end;
|
---|
78 |
|
---|
79 | procedure TInstructionWriter.Halt;
|
---|
80 | begin
|
---|
81 | PrefixBegin;
|
---|
82 | Write8(Byte(opHalt));
|
---|
83 | PrefixEnd;
|
---|
84 | end;
|
---|
85 |
|
---|
86 | procedure TInstructionWriter.Loadi(Reg: TRegIndex; Value: QWord);
|
---|
87 | begin
|
---|
88 | PrefixBegin;
|
---|
89 | Write8(Byte(opLoadi));
|
---|
90 | Write8(Reg);
|
---|
91 | WriteData(Value);
|
---|
92 | PrefixEnd;
|
---|
93 | end;
|
---|
94 |
|
---|
95 | procedure TInstructionWriter.Increment(Reg: TRegIndex);
|
---|
96 | begin
|
---|
97 | PrefixBegin;
|
---|
98 | Write8(Byte(opInc));
|
---|
99 | Write8(Reg);
|
---|
100 | PrefixEnd;
|
---|
101 | end;
|
---|
102 |
|
---|
103 | procedure TInstructionWriter.Decrement(Reg: TRegIndex);
|
---|
104 | begin
|
---|
105 | PrefixBegin;
|
---|
106 | Write8(Byte(opDec));
|
---|
107 | Write8(Reg);
|
---|
108 | PrefixEnd;
|
---|
109 | end;
|
---|
110 |
|
---|
111 | procedure TInstructionWriter.Jump(Addr: QWord);
|
---|
112 | begin
|
---|
113 | PrefixBegin;
|
---|
114 | Write8(Byte(opJump));
|
---|
115 | WriteAddress(Addr);
|
---|
116 | PrefixEnd;
|
---|
117 | end;
|
---|
118 |
|
---|
119 | procedure TInstructionWriter.JumpNotZero(Addr: QWord);
|
---|
120 | begin
|
---|
121 | PrefixBegin;
|
---|
122 | Write8(Byte(opJumpNotZero));
|
---|
123 | WriteAddress(Addr);
|
---|
124 | PrefixEnd;
|
---|
125 | end;
|
---|
126 |
|
---|
127 | procedure TInstructionWriter.JumpZero(Addr: QWord);
|
---|
128 | begin
|
---|
129 | PrefixBegin;
|
---|
130 | Write8(Byte(opJumpZero));
|
---|
131 | WriteAddress(Addr);
|
---|
132 | PrefixEnd;
|
---|
133 | end;
|
---|
134 |
|
---|
135 | function TInstructionWriter.GetRelativeAddr(BitWidth: TBitWidth; BaseIP, TargetAddr: QWord): Int64;
|
---|
136 | begin
|
---|
137 | Result := Int64(TargetAddr) - (BaseIP + 1 + BitWidthBytes[BitWidth]);
|
---|
138 | end;
|
---|
139 |
|
---|
140 | procedure TInstructionWriter.JumpRel(Addr: QWord);
|
---|
141 | var
|
---|
142 | RelAddr: Int64;
|
---|
143 | begin
|
---|
144 | PrefixBegin;
|
---|
145 | RelAddr := GetRelativeAddr(AddrSize, IP, Addr);
|
---|
146 | Write8(Byte(opJumpRel));
|
---|
147 | WriteAddressSigned(RelAddr);
|
---|
148 | PrefixEnd;
|
---|
149 | end;
|
---|
150 |
|
---|
151 | procedure TInstructionWriter.JumpRelNotZero(Addr: QWord);
|
---|
152 | var
|
---|
153 | RelAddr: Int64;
|
---|
154 | begin
|
---|
155 | PrefixBegin;
|
---|
156 | RelAddr := GetRelativeAddr(AddrSize, IP, Addr);
|
---|
157 | Write8(Byte(opJumpRelNotZero));
|
---|
158 | WriteAddressSigned(RelAddr);
|
---|
159 | PrefixEnd;
|
---|
160 | end;
|
---|
161 |
|
---|
162 | procedure TInstructionWriter.JumpRelZero(Addr: QWord);
|
---|
163 | var
|
---|
164 | RelAddr: Int64;
|
---|
165 | begin
|
---|
166 | PrefixBegin;
|
---|
167 | RelAddr := GetRelativeAddr(AddrSize, IP, Addr);
|
---|
168 | Write8(Byte(opJumpRelZero));
|
---|
169 | WriteAddressSigned(RelAddr);
|
---|
170 | PrefixEnd;
|
---|
171 | end;
|
---|
172 |
|
---|
173 | procedure TInstructionWriter.Push(Reg: TRegIndex);
|
---|
174 | begin
|
---|
175 | PrefixBegin;
|
---|
176 | Write8(Byte(opPush));
|
---|
177 | Write8(Reg);
|
---|
178 | PrefixEnd;
|
---|
179 | end;
|
---|
180 |
|
---|
181 | procedure TInstructionWriter.Pop(Reg: TRegIndex);
|
---|
182 | begin
|
---|
183 | PrefixBegin;
|
---|
184 | Write8(Byte(opPop));
|
---|
185 | Write8(Reg);
|
---|
186 | PrefixEnd;
|
---|
187 | end;
|
---|
188 |
|
---|
189 | procedure TInstructionWriter.Call(Addr: QWord);
|
---|
190 | begin
|
---|
191 | PrefixBegin;
|
---|
192 | Write8(Byte(opCall));
|
---|
193 | WriteAddress(Addr);
|
---|
194 | PrefixEnd;
|
---|
195 | end;
|
---|
196 |
|
---|
197 | procedure TInstructionWriter.Return;
|
---|
198 | begin
|
---|
199 | PrefixBegin;
|
---|
200 | Write8(Byte(opRet));
|
---|
201 | PrefixEnd;
|
---|
202 | end;
|
---|
203 |
|
---|
204 | procedure TInstructionWriter.Convert(Reg: TRegIndex);
|
---|
205 | begin
|
---|
206 | PrefixBegin;
|
---|
207 | Write8(Byte(opConvert));
|
---|
208 | Write8(Reg);
|
---|
209 | PrefixEnd;
|
---|
210 | end;
|
---|
211 |
|
---|
212 | procedure TInstructionWriter.DataPrefix8;
|
---|
213 | begin
|
---|
214 | Prefix := True;
|
---|
215 | DataSize := bw8;
|
---|
216 | Write8(Byte(opDataPrefix8));
|
---|
217 | end;
|
---|
218 |
|
---|
219 | procedure TInstructionWriter.DataPrefix16;
|
---|
220 | begin
|
---|
221 | Prefix := True;
|
---|
222 | DataSize := bw16;
|
---|
223 | Write8(Byte(opDataPrefix16));
|
---|
224 | end;
|
---|
225 |
|
---|
226 | procedure TInstructionWriter.DataPrefix32;
|
---|
227 | begin
|
---|
228 | Prefix := True;
|
---|
229 | DataSize := bw32;
|
---|
230 | Write8(Byte(opDataPrefix32));
|
---|
231 | end;
|
---|
232 |
|
---|
233 | procedure TInstructionWriter.DataPrefix64;
|
---|
234 | begin
|
---|
235 | Prefix := True;
|
---|
236 | DataSize := bw64;
|
---|
237 | Write8(Byte(opDataPrefix64));
|
---|
238 | end;
|
---|
239 |
|
---|
240 | procedure TInstructionWriter.AddrPrefix8;
|
---|
241 | begin
|
---|
242 | Prefix := True;
|
---|
243 | AddrSize := bw8;
|
---|
244 | Write8(Byte(opAddrPrefix8));
|
---|
245 | end;
|
---|
246 |
|
---|
247 | procedure TInstructionWriter.AddrPrefix16;
|
---|
248 | begin
|
---|
249 | Prefix := True;
|
---|
250 | AddrSize := bw16;
|
---|
251 | Write8(Byte(opAddrPrefix16));
|
---|
252 | end;
|
---|
253 |
|
---|
254 | procedure TInstructionWriter.AddrPrefix32;
|
---|
255 | begin
|
---|
256 | Prefix := True;
|
---|
257 | AddrSize := bw32;
|
---|
258 | Write8(Byte(opAddrPrefix32));
|
---|
259 | end;
|
---|
260 |
|
---|
261 | procedure TInstructionWriter.AddrPrefix64;
|
---|
262 | begin
|
---|
263 | Prefix := True;
|
---|
264 | AddrSize := bw64;
|
---|
265 | Write8(Byte(opAddrPrefix64));
|
---|
266 | end;
|
---|
267 |
|
---|
268 | procedure TInstructionWriter.StoreMem(RegAddr, RegSrc: TRegIndex);
|
---|
269 | begin
|
---|
270 | Write8(Byte(opStoreMem));
|
---|
271 | Write8(RegAddr);
|
---|
272 | Write8(RegSrc);
|
---|
273 | end;
|
---|
274 |
|
---|
275 | procedure TInstructionWriter.LoadMem(RegDst, RegAddr: TRegIndex);
|
---|
276 | begin
|
---|
277 | PrefixBegin;
|
---|
278 | Write8(Byte(opLoadMem));
|
---|
279 | Write8(RegDst);
|
---|
280 | Write8(RegAddr);
|
---|
281 | PrefixEnd;
|
---|
282 | end;
|
---|
283 |
|
---|
284 | procedure TInstructionWriter.Output(Port: TAddress; Reg: TRegIndex);
|
---|
285 | begin
|
---|
286 | PrefixBegin;
|
---|
287 | Write8(Byte(opOut));
|
---|
288 | WriteAddress(Port);
|
---|
289 | Write8(Reg);
|
---|
290 | PrefixEnd;
|
---|
291 | end;
|
---|
292 |
|
---|
293 | procedure TInstructionWriter.Input(Reg: TRegIndex; Port: TAddress);
|
---|
294 | begin
|
---|
295 | PrefixBegin;
|
---|
296 | Write8(Byte(opIn));
|
---|
297 | Write8(Reg);
|
---|
298 | WriteAddress(Port);
|
---|
299 | PrefixEnd;
|
---|
300 | end;
|
---|
301 |
|
---|
302 | procedure TInstructionWriter.Test(Reg: TRegIndex);
|
---|
303 | begin
|
---|
304 | PrefixBegin;
|
---|
305 | Write8(Byte(opTest));
|
---|
306 | Write8(Reg);
|
---|
307 | Prefixend;
|
---|
308 | end;
|
---|
309 |
|
---|
310 | procedure TInstructionWriter.WriteString(Text: string);
|
---|
311 | var
|
---|
312 | I: Integer;
|
---|
313 | begin
|
---|
314 | for I := 1 to Length(Text) do
|
---|
315 | Write8(Ord(Text[I]));
|
---|
316 | end;
|
---|
317 |
|
---|
318 | procedure TInstructionWriter.PrefixBegin;
|
---|
319 | begin
|
---|
320 | Prefix := False;
|
---|
321 | end;
|
---|
322 |
|
---|
323 | procedure TInstructionWriter.PrefixEnd;
|
---|
324 | begin
|
---|
325 | if not Prefix then begin
|
---|
326 | DataSize := DataSizeBase;
|
---|
327 | AddrSize := AddrSizeBase;
|
---|
328 | end;
|
---|
329 | end;
|
---|
330 |
|
---|
331 | procedure TInstructionWriter.Init;
|
---|
332 | begin
|
---|
333 | DataSizeBase := Cpu.DataSizeBase;
|
---|
334 | DataSize := DataSizeBase;
|
---|
335 | AddrSizeBase := Cpu.AddrSizeBase;
|
---|
336 | AddrSize := AddrSizeBase;
|
---|
337 | IP := 0;
|
---|
338 | Prefix := False;
|
---|
339 | end;
|
---|
340 |
|
---|
341 | procedure TInstructionWriter.Write8(Value: Byte);
|
---|
342 | begin
|
---|
343 | PByte(Cpu.Memory + IP)^ := Value;
|
---|
344 | Inc(IP, SizeOf(Byte));
|
---|
345 | end;
|
---|
346 |
|
---|
347 | procedure TInstructionWriter.Write16(Value: Word);
|
---|
348 | begin
|
---|
349 | PWord(Cpu.Memory + IP)^ := Value;
|
---|
350 | Inc(IP, SizeOf(Word));
|
---|
351 | end;
|
---|
352 |
|
---|
353 | procedure TInstructionWriter.Write32(Value: DWord);
|
---|
354 | begin
|
---|
355 | PDWord(Cpu.Memory + IP)^ := Value;
|
---|
356 | Inc(IP, SizeOf(DWord));
|
---|
357 | end;
|
---|
358 |
|
---|
359 | procedure TInstructionWriter.Write64(Value: QWord);
|
---|
360 | begin
|
---|
361 | PQWord(Cpu.Memory + IP)^ := Value;
|
---|
362 | Inc(IP, SizeOf(QWord));
|
---|
363 | end;
|
---|
364 |
|
---|
365 | procedure TInstructionWriter.WriteAddress(Value: TAddress);
|
---|
366 | begin
|
---|
367 | case AddrSize of
|
---|
368 | bw8: Write8(Value and $ff);
|
---|
369 | bw16: Write16(Value and $ffff);
|
---|
370 | bw32: Write32(Value and $ffffffff);
|
---|
371 | bw64: Write64(Value);
|
---|
372 | end;
|
---|
373 | end;
|
---|
374 |
|
---|
375 | procedure TInstructionWriter.WriteAddressSigned(Value: TAddressSigned);
|
---|
376 | begin
|
---|
377 | case AddrSize of
|
---|
378 | bw8: Write8(Byte(Value and $ff));
|
---|
379 | bw16: Write16(Word(Value and $ffff));
|
---|
380 | bw32: Write32(DWord(Value and $ffffffff));
|
---|
381 | bw64: Write64(QWord(Value));
|
---|
382 | end;
|
---|
383 | end;
|
---|
384 |
|
---|
385 | procedure TInstructionWriter.WriteData(Value: QWord);
|
---|
386 | begin
|
---|
387 | case DataSize of
|
---|
388 | bw8: Write8(Value and $ff);
|
---|
389 | bw16: Write16(Value and $ffff);
|
---|
390 | bw32: Write32(Value and $ffffffff);
|
---|
391 | bw64: Write64(Value);
|
---|
392 | end;
|
---|
393 | end;
|
---|
394 |
|
---|
395 | end.
|
---|
396 |
|
---|