Что ж, ваша общая идея вроде как хорошая, но вы не объясняете, с какой проблемой вы столкнулись, чтобы не реализовать ее.
Мне кажется, что одним из PITA будет этот макрос csrPos 38, 7
(Я действительно ненавижу макросы, особенно в коде людей, которые только изучают ассемблер, так что воспринимайте это как предвзятое мнение, но на самом деле ... я попытаюсь объяснить также на самом деле, так что вы можете решить сами).
Это мгновенно перемещает позицию вывода для следующего вывода, но затем вы печатаете символ как серию многократных выводов, поэтому вам нужно настроить положение между ... но этот предложенный код prnstr msgfive
не имеет простого представления, где предыдущий * Макрос 1007 * настроил его. Вы можете решить это внутри prnstr
с помощью службы BIOS, чтобы фактически прочитать текущую позицию перед печатью, распечатать символы, откорректировать положение и выполнить csrPos
... эта идея должна сразу почувствовать себя «запахом кода» (хотя если у вас нет лучшей идеи, это часто помогает написать это, по крайней мере, «неправильным» способом, чтобы вы могли сами увидеть полученный источник и снова подумать об этом с новым опытом, который часто помогает найти лучшее решение).
То, что вам, вероятно, нужно, это что-то вроде prnstr msgfive, 38, 7
, позволяющее prnstr
обрабатывать само положение и удаляющее csrPos 38, 7
из основной части кода ..., которое также сэкономит вам 1LOC, а также удалит это столкновение ответственности за информацию, где prnstr
не знал, где он должен его распечатать.
Но тогда я бы пожертвовал несколькими LOC исходного кода, чтобы полностью избежать макроса, и скорее сделал бы что-то вроде (например, также не стесняйтесь выбирать другой способ предоставления аргументов, например, разные регистры или даже соглашение о вызовах на основе стека, если хотите):
...
mov dx,38 + 7*256 ; position[38,7]
mov si,OFFSET char_five ; memory address of font data
mov bl,10 ; light green color
call print_char ; call subroutine to output the character
...
Теперь подпрограмма print_char
, выполняющая всю тяжелую работу, обладает всей важной информацией, поэтому она сама может решить, когда / как она изменит выходную позицию, и задача отображения некоторого символа теперь составляет всего 4 LOC в основной блок, который является разумным ИМО.
Как вы можете получить хорошие идеи о том, как сократить свой код ... ну, если вы посмотрите на свой оригинальный код (в идеале в режиме дизассемблирования в отладчике), вы увидите серию одних и тех же инструкций, повторяющихся снова и снова просто с разными непосредственными значениями. Это всегда признак того, что вы можете переместить эти непосредственные данные в некую структуру данных и написать код только один раз, используя своего рода «цикл», чтобы повторить его с несколькими данными.
Таким образом, вы должны искать важные части вашего кода, которые отличаются от других и продолжают повторяться - если это больше 3 раз, вероятно, стоит преобразовать его в подпрограмму.
Также вам следует часто пытаться искать непосредственные данные, которые можно реально рассчитать - например, если вы хотите напечатать простые числа от 2 до 1000, вы можете либо поместить полный список в виде текста в источник (и он будет самым быстрым решение!), или вы можете запрограммировать его в виде цикла от целого числа 2 до 1000, проверяя каждый, является ли оно простым, и выводить его (меньший двоичный файл для цены вычисления).
Некоторые данные часто проще вычислить, чем записать вручную в источнике (например, «положение курсора для блока строк, начинающегося в столбце 38), и падение производительности часто незначительно (как в вашей текущей задаче, вам следует с задержкой в 1 секунду, поэтому неважно, отображаете ли вы цифру в 10 микросекунд или 15 микросекунд).
Другие связанные с ASM способы сохранения некоторых LOC или упрощения обслуживания:
если вы знаете, что ваша подпрограмма должна будет поместить позицию в dh
и dl
, и вы можете использовать свое собственное соглашение о вызовах, то нет причин не передавать аргумент напрямую в dx
, поэтому подпрограмме не нужно копировать / перемещать значения аргумента в dh:dl
.
использовать подпрограммы вместо макросов, это упрощает просмотр исходного кода для других и облегчает отладку, поскольку то, что вы видите в отладчике, намного больше похоже на то, что вы написали в исходном коде.Когда вы отлаживаете макросы, вы видите их в отладчике во внедренном виде, то есть он совсем не похож на источник, что делает его более запутанным (как только вы попадете в особую ситуацию, где использование макроса имеет смысл, вы узнаете его, но в этот момент ваши макросы скорее похожи на подпрограммы и должны быть написаны так).(также, когда опытный программист просматривает ваш код, он знает, что делает mov ax,10h
, но он не знает, что делает csrPos
, потому что это не инструкция x86, поэтому им приходится переключаться назад и вперед между кодом, который он просматривает, иопределение макроса, потому что они не запомнят его мгновенно, но они должны каждый раз учитывать каждую инструкцию, скрытую в макросе, так как они могут иметь нежелательные побочные эффекты для вашего другого кода, поэтому они не могут просто походить на «хорошо, это простопоменяйте позицию, не нужно беспокоиться о инструкциях "... и вы сами будете смущены, когда через несколько месяцев вы проверите этот источник)
Вы можете проверить мой ответ на несколько других-схожий вопрос здесь Положение курсора TASM , чтобы увидеть конкретный способ реализации аналогичной подпрограммы print_char
, используя циклы и определения данных, чтобы сделать код более «общим», подходящим для печати «любого» символа.Это делает саму подпрограмму намного более сложной, чем ваша последовательность pos, print, pos, print, pos, print, ...
, но вы должны написать ее только один раз, отладить только сто раз, а затем вы можете использовать ее для всех символов.Кроме того, это веселее, даже если это займет больше времени.И вы можете похвастаться, что вы более изощренный программист, чем кто-либо, использующий эту утомительную ручную последовательность написания всего ...;): D