Jump to content

vidak

Members
  • Content Count

    499
  • Joined

  • Last visited

Everything posted by vidak

  1. Thanks I'm gonna work more on this tomorrow...
  2. Forgive me again, I'm stuck. I noticed the pointers were loading data from memory locations that were 1 or 2 addresses too far in memory. So I changed LDA #P0_HEIGHT to LDA #P0_HEIGHT-2. This seems to load the graphics from the correct starting memory address, but for some reason the kernel only loads 24 out of the 25 lines of graphics. What am I doing wrong? Am I decrementing the scanline counter improperly? Or are the pointers not set up properly? For some reason SpiceWare has his pointers for Collect set up like this: Player0Ptr = Label + P0_HEIGHT - 1 - Y position Would that be a better method? I'm inching closer and closer to understanding how all this works... coloured_guerrilla006.asm
  3. I am learning an insane amount right now. Thank you SO much. I will eventually think of a way to repay all this kindness.
  4. Yeah, same for me. I can help you find content if you need.
  5. Games are bigger now... but are they any better? The new Ghost Recon game was just loads of mountains and lots of quests that had you murder people. I feel like the open world standard big game is pretty overrated.
  6. I'm having a little trouble understanding how to set pointers. I can't seem to draw the right image on the screen. Basically what I want to do is draw a little multi-coloured sprite at coordinates 40, 80. I was using SET_POINTER Player0Ptr, Guerrill0 before, but that was drawing all $FFFFFFFF for the height of the character. I set the pointers just before the Main Loop, and I put the pointer reference in the Over Scan. Could someone help me? How do you set up pointers? I know they're not necessary for this stage of experimentation and learning, I could use LDA Absolute,X - but at some point I will have to learn how to use pointers. Please see the source code. coloured_guerrilla005.asm
  7. I know this isn't really a general comparison of the two systems, but Zaxxon looks and plays a whole lot better on the 2600. The Intellivision is very choppy and blocky. I was pleasantly surprised when I saw how well Zaxxon turned out on the 2600.
  8. I think you can compare them though - you need bigger teams because of the logic of money. If you forget about money, something totally incidental and secondary to making games aesthetically perfect, you don't have this dilemma. If people have enough time to finish the game, the game has a much higher chance of actually being good. Because of the first week of sale, because of Christmas, we're forced to have enormous teams creating bland sequels.
  9. I think there is a difference between popularity and official corporate support, so maybe there is an argument to be made that the 2600 was finished before it was officially unsupported by Atari. But I think we can still interpret the wording of the OP charitably - the 2600 did have a very long lifespan.
  10. Okay! So I think I have mastered how to draw the kernel that SpiceWare outlined in StayFrosty. If make sure you read all of the blog posts under the #5 heading so you understand what I am talking about. Remember this his how the main player character is drawn in the kernel: ldy Heights+.SEC ... lda (FrostyImagePtr+.SEC*2),y and (FrostyMaskPtr+.SEC*2),y sta GRP0 lda (FrostyColorPtr+.SEC*2),y sta COLUP0 I The "Heights" Variable I asked SpiceWare for some help in understanding how the Heights variable worked. It turned out my analysis was more or less correct, despite some small errors. This is how the Heights variable is set: ldy #SECTIONS*DATA_BYTES_PER_SECTION-4-1+2+2 ; -4 for the 4 unused platform bytes ; +2 for fireball size info ; +2 for level control initLINE 2200: .plLoop lda (LevelDataPtr),y sta Heights,y dey bpl .plLoop There are 55 bytes of data in ROM, and the Y Register is loaded with the number 54. The BPL instruction for .plLoop causes the loop at line 2200 to loop through the number zero, so we go through the loop 55 times. This loop transfers 55 bytes of data into 55 bytes of ROM. It transfers the 5 bytes of the heights of the different bands into Heights, but then it also transfers the other 50 bytes of level data into the RAM variables after heights. My analysis in #5.2 was correct. II Preparing the Pointers for Sections 1 to 4 It was easy enough to understand how the pointers for the graphics were set up for Section 0 of the screen. This is because the bottom of the screen is the designated origin of the Y position of the main player character. But we need to adjust the Y positions of all the copies of the main player character up the screen. We will mask out all but one image of the main player character, but we still need to make the kernel attempt to draw the image 5 times up the screen before we mask it out. So this is how we prepare the pointers for the above purpose: LINE 2006: ldx #0 ldy #0pfLoop clc lda FrostyImagePtr,y adc Heights,x iny ; 1 iny ; 2 sta FrostyImagePtr,y dey ; 1 lda FrostyImagePtr,y adc #0 iny ; 2 iny ; 3 sta FrostyImagePtr,y <Repeated Process for the Mask and Colours here> dey ; 2 inx cpx #SECTIONS-1 bcc pfLoop What is happening in the above code? This is what is happening: We are adding a 1 byte number to a 2 byte number. The process for doing this requires you to add the 1 byte number to the lower byte of the 2 byte number, and add any overflow to the higher byte. I did not realise this was happening! So if Heights (1 bytes) + ImagePtr(Lower byte) = 256, we add the carry put in the Program Counter to ImagePtr (Highter Byte). So, what the code achieves overall is this: FrostyImagePtr1 = FrostyImagePtr0 + Height0FrostyImagePtr2 = FrostyImagePtr1 + Height1FrostyImagePtr3 = FrostyImagePtr2 + Height2FrostyImagePtr4 = FrostyImagePtr3 + Height3 This makes perfect sense. We are setting the minimum Y position of each image pointer as the top height of the band of the screen below it. III The Final Component of the Kernel: (.SEC*2) The final element of drawing the main player character in the kernel is understanding what .SEC*2 does in the following code: lda (FrostyImagePtr+.SEC*2),y This is what is happening: .SEC is the argument passed into the kernel macro. This argument is converted into a pseudo-variable in the code. It is not a real variable because .SEC is not a piece of memory that contains data. .SEC is a set of characters that are mapped into the code depending on the value of the argument passed into the macro. .SEC therefore specifies a number between 0 and 4 - which tells the kernel to draw a specific band of graphics up and down the screen. What does " *2 " achieve though? This is simple. The image pointer is a 2 byte variable, so we need to tell the macro to specify in the code that the variable we want to specify in the final code is a 2 byte memory location. Simple. IV But What About the Mask and the Colour? The colour pointer works in exactly the same way as the image pointer. It is like a second part of the image pointer that needs to be set up separately with its own code. The process of setting a colour pointer for a multi-band screen is perfectly isomorphic with setting the graphics pointer. This is the data in ROM which sets out the mask used to let the main player character graphics through onto the correct band of the screen: LINE 865: align 256BlankGraphic repeat 50 ; 148-26 .byte 0 repend repeat 26 .byte $ff rependFrostyMask repeat 50 ; 148-26 .byte 0 repend The data is set out in macro code, but it is easy to interpret. It is 50 bytes (scanlines) of zeroes, followed by 26 bytes (scanlines) of $FF, followed by 50 bytes (scanlines) of zeroes. The origin of the pointer is the label FrostyMask, so we need to count down 26 bytes of memory address in order to draw the main player character, and count up 50 bytes in order to blank out the main player character. Once the kernel has counted down 26 bytes and drawn the character, there are then 50 bytes of zeroes, which will blank out drawing the graphics. The idea is to have the 26 bytes of $FF set to the correct scanline of the screen, so that when we bitwise AND the player graphics on the first line for them to show, the first like of the $FF of the mask is loaded. V The End That's it! Now I can get to writing my own kernel!
  11. I recently bought a Raspberry Pi 3! I want to create a dedicated box with it that emulates a classic 8 bit computer! I was thinking of going with the Commodore 64, but I also know the Atari 8 bits were great! I want to emulate one machine - which one should it be? PS. Is this in the right forum? Haha
  12. YES. Dude you're a total genius.
  13. Thank you very much! I have one last question - what is the significance of .SEC*2 in loading the pointers in the kernel? Is that because the pointers are 2 bytes? I owe you a beer or something!
  14. I agree with this. There should be a big conceptual distinction between the game and the DLC. The DLC really should be an extension of the game, and not a necessary component of the game.
  15. Well we can make huge carts now. Anyway I don't wanna start a fight. I just think having enough time to finish and polish a game would allow you to release it with very few bugs. Which I think the the experience we had with carts back in the day.
  16. Maaaaaan, cartridges. I love carts. We had none of these problems with carts.
  17. Introduction Despite the fact that I have always been obsessed with computers and programming, I have always been a novice at it. I only ever learned to program the simple programs you could copy out of magazines. The programming language I know best is 6502 assembly, but I started learning it 6 months ago. The next language I am most proficient in is Python. My level of skill is finishing the Code Academy guided learning tutorials. The subject area I am most proficient in is philosophy. I am equally good at metaphysics and political philosophy. Philosophy is not like programming at all. At least the philosophy I have been trained in. It is possible to use mathematics, statistics, and computers to do philosophy, but that kind of research is closer to the sciences than the humanities. The type of philosophy I know best is a subject area of the humanities. This kind of philosophy is very discursive and involves reading lots of words and learning a lot of qualitative information. Everything you do in the humanities is about writing essays and linking discursive concepts together into a logical argument. The word "argument" exists in programming, but it has a very different meaning. In programming, an "argument" is a value that is passed between functions, programs or subroutines. In philosophy, an argument is a collection of reasons to support a claim. If the reasons are good enough, you are entitled to "prove" your claim. The process of making arguments (the main activity in philosophy) is very different to programming. Programming is a mechanical process, where you have to build up your entire program or game out of discrete interlocking parts. The whole program is the entire sum of the parts that go into making it up. In philosophy, the whole is more than the sum of the parts. Even though you can have a "big picture" aim in programming, the "big picture" of a philosophy book, article, or thesis is qualitatively different, and in some ways independent of the reasoning you undertake to make up its "overall message". How to Start From the Absolute Beginning It's Okay to Do Unfamiliar Things Anyway, despite programming and philosophy sometimes being different, there is nothing stopping you from learning both skills. I want to put forward a theory about how it is possible to go about learning programming for the Atari 2600 if you're a humanities student (like me). The first step you take in learning something new is dedicating time and effort to starting. Through every phase of coming to master a subject area you will have to put effort in. I suppose the point I am trying to make here is that at the very beginning of learning to program for the Atari you're going to have to get used to doing something familiar. For example I've had to improve my mental maths. I frequently found myself going to google or a calculator in order to do simple arithmetic, because I had forgotten a lot of my mental maths since I had done calculus in high school. But now I'm getting better. It was an unpleasant feeling, looking at two two-digit numbers and feeling helpless to add them together. But I got there. I pushed myself, and I forced myself to keep working despite the fact I was unfamiliar with this kind of activity. Accept Your Current Skill I feel like a lot of people who go about starting off in philosophy give up when they first fail at writing a good essay. A lot of people say "I will never succeed at this goal I have to be a good XYZ". This is only true if you never try. However if you put even a minimal amount of effort in every day, say, a hour's practice at something every day, it is completely false that you will never master a specific skill. The only thing that is stopping you from achieving some specific goal -- say learning how to argue for a specific premise in an argument, or learnign how Indirect Indexed addressing works for the 6502 -- is the frustration you are feeling with the lack of a habit you have at completing that task. The whole point of learning is to form habits, and when you first start out learning something, you don't have that habit. You are frustrated when you first start off learning something because you expect to have a habit that is ready-to-hand in order to help you succeed at completing that task. The best strategy to diminish the level of frustration you have at learning something new is to try and accept that you don't yet have a habit for solving that task. Voluntarism So in a way, the mythology that asserts that if you spend ten thousand (10 000) hours practicing a skill, you will perfect it, is half-true. You do need to keep practicing an activity for a long time in order to become good at it. The mythology is in reality completely misleading and very false. This is because not just any practice will lead to you mastering a subject area. You need the correct kinds of habit-forming practice in order to eventually becoming an expert at something. This article (https://www.daedtech.com/how-developers-stop-learning-rise-of-the-expert-beginner/), by Erik Dietrich, demonstrates what happens if you learn the wrong kinds of habits when you first go about learning how to do something new. The article says you will definitely become an expert if you learn the right habits. It adopts a model from Dreyfus and Dreyfus to show what stages you go through if you learn all the right habits for a subject area: Novice; Advanced Beginner; Competent; Proficient; and Expert. But Dietrich says things can go wrong. If you learn bad habits learn your new subject area, you risk becoming derailed from this pathway to becoming an expert. You may advance beyond being a Novice and Advanced Beginner with bad habits in a subject area, but you will never become Competent. Being an Expert Beginner You will become an Expert Beginner instead. Dietrich helps describe what the bad state of being an Expert Beginner is: When you consider the Dreyfus model, you’ll notice that there is a trend over time from being heavily rules-oriented and having no understanding of the big picture to being extremely intuitive and fully grasping the big picture. The Advanced Beginner stage is the last one in which the skill acquirer has no understanding of the big picture. As such, it’s the last phase in which the acquirer might confuse himself with an Expert. A Competent has too much of a handle on the big picture to confuse himself with an Expert: he knows what he doesn’t know. This isn’t true during the Advanced Beginner phase, since Advanced Beginners are on the “unskilled” end of the Dunning Kruger Effect and tend to epitomize the notion that, “if I don’t understand it, it must be easy.” The Expert Beginner does not know what they do not know. They don't understand the bigger picture of the subject area they are learning. The point Dietrich is trying to make here is you will only ever learn the correct habits to finally becoming competent if you understand the bigger picture of the discipline you are becoming initiated into. Dietrich illustrates this argument by relaying a story about how they once used to enjoy bowling. Dietrich says when they started off as a novice at bowling, they adopted a very bad method of throwing the ball down the lane. Such a method was very bad for eventually becoming an expert and bowling, but it was adequate in order to progress right up to being an Advanced Beginner. Eventually Dietrich's bowling game hit 160, and he could never seem to improve beyond that point. So he asked for help. A mentor said he would have to completely unlearn the terrible habit he had at throwing the ball in order to eventually become competent. This meant that he would immediately become much worse at bowling before he ever become better. The frustration Dietrich went through unlearning his bad habits was so irritating he gave up bowling. From Humanities to Programming Dietrich did not understand the overall point of bowling, so he was happy to at first adopt some terrible habits about playing the game. I think the exact same lessons applies to people like me who have originally been trained in the humanities, and are trying to learn programming as a new skill. Don't immediately assume that just because you have mastered a couple of interesting tricks for the Atari 2600 that you have mastered everything you need to know about programming for the system. You will never truly understand how to become an expert at the Atari unless you are humble and pay attention to the advice of others. Learning the Atari is not an individual but a collective process. Make sure you socialise with the community adequately and pay attention to the work other people are doing. Having a box of tricks that you have memorised to deploy at certain instances is not an adequate mastery of the system. Maybe I am being too demanding, but I think a very deep understanding of a subject area is the only way anyone can go about becoming an expert at something.
  18. I need some help. I have two issues: How the Variable "Heights" Works in Stay Frosty One thing doesn't add up in my analysis of how the Y Register in the Stay Frosty kernel is formed. This code forms the Heights variable: LINE 2196: ldy #SECTIONS*DATA_BYTES_PER_SECTION-4-1+2+2 ; -4 for the 4 unused platform bytes ; +2 for fireball size info ; +2 for level control init .plLoop lda (LevelDataPtr),y sta Heights,y dey bpl .plLoop The SECTIONS constant equals 5. The DATA_BYTES_PER_SECTION constant equals 11. Cancelling out the minor adjustments, the first LDY operation should load Y with 54. As we know from the previous blog post, the LevelDataPtr is pointing to the Level1 label in ROM. The first inconsistency is this: There is only 53 bytes of information apart from game logic in those sections of ROM. The second inconsistency with my analysis is: there are only 6 or 7 bytes of information in ROM under those labels that could be construed as the Height of things. The third inconsistency is this: There are only 5 bytes set aside for Heights in the RAM. This equals the number of sections of Height that the variable is supposed to store. The STA operation in the above code is using Absolute Indexed addressing. This means the Y register is used to increment the memory location relative to Heights, not the value in the Heights memory location. This means if we increment the memory location more than 5 times we are starting to store data in other memory labels than Heights. I am thoroughly confused. If anyone can help me understand this, I would be very grateful. I feel as if I don't understand the order of operations being done with the constants in the first LDY operation. I also don't understand what DATA_BYTES_PER_SECTION refers to. I cannot find any groups of 11 bytes of data anywhere. Preparing the Graphics Pointers for Sections 1 to 4 How does this code work? LINE 2006: ldx #0 ldy #0 pfLoop clc lda FrostyImagePtr,y adc Heights,x iny ; 1 iny ; 2 sta FrostyImagePtr,y ; Graphics Address (0) + Heights -> Graphics Address + 2 dey ; 1 lda FrostyImagePtr,y ; LDA Graphics Address + 1 adc #0 iny ; 2 iny ; 3 sta FrostyImagePtr,y ; Graphics Address + 1 -> Graphics Address + 3 <Repeated Process for the Mask and Colours here> dey ; 2 inx cpx #SECTIONS-1 bcc pfLoop I think what is happening in the above code is this: We loop through this above code 5 times - as many times as there are bands up the screen. (5 times) Everytime we move through the loop, the Y Register increases by 2. So the 5 times we move through the loop Y increases through these values: 0 -> 2, 1 -> 3 2 -> 4, 3 -> 5 4 -> 6, 5 -> 7 6 -> 8, 7 -> 9 8 -> 10, 9 -> 11 This means we are increasing the graphics pointer memory address by 2 every time--both the lower byte of the pointer, and the higher byte. We are shifting the line of graphics by 2 up every band of the screen. This is confusing - why do we need to do this? What seems to be happening to the lower byte is that we increment its memory address by the number of bytes equal to the height of the band. Why don't we also do this to the higher byte? Wouldn't this lead to the lower byte increasing something like 30+2 locations forward, where the higher byte only moves 2 locations forward? I need some clarification on the above issues.
  19. vidak

    Guerrilla Game #5.2

    I Problems One thing doesn't add up in my analysis of how the Y Register in the Stay Frosty kernel is formed. This code forms the Heights variable: ldy #SECTIONS*DATA_BYTES_PER_SECTION-4-1+2+2 ; -4 for the 4 unused platform bytes ; +2 for fireball size info ; +2 for level control init.plLoop lda (LevelDataPtr),y sta Heights,y dey bpl .plLoop The SECTIONS constant equals 5. The DATA_BYTES_PER_SECTION constant equals 11. Cancelling out the minor adjustments, the first LDY operation should load Y with 54. As we know from the previous blog post, the LevelDataPtr is pointing to the Level1 label in ROM. The first inconsistency is this: There is only 53 bytes of information apart from game logic in those sections of ROM. The second inconsistency with my analysis is: there are only 6 or 7 bytes of information in ROM under those labels that could be construed as the Height of things. The third inconsistency is this: There are only 5 bytes set aside for Heights in the RAM. This equals the number of sections of Height that the variable is supposed to store. The STA operation in the above code is using Absolute Indexed addressing. This means the Y register is used to increment the memory location relative to Heights, not the value in the Heights memory location. This means if we increment the memory location more than 5 times we are starting to store data in other memory labels than Heights. I am thoroughly confused. If anyone can help me understand this, I would be very grateful. I feel as if I don't understand the order of operations being done with the constants in the first LDY operation. I also don't understand what DATA_BYTES_PER_SECTION refers to. I cannot find any groups of 11 bytes of data anywhere. I know there are 4 unused bytes for drawing the platforms. Anyway let's continue attempting to understand how the kernel is drawn. II The Actual Pointer Remember, this is how the kernel is drawn: ldy Heights+.SEC ... lda (FrostyImagePtr+.SEC*2),y and (FrostyMaskPtr+.SEC*2),y sta GRP0 lda (FrostyColorPtr+.SEC*2),y sta COLUP0 We need not worry about the strange loading of 54 bytes of information into the memory location relative to Heights, because only the data in the first 5 bytes relative to Heights is loaded into the Y Register. Heights is only set out as 5 bytes large, and the first 5 bytes of ROM contain the section heights, and the .SEC pseudo-variable only increments Heights by 5 bytes of memory addresses. A FrostyImagePtr The first element of the kernel we need to trace is the Image Pointer. This pointer contains the 16 bit memory address that contains the main player graphics. How is this pointer formed? LINE 1975: SET_POINTER FrostyImagePtr, FrostyGraphic It is formed with the macro SET_POINTER. All of this code is executed in Vertical Blank. You can find the set of instructions which corresponds to SET_POINTER in MACRO.H: MAC SET_POINTER.POINTER SET {1}.ADDRESS SET {2} LDA #<.ADDRESS ; Get Lowbyte of Address STA .POINTER ; Store in pointer LDA #>.ADDRESS ; Get Hibyte of Address STA .POINTER+1 ; Store in pointer+1 ENDM There are two arguments for this macro. The first argument is the pointer variable in memory. The second argument is the memory address. What this macro does is store the 16 bit memory address location inside the 2 bytes of pointer memory. Simple enough to understand. For your reference, this is what exists at the memory address we have now stored inside the FrostyImagePtr: FrostyGraphic is a label in ROM: LINE 986: .byte zz__XXXX__ ; 0 .byte zz_XXXXXX_ ; 1 .byte zzXXXXXXXX ; 2 .byte zzXXXXXXXX ; 3 .byte zzXXXXXXXX ; 4 .byte zzXXXXXXXX ; 5 .byte zzXXXX_XXX ; 6 .byte zz_XXXXXX_ ; 7 .byte zz__XXXX__ ; 8 .byte zz_XXXXXX_ ; 9 .byte zz_XXX_XX_ ; 10 .byte zz_XXXXXX_ ; 11 .byte zz_XXXXXX_ ; 12 .byte zz_XXX_XX_ ; 13 .byte zz__XXXX__ ; 14 .byte zz___XX___ ; 15 .byte zz__X__X__ ; 16 .byte zz__XXXX__ ; 17 .byte zz__X_X___ ; 18 .byte zz__XXXX__ ; 19 .byte zz___XX___ ; 20 .byte zz__XXXX__ ; 21 .byte zz___XX___ ; 22 .byte zz___XX___ ; 23 .byte zz___XX___ ; 24 .byte zz___XX___ ; 25FrostyGraphic There is some code directly underneath the SET_POINTER macro call: LINE 1979: sec lda FrostyImagePtr sbc FrostyY sta FrostyImagePtr lda FrostyImagePtr+1 sbc #0 sta FrostyImagePtr+1 This adjusts the line of graphics we load into the kernel. The variable FrostyY stores the vertical position of the main player character on the screen. So what we are doing is adjusting the line of graphics we load into the kernel relative to what FrostyY contains. What happens in this game is that Frosty--the main player character--melts. As Frosty melts, we load less and less of the player graphics as Frosty sinks into the ground. The above setting of the pointer is sufficient for a game that does not have a kernel which is repeated in bands down the screen. Because we have a game with bands, we need to adjust the graphics pointers. If we do not adjust the pointers for the main player character, it will only be visible on a single band. The main player character needs to (a) be visble in different bands; and (b) be visible moving between bands. I assume this can all be achieved by adjusting the pointers relative to the values of the heights of the different bands up and down the screen. This is how SpiceWare prepared the graphics pointer for Sections 1-4. This means the main player character must appear at Section 0 at the beginning of the game, and is the origin for the Y position of the main player character. LINE 2006: ldx #0 ldy #0pfLoop clc lda FrostyImagePtr,y adc Heights,x iny ; 1 iny ; 2 sta FrostyImagePtr,y ; Graphics Address (0) + Heights -> Graphics Address + 2 dey ; 1 lda FrostyImagePtr,y ; LDA Graphics Address + 1 adc #0 iny ; 2 iny ; 3 sta FrostyImagePtr,y ; Graphics Address + 1 -> Graphics Address + 3<Repeated Process for the Mask and Colours here> dey ; 2 inx cpx #SECTIONS-1 bcc pfLoop I think what is happening in the above code is this: We loop through this above code 5 times - as many times as there are bands up the screen. (5 times) Everytime we move through the loop, the Y Register increases by 2. So the 5 times we move through the loop Y increases through these values: 0 -> 2, 1 -> 3 2 -> 4, 3 -> 5 4 -> 6, 5 -> 7 6 -> 8, 7 -> 9 8 -> 10, 9 -> 11 This means we are increasing the graphics pointer memory address by 2 every time--both the lower byte of the pointer, and the higher byte. We are shifting the line of graphics by 2 up every band of the screen. This is confusing - why do we need to do this? What seems to be happening to the lower byte is that we increment its memory address by the number of bytes equal to the height of the band. Why don't we also do this to the higher byte? Wouldn't this lead to the lower byte increasing something like 30+2 locations forward, where the higher byte only moves 2 locations forward? I need some clarification on the above issues. The final process of forming the main player's graphics pointers is tweaking the pointers so that the memory addresses they point to don't cross any page boundaries. When the kernel uses the LDA (ZP),Y operation in the kernel, it needs to take a precise amount of time. If the CPU has to cross a page boundary in memory in order to fetch the data at the pointer's address, it will add a cycle and disrupt the very precise timing of the kernel.LINE 2059:;+-------------------------+;| tweek Frosty's pointers |;| so no page breaks occur |;+-------------------------+ ldy #1MaskLoop lda FrostyMaskPtr,y ; Load higher byte of Mask Pointer cmp #>BlankGraphic ; CMP with higher byte of BlankGraphic beq MaskCheck2 ; If it is blank then branch lda #>BlankGraphic ; If not, load higher byte of BlankGraphic sta FrostyMaskPtr,y sta FrostyImagePtr,y sta FrostyColorPtr,y ; ...and store it into the higher byte of the pointers. dey ; This blanks them all out. lda #0 sta FrostyMaskPtr,y sta FrostyImagePtr,y sta FrostyColorPtr,y ; ...blank out all of the lower bytes of the pointers as well iny bne NextMask ; Always branchMaskCheck2 dey lda FrostyMaskPtr,y cmp #<FrostyMask bcc NextMask2 ; Branch if lower byte of Mask Pointer (less or) equal to lower byte of FrostyMask lda #0 sta FrostyMaskPtr,y sta FrostyImagePtr,y sta FrostyColorPtr,y ; ...if not (higher than) blank out lower byte of pointers iny lda #>BlankGraphic sta FrostyMaskPtr,y sta FrostyImagePtr,y sta FrostyColorPtr,y ; ...and blank out the higher byte as well bne NextMask ; Always branch?NextMask2 inyNextMask iny iny cpy #SECTIONS*2 ; Have we gone through the loop 10 times? (5 x 16 bits worth of memory addresses) bcc MaskLoop ; If we haven't, keep looping! This is about all I can achieve for now...
  20. I never had a concrete name for this device! I just called it "double crocodile clips" - "helping hands" is much better hahahah
  21. Yeah I agree with the Atari "Fuji" logo on the second sign. I'm not sure what the people who own the intellectual property would say about it. If *I* owned the IP I'd totally go for it.
×
×
  • Create New...