HomeAbout MeProjectsContactMeow

68000 Tablet - First Program

27 May 2020

I finally have enough parts to start running programs on my 68000 tablet. The only thing I'm missing is the 68681, which is required to use the serial port.

I did had to make a small modification to the board to get it running though. I decided to switch from EPROMs to EEPROMs, and the new EEPROMs had a slightly different pinout. The only thing I had to change was to assert the ~WE pin HIGH so that I could actually read from the chip. This was done by running a wire from each ~WE pin to the VCC pin of an unused socket. Other than that, the board has no significant bugs!

As a simple test, I thought I'd blink a light. My source code is below:

  /*
	  Tests the timer circuit/interrupt.
	  Code enters an infinite loop at 0x1000.
	  This lights up only one of the address LEDs.
	  Once the timer interrupt fires 386 times, we
	  switch to 0x2000. We flip back to 0x1000
	  after another 386 interrupts. The result of this
	  is that the address LEDs toggle between 0x1000
	  and 0x2000 every second.
  */

	  .global _start
	  /* we have 256KB of RAM connected
	  however a17 is connected to CE2, so we
	  need to assert it
	  and RAM is only enabled from 1MB to 2MB
	  hence the weird number here
	  this stores the interrupt count
	  (how many times the timer interrupt
	  has fired)
	  */
	  .equ INT_COUNT, 0x140000
	  /* Are we at 0x1000 or 0x2000? */
	  .equ WHEREWEAT, 0x140002
	
	  .long 0x140500				/* stack pointer */
	  .long _start

	  .org 0x100
	  .long timer /* Timer vector */

	  .org 0x400

  _start:
	  MOVE.W #0, (INT_COUNT)			/* set int count to 0 */
	  MOVE.B #0, (WHEREWEAT)			/* set whereweat to 0 */
	  /* Enable interrupts by negating int mask */
	  ANDI.W #0xF8FF, %sr
	  JMP LOWER_LOOP

  timer:
	  MOVE.W (INT_COUNT), %d0		/* Increment INT_COUNT */
	  ADD.L #1, %d0
	  CMP #386, %d0
	  BEQ timer_rollover
	  MOVE.W %d0, (INT_COUNT)
	  RTE							/* done */

	  /* Timer interrupt triggered 386 times */
  timer_rollover:
	  MOVE.W #0, (INT_COUNT) 		/* reset counter */
	  MOVE.B (WHEREWEAT), %d1
	  EORI.B #1, %d1				/* flip WHEREWEAT */
	  MOVE.B %d1, (WHEREWEAT)
	  CMP.B #1, %d1
	  BNE timer_upper /* temp */
	  /* switch to 0x1000 */
	  MOVE.L #0x1000, (2, %ssp)	/* Overwrite PC in stack */
	  RTE							/* done */
  timer_upper:					/* switch to 0x2000 */
	  MOVE.L #0x2000, (2, %ssp)
	  RTE							/* done */

	  .org 0x1000
  LOWER_LOOP:
	  JMP LOWER_LOOP				/* Infinite loop */
	
	  .org 0x2000
  UPPER_LOOP:
	  JMP UPPER_LOOP

Basically, we define two infinite loops: one at 0x1000, and one at 0x2000. The timer interrupt fires roughly 386 times per second, so we count the number of times it fires and use that to call the timer_rollover branch roughly once per second. When it fires, we flip between 0x1000 and 0x2000.

Video below. I put a box over the data bus LEDs because they were washing out the imagine significantly. One of these days, I'm going to put higher-value resistors in place.

As you can see, it works as intended! It took me a few hours to get it running properly on the computer. Debugging with LEDs is a huge amount of fun!