home *** CD-ROM | disk | FTP | other *** search
/ Vectronix 2 / VECTRONIX2.iso / FILES_03 / JAG_DOX.ZIP / op.txt < prev    next >
Text File  |  1996-01-28  |  23KB  |  617 lines

  1. # -------------------------------------------------------------------
  2. # OBJECTPROCESSOR                  (c) Copyright 1995-1996 Nat! & KKP
  3. # -------------------------------------------------------------------
  4. # These are some of the results/guesses that Klaus and Nat! found
  5. # out about the Jaguar. Since we are not under NDA or anything from
  6. # Atari we feel free to give this to you for educational purposes
  7. # only.
  8. #
  9. # Please note, that this is not official documentation from Atari
  10. # or derived work thereof (both of us have never seen the Atari docs)
  11. # and Atari isn't connected with this in any way.
  12. #
  13. # Please use this informationphile as a starting point for your own
  14. # exploration and not as a reference. If you find anything innacurate,
  15. # missing, needing more explanation etc. by all means please write
  16. # to us:
  17. #    nat@zumdick.rhein-main.de
  18. # or
  19. #    kkp@gamma.dou.dk
  20. #
  21. # If you could do us a small favor, don't use this information for
  22. # those lame flamewars on r.g.v.a or the mailing list.
  23. #
  24. # HTML soon ?
  25. # -------------------------------------------------------------------
  26. # $Id: op.txt,v 1.10 1996/01/28 20:23:20 nat Exp $
  27. #
  28. # If there are two theories I put the more likely one first.
  29. # -------------------------------------------------------------------
  30. Things to know about the Objectprocessor (OP):
  31.  
  32. -1 Imagine a phrase being an entity of 64 bits (or 8 bytes for that
  33.    matter).
  34.  
  35. 0. The object list is a linked list.
  36.  
  37. 1. The object list is traversed by the object processor for
  38.    each! scanline.
  39.  
  40. 2. The Objectprocessor probably works like this:
  41.  
  42.    Whenever a new scanline needs to be displayed, the
  43.    objectprocessor provides a linebuffer to the videosystem. While
  44.    the videosystem is busy displaying this, the OP readies the next
  45.    scanline. (It uses a doublebuffering strategy) It does
  46.    this by traversing the objectlist and interpreting each
  47.    object in sequence. Each object has per scanline the chance
  48.    ONCE to fill the linebuffer. It fills the linebuffer at
  49.    a specified horizontal position for a specified width. The data
  50.    in the linebuffer is always overwritten (except when the
  51.    Read-Modify-Write bit is set). If the active object has the
  52.    transparent bit set, it will not overwrite values in the
  53.    linebuffer when its source pixel has the value zero.
  54.    The 'transparency' check is done before looking up the pixel's
  55.    color in the CLUT (1 - 256 color modes).
  56.  
  57. 2.1   The sooner a object appears in the list the more
  58.    in the background it appears. The linebuffer is initalized with
  59.    the linebufferbackgroundcolor (BG) before the objectprocessor
  60.    starts filling the linebuffer.
  61.  
  62.    One may also assume that the OP normally traverses the
  63.    linebuffer from left to right, except when the horizontal flip
  64.    bit is set. (Very useful information indeed! (har) )
  65.  
  66.    Each bitmap object is made up of pixels. These pixels can be either
  67.    contain the color itself (direct) as in CrY and TrueColor modes
  68.    or be an index into a Colorlookuptable (indirect).
  69.  
  70. 2.2   We assume that the OP writes into the linebuffer locally, so that
  71.    the objectdata is read over the bus, but not written into the
  72.    linebuffer over the bus (which would be way evil)
  73.  
  74. 2.3.  The videosystem can deal with 16bit RGB/Crycolor and 24bit RGB
  75.    pixels, the size of the pixels the OP writes into the linebuffer
  76.    and pulls out of the CLUT, depends on the pixeltype chosen for
  77.    the videosystem.
  78.  
  79. 2.4   The object in the objectlist are *modified* by the OP. This means
  80.    that an object list is only good for one frame. You need to
  81.    continually refresh your object list each VBLANK.
  82.  
  83. 3.  ...
  84. 4.  ...
  85.  
  86. 5. The last object must be a STOP object.
  87.  
  88. 6. The Objectlist must be doublephrase aligned. This means
  89.    that the lower nybble of the address must be zero.
  90.  
  91. 7. The address of the image of an object must be (as expected)
  92.    phrase aligned (zero in the lower 3 bits)
  93.  
  94. 8. There are five different objects that the Objectprocessor knows
  95.    about. These are:
  96.  
  97.    1. Bitmapped Object
  98.    2. Scaled bitmapped object
  99.    3. GPU-Object (Calls the GPU to do the displaying ?? )
  100.    4. Branchobject
  101.    5. Stopobject (marks the end of the object list)
  102.  
  103.    The objects have different sizes. The minimum size of an object
  104.    is a "phrase".
  105.  
  106.    Object type    Number     Size in phrases
  107.    -----------------------------------------
  108.    BIMAP          0           2
  109.    SCALE          1           3 (4?)
  110.    GPU            2           1
  111.    BRANCH         3           1
  112.    STOP           4           1
  113.  
  114.    It looks like you need to pad your scale objects to four phrases...
  115.  
  116. 9  To keep the Objectprocessor from fetching data (and wasting bandwidth)
  117.    during the VBLANK you usually put two branch objects at the beginning
  118.    of the display list, that branch to the stop object if the first
  119.    displayable scanline has not been reached or the last displayable
  120.    scanline has already been displayed.
  121.  
  122. 10.   Just reading concurrently from the linebuffers while the OP is
  123.    displaying data produces glitches. Advice: Stay out of them!
  124.  
  125. :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
  126. 10             This is what a branch object looks like:
  127. :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
  128.  
  129. Phrase #0:
  130.  
  131.    63      56        48       40       32        24       16       8    3   0
  132.   +--------^---------^-----+---^--------^--------+--------+--+-----^----+---+
  133.   |        unused          |      Link-address   | unknown|CC|   VCnt   |011|
  134.   +------------------------+---------------------+--------+--+----------+---+
  135.       63 .............43      42..........24      23...16 15.14 13 .... 3
  136.  
  137.  
  138.    The branch objects are used to compare the current scanline
  139.    with the value stored in the branch object. Depending on the
  140.    branch instructions comparison mode, the branch is taken
  141.    either on < == != or >. The taken branch taken uses the information
  142.    from the Linkinfo and branches to the phraseindexed
  143.    object. If the comparison fails it simply examines and handles
  144.    the next object in the list.
  145.  
  146.  
  147. VCnt:    This is the value you compare the vertical scanline
  148. counter with (VC). For CC code 10 the operation goes:
  149.  
  150.    if( object->YCnt < VC)
  151.       goto object->link;
  152.  
  153.  
  154. Conditioncodes:
  155.  
  156.         Values     Comparison/Branch
  157.    ------------------------------------------------
  158.       000   Branch on equal            (VCnt==VC)
  159.       001   Branch on less than        (VCnt>VC)
  160.       010   Branch on greater than     (VCnt<VC)
  161.       011   Branch if OP flag is set
  162.  
  163. Note that 000 is a branch always if VCnt == $7FF (very strange!)
  164.  
  165.  
  166. :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
  167. 11                This is what a stop object looks like:
  168. :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
  169.  
  170. Phrase #0 (1 of 1):
  171.  
  172.  63       56        48        40       32        24       16       8    3   0
  173.   +--------^---------^---------^--------^--------^--------^--------^----+---+
  174.   |                                 datafield                           |100|
  175.   +---------------------------------------------------------------------+---+
  176.  
  177.  There is a datafield in this instruction of unkown size. This may or
  178.  may not be a way to generate horizontal interrupts. Maybe this is just
  179.  a flag that someone can poll from somewhere...
  180.  
  181.  
  182. :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
  183. 12.               This is what a bitmap object looks like:
  184. :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
  185. Phrase #0 (1 of 2):
  186.  
  187.  63       56        48        40       32        24       16       8    3   0
  188.   +--------^---------^-----+------------^--------+--------^--+-----^----+---+
  189.   |        data-address    |     Link-address    |   Height  |   YPos   |000|
  190.   +------------------------+---------------------+-----------+----------+---+
  191.       63 .............43         42..........24   23 ..... 14 13 ..... 3 2.0
  192.         21 bits           19 bits        10 bits     11 bits  3 bits
  193.  
  194.  
  195.   data-address:   Pointer to the bitmap      ***DESTROYED BY THE OP***
  196.   link-address:   Pointer to the next object
  197.   height:         Height in pixels
  198.   y-pos:          Vertical position          ***DESTROYED BY THE OP***
  199.   type:           Object type
  200.  
  201.  
  202. data-address:
  203.    An address is a memory address in terms of phrases. To get the
  204.    byte address you have to shift it up by 3. (or in this example
  205.    to get the data-address you would fetch the upper lword with
  206.    the 68K and do):
  207.  
  208.       move.l   (a0),d0     ; fetch it  (bits 63-32)
  209.       moveq #11,d1         ; or some other less lame way
  210.       lsr.l d1,d0          ; shift it down for phrase address
  211.       lsl.l d1,d0          ; shift it up for byte address
  212.  
  213. link-address:
  214.    The link address strings the object list together. So it really
  215.    is a linked list, not just an array. OK an array would have
  216.    been better and the link could have been a number of phrases
  217.    to skip. It misses the upper two bits two form a proper full
  218.    24 bit address. This means that objects must reside in the
  219.    lower 4 MB.
  220.  
  221. height:
  222.    The height of the object is also stored in the first phrase.
  223.    This is the number of pixels an object has in it vertical extent.
  224.  
  225. ypos:
  226.    The YPos is predictably the vertical position of the object on
  227.    the screen. The vertical position is the halfline vertical
  228.    position.
  229.  
  230.  Theory 1:
  231.    Like on the Falcon the screen is divided into two horizonzal
  232.    halflines. Except for really wide screens in excess of 1024
  233.    pixels horizontally, you always stay in the first halfline.
  234.    (That's why its eleven bits, and the height is only 10 bits.)
  235.    A problem with this theory is, that the Xpos field is 12 bits
  236.    anyway...
  237.  
  238.  Theory 2:
  239.    This means that in interlace mode this is the "true"
  240.    vertical position on the screen. In non-interlaced modes
  241.    (non-flicker)  modes, you should multiply your Y-Pos by two and
  242.    stuff that into the object.
  243.    (That's why its eleven bits, and the height is only 10 bits.)
  244.  
  245. type:
  246.    Lastly the object type indicates with a 0 (000) that this object
  247.    is a normal non-scaled bitmap object.
  248.  
  249.  
  250. Phrase #1 (2 of 2):
  251.  
  252.    63      56        48       40       32        24       16       8       0
  253.   +--------+---------+------+--^--+-----^---+----^----+---+---+----^--------+
  254.   | unused | 1stpix  |flags | idx | iwidth  | dwidth  | p | d |    <XPos>   |
  255.   +--------+---------+------+-----+---------+---------+---+---+-------------+
  256.     63...55 54....49  48..45 44.38  37...28    27..18 17.15 14.12   11.....0
  257.                6bit  4bit  7bit   10bit   10bit  3bit  3bit     12bit
  258.  
  259.    Curiously there seem to be some unused bits in the top half of
  260.    this second phrase. Anyway starting from the left:
  261.  
  262.    firstpix:   Pixels to skip
  263.    flags:      How to handle the source data
  264.    index:      Index into the CLUT
  265.    iwidth:     Width of the image
  266.    dwidth:     Offset to the next line of the image
  267.    pitch:      Increment for the Datapointer
  268.    depth:      Pixeldepth of the bitmap
  269.    x-pos:      Horizontal position of the object
  270.  
  271.  
  272. 1stpix: this is a field of 6 bits that contains the number of
  273.    'bits' to skip before fetching the first pixel. This must be
  274.    used whenever your bitmap data isn't phrase aligned.
  275.    Maybe most often used for CLUT modes.
  276.    You get the value you want to write here by calculating:
  277.  
  278.    pixelindex * bits_per_pixel (f.e. 8 for 256 color mode)
  279.  
  280.  
  281. flags:   You can tell the Objectprocessor the way it should
  282.    handle the display data. These are the values you set here:
  283.  
  284.    Bit0        Bit1        Bit2        Bit3
  285.     --------------------------------------------------------------
  286.      Horizontal Flip   ReadWriteModify   Transparent   Release
  287.  
  288. A few guesses as to what each flag does:
  289.  
  290. Horizonal flip:      Lets the Objectprocessor run
  291.    its path from the other end of the spritedata, which should
  292.    effectively flip you sprite data.
  293.  
  294. ReadWriteModify:  The object processor reads the the pixel from the
  295.    line buffer does something with the bitmap pixel value
  296.    and the linebuffer pixel value and stores the result back into
  297.    the linebuffer.
  298.  
  299.    Theory 1. For Crycolor the lower byte of the bitmap pixel value
  300.    is sign extended and added to the lower byte of the linebuffer pixel
  301.    value, thereby increasing or decreasing (depending on the sign)
  302.    the intensity of the linebuffer pixel. This is a 'saturating add'
  303.    meaning that you don't wrap around, but subtractions stick at 0 and
  304.    additions stick at 255.
  305.    The cryhues (upper byte) are mangled even more strangely, the effect
  306.    could (with the right values) be like looking through a colored
  307.    glass (your bitmap object with the RMW-flag set) onto the
  308.    background (the other bitmap objects below it)
  309.    This might be similiar to what happens when gouraudshading. Refer
  310.    to the blitter docs.
  311.  
  312.    Theory 2. Both values are simply added together
  313.  
  314.  
  315. Transparent:      When the source pixel is zero, this
  316.    pixel will not be written. This is the way to achieve
  317.    transparent sprites with the GPU. (Both CLUT and non-CLUT pixels)
  318.  
  319. Release:    If cleared then the OP 'hogs' the bus for
  320.    the time it takes to fetch the scanline data of the object. If this
  321.    bit is set, then the bustime is shared with other processors. If you
  322.    have lotsa interrupts going, this might be worthwhile.
  323.  
  324. index (idx):   Index into the ColorLookUpTable (CLUT)
  325.    This information is only used for 1 - 2 or 4 bitplane objects,
  326.    to determine the offset in the CLUT to use.
  327.  
  328.    1 bitplane           2 bitplane       4 bitplane
  329.    -------------------------------------------------------
  330.         iiiiiiii          iiiiii0         iiiii00
  331.  
  332.    The value is shifted left once and then used as an index into
  333.    the CLUT. Note that in 2 + 4 bitplane modes not all bits are in
  334.    used, because the lower bits are replaced with the pixel value.
  335.  
  336.    For example in 4-bits-per-pixel mode pixel #7 and an idx value of
  337.    64 gives you an index of (64*2)+7 -> 135
  338.  
  339.    So you preload the CLUT with the colors you want to use, for
  340.    example green at index #241. When you want to display a small
  341.    green arrow on the screen (as a pointer) for example you set
  342.    your object to transparent, and the index to 120. When the
  343.    object pointer fetches a set pixel, it will write the green
  344.    value into the linebuffer.
  345.  
  346. iwidth:     Tell the OP how many *phrases* to draw in each
  347.    line. This is the actual number of phrases to draw, not the
  348.    horizontal index to index the next line (dwidth). This is
  349.    probably not just  #pixels_to_draw / bits_per_pixel, but rather
  350.    the number of phrases the object spans. If a 32bit object spans
  351.    two phrases you should enter a two here.
  352.  
  353. dwidth:     The horizontal phrase offset the OP should use
  354.    to index to the next line. If you data is laid out in
  355.    consecutive strips of horizontal data like this:
  356.  
  357. screen <destination>:
  358.    00000000000
  359.    11111111111
  360.    22222222222
  361.    33333333333
  362.  
  363. memory <source>:
  364.    00000000000111111111112222222222233333333333
  365.  
  366.    then this will be just the same as <iwidth>. But if your data
  367.    is laid out like this:
  368.  
  369.    00000000000xxxxx11111111111xxxxx22222222222xxxxx33333333333xxxxx
  370.  
  371.    you should set <dwidth> to the proper offset so that adding
  372.    <dwidth> to the phrase-address will bring you to the next line.
  373.    (This might be useful for 'horizontally scrolling' objects).
  374.  
  375. pitch (p):  If you so desire you can organize your bitmap
  376.    data in even stranger ways than one would think possible. With
  377.    this value you control the datapointer that the OP uses to
  378.    traverse your bitmap data. This value is added to the
  379.    datapointer after the last fetch. If you use a 0 you will be
  380.    always fetching the same phrase over and over again. Normally
  381.    you set <pitch> to 1, to advance through memory contigously.
  382.  
  383. depth (d):  The number of bits of each pixel. This
  384.    specifies the rez of the object. You have the choice between
  385.    direct pixel modes (16 or 24/32 bits) and indirect (CLUT)
  386.    pixel modes. Note that using transparency effectively
  387.    reduces the number of available colors by one (color #0).
  388.  
  389.    Values:
  390.  
  391.    0  1 bits per pixel  2 colors       CLUT
  392.    1  2 bits per pixel  4 colors       CLUT
  393.    2  4 bits per pixel  16 colors      CLUT
  394.    3  8 bits per pixel  256 colors     CLUT
  395.    4  16 bits per pixel 65536 colors   CRY
  396.    5  24 bits per pixel 16 Mio Colors  TrueColor
  397.    6  unused
  398.    7  unused
  399.  
  400. xpos:    The horizontal position of the object on the
  401.    screen (or in the linebuffer if you will)
  402.  
  403.  
  404.  
  405. :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
  406. 13.            This is what a scaled bitmap object looks like.
  407. :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
  408.  
  409. Phrase #0 (1 of 3):
  410.  
  411.  63       56        48        40       32       24       16        8    3   0
  412.   +--------^---------^-----+---^--------^--------+--------^--+-----^----+---+
  413.   |       <data-address>   |    <Link-address>   | < Height >|  <YPos>  |001|
  414.   +------------------------+---------------------+-----------+----------+---+
  415.       63 .............43         42..........24   23 ..... 14 13 ..... 3 2.0
  416.         21 bits           19 bits        10 bits     11 bits  3 bits
  417.  
  418.    Except for the type, which is different, this is just
  419.    the same as the first phrase of the bitmap (non-scaled)
  420.    object.
  421.  
  422.  
  423. Phrase #1 (2 of 3):  This is the same as the the 'bitmapped' object
  424.  
  425.  
  426. Phrase #2 (3 of 3):
  427.  
  428.    63      56        48       40       32        24       16       8       0
  429.   +--------^---------^---------^--------^--------+--------+--------+--------+
  430.   |                  unused                      | remain | VScale | HScale |
  431.   +----------------------------------------------+--------+--------+--------+
  432.                                                    23...16  15...8   7...0
  433.  
  434.   remainder:   Keeps the VScale remainder ***DESTROYED BY THE OP***
  435.   v-scale:     Vertical scaling factor
  436.   h-scale:     Horizontal scaling factor
  437.  
  438.  
  439.   The scale is a fractional representation, using 3 bits for the integer
  440.   part and 5 bits for the fractional part. Or in ASCII-Graphics:
  441.  
  442.    76543210 00100000 or 0x20 is 1.0
  443.    iiifffff 00010000 or 0x10 is 0.5
  444.  
  445.   The remainder is used by the objectprocessor for the vertical scaling,
  446.   as a memory place. You should initialize it to 0.5 for best results,
  447.   although in a lot of democode its initialized to 1.0.
  448.  
  449.  
  450. :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
  451. 14.                     The elusive GPU-object
  452. :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
  453.  
  454. Phrase #0 (1 of 1):
  455.  
  456.  63       56        48        40       32       24       16        8    3   0
  457.   +--------^---------^---------^--------^--------^--------^--------^----+---+
  458.   |                           datafield                                 |010|
  459.   +---------------------------------------------------------------------+---+
  460.  
  461.    The GPU object gets an interrupt, it is believed that the OP is not
  462.    halted because of this action. You might want to stuff some information
  463.    into the datafield, which the GPU could then read from the OLP registers.
  464.    But what for ?
  465.  
  466.  
  467. :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
  468. 15 You can also look at the object in terms of C-structs, that's how
  469.    they'd look like.
  470. :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
  471.  
  472. /* DON'T USE THESE BITFIELDS WITH ANYTHING ELSE THAN A
  473.    ***GOOD*** C-COMPILER AND A MOTOROLA PROCESSOR
  474. */
  475.  
  476.  
  477.    #define byte   unsigned char
  478.    #define word   unsigned short
  479.    #define lword  unsigned long
  480.    #define phrase unsigned long long
  481.  
  482.  
  483.    typedef struct
  484.    {
  485.        lword   data:21;
  486.        lword   link:19;
  487.        word height:10;
  488.        word ypos:11;
  489.        word type:3;
  490.    } bitmap_obj_phrase_0;
  491.  
  492.  
  493.    typedef struct
  494.    {
  495.       word  unused:9;
  496.       word  firstpix:6;
  497.       word  flags:4;
  498.       word  index:7;
  499.       word  iwidth:10;
  500.       word  dwith:10;
  501.       word  pitch:3;
  502.       word  depth:3;
  503.       word  x_pos:12;
  504.    } bitmap_obj_phrase_1;
  505.  
  506.  
  507.    typedef struct
  508.    {
  509.       lword   unused:24;
  510.       word    remainder:8;
  511.       word    v_scale:8;
  512.       word    h_scale:8;
  513.    } scale_obj_phrase_2;
  514.  
  515.  
  516.    typedef struct
  517.    {
  518.        lword   unused:21;
  519.        lword   link:19;
  520.        word    conditioncode:2;
  521.        word    unused:8;   ;; maybe index to register ?
  522.        word    ypos:11;
  523.        word    type:3;
  524.    } branch_obj_phrase_0;
  525.  
  526.  
  527.    typedef struct
  528.    {
  529.        phrase  unused:61;
  530.        word type:3;
  531.    } stop_obj_phrase_0;
  532.  
  533.    typedef struct
  534.    {
  535.        phrase  unknown:61;
  536.        word type:3;
  537.    } gpu_obj_phrase_0;
  538.  
  539.  
  540.    typedef struct
  541.    {
  542.       stop_obj_phrase_0 p0;
  543.    } stop_obj;
  544.  
  545.  
  546.    typedef struct
  547.    {
  548.       branch_obj_phrase_0  p0;
  549.    } branch_obj;
  550.  
  551.  
  552.    typedef struct
  553.    {
  554.       gpu_obj_phrase_0  p0;
  555.    } gpu_obj;
  556.  
  557.  
  558.    typedef struct
  559.    {
  560.       bitmap_obj_phrase_0  p0;
  561.       bitmap_obj_phrase_1  p1;
  562.    } bitmap_obj;
  563.  
  564.  
  565.    typedef struct
  566.    {
  567.       bitmap_obj_phrase_0  p0;
  568.       bitmap_obj_phrase_1  p1;
  569.       scale_obj_phrase_2   p2;
  570.       /* need one padding phrase ? */
  571.    } scale_obj;
  572.  
  573.  
  574.  
  575.  
  576. SMALL DISCUSSION:
  577.    Since the object processor walks the object list for each
  578.    scanline, you should consider the following:
  579.  
  580.    If you have 64 bitmaps objects in your object list and a
  581.    vertical rez of 240 lines going and a refreshrate of 60Hz
  582.    the Objectprozessor is pulling
  583.  
  584.    60 hz * 240 lines * 64 objects * 2 phrases =  1.8 Mio phrases/s
  585.    ~ 14.7 Mio bytes/s  for the object processor list alone!
  586.       (ca. 14% of the systems bandwidth)
  587.  
  588.  
  589.    If you figure you're using 128x128x16bit sprites fully visible,
  590.    you're doing:
  591.  
  592.    128x128*16bits/64bits = 4096 phrases a sprite
  593.    64 sprites in 60hz    = 3840 sprites
  594.    yields 15728640 phrases/s or 120 Mbytes/s
  595.  
  596.    So it is fairly easy to unknowingly saturate the bus with
  597.    a nice object list...
  598.    It should be obvious that non-"truecolor" sprites still make
  599.    lotsa sense, when you're using the OP heavily.
  600.  
  601.    It would have been better in our opinion, if Atari had used a
  602.    small 2-Kbit hitbuffer (or single bit Z-Buffer) and reversed
  603.    the object order, so that the nearest object comes first and
  604.    the background last in the object list.
  605.  
  606.    With such a slightly more complicated scheme,the OP could
  607.    run at a rather constant:
  608.  
  609.       hrez * vrez * refresh * average_bits_per_pixel
  610.       ---------------------------------------------- phrases/s
  611.                64
  612.  
  613.  
  614. NEEDED STUFF:
  615.    Need to document the logic setting up objects, that cross
  616.    boundaries (especially the scaled bitmaps)
  617.