Прочитав хотя бы первые 3 или 4 главы примерно 4 разных книг по программированию на ассемблере, я дошел до стадии, когда я могу поместить «Hello World» на консоль dosbox с помощью MASM 6.11. Представьте себе мой восторг !!
В первой версии моей программы использовалась функция DOS 13h. Вторая версия моей программы использовала функцию BIOS 10h
Теперь я хочу сделать третью версию, используя прямой аппаратный вывод. Я прочитал части книг, в которых объясняется, что экран разделен на 80x25 на мониторах VGA (не беспокоился об обнаружении CGA и всем остальном, поэтому моя программа использует адрес памяти 0B800h для цветного VGA, потому что DOSBox великолепен и все, и мое желание перейти на Win Assembler когда-то до того, как мне исполнится 90 лет). Я читал, что каждый символ на экране оборудования составляет 2 байта (1 для атрибута и один для самого символа, поэтому у вас 80x25x2 = 4000 байтов). Нечетные байты описывают атрибут, а четные байты - символ ASCII.
Но моя проблема вот в чем. Как бы я ни старался, я не могу заставить свою программу выводить простую черно-белую (что является просто атрибутом, я полагаю, я могу достаточно легко изменить это) строку (которая представляет собой просто массив байтов) в 5 строках сверху экрана и 20 символов от левого края (это просто количество пустых символов от нулевого индекса длиной 4000 байтов). (если мой расчет верен, это 5x80 = 400 + 20 = 420x2 = 840 - это начальная позиция моей строки в массиве из 4000 байтов)
Как мне отделить атрибут от символа (я заставил его работать частично, но он показывает только каждый второй символ, а затем кучу случайного мусора (вот как я решил, что мне нужна какая-то пара байтов для атрибута и текста) или Как мне настроить его так, чтобы оба распознавались вместе. Как мне контролировать положение текста на экране после выполнения вычислений. Где я ошибаюсь.
Я пробовал поискать в Интернете этот, казалось бы, простой вопрос, но не могу найти решения. Есть ли кто-нибудь, кто раньше программировал в DOS и на ассемблере x86, и мог бы сказать мне, как сделать эту простую небольшую программу, не используя функции BIOS или DOS, а только с оборудованием.
Я бы действительно порекомендовал простой фрагмент кода, если это возможно. Или ссылку на какой-нибудь сайт или бесплатную электронную книгу. Я не хочу покупать большую книгу по программированию консоли dos, которая вскоре окажется бесполезной, когда я перейду на Windows. Единственная причина, по которой я сосредоточен на этом, заключается в том, что я хочу изучить настоящую сборку, а не какой-то макроязык или какой-то претенциозный язык высокого уровня, который претендует на то, чтобы быть сборкой.
Я пытаюсь создать библиотеку подпрограмм, которая упростит освоение ассемблера, чтобы людям не приходилось работать, хотя все от 3 до 6 глав в 10 книгах теории, по сути, снова и снова объясняют одни и те же вещи, когда на самом деле все, что нужно, достаточно чтобы знать, как получить некоторый результат, присвоить значения переменным, получить некоторый ввод и выполнить некоторые циклы и решения. Теория может появиться позже, и к тому времени, когда они дойдут до циклов и решений, большинство людей уже сделают достаточно ассемблера, чтобы иметь всю теорию в любом случае. Я верю, что сборку следует обучать не иначе, как любому другому языку, начиная с простой программы hello world, а затем получая ввод и т. Д. Я хочу сделать это возможным. Но эй, я только новичок, может быть, мои таланты изменятся, когда я узнаю больше.
Еще одно замечание: я точно знаю, что проблема НЕ в DOSBox, так как у меня очень старый компьютер с истинной MS-DOS V6.2, и программа все еще не работает (но дает почти идентичный результат). Фактически, DOSBox запускает некоторые из моих старых программ даже лучше, чем True dos. Рабочий стол Gem является одним из примеров. Просто хотел очистить это, прежде чем люди попытаются предположить, что это проблема с эмулятором. Не может быть, не с такими простыми программами. Не боюсь, проблема в том, что мой маленький мозг не полностью понимает, что нужно.
Может кто-нибудь там, пожалуйста, помогите !!
Ниже представлена программа, которую я использовал (MASM 6.1 под DOSBox на Win 7 64-бит). Он использует BIOS Intrrupt 10h, функцию 13h, подфункцию 0. Я хочу сделать то же самое, используя прямой аппаратный ввод-вывод.
.model small .stack .data ;part of the program containing data ;Constants - None ;Variables MyMsg db 'Hello World' .code Main: GetAddress: mov ax,@data ;Gets address of data segment mov es,ax ;Loads segment address into es regrister mov bp,OFFSET MyMsg ;Load Offset into DX SetAttributes: mov bl,01001111b ;BG/FG Colour attributes mov cx,11 ;Length of string in data segment SetRowAndCol: mov dh,24 ;Set the row to start printing at mov dl,68 ;Set the column to start printing at GetFunctionAndSub: mov ah,13h ;BIOS Function 10h - String Output mov al,0 ;BIOS Sub-Function (0-3) Execute: int 10h ;BIOS Interrupt 10h EndProg: mov ax,4c00h ;Terminate program return 0 to OS int 21h ;DOS Interrupt 21h end Main end
Я хочу, чтобы это было в формате, который легко объяснить. Итак, вот моя текущая работа. Я почти понял. Но он печатает только атрибуты, вывести символы на экран - проблема. (Иногда, когда я его немного изменяю, я получаю каждый второй символ со случайными атрибутами (я думаю, что знаю технические детали, но не знаю достаточно ассемблера, чтобы исправить это)).
.model small .stack .data ;Constants ScreenSeg equ 0B800h ;Variables MyMsg db 'Hello World' StrLen equ $-MyMsg .code Main: SetSeg: mov ax, ScreenSeg ;set segment register: mov ds, ax InitializeStringLoop: ;Display all characters: - Not working :( Y! mov cx, StrLen ;number of characters. mov di, 00h ;start from byte 'h' OutputString: mov [di], offset byte ptr MyMsg[di] add di, 2 ;skip over next attribute code in vga memory. loop OutputString InitializeAttributeLoop:;Color all characters: - Atributes are working fine. mov cx, StrLen ;number of characters. mov di, 01h ;start from byte after 'h' ;Assuming I have all chars with same attributes - fine for now - later I would make this ;into a procedure that I will just pass the details into. - But for now I just want a ;basic output tutorial. OutputAttributes: mov [di], 11101100b ;light red(1100) on yellow(1110) add di, 2 ;skip over next ascii code in vga memory. loop OutputAttributes EndPrg: mov ax, 4C00h int 21h end Main
Конечно, я хочу сократить количество используемых инструкций до самого необходимого. (для надлежащего обучения, меньше покрывать при обучении других). По этой причине я не использовал MOVSB / W / D ect с REP. Вместо этого я выбрал простой для объяснения ручной цикл с использованием стандартных MOV, INC, ADD и т. Д. Это достаточно простые инструкции, которые легко объяснить новичкам. Так что, если возможно, я хотел бы сохранить его как можно ближе к этому.
Я знаю, что все, что кажется неправильным, - это цикл для фактического обработчика строк. Это не позволяет мне увеличивать адрес так, как я хочу. Меня это смущает, потому что я на самом деле неплохой программист, использующий C ++, C #, VB и Delphi (когда-то давно)). Я знаю, вы бы не подумали, что, учитывая, что я даже не могу получить цикл прямо на ассемблере, но это совсем другой язык. В языках высокого уровня есть 2 или 3 цикла, и кажется, что существует бесконечная комбинация способов создания циклов в ассемблере в зависимости от инструкций. Итак, я говорю «Простая петля», но на самом деле в этом нет ничего простого.
Я надеюсь, что кто-то может мне помочь с этим, вы спасете мою карьеру сборщика и сделаете так, чтобы я в конечном итоге стал хорошим учителем сборки. Заранее спасибо, особенно за то, что дочитали до этого места.