--- title: "Morse Code Sender" id: 57128 type: "computer_media" slug: "unknown-machine-code-routine-2" url: "http://localhost/computer_media/unknown-machine-code-routine-2/" markdown_url: "http://localhost/computer_media/unknown-machine-code-routine-2.md" published_at: "2024-10-03T23:57:43+00:00" modified_at: "2026-03-30T21:19:42+00:00" author: "David Anderson" featured_image: url: "http://localhost/wp-content/uploads/2024/10/77_Unk.png" excerpt: "Type any text and this program encodes and transmits it as Morse code in real time, driven by a compact machine code routine hidden inside a REM statement." 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/" genre: - name: "Ham Radio" slug: "ham-radio" taxonomy: "genre" url: "http://localhost/type/ham-radio/" media_contents: - id: 56733 title: "Timex Sinclair Public Domain Library Tape 1002" type: "computer_media" url: "http://localhost/computer_media/timex-sinclair-public-domain-library-tape-1002/" media_type: "Program" mediadate: "198x" images: - url: "http://localhost/wp-content/uploads/2024/10/77_Unk.png" media_type_tags: "Ham Radio" --- # Morse Code Sender This program accepts a string from the user and transmits it using Morse code via the ZX Spectrum/TS2068 EAR/MIC port, driven by a machine code routine embedded in the REM statement at line 1. The BASIC shell dimensions the input string to 32 characters, prints it to the screen, then calls the machine code at address 16514 (the byte immediately after the REM opcode at line 1) with RAND USR. The machine code routine reads each character of the string, looks up its Morse representation, and toggles the output port to produce dots and dashes. After transmission, control returns to BASIC and the program loops for the next input, making it a functional interactive Morse code encoder. *** ## Program Analysis ### Program Structure The program is a short BASIC shell that wraps a self-contained machine code Morse transmitter. Execution flows as follows: 1. Line `100`: Accept a string from the user into `A$`. 2. Line `110`: Redimension `A$` to exactly 32 characters (pads/truncates). 3. Line `120`: Clear the screen. 4. Line `130`: Display the string being transmitted. 5. Line `140`: Execute the machine code routine via `RAND USR 16514`. 6. Line `150`: Loop back to `100` for the next message. Lines `160` and `170` are a `SAVE`/`RUN` pair used only when saving or autostarting the program and are never reached during normal execution. ### Machine Code Routine (REM at Line 1) The REM statement at line 1 holds 63 bytes of Z80 machine code beginning at address 16514 (the first byte after the REM opcode in memory). The entry point called by `RAND USR 16514` is this routine. A disassembly of the embedded bytes reveals the following logical structure: - `CD 87 40` — CALL to an internal subroutine (at offset within the REM) responsible for producing a single tone pulse on the EAR/MIC port. - `18 FB` / `0E 01` / `06 00` — Timing and loop setup for dot/dash durations. - `3E 7F DB FE` — Load A with `0x7F`, then `IN A,(0xFE)`: reads the keyboard/EAR port, used for abort-key polling. - `D3 FF` — `OUT (0xFF),A`: writes to the MIC/EAR port to toggle the audio output line. - `1F D0` — `RRA` then `RET NC`: returns early if a key is pressed (abort mechanism). - `2A 0C 40` — `LD HL,(0x400C)`: loads the address of `A$` from the system variable area, giving the routine direct access to the input string. - A secondary subroutine at the latter half of the REM (entered via `D5 1E 94 06 1A`) handles iterating over each character of the 32-byte string, looking up its Morse pattern, and calling the tone-pulse routine the appropriate number of times for dots and dashes. - `C9` — `RET`: returns cleanly to BASIC after the full string has been transmitted. ### Key BASIC Idioms The use of `DIM A$(32)` after `INPUT A$` (line 110 after line 100) is a deliberate technique: re-dimensioning a string variable pads it with spaces to the declared length. This gives the machine code a fixed-length, known-address buffer to iterate over without needing to consult the string length separately — the routine simply processes all 32 characters, with trailing spaces producing inter-word pauses in Morse. `RAND USR 16514` is the standard idiom for calling machine code from BASIC without disturbing the RANDOMIZE seed in a meaningful way; the return value of the USR call is discarded. ### Port Usage | Port | Direction | Purpose | | --- | --- | --- | | `0xFE` (IN A,(`0xFE`)) | Read | Keyboard/EAR input; polled for abort keypress | | `0xFF` (OUT (`0xFF`),A) | Write | MIC/EAR output; toggled to generate audio tones | ### Notable Techniques - The entire machine code is stored in a REM statement, a classic technique that keeps code in a predictable, fixed memory location (immediately after the program’s first line header at address 16514). - The abort-on-keypress mechanism using `IN A,(0xFE)` followed by `RRA` / `RET NC` is an efficient way to allow the user to interrupt a long transmission without returning to BASIC via a break. - The fixed 32-character string buffer (imposed by `DIM A$(32)`) simplifies the machine code loop logic, avoiding the need to read the string’s length descriptor from the heap. - Direct port output at `0xFF` for audio is consistent with hardware that routes the MIC bit through this port address. ### Potential Anomalies Redimensioning `A$` at line 110 *after* the `INPUT` at line 100 means any string longer than 32 characters entered by the user will be silently truncated. Strings shorter than 32 characters are padded with spaces, which in Morse produce inter-character silence — a reasonable behaviour, but the user receives no warning about truncation. This is a minor UX limitation rather than a bug in the transmitter logic itself. ## Source Code ``` 1 REM \CD\87\40\18\FB\0E\01\06\00\3E\7F\DB\FE\D3\FF\1F\D0\17\17\38\10\10\F2\F1\2A\0C\40\CD\87\40\23\71\CB\79\28\F7\C9\D5\1E\94\06\1A\1D\DB\FE\17\CB\7B\7B\38\F5\10\F5\D1\20\04\FE\56\30\CB\3F\CB\11\30\C6\C9\25\1C 100 INPUT A$ 110 DIM A$(32) 120 CLS 130 PRINT A$ 140 RAND USR 16514 150 GOTO 100 160 SAVE "1007%7" 170 RUN ```