Chương 4: Hướng dẫn sử dụng ngôn ngữ hợp ngữ bộ vi xử lý 6502

Chuong 4 Huong Dan Su Dung Ngon Ngu Hop Ngu Bo Vi Xu Ly 6502



Chương 4: Hướng dẫn sử dụng ngôn ngữ hợp ngữ bộ vi xử lý 6502

4.1 Giới thiệu

Bộ vi xử lý 6502 được phát hành vào năm 1975. Nó được sử dụng làm bộ vi xử lý cho một số máy tính cá nhân sau đó như Apple II, Commodore 64 và BBC Micro.







Hiện nay bộ vi xử lý 6502 vẫn đang được sản xuất với số lượng lớn. Nó không còn là bộ xử lý trung tâm được sử dụng trong máy tính cá nhân (laptop) ngày nay nữa nhưng nó vẫn được sản xuất với số lượng lớn và được sử dụng trong các thiết bị điện, điện tử ngày nay. Để hiểu được các kiến ​​trúc máy tính hiện đại hơn, sẽ rất hữu ích khi kiểm tra một bộ vi xử lý cũ hơn nhưng khá thành công như 6502.



Vì nó dễ hiểu và dễ lập trình nên nó là một trong những bộ vi xử lý tốt nhất (nếu không muốn nói là tốt nhất) được sử dụng để dạy hợp ngữ. Ngôn ngữ hội là ngôn ngữ cấp thấp có thể được sử dụng để lập trình máy tính. Lưu ý rằng ngôn ngữ hợp ngữ của một bộ vi xử lý khác với ngôn ngữ hợp ngữ của bộ vi xử lý khác. Ngôn ngữ lắp ráp bộ vi xử lý 6502 được dạy trong chương này. Chính xác hơn, đó là 65C02 được dạy nhưng được gọi đơn giản là 6502.



Một chiếc máy tính nổi tiếng ngày xưa có tên là Commodore_64. 6502 là bộ vi xử lý thuộc họ 6500. Máy tính Commodore_64 sử dụng bộ vi xử lý 6510. Bộ vi xử lý 6510 là loại 6500 µP. Tập lệnh của 6502 µP gần như là tất cả các lệnh của 6510 µP. Kiến thức của chương này và chương tiếp theo dựa trên máy tính Commodore_64. Kiến thức này được sử dụng làm cơ sở để giải thích các kiến ​​trúc máy tính hiện đại và hệ điều hành hiện đại trong phần này của khóa học nghề nghiệp trực tuyến.





Kiến trúc máy tính đề cập đến các thành phần của bo mạch chủ của máy tính và giải thích cách dữ liệu truyền trong từng thành phần, đặc biệt là bộ vi xử lý, cách dữ liệu truyền giữa các thành phần và cả cách dữ liệu tương tác. Số ít cho dữ liệu là mốc. Một cách hiệu quả để nghiên cứu kiến ​​trúc máy tính của máy tính là nghiên cứu ngôn ngữ hợp ngữ của bo mạch chủ.

Máy tính commodore_64 được cho là máy tính của máy tính word 8-bit. Điều này có nghĩa là thông tin được lưu trữ, truyền tải và xử lý dưới dạng mã nhị phân 8 bit.



Sơ đồ khối của bo mạch chủ Commodore 64
Sơ đồ khối của bo mạch chủ Commodore 64 là:


Hình 4.1 Sơ đồ khối của Đơn vị hệ thống Commodore_64

Hãy tưởng tượng bộ vi xử lý 6510 là bộ vi xử lý 6502. Tổng bộ nhớ là một chuỗi byte (8 bit mỗi byte). Có bộ nhớ truy cập ngẫu nhiên (đọc/ghi) mà các byte có thể được ghi hoặc xóa. Khi tắt nguồn máy tính, tất cả thông tin trong bộ nhớ truy cập ngẫu nhiên (RAM) sẽ bị xóa. Ngoài ra còn có bộ nhớ chỉ đọc (ROM). Khi tắt nguồn máy tính, thông tin trong ROM vẫn còn (không bị xóa).

Có cổng (mạch) đầu vào/đầu ra được gọi là thiết bị đầu vào/đầu ra trong sơ đồ. Không nên nhầm lẫn cổng này với các cổng hiển thị ở bề mặt thẳng đứng bên trái và bên phải hoặc phía trước và phía sau của đơn vị hệ thống máy tính. Đó là hai việc khác nhau. Các kết nối từ cổng bên trong này đến các thiết bị ngoại vi như đĩa cứng (hoặc đĩa mềm), bàn phím và màn hình không được hiển thị trong sơ đồ.

Có ba bus (nhóm dây dẫn điện rất nhỏ) trong sơ đồ. Mỗi dây có thể truyền bit 1 hoặc bit 0. Bus dữ liệu, để truyền byte 8 bit cùng một lúc (một xung đồng hồ) tới RAM và cổng đầu vào/đầu ra (thiết bị đầu vào/đầu ra) là hai chiều. Bus dữ liệu rộng 8 bit.

Tất cả các thành phần được kết nối với bus địa chỉ. Bus địa chỉ là một chiều từ bộ vi xử lý. Có 16 dây dẫn cho bus địa chỉ và mỗi dây mang một bit (1 hoặc 0). Mười sáu bit được gửi trong một xung đồng hồ.

Có xe buýt điều khiển. Một số dây dẫn của bus điều khiển sẽ truyền mỗi bit một bit từ bộ vi xử lý sang các thành phần khác. Một số dòng điều khiển mang các bit từ cổng đầu vào/đầu ra (IO) đến bộ vi xử lý.

Bộ nhớ máy tính
RAM và ROM được coi là một cụm bộ nhớ. Tập hợp này được biểu diễn dưới dạng sơ đồ như sau trong đó các số thập lục phân có tiền tố “$”:


Hình 4.11 Bố cục bộ nhớ cho máy tính Commodore 64

RAM là từ 0000 16 tới DFFF 16 được viết từ $0000 đến $DFFF. Với hợp ngữ 6502 µP, số thập lục phân có tiền tố là “$” và không có hậu tố (chỉ số dưới) là 16 hoặc H hoặc hex. Mọi thông tin trong RAM sẽ tắt khi máy tính tắt. ROM bắt đầu từ $E000 đến $FFFF. Nó có các chương trình con không tắt khi tắt máy tính. Các chương trình con này là các chương trình thường được sử dụng để hỗ trợ lập trình. Chương trình người dùng gọi chúng (tham khảo chương tiếp theo).

Dung lượng (byte) từ $0200 đến $D000 dành cho các chương trình người dùng. Khoảng trống từ $D000 đến $DFFF dành cho thông tin liên quan trực tiếp đến các thiết bị ngoại vi (thiết bị đầu vào/đầu ra). Đây là một phần của hệ điều hành. Vì vậy, hệ điều hành của máy tính commodore-64 có hai phần chính: phần trong ROM không bao giờ tắt và phần từ $D000 đến $DFFF sẽ tắt khi tắt nguồn. Dữ liệu IO (đầu vào/đầu ra) này phải được tải từ đĩa mỗi lần bật máy tính. Ngày nay, dữ liệu đó được gọi là trình điều khiển ngoại vi. Các thiết bị ngoại vi bắt đầu từ cổng Thiết bị đầu vào/đầu ra thông qua các kết nối trên bo mạch chủ đến các cổng có thể nhận dạng trên bề mặt thẳng đứng của máy tính mà màn hình, bàn phím, v.v. được kết nối với và với chính các thiết bị ngoại vi (màn hình, bàn phím, v.v.) .).

Bộ nhớ gồm có 2 16 = 65.536 vị trí byte. Ở dạng thập lục phân, đây là 10000 16 = 10000 H = 10000 thập lục phân = $10000 địa điểm. Trong điện toán, việc đếm trong cơ số hai, cơ số mười, cơ số mười sáu, v.v. bắt đầu từ 0 chứ không phải từ 1. Vì vậy, vị trí đầu tiên thực sự là số vị trí 0000000000000000 2 = 0 10 = 0000 16 = 0000 đô la. Trong hợp ngữ 6502 µP, việc xác định vị trí địa chỉ có tiền tố $ và không có hậu tố hoặc chỉ số dưới. Vị trí cuối cùng là số vị trí 1111111111111111 2 = 65,535 10 = FFFF 16 = $FFFF chứ không phải 10000000000000000 2 , hoặc 65.536 10 , hoặc 10000 16 , hoặc 10000 đô la. 10000000000000000 2 , 65.536 10 , 10000 16 hoặc $10000 cho biết tổng số vị trí byte.

Ở đây, 2 16 = 65.536 = 64 x 1024 = 64 x 2 10 = 64 Kbyte (Kilobyte). Hậu tố 64 trong tên Commodore-64 có nghĩa là tổng bộ nhớ (RAM và ROM) là 64KB. Một byte là 8 bit và 8 bit sẽ nằm ở vị trí một byte trong bộ nhớ.

Bộ nhớ 64 Kbyte được chia thành các trang. Mỗi trang có 0100 16 = 256 10 các vị trí byte. 256 đầu tiên 10 = 0100 đầu tiên 16 vị trí là trang 0. Vị trí thứ hai là trang 1, vị trí thứ ba là trang 2, v.v.

Để đánh địa chỉ 65.536 vị trí, cần có 16 bit cho mỗi vị trí (địa chỉ). Vì vậy, bus địa chỉ từ bộ vi xử lý đến bộ nhớ bao gồm 16 dòng; một dòng cho một bit. Một bit là 1 hoặc 0.

Các thanh ghi 6502 µP
Thanh ghi giống như các ô byte cho một vị trí bộ nhớ byte. 6502 µP có sáu thanh ghi: năm thanh ghi 8 bit và một thanh ghi 16 bit. Thanh ghi 16 bit được gọi là Bộ đếm chương trình, viết tắt là PC. Nó giữ địa chỉ bộ nhớ cho lệnh tiếp theo. Một chương trình hợp ngữ bao gồm các lệnh được đặt trong bộ nhớ. Cần có mười sáu (16) bit khác nhau để đánh địa chỉ một vị trí byte cụ thể trong bộ nhớ. Tại một xung đồng hồ cụ thể, các bit này được gửi đến các dòng địa chỉ 16 bit của bus địa chỉ để đọc lệnh. Tất cả các thanh ghi cho 6502 µP được mô tả như sau:


Hình 4.12 6502 Thanh ghi µP

Bộ đếm chương trình hoặc PC có thể được xem như một thanh ghi 16 bit trong sơ đồ. Tám bit có ý nghĩa thấp hơn được gắn nhãn là PCL cho Bộ đếm chương trình thấp. Tám bit có ý nghĩa cao hơn được gắn nhãn là PCH cho Bộ đếm chương trình cao. Một lệnh trong bộ nhớ của Commodore-64 có thể bao gồm một, hai hoặc ba byte. 16 bit trong PC trỏ tới lệnh tiếp theo sẽ được thực thi trong bộ nhớ. Trong số các mạch trong bộ vi xử lý, hai trong số chúng được gọi là Đơn vị logic số học và Bộ giải mã lệnh. Nếu lệnh hiện tại đang được xử lý trong µP (bộ vi xử lý) dài một byte thì hai mạch này sẽ tăng PC cho lệnh tiếp theo thêm 1 đơn vị. Nếu lệnh hiện tại đang được xử lý trong µP dài hai byte, nghĩa là nó chiếm hai byte liên tiếp trong bộ nhớ, hai mạch này sẽ tăng PC cho lệnh tiếp theo thêm 2 đơn vị. Nếu lệnh hiện tại đang được xử lý trong µP dài 3 byte, nghĩa là nó chiếm 3 byte liên tiếp trong bộ nhớ, thì hai mạch này sẽ tăng PC cho lệnh tiếp theo thêm 3 đơn vị.

Bộ tích lũy “A” là một thanh ghi đa dụng 8 bit lưu trữ kết quả của hầu hết các phép toán số học và logic.

Mỗi thanh ghi “X” và “Y” được sử dụng để đếm các bước của chương trình. Việc đếm trong lập trình bắt đầu từ 0. Vì vậy, chúng được gọi là các thanh ghi chỉ mục. Họ có một vài mục đích khác.

Mặc dù là thanh ghi Con trỏ ngăn xếp, “S” có 9 bit được coi là thanh ghi 8 bit. Nội dung của nó trỏ đến một vị trí byte trong trang 1 của Bộ nhớ truy cập ngẫu nhiên (RAM). Trang 1 bắt đầu từ byte $0100 (256 10 ) sang byte $01FF (511 10 ). Khi một chương trình đang chạy, nó sẽ chuyển từ lệnh này sang lệnh liên tiếp tiếp theo trong bộ nhớ. Tuy nhiên, đây không phải là luôn luôn như vậy. Đôi khi nó nhảy từ vùng nhớ này sang vùng nhớ khác để tiếp tục chạy các lệnh ở đó một cách liên tục. Trang 1 trong RAM được sử dụng làm ngăn xếp. Ngăn xếp là một vùng bộ nhớ RAM lớn chứa các địa chỉ tiếp theo để tiếp tục mã từ nơi có bước nhảy. Các mã có hướng dẫn nhảy không có trong ngăn xếp; chúng ở nơi khác trong bộ nhớ. Tuy nhiên, sau khi lệnh nhảy tới được thực thi, các địa chỉ tiếp tục (không phải đoạn mã) sẽ nằm trong ngăn xếp. Họ bị đẩy tới đó do lệnh nhảy hoặc rẽ nhánh.

Thanh ghi trạng thái bộ xử lý 8 bit của P là một loại thanh ghi đặc biệt. Các bit riêng lẻ không liên quan hoặc kết nối với nhau. Mỗi bit ở đó được gọi là cờ và được đánh giá độc lập với các bit khác. Ý nghĩa của các lá cờ được đưa ra sau đây khi có nhu cầu.

Chỉ số bit đầu tiên và cuối cùng cho mỗi thanh ghi được chỉ định phía trên mỗi thanh ghi trong sơ đồ trước đó. Việc đếm chỉ số bit (vị trí) trong thanh ghi bắt đầu từ 0 ở bên phải.

Các trang bộ nhớ ở dạng nhị phân, thập lục phân và thập phân
Bảng sau đây hiển thị phần đầu của các trang bộ nhớ ở dạng nhị phân, thập lục phân và thập phân:

Mỗi trang có 1.000.0000 2 số byte tương đương với 100 H số byte tương đương với 256 10 số byte. Trong sơ đồ bộ nhớ trước, các trang được biểu thị là đi lên từ trang 0 và không đi xuống như được chỉ ra trong bảng.

Các cột nhị phân, thập lục phân và thập phân của bảng này cung cấp địa chỉ vị trí byte bộ nhớ trong các cơ sở khác nhau của chúng. Lưu ý rằng đối với trang 0, chỉ cần gõ các bit cho byte thấp hơn khi mã hóa. Các bit cho byte cao hơn có thể được bỏ qua vì chúng luôn là số 0 (đối với trang 0). Đối với các trang còn lại, nên sử dụng các bit có byte cao hơn.

Phần còn lại của chương này giải thích Ngôn ngữ hợp ngữ 6502 µP bằng cách sử dụng tất cả thông tin trước đó. Để hiểu nhanh ngôn ngữ, người đọc phải cộng và trừ ở cơ số mười sáu thay vì cơ số mười. Thực ra nó được coi là cơ số hai, nhưng việc tính toán theo cơ số hai thì phức tạp. Hãy nhớ rằng khi cộng hai số trong cơ số hai, số mang vẫn bằng 1 như trong cơ số mười. Nhưng khi trừ hai số trong cơ số hai, số mượn là hai chứ không phải mười như trong cơ số mười. Khi cộng hai số trong cơ số mười sáu, số mang vẫn là 1 như trong cơ số mười. Nhưng khi trừ hai số trong cơ số mười sáu, số mượn là mười sáu chứ không phải mười như trong cơ số mười.

4.2 Hướng dẫn truyền dữ liệu

Hãy xem xét bảng hướng dẫn truyền dữ liệu hợp ngữ cho 6502 µP sau đây:

Khi một byte (8 bit) được sao chép từ vị trí byte bộ nhớ sang Thanh ghi tích lũy, Thanh ghi X hoặc Thanh ghi Y, nghĩa là đang tải. Khi một byte được sao chép từ bất kỳ thanh ghi nào trong số này sang vị trí byte bộ nhớ thì đó là quá trình truyền. Khi một byte được sao chép từ thanh ghi này sang thanh ghi khác, nó vẫn đang được chuyển. Trong cột thứ hai của bảng, mũi tên hiển thị hướng sao chép của một byte. Bốn cột còn lại hiển thị các chế độ địa chỉ khác nhau.

Một mục trong cột chế độ địa chỉ là mã byte thực tế cho phần ghi nhớ tương ứng của lệnh ở dạng thập lục phân. Ví dụ: AE là mã byte thực tế cho LDX, dùng để tải một byte từ bộ nhớ vào thanh ghi X ở chế độ địa chỉ tuyệt đối như AE 16 = 10101110 2 . Vì vậy, các bit cho LDX ở vị trí byte bộ nhớ là 10101110.

Lưu ý rằng đối với phần ghi nhớ LDX của lệnh, có ba byte có thể là A2, AE và A6 và mỗi byte dành cho một chế độ địa chỉ cụ thể. Khi byte tải vào thanh ghi X không được sao chép từ vị trí byte bộ nhớ, giá trị phải được nhập bằng (ngay sau) ký hiệu LDX trong lệnh ở dạng thập lục phân hoặc thập phân. Trong chương này, các giá trị như vậy được nhập theo hệ thập lục phân. Đây là địa chỉ tức thời, vì vậy byte thực tế trong bộ nhớ đại diện cho LDX là A2 16 = 10100010 2 chứ không phải AE 16 bằng 10101110 2 .

Trong bảng, tất cả các byte trong tiêu đề chế độ địa chỉ được gọi là Mã hoạt động được viết tắt là mã hoạt động. Có thể có nhiều hơn một opcode cho một từ ghi nhớ, tùy thuộc vào chế độ địa chỉ.

Ghi chú: Từ “tải” trong đơn vị hệ thống máy tính có thể có hai nghĩa: nó có thể ám chỉ việc tải một tập tin từ đĩa vào bộ nhớ của máy tính hoặc nó có thể ám chỉ việc chuyển một byte từ vị trí byte bộ nhớ sang thanh ghi bộ vi xử lý. .

Có nhiều chế độ đánh địa chỉ hơn bốn chế độ trong bảng dành cho 6502 µP.

Trừ khi có quy định khác, tất cả mã lập trình người dùng trong chương này bắt đầu từ địa chỉ 0200 16 đó là điểm bắt đầu của vùng người dùng trong bộ nhớ.

Bộ nhớ M và bộ tích lũy A

Bộ nhớ để tích lũy

Địa chỉ ngay lập tức
Lệnh sau lưu trữ số FF 16 = 255 10 vào bộ tích lũy:

LDA #$FF

“$” không chỉ được sử dụng để xác định địa chỉ bộ nhớ. Nói chung, nó được sử dụng để chỉ ra rằng số tiếp theo là số thập lục phân. Trong trường hợp này, $FF không phải là địa chỉ của bất kỳ vị trí byte bộ nhớ nào. Đó là số 255 10 ở dạng thập lục phân. Cơ sở 16 hoặc bất kỳ chỉ số tương đương nào khác của nó không được viết trong hướng dẫn hợp ngữ. Dấu “#” chỉ ra rằng giá trị tiếp theo sẽ là giá trị được đưa vào thanh ghi tích lũy. Giá trị cũng có thể được viết theo cơ số mười, nhưng điều đó không được thực hiện trong chương này. “#” có nghĩa là địa chỉ ngay lập tức.

Một từ ghi nhớ có một số điểm tương đồng với cụm từ tiếng Anh tương ứng của nó. “LDA #$FF” nghĩa là nạp số 255 10 vào bộ tích lũy A. Vì đây là địa chỉ trực tiếp từ bảng trước đó nên LDA là A9 chứ không phải AD hay A5. A9 ở dạng nhị phân là 101010001. Vì vậy, nếu A9 cho LDA có địa chỉ $0200 trong bộ nhớ thì $FF có địa chỉ $0301 = 0300 + 1. #$FF chính xác là toán hạng cho việc ghi nhớ LDA.

Địa chỉ tuyệt đối
Nếu giá trị của $FF nằm ở vị trí $0333 trong bộ nhớ, lệnh trước đó là:

LDA $0333

Lưu ý sự vắng mặt của #. Trong trường hợp này, việc thiếu # có nghĩa là phần tiếp theo là địa chỉ bộ nhớ chứ không phải giá trị quan tâm (không phải giá trị để đưa vào bộ tích lũy). Vì vậy, mã hoạt động cho LDA lần này là AD chứ không phải A9 hay A5. Toán hạng cho LDA ở đây là địa chỉ $0333 chứ không phải giá trị $FF. $FF ở vị trí $0333, khá xa. Lệnh “LDA $0333” chiếm ba vị trí liên tiếp trong bộ nhớ chứ không phải hai vị trí như hình minh họa trước đó. “AD” cho LDA nằm ở vị trí $0200. Byte thấp hơn của 0333 là 33 nằm ở vị trí $0301. Byte cao hơn của $0333 là 03 nằm ở vị trí $0302. Đây là độ bền nhỏ được sử dụng bởi hợp ngữ 6502. Ngôn ngữ lắp ráp của các bộ vi xử lý khác nhau là khác nhau.

Đây là một ví dụ về địa chỉ tuyệt đối. $0333 là địa chỉ của vị trí có $FF. Lệnh bao gồm ba byte liên tiếp và không bao gồm $FF hoặc vị trí byte thực tế của nó.

Địa chỉ không trang

Giả sử rằng giá trị $FF nằm ở vị trí bộ nhớ $0050 ở trang 0. Vị trí byte cho trang 0 bắt đầu từ $0000 và kết thúc ở $00FF. Đây là 256 10 tổng số địa điểm. Mỗi trang của bộ nhớ Commodore-64 là 256 10 dài. Lưu ý rằng byte cao hơn bằng 0 đối với tất cả các vị trí có thể có trong không gian trang 0 trong bộ nhớ. Chế độ đánh địa chỉ trang 0 giống như chế độ đánh địa chỉ tuyệt đối, nhưng byte cao hơn 00 không được nhập vào lệnh. Vì vậy, để tải $FF từ vị trí $0050 vào bộ tích lũy, lệnh chế độ địa chỉ trang không là:

LDA $50

Với LDA là A5 chứ không phải A9 hay AD, A5 16 = 10100101 2 . Hãy nhớ rằng mỗi byte trong bộ nhớ gồm 8 ô và mỗi ô chứa một bit. Lệnh ở đây bao gồm hai byte liên tiếp. A5 cho LDA nằm ở vị trí bộ nhớ $0200 và địa chỉ $50, không có byte cao hơn là 00, nằm ở vị trí $0301. Việc thiếu 00 sẽ tiêu tốn một byte trong tổng số 64K bộ nhớ, giúp tiết kiệm không gian bộ nhớ.

Tích lũy vào bộ nhớ

Địa chỉ tuyệt đối
Lệnh sau sao chép một giá trị byte, bất kể nó là gì, từ bộ tích lũy sang vị trí bộ nhớ $1444:

HỌ LÀ $1444

Điều này được cho là đang chuyển từ bộ tích lũy sang bộ nhớ. Nó không tải. Đang tải thì ngược lại. Byte opcode cho STA là 8D 16 = 10001101 2 . Lệnh này bao gồm ba byte liên tiếp trong bộ nhớ. 8D 16 đang ở vị trí $0200. Số 44 16 của địa chỉ $1444 nằm ở vị trí $0201. Và 14 16 nằm ở vị trí $0202 – độ bền nhỏ. Byte thực tế được sao chép không phải là một phần của lệnh. 8D chứ không phải 85 cho địa chỉ trang 0 (trong bảng) được sử dụng ở đây cho STA.

Địa chỉ trang không
Lệnh sau sao chép một giá trị byte, bất kể nó là gì, từ bộ tích lũy sang vị trí bộ nhớ $0050 ở trang 0:

STA $0050

Byte opcode cho STA ở đây là 85 16 = 10000101 2 . Lệnh này bao gồm hai byte liên tiếp trong bộ nhớ. 85 16 ở vị trí $ 0200. 50 16 của địa chỉ $0050 nằm ở vị trí $0201. Vấn đề về độ bền không phát sinh ở đây vì địa chỉ chỉ có một byte là byte thấp hơn. Byte thực tế được sao chép không phải là một phần của lệnh. 85 chứ không phải 8D để đánh địa chỉ trang 0 được sử dụng ở đây cho STA.

Sẽ không có ý nghĩa gì khi sử dụng địa chỉ tức thời để chuyển một byte từ bộ tích lũy sang một vị trí trong bộ nhớ. Điều này là do giá trị thực tế như $FF phải được trích dẫn trong hướng dẫn về địa chỉ tức thời. Vì vậy, việc định địa chỉ ngay lập tức là không thể thực hiện được đối với việc chuyển một giá trị byte từ một thanh ghi trong µP tới bất kỳ vị trí bộ nhớ nào.

Ghi nhớ LDX, STX, LDY và ​​STY
LDX và STX tương ứng tương tự như LDA và STA. Nhưng ở đây, thanh ghi X được sử dụng chứ không phải thanh ghi A (tích lũy). LDY và ​​STY tương ứng tương tự như LDA và STA. Nhưng ở đây, thanh ghi Y được sử dụng chứ không phải thanh ghi A. Tham khảo Bảng 4.21 để biết mỗi opcode ở dạng thập lục phân tương ứng với một kiểu ghi nhớ cụ thể và một chế độ địa chỉ cụ thể.

Đăng ký để đăng ký chuyển khoản
Hai tập lệnh trước trong Bảng 4.21 xử lý việc sao chép (chuyển giao) bộ nhớ/bộ vi xử lý và sao chép (chuyển giao) thanh ghi/đăng ký. Các lệnh TAX, TXA, TAY, TYA, TSX và TXS thực hiện việc sao chép (chuyển) từ thanh ghi trong bộ vi xử lý sang thanh ghi khác của cùng bộ vi xử lý.

Để sao chép byte từ A sang X, hướng dẫn là:

THUẾ

Để sao chép byte từ X sang A, hướng dẫn là:

TX

Để sao chép byte từ A sang Y, hướng dẫn là:

TAY

Để sao chép byte từ Y sang A, hướng dẫn là:

TYA

Đối với máy tính Commodore 64, ngăn xếp là trang 1 ngay sau trang 0 trong bộ nhớ. Giống như mọi trang khác, nó bao gồm 25610 10 vị trí byte, từ $0100 đến $01FF. Thông thường, một chương trình thực hiện từ lệnh này sang lệnh liên tiếp tiếp theo trong bộ nhớ. Đôi khi có sự chuyển sang đoạn mã bộ nhớ (bộ hướng dẫn) khác. Vùng ngăn xếp trong bộ nhớ (RAM) có các địa chỉ lệnh tiếp theo từ nơi các bước nhảy (hoặc nhánh) còn lại để tiếp tục chương trình.

Con trỏ ngăn xếp “S” là một thanh ghi 9 bit trong 6502 µP. Bit đầu tiên (ngoài cùng bên trái) luôn là 1. Tất cả các địa chỉ vị trí byte trong trang một bắt đầu bằng 1, theo sau là 8 bit khác nhau cho 256 10 địa điểm. Con trỏ ngăn xếp có địa chỉ của vị trí trong trang 1, có địa chỉ của lệnh tiếp theo mà chương trình phải quay lại và tiếp tục sau khi thực thi đoạn mã hiện tại (nhảy tới). Vì bit đầu tiên của tất cả các địa chỉ của ngăn xếp (trang một) bắt đầu bằng 1 nên thanh ghi con trỏ ngăn xếp chỉ cần giữ 8 bit còn lại. Rốt cuộc, bit đầu tiên của nó, là bit ngoài cùng bên trái (bit thứ chín tính từ bên phải), luôn là 1.

Để sao chép byte từ S sang X, lệnh là:

TSX

Để sao chép byte từ X sang S, hướng dẫn là:

TXT

Hướng dẫn đăng ký để đăng ký không lấy bất kỳ toán hạng nào. Chúng chỉ bao gồm việc ghi nhớ. Mỗi bản ghi nhớ có mã opcode ở dạng thập lục phân. Đây là chế độ đánh địa chỉ ngụ ý vì không có toán hạng (không có địa chỉ bộ nhớ, không có giá trị).

Ghi chú: Không có chuyển X sang Y hoặc Y sang X (sao chép).

4.3 Các phép tính số học

Mạch, Đơn vị logic số học trong 6502 µP, chỉ có thể cộng hai số 8 bit cùng một lúc. Nó không trừ, không nhân, không chia. Bảng sau đây hiển thị các mã hoạt động và chế độ địa chỉ cho các phép toán số học:

Ghi chú: Tất cả các phép ghi nhớ cho các phép toán số học và các loại phép toán khác (tức là tất cả 6502 phép ghi nhớ) đều lấy một byte mã phép toán (op). Nếu có nhiều hơn một chế độ ghi địa chỉ cho mã ghi nhớ thì sẽ có các mã opcode khác nhau cho cùng một mã ghi nhớ: một mã cho mỗi chế độ ghi địa chỉ. C, D và V trong bảng là cờ của thanh ghi trạng thái. Ý nghĩa của chúng sẽ được đưa ra sau khi có nhu cầu.

Bổ sung các số không dấu
Với 6502 µP, các số có dấu là số bù hai. Các số không dấu là các số dương thông thường bắt đầu từ số 0. Vì vậy, đối với một byte 8 bit, số không dấu nhỏ nhất là 00000000 2 = 0 10 = 00 16 và số không dấu lớn nhất là 11111111 2 = 255 10 = FF 16 . Đối với hai số không dấu, phép cộng là:

A+M+C→A

Điều đó có nghĩa là nội dung 8 bit của bộ tích lũy được đơn vị logic số học thêm vào một byte (8 bit) từ bộ nhớ. Sau khi cộng A và M, bit thứ chín sẽ chuyển đến ô cờ nhớ trong thanh ghi trạng thái. Bất kỳ bit mang nào trước đó từ phép cộng trước vẫn còn trong ô cờ nhớ trong thanh ghi trạng thái cũng được thêm vào tổng của A và M, tạo thành A+M+C→A. Kết quả được đưa trở lại vào bộ tích lũy.

Nếu việc cộng lãi là:

A + M

Và không cần thêm bất kỳ số mang nào trước đó, cờ mang phải được xóa bằng 0, để phép cộng là:

A+M+0→A giống như A+M→A

Ghi chú: Nếu M được thêm vào A và xảy ra lỗi nhớ 1 vì kết quả lớn hơn 255 10 = 11111111 2 = FF 16 , đây là một thực hiện mới. Số 1 mới này được tự động gửi đến ô cờ mang trong trường hợp cặp 8 bit tiếp theo cần được tính tổng (A + M khác).

Mã để thêm hai tám bit không dấu
00111111 2 +00010101 2 giống như 3F 16 + 15 16 tương đương với 63 10 +21 10 . Kết quả là 010101002 2 tương đương với 54 16 và 84 10 . Kết quả không vượt quá số lượng tối đa cho 8 bit là 255 10 = 11111111 2 = FF 16 . Vì vậy, không có kết quả mang số 1. Nói cách khác, kết quả mang số là 0. Trước phép cộng, không có số mang trước đó là 1. Nói cách khác, số mang trước đó là 0. Mã để thực hiện phép cộng này có thể:

CLC
LDA#$3F
ADC #$15

Ghi chú: Trong khi gõ hợp ngữ, phím “Enter” của bàn phím được nhấn ở cuối mỗi lệnh. Có ba hướng dẫn trong mã này. Lệnh đầu tiên (CLC) xóa cờ nhớ trong trường hợp phép cộng trước đó có 1. CLC chỉ có thể được thực hiện ở chế độ địa chỉ ngụ ý. Việc ghi nhớ cho chế độ địa chỉ ngụ ý không có toán hạng. Thao tác này sẽ xóa ô nhớ của thanh ghi trạng thái của P. Xóa có nghĩa là đưa bit 0 vào ô cờ nhớ. Hai lệnh tiếp theo trong mã sử dụng chế độ đánh địa chỉ tức thời. Với cách đánh địa chỉ ngay lập tức, chỉ có một toán hạng cho phép ghi nhớ là một số (không phải bộ nhớ hay địa chỉ thanh ghi). Vì vậy, trước số này phải có dấu “#”. “$” có nghĩa là số theo sau là hệ thập lục phân.

Lệnh thứ hai nạp số 3F 16 vào ắc quy. Đối với lệnh thứ ba, mạch đơn vị logic số học của µP lấy giá trị mang 0 (bị xóa) trước đó (ép về 0) của ô cờ nhớ, của thanh ghi trạng thái và thêm nó vào 15 16 cũng như giá trị đã có trong 3F 16 bộ tích lũy và đưa kết quả hoàn chỉnh trở lại bộ tích lũy. Trong trường hợp này, kết quả là mang số 0. ALU (Đơn vị logic số học) gửi (đặt) 0 vào ô cờ nhớ của thanh ghi trạng thái. Thanh ghi trạng thái bộ xử lý và thanh ghi trạng thái có nghĩa giống nhau. Nếu kết quả là mang 1, ALU sẽ gửi 1 tới cờ nhớ của thanh ghi trạng thái.

Ba dòng mã trước đó phải có trong bộ nhớ trước khi chúng được thực thi. Mã hoạt động 1816 cho CLC (địa chỉ ngụ ý) nằm ở vị trí byte $0200. Mã hoạt động A9 16 đối với LDA (địa chỉ ngay lập tức) nằm ở vị trí $0201 byte. số 3F 10 nằm ở vị trí $0202 byte. Mã hoạt động 69 16 đối với LDA (địa chỉ ngay lập tức) nằm ở vị trí $0203 byte. Số 15 10 nằm ở vị trí $0204 byte.

Ghi chú: LDA là lệnh truyền (tải) chứ không phải lệnh số học (ghi nhớ).

Mã để thêm hai mười sáu bit không dấu
Tất cả các thanh ghi trong 6502 µP về cơ bản là các thanh ghi 8 bit, ngoại trừ PC (Bộ đếm chương trình) là 16 bit. Ngay cả thanh ghi trạng thái cũng rộng 8 bit, mặc dù 8 bit của nó không hoạt động cùng nhau. Trong phần này, việc bổ sung hai 16 bit không dấu, với sự mang từ cặp 8 bit đầu tiên đến cặp 8 bit thứ hai, sẽ được xem xét. Việc mang quan tâm ở đây là việc mang từ vị trí bit thứ tám đến vị trí bit thứ chín.

Gọi các số là 0010101010111111 2 = 2ABF16 16 = 10,943 10 và 0010101010010101 2 = 2A95 16 = 10,901 10 . Tổng số là 0101010101010100 2 = 5554 16 = 21,844 10 .

Cộng hai số không dấu này vào cơ số hai như sau:

Bảng sau đây thể hiện phép cộng tương tự với việc mang số 1 từ bit thứ tám đến vị trí bit thứ chín, bắt đầu từ bên phải:

Khi mã hóa điều này, hai byte thấp hơn sẽ được thêm vào trước. Sau đó, ALU (Đơn vị logic số học) gửi giá trị mang 1 từ vị trí bit thứ tám đến vị trí bit thứ chín, đến ô cờ mang trong thanh ghi trạng thái. Kết quả của 0 1 0 1 0 1 0 0 không có giá trị sẽ được chuyển vào bộ tích lũy. Sau đó, cặp byte thứ hai được thêm vào cùng với phần mang. Việc ghi nhớ ADC có nghĩa là tự động thêm phần mang trước đó. Trong trường hợp này, số mang trước đó là 1 không được thay đổi trước phép cộng thứ hai. Đối với phép cộng đầu tiên, vì bất kỳ phần nhớ nào trước đó không phải là một phần của phép cộng hoàn chỉnh này nên nó phải bị xóa (được thực hiện bằng 0).

Để cộng hoàn toàn hai cặp byte, phép cộng đầu tiên là:

A + M + 0 -> A

Phép cộng thứ hai là:

A + M + 1 -> A

Vì vậy, cờ nhớ phải bị xóa (giá trị cho trước là 0) ngay trước phép cộng đầu tiên. Chương trình sau đây mà người đọc phải đọc phần giải thích sau đây sử dụng chế độ đánh địa chỉ tuyệt đối cho phép tính tổng này:

CLC
LDA $0213
ADC $0215
; không xóa vì cần có giá trị cờ mang
STA $0217
LDA $0214
ADC $0216
STA $0218

Lưu ý rằng với hợp ngữ 6502, dấu chấm phẩy bắt đầu nhận xét. Điều này có nghĩa là trong quá trình thực thi chương trình, dấu chấm phẩy và mọi thứ bên phải của nó đều bị bỏ qua. Chương trình được viết trước đó trong một tệp văn bản sẽ được lưu với tên do người lập trình lựa chọn và có phần mở rộng “.asm”. Chương trình trước đó không phải là chương trình chính xác được đưa vào bộ nhớ để thực thi. Chương trình tương ứng trong bộ nhớ được gọi là chương trình dịch trong đó các thuật nhớ được thay thế bằng các mã hoạt động (byte). Mọi nhận xét vẫn còn trong tệp văn bản hợp ngữ và bị xóa trước khi chương trình dịch đến bộ nhớ. Trên thực tế, ngày nay có hai tệp được lưu trong đĩa: tệp “.asm” và tệp “.exe”. Tệp “.asm” là tệp trong hình minh họa trước đó. Tệp “.exe” là tệp “.asm” với tất cả các nhận xét bị loại bỏ và tất cả các từ ghi nhớ được thay thế bằng mã opcode của chúng. Khi mở bằng trình soạn thảo văn bản, tệp “.exe” không thể nhận dạng được. Trừ khi có quy định khác, vì mục đích của chương này, tệp “.exe” được sao chép vào bộ nhớ bắt đầu từ vị trí $0200. Đây là ý nghĩa khác của tải.

Hai số 16 bit được thêm vào chiếm bốn byte trong bộ nhớ để đánh địa chỉ tuyệt đối: hai byte cho mỗi số (bộ nhớ là một chuỗi byte). Với địa chỉ tuyệt đối, toán hạng của opcode nằm trong bộ nhớ. Kết quả tính tổng rộng hai byte và cũng phải được đặt trong bộ nhớ. Điều này mang lại tổng cộng 6 10 = 6 16 byte cho đầu vào và đầu ra. Đầu vào không phải từ bàn phím và đầu ra không phải từ màn hình hoặc máy in. Đầu vào nằm trong bộ nhớ (RAM) và đầu ra (kết quả tổng hợp) quay trở lại bộ nhớ (RAM) trong tình huống này.

Trước khi chương trình được thực thi, phiên bản dịch phải có trong bộ nhớ trước. Nhìn vào đoạn mã chương trình trước có thể thấy các lệnh không có chú thích tạo thành 19 10 = 13 16 byte. Vì vậy, chương trình sẽ lấy từ vị trí $0200 byte trong bộ nhớ đến các vị trí byte $0200 + $13 – $1 = $0212 (bắt đầu từ $0200 chứ không phải $0201 ngụ ý – $1). Việc thêm 6 byte cho số đầu vào và đầu ra sẽ làm cho tất cả chương trình kết thúc ở mức $0212 + $6 = $0218. Tổng thời lượng của chương trình là 19 16 = 25 10 .

Byte thấp hơn của phần mở rộng phải ở địa chỉ $0213 và byte cao hơn của cùng một phần mở rộng phải ở địa chỉ $0214 – độ bền nhỏ. Tương tự, byte thấp hơn của phần bổ sung phải ở địa chỉ $0215 và byte cao hơn của cùng phần bổ sung phải ở địa chỉ $0216 – độ bền nhỏ. Byte thấp hơn của kết quả (tổng) phải ở địa chỉ $0217 và byte cao hơn của cùng kết quả phải ở địa chỉ $0218 – độ cuối nhỏ.

Mã hoạt động 18 16 đối với CLC (địa chỉ ngụ ý) nằm ở vị trí byte là $0200. Mã hoạt động cho “LDA $0213”, tức là AD 16 đối với LDA (địa chỉ tuyệt đối), nằm ở vị trí byte là $0201. Byte thấp hơn của augend là 10111111 nằm ở vị trí byte bộ nhớ là $0213. Hãy nhớ rằng mỗi opcode chiếm một byte. Địa chỉ “$0213” của “LDA $0213” nằm ở vị trí byte của $0202 và $0203. Lệnh “LDA $0213” tải byte thấp hơn của phần mở rộng vào bộ tích lũy.

Mã hoạt động cho “ADC $0215”, tức là 6D 16 đối với ADC (địa chỉ tuyệt đối), nằm ở vị trí byte là $0204. Byte thấp hơn của phần bổ sung là 10010101 nằm ở vị trí byte là $0215. Địa chỉ “$0215” của “ADC $0215” nằm ở vị trí byte của $0205 và $0206. Lệnh “ADC $0215” thêm byte thấp hơn của phần bổ sung vào byte thấp hơn của phần bổ sung đã có trong bộ tích lũy. Kết quả được đặt trở lại trong bộ tích lũy. Bất kỳ số mang nào sau bit thứ tám sẽ được gửi đến cờ nhớ của thanh ghi trạng thái. Ô cờ mang không được xóa trước lần cộng thứ hai của byte cao hơn. Phần mang này được tự động thêm vào tổng của các byte cao hơn. Trên thực tế, số 0 được tự động thêm vào tổng các byte thấp hơn ngay từ đầu (tương đương với việc không thêm số mang nào) do CLC.

Bình luận chiếm 48 tiếp theo 10 = 30 16 byte. Tuy nhiên, điều này chỉ còn lại trong tệp văn bản “.asm”. Nó không đạt đến bộ nhớ. Nó bị loại bỏ bởi bản dịch được thực hiện bởi trình biên dịch chương trình (một chương trình).

Đối với lệnh tiếp theo là “STA $0217”, mã hoạt động của STA là 8D 16 (địa chỉ tuyệt đối) nằm ở vị trí byte $0207. Địa chỉ “$0217” của “STA $0217” nằm trong các vị trí bộ nhớ của $0208 và $0209. Lệnh “STA $0217” sao chép nội dung 8 bit của bộ tích lũy vào vị trí bộ nhớ là $0217.

Byte cao hơn của phần bổ sung là 00101010 nằm ở vị trí bộ nhớ là $0214 và byte cao hơn của phần bổ sung là 00101010 nằm ở vị trí byte là $02 16 . Mã hoạt động cho “LDA $0214” là AD16 cho LDA (địa chỉ tuyệt đối) nằm ở vị trí byte là $020A. Địa chỉ “$0214” của “LDA $0214” nằm ở vị trí $020B và $020C. Lệnh “LDA $0214” tải byte cao hơn của phần tăng thêm vào bộ tích lũy, xóa mọi thứ có trong bộ tích lũy.

Opcode cho “ADC $0216” là 6D 16 đối với ADC (địa chỉ tuyệt đối) nằm ở vị trí byte là $020D. Địa chỉ “$0216” của “ADC 0216” nằm ở vị trí byte của $020E và $020F. Lệnh “ADC $0216” thêm byte cao hơn của phần bổ sung vào byte cao hơn của phần bổ sung đã có trong bộ tích lũy. Kết quả được đặt trở lại vào bộ tích lũy. Nếu có số 1, thì đối với phép cộng thứ hai này, nó sẽ tự động được đặt vào ô nhớ của thanh ghi trạng thái. Mặc dù việc mang vượt quá bit thứ mười sáu (trái) là không bắt buộc đối với vấn đề này, nhưng thật tốt khi kiểm tra xem việc mang 1 có xảy ra hay không bằng cách kiểm tra xem cờ nhớ có trở thành 1 hay không.

Đối với lệnh tiếp theo và cuối cùng là “STA $0218”, mã hoạt động của STA là 8D16 (địa chỉ tuyệt đối) nằm ở vị trí byte là $0210. Địa chỉ “$0218” của “STA $0218” nằm trong các vị trí bộ nhớ của $0211 và $0212. Lệnh “STA $0218” sao chép nội dung 8 bit của bộ tích lũy vào vị trí bộ nhớ là $0218. Kết quả của phép cộng hai số 16 bit là 0101010101010100, với byte thấp hơn là 01010100 ở vị trí bộ nhớ là $0217 và byte cao hơn là 01010101 ở vị trí bộ nhớ là $0218 – độ bền nhỏ.

Phép trừ
Với 6502 µP, các số có dấu là số bù hai. Số bù hai có thể là tám bit, mười sáu bit hoặc bất kỳ bội số nào của tám bit. Với phần bù hai, bit đầu tiên từ bên trái là bit dấu. Đối với số dương, bit đầu tiên này là 0 để biểu thị dấu. Các bit còn lại tạo thành số theo cách thông thường. Để có được phần bù hai của một số âm, hãy đảo ngược tất cả các bit của số dương tương ứng, sau đó thêm 1 vào kết quả từ đầu bên phải.

Để trừ một số dương cho một số dương khác, số trừ được chuyển thành số âm bù hai. Sau đó, số trừ và số âm mới được cộng theo cách thông thường. Vì vậy, phép trừ 8 bit trở thành:

Trong đó số mang được giả định là 1. Kết quả trong bộ tích lũy là hiệu của phần bù hai. Vì vậy, để trừ hai số, cờ nhớ phải được đặt (thành 1).

Khi trừ hai số 16 bit, phép trừ được thực hiện hai lần giống như phép cộng hai số 16 bit. Vì phép trừ là một dạng phép cộng với 6502 µP, nên khi trừ hai số 16 bit, cờ nhớ chỉ được đặt một lần cho phép trừ đầu tiên. Đối với phép trừ thứ hai, mọi cài đặt của cờ nhớ đều được thực hiện tự động.

Lập trình phép trừ cho số tám bit hoặc số mười sáu bit được thực hiện tương tự như lập trình phép cộng. Tuy nhiên, cờ mang theo phải được đặt ngay từ đầu. Cách ghi nhớ để làm điều này là:

Phép trừ với số dương mười sáu bit
Xét phép trừ với các số sau:

Phép trừ này không liên quan đến phần bù hai. Vì phép trừ trong 6502 µP được thực hiện theo phần bù hai nên phép trừ trong cơ số hai được thực hiện như sau:

Kết quả phần bù của hai giống với kết quả thu được từ phép trừ thông thường. Tuy nhiên, lưu ý rằng số 1 ở vị trí bit thứ 17 tính từ bên phải sẽ bị bỏ qua. Phần trừ và phần trừ được chia thành hai bit số tám. Phần bù hai của 10010110 của byte thấp hơn của phần phụ được xác định độc lập với byte cao hơn của nó và với bất kỳ phần mang nào. Phần bù hai của 11101011 của byte cao hơn của phần phụ được xác định độc lập với byte thấp hơn của nó và với bất kỳ phần mang nào.

16 bit của số bị trừ đã ở dạng bù hai, bắt đầu bằng 0 từ bên trái. Vì vậy, nó không cần bất kỳ sự điều chỉnh nào về bit. Với 6502 µP, byte thấp hơn của số bị trừ mà không có bất kỳ sửa đổi nào sẽ được thêm vào byte dưới của phần bù hai của số bị trừ. Byte thấp hơn của số bị trừ không được chuyển đổi thành phần bù hai vì mười sáu bit của toàn bộ số bị trừ phải ở dạng phần bù hai (với 0 là bit đầu tiên ở bên trái). Trong lần bổ sung đầu tiên này, số 1 bắt buộc được thêm vào do lệnh 1=0 GIÂY.

Trong phép trừ hiệu quả hiện tại, có một số mang 1 (của phép cộng) từ bit thứ tám đến bit thứ chín (từ bên phải). Vì đây là phép trừ hiệu quả nên bất kỳ bit nào được cho là có trong cờ nhớ trong thanh ghi trạng thái đều được bổ sung (đảo ngược). Vì vậy, số 1 trở thành 0 trong cờ C. Trong thao tác thứ hai, byte cao hơn của số trừ được thêm vào byte bù hai cao hơn của số phụ. Bit cờ mang được bổ sung tự động của thanh ghi trạng thái (trong trường hợp này là 0) cũng được thêm vào (vào các byte cao hơn). Bất kỳ số 1 nào vượt quá bit thứ mười sáu tính từ bên phải đều bị bỏ qua.

Điều tiếp theo chỉ là mã hóa tất cả sơ đồ đó như sau:

GIÂY
LDA $0213
SBC $0215
; không xóa vì cần có giá trị cờ mang ngược
STA $0217
LDA $0214
SBC $0216
STA $0218

Hãy nhớ rằng với hợp ngữ 6502, dấu chấm phẩy bắt đầu một nhận xét không được đưa vào phiên bản chương trình đã dịch trong bộ nhớ. Hai số 16-bit dùng cho phép trừ chiếm 4 byte bộ nhớ với địa chỉ tuyệt đối; hai mỗi số (bộ nhớ là một chuỗi byte). Những đầu vào này không phải từ bàn phím. Kết quả tính tổng là hai byte và cũng phải được đặt trong bộ nhớ ở một nơi khác. Đầu ra này không đi tới màn hình hoặc máy in; nó đi vào bộ nhớ. Điều này mang lại tổng cộng 6 10 = 6 16 byte cho đầu vào và đầu ra được đặt trong bộ nhớ (RAM).

Trước khi một chương trình được thực thi, trước tiên nó phải ở trong bộ nhớ. Nhìn vào code chương trình có thể thấy các hướng dẫn không có chú thích tạo thành 19 10 = 13 16 byte. Vì tất cả các chương trình trong chương này đều bắt đầu từ vị trí bộ nhớ là $0200, nên chương trình sẽ lấy từ vị trí byte $0200 trong bộ nhớ đến vị trí byte $0200 + $13 – $1 = $0212 (bắt đầu từ $0200 chứ không phải $0201). Phạm vi này không bao gồm vùng cho byte đầu vào và đầu ra. Hai số đầu vào có dung lượng 4 byte và một số đầu ra có dung lượng 2 byte. Việc thêm 6 byte cho số đầu vào và đầu ra sẽ tạo ra phạm vi cho chương trình kết thúc ở mức $0212 + $6 = $0218. Tổng thời lượng của chương trình là 19 16 = 25 10 .

Byte thấp hơn của số bị trừ phải ở địa chỉ $0213 và byte cao hơn của cùng số bị trừ phải ở địa chỉ $0214 – độ cuối nhỏ. Tương tự, byte thấp hơn của địa chỉ con phải ở địa chỉ $0215 và byte cao hơn của cùng địa chỉ con đó phải ở địa chỉ $0216 – độ cuối nhỏ. Byte thấp hơn của kết quả (sự khác biệt) phải ở địa chỉ $0217 và byte cao hơn của cùng một kết quả phải ở địa chỉ $0218 – độ bền nhỏ.

Mã lệnh của 38 16 đối với SEC (địa chỉ ngụ ý) nằm ở địa chỉ $0200. Tất cả các chương trình trong chương này được giả định bắt đầu ở vị trí bộ nhớ $0200, hủy bỏ mọi chương trình lẽ ra đã có ở đó; ngoại trừ có quy định khác. Mã hoạt động cho “LDA $0213”, tức là AD 16 , đối với LDA (địa chỉ tuyệt đối) nằm ở vị trí byte $0201. Byte thấp hơn của số trừ là 10111111 nằm ở vị trí byte bộ nhớ là $0213. Hãy nhớ rằng mỗi opcode chiếm một byte. Địa chỉ “$0213” của “LDA $0213” nằm ở vị trí byte của $0202 và $0203. Lệnh “LDA $0213” tải byte thấp hơn của số trừ vào bộ tích lũy.

Mã hoạt động cho “SBC $0215”, tức là ED 16 , đối với SBC (địa chỉ tuyệt đối) nằm ở vị trí $0204 byte. Byte thấp hơn của phần phụ là 01101010 nằm ở vị trí byte $0215. Địa chỉ “$0215” của “ADC $0215” nằm ở vị trí byte của $0205 và $0206. Lệnh “SBC $0215” trừ byte thấp hơn của phần trừ khỏi byte thấp hơn của phần trừ đã có trong bộ tích lũy. Đây là phép trừ bù hai. Kết quả được đặt trở lại trong bộ tích lũy. Phần bù (đảo ngược) của bất kỳ số mang nào sau bit thứ tám được gửi đến cờ nhớ của thanh ghi trạng thái. Cờ mang này không được xóa trước phép trừ thứ hai với byte cao hơn. Việc mang này được tự động thêm vào phép trừ các byte cao hơn.

Bình luận chiếm 57 tiếp theo 10 = 3916 16 byte. Tuy nhiên, điều này chỉ còn lại trong tệp văn bản “.asm”. Nó không đạt đến bộ nhớ. Nó bị loại bỏ bởi bản dịch được thực hiện bởi trình biên dịch chương trình (một chương trình).

Đối với lệnh tiếp theo là “STA $0217”, mã hoạt động của STA, tức là 8D 16 (địa chỉ tuyệt đối), nằm ở vị trí byte $0207. Địa chỉ “$0217” của “STA $0217” nằm trong các vị trí bộ nhớ của $0208 và $0209. Lệnh “STA $0217” sao chép nội dung 8 bit của bộ tích lũy vào vị trí bộ nhớ là $0217.

Byte cao hơn của phần phụ là 00101010 nằm ở vị trí bộ nhớ là $0214 và byte cao hơn của phần phụ là 00010101 nằm ở vị trí byte là $0216. Mã hoạt động cho “LDA $0214”, tức là AD 16 đối với LDA (địa chỉ tuyệt đối), nằm ở vị trí byte $020A. Địa chỉ “$0214” của “LDA $0214” nằm ở vị trí $020B và $020C. Lệnh “LDA $0214” tải byte cao hơn của số trừ vào bộ tích lũy, xóa mọi thứ có trong bộ tích lũy.

Mã hoạt động cho “SBC $0216”, tức là ED 16 đối với SBC (địa chỉ tuyệt đối), nằm ở vị trí byte $020D. Địa chỉ “$0216” của “SBC $0216” nằm ở vị trí byte của $020E và $020F. Lệnh “SBC $0216” trừ byte cao hơn của phần trừ khỏi byte cao hơn của phần trừ (phần bù hai) đã có trong bộ tích lũy. Kết quả được đặt trở lại vào bộ tích lũy. Nếu có giá trị mang bằng 1 cho phép trừ thứ hai này, phần bù của nó sẽ tự động được đặt trong ô mang của thanh ghi trạng thái. Mặc dù việc mang vượt quá bit thứ mười sáu (trái) là không cần thiết cho vấn đề này, nhưng thật tốt khi kiểm tra xem việc mang phần bổ sung có xảy ra hay không bằng cách kiểm tra cờ mang.

Đối với lệnh tiếp theo và cuối cùng là “STA $0218”, mã hoạt động của STA, tức là 8D 16 (địa chỉ tuyệt đối), nằm ở vị trí byte $0210. Địa chỉ “$0218” của “STA $0218” nằm trong các vị trí bộ nhớ của $0211 và $0212. Lệnh “STA $0218” sao chép nội dung 8 bit của bộ tích lũy vào vị trí bộ nhớ là $0218. Kết quả của phép trừ với hai số mười sáu bit là 0001010101010101 với byte thấp hơn là 01010101 ở vị trí bộ nhớ là $0217 và byte cao hơn là 00010101 ở vị trí bộ nhớ là $0218 – độ bền nhỏ.

6502 µP chỉ có mạch điện để cộng và gián tiếp cho phép trừ phần bù của cả hai. Nó không có mạch để nhân và chia. Để thực hiện phép nhân và chia, cần phải viết một chương trình hợp ngữ với các chi tiết, bao gồm cả việc dịch chuyển từng phần tích và một phần phần bị chia.

4.4 Hoạt động logic

Trong 6502 µP, từ gợi nhớ cho OR là ORA và từ gợi nhớ cho OR độc quyền là EOR. Lưu ý rằng các phép toán logic không có địa chỉ ngụ ý. Địa chỉ ngụ ý không có toán hạng. Mỗi toán tử logic phải có hai toán hạng. Cái đầu tiên nằm trong bộ tích lũy và cái thứ hai nằm trong bộ nhớ hoặc trong lệnh. Kết quả (8 bit) được đưa trở lại bộ tích lũy. Dữ liệu đầu tiên trong bộ tích lũy được đặt ở đó bằng lệnh ngay lập tức hoặc được sao chép từ bộ nhớ với địa chỉ tuyệt đối. Trong phần này, chỉ sử dụng địa chỉ trang 0 để minh họa. Các toán tử logic này đều là toán tử Bitwise.


Bảng sau minh họa Bitwise AND ở dạng nhị phân, thập lục phân và thập phân:

Tất cả các chương trình trong chương này sẽ bắt đầu ở vị trí byte bộ nhớ là $0200. Tuy nhiên, các chương trình trong phần này nằm ở trang 0, nhằm mục đích minh họa việc sử dụng trang 0 mà không có byte cao hơn 00000000 2 . ANDing trước đó có thể được mã hóa như sau:

LDA #$9A ; không phải từ bộ nhớ – địa chỉ ngay lập tức
VÀ #$CD ; không phải từ bộ nhớ – địa chỉ ngay lập tức
STA $30 ; lưu trữ $88 ở mức $0030 dựa trên số không

HOẶC
Bảng sau minh họa Bitwise OR ở dạng nhị phân, thập lục phân và thập phân:

LDA #$9A ; không phải từ bộ nhớ – địa chỉ ngay lập tức
ORA #$CD ; không phải từ bộ nhớ – địa chỉ ngay lập tức
STA $30 ; lưu trữ $CF ở mức giá gốc $0030

MIỄN PHÍ
Bảng sau minh họa Bitwise XOR ở dạng nhị phân, thập lục phân và thập phân:

LDA #$9A ; không phải từ bộ nhớ – địa chỉ ngay lập tức
EOR #$CD ; không phải từ bộ nhớ – địa chỉ ngay lập tức
STA $30 ; lưu trữ $57 ở mức $0030 dựa trên số không

4.5 Thao tác dịch chuyển và xoay

Các thuật nhớ và mã opcode cho các toán tử dịch chuyển và xoay là:

ASL: Dịch chuyển sang trái một bit của bộ tích lũy hoặc vị trí bộ nhớ, chèn số 0 vào ô ngoài cùng bên phải còn trống.

LSR: Dịch sang phải một bit của bộ tích lũy hoặc vị trí bộ nhớ, chèn số 0 vào ô ngoài cùng bên trái còn trống.
ROL: Xoay một bit sang trái của bộ tích lũy hoặc vị trí bộ nhớ, chèn bit bị bỏ ở bên trái vào ô ngoài cùng bên phải còn trống.
ROR: Xoay một bit sang phải của bộ tích lũy hoặc vị trí bộ nhớ, chèn bit bị bỏ ở bên phải vào ô ngoài cùng bên trái còn trống.

Để thực hiện dịch chuyển hoặc xoay bằng bộ tích lũy, hướng dẫn như sau:

LSR A

Điều này sử dụng một chế độ địa chỉ khác gọi là chế độ địa chỉ tích lũy.

Để thực hiện dịch chuyển hoặc xoay với vị trí bộ nhớ byte, hướng dẫn sẽ giống như sau:

ROR $2BCD

Trong đó 2BCD là vị trí bộ nhớ.

Lưu ý rằng không có chế độ địa chỉ ngay lập tức hoặc ngụ ý cho việc dịch chuyển hoặc xoay. Không có chế độ đánh địa chỉ ngay lập tức vì không có ích gì khi dịch chuyển hoặc xoay một số chỉ còn lại trong lệnh. Không có chế độ địa chỉ ngụ ý vì các nhà thiết kế của 6502 µP chỉ muốn nội dung của bộ tích lũy (thanh ghi A) hoặc vị trí byte bộ nhớ được dịch chuyển hoặc xoay.

4.6 Chế độ đánh địa chỉ tương đối

Bộ vi xử lý luôn tăng (1, 2 hoặc 3 đơn vị) Bộ đếm chương trình (PC) để trỏ đến lệnh tiếp theo sẽ được thực thi. 6502 µP có một lệnh có ký hiệu là BVS, nghĩa là Nhánh trên Tập tràn. PC bao gồm hai byte. Lệnh này làm cho PC có một địa chỉ bộ nhớ khác để lệnh tiếp theo được thực thi mà không phải do mức tăng bình thường. Nó làm như vậy bằng cách cộng hoặc trừ một giá trị, được gọi là giá trị offset, đối với nội dung của PC. Và do đó, PC sẽ trỏ đến một vị trí bộ nhớ (được phân nhánh) khác để máy tính tiếp tục thực thi từ đó. Phần bù là một số nguyên từ -128 10 đến +127 10 (bù hai). Vì vậy, phần bù có thể làm cho bước nhảy tiếp tục trong bộ nhớ. Nếu nó là dương hoặc ở phía sau trong bộ nhớ, hoặc nếu nó là âm.

Lệnh BVS chỉ lấy một toán hạng là offset. BVS sử dụng địa chỉ tương đối. Hãy xem xét hướng dẫn sau:

BVS $7F

Trong cơ sở hai, 7F H là 01111111 2 = 127 10 . Giả sử rằng nội dung trong PC cho lệnh tiếp theo là $0300. Lệnh BVS làm cho $7F (một số dương đã có trong phần bù hai) được thêm vào $0300 để tạo ra $037F. Vì vậy, thay vì lệnh tiếp theo được thực thi tại vị trí bộ nhớ $0300, nó lại ở vị trí bộ nhớ $037F (chênh lệch khoảng một nửa trang).

Có những hướng dẫn nhánh khác, nhưng BVS là một hướng dẫn rất tốt để sử dụng để minh họa cách đánh địa chỉ tương đối. Địa chỉ tương đối xử lý các lệnh nhánh.

4.7 Địa chỉ được lập chỉ mục và Địa chỉ gián tiếp riêng biệt

Các chế độ địa chỉ này cho phép 6502 µP xử lý lượng dữ liệu khổng lồ trong khoảng thời gian ngắn với số lượng lệnh giảm. Có các vị trí 64KB cho toàn bộ bộ nhớ Comodore-64. Vì vậy, để truy cập bất kỳ vị trí byte nào, gồm 16 bit, cần tạo hai byte. Ngoại lệ duy nhất đối với việc cần hai byte là đối với trang 0, trong đó byte cao hơn $00 được bỏ qua để tiết kiệm không gian được chiếm bởi lệnh trong bộ nhớ. Với chế độ đánh địa chỉ không phải số trang, cả byte cao hơn và byte thấp hơn của địa chỉ bộ nhớ 16 bit hầu hết đều được biểu thị bằng cách nào đó.

Địa chỉ được lập chỉ mục cơ bản

Địa chỉ chỉ mục tuyệt đối
Hãy nhớ rằng thanh ghi X hoặc Y được gọi là thanh ghi chỉ mục. Hãy xem xét hướng dẫn sau:

LDA $C453,X

Giả sử rằng giá trị của 6 H nằm trong thanh ghi X. Lưu ý rằng 6 không được gõ vào bất cứ đâu trong hướng dẫn. Lệnh này thêm giá trị của 6H vào C453 H là một phần của lệnh đã gõ trong tệp văn bản vẫn đang được tập hợp – C453 H + 6 H = C459 H . LDA có nghĩa là tải một byte vào bộ tích lũy. Byte được tải vào bộ tích lũy đến từ địa chỉ $C459. $C459 là tổng của $C453 được gõ theo lệnh và 6 H được tìm thấy trong thanh ghi X trở thành địa chỉ hiệu quả mà byte được tải vào bộ tích lũy bắt nguồn từ đó. Nếu 6 H nằm trong thanh ghi Y, Y được nhập vào vị trí của X trong lệnh.

Trong câu lệnh lệnh được gõ, $C453 được coi là địa chỉ cơ sở và số 6 H trong thanh ghi X hoặc Y được gọi là phần đếm hoặc chỉ mục cho địa chỉ hiệu dụng. Địa chỉ cơ sở có thể tham chiếu đến bất kỳ địa chỉ byte nào trong bộ nhớ và 256 địa chỉ tiếp theo 10 có thể truy cập các địa chỉ, giả sử rằng chỉ mục (hoặc số đếm) bắt đầu trong thanh ghi X hoặc Y là 0. Hãy nhớ rằng một byte có thể cung cấp phạm vi liên tục lên tới 256 10 số (tức là 00000000 2 tới 11111111 2 ).

Vì vậy, địa chỉ tuyệt đối sẽ thêm bất cứ thứ gì đã được đặt (đã được đặt bởi lệnh khác) vào thanh ghi X hoặc Y vào 16 địa chỉ được gõ cùng với lệnh để có được địa chỉ hiệu quả. Trong lệnh được gõ, hai thanh ghi chỉ mục được phân biệt bằng X hoặc Y được gõ sau dấu phẩy. X hoặc Y được gõ; không phải cả hai.

Sau khi tất cả chương trình được nhập vào trình soạn thảo văn bản và được lưu với tên tệp mở rộng “.asm”, trình biên dịch chương trình, là một chương trình khác, phải dịch chương trình đã nhập sang nội dung được (được tải) trong bộ nhớ. Lệnh trước đó là “LDA $C453,X”, chiếm ba vị trí byte trong bộ nhớ chứ không phải năm.

Hãy nhớ rằng một thuật nhớ như LDA có thể có nhiều hơn một opcode (các byte khác nhau). Opcode của lệnh sử dụng thanh ghi X khác với opcode sử dụng thanh ghi Y. Trình biên dịch mã biết nên sử dụng mã opcode nào dựa trên lệnh đã nhập. Mã hoạt động một byte cho “LDA $C453,X” khác với mã hoạt động một byte cho “LDA $C453,Y”. Trên thực tế, mã hoạt động cho LDA trong “LDA $C453,X” là BD và mã hoạt động cho LDA trong “LDA $C453,9” là BD.

Nếu opcode cho LDA nằm ở vị trí $0200 byte. Sau đó, địa chỉ 16-bit của $C453 lấy vị trí tiếp theo của byte trong bộ nhớ là $0201 và $0202. Byte opcode cụ thể cho biết đó là thanh ghi X hay thanh ghi Y có liên quan. Và do đó, lệnh ngôn ngữ được tổng hợp là “LDA $C453,X” hoặc “LDA $C453,Y” chiếm ba byte liên tiếp trong bộ nhớ chứ không phải bốn hoặc năm byte.

Địa chỉ được lập chỉ mục không trang
Địa chỉ chỉ mục trang 0 giống như địa chỉ chỉ mục tuyệt đối đã được mô tả trước đó, nhưng byte đích chỉ phải ở trên trang 0 (từ $0000 đến $00FF). Bây giờ, khi xử lý trang số 0, byte cao hơn luôn là 00 H đối với các vị trí bộ nhớ thường được tránh. Vì vậy, người ta thường đề cập rằng trang 0 bắt đầu từ $00 đến FF. Và như vậy, hướng dẫn trước đó của “LDA $C453,X” là:

LDA $53,X

$C4, một byte cao hơn đề cập đến một trang phía trên trang 0, không thể được sử dụng trong lệnh này vì nó đặt byte mục tiêu dự kiến ​​sẽ được tải vào byte tích lũy bên ngoài và phía trên trang 0.

Khi giá trị được gõ trong lệnh được thêm vào giá trị trong thanh ghi chỉ mục, tổng sẽ không cho kết quả cao hơn trang 0 (FF H ). Vì vậy, không thể có lệnh như “LDA $FF, X” và giá trị như FF H trong thanh ghi chỉ mục vì FF H +FF H = 200 H là vị trí byte đầu tiên ($0200) của trang 2 (trang thứ ba) trong bộ nhớ, cách trang 0 rất xa. Vì vậy, với địa chỉ được lập chỉ mục trang 0, địa chỉ hiệu quả phải nằm ở trang 0.

Địa chỉ gián tiếp

Chuyển địa chỉ tuyệt đối
Trước khi thảo luận về Địa chỉ gián tiếp tuyệt đối, trước tiên bạn nên xem xét địa chỉ tuyệt đối của JMP. Giả sử rằng địa chỉ có giá trị quan tâm (byte mục tiêu) là $8765. Đây là 16 bit bao gồm hai byte: byte cao hơn là 87 H và byte thấp hơn là 65 H . Vì vậy, hai byte trị giá $8765 được đặt vào PC (bộ đếm chương trình) cho lệnh tiếp theo. Những gì được gõ trong chương trình (tệp) hợp ngữ là:

JMP $8765

Chương trình thực thi trong bộ nhớ sẽ nhảy từ bất kỳ địa chỉ nào mà nó truy cập tới $8765. Bộ ghi nhớ JMP có ba mã opcode là 4C, 6C và 7C. Opcode cho địa chỉ tuyệt đối này là 4C. Mã hoạt động cho địa chỉ gián tiếp tuyệt đối của JMP là 6C (tham khảo các hình minh họa sau).

Địa chỉ gián tiếp tuyệt đối
Điều này chỉ được sử dụng với lệnh nhảy (JMP). Giả sử rằng địa chỉ có byte quan tâm (byte mục tiêu) là $8765. Đây là 16 bit bao gồm hai byte: byte cao hơn là 87 H và byte thấp hơn là 65 H . Với địa chỉ gián tiếp tuyệt đối, hai byte này thực sự nằm ở hai vị trí byte liên tiếp ở nơi khác trong bộ nhớ.

Giả sử rằng chúng nằm ở vị trí bộ nhớ của $0210 và $0211. Sau đó, byte thấp hơn của địa chỉ quan tâm là 65 H ở địa chỉ $0210 và byte cao hơn là 87 H ở địa chỉ $0211. Điều đó có nghĩa là byte bộ nhớ quan tâm thấp hơn sẽ chuyển đến địa chỉ liên tiếp thấp hơn và byte bộ nhớ quan tâm cao hơn sẽ chuyển đến địa chỉ liên tiếp cao hơn - độ bền nhỏ.

Địa chỉ 16 bit có thể đề cập đến hai địa chỉ liên tiếp trong bộ nhớ. Trong trường hợp đó, địa chỉ $0210 đề cập đến địa chỉ của $0210 và $0211. Cặp địa chỉ $0210 và $0211 giữ địa chỉ cuối cùng (16 bit của hai byte) của byte mục tiêu, với byte thấp hơn là 65 H bằng $0210 và byte cao hơn là 87 H bằng $0211. Vì vậy, lệnh nhảy được gõ là:

JMP ($0210)

Bộ ghi nhớ JMP có ba mã opcode là 4C, 6C và 7C. Opcode cho địa chỉ gián tiếp tuyệt đối là 6C. Nội dung được nhập vào tệp văn bản là “JMP ($0210)”. Do có dấu ngoặc đơn nên trình biên dịch (trình biên dịch) sử dụng mã hoạt động 6C cho JMP chứ không phải 4C hay 7C.

Với địa chỉ gián tiếp tuyệt đối, thực tế có ba vùng bộ nhớ. Vùng đầu tiên có thể bao gồm các vị trí byte $0200, $0201 và $0202. Lệnh này có ba byte cho lệnh “JMP ($0210)”. Vùng thứ hai, không nhất thiết phải nằm cạnh vùng thứ nhất, bao gồm hai vị trí byte liên tiếp là $0210 và $0211. Byte thấp hơn ở đây ($0210) được nhập vào lệnh chương trình hợp ngữ. Nếu địa chỉ quan tâm là $8765 thì byte thấp hơn là 65 H nằm ở vị trí byte $0210 và byte cao hơn là 87 H nằm ở vị trí $0211 byte. Vùng thứ ba chỉ bao gồm một vị trí byte. Nó có địa chỉ $8765 cho byte được nhắm mục tiêu (byte quan tâm cuối cùng). Cặp địa chỉ liên tiếp $0210 và $0211 chứa con trỏ $8765 là địa chỉ quan tâm. Sau khi diễn giải tính toán, số tiền $8765 được đưa vào PC (Bộ đếm chương trình) để truy cập byte mục tiêu.

Địa chỉ gián tiếp trang Zero
Địa chỉ này giống như địa chỉ gián tiếp tuyệt đối, nhưng con trỏ phải ở trang 0. Địa chỉ byte thấp hơn của vùng con trỏ là địa chỉ trong lệnh được gõ như sau:

JMP ($50)

Byte cao hơn của con trỏ nằm ở vị trí byte $51. Địa chỉ hiệu quả (nhọn) không nhất thiết phải ở trang 0.

Vì vậy, với việc đánh địa chỉ chỉ mục, giá trị trong thanh ghi chỉ mục sẽ được thêm vào địa chỉ cơ sở được đưa ra trong lệnh để có địa chỉ hiệu quả. Địa chỉ gián tiếp sử dụng một con trỏ.

4.8 Địa chỉ gián tiếp được lập chỉ mục

Địa chỉ gián tiếp được lập chỉ mục tuyệt đối
Chế độ đánh địa chỉ này chỉ được sử dụng với lệnh JMP.
Với địa chỉ gián tiếp tuyệt đối, có giá trị nhọn (byte) với hai địa chỉ byte liên tiếp của chính nó. Hai địa chỉ liên tiếp này tạo thành con trỏ nằm trong vùng con trỏ của hai byte liên tiếp trong bộ nhớ. Byte thấp hơn của vùng con trỏ là byte được gõ trong lệnh trong ngoặc đơn. Con trỏ là địa chỉ của giá trị được trỏ. Trong tình huống trước, $8765 là địa chỉ của giá trị nhọn. $0210 (theo sau là $0211) là địa chỉ có nội dung là $8765, là con trỏ. Với chế độ đánh địa chỉ gián tiếp tuyệt đối, nó ($0210) được nhập vào chương trình (tệp văn bản), bao gồm cả dấu ngoặc đơn.

Mặt khác, với Chế độ đánh địa chỉ gián tiếp được lập chỉ mục tuyệt đối, byte địa chỉ thấp hơn cho vùng con trỏ được hình thành bằng cách thêm giá trị trong thanh ghi X vào địa chỉ đã nhập. Ví dụ: nếu con trỏ ở vị trí địa chỉ $0210, lệnh được nhập có thể giống như sau:

JMP ($020A,X)

Trong đó thanh ghi X có giá trị là 6 H . 020A H + 6 H = 0210 H . Thanh ghi Y không được sử dụng với chế độ đánh địa chỉ này.

Địa chỉ gián tiếp được lập chỉ mục trang không
Chế độ đánh địa chỉ này sử dụng thanh ghi X chứ không phải thanh ghi Y. Với chế độ đánh địa chỉ này, vẫn có giá trị nhọn và con trỏ trong vùng con trỏ địa chỉ hai byte của nó. Phải có hai byte liên tiếp trong trang 0 cho con trỏ. Địa chỉ được gõ trong lệnh là địa chỉ một byte. Giá trị này được thêm vào giá trị trong thanh ghi X và mọi giá trị mang sẽ bị loại bỏ. Kết quả trỏ đến vùng con trỏ trong trang 0. Ví dụ: nếu địa chỉ quan tâm (nhọn) là $8765 và nó nằm ở vị trí byte của $50 và $51 của trang 0 và giá trị trong thanh ghi X là $30, thì hướng dẫn đánh máy là như thế này:

LDA ($20,X)

Vì 20 USD + 30 USD = 50 USD.

Địa chỉ được lập chỉ mục gián tiếp
Chế độ đánh địa chỉ này sử dụng thanh ghi Y chứ không phải thanh ghi X. Với chế độ đánh địa chỉ này, vẫn có giá trị nhọn và vùng con trỏ nhưng nội dung của vùng con trỏ hoạt động khác nhau. Phải có hai byte liên tiếp trong trang 0 cho vùng con trỏ. Địa chỉ thấp hơn của vùng con trỏ được gõ vào lệnh. Số (cặp byte) này được chứa trong vùng con trỏ được thêm vào giá trị trong thanh ghi Y để có con trỏ thực. Ví dụ: đặt địa chỉ quan tâm (nhọn) là $8765, giá trị 6H nằm trong thanh ghi Y và số (hai byte) ở địa chỉ 50 H và 51 H . Hai byte cộng lại là $875F vì $875F + $6 = $8765. Hướng dẫn được gõ giống như thế này:

LDA ($50),Y

4.9 Hướng dẫn tăng, giảm và kiểm tra BIT

Bảng sau đây trình bày các thao tác của lệnh tăng và giảm:

INA và DEA lần lượt tăng và giảm bộ tích lũy. Đó được gọi là địa chỉ tích lũy. INX, DEX, INY và DEY lần lượt dành cho các thanh ghi X và Y. Họ không lấy bất kỳ toán hạng nào. Vì vậy, họ sử dụng chế độ địa chỉ ngụ ý. Tăng có nghĩa là thêm 1 vào thanh ghi hoặc byte bộ nhớ. Giảm có nghĩa là trừ đi 1 từ thanh ghi hoặc byte bộ nhớ.

INC và DEC lần lượt tăng và giảm một byte bộ nhớ (chứ không phải một thanh ghi). Việc sử dụng địa chỉ trang 0 thay vì địa chỉ tuyệt đối là để tiết kiệm bộ nhớ cho lệnh. Địa chỉ trang 0 nhỏ hơn một byte so với địa chỉ tuyệt đối của lệnh trong bộ nhớ. Tuy nhiên, chế độ đánh địa chỉ trang 0 chỉ ảnh hưởng đến trang 0.

Lệnh BIT kiểm tra các bit của một byte trong bộ nhớ với 8 bit trong bộ tích lũy, nhưng không thay đổi gì cả. Chỉ một số cờ của Thanh ghi trạng thái bộ xử lý “P” được đặt. Các bit của vị trí bộ nhớ đã chỉ định được AND logic với các bit của bộ tích lũy. Sau đó, các bit trạng thái sau được đặt:

  • N là bit 7 và bit cuối cùng (trái) của thanh ghi trạng thái, nhận bit 7 của vị trí bộ nhớ trước ANDing.
  • V là bit 6 của thanh ghi trạng thái nhận bit 6 của vị trí bộ nhớ trước ANDing.
  • Cờ Z của thanh ghi trạng thái được đặt (làm 1) nếu kết quả của AND bằng 0 (00000000 2 ). Ngược lại, nó sẽ bị xóa (làm 0).

4.10 Hướng dẫn so sánh

Cách ghi nhớ lệnh so sánh cho 6502 µP là CMP, CPX và CPY. Sau mỗi lần so sánh, các cờ N, Z và C của thanh ghi trạng thái bộ xử lý “P” bị ảnh hưởng. Cờ N được đặt (làm 1) khi kết quả là số âm. Cờ Z được đặt (làm 1) khi kết quả bằng 0 (000000002). Cờ C được đặt (tạo thành 1) khi có bit nhớ từ bit thứ 8 đến bit thứ 9. Bảng sau đây minh họa chi tiết

Có nghĩa là “lớn hơn”. Cùng với đó, bảng so sánh sẽ tự giải thích.

4.11 Hướng dẫn nhảy và rẽ nhánh

Bảng sau đây tóm tắt các lệnh nhảy và rẽ nhánh:

Lệnh JMP sử dụng địa chỉ tuyệt đối và gián tiếp. Các lệnh còn lại trong bảng là các lệnh rẽ nhánh. Họ chỉ sử dụng địa chỉ tương đối với 6502 µP. Cùng với đó, bảng sẽ trở nên dễ hiểu nếu nó được đọc từ trái sang phải và từ trên xuống dưới.

Lưu ý rằng các nhánh chỉ có thể được áp dụng cho các địa chỉ trong phạm vi -128 đến +127 byte tính từ địa chỉ đã cho. Đây là địa chỉ tương đối. Đối với cả lệnh JMP và lệnh nhánh, Bộ đếm chương trình (PC) bị ảnh hưởng trực tiếp. 6502 µP không cho phép các nhánh có địa chỉ tuyệt đối, mặc dù bước nhảy có thể thực hiện địa chỉ tuyệt đối. Lệnh JMP không phải là lệnh rẽ nhánh.

Ghi chú: Địa chỉ tương đối chỉ được sử dụng với các lệnh nhánh.

4.12 Khu vực ngăn xếp

Chương trình con giống như một trong những chương trình ngắn trước đó để cộng hoặc trừ hai số. Vùng ngăn xếp trong bộ nhớ bắt đầu từ $0100 đến $01FF. Khu vực này được gọi đơn giản là ngăn xếp. Khi bộ vi xử lý thực hiện bước nhảy tới lệnh chương trình con (JSR – hãy tham khảo phần thảo luận sau), nó cần biết nơi để quay lại khi kết thúc. 6502 µP giữ thông tin này (địa chỉ trả về) trong bộ nhớ thấp từ $0100 đến $01FF (vùng ngăn xếp) và sử dụng nội dung thanh ghi con trỏ ngăn xếp là “S” trong bộ vi xử lý làm con trỏ (9 bit) đến địa chỉ được trả về cuối cùng được lưu trữ trong trang 1 ($0100 đến $01FF) của bộ nhớ. Ngăn xếp tăng dần từ $01FF và cho phép lồng các chương trình con sâu tới 128 cấp.

Một cách sử dụng khác của con trỏ ngăn xếp là xử lý các ngắt. 6502 µP có các chân được dán nhãn là IRQ và NMI. Có thể một số tín hiệu điện nhỏ được đưa vào các chân này và khiến 6502 µP ngừng thực hiện một chương trình và khiến nó bắt đầu thực hiện một chương trình khác. Trong trường hợp này, chương trình đầu tiên bị gián đoạn. Giống như các chương trình con, các đoạn mã ngắt có thể được lồng vào nhau. Xử lý ngắt sẽ được thảo luận trong chương tiếp theo.

Ghi chú : Con trỏ ngăn xếp có 8 bit dành cho địa chỉ byte thấp hơn trong việc đánh địa chỉ các vị trí từ $0100 đến $01FF. Byte cao hơn của 00000001 2 được giả định.

Bảng sau đưa ra các hướng dẫn liên quan đến con trỏ ngăn xếp “S” với các thanh ghi A, X, Y và P với vùng ngăn xếp trong bộ nhớ:

4.13 Gọi và quay lại chương trình con

Một chương trình con là một tập hợp các hướng dẫn nhằm đạt được một mục tiêu cụ thể. Chương trình cộng hoặc trừ trước đó là một chương trình con rất ngắn. Các chương trình con đôi khi chỉ được gọi là các chương trình thường trình. Lệnh gọi một chương trình con là:

JSR: Chuyển tới chương trình con

Lệnh quay về từ một chương trình con là:

RTS : Quay lại từ chương trình con

Bộ vi xử lý có xu hướng thực hiện liên tục các lệnh trong bộ nhớ, lần lượt từng lệnh. Giả sử rằng bộ vi xử lý hiện đang thực thi một đoạn mã và nó gặp lệnh nhảy (JMP) để thực thi một đoạn mã được mã hóa phía sau mà nó có thể đã được thực thi. Nó thực thi đoạn mã phía sau đó và tiếp tục thực thi tất cả các đoạn mã (hướng dẫn) theo đoạn mã phía sau, cho đến khi nó thực thi lại đoạn mã hiện tại và tiếp tục bên dưới. JMP không đẩy lệnh tiếp theo vào ngăn xếp.

Không giống như JMP, JSR đẩy địa chỉ của lệnh tiếp theo sau chính nó từ PC (bộ đếm chương trình) vào ngăn xếp. Vị trí ngăn xếp của địa chỉ này được đặt trong con trỏ ngăn xếp “S”. Khi gặp một lệnh RTS (được thực thi) trong chương trình con, địa chỉ được đẩy lên ngăn xếp sẽ kéo ra khỏi ngăn xếp và chương trình sẽ tiếp tục tại địa chỉ được kéo ra đó là địa chỉ lệnh tiếp theo ngay trước lệnh gọi chương trình con. Địa chỉ cuối cùng được lấy ra khỏi ngăn xếp sẽ được gửi tới bộ đếm chương trình. Bảng sau đây cung cấp chi tiết kỹ thuật của các lệnh JSR và RTS:

Xem hình minh họa sau đây để biết cách sử dụng JSR và RTS:

4.14 Ví dụ về vòng lặp đếm ngược

Chương trình con sau đây đếm ngược từ $FF đến $00 (tổng cộng 256 10 tính):

bắt đầu LDX #$FF ; tải X với $FF = 255
vòng DEX; X = X – 1
vòng BNE; nếu X khác 0 thì vòng lặp goto
RTS; trở lại

Mỗi dòng có một bình luận. Bình luận không bao giờ được đưa vào bộ nhớ để thực thi. Trình biên dịch (trình dịch) chuyển đổi một chương trình thành chương trình có trong bộ nhớ để thực thi (đang chạy) luôn loại bỏ các nhận xét. Một bình luận bắt đầu bằng “;” . Phần “bắt đầu” và “vòng lặp” trong chương trình này được gọi là nhãn. Nhãn xác định (tên) cho địa chỉ của lệnh. Nếu lệnh là lệnh một byte (địa chỉ ngầm định), nhãn là địa chỉ của lệnh đó. Nếu lệnh là lệnh nhiều byte, nhãn sẽ xác định byte đầu tiên cho lệnh nhiều byte. Lệnh đầu tiên của chương trình này bao gồm hai byte. Giả sử rằng nó bắt đầu ở địa chỉ $0300, địa chỉ $0300 có thể được thay thế bằng địa chỉ “bắt đầu” trong chương trình. Lệnh thứ hai (DEX) là một lệnh byte đơn và phải có địa chỉ $0302. Điều này có nghĩa là địa chỉ $0302 có thể được thay thế bằng “vòng lặp”, xuống trong chương trình, thực tế là như vậy trong “vòng lặp BNE”.

“Vòng lặp BNE” có nghĩa là nhánh đến địa chỉ đã cho khi cờ Z của thanh ghi trạng thái là 0. Khi giá trị trong thanh ghi A hoặc X hoặc Y là 00000000 2 , do thao tác cuối cùng, cờ Z là 1 (đã đặt). Vì vậy, mặc dù nó là 0 (không phải 1), lệnh thứ hai và thứ ba trong chương trình được lặp lại theo thứ tự đó. Trong mỗi chuỗi lặp lại, giá trị (số nguyên) trong thanh ghi X giảm đi 1. DEX có nghĩa là X = X – 1. Khi giá trị trong thanh ghi X là $00 = 00000000 2 , Z trở thành 1. Tại thời điểm đó, hai lệnh không còn lặp lại nữa. Lệnh RTS cuối cùng trong chương trình, là lệnh một byte (địa chỉ ngụ ý), trả về từ chương trình con. Tác dụng của lệnh này là tạo địa chỉ bộ đếm chương trình trong ngăn xếp cho mã được thực thi trước lệnh gọi chương trình con và quay trở lại bộ đếm chương trình (PC). Địa chỉ này là địa chỉ của lệnh sẽ được thực thi trước khi chương trình con được gọi.

Ghi chú: Khi viết chương trình hợp ngữ cho 6502 µP, chỉ có nhãn phải bắt đầu ở đầu dòng; bất kỳ mã dòng nào khác phải được dịch chuyển ít nhất một khoảng trắng sang phải.

Gọi một chương trình con
Bỏ qua không gian bộ nhớ được chiếm bởi các nhãn trước đó, chương trình sẽ lấy 6 byte vị trí liên tiếp trong bộ nhớ (RAM) từ $0300 đến $0305. Trong trường hợp này, chương trình là:

LDX #$FF ; tải X với $FF = 255
DEX ; X = X – 1
BNE $0302 ; nếu X khác 0 thì vòng lặp goto
RTS; trở lại

Bắt đầu từ địa chỉ $0200 trong bộ nhớ có thể gọi chương trình con. Hướng dẫn gọi là:

JSR bắt đầu; địa chỉ bắt đầu là $0300, tức là JSR $0300

Chương trình con và lệnh gọi của nó được ghi chính xác trong tệp soạn thảo văn bản là:

bắt đầu LDX #$FF; tải X với $FF = 255
vòng DEX; X = X – 1

vòng BNE; nếu X khác 0 thì vòng lặp goto
RTS; trở lại

Bắt đầu JSR: chuyển sang hoạt động thường lệ bắt đầu từ $0300

Bây giờ, có thể có nhiều chương trình con trong một chương trình dài. Tất cả đều không thể có cái tên “bắt đầu”. Họ nên có tên khác nhau. Trên thực tế, không ai trong số họ có thể có tên “bắt đầu”. “Bắt đầu” được sử dụng ở đây vì lý do giảng dạy.

4.15 Dịch chương trình

Dịch một chương trình hoặc lắp ráp nó có nghĩa tương tự. Hãy xem xét chương trình sau:

bắt đầu LDX #$FF : tải X với $FF = 255
vòng lặp DEX : X = X – 1
Vòng lặp BNE: nếu X khác 0 thì vòng lặp goto
RTS: trở lại
Bắt đầu JSR: chuyển sang hoạt động thường lệ bắt đầu từ $0300

Đây là chương trình đã được viết trước đó. Nó bao gồm chương trình con, bắt đầu và lệnh gọi chương trình con. Chương trình đếm ngược từ 255 10 đến 0 10 . Chương trình bắt đầu tại địa chỉ bắt đầu của người dùng là $0200 (RAM). Chương trình được gõ vào trình soạn thảo văn bản và được lưu vào đĩa. Nó có tên như “sample.asm” trong đó “sample” là tên do lập trình viên lựa chọn nhưng phần mở rộng “.asm” cho hợp ngữ phải được liên kết với tên tệp.

Chương trình được lắp ráp được tạo ra bởi một chương trình khác được gọi là trình biên dịch chương trình. Bộ lắp ráp được cung cấp bởi nhà sản xuất 6502 µP hoặc bởi bên thứ ba. Trình biên dịch chương trình tái tạo chương trình theo cách nó nằm trong bộ nhớ (RAM) khi nó thực thi (chạy).

Giả sử rằng lệnh JSR bắt đầu tại địa chỉ $0200 và chương trình con bắt đầu tại địa chỉ $0300. Trình biên dịch mã loại bỏ tất cả các nhận xét và khoảng trắng. Các bình luận và khoảng trắng sẽ lãng phí bộ nhớ vốn luôn khan hiếm. Một dòng trống có thể có giữa đoạn mã chương trình con trước đó và lệnh gọi chương trình con là một ví dụ về khoảng trắng. Tệp đã tập hợp vẫn được lưu trong đĩa và được đặt tên giống như “sample.exe”. “Mẫu” là tên do lập trình viên lựa chọn, nhưng phần mở rộng “.exe” phải ở đó để cho biết rằng đó là tệp thực thi.

Chương trình được lắp ráp có thể được ghi lại như sau:

Việc tạo ra một tài liệu như thế này được cho là lắp ráp bằng tay. Lưu ý rằng các chú thích trong tài liệu này không xuất hiện trong bộ nhớ (để thực thi). Cột địa chỉ trong bảng cho biết địa chỉ bắt đầu của các lệnh trong bộ nhớ. Lưu ý rằng “JSR start” là “JSR $0300”, dự kiến ​​sẽ được mã hóa là “20 03 00”, thực tế được mã hóa là “20 00 03” với địa chỉ byte bộ nhớ thấp hơn lấy byte thấp hơn trong bộ nhớ và địa chỉ byte bộ nhớ cao hơn lấy byte cao hơn trong bộ nhớ - độ bền nhỏ. Mã hoạt động của JSR là 20 16 .

Lưu ý rằng độ lệch của lệnh rẽ nhánh như BNE là số bù hai trong phạm vi 128 10 đến + 127 10 . Vì vậy, “Vòng lặp BNE” có nghĩa là “BNE -1 10 ” thực ra là “D0 FF” ở dạng mã FF 16 là -1 trong phần bù hai được viết là = 11111111 trong cơ số hai. Chương trình biên dịch mã thay thế các nhãn và trường thành số thập lục phân thực tế (số thập lục phân là số nhị phân được nhóm thành bốn bit). Các địa chỉ thực tế nơi mỗi lệnh bắt đầu thực sự được bao gồm.

Ghi chú: Lệnh “bắt đầu JSR” được thay thế bằng các lệnh ngắn hơn gửi nội dung hiện tại (byte cao và byte thấp) của bộ đếm chương trình tới ngăn xếp với con trỏ ngăn xếp được giảm đi hai lần (một lần cho byte cao và một lần cho byte thấp) và sau đó tải lại PC với địa chỉ $0300. Con trỏ ngăn xếp bây giờ trỏ đến $00FD, giả sử rằng nó được khởi tạo là $01FF.

Ngoài ra, lệnh RTS được thay thế bằng một số lệnh ngắn hơn làm tăng con trỏ ngăn xếp “S” hai lần (một lần cho byte thấp và một lần cho byte cao) và kéo hai byte địa chỉ tương ứng từ con trỏ ngăn xếp tới PC để hướng dẫn tiếp theo.

Ghi chú: Văn bản nhãn không được có nhiều hơn 8 ký tự.

“Vòng lặp BNE” sử dụng địa chỉ tương đối. Có nghĩa là thêm -3 10 đến nội dung bộ đếm chương trình tiếp theo là $0305. Các byte cho “vòng lặp BNE” là “D0 FD” trong đó FD là phần bù hai của -3 10 .

Lưu ý: Chương này không trình bày tất cả các hướng dẫn dành cho 6502 µP. Tất cả các hướng dẫn và chi tiết của chúng có thể được tìm thấy trong tài liệu có tiêu đề “Dòng bộ vi xử lý 8-bit SY6500”. Có một tệp PDF có tên “6502.pdf” cho tài liệu này được cung cấp miễn phí trên Internet. 6502 µP được mô tả trong tài liệu này là 65C02.

4.16 Ngắt

Tín hiệu của bất kỳ thiết bị nào được kết nối với các cổng bên ngoài (bề mặt thẳng đứng) của Commodore 64 đều phải đi qua mạch (IC) CIA 1 hoặc CIA 2 trước khi đến bộ vi xử lý 6502. Các tín hiệu từ bus dữ liệu của 6502 µP phải đi qua chip CIA 1 hoặc CIA 2 trước khi đến bất kỳ thiết bị bên ngoài nào. CIA là viết tắt của Bộ điều hợp giao diện phức tạp. Trong Hình 4.1 “Sơ đồ khối của bo mạch chủ Commodore_64”, các thiết bị đầu vào/đầu ra khối đại diện cho CIA 1 và CIA 2. Khi một chương trình đang chạy, nó có thể bị gián đoạn để chạy một số đoạn mã khác trước khi tiếp tục. Có gián đoạn phần cứng và gián đoạn phần mềm. Đối với gián đoạn phần cứng, có hai chân tín hiệu đầu vào tới 6502 µP. Tên của các chân này là IRQ NMI . Đây không phải là dòng dữ liệu µP. Các dòng dữ liệu cho µP là D7, D6, D5, D4, D3, D2, D1 và D0; với D0 cho bit có trọng số thấp nhất và D7 cho bit có trọng số cao nhất.

IRQ là viết tắt của Interrupt ReQuest “hoạt động” ở mức thấp. Đường dây đầu vào này của µP thường ở mức cao, khoảng 5 volt. Khi nó giảm xuống khoảng 0 volt, đó là một yêu cầu ngắt báo hiệu cho µP. Ngay sau khi yêu cầu được chấp nhận, đường dây sẽ trở lại mức cao. Việc chấp nhận yêu cầu ngắt có nghĩa là µP phân nhánh tới mã (chương trình con) xử lý ngắt.

NMI là viết tắt của Non-Maskable Interrupt “hoạt động” ở mức thấp. Trong khi mã cho IRQ đang được thực thi NMI có thể xuống thấp. Trong trường hợp này, NMI được xử lý (mã riêng của nó được thực thi). Sau đó, mã cho IRQ tiếp tục. Sau mã cho IRQ kết thúc, mã chương trình chính tiếp tục. Đó là, NMI làm gián đoạn IRQ người xử lý. Tín hiệu cho NMI vẫn có thể được cấp cho µP ngay cả khi µP ở trạng thái rảnh và không xử lý bất kỳ thứ gì hoặc không chạy chương trình chính.

Ghi chú: Thực ra đó là sự chuyển tiếp từ cao xuống thấp của NMI , đó là NMI tín hiệu - sẽ nói thêm về điều đó sau. IRQ thường đến từ CIA 1 và NMI thường đến từ CIA 2. NMI , viết tắt của Non-Maskable Interrupt, có thể được coi là ngắt không thể dừng được.

Xử lý ngắt
Cho dù yêu cầu đến từ IRQ hoặc NMI , hướng dẫn hiện tại phải hoàn thành. 6502 chỉ có các thanh ghi A, X và Y. Trong khi một chương trình con đang hoạt động, nó có thể sử dụng ba thanh ghi này cùng nhau. Trình xử lý ngắt vẫn là một chương trình con, mặc dù không được xem như vậy. Sau khi lệnh hiện tại hoàn thành, nội dung của các thanh ghi A, X và Y cho 65C02 µP sẽ được lưu vào ngăn xếp. Địa chỉ của lệnh tiếp theo của Bộ đếm chương trình cũng được gửi vào ngăn xếp. Sau đó µP sẽ phân nhánh tới mã ngắt. Sau đó, nội dung của các thanh ghi A, X và Y sẽ được khôi phục từ ngăn xếp theo thứ tự ngược lại khi chúng được gửi đến.

Mã hóa ví dụ cho một ngắt
Để đơn giản, giả sử rằng thủ tục cho µP IRQ ngắt chỉ là cộng các số $01 và $02 và lưu kết quả của $03 vào địa chỉ bộ nhớ $0400. Mã là:

ISR PHA
PHX
vật lý
;
LDA #$01
ADC #$02
CHÚNG CÓ GIÁ $ 0400
;
LỚP
PLX
PLA
RTI

ISR là nhãn và xác định địa chỉ bộ nhớ chứa lệnh PHA. ISR có nghĩa là Dịch vụ gián đoạn thường xuyên. PHA, PHX và PHY gửi nội dung của các thanh ghi A, X và Y đến ngăn xếp với hy vọng rằng chúng sẽ cần thiết cho bất kỳ mã (chương trình) nào đang chạy ngay trước khi bị gián đoạn. Ba lệnh tiếp theo tạo thành cốt lõi của trình xử lý ngắt. Các lệnh PLY, PLX và PLA phải theo thứ tự đó và chúng mang lại nội dung của các thanh ghi Y, X và A. Lệnh cuối cùng, là RTI, (không có toán hạng) trả về việc tiếp tục thực thi cho bất kỳ mã (chương trình) nào đang thực thi trước khi bị gián đoạn. RTI kéo địa chỉ của lệnh tiếp theo của mã đang thực thi từ ngăn xếp trở lại bộ đếm chương trình. RTI có nghĩa là Quay lại từ ngắt. Như vậy, việc xử lý ngắt (chương trình con) đã kết thúc.

Ngắt phần mềm
Cách chính để gây ra ngắt phần mềm cho 6502 µP là sử dụng lệnh địa chỉ ngụ ý BRK. Giả sử chương trình chính đang chạy và gặp lệnh BRK. Từ thời điểm đó, địa chỉ của lệnh tiếp theo trong PC sẽ được gửi vào ngăn xếp khi lệnh hiện tại được hoàn thành. Một chương trình con để xử lý lệnh phần mềm phải được gọi là “tiếp theo”. Chương trình con ngắt này sẽ đẩy nội dung thanh ghi A, X và Y vào ngăn xếp. Sau khi phần lõi của chương trình con được thực thi, nội dung của các thanh ghi A, X và Y sẽ được kéo trở lại từ ngăn xếp về các thanh ghi của chúng bằng chương trình con hoàn thành. Câu lệnh cuối cùng trong quy trình là RTI. Nội dung PC cũng được tự động kéo trở lại từ ngăn xếp về PC do RTI.

So sánh và đối chiếu chương trình con và chương trình dịch vụ ngắt
Bảng sau đây so sánh và đối chiếu Chương trình con và Quy trình dịch vụ ngắt:

4.17 Tóm tắt các chế độ đánh địa chỉ chính của 6502

Mỗi lệnh cho 6502 là một byte, theo sau là 0 hoặc nhiều toán hạng.

Chế độ đánh địa chỉ tức thời
Với chế độ đánh địa chỉ ngay lập tức, sau toán hạng, là giá trị chứ không phải địa chỉ bộ nhớ. Giá trị phải được bắt đầu bằng #. Nếu giá trị ở dạng thập lục phân thì “#” phải theo sau là “$”. Các lệnh đánh địa chỉ trực tiếp cho 65C02 là: ADC, AND, BIT, CMP, CPX, CPY, EOR, LDA, LDX, LDY, ORA, SBC. Người đọc nên tham khảo tài liệu dành cho 65C02 µP để biết cách sử dụng các hướng dẫn được liệt kê ở đây mà chưa được giải thích trong chương này. Một hướng dẫn ví dụ là:

LDA #$77

Chế độ đánh địa chỉ tuyệt đối
Trong chế độ đánh địa chỉ tuyệt đối, có một toán hạng. Toán hạng này là địa chỉ của giá trị trong bộ nhớ (thường ở dạng thập lục phân hoặc nhãn). Có 64K 10 = 65,536 10 địa chỉ bộ nhớ cho 6502 µP. Thông thường, giá trị một byte nằm ở một trong những địa chỉ này. Các hướng dẫn đánh địa chỉ tuyệt đối cho 65C02 là: ADC, AND, ASL, BIT, CMP, CPX, CPY, DEC, EOR, INC, JMP, JSR, LDA, LDX, LDY, LSR, ORA, ROL, ROR, SBC, STA , STX, STY, STZ, TRB, TSB. Người đọc nên tham khảo tài liệu về 65C02 µP để biết cách sử dụng các lệnh được liệt kê ở đây, cũng như các chế độ địa chỉ còn lại không được giải thích trong chương này. Một hướng dẫn ví dụ là:

HỌ LÀ $1234

Chế độ địa chỉ ngụ ý
Trong chế độ địa chỉ ngụ ý, không có toán hạng. Bất kỳ thanh ghi µP nào liên quan đều được hàm ý trong lệnh. Các hướng dẫn đánh địa chỉ ngụ ý cho 65C02 là: BRK, CLC, CLD, CLI, CLV, DEX, DEY, INX, INY, NOP, PHA, PHP, PHX, PHY, PLA, PLP, PLX, PLY, RTI, RTS, SEC , SED, SEI, THUẾ, TAY, TSX, TXA, TXS, TYA. Một hướng dẫn ví dụ là:

DEX : Giảm thanh ghi X đi một đơn vị.

Chế độ đánh địa chỉ tương đối
Chế độ địa chỉ tương đối chỉ xử lý các lệnh nhánh. Trong chế độ đánh địa chỉ tương đối, chỉ có một toán hạng. Đó là một giá trị từ -128 10 đến +127 10 . Giá trị này được gọi là offset. Dựa vào dấu hiệu, giá trị này được cộng hoặc trừ khỏi lệnh tiếp theo của Bộ đếm chương trình để tạo ra địa chỉ của lệnh tiếp theo dự định. Các hướng dẫn chế độ địa chỉ tương đối là: BCC, BCS, BEQ, BMI, BNE, BPL, BRA, BVC, BVS. Các ví dụ hướng dẫn là:

BNE $7F : (nhánh nếu Z = 0 trong thanh ghi trạng thái, P)

Thêm 127 vào bộ đếm chương trình hiện tại (địa chỉ để thực thi) và bắt đầu thực hiện lệnh tại địa chỉ đó. Tương tự:

BEQ $F9 : (nhánh nếu Z = : trong thanh ghi trạng thái, P)

Việc này thêm -7 vào bộ đếm chương trình hiện tại và bắt đầu thực thi tại địa chỉ bộ đếm chương trình mới. Toán hạng là số bù hai.

Địa chỉ được lập chỉ mục tuyệt đối
Trong địa chỉ chỉ mục tuyệt đối, nội dung của thanh ghi X hoặc Y được thêm vào địa chỉ tuyệt đối đã cho (bất kỳ nơi nào từ $0000 đến $FFFF, tức là từ 0 10 tới 65536 10 ) để có địa chỉ thực. Địa chỉ tuyệt đối đã cho này được gọi là địa chỉ cơ sở. Nếu thanh ghi X được sử dụng, hướng dẫn lắp ráp sẽ giống như thế này:

LDA $C453,X

Nếu thanh ghi Y được sử dụng, nó sẽ giống như:

LDA $C453,Y

Giá trị cho thanh ghi X hoặc Y được gọi là giá trị đếm hoặc chỉ số và nó có thể ở bất kỳ đâu từ $00 (0 10 ) đến $FF (250 10 ). Nó không được gọi là bù đắp.

Các lệnh đánh địa chỉ chỉ số tuyệt đối là: ADC, AND, ASL (chỉ X), BIT (với bộ tích lũy và bộ nhớ, chỉ với X), CMP, DEC (chỉ bộ nhớ và X), EOR, INC (chỉ bộ nhớ và X), LDA , LDX, LDY, LSR (chỉ X), ORA, ROL (chỉ X), ROR (chỉ X), SBC, STA, STZ (chỉ X).

Địa chỉ gián tiếp tuyệt đối
Điều này chỉ được sử dụng với lệnh nhảy. Với điều này, địa chỉ tuyệt đối đã cho có một địa chỉ con trỏ. Địa chỉ con trỏ bao gồm hai byte. Con trỏ hai byte trỏ tới (là địa chỉ của) giá trị byte đích trong bộ nhớ. Vì vậy, hướng dẫn hợp ngữ là:

JMP ($3456)

Với dấu ngoặc đơn và $13 nằm ở vị trí địa chỉ của $3456 trong khi $EB nằm ở vị trí địa chỉ của $3457 (= $3456 + 1). Khi đó, địa chỉ đích là $13EB và $13EB là con trỏ. Số $3456 tuyệt đối nằm trong ngoặc đơn trong lệnh trong đó 34 là byte thấp hơn và 56 là byte cao hơn.

4.18 Tạo một chuỗi bằng ngôn ngữ hợp ngữ 6502 µP

Như được trình bày ở chương tiếp theo, sau khi tạo một tập tin trong bộ nhớ, tập tin đó có thể được lưu vào đĩa. Tập tin cần phải được đặt tên. Tên là một ví dụ về một chuỗi. Có rất nhiều ví dụ khác về chuỗi trong lập trình.

Có hai cách chính để tạo một chuỗi mã ASCII. Theo cả hai cách, tất cả các mã ASCII (ký tự) đều chiếm các vị trí byte liên tiếp trong bộ nhớ. Theo một trong các cách, chuỗi byte này được bắt đầu bằng một byte số nguyên là độ dài (số ký tự) trong chuỗi (chuỗi). Nói cách khác, chuỗi ký tự được nối tiếp (ngay sau đó) bởi byte Null là 00 16 , tức là $00. Độ dài của chuỗi (số ký tự) không được biểu thị theo cách khác. Ký tự Null không được sử dụng theo cách đầu tiên.

Ví dụ: hãy xem xét câu “Anh yêu em!” chuỗi không có dấu ngoặc kép. Độ dài ở đây là 11; một khoảng trắng được tính là một byte ASCII (ký tự). Giả sử rằng chuỗi phải được đặt trong bộ nhớ với ký tự đầu tiên có địa chỉ $0300.

Bảng sau hiển thị cài đặt bộ nhớ chuỗi khi byte đầu tiên là 11 10 = 0B 16 :

Bảng sau đây hiển thị cài đặt bộ nhớ chuỗi khi byte đầu tiên là “I” và byte cuối cùng là Null ($00):

Hướng dẫn sau đây có thể được sử dụng để bắt đầu tạo chuỗi:

CHÚNG CÓ GIÁ $ 0300

Giả sử rằng byte đầu tiên nằm trong bộ tích lũy sẽ được gửi đến vị trí địa chỉ $0300. Hướng dẫn này đúng cho cả hai trường hợp (cả hai loại chuỗi).

Sau khi khớp tất cả các ký tự trong các ô nhớ, từng ký tự một, chuỗi có thể được đọc bằng vòng lặp. Đối với trường hợp đầu tiên, số lượng ký tự sau độ dài được đọc ra. Đối với trường hợp thứ hai, các ký tự được đọc từ “I” cho đến khi gặp ký tự Null là “Null”.

4.19 Tạo một mảng với ngôn ngữ hợp ngữ 6502 µP

Một mảng các số nguyên byte đơn bao gồm các vị trí byte bộ nhớ liên tiếp với các số nguyên. Sau đó, có một con trỏ trỏ tới vị trí của số nguyên đầu tiên. Vì vậy, một mảng số nguyên bao gồm hai phần: con trỏ và chuỗi vị trí.

Đối với một mảng các chuỗi, mỗi chuỗi có thể ở một vị trí khác nhau trong bộ nhớ. Sau đó, có các vị trí bộ nhớ liên tiếp với các con trỏ trong đó mỗi con trỏ trỏ đến vị trí đầu tiên của mỗi chuỗi. Một con trỏ trong trường hợp này bao gồm hai byte. Nếu một chuỗi bắt đầu bằng độ dài của nó thì con trỏ tương ứng sẽ trỏ đến vị trí của độ dài đó. Nếu một chuỗi không bắt đầu bằng độ dài của nó nhưng kết thúc bằng ký tự null thì con trỏ tương ứng sẽ trỏ đến vị trí của ký tự đầu tiên trong chuỗi. Và có một con trỏ trỏ đến địa chỉ byte thấp hơn của con trỏ đầu tiên của các con trỏ liên tiếp. Vì vậy, một mảng các chuỗi bao gồm ba phần: các chuỗi ở các vị trí khác nhau trong bộ nhớ, các con trỏ liên tiếp tương ứng và con trỏ tới con trỏ đầu tiên của các con trỏ liên tiếp.

4.20 Vấn đề

Người đọc nên giải quyết tất cả các vấn đề trong một chương trước khi chuyển sang chương tiếp theo.

  1. Viết chương trình hợp ngữ có giá khởi điểm là $0200 cho 6502 µP và thêm các số không dấu là 2A94 H (thêm) vào 2ABF H (tăng cường). Hãy để đầu vào và đầu ra ở trong bộ nhớ. Ngoài ra, hãy tạo tài liệu chương trình đã được lắp ráp bằng tay.
  2. Viết chương trình hợp ngữ có giá khởi điểm là $0200 cho 6502 µP và trừ các số không dấu là 1569 H (trừ) từ 2ABF H (trừ). Hãy để đầu vào và đầu ra ở trong bộ nhớ. Ngoài ra, hãy tạo tài liệu chương trình đã được lắp ráp bằng tay.
  3. Viết chương trình hợp ngữ cho 6502 µP đếm từ $00 đến $09 bằng cách sử dụng vòng lặp. Chương trình sẽ bắt đầu ở mức $0200. Ngoài ra, hãy tạo tài liệu chương trình đã được lắp ráp bằng tay.
  4. Viết chương trình hợp ngữ có giá khởi điểm là $0200 cho 6502 µP. Chương trình có hai chương trình con. Chương trình con thứ nhất cộng các số không dấu 0203 H (tăng cường) và 0102H (bổ sung). Chương trình con thứ hai cộng tổng từ chương trình con thứ nhất là 0305H vào 0006 H (tăng cường). Kết quả cuối cùng được lưu trữ trong bộ nhớ. Gọi chương trình con đầu tiên là FSTSUB và chương trình con thứ hai là SECSUB. Hãy để đầu vào và đầu ra ở trong bộ nhớ. Ngoài ra, hãy tạo tài liệu chương trình đã lắp ráp cho toàn bộ chương trình bằng tay.
  5. Cho rằng một IRQ trình xử lý thêm $02 vào $01 tại bộ tích lũy dưới dạng xử lý cốt lõi trong khi NMI được ban hành và xử lý cốt lõi cho NMI thêm $05 vào $04 tại bộ tích lũy, viết ngôn ngữ lắp ráp cho cả hai trình xử lý bao gồm cả các lệnh gọi của chúng. Cuộc gọi tới IRQ trình xử lý phải ở địa chỉ $0200. Các IRQ trình xử lý nên bắt đầu ở địa chỉ $0300. Các NMI trình xử lý phải bắt đầu ở địa chỉ $0400. Kết quả của IRQ bộ xử lý phải được đặt ở địa chỉ $0500, và kết quả của NMI bộ xử lý phải được đặt ở địa chỉ $0501.
  6. Giải thích ngắn gọn cách sử dụng lệnh BRK để tạo ra ngắt phần mềm trong máy tính 65C02.
  7. Tạo một bảng so sánh và đối chiếu một chương trình con bình thường với một chương trình phục vụ ngắt.
  8. Giải thích ngắn gọn các chế độ đánh địa chỉ chính của 65C02 µP dựa trên các ví dụ hướng dẫn hợp ngữ.
  9. a) Viết chương trình ngôn ngữ máy 6502 để viết câu “Anh yêu em!” chuỗi mã ASCII trong bộ nhớ, bắt đầu từ địa chỉ $0300 với độ dài của chuỗi. Chương trình sẽ bắt đầu tại địa chỉ $0200. Lấy từng ký tự từ bộ tích lũy, giả sử rằng chúng được gửi đến đó bằng một chương trình con nào đó. Ngoài ra, lắp ráp chương trình bằng tay. (Nếu bạn cần biết mã ASCII của câu “Anh yêu em!”. Đây là: ‘I’:49 16 , khoảng trống : 20 16 , ‘l’: 6C 16 , ‘o’:6F 16 , 'trong':76 16 , 'e':65, 'y':79 16 , 'trong':75 16 và ‘!’:21 16 (Lưu ý: mỗi mã chiếm 1 byte).
    b) Viết chương trình ngôn ngữ máy 6502 để viết câu “Anh yêu em!” chuỗi mã ASCII trong bộ nhớ, bắt đầu từ địa chỉ $0300 không có độ dài chuỗi nhưng kết thúc bằng 00 16 . Chương trình sẽ bắt đầu tại địa chỉ $0200. Lấy từng ký tự từ bộ tích lũy, giả sử rằng chúng được gửi đến đó, từng ký tự một, bởi một chương trình con nào đó. Ngoài ra, lắp ráp chương trình bằng tay.