Jump to content
IGNORED

IntyBASIC compiler v1.0 crunchy&tasty :)


nanochess

Recommended Posts

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. ;)

Link to comment
Share on other sites

 

 

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 by intvnut
  • Like 1
Link to comment
Share on other sites

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).

Link to comment
Share on other sites

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 by intvnut
Link to comment
Share on other sites

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!

  • Like 2
Link to comment
Share on other sites

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" ;)

Link to comment
Share on other sites

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.

 

post-14113-0-12358600-1416638311.gif

 

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 by intvnut
  • Like 3
Link to comment
Share on other sites

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

  • Like 2
Link to comment
Share on other sites

 

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! :rolling:

Link to comment
Share on other sites

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

Link to comment
Share on other sites

 

Ok, here's a screen shot showing some fun stuff.

 

attachicon.gifjzintv_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. :D

 

I'm updating the manual to include this information :)

 

Link to comment
Share on other sites

 

.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. :P

 

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.

Link to comment
Share on other sites

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?

  • Like 1
Link to comment
Share on other sites

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.

Link to comment
Share on other sites

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?

Link to comment
Share on other sites

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,

Link to comment
Share on other sites

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 :)

  • Like 1
Link to comment
Share on other sites

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 8)

 

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 :) :thumbsup:

  • Like 1
Link to comment
Share on other sites

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. :D 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 by intvnut
  • Like 2
Link to comment
Share on other sites


            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. :D

 

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 by intvnut
Link to comment
Share on other sites

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. :)

  • Like 1
Link to comment
Share on other sites

 

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.

 

  • Like 1
Link to comment
Share on other sites

 

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.

Link to comment
Share on other sites

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.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

Loading...
  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...