[net.micro.atari16] upside-down DA, source and uuencoded binary

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(" @("  &
 
end

jhs@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