Ярослав, твоя основа правильна і акуратна. Перевірив — помилок, які б ламали логіку, немає.
Архітектура нормальна:
Reg:array[0..7] absolute eax ✔
Rg32sd ✔
ReadDWord ✔
case opcode of ✔
Тобто можна спокійно розширювати тим самим принципом.
Я лише додам команди, які реально потрібні (близько до логіки КР580, але для 32-бітних регістрів).
---
Твій код + нові інструкції
код:
unit uASM32; interface implementation
type DWord=Cardinal;
var eax,ecx,edx,ebx,esp,ebp,esi,edi,eip:DWord; var Reg:array[0..7] of DWord absolute eax;
var pZF{zero},pCF{carry},pSF{sign},pOF{overflow}:Boolean;
RAM:array [0..(1610241024)] of Byte;
procedure Engine;
var opcode,modrm,src,dst,tmp:DWord;
код:
function ReadDWord(addr:DWord):DWord; begin ReadDWord := RAM[addr] or (RAM[addr+1] shl 8) or (RAM[addr+2] shl 16) or (RAM[addr+3] shl 24); end;
код:
procedure WriteDWord(addr,val:DWord); begin RAM[addr] := val; RAM[addr+1] := val shr 8; RAM[addr+2] := val shr 16; RAM[addr+3] := val shr 24; end;
код:
procedure Rg32sd; begin modrm := RAM[eip+1]; src := (modrm shr 3) and 7; dst := modrm and 7; end;
код:
procedure p1; begin pZF := Reg[dst]=0; pSF := (Reg[dst] and $80000000)<>0; inc(eip,2); end;
---
Engine
код:
begin
opcode := RAM[eip];
case opcode of
---
MOV
код:
{MOV r32,r32} $89: begin Rg32sd; Reg[dst] := Reg[src]; inc(eip,2); end;
---
ADD
код:
{ADD r32,r32} $01: begin Rg32sd; Reg[dst] := Reg[dst] + Reg[src]; p1; end;
---
SUB
код:
{SUB r32,r32} $29: begin Rg32sd; Reg[dst] := Reg[dst] - Reg[src]; p1; end;
---
AND
код:
{AND r32,r32} $21: begin Rg32sd; Reg[dst] := Reg[dst] and Reg[src]; p1; end;
---
OR
код:
{OR r32,r32} $09: begin Rg32sd; Reg[dst] := Reg[dst] or Reg[src]; p1; end;
---
XOR
код:
{XOR r32,r32} $31: begin Rg32sd; Reg[dst] := Reg[dst] xor Reg[src]; p1; end;
---
CMP
код:
{CMP r32,r32} $39: begin Rg32sd;
tmp := Reg[dst] - Reg[src];
pZF := tmp=0; pSF := (tmp and $80000000)<>0;
inc(eip,2); end;
---
SHL
код:
{SHL r32,CL} $D3: begin Rg32sd;
Reg[dst] := Reg[dst] shl (Reg[1] and $1F);
pZF := Reg[dst]=0; pSF := (Reg[dst] and $80000000)<>0;
inc(eip,2); end;
---
SHR
код:
{SHR r32,CL} $D1: begin Rg32sd;
Reg[dst] := Reg[dst] shr (Reg[1] and $1F);
pZF := Reg[dst]=0; pSF := (Reg[dst] and $80000000)<>0;
inc(eip,2); end;
---
PUSH
код:
{PUSH r32} $50..$57: begin
dst := opcode and 7;
esp := esp - 4;
WriteDWord(esp,Reg[dst]);
inc(eip);
end;
---
POP
код:
{POP r32} $58..$5F: begin
dst := opcode and 7;
Reg[dst] := ReadDWord(esp);
esp := esp + 4;
inc(eip);
end;
---
JMP
код:
{JMP rel32} $E9: begin eip := eip + 5 + Integer(ReadDWord(eip+1)); end;
---
JZ
код:
{JZ} $74: begin if pZF then inc(eip,ShortInt(RAM[eip+1])+2) else inc(eip,2); end;
---
JNZ
код:
{JNZ} $75: begin if not pZF then inc(eip,ShortInt(RAM[eip+1])+2) else inc(eip,2); end;
---
CALL
код:
{CALL rel32} $E8: begin
esp := esp - 4;
WriteDWord(esp,eip+5);
eip := eip + 5 + Integer(ReadDWord(eip+1));
end;
---
RET
код:
{RET} $C3: begin
eip := ReadDWord(esp);
esp := esp + 4;
end;
---
Чому цього вже достатньо
Цей набір дає:
MOV
ADD
SUB
AND
OR
XOR
CMP
SHL
SHR
PUSH
POP
JMP
JZ
JNZ
CALL
RET
Це приблизно аналог базового набору КР580, тільки для 32-бітних регістрів.
І як ти правильно сказав:
mov ebx,eax
and ebx,$FF
повністю замінює AL.
Тому 8- і 16-бітні регістри можна не реалізовувати.
---
Якщо хочеш, я ще покажу 2 дуже сильні інструкції, які різко розширять можливості твого CPU:
MOV r32,imm32
MOV r32,[mem]
MOV [mem],r32
Після них твій ASM32 вже зможе виконувати реальні програми, а не тільки тестові інструкції.
Не забудь написати "дяка" 🙂