by Jon Ripley, August 2006
This article documents three routines to output strings and VDU command sequences from assembler:
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
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
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.
RISC OS Programmer's Reference Manual volume 1.