[Software] Minimal PC Engine startup code.

hu, cd, scd, acd, supergrafx discussions.
Post Reply
User avatar
MooZ
Site Admin
Posts: 386
Joined: Sun Jun 22, 2008 3:19 pm
Location: Lvl 3
Contact:

[Software] Minimal PC Engine startup code.

Post by MooZ » Sun Apr 05, 2015 4:55 pm

Let say you want to start coding something for the PC Engine but you want to do it all by yourself.
At first it sounds simple. Nonetheless, there are a few "gotchas".

1. Interrupt vectors.
Interrupts vectors are the addresses of the routines run when interrupts are triggered. There are 4 of them. I will not describe them here, but the most important one is the RESET IRQ vector. It specifies the address of the first instruction to run when the console is powered on. This address must be in the first ROM page. Basically this is what you will have:

Code: Select all

    .data
    .bank 0        
    .org $fff6

    .dw irq_2                ; irq 2
    .dw irq_1                ; irq 1
    .dw irq_timer            ; timer
    .dw irq_nmi              ; nmi
    .dw irq_reset            ; reset

    .code
    .bank 0
    .org $e000
irq_2:
    ; [...]
    rti

irq_1:
    ; [...]
    rti

irq_timer:
    ; [...]
    rti

irq_nmi:
    ; [...]
    rti

irq_reset:
    ; This is your "main" program code.
    ; Usually it is some setup code followed by an infinite loop.
.loop:
    bra    .loop
There's no need for these addresses to be different. Nothing prevents you from using the same address. For example you can have something like this:

Code: Select all

    .data
    .bank 0        
    .org $fff6

    .dw irq_dummy            ; irq 2
    .dw irq_dummy            ; irq 1
    .dw irq_dummy            ; timer
    .dw irq_dummy            ; nmi
    .dw irq_reset            ; reset

    .code
    .bank 0
    .org $e000
irq_dummy:
    ; Even if we will not use any interrupt, it is safer and cleaner to declare a dummy one.
    rti

irq_reset:
    ; This is your "main" program code.
    ; Usually it is some setup code followed by an infinite loop.
.loop:
    bra    .loop
An important note. We set the address for the irq routines and vector to start at $e000 and $fff6. This means that the physical address will be computed using the bank address used in the MPR #7. At power-up all the MPRs are set to zero. This means that any address will hit the first ROM bank.. By convention, the MPR #7 is always set to 0. At this time, I don't know if changing the value of MPR #7 to another bank will make the CPU fetchs the address of the handler routine in this bank.

2. RESET IRQ vector.
As written in the previous section, this is the "boot" or startup program. There are couple of things to do before playing with graphics or sound.
The first thing is to disable interrupts with sei. In fact if you look at the vast majority (if not all) the PC Engine games, this is the first instruction executed. This will disable all the interrupts. It's a safeguard because all the MPRs, VDC, VCE, PSG, Status registered are unitialized at this point.
The next thing to do is to setup the CPU speed using csh to select high speed mode (7.16MHz) or csl for low speed mode (1.76MHz). At power-up the CPU is in low speed mode. The only time this mode is needed is during Backup RAM accesses.
The PC Engine supports the use of a decimal flag that will switch arythmetic operation to decimal mode. This means that numbers (and registers) are BCD encoded. Once again, this special feature is not needed. The decimal mode must then be disabled by calling the cld instruction.
The stack pointer must be set otherwise the stack instructions (pla, pha, ...) will produce weird results. This is done by using the txs which will use the value stored in the X register to set the value of the stack pointer. This pointer goes backward. It is decremented when something is pushed, and incremented when a byte is pulled from the stack. The stack is then empty when the stack pointer equals #$ff.

Code: Select all

    ldx #$ff
    txs
The first 2 MPRs must be initialized with #$ff and #$f8 respectively. The bank #$ff is the I/O bank, and #$f8 is the RAM.
To sum it up:

Code: Select all

irq_reset:
    sei         ; disable interrupts
    csh         ; select the 7.16 MHz clock
    cld         ; clear the decimal flag
    ldx #$FF    ; initialize the stack pointer
    txs
    lda #$FF    ; map the I/O bank in the first page
    tam #0
    lda #$F8    ; and the RAM bank in the second page
    tam #1
At this point, you can start configuring the VDC, VCE, PSG, etc... Before that, you can also make sure the RAM is clean by using the one of the transfer instruction. For example:

Code: Select all

    stz $2000                ; clear all the RAM
    tii $2000,$2001,$1FFF

Debvgger
Posts: 13
Joined: Sun Jun 29, 2008 4:30 pm

Re: [Software] Minimal PC Engine startup code.

Post by Debvgger » Sun Apr 05, 2015 5:13 pm

OK, this was beyond awesome, thank you very much for your help ;-)

Debvgger
Posts: 13
Joined: Sun Jun 29, 2008 4:30 pm

Re: [Software] Minimal PC Engine startup code.

Post by Debvgger » Mon Apr 06, 2015 9:27 pm

Change "irq_rest" for "irq_reset" ;)

User avatar
MooZ
Site Admin
Posts: 386
Joined: Sun Jun 22, 2008 3:19 pm
Location: Lvl 3
Contact:

Re: [Software] Minimal PC Engine startup code.

Post by MooZ » Tue Apr 07, 2015 8:23 am

Woops!

I think I'll add some explanations about IRQ setup and VDC display registers ($0A-$0E) initialization as it's usually done at startup.

Post Reply