Как преобразовать BCD в ASCII и распечатать результат?

Я хочу вывести дату RTC.

Я понял, что для этого мне нужно преобразовать BCD в ASCII, но я не знаю, что делать.

Для преобразования я использую эту страницу: преобразование BCD в ASCII, но она использует прерывание 21h и в эта страница: https://en.wikipedia.org/wiki/BIOS_interrupt_call прерывание 21h не существует.

Как я могу конвертировать и печатать BCD?

DAY:
mov ah,0x04
int 0x1a
mov al,dl
aam ;to convert.
mov bx,ax
mov cx,ax
add dl,ch
mov ah,02h
int 21h
mov dl,cl
int 21h

Я тестировал код в Ubuntu. Я думаю, что я должен использовать прерывание 10h для вывода, а не 21h. (int 21h не активен).

Итак, как преобразовать BCD в ASCII и как напечатать его, используя прерывание 10h?
Просто используйте следующий стиль?

mov al, 'h'
int 10h

person LocketGoma    schedule 09.09.2017    source источник
comment
PS. Я не использую DOS-прерывание. Это нарушение данных мне правил. Просто используйте «вызов прерывания биоса» на странице википедии.   -  person LocketGoma    schedule 09.09.2017
comment
Это может оказаться полезным: en.wikipedia.org/wiki/INT_10H   -  person Ruud Helderman    schedule 09.09.2017
comment
Обратите внимание, что вы не можете использовать прерывания DOS в Ubuntu. В конце концов, Ubuntu — это не DOS, а Linux. Вы запускаете свой код в Dosbox или что-то в этом роде?   -  person fuz    schedule 09.09.2017
comment
Я уже описал вам процесс здесь в последний раз, когда вы спросили. Глядя на приведенный выше код, я не вижу, чтобы вы даже пытались это сделать. Хотя я готов помочь людям с домашним заданием, я не собираюсь делать все за них. Учитывая, что печать целых чисел не является «тривиальной», вы, вероятно, захотите создать PROC, который принимает целочисленный параметр и выводит каждую цифру. Затем вы можете вызвать этот PROC для каждого из номеров, которые вы хотите напечатать.   -  person David Wohlferd    schedule 10.09.2017
comment
Я пытаюсь использовать PROC, но при использовании (PROC {code} A ENDP) возникает ошибка «Переопределение». Я не знаю, почему возникает ошибка.   -  person LocketGoma    schedule 10.09.2017
comment
Могу ли я использовать прыжок вместо PROC/вызова?   -  person LocketGoma    schedule 10.09.2017
comment
Какой ассемблер используете? Если вы собираетесь вызывать PROC более одного раза, переход не очень хорошо работает. Откуда вы знаете, куда вернуться, когда это будет сделано?   -  person David Wohlferd    schedule 10.09.2017
comment
Ой. дерьмо. Вы имеете в виду, что если { A func {вызов P}, B func {вызов P}, ..., P proc {code} P endp}, proc jump странно работает? // Я использую ассемблер nasm // Будет ли работать, если я добавлю код процедуры в каждую вызывающую программу? Теперь я вижу это ссылка   -  person LocketGoma    schedule 10.09.2017
comment
И еще один вопрос. Сборка тоже компилируется построчно? Я пытаюсь вставить код в завершенный код. Но, возможно, это не работает. : ‹, я думаю, что просто пытаюсь плохо звонить или делать плохие коды, но просто интересно..   -  person LocketGoma    schedule 10.09.2017
comment
Определение функций выполняется по-разному в зависимости от того, какой ассемблер вы используете. Хорошее объяснение/пример использования call с nasm здесь. Что касается того, как его использовать, представьте что-то вроде mov al, ch; call writeint; mov al, cl; call writeint; mov al, dh; call writeint.   -  person David Wohlferd    schedule 10.09.2017
comment
Я пробую другой способ решить проблему. (Используя RTC, чтобы получить дату) mov ah,04h; int 1Ah, mov ax,[dl](http://vitaly_filatov.tripod.com/ng/asm/asm_029.5.html); mov cl,ax; (Я получил код печати, используя cl :mov cl,'a'; mov ch, (color code); mov bx, (postion); mov [bx], cx ) Но mov ax, dl & mov cl, ax line неверный код операции и ошибка операндов. В чем проблема с использованием прерывания 1Ah?   -  person LocketGoma    schedule 10.09.2017
comment
Код печати здесь: org 100h; mov ax, 0b800h ; mov ds, ax; mov cl, 'A'; mov ch, 11011111b; mov bx, 15eh; mov [bx], cx; ret;   -  person LocketGoma    schedule 10.09.2017
comment
Вы пытаетесь это сделать в среде, где у вас есть отладчик? Если нет, возможно, измените среду и попробуйте отладку, это может помочь вам визуализировать процесс вычисления. Говорят, что виртуальная машина BOCHS имеет отладчик (сам я не пробовал, просто постоянно вижу его здесь в вопросах о разработке загрузчиков и ядер). Потратив полдня на его настройку и изучение того, как его контролировать и отлаживать, позже вы сможете получить огромное преимущество. И у вас неправильные теги в этом вопросе. сборка ubuntu + полностью не соответствует вашей реальной целевой платформе.   -  person Ped7g    schedule 10.09.2017
comment
Я уже использую среду Bochs. но я не могу попробовать отладчик Bochs, потому что, если я попытаюсь «сделать» в консоли, сообщение об ошибке будет напечатано в консоли. поэтому я не пытаюсь использовать Bochs, если у моего кода есть проблемы.   -  person LocketGoma    schedule 10.09.2017
comment
Я проголосовал против, потому что вопрос сборки, в котором не указана архитектура (из фрагмента мы можем понять, что это x86, но вы нигде не указали это; и самое главное, 16, 32 или 64 бит? Какой режим?), используемый ассемблер (из фрагмента может быть MASM, NASM или TASM) и целевая среда (вы говорите о вызовах BIOS, об Ubuntu и коде ссылки, который использует DOS int 21h - WTF?), по сути, без ответа и большая трата времени для всех участников, так как все здесь заполняют пробелы по-разному.   -  person Matteo Italia    schedule 10.09.2017
comment
@LocketGoma Обратите внимание, что ответ на странице преобразование BCD в ASCII неверен! Инструкция AAM используется неправильно.   -  person Sep Roland    schedule 10.09.2017


Ответы (1)


Что такое BCD (двоично-десятичный код)?

В случае прерывания времени BIOS используется "упакованный BCD". Каждый байт (8 бит) делится на две половины по 4 бита (полубайты), каждая из которых содержит одно десятичное значение (4 бита позволяют использовать значения 0–15, но только значения 0–9 используются, чтобы оставаться «десятичными»).

Так, например, если время заканчивается на «37» секунд, байт секунд будет содержать значение 0x37 = 55 = 0b00110111. Обратите внимание, как в шестнадцатеричном, так и в двоичном формате 4-битные половины видны/читаются даже человеком после небольшой практики (в десятичном виде нет, вам нужно вычислить в голове деление/остаток на 16, чтобы разделить его на 3 и 7: 55 / 16 = 3, 55 % 16 = 7 ).

Теперь сборка довольно проста с небольшими изменениями, поэтому, даже если вы не хотите углубляться в специализированные инструкции BCD, такие как AAM, вы можете использовать обычную битовую маскировку + сдвиг для извлечения двух значений.

Допустим, у вас есть значение 0x37 в BL, и вы хотите извлечь его в BH (0x03) и BL (0x07), тогда, например, этот код рассчитает, что:

mov bh, bl   ; copy the packed value also into BH
and bl, 0x0F ; keep only lower 4 bits in BL (0x37 & 0x0F = 0x07)
shr bh, 4    ; shift right by 4 bits BH (unsigned(0x37) >> 4 = 0x03)
; and that's it, it's that simple to manipulate bits in assembly

Как его отобразить?

Это зависит от вашей целевой платформы, судя по вопросам и комментариям, вы стремитесь к реальному режиму x86 16b на компьютере, совместимом с ПК, с доступным только BIOS, поэтому один из самых простых способов - преобразовать эти десятичные значения 0-9 в значения ASCII цифр ( добавление 48 работает, или многие ассемблеры сделают для вас преобразование из символов, поэтому, например, add bl,'0' работает, и вы можете думать об этом как «добавить символ шрифта 0 в значение 0-9», и поскольку следующие цифры в шрифте определены в +1 путь от '0', он рассчитает правильное значение символа).

Затем используйте один из сервисов int 10h для отображения символа ASCII, например сервис AH=0x0A. Пример отображения символа ASCII из BL:

mov ah, 0x0A  ; write ASCII character
mov al, bl    ; character value to write
xor bx, bx    ; bh = bl = 0 in text mode (adjust in gfx mode as needed)
mov cx, 1     ; write it only once
int 0x10      ; call the BIOS service

Так как вы хотите отображать время, и у вас есть значения в нескольких регистрах, вам, вероятно, потребуется сохранить их между печатью, например, если бы я использовал int 0x1A,02 для чтения RTC, я бы использовал эту "архитектуру" для его отображения (не пишу полную реализацию, просто верхнюю логику, чтобы показать вам, как вы можете использовать push/pop инструкции стека для сохранения значений для последующего использования):

read_and_display_rtc_time:
    mov  ah,2
    int  0x1A     ; call service 00 of RTC BIOS interrupt
    push dx       ; preserve DH (seconds)
    push cx       ; preserve CL (minutes)
    mov  al,ch    ; AL = CH (hours)
    call display_bcd   ; display AL as BCD-packed decimal value
    call display_colon ; display ":"
    pop  ax       ; restore minutes (push cx) into AL
    call display_bcd   ; display AL as BCD-packed decimal value
    call display_colon ; display ":"
    pop  ax
    mov  al,ah    ; restore seconds into AL
    call display_bcd   ; display AL as BCD-packed decimal value
    ret

display_bcd:
    ; AL contains BCD-packed decimal value (4:4 bits)
    ; TODO code to split it into two values, convert to ASCII and display
    ret

display_colon:
    ; TODO code to display colon on screen
    ret

Теперь я прокомментирую некоторые ваши проблемы в комментариях:

mov cl,ax

Да, это незаконно, потому что ax — это 16-битный регистр, а cl — 8-битный регистр (псевдоним для младшей 8-битной части cx), поэтому при такой операции вы потеряете 8 бит.

Чтобы программисту показать, что вы действительно хочете потерять старшие 8 бит, вы можете написать mov cl,al (al — это псевдоним младших 8 бит ax).

Противоположное преобразование, такое как mov ax,cl, снова не удастся, но опять же, как программист, вы можете точно определить, как 8-битное значение должно быть преобразовано в 16-битное значение.

Например, чтобы выполнить «беззнаковое» преобразование, вы можете использовать инструкцию 386+:

movzx ax,cl

Или способ расчета 8086-80286:

xor ax,ax   ; set all bits of AX to zero first
mov al,cl   ; copy the CL into lower 8 bits of AX

А для "подписанного" преобразования снова есть специализированный способ 386+:

movsx ax,cl
; or before 80386 times there are two common options
mov   al,cl     ; if "ax" is target, then there's special instr.
cbw             ; sign extend AL into AX
; or when non-ax register is target, like DX
mov   dh,cl     ; copy CL into upper 8 bits first
sar   dx,8      ; now do sign-right-shift by 8 bits
  ; dx = sign extended CL

Просто имейте в виду, что компьютер — это немного более сложный калькулятор, не более того, поэтому вы должны попытаться преобразовать слово «задача» в размышления о том, какие числовые значения у вас есть на входной стороне, какие числовые значения представляют выходную сторону (даже «символы» просто числовые значения в компьютере), а затем вы просто вычисляете математические формулы для преобразования входных чисел в выходные числа.

Если у вас есть бохи, закомментируйте код, который еще не компилируется, и начните с небольшого фрагмента кода, который работает, проверьте в отладчике, что они делают, чтобы вы могли визуально увидеть, как происходит вычисление, затем постепенно добавляйте новые части кода. код с помощью 2-3 инструкций и продолжайте запускать их в отладчике, чтобы увидеть, вычисляют ли они то, что вы хотите. (чрезмерное использование слова «вычислить» в последних абзацах является преднамеренным.. если вы знаете, как работать с калькулятором, вы довольно близко знаете, как кодировать на ассемблере, хотя ваш исходный код, вероятно, будет уродливым, так как требуется время для подобрать также «стиль» и эффективность — просто проверьте набор инструкций, чтобы понять, какие вычисления возможны, и лучше понять, что означает, что AX — это 16-битный регистр, а AL — 8-битный, и как числовые значения кодируются в бит (электрический ток)).


"проверено в убунту"

Не совсем так, вы запустили только nasm в Ubuntu для создания 16-битного двоичного машинного кода x86 (кросс-компиляция, вы можете создать такой двоичный файл на любой другой машине, на которой есть ассемблер x86, на самом деле не имеет отношения к вашим вопросам, за исключением того, что вы должны указать NASM, поэтому люди, пытающиеся ответить вам, будут знать, какой синтаксис сборки x86 использовать, каждый ассемблер имеет небольшие различия). Затем вы попробовали этот двоичный файл на виртуальной машине (BOCHS). Если вы попытаетесь запустить его непосредственно под Ubuntu, это полностью потерпит неудачу, поскольку ОС Ubuntu не поддерживает среду выполнения для машинного кода реального режима 16b.

Если вы не уверены, что важно, просто опишите все ваши инструменты и командные строки/параметры, которые вы используете.

person Ped7g    schedule 10.09.2017
comment
Спасибо за ответ. я попробую. - person LocketGoma; 10.09.2017
comment
Вероятно, вам следует упомянуть, что после распаковки пары цифр BCD в 16-битный регистр вы можете преобразовать обе половины в целое число с помощью add bx, '00'. Вы можете сохранить это в памяти и распечатать в виде строки или распечатать по одному. Или даже lea cx, [bx+'00'] - person Peter Cordes; 10.09.2017