hhos Posted January 23 Share Posted January 23 51 minutes ago, Lee Stewart said: As I mentioned in my last post, MAPAGX is irrelevant to any existing SAMS card. CRU bit 2 is not currently used. This was a design proposal by Thierry. ...lee I agree that the SBO 2/SBZ 2 instructions are irrelevant. As far as I can tell, though, MAPAGX should work fine, with or without them. I think it wouldn't need the last SWPB 0 either. Leaving all three instructions out would be a significant saving in execution time. How does this look for a routine? * Set page number, for 8 Megs modification * Page # in R0, memory address in R1 * Add >0800 to enable mapping in a bank MAPAGX SRL R1,12 Reduce address to 4K chunks SLA R1,1 Registers are 2 bytes apart * Entry address to change mapping when the map register # has already been determined * Page # in R0, Map register # in R1 (x 2) MAPRGX LI R12,>1E00 Superams CRU address SWPB 0 Msb is in odd byte SBO 0 Turn it on MOV R0,@>4000(R1) Use MOV instead of MOVB SBZ 0 Access off B *R11 It seems to me that it conforms to the guidelines in that Super-AMS.pdf I uploaded. I think it should work on the 1M, and up to 16M, memory boards. 2 Quote Link to comment Share on other sites More sharing options...
+TheBF Posted January 24 Share Posted January 24 Some SAMS ideas that others may find useful. ? In my SAMS system I remember the last SAMS page that was used in a memory location. When it comes time to pull in a page I test if it's already in memory and jump around the mapping code. Otherwise I update the variable, which adds one instruction to the mapping code. This works well on simple setups where I just have one 4K window reserved for SAMS pages. Another thing I have done is to think of 1M SAMS as 16 64K segments. I keep a variable for the active segment. This lets you use 16 bit address math and 64K is usually enough for a specific purpose in my programs. Also have a piece of code that given a 16 bit address, it computes the SAMS page and the offset which is added to the RAM window address. This can be done with a DIV by 4096, to get a quotient and remainder or with some bit twiddling that @Lee Stewart created for me. This gives you a contiguous 64K virtual memory space that you can access sequentially like it really existed. I would show you the code but it is in Forth's reverse polish Assembler so you need to read it hanging from the ceiling by your feet. (so said @apersson850 one time) And these ideas are not complicated for people to implement their own way. 2 Quote Link to comment Share on other sites More sharing options...
+Lee Stewart Posted January 24 Share Posted January 24 1 hour ago, hhos said: I agree that the SBO 2/SBZ 2 instructions are irrelevant. As far as I can tell, though, MAPAGX should work fine, with or without them. I think it wouldn't need the last SWPB 0 either. Leaving all three instructions out would be a significant saving in execution time. How does this look for a routine? * Set page number, for 8 Megs modification * Page # in R0, memory address in R1 * Add >0800 to enable mapping in a bank MAPAGX SRL R1,12 Reduce address to 4K chunks SLA R1,1 Registers are 2 bytes apart * Entry address to change mapping when the map register # has already been determined * Page # in R0, Map register # in R1 (x 2) MAPRGX LI R12,>1E00 Superams CRU address SWPB 0 Msb is in odd byte SBO 0 Turn it on MOV R0,@>4000(R1) Use MOV instead of MOVB SBZ 0 Access off B *R11 It seems to me that it conforms to the guidelines in that Super-AMS.pdf I uploaded. I think it should work on the 1M, and up to 16M, memory boards. It does, indeed. Though for clarity, I would change the SWPB line to SWPB R0 ...lee 2 Quote Link to comment Share on other sites More sharing options...
matthew180 Posted January 24 Author Share Posted January 24 1 hour ago, retrodroid said: Does anyone have any comments or suggestions on how to proceed, given my (and my project's) limitations? I suspect my sound list player will use less code and CPU than Tursi's player, since my player is a simple expansion (adds looping and some other features) of the XB list player, IIRC. I'm sure Tursi's player will give you a lot more options and more complex tunes / sounds if you can afford the overhead. I really don't know the actual computational differences though, and maybe it is not really that much. You should mess around with both and then decide. Only you will know which is best for your project. When you choose limitations like an unexpanded console, there will always be trade-offs you will have to consider. Something to think about, Tursi might also have provided external tools used to create music/sounds for his player. I did not write any such tools for my sound list player, so composition might be more of an effort for the basic sound list player. Owen was already making music for XB, so that was not a concern he had when I did that player. 1 Quote Link to comment Share on other sites More sharing options...
matthew180 Posted January 24 Author Share Posted January 24 (edited) edit: double post Edited January 24 by matthew180 Quote Link to comment Share on other sites More sharing options...
Tursi Posted January 24 Share Posted January 24 1 hour ago, matthew180 said: I suspect my sound list player will use less code and CPU than Tursi's player, since my player is a simple expansion (adds looping and some other features) of the XB list player, IIRC. I'm sure Tursi's player will give you a lot more options and more complex tunes / sounds if you can afford the overhead. I really don't know the actual computational differences though, and maybe it is not really that much. You should mess around with both and then decide. Only you will know which is best for your project. When you choose limitations like an unexpanded console, there will always be trade-offs you will have to consider. Something to think about, Tursi might also have provided external tools used to create music/sounds for his player. I did not write any such tools for my sound list player, so composition might be more of an effort for the basic sound list player. Owen was already making music for XB, so that was not a concern he had when I did that player. There are a lot of tools included with my player, but it's worth noting that it is also just a playback engine, it's not a tracker. You call it as often as you want - normally once a frame, so there are no options or the like for playback. The CPU load depends on the complexity of the tune but if you have notes changing every frame at 60hz it can be as high as about 30% CPU. For simpler tunes, it can be nearly unmeasurable. Super Space Acer seems to hover around 10-15% CPU. The memory cost is about 730 bytes for the player and 88 bytes for data (for music alone), and of course the data cost depends on how well the song compresses, but it compresses well enough that I've used it for standalone data compression as well as the dedicated music. All that said, the tools may be useful for manipulating any music, depending on the complexity you need. I have provided tools to convert TI soundlists (to and from, though I don't remember how comprehensive going back to playlist is. The data format is a simple text file per sound channel - easy to edit. Tools are included to merge channels, convert bass tones to noise, change playback rate, remove duplicates (helps compression), adjust volume, adjust pitch, and more. For samples, as much as a playback engine doesn't really show up in the samples: https://www.youtube.com/watch?v=vb0D47OZML8 https://www.youtube.com/watch?v=Wtwhu_ETzQ0 https://www.youtube.com/watch?v=8uM2c2y0ZzU https://www.youtube.com/watch?v=FjqEqPZa8g0 Is it easy to use? Very! Is it easy to learn? No. It will take time to learn how best to apply the tools to your system. There's even a strong argument it doesn't make much sense unless the tunes are complex, such as the converted music it was intended for. (Though it will compress simple tunes very well.) But I don't provide any tools for composition either. I'm not interested in making trackers. There are plenty of high quality tools already out there for that. https://harmlesslion.com/software/vgmcomp2/ Anyway, I think I'm way off topic. Now back to your program! 3 2 Quote Link to comment Share on other sites More sharing options...
PeteE Posted January 25 Share Posted January 25 On 1/23/2024 at 2:51 PM, retrodroid said: However, I may be able to source some of the desired sounds from existing non-TI hardware, in which case option 1 might make things easier. Does anyone have any comments or suggestions on how to proceed, given my (and my project's) limitations? I can tell you what I did for my no-expansion bare-console projects: For Bounce'n'Pounce, I made a dual sound list player, one dedicated to playing music on the first two tone generators, and the other to playing sound effects on the 3rd tone and noise generator. Each music or sound effect sound list is crafted to only play on the correct channel. The workspace RAM usage is slight: one byte counter and a word pointer for each sound list, so 6 bytes total. An additional feature for sound effect priority was to sort the sound effects in ROM in order of priority, and when a new sound effect is to be played, its address can be compared to the currently playing sound list address to determine if it can be played or not. Game thread here. For Tilda, I made my own advanced music and sound effect player. For this I wanted the music to be played using all four generators, but also allow sound effects to play on any generator and allow music to resume after the sound effect ends. Also, the music turned out to be quite large so I also needed a method of compression so that it will fit in a single ROM bank. The memory usage for this scheme was 4 words for music, and 4 words for sound effect, so 16 bytes total workspace usage, plus a little extra in the VDP memory for pattern-return-addresses. Each word contains a 3-bit counter, and 13-bit address (the player code and sound+music data reside in the same ROM bank so this is sufficient.) The compression works by making codes for volume changes a single byte and volume+note 2 bytes. Also if the music contains repeated patterns, these can be split out into a subroutine-like gosub and return. If the music needs to loop, it can use the gosub without the return. The notes and sub-pattern addresses are stored in a 256-entry table. More info here. I haven't released any of the tools for this, but I could maybe polish them up if it sounds useful. 2 1 Quote Link to comment Share on other sites More sharing options...
retrodroid Posted January 25 Share Posted January 25 15 hours ago, PeteE said: I can tell you what I did for my no-expansion bare-console projects: For Bounce'n'Pounce, I made a dual sound list player, one dedicated to playing music on the first two tone generators, and the other to playing sound effects on the 3rd tone and noise generator. Each music or sound effect sound list is crafted to only play on the correct channel. The workspace RAM usage is slight: one byte counter and a word pointer for each sound list, so 6 bytes total. An additional feature for sound effect priority was to sort the sound effects in ROM in order of priority, and when a new sound effect is to be played, its address can be compared to the currently playing sound list address to determine if it can be played or not. Game thread here. For Tilda, I made my own advanced music and sound effect player. For this I wanted the music to be played using all four generators, but also allow sound effects to play on any generator and allow music to resume after the sound effect ends. Also, the music turned out to be quite large so I also needed a method of compression so that it will fit in a single ROM bank. The memory usage for this scheme was 4 words for music, and 4 words for sound effect, so 16 bytes total workspace usage, plus a little extra in the VDP memory for pattern-return-addresses. Each word contains a 3-bit counter, and 13-bit address (the player code and sound+music data reside in the same ROM bank so this is sufficient.) The compression works by making codes for volume changes a single byte and volume+note 2 bytes. Also if the music contains repeated patterns, these can be split out into a subroutine-like gosub and return. If the music needs to loop, it can use the gosub without the return. The notes and sub-pattern addresses are stored in a 256-entry table. More info here. I haven't released any of the tools for this, but I could maybe polish them up if it sounds useful. Both of these sounds pretty great! My needs are pretty simple so something like the BnP implementation would suffice I would think. Let me do some more research and testing on my needs and the available options before you invest the time to polish them up, at least on my account. Quote Link to comment Share on other sites More sharing options...
+dhe Posted January 28 Share Posted January 28 Two problems for the price of one. The code: CLR @STATUS CLEAR GPL STATUS BYTE. BLWP @GPLLNK CALL GPLLNK * ARTICLE BY RAG DATA >0034 To start a BEEP LIMI 2 Enable interupt for sound processing LIMI 0 Stop them {rest of code} The problem: After the code ends, I continue to get the beep tone. Years ago, I had this problem and found Funnelweb's Loader, didn't have this problem. This time I though I would be cleaver and use the MG GPLLNK - I have the same symptom with both the EA and MG GPLLNK. My questions: 1) Am I calling or returning wrong? 2) What assembly code would I use to shush the sound chip? When I end the program with a BLWP @0000 on Classic99 the sound stops. 3) I've not develed in to the TMS9919 manual - as sound processing hasn't made it to my list of things to read up on yet, but it seems the sound chip continues to do it's soundy thing even after interrupts are turned off? Added bonus for me, there was some mention that sound lists can be processed from different memory (CPU, GROM, VDP RAM) - and it was alluded to, the handling might need to be different. Quote Link to comment Share on other sites More sharing options...
+TheBF Posted January 28 Share Posted January 28 I am going to make a guess. From my understanding the sound processing code is running on the interrupt. So code is executed every 16mS. GPLLNK sets up to make a sound. you enable interrupts the sound producing code turns on the oscillator and probably returns because it is going to do a time delay for the sound duration. When the interrupt returns to your code it hits LIMI 0. So now the rest of the sound generating code never runs because interrupts are off, which includes the delay code and the code to turn off the sound. So either a put in a delay before LIMI 0 or do some other stuff before invoking LIMI 0 and see what happens. Quote Link to comment Share on other sites More sharing options...
+Lee Stewart Posted January 28 Share Posted January 28 5 hours ago, dhe said: Two problems for the price of one. The code: CLR @STATUS CLEAR GPL STATUS BYTE. BLWP @GPLLNK CALL GPLLNK * ARTICLE BY RAG DATA >0034 To start a BEEP LIMI 2 Enable interupt for sound processing LIMI 0 Stop them {rest of code} The problem: After the code ends, I continue to get the beep tone. Years ago, I had this problem and found Funnelweb's Loader, didn't have this problem. This time I though I would be cleaver and use the MG GPLLNK - I have the same symptom with both the EA and MG GPLLNK. My questions: 1) Am I calling or returning wrong? 2) What assembly code would I use to shush the sound chip? When I end the program with a BLWP @0000 on Classic99 the sound stops. 3) I've not develed in to the TMS9919 manual - as sound processing hasn't made it to my list of things to read up on yet, but it seems the sound chip continues to do it's soundy thing even after interrupts are turned off? Added bonus for me, there was some mention that sound lists can be processed from different memory (CPU, GROM, VDP RAM) - and it was alluded to, the handling might need to be different. The normal state of the machine is with interrupts off (LIMI 0). If you have interrupts off, you should not need the "LIMI 2..LIMI 0" sequence. The GPL interpreter starts every GPL statement with that sequence—you do not need to supply it. That said, it really should not matter that you included that sequence. You might also try clearing only the GPL status byte (I presume STATUS = >837C), though again, I do not think it matters that you are also clearing the byte following STATUS: CLR R0 MOVB R0,@STATUS BLWP @GPLLNK DATA >0034 Other than that, you can turn off the sound generators yourself—code to follow. ...lee 2 Quote Link to comment Share on other sites More sharing options...
+Lee Stewart Posted January 28 Share Posted January 28 (edited) 13 minutes ago, Lee Stewart said: Other than that, you can turn off the sound generators yourself—code to follow. * Mute all four sound generators * BL @MUTE to execute this routine * SOUND EQU >8400 MUTE LI R0,>9F00 byte to mute tone generator 0 LI R1,4 count for 4 generators MUTE1 MOVB R0,@SOUND mute next generator AI R0,>2000 inc to next generator DEC R1 done? JNE MUTE1 do another if not RT return to caller ...lee Edited January 28 by Lee Stewart clarification 3 Quote Link to comment Share on other sites More sharing options...
+TheBF Posted January 28 Share Posted January 28 50 minutes ago, Lee Stewart said: * Mute all four sound generators * BL @MUTE to execute this routine * SOUND EQU >8400 MUTE LI R0,>9F00 byte to mute tone generator 0 LI R1,4 count for 4 generators MUTE1 MOVB R0,@SOUND mute next generator AI R0,>2000 inc to next generator DEC R1 done? JNE MUTE1 do another if not RT return to caller ...lee So does the GPLLNK beep code never turn off the sound on its own? Quote Link to comment Share on other sites More sharing options...
+dhe Posted January 28 Share Posted January 28 On my own, I initially tried putting two swpb between limi 2 and limi 0. It's a recommendation I read about when directly accessing vdp memory to slow down access. ** Didn't work ** Following @TheBF advice: I then went ahead and moved the limi 2/limi 0 combination to the programs main loop. That fixed the tone not going off. ** Fixed ** 1 hour ago, Lee Stewart said: The GPL interpreter starts every GPL statement with that sequence—you do not need to supply it. That advice appears to be spot on, because I removed the limi combo from beneath: BLWP @GPLLNK CALL GPLLNK * ARTICLE BY RAG DATA >0034 To start a BEEP And it the beep works just find, I don't know that that was common knowledge BITD, as I saw lots of examples with limi combo right below the DATA statement. So far, I've not had luck with @Lee Stewart 's code to turn off GPLLNK's beep, I will play with it further. I think sound lists just got moved up, before SAMS. Appreciation to both of you! 1 Quote Link to comment Share on other sites More sharing options...
+TheBF Posted January 28 Share Posted January 28 I was surprised how sound list are pretty easy once the magic addresses are discovered. I was able to start the whole thing with just Forth. I just needed to add 0LIMI and 2LIMI to let Forth do the interrupt control. Below is how I play sound lists in VDP RAM. Maybe you can make some use of this to write it in Assembler with the comments I added,. 83C2 EQU AMSQ \ interrupt DISABLE bits \ AMSQ bit meaning: \ 80 all interrupts disabled \ 40 motion disabled \ 20 Sound disabled \ 10 quit key disabled This code will play a VDP sound list that is "MOVed" into 83CC 0LIMI \ interrupts off 83CC ! \ store the Vdp address of your sound list in >83CC AMSQ C@ 5 AND AMSQ C! \ Read the byte at AMSQ address, AND the value with 5 01 83CE C! \ store 1 in the byte at >83CE. Triggers sound list processing 83FD C@ 01 OR 83FD C! \ set bit 1 at >83FD makes "VDP RAM the "source" of a sound list 2LIMI \ interrupts on starts the sound 3 Quote Link to comment Share on other sites More sharing options...
+dhe Posted January 28 Share Posted January 28 1 hour ago, TheBF said: I just needed to add 0LIMI and 2LIMI to let Forth do the interrupt control. Thanks BF, Molesworth doesn't cover sound and Lottrup is a pretty quick about, but, your quote above is the piece I was missing. A one second note, is equal in duration to 100's or 1000's of assembly instructions. That's why, when putting it in the main loop {waiting for user input} worked - lots of time for the sound list to finish! 1 Quote Link to comment Share on other sites More sharing options...
Tursi Posted January 29 Share Posted January 29 5 hours ago, dhe said: On my own, I initially tried putting two swpb between limi 2 and limi 0. It's a recommendation I read about when directly accessing vdp memory to slow down access. ** Didn't work ** Yeah, this won't do anything, especially with respect to VDP memory. LIMI 2 lets the CPU accept interrupt requests from devices, normally the VDP. While it's possible to trigger at exactly that moment, normally the VDP has already set the request and so as soon as the instruction completes, the interrupt is processed (the CPU jumps to the interrupt routine and executes there). When it's finished, it returns to your code and the LIMI 0 turns off interrupt request processing. If the interrupt request from the VDP was not already waiting, then nothing really happens. The CPU checks the interrupt pin, it's not set, and the next instruction turns interrupt processing back off again. Adding a delay between the two just allows more time for the interrupt to maybe be detected, but the net effect is probably not useful and just slows your program down. It's really just polling, and you could get almost the same effect from reading the CRU pin yourself. But, LIMI is faster than loading R12 if you have to, and faster than reading the VDP status register and testing yourself (if you are going to use the console interrupt anyway.) Looks like you got it all solved anyway! 1 1 Quote Link to comment Share on other sites More sharing options...
matthew180 Posted January 29 Author Share Posted January 29 On 1/28/2024 at 7:26 AM, dhe said: I've not develed in to the TMS9919 manual - as sound processing hasn't made it to my list of things to read up on yet, but it seems the sound chip continues to do it's soundy thing even after interrupts are turned off? Just to be clear, interrupts have nothing to do with generating sound. Nothing. Zip. Nada. The sound chip (SN76489) never stops producing tones; once you set a tone and volume, it continues until you change it, and turning a sound "off" is done by setting the channel volumes to the lowest level, basically muting each channel. Also, the SN76489 "wakes up" (powers on) with all tone volumes at max level, and one of the first things the system has to do is turn the volumes down. That is how the console generates its "beep" when you turn it on; it is actually the system turning the sound chip volume down. The length of the beep is the time it takes to execute the "turn volume down" code. This is also why a system with a dead CPU, or bad ROMs that do not get very far in execution, is called a "screaming banshee" (the sound chip is full on, the screen is black, and nothing is happening). The sound chip is memory mapped, like the VDP, and you can write data to it at any time. It is a very simple device with a few registers, so I highly recommend taking 30 minutes to just review the datasheet, it might help with some of the mystery. The whole LIMI 2, LIMI 0 thing is only to allow the CPU to check for interrupts, and on the 99/4A that would be a VDP interrupt that will trigger the console ISR, which sets the ISR rate to 50 or 60 Hertz. Note, you can also poll the VDP directly in your code (this is also covered in detail in this thread), rather than having the system ISR triggered via the VDP interrupt. Unfortunately the CPU's ISR vector table is in ROM, so we cannot change what routine is run when CPU interrupts are enabled. Thankfully the ISR does allow some of its housekeeping to be enabled/disabled, and there is a single hook at the end where a user-written routine can be called. A breakdown of the console ISR is in this thread, as well as how to disable the functions you might not want. Part of the ISR is to call the console routine to play a "sound list", which is a format specific to that routine. Sound lists have nothing directly to do with the sound chip other than ultimately tones and volume levels get sent to the SN76489. As for needing LIMI 2, LIMI 0 for sound, that is only required if you are working with an environment that uses or expects the console sound processing routine to play a sound list. If you use the console ISR and the sound list routine, then you should have LIMI 2, LIMI 0 in your main loop somewhere, and you need to follow all the memory use rules (mostly the use of scratch-pad RAM) set up by the console ROM, GPL environment, and BASIC environment (if you are interfacing with BASIC). Anyway, there are trade-offs when using the system ISR, and you need to decide if it is worth the effort. But you need to understand that CPU interrupts, the ISR, and the sound list routine are side effects of the 99/4A architecture and have nothing directly to do with the SN76489 sound chip outputting sound; it does that all by itself with just power applied and a clock input. 6 1 Quote Link to comment Share on other sites More sharing options...
+mizapf Posted January 29 Share Posted January 29 7 minutes ago, matthew180 said: Also, the SN76489 "wakes up" (powers on) with all tone volumes at max level, and one of the first things the system has to do is turn the volumes down. That is how the console generates its "beep" when you turn it on; it is actually the system turning the sound chip volume down. The length of the beep is the time it takes to execute the "turn volume down" code. The beep is produced by a portion of GPL code. But you're right that at the start, the first thing the console does is to turn off the volume, and sometimes you can hear some random tones and noises when powering up the system. From TI Intern: Power up routine 004F : DCLR @>83CE Clear sound bytes 0052 : ST @>9400,>70 Load speech write 0057 : ST @>8400,>9F Set sound generators 005B : ST @>8400,>BF 005F : ST @>8400,>DF 0063 : ST @>8400,>FF 0067 : DST @>8372,>FF7E Load data/substack 006B : MOVE >0007 TO REG>01 FROM GROM@>044E Load VDP register 0071 : CLR @>8300 0073 : MOVE >0071 TO @>8301 FROM @>8300 Clear scratch pad >00->71 0078 : MOVE >003E TO @>8382 FROM @>8300 >82->C0 007E : MOVE >000B TO @>8374 FROM @>8300 >74->7F 0083 : MOVE >0008 TO @>83C2 FROM @>8300 >C2->CA 0089 : DST @>8303,>0308 9901 Set CRU 008D : I/O @>8302,>03 0090 : DST @>8303,>1001 0094 : I/O @>8302,>03 0097 : ST @>8303,>18 009A : I/O @>8302,>03 009D : INV @>8300 009F : ST @>8303,>02 00A2 : I/O @>8302,>03 00A5 : ST @>8303,>01 00A8 : I/O @>8302,>03 00AB : DST @>8303,>1602 00AF : I/O @>8302,>03 00B2 : CALL GROM@>03CB Accept tone 00B5 : CLR VDP@>0000 Check VDP RAM 00B8 : ST @>8370,>10 3 Quote Link to comment Share on other sites More sharing options...
matthew180 Posted January 29 Author Share Posted January 29 Thanks for the detail, I was unaware the console issued an actual tone after silencing the sound chip. Quote Link to comment Share on other sites More sharing options...
retrodroid Posted January 30 Share Posted January 30 22 hours ago, matthew180 said: Just to be clear, interrupts have nothing to do with generating sound. Nothing. Zip. Nada. The sound chip (SN76489) never stops producing tones; once you set a tone and volume, it continues until you change it, and turning a sound "off" is done by setting the channel volumes to the lowest level, basically muting each channel. Also, the SN76489 "wakes up" (powers on) with all tone volumes at max level, and one of the first things the system has to do is turn the volumes down. That is how the console generates its "beep" when you turn it on; it is actually the system turning the sound chip volume down. The length of the beep is the time it takes to execute the "turn volume down" code. This is also why a system with a dead CPU, or bad ROMs that do not get very far in execution, is called a "screaming banshee" (the sound chip is full on, the screen is black, and nothing is happening). The sound chip is memory mapped, like the VDP, and you can write data to it at any time. It is a very simple device with a few registers, so I highly recommend taking 30 minutes to just review the datasheet, it might help with some of the mystery. The whole LIMI 2, LIMI 0 thing is only to allow the CPU to check for interrupts, and on the 99/4A that would be a VDP interrupt that will trigger the console ISR, which sets the ISR rate to 50 or 60 Hertz. Note, you can also poll the VDP directly in your code (this is also covered in detail in this thread), rather than having the system ISR triggered via the VDP interrupt. Unfortunately the CPU's ISR vector table is in ROM, so we cannot change what routine is run when CPU interrupts are enabled. Thankfully the ISR does allow some of its housekeeping to be enabled/disabled, and there is a single hook at the end where a user-written routine can be called. A breakdown of the console ISR is in this thread, as well as how to disable the functions you might not want. Part of the ISR is to call the console routine to play a "sound list", which is a format specific to that routine. Sound lists have nothing directly to do with the sound chip other than ultimately tones and volume levels get sent to the SN76489. As for needing LIMI 2, LIMI 0 for sound, that is only required if you are working with an environment that uses or expects the console sound processing routine to play a sound list. If you use the console ISR and the sound list routine, then you should have LIMI 2, LIMI 0 in your main loop somewhere, and you need to follow all the memory use rules (mostly the use of scratch-pad RAM) set up by the console ROM, GPL environment, and BASIC environment (if you are interfacing with BASIC). Anyway, there are trade-offs when using the system ISR, and you need to decide if it is worth the effort. But you need to understand that CPU interrupts, the ISR, and the sound list routine are side effects of the 99/4A architecture and have nothing directly to do with the SN76489 sound chip outputting sound; it does that all by itself with just power applied and a clock input. Excellent overview of the situation, thanks! Quote Link to comment Share on other sites More sharing options...
apersson850 Posted January 31 Share Posted January 31 A handy side effect of my own internal memory expansion design is that I can change the interrupt vectors as I like. 2 Quote Link to comment Share on other sites More sharing options...
+TheBF Posted January 31 Share Posted January 31 3 hours ago, apersson850 said: A handy side effect of my own internal memory expansion design is that I can change the interrupt vectors as I like. Sounds like TI-99 heaven. 1 Quote Link to comment Share on other sites More sharing options...
apersson850 Posted February 1 Share Posted February 1 (edited) For those who may not know: When I did my internal 32 K RAM, 16 bit wide, expansion I did like many others had done. I installed 64 K RAM and let the normal memory expansion be the part of that RAM where memory expansion normally shows up. But instead of letting the remaining 32 K RAM just sit there unused, I made it possible to page in that part, in 8 K chunks, on all remaining addresses. If these 8 K banks are enabled, they'll overlay the system memory/devices normally at these addresses. So I can copy system ROM into RAM, switch in the RAM and then modify what's now system RAM as I like. This also makes it possible to give the machine a contiguous 64 K RAM that's 16 bit wide. Only works with assembly of course, but you can write a program as big as the CPU can address. When all of that is enabled, you can't access system resources like VDP, sound and stuff, since they are also overlaid by RAM. But with some thought you may be able to live without that part, or you can use that part of RAM for data storage and switch it away when accessing the screen. Finally, the ability to page in RAM banks over various system devices also works in reverse. I can page out the internal memory expansion, in which case the standard memory expansion (if available) becomes visible. So an assembly program can swap out the internal 32 K RAM expansion, use the external 32 K RAM and still have another 32 K internal RAM to use for the program. Or whatever you like. The paging is done with eight CRU bits at base address >0400. Thus it can be reached regardless of which memory page is currently in place. Combined with a standard memory expansion, perhaps implemented on a RAMdisk card or something, this gives the machine a system memory of 96 Kbytes. Add video RAM and you have 112 Kbytes. I made a simple RAMdisk combining the 64 Kbytes that's not the normal 32 K RAM expansion plus the 56 Kbytes of RAM in the Maximem module. DSR resides in a RAM chip on my IO card. That gave me a 120 Kbytes RAMdisk, a bit larger than a standard SS/SD disk. I wrote drivers only for sector read/write, but that's enough to add this "device" as a storage unit when using Pascal. With the compiler on a RAMdisk compilation time is cut in half (even with source and object code on a standard disk), since the compiler uses very frequent disk access at compile time. Although not a pure assembly programming thing, I wrote this recap here anyway, since it does take some assembly to actually use it. Edited February 1 by apersson850 7 1 Quote Link to comment Share on other sites More sharing options...
+dhe Posted February 1 Share Posted February 1 Is this a board that can be reproduced or point to point? 1 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.