DavidEth
Members-
Posts
62 -
Joined
-
Last visited
Content Type
Profiles
Forums
Blogs
Gallery
Events
Store
Community Map
Everything posted by DavidEth
-
SpiceWare, I don't understand what's going on here: SetChopper0: lda #ChopperGraphicHeight clc adc Chopper0Y cmp #ChopperGraphicHeight bcs NoYadjustC0 lda #$FF .byte #$2c NoYadjustC0 lda #$0 sta NegativeYadjust sec lda TempPtr sbc Chopper0Y sta DF0LOW lda TempPtr+1 sbc NegativeYadjust sta DF0HI Seems like it's comparing Y+8 to 8 and using the result of that test to store 0 or -1 into an adjust value. Seems like it could just be comparing Y to zero directly? -Dave
-
Yeah, that would work too. I'm not sure how useful adding zero would be anyway, since you can achieve the same end (assuming 0.8 fixed point) by using 1/256th, which will not overflow for another 255 scanlines either. Main problem with always adding 1 is that it throws off all the rest of the fractions (although 0x100 - FRAC is even worse in this regard). -Dave
-
In the big scheme of things none of this matters, but since this is all just firmware anyway, there are three possible "fixes" to this nonexistent problem: 1. Treat 0 as a special case meaning 256, either implicitly, or by having the "hardware" add 0x0100 - FRAC. 2. Make the fractional value 1.7 or 2.6 instead of 0.8; this would also let you zoom out a playfield vertically, for whatever that is worth. 3. Whenever the address is rewritten (which presumably zeroes out the fractional LSB's), just set the LSB's to %0000 0001 instead of pure zero. -Dave
-
So is the priming read just because you're using 1.8 fixed point with only 8 fractional bits? In other words, without the priming read, you're going to return the first data twice, because if the counter starts at zero and the most you can add is 255, you'd get: 0x0000 - return line 0 0x00FF - return line 0 0x01FE - return line 1 0x02FD - return line 2 0x03FC - return line 3 It wouldn't repeat a line again for another 255 or so scanlines, typically more than you're ever going to render on a 2600. -Dave
-
I wanted a fully programmable playfield and two full color sprites and quickly realized that DPC+ with fastfetch would let me focus on writing a game instead of a bunch of custom kernels. I cut and paste a bunch of the sample code and got my own app working. Nothing special about my code otherwise, but it might be easier to start with. (Note that my code doesn't bother to do the special "priming read" that SpiceWare's code has in it, been meaning to ask him about that) -Dave Note: Example sprite from this thread -- http://www.atariage.com/forums/topic/169238-free-sprites-for-the-taking/ -- courtesy of PAC-MAN-RED. hack2600.zip
-
I probably don't understand your question, but here are the standard 2600 headers. http://www.atari2600.org/DASM/Atari2600_1_10.zip -Dave
-
Looking at the game, you might be able to do it with both missiles and the ball combining to allow up to three "drops" per scanline. Every such tuple would share a single Y coordinate but would have unique X coordinates. Assuming you got creative and made the row implicit, you'd need probably four bytes to hold three positions and three X velocities, which would give you maybe 60 bullets on the screen at once. Another option would be to table a bunch of spread patterns in ROM, and just remember which pattern is active (so a single spread pattern may be 50-60 bullets, you just remember which pattern is active, and perhaps apply a slight random offset to each frame) -Dave
-
Minor update to above, finally got REPEAT / RENEND working in nested case. BOUNDARY macro in climber5.asm is still screwed up, although I think the ALIGN operation does the same thing. Climber5 also has some duplicate symbols because of the way it implements overlays. -Dave my2600src.zip
-
/* ChangeLog 28 Sep 2010 - More refactoring of assembler and debugger - Implemented BRK and RTI (BRK was necessary for cave1k) - Cleaned up insn decoder, added expected insn counts for clarity, assert they match at runtime - REPEAT / REPEND work better now (well, they don't quite nest yet, see dkong.asm) - Can write assembler output to a file now. - SEG.U turns off initialization, SEG turns it back on - ORG and RORG can now be used to generate at least 8k roms (bzone.asm, montezuma.asm). */ -Dave my2600src.zip
-
Started keeping a proper changelog. Got massively sidetracked improving the assembler so I could hack on more of the example code out there quickly and easily. Not convinced REPEAT/REPEND handling is quite correct yet. - VDELBL was broken, Pitfall vine works again - Assembler improvements: - * and . equate to program counter - File inclusion works - IFCONST, IFNCONST work - Preserves case on everything except opcodes - Opcode parsing improved - Don't need -a flag any longer, just pass in .asm file - No longer has built-in version of VCS.H, but can re-enable with -V flag. - .z opcode suffix forces zero page (like .w) - MAC / ENDM / SET / EQU now understood. SET and = can reassign values, EQU cannot. - REPEAT / REPEND now understood. - local labels work (inherits context from macro invokation line and/or SUBROUTINE) - Runtime trace displays effective address and contents of memory when appropriate - SDL usage can be completed compiled out - Added DCP opcode - Messed around with VBLANK/VSYNC handling a bit my2600src.zip
-
I think FE bankswitching just works by switching on any access to $FE The main program is stored in one bank and all subroutines in the other. The stack pointer is set to $FF at startup and any jsr will push values to $FF and $FE the rts will then pull values from $FE and $FF. But I thought that the cartridge is never going to see any access to $FE. In other words, bit 12 of the address line of the 6507 is wired to the "cartridge select" line? -Dave
-
Interesting -- that must be how FE-style bankswitching works on Robot Tank then? Hardware on the cart itself sees if an opcode being fetched is a JSR or RTS and behaves accordingly. How do you tell fetching a JSR opcode (or in your case, LDA #imm) apart from just a normal data read? (Is the source code to the Harmony BIOS available? The 1.05 download I tried only had a bunch of .arm binary files) -Dave
-
Okay, Conquest of Mars had the same lockup on startup problem Berzerk had. It was setting the interval to 64 and doing a series of STA WSYNC / LDA INTIM / BNE TOP checks, and it would skip hitting exactly zero. I hacked around it by nerfing the RIOT behavior of resetting the decrement interval to 1 once INTIM reaches zero, but I suspsect something else must be going wrong here? Conquest of Mars also didn't produce a display because my emulator only resets the raster back to the top when it sees VBLANK D2 go from one to zero, which has worked well on other cartridges. When VSYNC D2 goes from 1->0, I flip the screen buffer and process events. When VBLANK D2 goes from 1->0, I was resetting the emulated raster to the top, but it seems like Conquest only ever writes 0 to VBLANK, is there some special reason for that? (I also have to track down what opcode 0xC7 is, I'm guessing it's DCP) -Dave
-
Seems like it could work -- the mountains in Chopper Command might be doing it. Assume I have a grid of squares, and I want each square to have an arbitrary color based on terrain type. (Using SCORE mode works great for games like Medieval Mayhem, not sure it applies here) Assuming I had a subroutine for each of several combinations of terrain, can I hit COLUBK multiple times per scanline and expect it to work on real hardware? Seems like the fastest I could do it is every 9 color clocks (a bunch of STA/STX/STY COLUBK's to pick between three colors), but that doesn't line up with the playfield and I would be unable to update the playfield registers either. Every color clock being 3 cpu cycles makes it a bit of a pain in the ass to line up though. Does the write from the CPU happen on the last cycle of the instruction? ST{AXY} COLUP0 ; 3 cycles, 9 color clocks; 17 tiles across, only 3 colors. ST{AXY}.w COLUP0 ; 4 cycles, 12 color clocks. 13 tiles across. Playing field would line up at least. LDA #NN STA COLUP0 ; 5 cycles, 15 color clocks. 10 tiles across. Arbitrary colors. LDA #NN STA.w COLUP0 ; 6 cycles, 18 color clocks. 8 tiles across. Arbitrary colors. LDA #NN NOP STA COLUUP0 ; 7 cycles, 21 color clocks, not very useful. LDA #NN STA zp_dummy STA COLUP0; 8 cycles, 24 color clocks. 6 tiles across. Playing field would line up. I guess the only practical one gives me a whopping 6 tiles across while still having enough time to update playfield registers too. If I wanted a bigger map I guess it could scroll? -Dave
-
I read the discussion here: http://www.atariage.com/forums/topic/162520-fine-positioning-not-working/page__view__findpost__p__2006722 and it clears up a lot of things for me, thanks. It sounds like people generally hit HMOVE on either: - Cycle 0 (right after a WSYNC) or cycle 75, giving you an eight-pixel black bar. - Or cycle 73 or 74, which eliminates the black bar but only lets you move the sprite left. -Dave
-
For anybody else following from home, http://www.qotile.net/minidig/docs/2600_advanced_prog_guide.txt. Brad's presentation was convenient for shoving into an emulator, but I agree, your version is handy for a human trying to achieve a particular effect in a game. -Dave
-
Okay, question about "late HMOVE" processing. When I fixed Halo 2600, I ended up breaking River Raid. If I tweak the offset within the HMOVE adjustment table, I can fix River Raid but then Halo 2600 breaks. So I guess I'm asking, when do people generally hit HMOVE? River Raid hits it on color cycle -68 and cycle 157, meaning both the first and last cycle on a scanline. Ed mentioned that Halo hits it on cycle 74. I think that was a CPU cycle though? So if I understand things correctly, hitting HMOVE at the beginning of the scanline can cause the ugly black borders. So people try to hit it later on (dealing with the fact that it's interpreted strangely) to hide the bars? I started with the table at http://www.bjars.com/resources/hmove.txt, but had to move all the lines marked HBLANK to the top of my table, because I index the 76 entries at (color_cycle + 68) / 3, where color_cycle ranges from -68 to 159. I can't seem to find a consistent bias there that works for both River Raid and Halo 2600. The really tricky bit is that there's a huge discontinuity between the last and first cycles. EDIT - Are there circumstances where hitting HMOVE always works the "documented" way? I think River Raid glitches out when it's trying to position something that is just scrolling onto the screen from the top. So maybe HMOVE always works properly if it's hit when we're in vertical blank? If I put back my old code which always did an HMOVE as a straight "value minus (factor >> 4)" River Raid works again. EDIT 2 - It seems that if HMOVE is hit on the first scanline, I should ignore any compensation factors. Both River Raid and Halo 2600 work. New version attached with both Halo 2600 and River Raid working. Also finally tracked down the gaps in the copyright strings, and it was really mundane -- my repeat counts for duplicated sprites was off by a cycle because they didn't get decremented on the cycle they were refreshed. -Dave my2600src.zip
-
Another minor update, added support for TigerVision (-T flag on command line) and Parker Brothers (-P flag on command line) ROM bank switching methods. I'm curious how the FE method used by Robot Tank and Decathalon can "detect" a JSR / RTS and bankswitch properly. Only other method still to implement is the M-Network method, but it has some crazy RAM decode. I think for my own stuff, I'll stick to the standard F8/F6 variants and maybe use a superchip. EDIT - Included some compile fixes for non-PC systems, assembler works again. -Dave my2600src.zip
-
On a side note, I think I'm far enough along to justify picking up some actual 2600 hardware. Obviously I want the Harmony cart, but I'm wondering what I should plug that into? Just buy an old 2600 off of ebay and hope for the best? I've got some old CRT televisions around here so the AV mod isn't too important. Would I be better off trying to track down a 7800? I think I have an old Sega Genesis with some controllers too, those will work in a 2600, right? -Dave
-
Another minor update. Implemented a bunch of NOP variants, along with LAX and SAX. Also added a four-stage delay to writes to the playfield registers to fix the Halo 2600 title and the ladders in Mountain King. No idea why the delays are really needed, but hey, it works now. The delays run even during HBLANK, otherwise the leftmost edge was getting screwed up. Earlier today I noticed that Berzerk was hanging on startup again (the original reason for this thread) and had to initialize INTIM to a minimum of 3 to get it to not hang. But the good news is that the game appears to work pretty much perfectly now! -Dave my2600src.zip
-
DASM uses square brackets for arithmetic grouping. Ordinary parentheses will also work for arithmetic grouping in some contexts, but will be interpreted as special addressing modes in other contests. I tend to just use square brackets in DASM instructions whether or not it's necessary in any particular context. For example: if FOO is $4321 and BAR is $1234, "JMP [FOO-BAR]" will be regarded as "JMP $30ED", while "JMP (FOO-BAR)" will be assembled as "JMP ($303D)", a different instruction. That makes a lot of sense, thanks for explaining that. I've done a lot of x86 programming in the years between when I did 6502 and now, so it was never an issue because that platform already used square brackets for indirect addressing. Okay, some questions on DCP, LAX, SAX, SBX (the four instructions recommended as being critical on the 2601 blog) (They also mention a two-cycle NOP -- but I thought that was 0xEA already? Is there a different one?) Based on the explanations on http://www.oxyron.de/html/opcodes02.html, DCP is unclear. Should it really be: {adr}:={adr}-1 and then A:=A-{adr} and does A have the old or newly-decremented version of [adr] in it? EDIT - According to a NES page, it computes A-{adr} (the newly decremented value) like a compare and doesn't store the result, just tests the flags. LAX and SAX both seem pretty simple. I assume they take the "usual" number of cycles for a load operation and a store operation? Finally, SBX is nowhere to be found on that page. -Dave
-
While that demo doesn't work on my emulator at all, I clicked through your avatar picture and tracked down MedievalMayhem and added 32k ROM support for it. It pretty much works (except for the gaps in the text, and no paddle support, and that VDELP0 "smear" bug)! My emulator was spewing "riot_read - unexpected read from 9" and after setting a breakpoint in my emulator and digging around, I finally found this code: .notDead2 lda #7 ; draw king shape, a player still lives .byte $2c .bothDead lda #15 ; don't draw king shape, they're both dead Issue a BIT to a dummy address to skip the lda #15 insn, neat trick. Just happens to resolve to a bogus address but it's ultimately harmless. I haven't done any serious 6502 programming since the early 1980's, it's pretty fun to dig back into this stuff again. -Dave EDIT: Add support for NOP x instruction (I call it NP3 in the assembler although I just realized I don't really need to do that). Added 32k ROM support, and cleaned up the bank switching code so that it doesn't do a stupid parallel compare on every access. my2600src.zip
-
Nice! Although I have to implement the 3-cycle NOP now... looks like it's instruction 4. In macro.h, the syntax is "NOP 0", is that correct? What is the 0 supposed to mean? Wait -- lemme guess, that's the address it will issue a bogus read to, since it's really a "zero page direct" opcode? -Dave
-
Okay, time to try to get my VDELP0/1 logic exactly correct. Here's how I handle writes to GRP0: case GRP0: if (tia_state[VDELP0] & 1) grp0_delayed = val; else grp0_current = val; if (tia_state[VDELP1] & 1) grp1_current = grp1_delayed; break; When the player horizontal motion counter goes to zero, I load the serial register with grp0_current. Does this logic seem correct? It mostly works, but there are some bugs that indicate I'm missing an edge case. Should that grp1_current = grp1_delayed actually *exchange* the two registers, by chance? -Dave
-
Transcribing that table and fudging the offsets got the player working in Halo 2600, although the visor isn't matching up because I only applied the rules to P0 and P1 since the table mentioned HMPx at the top. Should I be using the same table for everything, or just the player and ball? Nevermind, looks like I should apply it to everything, Halo 2600 looks pretty good now. EDIT: Latest version, fixed HMOVE mid-scanline handling. Good to know that hitting HMOVE in the middle of the scanline is useful for avoiding the ugly margin bar. Also added a scanline debugger on PgUp/PgDn and Home/End which causes instructions only for the current scanline(s) to be dumped out in the trace window. EDIT 2: Also, when I implemented HMOVE properly, I was able to take out the other two hacks to avoid weird collision issues on Halo 2600. Trying to think what's left here - 1. I'm pretty sure I don't have VDELP0/1 logic quite right yet -- the score in Yar's Revenge and the humans in Stargate both have weird bugs. Probably also explains the one-pixel gaps in Activision logos and River Raid fuel gauge. 2. Sound, obviously. 3. Hitting HMOVE and/or RESP0/1 in the middle of a scanline doesn't work right yet for Galaxian-style sprite duplication. For item 3, if I understand things correctly -- if you hit RESP0/1, it doesn't take effect until the next scanline, UNLESS you're using "multiple copies" mode and you haven't picked up one of the second copies yet? So you could set your mode to two copies, then hit RESP0 on the previous scanline to set the first copy horizontal position, then hit RESP0 again multiple times on the current scanline to scan out more copies? But then how do you get the original position set again? -Dave my2600src.zip
