[net.micro.atari16] Upside-down DA, v.2

csc@watmath.UUCP (Jan Gray) (09/16/86)

Just when you thought it was safe to turn your monitor rightside-up...

Here are the sources and uuencoded binary to a new version of my
silly upside down desk accessory.  This one refreshes the screen at
more than 10 Hz when there is little change between refreshes.

It keeps checksums on 32 byte blocks of the screen and reverses the
changed blocks.

I promise not to post any more of these.  Honest.

What do you mean, pointless?

Jan Gray


ud.c:
------------------
/*
 * Upside-down DA, v.2 ...a somewhat less disappointing experiment
 *
 * Jan Gray 1986
 *
 * link: accstart,ud,flip,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! */

long	Chksums[32000/32];
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();
	zapChksums();

	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 */
		refreshFlip();
		Phys = FlipScreen;
		Supexec(setPhysBase);
			
		/*
		 * Wait for accessory open or close message or 50 ms timeout.
		 */
		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, 50, 0,
				 	   &ret, &ret, &ret, &ret, &ret, &ret);
			if (event & MU_TIMER)
				refreshFlip();	/* 20 to 150 ms */
		} while (!((event & MU_MESAG) &&
			   (msg[0] == AC_OPEN && msg[4] == menuID ||
			    msg[0] == AC_CLOSE && msg[3] == 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);
}

zapChksums()				/* Initialize the checksums to ff's */
{
	register long	*p;
	register long	ffffffff	= 0xffffffffL;

	for (p = Chksums; p < &Chksums[32000/32]; ) {
		*p++ = ffffffff;
		*p++ = ffffffff;
		*p++ = ffffffff;
		*p++ = ffffffff;
	}
}

#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);
}

/* Writing strcpy here saves us from linking with gemlib */
strcpy(dst, src)
register char	*dst;
register char	*src;
{
	while (*dst++ = *src++)
		;
}
----------------------
flip.s:
----------------------
*
* flip.s
*
* Assembler _refreshFlip.
*
* Reverse the real screen onto the flip screen.  Rather than reversing
* every byte every time called (which is slow -- about 120 ms per call),
* we reverse only those bytes which have changed since the last call.
*
* Instead of saving yet another copy of the screen, we keep a longword
* checksum for each block of 32 bytes.  If a new checksum differs, we save
* it away and reverse that 32 byte block.
*
* Since the screen changes little between calls, this is a big win, reducing
* the average time spent here from about 120 to 20 ms per call.
*
*
* Registers used
* a5	- real screen
* a4	- flip screen start
* a3	- flip screen
* a2	- reverse table
* a1	- checksum table
* a0	- constant 32
* d7-d0	- scratch
.globl _RealScreen
.globl _FlipScreen
.globl _RevBytes
.globl _Chksums
.text
.globl _refreshFlip
_refreshFlip:
	link	a6,#0
	movem.l	d0-d7/a0-a5,-(sp)
	move.l	_RealScreen,a5
	move.l	_FlipScreen,a4
	move.l	a4,a3
	add.l	#32000,a3			* a3 = end of FlipScreen
	move.l	#_RevBytes,a2
	move.l	#_Chksums,a1
	move.l	#32,a0
loop:
	movem.l	(a5)+,d0-d7			* fetch 32 bytes
	add.l	d1,d0				* compute new checksum
	add.l	d2,d0
	add.l	d3,d0
	add.l	d4,d0
	add.l	d5,d0
	add.l	d6,d0
	add.l	d7,d0
	cmp.l	(a1)+,d0			* compare against old checksum
	bne	rev				* reverse line if different
	sub.l	a0,a3				* skip 32 bytes on flip screen
loop1:
	cmp.l	a4,a3				* done?
	bcc	loop
	movem.l	(sp)+,d0-d7/a0-a5
	unlk	a6
	rts

rev:
	move.l	d0,-4(a1)			* differs; save new checksum
	sub.l	a0,a5				* adjust a5 to front of 32 bytes
	moveq.l	#0,d0				* load upper byte with 0
	move.b	(a5)+,d0			* copy real byte through byte-
	move.b	0(a2,d0.w),-(a3)		*  reversal table to flip screen
	move.b	(a5)+,d0			* likewise for 31 bytes
	move.b	0(a2,d0.w),-(a3)
	move.b	(a5)+,d0
	move.b	0(a2,d0.w),-(a3)
	move.b	(a5)+,d0
	move.b	0(a2,d0.w),-(a3)
	move.b	(a5)+,d0
	move.b	0(a2,d0.w),-(a3)
	move.b	(a5)+,d0
	move.b	0(a2,d0.w),-(a3)
	move.b	(a5)+,d0
	move.b	0(a2,d0.w),-(a3)
	move.b	(a5)+,d0
	move.b	0(a2,d0.w),-(a3)
	move.b	(a5)+,d0
	move.b	0(a2,d0.w),-(a3)
	move.b	(a5)+,d0
	move.b	0(a2,d0.w),-(a3)
	move.b	(a5)+,d0
	move.b	0(a2,d0.w),-(a3)
	move.b	(a5)+,d0
	move.b	0(a2,d0.w),-(a3)
	move.b	(a5)+,d0
	move.b	0(a2,d0.w),-(a3)
	move.b	(a5)+,d0
	move.b	0(a2,d0.w),-(a3)
	move.b	(a5)+,d0
	move.b	0(a2,d0.w),-(a3)
	move.b	(a5)+,d0
	move.b	0(a2,d0.w),-(a3)
	move.b	(a5)+,d0
	move.b	0(a2,d0.w),-(a3)
	move.b	(a5)+,d0
	move.b	0(a2,d0.w),-(a3)
	move.b	(a5)+,d0
	move.b	0(a2,d0.w),-(a3)
	move.b	(a5)+,d0
	move.b	0(a2,d0.w),-(a3)
	move.b	(a5)+,d0
	move.b	0(a2,d0.w),-(a3)
	move.b	(a5)+,d0
	move.b	0(a2,d0.w),-(a3)
	move.b	(a5)+,d0
	move.b	0(a2,d0.w),-(a3)
	move.b	(a5)+,d0
	move.b	0(a2,d0.w),-(a3)
	move.b	(a5)+,d0
	move.b	0(a2,d0.w),-(a3)
	move.b	(a5)+,d0
	move.b	0(a2,d0.w),-(a3)
	move.b	(a5)+,d0
	move.b	0(a2,d0.w),-(a3)
	move.b	(a5)+,d0
	move.b	0(a2,d0.w),-(a3)
	move.b	(a5)+,d0
	move.b	0(a2,d0.w),-(a3)
	move.b	(a5)+,d0
	move.b	0(a2,d0.w),-(a3)
	move.b	(a5)+,d0
	move.b	0(a2,d0.w),-(a3)
	move.b	(a5)+,d0
	move.b	0(a2,d0.w),-(a3)
	bra	loop1				* continue
-----------------
ud.acc.uue:
-----------------
begin 644 ud.acc
M8!H   8.   !>@  %38                  "Y\   +C$ZY    ("Z\    
M $Y!(B\ !# \ ,A.0DYU3E;_TDZY   $4$ZY   !T$ZY   "2#Z\  ).N0  
M!=XCP   "[ NO   ?P _/ !(3KD   7^5(_0O    ?_ O/___@ CP   "])"
M+O_L+HX&E____^P_.0  #1!.N0  !;Q4CSU _^HNO   !VHO#@:7____[$ZY
M   "I%B/+HX&E____]A.N0  !,0]0/_H#&X */_89N8P+O_@L&[_ZF;<3KD 
M  +&(_D   O2   +E"Z\   "=C\\ "9.N0  !=Y4CRZ\   '>"\.!I?____L
M3KD   *D6(\NC@:7____UB\.!I?____6+PX&E____]8O#@:7____UB\.!I?_
M___6+PX&E____]9"9S\\ #(O#@:7____V$)G0F="9T)G0F="9T)G0F="9T)G
M0F="9T)G/SP ,$ZY   $WM_\    .#U _^@(+@ %_^EG   (3KD   +&""X 
M!/_I9P#_? QN "C_V&8   XP+O_@L&[_ZF<  !@,;@ I_]AF /]<,"[_WK!N
M_^IF /]0(_D   NP   +E"Z\   "=C\\ "9.N0  !=Y4CV  _KY.7DYU3E8 
M $CG P!"1V   %PP!\!\  'O0#('PGP  NM!@$$R!\)\  3G08!!,@?"?  (
MXT& 03('PGP $.)!@$$R!\)\ "#F08!!,@?"? ! ZD& 03('PGP @.Y!@$$R
M1]/\   +UA* 4D>^? $ ;:!*GTS? (!.7DYU3E8  $CG P1^_RI\   -&F  
M  HJQRK'*L<JQ[O\   <NF7P2I],WR" 3EY.=4Y6__P@.0  "Y1R$.*HP'P 
M_Q/  /^" 2 Y   +E."(P'P _Q/  /^" TY>3G5.5@  2.<!#"IN  @H;@ ,
M8    AK<9OQ*GTS?, !.7DYU3E8  $CG__PJ>0  "[ H>0  "](F3-?\  !]
M "1\   +UB)\   -&B!\    ($S= /_0@=""T(/0A-"%T(;0A["99@  $)?(
MM\QDXDS?/_].7DYU(T#__)O(<  0'1<R   0'1<R   0'1<R   0'1<R   0
M'1<R   0'1<R   0'1<R   0'1<R   0'1<R   0'1<R   0'1<R   0'1<R
M   0'1<R   0'1<R   0'1<R   0'1<R   0'1<R   0'1<R   0'1<R   0
M'1<R   0'1<R   0'1<R   0'1<R   0'1<R   0'1<R   0'1<R   0'1<R
M   0'1<R   0'1<R   0'1<R   0'1<R   0'1<R  !@ /\J3E;_]C/N  @ 
M  S6,"X "-!\__;!_  #2,#0O   !@XM0/_Z/7P  ?_^8!X@;O_Z$!!(@#)N
M__[3R=/\   ,UC* 4J[_^E)N__X,;@ $__YMVBZY   -#$ZY    %$) ,#D 
M  S^3EY.=4Y6__HC_   #-8   N8(_P   NT   +G"/\   ,W@  "Z C_   
M#/X   ND(_P   T2   +J"/\   <N@  "ZPC_   "Y@   T,/KP "F$ _T8S
M^0  #/X   T0< %.7DYU3E;__#Z\ !-A /\J< %.7DYU3E;__"/N  @   T2
M/KP %TZY   #YDY>3G5.5O_\,^X "   #-XS[@ *   ,X#/N  P   SB,^X 
M#@  #.0S[@ 0   ,YC/N !(   SH,^X %   #.HS[@ 6   ,[#/N !@   SN
M,^X &@  #/ S[@ <   ,\C/N !X   ST,^X (   #/8S[@ B   ,^"/N "0 
M  T2,^X *   #/HS[@ J   ,_#Z\ !E.N0   ^8@;@ L,+D   T (&X ,#"Y
M   - B!N #0PN0  #00@;@ X,+D   T&(&X /#"Y   -""!N $ PN0  #0I"
M0# Y   ,_DY>3G5.5O_\,^X "   #-XC[@ *   -$CZ\ "-.N0   ^9.7DYU
M(]\   N03DXO.0  "Y!.=2/?   +D$Y-+SD   N03G4CWP  "Y!.02\Y   +
MD$YU  $  @$! @$!  $! @$! 0$!              $   $  P4 !04   $!
M @$ $ <! @$              0$! @$! @$! @$! 0$" 0$!            
M     @$! 0$!!@$!! $! 0,! @$!! (!" $!         0$!"0$! 0$! 0$ 
M  4!                                                        
M    ! , " , !@$ " $ " $ ! $! P$!  4  0$!  4   $!  $!        
M                          ("                                
M    !0$ !0$  0$  0$  @4 !@$  @$  0$ !@4       $!  $  @$  @$!
M 0$!                      $" P$" 0$! 0$!  $!  $"("!5<'-I9&4M
M9&]W;@ @(%)I9VAT<VED92UU<        @8>!@8*!A 4$@8,#A <!@0&"@@.
M9!H\! 8*;B02%A1 !@X& 084(!@&" X$!@0&! 8$!@0&! 8$#@0D"A (" @(
>" @(" @(" @(" @("@H*"@H*"@@0" H*" @(" @ 
 
end