--- title: "Graphics Archiver" id: 51370 type: "computer_media" slug: "graphics-archiver" url: "http://localhost/computer_media/graphics-archiver/" markdown_url: "http://localhost/computer_media/graphics-archiver.md" published_at: "2023-07-29T14:26:38+00:00" modified_at: "2026-04-04T20:18:09+00:00" author: "David Anderson" featured_image: url: "http://localhost/wp-content/uploads/2019/02/20230809-041332.jpg" excerpt: "A utility that embeds an entire hi-res graphics screen inside a BASIC program's REM statement for archival, with Upload, Download, Invert, and Display functions driven by machine code." category: - name: "Archived Media" slug: "archived-media" taxonomy: "category" url: "http://localhost/category/archived-media/" post_tag: - name: "Downloadable" slug: "downloadable" taxonomy: "post_tag" url: "http://localhost/tag/downloadable/" - name: "TS 1000" slug: "ts1000" taxonomy: "post_tag" url: "http://localhost/tag/ts1000/" model: - name: "Timex/Sinclair 1000" slug: "ts-1000" taxonomy: "model" url: "http://localhost/model/ts-1000/" indiv: - name: "Gregory Harder" slug: "gregory-harder" taxonomy: "indiv" url: "http://localhost/indiv/gregory-harder/" genre: - name: "Graphics" slug: "graphics" taxonomy: "genre" url: "http://localhost/type/graphics/" media_type: "Cassette" programmers: - name: "Gregory Harder" slug: "gregory-harder" taxonomy: "indiv" url: "http://localhost/indiv/gregory-harder/" download_url: "https://archive.org/download/timex-sinclair-software-archive/Graphics%20Archiver%20WRX%20%28198x%29%28Harder%2C%20Gregory%29%28US%29%28TS1000%29%28Program%29.zip" mediadate: "1986" images: - url: "http://localhost/wp-content/uploads/2023/07/SCR-20260404-dpdp.png" media_type_tags: "Graphics" --- # Graphics Archiver Graphics Archiver is a utility for storing and retrieving WRX16 high-resolution graphics screens, offering Upload, Download, Invert, Display, and Save functions through an inverse-video menu interface. The program stores the entire hi-res screen data within itself using machine code routines embedded in the line 0 REM statement, with entry points defined by the BASIC variables ULOD, DLOD, INVT, and DPLY holding addresses into that code block. The Upload routine copies the current WRX16 display file into the program’s data area, while Download does the reverse, and the Invert routine bitwise-complements the stored screen data. A SAVE at line 1120 preserves the program complete with any uploaded screen data, effectively archiving the graphics as part of the BASIC file itself. The KEY subroutine at line 9000 implements a clean “press any key” wait by first flushing any held key before polling for a new press. *** ## Program Analysis ### Program Structure The program is organized into several functional blocks separated by line number ranges: - **Line 0:** REM statement containing all machine code routines and the hi-res screen data storage area. - **Lines 10–17:** Variable initialization, including machine code entry points and constants. - **Lines 20–50:** Screen clear using a blank inverse-video string. - **Lines 100–150:** Main menu display and input dispatch. - **Lines 200–230:** Upload function. - **Lines 400–440:** Download function. - **Lines 600–640:** Invert function. - **Lines 800–830:** Display function. - **Lines 1000–1130:** Save function with filename prompt and confirmation. - **Lines 9000–9040:** KEY subroutine — waits for a keypress. ### Machine Code in the REM Statement All executable machine code is stored in the line 0 REM statement, a well-established technique for embedding Z80 routines in BASIC programs. The BASIC variables `ULOD`, `DLOD`, `INVT`, and `DPLY` hold the absolute addresses of the Upload, Download, Invert, and Display entry points within that REM data. These are called via `RAND USR` at lines 220, 420, 430, 620, 630, and 820. The bulk of the REM after the active machine code is zero-padded — this is the screen storage area that receives a WRX16 hi-res frame (6144 bytes) during an Upload operation. Because the hi-res data lives inside the BASIC program itself, a subsequent `SAVE` at line 1120 serializes the screen alongside the code. ### Variable Initialization Idioms Lines 10–17 use `VAL "number"` to assign numeric constants to named variables. This is a standard memory-saving idiom: storing a number as a string literal in a `VAL` expression can be more compact in the BASIC token stream than a bare numeric literal for certain values. Key variables are: | Variable | Value | Purpose | | --- | --- | --- | | `ULOD` | 16672 | USR entry point: Upload routine | | `DLOD` | 16684 | USR entry point: Download routine | | `INVT` | 16692 | USR entry point: Invert routine | | `DPLY` | 16633 | USR entry point: Display routine | | `MNU` | 110 | Line number of main menu (used in GOTO) | | `KEY` | 0x9E3 = 2531 | Line number of KEY subroutine (hex literal via VAL) | | `O` | 0 (NOT PI) | Zero constant used for AT and FOR parameters | | `T` | 21 | Bottom screen row for status messages | `NOT PI` evaluates to 0 (since PI is non-zero, NOT returns 0), giving a compact way to initialize `O` as a zero constant. `INT PI` is used inline throughout as a shorthand for 3 (the integer part of π), saving repeated literal storage. ### Menu Dispatch The menu accepts digits 1–5. Line 140 rejects any character outside this range. Line 150 uses `GOTO VAL "200"*VAL I$` to compute the target line number arithmetically: key “1” → line 200, “2” → line 400, “3” → line 600, “4” → line 800, “5” → line 1000. This is a compact computed GOTO that avoids a chain of IF statements. ### KEY Subroutine The subroutine at line 9000 displays “ANY KEY” at row 21, column 12, then at line 9010 waits for the key to be released (loops while `INKEY$` is non-empty), and at line 9020 waits for a new keypress (loops while `INKEY$` is empty). This two-phase approach prevents a key held from a previous action from immediately advancing past the prompt. Line 9030 clears the status row with the blank string `A$` before returning. ### Save Confirmation and Filename Handling The Save routine (lines 1000–1130) asks for confirmation before proceeding, accepting only “Y” or “N” at lines 1037. If confirmed, it prompts for a filename via `INPUT N$` at line 1070 and displays it on screen before issuing `SAVE N$` at line 1120. Line 1125 checks whether the last character of `N$` has its high bit set (code > 127) and strips the flag by subtracting 128, normalizing the filename string after the save operation completes. ### Screen Initialization Rather than using `CLS`, the program fills the display by PRINTing the 32-character inverse-space string `A$` (defined at line 20) 22 times in a FOR loop (lines 30–50), producing a solid inverse-video background. This gives full control over the visual appearance of the menu without relying on system attributes. ### Notable Anomalies - The variable `KEY` holds the hex value `0x9E3` expressed as a string literal `"9E3"` — but `VAL "9E3"` in BASIC evaluates to 9000 (scientific notation: 9×10³), which is indeed the line number of the KEY subroutine. This is intentional and correct. - Line 1125 strips the high-bit flag from the last character of `N$` post-save. This is a side-effect of the SAVE command modifying the string, and the correction ensures `N$` remains displayable in subsequent menu renders at line 110. - The addresses stored in `ULOD`, `DLOD`, `INVT`, and `DPLY` are absolute RAM addresses pointing into the line 0 REM body. They are fixed constants that assume the program is loaded at a specific memory location, which is typical for utilities of this kind that are designed to be used as-is rather than merged into other programs. ## Source Code ``` 0 REM B8A8B7AAAAB3B87676ED4F00000000000000000000000000000000C3C740F33E647010FDC6EE3C20FD6C01120021020C3CE40005CAD540197CED477DC38BC02AC402AC402AC40011F782193E1EED473EF5172CD922CD202DD21B040C3A42218B40EB210801922D340EB1250EDB0CD2BFDD21B040FDCB3B4628FA3E1EED47DD21812C9210201144411018EDB0C92144411102018F22102010187E2F7723B78B120F7C9000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 10 LET ULOD=VAL "16672" 11 LET DLOD=VAL "16684" 12 LET INVT=VAL "16692" 13 LET DPLY=VAL "16633" 14 LET MNU=VAL "110" 15 LET KEY=VAL "9E3" 16 LET O=NOT PI 17 LET T=VAL "21" 20 LET A$="% % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % " 30 FOR N=O TO T 40 PRINT A$ 50 NEXT N 100 PRINT AT O,O;"%S%C%R%E%E%N% %F%I%L%E%=%=%=%>%F%O%R% %T%H%E% % %A%R%C%H%I%V%A%L%S%T%O%R%A%G%E% %O%F% %H%I%-%R%E%S% %S%C%R%E%E%N% %F%I%L%E%S%.% " 110 PRINT AT INT PI,O;"%C%U%R%R%E%N%T% %F%I%L%E% %I%S%:% ";N$;AT VAL "7",O;"% % % %M%E%N%U";AT VAL "9",O;"%1%.% %U%P%L%O%A%D";TAB O;"%2%.% %D%O%W%N%L%O%A%D";TAB O;"%3%.% %I%N%V%E%R%T";TAB O;"%4%.% %D%I%S%P%L%A%Y";TAB O;"%5%.% %S%A%V%E";AT VAL "15",O;"%E%N%T%E%R% %N%U%M%B%E%R" 120 LET I$=INKEY$ 130 IF I$="" THEN GOTO 120 140 IF CODE I$CODE "5" THEN GOTO VAL "120" 150 GOTO VAL "200"*VAL I$ 200 PRINT AT VAL "9",INT PI;"UPLOAD" 210 GOSUB KEY 220 RAND USR ULOD 230 GOTO MNU 400 PRINT AT VAL "10",INT PI;"DOWNLOAD" 410 GOSUB KEY 420 RAND USR DLOD 430 RAND USR DPLY 440 GOTO MNU 600 PRINT AT VAL "11",INT PI;"INVERT" 610 GOSUB KEY 620 RAND USR INVT 630 RAND USR DPLY 640 GOTO MNU 800 PRINT AT VAL "12",INT PI;"DISPLAY" 810 GOSUB KEY 820 RAND USR DPLY 830 GOTO MNU 1000 PRINT AT VAL "13",INT PI;"SAVE" 1010 GOSUB KEY 1020 PRINT AT T,O;"% %D%I%D% %Y%O%U% %U%P%L%O%A%D% %Y%O%U%R% %F%I%L%E%?%(%Y%/%N%)" 1030 LET S$=INKEY$ 1035 IF S$="" THEN GOTO VAL "1030" 1037 IF S$<>"N" AND S$<>"Y" THEN GOTO VAL "1030" 1040 PRINT AT T,O;A$ 1050 IF S$="N" THEN GOTO MNU 1060 PRINT AT T,O;"%F%I%L%E% %N%A%M%E%?" 1070 INPUT N$ 1080 PRINT AT T,O;"%S%T%A%R%T% %T%A%P%E%." 1090 PRINT AT INT PI,VAL "16";A$;AT INT PI,VAL "17";N$ 1100 GOSUB KEY 1120 SAVE N$ 1125 IF N$(LEN N$)>CHR$ 127 THEN LET N$(LEN N$)=CHR$ (CODE N$(LEN N$)-VAL "128") 1130 GOTO VAL "100" 9000 PRINT AT T,VAL "12";"%A%N%Y% %K%E%Y" 9010 IF INKEY$<>"" THEN GOTO VAL "9010" 9020 IF INKEY$="" THEN GOTO VAL "9020" 9030 PRINT AT T,O;A$ 9040 RETURN ```