---
# System prepended metadata

title: Chap 19

---

# Chap 19
## Microprocessor
* Bộ vi xử lí (microprocessor) là bộ phận hợp nhất tất cả các thành phần của bộ xử lí trung tâm (CPU)
* Bộ vi xử lí 8-bit có thể gửi đi 256 lệnh khác nhau (instructions)

--- 
## Bộ vi xử lí Intel 8080 
---
### Lệnh - Instructions
* Một bộ vi xử lí có thể có các lệnh như Load, Store, Add, Subtract, ...
* Theo chap 17, mỗi lệnh thường có 3 bytes, byte đầu tiên là opcode (mã lệnh), 2 bytes tiếp theo là địa chỉ của ô nhớ
![](https://i.imgur.com/DuUfY4z.png) 
* Trong trường hợp bộ vi xử lí, các lệnh có thể được biểu diễn : 
![](https://i.imgur.com/u8IeU6E.png)

    Trong đó A là thanh tổng (accumulator), và [aaaa] là địa chỉ ô chứa thông tin. Lệnh ````STA [aaaa] , A````  có nghĩa lấy từ ô chứa [aaaa] và nhập vào thanh tổng (accumulator)

### Thanh ghi - Register
* Ngoài thanh tổng, bộ vi xử lí có thêm 6 thanh ghi phụ, tên B, C, D, E, H, L
* Cả 7 thanh đều cho phép chứa các giá trị 8-bit, cho phép lưu byte từ bộ nhớ, hay xuất ra bộ nhớ.
* Nhưng thanh tổng A đặc biệt hơn, ví dụ khi thực hiện phép tính giữa 2 số 8-bit, kết quả chỉ hiển thị duy nhất trên thanh A.
* Có thể ghép 2 thanh ghi với nhau để tạo địa chỉ 16-bit, ví dụ ghép thanh H và L để tạo thanh địa chỉ 16-bit [HL]
### Lệnh với các thanh ghi
- Có nhiều lệnh là lệnh gán, ví dụ LDA, MOV, MVI nhưng cách thực hiện gán lại khác nhau
- **direct addressing**: gán trực tiếp. Ví dụ ````LDA A, [aaaa]````
- **indexed addressing**: lệnh gán địa chỉ. Ví dụ ````MOV A, [HL]```` . 
- **immediate addressing**: lệnh gán lập tức. Ví dụ sau lệnh ````MVI E, 37h````, thanh ghi E lập tức mang giá trị 37h
- Ví dụ về lệnh ````MOV```` 8-bit : ````01dddsss````. Trong đó ````01```` là mã của lệnh ````MOV````, ````ddd```` là mã 3 bits chỉ địa chỉ ô chứa đích, và ````sss```` chỉ địa chỉ ô lấy giá trị. 
- ![](https://i.imgur.com/f1BzeIO.png)

- Lệnh ````MOV L, E```` sẽ có mã opcode là````01101011````, hay ````6Bh````
### Flag 
Ngoài thanh ghi, ta có các Flags để rõ hơn về tính trạng của kết quả, ví dụ:
- Sign flag (dấu) là 1 nếu kết quả của phép tính cuối cùng là âm
- Zero flag (không) được về 1 nếu kết quả phép tính cuối cùng bằng 0
- Parity flag đạt giá trị 1 khi số số bit ````1```` trong kết quả là chẵn, 0 nếu ngược lại. Được dùng để kiểm tra độ chính xác kết quả, không phổ biến trong Intel 8080.
- Carry flag (nhớ) tăng 1 khi phép cộng ````ADD```` ,````ADC```` có nhớ; khi phép trừ ````SUB```` hoặc ````SBB```` không có nhớ
- Axiliary flag (phụ trợ) bằng 1 nếu phép tính từ hàng đơn vị lên hàng trăm/chục có nhớ

- Một số lệnh ảnh hưởng đến Flag, một số lệnh không. Ở đây sẽ chỉ đề cập một số loại lệnh:
    * ````CMP A, B```` : lệnh trừ giá trị ở hai thanh ghi A, B, nhưng kết quả bị hủy ngay sau đó. Thế có điều gì xảy ra? Zero Flag sẽ thành 1 nếu ````A = B````, Carry Flag nhận giá trị tương tự nếu ````A < B```` 
    * Lệnh tăng 1(````INR````) và giảm 1(````DCR````) ảnh hưởng tất cả các flag trừ carry flag
               ![](https://i.imgur.com/J7U8YWU.png)

               
    * Lệnh dịch bit trái phải ````RLC```` và ````RRC````
               ![](https://i.imgur.com/prAuhXw.png)
     
         Giả sử thanh tổng đang chứa giá trị ````110100111````, lệnh ````RLC```` dịch chuyển các bit từ phải sang trái, được kết quả ````01001111````, lưu 1 vào Carry Flag. Trong khi đó, ````RRC```` cho kết quả ````11010011````, kết thúc với giá trị Carry Flag được đẩy lên 1.


### Ngăn xếp (stack)

* Khi các thanh ghi cần làm việc với giá trị khác nhưng cần giữ lại giá trị hiện tại để xử lí trong tương lai, ta cần chứa nó ở đâu đó, đó chính là stack.
##### - Nguyên lí của stack 
* Như chồng sách: vào đầu ra cuối. Quyển sách được chồng vào sớm nhất được lấy cuối cùng.
* Hai thao tác chính: 
     * PUSH : Đẩy một giá trị vào stack
     * POP  : Lấy giá trị đầu tiên ra khỏi stack
* Ví dụ : 
   ````
   PUSH A
   PUSH B
   PUSH C
   ````
   để lấy các giá trị ra, lấy theo giá trị ngược lại:
   ````
   POP C
   POP B
   POP A
   ````
##### - Lập trình stack
* Cấu trúc : Trên bộ vi xử lí có 1 thanh ghi 16-bit tên Stack Pointer, mang địa chỉ của một đoạn trống trên RAM. Đoạn trống trên RAM này là stack ta đang cần. 
* Ví dụ về hoạt động : Giả sử ````Stack Pointer```` đang có giá trị 8000h. Và chúng ta cần ````PUSH BC````, máy tính thực hiện các bước:
     * Giảm ````Stack Pointer```` còn 7FFFh
     * Lưu giá trị hiện tại của thanh B vào địa chỉ của ````Stack Pointer````, hay ````7FFFh````
     * Giảm ````Stack Pointer```` xuống ````7FFEh````
     * Lưu giá trị hiện tại của thanh C vào địa chỉ ````7FFEh````

     Tương tự với ````POP CB````
     * Lấy giá trị ở ô ````Stack Pointer 7FFEh````  
     * Tăng ````Stack Pointer```` lên ````7FFFh````
     * Lấy giá trị ở ô ````7FFFh````
     * Tăng ````Stack Pointer```` lên ````8000h````
#### Các vấn đề của stack
* overflow : tràn ngăn xếp, xảy ra khi ngăn xếp hết không gian chứa các giá trị và phải nhận thêm quá nhiều lệnh ````PUSH````
* underflow : khi ngăn xếp đã trống và phải nhận thêm quá nhiều lệnh ````POP````
## Little-edian và Big-edian
Cùng xét ví dụ để hiểu hơn về sự khác biệt của 2 loại bộ vi xử lí Intel 8080 (little-edian) và Motorola 6800 (big-edian).
Giả sử có một lệnh gồm 3 bytes như sau cho Intel 8080: 

![](https://i.imgur.com/oKXORB4.png) 

và lệnh tương tự cho Motorola 6800 :

![](https://i.imgur.com/bWGwKlZ.png)


Với ````3Ah```` là opcode của ````LAD```` cho Intel 8080, ````B6h```` là opcode của ````LAD```` cho Motorola 6080.

Ở trường hợp Intel 8080, bộ vi này sẽ đọc vào thanh tổng giá trị ở địa chỉ ````347Bh```` . Ngược lại, bộ vi 6800 đọc giá trị ở địa chỉ ````7B34h````.

Đây chính là điểm khác biệt lớn nhất giữa little-edian và big-edian. Little-edian đọc byte ở vị trí thấp nhất và nhỏ nhất đầu tiên. Trái lại, big-edian đọc byte ở vị trí cao nhất, lớn nhất trước và sau đó tới byte ở vị trí nhỏ hơn. 


Điểm khác nhau rõ rệt trên đã tạo ra một vài khó khăn trong việc trao đổi thông tin giữa hai hệ thống có hai bộ vi xử lí khác nhau này. 


