Changeset 197 for branches/virtcpu varint/UMachine.pas
- Timestamp:
- Sep 22, 2019, 9:31:49 PM (5 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
branches/virtcpu varint/UMachine.pas
r196 r197 6 6 7 7 uses 8 Classes, SysUtils, UVarInt ;8 Classes, SysUtils, UVarInt, UCpu, syncobjs; 9 9 10 10 type 11 12 T = TVarInt; 13 14 TOpcode = (opNop, opLoad, opLoadConst, opNeg, 15 opJump, opJumpRel, 16 opInc, opDec, 17 opLoadMem, opStoreMem, 18 opAdd, opSub, 19 opInput, opOutput, 20 opCall, opCallRel, opRet, 21 opExchg, 22 opAnd, opOr, opXor, 23 opShl, opShr, 24 opRor, opRol, 25 opPush, opPop, 26 opJumpRelCond, 27 opLdir, opLddr, 28 opJumpCond, opTestEqual, opTestNotEqual, opTestLess, 29 opTestLessEqual, opTestGreater, opTestGreaterEqual, 30 opMul, opDiv, opHalt 31 ); 32 33 TOpcodeHandler = procedure of object; 34 TInputEvent = function (Port: T): T of object; 35 TOutputEvent = procedure (Port, Value: T) of object; 36 37 { TCPU } 38 39 TCPU = class(TComponent) 40 private 41 FOnInput: TInputEvent; 42 FOnOutput: TOutputEvent; 43 OpcodeHandlers: array[TOpcode] of TOpcodeHandler; 44 function ReadNext: T; inline; 45 procedure OpcodeNop; 46 procedure OpcodeHalt; 47 procedure OpcodeLoad; 48 procedure OpcodeLoadConst; 49 procedure OpcodeJump; 50 procedure OpcodeJumpRel; 51 procedure OpcodeNeg; 52 procedure OpcodeInc; 53 procedure OpcodeDec; 54 procedure OpcodeLoadMem; 55 procedure OpcodeStoreMem; 56 procedure OpcodeExchange; 57 procedure OpcodeTestEqual; 58 procedure OpcodeTestNotEqual; 59 procedure OpcodeTestGreatEqual; 60 procedure OpcodeTestGreat; 61 procedure OpcodeTestLessEqual; 62 procedure OpcodeTestLess; 63 procedure OpcodeJumpCond; 64 procedure OpcodeJumpRelCond; 65 procedure OpcodeShl; 66 procedure OpcodeShr; 67 procedure OpcodeRor; 68 procedure OpcodeRol; 69 procedure OpcodeAnd; 70 procedure OpcodeOr; 71 procedure OpcodeXor; 72 procedure OpcodePush; 73 procedure OpcodePop; 74 procedure OpcodeCall; 75 procedure OpcodeReturn; 76 procedure OpcodeCallRel; 77 procedure OpcodeOutput; 78 procedure OpcodeInput; 79 procedure OpcodeAdd; 80 procedure OpcodeSub; 81 procedure OpcodeMul; 82 procedure OpcodeDiv; 83 procedure OpcodeLdir; 84 procedure OpcodeLddr; 85 public 86 Memory: Pointer; 87 Registers: array of T; 88 IP: T; 89 SP: T; 90 Condition: Boolean; 91 Terminated: Boolean; 92 Ticks: Integer; 93 procedure Start; 94 procedure Stop; 95 procedure Step; inline; 96 constructor Create(AOwner: TComponent); override; 97 published 98 property OnInput: TInputEvent read FOnInput write FOnInput; 99 property OnOutput: TOutputEvent read FOnOutput write FOnOutput; 11 TScreen = class 12 Size: TPoint; 13 MemoryBase: Integer; 14 MemorySize: Integer; 15 ChangedAreaFrom: Integer; 16 ChangedAreaTo: Integer; 100 17 end; 101 18 … … 106 23 FMemorySize: Integer; 107 24 procedure SetMemorySize(AValue: Integer); 25 function CpuInput(Port: T): T; 26 procedure CpuOutput(Port: T; Value: T); 108 27 public 109 28 Cpu: TCpu; 110 29 Memory: Pointer; 30 Screen: TScreen; 31 InputBuffer: string; 32 OutputBuffer: string; 33 LockInput: TCriticalSection; 34 LockOutput: TCriticalSection; 111 35 property MemorySize: Integer read FMemorySize write SetMemorySize; 112 36 constructor Create(AOwner: TComponent); override; … … 125 49 Memory := ReAllocMem(Memory, FMemorySize); 126 50 Cpu.Memory := Memory; 51 Cpu.OnOutput := CpuOutput; 52 Cpu.OnInput := CpuInput; 53 end; 54 55 function TMachine.CpuInput(Port: T): T; 56 begin 57 Result := 0; 58 case Integer(Port) of 59 0: begin 60 LockInput.Acquire; 61 while (Length(InputBuffer) = 0) and not Cpu.Terminated do begin 62 LockInput.Release; 63 Sleep(100); 64 LockInput.Acquire; 65 end; 66 if Length(InputBuffer) > 0 then begin 67 Result := Ord(InputBuffer[1]); 68 Delete(InputBuffer, 1, 1); 69 end else Result := 0; 70 LockInput.Release; 71 end; 72 1: Result := Screen.Size.X; 73 2: Result := Screen.Size.Y; 74 3: Result := Screen.MemoryBase; 75 end; 76 end; 77 78 procedure TMachine.CpuOutput(Port: T; Value: T); 79 begin 80 case Integer(Port) of 81 0: begin 82 LockOutput.Acquire; 83 OutputBuffer := OutputBuffer + Char(Value); 84 LockOutput.Release; 85 end; 86 1: Screen.Size.X := Value; 87 2: Screen.Size.Y := Value; 88 3: Screen.MemoryBase := Value; 89 4: Screen.ChangedAreaFrom := Value; 90 5: Screen.ChangedAreaTo := Value; 91 end; 127 92 end; 128 93 … … 130 95 begin 131 96 inherited; 97 LockInput := TCriticalSection.Create; 98 LockOutput := TCriticalSection.Create; 132 99 Cpu := TCpu.Create(nil); 133 100 MemorySize := 1000; 101 Screen := TScreen.Create; 102 Screen.Size := Point(320, 240); 103 Screen.MemoryBase := $200; 134 104 end; 135 105 … … 137 107 begin 138 108 MemorySize := 0; 109 FreeAndNil(Screen); 139 110 FreeAndNil(Cpu); 140 111 inherited Destroy; 141 112 end; 142 113 143 { TCPU }144 145 function TCPU.ReadNext: T;146 begin147 IP := IP + Result.ReadFromAddr(Pointer(NativeUInt(Memory) + IP));148 end;149 150 procedure TCPU.OpcodeHalt;151 begin152 Terminated := True;153 end;154 155 procedure TCPU.OpcodeNop;156 begin157 // Do nothing158 end;159 160 procedure TCPU.OpcodeLoad;161 var162 P1: T;163 P2: T;164 begin165 P1 := ReadNext;166 P2 := ReadNext;167 Registers[P1] := Registers[P2];168 end;169 170 procedure TCPU.OpcodeLoadConst;171 var172 P1: T;173 P2: T;174 begin175 P1 := ReadNext;176 P2 := ReadNext;177 Registers[P1] := P2;178 end;179 180 procedure TCPU.OpcodeLoadMem;181 var182 P1: T;183 P2: T;184 begin185 P1 := ReadNext;186 P2 := ReadNext;187 Registers[P1].ReadFromAddr(Pointer(NativeUInt(Memory) + Integer(Registers[P2])));188 end;189 190 procedure TCPU.OpcodeStoreMem;191 var192 P1: T;193 P2: T;194 begin195 P1 := ReadNext;196 P2 := ReadNext;197 Registers[P2].WriteToAddr(Pointer(NativeUInt(Memory) + Registers[P1]));198 end;199 200 procedure TCPU.OpcodeNeg;201 var202 P1: T;203 begin204 P1 := ReadNext;205 Registers[P1] := -Registers[P1];206 end;207 208 procedure TCPU.OpcodeExchange;209 var210 P1, P2, Temp: T;211 begin212 P1 := ReadNext;213 P2 := ReadNext;214 Temp := Registers[P1];215 Registers[P1] := Registers[P2];216 Registers[P2] := Temp;217 end;218 219 procedure TCPU.OpcodeJump;220 begin221 IP := ReadNext;222 end;223 224 procedure TCPU.OpcodeJumpRel;225 begin226 IP := IP + ReadNext;227 end;228 229 procedure TCPU.OpcodeTestEqual;230 begin231 Condition := ReadNext = ReadNext;232 end;233 234 procedure TCPU.OpcodeTestNotEqual;235 begin236 Condition := ReadNext <> ReadNext;237 end;238 239 procedure TCPU.OpcodeTestGreatEqual;240 begin241 Condition := ReadNext >= ReadNext;242 end;243 244 procedure TCPU.OpcodeTestGreat;245 begin246 Condition := ReadNext > ReadNext;247 end;248 249 procedure TCPU.OpcodeTestLessEqual;250 begin251 Condition := ReadNext <= ReadNext;252 end;253 254 procedure TCPU.OpcodeTestLess;255 begin256 Condition := ReadNext < ReadNext;257 end;258 259 procedure TCPU.OpcodeJumpCond;260 var261 Addr: T;262 begin263 Addr := ReadNext;264 if Condition then IP := Addr;265 end;266 267 268 procedure TCPU.OpcodeJumpRelCond;269 var270 Addr: T;271 begin272 Addr := ReadNext;273 if Condition then IP := IP + Addr;274 end;275 276 procedure TCPU.OpcodeRor;277 var278 P1, P2: T;279 begin280 P1 := ReadNext;281 P2 := ReadNext;282 Registers[P1] := (Registers[P1] shr Registers[P2]) or283 ((Registers[P1] and ((1 shl Registers[P2]) - 1)) shl (SizeOf(T) * 8 - Registers[P2]));284 end;285 286 procedure TCPU.OpcodeRol;287 var288 P1, P2: T;289 begin290 P1 := ReadNext;291 P2 := ReadNext;292 Registers[P1] := (Registers[P1] shl Registers[P2]) or293 ((Registers[P1] shr (SizeOf(T) * 8 - Registers[P2])) and ((1 shl Registers[P2]) - 1));294 end;295 296 procedure TCPU.OpcodeShl;297 var298 P1, P2: T;299 begin300 P1 := ReadNext;301 P2 := ReadNext;302 Registers[P1] := Registers[P1] shl Registers[P2];303 end;304 305 procedure TCPU.OpcodeShr;306 var307 P1, P2: T;308 begin309 P1 := ReadNext;310 P2 := ReadNext;311 Registers[P1] := Registers[P1] shr Registers[P2];312 end;313 314 procedure TCPU.OpcodeAnd;315 var316 P1, P2: T;317 begin318 P1 := ReadNext;319 P2 := ReadNext;320 Registers[P1] := Registers[P1] and Registers[P2];321 end;322 323 procedure TCPU.OpcodeOr;324 var325 P1, P2: T;326 begin327 P1 := ReadNext;328 P2 := ReadNext;329 Registers[P1] := Registers[P1] or Registers[P2];330 end;331 332 procedure TCPU.OpcodeXor;333 var334 P1, P2: T;335 begin336 P1 := ReadNext;337 P2 := ReadNext;338 Registers[P1] := Registers[P1] xor Registers[P2];339 end;340 341 procedure TCPU.OpcodePush;342 var343 P1: T;344 begin345 P1 := ReadNext;346 SP := SP - Registers[P1].GetByteSize;347 Registers[P1].WriteToAddr(Pointer(NativeUInt(Memory) + Integer(SP)));348 end;349 350 procedure TCPU.OpcodePop;351 begin352 SP := SP + Registers[ReadNext].ReadFromAddr(Pointer(NativeUInt(Memory) + Integer(SP)));353 end;354 355 procedure TCPU.OpcodeCall;356 var357 Addr: T;358 begin359 Addr := ReadNext;360 SP := SP - IP.GetByteSize;361 IP.WriteToAddr(Pointer(NativeUInt(Memory) + SP));362 IP := Addr;363 end;364 365 procedure TCPU.OpcodeCallRel;366 var367 Addr: T;368 begin369 Addr := ReadNext;370 SP := SP - IP.GetByteSize;371 IP.WriteToAddr(Pointer(NativeUInt(Memory) + SP));372 IP := IP + Addr;373 end;374 375 procedure TCPU.OpcodeReturn;376 begin377 SP := SP + IP.ReadFromAddr(Pointer(NativeUInt(Memory) + SP));378 end;379 380 procedure TCPU.OpcodeOutput;381 var382 R1: T;383 R2: T;384 begin385 R1 := ReadNext;386 R2 := ReadNext;387 if Assigned(FOnOutput) then388 FOnOutput(Registers[R1], Registers[R2]);389 end;390 391 procedure TCPU.OpcodeInput;392 var393 R1: T;394 R2: T;395 begin396 R1 := ReadNext;397 R2 := ReadNext;398 if Assigned(FOnInput) then399 Registers[R1] := FOnInput(Registers[R2]);400 end;401 402 procedure TCPU.OpcodeInc;403 var404 R: T;405 begin406 R := ReadNext;407 Registers[R] := Registers[R] + 1;408 end;409 410 procedure TCPU.OpcodeDec;411 var412 R: T;413 begin414 R := ReadNext;415 Registers[R] := Registers[R] - 1;416 end;417 418 procedure TCPU.OpcodeAdd;419 var420 R1: T;421 R2: T;422 begin423 R1 := ReadNext;424 R2 := ReadNext;425 Registers[R1] := Registers[R1] + Registers[R2];426 end;427 428 procedure TCPU.OpcodeSub;429 var430 R1: T;431 R2: T;432 begin433 R1 := ReadNext;434 R2 := ReadNext;435 Registers[R1] := Registers[R1] - Registers[R2];436 end;437 438 procedure TCPU.OpcodeMul;439 var440 R1: T;441 R2: T;442 begin443 R1 := ReadNext;444 R2 := ReadNext;445 Registers[R1] := Registers[R1] * Registers[R2];446 end;447 448 procedure TCPU.OpcodeDiv;449 var450 R1: T;451 R2: T;452 begin453 R1 := ReadNext;454 R2 := ReadNext;455 Registers[R1] := Registers[R1] div Registers[R2];456 end;457 458 procedure TCPU.OpcodeLdir;459 var460 Src: T;461 Dst: T;462 Count: T;463 Bytes: T;464 begin465 Src := ReadNext;466 Dst := ReadNext;467 Count := ReadNext;468 Bytes := ReadNext;469 while Registers[Count] > 0 do begin470 Move(Pointer(NativeUInt(Memory) + Registers[Src])^,471 Pointer(NativeUInt(Memory) + Registers[Dst])^, Bytes);472 Inc(Registers[Src], Bytes);473 Inc(Registers[Dst], Bytes);474 Dec(Registers[Count]);475 end;476 end;477 478 procedure TCPU.OpcodeLddr;479 var480 Src: T;481 Dst: T;482 Count: T;483 Bytes: T;484 begin485 Src := ReadNext;486 Dst := ReadNext;487 Count := ReadNext;488 Bytes := ReadNext;489 while Registers[Count] > 0 do begin490 Move(Pointer(NativeUInt(Memory) + Registers[Src])^,491 Pointer(NativeUInt(Memory) + Registers[Dst])^, Bytes);492 Dec(Registers[Src], Bytes);493 Dec(Registers[Dst], Bytes);494 Dec(Registers[Count]);495 end;496 end;497 498 procedure TCPU.Start;499 begin500 Terminated := False;501 Ticks := 0;502 IP := 0;503 SP := MemSize(Memory);504 while not Terminated do505 Step;506 end;507 508 procedure TCPU.Stop;509 begin510 Terminated := True;511 end;512 513 procedure TCPU.Step;514 var515 Opcode: T;516 begin517 Opcode := ReadNext;518 if (Opcode >= 0) and (Opcode <= T(Integer(High(TOpcode)))) then519 OpcodeHandlers[TOpcode(Byte(Opcode))]520 else raise Exception.Create(Format('Unsupported instruction %d on address %x', [Int64(Opcode), Int64(IP)]));521 Inc(Ticks);522 end;523 524 constructor TCPU.Create(AOwner: TComponent);525 begin526 inherited;527 SetLength(Registers, 16);528 OpcodeHandlers[opNop] := OpcodeNop;529 OpcodeHandlers[opHalt] := OpcodeHalt;530 OpcodeHandlers[opLoad] := OpcodeLoad;531 OpcodeHandlers[opLoadConst] := OpcodeLoadConst;532 OpcodeHandlers[opNeg] := OpcodeNeg;533 OpcodeHandlers[opJump] := OpcodeJump;534 OpcodeHandlers[opInc] := OpcodeInc;535 OpcodeHandlers[opDec] := OpcodeDec;536 OpcodeHandlers[opJumpRel] := OpcodeJumpRel;537 OpcodeHandlers[opLoadMem] := OpcodeLoadMem;538 OpcodeHandlers[opStoreMem] := OpcodeStoreMem;539 OpcodeHandlers[opExchg] := OpcodeExchange;540 OpcodeHandlers[opAnd] := OpcodeAnd;541 OpcodeHandlers[opOr] := OpcodeOr;542 OpcodeHandlers[opXor] := OpcodeXor;543 OpcodeHandlers[opShl] := OpcodeShl;544 OpcodeHandlers[opShr] := OpcodeShr;545 OpcodeHandlers[opPush] := OpcodePush;546 OpcodeHandlers[opPop] := OpcodePop;547 OpcodeHandlers[opCall] := OpcodeCall;548 OpcodeHandlers[opCallRel] := OpcodeCallRel;549 OpcodeHandlers[opRet] := OpcodeReturn;550 OpcodeHandlers[opRor] := OpcodeRor;551 OpcodeHandlers[opRol] := OpcodeRol;552 OpcodeHandlers[opInput] := OpcodeInput;553 OpcodeHandlers[opOutput] := OpcodeOutput;554 OpcodeHandlers[opAdd] := OpcodeAdd;555 OpcodeHandlers[opSub] := OpcodeSub;556 OpcodeHandlers[opLdir] := OpcodeLdir;557 OpcodeHandlers[opLddr] := OpcodeLddr;558 OpcodeHandlers[opJumpCond] := OpcodeJumpCond;559 OpcodeHandlers[opJumpRelCond] := OpcodeJumpRelCond;560 OpcodeHandlers[opTestEqual] := OpcodeTestEqual;561 OpcodeHandlers[opTestNotEqual] := OpcodeTestNotEqual;562 OpcodeHandlers[opTestLess] := OpcodeTestLess;563 OpcodeHandlers[opTestLessEqual] := OpcodeTestLessEqual;564 OpcodeHandlers[opTestGreater] := OpcodeTestGreat;565 OpcodeHandlers[opTestGreaterEqual] := OpcodeTestGreatEqual;566 OpcodeHandlers[opMul] := OpcodeMul;567 OpcodeHandlers[opDiv] := OpcodeDiv;568 end;569 570 114 end. 571 115
Note:
See TracChangeset
for help on using the changeset viewer.