diff --git a/cfg/pce.cfg b/cfg/pce.cfg index 6332f8eff..77f8c5c97 100644 --- a/cfg/pce.cfg +++ b/cfg/pce.cfg @@ -1,34 +1,29 @@ -# linker config to produce simple NEC PC-Engine cartridge (.pce) - +# linker config. to produce a NEC PC-Engine 8K, 16K, or 32K image (.bin) SYMBOLS { + __CARTSIZE__: type = weak, value = $2000; # $2000, $4000, or $8000 __STACKSIZE__: type = weak, value = $0300; # 3 pages stack } - MEMORY { - # FIXME: is this correct? the first 3? bytes cant be used? - ZP: file = "", start = $0003, size = $00FD, type = rw, define = yes; - - # reset-bank and hardware vectors - ROM0: file = %O, start = $E000, size = $1FF6, fill = yes, define = yes; - ROMV: file = %O, start = $FFF6, size = $000A, fill = yes; - - # first RAM page (also contains stack and zeropage) - RAM: file = "", start = $2200, size = $1e00, define = yes; + ZP: file = "", start = $0000, size = $0100, define = yes; + # RAM bank + MAIN: file = "", start = $2200, size = $1E00 - __STACKSIZE__, define = yes; + # ROM banks, before swapping, and after mapping + ROM: file = %O, start = $10000 - __CARTSIZE__, size = __CARTSIZE__, fill = yes, fillval = $FF; } - SEGMENTS { - ZEROPAGE: load = ZP, type = zp, define = yes; - EXTZP: load = ZP, type = zp, define = yes, optional = yes; - APPZP: load = ZP, type = zp, define = yes, optional = yes; - STARTUP: load = ROM0, type = ro, define = yes; - ONCE: load = ROM0, type = ro, optional = yes; - CODE: load = ROM0, type = ro, define = yes; - RODATA: load = ROM0, type = ro, define = yes; - DATA: load = ROM0, run = RAM, type = rw, define = yes; - BSS: load = RAM, type = bss, define = yes; - VECTORS: load = ROMV, type = rw, define = yes; + ZEROPAGE: load = ZP, type = zp; + EXTZP: load = ZP, type = zp, optional = yes; + APPZP: load = ZP, type = zp, optional = yes; + DATA: load = ROM, run = MAIN, type = rw, define = yes; + INIT: load = MAIN, type = bss, optional = yes; + BSS: load = MAIN, type = bss, define = yes; + RODATA: load = ROM, type = ro; + CODE: load = ROM, type = ro; + LOWCODE: load = ROM, type = ro, optional = yes; + ONCE: load = ROM, type = ro, optional = yes; + STARTUP: load = ROM, type = ro, start = $FFF6 - $0066; + VECTORS: load = ROM, type = ro, start = $FFF6; } - FEATURES { CONDES: type = constructor, label = __CONSTRUCTOR_TABLE__, diff --git a/doc/pce.sgml b/doc/pce.sgml index 927df8f5c..bc7dcf5c8 100644 --- a/doc/pce.sgml +++ b/doc/pce.sgml @@ -3,9 +3,9 @@
PC-Engine (TurboGrafx) System specific information for cc65 -<author> -<url url="mailto:groepaz@gmx.net" name="Groepaz/Hitmen"> -<date>2016-09-29 +<author><url url="mailto:groepaz@gmx.net" name="Groepaz/Hitmen">,<newline> +<url url="mailto:greg.king5@verizon.net" name="Greg King"> +<date>2018-02-12 <abstract> An overview over the PCE runtime system as it is implemented for the @@ -30,11 +30,36 @@ more than one platform. Please see the function reference for more information. + <sect>Binary format<p> -The standard binary output format generated by the linker for the PCE target -is a cartridge image with no header. It is of course possible to change this -behaviour by using a modified startup file and linker config. +The binary output file generated by the linker, for the PCE target, is an +image, with no header, that has 8K bytes in the wrong place. That file must be +post-processed; the 8K at the end must be moved to the front of the image. + +On POSIX systems, the <tt/dd/ command and the shell give a convenient way to do +it. Here is an example of their use: +<tscreen><verb> +dd if=conio.bin bs=8K skip=3 > conio.pce +dd if=conio.bin bs=8K count=3 >> conio.pce +</verb></tscreen> +The first command grabs the last 8K of a 32K file, and writes it as the first +part of a new file. The second command reads all but the last part of the old +file, and appends it to the new file. +<tscreen><verb> ++--------+--------+--------+--------+ +| Bank 1 | Bank 2 | Bank 3 | Bank 0 | <-- "conio.bin" ++--------+--------+--------+--------+ + ++--------+--------+--------+--------+ +| Bank 0 | Bank 1 | Bank 2 | Bank 3 | <-- "conio.pce" ++--------+--------+--------+--------+ +</verb></tscreen> +<em/Note/: That <tt/.pce/ file shows the format of the ROM cartridge that is +plugged into a PC-Engine. But, that <tt/.bin/ file shows what programs +actually see when they execute the code in that cartridge. + + <sect>Memory layout<p> @@ -52,19 +77,23 @@ Special locations: <tag/Stack/ The C runtime stack is located in system RAM at $3FFF and growing downwards. - <tag/BSS and Data/ - - The BSS (uninitialized variables) and Data (initialized variables) sections are - placed one after the other into system RAM at $2000. + <tag/Data and BSS/ + The Data (initialized variables) and BSS (uninitialized variables) sections are + placed one after the other into system RAM at $2200. <tag/Heap/ - The C heap is located after the end of the Data section and grows towards the C + The C heap is located after the end of the BSS section; and, grows towards the C runtime stack. <tag/Code/ - The startup code is located at $E000 in the System/Hardware bank. Further - code can be placed in other ROM banks, this must be done manually however. + In an 8K ROM cartridge, code and read-only data are located between + $E000 and $FFF5 in the System bank. + In a 16K cartridge, code and read-only data are located between $C000 + and $FFF5. + + In a 32K cartridge, code and read-only data are located between $8000 + and $FFF5. </descrip><p> @@ -171,7 +200,8 @@ following functions (and a few others): <sect>Other hints<p> <itemize> -<item>a good emulator to use for PC-Engine is "mednafen" (<url url="http://mednafen.fobby.net/">) +<item><url url="https://mednafen.github.io/" name= "Mednafen"> is a good +emulator to use for the PC-Engine. </itemize> some useful resources on PCE coding: @@ -210,6 +240,3 @@ freely, subject to the following restrictions: </enum> </article> - - - diff --git a/libsrc/pce/crt0.s b/libsrc/pce/crt0.s index 80b32c089..75ffb7f05 100644 --- a/libsrc/pce/crt0.s +++ b/libsrc/pce/crt0.s @@ -4,33 +4,26 @@ ; by Groepaz/Hitmen <groepaz@gmx.net> ; based on code by Ullrich von Bassewitz <uz@cc65.org> ; -; This must be the *first* file on the linker command line +; 2018-02-11, Greg King ; .export _exit .export __STARTUP__ : absolute = 1 ; Mark as startup .import initlib, donelib - .import push0, _main, zerobss - .import initheap + .import push0, _main .import IRQStub - ; Linker generated - .import __RAM_START__, __RAM_SIZE__ - .import __ROM0_START__, __ROM0_SIZE__ - .import __ROM_START__, __ROM_SIZE__ - .import __STARTUP_LOAD__,__STARTUP_RUN__, __STARTUP_SIZE__ - .import __CODE_LOAD__,__CODE_RUN__, __CODE_SIZE__ - .import __RODATA_LOAD__,__RODATA_RUN__, __RODATA_SIZE__ - .import __DATA_LOAD__,__DATA_RUN__, __DATA_SIZE__ - .import __BSS_SIZE__ + ; Linker-generated + .import __CARTSIZE__ + .import __DATA_LOAD__, __DATA_RUN__, __DATA_SIZE__ + .import __BSS_RUN__, __BSS_SIZE__ + .import __MAIN_START__, __MAIN_SIZE__, __STACKSIZE__ .include "pce.inc" .include "extzp.inc" .importzp sp - .importzp ptr1,ptr2 - .importzp tmp1,tmp2,tmp3 ; ------------------------------------------------------------------------ ; Place the startup code in a special segment. @@ -53,29 +46,27 @@ start: ldx #$FF ; Stack top ($21FF) txs - ; At startup all MPRs are set to 0, so init them - lda #$ff - tam #%00000001 ; 0000-1FFF = Hardware page + ; At power-on, most MPRs have random values; so, initiate them. + lda #$FF + tam #%00000001 ; $0000-$1FFF = Hardware bank lda #$F8 - tam #%00000010 ; 2000-3FFF = Work RAM - - ; FIXME: setup a larger block of memory to use with C-code + tam #%00000010 ; $2000-$3FFF = Work RAM ;lda #$F7 - ;tam #%00000100 ; 4000-5FFF = Save RAM - ;lda #1 - ;tam #%00001000 ; 6000-7FFF Page 2 - ;lda #2 - ;tam #%00010000 ; 8000-9FFF Page 3 - ;lda #3 - ;tam #%00100000 ; A000-BFFF Page 4 + ;tam #%00000100 ; $4000-$47FF = 2K Battery-backed RAM ;lda #4 - ;tam #%01000000 ; C000-DFFF Page 5 - ;lda #0 - ;tam #%10000000 ; e000-fFFF hucard/syscard bank 0 + ;tam #%00001000 ; $6000-$7FFF - ; Clear work RAM (2000-3FFF) - stz <$00 - tii $2000, $2001, $1FFF + lda #$01 + ldx #>$8000 + cpx #>__CARTSIZE__ + bcc @L1 ;(blt) + tam #%00010000 ; $8000-$9FFF = ROM bank 1 (32K block of ROM) + inc a + tam #%00100000 ; $A000-$BFFF = ROM bank 2 + inc a +@L1: tam #%01000000 ; $C000-$DFFF = ROM bank 3 (32K) or 1 (16K) + ;lda #$00 ; (The reset default) + ;tam #%10000000 ; $E000-$FFFF hucard/syscard bank 0 ; Initialize hardware stz TIMER_CTRL ; Timer off @@ -91,15 +82,16 @@ start: lda #$05 sta IRQ_MASK ; IRQ1=on - ; Clear the BSS data - jsr zerobss - ; Copy the .data segment to RAM tii __DATA_LOAD__, __DATA_RUN__, __DATA_SIZE__ + ; Clear the .bss segment + stz __BSS_RUN__ + tii __BSS_RUN__, __BSS_RUN__ + 1, __BSS_SIZE__ - 1 + ; Set up the stack - lda #<(__RAM_START__+__RAM_SIZE__) - ldx #>(__RAM_START__+__RAM_SIZE__) + lda #<(__MAIN_START__ + __MAIN_SIZE__ + __STACKSIZE__) + ldx #>(__MAIN_START__ + __MAIN_SIZE__ + __STACKSIZE__) sta sp stx sp + 1 diff --git a/testcode/lib/pce/Makefile b/testcode/lib/pce/Makefile index 9a4dd7506..a4a495c9a 100644 --- a/testcode/lib/pce/Makefile +++ b/testcode/lib/pce/Makefile @@ -1,12 +1,29 @@ .PHONY: all clean test +# Size of cartridge to generate. +# Possible values: +# 8K = 0x2000 +# 16K = 0x4000 +# 32K = 0x8000 +CARTSIZE := 0x2000 + +ifeq (${CARTSIZE},0x8000) +COUNT := 3 +else +COUNT := 1 +endif + all: conio.pce -conio.pce: conio.c - ../../../bin/cl65 -t pce conio.c --mapfile conio.map -o conio.pce +%.pce: %.bin + dd if=$< bs=8K skip=${COUNT} > $@ + dd if=$< bs=8K count=${COUNT} >> $@ + +%.bin: %.c ../../../lib/pce.lib + ../../../bin/cl65 -t pce $< -Wl -D__CARTSIZE__=${CARTSIZE} -m $*.map -o $@ clean: - $(RM) conio.o conio.pce conio.map + $(RM) conio.o conio.??? test: conio.pce - mednafen -force_module pce conio.pce + mednafen -force_module pce $< diff --git a/testcode/lib/pce/conio.c b/testcode/lib/pce/conio.c index ed3f86240..858f01918 100644 --- a/testcode/lib/pce/conio.c +++ b/testcode/lib/pce/conio.c @@ -45,7 +45,7 @@ void main(void) p[8],p[9],p[10],p[11],p[12],p[13],p[14],p[15] ); } - memcpy(p, main, 0); /* test that a zero length doesn't copy 64K */ + memcpy(p, main, i = 0); /* test that a zero length doesn't copy 64K */ gotoxy(0,ysize - 1); for (i = 0; i < xsize; ++i) {