Why Wouldn't This Code Compile/Build...?

Started by amirdagan, April 21, 2009, 11:35:29 AM

Previous topic - Next topic

amirdagan

On a regular win xp pro pc (pentium 4), - a code that takes date and time from the Real Time Clock and prints it to the scren.
Thanks a lot.
Amir

.386
.model small

.data
   resbeg db 'day, hour, minute, second'
   res db 3 dup (?)
   resend db '$'

.stack
dw 100 dup (?)

.code
start:
; Defines data and code and stack segments.
   mov ax, @data
   mov ds, ax
   mov ax, @code
   mov cs, ax
   mov ax, @stack
   mov ss, ax   

   ; Reads seconds from RTC and puts it in the last index of res.
   mov al, 00h
   out 70h, al
   in al, 71h
   mov res[3], al
   
   mov al, 02h
   out 70h, al
   in al, 71h
   mov res[2], al
   
   mov al, 04h
   out 70h, al
   in al, 71h
   mov res[1], al
   
   mov al, 06h
   out 70h, al
   in al, 71h
   mov res[0], al
   
   ; Prints out entire vector.
   mov dx, offset @data
   mov ah, 9
   int 21h
   
end start

MichaelW

The first problem is the position of the .386 processor directive relative to the .MODEL directive. When a .386 or later processor directive precedes the .MODEL directive it not only enables assembly of the processor's instruction set, but also sets the offset address size to 32 bits, which will not work for 16-bit code. The solution is to place the processor directive below the .MODEL directive.

The second problem is in the code that loads the segment registers. The MOV instruction cannot be used to load the CS segment register, so when the processor attempts to execute:

mov cs, ax

It triggers an invalid opcode exception, and the system pops us a message box stating that the NTVDM CPU has encountered an illegal instruction. Since the program loader takes care of loading the correct segment address into CS, the solution is to simply remove the:

mov ax, @code
mov cs, ax

And since the program loader will also set up a workable stack, you can also remove the:

mov ax, @stack
mov ss, ax

The third problem is that your code is not converting the day, hour, minute, and second values to digits before it attempts to display them. Since the values are Binary Coded Decimal (BCD), where each digit value is represented by 4 bits, the conversion is simple - you isolate each 4-bit value in a byte register and add the ASCII character code for the decimal digit 0 (30h). The following code converts the BCD value less than 100 decimal in AL to two decimal digits, and uses Interrupt 21h function 2 to display the digits.

  push ax         ; preserve AL
  shr al, 4       ; isolate high-order 4 bits
  add al, 30h     ; convert to decimal digit
  mov ah, 2       ; use function 2 to display
  mov dl, al
  int 21h
  pop ax          ; recover AL
  and al, 0fh     ; isolate low-order 4 bits
  add al, 30h     ; convert to decimal digit
  mov ah, 2       ; use function 2 to display
  mov dl, al
  int 21h


And the fourth problem is that your program is not terminating properly. The common way of doing this would be to call Interrupt 21h function 4Ch.
eschew obfuscation