As mentioned in previous post, Matej asked me if Dreamtracker app is running on X65. I told him that yes, it should run, but better to test it first myself. I downloaded Dreamtracker in its current version V0.71, fired it up, and well, after a promising start – I could see its main menu for a split second – the program crashed into the Monitor…. Well, that felt embarrasing 😮
This youtube video shows the crashed start:
![](https://www.jsykora.info/wp-content/uploads/2024/10/dt-monitor.png)
The Monitor report indicates the crash was caused by executing a BRK instruction. In 6502 CPU the BRK instruction has the opcode $00, and the value is typically used as a filler byte in empty regions. The PC=0xFEAC and RO=0x00 indicates the instruction was executed at a location near the end of the first ROM bank.
I wanted to see exactly from where the CPU came to this instruction address. I don’t know how to do that on a regular 6502-based system, but on my X65 it was not so difficult. NORA FPGA already has a built-in In-Circuit Debugger (ICD). The ICD monitors instruction stream executed by the CPU in real time and stores instruction trace in a 512-element ring buffer, which could be read out to a PC over the USB link any time. NORA can also send ABORT signal the CPU when specific conditions in the instruction stream are encountered. Therefore, all I needed was to (temporarily) modify ICD in the FPGA to stop the CPU clock when the BRK opcode (0x00) is executed. This was done and these are the last seven instructions before the faulting BRK opcode:
Cyc # -25: MAH: 0 (low : 0) CBA: 0 CA: 3c3 CD:68 ctr:1f:---- sta:7f:r--emxPDS PLA
Cyc # -21: MAH: 0 (low : 0) CBA: 0 CA: 3c4 CD:85 ctr:1f:---- sta:7f:r--emxPDS STA $01
Cyc # -18: MAH: 0 (low : 0) CBA: 0 CA: 3c6 CD:68 ctr:1f:---- sta:7f:r--emxPDS PLA
Cyc # -14: MAH: 0 (low : 0) CBA: 0 CA: 3c7 CD:40 ctr:1f:---- sta:7f:r--emxPDS RTI
Cyc # -8: MAH: 1 (low : 1) CBA: 0 CA:372c CD:a9 ctr:1f:---- sta:7f:r--emxPDS LDA #$08
Cyc # -6: MAH: 1 (low : 1) CBA: 0 CA:372e CD:20 ctr:1f:---- sta:7f:r--emxPDS JSR $feab
Cyc # 0: MAH:41 (RomB: 0) CBA: 0 CA:feab CD: 0 ctr:1f:---- sta:7f:r--emxPDS BRK #$00
Let’s have a look at the instructions. The first four must be a part of an interrupt handler which ends with RTI, Return From Interrupt. Then we have “LDA #$08” which loads the value 0x08 into Acumulator register and “JSR $feab” a Jump to Subroutine at the address 0xFEAB. At this address the processor encounters the BRK instruction and NORA has stopped it. It really looks that the jump to $FEAB in ROM is intentional in the Dreamtracker code. So I searched the Dreamtracker code source and I found it pretty quickly: in the file x16.inc there are the following definitions of jump addresses:
...
SCREEN_SET_MODE := $FF5F
SCREEN_SET_CHARSET := $FF62
screen_set_charset := $FF62
extapi := $FEAB <=== HERE
i2c_write_byte := $FEC9
I2C_WRITE_BYTE := $FEC9
entropy_get := $FECF
....
Evidently $FEAB is supposed to be extapi
in the ROM. We can find several references to extapi
throughout the dreamtracker code, for example here in the main:
; Check for input from the keyboard, and do something if
; a key was pressed (return value is something other than 0)
check_keyboard:
;sei
; call ps2data_fetch
lda #$08
jsr extapi <=== HERE
jsr SCNKEY
jsr GETIN ;keyboard
beq main_application_loop
sta zp_KEY_PRESSED
I searched extapi
in my copy of X16 ROM sources, and found none. Then I searched for $FEAB and found it in vectors.s
:
; *** this is space for new X16 KERNAL vectors ***
;
; !!! DO NOT RELY ON THEIR ADDRESSES JUST YET !!!
;
.byte 0,0,0 ; $FEA8
.byte 0,0,0 ; $FEAB <=== HERE :-(
.byte 0,0,0 ; $FEAE
jmp mciout ; $FEB1
jmp i2c_batch_read ; $FEB4
Oh, evidently the vector is not used – in my copy of the ROM. I updated to the latest CX16 ROM version R48 and there it was – the extapi
function is now defined at that specific address!
; *** this is space for new X16 KERNAL vectors ***
;
jmp extapi16 ; $FEA8
jmp extapi ; $FEAB <=== HERE :-)
.byte 0,0,0 ; $FEAE
jmp mciout ; $FEB1
jmp i2c_batch_read ; $FEB4
Now I was pretty confident that after a ROM update in the X65 computer the Dreamtracker would start.
In X65 a ROM update is done from a Linux PC via the USB connection, no additional HW necessary. You could either download the released (already compiled) ROM file from CX16 git repository, or you could build it yourself from the sources. In later case the output file rom.bin is found in directory x16-rom/build/x16. In any case this rom.bin file must be copied into x65’s repository directory sw-spiflash/sbl-for-cx16 (or you could modify variable CX16ROM in Makefile in that directory), and after that you must run make
to wrap it:
jara@megalit:~/hw/Open65/sw-spiflash/sbl-for-cx16$ make
ca65 -I../../include -I. --cpu 65c02 ../common/../common/sbl.s
ca65 -I../../include -I. --cpu 65c02 ../common/../common/isafix.s
ca65 -I../../include -I. --cpu 65c02 ../common/../common/vidtext.s
ca65 -I../../include -I. --cpu 65c02 ../common/../common/font8x8.s
ld65 -C ../common/sbl.ld ../common/sbl.o ../common/isafix.o ../common/vidtext.o ../common/font8x8.o -o sbl.bin
ca65 -I../../include -I. --cpu 65c02 ../common/sbl.s -l sbl.lst
ca65 -I../../include -I. --cpu 65c02 ../common/isafix.s -l isafix.lst
ca65 -I../../include -I. --cpu 65c02 ../common/trampoline.s -l trampoline.lst
cat sbl.bin rom.bin >img.bin
This sequence has built a Secondary Bootloader (SBL) for X65 and appended CX16 ROM as SBL’s payload. The SBL provides a splash screen while the CX16 “ROM” is loading, and a startup wrapper code to kick off the CX16 “ROM” in correct parts once it has been loaded in the X65 RAM. The next step is to write the complete file img.bin
into the flash memory of X65. This is done by make prog_img
as follows:
jara@megalit:~/hw/Open65/sw-spiflash/sbl-for-cx16$ make prog_img
../../x65prog/x65prog -N -o 256k img.bin
init..
cdone: high
reset..
cdone: low
flash ID: 0xEF 0x40 0x15 0x00
file size: 253952
erase 64kB sector at 0x040000..
erase 64kB sector at 0x050000..
erase 64kB sector at 0x060000..
erase 64kB sector at 0x070000..
programming..
done.
reading..
VERIFY OK
cdone: high
Bye.
With the R48 ROM ready and flashed in the X65 computer, I did not expect further problems. What a surprise then, when it did not boot at once!
After some head-scratching and google-googling, I had a hunch that this problem might be related to CX16’s latest addition of the support for the 65816 CPU. The discussion in this thread tells us how the ROM newly distinguishes between the 6502 and 65816 processors. It is using the following instructions in hex: $18, $E2, $01. The code is interpretted by 65c02 as:
CLC ; clear carry flag
NOP #$01 ; a 2-byte no-op
While 65c816 interprets the same code as:
CLC ; clear carry flag
SEP #$01 ; sets bit 0 of the processor status register, which is the carry flag
he resulting carry flag is zero (cleared) on 65c02, and one (set) on 65c816. Any code that follows can use this information to possibly switch the processor in 16-bit mode, if 65816 has been detected, or use an alternate 8-bit code on 6502.
In case of X65 I got some in-between behaviour. The ROM apperantly detected that it is running on 65816, and then did something unexpected – which I have not so far had the time to investigate. Sorry! There is an information in the CX16 thread that no addressing into different bank than the BANK $00 takes place, but one could not be sure. The original CX16 does not decode the BANK bits of 65816, so a program bug in this case would go invisible.
To get the latest ROM running quicky while not spending my time an another annoying reverse-engineering task at that point, I got creative and hot-fixed the issue in the NORA FPGA. The FPGA has already support for observing the processor instruction stream as it is going, and throwing an ABORT exception whenever a “banned” instruction is about to execute. “Banned” are attempts to run 65816-only instructions while the processor is in the Emulation mode. So far I have used this feature to filter out the RMBx, SMBx, BBRx and BBSx opcodes, which have a completely different meaning in 6502 versus in 65816. For these instruction NORA FPGA raises the ABORT exception in the 65816 processor, and a handler emulates the “banned” instruction step-by-step in software code. Newly I have added the opcodes $E2 (SEP xy) and $C2 (REP xy) to the list of banned opcodes in the Emulation mode. (Note that when the 65816 is in the Native mode (8-bit or 16-bit), no opcodes are banned by NORA – we assume clean code then). Exception handler for banned instructions has been updated to just skip the 2 bytes ($E2 $xy, and $C2 $xy), thus exactly emulating the behaviour of 6502 on 65816 processor in Emulation mode as NOPs. This way we fool the CX16 ROM in thinking it is runing on the “good old” 6502, and it attempts no switching into the Native mode. And yes, after this FPGA hot-fix the ROM started with no problems. We will investigate why it had failed sometime later.
Finally I could run Dreamtracker 0.71 and amuse myself with some of its tones:
So yes, Dreamtracker V0.71 with ROM R48 runs well on X65.