Index wersja polskawersja polska

Elektronika MK-85 - machine code programming

Executing machine code programs happens to be possible due to holes in the INPUT command implementation.

First example program

Traditionally, the first piece of code written in a new environment or language is one that prints "Hello world". This one will not be an exception, either:

        .radix  16              ;all numbers hexadecimal

start:  mov     #41,@#8264      ;system variable
loop:   jsr     r4,print1
        .asciz  "HELLO WORLD! "
        br      loop

print1: jsr     pc,@#1248       ;print string (ROM call)
        rts     r4

Unfortunately, there's a limited choice of codes which can be typed on the keyboard, and the program should to some degree look like BASIC to be accepted by the editor. The modified code below fulfills these requirements:

start:
8272:   bmi     82B6

8296:   jsr     r4,@#82B0
829A:   .asciz  "HELLO=WORLD!="
82A8:   jsr     r5,@#82AE
82AC:   sob     r0,8296
82AE:   rts     r5
82B0:   jsr     pc,@#1248
82B4:   rts     r4
82B6:   mov     #8041,@#8264
82BC:   sob     r0,8296

Finally, here's the code which has to be typed in the program area P0 (because only the first one has fixed starting address):

first machine code program

Regular Latin characters are coloured black, Cyrillic ones are red, graphic ones are green, BASIC keywords are blue. Care should be given to type them correctly, because different characters from different sets can look very similar.

Hex dump of the memory area storing the program

8260:  7B 81 00 00  81 00 00 00  00 08 00 0A  00 DF 38 32  {.............82
8270:  35 36 21 81  30 00 14 00  E7 00 1E 00  21 30 31 32  56!.0.......!012
8280:  33 34 35 36  37 38 39 00  28 00 21 30  31 32 33 34  3456789.(.!01234
8290:  35 36 37 38  39 00 1F 09  B0 82 48 45  4C 4C 4F 3D  56789.....HELLO=
82A0:  57 4F 52 4C  44 21 3D 00  5F 09 AE 82  0C 7E 85 00  WORLD!=._.......
82B0:  DF 09 48 12  84 00 DF 15  41 80 64 82  14 7E 00 00  ..H.....A.d.....

download mk85fipr.zip - RAM image for the emulator

Executing the program

  1. Start the program with the RUN command.
  2. When the INPUT prompt appears, type input string and confirm with [EXE], or simply press [AC].
  3. After the display is cleared and the cursor appears, press [EXE] again.
  4. A scrolling text should appear on the display. The program can be terminated by pressing [STOP].

How does it work

Altering the memory contents

Command INPUT treats the numeric literal in the argument field like a string variable $, which is caused by missing check what is actually returned by the expression evaluator (at about address 1C62). The string of up to 1E characters typed at the INPUT prompt is copied to the RAM address allocated to the variable. The address of the variable is taken from the second word of the stack entry. In case of a numeric literal this word contains first four digits of the mantissa.

Starting machine code programs

The method exploits an indirect jump via the variable 8258, found in the ROM at address 0E76. This part of the code can be, among others, reached from the direct mode main loop at about address 0BC6, originally designed to resume the BASIC program execution after a STOP condition.

The variable 8258 is misused by the INPUT procedure as temporary storage for the pointer to the next interpreted BASIC statement. Therefore, the data following the INPUT statement could be executed as machine code program if we manage to pass control to the direct mode main loop, while meeting following requirements:

In this situation pressing [EXE] is incorrectly interpreted as a request to resume the BASIC program execution, which effectively starts the user's machine code pointed to by variable 8258.

Currently there are two methods known to me to enter the direct mode main loop:

1. Creating a false STOP condition

Usually the STOP condition is caused either by pressing the [STOP] key, or by the STOP instruction, or in the TRACE mode. It's handled by the routine 179A, which displays the program and line number, then goes to the direct mode.

A false STOP condition can be forced by setting bit 0 of the mode variable 8256 by changing the contents of this variable from 8000 to 8001 (by typing the string input string in response to the INPUT 8256 statement in the line 10). Character code 01 cannot be typed from the keyboard, but code 31 (character '1') fits our purposes too. Typing '1' alone would also change the most significant byte of the mode variable to 00, because the typed string is terminated by zero. So, it is necessary to enter three more characters to preserve the next system variable 8258 as well. The terminating byte 00 will affect the variable 825A, which is unimportant in this context.

To enter the direct mode, some BASIC command valid both in program and direct modes has to be executed, for example VAC (in line 20). These commands have a common exit point at address 1652, where the program flow continues to the direct mode main loop 0BA0, or the BASIC interpreter main loop, depending on the state of the bit 0 of the mode variable.

2. Breaking the INPUT statement with the [AC] key

The [AC] key is handled at address 05C0 in the ROM. This procedure clears the input buffer and the display, then enters the direct mode main loop without altering the variables 8256 and 8258. When using this method, the INPUT argument doesn't matter (it doesn't need to be a numeric literal, any variable would do), neither does the VAC command in the line 20 (as it never gets executed).


More advanced programming

Writing machine code distinguished as BASIC appears to be a cumbersome and time consuming task. The procedure described below allows assembly programming without any artificial limitations.

Memory allocation

This step creates a safe place for machine code programs by changing the ramtop system variable 8252. The space from the ramtop up to physical end of the RAM will remain unaccessible to the BASIC interpreter.
The ramtop variable can be modified with following program:

10 INPUT 8252:VAC

Writing 8680 to the ramtop variable will give a space of 0180 bytes starting at address 8680 (all numbers hexadecimal). This value is equivalent to a string input string typed at the INPUT prompt. The program needs to be run only once. The new memory configuration will last until the init switch on the back of the calculator is pressed, or the TEST command is executed.

Simple hex loader

Next program will copy a binary file (stored as a list of hex numerals in BASIC lines) to the destination area, then perform an indirect jump to the beginning of the code. As in the previous example, some weirdness is caused by the need to squeeze it to the imposed BASIC program layout.

        .radix  16

        .loc    8272
start:  bmi     start1

        .loc    8286
exec:   jmp     (r5)

loop:   tstb    (r2)+           ;separator or end-of-line character
        nop
        bne     byte
        nop
        jsr     r0,@#return     ;dummy
line:   tstb    (r2)+
        cmpb    (r2)+,#2727     ;test if line number > 9987
        bcc     exec1
        tstb    (r2)+           ;skip the '!'
        nop
        jsr     r0,return       ;dummy
byte:   jsr     pc,@#digit
        nop
        jsr     pc,digit
        inc     r4              ;dummy
        movb    r0,(r3)+
        sob     r1,loop
exec1:  sob     r2,exec

start1: bmi     start2

return: rts     r0

digit:  asl     r0
        asl     r0
        asl     r0
        asl     r0
        nop
        mov     r0,-(sp)
        movb    (r2)+,r0
        cmpb    r0,#4141        ;'A'
        bcs     digit1
        sub     #3737,r0
        add     (sp)+,r0
        rts     pc

start2: mov     #4080,r1        ;arbitrary chosen value
        add     #8800-4080,r1   ;r1 = top of RAM
        nop
        mov     #4080,r2
        add     #data+1-4080,r2 ;r2 = source address
        nop
        mov     8252,r3         ;destination address = ramtop
        mov     r3,r5           ;jump vector
        sub     r3,r1           ;max. number of bytes
        sob     r2,line

digit1: sub     #3030,r0
        add     (sp)+,r0
        rts     pc

data:                           ;data start here

machine code loader

The loader program should be followed by a sequence of BASIC lines containing a list of bytes in hexadecimal format, starting with an exclamation mark, and separated by a single character (comma or space preferred). Any number of bytes in a line is allowed. The code should be terminated by a line with a number 9988 or greater. The example below was assembled from the initial version of the "Hello world" program:

9000 !DF,15,41,00,64,82,37,09
9010 !10,00,48,45,4C,4C,4F,20
9020 !57,4F,52,4C,44,21,20,00
9030 !F6,01,DF,09,48,12,84,00
9999 END

It's a lot of typing! Everything should be checked twice before proceeding!
So looks the loader along with the data lines in the RAM:

8260:  6D 81 00 80  00 80 00 00  00 00 00 0A  00 DF 38 32  m.............82
8270:  35 36 21 81  30 00 14 00  E7 00 1E 00  21 30 31 32  56!.0.......!012
8280:  33 34 35 36  37 00 4D 00  D2 8B A0 00  0B 02 A0 00  34567.M.........
8290:  1F 08 B8 82  D2 8B 97 A4  27 27 0C 86  D2 8B A0 00  ........''......
82A0:  37 08 14 00  DF 09 BA 82  A0 00 F7 09  0C 00 84 0A  7...............
82B0:  13 90 56 7E  98 7E 0F 81  80 00 C0 0C  C0 0C C0 0C  ..V.............
82C0:  C0 0C A0 00  26 10 80 94  17 A0 41 41  13 87 C0 E5  ....&.....AA....
82D0:  37 37 80 65  87 00 C1 15  80 40 C1 65  80 47 A0 00  [email protected]
82E0:  C2 15 80 40  C2 65 7D 42  A0 00 C3 17  52 82 C5 10  [email protected]}B....R...
82F0:  C1 E0 B0 7E  C0 E5 30 30  80 65 87 00  28 23 21 44  ......00.e..(#!D
8300:  46 2C 31 35  2C 34 31 2C  30 30 2C 36  34 2C 38 32  F,15,41,00,64,82
8310:  2C 33 37 2C  30 39 00 32  23 21 31 30  2C 30 30 2C  ,37,09.2#!10,00,
8320:  34 38 2C 34  35 2C 34 43  2C 34 43 2C  34 46 2C 32  48,45,4C,4C,4F,2
8330:  30 00 3C 23  21 35 37 2C  34 46 2C 35  32 2C 34 43  0.<#!57,4F,52,4C
8340:  2C 34 34 2C  32 31 2C 32  30 2C 30 30  00 46 23 21  ,44,21,20,00.F#!
8350:  46 36 2C 30  31 2C 44 46  2C 30 39 2C  34 38 2C 31  F6,01,DF,09,48,1
8360:  32 2C 38 34  2C 30 30 00  0F 27 E4 00  00 00 00 00  2,84,00..'......

download mk85load.zip - RAM image for the emulator

The program should be started the same way as the previous "Hello world" example.

Once the machine code is in place, the loader program can be deleted. The machine code will stay in the memory until the init switch on the back of the calculator is pressed, or the TEST command is executed.

Starter program

This short program executes the loaded machine code in absence of the loader:

82B6:   mov     @#8252,r0
82BA:   jmp     (r0)

starter program

8260:  6D 81 00 80  00 80 00 00  00 00 00 0A  00 DF 38 32  m.............82
8270:  35 36 21 81  30 00 14 00  E7 00 1E 00  21 30 31 32  56!.0.......!012
8280:  33 34 35 36  37 38 39 00  28 00 21 30  31 32 33 34  3456789.(.!01234
8290:  35 36 37 38  39 00 32 00  21 30 31 32  33 34 35 36  56789.2.!0123456
82A0:  37 38 39 00  3C 00 21 30  31 32 33 34  35 36 37 38  789.<.!012345678
82B0:  39 30 31 32  33 00 C0 17  52 82 48 00  00 00 00 00  90123...R.H.....

download mk85strt.zip - RAM image for the emulator