15

Some small utilities, tools etc for Atari were distributed as BASIC programs that would consist of just one line, that looked something like this:

10 A=USR(ADR("p$PHHLéúÿÿÇEéúÿÿ@éüÿÿ2A$éòùÿÿE°U´è§øÿÿøÿÆûÿÿé`"))

Sometimes they would be split into two lines, but rarely more.

enter image description here

Essentially, the machine language program was encoded as a string (Atari could display all 256 characters of ATASCII even if typing some of them required some hoop-jumping), the string was wrapped into ADR (returning the address of the string) and USR (jumping to the address given).

I can't quite imagine anyone converting the binary generated by the assembler into ATASCII by hand, especially if the program was longer. There had to be some utility to do this - emit a fragment of memory as string, wrap it into the commands, save as BASIC program. Is it obtainable somehow?

3
  • 1
    Just as a hint to one who wants to answer this with a program: I assume that like most BASIC dialects of that time the Atari one had PEEK() and CHR$() functions or equivalents. Would be fairly easy to use them for the task. Commented Apr 21, 2016 at 13:50
  • I've written programs in machine code before. It's a bit of a pain, but if you need 32-bit x86 code and your assembler will only directly emit 16-bit instructions, you don't have many options.
    – Mark
    Commented May 13, 2016 at 4:44
  • @Mark - interestingly, it's actually relatively simple to use a 16-bit x86 assembler for 32-bit code: just use the ax/bx/etc register names when you mean eax/ebx and so on, and judiciously sprinkle with db 66h and db 67h when you need to change operand and/or effective address sizes of the next instruction to 16 bits.
    – Jules
    Commented Feb 23, 2018 at 19:16

1 Answer 1

12

One solution is to use the program published at COMPUTE! ISSUE 76 / SEPTEMBER 1986 / PAGE 100 :

http://www.atarimagazines.com/compute/issue76/AtariML.php

The program heavily utilizes the BASIC "self-programming trick".

First, let's explain the trick. An example - dynamically allocating a string of variable length - is located starting with line 31570:

PH 31570 GRAPHICS 0:POSITION 2,4:PRINT "31750 DIM TEMP$(";FILSIZ;"):RETURN"
FK 31580 PRINT "CONT":POSITION 2,0:POKE 842,13:STOP
FK 31590 POKE 842,12:GOSUB 31750

31570:

  • clear screen (GRAPHICS 0).
  • position the cursor leaving a little room above (POSITION 2,4)
  • Output the text of the program line that is to be added/changed. In this case, that's creation (or on subsequent runs overwrite) of line 31750 which contains a subroutine, allocating space for a new variable, and returning.

31580:

  • In the next line, output the command CONT - this command makes sense only in immediate context - used in a program it would trigger 'already running' error.
  • Position the cursor at the topmost line of the screen.
  • Perform a "magical" POKE 842,13 - I'm not sure what's 'behind the scenes' - 842 is the ICAX1 register, but I only managed to find the meaning of its 2 and 3 (device open for read and write); not bit 0 which is toggled here.
  • Perform 'STOP'. This is mostly equivalent to pressing BREAK - aborting the activity of the program, in a way that is resumable by the CONT instruction.

The moment the "Magical Poke" is executed Atari begins outputting the Return key repeatedly. The program is aborted before the cursor reaches the text on screen, so when it does, the computer is in immediate mode, but with "jammed Return". Whatever lines the cursor rides through, are executed as if they were typed in. In that case, that's the line preceded by the number - which gets written into the program - and then, the line CONT, which resumes execution from the next command after STOP. Which happens to be...

31590:

  • POKE 842,12 to cancel the cursor madness
  • GOSUB 31750 - execute the newly entered line.

Now, what the program actually does:

  • open the binary file for reading. (31540)
  • obtain file size (31560)
  • allocate a string of length corresponding to the binary length (using the self-programming trick) (31570)
  • load the binary into the memory location of the allocated string (31600)
  • output the contents of the string, wrapped in context of new program lines and variable assignments. (31610)
  • Enter them using the self-programming trick (31720),
  • Erase self from memory, using the self-programming trick. (31720)

It's up to the user to save the remaining program containing the gibberish strings of machine code.

1
  • 1
    For files, the low bit of ICAX1 is append (and read+write+append is an invalid combination), but other drivers can interpret them how they like. The screen driver appears to interpret the low bit to do, well, this. A more accurate way to say it would probably be "read from screen memory instead of the keyboard".
    – hobbs
    Commented Feb 8, 2017 at 18:45

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .