Jump to content

Tursi

Members
  • Content Count

    7,205
  • Joined

  • Last visited

  • Days Won

    8

Everything posted by Tursi

  1. Reached the point where I could fully process a song and so finished off the new visualizer demo I started in /2017/. It didn't turn out as well as I'd have liked, but it works. I still like the concept but the layout clearly needs more thought. Anyway, new tune! Program and source attached, or just have a look at the video. https://open.lbry.com/@tursilion:1/2020-07-18-05-09-29:4?r=J8w7SGxXLD3UUrHVxe5d5g1o5rwKT1Wh vgmcplay3r.zip
  2. 33mb text file - pah! Amateurs! When I was at NET we regularly had to parse multi-GIGABYTE text files. I had a tool that could play the text log back into our graphical monitoring tool. It was invaluable to have so much detail in the logs but could be painful when you didn't know what you were looking for.
  3. Here's the updated video, moving on. https://open.lbry.com/@tursilion:1/Tursilion-messing-around-v681806266:0?r=J8w7SGxXLD3UUrHVxe5d5g1o5rwKT1Wh
  4. I pushed an updated version since that video - I think the tinniness (spell check says that's a word!) was due to a mis-scale of frequency. I halved the tone frequencies and things sounded a heck of a lot better. Probably need to do a new video.
  5. Yeah, you can, I've tested a 9928 in an NTSC TI before. If you can get one!
  6. Been a little tougher, but I got MOD conversion mostly working. It's somewhat random how well the automatic process works, but I think it's possible to massage most MODs into something usable. Don't expect to not have to do SOME work, but for a sample of what can be done with NO effect, I posted a short video of the current status. https://open.lbry.com/@tursilion:1/VGMComp-Mod-Test:5?r=J8w7SGxXLD3UUrHVxe5d5g1o5rwKT1Wh
  7. 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.
  8. v399.30 - Added View->Log Disasm to Disk to the Debug menu - Some work on SID debug but it's not visible yet - proper line counting in the debug output, so the cursor stays where it's supposed to - bugfix so that CLOSE doesn't return an error on devices without FLUSH (like CLOCK) http://harmlesslion.com/software/classic99
  9. Good catch, that was confusing! The problem is that at some point in the past I added a call to "flush" to the CLOSE opcode, since it needs to flush any changed data to disk, but the CLOCK didn't implement flush and so returned illegal operation. Yes, the CLOSE failed. It didn't used to be able to, but in the event that flushing the file failed it was important to report it. Anyway, I'll post the new build in a few minutes.
  10. I want to say that I /also/ found evidence years ago that the 9919 - a PAL VDP with composite output - was at least specified. But I can't remember now why I think that.
  11. Looks like they didn't make it to the last step of actually getting the data INTO a TI... so maybe the last step is converting it into a WAVE file.
  12. It is extremely unlikely that it's the F18A if you are getting any signal on the monitor at all. Since you've narrowed it down to the PEB, start by removing all the PEB cards except the flex cable interface. If the system boots fine with that on, then insert one card at a time until it locks up - that can help identify if it's a PEB card. This can be a slow process, remember that you MUST turn the PEB off before inserting or removing a card, and TI recommends leaving it off for 30 seconds before you do so!
  13. 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!
  14. Didn't try it, but I did find this: https://github.com/doegox/Oscar Links to a descriptive page as well!
  15. Classic99 tries to auto-adjust level, but I can't do much for files that don't load as I've never dug too deeply into how the cassette system works. We have had experts in the past create external tools like CS1er and I've always felt that was the better approach, but the appeal of trying to get tape read to work eventually overwhelmed me. In short, I don't know the answer to your question. Make it as loud as you can without allowing any of the waveform to clip, and you'll have the best chance of reading it.
  16. I heard of this back in the day, but I never played with it. The format doesn't appear to be documented online, but from the manual published at Mainbyte, apparently you could load software with OLD CS1, so the format of the ultimate data must match the cassette. Further we can see the thick black bars at the end of a line are an end marker, since you go left to right, then right to left when scanning. Looks like the Atari version was similar. The fact that the wand had enough intelligence to detect a scanned line and beep makes me think there's a format, maybe additional checksums, but at the same time I can't help but wonder if the data there is literally just bits for the cassette port... I guess if it was, it needs to start with a constant tone, so on the assumption they didn't make the hardware that different between machines, it must be there in the barcode.
  17. I don't know if you can come up with enough 9918-NO-A chips to be worth even considering anymore...
  18. SAMS is a good standard, but the base machine was not designed with the concept of adding more memory. The flat memory space of the TI is 64k and always will be. So to get more than the 32K RAM it was designed with, software /needs/ to be aware of it. The way that other machines do it is with a concept of memory mapping. For instance, let's just talk about how Windows 32-bit does it - other systems are similar. The combination of the memory mapper and the CPU design allows the operating system to set up a full 32-bit address space for every application that starts - every application gets its own 4GB of memory space. Normally, half that space is reserved for the operating system, and the other half (2GB) is given to the program. Of course, when this system was released, having 2GB of RAM was unheard of. You probably had 8MB. So when the program asked for memory, the operating system would allocate a block from the 2GB of space, and make a note where the program was told that it lives. Now, any time the program tries to access that memory, one of two things can happen. First, if the memory is still available to the program, then it just goes ahead and accesses it, no impact. But the memory might not be available to the program. In that case, the hardware stops the access, and the operating system steps in to swap the memory - it looks for some block of memory that is not immediately required, probably for another program, and saves it to disk. Then it loads this program's memory from disk, and finally updates the memory mapper so that when the program requests it at the memory address it knows, it gets the physical hardware address that was just loaded. It's the latter swapping that happens all the time - and it's why adding RAM speeds up the machine (because it needs to stop to swap less often). But the net result is that the physical address in RAM is not the address that the program sees it at - there's always this level of indirection. This indirection is why you can just add RAM to the system, and all the software still works. The TI existed before any of this was in common use, so it has a fixed 64k memory space - the CPU can not access any more than that. Furthermore, the entire memory space is spoken for. So there is no way to just drop a memory mapper in there for automatic additional memory, and even if there was, no software would be able to do anything with out. It's not impossible to add mapper hardware, and come up with a scheme for accessing additional RAM. The 8088 probably came closest to something we could use with the segment register, which basically banked the memory space into 64k spaces. This function was embedded in the CPU, but /technically/ we can sort of add instructions to the 9900, so we could catch a particular illegal opcode and use it... Changing the page register could update the memory mapped in. We could also use the XMS/EMS driver concept - software would request the memory that it wants, and the driver would keep track of allocations. Software would need to tell the driver to do the banking for it before an access so the memory can be paged in. But the AMS is a fairly nice system - it's easy to code for - and it's easy to test for maximum size. Software that uses it can just as easily use its own memory management. There are really only two reasons to provide a standardized software interface - either you have lots of different kinds of memory access and you want to make it consistent, or you are multitasking and you want to ensure software doesn't step on each other. We don't really have that problem on the TI.
  19. Classic99 can read your WAV files in overdrive mode, too, which should load the data a little faster. It won't sound right, it'll cut off and may jump around, but the computer is hearing it fine. I've tested that a few times.
  20. Sorry for the AMS hassle. The current core of Classic99 requires me to pre-init the AMS registers, and it has bitten numerous people. But remember - you should always initialize all registers of any hardware you're using - don't assume someone else did it. Then you know your software will always work.
  21. 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.
  22. You're too kind. The important bit is you solved the issue!
  23. Well, it's pretty clear in your screenshot. R5 contains >A070, and your last executed instruction that uses it is B *R5. The trace shows that >A070 was executed, it even tells you how many cycles it took. You insist that >A070 is not supposed to be executed, it's supposed to be a pointer to the function at >A072. I know how to read the debugger I wrote, and I know 9900 assembly. I also know this particular trap is easy to get screwed up on, as I just spent a full month fighting it in my music player. The 9900 doesn't do indirection intuitively, that extra lookup is needed. Anyway, I've explained the debug message. I've analyzed your code. But until you try the suggestion that's enough work on my side.
  24. Well, Classic99 won't disassemble data statements, only statements the CPU has executed, so that helps. (edit: well, if they are above the cursor, anyway ) Your breakpoint is on /access/ to >A070, not execution... put no prefix at all on it. That said, the execution trace clearly shows that >A070 was executed as an instruction. You need to be starting your function at >A072. From the code that's posted, I guess these are the lines in question: 838A C239 mov *R9+,R8 * Forth interpreter *IP+ -> W 838C C178 mov *R8+,R5 * *W+ -> temp 838E 0455 b *R5 * branch *temp So in >838A, R9 was B284 -- we can't see what is there, but we know that it dumped it into R8 and must have got >AA86 We then moved from AA86 into R5, then jumped to it. We can see that R5 is indeed >A070. Assuming the first two statements are correct, I think you probably meant to have one more indirection there: mov *R8+,R5 * *W+ -> temp mov *r5,r5 * get function pointer from temp b *r5 * and branch to it
  25. I think that you are getting confused by the details being imprecise, and letting your knowledge of the software make you disregard the evidence. Based on what you posted, the CPU is /executing/ >A070, which happens to contain your pointer which happens to be >A072. But it's not /supposed/ to be executing >A070, so we need to disregard the fact that it points to the correct code in the very next instruction, and see why it's executing >A070. Either that or I'm missing information.
×
×
  • Create New...