I’ve written a small program to demonstrate the problem (see below). In a nutshell it does the following:
- Point IIR to address 0x0100 in Flash, which is pre-filled with ISR stubs.
- Connect memory bank 2 to RAM.
- Set up stack.
- Call the
_main
function, which:
a. Disables the watchdog.
b. Sets parallel port B as output.
c. Optionally enables either periodic or Timer B interrupts.
d. Blinks some lights.
If I don’t enable either of the interrupts, the lights blink. As soon as I enable one or both of them, the board hangs.
.module crt0
GCSR .equ 0x00 ; Global control / status register
WDTCR .equ 0x08
WDTTR .equ 0x09
SWDTR .equ 0x0c
GOCR .equ 0x0e
MMIDR .equ 0x10
STACKSEG .equ 0x11
SEGSIZE .equ 0x13
MB0CR .equ 0x14 ; Memory Bank 0 Control Register
MB1CR .equ 0x15 ; Memory Bank 1 Control Register
MB2CR .equ 0x16 ; Memory Bank 2 Control Register
MB3CR .equ 0x17 ; Memory Bank 3 Control Register
PBDR .equ 0x40
PBDDR .equ 0x47
TBCSR .equ 0xb0
TBCR .equ 0xb1
TBM1R .equ 0xb2
TBL1R .equ 0xb3
TBM2R .equ 0xb4
TBL2R .equ 0xb5
.area _HEADER (ABS)
.org 0
; setup internal interrupts
ld a, #1
ld iir, a
; Configure physical address space.
; Leave MB0CR Flash at default slow at /OE0, /CS0
; Assume slow RAM at /CS1, /OE1, /WE1
ld a, #0x05
ioi
ld (MB2CR), a;
; Configure logical address space. 32 KB root segment followed by 8 KB data segment, 16 KB stack segement, 8 KB xpc segment.
; By default, SDCC will use the root segment for code and constant data, stack segment for data (including stack). data segment and xpc segement are then unused.
ld a, #0xa8 ; 16 KB stack segment at 0xa000, 8 KB data segment at 0x8000
ioi
ld (SEGSIZE), a
; Configure mapping to physical address space.
ld a, #0x76
ioi
ld (STACKSEG), a ; stack segment base at 0x76000 + 0xa000 = 0x80000
; Set stack pointer directly above top of stack segment
ld sp, #0xe000
call _main
jp _exit
.org 0x100 ; Periodic Interrupt
push af
ioi
ld a, (GCSR) ; clear interrupt
pop af
ipres
ret
.org 0x110 ; Secondary Watchdog - Rabbit 3000A only
ipres
ret
.org 0x120 ; rst 0x10
ret
.org 0x130 ; rst 0x18
ret
.org 0x140 ; rst 0x20
ret
.org 0x150 ; rst 0x28
ret
.org 0x160 ; Syscall instruction - Rabbit 3000A only
ret
.org 0x170 ; rst 0x38
ret
.org 0x180 ; Slave Port
ipres
ret
.org 0x1a0 ; Timer A
ipres
ret
.org 0x1b0 ; Timer B
push af
ioi
ld a, (TBCSR)
pop af
ipres
ret
.org 0x1c0 ; Serial Port A
ipres
ret
.org 0x1d0 ; Serial Port B
ipres
ret
.org 0x1e0 ; Serial Port C
ipres
ret
.org 0x1f0 ; Serial Port D
ipres
ret
.org 0x200
.area _HOME
.area _CODE
.area _INITIALIZER
.area _GSINIT
.area _GSFINAL
.area _DATA
.area _INITIALIZED
.area _BSEG
.area _BSS
.area _HEAP
.area _CODE
_exit::
1$:
jr 1$
_main:
ipset 0
ld hl, #0xffff
call _sleep
ld a, #0x51 ; disable watchdog
ioi
ld (WDTTR), a
ld a, #0x54
ioi
ld (WDTTR), a
ld a, #0xff ; parallel B as output
ioi
ld (PBDDR), a
;call _enable_periodic
;call _enable_timer_b
_blink:
ld hl, #0xffff
call _sleep
ld a, #0xff
ioi
ld (PBDR), a ; turn on all LEDs
ld hl, #0xffff
call _sleep
ld a, #0x00
ioi
ld (PBDR), a ; turn off all LEDs
jr _blink
_sleep:
ld a, h
or a, l
ret z
dec hl
jr _sleep
_enable_periodic:
ld a, #0x01
ioi
ld (GCSR), a
ret
_enable_timer_b:
ld a, #0x00
ioi
ld (TBM1R), a
ioi
ld (TBL1R), a
ld a, #0xff
ioi
ld (TBM2R), a
ioi
ld (TBL2R), a
ld a, #0x07
ioi
ld (TBCSR), a
ld a, #0x01
ioi
ld (TBCR), a
ret