2016-11-26 1 views
1

Я начинаю, и мне нужна помощь в преобразовании 16-битного двоичного числа в шестнадцатеричное. Я сделал большую часть кода, но мне нужна помощь с несколькими вещами.Преобразование бункера в гексагон в сборке

  1. Как это сделать, только принимать 0 и 1 во входных данных и игнорировать остальные цифры и буквы?
  2. После процесса преобразования я получаю неправильный номер в шестнадцатеричном формате. Что я сделал не так?

Пример входных данных:

Ожидаемые результаты:

ABCD

Выход по току:

AAAC

Вот мой код:

.MODEL SMALL 
.STACK 1000h 

.DATA 
    title db 'Convert BIN to HEX:.',13,10,'$' 
    HEX_Map DB '0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F' 
    HEX_Out DB "00", 13, 10, '$' ; string with line feed and '$'-terminator 

.CODE 

main PROC 
    mov ax, @DATA     ; Initialize DS 
    mov ds, ax 

    mov ah, 0         
    mov al, 3    ;clearing             
    int 10h                 

    mov ah, 9                 
    lea dx, title               
    int 21h  ;displays title 

    mov dx, 0 

loop16:                 
    mov cx, 16 ;loop goes 16 Times because I need 16 bit binary input 
    mov bx, 0 

;here I'm checking if input numer is 0 or 1, but it doesn't work as I want  
read:                  
    mov ah, 10h                 
    int 16h       

    cmp al, '0'                 
    jb read                   

    cmp al, '1'                
    ja read10 



read10:                  
    mov ah, 0eh                 
    int 10h                  
    sub al, 48 ;conversion, sub 48 from ascii since 0 is on 48th place in ascii, but I'm not sure if this part is must to be or not      

    jmp end_loop 

end_loop:                 
    mov ah, 0  ;ah=0 so we can add ax to bx   
    add bx, ax    

    loop read   
    push bx       ;here I push bx on stack, bx is as my input number           

    mov al, 13 
    mov ah, 0eh 
    int 10h 

    mov al, 10 
    mov ah, 0eh 
    int 10h 



    mov di, OFFSET HEX_Out   ; First argument: pointer 
    pop bx       ;Here I take input number from stack 
    mov ax, bx 
    call IntegerToHexFromMap  ; Call with arguments 
    mov ah, 09h      ; Int 21h/09h: Write string to STDOUT 
    mov dx, OFFSET HEX_Out   ; Pointer to '$'-terminated string 
    int 21h       ; Call MS-DOS 

    mov ah, 10h                 
    int 16h 

    mov ax, 4C00h     ; Int 21h/4Ch: Terminate program (Exit code = 00h) 
    int 21h       ; Call MS-DOS 
main ENDP 

IntegerToHexFromMap PROC 
    mov si, OFFSET Hex_Map   ; Pointer to hex-character table 

    mov bx, ax      ; BX = argument AX 
    and bx, 00FFh     ; Clear BH (just to be on the safe side) 
    shr bx, 1 
    shr bx, 1 
    shr bx, 1 
    shr bx, 1      ; Isolate high nibble (i.e. 4 bits) 
    mov dl, [si+bx]     ; Read hex-character from the table 
    mov [di+0], dl     ; Store character at the first place in the output string 

    mov bx, ax      ; BX = argument AX 
    and bx, 00FFh     ; Clear BH (just to be on the safe side) 
    shr bx, 1 
    shr bx, 1 
    shr bx, 1 
    shr bx, 1      ; Isolate high nibble (i.e. 4 bits) 
    mov dl, [si+bx]     ; Read hex-character from the table 
    mov [di+1], dl     ; Store character at the first place in the output string 

    mov bx, ax      ; BX = argument AX 
    and bx, 00FFh     ; Clear BH (just to be on the safe side) 
    shr bx, 1 
    shr bx, 1 
    shr bx, 1 
    shr bx, 1      ; Isolate high nibble (i.e. 4 bits) 
    mov dl, [si+bx]     ; Read hex-character from the table 
    mov [di+2], dl     ; Store character at the first place in the output string 

    mov bx, ax      ; BX = argument AX (just to be on the safe side) 
    and bx, 00FFh     ; Clear BH (just to be on the safe side) 
    and bl, 0Fh      ; Isolate low nibble (i.e. 4 bits) 
    mov dl, [si+bx]     ; Read hex-character from the table 
    mov [di+3], dl     ; Store character at the second place in the output string 

    ret 
IntegerToHexFromMap ENDP 

IntegerToHexCalculated PROC 
    mov si, OFFSET Hex_Map   ; Pointer to hex-character table 

    mov bx, ax      ; BX = argument AX 
    shr bl, 1 
    shr bl, 1 
    shr bl, 1 
    shr bl, 1      ; Isolate high nibble (i.e. 4 bits) 
    cmp bl, 10      ; Hex 'A'-'F'? 
    jl .1       ; No: skip next line 
    add bl, 7      ; Yes: adjust number for ASCII conversion 
    .1: 
    add bl, 30h      ; Convert to ASCII character 
    mov [di+0], bl     ; Store character at the first place in the output string 

    mov bx, ax      ; BX = argument AX 
    shr bl, 1 
    shr bl, 1 
    shr bl, 1 
    shr bl, 1      ; Isolate high nibble (i.e. 4 bits) 
    cmp bl, 10      ; Hex 'A'-'F'? 
    jl .2       ; No: skip next line 
    add bl, 7      ; Yes: adjust number for ASCII conversion 
    .2: 
    add bl, 30h      ; Convert to ASCII character 
    mov [di+1], bl     ; Store character at the first place in the output string 

    mov bx, ax      ; BX = argument AX 
    shr bl, 1 
    shr bl, 1 
    shr bl, 1 
    shr bl, 1      ; Isolate high nibble (i.e. 4 bits) 
    cmp bl, 10      ; Hex 'A'-'F'? 
    jl .3       ; No: skip next line 
    add bl, 7      ; Yes: adjust number for ASCII conversion 
    .3: 
    add bl, 30h      ; Convert to ASCII character 
    mov [di+2], bl     ; Store character at the first place in the output string 

    mov bx, ax      ; BX = argument AX (just to be on the safe side) 
    and bl, 0Fh      ; Isolate low nibble (i.e. 4 bits) 
    cmp bl, 10      ; Hex 'A'-'F'? 
    jl .4       ; No: skip next line 
    add bl, 7      ; Yes: adjust number for ASCII conversion 
    .4: 
    add bl, 30h      ; Convert to ASCII character 
    mov [di+3], bl     ; Store character at the second place in the output string 

    ret 
IntegerToHexCalculated ENDP 

END main       ; End of assembly with entry-procedure 
+0

Я вижу, что вы уже проверяете '0' и' 1' - не так ли получается? Кроме того, пожалуйста, отредактируйте свой вопрос и укажите пример ввода, ожидаемого результата и текущего вывода. – usr2564301

+0

@RadLexus Я только что отредактировал. И нет, это не работает. Когда я пишу буквы и другие числа в качестве входных данных, это позволяет, и я понятия не имею, как сделать это onlly разрешать 0 и 1. – Anna

+1

Можете ли вы добавить комментарий рядом с каждым вызовом прерывания, детализируя, что он делает? Это было давно, так как я знал их наизусть. Кстати, нижняя половина вашего кода очень хорошо прокомментирована. – usr2564301

ответ

3

Вы не можете использовать int 10h (0e) для вывода полукокса, когда вы собираете биты в bx. Для этого требуется intbl для цветного текста переднего плана и bh, чтобы указать на текстовую страницу.

Также в bx вы будете подсчитывать количество единиц, а не номер входа. Попробуйте в отладчике (ваш исходный код), положите точку останова после loop и введите (вслепую, если это не отображается), например «1100110011001100», bx будет 8 (я могу ошибаться, если какой-то звонок int уничтожить bx, я didn «Забери это, как раз в моей голове»).

Таким образом, чтобы исправить входную часть я хотел бы пойти на int 21h, 2 вместо для отображения символов, как это (также устраняет накопление результата в bx):

; read 16 bits from keyboard ('0'/'1' characters accepted only) 
    mov cx, 16 ; loop goes 16 Times because I need 16 bit binary input 
    xor bx, bx ; result number (initialized to zero) 

read: 
    mov ah, 10h 
    int 16h  ; read character from keyboard 

    cmp al, '0' 
    jb read  ; ASCII character below '0' -> re-read it 

    cmp al, '1' 
    ja read  ; ASCII character above '1' -> re-read it 

    mov dl,al ; keep ASCII for output in DL 

    shr al,1 ; turn ASCII '0'(0x30)/'1'(0x31) into CF=0/1 (Carry Flag) 
    rcl bx,1 ; enrol that CF into result from right (and shift previous bits up) 

    mov ah,2 ; output character in DL on screen 
    int 21h 

    loop read ; read 16 bits 

Я не проверял остальную часть код, потому что, если бы я хотел, у меня было бы сильное зуд, чтобы полностью переписать его, поэтому пусть на данный момент встает с входной частью.


отладчик должен позволить вам пошагово одну инструкцию за раз (или поставить точки останова на любой строке, и разбежались до него).

Таким образом, вы можете проверять значения в регистрах и памяти после каждого шага.

Если вы, например, ставить точки останова перед вашим add bx,ax в исходном коде, вы должны быть в состоянии прочитать в отладчик (после удара клавиши «1» и отладчик нарушение на add), что:

ax 1 (в соответствии с нажатой клавишей), а bx переходит от 0 к числу нажатий клавиш «1» (в дальнейших итерациях).

После этого, как четыре нажатия клавиш «1» это должно быть очевидно для вас, что bx равно 4 (0100 в двоичной системе) является далеко от 1111, что-то не работает, как вы хотите, и вы должны перенастроить от «что я хотел написать там» до «того, что я действительно написал», снова прочитайте свой код и поймите, что нужно изменить, чтобы получить ожидаемый результат.

В вашем случае, например, добавление инструкции shl bx,1 перед add исправит ситуацию (перемещение старых бит по одной позиции «вверх», оставив младший значащий бит равным нулю, то есть «готов к добавлению топора»).

Продолжайте упорствовать в работе отладчика, практически невозможно сделать что-либо в сборке без выяснения отладчика. Или продолжайте спрашивать здесь, что вы видите и что вы не понимаете. Это действительно абсолютно необходимо для программирования Assembly.

Другой вариант - просто «эмулировать» процессор в вашей голове и запускать инструкции с экрана с помощью справок (я предлагаю сильно бумагу, ПК как-то не работает для меня). Это намного сложнее и утомительно, чем использование отладчика. Может потребоваться несколько недель/месяцев, прежде чем вы начнете «подражать» без лишних ошибок, поэтому сначала вы обнаружите ошибки, которые возникают при первой попытке. С яркой стороны это даст вам глубокое понимание того, как работает процессор.


О второй части (преобразование числа в шестнадцатеричную строку).

Я попытаюсь помочь вам понять, что у вас есть, и забрать некоторые ошибки из исходного кода, чтобы продемонстрировать, как с ним работать.

Так у вас есть 16 битное число, например:

1010 1011 1100 1101 (unsigned decimal 43981) 

Я ставлю пробелы между каждой группой из 4 бит (редко называют как «грызть»), потому что это смешно факт. Каждый полубайт составляет одну шестнадцатеричную цифру, точно. Таким образом, число выше в шестнадцатеричном:

A B C D  (10, 11, 12, 13) 

Проверьте, как каждая шестнадцатеричная цифра соответствует 4 бита выше.

Итак, вы хотите разбить исходное значение 16b на четыре 4-битных числа, от самых значимых до наименее значимых (b12-b15, b8-b11, b4-b7, b0-b3 => конкретных бит от 16 бит номер: "b15 b14 b13 ... b2 b1 b0").

Каждое такое число будет иметь значение 0-15 (потому что они являются 4 бита, и используя все возможные комбинации), так, то вы хотите, чтобы превратить это в ASCII символ '0' - '9' для значений 0-9 и 'A' - 'F' для значений 10-15.

И каждое преобразованное значение сохраняется в буфере памяти, в следующем положении байта, поэтому в конце они образуют строку «ABCD».

Это может показаться «очевидным», но это полное описание внутреннего расчета части 2, поэтому убедитесь, что вы действительно понимаете каждый шаг, чтобы вы могли в любой момент проверить свой код на это и найти различия.


Теперь я покажу вам некоторые из ошибок, которые я вижу во второй части, пытаясь связать их с теорией выше.

данные и структуры первые:

HEX_Out DB "00", 13, 10, '$' 

Это компилируются в байты: '0', '0', 13, 10, '$' (или 30 30 0D 0A 24, если смотреть в шестнадцатеричных байтах).

Если вы написали 'A', 'B', 'C', 'D' над ним, можете ли вы выявить проблему?

Вы зарезервирован только два байта (от «00») для числа, но вы пишете четыре байта, так и 13 и 10 будут перезаписаны.


Теперь о IntegerToHexFromMap, из кода похоже, вы не понимаете, что and и shr делает (поиск bitwise operations explanation).

Вы извлекаете для первых трех символов те же биты b4-b7 из bx (copy of ax), затем для четвертой буквы вы извлекаете биты b0-b3. Итак, это ваша попытка расширить 8-разрядный код преобразования до 16 бит, но вы не извлекаете правильные биты.

Я попытаюсь подробно прокомментировать первую его часть, чтобы дать вам представление о том, что вы сделали.

; bx = 16 bit value, mark each bit as "a#" from a0 to a15 
    and bx, 00FFh 
; the original: a15 a14 a13 ... a2 a1 a0 bits get 
; AND-ed by:  0 0 0 ... 1 1 1 
; resulting into bx = "a7 to a0 remains, rest is cleared to 0" 
    shr bx, 1 
; shifts bx to right by one bit, inserting 0 into top bit 
; bx = 0 0 0 0 0 0 0 0 0 a7 a6 a5 a4 a3 a2 a1 (a0 is in CF) 
    shr bx, 1 
; shifts it further 
; bx = 0 0 0 0 0 0 0 0 0 0 a7 a6 a5 a4 a3 a2 (a1 is in CF) 
    shr bx, 1 
; bx = 0 0 0 0 0 0 0 0 0 0 0 a7 a6 a5 a4 a3 (a2 ...) 
    shr bx, 1 
; bx = 0 0 0 0 0 0 0 0 0 0 0 0 a7 a6 a5 a4 

; so if bx was value 0x1234 at the beginning, now bx = 0x0003 

; conversion to ASCII and write is OK. 

Итак, вы берете бит b4-b7 для первого символа, но вам нужны биты b12-b15. Я надеюсь, что вы полностью получите это, я знаю, что с самого начала может быть запутанным, какой бит есть и почему иногда есть что-то справа, а затем и слева.

Бит обычно называют из наименее значимого (значения 2 = 1, так что называть его «b0») до наиболее значимого (значения 2 = 32768, в случае 16-битового числа, я называю это " b15").

Но по числовым соображениям биты записываются от наиболее значимых до наименее значимых (в двоичных числах), поэтому бит в «левом» начинается с b15, а бит «справа» заканчивается на b0.

Смещение вправо означает, что для перемещения b_i к B_ (I-1), который эффективно половинки его значение, поэтому shr value,1 можно рассматривать и как беззнаковое деление на два.

Переход к слева от b_i к B_ (I + 1), эффективно умножает значение на два (инструкции shl и sal, как производить такой же результат, как и b0 устанавливается в ноль с обоими).

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

Кстати, с 80286 CPU вы можете использовать shr bx,4 (что также можно рассматривать как деление на 16 = 2 * 2 * 2 * 2). Вы действительно вынуждены кодировать для 8086? Тогда может стоить загрузить cl с 4 и сделать shr bx,cl, вместо четырех shr bx,1. Это раздражает меня, четыре идентичные строки.

Кроме того, если вы уже понимаете, что and делает, это должно выглядеть смешно вам:

and bx, 00FFh ; why not 0Fh already here??? 
    and bl, 0Fh 

Теперь лицезреть на некоторое время, как извлекать биты b12-b15 для первого символа и как исправить IntegerToHexFromMap.


И в конечном счете, я покажу вам, как я бы переписать его, чтобы иметь код очень короткий, я имею в виду источник, но и бинарный формат. (для производительности я бы написал другой код, а не для 8086, но этот должен работать на 8086):

ПРЕДУПРЕЖДЕНИЕ. Постарайтесь самостоятельно исправить свою версию выше. Только когда у вас будет исправленная версия, посмотрите на мой код, как вдохновение для новых идей, как некоторые вещи были написаны 30 лет назад. Также, если вы проводите школьную аттестацию, убедитесь, что вы можете сказать все о инструкции XLAT от руководителя, потому что в качестве лектора я был бы очень подозрительным в отношении любого учащегося, использующего этот, это общая история, и поскольку компиляторы не используют его, это очевидно код был написан человеком, и, вероятно, был опытным.

IntegerToHexFromMap PROC 
    ; ax = number to convert, di = string buffer to write to 
    ; modifies: ax, bx, cx, dx, di 

    ; copy of number to convert (AX will be used for calculation) 
    mov dx, ax 
    ; initialize other helpful values before loop 
    mov bx, OFFSET HEX_Map ; Pointer to hex-character table 
    mov cx, 00404h   ; for rotation of bits and loop counter 
     ; cl = 4, ch = 4 (!) Hexadecimal format allows me 
     ; to position the two "4" easily in single 16b value. 

FourDigitLoop: ; I will do every digit with same code, in a loop 
    ; move next nibble (= hexa digit) in DX into b0-b3 position 
    rol dx, cl 
    ; copy DX b0-b3 into AL, clear other bits (AL = value 0-15) 
    mov al, dl 
    and al, 0Fh 
    ; convert 0-15 in AL into ASCII char by special 8086 instruction 
    ; designed to do exactly this task (ignored by C/C++ compilers :)) 
    xlat 
    ; write it into string, and move string pointer to next char 
    mov [di],al 
    inc di 
    ; loop trough 4 digits (16 bits) 
    dec ch 
    jnz FourDigitLoop 

    ret 
IntegerToHexFromMap ENDP 

Если вы будете просто использовать этот код без понимания того, как это работает, бог убивает котенка ... Вы не хотите, верно?

Окончательный отказ от ответственности: у меня нет 16-битной среды x86, поэтому я написал весь код без тестирования (иногда я пытаюсь его скомпилировать, но синтаксис должен быть похожим на NASM, поэтому я не делаю этого для этих источников MASM/TASM/emu8086). Таким образом, могут возникнуть некоторые ошибки синтаксиса (возможно, даже функциональная ошибка?: -O), если вы не сможете заставить ее работать, комментируйте.

+0

Большое вам спасибо! Это действительно помогло мне, теперь я больше понимаю, как это работает. I знаете, что вы сказали, что вторая часть - переписать, но не могли бы вы помочь с этим? Я хотел сделать преобразование в цикле, чтобы он повторял 4 раза, поскольку двоичный номер 16 бит, но я не знаю, как начать. – Anna

+0

@ Анна ответ продлится .. о том, «как начать». Сначала вы пишете на человеческом языке, что вы хотите сделать. Затем попробуйте почистить его пополам в более простой и si mpler, пока они не начнут напоминать простые шаги вычисления. Петля 4 раза? «1) counter = 4, 2): 3) счетчик декремента и перейти к метке, если не ноль» -> готов к написанию кода.Первая часть ответа «часть 2» показывает, как вы можете рассматривать «16 бит в 4x 4 бит» на английском языке. ... также **, пожалуйста, продолжайте пытаться запустить все в отладчике ** и исследовать его части, чтобы вы могли смотреть CPU, какая инструкция меняет что. – Ped7g

+0

@ Анна и начните использовать инструкцию по использованию инструкции, чтобы прочитать о каждой инструкции, что она делает. Это самый простой способ узнать, почему «эта инструкция произвела отличный результат, чем я ожидал, WTF?». (Я использую google с инструкцией '' x86 <имя инструкции> '' строка поиска, а затем ищите сайты со знакомым доменом, например «renejeschke» и некоторые другие). – Ped7g

Смежные вопросы