2 524224 hướng dẫn
Chương trình của tôi:
_start:
mov bl, _end
stc
iloop: adc [bx], al
inc bx
jnz iloop
jnc _start
a32
loop _start
hlt
_end:
(Lưu ý kỹ thuật: phần này được viết cho nasm. a32
Cú pháp của nasm cho byte tiền tố kích thước địa chỉ thay thế. Đối với masm, bạn sẽ thay thế a32
bằng defb 0x67
.)
Để rõ ràng, đây là đầu ra danh sách:
1 _start:
2 0000 B310 mov bl, _end
3 0002 F9 stc
4 0003 1007 iloop: adc [bx], al
5 0005 43 inc bx
6 0006 75F9 jnz iloop
7 0008 73F4 jnc _start
8 000A 67 a32
9 000B E2F1 loop _start
10 000D F4 hlt
11 _end:
Chương trình giả định rằng bộ xử lý ở chế độ thực và chương trình nằm ở dưới cùng của phân đoạn bộ nhớ 64k, nếu không được khởi tạo thành all-bit-zero. Thiết kế của nó rất đơn giản: coi bộ nhớ là một số nguyên không dấu khổng lồ duy nhất và tăng nó thông qua tất cả các giá trị có thể, cho đến khi nó quay trở lại tất cả các số không. Lặp lại 2 lần này 32 lần. Rồi dừng lại.
Vòng lặp trong cùng (dòng 4‒6) chịu trách nhiệm tăng số nguyên khổng lồ. Mỗi lần lặp lại thêm 0 hoặc 1 vào một byte đơn, tùy thuộc vào việc có thực hiện được byte trước đó hay không. Lưu ý rằng mỗi byte trong số nguyên khổng lồ được truy cập, cho dù nó có thay đổi hay không, vì vậy vòng lặp này luôn lặp lại 2 16 - 14 lần.
Nhân tiện, trong trường hợp bạn đang tự hỏi, mã này minh họa lý do tại sao x86 inc
/ dec
hướng dẫn không ảnh hưởng đến cờ mang: chỉ để đơn giản hóa kiểu mẫu mang nhiều byte này. (Mẫu này xuất hiện thường xuyên hơn vào thời của bộ vi xử lý 8 bit, khi tập lệnh 8080 ban đầu được xác định.)
Dòng 7 làm cho quá trình tăng dần lặp lại cho đến khi một chuỗi được thực hiện từ byte cuối cùng, chỉ ra rằng số nguyên khổng lồ đã được đặt lại thành all-bits-zero. Điều này mất một thời gian dài.
Các dòng 8‒9 đánh dấu vòng lặp ngoài cùng và khiến quá trình này lặp lại 2 32 lần, cho đến khi thanh ecx
ghi cuộn quanh không. Điều này có hiệu quả tương đương với việc thêm 32 bit khác vào số nguyên khổng lồ.
Có thể thêm một vòng lặp bên ngoài khác và thực hiện lại bằng cách sử dụng (giả sử) thanh edx
ghi, sau đó có thể sử dụng esi
và edi
cho nhiều lần lặp lại hơn nữa. Tuy nhiên, nó không đáng để làm. Các hướng dẫn để tăng và vòng lặp yêu cầu bốn byte. Bốn byte đó được lấy đi từ số nguyên khổng lồ. Vì vậy, chúng tôi mất 32 bit trên bộ đếm RAM, chỉ để thêm 32 bit thông qua một thanh ghi: cuối cùng nó là một rửa. Lý do duy nhất ecx
là một ngoại lệ là nó có một loop
lệnh chuyên biệt chỉ phù hợp với ba byte. Do đó, chương trình giao dịch 24 bit cho 32, mức tăng nhỏ nhưng vẫn dương 8 bit.
Không quá khó để tính trực tiếp số lượng lệnh mà chương trình thực hiện trước khi dừng. Tuy nhiên, có một cách đơn giản hơn nhiều để ước tính con số này. Các chương trình Sửa tất cả các bộ nhớ của nó, trừ đi 14 byte có chứa các chương trình, và các bx
và ecx
thanh ghi. Điều này thêm tối đa 2 16 - 14 + 2 + 4 = 65528 byte, với tổng số 524224 bit. Phím tắt liên quan đến việc nhận ra rằng, trong quá trình chạy, mọi mẫu có thể có của 524224 bit xuất hiện chính xác một lần. Đối với RAM và thanh ecx
ghi, điều này rất dễ thấy, vì chương trình tăng dần qua từng giá trị. Dành chobx
điều này ít rõ ràng hơn vì nó được thay đổi cùng lúc với giá trị trong bộ nhớ đang được cập nhật. Tuy nhiên, người ta có thể chỉ ra rằng, với cấu trúc của chương trình, nếu một mẫu bit hoàn chỉnh thực sự xuất hiện hai lần, thì chương trình sẽ phải nằm trong một vòng lặp vô hạn. Vì đây không phải là trường hợp, mỗi mẫu bit cuối cùng chỉ được truy cập một lần. (Bằng chứng hoàn toàn được để lại như một bài tập cho người đọc, một cách tự nhiên.)
Vì mọi mẫu bit có thể xuất hiện trong quá trình của chương trình, chương trình phải thực hiện ít nhất 2 524224 hướng dẫn, tương đương với 1,4 × 10 157807 . (Số acutal cao hơn một chút, vì các lệnh nhảy, nhưng sự khác biệt ở cường độ này là không đáng kể.)
Rõ ràng, điều này có thể được cải thiện đáng kể bằng cách sử dụng hơn 64k RAM. Tôi đang giữ phiên bản tiếp theo của mã cho đến khi tôi biết chính xác có thể truy cập bao nhiêu RAM.