Forums before death by AOL, social media and spammers... "We can't have nice things"
|    comp.lang.asm.x86    |    Ahh, the lost art of x86 assembly    |    4,675 messages    |
[   << oldest   |   < older   |   list   |   newer >   |   newest >>   ]
|    Message 4,389 of 4,675    |
|    luser.droog@nospicedham.gmail.com to luser...@nospicedham.gmail.com    |
|    Re: shorter code to print a 16bit number    |
|    06 Aug 21 22:04:30    |
      From: luser...@nospicedham.gmail.com              On Friday, July 30, 2021 at 12:13:00 AM UTC-5, luser...@nospicedham.gmail.com       wrote:       > I wrote this machine code to trace the LIT word in my forth interpreter.       > Is it possible to tighten up this code? It's trying to print a 16bit signed       > integer (ignoring INT_MIN) left to right with no leading zeros.       >       > This is assembly code, but I hope you'll forgive my ideosyncratic syntax.       > The operands map left to right to the reg and reg/mem fields into the       > mod-reg-reg/mem byte and the opcodes target the "to" form (direction       > field = 1), eg. in "MOV(,R,BX,AX)", BX is the dest, AX is the source, the       > R is needed to select register-to-register mode (the mod field). The empty       > first argument is for tweaks to the opcode which could be F (clear the       > direction field by subtracting 2) or BYTE (clear the word field by       subtracting 1).       >       > It tests each digit for zero where it jumps over the int 10h call except       > the last digit.       >       > It occurs to me that the DIV instruction has a mod field. So that means       > the divisor could be register indirect, right? like through SI or BX, maybe?       > Then it could probably be rolled up in a loop, right? Sorry if I'm jumping       > the gun asking for help before exerting the requisite effort.       >              Thanks for the help, everyone! Thanks to Rudy for pointing out that my       algorithm was malformed. I had tested it (sort of, I ran it and saw that       there was output), but I didn't check it against known values and so       didn't see the problem of suppressing inner zeros. (the numbers it       printed did appear weird, but I didn't properly consider and valuate       that clue).              John's code is so sweet and simple, I am envious of the ability to write       in such a way. I translated it to my syntax and then tried a few of the       variations alluded to earlier, like using BX to point to a table of divisors.       But I haven't actually implemented the LOOP instruction in the emulator       and the syntax I have for using labels in machine code hasn't been       incorporated into the emulator at all yet. So I haven't tested any of the       following code except to run it through CPP to check that macro expansion       works.              First I just translated John's code to my syntax (now with labels) and       lo and behold, it's super short and sweet. Exactly what I asked for.              CODE(lit, (LIT, LODS, PUSH(AX))       #ifdef TRACE        , (PrtNum, TEST(R,AX,AX), JGE, NotNeg-_, \        PUSH(AX), MOVAX(0xE00+'-'), INT(10), POP(AX),       NEG(R,AX)),        (NotNeg, MOVBX(10), XOR(,R,CX,CX)),        (NextDigit, INC(CX), XOR(DX,DX), DIV(BX), PUSH(DX), TEST(AX,AX),       JNZ, NextDigit-_),        (PutDigit, POP(AX), ADDAX(0xE00+'0'), INT(10), LOOP, PutDigit-_)       #endif       )              First I tried doing it with a table of divisors and unrolled code to divide by       each       word in the table.              CODE(lit, (LIT, LODS, PUSH(AX))       #ifdef TRACE        , (stub, sJMP, CODE-_),        (divisors, DW(10000), DW(1000), DW(100), DW(10)),        (CODE, MOVBX(divisors), XOR(,R,DX,DX),        DIV(Z,BX_), ADDAX(0xE00+'0'), INT(10)),        (L1, MOV(,R,AX,DX), DIV(B,BX_),2, ADDAX(0xE000+'0'),       INT(10),        MOV(,R,AX,DX), DIV(B,BX_),4, ADDAX(0xE000+'0'),       INT(10)),        (L2, MOV(,R,AX,DX), DIV(B,BX_),6, ADDAX(0xE000+'0'),       INT(10),        MOD(,R,AX,DX), ADDAX(0xE00+'0'), INT(10))       #endif       )              Which is longer, uglier, replete with repetition.              Then I tried doing it with a table of divisors and a loop to run through       left-to-right.              CODE(lit, (LIT, LODS, PUSH(AX))       #ifdef TRACE        , (tracelit, MOVBX(divisors), XOR(,R,DX,DX), MOVCX(5)),        (digit, DIV(Z,BX_), ADDAX(0xE00+'0'), INT(10),        MOV(,R,AX,DX), ADDI(BX,2), LOOP, digit-_,        NEXT)        (divisors, DW(10000), DW(1000), DW(100), DW(10), DW(1)),       #endif       )              where NEXT is a macro for jumping to the next Forth word, pointed to by SI.       That's pretty short, but it treats all numbers as unsigned and makes       no attempt to suppress leading zeros.              Then I tried without using a table and calling a procedure for each digit.              CODE(lit, (LIT, LODS, PUSH(AX))       #ifdef TRACE        , (tracelit, XOR(,R,DX,DX), MOVCX(5),        TEST(R,AX,AX), JGE,notneg,        MOVI(AX,0xE00+'-'), INT(10), NEG(R,AX), JNO, notneg,        INC(R,DX)),        (notneg, MOVI(BX,10000), DIV(R,BX), CALL, print,        MOVI(BX,1000), MOV(,R,AX,DX), DIV(R,BX), CALL, print,        MOVI(BX,100), MOV(,R,AX,DX), DIV(R,BX), CALL, print,        MOVI(BX,10), MOV(,R,AX,DX), DIV(R,BX), CALL, print,        MOV(,R,AX,DX), CALL, print,        NEXT),        (print, ADDAX(0xE00'0'), INT(10), RET)       #endif       )              It's pretty cool that adding labels also lets me have local procedures,       but I feel like the call instruction vs, the ADD and INT instructions       doesn't really save much and is slower and longer on the screen.       But maybe all that just means that I should be using a DOS string       printing function instead of a character printing function.              And also, Rod was right and this whole effort was a wholy       unnecessary X/Y problem. And if I just add a high-level LIT word,       then I can call U. to print the number be done with this snipe hunt.              On a side note, I stumbled across the source on github for DOS 1.25       and 2.0 and I'm browsing ASM.ASM from 1.25 to get ideas about how to       make an assembler with a more common syntax.              --- SoupGate-Win32 v1.05        * Origin: you cannot sedate... all the things you hate (1:229/2)    |
[   << oldest   |   < older   |   list   |   newer >   |   newest >>   ]
(c) 1994, bbs@darkrealms.ca