Jump to content
IGNORED

That's why TI BASIC is so slow!


Airshack
 Share

Recommended Posts

I'm not sure I understand why?

 

A. BASIC is written in GPL (vs assembler) so it's twice interpreted: once for BASIC-to-GPL + once for GPL-to-machine code. Most BASICs of the day were written in Assembler so they're only interpreted once (BASIC-to-machine code) as they run programs.

 

B. The whole 16-bit CPU shoehorned into an 8-bit motherboard (data bus 8-bit) is the reason.

 

C. The VDP RAM boondoggle? CPU needs to request info from VDP and then wait for VDP to grab info and notify CPU.

 

D. Other reasons such as the water in Lubbock.

 

Please clarify if you understand the complete story. Thx!

 

 

 

 

Sent from my iPhone using Tapatalk

Link to comment
Share on other sites

A. I see the GPL support as an early version of a virtual machine, as you know from Java. In fact, TI emulates a complex instruction set 8-bit CPU, the GPL is its machine language, and thus TI BASIC is actually running in this virtual machine. So yes, I would consider this is the primary cause. Note that Extended Basic reimplements some functions in its cartridge ROM for faster execution.

 

B. Partly yes, but the Geneve uses the 9995 which has the data bus multiplexer built into the package and is arguably pretty fast (with higher clock, yes). Also, this was not so uncommon; consider the Intel 8088, a 16-bit CPU with 8 bit data bus, or the 80386SX (32 bit with 16 bit data bus). The problem is rather that the TI CPU 9900 implements byte access in an awkward way, requiring it to always load a memory word before changing one of its bytes, then writing the word back. Together with the data bus multiplexer and wait states, this add up to a lot of CPU cycles.

 

C. The VDP is not such a narrow bottleneck in that architecture, particularly considering the virtual machine as described in A. It is a problem for the native machine, since you cannot execute machine language programs from it. The VDP does not notify the CPU; it does not even have a busy line, which is also a pity, since that means you have to take care for the timing in your program (using NOPs for example).

Edited by mizapf
Link to comment
Share on other sites

Several BASICS of the era supported straight integers as well as numerics... I believe they used the % symbol to indicate an integer variable or array.

 

I think the worst problem with the architecture is just the (near) lack of CPU memory. I understand why all the RAM was in the VDP only; memory was expensive at the time.

 

The memory issue cropped up even with cartridges as well. I know that several of TI's attempts to get commercial software produced for the TI failed in part because they demanded the 3rd party try and fit everything in the 8K memory slot for cartridges. In particular, Zaxxon was right out.

  • Like 1
Link to comment
Share on other sites

A. I see the GPL support as an early version of a virtual machine, as you know from Java. In fact, TI emulates a complex instruction set 8-bit CPU, the GPL is its machine language, and thus TI BASIC is actually running in this virtual machine. So yes, I would consider this is the primary cause. Note that Extended Basic reimplements some functions in its cartridge ROM for faster execution.

 

B. Partly yes, but the Geneve uses the 9995 which has the data bus multiplexer built into the package and is arguably pretty fast (with higher clock, yes). Also, this was not so uncommon; consider the Intel 8088, a 16-bit CPU with 8 bit data bus, or the 80386SX (32 bit with 16 bit data bus). The problem is rather that the TI CPU 9900 implements byte access in an awkward way, requiring it to always load a memory word before changing one of its bytes, then writing the word back. Together with the data bus multiplexer and wait states, this add up to a lot of CPU cycles.

 

C. The VDP is not such a narrow bottleneck in that architecture, particularly considering the virtual machine as described in A. It is a problem for the native machine, since you cannot execute machine language programs from it. The VDP does not notify the CPU; it does not even have a busy line, which is also a pity, since that means you have to take care for the timing in your program (using NOPs for example).

 

Very true in the XB ROM's you see a crap load of JMP $+2 which means do nothing and just jump to next instruction and I think they did not know there was a CPU NOP (No Operation) instruction in the CPU.

These are there in XB ROM's to allow for all the VDP only access being used which slows down XB considerably.

Example in VDP STACK takes much longer then RAM stack to do the same thing and every variable name or Subroutine is pushed onto the VDP Stack temporarily at one time or another again slows XB.

Edited by RXB
Link to comment
Share on other sites

I'm not sure I understand why?

 

A. BASIC is written in GPL (vs assembler) so it's twice interpreted: once for BASIC-to-GPL + once for GPL-to-machine code. Most BASICs of the day were written in Assembler so they're only interpreted once (BASIC-to-machine code) as they run programs.

 

B. The whole 16-bit CPU shoehorned into an 8-bit motherboard (data bus 8-bit) is the reason.

 

C. The VDP RAM boondoggle? CPU needs to request info from VDP and then wait for VDP to grab info and notify CPU.

 

D. Other reasons such as the water in Lubbock.

 

Please clarify if you understand the complete story. Thx!

 

 

 

 

Sent from my iPhone using Tapatalk

 

Most of the issue with TI BASIC speed was EVERYTHING RAN FROM VDP.

This is unlike XB that with no memory expansion XB still has Assembly in three 4K ROM's running from a console, thus improved speed of XB execution.

With a memory expansion of 32K XB would move the Numeric variables and XB program into upper 24K of RAM, as this also increased speed of XB execution.

 

Both TI BASIC and XB were mostly written in GPL, but TI Basic being 100% restricted to VDP RAM ONLY and no Assembly support built in really slowed it to a crawl.

Link to comment
Share on other sites

The question is why they didn't uncripple several features with the release of the TI-99/4A in 1981. Like extend the SRAM to 1,2, or 4K and add the 32K internally. A MMU of some sort would of been nice too -- along with a newer mlx XB with expanded memory support (similar to the TI-99/8). This would of allowed it to compete with the likes of the C64, Atari 800, and Apple II+/e. Instead they battled it out in price war against Commodore's low-end Vic-20.

 

Just boils down to woulda-shouda-coulda that TI missed in the 80's.

Edited by Torrax
  • Like 2
Link to comment
Share on other sites

 

Really? I think you'll find that NOP just assembles to JMP $+2.

I used to have the original XB ROM source code from TI and no it did not use the NOP but had JMP $+2

Seems unlikely he TI Assembler did not contain NOP, more likely like many things in the TI the left had did not know what the right hand was doing.

 

Like in XB ROMs they have odd code that GPL does faster than the Assembly versions they made in XB ROMs.

 

GVWITE is a GROM to VDP routine that is slower then the GPL MOVE command as it takes more bytes to set up and execute and is no faster.

I have run tests and many of the routines in XB ROM are faster but some are actually slower than GPL equivalent commands.

Edited by RXB
  • Like 1
Link to comment
Share on other sites

 

Really? I think you'll find that NOP just assembles to JMP $+2.

 

The 9900 instruction set does not have NOP. It is a pseudo-instruction that the TI assembler converts to a JMP instruction as Stuart says.

 

Indeed so! Here is Section 13.1 on page 206 of the Editor Assembler Manual, Section 13 “Pseudo Instructions”:

13.1 NO OPERATION--NOP
Syntax definiton:
[<label>] b NOP b [<comment>]
NOP places a machine instruction in the object code which only effects [sic] the execution
time of the program. Use of the label field is optional. When the label field is
used, the label is assigned the location of the instruction. The operation field
contains NOP. The operand field is not used. Use of the comment field is optional.
Enter the NOP pseudo-instructions as shown in the following example.
MOD NOP
Location MOD contains a NOP pseudo-instruction when the program is loaded.
Another instruction may be placed in location MOD during execution to implement a
program option. The Assembler supplies the same object code as though the source
statement contained the following code.
MOD JMP $+2
...lee
Link to comment
Share on other sites

Reading data from GROM or VDP RAM isn't that extremely slow, as long as you read consecutive addresses. But when you start modifying the address, the overhead to load a new address and then read data is substantial.

At least the GPL interpreter runs from 16 bit ROM.

My console, which has 64 K RAM built in, on 16 bit wide bus, is about 110% faster than an original TI 99/4A, when you run programs that has both code and workspace in expansion RAM. That is, in memory that normally is only 8 bit wide. This give you an idea about how a "real" Commodore 64 competitor version could have performed, with little change to the rest of the architecture.

Of course, all sensibly written software doesn't speed up that much, since it has workspace in RAM PAD, which already is 16 bit wide.

Link to comment
Share on other sites

I did some analysis when I first implemented the UberGROM, since I expected to see some speed boost if I pulled the console GROMs out, and did not. My analysis suggested it's all in the GPL interpreter. It's partly because the GPL interpreter was coded for memory, not speed - as such it jumps around a lot and tends to repeat calculations and memory sets that it has already done. But on average (IIRC), I came up with a number of something like 30:1 CPU instructions to GPL instructions - even the simple ones. Many of them could be much faster with the coding techniques we have today - but that's a rewrite of the GPL interpreter. Every so often I get the urge to prove this claim, but time is not something I've got a lot of. :/ Basically it means that any time lost to accessing slow VDP or slower GROM is completely overshadowed by how much code is executed just to get there. They add impact, but it's a smaller piece.

  • Like 1
Link to comment
Share on other sites

That makes sense. Here's a stub of an interpreter for a byte-coded (to save memory) stack machine (similar to the PME, that runs the p-code card). SP is stack pointer, CP is code pointer. EREC is the current environment record, inside which the currently executing procedure's local variables are stored.

Each op-code is assumed to define the instruction completely. Even with this very simple approach, the instruction fetch and decoding loop is five instructions. Then add the instruction itself, which for these simple examples adds 2-5 instructions to interpret one instruction code. So here we have ten instructions to accomplish what two could do, or seven to do what one could do, if it was normal assembly code that was running instead of interpreted code on byte level.

interp: MOVB *CP+,R1
        SRL  R1,7
        MOV  @INTTAB(R1),R0
        BL   *R0
        JMP  interp

; Code for ADD values at stack, return result on stack
addc:   A    *SP+,*SP
        B    *R11

; Code for INC top of stack
incc:   INC  *SP
        B    *R11

; Code for push integer immediate to stack
push:   MOVB *CP+,R1
        MOVB *CP+,@R1LBYT
        DECT SP
	MOV  R1,*SP
	B    *R11

; Code for local store integer (offset into local variable area in byte after instruction)
locst:  MOVB *CP+,R1
        SRL  R1,7
        MOV  *SP+,@EREC(R1)
        B    *R11





















Edited by apersson850
Link to comment
Share on other sites

Interpreted means you can program and test on the fly instantly.

 

Interpreted requires:

1. Write Code.

2. if not correct go to step 1 and start over.

 

Pro and Con interpreted is fast on turn around on finished product is easy to read and debug. Slow execution.

 

Compiled requires:

1. Write Code.

2. Compile Code.

3 Load and RUN code to test it.

4. If not correct go to step 1 and start over.

 

Pro and Con compiled is slow on turn around on finished product is hard to read and debug. Fast execution.

 

I think Forth is best for both worlds as it is both interpreted and compiled. Big con is you write Forth code to suit the RPN stack construction.

Edited by RXB
  • Like 1
Link to comment
Share on other sites

If it's FINISHED, I would not be at all concerned with reading it or debugging it in it's compiled form.

I'd keep the BASIC source code if I thought I might want to change it at a later date.

 

For a guy like me a BASIC compiler is a WIN(1)-WIN(2)-WIN(3).

 

1) I don't have to spend the rest of my life trying to learn assembly language just to write a program.

2) I can use a language I already know and can tweak at whim.

3) Once I get it the way I want it... convert it into something better and more 'usable'.

  • Like 1
Link to comment
Share on other sites

My build cycle for assembly is like this:

 

1) Edit code in IntelliJ IDEA on PC (using Ralph's plugin) with syntax highlighting, global label renaming, short cut key for jumping to labels, etc..

2) Press a button to build disk and cartridge images within seconds using the xas99, xdm99 and my own cartridge build tool.

3) Open and run object file directly in js99er.net without pressing any keys on the TI.

 

All in all about 10 seconds from making a change in the code until you can see the result. :grin:

  • Like 1
Link to comment
Share on other sites

I've never really used any TI 99/4A that hasn't been the real thing.

But when the 99 was the computer I had, I mainly used the p-system, and Pascal, for my software development. In that case I wrote everything that was doable in Pascal, and that's quite a lot, in Pascal. When the code worked, I used it as it was, if that was satisfactory. If there was a speed problem, I'd think about what part of the code was best to optimize, and then convert that to assembly. Normally I had a good idea about which part would be a good candidate for conversion to assembly already when starting out, so I made sure I wrote that part as a Pascal function/procedure in such a way that it would be easy to convert it to assembly.

Thus I didn't spend time designing things like data entry or disk access in assembly, since there are other things around these activities that are slowing them down anyway. Like running the drive or me typing on the keyboard. But a procedure to sort numbers or whatever would be very good to convert to assembly, to speed it up. Especially since such tasks often are time consuming.

Link to comment
Share on other sites

My build cycle for assembly is like this:

 

1) Edit code in IntelliJ IDEA on PC (using Ralph's plugin) with syntax highlighting, global label renaming, short cut key for jumping to labels, etc..

2) Press a button to build disk and cartridge images within seconds using the xas99, xdm99 and my own cartridge build tool.

3) Open and run object file directly in js99er.net without pressing any keys on the TI.

 

All in all about 10 seconds from making a change in the code until you can see the result. :grin:

And not on a TI Console, you have to use a PC and then you can run it on the TI99/4A or a Emulator.

 

I use Classic99 myself using text and using TIDIR99 to put into a TI DV80 Source file, then assemble it in Editor Assembler.

Most of what I do could be done on the TI instead, you are on the other hand have to use the PC.

 

Point is it is not TI in anyway it is all Emulation of TI.

Fine you can do that but do not pretend it is the same as using a real TI99/4A, and I do realize I am using a emulator not real hardware.

Link to comment
Share on other sites

 

 

I use Classic99 myself using text and using TIDIR99 to put into a TI DV80 Source file, then assemble it in Editor Assembler.

 

Classic99 can read Windows text files natively - you could skip this step. Just give it a .TXT extension (and of course use a disk folder, rather than a disk image). I used to build my programs through Editor Assembler this way.

 

https://youtu.be/GbpiUzn6kt0

  • Like 1
Link to comment
Share on other sites

 

Classic99 can read Windows text files natively - you could skip this step. Just give it a .TXT extension (and of course use a disk folder, rather than a disk image). I used to build my programs through Editor Assembler this way.

 

https://youtu.be/GbpiUzn6kt0

This gives me a second copy in DV80 format in case I make changes to text file. It is my way to have auto backups of what I am doing without the worry of forgetting to backup files.

 

Also when GPL Assembling files 4000 lines long I have no line numbers in PC Text files to find the line with the problem.

 

GPL Assembler says unknown symbol in line 743 so how the hell do I know where line 743 is in a PC NotePad text file?

(I do not like Notepad + or Notepad 2 as they attempt to make everything a NotePad + or NotePad 2 file.)

Edited by RXB
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...
 Share

  • Recently Browsing   0 members

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