Short: patch old C68-compiled code to work on 68040 and later Author: Mark J Swift Version: 1.03 Uploader: msw@blackpool.ac.uk Type: util/ptch This BASIC program fixes known cache problems with old C68 compiled code. Old versions of C68 have inadequate cache routines. New versions of C68 are OK (I think). The problem arises on 68040 and 68060 processors - especially when COPYBACK is enabled. The program may seem fussy and overcomplicated compared to other patchers - but it should recognise and fix more. ARCHIVE CONTENTS C68PATCH_bas - The patcher program. C68PATCH_readme - This file. WHY IS IT NECESSARY? On machines with 68040 and 68060 processors, enabling the COPYBACK cache can give substantial speed increases since memory is only updated from the caches when absolutely necessary. Thus with COPYBACK enabled, it is ESSENTIAL to flush the caches out to memory before they are cleared or disabled. From a disassembly it can be seen that during the start-up code (before program relocation) C68 reads the status of the caches - then disables them. After program relocation the caches are put back in the same state as when the program was entered. The caches are typically disabled by the following subroutine: CACHOFF: cmpi.b #$20,$A1(a6) bls.s CACHOFX * movec cacr,d0 * 1=data cache enable (>=040) * | 1=instr cache enable (>=040) * | | 1=clear data cache (030) * | | | 1=data cache enable (030) * | | | | 1=clear instr cache (020,030) * | | | | | 1=instr cache enable(020,030) * | | | | | | move.l #%00000000000000000000100000001000,d1 movec d1,cacr * CACHOFX: rts On 030 processors this clears (bits 3 and 11 set) the data and instruction caches and also disables them (bits 0 and 8 clear). On the >=040 processors the code simply disables the caches. It does not update the memory from the caches. In most cases on the '040 the code will be sufficient (i.e it usually works). However on an '040 with COPYBACK enabled the subroutine always fails - usually with a corrupted return stack. Here is what happens... The subroutine CACHEOFF is called and the return address is pushed on the stack. However with COPYBACK enabled the return address is written to the data cache but not written through to memory. Next, the subroutine disables the caches but does not flush them to memory beforehand. Now memory does not contain up-to-date information and cache contents are already lost. This means that the return stack will NOT contain the correct return address - so the RTS instruction bombs the machine. The section of code that sets the cache to a value (passed in d0) also fails to flush the caches: SETCACH: tst.l d0 beq.s SETCACHX cmpi.b #$40,$A1(a6) blt.s SETCACH2030 cinva ic/dc SETCACH2030: movec d0,cacr SETCACHX: rts In fact, C68 NEED NOT DISABLE the caches at all. It should simply flush them out to RAM - before and after relocation. The following routine correctly flushes the caches. It is patched into offending code by C68PATCH_bas. ******************************************************************* * * routine to flush the caches (must be called from user mode) * FLSHCACH: trap #0 enter supervisor mode movem.l d0-d2/a0,-(a7) moveq #0,d0 trap #1 sys var address in a0 cmpi.b #$10,$A1(a0) bls.s FLSHCACHX exit if 010 or less dc.l $4E7A1002 (movec cacr,d1) ori.w #$0808,d1 on 020/030 always clear caches cmpi.b #$30,$A1(a0) bls.s FLSHCACHSET tst.w d1 check 040 bits bpl.s FLSHCACHDCHK branch if instruction cache off dc.w $F4B8 (cpusha ic) otherwise update memory from cache FLSHCACHDCHK: tst.l d1 check 040 bits bpl.s FLSHCACHDINV branch if data cache off dc.w $F478 (cpusha dc) otherwise update memory from cache bra.s FLSHCACHIINV FLSHCACHDINV: dc.w $F458 (cinva dc) invalidate data cache FLSHCACHIINV: dc.w $F498 (cinva ic) invalidate instruction cache FLSHCACHSET: dc.l $4E7B1002 (movec d1,cacr) set the cache FLSHCACHX: movem.l (a7)+,d0-d2/a0 andi.w #$D8FF,sr back into user mode rts ******************************************************************* CONTACT post: MARK J SWIFT e-mail: msw@blackpool.ac.uk 175 CHURCH STREET BLACKPOOL LANCS FY1 3NX