So, for this post I want to talk about my development environment and where I’m up to as far as the Retro Challenge.

I’ve had a lot of issues with this project. Initially I was cruising well and looking well on track to make something really cool, but then I damaged the board.

The board started to exhibit a fault with it’s ability to load bytes from ROM. This became apparent as I started porting the TS2 ROM Monitor. When the fault occurred I started to gradually break the application down to the point of just the minimal initialization stuff for the CPU and UART and printing a string from ROM to the UART.

As I was doing this testing, the CPU would appear to crash or not properly enter into any exception handler (even when forced too by using an illegal instruction!). After many, many days of trial and error and screaming at the board I finally broke it down to the point of it was either a faulty CPU or I’m a complete idiot and can’t write five m68k assembly instructions.

So, I cut my losses and switch to my fall back board that was a little newer and based on a MC68340 CPU. My main hesitation initially for not using this board to begin with was that it was a peripheral integrated CPU, which meant the board was basically ROM, RAM, CPU, and power related parts.

AMX AXC-EM board.
The AMX AXC-EM board.

As it stands I’ve had a much more enjoyable time working with this board and so have progressed much further with the software, rather than staring at a blinking LED and hoping it blinks just right this time (if you follow me on Twitter you’ll know what I mean)..

The Software Environment.

At the moment I’m writing everything in assembler for the m68k. I’m on a Macbook Pro and I run the m68k development environment in a Ubuntu Xenial VM using Vagrant. Rather than trying to setup the cross compiler in OSX, I just opted to use Linux and the Ubuntu m86k deb packages.

So, to edit the code I use a Vagrant share and access the files in OSX using Vim in iTerm, and in another panel I have an open SSH session into the VM to do the compilation.

To get the code onto the EEPROMs I use a TL866a MiniPro programmer, which I’ve compiled the open source command line tool for it in OSX. This means to program the EEPROMs I run the commands in OSX.

Sounds difficult but it’s really not. I have a Makefile which handles all the compiling and ROM images, plus outputting dump files. It also has the recipe for programming the even and odd ROM images to the EEPROMs via the MiniPro tool.

The flow sorta looks like this:

  • Makes changes to the source code in vim inside one iTerm pane.
  • Switch to the VM pane that’s SSH’d into the VM. Run the make compile command.
  • Switch back to the editor pane in iTerm.
  • Put the even EEPROM in the programmer.
  • From inside vim run the make commands to program the even EEPROM
  • Rinse repeat for the odd ROM

Here is the Makefile I’m using, you can see it here on Github too.

M68K=m68k-linux-gnu
AS=$(M68K)-as
LD=$(M68K)-ld
COPY=$(M68K)-objcopy
DUMP=$(M68K)-objdump

ASFLAGS=-m68340 --warn --fatal-warnings
LDFLAGS=-T m68k.ld
DUMPFLAGS=-m68020 -x -D

EEPROM=AT28C256
PREFIX=m68k-

FMT=binary

SRCS=loader.s
OBJS=$(SRCS:.s=.o)
MAIN=loader

.PHONY: dump clean

all:	$(MAIN)

.s.o:
	$(AS) $(ASFLAGS) -o $@ $<

$(MAIN): $(OBJS)
	$(LD) $(LDFLAGS) -o $(MAIN).a $(OBJS)
	$(COPY) -b 0 -i 2 --interleave-width=1 -O $(FMT) $(MAIN).a $(PREFIX)$(MAIN)-even.bin
	$(COPY) -b 1 -i 2 --interleave-width=1 -O $(FMT) $(MAIN).a $(PREFIX)$(MAIN)-odd.bin

clean:
	rm -f *.o $(PREFIX)$(MAIN)-even.bin $(PREFIX)$(MAIN)-odd.bin $(PREFIX)$(MAIN).bin $(MAIN).a

prog_even:
	@echo Programming $(MAIN)-even onto $(EEPROM)
	minipro -p "$(EEPROM)" -w $(PREFIX)$(MAIN)-even.bin -s

prog_odd:
	@echo Programming $(MAIN)-odd onto $(EEPROM)
	minipro -p "$(EEPROM)" -w $(PREFIX)$(MAIN)-odd.bin -s

dump:	$(MAIN)
	$(DUMP) $(DUMPFLAGS) $(MAIN).a

Compilation and Linking

As you can see from the Makefile above I’m using m68k-linux-gnu-as to assemble the object files from the source files. I am then using m68k-linux-gnu-ld to link the object file(s) into the .a archive object file. Which is then split into the even and odd ROM binary images needed for the two 8 bit EEPROMS to make the 16bit wide program data.

I have a small linker script to handle the vector mapping, the stack and RAM locations etc. This step makes moving the resources around very easy, which I’m now thankful for because the two boards I have are vastly different in memory map to each other.

MEMORY
{
    ROM (rx) : ORIGIN = 0x00000000, LENGTH = 0x10000
    RAM (xrw) : ORIGIN = 0x00040000, LENGTH = 0x10000
}

/* stack location */
stack_size = 1024;

_stack_start = ORIGIN(RAM)+LENGTH(RAM)-0x10;
_stack_end = _stack_start - stack_size;

/* ram location */
_ram_start = ORIGIN(RAM);
_ram_end = ORIGIN(RAM)+LENGTH(RAM);

/* system integration module */
_sim40 = 0x80000;
_timers = _sim40 + 0x600;
_uarts = _sim40 + 0x700;
_dma = _sim40 + 0x780;

SECTIONS {
  .vectors 0x00 :
  {
    . = ALIGN(4);
    KEEP(*(.vectors))
    . = ALIGN(4);
  } > ROM

  .text 0x400 : {
    . = ALIGN(4);
    *(.text)
    . = ALIGN(4);
  } > ROM

  .data : { *(.data) } > RAM
  .bss :  { *(.bss)  *(COMMON) } > RAM
}

OUTPUT_ARCH(m68k)

I’ve been trying to get an .rodata section working, but for whatever reason my sections end up with the wrong alignment and any strings I put there are in the ROM image, but don’t appear to work. Maybe when I get some times I’ll figure out why that is, for now I’m happy to just put the strings at the end of the .text section.

Initializing the MC68340 CPU

The MC68430 is a great CPU, it has a lovely set of peripherals, and some very nice features. However getting it going can be a little trick as both the RAM and ROM positions are controlled completely by the System Integration Module. The “SIM40” is a peripheral module in the MC68340 that basically handles all the address decoding and glue logic the other board had in 74 series ICs. This allows cool things like loading the START and SP registers from the ROM, and then moving the ROM up high in the memory map and replacing where the ROM would be with RAM. All with just a few instructions. Done in hardware you’d need complex gating or a GAL to achieve something similar.

So to start with here is a chunk of code that configures the ROM and RAM locations in the memory map, and configures the CPU speed and interrupt maps.

*************************************************************************
*
*  Init the CPU and System Integration Module - Configs module options
*
.init:
            move.w      #0x2700, %sr                    | mask interrupts and set supervisor mode

            moveq       #7, %d0
            movec       %d0, %dfc
            move.l      #_sim40 + 1, %d0
            moves.l     %d0, 0x3ff00                    | move sim40 base address to 0x80000

            /* setup ROM chip select CS0 */
            move.l      #0x03fffd, _sm_csam0 + _sim40   | 16 bit port, three wait, mask FC bits, 256KB in size
            move.l      #0x000001, _sm_csbar0 + _sim40  | starting at 0x00000

            /* setup RAM chip select CS1 */
            move.l      #0x03fff1, _sm_csam1 + _sim40   | 16 bit port, zero wait, mask FC bits, 256KB in size
            move.l      #0x040001, _sm_csbar1 + _sim40  | starting at 0x40000

            /* setup system protects and clock */
            move.b      #0x06, _sm_sypcr + _sim40       | turn off watchdogs, bus fault, bus monitor
            move.w      #0x7c00, _sm_syncr + _sim40     | set clock to 15.991 MHz
            move.w      #0x420f, _sm_mcr + _sim40       | set MCR, no interrupts etc

In this project I’ve just kept the memory map really simple.

  • 0x000000 is ROM
  • 0x040000 is RAM
  • 0x080000 is the SIM40 peripherals

I may switch the RAM and ROM around later as this would allow me to dynamically change the interrupt and trap vectors. Otherwise I have to hard code jumps to RAM locations inside the ROM where the vectors are in order to make them dynamic. At the moment I’m not really using interrupts, but I can see myself wanting too in the near future (also breakpoints etc in my ROM Monitor).

Initializing the MC68340

The MC68340 has a great suite of peripherals, from UARTs, Timers, System protection devices and DMA.

The internals of the MC68340

The SIM40 modules can move the addresses of these devices where ever you choose, but the layout is:

The SIM40 address structure

As you can see in the code above I’ve set it to the address of 0x080000. For this project at the moment I’m turning more stuff off than I’m turning on. By default all these peripherals are available and running, you have to disable them if you’re not using them. Realistically this is more about power reduction than anything, but like unused logic gates, I feel they must be put into a known state. :)

So I turn off all watchdogs, and system protection peripherals (eg. double bus fault monitors, bus monitors, reset etc), the timers, and the DMA. Since I need a UART I configure one and disable the other.

The boot-loader

Initially I was just going to port across an existing ROM monitor for the m68k, there are plenty of quality ones out there but given the time I lost on the faulty CPU/board I quickly realized I won’t be able to port the monitor quickly enough if I had to burn EEPROMs each time to make any actual application with the board. I set out to make an Mandelbrot set with this board, so debugging a monitor wasn’t something I had time to do.

So speaking to my friend @trc_wm he suggested getting just something dumb that dumps binary into RAM and jumps to it, then write some python to push the binary at the serial port.

I started implementing that until I saw a few pieces of code that would load srec format into RAM. I decoded the logic and wrote my own implementation in a few hours, I figured this would be all round simpler in the long run as I wouldn’t need to write the python. Instead I could just cut and paste the srec records straight into the terminal, or at the very least cat them out to the serial port.

Here is an example showing altering the code, compiling, copying the srecord data and running it:

GIF showing the boot-loader in action
Demo showing updating code and pushing it to the bootloader

Enough for today

That ought to do me for today. To achieve my goal of generating a Mandelbrot set with the board for the Retro Challenge, I’m going to work on either getting compiling C to run on the m68k, or port a BASIC/FORTH tomorrow and then write a Mandelbrot set generator in the chosen language.

We’ll see…

Updated:

Comments