csc@watmath.UUCP (Jan Gray) (09/12/86)
This silly desk accessory turns your ST screen upside down. It was mainly
a "see if it can be done" experiment which I thought you might enjoy.
It allocates memory for another screen, moves the hardware screen there, and
repeatedly flips the "logical" screen onto the new screen. Unfortunately
I couldn't coerce the 68000 to take less than 120 ms per flip, so leaving
the ST some computing cycles you get about a 4 Hz update rate.
Following are the C sources (which work with the new Alcyon C release) and
a uuencoded binary. Unpack it, uudecode it, upload it and install it as
ud.acc. It's cute, but you'll tire of it quickly, believe me.
Jan Gray
University of Waterloo but doing a workterm at Northern Software (519) 885-5921
ud.c:
-----------------------------
/*
* Upside-down DA...a somewhat disappointing experiment
*
* Jan Gray 1986
*
* link: accstart,ud,aesbind,osbind
*/
#include "gemdefs.h"
#include "osbind.h"
#define NULL 0
#define SCR_BYTES 32000L
#define SCR_ALIGN 512L /* must page align screen */
#define Supexec(code) xbios(38, code)
typedef unsigned char Byte; /* must be unsigned! */
Byte RevBytes[256];
Byte *RealScreen; /* real screen address */
Byte *FlipScreen; /* flipped screen address */
Byte *Phys; /* passed to setPhysBase() */
setPhysBase();
main()
{
extern int gl_apid;
char menuName[20];
int menuID;
int event;
int msg[8];
int ret;
appl_init();
buildRevBytes();
RealScreen = Physbase();
FlipScreen = (Byte *)((Malloc(SCR_BYTES + SCR_ALIGN) + (SCR_ALIGN-1))
& ~(SCR_ALIGN-1));
menuName[0] = NULL;
menuID = menu_register(gl_apid, menuName);
for (;;) {
/* Wait for accessory open message */
strcpy(menuName, " Upside-down");
do {
event = evnt_mesag(msg);
} while (!(msg[0] == AC_OPEN && msg[4] == menuID));
/* Flip screen */
Phys = FlipScreen;
Supexec(setPhysBase);
refreshFlip();
/*
* Wait for accessory open message or 130 ms timeout.
* 130 ms should give roughly 50% duty cycle.
*/
strcpy(menuName, " Rightside-up");
do {
event = evnt_multi(MU_MESAG | MU_TIMER,
0, 0, 0,
0, 0, 0, 0, 0,
0, 0, 0, 0, 0,
msg, 130, 0,
&ret, &ret, &ret, &ret, &ret, &ret);
if (event & MU_TIMER)
refreshFlip();
} while (!((event & MU_MESAG) &&
msg[0] == AC_OPEN && msg[4] == menuID));
/* Restore screen */
Phys = RealScreen;
Supexec(setPhysBase);
}
}
buildRevBytes() /* Build the byte reversal table */
{
register int i;
for (i = 0; i < 256; i++)
RevBytes[i] = ((i & 1) << 7) | ((i & 2) << 5) |
((i & 4) << 3) | ((i & 8) << 1) |
((i & 0x10) >> 1) | ((i & 0x20) >> 3) |
((i & 0x40) >> 5) | ((i & 0x80) >> 7);
}
#define VBASE_HIGH (Byte *)0xff8201L
#define VBASE_LOW (Byte *)0xff8203L
/*
* setPhysBase -- set the physical screen to Phys. I don't use Setscreen()
* because it seems to clear the old logical screen...I don't want the
* ST to know that anything funny is going on, just to go merrily on its
* way writing to what it thinks is the physical screen...
*/
setPhysBase()
{
*VBASE_HIGH = (Byte)((unsigned long)Phys >> 16);
*VBASE_LOW = (Byte)((unsigned long)Phys >> 8);
}
/*
* Copy the flip of the real screen to FlipScreen. Scans the real screen
* from last byte to first, writing to the flip screen from first byte
* to last.
*/
refreshFlip()
{
register /* a5 */ Byte *real = RealScreen + SCR_BYTES;
register /* a4 */ Byte *flip = FlipScreen;
register /* a3 */ Byte *rev = RevBytes;
register int count = SCR_BYTES/8;
/*
* Copy bytes of the real screen to the flip screen, through
* the byte reverse table. Unrolled 8 times for speed.
*
* Written in assembler (probably not optimal assembler...)
* because Alcyon C 4.14 generates really really stupid code
* (like "andi #$ff, d0" followed by "andi.l #$ff, d0"). Oh, God.
*
* Expected time: 4 us/byte * 32000 bytes = 130 ms
*/
while (count-- > 0) {
#ifdef STUPID_ALCYON_C
#define COPY *flip++ = rev[*--real];
#else
asm("moveq #0,d0"); /* clear upper byte of d0.w */
#define COPY asm("move.b -(a5),d0"); /* 10->12 cycles == 1.5 us */\
asm("move.b 0(a3,d0.w),(a4)+"); /* 18->20 cycles == 2.5 us */
#endif
COPY COPY COPY COPY COPY COPY COPY COPY
}
}
/* Writing strcpy here saves us from linking with gemlib */
strcpy(dst, src)
register char *dst;
register char *src;
{
while (*dst++ = *src++)
;
}
--------------------------
ud.acc.uue:
--------------------------
begin 644 ud.acc
M8!H 40 !>@ !98 "Y\ *CDZY ("Z\
M $Y!(B\ !# \ ,A.0DYU3E;_TDZY #4DZY !M#Z\ ).N0 !. CP
M"K(NO ?P _/ !(3KD 4 5(_0O ?_ O/___@ CP "M1"+O_L+HX&
ME____^P_.0 #!).N0 !+Y4CSU _^HNO !FPO#@:7____[$ZY "QEB/
M+HX&E____]A.N0 \8]0/_H#&X */_89N8P+O_@L&[_ZF;<(_D K4 *
MEBZ\ "+#\\ "9.N0 !.!4CTZY "6BZ\ &>B\.!I?____L3KD +&
M6(\NC@:7____UB\.!I?____6+PX&E____]8O#@:7____UB\.!I?____6+PX&
ME____]9"9S\\ ((O#@:7____V$)G0F="9T)G0F="9T)G0F="9T)G0F="9T)G
M/SP ,$ZY #X-_\ .#U _^@(+@ %_^EG (3KD ):""X !/_I9P#_
M? QN "C_V&8 _W(P+O_@L&[_ZF8 _V8C^0 "K( J6+KP (L/SP )DZY
M $X%2/8 #^U$Y>3G5.5@ 2.<# $)'8 7# 'P'P >] ,@?"? "ZT&
M03('PGP !.=!@$$R!\)\ CC08!!,@?"? 0XD& 03('PGP (.9!@$$R!\)\
M $#J08!!,@?"? " [D& 03)'T_P K8$H!21[Y\ 0!MH$J?3-\ @$Y>3G5.
M5O_\(#D J6<A#BJ,!\ /\3P #_@@$@.0 "I;@B,!\ /\3P #_@@-.7DYU
M3E8 $CG QPJ>0 "K+;_ ?0 H>0 "M0F? "M@^/ ^@8 -' $"48
M\P $"48\P $"48\P $"48\P $"48\P $"48\P $"48\P $"48\P
M, =31TI ;L9*GTS?.(!.7DYU3E8 $CG 0PJ;@ (*&X #& (:W&;\2I],
MWS 3EY.=4Y6__8S[@ ( +V# N C0?/_VP?P TC T+P 40+4#_^CU\
M '__F >(&[_^A 02( R;O_^T\G3_ "]@R@%*N__I2;O_^#&X !/_^;=HN
MN0 # Y.N0 !1"0# Y , $Y>3G5.5O_Z(_P O8 *FB/\ *M@
M"IXC_ "^ JB(_P P *IB/\ ,% "JHC_ #!P JN(_P
M J: ,#CZ\ IA /]&,_D P ,$G !3EY.=4Y6__P^O 380#_*G !
M3EY.=4Y6__PC[@ ( ,%#Z\ !=.N0 NA.7DYU3E;__#/N @ O@,^X
M"@ "^(S[@ , +Y#/N X OF,^X $ "^@S[@ 2 +ZC/N !0 OL
M,^X %@ "^XS[@ 8 +\#/N !H OR,^X ' "_0S[@ > +]C/N "
M OX,^X (@ "_HC[@ D ,%#/N "@ O\,^X *@ "_X^O 93KD +H
M(&X +#"Y , B!N # PN0 # 0@;@ T,+D P&(&X .#"Y ,""!N #PP
MN0 # H@;@! ,+D P,0D P.0 # !.7DYU3E;__#/N @ O@(^X "@
M#!0^O C3KD +H3EY.=2/? *DDY.+SD J23G4CWP "I).32\Y *
MDDYU(]\ J23D$O.0 "I).=0 ! (! 0(! 0 ! 0(! 0$! 0
M ! ! ,% 4% ! 0(! ! ' 0(! $! 0(! 0(! 0(!
M 0$! @$! 0 (! 0$! 08! 00! 0$# 0(! 00" 0@! 0
M $! 0D! 0$! 0$! % 0
M 0# @# 8! @! @! 0! 0,! 0 % $!
M 0 % ! 0 ! 0 " @
M 4! 4! $! $! (% 8! (! $! 8%
M ! 0 ! (! (! 0$! 0 ! @,! @$! 0$!
M 0 ! 0 ! B @57!S:61E+61O=VX ("!2:6=H='-I9&4M=7 (&'@8*
M!A 4$@8,#A <! 8*" 8.9!HF! 8*;AX4'@P&>A0@& 8(#@0&! 8$!@0&! 8$
I!@0.!"0*$ @(" @(" @(" @(" @(" @*"@H*"@H*"! ("@H(" @(" &
endjhs@mitre-bedford.ARPA (09/13/86)
Heck, if all you want to do is turn a screen upside down, buy an Atari 800xl. All you have to do there is write one number to one memory location and the screen turns upside down! (:^/) -jhs