Mar 97 Tips
Volume Number: 13
Issue Number: 3
Column Tag: Tips & Tidbits
Tips & Tidbits
By Steve Sisak
Whenever you directly or indirectly modify code, you need to make sure the processor
caches are synchronized in order to avoid confusing the processor and/or emulator.
This includes not only self-modifying code, but also creating routine descriptors and
loading code resources by hand.
If you move 68k code with BlockMove on any system (68k or PowerPC) the caches are
flushed automatically (assuming blocks greater than 12 bytes). Use BlockMoveData
for blocks containing no code, since they do not require the cache flushing overhead.
Note that on a PowerPC, BlockMove does not flush PPC caches at all. The only reason
BlockMove flushes 68k code is for backward compatibility with software written
before the '040s. It is unfortunate that a frequently-used routine like BlockMove
should have to know anything about instruction caches. On the bright side, most
developers do not need to copy PPC code around, since fragment preparation occurs
within CFM.
On a PPC machine, calls to the 68k cache flushing routines (including
FlushCodeCacheRange and indirectly via BlockMove) do everything necessary to
maintain 68k instruction cache coherency. On the original 68k emulator, this meant
nothing needed to be done since there was no cached code. On the DR Emulator and Speed
Emulator, these calls force the emulator to "throw out" any recompiled code associated
with the specified code range.
I know the different cache flushing routines are confusing and not very well
documented. Here are some simple rules:
If you are dealing with 68k instructions, use BlockMove or FlushCodeCacheRange. They
both specify a range of memory and therefore do not require the newer recompiling
68k emulators to perform a complete cache flush (a very time-intensive operation
that can degrade performance significantly.)
If you are dealing with PPC code, you probably don't need to worry about the issue
because your code was probably directly or indirectly prepared by CFM. However, if
you do generate PPC code on the fly, you should call MakeDataExecutable on the range.
Note that this does more than just flushing the cache. It does everything (including
flushing the processor's prefetch queue) necessary to deal with newly-generated code.
Hope this helps clear things up. If you want more details, check out the tech note I
wrote while I was still at Apple on the DR Emulator.
Eric Traut
Connectix Corp.
(Almost) Painless Mixing of C and Pascal Strings
It's fair to say that most of us have found ourselves in this situation: "The API wants
C-style strings and all I have are these Pascsal strings!". The typical solution is to
use utilities like PtoCStr and CtoPStr to shuffle the bytes around. Consider the
following example where sprintf is being used to create a menu title.
void DescribeFile (Str255 title, Str255 fileName, Str255 volumeName,
unsigned long size)
// Temporarily convert fileName and volumeName to C strings
PtoCStr (fileName);
PtoCStr (volumeName);
// Use sprintf to describe the file eg. "File foo on bar (120.5K)
sprintf ((char*) title, "File %s on %s (%.2fK)",
(char*) fileName,
(char*) volumeName,
(double) size / 1024.0);
// Convert title, fileName and volumeName to Pascal strings
// back to Pascal strings
CtoPStr ((char*) title);
CtoPStr ((char*) fileName);
CtoPStr ((char*) volumeName);
}
As you know there's at least one unused byte at the end of the Pascal string, and the
string is not a literal, you can take a shortcut by making the Pascal strings "hybrid
strings". A "hybrid string" is a null-terminated pascal string. Observe:
void DescribeFile (Str255 title, Str255 fileName, Str255
volumeName,unsigned
long size)
// Convert fileName and volumeName to hybrid strings
fileName [fileName [0] + 1] = ‘\0';
volumeName [volumeName [0] + 1] = ‘\0';
// Use sprintf to describe the file eg. "File foo on bar (120.5K)
// Note that we skip the first byte of the hybrid strings
sprintf ((char*) &title [1], "File %s on %s (%.2fK)",
(char*) &fileName [1],
(char*) &volumeName [1],
(double) size / 1024.0);
// ‘title' is not yet a hybrid string, it has an undefined length
byte
title [0] = strlen ((char*) &title [1]);
}
Remember, you can't always get away with this. In the above we know that title,
fileName and volumeName are non-const strings with room for 255 characters. Since
‘fileName' and ‘volumeName' will never be more than 63 and 27 bytes respectively,
we're sure there is room to add the length byte to the end. Similarly, ‘title' won't
break 130 bytes.
Damon Cokenias
<http://www.netgate.net/~cokenias>