Porting OpenBSD to the Solbourne S4000

[ Index ] [ Prev: Playing With The Hardware ] [ Next: Taming The MMU ]

Blinking The LED

So, I now could run arbitrary code on the box. But how far did it go? And how could it talk to me?

An easy way would be to have the code send characters to the serial port. But, on the ZSCC, this requires a few delays between registers programming, which can be a bit tedious. So, before I could be in a good enough situation to be able to talk over serial, I needed something simpler... and glancing at idt/cpuboard.h, I realized the front LED has 6 different states:

/* board status register */
#define iGLU_BSR (iGLU_BASE + 0x0001800)		/* physical address */
# define BSR_LED	0x07	/* mask for LED control bits */
#  define BSR_LED_OFF	0x00	/* LED off */
#  define BSR_LED_YEL	0x02	/* LED yellow */
#  define BSR_LED_BYEL	0x03	/* LED blink yellow */
#  define BSR_LED_GRN	0x04	/* LED green */
#  define BSR_LED_BGRN	0x05	/* LED blink green */
#  define BSR_LED_BALT	0x07	/* LED blink alternating yellow/green */
This would be good enough for a while...

So, I naively put something like this at the very beginning of my locore.s:

	set	0x60001800, %l1		! iGLU_BSR
	ld	[%l1], %l2
	andn	%l2, 7, %l2
	or	%l2, 2, %l2		! fixed amber
	st	%l2, [%l1]
Unfortunately for me, the LED did not become amber (the header file says yellow, but it lies). Yet the PROM had loaded and run my code! What could be wrong?

Nothing was wrong, really. Except that, when writing this code, I had made the following assumptions:

These are easy to check at the PROM, with some Forth code. Moreover, the PROM even defines an iglu-bsr symbol!

ok iglu-bsr .
So my first assumption is correct. Let's verify the second one:
ok iglu-bsr l@ .
It is correct. But something's fishy. The idt/cpuboard.h file only defines values for the low 6 bits of this register, so we should not have a value greater than 0000003f here...

Let's read it again.

ok iglu-bsr l@ .
Interesting. It looks like the top 8 bits are our value, while the low 24 bits are simply noise from the bus latches. Let's prove it by changing the LED status! Here our value was 1c, so the LED bits were 04 (1c & 07), solid green. If we want to turn this into flashing amber, we need to do something like this:
ok iglu-bsr l@ f8000000 and 03000000 or iglu-bsr l!
and the LED indeed turned flashing amber (the Forth sequence above reads iglu-bsr, ands the value read with f8000000, thus masking the low 24 bits and the LED mask, then ors it with 03000000, thus selecting BSR_LED_BYEL shifted 24 bits, and writes it into iglu-bsr).

My code quickly became:

ENTRY(blink)				! void blink(int);
	save	%sp, -64, %sp
	set	0x60001800, %l1		! iGLU_BSR
	ld	[%l1], %l2
	srl	%l2, 24, %l2
	andn	%l2, 7, %l2		! BSR_LED
	or	%l2, %i0, %l2
	sll	%l2, 24, %l2
	st	%l2, [%l1]
#define BLINK(how) \
	call	_C_LABEL(blink); \
	 mov	how, %o0
	BLINK(2)		! fixed amber
and I could pick my favorite LED state, and even call blink() from C code...

[ Index ] [ Prev: Playing With The Hardware ] [ Next: Taming The MMU ]