title: Assembly A86 - Get and Display Time
body: <p>I am working on an Assembly program to get system time and date, convert it to ASCII, and display it on the monitor. I am having trouble getting it to display properly and cannot find where I've gone wrong. This is for an assignment, and I'd rather have explanations than just solutions, if possible.
  Here is my code:</p>
  
  <pre><code>TITLE GETDTTM
  PAGE 60, 132
  
  ;   This program retrieve the system date and time,
  ;   converts it to ASCII, and displays it to the screen
  
  ;   Define constants
  ;
  CR      EQU 0DH ;define carriage return
  LF      EQU 0AH ;define line feed
  EOM     EQU '$' ;define end of message marker
  NULL    EQU 00H ;define NULL byte
  ;
  ;   Define variables
  ;
  JMP START
  PROMPT  DB  CR, LF, "The current time is: ",EOM
  PROMPT2 DB  CR, LF, "The date is: ",EOM
  TIME    DB  "00:00:00", CR, LF, EOM
  DATE    DB  "00/00/0000", CR, LF, EOM
  ;
  ;   Program code
  ;
  START:  
  CALL GET_TIME   ;call function to get system time
  CALL GET_DATE   ;call function to get system date
  
  LEA DX, PROMPT  ;print time prompt to screen
  MOV AH, 09H
  INT 21H
  
  LEA DX, TIME    ;print time
  MOV AH, 09H
  INT 21H
  
  LEA DX, PROMPT2 ;print date prompt to screen
  MOV AH, 09H
  INT 21H
  
  LEA DX, DATE    ;print date
  MOV AH, 09H
  INT 21H
  
  
  CVT_TIME:   ;converts the time to ASCII
  CALL CVT_HR
  CALL CVT_MIN
  CALL CVT_SEC
  RET
  
  CVT_HR:
  MOV BH, CH  ;copy contents of hours to BH
  SHR CH,4    ;convert high char to low order bits
  ADD CH, 30H ;add 30H to convert to ASCII
  MOV [TIME], CH  ;save it
  AND BH, 0FH ;isolate lower 4 bits
  ADD BH, 30H ;convert to ASCII
  MOV [TIME+1], BH    ;save it
  RET
  
  CVT_MIN:
  MOV BH, CL  ;copy contents of minutes to BH
  SHR CL, 4   ;convert high char to low order bits
  ADD CL, 30H ;add 30H to convert to ASCII
  MOV [TIME+3], CL    ;save it
  AND BH, 0FH ;isolate lower 4 bits
  ADD BH, 30H ; convert to ASCII
  MOV[TIME+4], BH ;save it
  
  CVT_SEC:
  MOV BH, DH  ;copy contents of seconds to BH
  SHR DH, 4   ;convert high char to low order bits
  ADD DH, 30H ;add 30H to convert to ASCII
  MOV [TIME+6], DH    ;save it
  AND BH, 0FH ;isolate lower 4 bits
  ADD BH, 30H ;convert to ASCII
  MOV[TIME+7], BH ;save it
  
  GET_DATE:   ;get date from the system
      MOV AH, 04H    ;BIOS function to read date
      INT 1AH        ;call to BIOS, run 04H
      CALL CVT_DATE
      RET
  ;CH = Century
  ;CL = Year
  ;DH = Month
  ;DL = Day
  ;CF = 0 if clock is running, otherwise 1
  
  CVT_DATE:
      CALL CVT_MO
      CALL CVT_DAY
      CALL CVT_YR
      CALL CVT_CT
      RET
  
  CVT_MO:     ;convert the month to ASCII
  MOV BH, DH  ;copy month to BH
  SHR BH, 4   ;convert high char to low order bits
  ADD BH, 30H ;add 30H to convert to ASCII
  MOV [DATE], BH  ;save in DATE string
  MOV BH, DH  ;copy month to BH
  AND BH, 0FH ;isolate lower 4 bits
  ADD BH, 30H ;convert lower bits to ASCII
  MOV [DATE+1], BH;save in DATE string
  RET
  
  CVT_DAY:    ;convert the day to ASCII
  MOV BH, DL  ;copy days to BH
  SHR BH, 4   ;convert high char to low order bits
  ADD BH, 30H ;add 30H to convert to ASCII
  MOV [DATE+3], BH    ;save in DATE string
  MOV BH, DL  ;copy days to BH
  AND BH, 0FH ;isolate lower 4 bits
  ADD BH, 30H ;convert lower bits to ASCII
  MOV [DATE+4], BH;save in DATE string
  RET
  
  CVT_YR:     ;convert the year to ASCII
  MOV BH, CL      ;copy year to BH
  SHR BH, 4       ;convert high char to low order bits
  ADD BH, 30H     ;convert to ASCII
  MOV [DATE+8], BH    ;save it
  MOV BH, CL      ;copy year to BH
  AND BH, 0FH     ;isolate low order bits
  ADD BH, 30H     ;convert to ASCII
  MOV [DATE+9], BH    ;save in DATE string
  RET
  
  CVT_CT:     ;convert the century to ASCII
  MOV BH, CH      ;copy century to BH
  SHR BH, 4       ;convert high char to low order bits
  ADD BH, 30H     ;convert to ASCII
  MOV [DATE+6], BH    ;save it
  MOV BH, CH      ;copy century to BH
  AND BH, 0FH     ;isolate low order bits
  ADD BH, 30H     ;convert to ASCII
  MOV [DATE+7], BH    ;save it
  RET
  ;
  ;Program End
  ;
  
  End
  </code></pre>
  
  <p>And here's what I get when I run it at 9:11AM on 2/19/2015:</p>
  
  <pre><code>The current time is: 09:00:00
  The date is: 02/09/0005
  </code></pre>
  
  <p>I've tried to add lots of comments of my intentions, so that you can get an idea of what I'm trying to do and easier see if there's some kind of logic error. I think it's pretty clear from the output that I'm missing getting my minutes and seconds into TIME and have some ideas on how to fix that, but after noon, I get some weird times, and I'm confused as to what's happening to my date. Any help is much appreciated.</p>
  
  <p>Edit: Got time to work by splitting it up and actually dealing with minutes and seconds... whoops. Now my output is as follows:</p>
  
  <p>Run at 9:23AM on 02/19/2015</p>
  
  <pre><code>The current time is: 09:23:02
  The date is: 02/09/0005
  </code></pre>
  
  <p>EDIT2: Getting closer! Thanks for the [DATE] catch - I fixed that and am getting correct month and day values, and closer on year values. Figured out I wasn't shifting far enough since year is 4 characters long - 16 bits, not 8! - so I couldn't get the whole thing by only SHR 4 bits! My output now looks like:</p>
  
  <pre><code>The current time is: 09:43:02
  The date is: 02/19/0015
  </code></pre>
  
  <p>EDIT 3: Added CVT_CT to convert the century to ASCII and add it to the [DATE] string, but am still getting the same output...</p>
  
  <pre><code>The current time is: 10:06:02
  The date is: 02/19/0015
  </code></pre>
  
  <p>EDIT 4: I forgot to add a call to my new function... Wow. Working now!!! Thank you all for your help!</p>
  
  <pre><code>The current time is: 10:09:02
  The date is: 02/19/2015
  </code></pre>
  
  <p>Side question: Any idea why the seconds would always be 02?</p>