Author Topic: Access to upper RAM during unpacking  (Read 271 times)

0 Members and 1 Guest are viewing this topic.

Offline leuat

  • CPC464
  • **
  • Posts: 4
  • Country: no
    • TRSE
  • Liked: 1
  • Likes Given: 0
Access to upper RAM during unpacking
« on: 20:15, 30 September 20 »
Hi there!

I'm the developer of Turbo Rascal SE (see www.turborascal.com), an IDE + compiler + general toolshop for creating games/demos for various 8/16 bit computers. TRSE now also supports the Amstrad CPC 464, with a handful of tutorials (must use Caprice32 emulator, for now)

I'm currently adding more functionality to the CPC / Z80 stuff, and have recently implemented a resource compression/decompression system, working just fine.
Today, I implemented a system for automatic packing and extracting of executable files, but I'm having a huge problem - how the hell do I work with RAM at the Bxxx-range?

here is what I do :

- compile programs as usual in TRSE, but with executable packing toggled. This will generate code that starts at $200.- The compiled program is automatically packed, and then a *new* program is compiled - starting at $4000, containing the unpacking code + the packed executable.
- When the hacked code is executed on the CPC at $4000, it will first jump to the the unpacker code, copy itself to $100, jump there and start unpacking code/data to $200.

Everything works well for smaller codes - but whenever the unpacker starts reading data into the $B000-area, it crashes. I've tried experimenting with turning off ROM reading ie  "call $B909, call $B903" but to no avail - everything seems to crash whenever $B??? is hit.

I am having a hard time finding useful information online about how to handle this - is there any way to turn *off* ROM/commands for $B000, so the that the packed code can be read from this location? Or am I missing something here?

Complete CPC n00b here, so any help would be appreciated!





Offline SRS

  • Supporter
  • 6128 Plus
  • *
  • Posts: 596
  • Country: de
  • Schneider CPC464 - what else ?
  • Liked: 598
  • Likes Given: 325
Re: Access to upper RAM during unpacking
« Reply #1 on: 20:39, 30 September 20 »
I guess it's because thats the place of firmware jump blocks. You maybe have to disable firmware while doing that ?
http://www.cpcalive.com/docs/amstrad_cpc_6128_memory_map.html


Offline leuat

  • CPC464
  • **
  • Posts: 4
  • Country: no
    • TRSE
  • Liked: 1
  • Likes Given: 0
Re: Access to upper RAM during unpacking
« Reply #2 on: 20:43, 30 September 20 »
Thanks for the reply, SRS! Problem is that I can't seem to find anything that resembles "disable firmware" etc at $B900 , only how to enable RAM for $C000-$FFFF. I'll keep looking though

Offline SRS

  • Supporter
  • 6128 Plus
  • *
  • Posts: 596
  • Country: de
  • Schneider CPC464 - what else ?
  • Liked: 598
  • Likes Given: 325
Re: Access to upper RAM during unpacking
« Reply #3 on: 22:44, 30 September 20 »
CPCTELERA sources may help. https://github.com/lronaldo/cpctelera/tree/master/cpctelera/src/firmware



Code: [Select]
.include /firmware.s/

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;
;; Function: cpct_disableFirmware
;;
;;    Disables Amstrad CPC firmware, preventing it from being executed at every
;; CPU interrupt.
;;
;; C Definition:
;;    u16 <cpct_disableFirmware> ()
;;
;; Assembly call:
;;    > call cpct_disableFirmware_asm
;;
;; Return value:
;;    <u16> - Pointer to present interrupt handler (normally, pointer to firmware ROM code).
;; This value should be stored to restore it later, if required.
;;
;; Details:
;;    This function is exactly the same as <cpct_removeInterruptHandler>, as firmware
;; is executed as an interrupt handler, and disabling them is nothing more than removing
;; it. For more details on how it works, see <cpct_removeInterruptHandler>
;;
;;    Disabling the firmware is useful for several reasons:
;;    - Firmware code gets executed 6 times per frame (1 at each interrupt) when
;; is active. If you turn it off, you win CPU clock cycles for your program,
;; because firmware will not execute anymore.
;;    - Most of CPCtelera's functions talk directly to hardware, no to firmware.
;; They are faster, but they do not change firmware variables. As a result,
;; firmware can revert changes made by CPCtelera's functions when active. For
;; instance, if you change to video mode 0 using CPCtelera's functions, firmware
;; will see that the video mode is different from what it should be (attending
;; to its own variables) and will change it again to 1. This happens with video
;; modes and palette values mainly.
;;    - Also, firmware uses part of the RAM to store its variables (from
;; 0xA6FC to 0xBFFF). If you accidentaly overwrite anything there with firmware
;; being active, unpredictable things will happen, even hanging the computer.
;; Moreover, disabling firmware lets you use this part of the RAM for your
;; own uses.
;;
;; Destroyed Register values:
;;    HL
;;
;; Required memory:
;;    16 bytes
;;
;; Time Measures:
;; (start code)
;; Case | microSecs (us) | CPU Cycles
;; --------------------------------------
;; Any  |      22        |     88
;; --------------------------------------
;; (end code)
;;
;; Credits:                                                       
;;    This function was initially based on cpc_disableFirmware function
;; from CPCRSLib by Raul Simarro.
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;
;; Function: cpct_removeInterruptHandler
;;
;;    Sets nothing as interrupt handler (returns every time it is called). It
;; returns previous interrupt handler for restoration purposes.
;;
;; C Definition:
;;    u16 <cpct_removeInterruptHandler> ()
;;
;; Assembly call:
;;    > call cpct_removeInterruptHandler_asm
;;
;; Return value:
;;   (u16, HL) - Previous interrupt code pointer located at 0x0039.
;;
;; Details:
;;    This function sets Interrupt Mode to 1 (call 0x0038 every time a maskable
;; interrupt happens) and then writes assembly instructions EI : RET at 0x0038.
;; (0xC9FB --> 0xFB = EI, 0xC9 = RET). This makes the CPU directly return every
;; time an interrupt creates a jump to 0x0038 (6 times per frame, 300 times per
;; second).
;;
;;    This function retrieves previous interrupt handler before setting it. This
;; previous interrupt handler is returned. You may store it as a 16-bits value
;; and use it again to restore it later on if you wanted.
;;
;;    Modifying the interrupt vector, this function also disables firmware, as
;; firmware will not be called again. Firmware routines are executed as a interrupt
;; handler and the ROM entry point is stored at 0x0039 (a 16-bit address where the
;; firmware code starts).
;;
;;    Before inserting 0xC9FB at 0x0038, the 2 bytes lying at 0x0039 are saved
;; into DE. These 2 bytes are returned to the caller, to let them be stored and
;; restored later on, if normal firmware operation (or previous interrupt handler)
;; is required again. <cpct_reenableFirmware> may be used for this restoring
;; operation.
;;
;; Destroyed Register values:
;;    HL
;;
;; Required memory:
;;    16 bytes
;;
;; Time Measures:
;; (start code)
;; Case | microSecs (us) | CPU Cycles
;; -------------------------------------
;; Any  |     22         |     88
;; -------------------------------------
;; (end code)
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

_cpct_disableFirmware::
cpct_disableFirmware_asm::
_cpct_removeInterruptHandler::
cpct_removeInterruptHandler_asm::
   di                             ;; [1] Disable interrupts
   ld   hl, (firmware_RST_jp+1)   ;; [5] Obtain pointer to the present interrupt handler
   ex   de, hl                    ;; [1] DE = HL (DE saves present pointer to previous interrupt handler)

   im    1                        ;; [2] Set Interrupt Mode 1 (CPU will jump to 0x38 when a interrupt occurs)
   ld   hl, #0xC9FB               ;; [3] FB C9 (take into account little endian) => EI : RET

   ld (firmware_RST_jp), hl       ;; [5] Setup new "null interrupt handler" and enable interrupts again
   ei                             ;; [1]
   ex   de, hl                    ;; [1] HL = Pointer to previous interrupt handler (return value)

   ret                            ;; [3] Return
Code: [Select]
;;-----------------------------LICENSE NOTICE------------------------------------
;;  This file is part of CPCtelera: An Amstrad CPC Game Engine
;;  Copyright (C) 2014 ronaldo / Fremos / Cheesetea / ByteRealms (@FranGallegoBR)
;;
;;  This program is free software: you can redistribute it and/or modify
;;  it under the terms of the GNU Lesser General Public License as published by
;;  the Free Software Foundation, either version 3 of the License, or
;;  (at your option) any later version.
;;
;;  This program is distributed in the hope that it will be useful,
;;  but WITHOUT ANY WARRANTY; without even the implied warranty of
;;  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
;;  GNU Lesser General Public License for more details.
;;
;;  You should have received a copy of the GNU Lesser General Public License
;;  along with this program.  If not, see <http://www.gnu.org/licenses/>.
;;-------------------------------------------------------------------------------
;#####################################################################
;### MODULE: Firmware and ROM routines                             ###
;#####################################################################
;### Routines to disable CPC Firmware and reenable it when needed, ###
;### and managing Upper and Lower ROMs.                            ###
;#####################################################################
;
.module cpct_firmware

.include /firmware.s/

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;
;; Function: cpct_reenableFirmware
;;
;;    Re-enables previously disabled Amstrad CPC firmware.
;;
;; C Definition:
;;    void <cpct_reenableFirmware> (<u16> firmware_ROM_pointer) __z88dk_fastcall;
;;
;; Assembly call:
;;    > call cpct_reenableFirmware_asm
;;
;; Input Parameters (2 Bytes):
;;   (2B HL) *firmware_ROM_pointer* - 2 bytes with previous pointer stored at 0x0039.
;; This is the address where firmware ROM code starts.
;;
;; Parameter Restrictions:
;;    * *firmware_ROM_pointer* is a 16bits value that should have been previously obtained
;; calling <cpct_disableFirmware> or <cpct_removeInterruptHandler>. This 16bits value should
;; be the pointer to the firmware ROM code that must be called every time an interrupt happens.
;; This pointer is placed at 0x0039, along with a JP instruction (0xC3) at 0x0038. Being the
;; CPU in interrupt mode 1, a jump to 0x0038 address is produced 6 times per frame, 300
;; times per second.
;;
;; Details:
;;    Restores normal operation of Amstrad CPC firmware after having been disabled.
;; Do not try to call this function before disabling firmware. If you do, the most
;; normal result is getting your Amstrad CPC resetted.
;;
;;    This function could also be used to change the present interrupt handler. However,
;; take into account that it does not create a safe wrapper for the given interrupt
;; handler. Use it with care in this case.
;;
;; Destroyed Register values:
;;    HL
;;
;; Required memory:
;;    11 bytes
;;
;; Time Measures:
;; (start code)
;; Case | microSecs(us) | CPU Cycles
;; -----------------------------------
;; Any  |      16       |     64
;; -----------------------------------
;; (end code)
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

.equ JP_opcode, 0xC3

_cpct_reenableFirmware::
cpct_reenableFirmware_asm::
   di                         ;; [1] Disable interrupts
   ld a, #JP_opcode           ;; [2] A = 0xC3, opcode for JP instruction
   ld (firmware_RST_jp), a    ;; [4] Put JP instruction at 0x0038, to create a jump to the pointer at 0x0039
   ld (firmware_RST_jp+1), hl ;; [5] HL = previous interrupt handler pointer (firmware ROM pointer)
   ei                         ;; [1] Reenable interrupts and return
   ret                        ;; [3] Return
Code: [Select]
;;-----------------------------LICENSE NOTICE------------------------------------
;;  This file is part of CPCtelera: An Amstrad CPC Game Engine
;;  Copyright (C) 2014 ronaldo / Fremos / Cheesetea / ByteRealms (@FranGallegoBR)
;;
;;  This program is free software: you can redistribute it and/or modify
;;  it under the terms of the GNU Lesser General Public License as published by
;;  the Free Software Foundation, either version 3 of the License, or
;;  (at your option) any later version.
;;
;;  This program is distributed in the hope that it will be useful,
;;  but WITHOUT ANY WARRANTY; without even the implied warranty of
;;  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
;;  GNU Lesser General Public License for more details.
;;
;;  You should have received a copy of the GNU Lesser General Public License
;;  along with this program.  If not, see <http://www.gnu.org/licenses/>.
;;-------------------------------------------------------------------------------
;#####################################################################
;### MODULE: Firmware and ROM routines                             ###
;#####################################################################
;### Routines to disable CPC Firmware and reenable it when needed, ###
;### and managing Upper and Lower ROMs.                            ###
;#####################################################################
;
.module cpct_firmware

;;
;; Title: Firmware&ROM constants
;;

;;
;; Constants: Firmware useful constants
;;
;;    Constants used by firmware routines.
;;
;;    firmware_RST_jp - Memory address that stores a pointer to the start of
;; firmware code, executed on every interruption.
;;    GA_port_byte    - Output port where Gate Array (GA) listens.
;;
.equ firmware_RST_jp, 0x38  ;; Memory address were a jump (jp) to the firmware code is stored.
.equ GA_port_byte,    0x7F  ;; 8-bit Port of the Gate Array

Offline leuat

  • CPC464
  • **
  • Posts: 4
  • Country: no
    • TRSE
  • Liked: 1
  • Likes Given: 0
Re: Access to upper RAM during unpacking
« Reply #4 on: 23:05, 30 September 20 »
Thanks a bunch! That really helped, managed to both disable / enable firmware while copying.. but it still crashes, which I realized is probably due to the stack being located at  $c000 and down! Do you guys know if there is a way to move the stack pointer (say, to $FF00)?

Offline leuat

  • CPC464
  • **
  • Posts: 4
  • Country: no
    • TRSE
  • Liked: 1
  • Likes Given: 0
Re: Access to upper RAM during unpacking
« Reply #5 on: 23:12, 30 September 20 »
ah sorry, stupid question =) ld sp, $200