Changeset 223 for branches/CpuSingleSize/UCpu.pas
- Timestamp:
- Jul 12, 2022, 10:43:40 PM (2 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
branches/CpuSingleSize/UCpu.pas
r220 r223 1 1 unit UCpu; 2 3 {$mode delphi}4 2 5 3 interface … … 12 10 inAdd, inSub, inIn, inOut, inJump, inJumpZero, inJumpNotZero, inPush, inPop, 13 11 inCall, inRet, inAnd, inOr, inXor, inShl, inShr, inMul, inDiv, inMod, 14 inJumpRel, inLoadIndex, inStoreIndex );12 inJumpRel, inLoadIndex, inStoreIndex, inLoadCpu, inStoreCpu, inEi, inDi); 15 13 16 14 TInteger = Integer; … … 20 18 TInputEvent = function (Device, Port: TInteger): TInteger of object; 21 19 20 { TCpuStatus } 21 22 TCpuStatus = packed record 23 InterruptEnabled: Boolean; 24 UserMode: Boolean; 25 UserModeWasActive: Boolean; 26 function GetInteger: TInteger; 27 procedure SetInteger(Value: TInteger); 28 end; 29 30 TIntegerArray = array of TInteger; 31 32 TMemoryBlock = record 33 Base: TIntegerArray; 34 Size: TInteger; 35 end; 36 37 TMemoryBlockIndex = (mbCode, mbData, mbStack, mbInterrupt); 38 TInstructionHandler = procedure of object; 39 TSystemInterrupt = (siReset, siUserIn, siUserOut, siUserInvalidMemory, 40 siPrivilegedInstruction); 41 TCpuRegister = (crIP, crSP, crStatusRegister, crUserMemoryBase, crUserMemorySize); 42 22 43 { TCpu } 23 44 24 45 TCpu = class 25 46 private 47 FBaseMemory: TMemoryBlock; 48 FUserMemory: TMemoryBlock; 49 FMemory: TMemoryBlock; 26 50 FRunning: Boolean; 27 51 FThread: TCpuThread; … … 30 54 FNextInterupt: TInteger; 31 55 FHalted: Boolean; 56 FTicks: Integer; 57 FInstructionHandlers: array[TInstruction] of TInstructionHandler; 58 function GetMemory: TIntegerArray; 59 procedure InstructionNop; 60 procedure InstructionHalt; 61 procedure InstructionSet; 62 procedure InstructionCopy; 63 procedure InstructionLoad; 64 procedure InstructionStore; 65 procedure InstructionInc; 66 procedure InstructionDec; 67 procedure InstructionAdd; 68 procedure InstructionSub; 69 procedure InstructionIn; 70 procedure InstructionOut; 71 procedure InstructionJump; 72 procedure InstructionJumpRel; 73 procedure InstructionJumpZero; 74 procedure InstructionJumpNotZero; 75 procedure InstructionPush; 76 procedure InstructionPop; 77 procedure InstructionCall; 78 procedure InstructionRet; 79 procedure InstructionReti; 80 procedure InstructionAnd; 81 procedure InstructionOr; 82 procedure InstructionXor; 83 procedure InstructionShl; 84 procedure InstructionShr; 85 procedure InstructionMod; 86 procedure InstructionDiv; 87 procedure InstructionMul; 88 procedure InstructionLoadIndex; 89 procedure InstructionStoreIndex; 90 procedure InstructionLoadCpu; 91 procedure InstructionStoreCpu; 92 procedure InstructionEi; 93 procedure InstructionDi; 94 procedure SetMemory(AValue: TIntegerArray); 32 95 procedure SetRunning(AValue: Boolean); 33 96 procedure CheckInterreupts; 97 procedure Push(Value: TInteger); 98 function Pop: TInteger; 99 procedure StoreContext; 100 procedure LoadContext; 101 procedure InitInstructions; 102 procedure ActivateUserMode; 103 procedure DeactivateUserMode; 34 104 public 35 Ticks: Integer; 36 IP: TInteger; 37 SP: TInteger; 38 Data: array of TInteger; 105 InstructionPointer: TInteger; // Instruction Pointer 106 StackPointer: TInteger; // Stack Pointer 107 StatusRegister: TCpuStatus; // Status Register 39 108 R: array of TInteger; 40 109 function ReadNext: TInteger; … … 44 113 procedure Stop; 45 114 procedure Reset; 46 procedure Interrupt(Index: TInteger); 115 procedure Interrupt(Index: TSystemInterrupt); overload; 116 procedure Interrupt(Index: TInteger); overload; 47 117 constructor Create; 48 118 destructor Destroy; override; 119 property Ticks: Integer read FTicks; 120 property Memory: TIntegerArray read GetMemory write SetMemory; 49 121 property OnInput: TInputEvent read FOnInput write FOnInput; 50 122 property OnOutput: TOutputEvent read FOnOutput write FOnOutput; … … 62 134 63 135 implementation 136 137 { TCpuStatus } 138 139 function TCpuStatus.GetInteger: TInteger; 140 begin 141 142 end; 143 144 procedure TCpuStatus.SetInteger(Value: TInteger); 145 begin 146 147 end; 64 148 65 149 { TCpuThread } … … 83 167 end; 84 168 169 procedure TCpu.InstructionNop; 170 begin 171 // No operation 172 end; 173 174 function TCpu.GetMemory: TIntegerArray; 175 begin 176 Result := FBaseMemory.Base; 177 end; 178 179 procedure TCpu.InstructionHalt; 180 begin 181 FHalted := True; 182 end; 183 184 procedure TCpu.InstructionSet; 185 begin 186 R[ReadNext] := ReadNext; 187 end; 188 189 procedure TCpu.InstructionCopy; 190 begin 191 R[ReadNext] := R[ReadNext]; 192 end; 193 194 procedure TCpu.InstructionLoad; 195 begin 196 R[ReadNext] := FMemory.Base[R[ReadNext]]; 197 end; 198 199 procedure TCpu.InstructionStore; 200 begin 201 FMemory.Base[R[ReadNext]] := R[ReadNext]; 202 end; 203 204 procedure TCpu.InstructionInc; 205 begin 206 Inc(R[ReadNext]); 207 end; 208 209 procedure TCpu.InstructionDec; 210 begin 211 Dec(R[ReadNext]); 212 end; 213 214 procedure TCpu.InstructionAdd; 215 var 216 Index: TInteger; 217 begin 218 Index := ReadNext; 219 R[Index] := R[Index] + R[ReadNext]; 220 end; 221 222 procedure TCpu.InstructionSub; 223 var 224 Index: TInteger; 225 begin 226 Index := ReadNext; 227 R[Index] := R[Index] - R[ReadNext]; 228 end; 229 230 procedure TCpu.InstructionIn; 231 var 232 Index: TInteger; 233 Device: TInteger; 234 Port: TInteger; 235 begin 236 Index := ReadNext; 237 Device := R[ReadNext]; 238 Port := R[ReadNext]; 239 if StatusRegister.UserMode then begin 240 Interrupt(siUserIn); 241 end else begin 242 if Assigned(FOnInput) then R[Index] := FOnInput(Device, Port); 243 end; 244 end; 245 246 procedure TCpu.InstructionOut; 247 var 248 Device: TInteger; 249 Port: TInteger; 250 Index: TInteger; 251 begin 252 Device := R[ReadNext]; 253 Port := R[ReadNext]; 254 Index := ReadNext; 255 if StatusRegister.UserMode then begin 256 Interrupt(siUserOut); 257 end else begin 258 if Assigned(FOnOutput) then FOnOutput(Device, Port, R[Index]); 259 end; 260 end; 261 262 procedure TCpu.InstructionJump; 263 begin 264 InstructionPointer := ReadNext; 265 end; 266 267 procedure TCpu.InstructionJumpRel; 268 begin 269 InstructionPointer := InstructionPointer + ReadNext; 270 end; 271 272 procedure TCpu.InstructionJumpZero; 273 var 274 Index: TInteger; 275 Address: TInteger; 276 begin 277 Index := ReadNext; 278 Address := ReadNext; 279 if R[Index] = 0 then InstructionPointer := Address; 280 end; 281 282 procedure TCpu.InstructionJumpNotZero; 283 var 284 Index: TInteger; 285 Address: TInteger; 286 begin 287 Index := ReadNext; 288 Address := ReadNext; 289 if R[Index] <> 0 then InstructionPointer := Address; 290 end; 291 292 procedure TCpu.InstructionPush; 293 begin 294 Push(R[ReadNext]); 295 end; 296 297 procedure TCpu.InstructionPop; 298 begin 299 R[ReadNext] := Pop; 300 end; 301 302 procedure TCpu.InstructionCall; 303 var 304 Address: TInteger; 305 begin 306 Address := ReadNext; 307 Push(InstructionPointer); 308 InstructionPointer := Address; 309 end; 310 311 procedure TCpu.InstructionRet; 312 begin 313 InstructionPointer := Pop; 314 end; 315 316 procedure TCpu.InstructionReti; 317 begin 318 if StatusRegister.UserMode then begin 319 Interrupt(siPrivilegedInstruction); 320 Exit; 321 end; 322 if StatusRegister.UserModeWasActive then ActivateUserMode; 323 StatusRegister.InterruptEnabled := True; 324 InstructionPointer := Pop; 325 end; 326 327 procedure TCpu.InstructionAnd; 328 var 329 Index: TInteger; 330 begin 331 Index := ReadNext; 332 R[Index] := R[Index] and R[ReadNext]; 333 end; 334 335 procedure TCpu.InstructionOr; 336 var 337 Index: TInteger; 338 begin 339 Index := ReadNext; 340 R[Index] := R[Index] or R[ReadNext]; 341 end; 342 343 procedure TCpu.InstructionXor; 344 var 345 Index: TInteger; 346 begin 347 Index := ReadNext; 348 R[Index] := R[Index] xor R[ReadNext]; 349 end; 350 351 procedure TCpu.InstructionShl; 352 var 353 Index: TInteger; 354 begin 355 Index := ReadNext; 356 R[Index] := R[Index] shl R[ReadNext]; 357 end; 358 359 procedure TCpu.InstructionShr; 360 var 361 Index: TInteger; 362 begin 363 Index := ReadNext; 364 R[Index] := R[Index] shr R[ReadNext]; 365 end; 366 367 procedure TCpu.InstructionMod; 368 var 369 Index: TInteger; 370 begin 371 Index := ReadNext; 372 R[Index] := R[Index] mod R[ReadNext]; 373 end; 374 375 procedure TCpu.InstructionDiv; 376 var 377 Index: TInteger; 378 begin 379 Index := ReadNext; 380 R[Index] := R[Index] div R[ReadNext]; 381 end; 382 383 procedure TCpu.InstructionMul; 384 var 385 Index: TInteger; 386 begin 387 Index := ReadNext; 388 R[Index] := R[Index] * R[ReadNext]; 389 end; 390 391 procedure TCpu.InstructionLoadIndex; 392 begin 393 R[ReadNext] := FMemory.Base[R[ReadNext] + ReadNext]; 394 end; 395 396 procedure TCpu.InstructionStoreIndex; 397 begin 398 FMemory.Base[R[ReadNext] + ReadNext] := R[ReadNext]; 399 end; 400 401 procedure TCpu.InstructionLoadCpu; 402 var 403 Index: TInteger; 404 I: TInteger; 405 begin 406 R[ReadNext] := FMemory.Base[R[ReadNext]]; 407 Index := ReadNext; 408 I := ReadNext; 409 case TCpuRegister(I) of 410 crIP: R[Index] := InstructionPointer; 411 crSP: R[Index] := StackPointer; 412 crStatusRegister: R[Index] := StatusRegister.GetInteger; 413 crUserMemoryBase: R[Index] := Pointer(FUserMemory.Base) - Pointer(FBaseMemory.Base); 414 crUserMemorySize: R[Index] := FUserMemory.Size; 415 end; 416 end; 417 418 procedure TCpu.InstructionStoreCpu; 419 var 420 Index: TInteger; 421 I: TInteger; 422 begin 423 if StatusRegister.UserMode then begin 424 Interrupt(siPrivilegedInstruction); 425 Exit; 426 end; 427 R[ReadNext] := FMemory.Base[R[ReadNext]]; 428 Index := ReadNext; 429 I := ReadNext; 430 case TCpuRegister(I) of 431 crIP: InstructionPointer := R[Index]; 432 crSP: StackPointer := R[Index]; 433 crStatusRegister: StatusRegister.SetInteger(R[Index]); 434 crUserMemoryBase: FUserMemory.Base := Pointer(FBaseMemory.Base) + R[Index]; 435 crUserMemorySize: FUserMemory.Size := R[Index]; 436 end; 437 end; 438 439 procedure TCpu.InstructionEi; 440 begin 441 if StatusRegister.UserMode then begin 442 Interrupt(siPrivilegedInstruction); 443 Exit; 444 end; 445 StatusRegister.InterruptEnabled := True; 446 end; 447 448 procedure TCpu.InstructionDi; 449 begin 450 if StatusRegister.UserMode then begin 451 Interrupt(siPrivilegedInstruction); 452 Exit; 453 end; 454 StatusRegister.InterruptEnabled := False; 455 end; 456 457 procedure TCpu.SetMemory(AValue: TIntegerArray); 458 begin 459 if (FBaseMemory.Base = AValue) and (FBaseMemory.Size = Length(AValue)) then Exit; 460 FBaseMemory.Base := AValue; 461 FBaseMemory.Size := Length(AValue); 462 end; 463 85 464 procedure TCpu.CheckInterreupts; 86 465 begin 87 if FNextInterupt <> -1 then begin 88 Dec(SP); 89 Data[SP] := IP; 90 IP := Data[FNextInterupt]; 466 if StatusRegister.InterruptEnabled and (FNextInterupt <> -1) then begin 467 Push(InstructionPointer); 468 if StatusRegister.UserMode then DeactivateUserMode; 469 InstructionPointer := FMemory.Base[FNextInterupt]; 470 StatusRegister.InterruptEnabled := False; 91 471 FNextInterupt := -1; 92 472 FHalted := False; … … 94 474 end; 95 475 476 procedure TCpu.Push(Value: TInteger); 477 begin 478 Dec(StackPointer); 479 FMemory.Base[StackPointer] := Value; 480 end; 481 482 function TCpu.Pop: TInteger; 483 begin 484 Result := FMemory.Base[StackPointer]; 485 Inc(StackPointer); 486 end; 487 488 procedure TCpu.StoreContext; 489 var 490 I: Integer; 491 begin 492 for I := 0 to Length(R) - 1 do 493 Push(R[I]); 494 end; 495 496 procedure TCpu.LoadContext; 497 var 498 I: Integer; 499 begin 500 for I := Length(R) - 1 downto 0 do 501 R[I] := Pop; 502 end; 503 504 procedure TCpu.InitInstructions; 505 begin 506 FInstructionHandlers[inNop] := InstructionNop; 507 FInstructionHandlers[inHalt] := InstructionHalt; 508 FInstructionHandlers[inSet] := InstructionSet; 509 FInstructionHandlers[inCopy] := InstructionCopy; 510 FInstructionHandlers[inLoad] := InstructionLoad; 511 FInstructionHandlers[inStore] := InstructionStore; 512 FInstructionHandlers[inInc] := InstructionInc; 513 FInstructionHandlers[inDec] := InstructionDec; 514 FInstructionHandlers[inAdd] := InstructionAdd; 515 FInstructionHandlers[inSub] := InstructionSub; 516 FInstructionHandlers[inIn] := InstructionIn; 517 FInstructionHandlers[inOut] := InstructionOut; 518 FInstructionHandlers[inJump] := InstructionJump; 519 FInstructionHandlers[inJumpRel] := InstructionJumpRel; 520 FInstructionHandlers[inJumpZero] := InstructionJumpZero; 521 FInstructionHandlers[inJumpNotZero] := InstructionJumpNotZero; 522 FInstructionHandlers[inPush] := InstructionPush; 523 FInstructionHandlers[inPop] := InstructionPop; 524 FInstructionHandlers[inCall] := InstructionCall; 525 FInstructionHandlers[inRet] := InstructionRet; 526 FInstructionHandlers[inAnd] := InstructionAnd; 527 FInstructionHandlers[inOr] := InstructionOr; 528 FInstructionHandlers[inXor] := InstructionXor; 529 FInstructionHandlers[inShl] := InstructionShl; 530 FInstructionHandlers[inShr] := InstructionShr; 531 FInstructionHandlers[inMul] := InstructionMul; 532 FInstructionHandlers[inDiv] := InstructionDiv; 533 FInstructionHandlers[inMod] := InstructionMod; 534 FInstructionHandlers[inLoadIndex] := InstructionLoadIndex; 535 FInstructionHandlers[inStoreIndex] := InstructionStoreIndex; 536 FInstructionHandlers[inLoadCpu] := InstructionLoadCpu; 537 FInstructionHandlers[inStoreCpu] := InstructionStoreCpu; 538 FInstructionHandlers[inEi] := InstructionEi; 539 FInstructionHandlers[inDi] := InstructionDi; 540 end; 541 542 procedure TCpu.ActivateUserMode; 543 begin 544 StatusRegister.UserMode := True; 545 FMemory := FUserMemory; 546 end; 547 548 procedure TCpu.DeactivateUserMode; 549 begin 550 FMemory := FBaseMemory; 551 StatusRegister.UserModeWasActive := StatusRegister.UserMode; 552 StatusRegister.UserMode := False; 553 end; 554 96 555 function TCpu.ReadNext: TInteger; 97 556 begin 98 if I P >= Length(Data) then IP:= 0;99 Result := Data[IP];100 Inc(I P);557 if InstructionPointer >= FMemory.Size then InstructionPointer := 0; 558 Result := FMemory.Base[InstructionPointer]; 559 Inc(InstructionPointer); 101 560 end; 102 561 103 562 procedure TCpu.WriteNext(Value: TInteger); 104 563 begin 105 if I P >= Length(Data) then IP:= 0;106 Data[IP] := Value;107 Inc(I P);564 if InstructionPointer >= FMemory.Size then InstructionPointer := 0; 565 FMemory.Base[InstructionPointer] := Value; 566 Inc(InstructionPointer); 108 567 end; 109 568 … … 111 570 var 112 571 Instruction: TInstruction; 113 Address: TInteger;114 Index: TInteger;115 Port: TInteger;116 Dest: TInteger;117 Device: TInteger;118 572 begin 119 573 Instruction := TInstruction(ReadNext); 120 case Instruction of 121 inNop: ; 122 inHalt: FHalted := True; 123 inSet: R[ReadNext] := ReadNext; 124 inCopy: R[ReadNext] := R[ReadNext]; 125 inLoad: R[ReadNext] := Data[R[ReadNext]]; 126 inStore: Data[R[ReadNext]] := R[ReadNext]; 127 inInc: Inc(R[ReadNext]); 128 inDec: Dec(R[ReadNext]); 129 inAdd: begin 130 Index := ReadNext; 131 R[Index] := R[Index] + R[ReadNext]; 132 end; 133 inSub: begin 134 Index := ReadNext; 135 R[Index] := R[Index] - R[ReadNext]; 136 end; 137 inIn: begin 138 Index := ReadNext; 139 Device := R[ReadNext]; 140 Port := R[ReadNext]; 141 if Assigned(FOnInput) then R[Index] := FOnInput(Device, Port); 142 end; 143 inOut: begin 144 Device := R[ReadNext]; 145 Port := R[ReadNext]; 146 if Assigned(FOnOutput) then FOnOutput(Device, Port, R[ReadNext]); 147 end; 148 inJump: IP := ReadNext; 149 inJumpRel: begin 150 Address := ReadNext; 151 IP := IP + Address; 152 end; 153 inJumpZero: begin 154 Index := ReadNext; 155 Address := ReadNext; 156 if R[Index] = 0 then IP := Address; 157 end; 158 inJumpNotZero: begin 159 Index := ReadNext; 160 Address := ReadNext; 161 if R[Index] <> 0 then IP := Address; 162 end; 163 inPush: begin 164 Dec(SP); 165 Data[SP] := R[ReadNext]; 166 end; 167 inPop: begin 168 R[ReadNext] := Data[SP]; 169 Inc(SP); 170 end; 171 inCall: begin 172 Address := ReadNext; 173 Dec(SP); 174 Data[SP] := IP; 175 IP := Address; 176 end; 177 inRet: begin 178 IP := Data[SP]; 179 Inc(SP); 180 end; 181 inAnd: begin 182 Index := ReadNext; 183 R[Index] := R[Index] and R[ReadNext]; 184 end; 185 inOr: begin 186 Index := ReadNext; 187 R[Index] := R[Index] or R[ReadNext]; 188 end; 189 inXor: begin 190 Index := ReadNext; 191 R[Index] := R[Index] xor R[ReadNext]; 192 end; 193 inShl: begin 194 Index := ReadNext; 195 R[Index] := R[Index] shl R[ReadNext]; 196 end; 197 inShr: begin 198 Index := ReadNext; 199 R[Index] := R[Index] shr R[ReadNext]; 200 end; 201 inMul: begin 202 Index := ReadNext; 203 R[Index] := R[Index] * R[ReadNext]; 204 end; 205 inDiv: begin 206 Index := ReadNext; 207 R[Index] := R[Index] div R[ReadNext]; 208 end; 209 inMod: begin 210 Index := ReadNext; 211 R[Index] := R[Index] mod R[ReadNext]; 212 end; 213 inLoadIndex: R[ReadNext] := Data[R[ReadNext] + ReadNext]; 214 inStoreIndex: Data[R[ReadNext] + ReadNext] := R[ReadNext]; 215 end; 216 Inc(Ticks); 574 if Assigned(FInstructionHandlers[Instruction]) then 575 FInstructionHandlers[Instruction] 576 else raise Exception.Create('Missing handler for instruction ' + IntToStr(Integer(Instruction))); 577 Inc(FTicks); 217 578 end; 218 579 … … 243 604 I: Integer; 244 605 begin 606 FMemory := FBaseMemory; 245 607 FNextInterupt := -1; 246 608 FHalted := False; 247 Ticks := 0;248 I P := Data[0]; // Reset interrupt vector249 S P := Length(Data);609 FTicks := 0; 610 InstructionPointer := FMemory.Base[Integer(siReset)]; 611 StackPointer := FMemory.Size; 250 612 for I := 0 to Length(R) - 1 do 251 613 R[I] := 0; 252 614 end; 253 615 616 procedure TCpu.Interrupt(Index: TSystemInterrupt); 617 begin 618 Interrupt(TInteger(Index)); 619 end; 620 254 621 procedure TCpu.Interrupt(Index: TInteger); 255 622 begin … … 260 627 begin 261 628 SetLength(R, 16); 262 SetLength(Data, 0); 629 Memory := nil; 630 InitInstructions; 263 631 end; 264 632
Note:
See TracChangeset
for help on using the changeset viewer.