[Search for users] [Overall Top Noters] [List of all Conferences] [Download this site]

Conference noted::hackers_v1

Title:-={ H A C K E R S }=-
Notice:Write locked - see NOTED::HACKERS
Moderator:DIEHRD::MORRIS
Created:Thu Feb 20 1986
Last Modified:Mon Aug 03 1992
Last Successful Update:Fri Jun 06 1997
Number of topics:680
Total number of notes:5456

98.0. "Wot Duzzit Do?" by VIKING::JENSEN () Thu Mar 07 1985 21:08

In the January 1985 issue of Dr. Dobb's Journal, on page 17 the following
article appeared:

======================================================================

		WOT DUZZIT DEW?

David S. Tilton sent us [DDJ] the following sequence of Z80 code. It's an
absolutely astonishing implementation of...but you can figure it out. 
Unfortunately, it requires such narrowly defined conditions that it's 
probably useless, despite being the fastest one of its kind. What does it 
do, and what are its narrow requirements for utility?

Loop:
	cp	(hl)
	ret	z

	rl	L
	djnz	Loop

	ld	L,0
	ret

Might there be a way to use this gimmick in another architecture (e.g., 8086,
68000) to get the same result with more flexibility?

======================================================================

I haven't seen any responses to this article, nor have I totally figured it
out. I'll include my knowledge in a later reply. What does it do? Where would
you use it? Any ideas?

								Steve
T.RTitleUserPersonal
Name
DateLines
98.1PIPA::JANZENFri Mar 08 1985 13:4012
			; FOR THOSE WITHOUT Z80 BOOKS, BEATS ME
			; ROUTINE
			; A HOLDS COMPARER
			; HL HOLDS ADDRESS OF COMPARAND
			; B HOLDS NUMBER OF LOOPS, 1 < B < 8
LOOP:	CP	(HL)	; A-(HL) COMPARE A AND MEMORY BYTE POINTED BY HL
	RETZ		; RETURN IF ZERO FLAG IS SET (A = (HL))
	RL	L	; <= CARRY <= L7L6L5L4L3L2L1L0 <=, HL POINTS TO NEW LOC
	DJNZ	LOOP	; B<=B-1; IF B<>0 GOTO LOOP; IF B=0 CONTINUE
	LD	L,0	; L <= 0
	RET		; UNCONDITIONALLY RETURN TO CALLING ROUTINE 
			; TOM
98.2VAXUUM::DYERFri Mar 08 1985 16:154
	Quite obviously the Towers of Hanoi.
#6	<_Jym_>\
P.S.:  You can make a phase-of-moon program out of it by changing one (1)
       instruction.
98.3VIKING::JENSENTue Mar 12 1985 19:4523
Jym, I don't know if you're joking or not. If not, how about explaining how
it would work?

Here's what I've learned:

Compare (CP) will set the carry flag if it needs to borrow when it subtracts
the contents of the memory location from the A register. This seems important
since the rotate goes through the carry (the non-carry circular rotate would
have been chosen otherwise). 

Which means that the table doesn't need to be limited to 8 locations (that was
my first thought too), but probably doesn't exceed 256, because then you'd have
to change the H register. 256 is the maximum number of times through the loop,
since the DJNZ instruction decrements before checking for 0. 

The answer is apparently returned in the L register. L is loaded with 0 if no
match is found for A, but left alone when a match is found. 

Well, that covers most of what I was able to figure out. Can anyone take it
from here?

								Steve

98.4LATOUR::CSMITHTue Mar 12 1985 22:289
I've seen this one before, so it would be cheating for me to "solve" it,
but for PDP-10 hackers, here's the equivalent code:

loop:	sub	ac,value	; ac := ac - value
	tlnn	ac,-1		; skip if ac left half /= 0
	  popj	p,		; return
	jra	ac,loop		; load ac from address in ac left half, jump

The required data structure is even more arcane than the Z80 equivalent.
98.5VIKING::WASSER_1Mon Mar 18 1985 10:3861
Here are the results of posting this to "net.puzzle" on Usenet:
-------------------------------------------------------------------------------
From:	RHEA::DECWRL::"allegra!watmath!watdaisy!ndiamond" 
Regarding the Z80 code puzzle you posted:  is it a binary search?
(Please be kind enough to answer, and I won't post it.  Thank you.)
   Norman Diamond
UUCP:  {decvax|utzoo|ihnp4|allegra}!watmath!watdaisy!ndiamond
CSNET: ndiamond%[email protected]
ARPA:  ndiamond%watdaisy%[email protected]
-------------------------------------------------------------------------------
From:	RHEA::DECWRL::"[email protected]" 
It isn't that hard to figgure out. The code is checking up to 8 memory
locations in the same page of memory for a particular byte. Code very
similar to this is used by my model 1 to scan the keyboard (which works
by shorting address lines to data lines, and software decoding), with
the compare being for any non-zero location => key pressed.
				Michael Gersten
-------------------------------------------------------------------------------
From:	RHEA::DECWRL::"ihnp4!alberta!zaphod!bobd"
This is simply marvelous!  As far as I can tell from my Z80 instruction
manual, what we have is a basic heap search.  Here are my assumptions
about the registers and data structures:

	a) HL points to a table on a 256 byte boundary.
	b) B has log(2) N of the table size (rounded up).
	c) The table is maximum 255 bytes long
	d) The first entry is empty (irrelevant)
	e) HL is initialized to baseOfTable + 1 (L=1, H=??)
	f) The table entries are one byte values ordered in heap
	   formation.  I.e., the first item is the midpoint value of the
	   table.  The entries at 2 and 3 are the midpoints of the upper
	   and lower ranges.

The carry bit from the CP instruction is used to decide whether to use
the upper or lower half of the table.  To do a Knuth style analysis of
the performance, let N be the number of entries in the table, let k be
the ceiling of log2 N,

; A is an 8 bit register (the comparand)
; B is an 8 bit register ( = k )
; HL is a 16 bit register made up of H (the high byte) and L (the low byte)
;  HL = ??01
LOOP:
	CP	(HL)	; 7 cycles
	RET	Z	; 5 cycles or 11 cycles if taken
	RL	L	; 8 cycles
	DJNZ	LOOP	; 8 cycles or 13 cycles if taken
	LD	L,0	; 7 cycles
	RET		; 10 cycles

For the value in A not in the table, the loop time is 28*k + 5*(k-1) +
17 cycles.  Since k is 8 or less, the search will fail in a maximum of 276
cycles.

I do not agree that this is from a narrowly defined constraints;
obviously the constraints must be well defined.  I still the algorithm
is a marvelous implementation of a good data structure algorithm.

Please let me know if there are problems with my analysis, or if there
are other points that people brought up.
-------------------------------------------------------------------------------
98.6VIKING::JENSENTue Jun 11 1985 10:2858
DDJ finally printed the answer to the Wot Duzzit Dew problem they printed
back in January. Here is David Tilton's (the puzzle's originator) description:

BTS:	cp	(hl)
	ret	z

	rl	L
	djnz	BTS

	ld	L,0
	ret

"[The routine] actually outperforms the CPIR instruction of the Z80 in 
searching a list of bytes for a match by using a binary rather than a linear
search, but the restrictions on the sequence of the list and its placement
in memory make it less than attractive. 

"On entry, A contains the byte to search for, B contains the number of levels
in the tree, and HL points to the root of the binary tree. One of the 
unfortunate restrictions is that the value of L for the root must be 01H.
Since the value of H remains constant, it is the value of L on return that
indicates the result.

"It is helpful to think of the list as a byte array indexed by L. We start 
with a comparison. If there is a match, the second instruction returns with
L indicating where the match occurred.

"If there was no match, the value in the tree was either too large or too 
small. The carry flag will be set if it was too large. The next instruction
multiplies the contents of L by two and, if the carry flag was set, adds one.
The DJNZ instruction checks for another level in the tree and, if there is
one, loops to check the already-selected node in it. If there is not another
level, L is set to zero to indicate that the byte sought was not in the tree.

"There are many disadvantages to this arrangement. It is inflexible. For
one thing, a full tree must be maintained; that is, the size of the tree 
must always be some power of two less one. It is significantly faster than
CPIR only for the larger trees. Furthermore, if you can spare a full page
of 256 bytes [to hold the tree] then there is an even faster way of doing
the same thing:

BTL:	ld	L,A
	ld	L,(HL)
	ret

This is, of course, simply a byte lookup table. I thought I was being really
clever with my BTS routine, but it turns out to be virtually useless."

Oh, now, cheer up. You got deep into binary trees, right? It's very profound
that the successive carry-bits shifted into L are a record of the path through
a tree to the desired node, where [a] one means "go left" and zero means
"go right." The binary number that defines the path to a node is a unique 
label for that node; it's basically a "Dewey Decimal Number" for the node.

There's a discussion of this in Knuth's Volume 1, Section 2.3 (especially see
the answer to Exercise 15, p. 315). There also is a connection to data 
compression: if the compared values were wider than a byte, their binary node
labels would be a compressed representation of them.