2010-01-18 40 views
7

Bối cảnh: Tôi đã được giao nhiệm vụ viết chương trình thu thập dữ liệu cho Unitech HT630, chạy hệ điều hành DOS độc quyền có thể chạy các tệp thi hành được biên dịch cho MS DOS 16 bit, mặc dù có một số hạn chế. Tôi đang sử dụng trình biên dịch C/C++ kỹ thuật số Mars, có vẻ hoạt động rất tốt.Sự khác biệt giữa hai hình thức lắp ráp nội tuyến trong C là gì?

Đối với một số thứ tôi có thể sử dụng thư viện C chuẩn, nhưng những thứ khác như vẽ trên màn hình của thiết bị yêu cầu mã lắp ráp. Các ví dụ lắp ráp được đưa ra trong tài liệu của thiết bị khác với cách tôi được dạy sử dụng mã lắp ráp nội tuyến trong C/C++. Để tham khảo, BYTE trong các ví dụ bên dưới là loại unsigned char.

Mẫu mã ví dụ tôi đã được đưa ra:

#include <dos.h> 

/* Set the state of a pixel */ 
void LCD_setpixel(BYTE x, BYTE y, BYTE status) { 
    if(status > 1 || x > 63 || y > 127) { 
    /* out of range, return */ 
    return; 
    } 
    /* good data, set the pixel */ 
    union REGS regs; 
    regs.h.ah = 0x41; 
    regs.h.al = status; 
    regs.h.dh = x; 
    regs.h.dl = y; 
    int86(0x10, &regs, &regs); 
} 

Làm thế nào tôi luôn được dạy để sử dụng lắp ráp nội tuyến:

/* Set the state of a pixel */ 
void LCD_setpixel(BYTE x, BYTE y, BYTE status) { 
    if(status > 1 || x > 63 || y > 127) { 
    /* out of range, return */ 
    return; 
    } 
    /* good data, set the pixel */ 
    asm { 
    mov AH, 41H 
    mov AL, status 
    mov DH, x 
    mov DL, y 
    int 10H 
    } 
} 

Cả hai hình thức có vẻ làm việc, tôi đã không gặp phải một vấn đề với một trong hai cách tiếp cận. Là một hình thức được coi là tốt hơn so với khác cho lập trình DOS? Có phải chức năng int86 xử lý một cái gì đó cho tôi rằng tôi không xử lý bản thân mình trong mã assembly của riêng tôi trong ví dụ thứ hai?

Cảm ơn bạn trước vì đã được trợ giúp.

+0

Tiêu đề gây hiểu nhầm/sai. Không có nội tuyến nào trong phiên bản đầu tiên, chỉ cần một trình bao bọc chức năng gọi xung quanh cuộc gọi hệ thống. (Hoặc một trình biên dịch có thể thực hiện 'int86()' như một nội tại và nội dòng bên phải). –

Trả lời

9

Khi bạn sử dụng lệnh gọi hàm int86, đó là cuộc gọi thư viện thời gian chạy C, thiết lập thanh ghi và phát hành chức năng lỗi int. Cả hai phương thức đều thực sự giống nhau với một ngoại lệ, khi bạn sử dụng trình lắp ráp nội tuyến, mã thực sự được nhúng vào mã đối tượng khi được biên dịch và liên kết.

Lắp ráp nội tuyến sẽ được coi là nhanh hơn vì bạn không có chi phí liên quan đến việc gọi thư viện thời gian chạy C để gọi ngắt DOS cho bạn. Onus là trên bạn để đảm bảo có đủ không gian ngăn xếp khi sử dụng lắp ráp nội tuyến, trong khi thư viện C Runtime sẽ chăm sóc phân bổ không gian ngăn xếp khi thiết lập thanh ghi trước khi gọi hàm int86.

int86 là cách dễ dàng hơn để gọi các ngắt DOS. Điều này đã rất phổ biến trong bộ phần mềm biên dịch Borland Turbo C cũ và trên Microsoft, tôi đang nói về các trình biên dịch cũ trước khi Win 3.1 xuất hiện.

Phát biểu của ngắt 0x10, có trách nhiệm đối với đầu ra video, nếu tôi nhớ không lầm, vào thời điểm đó, một số của BIOS đã phá hủy bp đăng ký và thực hiện giải pháp là để làm điều này:

__asm{ 
    push bp; 
} 
/* set up the registers */ 
int86(0x10, &regs, &regs); 
__asm{ 
    pop bp; 
} 

Bạn có thể tìm hiểu các chức năng BIOS mở rộng trên Danh sách gián đoạn của Ralph Brown here. Ngoài ra HelpPC v2.1 cũng có thể trợ giúp, tìm thấy here.

+0

Tôi nghĩ rằng tôi đã có một bản sao danh sách gián đoạn của Ralph Brown ở trường đại học mà tôi nghĩ về nó, và tôi không biết mình đã làm gì với nó. Dường như tôi quên tài nguyên tuyệt vời này tồn tại, cảm ơn bạn! Điều này rất hữu ích. –

+0

+1 để đề cập đến danh sách gián đoạn của Ralph Brown và HelpPc –

0

Đó không phải là lắp ráp nội tuyến, đó là C. Rất ở mức độ thấp C, sử dụng một chức năng để gây ra sự gián đoạn, nhưng vẫn C.

This page có một số tài liệu (đối với trình biên dịch DJGPP, bạn có thể làm việc khác nhau), bao gồm cấu trúc được sử dụng để biểu diễn thanh ghi. Nó cũng lưu ý:

Lưu ý rằng, không giống như các __dpmi_int chức năng, yêu cầu mà đi qua int86 và chức năng tương tự được đặc biệt xử lý để làm cho họ thích hợp cho cách gọi chế độ thực ngắt từ chế độ bảo vệ chương trình . Ví dụ: nếu một quy trình cụ thể nhận con trỏ trong BX, int86 hy vọng bạn sẽ đặt con trỏ (mã được bảo vệ) vào EBX. Do đó, int86 cần được hỗ trợ cụ thể cho mọi gián đoạn và chức năng bạn gọi theo cách này . Hiện nay, nó chỉ hỗ trợ một tập hợp con của tất cả các ngắt có sẵn và chức năng [...]

+0

điều này đúng với trình biên dịch DJGPP C, vì int86 không phải là một chức năng chuẩn, nó không được cho là trình biên dịch Mars Digital hoạt động theo cùng một cách, nó có thể có nhiều hạn chế hoặc ít hơn – Alon

1

hình thức đầu tiên là dễ đọc hơn mà cũng đếm cho một cái gì đó ;-)

nếu bạn muốn biết nếu int86 đang làm điều gì đó phía sau lưng bạn, chỉ cần biên dịch chương trình của bạn và kiểm tra mã assembly được tạo ra

+0

"dạng đầu tiên dễ đọc hơn". Nó là? –

+0

Tôi nghĩ rằng hình thức nào là "dễ đọc" hơn cái kia là vấn đề cá nhân, bởi vì cá nhân tôi thấy thứ hai dễ đọc hơn, nhưng cả hai đều dễ hiểu. Việc giải mã mã được biên dịch sẽ là thứ gì đó của một phương sách cuối cùng, nếu ai đó không có câu trả lời cho tôi ở đây thì tôi chắc chắn sẽ đi theo con đường đó. –

+0

Dạng đầu tiên dễ đọc hơn bởi các trình biên dịch sử dụng một định dạng khác để lắp ráp nội tuyến. Nhưng bạn có thể lo lắng về chi phí của cuộc gọi hàm không cần thiết, cộng với việc giải quyết các phần tử của liên kết 'REGS', có lẽ là' int86' sao chép tất cả các thanh ghi (tất cả những người được định nghĩa trong liên minh chứ không phải chỉ những cái mà bạn sử dụng) bộ nhớ, sau đó sao chép chúng tất cả trở lại một lần nữa (mà bạn sau đó loại bỏ). –

1

Bằng cách gọi int86, mã của bạn vẫn còn trong C. Dù bằng cách nào, nó viết pixel bằng cách làm gián đoạn hệ thống.

Nếu bạn có pixel cần ghi và bạn bắt đầu nhấn mạnh vấn đề tốc độ, có thể có cách trực tiếp hơn (và ít an toàn hơn nhưng đáng giá hơn) để ghi trực tiếp vào bộ nhớ pixel.

+0

Có thể có một điểm mà tôi sẽ có nhiều điểm ảnh để viết, vì ứng dụng khách đang tranh luận về màn hình giật gân ở đầu ứng dụng. Bây giờ, tôi chỉ cần điều này để vẽ các dòng lẻ trên màn hình. Vấn đề đó có thể sẽ là câu hỏi riêng của nó khi thời gian đến. –

+0

@Heather: Vâng, tôi đã tra cứu máy tính của bạn và màn hình đơn sắc và nhỏ xíu, vì vậy tôi nghi ngờ nếu đồ họa có nhiều nút cổ chai. –

1

Cả hai đoạn mã đều thực hiện tương tự. Ưu điểm lớn của phiên bản thứ nhất là có khả năng bạn vẫn có thể sử dụng nó khi bạn chuyển đổi trình biên dịch. Và bạn không dẫm lên một thanh ghi mà trình tạo mã của trình biên dịch 'C' đang sử dụng cho mục đích khác. Một cái gì đó bạn chắc chắn quên để chăm sóc trong đoạn mã asm của bạn.

+0

Tôi nghi ngờ tôi đã không làm điều gì đó tôi cần phải làm trong khối asm. Cảm ơn. –

1

Bạn nên kiểm tra sổ tay trình biên dịch để tìm ra ai chịu trách nhiệm khôi phục giá trị đăng ký sau phần lắp ráp nội tuyến. Vì các biến của bạn được gán cho thanh ghi, các thay đổi không mong muốn của các giá trị có thể dẫn đến các lỗi khó tìm. int86 (0x10, & regs, & regs); lưu sổ đăng ký và khôi phục chúng sau khi thực hiện ngắt phần mềm.

Một số trình biên dịch chấp nhận các hướng dẫn để xác định danh sách dấu kiểm tra (các thanh ghi phải được lưu và khôi phục). Thông thường một bộ phận lắp ráp nên lưu sổ đăng ký và cờ sẽ được thay đổi bằng cách đẩy và khôi phục chúng bằng cách sử dụng pop, hoặc bởi trình biên dịch hoặc chính bạn. Do đó, ví dụ đầu tiên nên được ưu tiên hơn.

+0

Tôi đồng ý về int86 - Tôi nghĩ rằng tôi sẽ sử dụng phương pháp này để được an toàn trừ khi tốc độ trở thành một vấn đề thực sự, cảm ơn :) –

Các vấn đề liên quan