[comp.sys.atari.st] Questions about ST Video Ram

brenes@skywest.UUCP (Erasmo Brenes) (08/03/88)

Hello, this is a question to the ST graphic 'gurus':

I've written a program which is capable of generating a full screen (640 x 200)
at a high rate (approx. refresh rate). Thus I have a NextScreen[32k] buffer
which I use as a secondary video buffer. The idea behind it is to ping-pong
between this NextScreen[] buffer and the one that the ST assigns for the
Video, by changing the physical address from which the Shifter expects to
find the video information. In this way I save the time consuming operation
of moving data from NextScreen[] to the video buffer for display.

The problem that I have is that every time I call the XBIOS routine
SetScreen(logadr,phyadr,rez), where phyadr = &NextScreen[0], the screen jumps 
horizontally left to right. The information displayed on the screen is
correct but is skewed to the right 3/4 of the screen (BTW, the program
is written using MWC 2.x). What I've noticed is that the video buffer that
the ST starts with is located in a 32K boundary, 0xf8000, while the starting
location of NextScreen[] is not. It also seems that if a take &NextScreen[0]
mod 32K, the remainder is the offset that I see on the screen. So, the
question is: If the Shifter expects the video ram to start at 32K boundaries,
then how do I get MWC, or any C program to allocate a 32Kb buffer starting in
a 32Kb boundary in an efficient manner?  An initial thought was to use Malloc()
to allocate 64Kb and then only use the 32Kb which start in a 32Kb boundary,
but this method is too wasteful. There's got to be a better way, isn't there?

Any suggestions will be welcomed.

Erasmo.

koreth@ucscb.UCSC.EDU (Socking the Sockets) (08/03/88)

In article <535@skywest.UUCP> brenes@skywest.UUCP (Erasmo Brenes) writes:
>If the Shifter expects the video ram to start at 32K boundaries,
>then how do I get MWC, or any C program to allocate a 32Kb buffer starting in
>a 32Kb boundary in an efficient manner?

Well, the boundary turns out to be a lot less than 32K: screen RAM must
start on a page boundary, which is to say screenram%256 == 0.
Thus you only have to allocate 32256 bytes, which you can most likely
afford.  (Screen memory is 32000 bytes, not a full 32K.)

---
These are my opinions, and in no way reflect those of UCSC, which are wrong.
Steven Grimm		Moderator, comp.{sources,binaries}.atari.st
koreth@ssyx.ucsc.edu	...!ucbvax!ucscc!ssyx!koreth

jason@lakesys.UUCP (Jason) (08/03/88)

In article <535@skywest.UUCP>, brenes@skywest.UUCP (Erasmo Brenes) writes:
> is written using MWC 2.x). What I've noticed is that the video buffer that
> the ST starts with is located in a 32K boundary, 0xf8000, while the starting
> location of NextScreen[] is not. It also seems that if a take &NextScreen[0]
> mod 32K, the remainder is the offset that I see on the screen. So, the
> question is: If the Shifter expects the video ram to start at 32K boundaries,
> then how do I get MWC, or any C program to allocate a 32Kb buffer starting in
> a 32Kb boundary in an efficient manner?  An initial thought was to use Malloc()
> to allocate 64Kb and then only use the 32Kb which start in a 32Kb boundary,
> but this method is too wasteful. There's got to be a better way, isn't there?
> 

	Like the summary says, the address needs to be evenly divisible by
0x100 (some people claim 0x200, but I've never had problems with 0x100). The
method for this fairly simple:

char	NextScreen[32256],*NSPtr;

somewhere down the line:

	NSPtr = (NextScreen & (~0xff)) + (((NextScreen & 0xff) > 0) * 0x100);

	This code flat won't work, as MWC doesn't allow anding an address
(last time I checked, anyways), so you just cast NextScreen to a long in the
line above (or use a temporary variable, or whatever toggles your fancy).

	The second half of the line takes care of the problem of just using
the &. However, if I remember correctly, the line will be faster than using
a mod - this should probably be checked out via diassembly...

> Erasmo.

-- 

Jason - Not your average iconoclast  |	UUCP: uwvax!uwmcsd1!lakesys!jason

jf@laura.UUCP (Jan Hinrich Fessel) (08/03/88)

In article <535@skywest.UUCP> brenes@skywest.UUCP (Erasmo Brenes) writes:
>Hello, this is a question to the ST graphic 'gurus':
>question is: If the Shifter expects the video ram to start at 32K boundaries,
>then how do I get MWC, or any C program to allocate a 32Kb buffer starting in
>a 32Kb boundary in an efficient manner?  An initial thought was to use Malloc()
>to allocate 64Kb and then only use the 32Kb which start in a 32Kb boundary,
>but this method is too wasteful. There's got to be a better way, isn't there?
>
Me no graphic-guru, but as far as I know the buffer has to be aligned on a
512 byte boundary, so Malloc() is wasting only up to 511 bytes.
Hope thats correct, i haven't tried it yet:-)

Jan-Hinrich

 ==============================================================================
 Jan-Hinrich Fessel        | EMail: jf@unido.uucp
 Computer Science Dpt.     |        jf@unido.bitnet
 University of Dortmund    |        jf@unido.irb.informatik.uni-dortmund.de
 PO Box 500500             |        ...!uunet!unido!jf
 D-4600 Dortmund           |
 W-Germany                 |
 ==============================================================================

greg@bilbo (Greg Wageman) (08/03/88)

In article <535@skywest.UUCP> brenes@skywest.UUCP (Erasmo Brenes) writes:
>Hello, this is a question to the ST graphic 'gurus':
>
>The problem that I have is that every time I call the XBIOS routine
>SetScreen(logadr,phyadr,rez), where phyadr = &NextScreen[0], the screen jumps 
>horizontally left to right. The information displayed on the screen is
>correct but is skewed to the right 3/4 of the screen (BTW, the program
>is written using MWC 2.x).

The documentation states that the display buffer must be aligned on a
256-byte boundry.  There is an example in the MWC manual that shows
how to do this.  I believe it is the example for Setscreen, but I do
not recall for certain.  Essentially, you must allocate a 32K-plus-
256-byte buffer, then round the screen base address up to the nearest
256-byte boundry, like this:

	long alt_screen;	/* Alternate screen address */
	long mem_block;		/* Place to keep original address of
				   buffer, in case we want to Free() it */

	/* Allocate memory for an alternate screen buffer */
	if ((mem_block = (long)Malloc((unsigned)0x8100)) == NULL) {

		/* Handle out-of-memory error here */
	}

	/* Round the address up past the next 256-byte boundry, then
	   zero the low-order 8 bits.  This guarantees that the
	   address is both within the block we allocated, and at the
	   proper alignment.  This can waste 256-bytes, worst case. */
	alt_screen = (mem_block + 0x100L) & (~0xFFL);

If the returned address from Malloc() was already properly aligned,
then the wasted 256 bytes will all be at the start of the block.  In all
other cases, the wasted space will be split between the beginning of
the block and the start of the screen, and the end of the screen and
the end of the block.  If you are that desparate for memory,

	alt_screen - mem_block

is the number of bytes wasted before the start of the screen and

	256 - (alt_screen - mem_block)

is the number of bytes wasted past the end of the screen.


Greg Wageman             	ARPA: greg%sentry@spar.slb.com
Schlumberger Technologies	BIX:  gwage
1601 Technology Drive     	CIS:  74016,352
San Jose, CA 95110        	GEnie: GWAGEMAN
(408) 437-5198            	UUCP: ...!decwrl!spar!sentry!greg
------------------
The opinions expressed herein are solely the responsibility of the
author.

leo@philmds.UUCP (Leo de Wit) (08/04/88)

In article <535@skywest.UUCP> brenes@skywest.UUCP (Erasmo Brenes) writes:
 [some lines deleted]...
|The problem that I have is that every time I call the XBIOS routine
|SetScreen(logadr,phyadr,rez), where phyadr = &NextScreen[0], the screen jumps 
|horizontally left to right. The information displayed on the screen is
|correct but is skewed to the right 3/4 of the screen (BTW, the program
|is written using MWC 2.x). What I've noticed is that the video buffer that
|the ST starts with is located in a 32K boundary, 0xf8000, while the starting
|location of NextScreen[] is not. It also seems that if a take &NextScreen[0]
|mod 32K, the remainder is the offset that I see on the screen. So, the
|question is: If the Shifter expects the video ram to start at 32K boundaries,
|then how do I get MWC, or any C program to allocate a 32Kb buffer starting in
|a 32Kb boundary in an efficient manner?  An initial thought was to use Malloc()
|to allocate 64Kb and then only use the 32Kb which start in a 32Kb boundary,
|but this method is too wasteful. There's got to be a better way, isn't there?

The shifter does not expect the video ram to start at 32K boundaries.
The restriction for the start address is that it has to be a 256 byte boundary.
The top byte of the long that contains the start address (the least
significant one, bits 0-7) is ignored, as is the low byte (the most
significant one, bits 24-31) of course because of 24 bit wide
addresses. top -1 goes to 0xffff8201, top -2 to 0xffff8203.

If you use Malloc():

    long memptr;
    extern long Malloc();

    memptr = (Malloc(32000 + 256) + 255) & ~255;

should do the trick (can fancy it by checking whether Malloc returns
out of memory, and/or by saving the return value for a possible
Mfree()). Note that a screen fits in 32000 bytes, that's less than
32K.  The overhead is the extra 256 bytes.
Adding 255 and dropping the lower 8 bits with & ~255 will ensure that
memptr will have a value between that returned by Malloc and 256 more
than that value, and that the LSB of it is 0.

|Any suggestions will be welcomed.  
| 
|Erasmo.

Hope this helped.

Leo.

wayneck@tekig5.PEN.TEK.COM (Wayne Knapp) (08/04/88)

In article <535@skywest.UUCP>, brenes@skywest.UUCP (Erasmo Brenes) writes:
> to allocate 64Kb and then only use the 32Kb which start in a 32Kb boundary,
> but this method is too wasteful. There's got to be a better way, isn't there?
> 

Actually, I think you need to allocate the screen on 512 byte boundry.  The
reason for this if the shifter is missing the lower nine bits of it's 
screen base pointer.  (It could be 8 bits and 256 byte boundry)  Anyway
try this.

    unsigned char  screen[32512]; 

    long  scrtemp;
    unsigned char *scrptr; 

    {
      ...
        scrtemp = (long) screen;
        scrtemp &= 0xfffe0000L;
        scrptr = (unsigned char *) scrtemp;
      ...
        Setscreen(scrptr,scrptr,0)  /* set screen to low resolution */
      ...
   } 

   Maybe not 100% correct but I sure it is closer to what you want.

                                      Wayne Knapp

neil@cs.hw.ac.uk (Neil Forsyth) (08/04/88)

In article <535@skywest.UUCP> brenes@skywest.UUCP (Erasmo Brenes) writes:

>The problem that I have is that every time I call the XBIOS routine
>SetScreen(logadr,phyadr,rez), where phyadr = &NextScreen[0], the screen jumps 
>horizontally left to right. The information displayed on the screen is
>correct but is skewed to the right 3/4 of the screen (BTW, the program
>is written using MWC 2.x). What I've noticed is that the video buffer that
>the ST starts with is located in a 32K boundary, 0xf8000, while the starting
>location of NextScreen[] is not. It also seems that if a take &NextScreen[0]
>mod 32K, the remainder is the offset that I see on the screen. So, the
>question is: If the Shifter expects the video ram to start at 32K boundaries,
>then how do I get MWC, or any C program to allocate a 32Kb buffer starting in
>a 32Kb boundary in an efficient manner?

The video RAM address must start on a 256 byte boundary. To be sure that your
buffer is on this boundary try this: (Forgive any lack of style)

	if ( (buffer=malloc(32256)) == NULL)	/* Get memory */
		{
		fprintf(stderr, "Not enough memory\n");	/* Or bust */
		exit(-1);
		}

	screen=(buffer+256) & 0xFFFFFF00L;	/* align on boundary by */
						/* by leaping 256 bytes */
						/* into buffer then     */
						/* clearing lowest bits */

If you want loads of screens you just malloc that many times 32000 and add 256
for allignment.

 _____________________________________________________________________________
/ "I think all right thinking people in this country are sick and tired of    \
! being told that ordinary decent people are fed up in this country with      !
! being sick and tired. I'm certainly not and I'm sick and tired of being     !
! told that I am!" - Monty Python                                             !
!                                                                             !
! Neil Forsyth                           JANET:  neil@uk.ac.hw.cs             !
! Dept. of Computer Science              ARPA:   neil@cs.hw.ac.uk             !
! Heriot-Watt University                 UUCP:   ..!ukc!cs.hw.ac.uk!neil      !
! Edinburgh                                                                   !
! Scotland                                                                    !
\_____________________________________________________________________________/

pes@ux63.bath.ac.uk (Smee) (08/04/88)

In article <535@skywest.UUCP> brenes@skywest.UUCP (Erasmo Brenes) writes:
>... If the Shifter expects the video ram to start at 32K boundaries,
>then how do I get MWC, or any C program to allocate a 32Kb buffer starting in
>a 32Kb boundary in an efficient manner?  An initial thought was to use Malloc()
>to allocate 64Kb and then only use the 32Kb which start in a 32Kb boundary,
>but this method is too wasteful. There's got to be a better way, isn't there?

You've got the concept right, but not the detail.  The video buffer must
start at a location which is 0 mod 256 (or is it 512, and I'm wrong again?
anyway, doesn't matter, fits into 32K regardless).  The video buffer is
32000 (exactly, decimal) bytes long.  So, allocate 32K (32768 decimal) and
then start your buffer at the first location therein which is 0 mod 256.
Tiny bit of waste, but...

alderaan@netmbx.UUCP (Thomas Cervera) (08/05/88)

In article <529@laura.UUCP>, jf@laura.UUCP (Jan Hinrich Fessel) writes:

> In article <535@skywest.UUCP> brenes@skywest.UUCP (Erasmo Brenes) writes:
> >Hello, this is a question to the ST graphic 'gurus':
> >question is: If the Shifter expects the video ram to start at 32K boundaries,
> >then how do I get MWC, or any C program to allocate a 32Kb buffer starting in
> >a 32Kb boundary in an efficient manner?  An initial thought was to use Malloc()
> >to allocate 64Kb and then only use the 32Kb which start in a 32Kb boundary,
> >but this method is too wasteful. There's got to be a better way, isn't there?
> >

> Me no graphic-guru, but as far as I know the buffer has to be aligned on a
> 512 byte boundary, so Malloc() is wasting only up to 511 bytes.
> Hope thats correct, i haven't tried it yet:-)
> 

Not quite right. As I know, (would be more logical) the video bitmap graphics
array must start at a page (256b) boundary. So, substract #256 from all values
given by Jan-Hinrich and it will be ok, I guess ...

  With my best wishes for your success -- alderaan.


--

alderaan
OP RKOpdp (RSTS/E)
FB Mathematik/Informatik
RKO Berlin

Dieffenbachstrasze 60-61
1000 Berlin 61

jpdres13@usl-pc.usl.edu (John Joubert) (08/26/88)

In article <535@skywest.UUCP> brenes@skywest.UUCP (Erasmo Brenes) writes:
>... If the Shifter expects the video ram to start at 32K boundaries,
>then how do I get MWC, or any C program to allocate a 32Kb buffer starting in
>a 32Kb boundary in an efficient manner? An initial thought was to use Malloc()
>to allocate 64Kb and then only use the 32Kb which start in a 32Kb boundary,
>but this method is too wasteful. There's got to be a better way, isn't there?

--------------------------

Here is how I find a 256 byte boundary to put in a screen.  


   char *blk;                               /* Pointer to the start of */
                                            /* malloc'ed block.        */
   char *work_scr;                          /* New screen desired.     */
   char *desktop_scr;                       /* Old screen pointer.     */

   desktop_scr = (char *)Physbase();	    /* Save old screen pointer.*/

                                            /* Find a screen pointer   */
                                            /* On a 256 byte boundary. */
    work_scr=(char *)( (long)(blk=malloc(32768L)) & 0xffffff00 )+0x0100;

    Setscreen(work_scr,work_scr,-1);        /* Flip in work screen.    */


The "blk" pointer will give you a pointer to the beginning of the actual
block of mem that was malloc'ed, use this at the end of the program to
"free" up the memory.

The "work_scr" gives you the pointer to the new screen that you want to fill
with data.

The "desktop_scr" gives you the pointer to your old desktop.  If you want a 
graceful exit back to the desktop at the end of your program, make sure
to make this the current screen with the Setscreen() command right before
you exit.

The next line of code is not  mine,  I got it here off the net a while
back.  I don't know who wrote it in it's original state, but it works fine.  
It will place your pointer on a 256 byte boundary in your malloc'ed block.
I have not really taken the time to see how exactly it works, I just know that
it does.  I was going to write my own ... when the very same day I saw this 
thing.  I plugged it in and it worked!  Not one to re-invent the wheel, 
I hardly ever glanced at it again, all that I ever did to it was add in the 
"blk=" assignment.

The last line of code of course, sets the screen to the new work area.


Hope this helps,
----------------------------------------------------------------------------
John Joubert                         |     /\  |    /\    |     _ 
jpdres13@usl-pc.USL   or ...         |     \|<>|>|> \|<>|>|><`|`|
ut-sally!usl!usl-pc!jpdres13         |-----/|-------/|----------------------
GEnie: J.JOUBERT                     |     \/       \/
-----------------------------------------------------------------------------

uace0@uhnix2.uh.edu (Michael B. Vederman) (08/28/88)

In article <12@usl-pc.usl.edu> jpdres13@usl-pc.UUCP (John Joubert) writes:
>In article <535@skywest.UUCP> brenes@skywest.UUCP (Erasmo Brenes) writes:
>>... If the Shifter expects the video ram to start at 32K boundaries,
>>then how do I get MWC, or any C program to allocate a 32Kb buffer starting in
>>a 32Kb boundary in an efficient manner? An initial thought was to use Malloc()
>>to allocate 64Kb and then only use the 32Kb which start in a 32Kb boundary,
>>but this method is too wasteful. There's got to be a better way, isn't there?
>
>--------------------------
[deleted
 lines of
 text]
>
>Here is how I find a 256 byte boundary to put in a screen.  
>
[ deleted
  lines of
  'C' code ]
>                                            /* On a 256 byte boundary. */
>    work_scr=(char *)( (long)(blk=malloc(32768L)) & 0xffffff00 )+0x0100;
>
[ More deleted stuff ]
>Hope this helps,
>----------------------------------------------------------------------------
>John Joubert                         |     /\  |    /\    |     _ 
>jpdres13@usl-pc.USL   or ...         |     \|<>|>|> \|<>|>|><`|`|
>ut-sally!usl!usl-pc!jpdres13         |-----/|-------/|----------------------
>GEnie: J.JOUBERT                     |     \/       \/
>-----------------------------------------------------------------------------

Dear John,


There is really one little problem with the code you have written, that being if
the block you Malloc is just one byte past a 256 byte boundary, then you will
be wasting 255 bytes, therefore you will need to Malloc at least (32K+255) to
insure that you have at least enough memory to draw a full screen in.  Other-
wise you will be overwriting memory which is not yours (a discussion of which

there has been an abundance of these days :-).

- Mike




-- 
for (;;)                              : Use ATARINET, send an interactive
        do_it(c_programmers);         : message such as:
                                      : Tell UH-INFO at UHUPVM1 ATARINET HELP
University Atari Computer Enthusiasts : University of Houston UACE

leo@philmds.UUCP (Leo de Wit) (08/28/88)

In article <657@uhnix2.uh.edu> uace0@uhnix2.UUCP writes:
>In article <12@usl-pc.usl.edu> jpdres13@usl-pc.UUCP (John Joubert) writes:
   [lines deleted]...
>>                                            /* On a 256 byte boundary. */
>>    work_scr=(char *)( (long)(blk=malloc(32768L)) & 0xffffff00 )+0x0100;
   [lines deleted]...
>Dear John,
>
>
>There is really one little problem with the code you have written, that being if
>the block you Malloc is just one byte past a 256 byte boundary, then you will
>be wasting 255 bytes, therefore you will need to Malloc at least (32K+255) to
>insure that you have at least enough memory to draw a full screen in.  Other-
>wise you will be overwriting memory which is not yours (a discussion of which
>there has been an abundance of these days :-).

I thought we had all this Video Ram discussion in various flavours a
few months ago (maybe you lucky people have vacations that long 8-).
Alignment on a 256 byte boundary automatically implies there is a
worst-case waste of 255 bytes. You cannot avoid that. John's code is
correct however (maybe not intentionally), since a screenful amounts to
32000 bytes, not 32K. So a Malloc of 32256 is in fact satisfactory, and
hence certainly John's 32768.

B.T.W. What I've seen from the initialization of the screen memory seems
to imply that the start of the physical screen is always taken to be
physical RAMtop minus 32K. So there's always a waste of 768 bytes at the
top of RAM. To be used whatfor? A program? Some data? Any suggestions?

                         Leo.

) (08/29/88)

>B.T.W. What I've seen from the initialization of the screen memory seems
>to imply that the start of the physical screen is always taken to be
>physical RAMtop minus 32K. So there's always a waste of 768 bytes at the
>top of RAM. To be used whatfor? A program? Some data? Any suggestions?
>
>                         Leo.


A certain resident RAMdisk makes use of that area (and maybe some bothersome
virusses as well.)

apratt@atari.UUCP (Allan Pratt) (08/30/88)

In article <657@uhnix2.uh.edu> uace0@uhnix2.UUCP writes:
> In article <12@usl-pc.usl.edu> jpdres13@usl-pc.UUCP (John Joubert) writes:
> > In article <535@skywest.UUCP> brenes@skywest.UUCP (Erasmo Brenes) writes:
> > >... If the Shifter expects the video ram to start at 32K boundaries,
> >
> > [Code sample for getting a screen block]
> 
> There is really one little problem with the code you have written, that being if
> the block you Malloc is just one byte past a 256 byte boundary, then you will
> be wasting 255 bytes, therefore you will need to Malloc at least (32K+255) to
> insure that you have at least enough memory to draw a full screen in.

The continuing misunderstanding here is that people think the screen
takes up 32K bytes, and (in Erasmo Brenes' case) that the screen memory
must start on a 32K boundary.  The screen takes up 32000 bytes, not 32K
(which is 32768 bytes), and needs to start on a 256-byte boundary.  The
upshot of this is that you only need to allocate 32256 bytes to be sure
that there is a 32000-byte block on a 256-byte boundary in there
somewhere.  Since John Joubert's code allocated 32768 bytes, it worked
fine. 

I appreciate this discussion because it shows that people care about
doing The Right Thing about allocating memory.  The Wrong Thing which
some people do is assume that consecutive Malloc calls allocate
contiguous memory.  This is accidentally and unfortunately true in
current ROMs, and part of what I had to keep doing because people came
to rely on it, but it is not correct to assume it will go on being that
way. 

Moreover, you have to watch out for future Atari video modes which use
more than 32000 bytes for a screen, and/or have different (probably more
relaxed) restrictions on the screen-memory base address. 

============================================
Opinions expressed above do not necessarily	-- Allan Pratt, Atari Corp.
reflect those of Atari Corp. or anyone else.	  ...ames!atari!apratt

gaz@apollo.COM (Gary Zaidenweber) (08/31/88)

From article <657@uhnix2.uh.edu>, by uace0@uhnix2.uh.edu (Michael B. Vederman):
> 
> Dear John,
(I love "dear John" letters :-) )
> 
> There is really one little problem with the code you have written, that being if
> the block you Malloc is just one byte past a 256 byte boundary, then you will
> be wasting 255 bytes, therefore you will need to Malloc at least (32K+255) to
> insure that you have at least enough memory to draw a full screen in.  Other-
> wise you will be overwriting memory which is not yours (a discussion of which
> 
> there has been an abundance of these days :-).
> 
> - Mike

Actually, the screen memory takes up 32000, not 32768 bytes (I got that from
a previous discussion.) Therefore, if you can malloc() 32K (32768) bytes, and
waste N bytes at the beginning, you have 768-N bytes of "padding" at the end
before you have to worry about touching memory which you don't own. Easy to
make this mistake (lucky motorola didn't call the processor the M69632, huh?)
-- 
    UUCP:   ...{umix,mit-eddie,uw-beaver}!apollo!gaz
    ARPA:   gaz@apollo.COM
    AT&T:   (508)256-6600 x6081
    Its never too late to have a happy childhood!