-
Content Count
415 -
Joined
-
Last visited
Posts posted by ScumSoft
-
-
I've implemented a software 96x192 pixel display output.
However I am having some issues coming up with a fast method to do mid-byte positioning.
I have a 12byte display output buffer and brute forcing a sprites bits into position would be done like this:
GeneratePixelOffset: lax PlayerX ;[]+3 Load Players X position 0-95 ldy XPosTable,X ;[]+4 Get amount to shift sty ShiftAMT ;[]+3 Store for later lsr ;[]+2 Divide by 8 lsr ;[]+2 lsr ;[]+2 tax ;[]+2 Use as offset lda GFXtable,X ;[]+4 Get GFXbuffer slot number sta P0GFXslot ;[]+3 Save for later rts ;[]+6 GFXtable: .byte $00,$06,$01,$07,$02,$08,$03,$09,$04,$0A,$05,$0B ;GFXbuffer 0-11 XPosTable: .byte $00,$01,$02,$03,$04,$05,$06,$07 ;Pixels 00-07 .byte $00,$01,$02,$03,$04,$05,$06,$07 ;Pixels 08-15 .byte $00,$01,$02,$03,$04,$05,$06,$07 ;Pixels 16-23 .byte $00,$01,$02,$03,$04,$05,$06,$07 ;Pixels 24-31 .byte $00,$01,$02,$03,$04,$05,$06,$07 ;Pixels 32-39 .byte $00,$01,$02,$03,$04,$05,$06,$07 ;Pixels 40-47 .byte $00,$01,$02,$03,$04,$05,$06,$07 ;Pixels 48-55 .byte $00,$01,$02,$03,$04,$05,$06,$07 ;Pixels 56-63 .byte $00,$01,$02,$03,$04,$05,$06,$07 ;Pixels 64-71 .byte $00,$01,$02,$03,$04,$05,$06,$07 ;Pixels 72-79 .byte $00,$01,$02,$03,$04,$05,$06,$07 ;Pixels 80-87 .byte $00,$01,$02,$03,$04,$05,$06,$07 ;Pixels 88-95 [...] ***THEN IN THE SCANLINE KERNAL*** ;Pretend I want to draw the player right now ldy GFXindex ;Which sprite to draw? lda (GFXplayer),Y ;fetch GFX data to be drawn ldx P0GFXslot ;calculated outside kernal, 0 to 11 ;Position the sprite roughly into the appropriate GFXbuffer byte sta GFXbuffer,X ;Now rotate into position determined by ShiftAMT lda ShiftAMT beq .noShift lsr beq Shift1 lsr beq Shift2 [ect...]This would take too many cycles just checking to see how many bytes to shift.
Then if say I am shifting over 3 bytes:
shift3: lsr GFXbuffer,X ror GFXbuffer+1,X lsr GFXbuffer,X ror GFXbuffer+1,X lsr GFXbuffer,X ror GFXbuffer+1,X
Way too many cycles over budget.
So I am currently looking into doing some smart masking and bit flipping to avoid this much overhead.
Would a simpler method already be known that I could learn from?
-
Thanks nukey! That makes much more sense.
I was looking through the header file and wondered why those bytes were undefined and decided to just check em out.
Okay my side tracked mission is done. Back to coding I go.
-
You'd really have to dumb down the games action a bit for the 2600. It would most likely resemble Disc's of Tron with a honeycomb grid doing things the normal way.
-
; Unused/undefined registers ($285-$294) ds 1 ; $286 ds 1 ; $287 ds 1 ; $288 TEMP0 ds 1 ; $289 Writeable and readable ds 1 ; $28A TEMP1 ds 1 ; $28B Writeable and readable ds 1 ; $28C ds 1 ; $28D ds 1 ; $28E ds 1 ; $28F ds 1 ; $290 ds 1 ; $291 Mirror of TEMP0 data ds 1 ; $292 ds 1 ; $293 Mirror of TEMP1 dataI modified VCS.h like this.
I noticed there was a few undefined bytes of memory space, but I am not sure where this space is located. So I assigned a name to each and tried storing and loading data from each of them, and this is what I got.
Stella can read and write to the above addresses, but I wasn't sure if a real 2600 could, so I loaded GFX data into TEMP0 and TEMP1 each scanline, slapped it into my harmony cart and behold they work on a real 2600.
Where in the 2600 are these bytes located? It defines these in the riot chip, but what parts of this chip are actually unused? The other bytes aren't writable but those 2 are for some reason.
Found a RIOT.txt that explains them as this:
$0286 = (RIOT $06) - Write edge detect control - negative edge, enable int (1)
$0287 = (RIOT $07) - Write edge detect control - positive edge, enable int (1)
$0288 = (RIOT $08) - Write DRA
$0289 = (RIOT $09) - Write DDRA
$028A = (RIOT $0A) - Write DRB
$028B = (RIOT $0B) - Write DDRB
$028C = (RIOT $0C) - Write edge detect control - negative edge, disable int (1)
$028D = (RIOT $0D) - Write edge detect control - positive edge, disable int (1)
$028E = (RIOT $0E) - Write edge detect control - negative edge, enable int (1)
$028F = (RIOT $0F) - Write edge detect control - positive edge, enable int (1)
$0290 = (RIOT $10) - Write DRA
$0291 = (RIOT $11) - Write DDRA
$0292 = (RIOT $12) - Write DRB
$0293 = (RIOT $13) - Write DDRB
I'm not sure what DRA/DDRA/DRB/DDRB pertain too.
-
I read somewhere else here, that it was a compromise of the Tia designers realized only too late. There wasn't an expectation during design that programmers would exploit more potential from the system than originally anticipated.
It was designed for basic games...
"Programmers break free. Programmers expand to new territories. Painfully, perhaps even dangerously. But Programmers find a way"

-
The engine I've been working on for my game changes things quite a bit. I've more or less taken the limits on horizontal positioning of P0/P1 and threw them out the window.
(I had to go fetch my Atari from the neighbors yard afterwards but this is another story)

Instead of worrying about a P0 sprite being placed all over the screen for multiple things, I've decided to lock it in place along with P1 in a 3 by 3 config, 8 pixels apart then splitting this between 2 frames. At the end of the first frame and in the overscan, I move P0 and P1 over 8 pixels which fills in the gaps. This causes some flicker to happen, but only when the entire screen is one color, for smaller sprites it provides very little flicker, more like a shimmer effect.
So what this effectively did, was give me a 96x192 software controlled playfield with 12 sprites per scanline and 24 rows for a total of 288 unique sprites.
How one uses this is another story, as I am still creating the control logic behind it all. But so far it is VERY flexible and should allow for all sorts of new and neat things to be drawn. After drawing a scanline I have 27 cycles left, and in the interlaced lines I have 64 cycles free. This allows just enough time to stuff a 12-byte pixel buffer with the next scanlines data. Couple this with smart masking and you have a nice display that can do per pixel stuff. It also allows me to set 2 unique colors per sprite, so that is 24 colors per scanline total. I am currently coding the rotation kernal for moving images left and right.
The only sad limit, is while you can do so much, it is limited to 96 pixels wide. So to get around this limit, I've come up with the idea(not completely implemented yet) to move the 96 pixel viewport around the screen as my player moves. This gives the illusion that the world is staying still and only the viewport is moving within the screen bounds.
I was hoping to have a demo up today, but there are some delays I didn't foresee. Hopefully before this weekend is over I'll have something nice to show everyone.
-
New one has a stronger contrast to the color, the older one looks to be a bit more washed. But I also think it will depend on which game screen is shown.
Say if you were in a dungeon, would the new one look much better than the old? I think its just the limited shades of green for these screenies.
-
END!
Got a kick out of that

Neat asteroid, I like it.
-
Yeah likewise, without using the SaveKey device, its the only real logical way to implement a save feature plus it's fairly easy to use.
-
Well never mind the first post here, I found a much better way to interlace the frames. Much of that code was not really needed at all

Hurray for optimizations!
-
Well the RPG I am making would benefit from extra level storage, but for my first game I'll ("try") to keep it at 4k.
But those extra features would be great for other games.
-
Oh thank you so much SpiceWare its working great!
I had the addressing wrong, I was placing commands in the table and not offsets to the routines.
Once I finish my game, I'll have a huge list of problems I've encountered and should compile them together and their appropriate solutions for others to learn by.
Beginner tutorials are great for getting started, but actual game design problems and their solutions would be a valuable resource don't you think?
Now I can finally proceed. Thanks again.
-
This could be done so long as you had writable internal storage in the cart itself, and just overwrite the playdata when it asks.
Though this would be easier said than done. But I'm no expert, it may be impossible for all I really know.
[edit] on second thought, doesn't Dragonstomper stream the data from the cassettes, so all you need is control logic in the game for seeking data from an external storage device hooked directly into the cartridge so as to avoid slow transfers via joy ports right? Hmm, might be easier to just use the harmony cart for this idea.
-
Alright I give. How does one implement a Jump table in 6507 code? I'd like to hold an offset like such to a table of Jumps:
Offset = 0 through 3
JumpTable:
jmp doThis
jmp doThat
jmp doSomething
jmp DONTDOTHAT
And I'd like to call it via jmp JumpTable,Offset to land on the right bounce.
-
Hello again everyone, I've been busy since last week programming up my games framework(see blog for details).
Its great to be back here and to start coding again.
I have come up with a neat interlaced routine (not sure if something similar has been posted) and
I need to flip a single bit on and off every frame which sets the interlace routine to even/odd frames:
So what happens is during the kernal I manage it all like this:
ldy Scanlines ;[]+3 ;Our Scanline count for our interlaced loops ;-Loaded from VBLANK to save precious playfield cycles PF_LOOP: tya ;[3]+2 ;Interlace frame check eor #1 ;[5]+2 ;Toggle bit, this switches between Draw & Logic scanlines and #$01 ;[7]+2 ;Mask all but bit 1 beq PF_LOGIC ;[9]+2/3 ;Branch to Logic scanline PF_DRAW: ;******************************** ; [DRAW SCANLINE] ; * 96 Scanlines of visible graphics ; * Scanline [??], S.cyc [11] ; * PixelPos [-35], Color clock [33] ;******************************** ;***DO STUFF like draw graphics jmp PF_Return ;[]+3 ;Jump out of Draw PF_LOGIC: ;******************************** ; [LOGIC] ; * 96 scanlines for logic ; * Scanline [39 to ??], S.cyc [12] ; * PixelPos [-32], Color clock [36] ;******************************** ;***DO STUFF LIKE ;***Blank out graphics so they are not visible on this scanline ;***Process updates ect ;-Fall through to PF_Return PF_Return: dey ;Decrement scanline sta WSYNC ;- bne PF_LOOP ;If more scanlines left, loop ;All done? Fall through to overscan And in the Overscan I do this: ;***Interlaced display settings*** lda Interlace ;This will interlace the display eor #1 ;-toggle bit between 0 and 1 sta Interlace ;-store value for next pass bne .ODD ;-if its a 1 then setup for ODD frames lda #191 ;Set to 192 scanlines total (191 to 0) sta Scanlines ;-used during PF_LOOP lda #33 ;Compensate 1 more scanline for interlace sta TIM64T ;Will total 262 scanlines jmp .OS_LOGIC ;Proceed to Overscan logic .ODD: lda #192 ;We want 193 scanlines (192 to 0) sta Scanlines ;-store value for next pass lda #34 ;Compensate 1 less scanline for interlace sta TIM64T ;Will total 262 scanlines ;-proceed to Overscan logicIs this a typical way of doing an interlaced kernal? Every frame is alternated starting at Logic->Draw to Draw->Logic and so forth, I find this gives minimal flicker and allows for an entire frames worth of time for logic and drawing collectively.
What I would like to know is if someone invented a better way to do interlaced kernals. This seems to work fine right now for my game, but I am very curious as to what others have done before me.
Okay sleep time, cya all tomorrow.
-
Alright! My cart showed up just a little while ago. Very impressive, thank you for such a great product!
It has already showed me a few glaring errors in my games draw routines that seemed to look fine in stella.
Great product! this is going to make programming oh so much more fun.
-
DOH! Right from the get go I got stuck on the right < border right on the tip.
I didn't take a screenshot the first time so I managed to do it again for ya.

Only seems to happen when I set the controls to 45 deg.
You collide it from the bottom left and you fall off the cliff behind the border, then it spawns you inside the barrier.
Otherwise fantastic job!
-
1
-
-
So ferrite beads are like mouse droppings?
No, those taste like bonbons, these do not.
-
This is pretty slick. I'm liking the theme

-
I just placed my order for one, and am eagerly awaiting with much glee and anticipation

I joined a little over a year ago with the idea that I would learn how to program the 2600, well.. I still don't have a very good grasp on it but I am chugging away.
-
The "Insert Logic Here" comments for VBLANK and Overscan should be placed before their looping labels, instead of after. Otherwise the inserted code will loop N number of times per frame instead of once per frame. (where N depends on the cycle timing of the inserted code.)
I modified my version of the template to use the timer approach for the playfield as well, so I can build up the different sections of the screen (score, radar, whatever) as I go along and still have a 292 cycle count the whole time, but that's just a matter of preference.
Thanks for the nice template!

Yes this was fixed on my end a little while after I posted, but due to not being able to edit the post after it was replied to I just left it to the user to fix without mention.
Glad its at least helped some

[edit]test test
-
Yeah I'll be posting something good once it's at a presentable state. In the mean time I am trying to pickup on everything that assists me in understanding the 2600 better.
I am curious though, I was under the impression that the 6507 didn't have enough umph to push the TIA for more than 9 color changes per scanline. How would a chip on the cartridge feed the TIA when it must first pass through the slow 6507? Is there direct access to the TIA from a rom space?

-
Very cool, I like it. Any massive hardware tricks required?
I'm still learning how the 2600 all works and just got Visual Batari running under Win7's XP virtual machine.
Would you have enough cycles left for player movement and enemy updates? If so it would be really cool to play.
-
Yes with the exception of those of course

I understand what is being said now, I thought you were somehow accessing the data written to the read only registers.
You wish for the lower nibble of PF0 to set a flag, then push that flag onto the stack in order for it to be reused later on correct?

Coding tricks
in 2600 Programming For Newbies
Posted · Edited by ScumSoft
Brilliant! I really appreciate the help.
[edit] Well eor only works on the acc, so to place the result into ram I have to use a sta regardless right?