Benchmarking the CoCo keyboard – part 5

See also: part 1, part 2, part 3, part 4, part 5, part 6, part 7 and more (coming “soon”).

By now, many of you have realized that I have no idea what I am doing. It’s through great comments that this series is evolving into something hopefully useful. For example, MC-10 programmer extraordinaire Jim Gerrie left this comment:

20 CLS:FORZ=.TO1STEP.IF(PEEK(344)ANDPEEK(343)ANDPEEK(342)ANDPEEK(341))<>255THENK=PEEK(135):PRINT@32*Y+X,” “;:X=X+(X>.ANDK=8)-(X<31ANDK=9):Y=Y+(Y>.ANDK=94)-(Y<14ANDK=10):NEXT ELSENEXT:END

I think the POKES are not needed for Coco3 or anything below BASIC 1.2 on the Coco 2.

Jim Gerrie

This reminded me of a cryptic code sample he posted earlier this year on Facebook:

1 PCLEAR4:SCREEN1,1:PCLS
7 POKE341,255:POKE342,255:POKE343,255:POKE344,255:IFNOT((PEEK(341)ANDPEEK(342)ANDPEEK(343)ANDPEEK(344))=255)THENK=PEEK(135):X=X+(K=8ANDX>.)-(K=9ANDX<255):Y=Y+(K=94ANDY>.)-(K=10ANDY<191)
8 PSET(X,Y):GOTO7

You can see the keyboard KEYBUF memory locations (341-344) being used, as well as the “last key pressed” location (135). Typing in the above code snippet produces a black PMODE 4 graphics screen with a dot you can move around using the arrow keys.

My head spins just trying to figure out the logic of the use of NOT, AND and logical comparisons (a > b). The end result is an all-in-one routine that adds or subtracts values to X and Y coordinates. Clever.

Since this code is basically reading a key that is being held down, it only gets back one value (such as Up, Down, Left or Right). It does not support diagonal movement.

Here’s my much longer version that will support diagonals:

0 REM ahkeybd.bas
10 PCLEAR4:SCREEN1,1:PCLS:X=0:Y=0
20 POKE&H155,&HFF:POKE&H156,&HFF:POKE&H157,&HFF:POKE&H158,&HFF
30 IF PEEK(&H155)=&HF7 THEN IF Y>. THEN Y=Y-1
40 IF PEEK(&H156)=&HF7 THEN IF Y<&HDF THEN Y=Y+1
50 IF PEEK(&H157)=&HF7 THEN IF X>. THEN X=X-1
60 IF PEEK(&H158)=&HF7 THEN IF X<&HFE THEN X=X+1
80 IF PEEK(&H159)=&HF7 THEN PRESET(X,Y) ELSE PSET(X,Y)
90 GOTO 20

Also, SPACE can be used to erase. But it is still really slow.

Make go faster

Let’s benchmark my version, which is already sped up by using hex constants. I’ll take out the part that deals with the SPACE bar, and remove unneeded spaces.

0 REM arrowbench.bas
10 TIMER=0:FOR A=1 TO 1000
20 POKE&H155,&HFF:POKE&H156,&HFF:POKE&H157,&HFF:POKE&H158,&HFF
30 IFPEEK(&H155)=&HF7 THENIFY>.THENY=Y-1
40 IFPEEK(&H156)=&HF7 THENIFY<&HDF THENY=Y+1
50 IFPEEK(&H157)=&HF7 THENIFX>.THENX=X-1
60 IFPEEK(&H158)=&HF7 THENIFX<&HFE THENX=X+1
90 NEXT:PRINT TIMER

This produces 2139.

I should be able to speed it up further by replacing the PEEK values with variables:

0 REM arrowbench2.bas
5 V=&HF7:U=&H155:D=&H156:L=&H157:R=&H158
10 TIMER=0:FOR A=1 TO 1000
20 POKEU,V:POKED,V:POKEL,V:POKER,V
30 IFPEEK(U)=V THENIFY>.THENY=Y-1
40 IFPEEK(D)=V THENIFY<&HDF THENY=Y+1
50 IFPEEK(L)=V THENIFX>.THENX=X-1
60 IFPEEK(R)=V THENIFX<&HFE THENX=X+1
90 NEXT:PRINT TIMER

This actually slows down to 2864. I did not expect that. Okay, no variables for my version, then.

Now let’s benchmark Jim’s much smaller (and far more clever) routine:

0 REM arrowbench3.bas
10 TIMER=0:FOR A=1 TO 1000
20 POKE341,255:POKE342,255:POKE343,255:POKE344,255:IFNOT((PEEK(341)ANDPEEK(342)ANDPEEK(343)ANDPEEK(344))=255)THENK=PEEK(135):X=X+(K=8ANDX>.)-(K=9ANDX<255):Y=Y+(K=94ANDY>.)-(K=10ANDY<191)
90 NEXT:PRINT TIMER

This prints 3609. So far, it looks like mine is faster. But let’s do the same optimizations to Jim’s code.

Let’s convert the decimal constants into hex:

0 REM arrowbench4.bas
10 TIMER=0:FOR A=1 TO 1000
20 POKE&H155,&HFF:POKE&H156,&HFF:POKE&H157,&HFF:POKE&H158,&HFF:IFNOT((PEEK(&H155)ANDPEEK(&H156)ANDPEEK(&H157)ANDPEEK(&H158))=&HFF)THENK=PEEK(&H87):X=X+(K=&H8 ANDX>.)-(K=&H9 ANDX<&HFF):Y=Y+(K=&H5E ANDY>.)-(K=&HA ANDY<&HBF)
90 NEXT:PRINT TIMER

This lowers it to 2120! That’s slightly faster than my version. I did not expect that.

Even though using variables was slower in my version, let’s see what happens with Jim’s:

0 REM arrowbench5.bas
5 V=&HFF:U=&H155:D=&H156:L=&H157:R=&H158:P=&H87
10 TIMER=0:FOR A=1 TO 1000
20 POKEU,V:POKED,V:POKEL,V:POKER,V:IFNOT((PEEK(U)ANDPEEK(D)ANDPEEK(L)ANDPEEK(R))=V)THENK=PEEK(P):X=X+(K=&H8 ANDX>.)-(K=&H9 ANDX<&HFF):Y=Y+(K=&H5E ANDY>.)-(K=&HA ANDY<&HBF)
90 NEXT:PRINT TIMER

To my surprise, this drops it even further to 1715. It is now twice as fast as the original version that used decimal constants!

But why did mine get slower when I swapped out the same variables? I *speculate* that the processing of things like AND and NOT and comparisons may be alot faster on variables than whatever it has to do when encountering constants, but that’s a benchmark digression for another time.

To test that theory, let me change the POKEs back to hex and see if that slows down or speeds up. We’ll just use the variables in the AND/NOT stuff.

0 REM arrowbench6.bas
5 V=&HFF:U=&H155:D=&H156:L=&H157:R=&H158:P=&H87
10 TIMER=0:FOR A=1 TO 1000
20 POKE&H155,&HFF:POKE&H156,&HFF:POKE&H157,&HFF:POKE&H158,&HFF:IFNOT((PEEK(U)ANDPEEK(D)ANDPEEK(L)ANDPEEK(R))=V)THENK=PEEK(P):X=X+(K=&H8 ANDX>.)-(K=&H9 ANDX<&HFF):Y=Y+(K=&H5E ANDY>.)-(K=&HA ANDY<&HBF)
90 NEXT:PRINT TIMER

Nope. This slows down to 1947. For whatever reason, the variables sped up Jim’s, but slowed down mine.

I suppose we could try changing the remaining hex constants to variables and see what that did, but for now, I’ll just say:

Nicely done, Jim!

Can we find a way to do this but also support diagonals?

To be continued…

One thought on “Benchmarking the CoCo keyboard – part 5

Leave a Reply

This site uses Akismet to reduce spam. Learn how your comment data is processed.