Power Pack 1 is a collection of four separate BASIC programs: a scrolling “TIMEX” logo display, a bar chart generator, a ten-slot memory calculator with save capability, and a function plotter. The logo program uses POKE and RAND USR calls into the system ROM (addresses 16514, 16560, 16683) to drive display effects, cycling through characters in a string via a looping CODE lookup. The bar chart program accepts up to 12 named bars with values, scales them to fit a 20-row display using computed column widths, and optionally prints bar labels and values alongside the bars. The function plotter evaluates user-supplied equations via VAL on a 64-point X axis, auto-scales the result range to fit the 44-row pixel display, and uses PLOT to render the curve.
Program Analysis
Power Pack 1 contains four independent programs concatenated into a single listing. Each program uses common ZX81/TS1000 BASIC idioms such as LET O=PI/PI (to obtain 1 without embedding a literal), LET Z=O-O (for 0), and VAL "number" in GO TO/GO SUB targets as a memory optimization. These constants are referenced throughout to avoid storing repeated numeric literals in the token stream.
Program 1: Scrolling Logo / Display Driver (lines 90–9080)
This program displays an animated “TIMEX” framed logo and then cycles through characters of an input string, poking each character code into a system address and invoking machine code via RAND USR.
LET H=CODE "▒"(line 100) stores a specific character code used as a display attribute or control value.LET T=VAL "16671"andLET CT=T+VAL "4"(lines 110–120) target system memory locations;LET SF=T-Oderives the USR entry point at 16670.- Lines 9005–9050 use
POKE T,H/POKE CT,VAL "168"to configure a display register, then callRAND USR SF(address 16670) to invoke machine code, likely a ROM routine for a screen effect. - Line 1050 uses
POKE VAL "16514",CODE A$(C)to place a character code into the keyboard buffer or display register at address 16514, feeding it to the machine code called on line 1060. - Line 1060 calls
RAND USR VAL "16560"+USR VAL "16683"— the addition of two USR results produces a combined machine-code address, a compact way to build a dynamic call target. - The main loop (lines 1020–1110) cycles index
CthroughA$, wrapping at the end, and exits on any keypress. - Subroutine 8000 draws a receding nested border spelling “TIMEX” using
PRINT ATwith decreasing indentation. - Subroutine 9000 constructs a decorative box border using block graphics characters (▛▜▟▙▌▐█) placed with
PRINT AT.
Program 2: Bar Chart Generator (lines 10–910)
This program collects up to 12 named bars with numeric values, then renders a scaled bar chart on screen using block graphics.
LET Q=VAL "12"sets the maximum bar count;DIM B(Q)andDIM B$(Q,VAL "4")allocate parallel numeric and string arrays.- Scaling is computed as
B(J)/(M/(H-O))inside the K loop (line 260), whereMis the running maximum andH=VAL "20"is the chart height in rows. - Column width per bar is
W/YwhereW=VAL "25", distributing bars evenly across 25 columns. - Line 265 substitutes a solid block
█for the▒fill character at the rightmost column of each bar whenY<=T(10 or fewer bars), creating a visual border. - Subroutine 700 prints bar name labels and value strings alongside the bars; lines 805 and 900 handle fallback positions when the bar is too short to contain the label, using computed
ATexpressions with string literals likeVAL "12+N"— note thatVAL "12+N"is a bug:VALon a string containing an unresolved variable name will cause an error at runtime, sinceNis not a string variable in scope forVAL. - Line 243 switches to FAST mode before rendering for speed.
Program 3: Memory Calculator (lines 80–2040)
A simple ten-slot numeric memory store. The user enters arithmetic expressions as strings; VAL A$ evaluates them, and the result can be stored in any of the ten slots displayed on screen.
DIM A(10)holds the ten memory slots, displayed in a two-column table (slot number and value) by subroutine 1000.- Line 115 guards against empty input; line 116 branches to
SAVE "TSCALC"(line 2030) if the user enters"S", persisting the program. - Subroutine 2000 stores
VintoA(R)and updates the on-screen table in place usingPRINT AT R,9, avoiding a full redraw. - Line 170 clears the result line with a string of spaces before looping, keeping the display tidy.
- This program does not use the
O/Zconstant idiom — it uses literal1and0directly, suggesting it was written independently of the others.
Program 4: Function Plotter (lines 90–3030)
Plots a user-defined mathematical function by evaluating the input string as an expression for each integer X from 0 to 63, auto-scaling the result to fit the display.
LET P=VAL "63"sets the X range;DIM D(P+O)allocates 64 elements to store computed Y values.- Line 580 uses
LET D=VAL E$inside the X loop — sinceXis a live numeric variable, any formula referencingX(e.g.,"X*X") is evaluated correctly by the BASIC interpreter’sVAL. - The auto-scaling pass (lines 600–640) finds
M(max) andMI(min), then computesSC=(M-MI)/32to map the value range onto 32 pixel rows. - Line 660 computes the plot Y position as
(D(X+O)+MI)/SC— note the sign: addingMI(the minimum, which may be negative) effectively shifts all values up so the minimum maps to zero. However, ifMIis negative, adding it reduces the value; the correct offset should subtractMI. This is a bug that will produce a vertically misplaced or compressed plot for functions with negative minima. - Subroutine 1000 draws axis lines using PLOT across the full X range at row
S=43and38, plus vertical end markers. - Subroutine 3000 (lines 3000–3030) unplots the previous curve using the same formula, providing a clear-before-redraw capability, though it is never called from the main loop — it appears to be dead code in this listing.
LET U=VAL "3000"serves double duty: as a large numeric sentinel for max/min initialization (LET M=-U,LET MI=U) and as the line number forGOSUB Uat line 500, calling subroutine 3000 to unplot the old curve before re-entering the input loop.
Notable Techniques Across All Programs
| Technique | Usage |
|---|---|
LET O=PI/PI | Compact way to store integer 1 without a literal token |
VAL "number" in GO TO/GO SUB | Memory saving: numeric literals in strings are shorter than in-line constants |
RAND USR address | Machine code invocation without a dedicated USR variable |
| POKE + RAND USR for ROM calls | Program 1 uses system addresses 16514, 16560, 16670, 16683 for display control |
| Block graphics via PRINT AT | Programs 1 and 2 use ▌▐▛▜▟▙█ for borders and bar fills |
| VAL E$ in a loop | Program 4 evaluates user formula strings with the current X in scope |
Content
Image Gallery
Source Code
10 REM B▘.... ▗▖▄▝▐▞▟▘▚▌▙▀▜▛█ E£RND7▘#▘U▄RND RETURN▘TAB [K]RND GOSUB #6:RND5▙RND#[B]*****- ACS >#5 2;:▖▞▖#7#7 FAST[J]ACS >*ACS >*ACS <*ACS <*5[▒]RND▐##E:RND#76:RND( STOPSTR$ )1 ;6:RNDSGN LPRINT $4INT )█ COPYE:RND;6:RND#TAN E£RND7▘#▘,, ▞▖VAL Y ##< FOR ▘3 GOSUB [K]>7AT ( LOAD TAN Y ▞▖:KNOT $4 UNPLOT ( SAVE TAN LN ▘INKEY$ LN ▘INKEY$ LN ▘INKEY$ LN ▘INKEY$ TAN
90 LET O=PI/PI
95 LET Z=O-O
100 LET H=CODE "▒"
110 LET T=VAL "16671"
120 LET CT=T+VAL "4"
130 LET SF=T-O
140 LET B$="▜██████████████████████████████▛"
150 LET J=VAL "21"
160 LET W=VAL "31"
900 SLOW
905 CLS
907 GOSUB VAL "8000"
910 GOSUB VAL "9000"
940 INPUT A$
950 SLOW
1000 REM
1010 LET C=Z
1020 LET C=C+O
1040 IF C>LEN A$ THEN LET C=O
1050 POKE VAL "16514",CODE A$(C)
1055 PRINT AT VAL "10",VAL "28";
1060 RAND USR VAL "16560"+USR VAL "16683"
1070 IF INKEY$ <>"" THEN GOTO VAL "900"
1110 GOTO VAL "1020"
8000 FOR G=J-O TO O STEP -O
8010 PRINT AT G+O,G+O;" ";AT G,G;" TIMEX "
8020 NEXT G
8999 RETURN
9000 PRINT AT Z,Z;" ";
9005 POKE T,H
9006 POKE CT,VAL "168"
9010 RAND USR SF
9020 POKE T,Z
9030 POKE CT,VAL "48"
9040 PRINT AT VAL "9",Z;
9050 RAND USR SF
9060 PRINT AT VAL "8",Z;B$;AT VAL "15",Z;"▟";B$(O+O TO W);"▙"
9065 FOR G=1 TO 6
9066 PRINT AT G+O,Z;"▌";AT G+O,W;"▐";AT VAL "22"-G,Z;"▌";AT VAL "22"-G,W;"▐"
9067 NEXT G
9070 PRINT AT O,Z;"█";AT O,W;"█";AT J,Z;"█";AT J,W;"█";
9080 RETURN
10 LET T=VAL "10"
11 LET O=PI/PI
12 LET Z=O-O
13 LET Q=VAL "12"
14 LET H=VAL "20"
15 LET W=VAL "25"
110 SLOW
120 CLS
130 PRINT AT T,T;"BAR-[G][R][A][P][H]"
140 PAUSE 100
160 CLS
172 DIM B(Q)
175 LET M=Z
180 DIM B$(Q,VAL "4")
181 PRINT "HOW MANY BARS ?"
182 INPUT Y
183 PRINT Y
184 IF Y>Q OR Y=Z THEN GOTO VAL "160"
185 FOR N=1 TO Y
190 PRINT "[V][A][L][U][E] ";N;" ";
195 INPUT B(N)
197 IF B(N)>M THEN LET M=B(N)
200 PRINT B(N);
210 PRINT " [N][A][M][E] ";N;" ";
220 INPUT B$(N)
230 PRINT B$(N)
235 NEXT N
237 PRINT "TITLE"
238 INPUT T$
242 CLS
243 FAST
244 GOSUB VAL "500"
245 FOR J=O TO Y
247 LET S$="[▒]"
250 FOR X=O TO W/Y-O
260 FOR K=O TO B(J)/(M/(H-O))
262 IF Y>T THEN GOTO VAL "270"
265 IF X=INT (W/Y-O) THEN LET S$="█"
270 PRINT AT H-K,X+O+((J-O)*W/Y);S$
280 NEXT K
290 NEXT X
295 IF Y<VAL "09" THEN GOSUB VAL "700"
300 NEXT J
499 STOP
500 FOR N=O TO W+O
510 PRINT AT H,N;"█"
520 NEXT N
565 PRINT AT H+O,Z;T$
570 RETURN
700 REM
710 FOR N=1 TO LEN B$(J)
715 IF K<LEN B$(J)+VAL "1" THEN GOTO VAL "900"
720 PRINT AT H-K+N+1,X+((J-O)*W/Y);B$(J,N TO N)
730 NEXT N
732 LET Q$=STR$ B(J)
735 FOR N=1 TO LEN Q$
743 IF K<LEN Q$+VAL "1" THEN GOTO VAL "805"
745 PRINT AT H-K+N,X-2+((J-O)*W/Y);Q$(N)
750 NEXT N
799 RETURN
805 PRINT AT VAL "12+N",X-VAL "2"+((J-O)*W/Y);Q$(N)
810 GOTO VAL "750"
900 PRINT AT VAL "13+N",X+((J-O)*W/Y);B$(J,N TO N)
910 GOTO VAL "730"
80 SLOW
90 DIM A(10)
100 GOSUB 1000
110 INPUT A$
115 IF A$="" THEN GOTO 110
116 IF A$="S" THEN GOTO 2030
120 LET V=VAL A$
130 PRINT AT 16,0;"THE RESULT IS: ";V
140 PRINT "INTO WHAT MEMORY SHOULD I PLACE THIS VALUE?"
150 INPUT R
160 IF R>=1 AND R<=10 THEN GOSUB 2000
170 PRINT AT 16,0;" "
180 GOTO 110
1000 CLS
1010 PRINT AT 0,0;"MEMORY";TAB 9;"VALUE"
1020 FOR G=1 TO 10
1030 PRINT G;TAB 9;A(G)
1040 NEXT G
1050 RETURN
2000 LET A(R)=V
2010 PRINT AT R,9;" ";AT R,9;V
2020 RETURN
2030 SAVE "TSCAL[C]"
2040 GOTO 110
90 SLOW
100 LET O=PI/PI
110 LET Z=O-O
120 LET P=VAL "63"
130 LET E$="TSGRAPH"
140 LET U=VAL "3000"
150 DIM D(P+O)
160 LET S=VAL "43"
170 LET F=VAL "4"
180 LET S$=" "
480 GOSUB VAL "1000"
490 GOTO VAL "550"
500 GOSUB U
550 PRINT AT VAL "21",Z;"YOUR EQUATION?"
560 INPUT E$
561 PRINT AT VAL "21",Z;S$
562 FAST
563 GOSUB VAL "2000"
565 LET M=-U
567 LET MI=U
570 FOR X=Z TO P
580 LET D=VAL E$
590 LET D(X+O)=D
600 IF D>M THEN LET M=D
610 IF D<MI THEN LET MI=D
620 NEXT X
630 LET D=M-MI
640 LET SC=D/VAL "32"
645 SLOW
650 FOR X=F TO P-F
660 LET Y=((D(X+O)+MI)/SC)
665 PLOT X,Y
670 NEXT X
680 PAUSE U
690 GOTO VAL "500"
1000 FOR X=Z TO P
1010 PLOT X,S
1020 PLOT X,VAL "38"
1040 NEXT X
1050 FOR Y=S TO S-VAL "4" STEP -O
1060 PLOT Z,Y
1070 PLOT P,Y
1080 NEXT Y
2000 PRINT AT O,O;S$;AT O,O;"Y=";E$
2010 RETURN
3000 FOR X=F TO P-F
3010 UNPLOT X,((D(X+O)+MI)/SC)
3020 NEXT X
3030 RETURN
Note: Type-in program listings on this website use ZMAKEBAS notation for graphics characters.