+atari2600land Posted August 8, 2019 Share Posted August 8, 2019 I can't move the fish sprite left and right. What I want it to do is move in a circle. have it move up and then when it reaches the top, move right. I got it moving up, but I can't get it to move right. flawedcodgod6.asm Quote Link to comment Share on other sites More sharing options...
+atari2600land Posted August 9, 2019 Author Share Posted August 9, 2019 I cleaned up my code a little. No matter what I do I can not get the fish to move down. WHY? It's especially anger-inducing when the up code is exactly like the down code except the down code doesn't work. flawedcodgod6a.asm Quote Link to comment Share on other sites More sharing options...
Tursi Posted August 9, 2019 Share Posted August 9, 2019 I don't fully follow the code, but I traced through to the first NMI. I see you initialize direction and all that fine, but in mov_cod there's a (small, probably inconsequential) bug where if COD_DIR is not 1-4, you'll start moving up. It looks like in the normal case where it jumps to move_cod_up, move_cod_down, etc, that de is not initialized. You only ld de in the begin_cod_xxx blocks, which are not called during normal movement. It might simply be that up never finishes. Try putting a ld de,COD_DIR after move_cod_up? Otherwise it looks like de is whatever was read from $8002... (which I don't see being initialized...?) Quote Link to comment Share on other sites More sharing options...
Tony Cruise Posted August 13, 2019 Share Posted August 13, 2019 First some suggestions: 1. try and split your logic so that you are only writing your sprite table to VRAM during the NM, and any other video writes. 2. Put your logic to update the sprites position in your main code (outside of NMI), use the TIMER routines to control how fast things move Now your actual bug: You are using a Zero value comparison, and directly calling the next direction setup, with it's own Zero value comparison which ends up already being true i.e. you skip through your different direction set-ups immediately. You should probably split up your logic into two sections: 1. Decide whether it is time to change direction 2. Update the position based on the current direction and each should only be called once per loop. I hope that has not confused you further. If you want to see some of what I have described above I have made a video series called Lets Make a Retro game on Youtube, that includes sample code for the Coleco. Quote Link to comment Share on other sites More sharing options...
+atari2600land Posted July 8, 2020 Author Share Posted July 8, 2020 Wow, it's been this long? Anyway, I have a couple questions again. #1. Why can't I make the year of the program be 2020? I put in 2020 and the fist doesn't display. If I put in 2019, it does. #2. I'm trying to make the fish move in a circle. Whenever it gets to the right side of the screen to go down, it moves to the extreme left side of the screen before going down. And when it's time to move left, it goes back to the x position of where it was before it went down. Why does it do that and how do I stop it? I really want to learn Colecovision programming, but this is so frustrating. flawedcodgod11.asm flawedcodgod11.rom Quote Link to comment Share on other sites More sharing options...
Tursi Posted July 8, 2020 Share Posted July 8, 2020 (edited) I don't know if I can answer all the questions, but I can answer some... Your code asks why you need the "QQQ" at the beginning of your copyright string. This is because that string must start at address $8024 in the ROM. If you count the bytes in your header block, you will see that you only get to $8020, plus the RET makes $8021. So you need three more padding bytes to get to the start address. It looks like you're pretty close! ASM can be confusing, yes, because you the programmer need to keep track of every little detail. I don't fully follow the main loop -- it's not a bad idea in assembly language to comment the intent of /every line/. It helps a lot even when you come back to it in the future. It helps more when other people need to understand it. I accidentally found your 2020 issue while I was trying to debug the main loop. Basically, your NMI vector is at the wrong address too - this must start at $8021, and yours starts much later. As a result, it ends up executing a lot of your header block, and most of that has no side effect. Unfortunately, the "2020" string results in code that does affect something, while " NOT" doesn't. It was just bad luck of the draw there. Generally, we work around that just by putting a JP at the correct place. So the fix for that one is to fix your startup header. Here's an adaptation of mine to fit your program: org $8000 ; HEADER db 0x55, 0xaa ; Header: 55AA to skip title page, AA55 to display it dw $7100 ; sprite table pointer for BIOS dw $7000 ; single byte pointer dw 0 ; unknown, unused dw 0 ; unknown, unused dw Start ; address of start code ; interrupt vectors ei ; RST 0x08 reti ei ; RST 0x10 reti ei ; RST 0x18 reti ei ; RST 0x20 reti ei ; RST 0x28 reti ei ; RST 0x30 reti ei ; RST 0x38 - spinner interrupt reti jp Nmi ; NMI db "I SAWED THE FLAWED COD GOD/CHRIS PRESENTS/ NOT" That should fix your 2020 issue and the need for the extra 'Q's. Unfortunately you are NOT allowed to move any of those things, they must always sit at those addresses, so the exact size and order of all those header bytes matters. This code appears to do nothing helpful: move_cod: ; we are on the NMI ld a,COD_DIR ; COD_DIR equ 1 - immediate load? cp 2 ; as a result, I think this code never matches... jr z,move_cod_right_fffff cp 3 ; nor this jr z,move_cod_down_fffff cp 4 ; nor this jr z,move_cod_left_fffff So the actual movement is the code that happens after that. Most movement functions have a little block like this: ld c,COD_DIR ; COD_DIR equ 1 - load C with '1' ld a,4 ; load A with '4' ld c,a ; copy A to C I think you're trying to record what direction you last moved, but as it stands it doesn't do that, it just loads A and C with a fixed value that doesn't get used. The reason I call these out is that to make your debugging task easier, you might want to just delete these blocks to avoid confusion. I'm not entirely sure I understand the movement code or how it gets to the sprite table. When the fish is moving left/right, you update $7180, and when it's moving up/down you update $7100. I can say that $7100 seems to contain a mirror of your sprite table, and since you aren't changing the X position, when it's being used the X position is locked at $15. (I changed it in the debugger to $80 and proved this). So maybe all you need to do is change the left/right code to change the byte at $7101 instead of at $7180, so that you're always updating the same table. Edited July 8, 2020 by Tursi fix formatting - spoiler tag broke the code tag. Twice. I hate web editors. Quote Link to comment Share on other sites More sharing options...
+atari2600land Posted July 8, 2020 Author Share Posted July 8, 2020 Success! What I needed to do was change the $7180 to $7101. I'll admit that I have no idea how the Colecovision works, but I do have some experience in coding assembly, the Game Gear uses something similar to this. As for how I'm moving, what I wanted to do was change the COD_DIR when necessary so that on each loop, it would check to see the value of COD_DIR and then move accordingly. Eventually I want to add a second sprite, a gray saw (hence the title being "SAWED" and not "SAW".) But first it would be nice to have some sort of idea how to do sound and controller input stuff first. Are there any tutorials for Colecovision programming that stuff? flawedcodgod12.rom flawedcodgod12.asm Quote Link to comment Share on other sites More sharing options...
+atari2600land Posted July 12, 2020 Author Share Posted July 12, 2020 It has been a while since I got out my Colecovision and played it. It seems as though the emulator I'm using (CoolCV) doesn't add the blue screen with yellow text that asks you to press a number 1-4. So would that show up if I were to try this on a real Colecovision? Also, how do I do sound? A little fish ditty on the title screen would be cute. Quote Link to comment Share on other sites More sharing options...
Tursi Posted July 12, 2020 Share Posted July 12, 2020 That screen needs to be programmed into the software, it's not automatic. Sound can be complicated... I refrained from offering advice on that one because you're using the Coleco BIOS to simplify your program, and I've always gone straight to the hardware. Hopefully someone has some advice on you. That said, if they don't, here's a very very basic low-level introduction on how to make a tone. This is NOT using the BIOS, this is straight to the hardware. So basic information on the sound chip: the ColecoVision sound chip is an SN76489, and you can find the official datasheet here: http://map.grauw.nl/resources/sound/texas_instruments_sn76489an.pdf It has a single interface point on the ColecoVision, you write data to it by using an OUT instruction, and it is accessed at port 0xFF. So all commands are written in assembly like OUT (0xff),value -- I assume that you understand the OUT instruction better than I do. The sound chip has three tone channels and one noise channel. Each tone channel has a "shift rate" which defines the frequency, it has 6 bits of resolution (or a range from 0x000 to 0x3ff), and four bits of volume control (from 0x00 to 0x0F). The noise channel defines two types of noise (white or periodic), and has the same 4-bit volume. I'll break these down below. Tone channels: The way the sound chip generates sound is very primitive. Basically, it has an internal register that counts down from the value you program at a fixed rate based on the hardware clock. When it reaches zero, the output switches. When it switches twice, that's one cycle, and the number of cycles you get per second is the frequency in hertz. But nobody thinks that way. Usually, you know the frequency you want - probably as a musical note. You can find lookup tables online to convert a musical note to hertz, and to convert hertz to the shift counter there is a fixed formula: 111860.8/hertz = code. The code is what you write to the sound chip. Once you have a code, like 0x105, you need to get it to the sound chip. There are two issues to overcome: - you have to write more than 8 bits, but OUT only does 8 bits at a time - you have to tell the chip WHICH channel, but you only have one access port The chip looks at the top four bits of the byte that you write to decide where you meant for the data to go. For tones, those command bits are 0x80 for channel 1, 0xA0 for channel 2, and 0xC0 for channel 3. These bits are decided by Texas Instruments and can't be changed. The need to write a total of 10 bits complicates the tone channel a little bit - if you simply set the bits the way it immediately looks obvious it would require extra hardware to understand first or second byte, and they chose not to do that. Instead, they "swizzle" the bits a bit to write in a different order. First write: 0xYZ - Y is the command bits, Z is the /least significant/ 4 bits. Second write: 0xAB - A is the most significant 2 bits, and B is the middle 4 bits. So, to write that value 0x105 to channel 1, you would do OUT (0xFF),0x85, then OUT (0xFF),0x10 -- the order matters. While there are advanced tricks you can do, just assume for now you always need both writes for a tone. Volume: Tone channels are the only ones that require more than 1 write to update, making volume and noise much simpler. Volume is treated as "attenuation", which means that the output is maximum volume and you specify how much quieter to make it. So 0x0 is maximum volume, and 0xF is silent. The ramp is not linear, but for basic use you don't need to worry about that. The command bits for volume are 0x90 for channel 1, 0xB0 for channel 2, 0xD0 for channel 3, and 0xF0 for noise volume. Just a single OUT is all it takes. So for instance, to set the volume on channel 1 to 3 lower than maximum, OUT (0xFF),0x93 Noise: Noise has two modes, periodic and white noise. Periodic is just like it sounds - it's a periodic tick. The tick is generally very rapid, and so the net effect is a buzzing sound. Most of the time you would use white noise, which is the hiss that you might associate with an untuned radio, for instance. This would be used for shooting or explosion sounds, usually. Each noise has three fixed frequencies, and one user-defined one. I am going to recommend not worrying about the user-defined one for now, but basically, it makes the noise take the frequency from tone channel 3. This is often used for special effects like pitch shifted explosions, or buzzy bass lines in music. The noise type is written with the command bits 0xE0, and there are 8 possible types: - 0x00 - periodic noise high - 0x01 - periodic noise medium - 0x02 - periodic noise low - 0x03 - periodic noise custom - 0x04 - white noise high - 0x05 - white noise medium - 0x06 - white noise low - 0x07 - white noise custom So, to play white noise medium, you would use OUT (0xFF),0xE6 Putting it together To hear a sound, you need to set the frequency AND the volume, and to stop hearing it, you can just turn off the volume. The sound chip will remember the last settings, so you never need to repeatedly set values you've already set. So let's play 523Hz (which should be a 'C' note). 111860.8/523 = 213.88. Round that up to 214, then convert to hexadecimal: 0x0D6. (To make the "swizzle" obvious, I always write all three nibbles). And we'll play at maximum volume, so that's 0. Our command codes are 0x80 for tone, and 0x90 for volume. So these three OUT statements will turn the sound on: OUT (0xFF),0x86 ; first command for tone, least significant nibble OUT (0xFF),0x0D ; second write for tone, the other 6 bits OUT (0xFF),0x90 ; channel 1 volume to maximum And to mute it, just mute the volume: OUT (0xFF),0x9F ; channel 1 volume to mute Hope that helps! Quote Link to comment Share on other sites More sharing options...
+atari2600land Posted July 13, 2020 Author Share Posted July 13, 2020 Tried putting the three lines in the game. I got an error message that reads "No valid register." EDIT: This works: ld a,$86 out ($ff),a ld a,$0d out ($ff),a ld a,$90 out ($ff),a 1 Quote Link to comment Share on other sites More sharing options...
+atari2600land Posted July 13, 2020 Author Share Posted July 13, 2020 I tried this for three hours and I can't make it work. What I want to do is make the MUSIC_TIMER variable increase by 1 each loop and then have it play the corresponding code. But it won't. What am I doing wrong? Why won't it add? I've tried various crap for three hours and none of what I tried works. little_tune: ld (hl),MUSIC_TIMER inc hl ld a,MUSIC_TIMER cp 1 jr z,note2 cp 2 jr z,note4 cp 3 jr z,note2 cp 4 jr z,note5 cp 5 jr z,note3 cp 6 jr z,note2 cp 7 jr z,silence ret Quote Link to comment Share on other sites More sharing options...
artrag Posted July 14, 2020 Share Posted July 14, 2020 17 hours ago, atari2600land said: I tried this for three hours and I can't make it work. What I want to do is make the MUSIC_TIMER variable increase by 1 each loop and then have it play the corresponding code. But it won't. What am I doing wrong? Why won't it add? I've tried various crap for three hours and none of what I tried works. little_tune: ld (hl),MUSIC_TIMER inc hl ld a,MUSIC_TIMER cp 1 jr z,note2 cp 2 jr z,note4 cp 3 jr z,note2 cp 4 jr z,note5 cp 5 jr z,note3 cp 6 jr z,note2 cp 7 jr z,silence ret Try with LD A,(MUSIC_TIMER) note the brackets Quote Link to comment Share on other sites More sharing options...
+atari2600land Posted July 14, 2020 Author Share Posted July 14, 2020 No, that didn't work. flawedcodgod14.asm Quote Link to comment Share on other sites More sharing options...
pearsoe Posted July 15, 2020 Share Posted July 15, 2020 I think you are trying to do this: ld hl,MUSIC_TIMER ;load hl with the address of the value for MUSIC_TIMER inc (hl) ;increment the MUSIC_TIMER value at location hl ld a,(hl) ;load A with the incremented value at location hl Quote Link to comment Share on other sites More sharing options...
+atari2600land Posted July 15, 2020 Author Share Posted July 15, 2020 I know when I'm beat and I am right now. I give up. If anyone cares, here's where I left off. flawedcodgod14.asm Quote Link to comment Share on other sites More sharing options...
Tursi Posted July 15, 2020 Share Posted July 15, 2020 (edited) Your problem starts here: MUSIC_TIMER: equ 1 "equ" means "EQUATE", and literally means "where you see this string, replace it with this number". So later in the code when you do "ld de,MUSIC_TIMER", you are actually writing "ld de,1" You need a memory location to store your data at, currently your code kind of hand-waves the RAM data, using a fixed address in the header (the $7100). This is the same reason that the direction tracking code I called out above didn't work. Memory allocation in assembly is entirely on your shoulders. But the simplest way is to ORG and define it inline. You have three basic equates at the top of your file: NBR_SPRITES: equ 1 COD_DIR: equ 1 MUSIC_TIMER: equ 1 NBR_SPRITES is, I assume "number of sprites", and so setting it to 1 makes sense. But the other two are data that you want your program to change. They are variables, and so they need to be located in RAM. Remove COD_DIR and MUSIC_TIMER from here and add this after your "cpu z80" but before the "org $8000": org $7200 COD_DIR: ds 1 MUSIC_TIMER: ds 1 RAM on the ColecoVision runs from $7000 to $73FF - 1KB. You've got a sprite table at $7100, and I don't know if the BIOS uses anything lower. I don't think it does - but I leave that as an exercise for you. The sprite table technically only takes 128 bytes, but I jumped all the way to $7200 anyway. "ds" means "define space" and allocates the number of bytes you ask for. You can't pre-initialize it here because it's not part of your program, it's just a hint for the assembler. I've allocated 1 byte for each and though it's not important to remember, COD_DIR ends up at $7200 and MUSIC_TIMER ends up at $7201 Now when you want to access them, you need to use the indirect syntax described to you above by Artrag and Pearsoe, because you're accessing a memory location, similar to how you're using hl and de in the movement code. Edited July 15, 2020 by Tursi equ means equ, duh.... 1 Quote Link to comment Share on other sites More sharing options...
+atari2600land Posted March 15, 2021 Author Share Posted March 15, 2021 Note: I'm using TNIASM. Apparently it likes define spaces at the beginning of the file, which is where I put them. If I put them in $7200, the program will not work. I am wondering how this will affect my program if at all. It seems to work okay right now. I made a little song that loops. I am also wondering why equates even exist. I mean why not just use their value instead? I am also wondering why I have to use ix and not b to make this work: ld ix,(MUSIC_TIMER) inc (ix) ld a,(ix) I looked through the code, saw 'iy' and figured if 'iy' was being used, so could 'ix'. So I tried it and it worked. Although I have no idea what it is. Another thing I am wondering is how complex games are handled when there's a limited number of things to write define spaces to. flawedcodgod15.zip Quote Link to comment Share on other sites More sharing options...
+atari2600land Posted March 16, 2021 Author Share Posted March 16, 2021 OK, this is stupid. Why won't this work? ld ix,(MUSIC_B) inc (ix) ld a,(ix) cp 2 jr z,note222 note2: ld a,$86 out ($ff),a ld a,$0d out ($ff),a jp move_cod note222: ld a,$80 out ($ff),a ld a,$0a out ($ff),a jp move_cod codgodfraud16.asm Quote Link to comment Share on other sites More sharing options...
Recommended Posts
Join the conversation
You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.