@database "JOTD HD Install Collection" @Index INDEXNODE @NODE Main "JOTD HD Startup code autodocs" *************************************************************************** @{b}JOTD Startup V3.1@{ub} © Copyright 1995-99 Jean-François Fabre/Ralf Huvendiek *************************************************************************** @{" Memory setup " Link memorg} @{" Starting your code " Link loader} @{" Why decrunch routines ?" Link whydecrunch} @{" Macros " Link macros} @{" Library Functions " Link functions} @{" The printlog tool " Link printlog} @{" Contact us " Link contact} @ENDNODE @NODE memorg "Memory setup" To understand some choices and notions, you have to know how the memory is organized by my loading routines: On a fastmem amiga: V39: High Fast: User object, General reloc routines, disks images or RAM files, OS chip mirror, extension mem (for the 1MB games) (if any) Fast: The JOTDStartup program routines not relocated. Low Chip: The game (can take 512K, 1024K or 2048K) Older than V39: Fast: User object, General reloc routines, disks images or RAM files, OS chip mirror, extension mem (for the 1MB games) (if any), the HD load program Low Chip: The game (can take 512K, 1024K or 2048K) On a chip only amiga (V39): High Chip: User object, General reloc routines, disks images or RAM files, OS chip mirror, extension mem (for the 1MB games) (if any) Chip: The game, The JOTDStartup program routines not relocated. Obviously, while the game is running, you cannot call non-relocated routines (the ones callable with JSRABS), or else it will crash. You won't need those routines anyway during the game (you can use JSRABS routines in a code called using InGameOSCall) If the game needs more than 512K to run, you'll have to find where the expansion memory detection is done to replace it by a pointer on the extension mem you allocated with AllocExtMem(), else the game can crash (older than V39) The NOFAST tooltype will try to allocate chipmem for AllocExtMem unless you've got no chipmem above $80000 (the assumed chip size before you make a SaveOSData()) In this case it will return 0 (it's useless to allocate mem that will be overwritten by the game) Note: If you succeed in tracking the game memory 'allocation', you don't need relocatable routines, and nothing will overwrite your code, but it depends on which level of quality you want when you program your installers... And this is also compulsory if you want to install a clean quit option! In the case you would like to leave some OS code done by the game, JST supports ExecBase emulation since V0.7. Some calls are supported, others are redefinable by the user, (see OpenFakeExec() function) @ENDNODE @NODE loader "Calling the user code" Your relocatable object file will be loaded by JST and it will be checked against relocatable symbols. For instance, you cannot do things like: move.l #20,var because this instruction needs relocation, and we can't afford it since JST is not yet able to do this. Instead you can use one of the reloc macros. This instruction will become: RELOC_MOVEL #20,var JST passes some arguments in registers: D0.L: 0 if no trainer detected via tooltypes/args, -1 if trainer requested D1.L: 0 if OS swap is allowed, -1 if not (see InGameOsCall()) D2.L: -1 if JOYPAD is set in the tooltypes, 0 else D3.L: -1 if HDLOAD is set in the tooltypes, 0 else D4.L: -1 if BUTTONWAIT is set in the tooltypes, 0 else D5.L: -1 if LOWMEM is set in the tooltypes, 0 else The others (function tables) are passed in the HD_PARAMS structure. Use the macros, and don't fool with the variables in HD_PARAMS. @ENDNODE @NODE macros "Useful macros" Some of these macros are compulsory for a good compilation and linking of the user program. They are compatible with phxass and should cause no problem with other assemblers. @{" STORE_REGS " Link STORE_REGS} @{" RESTORE_REGS " Link STORE_REGS} @{" Mac_printf " Link Mac_printf} @{" PUTS " Link Mac_printf} @{" NEWLINE " Link Mac_printf} @{" GETUSRADDR " Link PatchMacros} @{" GETGENADDR " Link PatchMacros} @{" PATCHUSRJMP " Link PatchMacros} @{" PATCHUSRJSR " Link PatchMacros} @{" PATCHABSJMP " Link PatchMacros} @{" PATCHABSJSR " Link PatchMacros} @{" PATCHGENJMP " Link PatchMacros} @{" PATCHGENJSR " Link PatchMacros} @{" JSRGEN " Link CallMacros} @{" JSRGEN_FREEZE " Link CallMacros} @{" JMPGEN " Link CallMacros} @{" JSRABS " Link CallMacros} @{" JMPABS " Link CallMacros} @{" TESTFILE " Link MiscMacros} @{" WAIT_BLIT " Link MiscMacros} @{" BEAM_DELAY " Link MiscMacros} @{" GETLVO " Link MiscMacros} @{" WAIT_JOY " Link MiscMacros} @{" WAIT_LMB " Link MiscMacros} @{" HDPARAMS " Link CompMacros} @{" SAVEOS_DATA " Link CompMacros} @{" SET_VARZONE " Link CompMacros} @{" RELOC_MOVEL " Link RelocMove} @{" RELOC_MOVEW " Link RelocMove} @{" RELOC_MOVEB " Link RelocMove} @{" RELOC_CLRL " Link RelocMove} @{" RELOC_CLRW " Link RelocMove} @{" RELOC_CLRB " Link RelocMove} @{" RELOC_STL " Link RelocMove} @{" RELOC_STW " Link RelocMove} @{" RELOC_STB " Link RelocMove} @{" RELOC_TSTL " Link RelocMove} @{" RELOC_TSTW " Link RelocMove} @{" RELOC_TSTB " Link RelocMove} @{" RELOC_SUBL " Link RelocMove} @{" RELOC_SUBW " Link RelocMove} @{" RELOC_SUBB " Link RelocMove} @{" RELOC_ADDL " Link RelocMove} @{" RELOC_ADDW " Link RelocMove} @{" RELOC_ADDB " Link RelocMove} @{" Using registers " Link CautionMacros} @ENDNODE @NODE STORE_REGS "STORE_REGS-RESTORE_REGS" STORE_REGS Save all the registers to stack (D0 to A6) RESTORE_REGS Restore all the registers from stack (D0 to A6) No parametrers expected. @ENDNODE @NODE Mac_printf "Console output" Mac_printf: Prints messages with an easy syntax in an assembly program. Avoids label definition, and all the problems going with it. Mac_printf "Hello world" Mac_printf "You are ",jkjdkfj Mac_printf "a hd-installer maniac" will display on the console: Hello world You are a hd-installer maniac If you use 2 arguments in the macro, there will be no linefeed. PUTS: Puts a string on the screen Argument: string pointer. NEWLINE: Just skips a line. No argument needed. Note: Those macros use the @{"Display()" link Display} routine. @ENDNODE @NODE PatchMacros "PatchMacros" GETUSRADDR Returns in D0 the relocated address of a routine in the user code. This avoids a lea addr(pc),A0 then move.l A0,D0, but is not really useful anymore in the JST environnement. GETGENADDR Returns (in D0) the address of a relocated general purpose routine. Example: lea $1456(A1),A0 GETGENADDR ReadRobSectors move.w #$4EF9,(A0)+ move.l D0,(A0)+ PATCHUSRJMP Sets a JMP to a given user relocatable address. The patched location is absolute. It may be used for chipmem, but not for extension mem, since you cannot know the absolute address (you have to calculate it). Do it by hand in this case. PATCHUSRJSR Same thing, but with a JSR PATCHABSJMP PATCHABSJSR Obsolete. Same thing as PATCHUSRJMP/JSR PATCHGENJMP Sets a JMP in the general purpose relocated area (i.e. the functions of this library callable with JSRGEN) PATCHGENJSR Same thing, for JSRs @ENDNODE @NODE CallMacros "CallMacros" JSRGEN JSRGEN_FREEZE JMPGEN Calls a relocated general purpose function. E.g: JSRGEN TrackLoad Those macros use A5 to get the function address. This register is restored. JSRGEN_FREEZE can be useful if A5 (and also other registers used by the JST function) is used during interrupts. This macro freezes all the interrupts by setting SR to $2700 (means that you've got to be in superuser mode to use it), executes the function, then restores SR. I had to use it in Menace and Lotus Turbo Challenge. JSRABS JMPABS Calls a absolute general purpose subroutine E.g: JSRABS LoadDisks @ENDNODE @NODE CompMacros "Compelling Macros" Those macros are used in (almost) every loader. GO_SUPERVISOR Calls the Supervisor exec routine and stores the userstack in a variable.No argument needed. Since v1.1d GO_SUPERVISOR can be called twice safely (there's a check for user mode) SAVE_OSDATA Calls @{"SaveOSData()" link SaveOSData} with the chipmem you want to be saved. If you want to save 512K chipmem, type SAVE_OSDATA $80000 Passing $200000 to the function will allocate as much as chipmem possible, and mirror only the other parts (0-low boundary and high boundary-$200000) If you want to save all the 2MB of chipmem: SAVE_OSDATA $200000 This will allocate a big block of chipmem, and this block won't have to be mirrored. Passing 2 arguments to SAVE_OSDATA will activate autoquit key feature. The 2nd argument is the autoquit key that you want to use (raw keycode) Passing 3 arguments to SAVE_OSDATA will allow you to specify some custom user code you want called on exit (just like in SetExitRoutine()) The 3rd argument is the address of the custom routine. HD_PARAMS A compulsory macro which declares some variables, and also set tags for JST to read and write data and also recognize the loader. HD_PARAMS "game.d",filesize,number of disks The filesize can be set to STD_DISK_SIZE (901120) for normal trackload copiable disks. See the examples. In diskfile mode, this call makes JST expect the diskfiles to be named game.d1, game.d2, etc... In files mode, the first argument allows to specify the subdir where the data files are to be located. (But you can also use SetFilesPath() to set the subdir too) For a loader using files located in the same directory as the loader: HD_PARAMS "",0,0 WARNING: This macro has 3 arguments. It's not possible to choose the window name any more. An error message will show up when assembling if you put the wrong number of arguments. SET_VARZONE: A macro useful in the case you want to add snapshot option to your loader and you've got local variables that you need to save in the loader (e.g. current disk unit, some flags...) Put it everywhere you want. The best thing is to put it right after HD_PARAMS macro. The code will be executed even before your loader code. This macro consists in a simple JSRABS SetLocalVarZone, with in A0 the start location of the variables (argument 1 of the macro) and in A1 the end location of the variables (argument 2 of the macro). All registers are preserved. If you pass invalid values to this routine (e.g start after end) JST will tell it and quit. @ENDNODE @NODE MiscMacros "MiscMacros" WAIT_LMB: A simple left mouse button pause (port 0). WAIT_JOY: A simple joystick button pause (port 1). TESTFILE: Calls the @{"TestFile()" link TestFile} function, with relocatable argument. TESTFILE fname tst.l D0 bne FileError Actually this routine takes D0 as input and that's a bit annoying since in a relocatable environment we have to lea (pc) in an address register then move to D0 and call the routine. I don't want to change the way the routine works (backwards compatibility) but this little macro makes life easier. GETLVO: A simple macro to get LVO offset in D0. Example: GETLVO AvailMem will return negative offset of AvailMem Intended to use with SetFakeFunction() WAIT_BLIT A macro to wait for the blitter operation to end (equivalent to WaitBlit but does not use any registers, useful for games which use/modify registers in interrupts) BEAM_DELAY A macro to wait using the vertical beam. Takes one argument. BEAM_DELAY 1 will wait approx. 20 ms (PAL) @ENDNODE @NODE RelocMove "Relocatable Memory operations" RELOC_MOVEL/W/B: A macro which allows to move some data in an address specified by a label, but in a relocatable way: move.l D0,label ; is not relocatable and JST will refuse it move.l A6,-(sp) lea label(pc),A6 move.l D0,(A6) ; is relocatable. but a pain to write move.l (sp)+,A6 That's what RELOC_MOVEL does. For Word and Byte format, similar macros known as RELOC_MOVEW and RELOC_MOVEB exist. RELOC_TSTL/W/B: With the 68020+ instruction set, it's possible to test a label in a relocatable way: tst.l label(pc) But with the 68000 this is not possible. So I made a useful macro: RELOC_TSTL label RELOC_CLRL/W/B: Makes a RELOC_MOVE/W/B #0 to location RELOC_ADDL/W/B: RELOC_SUBL/W/B: relocatable add/sub @ENDNODE @NODE CautionMacros "Registers: CAUTION!" Be careful not to use registers A5 and A6 with some macros, because they often use those registers: e.g: PATCHUSRJMP ($30,A5),PatchLoader will crash because PATCHUSRJMP uses A5. This is subject to change, though. To change working registers (A5,A6) used in the macros to lets say (A3,A4), just include the following lines BEFORE the jst.i include. REDEFINED_REGISTERS = 1 ; to tell jst.i that we've redefined the registers Ax EQUR A3 ; work register #1 Ay EQUR A4 ; work register #2 Or manually: move.l A0,-(sp) move.l A5,A0 PATCHUSRJMP ($30,A0),PatchLoader move.l (sp)+,A0 @ENDNODE @NODE whydecrunch "Why decrunch routines?" Why decrunch routines in this package? 2 main reasons: - If you patch the decrunch entry point in chipmem by a JMP, the data will decrunch MUCH faster -> better loader. - You can also patch the decrunch entry point by a JSR and then do some patch stuff easily as the code is now unpacked. Then RTS. @ENDNODE @NODE functions "Functions list" Absolute callable routine (JSRABS only) @{"CloseAll() " link CloseAll} @{"CloseAllQuiet() " link CloseAllQuiet} @{"LoadDisks() " link LoadDisks} @{"LoadDiskFromName() " link LoadDiskFromName} @{"LoadDisksIndex() " link LoadDisksIndex} @{"LoadFiles() " link LoadFiles} @{"LoadSmallFiles() " link LoadSmallFiles} @{"LoadRNCFile() " link LoadRNCFile} @{"Kick37Test() " link Kick37Test} @{"KickVerTest() " link KickVerTest} @{"GetMemFlag() " link GetMemFlag} @{"TransfRoutines() " link TransfRoutines} @{"SaveOSData() " link SaveOSData} @{"FreezeAll() " link FreezeAll} @{"Display() " link Display} @{"AllocExtMem() " link AllocExtMem} @{"Test1MBChip() " link TestxMBChip} @{"Test2MBChip() " link TestxMBChip} @{"Reboot() " link Reboot} @{"Enhance() " link Enhance} @{"Degrade() " link Degrade} @{"DegradeCpu() " link DegradeCpu} @{"DegradeGfx() " link DegradeGfx} @{"FlushCachesSys() " link FlushCachesSys} @{"TestFile() " link TestFile} @{"TestFileAbs() " link TestFileAbs} @{"OpenFakeExec() " link OpenFakeExec} @{"SetFilesPath() " link SetFilesPath} @{"SetLocalVarZone() " link SetLocalVarZone} @{"InitLogPatch() " link InitLogPatch} @{"UseHarryOSEmu() " link UseHarryOSEmu} @{"DisableChipmemGap() " link DisableChipmemGap} Relocate callable routines (only with JSRGEN) Low level calls @{"GetSR() " link GetSR} @{"GoECS() " link GoECS} @{"SaveCustomRegs() " link HandleRegs} @{"RestoreCustomRegs() " link HandleRegs} @{"SaveCIARegs() " link HandleRegs} @{"RestoreCIARegs() " link HandleRegs} @{"InGameOSCall() " link InGameOSCall} @{"InGameIconify() " link InGameIconify} @{"ResetDisplay() " link ResetDisplay} @{"PatchExceptions() " link PatchExceptions} @{"InGameExit() " link InGameExit} @{"GetAttnFlags() " link GetAttnFlags} @{"ResetSprites() " link ResetSprites} @{"BlackScreen() " link BlackScreen} @{"BlockFastMem() " link BlockFastMem} @{"WaitBlit() " link WaitBlit} @{"BeamDelay() " link BeamDelay} @{"PatchMoveBlit_Idx() " link PatchMoveBlit_Idx} @{"LogPatch() " link LogPatch} @{"SetQuitKey() " link SetQuitKey} @{"SetIconifyKey() " link SetIconifyKey} Iconify related routines (new since JST V1.0) @{"PatchMoveCList_Abs() " link PatchMoveCList_Abs} @{"PatchMoveCList_Ind() " link PatchMoveCList_Ind} @{"PatchMoveCList_Idx() " link PatchMoveCList_Idx} @{"InGameIconify() " link InGameIconify} @{"StoreCopperPointer() " link StoreCopperPointer} @{"TellCopperPointer() " link TellCopperPointer} HD/floppy emulation related routines @{"InitTrackDisk() " link InitTrackDisk} @{"TrackLoad() " link TrackLoad} @{"SetTDUnit() " link SetTDUnit} @{"ReadRobSectors() " link ReadRobSectors} @{"ReadDiskPart() " link ReadDiskPart} @{"SetDisk() " link SetDisk} @{"ReadFile() " link ReadFile} @{"ReadFileFast() " link ReadFileFast} @{"ReadFileHD() " link ReadFileHD} @{"ReadFilePart() " link ReadFilePart} @{"ReadFilePartHD() " link ReadFilePartHD} @{"WriteFileHD() " link WriteFileHD} @{"DeleteFileHD() " link DeleteFileHD} @{"ReadUserFileHD() " link ReadUserFileHD} @{"WriteUserFileHD() " link WriteUserFileHD} @{"DeleteUserFileHD() " link DeleteUserFileHD} @{"GetDiskPointer() " link GetDiskPointer} @{"ReadUserDir() " link ReadUserDir} @{"SetFakeFunction() " link SetFakeFunction} @{"GetUserData() " link GetUserData} @{"GetUserFlags() " link GetUserFlags} @{"ReadFileFromImage() " link ReadFileFromImage} @{"WriteFilePartHD() " link WriteFilePartHD} Unpack routines @{"RNCDecrunch() " link RNCDecrunch} @{"RNCDecrunchEncrypted() " link RNCDecrunchEncrypted} @{"RNCLength() " link RNCLength} @{"ATNDecrunch() " link ATNDecrunch} @{"PPDecrunch() " link PPDecrunch} @{"FireDecrunch() " link FireDecrunch} @{"FlushCachesHard() " link FlushCachesHard} Utility @{"StrcmpAsm() " link StrcmpAsm} @{"StrncmpAsm() " link StrncmpAsm} @{"StrcpyAsm() " link StrcpyAsm} @{"StrncpyAsm() " link StrncpyAsm} @{"StrlenAsm() " link StrlenAsm} @{"ToUpperAsm() " link ToUpperAsm} @{"HexToString() " link HexToString} @{"CRC16() " link CRC16} @{"CheckAGA() " link CheckAGA} @{"HexReplaceLong() " link HexReplaceLong} @{"HexReplaceWord() " link HexReplaceWord} @{"JoypadState() " link JoypadState} @{"IsRegistered() " link IsRegistered} Debug/Development @{"WaitMouse() " link WaitMouse} @{"WaitMouseInterrupt() " link WaitMouseInterrupt} @{"EnterDebugger() " link EnterDebugger} @{"SetTraceVector() " link SetTraceVector} @ENDNODE @NODE JoypadState "JoypadState()" ULONG JoypadState(port) D0 D0 This routine allows to check CD32 joypad buttons. It obviously does not use lowlevel.library and is buggy unless on a CD32 (why???). It's ripped from James Pond 3 routine (I was not the first since the ReadJoypad.s from aminet was also ripped from this one). port can be 0 (mouse port) or 1 (joystick port). The routine returns bits that you can test. The bits are defined in gp_macros.i moveq #0,D0 JSRGEN JoypadState btst #AFB_START ; start/pause button beq nostart$ ... On a normal amiga, you've got to go in a direction to make this routine work. I don't know why, but it works perfectly on a CD32. Also, you can't press fire (red button) and the other buttons together, or only fire will be detected. You have to wait for a vertical blank to occur before you can use this function. I suggest that you put it in the level 3 interrupt, just before acknowledge (which is a move in $DFF09C) and set the flags here. Then another routine will check those flags and emulate game keys such as pause, jump/fire, etc... it's up to you :) NOTE: If you only want to check the second button (blue, or Sega joystick 2nd button), you can also read $DFF016 and check for bit 14 low, still after a VBLANK. Don't forget to reset the potgo in that case by move.w #$CC01,($DFF034) See also: @ENDNODE @NODE GetUserData "GetUserData()" APTR GetUserData(void) A0 This routine returns in A0 a pointer to the NULL terminated string passed by the USERDATA argument or tooltype. It points to an empty string if USERDATA was not filled. It's useful to set a swith other than the user ones already present such as TRAINER, JOYPAD... and some info can be passed (it's not only a switch) I used it in the Awesome JST ripper to specify the disk, side and drive unit. See also: GetUserFlags() @ENDNODE @NODE GetUserFlags "GetUserFlags()" ULONG GetUserFlags(void) - returns loader set options D0 This routine returns in D0 a combination of the option the user could have set. Not all the options are present here, only some switches which are: TRAINER HDLOAD LOWMEM NTSC NOOSSWAP JOYPAD To test if an option is active, just do a btst #AFB_