Sample solution to assignment 5
.seg "bss"
.global _buf
.common _buf, 4096
.seg "text"
.align 4
.proc 4
.global _main
_main:
save %sp, -96, %sp
!! l7 -> buffer base
!! l6 -> buffer end
!! l5 -> wrap-around flag
!! l0 -> current read pointer
set _buf, %l7
set _buf+4096, %l6
set 0, %l5
!! The read loop tries to read as many characters at one time
!! as possible. %l0 = %o1 points somewhere into _buf, and %o2
!! is set to the number of characters in _buf starting from
!! %o1. %l0 is then adjusted according to the result of the call
!! to _read.
rloop0:
mov %l7, %l0
rloop:
subcc %l6, %l0, %o2 ! space for how many chars left?
bz,a rloop0 ! none -> reset read pointer?
add %g0, 1, %l5 ! remember having wrapped around (delay slot)
set 0, %o0 ! stdin
call _read
mov %l0, %o1 ! current read position (delay slot)
cmp %o0, %g0 ! EOF?
be eof
nop
ba rloop ! one more round
add %o0, %l0, %l0 ! adjust current read position (delay slot)
eof:
!! now: l0 -> circular buffer end
!! must arrange: l1 -> circular buffer start
cmp %l5, %g0 ! wrapped around while reading?
bne wrapped
nop
cmp %l0, %l7 ! read anything at all?
be ret ! no -> return right away
nop
!! no wrap -> circular buffer starts at %l7
ba lastchar
mov %l7, %l1
wrapped:
!! wrapped -> circular buffer starts where it ends (mod 4096)
mov %l0, %l1
cmp %l1, %l6
bge,a lastchar
mov %l7, %l1
lastchar:
!! l2 -> inspected location, starts from end (%l0)
!! l3 -> newline counter
!! l4 -> holds character for inspection
!! Must find the 23rd newline or the beginning of the circular
!! buffer.
!! If last char isn't \n, then counter %l3 starts at 1 instead of 0.
mov %l0, %l2 ! start at the end of circular buffer
ldsb [%l2-1], %l4 ! inspect last character
cmp %l4, 10 ! newline?
be sloop ! yes -> goto scan-loop
clr %l3 ! initialize newline counter (delay slot)
add %l3, 1, %l3 ! newline counter <- 1 (incomplete last line)
sloop:
!! Scan-loop.
!! This is a do-style loop (we know there is at least one char!).
sub %l2, 1, %l2 ! decrement current location pointer
cmp %l2, %l7 ! adjust (wrap around) if necessary
bl,a L
sub %l6, 1, %l2
L: ldsb [%l2], %l4 ! look at current char
cmp %l4, 10 ! newline?
bne boundscheck ! no -> see if at beginning of buffer
nop
add %l3, 1, %l3 ! yes -> increment newline counter
cmp %l3, 23 ! hit 23rd newline?
bl boundscheck ! no -> see if at beginning of buffer
nop
ba found ! yes -> skip this newline character
add %l2, 1, %l2
boundscheck:
cmp %l2, %l1 ! hit beginning of circular buffer?
bne sloop ! no -> keep going
nop
found:
!! l2 -> beginning of segment to be printed
!! l0 -> end of segment to be printed
!! If l2 < l0, then we can use one call to _write:
!! write (1, %l2, %l0 - %l2);
!! Otherwise we need two calls:
!! write (1, %l2, %l6 - %l2);
!! write (1, %l7, %l0 - %l7);
cmp %l2, %l0
bl rightorder
mov %l2, %o1
!! need to print it in two parts
set 1, %o0
call _write
sub %l6, %o1, %o2
mov %l7, %o1
rightorder:
set 1, %o0
call _write
sub %l0, %o1, %o2
ret:
set 0, %i0
ret
restore
Matthias Blume,
CS Department,
Princeton University