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