Replying to a message of Darryl Gregorash to Benjamin L Mcgee:
Here are the problems with the read_char function that I mentioned in the
previous msg to James. First, the function makes no attempt to return any
error condition if called with an empty queue. Secondly, and far more
important, the actual value stored in BUF_HEAD after a character is read is
absolutely wrong.
read_char proc far
...
lds si, BUF_PTR ; load far pointer to BUFFER
add si, BUF_HEAD ; and ensure DS:SI points to next character to
read
lodsb ; read the character into AL and increment SI
cmp si, LEN
jb no-wrap ; if SI >= LEN, we must wrap to the head of the
; physical buffer
sub SI, LEN ; perform the wrap by subtraction
no-wrap:
mov BUF_HEAD, si ; save the incremented buffer pointer index
...
Cute; at this point, SI contains (OFFSET BUF_PTR) + BUF_HEAD + 1.. comparing
SI with LEN is ridiculous, plus that offset must be subtracted from SI before
the data is stored.
read_char endp
There are several ways to achieve this. Possibly the easiest is to increment
BUF_HEAD directly in memory before the CMP si, LEN instruction, then subtract
LEN directly from BUF_HEAD if a wrap condition has occurred. This probably
means the way the LDS instruction is used here is inefficient or else the
LODS instruction should not be used, but I make no attempt right now to
improve things in this regard. I'll take a closer look at this later.
lodsb ; read the character into AL and increment SI
inc BUF_HEAD
cmp BUF_HEAD, LEN
jb no-wrap ; if BUF_HEAD >= LEN, we must wrap to the head
of the
; physical buffer
sub BUF_HEAD, LEN ; perform the wrap by subtraction
no-wrap:
...
Note that the MOV BUF_HEAD, si instruction now becomes unnecessary. Here is
the complete corrected (I hope :) ) function:
BUF_PTR DD
BUF_HEAD DB 0
BUF_TAIL DB 0
LEN EQU
BUFFER DB LEN DUP 0
read_char proc far
; uses EAX
; returns: carry clear with character read returned in AL, if no error
carry flag set, if queue empty when function called
cmp BUF_HEAD, BUF_TAIL ; check if buffer empty
je empty ; do not read character if buffer empty
push ds ; preserve DS:SI
push si
lds si, BUF_PTR ; load far pointer to BUFFER
add si, BUF_HEAD ; and ensure DS:SI points to next character to
read
lodsb ; read the character into AL and increment SI
inc BUF_HEAD
cmp BUF_HEAD, LEN
jb no-wrap ; if SI >= LEN, we must wrap to the head of the
; physical buffer
sub BUF_HEAD, LEN ; perform the wrap by subtraction
no-wrap:
pop si ; restore registers
pop ds
clc
retf
empty:
stc
retf
read_char endp
--- FleetStreet 1.21 NR
---------------
* Origin: BIG BANG Burger Bar: Regina SK Canada (1:140/86)
|