Jump to content
IGNORED

IntyBASIC compiler v1.0 crunchy&tasty :)


Recommended Posts

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

No, the limit of 16 GRAM update per frame stands up, the only difference is that you now can update separate sections of GRAM data.

 

An idea that came to my mind was one player and one enemy with a variety of animations.

 

For example:

 

DEFINE 0,2,player_left_frame2
DEFINE ALTERNATE 8,2,enemy_right_frame1

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

Yes! being optimized in assembler it saves LOTS of cycles! (you should give thanks to intvnut for providing such an useful routine :) )

intvnut, what routine did you provide nanochess for printing decimals? Are those the ones in the SDK-1600 (prnum16.asm and prnum32.asm)?

He offered the code and I've taken what I could use :D

 

I've used prnum16.asm from jzintv download.

 

BTW, with the new USR call routine you can integrate very easily your PRNG routines, using something like this:

 

'.... some code....
A = USR PRNG(4)    ' 4 bits of PRNG
'.... more code.....

ASM INCLUDE prng.asm
In fact I've put also a VARPTR function to get the address of a variable and do optimized assembly processing :)

 

DIM B(10)

A = USR complicated(VARPTR B(3),4)  ' Passes pointer to B(3) and the 4 for processing, let us say, 4 numbers
  • Like 2

He offered the code and I've taken what I could use :D

 

I've used prnum16.asm from jzintv download.

 

 

I ask because at some point in time in the past, Joe had discussed the use of a binary search tree look-up for decimal number encoding, and I was wondering if that was in play here. I see that prnum16.asm does repeated subtraction. I wonder how it performs against a routine that alternates between subtraction and addition, provided by GroovyBee in this thread.

 

Update: The decision-tree routine was discussed in that same thread.

Edited by DZ-Jay
  • Like 1

 

I ask because at some point in time in the past, Joe had discussed the use of a binary search tree look-up for decimal number encoding, and I was wondering if that was in play here. I see that prnum16.asm does repeated subtraction. I wonder how it performs against a routine that alternates between subtraction and addition, provided by GroovyBee in this thread.

 

Update: The decision-tree routine was discussed in that same thread.

 

 

Why not write up a benchmark and see? :) Both of those approaches should be faster, although I don't know by how much. PRNUM16 does have the benefit of being available and public domain.

 

Most of the savings will be in replacing the repeated subtract, which already isn't terribly expensive as it repeats by powers of 10. It's 16 23 cycles per iteration plus 8 cycles fixup, so around 152 215 cycles for the worst-case digit.

 

EDIT: Fixed some numbers above. Also: For Groovy's approach, his loop is 2 cycles faster than mine I believe, so 21 cycles/iter and less fixup means he'll be about 8-10% faster overall. The decision tree approach, if I recall correctly, was around 95 cycles for the worst case branch, so that'd be over 2x, but at a huge bloat in code size.

Edited by intvnut

 

 

Why not write up a benchmark and see? :) Both of those approaches should be faster, although I don't know by how much. PRNUM16 does have the benefit of being available and public domain.

 

Most of the savings will be in replacing the repeated subtract, which already isn't terribly expensive as it repeats by powers of 10. It's 16 23 cycles per iteration plus 8 cycles fixup, so around 152 215 cycles for the worst-case digit.

 

EDIT: Fixed some numbers above. Also: For Groovy's approach, his loop is 2 cycles faster than mine I believe, so 21 cycles/iter and less fixup means he'll be about 8-10% faster overall. The decision tree approach, if I recall correctly, was around 95 cycles for the worst case branch, so that'd be over 2x, but at a huge bloat in code size.

 

Very interesting, thanks. Also, not to speak for GroovyBee, but presumably he posted that code in a public forum--with no explicit copyright claim--to make it available and public for others to use.

 

My interest on this routines right now is because I'm working this week-end on the "Print Number" routine for P-Machinery v2.0. I was going to adapt the one I used in Christmas Carol, which in itself was adapted from Groovy's code on that thread (after a thorough explanation provided by catsfolly). However, I'll be interested in trying other approaches that may be faster.

 

 

I'll try to benchmark all of them with some random numbers. I'm also interested in playing with the decision tree approach, but I'll have to dig deeper into it to understand it. I'm not too afraid of a "huge bloat in code size." ;)

 

Thanks,

-dZ.

  • Like 1

 

Very interesting, thanks. Also, not to speak for GroovyBee, but presumably he posted that code in a public forum--with no explicit copyright claim--to make it available and public for others to use.

 

My interest on this routines right now is because I'm working this week-end on the "Print Number" routine for P-Machinery v2.0. I was going to adapt the one I used in Christmas Carol, which in itself was adapted from Groovy's code on that thread (after a thorough explanation provided by catsfolly). However, I'll be interested in trying other approaches that may be faster.

 

 

I'll try to benchmark all of them with some random numbers. I'm also interested in playing with the decision tree approach, but I'll have to dig deeper into it to understand it. I'm not too afraid of a "huge bloat in code size." ;)

 

Thanks,

-dZ.

 

 

Well, the divide-and-conquer tree based approach should be the fastest without hardware acceleration. If you want to provide left-justified, right-justified and leading-zero forms that'll obviously take some additional work.

Very interesting, thanks. Also, not to speak for GroovyBee, but presumably he posted that code in a public forum--with no explicit copyright claim--to make it available and public for others to use.

Yep! Anybody can use it any project they like.

  • Everyone wanted it, so now there is Intellivoice support using the VOICE statement, the library also provided by all-powerful intvnut. (note: not yet tested in real hardware, but it should work)

 

I had someone with a CC3 test the Intellivoice code on a real console.

 

"I tested on an Intellivision and an Intellivision II, with and without the Intellivoice attached. Didn't notice any crashing or anything unusual."

 

 

Which means my Voice statements seemed to be nicely handled if the IntelliVoice module isn't plugged in; without me having to always check first. Well done. Also good news is that many of my voice commands were also recognizable as speech ;)

  • Like 1

I had someone with a CC3 test the Intellivoice code on a real console.

 

"I tested on an Intellivision and an Intellivision II, with and without the Intellivoice attached. Didn't notice any crashing or anything unusual."

 

Which means my Voice statements seemed to be nicely handled if the IntelliVoice module isn't plugged in; without me having to always check first. Well done. Also good news is that many of my voice commands were also recognizable as speech ;)

 

Awesome. My Intellivoice driver is supposed to detect the Intellivoice on initialization, and if it doesn't see it, it silently drops all requests to play voices so that games can proceed unimpeded, just voiceless.

 

While I've tested my original driver on real hardware—heck, it's in SG&R I'm pretty sure—it's good to see that the version in IntyBASIC retains this property. :)

 

 

 

I'll try to benchmark all of them with some random numbers. I'm also interested in playing with the decision tree approach, but I'll have to dig deeper into it to understand it. I'm not too afraid of a "huge bloat in code size." ;)

 

Yeah, the decision tree code is pretty big. You and anyone else are welcome to use my code from the other thread for any purpose. The main "trick" in the code (aside from the decision tree itself) is using subtracts and adds to double as comparisons. (GroovyBee's non-restoring divide—the technical term for switching between add and subtract on alternate digits—also takes advantage of the flags set by ADD/SUB.) As I recall, my decision tree code is a restoring divide, meaning that if it goes down the wrong branch and takes too much off the remaining quotient, it'll restore the quotient. If you really want to blow up the code size, you could avoid restoration, and instead replicate the code with adjusted comparisons. For 5 digits, though, you could be looking at a 16x increase in size.

 

As for benchmarking random numbers, you might try certain "endpoint numbers" such as 59999 and 1, which should be worst-case and best-case 16-bit numbers for iterative methods, and numbers like 11111, 22222, 33333, 44444, 55555, x6666, x7777, x8888, x9999 (where x could be any digit 0-5) to see how balanced the decision tree approach is.

 

From a game performance point of view, worst-case performance is probably the main care-about. You don't want a sudden spike in cycles because you've decided to refresh the score on the screen. That's part of what makes the decision tree code attractive: Not only is the peak lower, but also the ratio of peak to best-case is lower too.

 

 

FWIW, 4-Tris used a more primitive version of the PRNUM16 code (called DEC16), and it was never short on cycles despite updating the score once a frame every frame. (Recall, 4-Tris "animated" score updates by rolling the score upward like a pinball machine might.)

 

EDIT: And if you really, really don't care about ROM size, check out the attached "stupid bindec" code. It runs crazy fast (314 cycles for any number) and could possibly be optimized a little further. But about that code-size... In case you're interested, the call to the function occurs at $5041, and the function itself resides at $5052. The function has a few... erm... data tables that reside... well, everywhere else.

 

"We're going to need a bigger cartridge."

stupid_bindec.zip

Edited by intvnut
  • Like 1

My hacky BCD wannabe code (written entirely in BASIC) is also very fast, but consumes a fair bit of ROM (and RAM, for that matter). Which isn't much of a concern these days, but... to be honest GoatNom is past 36KB at this point and there's still a fair bit more to add. So I don't mind trimming that part out :)

My hacky BCD wannabe code (written entirely in BASIC) is also very fast, but consumes a fair bit of ROM (and RAM, for that matter). Which isn't much of a concern these days, but... to be honest GoatNom is past 36KB at this point and there's still a fair bit more to add. So I don't mind trimming that part out :)

 

My ROM up there is over 640kB and all it does it print a number.... :D But it's hella fast! :rolling:

Edited by intvnut

 

But... it's fast! :D

 

And now 5% faster... An even 300 cycles. :rolling:

 

 

And it should be enough space for anyone.

 

Indeed!

 

You can tell just how efficient it is by the fact the ROM image compresses 98%. ;) ;) ;)

stupid_bindec.zip

 

I had someone with a CC3 test the Intellivoice code on a real console.

 

"I tested on an Intellivision and an Intellivision II, with and without the Intellivoice attached. Didn't notice any crashing or anything unusual."

 

 

Which means my Voice statements seemed to be nicely handled if the IntelliVoice module isn't plugged in; without me having to always check first. Well done. Also good news is that many of my voice commands were also recognizable as speech ;)

So cool! :) thanks for the test! :thumbsup:

Hello all,

 

I'm not new to the Intellivision but new to Intellivision programing. Is there a forum posting that outlines how to setup the compiler? Is there an IDE?

 

Thanks.

 

Rick

 

There is no IDE as of yet.

 

Basically the compiler is a command-line tool. If you're comfortable with the command line, it should be pretty straightforward to figure it out (and if you have problems with it, post your OS here and someone will surely be able to help). If you're not familiar with the command line, you're going to struggle a bit getting things set up. There is no way to work around the command line usage for the moment.

 

In total there are 3 components you need here: the compiler (which you've found), the assembler (as1600), and the emulator (jzintv). You edit your source code in a text editor, compile with IntyBASIC, assemble with as1600, and run in jzintv. Many of us have written little command line scripts to automate this 3 step process - so you save your code and run a single command to run it, in essence.

 

Here's the best thread I can find at the moment with links to the 3 major components:

 

http://atariage.com/forums/topic/169024-programming-resources/

 

It's a bit dated however I don't think as1600 or jzintv need to be updated from that first post? Either way, we should use that first stickied post as a link to the current compiler and everything else. *me waves at GroovyBee*

 

I just go straight the source for the assembler and emulator: http://spatula-city.org/~im14u2c/intv/ . They're both written by the same guy, so it's convenient that way :)

Edited by freeweed
  • 2 weeks later...
  • 2 weeks later...

BTW, freeweed's recent Crazybus post exposed a flaw in both jzIntv and the Intellivoice driver (and therefore IntyBASIC 1.0). :-) I've been testing a fix, and I think its gelled enough to share.

 

Specifically: If you call VOICE INIT while the Intellivoice is speaking, you could crash the real Intellivoice.

 

Here's the issue: Writing $0400 to location $0080 resets the speech buffer chip (SBP640). It only resets the speech buffer chip. It does not reset the actual speech chip (SP0256). In jzIntv, it resets both.

 

The IV_INIT function blindly writes $0400 to $0080, and then does the rest of the initialization. If that happens while the speech chip expects more speech data from the speech FIFO.... Go directly to jail. Do not collect $200. Lose the next three turns. ... That is, the speech chip crashes, and it may not be recoverable without a hard reset on the Intellivision.

 

So, I set about fixing IV_INIT in the intybasic_epilogue.asm. I modified freeweed's Crazybus to be even more crazy annoying, triggering VOICE INIT much more often, but still randomly. (Imagine the looks I got here at home. :D ) The new code seems clean.

 

With this new version, VOICE INIT forcibly drops the contents of the software speech queue. It does, however, wait for any FIFOed sample to complete. And, it has some extra synchronization steps. Overall, it seems to work pretty well.

 

Here's the modified IV_INIT code. You should be able to edit this into your intybasic_epilogue.asm if you need it. You only need it, though, if you call VOICE INIT more than once in your IntyBASIC program.

;; ======================================================================== ;;
;;  NAME                                                                    ;;
;;      IV_INIT     Initialize the Intellivoice                             ;;
;;                                                                          ;;
;;  AUTHOR                                                                  ;;
;;      Joseph Zbiciak <intvnut AT gmail.com>                               ;;
;;                                                                          ;;
;;  REVISION HISTORY                                                        ;;
;;      15-Sep-2002 Initial revision . . . . . . . . . . .  J. Zbiciak      ;;
;;      14-Dec-2014 Updated to allow INIT called anytime .  J. Zbiciak      ;;
;;                                                                          ;;
;;  INPUTS for IV_INIT                                                      ;;
;;      R5      Return address                                              ;;
;;                                                                          ;;
;;  OUTPUTS                                                                 ;;
;;      R0      0 if Intellivoice found, -1 if not.                         ;;
;;                                                                          ;;
;;  DESCRIPTION                                                             ;;
;;      Initializes (or reinitializes) the Intellivoice.  Note:  Relies     ;;
;;      on memory holding the IV variables to be initialized to zero at     ;;
;;      reset.                                                              ;;
;;                                                                          ;;
;; ------------------------------------------------------------------------ ;;
;;                   Copyright (c) 2002, Joseph Zbiciak                     ;;
;; ======================================================================== ;;

IV_INIT     PROC
            MVI     IV.QH,  R0          ; \
            SWAP    R0,     2           ;  |- If there was none, there still
            BMI     @@no_ivoice         ; /   is none.

            MVI     $0081,  R0          ; \
            RLC     R0,     2           ;  |-- See if we detect Intellivoice
            BOV     @@no_ivoice         ; /    

            ; Forcefully discard queued phrases that aren't spoken yet.
            DIS
            MVI     IV.QT,  R0
            ANDI    #7,     R0
            MVO     R0,     IV.QH

            CLRR    R0

            ; Kill the current phrase
            MVO     R0,     IV.PPTR
            EIS

            ; If the FIFO-data pointer is non-NULL, the Intellivoice is
            ; clearly already initialized.  Skip the rest of this jazz.
            CMP     IV.FPTR,R0
            BNEQ    @@done

            ; If Intellivoice is non-idle, it's already initialized and 
            ; doing interesting stuff.  Just leave.
@@ready:    MVI     $80,    R0          ; Get w/ ALD status.  1 == ready
            SLLC    R0
            BNC     @@done

            ; Play a silent sample
            MVII    #5,     R0          ; Short silent sample
            MVO     R0,     $80         ; Say it

            ; Wait for it to start (which means no data remains in FIFO)
@@ready2:   MVI     $80,    R0          ; Get w/ ALD status.  1 == ready
            SLLC    R0
            BNC     @@ready2

            MVII    #$0400, R0          ;
            MVO     R0,     $0081       ; Reset the Speech Buffer Chip

            CLRR    R0                  ; 
            MVO     R0,     IV.FPTR     ; No data for FIFO
            MVO     R0,     IV.PPTR     ; No phrase being spoken
            NOP
            MVO     R0,     IV.QH       ; Clear our queue
            MVO     R0,     IV.QT       ; Clear our queue
@@done:     JR      R5                  ; Done!

@@no_ivoice:
            CLRR    R0
            MVO     R0,     IV.FPTR     ; No data for FIFO
            MVO     R0,     IV.PPTR     ; No phrase being spoken
            DECR    R0
            MVO     R0,     IV.QH       ; Set queue to -1 ("No Intellivoice")
            MVO     R0,     IV.QT       ; Set queue to -1 ("No Intellivoice")
            JR      R5                  ; Done!
            ENDP


Edited by intvnut
  • Like 1

Yeah, intvnut and I chatted about this. Basically you can avoid this by simply calling VOICE INIT only once (initialization stage of the program makes the most sense).

 

However to prevent newbie coders from breaking things, we either need that very well documented in the manual, or better, the "official" epilogue.asm fixed. IntyBASIC is extremely forgiving with structure and I can see people messing this up (I did on the first program I wrote that was tested on real hardware, ha-ha).

  • Like 1

Truth to be told I'm surprised by the bug :)

 

Good to have it reported here, and I'll put this in the intybasic_epilogue.asm

 

I was surprised too. And just to be sure, I went ahead and tested it with two different Intellivoices with widely spaced serial numbers, to see if there was a change in Intellivoice behavior on the unit I had reverse engineered years ago vs. the unit currently installed on my bench system. Both behaved about the same. They also behave in line with what's described in the now-available documentation on PapaIntellivision.

 

I had honestly never tested calling IV_INIT randomly. I always just called it once at the 'beginning of time' and it worked as expected. Now it's considerably more robust. You can do VOICE INIT to kill everything queued up, which is a reasonable thing to do in certain game circumstances. (Like, for example, your ship blows up and its game over.)

  • Like 1

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