%if 0 2021 by C. Masloch Usage of the works is permitted provided that this instrument is retained with the works, so that any entity that uses the works is notified of this instrument. DISCLAIMER: THE WORKS ARE WITHOUT WARRANTY. %endif %include "lmacros3.mac" cpu 8086 org 256 start: mov bx, 2 baseloop: mov di, buffer mov al, '0' mov cx, 32 rep stosb mov dx, ((1 << 32) - 2 * 36) >> 16 mov ax, ((1 << 32) - 2 * 36) & 0FFFFh mov si, di call dumpdword mov ax, 13 | (10 << 8) stosw mov bp, di .loop: push si push di push bx mov dx, bx call parse xchg dx, bx xchg bx, ax pop bx pop di pop si jnc .next jz basenext .match: push si push di push bx mov ax, bx mov bx, 10 div bl add ax, "00" mov word [msg.match.base], ax mov dx, msg.match mov ah, 09h int 21h mov dx, si mov cx, bp sub cx, dx mov ah, 40h mov bx, 1 int 21h pop bx pop di pop si ; mov ax, 4C01h ; int 21h .next: mov al, bl add al, '0' - 1 cmp al, '9' jbe @F add al, -('9'+1)+'A' @@: lea di, [bp - 2] .incloop: cmp byte [es:di - 1], al jb .incdigit je .nextdigit internalerror: equ $ mov dx, msg.internalerror mov ah, 09h int 21h mov ax, 4CFFh int 21h .nextdigit: dec di mov byte [es:di], '0' jmp .incloop .incdigit: dec di inc byte [es:di] cmp byte [es:di], '9' + 1 jne @F mov byte [es:di], 'A' @@: cmp si, di jb @F mov si, di @@: jmp .loop basenext: inc bx cmp bx, 37 jb baseloop mov ax, 4C00h int 21h align 256 buffer: times 256 db 0 msg: .internalerror: ascic "Internal error!",13,10 .match: db "Match: base=" .match.base: ascic "-- number=" ; INP: si -> number, terminated by 13 (CR) ; dx = base, 2..36 ; OUT: NC no overflow, ; bx:dx = number read ; CY if error, ; ZR if expected error ; NZ if unexpected error ; CHG: ax, bx, cx, dx, si, di parse: lodsb mov ah, 0 ; (not sure why this) xor bx, bx mov di, dx ; di = base mov cl, dl add cl, '0'-1 cmp cl, '9' jbe .lit_basebelow11 mov cl, '9' .lit_basebelow11: ; cl = highest decimal digit for base ('1'..'9') mov ch, dl add ch, 'A'-10-1 ; ch = highest letter for base ('A'-x..'Z') call .lit_isdigit? ; first character must be a digit jc .err2_true xor dx, dx ; initialize value .lit_loopdigit: cmp al, '_' je .lit_skip call .lit_isdigit? ; was last character ? jc .lit_end ; yes --> call uppercase sub al, '0' cmp al, 9 ; was decimal digit ? jbe .lit_decimaldigit ; yes --> sub al, 'A'-('9'+1) ; else adjust for hexadecimal digit .lit_decimaldigit: push ax mov ax, dx push bx mul di ; multiply low word with base mov bx, dx mov dx, ax pop ax push dx mul di ; multiply high word with base test dx, dx pop dx jnz .err2_false_pop ; overflow --> add bx, ax ; add them pop ax jc .err2_false ; overflow --> add dl, al ; add in the new digit adc dh, 0 adc bx, byte 0 jc .match .lit_skip: lodsb jmp short .lit_loopdigit .match: or al, 1 ; NZ stc ; CY retn .err2_false_pop: pop ax .err2_false: cmp al, al ; ZR stc ; CY .retn: retn .lit_end: cmp al, 13 je .retn ; NC .err2_true: jmp internalerror ; none here --> parse.lit_isdigit?: cmp al, '0' jb .no cmp al, cl jbe .yes push ax call uppercase cmp al, ch ja .no_p cmp al, 'A' jb .no_p pop ax .yes: clc retn .no_p: pop ax .no: stc retn uppercase: cmp al, 'a' jb .ret cmp al, 'z' ja .ret add al, -'a'+'A' .ret: retn ; Dump dword as arbitrary base number string ; ; INP: dx:ax = dword ; bx = base ; di -> where to store ; OUT: - ; CHG: di -> behind variable-length string ; STT: UP dumpdword: lframe near lequ 32, bufferlen lvar ?bufferlen,buffer lenter lvar dword, dividend push dx push ax lvar word, base push bx push ax push bx push cx push dx push si push di push es push ss pop es lea di, [bp + ?buffer + ?bufferlen - 1] mov bx, di std ; _AMD_ERRATUM_109_WORKAROUND does not apply ; dx:ax = word to display mov cx, word [bp + ?base] .loop_write: xor dx, dx push di mov di, 4 .loop_divide: mov ax, [bp + ?dividend - 2 + di] div cx mov word [bp + ?dividend - 2 + di], ax dec di dec di jnz .loop_divide ; dx = last remainder pop di xchg ax, dx ; ax = remainder (next digit) ; dword [bp + ?dividend] = result of div add al, '0' cmp al, '9' jbe @F add al, -('9'+1)+'A' @@: stosb cmp word [bp + ?dividend + 2], 0 jnz .loop_write cmp word [bp + ?dividend], 0 ; any more ? jnz .loop_write ; loop --> cld sub bx, di mov cx, bx mov si, di inc si pop es pop di @@: ss movsb ; do not replace by rep ss movsb, because ; some 8086 don't like two-prefix opcodes loop @B pop si pop dx pop cx pop bx pop ax lleave retn ; HEXWORD - Print hex word (in AX). ; HEXBYTE - Print hex byte (in AL). ; HEXNYB - Print hex digit. ; Uses none. hexword: xchg al, ah call hexbyte xchg al, ah hexbyte: push cx mov cl, 4 rol al, cl call hexnyb rol al, cl pop cx hexnyb: push ax and al, 0Fh add al, 90h daa adc al, 40h daa ; these four instructions change to ASCII hex stosb pop ax retn