2010-02-10

Next Project Minimal CP/M 68k

The Solarlight project has been taking more than normal, but the truth is I haven't had much time lately...so I decided to announce my next project, revive a minimal CP/M-68k system and document the process. The main components are a MC68008 CPU, a MC68901 MPU, 512K of SRAM, 32k EPROM, and a IDE/ATA connector. The MPU (multi-peripheral unit) will serve as UART and probably as basic memory manager, the IDE interface will probably be based in GIDE or something similar. While I'm still working on the schematics, I've already built the base circuit from my hand written schematics... here's a picture.

The sources and documentation of the code are available in Gaby's site. This site used the sources to build a VAX version, so the sources appear not to have suffered from too much of "bit rot".
For cross compiling and debugging I'll try to use binutils/gcc/gdb in remote mode. I'll try to build the cross tools (elf format, coff has been since long time killed) and a remote gdb-stub to download and debug some initial code... we'll see how it goes..
Here I've already built the cross-compiler toolchain for m68k-elf (binutils-2.20, gcc-core-3.4.6, gdb-6.8 and newlib 1.18.0), I didn't use a more recent one because from searching gcc-3.x.x is easier to cross compile with the newlib, and I wanted to use a smaller libraries than libc.
Download the sources from the gnu ftp site (except for newlib that is here), I followed this guide because not only it appeared simpler (no "bootstrap compiler" step) but also it is dedicated to embedded systems. Don't forget to move newlib and libgloss inside the gcc directory and after the binutils compile put them in the path. I also used gnu gdb instead of insight but no other than that.
Finally set the path in your .profile for your convenience, see here for details on OpenSuse.
My first objective after building the system on a breadboard is to download a small m68k assembly program to the EPROM EMULATOR and see it run, then a small C program and finally a gdb-stub. Then I'll have to repeat the process since from that point on there must be a change in the linker file as programs stop being linked to ROM but linked to RAM.
I've successfully assembled a "loop:nop,nop,bra.s loop" but a few problems or "unknowns" remain...
I've created my simple assembly file called test.S

/*
* test.S -- test file for assembler output
*/

#include "asm.h"
.title "test.S - test file for assembler output m68k-elf-as"
#define STACKSIZE 0x4000

.data

.text

.extern __stack

.global SYM (_start)
SYM (_start):
nop
nop
bra.s _start

I assemble it with "m68k-elf-gcc -c test.S -o test.o" then link it still with gcc "m68k-elf-gcc test.o -o test.x -nostartfiles -nostdlib -v -fpic -WL,Ttest.ld"
I had to include the -nostartfiles and -nostdlib to remove the standard crt0 and the global constructors for C++.
My current linker file is very simple and probably some things are missing for a full C program compilation but for now things appear to be ok.

/* ld file for rom programs */
/* for 8 cycles rom is at 0x00000 (fetch SP and PC), from then on 0x80000
/* STARTUP(crt0.o) - no startup file*/
OUTPUT_ARCH(m68k)
OUTPUT_FORMAT(srec)
SEARCH_DIR(.)
/*
*Setup the memory map of mini68k, stack grows down from high memory.
*/
MEMORY {
ram (rwx) : ORIGIN = 0x01000, LENGTH = 0x80000-0x01000
rom : ORIGIN = 0x80000, LENGTH = 64K }
/*
* allocate the stack to be at the top of memory, since the stack
* grows down, also PUSH => -(SP) = xx, i.e. predecrement therefore
* first stack address never gets written
*/

PROVIDE (__stack = 0x80000);

SECTIONS
{
.text :
{
_stext = .;
*(.text .text.*)
. = ALIGN(0x4);
_etext = .;
} > rom

.data :
{
*(.data .data.*)
_edata = .;
} > ram

.bss :
{
. = ALIGN(0x4);
__bss_start = . ;
*(.bss .bss.*)
_end = ALIGN (0x8);
__end = _end;
} > ram
} /* missing in the initial file - causes an error ld does not complain! - beware */

Then I can also successfully convert the object file test.x to a SRECORD file with the command "m68k-elf-objcopy -O srec test.x test.S19" and then revert the intermediate object file test.x to assembler with "m68k-lef-objdump -d -X test.x > test.dis"
After successfully removing all the initialization code gcc attaches to your code (with -nostartfiles -nostdlib(p.s. you only need the first one since you don't add any library function)) I was left with one question, why is my code placed at absolute address 0x80000054?? when I told in the linker file to put it at 0x80000 (less a few zeros in the middle) Here is the disassembly:

test.x: file format elf32-m68k

Disassembly of section .text:

80000054 <_start>:
80000054: 4e71 nop
80000056: 4e71 nop
80000058: 60fa bras 80000054 <_start>

Ok, this was a bug. I forgot a } in the memory definitions of the linker file *.ld... After adding it the code was located at the correct place 0x80000.
Well there are still some hurdles to overcome, namely:
- placing the start SP and start address in vectors 0 and 1;
- place the other vector in ram
- place the code in proper ROM addresses (and the initial SP,PC)
- download the code and see it run...
... the path through cross-gcc appears to be hard ...

8 comments:

Anonymous said...

Found it. The Art of Electronics, page 764, has a detailed description of the intricate dance required to have first a ROM, then a RAM at address $00000000 during the 68K boot sequence.

Anonymous said...

Details on how to set up RAM and ROM for 68K boot are in _The Art of Electronics_, pp 762-765.

Basically, you need a way to disable the RAM that would normally reside at $00000 and replace it with the ROM, but only until the restart vector and SP are read, then swap back to normal address decoding.

There are a number of ways to do this, but all involve messing with the chip selects of the RAM during the first few bus transfers.

Regards,
Peter

Alan Carvalho de Assis said...

Nice Work João!

Impressive!!!

Best Regards,

Alan

João Silva said...

Hello Peter,
I have "the art of electronics" but I've used a different solution. I used the solution in Motorola Application note AN897. It uses a shift register that is 0 for the first 8 AddressStrobe cycles and then on changes to 1.
My problem was the gnu ld, it was placing the code at a wrong place.. I found out that it was a bad loader file. My mistake...
I'll post it soon.

João Silva said...

Thanks Alan!

mjd said...

Hi João,

I saw this and thought you might like it.

http://blog.makezine.com/archive/2010/07/ultim809_homebrew_computer.html

Mitch

Unknown said...

Hi Mitch, thanks again...
this project is a bit on hold, there's never enough time. But another small step is close. I'll add the SDCard interface and try to read/write sectors, a copy of the arduino project. I'm also planning some development boards for old 8 bit micros.
Thanks for pointing it out.
JS

Mads Barnkob said...

It is a little funny to read about projects with the Motorola 68000 CPU. I work with ABB controllers back from 1986 which has a m68k processor and up to 4MB memory.

They are called ABB Masterpiece 200/1 and are very close in layout to most m68k projects, a good old school controller that is hard to down with the neck. As you can see they are still used almost 40 years old.