Jump to content



0

HoleyDMA & Atari 7800


15 replies to this topic

#1 Heaven/TQA ONLINE  

Heaven/TQA

    Quadrunner

  • 8,109 posts
  • Location:Baden-Württemberg, Germany

Posted Thu Jan 15, 2004 4:11 AM

finally i have realised how this mode works... unfortunatly MARIA description & programming docs aren't so large as I wish. thanks to Dan's vertical sprite movement example (without any comments... :() i figured out how this works...

most of you know that the 7800 architecture is different to 2600,5200, Lynx and 800... and is more like on older arcade games... and works with "zones" & object lists for scanlines...

quote from the atari 7800 dev guide:

"The group of rasters specified by one DLL entry is called a
"zone." Again, the number of rasters in a zone equals OFFSET+1.
Larger zones mean less RAM is needed for DLLs, Display Lists and
Character Maps (see DMA MODES below). But upon consideration of
how to use zones, you will realize that to achieve smooth
vertical motion each stamp must be padded at top and bottom with
zeros. For example, if the top raster of an object is to appear
on the last line of a 16 high zone, it must have 15 lines of
zeros above it. If that object is 8 pixels (2 bytes) wide, and
its top line of data is located at x'CF04', then you
will need two bytes of zeros at x'D004', x'D104', x'D304',...,
and x'DE04' (remember that OFFSET decrements). As this can add
up to many pages of zeros, you can specify that MARIA should
interpret certain data as zeros, even if it isn't. This is
called "Holey DMA" because DMA will see "holes" in the data that
aren't really there. This can be enabled and disabled on a zone
by zone basis via a DLL entry. Holey DMA has been aimed at 8 or
16 raster zones, but will have the same effect for other zone
sizes. MARIA can be told to interpret odd 4K blocks as zero,
for 16 high zones, or odd 2K blocks as zeros for 8 high zones.
This will only work for addresses above x '8000'. This means
that these blocks can hold meaningful code, or tables, or
graphics data used in a zone where Holey DMA is not on."


so... my 1st mistake was... i mixed up "odd" with "even"... which wasn't good... ;)

then i went through Dan's vertical sprite demo and tried to understand how vertical sprite posititioning works on 7800 in detail. the basics are clear... but the holey DMA issue drove me crazy...

so... assuming you have build up the screen with zones covering each 16 scanlines. your sprite is f.e. 16x16 pixel...

remember that gfx data has to be layed out in ram with 256 bytes "scanlines"... f.e. the sprite would cover the adress space:

$a000-$a003
$a100-$a103
$a200-$a203
$a300-$a303
...
$af00-$af03

(16 pixel are in 160x2 mode, similar to antic e, 4 bytes as each byte holds 4 pixels)

for vertcial sprite positioning we have to modify the DLs for the zone(s) the sprite would appear... which means the starting adress of the sprite data... as it is written in the dev document...

to avoid a lot of wasting ROM space because of the "0" each sprite would need to be positioned smoothly... MARIA has the holeyDMA feature...

assuming holeyDMA16 (for 16 scanline zones) is set in the display list list (DLL) the dev doc says that now every odd 4k block above $8000 will be interpreted by MARIA as 0 even if there is no zero data...

ok... what does this mean? now my bad logical brain confused me... for me each 4k block is even, not odd... 4096 is even... but then i found this bit in the dev doc:

DLI - Display List Interrupt flag.
0 => No DLI.
1 => Interrupt after DMA on last line
of previous zone.

H16 - 16 high zone Holey DMA enable.
0 => Not enabled.
1 => Enabled. DMA interprets odd 4K
blocks as zeros. (A12 high => data=0)

H8 - 8 high zone Holey DMA enable.
0 => Not enabled.
1 => Enabled. DMA interprets odd 2K
blocks as zeros. (A11 high => data=0)

OFFSET - OFFSET starting value.
4 bits only.

DL ADDRESS - Address of Display List for this zone.


the interesting part is "A12 high => data=0" in the H16 section... now we have to think "binary". so let us perform a CLD in our brain... ;)

A12 means the Bit12 of the sprite data adress (A0-A15)

now... let us check:

Bit counting from left to right 15,14,13,12,11,10,9,8,7,6,5,4,3,2,1,0

$a000 = %10100000 00000000 (high low)
$a100 = %10100001 00000000
$a200 = %10100010 00000000
...

etc... Bit 12 is always 0 = even in MARIA definition so gfx data is being visible on screen.

now...for vertical movement we would need data "on top of our sprite at $b000-$bf00 for being possible to set the sprite on scanline basis...

so... let us write $b000 etc... in binary mode

$b000 = %10110000 00000000
$b100 = %10110001 00000000
$b200 = %10110010 00000000
...

and voila... Bit 12 is set for the whole range $b000 - $bfff ergo is this ROM space "odd" for Maria when holeyDMA16 is enabled... so data lying here will not be interpreted as sprite data but instead as "zero" = 0

so... now your code has just to calculate on which zone(s) your sprite appears and has to modify the DL entries including the sprite adress pointer... but this is not more complicated then it looks...check out dan's sprite demo...

it's still not so comfortable like on "real hardware sprite" systems... where you just need to alter x,y hardware adresses but with this method is very similar as you move the sprites by altering the "high byte" of your sprite pointer... and this is similar to the above system...you have just to add the starting adress of your sprite data to the y-position... and voila...

MARIA designes had really fast gfx in mind... as the chip seems designed for speed (and having the 6502 in mind as well...) all counters count downwards, gfx data has to be stored "top-down", gfx data has to be stored with "256 bytes" long scanlines in mind... all neat tricks by hardware which we demo coder would use in our own productions...

i hope i could explain a little bit to the newbies...

#2 EricBall OFFLINE  

EricBall

    Dragonstomper

  • 711 posts
  • Location:Markham, Ontario, Canada

Posted Thu Jan 15, 2004 11:59 AM

On the 7800 the screen is broken up into "zones" of 1-16 scanlines (typically 8 or 16), based on the 3 byte DLL header. The DLL header contains a 16 bit address pointer to the display list for the zone.

The display list is made up of a sequence of 4 or 5 byte sprite headers ended by a 2 byte null header. Each direct sprite header contains a 16 bit address pointer to the graphics data drawn on the last scanline of the zone. (Indirect sprites, or tiles, are a little different.)

Graphics data is laid out "upside down" with the last scanline on the lowest address and each scanline on a separate page. e.g. for a 2 byte x 16 line sprite
$e000-$e001 bottom line
$e100-$e101 2nd last line
...
$ee00-$ee01 2nd line
$ef00-$ef01 top line

Horizontal motion on the 7800 is easy 'cause each sprite header contains a 1 byte horizontal position (though this means only 160 onscreen positions even in 320 modes). Vertical motion requires a little more work. Assume we are using 16 line sprites and zones. If the sprite is "on grid" then we have the following

line 0-15 DLL -> sprite header -> $e000

Now say that the sprite moves down one scanline, then the sprite is overlaps two zones and we need the following

line 0-15 DLL -> sprite header -> $e100
line 16-31 DLL -> sprite header -> $d100

Some of this seems counter-intuitive, but remember that the sprite header points to the bottom of the sprite. So the top scanline of the second zone will draw the graphics stored at $d100 + 15*256 = $e000 or the last scanline of the sprite. So the sprite has moved down one scanline.

This is also where "Holey DMA" comes into play. In the above example the top scanline of the first zone will draw the graphics stored at $e100 + 15*256 = $f000. In the DLL there are two flags, one which treats odd 4K segment of ROM as full of zeros. So when that flag is set, graphics reads from $dxxx and $fxxx will be treated as zeros. Thus we can store code and non-graphics data in those segments.

Now that we know how to handle vertical motion, the next challenge is building that silly display list. (See the mega sprite demo I posted to the Atari 7800 Programming mailing list.)

#3 DanBoris OFFLINE  

DanBoris

    Dragonstomper

  • 930 posts
  • Location:New Jersey, USA

Posted Thu Jan 15, 2004 12:01 PM

Heaven/TQA said:

it's still not so comfortable like on "real hardware sprite" systems... where you just need to alter x,y hardware adresses but with this method is very similar as you move the sprites by altering the "high byte" of your sprite pointer... and this is similar to the above system...you have just to add the starting adress of your sprite data to the y-position... and voila...

The nice thing about the 7800 hardware is that you can simulate a "real hardware sprite system", or any other type of graphics hardware you like. You would create a display engine that reads a table of sprite X,Y positions and generate the DL's from this table. Once this is done, you game logic only has to deal with the sprite table and not directly with the display lists. This also gives you the flexibility to design different display engines for different games. You might have an engine for just doing sprites, an engine for a tiled background with sprites, an engine for a side scrolling background, etc.

Dan

#4 DEBRO OFFLINE  

DEBRO

    Stargunner

  • 1,862 posts
  • Location:Atlanta, GA

Posted Thu Jan 15, 2004 12:10 PM

:idea: This is the type of thing I'd like to see on the mailing list.

#5 Heaven/TQA ONLINE  

Heaven/TQA

    Quadrunner

  • 8,109 posts
  • Location:Baden-Württemberg, Germany

Posted Thu Jan 15, 2004 2:03 PM

i would be very interested in the sprite demo you have mentioned... is the 7800 discussion list archived?

#6 Mitch OFFLINE  

Mitch

    Quadrunner

  • 5,769 posts
  • 7800 Guy
  • Location:Southern California, USA

Posted Fri Jan 16, 2004 1:38 PM

Heaven/TQA said:

i would be very interested in the sprite demo you have mentioned... is the 7800 discussion list archived?

The 7800 list archive is here.

Mitch

#7 DEBRO OFFLINE  

DEBRO

    Stargunner

  • 1,862 posts
  • Location:Atlanta, GA

Posted Fri Jan 16, 2004 1:51 PM

Thanks Mitch.

Apparently they don't archive attachments though :sad:

#8 Heaven/TQA ONLINE  

Heaven/TQA

    Quadrunner

  • 8,109 posts
  • Location:Baden-Württemberg, Germany

Posted Fri Jan 16, 2004 3:41 PM

just for comparison attachted the source code of my playstation1 intro... it's pure R3000 assembler... huj... it's from 1999... long time ago...




; basic psx-routines by Silpheed of HITMEN
; Heaven/Taquart 1st intro on psx!!!


;
; start: several weeks ago...
; end  : 05th jun 1999
;
; still playing around with 256 color-images...
;
; greetinx to all at napalm message-board
; and of course to all members of Taquart !!!


; - 06/05 dolphin sprite rendered
;         lets try to include it in demo...
;         yeah... i got it...
; - 06/05 try to fade the logo in...
;         yeah... works...
; - 06/05 now moving dolphin-head works, too
; - 06/05 added some gouraud-lines moving around
; - 06/06 after going out night i have new ideas to improve intro
;         i will add a lensflare moving behind the logo...









            org $80010000

            

            li sp, $801fff00

            li k1, $1f800000           ; set to hardware base



            li a0, $08000009           ; a0 = display-mode

                                       ; 8 = pal

                                        

            jal InitGPU                ; initialise the GPU

            nop



            la a0, image               ; transfer image data to VRAM

            li a1, 320                ; 320 position in vram

            li a2, $8000a0            ; image-size y,x/2 

            li a3, 10240              ; (x/2)*y div 2

            jal MEM2VRAM_IO

            nop



            la a0, clut                ; transfer clut data to VRAM

            li a1, $1000140

            li a2, $10100

            li a3, 128

            jal MEM2VRAM_IO

            nop

            nop



            la a0, dolphin             ; transfer dolphin to vram

            li a1, 512             ; at (320,256)

            li a2, $640028             ; size 80x100

            li a3, 2000

            jal MEM2VRAM_IO

            nop



            la a0, clut2

            li a1, $0000300

            li a2, $10100

            li a3, 128

            jal MEM2VRAM_IO

            nop


;exit        nop
;            j exit
;            nop



            jal InitPads               ; init pads, also the wait vsync routine

            nop



            la a0, module

            jal HM_Init                ; init the mod player

            nop

                                        

part1                                  ; fade logo in...



            li s0,$64000000

            li s1,$00111111

            li s3, 0

part1_loop0

            li s2, 0



part1_loop



            jal HM_Poll                ; call mod player

            nop



            jal WaitIdle               ; wait for GPU to finish processing

            nop

            

            jal WaitVSync              ; wait for vertical retrace period

            nop

            

            la a0, list    

            jal SendList               ; send display list to GPU

            nop



            addiu s2,1

            slt t0, s2, 2           ; wait for 2 frames before continuing

            bnez t0, part1_loop

            nop

            addu s3,1


;crash           j crash
;            nop





            addu s0, s1,s0

            sw s0, fade1

            sw s0, fade2



            slt t0, s3, 15

            bnez t0, part1_loop0

            nop
;crash           j crash
;            nop



part2       li s0,$009cffc0   ; move dolphin

            li s3,0



part2_loop



            jal HM_Poll                ; call mod player

            nop



            jal WaitIdle               ; wait for GPU to finish processing

            nop

            

            jal WaitVSync              ; wait for vertical retrace period

            nop

            

            la a0, list    

            jal SendList               ; send display list to GPU

            nop



            sh s0, dolphin_pos



            addu s0,1

            addu s3, 1

            slt t0, s3, 80            

            bnez t0, part2_loop

            nop

            


; Main parts of the intro:



            li s1, 0

            li s3,0

            li s4,0

part3
; draw the thetraeder...
; verry basic...;)
; there are 4 primitives, 3 sides and one top-one to "close" the thetraeder
; lineposnx means n=primitive nr; x which vertice of the triangle




;set all 4 primitives on the sin-tables to make nice moving...



            la s0, SinTab1

            addu s0,s1

            addu s1,2

            and s1,$000000ff

            lb s2, (s0)

            sb s2, linepos11

            sb s2, linepos41

            sb s2, linepos32

            sb s2, line_color31+2

            sb s2, line_color22+1



            lb s2, (s0)

            lb s2, 64(s0)

            sb s2, linepos12

            sb s2, linepos43

            sb s2, linepos21

            sb s2, line_color21+1

            sb s2, line_color11



            lb s2, 128(s0)

            sb s2, linepos22

            sb s2, linepos42

            sb s2, linepos31

            sb s2, line_color32+2

            sb s2, line_color12


;now move them a little bit vertical
;and set the vertice colors...



            la s0, SinTab2

            addu s0,s1

            

            lb s2, (s0)

            sb s2, linepos11+2

            sb s2, linepos22+2

            sb s2, linepos32+2

            sb s2, linepos41+2





            lb s2, 64(s0)

            sb s2, linepos12+2

            sb s2, linepos43+2

            sb s2, linepos21+2

            lb s2, 128(s0)

            addu s2, 48

            sb s2, linepos31+2

            sb s2, linepos42+2





            

            jal HM_Poll                ; call mod player

            nop

skipupdate            

            jal WaitIdle

            nop



            jal WaitVSync

            nop

    

            la a0, list

            jal SendList

            nop

                                            

            j part3                    ; loop forever

            nop

            

            



include silph.inc                      ; some useful routines            



align 4

image incbin logo31.raw                   ; the raw image data for the logo and chars

clut incbin logo31.clt                    ; clut info for above



align 4

dolphin incbin dolphin.raw             ; 80x100x256 head of dolphin

clut2 incbin dolphin.clt               ; clutinfo for dolphin



align 4

list include hvelist3.inc                  ; the display list



align 4

module incbin thesong.hit



align 4

include hitmod.inc



align 4

include sintab.inc



and here is the interesting part... the "Object list" for the grafix processor of the PSone...


prim291   ; SPRT

    db prim292, prim292>>8, prim292>>16, $4



fade1 dw $64000000

lpos1

    dw $00000004

    dw $40140000

    dw $800100



prim292   ; DR_TPAGE

    db prim293, prim293>>8, prim293>>16, $1

    dw $E1000086



prim293   ; SPRT

    db prim294, prim294>>8, prim294>>16, $4



fade2    dw $64000000

lpos2

    dw $00000104

    dw $40140080

    dw $800040





prim294        ; dr_tpage

    db prim295, prim295>>8, prim295>>16, $1

    dw $e1000088



prim295        ; dolphin
;     db $ff,$ff,$ff, $4



    db prim100, prim100>>8, prim100>>16, $4

    dw $64aaaaaa

dolphin_pos

    dw $009cffb0

    dw $00300000       ; clut at $00003000

    dw $640050



prim100        ; gouraud triangle

    db prim101, prim101>>8, prim101>>16, $6

line_color11

    dw $30000080

linepos11

    dw $00800080

    dw $00ffffff

    dw $00f000c0

line_color12

    dw $00000080

linepos12

    dw $00800080



prim101        ; gouraud triangle

    db prim102, prim102>>8, prim102>>16, $6

line_color21

    dw $30000000

linepos21

    dw $00800080

    dw $00ffffff

    dw $00f000c0

line_color22

    dw $00000000

linepos22

    dw $00800080



prim102        ; gouraud triangle

    db prim103, prim103>>8, prim103>>16, $6

line_color31

    dw $30800000

linepos31

    dw $00800080

    dw $00ffffff

    dw $00f000c0

line_color32

    dw $00800000

linepos32

    dw $00800080



prim103        ; gouraud triangle

    db $ff, $ff, $ff, $6

line_color41

    dw $30115011

linepos41

    dw $00800080

    dw $00ffffff

linepos43

    dw $00f000c0

line_color42

    dw $00ffffff

linepos42

    dw $00800080



    



prim999   ; BLOCK FILL

    db $ff, $ff, $ff, $3

    dw $02634522

    dw $0

    dw $F0140


; End of display list




and you see it's the main concept as MARIA chip has... and it's even called display list... ok...you have more possibilities but basicly it's the same... but each object in the list can have every postion on the screen...

sorry...don't know why i have posted that...

#9 conda OFFLINE  

conda

    Chopper Commander

  • 199 posts
  • Location:Pennsylvania

Posted Mon Apr 18, 2005 8:05 PM

EricBall, on Thu Jan 15, 2004 12:59 PM, said:

This is also where "Holey DMA" comes into play.  In the above example the top scanline of the first zone will draw the graphics stored at $e100 + 15*256 = $f000.  In the DLL there are two flags, one which treats odd 4K segment of ROM as full of zeros.  So when that flag is set, graphics reads from $dxxx and $fxxx will be treated as zeros.  Thus we can store code and non-graphics data in those segments.

Wow, I've been trying to understand Holey DMA and almost gave up. This post cleared it right up. Thanks for this. Damn, it's really simple.

#10 Bruce Tomlin OFFLINE  

Bruce Tomlin

    River Patroller

  • 3,531 posts
  • CD C9 01
  • Location:Austin, TX

Posted Wed Apr 20, 2005 7:29 AM

I dunno, I understood it right away, and got it right the first time when I actually wrote some code that used it.

Basically it just handles going over the top or bottom edge of your sprites for you. Every other zone-sized memory block is a "no-mans land" which the Maria pretends always contains nothing. So you either start or end outside your graphics memory block far enough to show just the scan lines you need.

The Maria is a really nice design, if it weren't for stuff like the wierd pixel mappings, the horribly low-res 160-pixel mode, and the cycle-stealing DMA. (And the pathetic 2K SRAM when the 5200 and ColecoVision already had 16K DRAM.) If the 7800 had been released in 1984 and if it had become a success, Atari would probably have had to release an upgraded Maria+ system of some sort just to stay competitive.

Heaven/TQA: could you please edit your post to not have all those extra blank lines? There's something wierd about this BB software that it throws a bunch extra blank lines into CODE tags.

EricBall, on Thu Jan 15, 2004 12:59 PM, said:

Horizontal motion on the 7800 is easy 'cause each sprite header contains a 1 byte horizontal position (though this means only 160 onscreen positions even in 320 modes). Vertical motion requires a little more work.
A little more work? Not only do you have to decide how many zones your sprite fits into, you have to figure out which zones and then insert into variable-length display lists.

#11 conda OFFLINE  

conda

    Chopper Commander

  • 199 posts
  • Location:Pennsylvania

Posted Wed Apr 20, 2005 8:20 AM

Maybe you can explain this to me regarding video resolution.

Why does the NES have a better resolution than the Atari's? From the Atari docs I've read, they seem to imply that you cannot exceed the 160x192 resolutions. But the NES has a 256x224 resolution--much better.

After reading this, I changed my DLL to use 224 lines (14 zones, 16 high), and it worked in the emulator, but I don't have an MMC card for my CC2 yet, so I could not test it on real hardware.

How does the NES pull this off where Atari cannot?

#12 DEBRO OFFLINE  

DEBRO

    Stargunner

  • 1,862 posts
  • Location:Atlanta, GA

Posted Wed Apr 20, 2005 9:30 AM

conda, on Wed Apr 20, 2005 10:20 AM, said:

Maybe you can explain this to me regarding video resolution.

Why does the NES have a better resolution than the Atari's?  From the Atari docs I've read, they seem to imply that you cannot exceed the 160x192 resolutions.  But the NES has a 256x224 resolution--much better.

After reading this, I changed my DLL to use 224 lines (14 zones, 16 high), and it worked in the emulator, but I don't have an MMC card for my CC2 yet, so I could not test it on real hardware.

How does the NES pull this off where Atari cannot?

View Post

Atari recommends using 192 scan lines because that would fit with every NTSC TV. IIRC you can fit 200 scan lines inside a modern TV frame without issues. Outside of that the full screen may not show.

Also, remember MARIA handles VSYNC for you (unlike STELLA). So the 7800 truly has a vertical resolution of 243 scan lines.

Edited by DEBRO, Wed Apr 20, 2005 9:40 AM.


#13 Bruce Tomlin OFFLINE  

Bruce Tomlin

    River Patroller

  • 3,531 posts
  • CD C9 01
  • Location:Austin, TX

Posted Thu Apr 21, 2005 7:46 AM

DEBRO, on Wed Apr 20, 2005 10:30 AM, said:

Atari recommends using 192 scan lines because that would fit with every NTSC TV. IIRC you can fit 200 scan lines inside a modern TV frame without issues. Outside of that the full screen may not show.

View Post

Also, the more lines you show, the less CPU time you get to do computations, because of the DMA cycle stealing. Emulators will generally not show the effect of this.

And don't forget the 320 pixel modes. Not a lot of colors (320B gives you a total of seven, and another 320 mode gives you a total of nine, but you can only use three+background at most in any object), and lots more of a DMA hit, but it's got nice square pixels.

I wish they had made a 240 pixel mode for Maria. 160 is low enough to be ugly, even with 4 bit pixels (which is what, 13 colors due to the palette mapping?), and 320 is just too hungry.

#14 conda OFFLINE  

conda

    Chopper Commander

  • 199 posts
  • Location:Pennsylvania

Posted Thu Apr 21, 2005 8:08 AM

Bruce Tomlin, on Thu Apr 21, 2005 8:46 AM, said:

And don't forget the 320 pixel modes.  Not a lot of colors (320B gives you a total of seven, and another 320 mode gives you a total of nine, but you can only use three+background at most in any object), and lots more of a DMA hit, but it's got nice square pixels.

In essance you are saying the 7800 should be able to run in a 320x200 mode with a palette selection of seven or nine colors?

#15 EricBall OFFLINE  

EricBall

    Dragonstomper

  • 711 posts
  • Location:Markham, Ontario, Canada

Posted Wed Apr 27, 2005 10:36 AM

conda, on Wed Apr 20, 2005 9:20 AM, said:

Maybe you can explain this to me regarding video resolution.

Why does the NES have a better resolution than the Atari's?  From the Atari docs I've read, they seem to imply that you cannot exceed the 160x192 resolutions.  But the NES has a 256x224 resolution--much better.
A standard NTSC field has 262 lines (312 for PAL), however 9 of those lines are part of the vertical sync and some of the remaining lines are not visible onscreen. There's nothing preventing a 7800 game from outputting 224 lines (or even 240) of graphics data.

The horizontal resolution is more of a design decision. The 7800 video signal is driven by a clock which is a even multiple of the colorburst frequency (x1 for 160, x2 for 320), while the NES uses a 1.5 multiplier. More pixels also increase the on-chip line RAM requirements.

#16 EricBall OFFLINE  

EricBall

    Dragonstomper

  • 711 posts
  • Location:Markham, Ontario, Canada

Posted Wed Apr 27, 2005 10:38 AM

conda, on Thu Apr 21, 2005 9:08 AM, said:

In essance you are saying the 7800 should be able to run in a 320x200 mode with a palette selection of seven or nine colors?
See http://atari7800.xwi...n/GraphicsModes for the nitty-gritty details.




1 user(s) are reading this topic

0 members, 1 guests, 0 anonymous users