0

Oh boy... Where do I even begin? I have tried COUNTLESS times to get a simple program that calculates the surface area of a box (in only 4 or less multiplication steps) and returns the total area. I have tried defining the program with the main variables being words, and then again being bytes. but no matter what, I keep getting an answer that does not match up. my program contains no errors or warnings, so that is a good sign so far. I've tried signed and unsigned multiplication, but nothing seems to quite work. I can't use double words unfortunately as I do not have the right software the following is my program:

INCLUDE io.h

Cr        EQU  0DH       ; carriage return
Lf        EQU  0AH       ; line feed

TheStack  SEGMENT STACK
          DW   100H DUP (?)
TheStack  ENDS

Data      SEGMENT
a     Dw ?
b     Dw  ?
c     Dw  ?
d         Dw  ?
f         Dw  ?
g         Dw  ?
h         Dw  ?
e     dw   '2'
Int1      db   6 DUP (?), 0
Int2      db   6 DUP (?), 0
SUM       Db   6 DUP (?), 0
Int3      Db   6 DUP (?), 0
Prompt1   DB   'Please enter the height:  ', 0
Prompt2   DB   Cr, Lf, 'Enter the width:  ', 0
Prompt3   DB   Cr, Lf, 'Enter the length:  ', 0
String    DB   40 DUP (?)
Label1    DB   Cr, Lf, 'The sum is '
result1   DB   10 DUP (?), 0

Data      ENDS

Code      SEGMENT
          ASSUME Cs:Code, Ds:Data

Start:    Mov Ax, SEG Data    ; Load Data Segment Number.
          Mov Ds, Ax

Prompt:   Output Prompt1      ; Prompt for first number.
          Inputs String, 40   ; Read the ASCII characters.
          AToI String         ; Convert ASCII to Integer.
          Mov a, ax; Store first number.
          Output Prompt2      ; Prompt for second number.
          Inputs String, 40   
          AToI String
          Mov b, dx ; Store second number. 
          Mul dx; Add second number.
      mov d, ax
      itoa result1, ax
      output result1  
          Output Prompt3
      Inputs String, 40   
          AToI String
          Mov c, Dx ; Store second number
      Mul dx; Add second number.
      mov f, dx
      output f
      Mov b, dx
      Mov c, ax
      mul dx
      mov g, ax
      ATOI g
          mov g, ax
      ATOI f
          mov f, ax
      ATOI d
          mov d, ax
      add ax, f
      add ax, g
      mov h, ax
      output h
      AToI e
      mov e, ax
      mov h, dx
      mul dx
      itoa result1, ax
      output result1  


Quit:     Mov Al, 0           ; Put return code of zero in Al.
          Mov Ah, 4CH         ; Put DOS function call in Ah.
          int 21H             ; Call DOS

Code      ENDS
          END  Start

I do apologize for the bad explanations in the code as I've copied the jist of it from previous program. now what I don't understand is how some perfectly defined variables can return incorrect values. I've even changed variables around, but I still have not had luck. This is both confusing, and annoying. To put it in perspective, when I try to multiply 1 times 1, the returned value is 402, which is way off! I am new to programming in assembly, so I do believe that part of this is due to inexperience. My question is how does this error free program end up returning wrong values when it is seemingly put together correctly and checked over numerous times for errors? Is there a missing piece? Do I need to re-write it entirely? Is it the emulator's fault? What is it that is wrong with the code that causes what seems like a perfect program to not work right?

  • 1
    Use a debugger so you can single-step through it and examine registers/memory. Do your `ATOI`, `itoa`, or `output` functions save/restore DX? I think I see at least one case where you use DX right after calling `output`. In most calling conventions, DX is not call-preserved. You don't show code for them, or say what library they come from. – Peter Cordes Oct 24 '16 at 08:18
  • If your program only reads two numbers from the user, why does it call ATOI more than twice? Just convert everything to integer right after reading it. Then you can keep stuff in registers without a bunch of function calls and loads/stores in between your math. (On a modern CPU, a store/reload round-trip takes about 5 cycles, which is more than a multiply. Caring about the number of multiplies is basically irrelevant compared to the amount of stuff this code is doing :P) – Peter Cordes Oct 24 '16 at 08:23
  • 1
    You realize that multiplying two 16 bit values returns a 32 bit value and multiplying two 8 bit values returns a 16 bit value? You should probably have a close look at the documentation for `MUL` and `IMUL` and make sure that you're not inadvertently leaving data behind. – David Hoelzer Oct 24 '16 at 11:17

1 Answers1

0

from what i see, a box has 6 sides, 2 of each are equal size:

2 squares x by y
2 squares x by z
2 squares y by z
the box's surface is the sum of all

so all you have to is:

store the entered lengths to [side_x], to [side_x] and [side_z]. Then calculation of the sum of all 3 pair of squares could look like this (it's all but optimized)

start: mov ax,[side_x]          ; side x*y
       mov bx,[side_y]
       mov dx,0
       mul bx
       shl ax,1                 ; 2 times
       mov [box_size],ax

       ; + 2 sides x*z
       mov ax,[side_x]         
       mov bx,[side_z]
       mov dx,0
       mul bx 
       shl ax,1
       add ax,[box_size]
       mov [box_size],ax

       ; + 2 sides y*z
       mov ax,[side_y]         
       mov bx,[side_z]
       mov dx,0
       mul bx
       shl ax,1
       add ax,[box_size]
       mov [box_size],ax

then print out [box_size] and you're done

note: of course this only works when the box's size fits a 16 bit register (< 65536), so the "upper part" of the multiplication (in dx) is ignored

Tommylee2k
  • 2,683
  • 1
  • 9
  • 22
  • I've tried this and even afterwards, I'm still not getting the correct value returned. I'm supposed to prompt the user for the sizes then multiply them. I'm not even sure what I'm doing wrong! I feel like I'm just running around in circles. – john erikson Oct 24 '16 at 13:34
  • scratch that, i just tried it with pre-defined variables and it works. but not with variables that i want to be defined via prompt. Strange. Wonder what I'm doing wrong. – john erikson Oct 24 '16 at 13:39
  • aha! Found out what i did wrong! It was right under my nose! I put the third prompt in too early. Now, why in the world did i miss that? lol – john erikson Oct 24 '16 at 13:41
  • no wait, never mind I still had them predefined. Shoot... Seems like dosbox is being a big pain for no entire reason. I've put the following before each new side: – john erikson Oct 24 '16 at 13:43
  • output prompt3 Inputs String, 40 ; Read the ASCII characters. AToI String – john erikson Oct 24 '16 at 13:43
  • Note: prompt3 changes to prompt2 or prompt1 for x and y respectively – john erikson Oct 24 '16 at 13:44
  • `mov dx,0` / `mul bx`: DX is a write-only operand for MUL. [Were you thinking of DIV](http://stackoverflow.com/questions/36464879/when-and-why-do-we-sign-extend-and-use-cdq-with-mul-div)? Also, you could just use `mov ax,[side_x]` / `mul [side_y]`, if you aren't going to bother keeping side_y around in BX for the z * y multiply. Why do people love to write code with so much redundant loading and storing, instead of keeping data live in registers? – Peter Cordes Oct 24 '16 at 14:10
  • Similarly, you can factor out the multiply by 2, and do one SHL at the end. – Peter Cordes Oct 24 '16 at 14:12
  • @PeterCordes: mind the `"(it's all but optimized)"` there's a lot of crap, and i intentionally left it in ... it's a homework and i'll not present him a perfect code to just copy&paste it ;-) so: no xor, no `mul (word ptr) [size_x]` (my assembler wont accept it without size). no efficiency, no variable avoiding in registers – Tommylee2k Oct 24 '16 at 14:18
  • Ah I missed that. I think you mean "anything but optimized", though. (And yes, I forgot the `word` in my `mul` instruction.) But why do you mention no XOR? Nothing needs zeroing at all here. You've introduced extra inefficiency that the OP's code didn't have. (Although now that I look, it's pretty suspicious that the OP's code did stuff like CALL something / `Mov c, Dx` / `mul dx`, as if the function returned two values... The only instructions with DX as a destination operand are MUL, and DX is read before the first MUL) – Peter Cordes Oct 24 '16 at 14:27