Retrochallenge 2010
      Winter Warmup
      Mark Wickens
      8-Jan-2010

                             Motorola Educational Computer Board

      So, logically after yesterdays Amiga excursion we come to the MECB. It's a
      single board computer using the MC68000 processor (the same as the Amiga). My
      board is actually a clone of the original one produced by Motorola, but apart
      from more memory and some different peripheral addresses it's almost identical.
      The clone manual specifies the following features:

      a. 8 MHz 68000 16-bit MPU
      b. 16K SRAM (6264 x 2) or 64K SRAM (256 x 2)
      c. 64K EPROM (27256 x 2) or 128K EPROM (27512 x 2)
      d. Two RS-232e serial ports (9600 or 19200 baud)
      e. One timer/counter and one 24-bit parallel port
      f. Self-contained operating firmware that provides monitor and debug function
      g. Individual LEDs indicate: 68000 free-run, DTACK, RAM/EPROM chip enable volt
         only operation
      i. Size 8" x 5"

      The board looks like this:

      MECB Clone

      The board was shipped with a copy of the Tutor firmware as developed for the
      original MECB. This is a sophisticated application that provides you with a
      command line interface for interacting with the board, running programs, dumping
      memory and assembling/disassembling source code. The board connects to a host
      computer via a serial cable.

      The ROMs supplied with the clone board had an assembly error embedded which
      corrupts the TRAP #14 function table. The TRAP #14 table is table of functions
      which can be called using the TRAP assembler instruction. This is similar to an
      MS-DOS int call - specifying different arguments allows interaction with the
      boards 'bios' to do things like output characters to the terminal, read input,
      send data to an attached printer, and perform simple conversions.

      In order to get the board working I had to correct the assembly error by using a
      copy of the MECB tutor code formatted for the excellent windows-based Easy68k
      assembler [1], split the resulting binary file into high and low byte blocks,
      burn two EPROMS and replace the supplied EPROMS. Unbelievably, all that worked!

      Easy68k Screenshot

      Having done a project last time in assembly language I thought I'd see if I
      could find a C compiler to speed any development. I searched high and low
      without much success then when I'd almost given up I found ide68k[2]. This is a
      Windows application developed by Peter J. Fondse which couldn't have been a
      better fit for what I need. The compiler assumes very little about the
      underlying hardware. It uses a very simple assembler cstart file (anyone who's
      delved into C under-the-hood will know it or something similar) which is the
      bootstrap file to setup the  environment for a program before jumping into the
      main() function.

      IDE68K About

      By altering the cstart file to use TRAP #14 functions I was able to define basic
      input and output. For example, I defined the __putch() function as follows:
      
              __putch:                           ; Basic character output routine
                     link      A6,#0
                     move.l    8(A6),D0
                     movem.l   D7,-(A7)          ; Push D7 onto stack
                     move.b    #248,D7           ; trap #14 function 248 - OUTCH
                     trap      #14
                     movem.l   (A7)+,D7          ; restore D7
                     unlk      A6
                     rts

      The key lines of interest are highlighted in the middle of the function. The
      first line puts the character supplied to the function into the register D0. The
      second line stores the TRAP #14 function call number, in this case 248 (which is
      defined as 'OUTCH - Output single character to Port 1' and then TRAP #14 is
      called. This enters the Tutor 'bios' routine to output a single character.

      The __getch() function is similarly defined:

              __getch:                           ; Basic character input routine
                     movem.l   D7,-(A7)
                     move.b    #247,D7
                     trap      #14
                     ext.w     D0
                     ext.l     D0
                     movem.l   (A7)+,D7
                     rts

      In this case the TRAP #14 function call number 247, 'INCHE - Input single
      character from Port 1' is called, the result of the call being the lower byte of
      D0. This is extended to a word then a long. The compiler is defined to return
      the result of a function in D0, so it's all ready to use in the return.

      So I created the familiar Hello World example:

              #include <stdio.h>

              void main()
              {
                  printf("Hello world!\n");
              }

      but this didn't work, and once I'd traced the code through I decided to try a
      simpler test, as the printf() statement above was pulling in lots of functions
      (it is after all a fairly powerful function).

      So, as an example, the slightly simpler code below:

              #include <stdio.h>

              void main()
              {
                  putch('H');
                  putch('e');
                  putch('l');
                  putch('l');
                  putch('o');
                  putch('\n');
              }

      results in the following assembly language source code (I've omitted code not
      directly relevant, and once I'd worked out (by reading the help system!) that
      the order of files as defined in the ide68k project defines the order in which
      the code appears in the resulting binary output I managed to get the code to run
      successfully on the MECB.

              ; CSTART.ASM  -  C startup-code for SIM68K

              lomem  equ       $1000            ; Lowest usable address
              himem  equ       $8000            ; Highest memory address + 1
              stklen equ       $1000            ; Default stacksize

                     org       lomem
              start:
                     move.l    #-1,__ungetbuf
                     clr.l     __allocp
                     lea       himem,A7
                     jsr       _main
                     bra.s     __exit

              _main:
                     movem.l   A2,-(A7)
                     lea       _putch,A2
              ; putch('H');
                     pea       72
                     jsr       (A2)
                     addq.w    #4,A7
              ; putch('e');
                     pea       101
                     jsr       (A2)
                     addq.w    #4,A7

                      ...

              ; putch('\n');
                     pea       10
                     jsr       (A2)
                     addq.w    #4,A7
                     movem.l   (A7)+,A2
                     rts
              ; }

      To run the code on the MECB it needs to be loaded via the serial cable. Motorola
      defined a standard for this - the S-record standard, which is a way of encoding
      a binary file in plain ASCII. The ide68k program outputs such a file:

              LO1;X
              S004000000FB
              S113100023FCFFFFFFFF0000110E42B90000111284
              S11310104FF9000080004EB90000109E60104E563B
              S11310200000202E00084E5EDFFC0000000A1E3C7B
              S113103000E44E4E60CA4E560000202E000848E7D9
              S113104001001E3C00F84E4E4CDF00804E5E4E7593
              S113105048E701001E3C00F74E4E488048C04CDF74
              S113106000804E7561EA56C04E754FF9000080004D
              S113107041FA00084E4F000760B4537461636B205B
              S11310806F766572666C6F77210A0D50726F6772A6
              S1131090616D2061626F727465640A0D000048E737
              S11310A0002045F9000010DE487800484E92584F61
              S11310B0487800654E92584F4878006C4E92584FCD
              S11310C04878006C4E92584F4878006F4E92584FB3
              S11310D04878000A4E92584F4CDF04004E754E5625
              S11310E0000048E72000242E00080C820000000ABB
              S11310F0660A4878000D6100FF3E584F2F026100D8
              S1131100FF36584F20024CDF00044E5E4E75FFFF41
              S1111110FFFF000000000000111E0000700030
              S9031000EC

      I've added the first line manually - this tells the MECB to load a program from
      port 1 (the one connected to the PC). The S-record format is pretty
      straightforward, the digit after the initial S is the record type. The 'meat' of
      the program is stored in type 1 records. Taking the first line as an example we
      have:

      S113100023FCFFFFFFFF0000110E42B90000111284

      This can be broken down as follows:

      S1 | 13 | 1000 | 23FCFFFFFFFF0000110E42B90000111284

      S1 - record type
      13 - number of two-character (one byte) records to follow
      1000 - address to which data should be stored
      23FC... - the actual data

      The data can be machine code or program data - the MECB doesn't care what it is
      as it's being loaded, only when you try and run it.

      On an operational level, I use Tera Term VT as my terminal onto the MECB because
      it allows you to set a delay when sending data to the MECB (if the delay isn't
      present the MECB experiences buffer overflow):

      Tera Term Serial Options

      Once the S-records have been loaded the Motorola returns to the Tutor prompt.
      The Tutor firmware accepts uppercase-only commands, the following command does a
      memory dump from 1000 to 1030 using the disassembly option:

              TUTOR  1.3 > MD 1000 30;DI
              001000    23FCFFFFFFFF0000110E MOVE.L  #-1,$0000110E
              00100A    42B900001112         CLR.L   $00001112
              001010    4FF900008000         LEA.L   $00008000,A7
              001016    4EB90000109E         JSR.L   $0000109E
              00101C    6010                 BRA.S   $00102E
              00101E    4E560000             LINK    A6,#0
              001022    202E0008             MOVE.L  8(A6),D0
              001026    4E5E                 UNLK    A6
              001028    DFFC0000000A         ADD.L   #10,A7
              00102E    1E3C00E4             MOVE.B  #228,D7

              TUTOR  1.3 >

      I can then run the program by loading the start address into the program counter
      register and either using the G command to GO or the T command to trace:

              TUTOR  1.3 > .PC 1000

              TUTOR  1.3 > G
              PHYSICAL ADDRESS=00001000
              Hello

              TUTOR  1.3 >

      There is the magic word 'Hello' output to the terminal! Hurrah! Tracing the
      program results in a full register dump after each instruction is executed:

              TUTOR  1.3 > .PC 1000

              TUTOR  1.3 > T
              PHYSICAL ADDRESS=00001000
              PC=0000100A SR=2708=.S7.N... US=FFFFFFFF SS=00007FDC
              D0=000010CE D1=00004D3B D2=00000048 D3=00000000
              D4=00000000 D5=00000030 D6=FFFFFFFF D7=FFFFFFF8
              A0=000211C2 A1=00020350 A2=0000054E A3=0001094D
              A4=0001090E A5=00000540 A6=00007FDC A7=00007FDC
              --------------------00100A    42B900001112         CLR.L   $00001112

              TUTOR  1.3 :> T
              PHYSICAL ADDRESS=0000100A
              PC=00001010 SR=2704=.S7..Z.. US=FFFFFFFF SS=00007FDC
              D0=000010CE D1=00004D3B D2=00000048 D3=00000000
              D4=00000000 D5=00000030 D6=FFFFFFFF D7=FFFFFFF8
              A0=000211C2 A1=00020350 A2=0000054E A3=0001094D
              A4=0001090E A5=00000540 A6=00007FDC A7=00007FDC
              --------------------001010    4FF900008000         LEA.L   $00008000,A7

              TUTOR  1.3 :>

      After I'd fixed the putch() function I recompiled the original Hello World
      program and sure enough although the binary was much larger it worked fine:

              TUTOR  1.3 > .PC 1000

              TUTOR  1.3 > G
              PHYSICAL ADDRESS=00001000
              Hello World!

      I guess that's probably enough for the first installment. I'm not sure what I
      can get done in the time available to me this month, so I'm certainly open to
      suggestions! I was going to make a large multi-digit seven-segment display, but
      that will have to wait for now. Something slightly simpler - I might have a go
      at a VT terminal based game. Any ideas?

      
      ENDNOTES

      1. Easy 68K Assembler

      2. IDE68k