Jump to content

EricBall

Members
  • Posts

    2,427
  • Joined

  • Last visited

Blog Entries posted by EricBall

  1. EricBall
    I love that I can download demos for my (new) PS3. Yeah, I can pay for and download Virtual Console games for my Wii, but nothing beats free. Last night I added Lucasart's Force Unleashed demo to the list of PS3 games & demos I've downloaded.
     
    In this demo, you're Vader's secret apprentice out on his first misson to eliminate one of the remaining Jedi, along with whoever & whatever gets in your way. Yes, you have a lightsaber, but in a lot of cases you'll be throwing stuff around with the power of the force (think Darth vs Luke in Cloud City), including rebel & Imperial troops. There's also a combo system, so slash, slash, lightning charges up your 'sabre for a major attack. The demo is just the right length - long enough to figure out whether it's worth buying, but short enough to finish in a sitting. (Actually, I think it took longer to download & install than to play.)
     
    I have one major and one minor criticisim. The big one is the 3rd person 3-D camera - it has a habit of looking at me rather than whomever is shooting at me. Yes, it can be manually adjusted, but I'd rather not have to move my thumb off the action buttons to adjust the camera. My minor quibble is the demo doesn't tell you what the status buttons in the corner mean/do and how "force points" (which upgrade your force powers) work.
     
    But it's a fun demo, and I'd probably be thinking about buying the full game except I don't think the content is appropriate for my 8 year old son. So I guess I'll play the demo a couple more times after he goes to bed before I delete it.
  2. EricBall
    I've finally finished (and debugged) my Fast Discrete Hartley Transform for the Propeller. It takes 2^N signed 32 bit input samples and produces the output in the same array. I've measured the following:
    16 samples in 12,496 clock cycles
    64 samples in 87,648 clock cycles
    256 samples in 534,656 clock cycles
    1024 samples in 2,899,504 clock cycles
    4096 samples in 14,668,112 clock cycles
     
    At 80MHz that's 27.5 1024 sample DHTs per second!
  3. EricBall
    Sample code (unoptimized). Comment if you want more details.
    L = log2(N)for i = 0 to N-1 j = bitreverse( i, L ) if j > i then t = x[i] x[i] = x[j] x[j] = t endifnext ifor i = 0 to N-1 step 4 t0 = x[i] t2 = x[i+1] t1 = x[i+2] t3 = x[i+3] x[i+0]=(t0+t1+t2+t3)/2 x[i+1]=(t0+t1-t2-t3)/2 x[i+2]=(t0-t1+t2-t3)/2 x[i+3]=(t0-t1-t2+t3)/2next ifor o = 3 to L s = 1 << o h = s / 2 q = s / 4 for i = 0 to N-1 step s t0 = x[i] t1 = x[i+q] t2 = x[i+h] t2 = x[i+h+q] x[i] = t0 + t2 x[i+q] = t1 + t3 x[i+h] = t0 - t2 x[i+h+q] = t1 - t3 for j = 1 to h-1 t0 = x[i+j] / sqrt(2) t1 = x[i+h-j] / sqrt(2) t2 = x[i+h+j] / sqrt(2) t2 = x[i+s-j] / sqrt(2) x[i+j] = t0 + t1 * cos(2*pi()*j/N) + t3 * sin(2*pi()*j/N) x[i+h-j] = t2 + t1 * sin(2*pi()*j/N) - t3 * cos(2*pi()*j/N) x[i+h+j] = t0 - t1 * cos(2*pi()*j/N) - t3 * sin(2*pi()*j/N) x[i+s-j] = t2 - t1 * sin(2*pi()*j/N) + t3 * cos(2*pi()*j/N) next j next inext o
  4. EricBall
    Most developers understand it is possible to trade off space for speed, e.g. unrolling loops or using table lookups instead of complex calculations. This is particularly true for low level programming where you are often trying to squeeze out the maximum speed in the minimum space. But I've recently discovered Propeller Assembly (PASM) it's possible to maximize speed and minimize space simultaneously.The Propeller is different from most processors in there are no dedicated ALU registers. Instead, any 32 bit entry in processor RAM may be used as a register. Thus processor RAM can be looked at as a 512 entry register file. Or 496 instructions (16 of the registers are dedicated to I/O), with each instruction taking a single register. Or 496 32 bit data values. It is even possible (and sometimes necessary) to modify an instruction using ALU operations.In the program I'm working on, I've programmed two 16.16 x 0.16 fixed point multiplies; multiplying one value twice (by cos & sin). In pseudo code:
    frac = fixed & 0xFFFF int = fixed >> 16 frac_cos = cos * frac int_cos = cos * int/* because the algorithm destroys the inputs, they must be reloaded */ frac = fixed & 0xFFFF int = fixed >> 16 frac_sin = sin * frac int_sin = sin * int Now, in a normal speed optimization, you'd look and see that the same value is being calculated twice. So to speed things up, you save the value (more space) so the calculations don't have to be done again. But in PASM this sometimes doesn't save any time and ends up taking additional space!
    mov frac, fixed // frac = fixed and frac, H0000FFFFF // frac &= 0xFFFF H0000FFFF is a register which has the appropriate value preset mov sav_frac, frac // sav_frac = frac save the value in a temporary register... mov frac, sav_frac // reload value As you can see, calculating the value requires 2 instructions. Saving the value requires 1 additional instruction, and the reload is an instruction. So calculating the value requires the same number of instructions as save+reload, but the save+reload requires an extra register (sav_frac). So save+reload isn't any faster and requires more space!Obviously this is a simple example which only required one instruction to calculate each value. But the converse is also true. In another part of the program I am finding it's better to maintain additional variables rather than calculating the necessary value from the loop counters.
  5. EricBall
    Last friday was my son's 9th birthday, so I got him Scribblenauts for the DS. After playing through the first world (11 "puzzle" levels and 11 "action" levels), I have to say I'm fairly impressed. The game manages to squeeze a mind boggling number of items onto the cartridge. And there's another nine worlds to be played through (each with 11 puzzle & 11 action levels). I also like how it makes you think - and the spelling is a good "edutainment" angle.And yet, I have a few complaints:
    Handwriting recognition is hit & miss. You'd think after 20+ years of research and improvements in computing power that it could accurately recognize "R" correctly rather than "P" or "K". I'd prefer to write than use the keyboard, but the mistakes can be frustrating and make writing slower than tapping. I end up using a jetpack more often than I'd like. And there doesn't seem to be an obvious alternative. It's also something which isn't shown - so if you didn't think of it you could get very stuck. Some puzzles are very picky (and tricky), while others seem to almost accept anything as the correct solution. (However, I did have fun seeing what clothing items I could put on the maniquin - including garters & a corset!
  6. EricBall
    My wife saw Beatles Rock Band in the store the other day and made some "wanna have it" noises. Now, although when RB2 & GHWT we talked about buying one of them, we never did. My main problem with them (and B:RB) is they are, at heart, rhythm games. You aren't just rockin' along to some tunes you know. Nope, the game want you to do the right thing at the right time, or no cookie for you. I downloaded an Aerosmith demo and played through it using my controller. (Yes, not ideal, but enough to get the basic flavor.) And, let me tell you, it's annoying when the song ends part way through and your avatar hangs his head in shame because you couldn't keep up with the beats. I also don't relish the thought of having a bunch of plastic instruments cluttering up my living room.But, what about a karaoke game? Singing along with songs sounds a lot more fun than trying to play a plastic instrument. Unfortunately, the two PS3 karaoke games are both less than perfect. While it's possible to download additional songs for both, I'm not really interested in paying US$1.49 per song. Plus, both have released sequels with exclusive content. Again, it's paying extra for the stuff I want. I'm still debating this one, but it's not the slam dunk which I wanted.The other idea is to get a DDR-style game. Exercise to the beat! Unfortunately, the first PS3 game won't be out 'til Christmas - after my wife's birthday.
  7. EricBall
    WB has pushed back the release of Lord of the Rings on Blu-Ray to next year. And although I'd love to have LotR on bluray, I don't care - cause this is the theatrical release, not the extended version. Annoyingly, WB hasn't mentioned anything about the extended version yet. But I can wait, I have patience.
  8. EricBall
    Last year I bought my wife a MacBook, which she loves. One of the cool tools provided with OS X is Time Machine, which will automatically back up any changes to an external hard drive. She has an external USB hard drive for this which she connects about once a week, but you're only as safe as your most recent backup.
     
    Apple also makes the Time Capsule, which is a WiFi router with a built in 1TB hard drive. With one of these, Time Machine would automatically back up her MacBook any time she's connected to the network. However, it has three problems: #1 it's a single drive so there's no protection from a hard disk failure; #2 I already have a WiFi router; #3 it's pricey - C$330.
     
    What I really want is a NAS - Network Attached Storage, which I could use for backing up all of my PCs, sharing folders, and maybe as a media server. And although Apple doesn't officially support using Time Machine with a NAS other than Time Capsule, three NAS vendors officially support Time Machine for their RAID models. (Using an unofficial hack for backups doesn't seem smart to me.) Of the three vendors (Buffalo - 2 models, LaCie - 1 model & Netgear - most models), the Netgear ReadyNAS Duo was my preferred choice because the hard drives could be upgraded.
     
    Unfortunately, the ReadyNAS ain't cheap (and neither are the others) - C$400 for the base NAS and C$300 for two 1.5TB drives. OUCH! Maybe Apple will create a RAID1 version of the Time Capsule. But, until then, it looks like I'll stick with the external drives.
     
    Note: One thing which I have learned is RAID1 can protect you against a disk failure, it won't protect you from theft, destruction, or failure of the NAS. So you really should back up the NAS too - preferably offsite.
  9. EricBall
    What do you think the following C should do?
     

    unsigned byte zmem[128*1024]; int read_word( int a, x ) { a = zmem[a++]<<8 + zmem[a]; ... }
    There are three (!) errors in the above code:

    precedence error : addition is done before shift
    order of operations : is a incremented before the second array reference?
    compiler bug : a contains a++ after the operation

    All three can be worked around by using a temporary variable. Here's another gotcha I ran into:

    int PC; void run( void ) { ... op2code( op & 31, zmem[PC++], zmem[PC++] ); ... }
    Looks reasonable, provide the next two bytes in the instruction stream as operands. Again, there are several potential bugs lurking:

    is PC incremented before or after the function call (tested - it's before, at least with my compiler)
    order of operations : which operand gets which byte?
    is actually PC incremented before the second array reference?

    #3 turned out to be not true - the same value was passed in for both operands. Again, recoding with temporary variables worked around the problem.
     
    In both of these cases, the code looks sane. The compiler doesn't flag them as errors. But the results aren't what you'd expect.
  10. EricBall
    This weekend my wife spotted Civilization Revolution for the PS3 at Walmart. She (and I) loved playing Civ (1,2&3) so she was immediately interested. I thought I remembered seeing a downloadable demo, but I couldn't find it. Silly me it's "Sid Meier's Civilization" so it's under S. Anyway, I downloaded it and starting playing Monday morning.
     
    They are cruel. This ain't no demo, it's the first third of the game in all it's glory. More than enough to make me remember why I spent so many hours playing Civ. I originally skipped the demo because some of the early reviews implied it was "dumbed down" for the console. While I understand that a Civ4 purist might scoff at the simplifications; I, for one, won't mind not having to micromanage each citizen.
     
    Unfortunately, you can't save your game in the demo. But I'm sure this coming weekend I'll be playing the full version.
  11. EricBall
    The Propeller projects I listed in a previous blog:
     
    PWM based waveform generator
    Done, but I'm not going to release it as the limitations outweigh the results. Since the waveform is hardcoded, there's no way to dynamically change volume. There's also no way to internally mix voices onto one channel. And, finally, the sound isn't that impressive. (I was hoping to get something which really sounded like a cello or trumpet.)
     
    single pin NTSC text display driver
    Functionally working 100% even without a filtering cap. Now I need to make the hardcoded variables into parameters and calculated values. I might even do a PAL version. Plan is to release this to ObEx.
     
    IF_NEVER timing tests
    Complete. All IF_NEVERs take 4 cycles, irrespective of the opcode. It would have been more interesting if it wasn't, but this result merely confirms the datasheet.
     
    Extend NTSC240H to have background tiles too
    On hold pending interest (mine and others).
     
    I think my next geek project will be the GH antenna.
  12. EricBall
    Found the typo/bug. Again, I was using MOV instead of MOVS and setting the PixelClocks to 0 (which means 256 clocks per pixel) when it should have been 1. So now I have beautiful color bars.
     
    Next steps:

    Put back in my rainbow display & check the colors are right (i.e. phase order correct)
    Variablize parameters
    Multiple cog action!

  13. EricBall
    I found a couple of bugs in my code (using MOV instead of MOVS and wiping out the pixel counter), and I've determined my 240 pixels will probably stretch into the overscan. But even with those bugs fixed I still didn't get anything more than a B&W picture. Hrmm... But, curiously, my video capture card picks up colors although it's not stable.
     
    Found a typo / miscalculation in the number of pixel clocks for the blanking. Getting closer, but still not 100% stable.
  14. EricBall
    Reset now works. This now resets the level (except for the level timer) back to the initial state.
     
    TODOs
    1. Make level timer difficulty (speed) dependent. i.e. At higher difficulties the timer will count down more slowly.
    2. Handle out of time & end of level (all gold picked up) states
    3. Start on the end-of-level scoring screen.
    4. Start on level loader
     
    I'll update the editor as soon as I get home and find my password.
  15. EricBall
    I've been toying with an idea for a 2600/7800 TIA music player for a while. The design point is to minimize the space required, near 1 byte per note. A single byte would contain both frequency and period (4 possible). Plus, there's 34 codes for notes which would be played for a single frame for percussion sounds.
     
    Anyway, I'm wondering if anyone has a suggestion for AUDC/AUDF values for the single frame codes. e.g.
    AUDC = 8 AUDF = 0 high hat
    AUDC = 8 AUDF = 8 snare
    AUDC = 15 AUDF =6 snare
    AUDC = 15 AUDF = 30 kick drum
  16. EricBall
    One of the classic complaints against the 7800 is it uses the 2600's TIA for sound. Maybe that could be used as an advantage.
     
    Imagine a TIA music editor which uses the 7800's graphical capabilities to display notes on a scale and to scroll in realtime during playback.
     
    My only question is how to get compositions out of the 7800 and back to a PC so the creations could be added to 2600/7800 homebrews. Maybe via a SaveKey <-> serial interface?
  17. EricBall
    I've merged in the initialization and display list builder code from 4K SpaceWar! 7800 and made the necessary tweaks to handle the moving zones. Fun! My main problem with this code was I kept running out of ZP RAM, which would push a (ZP),Y pointer variable to $FF, which doesn't work at all.
     
    I first ran into the problem when I put in the initialization code and tweaked the display list initialization (so the constant parts of the tile headers only get written once). Kaboom! So I dragged out the EP code and started undoing changes with no success. Then I started anew and did one thing at a time. Step #1 - add ZP RAM variables. Kaboom?!? DASM really should warn you when DS crosses a page boundary....
     
    Okay, so that's working. I need to write the code to create the last display list based on the first display list so top/bottom wrap around works. I also want to see if there's any cycles I can squeeze out of the display list builder code somehow then do a cycle count (ugh!).
  18. EricBall
    The starfield now move up and down, following the sine wave, though in 8 line jumps. Smooth scrolling is next, but that requires some display list & display list list magic.
     
    I've also started using a 6502 simulator for general debugging. Since a lot of 7800 code is data movement, it's reasonable to use a general 6502 simulator. I caught a couple of bugs this way. The biggest problem is the built-in assembler isn't DASM compatible and isn't as capable.
     
    I've also made some major improvements to the SINE routine:

    SINE LDX #3 ; y[n+1] = y[n] - y[n-1] - y[n]/64K + y[n] SEC 3$ LDA STARY,X SBC STARYP,X STA STARYP,X DEX BPL 3$ LDA STARY+2 ; rounding EOR STARY ; reverse if negative EOR #$80 ; reverse for subtract ASL ; put in Carry LDA STARYP+3 SBC STARY+1 STA STARYP+3 LDX #2 4$ LDA STARYP,X SBC STARY ; sign extended STA STARYP,X DEX BPL 4$ LDX #3 CLC 5$ LDA STARY,X TAY ADC STARYP,X STA STARY,X STY STARYP,X DEX BPL 5$
    Some of the changes are because StarY is 9.16 bits, so the MSByte is either 0 or -1 ($FF). This means the -y[n]/64K can use that byte directly as a sign extend rather than having two branches. The rounding calculation is also much simpler, again no branching required. I also realized I didn't need an extra temporary variable.
     
    Oh, I've also decreased the number of stars to those less than magnitude 5. I still can't pick out constellations though. FoV = 61 degrees horizontal, 42 degrees vertical which is fairly wide.
  19. EricBall
    Saturday my wife declared she had suffered enough cabin fever and declared we were heading out, preferably to a flea market in the area. She was looking for Premier League jerseys (ideally an authentic Joe Cole Chelsea blue), but I was keeping my eyes peeled for stuff to add to my Nintendo collection (although I've given it up for Lent, 'cause she convinced my son to do the same). I think I saw two booths with used games and premium prices. My target price these days is C$10 so seeing stuff three and four times that price doesn't inspire me to search.
     
    But another booth had a small selection but better prices. When I went back for a better look I didn't find any games, but did pick up a Super GameBoy for C$8. It turned out that the stock was from a local Cash Converters, so we drove over there to see what they had. There were a couple of N64 games (Paper Mario for me, Mario Golf for my son) but they were both over my target price so I gave them a miss. Surprisingly they had a display case full of VCS games, though it was a little wierd to see the huge number of duplicates. (I mean 2 or 3 of a title I can understand, but 10+ Defenders?)
  20. EricBall
    Current status - static starfield complete (NTSC version)
     
    The next big step is turning the Star X,Y into DLL & DL entries and going to a dynamically built DLLs (one for on grid i.e. StarY&7=0) instead of the static DLL & DLs. Once that's done, I'll need to integrate the 4K SpaceWar! 7800 sprite to DL routine.
     
    Sorry if this is a little dense and cryptic. It's mostly for me to remind me of the design decisions which I've made (or remade).
     
    Reviewed old blog entries, found ROM memory map: 2K even star tiles, 22K (236x88) starfield tilemap, 2K odd star tiles, 2K code, 2K sprite graphics, 2K code/data/signature.
     
    Regenerated starfield tilemap & tile graphics from Yale Bright Star Catalog - all stars < 6 magnitude (visible to naked eye) mapped to 236x108 cylindar (avg of NTSC/PAL aspect ratio), trimmed to 88 rows. 236 tiles per row with first 20 tiles duplicated at end for easy wrap-around. 0,0 = bottom left (note: top left used for sprite positions) so StarY&7 is used for CHARBASE & SPRITE LSB offset on last row & sprite Ypos adjustment. Tile map stored with 0,0 at $8800. Quincunx (diagonal) sampling with bit 0 lower left and bit 1 lower middle right (next row middle at bottom middle left, right). 4836 stars in starfield.
     
    StarX is 2 bytes: 0-235 (row offset, two 4-byte DL entries per DL, width=21/20, handle wrap around by SBC & test) and -8 - -1 (Xpos + odd/even)
    StarY is 4 bytes (2+2 fractional). MSW is 9 bits (8 * (88-25 = 63 row) + 0-7 raster) stored as signed value for SINE routine, so the MSB is just a sign extend (very useful for the SINE routine). The initial values of StarY[n] and StarY[n-1] will need to be adjusted for PAL to keep the starmap onscreen.
     
    RAM will be primarily consumed by display lists (32 required for PAL). The two DLLs take up 213 bytes so can be stuck in $2100, which will extend into the stack page. That leaves 3.5 K for the display lists. Two possibilities exist. First, three 85 byte DLs per page. That nets 18 sprites per row. Second, allow the DLs to cross page boundaries giving 108-116 bytes per DL (depending on ZP overlap) with 24-26 sprites per row. Each player ship can use up to 4 sprite entries per row + shots. One option is to allow larger DLs for the rows which will contain the score etc.
     
    One important item for display lists, vertical scrolling and vertical wrap around. The current SW display list builder uses a additional DL pointer list entry for bottom to top wrap around. With vertical scrolling, the display list builder works in the same way. However, the bottom display list is basically just a duplicate of the top display list with the StarY & 7 offset! I will have to do some thinking to make sure the vertical shift can't push a sprite off the bottom of the screen.
  21. EricBall
    One of the things my mother-in-law brought with her was her copy of Wind Waker. Last night I sat down for an hour or so and played through the intro island. I really enjoyed playing both N64 Zeldas (though I prefer Occarina to Majora) and my hands instantly "remembered" the controls; pressing R to shift the camera and still pressing A to jump :-).
     
    The big change from the N64 Zeldas is, of course, the cell-shaded style graphics. My first thoughts were "ick, ugh, how annoying and distracting." But once I got into playing I noticed it less, so there's hope. Also, everything is still 3-D, so it's not like Paper Mario with 2-D characters in a 3-D world. Hmm... I'll have to check out the shadows the next time I play.
     
    The story set-up is also radically different from the N64 Zeldas; although I could see the sister-napping coming from the first "Big Brother". (Although I thought I might have been wrong when the sassy pirate first appeared.) It will be interesting to see whether saving the sister remains the driving force behind the game, or whether Link simply assumes the mantle of hero to rid the world of evil.
  22. EricBall
    My son got a DS lite as an early Christmas present (to play with on the plane). We also gave him "Super Mario 64 DS" and "New Super Mario Bros.", along with the GBA version of Activision Anthology which I happen to have...
     
    I have to say I'm amazed that the DS is able to do justice to SM64 from a graphics perspective. It really says what kind of 3D power it has under the hood. NSMB also has 3D graphics, but more in the Donkey Kong Country style - but rendered in real time instead of pre-rendered.
     
    Unfortunately, the DS is constrained from a controls perspective. Namely it doesn't have an analog joystick. Yeah, you can use the touch-screen as a pseudo analog joystick in SM64DS, but it's not the same. I wonder if it would have been possible to make the joypad pressure sensitive, with some kind of digital compatibility workaround for GBA titles.
     
    And that's my main complaint so far with SM64DS - the control scheme. Y for run works okay until you have to do a running jump. And why waste X on zoom? Maybe the touchscreen mode works better with the wrist strap / thumb stylus (not included with the DS lite) instead of the pen stylus.
     
    On the other hand, NSMB doesn't suffer from the lack of an analog joystick. (Both because it was developed specifically for the DS and it's heritage goes all the way back to the NES.) My main complaint with NSMB is you only get to save after defeating Bowser or Baby Bowser - twice per world instead of after every level. Now, that may be better than it's predecessors, but it still significantly increases the difficulty level of an already tough game. (Well, tough for my 6 year old son at least.)
     
    Unfortunately, we don't have any way to try out any of the wireless functions lacking a second DS or a game which supports playing over the Internet.
     
    Oh, and it is kinda cool to play Skeleton+ on the DS (without any unnecessary HMOVE bar removal which appeared in some of the other versions). The controls are a little weird (or at least not intuitive), but that probably comes from trying to adapt 6 switch + fire +menu to the 6 button GBA.
  23. EricBall
    One of Woz's design decisions for the Disk ][ was to force the MSB of each byte read to be 1. Although this restricted the number of values each byte could take, this was already restricted by the number of sequential zero bits i.e the time between changes in magnetic field; initally 1 (DOS 3.2), later 2 (DOS 3.3). But the restriction on the MSB had several positive side effects:
    1. The MSB could be used as an easy "data ready" flag by the CPU.
    2. The read sequencer could hold the completed byte even after the MSB of the next byte was received. This gave the CPU extra time to read the completed byte.
    3. Extra zero bits between bytes could be ignored, which allowed the read sequencer to automatically synch to a series of FF bytes separated by 1 or 2 zeros.
     
    One alternative would have been to store each set of 8 bits in a FIFO which the CPU could read. But then the CPU would need to perform the synchronization - determining the start & end of each byte.
     
    The following is a decode of the state machine for the DOS 3.3 Read Sequencer. For each state (n the left there)are four possible commands+next states depending on whether the MSB of the shift register is 1 or zero and whether a read pulse (change in magnetic field=1 bit) was received from the disk. Note: The command takes effect as part of the state change.

    MSB=0,RP=0 MSB=0,RP=1 MSB=1,RP=0 MSB=1,RP=1 0 NOP 1 NOP 1 NOP 1 NOP 1 1 SL1 2 SL1 2 NOP 3 NOP 3 2 NOP 3 NOP D NOP 2* NOP 0 3 NOP 4 NOP D NOP 4 NOP 4 4 NOP 5 NOP D NOP 5 NOP D 5 NOP 6 NOP D NOP 6 NOP D 6 NOP 7 NOP D NOP 7 NOP D 7 NOP 8 NOP D NOP 8 NOP D 8 NOP 9 NOP D NOP 9 NOP D 9 SL0 2 NOP D NOP A NOP D A SL1 B SL1 C NOP B NOP D B SL0 5 SL0 D NOP C NOP D C SL0 D SL0 D CLR A NOP D D NOP 0 NOP D NOP E NOP E E SL1 F SL1 F NOP F NOP F F SL1 4 SL1 D CLR E CLR E
    One important note is the "code" won't read the first byte correctly when entering read mode from "sense write protect" mode, which leaves the system in state 0 with the MSB in an unknown state. Maybe it was felt programs would typically leave the Disk ][ in read mode and there was no need to try to read the first byte after a mode switch correctly. Thus, the logical point to start figuring out the behaviour of the sequencer is to start with the "Hold" state which occurs when a byte has been completely read - state 2 with the MSB set, marked with a *.
     
    What this simple command+state does is ignores any zero bits between bytes. Once a read pulse is received it starts with state 0 (MSB=1) and continues down, ignoring any read pulses for the next 4 cycles, then waiting for the next read pulse or another 8 cycles. (It acutally waits up to 13 cycles total for a read pulse before deciding the bit is a zero.) If a read pulse is received then it jumps to state D (MSB=1), waits for another few cycles, then clears the shift register and shifts in the first bits. (The CLR naturally forces the MSB=0 for the next state.)
     
    This is all about holding onto the completed byte as long as possible as the CPU needs the data to be at least 7 CPU=14 state machine cycles (for RLOOP LDA $C08A,X + BPL RLOOP), even though there is only 4 CPU=8 state machine cycles between bits.
     
    On the MSB=0 the logic is fairly simple - wait for a read pulse. When RP=1 jump to state D, wait for RP=0, then jump back to state 0, wait one cycle, then shift in a 1. If no read pulse is recieved after 11 cycles then shift in a zero (it only waits 8 cycles for the second zero). The only trick is after the shift it jumps to state 2, which kicks over to the "Hold" state when the MSB=1 after the shift.
     
    One interesting item is how the "code" tries to mask unstable read pulses. In some cases the state transitions after a read pulse is received ignore futher read pulses for several, but in other cases (such as state D MSB=0) the code loops indefinitely waiting for the read pulses to stop. This is done because the the magnetic transition might "ring" (in either the magnetic or electrical domain) causing extra pulses (hopefully an even number); so it makes sense to somehow ignore them.
     
    Waiting for the read pulses is more efficient, but this affects zero bit detection. In theory bits would occur every 8 state machine cycles, since that is the timing of the write sequencer. However, that assumes the disk is rotating at exactly the same speed as it was written (and there is no jitter in the clock supplied to the state machine, which I believe there is). Thus the read sequencer needs to allow for some variation - both fast & slow. Where problems can arrise is with two quick zero bits, or where there is 3 * ( 8 - ? ) - 1 cyles between one bits. The read pulse masking could reduce that number of cycles futher, which could cause the second zero bit to be lost since the state machine has to wait 2 * ( 8 + ? ) cycles to decode the zero bits.
     
    Coming up with alternate state machines is an interesting exercise. The real limitation is there are only 16 MSB=0 states which have to handle stuffing the first two bits into the byte and then detecting the other six bits.
  24. EricBall
    I've attached my current WIP, but no updates to the LLE since this version has obvious issues even with my built-in level.
     
    I've added in the "walking on heads" feature. (It actually wasn't as hard as I thought it might have been as it required changes to only one bit of code.) When I first added it the leprechauns had an amusing habit of walking across the screen on top of one another. The look-ahead code took care of that but causes other quirkyness & problems. Hmm... just realized I need to check to make sure the leprechauns can't walk on the player's head. Yep, used BNE instead of BPL, so that should work.
     
    Anyway, one important note: unlike Lode Runner, the leprechauns don't stop moving when they fall into a hole. Thus, if the hole is two bricks wide they will wander back & forth. This means two brick wide holes will probably not catch two leprechauns since the second walks over the first.
     
    But the big change in this version is drop-off detection. In the attached WIP, the leprechauns simply reverse direction when they see a drop off and the player is higher than them. (If the player is on the same row or below, then they happily walk off the edge.) The problem with this method is it's very easy for the leprechauns to wander back and forth, never getting anywhere. A somewhat better solution was to treat the drop-off like a wall and fall into that routine (which rotates their virtual joystick). Then there was a 50/50 chance the leprechaun would walk off the edge anyway. But there was still a chance they would get stuck.
     
    I think I'm going to have to re-implement hunt/chase logic or go back to no drop-off detection.
     
    As I'm sure other coders are aware, good AI is tough to get right. I try to think through how the logic will play out, but I frequently don't anticipate something. (Fortunately, my bugs tend to be blatent rather than subtle.) Then I have to try to reproduce the quirk and trap it in the debugger, step through the code, and try to figure out what's going on.
     
    I think part of the problem is the AI is based on what the leprechaun did last grid position, not so much the grid they are on right now. Most of the time it's not a big deal, but sometimes the leprechauns don't behave quite the way I expected.
  25. EricBall
    I'll also update the Leprechaun Level Editor in a minute.
     
    Updates:
    1. enemies on ropes will fall if you pass under them
    2. enemies get off ladders before they get to the top
    3. simple enemy-enemy collision detection to keep them from getting stuck together (sometimes they pass through each other, sometimes they bounce, but they shouldn't stay in lockstep)
    4. code tweaks and a fix so the player doesn't always face left when stopped
     
    I haven't put in the drop-off detection yet. From a code perspective it's an extension of the ladder enhancement, but I'm not sure how it will impact gameplay. I'm concerned it might lead to the enemies getting stuck more easily when the player is higher than them. Even now there are a lot of cases the enemy AI doesn't effectively chase the player. (It's easy enough to put in a kind of "left-wall-follow" logic, the trick is knowing when to stop!)
     
    Hmm.... I wonder if hunting until the enemy is either in the same column or row would work (and going in the right direction...)
     
    No walking on heads yet. That impacts a different chunk of code. I've learned to keep the deltas small.
×
×
  • Create New...