-
Content Count
16,912 -
Joined
-
Last visited
-
Days Won
10
Posts posted by SpiceWare
-
-
2 hours ago, pvmpkin said:One issue I come up against each time is purely having instructions in the wrong place and getting unexpected results.
One part of PosObject is very time critical and could be thrown off based on where the routine ends up in memory:
DivideLoop sbc #15 ; 2 2 - each time thru this loop takes 5 cycles, which is bcs DivideLoop ; 2 4 - the same amount of time it takes to draw 15 pixels eor #7 ; 2 6 - The EOR & ASL statements convert the remainderThe issue is the BCS instruction. All 6502 branch instructions include this note:
QuoteA page boundary crossing occurs when the branch destination is on a different page than the instruction AFTER the branch instruction.
The page is the upper byte of an address. If you have dasm create a listing you can see the address for the DivideLoop and the EOR instruction. For this:
216 f003 DivideLoop 217 f003 e9 0f sbc #15 ; 2 2 - each time thru this loop takes 5 cycles, which is 218 f005 b0 fc bcs DivideLoop ; 2 4 - the same amount of time it takes to draw 15 pixels 219 f007 49 07 eor #7 ; 2 6 - The EOR & ASL statements convert the remainderthe address of DivideLoop = $F003, the EOR = $F007 so the page for both is $F0.
For this:
216 f0fc DivideLoop 217 f0fc e9 0f sbc #15 ; 2 2 - each time thru this loop takes 5 cycles, which is 218 f0fe b0 fc bcs DivideLoop ; 2 4 - the same amount of time it takes to draw 15 pixels 219 f100 49 07 eor #7 ; 2 6 - The EOR & ASL statements convert the remainderthe DivideLoop is on page $F0, but the EOR is on page $F1, so there's a 1 cycle penalty. That means the expected 5 cycles is now 6 cycles each time you go thru the loop, which will cause the objects to have the wrong positions.
If the address of DivideLoop is $xxfc, $xxfd, $xxfe, or $xxff (where xx is any page) then the penalty will occur.
-
1
-
-
No.
If you need the X position you need to use a byte of RAM to keep track of it. Then instead of using HMPx and HMOVE to shift the object left/right you use a subroutine like PosObject to reposition the object on every frame.
Here's the subroutine from Step 4 of my tutorial:
;=============================================================================== ; PosObject ;---------- ; subroutine for setting the X position of any TIA object ; when called, set the following registers: ; A - holds the X position of the object ; X - holds which object to position ; 0 = player0 ; 1 = player1 ; 2 = missile0 ; 3 = missile1 ; 4 = ball ; the routine will set the coarse X position of the object, as well as the ; fine-tune register that will be used when HMOVE is used. ;=============================================================================== PosObject: sec sta WSYNC DivideLoop sbc #15 ; 2 2 - each time thru this loop takes 5 cycles, which is bcs DivideLoop ; 2 4 - the same amount of time it takes to draw 15 pixels eor #7 ; 2 6 - The EOR & ASL statements convert the remainder asl ; 2 8 - of position/15 to the value needed to fine tune asl ; 2 10 - the X position asl ; 2 12 asl ; 2 14 sta.wx HMP0,X ; 5 19 - store fine tuning of X sta RESP0,X ; 4 23 - set coarse X position of object rts ; 6 29Here's how you'd use it to set the positions of the players:
;=============================================================================== ; PositionObjects ; -------------- ; Updates TIA for X position of all objects ; Updates Kernel variables for Y position of all objects ;=============================================================================== PositionObjects: ldx #1 ; position objects 0-1: player0 and player1 POloop lda ObjectX,x ; get the object's X position jsr PosObject ; set coarse X position and fine-tune amount dex ; DEcrement X bpl POloop ; Branch PLus so we position all objects sta WSYNC ; wait for end of scanline sta HMOVE ; use fine-tune values to set final X positionsIn Step 11 I added the ball object, the missiles are added in Step 12. In Step 11 I talked about how the X values for the ball and missiles are 1 off from the players, and updated the comment for PosObject to reflect this:
;=============================================================================== ; PosObject ;---------- ; subroutine for setting the X position of any TIA object ; when called, set the following registers: ; A - holds the X position of the object ; X - holds which object to position ; 0 = player0 ; 1 = player1 ; 2 = missile0 ; 3 = missile1 ; 4 = ball ; the routine will set the coarse X position of the object, as well as the ; fine-tune register that will be used when HMOVE is used. ; ; Note: The X position differs based on the object, for player0 and player1 ; 0 is the leftmost pixel while for missile0, missile1 and ball 1 is ; the leftmost pixel: ; players - X range is 0-159 ; missiles - X range is 1-160 ; ball - X range is 1-160 ; Note: Setting players to double or quad size will affect the position of ; the players. ;===============================================================================
-
1
-
-
Not yet, it'll be rewritten using CDFJ instead of DPC+
-
3
-
-
After writing my games I tend not to play them often as I get too burned out by all the play-testing that occurs during the development.
With everything going on with COVID-19 I've needed something to take my mind off things, so dusted off Draconian and have been playing a few rounds each day. Blasting everything away sure seems to help!
I've specifically been playing the Δ Quadrant Sectors(winners of the level design contest) and have been averaging around 250K for the past week. Today I did quite a bit better - even managed to make it to Sector 17 which is when the sectors start to repeat, but with a higher difficulty.
-
7
-
-
I've done some work on Stella, a preliminary fix for the DPC+ jitter issue that occurs in some games due to various versions of the DPC+ drivers. I plan to do some more work on that, but have put it on the back burner as my mind's too distracted.
I don't play my games that often as I get burned out on them during development, but it's been long enough that I've been playing a few rounds of Draconian (port of Bosconian) each day - it's easy to zone out while blasting the enemy. Specifically I've been playing the Δ Quadrant Sectors, which are the winners of the level design contest.
While playing I twice managed to take out a formation by blowing up a station as the formation flew over it. Also saw a rare bug - one of the enemy ships became stationary.
-
4
-
-
On 7/10/2019 at 7:22 AM, Marcus Englert said:Hi,
why is Epic Adventure (and EMR II) not running on my Harmony Cartridge (PAL50, newest firmware)? I get the the blue startup circle but this is it....
Any help much appreciated.
Thanks
Marcus
Harmony Encore? Epic Adventure is using a version of the DPC+ driver that doesn't work correctly on the Encore. The driver is the first 3K of the ROM, this version has the driver replaced with one that works on the Encore.
-
1
-
-
1 hour ago, stephena said:@SpiceWare, I just realized that we don't have a ROM properties entry for Stay Frosty 2 in Stella. As such, we can't make an exception for this game to use Joystick by default. Did you ever release the ROMs for this game? If so, please provide them, as well as any info you want in the database. We're planning a new release by the end of the coming week, so it would be great to get this updated before then.
Here's the ROMs, they were released here for the High Score Club.
Properties:
"Cart.MD5" "541cac55ebcf7891d9d51c415922303f" "Cart.Manufacturer" "SpiceWare - Darrell Spice Jr." "Cart.ModelNo" "SW-05" "Cart.Name" "Stay Frosty 2" "Cart.Note" "AtariAge Holiday Greetings 2014" "Cart.Rarity" "Homebrew" "Controller.Left" "JOYSTICK" "Display.Phosphor" "YES" "" "Cart.MD5" "791c88eca9836af8c34bf32b07cb58a7" "Cart.Manufacturer" "SpiceWare - Darrell Spice Jr." "Cart.ModelNo" "SW-05" "Cart.Name" "Stay Frosty 2 (PAL60)" "Cart.Note" "AtariAge Holiday Greetings 2014" "Cart.Rarity" "Homebrew" "Controller.Left" "JOYSTICK" "Display.Format" "PAL60" "Display.Phosphor" "YES" ""
-
1
-
-
Same issue will occur with Stay Frosty 2, if you don't switch it to Joystick then you won't be able to throw snowballs and thus get stuck on level 4.
-
With this:
while(getline (input,line)) { while(line.length() == 0) { getline (input,line); //get next line if line is empty (skip spaces between lines) } lines.push_back(line); }
you'll likely have problems if there are empty lines are at the end of the file. I would change it to:
while(getline (input,line)) { if (line.length() > 0) lines.push_back(line); }
-
1
-
-
29 minutes ago, TwentySixHundred said:Ok so i have thrown this together quickly for the purpose to test this and have made the program deliberatly only update DFxFRACINC line during the main loop.
That uses driver 5f80b5a5adbe483addc3f6e6f1b472f8:$ dd count=3 bs=1024 if=jitter.bin | md5 3+0 records in 3+0 records out 3072 bytes transferred in 0.000034 secs (90738746 bytes/sec) 5f80b5a5adbe483addc3f6e6f1b472f8
18 minutes ago, SpiceWare said:* at the moment Stella correctly emulates 3 of the 4 drivers.
At the moment driver 5f80b5a5adbe483addc3f6e6f1b472f8 is the one that Stella does not correctly emulate. With that driver if you leave out the DFxFRACINC then on real hardware the display is stable, but in Stella it jitters.
-
2
-
1
-
-
41 minutes ago, TwentySixHundred said:Interesting, how would we know exactly what driver is being used?
That's what I'm working on. I'm currently on step 1:
- Find as many examples of DPC+ games as I can. It's time consuming, which is why I asked for help.
- The driver is the first 3K of the game, I use the MD5 value of that 3K to identify the driver
- Figure out how each driver behaves on real hardware (stable vs jitter, and Encore compatibility).
- Update Stella's DPC+ Jitter emulation to match*
- Update Stella's debugger* to show the MD5 value and Jitter/Encore status
- Work my way thru the private Harmony and Stay Frosty 2 forums to figure out release dates for each version
- Update Stella's debugger* to show the release date
* at the moment Stella correctly emulates 3 of the 4 drivers.
* plan to show this info in the Description box of the CartridgeDPC+ tab.
-
1
-
11 hours ago, TwentySixHundred said:Thanks, so i am guessing DF4FRACINC is the only line that needs to be updated every drawscreen. This is interesting because once the colours are pushed to the TIA i would think they only need updating once unless the colour is changed ect? Does this have anything to do with how DPC+ stores the graphics data into RAM?
No, if you're using a version of the DPC+ driver that exhibits the jitter issue then DF0-DF3FRACINC need to be updated as well. If you're using the multicolor background feature then DF6FRACINC would also need to be updated before each use of drawscreen.
The issue is due to how the fractional data fetchers were implemented in the driver, the specifics of which I'm not familiar with as source for the driver is not available.
-
1
-
-
Most likely. Hope to eventually narrow down dates for each version I find.
-
32 minutes ago, satyrsfaction said:ok, let me know if that helped. Thanks!!!
That did it.
Scanlines aren't consistent when moving from room to room, that can cause jitter on some TVs.
You can see it in Stella using the debugger. Move to an exit, such as the one at the bottom then enter Stella's Debugger by pressing the ` key
Click the I/O tab, check the DOWN direction for the joystick, then click Frame +1 a few times until you see the Scanline Count change from 262 to something else.
-
On 3/5/2020 at 5:49 PM, satyrsfaction said:OK, i put the lines in every time I call drawscreen. Did it help?
On 3/5/2020 at 8:22 PM, TwentySixHundred said:Yep that's a huge difference and on the right track, only a very small amount of jitter. It's probably something to do with the collision detection code now 👍
The playfiled no longer jitters, but the colors used to draw the playfield does. Looking at this fetcher 4 is used for playfield colors, so adding DF4FRACINC before the call to drawscreen should fix it:
DF0FRACINC = 43 : DF1FRACINC = 43 : DF2FRACINC = 43 : DF3FRACINC = 43 DF4FRACINC = 50 drawscreen
-
1
-
-
We're trying to get a handle on the screen jitter issue that can occur in some DPC+ games if the Fractional Data Fetcher Increments are not reset on every frame. There's a number of versions of the DPC+ driver floating around, some of them exhibit jitter while some of them do not. Stella also selectively emulates the jitter issue, but is not aware of all the versions of the driver so whether a given ROM jitters or not in Stella may not match what's seen on real hardware.
To that end I've written a script file that'll find all the unique DPC+ driver versions when provided a set of ROMs. So far I've found 4 DPC+ driver versions. What I need now is more DPC+ games to see if I can find any other versions so we can make Stella emulate them correctly. Please add ROMs or links to DPC+ games in this topic.
If you're curious about this issue you can run these versions of Doom Patrol that have been merged with the 4 DPC+ drivers I've found so far. The hexadecimal numbers in the filenames are the MD5 value of the DPC+ driver used in that ROM. If you'd like more info about this check my recent blog entry (and the comments) DPC+ Jitter.
This one jitters on real hardware, and in Stella
DP_17884ec14f9b1d06fe8d617a1fbdcf47.bin
This one is stable on real hardware, incorrectly jitters in Stella.
DP_5f80b5a5adbe483addc3f6e6f1b472f8.bin
This one is stable on real hardware, and in Stella.
This DPC+ driver is also NOT compatible with the Harmony Encore, the other 3 are.
DP_8dd73b44fd11c488326ce507cbeb19d1.bin
This one jitters on real hardware, and in Stella.
-
1
-
-
If you check the source in Part 2 you'll see I set REFP0 3 times.
During Vertical Blank for the Sun:lda FrostyX cmp CelestialX bcc .facingLeft lda #%00001000 sta REFP0
After the horizon is drawn for Frosty:lda FrostyControl lsr lsr sta REFP0 ; set Frosty facing left or rightAnd before drawing the score:
lda #0 sta HMP0 sta REFP0 ; reset in case Frosty was facing leftFor Frosty the left/right is calculated during OverScan and saved in bit 5 of the RAM location labeled FrostyControl (hence the use of LSR, LSR):
FrostyControl ds 1 ; 76543210 ; 5 = 0 facing right, 1 = facing left ; 43210 - 0 to 31, jump height OverScanCode ... lda FrostyControl and #%11011111 ; set facing right sta FrostyControl ... lda FrostyControl ora #%00100000 ; set facing left sta FrostyControl-
1
-
-
41 minutes ago, pvmpkin said:Do you have an example of how this is achieved in code, how one kernel has isolated instructions (for example unique REFP0) from another ?
There's an unfinished series covering the development of Stay Frosty in my blog. I used to have all my blog entries flagged with categories to make it easy to find things, but sadly the last forum upgrade eliminated categories. But if you go to the overview of my blog and click on page 5 you'll see parts 1 & 2. On page 4 you'll find parts 3-9. On page 2 you'll find part 10.
Part 2 should help with what you're looking for. At this point in its development you can move Frosty around the screen:If you use Stella's Developer Key for Fixed Debug Colors mode (COMMAND-COMMA on Mac, ALT-COMMA on Linux & Windows) you can see how the screen is drawn:
By the red color you can see the sun, Frosty, and parts of the score & lives are all drawn using player0. The sun moves across the screen and always looks at Frosty, which is done by setting REFP0. Likewise Frosty faces left/right based on the direction you're moving, once again by setting REFP0. REFP0 is cleared before drawing the score.
Note that the source doesn't cleanly break apart the kernels. The Horizon Kernel is basically this bit of code:
.HorizonLoop sta WSYNC cpx #8 ; 2 bcs .skipHills ; 2 4 lda HillColor,x sta COLUPF lda Hill0,x ; 4 8 sta PF0 ; 3 11 lda Hill1,x ; 4 15 sta PF1 ; 3 18 lda Hill2,x ; 4 22 sta PF2 ; 3 25 .skipHills txa sec sbc CelestialY adc #CELESTIALHEIGHT bcc .skipCelestialDraw tay lda (CelestialImagePtr),y ; .celestialDraw sta GRP0 ; dex ; 2 44 bpl .HorizonLoop ; 2 46Once it finishes it does some prep for the game kernel:
inx stx WSYNC stx CTRLPF ; repeated playfield for game screen stx COLUBK stx PF0 stx PF1 stx PF2 lda FrostyControl lsr lsr sta REFP0 ; set Frosty facing left or right lda FrostyX ldx #0 jsr PosObject lda #0 ldx #148
The game kernel is this bit:.testloop sta WSYNC sta GRP0 sty COLUP0 cpx FrostyNoseY php pla sta ENAM1 txa sec sbc FrostyY adc #FROSTYHEIGHT bcc .skipDrawTL tay lda (FrostyImagePtr),y .frostyDraw pha lda (FrostyColorPtr),y tay pla dex bne .testloop beq .score .skipDrawTL lda #0 beq .frostyDrawand so on for the prep for the score and the score kernel.
-
1
-
-
The kernel is the portion of your code that updates TIA in real time to draw the visible portion of the display. Updating TIA to position players during vertical blank is not part of the kernel, though it is prep for the kernel.
The kernel is often broken up into multiple kernels that handle specific parts of the screen. A game like Combat has 2 kernels:
Stay Frosty has multiple kernels:
The Game Kernel in Stay Frosty is actually broken up even more with kernels that repeat going down the screen. Besides drawing the screen they also do some prep work:
- Air Kernel - draws snowman, resets TIA collision registers, repositions player1 (multiple fireballs), draws tops of fireballs
- Ice Kernel - draws snowman, ice blocks, bottoms of fireballs
- Platform Kernel - draws snowman, platforms, saves TIA collision registers which get processed during overscan
-
I've written a tutorial that may help you in your endeavors. It covers writing a 2K game from scratch, with lots of comments in the source code to explain what's going on.
-
1
-
-
Sure, you write multiple kernels to draw the screen. It's normally easier* to put the score at the bottom for this. Instead of:
- Vertical Blank = game logic, position players, etc.
- Kernel = draw entire screen
- Overscan = additional game logic
You'd do this:
- Vertical Blank = game logic, position players, set REFP0, etc. for the game kernel
- Game Kernel = draw large upper portion of the screen, where the action takes place
- Prep for Score Kernel = use 2-3 scanlines to position players, set REFP0 etc. for the score kernel
- Score Kernel = draw small lower portion of the screen, where the score is shown
- Overscan = additional game logic
* The reason it's easier is the routines to position the players take a variable number of scanlines depending on the X position. That'll cause jitter if done in the middle of the visible portion of the screen. You can work around this, but it complicates things when you're learning the 2600.
-
2
-
14 minutes ago, JeffJetton said:And, as an aside, some computers like the ZX80 and (when in "fast" mode) the ZX81 would routinely drop the video signal logic when it came time for any sort of intensive calculations.
The 40 column display on the C= 128 would blank out if you switched it from 1 to 2 MHz mode. I wrote an IRQ routine that would turn on 1 MHz mode while the visible 200 scanlines were drawn, then turn on 2 MHz mode for the 62 scanlines that made up Overscan and Vertical Blank. Basically giving you 324 scanlines worth of processing per frame, about a 23% speed boost. It also worked when running C=64 software on a 128.
QuoteAnother option is to simply reduce the number of scanlines used for the visual part of the game, rather than get rid of them all together. That would give you more time in the overscan and/or vertical blank for "thinking", at the expense of a more "letterbox" image. Didn't a lot of carts use that trick?
I've not reviewed the games looking for that, but I did point out once that Draconian used fewer scanlines than my other games.
-
-
5 hours ago, stephena said:The changes you made in that link to CartDPCPlus.cxx are exactly what I was referring to above. There is an older mask ($F0000) and a newer mask ($F00FF). If I manually set the code to use the old mask, it works fine. The default is to use the new mask, of course.
@SpiceWare, where did the idea come from to change this mask? I always assumed it was because of a change in the DPC+ driver behaviour, but now I'm not sure what the actual logic was???
Don't recall where the idea came from, it was almost 5 years ago. Change was done to match what was seen on real hardware when the DFxFRACINC registers were not updated in Doom Patrol. I just finished doing some research that suggests Stella's DPC+ driver could be changed to this as there's actually 2 versions of Epic Adventure, one that runs on the Harmony Encore:
CartDPCPlus.cxxstring md5 = MD5::hash(image, 3_KB); if(md5 == "8dd73b44fd11c488326ce507cbeb19d1" || md5 == "5f80b5a5adbe483addc3f6e6f1b472f8") myFractionalLowMask = 0x0F0000;
The Encore version uses the same driver that Space Rocks and Stay Frosty 2 use, so maybe it would make better sense to swap the mask values in the header and C files, then check for the DPC+ driver used in Doom Patrol.
CartDPCPlus.hxxuInt32 myFractionalLowMask{0x0F0000};
CartDPCPlus.cxx// DPC+ driver used in Doom Patrol 0.5 exhibits jitter on real hardware if the DFxFRACINC registers are not updated if(MD5::hash(image, 3_KB) == "17884ec14f9b1d06fe8d617a1fbdcf47") myFractionalLowMask = 0x0F00FF;
The research is in this blog post:

Portland Retro Gaming Expo 2020, August 14th-16th
in Events
Posted
PRGE 2020 has been cancelled