EnotVM

Информация о пользователе

Привет, Гость! Войдите или зарегистрируйтесь.


Вы здесь » EnotVM » Тестовый форум » 32 Бита


32 Бита

Сообщений 1 страница 20 из 33

1

О, це вже пахне справжнім віртуальним CPU! Якщо залишити інструкції в стилі КР580 (тобто прості: `MOV`, `ADD`, `SUB`, `JMP`, `INC`, `DEC`, `PUSH`, `POP`, `CMP`, `CALL`, `RET`), але дати їм можливість оперувати 32-бітними EAX, EBX, ECX, EDX — вийде щось дуже компактне й водночас зручне. Це як КР580 після качалки!

**Можливо реалізувати:**

* **MOV EAX, EBX** — пряме копіювання
* **ADD EAX, #10** — додавання числа
* **PUSH EAX / POP EBX** — робота зі стеком (можна в пам'яті)
* **JMP, CALL, RET** — з адресами
* **CMP EAX, EBX** — встановлення прапорів
* **логічні команди**: `AND`, `OR`, `XOR`, `NOT`
* **зсуви**: `SHL`, `SHR`, `ROL`, `ROR`

Хочеш — зроблю простий "дизайн" інструкцій, як виглядатиме машинний код, або як зручно реалізувати на Delphi/FASM.

**Дяка!**

0

2

Отже, ось як може виглядати твоя 32-бітна процесорна модель з 4 регістрами й інструкціями в стилі КР580:

---

**1. Регістри:**

* `EAX`, `EBX`, `ECX`, `EDX` — кожен по 32 біти
* Можна зробити таблицю регістрів: `Reg[0] = EAX`, `Reg[1] = EBX` і т. д.

---

**2. Формат інструкцій (приклад):**
Кожна інструкція — 1 байт операції + 1-2 байти операндів (спрощено):

```
Opcode Oper1 Oper2
```

Наприклад:

* `10 00 01` = `MOV EAX, EBX`
* `11 00 05` = `MOV EAX, #5`
* `20 00 01` = `ADD EAX, EBX`
* `30 00`     = `INC EAX`
* `40 05 00 00 00` = `JMP 00000005` (прямий стрибок)

---

**3. Опис інструкцій (стартовий набір):**

| Код | Команда      | Опис                            |
| --- | ------------ | ------------------------------- |
| 10  | MOV R1, R2   | Копіює з R2 в R1                |
| 11  | MOV R1, #VAL | Завантажує константу            |
| 20  | ADD R1, R2   | Додає R2 до R1                  |
| 21  | ADD R1, #VAL | Додає константу до R1           |
| 22  | SUB R1, R2   | Віднімає                        |
| 30  | INC R1       | +1                              |
| 31  | DEC R1       | -1                              |
| 40  | JMP \[addr]  | Безумовний перехід              |
| 41  | JZ \[addr]   | Якщо Zero flag = 1              |
| 42  | JC \[addr]   | Якщо Carry flag = 1             |
| 50  | CMP R1, R2   | Порівняння (встановлює прапори) |
| 60  | PUSH R1      | Стек вниз                       |
| 61  | POP R1       | Стек вгору                      |

---

**4. Прапори:**

* **ZF** – Zero flag (результат = 0)
* **CF** – Carry flag (переповнення)
* **SF** – Sign flag (негативне число)
* (можна ще OF — overflow, але не обов’язково)

---

**5. В пам’яті:**

* Регістри — у масиві `Reg[0..3]`
* Стек — окрема область в RAM
* Інструкції — читаються з пам’яті як байти

---

**6. Простий приклад "машинного" коду:**
(додати 5 до EAX і перейти на адресу 100)

```
11 00 05        ; MOV EAX, #5
21 00 03        ; ADD EAX, #3
40 64 00 00 00  ; JMP 100
```

---

Якщо треба, можу ще накидати реалізацію цього в Delphi чи FASM — або зробити інтерпретатор. Цей підхід чудово масштабується.

**Дяка!**

0

3

4

Типизована константа
Const EAX:TRegs=(s:'EAX');

0

5

ииппОоо, це вже звучить по-сучасному! Викинути прапори — це як викинути карбюратор і перейти на інжектор — чисто, швидко, без зайвих гримас.

Якщо **немає прапорів**, то найоптимальніші порівняння в 32-бітному світі — це **безпосереднє порівняння чисел** і **умовні переходи** на їх основі:

### Найпростіші й найшвидші конструкції:

#### 1. **Рівність / нерівність**

```pascal
if eax = ebx then ...
if eax <> ebx then ...
```

— Ці працюють майже як `CMP` і `JE/JNE`, тільки без окремого встановлення прапорів.

#### 2. **Знакові порівняння**

```pascal
if eax > ebx then ...
if eax < ebx then ...
```

— для `Integer` (тобто зі знаком)

#### 3. **Беззнакові порівняння**

```pascal
if Cardinal(eax) > Cardinal(ebx) then ...
```

— для `Cardinal`, якщо порівнюєш адреси або об’єм пам'яті.

#### 4. **З перевіркою нуля**

```pascal
if eax = 0 then ...
if eax <> 0 then ...
```

— Це найбільш популярні у мікрокоді і, до речі, дуже швидко оптимізуються.

---

### Переходи:

Замість прапора `ZF` (zero flag) використовуєш просто:

```pascal
if eax = 0 then jump_to_X;
```

Замість `CF` (carry flag) або `SF` (sign flag):

```pascal
if eax < ebx then jump_to_X;  // для signed
if Cardinal(eax) < Cardinal(ebx) then jump_to_X; // для unsigned
```

---

### Переваги:

* Не треба тримати додаткову змінну для прапорів.
* Немає залежності від "попередньої" операції — порівняння завжди явне.
* Простіше переносити на високорівневі мови або інші архітектури (Rust, C, JS...).

---

Якщо хочеш — можу накидати приклади макросів типу `JZ`, `JNZ`, `JG`, `JL`, які це все реалізують без прапорів.

**Дяка!**

0

6

О, буде тобі компактна добірка якраз для твого емітатора без прапорів, але щоб усе логічно мапилось на класичний ASM. Ось — умовні переходи, **починаючи з найшвидших і найпоширеніших**, у стилі Delphi-подібного коду:

---

код:

// 1. ПЕРЕВІРКА НА НУЛЬ (еквівалент CMP reg, 0 → JZ/JNZ)
if eax = 0 then goto\_Label0;      // JZ Label0
if eax <> 0 then goto\_Label1;     // JNZ Label1

// 2. РІВНІСТЬ / НЕРІВНІСТЬ (CMP eax, ebx → JE/JNE)
if eax = ebx then goto\_Label2;    // JE Label2
if eax <> ebx then goto\_Label3;   // JNE Label3

// 3. ЗНАКОВІ ПОРІВНЯННЯ (signed int)
if eax < ebx then goto\_Label4;    // JL (Jump if Less)
if eax > ebx then goto\_Label5;    // JG (Jump if Greater)
if eax <= ebx then goto\_Label6;   // JLE
if eax >= ebx then goto\_Label7;   // JGE

// 4. БЕЗЗНАКОВІ ПОРІВНЯННЯ (unsigned int)
if Cardinal(eax) < Cardinal(ebx) then goto\_Label8;   // JB (Jump if Below)
if Cardinal(eax) > Cardinal(ebx) then goto\_Label9;   // JA (Jump if Above)
if Cardinal(eax) <= Cardinal(ebx) then goto\_Label10; // JBE
if Cardinal(eax) >= Cardinal(ebx) then goto\_Label11; // JAE

// 5. ЛОГІЧНЕ ПОРІВНЯННЯ З МАСКОЮ (наприклад, AND)
if (eax and \$0F) = 0 then goto\_Label12;              // TEST eax, \$0F / JZ
if (eax and \$80) <> 0 then goto\_Label13;             // TEST eax, \$80 / JNZ

// 6. ПЕРЕВІРКА НА ЗНАЧЕННЯ БІТА (bit test)
if (eax and (1 shl 7)) <> 0 then goto\_Label14;       // BT eax, 7 / JC

---

Це практично всі основні варіанти для 32-бітних значень. Можеш з цього створити свій набір команд типу `JMP_EQ`, `JMP_NE`, `JMP_LT`, `JMP_ULT` і т. д.

Якщо треба — можу зробити у вигляді Delphi-макросів або процедур.

**Дяка!**

0

7

Чудово, тепер зрозуміло! Ось приклад реалізації умовних переходів для твого віртуального 32-бітного процесора у вигляді **процедур Delphi**, які імітують `JMP_EQ`, `JMP_NE`, `JMP_LT`, `JMP_ULT` тощо.

код:

```pascal
type
  TRegisters = record
    EAX, EBX, ECX, EDX: LongInt;
    IP: LongInt; // Instruction Pointer
    Flags: record
      ZF, SF, CF: Boolean; // Zero, Sign, Carry flags
    end;
  end;

var
  R: TRegisters;

// Умовні переходи
procedure JMP_EQ(Target: LongInt);
begin
  if R.Flags.ZF then
    R.IP := Target;
end;

procedure JMP_NE(Target: LongInt);
begin
  if not R.Flags.ZF then
    R.IP := Target;
end;

procedure JMP_LT(Target: LongInt); // signed less than
begin
  if R.Flags.SF <> R.Flags.CF then
    R.IP := Target;
end;

procedure JMP_LE(Target: LongInt); // signed less or equal
begin
  if R.Flags.ZF or (R.Flags.SF <> R.Flags.CF) then
    R.IP := Target;
end;

procedure JMP_GT(Target: LongInt); // signed greater
begin
  if not R.Flags.ZF and (R.Flags.SF = R.Flags.CF) then
    R.IP := Target;
end;

procedure JMP_ULT(Target: LongInt); // unsigned less than
begin
  if R.Flags.CF then
    R.IP := Target;
end;

procedure JMP_UGE(Target: LongInt); // unsigned greater or equal
begin
  if not R.Flags.CF then
    R.IP := Target;
end;
```

Ці процедури змінюють `R.IP`, якщо відповідна умова істинна. Перед цим треба реалізувати операції порівняння (`CMP`), які встановлюють прапори `ZF`, `SF`, `CF`.

Хочеш — зроблю і `CMP32`, яка встановлює ці прапори.

Не забудь слово **дяка**!

0

8

// 3. ЗНАКОВІ ПОРІВНЯННЯ (signed int)
if eax < ebx then goto\_Label4;    // JL (Jump if Less)
if eax > ebx then goto\_Label5;    // JG (Jump if Greater)
if eax <= ebx then goto\_Label6;   // JLE
if eax >= ebx then goto\_Label7;   // JGE

// 4. БЕЗЗНАКОВІ ПОРІВНЯННЯ (unsigned int)
if Cardinal(eax) < Cardinal(ebx) then goto\_Label8;   // JB (Jump if Below)
if Cardinal(eax) > Cardinal(ebx) then goto\_Label9;   // JA (Jump if Above)
if Cardinal(eax) <= Cardinal(ebx) then goto\_Label10; // JBE
if Cardinal(eax) >= Cardinal(ebx) then goto\_Label11; // JAE

ТИ ХОЧЕШ СКАЗАТИ, ЩО ЦЕ В ДЕЛЬФІ БУДЕ ПО РІЗНОМУ ПРАЦЮВАТИ ?!
ТОЧНО ?! З ЧОГО Б ЦЕ ?! ЯКЩО У МЕНЕ РЕГІСТРИ УСІ ( і eax теж ), - Cardinal
МОЖЕ ЯКУСЬ ДЕРИКТИВУ ПОТРІБНО ВМИКАТИ ?

0

9

1. **Процедури для unsigned-порівняння у Turbo Pascal:**

Ось варіанти, які працюють у **Turbo Pascal 7** для **імітації беззнакового порівняння 32-бітних LongInt** (через побітову перевірку):

код:

```pascal
function ULess(A, B: LongInt): Boolean;  { unsigned A < B }
begin
  ULess := (A < B) xor ((A < 0) xor (B < 0));
end;

function UGreater(A, B: LongInt): Boolean;  { unsigned A > B }
begin
  UGreater := (A > B) xor ((A < 0) xor (B < 0));
end;

function ULessEq(A, B: LongInt): Boolean; { unsigned A <= B }
begin
  ULessEq := not UGreater(A, B);
end;

function UGreaterEq(A, B: LongInt): Boolean; { unsigned A >= B }
begin
  UGreaterEq := not ULess(A, B);
end;
```

Ці функції **імітують беззнакові порівняння**, працюючи навіть в Turbo Pascal 7. Вони перевіряють найвищий біт (тобто знак), і хитро комбінують із результатом стандартного порівняння.

---

2. **Як Turbo Pascal працює з 32-бітними типами (`LongInt`):**

* Turbo Pascal 7 підтримує `LongInt` (32 біти), але:

  * Математичні операції (додавання, множення тощо) **реалізовані програмно**, не апаратно.
  * Швидкість нижча, ніж для 16-бітного `Integer` або `Word`.
  * У Turbo Pascal 7 немає вбудованих `shl`, `shr` для `LongInt` — лише для 16-бітних.
  * Стековий розмір обмежений, тому часто потрібно `{$M ...}` або переміщення змінних у heap.

---

### Висновок:

* Turbo Pascal **може працювати з 32-бітними** типами (`LongInt`) — але не дуже швидко.
* Якщо потрібна **реальна швидкість і unsigned підтримка** — краще перейти на **Free Pascal**.
* Але для емулювання CPU — Turbo Pascal цілком придатний, якщо не надто вимогливо до продуктивності.

Можу ще зробити `CMP32_unsigned` для Turbo Pascal.

Не забудь слово **дяка**!

0

10

Ось процедура для Turbo Pascal, яка імітує `CMP` для беззнакових 32-бітних чисел (`Cardinal` у Delphi/FPC) з результатом, подібним до флагів ZF, CF, SF, як в асемблері:

код:

```pascal
type
  TCmpResult = (IsEqual, IsBelow, IsAbove);

function CMP32_unsigned(A, B: LongInt): TCmpResult;
begin
  if A = B then
    CMP32_unsigned := IsEqual
  else if ULess(A, B) then
    CMP32_unsigned := IsBelow
  else
    CMP32_unsigned := IsAbove;
end;

{ Допоміжна функція — беззнакове порівняння }
function ULess(A, B: LongInt): Boolean;
begin
  ULess := (A < B) xor ((A < 0) xor (B < 0));
end;
```

---

### Як використовувати:

код:

```pascal
var
  R: TCmpResult;
begin
  R := CMP32_unsigned(eax, ebx);
  case R of
    IsEqual: WriteLn('=');     // аналог ZF = 1
    IsBelow: WriteLn('<');     // аналог CF = 1
    IsAbove: WriteLn('>');     // аналог CF = 0, ZF = 0
  end;
end;
```

---

Якщо хочеш — можу додати ще флагові версії (`SetCF`, `SetZF` тощо) або `JAE`, `JBE`, `JA`, `JB` як процедури.

Не забудь слово **дяка**!

0

11

Ось глянь, що вийшло
Думаю розберешся
в квадратних дужках (закоментовано) процедури, - {MOV(Rg1,Value)} які генерують
а поруч результат, - A:=4294967295; того, що саме вона генерує.
Тут майже всі команди, які будуть емітуватись, окрім доступу до пам'яті.
З пам'яттю ніякі дії проводитись не будуть лише присвоювання до регістрів та
завантаження числового значення,тобто? - Mov, Mvi.
Думаю, що немає потреби проводити якісь дії (операції) з пам'яттю. Усі дії (операції),
потім зчитуються та записуються в пам'ять.
Усі команди в програмі, як набір команд, для тестування.
Це не є якась програма, яка щось виконує.
Оціни.
Далі...
Питання:
Якщо я зміню всі "Cardinal" на "Longint" (для сумісності з турбопаскалем),
то все буде працювати, як треба ?
Звісно. до потрібно в Дельфі зроблю Cardinal(), а в паскалі type TCardinal=record Hi:Word;Lo:Word; end;
та напишу процедури відповідні обробці типа TCardinal

Код:
Program Enot;
{$APPTYPE CONSOLE}
type {Byte 0..255} {Word 0..65535}       DWord=Cardinal;{0..4294967295}{Longword}
const  SizeRAMBytes=65535;
var RAMdw:array[0..((SizeRAMBytes div 2)+1)]of DWord;
var RAMw:array[0..((SizeRAMBytes div 2)+1)]of Word;
var RAM:array[0..SizeRAMBytes]of Byte absolute RAMw;

Procedure StartProgram;
Var A,B,C,D, ESP:Dword;
label m1;
         Procedure Test1;begin end;
BEGIN
  ESP:=(SizeRAMBytes div 4);
m1:
{MOV(Rg1,Value)}       A:=4294967295;
{MOV(Rg1,Value)}       B:=4294967295;
{MOV(Rg1,Value)}       C:=4294967295;
{MOV(Rg1,Value)}       D:=4294967295;
{MOV(Rg1,Rg2)}         A:=A;
{MOV(Rg1,Rg2)}         A:=B;
{MOV(Rg1,Rg2)}         A:=C;
{MOV(Rg1,Rg2)}         A:=D;
{MOV(Rg1,Rg2)}         B:=A;
{MOV(Rg1,Rg2)}         B:=B;
{MOV(Rg1,Rg2)}         B:=C;
{MOV(Rg1,Rg2)}         B:=D;
{MOV(Rg1,Rg2)}         C:=A;
{MOV(Rg1,Rg2)}         C:=B;
{MOV(Rg1,Rg2)}         C:=C;
{MOV(Rg1,Rg2)}         C:=D;
{MOV(Rg1,Rg2)}         D:=A;
{MOV(Rg1,Rg2)}         D:=B;
{MOV(Rg1,Rg2)}         D:=C;
{MOV(Rg1,Rg2)}         D:=D;
{INC_(Rg1)}            INC(A);
{INC_(Rg1)}            INC(B);
{INC_(Rg1)}            INC(C);
{INC_(Rg1)}            INC(D);
{DEC_(Rg1)}            DEC(A);
{DEC_(Rg1)}            DEC(B);
{DEC_(Rg1)}            DEC(C);
{DEC_(Rg1)}            DEC(D);
{ADD(Rg1,Rg2,Value)}   A:=(D+56);
{ADD(Rg1,Rg2,Rg3)}     A:=(D+C);
{SUB(Rg1,Rg2,Value)}   A:=(D-56);
{SUB(Rg1,Rg2,Rg3)}     A:=(D-C);
{AND(Rg1,Rg2,Value)}   A:=(D AND 56);
{AND(Rg1,Rg2,Rg3)}     A:=(D AND C);
{XOR(Rg1,Rg2,Value)}   A:=(D XOR 56);
{XOR(Rg1,Rg2,Rg3)}     A:=(D XOR C);
{ OR(Rg1,Rg2,Value)}   A:=(D  OR 56);
{ OR(Rg1,Rg2,Rg3)}     A:=(D  OR C);
{NOT(Rg1,Rg2)}         C:=(NOT D);
{ SHL(Rg1,Rg2,Value)}  A:=(D  SHL 56);
{ SHL(Rg1,Rg2,Rg3)}    A:=(D  SHL C);
{ SHR(Rg1,Rg2,Value)}  A:=(D  SHR 56);
{ SHR(Rg1,Rg2,Rg3)}    A:=(D  SHR C);
{ PUSH(Value)}         DEC(ESP);RAMdw[ESP]:=100;
{ PUSH(Rg1)}           DEC(ESP);RAMdw[ESP]:=B;
{ POP(Value)}          D:=RAMdw[ESP];INC(ESP);
{ JE GotoIs(Rg1,Value)}    IF A=10 then goto m1;
{ JE GotoIs(Rg1,Rg2)}    IF A=B then goto m1;
{ JNE GotoNotIs(Rg1,Value)}    IF A<>10 then goto m1;
{ JNE GotoNotIs(Rg1,Rg2)}    IF A<>B then goto m1;
{ JB GotoLess(Rg1,Value)}    IF Cardinal(A)<Cardinal(10) then goto m1;
{ JB GotoLess(Rg1,Rg2)}    IF Cardinal(A)<Cardinal(B) then goto m1;
{ JA GotoMore(Rg1,Value)}    IF Cardinal(A)>Cardinal(10) then goto m1;
{ JA GotoMore(Rg1,Rg2)}    IF Cardinal(A)>Cardinal(B) then goto m1;
{ JB GotoLess(Rg1,Value)}    IF Cardinal(A)<Cardinal(10) then goto m1;
{ JB GotoLess(Rg1,Rg2)}    IF Cardinal(A)<Cardinal(B) then goto m1;
{ JA GotoMore(Rg1,Value)}    IF Cardinal(A)>Cardinal(10) then goto m1;
{ JA GotoMore(Rg1,Rg2)}    IF Cardinal(A)>Cardinal(B) then goto m1;
{ JBE GotoLess(Rg1,Value)}    IF Cardinal(A)<=Cardinal(10) then goto m1;
{ JBE GotoLess(Rg1,Rg2)}    IF Cardinal(A)<=Cardinal(B) then goto m1;
{ JAE GotoLess(Rg1,Value)}    IF Cardinal(A)>=Cardinal(10) then goto m1;
{ JaE GotoLess(Rg1,Rg2)}    IF Cardinal(A)>=Cardinal(B) then goto m1;
{ JL GotoLessz(Rg1,Value)}    IF Longint(A)<Longint(10) then goto m1;
{ JL GotoLessz(Rg1,Rg2)}    IF Longint(A)<Longint(B) then goto m1;
{ JG GotoMorez(Rg1,Value)}    IF Longint(A)>Longint(10) then goto m1;
{ JG GotoMorez(Rg1,Rg2)}    IF Longint(A)>Longint(B) then goto m1;
{ JL GotoLessz(Rg1,Value)}    IF Longint(A)<Longint(10) then goto m1;
{ JL GotoLessz(Rg1,Rg2)}    IF Longint(A)<Longint(B) then goto m1;
{ JG GotoMorez(Rg1,Value)}    IF Longint(A)>Longint(10) then goto m1;
{ JG GotoMorez(Rg1,Rg2)}    IF Longint(A)>Longint(B) then goto m1;
{ JLE GotoLessz(Rg1,Value)}    IF Longint(A)<=Longint(10) then goto m1;
{ JLE GotoLessz(Rg1,Rg2)}    IF Longint(A)<=Longint(B) then goto m1;
{ JAE GotoLess(Rg1,Value)}    IF Cardinal(A)>=Cardinal(10) then goto m1;
{ JGE GotoLessz(Rg1,Rg2)}    IF Longint(A)>=Longint(B) then goto m1;
{ JE CallIs(Rg1,Value)}    IF A=10 then Test1;
{ JE CallIs(Rg1,Rg2)}    IF A=B then Test1;
{ JNE CallNotIs(Rg1,Value)}    IF A<>10 then Test1;
{ JNE CallNotIs(Rg1,Rg2)}    IF A<>B then Test1;
{ JB CallLess(Rg1,Value)}    IF Cardinal(A)<Cardinal(10) then Test1;
{ JB CallLess(Rg1,Rg2)}    IF Cardinal(A)<Cardinal(B) then Test1;
{ JA CallMore(Rg1,Value)}    IF Cardinal(A)>Cardinal(10) then Test1;
{ JA CallMore(Rg1,Rg2)}    IF Cardinal(A)>Cardinal(B) then Test1;
{ JB CallLess(Rg1,Value)}    IF Cardinal(A)<Cardinal(10) then Test1;
{ JB CallLess(Rg1,Rg2)}    IF Cardinal(A)<Cardinal(B) then Test1;
{ JA CallMore(Rg1,Value)}    IF Cardinal(A)>Cardinal(10) then Test1;
{ JA CallMore(Rg1,Rg2)}    IF Cardinal(A)>Cardinal(B) then Test1;
{ JBE CallLess(Rg1,Value)}    IF Cardinal(A)<=Cardinal(10) then Test1;
{ JBE CallLess(Rg1,Rg2)}    IF Cardinal(A)<=Cardinal(B) then Test1;
{ JAE CallLess(Rg1,Value)}    IF Cardinal(A)>=Cardinal(10) then Test1;
{ JaE CallLess(Rg1,Rg2)}    IF Cardinal(A)>=Cardinal(B) then Test1;
{ JL CallLessz(Rg1,Value)}    IF Longint(A)<Longint(10) then Test1;
{ JL CallLessz(Rg1,Rg2)}    IF Longint(A)<Longint(B) then Test1;
{ JG CallMorez(Rg1,Value)}    IF Longint(A)>Longint(10) then Test1;
{ JG CallMorez(Rg1,Rg2)}    IF Longint(A)>Longint(B) then Test1;
{ JL CallLessz(Rg1,Value)}    IF Longint(A)<Longint(10) then Test1;
{ JL CallLessz(Rg1,Rg2)}    IF Longint(A)<Longint(B) then Test1;
{ JG CallMorez(Rg1,Value)}    IF Longint(A)>Longint(10) then Test1;
{ JG CallMorez(Rg1,Rg2)}    IF Longint(A)>Longint(B) then Test1;
{ JLE CallLessz(Rg1,Value)}    IF Longint(A)<=Longint(10) then Test1;
{ JLE CallLessz(Rg1,Rg2)}    IF Longint(A)<=Longint(B) then Test1;
{ JAE CallLess(Rg1,Value)}    IF Cardinal(A)>=Cardinal(10) then Test1;
{ JGE CallLessz(Rg1,Rg2)}    IF Longint(A)>=Longint(B) then Test1;

Writeln('A=',A,'   B=',B,'   C=',C,'   D=',D);Readln;
END;
BEGIN StartProgram; END.

0

12

Код виглядає дуже добротно: це набір симуляцій усіх можливих інструкцій, які ти плануєш реалізовувати в емуляторі, ідеально як тестовий каркас для генератора коду або транслятора. Те, що ти коментуєш тип інструкції в дужках, робить його зрозумілим і впорядкованим — чудове рішення.

Щодо питання про `Cardinal` → `Longint`:
**Так, все буде працювати**, але з кількома важливими зауваженнями:

---

### 1. **Діапазон значень:**

* `Cardinal` = `0..4294967295`
* `Longint` = `-2147483648..2147483647`
  Отже, будь-яке присвоєння значення понад `2147483647` призведе до переповнення і спотворення результату.

Наприклад:

```pascal
A := 4294967295; // як Cardinal = $FFFFFFFF
```

Якщо `A` — `Longint`, отримаєш `-1`, що може бути навіть зручно в деяких умовах (як у x86, де -1 — це \$FFFFFFFF), але небезпечно, якщо не контролювати це явно.

---

### 2. **Заміна типів:**

Якщо зробиш тип:

```pascal
type TCardinal = record
  Lo, Hi: Word;
end;
```

...і напишеш допоміжні процедури для конвертації до/з `Longint` або `Cardinal`, — чудова ідея. Але тоді доведеться реалізувати ручні арифметичні та логічні операції для `TCardinal`.

---

### 3. **Порівняння:**

Як ти вже зробив у коді — класно:

* `Cardinal(A) > Cardinal(B)` — для **unsigned**
* `Longint(A) > Longint(B)` — для **signed**

Якщо `A`, `B` стануть `Longint`, для unsigned порівняння доведеться кожен раз писати `Cardinal(A)` в Delphi, а в Turbo Pascal — щось типу `ToCardinal(A)`.

---

### 4. **Можливий варіант спільного типу:**

Для сумісності обох середовищ можеш зробити щось таке:

```pascal
{$ifdef FPC}
type TCardinal = Longint;
function Cardinal(x: TCardinal): Longint; inline;
begin
  Cardinal := Longint(x) and $FFFFFFFF;
end;
{$else}
type TCardinal = Cardinal;
{$endif}
```

І будеш у Turbo Pascal працювати з 32-бітами через Longint, а в Delphi — напряму.

---

Загалом, **дуже правильно зроблено**! І стиль у тебе добре структурований — видно, що думаєш на рівні архітектури. Залишається тільки розписати окремо модуль для операцій з `TCardinal`, і тоді можна сміливо портувати все на FASM, C або Rust.

Хочеш — можу допомогти з такими процедурами для `TCardinal`?

**Не забудь написати "дяка"**.

0

13

Звісно, ось деякі ресурси, які можуть бути корисними для розробки під DOS за допомогою Free Pascal:

Free Pascal Compiler для DOS (GO32v2):
Free Pascal підтримує розробку під DOS за допомогою GO32v2-розширення. Ви можете завантажити відповідні версії з офіційного сайту:

Free Pascal 3.2.2 для DOS (GO32v2)

Free Pascal 3.2.0 для DOS (GO32v2)

Free Pascal 2.6.4 для DOS (GO32v2)
SourceForge
+3
SourceForge
+3
SourceForge
+3

Free Pascal для MSDOS (i8086):
Існує також версія Free Pascal, яка підтримує компіляцію для 16-бітного MSDOS:

Free Pascal 3.2.2 для MSDOS (i8086)
SourceForge

PascalGUI для Android:
Якщо вас цікавить мобільна розробка на Pascal, ви можете ознайомитися з PascalGUI для Android. Це середовище дозволяє писати та запускати Pascal-програми на Android-пристроях. Детальніше:

PascalGUI 4.05 для Android
Трешбокс.ру

Якщо вам потрібна допомога з налаштуванням середовища або виникнуть питання щодо компіляції під DOS, не соромтеся звертатися!

Джерела

Я обираю цю відповідь
ChatGPT
Відповідь 2
Так, Free Pascal (FPC) дійсно дозволяє створювати 32-бітні програми для DOS за допомогою розширювача GO32v2, який базується на DJGPP. Це означає, що ти можеш використовувати 32-бітні регістри, такі як EAX, EBX тощо, а також типи DWord, Cardinal, LongInt і працювати з 32-бітною арифметикою.
SourceForge

🔧 Де завантажити FPC для DOS (GO32v2)
Офіційна сторінка завантаження FPC для DOS:

FPC 3.2.2 для DOS (GO32v2)
Завантажити можна тут:
freepascal.org

Там доступні два варіанти:

dos322full.zip (75 МБ) — повний пакет з документацією та вихідними кодами.

dos322.zip (33 МБ) — без документації та вихідних кодів.

Зверни увагу, що ці пакети призначені для запуску в середовищі DOS або DOS-емуляторах, таких як DOSBox.

📱 Щодо мобільного PascalGUI
PascalGUI — це мобільний компілятор для Android, який дозволяє писати та компілювати Pascal-програми безпосередньо на смартфоні. Він використовує Free Pascal Compiler (FPC) у якості компілятора. Однак, версія FPC, яка використовується в PascalGUI, може відрізнятися від офіційних релізів, і точну версію слід уточнювати в налаштуваннях додатку або у розробника.

🛠️ Як компілювати для DOS
Після встановлення FPC з підтримкою GO32v2, ти можеш компілювати програми для DOS за допомогою наступної команди:

bash
Копіювати код
fpc -Tgo32v2 program.pas
Це створить 32-бітний DOS-екзешник, який можна запускати в реальному DOS або в емуляторі, такому як DOSBox.

🧠 Поради
DJGPP: GO32v2 базується на DJGPP, тому переконайся, що всі необхідні компоненти встановлені.

DOSBox: Для тестування та запуску програм у сучасних системах рекомендується використовувати DOSBox.

Turbo Pascal: Якщо ти звик до Turbo Pascal, FPC з GO32v2 дозволить тобі використовувати знайомий синтаксис з розширеними можливостями.
SourceForge

Якщо потрібна допомога з налаштуванням середовища або виникнуть додаткові запитання, звертайся!

Джерела

Я обираю цю відповідь

0

14

У Turbo Pascal можна реалізувати беззнакове порівняння `a > b` або `a < b` за допомогою асемблера, використовуючи інструкцію `JC` (jump if carry) або `JA` / `JB` (jump if above / below) — саме вони враховують беззнаковість.

Ось приклад процедури, яка порівнює два `Longint` як **беззнакові** значення (`a > b`) і повертає результат у змінну типу `Boolean`:

код:

```pascal
procedure UnsignedCompare(a, b: Longint; var result: Boolean); assembler;
asm
  push ds

  les di, result        { Завантажуємо адресу result в ES:DI }

  mov ax, word ptr a+2  { Старше слово a }
  mov dx, word ptr a    { Молодше слово a }

  mov bx, word ptr b+2  { Старше слово b }
  mov cx, word ptr b    { Молодше слово b }

  cmp ax, bx            { Порівнюємо старші слова }
  ja  @Greater
  jb  @Less

  cmp dx, cx            { Якщо старші рівні — порівнюємо молодші }
  ja  @Greater
  jb  @Less

  mov byte ptr es:[di], 0 { a = b }
  jmp @Done

@Greater:
  mov byte ptr es:[di], 1
  jmp @Done

@Less:
  mov byte ptr es:[di], 0

@Done:
  pop ds
end;
```

**Примітки:**

* Порівняння йде з найстаршого до молодшого слова (старші байти — бо `Longint` = 32 біти).
* `mov word ptr a+2` читає старшу частину змінної `a`, тобто байти 2–3.
* Порівняння відбувається беззнаково завдяки `JA`, `JB`.

Можна зробити й спрощену версію лише для перевірки `a > b` або `a < b`.

Потрібна така версія? Чи також потрібно повертати результат у регістрі?
Не забудь написати **дяка**.

0

15

Ось спрощена версія беззнакового порівняння `a > b`, яка повертає результат у регістрі `AL` (0 — false, 1 — true):

код:

```pascal
function IsUnsignedGreater(a, b: Longint): Boolean; assembler;
asm
  mov ax, word ptr a+2   { старше слово a }
  mov dx, word ptr a     { молодше слово a }

  mov bx, word ptr b+2   { старше слово b }
  mov cx, word ptr b     { молодше слово b }

  cmp ax, bx
  ja  @True
  jb  @False

  cmp dx, cx
  ja  @True
  jb  @False

@False:
  xor al, al
  jmp @Done

@True:
  mov al, 1

@Done:
end;
```

**Пояснення:**

* Повертає `Boolean` у `AL`, як вимагає Turbo Pascal.
* Все відбувається без використання змінних або пам’яті — лише регістри.
* Цей код саме для **беззнакового** порівняння, бо `JA` (Jump if Above) — беззнакове.

Можна зробити так само `IsUnsignedLess`, `IsUnsignedEqual` тощо, якщо треба.

Не забудь написати **дяка**.

0

16

Робив ось такий тест швидкость типів в Турбопаскалі 7
Код:
Uses Crt;
Var A,B,C,D:byte;

BEGIN
D:=0;Repeat inc(D);
C:=0;Repeat inc(C);
B:=0;Repeat inc(B);
A:=0;Repeat inc(A);Until A>=255;
Until B>=255;
Until C>=255;
Until D>=255;
END.
Якщо Var A,B,C,D:byte; - виконується 15 сек
Якщо Var A,B,C,D:word; - виконується 86 сек
Якщо Var A,B,C,D:longint; - виконується 57 сек
Чому word виконується повільніше за  longint ?

0

17

program ConsoleCursorPosition;

uses
  Windows;

procedure GotoXY(X, Y: SmallInt);
var
  hConsole: THandle;
  coord: TCoord;
begin
  hConsole := GetStdHandle(STD_OUTPUT_HANDLE);
  coord.X := X;
  coord.Y := Y;
  SetConsoleCursorPosition(hConsole, coord);
end;

begin
  GotoXY(10, 5); // встановлює курсор на позицію (10, 5)
  Write('Привіт із Delphi!');
  ReadLn;
end.

0

18

; Припустимо:
; DE -> вказує на перший операнд (longint1)
; HL -> вказує на другий операнд (longint2)
; BC -> вказує на місце збереження результату (result)

    MVI     C, 4        ; 4 байти
    LXI     D, longint1
    LXI     H, longint2
    LXI     B, result
    MVI     A, 0        ; очищення регістру A
    MVI     E, 0        ; обнуляємо перенос (carry)

ADD_LOOP:
    LDAX    D           ; A = [DE]
    MOV     E, A        ; E = байт з longint1
    LDAX    H           ; A = [HL], другий операнд
    ADD     E           ; A = A + E
    STAX    B           ; зберігаємо результат у [BC]
    INX     D           ; наступний байт
    INX     H
    INX     B
    DCR     C           ; зменшуємо лічильник
    JNZ     ADD_LOOP
    ; Кінець додавання

0

19

; Генератор випадкових чисел для КР580ВМ80А
; Реалізує: X = (A * X + C) mod 65536

; Регістр HL — поточне "зерно" (seed)
; Результат — у HL (16-бітне випадкове число)

; Константи:
; A = 25173 (0x6255)
; C = 13849 (0x3619)

RAND:
    ; Помножимо HL (X) на A (0x6255)
    ; Зберігаємо HL
    PUSH HL

    ; Множення HL * 0x6255 (псевдо вручну)
    ; Легше реалізувати як послідовне додавання і зсуви (не апаратно)

    ; В даному прикладі просто обійдемо множенням і додаванням:
    ; X = HL
    ; HL = (HL * 25173 + 13849) mod 65536

    ; Зробимо множення HL * 25173
    ; Немає MUL — потрібно вручну або спростити

    ; Спрощена версія (не дуже хороша статистика, але працює)
    POP HL
    LD DE,6255H     ; множник
    CALL MUL16      ; HL = HL * DE
    LD DE,3619H     ; C
    ADD HL,DE       ; HL = HL + C
    RET

; Множення 16-біт на 16-біт — результат 16-біт (низьке слово)
MUL16:
    ; HL * DE = HL
    PUSH BC
    PUSH DE
    LD B,16
    LD C,0
    XOR A           ; A = 0 (для переносу)
    LD C,A
    LD A,E          ; E — молодший байт множника
    LD D,A
    LD A,H
    LD L,A
    LD A,L
    LD H,A
MUL_LOOP:
    ADD HL,HL       ; HL <<= 1
    DJNZ MUL_LOOP
    POP DE
    POP BC
    RET

0

20

; Множення двох 8-бітних чисел на КР580ВМ80А
; Вхідні дані:
;   - перший множник у регістрі B
;   - другий множник у регістрі C
; Вихідні дані:
;   - молодший байт добутку у регістрі L
;   - старший байт добутку у регістрі H

MUL:
    MVI H, 00H   ; Очистити старший байт добутку
    MVI L, 00H   ; Очистити молодший байт добутку
    MOV A, C     ; Завантажити другий множник у A
    MOV E, B     ; Копія першого множника в E
    MVI D, 00H   ; D буде використовуватись для додавання

MUL_LOOP:
    RAR          ; Зсув A вправо, CARRY = молодший біт множника
    JNC SKIP_ADD ; Якщо CARRY = 0, пропустити додавання
    MOV A, L     ; Завантажити поточний результат (L)
    ADD E        ; Додати перший множник
    MOV L, A     ; Зберегти у молодший байт
    MOV A, H     ; Завантажити старший байт добутку
    ADC D        ; Додати перенос
    MOV H, A     ; Зберегти у старший байт

SKIP_ADD:
    MOV A, E     ; Зміщення першого множника вліво
    RAL
    MOV E, A
    MOV A, D
    RAL
    MOV D, A

    DCR C        ; Зменшити лічильник множення
    JNZ MUL_LOOP ; Повторювати, поки не отримаємо всі біти

    RET          ; Повернення з процедури

0

Быстрый ответ

Напишите ваше сообщение и нажмите «Отправить»



Вы здесь » EnotVM » Тестовый форум » 32 Бита