intvnut Posted November 22, 2014 Share Posted November 22, 2014 I touched on this, but for any programmers not paying attention: The compiler now provides some great feedback in terms of how much RAM you're using for variables, and how much you have left. For example, this is GoatNom after I've included VOICE and MUSIC support: 135 used 8-bit variables of 178 available 15 used 16-bit variables of 42 available The "available" numbers will change depending on what you compile in (ie: what you use in your code). Several of nanochess's routines take a chunk out of this. VOICE support takes quite a few out of the 16 bit variables (something like 30 I think). MUSIC takes a fair bit of the 8 bit (again something like 30). And neither are comprehensive measures, I'm just going by memory here. But wow, there's still a ton of room to play around in. And I've been very lazy on a large new chunk of code, so I can reclaim some of that space. Anyway, an extremely handy addition as we start getting more and more complicated with IntyBASIC games. I've avoided a lot of arrays as they use a goodly amount of space, but at least now I can keep easier tabs on it. It looks like IntyBASIC's intybasic_epilogue.asm allocates the IV.Q array in 16-bit memory, but actually it can live in 8-bit memory. Only IV.FPTR and IV.PPTR need 16-bit memory. The exact cost of voice support, as currently implemented, appears to be: 10 x 16-bit words 3 x 8-bit bytes If IV.Q gets moved to 8-bit RAM, then it should be: 2 x 16-bit words 11 x 8-bit bytes It shouldn't be difficult to modify your intybasic_epilogue.asm to make this change. Move this line: . IV.Q: RMB 8 ; IV_xxx 16-bit Voice queue (8 words) . down to this group of variables, like so: (and notice I updated the comment to reflect it's 8-bit data.) . IF DEFINED intybasic_voice IV.Q: RMB 8 ; IV_xxx 8-bit Voice queue (8 bytes) IV.QH: RMB 1 ; IV_xxx 8-bit Voice queue head IV.QT: RMB 1 ; IV_xxx 8-bit Voice queue tail IV.FLEN: RMB 1 ; IV_xxx 8-bit Length of FIFO data ENDI . The only downside to keeping the queue in 8-bit RAM is that you can only define 213 unique phrases. Somehow, I think folks will cope. Quote Link to comment Share on other sites More sharing options...
intvnut Posted November 22, 2014 Share Posted November 22, 2014 (edited) It looks like IntyBASIC's intybasic_epilogue.asm allocates the IV.Q array in 16-bit memory, but actually it can live in 8-bit memory. Only IV.FPTR and IV.PPTR need 16-bit memory. The exact cost of voice support, as currently implemented, appears to be: 10 x 16-bit words 3 x 8-bit bytes If IV.Q gets moved to 8-bit RAM, then it should be: 2 x 16-bit words 11 x 8-bit bytes It shouldn't be difficult to modify your intybasic_epilogue.asm to make this change. Move this line: . Actually, never mind... Leave it where it is in 16-bit RAM. It appears nanochess made some modifications to how the driver works, and the IV.Q does need to live in 16-bit RAM. EDIT: Specifically, IntyBASIC's version of the driver omits the phrase-table concept, just playing the samples directly. Without the phrase table, you end up needing to store the full address of the phrase, which is why the queue now lives in 16-bit RAM. It certainly simplifies the data structures a bit, but it does eat 8 16-bit variables. Of course, with the --jlp switch, you get 8000 more, so there's that. Edited November 22, 2014 by intvnut 1 Quote Link to comment Share on other sites More sharing options...
freewheel Posted November 22, 2014 Share Posted November 22, 2014 Fine, I think I can survive with nearly 3x the 16-bit variables that I thought I had available I had typed a comment about 213 phrases being annoying after a while, what with the robotic voice, but that's a moot point now, so let me ask my follow-up question - how did they get different voices in Same Game? They've obviously recorded and encoded their own audio, unless I'm missing something. Also - farm animal sounds are surprisingly easy with this. And I'll give major high fives to the first person who puts together a decent 3 minute rap tune (because I just can't see this voice sounding like singing, ever). Quote Link to comment Share on other sites More sharing options...
intvnut Posted November 22, 2014 Share Posted November 22, 2014 (edited) Fine, I think I can survive with nearly 3x the 16-bit variables that I thought I had available I had typed a comment about 213 phrases being annoying after a while, what with the robotic voice, but that's a moot point now, so let me ask my follow-up question - how did they get different voices in Same Game? They've obviously recorded and encoded their own audio, unless I'm missing something. Also - farm animal sounds are surprisingly easy with this. And I'll give major high fives to the first person who puts together a decent 3 minute rap tune (because I just can't see this voice sounding like singing, ever). Well, that's 213 distinct phrases. You could always string them together by putting them in subroutines and using GOSUB. As for SameGame, David had access to a version of my encoding tool. I can't say I was completely impressed with the result. The tool is very sensitive to the quality of the input data, and seems to be tuned for voices in a specific pitch range and range of volumes, filtered in a particular way. With the AL2 data, it is possible to change the pitch of the allophones if you edit the voice data. It's not terribly easy in the encoded form I provide in SDK-1600. (The original data is variable bit-length encoded, and you'll need to repack it as 10-bit data after editing the pitch period parameters.) But even without changing the pitch period, I imagine someone could do a cover of MC Hawking. Edited November 22, 2014 by intvnut Quote Link to comment Share on other sites More sharing options...
freewheel Posted November 22, 2014 Share Posted November 22, 2014 Ah, I was going to ask if pitch can be modified. Looks like a fair bit of work. Quote Link to comment Share on other sites More sharing options...
+Tarzilla Posted November 22, 2014 Share Posted November 22, 2014 Hi everyone. I've put the IntyBASIC compiler v1.0 out of the oven, this compiler has made a long way since its first release in Jan/28/2014 This data sheet should be helpful: http://www.futurebots.com/spo256.pdf Those are the same allophones as what IntyBASIC's using. Flip to the middle (page 5 of the PDF, page 8 of the original document) for a description of the phonemes, and example phrases. To nanochess and intvnut: YOU BASTARDS HAVE RUINED MY WEEKEND! I should be asleep by now but instead I'm thinking in Phonemes and sticking appropriate voice samples all through my largest game, exactly where I wanted them to be weeks ago as I struggled to put them in the hard way! I have lots to do this weekend, but instead my brain will be unable to focus on tasks around the house because I'll be coding in my head, dying to get back to my PC to type in code! 2 Quote Link to comment Share on other sites More sharing options...
+Tarzilla Posted November 22, 2014 Share Posted November 22, 2014 Fine, I think I can survive with nearly 3x the 16-bit variables that I thought I had available I had typed a comment about 213 phrases being annoying after a while, what with the robotic voice, but that's a moot point now, so let me ask my follow-up question - how did they get different voices in Same Game? They've obviously recorded and encoded their own audio, unless I'm missing something. Also - farm animal sounds are surprisingly easy with this. And I'll give major high fives to the first person who puts together a decent 3 minute rap tune (because I just can't see this voice sounding like singing, ever). key word being "decent" Quote Link to comment Share on other sites More sharing options...
intvnut Posted November 22, 2014 Share Posted November 22, 2014 (edited) Ah, I was going to ask if pitch can be modified. Looks like a fair bit of work. Unfortunately. Although, that said, the period field itself is in fixed location(s) in each allophone sample, and is always 8 bits. The harder part is adapting all the repeat counts, as repeat counts are always expressed in terms of "number of pitch periods." If you make the period 20% smaller (for a higher pitch), the sample gets 20% faster. Conversely, if you make the period 20% larger, the sample gets 20% slower. To keep everything roughly the same speed, you'd need to adjust both the pitch and the repeat counts. There's also the likelihood that at certain pitches, some allophones develop resonances that lead to weird "popping" artifacts. That seems like less of a concern, but it's possible. The TI Terminal Emulator II cartridge for the TI-99/4A stored its allophone / phoneme data in a form that allowed changing the pitch fairly easily. I suppose such a transformation could be done here too, but that's likely a project for a distant future date. :-) A different, interesting direction might be to use the Intellivoice for sound effects. If you want to play around with the Intellivoice speech parameters, I wrote a tool some years ago called "Voice Tinkerer" (named in honor of Ryan Kinnen's neat little tool PSG Tinkerer) that lets you adjust various parameters and hear them live on the Intellivoice. It also shows you the "pole map" indicating where the parameters place the various poles in the frequency response. (Poles represent the resonances in the all-poles digital filter at the heart of the vocal tract model.) I've attached the Voice Tinkerer here. The controls are a bit wonky. Use the DISC to navigate between the various parameters. [1] and [4] change the upper nybble of the highlighted value [2] and [5] change the lower nybble of the highlighted value [3] and [6] change between "auto on" and "auto off". (Auto mode means "load the parameters immediately". If off, you have to press an action button to load them.) IIRC, top action button hushes the Intellivoice, and bottom action buttons load parameters if not in auto mode. (Or vice versa. I forget.) The top two parameters are amplitude (top left) and period (top right). A period of 00 indicates "white noise". The rest are tones, roughly. (The tones are actually repeating impulses.) The remaining 12 parameters are pairs of coefficients that control different pairs of poles drawn at the right on a big circle-chart. (This is a z-plane chart, for the curious.) You want to keep the little squares inside the circle. If you come up with some interesting parameter sequences, I have some macros that can encode it into voice data for you. EDIT: And in case you're wondering why the screen shot is animated: Voice Tinkerer displays 6 pairs of poles (12 poles total) and uses multiplexing to get all 12 spots on the display. It looks much better in jzIntv or on a real Intellivision. Also, if you put jzIntv next to a real Intellivision, you'll find that jzIntv's Intellivoice emulation is pretty darn accurate for poles that stay within the unit circle, but for edge conditions near the unit circle and outside of it, both diverge fairly quickly. Those are regions where the filters become unstable, and I never fully worked out the overflow behavior of the Intellivoice's serial multipliers and adders. Proper voice data should never push those boundaries though. EDIT 2: Here's a video of the TI Terminal Emulator II in action. Notice how the pitch adjustment is used to pretty awful effect, progressively pitch-bending down every sentence by default. (It also pitch-bends upwards sentences ending in a question mark.) It's a very, very awful approximation of how humans actually inflect speech. vtinker.rom Edited November 22, 2014 by intvnut 3 Quote Link to comment Share on other sites More sharing options...
+Tarzilla Posted November 22, 2014 Share Posted November 22, 2014 Fine, I think I can survive with nearly 3x the 16-bit variables that I thought I had available I had typed a comment about 213 phrases being annoying after a while, what with the robotic voice, but that's a moot point now, so let me ask my follow-up question - how did they get different voices in Same Game? They've obviously recorded and encoded their own audio, unless I'm missing something. Also - farm animal sounds are surprisingly easy with this. And I'll give major high fives to the first person who puts together a decent 3 minute rap tune (because I just can't see this voice sounding like singing, ever). Here is my entry in the worst vocal track of the day category. Try this, and don't look at the Phonemes, because at this point you can probably read them just as easy as regular text, I know I'm starting to after 2 hours of playing...I can see the goat using an exaggerated version of by extending the AH sound. CrappySong: Voice BB1,IY,KK1,AW,ZH,PA1,AA,AY,MM,PA1,BB2,AE1,AE1,AE1,DD1,PA1, AA,AY,MM, BB1,AE1,AE1,AE1,DD1,PA3,KK1,UH,MM, PA1, AW,NN1,PA1 Voice YY1,UW1,PA1, NN2,AX,OW,PA2,AA,AY,MM, BB1,AE1,AE1,AE1,DD2,PA1, AA,AY,MM, BB1,AE1,AE1,AE1,DD1,PA1,YY1,UW1,PA1, NN2,AX,OW,PA1,IH,IH,TT1,PA1,0 2 Quote Link to comment Share on other sites More sharing options...
intvnut Posted November 22, 2014 Share Posted November 22, 2014 Here is my entry in the worst vocal track of the day category. Try this, and don't look at the Phonemes, because at this point you can probably read them just as easy as regular text, I know I'm starting to after 2 hours of playing...I can see the goat using an exaggerated version of by extending the AH sound. CrappySong: Voice BB1,IY,KK1,AW,ZH,PA1,AA,AY,MM,PA1,BB2,AE1,AE1,AE1,DD1,PA1, AA,AY,MM, BB1,AE1,AE1,AE1,DD1,PA3,KK1,UH,MM, PA1, AW,NN1,PA1 Voice YY1,UW1,PA1, NN2,AX,OW,PA2,AA,AY,MM, BB1,AE1,AE1,AE1,DD2,PA1, AA,AY,MM, BB1,AE1,AE1,AE1,DD1,PA1,YY1,UW1,PA1, NN2,AX,OW,PA1,IH,IH,TT1,PA1,0 Ok... there's at least one bad allophone in there. "coom"? I think you want AH or AW there not UH. But the whole thing's bad and you know it. ;) Good show! Quote Link to comment Share on other sites More sharing options...
+nanochess Posted November 22, 2014 Author Share Posted November 22, 2014 There doesn't seem to be a good sound for the "oh" in "go". Edit - no, it's "OW". Not what I expected. Also "OR" should probably not be in the list of sounds - it's its own word, like the MATTEL phrase and PRESS. That's why it sounded so weird. Better cursing: VOICE GG3,OW,PA2 VOICE FF,UH,KK2,PA2 VOICE YY2,OW,RR2,SS,EH,LL,FF,PA1,0 I plan on writing a table of "sounds like" translation table for this, once I get my feet wet. I am not an expert on this stuff but man - with the ROM space we have available, the possibilities are endless. It's a bit robotic compared to most Intellivoice games but I am super impressed with the implementation. Another mistake, in my effort to simplify the access to programmers, I've made a collision between the word OR from Intellivoice and the OR phoneme from SPO-256AL2. So I've renamed the OR phoneme in intybasic_epilogue.asm to OR2. Until I update IntyBASIC file I would suggest everyone to make this small change to intybasic_epilogue.asm: _OR2: DECLE _OR2.end - _OR2 - 1 DECLE $0218, $018C, $016D, $02A6, $03AB, $004F, $0301, $0390 DECLE $02EA, $0289, $0228, $0356, $01CF, $02D5, $0135, $007D DECLE $02B5, $02AF, $024A, $02E2, $0153, $0167, $0333, $02A9 DECLE $02B3, $039A, $0351, $0147, $03CD, $0339, $02DA, $0000 _OR2.end: ; 32 decles Quote Link to comment Share on other sites More sharing options...
+nanochess Posted November 22, 2014 Author Share Posted November 22, 2014 Ok, here's a screen shot showing some fun stuff. jzintv_basic_debug.png What you see here is 'sprites.bas' running in jzIntv's debugger. Notice that column in the middle that shows what BASIC statement each assembler statement is part of? That's what we've enabled here. It's not completely tight integration, but it's a step forward. To see your BASIC program in jzIntv's debugger, do the following: Compile your game as always with IntyBASIC: intybasic game.bas game.asm Ask AS1600 for a source map file with the -j flag: as1600 -o game -l game.lst -j game.smap game.asm Run the new "intysmap" utility on the source map file: contrib/intysmap game.smap Now tell jzIntv about the source map file when you launch the debugger: jzintv -d --src-map=game.smap game Now jzIntv will show the IntyBASIC source alongside the disassembly when running your game in jzIntv's debugger. You can go a step further and have jzIntv recognize labels from the assembly code by adding the -s flag to AS1600, and --sym-file to the jzIntv command line: Compile your game as always with IntyBASIC: intybasic game.bas game.asm Ask AS1600 for a source map file with the -j flag: as1600 -o game -l game.lst -j game.smap -s game.sym game.asm Run the new "intysmap" utility on the source map file: contrib/intysmap game.smap Now tell jzIntv about the source map file when you launch the debugger: jzintv -d --src-map=game.smap --sym-file=game.sym game Now jzIntv will know about the various labels from the generated assembly. This doesn't necessarily correlate well back to the original BASIC source, but it can still be helpful. For example, WAIT maps to _wait, so this additional flag will tell jzIntv about _wait. Play around with it. See what you think. I'm sure it can be improved. BTW, down the road, the intysmap utility won't be necessary. I worked with nanochess to define a new directive that builds the required information into the generated ASM file in such a way that the next release of AS1600 will extract it automatically. I'm updating the manual to include this information Quote Link to comment Share on other sites More sharing options...
freewheel Posted November 22, 2014 Share Posted November 22, 2014 .A different, interesting direction might be to use the Intellivoice for sound effects. If you want to play around with the Intellivoice speech parameters, I wrote a tool some years ago called "Voice Tinkerer" (named in honor of Ryan Kinnen's neat little tool PSG Tinkerer) that lets you adjust various parameters and hear them live on the Intellivoice. It also shows you the "pole map" indicating where the parameters place the various poles in the frequency response. (Poles represent the resonances in the all-poles digital filter at the heart of the vocal tract model.) I've attached the Voice Tinkerer here. This program is an EXCELLENT noise generator. And that's about all I can get out of it. Seriously though, even with just this - I wonder if anyone at Mattel ever thought about using the Intellivoice in this fashion. You can get some pretty good ocean sounds, or wind sounds, that kinda thing, very easily. I bet it could do some nice explosions and whatnot too. I guess the ECS gives that extra noise generator, but still - I'd imagine you could do some more layered and complex sound sequences when you combine all of this. It's just too bad that we have to tweak with the INTV controls and display. I wonder if there would be a way to extract the PSG(s) and Voice elements from the emulator, but front-end them with an interface with mouse sliders and such. So that you could much more easily and quickly mess around with this stuff. Quote Link to comment Share on other sites More sharing options...
freewheel Posted November 22, 2014 Share Posted November 22, 2014 I'm noticing something peculiar with jzintv. I think. I'm playing around with random data to the VOICE command. As an example, this: VOICE $8651,PA1,0 Now I'm not expecting anything useful. It just bursts out some noise and that's it. However - when I first start the emulator it's a louder, longer noise. When I simply reset the emulator, it's a much quieter and shorter burst. Does reset not quite reset everything? 1 Quote Link to comment Share on other sites More sharing options...
+nanochess Posted November 22, 2014 Author Share Posted November 22, 2014 Does reset not quite reset everything? The zero numbers marks end of voice, numbers between 1 and 43 generates recorded Intellivoice phrases, and any number above 43 actually refers to a location in memory that contains the phoneme data, for example, GG3 actually points to _GG3 in intybasic_epilogue.asm So when you put $8651 it accesses memory with unknown values, so your mileage and results can vary. You could make a test of course, writing into RAM these values, and then pointing to that very RAM, this way you could make dynamic phonemes if you understand the voice chip of Intellivoice. Quote Link to comment Share on other sites More sharing options...
freewheel Posted November 22, 2014 Share Posted November 22, 2014 Yeah that's exactly what I was doing - I've already discovered where the various built in phrases and sounds sit I'm more curious as to why a reset of the emulator doesn't seem to reset the Intellivoice fully. Or maybe I'm just misunderstanding something. I guess I've always assumed that reset wipes everything and you start from scratch. Are some of the previous memory values left sitting around? Quote Link to comment Share on other sites More sharing options...
+nanochess Posted November 22, 2014 Author Share Posted November 22, 2014 Yeah that's exactly what I was doing - I've already discovered where the various built in phrases and sounds sit I'm more curious as to why a reset of the emulator doesn't seem to reset the Intellivoice fully. Or maybe I'm just misunderstanding something. I guess I've always assumed that reset wipes everything and you start from scratch. Are some of the previous memory values left sitting around? I don't know. Maybe intvnut knows, Quote Link to comment Share on other sites More sharing options...
CrazyBoss Posted November 22, 2014 Share Posted November 22, 2014 it seems to steal one 8bit variable ? maybe something about the DIM ? had to change a 8bit value to a 16bit value. But the rom file is 1k smaller now. Get a lot of warnings with procedure, does it mean that I actually need to put an END when a procedure is finished? (after RETURN) print number directly is nice 1 Quote Link to comment Share on other sites More sharing options...
+nanochess Posted November 22, 2014 Author Share Posted November 22, 2014 it seems to steal one 8bit variable ? maybe something about the DIM ? had to change a 8bit value to a 16bit value. Yes, because of DEFINE ALTERNATE But the rom file is 1k smaller now. Exactly, because of optimization Get a lot of warnings with procedure, does it mean that I actually need to put an END when a procedure is finished? (after RETURN) It's right, it helps to structure your program. print number directly is nice I'm glad you like it 1 Quote Link to comment Share on other sites More sharing options...
intvnut Posted November 23, 2014 Share Posted November 23, 2014 (edited) I'm noticing something peculiar with jzintv. I think. I'm playing around with random data to the VOICE command. As an example, this: VOICE $8651,PA1,0 Now I'm not expecting anything useful. It just bursts out some noise and that's it. However - when I first start the emulator it's a louder, longer noise. When I simply reset the emulator, it's a much quieter and shorter burst. Does reset not quite reset everything? I don't know. Maybe intvnut knows, Reset doesn't quite reset everything. It stops the current excitation, sets the speech buffer read/write pointers to 0, and resets the filter parameters and filter feedback. I believe this is consistent with the real Intellivoice, but I could be mistaken. Here's the code, if you care: /* ---------------------------------------------------------------- */ /* If Bit 10 is set, just reset the FIFO and SP0256. */ /* ---------------------------------------------------------------- */ if (data & 0x400) { ivoice->fifo_head = ivoice->fifo_tail = ivoice->fifo_bitp = 0; memset(&ivoice->filt, 0, sizeof(ivoice->filt)); ivoice->halted = 1; ivoice->filt.rpt = -1; ivoice->filt.rng = 1; ivoice->lrq = 0x8000; ivoice->ald = 0x0000; ivoice->pc = 0x0000; ivoice->stack = 0x0000; ivoice->fifo_sel = 0; ivoice->mode = 0; ivoice->page = 0x1000 << 3; ivoice->silent = 1; return; } Some of the SP0256 opcodes are "delta updates", meaning that the opcode updates the previous value in the registers as opposed to uploading a new value. A random address like $8651 most likely points to "unmapped memory", and that will read as $FFFF. That value, if written to the Intellivoice FIFO, simply resets the Intellivoice. In fact, anything with bit 10 set. See above. You'll quickly get the driver out of sync with the Intellivoice and eventually the driver will just stop pushing data to the Intellivoice. Here's a quick primer on how the Intellivoice works: The speech chip (SP0256) has a very simple microsequencer in it that can unpack bit-aligned data, do some simple math, and even handle one level of call-and-return. It isn't Turing complete, though: It has no conditional expressions or looping constructs. It's just a very simple sequencing engine that unpacks bits and does a little bit of math. The microsequencer unpacks voice parameters into the vocal tract model (VTM), and waits for each parameter set to execute. It keeps doing this until it sees a return instruction when no call is active, and there's no pending address load. (More on that in a second.) At that point, it stops sequencing. (Note: If you leave the VTM active playing a particular parameter set without silencing it, it'll play that indefinitely. That's potentially useful, actually...) To play a new sample on the SP0256, you perform an address load (ALD). This tells the SP0256 to branch to the specified address times 2 in its Resident ROM (RESROM), and start executing. The SP0256 lets you load up the address of the next thing to speak while the current command is executing, to allow it to seamlessly string phrases together. The load request (LRQ) bit says whether the SP0256 can accept another ALD. The SP0256 processes the requested sample when it's idle, or when the currently running sample sends a return when no call is active. The Intellivoice RESROM has 43 samples stored in it, ranging from simple pauses (PA1 through PA5) to the gusto-rific "Mattel Electronics Presents," and one special entry point, entry #0. (It also has 5 unused entry points that just return immediately. I suspect these were meant for engaging localized versions of the Intellivoice.) Entry #0 jumps to a special location outside the RESROM: The Speech FIFO. The Speech FIFO tries to mimic a speech ROM without actually being a ROM. It shifts data into the Intellivoice as if it were ROM data residing at the magic address $1800. (The RESROM exists at speech address $1000. This address, perhaps not coincidentally, is just after the RESROM. And yes, the Intellivoice has a private address space unrelated to addresses in the Intellivision.) The Speech FIFO is actually a 64 entry x 10-bit buffer residing in a separate chip, the SPB640. (If I had to hazard a guess, the part number comes from the total capacity of the buffer: 64 x 10.) To play a sample contained in a game cartridge, the game first needs to start loading data into the speech FIFO, and then once enough data's loaded, trigger the SP0256 to start speaking that data by asking it to speak phrase #0. The SP0256 will keep drawing data from the SPB640 until it reaches the end of the data, as determined by seeing a return statement when no call is in effect. You're expected to only send exactly as much data as the sample requires. If you send too much, then the SP0256 won't read everything you sent. If you send too little, the SP0256 will read from the empty FIFO and see "phantom data" that had been pushed earlier. (There's no way to stop the SP0256 from reading from the FIFO when it's empty.) My Intellivoice driver tries to keep the speech FIFO as full as possible as long as there's cartridge data to load into the FIFO and LRQ says I can load new commands. There needs to be a 1:1 relationship between the number of return statements that halt a sample and the number of commands I issue. If these get out of sync (for example, a sample halts before the end of the data), then the whole thing just backs up and stops working. So, there are at least a couple reasons why garbage samples sound different after a reset: The garbage samples used delta-update opcodes, and the VTM parameters encountered were different. The garbage samples lacked a return opcode to halt the SP0256, and the garbage replayed from the FIFO queue when the read pointer overruns the write pointer is slightly different. If you really want to experiment with sending random data to the Intellivoice, I do have a routine (IVPLAY) that lets you program up all the parameters in Opcode 0000 (Load All) and send that to the Intellivoice. It's the routine at the heart of Voice Tinkerer. There's also an IVHUSH to make it shut up. With some slight modification, IVPLAY could work with the voice driver in IntyBASIC to let you treat the Intellivoice as a special kind of PSG for sound effect generation. Here's the relevant excerpt from Voice Tinkerer. The IVPUSH calls would be replaced with MVO@ instructions that fill a buffer in 16-bit RAM, and then you'd use a VOICE command to play that buffer. ;; ======================================================================== ;; ;; IVPLAY Play out the current set of coefficients and copy them over. ;; ;; ======================================================================== ;; IVPLAY PROC BEGIN CALL MEMCPY DECLE VCOPY, VCOEF, 14 ;; ------------------------------------------------------------ ;; ;; Send the following instruction sequence: ;; ;; ;; ;; SETMODE 0000 ;; ;; LOADALL RPT=0001 ;; ;; RTS ;; ;; ;; ;; ------------------------------------------------------------ ;; ;; OPCODE 0001: SETMODE Set the Mode bits and Repeat MSBs ;; ;; ------------------------------------------------------------ ;; ;; ;; ;; Format: ;; ;; [7654 3210] ;; ;; 0001 MMRR ;; ;; ;; ;; Action: ;; ;; Serves as a prefix to many other instructions. The ;; ;; upper two bits of the immediate constant are loaded ;; ;; into the upper two bits of the 6-bit repeat register. ;; ;; These two bits combine with the four LSBs that are ;; ;; provided by most parameter-load instructions to ;; ;; provide longer repetition periods. ;; ;; ;; ;; The two MM bits select the data format / coefficient ;; ;; count for many of the parameter load instructions, and ;; ;; are "sticky." ;; ;; ;; ;; ------------------------------------------------------------ ;; ;; OPCODE 1000: LOADALL Load All Parameters ;; ;; ------------------------------------------------------------ ;; ;; ;; ;; Format: ;; ;; [7654 3210] ;; ;; 1000 RRRR [data] ;; ;; ;; ;; Data formats, by mode prefix (read right-to-left): ;; ;; ;; ;; [FEDCBZ98 76543210] ;; ;; Mode x0: PPPPPPPP AAAAAAAA ;; ;; SFFFFFFF SBBBBBBB (coeff pair 0) ;; ;; SFFFFFFF SBBBBBBB (coeff pair 1) ;; ;; SFFFFFFF SBBBBBBB (coeff pair 2) ;; ;; SFFFFFFF SBBBBBBB (coeff pair 3) ;; ;; SFFFFFFF SBBBBBBB (coeff pair 4) ;; ;; SFFFFFFF SBBBBBBB (coeff pair 5) ;; ;; ;; ;; [FEDCBZ98 76543210] ;; ;; Mode x1: PPPPPPPP AAAAAAAA ;; ;; SFFFFFFF SBBBBBBB (coeff pair 0) ;; ;; SFFFFFFF SBBBBBBB (coeff pair 1) ;; ;; SFFFFFFF SBBBBBBB (coeff pair 2) ;; ;; SFFFFFFF SBBBBBBB (coeff pair 3) ;; ;; SFFFFFFF SBBBBBBB (coeff pair 4) ;; ;; SFFFFFFF SBBBBBBB (coeff pair 5) ;; ;; sppppppp saaaaaaa (pitch and ampl interp) ;; ;; ;; ;; Action: ;; ;; Loads amplitude, pitch, and all coefficient pairs at ;; ;; full 8-bit precision. ;; ;; ;; ;; Notes: ;; ;; -- The pitch and amplitude deltas that are available in ;; ;; Mode 01 and 11 are applied EVERY pitch period, not ;; ;; just once. Wraparound is allowed to occur. If the ;; ;; Pitch goes to zero, the periodic excitation switches ;; ;; to noise. ;; ;; ;; ;; ------------------------------------------------------------ ;; ;; The above bitstreams get packed into decles as follows: ;; ;; ;; ;; 9 8 7 6 5 4 3 2 1 0 ;; ;; +----+----+----+----+----+----+----+----+----+----+ ;; ;; | 0 | 1 | 0 | 0 | 0 | 1 | 0 | 0 | 0 | 0 | ;; ;; +----+----+----+----+----+----+----+----+----+----+ ;; ;; Repeat Cnt->|<---- SET MODE --->|<--M M-->|<--R R-->| ;; ;; ;; ;; +----+----+----+----+----+----+----+----+----+----+ ;; ;; | A3 | A2 | A1 | A0 | 1 | 0 | 0 | 0 | 0 | 0 | ;; ;; +----+----+----+----+----+----+----+----+----+----+ ;; ;; Amplitude --------->|<---- LOAD ALL --->|<- Repeat Cnt ;; ;; ;; ;; +----+----+----+----+----+----+----+----+----+----+ ;; ;; | P5 | P4 | P3 | P2 | P1 | P0 | A7 | A6 | A5 | A4 | ;; ;; +----+----+----+----+----+----+----+----+----+----+ ;; ;; Pitch ----------------------->|<--------- Amplitude ;; ;; ;; ;; +----+----+----+----+----+----+----+----+----+----+ ;; ;; | B7 | B6 | B5 | B4 | B3 | B2 | B1 | B0 | P7 | P6 | ;; ;; +----+----+----+----+----+----+----+----+----+----+ ;; ;; |<---------- Coefficient B0 ----------->|<--- Pitch ;; ;; ;; ;; [9876543210] ;; ;; BBFFFFFFFF Coefficient B1 / Coefficient F0 ;; ;; FFFFBBBBBB Coefficient F1 / Coefficient B1 ;; ;; BBBBBBFFFF Coefficient B2 / Coefficient F1 ;; ;; FFFFFFFFBB Coefficient F2 / Coefficient B2 ;; ;; FFBBBBBBBB Coefficient F3 / Coefficient B3 ;; ;; BBBBFFFFFF Coefficient B4 / Coefficient F3 ;; ;; FFFFFFBBBB Coefficient F4 / Coefficient B4 ;; ;; BBBBBBBBFF Coefficient B5 / Coefficient F4 ;; ;; 00FFFFFFFF RTS / Coefficient F5 ;; ;; 0000000000 RTS ;; ;; ;; ;; ------------------------------------------------------------ ;; MVII #VCOPY, R4 MVII #%0100010000, R0 CALL IVPUSH MVII #%0000100000, R0 MVI@ R4, R1 ; Amplitude SLL R1, 2 ; 0000 00AA AAAA AA00 SLL R1, 2 ; 0000 AAAA AAAA 0000 SLL R1, 2 ; 00AA AAAA AA00 0000 XORR R1, R0 ; AAAA100010 CALL IVPUSH SLL R1, 2 ; AAAA AAAA 0000 0000 MVI@ R4, R0 ; Pitch RLC R1, 2 ; AAAA AA00 0000 00xx RLC R0, 2 ; 0000 00PP PPPP PPAA RLC R1, 2 ; AAAA 0000 0000 xxxx RLC R0, 2 ; 0000 PPPP PPPP AAAA MVI@ R4, R1 ; B0 CALL IVPUSH SLL R0, 2 ; 00PP PPPP PPAA AA00 SLL R0, 2 ; PPPP PPPP AAAA 0000 RLC R0, 2 ; PPPP PPAA AA00 00xx RLC R1, 2 ; 0000 00BB BBBB BBPP MOVR R1, R0 CALL IVPUSH SDBD ; B1 / F0 MVI@ R4, R0 ; BBBB BBBB FFFF FFFF CALL IVPUSH MVI@ R4, R1 ; F1 SWAP R0 ; FFFF FFFF BBBB BBBB (F0/B1) ANDI #$FF, R0 ; 0000 0000 BBBB BBBB (B1) SWAP R1 ; FFFF FFFF 0000 0000 (F1) XORR R1, R0 ; FFFF FFFF BBBB BBBB (F1/B1) SLR R0, 2 ; 00FF FFFF FFBB BBBB (F1/B1) CALL IVPUSH SWAP R0 ; FFBB BBBB 00FF FFFF SLR R0, 2 ; 00FF BBBB BB00 FFFF ANDI #$F, R0 ; 0000 0000 0000 FFFF (F1) MVI@ R4, R1 ; B2 SLL R1, 2 ; 0000 00BB BBBB BB00 SLL R1, 2 ; 0000 BBBB BBBB 0000 XORR R1, R0 ; 0000 BBBB BBBB FFFF CALL IVPUSH SWAP R0 SLR R0, 2 ANDI #3, R0 ; 0000 0000 0000 00BB MVI@ R4, R1 ; F2 SLL R1, 2 ; 0000 00FF FFFF FF00 XORR R1, R0 ; 0000 00FF FFFF FFBB CALL IVPUSH SDBD ; F3 / B3 MVI@ R4, R0 ; FFFF FFFF BBBB BBBB CALL IVPUSH SWAP R0 ANDI #$FF, R0 ; 0000 0000 FFFF FFFF (F3) MVI@ R4, R1 ; B4 SWAP R1 ; BBBB BBBB 0000 0000 (B4) XORR R1, R0 ; BBBB BBBB FFFF FFFF (B4/F3) SLR R0, 2 ; 00BB BBBB BBFF FFFF (B4/F3) CALL IVPUSH SWAP R0 ; BBFF FFFF 00BB BBBB (F3/B4) SLR R0, 2 ; 00BB FFFF FF00 BBBB ANDI #$0F, R0 ; 0000 0000 0000 BBBB (B4) MVI@ R4, R1 ; F4 SLL R1, 2 ; 0000 00FF FFFF FF00 SLL R1, 2 ; 0000 FFFF FFFF 0000 XORR R1, R0 ; 0000 FFFF FFFF BBBB (F4/B4) CALL IVPUSH SWAP R0 SLR R0, 2 ANDI #3, R0 ; 0000 0000 0000 00FF MVI@ R4, R1 ; B5 SLL R1, 2 ; 0000 00BB BBBB BB00 XORR R1, R0 ; 0000 00BB BBBB BBFF CALL IVPUSH MVI@ R4, R0 ; F5 CALL IVPUSH CLRR R0 CALL IVPUSH ;; ------------------------------------------------------------ ;; ;; Tell Intellivoice to say it now. ;; ;; ------------------------------------------------------------ ;; CALL IVSAY RETURN ENDP ;; ======================================================================== ;; ;; IVHUSH "Now make it shaddup." ;; ;; ======================================================================== ;; IVHUSH PROC BEGIN @@1: ;; ------------------------------------------------------------ ;; ;; Send the following instruction sequence: ;; ;; ;; ;; PAUSE RPT=0001 ;; ;; RTS ;; ;; ;; ;; Encoded as: ;; ;; ;; ;; 00 1111 0001 ;; ;; 00 0000 0000 ;; ;; ------------------------------------------------------------ ;; MVII #$F1, R0 CALL IVPUSH CLRR R0 CALL IVPUSH CALL IVSAY MVII #VCOPY, R4 MVII #14, R1 CALL FILLZERO RETURN ENDP I've attached the full Voice Tinkerer source code if you care to poke around with it. It's GPLed. If the "specialized sound effect generator" mode of using the Intellivoice is interesting to IntyBASIC, I'm happy to work on adapting and relicensing the necessary bits. EDIT: I missed the memset() call in my ivoice.c code above. I do reset the full VTM parameter set, so the only difference you should encounter across a reset is different garbage in the speech FIFO. I made a couple minor edits above to reflect that. vtinker.zip Edited November 23, 2014 by intvnut 2 Quote Link to comment Share on other sites More sharing options...
intvnut Posted November 23, 2014 Share Posted November 23, 2014 (edited) MVII #%0100010000, R0 CALL IVPUSH MVII #%0000100000, R0 MVI@ R4, R1 ; Amplitude SLL R1, 2 ; 0000 00AA AAAA AA00 SLL R1, 2 ; 0000 AAAA AAAA 0000 SLL R1, 2 ; 00AA AAAA AA00 0000 XORR R1, R0 ; AAAA100010 CALL IVPUSH SLL R1, 2 ; AAAA AAAA 0000 0000 MVI@ R4, R0 ; Pitch RLC R1, 2 ; AAAA AA00 0000 00xx RLC R0, 2 ; 0000 00PP PPPP PPAA RLC R1, 2 ; AAAA 0000 0000 xxxx RLC R0, 2 ; 0000 PPPP PPPP AAAA MVI@ R4, R1 ; B0 CALL IVPUSH And... if IntyBASIC did take on the "Intellivoice as another sound effect generator" concept, I do see a few opportunities there for optimization if it ends up using this code as a starting point. I vaguely recall trying to optimize it at the time, and then thinking "Ya know, I best get this right first even if the code sucks, and then optimize it later if it ever becomes important." After all, for Voice Tinkerer, it was never performance critical, but correctness was paramount. Edited November 23, 2014 by intvnut Quote Link to comment Share on other sites More sharing options...
freewheel Posted November 23, 2014 Share Posted November 23, 2014 Reset doesn't quite reset everything. You have once again overloaded my brain. This is all going in the reference manual (ie: invaluable bookmarks for when I run into a weird edge case or have an unusual requirement). So for now - is there anything else in the hardware where a reset is different than a cold start? I'm curious because I want to make sure I'm not testing things based on either - I want behaviour to work the same way regardless. Like for example, if memory doesn't get zeroed out the same way, then I want to make sure I'm doing that at the start of certain subroutines, etc. I know that with some hardware, RESET is not the same as a cold boot - so I'm curious a) how this behaves on the real thing and b) if the emulator differs in any way. Good to know that the with the Intellivoice, I can't rely on a reset. And now back to IntyBASIC, questions/comments for nanochess: The DEFINE ALTERNATE - just so I understand, this is so you can load 32 GRAM cards in a single frame? Wow, that's some aggressive animation but it does give me ideas... PRINT <>number - it took me a while to realize that you need the <> but that was just me not reading the example first. Having an example of many of these things in the manual, by the way, has been invaluable. It makes it very obvious what the syntax is. So far this routine has very good performance although I haven't tried it with very large numbers yet. But wow - I'm going to be able to strip out SO much code. All of my score calculation and printing routines were dumping large values into arrays and such, to avoid repetitive /10 operations. This may be the single biggest performance enhancement (the rest of the changes are all new features and such). So - thanks! I don't print a lot of numbers but I do use PRINT for a lot of newbie-style debugging. This will save a LOT of cut/paste. 1 Quote Link to comment Share on other sites More sharing options...
intvnut Posted November 23, 2014 Share Posted November 23, 2014 You have once again overloaded my brain. This is all going in the reference manual (ie: invaluable bookmarks for when I run into a weird edge case or have an unusual requirement). So for now - is there anything else in the hardware where a reset is different than a cold start? I'm curious because I want to make sure I'm not testing things based on either - I want behaviour to work the same way regardless. Like for example, if memory doesn't get zeroed out the same way, then I want to make sure I'm doing that at the start of certain subroutines, etc. I know that with some hardware, RESET is not the same as a cold boot - so I'm curious a) how this behaves on the real thing and b) if the emulator differs in any way. Good to know that the with the Intellivoice, I can't rely on a reset. The EXEC zeros out 8-bit memory but not 16-bit memory. I think nanochess says IntyBASIC zeroes out 16-bit RAM, but not sure. In any case, if you fire up jzintv with --rand-mem, it'll start up with fully randomized memory. Always a great idea when stressing out your code. For the Intellivoice, RESET really does reset most relevant things. Any differences will only be noticeable if you feed bad voice data to it. PRINT <>number - it took me a while to realize that you need the <> but that was just me not reading the example first. Having an example of many of these things in the manual, by the way, has been invaluable. It makes it very obvious what the syntax is. So far this routine has very good performance although I haven't tried it with very large numbers yet. But wow - I'm going to be able to strip out SO much code. All of my score calculation and printing routines were dumping large values into arrays and such, to avoid repetitive /10 operations. This may be the single biggest performance enhancement (the rest of the changes are all new features and such). So - thanks! I don't print a lot of numbers but I do use PRINT for a lot of newbie-style debugging. This will save a LOT of cut/paste. The performance for PRINT <>number should be pretty good. The worst case number you can print is probably 59999 (since IntyBASIC uses PRNUM16 and is therefore limited to 16-bit values). I just benchmarked that, and it took about 1652 cycles. Have a look. (Cycle numbers are at the far right.) This trace was taken with jzIntv's source-level debugger, so you'll see the original IntyBASIC code along with whatever was in the intybasic_epilogue.asm file at the right. Cool stuff, eh? EA5F 0000 01BC 8007 02F0 508A 02F0 508A ----I-i- MVII #$EA5F,R0 | PRINT <5>59999 150890 > s-1 EA5F 0000 01BC 8007 02F0 508A 02F0 508C ----I-i- MVII #$0005,R2 | PRINT <5>59999 150898 EA5F 0000 0005 8007 02F0 508A 02F0 508E ----I-i- MVI _color ($033F),R3 | PRINT <5>59999 150906 EA5F 0000 0005 0007 02F0 508A 02F0 5090 ----I-i- MVI _screen ($033E),R4 | PRINT <5>59999 150916 EA5F 0000 0005 0007 0200 508A 02F0 5092 ----I-i- JSR R5,PRNUM16.z ($51CA) | PRINT <5>59999 150926 PRNUM16.z: EA5F 0000 0005 0007 0200 5095 02F0 51CA ----I-i- PSHR R5 | @@z: PSHR R5 150939 PRNUM16.z1: EA5F 0000 0005 0007 0200 5095 02F1 51CB ----I--- PSHR R2 | @@z1: PSHR R2 150948 PRNUM16.z2: EA5F 0000 0005 0007 0200 5095 02F2 51CC ----I--- PSHR R1 | @@z2: PSHR R1 150957 EA5F 0000 0005 0007 0200 5095 02F3 51CD ----I--- MVII #$51BE,R1 | MVII #_PW10+5,R1 ; Point to end of power-of-10 table 150966 EA5F 51BE 0005 0007 0200 5095 02F3 51CF ----I-i- SUBR R2,R1 | SUBR R2, R1 ; Subtract the field width to get right power 150974 EA5F 51B9 0005 0007 0200 5095 02F3 51D0 -C--I-i- PSHR R3 | PSHR R3 ; save format word 150980 EA5F 51B9 0005 0007 0200 5095 02F4 51D1 -C--I--- CMPI #$0002,R5 | CMPI #2, R5 ; are we leading with zeros? 150989 EA5F 51B9 0005 0007 0200 5095 02F4 51D3 -C--I-i- BNC PRNUM16.lblnk ($51DD) | BNC @@lblnk ; no: then do the loop w/ blanks 150997 EA5F 51B9 0005 0007 0200 5095 02F4 51D5 -C--I-i- CLRR R5 | CLRR R5 ; force R5==0 151004 EA5F 51B9 0005 0007 0200 0000 02F4 51D6 -C-ZI-i- ADDI #$0080,R3 | ADDI #$80, R3 ; yes: do the loop with zeros 151010 EA5F 51B9 0005 0087 0200 0000 02F4 51D8 ----I-i- B PRNUM16.lblnk ($51DD) | B @@lblnk 151018 PRNUM16.lblnk: EA5F 51B9 0005 0087 0200 0000 02F4 51DD ----I-i- DECR R2 | @@lblnk DECR R2 ; decrement available digits 151027 EA5F 51B9 0004 0087 0200 0000 02F4 51DE ----I-i- BEQ PRNUM16.ldone ($51E7) | BEQ @@ldone 151033 EA5F 51B9 0004 0087 0200 0000 02F4 51E0 ----I-i- CMPI #$0005,R2 | CMPI #5, R2 ; field too wide? 151040 EA5F 51B9 0004 0087 0200 0000 02F4 51E2 S---I-i- BGE PRNUM16.llp ($51DA) | BGE @@llp ; just force blanks/zeros 'till we're narrower. 151048 EA5F 51B9 0004 0087 0200 0000 02F4 51E4 S---I-i- CMP@ R1,R0 | CMP@ R1, R0 ; Is this power of 10 too big? 151055 EA5F 51B9 0004 0087 0200 0000 02F4 51E5 SC--I-i- BNC PRNUM16.llp ($51DA) | BNC @@llp ; Yes: Put a blank and go to next 151063 PRNUM16.ldone: EA5F 51B9 0004 0087 0200 0000 02F4 51E7 SC--I-i- PULR R3 | @@ldone PULR R3 ; restore format word 151070 PRNUM16.digit: EA5F 51B9 0004 0007 0200 0000 02F3 51E8 SC--I-i- TSTR R0 | @@digit TSTR R0 ; If the number is zero, print zero and leave 151082 EA5F 51B9 0004 0007 0200 0000 02F3 51E9 SC--I-i- BNEQ PRNUM16.dig1 ($51F1) | BNEQ @@dig1 ; no: print the number 151088 PRNUM16.dig1: EA5F 51B9 0004 0007 0200 0000 02F3 51F1 SC--I-i- MOVR R3,R5 | @@nxdig MOVR R3, R5 ; save display format word 151097 PRNUM16.cont: EA5F 51B9 0004 0007 0200 0007 02F3 51F2 -C--I-i- ADDI #$0078,R5 | @@cont: ADDI #$80-8, R5 ; start our digit as one just before '0' 151103 PRNUM16.spcl: EA5F 51B9 0004 0007 0200 007F 02F3 51F4 ----I-i- ADDI #$0008,R5 | @@div: ADDI #8, R5 ; increment our digit 151111 EA5F 51B9 0004 0007 0200 0087 02F3 51F6 ----I-i- SUB@ R1,R0 | SUB@ R1, R0 ; subtract power of 10 151119 C34F 51B9 0004 0007 0200 0087 02F3 51F7 SC--I-i- BC PRNUM16.spcl ($51F4) | BC @@div ; loop until we go too far 151127 PRNUM16.spcl: C34F 51B9 0004 0007 0200 0087 02F3 51F4 SC--I-i- ADDI #$0008,R5 | @@div: ADDI #8, R5 ; increment our digit 151136 C34F 51B9 0004 0007 0200 008F 02F3 51F6 ----I-i- SUB@ R1,R0 | SUB@ R1, R0 ; subtract power of 10 151144 9C3F 51B9 0004 0007 0200 008F 02F3 51F7 SC--I-i- BC PRNUM16.spcl ($51F4) | BC @@div ; loop until we go too far 151152 PRNUM16.spcl: 9C3F 51B9 0004 0007 0200 008F 02F3 51F4 SC--I-i- ADDI #$0008,R5 | @@div: ADDI #8, R5 ; increment our digit 151161 9C3F 51B9 0004 0007 0200 0097 02F3 51F6 ----I-i- SUB@ R1,R0 | SUB@ R1, R0 ; subtract power of 10 151169 752F 51B9 0004 0007 0200 0097 02F3 51F7 -CO-I-i- BC PRNUM16.spcl ($51F4) | BC @@div ; loop until we go too far 151177 PRNUM16.spcl: 752F 51B9 0004 0007 0200 0097 02F3 51F4 -CO-I-i- ADDI #$0008,R5 | @@div: ADDI #8, R5 ; increment our digit 151186 752F 51B9 0004 0007 0200 009F 02F3 51F6 ----I-i- SUB@ R1,R0 | SUB@ R1, R0 ; subtract power of 10 151194 4E1F 51B9 0004 0007 0200 009F 02F3 51F7 -C--I-i- BC PRNUM16.spcl ($51F4) | BC @@div ; loop until we go too far 151202 PRNUM16.spcl: 4E1F 51B9 0004 0007 0200 009F 02F3 51F4 -C--I-i- ADDI #$0008,R5 | @@div: ADDI #8, R5 ; increment our digit 151211 4E1F 51B9 0004 0007 0200 00A7 02F3 51F6 ----I-i- SUB@ R1,R0 | SUB@ R1, R0 ; subtract power of 10 151219 270F 51B9 0004 0007 0200 00A7 02F3 51F7 -C--I-i- BC PRNUM16.spcl ($51F4) | BC @@div ; loop until we go too far 151227 PRNUM16.spcl: 270F 51B9 0004 0007 0200 00A7 02F3 51F4 -C--I-i- ADDI #$0008,R5 | @@div: ADDI #8, R5 ; increment our digit 151236 270F 51B9 0004 0007 0200 00AF 02F3 51F6 ----I-i- SUB@ R1,R0 | SUB@ R1, R0 ; subtract power of 10 151244 FFFF 51B9 0004 0007 0200 00AF 02F3 51F7 S---I-i- BC PRNUM16.spcl ($51F4) | BC @@div ; loop until we go too far 151252 FFFF 51B9 0004 0007 0200 00AF 02F3 51F9 S---I-i- ADD@ R1,R0 | ADD@ R1, R0 ; add back the extra power of 10. 151259 270F 51B9 0004 0007 0200 00AF 02F3 51FA -C--I-i- MVO@ R5,R4 | MVO@ R5, R4 ; display the digit. 151267 270F 51B9 0004 0007 0201 00AF 02F3 51FB -C--I--- INCR R1 | INCR R1 ; point to next power of 10 151276 270F 51BA 0004 0007 0201 00AF 02F3 51FC -C--I-i- DECR R2 | DECR R2 ; any room left in field? 151282 270F 51BA 0003 0007 0201 00AF 02F3 51FD -C--I-i- BPL PRNUM16.dig1 ($51F1) | BPL @@nxdig ; keep going until R2 < 0. 151288 PRNUM16.dig1: 270F 51BA 0003 0007 0201 00AF 02F3 51F1 -C--I-i- MOVR R3,R5 | @@nxdig MOVR R3, R5 ; save display format word 151297 PRNUM16.cont: 270F 51BA 0003 0007 0201 0007 02F3 51F2 -C--I-i- ADDI #$0078,R5 | @@cont: ADDI #$80-8, R5 ; start our digit as one just before '0' 151303 PRNUM16.spcl: 270F 51BA 0003 0007 0201 007F 02F3 51F4 ----I-i- ADDI #$0008,R5 | @@div: ADDI #8, R5 ; increment our digit 151311 270F 51BA 0003 0007 0201 0087 02F3 51F6 ----I-i- SUB@ R1,R0 | SUB@ R1, R0 ; subtract power of 10 151319 2327 51BA 0003 0007 0201 0087 02F3 51F7 -C--I-i- BC PRNUM16.spcl ($51F4) | BC @@div ; loop until we go too far 151327 PRNUM16.spcl: 2327 51BA 0003 0007 0201 0087 02F3 51F4 -C--I-i- ADDI #$0008,R5 | @@div: ADDI #8, R5 ; increment our digit 151336 2327 51BA 0003 0007 0201 008F 02F3 51F6 ----I-i- SUB@ R1,R0 | SUB@ R1, R0 ; subtract power of 10 151344 1F3F 51BA 0003 0007 0201 008F 02F3 51F7 -C--I-i- BC PRNUM16.spcl ($51F4) | BC @@div ; loop until we go too far 151352 PRNUM16.spcl: 1F3F 51BA 0003 0007 0201 008F 02F3 51F4 -C--I-i- ADDI #$0008,R5 | @@div: ADDI #8, R5 ; increment our digit 151361 1F3F 51BA 0003 0007 0201 0097 02F3 51F6 ----I-i- SUB@ R1,R0 | SUB@ R1, R0 ; subtract power of 10 151369 1B57 51BA 0003 0007 0201 0097 02F3 51F7 -C--I-i- BC PRNUM16.spcl ($51F4) | BC @@div ; loop until we go too far 151377 PRNUM16.spcl: 1B57 51BA 0003 0007 0201 0097 02F3 51F4 -C--I-i- ADDI #$0008,R5 | @@div: ADDI #8, R5 ; increment our digit 151386 1B57 51BA 0003 0007 0201 009F 02F3 51F6 ----I-i- SUB@ R1,R0 | SUB@ R1, R0 ; subtract power of 10 151394 176F 51BA 0003 0007 0201 009F 02F3 51F7 -C--I-i- BC PRNUM16.spcl ($51F4) | BC @@div ; loop until we go too far 151402 PRNUM16.spcl: 176F 51BA 0003 0007 0201 009F 02F3 51F4 -C--I-i- ADDI #$0008,R5 | @@div: ADDI #8, R5 ; increment our digit 151411 176F 51BA 0003 0007 0201 00A7 02F3 51F6 ----I-i- SUB@ R1,R0 | SUB@ R1, R0 ; subtract power of 10 151419 1387 51BA 0003 0007 0201 00A7 02F3 51F7 -C--I-i- BC PRNUM16.spcl ($51F4) | BC @@div ; loop until we go too far 151427 PRNUM16.spcl: 1387 51BA 0003 0007 0201 00A7 02F3 51F4 -C--I-i- ADDI #$0008,R5 | @@div: ADDI #8, R5 ; increment our digit 151436 1387 51BA 0003 0007 0201 00AF 02F3 51F6 ----I-i- SUB@ R1,R0 | SUB@ R1, R0 ; subtract power of 10 151444 0F9F 51BA 0003 0007 0201 00AF 02F3 51F7 -C--I-i- BC PRNUM16.spcl ($51F4) | BC @@div ; loop until we go too far 151452 PRNUM16.spcl: 0F9F 51BA 0003 0007 0201 00AF 02F3 51F4 -C--I-i- ADDI #$0008,R5 | @@div: ADDI #8, R5 ; increment our digit 151461 0F9F 51BA 0003 0007 0201 00B7 02F3 51F6 ----I-i- SUB@ R1,R0 | SUB@ R1, R0 ; subtract power of 10 151469 0BB7 51BA 0003 0007 0201 00B7 02F3 51F7 -C--I-i- BC PRNUM16.spcl ($51F4) | BC @@div ; loop until we go too far 151477 PRNUM16.spcl: 0BB7 51BA 0003 0007 0201 00B7 02F3 51F4 -C--I-i- ADDI #$0008,R5 | @@div: ADDI #8, R5 ; increment our digit 151486 0BB7 51BA 0003 0007 0201 00BF 02F3 51F6 ----I-i- SUB@ R1,R0 | SUB@ R1, R0 ; subtract power of 10 151494 07CF 51BA 0003 0007 0201 00BF 02F3 51F7 -C--I-i- BC PRNUM16.spcl ($51F4) | BC @@div ; loop until we go too far 151502 PRNUM16.spcl: 07CF 51BA 0003 0007 0201 00BF 02F3 51F4 -C--I-i- ADDI #$0008,R5 | @@div: ADDI #8, R5 ; increment our digit 151511 07CF 51BA 0003 0007 0201 00C7 02F3 51F6 ----I-i- SUB@ R1,R0 | SUB@ R1, R0 ; subtract power of 10 151519 03E7 51BA 0003 0007 0201 00C7 02F3 51F7 -C--I-i- BC PRNUM16.spcl ($51F4) | BC @@div ; loop until we go too far 151527 PRNUM16.spcl: 03E7 51BA 0003 0007 0201 00C7 02F3 51F4 -C--I-i- ADDI #$0008,R5 | @@div: ADDI #8, R5 ; increment our digit 151536 03E7 51BA 0003 0007 0201 00CF 02F3 51F6 ----I-i- SUB@ R1,R0 | SUB@ R1, R0 ; subtract power of 10 151544 FFFF 51BA 0003 0007 0201 00CF 02F3 51F7 S---I-i- BC PRNUM16.spcl ($51F4) | BC @@div ; loop until we go too far 151552 FFFF 51BA 0003 0007 0201 00CF 02F3 51F9 S---I-i- ADD@ R1,R0 | ADD@ R1, R0 ; add back the extra power of 10. 151559 03E7 51BA 0003 0007 0201 00CF 02F3 51FA -C--I-i- MVO@ R5,R4 | MVO@ R5, R4 ; display the digit. 151567 03E7 51BA 0003 0007 0202 00CF 02F3 51FB -C--I--- INCR R1 | INCR R1 ; point to next power of 10 151576 03E7 51BB 0003 0007 0202 00CF 02F3 51FC -C--I-i- DECR R2 | DECR R2 ; any room left in field? 151582 03E7 51BB 0002 0007 0202 00CF 02F3 51FD -C--I-i- BPL PRNUM16.dig1 ($51F1) | BPL @@nxdig ; keep going until R2 < 0. 151588 PRNUM16.dig1: 03E7 51BB 0002 0007 0202 00CF 02F3 51F1 -C--I-i- MOVR R3,R5 | @@nxdig MOVR R3, R5 ; save display format word 151597 PRNUM16.cont: 03E7 51BB 0002 0007 0202 0007 02F3 51F2 -C--I-i- ADDI #$0078,R5 | @@cont: ADDI #$80-8, R5 ; start our digit as one just before '0' 151603 PRNUM16.spcl: 03E7 51BB 0002 0007 0202 007F 02F3 51F4 ----I-i- ADDI #$0008,R5 | @@div: ADDI #8, R5 ; increment our digit 151611 03E7 51BB 0002 0007 0202 0087 02F3 51F6 ----I-i- SUB@ R1,R0 | SUB@ R1, R0 ; subtract power of 10 151619 0383 51BB 0002 0007 0202 0087 02F3 51F7 -C--I-i- BC PRNUM16.spcl ($51F4) | BC @@div ; loop until we go too far 151627 PRNUM16.spcl: 0383 51BB 0002 0007 0202 0087 02F3 51F4 -C--I-i- ADDI #$0008,R5 | @@div: ADDI #8, R5 ; increment our digit 151636 0383 51BB 0002 0007 0202 008F 02F3 51F6 ----I-i- SUB@ R1,R0 | SUB@ R1, R0 ; subtract power of 10 151644 031F 51BB 0002 0007 0202 008F 02F3 51F7 -C--I-i- BC PRNUM16.spcl ($51F4) | BC @@div ; loop until we go too far 151652 PRNUM16.spcl: 031F 51BB 0002 0007 0202 008F 02F3 51F4 -C--I-i- ADDI #$0008,R5 | @@div: ADDI #8, R5 ; increment our digit 151661 031F 51BB 0002 0007 0202 0097 02F3 51F6 ----I-i- SUB@ R1,R0 | SUB@ R1, R0 ; subtract power of 10 151669 02BB 51BB 0002 0007 0202 0097 02F3 51F7 -C--I-i- BC PRNUM16.spcl ($51F4) | BC @@div ; loop until we go too far 151677 PRNUM16.spcl: 02BB 51BB 0002 0007 0202 0097 02F3 51F4 -C--I-i- ADDI #$0008,R5 | @@div: ADDI #8, R5 ; increment our digit 151686 02BB 51BB 0002 0007 0202 009F 02F3 51F6 ----I-i- SUB@ R1,R0 | SUB@ R1, R0 ; subtract power of 10 151694 0257 51BB 0002 0007 0202 009F 02F3 51F7 -C--I-i- BC PRNUM16.spcl ($51F4) | BC @@div ; loop until we go too far 151702 PRNUM16.spcl: 0257 51BB 0002 0007 0202 009F 02F3 51F4 -C--I-i- ADDI #$0008,R5 | @@div: ADDI #8, R5 ; increment our digit 151711 0257 51BB 0002 0007 0202 00A7 02F3 51F6 ----I-i- SUB@ R1,R0 | SUB@ R1, R0 ; subtract power of 10 151719 01F3 51BB 0002 0007 0202 00A7 02F3 51F7 -C--I-i- BC PRNUM16.spcl ($51F4) | BC @@div ; loop until we go too far 151727 PRNUM16.spcl: 01F3 51BB 0002 0007 0202 00A7 02F3 51F4 -C--I-i- ADDI #$0008,R5 | @@div: ADDI #8, R5 ; increment our digit 151736 01F3 51BB 0002 0007 0202 00AF 02F3 51F6 ----I-i- SUB@ R1,R0 | SUB@ R1, R0 ; subtract power of 10 151744 018F 51BB 0002 0007 0202 00AF 02F3 51F7 -C--I-i- BC PRNUM16.spcl ($51F4) | BC @@div ; loop until we go too far 151752 PRNUM16.spcl: 018F 51BB 0002 0007 0202 00AF 02F3 51F4 -C--I-i- ADDI #$0008,R5 | @@div: ADDI #8, R5 ; increment our digit 151761 018F 51BB 0002 0007 0202 00B7 02F3 51F6 ----I-i- SUB@ R1,R0 | SUB@ R1, R0 ; subtract power of 10 151769 012B 51BB 0002 0007 0202 00B7 02F3 51F7 -C--I-i- BC PRNUM16.spcl ($51F4) | BC @@div ; loop until we go too far 151777 PRNUM16.spcl: 012B 51BB 0002 0007 0202 00B7 02F3 51F4 -C--I-i- ADDI #$0008,R5 | @@div: ADDI #8, R5 ; increment our digit 151786 012B 51BB 0002 0007 0202 00BF 02F3 51F6 ----I-i- SUB@ R1,R0 | SUB@ R1, R0 ; subtract power of 10 151794 00C7 51BB 0002 0007 0202 00BF 02F3 51F7 -C--I-i- BC PRNUM16.spcl ($51F4) | BC @@div ; loop until we go too far 151802 PRNUM16.spcl: 00C7 51BB 0002 0007 0202 00BF 02F3 51F4 -C--I-i- ADDI #$0008,R5 | @@div: ADDI #8, R5 ; increment our digit 151811 00C7 51BB 0002 0007 0202 00C7 02F3 51F6 ----I-i- SUB@ R1,R0 | SUB@ R1, R0 ; subtract power of 10 151819 0063 51BB 0002 0007 0202 00C7 02F3 51F7 -C--I-i- BC PRNUM16.spcl ($51F4) | BC @@div ; loop until we go too far 151827 PRNUM16.spcl: 0063 51BB 0002 0007 0202 00C7 02F3 51F4 -C--I-i- ADDI #$0008,R5 | @@div: ADDI #8, R5 ; increment our digit 151836 0063 51BB 0002 0007 0202 00CF 02F3 51F6 ----I-i- SUB@ R1,R0 | SUB@ R1, R0 ; subtract power of 10 151844 FFFF 51BB 0002 0007 0202 00CF 02F3 51F7 S---I-i- BC PRNUM16.spcl ($51F4) | BC @@div ; loop until we go too far 151852 FFFF 51BB 0002 0007 0202 00CF 02F3 51F9 S---I-i- ADD@ R1,R0 | ADD@ R1, R0 ; add back the extra power of 10. 151859 0063 51BB 0002 0007 0202 00CF 02F3 51FA -C--I-i- MVO@ R5,R4 | MVO@ R5, R4 ; display the digit. 151867 0063 51BB 0002 0007 0203 00CF 02F3 51FB -C--I--- INCR R1 | INCR R1 ; point to next power of 10 151876 0063 51BC 0002 0007 0203 00CF 02F3 51FC -C--I-i- DECR R2 | DECR R2 ; any room left in field? 151882 0063 51BC 0001 0007 0203 00CF 02F3 51FD -C--I-i- BPL PRNUM16.dig1 ($51F1) | BPL @@nxdig ; keep going until R2 < 0. 151888 PRNUM16.dig1: 0063 51BC 0001 0007 0203 00CF 02F3 51F1 -C--I-i- MOVR R3,R5 | @@nxdig MOVR R3, R5 ; save display format word 151897 PRNUM16.cont: 0063 51BC 0001 0007 0203 0007 02F3 51F2 -C--I-i- ADDI #$0078,R5 | @@cont: ADDI #$80-8, R5 ; start our digit as one just before '0' 151903 PRNUM16.spcl: 0063 51BC 0001 0007 0203 007F 02F3 51F4 ----I-i- ADDI #$0008,R5 | @@div: ADDI #8, R5 ; increment our digit 151911 0063 51BC 0001 0007 0203 0087 02F3 51F6 ----I-i- SUB@ R1,R0 | SUB@ R1, R0 ; subtract power of 10 151919 0059 51BC 0001 0007 0203 0087 02F3 51F7 -C--I-i- BC PRNUM16.spcl ($51F4) | BC @@div ; loop until we go too far 151927 PRNUM16.spcl: 0059 51BC 0001 0007 0203 0087 02F3 51F4 -C--I-i- ADDI #$0008,R5 | @@div: ADDI #8, R5 ; increment our digit 151936 0059 51BC 0001 0007 0203 008F 02F3 51F6 ----I-i- SUB@ R1,R0 | SUB@ R1, R0 ; subtract power of 10 151944 004F 51BC 0001 0007 0203 008F 02F3 51F7 -C--I-i- BC PRNUM16.spcl ($51F4) | BC @@div ; loop until we go too far 151952 PRNUM16.spcl: 004F 51BC 0001 0007 0203 008F 02F3 51F4 -C--I-i- ADDI #$0008,R5 | @@div: ADDI #8, R5 ; increment our digit 151961 004F 51BC 0001 0007 0203 0097 02F3 51F6 ----I-i- SUB@ R1,R0 | SUB@ R1, R0 ; subtract power of 10 151969 0045 51BC 0001 0007 0203 0097 02F3 51F7 -C--I-i- BC PRNUM16.spcl ($51F4) | BC @@div ; loop until we go too far 151977 PRNUM16.spcl: 0045 51BC 0001 0007 0203 0097 02F3 51F4 -C--I-i- ADDI #$0008,R5 | @@div: ADDI #8, R5 ; increment our digit 151986 0045 51BC 0001 0007 0203 009F 02F3 51F6 ----I-i- SUB@ R1,R0 | SUB@ R1, R0 ; subtract power of 10 151994 003B 51BC 0001 0007 0203 009F 02F3 51F7 -C--I-i- BC PRNUM16.spcl ($51F4) | BC @@div ; loop until we go too far 152002 PRNUM16.spcl: 003B 51BC 0001 0007 0203 009F 02F3 51F4 -C--I-i- ADDI #$0008,R5 | @@div: ADDI #8, R5 ; increment our digit 152011 003B 51BC 0001 0007 0203 00A7 02F3 51F6 ----I-i- SUB@ R1,R0 | SUB@ R1, R0 ; subtract power of 10 152019 0031 51BC 0001 0007 0203 00A7 02F3 51F7 -C--I-i- BC PRNUM16.spcl ($51F4) | BC @@div ; loop until we go too far 152027 PRNUM16.spcl: 0031 51BC 0001 0007 0203 00A7 02F3 51F4 -C--I-i- ADDI #$0008,R5 | @@div: ADDI #8, R5 ; increment our digit 152036 0031 51BC 0001 0007 0203 00AF 02F3 51F6 ----I-i- SUB@ R1,R0 | SUB@ R1, R0 ; subtract power of 10 152044 0027 51BC 0001 0007 0203 00AF 02F3 51F7 -C--I-i- BC PRNUM16.spcl ($51F4) | BC @@div ; loop until we go too far 152052 PRNUM16.spcl: 0027 51BC 0001 0007 0203 00AF 02F3 51F4 -C--I-i- ADDI #$0008,R5 | @@div: ADDI #8, R5 ; increment our digit 152061 0027 51BC 0001 0007 0203 00B7 02F3 51F6 ----I-i- SUB@ R1,R0 | SUB@ R1, R0 ; subtract power of 10 152069 001D 51BC 0001 0007 0203 00B7 02F3 51F7 -C--I-i- BC PRNUM16.spcl ($51F4) | BC @@div ; loop until we go too far 152077 PRNUM16.spcl: 001D 51BC 0001 0007 0203 00B7 02F3 51F4 -C--I-i- ADDI #$0008,R5 | @@div: ADDI #8, R5 ; increment our digit 152086 001D 51BC 0001 0007 0203 00BF 02F3 51F6 ----I-i- SUB@ R1,R0 | SUB@ R1, R0 ; subtract power of 10 152094 0013 51BC 0001 0007 0203 00BF 02F3 51F7 -C--I-i- BC PRNUM16.spcl ($51F4) | BC @@div ; loop until we go too far 152102 PRNUM16.spcl: 0013 51BC 0001 0007 0203 00BF 02F3 51F4 -C--I-i- ADDI #$0008,R5 | @@div: ADDI #8, R5 ; increment our digit 152111 0013 51BC 0001 0007 0203 00C7 02F3 51F6 ----I-i- SUB@ R1,R0 | SUB@ R1, R0 ; subtract power of 10 152119 0009 51BC 0001 0007 0203 00C7 02F3 51F7 -C--I-i- BC PRNUM16.spcl ($51F4) | BC @@div ; loop until we go too far 152127 PRNUM16.spcl: 0009 51BC 0001 0007 0203 00C7 02F3 51F4 -C--I-i- ADDI #$0008,R5 | @@div: ADDI #8, R5 ; increment our digit 152136 0009 51BC 0001 0007 0203 00CF 02F3 51F6 ----I-i- SUB@ R1,R0 | SUB@ R1, R0 ; subtract power of 10 152144 FFFF 51BC 0001 0007 0203 00CF 02F3 51F7 S---I-i- BC PRNUM16.spcl ($51F4) | BC @@div ; loop until we go too far 152152 FFFF 51BC 0001 0007 0203 00CF 02F3 51F9 S---I-i- ADD@ R1,R0 | ADD@ R1, R0 ; add back the extra power of 10. 152159 0009 51BC 0001 0007 0203 00CF 02F3 51FA -C--I-i- MVO@ R5,R4 | MVO@ R5, R4 ; display the digit. 152167 0009 51BC 0001 0007 0204 00CF 02F3 51FB -C--I--- INCR R1 | INCR R1 ; point to next power of 10 152176 0009 51BD 0001 0007 0204 00CF 02F3 51FC -C--I-i- DECR R2 | DECR R2 ; any room left in field? 152182 0009 51BD 0000 0007 0204 00CF 02F3 51FD -C-ZI-i- BPL PRNUM16.dig1 ($51F1) | BPL @@nxdig ; keep going until R2 < 0. 152188 PRNUM16.dig1: 0009 51BD 0000 0007 0204 00CF 02F3 51F1 -C-ZI-i- MOVR R3,R5 | @@nxdig MOVR R3, R5 ; save display format word 152197 PRNUM16.cont: 0009 51BD 0000 0007 0204 0007 02F3 51F2 -C--I-i- ADDI #$0078,R5 | @@cont: ADDI #$80-8, R5 ; start our digit as one just before '0' 152203 PRNUM16.spcl: 0009 51BD 0000 0007 0204 007F 02F3 51F4 ----I-i- ADDI #$0008,R5 | @@div: ADDI #8, R5 ; increment our digit 152211 0009 51BD 0000 0007 0204 0087 02F3 51F6 ----I-i- SUB@ R1,R0 | SUB@ R1, R0 ; subtract power of 10 152219 0008 51BD 0000 0007 0204 0087 02F3 51F7 -C--I-i- BC PRNUM16.spcl ($51F4) | BC @@div ; loop until we go too far 152227 PRNUM16.spcl: 0008 51BD 0000 0007 0204 0087 02F3 51F4 -C--I-i- ADDI #$0008,R5 | @@div: ADDI #8, R5 ; increment our digit 152236 0008 51BD 0000 0007 0204 008F 02F3 51F6 ----I-i- SUB@ R1,R0 | SUB@ R1, R0 ; subtract power of 10 152244 0007 51BD 0000 0007 0204 008F 02F3 51F7 -C--I-i- BC PRNUM16.spcl ($51F4) | BC @@div ; loop until we go too far 152252 PRNUM16.spcl: 0007 51BD 0000 0007 0204 008F 02F3 51F4 -C--I-i- ADDI #$0008,R5 | @@div: ADDI #8, R5 ; increment our digit 152261 0007 51BD 0000 0007 0204 0097 02F3 51F6 ----I-i- SUB@ R1,R0 | SUB@ R1, R0 ; subtract power of 10 152269 0006 51BD 0000 0007 0204 0097 02F3 51F7 -C--I-i- BC PRNUM16.spcl ($51F4) | BC @@div ; loop until we go too far 152277 PRNUM16.spcl: 0006 51BD 0000 0007 0204 0097 02F3 51F4 -C--I-i- ADDI #$0008,R5 | @@div: ADDI #8, R5 ; increment our digit 152286 0006 51BD 0000 0007 0204 009F 02F3 51F6 ----I-i- SUB@ R1,R0 | SUB@ R1, R0 ; subtract power of 10 152294 0005 51BD 0000 0007 0204 009F 02F3 51F7 -C--I-i- BC PRNUM16.spcl ($51F4) | BC @@div ; loop until we go too far 152302 PRNUM16.spcl: 0005 51BD 0000 0007 0204 009F 02F3 51F4 -C--I-i- ADDI #$0008,R5 | @@div: ADDI #8, R5 ; increment our digit 152311 0005 51BD 0000 0007 0204 00A7 02F3 51F6 ----I-i- SUB@ R1,R0 | SUB@ R1, R0 ; subtract power of 10 152319 0004 51BD 0000 0007 0204 00A7 02F3 51F7 -C--I-i- BC PRNUM16.spcl ($51F4) | BC @@div ; loop until we go too far 152327 PRNUM16.spcl: 0004 51BD 0000 0007 0204 00A7 02F3 51F4 -C--I-i- ADDI #$0008,R5 | @@div: ADDI #8, R5 ; increment our digit 152336 0004 51BD 0000 0007 0204 00AF 02F3 51F6 ----I-i- SUB@ R1,R0 | SUB@ R1, R0 ; subtract power of 10 152344 0003 51BD 0000 0007 0204 00AF 02F3 51F7 -C--I-i- BC PRNUM16.spcl ($51F4) | BC @@div ; loop until we go too far 152352 PRNUM16.spcl: 0003 51BD 0000 0007 0204 00AF 02F3 51F4 -C--I-i- ADDI #$0008,R5 | @@div: ADDI #8, R5 ; increment our digit 152361 0003 51BD 0000 0007 0204 00B7 02F3 51F6 ----I-i- SUB@ R1,R0 | SUB@ R1, R0 ; subtract power of 10 152369 0002 51BD 0000 0007 0204 00B7 02F3 51F7 -C--I-i- BC PRNUM16.spcl ($51F4) | BC @@div ; loop until we go too far 152377 PRNUM16.spcl: 0002 51BD 0000 0007 0204 00B7 02F3 51F4 -C--I-i- ADDI #$0008,R5 | @@div: ADDI #8, R5 ; increment our digit 152386 0002 51BD 0000 0007 0204 00BF 02F3 51F6 ----I-i- SUB@ R1,R0 | SUB@ R1, R0 ; subtract power of 10 152394 0001 51BD 0000 0007 0204 00BF 02F3 51F7 -C--I-i- BC PRNUM16.spcl ($51F4) | BC @@div ; loop until we go too far 152402 PRNUM16.spcl: 0001 51BD 0000 0007 0204 00BF 02F3 51F4 -C--I-i- ADDI #$0008,R5 | @@div: ADDI #8, R5 ; increment our digit 152411 0001 51BD 0000 0007 0204 00C7 02F3 51F6 ----I-i- SUB@ R1,R0 | SUB@ R1, R0 ; subtract power of 10 152419 0000 51BD 0000 0007 0204 00C7 02F3 51F7 -C-ZI-i- BC PRNUM16.spcl ($51F4) | BC @@div ; loop until we go too far 152427 PRNUM16.spcl: 0000 51BD 0000 0007 0204 00C7 02F3 51F4 -C-ZI-i- ADDI #$0008,R5 | @@div: ADDI #8, R5 ; increment our digit 152436 0000 51BD 0000 0007 0204 00CF 02F3 51F6 ----I-i- SUB@ R1,R0 | SUB@ R1, R0 ; subtract power of 10 152444 FFFF 51BD 0000 0007 0204 00CF 02F3 51F7 S---I-i- BC PRNUM16.spcl ($51F4) | BC @@div ; loop until we go too far 152452 FFFF 51BD 0000 0007 0204 00CF 02F3 51F9 S---I-i- ADD@ R1,R0 | ADD@ R1, R0 ; add back the extra power of 10. 152459 0000 51BD 0000 0007 0204 00CF 02F3 51FA -C-ZI-i- MVO@ R5,R4 | MVO@ R5, R4 ; display the digit. 152467 0000 51BD 0000 0007 0205 00CF 02F3 51FB -C-ZI--- INCR R1 | INCR R1 ; point to next power of 10 152476 0000 51BE 0000 0007 0205 00CF 02F3 51FC -C--I-i- DECR R2 | DECR R2 ; any room left in field? 152482 0000 51BE FFFF 0007 0205 00CF 02F3 51FD SC--I-i- BPL PRNUM16.dig1 ($51F1) | BPL @@nxdig ; keep going until R2 < 0. 152488 PRNUM16.done: 0000 51BE FFFF 0007 0205 00CF 02F3 51FF SC--I-i- PULR R1 | @@done: PULR R1 ; restore R1 152495 0000 0000 FFFF 0007 0205 00CF 02F2 5200 SC--I-i- PULR R2 | PULR R2 ; restore R2 152507 0000 0000 0005 0007 0205 00CF 02F1 5201 SC--I-i- PULR R7 | PULR PC ; return 152519 0000 0000 0005 0007 0205 00CF 02F0 5095 SC--I-i- MVO R4,_screen ($033E) | PRINT <5>59999 152531 Q2: 0000 0000 0005 0007 0205 00CF 02F0 5097 SC--I--- B Q2 ($5097) | b: GOTO b 152542 Hit breakpoint at $5097 Q2: 0000 0000 0005 0007 0205 00CF 02F0 5097 SC--I-i- B Q2 ($5097) | b: GOTO b 152542 So, 152542 - 150890 = 1652. That's about 1/8th of a screen time. 1 Quote Link to comment Share on other sites More sharing options...
intvnut Posted November 23, 2014 Share Posted November 23, 2014 So, 152542 - 150890 = 1652. That's about 1/8th of a screen time. Ok, I just benchmarked printing the number '1' in a 5 digit, leading zero field and that only took 588 cycles. So the worst-case number takes 2.8x as long as the best-case number. (Not counting printing '0' as that's a special case that goes really fast.) And a slight clarification: 1652 cycles is about 1/8th of a screen time when the display's enabled (the typical case). If the display's blanked, you can actually squeeze 9 of those into a single frame time. Quote Link to comment Share on other sites More sharing options...
+DZ-Jay Posted November 23, 2014 Share Posted November 23, 2014 intvnut, what routine did you provide nanochess for printing decimals? Are those the ones in the SDK-1600 (prnum16.asm and prnum32.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.