0

I currently got an assignment where I have to code in assembly language where you take user input to get a 4 digit hexadecimal value and convert it into binary and then after you get the binary value you have to convert it into a month day and year, where the first 7 digits would be the year, the next four are the month, and the last 5 are the day.

I have everything converted into binary and have an idea of how to get it from binary into normal integer values for the year, month and day. When I run my code the output is 0/0/0. I'm not sure if it is where I messed up with my shifting or something else. Could you guys take a look and give me an input on where to correct? In the code that I'm pasting, I'm only putting up to calcYear and figured I can figure that out and then work on the rest from there.

My code:

firstLine:

    call crlf
    mov si, offset programOne
    mov cx, programOneLen
    call putStrng       ;displays 'Program by Joe Remaklus'

    call crlf
    call crlf

    call inputVal   ;prompt for hex input
    call putBin ;display the value in AX as binary
    call crlf
    call calcYear   ;display the year of the first 7 binary digits.
    mov si, offset slash
    mov cx, slashLen
    call putStrng
    call calcMonth  ;display the month of the next 4 binary digits.
    mov si, offset slash
    mov cx, slashLen
    call putStrng
    call calcDay    ;display the day of the next 5 binary digits.
    call crlf

    call inputVal
    call putBin






    mov ah,04c
    int 021




prompt db 'Enter a 4-digit hex value'

lenPrompt = $-prompt


inputVal:

    push si, cx

    mov  si, offset prompt

    mov  cx, lenPrompt

    call putStrng

    call crlf

    call getHex

    call crlf

    pop  cx, si

    ret
;---------------------------------------------------------------

putBin:

    push ax, cx, dx

    mov  cx, 16     ;number of bits to display

  putBinLoopTop:

    mov  dl, '0'        ;assume bit to display is zero

    shl  ax, 1      ;shift bit to display into Carry Flag

    jnc  putBinSkipInc  ;if the top bit was zero skip the inc

    inc  dl         ;else inc DL to '1'

  putBinSkipInc:

    call putChar        ;display the character in DL

    loop putBinLoopTop  ;continue until 16 bits are displayed

    pop  dx, cx, ax

    ret
;---------------------------------------------------------------

calcYear:

    mov year, 0

    mov si, 0

    shl ax, 1
    adc si, 0
    iMul onetwoeight
    add year, si
    mov si, 0 

    shl ax, 1
    adc si, 0
    iMul sixfour
    add year, si
    mov si, 0

    shl ax, 1
    adc si, 0
    iMul threetwo
    add year, si
    mov si, 0

    shl ax, 1
    adc si, 0
    iMul sixteen
    add year, si
    mov si, 0

    shl ax, 1
    adc si, 0
    iMul eight
    add year, si
    mov si, 0


    shl ax, 1
    adc si, 0
    iMul four
    add year, si
    mov si, 0


    shl ax, 1
    adc si, 0
    iMul two
    add year, si
    mov si, 0


    shl ax, 1
    adc si, 0
    iMul one
    add year, si
    mov si, year
    add si, 1980
    call putPos
ret
Michael Petch
  • 46,082
  • 8
  • 107
  • 198
jbr012
  • 13
  • 3
  • Did you single-step this in a debugger to make sure values in regs are what you expect? You're right that `shl ax` / `adc si, 0` is equivalent to testing a bit in ax and then using `setcc`. (e.g. `xor dx,dx` / `bt ax, 3` / `setc dl`, except this doesn't modify `ax`) I'm not at all confident that your `imul`s make sense. Maybe it's a really round-about way of doing something, but I haven't figured out what. You know multiplying by powers of 2 is the same as shifting, right? Also, you could keep `year` in `si` the whole time, instead of using a memory destination all the time. – Peter Cordes Apr 28 '16 at 03:46
  • downvoted for lack of comments in the code or description of what algorithm exactly the year calc is supposed to be implementing. It looks like some kind of weird adding the bits, to me (popcnt). Also for not having a minimal example that just demonstrates the problem you're having. That's still a lot of code. If you improve the question, leave a reply and I may remove my downvote. – Peter Cordes Apr 28 '16 at 03:52
  • 1
    No. Use a debugger to determine where your code is going wrong and if you can't see why that specific behavior is happening, ask again with something more specific than, "...input on where to correct." – David Hoelzer Apr 28 '16 at 11:24

1 Answers1

1

If I understand you correctly, at entry of calcYear your "ax" looks like this in binary: yyyy yyym mmmd dddd

And you want to extract the values back to ordinary numbers. I think I can understand your idea of "calcYear", but I'm sorry to not bother to try to fully understand it and fix it. If you are still curious, just use debugger to single step over each instruction and see where it goes south.

I will instead show you how to think about this problem differently.

Let's try to dig trough and understand this:

    ; ax is encoded as this: yyyy yyym mmmd dddd
    push ax
    push ax ; store the encoded value at stack twice
    ; extract "day" value
    and ax,01Fh  ;only "d" bits will survive
    mov [day],ax
    ; extract "month" value
    pop ax ; restore encoded input
    shr ax,5 ; shift ax by number of "d" bits
    and ax,0Fh ; only shifted "m" bits
    mov [month],ax
    ; extract "year" value
    pop ax ; restore encoded input
    shr ax,5+4 ; shift ax by number of "d" and "m" bits
    ; no need to "and", as "shr" did fill upper bits by zeroes
    add ax,1980 ; so "0" encoded year is 1980? (deducted from OP source)
    mov [year],ax
    ret

I hope this will give you some new ideas, how to work with particular bits in number. Keep in mind and/or are good to mask out things you are interested in and shr/sar/sal/shl/ror/rol/rcr/... are good to put it in desired position. xor may be used to somewhat patch the result (if needed), test is like and but getting only flags register update, and then there are some more bit oriented x386+ (or 486?) instructions, which are somewhat "advanced" and can save you some 2-3 instruction combinations of those basics I mentioned before. So you can safely ignore them, as long as you understand fully those basic ones and can bend anything with them as desired.

Ped7g
  • 16,236
  • 3
  • 26
  • 63
  • And in case you are curious how I thought about the problem... unfortunately I did show you only half of magic, that's the very first line: `; ax is encoded as this: yyyy yyym mmmd dddd` = 1) make sure you understand what are your input data. The hidden second half of magic is 2) to be fully aware of desired output data, in this case I wanted to get `year = 0yyy yyyy, month = 0000 mmmm, day = 000d dddd` ... then I started to think how to move those bits around and extract them by masking to get the desired output. Make sure you are fully aware of the **goal**, then find algorithm to do it. – Ped7g Apr 28 '16 at 11:40
  • And final note... if you are student, you may wonder why `and ax,01F` (why I use hex way of 31)... because after years of ASM programming I can almost see the bits in the hex numbers, so for example AA is nice "1010 1010" pattern... Just keep in mind that every 4 bits (sometimes called a "nibble") form up a single hex digit, so calculating hex value from long binary number is for human actually easier, than trying to calculate decimal value, which involves lot of multiplying and adding. So when I write "and reg, MASK", and I know value of MASK in binary, I just write it in hex from head. – Ped7g Apr 28 '16 at 11:50
  • Not upvoting because of your crazy suggestion to `push ax` twice. How about pushing once, then just loading instead of `pop`ing? Or better yet, copy it to another register. Otherwise, pretty good answer, but these code-dump questions don't add much value to SO for future readers. – Peter Cordes Apr 28 '16 at 16:03
  • @PeterCordes out of curiosity, what's so crazy about `push`/`pop`? I mean: that's what stack was introduced for (in theory of programming), to store temporary values. Of course cloning the value into other register should be performance-wise much faster on current CPU (as it doesn't involve any memory manipulation), maybe even simpler to read/understand in the source, but... Please note my example doesn't pollute any other register (works solely with `ax`), which may be interesting lesson on it's own, and also it should push the student to learn more about `push`. ;) – Ped7g May 03 '16 at 10:18
  • 1
    My main objection is that you push *twice*, instead of `push` / `mov ax, [bp-?]` / `pop ax`. Oh, I guess you avoided wasting instructions on a stack frame, and 16bit can't use `[sp]`... Still, not a fan of the coding style that avoids using scratch registers. Learning about call-preserved registers vs. call-clobbered regs that functions can use for scratch space is valuable. I have to admit that your extra `push` is also better than using memory destinations all over the place would be. – Peter Cordes May 03 '16 at 14:27
  • 1
    I don't think this question should have been answered at all. It's not a minimal example of the problem the OP is having, and I don't think it's going to have much future value for future SO readers, so it's just taking up space. Answering bad questions only encourages people to keep asking them. I also have to admit that I do tend to leave comments with some minor help before downvoting and voting to close. But complete working solutions are definitely too much for some questions. Anyway, have an upvote for not wasting instructions making a stack frame. – Peter Cordes May 03 '16 at 14:34
  • Thanks for the explanation. I tend to not use [bp-?] notation too much, as when I was doing Z80 and x86 assembly, I was doing whole apps in asm only, not interacting with other languages, so I didn't use the "stack frame" at all (and usually I handled parameters over in registers). BTW, that was *crazy*, but somehow I didn't mind it back then (when all you know is "insane", insane looks quite normal to you :) ... then I learned some higher level languages, OOP, more theory, etc... and suddenly 700kB single .ASM file looked a bit weird). – Ped7g May 05 '16 at 12:48
  • BTW, there are whole high level languages, where "stack" (and pushing/poping values ahead of sub routines) is the main work bench, this pushing value ahead (and building input stack) idea comes from there probably. I never wrote anything serious in those languages (forth family?), but learning about them allowed me sometimes to use those ideas. – Ped7g May 05 '16 at 12:52