zx128: update the various ZX128 bits needed
authorAlan Cox <alan@linux.intel.com>
Tue, 10 Feb 2015 23:38:35 +0000 (23:38 +0000)
committerAlan Cox <alan@linux.intel.com>
Tue, 10 Feb 2015 23:38:35 +0000 (23:38 +0000)
Kernel/platform-zx128/README
Kernel/platform-zx128/crt0.s
Kernel/platform-zx128/fuzix.lnk
Kernel/platform-zx128/zx128.s

index b40fc83..e716efe 100644 (file)
@@ -1,22 +1,29 @@
 An FUZIX target for ZX Spectrum 128.
 
-0000-3FFF      Fixed BASIC ROM
+0000-3FFF      Fixed BASIC ROM (including ROM font)
+               (Strictly speaking this is a choice of ROMs and magic
+                overlaying hardware ROMs like the interface 1). We need the
+               48K one so we can use the font and the 0x3900 hack
 4000-7FFF      Kernel data, common read/write space, constants, common read
                only, plenty of space
 8000-BFFF      _DISCARD area - blown away when we exec init
+               followed by the initializing copies of common etc that are
+               copied down post boot
 C000-FFFF
        0:      Kernel CODE (full)
        1:      Kernel CODE2 (full)
-       2:      Mapped at 0x8000-0xBFFF
+       2:      Mapped at 0x8000-0xBFFF (exchanged with user process buffer)
        3:      User process
        4:      User process
-       5:      Mapped at 0x4000-0x7FFF
+       5:      Mapped at 0x4000-0x7FFF (Kernel data/common)
        6:      User process
-       7:      CODE3, Display + Video, Font (fairly full)
+       7:      CODE3, Display + Video, Font (fairly full - font not needed
+               however)
 
 Which gives us the ability to run 16K and 32K processes although we'd need
-to do bank exchanges to keep 2 x32K in memory at once (one in 2/3 one in
-4/7 and doing a block exchange of the memory).
+to do bank exchanges to keep 2 x 32K in memory at once (one in 2/3 one in
+4/7 and doing a block exchange of the memory). From the TRS80 this seems
+to be worth the extra effort.
 
 Making the base kernel use the low ROM space is surprisingly pointless. We
 could just about squash it in with screen at 0x4000 and claim back page 7.
@@ -42,6 +49,47 @@ on the 128.
 
 TODO:
 
-Use IM2 so we can capture timer interrupts correctly. This is a hack but
-it's necessary and is also how all the spectrum games do it.
+Set vectors for syscalls somewhere safe and common (can't use the normal RST
+ones). Need a reloc hack to pick syscall method ??
 
+Support the +2A and +3 platform. These have the same banking options but
+also "special mode". In special mode we get a choice of four other pure RAM
+bank setups
+
+       00  40  80  C0
+conf0  [0] [1] [2] [3]
+conf1  [4] [5] [6] [7]
+conf2  [4] [5] [6] [3]
+conf3  [4] [7] [6] [3]
+
+
+That gives us a conventional low 0/1 and 4/5 for user space with the kernel
+using 2/3/6/7.
+
+Kernel maps are then
+
+3 = common (always mapped high)
+2/6 = banked (at 0x8000)
+7 = banked with screen (at 0x4000)
+
+although 7 does not appear to be part of the banks we cannot map 2 and 7
+together so it's effectively banked, but we can hack the linker to do smart
+optimisations for calls between banks 6 and 7.
+
+Alternatively we could go with a single 64K swapping user space with
+kernel mapped normally at 4-7  (with screen hole at C000) and user at 0-3
+and a small copied common in bank 3 and 7
+
+No IM2 hack needed.
+
+
+The Timx is different again. Memory is 3 banks of 64K. The main bank is laid
+out like the Spectrum 48K but with the screen at 0x4000 (or for 80 col mode
+most of 0x4000-0x8000). Each 8K can come from either main memory or an
+external bank (EX-ROM or DOCK). Dock and EX_ROM pages cannot be mapped at
+the same time. Not clear how well it can be supported
+
+Kernel in base 0x4000->0xFFFF (minus one screen), user in dock perhaps ?
+Would be tight for kernel but give 2 x 32K apps if supported relocations.
+
+Might need OS partly in cartridge ROM to make it work (certainly for 80col)
index b3609da..588987a 100644 (file)
@@ -1,34 +1,39 @@
         .module crt0
 
-       ; Loaded at 0x4000 and the lowest available RAM (the display we keep
-       ; in bank 7 and mapped high).
+       ;
+       ;       Our common and data live in 0x4000-0x7FFF
+       ;
+        .area _COMMONMEM
+       .area _STUBS
        .area _COMMONDATA
+        .area _CONST
         .area _INITIALIZED
+       ;
+       ;       We move INITIALIZER into INITIALIZED at preparation time
+       ;       then pack COMMONMEM.. end of INITIALIZED after DISCARD
+       ;       in the load image. Beyond that point we just zero.
+       ;
         .area _DATA
         .area _BSEG
         .area _BSS
-       ; These are loaded as low as we can in memory. If we are using an
-       ; interface 1 cartridge then _CONST to the end of _STUBS can live in
-       ; ROM. Right now we still need to fiddle with RO as we don't use the
-       ; IM2 hack and we'll need to modify SDCC and the bank linker not to
-       ; use RST to avoid this.
-        .area _CONST
-        .area _COMMONMEM
-       .area _STUBS
         .area _HEAP
-        ; note that areas below here may be overwritten by the heap at runtime, so
-        ; put initialisation stuff in here
         .area _INITIALIZER
         .area _GSINIT
         .area _GSFINAL
+       ;
+       ;       All our code is banked at 0xC000
+       ;
         .area _CODE
        .area _CODE2
        ;
        ; Code3 sits above the display area along with the font and video
-       ; code so that they can access the display easily.
+       ; code so that they can access the display easily. It lives at
+       ; 0xDB00 therefore
        ;
        .area _CODE3
         .area _VIDEO
+
+       ; FIXME: We should switch to the ROM font and an ascii remap ?
         .area _FONT
        ; Discard is dumped in at 0x8000 and will be blown away later.
         .area _DISCARD
         .globl _fuzix_main
         .globl init_early
         .globl init_hardware
-        .globl s__INITIALIZER
-        .globl l__INITIALIZER
-        .globl s__INITIALIZED
-        .globl s__COMMONMEM
         .globl l__COMMONMEM
-        .globl s__DATA
-        .globl l__DATA
+        .globl l__STUBS
+        .globl l__COMMONDATA
+        .globl l__INITIALIZED
+       .globl l__CONST
+       .globl s__DISCARD
+       .globl l__DISCARD
         .globl kstack_top
 
         .globl unix_syscall_entry
         ; startup code
         .area _CODE
 init:
-        jp 0x003            ; workaround for lowlevel-z80.s check for C3 at 0000
+       jp init1        ;       0xC000 - entry point
+       jp init2        ;       0xC003 - entry point for .sna debug hacks
+init1:
         di
 
-        ; if any button is pressed during reset - boot BASIC48
-        in a, (#0xFE)       ; only low 5 bits of 0xFE port contains key info. Bit is 0 when corresponding key of any half row is pressed.
-        or #0xE0            ; so setting high 3 bits to 1
-        add #1              ; and check if we got 0xFF
-
-        jp z, init_continue
-
-        ; otherwise perform ROM bank switch and goto 0x0000
-        ld de, #0x4000
-        ld hl, #jump_to_basic_start
-        ld bc, #jump_to_basic_start - #jump_to_basic_end
-        ldir
-        jp 0x4000
-
-jump_to_basic_start:
-        ld bc, #0x7FFD
-        ld a, #0x10
-        out (c), a
-        jp 0
-jump_to_basic_end:
-
-        ; spacer
-        .ds 0x0B
-
-        ; .org 0x0030       ; syscall entry
-        jp unix_syscall_entry
+       ;  We need to wipe the BSS etc, then copy the initialized data
+       ;  and common etc from where they've been stuffed above the
+       ;  discard segment loaded into 0x8000
 
-        .ds 0x05            ; spacer
-
-        ; .org 0x0038       ; interrupt handler
-        jp interrupt_handler
-        .ds 0x2B
-
-        ; .org 0x0066       ; nmi handler
-        jp nmi_handler
-
-init_continue:
-        ; hack for emulator. Read remaining fuzix part to RAM from fuzix.bin
-;        ld bc, #0x1ee7
-;        in a, (c)
        ld hl, #0x4000
        ld de, #0x4001
+       ld bc, #0x3FFF
        ld (hl), #0
-       ld bc, #0x1800
        ldir
-       ld (hl), #0x7
-       ld bc, #0x02ff
+       ld hl, #s__DISCARD
+       ld de, #l__DISCARD
+       add hl, de              ; linker dumbness workarounds
+       ld de, #0x4000
+       ld bc, #l__COMMONMEM
+       ldir
+       ld bc, #l__STUBS
+       ldir
+       ld bc, #l__COMMONDATA
+       ldir
+       ld bc, #l__CONST
+       ldir
+       ld bc, #l__INITIALIZED
        ldir
 
-;
-;      These hooks will be platform/dev specific
-;
-       .if MICRODRIVE_BOOT
-       .globl mdv_boot
-
-boot_stack .equ 0xc000
-       ld sp, #boot_stack
-       push af
-       call mdv_boot
-       pop af
-       .endif
-
-
+init2:
         ld sp, #kstack_top
 
         ; Configure memory map
@@ -128,27 +97,17 @@ boot_stack .equ 0xc000
         call init_early
        pop af
 
-        ; our COMMONMEM is located in main code-data blob, so we
-        ; do not need to move it manually
-
-       ; initialized data
-       ld hl, #s__INITIALIZER
-       ld de, #s__INITIALIZED
-       ld bc, #l__INITIALIZER
-       ldir
-
-        ; then zero the data area
-        ld hl, #s__DATA
-        ld de, #s__DATA + 1
-        ld bc, #l__DATA - 1
-        ld (hl), #0
-        ldir
-
         ; Hardware setup
        push af
         call init_hardware
        pop af
 
+l1:    ld a, #7
+       out (0xfe), a
+       xor a
+       out (0xfe), a
+       jr l1
+
         ; Call the C main routine
        push af
         call _fuzix_main
index 78652dd..2ad58f4 100644 (file)
@@ -1,7 +1,7 @@
 -mwxuy
 -r
 -i fuzix.ihx
--b _COMMONDATA=0x4000
+-b _COMMONMEM=0x4000
 -b _CODE=0xC000
 -b _CODE2=0xC000
 -b _CODE3=0xDB00
index 9ff6d29..2ddfd95 100644 (file)
@@ -9,6 +9,7 @@
         .globl init_hardware
         .globl _program_vectors
         .globl platform_interrupt_all
+       .globl interrupt_handler
 
         .globl map_kernel
         .globl map_process
@@ -65,13 +66,18 @@ _trap_reboot:
 ; -----------------------------------------------------------------------------
         .area _CODE
 
+;
+;      The memory banker will deal with the map setting
+;
 init_early:
-        ld bc, #0x7ffd
-        xor a
-        ld (current_map), a
-        out (c), a            ; set page 0 at 0xC000
+;        ld bc, #0x7ffd
+;        xor a
+;        ld (current_map), a
+;        out (c), a            ; set page 0 at 0xC000
         ret
 
+       .area _VIDEO
+
 init_hardware:
         ; set system RAM size
         ld hl, #128
@@ -79,10 +85,13 @@ init_hardware:
         ld hl, #(128 - 48)        ; 48K for kernel
         ld (_procmem), hl
 
+       ld a, #4
+       out (0xfe), a
+l2:    jr l2
         ; screen initialization
         ; clear
-        ld hl, #0x4000
-        ld de, #0x4001
+        ld hl, #0xC000
+        ld de, #0xC001
         ld bc, #0x1800            ; There should be 0x17FF, but we are going
         xor a                     ; to copy additional byte to avoid need of
         ld (hl), a                ; DE and HL increment before attribute
@@ -94,7 +103,29 @@ init_hardware:
         ld (hl), a
         ldir
 
-        im 1 ; set CPU interrupt mode
+       ; set up the interrupt vectors at 0xFFF4 in each bank we use for
+       ; kernel. This is a standard spectrum trick from the game world. The
+       ; interrupt vectors are in ROM and there is no mechanism to make
+       ; them call your own code. Instead we use IM2 and autovectors.
+       ; The spectrum bus value is not predictable so IM2 will jump through
+       ; a vector at I + (random 8bit value).
+       ; We point I at a chunk of empty ROM that holds 0xFF 0xFF .. for at
+       ; least 256 bytes. Our IRQ will jump to 0xFFFF which we set to be a
+       ; JR instruction. 0x0000 is a fixed ROM constant which forms a
+       ; backward jump to 0xFFF4, where we can finally grab the IRQ.
+       ;
+       ; We must keep the Spectrum 48K ROM image mapped at all times. The
+       ; 128K image hasn't got the 0xFF space we use!
+       ;
+       xor a
+       call setvectors
+       ld a, #1
+       call setvectors
+       ld a, #7
+       call setvectors
+       ld a, #0x39
+       ld i, a
+;        im 2 ; set CPU interrupt mode
         ret
 
 ;------------------------------------------------------------------------------
@@ -102,12 +133,30 @@ init_hardware:
 
         .area _COMMONMEM
 
-        ; our vectors are in ROM, so nothing to do here
 _program_vectors:
-        ret
+       pop bc
+       pop de
+       pop iy                  ;       task ptr
+       push iy
+       push de
+       push bc
+       ld a, P_TAB__P_PAGE_OFFSET+1(iy)        ; high page of the pair
+setvectors:
+       call switch_bank
+       ld a, #0x19
+       ld (0xffff), a          ;       JR (plus ROM at 0 gives JR $FFF4)
+       ld a, #0xC3             ;       JP
+       ld (0xFFF4), a
+       ld hl, #interrupt_handler
+       ld (0xFFF5), a          ;       to IRQ handler
+       ret
+
 
         ; bank switching procedure. On entrance:
         ;  A - bank number to set
+       ;
+       ; FIXME: we can probably stack BC now we are banking sanely
+       ;
 switch_bank:
         di                  ; TODO: we need to call di() instead
         ld (current_map), a
@@ -117,13 +166,14 @@ switch_bank:
         ld (place_for_c), a
         ld bc, #0x7ffd
         ld a, (current_map)
+       or #0x18           ; Spectrum 48K ROM, Screen in Bank 7
         out (c), a
         ld a, (place_for_b)
         ld b, a
         ld a, (place_for_c)
         ld c, a
         ld a, (place_for_a)
-        ei
+;FIXME      ei
         ret
 
 map_kernel:
@@ -183,10 +233,15 @@ place_for_c:
 ;
 ;      Banking helpers
 ;
-;      FIXME: use real bank asssignments (0 is not 0 etc)
+;      Logical         Physical
+;      0               COMMON (0x4000)
+;      1               0
+;      2               1
+;      3               7
+;
 ;
 __bank_0_1:
-       ld a, #1
+       xor a              ; switch to physical bank 0 (logical 1)
 bankina0:
        call switch_bank   ; Move to new bank
        pop hl             ; Return address (points to true function address)
@@ -196,19 +251,20 @@ bankina0:
        inc hl
        push hl            ; Restore corrected return pointer
        ex de, hl
-       call callhl        ; call the function
-       xor a              ; return to bank 0
-       jp switch_bank
-callhl:        jp (hl)
+       call callhl        ; can't optimise - we need the stack depth right
+       ret
+callhl:        jp (hl)            ; calls from bank 0 are different to the others
+                          ; we started in common so we don't need to map
+                          ; the old state back
 __bank_0_2:
-       ld a, #2
+       ld a, #1           ; logical 2 -> physical 1
        jr bankina0
 __bank_0_3:
-       ld a, #3
+       ld a, #7           ; logical 3 -> physical 7
        jr bankina0
 
 __bank_1_2:
-       ld a, #2
+       ld a, #1
 bankina1:
        call switch_bank   ; Move to new bank
        pop hl             ; Return address (points to true function address)
@@ -218,14 +274,22 @@ bankina1:
        inc hl
        push hl            ; Restore corrected return pointer
        ex de, hl
+       call outhl
        call callhl        ; call the function
-       ld a, #1           ; return to bank 0
-       jp switch_bank
+       xor a              ; return to bank 1 (physical 0)
+       call switch_bank
+l1:    ld c, #0xfe
+       ld a, #2
+       out (c), a
+       ld b, #0
+       out (c),b
+       jr l1
+
 __bank_1_3:
-       ld a, #3
+       ld a, #7
        jr bankina1
 __bank_2_1:
-       ld a, #1
+       xor a
 bankina2:
        call switch_bank   ; Move to new bank
        pop hl             ; Return address (points to true function address)
@@ -236,13 +300,13 @@ bankina2:
        push hl            ; Restore corrected return pointer
        ex de, hl
        call callhl        ; call the function
-       ld a, #2           ; return to bank 0
+       ld a, #1           ; return to bank 2
        jp switch_bank
 __bank_2_3:
-       ld a, #3
+       ld a, #7
        jr bankina2
 __bank_3_1:
-       ld a, #1
+       xor a
 bankina3:
        call switch_bank   ; Move to new bank
        pop hl             ; Return address (points to true function address)
@@ -253,9 +317,9 @@ bankina3:
        push hl            ; Restore corrected return pointer
        ex de, hl
        call callhl        ; call the function
-       ld a, #2           ; return to bank 0
+       ld a, #7           ; return to bank 0
        jp switch_bank
 
 __bank_3_2:
-       ld a, #2
+       ld a, #1
        jr bankina3