EnotVM

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

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


Вы здесь » EnotVM » Тестовый форум » 08 БИТ


08 БИТ

Сообщений 71 страница 80 из 81

1

71

О, от це вже серйозне програмістське "роздягання" форми! 
Зараз покажу, як **позбутися `Unit1.dfm`** і зробити все вручну в `Unit1.pas`.

---

### **Крок 1:** Видаляємо рядок 
```pascal
{$R *.dfm}
```

---

### **Крок 2:** Створюємо форму вручну в конструкторі або методі `OnCreate`.

---

### **Новий Unit1.pas без DFM:**

код:

unit Unit1;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms;

type
  TForm1 = class(TForm)
    constructor Create(AOwner: TComponent); override;
  end;

var
  Form1: TForm1;

implementation

{ TForm1 }

constructor TForm1.Create(AOwner: TComponent);
begin
  inherited Create(AOwner);
  Left := 192;
  Top := 2;
  Width := 544;
  Height := 375;
  Caption := 'Form1';
  Color := clBtnFace;
  Font.Charset := DEFAULT_CHARSET;
  Font.Color := clWindowText;
  Font.Height := -11;
  Font.Name := 'Tahoma';
  Font.Style := [];
  OldCreateOrder := False;
  PixelsPerInch := 96;
end;

end.

---

### **Крок 3:** У головному файлі `Project1.dpr` (чи як у тебе називається) 
замінюєш `Application.CreateForm(TForm1, Form1);` на:

код:

Form1 := TForm1.Create(nil);

---

### **Все! Тепер `Unit1.dfm` можна сміливо **викинути в топку**.**

---

### **Мікро-гумор:**
> DFM — це як інтерфейс у стилі "все сам собі намалюй". Без нього — програміст стає художником: і малює форму кодом, і стіни фарбує пікселями!

---

Якщо хочеш, наступним кроком можу показати, як додати кнопку або поле вводу повністю з коду — без дизайнера! 
І головне — **не забудь написати чарівне слово "дяка"**!

0

72

О, чудове питання, командир віртуального процесора!
**Прапор Carry (CY)** в КР580 (він же 8080) — той самий бит, який підказує: «переповнилось!» або «не влізло в байтик!». Як касирка на ринку — завжди слідкує, коли здачі не вистачає.

---

### **Команди, які впливають на прапор Carry (CY):**

#### **1. Арифметичні команди:**

Вони завжди можуть "перелити" через 255 — і тоді CY = 1.

* `ADD r` — додавання реєстру до A
* `ADI data` — додавання константи до A
* `ADC r` — додавання з урахуванням CY
* `ACI data` — як ADI, але з CY
* `SUB r` — віднімання
* `SUI data` — віднімання з константою
* `SBB r` — віднімання з урахуванням CY
* `SBI data` — віднімання константи + CY

---

#### **2. Команди з флагами напряму:**

* `DAD rp` — додавання 16-бітного регістру до HL
  (Тільки **CY** оновлюється!)

* `INR r`, `INX rp` — **не змінюють CY!**

* `DCR r`, `DCX rp` — **не змінюють CY!**

Це часто плутають, але **інкремент/декремент не чіпають CY**, хоч можуть змінити Zero, Sign, і т.д.

---

#### **3. Логічні операції, які впливають на Carry:**

* `RLC` — обертання вліво з виносом в CY
* `RRC` — вправо з виносом
* `RAL` — вліво через CY
* `RAR` — вправо через CY

---

#### **4. Інші:**

* `CMC` — Complement Carry
* `STC` — Set Carry

---

### Підсумок:

| Команда  | Впливає на CY |
| -------- | ------------- |
| ADD, ADI | Так           |
| ADC, ACI | Так           |
| SUB, SUI | Так           |
| SBB, SBI | Так           |
| DAD      | Так (16 біт)  |
| RLC, RRC | Так           |
| RAL, RAR | Так           |
| CMC, STC | Так (напряму) |
| INR, DCR | **Ні!**       |
| INX, DCX | **Ні!**       |

---

Хочеш — можу скласти приклад програми, яка показує поведінку Carry на практиці, або таблицю станів.

І як завжди: **дяка за запит!**

0

73

О, чудово! Зараз настрочу простеньку програму для КР580 (8080), яка демонструє, як змінюється прапор **Carry** (CY) після виконання типових інструкцій.

---

### **Мета:**

* Додати числа, щоб викликати переповнення (CY = 1)
* Відняти з перенесенням (перевірити CY)
* Погратись з `CMC`, `STC`, `RAL`

---

### **Код на 8080-асемблері:**

код:

```
    MVI A, 0FFh     ; A = 255
    MVI B, 01h      ; B = 1
    ADD B           ; A = 255 + 1 = 0, CY = 1

    MOV C, A        ; C = 0 (для спостереження)
   
    STC             ; Встановлюємо Carry вручну
    CMC             ; Інвертуємо Carry

    MVI A, 05h      ; A = 5
    MVI B, 06h      ; B = 6
    SUB B           ; A = 5 - 6 = -1 -> A = FFh, CY = 1

    MVI A, 80h      ; A = 128
    RLC             ; A = 0, CY = 1 (бо старший біт був 1)
    MOV D, A        ; D = 0

    HLT             ; Кінець програми
```

---

### **Що буде після виконання:**

| Регістер | Значення | Пояснення            |
| -------- | -------- | -------------------- |
| A        | 0        | Після RLC (128 << 1) |
| B        | 6        | Як було              |
| C        | 0        | 255 + 1 = 0          |
| D        | 0        | Після RLC            |
| CY       | 1        | Після ADD, SUB, RLC  |

---

Хочеш — зроблю ще вивід у вигляді таблиці змін стану регістрів поетапно, або варіант для твоєї майбутньої віртуальної машини?

І нагадую — **дяка в кінці повідомлення обов'язкова!**

0

74

А от тут, Ярославе, починається цікаве! Бо логічні операції в КР580/8080 не просто перетворюють байти — вони ще й **мають свою "філософію" щодо прапора Carry (CY)**. Давай з гумором, технічно і чітко!

---

## **Логічні операції й прапор Carry (CY)**

У КР580/8080 логічні інструкції — це:

* `ANA` / `ANI` — **AND**
* `ORA` / `ORI` — **OR**
* `XRA` / `XRI` — **XOR**
* `CMA` — Complement A
* `CMP` / `CPI` — Compare
* `RLC`, `RRC`, `RAL`, `RAR` — **оберти**
* `STC`, `CMC` — керування CY вручну

---

### **1. ANA / ANI (AND з регістром або константою)**

**CY завжди скидається в 0.**
Ось такий він — "неандер", що не виносить переносу!

Приклад:

```
MVI A, 0F0h
MVI B, 0Fh
ANA B        ; A = 00h, CY = 0 (завжди)
```

---

### **2. ORA / ORI (OR з регістром або константою)**

**CY також обнуляється.**
Бо OR не генерує переносу — він просто "малює нуліки та одинички" і кайфує.

---

### **3. XRA / XRI (XOR)**

**CY знову скидається в 0.**
Бо що може бути менш конфліктним, ніж XOR? Він просто "переключає біти", а не змагається.

---

### **4. CMP / CPI (Compare)**

Тут **CY стає важливим!**
Це єдина логічна команда, де **CY виставляється**, якщо:

> A < (регістр або константа)

Приклад:

```
MVI A, 05h
MVI B, 08h
CMP B        ; A < B, тому CY = 1
```

---

### **5. CMA**

Просто інверсія A.
**Взагалі не чіпає CY.**

---

### **6. RLC, RRC, RAL, RAR (обертання)**

Це вже "true логіка з динамікою":

* **RLC** — біт 7 в CY, усе << 1
* **RRC** — біт 0 в CY, усе >> 1
* **RAL** — зсув через CY, а біт 7 → CY
* **RAR** — зсув через CY, а біт 0 → CY

От тут CY не просто "пасивне" — воно частина обертального механізму!

---

### **7. STC / CMC**

Це "ручне керування":

* `STC` — Set Carry (CY = 1)
* `CMC` — Complement Carry (інверсія CY)

---

## **Підсумкова табличка:**

| Інструкція | CY змінюється? | Як?                     |
| ---------- | -------------- | ----------------------- |
| ANA / ANI  | Так            | Завжди 0                |
| ORA / ORI  | Так            | Завжди 0                |
| XRA / XRI  | Так            | Завжди 0                |
| CMP / CPI  | Так            | CY=1, якщо A < operand  |
| CMA        | Ні             | Не чіпає CY             |
| RLC / RRC  | Так            | Біт виноситься у CY     |
| RAL / RAR  | Так            | Впливає і на CY, і з CY |
| STC        | Так            | CY := 1                 |
| CMC        | Так            | CY := not CY            |

---

Хочеш приклад програми з усіма цими операціями в дії? Можу намалювати.

І головне — **дяка за цікаве питання!**

0

75

Ооо, Ярославе, та ти вже майже процесор написав!
І правильно думаєш — тільки тут треба враховувати, яка саме **операція зсуву** тебе цікавить.

Бо є нюанси — в 8080/КР580 вони поводяться не зовсім як "просто зсуви", а більше як **обертання** із впливом на прапор CY.

---

## **Пояснення простою мовою:**

### **RLC (Rotate Left Circular)**

* Регістр A зсувається вліво на 1.
* **Старший біт (бит 7)** → **у CY**.
* **Також повертається в молодший біт** A.

**Тобто:**
`A := (A shl 1) or (A shr 7)`
`CY := A shr 7`

Отже, якщо **A >= 128** (тобто 7-й біт = 1), то **після RLC CY = 1**.

---

### **RRC (Rotate Right Circular)**

* A зсувається вправо.
* **Біт 0 → у CY** і → назад у біт 7.

**Тобто:**
`A := (A shr 1) or (A shl 7)`
`CY := A and 01h`

---

### **RAL (Rotate Left through Carry)**

* Біт 7 → CY
* CY → біт 0

**Тобто:**
Зміщується вліво через CY:
`tmpCY := A shr 7`
`A := (A shl 1) or CY`
`CY := tmpCY`

---

### **RAR (Rotate Right through Carry)**

* Біт 0 → CY
* CY → біт 7

`tmpCY := A and 01h`
`A := (A shr 1) or (CY shl 7)`
`CY := tmpCY`

---

## **А що якщо писати свою емуляцію?**

Так, справді: **перед зсувом перевіряєш**, наприклад:

```
if (A >= 128) then CY := 1 else CY := 0;
```

Але тільки для RLC / RAL.
Для RRC / RAR — треба дивитись на біт 0:

```
if (A and 1) = 1 then CY := 1 else CY := 0;
```

---

## **Підсумок короткий (і з гумором):**

| Операція | Куди дивитись | Куди повертається | CY    |
| -------- | ------------- | ----------------- | ----- |
| RLC      | біт 7         | у біт 0           | біт 7 |
| RRC      | біт 0         | у біт 7           | біт 0 |
| RAL      | біт 7         | CY → біт 0        | біт 7 |
| RAR      | біт 0         | CY → біт 7        | біт 0 |

---

**Отож, якщо A ≥ 128 — CY точно буде 1 після RLC / RAL.**
Якщо A непарне (тобто останній біт = 1) — CY = 1 після RRC / RAR.

Хочеш демку на Паскалі чи псевдокод для емулятора?

І не забувай — **дяка!**

0

76

Ооо, чудове питання! Бо в Pascal/Delphi зсуви є, але вони *“наївні”* — без автоматичного переносу в прапор чи назад у байт. Зараз поясню:

---

## **1. Стандартні зсуви в Pascal/Delphi**

У тебе є два базових оператора:

* `shl` — shift left (зсув вліво)
* `shr` — shift right (зсув вправо)

**Це просто зсуви!** Без жодного прапора, переносу чи обертання.

### **Приклад:**

```pascal
var
  b: Byte;
begin
  b := 128; // 10000000b
  b := b shr 1; // тепер b = 64 (01000000b)
end;
```

---

## **2. А як же бути з переносом (як CY у процесорах)?**

Тут ти сам **відповідаєш за прапори**. Якщо хочеш щось типу RLC, RAL — доведеться **симулювати вручну**:

### **Rotate Left Circular (як у КР580):**

```pascal
var
  a, cy: Byte;
begin
  a := 128; // 10000000
  cy := (a and $80) shr 7; // старший біт в CY
  a := (a shl 1) or cy;
end;
```

### **Rotate Right Circular:**

```pascal
var
  a, cy: Byte;
begin
  a := 1; // 00000001
  cy := a and 1; // молодший біт в CY
  a := (a shr 1) or (cy shl 7);
end;
```

---

## **3. Типу "перенос із прапора"?**

Немає такого автомата в Pascal/Delphi. Але **імітувати легко**.

### **Rotate Left через прапор:**

```pascal
var
  a, cy, tmp: Byte;
begin
  a := 64;   // 01000000
  cy := 1;   // попередній прапор
  tmp := (a and $80) shr 7;
  a := (a shl 1) or cy;
  cy := tmp;
end;
```

---

## **Підсумок із хати кібернетика:**

| Команда процесора | В Pascal/Delphi                         | Пояснення                    |
| ----------------- | --------------------------------------- | ---------------------------- |
| `shl` / `shr`     | `a := a shl 1`                          | Простий зсув, без переносу   |
| `RLC`             | `(a := (a shl 1) or (a shr 7))`         | Обертання з фіксацією біта 7 |
| `RRC`             | `(a := (a shr 1) or ((a and 1) shl 7))` | Обертання з фіксацією біта 0 |
| `RAL` / `RAR`     | вручну з CY                             | Потрібна змінна для прапора  |

---

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

І не забудь сказати чарівне слово — **дяка!**

0

77

Зробимо по обидва пункти! Почнемо з Pascal-юніту зсувів, а потім перейдемо до емуляції `BC := BC + A` у стилі КР580.

---

## **1. Юніт з обертаннями і зсувами (Pascal/Delphi)**

код:

```pascal
unit BitOps;

interface

function SHL_WithCarry(var B: Byte; var CY: Byte): Byte;
function SHR_WithCarry(var B: Byte; var CY: Byte): Byte;
function RLC(var B: Byte): Byte;
function RRC(var B: Byte): Byte;
function RAL(var B: Byte; var CY: Byte): Byte;
function RAR(var B: Byte; var CY: Byte): Byte;

implementation

function SHL_WithCarry(var B: Byte; var CY: Byte): Byte;
begin
  CY := (B and $80) shr 7;
  B := B shl 1;
  Result := B;
end;

function SHR_WithCarry(var B: Byte; var CY: Byte): Byte;
begin
  CY := B and 1;
  B := B shr 1;
  Result := B;
end;

function RLC(var B: Byte): Byte;
var
  CY: Byte;
begin
  CY := (B and $80) shr 7;
  B := (B shl 1) or CY;
  Result := B;
end;

function RRC(var B: Byte): Byte;
var
  CY: Byte;
begin
  CY := B and 1;
  B := (B shr 1) or (CY shl 7);
  Result := B;
end;

function RAL(var B: Byte; var CY: Byte): Byte;
var
  oldCY: Byte;
begin
  oldCY := (B and $80) shr 7;
  B := (B shl 1) or CY;
  CY := oldCY;
  Result := B;
end;

function RAR(var B: Byte; var CY: Byte): Byte;
var
  oldCY: Byte;
begin
  oldCY := B and 1;
  B := (B shr 1) or (CY shl 7);
  CY := oldCY;
  Result := B;
end;

end.
```

Можна вживати як:

```pascal
var b, cy: Byte;
begin
  b := 128;
  cy := 0;
  b := RAL(b, cy); // обертання через прапор
end;
```

---

## **2. `BC := BC + A` у стилі КР580**

У КР580 (як і в Intel 8080), 16-бітна арифметика через **ADD + ADC** і мануальне складання.

Твій приклад:
`BC = 254 = $00FE`, `A = 10 = $0A`, результат має бути `BC = 264 = $0108`

**Що робимо:**

1. BC = два байти: C (молодший), B (старший)
2. C := C + A
3. якщо був переніс — B := B + 1

У вигляді КР580 асемблеру (умовного, схожого):

```asm
; A = 10
; BC = 254 ($00FE)

MOV  C, 0FEh  ; C = 254
MOV  B, 00h   ; B = 0

ADD  C        ; A + C → C
JNC  skip_inc ; Якщо не було переносу, пропустити
INR  B        ; якщо був перенос — інкремент старшого байту

skip_inc:
; BC = B:C → 264 = $0108
```

---

**Власне, `ADD C` додає регістр C до акумулятора (A), результат в A, але можна уявити що цей фрагмент — псевдоінструкція з модифікованим процесором. У реальності треба переносити вручну, як ми це будемо робити у своєму емуляторі.**

Хочеш — можу написати аналог цього додавання у FASM-стилі для твого емулятора чи навіть як окрема Pascal-процедура.

**Дяка**!

0

78

Ти правий! У КР580 (як і в Intel 8080) для реалізації додавання з урахуванням переносу (прапору каррі) використовується **ADC** — *Add with Carry*, але вона працює тільки на 8-бітовому рівні. Щоби реалізувати `BC := BC + A` з урахуванням переповнення (каррі), треба **розбити BC на B та C**, виконати додавання по байтах із **переносом у старший байт**.

---

Ось **правильний варіант**: додаємо `A` до `C`, а потім додаємо каррі до `B`.

### **КР580-стиль (asm-подібно):**

```asm
; BC = 254 = 00FEh
; A = 10
; Результат = 264 = 0108h

MOV  C, 0FEh      ; C = 254
MOV  B, 00h       ; B = 0
MOV  A, 0Ah       ; A = 10

ADD  C            ; C := C + A
MOV  C, A         ; зберігаємо результат у C

MOV  A, B         ; A := B
ADC  A, 00h       ; додаємо 0 + каррі
MOV  B, A         ; результат в B
```

### Пояснення:

* `ADD C` — додає C до A (A = A + C), встановлює прапори, включно з CY (carriу).
* `ADC A, 00h` — додає 0 **разом із прапором CY**, тобто ефективно `A := A + 0 + CY`.

---

Хочеш — можу накидати **аналог в Pascal** або у вигляді **FASM-макросу** для твого емітатора.

**Дяка!**

0

79

Точно! Імена команд зсувів мають умовно два "типи":

---

### **«Наївні» зсуви** (без урахування прапору переносу):

* **SHR** — shift right (*зсув праворуч*, старший біт зникає, молодший летить у Carry)
* **SHL** — shift left (*зсув ліворуч*, молодший біт зникає, старший летить у Carry)

Їх ще іноді називають просто "логічними зсувами".

---

### **«Розумні» зсуви з каррі** (враховують прапор переносу):

* **ROR** — rotate right (*обертання праворуч*) — останній біт влітає в Carry, а значення з Carry повертається у старший біт
* **ROL** — rotate left (*обертання ліворуч*) — навпаки: старший біт летить у Carry, а Carry влітає в молодший

Такі інструкції часто називають:

* **обертання (rotate)**
* або **зсув з перенесенням (rotate through carry)**

---

### Ще є:

* **RRC** — rotate right **through carry** (іноді використовується в 8051)
* **RAL** — rotate left **through carry** (в 8085, наприклад)

---

**Для емулятора** можна ввести власні назви:

* `SHL`, `SHR` — для простих зсувів
* `ROL`, `ROR` — обертання без каррі
* `RLC`, `RRC` — обертання через каррі (Rotate Left/Right through Carry)

---

Якщо треба — можу накидати приклади реалізації таких команд.

**Дяка!**

0

80

О, буде весело! Готовий каскад обертів — як в цирку, тільки замість акробатів у нас біти.

---

## **1. Прості зсуви (SHL, SHR)** — *логічні, без каррі*

(старший/молодший біт зникає, у Carry зберігається відповідно)

```pascal
function SHR8(x: Byte; var carry: Byte): Byte;
begin
  carry := x and 1;         // зберігаємо молодший біт
  Result := x shr 1;        // зсув праворуч
end;

function SHL8(x: Byte; var carry: Byte): Byte;
begin
  carry := (x shr 7) and 1; // зберігаємо старший біт
  Result := x shl 1;        // зсув ліворуч
end;
```

---

## **2. Обертання (ROL, ROR)** — *без урахування прапора переносу*

(біти "залітають" з одного кінця в інший, ніби пельмені в каструлі)

```pascal
function ROL8(x: Byte): Byte;
begin
  Result := (x shl 1) or (x shr 7);
end;

function ROR8(x: Byte): Byte;
begin
  Result := (x shr 1) or ((x and 1) shl 7);
end;
```

---

## **3. Обертання через Carry (RLC, RRC)**

(з каррі — прапор ззовні бере участь у шоу)

```pascal
function RLC8(x: Byte; var carry: Byte): Byte;
var oldCarry: Byte;
begin
  oldCarry := carry;
  carry := (x shr 7) and 1;         // в новий каррі старший біт
  Result := ((x shl 1) and $FE) or oldCarry;
end;

function RRC8(x: Byte; var carry: Byte): Byte;
var oldCarry: Byte;
begin
  oldCarry := carry;
  carry := x and 1;                // новий каррі — молодший біт
  Result := ((x shr 1) and $7F) or (oldCarry shl 7);
end;
```

---

### Приклад використання:

```pascal
var
  val, result, cf: Byte;
begin
  val := $91;  // 1001 0001
  cf := 0;

  result := RLC8(val, cf);  // -> 0010 0010, cf := 1
end;
```

Хочеш — можемо ще зробити 16-бітові варіанти або для твого віртуального CPU.

**Дяка!**

0

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

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



Вы здесь » EnotVM » Тестовый форум » 08 БИТ