by Jon Ripley, August 2006

This article documents three routines to output strings and VDU command sequences from assembler:

  • Write0 - Output a NULL terminated string
  • WriteN - Output a known length string
  • WriteS - Output an in-line string

Output a NULL terminated string


The subroutine below outputs a NULL terminated string to the active output stream. The string must be terminated by ASCII character zero:

      ;
      ; Write0 - write NULL terminated string to active output stream
      ; eax - pointer to NULL terminated string
      ; On exit:
      ;   eax = pointer to end of string + 1
      ;   Corrupts flags
      ;
      .Write0
      push edx            ; store edx
      mov edx,eax         ; edx = pointer to string
      .Write0_lp
      mov al, [edx]       ; read character from string
      inc edx             ; move to next character
      cmp al,0            ; is it the terminating character?
      jz Write0_end       ; yes, exit routine
      call "oswrch"       ; output character
      jmp Write0_lp       ; jump to start of loop
      .Write0_end
      mov eax,edx         ; preserve current string pointer
      pop edx             ; restore edx
      ret                 ; return

If the string address is constant use code similar to the following:

      mov eax, Str        ; load pinter to string
      call Write0         ; output string
      ret                 ; return
      .Str
      db "Hello world!"   ; the string
      db 0                ; terminating character

If the string is pointed to by a BASIC variable use code similar to the following. The BASIC variable should be an integer:

      mov eax, [^Str%]    ; load pointer to string (current value of BASIC variable Str%)
      call Write0         ; output string
      ret                 ; return

Output a known length string


The previous routine suffers from the problem that it cannot output any strings containing ASCII character zero as this is the terminator. However when sending characters to the VDU driver for graphics operations it is sometimes required to include character zero in the command sequence. This alternative routine is used to print any string where the length is known:

The subroutine below outputs a known length string to the active output stream:

      ;
      ; WriteN - write string to active output stream
      ; eax - Pointer to string
      ; ecx - Number of characters to write
      ; All registers preserved, corrupts flags
      ;
      .WriteN
      jecxz WriteN_end    ; if (ecx=0) there are no characters to write
      push eax            ; store eax
      push ecx            ; store ecx
      push edx            ; store edx
      mov edx, eax        ; edx = pointer to string
      .WriteN_lp
      mov al, [edx]       ; read character
      inc edx             ; move to next character
      call "oswrch"       ; output character
      loop WriteN_lp      ; loop while there are characters to write
      pop edx             ; restore edx
      pop ecx             ; restore ecx
      pop eax             ; restore eax
      .WriteN_end
      ret                 ; return

If the string address is constant use code similar to the following:

      mov eax, Str        ; load pointer to string
      mov ecx, 12         ; load length of string
      call WriteN         ; output string
      ret                 ; return
      .Str
      db "Hello world!"   ; the string

If the string pointer is variable use code similar to the following. The BASIC variable should be an integer:

      mov eax, [^Str%]    ; load pointer to string (current value of BASIC variable Str%)
      mov ecx, 12         ; load length of string
      call WriteN         ; output string
      ret                 ; return

To print a BASIC string use the following code:

      mov eax, [^my$]     ; read current string address
      mov ecx, 0          ; clear ecx register
      mov cx, [^my$+4]    ; read length of string
      call WriteN         ; output string

Output an in-line string


The subroutine below outputs an in-line NULL terminated string to the active output stream. The string must be terminated by ASCII character zero:

      ;
      ; WriteS - write in-line NULL terminated string to active output stream
      ; All registers preserved, corrupts flags
      ;
      .WriteS
      xchg eax,[esp]      ; store eax, read pointer to in-line string
      call Write0         ; write string, set eax to new return address
      xchg eax,[esp]      ; restore eax, store return address
      ret

This routine is useful for embedding fixed prompts and messages in programs, such as:

      call WriteS         ; output in-line string
      db "Press any key to continue."  ; the in-line string
      db 0                ; terminating character
      call "osrdch"       ; wait for key press
      ret                 ; return

Note: The routines Write0 and WriteN may be called from BASIC for testing purposes, however WriteS is designed to be called only from assembler. Calling WriteS from BASIC will cause undefined behaviour to occur and may crash BASIC.

References


RISC OS Programmer's Reference Manual volume 1.