Компиляция com программы - Assembler
Формулировка задачи:
Нашла задачу, рисует линии, как я поняла от точки до точки. С помощью tasm и tlink делаю exe файл, запускается, курсор видно, но линии не рисуются. Прочитала что нужно делать не exe, а COM, но так и не поняла как его делать...
В общем, кто звстречался с проблемой, помогитее
; mousedr.asm ;Рисует на экране прямые линии, оканчивающиеся в позициях, которые указываются мышью. STACK 256 .model tiny .code org 100h ; COM-файл. .186 ; Для команжы shr cx, 3. start: mov ax, 12h int 10h ; Видеорежим 640*480. mov ax, 0 ; Инициализировать мышь. int 33h mov ax, 1 ; Показать курсор мыши. int 33h mov ax, 000Ch ; Установить обработчик событий мыши. mov cx, 0002h ; Событие - нажатие левой кнопки. mov dx, offset handler ; ES:DX - адрес обработчика. int 33h mov ah, 0 ; Ожидание нажатия любой клавиши. int 16h mov ax, 000Ch mov cx, 0000h ; Удалить обработчик событий мыши. int 33h mov ax, 3 ; Текстоый режим. int 10h ret ; Конец программы. ; Обработчик событий мыши: при первом нажатии выводит точку на экран, ; при каждом дальнейшем вызове проводит прямую линию от предыдущей ; точки к текущей. handler: push 0A000h pop es ; ES - начало видеопамяти. push cs pop ds ; DS - сегмент кода и данных этой программы. push cx ; CX (X-координата) и DX(Y-координата) push dx ; потребуются в конце. mov ax, 2 ; Спрятать курсор мыши перед выводом на экран. int 33h cmp word ptr previous_X, -1 ; Если это первый вызов, je first_point ; только вывести точку. call line_bresenham ; Иначе - провести прямую. exit_handler: pop dx ; Восстановить CX и DX pop cx mov previous_X, cx ; и запомнить их как предыдущие mov previous_Y, dx ; координаты. mov ax, 1 ; Показать курсор мыши. int 33h retf ; Выход из обработчика - команда RETF. first_point: call putpixellb ; Вывод одной точки (при первом вызове). jmp short exit_handler ; Процедура рисования прямой линии с использованием алгоритма Брезенхама. ; Вывод CX, DX - X, Y начальной точки. ; previous_X, previous_Y - X, Y начальной точки. line_bresenham: mov ax, cx sub ax, previous_X ; AX = длина проекции прямой на ось X. jns dx_pos ; Если AX отрицательный - neg ax ; сменить его знак, причем mov word ptr X_increment, 1 ; координата X при выводе jmp short dx_neg ; прямой будет расти. dx_pos: mov word ptr X_increment, -1 ; Иначе - уменьшаться. dx_neg: mov bx, dx sub bx, previous_Y ; BX = длина проекции прямой на ось Y. jns dy_pos ; Если BX отрицательный - neg bx ; сменить его знак, причем mov word ptr Y_increment, 1 ; координата Y при выводе jmp short dy_neg ; прямой будет расти. dy_pos: mov word ptr Y_increment, -1 ; иначе - уменьшаться. dy_neg: shl ax, 1 ; Удвоить значения проекций, shl bx, 1 ; чтобы избежать работы с полуцелыми числами. call putpixellb ; Вывести первую точку (прямая рисуется от ; CX, DX к previous_X, previous_Y). cmp ax, bx ; Если проекция на ось X больше, чем на Y, jna dx_le_dy mov di, ax ; DI будет указывать, в какую сторону мы shr di, 1 ; отклонились от идеальной прямой. neg di ; Оптимальное начальное значение DI: add di, bx ; DI = 2 * dy - dx cycle: cmp cx, word ptr previous_X ; Основной цикл выполняется, je exit_bres ; пока X не станет равное previous_X. cmp di, 0 ; Если DI > 0, jl fractlt0 add dx, word ptr Y_increment ; перейти к следующему Y sub di, ax ; и уменьшить DI на 2 * dx. fractlt0: add cx, word ptr X_increment ; Следующий X (на каждом шаге). add di, bx ; Увеличить на DI на 2 * dy. call putpixellb ; Вывести точку. ;!!!!! jmp short cycle ; Продолжить цикл. dx_le_dy: ; Если проекция на ось Y больше, чем на X. mov di, bx shr di, 1 neg di ; Оптимальное начальное значение DI: add di, ax ; DI = 2 * dx - dy. cycle2: cmp dx, word ptr previous_Y ; Основной цикл выполняется, je exit_bres ; пока Y не станет равным previous_Y. cmp di, 0 ; Если DI > 0, jl fractlt02 add cx, word ptr X_increment ; перейти к следующему X sub di, bx ; и уменьшить DI на 2 * dy, fractlt02: add dx, word ptr Y_increment ; Следующий Y (на каждом шаге). add di, ax ; Увеличить DI на 2 * dy, call putpixellb ; вывести точку, jmp short cycle2 ; продолжить цикл. exit_bres: ret ; Конец процедуры. ; Процедура вывода точки на экран в режиме, использующем один бит для ; хранения одного пикселя. ; DX = строка, CX = столбец. ; Все регистры сохраняются. putpixellb: pusha ; Сохранить регистры. xor bx, bx mov ax, dx ; AX = номер строки. imul ax, ax, 80 ; AX = номер строки x число байтов в строке. push cx shr cx, 3 ; CX = номер байта в строке. add ax, cx ; AX = номер байта в видеопамяти. mov di, ax ; Поместить его в SI и DI для команд mov si, di ; строковой обработки. pop cx ; CX снова содержит номер столбца. mov bx, 0080h and cx, 07h ; Последние три бита CX = ; остаток от деления на 8 = номер бита в байте ; считая справа налево. shr bx, cl ; Теперь в BL установлен в 1 нужный бит. lods es: byte ptr some_label ; AL = байт из видеопамяти. ;or ax, bx ; Установить выводимый бит в 1, ; Чтобы стереть пиксел с экрана, эту команду OR можно заменить на not bx and ax, bx ; или лучше инициализировать BX не числом 0080h, а числом FF7Fh и использовать ; только and stosb ; И вернуть байт на место. popa ; Восстановить регистры. ret ; Конец. previous_X dw -1 ; Предыдущая X-координата. previous_Y dw -1 ; Предыдущая Y-координата. Y_increment dw -1 ; Направление изменения Y. X_increment dw -1 ; Направление изменения X. some_label: ; Метка, используемая для переопределения ; сегмента-источника для lods с DS на ES. end start
Решение задачи: «Компиляция com программы»
textual
Листинг программы
tasm MyProg.asm tlink /Tdc MyProg.obj
Объяснение кода листинга программы
tasm
: это команда компилятора Assembler, поддерживаемого Borland Turbo Assembler (TASM).MyProg.asm
: это имя исходного файла Assembler, который будет скомпилирован.tlink
: это команда линковщика для создания исполняемого файла./Tdc
: это флаг командной строки, указывающий линковщику использовать определенный формат исполняемого файла.MyProg.obj
: это имя объектного файла, который будет использоваться в процессе линковки.
ИИ поможет Вам:
- решить любую задачу по программированию
- объяснить код
- расставить комментарии в коде
- и т.д