wickensonline.co.uk
Retrochallenge 2010 Winter Warmup Entry
Mecb
|
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:
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!
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.
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):
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